Move selection hotkeys out of world interaction widget

- Split SelectionUtils for selecting actors in the world to a static class
- Split selection hotkeys into their own logic classes
This commit is contained in:
Ivaylo Draganov
2021-09-19 21:44:05 +03:00
committed by Matthias Mailänder
parent e9cc89a336
commit a537346580
6 changed files with 248 additions and 141 deletions

View File

@@ -22,9 +22,6 @@ namespace OpenRA.Mods.Common.Widgets
{
public class WorldInteractionControllerWidget : Widget
{
public readonly HotkeyReference SelectAllKey = new HotkeyReference();
public readonly HotkeyReference SelectSameTypeKey = new HotkeyReference();
protected readonly World World;
readonly WorldRenderer worldRenderer;
readonly Color normalSelectionColor;
@@ -72,12 +69,12 @@ namespace OpenRA.Mods.Common.Widgets
Game.Renderer.RgbaColorRenderer.DrawRect(a, b, 1, color);
// Render actors in the dragbox
rollover = SelectActorsInBoxWithDeadzone(World, dragStart, mousePos, modifiers);
rollover = SelectionUtils.SelectActorsInBoxWithDeadzone(World, dragStart, mousePos, modifiers);
}
else
{
// Render actors under the mouse pointer
rollover = SelectActorsInBoxWithDeadzone(World, mousePos, mousePos, modifiers);
rollover = SelectionUtils.SelectActorsInBoxWithDeadzone(World, mousePos, mousePos, modifiers);
}
worldRenderer.World.Selection.SetRollover(rollover);
@@ -127,11 +124,7 @@ namespace OpenRA.Mods.Common.Widgets
var unit = World.ScreenMap.ActorsAtMouse(mousePos)
.WithHighestSelectionPriority(mousePos, mi.Modifiers);
// Players to be included in the selection (the viewer or all players in "Disable shroud" / "All players" mode)
var viewer = World.RenderPlayer ?? World.LocalPlayer;
var isShroudDisabled = viewer == null || (World.RenderPlayer == null && World.LocalPlayer.Spectating);
var isEveryone = viewer != null && viewer.NonCombatant && viewer.Spectating;
var eligiblePlayers = isShroudDisabled || isEveryone ? World.Players : new[] { viewer };
var eligiblePlayers = SelectionUtils.GetPlayersToIncludeInSelection(World);
if (unit != null && eligiblePlayers.Contains(unit.Owner))
{
@@ -139,7 +132,7 @@ namespace OpenRA.Mods.Common.Widgets
if (s != null)
{
// Select actors on the screen that have the same selection class as the actor under the mouse cursor
var newSelection = SelectActorsOnScreen(World, worldRenderer, new HashSet<string> { s.Class }, eligiblePlayers);
var newSelection = SelectionUtils.SelectActorsOnScreen(World, worldRenderer, new HashSet<string> { s.Class }, eligiblePlayers);
World.Selection.Combine(World, newSelection, true, false);
}
@@ -158,7 +151,7 @@ namespace OpenRA.Mods.Common.Widgets
*/
if (isDragging && (uog.ClearSelectionOnLeftClick || IsValidDragbox))
{
var newSelection = SelectActorsInBoxWithDeadzone(World, dragStart, mousePos, mi.Modifiers);
var newSelection = SelectionUtils.SelectActorsInBoxWithDeadzone(World, dragStart, mousePos, mi.Modifiers);
World.Selection.Combine(World, newSelection, mi.Modifiers.HasModifier(Modifiers.Shift), dragStart == mousePos);
}
}
@@ -233,128 +226,5 @@ namespace OpenRA.Mods.Common.Widgets
return World.OrderGenerator.GetCursor(World, cell, worldPixel, mi);
});
}
public override bool HandleKeyPress(KeyInput e)
{
if (e.Event == KeyInputEvent.Down)
{
// Players to be included in the selection (the viewer or all players in "Disable shroud" / "All players" mode)
var viewer = World.RenderPlayer ?? World.LocalPlayer;
var isShroudDisabled = viewer == null || (World.RenderPlayer == null && World.LocalPlayer.Spectating);
var isEveryone = viewer != null && viewer.NonCombatant && viewer.Spectating;
var eligiblePlayers = isShroudDisabled || isEveryone ? World.Players : new[] { viewer };
if (SelectAllKey.IsActivatedBy(e) && !World.IsGameOver)
{
// Select actors on the screen which belong to the current player(s)
var ownUnitsOnScreen = SelectActorsOnScreen(World, worldRenderer, null, eligiblePlayers).SubsetWithHighestSelectionPriority(e.Modifiers).ToList();
// Check if selecting actors on the screen has selected new units
if (ownUnitsOnScreen.Count > World.Selection.Actors.Count())
TextNotificationsManager.AddFeedbackLine("Selected across screen.");
else
{
// Select actors in the world that have highest selection priority
ownUnitsOnScreen = SelectActorsInWorld(World, null, eligiblePlayers).SubsetWithHighestSelectionPriority(e.Modifiers).ToList();
TextNotificationsManager.AddFeedbackLine("Selected across map.");
}
World.Selection.Combine(World, ownUnitsOnScreen, false, false);
Game.Sound.PlayNotification(World.Map.Rules, World.LocalPlayer, "Sounds", ClickSound, null);
}
else if (SelectSameTypeKey.IsActivatedBy(e) && !World.IsGameOver)
{
if (!World.Selection.Actors.Any())
{
TextNotificationsManager.AddFeedbackLine("Nothing selected.");
Game.Sound.PlayNotification(World.Map.Rules, World.LocalPlayer, "Sounds", ClickDisabledSound, null);
return false;
}
var ownedActors = World.Selection.Actors
.Where(x => !x.IsDead && eligiblePlayers.Contains(x.Owner))
.ToList();
if (!ownedActors.Any())
return false;
// Get all the selected actors' selection classes
var selectedClasses = ownedActors
.Select(a => a.Trait<ISelectable>().Class)
.ToHashSet();
// Select actors on the screen that have the same selection class as one of the already selected actors
var newSelection = SelectActorsOnScreen(World, worldRenderer, selectedClasses, eligiblePlayers).ToList();
// Check if selecting actors on the screen has selected new units
if (newSelection.Count > World.Selection.Actors.Count())
TextNotificationsManager.AddFeedbackLine("Selected across screen.");
else
{
// Select actors in the world that have the same selection class as one of the already selected actors
newSelection = SelectActorsInWorld(World, selectedClasses, eligiblePlayers).ToList();
TextNotificationsManager.AddFeedbackLine("Selected across map.");
}
World.Selection.Combine(World, newSelection, true, false);
Game.Sound.PlayNotification(World.Map.Rules, World.LocalPlayer, "Sounds", ClickSound, null);
}
}
return false;
}
static IEnumerable<Actor> SelectActorsOnScreen(World world, WorldRenderer wr, IEnumerable<string> selectionClasses, IEnumerable<Player> players)
{
var actors = world.ScreenMap.ActorsInMouseBox(wr.Viewport.TopLeft, wr.Viewport.BottomRight).Select(a => a.Actor);
return SelectActorsByOwnerAndSelectionClass(actors, players, selectionClasses);
}
static IEnumerable<Actor> SelectActorsInWorld(World world, IEnumerable<string> selectionClasses, IEnumerable<Player> players)
{
return SelectActorsByOwnerAndSelectionClass(world.Actors.Where(a => a.IsInWorld), players, selectionClasses);
}
static IEnumerable<Actor> SelectActorsByOwnerAndSelectionClass(IEnumerable<Actor> actors, IEnumerable<Player> owners, IEnumerable<string> selectionClasses)
{
return actors.Where(a =>
{
if (!owners.Contains(a.Owner))
return false;
var s = a.TraitOrDefault<ISelectable>();
// selectionClasses == null means that units, that meet all other criteria, get selected
return s != null && (selectionClasses == null || selectionClasses.Contains(s.Class));
});
}
static IEnumerable<Actor> SelectHighestPriorityActorAtPoint(World world, int2 a, Modifiers modifiers)
{
var selected = world.ScreenMap.ActorsAtMouse(a)
.Where(x => x.Actor.Info.HasTraitInfo<ISelectableInfo>() && (x.Actor.Owner.IsAlliedWith(world.RenderPlayer) || !world.FogObscures(x.Actor)))
.WithHighestSelectionPriority(a, modifiers);
if (selected != null)
yield return selected;
}
static IEnumerable<Actor> SelectActorsInBoxWithDeadzone(World world, int2 a, int2 b, Modifiers modifiers)
{
// For dragboxes that are too small, shrink the dragbox to a single point (point b)
if ((a - b).Length <= Game.Settings.Game.SelectionDeadzone)
a = b;
if (a == b)
return SelectHighestPriorityActorAtPoint(world, a, modifiers);
return world.ScreenMap.ActorsInMouseBox(a, b)
.Select(x => x.Actor)
.Where(x => x.Info.HasTraitInfo<ISelectableInfo>() && (x.Owner.IsAlliedWith(world.RenderPlayer) || !world.FogObscures(x)))
.SubsetWithHighestSelectionPriority(modifiers);
}
}
}