From f805d67741169579983c56729083596ba28c1f60 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sun, 27 Oct 2024 16:20:19 +0000 Subject: [PATCH] Allow mods to display Encyclopedia production info. --- OpenRA.Mods.Common/Traits/Encyclopedia.cs | 6 ++ .../Widgets/Logic/EncyclopediaLogic.cs | 96 +++++++++++++++++-- mods/common/fluent/common.ftl | 2 +- 3 files changed, 96 insertions(+), 8 deletions(-) diff --git a/OpenRA.Mods.Common/Traits/Encyclopedia.cs b/OpenRA.Mods.Common/Traits/Encyclopedia.cs index 3f82486b89..17a0d6d53b 100644 --- a/OpenRA.Mods.Common/Traits/Encyclopedia.cs +++ b/OpenRA.Mods.Common/Traits/Encyclopedia.cs @@ -28,6 +28,12 @@ namespace OpenRA.Mods.Common.Traits [Desc("Scale the actor preview.")] public readonly float Scale = 1f; + [Desc("Ignore the Buildable trait when listing information.")] + public readonly bool HideBuildable = false; + + [Desc("Specifies a production queue type if the actor can be built from multiple queues.")] + public readonly string BuildableQueue = null; + public override object Create(ActorInitializer init) { return Encyclopedia.Instance; } } diff --git a/OpenRA.Mods.Common/Widgets/Logic/EncyclopediaLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/EncyclopediaLogic.cs index e73f8f2611..6b52cc2500 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/EncyclopediaLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/EncyclopediaLogic.cs @@ -11,6 +11,7 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using OpenRA.FileFormats; using OpenRA.Graphics; @@ -23,6 +24,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic { public class EncyclopediaLogic : ChromeLogic { + [FluentReference("prerequisites")] + const string Requires = "label-requires"; + readonly World world; readonly ModData modData; readonly Dictionary info = new(); @@ -41,6 +45,12 @@ namespace OpenRA.Mods.Common.Widgets.Logic readonly Sprite portraitSprite; readonly Png defaultPortrait; + readonly Widget productionContainer; + readonly LabelWidget productionCost; + readonly LabelWidget productionTime; + readonly Widget productionPowerIcon; + readonly LabelWidget productionPower; + ActorInfo selectedActor; ScrollItemWidget firstItem; @@ -79,6 +89,12 @@ namespace OpenRA.Mods.Common.Widgets.Logic actorList.RemoveChildren(); + productionContainer = descriptionPanel.GetOrNull("ACTOR_PRODUCTION"); + productionCost = productionContainer?.Get("COST"); + productionTime = productionContainer?.Get("TIME"); + productionPowerIcon = productionContainer?.Get("POWER_ICON"); + productionPower = productionContainer?.Get("POWER"); + foreach (var actor in modData.DefaultRules.Actors.Values) { if (actor.TraitInfos().Count == 0) @@ -184,20 +200,49 @@ namespace OpenRA.Mods.Common.Widgets.Logic if (titleLabel != null) titleLabel.Text = ActorName(modData.DefaultRules, actor.Name); - var text = ""; - var buildable = actor.TraitInfoOrDefault(); - if (buildable != null) + var bi = actor.TraitInfoOrDefault(); + + if (productionContainer != null && bi != null && !selectedInfo.HideBuildable) { - var prerequisites = buildable.Prerequisites + productionContainer.Visible = true; + var cost = actor.TraitInfoOrDefault()?.Cost ?? 0; + + var time = BuildTime(selectedActor, selectedInfo.BuildableQueue); + productionTime.Text = WidgetUtils.FormatTime(time, world.Timestep); + + var costText = cost.ToString(NumberFormatInfo.CurrentInfo); + productionCost.Text = costText; + + var power = actor.TraitInfos().Where(i => i.EnabledByDefault).Sum(i => i.Amount); + if (power != 0) + { + productionPowerIcon.Visible = true; + productionPower.Visible = true; + productionPower.Text = power.ToString(NumberFormatInfo.CurrentInfo); + } + else + { + productionPowerIcon.Visible = false; + productionPower.Visible = false; + } + } + else if (productionContainer != null) + productionContainer.Visible = false; + + var text = ""; + if (bi != null) + { + var prereqs = bi.Prerequisites .Select(a => ActorName(modData.DefaultRules, a)) .Where(s => !s.StartsWith('~') && !s.StartsWith('!')) .ToList(); - if (prerequisites.Count != 0) - text += $"Requires {prerequisites.JoinWith(", ")}\n\n"; + + if (prereqs.Count != 0) + text += FluentProvider.GetMessage(Requires, "prerequisites", prereqs.JoinWith(", ")) + "\n\n"; } if (selectedInfo != null && !string.IsNullOrEmpty(selectedInfo.Description)) - text += WidgetUtils.WrapText(FluentProvider.GetMessage(selectedInfo.Description) + "\n\n", descriptionLabel.Bounds.Width, descriptionFont); + text += WidgetUtils.WrapText(FluentProvider.GetMessage(selectedInfo.Description), descriptionLabel.Bounds.Width, descriptionFont); var height = descriptionFont.Measure(text).Y; descriptionLabel.GetText = () => text; @@ -218,5 +263,42 @@ namespace OpenRA.Mods.Common.Widgets.Logic return name; } + + int BuildTime(ActorInfo info, string queue) + { + var bi = info.TraitInfoOrDefault(); + + if (bi == null) + return 0; + + var time = bi.BuildDuration; + if (time == -1) + { + var valued = info.TraitInfoOrDefault(); + if (valued == null) + return 0; + else + time = valued.Cost; + } + + int pbi; + if (queue != null) + { + var pqueue = modData.DefaultRules.Actors.Values.SelectMany(a => a.TraitInfos() + .Where(x => x.Type == queue)).FirstOrDefault(); + + pbi = pqueue?.BuildDurationModifier ?? 100; + } + else + { + var pqueue = modData.DefaultRules.Actors.Values.SelectMany(a => a.TraitInfos() + .Where(x => bi.Queue.Contains(x.Type))).FirstOrDefault(); + + pbi = pqueue?.BuildDurationModifier ?? 100; + } + + time = time * bi.BuildDurationModifier * pbi / 10000; + return time; + } } } diff --git a/mods/common/fluent/common.ftl b/mods/common/fluent/common.ftl index 60dcc23882..d457497fef 100644 --- a/mods/common/fluent/common.ftl +++ b/mods/common/fluent/common.ftl @@ -551,7 +551,7 @@ label-audio-unmuted = Audio unmuted. label-loading-player-profile = Loading player profile... label-loading-player-profile-failed = Failed to load player profile. -## ProductionTooltipLogic +## ProductionTooltipLogic, EncyclopediaLogic label-requires = Requires { $prerequisites }. ## ReplayBrowserLogic