aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp17
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp5
-rw-r--r--src/server/game/Movement/MovementDefines.h15
-rw-r--r--src/server/game/Spells/Spell.cpp71
-rw-r--r--src/server/game/Spells/Spell.h1
-rw-r--r--src/server/game/Spells/SpellEffects.cpp4
6 files changed, 67 insertions, 46 deletions
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index 900ae1b9d16..5f730c9c996 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -3246,21 +3246,10 @@ void Creature::DoNotReacquireSpellFocusTarget()
bool Creature::IsMovementPreventedByCasting() const
{
- // first check if currently a movement allowed channel is active and we're not casting
- if (Spell* spell = m_currentSpells[CURRENT_CHANNELED_SPELL])
- {
- if (spell->getState() != SPELL_STATE_FINISHED && spell->IsChannelActive())
- if (spell->GetSpellInfo()->IsMoveAllowedChannel())
- return false;
- }
-
- if (HasSpellFocus())
- return true;
-
- if (HasUnitState(UNIT_STATE_CASTING))
- return true;
+ if (!Unit::IsMovementPreventedByCasting() && !HasSpellFocus())
+ return false;
- return false;
+ return true;
}
void Creature::StartPickPocketRefillTimer()
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 43c3446daf9..d412b619be7 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -3123,6 +3123,11 @@ bool Unit::IsMovementPreventedByCasting() const
if (!HasUnitState(UNIT_STATE_CASTING))
return false;
+ if (Spell* spell = m_currentSpells[CURRENT_GENERIC_SPELL])
+ if (spell->getState() == SPELL_STATE_FINISHED ||
+ !(spell->m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT))
+ return false;
+
// channeled spells during channel stage (after the initial cast timer) allow movement with a specific spell attribute
if (Spell* spell = m_currentSpells[CURRENT_CHANNELED_SPELL])
if (spell->getState() != SPELL_STATE_FINISHED && spell->IsChannelActive())
diff --git a/src/server/game/Movement/MovementDefines.h b/src/server/game/Movement/MovementDefines.h
index fd4cc0095f6..f4d35ec55d8 100644
--- a/src/server/game/Movement/MovementDefines.h
+++ b/src/server/game/Movement/MovementDefines.h
@@ -47,6 +47,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 f59e27da9c1..eaa4f1fad65 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -36,6 +36,7 @@
#include "Item.h"
#include "Log.h"
#include "LootMgr.h"
+#include "MotionMaster.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "Opcodes.h"
@@ -3148,19 +3149,9 @@ SpellCastResult Spell::prepare(SpellCastTargets const& targets, AuraEffect const
else
m_casttime = m_spellInfo->CalcCastTime(this);
- // don't allow channeled spells / spells with cast time to be cast while moving
- // 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)
- if ((m_spellInfo->IsChanneled() || m_casttime) && m_caster->GetTypeId() == TYPEID_PLAYER && !(m_caster->ToPlayer()->IsCharmed() && m_caster->ToPlayer()->GetCharmerGUID().IsCreature()) && m_caster->ToPlayer()->isMoving() && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT))
- {
- // 1. Has casttime, 2. Or doesn't have flag to allow movement during channel
- if (m_casttime || !m_spellInfo->IsMoveAllowedChannel())
- {
- SendCastResult(SPELL_FAILED_MOVING);
- finish(false);
- return SPELL_FAILED_MOVING;
- }
- }
+ SpellCastResult movementResult = SPELL_CAST_OK;
+ if (m_caster->IsUnit() && m_caster->ToUnit()->isMoving())
+ 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))
@@ -3173,6 +3164,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();
+ }
+ }
+
// set timer base at cast time
ReSetTimer();
@@ -3805,21 +3814,9 @@ void Spell::update(uint32 difftime)
return;
}
- // check if the player caster has moved before the spell finished
- if (m_caster->GetTypeId() == TYPEID_PLAYER && m_timer != 0 &&
- m_caster->ToPlayer()->isMoving() && m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT &&
- (!m_spellInfo->HasEffect(SPELL_EFFECT_STUCK) || !m_caster->ToPlayer()->HasUnitMovementFlag(MOVEMENTFLAG_FALLING_FAR)))
- {
- // 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->ToPlayer()->GetCharmerGUID().IsCreature())
- cancel();
- }
- }
+ // 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)
+ cancel();
switch (m_spellState)
{
@@ -6396,6 +6393,24 @@ int32 Spell::CalculateDamage(SpellEffectInfo const& spellEffectInfo) const
return m_caster->CalculateSpellDamage(spellEffectInfo, m_spellValue->EffectBasePoints + spellEffectInfo.EffectIndex);
}
+SpellCastResult Spell::CheckMovement() const
+{
+ if (IsTriggered())
+ return SPELL_CAST_OK;
+
+ if (getState() == SPELL_STATE_PREPARING)
+ {
+ if (m_casttime > 0)
+ if (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT)
+ return SPELL_FAILED_MOVING;
+ }
+ else if (getState() == SPELL_STATE_CASTING)
+ if (!m_spellInfo->IsMoveAllowedChannel())
+ return SPELL_FAILED_MOVING;
+
+ return SPELL_CAST_OK;
+}
+
bool Spell::CanAutoCast(Unit* target)
{
if (!target)
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index 496dd23e698..29b5fb3b105 100644
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -338,6 +338,7 @@ class TC_GAME_API Spell
SpellCastResult CheckPower() const;
SpellCastResult CheckRuneCost(uint32 runeCostID) const;
SpellCastResult CheckCasterAuras(uint32* param1) const;
+ SpellCastResult CheckMovement() const;
bool CheckSpellCancelsAuraEffect(AuraType auraType, uint32* param1) const;
bool CheckSpellCancelsCharm(uint32* param1) const;
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index b4cf72a7ac5..70eafbcb172 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -4309,10 +4309,6 @@ void Spell::EffectKnockBack()
if (unitTarget->HasUnitState(UNIT_STATE_ROOT))
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;