From 50d89629a2a2bb87d08ea784140aff3168268d8a Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sun, 16 Mar 2014 22:13:07 +1300 Subject: [PATCH] Add BuildableTerrainLayer and LaysTerrain traits. --- OpenRA.Mods.RA/Buildings/LaysTerrain.cs | 88 +++++++++++++++++++ OpenRA.Mods.RA/OpenRA.Mods.RA.csproj | 2 + OpenRA.Mods.RA/World/BuildableTerrainLayer.cs | 82 +++++++++++++++++ 3 files changed, 172 insertions(+) create mode 100755 OpenRA.Mods.RA/Buildings/LaysTerrain.cs create mode 100644 OpenRA.Mods.RA/World/BuildableTerrainLayer.cs diff --git a/OpenRA.Mods.RA/Buildings/LaysTerrain.cs b/OpenRA.Mods.RA/Buildings/LaysTerrain.cs new file mode 100755 index 0000000000..c7455458f9 --- /dev/null +++ b/OpenRA.Mods.RA/Buildings/LaysTerrain.cs @@ -0,0 +1,88 @@ +#region Copyright & License Information +/* + * Copyright 2007-2014 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.FileFormats; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Buildings +{ + public class LaysTerrainInfo : ITraitInfo, Requires, Requires + { + [Desc("The terrain template to place. If the template is PickAny, then" + + "the actor footprint will be filled with this tile.")] + public readonly ushort Template = 0; + + [Desc("The terrain types that this template will be placed on")] + public readonly string[] TerrainTypes = {}; + + [Desc("Offset relative to the actor TopLeft. Not used if the template is PickAny")] + public readonly CVec Offset = CVec.Zero; + + public object Create(ActorInitializer init) { return new LaysTerrain(init.self, this); } + } + + public class LaysTerrain : INotifyAddedToWorld + { + readonly LaysTerrainInfo info; + readonly BuildableTerrainLayer layer; + readonly BuildingInfluence bi; + readonly TileTemplate template; + + public LaysTerrain(Actor self, LaysTerrainInfo info) + { + this.info = info; + layer = self.World.WorldActor.Trait(); + bi = self.World.WorldActor.Trait(); + template = self.World.TileSet.Templates[info.Template]; + } + + public void AddedToWorld(Actor self) + { + if (template.PickAny) + { + // Fill the footprint with random variants + foreach (var c in FootprintUtils.Tiles(self)) + { + // Only place on allowed terrain types + if (!info.TerrainTypes.Contains(self.World.GetTerrainType(c))) + continue; + + // Don't place under other buildings or custom terrain + if (bi.GetBuildingAt(c) != self || self.World.Map.CustomTerrain[c.X, c.Y] != null) + continue; + + var index = template.Tiles.Keys.Random(Game.CosmeticRandom); + layer.AddTile(c, new TileReference(template.Id, index)); + } + + return; + } + + var origin = self.Location + info.Offset; + foreach (var i in template.Tiles.Keys) + { + var c = origin + new CVec(i % template.Size.X, i / template.Size.X); + + // Only place on allowed terrain types + if (!info.TerrainTypes.Contains(self.World.GetTerrainType(c))) + continue; + + // Don't place under other buildings or custom terrain + if (bi.GetBuildingAt(c) != self || self.World.Map.CustomTerrain[c.X, c.Y] != null) + continue; + + layer.AddTile(c, new TileReference(template.Id, i)); + } + } + } +} diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index e88021fff3..cef7e49b34 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -482,6 +482,8 @@ + + diff --git a/OpenRA.Mods.RA/World/BuildableTerrainLayer.cs b/OpenRA.Mods.RA/World/BuildableTerrainLayer.cs new file mode 100644 index 0000000000..b8be9a45d4 --- /dev/null +++ b/OpenRA.Mods.RA/World/BuildableTerrainLayer.cs @@ -0,0 +1,82 @@ +#region Copyright & License Information +/* + * Copyright 2007-2014 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; +using System.Collections.Generic; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Graphics; +using OpenRA.Mods.RA.Effects; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + public class BuildableTerrainLayerInfo : TraitInfo { } + public class BuildableTerrainLayer : IRenderOverlay, IWorldLoaded, ITickRender + { + Dictionary tiles; + Dictionary dirty; + Theater theater; + TileSet tileset; + Map map; + + public void WorldLoaded(World w, WorldRenderer wr) + { + theater = wr.Theater; + tileset = w.TileSet; + map = w.Map; + tiles = new Dictionary(); + dirty = new Dictionary(); + } + + public void AddTile(CPos cell, TileReference tile) + { + map.CustomTerrain[cell.X, cell.Y] = tileset.GetTerrainType(tile); + + // Terrain tiles define their origin at the topleft + var s = theater.TileSprite(tile); + dirty[cell] = new Sprite(s.sheet, s.bounds, float2.Zero, s.channel, s.blendMode); + } + + 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 = wr.Viewport.CellBounds; + var pal = wr.Palette("terrain"); + + foreach (var kv in tiles) + { + if (!cliprect.Contains(kv.Key.X, kv.Key.Y)) + continue; + + if (wr.world.ShroudObscures(kv.Key)) + continue; + + new SpriteRenderable(kv.Value, kv.Key.CenterPosition, + WVec.Zero, -511, pal, 1f, true).Render(wr); + } + } + } +}