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.")]
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 class Minelayer : IIssueOrder, IResolveOrder, ISync, IIssueDeployOrder, IOrderVoice, ITick
{
public readonly MinelayerInfo Info;
public readonly Sprite Tile;
readonly Actor self;
[Sync]
CPos minefieldStart;
public Minelayer(Actor self, MinelayerInfo info)
{
Info = info;
this.self = self;
var tileset = self.World.Map.Tileset.ToLowerInvariant();
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);
@@ -70,7 +82,7 @@ namespace OpenRA.Mods.Cnc.Traits
get
{
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);
}
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)
{
@@ -109,17 +124,21 @@ namespace OpenRA.Mods.Cnc.Traits
if (order.OrderString == "BeginMinefield")
minefieldStart = cell;
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")
{
// A different minelayer might have started laying the field without this minelayer knowing the start
minefieldStart = order.ExtraLocation;
var movement = self.Trait<IPositionable>();
var mobile = movement as Mobile;
var minefield = GetMinefieldCells(minefieldStart, cell, Info.MinefieldDepth)
.Where(c => movement.CanEnterCell(c, null, BlockedByActor.Immovable)
|| (!self.Owner.Shroud.IsVisible(c) && self.World.Map.Contains(c)))
.Where(c => IsCellAcceptable(self, c) && self.Owner.Shroud.IsExplored(c)
&& movement.CanEnterCell(c, null, BlockedByActor.Immovable) && (mobile != null && mobile.CanStayInCell(c)))
.OrderBy(c => (c - minefieldStart).LengthSquared).ToList();
self.QueueActivity(order.Queued, new LayMines(self, minefield));
@@ -161,9 +180,22 @@ namespace OpenRA.Mods.Cnc.Traits
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
{
readonly List<Actor> minelayers;
readonly Minelayer minelayer;
readonly Sprite tileOk;
readonly Sprite tileUnknown;
readonly Sprite tileBlocked;
@@ -176,7 +208,7 @@ namespace OpenRA.Mods.Cnc.Traits
minefieldStart = xy;
this.queued = queued;
var minelayer = a.Trait<Minelayer>();
minelayer = a.Trait<Minelayer>();
var tileset = a.World.Map.Tileset.ToLowerInvariant();
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);
@@ -243,9 +275,12 @@ namespace OpenRA.Mods.Cnc.Traits
var tile = tileOk;
if (!world.Map.Contains(c))
tile = tileBlocked;
else if (world.ShroudObscures(c))
tile = tileBlocked;
else if (world.FogObscures(c))
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;
yield return new SpriteRenderable(tile, world.Map.CenterOfCell(c), WVec.Zero, -511, pal, 1f, true, true);

View File

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