Core/Spells: Apply spell modifiers multiple times to each cast, based on number of matched SpellFamilyFlags bits
Port From (https://github.com/TrinityCore/TrinityCore/commit/dfcd41abefec371e6af9db7db92c1dd55aa701ff)
This commit is contained in:
@@ -3041,6 +3041,9 @@ namespace Game.Entities
|
|||||||
flat = 0;
|
flat = 0;
|
||||||
pct = 1.0f;
|
pct = 1.0f;
|
||||||
|
|
||||||
|
if (!spellInfo.IsAffectedBySpellMods())
|
||||||
|
return;
|
||||||
|
|
||||||
// Drop charges for triggering spells instead of triggered ones
|
// Drop charges for triggering spells instead of triggered ones
|
||||||
if (m_spellModTakingSpell != null)
|
if (m_spellModTakingSpell != null)
|
||||||
spell = m_spellModTakingSpell;
|
spell = m_spellModTakingSpell;
|
||||||
@@ -3053,7 +3056,7 @@ namespace Game.Entities
|
|||||||
SpellModifier modInstantSpell = null;
|
SpellModifier modInstantSpell = null;
|
||||||
foreach (SpellModifierByClassMask mod in m_spellMods[(int)op][(int)SpellModType.Pct])
|
foreach (SpellModifierByClassMask mod in m_spellMods[(int)op][(int)SpellModType.Pct])
|
||||||
{
|
{
|
||||||
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
|
if (IsAffectedBySpellmod(spellInfo, mod, spell) == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (baseValue.CompareTo(10000) < 0 && mod.value <= -100)
|
if (baseValue.CompareTo(10000) < 0 && mod.value <= -100)
|
||||||
@@ -3067,7 +3070,7 @@ namespace Game.Entities
|
|||||||
{
|
{
|
||||||
foreach (SpellPctModifierByLabel mod in m_spellMods[(int)op][(int)SpellModType.LabelPct])
|
foreach (SpellPctModifierByLabel mod in m_spellMods[(int)op][(int)SpellModType.LabelPct])
|
||||||
{
|
{
|
||||||
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
|
if (IsAffectedBySpellmod(spellInfo, mod, spell) == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (baseValue.CompareTo(10000) < 0 && mod.value.ModifierValue <= -1.0f)
|
if (baseValue.CompareTo(10000) < 0 && mod.value.ModifierValue <= -1.0f)
|
||||||
@@ -3092,7 +3095,7 @@ namespace Game.Entities
|
|||||||
SpellModifier modCritical = null;
|
SpellModifier modCritical = null;
|
||||||
foreach (SpellModifierByClassMask mod in m_spellMods[(int)op][(int)SpellModType.Flat])
|
foreach (SpellModifierByClassMask mod in m_spellMods[(int)op][(int)SpellModType.Flat])
|
||||||
{
|
{
|
||||||
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
|
if (IsAffectedBySpellmod(spellInfo, mod, spell) == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (mod.value >= 100)
|
if (mod.value >= 100)
|
||||||
@@ -3106,7 +3109,7 @@ namespace Game.Entities
|
|||||||
{
|
{
|
||||||
foreach (SpellFlatModifierByLabel mod in m_spellMods[(int)op][(int)SpellModType.LabelFlat])
|
foreach (SpellFlatModifierByLabel mod in m_spellMods[(int)op][(int)SpellModType.LabelFlat])
|
||||||
{
|
{
|
||||||
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
|
if (IsAffectedBySpellmod(spellInfo, mod, spell) == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (mod.value.ModifierValue >= 100)
|
if (mod.value.ModifierValue >= 100)
|
||||||
@@ -3131,33 +3134,36 @@ namespace Game.Entities
|
|||||||
|
|
||||||
foreach (SpellModifierByClassMask mod in m_spellMods[(int)op][(int)SpellModType.Flat])
|
foreach (SpellModifierByClassMask mod in m_spellMods[(int)op][(int)SpellModType.Flat])
|
||||||
{
|
{
|
||||||
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
|
int applyCount = IsAffectedBySpellmod(spellInfo, mod, spell);
|
||||||
|
if (applyCount == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int value = mod.value;
|
int value = mod.value;
|
||||||
if (value == 0)
|
if (value == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
flat += value;
|
flat += value * applyCount;
|
||||||
ApplyModToSpell(mod, spell);
|
ApplyModToSpell(mod, spell);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (SpellFlatModifierByLabel mod in m_spellMods[(int)op][(int)SpellModType.LabelFlat])
|
foreach (SpellFlatModifierByLabel mod in m_spellMods[(int)op][(int)SpellModType.LabelFlat])
|
||||||
{
|
{
|
||||||
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
|
int applyCount = IsAffectedBySpellmod(spellInfo, mod, spell);
|
||||||
|
if (applyCount == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int value = mod.value.ModifierValue;
|
int value = mod.value.ModifierValue;
|
||||||
if (value == 0)
|
if (value == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
flat += value;
|
flat += value * applyCount;
|
||||||
ApplyModToSpell(mod, spell);
|
ApplyModToSpell(mod, spell);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (SpellModifierByClassMask mod in m_spellMods[(int)op][(int)SpellModType.Pct])
|
foreach (SpellModifierByClassMask mod in m_spellMods[(int)op][(int)SpellModType.Pct])
|
||||||
{
|
{
|
||||||
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
|
int applyCount = IsAffectedBySpellmod(spellInfo, mod, spell);
|
||||||
|
if (applyCount == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// skip percent mods for null basevalue (most important for spell mods with charges)
|
// skip percent mods for null basevalue (most important for spell mods with charges)
|
||||||
@@ -3175,13 +3181,14 @@ namespace Game.Entities
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
pct *= 1.0f + MathFunctions.CalculatePct(1.0f, value);
|
pct *= MathF.Pow(1.0f + MathFunctions.CalculatePct(1.0f, value), applyCount);
|
||||||
ApplyModToSpell(mod, spell);
|
ApplyModToSpell(mod, spell);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (SpellPctModifierByLabel mod in m_spellMods[(int)op][(int)SpellModType.LabelPct])
|
foreach (SpellPctModifierByLabel mod in m_spellMods[(int)op][(int)SpellModType.LabelPct])
|
||||||
{
|
{
|
||||||
if (!IsAffectedBySpellmod(spellInfo, mod, spell))
|
int applyCount = IsAffectedBySpellmod(spellInfo, mod, spell);
|
||||||
|
if (applyCount == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// skip percent mods for null basevalue (most important for spell mods with charges)
|
// skip percent mods for null basevalue (most important for spell mods with charges)
|
||||||
@@ -3199,50 +3206,50 @@ namespace Game.Entities
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
pct *= value;
|
pct *= MathF.Pow(value, applyCount);
|
||||||
ApplyModToSpell(mod, spell);
|
ApplyModToSpell(mod, spell);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsAffectedBySpellmod(SpellInfo spellInfo, SpellModifier mod, Spell spell)
|
int IsAffectedBySpellmod(SpellInfo spellInfo, SpellModifier mod, Spell spell)
|
||||||
{
|
{
|
||||||
if (mod == null || spellInfo == null)
|
if (mod == null || spellInfo == null)
|
||||||
return false;
|
return 0;
|
||||||
|
|
||||||
// First time this aura applies a mod to us and is out of charges
|
// First time this aura applies a mod to us and is out of charges
|
||||||
if (spell != null && mod.ownerAura.IsUsingCharges() && mod.ownerAura.GetCharges() == 0 && !spell.m_appliedMods.Contains(mod.ownerAura))
|
if (spell != null && mod.ownerAura.IsUsingCharges() && mod.ownerAura.GetCharges() == 0 && !spell.m_appliedMods.Contains(mod.ownerAura))
|
||||||
return false;
|
return 0;
|
||||||
|
|
||||||
switch (mod.op)
|
switch (mod.op)
|
||||||
{
|
{
|
||||||
case SpellModOp.Duration: // +duration to infinite duration spells making them limited
|
case SpellModOp.Duration: // +duration to infinite duration spells making them limited
|
||||||
if (spellInfo.GetDuration() == -1)
|
if (spellInfo.GetDuration() == -1)
|
||||||
return false;
|
return 0;
|
||||||
break;
|
break;
|
||||||
case SpellModOp.CritChance: // mod crit to spells that can't crit
|
case SpellModOp.CritChance: // mod crit to spells that can't crit
|
||||||
if (!spellInfo.HasAttribute(SpellCustomAttributes.CanCrit))
|
if (!spellInfo.HasAttribute(SpellCustomAttributes.CanCrit))
|
||||||
return false;
|
return 0;
|
||||||
break;
|
break;
|
||||||
case SpellModOp.PointsIndex0: // check if spell has any effect at that index
|
case SpellModOp.PointsIndex0: // check if spell has any effect at that index
|
||||||
case SpellModOp.Points:
|
case SpellModOp.Points:
|
||||||
if (spellInfo.GetEffects().Count <= 0)
|
if (spellInfo.GetEffects().Count <= 0)
|
||||||
return false;
|
return 0;
|
||||||
break;
|
break;
|
||||||
case SpellModOp.PointsIndex1: // check if spell has any effect at that index
|
case SpellModOp.PointsIndex1: // check if spell has any effect at that index
|
||||||
if (spellInfo.GetEffects().Count <= 1)
|
if (spellInfo.GetEffects().Count <= 1)
|
||||||
return false;
|
return 0;
|
||||||
break;
|
break;
|
||||||
case SpellModOp.PointsIndex2: // check if spell has any effect at that index
|
case SpellModOp.PointsIndex2: // check if spell has any effect at that index
|
||||||
if (spellInfo.GetEffects().Count <= 2)
|
if (spellInfo.GetEffects().Count <= 2)
|
||||||
return false;
|
return 0;
|
||||||
break;
|
break;
|
||||||
case SpellModOp.PointsIndex3: // check if spell has any effect at that index
|
case SpellModOp.PointsIndex3: // check if spell has any effect at that index
|
||||||
if (spellInfo.GetEffects().Count <= 3)
|
if (spellInfo.GetEffects().Count <= 3)
|
||||||
return false;
|
return 0;
|
||||||
break;
|
break;
|
||||||
case SpellModOp.PointsIndex4: // check if spell has any effect at that index
|
case SpellModOp.PointsIndex4: // check if spell has any effect at that index
|
||||||
if (spellInfo.GetEffects().Count <= 4)
|
if (spellInfo.GetEffects().Count <= 4)
|
||||||
return false;
|
return 0;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -493,7 +493,7 @@ namespace Game.Spells
|
|||||||
// only passive and permament auras-active auras should have amount set on spellcast and not be affected
|
// only passive and permament auras-active auras should have amount set on spellcast and not be affected
|
||||||
// if aura is cast by others, it will not be affected
|
// if aura is cast by others, it will not be affected
|
||||||
if ((!aura.IsPassive() && !aura.IsPermanent() && !GetSpellInfo().IsUpdatingTemporaryAuraValuesBySpellMod())
|
if ((!aura.IsPassive() && !aura.IsPermanent() && !GetSpellInfo().IsUpdatingTemporaryAuraValuesBySpellMod())
|
||||||
|| aura.GetCasterGUID() != guid || !aura.GetSpellInfo().IsAffectedBySpellMod(m_spellmod))
|
|| aura.GetCasterGUID() != guid || !aura.GetSpellInfo().IsAffectedBySpellMods() || aura.GetSpellInfo().IsAffectedBySpellMod(m_spellmod) == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (recalculateEffectIndex.HasValue)
|
if (recalculateEffectIndex.HasValue)
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ using System.Collections;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Framework.Collections;
|
using Framework.Collections;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace Game.Spells
|
namespace Game.Spells
|
||||||
{
|
{
|
||||||
@@ -645,36 +646,41 @@ namespace Game.Spells
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsAffectedBySpellMods()
|
public bool IsAffectedBySpellMods()
|
||||||
{
|
{
|
||||||
return !HasAttribute(SpellAttr3.IgnoreCasterModifiers);
|
return !HasAttribute(SpellAttr3.IgnoreCasterModifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsAffectedBySpellMod(SpellModifier mod)
|
public int IsAffectedBySpellMod(SpellModifier mod)
|
||||||
{
|
{
|
||||||
if (!IsAffectedBySpellMods())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
SpellInfo affectSpell = Global.SpellMgr.GetSpellInfo(mod.spellId, Difficulty);
|
SpellInfo affectSpell = Global.SpellMgr.GetSpellInfo(mod.spellId, Difficulty);
|
||||||
if (affectSpell == null)
|
if (affectSpell == null)
|
||||||
return false;
|
return 0;
|
||||||
|
|
||||||
switch (mod.type)
|
switch (mod.type)
|
||||||
{
|
{
|
||||||
case SpellModType.Flat:
|
case SpellModType.Flat:
|
||||||
case SpellModType.Pct:
|
case SpellModType.Pct:
|
||||||
|
{
|
||||||
// TEMP: dont use IsAffected - !familyName and !familyFlags are not valid options for spell mods
|
// TEMP: dont use IsAffected - !familyName and !familyFlags are not valid options for spell mods
|
||||||
// TODO: investigate if the !familyName and !familyFlags conditions are even valid for all other (nonmod) uses of SpellInfo::IsAffected
|
// TODO: investigate if the !familyName and !familyFlags conditions are even valid for all other (nonmod) uses of SpellInfo::IsAffected
|
||||||
return affectSpell.SpellFamilyName == SpellFamilyName && (mod as SpellModifierByClassMask).mask & SpellFamilyFlags;
|
if (affectSpell.SpellFamilyName != SpellFamilyName)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// spell modifiers should apply as many times as number of matched SpellFamilyFlags bits (verified with spell 1218116 with modifier 384451 in patch 11.1.0 and client tooltip code since at least 3.3.5)
|
||||||
|
// unknown if this is a bug or strange design choice...
|
||||||
|
var matched = (mod as SpellModifierByClassMask).mask & SpellFamilyFlags;
|
||||||
|
return BitOperations.PopCount(matched[0]) + BitOperations.PopCount(matched[1]) + BitOperations.PopCount(matched[2]) + BitOperations.PopCount(matched[3]);
|
||||||
|
}
|
||||||
case SpellModType.LabelFlat:
|
case SpellModType.LabelFlat:
|
||||||
return HasLabel((uint)(mod as SpellFlatModifierByLabel).value.LabelID);
|
return HasLabel((uint)(mod as SpellFlatModifierByLabel).value.LabelID) ? 1 : 0;
|
||||||
case SpellModType.LabelPct:
|
case SpellModType.LabelPct:
|
||||||
return HasLabel((uint)(mod as SpellPctModifierByLabel).value.LabelID);
|
return HasLabel((uint)(mod as SpellPctModifierByLabel).value.LabelID) ? 1 : 0;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsUpdatingTemporaryAuraValuesBySpellMod()
|
public bool IsUpdatingTemporaryAuraValuesBySpellMod()
|
||||||
|
|||||||
Reference in New Issue
Block a user