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)
This commit is contained in:
Shauren
2022-09-05 22:23:03 +02:00
parent b2eeca702c
commit 66b03acc47
12 changed files with 143 additions and 100 deletions
@@ -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
+1 -1
View File
@@ -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;
+3 -2
View File
@@ -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()
+1 -1
View File
@@ -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;
+3 -2
View File
@@ -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);
}
+1 -1
View File
@@ -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;
+74 -51
View File
@@ -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);
RemoveAurasWithMechanic(1 << MECHANIC_ROOT, AURA_REMOVE_BY_DEFAULT, 0, true);
// 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;
}
// 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;
}
+8 -8
View File
@@ -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);
+33 -25
View File
@@ -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;
}
}
+1 -1
View File
@@ -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; }
+1 -1
View File
@@ -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()
+14 -5
View File
@@ -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;
});
}
}
}