From 2a0b9a8596e5e3605d59f58b83020ee220891593 Mon Sep 17 00:00:00 2001 From: Scott_NZ Date: Sat, 24 Nov 2012 01:39:02 +1300 Subject: [PATCH] Display support powers --- OpenRA.Mods.RA/OpenRA.Mods.RA.csproj | 3 +- .../Widgets/Logic/ObserverStatsLogic.cs | 92 ++++++++++----- ...et.cs => ObserverProductionIconsWidget.cs} | 8 +- .../ObserverSupportPowerIconsWidget.cs | 107 ++++++++++++++++++ mods/ra/chrome/ingame.yaml | 51 ++++++++- 5 files changed, 222 insertions(+), 39 deletions(-) rename OpenRA.Mods.RA/Widgets/{ObserverBuildIconsWidget.cs => ObserverProductionIconsWidget.cs} (91%) create mode 100644 OpenRA.Mods.RA/Widgets/ObserverSupportPowerIconsWidget.cs diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index 59ed96a34e..988c9c1d70 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -382,7 +382,8 @@ - + + diff --git a/OpenRA.Mods.RA/Widgets/Logic/ObserverStatsLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/ObserverStatsLogic.cs index 170eddab3b..8b53853b52 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/ObserverStatsLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/ObserverStatsLogic.cs @@ -21,18 +21,13 @@ namespace OpenRA.Mods.RA.Widgets.Logic { public class ObserverStatsLogic { - class StatsDropDownOption - { - public string Title; - public Func IsSelected; - public Action OnClick; - } - ContainerWidget basicStatsHeaders; ContainerWidget economicStatsHeaders; + ContainerWidget supportStatsHeaders; ScrollPanelWidget playerStatsPanel; ScrollItemWidget basicPlayerTemplate; ScrollItemWidget economicPlayerTemplate; + ScrollItemWidget supportPlayerTemplate; ScrollItemWidget teamTemplate; DropDownButtonWidget statsDropDown; LabelWidget title; @@ -49,12 +44,15 @@ namespace OpenRA.Mods.RA.Widgets.Logic basicStatsHeaders = widget.Get("BASIC_STATS_HEADERS"); economicStatsHeaders = widget.Get("ECONOMIC_STATS_HEADERS"); + supportStatsHeaders = widget.Get("SUPPORT_STATS_HEADERS"); playerStatsPanel = widget.Get("PLAYER_STATS_PANEL"); playerStatsPanel.Layout = new GridLayout(playerStatsPanel); basicPlayerTemplate = playerStatsPanel.Get("BASIC_PLAYER_TEMPLATE"); economicPlayerTemplate = playerStatsPanel.Get("ECONOMIC_PLAYER_TEMPLATE"); + supportPlayerTemplate = playerStatsPanel.Get("SUPPORT_PLAYER_TEMPLATE"); + teamTemplate = playerStatsPanel.Get("TEAM_TEMPLATE"); statsDropDown = widget.Get("STATS_DROPDOWN"); @@ -84,6 +82,17 @@ namespace OpenRA.Mods.RA.Widgets.Logic statsDropDown.GetText = () => "Economic"; LoadStats(EconomicStats); } + }, + new StatsDropDownOption + { + Title = "Support", + IsSelected = () => supportStatsHeaders.Visible, + OnClick = () => + { + ClearStats(); + statsDropDown.GetText = () => "Support"; + LoadStats(SupportStats); + } } }; Func setupItem = (option, template) => @@ -107,9 +116,10 @@ namespace OpenRA.Mods.RA.Widgets.Logic playerStatsPanel.Children.Clear(); basicStatsHeaders.Visible = false; economicStatsHeaders.Visible = false; + supportStatsHeaders.Visible = false; } - void LoadStats(Action forEachPlayer) + void LoadStats(Func forEachPlayer) { var teams = players.GroupBy(p => (world.LobbyInfo.ClientWithIndex(p.ClientIndex) ?? new Session.Client()).Team).OrderBy(g => g.Key); foreach (var t in teams) @@ -122,23 +132,30 @@ namespace OpenRA.Mods.RA.Widgets.Logic foreach (var p in team) { var player = p; - forEachPlayer(player); + playerStatsPanel.AddChild(forEachPlayer(player)); } } } - void EconomicStats(Player player) + ScrollItemWidget SupportStats(Player player) + { + supportStatsHeaders.Visible = true; + var template = SetupPlayerScrollItemWidget(supportPlayerTemplate, player); + + AddPlayerFlagAndName(template, player); + + var supportPowers = template.Get("SUPPORT_POWERS"); + supportPowers.GetPlayer = () => player; + + return template; + } + + ScrollItemWidget EconomicStats(Player player) { economicStatsHeaders.Visible = true; var template = SetupPlayerScrollItemWidget(economicPlayerTemplate, player); - var flag = template.Get("FACTION_FLAG"); - flag.GetImageName = () => player.Country.Race; - flag.GetImageCollection = () => "flags"; - - var playerName = template.Get("PLAYER"); - playerName.GetText = () => player.PlayerName + (player.WinState == WinState.Undefined ? "" : " (" + player.WinState + ")"); - playerName.GetColor = () => player.ColorRamp.GetColor(0); + AddPlayerFlagAndName(template, player); var res = player.PlayerActor.Trait(); template.Get("CASH").GetText = () => "$" + (res.DisplayCash + res.DisplayOre); @@ -147,9 +164,10 @@ namespace OpenRA.Mods.RA.Widgets.Logic change.GetText = () => Math.Round(res.IncomeChange * 100, 1, MidpointRounding.AwayFromZero) + "%"; change.GetColor = () => { - if (res.IncomeChange < 0) return Color.Red; - if (res.IncomeChange > 0) return Color.LimeGreen; - else return Color.White; + var c = Math.Round(res.IncomeChange, 1, MidpointRounding.AwayFromZero); + if (c < 0) return Color.Red; + if (c > 0) return Color.LimeGreen; + return Color.White; }; var assets = template.Get("TOTAL_ASSETS"); @@ -160,21 +178,15 @@ namespace OpenRA.Mods.RA.Widgets.Logic var numHarvesters = template.Get("NUMBER_HARVESTERS"); numHarvesters.GetText = () => world.Actors.Count(a => a.Owner == player && !a.IsDead() && a.HasTrait()).ToString(); - playerStatsPanel.AddChild(template); + return template; } - void BasicStats(Player player) + ScrollItemWidget BasicStats(Player player) { basicStatsHeaders.Visible = true; var template = SetupPlayerScrollItemWidget(basicPlayerTemplate, player); - var flag = template.Get("FACTION_FLAG"); - flag.GetImageName = () => player.Country.Race; - flag.GetImageCollection = () => "flags"; - - var playerName = template.Get("PLAYER"); - playerName.GetText = () => player.PlayerName + (player.WinState == WinState.Undefined ? "" : " (" + player.WinState + ")"); - playerName.GetColor = () => player.ColorRamp.GetColor(0); + AddPlayerFlagAndName(template, player); var res = player.PlayerActor.Trait(); template.Get("CASH").GetText = () => "$" + (res.DisplayCash + res.DisplayOre); @@ -188,10 +200,10 @@ namespace OpenRA.Mods.RA.Widgets.Logic template.Get("KILLS").GetText = () => player.Kills.ToString(); template.Get("DEATHS").GetText = () => player.Deaths.ToString(); - var production = template.Get("PRODUCTION_ICONS"); + var production = template.Get("PRODUCTION_ICONS"); production.GetPlayer = () => player; - playerStatsPanel.AddChild(template); + return template; } ScrollItemWidget SetupPlayerScrollItemWidget(ScrollItemWidget template, Player player) @@ -206,6 +218,17 @@ namespace OpenRA.Mods.RA.Widgets.Logic }); } + static void AddPlayerFlagAndName(ScrollItemWidget template, Player player) + { + var flag = template.Get("FLAG"); + flag.GetImageName = () => player.Country.Race; + flag.GetImageCollection = () => "flags"; + + var playerName = template.Get("PLAYER"); + playerName.GetText = () => player.PlayerName + (player.WinState == WinState.Undefined ? "" : " (" + player.WinState + ")"); + playerName.GetColor = () => player.ColorRamp.GetColor(0); + } + static void InitializeWidgets(params Widget[] widgets) { var args = new WidgetArgs(); @@ -221,5 +244,12 @@ namespace OpenRA.Mods.RA.Widgets.Logic if (state == PowerState.Low) return Color.Orange; return Color.LimeGreen; } + + class StatsDropDownOption + { + public string Title; + public Func IsSelected; + public Action OnClick; + } } } diff --git a/OpenRA.Mods.RA/Widgets/ObserverBuildIconsWidget.cs b/OpenRA.Mods.RA/Widgets/ObserverProductionIconsWidget.cs similarity index 91% rename from OpenRA.Mods.RA/Widgets/ObserverBuildIconsWidget.cs rename to OpenRA.Mods.RA/Widgets/ObserverProductionIconsWidget.cs index d66fa78714..68b78a7b20 100644 --- a/OpenRA.Mods.RA/Widgets/ObserverBuildIconsWidget.cs +++ b/OpenRA.Mods.RA/Widgets/ObserverProductionIconsWidget.cs @@ -17,7 +17,7 @@ using System.Drawing; namespace OpenRA.Mods.RA.Widgets { - public class ObserverBuildIconsWidget : Widget + public class ObserverProductionIconsWidget : Widget { public Func GetPlayer; Dictionary iconSprites; @@ -26,7 +26,7 @@ namespace OpenRA.Mods.RA.Widgets Dictionary clocks; [ObjectCreator.UseCtor] - public ObserverBuildIconsWidget(World world, WorldRenderer worldRenderer) + public ObserverProductionIconsWidget(World world, WorldRenderer worldRenderer) : base() { iconSprites = Rules.Info.Values.Where(u => u.Traits.Contains() && u.Name[0] != '^') @@ -38,7 +38,7 @@ namespace OpenRA.Mods.RA.Widgets clocks = new Dictionary(); } - protected ObserverBuildIconsWidget(ObserverBuildIconsWidget other) + protected ObserverProductionIconsWidget(ObserverProductionIconsWidget other) : base(other) { GetPlayer = other.GetPlayer; @@ -101,7 +101,7 @@ namespace OpenRA.Mods.RA.Widgets public override Widget Clone() { - return new ObserverBuildIconsWidget(this); + return new ObserverProductionIconsWidget(this); } } } diff --git a/OpenRA.Mods.RA/Widgets/ObserverSupportPowerIconsWidget.cs b/OpenRA.Mods.RA/Widgets/ObserverSupportPowerIconsWidget.cs new file mode 100644 index 0000000000..fba606a789 --- /dev/null +++ b/OpenRA.Mods.RA/Widgets/ObserverSupportPowerIconsWidget.cs @@ -0,0 +1,107 @@ +#region Copyright & License Information +/* + * Copyright 2007-2012 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Widgets; +using System.Drawing; + +namespace OpenRA.Mods.RA.Widgets +{ + public class ObserverSupportPowerIconsWidget : Widget + { + public Func GetPlayer; + Dictionary iconSprites; + World world; + WorldRenderer worldRenderer; + Dictionary clocks; + + [ObjectCreator.UseCtor] + public ObserverSupportPowerIconsWidget(World world, WorldRenderer worldRenderer) + : base() + { + iconSprites = Rules.Info.Values.SelectMany(u => u.Traits.WithInterface()) + .Select(u => u.Image).Distinct() + .ToDictionary( + u => u, + u => Game.modData.SpriteLoader.LoadAllSprites(u)[0]); + this.world = world; + this.worldRenderer = worldRenderer; + clocks = new Dictionary(); + } + + protected ObserverSupportPowerIconsWidget(ObserverSupportPowerIconsWidget other) + : base(other) + { + GetPlayer = other.GetPlayer; + iconSprites = other.iconSprites; + world = other.world; + worldRenderer = other.worldRenderer; + clocks = other.clocks; + } + + public override void Draw() + { + var player = GetPlayer(); + if (player == null) + { + return; + } + var powers = player.PlayerActor.Trait().Powers + .Select((a, i) => new { a, i }); + foreach (var power in powers) + { + if (!clocks.ContainsKey(power.a.Key)) + { + clocks.Add(power.a.Key, new Animation("clock")); + } + } + foreach (var power in powers) + { + var item = power.a.Value; + if (item == null) + { + continue; + } + var sprite = iconSprites[item.Info.Image]; + var size = sprite.size / new float2(2, 2); + var location = new float2(RenderBounds.Location) + new float2(power.i * (int)size.Length, 0); + WidgetUtils.DrawSHP(sprite, location, worldRenderer, size); + + var clock = clocks[power.a.Key]; + clock.PlayFetchIndex("idle", + () => (item.TotalTime - item.RemainingTime) + * (clock.CurrentSequence.Length - 1) / item.TotalTime); + clock.Tick(); + WidgetUtils.DrawSHP(clock.Image, location, worldRenderer, size); + + var tiny = Game.Renderer.Fonts["Tiny"]; + var text = GetOverlayForItem(item); + tiny.DrawTextWithContrast(text, + location + new float2(16, 16) - new float2(tiny.Measure(text).X / 2, 0), + Color.White, Color.Black, 1); + } + } + + static string GetOverlayForItem(SupportPowerManager.SupportPowerInstance item) + { + if (item.Disabled) return "ON HOLD"; + if (item.Ready) return "READY"; + return WidgetUtils.FormatTime(item.RemainingTime); + } + + public override Widget Clone() + { + return new ObserverSupportPowerIconsWidget(this); + } + } +} diff --git a/mods/ra/chrome/ingame.yaml b/mods/ra/chrome/ingame.yaml index e7f855d18f..5f49aff40d 100644 --- a/mods/ra/chrome/ingame.yaml +++ b/mods/ra/chrome/ingame.yaml @@ -518,6 +518,27 @@ Container@OBSERVER_ROOT: Font:Bold Text:Harvesters Align:Right + Container@SUPPORT_STATS_HEADERS: + X:0 + Y:0 + Width:PARENT_RIGHT + Height:PARENT_BOTTOM + Children: + Label@PLAYER_HEADER: + X:85 + Y:40 + Width:160 + Height:25 + Font:Bold + Text:Player + Label@SUPPORT_POWERS_HEADER: + X:245 + Y:40 + Width:300 + Height:25 + Font:Bold + Text:Support Powers + Align:Center ScrollPanel@PLAYER_STATS_PANEL: X:25 Y:70 @@ -543,7 +564,7 @@ Container@OBSERVER_ROOT: Width:PARENT_RIGHT-35 Height:25 Children: - Image@FACTION_FLAG: + Image@FLAG: X:20 Y:5 Width:35 @@ -583,7 +604,7 @@ Container@OBSERVER_ROOT: Width:40 Height:PARENT_BOTTOM Align:Right - ObserverBuildIcons@PRODUCTION_ICONS: + ObserverProductionIcons@PRODUCTION_ICONS: X:575 Y:0 Width:240 @@ -594,7 +615,7 @@ Container@OBSERVER_ROOT: Width:PARENT_RIGHT-35 Height:25 Children: - Image@FACTION_FLAG: + Image@FLAG: X:20 Y:5 Width:35 @@ -633,6 +654,30 @@ Container@OBSERVER_ROOT: Width:60 Height:PARENT_BOTTOM Align:Right + ScrollItem@SUPPORT_PLAYER_TEMPLATE: + X:0 + Y:0 + Width:PARENT_RIGHT-35 + Height:25 + Children: + Image@FLAG: + X:20 + Y:5 + Width:35 + Height:PARENT_BOTTOM-5 + ImageName:random + ImageCollection:flags + Label@PLAYER: + X:55 + Y:0 + Width:160 + Height:PARENT_BOTTOM + Font:Bold + ObserverSupportPowerIcons@SUPPORT_POWERS: + X:215 + Y:0 + Width:300 + Height:PARENT_BOTTOM Background@FMVPLAYER: Width:WINDOW_RIGHT Height:WINDOW_BOTTOM