From efb3bca1c55ff815028300d9e506d0cfc3f07850 Mon Sep 17 00:00:00 2001 From: Whatstone <166147148+whatston3@users.noreply.github.com> Date: Sat, 26 Oct 2024 17:37:43 -0400 Subject: [PATCH] Medical recipe guidebook entries (#2331) --- .../Controls/GuideMedicalComposition.xaml | 21 ++ .../Controls/GuideMedicalComposition.xaml.cs | 32 +++ .../Controls/GuideMedicalDamage.xaml | 21 ++ .../Controls/GuideMedicalDamage.xaml.cs | 40 ++++ .../Guidebook/Controls/GuideMedicalEmbed.xaml | 53 +++++ .../Controls/GuideMedicalEmbed.xaml.cs | 188 ++++++++++++++++++ .../Controls/GuideMedicalGroupEmbed.xaml | 4 + .../Controls/GuideMedicalGroupEmbed.xaml.cs | 36 ++++ .../Controls/GuideMedicalSource.xaml | 36 ++++ .../Controls/GuideMedicalSource.xaml.cs | 96 +++++++++ .../EntitySystems/MedicalGuideDataSystem.cs | 30 +++ .../EntitySystems/MedicalRecipeDataSystem.cs | 88 ++++++++ .../Medical/SharedMedicalGuideDataSystem.cs | 81 ++++++++ .../Locale/en-US/_NF/guidebook/guides.ftl | 3 + .../Locale/en-US/_NF/guidebook/medical.ftl | 4 + Resources/Prototypes/Guidebook/references.yml | 3 +- .../Prototypes/_NF/Guidebook/references.yml | 5 + .../_EE/Guidebook/Service/FoodRecipes.xml | 2 +- .../_NF/Guidebook/Medical/MedicalRecipes.xml | 8 + 19 files changed, 748 insertions(+), 3 deletions(-) create mode 100644 Content.Client/_NF/Guidebook/Controls/GuideMedicalComposition.xaml create mode 100644 Content.Client/_NF/Guidebook/Controls/GuideMedicalComposition.xaml.cs create mode 100644 Content.Client/_NF/Guidebook/Controls/GuideMedicalDamage.xaml create mode 100644 Content.Client/_NF/Guidebook/Controls/GuideMedicalDamage.xaml.cs create mode 100644 Content.Client/_NF/Guidebook/Controls/GuideMedicalEmbed.xaml create mode 100644 Content.Client/_NF/Guidebook/Controls/GuideMedicalEmbed.xaml.cs create mode 100644 Content.Client/_NF/Guidebook/Controls/GuideMedicalGroupEmbed.xaml create mode 100644 Content.Client/_NF/Guidebook/Controls/GuideMedicalGroupEmbed.xaml.cs create mode 100644 Content.Client/_NF/Guidebook/Controls/GuideMedicalSource.xaml create mode 100644 Content.Client/_NF/Guidebook/Controls/GuideMedicalSource.xaml.cs create mode 100644 Content.Client/_NF/Medical/EntitySystems/MedicalGuideDataSystem.cs create mode 100644 Content.Server/_NF/Medical/EntitySystems/MedicalRecipeDataSystem.cs create mode 100644 Content.Shared/_NF/Medical/SharedMedicalGuideDataSystem.cs create mode 100644 Resources/Locale/en-US/_NF/guidebook/medical.ftl create mode 100644 Resources/Prototypes/_NF/Guidebook/references.yml create mode 100644 Resources/ServerInfo/_NF/Guidebook/Medical/MedicalRecipes.xml diff --git a/Content.Client/_NF/Guidebook/Controls/GuideMedicalComposition.xaml b/Content.Client/_NF/Guidebook/Controls/GuideMedicalComposition.xaml new file mode 100644 index 00000000000..87b755d6f1a --- /dev/null +++ b/Content.Client/_NF/Guidebook/Controls/GuideMedicalComposition.xaml @@ -0,0 +1,21 @@ + + + + + + diff --git a/Content.Client/_NF/Guidebook/Controls/GuideMedicalComposition.xaml.cs b/Content.Client/_NF/Guidebook/Controls/GuideMedicalComposition.xaml.cs new file mode 100644 index 00000000000..fd44847e355 --- /dev/null +++ b/Content.Client/_NF/Guidebook/Controls/GuideMedicalComposition.xaml.cs @@ -0,0 +1,32 @@ +using Content.Client.Guidebook.Controls; +using Content.Client.UserInterface.ControlExtensions; +using Content.Shared.Chemistry.Reagent; +using Content.Shared.FixedPoint; +using JetBrains.Annotations; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client._NF.Guidebook.Controls; // Frontier: add _EE + +[UsedImplicitly, GenerateTypedNameReferences] +public sealed partial class GuideMedicalComposition : BoxContainer, ISearchableControl +{ + public GuideMedicalComposition(ReagentPrototype proto, FixedPoint2 quantity) + { + RobustXamlLoader.Load(this); + + ReagentLabel.Text = proto.LocalizedName; + AmountLabel.Text = quantity.ToString(); + } + + public bool CheckMatchesSearch(string query) + { + return this.ChildrenContainText(query); + } + + public void SetHiddenState(bool state, string query) + { + Visible = CheckMatchesSearch(query) ? state : !state; + } +} diff --git a/Content.Client/_NF/Guidebook/Controls/GuideMedicalDamage.xaml b/Content.Client/_NF/Guidebook/Controls/GuideMedicalDamage.xaml new file mode 100644 index 00000000000..d8ef86c56e1 --- /dev/null +++ b/Content.Client/_NF/Guidebook/Controls/GuideMedicalDamage.xaml @@ -0,0 +1,21 @@ + + + + + + + + diff --git a/Content.Client/_NF/Guidebook/Controls/GuideMedicalDamage.xaml.cs b/Content.Client/_NF/Guidebook/Controls/GuideMedicalDamage.xaml.cs new file mode 100644 index 00000000000..8f8dcefa64a --- /dev/null +++ b/Content.Client/_NF/Guidebook/Controls/GuideMedicalDamage.xaml.cs @@ -0,0 +1,40 @@ +using Content.Client.Guidebook.Controls; +using Content.Client.UserInterface.ControlExtensions; +using Content.Shared.Damage.Prototypes; +using Content.Shared.FixedPoint; +using JetBrains.Annotations; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client._NF.Guidebook.Controls; + +[UsedImplicitly, GenerateTypedNameReferences] +public sealed partial class GuideMedicalDamage : BoxContainer, ISearchableControl +{ + public GuideMedicalDamage(DamageTypePrototype proto, FixedPoint2 quantity) + { + RobustXamlLoader.Load(this); + + DamageLabel.Text = proto.LocalizedName; + AmountLabel.Text = quantity.ToString(); + } + + public GuideMedicalDamage(DamageGroupPrototype proto, FixedPoint2 quantity) + { + RobustXamlLoader.Load(this); + + DamageLabel.Text = Loc.GetString("guidebook-medical-damage-group", ("name", proto.LocalizedName)); + AmountLabel.Text = quantity.ToString(); + } + + public bool CheckMatchesSearch(string query) + { + return this.ChildrenContainText(query); + } + + public void SetHiddenState(bool state, string query) + { + Visible = CheckMatchesSearch(query) ? state : !state; + } +} diff --git a/Content.Client/_NF/Guidebook/Controls/GuideMedicalEmbed.xaml b/Content.Client/_NF/Guidebook/Controls/GuideMedicalEmbed.xaml new file mode 100644 index 00000000000..a6f64498269 --- /dev/null +++ b/Content.Client/_NF/Guidebook/Controls/GuideMedicalEmbed.xaml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Content.Client/_NF/Guidebook/Controls/GuideMedicalEmbed.xaml.cs b/Content.Client/_NF/Guidebook/Controls/GuideMedicalEmbed.xaml.cs new file mode 100644 index 00000000000..2016deb4200 --- /dev/null +++ b/Content.Client/_NF/Guidebook/Controls/GuideMedicalEmbed.xaml.cs @@ -0,0 +1,188 @@ +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Content.Client._NF.Medical.EntitySystems; +using Content.Client.Chemistry.EntitySystems; +using Content.Client.Guidebook.Controls; +using Content.Client.Guidebook.Richtext; +using Content.Client.Message; +using Content.Shared.Chemistry.Reagent; +using Content.Shared.Damage.Prototypes; +using Content.Shared.FixedPoint; +using JetBrains.Annotations; +using Robust.Client.AutoGenerated; +using Robust.Client.Graphics; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.Prototypes; +using Robust.Shared.Utility; + +namespace Content.Client._NF.Guidebook.Controls; + +/// +/// Control for embedding a medical recipe into a guidebook. +/// +[UsedImplicitly, GenerateTypedNameReferences] +public sealed partial class GuideMedicalEmbed : BoxContainer, IDocumentTag, ISearchableControl +{ + [Dependency] private readonly IEntitySystemManager _systemManager = default!; + [Dependency] private readonly IPrototypeManager _prototype = default!; + + private readonly MedicalGuideDataSystem _medicalGuideData; + private readonly ISawmill _logger = default!; + + public GuideMedicalEmbed() + { + RobustXamlLoader.Load(this); + IoCManager.InjectDependencies(this); + _medicalGuideData = _systemManager.GetEntitySystem(); + _logger = Logger.GetSawmill("medical guide"); + MouseFilter = MouseFilterMode.Stop; + } + + public GuideMedicalEmbed(MedicalGuideEntry entry) : this() + { + GenerateControl(entry); + } + + public bool CheckMatchesSearch(string query) + { + return ResultName.GetMessage()?.Contains(query, StringComparison.InvariantCultureIgnoreCase) == true + || Description.GetMessage()?.Contains(query, StringComparison.InvariantCultureIgnoreCase) == true; + } + + public void SetHiddenState(bool state, string query) + { + Visible = CheckMatchesSearch(query) ? state : !state; + } + + public bool TryParseTag(Dictionary args, [NotNullWhen(true)] out Control? control) + { + control = null; + if (!args.TryGetValue("Result", out var id)) + { + _logger.Error("Result embed tag is missing food prototype argument."); + return false; + } + + if (!_medicalGuideData.TryGetData(id, out var data)) + { + _logger.Warning($"Specified result prototype \"{id}\" does not have any known sources."); + return false; + } + + GenerateControl(data); + + control = this; + return true; + } + + private void GenerateControl(MedicalGuideEntry data) + { + _prototype.TryIndex(data.Result, out var proto); + if (proto == null) + { + ResultName.SetMarkup(Loc.GetString("guidebook-food-unknown-proto", ("id", data.Result))); + return; + } + + var composition = data.Composition + .Select(it => _prototype.TryIndex(it.Reagent.Prototype, out var reagent) ? (reagent, it.Quantity) : (null, 0)) + .Where(it => it.reagent is not null) + .Cast<(ReagentPrototype, FixedPoint2)>() + .ToList(); + + #region Colors + + CalculateColors(composition, out var textColor, out var backgroundColor); + + NameBackground.PanelOverride = new StyleBoxFlat + { + BackgroundColor = backgroundColor + }; + ResultName.SetMarkup(Loc.GetString("guidebook-food-name", ("color", textColor), ("name", proto.Name))); + + #endregion + + #region Recipes + if (data.Recipes.Length > 0) + RecipesContainer.Visible = true; + + foreach (var recipe in data.Recipes.OrderBy(it => it.OutputCount)) + { + var control = new GuideMedicalSource(proto, recipe, _prototype); + RecipesDescriptionContainer.AddChild(control); + } + + #endregion + + #region Composition + if (composition.Count > 0) + CompositionContainer.Visible = true; + + foreach (var (reagent, quantity) in composition) + { + var control = new GuideMedicalComposition(reagent, quantity); + CompositionDescriptionContainer.AddChild(control); + } + + #endregion + + #region Damage + var damageDict = data.Healing?.DamageDict ?? new(); + if (damageDict.Count > 0) + DamageContainer.Visible = true; + + foreach (var (damageType, damage) in damageDict) + { + if (_prototype.TryIndex(damageType, out var damageProto)) + { + var control = new GuideMedicalDamage(damageProto, -damage); // Negative damage means positive healing + DamageDescriptionContainer.AddChild(control); + } + else if (_prototype.TryIndex(damageType, out var groupProto)) + { + var control = new GuideMedicalDamage(groupProto, -damage); // Negative damage means positive healing + DamageDescriptionContainer.AddChild(control); + } + } + + #endregion + + FormattedMessage description = new(); + description.AddText(proto?.Description ?? string.Empty); + // Cannot describe food flavor or smth beause food is entirely server-side + + Description.SetMessage(description); + } + + private void CalculateColors(List<(ReagentPrototype, FixedPoint2)> composition, out Color text, out Color background) + { + // Background color is calculated as the weighted average of the colors of the composition. + // Text color is determined based on background luminosity. + float r = 0, g = 0, b = 0; + FixedPoint2 weight = 0; + + foreach (var (proto, quantity) in composition) + { + var tcolor = proto.SubstanceColor; + var prevalence = + quantity <= 0 ? 0f + : weight == 0f ? 1f + : (quantity / (weight + quantity)).Float(); + + r = r * (1 - prevalence) + tcolor.R * prevalence; + g = g * (1 - prevalence) + tcolor.G * prevalence; + b = b * (1 - prevalence) + tcolor.B * prevalence; + + if (quantity > 0) + weight += quantity; + } + + // Copied from GuideReagentEmbed which was probably copied from stackoverflow. This is the formula for color luminosity. + var lum = 0.2126f * r + 0.7152f * g + 0.0722f; + + background = new Color(r, g, b); + text = lum > 0.5f ? Color.Black : Color.White; + } +} diff --git a/Content.Client/_NF/Guidebook/Controls/GuideMedicalGroupEmbed.xaml b/Content.Client/_NF/Guidebook/Controls/GuideMedicalGroupEmbed.xaml new file mode 100644 index 00000000000..6551f2cf18c --- /dev/null +++ b/Content.Client/_NF/Guidebook/Controls/GuideMedicalGroupEmbed.xaml @@ -0,0 +1,4 @@ + + + diff --git a/Content.Client/_NF/Guidebook/Controls/GuideMedicalGroupEmbed.xaml.cs b/Content.Client/_NF/Guidebook/Controls/GuideMedicalGroupEmbed.xaml.cs new file mode 100644 index 00000000000..134e51ff544 --- /dev/null +++ b/Content.Client/_NF/Guidebook/Controls/GuideMedicalGroupEmbed.xaml.cs @@ -0,0 +1,36 @@ +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Content.Client._NF.Medical.EntitySystems; +using Content.Client.Guidebook.Richtext; +using JetBrains.Annotations; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client._NF.Guidebook.Controls; + +[UsedImplicitly, GenerateTypedNameReferences] +public sealed partial class GuideMedicalGroupEmbed : BoxContainer, IDocumentTag +{ + [Dependency] private readonly IEntitySystemManager _sysMan = default!; + + public GuideMedicalGroupEmbed() + { + RobustXamlLoader.Load(this); + IoCManager.InjectDependencies(this); + MouseFilter = MouseFilterMode.Stop; + + foreach (var data in _sysMan.GetEntitySystem().Registry.OrderBy(it => it.Identifier)) + { + var embed = new GuideMedicalEmbed(data); + GroupContainer.AddChild(embed); + } + } + + public bool TryParseTag(Dictionary args, [NotNullWhen(true)] out Control? control) + { + control = this; + return true; + } +} diff --git a/Content.Client/_NF/Guidebook/Controls/GuideMedicalSource.xaml b/Content.Client/_NF/Guidebook/Controls/GuideMedicalSource.xaml new file mode 100644 index 00000000000..4527225ee4c --- /dev/null +++ b/Content.Client/_NF/Guidebook/Controls/GuideMedicalSource.xaml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + diff --git a/Content.Client/_NF/Guidebook/Controls/GuideMedicalSource.xaml.cs b/Content.Client/_NF/Guidebook/Controls/GuideMedicalSource.xaml.cs new file mode 100644 index 00000000000..eb8954af8b5 --- /dev/null +++ b/Content.Client/_NF/Guidebook/Controls/GuideMedicalSource.xaml.cs @@ -0,0 +1,96 @@ +using System.Linq; +using Content.Client.Chemistry.EntitySystems; +using Content.Client.Guidebook.Controls; +using Content.Client.UserInterface.ControlExtensions; +using Content.Shared.Chemistry.Reagent; +using Content.Shared.FixedPoint; +using Content.Shared.Kitchen; +using JetBrains.Annotations; +using Robust.Client.AutoGenerated; +using Robust.Client.GameObjects; +using Robust.Client.Graphics; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.Prototypes; +using Robust.Shared.Utility; + +namespace Content.Client._NF.Guidebook.Controls; + +[UsedImplicitly, GenerateTypedNameReferences] +public sealed partial class GuideMedicalSource : BoxContainer, ISearchableControl +{ + private readonly IPrototypeManager _protoMan; + private readonly SpriteSystem _sprites = default!; + + public GuideMedicalSource(IPrototypeManager protoMan) + { + RobustXamlLoader.Load(this); + _protoMan = protoMan; + _sprites = IoCManager.Resolve().GetEntitySystem(); + } + + public GuideMedicalSource(EntityPrototype result, MedicalRecipeData entry, IPrototypeManager protoMan) : this(protoMan) + { + GenerateControl(entry); + + GenerateOutputs(result, entry); + } + + private void GenerateControl(MedicalRecipeData entry) + { + if (!_protoMan.TryIndex(entry.Recipe, out var recipe)) + { + SourceLabel.Text = Loc.GetString("guidebook-food-unknown-proto", ("id", entry.Result)); // Frontier: SetMessage _protoMan.TryIndex(it.Key, out var proto) ? FormatIngredient(proto, it.Value) : "") + .Where(it => it.Length > 0); + var combinedLiquids = recipe.IngredientsReagents + .Select(it => _protoMan.TryIndex(it.Key, out var proto) ? FormatIngredient(proto, it.Value) : "") + .Where(it => it.Length > 0); + + var combinedIngredients = string.Join("\n", combinedLiquids.Union(combinedSolids)); + SourceLabel.Text = Loc.GetString("guidebook-food-processing-recipe", ("ingredients", combinedIngredients)); // Frontier: SetMessage(OnReceiveRegistryUpdate); + } + + private void OnReceiveRegistryUpdate(MedicalGuideRegistryChangedEvent message) + { + Registry = message.Changeset; + } + + public bool TryGetData(EntProtoId result, out MedicalGuideEntry entry) + { + var index = Registry.FindIndex(it => it.Result == result); + if (index == -1) + { + entry = default; + return false; + } + + entry = Registry[index]; + return true; + } +} diff --git a/Content.Server/_NF/Medical/EntitySystems/MedicalRecipeDataSystem.cs b/Content.Server/_NF/Medical/EntitySystems/MedicalRecipeDataSystem.cs new file mode 100644 index 00000000000..36c420c2403 --- /dev/null +++ b/Content.Server/_NF/Medical/EntitySystems/MedicalRecipeDataSystem.cs @@ -0,0 +1,88 @@ +using System.Linq; +using Content.Client.Chemistry.EntitySystems; +using Content.Server.Medical.Components; +using Content.Shared.Chemistry.Components.SolutionManager; +using Content.Shared.Chemistry.Reagent; +using Content.Shared.Damage; +using Content.Shared.Kitchen; +using Robust.Server.Player; +using Robust.Shared.Enums; +using Robust.Shared.Player; +using Robust.Shared.Prototypes; +using Robust.Shared.Utility; + +namespace Content.Server._NF.Medical.EntitySystems; + +public sealed class MedicalRecipeDataSystem : SharedMedicalGuideDataSystem +{ + [Dependency] private readonly IPlayerManager _player = default!; + [Dependency] private readonly IPrototypeManager _protoMan = default!; + [Dependency] private readonly IComponentFactory _componentFactory = default!; + + private Dictionary> _sources = new(); + + public override void Initialize() + { + SubscribeLocalEvent(OnPrototypesReloaded); + _player.PlayerStatusChanged += OnPlayerStatusChanged; + + ReloadRecipes(); + } + + private void OnPrototypesReloaded(PrototypesReloadedEventArgs args) + { + if (!args.WasModified() + && !args.WasModified() + ) + return; + + ReloadRecipes(); + } + + public void ReloadRecipes() + { + // TODO: add this code to the list of known recipes because this is spaghetti + _sources.Clear(); + + // Recipes + foreach (var recipe in _protoMan.EnumeratePrototypes()) + { + MicrowaveRecipeType recipeType = (MicrowaveRecipeType)recipe.RecipeType; + if (recipeType.HasFlag(MicrowaveRecipeType.MedicalAssembler)) + { + _sources.GetOrNew(recipe.Result).Add(new MedicalRecipeData(recipe)); + } + } + + Registry.Clear(); + + foreach (var (result, sources) in _sources) + { + var proto = _protoMan.Index(result); + ReagentQuantity[] reagents = []; + // Hack: assume + if (proto.TryGetComponent(out var manager, _componentFactory)) + reagents = manager?.Solutions?.FirstOrNull()?.Value?.Contents?.ToArray() ?? []; + + DamageSpecifier? damage = null; + if (proto.TryGetComponent(out var healing, _componentFactory)) + damage = healing.Damage; + + // Limit the number of sources to 10 - shouldn't be an issue for medical recipes, but just in case. + var distinctSources = sources.DistinctBy(it => it.Identitier).Take(10); + + var entry = new MedicalGuideEntry(result, proto.Name, distinctSources.ToArray(), reagents, damage); + Registry.Add(entry); + } + + RaiseNetworkEvent(new MedicalGuideRegistryChangedEvent(Registry)); + } + + private void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs args) + { + if (args.NewStatus != SessionStatus.Connected) + return; + + RaiseNetworkEvent(new MedicalGuideRegistryChangedEvent(Registry), args.Session); + } +} diff --git a/Content.Shared/_NF/Medical/SharedMedicalGuideDataSystem.cs b/Content.Shared/_NF/Medical/SharedMedicalGuideDataSystem.cs new file mode 100644 index 00000000000..adefdf8f7bb --- /dev/null +++ b/Content.Shared/_NF/Medical/SharedMedicalGuideDataSystem.cs @@ -0,0 +1,81 @@ +using Content.Shared.Chemistry.Reagent; +using Content.Shared.Damage; +using Content.Shared.Kitchen; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; + +namespace Content.Client.Chemistry.EntitySystems; + +// A clone of the FoodGuideDataSystem. Thank you to Mnemotechnician for the original implementation. +// Redundancy. +public abstract class SharedMedicalGuideDataSystem : EntitySystem +{ + public List Registry = new(); +} + +[Serializable, NetSerializable] +public sealed class MedicalGuideRegistryChangedEvent : EntityEventArgs +{ + [DataField] + public List Changeset; + + public MedicalGuideRegistryChangedEvent(List changeset) + { + Changeset = changeset; + } +} + +[DataDefinition, Serializable, NetSerializable] +public partial struct MedicalGuideEntry +{ + [DataField] + public EntProtoId Result; + + [DataField] + public string Identifier; // Used for sorting + + [DataField] + public MedicalRecipeData[] Recipes; + + [DataField] + public ReagentQuantity[] Composition; + + [DataField] + public DamageSpecifier? Healing; + + public MedicalGuideEntry(EntProtoId result, string identifier, MedicalRecipeData[] recipes, ReagentQuantity[] composition, DamageSpecifier? healing) + { + Result = result; + Identifier = identifier; + Recipes = recipes; + Composition = composition; + Healing = healing; + } +} + +[Serializable, NetSerializable] +public sealed partial class MedicalRecipeData +{ + [DataField] + public ProtoId Recipe; + + [DataField] + public EntProtoId Result; + + [DataField] + private int _outputCount; + public int OutputCount => _outputCount; + + /// + /// A string used to distinguish different sources. Typically the name of the related entity. + /// + public string Identitier; + + public MedicalRecipeData(FoodRecipePrototype proto) + { + Identitier = proto.Name; + Recipe = proto.ID; + Result = proto.Result; + _outputCount = proto.ResultCount; + } +} diff --git a/Resources/Locale/en-US/_NF/guidebook/guides.ftl b/Resources/Locale/en-US/_NF/guidebook/guides.ftl index c538a8dcaf0..9d887b492ae 100644 --- a/Resources/Locale/en-US/_NF/guidebook/guides.ftl +++ b/Resources/Locale/en-US/_NF/guidebook/guides.ftl @@ -10,6 +10,9 @@ guide-entry-frontier-rules = Server Rules # Security entries guide-entry-nfsd-smuggling = Smuggling +# Reference entries +guide-entry-medicalrecipes = Medical Recipes + # Expedition faction entries guide-entry-expedition-aberrant-flesh = Aberrant Flesh guide-entry-expedition-argocytes = Argocytes diff --git a/Resources/Locale/en-US/_NF/guidebook/medical.ftl b/Resources/Locale/en-US/_NF/guidebook/medical.ftl new file mode 100644 index 00000000000..ed5ebf4a937 --- /dev/null +++ b/Resources/Locale/en-US/_NF/guidebook/medical.ftl @@ -0,0 +1,4 @@ +guidebook-medical-reagents-header = Active Components +guidebook-medical-damage-header = Healing + +guidebook-medical-damage-group = [color=gold]{$name}[/color] \ No newline at end of file diff --git a/Resources/Prototypes/Guidebook/references.yml b/Resources/Prototypes/Guidebook/references.yml index c0f9cc01ff2..23870676c56 100644 --- a/Resources/Prototypes/Guidebook/references.yml +++ b/Resources/Prototypes/Guidebook/references.yml @@ -7,6 +7,7 @@ - Drinks - FoodRecipes - Writing + - MedicalRecipes # Frontier - type: guideEntry id: Drinks @@ -24,5 +25,3 @@ id: Writing name: guide-entry-writing text: "/ServerInfo/Guidebook/Writing.xml" - - diff --git a/Resources/Prototypes/_NF/Guidebook/references.yml b/Resources/Prototypes/_NF/Guidebook/references.yml new file mode 100644 index 00000000000..2827b8ab0bc --- /dev/null +++ b/Resources/Prototypes/_NF/Guidebook/references.yml @@ -0,0 +1,5 @@ +- type: guideEntry + id: MedicalRecipes + name: guide-entry-medicalrecipes + text: "/ServerInfo/_NF/Guidebook/Medical/MedicalRecipes.xml" + filterEnabled: True \ No newline at end of file diff --git a/Resources/ServerInfo/_EE/Guidebook/Service/FoodRecipes.xml b/Resources/ServerInfo/_EE/Guidebook/Service/FoodRecipes.xml index c74b947dbf6..f6a933765df 100644 --- a/Resources/ServerInfo/_EE/Guidebook/Service/FoodRecipes.xml +++ b/Resources/ServerInfo/_EE/Guidebook/Service/FoodRecipes.xml @@ -1,5 +1,5 @@ -## Recipe list +## Recipe List Note: Only solid foods are listed here! To learn recipes for liquid ingredients, check the chemistry guidebook. This list is auto-generated and contains all known foods. diff --git a/Resources/ServerInfo/_NF/Guidebook/Medical/MedicalRecipes.xml b/Resources/ServerInfo/_NF/Guidebook/Medical/MedicalRecipes.xml new file mode 100644 index 00000000000..37fbe1f45d7 --- /dev/null +++ b/Resources/ServerInfo/_NF/Guidebook/Medical/MedicalRecipes.xml @@ -0,0 +1,8 @@ + +## Medical Recipe List + +This list is auto-generated and contains all known recipes for the medical assembler. + + + +