diff --git a/OpenRa.Game/Actor.cs b/OpenRa.Game/Actor.cs index e860afd679..f440962df6 100755 --- a/OpenRa.Game/Actor.cs +++ b/OpenRa.Game/Actor.cs @@ -65,13 +65,13 @@ namespace OpenRa.Game get { var firstSprite = Render().FirstOrDefault(); - if( firstSprite == null ) + if( firstSprite.Sprite == null ) return new float2( 0, 0 ); - return firstSprite.a.size; + return firstSprite.Sprite.size; } } - public IEnumerable> Render() + public IEnumerable Render() { var mods = traits.WithInterface(); var sprites = traits.WithInterface().SelectMany(x => x.Render(this)); diff --git a/OpenRa.Game/Effects/Bullet.cs b/OpenRa.Game/Effects/Bullet.cs index ae930e97f6..3f47590d5e 100644 --- a/OpenRa.Game/Effects/Bullet.cs +++ b/OpenRa.Game/Effects/Bullet.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using OpenRa.Game.GameRules; using OpenRa.Game.Graphics; +using OpenRa.Game.Traits; namespace OpenRa.Game.Effects { @@ -60,7 +61,7 @@ namespace OpenRa.Game.Effects const float height = .1f; - public IEnumerable> Render() + public IEnumerable Render() { if (anim != null) { @@ -72,15 +73,15 @@ namespace OpenRa.Game.Effects if (Projectile.High || Projectile.Arcing) { if (Projectile.Shadow) - yield return Tuple.New(anim.Image, pos, 8); + yield return new Renderable(anim.Image, pos, 8); var at = (float)t / TotalTime(); var highPos = pos - new float2(0, (VisualDest - Src).Length * height * 4 * at * (1 - at)); - yield return Tuple.New(anim.Image, highPos, Owner.Palette); + yield return new Renderable(anim.Image, highPos, Owner.Palette); } else - yield return Tuple.New(anim.Image, pos, Projectile.UnderWater ? 8 : Owner.Palette); + yield return new Renderable(anim.Image, pos, Projectile.UnderWater ? 8 : Owner.Palette); } } } diff --git a/OpenRa.Game/Effects/Corpse.cs b/OpenRa.Game/Effects/Corpse.cs index 31d0427951..efdbf8cb4c 100644 --- a/OpenRa.Game/Effects/Corpse.cs +++ b/OpenRa.Game/Effects/Corpse.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using OpenRa.Game.Graphics; +using OpenRa.Game.Traits; namespace OpenRa.Game.Effects { @@ -24,9 +25,9 @@ namespace OpenRa.Game.Effects public void Tick() { anim.Tick(); } - public IEnumerable> Render() + public IEnumerable Render() { - yield return Tuple.New(anim.Image, pos - .5f * anim.Image.size, owner.Palette); + yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, owner.Palette); } } } diff --git a/OpenRa.Game/Effects/Explosion.cs b/OpenRa.Game/Effects/Explosion.cs index 8de120a3b7..5da0021aeb 100644 --- a/OpenRa.Game/Effects/Explosion.cs +++ b/OpenRa.Game/Effects/Explosion.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using OpenRa.Game.Graphics; +using OpenRa.Game.Traits; namespace OpenRa.Game.Effects { @@ -19,9 +20,9 @@ namespace OpenRa.Game.Effects public void Tick() { anim.Tick(); } - public IEnumerable> Render() + public IEnumerable Render() { - yield return Tuple.New(anim.Image, pos.ToFloat2() - 0.5f * anim.Image.size, 0); + yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, 0); } public Player Owner { get { return null; } } diff --git a/OpenRa.Game/Effects/IEffect.cs b/OpenRa.Game/Effects/IEffect.cs index 43fb1453a2..feb99cd504 100644 --- a/OpenRa.Game/Effects/IEffect.cs +++ b/OpenRa.Game/Effects/IEffect.cs @@ -1,11 +1,12 @@ using System.Collections.Generic; using OpenRa.Game.Graphics; +using OpenRa.Game.Traits; namespace OpenRa.Game.Effects { interface IEffect { void Tick(); - IEnumerable> Render(); + IEnumerable Render(); } } diff --git a/OpenRa.Game/Effects/Missile.cs b/OpenRa.Game/Effects/Missile.cs index bb6fb8e302..f1e1fc2267 100644 --- a/OpenRa.Game/Effects/Missile.cs +++ b/OpenRa.Game/Effects/Missile.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using OpenRa.Game.GameRules; using OpenRa.Game.Graphics; +using OpenRa.Game.Traits; namespace OpenRa.Game.Effects { @@ -75,9 +76,9 @@ namespace OpenRa.Game.Effects // todo: turbo boost vs aircraft } - public IEnumerable> Render() + public IEnumerable Render() { - yield return Tuple.New(anim.Image, Pos - 0.5f * anim.Image.size, 0); + yield return new Renderable(anim.Image, Pos - 0.5f * anim.Image.size, 0); } } } diff --git a/OpenRa.Game/Effects/Smoke.cs b/OpenRa.Game/Effects/Smoke.cs index f13f3fe6cd..edafcd7818 100644 --- a/OpenRa.Game/Effects/Smoke.cs +++ b/OpenRa.Game/Effects/Smoke.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using OpenRa.Game.Graphics; +using OpenRa.Game.Traits; namespace OpenRa.Game.Effects { @@ -20,9 +21,9 @@ namespace OpenRa.Game.Effects anim.Tick(); } - public IEnumerable> Render() + public IEnumerable Render() { - yield return Tuple.New(anim.Image, pos.ToFloat2() - .5f * anim.Image.size, 0); + yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, 0); } } } diff --git a/OpenRa.Game/Effects/TeslaZap.cs b/OpenRa.Game/Effects/TeslaZap.cs index 417d5171f7..8422a260f0 100755 --- a/OpenRa.Game/Effects/TeslaZap.cs +++ b/OpenRa.Game/Effects/TeslaZap.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using OpenRa.Game.Graphics; +using OpenRa.Game.Traits; namespace OpenRa.Game.Effects { @@ -26,7 +27,7 @@ namespace OpenRa.Game.Effects --timeUntilRemove; } - public IEnumerable> Render() + public IEnumerable Render() { if( from.X < to.X ) return DrawZap( from, to, tesla ); @@ -36,7 +37,7 @@ namespace OpenRa.Game.Effects return DrawZap( from, to, tesla ); } - static IEnumerable> DrawZap( int2 from, int2 to, Sequence tesla ) + static IEnumerable DrawZap( int2 from, int2 to, Sequence tesla ) { int2 d = to - from; if( d.X < 8 ) @@ -45,7 +46,7 @@ namespace OpenRa.Game.Effects var y = d.Y; while( y >= prev.Y + 8 ) { - yield return Tuple.New( tesla.GetSprite( 2 ), (float2)( from + prev - new int2( 0, 8 ) ), 0 ); + yield return new Renderable( tesla.GetSprite( 2 ), (float2)( from + prev - new int2( 0, 8 ) ), 0 ); prev.Y += 8; } } @@ -57,26 +58,26 @@ namespace OpenRa.Game.Effects var y = i * d.Y / d.X; if( y <= prev.Y - 8 ) { - yield return Tuple.New( tesla.GetSprite( 3 ), (float2)( from + prev - new int2( 8, 16 ) ), 0 ); + yield return new Renderable(tesla.GetSprite(3), (float2)(from + prev - new int2(8, 16)), 0); prev.Y -= 8; while( y <= prev.Y - 8 ) { - yield return Tuple.New( tesla.GetSprite( 2 ), (float2)( from + prev - new int2( 0, 16 ) ), 0 ); + yield return new Renderable(tesla.GetSprite(2), (float2)(from + prev - new int2(0, 16)), 0); prev.Y -= 8; } } else if( y >= prev.Y + 8 ) { - yield return Tuple.New( tesla.GetSprite( 0 ), (float2)( from + prev - new int2( 8, 8 ) ), 0 ); + yield return new Renderable(tesla.GetSprite(0), (float2)(from + prev - new int2(8, 8)), 0); prev.Y += 8; while( y >= prev.Y + 8 ) { - yield return Tuple.New( tesla.GetSprite( 2 ), (float2)( from + prev - new int2( 0, 8 ) ), 0 ); + yield return new Renderable(tesla.GetSprite(2), (float2)(from + prev - new int2(0, 8)), 0); prev.Y += 8; } } else - yield return Tuple.New( tesla.GetSprite( 1 ), (float2)( from + prev - new int2( 8, 8 ) ), 0 ); + yield return new Renderable(tesla.GetSprite(1), (float2)(from + prev - new int2(8, 8)), 0); prev.X += 8; } diff --git a/OpenRa.Game/Graphics/WorldRenderer.cs b/OpenRa.Game/Graphics/WorldRenderer.cs index f62182e0f0..fb835ba60b 100644 --- a/OpenRa.Game/Graphics/WorldRenderer.cs +++ b/OpenRa.Game/Graphics/WorldRenderer.cs @@ -31,18 +31,30 @@ namespace OpenRa.Game.Graphics } void DrawSpriteList(RectangleF rect, - IEnumerable> images) + IEnumerable images) { foreach (var image in images) { - var loc = image.b; + var loc = image.Pos; - if (loc.X > rect.Right || loc.X < rect.Left - image.a.bounds.Width) + if (loc.X > rect.Right || loc.X < rect.Left - image.Sprite.bounds.Width) continue; - if (loc.Y > rect.Bottom || loc.Y < rect.Top - image.a.bounds.Height) + if (loc.Y > rect.Bottom || loc.Y < rect.Top - image.Sprite.bounds.Height) continue; - spriteRenderer.DrawSprite(image.a, loc, image.c); + spriteRenderer.DrawSprite(image.Sprite, loc, image.Palette); + } + } + + class SpriteComparer : IComparer + { + public int Compare(Renderable x, Renderable y) + { + var result = x.ZOffset.CompareTo(y.ZOffset); + if (result == 0) + result = x.Pos.Y.CompareTo(y.Pos.Y); + + return result; } } @@ -50,17 +62,18 @@ namespace OpenRa.Game.Graphics { terrainRenderer.Draw(Game.viewport); + var comparer = new SpriteComparer(); + var rect = new RectangleF( Game.viewport.Location.ToPointF(), new SizeF( Game.viewport.Width, Game.viewport.Height )); - foreach (Actor a in Game.world.Actors.OrderBy(u => u.CenterLocation.Y)) - DrawSpriteList(rect, a.Render()); + /* todo: cull to screen again */ + var renderables = Game.world.Actors.SelectMany(a => a.Render()) + .OrderBy(r => r, comparer); - foreach (var a in Game.world.Actors - .Where(u => u.traits.Contains()) - .Select(u => u.traits.Get())) - DrawSpriteList(rect, a.RenderRoof(a.self)); + foreach (var r in renderables) + spriteRenderer.DrawSprite(r.Sprite, r.Pos, r.Palette); foreach (var e in Game.world.Effects) DrawSpriteList(rect, e.Render()); diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj index 7443d3d350..6962cd2d7a 100644 --- a/OpenRa.Game/OpenRa.Game.csproj +++ b/OpenRa.Game/OpenRa.Game.csproj @@ -164,6 +164,7 @@ + diff --git a/OpenRa.Game/Traits/BelowUnits.cs b/OpenRa.Game/Traits/BelowUnits.cs new file mode 100644 index 0000000000..39260253f9 --- /dev/null +++ b/OpenRa.Game/Traits/BelowUnits.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenRa.Game.Traits +{ + class BelowUnits : IRenderModifier + { + public BelowUnits(Actor self) { } + + public IEnumerable ModifyRender(Actor self, IEnumerable r) + { + return r.Select(a => a.WithZOffset(-1)); + } + } +} diff --git a/OpenRa.Game/Traits/Cloak.cs b/OpenRa.Game/Traits/Cloak.cs index f152b04c9e..93814e0a80 100644 --- a/OpenRa.Game/Traits/Cloak.cs +++ b/OpenRa.Game/Traits/Cloak.cs @@ -18,16 +18,16 @@ namespace OpenRa.Game.Traits remainingUncloakTime = (int)(Rules.General.SubmergeDelay * 60 * 25); } - public IEnumerable> - ModifyRender(Actor self, IEnumerable> rs) + public IEnumerable + ModifyRender(Actor self, IEnumerable rs) { if (remainingUncloakTime > 0) return rs; if (self.Owner == Game.LocalPlayer) - return rs.Select(a => Tuple.New(a.a, a.b, 8)); + return rs.Select(a => a.WithPalette(8)); else - return new Tuple[] { }; + return new Renderable[] { }; } public void Tick(Actor self) diff --git a/OpenRa.Game/Traits/RallyPoint.cs b/OpenRa.Game/Traits/RallyPoint.cs index e55daad437..e4a3fc7d99 100644 --- a/OpenRa.Game/Traits/RallyPoint.cs +++ b/OpenRa.Game/Traits/RallyPoint.cs @@ -16,7 +16,7 @@ namespace OpenRa.Game.Traits anim.PlayRepeating("idle"); } - public IEnumerable> Render(Actor self) + public IEnumerable Render(Actor self) { var uog = Game.controller.orderGenerator as UnitOrderGenerator; if (uog != null && self.Owner == Game.LocalPlayer && uog.selection.Contains(self)) diff --git a/OpenRa.Game/Traits/RenderBuildingWarFactory.cs b/OpenRa.Game/Traits/RenderBuildingWarFactory.cs index 55165c9e58..8f8dbf52f2 100644 --- a/OpenRa.Game/Traits/RenderBuildingWarFactory.cs +++ b/OpenRa.Game/Traits/RenderBuildingWarFactory.cs @@ -3,7 +3,7 @@ using OpenRa.Game.Graphics; namespace OpenRa.Game.Traits { - class RenderWarFactory : RenderBuilding, INotifyBuildComplete + class RenderWarFactory : IRender, INotifyBuildComplete, INotifyDamage, ITick { public Animation roof; bool doneBuilding; @@ -12,7 +12,6 @@ namespace OpenRa.Game.Traits string prefix = ""; public RenderWarFactory(Actor self) - : base(self) { this.self = self; roof = new Animation(self.Info.Image ?? self.Info.Name); @@ -21,22 +20,19 @@ namespace OpenRa.Game.Traits public void BuildingComplete( Actor self ) { doneBuilding = true; - anim.Play( "idle" ); roof.Play( prefix + "idle-top" ); } - public IEnumerable> RenderRoof(Actor self) + public IEnumerable Render(Actor self) { if (doneBuilding) - yield return Tuple.New(roof.Image, - 24f * (float2)self.Location, self.Owner.Palette); + yield return new Renderable(roof.Image, + 24f * (float2)self.Location, self.Owner.Palette, 2); } - public override void Tick(Actor self) + public void Tick(Actor self) { - base.Tick(self); - if (doneBuilding) - roof.Tick(); + if (doneBuilding) roof.Tick(); var b = self.Bounds; if (isOpen && null == Game.UnitInfluence.GetUnitAt(((1/24f) * self.CenterLocation).ToInt2())) @@ -51,10 +47,8 @@ namespace OpenRa.Game.Traits roof.PlayThen(prefix + "build-top", () => isOpen = true); } - public override void Damaged(Actor self, AttackInfo e) + public void Damaged(Actor self, AttackInfo e) { - base.Damaged(self, e); - if (!e.DamageStateChanged) return; switch (e.DamageState) { diff --git a/OpenRa.Game/Traits/RenderSimple.cs b/OpenRa.Game/Traits/RenderSimple.cs index a1648404cd..48f9ec7837 100644 --- a/OpenRa.Game/Traits/RenderSimple.cs +++ b/OpenRa.Game/Traits/RenderSimple.cs @@ -15,7 +15,7 @@ namespace OpenRa.Game.Traits anims.Add( "", new Animation( self.Info.Image ?? self.Info.Name ) ); } - public virtual IEnumerable> Render( Actor self ) + public virtual IEnumerable Render( Actor self ) { foreach( var a in anims.Values ) if( a.DisableFunc == null || !a.DisableFunc() ) @@ -46,7 +46,7 @@ namespace OpenRa.Game.Traits this.DisableFunc = d; } - public Tuple Image( Actor self ) + public Renderable Image( Actor self ) { if( OffsetFunc != null ) return Util.Centered( self, Animation.Image, self.CenterLocation + OffsetFunc() ); diff --git a/OpenRa.Game/Traits/Submarine.cs b/OpenRa.Game/Traits/Submarine.cs index 421e4b605e..5500c06d61 100644 --- a/OpenRa.Game/Traits/Submarine.cs +++ b/OpenRa.Game/Traits/Submarine.cs @@ -21,16 +21,16 @@ namespace OpenRa.Game.Traits public void Attacking(Actor self) { DoSurface(); } public void Damaged(Actor self, AttackInfo e) { DoSurface(); } - public IEnumerable> - ModifyRender(Actor self, IEnumerable> rs) + public IEnumerable + ModifyRender(Actor self, IEnumerable rs) { if (remainingSurfaceTime > 0) return rs; - if (self.Owner == Game.LocalPlayer) - return rs.Select(a => Tuple.New(a.a, a.b, 8)); - else - return new Tuple[] { }; + if (self.Owner == Game.LocalPlayer) + return rs.Select(a => a.WithPalette(8)); + else + return new Renderable[] { }; } public void Tick(Actor self) diff --git a/OpenRa.Game/Traits/TraitsInterfaces.cs b/OpenRa.Game/Traits/TraitsInterfaces.cs index 0d82077c1b..dbe8ff8203 100644 --- a/OpenRa.Game/Traits/TraitsInterfaces.cs +++ b/OpenRa.Game/Traits/TraitsInterfaces.cs @@ -10,9 +10,32 @@ namespace OpenRa.Game.Traits // depends on the order of pips in WorldRenderer.cs! enum PipType { Transparent, Green, Yellow, Red, Gray }; enum TagType { None, Fake, Primary }; + + struct Renderable + { + public readonly Sprite Sprite; + public readonly float2 Pos; + public readonly int Palette; + public readonly int ZOffset; + + public Renderable(Sprite sprite, float2 pos, int palette, int zOffset) + { + Sprite = sprite; + Pos = pos; + Palette = palette; + ZOffset = zOffset; + } + + public Renderable(Sprite sprite, float2 pos, int palette) + : this(sprite, pos, palette, 0) { } + + public Renderable WithPalette(int newPalette) { return new Renderable(Sprite, Pos, newPalette, ZOffset); } + public Renderable WithZOffset(int newOffset) { return new Renderable(Sprite, Pos, Palette, newOffset); } + public Renderable WithPos(float2 newPos) { return new Renderable(Sprite, newPos, Palette, ZOffset); } + } interface ITick { void Tick(Actor self); } - interface IRender { IEnumerable> Render(Actor self); } + interface IRender { IEnumerable Render(Actor self); } interface INotifyDamage { void Damaged(Actor self, AttackInfo e); } interface INotifyBuildComplete { void BuildingComplete (Actor self); } interface IOrder @@ -23,8 +46,7 @@ namespace OpenRa.Game.Traits interface IProducer { bool Produce( Actor self, UnitInfo producee ); } interface IOccupySpace { IEnumerable OccupiedCells(); } interface INotifyAttack { void Attacking(Actor self); } - interface IRenderModifier { IEnumerable> - ModifyRender( Actor self, IEnumerable> r ); } + interface IRenderModifier { IEnumerable ModifyRender(Actor self, IEnumerable r); } interface IDamageModifier { float GetDamageModifier(); } interface ISpeedModifier { float GetSpeedModifier(); } interface IPips { IEnumerable GetPips(); } diff --git a/OpenRa.Game/Traits/Tree.cs b/OpenRa.Game/Traits/Tree.cs index 5b4621730f..f4c3ebced1 100644 --- a/OpenRa.Game/Traits/Tree.cs +++ b/OpenRa.Game/Traits/Tree.cs @@ -12,9 +12,9 @@ namespace OpenRa.Game.Traits Image = treeImage; } - public IEnumerable> Render(Actor self) + public IEnumerable Render(Actor self) { - yield return Tuple.New(Image, Game.CellSize * (float2)self.Location, 0); + yield return new Renderable(Image, Game.CellSize * (float2)self.Location, 0); } } } diff --git a/OpenRa.Game/Traits/Util.cs b/OpenRa.Game/Traits/Util.cs index 7f80dee427..9899519a3c 100755 --- a/OpenRa.Game/Traits/Util.cs +++ b/OpenRa.Game/Traits/Util.cs @@ -117,17 +117,11 @@ namespace OpenRa.Game.Traits public static float2 RelOffset(this int[] offset) { return new float2(offset[0], offset[1]); } public static float2 AbsOffset(this int[] offset) { return new float2(offset.ElementAtOrDefault(2), offset.ElementAtOrDefault(3)); } - public static Tuple Centered(Actor self, Sprite s, float2 location) + public static Renderable Centered(Actor self, Sprite s, float2 location) { var pal = self.Owner == null ? 0 : self.Owner.Palette; var loc = location - 0.5f * s.size; - return Tuple.New(s, loc.Round(), pal); - } - - public static Tuple CenteredShadow(Actor self, Sprite s, float2 location) - { - var loc = location - 0.5f * s.size; - return Tuple.New(s, loc.Round(), 8); + return new Renderable(s, loc.Round(), pal); } public static float GetEffectiveSpeed(Actor self) diff --git a/OpenRa.Game/Traits/WithShadow.cs b/OpenRa.Game/Traits/WithShadow.cs index 2c61805ded..529b3ac55c 100644 --- a/OpenRa.Game/Traits/WithShadow.cs +++ b/OpenRa.Game/Traits/WithShadow.cs @@ -10,11 +10,14 @@ namespace OpenRa.Game.Traits { public WithShadow(Actor self) {} - public IEnumerable> ModifyRender(Actor self, IEnumerable> r) + public IEnumerable ModifyRender(Actor self, IEnumerable r) { var unit = self.traits.Get(); - var shadowSprites = r.Select( a => Tuple.New( a.a, a.b, 8 )); - var flyingSprites = r.Select( a => Tuple.New( a.a, a.b - new float2( 0, unit.Altitude ), a.c )); + + var shadowSprites = r.Select(a => a.WithPalette(8)); + var flyingSprites = (unit.Altitude <= 0) ? r + : r.Select(a => a.WithPos(a.Pos - new float2(0, unit.Altitude)).WithZOffset(3)); + return shadowSprites.Concat(flyingSprites); } } diff --git a/units.ini b/units.ini index be36601dbc..d7be3988dc 100755 --- a/units.ini +++ b/units.ini @@ -331,7 +331,7 @@ SelectionPriority=3 LongDesc=Provides Allied advanced technologies.\n Special Ability: GPS Satellite [WEAP] Description=War Factory -Traits=Building, RenderWarFactory, RallyPoint, Production +Traits=Building, RenderBuilding, RenderWarFactory, RallyPoint, Production Dimensions=3,2 Footprint=xxx xxx Produces=Vehicle @@ -381,12 +381,12 @@ LongDesc=Stores excess harvested Ore [HPAD] Description=Helipad -Traits=Building, RenderBuilding, Production +Traits=Building, RenderBuilding, Production, BelowUnits Dimensions=2,2 Footprint=xx xx Produces=Plane SelectionPriority=3 -SpawnOffset=0,0 ; todo: push this up a bit, but we've got a z-order issue first. +SpawnOffset=0,-4 ; todo: push this up a bit, but we've got a z-order issue first. LongDesc=Produces and reloads helicopters [DOME] Description=Radar Dome @@ -397,7 +397,7 @@ SelectionPriority=3 LongDesc=Provides an overview of the battlefield.\n Requires power to operate. [AFLD] Description=Airstrip -Traits=Building, RenderBuilding, Production +Traits=Building, RenderBuilding, Production, BelowUnits Dimensions=3,2 Footprint=xxx xxx Produces=Plane @@ -452,7 +452,7 @@ SelectionPriority=3 LongDesc=Produces attack dogs [FIX] Description=Service Depot -Traits=Building, RenderBuilding +Traits=Building, RenderBuilding, BelowUnits Dimensions=3,3 Footprint=_x_ xxx _x_ SelectionPriority=3 @@ -466,7 +466,7 @@ SelectionPriority=3 LongDesc=Looks like a Construction Yard. [WEAF] Description=Fake War Factory -Traits=Building, RenderWarFactory, Fake +Traits=Building, RenderBuilding, RenderWarFactory, Fake Dimensions=3,2 Footprint=xxx xxx SelectionPriority=3