diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs
index df81e3eb88..93f785f8fd 100755
--- a/OpenRA.Game/Traits/TraitsInterfaces.cs
+++ b/OpenRA.Game/Traits/TraitsInterfaces.cs
@@ -74,6 +74,7 @@ namespace OpenRA.Traits
public interface INotifyBuildComplete { void BuildingComplete(Actor self); }
public interface INotifyBuildingPlaced { void BuildingPlaced(Actor self); }
public interface INotifyProduction { void UnitProduced(Actor self, Actor other, CPos exit); }
+ public interface INotifyDelivery { void IncomingDelivery(Actor self); void Delivered(Actor self); }
public interface INotifyOwnerChanged { void OnOwnerChanged(Actor self, Player oldOwner, Player newOwner); }
public interface INotifyCapture { void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner); }
public interface INotifyHarvest { void Harvested(Actor self, ResourceType resource); }
diff --git a/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj b/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj
index ec7117f3eb..cc401b6ba5 100644
--- a/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj
+++ b/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj
@@ -102,6 +102,7 @@
+
diff --git a/OpenRA.Mods.Cnc/ProductionAirdrop.cs b/OpenRA.Mods.Cnc/ProductionAirdrop.cs
index d093b56c20..6146002702 100644
--- a/OpenRA.Mods.Cnc/ProductionAirdrop.cs
+++ b/OpenRA.Mods.Cnc/ProductionAirdrop.cs
@@ -45,8 +45,8 @@ namespace OpenRA.Mods.Cnc
// Assume a single exit point for simplicity
var exit = self.Info.Traits.WithInterface().First();
- var rb = self.Trait();
- rb.PlayCustomAnimRepeating(self, "active");
+ foreach (var tower in self.TraitsImplementing())
+ tower.IncomingDelivery(self);
var actorType = (Info as ProductionAirdropInfo).ActorType;
@@ -67,7 +67,8 @@ namespace OpenRA.Mods.Cnc
if (!self.IsInWorld || self.IsDead())
return;
- rb.PlayCustomAnimRepeating(self, "idle");
+ foreach (var cargo in self.TraitsImplementing())
+ cargo.Delivered(self);
self.World.AddFrameEndTask(ww => DoProduction(self, producee, exit));
Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", (Info as ProductionAirdropInfo).ReadyAudio, self.Owner.Country.Race);
}));
diff --git a/OpenRA.Mods.Cnc/WithDeliveryAnimation.cs b/OpenRA.Mods.Cnc/WithDeliveryAnimation.cs
new file mode 100644
index 0000000000..ce38bdd30b
--- /dev/null
+++ b/OpenRA.Mods.Cnc/WithDeliveryAnimation.cs
@@ -0,0 +1,52 @@
+#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;
+using OpenRA.Mods.RA.Buildings;
+using OpenRA.Effects;
+
+namespace OpenRA.Mods.RA.Render
+{
+ public class WithDeliveryAnimationInfo : ITraitInfo, Requires
+ {
+ public readonly string ActiveSequence = "active";
+
+ public readonly string IdleSequence = "idle";
+
+ public object Create(ActorInitializer init) { return new WithDeliveryAnimation(init.self, this); }
+ }
+
+ public class WithDeliveryAnimation : INotifyDelivery
+ {
+ WithDeliveryAnimationInfo info;
+ RenderBuilding building;
+
+ public WithDeliveryAnimation(Actor self, WithDeliveryAnimationInfo info)
+ {
+ building = self.Trait();
+
+ this.info = info;
+ }
+
+ public void IncomingDelivery(Actor self)
+ {
+ building.PlayCustomAnimRepeating(self, info.ActiveSequence);
+ }
+
+ public void Delivered(Actor self)
+ {
+ building.PlayCustomAnimRepeating(self, info.IdleSequence);
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj b/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj
index fd7d79d8a8..7218a94d50 100644
--- a/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj
+++ b/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj
@@ -90,6 +90,7 @@
+
diff --git a/OpenRA.Mods.D2k/Render/WithDeliveryOverlay.cs b/OpenRA.Mods.D2k/Render/WithDeliveryOverlay.cs
new file mode 100644
index 0000000000..6048990a0a
--- /dev/null
+++ b/OpenRA.Mods.D2k/Render/WithDeliveryOverlay.cs
@@ -0,0 +1,74 @@
+#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 OpenRA.Effects;
+using OpenRA.FileFormats;
+using OpenRA.Graphics;
+using OpenRA.Traits;
+using OpenRA.Mods.RA.Buildings;
+
+namespace OpenRA.Mods.RA.Render
+{
+ public class WithDeliveryOverlayInfo : ITraitInfo, Requires, Requires
+ {
+ [Desc("Sequence name to use")]
+ public readonly string Sequence = "active";
+
+ [Desc("Position relative to body")]
+ public readonly WVec Offset = WVec.Zero;
+
+ public object Create(ActorInitializer init) { return new WithDeliveryOverlay(init.self, this); }
+ }
+
+ public class WithDeliveryOverlay : INotifyBuildComplete, INotifySold, INotifyDelivery
+ {
+ WithDeliveryOverlayInfo info;
+ Animation overlay;
+ bool buildComplete, delivering;
+
+ public WithDeliveryOverlay(Actor self, WithDeliveryOverlayInfo info)
+ {
+ this.info = info;
+
+ var rs = self.Trait();
+ var body = self.Trait();
+
+ buildComplete = !self.HasTrait(); // always render instantly for units
+
+ overlay = new Animation(self.World, rs.GetImage(self));
+ overlay.Play(info.Sequence);
+ rs.anims.Add("delivery_overlay_{0}".F(info.Sequence),
+ new AnimationWithOffset(overlay,
+ () => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))),
+ () => !buildComplete));
+ }
+
+ void PlayDeliveryOverlay()
+ {
+ if (delivering)
+ overlay.PlayThen(info.Sequence, PlayDeliveryOverlay);
+ }
+
+ public void BuildingComplete(Actor self)
+ {
+ self.World.AddFrameEndTask(w => w.Add(new DelayedAction(120, () =>
+ buildComplete = true)));
+ }
+
+ public void Sold(Actor self) { }
+ public void Selling(Actor self)
+ {
+ buildComplete = false;
+ }
+
+ public void IncomingDelivery(Actor self) { delivering = true; PlayDeliveryOverlay(); }
+ public void Delivered(Actor self) { delivering = false; }
+ }
+}
\ No newline at end of file
diff --git a/mods/cnc/rules/structures.yaml b/mods/cnc/rules/structures.yaml
index 5fcf9e9ffe..da3c0bd4a7 100644
--- a/mods/cnc/rules/structures.yaml
+++ b/mods/cnc/rules/structures.yaml
@@ -269,6 +269,7 @@ AFLD:
ExitCell: 3,1
ProductionAirdrop:
Produces: Vehicle
+ WithDeliveryAnimation:
ProductionQueue:
Type: Vehicle
Group: Vehicle
diff --git a/mods/d2k/rules/structures.yaml b/mods/d2k/rules/structures.yaml
index 2655ddabdc..d0d33ce578 100644
--- a/mods/d2k/rules/structures.yaml
+++ b/mods/d2k/rules/structures.yaml
@@ -379,6 +379,7 @@ CONCRETEB:
ProductionAirdrop:
Produces: Starport
ActorType: frigate
+ WithDeliveryOverlay:
ProductionBar:
PrimaryBuilding:
RequiresPower:
diff --git a/mods/d2k/sequences/structures.yaml b/mods/d2k/sequences/structures.yaml
index 5ee32b28ef..603f961982 100644
--- a/mods/d2k/sequences/structures.yaml
+++ b/mods/d2k/sequences/structures.yaml
@@ -309,19 +309,24 @@ starporta:
Start: 2671
ZOffset: -1c511
Offset: -48,64
- active: DATA
- Start: 2671
- Length: 1
- ZOffset: -1c511
- Offset: -48,64
damaged-idle: DATA
Start: 2672
ZOffset: -1c511
Offset: -48,64
- damaged-active: DATA
- Start: 2672
+ active: DATA
+ Start: 4723
+ Length: 23
ZOffset: -1c511
Offset: -48,64
+ BlendMode: Alpha
+ Tick: 200
+ damaged-active: DATA
+ Start: 4723
+ Length: 23
+ ZOffset: -1c511
+ Offset: -48,64
+ BlendMode: Alpha
+ Tick: 200
make: DATA
Start: 4347
Length: 11
@@ -806,19 +811,24 @@ starporth:
Start: 2831
ZOffset: -1c511
Offset: -48,64
- active: DATA
- Start: 2831
- Length: 1
- Offset: -48,64
- ZOffset: -1c511
damaged-idle: DATA
Start: 2832
Offset: -48,64
ZOffset: -1c511
- damaged-active: DATA
- Start: 2832
- Offset: -48,64
+ active: DATA
+ Start: 4723
+ Length: 23
ZOffset: -1c511
+ Offset: -48,64
+ BlendMode: Alpha
+ Tick: 200
+ damaged-active: DATA
+ Start: 4723
+ Length: 23
+ ZOffset: -1c511
+ Offset: -48,64
+ BlendMode: Alpha
+ Tick: 200
make: DATA
Start: 4347
Length: 11
@@ -1212,19 +1222,24 @@ starporto:
Start: 2991
Offset: -48,64
ZOffset: -1c511
- active: DATA
- Start: 2991
- Length: 1
- Offset: -48,64
- ZOffset: -1c511
damaged-idle: DATA
Start: 2992
Offset: -48,64
ZOffset: -1c511
- damaged-active: DATA
- Start: 2992
- Offset: -48,64
+ active: DATA
+ Start: 4723
+ Length: 23
ZOffset: -1c511
+ Offset: -48,64
+ BlendMode: Alpha
+ Tick: 200
+ damaged-active: DATA
+ Start: 4723
+ Length: 23
+ ZOffset: -1c511
+ Offset: -48,64
+ BlendMode: Alpha
+ Tick: 200
make: DATA
Start: 4347
Length: 11
@@ -1600,19 +1615,24 @@ starportc: # TODO: unused
Start: 2999
Offset: -48,64
ZOffset: -1c511
- active: DATA
- Start: 2999
- Length: 1
- Offset: -48,64
- ZOffset: -1c511
damaged-idle: DATA
Start: 3000
Offset: -48,64
ZOffset: -1c511
- damaged-active: DATA
- Start: 3000
- Offset: -48,64
+ active: DATA
+ Start: 4723
+ Length: 23
ZOffset: -1c511
+ Offset: -48,64
+ BlendMode: Alpha
+ Tick: 200
+ damaged-active: DATA
+ Start: 4723
+ Length: 23
+ ZOffset: -1c511
+ Offset: -48,64
+ BlendMode: Alpha
+ Tick: 200
make: DATA
Start: 4347
Length: 11