Disallow units idling on service depot.
This commit is contained in:
@@ -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);
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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>());
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user