Core/Movement: New waypoint movement features

* Allow going backwards on a repeatable waypoint path (instead of going directly to first point)
* Allow triggering random movement on path ends
* Max duration of waypoint movement
* Skipping mmap usage
* Forced speed for whole path
* Forced run/walk for whole path
This commit is contained in:
Shauren
2023-03-07 20:13:28 +01:00
parent 705d5701bf
commit cf2e0e2faa
5 changed files with 131 additions and 20 deletions

View File

@@ -596,12 +596,12 @@ void MotionMaster::MoveTargetedHome()
}
}
void MotionMaster::MoveRandom(float wanderDistance, Optional<Milliseconds> duration)
void MotionMaster::MoveRandom(float wanderDistance, Optional<Milliseconds> duration, MovementSlot slot /*= MOTION_SLOT_DEFAULT*/)
{
if (_owner->GetTypeId() == TYPEID_UNIT)
{
TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MoveRandom: '{}', started random movement (spawnDist: {})", _owner->GetGUID().ToString(), wanderDistance);
Add(new RandomMovementGenerator<Creature>(wanderDistance, duration), MOTION_SLOT_DEFAULT);
Add(new RandomMovementGenerator<Creature>(wanderDistance, duration), slot);
}
}
@@ -1075,19 +1075,27 @@ void MotionMaster::MoveDistract(uint32 timer, float orientation)
Add(new DistractMovementGenerator(timer, orientation));
}
void MotionMaster::MovePath(uint32 pathId, bool repeatable)
void MotionMaster::MovePath(uint32 pathId, bool repeatable, Optional<Milliseconds> duration, Optional<float> speed,
MovementWalkRunSpeedSelectionMode speedSelectionMode, Optional<std::pair<Milliseconds, Milliseconds>> waitTimeRangeAtPathEnd,
Optional<float> wanderDistanceAtPathEnds, bool followPathBackwardsFromEndToStart, bool generatePath)
{
if (!pathId)
return;
TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MovePath: '{}', starts moving over path Id: {} (repeatable: {})", _owner->GetGUID().ToString(), pathId, repeatable ? "YES" : "NO");
Add(new WaypointMovementGenerator<Creature>(pathId, repeatable), MOTION_SLOT_DEFAULT);
TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MovePath: '{}', starts moving over path Id: {} (repeatable: {})",
_owner->GetGUID().ToString(), pathId, repeatable ? "YES" : "NO");
Add(new WaypointMovementGenerator<Creature>(pathId, repeatable, duration, speed, speedSelectionMode, waitTimeRangeAtPathEnd,
wanderDistanceAtPathEnds, followPathBackwardsFromEndToStart, generatePath), MOTION_SLOT_DEFAULT);
}
void MotionMaster::MovePath(WaypointPath& path, bool repeatable)
void MotionMaster::MovePath(WaypointPath const& path, bool repeatable, Optional<Milliseconds> duration, Optional<float> speed,
MovementWalkRunSpeedSelectionMode speedSelectionMode, Optional<std::pair<Milliseconds, Milliseconds>> waitTimeRangeAtPathEnd,
Optional<float> wanderDistanceAtPathEnds, bool followPathBackwardsFromEndToStart, bool generatePath)
{
TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MovePath: '{}', starts moving over path Id: {} (repeatable: {})", _owner->GetGUID().ToString(), path.id, repeatable ? "YES" : "NO");
Add(new WaypointMovementGenerator<Creature>(path, repeatable), MOTION_SLOT_DEFAULT);
TC_LOG_DEBUG("movement.motionmaster", "MotionMaster::MovePath: '{}', starts moving over path Id: {} (repeatable: {})",
_owner->GetGUID().ToString(), path.id, repeatable ? "YES" : "NO");
Add(new WaypointMovementGenerator<Creature>(path, repeatable, duration, speed, speedSelectionMode, waitTimeRangeAtPathEnd,
wanderDistanceAtPathEnds, followPathBackwardsFromEndToStart, generatePath), MOTION_SLOT_DEFAULT);
}
void MotionMaster::MoveRotate(uint32 id, uint32 time, RotateDirection direction)

View File

