Replace Map.CustomTerrain radar colors with IRadarTerrainLayer.

* TSVeinsRenderer now shows border cells on the radar
* BuildableTerrainLayer now uses the radar colors defined on the individual tiles
* CliffBackImpassabilityLayer no longer overrides the underlying terrain color.
This commit is contained in:
Paul Chote
2021-08-20 18:43:22 +01:00
committed by abcdefg30
parent 72c0c7e38b
commit 7f94d67d39
11 changed files with 278 additions and 58 deletions

View File

@@ -675,16 +675,10 @@ namespace OpenRA
public (Color Left, Color Right) GetTerrainColorPair(MPos uv)
{
Color left, right;
var terrainInfo = Rules.TerrainInfo;
var type = terrainInfo.GetTerrainInfo(Tiles[uv]);
if (type.MinColor != type.MaxColor)
{
left = Exts.ColorLerp(Game.CosmeticRandom.NextFloat(), type.MinColor, type.MaxColor);
right = Exts.ColorLerp(Game.CosmeticRandom.NextFloat(), type.MinColor, type.MaxColor);
}
else
left = right = type.MinColor;
var left = type.GetColor(Game.CosmeticRandom);
var right = type.GetColor(Game.CosmeticRandom);
if (terrainInfo.MinHeightColorBrightness != 1.0f || terrainInfo.MaxHeightColorBrightness != 1.0f)
{

View File

@@ -12,6 +12,7 @@
using System.Collections.Generic;
using OpenRA.FileSystem;
using OpenRA.Primitives;
using OpenRA.Support;
using OpenRA.Traits;
namespace OpenRA
@@ -45,6 +46,14 @@ namespace OpenRA
public readonly byte RampType;
public readonly Color MinColor;
public readonly Color MaxColor;
public Color GetColor(MersenneTwister random)
{
if (MinColor != MaxColor)
return Exts.ColorLerp(random.NextFloat(), MinColor, MaxColor);
return MinColor;
}
}
public class TerrainTypeInfo

View File

@@ -13,6 +13,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Common;
using OpenRA.Mods.Common.Traits;
using OpenRA.Primitives;
using OpenRA.Traits;
@@ -20,7 +21,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Cnc.Traits
{
[Desc("Renders the Tiberian Sun Vein resources.", "Attach this to the world actor")]
public class TSVeinsRendererInfo : TraitInfo, Requires<IResourceLayerInfo>
public class TSVeinsRendererInfo : TraitInfo, Requires<IResourceLayerInfo>, IMapPreviewSignatureInfo
{
[FieldLoader.Require]
[Desc("Resource type used for veins.")]
@@ -45,10 +46,69 @@ namespace OpenRA.Mods.Cnc.Traits
[Desc("Actor types that should be treated as veins for adjacency.")]
public readonly HashSet<string> VeinholeActors = new HashSet<string> { };
void IMapPreviewSignatureInfo.PopulateMapPreviewSignatureCells(Map map, ActorInfo ai, ActorReference s, List<(MPos, Color)> destinationBuffer)
{
var resourceLayer = ai.TraitInfoOrDefault<IResourceLayerInfo>();
if (resourceLayer == null)
return;
if (!resourceLayer.TryGetResourceIndex(ResourceType, out var resourceIndex) || !resourceLayer.TryGetTerrainType(ResourceType, out var terrainType))
return;
var veinholeCells = new HashSet<CPos>();
foreach (var kv in map.ActorDefinitions)
{
var type = kv.Value.Value;
if (!VeinholeActors.Contains(type))
continue;
var actorReference = new ActorReference(type, kv.Value.ToDictionary());
var location = actorReference.Get<LocationInit>();
var veinholeInfo = map.Rules.Actors[actorReference.Type];
foreach (var cell in veinholeInfo.TraitInfo<IOccupySpaceInfo>().OccupiedCells(veinholeInfo, location.Value))
veinholeCells.Add(cell.Key);
}
var terrainInfo = map.Rules.TerrainInfo;
var info = terrainInfo.TerrainTypes[terrainInfo.GetTerrainIndex(terrainType)];
for (var i = 0; i < map.MapSize.X; i++)
{
for (var j = 0; j < map.MapSize.Y; j++)
{
var uv = new MPos(i, j);
// Cell contains veins
if (map.Resources[uv].Type == resourceIndex)
{
destinationBuffer.Add((uv, info.Color));
continue;
}
// Cell is a vein border if it is flat and adjacent to at least one cell
// that is also flat and contains veins (borders are not drawn next to slope vein cells)
var isBorder = map.Ramp[uv] == 0 && Common.Util.ExpandFootprint(uv.ToCPos(map), false).Any(c =>
{
if (!map.Resources.Contains(c))
return false;
if (veinholeCells.Contains(c))
return true;
return map.Resources[c].Type == resourceIndex && map.Ramp[c] == 0;
});
if (isBorder)
destinationBuffer.Add((uv, info.Color));
}
}
}
public override object Create(ActorInitializer init) { return new TSVeinsRenderer(init.Self, this); }
}
public class TSVeinsRenderer : IResourceRenderer, IWorldLoaded, IRenderOverlay, ITickRender, INotifyActorDisposing
public class TSVeinsRenderer : IResourceRenderer, IWorldLoaded, IRenderOverlay, ITickRender, INotifyActorDisposing, IRadarTerrainLayer
{
[Flags]
enum Adjacency : byte
@@ -95,6 +155,7 @@ namespace OpenRA.Mods.Cnc.Traits
readonly Queue<CPos> cleanDirty = new Queue<CPos>();
readonly HashSet<CPos> veinholeCells = new HashSet<CPos>();
readonly int maxDensity;
readonly Color veinRadarColor;
ISpriteSequence veinSequence;
PaletteReference veinPalette;
@@ -109,6 +170,10 @@ namespace OpenRA.Mods.Cnc.Traits
resourceLayer.CellChanged += AddDirtyCell;
maxDensity = resourceLayer.GetMaxDensity(info.ResourceType);
var terrainInfo = self.World.Map.Rules.TerrainInfo;
resourceLayer.Info.TryGetTerrainType(info.ResourceType, out var terrainType);
veinRadarColor = terrainInfo.TerrainTypes[terrainInfo.GetTerrainIndex(terrainType)].Color;
renderIndices = new CellLayer<int[]>(world.Map);
borders = new CellLayer<Adjacency>(world.Map);
}
@@ -334,5 +399,30 @@ namespace OpenRA.Mods.Cnc.Traits
var tintModifiers = veinSequence.IgnoreWorldTint ? TintModifiers.IgnoreWorldTint : TintModifiers.None;
yield return new SpriteRenderable(sprite, origin, WVec.Zero, 0, palette, veinSequence.Scale, alpha, float3.Ones, tintModifiers, false);
}
event Action<CPos> IRadarTerrainLayer.CellEntryChanged
{
add
{
renderIndices.CellEntryChanged += value;
borders.CellEntryChanged += value;
}
remove
{
renderIndices.CellEntryChanged -= value;
borders.CellEntryChanged -= value;
}
}
bool IRadarTerrainLayer.TryGetTerrainColorPair(MPos uv, out (Color Left, Color Right) value)
{
value = default;
if (borders[uv] == Adjacency.None && renderIndices[uv] == null)
return false;
value = (veinRadarColor, veinRadarColor);
return true;
}
}
}

