diff options
Diffstat (limited to 'src/server/game/Movement')
4 files changed, 172 insertions, 46 deletions
diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp index 8189fd5058..2b2aba6ef9 100644 --- a/src/server/game/Movement/MotionMaster.cpp +++ b/src/server/game/Movement/MotionMaster.cpp @@ -310,12 +310,29 @@ void MotionMaster::MoveConfused() /** * @brief Force the unit to chase this target. Doesn't work with UNIT_FLAG_DISABLE_MOVE */ -void MotionMaster::MoveChase(Unit* target, std::optional<ChaseRange> dist, std::optional<ChaseAngle> angle) +void MotionMaster::MoveChase(Unit* target, std::optional<ChaseRange> dist, std::optional<ChaseAngle> angle) { // ignore movement request if target not exist if (!target || target == _owner || _owner->HasUnitFlag(UNIT_FLAG_DISABLE_MOVE)) return; + if (GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE) + { + if (_owner->IsPlayer()) + { + ChaseMovementGenerator<Player>* gen = (ChaseMovementGenerator<Player>*)top(); + gen->SetOffsetAndAngle(dist, angle); + gen->SetNewTarget(target); + } + else + { + ChaseMovementGenerator<Creature>* gen = (ChaseMovementGenerator<Creature>*)top(); + gen->SetOffsetAndAngle(dist, angle); + gen->SetNewTarget(target); + } + return; + } + //_owner->ClearUnitState(UNIT_STATE_FOLLOW); if (_owner->IsPlayer()) { @@ -331,6 +348,24 @@ void MotionMaster::MoveChase(Unit* target, std::optional<ChaseRange> dist, std: } } +void MotionMaster::DistanceYourself(float dist) +{ + if (GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE) + { + if (_owner->IsPlayer()) + { + ChaseMovementGenerator<Player>* gen = (ChaseMovementGenerator<Player>*)top(); + gen->DistanceYourself((Player*)_owner, dist); + } + else + { + ChaseMovementGenerator<Creature>* gen = (ChaseMovementGenerator<Creature>*)top(); + gen->DistanceYourself((Creature*)_owner, dist); + } + return; + } +} + void MotionMaster::MoveBackwards(Unit* target, float dist) { if (!target) diff --git a/src/server/game/Movement/MotionMaster.h b/src/server/game/Movement/MotionMaster.h index 248263d7ba..0fcf5abae8 100644 --- a/src/server/game/Movement/MotionMaster.h +++ b/src/server/game/Movement/MotionMaster.h @@ -247,6 +247,8 @@ public: void ReinitializeMovement(); bool GetDestination(float& x, float& y, float& z); + + void DistanceYourself(float range); private: void Mutate(MovementGenerator* m, MovementSlot slot); // use Move* functions instead diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp index 76fb0840a4..4dfc688282 100644 --- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp @@ -63,6 +63,81 @@ bool ChaseMovementGenerator<T>::PositionOkay(T* owner, Unit* target, Optional<fl } template<class T> +void ChaseMovementGenerator<T>::SetOffsetAndAngle(std::optional<ChaseRange> dist, std::optional<ChaseAngle> angle) +{ + _range = dist; + _angle = angle; + _lastTargetPosition.reset(); +} + +template<class T> +void ChaseMovementGenerator<T>::SetNewTarget(Unit* target) +{ + i_target.link(target, this); + _lastTargetPosition.reset(); +} + +template<class T> +void ChaseMovementGenerator<T>::DistanceYourself(T* owner, float distance) +{ + // make a new path if we have to... + if (!i_path) + i_path = std::make_unique<PathGenerator>(owner); + + float x, y, z; + i_target->GetNearPoint(owner, x, y, z, owner->GetBoundaryRadius(), distance, i_target->GetAngle(owner)); + if (DispatchSplineToPosition(owner, x, y, z, false, false, 0.f, false, false)) + { + m_currentMode = CHASE_MODE_DISTANCING; + if constexpr (!std::is_same_v<T, Player>) + { + owner->AI()->DistancingStarted(); + } + } +} + +template<class T> +bool ChaseMovementGenerator<T>::DispatchSplineToPosition(T* owner, float x, float y, float z, bool walk, bool cutPath, float maxTarget, bool forceDest, bool target) +{ + Creature* cOwner = owner->ToCreature(); + + if (owner->IsHovering()) + owner->UpdateAllowedPositionZ(x, y, z); + + bool success = i_path->CalculatePath(x, y, z, forceDest); + if (!success || i_path->GetPathType() & PATHFIND_NOPATH) + { + if (cOwner) + { + cOwner->SetCannotReachTarget(i_target.getTarget()->GetGUID()); + } + + owner->StopMoving(); + return true; + } + + if (cutPath) + i_path->ShortenPathUntilDist(G3D::Vector3(x, y, z), maxTarget); + + if (cOwner) + { + cOwner->SetCannotReachTarget(); + } + + owner->AddUnitState(UNIT_STATE_CHASE_MOVE); + i_recalculateTravel = true; + + Movement::MoveSplineInit init(owner); + init.MovebyPath(i_path->GetPath()); + if (target) + init.SetFacing(i_target.getTarget()); + init.SetWalk(walk); + init.Launch(); + + return false; +} + +template<class T> bool ChaseMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff) { if (!i_target.isValid() || !i_target->IsInWorld() || !owner->IsInMap(i_target.getTarget())) @@ -71,6 +146,13 @@ bool ChaseMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff) if (!owner || !owner->IsAlive()) return false; + if (owner->HasUnitState(UNIT_STATE_NO_COMBAT_MOVEMENT)) // script paused combat movement + { + owner->StopMoving(); + _lastTargetPosition.reset(); + return true; + } + Creature* cOwner = owner->ToCreature(); bool isStoppedBecauseOfCasting = cOwner && cOwner->IsMovementPreventedByCasting(); @@ -243,53 +325,23 @@ bool ChaseMovementGenerator<T>::DoUpdate(T* owner, uint32 time_diff) shortenPath = false; } - if (owner->IsHovering()) - owner->UpdateAllowedPositionZ(x, y, z); - - bool success = i_path->CalculatePath(x, y, z, forceDest); - if (!success || i_path->GetPathType() & PATHFIND_NOPATH) - { - if (cOwner) - { - cOwner->SetCannotReachTarget(target->GetGUID()); - } - - owner->StopMoving(); - return true; - } - - if (shortenPath) - i_path->ShortenPathUntilDist(G3D::Vector3(x, y, z), maxTarget); - - if (cOwner) - { - cOwner->SetCannotReachTarget(); - } - bool walk = false; if (cOwner && !cOwner->IsPet()) { switch (cOwner->GetMovementTemplate().GetChase()) { - case CreatureChaseMovementType::CanWalk: - walk = owner->IsWalking(); - break; - case CreatureChaseMovementType::AlwaysWalk: - walk = true; - break; - default: - break; + case CreatureChaseMovementType::CanWalk: + walk = owner->IsWalking(); + break; + case CreatureChaseMovementType::AlwaysWalk: + walk = true; + break; + default: + break; } } - owner->AddUnitState(UNIT_STATE_CHASE_MOVE); - i_recalculateTravel = true; - - Movement::MoveSplineInit init(owner); - init.MovebyPath(i_path->GetPath()); - init.SetFacing(target); - init.SetWalk(walk); - init.Launch(); + DispatchSplineToPosition(owner, x, y, z, walk, shortenPath, maxTarget, forceDest, true); } } @@ -339,9 +391,24 @@ void ChaseMovementGenerator<T>::MovementInform(T* owner) if (!owner->IsCreature()) return; - // Pass back the GUIDLow of the target. If it is pet's owner then PetAI will handle - if (CreatureAI* AI = owner->ToCreature()->AI()) - AI->MovementInform(CHASE_MOTION_TYPE, i_target.getTarget()->GetGUID().GetCounter()); + switch (m_currentMode) + { + default: + { + // Pass back the GUIDLow of the target. If it is pet's owner then PetAI will handle + if (CreatureAI* AI = owner->ToCreature()->AI()) + AI->MovementInform(CHASE_MOTION_TYPE, i_target.getTarget()->GetGUID().GetCounter()); + break; + } + case CHASE_MODE_DISTANCING: + { + if (CreatureAI* AI = owner->ToCreature()->AI()) + AI->DistancingEnded(); + break; + } + } + + m_currentMode = CHASE_MODE_NORMAL; } //-----------------------------------------------// @@ -604,6 +671,13 @@ template bool ChaseMovementGenerator<Player>::DoUpdate(Player*, uint32); template bool ChaseMovementGenerator<Creature>::DoUpdate(Creature*, uint32); template void ChaseMovementGenerator<Unit>::MovementInform(Unit*); +template void ChaseMovementGenerator<Creature>::SetOffsetAndAngle(std::optional<ChaseRange>, std::optional<ChaseAngle>); +template void ChaseMovementGenerator<Creature>::SetNewTarget(Unit*); +template void ChaseMovementGenerator<Creature>::DistanceYourself(Creature*, float); +template void ChaseMovementGenerator<Player>::SetOffsetAndAngle(std::optional<ChaseRange>, std::optional<ChaseAngle>); +template void ChaseMovementGenerator<Player>::SetNewTarget(Unit*); +template void ChaseMovementGenerator<Player>::DistanceYourself(Player*, float); + template void FollowMovementGenerator<Player>::DoInitialize(Player*); template void FollowMovementGenerator<Creature>::DoInitialize(Creature*); template void FollowMovementGenerator<Player>::DoFinalize(Player*); diff --git a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h index 82ba2df472..e5e87f845b 100644 --- a/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h @@ -34,12 +34,20 @@ protected: FollowerReference i_target; }; +enum ChaseMovementMode +{ + CHASE_MODE_NORMAL, // chasing target + CHASE_MODE_BACKPEDAL, // collision movement + CHASE_MODE_DISTANCING, // running away from melee + CHASE_MODE_FANNING, // mob collision movement +}; + template<class T> class ChaseMovementGenerator : public MovementGeneratorMedium<T, ChaseMovementGenerator<T>>, public TargetedMovementGeneratorBase { public: ChaseMovementGenerator(Unit* target, Optional<ChaseRange> range = {}, Optional<ChaseAngle> angle = {}) - : TargetedMovementGeneratorBase(target), i_leashExtensionTimer(5000), i_path(nullptr), i_recheckDistance(0), i_recalculateTravel(true), _range(range), _angle(angle) {} + : TargetedMovementGeneratorBase(target), i_leashExtensionTimer(5000), i_path(nullptr), i_recheckDistance(0), i_recalculateTravel(true), _range(range), _angle(angle), m_currentMode(CHASE_MODE_NORMAL) {} ~ChaseMovementGenerator() { } MovementGeneratorType GetMovementGeneratorType() { return CHASE_MOTION_TYPE; } @@ -58,6 +66,11 @@ public: bool EnableWalking() const { return false; } bool HasLostTarget(Unit* unit) const { return unit->GetVictim() != this->GetTarget(); } + void SetOffsetAndAngle(std::optional<ChaseRange> dist, std::optional<ChaseAngle> angle); + void SetNewTarget(Unit* target); + + void DistanceYourself(T* owner, float distance); + bool DispatchSplineToPosition(T* owner, float x, float y, float z, bool walk, bool cutPath, float maxTarget, bool forceDest, bool target = false); private: TimeTrackerSmall i_leashExtensionTimer; std::unique_ptr<PathGenerator> i_path; @@ -65,10 +78,12 @@ private: bool i_recalculateTravel; Optional<Position> _lastTargetPosition; - Optional<ChaseRange> const _range; - Optional<ChaseAngle> const _angle; + Optional<ChaseRange> _range; + Optional<ChaseAngle> _angle; bool _movingTowards = true; bool _mutualChase = true; + + ChaseMovementMode m_currentMode; }; template<class T> |