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) if (evaluateNearestMovableCell && destination.HasValue)
{ {
var movableDestination = mobile.NearestMoveableCell(destination.Value); 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); 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 // If the actor is inside a tunnel then we must let them move
// all the way through before moving to the next activity // 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; return true;
}
if (mobile.IsTraitDisabled || mobile.IsTraitPaused) if (mobile.IsTraitDisabled || mobile.IsTraitPaused)
return false; return false;
@@ -225,7 +230,7 @@ namespace OpenRA.Mods.Common.Activities
{ {
// Are we close enough? // Are we close enough?
var cellRange = nearEnough.Length / 1024; 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(); path.Clear();
return null; return null;
@@ -312,7 +317,9 @@ namespace OpenRA.Mods.Common.Activities
public override void Cancel(Actor self, bool keepQueue = false) 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(); path.Clear();
base.Cancel(self, keepQueue); base.Cancel(self, keepQueue);

View File

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

View File

@@ -118,7 +118,7 @@ namespace OpenRA.Mods.Common.Traits
if (Info.Type == ExplosionType.Footprint && buildingInfo != null) if (Info.Type == ExplosionType.Footprint && buildingInfo != null)
{ {
var cells = buildingInfo.UnpathableTiles(self.Location); var cells = buildingInfo.OccupiedTiles(self.Location);
foreach (var c in cells) foreach (var c in cells)
weapon.Impact(Target.FromPos(self.World.Map.CenterOfCell(c)), source, Enumerable.Empty<int>()); 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); 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) public IReadOnlyDictionary<CPos, SubCell> OccupiedCells(ActorInfo info, CPos location, SubCell subCell = SubCell.Any)
{ {
return new ReadOnlyDictionary<CPos, SubCell>(new Dictionary<CPos, SubCell>() { { location, subCell } }); 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) foreach (CVec direction in CVec.Directions)
{ {
var p = ToCell + direction; var p = ToCell + direction;
if (CanEnterCell(p)) if (CanEnterCell(p) && CanStayInCell(p))
availCells.Add(p); availCells.Add(p);
else if (p != nextCell && p != ToCell) else if (p != nextCell && p != ToCell)
notStupidCells.Add(p); notStupidCells.Add(p);
@@ -507,6 +517,11 @@ namespace OpenRA.Mods.Common.Traits
return Info.CanEnterCell(self.World, self, cell, ToSubCell, ignoreActor, check); return Info.CanEnterCell(self.World, self, cell, ToSubCell, ignoreActor, check);
} }
public bool CanStayInCell(CPos cell)
{
return Info.CanStayInCell(self.World, cell);
}
#endregion #endregion
#region Local IPositionable-related #region Local IPositionable-related
@@ -666,6 +681,16 @@ namespace OpenRA.Mods.Common.Traits
QueueChild(mobile.VisualMove(self, pos, self.World.Map.CenterOfSubCell(cell, subCell))); QueueChild(mobile.VisualMove(self, pos, self.World.Map.CenterOfSubCell(cell, subCell)));
return true; 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, public Activity MoveToTarget(Actor self, Target target,
@@ -743,11 +768,14 @@ namespace OpenRA.Mods.Common.Traits
if (target.Layer != 0) if (target.Layer != 0)
target = new CPos(target.X, target.Y); 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; return target;
foreach (var tile in self.World.Map.FindTilesInAnnulus(target, minRange, maxRange)) foreach (var tile in self.World.Map.FindTilesInAnnulus(target, minRange, maxRange))
if (CanEnterCell(tile)) if (CanEnterCell(tile, check: BlockedByActor.Immovable) && CanStayInCell(tile))
return tile; return tile;
// Couldn't find a cell // Couldn't find a cell

View File

@@ -27,7 +27,8 @@ namespace OpenRA.Mods.Common.Traits
HasStationaryActor = 2, HasStationaryActor = 2,
HasMovableActor = 4, HasMovableActor = 4,
HasCrushableActor = 8, HasCrushableActor = 8,
HasTemporaryBlocker = 16 HasTemporaryBlocker = 16,
HasTransitOnlyActor = 32,
} }
public static class LocomoterExts public static class LocomoterExts
@@ -309,6 +310,11 @@ namespace OpenRA.Mods.Common.Traits
return true; 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) public SubCell GetAvailableSubCell(Actor self, CPos cell, BlockedByActor check, SubCell preferredSubCell = SubCell.Any, Actor ignoreActor = null)
{ {
if (MovementCostForCell(cell) == short.MaxValue) 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 isMovable = mobile != null && !mobile.IsTraitDisabled && !mobile.IsTraitPaused && !mobile.IsImmovable;
var isMoving = isMovable && mobile.CurrentMovementTypes.HasMovementType(MovementType.Horizontal); 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()) if (crushables.Any())
{ {
cellFlag |= CellFlag.HasCrushableActor; cellFlag |= CellFlag.HasCrushableActor;

View File

@@ -58,7 +58,7 @@ namespace OpenRA.Mods.Common.Traits
buildBlocked = sequences.GetSequence("overlay", "build-invalid").GetSprite(0); buildBlocked = sequences.GetSequence("overlay", "build-invalid").GetSprite(0);
var buildingInfo = ai.TraitInfo<BuildingInfo>(); 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, 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 Queue: Building.GDI, Building.Nod
Description: Repairs vehicles Description: Repairs vehicles
Building: Building:
Footprint: _=_ === _=_ Footprint: _+_ +++ _+_
Dimensions: 3,3 Dimensions: 3,3
Selectable: Selectable:
Bounds: 64,34,0,3 Bounds: 64,34,0,3

View File

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

View File

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

View File

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