View File

@@ -93,7 +93,7 @@ namespace OpenRA.Mods.Common.Traits
}
}
class Bridge : IRender, INotifyDamageStateChanged
class Bridge : IRender, INotifyDamageStateChanged, IRadarSignature
{
readonly BuildingInfo buildingInfo;
readonly Bridge[] neighbours = new Bridge[2];
@@ -108,6 +108,7 @@ namespace OpenRA.Mods.Common.Traits
readonly Lazy<bool> isDangling;
ushort template;
Dictionary<CPos, byte> footprint;
(CPos Cell, Color Color)[] radarSignature;
public LegacyBridgeHut Hut { get; private set; }
public bool IsDangling => isDangling.Value;
@@ -147,17 +148,23 @@ namespace OpenRA.Mods.Common.Traits
{
this.template = template;
this.footprint = footprint;
radarSignature = new (CPos Cell, Color Color)[footprint.Keys.Count];
// Set the initial custom terrain types
// Set the initial state
var i = 0;
foreach (var c in footprint.Keys)
self.World.Map.CustomTerrain[c] = GetTerrainType(c);
{
var tileInfo = GetTerrainInfo(c);
self.World.Map.CustomTerrain[c] = tileInfo.TerrainType;
radarSignature[i++] = (c, tileInfo.GetColor(self.World.LocalRandom));
}
}
byte GetTerrainType(CPos cell)
TerrainTileInfo GetTerrainInfo(CPos cell)
{
var dx = cell - self.Location;
var index = dx.X + terrainInfo.Templates[template].Size.X * dx.Y;
return terrainInfo.GetTerrainIndex(new TerrainTile(template, (byte)index));
return terrainInfo.GetTerrainInfo(new TerrainTile(template, (byte)index));
}
public void LinkNeighbouringBridges(World world, LegacyBridgeLayer bridges)
@@ -308,8 +315,13 @@ namespace OpenRA.Mods.Common.Traits
return;
// Update map
var i = 0;
foreach (var c in footprint.Keys)
self.World.Map.CustomTerrain[c] = GetTerrainType(c);
{
var tileInfo = GetTerrainInfo(c);
self.World.Map.CustomTerrain[c] = tileInfo.TerrainType;
radarSignature[i++] = (c, tileInfo.GetColor(self.World.LocalRandom));
}
// If this bridge repair operation connects two pathfinding domains,
// update the domain index.
@@ -401,5 +413,10 @@ namespace OpenRA.Mods.Common.Traits
neighbours[direction].Demolish(saboteur, direction, damageTypes))));
}
}
void IRadarSignature.PopulateRadarSignatureCells(Actor self, List<(CPos Cell, Color Color)> destinationBuffer)
{
destinationBuffer.AddRange(radarSignature);
}
}
}

