Core/Movement: Enable MotionMaster::MovePath for players

This commit is contained in:
Shauren
2026-01-05 14:18:45 +01:00
parent 1f1c859a47
commit 1db1a0e57f
10 changed files with 197 additions and 146 deletions

View File

@@ -131,12 +131,7 @@ namespace FactorySelector
MovementGenerator* SelectMovementGenerator(Unit* unit)
{
MovementGeneratorType type = unit->GetDefaultMovementType();
if (Creature* creature = unit->ToCreature())
if (!creature->GetPlayerMovingMe())
type = creature->GetDefaultMovementType();
MovementGeneratorCreator const* mv_factory = sMovementGeneratorRegistry->GetRegistryItem(type);
MovementGeneratorCreator const* mv_factory = sMovementGeneratorRegistry->GetRegistryItem(unit->GetDefaultMovementType());
return ASSERT_NOTNULL(mv_factory)->Create(unit);
}

View File

@@ -2973,6 +2973,14 @@ bool Creature::CanSwim() const
return false;
}
MovementGeneratorType Creature::GetDefaultMovementType() const
{
if (!GetPlayerMovingMe())
return m_defaultMovementType;
return IDLE_MOTION_TYPE;
}
void Creature::AllLootRemovedFromCorpse()
{
time_t now = GameTime::GetGameTime();

View File

@@ -160,7 +160,7 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
bool CanEnterWater() const override { return (CanSwim() || IsAmphibious()); };
bool CanFly() const override { return (IsFlying() || HasUnitMovementFlag(MOVEMENTFLAG_CAN_FLY)); }
MovementGeneratorType GetDefaultMovementType() const override { return m_defaultMovementType; }
MovementGeneratorType GetDefaultMovementType() const override;
void SetDefaultMovementType(MovementGeneratorType mgt) { m_defaultMovementType = mgt; }
CreatureClassifications GetCreatureClassification() const { return GetCreatureTemplate()->Classification; }

View File

@@ -803,10 +803,6 @@ void MotionMaster::MoveCharge(PathGenerator const& path, float speed /*= SPEED_C
void MotionMaster::MoveKnockbackFrom(Position const& origin, float speedXY, float speedZ, float angle /*= M_PI*/, Movement::SpellEffectExtraData const* spellEffectExtraData /*= nullptr*/)
{
// This function may make players fall below map
if (_owner->GetTypeId() == TYPEID_PLAYER)
return;
if (std::abs(speedXY) < 0.01f && std::abs(speedZ) < 0.01f)
return;
@@ -1144,8 +1140,13 @@ void MotionMaster::MovePath(uint32 pathId, bool repeatable, Optional<Millisecond
TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MovePath: '{}', starts moving over path Id: {} (repeatable: {})",
_owner->GetGUID(), pathId, repeatable ? "YES" : "NO");
Add(new WaypointMovementGenerator<Creature>(pathId, repeatable, duration, speed, speedSelectionMode, waitTimeRangeAtPathEnd,
wanderDistanceAtPathEnds, followPathBackwardsFromEndToStart, exactSplinePath, generatePath, std::move(scriptResult)), MOTION_SLOT_DEFAULT);
if (_owner->GetTypeId() == TYPEID_UNIT)
Add(new WaypointMovementGenerator<Creature>(pathId, repeatable, duration, speed, speedSelectionMode, waitTimeRangeAtPathEnd,
wanderDistanceAtPathEnds, followPathBackwardsFromEndToStart, exactSplinePath, generatePath, std::move(scriptResult)), MOTION_SLOT_DEFAULT);
else
Add(new WaypointMovementGenerator<Player>(pathId, repeatable, duration, speed, speedSelectionMode, waitTimeRangeAtPathEnd,
wanderDistanceAtPathEnds, followPathBackwardsFromEndToStart, exactSplinePath, generatePath, std::move(scriptResult)), MOTION_SLOT_DEFAULT);
}
void MotionMaster::MovePath(WaypointPath const& path, bool repeatable, Optional<Milliseconds> duration /*= {}*/, Optional<float> speed /*= {}*/,
@@ -1157,8 +1158,13 @@ void MotionMaster::MovePath(WaypointPath const& path, bool repeatable, Optional<
{
TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MovePath: '{}', starts moving over path Id: {} (repeatable: {})",
_owner->GetGUID(), path.Id, repeatable ? "YES" : "NO");
Add(new WaypointMovementGenerator<Creature>(path, repeatable, duration, speed, speedSelectionMode, waitTimeRangeAtPathEnd,
wanderDistanceAtPathEnds, followPathBackwardsFromEndToStart, exactSplinePath, generatePath, std::move(scriptResult)), MOTION_SLOT_DEFAULT);
if (_owner->GetTypeId() == TYPEID_UNIT)
Add(new WaypointMovementGenerator<Creature>(path, repeatable, duration, speed, speedSelectionMode, waitTimeRangeAtPathEnd,
wanderDistanceAtPathEnds, followPathBackwardsFromEndToStart, exactSplinePath, generatePath, std::move(scriptResult)), MOTION_SLOT_DEFAULT);
else
Add(new WaypointMovementGenerator<Player>(path, repeatable, duration, speed, speedSelectionMode, waitTimeRangeAtPathEnd,
wanderDistanceAtPathEnds, followPathBackwardsFromEndToStart, exactSplinePath, generatePath, std::move(scriptResult)), MOTION_SLOT_DEFAULT);
}
void MotionMaster::MoveRotate(uint32 id, RotateDirection direction, Optional<Milliseconds> time /*= {}*/,

View File

@@ -30,7 +30,7 @@ struct TaxiPathNodeEntry;
* FlightPathMovementGenerator generates movement of the player for the paths
* and hence generates ground and activities for the player.
*/
class FlightPathMovementGenerator : public MovementGeneratorMedium<Player, FlightPathMovementGenerator>, public PathMovementBase<Player, std::vector<TaxiPathNodeEntry const*>>
class FlightPathMovementGenerator : public MovementGeneratorMedium<Player, FlightPathMovementGenerator>, public PathMovementBase<std::vector<TaxiPathNodeEntry const*>>
{
public:
explicit FlightPathMovementGenerator(Optional<float> speed,

View File

@@ -21,7 +21,7 @@
#include "Define.h"
#include <string>
template<class Entity, class BasePath>
template<class BasePath>
class PathMovementBase
{
public:

View File

@@ -25,6 +25,7 @@
#include "MoveSplineInit.h"
#include "MovementDefines.h"
#include "PathGenerator.h"
#include "Player.h"
#include "Transport.h"
#include "WaypointManager.h"
#include <span>
@@ -34,72 +35,78 @@ namespace
constexpr Milliseconds SEND_NEXT_POINT_EARLY_DELTA = 1500ms;
}
WaypointMovementGenerator<Creature>::WaypointMovementGenerator(uint32 pathId, bool repeating, Optional<Milliseconds> duration, Optional<float> speed,
template <typename T>
WaypointMovementGenerator<T>::WaypointMovementGenerator(uint32 pathId, bool repeating, Optional<Milliseconds> duration, Optional<float> speed,
MovementWalkRunSpeedSelectionMode speedSelectionMode, Optional<std::pair<Milliseconds, Milliseconds>> waitTimeRangeAtPathEnd,
Optional<float> wanderDistanceAtPathEnds, Optional<bool> followPathBackwardsFromEndToStart, Optional<bool> exactSplinePath, bool generatePath,
Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult /*= {}*/)
: PathMovementBase(PathType(std::in_place_type<WaypointPath const*>)), _pathId(pathId), _speed(speed), _speedSelectionMode(speedSelectionMode),
: PathMovementBase(sWaypointMgr->GetPath(pathId)), _speed(speed), _speedSelectionMode(speedSelectionMode),
_waitTimeRangeAtPathEnd(std::move(waitTimeRangeAtPathEnd)), _wanderDistanceAtPathEnds(wanderDistanceAtPathEnds),
_followPathBackwardsFromEndToStart(followPathBackwardsFromEndToStart), _exactSplinePath(exactSplinePath), _repeating(repeating), _generatePath(generatePath),
_moveTimer(0), _nextMoveTime(0), _waypointTransitionSplinePointsIndex(0), _isReturningToStart(false)
{
Mode = MOTION_MODE_DEFAULT;
Priority = MOTION_PRIORITY_NORMAL;
Flags = MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING;
BaseUnitState = UNIT_STATE_ROAMING;
ScriptResult = std::move(scriptResult);
this->Mode = MOTION_MODE_DEFAULT;
this->Priority = MOTION_PRIORITY_NORMAL;
this->Flags = MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING;
this->BaseUnitState = UNIT_STATE_ROAMING;
this->ScriptResult = std::move(scriptResult);
if (duration)
_duration.emplace(*duration);
}
WaypointMovementGenerator<Creature>::WaypointMovementGenerator(WaypointPath const& path, bool repeating, Optional<Milliseconds> duration, Optional<float> speed,
template <typename T>
WaypointMovementGenerator<T>::WaypointMovementGenerator(WaypointPath const& path, bool repeating, Optional<Milliseconds> duration, Optional<float> speed,
MovementWalkRunSpeedSelectionMode speedSelectionMode, Optional<std::pair<Milliseconds, Milliseconds>> waitTimeRangeAtPathEnd,
Optional<float> wanderDistanceAtPathEnds, Optional<bool> followPathBackwardsFromEndToStart, Optional<bool> exactSplinePath, bool generatePath,
Optional<Scripting::v2::ActionResultSetter<MovementStopReason>>&& scriptResult /*= {}*/)
: PathMovementBase(std::make_unique<WaypointPath>(path)), _pathId(0), _speed(speed), _speedSelectionMode(speedSelectionMode),
: PathMovementBase(std::make_unique<WaypointPath>(path)), _speed(speed), _speedSelectionMode(speedSelectionMode),
_waitTimeRangeAtPathEnd(std::move(waitTimeRangeAtPathEnd)), _wanderDistanceAtPathEnds(wanderDistanceAtPathEnds),
_followPathBackwardsFromEndToStart(followPathBackwardsFromEndToStart), _exactSplinePath(exactSplinePath), _repeating(repeating), _generatePath(generatePath),
_moveTimer(0), _nextMoveTime(0), _waypointTransitionSplinePointsIndex(0), _isReturningToStart(false)
{
Mode = MOTION_MODE_DEFAULT;
Priority = MOTION_PRIORITY_NORMAL;
Flags = MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING;
BaseUnitState = UNIT_STATE_ROAMING;
ScriptResult = std::move(scriptResult);
this->Mode = MOTION_MODE_DEFAULT;
this->Priority = MOTION_PRIORITY_NORMAL;
this->Flags = MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING;
this->BaseUnitState = UNIT_STATE_ROAMING;
this->ScriptResult = std::move(scriptResult);
if (duration)
_duration.emplace(*duration);
std::get<std::unique_ptr<WaypointPath>>(_path)->BuildSegments();
std::get<std::unique_ptr<WaypointPath>>(this->_path)->BuildSegments();
}
WaypointMovementGenerator<Creature>::~WaypointMovementGenerator() = default;
template <typename T>
WaypointMovementGenerator<T>::~WaypointMovementGenerator() = default;
MovementGeneratorType WaypointMovementGenerator<Creature>::GetMovementGeneratorType() const
template <typename T>
MovementGeneratorType WaypointMovementGenerator<T>::GetMovementGeneratorType() const
{
return WAYPOINT_MOTION_TYPE;
}
void WaypointMovementGenerator<Creature>::Pause(uint32 timer)
template <typename T>
void WaypointMovementGenerator<T>::Pause(uint32 timer)
{
if (timer)
{
// Don't try to paused an already paused generator
if (HasFlag(MOVEMENTGENERATOR_FLAG_PAUSED))
if (this->HasFlag(MOVEMENTGENERATOR_FLAG_PAUSED))
return;
AddFlag(MOVEMENTGENERATOR_FLAG_TIMED_PAUSED);
this->AddFlag(MOVEMENTGENERATOR_FLAG_TIMED_PAUSED);
_nextMoveTime.Reset(timer);
RemoveFlag(MOVEMENTGENERATOR_FLAG_PAUSED);
this->RemoveFlag(MOVEMENTGENERATOR_FLAG_PAUSED);
}
else
{
AddFlag(MOVEMENTGENERATOR_FLAG_PAUSED);
this->AddFlag(MOVEMENTGENERATOR_FLAG_PAUSED);
_nextMoveTime.Reset(1); // Needed so that Update does not behave as if node was reached
RemoveFlag(MOVEMENTGENERATOR_FLAG_TIMED_PAUSED);
this->RemoveFlag(MOVEMENTGENERATOR_FLAG_TIMED_PAUSED);
}
}
void WaypointMovementGenerator<Creature>::Resume(uint32 overrideTimer)
template <typename T>
void WaypointMovementGenerator<T>::Resume(uint32 overrideTimer)
{
if (overrideTimer)
_nextMoveTime.Reset(overrideTimer);
@@ -107,10 +114,11 @@ void WaypointMovementGenerator<Creature>::Resume(uint32 overrideTimer)
if (_nextMoveTime.Passed())
_nextMoveTime.Reset(1); // Needed so that Update does not behave as if node was reached
RemoveFlag(MOVEMENTGENERATOR_FLAG_PAUSED);
this->RemoveFlag(MOVEMENTGENERATOR_FLAG_PAUSED);
}
bool WaypointMovementGenerator<Creature>::GetResetPosition(Unit* /*owner*/, float& x, float& y, float& z)
template <typename T>
bool WaypointMovementGenerator<T>::GetResetPosition(Unit* /*owner*/, float& x, float& y, float& z)
{
// prevent a crash at empty waypoint path.
WaypointPath const* path = GetPath();
@@ -126,22 +134,15 @@ bool WaypointMovementGenerator<Creature>::GetResetPosition(Unit* /*owner*/, floa
return true;
}
void WaypointMovementGenerator<Creature>::DoInitialize(Creature* owner)
template <typename T>
void WaypointMovementGenerator<T>::DoInitialize(T* owner)
{
RemoveFlag(MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING | MOVEMENTGENERATOR_FLAG_TRANSITORY | MOVEMENTGENERATOR_FLAG_DEACTIVATED);
if (IsLoadedFromDB())
{
if (!_pathId)
_pathId = owner->GetWaypointPathId();
_path = sWaypointMgr->GetPath(_pathId);
}
this->RemoveFlag(MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING | MOVEMENTGENERATOR_FLAG_TRANSITORY | MOVEMENTGENERATOR_FLAG_DEACTIVATED);
WaypointPath const* path = GetPath();
if (!path)
{
TC_LOG_ERROR("sql.sql", "WaypointMovementGenerator::DoInitialize: couldn't load path for creature ({}) (_pathId: {})", owner->GetGUID(), _pathId);
TC_LOG_ERROR("sql.sql", "WaypointMovementGenerator::DoInitialize: couldn't load path for {}", owner->GetGUID());
return;
}
@@ -153,22 +154,24 @@ void WaypointMovementGenerator<Creature>::DoInitialize(Creature* owner)
_nextMoveTime.Reset(1000);
}
void WaypointMovementGenerator<Creature>::DoReset(Creature* owner)
template <typename T>
void WaypointMovementGenerator<T>::DoReset(T* owner)
{
RemoveFlag(MOVEMENTGENERATOR_FLAG_TRANSITORY | MOVEMENTGENERATOR_FLAG_DEACTIVATED);
this->RemoveFlag(MOVEMENTGENERATOR_FLAG_TRANSITORY | MOVEMENTGENERATOR_FLAG_DEACTIVATED);
owner->StopMoving();
if (!HasFlag(MOVEMENTGENERATOR_FLAG_FINALIZED) && _nextMoveTime.Passed())
if (!this->HasFlag(MOVEMENTGENERATOR_FLAG_FINALIZED) && _nextMoveTime.Passed())
_nextMoveTime.Reset(1); // Needed so that Update does not behave as if node was reached
}
bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* owner, uint32 diff)
template <typename T>
bool WaypointMovementGenerator<T>::DoUpdate(T* owner, uint32 diff)
{
if (!owner || !owner->IsAlive())
if (!owner->IsAlive())
return true;
if (HasFlag(MOVEMENTGENERATOR_FLAG_FINALIZED | MOVEMENTGENERATOR_FLAG_PAUSED))
if (this->HasFlag(MOVEMENTGENERATOR_FLAG_FINALIZED | MOVEMENTGENERATOR_FLAG_PAUSED))
return true;
WaypointPath const* path = GetPath();
@@ -180,23 +183,25 @@ bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* owner, uint32 diff)
_duration->Update(diff);
if (_duration->Passed())
{
RemoveFlag(MOVEMENTGENERATOR_FLAG_TRANSITORY);
AddFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED);
AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED);
owner->UpdateCurrentWaypointInfo(0, 0);
SetScriptResult(MovementStopReason::Finished);
if constexpr (std::is_base_of_v<Creature, T>)
owner->UpdateCurrentWaypointInfo(0, 0);
this->RemoveFlag(MOVEMENTGENERATOR_FLAG_TRANSITORY);
this->AddFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED);
this->AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED);
this->SetScriptResult(MovementStopReason::Finished);
return false;
}
}
if (owner->HasUnitState(UNIT_STATE_NOT_MOVE | UNIT_STATE_LOST_CONTROL) || owner->IsMovementPreventedByCasting())
{
AddFlag(MOVEMENTGENERATOR_FLAG_INTERRUPTED);
this->AddFlag(MOVEMENTGENERATOR_FLAG_INTERRUPTED);
owner->StopMoving();
return true;
}
if (HasFlag(MOVEMENTGENERATOR_FLAG_INTERRUPTED))
if (this->HasFlag(MOVEMENTGENERATOR_FLAG_INTERRUPTED))
{
/*
* relaunch only if
@@ -208,21 +213,22 @@ bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* owner, uint32 diff)
*
* TODO: ((_nextMoveTime.Passed() && VALID_MOVEMENT) || (!_nextMoveTime.Passed() && !HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED)))
*/
if (HasFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED) && (_nextMoveTime.Passed() || !HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED)))
if (this->HasFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED) && (_nextMoveTime.Passed() || !this->HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED)))
{
StartMove(owner, true);
return true;
}
RemoveFlag(MOVEMENTGENERATOR_FLAG_INTERRUPTED);
this->RemoveFlag(MOVEMENTGENERATOR_FLAG_INTERRUPTED);
}
// if it's moving
if (!UpdateMoveTimer(diff) && !owner->movespline->Finalized())
{
// set home position at place (every MotionMaster::UpdateMotion)
if (owner->GetTransGUID().IsEmpty())
owner->SetHomePosition(owner->GetPosition());
if constexpr (std::is_base_of_v<Creature, T>)
if (owner->GetTransGUID().IsEmpty())
owner->SetHomePosition(owner->GetPosition());
// handle switching points in continuous segments
if (IsExactSplinePath())
@@ -233,25 +239,28 @@ bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* owner, uint32 diff)
OnArrived(owner);
++_waypointTransitionSplinePointsIndex;
if (ComputeNextNode())
if (CreatureAI* ai = owner->AI())
ai->WaypointStarted(path->Nodes[_currentNode].Id, path->Id);
{
if constexpr (std::is_base_of_v<Creature, T>)
if (CreatureAI* ai = owner->AI())
ai->WaypointStarted(path->Nodes[_currentNode].Id, path->Id);
}
}
}
// relaunch movement if its speed has changed
if (HasFlag(MOVEMENTGENERATOR_FLAG_SPEED_UPDATE_PENDING))
if (this->HasFlag(MOVEMENTGENERATOR_FLAG_SPEED_UPDATE_PENDING))
StartMove(owner, true);
}
else if (!_nextMoveTime.Passed()) // it's not moving, is there a timer?
{
if (UpdateWaitTimer(diff))
{
if (!HasFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED)) // initial movement call
if (!this->HasFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED)) // initial movement call
{
StartMove(owner);
return true;
}
else if (!HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED)) // timer set before node was reached, resume now
else if (!this->HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED)) // timer set before node was reached, resume now
{
StartMove(owner, true);
return true;
@@ -262,10 +271,10 @@ bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* owner, uint32 diff)
}
else // not moving, no timer
{
if (HasFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED) && !HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED))
if (this->HasFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED) && !this->HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED))
{
OnArrived(owner); // hooks and wait timer reset (if necessary)
AddFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED); // signals to future StartMove that it reached a node
this->AddFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED); // signals to future StartMove that it reached a node
}
if (_nextMoveTime.Passed()) // OnArrived might have set a timer
@@ -275,27 +284,36 @@ bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* owner, uint32 diff)
return true;
}
void WaypointMovementGenerator<Creature>::DoDeactivate(Creature* owner)
template <typename T>
void WaypointMovementGenerator<T>::DoDeactivate(T* owner)
{
AddFlag(MOVEMENTGENERATOR_FLAG_DEACTIVATED);
this->AddFlag(MOVEMENTGENERATOR_FLAG_DEACTIVATED);
owner->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
}
void WaypointMovementGenerator<Creature>::DoFinalize(Creature* owner, bool active, bool movementInform)
template <typename T>
void WaypointMovementGenerator<T>::DoFinalize(T* owner, bool active, bool movementInform)
{
AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED);
this->AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED);
if (active)
{
owner->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
// TODO: Research if this modification is needed, which most likely isnt
owner->SetWalk(false);
if constexpr (std::is_base_of_v<Creature, T>)
owner->SetWalk(false);
}
if (movementInform)
SetScriptResult(MovementStopReason::Finished);
this->SetScriptResult(MovementStopReason::Finished);
}
template <typename T>
void WaypointMovementGenerator<T>::MovementInform(T const* /*owner*/) const
{
}
template <>
void WaypointMovementGenerator<Creature>::MovementInform(Creature const* owner) const
{
WaypointPath const* path = GetPath();
@@ -307,7 +325,8 @@ void WaypointMovementGenerator<Creature>::MovementInform(Creature const* owner)
}
}
void WaypointMovementGenerator<Creature>::OnArrived(Creature* owner)
template <typename T>
void WaypointMovementGenerator<T>::OnArrived(T* owner)
{
WaypointPath const* path = GetPath();
if (!path || path->Nodes.empty())
@@ -331,14 +350,15 @@ void WaypointMovementGenerator<Creature>::OnArrived(Creature* owner)
_duration->Update(waitTime); // count the random movement time as part of waypoing movement action
if (_wanderDistanceAtPathEnds)
owner->GetMotionMaster()->MoveRandom(*_wanderDistanceAtPathEnds, waitTime, MOTION_SLOT_ACTIVE);
owner->GetMotionMaster()->MoveRandom(*_wanderDistanceAtPathEnds, waitTime, _speed, _speedSelectionMode, MOTION_SLOT_ACTIVE);
else
_nextMoveTime.Reset(waitTime);
}
MovementInform(owner);
owner->UpdateCurrentWaypointInfo(waypoint.Id, path->Id);
if constexpr (std::is_base_of_v<Creature, T>)
owner->UpdateCurrentWaypointInfo(waypoint.Id, path->Id);
}
namespace
@@ -441,73 +461,91 @@ void CreateMergedPath(Unit const* owner, WaypointPath const* path, uint32 previo
}
}
void WaypointMovementGenerator<Creature>::StartMove(Creature* owner, bool relaunch/* = false*/)
template <typename T>
void WaypointMovementGenerator<T>::StartMove(T* owner, bool relaunch/* = false*/)
{
// sanity checks
if (!owner || !owner->IsAlive() || HasFlag(MOVEMENTGENERATOR_FLAG_FINALIZED) || (relaunch && (HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED) || !HasFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED))))
if (!owner->IsAlive() || this->HasFlag(MOVEMENTGENERATOR_FLAG_FINALIZED)
|| (relaunch && (this->HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED) || !this->HasFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED))))
return;
WaypointPath const* path = GetPath();
if (!path || path->Nodes.empty())
return;
if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting() || (owner->IsFormationLeader() && !owner->IsFormationLeaderMoveAllowed())) // if cannot move OR cannot move because of formation
if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting()) // if cannot move
{
_nextMoveTime.Reset(1000); // delay 1s
return;
}
if constexpr (std::is_base_of_v<Creature, T>)
{
if (owner->IsFormationLeader() && !owner->IsFormationLeaderMoveAllowed()) // if cannot move because of formation
{
_nextMoveTime.Reset(1000); // delay 1s
return;
}
}
bool const transportPath = !owner->GetTransGUID().IsEmpty();
uint32 previousNode = _currentNode;
if (HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED) && HasFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED))
if (this->HasFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED) && this->HasFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED))
{
if (ComputeNextNode())
{
ASSERT(_currentNode < path->Nodes.size(), "WaypointMovementGenerator::StartMove: tried to reference a node id (%u) which is not included in path (%u)", _currentNode, path->Id);
// inform AI
if (CreatureAI* AI = owner->AI())
AI->WaypointStarted(path->Nodes[_currentNode].Id, path->Id);
if constexpr (std::is_base_of_v<Creature, T>)
if (CreatureAI* AI = owner->AI())
AI->WaypointStarted(path->Nodes[_currentNode].Id, path->Id);
}
else
{
WaypointNode const& waypoint = path->Nodes[_currentNode];
float x = waypoint.X;
float y = waypoint.Y;
float z = waypoint.Z;
float o = owner->GetOrientation();
this->AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED);
if (!transportPath)
owner->SetHomePosition(x, y, z, o);
else
if constexpr (std::is_base_of_v<Creature, T>)
{
if (TransportBase* trans = owner->GetTransport())
owner->UpdateCurrentWaypointInfo(0, 0);
WaypointNode const& waypoint = path->Nodes[_currentNode];
float x = waypoint.X;
float y = waypoint.Y;
float z = waypoint.Z;
float o = owner->GetOrientation();
if (!transportPath)
owner->SetHomePosition(x, y, z, o);
else
{
o -= trans->GetTransportOrientation();
owner->SetTransportHomePosition(x, y, z, o);
owner->SetHomePosition(trans->GetPositionWithOffset(owner->GetTransportHomePosition()));
if (TransportBase* trans = owner->GetTransport())
{
o -= trans->GetTransportOrientation();
owner->SetTransportHomePosition(x, y, z, o);
owner->SetHomePosition(trans->GetPositionWithOffset(owner->GetTransportHomePosition()));
}
// else if (vehicle) - this should never happen, vehicle offsets are const
}
// else if (vehicle) - this should never happen, vehicle offsets are const
// inform AI
if (CreatureAI* AI = owner->AI())
AI->WaypointPathEnded(waypoint.Id, path->Id);
}
AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED);
owner->UpdateCurrentWaypointInfo(0, 0);
// inform AI
if (CreatureAI* AI = owner->AI())
AI->WaypointPathEnded(waypoint.Id, path->Id);
SetScriptResult(MovementStopReason::Finished);
this->SetScriptResult(MovementStopReason::Finished);
return;
}
}
else if (!HasFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED))
else if (!this->HasFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED))
{
AddFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED);
this->AddFlag(MOVEMENTGENERATOR_FLAG_INITIALIZED);
// inform AI
if (CreatureAI* AI = owner->AI())
AI->WaypointStarted(path->Nodes[_currentNode].Id, path->Id);
if constexpr (std::is_base_of_v<Creature, T>)
if (CreatureAI* AI = owner->AI())
AI->WaypointStarted(path->Nodes[_currentNode].Id, path->Id);
}
ASSERT(_currentNode < path->Nodes.size(), "WaypointMovementGenerator::StartMove: tried to reference a node id (%u) which is not included in path (%u)", _currentNode, path->Id);
@@ -524,7 +562,7 @@ void WaypointMovementGenerator<Creature>::StartMove(Creature* owner, bool relaun
_waypointTransitionSplinePointsIndex = 0;
RemoveFlag(MOVEMENTGENERATOR_FLAG_TRANSITORY | MOVEMENTGENERATOR_FLAG_INFORM_ENABLED | MOVEMENTGENERATOR_FLAG_TIMED_PAUSED);
this->RemoveFlag(MOVEMENTGENERATOR_FLAG_TRANSITORY | MOVEMENTGENERATOR_FLAG_INFORM_ENABLED | MOVEMENTGENERATOR_FLAG_TIMED_PAUSED);
owner->AddUnitState(UNIT_STATE_ROAMING_MOVE);
@@ -613,10 +651,12 @@ void WaypointMovementGenerator<Creature>::StartMove(Creature* owner, bool relaun
_moveTimer.Reset(duration);
// inform formation
owner->SignalFormationMovement();
if constexpr (std::is_base_of_v<Creature, T>)
owner->SignalFormationMovement();
}
bool WaypointMovementGenerator<Creature>::ComputeNextNode()
template <typename T>
bool WaypointMovementGenerator<T>::ComputeNextNode()
{
WaypointPath const* path = GetPath();
if ((_currentNode == path->Nodes.size() - 1) && !_repeating)
@@ -647,7 +687,8 @@ bool WaypointMovementGenerator<Creature>::ComputeNextNode()
return true;
}
bool WaypointMovementGenerator<Creature>::IsFollowingPathBackwardsFromEndToStart() const
template <typename T>
bool WaypointMovementGenerator<T>::IsFollowingPathBackwardsFromEndToStart() const
{
if (_followPathBackwardsFromEndToStart)
return *_followPathBackwardsFromEndToStart;
@@ -655,7 +696,8 @@ bool WaypointMovementGenerator<Creature>::IsFollowingPathBackwardsFromEndToStart
return GetPath()->Flags.HasFlag(WaypointPathFlags::FollowPathBackwardsFromEndToStart);
}
bool WaypointMovementGenerator<Creature>::IsExactSplinePath() const
template <typename T>
bool WaypointMovementGenerator<T>::IsExactSplinePath() const
{
if (_exactSplinePath)
return *_exactSplinePath;
@@ -663,7 +705,8 @@ bool WaypointMovementGenerator<Creature>::IsExactSplinePath() const
return GetPath()->Flags.HasFlag(WaypointPathFlags::ExactSplinePath);
}
bool WaypointMovementGenerator<Creature>::IsCyclic() const
template <typename T>
bool WaypointMovementGenerator<T>::IsCyclic() const
{
return !IsFollowingPathBackwardsFromEndToStart()
&& IsExactSplinePath()
@@ -671,14 +714,18 @@ bool WaypointMovementGenerator<Creature>::IsCyclic() const
&& GetPath()->ContinuousSegments.size() == 1;
}
std::string WaypointMovementGenerator<Creature>::GetDebugInfo() const
template <typename T>
std::string WaypointMovementGenerator<T>::GetDebugInfo() const
{
return Trinity::StringFormat("{}\n{}",
PathMovementBase::GetDebugInfo(),
MovementGeneratorMedium::GetDebugInfo());
MovementGeneratorMedium<T, WaypointMovementGenerator>::GetDebugInfo());
}
MovementGenerator* WaypointMovementFactory::Create(Unit* /*object*/) const
MovementGenerator* WaypointMovementFactory::Create(Unit* object) const
{
return new WaypointMovementGenerator<Creature>(0, true);
return new WaypointMovementGenerator<Creature>(object->ToCreature()->GetWaypointPathId(), true);
}
template class WaypointMovementGenerator<Creature>;
template class WaypointMovementGenerator<Player>;

