Use CellLayers for shroud.
This commit is contained in:
@@ -27,9 +27,9 @@ namespace OpenRA.Traits
|
|||||||
Actor self;
|
Actor self;
|
||||||
Map map;
|
Map map;
|
||||||
|
|
||||||
int[,] visibleCount;
|
CellLayer<int> visibleCount;
|
||||||
int[,] generatedShroudCount;
|
CellLayer<int> generatedShroudCount;
|
||||||
bool[,] explored;
|
CellLayer<bool> explored;
|
||||||
|
|
||||||
readonly Lazy<IFogVisibilityModifier[]> fogVisibilities;
|
readonly Lazy<IFogVisibilityModifier[]> fogVisibilities;
|
||||||
|
|
||||||
@@ -47,9 +47,9 @@ namespace OpenRA.Traits
|
|||||||
this.self = self;
|
this.self = self;
|
||||||
map = self.World.Map;
|
map = self.World.Map;
|
||||||
|
|
||||||
visibleCount = new int[map.MapSize.X, map.MapSize.Y];
|
visibleCount = new CellLayer<int>(map);
|
||||||
generatedShroudCount = new int[map.MapSize.X, map.MapSize.Y];
|
generatedShroudCount = new CellLayer<int>(map);
|
||||||
explored = new bool[map.MapSize.X, map.MapSize.Y];
|
explored = new CellLayer<bool>(map);
|
||||||
|
|
||||||
self.World.ActorAdded += AddVisibility;
|
self.World.ActorAdded += AddVisibility;
|
||||||
self.World.ActorRemoved += RemoveVisibility;
|
self.World.ActorRemoved += RemoveVisibility;
|
||||||
@@ -104,8 +104,8 @@ namespace OpenRA.Traits
|
|||||||
// Update visibility
|
// Update visibility
|
||||||
foreach (var c in visible)
|
foreach (var c in visible)
|
||||||
{
|
{
|
||||||
visibleCount[c.X, c.Y]++;
|
visibleCount[c]++;
|
||||||
explored[c.X, c.Y] = true;
|
explored[c] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (visibility.ContainsKey(a))
|
if (visibility.ContainsKey(a))
|
||||||
@@ -122,7 +122,7 @@ namespace OpenRA.Traits
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
foreach (var c in visible)
|
foreach (var c in visible)
|
||||||
visibleCount[c.X, c.Y]--;
|
visibleCount[c]--;
|
||||||
|
|
||||||
visibility.Remove(a);
|
visibility.Remove(a);
|
||||||
Invalidate();
|
Invalidate();
|
||||||
@@ -147,7 +147,7 @@ namespace OpenRA.Traits
|
|||||||
var shrouded = GetVisOrigins(a).SelectMany(o => FindVisibleTiles(a.World, o, cs.Range))
|
var shrouded = GetVisOrigins(a).SelectMany(o => FindVisibleTiles(a.World, o, cs.Range))
|
||||||
.Distinct().ToArray();
|
.Distinct().ToArray();
|
||||||
foreach (var c in shrouded)
|
foreach (var c in shrouded)
|
||||||
generatedShroudCount[c.X, c.Y]++;
|
generatedShroudCount[c]++;
|
||||||
|
|
||||||
if (generation.ContainsKey(a))
|
if (generation.ContainsKey(a))
|
||||||
throw new InvalidOperationException("Attempting to add duplicate shroud generation");
|
throw new InvalidOperationException("Attempting to add duplicate shroud generation");
|
||||||
@@ -163,7 +163,7 @@ namespace OpenRA.Traits
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
foreach (var c in shrouded)
|
foreach (var c in shrouded)
|
||||||
generatedShroudCount[c.X, c.Y]--;
|
generatedShroudCount[c]--;
|
||||||
|
|
||||||
generation.Remove(a);
|
generation.Remove(a);
|
||||||
Invalidate();
|
Invalidate();
|
||||||
@@ -203,7 +203,7 @@ namespace OpenRA.Traits
|
|||||||
public void Explore(World world, CPos center, WRange range)
|
public void Explore(World world, CPos center, WRange range)
|
||||||
{
|
{
|
||||||
foreach (var q in FindVisibleTiles(world, center, range))
|
foreach (var q in FindVisibleTiles(world, center, range))
|
||||||
explored[q.X, q.Y] = true;
|
explored[q] = true;
|
||||||
|
|
||||||
var r = (range.Range + 1023) / 1024;
|
var r = (range.Range + 1023) / 1024;
|
||||||
var box = new Rectangle(center.X - r, center.Y - r, 2 * r + 1, 2 * r + 1);
|
var box = new Rectangle(center.X - r, center.Y - r, 2 * r + 1, 2 * r + 1);
|
||||||
@@ -214,19 +214,17 @@ namespace OpenRA.Traits
|
|||||||
|
|
||||||
public void Explore(Shroud s)
|
public void Explore(Shroud s)
|
||||||
{
|
{
|
||||||
for (var i = map.Bounds.Left; i < map.Bounds.Right; i++)
|
foreach (var cell in map.Cells)
|
||||||
for (var j = map.Bounds.Top; j < map.Bounds.Bottom; j++)
|
if (s.explored[cell])
|
||||||
if (s.explored[i,j] == true)
|
explored[cell] = true;
|
||||||
explored[i, j] = true;
|
|
||||||
|
|
||||||
ExploredBounds = Rectangle.Union(ExploredBounds, s.ExploredBounds);
|
ExploredBounds = Rectangle.Union(ExploredBounds, s.ExploredBounds);
|
||||||
|
Invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ExploreAll(World world)
|
public void ExploreAll(World world)
|
||||||
{
|
{
|
||||||
for (var i = map.Bounds.Left; i < map.Bounds.Right; i++)
|
explored.Clear(true);
|
||||||
for (var j = map.Bounds.Top; j < map.Bounds.Bottom; j++)
|
|
||||||
explored[i, j] = true;
|
|
||||||
|
|
||||||
ExploredBounds = world.Map.Bounds;
|
ExploredBounds = world.Map.Bounds;
|
||||||
|
|
||||||
@@ -235,23 +233,21 @@ namespace OpenRA.Traits
|
|||||||
|
|
||||||
public void ResetExploration()
|
public void ResetExploration()
|
||||||
{
|
{
|
||||||
for (var i = map.Bounds.Left; i < map.Bounds.Right; i++)
|
foreach (var cell in map.Cells)
|
||||||
for (var j = map.Bounds.Top; j < map.Bounds.Bottom; j++)
|
explored[cell] = visibleCount[cell] > 0;
|
||||||
explored[i, j] = visibleCount[i, j] > 0;
|
|
||||||
|
|
||||||
Invalidate();
|
Invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsExplored(CPos xy) { return IsExplored(xy.X, xy.Y); }
|
public bool IsExplored(CPos cell)
|
||||||
public bool IsExplored(int x, int y)
|
|
||||||
{
|
{
|
||||||
if (!map.IsInMap(x, y))
|
if (!map.IsInMap(cell))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (Disabled || !self.World.LobbyInfo.GlobalSettings.Shroud)
|
if (Disabled || !self.World.LobbyInfo.GlobalSettings.Shroud)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return explored[x, y] && (generatedShroudCount[x, y] == 0 || visibleCount[x, y] > 0);
|
return explored[cell] && (generatedShroudCount[cell] == 0 || visibleCount[cell] > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsExplored(Actor a)
|
public bool IsExplored(Actor a)
|
||||||
@@ -259,16 +255,15 @@ namespace OpenRA.Traits
|
|||||||
return GetVisOrigins(a).Any(o => IsExplored(o));
|
return GetVisOrigins(a).Any(o => IsExplored(o));
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsVisible(CPos xy) { return IsVisible(xy.X, xy.Y); }
|
public bool IsVisible(CPos cell)
|
||||||
public bool IsVisible(int x, int y)
|
|
||||||
{
|
{
|
||||||
if (!map.IsInMap(x, y))
|
if (!map.IsInMap(cell))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (Disabled || !self.World.LobbyInfo.GlobalSettings.Fog)
|
if (Disabled || !self.World.LobbyInfo.GlobalSettings.Fog)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return visibleCount[x, y] > 0;
|
return visibleCount[cell] > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actors are hidden under shroud, but not under fog by default
|
// Actors are hidden under shroud, but not under fog by default
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using OpenRA;
|
||||||
using OpenRA.Graphics;
|
using OpenRA.Graphics;
|
||||||
using OpenRA.Traits;
|
using OpenRA.Traits;
|
||||||
|
|
||||||
@@ -35,36 +36,41 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
public class ShroudRenderer : IRenderShroud, IWorldLoaded
|
public class ShroudRenderer : IRenderShroud, IWorldLoaded
|
||||||
{
|
{
|
||||||
struct ShroudTile
|
class ShroudTile
|
||||||
{
|
{
|
||||||
public CPos Position;
|
public readonly CPos Position;
|
||||||
public float2 ScreenPosition;
|
public readonly float2 ScreenPosition;
|
||||||
public int Variant;
|
public readonly int Variant;
|
||||||
|
|
||||||
public Sprite Fog;
|
public Sprite Fog;
|
||||||
public Sprite Shroud;
|
public Sprite Shroud;
|
||||||
|
|
||||||
|
public ShroudTile(CPos position, float2 screenPosition, int variant)
|
||||||
|
{
|
||||||
|
Position = position;
|
||||||
|
ScreenPosition = screenPosition;
|
||||||
|
Variant = variant;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ShroudRendererInfo info;
|
||||||
Sprite[] sprites;
|
Sprite[] sprites;
|
||||||
Sprite unexploredTile;
|
Sprite unexploredTile;
|
||||||
int[] spriteMap;
|
int[] spriteMap;
|
||||||
|
|
||||||
ShroudTile[] tiles;
|
CellLayer<ShroudTile> tiles;
|
||||||
int tileStride, variantStride;
|
int variantStride;
|
||||||
|
|
||||||
int shroudHash;
|
int shroudHash;
|
||||||
PaletteReference fogPalette, shroudPalette;
|
PaletteReference fogPalette, shroudPalette;
|
||||||
Rectangle bounds;
|
Map map;
|
||||||
bool useExtendedIndex;
|
|
||||||
|
|
||||||
public ShroudRenderer(World world, ShroudRendererInfo info)
|
public ShroudRenderer(World world, ShroudRendererInfo info)
|
||||||
{
|
{
|
||||||
var map = world.Map;
|
this.info = info;
|
||||||
bounds = map.Bounds;
|
map = world.Map;
|
||||||
useExtendedIndex = info.UseExtendedIndex;
|
|
||||||
|
|
||||||
tiles = new ShroudTile[map.MapSize.X * map.MapSize.Y];
|
tiles = new CellLayer<ShroudTile>(map);
|
||||||
tileStride = map.MapSize.X;
|
|
||||||
|
|
||||||
// Force update on first render
|
// Force update on first render
|
||||||
shroudHash = -1;
|
shroudHash = -1;
|
||||||
@@ -80,14 +86,10 @@ namespace OpenRA.Mods.RA
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Mapping of shrouded directions -> sprite index
|
// Mapping of shrouded directions -> sprite index
|
||||||
spriteMap = new int[useExtendedIndex ? 256 : 16];
|
spriteMap = new int[info.UseExtendedIndex ? 256 : 16];
|
||||||
for (var i = 0; i < info.Index.Length; i++)
|
for (var i = 0; i < info.Index.Length; i++)
|
||||||
spriteMap[info.Index[i]] = i;
|
spriteMap[info.Index[i]] = i;
|
||||||
|
|
||||||
// Set individual tile variants to reduce tiling
|
|
||||||
for (var i = 0; i < tiles.Length; i++)
|
|
||||||
tiles[i].Variant = Game.CosmeticRandom.Next(info.Variants.Length);
|
|
||||||
|
|
||||||
// Synthesize unexplored tile if it isn't defined
|
// Synthesize unexplored tile if it isn't defined
|
||||||
if (!info.Index.Contains(0))
|
if (!info.Index.Contains(0))
|
||||||
{
|
{
|
||||||
@@ -102,21 +104,21 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
static int FoggedEdges(Shroud s, CPos p, bool useExtendedIndex)
|
static int FoggedEdges(Shroud s, CPos p, bool useExtendedIndex)
|
||||||
{
|
{
|
||||||
if (!s.IsVisible(p.X, p.Y))
|
if (!s.IsVisible(p))
|
||||||
return 15;
|
return 15;
|
||||||
|
|
||||||
// If a side is shrouded then we also count the corners
|
// If a side is shrouded then we also count the corners
|
||||||
var u = 0;
|
var u = 0;
|
||||||
if (!s.IsVisible(p.X, p.Y - 1)) u |= 0x13;
|
if (!s.IsVisible(p + new CVec(0, -1))) u |= 0x13;
|
||||||
if (!s.IsVisible(p.X + 1, p.Y)) u |= 0x26;
|
if (!s.IsVisible(p + new CVec(1, 0))) u |= 0x26;
|
||||||
if (!s.IsVisible(p.X, p.Y + 1)) u |= 0x4C;
|
if (!s.IsVisible(p + new CVec(0, 1))) u |= 0x4C;
|
||||||
if (!s.IsVisible(p.X - 1, p.Y)) u |= 0x89;
|
if (!s.IsVisible(p + new CVec(-1, 0))) u |= 0x89;
|
||||||
|
|
||||||
var uside = u & 0x0F;
|
var uside = u & 0x0F;
|
||||||
if (!s.IsVisible(p.X - 1, p.Y - 1)) u |= 0x01;
|
if (!s.IsVisible(p + new CVec(-1, -1))) u |= 0x01;
|
||||||
if (!s.IsVisible(p.X + 1, p.Y - 1)) u |= 0x02;
|
if (!s.IsVisible(p + new CVec(1, -1))) u |= 0x02;
|
||||||
if (!s.IsVisible(p.X + 1, p.Y + 1)) u |= 0x04;
|
if (!s.IsVisible(p + new CVec(1, 1))) u |= 0x04;
|
||||||
if (!s.IsVisible(p.X - 1, p.Y + 1)) u |= 0x08;
|
if (!s.IsVisible(p + new CVec(-1, 1))) u |= 0x08;
|
||||||
|
|
||||||
// RA provides a set of frames for tiles with shrouded
|
// RA provides a set of frames for tiles with shrouded
|
||||||
// corners but unshrouded edges. We want to detect this
|
// corners but unshrouded edges. We want to detect this
|
||||||
@@ -129,21 +131,21 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
static int ShroudedEdges(Shroud s, CPos p, bool useExtendedIndex)
|
static int ShroudedEdges(Shroud s, CPos p, bool useExtendedIndex)
|
||||||
{
|
{
|
||||||
if (!s.IsExplored(p.X, p.Y))
|
if (!s.IsExplored(p))
|
||||||
return 15;
|
return 15;
|
||||||
|
|
||||||
// If a side is shrouded then we also count the corners
|
// If a side is shrouded then we also count the corners
|
||||||
var u = 0;
|
var u = 0;
|
||||||
if (!s.IsExplored(p.X, p.Y - 1)) u |= 0x13;
|
if (!s.IsExplored(p + new CVec(0, -1))) u |= 0x13;
|
||||||
if (!s.IsExplored(p.X + 1, p.Y)) u |= 0x26;
|
if (!s.IsExplored(p + new CVec(1, 0))) u |= 0x26;
|
||||||
if (!s.IsExplored(p.X, p.Y + 1)) u |= 0x4C;
|
if (!s.IsExplored(p + new CVec(0, 1))) u |= 0x4C;
|
||||||
if (!s.IsExplored(p.X - 1, p.Y)) u |= 0x89;
|
if (!s.IsExplored(p + new CVec(-1, 0))) u |= 0x89;
|
||||||
|
|
||||||
var uside = u & 0x0F;
|
var uside = u & 0x0F;
|
||||||
if (!s.IsExplored(p.X - 1, p.Y - 1)) u |= 0x01;
|
if (!s.IsExplored(p + new CVec(-1, -1))) u |= 0x01;
|
||||||
if (!s.IsExplored(p.X + 1, p.Y - 1)) u |= 0x02;
|
if (!s.IsExplored(p + new CVec(1, -1))) u |= 0x02;
|
||||||
if (!s.IsExplored(p.X + 1, p.Y + 1)) u |= 0x04;
|
if (!s.IsExplored(p + new CVec(1, 1))) u |= 0x04;
|
||||||
if (!s.IsExplored(p.X - 1, p.Y + 1)) u |= 0x08;
|
if (!s.IsExplored(p + new CVec(-1, 1))) u |= 0x08;
|
||||||
|
|
||||||
// RA provides a set of frames for tiles with shrouded
|
// RA provides a set of frames for tiles with shrouded
|
||||||
// corners but unshrouded edges. We want to detect this
|
// corners but unshrouded edges. We want to detect this
|
||||||
@@ -173,15 +175,12 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
public void WorldLoaded(World w, WorldRenderer wr)
|
public void WorldLoaded(World w, WorldRenderer wr)
|
||||||
{
|
{
|
||||||
// Cache the tile positions to avoid unnecessary calculations
|
// Initialize tile cache
|
||||||
for (var i = bounds.Left; i < bounds.Right; i++)
|
foreach (var cell in map.Cells)
|
||||||
{
|
{
|
||||||
for (var j = bounds.Top; j < bounds.Bottom; j++)
|
var screen = wr.ScreenPosition(cell.CenterPosition);
|
||||||
{
|
var variant = Game.CosmeticRandom.Next(info.Variants.Length);
|
||||||
var k = j * tileStride + i;
|
tiles[cell] = new ShroudTile(cell, screen, variant);
|
||||||
tiles[k].Position = new CPos(i, j);
|
|
||||||
tiles[k].ScreenPosition = wr.ScreenPosition(tiles[k].Position.CenterPosition);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fogPalette = wr.Palette("fog");
|
fogPalette = wr.Palette("fog");
|
||||||
@@ -209,22 +208,25 @@ namespace OpenRA.Mods.RA
|
|||||||
if (shroud == null)
|
if (shroud == null)
|
||||||
{
|
{
|
||||||
// Players with no shroud see the whole map so we only need to set the edges
|
// Players with no shroud see the whole map so we only need to set the edges
|
||||||
for (var k = 0; k < tiles.Length; k++)
|
foreach (var cell in map.Cells)
|
||||||
{
|
{
|
||||||
var shrouded = ObserverShroudedEdges(tiles[k].Position, bounds, useExtendedIndex);
|
var t = tiles[cell];
|
||||||
tiles[k].Shroud = GetTile(shrouded, tiles[k].Variant);
|
var shrouded = ObserverShroudedEdges(t.Position, map.Bounds, info.UseExtendedIndex);
|
||||||
tiles[k].Fog = GetTile(shrouded, tiles[k].Variant);
|
|
||||||
|
t.Shroud = GetTile(shrouded, t.Variant);
|
||||||
|
t.Fog = GetTile(shrouded, t.Variant);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (var k = 0; k < tiles.Length; k++)
|
foreach (var cell in map.Cells)
|
||||||
{
|
{
|
||||||
var shrouded = ShroudedEdges(shroud, tiles[k].Position, useExtendedIndex);
|
var t = tiles[cell];
|
||||||
var fogged = FoggedEdges(shroud, tiles[k].Position, useExtendedIndex);
|
var shrouded = ShroudedEdges(shroud, t.Position, info.UseExtendedIndex);
|
||||||
|
var fogged = FoggedEdges(shroud, t.Position, info.UseExtendedIndex);
|
||||||
|
|
||||||
tiles[k].Shroud = GetTile(shrouded, tiles[k].Variant);
|
t.Shroud = GetTile(shrouded, t.Variant);
|
||||||
tiles[k].Fog = GetTile(fogged, tiles[k].Variant);
|
t.Fog = GetTile(fogged, t.Variant);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -233,27 +235,20 @@ namespace OpenRA.Mods.RA
|
|||||||
{
|
{
|
||||||
Update(shroud);
|
Update(shroud);
|
||||||
|
|
||||||
var clip = wr.Viewport.CellBounds;
|
foreach (var cell in wr.Viewport.VisibleCells)
|
||||||
var width = clip.Width;
|
|
||||||
for (var j = clip.Top; j < clip.Bottom; j++)
|
|
||||||
{
|
{
|
||||||
var start = j * tileStride + clip.Left;
|
var t = tiles[cell];
|
||||||
for (var k = 0; k < width; k++)
|
|
||||||
|
if (t.Shroud != null)
|
||||||
{
|
{
|
||||||
var s = tiles[start + k].Shroud;
|
var pos = t.ScreenPosition - 0.5f * t.Shroud.size;
|
||||||
var f = tiles[start + k].Fog;
|
Game.Renderer.WorldSpriteRenderer.DrawSprite(t.Shroud, pos, shroudPalette);
|
||||||
|
}
|
||||||
|
|
||||||
if (s != null)
|
if (t.Fog != null)
|
||||||
{
|
{
|
||||||
var pos = tiles[start + k].ScreenPosition - 0.5f * s.size;
|
var pos = t.ScreenPosition - 0.5f * t.Fog.size;
|
||||||
Game.Renderer.WorldSpriteRenderer.DrawSprite(s, pos, shroudPalette);
|
Game.Renderer.WorldSpriteRenderer.DrawSprite(t.Fog, pos, fogPalette);
|
||||||
}
|
|
||||||
|
|
||||||
if (f != null)
|
|
||||||
{
|
|
||||||
var pos = tiles[start + k].ScreenPosition - 0.5f * f.size;
|
|
||||||
Game.Renderer.WorldSpriteRenderer.DrawSprite(f, pos, fogPalette);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user