diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj
index b6170b9d72..6b357803dc 100644
--- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj
+++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj
@@ -351,7 +351,6 @@
-
@@ -520,6 +519,7 @@
+
diff --git a/OpenRA.Mods.RA/SupportPowers/SonarPulsePower.cs b/OpenRA.Mods.RA/SupportPowers/SonarPulsePower.cs
deleted file mode 100755
index 01293151ce..0000000000
--- a/OpenRA.Mods.RA/SupportPowers/SonarPulsePower.cs
+++ /dev/null
@@ -1,64 +0,0 @@
-#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.Mods.RA.Activities;
-using OpenRA.Mods.RA.Effects;
-using OpenRA.Primitives;
-
-namespace OpenRA.Mods.RA
-{
- public class SonarPulsePowerInfo : SupportPowerInfo
- {
- [Desc("Actor to spawn to reveal the submarines")]
- public readonly string SonarActor = "sonar";
-
- [Desc("Amount of time to keep the actor alive")]
- public readonly int SonarDuration = 250;
-
- public readonly string SonarPing = "sonpulse.aud";
-
- public readonly string RippleSequence = "moveflsh";
- public readonly string RipplePalette = "moveflash";
-
- public override object Create(ActorInitializer init) { return new SonarPulsePower(init.self, this); }
- }
-
- public class SonarPulsePower : SupportPower
- {
- public SonarPulsePower(Actor self, SonarPulsePowerInfo info) : base(self, info) { }
- public override void Activate(Actor self, Order order, SupportPowerManager manager)
- {
- base.Activate(self, order, manager);
-
- var info = Info as SonarPulsePowerInfo;
-
- if (info.SonarActor != null)
- {
- self.World.AddFrameEndTask(w =>
- {
- var sonar = w.CreateActor(info.SonarActor, new TypeDictionary
- {
- new LocationInit(order.TargetLocation),
- new OwnerInit(self.Owner),
- });
-
- Sound.Play(info.SonarPing, sonar.CenterPosition);
-
- if (!string.IsNullOrEmpty(info.RippleSequence) && !string.IsNullOrEmpty(info.RipplePalette))
- w.Add(new SpriteEffect(sonar.CenterPosition, w, info.RippleSequence, info.RipplePalette));
-
- sonar.QueueActivity(new Wait(info.SonarDuration));
- sonar.QueueActivity(new RemoveSelf());
- });
- }
- }
- }
-}
diff --git a/OpenRA.Mods.RA/SupportPowers/SpawnActorPower.cs b/OpenRA.Mods.RA/SupportPowers/SpawnActorPower.cs
new file mode 100755
index 0000000000..a3927557e4
--- /dev/null
+++ b/OpenRA.Mods.RA/SupportPowers/SpawnActorPower.cs
@@ -0,0 +1,67 @@
+#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.Mods.RA.Activities;
+using OpenRA.Mods.RA.Effects;
+using OpenRA.Primitives;
+
+namespace OpenRA.Mods.RA
+{
+ [Desc("Spawns an actor that stays for a limited amount of time.")]
+ public class SpawnActorPowerInfo : SupportPowerInfo
+ {
+ [Desc("Actor to spawn.")]
+ public readonly string Actor = null;
+
+ [Desc("Amount of time to keep the actor alive in ticks.")]
+ public readonly int LifeTime = 250;
+
+ public readonly string DeploySound = null;
+
+ public readonly string EffectSequence = null;
+ public readonly string EffectPalette = null;
+
+ public override object Create(ActorInitializer init) { return new SpawnActorPower(init.self, this); }
+ }
+
+ public class SpawnActorPower : SupportPower
+ {
+ public SpawnActorPower(Actor self, SpawnActorPowerInfo info) : base(self, info) { }
+ public override void Activate(Actor self, Order order, SupportPowerManager manager)
+ {
+ base.Activate(self, order, manager);
+
+ var info = Info as SpawnActorPowerInfo;
+
+ if (info.Actor != null)
+ {
+ self.World.AddFrameEndTask(w =>
+ {
+ var location = self.World.Map.CenterOfCell(order.TargetLocation);
+
+ Sound.Play(info.DeploySound, location);
+
+ if (!string.IsNullOrEmpty(info.EffectSequence) && !string.IsNullOrEmpty(info.EffectPalette))
+ w.Add(new SpriteEffect(location, w, info.EffectSequence, info.EffectPalette));
+
+ var actor = w.CreateActor(info.Actor, new TypeDictionary
+ {
+ new LocationInit(order.TargetLocation),
+ new OwnerInit(self.Owner),
+ });
+
+ actor.QueueActivity(new Wait(info.LifeTime));
+ actor.QueueActivity(new RemoveSelf());
+ });
+ }
+ }
+ }
+}
diff --git a/OpenRA.Utility/UpgradeRules.cs b/OpenRA.Utility/UpgradeRules.cs
index e6ad3bd9ca..f1da09e260 100644
--- a/OpenRA.Utility/UpgradeRules.cs
+++ b/OpenRA.Utility/UpgradeRules.cs
@@ -282,6 +282,13 @@ namespace OpenRA.Utility
node.Key = "ParachuteSequence";
}
+ // SonarPulsePower was implemented as a generic SpawnActorPower
+ if (engineVersion < 20140703)
+ {
+ if (depth == 1 && node.Key == "SonarPulsePower")
+ node.Key = "SpawnActorPower";
+ }
+
if (engineVersion < 20140707)
{
// SpyPlanePower was removed (use AirstrikePower instead)
diff --git a/mods/ra/rules/misc.yaml b/mods/ra/rules/misc.yaml
index 4018d03757..6316d7d81c 100644
--- a/mods/ra/rules/misc.yaml
+++ b/mods/ra/rules/misc.yaml
@@ -282,13 +282,18 @@ powerproxy.parabombs:
CameraActor: camera
powerproxy.sonarpulse:
- SonarPulsePower:
+ SpawnActorPower:
Icon: sonar
Description: Sonar Pulse
LongDesc: Reveals all submarines in the vicinity for a \nshort time.
ChargeTime: 30
EndChargeSound: pulse1.aud
SelectTargetSound: slcttgt1.aud
+ Actor: sonar
+ LifeTime: 250
+ DeploySound: sonpulse.aud
+ EffectSequence: moveflsh
+ EffectPalette: moveflash
mpspawn:
Immobile: