diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
index c617cbea48..49d839cb9a 100644
--- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
+++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
@@ -405,6 +405,7 @@
+
diff --git a/OpenRA.Mods.Common/Traits/Render/WithProductionDoorOverlay.cs b/OpenRA.Mods.Common/Traits/Render/WithProductionDoorOverlay.cs
new file mode 100644
index 0000000000..85f95d526c
--- /dev/null
+++ b/OpenRA.Mods.Common/Traits/Render/WithProductionDoorOverlay.cs
@@ -0,0 +1,91 @@
+#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.Graphics;
+using OpenRA.Mods.Common.Traits;
+using OpenRA.Traits;
+
+namespace OpenRA.Mods.TS.Traits
+{
+ [Desc("Play an animation when a unit exits or blocks the exit after production finished.")]
+ class WithProductionDoorOverlayInfo : ITraitInfo, IRenderActorPreviewSpritesInfo, Requires, Requires, Requires
+ {
+ public readonly string Sequence = "idle-door";
+ public readonly string BuildSequence = "build-door";
+
+ public object Create(ActorInitializer init) { return new WithProductionDoorOverlay(init.Self, this); }
+
+ public IEnumerable RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)
+ {
+ var anim = new Animation(init.World, image, () => 0);
+ anim.PlayRepeating(Sequence);
+
+ var bi = init.Actor.Traits.Get();
+ var offset = FootprintUtils.CenterOffset(init.World, bi).Y + 512; // Additional 512 units move from center -> top of cell
+ yield return new SpriteActorPreview(anim, WVec.Zero, offset, p, rs.Scale);
+ }
+ }
+
+ class WithProductionDoorOverlay : INotifyBuildComplete, ITick, INotifyProduction, INotifySold, INotifyDamageStateChanged
+ {
+ readonly WithProductionDoorOverlayInfo info;
+ readonly RenderSprites renderSprites;
+ readonly Animation door;
+
+ bool isOpen;
+ CPos openExit;
+ bool buildComplete;
+
+ public WithProductionDoorOverlay(Actor self, WithProductionDoorOverlayInfo info)
+ {
+ this.info = info;
+ renderSprites = self.Trait();
+ door = new Animation(self.World, renderSprites.GetImage(self));
+ door.Play(RenderSprites.NormalizeSequence(door, self.GetDamageState(), info.Sequence));
+
+ var buildingInfo = self.Info.Traits.Get();
+
+ var offset = FootprintUtils.CenterOffset(self.World, buildingInfo).Y + 512;
+ renderSprites.Add("door_overlay_{0}".F(info.Sequence), new AnimationWithOffset(door, null, () => !buildComplete, offset));
+ }
+
+ public void BuildingComplete(Actor self)
+ {
+ buildComplete = true;
+ }
+
+ public void Tick(Actor self)
+ {
+ if (isOpen && !self.World.ActorMap.GetUnitsAt(openExit).Any(a => a != self))
+ {
+ isOpen = false;
+ door.PlayBackwardsThen(RenderSprites.NormalizeSequence(door, self.GetDamageState(), info.BuildSequence),
+ () => door.Play(RenderSprites.NormalizeSequence(door, self.GetDamageState(), info.Sequence)));
+ }
+ }
+
+ public void DamageStateChanged(Actor self, AttackInfo e)
+ {
+ if (door.CurrentSequence != null)
+ door.ReplaceAnim(RenderSprites.NormalizeSequence(door, e.DamageState, door.CurrentSequence.Name));
+ }
+
+ public void UnitProduced(Actor self, Actor other, CPos exit)
+ {
+ door.PlayThen(RenderSprites.NormalizeSequence(door, self.GetDamageState(), info.BuildSequence), () => { isOpen = true; openExit = exit; });
+ }
+
+ public void Selling(Actor self) { buildComplete = false; }
+ public void Sold(Actor self) { }
+ }
+}
diff --git a/mods/ts/rules/gdi-structures.yaml b/mods/ts/rules/gdi-structures.yaml
index 6ecf481663..a3138fcf3e 100644
--- a/mods/ts/rules/gdi-structures.yaml
+++ b/mods/ts/rules/gdi-structures.yaml
@@ -123,8 +123,6 @@ GAWEAP:
HP: 1000
RevealsShroud:
Range: 4c0
- -RenderBuilding:
- RenderBuildingWarFactory:
RallyPoint:
RallyPoint: 6,1
Exit@1:
@@ -134,6 +132,9 @@ GAWEAP:
Produces: Vehicle
PrimaryBuilding:
ProductionBar:
+ WithIdleOverlay@ROOF:
+ Sequence: idle-roof
+ WithProductionDoorOverlay@DOOR:
WithProductionOverlay@WHITELIGHTS:
Sequence: production-lights-white
WithProductionOverlay@REDLIGHTS:
diff --git a/mods/ts/rules/nod-structures.yaml b/mods/ts/rules/nod-structures.yaml
index 15118349d8..71aa3ad2e4 100644
--- a/mods/ts/rules/nod-structures.yaml
+++ b/mods/ts/rules/nod-structures.yaml
@@ -130,8 +130,6 @@ NAWEAP:
HP: 1000
RevealsShroud:
Range: 4c0
- -RenderBuilding:
- RenderBuildingWarFactory:
RallyPoint:
RallyPoint: 6,1
Exit@1:
@@ -141,6 +139,9 @@ NAWEAP:
Produces: Vehicle
PrimaryBuilding:
ProductionBar:
+ WithIdleOverlay@ROOF:
+ Sequence: idle-roof
+ WithProductionDoorOverlay@DOOR:
WithProductionOverlay@LIGHTS:
Sequence: production-lights
WithIdleOverlay@BIB:
diff --git a/mods/ts/sequences/structures.yaml b/mods/ts/sequences/structures.yaml
index 7deb008378..0ba1da08d2 100644
--- a/mods/ts/sequences/structures.yaml
+++ b/mods/ts/sequences/structures.yaml
@@ -136,12 +136,17 @@ gaweap:
Defaults:
Offset: -12, -42
UseTilesetCode: true
- idle:
- ShadowStart: 3
- damaged-idle:
+ idle: gtweap_1
+ ShadowStart: 2
+ damaged-idle: gtweap_1
Start: 1
- ShadowStart: 4
- dead:
+ ShadowStart: 3
+ idle-roof: gtweap_2
+ ShadowStart: 2
+ damaged-idle-roof: gtweap_2
+ Start: 1
+ ShadowStart: 3
+ dead: gtweap
Start: 2
ShadowStart: 5
Tick: 400
@@ -171,14 +176,14 @@ gaweap:
Length: 4
Tick: 80
ZOffset: 2048
- build-top: gtweap_d
+ build-door: gtweap_d
Length: 9
ShadowStart: 9
- damaged-build-top: gtweap_d
+ damaged-build-door: gtweap_d
Length: 9
ShadowStart: 9
- idle-top: gtweap_2
- damaged-idle-top: gtweap_2
+ idle-door: gtweap_d
+ damaged-idle-door: gtweap_d
Start: 1
make: gtweapmk
Length: 20
@@ -195,7 +200,6 @@ gaweap:
icon: weapicon
Offset: 0, 0
UseTilesetCode: false
-# TODO: gtweap_1 & gtweap_a & gtweap_b & gtweap_c are unused
napowr:
Defaults:
@@ -289,12 +293,17 @@ naweap:
Defaults:
Offset: -12, -42
UseTilesetCode: true
- idle:
- ShadowStart: 3
- damaged-idle:
+ idle: ntweap_1
+ ShadowStart: 2
+ damaged-idle: ntweap_1
Start: 1
- ShadowStart: 4
- dead:
+ ShadowStart: 3
+ idle-roof: ntweap_2
+ ShadowStart: 2
+ damaged-idle-roof: ntweap_2
+ Start: 1
+ ShadowStart: 3
+ dead: ntweap
Start: 2
ShadowStart: 5
Tick: 400
@@ -307,15 +316,15 @@ naweap:
Length: 16
Tick: 100
ZOffset: 2048
- build-top: ntweap_b
+ build-door: ntweap_b
Length: 10
ShadowStart: 10
- damaged-build-top: ntweap_b
+ damaged-build-door: ntweap_b
Start: 10
Length: 10
ShadowStart: 20
- idle-top: ntweap_2
- damaged-idle-top: ntweap_2
+ idle-door: ntweap_b
+ damaged-idle-door: ntweap_b
Start: 1
make: ntweapmk
Length: 22
@@ -329,7 +338,6 @@ naweap:
icon: nwepicon
Offset: 0, 0
UseTilesetCode: false
-# TODO: ntweap_1 & ntweap_b & ntweap_c are unused
naradr:
Defaults: