diff --git a/Source/Game/Entities/Creature/Creature.cs b/Source/Game/Entities/Creature/Creature.cs index 4de5116ec..97c6d1122 100644 --- a/Source/Game/Entities/Creature/Creature.cs +++ b/Source/Game/Entities/Creature/Creature.cs @@ -1160,7 +1160,7 @@ namespace Game.Entities if (spell != null) { if (spell.GetState() != SpellState.Finished && spell.IsChannelActive()) - if (spell.GetSpellInfo().IsMoveAllowedChannel()) + if (spell.CheckMovement() != SpellCastResult.SpellCastOk) if (HasUnitState(UnitState.Casting)) return true; } diff --git a/Source/Game/Entities/Unit/Unit.Spells.cs b/Source/Game/Entities/Unit/Unit.Spells.cs index 1be859ef6..c09225f5c 100644 --- a/Source/Game/Entities/Unit/Unit.Spells.cs +++ b/Source/Game/Entities/Unit/Unit.Spells.cs @@ -1058,7 +1058,7 @@ namespace Game.Entities spell = m_currentSpells.LookupByKey(CurrentSpellTypes.Channeled); if (spell != null) if (spell.GetState() != SpellState.Finished && spell.IsChannelActive()) - if (spell.GetSpellInfo().IsMoveAllowedChannel()) + if (spell.GetSpellInfo().IsMoveAllowedChannel() || CanCastSpellWhileMoving(spell.GetSpellInfo())) return false; // prohibit movement for all other spell casts diff --git a/Source/Game/Entities/Unit/Unit.cs b/Source/Game/Entities/Unit/Unit.cs index efd81c2d6..0eb592ddb 100644 --- a/Source/Game/Entities/Unit/Unit.cs +++ b/Source/Game/Entities/Unit/Unit.cs @@ -1563,8 +1563,7 @@ namespace Game.Entities // check "realtime" interrupts // don't cancel spells which are affected by a SPELL_AURA_CAST_WHILE_WALKING effect - if (((IsTypeId(TypeId.Player) && ToPlayer().IsMoving()) || IsNonMeleeSpellCast(false, false, true, autoRepeatSpellInfo.Id == 75)) && - !CanCastSpellWhileMoving(autoRepeatSpellInfo)) + if ((IsMoving() && GetCurrentSpell(CurrentSpellTypes.AutoRepeat).CheckMovement() != SpellCastResult.SpellCastOk) || IsNonMeleeSpellCast(false, false, true, autoRepeatSpellInfo.Id == 75)) { // cancel wand shoot if (autoRepeatSpellInfo.Id != 75) diff --git a/Source/Game/Spells/Spell.cs b/Source/Game/Spells/Spell.cs index f8b685586..4978e7859 100644 --- a/Source/Game/Spells/Spell.cs +++ b/Source/Game/Spells/Spell.cs @@ -2511,19 +2511,14 @@ namespace Game.Spells else m_casttime = m_spellInfo.CalcCastTime(this); - // don't allow channeled spells / spells with cast time to be casted while moving - // exception are only channeled spells that have no casttime and dont have movement interrupt flag - // (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 != 0) && m_caster.IsPlayer() && !(m_caster.ToUnit().IsCharmed() && m_caster.ToUnit().GetCharmerGUID().IsCreature()) && m_caster.ToUnit().IsMoving() && - m_spellInfo.InterruptFlags.HasFlag(SpellInterruptFlags.Movement)) && !m_caster.ToUnit().CanCastSpellWhileMoving(m_spellInfo)) + if (m_caster.IsUnit() && m_caster.ToUnit().IsMoving()) { - // 1. Has casttime, 2. Or doesn't have flag to allow movement during channel - if (m_casttime != 0 || !m_spellInfo.IsMoveAllowedChannel()) + result = CheckMovement(); + if (result != SpellCastResult.SpellCastOk) { - SendCastResult(SpellCastResult.Moving); + SendCastResult(result); Finish(false); - return SpellCastResult.Moving; + return result; } } @@ -3284,20 +3279,13 @@ namespace Game.Spells // check if the player caster has moved before the spell finished // with the exception of spells affected with SPELL_AURA_CAST_WHILE_WALKING effect - if ((m_caster.IsTypeId(TypeId.Player) && m_timer != 0) && - m_caster.ToUnit().IsMoving() && (m_spellInfo.InterruptFlags.HasFlag(SpellInterruptFlags.Movement)) && - (!m_spellInfo.HasEffect(SpellEffectName.Stuck) || !m_caster.ToUnit().HasUnitMovementFlag(MovementFlag.FallingFar)) && - !m_caster.ToUnit().CanCastSpellWhileMoving(m_spellInfo)) + if (m_timer != 0 && m_caster.IsUnit() && m_caster.ToUnit().IsMoving() && CheckMovement() != SpellCastResult.SpellCastOk) { - // don't cancel for melee, autorepeat, triggered and instant spells - if (!m_spellInfo.IsNextMeleeSwingSpell() && !IsAutoRepeat() && !IsTriggered() && !(IsChannelActive() && m_spellInfo.IsMoveAllowedChannel())) - { - // if charmed by creature, trust the AI not to cheat and allow the cast to proceed - // @todo this is a hack, "creature" movesplines don't differentiate turning/moving right now - // however, checking what type of movement the spline is for every single spline would be really expensive - if (!m_caster.ToUnit().GetCharmerGUID().IsCreature()) - Cancel(); - } + // if charmed by creature, trust the AI not to cheat and allow the cast to proceed + // @todo this is a hack, "creature" movesplines don't differentiate turning/moving right now + // however, checking what type of movement the spline is for every single spline would be really expensive + if (!m_caster.ToUnit().GetCharmerGUID().IsCreature()) + Cancel(); } switch (m_spellState) @@ -4768,19 +4756,6 @@ namespace Game.Spells return SpellCastResult.AffectingCombat; } - // cancel autorepeat spells if cast start when moving - // (not wand currently autorepeat cast delayed to moving stop anyway in spell update code) - // Do not cancel spells which are affected by a SPELL_AURA_CAST_WHILE_WALKING effect - if (unitCaster.IsPlayer() && unitCaster.ToPlayer().IsMoving() - && (!unitCaster.IsCharmed() || !unitCaster.GetCharmerGUID().IsCreature()) - && !unitCaster.CanCastSpellWhileMoving(m_spellInfo)) - { - // skip stuck spell to allow use it in falling case and apply spell limitations at movement - if ((!unitCaster.HasUnitMovementFlag(MovementFlag.FallingFar) || !m_spellInfo.HasEffect(SpellEffectName.Stuck)) && - (IsAutoRepeat() || m_spellInfo.HasAuraInterruptFlag(SpellAuraInterruptFlags.Standing))) - return SpellCastResult.Moving; - } - // Check vehicle flags if (!Convert.ToBoolean(_triggeredCastFlags & TriggerCastFlags.IgnoreCasterMountedOrOnVehicle)) { @@ -7801,6 +7776,33 @@ namespace Game.Spells List m_loadedScripts = new(); + public SpellCastResult CheckMovement() + { + if (IsTriggered()) + return SpellCastResult.SpellCastOk; + + Unit unitCaster = m_caster.ToUnit(); + if (unitCaster != null) + { + if (!unitCaster.CanCastSpellWhileMoving(m_spellInfo)) + { + if (m_casttime != 0) + { + if (m_spellInfo.InterruptFlags.HasFlag(SpellInterruptFlags.Movement)) + return SpellCastResult.Moving; + } + else + { + // only fail channeled casts if they are instant but cannot be channeled while moving + if (m_spellInfo.IsChanneled() && !m_spellInfo.IsMoveAllowedChannel()) + return SpellCastResult.Moving; + } + } + } + + return SpellCastResult.SpellCastOk; + } + int CalculateDamage(SpellEffectInfo spellEffectInfo, Unit target) { return CalculateDamage(spellEffectInfo, target, out _);