diff options
author | Shauren <shauren.trinity@gmail.com> | 2025-06-14 14:55:06 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2025-06-14 14:55:06 +0200 |
commit | e6b553b913152667bcd1cfb79790ec70790d0f6e (patch) | |
tree | 740b16f0d018204e500cbd7fb48c7adccd6f34f2 | |
parent | f94d87b00fe384df055d197fe957db083e4fd3c6 (diff) |
Core/Players: Fixed traits not updating aura values when changing rank
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 98 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 15 | ||||
-rw-r--r-- | src/server/game/Handlers/TraitHandler.cpp | 10 | ||||
-rw-r--r-- | src/server/game/Spells/SpellInfo.cpp | 29 |
4 files changed, 81 insertions, 71 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index b4174fe0a91..f48bb73995e 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -2754,7 +2754,7 @@ WorldLocation const* Player::GetStoredAuraTeleportLocation(uint32 spellId) const return nullptr; } -bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent, bool disabled, bool loading /*= false*/, int32 fromSkill /*= 0*/, bool favorite /*= false*/, Optional<int32> traitDefinitionId /*= {}*/) +bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent, bool disabled, bool loading /*= false*/, int32 fromSkill /*= 0*/, bool favorite /*= false*/, Optional<PlayerSpellTrait> trait /*= {}*/) { SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, DIFFICULTY_NONE); if (!spellInfo) @@ -2834,13 +2834,13 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent dependent_set = true; } - if (itr->second.TraitDefinitionId != traitDefinitionId) + if (itr->second.Trait != trait) { - if (itr->second.TraitDefinitionId) - if (TraitDefinitionEntry const* traitDefinition = sTraitDefinitionStore.LookupEntry(*itr->second.TraitDefinitionId)) + if (itr->second.Trait) + if (TraitDefinitionEntry const* traitDefinition = sTraitDefinitionStore.LookupEntry(itr->second.Trait->DefinitionId)) RemoveOverrideSpell(traitDefinition->OverridesSpellID, spellId); - itr->second.TraitDefinitionId = traitDefinitionId; + itr->second.Trait = trait; } itr->second.favorite = favorite; @@ -2918,7 +2918,7 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent LearnSpell(prev_spell, true, fromSkill); } - std::pair<PlayerSpellMap::iterator, bool> inserted = m_spells.emplace(std::piecewise_construct, std::forward_as_tuple(spellId), std::forward_as_tuple()); + std::pair<PlayerSpellMap::iterator, bool> inserted = m_spells.try_emplace(spellId); PlayerSpell& newspell = inserted.first->second; // learning a previous rank might have given us this spell already from a skill autolearn, most likely with PLAYERSPELL_NEW state // we dont want to do double insert if this happened during load from db so we force state to CHANGED, just in case @@ -2927,8 +2927,7 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent newspell.dependent = dependent; newspell.disabled = disabled; newspell.favorite = favorite; - if (traitDefinitionId) - newspell.TraitDefinitionId = *traitDefinitionId; + newspell.Trait = trait; // replace spells in action bars and spellbook to bigger rank if only one spell rank must be accessible if (newspell.active && !newspell.disabled && spellInfo->IsRanked()) @@ -2994,48 +2993,13 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent if (castSpell) { - CastSpellExtraArgs args; - args.SetTriggerFlags(TRIGGERED_FULL_MASK); - - if (traitDefinitionId) - { - if (UF::TraitConfig const* traitConfig = GetTraitConfig(m_activePlayerData->ActiveCombatTraitConfigID)) - { - int32 traitEntryIndex = traitConfig->Entries.FindIndexIf([traitDefinitionId](UF::TraitEntry const& traitEntry) - { - return sTraitNodeEntryStore.AssertEntry(traitEntry.TraitNodeEntryID)->TraitDefinitionID == traitDefinitionId; - }); - int32 rank = 0; - if (traitEntryIndex >= 0) - rank = traitConfig->Entries[traitEntryIndex].Rank + traitConfig->Entries[traitEntryIndex].GrantedRanks; - - if (rank > 0) - { - if (std::vector<TraitDefinitionEffectPointsEntry const*> const* traitDefinitionEffectPoints = TraitMgr::GetTraitDefinitionEffectPointModifiers(*traitDefinitionId)) - { - for (TraitDefinitionEffectPointsEntry const* traitDefinitionEffectPoint : *traitDefinitionEffectPoints) - { - if (traitDefinitionEffectPoint->EffectIndex >= int32(spellInfo->GetEffects().size())) - continue; - - float basePoints = sDB2Manager.GetCurveValueAt(traitDefinitionEffectPoint->CurveID, rank); - if (traitDefinitionEffectPoint->GetOperationType() == TraitPointsOperationType::Multiply) - basePoints *= spellInfo->GetEffect(SpellEffIndex(traitDefinitionEffectPoint->EffectIndex)).CalcBaseValue(this, nullptr, 0, -1); - - args.AddSpellMod(SpellValueMod(SPELLVALUE_BASE_POINT0 + traitDefinitionEffectPoint->EffectIndex), basePoints); - } - } - } - } - } - - CastSpell(this, spellId, args); + CastSpell(this, spellId, true); if (spellInfo->HasEffect(SPELL_EFFECT_SKILL_STEP)) return false; } - if (traitDefinitionId) - if (TraitDefinitionEntry const* traitDefinition = sTraitDefinitionStore.LookupEntry(*traitDefinitionId)) + if (trait) + if (TraitDefinitionEntry const* traitDefinition = sTraitDefinitionStore.LookupEntry(trait->DefinitionId)) if (traitDefinition->OverridesSpellID) AddOverrideSpell(traitDefinition->OverridesSpellID, spellId); @@ -3206,7 +3170,7 @@ bool Player::HandlePassiveSpellLearn(SpellInfo const* spellInfo) return need_cast && (!spellInfo->CasterAuraState || HasAuraState(AuraStateType(spellInfo->CasterAuraState))); } -void Player::LearnSpell(uint32 spell_id, bool dependent, int32 fromSkill /*= 0*/, bool suppressMessaging /*= false*/, Optional<int32> traitDefinitionId /*= {}*/) +void Player::LearnSpell(uint32 spell_id, bool dependent, int32 fromSkill /*= 0*/, bool suppressMessaging /*= false*/, Optional<PlayerSpellTrait> trait /*= {}*/) { PlayerSpellMap::iterator itr = m_spells.find(spell_id); @@ -3214,7 +3178,7 @@ void Player::LearnSpell(uint32 spell_id, bool dependent, int32 fromSkill /*= 0*/ bool active = disabled ? itr->second.active : true; bool favorite = itr != m_spells.end() ? itr->second.favorite : false; - bool learning = AddSpell(spell_id, active, true, dependent, false, false, fromSkill, favorite, traitDefinitionId); + bool learning = AddSpell(spell_id, active, true, dependent, false, false, fromSkill, favorite, trait); // prevent duplicated entires in spell book, also not send if not in world (loading) if (learning && IsInWorld()) @@ -3223,7 +3187,8 @@ void Player::LearnSpell(uint32 spell_id, bool dependent, int32 fromSkill /*= 0*/ WorldPackets::Spells::LearnedSpellInfo& learnedSpellInfo = learnedSpells.ClientLearnedSpellData.emplace_back(); learnedSpellInfo.SpellID = spell_id; learnedSpellInfo.Favorite = favorite; - learnedSpellInfo.TraitDefinitionID = traitDefinitionId; + if (trait) + learnedSpellInfo.TraitDefinitionID = int32(trait->DefinitionId); learnedSpells.SuppressMessaging = suppressMessaging; SendDirectMessage(learnedSpells.Write()); } @@ -3278,7 +3243,7 @@ void Player::RemoveSpell(uint32 spell_id, bool disabled /*= false*/, bool learn_ bool cur_active = itr->second.active; bool cur_dependent = itr->second.dependent; - Optional<int32> traitDefinitionId = itr->second.TraitDefinitionId; + Optional<PlayerSpellTrait> trait = itr->second.Trait; if (disabled) { @@ -3437,8 +3402,8 @@ void Player::RemoveSpell(uint32 spell_id, bool disabled /*= false*/, bool learn_ } } - if (traitDefinitionId) - if (TraitDefinitionEntry const* traitDefinition = sTraitDefinitionStore.LookupEntry(*traitDefinitionId)) + if (trait) + if (TraitDefinitionEntry const* traitDefinition = sTraitDefinitionStore.LookupEntry(trait->DefinitionId)) RemoveOverrideSpell(traitDefinition->OverridesSpellID, spell_id); m_overrideSpells.erase(spell_id); @@ -17643,9 +17608,6 @@ void Player::_LoadEquipmentSets(PreparedQueryResult result) if (ObjectGuid::LowType guid = fields[6 + i].GetUInt64()) eqSet.Data.Pieces[i] = ObjectGuid::Create<HighGuid::Item>(guid); - eqSet.Data.Appearances.fill(0); - eqSet.Data.Enchants.fill(0); - if (eqSet.Data.SetID >= MAX_EQUIPMENT_SET_INDEX) // client limit continue; @@ -17676,7 +17638,6 @@ void Player::_LoadTransmogOutfits(PreparedQueryResult result) eqSet.Data.SetIcon = fields[3].GetString(); eqSet.Data.IgnoreMask = fields[4].GetUInt32(); eqSet.State = EQUIPMENT_SET_UNCHANGED; - eqSet.Data.Pieces.fill(ObjectGuid::Empty); for (uint32 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i) eqSet.Data.Appearances[i] = fields[5 + i].GetInt32(); @@ -28789,7 +28750,7 @@ void Player::ApplyTraitEntryChanges(int32 editedConfigId, WorldPackets::Traits:: // remove traits not found in new config std::set<int32, std::greater<>> entryIndicesToRemove; - for (int32 i = 0; i < int32(editedConfig.Entries.size()); ++i) + for (int32 i = 0; i < std::ssize(editedConfig.Entries); ++i) { UF::TraitEntry const& oldEntry = editedConfig.Entries[i]; auto entryItr = std::ranges::find_if(newConfig.Entries, makeTraitEntryFinder(oldEntry.TraitNodeID, oldEntry.TraitNodeEntryID)); @@ -28812,9 +28773,8 @@ void Player::ApplyTraitEntryChanges(int32 editedConfigId, WorldPackets::Traits:: std::vector<WorldPackets::Traits::TraitEntry> costEntries; // apply new traits - for (std::size_t i = 0; i < newConfig.Entries.size(); ++i) + for (WorldPackets::Traits::TraitEntry const& newEntry : newConfig.Entries) { - WorldPackets::Traits::TraitEntry const& newEntry = newConfig.Entries[i]; int32 oldEntryIndex = editedConfig.Entries.FindIndexIf(makeTraitEntryFinder(newEntry.TraitNodeID, newEntry.TraitNodeEntryID)); if (oldEntryIndex < 0) { @@ -28851,7 +28811,10 @@ void Player::ApplyTraitEntryChanges(int32 editedConfigId, WorldPackets::Traits:: .ModifyValue(&UF::TraitEntry::GrantedRanks), newEntry.GrantedRanks); if (applyTraits) + { + ApplyTraitEntry(newEntry.TraitNodeEntryID, 0, 0, false); ApplyTraitEntry(newEntry.TraitNodeEntryID, newEntry.Rank, newEntry.GrantedRanks, true); + } } } @@ -28880,9 +28843,8 @@ void Player::ApplyTraitEntryChanges(int32 editedConfigId, WorldPackets::Traits:: } } - for (std::size_t i = 0; i < newConfig.SubTrees.size(); ++i) + for (WorldPackets::Traits::TraitSubTreeCache const& newSubTree : newConfig.SubTrees) { - WorldPackets::Traits::TraitSubTreeCache const& newSubTree = newConfig.SubTrees[i]; int32 oldSubTreeIndex = editedConfig.SubTrees.FindIndexIf([&](UF::TraitSubTreeCache const& ufSubTree) { return ufSubTree.TraitSubTreeID == newSubTree.TraitSubTreeID; }); std::vector<UF::TraitEntry> subTreeEntries; subTreeEntries.resize(newSubTree.Entries.size()); @@ -28894,6 +28856,7 @@ void Player::ApplyTraitEntryChanges(int32 editedConfigId, WorldPackets::Traits:: newUfEntry.Rank = newSubTree.Entries[j].Rank; newUfEntry.GrantedRanks = newSubTree.Entries[j].GrantedRanks; } + if (oldSubTreeIndex < 0) { UF::TraitSubTreeCache& newUfSubTree = AddDynamicUpdateFieldValue(m_values.ModifyValue(&Player::m_activePlayerData) @@ -28972,7 +28935,7 @@ void Player::ApplyTraitConfig(int32 configId, bool apply) ApplyTraitEntry(traitEntry.TraitNodeEntryID, traitEntry.Rank, traitEntry.GrantedRanks, apply); } -void Player::ApplyTraitEntry(int32 traitNodeEntryId, int32 /*rank*/, int32 /*grantedRanks*/, bool apply) +void Player::ApplyTraitEntry(int32 traitNodeEntryId, int32 rank, int32 grantedRanks, bool apply) { TraitNodeEntryEntry const* traitNodeEntry = sTraitNodeEntryStore.LookupEntry(traitNodeEntryId); if (!traitNodeEntry) @@ -28984,8 +28947,10 @@ void Player::ApplyTraitEntry(int32 traitNodeEntryId, int32 /*rank*/, int32 /*gra if (traitDefinition->SpellID) { + ASSERT(traitNodeEntry->TraitDefinitionID <= 0xFFFFFF && rank + grantedRanks <= 0xFF); + if (apply) - LearnSpell(traitDefinition->SpellID, true, 0, false, traitNodeEntry->TraitDefinitionID); + LearnSpell(traitDefinition->SpellID, true, 0, false, PlayerSpellTrait{ .DefinitionId = traitNodeEntry->TraitDefinitionID, .Rank = rank + grantedRanks }); else RemoveSpell(traitDefinition->SpellID); } @@ -29064,6 +29029,13 @@ void Player::SetTraitConfigUseSharedActionBars(int32 traitConfigId, bool usesSha m_traitConfigStates[traitConfigId] = PLAYERSPELL_CHANGED; } +Optional<PlayerSpellTrait> Player::GetTraitInfoForSpell(uint32 spellId) const +{ + if (PlayerSpell const* spell = Trinity::Containers::MapGetValuePtr(m_spells, spellId)) + return spell->Trait; + return {}; +} + void Player::SetReputation(uint32 factionentry, int32 value) { GetReputationMgr().SetReputation(sFactionStore.LookupEntry(factionentry), value); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 7389695ce38..bdce5bc9b76 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -200,6 +200,14 @@ enum PlayerSpellState : uint8 PLAYERSPELL_TEMPORARY = 4 }; +struct PlayerSpellTrait +{ + int32 DefinitionId : 24; + int32 Rank : 8; + + friend bool operator==(PlayerSpellTrait const&, PlayerSpellTrait const&) noexcept = default; +}; + struct PlayerSpell { PlayerSpellState state; @@ -207,7 +215,7 @@ struct PlayerSpell bool dependent : 1; // learned as result another spell learn, skill grow, quest reward, etc bool disabled : 1; // first rank has been learned in result talent learn but currently talent unlearned, save max learned ranks bool favorite : 1; - Optional<int32> TraitDefinitionId; + Optional<PlayerSpellTrait> Trait; }; struct StoredAuraTeleportLocation @@ -1891,8 +1899,8 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player> void SendProficiency(ItemClass itemClass, uint32 itemSubclassMask) const; void SendKnownSpells(); void SendUnlearnSpells(); - bool AddSpell(uint32 spellId, bool active, bool learning, bool dependent, bool disabled, bool loading = false, int32 fromSkill = 0, bool favorite = false, Optional<int32> traitDefinitionId = {}); - void LearnSpell(uint32 spell_id, bool dependent, int32 fromSkill = 0, bool suppressMessaging = false, Optional<int32> traitDefinitionId = {}); + bool AddSpell(uint32 spellId, bool active, bool learning, bool dependent, bool disabled, bool loading = false, int32 fromSkill = 0, bool favorite = false, Optional<PlayerSpellTrait> trait = {}); + void LearnSpell(uint32 spell_id, bool dependent, int32 fromSkill = 0, bool suppressMessaging = false, Optional<PlayerSpellTrait> trait = {}); void RemoveSpell(uint32 spell_id, bool disabled = false, bool learn_low_rank = true, bool suppressMessaging = false); void ResetSpells(bool myClassOnly = false); void LearnCustomSpells(); @@ -1986,6 +1994,7 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player> void SetActiveCombatTraitConfigID(int32 traitConfigId) { SetUpdateFieldValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::ActiveCombatTraitConfigID), traitConfigId); } void SetTraitConfigUseStarterBuild(int32 traitConfigId, bool useStarterBuild); void SetTraitConfigUseSharedActionBars(int32 traitConfigId, bool usesSharedActionBars, bool isLastSelectedSavedConfig); + Optional<PlayerSpellTrait> GetTraitInfoForSpell(uint32 spellId) const; uint32 GetFreePrimaryProfessionPoints() const { return m_activePlayerData->CharacterPoints; } void SetFreePrimaryProfessions(uint16 profs) { SetUpdateFieldValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::CharacterPoints), profs); } diff --git a/src/server/game/Handlers/TraitHandler.cpp b/src/server/game/Handlers/TraitHandler.cpp index 1e1de92a139..086e25bc0b4 100644 --- a/src/server/game/Handlers/TraitHandler.cpp +++ b/src/server/game/Handlers/TraitHandler.cpp @@ -47,7 +47,7 @@ void WorldSession::HandleTraitsCommitConfig(WorldPackets::Traits::TraitsCommitCo auto findEntry = [](WorldPackets::Traits::TraitConfig& config, int32 traitNodeId, int32 traitNodeEntryId) -> WorldPackets::Traits::TraitEntry* { - auto entryItr = std::find_if(config.Entries.begin(), config.Entries.end(), [=](WorldPackets::Traits::TraitEntry const& traitEntry) + auto entryItr = std::ranges::find_if(config.Entries, [=](WorldPackets::Traits::TraitEntry const& traitEntry) { return traitEntry.TraitNodeID == traitNodeId && traitEntry.TraitNodeEntryID == traitNodeEntryId; }); @@ -118,10 +118,10 @@ void WorldSession::HandleTraitsCommitConfig(WorldPackets::Traits::TraitsCommitCo if (newEntry.Rank) traitEntry->Rank = newEntry.Rank; else - newConfigState.Entries.erase(std::remove_if(newConfigState.Entries.begin(), newConfigState.Entries.end(), [&newEntry](WorldPackets::Traits::TraitEntry const& traitEntry) + std::erase_if(newConfigState.Entries, [&newEntry](WorldPackets::Traits::TraitEntry const& traitEntry) { return traitEntry.TraitNodeID == newEntry.TraitNodeID && traitEntry.TraitNodeEntryID == newEntry.TraitNodeEntryID; - }), newConfigState.Entries.end()); + }); } else newConfigState.Entries.emplace_back() = newEntry; @@ -152,7 +152,7 @@ void WorldSession::HandleClassTalentsRequestNewConfig(WorldPackets::Traits::Clas if ((classTalentsRequestNewConfig.Config.CombatConfigFlags & TraitCombatConfigFlags::ActiveForSpec) != TraitCombatConfigFlags::None) return; - int64 configCount = std::count_if(_player->m_activePlayerData->TraitConfigs.begin(), _player->m_activePlayerData->TraitConfigs.end(), [](UF::TraitConfig const& traitConfig) + int64 configCount = std::ranges::count_if(_player->m_activePlayerData->TraitConfigs, [](UF::TraitConfig const& traitConfig) { return static_cast<TraitConfigType>(*traitConfig.Type) == TraitConfigType::Combat && (static_cast<TraitCombatConfigFlags>(*traitConfig.CombatConfigFlags) & TraitCombatConfigFlags::ActiveForSpec) == TraitCombatConfigFlags::None; @@ -179,7 +179,7 @@ void WorldSession::HandleClassTalentsRequestNewConfig(WorldPackets::Traits::Clas for (UF::TraitEntry const& grantedEntry : TraitMgr::GetGrantedTraitEntriesForConfig(classTalentsRequestNewConfig.Config, _player)) { - auto entryItr = std::find_if(classTalentsRequestNewConfig.Config.Entries.begin(), classTalentsRequestNewConfig.Config.Entries.end(), + auto entryItr = std::ranges::find_if(classTalentsRequestNewConfig.Config.Entries, [&](WorldPackets::Traits::TraitEntry const& entry) { return entry.TraitNodeID == grantedEntry.TraitNodeID && entry.TraitNodeEntryID == grantedEntry.TraitNodeEntryID; }); WorldPackets::Traits::TraitEntry& newEntry = entryItr != classTalentsRequestNewConfig.Config.Entries.end() ? *entryItr : classTalentsRequestNewConfig.Config.Entries.emplace_back(); diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index 12d9947db55..7e81e5570f2 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -35,6 +35,7 @@ #include "Spell.h" #include "SpellAuraEffects.h" #include "SpellMgr.h" +#include "TraitMgr.h" #include "Vehicle.h" #include <G3D/g3dmath.h> #include <bit> @@ -503,7 +504,35 @@ int32 SpellEffectInfo::CalcValue(WorldObject const* caster /*= nullptr*/, int32 Unit const* casterUnit = nullptr; if (caster) + { casterUnit = caster->ToUnit(); + if (Player const* playerCaster = caster->ToPlayer()) + { + if (Optional<PlayerSpellTrait> trait = playerCaster->GetTraitInfoForSpell(_spellInfo->Id)) + { + if (std::vector<TraitDefinitionEffectPointsEntry const*> const* traitDefinitionEffectPoints = TraitMgr::GetTraitDefinitionEffectPointModifiers(trait->DefinitionId)) + { + auto pointsOverride = std::ranges::find(*traitDefinitionEffectPoints, EffectIndex, &TraitDefinitionEffectPointsEntry::EffectIndex); + if (pointsOverride != traitDefinitionEffectPoints->end()) + { + float traitBasePoints = sDB2Manager.GetCurveValueAt((*pointsOverride)->CurveID, trait->Rank); + switch ((*pointsOverride)->GetOperationType()) + { + case TraitPointsOperationType::Set: + value = traitBasePoints; + break; + case TraitPointsOperationType::Multiply: + value *= traitBasePoints; + break; + case TraitPointsOperationType::None: + default: + break; + } + } + } + } + } + } if (Scaling.Variance) { |