fix(Core/Unit): correct partial school immunity for dual-school spells (#26254)

This commit is contained in:
sogladev
2026-07-20 01:53:19 +02:00
committed by GitHub
parent 3b1df8136d
commit 4a44d6a190
4 changed files with 42 additions and 110 deletions

View File

@@ -939,34 +939,8 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, uint32 effectMask, Unit
if (hasCheckedEffect && immuneToAllEffects)
return true;
if (!spellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES))
{
if (spellInfo->Id == 42292 || spellInfo->Id == 59752 || spellInfo->Id == 19574 || spellInfo->Id == 34471)
return false;
SpellSchoolMask schoolMask = spellInfo->GetSchoolMask();
if (schoolMask != SPELL_SCHOOL_MASK_NONE)
{
SpellImmuneContainer const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
for (auto const& [immunitySchoolMask, immunityAuraId] : schoolList)
{
SpellInfo const* immuneSpellInfo = sSpellMgr->GetSpellInfo(immunityAuraId);
if (immunityAuraId == spellInfo->Id)
continue;
if ((immunitySchoolMask & schoolMask) != schoolMask)
continue;
if (IgnoresSchoolImmunityFromFriendlyCaster(caster, immunityAuraId, immuneSpellInfo))
continue;
if (spellInfo->CanPierceImmuneAura(immuneSpellInfo))
continue;
return true;
}
}
}
if (!spellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES) && HasSchoolImmunityForMask(spellInfo->GetSchoolMask(), caster, spellInfo))
return true;
return false;
}
@@ -9860,6 +9834,32 @@ bool Unit::IgnoresSchoolImmunityFromFriendlyCaster(Unit const* caster, uint32 im
return immunityAuraId == std::numeric_limits<uint32>::max();
}
bool Unit::HasSchoolImmunityForMask(SpellSchoolMask schoolMask, Unit const* caster, SpellInfo const* spellInfo) const
{
if (schoolMask == SPELL_SCHOOL_MASK_NONE)
return false;
uint32 accumulatedMask = 0;
for (auto const& [immunitySchoolMask, immunityAuraId] : m_spellImmune[IMMUNITY_SCHOOL])
{
// Skip the spell's own immunity entry
if (spellInfo && immunityAuraId == spellInfo->Id)
continue;
SpellInfo const* immuneSpellInfo = sSpellMgr->GetSpellInfo(immunityAuraId);
if (IgnoresSchoolImmunityFromFriendlyCaster(caster, immunityAuraId, immuneSpellInfo))
continue;
if (spellInfo && immuneSpellInfo && spellInfo->CanPierceImmuneAura(immuneSpellInfo))
continue;
accumulatedMask |= immunitySchoolMask;
}
return (SpellSchoolMask(accumulatedMask) & schoolMask) == schoolMask;
}
bool Unit::IsImmunedToDamage(SpellSchoolMask schoolMask) const
{
if (schoolMask == SPELL_SCHOOL_MASK_NONE)
@@ -9935,68 +9935,10 @@ bool Unit::IsImmunedToSchool(SpellSchoolMask schoolMask) const
});
}
bool Unit::IsImmunedToSchool(SpellInfo const* spellInfo) const
{
if (spellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES) && !HasSpiritOfRedemptionAura())
return false;
uint32 schoolMask = spellInfo->GetSchoolMask();
if (schoolMask == SPELL_SCHOOL_MASK_NONE)
{
return false;
}
if (spellInfo->Id != 42292 && spellInfo->Id != 59752 && spellInfo->Id != 19574 && spellInfo->Id != 34471)
{
// Check IMMUNITY_SCHOOL: returns true if ALL schools in the mask are covered and spell can't pierce
SpellImmuneContainer const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr)
if ((itr->first & schoolMask) == schoolMask && !spellInfo->CanPierceImmuneAura(sSpellMgr->GetSpellInfo(itr->second)))
return true;
}
return false;
}
bool Unit::IsImmunedToSchool(Spell const* spell) const
{
SpellInfo const* spellInfo = spell->GetSpellInfo();
if (spellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES) && !HasSpiritOfRedemptionAura())
{
return false;
}
uint32 schoolMask = spell->GetSpellSchoolMask();
if (schoolMask == SPELL_SCHOOL_MASK_NONE)
{
return false;
}
if (spellInfo->Id != 42292 && spellInfo->Id != 59752 && spellInfo->Id != 19574 && spellInfo->Id != 34471)
{
// Check IMMUNITY_SCHOOL: returns true if ALL schools in the mask are covered and spell can't pierce
SpellImmuneContainer const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr)
{
SpellInfo const* immuneSpellInfo = sSpellMgr->GetSpellInfo(itr->second);
if ((itr->first & schoolMask) == schoolMask
&& !IgnoresSchoolImmunityFromFriendlyCaster(spell->GetCaster(), itr->second, immuneSpellInfo)
&& !spellInfo->CanPierceImmuneAura(immuneSpellInfo))
{
return true;
}
}
}
return false;
}
bool Unit::IsImmunedToDamageOrSchool(SpellSchoolMask schoolMask) const
{
if (schoolMask == SPELL_SCHOOL_MASK_NONE)
{
return false;
}
return IsImmunedToDamage(schoolMask) || IsImmunedToSchool(schoolMask);
}
@@ -10102,27 +10044,8 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, Unit const* caster, Spel
if (!spellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES))
{
if (spellSchoolMask != SPELL_SCHOOL_MASK_NONE)
{
SpellImmuneContainer const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr)
{
if (itr->second == spellInfo->Id)
continue;
SpellInfo const* immuneSpellInfo = sSpellMgr->GetSpellInfo(itr->second);
if (!(itr->first & spellSchoolMask))
continue;
if (IgnoresSchoolImmunityFromFriendlyCaster(caster, itr->second, immuneSpellInfo))
continue;
if (spellInfo->CanPierceImmuneAura(immuneSpellInfo))
continue;
return true;
}
}
if (HasSchoolImmunityForMask(spellSchoolMask, caster, spellInfo))
return true;
}
return false;

