diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj
index 9d98f7e452..fe0a9a30da 100644
--- a/OpenRa.Game/OpenRa.Game.csproj
+++ b/OpenRa.Game/OpenRa.Game.csproj
@@ -226,6 +226,7 @@
+
diff --git a/OpenRa.Game/Traits/ChronoshiftPower.cs b/OpenRa.Game/Traits/ChronoshiftPower.cs
index 82d956fd4d..26143e1cdd 100644
--- a/OpenRa.Game/Traits/ChronoshiftPower.cs
+++ b/OpenRa.Game/Traits/ChronoshiftPower.cs
@@ -32,7 +32,9 @@ namespace OpenRa.Traits
if (order.OrderString == "ChronosphereFinish")
{
- Game.controller.CancelInputMode();
+ if (self.Owner == self.World.LocalPlayer)
+ Game.controller.CancelInputMode();
+
FinishActivate();
Sound.Play("chrono2.aud");
diff --git a/OpenRa.Game/Traits/GpsPower.cs b/OpenRa.Game/Traits/GpsPower.cs
index b3ea8af8c5..425d2120c7 100644
--- a/OpenRa.Game/Traits/GpsPower.cs
+++ b/OpenRa.Game/Traits/GpsPower.cs
@@ -27,6 +27,9 @@ namespace OpenRa.Traits
Owner.World.AddFrameEndTask(w =>
{
+ if (Owner == Owner.World.LocalPlayer)
+ Sound.Play("satlnch1.aud");
+
w.Add(new SatelliteLaunch(launchSite));
w.Add(new DelayedAction((Info as GpsPowerInfo).RevealDelay * 25,
() => Owner.Shroud.HasGPS = true));
diff --git a/OpenRa.Game/Traits/SpyPlanePower.cs b/OpenRa.Game/Traits/SpyPlanePower.cs
new file mode 100644
index 0000000000..b839e419ff
--- /dev/null
+++ b/OpenRa.Game/Traits/SpyPlanePower.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace OpenRa.Traits
+{
+ class SpyPlanePowerInfo : SupportPowerInfo
+ {
+ public override object Create(Actor self) { return new SpyPlanePower(self,this); }
+ }
+
+ class SpyPlanePower : SupportPower, IResolveOrder
+ {
+ public SpyPlanePower(Actor self, SpyPlanePowerInfo info) : base(self, info) { }
+
+ protected override void OnFinishCharging() { Sound.Play("spypln1.aud"); }
+
+ public void ResolveOrder(Actor self, Order order)
+ {
+ if (order.OrderString == "SpyPlane")
+ {
+ FinishActivate();
+
+ if (order.Player == Owner.World.LocalPlayer)
+ Game.controller.CancelInputMode();
+
+ // todo: pick a cell p1 on the edge of the map; get the cell p2 at the other end of the line
+ // through that p1 & the target location;
+
+ // todo: spawn a SpyPlane at p1 with activities:
+ // -- fly to target point
+ // -- take picture
+ // -- fly to p2
+ // -- leave the world
+ }
+ }
+
+ class SelectTarget : IOrderGenerator
+ {
+ public IEnumerable Order(World world, int2 xy, MouseInput mi)
+ {
+ if (mi.Button == MouseButton.Right)
+ {
+ Game.controller.CancelInputMode();
+ yield break;
+ }
+
+ yield return new Order("SpyPlane", Game.world.LocalPlayer.PlayerActor, xy);
+ }
+
+ public void Tick(World world) {}
+ public void Render(World world) {}
+
+ public Cursor GetCursor(World world, int2 xy, MouseInput mi) { return Cursor.Ability; }
+ }
+ }
+}
diff --git a/mods/ra/merge-rules.yaml b/mods/ra/merge-rules.yaml
index 18fa29e37f..5fbba749d7 100644
--- a/mods/ra/merge-rules.yaml
+++ b/mods/ra/merge-rules.yaml
@@ -27,6 +27,13 @@ Player:
Prerequisites: IRON
TechLevel: 12
Duration: .75
+ SpyPlanePower:
+ Image: smigicon
+ ChargeTime: 3
+ Description: Spy Plane
+ LongDesc: Reveals an area of the map.
+ Prerequisites: AFLD
+ TechLevel: 5
World:
WaterPaletteRotation:
diff --git a/mods/ra/rules.yaml b/mods/ra/rules.yaml
index 9a4cf44835..fd8a5814d4 100644
--- a/mods/ra/rules.yaml
+++ b/mods/ra/rules.yaml
@@ -27,6 +27,13 @@ Player:
Prerequisites: IRON
TechLevel: 12
Duration: .75
+ SpyPlanePower:
+ Image: smigicon
+ ChargeTime: 3
+ Description: Spy Plane
+ LongDesc: Reveals an area of the map.
+ Prerequisites: AFLD
+ TechLevel: 5
World:
WaterPaletteRotation:
diff --git a/mods/ra/units.ini b/mods/ra/units.ini
index 11dc2ea24a..c65055783c 100644
--- a/mods/ra/units.ini
+++ b/mods/ra/units.ini
@@ -880,15 +880,6 @@ TechLevel=5
GivenAuto=no
Impl=NullPower
-[SpyPlanePower] ; free with first AFLD
-ChargeTime=3
-TechLevel=5
-Description=Spy Plane
-LongDesc=Reveals an area of the map.
-Prerequisite=AFLD
-Image=smigicon
-Impl=NullPower
-
[NukePower] ; the point of MSLO
ChargeTime=13
Description=Atom Bomb