Files
OpenRA/OpenRA.Mods.Common/Activities/Move/MoveOnto.cs
RoosterDragon 0c4dff77c9 Fix moves being reported as blocked when already at the destination.
When a move is made where the source and target locations are the same and no actual moving is required, a path of length 0 is returned. When a move cannot be made as there is no valid route, a path of length 0 is also returned. This means Move is unable to tell the difference between no movement required, and no path is possible. Currently it will hit the `hadNoPath` case and report CompleteDestinationBlocked.

To fix the scenario where the source and target location match, track a alreadyAtDestination field. When this scenario triggers, report CompleteDestinationReached instead.

This fixes activities that were using this result to inform their next actions. e.g. MoveOntoAndTurn would previously cancel the Turn portion of the activity, believing that the destination could not be reached. Now, it knows the destination was reached (since we are already there!) and will perform the turn.
2024-08-19 14:33:38 +03:00

61 lines
2.0 KiB
C#

#region Copyright & License Information
/*
* Copyright (c) The OpenRA Developers and Contributors
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using System.Collections.Generic;
using OpenRA.Mods.Common.Traits;
using OpenRA.Primitives;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Activities
{
public class MoveOnto : MoveAdjacentTo
{
readonly WVec offset = WVec.Zero;
public MoveOnto(Actor self, in Target target, WVec? offset = null, WPos? initialTargetPosition = null, Color? targetLineColor = null)
: base(self, target, initialTargetPosition, targetLineColor)
{
if (offset.HasValue)
this.offset = offset.Value;
}
protected override void SetVisibleTargetLocation(Actor self, Target target)
{
lastVisibleTargetLocation = self.World.Map.CellContaining(Target.CenterPosition + offset);
}
protected override bool ShouldStop(Actor self)
{
// Stop if the target is dead.
return Target.Type == TargetType.Terrain;
}
protected override (bool AlreadyAtDestination, List<CPos> Path) CalculatePathToTarget(Actor self, BlockedByActor check)
{
if (lastVisibleTargetLocation == self.Location)
return (true, PathFinder.NoPath);
// If we are close to the target but can't enter, we wait.
if (!Mobile.CanEnterCell(lastVisibleTargetLocation) && Util.AreAdjacentCells(lastVisibleTargetLocation, self.Location))
return (false, PathFinder.NoPath);
// PERF: Don't create a new list every run.
// PERF: Also reuse the already created list in the base class.
if (SearchCells.Count == 0)
SearchCells.Add(lastVisibleTargetLocation);
else if (SearchCells[0] != lastVisibleTargetLocation)
SearchCells[0] = lastVisibleTargetLocation;
return (false, Mobile.PathFinder.FindPathToTargetCells(self, self.Location, SearchCells, check));
}
}
}