Rework minefield visualisation.
This commit is contained in:
@@ -12,6 +12,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using OpenRA.Graphics;
|
||||||
using OpenRA.Primitives;
|
using OpenRA.Primitives;
|
||||||
using OpenRA.Traits;
|
using OpenRA.Traits;
|
||||||
|
|
||||||
@@ -23,13 +24,15 @@ namespace OpenRA.Activities
|
|||||||
{
|
{
|
||||||
public readonly Target Target;
|
public readonly Target Target;
|
||||||
public readonly Color Color;
|
public readonly Color Color;
|
||||||
|
public readonly Sprite Tile;
|
||||||
|
|
||||||
public TargetLineNode(Target target, Color color)
|
public TargetLineNode(Target target, Color color, Sprite tile = null)
|
||||||
{
|
{
|
||||||
// Note: Not all activities are drawable. In that case, pass Target.Invalid as target,
|
// Note: Not all activities are drawable. In that case, pass Target.Invalid as target,
|
||||||
// if "yield break" in TargetLineNode(Actor self) is not feasible.
|
// if "yield break" in TargetLineNode(Actor self) is not feasible.
|
||||||
Target = target;
|
Target = target;
|
||||||
Color = color;
|
Color = color;
|
||||||
|
Tile = tile;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
*/
|
*/
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using OpenRA.Activities;
|
using OpenRA.Activities;
|
||||||
using OpenRA.Mods.Cnc.Traits;
|
using OpenRA.Mods.Cnc.Traits;
|
||||||
@@ -22,30 +23,43 @@ namespace OpenRA.Mods.Cnc.Activities
|
|||||||
// Assumes you have Minelayer on that unit
|
// Assumes you have Minelayer on that unit
|
||||||
public class LayMines : Activity
|
public class LayMines : Activity
|
||||||
{
|
{
|
||||||
readonly MinelayerInfo info;
|
readonly Minelayer minelayer;
|
||||||
readonly AmmoPool[] ammoPools;
|
readonly AmmoPool[] ammoPools;
|
||||||
readonly IMove movement;
|
readonly IMove movement;
|
||||||
readonly RearmableInfo rearmableInfo;
|
readonly RearmableInfo rearmableInfo;
|
||||||
readonly CPos[] minefield;
|
|
||||||
|
List<CPos> minefield;
|
||||||
|
bool returnToBase;
|
||||||
|
Actor rearmTarget;
|
||||||
|
|
||||||
public LayMines(Actor self, CPos[] minefield)
|
public LayMines(Actor self, CPos[] minefield)
|
||||||
{
|
{
|
||||||
info = self.Info.TraitInfo<MinelayerInfo>();
|
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)
|
||||||
|
this.minefield = minefield.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnFirstRun(Actor self)
|
||||||
|
{
|
||||||
|
if (minefield == null)
|
||||||
|
minefield = new CPos[] { self.Location }.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Tick(Actor self)
|
public override bool Tick(Actor self)
|
||||||
{
|
{
|
||||||
|
returnToBase = false;
|
||||||
|
|
||||||
if (IsCanceling)
|
if (IsCanceling)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (rearmableInfo != null && ammoPools.Any(p => p.Info.Name == info.AmmoPoolName && !p.HasAmmo()))
|
if (rearmableInfo != null && ammoPools.Any(p => p.Info.Name == minelayer.Info.AmmoPoolName && !p.HasAmmo()))
|
||||||
{
|
{
|
||||||
// Rearm (and possibly repair) at rearm building, then back out here to refill the minefield some more
|
// Rearm (and possibly repair) at rearm building, then back out here to refill the minefield some more
|
||||||
var rearmTarget = self.World.Actors.Where(a => self.Owner.Stances[a.Owner] == Stance.Ally
|
rearmTarget = self.World.Actors.Where(a => self.Owner.Stances[a.Owner] == Stance.Ally
|
||||||
&& rearmableInfo.RearmActors.Contains(a.Info.Name))
|
&& rearmableInfo.RearmActors.Contains(a.Info.Name))
|
||||||
.ClosestTo(self);
|
.ClosestTo(self);
|
||||||
|
|
||||||
@@ -56,6 +70,7 @@ namespace OpenRA.Mods.Cnc.Activities
|
|||||||
QueueChild(new MoveAdjacentTo(self, Target.FromActor(rearmTarget)));
|
QueueChild(new MoveAdjacentTo(self, Target.FromActor(rearmTarget)));
|
||||||
QueueChild(movement.MoveTo(self.World.Map.CellContaining(rearmTarget.CenterPosition), rearmTarget));
|
QueueChild(movement.MoveTo(self.World.Map.CellContaining(rearmTarget.CenterPosition), rearmTarget));
|
||||||
QueueChild(new Resupply(self, rearmTarget, new WDist(512)));
|
QueueChild(new Resupply(self, rearmTarget, new WDist(512)));
|
||||||
|
returnToBase = true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,10 +78,11 @@ namespace OpenRA.Mods.Cnc.Activities
|
|||||||
{
|
{
|
||||||
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
|
||||||
|
minefield.Remove(self.Location);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (minefield != null && minefield.Length > 0)
|
if (minefield != null && minefield.Count > 0)
|
||||||
{
|
{
|
||||||
// Don't get stuck forever here
|
// Don't get stuck forever here
|
||||||
for (var n = 0; n < 20; n++)
|
for (var n = 0; n < 20; n++)
|
||||||
@@ -84,6 +100,20 @@ namespace OpenRA.Mods.Cnc.Activities
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<TargetLineNode> TargetLineNodes(Actor self)
|
||||||
|
{
|
||||||
|
if (returnToBase)
|
||||||
|
yield return new TargetLineNode(Target.FromActor(rearmTarget), Color.Green);
|
||||||
|
|
||||||
|
if (minefield == null || minefield.Count == 0)
|
||||||
|
yield break;
|
||||||
|
|
||||||
|
yield return new TargetLineNode(Target.FromCell(self.World, minefield[0]), Color.Crimson);
|
||||||
|
|
||||||
|
foreach (var c in minefield)
|
||||||
|
yield return new TargetLineNode(Target.FromCell(self.World, c), Color.Crimson, tile: minelayer.Tile);
|
||||||
|
}
|
||||||
|
|
||||||
static bool ShouldLayMine(Actor self, CPos p)
|
static bool ShouldLayMine(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 want to place a mine here
|
||||||
@@ -94,14 +124,14 @@ namespace OpenRA.Mods.Cnc.Activities
|
|||||||
{
|
{
|
||||||
if (ammoPools != null)
|
if (ammoPools != null)
|
||||||
{
|
{
|
||||||
var pool = ammoPools.FirstOrDefault(x => x.Info.Name == info.AmmoPoolName);
|
var pool = ammoPools.FirstOrDefault(x => x.Info.Name == minelayer.Info.AmmoPoolName);
|
||||||
if (pool == null)
|
if (pool == null)
|
||||||
return;
|
return;
|
||||||
pool.TakeAmmo(self, 1);
|
pool.TakeAmmo(self, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.World.AddFrameEndTask(
|
self.World.AddFrameEndTask(
|
||||||
w => w.CreateActor(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),
|
||||||
|
|||||||
@@ -37,27 +37,27 @@ namespace OpenRA.Mods.Cnc.Traits
|
|||||||
public object Create(ActorInitializer init) { return new Minelayer(init.Self, this); }
|
public object Create(ActorInitializer init) { return new Minelayer(init.Self, this); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Minelayer : IIssueOrder, IResolveOrder, IRenderAboveShroudWhenSelected, ISync, IIssueDeployOrder, IOrderVoice
|
public class Minelayer : IIssueOrder, IResolveOrder, ISync, IIssueDeployOrder, IOrderVoice
|
||||||
{
|
{
|
||||||
readonly MinelayerInfo info;
|
public readonly MinelayerInfo Info;
|
||||||
|
|
||||||
// TODO: [Sync] when sync can cope with arrays!
|
// TODO: [Sync] when sync can cope with arrays!
|
||||||
public CPos[] Minefield = null;
|
public CPos[] Minefield = null;
|
||||||
|
|
||||||
readonly Sprite tile;
|
public readonly Sprite Tile;
|
||||||
|
|
||||||
[Sync]
|
[Sync]
|
||||||
CPos minefieldStart;
|
CPos minefieldStart;
|
||||||
|
|
||||||
public Minelayer(Actor self, MinelayerInfo info)
|
public Minelayer(Actor self, MinelayerInfo info)
|
||||||
{
|
{
|
||||||
this.info = info;
|
Info = info;
|
||||||
|
|
||||||
var tileset = self.World.Map.Tileset.ToLowerInvariant();
|
var tileset = self.World.Map.Tileset.ToLowerInvariant();
|
||||||
if (self.World.Map.Rules.Sequences.HasSequence("overlay", "build-valid-{0}".F(tileset)))
|
if (self.World.Map.Rules.Sequences.HasSequence("overlay", "build-valid-{0}".F(tileset)))
|
||||||
tile = self.World.Map.Rules.Sequences.GetSequence("overlay", "build-valid-{0}".F(tileset)).GetSprite(0);
|
Tile = self.World.Map.Rules.Sequences.GetSequence("overlay", "build-valid-{0}".F(tileset)).GetSprite(0);
|
||||||
else
|
else
|
||||||
tile = self.World.Map.Rules.Sequences.GetSequence("overlay", "build-valid").GetSprite(0);
|
Tile = self.World.Map.Rules.Sequences.GetSequence("overlay", "build-valid").GetSprite(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerable<IOrderTargeter> IIssueOrder.Orders
|
IEnumerable<IOrderTargeter> IIssueOrder.Orders
|
||||||
@@ -109,19 +109,18 @@ namespace OpenRA.Mods.Cnc.Traits
|
|||||||
{
|
{
|
||||||
var movement = self.Trait<IPositionable>();
|
var movement = self.Trait<IPositionable>();
|
||||||
|
|
||||||
Minefield = GetMinefieldCells(minefieldStart, cell, info.MinefieldDepth)
|
Minefield = GetMinefieldCells(minefieldStart, cell, Info.MinefieldDepth)
|
||||||
.Where(p => movement.CanEnterCell(p, null, false)).ToArray();
|
.Where(p => movement.CanEnterCell(p, null, false)).ToArray();
|
||||||
|
|
||||||
self.QueueActivity(order.Queued, new LayMines(self, Minefield));
|
self.QueueActivity(order.Queued, new LayMines(self, Minefield));
|
||||||
if (Minefield.Length == 1 && Minefield[0] != self.Location)
|
self.ShowTargetLines();
|
||||||
self.ShowTargetLines();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string IOrderVoice.VoicePhraseForOrder(Actor self, Order order)
|
string IOrderVoice.VoicePhraseForOrder(Actor self, Order order)
|
||||||
{
|
{
|
||||||
if (order.OrderString == "PlaceMine" || order.OrderString == "PlaceMinefield")
|
if (order.OrderString == "PlaceMine" || order.OrderString == "PlaceMinefield")
|
||||||
return info.Voice;
|
return Info.Voice;
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -145,23 +144,6 @@ namespace OpenRA.Mods.Cnc.Traits
|
|||||||
yield return new CPos(i, j);
|
yield return new CPos(i, j);
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerable<IRenderable> IRenderAboveShroudWhenSelected.RenderAboveShroud(Actor self, WorldRenderer wr)
|
|
||||||
{
|
|
||||||
if (self.Owner != self.World.LocalPlayer || Minefield == null)
|
|
||||||
yield break;
|
|
||||||
|
|
||||||
// Single-cell mine fields use a target line instead
|
|
||||||
if (Minefield.Length == 1)
|
|
||||||
yield break;
|
|
||||||
|
|
||||||
var pal = wr.Palette(TileSet.TerrainPaletteInternalName);
|
|
||||||
foreach (var c in Minefield)
|
|
||||||
yield return new SpriteRenderable(tile, self.World.Map.CenterOfCell(c),
|
|
||||||
WVec.Zero, -511, pal, 1f, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IRenderAboveShroudWhenSelected.SpatiallyPartitionable { get { return false; } }
|
|
||||||
|
|
||||||
class MinefieldOrderGenerator : OrderGenerator
|
class MinefieldOrderGenerator : OrderGenerator
|
||||||
{
|
{
|
||||||
readonly List<Actor> minelayers;
|
readonly List<Actor> minelayers;
|
||||||
|
|||||||
@@ -81,8 +81,16 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
{
|
{
|
||||||
if (n.Target.Type != TargetType.Invalid)
|
if (n.Target.Type != TargetType.Invalid)
|
||||||
{
|
{
|
||||||
yield return new TargetLineRenderable(new[] { prev, n.Target.CenterPosition }, n.Color, info.LineWidth, info.MarkerWidth);
|
var pal = wr.Palette(TileSet.TerrainPaletteInternalName);
|
||||||
prev = n.Target.CenterPosition;
|
var tile = n.Tile;
|
||||||
|
var pos = n.Target.CenterPosition;
|
||||||
|
|
||||||
|
if (tile == null)
|
||||||
|
yield return new TargetLineRenderable(new[] { prev, pos }, n.Color, info.LineWidth, info.MarkerWidth);
|
||||||
|
else
|
||||||
|
yield return new SpriteRenderable(tile, pos, WVec.Zero, -511, pal, 1f, true);
|
||||||
|
|
||||||
|
prev = pos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user