Core/Players: Fixed traits not updating aura values when changing rank

Port From (https://github.com/TrinityCore/TrinityCore/commit/e6b553b913152667bcd1cfb79790ec70790d0f6e)
This commit is contained in:
Hondacrx
2025-08-18 10:32:35 -04:00
parent 51fbf8e33e
commit 32d166380c
4 changed files with 91 additions and 60 deletions
+18 -55
View File
@@ -2141,7 +2141,7 @@ namespace Game.Entities
SendPacket(new SendUnlearnSpells());
}
public void LearnSpell(uint spellId, bool dependent, uint fromSkill = 0, bool suppressMessaging = false, int? traitDefinitionId = null)
public void LearnSpell(uint spellId, bool dependent, uint fromSkill = 0, bool suppressMessaging = false, PlayerSpellTrait trait = null)
{
PlayerSpell spell = m_spells.LookupByKey(spellId);
@@ -2149,7 +2149,7 @@ namespace Game.Entities
bool active = !disabled || spell.Active;
bool favorite = spell != null ? spell.Favorite : false;
bool learning = AddSpell(spellId, active, true, dependent, false, false, fromSkill, favorite, traitDefinitionId);
bool learning = AddSpell(spellId, 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)
@@ -2158,7 +2158,8 @@ namespace Game.Entities
LearnedSpellInfo learnedSpellInfo = new();
learnedSpellInfo.SpellID = spellId;
learnedSpellInfo.Favorite = favorite;
learnedSpellInfo.TraitDefinitionID = traitDefinitionId;
if (trait != null)
learnedSpellInfo.TraitDefinitionID = trait.DefinitionId;
learnedSpells.SuppressMessaging = suppressMessaging;
learnedSpells.ClientLearnedSpellData.Add(learnedSpellInfo);
SendPacket(learnedSpells);
@@ -2216,7 +2217,7 @@ namespace Game.Entities
bool cur_active = pSpell.Active;
bool cur_dependent = pSpell.Dependent;
int? traitDefinitionId = pSpell.TraitDefinitionId;
PlayerSpellTrait trait = pSpell.Trait;
if (disabled)
{
@@ -2380,9 +2381,9 @@ namespace Game.Entities
}
}
if (traitDefinitionId.HasValue)
if (trait != null)
{
var traitDefinition = CliDB.TraitDefinitionStorage.LookupByKey(traitDefinitionId.Value);
var traitDefinition = CliDB.TraitDefinitionStorage.LookupByKey(trait.DefinitionId);
if (traitDefinition != null)
RemoveOverrideSpell(traitDefinition.OverridesSpellID, spellId);
}
@@ -2480,7 +2481,7 @@ namespace Game.Entities
return null;
}
bool AddSpell(uint spellId, bool active, bool learning, bool dependent, bool disabled, bool loading = false, uint fromSkill = 0, bool favorite = false, int? traitDefinitionId = null)
bool AddSpell(uint spellId, bool active, bool learning, bool dependent, bool disabled, bool loading = false, uint fromSkill = 0, bool favorite = false, PlayerSpellTrait? trait = null)
{
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, Difficulty.None);
if (spellInfo == null)
@@ -2559,16 +2560,16 @@ namespace Game.Entities
dependent_set = true;
}
if (spell.TraitDefinitionId != traitDefinitionId)
if (spell.Trait != trait)
{
if (spell.TraitDefinitionId.HasValue)
if (spell.Trait != null)
{
TraitDefinitionRecord traitDefinition = CliDB.TraitDefinitionStorage.LookupByKey(spell.TraitDefinitionId.Value);
TraitDefinitionRecord traitDefinition = CliDB.TraitDefinitionStorage.LookupByKey(spell.Trait.DefinitionId);
if (traitDefinition != null)
RemoveOverrideSpell((uint)traitDefinition.OverridesSpellID, spellId);
RemoveOverrideSpell(traitDefinition.OverridesSpellID, spellId);
}
spell.TraitDefinitionId = traitDefinitionId;
spell.Trait = trait;
}
spell.Favorite = favorite;
@@ -2655,8 +2656,7 @@ namespace Game.Entities
newspell.Dependent = dependent;
newspell.Disabled = disabled;
newspell.Favorite = favorite;
if (traitDefinitionId.HasValue)
newspell.TraitDefinitionId = traitDefinitionId.Value;
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())
@@ -2725,51 +2725,14 @@ namespace Game.Entities
if (castSpell)
{
CastSpellExtraArgs args = new(TriggerCastFlags.FullMask);
if (traitDefinitionId.HasValue)
{
TraitConfig traitConfig = GetTraitConfig((int)(uint)m_activePlayerData.ActiveCombatTraitConfigID);
if (traitConfig != null)
{
int traitEntryIndex = traitConfig.Entries.FindIndexIf(traitEntry =>
{
return CliDB.TraitNodeEntryStorage.LookupByKey(traitEntry.TraitNodeEntryID)?.TraitDefinitionID == traitDefinitionId;
});
int rank = 0;
if (traitEntryIndex >= 0)
rank = traitConfig.Entries[traitEntryIndex].Rank + traitConfig.Entries[traitEntryIndex].GrantedRanks;
if (rank > 0)
{
var traitDefinitionEffectPoints = TraitMgr.GetTraitDefinitionEffectPointModifiers(traitDefinitionId.Value);
if (traitDefinitionEffectPoints != null)
{
foreach (TraitDefinitionEffectPointsRecord traitDefinitionEffectPoint in traitDefinitionEffectPoints)
{
if (traitDefinitionEffectPoint.EffectIndex >= spellInfo.GetEffects().Count)
continue;
float basePoints = Global.DB2Mgr.GetCurveValueAt((uint)traitDefinitionEffectPoint.CurveID, rank);
if (traitDefinitionEffectPoint.GetOperationType() == TraitPointsOperationType.Multiply)
basePoints *= spellInfo.GetEffect((uint)traitDefinitionEffectPoint.EffectIndex).CalcBaseValue(this, null, 0, -1);
args.AddSpellMod(SpellValueMod.BasePoint0 + traitDefinitionEffectPoint.EffectIndex, (int)basePoints);
}
}
}
}
}
CastSpell(this, spellId, args);
CastSpell(this, spellId, true);
if (spellInfo.HasEffect(SpellEffectName.SkillStep))
return false;
}
if (traitDefinitionId.HasValue)
if (trait != null)
{
TraitDefinitionRecord traitDefinition = CliDB.TraitDefinitionStorage.LookupByKey(traitDefinitionId.Value);
TraitDefinitionRecord traitDefinition = CliDB.TraitDefinitionStorage.LookupByKey(trait.DefinitionId);
if (traitDefinition != null && traitDefinition.OverridesSpellID != 0)
AddOverrideSpell(traitDefinition.OverridesSpellID, spellId);
}
@@ -4043,6 +4006,6 @@ namespace Game.Entities
public bool Dependent;
public bool Disabled;
public bool Favorite;
public int? TraitDefinitionId;
public PlayerSpellTrait Trait;
}
}
+18 -5
View File
@@ -1014,9 +1014,8 @@ namespace Game.Entities
List<TraitEntryPacket> costEntries = new();
// apply new traits
for (var i = 0; i < newConfig.Entries.Count; ++i)
foreach (TraitEntryPacket newEntry in newConfig.Entries)
{
TraitEntryPacket newEntry = newConfig.Entries[i];
int oldEntryIndex = editedConfig.Entries.FindIndexIf(ufEntry => ufEntry.TraitNodeID == newEntry.TraitNodeID && ufEntry.TraitNodeEntryID == newEntry.TraitNodeEntryID);
if (oldEntryIndex < 0)
{
@@ -1033,8 +1032,11 @@ namespace Game.Entities
AddDynamicUpdateFieldValue(newTraitConfig.ModifyValue(newTraitConfig.Entries), newUfEntry);
if (applyTraits)
{
ApplyTraitEntry(newEntry.TraitNodeEntryID, 0, 0, false);
ApplyTraitEntry(newUfEntry.TraitNodeEntryID, newUfEntry.Rank, 0, true);
}
}
else if (newEntry.Rank != editedConfig.Entries[oldEntryIndex].Rank || newEntry.GrantedRanks != editedConfig.Entries[oldEntryIndex].GrantedRanks)
{
if (consumeCurrencies && newEntry.Rank > editedConfig.Entries[oldEntryIndex].Rank)
@@ -1080,9 +1082,8 @@ namespace Game.Entities
}
}
for (int i = 0; i < newConfig.SubTrees.Count; ++i)
foreach (TraitSubTreeCachePacket newSubTree in newConfig.SubTrees)
{
var newSubTree = newConfig.SubTrees[i];
int oldSubTreeIndex = editedConfig.SubTrees.FindIndexIf(ufSubTree => ufSubTree.TraitSubTreeID == newSubTree.TraitSubTreeID);
List<TraitEntry> subTreeEntries = new();
@@ -1094,6 +1095,7 @@ namespace Game.Entities
newUfEntry.Rank = newSubTree.Entries[j].Rank;
newUfEntry.GrantedRanks = newSubTree.Entries[j].GrantedRanks;
}
if (oldSubTreeIndex < 0)
{
TraitSubTreeCache newUfSubTree = new();
@@ -1182,13 +1184,24 @@ namespace Game.Entities
if (traitDefinition.SpellID != 0)
{
Cypher.Assert(traitNodeEntry.TraitDefinitionID <= 0xFFFFFF && rank + grantedRanks <= 0xFF);
if (apply)
LearnSpell(traitDefinition.SpellID, true, 0, false, traitNodeEntry.TraitDefinitionID);
LearnSpell(traitDefinition.SpellID, true, 0, false, new PlayerSpellTrait(traitNodeEntry.TraitDefinitionID, rank + grantedRanks));
else
RemoveSpell(traitDefinition.SpellID);
}
}
public PlayerSpellTrait GetTraitInfoForSpell(uint spellId)
{
PlayerSpell spell = m_spells.LookupByKey(spellId);
if (spell != null)
return spell.Trait;
return null;
}
public void SetTraitConfigUseStarterBuild(int traitConfigId, bool useStarterBuild)
{
int configIndex = m_activePlayerData.TraitConfigs.FindIndexIf(traitConfig =>
+24
View File
@@ -8068,4 +8068,28 @@ namespace Game.Entities
public uint? InstanceId;
public uint? LfgDungeonsId;
}
public class PlayerSpellTrait
{
public int DefinitionId;
public int Rank;
public PlayerSpellTrait(int definitionId, int rank)
{
DefinitionId = definitionId;
Rank = rank;
}
public override bool Equals(object obj)
{
return obj is PlayerSpellTrait trait &&
DefinitionId == trait.DefinitionId &&
Rank == trait.Rank;
}
public override int GetHashCode()
{
return HashCode.Combine(DefinitionId, Rank);
}
}
}
+31
View File
@@ -4107,7 +4107,38 @@ namespace Game.Spells
Unit casterUnit = null;
if (caster != null)
{
casterUnit = caster.ToUnit();
Player playerCaster = caster.ToPlayer();
if (playerCaster != null)
{
PlayerSpellTrait trait = playerCaster.GetTraitInfoForSpell(_spellInfo.Id);
if (trait != null)
{
var traitDefinitionEffectPoints = TraitMgr.GetTraitDefinitionEffectPointModifiers(trait.DefinitionId);
if (traitDefinitionEffectPoints != null)
{
var pointsOverride = traitDefinitionEffectPoints.Find(p => p.EffectIndex == EffectIndex);
if (pointsOverride != null)
{
float traitBasePoints = Global.DB2Mgr.GetCurveValueAt((uint)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 != 0)
{