diff options
author | Shauren <shauren.trinity@gmail.com> | 2024-05-18 11:50:00 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2024-05-18 11:50:00 +0200 |
commit | f80f931e2bee9dbf08c3edee94d0c79dbbb64072 (patch) | |
tree | e83b6b14abb48a34a9baa85139e549e77af25897 | |
parent | 2ad7c7829b17bb9e6e951632e8e0e68f68b9aa44 (diff) |
Core/Spells: Prevent creatures from being able to cast all their spells while moving
Closes #26137
-rw-r--r-- | src/server/game/Movement/MovementDefines.h | 15 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 47 | ||||
-rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 4 |
3 files changed, 38 insertions, 28 deletions
diff --git a/src/server/game/Movement/MovementDefines.h b/src/server/game/Movement/MovementDefines.h index c00cb7a7b88..e2b2dc16e5d 100644 --- a/src/server/game/Movement/MovementDefines.h +++ b/src/server/game/Movement/MovementDefines.h @@ -49,6 +49,21 @@ enum MovementGeneratorType : uint8 MAX_MOTION_TYPE // SKIP }; +constexpr bool CanStopMovementForSpellCasting(MovementGeneratorType type) +{ + // MovementGenerators that don't check Unit::IsMovementPreventedByCasting + switch (type) + { + case HOME_MOTION_TYPE: + case FLIGHT_MOTION_TYPE: + case EFFECT_MOTION_TYPE: // knockbacks, jumps, falling, land/takeoff transitions + return false; + default: + break; + } + return true; +} + enum MovementGeneratorMode : uint8 { MOTION_MODE_DEFAULT = 0, diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 53d14d7ea69..cacc14b1f49 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -43,6 +43,7 @@ #include "Log.h" #include "Loot.h" #include "LootMgr.h" +#include "MotionMaster.h" #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "PathGenerator.h" @@ -3528,16 +3529,9 @@ SpellCastResult Spell::prepare(SpellCastTargets const& targets, AuraEffect const m_casttime = CallScriptCalcCastTimeHandlers(m_spellInfo->CalcCastTime(this)); + SpellCastResult movementResult = SPELL_CAST_OK; if (m_caster->IsUnit() && m_caster->ToUnit()->isMoving()) - { - result = CheckMovement(); - if (result != SPELL_CAST_OK) - { - SendCastResult(result); - finish(result); - return result; - } - } + movementResult = CheckMovement(); // Creatures focus their target when possible if (m_casttime && m_caster->IsCreature() && !m_spellInfo->IsNextMeleeSwingSpell() && !IsAutoRepeat() && !m_caster->ToUnit()->HasUnitFlag(UNIT_FLAG_POSSESSED)) @@ -3550,6 +3544,24 @@ SpellCastResult Spell::prepare(SpellCastTargets const& targets, AuraEffect const m_caster->ToCreature()->SetSpellFocus(this, nullptr); } + if (movementResult != SPELL_CAST_OK) + { + if (m_caster->ToUnit()->IsControlledByPlayer() || !CanStopMovementForSpellCasting(m_caster->ToUnit()->GetMotionMaster()->GetCurrentMovementGeneratorType())) + { + SendCastResult(movementResult); + finish(movementResult); + return movementResult; + } + else + { + // Creatures (not controlled) give priority to spell casting over movement. + // We assume that the casting is always valid and the current movement + // is stopped immediately (because spells are updated before movement, so next Unit::Update would cancel the spell before stopping movement) + // and future attempts are stopped by by Unit::IsMovementPreventedByCasting in movement generators to prevent casting interruption. + m_caster->ToUnit()->StopMoving(); + } + } + CallScriptOnPrecastHandler(); // set timer base at cast time @@ -4278,16 +4290,9 @@ void Spell::update(uint32 difftime) return; } - // check if the player caster has moved before the spell finished - // with the exception of spells affected with SPELL_AURA_CAST_WHILE_WALKING effect + // check if the unit caster has moved before the spell finished if (m_timer != 0 && m_caster->IsUnit() && m_caster->ToUnit()->isMoving() && CheckMovement() != SPELL_CAST_OK) - { - // 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(); - } + cancel(); switch (m_spellState) { @@ -7238,12 +7243,6 @@ SpellCastResult Spell::CheckMovement() const if (IsTriggered()) return SPELL_CAST_OK; - // Creatures (not controlled) give priority to spell casting over movement. - // We assume that the casting is always valid and the current movement - // is stopped by Unit:IsmovementPreventedByCasting to prevent casting interruption. - if (m_caster->IsCreature() && !m_caster->ToCreature()->IsControlledByPlayer()) - return SPELL_CAST_OK; - if (Unit* unitCaster = m_caster->ToUnit()) { if (!unitCaster->CanCastSpellWhileMoving(m_spellInfo)) diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 28a0ead95f3..1ca54fc6b76 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -3917,10 +3917,6 @@ void Spell::EffectKnockBack() if (unitTarget->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED)) return; - // Instantly interrupt non melee spells being cast - if (unitTarget->IsNonMeleeSpellCast(true)) - unitTarget->InterruptNonMeleeSpells(true); - float ratio = 0.1f; float speedxy = float(effectInfo->MiscValue) * ratio; float speedz = float(damage) * ratio; |