diff --git a/OpenRA.Game/Traits/World/ResourceLayer.cs b/OpenRA.Game/Traits/World/ResourceLayer.cs index 59c25462c2..bf7dc4536a 100644 --- a/OpenRA.Game/Traits/World/ResourceLayer.cs +++ b/OpenRA.Game/Traits/World/ResourceLayer.cs @@ -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 { } - public class ResourceLayer : IRenderOverlay, IWorldLoaded + public class ResourceLayer : IRenderOverlay, IWorldLoaded, ITickRender { World world; - public ResourceType[] resourceTypes; + ResourceType[] resourceTypes; CellContents[,] content; - + CellContents[,] render; + List 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(); resourceTypes = w.WorldActor.TraitsImplementing().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(); + 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; } } } diff --git a/OpenRA.Mods.RA/Buildings/BibLayer.cs b/OpenRA.Mods.RA/Buildings/BibLayer.cs index 415a08ae0a..ce4711c1ea 100755 --- a/OpenRA.Mods.RA/Buildings/BibLayer.cs +++ b/OpenRA.Mods.RA/Buildings/BibLayer.cs @@ -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> Tiles; + public IEnumerable Footprint; + public bool Visible; + } + + class BibLayer : IRenderOverlay, IWorldLoaded, ITickRender { World world; BibLayerInfo info; - Dictionary> tiles; + Dictionary visible; + Dictionary 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()) DoBib(a,true); }; - self.World.ActorRemoved += - a => { if (a.HasTrait()) 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>(); + visible = new Dictionary(); + dirty = new Dictionary(); } public void DoBib(Actor b, bool isAdd) { + if (!b.HasTrait()) + return; + var buildingInfo = b.Info.Traits.Get(); 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)(bib + 1), (byte)i); - else - tiles.Remove(p); + Footprint = FootprintUtils.Tiles(b), + Tiles = new Dictionary>(), + 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)(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(); + 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 { } + public class BibInfo : TraitInfo, Requires { } public class Bib { } } diff --git a/OpenRA.Mods.RA/Effects/Corpse.cs b/OpenRA.Mods.RA/Effects/Corpse.cs index c4c301877f..304e50af48 100644 --- a/OpenRA.Mods.RA/Effects/Corpse.cs +++ b/OpenRA.Mods.RA/Effects/Corpse.cs @@ -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 Render(WorldRenderer wr) { - return Anim.Render(Pos, wr.Palette(PaletteName)); + if (world.FogObscures(cell)) + return SpriteRenderable.None; + + return anim.Render(pos, wr.Palette(paletteName)); } } } diff --git a/OpenRA.Mods.RA/Effects/CrateEffect.cs b/OpenRA.Mods.RA/Effects/CrateEffect.cs index 52fbae7f80..61bcdfa4e0 100644 --- a/OpenRA.Mods.RA/Effects/CrateEffect.cs +++ b/OpenRA.Mods.RA/Effects/CrateEffect.cs @@ -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 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")); diff --git a/OpenRA.Mods.RA/Effects/Explosion.cs b/OpenRA.Mods.RA/Effects/Explosion.cs index d0d2507bad..35afe19db5 100644 --- a/OpenRA.Mods.RA/Effects/Explosion.cs +++ b/OpenRA.Mods.RA/Effects/Explosion.cs @@ -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 Render(WorldRenderer wr) { + if (world.FogObscures(cell)) + return SpriteRenderable.None; + return anim.Render(pos, wr.Palette("effect")); } } diff --git a/OpenRA.Mods.RA/Effects/FrozenActorProxy.cs b/OpenRA.Mods.RA/Effects/FrozenActorProxy.cs new file mode 100644 index 0000000000..96fe2d82e0 --- /dev/null +++ b/OpenRA.Mods.RA/Effects/FrozenActorProxy.cs @@ -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 footprint; + IRenderable[] renderables; + + public FrozenActorProxy(Actor self, IEnumerable footprint) + { + this.self = self; + this.footprint = footprint; + } + + public void Tick(World world) { } + public void SetRenderables(IEnumerable r) + { + renderables = r.Select(rr => rr).ToArray(); + } + + public IEnumerable 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; + } + } +} diff --git a/OpenRA.Mods.RA/Effects/PowerdownIndicator.cs b/OpenRA.Mods.RA/Effects/PowerdownIndicator.cs index 6405ba0d3d..e8522ce76b 100644 --- a/OpenRA.Mods.RA/Effects/PowerdownIndicator.cs +++ b/OpenRA.Mods.RA/Effects/PowerdownIndicator.cs @@ -36,7 +36,7 @@ namespace OpenRA.Mods.RA.Effects public IEnumerable 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")); diff --git a/OpenRA.Mods.RA/Effects/RepairIndicator.cs b/OpenRA.Mods.RA/Effects/RepairIndicator.cs index 6cca5290d7..f8e7a352b7 100755 --- a/OpenRA.Mods.RA/Effects/RepairIndicator.cs +++ b/OpenRA.Mods.RA/Effects/RepairIndicator.cs @@ -44,7 +44,7 @@ namespace OpenRA.Mods.RA.Effects public IEnumerable Render(WorldRenderer wr) { - if (building.Destroyed) + if (building.Destroyed || wr.world.FogObscures(building)) return SpriteRenderable.None; return anim.Render(building.CenterPosition, diff --git a/OpenRA.Mods.RA/Effects/Smoke.cs b/OpenRA.Mods.RA/Effects/Smoke.cs index b9e19cf006..182a81de12 100644 --- a/OpenRA.Mods.RA/Effects/Smoke.cs +++ b/OpenRA.Mods.RA/Effects/Smoke.cs @@ -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 Render(WorldRenderer wr) { - return Anim.Render(Pos, wr.Palette("effect")); + if (world.FogObscures(cell)) + return SpriteRenderable.None; + + return anim.Render(pos, wr.Palette("effect")); } } } diff --git a/OpenRA.Mods.RA/Harvester.cs b/OpenRA.Mods.RA/Harvester.cs index 562364f255..ec1860261d 100644 --- a/OpenRA.Mods.RA/Harvester.cs +++ b/OpenRA.Mods.RA/Harvester.cs @@ -433,7 +433,7 @@ namespace OpenRA.Mods.RA if (!self.Owner.Shroud.IsExplored(location)) return false; - var res = self.World.WorldActor.Trait().GetResource(location); + var res = self.World.WorldActor.Trait().GetRenderedResource(location); var info = self.Info.Traits.Get(); if (res == null || !info.Resources.Contains(res.info.Name)) diff --git a/OpenRA.Mods.RA/Modifiers/FrozenUnderFog.cs b/OpenRA.Mods.RA/Modifiers/FrozenUnderFog.cs index 3ec4839eaa..14b1620797 100644 --- a/OpenRA.Mods.RA/Modifiers/FrozenUnderFog.cs +++ b/OpenRA.Mods.RA/Modifiers/FrozenUnderFog.cs @@ -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 {} - - class FrozenUnderFog : IRenderModifier, IVisibilityModifier + public class FrozenUnderFogInfo : ITraitInfo, Requires, Requires { + public object Create(ActorInitializer init) { return new FrozenUnderFog(init.self); } + } + + public class FrozenUnderFog : IRenderModifier, IVisibilityModifier, ITickRender + { + FrozenActorProxy proxy; + IEnumerable 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 ModifyRender(Actor self, WorldRenderer wr, IEnumerable r) { - if (IsVisible(self, self.World.RenderPlayer)) - cache = r.ToArray(); - return cache; + return visible ? r : SpriteRenderable.None; } } -} +} \ No newline at end of file diff --git a/OpenRA.Mods.RA/Modifiers/HiddenUnderFog.cs b/OpenRA.Mods.RA/Modifiers/HiddenUnderFog.cs index 7d098af3b8..843407085b 100644 --- a/OpenRA.Mods.RA/Modifiers/HiddenUnderFog.cs +++ b/OpenRA.Mods.RA/Modifiers/HiddenUnderFog.cs @@ -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 {} + public class HiddenUnderFogInfo : TraitInfo { } - 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 ModifyRender(Actor self, WorldRenderer wr, IEnumerable r) { - return IsVisible(self, self.World.RenderPlayer) ? r : Nothing; + return IsVisible(self, self.World.RenderPlayer) ? r : SpriteRenderable.None; } } } diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index b45286a48b..c488da4824 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -461,6 +461,7 @@ + diff --git a/OpenRA.Mods.RA/World/SmudgeLayer.cs b/OpenRA.Mods.RA/World/SmudgeLayer.cs index 883a4c8fdb..a760e9b31e 100755 --- a/OpenRA.Mods.RA/World/SmudgeLayer.cs +++ b/OpenRA.Mods.RA/World/SmudgeLayer.cs @@ -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> tiles; + Dictionary> dirty; Sprite[][] smudgeSprites; World world; @@ -46,49 +47,66 @@ namespace OpenRA.Mods.RA { world = w; tiles = new Dictionary>(); + dirty = new Dictionary>(); // 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)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(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(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(); + 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); } } } diff --git a/mods/cnc/rules/defaults.yaml b/mods/cnc/rules/defaults.yaml index 91240d58a8..8c3f55a1ea 100644 --- a/mods/cnc/rules/defaults.yaml +++ b/mods/cnc/rules/defaults.yaml @@ -317,12 +317,14 @@ Guardable: Range: 3 BodyOrientation: + FrozenUnderFog: ^CivBuilding: Inherits: ^Building -DeadBuildingState: -Buildable: -GivesBuildableArea: + -FrozenUnderFog: Health: HP: 400 Armor: diff --git a/mods/cnc/rules/system.yaml b/mods/cnc/rules/system.yaml index f3dc876469..0da2d447c6 100644 --- a/mods/cnc/rules/system.yaml +++ b/mods/cnc/rules/system.yaml @@ -273,6 +273,7 @@ World: ProductionQueueFromSelection: ProductionTabsWidget: PRODUCTION_TABS BibLayer: + FrozenUnderFog: true DomainIndex: ResourceLayer: ResourceClaimLayer: diff --git a/mods/d2k/rules/system.yaml b/mods/d2k/rules/system.yaml index 639a37d593..0241c1bd2c 100644 --- a/mods/d2k/rules/system.yaml +++ b/mods/d2k/rules/system.yaml @@ -354,6 +354,7 @@ World: BibLayer: BibTypes: bib3x, bib2x BibWidths: 3, 2 + FrozenUnderFog: true DomainIndex: ResourceLayer: ResourceClaimLayer: diff --git a/mods/ra/rules/defaults.yaml b/mods/ra/rules/defaults.yaml index e5259b6b02..d4d49b2504 100644 --- a/mods/ra/rules/defaults.yaml +++ b/mods/ra/rules/defaults.yaml @@ -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: diff --git a/mods/ra/rules/system.yaml b/mods/ra/rules/system.yaml index af115dc9e3..bcb15b969f 100644 --- a/mods/ra/rules/system.yaml +++ b/mods/ra/rules/system.yaml @@ -604,6 +604,7 @@ World: Name: Soviet Race: soviet BibLayer: + FrozenUnderFog: true DomainIndex: ResourceLayer: ResourceClaimLayer: