Disallow units idling on service depot.

This commit is contained in:
tovl
2019-09-22 23:52:11 +02:00
committed by Paul Chote
parent c360d8bcef
commit 434c46058f
10 changed files with 86 additions and 18 deletions

View File

@@ -146,7 +146,7 @@ namespace OpenRA.Mods.Common.Activities
if (evaluateNearestMovableCell && destination.HasValue)
{
var movableDestination = mobile.NearestMoveableCell(destination.Value);
destination = mobile.CanEnterCell(movableDestination) ? movableDestination : (CPos?)null;
destination = mobile.CanEnterCell(movableDestination, check: BlockedByActor.Immovable) ? movableDestination : (CPos?)null;
}
path = EvalPath(BlockedByActor.Stationary);
@@ -160,8 +160,13 @@ namespace OpenRA.Mods.Common.Activities
// If the actor is inside a tunnel then we must let them move
// all the way through before moving to the next activity
if (IsCanceling && self.Location.Layer != CustomMovementLayerType.Tunnel)
if (IsCanceling && self.Location.Layer != CustomMovementLayerType.Tunnel && mobile.CanStayInCell(mobile.ToCell))
{
if (path != null)
path.Clear();
return true;
}
if (mobile.IsTraitDisabled || mobile.IsTraitPaused)
return false;
@@ -225,7 +230,7 @@ namespace OpenRA.Mods.Common.Activities
{
// Are we close enough?
var cellRange = nearEnough.Length / 1024;
if (!containsTemporaryBlocker && (mobile.ToCell - destination.Value).LengthSquared <= cellRange * cellRange)
if (!containsTemporaryBlocker && (mobile.ToCell - destination.Value).LengthSquared <= cellRange * cellRange && mobile.CanStayInCell(mobile.ToCell))
{
path.Clear();
return null;
@@ -312,7 +317,9 @@ namespace OpenRA.Mods.Common.Activities
public override void Cancel(Actor self, bool keepQueue = false)
{
if (path != null)
// We need to clear the path here in order to prevent MovePart queueing new instances of itself
// when the unit is making a turn.
if (path != null && mobile.CanStayInCell(mobile.ToCell))
path.Clear();
base.Cancel(self, keepQueue);

View File

@@ -23,7 +23,8 @@ namespace OpenRA.Mods.Common.Traits
Empty = '_',
OccupiedPassable = '=',
Occupied = 'x',
OccupiedUntargetable = 'X'
OccupiedUntargetable = 'X',
OccupiedPassableTransitOnly = '+'
}
public class BuildingInfo : ITraitInfo, IOccupySpaceInfo, IPlaceBuildingDecorationInfo
@@ -107,6 +108,9 @@ namespace OpenRA.Mods.Common.Traits
foreach (var t in FootprintTiles(location, FootprintCellType.OccupiedUntargetable))
yield return t;
foreach (var t in FootprintTiles(location, FootprintCellType.OccupiedPassableTransitOnly))
yield return t;
}
public IEnumerable<CPos> FrozenUnderFogTiles(CPos location)
@@ -118,13 +122,16 @@ namespace OpenRA.Mods.Common.Traits
yield return t;
}
public IEnumerable<CPos> UnpathableTiles(CPos location)
public IEnumerable<CPos> OccupiedTiles(CPos location)
{
foreach (var t in FootprintTiles(location, FootprintCellType.Occupied))
yield return t;
foreach (var t in FootprintTiles(location, FootprintCellType.OccupiedUntargetable))
yield return t;
foreach (var t in FootprintTiles(location, FootprintCellType.OccupiedPassableTransitOnly))
yield return t;
}
public IEnumerable<CPos> PathableTiles(CPos location)
@@ -136,6 +143,12 @@ namespace OpenRA.Mods.Common.Traits
yield return t;
}
public IEnumerable<CPos> TransitOnlyTiles(CPos location)
{
foreach (var t in FootprintTiles(location, FootprintCellType.OccupiedPassableTransitOnly))
yield return t;
}
public WVec CenterOffset(World w)
{
var off = (w.Map.CenterOfCell(new CPos(Dimensions.X, Dimensions.Y)) - w.Map.CenterOfCell(new CPos(1, 1))) / 2;
@@ -225,7 +238,7 @@ namespace OpenRA.Mods.Common.Traits
public IReadOnlyDictionary<CPos, SubCell> OccupiedCells(ActorInfo info, CPos topLeft, SubCell subCell = SubCell.Any)
{
var occupied = UnpathableTiles(topLeft)
var occupied = OccupiedTiles(topLeft)
.ToDictionary(c => c, c => SubCell.FullCell);
return new ReadOnlyDictionary<CPos, SubCell>(occupied);
@@ -255,6 +268,7 @@ namespace OpenRA.Mods.Common.Traits
Pair<CPos, SubCell>[] occupiedCells;
Pair<CPos, SubCell>[] targetableCells;
CPos[] transitOnlyCells;
public CPos TopLeft { get { return topLeft; } }
public WPos CenterPosition { get; private set; }
@@ -266,17 +280,21 @@ namespace OpenRA.Mods.Common.Traits
Info = info;
influence = self.World.WorldActor.Trait<BuildingInfluence>();
occupiedCells = Info.UnpathableTiles(TopLeft)
occupiedCells = Info.OccupiedTiles(TopLeft)
.Select(c => Pair.New(c, SubCell.FullCell)).ToArray();
targetableCells = Info.FootprintTiles(TopLeft, FootprintCellType.Occupied)
.Select(c => Pair.New(c, SubCell.FullCell)).ToArray();
transitOnlyCells = Info.TransitOnlyTiles(TopLeft).ToArray();
CenterPosition = init.World.Map.CenterOfCell(topLeft) + Info.CenterOffset(init.World);
}
public Pair<CPos, SubCell>[] OccupiedCells() { return occupiedCells; }
public CPos[] TransitOnlyCells() { return transitOnlyCells; }
Pair<CPos, SubCell>[] ITargetableCells.TargetableCells() { return targetableCells; }
void INotifyAddedToWorld.AddedToWorld(Actor self)

View File

@@ -118,7 +118,7 @@ namespace OpenRA.Mods.Common.Traits
if (Info.Type == ExplosionType.Footprint && buildingInfo != null)
{
var cells = buildingInfo.UnpathableTiles(self.Location);
var cells = buildingInfo.OccupiedTiles(self.Location);
foreach (var c in cells)
weapon.Impact(Target.FromPos(self.World.Map.CenterOfCell(c)), source, Enumerable.Empty<int>());

View File

@@ -102,6 +102,16 @@ namespace OpenRA.Mods.Common.Traits
return locomotor.CanMoveFreelyInto(self, cell, subCell, check, ignoreActor);
}
public bool CanStayInCell(World world, CPos cell)
{
// PERF: Avoid repeated trait queries on the hot path
if (locomotor == null)
locomotor = world.WorldActor.TraitsImplementing<Locomotor>()
.SingleOrDefault(l => l.Info.Name == Locomotor);
return locomotor.CanStayInCell(cell);
}
public IReadOnlyDictionary<CPos, SubCell> OccupiedCells(ActorInfo info, CPos location, SubCell subCell = SubCell.Any)
{
return new ReadOnlyDictionary<CPos, SubCell>(new Dictionary<CPos, SubCell>() { { location, subCell } });
@@ -363,7 +373,7 @@ namespace OpenRA.Mods.Common.Traits
foreach (CVec direction in CVec.Directions)
{
var p = ToCell + direction;
if (CanEnterCell(p))
if (CanEnterCell(p) && CanStayInCell(p))
availCells.Add(p);
else if (p != nextCell && p != ToCell)
notStupidCells.Add(p);
@@ -507,6 +517,11 @@ namespace OpenRA.Mods.Common.Traits
return Info.CanEnterCell(self.World, self, cell, ToSubCell, ignoreActor, check);
}
public bool CanStayInCell(CPos cell)
{
return Info.CanStayInCell(self.World, cell);
}
#endregion
#region Local IPositionable-related
@@ -666,6 +681,16 @@ namespace OpenRA.Mods.Common.Traits
QueueChild(mobile.VisualMove(self, pos, self.World.Map.CenterOfSubCell(cell, subCell)));
return true;
}
public override void Cancel(Actor self, bool keepQueue = false)
{
// If we are forbidden from stopping in this cell, use evaluateNearestMovableCell
// to nudge us to the nearest cell that we can stop in.
if (!mobile.CanStayInCell(cell))
QueueChild(new Move(self, cell, WDist.Zero, null, true));
base.Cancel(self, keepQueue);
}
}
public Activity MoveToTarget(Actor self, Target target,
@@ -743,11 +768,14 @@ namespace OpenRA.Mods.Common.Traits
if (target.Layer != 0)
target = new CPos(target.X, target.Y);
if (CanEnterCell(target))
if (target == self.Location && CanStayInCell(target))
return target;
if (CanEnterCell(target, check: BlockedByActor.Immovable) && CanStayInCell(target))
return target;
foreach (var tile in self.World.Map.FindTilesInAnnulus(target, minRange, maxRange))
if (CanEnterCell(tile))
if (CanEnterCell(tile, check: BlockedByActor.Immovable) && CanStayInCell(tile))
return tile;
// Couldn't find a cell

View File

@@ -27,7 +27,8 @@ namespace OpenRA.Mods.Common.Traits
HasStationaryActor = 2,
HasMovableActor = 4,
HasCrushableActor = 8,
HasTemporaryBlocker = 16
HasTemporaryBlocker = 16,
HasTransitOnlyActor = 32,
}
public static class LocomoterExts
@@ -309,6 +310,11 @@ namespace OpenRA.Mods.Common.Traits
return true;
}
public bool CanStayInCell(CPos cell)
{
return !GetCache(cell).CellFlag.HasCellFlag(CellFlag.HasTransitOnlyActor);
}
public SubCell GetAvailableSubCell(Actor self, CPos cell, BlockedByActor check, SubCell preferredSubCell = SubCell.Any, Actor ignoreActor = null)
{
if (MovementCostForCell(cell) == short.MaxValue)
@@ -496,6 +502,15 @@ namespace OpenRA.Mods.Common.Traits
var isMovable = mobile != null && !mobile.IsTraitDisabled && !mobile.IsTraitPaused && !mobile.IsImmovable;
var isMoving = isMovable && mobile.CurrentMovementTypes.HasMovementType(MovementType.Horizontal);
var building = actor.OccupiesSpace as Building;
var isTransitOnly = building != null && building.TransitOnlyCells().Contains(cell);
if (isTransitOnly)
{
cellFlag |= CellFlag.HasTransitOnlyActor;
continue;
}
if (crushables.Any())
{
cellFlag |= CellFlag.HasCrushableActor;

View File

@@ -58,7 +58,7 @@ namespace OpenRA.Mods.Common.Traits
buildBlocked = sequences.GetSequence("overlay", "build-invalid").GetSprite(0);
var buildingInfo = ai.TraitInfo<BuildingInfo>();
unpathableCells = new CachedTransform<CPos, List<CPos>>(topLeft => buildingInfo.UnpathableTiles(topLeft).ToList());
unpathableCells = new CachedTransform<CPos, List<CPos>>(topLeft => buildingInfo.OccupiedTiles(topLeft).ToList());
}
protected override IEnumerable<IRenderable> RenderFootprint(WorldRenderer wr, CPos topLeft, Dictionary<CPos, PlaceBuildingCellType> footprint,

View File

@@ -678,7 +678,7 @@ FIX:
Queue: Building.GDI, Building.Nod
Description: Repairs vehicles
Building:
Footprint: _=_ === _=_
Footprint: _+_ +++ _+_
Dimensions: 3,3
Selectable:
Bounds: 64,34,0,3

View File

@@ -881,7 +881,7 @@ repair_pad:
Tooltip:
Name: Repair Pad
Building:
Footprint: === === ===
Footprint: +++ +++ +++
Dimensions: 3,3
Health:
HP: 30000

View File

@@ -1989,7 +1989,7 @@ FIX:
Tooltip:
Name: Service Depot
Building:
Footprint: _=_ === _=_
Footprint: _+_ +++ _+_
Dimensions: 3,3
Selectable:
Bounds: 68,34,0,3

View File

@@ -320,7 +320,7 @@ GADEPT:
Queue: Building
Description: Repairs vehicles.
Building:
Footprint: === x== x==
Footprint: =+= x++ x+=
Dimensions: 3,3
Selectable:
Bounds: 96, 64, -6, -6