fix(Core/Unit): correct partial school immunity for dual-school spells (#26254)
This commit is contained in:
@@ -939,34 +939,8 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, uint32 effectMask, Unit
|
|||||||
if (hasCheckedEffect && immuneToAllEffects)
|
if (hasCheckedEffect && immuneToAllEffects)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!spellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES))
|
if (!spellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES) && HasSchoolImmunityForMask(spellInfo->GetSchoolMask(), caster, spellInfo))
|
||||||
{
|
|
||||||
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;
|
return true;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -9860,6 +9834,32 @@ bool Unit::IgnoresSchoolImmunityFromFriendlyCaster(Unit const* caster, uint32 im
|
|||||||
return immunityAuraId == std::numeric_limits<uint32>::max();
|
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
|
bool Unit::IsImmunedToDamage(SpellSchoolMask schoolMask) const
|
||||||
{
|
{
|
||||||
if (schoolMask == SPELL_SCHOOL_MASK_NONE)
|
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
|
bool Unit::IsImmunedToDamageOrSchool(SpellSchoolMask schoolMask) const
|
||||||
{
|
{
|
||||||
if (schoolMask == SPELL_SCHOOL_MASK_NONE)
|
if (schoolMask == SPELL_SCHOOL_MASK_NONE)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
return IsImmunedToDamage(schoolMask) || IsImmunedToSchool(schoolMask);
|
return IsImmunedToDamage(schoolMask) || IsImmunedToSchool(schoolMask);
|
||||||
}
|
}
|
||||||
@@ -10102,28 +10044,9 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, Unit const* caster, Spel
|
|||||||
|
|
||||||
if (!spellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES))
|
if (!spellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES))
|
||||||
{
|
{
|
||||||
if (spellSchoolMask != SPELL_SCHOOL_MASK_NONE)
|
if (HasSchoolImmunityForMask(spellSchoolMask, caster, spellInfo))
|
||||||
{
|
|
||||||
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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1645,14 +1645,13 @@ public:
|
|||||||
[[nodiscard]] bool IsImmunedToDamage(SpellSchoolMask schoolMask) const;
|
[[nodiscard]] bool IsImmunedToDamage(SpellSchoolMask schoolMask) const;
|
||||||
[[nodiscard]] bool IsImmunedToDamage(Unit const* caster, SpellInfo const* spellInfo) const;
|
[[nodiscard]] bool IsImmunedToDamage(Unit const* caster, SpellInfo const* spellInfo) const;
|
||||||
[[nodiscard]] bool IsImmunedToSchool(SpellSchoolMask schoolMask) 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; }
|
static bool IsImmuneMaskFully(SpellSchoolMask immuneMask, SpellSchoolMask schoolMask) { return (immuneMask & schoolMask) == schoolMask; }
|
||||||
|
|
||||||
[[nodiscard]] uint32 GetSchoolImmunityMask() const;
|
[[nodiscard]] uint32 GetSchoolImmunityMask() const;
|
||||||
[[nodiscard]] uint32 GetDamageImmunityMask() 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 IsImmunedToDamageOrSchool(SpellSchoolMask schoolMask) const;
|
||||||
[[nodiscard]] bool IsImmunedToAuraPeriodicTick(Unit const* caster, SpellInfo const* spellInfo) const;
|
[[nodiscard]] bool IsImmunedToAuraPeriodicTick(Unit const* caster, SpellInfo const* spellInfo) const;
|
||||||
virtual bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Unit const* caster = nullptr) const;
|
virtual bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Unit const* caster = nullptr) const;
|
||||||
|
|||||||
@@ -2982,7 +2982,7 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit* unit, uint32 effectMask, bool scaleA
|
|||||||
return SPELL_MISS_EVADE;
|
return SPELL_MISS_EVADE;
|
||||||
|
|
||||||
// For delayed spells immunity may be applied between missile launch and hit - check immunity for that case
|
// 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;
|
return SPELL_MISS_IMMUNE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5202,6 +5202,16 @@ void SpellMgr::LoadSpellInfoCorrections()
|
|||||||
spellInfo->Effects[EFFECT_0].BasePoints = 1;
|
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
|
// 51036 Summon Venture Co. Air Patrol
|
||||||
ApplySpellFix({ 51036 }, [](SpellInfo* spellInfo)
|
ApplySpellFix({ 51036 }, [](SpellInfo* spellInfo)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user