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 Framework.Constants;
using Game.AI; using Game.AI;
using Game.Entities; using Game.Entities;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@@ -11,29 +12,69 @@ namespace Game.Movement
{ {
public class WaypointMovementGenerator : MovementGeneratorMedium<Creature> 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); _nextMoveTime = new TimeTracker(0);
_pathId = pathId; _pathId = pathId;
_repeating = repeating; _repeating = repeating;
_loadedFromDB = true; _loadedFromDB = true;
_speed = speed;
_speedSelectionMode = speedSelectionMode;
_waitTimeRangeAtPathEnd = waitTimeRangeAtPathEnd;
_wanderDistanceAtPathEnds = wanderDistanceAtPathEnds;
_followPathBackwardsFromEndToStart = followPathBackwardsFromEndToStart;
_isReturningToStart = false;
_generatePath = generatePath;
Mode = MovementGeneratorMode.Default; Mode = MovementGeneratorMode.Default;
Priority = MovementGeneratorPriority.Normal; Priority = MovementGeneratorPriority.Normal;
Flags = MovementGeneratorFlags.InitializationPending; Flags = MovementGeneratorFlags.InitializationPending;
BaseUnitState = UnitState.Roaming; 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); _nextMoveTime = new TimeTracker(0);
_repeating = repeating; _repeating = repeating;
_path = path; _path = path;
_speed = speed;
_speedSelectionMode = speedSelectionMode;
_waitTimeRangeAtPathEnd = waitTimeRangeAtPathEnd;
_wanderDistanceAtPathEnds = wanderDistanceAtPathEnds;
_followPathBackwardsFromEndToStart = followPathBackwardsFromEndToStart;
_isReturningToStart = false;
_generatePath = generatePath;
Mode = MovementGeneratorMode.Default; Mode = MovementGeneratorMode.Default;
Priority = MovementGeneratorPriority.Normal; Priority = MovementGeneratorPriority.Normal;
Flags = MovementGeneratorFlags.InitializationPending; Flags = MovementGeneratorFlags.InitializationPending;
BaseUnitState = UnitState.Roaming; BaseUnitState = UnitState.Roaming;
if (duration.HasValue)
_duration = new(duration.Value);
} }
public override void Pause(uint timer = 0) 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()) if (HasFlag(MovementGeneratorFlags.Finalized | MovementGeneratorFlags.Paused) || _path == null || _path.nodes.Empty())
return true; 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()) if (owner.HasUnitState(UnitState.NotMove | UnitState.LostControl) || owner.IsMovementPreventedByCasting())
{ {
AddFlag(MovementGeneratorFlags.Interrupted); AddFlag(MovementGeneratorFlags.Interrupted);
@@ -228,13 +280,27 @@ namespace Game.Movement
return; return;
Cypher.Assert(_currentNode < _path.nodes.Count, $"WaypointMovementGenerator.OnArrived: tried to reference a node id ({_currentNode}) which is not included in path ({_path.id})"); 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) if (waypoint.delay != 0)
{ {
owner.ClearUnitState(UnitState.RoamingMove); owner.ClearUnitState(UnitState.RoamingMove);
_nextMoveTime.Reset(waypoint.delay); _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) 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()}."); 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 //! Do not use formationDest here, MoveTo requires transport offsets due to DisableTransportPathTransformations() call
//! but formationDest contains global coordinates //! 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) if (waypoint.orientation.HasValue && waypoint.delay != 0)
init.SetFacing(waypoint.orientation.Value); init.SetFacing(waypoint.orientation.Value);
@@ -356,6 +422,23 @@ namespace Game.Movement
break; 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(); init.Launch();
// inform formation // inform formation
@@ -367,7 +450,27 @@ namespace Game.Movement
if ((_currentNode == _path.nodes.Count - 1) && !_repeating) if ((_currentNode == _path.nodes.Count - 1) && !_repeating)
return false; 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; return true;
} }
@@ -375,7 +478,7 @@ namespace Game.Movement
{ {
return $"Current Node: {_currentNode}\n{base.GetDebugInfo()}"; return $"Current Node: {_currentNode}\n{base.GetDebugInfo()}";
} }
bool UpdateTimer(uint diff) bool UpdateTimer(uint diff)
{ {
_nextMoveTime.Update(diff); _nextMoveTime.Update(diff);
@@ -390,13 +493,5 @@ namespace Game.Movement
public override MovementGeneratorType GetMovementGeneratorType() { return MovementGeneratorType.Waypoint; } public override MovementGeneratorType GetMovementGeneratorType() { return MovementGeneratorType.Waypoint; }
public override void UnitSpeedChanged() { AddFlag(MovementGeneratorFlags.SpeedUpdatePending); } 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)); 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)) 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); } 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)); 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) if (pathId == 0)
return; 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) public void MoveRotate(uint id, uint time, RotateDirection direction)