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; + } + } +}