aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp67
-rw-r--r--src/server/game/Spells/Spell.cpp11
-rw-r--r--src/server/game/Spells/SpellDefines.h22
-rw-r--r--src/server/game/Spells/SpellEffects.cpp4
-rw-r--r--src/server/game/Spells/SpellInfo.cpp14
-rw-r--r--src/server/game/Spells/SpellInfo.h4
-rw-r--r--src/server/game/Spells/SpellMgr.cpp2
7 files changed, 85 insertions, 39 deletions
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index b81fb679c2d..3b4ef528d69 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -764,16 +764,11 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam
else
victim->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Damage, 0);
- // interrupt spells with SPELL_INTERRUPT_FLAG_ABORT_ON_DMG on absorbed damage (no dots)
- if (!damage && damagetype != DOT && cleanDamage && cleanDamage->absorbed_damage)
- if (victim != this && victim->GetTypeId() == TYPEID_PLAYER)
- if (Spell* spell = victim->m_currentSpells[CURRENT_GENERIC_SPELL])
- if (spell->getState() == SPELL_STATE_PREPARING)
- {
- uint32 interruptFlags = spell->m_spellInfo->InterruptFlags;
- if ((interruptFlags & SPELL_INTERRUPT_FLAG_ABORT_ON_DMG) != 0)
+ if (!damage && damagetype != DOT && cleanDamage && cleanDamage->absorbed_damage)
+ if (victim != this && victim->GetTypeId() == TYPEID_PLAYER)
+ if (Spell* spell = victim->m_currentSpells[CURRENT_GENERIC_SPELL])
+ if (spell->getState() == SPELL_STATE_PREPARING && spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::DamageAbsorb))
victim->InterruptNonMeleeSpells(false);
- }
// We're going to call functions which can modify content of the list during iteration over it's elements
// Let's copy the list so we can prevent iterator invalidation
@@ -920,25 +915,57 @@ uint32 Unit::DealDamage(Unit* victim, uint32 damage, CleanDamage const* cleanDam
}
}
- if (damagetype != NODAMAGE && damage)
+ if (damagetype != NODAMAGE)
{
- if (victim != this && victim->GetTypeId() == TYPEID_PLAYER && // does not support creature push_back
- (!spellProto || !spellProto->HasAttribute(SPELL_ATTR7_NO_PUSHBACK_ON_DAMAGE)))
+ if (victim != this
+ && (!spellProto || !spellProto->HasAttribute(SPELL_ATTR7_NO_PUSHBACK_ON_DAMAGE)))
{
if (damagetype != DOT)
+ {
if (Spell* spell = victim->m_currentSpells[CURRENT_GENERIC_SPELL])
+ {
if (spell->getState() == SPELL_STATE_PREPARING)
{
- uint32 interruptFlags = spell->m_spellInfo->InterruptFlags;
- if (interruptFlags & SPELL_INTERRUPT_FLAG_ABORT_ON_DMG)
+ auto isCastInterrupted = [&]()
+ {
+ if (!damage)
+ return spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::ZeroDamageCancels);
+
+ if ((victim->IsPlayer() && spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::DamageCancelsPlayerOnly)))
+ return true;
+
+ if (spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::DamageCancels))
+ return true;
+
+ return false;
+ };
+
+ auto isCastDelayed = [&]()
+ {
+ if (!damage)
+ return false;
+
+ if ((victim->IsPlayer() && spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::DamagePushbackPlayerOnly)))
+ return true;
+
+ if (spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::DamagePushback))
+ return true;
+
+ return false;
+ };
+
+ if (isCastInterrupted())
victim->InterruptNonMeleeSpells(false);
- else if (interruptFlags & SPELL_INTERRUPT_FLAG_PUSH_BACK)
+ else if (isCastDelayed())
spell->Delayed();
}
+ }
- if (Spell* spell = victim->m_currentSpells[CURRENT_CHANNELED_SPELL])
- if (spell->getState() == SPELL_STATE_CASTING && spell->m_spellInfo->HasChannelInterruptFlag(SpellAuraInterruptFlags::DamageChannelDuration) && damagetype != DOT)
- spell->DelayedChannel();
+ if (damage && victim->IsPlayer())
+ if (Spell* spell = victim->m_currentSpells[CURRENT_CHANNELED_SPELL])
+ if (spell->getState() == SPELL_STATE_CASTING && spell->m_spellInfo->HasChannelInterruptFlag(SpellAuraInterruptFlags::DamageChannelDuration))
+ spell->DelayedChannel();
+ }
}
}
@@ -8213,6 +8240,10 @@ void Unit::SetInCombatState(bool PvP, Unit* enemy)
aurApp->GetBase()->CallScriptEnterLeaveCombatHandlers(aurApp, true);
}
+ if (Spell* spell = m_currentSpells[CURRENT_GENERIC_SPELL])
+ if (spell->getState() == SPELL_STATE_PREPARING && spell->m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::Combat))
+ InterruptNonMeleeSpells(false);
+
RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::EnteringCombat);
ProcSkillsAndAuras(enemy, PROC_FLAG_ENTER_COMBAT, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr);
}
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 0cd419ee9e7..73f50ba6cb2 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -3016,7 +3016,7 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const* triggered
// (even if they are interrupted on moving, spells with almost immediate effect get to have their effect processed before movement interrupter kicks in)
// don't cancel spells which are affected by a SPELL_AURA_CAST_WHILE_WALKING effect
if (((m_spellInfo->IsChanneled() || m_casttime) && m_caster->GetTypeId() == TYPEID_PLAYER && !(m_caster->IsCharmed() && m_caster->GetCharmerGUID().IsCreature()) && m_caster->isMoving() &&
- m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT) && !m_caster->HasAuraTypeWithAffectMask(SPELL_AURA_CAST_WHILE_WALKING, m_spellInfo))
+ m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::Movement)) && !m_caster->HasAuraTypeWithAffectMask(SPELL_AURA_CAST_WHILE_WALKING, m_spellInfo))
{
// 1. Has casttime, 2. Or doesn't have flag to allow movement during channel
if (m_casttime || !m_spellInfo->IsMoveAllowedChannel())
@@ -3637,7 +3637,7 @@ void Spell::update(uint32 difftime)
// with the exception of spells affected with SPELL_AURA_CAST_WHILE_WALKING effect
SpellEffectInfo const* effect = m_spellInfo->GetEffect(EFFECT_0);
if ((m_caster->GetTypeId() == TYPEID_PLAYER && m_timer != 0) &&
- m_caster->isMoving() && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT) &&
+ m_caster->isMoving() && (m_spellInfo->InterruptFlags.HasFlag(SpellInterruptFlags::Movement)) &&
((effect && effect->Effect != SPELL_EFFECT_STUCK) || !m_caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING_FAR)) &&
!m_caster->HasAuraTypeWithAffectMask(SPELL_AURA_CAST_WHILE_WALKING, m_spellInfo))
{
@@ -6873,10 +6873,6 @@ void Spell::Delayed() // only called in DealDamage()
if (isDelayableNoMore()) // Spells may only be delayed twice
return;
- // spells not loosing casting time (slam, dynamites, bombs..)
- //if (!(m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_DAMAGE))
- // return;
-
//check pushback reduce
int32 delaytime = 500; // spellcasting delay is normally 500ms
int32 delayReduce = 100; // must be initialized to 100 for percent modifiers
@@ -7163,8 +7159,7 @@ bool Spell::IsChannelActive() const
bool Spell::IsAutoActionResetSpell() const
{
- /// @todo changed SPELL_INTERRUPT_FLAG_AUTOATTACK -> SPELL_INTERRUPT_FLAG_INTERRUPT to fix compile - is this check correct at all?
- if (IsTriggered() || !(m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT))
+ if (IsTriggered())
return false;
if (!m_casttime && m_spellInfo->HasAttribute(SPELL_ATTR6_NOT_RESET_SWING_IF_INSTANT))
diff --git a/src/server/game/Spells/SpellDefines.h b/src/server/game/Spells/SpellDefines.h
index cf26e4a7c05..c330b2b1aa8 100644
--- a/src/server/game/Spells/SpellDefines.h
+++ b/src/server/game/Spells/SpellDefines.h
@@ -34,16 +34,24 @@ namespace WorldPackets
}
}
-enum SpellInterruptFlags : uint32
+enum class SpellInterruptFlags : uint32
{
- SPELL_INTERRUPT_FLAG_MOVEMENT = 0x01, // why need this for instant?
- SPELL_INTERRUPT_FLAG_PUSH_BACK = 0x02, // push back
- SPELL_INTERRUPT_FLAG_UNK3 = 0x04, // any info?
- SPELL_INTERRUPT_FLAG_INTERRUPT = 0x08, // interrupt
- SPELL_INTERRUPT_FLAG_ABORT_ON_DMG = 0x10 // _complete_ interrupt on direct damage
- //SPELL_INTERRUPT_UNK = 0x20 // unk, 564 of 727 spells having this spell start with "Glyph"
+ None = 0,
+ Movement = 0x00000001,
+ DamagePushbackPlayerOnly = 0x00000002,
+ Stun = 0x00000004, // useless, even spells without it get interrupted
+ Combat = 0x00000008,
+ DamageCancelsPlayerOnly = 0x00000010,
+ MeleeCombat = 0x00000020, // NYI
+ Immunity = 0x00000040, // NYI
+ DamageAbsorb = 0x00000080,
+ ZeroDamageCancels = 0x00000100,
+ DamagePushback = 0x00000200,
+ DamageCancels = 0x00000400
};
+DEFINE_ENUM_FLAG(SpellInterruptFlags);
+
enum class SpellAuraInterruptFlags : uint32
{
None = 0,
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index bc784f91830..336de46e33a 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -2967,9 +2967,7 @@ void Spell::EffectInterruptCast(SpellEffIndex effIndex)
// check if we can interrupt spell
if ((spell->getState() == SPELL_STATE_CASTING
|| (spell->getState() == SPELL_STATE_PREPARING && spell->GetCastTime() > 0.0f))
- && (curSpellInfo->PreventionType & SPELL_PREVENTION_TYPE_SILENCE)
- && ((i == CURRENT_GENERIC_SPELL && curSpellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT)
- || (i == CURRENT_CHANNELED_SPELL)))
+ && curSpellInfo->CanBeInterrupted(m_caster, unitTarget))
{
if (m_originalCaster)
{
diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp
index f8cabac4d00..0a73ed4ad1f 100644
--- a/src/server/game/Spells/SpellInfo.cpp
+++ b/src/server/game/Spells/SpellInfo.cpp
@@ -1212,7 +1212,7 @@ SpellInfo::SpellInfo(SpellNameEntry const* spellName, ::Difficulty difficulty, S
// SpellInterruptsEntry
if (SpellInterruptsEntry const* _interrupt = data.Interrupts)
{
- InterruptFlags = _interrupt->InterruptFlags;
+ InterruptFlags = SpellInterruptFlags(_interrupt->InterruptFlags);
AuraInterruptFlags = SpellAuraInterruptFlags(_interrupt->AuraInterruptFlags[0]);
AuraInterruptFlags2 = SpellAuraInterruptFlags2(_interrupt->AuraInterruptFlags[1]);
ChannelInterruptFlags = SpellAuraInterruptFlags(_interrupt->ChannelInterruptFlags[0]);
@@ -1360,6 +1360,18 @@ bool SpellInfo::HasTargetType(::Targets target) const
return false;
}
+bool SpellInfo::CanBeInterrupted(Unit* interruptCaster, Unit* interruptTarget) const
+{
+ return HasAttribute(SPELL_ATTR7_CAN_ALWAYS_BE_INTERRUPTED)
+ || HasChannelInterruptFlag(SpellAuraInterruptFlags::Damage | SpellAuraInterruptFlags::EnteringCombat)
+ || (interruptTarget->IsPlayer() && InterruptFlags.HasFlag(SpellInterruptFlags::DamageCancelsPlayerOnly))
+ || InterruptFlags.HasFlag(SpellInterruptFlags::DamageCancels)
+ || interruptCaster->HasAuraTypeWithMiscvalue(SPELL_AURA_ALLOW_INTERRUPT_SPELL, Id)
+ || (!(interruptTarget->GetMechanicImmunityMask() & (1 << MECHANIC_INTERRUPT))
+ && !interruptTarget->HasAuraTypeWithAffectMask(SPELL_AURA_PREVENT_INTERRUPT, this)
+ && PreventionType & SPELL_PREVENTION_TYPE_SILENCE);
+}
+
bool SpellInfo::HasAnyAuraInterruptFlag() const
{
return AuraInterruptFlags != SpellAuraInterruptFlags::None || AuraInterruptFlags2 != SpellAuraInterruptFlags2::None;
diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h
index f453b11cb76..62dbbe00bbc 100644
--- a/src/server/game/Spells/SpellInfo.h
+++ b/src/server/game/Spells/SpellInfo.h
@@ -414,7 +414,7 @@ class TC_GAME_API SpellInfo
uint32 CategoryRecoveryTime = 0;
uint32 StartRecoveryCategory = 0;
uint32 StartRecoveryTime = 0;
- uint32 InterruptFlags = 0;
+ EnumFlag<SpellInterruptFlags> InterruptFlags = SpellInterruptFlags::None;
EnumFlag<SpellAuraInterruptFlags> AuraInterruptFlags = SpellAuraInterruptFlags::None;
EnumFlag<SpellAuraInterruptFlags2> AuraInterruptFlags2 = SpellAuraInterruptFlags2::None;
EnumFlag<SpellAuraInterruptFlags> ChannelInterruptFlags = SpellAuraInterruptFlags::None;
@@ -498,6 +498,8 @@ class TC_GAME_API SpellInfo
bool HasAttribute(SpellAttr14 attribute) const { return !!(AttributesEx14 & attribute); }
bool HasAttribute(SpellCustomAttributes customAttribute) const { return !!(AttributesCu & customAttribute); }
+ bool CanBeInterrupted(Unit* interruptCaster, Unit* interruptTarget) const;
+
bool HasAnyAuraInterruptFlag() const;
bool HasAuraInterruptFlag(SpellAuraInterruptFlags flag) const { return AuraInterruptFlags.HasFlag(flag); }
bool HasAuraInterruptFlag(SpellAuraInterruptFlags2 flag) const { return AuraInterruptFlags2.HasFlag(flag); }
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index 78459cbf0d3..5b7f34d737f 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -2827,7 +2827,7 @@ void SpellMgr::LoadSpellInfoServerside()
spellInfo.CategoryRecoveryTime = fields[36].GetUInt32();
spellInfo.StartRecoveryCategory = fields[37].GetUInt32();
spellInfo.StartRecoveryTime = fields[38].GetUInt32();
- spellInfo.InterruptFlags = fields[39].GetUInt32();
+ spellInfo.InterruptFlags = SpellInterruptFlags(fields[39].GetUInt32());
spellInfo.AuraInterruptFlags = SpellAuraInterruptFlags(fields[40].GetUInt32());
spellInfo.AuraInterruptFlags2 = SpellAuraInterruptFlags2(fields[41].GetUInt32());
spellInfo.ChannelInterruptFlags = SpellAuraInterruptFlags(fields[42].GetUInt32());