diff --git a/OpenRA.Game/Orders/GenericSelectTarget.cs b/OpenRA.Game/Orders/GenericSelectTarget.cs index 3f987be462..71909a62af 100644 --- a/OpenRA.Game/Orders/GenericSelectTarget.cs +++ b/OpenRA.Game/Orders/GenericSelectTarget.cs @@ -13,19 +13,19 @@ using OpenRA.Graphics; namespace OpenRA.Orders { - public class GenericSelectTarget : IOrderGenerator + public class GenericSelectTarget : UnitOrderGenerator { - readonly IEnumerable subjects; - readonly string order; - readonly string cursor; - readonly MouseButton expectedButton; + protected readonly IEnumerable Subjects; + protected readonly string OrderName; + protected readonly string Cursor; + protected readonly MouseButton ExpectedButton; public GenericSelectTarget(IEnumerable subjects, string order, string cursor, MouseButton button) { - this.subjects = subjects; - this.order = order; - this.cursor = cursor; - expectedButton = button; + Subjects = subjects; + OrderName = order; + Cursor = cursor; + ExpectedButton = button; } public GenericSelectTarget(IEnumerable subjects, string order, string cursor) @@ -37,26 +37,23 @@ namespace OpenRA.Orders public GenericSelectTarget(Actor subject, string order, string cursor, MouseButton button) : this(new Actor[] { subject }, order, cursor, button) { } - public IEnumerable Order(World world, CPos xy, MouseInput mi) + public override IEnumerable Order(World world, CPos xy, MouseInput mi) { - if (mi.Button != expectedButton) + if (mi.Button != ExpectedButton) world.CancelInputMode(); return OrderInner(world, xy, mi); } - IEnumerable OrderInner(World world, CPos xy, MouseInput mi) + protected virtual IEnumerable OrderInner(World world, CPos xy, MouseInput mi) { - if (mi.Button == expectedButton && world.Map.Contains(xy)) + if (mi.Button == ExpectedButton && world.Map.Contains(xy)) { world.CancelInputMode(); - foreach (var subject in subjects) - yield return new Order(order, subject, false) { TargetLocation = xy }; + foreach (var subject in Subjects) + yield return new Order(OrderName, subject, false) { TargetLocation = xy }; } } - public virtual void Tick(World world) { } - public IEnumerable Render(WorldRenderer wr, World world) { yield break; } - public IEnumerable RenderAfterWorld(WorldRenderer wr, World world) { yield break; } - public string GetCursor(World world, CPos xy, MouseInput mi) { return world.Map.Contains(xy) ? cursor : "generic-blocked"; } + public override string GetCursor(World world, CPos xy, MouseInput mi) { return world.Map.Contains(xy) ? Cursor : "generic-blocked"; } } } diff --git a/OpenRA.Game/Orders/UnitOrderGenerator.cs b/OpenRA.Game/Orders/UnitOrderGenerator.cs index 9031bb9262..4f6b3057e8 100644 --- a/OpenRA.Game/Orders/UnitOrderGenerator.cs +++ b/OpenRA.Game/Orders/UnitOrderGenerator.cs @@ -15,7 +15,7 @@ using OpenRA.Traits; namespace OpenRA.Orders { - class UnitOrderGenerator : IOrderGenerator + public class UnitOrderGenerator : IOrderGenerator { static Target TargetForInput(World world, CPos xy, MouseInput mi) { @@ -36,7 +36,7 @@ namespace OpenRA.Orders return Target.FromCell(world, xy); } - public IEnumerable Order(World world, CPos xy, MouseInput mi) + public virtual IEnumerable Order(World world, CPos xy, MouseInput mi) { var target = TargetForInput(world, xy, mi); var actorsAt = world.ActorMap.GetActorsAt(xy).ToList(); @@ -58,11 +58,11 @@ namespace OpenRA.Orders yield return CheckSameOrder(o.Order, o.Trait.IssueOrder(o.Actor, o.Order, o.Target, mi.Modifiers.HasModifier(Modifiers.Shift))); } - public void Tick(World world) { } - public IEnumerable Render(WorldRenderer wr, World world) { yield break; } - public IEnumerable RenderAfterWorld(WorldRenderer wr, World world) { yield break; } + public virtual void Tick(World world) { } + public virtual IEnumerable Render(WorldRenderer wr, World world) { yield break; } + public virtual IEnumerable RenderAfterWorld(WorldRenderer wr, World world) { yield break; } - public string GetCursor(World world, CPos xy, MouseInput mi) + public virtual string GetCursor(World world, CPos xy, MouseInput mi) { var useSelect = false; var target = TargetForInput(world, xy, mi); diff --git a/OpenRA.Game/Widgets/WorldInteractionControllerWidget.cs b/OpenRA.Game/Widgets/WorldInteractionControllerWidget.cs index c581301a32..1928ff1557 100644 --- a/OpenRA.Game/Widgets/WorldInteractionControllerWidget.cs +++ b/OpenRA.Game/Widgets/WorldInteractionControllerWidget.cs @@ -120,12 +120,25 @@ namespace OpenRA.Widgets } } } - else if (dragStart.HasValue) + else { - // Select actors in the dragbox - var newSelection = SelectActorsInBoxWithDeadzone(World, dragStart.Value, xy); - World.Selection.Combine(World, newSelection, mi.Modifiers.HasModifier(Modifiers.Shift), dragStart == xy); + /* The block below does three things: + // 1. Allows actor selection using a selection box regardless of input mode. + // 2. Allows actor deselection with a single click in the default input mode (UnitOrderGenerator). + // 3. Prevents units from getting deselected when exiting input modes (eg. AttackMove or Guard). + // + // We cannot check for UnitOrderGenerator here since it's the default order generator that gets activated in + // World.CancelInputMode. If we did check it, actor de-selection would not be possible by just clicking somewhere, + // only by dragging an empty selection box. + */ + if (dragStart.HasValue && (!(World.OrderGenerator is GenericSelectTarget) || hasBox)) + { + var newSelection = SelectActorsInBoxWithDeadzone(World, dragStart.Value, xy); + World.Selection.Combine(World, newSelection, mi.Modifiers.HasModifier(Modifiers.Shift), dragStart == xy); + } } + + World.CancelInputMode(); } dragStart = dragEnd = null; diff --git a/OpenRA.Mods.Common/Traits/Guard.cs b/OpenRA.Mods.Common/Traits/Guard.cs index 9b3f02a3a7..7ca77f34a1 100644 --- a/OpenRA.Mods.Common/Traits/Guard.cs +++ b/OpenRA.Mods.Common/Traits/Guard.cs @@ -14,6 +14,7 @@ using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Common; using OpenRA.Mods.Common.Activities; +using OpenRA.Orders; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits @@ -59,52 +60,40 @@ namespace OpenRA.Mods.Common.Traits } } - public class GuardOrderGenerator : IOrderGenerator + public class GuardOrderGenerator : GenericSelectTarget { - readonly IEnumerable subjects; + public GuardOrderGenerator(IEnumerable subjects, string order, string cursor, MouseButton button) + : base(subjects, order, cursor, button) { } - public GuardOrderGenerator(IEnumerable subjects) + protected override IEnumerable OrderInner(World world, CPos xy, MouseInput mi) { - this.subjects = subjects; - } - - public IEnumerable Order(World world, CPos xy, MouseInput mi) - { - if (mi.Button == Game.Settings.Game.MouseButtonPreference.Cancel) - { - world.CancelInputMode(); - yield break; - } - var target = FriendlyGuardableUnits(world, mi).FirstOrDefault(); - if (target == null || subjects.All(s => s.IsDead)) + if (target == null || Subjects.All(s => s.IsDead)) yield break; - foreach (var subject in subjects) + world.CancelInputMode(); + foreach (var subject in Subjects) if (subject != target) - yield return new Order("Guard", subject, false) { TargetActor = target }; + yield return new Order(OrderName, subject, false) { TargetActor = target }; } - public void Tick(World world) + public override void Tick(World world) { - if (subjects.All(s => s.IsDead || !s.Info.HasTraitInfo())) + if (Subjects.All(s => s.IsDead || !s.Info.HasTraitInfo())) world.CancelInputMode(); } - public IEnumerable Render(WorldRenderer wr, World world) { yield break; } - public IEnumerable RenderAfterWorld(WorldRenderer wr, World world) { yield break; } - - public string GetCursor(World world, CPos xy, MouseInput mi) + public override string GetCursor(World world, CPos xy, MouseInput mi) { - if (!subjects.Any()) + if (!Subjects.Any()) return null; - var multiple = subjects.Count() > 1; + var multiple = Subjects.Count() > 1; var canGuard = FriendlyGuardableUnits(world, mi) - .Any(a => multiple || a != subjects.First()); + .Any(a => multiple || a != Subjects.First()); - return canGuard ? "guard" : "move-blocked"; + return canGuard ? Cursor : "move-blocked"; } static IEnumerable FriendlyGuardableUnits(World world, MouseInput mi) diff --git a/OpenRA.Mods.Common/Widgets/WorldCommandWidget.cs b/OpenRA.Mods.Common/Widgets/WorldCommandWidget.cs index 10c96d78f9..402221167d 100644 --- a/OpenRA.Mods.Common/Widgets/WorldCommandWidget.cs +++ b/OpenRA.Mods.Common/Widgets/WorldCommandWidget.cs @@ -184,7 +184,8 @@ namespace OpenRA.Mods.Common.Widgets .Where(a => !a.Disposed && a.Owner == world.LocalPlayer && a.Info.HasTraitInfo()); if (actors.Any()) - world.OrderGenerator = new GuardOrderGenerator(actors); + world.OrderGenerator = new GuardOrderGenerator(actors, + "Guard", "guard", Game.Settings.Game.MouseButtonPreference.Action); return true; }