diff --git a/CHANGELOG b/CHANGELOG index 1dac99eeb8..f2aa6111df 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -15,6 +15,8 @@ NEW: Added a setting to always display unit status bars (can also be toggled by hotkey). Added a setting for team health bar colors. Added a new hotkey to select all units on screen (default: CTRL + A). + Added a new hotkey to jump to production buildings (default: TAB). + Changed default hotkey (PageUp/Down) for build palette cycling and made reverse user configurable. Asset Browser: Fixed crashes when trying to load invalid filenames or sprites with just 1 frame. Added support for all sprite types. diff --git a/OpenRA.Game/GameRules/Settings.cs b/OpenRA.Game/GameRules/Settings.cs index bb3d8adbc6..682dbbb76b 100644 --- a/OpenRA.Game/GameRules/Settings.cs +++ b/OpenRA.Game/GameRules/Settings.cs @@ -155,7 +155,9 @@ namespace OpenRA.GameRules public Hotkey PowerDownKey = new Hotkey(Keycode.F11, Modifiers.None); public Hotkey RepairKey = new Hotkey(Keycode.F12, Modifiers.None); - public Hotkey CycleTabsKey = new Hotkey(Keycode.TAB, Modifiers.None); + public Hotkey NextProductionTabKey = new Hotkey(Keycode.PAGEDOWN, Modifiers.None); + public Hotkey PreviousProductionTabKey = new Hotkey(Keycode.PAGEUP, Modifiers.None); + public Hotkey CycleProductionBuildingsKey = new Hotkey(Keycode.TAB, Modifiers.None); public Hotkey ToggleStatusBarsKey = new Hotkey(Keycode.INSERT, Modifiers.None); diff --git a/OpenRA.Mods.Cnc/Widgets/ProductionTabsWidget.cs b/OpenRA.Mods.Cnc/Widgets/ProductionTabsWidget.cs old mode 100755 new mode 100644 index cf05ad0bf6..d5ea98871d --- a/OpenRA.Mods.Cnc/Widgets/ProductionTabsWidget.cs +++ b/OpenRA.Mods.Cnc/Widgets/ProductionTabsWidget.cs @@ -89,10 +89,12 @@ namespace OpenRA.Mods.Cnc.Widgets paletteWidget = Lazy.New(() => Ui.Root.Get(PaletteWidget)); } - public void SelectNextTab(bool reverse) + public bool SelectNextTab(bool reverse) { if (queueGroup == null) - return; + return true; + + Sound.PlayNotification(null, "Sounds", "ClickSound", null); // Prioritize alerted queues var queues = Groups[queueGroup].Tabs.Select(t => t.Queue) @@ -103,6 +105,8 @@ namespace OpenRA.Mods.Cnc.Widgets CurrentQueue = queues.SkipWhile(q => q != CurrentQueue) .Skip(1).FirstOrDefault() ?? queues.FirstOrDefault(); + + return true; } public string QueueGroup @@ -277,12 +281,12 @@ namespace OpenRA.Mods.Cnc.Widgets if (e.Event != KeyInputEvent.Down) return false; - if (Hotkey.FromKeyInput(e) == Game.Settings.Keys.CycleTabsKey) - { - Sound.PlayNotification(null, "Sounds", "ClickSound", null); - SelectNextTab(e.Modifiers.HasModifier(Modifiers.Shift)); - return true; - } + var hotkey = Hotkey.FromKeyInput(e); + + if (hotkey == Game.Settings.Keys.NextProductionTabKey) + return SelectNextTab(false); + else if (hotkey == Game.Settings.Keys.PreviousProductionTabKey) + return SelectNextTab(true); return false; } diff --git a/OpenRA.Mods.RA/PrimaryBuilding.cs b/OpenRA.Mods.RA/PrimaryBuilding.cs index 301a5f4ded..46f151087a 100755 --- a/OpenRA.Mods.RA/PrimaryBuilding.cs +++ b/OpenRA.Mods.RA/PrimaryBuilding.cs @@ -10,12 +10,21 @@ using System.Collections.Generic; using System.Linq; -using OpenRA.Mods.RA.Orders; using OpenRA.FileFormats; +using OpenRA.Mods.RA.Orders; using OpenRA.Traits; namespace OpenRA.Mods.RA { + static class PrimaryExts + { + public static bool IsPrimaryBuilding(this Actor a) + { + var pb = a.TraitOrDefault(); + return pb != null && pb.IsPrimary; + } + } + [Desc("Used together with ClassicProductionQueue.")] class PrimaryBuildingInfo : TraitInfo { } @@ -26,18 +35,18 @@ namespace OpenRA.Mods.RA public IEnumerable GetTags() { - yield return (isPrimary) ? TagType.Primary : TagType.None; + yield return isPrimary ? TagType.Primary : TagType.None; } public IEnumerable Orders { - get { yield return new DeployOrderTargeter( "PrimaryProducer", 1 ); } + get { yield return new DeployOrderTargeter("PrimaryProducer", 1); } } - public Order IssueOrder( Actor self, IOrderTargeter order, Target target, bool queued ) + public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued) { - if( order.OrderID == "PrimaryProducer" ) - return new Order( order.OrderID, self, false ); + if (order.OrderID == "PrimaryProducer") + return new Order(order.OrderID, self, false); return null; } @@ -63,7 +72,7 @@ namespace OpenRA.Mods.RA .ActorsWithTrait() .Where(a => a.Actor.Owner == self.Owner) .Where(x => x.Trait.IsPrimary - && (x.Actor.Info.Traits.Get().Produces.Contains(p)))) + && x.Actor.Info.Traits.Get().Produces.Contains(p))) b.Trait.SetPrimaryProducer(b.Actor, false); isPrimary = true; @@ -71,13 +80,4 @@ namespace OpenRA.Mods.RA Sound.PlayNotification(self.Owner, "Speech", "PrimaryBuildingSelected", self.Owner.Country.Race); } } - - static class PrimaryExts - { - public static bool IsPrimaryBuilding(this Actor a) - { - var pb = a.TraitOrDefault(); - return pb != null && pb.IsPrimary; - } - } } diff --git a/OpenRA.Mods.RA/Widgets/BuildPaletteWidget.cs b/OpenRA.Mods.RA/Widgets/BuildPaletteWidget.cs index e6fd815b5c..998c5c9226 100755 --- a/OpenRA.Mods.RA/Widgets/BuildPaletteWidget.cs +++ b/OpenRA.Mods.RA/Widgets/BuildPaletteWidget.cs @@ -149,11 +149,13 @@ namespace OpenRA.Mods.RA.Widgets if (e.Event == KeyInputEvent.Up) return false; - if (Hotkey.FromKeyInput(e) == Game.Settings.Keys.CycleTabsKey) - { - TabChange(e.Modifiers.HasModifier(Modifiers.Shift)); - return true; - } + var hotkey = Hotkey.FromKeyInput(e); + + if (hotkey == Game.Settings.Keys.NextProductionTabKey) + return ChangeTab(false); + else if (hotkey == Game.Settings.Keys.PreviousProductionTabKey) + return ChangeTab(true); + return DoBuildingHotkey(e, world); } @@ -164,15 +166,10 @@ namespace OpenRA.Mods.RA.Widgets return true; if (mi.Button == MouseButton.WheelDown) - { - TabChange(false); - return true; - } + return ChangeTab(false); + if (mi.Button == MouseButton.WheelUp) - { - TabChange(true); - return true; - } + return ChangeTab(true); var action = tabs.Where(a => a.First.Contains(mi.Location)) .Select(a => a.Second).FirstOrDefault(); @@ -515,14 +512,21 @@ namespace OpenRA.Mods.RA.Widgets return false; } - void TabChange(bool shift) + // NOTE: Always return true here to prevent mouse events from passing through the sidebar and interacting with the world behind it. + bool ChangeTab(bool reverse) { + Sound.PlayNotification(null, "Sounds", "TabClick", null); var queues = VisibleQueues.Concat(VisibleQueues); - if (shift) queues = queues.Reverse(); + if (reverse) + queues = queues.Reverse(); var nextQueue = queues.SkipWhile(q => q != CurrentQueue) .ElementAtOrDefault(1); if (nextQueue != null) + { SetCurrentTab(nextQueue); + return true; + } + return true; } } } \ No newline at end of file diff --git a/OpenRA.Mods.RA/Widgets/Logic/SettingsLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/SettingsLogic.cs index 9e93fe7229..66484c1624 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/SettingsLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/SettingsLogic.cs @@ -257,9 +257,11 @@ namespace OpenRA.Mods.RA.Widgets.Logic { "PowerDownKey", "Power-down mode" }, { "RepairKey", "Repair mode" }, - { "CycleTabsKey", "Cycle production tabs" }, + { "NextProductionTabKey", "Next production tab" }, + { "PreviousProductionTabKey", "Previous production tab" }, + { "CycleProductionBuildingsKey", "Cycle production facilities" }, - { "ToggleStatusBarsKey", "Toggle status bars" } + { "ToggleStatusBarsKey", "Toggle status bars" }, }; var unitHotkeys = new Dictionary() diff --git a/OpenRA.Mods.RA/Widgets/WorldCommandWidget.cs b/OpenRA.Mods.RA/Widgets/WorldCommandWidget.cs index f4dedf5356..c86534ea1c 100644 --- a/OpenRA.Mods.RA/Widgets/WorldCommandWidget.cs +++ b/OpenRA.Mods.RA/Widgets/WorldCommandWidget.cs @@ -47,9 +47,13 @@ namespace OpenRA.Mods.RA.Widgets { var key = Hotkey.FromKeyInput(e); var ks = Game.Settings.Keys; + if (key == ks.CycleBaseKey) return CycleBases(); + if (key == ks.CycleProductionBuildingsKey) + return CycleProductionBuildings(); + if (key == ks.ToLastEventKey) return ToLastEvent(); @@ -199,6 +203,30 @@ namespace OpenRA.Mods.RA.Widgets return ToSelection(); } + bool CycleProductionBuildings() + { + var facilities = world.ActorsWithTrait() + .Where(a => a.Actor.Owner == world.LocalPlayer && !a.Actor.HasTrait()) + .OrderBy(f => f.Actor.Info.Traits.Get().Produces.First()) + .ToArray(); + + if (!facilities.Any()) + return true; + + var next = facilities + .Select(b => b.Actor) + .SkipWhile(b => !world.Selection.Actors.Contains(b)) + .Skip(1) + .FirstOrDefault(); + + if (next == null) + next = facilities.Select(b => b.Actor).First(); + + world.Selection.Combine(world, new Actor[] { next }, false, true); + + return ToSelection(); + } + bool ToLastEvent() { if (world.LocalPlayer == null)