@@ -156,7 +156,7 @@ class TC_GAME_API MotionMaster
void MoveIdle();
void MoveTargetedHome();
void MoveRandom(float wanderDistance = 0.0f, Optional<Milliseconds> duration = {});
void MoveRandom(float wanderDistance = 0.0f, Optional<Milliseconds> duration = {}, MovementSlot slot = MOTION_SLOT_DEFAULT);
void MoveFollow(Unit* target, float dist, ChaseAngle angle, Optional<Milliseconds> duration = {}, MovementSlot slot = MOTION_SLOT_ACTIVE);
void MoveChase(Unit* target, Optional<ChaseRange> dist = {}, Optional<ChaseAngle> angle = {});
void MoveChase(Unit* target, float dist, float angle) { MoveChase(target, ChaseRange(dist), ChaseAngle(angle)); }
@@ -194,8 +194,14 @@ class TC_GAME_API MotionMaster
void MoveSeekAssistanceDistract(uint32 timer);
void MoveTaxiFlight(uint32 path, uint32 pathnode);
void MoveDistract(uint32 time, float orientation);
void MovePath(uint32 pathId, bool repeatable);
void MovePath(WaypointPath& path, bool repeatable);
void MovePath(uint32 pathId, bool repeatable, Optional<Milliseconds> duration = {}, Optional<float> speed = {},
MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode::Default,
Optional<std::pair<Milliseconds, Milliseconds>> waitTimeRangeAtPathEnd = {}, Optional<float> wanderDistanceAtPathEnds = {},
bool followPathBackwardsFromEndToStart = false, bool generatePath = true);
void MovePath(WaypointPath const& path, bool repeatable, Optional<Milliseconds> duration = {}, Optional<float> speed = {},
MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode::Default,
Optional<std::pair<Milliseconds, Milliseconds>> waitTimeRangeAtPathEnd = {}, Optional<float> wanderDistanceAtPathEnds = {},
bool followPathBackwardsFromEndToStart = false, bool generatePath = true);
void MoveRotate(uint32 id, uint32 time, RotateDirection direction);
void MoveFormation(Unit* leader, float range, float angle, uint32 point1, uint32 point2);

View File

