From 70fbaefa8eaaa2a100eb1c3ce9b7ed3cc62baf99 Mon Sep 17 00:00:00 2001 From: UltraNix <80540499+UltraNix@users.noreply.github.com> Date: Mon, 15 Nov 2021 14:39:36 +0100 Subject: [PATCH] fix(Core/Movement): creatures should not cast while moving (#9141) - Closes #8843 --- src/server/game/Entities/Creature/Creature.h | 2 +- src/server/game/Entities/Unit/Unit.cpp | 24 +++++++++++++++++ src/server/game/Entities/Unit/Unit.h | 2 ++ .../ConfusedMovementGenerator.cpp | 5 +++- .../EscortMovementGenerator.cpp | 4 +-- .../FleeingMovementGenerator.cpp | 12 +++++---- .../PointMovementGenerator.cpp | 6 ++--- .../RandomMovementGenerator.cpp | 21 ++------------- .../WaypointMovementGenerator.cpp | 27 +++++-------------- src/server/game/Spells/SpellInfo.cpp | 2 +- 10 files changed, 53 insertions(+), 52 deletions(-) diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 62ee4f7e1..9f1983fdc 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -359,7 +359,7 @@ public: void SetTarget(ObjectGuid guid = ObjectGuid::Empty) override; void FocusTarget(Spell const* focusSpell, WorldObject const* target); void ReleaseFocus(Spell const* focusSpell); - bool IsMovementPreventedByCasting() const; + bool IsMovementPreventedByCasting() const override; // Part of Evade mechanics [[nodiscard]] time_t GetLastDamagedTime() const; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index fde97ec6e..fa8c17b34 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -3683,6 +3683,30 @@ int32 Unit::GetCurrentSpellCastTime(uint32 spell_id) const return 0; } +bool Unit::IsMovementPreventedByCasting() const +{ + // can always move when not casting + if (!HasUnitState(UNIT_STATE_CASTING)) + { + 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()) + { + if (spell->GetSpellInfo()->IsMoveAllowedChannel()) + { + return false; + } + } + } + + // prohibit movement for all other spell casts + return true; +} + bool Unit::CanMoveDuringChannel() const { if (Spell* spell = m_currentSpells[CURRENT_CHANNELED_SPELL]) diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index a34b83edf..b820dd455 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -2145,6 +2145,8 @@ public: [[nodiscard]] Spell* FindCurrentSpellBySpellId(uint32 spell_id) const; [[nodiscard]] int32 GetCurrentSpellCastTime(uint32 spell_id) const; + virtual bool IsMovementPreventedByCasting() const; + ObjectGuid m_SummonSlot[MAX_SUMMON_SLOT]; ObjectGuid m_ObjectSlot[MAX_GAMEOBJECT_SLOT]; diff --git a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp index eb08c58dd..f4162d12b 100644 --- a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp @@ -121,8 +121,11 @@ void ConfusedMovementGenerator::DoReset(T* unit) template bool ConfusedMovementGenerator::DoUpdate(T* unit, uint32 diff) { - if (unit->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED)) + if (unit->HasUnitState(UNIT_STATE_NOT_MOVE) || unit->IsMovementPreventedByCasting()) + { + unit->StopMoving(); return true; + } if (i_nextMoveTime.Passed()) { diff --git a/src/server/game/Movement/MovementGenerators/EscortMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/EscortMovementGenerator.cpp index f7ea048de..42d48857e 100644 --- a/src/server/game/Movement/MovementGenerators/EscortMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/EscortMovementGenerator.cpp @@ -50,9 +50,9 @@ bool EscortMovementGenerator::DoUpdate(T* unit, uint32 /*diff*/) if (!unit) return false; - if (unit->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED)) + if (unit->HasUnitState(UNIT_STATE_NOT_MOVE) || unit->IsMovementPreventedByCasting()) { - unit->ClearUnitState(UNIT_STATE_ROAMING_MOVE); + unit->StopMoving(); return true; } diff --git a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp index 7b4c02aa7..9175c3133 100644 --- a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp @@ -33,8 +33,10 @@ void FleeingMovementGenerator::_setTargetLocation(T* owner) if (!owner) return; - if (owner->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED)) + if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting()) + { return; + } if (!_setMoveData(owner)) return; @@ -346,9 +348,9 @@ bool FleeingMovementGenerator::DoUpdate(T* owner, uint32 time_diff) if (!owner || !owner->IsAlive()) return false; - if (owner->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED)) + if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting()) { - owner->ClearUnitState(UNIT_STATE_FLEEING_MOVE); + owner->StopMoving(); return true; } @@ -385,9 +387,9 @@ bool TimedFleeingMovementGenerator::Update(Unit* owner, uint32 time_diff) if (!owner->IsAlive()) return false; - if (owner->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED)) + if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting()) { - owner->ClearUnitState(UNIT_STATE_FLEEING_MOVE); + owner->StopMoving(); return true; } diff --git a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp index 824a28cb2..982f2c34a 100644 --- a/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/PointMovementGenerator.cpp @@ -28,7 +28,7 @@ template void PointMovementGenerator::DoInitialize(T* unit) { - if (unit->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED)) + if (unit->HasUnitState(UNIT_STATE_NOT_MOVE) || unit->IsMovementPreventedByCasting()) { // the next line is to ensure that a new spline is created in DoUpdate() once the unit is no longer rooted/stunned // todo: rename this flag to something more appropriate since it is set to true even without speed change now. @@ -98,9 +98,9 @@ bool PointMovementGenerator::DoUpdate(T* unit, uint32 /*diff*/) if (!unit) return false; - if (unit->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED)) + if (unit->HasUnitState(UNIT_STATE_NOT_MOVE) || unit->IsMovementPreventedByCasting()) { - unit->ClearUnitState(UNIT_STATE_ROAMING_MOVE); + unit->StopMoving(); return true; } diff --git a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp index 34217f37a..8f4b300a1 100644 --- a/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/RandomMovementGenerator.cpp @@ -260,10 +260,10 @@ void RandomMovementGenerator::DoFinalize(Creature* creature) template<> bool RandomMovementGenerator::DoUpdate(Creature* creature, const uint32 diff) { - if (creature->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED | UNIT_STATE_DISTRACTED)) + if (creature->HasUnitState(UNIT_STATE_NOT_MOVE) || creature->IsMovementPreventedByCasting()) { _nextMoveTime.Reset(0); // Expire the timer - creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE); + creature->StopMoving(); return true; } @@ -275,23 +275,6 @@ bool RandomMovementGenerator::DoUpdate(Creature* creature, const uint3 return true; } - // prevent movement while casting spells with cast time or channel time - if (creature->HasUnitState(UNIT_STATE_CASTING)) - { - bool stop = true; - if (Spell* spell = creature->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) - if (!(spell->GetSpellInfo()->ChannelInterruptFlags & (AURA_INTERRUPT_FLAG_MOVE | AURA_INTERRUPT_FLAG_TURNING)) && !(spell->GetSpellInfo()->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT)) - stop = false; - - if (stop) - { - if (!creature->IsStopped()) - creature->StopMoving(); - - return true; - } - } - if (creature->movespline->Finalized()) { _nextMoveTime.Update(diff); diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp index dc67e55b8..2412bb0c2 100644 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp @@ -145,8 +145,10 @@ bool WaypointMovementGenerator::StartMove(Creature* creature) } // xinef: do not initialize motion if we got stunned in movementinform - if (creature->HasUnitState(UNIT_STATE_NOT_MOVE)) + if (creature->HasUnitState(UNIT_STATE_NOT_MOVE) || creature->IsMovementPreventedByCasting()) + { return true; + } WaypointData const* node = i_path->at(i_currentNode); @@ -204,11 +206,13 @@ bool WaypointMovementGenerator::DoUpdate(Creature* creature, uint32 di { // Waypoint movement can be switched on/off // This is quite handy for escort quests and other stuff - if (creature->HasUnitState(UNIT_STATE_NOT_MOVE)) + if (creature->HasUnitState(UNIT_STATE_NOT_MOVE) || creature->IsMovementPreventedByCasting()) { - creature->ClearUnitState(UNIT_STATE_ROAMING_MOVE); + creature->StopMoving(); + Stop(1000); return true; } + // prevent a crash at empty waypoint path. if (!i_path || i_path->empty()) return false; @@ -217,23 +221,6 @@ bool WaypointMovementGenerator::DoUpdate(Creature* creature, uint32 di if (!creature->IsAlive()) return false; - // prevent movement while casting spells with cast time or channel time - if (creature->HasUnitState(UNIT_STATE_CASTING)) - { - bool stop = true; - if (Spell* spell = creature->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) - if (!(spell->GetSpellInfo()->ChannelInterruptFlags & (AURA_INTERRUPT_FLAG_MOVE | AURA_INTERRUPT_FLAG_TURNING)) && !(spell->GetSpellInfo()->InterruptFlags & SPELL_INTERRUPT_FLAG_MOVEMENT)) - stop = false; - - if (stop) - { - Stop(1000); - if (!creature->IsStopped()) - creature->StopMoving(); - return true; - } - } - if (Stopped()) { if (CanMove(diff)) diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index f6ce6b6d7..4a1272d6a 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -1243,7 +1243,7 @@ bool SpellInfo::IsChanneled() const bool SpellInfo::IsMoveAllowedChannel() const { - return IsChanneled() && (HasAttribute(SPELL_ATTR5_ALLOW_ACTION_DURING_CHANNEL) || (!(ChannelInterruptFlags & (AURA_INTERRUPT_FLAG_MOVE | AURA_INTERRUPT_FLAG_TURNING)))); + return IsChanneled() && HasAttribute(SPELL_ATTR5_ALLOW_ACTION_DURING_CHANNEL); } bool SpellInfo::NeedsComboPoints() const