View File

@@ -1645,14 +1645,13 @@ public:
[[nodiscard]] bool IsImmunedToDamage(SpellSchoolMask schoolMask) const;
[[nodiscard]] bool IsImmunedToDamage(Unit const* caster, SpellInfo const* spellInfo) const;
[[nodiscard]] bool IsImmunedToSchool(SpellSchoolMask schoolMask) const;
[[nodiscard]] bool HasSchoolImmunityForMask(SpellSchoolMask schoolMask, Unit const* caster, SpellInfo const* spellInfo) const;
static bool IsImmuneMaskFully(SpellSchoolMask immuneMask, SpellSchoolMask schoolMask) { return (immuneMask & schoolMask) == schoolMask; }
[[nodiscard]] uint32 GetSchoolImmunityMask() const;
[[nodiscard]] uint32 GetDamageImmunityMask() const;
[[nodiscard]] bool IsImmunedToSchool(SpellInfo const* spellInfo) const;
[[nodiscard]] bool IsImmunedToSchool(Spell const* spell) const;
[[nodiscard]] bool IsImmunedToDamageOrSchool(SpellSchoolMask schoolMask) const;
[[nodiscard]] bool IsImmunedToAuraPeriodicTick(Unit const* caster, SpellInfo const* spellInfo) const;
virtual bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Unit const* caster = nullptr) const;

View File

@@ -2982,7 +2982,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA
return SPELL_MISS_EVADE;
// For delayed spells immunity may be applied between missile launch and hit - check immunity for that case
if (m_spellInfo->Speed && ((m_damage > 0 && unit->IsImmunedToDamage(m_caster, m_spellInfo)) || unit->IsImmunedToSchool(this) || unit->IsImmunedToSpell(m_spellInfo, this)))
if (m_spellInfo->Speed && ((m_damage > 0 && unit->IsImmunedToDamage(m_caster, m_spellInfo)) || unit->IsImmunedToSpell(m_spellInfo, this)))
{
return SPELL_MISS_IMMUNE;
}

View File

@@ -5202,6 +5202,16 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->Effects[EFFECT_0].BasePoints = 1;
});
ApplySpellFix({
42292, // PvP Trinket
59752, // Every Man for Himself
19574, // Bestial Wrath
34471 // The Beast Within
}, [](SpellInfo* spellInfo)
{
spellInfo->AttributesEx2 |= SPELL_ATTR2_NO_SCHOOL_IMMUNITIES;
});
// 51036 Summon Venture Co. Air Patrol
ApplySpellFix({ 51036 }, [](SpellInfo* spellInfo)
{