diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
index 46d96e8281..167eb26aa1 100644
--- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
+++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
@@ -443,6 +443,8 @@
+
+
diff --git a/OpenRA.Mods.Common/Traits/Render/WithNukeLaunchAnimation.cs b/OpenRA.Mods.Common/Traits/Render/WithNukeLaunchAnimation.cs
new file mode 100644
index 0000000000..853681ffbf
--- /dev/null
+++ b/OpenRA.Mods.Common/Traits/Render/WithNukeLaunchAnimation.cs
@@ -0,0 +1,54 @@
+#region Copyright & License Information
+/*
+ * Copyright 2007-2017 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, either version 3 of
+ * the License, or (at your option) any later version. For more
+ * information, see COPYING.
+ */
+#endregion
+
+using OpenRA.Traits;
+
+namespace OpenRA.Mods.Common.Traits.Render
+{
+ [Desc("Replaces the building animation when `NukePower` is triggered.")]
+ public class WithNukeLaunchAnimationInfo : ConditionalTraitInfo, Requires
+ {
+ [Desc("Sequence name to use")]
+ [SequenceReference] public readonly string Sequence = "active";
+
+ public override object Create(ActorInitializer init) { return new WithNukeLaunchAnimation(init.Self, this); }
+ }
+
+ public class WithNukeLaunchAnimation : ConditionalTrait, INotifyNuke, INotifyBuildComplete, INotifySold
+ {
+ readonly WithSpriteBody spriteBody;
+ bool buildComplete;
+
+ public WithNukeLaunchAnimation(Actor self, WithNukeLaunchAnimationInfo info)
+ : base(info)
+ {
+ spriteBody = self.TraitOrDefault();
+ }
+
+ void INotifyNuke.Launching(Actor self)
+ {
+ if (buildComplete && spriteBody != null && !IsTraitDisabled)
+ spriteBody.PlayCustomAnimation(self, Info.Sequence, () => spriteBody.CancelCustomAnimation(self));
+ }
+
+ void INotifyBuildComplete.BuildingComplete(Actor self)
+ {
+ buildComplete = true;
+ }
+
+ void INotifySold.Selling(Actor self)
+ {
+ buildComplete = false;
+ }
+
+ void INotifySold.Sold(Actor self) { }
+ }
+}
\ No newline at end of file
diff --git a/OpenRA.Mods.Common/Traits/Render/WithNukeLaunchOverlay.cs b/OpenRA.Mods.Common/Traits/Render/WithNukeLaunchOverlay.cs
new file mode 100644
index 0000000000..ef5c8d86c5
--- /dev/null
+++ b/OpenRA.Mods.Common/Traits/Render/WithNukeLaunchOverlay.cs
@@ -0,0 +1,77 @@
+#region Copyright & License Information
+/*
+ * Copyright 2007-2017 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, either version 3 of
+ * the License, or (at your option) any later version. For more
+ * information, see COPYING.
+ */
+#endregion
+
+using OpenRA.Effects;
+using OpenRA.Graphics;
+using OpenRA.Traits;
+
+namespace OpenRA.Mods.Common.Traits.Render
+{
+ [Desc("Displays an overlay when `NukePower` is triggered.")]
+ public class WithNukeLaunchOverlayInfo : ConditionalTraitInfo, Requires, Requires
+ {
+ [Desc("Sequence name to use")]
+ [SequenceReference] public readonly string Sequence = "active";
+
+ [Desc("Position relative to body")]
+ public readonly WVec Offset = WVec.Zero;
+
+ [Desc("Custom palette name")]
+ [PaletteReference("IsPlayerPalette")] public readonly string Palette = null;
+
+ [Desc("Custom palette is a player palette BaseName")]
+ public readonly bool IsPlayerPalette = false;
+
+ public override object Create(ActorInitializer init) { return new WithNukeLaunchOverlay(init.Self, this); }
+ }
+
+ public class WithNukeLaunchOverlay : ConditionalTrait, INotifyBuildComplete, INotifySold, INotifyNuke
+ {
+ readonly Animation overlay;
+ bool buildComplete;
+ bool visible;
+
+ public WithNukeLaunchOverlay(Actor self, WithNukeLaunchOverlayInfo info)
+ : base(info)
+ {
+ var rs = self.Trait();
+ var body = self.Trait();
+
+ buildComplete = !self.Info.HasTraitInfo(); // always render instantly for units
+ overlay = new Animation(self.World, rs.GetImage(self));
+ overlay.PlayThen(info.Sequence, () => visible = false);
+
+ var anim = new AnimationWithOffset(overlay,
+ () => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))),
+ () => IsTraitDisabled || !visible || !buildComplete,
+ p => RenderUtils.ZOffsetFromCenter(self, p, 1));
+
+ rs.Add(anim, info.Palette, info.IsPlayerPalette);
+ }
+
+ void INotifyBuildComplete.BuildingComplete(Actor self)
+ {
+ buildComplete = true;
+ }
+
+ void INotifySold.Sold(Actor self) { }
+ void INotifySold.Selling(Actor self)
+ {
+ buildComplete = false;
+ }
+
+ void INotifyNuke.Launching(Actor self)
+ {
+ visible = true;
+ overlay.PlayThen(overlay.CurrentSequence.Name, () => visible = false);
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenRA.Mods.Common/Traits/SupportPowers/NukePower.cs b/OpenRA.Mods.Common/Traits/SupportPowers/NukePower.cs
index 44dd936059..05c13c01fb 100644
--- a/OpenRA.Mods.Common/Traits/SupportPowers/NukePower.cs
+++ b/OpenRA.Mods.Common/Traits/SupportPowers/NukePower.cs
@@ -72,10 +72,6 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Corresponds to `Type` from `FlashPaletteEffect` on the world actor.")]
public readonly string FlashType = null;
- [SequenceReference]
- [Desc("Sequence the launching actor should play when activating this power.")]
- public readonly string ActivationSequence = "active";
-
public WeaponInfo WeaponInfo { get; private set; }
public override object Create(ActorInitializer init) { return new NukePower(init.Self, this); }
@@ -103,11 +99,8 @@ namespace OpenRA.Mods.Common.Traits
base.Activate(self, order, manager);
PlayLaunchSounds();
- if (!string.IsNullOrEmpty(info.ActivationSequence))
- {
- var wsb = self.Trait();
- wsb.PlayCustomAnimation(self, info.ActivationSequence);
- }
+ foreach (var launchpad in self.TraitsImplementing())
+ launchpad.Launching(self);
var targetPosition = self.World.Map.CenterOfCell(order.TargetLocation);
var palette = info.IsPlayerPalette ? info.MissilePalette + self.Owner.InternalName : info.MissilePalette;
diff --git a/OpenRA.Mods.Common/TraitsInterfaces.cs b/OpenRA.Mods.Common/TraitsInterfaces.cs
index 0445f590db..4decc747c7 100644
--- a/OpenRA.Mods.Common/TraitsInterfaces.cs
+++ b/OpenRA.Mods.Common/TraitsInterfaces.cs
@@ -84,6 +84,7 @@ namespace OpenRA.Mods.Common.Traits
public interface INotifyBuildingPlaced { void BuildingPlaced(Actor self); }
public interface INotifyRepair { void Repairing(Actor self, Actor target); }
+ public interface INotifyNuke { void Launching(Actor self); }
public interface INotifyBurstComplete { void FiredBurst(Actor self, Target target, Armament a); }
public interface INotifyChat { bool OnChat(string from, string message); }
public interface INotifyProduction { void UnitProduced(Actor self, Actor other, CPos exit); }
diff --git a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs
index c98a1cbb6d..64ec434114 100644
--- a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs
+++ b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs
@@ -974,6 +974,16 @@ namespace OpenRA.Mods.Common.UtilityCommands
}
}
+ // nuke launch animation is now it's own trait
+ if (engineVersion < 20170820)
+ {
+ if (depth == 1 && node.Key.StartsWith("NukePower"))
+ {
+ node.Value.Nodes.RemoveAll(n => n.Key == "ActivationSequence");
+ addNodes.Add(new MiniYamlNode("WithNukeLaunchAnimation", new MiniYaml("")));
+ }
+ }
+
UpgradeActorRules(modData, engineVersion, ref node.Value.Nodes, node, depth + 1);
}
diff --git a/mods/cnc/rules/structures.yaml b/mods/cnc/rules/structures.yaml
index 59c5f5e805..1dda026f5f 100644
--- a/mods/cnc/rules/structures.yaml
+++ b/mods/cnc/rules/structures.yaml
@@ -724,6 +724,7 @@ TMPL:
ArrowSequence: arrow
ClockSequence: clock
CircleSequence: circles
+ WithNukeLaunchAnimation:
SupportPowerChargeBar:
Power:
Amount: -150
diff --git a/mods/d2k/rules/structures.yaml b/mods/d2k/rules/structures.yaml
index 44e80cbbed..de0d817b34 100644
--- a/mods/d2k/rules/structures.yaml
+++ b/mods/d2k/rules/structures.yaml
@@ -1072,9 +1072,13 @@ palace:
DisplayBeacon: True
DisplayRadarPing: True
CameraRange: 10c0
- ActivationSequence:
ArrowSequence: arrow
CircleSequence: circles
+ WithNukeLaunchOverlay:
+ RequiresCondition: !launchpad-damaged
+ GrantConditionOnDamageState@LAUNCHPADDAMAGED:
+ Condition: launchpad-damaged
+ ValidDamageState: Medium, Heavy, Critical
ProduceActorPower@fremen:
Description: Recruit Fremen
LongDesc: Elite infantry unit armed with assault rifles and rockets\n Strong vs Infantry, Vehicles\n Weak vs Artillery\n Special Ability: Invisibility
diff --git a/mods/d2k/sequences/structures.yaml b/mods/d2k/sequences/structures.yaml
index c7dc3b5941..fd1c05cd0a 100644
--- a/mods/d2k/sequences/structures.yaml
+++ b/mods/d2k/sequences/structures.yaml
@@ -566,6 +566,9 @@ palace.atreides:
idle: DATA.R8
Start: 2924
Offset: -48,48
+ active: DATA.R8
+ Start: 2924
+ Offset: -48,48
make: DATA.R8
Start: 4677
Length: 11
@@ -980,10 +983,10 @@ palace.harkonnen:
damaged-idle: DATA.R8
Start: 3085
Offset: -48,48
-# active: DATA.R8 # TODO: overlay
-# Start: 5084
-# Length: 20
-# Offset: -48,64
+ active: DATA.R8
+ Start: 5084
+ Length: 20
+ Offset: -48,64
damaged-active: DATA.R8
Start: 5084
Length: 20
@@ -1371,6 +1374,9 @@ palace.ordos:
idle: DATA.R8
Start: 3244
Offset: -48,48
+ active: DATA.R8
+ Start: 3244
+ Offset: -48,48
make: DATA.R8
Start: 4677
Length: 11
@@ -1485,6 +1491,9 @@ palace.corrino:
idle: DATA.R8
Start: 3252
Offset: -48,48
+ active: DATA.R8
+ Start: 3252
+ Offset: -48,48
damaged-idle: DATA.R8
Start: 3253
Offset: -48,48
diff --git a/mods/ra/rules/structures.yaml b/mods/ra/rules/structures.yaml
index fc1608bffd..586837b55e 100644
--- a/mods/ra/rules/structures.yaml
+++ b/mods/ra/rules/structures.yaml
@@ -61,6 +61,7 @@ MSLO:
Amount: -150
MustBeDestroyed:
RequiredForShortGame: false
+ WithNukeLaunchAnimation:
GAP:
Inherits: ^ScienceBuilding
diff --git a/mods/ts/rules/nod-support.yaml b/mods/ts/rules/nod-support.yaml
index 295f4b2a03..c517fccdc0 100644
--- a/mods/ts/rules/nod-support.yaml
+++ b/mods/ts/rules/nod-support.yaml
@@ -378,6 +378,7 @@ NAMISL:
DisplayRadarPing: True
BeaconPoster:
CameraRange: 10c0
+ WithNukeLaunchOverlay:
SelectionDecorations:
VisualBounds: 75,48
diff --git a/mods/ts/sequences/structures.yaml b/mods/ts/sequences/structures.yaml
index b96c8a2d0f..59c472fa8e 100644
--- a/mods/ts/sequences/structures.yaml
+++ b/mods/ts/sequences/structures.yaml
@@ -1871,10 +1871,10 @@ namisl:
make: ntmislmk
Length: 18
ShadowStart: 18
- active: ntmisl_a # TODO: This is an overlay, but currently used as animation
+ active: ntmisl_a
Length: 10
Tick: 80
- damaged-active: ntmisl_a # TODO: This is an overlay, but currently used as animation
+ damaged-active: ntmisl_a
Start: 10
Length: 10
Tick: 80