summaryrefslogtreecommitdiff
path: root/src/server/game/Movement
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/game/Movement')
-rw-r--r--src/server/game/Movement/MotionMaster.cpp37
-rw-r--r--src/server/game/Movement/MotionMaster.h2
-rw-r--r--src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp158
-rw-r--r--src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.h21
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>