Added valid TerrainTypes to the Minelayer trait

Also added a configurable deploy cursor and fixed Minelayer target cell validation checks, which should make for a much better experiencing when dragging over an area with blocking terrain, shroud, fog, etc.
This commit is contained in:
Pavel Penev
2020-03-24 16:55:40 +02:00
committed by abcdefg30
parent 538623c835
commit 4135045ca4
2 changed files with 44 additions and 8 deletions

View File

@@ -43,21 +43,33 @@ namespace OpenRA.Mods.Cnc.Traits
[Desc("Sprite overlay to use for minefield cells hidden behind fog or shroud.")] [Desc("Sprite overlay to use for minefield cells hidden behind fog or shroud.")]
public readonly string TileUnknownName = "build-unknown"; public readonly string TileUnknownName = "build-unknown";
[Desc("Only allow laying mines on listed terrain types. Leave empty to allow all terrain types.")]
public readonly HashSet<string> TerrainTypes = new HashSet<string>();
[Desc("Cursor to display when able to lay a mine.")]
public readonly string DeployCursor = "deploy";
[Desc("Cursor to display when unable to lay a mine.")]
public readonly string DeployBlockedCursor = "deploy-blocked";
public override object Create(ActorInitializer init) { return new Minelayer(init.Self, this); } public override object Create(ActorInitializer init) { return new Minelayer(init.Self, this); }
} }
public class Minelayer : IIssueOrder, IResolveOrder, ISync, IIssueDeployOrder, IOrderVoice, ITick public class Minelayer : IIssueOrder, IResolveOrder, ISync, IIssueDeployOrder, IOrderVoice, ITick
{ {
public readonly MinelayerInfo Info; public readonly MinelayerInfo Info;
public readonly Sprite Tile; public readonly Sprite Tile;
readonly Actor self;
[Sync] [Sync]
CPos minefieldStart; CPos minefieldStart;
public Minelayer(Actor self, MinelayerInfo info) public Minelayer(Actor self, MinelayerInfo info)
{ {
Info = info; Info = info;
this.self = self;
var tileset = self.World.Map.Tileset.ToLowerInvariant(); var tileset = self.World.Map.Tileset.ToLowerInvariant();
if (self.World.Map.Rules.Sequences.HasSequence("overlay", "{0}-{1}".F(Info.TileValidName, tileset))) if (self.World.Map.Rules.Sequences.HasSequence("overlay", "{0}-{1}".F(Info.TileValidName, tileset)))
Tile = self.World.Map.Rules.Sequences.GetSequence("overlay", "{0}-{1}".F(Info.TileValidName, tileset)).GetSprite(0); Tile = self.World.Map.Rules.Sequences.GetSequence("overlay", "{0}-{1}".F(Info.TileValidName, tileset)).GetSprite(0);
@@ -70,7 +82,7 @@ namespace OpenRA.Mods.Cnc.Traits
get get
{ {
yield return new BeginMinefieldOrderTargeter(); yield return new BeginMinefieldOrderTargeter();
yield return new DeployOrderTargeter("PlaceMine", 5); yield return new DeployOrderTargeter("PlaceMine", 5, () => IsCellAcceptable(self, self.Location) ? Info.DeployCursor : Info.DeployBlockedCursor);
} }
} }
@@ -98,7 +110,10 @@ namespace OpenRA.Mods.Cnc.Traits
return new Order("PlaceMine", self, Target.FromCell(self.World, self.Location), queued); return new Order("PlaceMine", self, Target.FromCell(self.World, self.Location), queued);
} }
bool IIssueDeployOrder.CanIssueDeployOrder(Actor self, bool queued) { return true; } bool IIssueDeployOrder.CanIssueDeployOrder(Actor self, bool queued)
{
return IsCellAcceptable(self, self.Location);
}
void IResolveOrder.ResolveOrder(Actor self, Order order) void IResolveOrder.ResolveOrder(Actor self, Order order)
{ {
@@ -109,17 +124,21 @@ 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)); {
if (IsCellAcceptable(self, cell))
self.QueueActivity(order.Queued, new LayMines(self));
}
else if (order.OrderString == "PlaceMinefield") else if (order.OrderString == "PlaceMinefield")
{ {
// A different minelayer might have started laying the field without this minelayer knowing the start // A different minelayer might have started laying the field without this minelayer knowing the start
minefieldStart = order.ExtraLocation; minefieldStart = order.ExtraLocation;
var movement = self.Trait<IPositionable>(); var movement = self.Trait<IPositionable>();
var mobile = movement as Mobile;
var minefield = GetMinefieldCells(minefieldStart, cell, Info.MinefieldDepth) var minefield = GetMinefieldCells(minefieldStart, cell, Info.MinefieldDepth)
.Where(c => movement.CanEnterCell(c, null, BlockedByActor.Immovable) .Where(c => IsCellAcceptable(self, c) && self.Owner.Shroud.IsExplored(c)
|| (!self.Owner.Shroud.IsVisible(c) && self.World.Map.Contains(c))) && movement.CanEnterCell(c, null, BlockedByActor.Immovable) && (mobile != null && mobile.CanStayInCell(c)))
.OrderBy(c => (c - minefieldStart).LengthSquared).ToList(); .OrderBy(c => (c - minefieldStart).LengthSquared).ToList();
self.QueueActivity(order.Queued, new LayMines(self, minefield)); self.QueueActivity(order.Queued, new LayMines(self, minefield));
@@ -161,9 +180,22 @@ namespace OpenRA.Mods.Cnc.Traits
yield return new CPos(i, j); yield return new CPos(i, j);
} }
public bool IsCellAcceptable(Actor self, CPos cell)
{
if (!self.World.Map.Contains(cell))
return false;
if (Info.TerrainTypes.Count == 0)
return true;
var terrainType = self.World.Map.GetTerrainInfo(cell).Type;
return Info.TerrainTypes.Contains(terrainType);
}
class MinefieldOrderGenerator : OrderGenerator class MinefieldOrderGenerator : OrderGenerator
{ {
readonly List<Actor> minelayers; readonly List<Actor> minelayers;
readonly Minelayer minelayer;
readonly Sprite tileOk; readonly Sprite tileOk;
readonly Sprite tileUnknown; readonly Sprite tileUnknown;
readonly Sprite tileBlocked; readonly Sprite tileBlocked;
@@ -176,7 +208,7 @@ namespace OpenRA.Mods.Cnc.Traits
minefieldStart = xy; minefieldStart = xy;
this.queued = queued; this.queued = queued;
var minelayer = a.Trait<Minelayer>(); minelayer = a.Trait<Minelayer>();
var tileset = a.World.Map.Tileset.ToLowerInvariant(); var tileset = a.World.Map.Tileset.ToLowerInvariant();
if (a.World.Map.Rules.Sequences.HasSequence("overlay", "{0}-{1}".F(minelayer.Info.TileValidName, tileset))) if (a.World.Map.Rules.Sequences.HasSequence("overlay", "{0}-{1}".F(minelayer.Info.TileValidName, tileset)))
tileOk = a.World.Map.Rules.Sequences.GetSequence("overlay", "{0}-{1}".F(minelayer.Info.TileValidName, tileset)).GetSprite(0); tileOk = a.World.Map.Rules.Sequences.GetSequence("overlay", "{0}-{1}".F(minelayer.Info.TileValidName, tileset)).GetSprite(0);
@@ -243,9 +275,12 @@ namespace OpenRA.Mods.Cnc.Traits
var tile = tileOk; var tile = tileOk;
if (!world.Map.Contains(c)) if (!world.Map.Contains(c))
tile = tileBlocked; tile = tileBlocked;
else if (world.ShroudObscures(c))
tile = tileBlocked;
else if (world.FogObscures(c)) else if (world.FogObscures(c))
tile = tileUnknown; tile = tileUnknown;
else if (!movement.CanEnterCell(c, null, BlockedByActor.Immovable) || (mobile != null && !mobile.CanStayInCell(c))) else if (!this.minelayer.IsCellAcceptable(minelayer, c)
|| !movement.CanEnterCell(c, null, BlockedByActor.Immovable) || (mobile != null && !mobile.CanStayInCell(c)))
tile = tileBlocked; tile = tileBlocked;
yield return new SpriteRenderable(tile, world.Map.CenterOfCell(c), WVec.Zero, -511, pal, 1f, true, true); yield return new SpriteRenderable(tile, world.Map.CenterOfCell(c), WVec.Zero, -511, pal, 1f, true, true);

View File

@@ -501,6 +501,7 @@ MNLY:
Minelayer: Minelayer:
Mine: MINV Mine: MINV
TileUnknownName: build-valid TileUnknownName: build-valid
TerrainTypes: Clear, Road, Beach, Ore, Gems, Rough, Bridge
MineImmune: MineImmune:
AmmoPool: AmmoPool:
Ammo: 5 Ammo: 5