Add BuildableTerrainLayer and LaysTerrain traits.

This commit is contained in:
Paul Chote
2014-03-16 22:13:07 +13:00
parent c098f85e6f
commit 50d89629a2
3 changed files with 172 additions and 0 deletions

View File

@@ -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<BuildingInfo>, Requires<RenderSpritesInfo>
{
[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<BuildableTerrainLayer>();
bi = self.World.WorldActor.Trait<BuildingInfluence>();
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<ushort, byte>(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<ushort, byte>(template.Id, i));
}
}
}
}

View File

@@ -482,6 +482,8 @@
<Compile Include="Widgets\Logic\GameTimerLogic.cs" /> <Compile Include="Widgets\Logic\GameTimerLogic.cs" />
<Compile Include="Immobile.cs" /> <Compile Include="Immobile.cs" />
<Compile Include="Widgets\Logic\ReplayControlBarLogic.cs" /> <Compile Include="Widgets\Logic\ReplayControlBarLogic.cs" />
<Compile Include="World\BuildableTerrainLayer.cs" />
<Compile Include="Buildings\LaysTerrain.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj"> <ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">

View File

@@ -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<BuildableTerrainLayer> { }
public class BuildableTerrainLayer : IRenderOverlay, IWorldLoaded, ITickRender
{
Dictionary<CPos, Sprite> tiles;
Dictionary<CPos, Sprite> 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<CPos, Sprite>();
dirty = new Dictionary<CPos, Sprite>();
}
public void AddTile(CPos cell, TileReference<ushort, byte> 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<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 = 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);
}
}
}
}