Core/Movement: New waypoint movement features

Port From (https://github.com/TrinityCore/TrinityCore/commit/cf2e0e2faad78617012e8259352d08e7a62e6026)
This commit is contained in:
hondacrx
2023-03-14 01:51:43 -04:00
parent 351e05104d
commit aeaf5da3a2
2 changed files with 119 additions and 20 deletions
@@ -4,6 +4,7 @@
using Framework.Constants;
using Game.AI;
using Game.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -11,29 +12,69 @@ namespace Game.Movement
{
public class WaypointMovementGenerator : MovementGeneratorMedium<Creature>
{
public WaypointMovementGenerator(uint pathId = 0, bool repeating = true)
TimeTracker _nextMoveTime;
uint _pathId;
bool _repeating;
bool _loadedFromDB;
WaypointPath _path;
int _currentNode;
TimeTracker _duration;
float? _speed;
MovementWalkRunSpeedSelectionMode _speedSelectionMode;
(TimeSpan min, TimeSpan max)? _waitTimeRangeAtPathEnd;
float? _wanderDistanceAtPathEnds;
bool _followPathBackwardsFromEndToStart;
bool _isReturningToStart;
bool _generatePath;
public WaypointMovementGenerator(uint pathId = 0, bool repeating = true, TimeSpan? duration = null, float? speed = null, MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode.Default,
(TimeSpan min, TimeSpan max)? waitTimeRangeAtPathEnd = null, float? wanderDistanceAtPathEnds = null, bool followPathBackwardsFromEndToStart = false, bool generatePath = true)
{
_nextMoveTime = new TimeTracker(0);
_pathId = pathId;
_repeating = repeating;
_loadedFromDB = true;
_speed = speed;
_speedSelectionMode = speedSelectionMode;
_waitTimeRangeAtPathEnd = waitTimeRangeAtPathEnd;
_wanderDistanceAtPathEnds = wanderDistanceAtPathEnds;
_followPathBackwardsFromEndToStart = followPathBackwardsFromEndToStart;
_isReturningToStart = false;
_generatePath = generatePath;
Mode = MovementGeneratorMode.Default;
Priority = MovementGeneratorPriority.Normal;
Flags = MovementGeneratorFlags.InitializationPending;
BaseUnitState = UnitState.Roaming;
if (duration.HasValue)
_duration = new(duration.Value);
}
public WaypointMovementGenerator(WaypointPath path, bool repeating = true)
public WaypointMovementGenerator(WaypointPath path, bool repeating = true, TimeSpan? duration = null, float? speed = null, MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode.Default,
(TimeSpan min, TimeSpan max)? waitTimeRangeAtPathEnd = null, float? wanderDistanceAtPathEnds = null, bool followPathBackwardsFromEndToStart = false, bool generatePath = true)
{
_nextMoveTime = new TimeTracker(0);
_repeating = repeating;
_path = path;
_speed = speed;
_speedSelectionMode = speedSelectionMode;
_waitTimeRangeAtPathEnd = waitTimeRangeAtPathEnd;
_wanderDistanceAtPathEnds = wanderDistanceAtPathEnds;
_followPathBackwardsFromEndToStart = followPathBackwardsFromEndToStart;
_isReturningToStart = false;
_generatePath = generatePath;
Mode = MovementGeneratorMode.Default;
Priority = MovementGeneratorPriority.Normal;
Flags = MovementGeneratorFlags.InitializationPending;
BaseUnitState = UnitState.Roaming;
if (duration.HasValue)
_duration = new(duration.Value);
}
public override void Pause(uint timer = 0)
@@ -125,6 +166,17 @@ namespace Game.Movement
if (HasFlag(MovementGeneratorFlags.Finalized | MovementGeneratorFlags.Paused) || _path == null || _path.nodes.Empty())
return true;
if (_duration != null)
{
_duration.Update(diff);
if (_duration.Passed())
{
RemoveFlag(MovementGeneratorFlags.Transitory);
AddFlag(MovementGeneratorFlags.InformEnabled);
return false;
}
}
if (owner.HasUnitState(UnitState.NotMove | UnitState.LostControl) || owner.IsMovementPreventedByCasting())
{
AddFlag(MovementGeneratorFlags.Interrupted);
@@ -228,13 +280,27 @@ namespace Game.Movement
return;
Cypher.Assert(_currentNode < _path.nodes.Count, $"WaypointMovementGenerator.OnArrived: tried to reference a node id ({_currentNode}) which is not included in path ({_path.id})");
WaypointNode waypoint = _path.nodes.ElementAt((int)_currentNode);
WaypointNode waypoint = _path.nodes.ElementAt(_currentNode);
if (waypoint.delay != 0)
{
owner.ClearUnitState(UnitState.RoamingMove);
_nextMoveTime.Reset(waypoint.delay);
}
if (_waitTimeRangeAtPathEnd.HasValue && _followPathBackwardsFromEndToStart
&& ((_isReturningToStart && _currentNode == 0) || (!_isReturningToStart && _currentNode == _path.nodes.Count - 1)))
{
owner.ClearUnitState(UnitState.RoamingMove);
TimeSpan waitTime = RandomHelper.RandTime(_waitTimeRangeAtPathEnd.Value.min, _waitTimeRangeAtPathEnd.Value.max);
if (_duration != null)
_duration.Update(waitTime); // count the random movement time as part of waypoing movement action
if (_wanderDistanceAtPathEnds.HasValue)
owner.GetMotionMaster().MoveRandom(_wanderDistanceAtPathEnds.Value, waitTime, MovementSlot.Active);
else
_nextMoveTime.Reset(waitTime);
}
if (waypoint.eventId != 0 && RandomHelper.URand(0, 99) < waypoint.eventChance)
{
Log.outDebug(LogFilter.MapsScript, $"Creature movement start script {waypoint.eventId} at point {_currentNode} for {owner.GetGUID()}.");
@@ -335,7 +401,7 @@ namespace Game.Movement
//! 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.HasValue && waypoint.delay != 0)
init.SetFacing(waypoint.orientation.Value);
@@ -356,6 +422,23 @@ namespace Game.Movement
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.HasValue)
init.SetVelocity(_speed.Value);
init.Launch();
// inform formation
@@ -367,7 +450,27 @@ namespace Game.Movement
if ((_currentNode == _path.nodes.Count - 1) && !_repeating)
return false;
_currentNode = (_currentNode + 1) % _path.nodes.Count;
if (!_followPathBackwardsFromEndToStart || _path.nodes.Count < 2)
_currentNode = (_currentNode + 1) % _path.nodes.Count;
else
{
if (!_isReturningToStart)
{
if (++_currentNode >= _path.nodes.Count)
{
_currentNode -= 2;
_isReturningToStart = true;
}
}
else
{
if (_currentNode-- == 0)
{
_currentNode = 1;
_isReturningToStart = false;
}
}
}
return true;
}
@@ -375,7 +478,7 @@ namespace Game.Movement
{
return $"Current Node: {_currentNode}\n{base.GetDebugInfo()}";
}
bool UpdateTimer(uint diff)
{
_nextMoveTime.Update(diff);
@@ -390,13 +493,5 @@ namespace Game.Movement
public override MovementGeneratorType GetMovementGeneratorType() { return MovementGeneratorType.Waypoint; }
public override void UnitSpeedChanged() { AddFlag(MovementGeneratorFlags.SpeedUpdatePending); }
TimeTracker _nextMoveTime;
uint _pathId;
bool _repeating;
bool _loadedFromDB;
WaypointPath _path;
int _currentNode;
}
}
+10 -6
View File
@@ -545,10 +545,10 @@ namespace Game.Movement
Add(new FollowMovementGenerator(target, SharedConst.PetFollowDist, new ChaseAngle(SharedConst.PetFollowAngle), null));
}
public void MoveRandom(float wanderDistance = 0.0f, TimeSpan? duration = null)
public void MoveRandom(float wanderDistance = 0.0f, TimeSpan? duration = null, MovementSlot slot = MovementSlot.Default)
{
if (_owner.IsTypeId(TypeId.Unit))
Add(new RandomMovementGenerator(wanderDistance, duration), MovementSlot.Default);
Add(new RandomMovementGenerator(wanderDistance, duration), slot);
}
public void MoveFollow(Unit target, float dist, float angle = 0.0f, TimeSpan? duration = null, MovementSlot slot = MovementSlot.Active) { MoveFollow(target, dist, new ChaseAngle(angle), duration, slot); }
@@ -996,17 +996,21 @@ namespace Game.Movement
Add(new DistractMovementGenerator(timer, orientation));
}
public void MovePath(uint pathId, bool repeatable)
public void MovePath(uint pathId, bool repeatable, TimeSpan? duration = null, float? speed = null, MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode.Default,
(TimeSpan min, TimeSpan max)? waitTimeRangeAtPathEnd = null, float? wanderDistanceAtPathEnds = null, bool followPathBackwardsFromEndToStart = false, bool generatePath = true)
{
if (pathId == 0)
return;
Add(new WaypointMovementGenerator(pathId, repeatable), MovementSlot.Default);
Log.outDebug(LogFilter.Movement, $"MotionMaster::MovePath: '{_owner.GetGUID()}', starts moving over path Id: {pathId} (repeatable: {repeatable})");
Add(new WaypointMovementGenerator(pathId, repeatable, duration, speed, speedSelectionMode, waitTimeRangeAtPathEnd, wanderDistanceAtPathEnds, followPathBackwardsFromEndToStart, generatePath), MovementSlot.Default);
}
public void MovePath(WaypointPath path, bool repeatable)
public void MovePath(WaypointPath path, bool repeatable, TimeSpan? duration = null, float? speed = null, MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode.Default,
(TimeSpan min, TimeSpan max)? waitTimeRangeAtPathEnd = null, float? wanderDistanceAtPathEnds = null, bool followPathBackwardsFromEndToStart = false, bool generatePath = true)
{
Add(new WaypointMovementGenerator(path, repeatable), MovementSlot.Default);
Log.outDebug(LogFilter.Movement, $"MotionMaster::MovePath: '{_owner.GetGUID()}', starts moving over path Id: {path.id} (repeatable: {repeatable})");
Add(new WaypointMovementGenerator(path, repeatable, duration, speed, speedSelectionMode, waitTimeRangeAtPathEnd, wanderDistanceAtPathEnds, followPathBackwardsFromEndToStart, generatePath), MovementSlot.Default);
}
public void MoveRotate(uint id, uint time, RotateDirection direction)