aboutsummaryrefslogtreecommitdiff
path: root/src
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 18:22:39 +0200
commit3306a4d06cc557967c23adcc60c2e3257811b324 (patch)
treeba39127335e73b1af89750fdba18c0329a036146 /src
parentf3384fecaa17c2b14bf2089c6813a31f5799a020 (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
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp11
-rw-r--r--src/server/game/Entities/Creature/Creature.h4
-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, 147 insertions, 104 deletions
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index c9230146340..d7f2bec6d57 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -2203,7 +2203,7 @@ void Creature::LoadTemplateImmunities()
}
}
-bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caster) const
+bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caster, bool requireImmunityPurgesEffectAttribute /*= false*/) const
{
if (!spellInfo)
return false;
@@ -2211,7 +2211,7 @@ bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* c
bool immunedToAllEffects = true;
for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
{
- if (spellEffectInfo.IsEffect() && !IsImmunedToSpellEffect(spellInfo, spellEffectInfo, caster))
+ if (spellEffectInfo.IsEffect() && !IsImmunedToSpellEffect(spellInfo, spellEffectInfo, caster, requireImmunityPurgesEffectAttribute))
{
immunedToAllEffects = false;
break;
@@ -2221,15 +2221,16 @@ bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* c
if (immunedToAllEffects)
return true;
- return Unit::IsImmunedToSpell(spellInfo, caster);
+ return Unit::IsImmunedToSpell(spellInfo, caster, requireImmunityPurgesEffectAttribute);
}
-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 8f1666ccfbe..8a65ca53724 100644
--- a/src/server/game/Entities/Creature/Creature.h
+++ b/src/server/game/Entities/Creature/Creature.h
@@ -136,8 +136,8 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
bool CanResetTalents(Player* player, bool pet) const;
bool CanCreatureAttack(Unit const* victim, bool force = true) const;
void LoadTemplateImmunities();
- bool IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caster) const override;
- bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, WorldObject const* caster) const override;
+ bool IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caster, bool requireImmunityPurgesEffectAttribute = false) 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 8fb15a50f76..c81044d3eda 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -1976,7 +1976,8 @@ void Player::SetObjectScale(float scale)
SetCombatReach(scale * DEFAULT_PLAYER_COMBAT_REACH);
}
-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))
@@ -1984,7 +1985,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 646d98925b3..1a8841338f2 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -914,7 +914,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
static bool BuildEnumData(PreparedQueryResult result, WorldPacket* data);
- 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 IsFalling() { return GetPositionZ() < m_lastFallZ; }
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 4cc7e6df3aa..08cf8ca867a 100644
--- a/src/server/game/Entities/Totem/Totem.cpp
+++ b/src/server/game/Entities/Totem/Totem.cpp
@@ -155,7 +155,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
@@ -176,5 +177,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 b94299c843c..00ffcb1eb01 100644
--- a/src/server/game/Entities/Totem/Totem.h
+++ b/src/server/game/Entities/Totem/Totem.h
@@ -58,7 +58,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 8316f8ff49f..db211e8d1fb 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -3739,59 +3739,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();)
{
@@ -3803,7 +3803,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();
}
@@ -4098,42 +4098,31 @@ void Unit::RemoveAurasWithFamily(SpellFamilyNames family, uint32 familyFlag1, ui
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()
@@ -7702,14 +7691,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))
+ if (immunitySourceSpell->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
+ 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_UNAFFECTED_BY_INVULNERABILITY))
@@ -7718,7 +7723,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;
}
@@ -7726,7 +7731,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;
}
@@ -7738,7 +7743,7 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caste
if (!spellEffectInfo.IsEffect())
continue;
- if (!IsImmunedToSpellEffect(spellInfo, spellEffectInfo, caster))
+ if (!IsImmunedToSpellEffect(spellInfo, spellEffectInfo, caster, requireImmunityPurgesEffectAttribute))
{
immuneToAllEffects = false;
break;
@@ -7760,7 +7765,8 @@ bool Unit::IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caste
SpellInfo const* immuneSpellInfo = sSpellMgr->GetSpellInfo(itr->second);
// 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_DISPEL_AURAS_ON_IMMUNITY)))
+ || !spellInfo->IsPositive() || !caster || !IsFriendlyTo(caster))
if (!spellInfo->CanPierceImmuneAura(immuneSpellInfo))
schoolImmunityMask |= itr->first;
}
@@ -7802,7 +7808,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 || !spellEffectInfo.IsEffect())
return false;
@@ -7810,15 +7817,31 @@ bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo co
if (spellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
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))
+ if (immunitySourceSpell->HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
+ return true;
+
+ return false;
+ });
+ };
+
// If m_immuneToEffect type contain this effect type, IMMUNE effect.
SpellImmuneContainer 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;
}
@@ -7827,7 +7850,7 @@ bool Unit::IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo co
if (!spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT))
{
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 0e2656cfcf3..22ce2f53230 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -1343,14 +1343,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, uint8 reqEffMask = 0, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT);
void RemoveAuraFromStack(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT);
@@ -1362,7 +1362,7 @@ class TC_GAME_API Unit : public WorldObject
void RemoveAurasWithInterruptFlags(uint32 flag, uint32 except = 0);
void RemoveAurasWithAttribute(uint32 flags);
void RemoveAurasWithFamily(SpellFamilyNames family, uint32 familyFlag1, uint32 familyFlag2, uint32 familyFlag3, 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();
@@ -1634,14 +1634,14 @@ class TC_GAME_API Unit : public WorldObject
float CalculateDefaultCoefficient(SpellInfo const* spellInfo, DamageEffectType damagetype) const;
void ApplySpellImmune(uint32 spellId, uint32 op, uint32 type, bool apply);
- virtual bool IsImmunedToSpell(SpellInfo const* spellInfo, WorldObject const* caster) const;
+ virtual 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 08a6dd42f62..84b52d86a1c 100644
--- a/src/server/game/Spells/Auras/SpellAuras.cpp
+++ b/src/server/game/Spells/Auras/SpellAuras.cpp
@@ -187,7 +187,7 @@ void AuraApplication::_HandleEffect(uint8 effIndex, bool apply)
SetNeedClientUpdate();
}
-void AuraApplication::UpdateApplyEffectMask(uint8 newEffMask)
+void AuraApplication::UpdateApplyEffectMask(uint8 newEffMask, bool canHandleNewEffects)
{
if (_effectsToApply == newEffMask)
return;
@@ -202,20 +202,17 @@ void AuraApplication::UpdateApplyEffectMask(uint8 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 (!(_flags & (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::BuildUpdatePacket(ByteBuffer& data, bool remove) const
@@ -333,7 +330,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
@@ -652,12 +649,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;
@@ -672,13 +674,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;
@@ -721,14 +727,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 bae8c93729c..b6c1ca5e6b5 100644
--- a/src/server/game/Spells/Auras/SpellAuras.h
+++ b/src/server/game/Spells/Auras/SpellAuras.h
@@ -73,7 +73,7 @@ class TC_GAME_API AuraApplication
bool IsSelfcast() const { return (_flags & AFLAG_CASTER) != 0; }
uint8 GetEffectsToApply() const { return _effectsToApply; }
- void UpdateApplyEffectMask(uint8 newEffMask);
+ void UpdateApplyEffectMask(uint8 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 7140403ce95..0c8a93f05c8 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -1083,7 +1083,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 88479010f44..cabad3bd6d2 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -2855,13 +2855,22 @@ void SpellInfo::ApplyAllSpellImmunitiesTo(Unit* target, uint8 effIndex, bool app
if (mechanicImmunity & (1 << i))
target->ApplySpellImmune(Id, IMMUNITY_MECHANIC, i, apply);
- if (apply && HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
+ if (HasAttribute(SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY))
{
- // 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;
+ });
+ }
}
}