Fix target invalidation and reacquisition in MoveAdjacentTo.
This commit is contained in:
@@ -26,40 +26,45 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
protected readonly Mobile Mobile;
|
protected readonly Mobile Mobile;
|
||||||
readonly IPathFinder pathFinder;
|
readonly IPathFinder pathFinder;
|
||||||
readonly DomainIndex domainIndex;
|
readonly DomainIndex domainIndex;
|
||||||
|
readonly Color? targetLineColor;
|
||||||
|
|
||||||
Target target;
|
|
||||||
bool canHideUnderFog;
|
|
||||||
protected Target Target
|
protected Target Target
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return target;
|
return useLastVisibleTarget ? lastVisibleTarget : target;
|
||||||
}
|
|
||||||
|
|
||||||
private set
|
|
||||||
{
|
|
||||||
target = value;
|
|
||||||
if (target.Type == TargetType.Actor)
|
|
||||||
canHideUnderFog = target.Actor.Info.HasTraitInfo<HiddenUnderFogInfo>();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected CPos targetPosition;
|
Target target;
|
||||||
|
Target lastVisibleTarget;
|
||||||
|
protected CPos lastVisibleTargetLocation;
|
||||||
|
bool useLastVisibleTarget;
|
||||||
|
|
||||||
Activity inner;
|
Activity inner;
|
||||||
bool repath;
|
bool repath;
|
||||||
|
|
||||||
public MoveAdjacentTo(Actor self, Target target, WPos? initialTargetPosition = null, Color? targetLineColor = null)
|
public MoveAdjacentTo(Actor self, Target target, WPos? initialTargetPosition = null, Color? targetLineColor = null)
|
||||||
{
|
{
|
||||||
Target = target;
|
this.target = target;
|
||||||
|
this.targetLineColor = targetLineColor;
|
||||||
Mobile = self.Trait<Mobile>();
|
Mobile = self.Trait<Mobile>();
|
||||||
pathFinder = self.World.WorldActor.Trait<IPathFinder>();
|
pathFinder = self.World.WorldActor.Trait<IPathFinder>();
|
||||||
domainIndex = self.World.WorldActor.Trait<DomainIndex>();
|
domainIndex = self.World.WorldActor.Trait<DomainIndex>();
|
||||||
|
|
||||||
if (initialTargetPosition.HasValue)
|
// The target may become hidden between the initial order request and the first tick (e.g. if queued)
|
||||||
targetPosition = self.World.Map.CellContaining(initialTargetPosition.Value);
|
// Moving to any position (even if quite stale) is still better than immediately giving up
|
||||||
else if (target.IsValidFor(self) && target.Actor.CanBeViewedByPlayer(self.Owner))
|
if ((target.Type == TargetType.Actor && target.Actor.CanBeViewedByPlayer(self.Owner))
|
||||||
targetPosition = self.World.Map.CellContaining(target.CenterPosition);
|
|| target.Type == TargetType.FrozenActor || target.Type == TargetType.Terrain)
|
||||||
|
{
|
||||||
|
lastVisibleTarget = Target.FromPos(target.CenterPosition);
|
||||||
|
lastVisibleTargetLocation = self.World.Map.CellContaining(target.CenterPosition);
|
||||||
|
}
|
||||||
|
else if (initialTargetPosition.HasValue)
|
||||||
|
{
|
||||||
|
lastVisibleTarget = Target.FromPos(initialTargetPosition.Value);
|
||||||
|
lastVisibleTargetLocation = self.World.Map.CellContaining(initialTargetPosition.Value);
|
||||||
|
}
|
||||||
|
|
||||||
repath = true;
|
repath = true;
|
||||||
}
|
}
|
||||||
@@ -69,9 +74,9 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual bool ShouldRepath(Actor self, CPos oldTargetPosition)
|
protected virtual bool ShouldRepath(Actor self, CPos targetLocation)
|
||||||
{
|
{
|
||||||
return targetPosition != oldTargetPosition;
|
return lastVisibleTargetLocation != targetLocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual IEnumerable<CPos> CandidateMovementCells(Actor self)
|
protected virtual IEnumerable<CPos> CandidateMovementCells(Actor self)
|
||||||
@@ -81,19 +86,30 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
|
|
||||||
public override Activity Tick(Actor self)
|
public override Activity Tick(Actor self)
|
||||||
{
|
{
|
||||||
var targetIsValid = Target.IsValidFor(self);
|
bool targetIsHiddenActor;
|
||||||
|
var oldTargetLocation = lastVisibleTargetLocation;
|
||||||
// Target moved under the fog. Move to its last known position.
|
target = target.Recalculate(self.Owner, out targetIsHiddenActor);
|
||||||
if (Target.Type == TargetType.Actor && canHideUnderFog
|
if (!targetIsHiddenActor && target.Type == TargetType.Actor)
|
||||||
&& !Target.Actor.CanBeViewedByPlayer(self.Owner))
|
|
||||||
{
|
{
|
||||||
if (inner != null)
|
lastVisibleTarget = Target.FromTargetPositions(target);
|
||||||
inner.Cancel(self);
|
lastVisibleTargetLocation = self.World.Map.CellContaining(target.CenterPosition);
|
||||||
|
|
||||||
self.SetTargetLine(Target.FromCell(self.World, targetPosition), Color.Green);
|
|
||||||
return ActivityUtils.RunActivity(self, new AttackMoveActivity(self, Mobile.MoveTo(targetPosition, 0)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var oldUseLastVisibleTarget = useLastVisibleTarget;
|
||||||
|
useLastVisibleTarget = targetIsHiddenActor || !target.IsValidFor(self);
|
||||||
|
|
||||||
|
// Update target lines if required
|
||||||
|
if (useLastVisibleTarget != oldUseLastVisibleTarget && targetLineColor.HasValue)
|
||||||
|
self.SetTargetLine(useLastVisibleTarget ? lastVisibleTarget : target, targetLineColor.Value, false);
|
||||||
|
|
||||||
|
// Target is hidden or dead, and we don't have a fallback position to move towards
|
||||||
|
if (useLastVisibleTarget && !lastVisibleTarget.IsValidFor(self))
|
||||||
|
return NextActivity;
|
||||||
|
|
||||||
|
// Target is equivalent to checkTarget variable in other activities
|
||||||
|
// value is either lastVisibleTarget or target based on visibility and validity
|
||||||
|
var targetIsValid = Target.IsValidFor(self);
|
||||||
|
|
||||||
// Inner move order has completed.
|
// Inner move order has completed.
|
||||||
if (inner == null)
|
if (inner == null)
|
||||||
{
|
{
|
||||||
@@ -107,26 +123,16 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
repath = false;
|
repath = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetIsValid)
|
// Cancel the current path if the activity asks to stop, or asks to repath
|
||||||
|
// The repath happens once the move activity stops in the next cell
|
||||||
|
var shouldStop = ShouldStop(self, oldTargetLocation);
|
||||||
|
var shouldRepath = targetIsValid && !repath && ShouldRepath(self, oldTargetLocation);
|
||||||
|
if (shouldStop || shouldRepath)
|
||||||
{
|
{
|
||||||
// Check if the target has moved
|
if (inner != null)
|
||||||
var oldTargetPosition = targetPosition;
|
inner.Cancel(self);
|
||||||
targetPosition = self.World.Map.CellContaining(Target.CenterPosition);
|
|
||||||
|
|
||||||
var shouldStop = ShouldStop(self, oldTargetPosition);
|
repath = shouldRepath;
|
||||||
if (shouldStop || (!repath && ShouldRepath(self, oldTargetPosition)))
|
|
||||||
{
|
|
||||||
// Finish moving into the next cell and then repath.
|
|
||||||
if (inner != null)
|
|
||||||
inner.Cancel(self);
|
|
||||||
|
|
||||||
repath = !shouldStop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Target became invalid. Move to its last known position.
|
|
||||||
Target = Target.FromCell(self.World, targetPosition);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ticks the inner move activity to actually move the actor.
|
// Ticks the inner move activity to actually move the actor.
|
||||||
@@ -149,7 +155,7 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
return NoPath;
|
return NoPath;
|
||||||
|
|
||||||
using (var fromSrc = PathSearch.FromPoints(self.World, Mobile.Info.LocomotorInfo, self, searchCells, loc, true))
|
using (var fromSrc = PathSearch.FromPoints(self.World, Mobile.Info.LocomotorInfo, self, searchCells, loc, true))
|
||||||
using (var fromDest = PathSearch.FromPoint(self.World, Mobile.Info.LocomotorInfo, self, loc, targetPosition, true).Reverse())
|
using (var fromDest = PathSearch.FromPoint(self.World, Mobile.Info.LocomotorInfo, self, loc, lastVisibleTargetLocation, true).Reverse())
|
||||||
return pathFinder.FindBidiPath(fromSrc, fromDest);
|
return pathFinder.FindBidiPath(fromSrc, fromDest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
|
|
||||||
protected override bool ShouldRepath(Actor self, CPos oldTargetPosition)
|
protected override bool ShouldRepath(Actor self, CPos oldTargetPosition)
|
||||||
{
|
{
|
||||||
return targetPosition != oldTargetPosition && (!AtCorrectRange(self.CenterPosition)
|
return lastVisibleTargetLocation != oldTargetPosition && (!AtCorrectRange(self.CenterPosition)
|
||||||
|| !Mobile.CanInteractWithGroundLayer(self));
|
|| !Mobile.CanInteractWithGroundLayer(self));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ namespace OpenRA.Mods.Common.Activities
|
|||||||
var maxCells = (maxRange.Length + 1023) / 1024;
|
var maxCells = (maxRange.Length + 1023) / 1024;
|
||||||
var minCells = minRange.Length / 1024;
|
var minCells = minRange.Length / 1024;
|
||||||
|
|
||||||
return map.FindTilesInAnnulus(targetPosition, minCells, maxCells)
|
return map.FindTilesInAnnulus(lastVisibleTargetLocation, minCells, maxCells)
|
||||||
.Where(c => AtCorrectRange(map.CenterOfSubCell(c, Mobile.FromSubCell)));
|
.Where(c => AtCorrectRange(map.CenterOfSubCell(c, Mobile.FromSubCell)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user