diff --git a/OpenRA.Mods.Cnc/Widgets/Logic/CncIngameChromeLogic.cs b/OpenRA.Mods.Cnc/Widgets/Logic/CncIngameChromeLogic.cs index e94b5a8c39..8c9614d21d 100644 --- a/OpenRA.Mods.Cnc/Widgets/Logic/CncIngameChromeLogic.cs +++ b/OpenRA.Mods.Cnc/Widgets/Logic/CncIngameChromeLogic.cs @@ -22,6 +22,7 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic MenuType menu = MenuType.None; Widget ingameRoot; + World world; void AddChatLine(Color c, string from, string text) { @@ -32,6 +33,13 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic { Game.AddChatLine -= AddChatLine; Game.BeforeGameStart -= UnregisterEvents; + + if (world.LocalPlayer != null) + { + var queueTabs = ingameRoot.GetWidget("PRODUCTION_TABS"); + world.ActorAdded += queueTabs.ActorChanged; + world.ActorRemoved += queueTabs.ActorChanged; + } } ProductionQueue QueueForType(World world, string type) @@ -45,6 +53,7 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic public CncIngameChromeLogic([ObjectCreator.Param] Widget widget, [ObjectCreator.Param] World world ) { + this.world = world; world.WorldActor.Trait() .Fade(CncMenuPaletteEffect.EffectType.None); @@ -65,33 +74,31 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic var buildPalette = playerWidgets.GetWidget("PRODUCTION_PALETTE"); var queueTabs = playerWidgets.GetWidget("PRODUCTION_TABS"); + + world.ActorAdded += queueTabs.ActorChanged; + world.ActorRemoved += queueTabs.ActorChanged; + var queueTypes = sidebarRoot.GetWidget("PRODUCTION_TYPES"); var buildingTab = queueTypes.GetWidget("BUILDING"); buildingTab.OnClick = () => queueTabs.QueueType = "Building"; - buildingTab.IsDisabled = () => !queueTabs.QueueCounts.ContainsKey("Building") - || queueTabs.QueueCounts["Building"] == 0; + buildingTab.IsDisabled = () => queueTabs.Groups["Building"].Tabs.Count == 0; var defenseTab = queueTypes.GetWidget("DEFENSE"); defenseTab.OnClick = () => queueTabs.QueueType = "Defense"; - defenseTab.IsDisabled = () => !queueTabs.QueueCounts.ContainsKey("Defense") - || queueTabs.QueueCounts["Defense"] == 0; + defenseTab.IsDisabled = () => queueTabs.Groups["Defense"].Tabs.Count == 0; var infantryTab = queueTypes.GetWidget("INFANTRY"); infantryTab.OnClick = () => queueTabs.QueueType = "Infantry"; - infantryTab.IsDisabled = () => !queueTabs.QueueCounts.ContainsKey("Infantry") - || queueTabs.QueueCounts["Infantry"] == 0; + infantryTab.IsDisabled = () => queueTabs.Groups["Infantry"].Tabs.Count == 0; var vehicleTab = queueTypes.GetWidget("VEHICLE"); vehicleTab.OnClick = () => queueTabs.QueueType = "Vehicle"; - vehicleTab.IsDisabled = () => !queueTabs.QueueCounts.ContainsKey("Vehicle") - || queueTabs.QueueCounts["Vehicle"] == 0; + vehicleTab.IsDisabled = () => queueTabs.Groups["Vehicle"].Tabs.Count == 0; var aircraftTab = queueTypes.GetWidget("AIRCRAFT"); aircraftTab.OnClick = () => queueTabs.QueueType = "Aircraft"; - aircraftTab.IsDisabled = () => !queueTabs.QueueCounts.ContainsKey("Aircraft") - || queueTabs.QueueCounts["Aircraft"] == 0; - + aircraftTab.IsDisabled = () => queueTabs.Groups["Aircraft"].Tabs.Count == 0; } ingameRoot.GetWidget("OPTIONS_BUTTON").OnClick = () => { diff --git a/OpenRA.Mods.Cnc/Widgets/ProductionTabsWidget.cs b/OpenRA.Mods.Cnc/Widgets/ProductionTabsWidget.cs index b43d83f955..368479d9ff 100755 --- a/OpenRA.Mods.Cnc/Widgets/ProductionTabsWidget.cs +++ b/OpenRA.Mods.Cnc/Widgets/ProductionTabsWidget.cs @@ -19,6 +19,44 @@ using System; namespace OpenRA.Mods.Cnc.Widgets { + public class ProductionTab + { + public string Name; + public ProductionQueue Queue; + } + + public class ProductionTabGroup + { + public List Tabs = new List(); + public string Group; + public int CumulativeCount; + + public void Update(IEnumerable allQueues) + { + var queues = allQueues.Where(q => q.Info.Group == Group).ToList(); + List tabs = new List(); + + // Remove stale queues + foreach (var t in Tabs) + { + if (!queues.Contains(t.Queue)) + continue; + + tabs.Add(t); + queues.Remove(t.Queue); + } + + // Add new queues + foreach (var queue in queues) + tabs.Add(new ProductionTab() + { + Name = (++CumulativeCount).ToString(), + Queue = queue + }); + Tabs = tabs; + } + } + class ProductionTabsWidget : Widget { string queueType; @@ -32,9 +70,8 @@ namespace OpenRA.Mods.Cnc.Widgets { queueType = value; ListOffset = 0; - ResetButtons(); Widget.RootWidget.GetWidget(PaletteWidget) - .CurrentQueue = tabs.Keys.FirstOrDefault(); + .CurrentQueue = Groups[queueType].Tabs[0].Queue; } } @@ -42,10 +79,7 @@ namespace OpenRA.Mods.Cnc.Widgets public float ScrollVelocity = 4f; public int TabWidth = 30; public int ArrowWidth = 20; - - public ProductionQueue[] AllQueues; - public Dictionary QueueCounts = new Dictionary(); - Dictionary tabs = new Dictionary(); + public Dictionary Groups; int ContentWidth = 0; float ListOffset = 0; @@ -53,19 +87,19 @@ namespace OpenRA.Mods.Cnc.Widgets bool rightPressed = false; Rectangle leftButtonRect; Rectangle rightButtonRect; - readonly World world; [ObjectCreator.UseCtor] public ProductionTabsWidget( [ObjectCreator.Param] World world ) { this.world = world; + Groups = Rules.Info.Values.SelectMany(a => a.Traits.WithInterface()) + .Select(q => q.Group).Distinct().ToDictionary(g => g, g => new ProductionTabGroup() { Group = g }); } public override void DrawInner() { var rb = RenderBounds; - leftButtonRect = new Rectangle(rb.X, rb.Y, ArrowWidth, rb.Height); rightButtonRect = new Rectangle(rb.Right - ArrowWidth, rb.Y, ArrowWidth, rb.Height); @@ -83,21 +117,24 @@ namespace OpenRA.Mods.Cnc.Widgets WidgetUtils.DrawRGBA(ChromeProvider.GetImage("scrollbar", rightPressed || rightDisabled ? "down_pressed" : "down_arrow"), new float2(rightButtonRect.Left + 2, rightButtonRect.Top + 2)); + if (QueueType == null) + return; + + // Draw tab buttons Game.Renderer.EnableScissor(leftButtonRect.Right, rb.Y + 1, rightButtonRect.Left - leftButtonRect.Right - 1, rb.Height); - var palette = Widget.RootWidget.GetWidget(PaletteWidget); - // TODO: Draw children buttons - var i = 1; - foreach (var tab in tabs) + var origin = new int2(leftButtonRect.Right - 1 + (int)ListOffset, leftButtonRect.Y); + SpriteFont font = Game.Renderer.Fonts["TinyBold"]; + ContentWidth = 0; + foreach (var tab in Groups[QueueType].Tabs) { - ButtonWidget.DrawBackground("button", tab.Value, false, tab.Key == palette.CurrentQueue, tab.Value.Contains(Viewport.LastMousePos)); + var rect = new Rectangle(origin.X + ContentWidth, origin.Y, TabWidth, rb.Height); + ButtonWidget.DrawBackground("button", rect, false, tab.Queue == palette.CurrentQueue, rect.Contains(Viewport.LastMousePos)); + ContentWidth += TabWidth - 1; - SpriteFont font = Game.Renderer.Fonts["TinyBold"]; - var text = i.ToString(); - int2 textSize = font.Measure(text); - int2 position = new int2(tab.Value.X + (tab.Value.Width - textSize.X)/2, tab.Value.Y + (tab.Value.Height - textSize.Y)/2); - font.DrawTextWithContrast(text, position, Color.White, Color.Black, 1); - i++; + int2 textSize = font.Measure(tab.Name); + int2 position = new int2(rect.X + (rect.Width - textSize.X)/2, rect.Y + (rect.Height - textSize.Y)/2); + font.DrawTextWithContrast(tab.Name, position, Color.White, Color.Black, 1); } Game.Renderer.DisableScissor(); @@ -109,18 +146,16 @@ namespace OpenRA.Mods.Cnc.Widgets ListOffset = Math.Min(0,Math.Max(Bounds.Width - rightButtonRect.Width - leftButtonRect.Width - ContentWidth, ListOffset)); } - public void ResetButtons() + // Is added to world.ActorAdded by the SidebarLogic handler + public void ActorChanged(Actor a) { - tabs.Clear(); - ContentWidth = 0; - var rb = RenderBounds; - var origin = new int2(leftButtonRect.Right - 1 + (int)ListOffset, leftButtonRect.Y); - - foreach (var queue in AllQueues.Where(q => q.Info.Type == QueueType)) + if (a.HasTrait()) { - var rect = new Rectangle(origin.X + ContentWidth, origin.Y, TabWidth, rb.Height); - tabs.Add(queue, rect); - ContentWidth += TabWidth - 1; + var allQueues = world.ActorsWithTrait() + .Where(p => p.Actor.Owner == world.LocalPlayer && p.Actor.IsInWorld) + .Select(p => p.Trait).ToArray(); + foreach (var g in Groups.Values) + g.Update(allQueues); } } @@ -128,15 +163,6 @@ namespace OpenRA.Mods.Cnc.Widgets { if (leftPressed) Scroll(1); if (rightPressed) Scroll(-1); - - AllQueues = world.ActorsWithTrait() - .Where(p => p.Actor.Owner == world.LocalPlayer) - .Select(p => p.Trait).ToArray(); - - QueueCounts = AllQueues.Select(q => q.Info.Type).Distinct() - .ToDictionary(t => t, t => AllQueues.Count(q => q.Info.Type == t)); - - ResetButtons(); base.Tick(); } @@ -145,7 +171,7 @@ namespace OpenRA.Mods.Cnc.Widgets leftPressed = rightPressed = false; return base.LoseFocus(mi); } - + public override bool HandleMouseInput(MouseInput mi) { if (mi.Button == MouseButton.WheelDown) @@ -175,16 +201,16 @@ namespace OpenRA.Mods.Cnc.Widgets leftPressed = leftButtonRect.Contains(mi.Location.X, mi.Location.Y); rightPressed = rightButtonRect.Contains(mi.Location.X, mi.Location.Y); - var queue = tabs.Where(a => a.Value.Contains(mi.Location)) - .Select(a => a.Key).FirstOrDefault(); - - if (queue != null) + // Check production tabs + var offsetloc = mi.Location - new int2(leftButtonRect.Right - 1 + (int)ListOffset, leftButtonRect.Y); + if (offsetloc.X > 0 && offsetloc.X <= ContentWidth) { var palette = Widget.RootWidget.GetWidget(PaletteWidget); - palette.CurrentQueue = queue; + palette.CurrentQueue = Groups[QueueType].Tabs[offsetloc.X/(TabWidth - 1)].Queue; + return true; } - return (leftPressed || rightPressed || queue != null); + return (leftPressed || rightPressed); } } } diff --git a/OpenRA.Mods.RA/Player/ProductionQueue.cs b/OpenRA.Mods.RA/Player/ProductionQueue.cs index e7ebb048bd..2975414315 100755 --- a/OpenRA.Mods.RA/Player/ProductionQueue.cs +++ b/OpenRA.Mods.RA/Player/ProductionQueue.cs @@ -19,6 +19,8 @@ namespace OpenRA.Mods.RA public class ProductionQueueInfo : ITraitInfo { public readonly string Type = null; + public readonly string Group = null; + public float BuildSpeed = 0.4f; public readonly int LowPowerSlowdown = 3; diff --git a/mods/cnc/rules/structures.yaml b/mods/cnc/rules/structures.yaml index eaceb7fe4b..5e83268c70 100644 --- a/mods/cnc/rules/structures.yaml +++ b/mods/cnc/rules/structures.yaml @@ -25,6 +25,7 @@ FACT: Facing: 108 ProductionQueue@Building: Type: Building + Group: Building BuildSpeed: .4 LowPowerSlowdown: 3 QueuedAudio: bldging1.aud @@ -33,6 +34,7 @@ FACT: CancelledAudio: cancel1.aud ProductionQueue@Defense: Type: Defense + Group: Defense BuildSpeed: .4 LowPowerSlowdown: 3 QueuedAudio: bldging1.aud @@ -165,6 +167,7 @@ PYLE: Produces: Infantry ProductionQueue: Type: Infantry + Group: Infantry BuildSpeed: .4 LowPowerSlowdown: 3 QueuedAudio: bldging1.aud @@ -204,6 +207,7 @@ HAND: Produces: Infantry ProductionQueue: Type: Infantry + Group: Infantry BuildSpeed: .4 LowPowerSlowdown: 3 QueuedAudio: bldging1.aud @@ -245,6 +249,7 @@ AFLD: Produces: Vehicle ProductionQueue: Type: Vehicle + Group: Vehicle BuildSpeed: .4 LowPowerSlowdown: 3 QueuedAudio: bldging1.aud @@ -287,6 +292,7 @@ WEAP: Produces: Vehicle ProductionQueue: Type: Vehicle + Group: Vehicle BuildSpeed: .4 LowPowerSlowdown: 3 QueuedAudio: bldging1.aud @@ -413,6 +419,7 @@ HPAD: RallyPoint: ProductionQueue: Type: Plane + Group: Aircraft BuildSpeed: .4 LowPowerSlowdown: 3 QueuedAudio: bldging1.aud diff --git a/mods/cnc/rules/tech.yaml b/mods/cnc/rules/tech.yaml index 8ff2786c19..f95631ccde 100644 --- a/mods/cnc/rules/tech.yaml +++ b/mods/cnc/rules/tech.yaml @@ -53,6 +53,7 @@ BIO: Produces: Biolab ProductionQueue: Type: Biolab + Group: Infantry BuildSpeed: .4 LowPowerSlowdown: 3 QueuedAudio: bldging1.aud