fix(Core/Spells): apply SPELLFAMILY_GENERIC mods to spells by default (#24996)

Co-authored-by: ariel- <ariel-@users.noreply.github.com>
This commit is contained in:
sogladev
2026-03-08 18:44:29 +01:00
committed by GitHub
parent 6d9b89c976
commit 06c0c6b655
5 changed files with 68 additions and 26 deletions

View File

@@ -1105,14 +1105,12 @@ bool AuraEffect::IsAffectedOnSpell(SpellInfo const* spell) const
{
if (!spell)
return false;
// Check family name
if (spell->SpellFamilyName != m_spellInfo->SpellFamilyName)
// Check family name and EffectClassMask
if (!spell->IsAffected(m_spellInfo->SpellFamilyName, m_spellInfo->Effects[m_effIndex].SpellClassMask))
return false;
// Check EffectClassMask
if (m_spellInfo->Effects[m_effIndex].SpellClassMask & spell->SpellFamilyFlags)
return true;
return false;
return true;
}
bool AuraEffect::HasSpellClassMask() const

View File

@@ -1285,6 +1285,20 @@ bool SpellInfo::IsAutoRepeatRangedSpell() const
return AttributesEx2 & SPELL_ATTR2_AUTO_REPEAT;
}
bool SpellInfo::IsAffected(uint32 familyName, flag96 const& familyFlags) const
{
if (!familyName)
return true;
if (familyName != SpellFamilyName)
return false;
if (familyFlags && !(familyFlags & SpellFamilyFlags))
return false;
return true;
}
bool SpellInfo::IsAffectedBySpellMods() const
{
return !(AttributesEx3 & SPELL_ATTR3_IGNORE_CASTER_MODIFIERS);
@@ -1300,23 +1314,12 @@ bool SpellInfo::IsAffectedBySpellMod(SpellModifier const* mod) const
SpellInfo const* affectSpell = sSpellMgr->GetSpellInfo(mod->spellId);
if (!affectSpell)
{
return false;
}
if (!sScriptMgr->OnIsAffectedBySpellModCheck(affectSpell, this, mod))
{
return true;
}
// False if affect_spell == nullptr or spellFamily not equal
if (affectSpell->SpellFamilyName != SpellFamilyName)
return false;
if (mod->mask && !(mod->mask & SpellFamilyFlags))
return false;
return true;
return IsAffected(affectSpell->SpellFamilyName, mod->mask);
}
bool SpellInfo::CanPierceImmuneAura(SpellInfo const* aura) const

View File

@@ -466,6 +466,8 @@ public:
bool IsRangedWeaponSpell() const;
bool IsAutoRepeatRangedSpell() const;
[[nodiscard]] bool IsAffected(uint32 familyName, flag96 const& familyFlags) const;
bool IsAffectedBySpellMods() const;
bool IsAffectedBySpellMod(SpellModifier const* mod) const;

View File

@@ -823,17 +823,10 @@ bool SpellMgr::CanSpellTriggerProcOnEvent(SpellProcEntry const& procEntry, ProcE
// check spell family name/flags (if set) for spells
if (eventInfo.GetTypeMask() & SPELL_PROC_FLAG_MASK)
{
if (SpellInfo const* eventSpellInfo = eventInfo.GetSpellInfo())
{
if (procEntry.SpellFamilyName && procEntry.SpellFamilyName != eventSpellInfo->SpellFamilyName)
if (!eventSpellInfo->IsAffected(procEntry.SpellFamilyName, procEntry.SpellFamilyMask))
return false;
if (procEntry.SpellFamilyMask && !(procEntry.SpellFamilyMask & eventSpellInfo->SpellFamilyFlags))
return false;
}
}
// check spell type mask (if set)
if (eventInfo.GetTypeMask() & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK))
{

View File

@@ -790,6 +790,52 @@ TEST_F(SpellProcTest, CanSpellTriggerProcOnEvent_SpellFamilyFlagsZeroAcceptsAll)
EXPECT_TRUE(sSpellMgr->CanSpellTriggerProcOnEvent(procEntry, eventInfo));
}
TEST_F(SpellProcTest, CanSpellTriggerProcOnEvent_GenericFamilyIgnoresMask)
{
// Generic family (0) should bypass family mask checks entirely
auto* spellInfo = SpellInfoBuilder()
.WithId(101)
.WithSpellFamilyName(SPELLFAMILY_MAGE)
.WithSpellFamilyFlags(0x1, 0, 0) // some mage flag
.Build();
_spellInfos.push_back(spellInfo);
DamageInfo damageInfo(nullptr, nullptr, 100, spellInfo, SPELL_SCHOOL_MASK_FIRE, SPELL_DIRECT_DAMAGE);
auto procEntry = SpellProcEntryBuilder()
.WithProcFlags(PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG)
.WithSpellFamilyName(0) // generic family
.WithSpellFamilyMask(flag96(0x2, 0, 0)) // does NOT match the spell's flags
.WithSpellPhaseMask(PROC_SPELL_PHASE_HIT)
.Build();
auto eventInfo = ProcEventInfoBuilder()
.WithTypeMask(PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG)
.WithSpellPhaseMask(PROC_SPELL_PHASE_HIT)
.WithHitMask(PROC_HIT_NORMAL)
.WithDamageInfo(&damageInfo)
.Build();
EXPECT_TRUE(sSpellMgr->CanSpellTriggerProcOnEvent(procEntry, eventInfo))
<< "Generic family entries should ignore mask restrictions";
}
TEST_F(SpellProcTest, SpellInfo_IsAffected_GenericBehavior)
{
auto* spellInfo = SpellInfoBuilder()
.WithId(102)
.WithSpellFamilyName(SPELLFAMILY_WARLOCK)
.WithSpellFamilyFlags(0x4, 0, 0)
.Build();
_spellInfos.push_back(spellInfo);
// generic family should return true regardless of mask
EXPECT_TRUE(spellInfo->IsAffected(0, flag96(0x4, 0, 0)));
EXPECT_TRUE(spellInfo->IsAffected(0, flag96(0x8, 0, 0)));
// a non-generic family still respects mask
EXPECT_FALSE(spellInfo->IsAffected(SPELLFAMILY_PALADIN, flag96(0x4, 0, 0)));
}
// =============================================================================
// Real-world Spell Proc Examples
// =============================================================================