diff options
author | Shauren <shauren.trinity@gmail.com> | 2016-08-25 19:12:00 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2016-08-25 19:12:00 +0200 |
commit | a727a99e34a1a50b4b7589ab549751caa63282b0 (patch) | |
tree | 65c60c621ee2a8452acc03292c28e296897fbea9 /src/server | |
parent | e2f133902f8a37984e462a807a30a6663448d01e (diff) |
Core/Players: Implemented new glyph system
Diffstat (limited to 'src/server')
-rw-r--r-- | src/server/database/Database/Implementation/CharacterDatabase.cpp | 3 | ||||
-rw-r--r-- | src/server/database/Database/Implementation/CharacterDatabase.h | 3 | ||||
-rw-r--r-- | src/server/database/Database/Implementation/HotfixDatabase.cpp | 6 | ||||
-rw-r--r-- | src/server/database/Database/Implementation/HotfixDatabase.h | 4 | ||||
-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 |
16 files changed, 307 insertions, 24 deletions
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index 0380cd45c2f..364b98d545d 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp @@ -135,6 +135,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() "appearance5, appearance6, appearance7, appearance8, appearance9, appearance10, appearance11, appearance12, appearance13, appearance14, appearance15, appearance16, " "appearance17, appearance18, mainHandEnchant, offHandEnchant FROM character_transmog_outfits WHERE guid = ? ORDER BY setindex", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_BGDATA, "SELECT instanceId, team, joinX, joinY, joinZ, joinO, joinMapId, taxiStart, taxiEnd, mountSpell FROM character_battleground_data WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_GLYPHS, "SELECT talentGroup, glyphId FROM character_glyphs WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_TALENTS, "SELECT spell, talentGroup FROM character_talent WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_SKILLS, "SELECT skill, value, max FROM character_skills WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_RANDOMBG, "SELECT guid FROM character_battleground_random WHERE guid = ?", CONNECTION_ASYNC); @@ -583,6 +584,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_CHAR_TRANSMOG_OUTFITS, "DELETE FROM character_transmog_outfits WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_GUILD_EVENTLOG_BY_PLAYER, "DELETE FROM guild_eventlog WHERE PlayerGuid1 = ? OR PlayerGuid2 = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_GUILD_BANK_EVENTLOG_BY_PLAYER, "DELETE FROM guild_bank_eventlog WHERE PlayerGuid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHAR_GLYPHS, "DELETE FROM character_glyphs WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_TALENT, "DELETE FROM character_talent WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_SKILLS, "DELETE FROM character_skills WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_CHAR_MONEY, "UPDATE characters SET money = ? WHERE guid = ?", CONNECTION_ASYNC); @@ -611,6 +613,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() "spellPower, resilience) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_PETITION_BY_OWNER, "DELETE FROM petition WHERE ownerguid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_PETITION_SIGNATURE_BY_OWNER, "DELETE FROM petition_sign WHERE ownerguid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHAR_GLYPHS, "INSERT INTO character_glyphs VALUES(?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_TALENT_BY_SPELL_SPEC, "DELETE FROM character_talent WHERE guid = ? and spell = ? and talentGroup = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_CHAR_TALENT, "INSERT INTO character_talent (guid, spell, talentGroup) VALUES (?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_ACTION_EXCEPT_SPEC, "DELETE FROM character_action WHERE spec<>? AND guid = ?", CONNECTION_ASYNC); diff --git a/src/server/database/Database/Implementation/CharacterDatabase.h b/src/server/database/Database/Implementation/CharacterDatabase.h index a8c26cdc316..c94cbdedd04 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.h +++ b/src/server/database/Database/Implementation/CharacterDatabase.h @@ -111,6 +111,7 @@ enum CharacterDatabaseStatements CHAR_SEL_CHARACTER_EQUIPMENTSETS, CHAR_SEL_CHARACTER_TRANSMOG_OUTFITS, CHAR_SEL_CHARACTER_BGDATA, + CHAR_SEL_CHARACTER_GLYPHS, CHAR_SEL_CHARACTER_TALENTS, CHAR_SEL_CHARACTER_SKILLS, CHAR_SEL_CHARACTER_RANDOMBG, @@ -487,6 +488,7 @@ enum CharacterDatabaseStatements CHAR_DEL_CHAR_TRANSMOG_OUTFITS, CHAR_DEL_GUILD_EVENTLOG_BY_PLAYER, CHAR_DEL_GUILD_BANK_EVENTLOG_BY_PLAYER, + CHAR_DEL_CHAR_GLYPHS, CHAR_DEL_CHAR_TALENT, CHAR_DEL_CHAR_SKILLS, CHAR_UPD_CHAR_MONEY, @@ -513,6 +515,7 @@ enum CharacterDatabaseStatements CHAR_INS_CHAR_STATS, CHAR_DEL_PETITION_BY_OWNER, CHAR_DEL_PETITION_SIGNATURE_BY_OWNER, + CHAR_INS_CHAR_GLYPHS, CHAR_DEL_CHAR_TALENT_BY_SPELL_SPEC, CHAR_INS_CHAR_TALENT, CHAR_DEL_CHAR_ACTION_EXCEPT_SPEC, diff --git a/src/server/database/Database/Implementation/HotfixDatabase.cpp b/src/server/database/Database/Implementation/HotfixDatabase.cpp index b62d54626f6..66fd71cd5f9 100644 --- a/src/server/database/Database/Implementation/HotfixDatabase.cpp +++ b/src/server/database/Database/Implementation/HotfixDatabase.cpp @@ -344,10 +344,16 @@ void HotfixDatabaseConnection::DoPrepareStatements() // GemProperties.db2 PrepareStatement(HOTFIX_SEL_GEM_PROPERTIES, "SELECT ID, Type, EnchantID, MinItemLevel FROM gem_properties ORDER BY ID DESC", CONNECTION_SYNCH); + // GlyphBindableSpell.db2 + PrepareStatement(HOTFIX_SEL_GLYPH_BINDABLE_SPELL, "SELECT ID, SpellID, GlyphPropertiesID FROM glyph_bindable_spell ORDER BY ID DESC", CONNECTION_SYNCH); + // GlyphProperties.db2 PrepareStatement(HOTFIX_SEL_GLYPH_PROPERTIES, "SELECT ID, SpellID, SpellIconID, Type, GlyphExclusiveCategoryID FROM glyph_properties" " ORDER BY ID DESC", CONNECTION_SYNCH); + // GlyphRequiredSpec.db2 + PrepareStatement(HOTFIX_SEL_GLYPH_REQUIRED_SPEC, "SELECT ID, GlyphPropertiesID, ChrSpecializationID FROM glyph_required_spec ORDER BY ID DESC", CONNECTION_SYNCH); + // GuildColorBackground.db2 PrepareStatement(HOTFIX_SEL_GUILD_COLOR_BACKGROUND, "SELECT ID, Red, Green, Blue FROM guild_color_background ORDER BY ID DESC", CONNECTION_SYNCH); diff --git a/src/server/database/Database/Implementation/HotfixDatabase.h b/src/server/database/Database/Implementation/HotfixDatabase.h index f209c0d569b..4519255a299 100644 --- a/src/server/database/Database/Implementation/HotfixDatabase.h +++ b/src/server/database/Database/Implementation/HotfixDatabase.h @@ -196,8 +196,12 @@ enum HotfixDatabaseStatements HOTFIX_SEL_GEM_PROPERTIES, + HOTFIX_SEL_GLYPH_BINDABLE_SPELL, + HOTFIX_SEL_GLYPH_PROPERTIES, + HOTFIX_SEL_GLYPH_REQUIRED_SPEC, + HOTFIX_SEL_GUILD_COLOR_BACKGROUND, HOTFIX_SEL_GUILD_COLOR_BORDER, 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*/) |