View File

@@ -10,6 +10,7 @@
#endregion
using System;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Traits;
@@ -29,6 +30,7 @@ namespace OpenRA.Mods.Common.Traits
public bool IsInitialized { get; private set; }
readonly World world;
IRadarTerrainLayer[] radarTerrainLayers;
CellLayer<(int, int)> terrainColor;
readonly Shroud shroud;
@@ -50,22 +52,20 @@ namespace OpenRA.Mods.Common.Traits
void UpdateTerrainCell(MPos uv)
{
if (!world.Map.CustomTerrain.Contains(uv))
return;
if (shroud.IsVisible(uv))
UpdateTerrainCellColor(uv);
}
void UpdateTerrainCellColor(MPos uv)
{
terrainColor[uv] = GetColor(world.Map, uv);
terrainColor[uv] = GetColor(world.Map, radarTerrainLayers, uv);
CellTerrainColorChanged?.Invoke(uv);
}
public void WorldLoaded(World w, WorldRenderer wr)
{
radarTerrainLayers = w.WorldActor.TraitsImplementing<IRadarTerrainLayer>().ToArray();
terrainColor = new CellLayer<(int, int)>(w.Map);
w.AddFrameEndTask(_ =>
@@ -75,7 +75,8 @@ namespace OpenRA.Mods.Common.Traits
UpdateTerrainCellColor(uv);
world.Map.Tiles.CellEntryChanged += cell => UpdateTerrainCell(cell.ToMPos(world.Map));
world.Map.CustomTerrain.CellEntryChanged += cell => UpdateTerrainCell(cell.ToMPos(world.Map));
foreach (var rtl in radarTerrainLayers)
rtl.CellEntryChanged += cell => UpdateTerrainCell(cell.ToMPos(world.Map));
IsInitialized = true;
});
@@ -83,14 +84,11 @@ namespace OpenRA.Mods.Common.Traits
public (int Left, int Right) this[MPos uv] => terrainColor[uv];
public static (int Left, int Right) GetColor(Map map, MPos uv)
public static (int Left, int Right) GetColor(Map map, IRadarTerrainLayer[] radarTerrainLayers, MPos uv)
{
var custom = map.CustomTerrain[uv];
if (custom != byte.MaxValue)
{
var c = map.Rules.TerrainInfo.TerrainTypes[custom].Color.ToArgb();
return (c, c);
}
foreach (var rtl in radarTerrainLayers)
if (rtl.TryGetTerrainColorPair(uv, out var c))
return (c.Left.ToArgb(), c.Right.ToArgb());
var tc = map.GetTerrainColorPair(uv);
return (tc.Left.ToArgb(), tc.Right.ToArgb());

View File

@@ -20,7 +20,7 @@ namespace OpenRA.Mods.Common.Traits
{
[TraitLocation(SystemActors.EditorWorld)]
[Desc("Required for the map editor to work. Attach this to the world actor.")]
public class EditorResourceLayerInfo : TraitInfo, IResourceLayerInfo, IMapPreviewSignatureInfo
public class EditorResourceLayerInfo : TraitInfo, IResourceLayerInfo
{
[FieldLoader.LoadUsing(nameof(LoadResourceTypes))]
public readonly Dictionary<string, ResourceLayerInfo.ResourceTypeInfo> ResourceTypes = null;
@@ -40,9 +40,28 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Override the density saved in maps with values calculated based on the number of neighbouring resource cells.")]
public readonly bool RecalculateResourceDensity = false;
void IMapPreviewSignatureInfo.PopulateMapPreviewSignatureCells(Map map, ActorInfo ai, ActorReference s, List<(MPos, Color)> destinationBuffer)
bool IResourceLayerInfo.TryGetTerrainType(string resourceType, out string terrainType)
{
ResourceLayerInfo.PopulateMapPreviewSignatureCells(map, ResourceTypes, destinationBuffer);
if (resourceType == null || !ResourceTypes.TryGetValue(resourceType, out var resourceInfo))
{
terrainType = null;
return false;
}
terrainType = resourceInfo.TerrainType;
return true;
}
bool IResourceLayerInfo.TryGetResourceIndex(string resourceType, out byte index)
{
if (resourceType == null || !ResourceTypes.TryGetValue(resourceType, out var resourceInfo))
{
index = 0;
return false;
}
index = resourceInfo.ResourceIndex;
return true;
}
public override object Create(ActorInitializer init) { return new EditorResourceLayer(init.Self, this); }
@@ -74,6 +93,7 @@ namespace OpenRA.Mods.Common.Traits
void IResourceLayer.ClearResources(CPos cell) { ClearResources(cell); }
bool IResourceLayer.IsVisible(CPos cell) { return Map.Contains(cell); }
bool IResourceLayer.IsEmpty => false;
IResourceLayerInfo IResourceLayer.Info => info;
public EditorResourceLayer(Actor self, EditorResourceLayerInfo info)
{

View File

@@ -33,7 +33,7 @@ namespace OpenRA.Mods.Common.Traits
[TraitLocation(SystemActors.World)]
[Desc("Attach this to the world actor.")]
public class ResourceLayerInfo : TraitInfo, IResourceLayerInfo, Requires<BuildingInfluenceInfo>, IMapPreviewSignatureInfo
public class ResourceLayerInfo : TraitInfo, IResourceLayerInfo, Requires<BuildingInfluenceInfo>
{
public class ResourceTypeInfo
{
@@ -76,27 +76,28 @@ namespace OpenRA.Mods.Common.Traits
return ret;
}
public static void PopulateMapPreviewSignatureCells(Map map, Dictionary<string, ResourceTypeInfo> resources, List<(MPos, Color)> destinationBuffer)
bool IResourceLayerInfo.TryGetTerrainType(string resourceType, out string terrainType)
{
var terrainInfo = map.Rules.TerrainInfo;
var colors = resources.Values.ToDictionary(
r => r.ResourceIndex,
r => terrainInfo.TerrainTypes[terrainInfo.GetTerrainIndex(r.TerrainType)].Color);
for (var i = 0; i < map.MapSize.X; i++)
if (resourceType == null || !ResourceTypes.TryGetValue(resourceType, out var resourceInfo))
{
for (var j = 0; j < map.MapSize.Y; j++)
{
var cell = new MPos(i, j);
if (colors.TryGetValue(map.Resources[cell].Type, out var color))
destinationBuffer.Add((cell, color));
}
}
terrainType = null;
return false;
}
void IMapPreviewSignatureInfo.PopulateMapPreviewSignatureCells(Map map, ActorInfo ai, ActorReference s, List<(MPos, Color)> destinationBuffer)
terrainType = resourceInfo.TerrainType;
return true;
}
bool IResourceLayerInfo.TryGetResourceIndex(string resourceType, out byte index)
{
PopulateMapPreviewSignatureCells(map, ResourceTypes, destinationBuffer);
if (resourceType == null || !ResourceTypes.TryGetValue(resourceType, out var resourceInfo))
{
index = 0;
return false;
}
index = resourceInfo.ResourceIndex;
return true;
}
public override object Create(ActorInitializer init) { return new ResourceLayer(init.Self, this); }
@@ -299,5 +300,6 @@ namespace OpenRA.Mods.Common.Traits
void IResourceLayer.ClearResources(CPos cell) { ClearResources(cell); }
bool IResourceLayer.IsVisible(CPos cell) { return !world.FogObscures(cell); }
bool IResourceLayer.IsEmpty => resCells < 1;
IResourceLayerInfo IResourceLayer.Info => info;
}
}

View File

@@ -9,6 +9,7 @@
*/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -20,7 +21,7 @@ namespace OpenRA.Mods.Common.Traits
{
[TraitLocation(SystemActors.World | SystemActors.EditorWorld)]
[Desc("Visualizes the state of the `ResourceLayer`.", " Attach this to the world actor.")]
public class ResourceRendererInfo : TraitInfo, Requires<IResourceLayerInfo>
public class ResourceRendererInfo : TraitInfo, Requires<IResourceLayerInfo>, IMapPreviewSignatureInfo
{
public class ResourceTypeInfo
{
@@ -61,10 +62,38 @@ namespace OpenRA.Mods.Common.Traits
return ret;
}
void IMapPreviewSignatureInfo.PopulateMapPreviewSignatureCells(Map map, ActorInfo ai, ActorReference s, List<(MPos, Color)> destinationBuffer)
{
var resourceLayer = ai.TraitInfoOrDefault<IResourceLayerInfo>();
if (resourceLayer == null)
return;
var terrainInfo = map.Rules.TerrainInfo;
var colors = new Dictionary<byte, Color>();
foreach (var r in ResourceTypes.Keys)
{
if (!resourceLayer.TryGetResourceIndex(r, out var resourceIndex) || !resourceLayer.TryGetTerrainType(r, out var terrainType))
continue;
var info = terrainInfo.TerrainTypes[terrainInfo.GetTerrainIndex(terrainType)];
colors.Add(resourceIndex, info.Color);
}
for (var i = 0; i < map.MapSize.X; i++)
{
for (var j = 0; j < map.MapSize.Y; j++)
{
var cell = new MPos(i, j);
if (colors.TryGetValue(map.Resources[cell].Type, out var color))
destinationBuffer.Add((cell, color));
}
}
}
public override object Create(ActorInitializer init) { return new ResourceRenderer(init.Self, this); }
}
public class ResourceRenderer : IResourceRenderer, IWorldLoaded, IRenderOverlay, ITickRender, INotifyActorDisposing
public class ResourceRenderer : IResourceRenderer, IWorldLoaded, IRenderOverlay, ITickRender, INotifyActorDisposing, IRadarTerrainLayer
{
protected readonly ResourceRendererInfo Info;
protected readonly IResourceLayer ResourceLayer;
@@ -284,6 +313,30 @@ namespace OpenRA.Mods.Common.Traits
yield return new SpriteRenderable(sprite, origin, WVec.Zero, 0, palette, sequence.Scale, alpha, float3.Ones, tintModifiers, false);
}
event Action<CPos> IRadarTerrainLayer.CellEntryChanged
{
add => RenderContents.CellEntryChanged += value;
remove => RenderContents.CellEntryChanged -= value;
}
bool IRadarTerrainLayer.TryGetTerrainColorPair(MPos uv, out (Color Left, Color Right) value)
{
value = default;
var type = RenderContents[uv].Type;
if (type == null)
return false;
if (!ResourceLayer.Info.TryGetTerrainType(type, out var terrainType))
return false;
var terrainInfo = World.Map.Rules.TerrainInfo;
var info = terrainInfo.TerrainTypes[terrainInfo.GetTerrainIndex(terrainType)];
value = (info.Color, info.Color);
return true;
}
public readonly struct RendererCellContents
{
public readonly string Type;

View File

@@ -677,7 +677,11 @@ namespace OpenRA.Mods.Common.Traits
IEnumerable<IRenderable> RenderPreview(WorldRenderer wr, TerrainTemplateInfo template, WPos origin);
}
public interface IResourceLayerInfo : ITraitInfoInterface { }
public interface IResourceLayerInfo : ITraitInfoInterface
{
bool TryGetTerrainType(string resourceType, out string terrainType);
bool TryGetResourceIndex(string resourceType, out byte index);
}
[RequireExplicitImplementation]
public interface IResourceLayer
@@ -692,6 +696,7 @@ namespace OpenRA.Mods.Common.Traits
bool IsVisible(CPos cell);
bool IsEmpty { get; }
IResourceLayerInfo Info { get; }
}
[RequireExplicitImplementation]
@@ -703,4 +708,11 @@ namespace OpenRA.Mods.Common.Traits
IEnumerable<IRenderable> RenderUIPreview(WorldRenderer wr, string resourceType, int2 origin, float scale);
IEnumerable<IRenderable> RenderPreview(WorldRenderer wr, string resourceType, WPos origin);
}
[RequireExplicitImplementation]
public interface IRadarTerrainLayer
{
event Action<CPos> CellEntryChanged;
bool TryGetTerrainColorPair(MPos uv, out (Color Left, Color Right) value);
}
}

