Files
OpenRA/OpenRA.Mods.Common/Traits/World/SmudgeLayer.cs
Paul Chote 4b1f541f34 Reorganize actor and smudge loading.
The actor and smudge definitions are now stored
as raw MiniYamlNodes in the map.  It is now the
responsibility of the consumers to parse these
into real objects.
2015-04-30 07:06:14 +12:00

159 lines
3.9 KiB
C#

#region Copyright & License Information
/*
* Copyright 2007-2015 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.Graphics;
using OpenRA.Mods.Common.Effects;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
{
[Desc("Attach this to the world actor.", "Order of the layers defines the Z sorting.")]
public class SmudgeLayerInfo : ITraitInfo
{
public readonly string Type = "Scorch";
[Desc("Sprite sequence name")]
public readonly string Sequence = "scorch";
public readonly int SmokePercentage = 25;
[Desc("Sprite sequence name")]
public readonly string SmokeType = "smoke_m";
public readonly string SmokePalette = "effect";
public readonly string Palette = "terrain";
public object Create(ActorInitializer init) { return new SmudgeLayer(this); }
}
public class SmudgeLayer : IRenderOverlay, IWorldLoaded, ITickRender
{
struct Smudge
{
public string Type;
public int Depth;
public Sprite Sprite;
}
public SmudgeLayerInfo Info;
Dictionary<CPos, Smudge> tiles;
Dictionary<CPos, Smudge> dirty;
Dictionary<string, Sprite[]> smudges;
World world;
public SmudgeLayer(SmudgeLayerInfo info)
{
this.Info = info;
}
public void WorldLoaded(World w, WorldRenderer wr)
{
world = w;
tiles = new Dictionary<CPos, Smudge>();
dirty = new Dictionary<CPos, Smudge>();
smudges = new Dictionary<string, Sprite[]>();
var types = world.Map.SequenceProvider.Sequences(Info.Sequence);
foreach (var t in types)
{
var seq = world.Map.SequenceProvider.GetSequence(Info.Sequence, t);
var sprites = Exts.MakeArray(seq.Length, x => seq.GetSprite(x));
smudges.Add(t, sprites);
}
// Add map smudges
foreach (var s in w.Map.SmudgeDefinitions)
{
var name = s.Key;
var vals = name.Split(' ');
var type = vals[0];
if (!smudges.ContainsKey(type))
continue;
var loc = vals[1].Split(',');
var cell = new CPos(Exts.ParseIntegerInvariant(loc[0]), Exts.ParseIntegerInvariant(loc[1]));
var depth = Exts.ParseIntegerInvariant(vals[2]);
var smudge = new Smudge
{
Type = type,
Depth = depth,
Sprite = smudges[type][depth]
};
tiles.Add(cell, smudge);
}
}
public void AddSmudge(CPos loc)
{
if (Game.CosmeticRandom.Next(0, 100) <= Info.SmokePercentage)
world.AddFrameEndTask(w => w.Add(new Smoke(w, world.Map.CenterOfCell(loc), Info.SmokeType, Info.SmokePalette)));
if (!dirty.ContainsKey(loc) && !tiles.ContainsKey(loc))
{
// No smudge; create a new one
var st = smudges.Keys.Random(world.SharedRandom);
dirty[loc] = new Smudge { Type = st, Depth = 0, Sprite = smudges[st][0] };
}
else
{
// Existing smudge; make it deeper
var tile = dirty.ContainsKey(loc) ? dirty[loc] : tiles[loc];
var maxDepth = smudges[tile.Type].Length;
if (tile.Depth < maxDepth - 1)
{
tile.Depth++;
tile.Sprite = smudges[tile.Type][tile.Depth];
}
dirty[loc] = tile;
}
}
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 pal = wr.Palette(Info.Palette);
foreach (var kv in tiles)
{
if (!wr.Viewport.VisibleCells.Contains(kv.Key))
continue;
if (world.ShroudObscures(kv.Key))
continue;
new SpriteRenderable(kv.Value.Sprite, world.Map.CenterOfCell(kv.Key),
WVec.Zero, -511, pal, 1f, true).Render(wr); // TODO ZOffset is ignored
}
}
}
}