@@ -57,5 +57,5 @@ WaypointMovementFactory::WaypointMovementFactory() : MovementGeneratorCreator(WA
MovementGenerator* WaypointMovementFactory::Create(Unit* /*object*/) const
{
return new WaypointMovementGenerator<Creature>();
return new WaypointMovementGenerator<Creature>(0, true);
}

View File

@@ -21,6 +21,7 @@
#include "Errors.h"
#include "Log.h"
#include "Map.h"
#include "MotionMaster.h"
#include "MovementDefines.h"
#include "MoveSpline.h"
#include "MoveSplineInit.h"
@@ -29,15 +30,29 @@
#include "WaypointManager.h"
#include <sstream>
WaypointMovementGenerator<Creature>::WaypointMovementGenerator(uint32 pathId, bool repeating) : _nextMoveTime(0), _pathId(pathId), _repeating(repeating), _loadedFromDB(true)
WaypointMovementGenerator<Creature>::WaypointMovementGenerator(uint32 pathId, bool repeating, Optional<Milliseconds> duration, Optional<float> speed,
MovementWalkRunSpeedSelectionMode speedSelectionMode, Optional<std::pair<Milliseconds, Milliseconds>> waitTimeRangeAtPathEnd,
Optional<float> wanderDistanceAtPathEnds, bool followPathBackwardsFromEndToStart, bool generatePath)
: _nextMoveTime(0), _pathId(pathId), _repeating(repeating), _loadedFromDB(true),
_speed(speed), _speedSelectionMode(speedSelectionMode), _waitTimeRangeAtPathEnd(std::move(waitTimeRangeAtPathEnd)),
_wanderDistanceAtPathEnds(wanderDistanceAtPathEnds), _followPathBackwardsFromEndToStart(followPathBackwardsFromEndToStart), _isReturningToStart(false),
_generatePath(generatePath)
{
Mode = MOTION_MODE_DEFAULT;
Priority = MOTION_PRIORITY_NORMAL;
Flags = MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING;
BaseUnitState = UNIT_STATE_ROAMING;
if (duration)
_duration.emplace(*duration);
}
WaypointMovementGenerator<Creature>::WaypointMovementGenerator(WaypointPath& path, bool repeating) : _nextMoveTime(0), _pathId(0), _repeating(repeating), _loadedFromDB(false)
WaypointMovementGenerator<Creature>::WaypointMovementGenerator(WaypointPath const& path, bool repeating, Optional<Milliseconds> duration, Optional<float> speed,
MovementWalkRunSpeedSelectionMode speedSelectionMode, Optional<std::pair<Milliseconds, Milliseconds>> waitTimeRangeAtPathEnd,
Optional<float> wanderDistanceAtPathEnds, bool followPathBackwardsFromEndToStart, bool generatePath)
: _nextMoveTime(0), _pathId(0), _repeating(repeating), _loadedFromDB(false),
_speed(speed), _speedSelectionMode(speedSelectionMode), _waitTimeRangeAtPathEnd(std::move(waitTimeRangeAtPathEnd)),
_wanderDistanceAtPathEnds(wanderDistanceAtPathEnds), _followPathBackwardsFromEndToStart(followPathBackwardsFromEndToStart), _isReturningToStart(false),
_generatePath(generatePath)
{
_path = &path;
@@ -45,8 +60,12 @@ WaypointMovementGenerator<Creature>::WaypointMovementGenerator(WaypointPath& pat
Priority = MOTION_PRIORITY_NORMAL;
Flags = MOVEMENTGENERATOR_FLAG_INITIALIZATION_PENDING;
BaseUnitState = UNIT_STATE_ROAMING;
if (duration)
_duration.emplace(*duration);
}
WaypointMovementGenerator<Creature>::~WaypointMovementGenerator() = default;
MovementGeneratorType WaypointMovementGenerator<Creature>::GetMovementGeneratorType() const
{
return WAYPOINT_MOTION_TYPE;
@@ -139,6 +158,17 @@ bool WaypointMovementGenerator<Creature>::DoUpdate(Creature* owner, uint32 diff)
if (HasFlag(MOVEMENTGENERATOR_FLAG_FINALIZED | MOVEMENTGENERATOR_FLAG_PAUSED) || !_path || _path->nodes.empty())
return true;
if (_duration)
{
_duration->Update(diff);
if (_duration->Passed())
{
RemoveFlag(MOVEMENTGENERATOR_FLAG_TRANSITORY);
AddFlag(MOVEMENTGENERATOR_FLAG_INFORM_ENABLED);
return false;
}
}
if (owner->HasUnitState(UNIT_STATE_NOT_MOVE | UNIT_STATE_LOST_CONTROL) || owner->IsMovementPreventedByCasting())
{
AddFlag(MOVEMENTGENERATOR_FLAG_INTERRUPTED);
@@ -248,6 +278,20 @@ void WaypointMovementGenerator<Creature>::OnArrived(Creature* owner)
_nextMoveTime.Reset(waypoint.delay);
}
if (_waitTimeRangeAtPathEnd && _followPathBackwardsFromEndToStart
&& ((_isReturningToStart && _currentNode == 0) || (!_isReturningToStart && _currentNode == _path->nodes.size() - 1)))
{
owner->ClearUnitState(UNIT_STATE_ROAMING_MOVE);
Milliseconds waitTime = randtime(_waitTimeRangeAtPathEnd->first, _waitTimeRangeAtPathEnd->second);
if (_duration)
_duration->Update(waitTime); // count the random movement time as part of waypoing movement action
if (_wanderDistanceAtPathEnds)
owner->GetMotionMaster()->MoveRandom(*_wanderDistanceAtPathEnds, waitTime, MOTION_SLOT_ACTIVE);
else
_nextMoveTime.Reset(waitTime);
}
if (waypoint.eventId && urand(0, 99) < waypoint.eventChance)
{
TC_LOG_DEBUG("maps.script", "Creature movement start script {} at point {} for {}.", waypoint.eventId, _currentNode, owner->GetGUID().ToString());
@@ -343,7 +387,7 @@ void WaypointMovementGenerator<Creature>::StartMove(Creature* owner, bool relaun
//! Do not use formationDest here, MoveTo requires transport offsets due to DisableTransportPathTransformations() call
//! but formationDest contains global coordinates
init.MoveTo(waypoint.x, waypoint.y, waypoint.z);
init.MoveTo(waypoint.x, waypoint.y, waypoint.z, _generatePath);
if (waypoint.orientation.has_value() && waypoint.delay > 0)
init.SetFacing(*waypoint.orientation);
@@ -365,6 +409,22 @@ void WaypointMovementGenerator<Creature>::StartMove(Creature* owner, bool relaun
default:
break;
}
switch (_speedSelectionMode) // overrides move type from each waypoint if set
{
case MovementWalkRunSpeedSelectionMode::Default:
break;
case MovementWalkRunSpeedSelectionMode::ForceRun:
init.SetWalk(false);
break;
case MovementWalkRunSpeedSelectionMode::ForceWalk:
init.SetWalk(true);
break;
default:
break;
}
if (_speed)
init.SetVelocity(*_speed);
init.Launch();
@@ -377,7 +437,28 @@ bool WaypointMovementGenerator<Creature>::ComputeNextNode()
if ((_currentNode == _path->nodes.size() - 1) && !_repeating)
return false;
_currentNode = (_currentNode + 1) % _path->nodes.size();
if (!_followPathBackwardsFromEndToStart || _path->nodes.size() < 2)
_currentNode = (_currentNode + 1) % _path->nodes.size();
else
{
if (!_isReturningToStart)
{
if (++_currentNode >= _path->nodes.size())
{
_currentNode -= 2;
_isReturningToStart = true;
}
}
else
{
if (_currentNode-- == 0)
{
_currentNode = 1;
_isReturningToStart = false;
}
}
}
return true;
}

View File

@@ -30,12 +30,19 @@ template<class T>
class WaypointMovementGenerator;
template<>
class WaypointMovementGenerator<Creature> : public MovementGeneratorMedium<Creature, WaypointMovementGenerator<Creature>>, public PathMovementBase<Creature, WaypointPath const*>
class WaypointMovementGenerator<Creature> : public MovementGeneratorMedium<Creature, WaypointMovementGenerator<Creature>>,
public PathMovementBase<Creature, WaypointPath const*>
{
public:
explicit WaypointMovementGenerator(uint32 pathId = 0, bool repeating = true);
explicit WaypointMovementGenerator(WaypointPath& path, bool repeating = true);
~WaypointMovementGenerator() { _path = nullptr; }
explicit WaypointMovementGenerator(uint32 pathId, bool repeating, Optional<Milliseconds> duration = {}, Optional<float> speed = {},
MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode::Default,
Optional<std::pair<Milliseconds, Milliseconds>> waitTimeRangeAtPathEnd = {}, Optional<float> wanderDistanceAtPathEnds = {},
bool followPathBackwardsFromEndToStart = false, bool generatePath = true);
explicit WaypointMovementGenerator(WaypointPath const& path, bool repeating, Optional<Milliseconds> duration, Optional<float> speed,
MovementWalkRunSpeedSelectionMode speedSelectionMode,
Optional<std::pair<Milliseconds, Milliseconds>> waitTimeRangeAtPathEnd, Optional<float> wanderDistanceAtPathEnds,
bool followPathBackwardsFromEndToStart, bool generatePath);
~WaypointMovementGenerator();
MovementGeneratorType GetMovementGeneratorType() const override;
@@ -72,6 +79,15 @@ class WaypointMovementGenerator<Creature> : public MovementGeneratorMedium<Creat
uint32 _pathId;
bool _repeating;
bool _loadedFromDB;
Optional<TimeTracker> _duration;
Optional<float> _speed;
MovementWalkRunSpeedSelectionMode _speedSelectionMode;
Optional<std::pair<Milliseconds, Milliseconds>> _waitTimeRangeAtPathEnd;
Optional<float> _wanderDistanceAtPathEnds;
bool _followPathBackwardsFromEndToStart;
bool _isReturningToStart;
bool _generatePath;
};
#endif