diff --git a/Source/Framework/Constants/Spells/SpellAuraConst.cs b/Source/Framework/Constants/Spells/SpellAuraConst.cs index 959f289eb..6c0825763 100644 --- a/Source/Framework/Constants/Spells/SpellAuraConst.cs +++ b/Source/Framework/Constants/Spells/SpellAuraConst.cs @@ -398,7 +398,7 @@ namespace Framework.Constants ModifyFallDamagePct = 374, ModPossessPet = 375, ModCurrencyGainFromSource = 376, // NYI - CastWhileWalking2 = 377, // NYI + CastWhileWalkingAll = 377, // Enables casting all spells while moving Unk378 = 378, ModManaRegenPct = 379, Unk380 = 380, diff --git a/Source/Game/Entities/Unit/Unit.Spells.cs b/Source/Game/Entities/Unit/Unit.Spells.cs index 89f5f744c..b2ff8fc3d 100644 --- a/Source/Game/Entities/Unit/Unit.Spells.cs +++ b/Source/Game/Entities/Unit/Unit.Spells.cs @@ -1051,9 +1051,14 @@ namespace Game.Entities if (!HasUnitState(UnitState.Casting)) return false; + Spell spell = GetCurrentSpell(CurrentSpellTypes.Generic); + if (spell != null) + if (CanCastSpellWhileMoving(spell.GetSpellInfo())) + return false; + // channeled spells during channel stage (after the initial cast timer) allow movement with a specific spell attribute - Spell spell = m_currentSpells.LookupByKey(CurrentSpellTypes.Channeled); - if (spell) + spell = m_currentSpells.LookupByKey(CurrentSpellTypes.Channeled); + if (spell != null) if (spell.GetState() != SpellState.Finished && spell.IsChannelActive()) if (spell.GetSpellInfo().IsMoveAllowedChannel()) return false; @@ -1406,6 +1411,21 @@ namespace Game.Entities return false; } + public bool CanCastSpellWhileMoving(SpellInfo spellInfo) + { + if (HasAuraTypeWithAffectMask(AuraType.CastWhileWalking, spellInfo)) + return true; + + if (HasAuraType(AuraType.CastWhileWalkingAll)) + return true; + + foreach (uint label in spellInfo.Labels) + if (HasAuraTypeWithMiscvalue(AuraType.CastWhileWalkingBySpellLabel, (int)label)) + return true; + + return false; + } + public static void ProcSkillsAndAuras(Unit actor, Unit actionTarget, ProcFlags typeMaskActor, ProcFlags typeMaskActionTarget, ProcFlagsSpellType spellTypeMask, ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask, Spell spell, DamageInfo damageInfo, HealInfo healInfo) { WeaponAttackType attType = damageInfo != null ? damageInfo.GetAttackType() : WeaponAttackType.BaseAttack; @@ -2777,14 +2797,14 @@ namespace Game.Entities return dispelList; } + bool IsInterruptFlagIgnoredForSpell(SpellAuraInterruptFlags flag, Unit unit, SpellInfo spellInfo) + { + return flag == SpellAuraInterruptFlags.Moving && unit.CanCastSpellWhileMoving(spellInfo); + } bool IsInterruptFlagIgnoredForSpell(SpellAuraInterruptFlags2 flag, Unit unit, SpellInfo spellInfo) { return false; } - bool IsInterruptFlagIgnoredForSpell(SpellAuraInterruptFlags flag, Unit unit, SpellInfo spellInfo) - { - return flag == SpellAuraInterruptFlags.Moving && unit.HasAuraTypeWithAffectMask(AuraType.CastWhileWalking, spellInfo); - } public void RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags flag, uint except = 0) { diff --git a/Source/Game/Entities/Unit/Unit.cs b/Source/Game/Entities/Unit/Unit.cs index 1727d4a43..a617509fb 100644 --- a/Source/Game/Entities/Unit/Unit.cs +++ b/Source/Game/Entities/Unit/Unit.cs @@ -1465,7 +1465,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)) && - !HasAuraTypeWithAffectMask(AuraType.CastWhileWalking, autoRepeatSpellInfo)) + !CanCastSpellWhileMoving(autoRepeatSpellInfo)) { // cancel wand shoot if (autoRepeatSpellInfo.Id != 75) diff --git a/Source/Game/Spells/Spell.cs b/Source/Game/Spells/Spell.cs index a8b4d3d37..f29cf67ce 100644 --- a/Source/Game/Spells/Spell.cs +++ b/Source/Game/Spells/Spell.cs @@ -2332,8 +2332,8 @@ namespace Game.Spells // exception are only channeled spells that have no casttime and SPELL_ATTR5_CAN_CHANNEL_WHEN_MOVING // (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.ToPlayer().IsCharmed() && m_caster.ToPlayer().GetCharmerGUID().IsCreature()) && m_caster.ToPlayer().IsMoving() && - m_spellInfo.InterruptFlags.HasFlag(SpellInterruptFlags.Movement)) && !m_caster.ToPlayer().HasAuraTypeWithAffectMask(AuraType.CastWhileWalking, m_spellInfo)) + 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)) { // 1. Has casttime, 2. Or doesn't have flag to allow movement during channel if (m_casttime != 0 || !m_spellInfo.IsMoveAllowedChannel()) @@ -3059,9 +3059,9 @@ 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.ToPlayer().IsMoving() && (m_spellInfo.InterruptFlags.HasFlag(SpellInterruptFlags.Movement)) && - (m_spellInfo.HasEffect(SpellEffectName.Stuck) || !m_caster.ToPlayer().HasUnitMovementFlag(MovementFlag.FallingFar)) && - !m_caster.ToPlayer().HasAuraTypeWithAffectMask(AuraType.CastWhileWalking, m_spellInfo)) + 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)) { // don't cancel for melee, autorepeat, triggered and instant spells if (!m_spellInfo.IsNextMeleeSwingSpell() && !IsAutoRepeat() && !IsTriggered() && !(IsChannelActive() && m_spellInfo.IsMoveAllowedChannel())) @@ -3069,7 +3069,7 @@ namespace Game.Spells // 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.ToPlayer().GetCharmerGUID().IsCreature()) + if (!m_caster.ToUnit().GetCharmerGUID().IsCreature()) Cancel(); } } @@ -4500,7 +4500,9 @@ namespace Game.Spells // 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.HasAuraTypeWithAffectMask(AuraType.CastWhileWalking, m_spellInfo)) + 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)) &&