View File

@@ -24,15 +24,11 @@
#include "WaypointDefines.h"
#include <variant>
class Creature;
class Unit;
template<class T>
class WaypointMovementGenerator;
template<>
class WaypointMovementGenerator<Creature> : public MovementGeneratorMedium<Creature, WaypointMovementGenerator<Creature>>,
public PathMovementBase<Creature, std::variant<WaypointPath const*, std::unique_ptr<WaypointPath>>>
template <typename T>
class WaypointMovementGenerator : public MovementGeneratorMedium<T, WaypointMovementGenerator<T>>,
public PathMovementBase<std::variant<WaypointPath const*, std::unique_ptr<WaypointPath>>>
{
public:
explicit WaypointMovementGenerator(uint32 pathId, bool repeating, Optional<Milliseconds> duration = {}, Optional<float> speed = {},
@@ -49,25 +45,25 @@ class WaypointMovementGenerator<Creature> : public MovementGeneratorMedium<Creat
MovementGeneratorType GetMovementGeneratorType() const override;
void UnitSpeedChanged() override { AddFlag(MOVEMENTGENERATOR_FLAG_SPEED_UPDATE_PENDING); }
void UnitSpeedChanged() override { this->AddFlag(MOVEMENTGENERATOR_FLAG_SPEED_UPDATE_PENDING); }
void Pause(uint32 timer) override;
void Resume(uint32 overrideTimer) override;
bool GetResetPosition(Unit*, float& x, float& y, float& z) override;
void DoInitialize(Creature*);
void DoReset(Creature*);
bool DoUpdate(Creature*, uint32);
void DoDeactivate(Creature*);
void DoFinalize(Creature*, bool, bool);
void DoInitialize(T* owner);
void DoReset(T* owner);
bool DoUpdate(T* owner, uint32 diff);
void DoDeactivate(T* owner);
void DoFinalize(T* owner, bool active, bool movementInform);
WaypointPath const* GetPath() const { return std::visit([](auto&& path) -> WaypointPath const* { return std::addressof(*path); }, _path); }
std::string GetDebugInfo() const override;
private:
void MovementInform(Creature const*) const;
void OnArrived(Creature*);
void StartMove(Creature*, bool relaunch = false);
void MovementInform(T const* owner) const;
void OnArrived(T* owner);
void StartMove(T* owner, bool relaunch = false);
bool ComputeNextNode();
bool UpdateMoveTimer(uint32 diff) { return UpdateTimer(_moveTimer, diff); }
bool UpdateWaitTimer(uint32 diff) { return UpdateTimer(_nextMoveTime, diff); }
@@ -88,7 +84,6 @@ class WaypointMovementGenerator<Creature> : public MovementGeneratorMedium<Creat
bool IsLoadedFromDB() const { return std::holds_alternative<WaypointPath const*>(_path); }
uint32 _pathId;
Optional<TimeTracker> _duration;
Optional<float> _speed;
MovementWalkRunSpeedSelectionMode _speedSelectionMode;

View File

@@ -171,7 +171,7 @@ public:
return false;
}
if (!pathid)
if (!pathid || !sWaypointMgr->GetPath(pathid))
{
handler->PSendSysMessage("%s%s|r", "|cffff33ff", "No valid path number provided.");
return true;

View File

@@ -782,7 +782,7 @@ class boss_flame_leviathan_overload_device : public CreatureScript
if (Unit* player = me->GetVehicle()->GetPassenger(SEAT_PLAYER))
{
me->GetVehicleBase()->CastSpell(player, SPELL_SMOKE_TRAIL, true);
player->GetMotionMaster()->MoveKnockbackFrom(me->GetVehicleBase()->GetPosition(), 30, 30);
player->KnockbackFrom(me->GetVehicleBase()->GetPosition(), 30, 30);
player->ExitVehicle();
}
}