diff options
-rw-r--r-- | sql/updates/characters/3.4.x/2023_11_19_00_characters.sql | 4 | ||||
-rw-r--r-- | src/server/database/Database/Implementation/CharacterDatabase.cpp | 12 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 90 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 9 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.h | 3 | ||||
-rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 17 |
6 files changed, 55 insertions, 80 deletions
diff --git a/sql/updates/characters/3.4.x/2023_11_19_00_characters.sql b/sql/updates/characters/3.4.x/2023_11_19_00_characters.sql new file mode 100644 index 00000000000..c20683eff7f --- /dev/null +++ b/sql/updates/characters/3.4.x/2023_11_19_00_characters.sql @@ -0,0 +1,4 @@ +ALTER TABLE `characters_10x`.`characters` + DROP COLUMN `activeTalentGroup`, + CHANGE `primarySpecialization` `activeTalentGroup` TINYINT UNSIGNED DEFAULT 0 NOT NULL, + ADD COLUMN `bonusTalentGroups` TINYINT UNSIGNED DEFAULT 0 NOT NULL AFTER `activeTalentGroup`; diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index e6b325b36d7..a47068200b9 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp @@ -94,9 +94,9 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_CHARACTER, "SELECT c.guid, account, name, race, class, gender, level, xp, money, inventorySlots, bankSlots, restState, playerFlags, playerFlagsEx, " "position_x, position_y, position_z, map, orientation, taximask, createTime, createMode, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, " - "resettalents_time, primarySpecialization, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, summonedPetNumber, at_login, zone, online, death_expire_time, taxi_path, dungeonDifficulty, " + "resettalents_time, activeTalentGroup, bonusTalentGroups, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, summonedPetNumber, at_login, zone, online, death_expire_time, taxi_path, dungeonDifficulty, " "totalKills, todayKills, yesterdayKills, chosenTitle, watchedFaction, drunk, " - "health, power1, power2, power3, power4, power5, power6, power7, power8, power9, power10, instance_id, activeTalentGroup, lootSpecId, exploredZones, knownTitles, actionBars, " + "health, power1, power2, power3, power4, power5, power6, power7, power8, power9, power10, instance_id, lootSpecId, exploredZones, knownTitles, actionBars, " "raidDifficulty, legacyRaidDifficulty, fishingSteps, honor, honorLevel, honorRestState, honorRestBonus, numRespecs, " "personalTabardEmblemStyle, personalTabardEmblemColor, personalTabardBorderStyle, personalTabardBorderColor, personalTabardBackgroundColor " "FROM characters c LEFT JOIN character_fishingsteps cfs ON c.guid = cfs.guid WHERE c.guid = ?", CONNECTION_ASYNC); @@ -475,17 +475,17 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_INS_CHARACTER, "INSERT INTO characters (guid, account, name, race, class, gender, level, xp, money, inventorySlots, bankSlots, restState, playerFlags, playerFlagsEx, " "map, instance_id, dungeonDifficulty, raidDifficulty, legacyRaidDifficulty, position_x, position_y, position_z, orientation, trans_x, trans_y, trans_z, trans_o, transguid, " "taximask, createTime, createMode, cinematic, " - "totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, primarySpecialization, " + "totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, activeTalentGroup, bonusTalentGroups," "extra_flags, summonedPetNumber, at_login, " "death_expire_time, taxi_path, totalKills, " "todayKills, yesterdayKills, chosenTitle, watchedFaction, drunk, health, power1, power2, power3, " - "power4, power5, power6, power7, power8, power9, power10, latency, activeTalentGroup, lootSpecId, exploredZones, equipmentCache, knownTitles, actionBars, lastLoginBuild) VALUES " + "power4, power5, power6, power7, power8, power9, power10, latency, lootSpecId, exploredZones, equipmentCache, knownTitles, actionBars, lastLoginBuild) VALUES " "(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_CHARACTER, "UPDATE characters SET name=?,race=?,class=?,gender=?,level=?,xp=?,money=?,inventorySlots=?,bankSlots=?,restState=?,playerFlags=?,playerFlagsEx=?," "map=?,instance_id=?,dungeonDifficulty=?,raidDifficulty=?,legacyRaidDifficulty=?,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=?,numRespecs=?,primarySpecialization=?,extra_flags=?,summonedPetNumber=?,at_login=?,zone=?,death_expire_time=?,taxi_path=?," + "logout_time=?,is_logout_resting=?,resettalents_cost=?,resettalents_time=?,numRespecs=?,activeTalentGroup=?,bonusTalentGroups=?,extra_flags=?,summonedPetNumber=?,at_login=?,zone=?,death_expire_time=?,taxi_path=?," "totalKills=?,todayKills=?,yesterdayKills=?,chosenTitle=?," - "watchedFaction=?,drunk=?,health=?,power1=?,power2=?,power3=?,power4=?,power5=?,power6=?,power7=?,power8=?,power9=?,power10=?,latency=?,activeTalentGroup=?,lootSpecId=?,exploredZones=?," + "watchedFaction=?,drunk=?,health=?,power1=?,power2=?,power3=?,power4=?,power5=?,power6=?,power7=?,power8=?,power9=?,power10=?,latency=?,lootSpecId=?,exploredZones=?," "equipmentCache=?,knownTitles=?,actionBars=?,online=?,honor=?,honorLevel=?,honorRestState=?,honorRestBonus=?,lastLoginBuild=? WHERE guid=?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG, "UPDATE characters SET at_login = at_login | ? WHERE guid = ?", CONNECTION_ASYNC); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index f69d5b80ba9..3e41f2aa05d 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -2358,7 +2358,6 @@ void Player::GiveLevel(uint8 level) UpdateSkillsForLevel(); LearnDefaultSkills(); - LearnSpecializationSpells(); // save base values (bonuses already included in stored stats for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i) @@ -17123,7 +17122,8 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol uint8 is_logout_resting; uint32 resettalents_cost; time_t resettalents_time; - uint32 primarySpecialization; + uint8 activeTalentGroup; + uint8 bonusTalentGroups; float trans_x; float trans_y; float trans_z; @@ -17146,7 +17146,6 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol uint32 health; std::array<uint32, MAX_POWERS_PER_CLASS> powers; uint32 instance_id; - uint8 activeTalentGroup; uint32 lootSpecId; std::string exploredZones; std::string knownTitles; @@ -17198,7 +17197,8 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol is_logout_resting = fields[i++].GetUInt8(); resettalents_cost = fields[i++].GetUInt32(); resettalents_time = fields[i++].GetInt64(); - primarySpecialization = fields[i++].GetUInt32(); + activeTalentGroup = fields[i++].GetUInt8(); + bonusTalentGroups = fields[i++].GetUInt8(); trans_x = fields[i++].GetFloat(); trans_y = fields[i++].GetFloat(); trans_z = fields[i++].GetFloat(); @@ -17222,7 +17222,6 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol for (uint32& power : powers) power = fields[i++].GetUInt32(); instance_id = fields[i++].GetUInt32(); - activeTalentGroup = fields[i++].GetUInt8(); lootSpecId = fields[i++].GetUInt32(); exploredZones = fields[i++].GetString(); knownTitles = fields[i++].GetString(); @@ -17710,8 +17709,8 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol UpdateSkillsForLevel(); //update skills after load, to make sure they are correctly update at player load SetNumRespecs(fields.numRespecs); - SetPrimarySpecialization(fields.primarySpecialization); SetActiveTalentGroup(fields.activeTalentGroup); + SetBonusTalentGroupCount(fields.bonusTalentGroups); uint32 lootSpecId = fields.lootSpecId; if (ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(lootSpecId)) @@ -17727,8 +17726,6 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol GetSession()->GetCollectionMgr()->LoadItemAppearances(); GetSession()->GetCollectionMgr()->LoadTransmogIllusions(); - 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(); @@ -19469,7 +19466,8 @@ void Player::SaveToDB(LoginDatabaseTransaction loginTransaction, CharacterDataba //save, but in tavern/city stmt->setUInt32(index++, GetTalentResetCost()); stmt->setInt64(index++, GetTalentResetTime()); - stmt->setUInt32(index++, AsUnderlyingType(GetPrimarySpecialization())); + stmt->setUInt8(index++, GetActiveTalentGroup()); + stmt->setUInt8(index++, GetBonusTalentGroupCount()); stmt->setUInt16(index++, (uint16)m_ExtraFlags); stmt->setUInt32(index++, 0); // summonedPetNumber stmt->setUInt16(index++, (uint16)m_atLoginFlags); @@ -19491,9 +19489,6 @@ void Player::SaveToDB(LoginDatabaseTransaction loginTransaction, CharacterDataba stmt->setUInt32(index++, m_unitData->Power[i]); stmt->setUInt32(index++, GetSession()->GetLatency()); - - stmt->setUInt8(index++, GetActiveTalentGroup()); - stmt->setUInt32(index++, GetLootSpecId()); ss.str(""); @@ -19602,7 +19597,8 @@ void Player::SaveToDB(LoginDatabaseTransaction loginTransaction, CharacterDataba stmt->setUInt32(index++, GetTalentResetCost()); stmt->setInt64(index++, GetTalentResetTime()); stmt->setUInt8(index++, GetNumRespecs()); - stmt->setUInt32(index++, AsUnderlyingType(GetPrimarySpecialization())); + stmt->setUInt8(index++, GetActiveTalentGroup()); + stmt->setUInt8(index++, GetBonusTalentGroupCount()); stmt->setUInt16(index++, (uint16)m_ExtraFlags); if (PetStable const* petStable = GetPetStable()) stmt->setUInt32(index++, petStable->GetCurrentPet() && petStable->GetCurrentPet()->Health > 0 ? petStable->GetCurrentPet()->PetNumber : 0); // summonedPetNumber @@ -19628,9 +19624,6 @@ void Player::SaveToDB(LoginDatabaseTransaction loginTransaction, CharacterDataba stmt->setUInt32(index++, m_unitData->Power[i]); stmt->setUInt32(index++, GetSession()->GetLatency()); - - stmt->setUInt8(index++, GetActiveTalentGroup()); - stmt->setUInt32(index++, GetLootSpecId()); ss.str(""); @@ -26378,9 +26371,7 @@ void Player::SendTalentsInfoData() uint8 activeGroup = GetActiveTalentGroup(); packet.ActiveGroup = activeGroup; - printf("sending talent info data for group %u\n", activeGroup); - - for (uint8 i = 0; i < MAX_SPECIALIZATIONS; ++i) + for (uint8 i = 0; i < (1 + GetBonusTalentGroupCount()); ++i) { WorldPackets::Talent::TalentGroupInfo& groupInfo = packet.TalentGroupInfos.emplace_back(); groupInfo.SpecID = MAX_SPECIALIZATIONS; @@ -27036,9 +27027,6 @@ void Player::ActivateTalentGroup(uint8 talentGroup) ApplyTraitConfig(m_activePlayerData->ActiveCombatTraitConfigID, false); - // Remove spec specific spells - RemoveSpecializationSpells(); - for (uint32 glyphId : GetGlyphs(GetActiveTalentGroup())) RemoveAurasDueToSpell(sGlyphPropertiesStore.AssertEntry(glyphId)->SpellID); @@ -27067,8 +27055,6 @@ void Player::ActivateTalentGroup(uint8 talentGroup) } } - LearnSpecializationSpells(); - InitTalentForLevel(); StartLoadingActionButtons(); @@ -28676,48 +28662,6 @@ void Player::RemoveOverrideSpell(uint32 overridenSpellId, uint32 newSpellId) m_overrideSpells.erase(overrides); } -void Player::LearnSpecializationSpells() -{ - if (std::vector<SpecializationSpellsEntry const*> const* specSpells = sDB2Manager.GetSpecializationSpells(AsUnderlyingType(GetPrimarySpecialization()))) - { - for (size_t j = 0; j < specSpells->size(); ++j) - { - SpecializationSpellsEntry const* specSpell = (*specSpells)[j]; - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(specSpell->SpellID, DIFFICULTY_NONE); - if (!spellInfo || spellInfo->SpellLevel > GetLevel()) - continue; - - LearnSpell(specSpell->SpellID, true); - if (specSpell->OverridesSpellID) - AddOverrideSpell(specSpell->OverridesSpellID, specSpell->SpellID); - } - } -} - -void Player::RemoveSpecializationSpells() -{ - for (uint32 i = 0; i < MAX_SPECIALIZATIONS; ++i) - { - if (ChrSpecializationEntry const* specialization = sDB2Manager.GetChrSpecializationByIndex(GetClass(), i)) - { - if (std::vector<SpecializationSpellsEntry const*> const* specSpells = sDB2Manager.GetSpecializationSpells(specialization->ID)) - { - for (size_t j = 0; j < specSpells->size(); ++j) - { - SpecializationSpellsEntry const* specSpell = (*specSpells)[j]; - RemoveSpell(specSpell->SpellID, true); - if (specSpell->OverridesSpellID) - RemoveOverrideSpell(specSpell->OverridesSpellID, specSpell->SpellID); - } - } - - for (uint32 j = 0; j < MAX_MASTERY_SPELLS; ++j) - if (uint32 mastery = specialization->MasterySpellID[j]) - RemoveAurasDueToSpell(mastery); - } - } -} - void Player::AddSpellCategoryCooldownMod(int32 spellCategoryId, int32 mod) { int32 categoryIndex = m_activePlayerData->CategoryCooldownMods.FindIndexIf([spellCategoryId](UF::CategoryCooldownMod const& mod) @@ -28778,6 +28722,20 @@ uint32 Player::GetDefaultSpecId() const { return ASSERT_NOTNULL(sDB2Manager.GetDefaultChrSpecializationForClass(GetClass()))->ID; } +void Player::SetBonusTalentGroupCount(uint8 amount) +{ + if (_specializationInfo.BonusGroups == amount) + return; + + _specializationInfo.BonusGroups = std::min<uint8>(amount, MAX_SPECIALIZATIONS - 1); + if (GetActiveTalentGroup() > amount) + { + ResetTalents(true); + ActivateTalentGroup(0); + } + else + SendTalentsInfoData(); +} ChrSpecializationEntry const* Player::GetPrimarySpecializationEntry() const { diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index c9b6e4fd7bc..0a6dc73fda6 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1065,13 +1065,14 @@ enum TalentLearnResult : int32 struct TC_GAME_API SpecializationInfo { - SpecializationInfo() : ResetTalentsCost(0), ResetTalentsTime(0), ActiveGroup(0) { } + SpecializationInfo() : ResetTalentsCost(0), ResetTalentsTime(0), ActiveGroup(0), BonusGroups(0) { } PlayerTalentMap Talents[MAX_SPECIALIZATIONS]; std::vector<uint32> Glyphs[MAX_SPECIALIZATIONS]; uint32 ResetTalentsCost; time_t ResetTalentsTime; uint8 ActiveGroup; + uint8 BonusGroups; private: SpecializationInfo(SpecializationInfo const&) = delete; @@ -1793,8 +1794,6 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void SetOverrideSpellsId(int32 overrideSpellsId) { SetUpdateFieldValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::OverrideSpellsID), overrideSpellsId); } void AddOverrideSpell(uint32 overridenSpellId, uint32 newSpellId); void RemoveOverrideSpell(uint32 overridenSpellId, uint32 newSpellId); - void LearnSpecializationSpells(); - void RemoveSpecializationSpells(); void AddSpellCategoryCooldownMod(int32 spellCategoryId, int32 mod); void RemoveSpellCategoryCooldownMod(int32 spellCategoryId, int32 mod); void SetSpellFavorite(uint32 spellId, bool favorite); @@ -1822,7 +1821,9 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> ChrSpecialization GetPrimarySpecialization() const { return ChrSpecialization(*m_playerData->CurrentSpecID); } void SetPrimarySpecialization(uint32 spec) { SetUpdateFieldValue(m_values.ModifyValue(&Player::m_playerData).ModifyValue(&UF::PlayerData::CurrentSpecID), spec); } uint8 GetActiveTalentGroup() const { return _specializationInfo.ActiveGroup; } - void SetActiveTalentGroup(uint8 group){ _specializationInfo.ActiveGroup = group; } + void SetActiveTalentGroup(uint8 group) { _specializationInfo.ActiveGroup = group; } + uint8 GetBonusTalentGroupCount() const { return _specializationInfo.BonusGroups; } + void SetBonusTalentGroupCount(uint8 amount); uint32 GetDefaultSpecId() const; ChrSpecializationEntry const* GetPrimarySpecializationEntry() const; diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index b16bf1eb5e6..f8026844fbc 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -370,7 +370,8 @@ class TC_GAME_API Spell void EffectTitanGrip(); void EffectEnchantItemPrismatic(); void EffectPlayMusic(); - void EffectActivateSpec(); + void EffectTalentSpecCount(); + void EffectTalentSpecSelect(); void EffectPlaySound(); void EffectRemoveAura(); void EffectDamageFromMaxHealthPCT(); diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 389e27c459e..69cecbbaf57 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -246,8 +246,8 @@ NonDefaultConstructible<SpellEffectHandlerFn> SpellEffectHandlers[TOTAL_SPELL_EF &Spell::EffectMilling, //158 SPELL_EFFECT_MILLING milling &Spell::EffectRenamePet, //159 SPELL_EFFECT_ALLOW_RENAME_PET allow rename pet once again &Spell::EffectForceCast, //160 SPELL_EFFECT_FORCE_CAST_2 - &Spell::EffectNULL, //161 SPELL_EFFECT_TALENT_SPEC_COUNT second talent spec (learn/revert) - &Spell::EffectActivateSpec, //162 SPELL_EFFECT_TALENT_SPEC_SELECT activate primary/secondary spec + &Spell::EffectTalentSpecCount, //161 SPELL_EFFECT_TALENT_SPEC_COUNT second talent spec (learn/revert) + &Spell::EffectTalentSpecSelect, //162 SPELL_EFFECT_TALENT_SPEC_SELECT activate primary/secondary spec &Spell::EffectNULL, //163 SPELL_EFFECT_OBLITERATE_ITEM &Spell::EffectRemoveAura, //164 SPELL_EFFECT_REMOVE_AURA &Spell::EffectDamageFromMaxHealthPCT, //165 SPELL_EFFECT_DAMAGE_FROM_MAX_HEALTH_PCT @@ -4982,7 +4982,18 @@ void Spell::EffectPlayMusic() unitTarget->ToPlayer()->SendDirectMessage(WorldPackets::Misc::PlayMusic(soundid).Write()); } -void Spell::EffectActivateSpec() +void Spell::EffectTalentSpecCount() +{ + if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) + return; + + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + unitTarget->ToPlayer()->SetBonusTalentGroupCount(static_cast<uint8>(effectInfo->BasePoints)); +} + +void Spell::EffectTalentSpecSelect() { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; |