aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2022-09-05 18:22:39 +0200
committerShauren <shauren.trinity@gmail.com>2022-09-05 22:23:03 +0200
commit66b03acc47665cd79646096e13aa8c6b513675aa (patch)
treee832b7e0c024a0d8c19552e127c83c9aabeaa38b
parentb2eeca702cc4868ed578f6755ea6b6bce9ba17b8 (diff)
Core/Auras: Improve aura interactions with immunities on spell effect level
* Effects that target is immune to will be suppressed instead of completely removed Closes #28096 (cherry picked from commit 3306a4d06cc557967c23adcc60c2e3257811b324)
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp5
-rw-r--r--src/server/game/Entities/Creature/Creature.h2
-rw-r--r--src/server/game/Entities/Player/Player.cpp5
-rw-r--r--src/server/game/Entities/Player/Player.h2
-rw-r--r--src/server/game/Entities/Totem/Totem.cpp5
-rw-r--r--src/server/game/Entities/Totem/Totem.h2
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp125
-rw-r--r--src/server/game/Entities/Unit/Unit.h16
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.cpp58
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.h2
-rw-r--r--src/server/game/Spells/SpellEffects.cpp2
-rw-r--r--src/server/game/Spells/SpellInfo.cpp19
12 files changed, 143 insertions, 100 deletions
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index ea00b2c8e6d..5f9512b0e77 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -2344,12 +2344,13 @@ void Creature::LoadTemplateImmunities()
}
}
-bool Creature::IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, WorldObject const* caster) const
+bool Creature::IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, WorldObject const* caster,
+ bool requireImmunityPurgesEffectAttribute /*= false*/) const
{
if (GetCreatureTemplate()->type == CREATURE_TYPE_MECHANICAL && spellEffectInfo.IsEffect(SPELL_EFFECT_HEAL))
return true;
- return Unit::IsImmunedToSpellEffect(spellInfo, spellEffectInfo, caster);
+ return Unit::IsImmunedToSpellEffect(spellInfo, spellEffectInfo, caster, requireImmunityPurgesEffectAttribute);
}
bool Creature::isElite() const
diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h
index 6caabee9ad0..aadd60fde52 100644
--- a/src/server/game/Entities/Creature/Creature.h
+++ b/src/server/game/Entities/Creature/Creature.h
@@ -151,7 +151,7 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
bool CanResetTalents(Player* player) const;
bool CanCreatureAttack(Unit const* victim, bool force = true) const;
void LoadTemplateImmunities();
- bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, WorldObject const* caster) const override;
+ bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, WorldObject const* caster, bool requireImmunityPurgesEffectAttribute = false) const override;
bool isElite() const;
bool isWorldBoss() const;
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 5d6a7d9e61c..d2fa06491d0 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -1673,7 +1673,8 @@ void Player::SetObjectScale(float scale)
SendMovementSetCollisionHeight(scale * GetCollisionHeight(), WorldPackets::Movement::UpdateCollisionHeightReason::Scale);
}
-bool Player::IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, WorldObject const* caster) const
+bool Player::IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, WorldObject const* caster,
+ bool requireImmunityPurgesEffectAttribute /*= false*/) const
{
// players are immune to taunt (the aura and the spell effect).
if (spellEffectInfo.IsAura(SPELL_AURA_MOD_TAUNT))
@@ -1681,7 +1682,7 @@ bool Player::IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo
if (spellEffectInfo.IsEffect(SPELL_EFFECT_ATTACK_ME))
return true;
- return Unit::IsImmunedToSpellEffect(spellInfo, spellEffectInfo, caster);
+ return Unit::IsImmunedToSpellEffect(spellInfo, spellEffectInfo, caster, requireImmunityPurgesEffectAttribute);
}
void Player::RegenerateAll()
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 30522d21adb..763cc48e231 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1150,7 +1150,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void Update(uint32 time) override;
- bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, WorldObject const* caster) const override;
+ bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, WorldObject const* caster, bool requireImmunityPurgesEffectAttribute = false) const override;
bool IsInAreaTriggerRadius(AreaTriggerEntry const* trigger) const;
diff --git a/src/server/game/Entities/Totem/Totem.cpp b/src/server/game/Entities/Totem/Totem.cpp
index 651e4dfcb41..89bfe9addff 100644
--- a/src/server/game/Entities/Totem/Totem.cpp
+++ b/src/server/game/Entities/Totem/Totem.cpp
@@ -140,7 +140,8 @@ void Totem::UnSummon(uint32 msTime)
AddObjectToRemoveList();
}
-bool Totem::IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, WorldObject const* caster) const
+bool Totem::IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, WorldObject const* caster,
+ bool requireImmunityPurgesEffectAttribute /*= false*/) const
{
// immune to all positive spells, except of stoneclaw totem absorb and sentry totem bind sight
// totems positive spells have unit_caster target
@@ -161,5 +162,5 @@ bool Totem::IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo c
break;
}
- return Creature::IsImmunedToSpellEffect(spellInfo, spellEffectInfo, caster);
+ return Creature::IsImmunedToSpellEffect(spellInfo, spellEffectInfo, caster, requireImmunityPurgesEffectAttribute);
}
diff --git a/src/server/game/Entities/Totem/Totem.h b/src/server/game/Entities/Totem/Totem.h
index 36919f20eb8..1bcfbe57ae7 100644
--- a/src/server/game/Entities/Totem/Totem.h
+++ b/src/server/game/Entities/Totem/Totem.h
@@ -50,7 +50,7 @@ class TC_GAME_API Totem : public Minion
void UpdateAttackPowerAndDamage(bool /*ranged*/) override { }
void UpdateDamagePhysical(WeaponAttackType /*attType*/) override { }
- bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, WorldObject const* caster) const override;
+ bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, WorldObject const* caster, bool requireImmunityPurgesEffectAttribute = false) const override;
protected:
TotemType m_type;
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 4a911096929..a070acbdf3a 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -3642,59 +3642,59 @@ void Unit::RemoveAura(Aura* aura, AuraRemoveMode mode)
RemoveAura(aurApp, mode);
}
-void Unit::RemoveAppliedAuras(std::function<bool(AuraApplication const*)> const& check)
+void Unit::RemoveAppliedAuras(std::function<bool(AuraApplication const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
{
for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
{
if (check(iter->second))
{
- RemoveAura(iter);
+ RemoveAura(iter, removeMode);
continue;
}
++iter;
}
}
-void Unit::RemoveOwnedAuras(std::function<bool(Aura const*)> const& check)
+void Unit::RemoveOwnedAuras(std::function<bool(Aura const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
{
for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
{
if (check(iter->second))
{
- RemoveOwnedAura(iter);
+ RemoveOwnedAura(iter, removeMode);
continue;
}
++iter;
}
}
-void Unit::RemoveAppliedAuras(uint32 spellId, std::function<bool(AuraApplication const*)> const& check)
+void Unit::RemoveAppliedAuras(uint32 spellId, std::function<bool(AuraApplication const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
{
for (AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
{
if (check(iter->second))
{
- RemoveAura(iter);
+ RemoveAura(iter, removeMode);
continue;
}
++iter;
}
}
-void Unit::RemoveOwnedAuras(uint32 spellId, std::function<bool(Aura const*)> const& check)
+void Unit::RemoveOwnedAuras(uint32 spellId, std::function<bool(Aura const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
{
for (AuraMap::iterator iter = m_ownedAuras.lower_bound(spellId); iter != m_ownedAuras.upper_bound(spellId);)
{
if (check(iter->second))
{
- RemoveOwnedAura(iter);
+ RemoveOwnedAura(iter, removeMode);
continue;
}
++iter;
}
}
-void Unit::RemoveAurasByType(AuraType auraType, std::function<bool(AuraApplication const*)> const& check)
+void Unit::RemoveAurasByType(AuraType auraType, std::function<bool(AuraApplication const*)> const& check, AuraRemoveMode removeMode /*= AURA_REMOVE_BY_DEFAULT*/)
{
for (AuraEffectList::iterator iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end();)
{
@@ -3706,7 +3706,7 @@ void Unit::RemoveAurasByType(AuraType auraType, std::function<bool(AuraApplicati
if (check(aurApp))
{
uint32 removedAuras = m_removedAurasCount;
- RemoveAura(aurApp);
+ RemoveAura(aurApp, removeMode);
if (m_removedAurasCount > removedAuras + 1)
iter = m_modAuras[auraType].begin();
}
@@ -4039,42 +4039,31 @@ void Unit::RemoveAurasWithFamily(SpellFamilyNames family, flag128 const& familyF
void Unit::RemoveMovementImpairingAuras(bool withRoot)
{
if (withRoot)
- RemoveAurasWithMechanic(1 << MECHANIC_ROOT);
-
- // Snares
- for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
- {
- Aura const* aura = iter->second->GetBase();
- if (aura->GetSpellInfo()->Mechanic == MECHANIC_SNARE)
- {
- RemoveAura(iter);
- continue;
- }
+ RemoveAurasWithMechanic(1 << MECHANIC_ROOT, AURA_REMOVE_BY_DEFAULT, 0, true);
- // turn off snare auras by setting amount to 0
- for (SpellEffectInfo const& spellEffectInfo : aura->GetSpellInfo()->GetEffects())
- if (iter->second->HasEffect(spellEffectInfo.EffectIndex) && spellEffectInfo.Mechanic == MECHANIC_SNARE)
- aura->GetEffect(spellEffectInfo.EffectIndex)->ChangeAmount(0);
-
- ++iter;
- }
+ RemoveAurasWithMechanic(1 << MECHANIC_SNARE, AURA_REMOVE_BY_DEFAULT, 0, false);
}
-void Unit::RemoveAurasWithMechanic(uint32 mechanic_mask, AuraRemoveMode removemode, uint32 except)
+void Unit::RemoveAurasWithMechanic(uint32 mechanicMaskToRemove, AuraRemoveMode removeMode, uint32 exceptSpellId, bool withEffectMechanics)
{
- for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
+ RemoveAppliedAuras([=](AuraApplication const* aurApp)
{
- Aura const* aura = iter->second->GetBase();
- if (!except || aura->GetId() != except)
- {
- if (aura->GetSpellInfo()->GetAllEffectsMechanicMask() & mechanic_mask)
- {
- RemoveAura(iter, removemode);
- continue;
- }
- }
- ++iter;
- }
+ Aura* aura = aurApp->GetBase();
+ if (exceptSpellId && aura->GetId() == exceptSpellId)
+ return false;
+
+ uint32 appliedMechanicMask = aura->GetSpellInfo()->GetSpellMechanicMaskByEffectMask(aurApp->GetEffectMask());
+ if (!(appliedMechanicMask & mechanicMaskToRemove))
+ return false;
+
+ // spell mechanic matches required mask for removal
+ if ((1 << aura->GetSpellInfo()->Mechanic) & mechanicMaskToRemove || withEffectMechanics)
+ return true;
+
+ // effect mechanic matches required mask for removal - don't remove, only update targets
+ aura->UpdateTargetMap(aura->GetCaster());
+ return false;
+ }, removeMode);
}
void Unit::RemoveAurasByShapeShift()
@@ -7244,14 +7233,30 @@ bool Unit::IsImmunedToDamage(SpellInfo const* spellInfo) const
return false;
}
-bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caster) const
+bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caster, bool requireImmunityPurgesEffectAttribute /*= false*/) const
{
if (!spellInfo)
return false;
+ auto hasImmunity = [requireImmunityPurgesEffectAttribute](SpellImmuneContainer const& container, uint32 key)
+ {
+ Trinity::IteratorPair<SpellImmuneContainer::const_iterator> range = Trinity::Containers::MapEqualRange(container, key);
+ if (!requireImmunityPurgesEffectAttribute)
+ return range.begin() != range.end();
+
+ return std::any_of(range.begin(), range.end(), [](SpellImmuneContainer::value_type const& entry)
+ {
+ if (SpellInfo const* immunitySourceSpell = sSpellMgr->GetSpellInfo(entry.second, DIFFICULTY_NONE))
+ if (immunitySourceSpell->HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT))
+ return true;
+
+ return false;
+ });
+ };
+
// Single spell immunity.
SpellImmuneContainer const& idList = m_spellImmune[IMMUNITY_ID];
- if (idList.count(spellInfo->Id) > 0)
+ if (hasImmunity(idList, spellInfo->Id))
return true;
if (spellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES))
@@ -7260,7 +7265,7 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caste
if (uint32 dispel = spellInfo->Dispel)
{
SpellImmuneContainer const& dispelList = m_spellImmune[IMMUNITY_DISPEL];
- if (dispelList.count(dispel) > 0)
+ if (hasImmunity(dispelList, dispel))
return true;
}
@@ -7268,7 +7273,7 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caste
if (uint32 mechanic = spellInfo->Mechanic)
{
SpellImmuneContainer const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
- if (mechanicList.count(mechanic) > 0)
+ if (hasImmunity(mechanicList, mechanic))
return true;
}
@@ -7279,7 +7284,7 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caste
// Ignore effects with mechanic, they are supposed to be checked separately
if (!spellEffectInfo.IsEffect())
continue;
- if (!IsImmunedToSpellEffect(spellInfo, spellEffectInfo, caster))
+ if (!IsImmunedToSpellEffect(spellInfo, spellEffectInfo, caster, requireImmunityPurgesEffectAttribute))
{
immuneToAllEffects = false;
break;
@@ -7303,7 +7308,8 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caste
SpellInfo const* immuneSpellInfo = sSpellMgr->GetSpellInfo(itr->second, GetMap()->GetDifficultyID());
// Consider the school immune if any of these conditions are not satisfied.
// In case of no immuneSpellInfo, ignore that condition and check only the other conditions
- if ((immuneSpellInfo && !immuneSpellInfo->IsPositive()) || !spellInfo->IsPositive() || !caster || !IsFriendlyTo(caster))
+ if ((immuneSpellInfo && !immuneSpellInfo->IsPositive() && (!requireImmunityPurgesEffectAttribute || immuneSpellInfo->HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT)))
+ || !spellInfo->IsPositive() || !caster || !IsFriendlyTo(caster))
if (!spellInfo->CanPierceImmuneAura(immuneSpellInfo))
schoolImmunityMask |= itr->first;
}
@@ -7344,7 +7350,8 @@ uint32 Unit::GetMechanicImmunityMask() const
return mask;
}
-bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, WorldObject const* caster) const
+bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, WorldObject const* caster,
+ bool requireImmunityPurgesEffectAttribute /*= false*/) const
{
if (!spellInfo)
return false;
@@ -7352,15 +7359,31 @@ bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo co
if (spellInfo->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES))
return false;
+ auto hasImmunity = [requireImmunityPurgesEffectAttribute](SpellImmuneContainer const& container, uint32 key)
+ {
+ Trinity::IteratorPair<SpellImmuneContainer::const_iterator> range = Trinity::Containers::MapEqualRange(container, key);
+ if (!requireImmunityPurgesEffectAttribute)
+ return range.begin() != range.end();
+
+ return std::any_of(range.begin(), range.end(), [](SpellImmuneContainer::value_type const& entry)
+ {
+ if (SpellInfo const* immunitySourceSpell = sSpellMgr->GetSpellInfo(entry.second, DIFFICULTY_NONE))
+ if (immunitySourceSpell->HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT))
+ return true;
+
+ return false;
+ });
+ };
+
// If m_immuneToEffect type contain this effect type, IMMUNE effect.
auto const& effectList = m_spellImmune[IMMUNITY_EFFECT];
- if (effectList.count(spellEffectInfo.Effect) > 0)
+ if (hasImmunity(effectList, spellEffectInfo.Effect))
return true;
if (uint32 mechanic = spellEffectInfo.Mechanic)
{
SpellImmuneContainer const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
- if (mechanicList.count(mechanic) > 0)
+ if (hasImmunity(mechanicList, mechanic))
return true;
}
@@ -7369,7 +7392,7 @@ bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo co
if (!spellInfo->HasAttribute(SPELL_ATTR3_ALWAYS_HIT))
{
SpellImmuneContainer const& list = m_spellImmune[IMMUNITY_STATE];
- if (list.count(aura) > 0)
+ if (hasImmunity(list, aura))
return true;
}
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index a9dcb0e3783..920f4fabcc9 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -1367,14 +1367,14 @@ class TC_GAME_API Unit : public WorldObject
void RemoveAura(Aura* aur, AuraRemoveMode mode = AURA_REMOVE_BY_DEFAULT);
// Convenience methods removing auras by predicate
- void RemoveAppliedAuras(std::function<bool(AuraApplication const*)> const& check);
- void RemoveOwnedAuras(std::function<bool(Aura const*)> const& check);
+ void RemoveAppliedAuras(std::function<bool(AuraApplication const*)> const& check, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT);
+ void RemoveOwnedAuras(std::function<bool(Aura const*)> const& check, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT);
// Optimized overloads taking advantage of map key
- void RemoveAppliedAuras(uint32 spellId, std::function<bool(AuraApplication const*)> const& check);
- void RemoveOwnedAuras(uint32 spellId, std::function<bool(Aura const*)> const& check);
+ void RemoveAppliedAuras(uint32 spellId, std::function<bool(AuraApplication const*)> const& check, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT);
+ void RemoveOwnedAuras(uint32 spellId, std::function<bool(Aura const*)> const& check, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT);
- void RemoveAurasByType(AuraType auraType, std::function<bool(AuraApplication const*)> const& check);
+ void RemoveAurasByType(AuraType auraType, std::function<bool(AuraApplication const*)> const& check, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT);
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, uint32 reqEffMask = 0, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT);
void RemoveAuraFromStack(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT, uint16 num = 1);
@@ -1387,7 +1387,7 @@ class TC_GAME_API Unit : public WorldObject
void RemoveAurasWithInterruptFlags(InterruptFlags flag, SpellInfo const* source = nullptr);
void RemoveAurasWithAttribute(uint32 flags);
void RemoveAurasWithFamily(SpellFamilyNames family, flag128 const& familyFlag, ObjectGuid casterGUID);
- void RemoveAurasWithMechanic(uint32 mechanic_mask, AuraRemoveMode removemode = AURA_REMOVE_BY_DEFAULT, uint32 except = 0);
+ void RemoveAurasWithMechanic(uint32 mechanicMaskToRemove, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT, uint32 exceptSpellId = 0, bool withEffectMechanics = false);
void RemoveMovementImpairingAuras(bool withRoot);
void RemoveAurasByShapeShift();
@@ -1710,14 +1710,14 @@ class TC_GAME_API Unit : public WorldObject
static uint32 SpellCriticalHealingBonus(Unit const* caster, SpellInfo const* spellProto, uint32 damage, Unit* victim);
void ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply);
- bool IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caster) const;
+ bool IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caster, bool requireImmunityPurgesEffectAttribute = false) const;
uint32 GetSchoolImmunityMask() const;
uint32 GetDamageImmunityMask() const;
uint32 GetMechanicImmunityMask() const;
bool IsImmunedToDamage(SpellSchoolMask meleeSchoolMask) const;
bool IsImmunedToDamage(SpellInfo const* spellInfo) const;
- virtual bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, WorldObject const* caster) const;
+ virtual bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, WorldObject const* caster, bool requireImmunityPurgesEffectAttribute = false) const;
static bool IsDamageReducedByArmor(SpellSchoolMask damageSchoolMask, SpellInfo const* spellInfo = nullptr);
static uint32 CalcArmorReducedDamage(Unit const* attacker, Unit* victim, uint32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType = MAX_ATTACK, uint8 attackerLevel = 0);
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp
index 0a3e8bee84f..ee837ef013d 100644
--- a/src/server/game/Spells/Auras/SpellAuras.cpp
+++ b/src/server/game/Spells/Auras/SpellAuras.cpp
@@ -179,7 +179,7 @@ void AuraApplication::_HandleEffect(uint8 effIndex, bool apply)
SetNeedClientUpdate();
}
-void AuraApplication::UpdateApplyEffectMask(uint32 newEffMask)
+void AuraApplication::UpdateApplyEffectMask(uint32 newEffMask, bool canHandleNewEffects)
{
if (_effectsToApply == newEffMask)
return;
@@ -194,20 +194,17 @@ void AuraApplication::UpdateApplyEffectMask(uint32 newEffMask)
return;
}
+ // update real effects only if they were applied already
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
- {
- // update real effects only if they were applied already
- if (!(_effectMask & (1 << i)))
- continue;
-
- if (removeEffMask & (1 << i))
+ if (HasEffect(i) && (removeEffMask & (1 << i)))
_HandleEffect(i, false);
- if (addEffMask & (1 << i))
- _HandleEffect(i, true);
- }
-
_effectsToApply = newEffMask;
+
+ if (canHandleNewEffects)
+ for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ if (addEffMask & (1 << i))
+ _HandleEffect(i, true);
}
void AuraApplication::SetNeedClientUpdate()
@@ -367,7 +364,7 @@ Aura* Aura::TryRefreshStackOrCreate(AuraCreateInfo& createInfo, bool updateEffec
// check effmask on owner application (if existing)
if (updateEffectMask)
if (AuraApplication* aurApp = foundAura->GetApplicationOfTarget(unit->GetGUID()))
- aurApp->UpdateApplyEffectMask(effMask);
+ aurApp->UpdateApplyEffectMask(effMask, false);
return foundAura;
}
else
@@ -635,12 +632,17 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply)
{
// needs readding - remove now, will be applied in next update cycle
// (dbcs do not have auras which apply on same type of targets but have different radius, so this is not really needed)
- if (!CanBeAppliedOn(itr->first))
+ if (itr->first->IsImmunedToSpell(GetSpellInfo(), caster, true) || !CanBeAppliedOn(itr->first))
{
targetsToRemove.push_back(applicationPair.second->GetTarget());
continue;
}
+ // check target immunities (for existing targets)
+ for (SpellEffectInfo const& spellEffectInfo : GetSpellInfo()->GetEffects())
+ if (itr->first->IsImmunedToSpellEffect(GetSpellInfo(), spellEffectInfo, caster, true))
+ itr->second &= ~(1 << spellEffectInfo.EffectIndex);
+
// needs to add/remove effects from application, don't remove from map so it gets updated
if (applicationPair.second->GetEffectMask() != itr->second)
continue;
@@ -655,13 +657,17 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply)
for (auto itr = targets.begin(); itr != targets.end();)
{
bool addUnit = true;
- // check target immunities
- for (SpellEffectInfo const& spellEffectInfo : GetSpellInfo()->GetEffects())
- if (itr->first->IsImmunedToSpellEffect(GetSpellInfo(), spellEffectInfo, caster))
- itr->second &= ~(1 << spellEffectInfo.EffectIndex);
+ AuraApplication* aurApp = GetApplicationOfTarget(itr->first->GetGUID());
+ if (!aurApp)
+ {
+ // check target immunities (for new targets)
+ for (SpellEffectInfo const& spellEffectInfo : GetSpellInfo()->GetEffects())
+ if (itr->first->IsImmunedToSpellEffect(GetSpellInfo(), spellEffectInfo, caster))
+ itr->second &= ~(1 << spellEffectInfo.EffectIndex);
- if (!itr->second || itr->first->IsImmunedToSpell(GetSpellInfo(), caster) || !CanBeAppliedOn(itr->first))
- addUnit = false;
+ if (!itr->second || itr->first->IsImmunedToSpell(GetSpellInfo(), caster) || !CanBeAppliedOn(itr->first))
+ addUnit = false;
+ }
if (addUnit && !itr->first->IsHighestExclusiveAura(this, true))
addUnit = false;
@@ -704,14 +710,16 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply)
ABORT();
}
- if (AuraApplication* aurApp = GetApplicationOfTarget(itr->first->GetGUID()))
+ if (aurApp)
{
- // aura is already applied, this means we need to update effects of current application
- itr->first->_UnapplyAura(aurApp, AURA_REMOVE_BY_DEFAULT);
+ aurApp->UpdateApplyEffectMask(itr->second, true); // aura is already applied, this means we need to update effects of current application
+ itr = targets.erase(itr);
+ }
+ else
+ {
+ itr->first->_CreateAuraApplication(this, itr->second);
+ ++itr;
}
-
- itr->first->_CreateAuraApplication(this, itr->second);
- ++itr;
}
}
diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h
index 345b1683c24..d5b193c07dd 100644
--- a/src/server/game/Spells/Auras/SpellAuras.h
+++ b/src/server/game/Spells/Auras/SpellAuras.h
@@ -84,7 +84,7 @@ class TC_GAME_API AuraApplication
bool IsSelfcast() const { return (_flags & AFLAG_NOCASTER) != 0; }
uint32 GetEffectsToApply() const { return _effectsToApply; }
- void UpdateApplyEffectMask(uint32 newEffMask);
+ void UpdateApplyEffectMask(uint32 newEffMask, bool canHandleNewEffects);
void SetRemoveMode(AuraRemoveMode mode) { _removeMode = mode; }
AuraRemoveMode GetRemoveMode() const { return _removeMode; }
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index 5dad69ba9f0..f79e0b6e11b 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -989,7 +989,7 @@ void Spell::EffectApplyAura()
if (!aurApp)
aurApp = unitTarget->_CreateAuraApplication(_spellAura, 1 << effectInfo->EffectIndex);
else
- aurApp->UpdateApplyEffectMask(aurApp->GetEffectsToApply() | 1 << effectInfo->EffectIndex);
+ aurApp->UpdateApplyEffectMask(aurApp->GetEffectsToApply() | 1 << effectInfo->EffectIndex, false);
}
void Spell::EffectUnlearnSpecialization()
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index e63e452e14f..b8802af30ab 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -3531,13 +3531,22 @@ void SpellInfo::ApplyAllSpellImmunitiesTo(Unit* target, SpellEffectInfo const& s
if (mechanicImmunity & (1 << i))
target->ApplySpellImmune(Id, IMMUNITY_MECHANIC, i, apply);
- if (apply && HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT))
+ if (HasAttribute(SPELL_ATTR1_IMMUNITY_PURGES_EFFECT))
{
- // exception for purely snare mechanic (eg. hands of freedom)!
- if (mechanicImmunity == (1 << MECHANIC_SNARE))
- target->RemoveMovementImpairingAuras(false);
- else
+ if (apply)
target->RemoveAurasWithMechanic(mechanicImmunity, AURA_REMOVE_BY_DEFAULT, Id);
+ else
+ {
+ target->RemoveAppliedAuras([mechanicImmunity](AuraApplication const* aurApp)
+ {
+ Aura* aura = aurApp->GetBase();
+ if (aura->GetSpellInfo()->GetAllEffectsMechanicMask() & mechanicImmunity)
+ aura->UpdateTargetMap(aura->GetCaster());
+
+ // only update targets, don't remove anything
+ return false;
+ });
+ }
}
}