fix(Core/Unit): partial immunity for mixed spells (#25219)
Co-authored-by: Shauren <shauren.trinity@gmail.com>
This commit is contained in:
@@ -910,15 +910,34 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, uint32 effectMask, Unit
|
|||||||
if (!spellInfo)
|
if (!spellInfo)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
bool immuneToAllEffects = true;
|
||||||
|
bool hasCheckedEffect = false;
|
||||||
|
|
||||||
for (uint8 i = EFFECT_0; i < MAX_SPELL_EFFECTS; ++i)
|
for (uint8 i = EFFECT_0; i < MAX_SPELL_EFFECTS; ++i)
|
||||||
{
|
{
|
||||||
if (!(effectMask & (1u << i)))
|
if (!(effectMask & (1u << i)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (!spellInfo->Effects[i].IsEffect())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
hasCheckedEffect = true;
|
||||||
|
|
||||||
if (IsImmunedToSpellEffect(spellInfo, i, caster))
|
if (IsImmunedToSpellEffect(spellInfo, i, caster))
|
||||||
|
{
|
||||||
|
if (spellInfo->HasAttribute(SPELL_ATTR4_NO_PARTIAL_IMMUNITY))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
immuneToAllEffects = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasCheckedEffect && immuneToAllEffects)
|
||||||
|
return true;
|
||||||
|
|
||||||
if (!spellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES))
|
if (!spellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES))
|
||||||
{
|
{
|
||||||
if (IsImmunedToSchool(spellInfo))
|
if (IsImmunedToSchool(spellInfo))
|
||||||
|
|||||||
@@ -105,6 +105,31 @@ namespace
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsEffectBlockedByStunImmunity(EffectDesc const& effect, bool immuneToStun)
|
||||||
|
{
|
||||||
|
if (!immuneToStun)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return effect.effect == EFFECT_APPLY_AURA && effect.aura == AURA_MOD_STUN;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsFullyImmunedByStunImmunity(SpellDesc const& spell, bool immuneToStun)
|
||||||
|
{
|
||||||
|
bool hasAnyEffect = false;
|
||||||
|
|
||||||
|
for (EffectDesc const& effect : spell.effects)
|
||||||
|
{
|
||||||
|
if (effect.effect == EFFECT_NONE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
hasAnyEffect = true;
|
||||||
|
if (!IsEffectBlockedByStunImmunity(effect, immuneToStun))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hasAnyEffect;
|
||||||
|
}
|
||||||
|
|
||||||
// The last parameter defaults to false to avoid updating existing tests
|
// The last parameter defaults to false to avoid updating existing tests
|
||||||
// that don't care about mechanic immunities. Bladestorm grants a
|
// that don't care about mechanic immunities. Bladestorm grants a
|
||||||
// specific mechanic immunity (including stun) that should block
|
// specific mechanic immunity (including stun) that should block
|
||||||
@@ -114,12 +139,12 @@ namespace
|
|||||||
{
|
{
|
||||||
// Mirrors current core ordering:
|
// Mirrors current core ordering:
|
||||||
// 1) full spell immunity check
|
// 1) full spell immunity check
|
||||||
// 2) mechanic immunity check (e.g. bladestorm vs stun)
|
// 2) full immunity from mechanic immunity (all effects blocked)
|
||||||
// 3) damage immunity only for damage-only spells
|
// 3) damage immunity only for damage-only spells
|
||||||
if (isImmunedToSpell)
|
if (isImmunedToSpell)
|
||||||
return SPELL_MISS_IMMUNE;
|
return SPELL_MISS_IMMUNE;
|
||||||
|
|
||||||
if (immuneToStun && IsStunSpell(spell))
|
if (IsFullyImmunedByStunImmunity(spell, immuneToStun))
|
||||||
return SPELL_MISS_IMMUNE;
|
return SPELL_MISS_IMMUNE;
|
||||||
|
|
||||||
if (HasOnlyDamageEffects(spell) && isImmunedToDamage)
|
if (HasOnlyDamageEffects(spell) && isImmunedToDamage)
|
||||||
@@ -328,3 +353,14 @@ TEST(SpellImmunityTest, Bladestorm_ImmuneToStun)
|
|||||||
// with a bladestorm‑style stun immunity it is blocked
|
// with a bladestorm‑style stun immunity it is blocked
|
||||||
EXPECT_EQ(ComputeSpellHitResult(false, false, stunSpell, true), SPELL_MISS_IMMUNE);
|
EXPECT_EQ(ComputeSpellHitResult(false, false, stunSpell, true), SPELL_MISS_IMMUNE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(SpellImmunityTest, StunImmunity_DoesNotFullyBlockMixedSpell)
|
||||||
|
{
|
||||||
|
SpellDesc mixedSpell;
|
||||||
|
mixedSpell.effects[0] = { EFFECT_SCHOOL_DAMAGE, AURA_NONE };
|
||||||
|
mixedSpell.effects[1] = { EFFECT_APPLY_AURA, AURA_MOD_STUN };
|
||||||
|
|
||||||
|
// This models partial immunity: stun effect is blocked, damage still hits.
|
||||||
|
EXPECT_TRUE(IsStunSpell(mixedSpell));
|
||||||
|
EXPECT_EQ(ComputeSpellHitResult(false, false, mixedSpell, true), SPELL_MISS_NONE);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user