diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 67 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 11 | ||||
-rw-r--r-- | src/server/game/Spells/SpellDefines.h | 22 | ||||
-rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 4 | ||||
-rw-r--r-- | src/server/game/Spells/SpellInfo.cpp | 14 | ||||
-rw-r--r-- | src/server/game/Spells/SpellInfo.h | 4 | ||||
-rw-r--r-- | src/server/game/Spells/SpellMgr.cpp | 2 |
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()); |