Lay mines in order from start to end.

This commit is contained in:
Paul Chote
2019-08-16 22:40:45 +00:00
committed by teinarss
parent 3a51cf0ef8
commit 9aec48aec3
2 changed files with 41 additions and 33 deletions

View File

@@ -32,25 +32,41 @@ namespace OpenRA.Mods.Cnc.Activities
bool returnToBase; bool returnToBase;
Actor rearmTarget; Actor rearmTarget;
public LayMines(Actor self, CPos[] minefield) public LayMines(Actor self, List<CPos> minefield = null)
{ {
minelayer = self.Trait<Minelayer>(); minelayer = self.Trait<Minelayer>();
ammoPools = self.TraitsImplementing<AmmoPool>().ToArray(); ammoPools = self.TraitsImplementing<AmmoPool>().ToArray();
movement = self.Trait<IMove>(); movement = self.Trait<IMove>();
rearmableInfo = self.Info.TraitInfoOrDefault<RearmableInfo>(); rearmableInfo = self.Info.TraitInfoOrDefault<RearmableInfo>();
this.minefield = minefield;
if (minefield != null) ChildHasPriority = false;
this.minefield = minefield.ToList();
} }
protected override void OnFirstRun(Actor self) protected override void OnFirstRun(Actor self)
{ {
if (minefield == null) if (minefield == null)
minefield = new CPos[] { self.Location }.ToList(); minefield = new List<CPos> { self.Location };
}
CPos? NextValidCell(Actor self)
{
if (minefield != null)
foreach (var c in minefield)
if (CanLayMine(self, c))
return c;
return null;
} }
public override bool Tick(Actor self) public override bool Tick(Actor self)
{ {
// Remove cells that have already been mined
minefield.RemoveAll(c => self.World.ActorMap.GetActorsAt(c)
.Any(a => a.Info.Name == minelayer.Info.Mine.ToLowerInvariant()));
if (!TickChild(self))
return false;
returnToBase = false; returnToBase = false;
if (IsCanceling) if (IsCanceling)
@@ -74,7 +90,7 @@ namespace OpenRA.Mods.Cnc.Activities
return false; return false;
} }
if ((minefield == null || minefield.Contains(self.Location)) && ShouldLayMine(self, self.Location)) if ((minefield == null || minefield.Contains(self.Location)) && CanLayMine(self, self.Location))
{ {
LayMine(self); LayMine(self);
QueueChild(new Wait(20)); // A little wait after placing each mine, for show QueueChild(new Wait(20)); // A little wait after placing each mine, for show
@@ -82,18 +98,11 @@ namespace OpenRA.Mods.Cnc.Activities
return false; return false;
} }
if (minefield != null && minefield.Count > 0) var nextCell = NextValidCell(self);
if (nextCell != null)
{ {
// Don't get stuck forever here QueueChild(movement.MoveTo(nextCell.Value, 0));
for (var n = 0; n < 20; n++) return false;
{
var p = minefield.Random(self.World.SharedRandom);
if (ShouldLayMine(self, p))
{
QueueChild(movement.MoveTo(p, 0));
return false;
}
}
} }
// TODO: Return somewhere likely to be safe (near rearm building) so we're not sitting out in the minefield. // TODO: Return somewhere likely to be safe (near rearm building) so we're not sitting out in the minefield.
@@ -108,15 +117,17 @@ namespace OpenRA.Mods.Cnc.Activities
if (minefield == null || minefield.Count == 0) if (minefield == null || minefield.Count == 0)
yield break; yield break;
yield return new TargetLineNode(Target.FromCell(self.World, minefield[0]), Color.Crimson); var nextCell = NextValidCell(self);
if (nextCell != null)
yield return new TargetLineNode(Target.FromCell(self.World, nextCell.Value), Color.Crimson);
foreach (var c in minefield) foreach (var c in minefield)
yield return new TargetLineNode(Target.FromCell(self.World, c), Color.Crimson, tile: minelayer.Tile); yield return new TargetLineNode(Target.FromCell(self.World, c), Color.Crimson, tile: minelayer.Tile);
} }
static bool ShouldLayMine(Actor self, CPos p) static bool CanLayMine(Actor self, CPos p)
{ {
// If there is no unit (other than me) here, we want to place a mine here // If there is no unit (other than me) here, we can place a mine here
return self.World.ActorMap.GetActorsAt(p).All(a => a == self); return self.World.ActorMap.GetActorsAt(p).All(a => a == self);
} }
@@ -130,12 +141,11 @@ namespace OpenRA.Mods.Cnc.Activities
pool.TakeAmmo(self, 1); pool.TakeAmmo(self, 1);
} }
self.World.AddFrameEndTask( self.World.AddFrameEndTask(w => w.CreateActor(minelayer.Info.Mine, new TypeDictionary
w => w.CreateActor(minelayer.Info.Mine, new TypeDictionary {
{ new LocationInit(self.Location),
new LocationInit(self.Location), new OwnerInit(self.Owner),
new OwnerInit(self.Owner), }));
}));
} }
} }
} }

View File

@@ -41,9 +41,6 @@ namespace OpenRA.Mods.Cnc.Traits
{ {
public readonly MinelayerInfo Info; public readonly MinelayerInfo Info;
// TODO: [Sync] when sync can cope with arrays!
public CPos[] Minefield = null;
public readonly Sprite Tile; public readonly Sprite Tile;
[Sync] [Sync]
@@ -104,15 +101,16 @@ namespace OpenRA.Mods.Cnc.Traits
if (order.OrderString == "BeginMinefield") if (order.OrderString == "BeginMinefield")
minefieldStart = cell; minefieldStart = cell;
else if (order.OrderString == "PlaceMine") else if (order.OrderString == "PlaceMine")
self.QueueActivity(order.Queued, new LayMines(self, null)); self.QueueActivity(order.Queued, new LayMines(self));
else if (order.OrderString == "PlaceMinefield") else if (order.OrderString == "PlaceMinefield")
{ {
var movement = self.Trait<IPositionable>(); var movement = self.Trait<IPositionable>();
Minefield = GetMinefieldCells(minefieldStart, cell, Info.MinefieldDepth) var minefield = GetMinefieldCells(minefieldStart, cell, Info.MinefieldDepth)
.Where(p => movement.CanEnterCell(p, null, false)).ToArray(); .Where(c => movement.CanEnterCell(c, null, false))
.OrderBy(c => (c - minefieldStart).LengthSquared).ToList();
self.QueueActivity(order.Queued, new LayMines(self, Minefield)); self.QueueActivity(order.Queued, new LayMines(self, minefield));
self.ShowTargetLines(); self.ShowTargetLines();
} }
} }