View File

@@ -34,6 +34,7 @@ namespace OpenRA.Mods.Common.Widgets
readonly World world;
readonly WorldRenderer worldRenderer;
readonly RadarPings radarPings;
readonly IRadarTerrainLayer[] radarTerrainLayers;
readonly bool isRectangularIsometric;
readonly int cellWidth;
readonly int previewWidth;
@@ -69,7 +70,7 @@ namespace OpenRA.Mods.Common.Widgets
this.worldRenderer = worldRenderer;
radarPings = world.WorldActor.TraitOrDefault<RadarPings>();
radarTerrainLayers = world.WorldActor.TraitsImplementing<IRadarTerrainLayer>().ToArray();
isRectangularIsometric = world.Map.Grid.Type == MapGridType.RectangularIsometric;
cellWidth = isRectangularIsometric ? 2 : 1;
previewWidth = world.Map.MapSize.X;
@@ -152,7 +153,8 @@ namespace OpenRA.Mods.Common.Widgets
else
{
world.Map.Tiles.CellEntryChanged -= CellTerrainColorChanged;
world.Map.CustomTerrain.CellEntryChanged -= CellTerrainColorChanged;
foreach (var rtl in radarTerrainLayers)
rtl.CellEntryChanged -= CellTerrainColorChanged;
}
if (newPlayerRadarTerrain != null)
@@ -160,7 +162,8 @@ namespace OpenRA.Mods.Common.Widgets
else
{
world.Map.Tiles.CellEntryChanged += CellTerrainColorChanged;
world.Map.CustomTerrain.CellEntryChanged += CellTerrainColorChanged;
foreach (var rtl in radarTerrainLayers)
rtl.CellEntryChanged += CellTerrainColorChanged;
}
playerRadarTerrain = newPlayerRadarTerrain;
@@ -206,7 +209,8 @@ namespace OpenRA.Mods.Common.Widgets
void UpdateTerrainColor(MPos uv)
{
var colorPair = playerRadarTerrain != null && playerRadarTerrain.IsInitialized ? playerRadarTerrain[uv] : PlayerRadarTerrain.GetColor(world.Map, uv);
var colorPair = playerRadarTerrain != null && playerRadarTerrain.IsInitialized ?
playerRadarTerrain[uv] : PlayerRadarTerrain.GetColor(world.Map, radarTerrainLayers, uv);
var leftColor = colorPair.Left;
var rightColor = colorPair.Right;

View File

@@ -9,10 +9,12 @@
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Traits;
using OpenRA.Primitives;
using OpenRA.Traits;
namespace OpenRA.Mods.D2k.Traits
@@ -30,13 +32,14 @@ namespace OpenRA.Mods.D2k.Traits
public override object Create(ActorInitializer init) { return new BuildableTerrainLayer(init.Self, this); }
}
public class BuildableTerrainLayer : IRenderOverlay, IWorldLoaded, ITickRender, INotifyActorDisposing
public class BuildableTerrainLayer : IRenderOverlay, IWorldLoaded, ITickRender, IRadarTerrainLayer, INotifyActorDisposing
{
readonly BuildableTerrainLayerInfo info;
readonly Dictionary<CPos, TerrainTile?> dirty = new Dictionary<CPos, TerrainTile?>();
readonly ITiledTerrainRenderer terrainRenderer;
readonly World world;
readonly CellLayer<int> strength;
readonly CellLayer<(Color, Color)> radarColor;
TerrainSpriteLayer render;
PaletteReference paletteReference;
@@ -47,6 +50,7 @@ namespace OpenRA.Mods.D2k.Traits
this.info = info;
world = self.World;
strength = new CellLayer<int>(world.Map);
radarColor = new CellLayer<(Color, Color)>(world.Map);
terrainRenderer = self.Trait<ITiledTerrainRenderer>();
}
@@ -61,8 +65,11 @@ namespace OpenRA.Mods.D2k.Traits
if (!strength.Contains(cell))
return;
world.Map.CustomTerrain[cell] = world.Map.Rules.TerrainInfo.GetTerrainIndex(tile);
strength[cell] = info.MaxStrength;
var uv = cell.ToMPos(world.Map);
var tileInfo = world.Map.Rules.TerrainInfo.GetTerrainInfo(tile);
world.Map.CustomTerrain[uv] = tileInfo.TerrainType;
strength[uv] = info.MaxStrength;
radarColor[uv] = (tileInfo.GetColor(world.LocalRandom), tileInfo.GetColor(world.LocalRandom));
dirty[cell] = tile;
}
@@ -85,8 +92,10 @@ namespace OpenRA.Mods.D2k.Traits
if (!strength.Contains(cell))
return;
world.Map.CustomTerrain[cell] = byte.MaxValue;
var uv = cell.ToMPos(world.Map);
world.Map.CustomTerrain[uv] = byte.MaxValue;
strength[cell] = 0;
radarColor[uv] = (Color.Transparent, Color.Transparent);
dirty[cell] = null;
}
@@ -121,6 +130,18 @@ namespace OpenRA.Mods.D2k.Traits
render.Draw(wr.Viewport);
}
event Action<CPos> IRadarTerrainLayer.CellEntryChanged
{
add => radarColor.CellEntryChanged += value;
remove => radarColor.CellEntryChanged -= value;
}
bool IRadarTerrainLayer.TryGetTerrainColorPair(MPos uv, out (Color Left, Color Right) value)
{
value = radarColor[uv];
return strength[uv] > 0;
}
void INotifyActorDisposing.Disposing(Actor self)
{
if (disposed)