diff options
Diffstat (limited to 'src')
22 files changed, 327 insertions, 379 deletions
diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index 35956191f5e..d1aa2f77cf8 100644 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -1070,7 +1070,7 @@ void Battleground::AddPlayer(Player* player) BattlegroundPlayer bp; bp.OfflineRemoveTime = 0; bp.Team = team; - bp.ActiveSpec = player->GetTalentSpec(player->GetActiveSpec()); + bp.ActiveSpec = player->GetActiveTalentSpec(); // Add to list/maps m_Players[player->GetGUID()] = bp; diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp index 598c2e5d5f3..333b7f5a2c2 100644 --- a/src/server/game/DataStores/DBCStores.cpp +++ b/src/server/game/DataStores/DBCStores.cpp @@ -163,6 +163,8 @@ DBCStorage <MapEntry> sMapStore(MapEntryfmt); DBCStorage <MapDifficultyEntry> sMapDifficultyStore(MapDifficultyEntryfmt); // only for loading MapDifficultyMap sMapDifficultyMap; +DBCStorage <MinorTalentEntry> sMinorTalentStore(MinorTalentEntryfmt); + DBCStorage <MovieEntry> sMovieStore(MovieEntryfmt); DBCStorage <MountCapabilityEntry> sMountCapabilityStore(MountCapabilityfmt); DBCStorage <MountTypeEntry> sMountTypeStore(MountTypefmt); @@ -570,7 +572,7 @@ void LoadDBCStores(const std::string& dataPath) LoadDBC(availableDbcLocales, bad_dbc_files, sSpellShapeshiftStore, dbcPath, "SpellShapeshift.dbc");//19116 LoadDBC(availableDbcLocales, bad_dbc_files, sSpellShapeshiftFormStore, dbcPath, "SpellShapeshiftForm.dbc");//19116 //LoadDBC(availableDbcLocales, bad_dbc_files, sStableSlotPricesStore, dbcPath, "StableSlotPrices.dbc"); - LoadDBC(availableDbcLocales, bad_dbc_files, sSummonPropertiesStore, dbcPath, "SummonProperties.dbc");//15595 + LoadDBC(availableDbcLocales, bad_dbc_files, sSummonPropertiesStore, dbcPath, "SummonProperties.dbc");//19116 // Must be done when sSkillLineAbilityStore, sSpellStore, sSpellLevelsStore and sCreatureFamilyStore are all loaded /* TODO: Requires spells attributes from SpellMisc.db2 is loaded after dbc @@ -608,8 +610,6 @@ void LoadDBCStores(const std::string& dataPath) } */ - LoadDBC(availableDbcLocales, bad_dbc_files, sTalentStore, dbcPath, "Talent.dbc");//15595 - // Create Spelldifficulty searcher /* TODO: 6.x update to new spell diffs for (uint32 i = 0; i < sSpellDifficultyStore.GetNumRows(); ++i) @@ -640,6 +640,9 @@ void LoadDBCStores(const std::string& dataPath) sSpellMgr->SetSpellDifficultyId(uint32(newEntry.SpellID[x]), spellDiff->ID); }*/ + LoadDBC(availableDbcLocales, bad_dbc_files, sTalentStore, dbcPath, "Talent.dbc");//19116 + LoadDBC(availableDbcLocales, bad_dbc_files, sMinorTalentStore, dbcPath, "MinorTalent.dbc");//19116 + for (unsigned int i = 0; i < sTalentStore.GetNumRows(); ++i) { TalentEntry const* talentInfo = sTalentStore.LookupEntry(i); @@ -649,35 +652,6 @@ void LoadDBCStores(const std::string& dataPath) sTalentBySpellIDMap[talentInfo->SpellID] = talentInfo; } - // create talent spells set - /* TODO: 6.x update to new talent system - - // prepare fast data access to bit pos of talent ranks for use at inspecting - { - // now have all max ranks (and then bit amount used for store talent ranks in inspect) - for (uint32 talentTabId = 1; talentTabId < sTalentTabStore.GetNumRows(); ++talentTabId) - { - TalentTabEntry const* talentTabInfo = sTalentTabStore.LookupEntry(talentTabId); - if (!talentTabInfo) - continue; - - // prevent memory corruption; otherwise cls will become 12 below - if ((talentTabInfo->ClassMask & CLASSMASK_ALL_PLAYABLE) == 0) - continue; - - // store class talent tab pages - for (uint32 cls = 1; cls < MAX_CLASSES; ++cls) - if (talentTabInfo->ClassMask & (1 << (cls - 1))) - sTalentTabPages[cls][talentTabInfo->tabpage] = talentTabId; - } - } - - LoadDBC(availableDbcLocales, bad_dbc_files, sTalentTreePrimarySpellsStore, dbcPath, "TalentTreePrimarySpells.dbc"); - for (uint32 i = 0; i < sTalentTreePrimarySpellsStore.GetNumRows(); ++i) - if (TalentTreePrimarySpellsEntry const* talentSpell = sTalentTreePrimarySpellsStore.LookupEntry(i)) - sTalentTreePrimarySpellsMap[talentSpell->TalentTree].push_back(talentSpell->SpellId); - sTalentTreePrimarySpellsStore.Clear();*/ - LoadDBC(availableDbcLocales, bad_dbc_files, sTaxiNodesStore, dbcPath, "TaxiNodes.dbc");//15595 LoadDBC(availableDbcLocales, bad_dbc_files, sTaxiPathStore, dbcPath, "TaxiPath.dbc");//15595 for (uint32 i = 1; i < sTaxiPathStore.GetNumRows(); ++i) diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h index bb75a5ed6b5..c59782983ec 100644 --- a/src/server/game/DataStores/DBCStores.h +++ b/src/server/game/DataStores/DBCStores.h @@ -179,6 +179,7 @@ extern DBCStorage <LiquidTypeEntry> sLiquidTypeStore; extern DBCStorage <LockEntry> sLockStore; extern DBCStorage <MailTemplateEntry> sMailTemplateStore; extern DBCStorage <MapEntry> sMapStore; +extern DBCStorage <MinorTalentEntry> sMinorTalentStore; extern DBCStorage <MountCapabilityEntry> sMountCapabilityStore; extern DBCStorage <MountTypeEntry> sMountTypeStore; extern DBCStorage <NameGenEntry> sNameGenStore; diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index 2556c141d8d..e1f6344e067 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -1608,6 +1608,14 @@ struct MapDifficultyEntry //char* LockID; // 6 }; +struct MinorTalentEntry +{ + uint32 ID; // 0 + uint32 SpecID; // 1 + uint32 SpellID; // 2 + uint32 OrderIndex; // 3 +}; + struct MountCapabilityEntry { uint32 ID; // 0 diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h index 4c590e8e6ee..640d10aae19 100644 --- a/src/server/game/DataStores/DBCfmt.h +++ b/src/server/game/DataStores/DBCfmt.h @@ -107,6 +107,7 @@ char const PhaseGroupfmt[] = "nii"; char const MailTemplateEntryfmt[] = "nxs"; char const MapEntryfmt[] = "nxiixxsixxixiffxiiiixx"; char const MapDifficultyEntryfmt[] = "diisiix"; +char const MinorTalentEntryfmt[] = "niii"; char const MovieEntryfmt[] = "nxxxx"; char const MountCapabilityfmt[] = "niiiiiii"; char const MountTypefmt[] = "niiiiiiiiiiiiiiiiiiiiiiii"; @@ -156,9 +157,7 @@ char const SpellShapeshiftEntryfmt[] = "niiiix"; char const SpellShapeshiftFormfmt[] = "nxxiixiiiiiiiiiiiiixx"; char const StableSlotPricesfmt[] = "ni"; char const SummonPropertiesfmt[] = "niiiii"; -char const TalentEntryfmt[] = "niiiiiiiiixxixxxxxx"; -char const TalentTabEntryfmt[] = "nxxiiixxxii"; -char const TalentTreePrimarySpellsfmt[] = "diix"; +char const TalentEntryfmt[] = "niiiiiiiiix"; char const TaxiNodesEntryfmt[] = "nifffsiiixx"; char const TaxiPathEntryfmt[] = "niii"; char const TaxiPathNodeEntryfmt[] = "diiifffiiii"; diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index 0fe830f861e..52045f46472 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -341,7 +341,8 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c if (owner->GetGroup()) owner->SetGroupUpdateFlag(GROUP_UPDATE_PET); - owner->SendTalentsInfoData(true); + // TODO: 6.x remove/update pet talents + //owner->SendTalentsInfoData(true); if (getPetType() == HUNTER_PET) { @@ -1735,6 +1736,7 @@ void Pet::resetTalentsForAllPetsOf(Player* owner, Pet* onlinePet /*= NULL*/) void Pet::InitTalentForLevel() { + /* TODO: 6.x remove/update pet talents uint8 level = getLevel(); uint32 talentPointsForLevel = GetMaxTalentPointsForLevel(level); // Reset talents in case low level (on level down) or wrong points for level (hunter can unlearn TP increase talent) @@ -1745,6 +1747,7 @@ void Pet::InitTalentForLevel() if (!m_loading) GetOwner()->SendTalentsInfoData(true); + */ } uint8 Pet::GetMaxTalentPointsForLevel(uint8 level) diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index c0753f72942..e412aa43098 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -32,6 +32,7 @@ #include "ChannelMgr.h" #include "CharacterDatabaseCleaner.h" #include "CharacterPackets.h" +#include "TalentPackets.h" #include "Chat.h" #include "Common.h" #include "ConditionMgr.h" @@ -2985,7 +2986,7 @@ void Player::GiveLevel(uint8 level) void Player::InitTalentForLevel() { if (!GetSession()->PlayerLoading()) - SendTalentsInfoData(false); // update at client + SendTalentsInfoData(); // update at client } void Player::InitStatsForLevel(bool reapplyMods) @@ -3308,20 +3309,29 @@ void DeleteSpellFromAllPlayers(uint32 spellId) } } -bool Player::AddTalent(uint32 spellId, uint8 spec, bool learning) +bool Player::AddTalent(uint32 talentId, uint8 spec) { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); + TalentEntry const* talentEntry = sTalentStore.LookupEntry(talentId); + + // Check if talent exists in Talent.dbc + if (!talentEntry) + { + TC_LOG_ERROR("spells", "Player::addTalent: Talent %u not found", talentId); + return false; + } + + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talentEntry->SpellID); if (!spellInfo) { // do character spell book cleanup (all characters) - if (!IsInWorld() && !learning) // spell load case + if (!IsInWorld()) // spell load case { - TC_LOG_ERROR("spells", "Player::addSpell: Non-existed in SpellStore spell #%u request, deleting for all characters in `character_spell`.", spellId); + TC_LOG_ERROR("spells", "Player::addSpell: Non-existed in SpellStore spell #%u request, deleting for all characters in `character_spell`.", talentEntry->SpellID); - DeleteSpellFromAllPlayers(spellId); + DeleteSpellFromAllPlayers(talentEntry->SpellID); } else - TC_LOG_ERROR("spells", "Player::addSpell: Non-existed in SpellStore spell #%u request.", spellId); + TC_LOG_ERROR("spells", "Player::addSpell: Non-existed in SpellStore spell #%u request.", talentEntry->SpellID); return false; } @@ -3329,35 +3339,25 @@ bool Player::AddTalent(uint32 spellId, uint8 spec, bool learning) if (!SpellMgr::IsSpellValid(spellInfo, this, false)) { // do character spell book cleanup (all characters) - if (!IsInWorld() && !learning) // spell load case + if (!IsInWorld()) // spell load case { - TC_LOG_ERROR("spells", "Player::addTalent: Broken spell #%u learning not allowed, deleting for all characters in `character_talent`.", spellId); + TC_LOG_ERROR("spells", "Player::addTalent: Broken spell #%u learning not allowed, deleting for all characters in `character_talent`.", talentEntry->SpellID); - DeleteSpellFromAllPlayers(spellId); + DeleteSpellFromAllPlayers(talentEntry->SpellID); } else - TC_LOG_ERROR("spells", "Player::addTalent: Broken spell #%u learning not allowed.", spellId); - - return false; - } + TC_LOG_ERROR("spells", "Player::addTalent: Broken spell #%u learning not allowed.", talentEntry->SpellID); - TalentEntry const* talentEntry = GetTalentBySpellID(spellId); - - // Check if talent exists in Talent.dbc - if (!talentEntry) { - TC_LOG_ERROR("spells", "Player::addTalent: Learning non-talent spell %u not allowed.", spellId); return false; } - TalentSpecInfo* talentSpecInfo = GetTalentSpecInfo(spec); + TalentGroupInfo* talentGroupInfo = GetTalentGroupInfo(spec); // Check if player already has this talent - if (talentSpecInfo->HasTalent(spellId)) + if (talentGroupInfo->HasTalent(talentId)) return false; - talentSpecInfo->Talents[talentEntry->TierID].SpellID = spellId; - if (learning) - talentSpecInfo->Talents[talentEntry->TierID].State = PLAYERSPELL_NEW; + talentGroupInfo->Talents[talentEntry->TierID] = talentId; return true; } @@ -3707,7 +3707,7 @@ bool Player::IsNeedCastPassiveSpellAtLearn(SpellInfo const* spellInfo) const bool Player::IsCurrentSpecMasterySpell(SpellInfo const* spellInfo) const { - if (ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(GetTalentSpec(GetActiveSpec()))) + if (ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(GetActiveTalentSpec())) return spellInfo->Id == chrSpec->MasterySpellID[0] || spellInfo->Id == chrSpec->MasterySpellID[1]; return false; @@ -4121,7 +4121,8 @@ bool Player::ResetTalents(bool no_cost) RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true); - uint8 spec = GetActiveSpec(); + uint8 group = GetActiveTalentGroup(); + uint32 specID = GetActiveTalentSpec(); for (uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId) { @@ -4147,13 +4148,10 @@ bool Player::ResetTalents(bool no_cost) for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) if (_spellEntry->Effects[i].TriggerSpell > 0 && _spellEntry->Effects[i].Effect == SPELL_EFFECT_LEARN_SPELL) RemoveSpell(_spellEntry->Effects[i].TriggerSpell, true); - - // Reset talents store - GetTalentSpecInfo(spec)->Reset(); } // Remove all specialization specific spells and give default ones which were overriden - auto specSpells = sSpecializationSpellsBySpecStore.find(GetTalentSpec(GetActiveSpec())); + auto specSpells = sSpecializationSpellsBySpecStore.find(specID); if (specSpells != sSpecializationSpellsBySpecStore.end()) { for (auto it = specSpells->second.begin(); it != specSpells->second.end(); ++it) @@ -4168,12 +4166,14 @@ bool Player::ResetTalents(bool no_cost) } // Unlearn masteries - ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(GetTalentSpec(spec)); + ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(specID); for (uint32 i = 0; i < MAX_MASTERY_SPELLS; ++i) if (uint32 mastery = chrSpec->MasterySpellID[i]) RemoveAurasDueToSpell(mastery); - SetTalentSpec(spec, 0); + // Reset talents store + GetTalentGroupInfo(group)->Reset(); + SetTalentSpec(group, 0); SQLTransaction trans = CharacterDatabase.BeginTransaction(); _SaveTalents(trans); @@ -4265,9 +4265,9 @@ bool Player::HasSpell(uint32 spell) const !itr->second->disabled); } -bool Player::HasTalent(uint32 spell, uint8 spec) +bool Player::HasTalent(uint32 talentId, uint8 group) { - return GetTalentSpecInfo(spec)->HasTalent(spell); + return GetTalentGroupInfo(group)->HasTalent(talentId); } bool Player::HasActiveSpell(uint32 spell) const @@ -6269,7 +6269,7 @@ void Player::SendActionButtons(uint32 state) const data << uint8(state); GetSession()->SendPacket(&data); - TC_LOG_INFO("network", "Action Buttons for '%s' spec '%u' Sent", GetGUID().ToString().c_str(), GetActiveSpec()); + TC_LOG_INFO("network", "Action Buttons for '%s' group '%u' Sent", GetGUID().ToString().c_str(), GetActiveTalentGroup()); } bool Player::IsActionButtonDataValid(uint8 button, uint32 action, uint8 type) @@ -9684,6 +9684,7 @@ void Player::SendTalentWipeConfirm(ObjectGuid guid) void Player::ResetPetTalents() { + /* TODO: 6.x remove/update pet talents // This needs another gossip option + NPC text as a confirmation. // The confirmation gossip listid has the text: "Yes, please do." Pet* pet = GetPet(); @@ -9699,6 +9700,7 @@ void Player::ResetPetTalents() } pet->resetTalents(); SendTalentsInfoData(true); + */ } /*********************************************************/ @@ -14117,7 +14119,7 @@ void Player::PrepareGossipMenu(WorldObject* source, uint32 menuId /*= 0*/, bool break; } case GOSSIP_OPTION_LEARNDUALSPEC: - if (!(GetSpecsCount() == 1 && creature->isCanTrainingAndResetTalentsOf(this) && !(getLevel() < sWorld->getIntConfig(CONFIG_MIN_DUALSPEC_LEVEL)))) + if (!(GetTalentGroupsCount() == 1 && creature->isCanTrainingAndResetTalentsOf(this) && !(getLevel() < sWorld->getIntConfig(CONFIG_MIN_DUALSPEC_LEVEL)))) canTalk = false; break; case GOSSIP_OPTION_UNLEARNTALENTS: @@ -14331,7 +14333,7 @@ void Player::OnGossipSelect(WorldObject* source, uint32 gossipListId, uint32 men GetSession()->SendTrainerList(guid); break; case GOSSIP_OPTION_LEARNDUALSPEC: - if (GetSpecsCount() == 1 && getLevel() >= sWorld->getIntConfig(CONFIG_MIN_DUALSPEC_LEVEL)) + if (GetTalentGroupsCount() == 1 && getLevel() >= sWorld->getIntConfig(CONFIG_MIN_DUALSPEC_LEVEL)) { // Cast spells that teach dual spec // Both are also ImplicitTarget self and must be cast by player @@ -17431,19 +17433,19 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder) //mails are loaded only when needed ;-) - when player in game click on mailbox. //_LoadMail(); - SetSpecsCount(fields[53].GetUInt8()); - SetActiveSpec(fields[54].GetUInt8()); + SetTalentGroupsCount(fields[53].GetUInt8()); + SetActiveTalentGroup(fields[54].GetUInt8()); // sanity check - if (GetSpecsCount() > MAX_TALENT_SPECS || GetActiveSpec() > MAX_TALENT_SPEC || GetSpecsCount() < MIN_TALENT_SPECS) + if (GetTalentGroupsCount() > MAX_TALENT_GROUPS || GetActiveTalentGroup() > MAX_TALENT_GROUP || GetTalentGroupsCount() < MIN_TALENT_GROUPS) { - SetActiveSpec(0); - TC_LOG_ERROR("entities.player", "Player %s (%s) has SpecCount = %u and ActiveSpec = %u.", GetName().c_str(), GetGUID().ToString().c_str(), GetSpecsCount(), GetActiveSpec()); + TC_LOG_ERROR("entities.player", "Player %s (%s) has SpecCount = %u and ActiveSpec = %u.", GetName().c_str(), GetGUID().ToString().c_str(), GetTalentGroupsCount(), GetActiveTalentGroup()); + SetActiveTalentGroup(0); } // Only load selected specializations, learning mastery spells requires this - Tokenizer talentSpecs(fields[26].GetString(), ' ', MAX_TALENT_SPECS); - for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i) + Tokenizer talentSpecs(fields[26].GetString(), ' ', MAX_TALENT_GROUPS); + for (uint8 i = 0; i < MAX_TALENT_GROUPS; ++i) { if (i >= talentSpecs.size()) break; @@ -17804,7 +17806,7 @@ void Player::_LoadGlyphAuras() { for (uint8 i = 0; i < MAX_GLYPH_SLOT_INDEX; ++i) { - if (uint32 glyph = GetGlyph(GetActiveSpec(), i)) + if (uint32 glyph = GetGlyph(GetActiveTalentGroup(), i)) { if (GlyphPropertiesEntry const* gp = sGlyphPropertiesStore.LookupEntry(glyph)) { @@ -19104,7 +19106,7 @@ void Player::SaveToDB(bool create /*=false*/) stmt->setUInt32(index++, GetTalentResetTime()); ss.str(""); - for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i) + for (uint8 i = 0; i < MAX_TALENT_GROUPS; ++i) ss << GetTalentSpec(i) << " "; stmt->setString(index++, ss.str()); stmt->setUInt16(index++, (uint16)m_ExtraFlags); @@ -19141,8 +19143,8 @@ void Player::SaveToDB(bool create /*=false*/) stmt->setUInt32(index++, GetSession()->GetLatency()); - stmt->setUInt8(index++, GetSpecsCount()); - stmt->setUInt8(index++, GetActiveSpec()); + stmt->setUInt8(index++, GetTalentGroupsCount()); + stmt->setUInt8(index++, GetActiveTalentGroup()); ss.str(""); for (uint32 i = 0; i < PLAYER_EXPLORED_ZONES_SIZE; ++i) @@ -19233,7 +19235,7 @@ void Player::SaveToDB(bool create /*=false*/) stmt->setUInt32(index++, GetTalentResetTime()); ss.str(""); - for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i) + for (uint8 i = 0; i < MAX_TALENT_GROUPS; ++i) ss << GetTalentSpec(i) << " "; stmt->setString(index++, ss.str()); stmt->setUInt16(index++, (uint16)m_ExtraFlags); @@ -19270,8 +19272,8 @@ void Player::SaveToDB(bool create /*=false*/) stmt->setUInt32(index++, GetSession()->GetLatency()); - stmt->setUInt8(index++, GetSpecsCount()); - stmt->setUInt8(index++, GetActiveSpec()); + stmt->setUInt8(index++, GetTalentGroupsCount()); + stmt->setUInt8(index++, GetActiveTalentGroup()); ss.str(""); for (uint32 i = 0; i < PLAYER_EXPLORED_ZONES_SIZE; ++i) @@ -19377,7 +19379,7 @@ void Player::_SaveActions(SQLTransaction& trans) case ACTIONBUTTON_NEW: stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_ACTION); stmt->setUInt64(0, GetGUID().GetCounter()); - stmt->setUInt8(1, GetActiveSpec()); + stmt->setUInt8(1, GetActiveTalentGroup()); stmt->setUInt8(2, itr->first); stmt->setUInt32(3, itr->second.GetAction()); stmt->setUInt8(4, uint8(itr->second.GetType())); @@ -19392,7 +19394,7 @@ void Player::_SaveActions(SQLTransaction& trans) stmt->setUInt8(1, uint8(itr->second.GetType())); stmt->setUInt64(2, GetGUID().GetCounter()); stmt->setUInt8(3, itr->first); - stmt->setUInt8(4, GetActiveSpec()); + stmt->setUInt8(4, GetActiveTalentGroup()); trans->Append(stmt); itr->second.uState = ACTIONBUTTON_UNCHANGED; @@ -19402,7 +19404,7 @@ void Player::_SaveActions(SQLTransaction& trans) stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACTION_BY_BUTTON_SPEC); stmt->setUInt64(0, GetGUID().GetCounter()); stmt->setUInt8(1, itr->first); - stmt->setUInt8(2, GetActiveSpec()); + stmt->setUInt8(2, GetActiveTalentGroup()); trans->Append(stmt); m_actionButtons.erase(itr++); @@ -23054,7 +23056,7 @@ void Player::SendInitialPacketsBeforeAddToMap() // SMSG_SET_FLAT_SPELL_MODIFIER // SMSG_UPDATE_AURA_DURATION - SendTalentsInfoData(false); + SendTalentsInfoData(); data.Initialize(SMSG_WORLD_SERVER_INFO, 1 + 1 + 4 + 4); data.WriteBit(0); // HasRestrictedLevel @@ -24802,7 +24804,7 @@ void Player::InitGlyphsForLevel() void Player::SetGlyph(uint8 slot, uint32 glyph) { - _talentMgr->SpecInfo[GetActiveSpec()].Glyphs[slot] = glyph; + _talentMgr->GroupInfo[GetActiveTalentGroup()].Glyphs[slot] = glyph; SetUInt32Value(PLAYER_FIELD_GLYPHS_1 + slot, glyph); } @@ -25487,7 +25489,7 @@ void Player::CompletedAchievement(AchievementEntry const* entry) bool Player::LearnTalent(uint32 talentId) { - uint8 spec = GetActiveSpec(); + uint8 group = GetActiveTalentGroup(); TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId); @@ -25498,13 +25500,15 @@ bool Player::LearnTalent(uint32 talentId) if (getClass() != talentInfo->ClassID) return false; - // Check player level. - if (getLevel() < (15*talentInfo->TierID + 15)) + // Check player level + // TODO: fix level requirements for deathknights + uint8 levelReq = std::min(15*talentInfo->TierID + 15, sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)); + if (getLevel() < levelReq) return false; // Check if such tier talent hasn't been picked already - TalentSpecInfo* talentSpecInfo = GetTalentSpecInfo(spec); - if (talentSpecInfo->Talents[talentInfo->TierID].SpellID != 0) + TalentGroupInfo* talentGroupInfo = GetTalentGroupInfo(group); + if (talentGroupInfo->Talents[talentInfo->TierID]) return false; // spell not set in talent.dbc @@ -25519,16 +25523,10 @@ bool Player::LearnTalent(uint32 talentId) if (HasSpell(spellid)) return false; - // learn! (other talent ranks will unlearned at learning) - LearnSpell(spellid, false); - AddTalent(spellid, spec, true); - - TC_LOG_INFO("misc", "TalentID: %u Spell: %u Spec: %u\n", talentId, spellid, spec); - - // set talent tree for player - if (!GetTalentSpec(spec)) + // set talent spec for player + if (!GetTalentSpec(group)) { - SetTalentSpec(spec, talentInfo->SpecID); + SetTalentSpec(group, talentInfo->SpecID); // Replace default spells by specialization spells auto specSpells = sSpecializationSpellsBySpecStore.find(talentInfo->SpecID); @@ -25553,6 +25551,16 @@ bool Player::LearnTalent(uint32 talentId) } } + // Check talent spec + if (talentInfo->SpecID != GetTalentSpec(group)) + return false; + + // learn! (other talent ranks will unlearned at learning) + LearnSpell(spellid, false); + AddTalent(talentId, group); + + TC_LOG_INFO("misc", "TalentID: %u Spell: %u Group: %u\n", talentId, spellid, group); + return true; } @@ -25630,160 +25638,38 @@ bool Player::CanSeeSpellClickOn(Creature const* c) const return false; } -void Player::BuildPlayerTalentsInfoData(WorldPacket* data) -{ - /* TODO: 6.x update with new talent system (and move to packet class) - *data << uint32(GetFreeTalentPoints()); // unspentTalentPoints - *data << uint8(GetSpecsCount()); // talent group count (0, 1 or 2) - *data << uint8(GetActiveSpec()); // talent group index (0 or 1) - - if (GetSpecsCount()) - { - if (GetSpecsCount() > MAX_TALENT_SPECS) - SetSpecsCount(MAX_TALENT_SPECS); - - // loop through all specs (only 1 for now) - for (uint8 specIdx = 0; specIdx < GetSpecsCount(); ++specIdx) - { - *data << uint32(GetPrimaryTalentTree(specIdx)); - uint8 talentIdCount = 0; - size_t pos = data->wpos(); - *data << uint8(talentIdCount); // [PH], talentIdCount - - // find class talent tabs (all players have 3 talent tabs) - uint32 const* talentTabIds = GetTalentTabPages(getClass()); - - for (uint8 i = 0; i < MAX_TALENT_TABS; ++i) - { - uint32 talentTabId = talentTabIds[i]; - - for (uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId) - { - TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId); - if (!talentInfo) - continue; - - // skip another tab talents - if (talentInfo->TalentTab != talentTabId) - continue; - - // find max talent rank (0~4) - int8 curtalent_maxrank = -1; - for (int8 rank = MAX_TALENT_RANK-1; rank >= 0; --rank) - { - if (talentInfo->RankID[rank] && HasTalent(talentInfo->RankID[rank], specIdx)) - { - curtalent_maxrank = rank; - break; - } - } - - // not learned talent - if (curtalent_maxrank < 0) - continue; - - *data << uint32(talentInfo->TalentID); // Talent.dbc - *data << uint8(curtalent_maxrank); // talentMaxRank (0-4) - - ++talentIdCount; - } - } - - data->put<uint8>(pos, talentIdCount); // put real count - - *data << uint8(MAX_GLYPH_SLOT_INDEX); // glyphs count - - for (uint8 i = 0; i < MAX_GLYPH_SLOT_INDEX; ++i) - *data << uint16(GetGlyph(specIdx, i)); // GlyphProperties.dbc - } - } - */ -} - -void Player::BuildPetTalentsInfoData(WorldPacket* data) +void Player::SendTalentsInfoData() { - /* TODO: 6.x update with new talent system (and move to packet class) - uint32 unspentTalentPoints = 0; - size_t pointsPos = data->wpos(); - *data << uint32(unspentTalentPoints); // [PH], unspentTalentPoints - - uint8 talentIdCount = 0; - size_t countPos = data->wpos(); - *data << uint8(talentIdCount); // [PH], talentIdCount - - Pet* pet = GetPet(); - if (!pet) - return; + WorldPackets::Talent::UpdateTalentData packet; - unspentTalentPoints = pet->GetFreeTalentPoints(); + packet.Info.ActiveGroup = GetActiveTalentGroup(); + + uint8 groupsCount = GetTalentGroupsCount(); - data->put<uint32>(pointsPos, unspentTalentPoints); // put real points - - CreatureTemplate const* ci = pet->GetCreatureTemplate(); - if (!ci) - return; - - CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->family); - if (!pet_family || pet_family->PetTalentType < 0) - return; - - for (uint32 talentTabId = 1; talentTabId < sTalentTabStore.GetNumRows(); ++talentTabId) + for (uint8 i = 0; i < groupsCount; ++i) { - TalentTabEntry const* talentTabInfo = sTalentTabStore.LookupEntry(talentTabId); - if (!talentTabInfo) - continue; - - if (!((1 << pet_family->PetTalentType) & talentTabInfo->petTalentMask)) - continue; - - for (uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId) + TalentGroupInfo* groupInfo = GetTalentGroupInfo(i); + WorldPackets::Talent::TalentGroupInfo groupInfoPkt; + + groupInfoPkt.SpecID = groupInfo->SpecID; + + groupInfoPkt.TalentIDs.reserve(MAX_TALENT_TIERS); + for (uint32 x = 0; x < MAX_TALENT_TIERS; ++x) { - TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId); - if (!talentInfo) - continue; - - // skip another tab talents - if (talentInfo->TalentTab != talentTabId) - continue; - - // find max talent rank (0~4) - int8 curtalent_maxrank = -1; - for (int8 rank = MAX_TALENT_RANK-1; rank >= 0; --rank) - { - if (talentInfo->RankID[rank] && pet->HasSpell(talentInfo->RankID[rank])) - { - curtalent_maxrank = rank; - break; - } - } - - // not learned talent - if (curtalent_maxrank < 0) - continue; - - *data << uint32(talentInfo->TalentID); // Talent.dbc - *data << uint8(curtalent_maxrank); // talentMaxRank (0-4) + // Do not send empty talents + if (!groupInfo->Talents[x]) + break; - ++talentIdCount; + groupInfoPkt.TalentIDs.push_back(groupInfo->Talents[x]); } + + for (uint32 x = 0; x < MAX_GLYPH_SLOT_INDEX; ++x) + groupInfoPkt.GlyphIDs[x] = groupInfo->Glyphs[x]; + + packet.Info.TalentGroups.push_back(groupInfoPkt); + } - data->put<uint8>(countPos, talentIdCount); // put real count - - break; - }*/ -} - -void Player::SendTalentsInfoData(bool pet) -{ - /* TODO: 6.x update with new talent system (and move to packet class) - WorldPacket data(SMSG_TALENTS_INFO, 50); - data << uint8(pet ? 1 : 0); - if (pet) - BuildPetTalentsInfoData(&data); - else - BuildPlayerTalentsInfoData(&data); - GetSession()->SendPacket(&data); - */ + GetSession()->SendPacket(packet.Write()); } void Player::BuildEnchantmentsInfoData(WorldPacket* data) @@ -26064,7 +25950,7 @@ void Player::SetMap(Map* map) void Player::_LoadGlyphs(PreparedQueryResult result) { - // SELECT spec, glyph1, glyph2, glyph3, glyph4, glyph5, glyph6, glyph7, glyph8, glyph9 FROM character_glyphs WHERE guid = '%u' + // SELECT group, glyph1, glyph2, glyph3, glyph4, glyph5, glyph6, glyph7, glyph8, glyph9 FROM character_glyphs WHERE guid = '%u' if (!result) return; @@ -26072,12 +25958,12 @@ void Player::_LoadGlyphs(PreparedQueryResult result) { Field* fields = result->Fetch(); - uint8 spec = fields[0].GetUInt8(); - if (spec >= GetSpecsCount()) + uint8 group = fields[0].GetUInt8(); + if (group >= GetTalentGroupsCount()) continue; for (uint8 i = 0; i < MAX_GLYPH_SLOT_INDEX; ++i) - _talentMgr->SpecInfo[spec].Glyphs[i] = fields[i + 1].GetUInt16(); + _talentMgr->GroupInfo[group].Glyphs[i] = fields[i + 1].GetUInt16(); } while (result->NextRow()); } @@ -26089,17 +25975,17 @@ void Player::_SaveGlyphs(SQLTransaction& trans) trans->Append(stmt); - for (uint8 spec = 0; spec < GetSpecsCount(); ++spec) + for (uint8 group = 0; group < GetTalentGroupsCount(); ++group) { uint8 index = 0; stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_GLYPHS); stmt->setUInt64(index++, GetGUID().GetCounter()); - stmt->setUInt8(index++, spec); + stmt->setUInt8(index++, group); for (uint8 i = 0; i < MAX_GLYPH_SLOT_INDEX; ++i) - stmt->setUInt16(index++, uint16(GetGlyph(spec, i))); + stmt->setUInt16(index++, uint16(GetGlyph(group, i))); trans->Append(stmt); } @@ -26111,57 +25997,40 @@ void Player::_LoadTalents(PreparedQueryResult result) if (result) { do - AddTalent((*result)[0].GetUInt32(), (*result)[1].GetUInt8(), false); + AddTalent((*result)[0].GetUInt32(), (*result)[1].GetUInt8()); while (result->NextRow()); } } void Player::_SaveTalents(SQLTransaction& trans) { - PreparedStatement* stmt = NULL; + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_TALENT); + stmt->setUInt64(0, GetGUID().GetCounter()); + trans->Append(stmt); - for (uint8 spec = 0; spec < MAX_TALENT_SPECS; ++spec) + for (uint8 group = 0; group < MAX_TALENT_GROUPS; ++group) { - TalentSpecInfo* talentSpecInfo = GetTalentSpecInfo(spec); + TalentGroupInfo* talentGroupInfo = GetTalentGroupInfo(group); for (uint32 tier = 0; tier < MAX_TALENT_TIERS; ++tier) { - PlayerTalent* talent = &talentSpecInfo->Talents[tier]; - - if (talent->State == PLAYERSPELL_REMOVED || talent->State == PLAYERSPELL_CHANGED) - { - stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_TALENT_BY_SPELL_SPEC); - stmt->setUInt64(0, GetGUID().GetCounter()); - stmt->setUInt32(1, talent->SpellID); - stmt->setUInt8(2, spec); - trans->Append(stmt); - } - - if (talent->State == PLAYERSPELL_NEW || talent->State == PLAYERSPELL_CHANGED) - { - stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_TALENT); - stmt->setUInt64(0, GetGUID().GetCounter()); - stmt->setUInt32(1, talent->SpellID); - stmt->setUInt8(2, spec); - trans->Append(stmt); - } - - if (talent->State == PLAYERSPELL_REMOVED) - talent->SpellID = 0; - - talent->State = PLAYERSPELL_UNCHANGED; + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_TALENT); + stmt->setUInt64(0, GetGUID().GetCounter()); + stmt->setUInt32(1, talentGroupInfo->Talents[tier]); + stmt->setUInt8(2, group); + trans->Append(stmt); } } } -void Player::UpdateSpecCount(uint8 count) +void Player::UpdateTalentGroupCount(uint8 count) { - uint32 curCount = GetSpecsCount(); + uint32 curCount = GetTalentGroupsCount(); if (curCount == count) return; - if (GetActiveSpec() >= count) - ActivateSpec(0); + if (GetActiveTalentGroup() >= count) + ActivateTalentGroup(0); SQLTransaction trans = CharacterDatabase.BeginTransaction(); PreparedStatement* stmt = NULL; @@ -26187,7 +26056,7 @@ void Player::UpdateSpecCount(uint8 count) _SaveActions(trans); stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACTION_EXCEPT_SPEC); - stmt->setUInt8(0, GetActiveSpec()); + stmt->setUInt8(0, GetActiveTalentGroup()); stmt->setUInt64(1, GetGUID().GetCounter()); trans->Append(stmt); @@ -26195,17 +26064,17 @@ void Player::UpdateSpecCount(uint8 count) CharacterDatabase.CommitTransaction(trans); - SetSpecsCount(count); + SetTalentGroupsCount(count); - SendTalentsInfoData(false); + SendTalentsInfoData(); } -void Player::ActivateSpec(uint8 spec) +void Player::ActivateTalentGroup(uint8 group) { - if (GetActiveSpec() == spec) + if (GetActiveTalentGroup() == group) return; - if (spec > GetSpecsCount()) + if (group > GetTalentGroupsCount()) return; if (IsNonMeleeSpellCast(false)) @@ -26251,7 +26120,7 @@ void Player::ActivateSpec(uint8 spec) } // Unlearn specialization specific spells - auto specSpells = sSpecializationSpellsBySpecStore.find(GetTalentSpec(GetActiveSpec())); + auto specSpells = sSpecializationSpellsBySpecStore.find(GetActiveTalentSpec()); if (specSpells != sSpecializationSpellsBySpecStore.end()) { for (auto it = specSpells->second.begin(); it != specSpells->second.end(); ++it) @@ -26265,7 +26134,7 @@ void Player::ActivateSpec(uint8 spec) } // Unlearn mastery spells - ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(GetTalentSpec(GetActiveSpec())); + ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(GetActiveTalentSpec()); for (uint32 i = 0; i < MAX_MASTERY_SPELLS; ++i) if (chrSpec->MasterySpellID[i]) RemoveSpell(chrSpec->MasterySpellID[i], true); @@ -26273,12 +26142,12 @@ void Player::ActivateSpec(uint8 spec) // set glyphs for (uint8 slot = 0; slot < MAX_GLYPH_SLOT_INDEX; ++slot) // remove secondary glyph - if (uint32 oldglyph = GetGlyph(GetActiveSpec(), slot)) + if (uint32 oldglyph = GetGlyph(GetActiveTalentGroup(), slot)) if (GlyphPropertiesEntry const* old_gp = sGlyphPropertiesStore.LookupEntry(oldglyph)) RemoveAurasDueToSpell(old_gp->SpellID); - // Activate new spec - SetActiveSpec(spec); + // Activate new group + SetActiveTalentGroup(group); for (uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId) { @@ -26291,14 +26160,11 @@ void Player::ActivateSpec(uint8 spec) if (getClass() != talentInfo->ClassID) continue; - if (HasTalent(talentInfo->SpellID, GetActiveSpec())) - { - LearnSpell(talentInfo->SpellID, false); - } + LearnSpell(talentInfo->SpellID, false); } // Replace default spells with specialization specific spells - auto newSpecSpells = sSpecializationSpellsBySpecStore.find(GetTalentSpec(spec)); + auto newSpecSpells = sSpecializationSpellsBySpecStore.find(GetActiveTalentSpec()); if (newSpecSpells != sSpecializationSpellsBySpecStore.end()) { for (auto it = newSpecSpells->second.begin(); it != newSpecSpells->second.end(); ++it) @@ -26314,7 +26180,7 @@ void Player::ActivateSpec(uint8 spec) } if (CanUseMastery()) - if (ChrSpecializationEntry const* newChrSpec = sChrSpecializationStore.LookupEntry(GetTalentSpec(spec))) + if (ChrSpecializationEntry const* newChrSpec = sChrSpecializationStore.LookupEntry(GetActiveTalentSpec())) for (uint32 i = 0; i < MAX_MASTERY_SPELLS; ++i) if (newChrSpec->MasterySpellID[i]) LearnSpell(newChrSpec->MasterySpellID[i], false); @@ -26322,7 +26188,7 @@ void Player::ActivateSpec(uint8 spec) // set glyphs for (uint8 slot = 0; slot < MAX_GLYPH_SLOT_INDEX; ++slot) { - uint32 glyph = GetGlyph(GetActiveSpec(), slot); + uint32 glyph = GetGlyph(GetActiveTalentGroup(), slot); // apply primary glyph if (glyph) @@ -26337,7 +26203,7 @@ void Player::ActivateSpec(uint8 spec) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_ACTIONS_SPEC); stmt->setUInt64(0, GetGUID().GetCounter()); - stmt->setUInt8(1, GetActiveSpec()); + stmt->setUInt8(1, GetActiveTalentGroup()); if (PreparedQueryResult result = CharacterDatabase.Query(stmt)) _LoadActions(result); } @@ -26350,7 +26216,7 @@ void Player::ActivateSpec(uint8 spec) SetPower(pw, 0); - if (!sChrSpecializationStore.LookupEntry(GetTalentSpec(spec))) + if (!sChrSpecializationStore.LookupEntry(GetActiveTalentSpec())) ResetTalents(true); } diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 54d542011a1..11167097e89 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -115,12 +115,6 @@ struct PlayerSpell bool disabled : 1; // first rank has been learned in result talent learn but currently talent unlearned, save max learned ranks }; -struct PlayerTalent -{ - PlayerSpellState State : 8; - uint32 SpellID : 32; -}; - extern uint32 const MasterySpells[MAX_CLASSES]; enum TalentSpecialization // talent tabs @@ -1217,46 +1211,52 @@ private: bool _isPvP; }; -struct TalentSpecInfo +struct TalentGroupInfo { - PlayerTalent Talents[MAX_TALENT_TIERS]; + uint32 Talents[MAX_TALENT_TIERS]; uint32 Glyphs[MAX_GLYPH_SLOT_INDEX]; - uint32 TalentSpec; + uint32 SpecID; - bool HasTalent(uint32 spellId) + bool HasTalent(uint32 talentId) { for (uint32 i = 0; i < MAX_TALENT_TIERS; ++i) - if (Talents[i].SpellID == spellId) + if (Talents[i] == talentId) return true; return false; } + uint32 TalentCount() + { + for (uint32 i = 0; i < MAX_TALENT_TIERS; ++i) + if (!Talents[i]) + return i; + return MAX_TALENT_TIERS; + } + void Reset() { - for (uint32 i = 0; i < MAX_TALENT_TIERS; ++i) { - Talents[i].State = PLAYERSPELL_REMOVED; - Talents[i].SpellID = 0; - } + for (uint32 i = 0; i < MAX_TALENT_TIERS; ++i) + Talents[i] = 0; } }; struct PlayerTalentInfo { - PlayerTalentInfo() : ResetTalentsCost(0), ResetTalentsTime(0), ActiveSpec(0), SpecsCount(1) + PlayerTalentInfo() : ResetTalentsCost(0), ResetTalentsTime(0), ActiveGroup(0), GroupsCount(1) { - for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i) + for (uint8 i = 0; i < MAX_TALENT_GROUPS; ++i) { - memset(SpecInfo[i].Talents, 0, sizeof(PlayerTalent)*MAX_TALENT_TIERS); - memset(SpecInfo[i].Glyphs, 0, MAX_GLYPH_SLOT_INDEX * sizeof(uint32)); - SpecInfo[i].TalentSpec = 0; + memset(GroupInfo[i].Talents, 0, sizeof(uint32)*MAX_TALENT_TIERS); + memset(GroupInfo[i].Glyphs, 0, MAX_GLYPH_SLOT_INDEX * sizeof(uint32)); + GroupInfo[i].SpecID = 0; } } - TalentSpecInfo SpecInfo[MAX_TALENT_SPECS]; + TalentGroupInfo GroupInfo[MAX_TALENT_GROUPS]; uint32 ResetTalentsCost; time_t ResetTalentsTime; - uint8 ActiveSpec; - uint8 SpecsCount; + uint8 ActiveGroup; + uint8 GroupsCount; private: PlayerTalentInfo(PlayerTalentInfo const&); @@ -1825,35 +1825,34 @@ class Player : public Unit, public GridObject<Player> void SetTalentResetCost(uint32 cost) { _talentMgr->ResetTalentsCost = cost; } uint32 GetTalentResetTime() const { return _talentMgr->ResetTalentsTime; } void SetTalentResetTime(time_t time_) { _talentMgr->ResetTalentsTime = time_; } - uint8 GetActiveSpec() const { return _talentMgr->ActiveSpec; } - void SetActiveSpec(uint8 spec){ _talentMgr->ActiveSpec = spec; } - uint8 GetSpecsCount() const { return _talentMgr->SpecsCount; } - void SetSpecsCount(uint8 count) { _talentMgr->SpecsCount = count; } - uint32 GetTalentSpec(uint8 spec) const { return _talentMgr->SpecInfo[spec].TalentSpec; } - void SetTalentSpec(uint8 spec, uint32 talentSpec) const { _talentMgr->SpecInfo[spec].TalentSpec = talentSpec; } + uint8 GetActiveTalentGroup() const { return _talentMgr->ActiveGroup; } + void SetActiveTalentGroup(uint8 group){ _talentMgr->ActiveGroup = group; } + uint8 GetTalentGroupsCount() const { return _talentMgr->GroupsCount; } + void SetTalentGroupsCount(uint8 count) { _talentMgr->GroupsCount = count; } + uint32 GetTalentSpec(uint8 group) const { return _talentMgr->GroupInfo[group].SpecID; } + void SetTalentSpec(uint8 group, uint32 talentSpec) const { _talentMgr->GroupInfo[group].SpecID = talentSpec; } + uint32 GetActiveTalentSpec() const { return _talentMgr->GroupInfo[_talentMgr->ActiveGroup].SpecID; } bool ResetTalents(bool no_cost = false); uint32 GetNextResetTalentsCost() const; void InitTalentForLevel(); - void BuildPlayerTalentsInfoData(WorldPacket* data); - void BuildPetTalentsInfoData(WorldPacket* data); - void SendTalentsInfoData(bool pet); + void SendTalentsInfoData(); bool LearnTalent(uint32 talentId); - bool AddTalent(uint32 spellId, uint8 spec, bool learning); - bool HasTalent(uint32 spell_id, uint8 spec); + bool AddTalent(uint32 talentId, uint8 spec); + bool HasTalent(uint32 talentId, uint8 spec); // Dual Spec - void UpdateSpecCount(uint8 count); - void ActivateSpec(uint8 spec); + void UpdateTalentGroupCount(uint8 count); + void ActivateTalentGroup(uint8 group); void InitGlyphsForLevel(); void SetGlyphSlot(uint8 slot, uint32 slottype) { SetUInt32Value(PLAYER_FIELD_GLYPH_SLOTS_1 + slot, slottype); } uint32 GetGlyphSlot(uint8 slot) const { return GetUInt32Value(PLAYER_FIELD_GLYPH_SLOTS_1 + slot); } void SetGlyph(uint8 slot, uint32 glyph); - uint32 GetGlyph(uint8 spec, uint8 slot) const { return _talentMgr->SpecInfo[spec].Glyphs[slot]; } + uint32 GetGlyph(uint8 group, uint8 slot) const { return _talentMgr->GroupInfo[group].Glyphs[slot]; } - TalentSpecInfo* GetTalentSpecInfo(uint8 spec) { return &_talentMgr->SpecInfo[spec]; } + TalentGroupInfo* GetTalentGroupInfo(uint8 group) { return &_talentMgr->GroupInfo[group]; } ActionButtonList const& GetActionButtons() const { return m_actionButtons; } uint32 GetFreePrimaryProfessionPoints() const { return GetUInt32Value(PLAYER_CHARACTER_POINTS); } diff --git a/src/server/game/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp index 37b4d4d97a0..ea15daed587 100644 --- a/src/server/game/Entities/Unit/StatSystem.cpp +++ b/src/server/game/Entities/Unit/StatSystem.cpp @@ -526,7 +526,7 @@ void Player::UpdateMastery() value += GetRatingBonusValue(CR_MASTERY); SetFloatValue(PLAYER_MASTERY, value); - ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(GetTalentSpec(GetActiveSpec())); + ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(GetActiveTalentSpec()); if (!chrSpec) return; diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 6e9560ac22f..7d892371931 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -1055,7 +1055,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) if (pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_TALENTS)) { pCurrChar->ResetTalents(true); - pCurrChar->SendTalentsInfoData(false); // original talents send already in to SendInitialPacketsBeforeAddToMap, resend reset state + pCurrChar->SendTalentsInfoData(); // original talents send already in to SendInitialPacketsBeforeAddToMap, resend reset state SendNotification(LANG_RESET_TALENTS); } @@ -1416,13 +1416,13 @@ void WorldSession::HandleRemoveGlyph(WorldPacket& recvData) return; } - if (uint32 glyph = _player->GetGlyph(_player->GetActiveSpec(), slot)) + if (uint32 glyph = _player->GetGlyph(_player->GetActiveTalentGroup(), slot)) { if (GlyphPropertiesEntry const* gp = sGlyphPropertiesStore.LookupEntry(glyph)) { _player->RemoveAurasDueToSpell(gp->SpellID); _player->SetGlyph(slot, 0); - _player->SendTalentsInfoData(false); + _player->SendTalentsInfoData(); } } } diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index b28068538ce..6f2cf949dfe 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -1242,6 +1242,7 @@ void WorldSession::HandleInspectOpcode(WorldPacket& recvData) WorldPacket data(SMSG_INSPECT_TALENT, 8 + 4 + 1 + 1 + talent_points + 8 + 4 + 8 + 4); data << player->GetGUID(); + /* TODO: 6.x update packet structure (BuildPlayerTalentsInfoData no longer exists) if (sWorld->getBoolConfig(CONFIG_TALENTS_INSPECTING) || _player->IsGameMaster()) player->BuildPlayerTalentsInfoData(&data); else @@ -1250,6 +1251,7 @@ void WorldSession::HandleInspectOpcode(WorldPacket& recvData) data << uint8(0); // talentGroupCount data << uint8(0); // talentGroupIndex } + */ player->BuildEnchantmentsInfoData(&data); if (Guild* guild = sGuildMgr->GetGuildById(player->GetGuildId())) diff --git a/src/server/game/Handlers/SkillHandler.cpp b/src/server/game/Handlers/SkillHandler.cpp index c3f9dfc2868..ef1e9031cb9 100644 --- a/src/server/game/Handlers/SkillHandler.cpp +++ b/src/server/game/Handlers/SkillHandler.cpp @@ -111,7 +111,7 @@ void WorldSession::HandleTalentWipeConfirmOpcode(WorldPacket& recvData) return; } - _player->SendTalentsInfoData(false); + _player->SendTalentsInfoData(); unit->CastSpell(_player, 14867, true); //spell: "Untalent Visual Effect" } diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index e2c82763161..9e8b5ca00f3 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -815,10 +815,10 @@ enum SpellAttr13 SPELL_ATTR13_UNK23 = 0x00800000 // 23 }; -#define MIN_TALENT_SPEC 0 -#define MAX_TALENT_SPEC 1 -#define MIN_TALENT_SPECS 1 -#define MAX_TALENT_SPECS 2 +#define MIN_TALENT_GROUP 0 +#define MAX_TALENT_GROUP 1 +#define MIN_TALENT_GROUPS 1 +#define MAX_TALENT_GROUPS 2 #define MAX_GLYPH_SLOT_INDEX 9 #define REQ_PRIMARY_TREE_TALENTS 31 diff --git a/src/server/game/Server/Packets/TalentPackets.cpp b/src/server/game/Server/Packets/TalentPackets.cpp new file mode 100644 index 00000000000..3410fb273f7 --- /dev/null +++ b/src/server/game/Server/Packets/TalentPackets.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "TalentPackets.h" + +WorldPacket const* WorldPackets::Talent::UpdateTalentData::Write() +{ + _worldPacket << Info.ActiveGroup; + _worldPacket << uint32(Info.TalentGroups.size()); + + for (auto& talentGroupInfo : Info.TalentGroups) + { + _worldPacket << talentGroupInfo.SpecID; + _worldPacket << uint32(talentGroupInfo.TalentIDs.size()); + + for (uint32 i = 0; i < MAX_GLYPH_SLOT_INDEX; ++i) + _worldPacket << talentGroupInfo.GlyphIDs[i]; + + for (uint16 talentID : talentGroupInfo.TalentIDs) + _worldPacket << talentID; + } + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/TalentPackets.h b/src/server/game/Server/Packets/TalentPackets.h new file mode 100644 index 00000000000..c756c6962bb --- /dev/null +++ b/src/server/game/Server/Packets/TalentPackets.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef TalentPackets_h__ +#define TalentPackets_h__ + +#include "Packet.h" +#include "Player.h" +#include <vector> + +namespace WorldPackets +{ + namespace Talent + { + struct TalentGroupInfo + { + uint32 SpecID; + std::vector<uint16> TalentIDs; + uint16 GlyphIDs[MAX_GLYPH_SLOT_INDEX]; + }; + + struct TalentInfoUpdate + { + uint8 ActiveGroup; + std::vector<TalentGroupInfo> TalentGroups; + }; + + class UpdateTalentData final : public ServerPacket + { + public: + UpdateTalentData() : ServerPacket(SMSG_TALENTS_INFO, 2+4+4+4+12) { } + + WorldPacket const* Write() override; + + TalentInfoUpdate Info; + }; + } +} + +#endif // TalentPackets_h__ diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 4e31af725a9..292f126d8a4 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -1246,7 +1246,7 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const // Also do it for Glyphs for (uint32 i = 0; i < MAX_GLYPH_SLOT_INDEX; ++i) { - if (uint32 glyphId = plrTarget->GetGlyph(plrTarget->GetActiveSpec(), i)) + if (uint32 glyphId = plrTarget->GetGlyph(plrTarget->GetActiveTalentGroup(), i)) { if (GlyphPropertiesEntry const* glyph = sGlyphPropertiesStore.LookupEntry(glyphId)) { diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index c3ba18cad2c..3579ba73c31 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -4034,7 +4034,7 @@ void Spell::EffectApplyGlyph(SpellEffIndex effIndex) } // remove old glyph - if (uint32 oldGlyph = player->GetGlyph(player->GetActiveSpec(), m_glyphIndex)) + if (uint32 oldGlyph = player->GetGlyph(player->GetActiveTalentGroup(), m_glyphIndex)) { if (GlyphPropertiesEntry const* oldGlyphProperties = sGlyphPropertiesStore.LookupEntry(oldGlyph)) { @@ -4045,16 +4045,16 @@ void Spell::EffectApplyGlyph(SpellEffIndex effIndex) player->CastSpell(m_caster, newGlyphProperties->SpellID, true); player->SetGlyph(m_glyphIndex, newGlyph); - player->SendTalentsInfoData(false); + player->SendTalentsInfoData(); } } - else if (uint32 oldGlyph = player->GetGlyph(player->GetActiveSpec(), m_glyphIndex)) // Removing the glyph, get the old one + else if (uint32 oldGlyph = player->GetGlyph(player->GetActiveTalentGroup(), m_glyphIndex)) // Removing the glyph, get the old one { if (GlyphPropertiesEntry const* oldGlyphProperties = sGlyphPropertiesStore.LookupEntry(oldGlyph)) { player->RemoveAurasDueToSpell(oldGlyphProperties->SpellID); player->SetGlyph(m_glyphIndex, 0); - player->SendTalentsInfoData(false); + player->SendTalentsInfoData(); } } } @@ -5494,7 +5494,7 @@ void Spell::EffectSpecCount(SpellEffIndex /*effIndex*/) if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) return; - unitTarget->ToPlayer()->UpdateSpecCount(damage); + unitTarget->ToPlayer()->UpdateTalentGroupCount(damage); } void Spell::EffectActivateSpec(SpellEffIndex /*effIndex*/) @@ -5505,7 +5505,7 @@ void Spell::EffectActivateSpec(SpellEffIndex /*effIndex*/) if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) return; - unitTarget->ToPlayer()->ActivateSpec(damage-1); // damage is 1 or 2, spec is 0 or 1 + unitTarget->ToPlayer()->ActivateTalentGroup(damage-1); // damage is 1 or 2, spec is 0 or 1 } void Spell::EffectPlaySound(SpellEffIndex effIndex) diff --git a/src/server/game/Tools/CharacterDatabaseCleaner.cpp b/src/server/game/Tools/CharacterDatabaseCleaner.cpp index a63a8ae6cdd..ec96d092393 100644 --- a/src/server/game/Tools/CharacterDatabaseCleaner.cpp +++ b/src/server/game/Tools/CharacterDatabaseCleaner.cpp @@ -147,7 +147,7 @@ bool CharacterDatabaseCleaner::TalentCheck(uint32 talent_id) void CharacterDatabaseCleaner::CleanCharacterTalent() { - CharacterDatabase.DirectPExecute("DELETE FROM character_talent WHERE spec > %u", MAX_TALENT_SPECS); + CharacterDatabase.DirectPExecute("DELETE FROM character_talent WHERE spec > %u", MAX_TALENT_GROUPS); CheckUnique("spell", "character_talent", &TalentCheck); } diff --git a/src/server/scripts/Commands/cs_learn.cpp b/src/server/scripts/Commands/cs_learn.cpp index 81499567b72..2cf97403595 100644 --- a/src/server/scripts/Commands/cs_learn.cpp +++ b/src/server/scripts/Commands/cs_learn.cpp @@ -204,7 +204,7 @@ public: // learn highest rank of talent and learn all non-talent spell ranks (recursive by tree) player->LearnSpellHighestRank(talentInfo->SpellID); - player->AddTalent(talentInfo->SpellID, player->GetActiveSpec(), true); + player->AddTalent(talentInfo->SpellID, player->GetActiveTalentGroup()); } handler->SendSysMessage(LANG_COMMAND_LEARN_CLASS_TALENTS); diff --git a/src/server/scripts/Commands/cs_reset.cpp b/src/server/scripts/Commands/cs_reset.cpp index 9d2621c0010..4a58a7f7e5d 100644 --- a/src/server/scripts/Commands/cs_reset.cpp +++ b/src/server/scripts/Commands/cs_reset.cpp @@ -204,6 +204,7 @@ public: Player* target; ObjectGuid targetGuid; std::string targetName; + /* TODO: 6.x remove/update pet talents if (!handler->extractPlayerTarget((char*)args, &target, &targetGuid, &targetName)) { // Try reset talents as Hunter Pet @@ -227,19 +228,22 @@ public: handler->SetSentErrorMessage(true); return false; } + */ if (target) { target->ResetTalents(true); - target->SendTalentsInfoData(false); + target->SendTalentsInfoData(); ChatHandler(target->GetSession()).SendSysMessage(LANG_RESET_TALENTS); if (!handler->GetSession() || handler->GetSession()->GetPlayer() != target) handler->PSendSysMessage(LANG_RESET_TALENTS_ONLINE, handler->GetNameLink(target).c_str()); + /* TODO: 6.x remove/update pet talents Pet* pet = target->GetPet(); Pet::resetTalentsForAllPetsOf(target, pet); if (pet) target->SendTalentsInfoData(true); + */ return true; } else if (!targetGuid.IsEmpty()) diff --git a/src/server/scripts/Spells/spell_druid.cpp b/src/server/scripts/Spells/spell_druid.cpp index ed0709c6ad9..184e12cdccb 100644 --- a/src/server/scripts/Spells/spell_druid.cpp +++ b/src/server/scripts/Spells/spell_druid.cpp @@ -168,7 +168,7 @@ class spell_dru_eclipse_energize : public SpellScriptLoader Player* caster = GetCaster()->ToPlayer(); // No boomy, no deal. - if (caster->GetTalentSpec(caster->GetActiveSpec()) != TALENT_SPEC_DRUID_BALANCE) + if (caster->GetActiveTalentSpec() != TALENT_SPEC_DRUID_BALANCE) return; switch (GetSpellInfo()->Id) diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp index e91aa10c52d..9c27f876054 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp @@ -74,7 +74,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() "position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, " "resettalents_time, talentTree, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, instance_mode_mask, " "totalKills, todayKills, yesterdayKills, chosenTitle, watchedFaction, drunk, " - "health, power1, power2, power3, power4, power5, instance_id, speccount, activespec, exploredZones, equipmentCache, knownTitles, actionBars, grantableLevels " + "health, power1, power2, power3, power4, power5, instance_id, talentGroupsCount, activeTalentGroup, exploredZones, equipmentCache, knownTitles, actionBars, grantableLevels " "FROM characters WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_GROUP_MEMBER, "SELECT guid FROM group_member WHERE memberGuid = ?", CONNECTION_BOTH); @@ -105,7 +105,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_CHARACTER_REPUTATION, "SELECT faction, standing, flags FROM character_reputation WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_INVENTORY, "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, bag, slot, " "item, itemEntry FROM character_inventory ci JOIN item_instance ii ON ci.item = ii.guid WHERE ci.guid = ? ORDER BY bag, slot", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_ACTIONS, "SELECT a.button, a.action, a.type FROM character_action as a, characters as c WHERE a.guid = c.guid AND a.spec = c.activespec AND a.guid = ? ORDER BY button", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_ACTIONS, "SELECT a.button, a.action, a.type FROM character_action as a, characters as c WHERE a.guid = c.guid AND a.spec = c.activeTalentGroup AND a.guid = ? ORDER BY button", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_MAILCOUNT, "SELECT COUNT(id) FROM mail WHERE receiver = ? AND (checked & 1) = 0 AND deliver_time <= ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_MAILDATE, "SELECT MIN(deliver_time) FROM mail WHERE receiver = ? AND (checked & 1) = 0", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_MAIL_COUNT, "SELECT COUNT(*) FROM mail WHERE receiver = ?", CONNECTION_SYNCH); @@ -122,8 +122,8 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_CHARACTER_EQUIPMENTSETS, "SELECT setguid, setindex, name, iconname, ignore_mask, item0, item1, item2, item3, item4, item5, item6, item7, item8, " "item9, item10, item11, item12, item13, item14, item15, item16, item17, item18 FROM character_equipmentsets 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 spec, glyph1, glyph2, glyph3, glyph4, glyph5, glyph6, glyph7, glyph8, glyph9 FROM character_glyphs WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_TALENTS, "SELECT spell, spec FROM character_talent WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_GLYPHS, "SELECT talentGroup, glyph1, glyph2, glyph3, glyph4, glyph5, glyph6, glyph7, glyph8, glyph9 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); PrepareStatement(CHAR_SEL_CHARACTER_BANNED, "SELECT guid FROM character_banned WHERE guid = ? AND active = 1", CONNECTION_ASYNC); @@ -376,13 +376,13 @@ void CharacterDatabaseConnection::DoPrepareStatements() "extra_flags, stable_slots, at_login, zone, " "death_expire_time, taxi_path, totalKills, " "todayKills, yesterdayKills, chosenTitle, watchedFaction, drunk, health, power1, power2, power3, " - "power4, power5, latency, speccount, activespec, exploredZones, equipmentCache, knownTitles, actionBars, grantableLevels) VALUES " + "power4, power5, latency, talentGroupsCount, activeTalentGroup, exploredZones, equipmentCache, knownTitles, actionBars, grantableLevels) VALUES " "(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_CHARACTER, "UPDATE characters SET name=?,race=?,class=?,gender=?,level=?,xp=?,money=?,playerBytes=?,playerBytes2=?,playerFlags=?," "map=?,instance_id=?,instance_mode_mask=?,position_x=?,position_y=?,position_z=?,orientation=?,trans_x=?,trans_y=?,trans_z=?,trans_o=?,transguid=?,taximask=?,cinematic=?,totaltime=?,leveltime=?,rest_bonus=?," "logout_time=?,is_logout_resting=?,resettalents_cost=?,resettalents_time=?,talentTree=?,extra_flags=?,stable_slots=?,at_login=?,zone=?,death_expire_time=?,taxi_path=?," "totalKills=?,todayKills=?,yesterdayKills=?,chosenTitle=?," - "watchedFaction=?,drunk=?,health=?,power1=?,power2=?,power3=?,power4=?,power5=?,latency=?,speccount=?,activespec=?,exploredZones=?," + "watchedFaction=?,drunk=?,health=?,power1=?,power2=?,power3=?,power4=?,power5=?,latency=?,talentGroupsCount=?,activeTalentGroup=?,exploredZones=?," "equipmentCache=?,knownTitles=?,actionBars=?,grantableLevels=?,online=? WHERE guid=?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG, "UPDATE characters SET at_login = at_login | ? WHERE guid = ?", CONNECTION_ASYNC); @@ -557,9 +557,9 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_PETITION_SIGNATURE_BY_OWNER, "DELETE FROM petition_sign WHERE ownerguid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_PETITION_BY_OWNER_AND_TYPE, "DELETE FROM petition WHERE ownerguid = ? AND type = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_PETITION_SIGNATURE_BY_OWNER_AND_TYPE, "DELETE FROM petition_sign WHERE ownerguid = ? AND type = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHAR_GLYPHS, "INSERT INTO character_glyphs (guid, spec, glyph1, glyph2, glyph3, glyph4, glyph5, glyph6, glyph7, glyph8, glyph9) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_DEL_CHAR_TALENT_BY_SPELL_SPEC, "DELETE FROM character_talent WHERE guid = ? and spell = ? and spec = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_INS_CHAR_TALENT, "INSERT INTO character_talent (guid, spell, spec) VALUES (?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHAR_GLYPHS, "INSERT INTO character_glyphs (guid, talentGroup, glyph1, glyph2, glyph3, glyph4, glyph5, glyph6, glyph7, glyph8, glyph9) 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); PrepareStatement(CHAR_UPD_CHAR_LIST_SLOT, "UPDATE characters SET slot = ? WHERE guid = ? AND account = ?", CONNECTION_ASYNC); |