diff --git a/src/Perpetuum/Zones/Movements/WaypointMovement.cs b/src/Perpetuum/Zones/Movements/WaypointMovement.cs index 5e4879401..f1403735c 100644 --- a/src/Perpetuum/Zones/Movements/WaypointMovement.cs +++ b/src/Perpetuum/Zones/Movements/WaypointMovement.cs @@ -24,9 +24,22 @@ public override void Start(Unit unit) unit.Direction = unit.CurrentPosition.DirectionTo(_target); unit.CurrentSpeed = 1.0; - _velocity = Vector2.Subtract(_target,unit.CurrentPosition.ToVector2()); - _distance = Vector2.Abs(_velocity); - _velocity = Vector2.Normalize(_velocity); + // Vector to destination + var path = Vector2.Subtract(_target, unit.CurrentPosition.ToVector2()); + // The absolute path along each coordinate + _distance = Vector2.Abs(path); + if (path.Length().IsApproximatelyEqual(0.0f)) + { + // If the path is zero, then is already at the destination + Arrived = true; + // Velocity vector in the direction of the unit. + _velocity = MathHelper.DirectionToVector(unit.Direction); + } + else + { + // Velocity vector in the direction of the path. + _velocity = Vector2.Normalize(path); + } base.Start(unit); } diff --git a/src/Perpetuum/Zones/NpcSystem/AI/CombatAI.cs b/src/Perpetuum/Zones/NpcSystem/AI/CombatAI.cs index 4b5b9eb07..8b2944c1b 100644 --- a/src/Perpetuum/Zones/NpcSystem/AI/CombatAI.cs +++ b/src/Perpetuum/Zones/NpcSystem/AI/CombatAI.cs @@ -24,6 +24,8 @@ public class CombatAI : BaseAI private const int UpdateFrequency = 1650; private const int Sqrt2 = 141; private const int Weight = 1000; + // Timer for periodically checking the main hostile target. + private readonly IntervalTimer updateHostileTimer = new IntervalTimer(UpdateFrequency, true); private readonly IntervalTimer processHostilesTimer = new IntervalTimer(UpdateFrequency); private readonly IntervalTimer primarySelectTimer = new IntervalTimer(UpdateFrequency); private List moduleActivators; @@ -261,7 +263,17 @@ protected void UpdateHostile(TimeSpan time, bool moveThreatToPseudoThreat = true return; } - if (!mostHated.Unit.CurrentPosition.IsEqual2D(this.lastTargetPosition)) + var forceCheckPrimary = false; + updateHostileTimer.Update(time); + if (updateHostileTimer.Passed) + { + updateHostileTimer.Reset(); + + // Forced check of the main hostile target. + forceCheckPrimary = movement?.Arrived ?? true; + } + + if (!mostHated.Unit.CurrentPosition.IsEqual2D(this.lastTargetPosition) || forceCheckPrimary) { this.lastTargetPosition = mostHated.Unit.CurrentPosition; @@ -393,6 +405,8 @@ private List FindNewAttackPosition(Unit hostile, CancellationToken cancel var end = hostile.CurrentPosition.GetRandomPositionInRange2D(0, smartCreature.BestActionRange - 1).ToPoint(); smartCreature.StopMoving(); + // Nulling movement so that the unit does not resume it at zero speed if the path is not found. + movement = null; var maxNode = Math.Pow(smartCreature.HomeRange, 2) * Math.PI; var priorityQueue = new PriorityQueue((int)maxNode);