fix(Core/Spell): spell immunity system and new separate immunities table (#24956)

Co-authored-by: ariel- <ariel-@users.noreply.github.com>
Co-authored-by: Keader <keader.android@gmail.com>
Co-authored-by: Shauren <shauren.trinity@gmail.com>
This commit is contained in:
sogladev
2026-03-22 23:36:35 +01:00
committed by GitHub
parent 0e0ff86e3e
commit a90570a2de
26 changed files with 1655 additions and 914 deletions

View File

@@ -72,6 +72,7 @@
#include "Vehicle.h"
#include "World.h"
#include "WorldPacket.h"
#include <algorithm>
#include <cmath>
float baseMoveSpeed[MAX_MOVE_TYPE] =
@@ -372,9 +373,6 @@ Unit::Unit() : WorldObject(),
m_transform = 0;
m_canModifyStats = false;
for (uint8 i = 0; i < MAX_SPELL_IMMUNITY; ++i)
m_spellImmune[i].clear();
for (uint8 i = 0; i < UNIT_MOD_END; ++i)
{
m_auraFlatModifiersGroup[i][BASE_VALUE] = 0.0f;
@@ -891,6 +889,29 @@ bool Unit::HasAuraTypeWithFamilyFlags(AuraType auraType, uint32 familyName, uint
return false;
}
bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, uint32 effectMask, Unit const* caster /*= nullptr*/)
{
if (!spellInfo)
return false;
for (uint8 i = EFFECT_0; i < MAX_SPELL_EFFECTS; ++i)
{
if (!(effectMask & (1u << i)))
continue;
if (IsImmunedToSpellEffect(spellInfo, i, caster))
return true;
}
if (!spellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES))
{
if (IsImmunedToSchool(spellInfo))
return true;
}
return false;
}
bool Unit::HasBreakableByDamageAuraType(AuraType type, uint32 excludeAura) const
{
AuraEffectList const& auras = GetAuraEffectsByType(type);
@@ -2075,7 +2096,7 @@ void Unit::DealDamageShieldDamage(Unit* victim)
}
// ...or immuned
if (IsImmunedToDamageOrSchool(i_spellProto))
if (IsImmunedToDamage(victim, i_spellProto))
{
victim->SendSpellDamageImmune(this, i_spellProto->Id);
continue;
@@ -3203,7 +3224,7 @@ void Unit::SendMeleeAttackStop(Unit* victim)
bool Unit::isSpellBlocked(Unit* victim, SpellInfo const* spellProto, WeaponAttackType attackType)
{
// These spells can't be blocked
if (spellProto && spellProto->HasAttribute(SPELL_ATTR0_NO_ACTIVE_DEFENSE))
if (spellProto && (spellProto->HasAttribute(SPELL_ATTR0_NO_ACTIVE_DEFENSE) || spellProto->HasAttribute(SPELL_ATTR3_ALWAYS_HIT)))
return false;
if (victim->HasIgnoreHitDirectionAura() || victim->HasInArc(M_PI, this))
@@ -3571,6 +3592,9 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit* victim, SpellInfo const* spellInfo
// Resist
SpellMissInfo Unit::SpellHitResult(Unit* victim, SpellInfo const* spell, bool CanReflect)
{
if (spell->HasAttribute(SPELL_ATTR3_ALWAYS_HIT))
return SPELL_MISS_NONE;
// Check for immune
if (victim->IsImmunedToSpell(spell))
return SPELL_MISS_IMMUNE;
@@ -3581,11 +3605,6 @@ SpellMissInfo Unit::SpellHitResult(Unit* victim, SpellInfo const* spell, bool Ca
&& (!IsHostileTo(victim))) // prevent from affecting enemy by "positive" spell
return SPELL_MISS_NONE;
// Check for immune
// xinef: check for school immunity only
if (victim->IsImmunedToSchool(spell))
return SPELL_MISS_IMMUNE;
if (this == victim)
return SPELL_MISS_NONE;
@@ -3650,13 +3669,17 @@ SpellMissInfo Unit::SpellHitResult(Unit* victim, Spell const* spell, bool CanRef
return SPELL_MISS_NONE;
}
// Check for immune
// xinef: check for school immunity only
if (victim->IsImmunedToSchool(spell))
// Check for immune to spell effects (includes school, mechanics, state, dispel immunities)
if (victim->IsImmunedToSpell(spellInfo, MAX_EFFECT_MASK, this))
{
return SPELL_MISS_IMMUNE;
}
// Damage immunity is only checked if the spell has damage effects, this immunity must not prevent aura apply
// returns SPELL_MISS_IMMUNE in that case, for other spells, the SMSG_SPELL_GO must show hit
if (spellInfo->HasOnlyDamageEffects() && victim->IsImmunedToDamage(this, spellInfo))
return SPELL_MISS_IMMUNE;
if (this == victim)
{
return SPELL_MISS_NONE;
@@ -5447,7 +5470,7 @@ void Unit::RemoveMovementImpairingAuras(bool withRoot)
}
}
void Unit::RemoveAurasWithMechanic(uint32 mechanic_mask, AuraRemoveMode removemode, uint32 except)
void Unit::RemoveAurasWithMechanic(uint64 mechanic_mask, AuraRemoveMode removemode, uint32 except)
{
for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
{
@@ -5466,7 +5489,7 @@ void Unit::RemoveAurasWithMechanic(uint32 mechanic_mask, AuraRemoveMode removemo
void Unit::RemoveAurasByShapeShift()
{
uint32 mechanic_mask = (1 << MECHANIC_SNARE) | (1 << MECHANIC_ROOT);
uint64 mechanic_mask = (UI64LIT(1) << MECHANIC_SNARE) | (UI64LIT(1) << MECHANIC_ROOT);
for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
{
Aura const* aura = iter->second->GetBase();
@@ -6015,17 +6038,17 @@ bool Unit::HasNegativeAuraWithAttribute(uint32 flag, ObjectGuid guid)
return false;
}
bool Unit::HasAuraWithMechanic(uint32 mechanicMask) const
bool Unit::HasAuraWithMechanic(uint64 mechanicMask) const
{
for (AuraApplicationMap::const_iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end(); ++iter)
{
SpellInfo const* spellInfo = iter->second->GetBase()->GetSpellInfo();
if (spellInfo->Mechanic && (mechanicMask & (1 << spellInfo->Mechanic)))
if (spellInfo->Mechanic && (mechanicMask & (UI64LIT(1) << spellInfo->Mechanic)))
return true;
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
if (iter->second->HasEffect(i) && spellInfo->Effects[i].Effect && spellInfo->Effects[i].Mechanic)
if (mechanicMask & (1 << spellInfo->Effects[i].Mechanic))
if (mechanicMask & (UI64LIT(1) << spellInfo->Effects[i].Mechanic))
return true;
}
@@ -8833,7 +8856,7 @@ uint32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, ui
});
}
if (uint32 mechanicMask = spellProto->GetAllEffectsMechanicMask())
if (uint64 mechanicMask = spellProto->GetAllEffectsMechanicMask())
{
int32 modifierMax = 0;
int32 modifierMin = 0;
@@ -8848,7 +8871,7 @@ uint32 Unit::SpellDamageBonusTaken(Unit* caster, SpellInfo const* spellProto, ui
if (!caster || caster->GetGUID() != (*i)->GetCasterGUID())
continue;
if (mechanicMask & uint32(1 << (*i)->GetMiscValue()))
if (mechanicMask & uint64(UI64LIT(1) << (*i)->GetMiscValue()))
{
if ((*i)->GetAmount() > 0)
{
@@ -9739,107 +9762,90 @@ int32 Unit::SpellBaseHealingBonusDone(SpellSchoolMask schoolMask)
return AdvertisedBenefit;
}
bool Unit::IsImmunedToDamage(SpellSchoolMask meleeSchoolMask) const
uint32 Unit::GetDamageImmunityMask() const
{
if (meleeSchoolMask == SPELL_SCHOOL_MASK_NONE)
{
return false;
}
// If m_immuneToDamage type contain magic, IMMUNE damage.
SpellImmuneList const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
for (SpellImmuneList::const_iterator itr = damageList.begin(); itr != damageList.end(); ++itr)
if ((itr->type & meleeSchoolMask) == meleeSchoolMask)
return true;
return false;
uint32 mask = 0;
SpellImmuneContainer const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
for (auto const& [immunitySchoolMask, _] : damageList)
mask |= immunitySchoolMask;
return mask;
}
bool Unit::IsImmunedToDamage(SpellInfo const* spellInfo) const
bool Unit::IsImmunedToDamage(SpellSchoolMask schoolMask) const
{
if (!spellInfo)
{
return false;
}
if (spellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES) && !HasSpiritOfRedemptionAura())
{
return false;
}
if (spellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS) || spellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES))
{
return false;
}
uint32 schoolMask = spellInfo->GetSchoolMask();
if (schoolMask == SPELL_SCHOOL_MASK_NONE)
{
return false;
}
// If m_immuneToDamage type contain magic, IMMUNE damage.
SpellImmuneList const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
for (SpellImmuneList::const_iterator itr = damageList.begin(); itr != damageList.end(); ++itr)
if ((itr->type & schoolMask) == schoolMask)
// If m_immuneToSchool type contains all requested schools, IMMUNE damage.
SpellImmuneContainer const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
for (auto const& itr : schoolList)
if (IsImmuneMaskFully(SpellSchoolMask(itr.first), schoolMask))
return true;
return false;
// If m_immuneToDamage type contains all requested schools, IMMUNE damage.
SpellImmuneContainer const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
return std::ranges::any_of(damageList, [schoolMask](auto const& immune)
{
return Unit::IsImmuneMaskFully(SpellSchoolMask(immune.first), schoolMask);
});
}
bool Unit::IsImmunedToDamage(Spell const* spell) const
bool Unit::IsImmunedToDamage(Unit const* caster, SpellInfo const* spellInfo) const
{
SpellInfo const* spellInfo = spell->GetSpellInfo();
if (!spellInfo)
{
return false;
}
if (spellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES) && !HasSpiritOfRedemptionAura())
{
if (spellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES) || spellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES))
return false;
}
if (spellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS) || spellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES))
{
return false;
}
uint32 schoolMask = spell->GetSpellSchoolMask();
SpellSchoolMask schoolMask = SpellSchoolMask(spellInfo->GetSchoolMask());
if (schoolMask == SPELL_SCHOOL_MASK_NONE)
{
return false;
}
// If m_immuneToDamage type contain magic, IMMUNE damage.
SpellImmuneList const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
for (SpellImmuneList::const_iterator itr = damageList.begin(); itr != damageList.end(); ++itr)
auto hasImmunity = [&](SpellImmuneContainer const& container)
{
if ((itr->type & schoolMask) == schoolMask)
uint32 schoolImmunityMask = 0;
for (auto const& [immunitySchoolMask, immunityAuraId] : container)
{
return true;
SpellInfo const* immuneAuraInfo = sSpellMgr->GetSpellInfo(immunityAuraId);
if (immuneAuraInfo && !immuneAuraInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS) && caster && caster->IsFriendlyTo(this))
continue;
if (immuneAuraInfo && spellInfo->CanPierceImmuneAura(immuneAuraInfo))
continue;
schoolImmunityMask |= immunitySchoolMask;
}
}
return false;
}
bool Unit::IsImmunedToSchool(SpellSchoolMask meleeSchoolMask) const
{
if (meleeSchoolMask == SPELL_SCHOOL_MASK_NONE)
{
return false;
}
// We need to be immune to all types
return (schoolImmunityMask & schoolMask) == schoolMask;
};
// If m_immuneToSchool type contain this school type, IMMUNE damage.
SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
for (SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
if ((itr->type & meleeSchoolMask) == meleeSchoolMask)
return true;
if (hasImmunity(m_spellImmune[IMMUNITY_SCHOOL]))
return true;
// If m_immuneToDamage type contain magic, IMMUNE damage.
if (hasImmunity(m_spellImmune[IMMUNITY_DAMAGE]))
return true;
return false;
}
bool Unit::IsImmunedToSchool(SpellSchoolMask schoolMask) const
{
if (schoolMask == SPELL_SCHOOL_MASK_NONE)
return false;
// Check IMMUNITY_SCHOOL: returns true if ALL schools in the mask are covered by at least one immunity
// (e.g., Anti-Magic Shell provides school immunity to all magic schools)
SpellImmuneContainer const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
return std::ranges::any_of(schoolList, [schoolMask](auto const& immune)
{
return (immune.first & schoolMask) == schoolMask;
});
}
bool Unit::IsImmunedToSchool(SpellInfo const* spellInfo) const
{
if (spellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES) && !HasSpiritOfRedemptionAura())
@@ -9853,10 +9859,10 @@ bool Unit::IsImmunedToSchool(SpellInfo const* spellInfo) const
if (spellInfo->Id != 42292 && spellInfo->Id != 59752 && spellInfo->Id != 19574 && spellInfo->Id != 34471)
{
// If m_immuneToSchool type contain this school type, IMMUNE damage.
SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
for (SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
if ((itr->type & schoolMask) == schoolMask && !spellInfo->CanPierceImmuneAura(sSpellMgr->GetSpellInfo(itr->spellId)))
// 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;
}
@@ -9879,11 +9885,11 @@ bool Unit::IsImmunedToSchool(Spell const* spell) const
if (spellInfo->Id != 42292 && spellInfo->Id != 59752 && spellInfo->Id != 19574 && spellInfo->Id != 34471)
{
// If m_immuneToSchool type contain this school type, IMMUNE damage.
SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
for (SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
// 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->type & schoolMask) == schoolMask && !spellInfo->CanPierceImmuneAura(sSpellMgr->GetSpellInfo(itr->spellId)))
if ((itr->first & schoolMask) == schoolMask && !spellInfo->CanPierceImmuneAura(sSpellMgr->GetSpellInfo(itr->second)))
{
return true;
}
@@ -9893,19 +9899,49 @@ bool Unit::IsImmunedToSchool(Spell const* spell) const
return false;
}
bool Unit::IsImmunedToDamageOrSchool(SpellSchoolMask meleeSchoolMask) const
bool Unit::IsImmunedToDamageOrSchool(SpellSchoolMask schoolMask) const
{
if (meleeSchoolMask == SPELL_SCHOOL_MASK_NONE)
if (schoolMask == SPELL_SCHOOL_MASK_NONE)
{
return false;
}
return IsImmunedToDamage(meleeSchoolMask) || IsImmunedToSchool(meleeSchoolMask);
return IsImmunedToDamage(schoolMask) || IsImmunedToSchool(schoolMask);
}
bool Unit::IsImmunedToDamageOrSchool(SpellInfo const* spellInfo) const
bool Unit::IsImmunedToAuraPeriodicTick(Unit const* caster, SpellInfo const* spellInfo) const
{
return IsImmunedToDamage(spellInfo) || IsImmunedToSchool(spellInfo);
if (!spellInfo)
return false;
if (spellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES) || spellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES))
return false;
SpellSchoolMask schoolMask = SpellSchoolMask(spellInfo->GetSchoolMask());
if (schoolMask == SPELL_SCHOOL_MASK_NONE)
return false;
auto hasImmunity = [&](SpellImmuneContainer const& container)
{
uint32 schoolImmunityMask = 0;
for (auto const& [immunitySchoolMask, immunityAuraId] : container)
{
SpellInfo const* immuneAuraInfo = sSpellMgr->GetSpellInfo(immunityAuraId);
if (immuneAuraInfo && !immuneAuraInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS) && caster && caster->IsFriendlyTo(this))
continue;
schoolImmunityMask |= immunitySchoolMask;
}
// We need to be immune to all types
return (schoolImmunityMask & schoolMask) == schoolMask;
};
// If m_immuneToSchool type contain this school type, IMMUNE periodic tick.
if (hasImmunity(m_spellImmune[IMMUNITY_SCHOOL]))
return true;
return false;
}
bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, Spell const* spell)
@@ -9914,39 +9950,35 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, Spell const* spell)
return false;
// Single spell immunity.
SpellImmuneList const& idList = m_spellImmune[IMMUNITY_ID];
for (SpellImmuneList::const_iterator itr = idList.begin(); itr != idList.end(); ++itr)
if (itr->type == spellInfo->Id)
return true;
SpellImmuneContainer const& idList = m_spellImmune[IMMUNITY_ID];
if (idList.count(spellInfo->Id) > 0)
return true;
// xinef: my special immunity, if spellid is not on this list it means npc is immune
SpellImmuneList const& allowIdList = m_spellImmune[IMMUNITY_ALLOW_ID];
SpellImmuneContainer const& allowIdList = m_spellImmune[IMMUNITY_ALLOW_ID];
if (!allowIdList.empty())
{
for (SpellImmuneList::const_iterator itr = allowIdList.begin(); itr != allowIdList.end(); ++itr)
if (itr->type == spellInfo->Id)
return false;
return true;
if (allowIdList.count(spellInfo->Id) == 0)
return true;
return false;
}
if (spellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES) && !HasSpiritOfRedemptionAura())
return false;
if (spellInfo->Dispel)
if (uint32 dispel = spellInfo->Dispel)
{
SpellImmuneList const& dispelList = m_spellImmune[IMMUNITY_DISPEL];
for (SpellImmuneList::const_iterator itr = dispelList.begin(); itr != dispelList.end(); ++itr)
if (itr->type == spellInfo->Dispel)
return true;
SpellImmuneContainer const& dispelList = m_spellImmune[IMMUNITY_DISPEL];
if (dispelList.count(dispel) > 0)
return true;
}
// Spells that don't have effectMechanics.
if (spellInfo->Mechanic)
if (uint32 mechanic = spellInfo->Mechanic)
{
SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
for (SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
if (itr->type == spellInfo->Mechanic)
return true;
SpellImmuneContainer const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
if (mechanicList.count(mechanic) > 0)
return true;
}
bool immuneToAllEffects = true;
@@ -9971,7 +10003,7 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, Spell const* spell)
if (immuneToAllEffects) //Return immune only if the target is immune to all spell effects.
return true;
if (spellInfo->Id != 42292 && spellInfo->Id != 59752 && spellInfo->Id != 19574 && spellInfo->Id != 34471)
if (!spellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES))
{
SpellSchoolMask spellSchoolMask = spellInfo->GetSchoolMask();
if (spell)
@@ -9981,16 +10013,24 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, Spell const* spell)
if (spellSchoolMask != SPELL_SCHOOL_MASK_NONE)
{
SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
for (SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
SpellImmuneContainer const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
for (auto itr = schoolList.begin(); itr != schoolList.end(); ++itr)
{
SpellInfo const* immuneSpellInfo = sSpellMgr->GetSpellInfo(itr->spellId);
if (((itr->type & spellSchoolMask) == spellSchoolMask)
&& (!immuneSpellInfo || immuneSpellInfo->IsPositive()) && !spellInfo->IsPositive()
&& !spellInfo->CanPierceImmuneAura(immuneSpellInfo))
SpellInfo const* immuneSpellInfo = sSpellMgr->GetSpellInfo(itr->second);
if (!(itr->first & spellSchoolMask))
continue;
if (immuneSpellInfo && !immuneSpellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS))
{
return true;
Unit const* spellCaster = spell ? spell->GetCaster() : nullptr;
if (spellCaster && spellCaster->IsFriendlyTo(this))
continue;
}
if (spellInfo->CanPierceImmuneAura(immuneSpellInfo))
continue;
return true;
}
}
}
@@ -9998,7 +10038,7 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, Spell const* spell)
return false;
}
bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) const
bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Unit const* caster /*= nullptr*/) const
{
if (!spellInfo || !spellInfo->Effects[index].IsEffect())
return false;
@@ -10010,12 +10050,16 @@ bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) cons
if (spellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES) && !HasSpiritOfRedemptionAura())
return false;
// Special-case handling for Vezax's Aura of Despair.
static constexpr uint32 SPELL_AURA_OF_DESPAIR_1 = 62692;
static constexpr uint32 SPELL_AURA_OF_DESPAIR_2 = 64848;
//If m_immuneToEffect type contain this effect type, IMMUNE effect.
uint32 effect = spellInfo->Effects[index].Effect;
SpellImmuneList const& effectList = m_spellImmune[IMMUNITY_EFFECT];
for (SpellImmuneList::const_iterator itr = effectList.begin(); itr != effectList.end(); ++itr)
SpellImmuneContainer const& effectList = m_spellImmune[IMMUNITY_EFFECT];
for (SpellImmuneContainer::const_iterator itr = effectList.begin(); itr != effectList.end(); ++itr)
{
if (itr->type == effect && (itr->spellId != 62692 || (spellInfo->Effects[index].MiscValue == POWER_MANA && !CanRestoreMana(spellInfo))))
if (itr->first == effect && (itr->second != SPELL_AURA_OF_DESPAIR_1 || (spellInfo->Effects[index].MiscValue == POWER_MANA && !CanRestoreMana(spellInfo))))
{
return true;
}
@@ -10023,41 +10067,32 @@ bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) cons
if (uint32 mechanic = spellInfo->Effects[index].Mechanic)
{
SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
for (SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
if (itr->type == mechanic)
return true;
auto const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
if (mechanicList.count(mechanic) > 0)
return true;
}
if (uint32 aura = spellInfo->Effects[index].ApplyAuraName)
if (!spellInfo->HasAttribute(SPELL_ATTR3_ALWAYS_HIT))
{
SpellImmuneList const& list = m_spellImmune[IMMUNITY_STATE];
for (SpellImmuneList::const_iterator itr = list.begin(); itr != list.end(); ++itr)
if (uint32 aura = spellInfo->Effects[index].ApplyAuraName)
{
if (itr->type == aura && (itr->spellId != 64848 || (spellInfo->Effects[index].MiscValue == POWER_MANA && !CanRestoreMana(spellInfo))))
SpellImmuneContainer const& list = m_spellImmune[IMMUNITY_STATE];
for (SpellImmuneContainer::const_iterator itr = list.begin(); itr != list.end(); ++itr)
{
if (!spellInfo->HasAttribute(SPELL_ATTR3_ALWAYS_HIT))
{
if (itr->blockType == SPELL_BLOCK_TYPE_ALL || spellInfo->IsPositive()) // xinef: added for pet scaling
{
return true;
}
}
}
}
if (!spellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES))
{
// Check for immune to application of harmful magical effects
AuraEffectList const& immuneAuraApply = GetAuraEffectsByType(SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL);
for (AuraEffectList::const_iterator iter = immuneAuraApply.begin(); iter != immuneAuraApply.end(); ++iter)
{
if (/*(spellInfo->Dispel == DISPEL_MAGIC || spellInfo->Dispel == DISPEL_CURSE || spellInfo->Dispel == DISPEL_DISEASE) &&*/ // Magic debuff, xinef: all kinds?
((*iter)->GetMiscValue() & spellInfo->GetSchoolMask()) && // Check school
!spellInfo->IsPositiveEffect(index) && // Harmful
spellInfo->Effects[index].Effect != SPELL_EFFECT_PERSISTENT_AREA_AURA) // Not Persistent area auras
{
if (itr->first == aura && (itr->second != SPELL_AURA_OF_DESPAIR_2 || (spellInfo->Effects[index].MiscValue == POWER_MANA && !CanRestoreMana(spellInfo))))
return true;
}
if (!spellInfo->HasAttribute(SPELL_ATTR2_NO_SCHOOL_IMMUNITIES))
{
// Check for immune to application of harmful magical effects
for (AuraEffect* immuneAuraApply : GetAuraEffectsByType(SPELL_AURA_MOD_IMMUNE_AURA_APPLY_SCHOOL))
{
if (!(immuneAuraApply->GetMiscValue() & spellInfo->GetSchoolMask())) // Check school
continue;
if (spellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_TO_HOSTILE_AND_FRIENDLY_EFFECTS) || (caster && !IsFriendlyTo(caster))) // Harmful
return true;
}
}
}
@@ -10286,17 +10321,17 @@ uint32 Unit::MeleeDamageBonusTaken(Unit* attacker, uint32 pdamage, WeaponAttackT
});
// Mod damage from spell mechanic
uint32 mechanicMask = spellProto->GetAllEffectsMechanicMask();
uint64 mechanicMask = spellProto->GetAllEffectsMechanicMask();
// Shred, Maul - "Effects which increase Bleed damage also increase Shred damage"
if (spellProto->SpellFamilyName == SPELLFAMILY_DRUID && spellProto->SpellFamilyFlags[0] & 0x00008800)
mechanicMask |= (1 << MECHANIC_BLEED);
mechanicMask |= (UI64LIT(1) << MECHANIC_BLEED);
if (mechanicMask)
{
TakenTotalMod *= GetTotalAuraMultiplier(SPELL_AURA_MOD_MECHANIC_DAMAGE_TAKEN_PERCENT, [mechanicMask](AuraEffect const* aurEff) -> bool
{
if (mechanicMask & uint32(1 << (aurEff->GetMiscValue())))
if (mechanicMask & uint64(UI64LIT(1) << (aurEff->GetMiscValue())))
return true;
return false;
});
@@ -10364,51 +10399,17 @@ private:
uint32 _type;
};
void Unit::ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply, SpellImmuneBlockType blockType)
void Unit::ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply, SpellImmuneBlockType /*blockType*/)
{
if (apply)
{
// xinef: immunities with spellId 0 are intended to be applied only once (script purposes mosty)
if (spellId == 0 && std::find_if(m_spellImmune[op].begin(), m_spellImmune[op].end(), spellIdImmunityPredicate(type)) != m_spellImmune[op].end())
return;
SpellImmune immune;
immune.spellId = spellId;
immune.type = type;
immune.blockType = blockType;
m_spellImmune[op].push_back(std::move(immune));
}
m_spellImmune[op].emplace(type, spellId);
else
{
for (SpellImmuneList::iterator itr = m_spellImmune[op].begin(); itr != m_spellImmune[op].end(); ++itr)
auto bounds = m_spellImmune[op].equal_range(type);
for (auto itr = bounds.first; itr != bounds.second;)
{
if (itr->spellId == spellId && itr->type == type)
{
m_spellImmune[op].erase(itr);
break;
}
}
}
}
void Unit::ApplySpellDispelImmunity(SpellInfo const* spellProto, DispelType type, bool apply)
{
ApplySpellImmune(spellProto->Id, IMMUNITY_DISPEL, type, apply);
if (apply && spellProto->HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT))
{
// Create dispel mask by dispel type
uint32 dispelMask = SpellInfo::GetDispelMask(type);
// Dispel all existing auras vs current dispel type
AuraApplicationMap& auras = GetAppliedAuras();
for (AuraApplicationMap::iterator itr = auras.begin(); itr != auras.end();)
{
SpellInfo const* spell = itr->second->GetBase()->GetSpellInfo();
if (spell->GetDispelMask() & dispelMask)
{
// Dispel aura
RemoveAura(itr);
}
if (itr->second == spellId)
itr = m_spellImmune[op].erase(itr);
else
++itr;
}
@@ -11174,8 +11175,9 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced)
{
if (Creature* creature = ToCreature())
{
uint32 immuneMask = creature->GetCreatureTemplate()->MechanicImmuneMask;
if (immuneMask & (1 << (MECHANIC_SNARE - 1)) || immuneMask & (1 << (MECHANIC_DAZE - 1)))
// use creature helper which now consults creature_immunities table
if (creature->HasMechanicTemplateImmunity(UI64LIT(1) << MECHANIC_SNARE) ||
creature->HasMechanicTemplateImmunity(UI64LIT(1) << MECHANIC_DAZE))
break;
}
@@ -11196,7 +11198,7 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced)
if (creature
&& !IsPet()
&& !(IsControlledByPlayer() && IsVehicle())
&& !(creature->HasMechanicTemplateImmunity(MECHANIC_SNARE))
&& !(creature->HasMechanicTemplateImmunity(UI64LIT(1) << MECHANIC_SNARE))
&& !(creature->IsDungeonBoss()))
{
// 1.6% for each % under 30.
@@ -15075,7 +15077,7 @@ Aura* Unit::AddAura(SpellInfo const* spellInfo, uint8 effMask, Unit* target)
{
if (!(effMask & (1 << i)))
continue;
if (target->IsImmunedToSpellEffect(spellInfo, i))
if (target->IsImmunedToSpellEffect(spellInfo, i, this))
effMask &= ~(1 << i);
}