diff --git a/OpenRA.Game/Settings.cs b/OpenRA.Game/Settings.cs index a64a1bf73c..262bab3edd 100644 --- a/OpenRA.Game/Settings.cs +++ b/OpenRA.Game/Settings.cs @@ -297,7 +297,6 @@ namespace OpenRA public Hotkey PrevMusicKey = new Hotkey(Keycode.AUDIOPREV, Modifiers.None); public Hotkey NextMusicKey = new Hotkey(Keycode.AUDIONEXT, Modifiers.None); - static readonly Func[] ProductionKeys = GetKeys(24, "Production"); static readonly Func[] SupportPowerKeys = GetKeys(6, "SupportPower"); static Func[] GetKeys(int count, string prefix) @@ -316,11 +315,6 @@ namespace OpenRA return () => (Hotkey)field.GetValue(this); } - public Hotkey GetProductionHotkey(int index) - { - return GetKey(ProductionKeys, index); - } - public Hotkey GetSupportPowerHotkey(int index) { return GetKey(SupportPowerKeys, index); diff --git a/OpenRA.Mods.Common/Widgets/Logic/Ingame/ProductionTooltipLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Ingame/ProductionTooltipLogic.cs index b32bb4eaf5..0c8196a897 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Ingame/ProductionTooltipLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Ingame/ProductionTooltipLogic.cs @@ -47,6 +47,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic var descFont = Game.Renderer.Fonts[descLabel.Font]; var requiresFont = Game.Renderer.Fonts[requiresLabel.Font]; ActorInfo lastActor = null; + Hotkey lastHotkey = Hotkey.Invalid; tooltipContainer.BeforeRender = () => { @@ -55,7 +56,11 @@ namespace OpenRA.Mods.Common.Widgets.Logic return; var actor = tooltipIcon.Actor; - if (actor == null || actor == lastActor) + if (actor == null) + return; + + var hotkey = tooltipIcon.Hotkey != null ? tooltipIcon.Hotkey.GetValue() : Hotkey.Invalid; + if (actor == lastActor && hotkey == lastHotkey) return; var tooltip = actor.TraitInfos().FirstOrDefault(Exts.IsTraitEnabled); @@ -65,14 +70,19 @@ namespace OpenRA.Mods.Common.Widgets.Logic nameLabel.GetText = () => name; - var hotkey = tooltipIcon.Hotkey; var nameWidth = font.Measure(name).X; - var hotkeyText = "({0})".F(hotkey.DisplayString()); - var hotkeyWidth = hotkey.IsValid() ? font.Measure(hotkeyText).X + 2 * nameLabel.Bounds.X : 0; - hotkeyLabel.GetText = () => hotkeyText; - hotkeyLabel.Bounds.X = nameWidth + 2 * nameLabel.Bounds.X; + var hotkeyWidth = 0; hotkeyLabel.Visible = hotkey.IsValid(); + if (hotkeyLabel.Visible) + { + var hotkeyText = "({0})".F(hotkey.DisplayString()); + + hotkeyWidth = font.Measure(hotkeyText).X + 2 * nameLabel.Bounds.X; + hotkeyLabel.Text = hotkeyText; + hotkeyLabel.Bounds.X = nameWidth + 2 * nameLabel.Bounds.X; + } + var prereqs = buildable.Prerequisites.Select(a => ActorName(mapRules, a)).Where(s => !s.StartsWith("~")); var requiresString = prereqs.Any() ? requiresLabel.Text.F(prereqs.JoinWith(", ")) : ""; requiresLabel.GetText = () => requiresString; @@ -112,6 +122,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic widget.Bounds.Height = Math.Max(leftHeight, rightHeight) * 3 / 2 + 3 * nameLabel.Bounds.Y; lastActor = actor; + lastHotkey = hotkey; }; } diff --git a/OpenRA.Mods.Common/Widgets/ProductionPaletteWidget.cs b/OpenRA.Mods.Common/Widgets/ProductionPaletteWidget.cs index a806f313b0..f6ced3d29e 100644 --- a/OpenRA.Mods.Common/Widgets/ProductionPaletteWidget.cs +++ b/OpenRA.Mods.Common/Widgets/ProductionPaletteWidget.cs @@ -14,6 +14,7 @@ using System.Collections.Generic; using System.Drawing; using System.Linq; using OpenRA.Graphics; +using OpenRA.Mods.Common.Lint; using OpenRA.Mods.Common.Orders; using OpenRA.Mods.Common.Traits; using OpenRA.Mods.Common.Traits.Render; @@ -26,7 +27,7 @@ namespace OpenRA.Mods.Common.Widgets { public ActorInfo Actor; public string Name; - public Hotkey Hotkey; + public NamedHotkey Hotkey; public Sprite Sprite; public PaletteReference Palette; public PaletteReference IconClockPalette; @@ -51,6 +52,10 @@ namespace OpenRA.Mods.Common.Widgets public readonly string TooltipContainer; public readonly string TooltipTemplate = "PRODUCTION_TOOLTIP"; + // Note: LinterHotkeyNames assumes that these are disabled by default + public readonly string HotkeyPrefix = null; + public readonly int HotkeyCount = 0; + public readonly string ClockAnimation = "clock"; public readonly string ClockSequence = "idle"; public readonly string ClockPalette = "chrome"; @@ -79,6 +84,7 @@ namespace OpenRA.Mods.Common.Widgets Lazy tooltipContainer; ProductionQueue currentQueue; + NamedHotkey[] hotkeys; public ProductionQueue CurrentQueue { @@ -90,10 +96,34 @@ namespace OpenRA.Mods.Common.Widgets Dictionary icons = new Dictionary(); Animation cantBuild, clock; Rectangle eventBounds = Rectangle.Empty; + readonly WorldRenderer worldRenderer; + SpriteFont overlayFont; float2 holdOffset, readyOffset, timeOffset, queuedOffset; + [CustomLintableHotkeyNames] + public static IEnumerable LinterHotkeyNames(MiniYamlNode widgetNode, Action emitError, Action emitWarning) + { + var prefix = ""; + var prefixNode = widgetNode.Value.Nodes.FirstOrDefault(n => n.Key == "HotkeyPrefix"); + if (prefixNode != null) + prefix = prefixNode.Value.Value; + + var count = 0; + var countNode = widgetNode.Value.Nodes.FirstOrDefault(n => n.Key == "HotkeyCount"); + if (countNode != null) + count = FieldLoader.GetValue("HotkeyCount", countNode.Value.Value); + + if (count == 0) + return new string[0]; + + if (string.IsNullOrEmpty(prefix)) + emitError("{0} must define HotkeyPrefix if HotkeyCount > 0.".F(widgetNode.Location)); + + return Exts.MakeArray(count, i => prefix + (i + 1).ToString("D2")); + } + [ObjectCreator.UseCtor] public ProductionPaletteWidget(OrderManager orderManager, World world, WorldRenderer worldRenderer) { @@ -109,6 +139,14 @@ namespace OpenRA.Mods.Common.Widgets clock = new Animation(world, ClockAnimation); } + public override void Initialize(WidgetArgs args) + { + base.Initialize(args); + + hotkeys = Exts.MakeArray(HotkeyCount, + i => new NamedHotkey(HotkeyPrefix + (i + 1).ToString("D2"), Game.Settings.Keys)); + } + public void ScrollDown() { if (CanScrollDown) @@ -307,7 +345,7 @@ namespace OpenRA.Mods.Common.Widgets if (batchModifiers != Modifiers.None) hotkey = new Hotkey(hotkey.Key, hotkey.Modifiers ^ Modifiers.Shift); - var toBuild = icons.Values.FirstOrDefault(i => i.Hotkey == hotkey); + var toBuild = icons.Values.FirstOrDefault(i => i.Hotkey != null && i.Hotkey.GetValue() == hotkey); return toBuild != null ? HandleEvent(toBuild, MouseButton.Left, batchModifiers) : false; } @@ -329,7 +367,6 @@ namespace OpenRA.Mods.Common.Widgets var oldIconCount = DisplayedIconCount; DisplayedIconCount = 0; - var ks = Game.Settings.Keys; var rb = RenderBounds; var faction = producer.Trait.Faction; @@ -348,7 +385,7 @@ namespace OpenRA.Mods.Common.Widgets { Actor = item, Name = item.Name, - Hotkey = ks.GetProductionHotkey(DisplayedIconCount), + Hotkey = DisplayedIconCount < HotkeyCount ? hotkeys[DisplayedIconCount] : null, Sprite = icon.Image, Palette = worldRenderer.Palette(bi.IconPalette), IconClockPalette = worldRenderer.Palette(ClockPalette), diff --git a/mods/cnc/chrome/ingame.yaml b/mods/cnc/chrome/ingame.yaml index 61879c2293..0b788f8a20 100644 --- a/mods/cnc/chrome/ingame.yaml +++ b/mods/cnc/chrome/ingame.yaml @@ -714,6 +714,8 @@ Container@PLAYER_WIDGETS: TooltipContainer: TOOLTIP_CONTAINER ReadyText: Ready HoldText: On Hold + HotkeyPrefix: Production + HotkeyCount: 24 ProductionTabs@PRODUCTION_TABS: Logic: ProductionTabsLogic PaletteWidget: PRODUCTION_PALETTE diff --git a/mods/d2k/chrome/ingame-player.yaml b/mods/d2k/chrome/ingame-player.yaml index 2d4f1d8dba..9635de756a 100644 --- a/mods/d2k/chrome/ingame-player.yaml +++ b/mods/d2k/chrome/ingame-player.yaml @@ -480,6 +480,8 @@ Container@PLAYER_WIDGETS: IconSpriteOffset: 0, 0 MinimumRows: 5 MaximumRows: 6 + HotkeyPrefix: Production + HotkeyCount: 24 Container@PRODUCTION_TYPES: X: 6 Y: 2 diff --git a/mods/ra/chrome/ingame-player.yaml b/mods/ra/chrome/ingame-player.yaml index aecaf57f8e..414e7f8919 100644 --- a/mods/ra/chrome/ingame-player.yaml +++ b/mods/ra/chrome/ingame-player.yaml @@ -469,6 +469,8 @@ Container@PLAYER_WIDGETS: IconSize: 62, 46 IconMargin: 1, 1 IconSpriteOffset: -1, -1 + HotkeyPrefix: Production + HotkeyCount: 24 Container@PALETTE_FOREGROUND: X: 40 Y: 0 - 1 diff --git a/mods/ts/chrome/ingame-player.yaml b/mods/ts/chrome/ingame-player.yaml index 5dcedf3e73..56ae8af438 100644 --- a/mods/ts/chrome/ingame-player.yaml +++ b/mods/ts/chrome/ingame-player.yaml @@ -483,6 +483,8 @@ Container@PLAYER_WIDGETS: IconSpriteOffset: 0, 0 MinimumRows: 4 MaximumRows: 6 + HotkeyPrefix: Production + HotkeyCount: 24 Container@PRODUCTION_TYPES: X: 0 Y: 0 - 32