diff --git a/OpenRA.Game/Orders/UnitOrderGenerator.cs b/OpenRA.Game/Orders/UnitOrderGenerator.cs index b0cf0c94de..f5e43a8a68 100644 --- a/OpenRA.Game/Orders/UnitOrderGenerator.cs +++ b/OpenRA.Game/Orders/UnitOrderGenerator.cs @@ -70,7 +70,7 @@ namespace OpenRA.Orders bool useSelect; if (Game.Settings.Game.UseClassicMouseStyle && !InputOverridesSelection(world, worldPixel, mi)) - useSelect = target.Type == TargetType.Actor && target.Actor.Info.HasTraitInfo(); + useSelect = target.Type == TargetType.Actor && target.Actor.Info.HasTraitInfo(); else { var ordersWithCursor = world.Selection.Actors @@ -81,7 +81,7 @@ namespace OpenRA.Orders if (cursorOrder != null) return cursorOrder.Cursor; - useSelect = target.Type == TargetType.Actor && target.Actor.Info.HasTraitInfo() && + useSelect = target.Type == TargetType.Actor && target.Actor.Info.HasTraitInfo() && (mi.Modifiers.HasModifier(Modifiers.Shift) || !world.Selection.Actors.Any()); } diff --git a/OpenRA.Game/SelectableExts.cs b/OpenRA.Game/SelectableExts.cs index 812b88982b..d47321acb2 100644 --- a/OpenRA.Game/SelectableExts.cs +++ b/OpenRA.Game/SelectableExts.cs @@ -20,7 +20,7 @@ namespace OpenRA.Traits { public static int SelectionPriority(this ActorInfo a, Modifiers modifiers) { - var selectableInfo = a.TraitInfoOrDefault(); + var selectableInfo = a.TraitInfoOrDefault(); return selectableInfo != null ? BaseSelectionPriority(selectableInfo, modifiers) : int.MinValue; } @@ -28,7 +28,7 @@ namespace OpenRA.Traits public static int SelectionPriority(this Actor a, Modifiers modifiers) { - var info = a.Info.TraitInfo(); + var info = a.Info.TraitInfo(); var basePriority = BaseSelectionPriority(info, modifiers); var viewer = (a.World.LocalPlayer == null || a.World.LocalPlayer.Spectating) ? a.World.RenderPlayer : a.World.LocalPlayer; @@ -47,7 +47,7 @@ namespace OpenRA.Traits } } - static int BaseSelectionPriority(SelectableInfo info, Modifiers modifiers) + static int BaseSelectionPriority(ISelectableInfo info, Modifiers modifiers) { var priority = info.Priority; diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index b5a099378d..356072b9a6 100644 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -440,6 +440,22 @@ namespace OpenRA.Traits bool SpatiallyPartitionable { get; } } + [Flags] + public enum SelectionPriorityModifiers + { + None = 0, + Ctrl = 1, + Alt = 2 + } + + [RequireExplicitImplementation] + public interface ISelectableInfo : ITraitInfoInterface + { + int Priority { get; } + SelectionPriorityModifiers PriorityModifiers { get; } + string Voice { get; } + } + public interface ISelection { int Hash { get; } diff --git a/OpenRA.Mods.Common/Lint/CheckConflictingMouseBounds.cs b/OpenRA.Mods.Common/Lint/CheckConflictingMouseBounds.cs index 17aaf64e9a..ee694742fd 100644 --- a/OpenRA.Mods.Common/Lint/CheckConflictingMouseBounds.cs +++ b/OpenRA.Mods.Common/Lint/CheckConflictingMouseBounds.cs @@ -11,6 +11,7 @@ using System; using System.Linq; +using OpenRA.Mods.Common.Traits; using OpenRA.Traits; namespace OpenRA.Mods.Common.Lint diff --git a/OpenRA.Game/Traits/Interactable.cs b/OpenRA.Mods.Common/Traits/Interactable.cs similarity index 97% rename from OpenRA.Game/Traits/Interactable.cs rename to OpenRA.Mods.Common/Traits/Interactable.cs index 11471f2af0..017daa17fd 100644 --- a/OpenRA.Game/Traits/Interactable.cs +++ b/OpenRA.Mods.Common/Traits/Interactable.cs @@ -12,8 +12,9 @@ using System.Linq; using OpenRA.Graphics; using OpenRA.Primitives; +using OpenRA.Traits; -namespace OpenRA.Traits +namespace OpenRA.Mods.Common.Traits { [Desc("Used to enable mouse interaction on actors that are not Selectable.")] public class InteractableInfo : ITraitInfo, IMouseBoundsInfo, IDecorationBoundsInfo diff --git a/OpenRA.Game/Traits/Selectable.cs b/OpenRA.Mods.Common/Traits/Selectable.cs similarity index 72% rename from OpenRA.Game/Traits/Selectable.cs rename to OpenRA.Mods.Common/Traits/Selectable.cs index bbb74cb424..d85e2328ef 100644 --- a/OpenRA.Game/Traits/Selectable.cs +++ b/OpenRA.Mods.Common/Traits/Selectable.cs @@ -10,19 +10,12 @@ #endregion using System; +using OpenRA.Traits; -namespace OpenRA.Traits +namespace OpenRA.Mods.Common.Traits { - [Flags] - public enum SelectionPriorityModifiers - { - None = 0, - Ctrl = 1, - Alt = 2 - } - [Desc("This actor is selectable. Defines bounds of selectable area, selection class, selection priority and selection priority modifiers.")] - public class SelectableInfo : InteractableInfo + public class SelectableInfo : InteractableInfo, ISelectableInfo { public readonly int Priority = 10; @@ -40,18 +33,24 @@ namespace OpenRA.Traits public readonly string Voice = "Select"; public override object Create(ActorInitializer init) { return new Selectable(init.Self, this); } + + int ISelectableInfo.Priority { get { return Priority; } } + SelectionPriorityModifiers ISelectableInfo.PriorityModifiers { get { return PriorityModifiers; } } + string ISelectableInfo.Voice { get { return Voice; } } } - public class Selectable : Interactable + public class Selectable : Interactable, ISelectable { - public readonly string Class = null; + readonly string selectionClass = null; public readonly SelectableInfo Info; public Selectable(Actor self, SelectableInfo info) : base(info) { - Class = string.IsNullOrEmpty(info.Class) ? self.Info.Name : info.Class; + selectionClass = string.IsNullOrEmpty(info.Class) ? self.Info.Name : info.Class; Info = info; } + + string ISelectable.Class { get { return selectionClass; } } } } diff --git a/OpenRA.Mods.Common/Traits/World/Selection.cs b/OpenRA.Mods.Common/Traits/World/Selection.cs index 2ba5dc9c36..16f27f790a 100644 --- a/OpenRA.Mods.Common/Traits/World/Selection.cs +++ b/OpenRA.Mods.Common/Traits/World/Selection.cs @@ -123,13 +123,12 @@ namespace OpenRA.Mods.Common.Traits // Play the selection voice from one of the selected actors // TODO: This probably should only be considering the newly selected actors - // TODO: Ship this into an INotifySelection trait to remove the engine dependency on Selectable foreach (var actor in actors) { if (actor.Owner != world.LocalPlayer || !actor.IsInWorld) continue; - var selectable = actor.Info.TraitInfoOrDefault(); + var selectable = actor.Info.TraitInfoOrDefault(); if (selectable == null || !actor.HasVoice(selectable.Voice)) continue; diff --git a/OpenRA.Mods.Common/TraitsInterfaces.cs b/OpenRA.Mods.Common/TraitsInterfaces.cs index 0c31450898..0a2e0cc47a 100644 --- a/OpenRA.Mods.Common/TraitsInterfaces.cs +++ b/OpenRA.Mods.Common/TraitsInterfaces.cs @@ -636,4 +636,10 @@ namespace OpenRA.Mods.Common.Traits { void NotifyTimerExpired(Actor self); } + + [RequireExplicitImplementation] + public interface ISelectable + { + string Class { get; } + } } diff --git a/OpenRA.Mods.Common/Widgets/WorldInteractionControllerWidget.cs b/OpenRA.Mods.Common/Widgets/WorldInteractionControllerWidget.cs index c8892b45fe..ec636efa49 100644 --- a/OpenRA.Mods.Common/Widgets/WorldInteractionControllerWidget.cs +++ b/OpenRA.Mods.Common/Widgets/WorldInteractionControllerWidget.cs @@ -13,6 +13,7 @@ using System.Collections.Generic; using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Common.Effects; +using OpenRA.Mods.Common.Traits; using OpenRA.Orders; using OpenRA.Primitives; using OpenRA.Traits; @@ -127,7 +128,7 @@ namespace OpenRA.Mods.Common.Widgets if (!IsValidDragbox && World.Selection.Actors.Any() && !multiClick) { var selectableActor = World.ScreenMap.ActorsAtMouse(mousePos).Select(a => a.Actor).Any(x => - x.Info.HasTraitInfo() && (x.Owner.IsAlliedWith(World.RenderPlayer) || !World.FogObscures(x))); + x.Info.HasTraitInfo() && (x.Owner.IsAlliedWith(World.RenderPlayer) || !World.FogObscures(x))); if (!selectableActor || uog.InputOverridesSelection(World, mousePos, mi)) { @@ -153,7 +154,7 @@ namespace OpenRA.Mods.Common.Widgets if (unit != null && eligiblePlayers.Contains(unit.Owner)) { - var s = unit.TraitOrDefault(); + var s = unit.TraitOrDefault(); if (s != null) { // Select actors on the screen that have the same selection class as the actor under the mouse cursor @@ -305,7 +306,7 @@ namespace OpenRA.Mods.Common.Widgets // Get all the selected actors' selection classes var selectedClasses = ownedActors - .Select(a => a.Trait().Class) + .Select(a => a.Trait().Class) .ToHashSet(); // Select actors on the screen that have the same selection class as one of the already selected actors @@ -346,7 +347,7 @@ namespace OpenRA.Mods.Common.Widgets if (!owners.Contains(a.Owner)) return false; - var s = a.TraitOrDefault(); + var s = a.TraitOrDefault(); // selectionClasses == null means that units, that meet all other criteria, get selected return s != null && (selectionClasses == null || selectionClasses.Contains(s.Class)); @@ -356,7 +357,7 @@ namespace OpenRA.Mods.Common.Widgets static IEnumerable SelectHighestPriorityActorAtPoint(World world, int2 a, Modifiers modifiers) { var selected = world.ScreenMap.ActorsAtMouse(a) - .Where(x => x.Actor.Info.HasTraitInfo() && (x.Actor.Owner.IsAlliedWith(world.RenderPlayer) || !world.FogObscures(x.Actor))) + .Where(x => x.Actor.Info.HasTraitInfo() && (x.Actor.Owner.IsAlliedWith(world.RenderPlayer) || !world.FogObscures(x.Actor))) .WithHighestSelectionPriority(a, modifiers); if (selected != null) @@ -374,7 +375,7 @@ namespace OpenRA.Mods.Common.Widgets return world.ScreenMap.ActorsInMouseBox(a, b) .Select(x => x.Actor) - .Where(x => x.Info.HasTraitInfo() && (x.Owner.IsAlliedWith(world.RenderPlayer) || !world.FogObscures(x))) + .Where(x => x.Info.HasTraitInfo() && (x.Owner.IsAlliedWith(world.RenderPlayer) || !world.FogObscures(x))) .SubsetWithHighestSelectionPriority(modifiers); } }