diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 41f4bf617..582237e0d 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -769,26 +769,32 @@ bool Unit::HasAuraTypeWithFamilyFlags(AuraType auraType, uint32 familyName, flag bool Unit::HasBreakableByDamageAuraType(AuraType type, uint32 excludeAura) const { - AuraEffectList const& auras = GetAuraEffectsByType(type); - for (AuraEffectList::const_iterator itr = auras.begin(); itr != auras.end(); ++itr) - if ((!excludeAura || excludeAura != (*itr)->GetSpellInfo()->Id) && //Avoid self interrupt of channeled Crowd Control spells like Seduction - (*itr)->GetSpellInfo()->HasAuraInterruptFlag(SpellAuraInterruptFlags::Damage)) + for (AuraEffect const* aura : GetAuraEffectsByType(type)) + if ((!excludeAura || excludeAura != aura->GetSpellInfo()->Id) && //Avoid self interrupt of channeled Crowd Control spells like Seduction + aura->GetSpellInfo()->HasAuraInterruptFlag(SpellAuraInterruptFlags::AnyDamageMask)) return true; return false; } -bool Unit::HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel) const +bool Unit::HasBreakableByDamageCrowdControlAura(Unit const* excludeCasterChannel) const { - uint32 excludeAura = 0; - if (Spell* currentChanneledSpell = excludeCasterChannel ? excludeCasterChannel->GetCurrentSpell(CURRENT_CHANNELED_SPELL) : nullptr) - excludeAura = currentChanneledSpell->GetSpellInfo()->Id; //Avoid self interrupt of channeled Crowd Control spells like Seduction + if (!HasInterruptFlag(SpellAuraInterruptFlags::AnyDamageMask)) + return false; - return ( HasBreakableByDamageAuraType(SPELL_AURA_MOD_CONFUSE, excludeAura) - || HasBreakableByDamageAuraType(SPELL_AURA_MOD_FEAR, excludeAura) - || HasBreakableByDamageAuraType(SPELL_AURA_MOD_STUN, excludeAura) - || HasBreakableByDamageAuraType(SPELL_AURA_MOD_ROOT, excludeAura) - || HasBreakableByDamageAuraType(SPELL_AURA_MOD_ROOT_2, excludeAura) - || HasBreakableByDamageAuraType(SPELL_AURA_TRANSFORM, excludeAura)); + uint32 excludeAura = 0; + if (excludeCasterChannel) + if (Spell const* currentChanneledSpell = excludeCasterChannel->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) + excludeAura = currentChanneledSpell->GetSpellInfo()->Id; //Avoid self interrupt of channeled Crowd Control spells like Seduction + + // This function is named after spell attribute it is meant for - SPELL_ATTR6_DO_NOT_CHAIN_TO_CROWD_CONTROLLED_TARGETS + // Not checking aura type is not a mistake here + for (AuraApplication const* aurApp : m_interruptableAuras) + if (!aurApp->IsPositive() + && (!excludeAura || excludeAura != aurApp->GetBase()->GetId()) + && aurApp->GetBase()->GetSpellInfo()->HasAuraInterruptFlag(SpellAuraInterruptFlags::AnyDamageMask)) + return true; + + return false; } /*static*/ void Unit::DealDamageMods(Unit const* attacker, Unit const* victim, uint32& damage, uint32* absorb) diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 7b6b01007..293eda06f 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1084,7 +1084,7 @@ class TC_GAME_API Unit : public WorldObject bool HasAuraTypeWithFamilyFlags(AuraType auraType, uint32 familyName, flag128 familyFlags) const; bool virtual HasSpell(uint32 /*spellID*/) const { return false; } bool HasBreakableByDamageAuraType(AuraType type, uint32 excludeAura = 0) const; - bool HasBreakableByDamageCrowdControlAura(Unit* excludeCasterChannel = nullptr) const; + bool HasBreakableByDamageCrowdControlAura(Unit const* excludeCasterChannel = nullptr) const; bool HasStealthAura() const { return HasAuraType(SPELL_AURA_MOD_STEALTH); } bool HasInvisibilityAura() const { return HasAuraType(SPELL_AURA_MOD_INVISIBILITY); } diff --git a/src/server/game/Spells/SpellDefines.h b/src/server/game/Spells/SpellDefines.h index 2f0915608..bea919354 100644 --- a/src/server/game/Spells/SpellDefines.h +++ b/src/server/game/Spells/SpellDefines.h @@ -110,7 +110,8 @@ enum class SpellAuraInterruptFlags : uint32 Summon = 0x40000000, LeavingCombat = 0x80000000, - NOT_VICTIM = (HostileActionReceived | Damage | NonPeriodicDamage) + NOT_VICTIM = HostileActionReceived | Damage | NonPeriodicDamage, + AnyDamageMask = Damage | NonPeriodicDamage | DamageCancelsScript }; DEFINE_ENUM_FLAG(SpellAuraInterruptFlags); diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index c8620b1b3..0ae1f432e 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -2418,7 +2418,7 @@ SpellCastResult SpellInfo::CheckTarget(WorldObject const* caster, WorldObject co return SPELL_FAILED_TARGETS_DEAD; // check this flag only for implicit targets (chain and area), allow to explicitly target units for spells like Shield of Righteousness - if (implicit && HasAttribute(SPELL_ATTR6_DO_NOT_CHAIN_TO_CROWD_CONTROLLED_TARGETS) && !unitTarget->CanFreeMove()) + if (implicit && HasAttribute(SPELL_ATTR6_DO_NOT_CHAIN_TO_CROWD_CONTROLLED_TARGETS) && unitTarget->HasBreakableByDamageCrowdControlAura()) return SPELL_FAILED_BAD_TARGETS; // checked in Unit::IsValidAttack/AssistTarget, shouldn't be checked for ENTRY targets