diff options
Diffstat (limited to 'src/server/game')
| -rw-r--r-- | src/server/game/DataStores/DB2Stores.cpp | 28 | ||||
| -rw-r--r-- | src/server/game/DataStores/DB2Stores.h | 6 | ||||
| -rw-r--r-- | src/server/game/DataStores/DB2Structure.h | 14 | ||||
| -rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 89 | ||||
| -rw-r--r-- | src/server/game/Entities/Player/Player.h | 37 | ||||
| -rw-r--r-- | src/server/game/Handlers/CharacterHandler.cpp | 4 | ||||
| -rw-r--r-- | src/server/game/Server/Packets/TalentPackets.cpp | 19 | ||||
| -rw-r--r-- | src/server/game/Server/Packets/TalentPackets.h | 19 | ||||
| -rw-r--r-- | src/server/game/Server/Protocol/Opcodes.cpp | 2 | ||||
| -rw-r--r-- | src/server/game/Spells/Spell.cpp | 58 | ||||
| -rw-r--r-- | src/server/game/Spells/Spell.h | 4 | ||||
| -rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 35 | 
12 files changed, 291 insertions, 24 deletions
diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp index a893bcc5ece..506dccd1f23 100644 --- a/src/server/game/DataStores/DB2Stores.cpp +++ b/src/server/game/DataStores/DB2Stores.cpp @@ -91,7 +91,9 @@ DB2Storage<GarrPlotInstanceEntry>               sGarrPlotInstanceStore("GarrPlot  DB2Storage<GarrSiteLevelEntry>                  sGarrSiteLevelStore("GarrSiteLevel.db2", GarrSiteLevelMeta::Instance(), HOTFIX_SEL_GARR_SITE_LEVEL);  DB2Storage<GarrSiteLevelPlotInstEntry>          sGarrSiteLevelPlotInstStore("GarrSiteLevelPlotInst.db2", GarrSiteLevelPlotInstMeta::Instance(), HOTFIX_SEL_GARR_SITE_LEVEL_PLOT_INST);  DB2Storage<GemPropertiesEntry>                  sGemPropertiesStore("GemProperties.db2", GemPropertiesMeta::Instance(), HOTFIX_SEL_GEM_PROPERTIES); +DB2Storage<GlyphBindableSpellEntry>             sGlyphBindableSpellStore("GlyphBindableSpell.db2", GlyphBindableSpellMeta::Instance(), HOTFIX_SEL_GLYPH_BINDABLE_SPELL);  DB2Storage<GlyphPropertiesEntry>                sGlyphPropertiesStore("GlyphProperties.db2", GlyphPropertiesMeta::Instance(), HOTFIX_SEL_GLYPH_PROPERTIES); +DB2Storage<GlyphRequiredSpecEntry>              sGlyphRequiredSpecStore("GlyphRequiredSpec.db2", GlyphRequiredSpecMeta::Instance(), HOTFIX_SEL_GLYPH_REQUIRED_SPEC);  DB2Storage<GuildColorBackgroundEntry>           sGuildColorBackgroundStore("GuildColorBackground.db2", GuildColorBackgroundMeta::Instance(), HOTFIX_SEL_GUILD_COLOR_BACKGROUND);  DB2Storage<GuildColorBorderEntry>               sGuildColorBorderStore("GuildColorBorder.db2", GuildColorBorderMeta::Instance(), HOTFIX_SEL_GUILD_COLOR_BORDER);  DB2Storage<GuildColorEmblemEntry>               sGuildColorEmblemStore("GuildColorEmblem.db2", GuildColorEmblemMeta::Instance(), HOTFIX_SEL_GUILD_COLOR_EMBLEM); @@ -362,7 +364,9 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale)      LOAD_DB2(sGarrSiteLevelStore);      LOAD_DB2(sGarrSiteLevelPlotInstStore);      LOAD_DB2(sGemPropertiesStore); +    LOAD_DB2(sGlyphBindableSpellStore);      LOAD_DB2(sGlyphPropertiesStore); +    LOAD_DB2(sGlyphRequiredSpecStore);      LOAD_DB2(sGuildColorBackgroundStore);      LOAD_DB2(sGuildColorBorderStore);      LOAD_DB2(sGuildColorEmblemStore); @@ -627,6 +631,12 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale)      for (HeirloomEntry const* heirloom : sHeirloomStore)          _heirlooms[heirloom->ItemID] = heirloom; +    for (GlyphBindableSpellEntry const* glyphBindableSpell : sGlyphBindableSpellStore) +        _glyphBindableSpells[glyphBindableSpell->GlyphPropertiesID].push_back(glyphBindableSpell->SpellID); + +    for (GlyphRequiredSpecEntry const* glyphRequiredSpec : sGlyphRequiredSpecStore) +        _glyphRequiredSpecs[glyphRequiredSpec->GlyphPropertiesID].push_back(glyphRequiredSpec->ChrSpecializationID); +      for (ItemBonusEntry const* bonus : sItemBonusStore)          _itemBonusLists[bonus->BonusListID].push_back(bonus); @@ -1245,6 +1255,24 @@ HeirloomEntry const* DB2Manager::GetHeirloomByItemId(uint32 itemId) const      return nullptr;  } +std::vector<uint32> const* DB2Manager::GetGlyphBindableSpells(uint32 glyphPropertiesId) const +{ +    auto itr = _glyphBindableSpells.find(glyphPropertiesId); +    if (itr != _glyphBindableSpells.end()) +        return &itr->second; + +    return nullptr; +} + +std::vector<uint32> const* DB2Manager::GetGlyphRequiredSpecs(uint32 glyphPropertiesId) const +{ +    auto itr = _glyphRequiredSpecs.find(glyphPropertiesId); +    if (itr != _glyphRequiredSpecs.end()) +        return &itr->second; + +    return nullptr; +} +  DB2Manager::ItemBonusList const* DB2Manager::GetItemBonusList(uint32 bonusListId) const  {      auto itr = _itemBonusLists.find(bonusListId); diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h index b8e5569ec9b..e435554be18 100644 --- a/src/server/game/DataStores/DB2Stores.h +++ b/src/server/game/DataStores/DB2Stores.h @@ -237,6 +237,8 @@ public:      typedef std::map<std::tuple<uint32, uint8, uint8, uint8>, EmotesTextSoundEntry const*> EmotesTextSoundContainer;      typedef std::unordered_map<uint32, std::vector<uint32>> FactionTeamContainer;      typedef std::unordered_map<uint32, HeirloomEntry const*> HeirloomItemsContainer; +    typedef std::unordered_map<uint32 /*glyphPropertiesId*/, std::vector<uint32>> GlyphBindableSpellsContainer; +    typedef std::unordered_map<uint32 /*glyphPropertiesId*/, std::vector<uint32>> GlyphRequiredSpecsContainer;      typedef std::vector<ItemBonusEntry const*> ItemBonusList;      typedef std::unordered_map<uint32 /*bonusListId*/, ItemBonusList> ItemBonusListContainer;      typedef std::unordered_map<int16, uint32> ItemBonusListLevelDeltaContainer; @@ -291,6 +293,8 @@ public:      EmotesTextSoundEntry const* GetTextSoundEmoteFor(uint32 emote, uint8 race, uint8 gender, uint8 class_) const;      std::vector<uint32> const* GetFactionTeamList(uint32 faction) const;      HeirloomEntry const* GetHeirloomByItemId(uint32 itemId) const; +    std::vector<uint32> const* GetGlyphBindableSpells(uint32 glyphPropertiesId) const; +    std::vector<uint32> const* GetGlyphRequiredSpecs(uint32 glyphPropertiesId) const;      ItemBonusList const* GetItemBonusList(uint32 bonusListId) const;      uint32 GetItemBonusListForItemLevelDelta(int16 delta) const;      std::set<uint32> GetItemBonusTree(uint32 itemId, uint32 itemBonusTreeMod) const; @@ -348,6 +352,8 @@ private:      EmotesTextSoundContainer _emoteTextSounds;      FactionTeamContainer _factionTeams;      HeirloomItemsContainer _heirlooms; +    GlyphBindableSpellsContainer _glyphBindableSpells; +    GlyphRequiredSpecsContainer _glyphRequiredSpecs;      ItemBonusListContainer _itemBonusLists;      ItemBonusListLevelDeltaContainer _itemLevelDeltaToBonusListContainer;      ItemBonusTreeContainer _itemBonusTrees; diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h index 627b2f6b916..319d69818f0 100644 --- a/src/server/game/DataStores/DB2Structure.h +++ b/src/server/game/DataStores/DB2Structure.h @@ -1108,6 +1108,13 @@ struct GemPropertiesEntry      uint16 MinItemLevel;  }; +struct GlyphBindableSpellEntry +{ +    uint32 ID; +    uint32 SpellID; +    uint16 GlyphPropertiesID; +}; +  struct GlyphPropertiesEntry  {      uint32 ID; @@ -1117,6 +1124,13 @@ struct GlyphPropertiesEntry      uint8 GlyphExclusiveCategoryID;  }; +struct GlyphRequiredSpecEntry +{ +    uint32 ID; +    uint16 GlyphPropertiesID; +    uint16 ChrSpecializationID; +}; +  struct GuildColorBackgroundEntry  {      uint32 ID; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 68a4f60e72f..491397a5a70 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -256,7 +256,6 @@ Player::Player(WorldSession* session) : Unit(true)      m_prevMapDifficulty = DIFFICULTY_NORMAL_RAID;      m_lastPotionId = 0; -    _talentMgr = new PlayerTalentInfo();      for (uint8 i = 0; i < BASEMOD_END; ++i)      { @@ -352,8 +351,6 @@ Player::~Player()      for (PlayerSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr)          delete itr->second; -    delete _talentMgr; -      //all mailed items should be deleted, also all mail should be deallocated      for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); ++itr)          delete *itr; @@ -4077,6 +4074,10 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe              stmt->setUInt64(0, guid);              trans->Append(stmt); +            stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_GLYPHS); +            stmt->setUInt64(0, guid); +            trans->Append(stmt); +              stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_QUESTSTATUS_DAILY);              stmt->setUInt64(0, guid);              trans->Append(stmt); @@ -17638,7 +17639,9 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder)      LearnSpecializationSpells(); +    _LoadGlyphs(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GLYPHS));      _LoadAuras(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_AURAS), holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_AURA_EFFECTS), time_diff); +    _LoadGlyphAuras();      // add ghost flag (must be after aura load: PLAYER_FLAGS_GHOST set in aura)      if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST))          m_deathState = DEAD; @@ -18002,6 +18005,12 @@ void Player::_LoadAuras(PreparedQueryResult auraResult, PreparedQueryResult effe      }  } +void Player::_LoadGlyphAuras() +{ +    for (uint32 glyphId : GetGlyphs(GetActiveTalentGroup())) +        CastSpell(this, sGlyphPropertiesStore.AssertEntry(glyphId)->SpellID, true); +} +  void Player::LoadCorpse(PreparedQueryResult result)  {      if (IsAlive() || HasAtLoginFlag(AT_LOGIN_RESURRECT)) @@ -19657,6 +19666,7 @@ void Player::SaveToDB(bool create /*=false*/)      _SaveWeeklyQuestStatus(trans);      _SaveSeasonalQuestStatus(trans);      _SaveMonthlyQuestStatus(trans); +    _SaveGlyphs(trans);      _SaveTalents(trans);      _SaveSpells(trans);      GetSpellHistory()->SaveToDB<Player>(trans); @@ -23078,6 +23088,17 @@ void Player::SendInitialPacketsBeforeAddToMap()      GetSpellHistory()->WritePacket(&sendSpellCharges);      SendDirectMessage(sendSpellCharges.Write()); +    WorldPackets::Talent::ActiveGlyphs activeGlyphs; +    activeGlyphs.Glyphs.reserve(GetGlyphs(GetActiveTalentGroup()).size()); +    for (uint32 glyphId : GetGlyphs(GetActiveTalentGroup())) +        if (std::vector<uint32> const* bindableSpells = sDB2Manager.GetGlyphBindableSpells(glyphId)) +            for (uint32 bindableSpell : *bindableSpells) +                if (HasSpell(bindableSpell) && m_overrideSpells.find(bindableSpell) == m_overrideSpells.end()) +                    activeGlyphs.Glyphs.emplace_back(uint32(bindableSpell), uint16(glyphId)); + +    activeGlyphs.IsFullUpdate = true; +    SendDirectMessage(activeGlyphs.Write()); +      /// SMSG_ACTION_BUTTONS      SendInitialActionButtons(); @@ -25882,6 +25903,51 @@ void Player::SetMap(Map* map)      m_mapRef.link(map, this);  } +void Player::_LoadGlyphs(PreparedQueryResult result) +{ +    // SELECT talentGroup, glyphId from character_glyphs WHERE guid = ? +    if (!result) +        return; + +    do +    { +        Field* fields = result->Fetch(); + +        uint8 spec = fields[0].GetUInt8(); +        if (spec >= MAX_SPECIALIZATIONS || !sDB2Manager.GetChrSpecializationByIndex(getClass(), spec)) +            continue; + +        uint16 glyphId = fields[1].GetUInt16(); +        if (!sGlyphPropertiesStore.LookupEntry(glyphId)) +            continue; + +        GetGlyphs(spec).push_back(glyphId); + +    } while (result->NextRow()); +} + +void Player::_SaveGlyphs(SQLTransaction& trans) const +{ +    PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_GLYPHS); +    stmt->setUInt64(0, GetGUID().GetCounter()); +    trans->Append(stmt); + +    for (uint8 spec = 0; spec < MAX_SPECIALIZATIONS; ++spec) +    { +        for (uint32 glyphId : GetGlyphs(spec)) +        { +            uint8 index = 0; + +            stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_GLYPHS); +            stmt->setUInt64(index++, GetGUID().GetCounter()); +            stmt->setUInt8(index++, spec); +            stmt->setUInt16(index++, uint16(glyphId)); + +            trans->Append(stmt); +        } +    } +} +  void Player::_LoadTalents(PreparedQueryResult result)  {      // SetPQuery(PLAYER_LOGIN_QUERY_LOADTALENTS, "SELECT spell, spec FROM character_talent WHERE guid = '%u'", GUID_LOPART(m_guid)); @@ -25985,6 +26051,9 @@ void Player::ActivateTalentGroup(ChrSpecializationEntry const* spec)      // Remove spec specific spells      RemoveSpecializationSpells(); +    for (uint32 glyphId : GetGlyphs(GetActiveTalentGroup())) +        RemoveAurasDueToSpell(sGlyphPropertiesStore.AssertEntry(glyphId)->SpellID); +      SetActiveTalentGroup(spec->OrderIndex);      SetUInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID, spec->ID);      if (!GetPrimarySpecialization()) @@ -26041,6 +26110,20 @@ void Player::ActivateTalentGroup(ChrSpecializationEntry const* spec)      for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i)          if (Item* equippedItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))              SetVisibleItemSlot(i, equippedItem); + +    for (uint32 glyphId : GetGlyphs(spec->OrderIndex)) +        CastSpell(this, sGlyphPropertiesStore.AssertEntry(glyphId)->SpellID, true); + +    WorldPackets::Talent::ActiveGlyphs activeGlyphs; +    activeGlyphs.Glyphs.reserve(GetGlyphs(spec->OrderIndex).size()); +    for (uint32 glyphId : GetGlyphs(spec->OrderIndex)) +        if (std::vector<uint32> const* bindableSpells = sDB2Manager.GetGlyphBindableSpells(glyphId)) +            for (uint32 bindableSpell : *bindableSpells) +                if (HasSpell(bindableSpell) && m_overrideSpells.find(bindableSpell) == m_overrideSpells.end()) +                    activeGlyphs.Glyphs.emplace_back(uint32(bindableSpell), uint16(glyphId)); + +    activeGlyphs.IsFullUpdate = true; +    SendDirectMessage(activeGlyphs.Write());  }  void Player::ResetTimeSync() diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index fd044cad8c2..1a6481d296a 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -972,6 +972,7 @@ enum PlayerLoginQueryIndex      PLAYER_LOGIN_QUERY_LOAD_EQUIPMENT_SETS,      PLAYER_LOGIN_QUERY_LOAD_TRANSMOG_OUTFITS,      PLAYER_LOGIN_QUERY_LOAD_BG_DATA, +    PLAYER_LOGIN_QUERY_LOAD_GLYPHS,      PLAYER_LOGIN_QUERY_LOAD_TALENTS,      PLAYER_LOGIN_QUERY_LOAD_ACCOUNT_DATA,      PLAYER_LOGIN_QUERY_LOAD_SKILLS, @@ -1173,21 +1174,22 @@ static uint32 const DefaultTalentRowLevels[MAX_TALENT_TIERS] = { 15, 30, 45, 60,  static uint32 const DKTalentRowLevels[MAX_TALENT_TIERS] = { 57, 58, 59, 60, 75, 90, 100 };  static uint32 const DHTalentRowLevels[MAX_TALENT_TIERS] = { 99, 100, 102, 104, 106, 108, 110 }; -struct TC_GAME_API PlayerTalentInfo +struct TC_GAME_API SpecializationInfo  { -    PlayerTalentInfo() : ResetTalentsCost(0), ResetTalentsTime(0), PrimarySpecialization(0), ActiveGroup(0) +    SpecializationInfo() : ResetTalentsCost(0), ResetTalentsTime(0), PrimarySpecialization(0), ActiveGroup(0)      {      }      PlayerTalentMap Talents[MAX_SPECIALIZATIONS]; +    std::vector<uint32> Glyphs[MAX_SPECIALIZATIONS];      uint32 ResetTalentsCost;      time_t ResetTalentsTime;      uint32 PrimarySpecialization;      uint8 ActiveGroup;  private: -    PlayerTalentInfo(PlayerTalentInfo const&) = delete; -    PlayerTalentInfo& operator=(PlayerTalentInfo const&) = delete; +    SpecializationInfo(SpecializationInfo const&) = delete; +    SpecializationInfo& operator=(SpecializationInfo const&) = delete;  };  class TC_GAME_API Player : public Unit, public GridObject<Player> @@ -1767,14 +1769,14 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>          uint32 GetLootSpecId() const { return GetUInt32Value(PLAYER_FIELD_LOOT_SPEC_ID); }          // Talents -        uint32 GetTalentResetCost() const { return _talentMgr->ResetTalentsCost; } -        void SetTalentResetCost(uint32 cost)  { _talentMgr->ResetTalentsCost = cost; } -        time_t GetTalentResetTime() const { return _talentMgr->ResetTalentsTime; } -        void SetTalentResetTime(time_t time_)  { _talentMgr->ResetTalentsTime = time_; } -        uint32 GetPrimarySpecialization() const { return _talentMgr->PrimarySpecialization; } -        void SetPrimarySpecialization(uint32 spec) { _talentMgr->PrimarySpecialization = spec; } -        uint8 GetActiveTalentGroup() const { return _talentMgr->ActiveGroup; } -        void SetActiveTalentGroup(uint8 group){ _talentMgr->ActiveGroup = group; } +        uint32 GetTalentResetCost() const { return _specializationInfo.ResetTalentsCost; } +        void SetTalentResetCost(uint32 cost)  { _specializationInfo.ResetTalentsCost = cost; } +        time_t GetTalentResetTime() const { return _specializationInfo.ResetTalentsTime; } +        void SetTalentResetTime(time_t time_)  { _specializationInfo.ResetTalentsTime = time_; } +        uint32 GetPrimarySpecialization() const { return _specializationInfo.PrimarySpecialization; } +        void SetPrimarySpecialization(uint32 spec) { _specializationInfo.PrimarySpecialization = spec; } +        uint8 GetActiveTalentGroup() const { return _specializationInfo.ActiveGroup; } +        void SetActiveTalentGroup(uint8 group){ _specializationInfo.ActiveGroup = group; }          uint32 GetDefaultSpecId() const;          bool ResetTalents(bool noCost = false); @@ -1791,8 +1793,10 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>          // Dual Spec          void ActivateTalentGroup(ChrSpecializationEntry const* spec); -        PlayerTalentMap const* GetTalentMap(uint8 spec) const { return &_talentMgr->Talents[spec]; } -        PlayerTalentMap* GetTalentMap(uint8 spec) { return &_talentMgr->Talents[spec]; } +        PlayerTalentMap const* GetTalentMap(uint8 spec) const { return &_specializationInfo.Talents[spec]; } +        PlayerTalentMap* GetTalentMap(uint8 spec) { return &_specializationInfo.Talents[spec]; } +        std::vector<uint32> const& GetGlyphs(uint8 spec) const { return _specializationInfo.Glyphs[spec]; } +        std::vector<uint32>& GetGlyphs(uint8 spec) { return _specializationInfo.Glyphs[spec]; }          ActionButtonList const& GetActionButtons() const { return m_actionButtons; }          uint32 GetFreePrimaryProfessionPoints() const { return GetUInt32Value(PLAYER_CHARACTER_POINTS); } @@ -2522,6 +2526,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>          void _LoadActions(PreparedQueryResult result);          void _LoadAuras(PreparedQueryResult auraResult, PreparedQueryResult effectResult, uint32 timediff); +        void _LoadGlyphAuras();          void _LoadBoundInstances(PreparedQueryResult result);          void _LoadInventory(PreparedQueryResult result, PreparedQueryResult artifactsResult, uint32 timeDiff);          void _LoadVoidStorage(PreparedQueryResult result); @@ -2545,6 +2550,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>          void _LoadEquipmentSets(PreparedQueryResult result);          void _LoadTransmogOutfits(PreparedQueryResult result);          void _LoadBGData(PreparedQueryResult result); +        void _LoadGlyphs(PreparedQueryResult result);          void _LoadTalents(PreparedQueryResult result);          void _LoadInstanceTimeRestrictions(PreparedQueryResult result);          void _LoadCurrency(PreparedQueryResult result); @@ -2568,6 +2574,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>          void _SaveSpells(SQLTransaction& trans);          void _SaveEquipmentSets(SQLTransaction& trans);          void _SaveBGData(SQLTransaction& trans); +        void _SaveGlyphs(SQLTransaction& trans) const;          void _SaveTalents(SQLTransaction& trans);          void _SaveStats(SQLTransaction& trans) const;          void _SaveInstanceTimeRestrictions(SQLTransaction& trans); @@ -2648,7 +2655,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>          std::unordered_map<uint32 /*overridenSpellId*/, std::unordered_set<uint32> /*newSpellId*/> m_overrideSpells;          uint32 m_lastPotionId;                              // last used health/mana potion in combat, that block next potion use -        PlayerTalentInfo* _talentMgr; +        SpecializationInfo _specializationInfo;          ActionButtonList m_actionButtons; diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index efbd3bcdcef..10f601f91b8 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -207,6 +207,10 @@ bool LoginQueryHolder::Initialize()      stmt->setUInt64(0, lowGuid);      res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_BG_DATA, stmt); +    stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GLYPHS); +    stmt->setUInt64(0, lowGuid); +    res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_GLYPHS, stmt); +      stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_TALENTS);      stmt->setUInt64(0, lowGuid);      res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_TALENTS, stmt); diff --git a/src/server/game/Server/Packets/TalentPackets.cpp b/src/server/game/Server/Packets/TalentPackets.cpp index 1069b8a89f7..c6f3b95a02f 100644 --- a/src/server/game/Server/Packets/TalentPackets.cpp +++ b/src/server/game/Server/Packets/TalentPackets.cpp @@ -70,3 +70,22 @@ WorldPacket const* WorldPackets::Talent::LearnTalentsFailed::Write()      return &_worldPacket;  } + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Talent::GlyphBinding const& glyphBinding) +{ +    data << uint32(glyphBinding.SpellID); +    data << uint16(glyphBinding.GlyphID); +    return data; +} + +WorldPacket const* WorldPackets::Talent::ActiveGlyphs::Write() +{ +    _worldPacket << uint32(Glyphs.size()); +    for (GlyphBinding const& glyph : Glyphs) +        _worldPacket << glyph; + +    _worldPacket.WriteBit(IsFullUpdate); +    _worldPacket.FlushBits(); + +    return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/TalentPackets.h b/src/server/game/Server/Packets/TalentPackets.h index 57893bb94a4..92c2e1efdce 100644 --- a/src/server/game/Server/Packets/TalentPackets.h +++ b/src/server/game/Server/Packets/TalentPackets.h @@ -93,6 +93,25 @@ namespace WorldPackets              int32 SpellID = 0;              std::vector<uint16> Talents;          }; + +        struct GlyphBinding +        { +            GlyphBinding(uint32 spellId = 0, uint16 glyphId = 0) : SpellID(spellId), GlyphID(glyphId) { } + +            uint32 SpellID; +            uint16 GlyphID; +        }; + +        class ActiveGlyphs final : public ServerPacket +        { +        public: +            ActiveGlyphs() : ServerPacket(SMSG_ACTIVE_GLYPHS) { } + +            WorldPacket const* Write() override; + +            std::vector<GlyphBinding> Glyphs; +            bool IsFullUpdate = false; +        };      }  } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 9a6d7adba71..96ce155de11 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -837,7 +837,7 @@ void OpcodeTable::Initialize()      DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACHIEVEMENT_DELETED,                     STATUS_NEVER,        CONNECTION_TYPE_INSTANCE);      DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACHIEVEMENT_EARNED,                      STATUS_NEVER,        CONNECTION_TYPE_INSTANCE);      DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACTIVATE_TAXI_REPLY,                     STATUS_NEVER,        CONNECTION_TYPE_REALM); -    DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACTIVE_GLYPHS,                           STATUS_UNHANDLED,    CONNECTION_TYPE_REALM); +    DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACTIVE_GLYPHS,                           STATUS_NEVER,        CONNECTION_TYPE_REALM);      DEFINE_SERVER_OPCODE_HANDLER(SMSG_ADD_BATTLENET_FRIEND_RESPONSE,           STATUS_UNHANDLED,    CONNECTION_TYPE_REALM);      DEFINE_SERVER_OPCODE_HANDLER(SMSG_ADD_ITEM_PASSIVE,                        STATUS_UNHANDLED,    CONNECTION_TYPE_REALM);      DEFINE_SERVER_OPCODE_HANDLER(SMSG_ADD_LOSS_OF_CONTROL,                     STATUS_UNHANDLED,    CONNECTION_TYPE_REALM); diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index b304491ba31..d6fa46bb267 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -5100,10 +5100,60 @@ SpellCastResult Spell::CheckCast(bool strict)              }              case SPELL_EFFECT_APPLY_GLYPH:              { -                uint32 glyphId = effect->MiscValue; -                if (GlyphPropertiesEntry const* gp = sGlyphPropertiesStore.LookupEntry(glyphId)) -                    if (m_caster->HasAura(gp->SpellID)) -                        return SPELL_FAILED_UNIQUE_GLYPH; +                if (m_caster->GetTypeId() != TYPEID_PLAYER) +                    return SPELL_FAILED_GLYPH_NO_SPEC; + +                Player* caster = m_caster->ToPlayer(); +                if (!caster->HasSpell(m_misc.SpellId)) +                    return SPELL_FAILED_NOT_KNOWN; + +                if (uint32 glyphId = effect->MiscValue) +                { +                    GlyphPropertiesEntry const* glyphProperties = sGlyphPropertiesStore.LookupEntry(glyphId); +                    if (!glyphProperties) +                        return SPELL_FAILED_INVALID_GLYPH; + +                    std::vector<uint32> const* glyphBindableSpells = sDB2Manager.GetGlyphBindableSpells(glyphId); +                    if (!glyphBindableSpells) +                        return SPELL_FAILED_INVALID_GLYPH; + +                    if (std::find(glyphBindableSpells->begin(), glyphBindableSpells->end(), m_misc.SpellId) == glyphBindableSpells->end()) +                        return SPELL_FAILED_INVALID_GLYPH; + +                    if (std::vector<uint32> const* glyphRequiredSpecs = sDB2Manager.GetGlyphRequiredSpecs(glyphId)) +                    { +                        if (!caster->GetUInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID)) +                            return SPELL_FAILED_GLYPH_NO_SPEC; + +                        if (std::find(glyphRequiredSpecs->begin(), glyphRequiredSpecs->end(), caster->GetUInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID)) == glyphRequiredSpecs->end()) +                            return SPELL_FAILED_GLYPH_INVALID_SPEC; +                    } + +                    uint32 replacedGlyph = 0; +                    for (uint32 activeGlyphId : caster->GetGlyphs(caster->GetActiveTalentGroup())) +                    { +                        if (std::vector<uint32> const* activeGlyphBindableSpells = sDB2Manager.GetGlyphBindableSpells(activeGlyphId)) +                        { +                            if (std::find(activeGlyphBindableSpells->begin(), activeGlyphBindableSpells->end(), m_misc.SpellId) != activeGlyphBindableSpells->end()) +                            { +                                replacedGlyph = activeGlyphId; +                                break; +                            } +                        } +                    } + +                    for (uint32 activeGlyphId : caster->GetGlyphs(caster->GetActiveTalentGroup())) +                    { +                        if (activeGlyphId == replacedGlyph) +                            continue; + +                        if (activeGlyphId == glyphId) +                            return SPELL_FAILED_UNIQUE_GLYPH; + +                        if (sGlyphPropertiesStore.AssertEntry(activeGlyphId)->GlyphExclusiveCategoryID == glyphProperties->GlyphExclusiveCategoryID) +                            return SPELL_FAILED_GLYPH_EXCLUSIVE_CATEGORY; +                    } +                }                  break;              }              case SPELL_EFFECT_FEED_PET: diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 33e3107dc03..1fa5fa6aa08 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -570,7 +570,9 @@ class TC_GAME_API Spell          {              // Alternate names for this value              uint32 TalentId; -            uint32 GlyphSlot; + +            // SPELL_EFFECT_APPLY_GLYPH +            uint32 SpellId;              // SPELL_EFFECT_TALENT_SPEC_SELECT              uint32 SpecializationId; diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index e2656495467..0df4abea54f 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -61,6 +61,7 @@  #include "DuelPackets.h"  #include "MiscPackets.h"  #include "SpellPackets.h" +#include "TalentPackets.h"  pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=  { @@ -3923,6 +3924,40 @@ void Spell::EffectApplyGlyph(SpellEffIndex /*effIndex*/)      Player* player = m_caster->ToPlayer();      if (!player)          return; + +    std::vector<uint32>& glyphs = player->GetGlyphs(player->GetActiveTalentGroup()); +    std::size_t replacedGlyph = glyphs.size(); +    for (std::size_t i = 0; i < glyphs.size(); ++i) +    { +        if (std::vector<uint32> const* activeGlyphBindableSpells = sDB2Manager.GetGlyphBindableSpells(glyphs[i])) +        { +            if (std::find(activeGlyphBindableSpells->begin(), activeGlyphBindableSpells->end(), m_misc.SpellId) != activeGlyphBindableSpells->end()) +            { +                replacedGlyph = i; +                player->RemoveAurasDueToSpell(sGlyphPropertiesStore.AssertEntry(glyphs[i])->SpellID); +                break; +            } +        } +    } + +    uint32 glyphId = effectInfo->MiscValue; +    if (replacedGlyph < glyphs.size()) +    { +        if (glyphId) +            glyphs[replacedGlyph] = glyphId; +        else +            glyphs.erase(glyphs.begin() + replacedGlyph); +    } +    else if (glyphId) +        glyphs.push_back(glyphId); + +    if (GlyphPropertiesEntry const* glyphProperties = sGlyphPropertiesStore.LookupEntry(glyphId)) +        player->CastSpell(player, glyphProperties->SpellID, true); + +    WorldPackets::Talent::ActiveGlyphs activeGlyphs; +    activeGlyphs.Glyphs.emplace_back(m_misc.SpellId, uint16(glyphId)); +    activeGlyphs.IsFullUpdate = false; +    player->SendDirectMessage(activeGlyphs.Write());  }  void Spell::EffectEnchantHeldItem(SpellEffIndex /*effIndex*/)  | 
