Merge pull request #3596 from pchote/fog-visibility-freezing

Fog visibility freezing fixes #3206 et al
This commit is contained in:
Matthias Mailänder
2013-07-25 11:12:36 -07:00
19 changed files with 358 additions and 148 deletions

View File

@@ -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;
}
}
}

View File

@@ -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 { }
}

View File

@@ -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));
}
}
}

View File

@@ -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"));

View File

@@ -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"));
}
}

View 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;
}
}
}

View File

@@ -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"));

View File

@@ -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,

View File

@@ -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"));
}
}
}

View File

@@ -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))

View File

@@ -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;
}
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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">

View File

@@ -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);
}
}
}

View File

@@ -317,12 +317,14 @@
Guardable:
Range: 3
BodyOrientation:
FrozenUnderFog:
^CivBuilding:
Inherits: ^Building
-DeadBuildingState:
-Buildable:
-GivesBuildableArea:
-FrozenUnderFog:
Health:
HP: 400
Armor:

View File

@@ -273,6 +273,7 @@ World:
ProductionQueueFromSelection:
ProductionTabsWidget: PRODUCTION_TABS
BibLayer:
FrozenUnderFog: true
DomainIndex:
ResourceLayer:
ResourceClaimLayer:

View File

@@ -354,6 +354,7 @@ World:
BibLayer:
BibTypes: bib3x, bib2x
BibWidths: 3, 2
FrozenUnderFog: true
DomainIndex:
ResourceLayer:
ResourceClaimLayer:

View File

@@ -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:

View File

@@ -604,6 +604,7 @@ World:
Name: Soviet
Race: soviet
BibLayer:
FrozenUnderFog: true
DomainIndex:
ResourceLayer:
ResourceClaimLayer: