Merge pull request #3596 from pchote/fog-visibility-freezing
Fog visibility freezing fixes #3206 et al
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
@@ -9,22 +9,23 @@
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
public class ResourceLayerInfo : TraitInfo<ResourceLayer> { }
|
||||
|
||||
public class ResourceLayer : IRenderOverlay, IWorldLoaded
|
||||
public class ResourceLayer : IRenderOverlay, IWorldLoaded, ITickRender
|
||||
{
|
||||
World world;
|
||||
|
||||
public ResourceType[] resourceTypes;
|
||||
ResourceType[] resourceTypes;
|
||||
CellContents[,] content;
|
||||
|
||||
CellContents[,] render;
|
||||
List<CPos> dirty;
|
||||
bool hasSetupPalettes;
|
||||
|
||||
public void Render(WorldRenderer wr)
|
||||
@@ -37,24 +38,31 @@ namespace OpenRA.Traits
|
||||
}
|
||||
|
||||
var clip = Game.viewport.WorldBounds(world);
|
||||
for (int x = clip.Left; x < clip.Right; x++)
|
||||
for (int y = clip.Top; y < clip.Bottom; y++)
|
||||
for (var x = clip.Left; x < clip.Right; x++)
|
||||
{
|
||||
for (var y = clip.Top; y < clip.Bottom; y++)
|
||||
{
|
||||
if (world.ShroudObscures(new CPos(x, y)))
|
||||
var pos = new CPos(x, y);
|
||||
if (world.ShroudObscures(pos))
|
||||
continue;
|
||||
|
||||
var c = content[x, y];
|
||||
if (c.image != null)
|
||||
c.image[c.density].DrawAt(
|
||||
new CPos(x, y).ToPPos().ToFloat2(),
|
||||
c.type.info.PaletteRef);
|
||||
var c = render[x, y];
|
||||
if (c.Image != null)
|
||||
{
|
||||
var tile = c.Image[c.Density];
|
||||
var px = wr.ScreenPxPosition(pos.CenterPosition) - 0.5f * tile.size;
|
||||
tile.DrawAt(px, c.Type.info.PaletteRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void WorldLoaded(World w)
|
||||
{
|
||||
this.world = w;
|
||||
content = new CellContents[w.Map.MapSize.X, w.Map.MapSize.Y];
|
||||
render = new CellContents[w.Map.MapSize.X, w.Map.MapSize.Y];
|
||||
dirty = new List<CPos>();
|
||||
|
||||
resourceTypes = w.WorldActor.TraitsImplementing<ResourceType>().ToArray();
|
||||
foreach (var rt in resourceTypes)
|
||||
@@ -62,8 +70,8 @@ namespace OpenRA.Traits
|
||||
|
||||
var map = w.Map;
|
||||
|
||||
for (int x = map.Bounds.Left; x < map.Bounds.Right; x++)
|
||||
for (int y = map.Bounds.Top; y < map.Bounds.Bottom; y++)
|
||||
for (var x = map.Bounds.Left; x < map.Bounds.Right; x++)
|
||||
for (var y = map.Bounds.Top; y < map.Bounds.Bottom; y++)
|
||||
{
|
||||
var type = resourceTypes.FirstOrDefault(
|
||||
r => r.info.ResourceType == w.Map.MapResources.Value[x, y].type);
|
||||
@@ -71,27 +79,53 @@ namespace OpenRA.Traits
|
||||
if (type == null)
|
||||
continue;
|
||||
|
||||
if (!AllowResourceAt(type, new CPos(x,y)))
|
||||
if (!AllowResourceAt(type, new CPos(x, y)))
|
||||
continue;
|
||||
|
||||
content[x, y].type = type;
|
||||
content[x, y].image = ChooseContent(type);
|
||||
render[x, y].Type = content[x, y].Type = type;
|
||||
render[x, y].Image = content[x, y].Image = ChooseContent(type);
|
||||
}
|
||||
|
||||
for (int x = map.Bounds.Left; x < map.Bounds.Right; x++)
|
||||
for (int y = map.Bounds.Top; y < map.Bounds.Bottom; y++)
|
||||
if (content[x, y].type != null)
|
||||
for (var x = map.Bounds.Left; x < map.Bounds.Right; x++)
|
||||
{
|
||||
for (var y = map.Bounds.Top; y < map.Bounds.Bottom; y++)
|
||||
{
|
||||
if (content[x, y].Type != null)
|
||||
{
|
||||
content[x, y].density = GetIdealDensity(x, y);
|
||||
w.Map.CustomTerrain[x, y] = content[x, y].type.info.TerrainType;
|
||||
render[x, y].Density = content[x, y].Density = GetIdealDensity(x, y);
|
||||
w.Map.CustomTerrain[x, y] = content[x, y].Type.info.TerrainType;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void TickRender(WorldRenderer wr, Actor self)
|
||||
{
|
||||
var remove = new List<CPos>();
|
||||
foreach (var c in dirty)
|
||||
{
|
||||
if (!self.World.FogObscures(c))
|
||||
{
|
||||
render[c.X, c.Y] = content[c.X, c.Y];
|
||||
remove.Add(c);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var r in remove)
|
||||
dirty.Remove(r);
|
||||
}
|
||||
|
||||
public bool AllowResourceAt(ResourceType rt, CPos a)
|
||||
{
|
||||
if (!world.Map.IsInMap(a.X, a.Y)) return false;
|
||||
if (!rt.info.AllowedTerrainTypes.Contains(world.GetTerrainInfo(a).Type)) return false;
|
||||
if (!rt.info.AllowUnderActors && world.ActorMap.AnyUnitsAt(a)) return false;
|
||||
if (!world.Map.IsInMap(a.X, a.Y))
|
||||
return false;
|
||||
|
||||
if (!rt.info.AllowedTerrainTypes.Contains(world.GetTerrainInfo(a).Type))
|
||||
return false;
|
||||
|
||||
if (!rt.info.AllowUnderActors && world.ActorMap.AnyUnitsAt(a))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -105,77 +139,95 @@ namespace OpenRA.Traits
|
||||
int sum = 0;
|
||||
for (var u = -1; u < 2; u++)
|
||||
for (var v = -1; v < 2; v++)
|
||||
if (content[i + u, j + v].type == t)
|
||||
if (content[i + u, j + v].Type == t)
|
||||
++sum;
|
||||
return sum;
|
||||
}
|
||||
|
||||
int GetIdealDensity(int x, int y)
|
||||
{
|
||||
return (GetAdjacentCellsWith(content[x, y].type, x, y) *
|
||||
(content[x, y].image.Length - 1)) / 9;
|
||||
return (GetAdjacentCellsWith(content[x, y].Type, x, y) *
|
||||
(content[x, y].Image.Length - 1)) / 9;
|
||||
}
|
||||
|
||||
public void AddResource(ResourceType t, int i, int j, int n)
|
||||
{
|
||||
if (content[i, j].type == null)
|
||||
if (content[i, j].Type == null)
|
||||
{
|
||||
content[i, j].type = t;
|
||||
content[i, j].image = ChooseContent(t);
|
||||
content[i, j].density = -1;
|
||||
content[i, j].Type = t;
|
||||
content[i, j].Image = ChooseContent(t);
|
||||
content[i, j].Density = -1;
|
||||
}
|
||||
|
||||
if (content[i, j].type != t)
|
||||
if (content[i, j].Type != t)
|
||||
return;
|
||||
|
||||
content[i, j].density = Math.Min(
|
||||
content[i, j].image.Length - 1,
|
||||
content[i, j].density + n);
|
||||
content[i, j].Density = Math.Min(
|
||||
content[i, j].Image.Length - 1,
|
||||
content[i, j].Density + n);
|
||||
|
||||
world.Map.CustomTerrain[i, j] = t.info.TerrainType;
|
||||
|
||||
var cell = new CPos(i, j);
|
||||
if (!dirty.Contains(cell))
|
||||
dirty.Add(cell);
|
||||
}
|
||||
|
||||
public bool IsFull(int i, int j) { return content[i, j].density == content[i, j].image.Length - 1; }
|
||||
public bool IsFull(int i, int j)
|
||||
{
|
||||
return content[i, j].Density == content[i, j].Image.Length - 1;
|
||||
}
|
||||
|
||||
public ResourceType Harvest(CPos p)
|
||||
{
|
||||
var type = content[p.X, p.Y].type;
|
||||
if (type == null) return null;
|
||||
var type = content[p.X, p.Y].Type;
|
||||
if (type == null)
|
||||
return null;
|
||||
|
||||
if (--content[p.X, p.Y].density < 0)
|
||||
if (--content[p.X, p.Y].Density < 0)
|
||||
{
|
||||
content[p.X, p.Y].type = null;
|
||||
content[p.X, p.Y].image = null;
|
||||
content[p.X, p.Y].Type = null;
|
||||
content[p.X, p.Y].Image = null;
|
||||
world.Map.CustomTerrain[p.X, p.Y] = null;
|
||||
}
|
||||
|
||||
if (!dirty.Contains(p))
|
||||
dirty.Add(p);
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
public void Destroy(CPos p)
|
||||
{
|
||||
// Don't break other users of CustomTerrain if there are no resources
|
||||
if (content[p.X, p.Y].type == null)
|
||||
if (content[p.X, p.Y].Type == null)
|
||||
return;
|
||||
|
||||
content[p.X, p.Y].type = null;
|
||||
content[p.X, p.Y].image = null;
|
||||
content[p.X, p.Y].density = 0;
|
||||
content[p.X, p.Y].Type = null;
|
||||
content[p.X, p.Y].Image = null;
|
||||
content[p.X, p.Y].Density = 0;
|
||||
world.Map.CustomTerrain[p.X, p.Y] = null;
|
||||
|
||||
if (!dirty.Contains(p))
|
||||
dirty.Add(p);
|
||||
}
|
||||
|
||||
public ResourceType GetResource(CPos p) { return content[p.X, p.Y].type; }
|
||||
public int GetResourceDensity(CPos p) { return content[p.X, p.Y].density; }
|
||||
public ResourceType GetResource(CPos p) { return content[p.X, p.Y].Type; }
|
||||
public ResourceType GetRenderedResource(CPos p) { return render[p.X, p.Y].Type; }
|
||||
public int GetResourceDensity(CPos p) { return content[p.X, p.Y].Density; }
|
||||
public int GetMaxResourceDensity(CPos p)
|
||||
{
|
||||
if (content[p.X, p.Y].image == null) return 0;
|
||||
return content[p.X, p.Y].image.Length - 1;
|
||||
if (content[p.X, p.Y].Image == null)
|
||||
return 0;
|
||||
|
||||
return content[p.X, p.Y].Image.Length - 1;
|
||||
}
|
||||
|
||||
public struct CellContents
|
||||
{
|
||||
public ResourceType type;
|
||||
public Sprite[] image;
|
||||
public int density;
|
||||
public ResourceType Type;
|
||||
public Sprite[] Image;
|
||||
public int Density;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Graphics;
|
||||
@@ -19,16 +20,25 @@ namespace OpenRA.Mods.RA.Buildings
|
||||
{
|
||||
class BibLayerInfo : ITraitInfo
|
||||
{
|
||||
public readonly string[] BibTypes = {"bib3", "bib2", "bib1"};
|
||||
public readonly int[] BibWidths = {2,3,4};
|
||||
public readonly string[] BibTypes = { "bib3", "bib2", "bib1" };
|
||||
public readonly int[] BibWidths = { 2, 3, 4 };
|
||||
public readonly bool FrozenUnderFog = false;
|
||||
public object Create(ActorInitializer init) { return new BibLayer(init.self, this); }
|
||||
}
|
||||
|
||||
class BibLayer: IRenderOverlay, IWorldLoaded
|
||||
struct CachedBib
|
||||
{
|
||||
public Dictionary<CPos, TileReference<byte, byte>> Tiles;
|
||||
public IEnumerable<CPos> Footprint;
|
||||
public bool Visible;
|
||||
}
|
||||
|
||||
class BibLayer : IRenderOverlay, IWorldLoaded, ITickRender
|
||||
{
|
||||
World world;
|
||||
BibLayerInfo info;
|
||||
Dictionary<CPos, TileReference<byte, byte>> tiles;
|
||||
Dictionary<Actor, CachedBib> visible;
|
||||
Dictionary<Actor, CachedBib> dirty;
|
||||
Sprite[][] bibSprites;
|
||||
|
||||
public BibLayer(Actor self, BibLayerInfo info)
|
||||
@@ -36,57 +46,89 @@ namespace OpenRA.Mods.RA.Buildings
|
||||
this.info = info;
|
||||
bibSprites = info.BibTypes.Select(x => Game.modData.SpriteLoader.LoadAllSprites(x)).ToArray();
|
||||
|
||||
self.World.ActorAdded +=
|
||||
a => { if (a.HasTrait<Bib>()) DoBib(a,true); };
|
||||
self.World.ActorRemoved +=
|
||||
a => { if (a.HasTrait<Bib>()) DoBib(a,false); };
|
||||
self.World.ActorAdded += a => DoBib(a, true);
|
||||
self.World.ActorRemoved += a => DoBib(a, false);
|
||||
}
|
||||
|
||||
public void WorldLoaded(World w)
|
||||
{
|
||||
world = w;
|
||||
tiles = new Dictionary<CPos, TileReference<byte, byte>>();
|
||||
visible = new Dictionary<Actor, CachedBib>();
|
||||
dirty = new Dictionary<Actor, CachedBib>();
|
||||
}
|
||||
|
||||
public void DoBib(Actor b, bool isAdd)
|
||||
{
|
||||
if (!b.HasTrait<Bib>())
|
||||
return;
|
||||
|
||||
var buildingInfo = b.Info.Traits.Get<BuildingInfo>();
|
||||
var size = buildingInfo.Dimensions.X;
|
||||
var bibOffset = buildingInfo.Dimensions.Y - 1;
|
||||
|
||||
int bib = Array.IndexOf(info.BibWidths,size);
|
||||
var bib = Array.IndexOf(info.BibWidths, size);
|
||||
if (bib < 0)
|
||||
{
|
||||
Log.Write("debug", "Cannot bib {0}-wide building {1}", size, b.Info.Name);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2 * size; i++)
|
||||
dirty[b] = new CachedBib()
|
||||
{
|
||||
var p = b.Location + new CVec(i % size, i / size + bibOffset);
|
||||
if (isAdd)
|
||||
tiles[p] = new TileReference<byte, byte>((byte)(bib + 1), (byte)i);
|
||||
else
|
||||
tiles.Remove(p);
|
||||
Footprint = FootprintUtils.Tiles(b),
|
||||
Tiles = new Dictionary<CPos, TileReference<byte, byte>>(),
|
||||
Visible = isAdd
|
||||
};
|
||||
|
||||
for (var i = 0; i < 2 * size; i++)
|
||||
{
|
||||
var cell = b.Location + new CVec(i % size, i / size + bibOffset);
|
||||
var tile = new TileReference<byte, byte>((byte)(bib + 1), (byte) i);
|
||||
dirty[b].Tiles.Add(cell, tile);
|
||||
}
|
||||
}
|
||||
|
||||
public void Render( WorldRenderer wr )
|
||||
public void TickRender(WorldRenderer wr, Actor self)
|
||||
{
|
||||
var remove = new List<Actor>();
|
||||
foreach (var kv in dirty)
|
||||
{
|
||||
if (!info.FrozenUnderFog || kv.Value.Footprint.Any(c => !self.World.FogObscures(c)))
|
||||
{
|
||||
if (kv.Value.Visible)
|
||||
visible[kv.Key] = kv.Value;
|
||||
else
|
||||
visible.Remove(kv.Key);
|
||||
|
||||
remove.Add(kv.Key);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var r in remove)
|
||||
dirty.Remove(r);
|
||||
}
|
||||
|
||||
public void Render(WorldRenderer wr)
|
||||
{
|
||||
var pal = wr.Palette("terrain");
|
||||
var cliprect = Game.viewport.WorldBounds(world);
|
||||
foreach (var kv in tiles)
|
||||
{
|
||||
if (!cliprect.Contains(kv.Key.X, kv.Key.Y))
|
||||
continue;
|
||||
if (world.ShroudObscures(kv.Key))
|
||||
continue;
|
||||
|
||||
bibSprites[kv.Value.type - 1][kv.Value.index].DrawAt(kv.Key.ToPPos().ToFloat2(), pal);
|
||||
foreach (var bib in visible.Values)
|
||||
{
|
||||
foreach (var kv in bib.Tiles)
|
||||
{
|
||||
if (!cliprect.Contains(kv.Key.X, kv.Key.Y))
|
||||
continue;
|
||||
if (world.ShroudObscures(kv.Key))
|
||||
continue;
|
||||
|
||||
var tile = bibSprites[kv.Value.type - 1][kv.Value.index];
|
||||
tile.DrawAt(wr.ScreenPxPosition(kv.Key.CenterPosition) - 0.5f * tile.size, pal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class BibInfo : TraitInfo<Bib> { }
|
||||
public class BibInfo : TraitInfo<Bib>, Requires<BuildingInfo> { }
|
||||
public class Bib { }
|
||||
}
|
||||
|
||||
@@ -17,23 +17,30 @@ namespace OpenRA.Mods.RA.Effects
|
||||
{
|
||||
public class Corpse : IEffect
|
||||
{
|
||||
readonly Animation Anim;
|
||||
readonly WPos Pos;
|
||||
readonly string PaletteName;
|
||||
readonly World world;
|
||||
readonly WPos pos;
|
||||
readonly CPos cell;
|
||||
readonly string paletteName;
|
||||
readonly Animation anim;
|
||||
|
||||
public Corpse(World world, WPos pos, string image, string sequence, string paletteName)
|
||||
{
|
||||
Pos = pos;
|
||||
PaletteName = paletteName;
|
||||
Anim = new Animation(image);
|
||||
Anim.PlayThen(sequence, () => world.AddFrameEndTask(w => w.Remove(this)));
|
||||
this.world = world;
|
||||
this.pos = pos;
|
||||
this.cell = pos.ToCPos();
|
||||
this.paletteName = paletteName;
|
||||
anim = new Animation(image);
|
||||
anim.PlayThen(sequence, () => world.AddFrameEndTask(w => w.Remove(this)));
|
||||
}
|
||||
|
||||
public void Tick(World world) { Anim.Tick(); }
|
||||
public void Tick(World world) { anim.Tick(); }
|
||||
|
||||
public IEnumerable<IRenderable> Render(WorldRenderer wr)
|
||||
{
|
||||
return Anim.Render(Pos, wr.Palette(PaletteName));
|
||||
if (world.FogObscures(cell))
|
||||
return SpriteRenderable.None;
|
||||
|
||||
return anim.Render(pos, wr.Palette(paletteName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
@@ -23,18 +23,17 @@ namespace OpenRA.Mods.RA.Effects
|
||||
public CrateEffect(Actor a, string seq)
|
||||
{
|
||||
this.a = a;
|
||||
anim.PlayThen(seq,
|
||||
() => a.World.AddFrameEndTask(w => w.Remove(this)));
|
||||
anim.PlayThen(seq, () => a.World.AddFrameEndTask(w => w.Remove(this)));
|
||||
}
|
||||
|
||||
public void Tick( World world )
|
||||
public void Tick(World world)
|
||||
{
|
||||
anim.Tick();
|
||||
}
|
||||
|
||||
public IEnumerable<IRenderable> Render(WorldRenderer wr)
|
||||
{
|
||||
if (!a.IsInWorld)
|
||||
if (!a.IsInWorld || a.World.FogObscures(a.Location))
|
||||
return SpriteRenderable.None;
|
||||
|
||||
return anim.Render(a.CenterPosition, wr.Palette("effect"));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
@@ -17,20 +17,27 @@ namespace OpenRA.Mods.RA.Effects
|
||||
{
|
||||
public class Explosion : IEffect
|
||||
{
|
||||
Animation anim;
|
||||
World world;
|
||||
WPos pos;
|
||||
CPos cell;
|
||||
Animation anim;
|
||||
|
||||
public Explosion(World world, WPos pos, string style)
|
||||
{
|
||||
this.world = world;
|
||||
this.pos = pos;
|
||||
this.cell = pos.ToCPos();
|
||||
anim = new Animation("explosion");
|
||||
anim.PlayThen(style, () => world.AddFrameEndTask(w => w.Remove(this)));
|
||||
}
|
||||
|
||||
public void Tick( World world ) { anim.Tick(); }
|
||||
public void Tick(World world) { anim.Tick(); }
|
||||
|
||||
public IEnumerable<IRenderable> Render(WorldRenderer wr)
|
||||
{
|
||||
if (world.FogObscures(cell))
|
||||
return SpriteRenderable.None;
|
||||
|
||||
return anim.Render(pos, wr.Palette("effect"));
|
||||
}
|
||||
}
|
||||
|
||||
53
OpenRA.Mods.RA/Effects/FrozenActorProxy.cs
Normal file
53
OpenRA.Mods.RA/Effects/FrozenActorProxy.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Effects;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Effects
|
||||
{
|
||||
public class FrozenActorProxy : IEffect
|
||||
{
|
||||
readonly Actor self;
|
||||
readonly IEnumerable<CPos> footprint;
|
||||
IRenderable[] renderables;
|
||||
|
||||
public FrozenActorProxy(Actor self, IEnumerable<CPos> footprint)
|
||||
{
|
||||
this.self = self;
|
||||
this.footprint = footprint;
|
||||
}
|
||||
|
||||
public void Tick(World world) { }
|
||||
public void SetRenderables(IEnumerable<IRenderable> r)
|
||||
{
|
||||
renderables = r.Select(rr => rr).ToArray();
|
||||
}
|
||||
|
||||
public IEnumerable<IRenderable> Render(WorldRenderer wr)
|
||||
{
|
||||
if (renderables == null)
|
||||
return SpriteRenderable.None;
|
||||
|
||||
if (footprint.Any(c => !wr.world.FogObscures(c)))
|
||||
{
|
||||
if (self.Destroyed)
|
||||
self.World.AddFrameEndTask(w => w.Remove(this));
|
||||
|
||||
return SpriteRenderable.None;
|
||||
}
|
||||
|
||||
return renderables;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ namespace OpenRA.Mods.RA.Effects
|
||||
|
||||
public IEnumerable<IRenderable> Render(WorldRenderer wr)
|
||||
{
|
||||
if (a.Destroyed || a.Owner.IsAlliedWith(a.World.RenderPlayer))
|
||||
if (a.Destroyed || wr.world.FogObscures(a))
|
||||
return SpriteRenderable.None;
|
||||
|
||||
return anim.Render(a.CenterPosition, wr.Palette("chrome"));
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace OpenRA.Mods.RA.Effects
|
||||
|
||||
public IEnumerable<IRenderable> Render(WorldRenderer wr)
|
||||
{
|
||||
if (building.Destroyed)
|
||||
if (building.Destroyed || wr.world.FogObscures(building))
|
||||
return SpriteRenderable.None;
|
||||
|
||||
return anim.Render(building.CenterPosition,
|
||||
|
||||
@@ -17,25 +17,29 @@ namespace OpenRA.Mods.RA.Effects
|
||||
{
|
||||
public class Smoke : IEffect
|
||||
{
|
||||
readonly WPos Pos;
|
||||
readonly Animation Anim;
|
||||
readonly World world;
|
||||
readonly WPos pos;
|
||||
readonly CPos cell;
|
||||
readonly Animation anim;
|
||||
|
||||
public Smoke(World world, WPos pos, string trail)
|
||||
{
|
||||
Pos = pos;
|
||||
Anim = new Animation(trail);
|
||||
Anim.PlayThen("idle",
|
||||
this.world = world;
|
||||
this.pos = pos;
|
||||
this.cell = pos.ToCPos();
|
||||
anim = new Animation(trail);
|
||||
anim.PlayThen("idle",
|
||||
() => world.AddFrameEndTask(w => w.Remove(this)));
|
||||
}
|
||||
|
||||
public void Tick(World world)
|
||||
{
|
||||
Anim.Tick();
|
||||
}
|
||||
public void Tick(World world) { anim.Tick(); }
|
||||
|
||||
public IEnumerable<IRenderable> Render(WorldRenderer wr)
|
||||
{
|
||||
return Anim.Render(Pos, wr.Palette("effect"));
|
||||
if (world.FogObscures(cell))
|
||||
return SpriteRenderable.None;
|
||||
|
||||
return anim.Render(pos, wr.Palette("effect"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -433,7 +433,7 @@ namespace OpenRA.Mods.RA
|
||||
if (!self.Owner.Shroud.IsExplored(location))
|
||||
return false;
|
||||
|
||||
var res = self.World.WorldActor.Trait<ResourceLayer>().GetResource(location);
|
||||
var res = self.World.WorldActor.Trait<ResourceLayer>().GetRenderedResource(location);
|
||||
var info = self.Info.Traits.Get<HarvesterInfo>();
|
||||
|
||||
if (res == null || !info.Resources.Contains(res.info.Name))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
@@ -11,25 +11,48 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Mods.RA.Buildings;
|
||||
using OpenRA.Mods.RA.Effects;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
class FrozenUnderFogInfo : TraitInfo<FrozenUnderFog> {}
|
||||
|
||||
class FrozenUnderFog : IRenderModifier, IVisibilityModifier
|
||||
public class FrozenUnderFogInfo : ITraitInfo, Requires<BuildingInfo>, Requires<RenderSpritesInfo>
|
||||
{
|
||||
public object Create(ActorInitializer init) { return new FrozenUnderFog(init.self); }
|
||||
}
|
||||
|
||||
public class FrozenUnderFog : IRenderModifier, IVisibilityModifier, ITickRender
|
||||
{
|
||||
FrozenActorProxy proxy;
|
||||
IEnumerable<CPos> footprint;
|
||||
bool visible;
|
||||
|
||||
public FrozenUnderFog(Actor self)
|
||||
{
|
||||
footprint = FootprintUtils.Tiles(self);
|
||||
proxy = new FrozenActorProxy(self, footprint);
|
||||
self.World.AddFrameEndTask(w => w.Add(proxy));
|
||||
}
|
||||
|
||||
public bool IsVisible(Actor self, Player byPlayer)
|
||||
{
|
||||
return byPlayer == null || Shroud.GetVisOrigins(self).Any(o => byPlayer.Shroud.IsVisible(o));
|
||||
return byPlayer == null || footprint.Any(c => byPlayer.Shroud.IsVisible(c));
|
||||
}
|
||||
|
||||
public void TickRender(WorldRenderer wr, Actor self)
|
||||
{
|
||||
if (self.Destroyed)
|
||||
return;
|
||||
|
||||
visible = IsVisible(self, self.World.RenderPlayer);
|
||||
if (visible)
|
||||
proxy.SetRenderables(self.Render(wr));
|
||||
}
|
||||
|
||||
IRenderable[] cache = { };
|
||||
public IEnumerable<IRenderable> ModifyRender(Actor self, WorldRenderer wr, IEnumerable<IRenderable> r)
|
||||
{
|
||||
if (IsVisible(self, self.World.RenderPlayer))
|
||||
cache = r.ToArray();
|
||||
return cache;
|
||||
return visible ? r : SpriteRenderable.None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
@@ -15,19 +15,18 @@ using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
class HiddenUnderFogInfo : TraitInfo<HiddenUnderFog> {}
|
||||
public class HiddenUnderFogInfo : TraitInfo<HiddenUnderFog> { }
|
||||
|
||||
class HiddenUnderFog : IRenderModifier, IVisibilityModifier
|
||||
public class HiddenUnderFog : IRenderModifier, IVisibilityModifier
|
||||
{
|
||||
public bool IsVisible(Actor self, Player byPlayer)
|
||||
{
|
||||
return byPlayer == null || Shroud.GetVisOrigins(self).Any(o => byPlayer.Shroud.IsVisible(o));
|
||||
}
|
||||
|
||||
static IRenderable[] Nothing = { };
|
||||
public IEnumerable<IRenderable> ModifyRender(Actor self, WorldRenderer wr, IEnumerable<IRenderable> r)
|
||||
{
|
||||
return IsVisible(self, self.World.RenderPlayer) ? r : Nothing;
|
||||
return IsVisible(self, self.World.RenderPlayer) ? r : SpriteRenderable.None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -461,6 +461,7 @@
|
||||
<Compile Include="World\DomainIndex.cs" />
|
||||
<Compile Include="MPStartUnits.cs" />
|
||||
<Compile Include="Orders\SetChronoTankDestination.cs" />
|
||||
<Compile Include="Effects\FrozenActorProxy.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
@@ -14,25 +14,26 @@ using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Mods.RA.Effects;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
public class SmudgeLayerInfo : ITraitInfo
|
||||
{
|
||||
public readonly string Type = "Scorch";
|
||||
public readonly string[] Types = {"sc1", "sc2", "sc3", "sc4", "sc5", "sc6"};
|
||||
public readonly int[] Depths = {1,1,1,1,1,1};
|
||||
public readonly string[] Types = { "sc1", "sc2", "sc3", "sc4", "sc5", "sc6" };
|
||||
public readonly int[] Depths = { 1, 1, 1, 1, 1, 1 };
|
||||
public readonly int SmokePercentage = 25;
|
||||
public readonly string SmokeType = "smoke_m";
|
||||
public object Create(ActorInitializer init) { return new SmudgeLayer(this); }
|
||||
}
|
||||
|
||||
public class SmudgeLayer: IRenderOverlay, IWorldLoaded
|
||||
public class SmudgeLayer : IRenderOverlay, IWorldLoaded, ITickRender
|
||||
{
|
||||
public SmudgeLayerInfo Info;
|
||||
Dictionary<CPos, TileReference<byte, byte>> tiles;
|
||||
Dictionary<CPos, TileReference<byte, byte>> dirty;
|
||||
Sprite[][] smudgeSprites;
|
||||
World world;
|
||||
|
||||
@@ -46,49 +47,66 @@ namespace OpenRA.Mods.RA
|
||||
{
|
||||
world = w;
|
||||
tiles = new Dictionary<CPos, TileReference<byte, byte>>();
|
||||
dirty = new Dictionary<CPos, TileReference<byte, byte>>();
|
||||
|
||||
// Add map smudges
|
||||
foreach (var s in w.Map.Smudges.Value.Where( s => Info.Types.Contains(s.Type )))
|
||||
foreach (var s in w.Map.Smudges.Value.Where(s => Info.Types.Contains(s.Type)))
|
||||
tiles.Add((CPos)s.Location, new TileReference<byte, byte>((byte)Array.IndexOf(Info.Types, s.Type), (byte)s.Depth));
|
||||
}
|
||||
|
||||
public void AddSmudge(CPos loc)
|
||||
{
|
||||
if (Game.CosmeticRandom.Next(0,100) <= Info.SmokePercentage)
|
||||
if (Game.CosmeticRandom.Next(0, 100) <= Info.SmokePercentage)
|
||||
world.AddFrameEndTask(w => w.Add(new Smoke(w, loc.CenterPosition, Info.SmokeType)));
|
||||
|
||||
// No smudge; create a new one
|
||||
if (!tiles.ContainsKey(loc))
|
||||
if (!dirty.ContainsKey(loc) && !tiles.ContainsKey(loc))
|
||||
{
|
||||
byte st = (byte)(1 + world.SharedRandom.Next(Info.Types.Length - 1));
|
||||
tiles.Add(loc, new TileReference<byte,byte>(st,(byte)0));
|
||||
return;
|
||||
// No smudge; create a new one
|
||||
var st = (byte)(1 + world.SharedRandom.Next(Info.Types.Length - 1));
|
||||
dirty[loc] = new TileReference<byte, byte>(st, (byte)0);
|
||||
}
|
||||
|
||||
var tile = tiles[loc];
|
||||
// Existing smudge; make it deeper
|
||||
int depth = Info.Depths[tile.type-1];
|
||||
if (tile.index < depth - 1)
|
||||
else
|
||||
{
|
||||
tile.index++;
|
||||
tiles[loc] = tile; // struct semantics.
|
||||
// Existing smudge; make it deeper
|
||||
var tile = dirty.ContainsKey(loc) ? dirty[loc] : tiles[loc];
|
||||
var depth = Info.Depths[tile.type - 1];
|
||||
if (tile.index < depth - 1)
|
||||
tile.index++;
|
||||
|
||||
dirty[loc] = tile;
|
||||
}
|
||||
}
|
||||
|
||||
public void Render( WorldRenderer wr )
|
||||
public void TickRender(WorldRenderer wr, Actor self)
|
||||
{
|
||||
var remove = new List<CPos>();
|
||||
foreach (var kv in dirty)
|
||||
{
|
||||
if (!self.World.FogObscures(kv.Key))
|
||||
{
|
||||
tiles[kv.Key] = kv.Value;
|
||||
remove.Add(kv.Key);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var r in remove)
|
||||
dirty.Remove(r);
|
||||
}
|
||||
|
||||
public void Render(WorldRenderer wr)
|
||||
{
|
||||
var cliprect = Game.viewport.WorldBounds(world);
|
||||
var pal = wr.Palette("terrain");
|
||||
|
||||
foreach (var kv in tiles)
|
||||
{
|
||||
if (!cliprect.Contains(kv.Key.X,kv.Key.Y))
|
||||
if (!cliprect.Contains(kv.Key.X, kv.Key.Y))
|
||||
continue;
|
||||
|
||||
if (world.ShroudObscures(kv.Key))
|
||||
continue;
|
||||
|
||||
smudgeSprites[kv.Value.type- 1][kv.Value.index].DrawAt(kv.Key.ToPPos().ToFloat2(), pal);
|
||||
smudgeSprites[kv.Value.type - 1][kv.Value.index].DrawAt(kv.Key.ToPPos().ToFloat2(), pal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,12 +317,14 @@
|
||||
Guardable:
|
||||
Range: 3
|
||||
BodyOrientation:
|
||||
FrozenUnderFog:
|
||||
|
||||
^CivBuilding:
|
||||
Inherits: ^Building
|
||||
-DeadBuildingState:
|
||||
-Buildable:
|
||||
-GivesBuildableArea:
|
||||
-FrozenUnderFog:
|
||||
Health:
|
||||
HP: 400
|
||||
Armor:
|
||||
|
||||
@@ -273,6 +273,7 @@ World:
|
||||
ProductionQueueFromSelection:
|
||||
ProductionTabsWidget: PRODUCTION_TABS
|
||||
BibLayer:
|
||||
FrozenUnderFog: true
|
||||
DomainIndex:
|
||||
ResourceLayer:
|
||||
ResourceClaimLayer:
|
||||
|
||||
@@ -354,6 +354,7 @@ World:
|
||||
BibLayer:
|
||||
BibTypes: bib3x, bib2x
|
||||
BibWidths: 3, 2
|
||||
FrozenUnderFog: true
|
||||
DomainIndex:
|
||||
ResourceLayer:
|
||||
ResourceClaimLayer:
|
||||
|
||||
@@ -222,7 +222,6 @@
|
||||
ActorTypes: e1,e1,e1,e1,e1,e1,e1,e1,e1,e1,e1,e1,e1,e1,e1,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,e6,e6,e6,e6,e6
|
||||
MustBeDestroyed:
|
||||
GivesExperience:
|
||||
# FrozenUnderFog:
|
||||
CaptureNotification:
|
||||
EditorAppearance:
|
||||
RelativeToTopLeft: yes
|
||||
@@ -237,6 +236,7 @@
|
||||
Guardable:
|
||||
Range: 3
|
||||
BodyOrientation:
|
||||
FrozenUnderFog:
|
||||
|
||||
^Wall:
|
||||
AppearsOnRadar:
|
||||
|
||||
@@ -604,6 +604,7 @@ World:
|
||||
Name: Soviet
|
||||
Race: soviet
|
||||
BibLayer:
|
||||
FrozenUnderFog: true
|
||||
DomainIndex:
|
||||
ResourceLayer:
|
||||
ResourceClaimLayer:
|
||||
|
||||
Reference in New Issue
Block a user