diff options
author | Shauren <shauren.trinity@gmail.com> | 2022-09-05 18:22:39 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2022-09-05 22:23:03 +0200 |
commit | 66b03acc47665cd79646096e13aa8c6b513675aa (patch) | |
tree | e832b7e0c024a0d8c19552e127c83c9aabeaa38b | |
parent | b2eeca702cc4868ed578f6755ea6b6bce9ba17b8 (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.cpp | 5 | ||||
-rw-r--r-- | src/server/game/Entities/Creature/Creature.h | 2 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 5 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 2 | ||||
-rw-r--r-- | src/server/game/Entities/Totem/Totem.cpp | 5 | ||||
-rw-r--r-- | src/server/game/Entities/Totem/Totem.h | 2 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 125 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.h | 16 | ||||
-rw-r--r-- | src/server/game/Spells/Auras/SpellAuras.cpp | 58 | ||||
-rw-r--r-- | src/server/game/Spells/Auras/SpellAuras.h | 2 | ||||
-rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Spells/SpellInfo.cpp | 19 |
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; + }); + } } } |