using System.Linq; using Content.Client.Message; using Content.Client.UserInterface.ControlExtensions; using Content.Shared.Atmos.Prototypes; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Reaction; using Content.Shared.Chemistry.Reagent; using Content.Shared.FixedPoint; using Content.Shared.Localizations; using JetBrains.Annotations; using Robust.Client.AutoGenerated; using Robust.Client.GameObjects; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.XAML; using Robust.Shared.Graphics.RSI; using Robust.Shared.Prototypes; using Robust.Shared.Utility; namespace Content.Client.Guidebook.Controls; [UsedImplicitly, GenerateTypedNameReferences] public sealed partial class GuideReagentReaction : BoxContainer, ISearchableControl { [ValidatePrototypeId] private const string DefaultMixingCategory = "DummyMix"; private readonly IPrototypeManager _protoMan; public GuideReagentReaction(IPrototypeManager protoMan) { RobustXamlLoader.Load(this); _protoMan = protoMan; } public GuideReagentReaction(ReactionPrototype prototype, IPrototypeManager protoMan, IEntitySystemManager sysMan) : this(protoMan) { Container container = ReactantsContainer; SetReagents(prototype.Reactants, ref container, protoMan); Container productContainer = ProductsContainer; var products = new Dictionary(prototype.Products); foreach (var (reagent, reactantProto) in prototype.Reactants) { if (reactantProto.Catalyst) products.Add(reagent, reactantProto.Amount); } SetReagents(products, ref productContainer, protoMan, false); var mixingCategories = new List(); if (prototype.MixingCategories != null) { foreach (var category in prototype.MixingCategories) { mixingCategories.Add(protoMan.Index(category)); } } else { mixingCategories.Add(protoMan.Index(DefaultMixingCategory)); } SetMixingCategory(mixingCategories, prototype, sysMan); } public GuideReagentReaction(EntityPrototype prototype, Solution solution, IReadOnlyList> categories, IPrototypeManager protoMan, IEntitySystemManager sysMan) : this(protoMan) { var icon = sysMan.GetEntitySystem().GetPrototypeIcon(prototype).GetFrame(RsiDirection.South, 0); var entContainer = new BoxContainer { Orientation = LayoutOrientation.Horizontal, HorizontalExpand = true, HorizontalAlignment = HAlignment.Center, Children = { new TextureRect { Texture = icon } } }; var nameLabel = new RichTextLabel(); nameLabel.SetMarkup(Loc.GetString("guidebook-reagent-sources-ent-wrapper", ("name", prototype.Name))); entContainer.AddChild(nameLabel); ReactantsContainer.AddChild(entContainer); Container productContainer = ProductsContainer; SetReagents(solution.Contents, ref productContainer, protoMan, false); SetMixingCategory(categories, null, sysMan); } public GuideReagentReaction(GasPrototype prototype, IReadOnlyList> categories, IPrototypeManager protoMan, IEntitySystemManager sysMan) : this(protoMan) { var label = new RichTextLabel(); label.SetMarkup(Loc.GetString("guidebook-reagent-sources-gas-wrapper", ("name", Loc.GetString(prototype.Name).ToLower()))); ReactantsContainer.Visible = true; ReactantsContainer.AddChild(label); if (prototype.Reagent != null) { var quantity = new Dictionary { { prototype.Reagent, FixedPoint2.New(0.21f) } }; Container productContainer = ProductsContainer; SetReagents(quantity, ref productContainer, protoMan, false); } SetMixingCategory(categories, null, sysMan); } private void SetReagents(List reagents, ref Container container, IPrototypeManager protoMan, bool addLinks = true) { var amounts = new Dictionary(); foreach (var (reagent, quantity) in reagents) { amounts.Add(reagent.Prototype, quantity); } SetReagents(amounts, ref container, protoMan, addLinks); } private void SetReagents( Dictionary reactants, ref Container container, IPrototypeManager protoMan, bool addLinks = true) { var amounts = new Dictionary(); foreach (var (reagent, reactantPrototype) in reactants) { amounts.Add(reagent, reactantPrototype.Amount); } SetReagents(amounts, ref container, protoMan, addLinks); } [PublicAPI] private void SetReagents( Dictionary, ReactantPrototype> reactants, ref Container container, IPrototypeManager protoMan, bool addLinks = true) { var amounts = new Dictionary(); foreach (var (reagent, reactantPrototype) in reactants) { amounts.Add(reagent, reactantPrototype.Amount); } SetReagents(amounts, ref container, protoMan, addLinks); } private void SetReagents(Dictionary reagents, ref Container container, IPrototypeManager protoMan, bool addLinks = true) { foreach (var (product, amount) in reagents.OrderByDescending(p => p.Value)) { var productProto = protoMan.Index(product); var msg = new FormattedMessage(); msg.AddMarkupOrThrow(Loc.GetString("guidebook-reagent-recipes-reagent-display", ("reagent", productProto.LocalizedName), ("ratio", amount))); var label = new GuidebookRichPrototypeLink(); if (addLinks) label.LinkedPrototype = productProto; label.SetMessage(msg); container.AddChild(label); } container.Visible = true; } private void SetMixingCategory(IReadOnlyList> mixingCategories, ReactionPrototype? prototype, IEntitySystemManager sysMan) { var foo = new List(); foreach (var cat in mixingCategories) { foo.Add(_protoMan.Index(cat)); } SetMixingCategory(foo, prototype, sysMan); } private void SetMixingCategory(IReadOnlyList mixingCategories, ReactionPrototype? prototype, IEntitySystemManager sysMan) { if (mixingCategories.Count == 0) return; // only use the first one for the icon. if (mixingCategories.First() is { } primaryCategory) { MixTexture.Texture = sysMan.GetEntitySystem().Frame0(primaryCategory.Icon); } var mixingVerb = ContentLocalizationManager.FormatList(mixingCategories .Select(p => Loc.GetString(p.VerbText)).ToList()); var minTemp = prototype?.MinimumTemperature ?? 0; var maxTemp = prototype?.MaximumTemperature ?? float.PositiveInfinity; var text = Loc.GetString("guidebook-reagent-recipes-mix-info", ("verb", mixingVerb), ("minTemp", minTemp), ("maxTemp", maxTemp), ("hasMax", !float.IsPositiveInfinity(maxTemp))); MixLabel.SetMarkup(text); } public bool CheckMatchesSearch(string query) { return this.ChildrenContainText(query); } public void SetHiddenState(bool state, string query) { Visible = CheckMatchesSearch(query) ? state : !state; } }