diff --git a/OpenRA.Mods.Common/Traits/SupportPowers/SupportPowerManager.cs b/OpenRA.Mods.Common/Traits/SupportPowers/SupportPowerManager.cs
index 1926c2d204..e6ea859e95 100644
--- a/OpenRA.Mods.Common/Traits/SupportPowers/SupportPowerManager.cs
+++ b/OpenRA.Mods.Common/Traits/SupportPowers/SupportPowerManager.cs
@@ -235,7 +235,8 @@ namespace OpenRA.Mods.Common.Traits
if (!Ready)
return;
- var power = Instances.FirstOrDefault(i => !InstanceDisabled(i));
+ var power = Instances.Where(i => !InstanceDisabled(i))
+ .MinByOrDefault(a => (a.Self.CenterPosition - a.Self.World.Map.CenterOfCell(order.TargetLocation)).HorizontalLengthSquared);
if (power == null)
return;
diff --git a/OpenRA.Mods.TS/OpenRA.Mods.TS.csproj b/OpenRA.Mods.TS/OpenRA.Mods.TS.csproj
index 14bab04b9a..1dfe59b25f 100644
--- a/OpenRA.Mods.TS/OpenRA.Mods.TS.csproj
+++ b/OpenRA.Mods.TS/OpenRA.Mods.TS.csproj
@@ -74,6 +74,7 @@
+
diff --git a/OpenRA.Mods.TS/Traits/SupportPowers/AttackOrderPower.cs b/OpenRA.Mods.TS/Traits/SupportPowers/AttackOrderPower.cs
new file mode 100644
index 0000000000..1f8e2e0c0f
--- /dev/null
+++ b/OpenRA.Mods.TS/Traits/SupportPowers/AttackOrderPower.cs
@@ -0,0 +1,148 @@
+#region Copyright & License Information
+/*
+ * Copyright 2007-2016 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 System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using OpenRA.Graphics;
+using OpenRA.Mods.Common.Graphics;
+using OpenRA.Mods.Common.Traits;
+using OpenRA.Traits;
+
+namespace OpenRA.Mods.TS.Traits
+{
+ class AttackOrderPowerInfo : SupportPowerInfo
+ {
+ public override object Create(ActorInitializer init) { return new AttackOrderPower(init.Self, this); }
+ }
+
+ class AttackOrderPower : SupportPower, INotifyAddedToWorld, INotifyAttack
+ {
+ readonly AttackOrderPowerInfo info;
+ AttackBase attack;
+
+ public AttackOrderPower(Actor self, AttackOrderPowerInfo info)
+ : base(self, info)
+ {
+ this.info = info;
+ }
+
+ public override void SelectTarget(Actor self, string order, SupportPowerManager manager)
+ {
+ Game.Sound.PlayToPlayer(manager.Self.Owner, Info.SelectTargetSound);
+ self.World.OrderGenerator = new SelectAttackPowerTarget(self, order, manager, info.Cursor, MouseButton.Left, attack);
+ }
+
+ public override void Activate(Actor self, Order order, SupportPowerManager manager)
+ {
+ base.Activate(self, order, manager);
+ attack.AttackTarget(Target.FromCell(self.World, order.TargetLocation), false, false, true);
+ }
+
+ void INotifyAddedToWorld.AddedToWorld(Actor self)
+ {
+ attack = self.Trait();
+ }
+
+ void INotifyAttack.Attacking(Actor self, Target target, Armament a, Barrel barrel)
+ {
+ self.World.IssueOrder(new Order("Stop", self, false));
+ }
+ }
+
+ public class SelectAttackPowerTarget : IOrderGenerator
+ {
+ readonly SupportPowerManager manager;
+ readonly SupportPowerInstance instance;
+ readonly string order;
+ readonly string cursor;
+ readonly string cursorBlocked;
+ readonly MouseButton expectedButton;
+ readonly AttackBase attack;
+
+ public SelectAttackPowerTarget(Actor self, string order, SupportPowerManager manager, string cursor, MouseButton button, AttackBase attack)
+ {
+ // Clear selection if using Left-Click Orders
+ if (Game.Settings.Game.UseClassicMouseStyle)
+ manager.Self.World.Selection.Clear();
+
+ instance = manager.GetPowersForActor(self).FirstOrDefault();
+ this.manager = manager;
+ this.order = order;
+ this.cursor = cursor;
+ expectedButton = button;
+ this.attack = attack;
+ cursorBlocked = cursor + "-blocked";
+ }
+
+ Actor GetFiringActor(World world, CPos cell)
+ {
+ var pos = world.Map.CenterOfCell(cell);
+ var range = attack.GetMaximumRange().LengthSquared;
+
+ return instance.Instances.Where(i => !i.Self.IsDisabled()).MinByOrDefault(a => (a.Self.CenterPosition - pos).HorizontalLengthSquared).Self;
+ }
+
+ bool IsValidTarget(World world, CPos cell)
+ {
+ var pos = world.Map.CenterOfCell(cell);
+ var range = attack.GetMaximumRange().LengthSquared;
+
+ return world.Map.Contains(cell) && instance.Instances.Any(a => !a.Self.IsDisabled() && (a.Self.CenterPosition - pos).HorizontalLengthSquared < range);
+ }
+
+ IEnumerable IOrderGenerator.Order(World world, CPos cell, int2 worldPixel, MouseInput mi)
+ {
+ world.CancelInputMode();
+ if (mi.Button == expectedButton && IsValidTarget(world, cell))
+ yield return new Order(order, manager.Self, false)
+ {
+ TargetActor = GetFiringActor(world, cell),
+ TargetLocation = cell,
+ SuppressVisualFeedback = true
+ };
+ }
+
+ void IOrderGenerator.Tick(World world)
+ {
+ // Cancel the OG if we can't use the power
+ if (!manager.Powers.ContainsKey(order))
+ world.CancelInputMode();
+ }
+
+ IEnumerable IOrderGenerator.Render(WorldRenderer wr, World world) { yield break; }
+
+ IEnumerable IOrderGenerator.RenderAfterWorld(WorldRenderer wr, World world)
+ {
+ foreach (var a in instance.Instances.Where(i => !i.Self.IsDisabled()))
+ {
+ yield return new RangeCircleRenderable(
+ a.Self.CenterPosition,
+ attack.GetMinimumRange(),
+ 0,
+ Color.Red,
+ Color.FromArgb(96, Color.Black));
+
+ yield return new RangeCircleRenderable(
+ a.Self.CenterPosition,
+ attack.GetMaximumRange(),
+ 0,
+ Color.Red,
+ Color.FromArgb(96, Color.Black));
+ }
+ }
+
+ string IOrderGenerator.GetCursor(World world, CPos cell, int2 worldPixel, MouseInput mi)
+ {
+ return IsValidTarget(world, cell) ? cursor : cursorBlocked;
+ }
+ }
+}