From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com>
Date: Sun, 31 Dec 2023 07:34:59 +0000 (-0500)
Subject: Add reagent sources to the guidebook (#22627)
X-Git-Url: https://git.smokeofanarchy.ru/gitweb.cgi?a=commitdiff_plain;h=f538a2e34a4b62ac406a5871a3c52e51f8f0fad4;p=space-station-14.git
Add reagent sources to the guidebook (#22627)
* source in my guidebook
* finish it!
* sir yes sir oorah
* network that bitch, baby
---
diff --git a/Content.Client/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs b/Content.Client/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs
index 736e22f834..4a9bd60dcb 100644
--- a/Content.Client/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs
+++ b/Content.Client/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs
@@ -1,16 +1,39 @@
-using Content.Shared.Chemistry;
+using System.Linq;
+using Content.Shared.Atmos.Prototypes;
+using Content.Shared.Body.Part;
+using Content.Shared.Chemistry;
+using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.Components.SolutionManager;
+using Content.Shared.Chemistry.Reaction;
+using Content.Shared.Chemistry.Reagent;
+using Content.Shared.Kitchen.Components;
+using Content.Shared.Prototypes;
+using Robust.Shared.Prototypes;
namespace Content.Client.Chemistry.EntitySystems;
///
public sealed class ChemistryGuideDataSystem : SharedChemistryGuideDataSystem
{
+ [ValidatePrototypeId]
+ private const string DefaultMixingCategory = "DummyMix";
+ [ValidatePrototypeId]
+ private const string DefaultGrindCategory = "DummyGrind";
+ [ValidatePrototypeId]
+ private const string DefaultJuiceCategory = "DummyJuice";
+ [ValidatePrototypeId]
+ private const string DefaultCondenseCategory = "DummyCondense";
+
+ private readonly Dictionary> _reagentSources = new();
+
///
public override void Initialize()
{
base.Initialize();
SubscribeNetworkEvent(OnReceiveRegistryUpdate);
+ SubscribeLocalEvent(OnPrototypesReloaded);
+ OnPrototypesReloaded(null);
}
private void OnReceiveRegistryUpdate(ReagentGuideRegistryChangedEvent message)
@@ -26,4 +49,176 @@ public sealed class ChemistryGuideDataSystem : SharedChemistryGuideDataSystem
Registry[key] = val;
}
}
+
+ private void OnPrototypesReloaded(PrototypesReloadedEventArgs? ev)
+ {
+ // this doesn't check what prototypes are being reloaded because, to be frank, we use a lot of them.
+ _reagentSources.Clear();
+ foreach (var reagent in PrototypeManager.EnumeratePrototypes())
+ {
+ _reagentSources.Add(reagent.ID, new());
+ }
+
+ foreach (var reaction in PrototypeManager.EnumeratePrototypes())
+ {
+ if (!reaction.Source)
+ continue;
+
+ var data = new ReagentReactionSourceData(
+ reaction.MixingCategories ?? new () { DefaultMixingCategory },
+ reaction);
+ foreach (var product in reaction.Products.Keys)
+ {
+ _reagentSources[product].Add(data);
+ }
+ }
+
+ foreach (var gas in PrototypeManager.EnumeratePrototypes())
+ {
+ if (gas.Reagent == null)
+ continue;
+
+ var data = new ReagentGasSourceData(
+ new () { DefaultCondenseCategory },
+ gas);
+ _reagentSources[gas.Reagent].Add(data);
+ }
+
+ // store the names of the entities used so we don't get repeats in the guide.
+ var usedNames = new List();
+ foreach (var entProto in PrototypeManager.EnumeratePrototypes())
+ {
+ if (entProto.Abstract || usedNames.Contains(entProto.Name))
+ continue;
+
+ if (!entProto.TryGetComponent(out var extractableComponent))
+ continue;
+
+ //these bloat the hell out of blood/fat
+ if (entProto.HasComponent())
+ continue;
+
+ //these feel obvious...
+ if (entProto.HasComponent())
+ continue;
+
+ if (extractableComponent.JuiceSolution is { } juiceSolution)
+ {
+ var data = new ReagentEntitySourceData(
+ new() { DefaultJuiceCategory },
+ entProto,
+ juiceSolution);
+ foreach (var (id, _) in juiceSolution.Contents)
+ {
+ _reagentSources[id.Prototype].Add(data);
+ }
+
+ usedNames.Add(entProto.Name);
+ }
+
+ if (extractableComponent.GrindableSolution is { } grindableSolutionId &&
+ entProto.TryGetComponent(out var manager) &&
+ manager.Solutions.TryGetValue(grindableSolutionId, out var grindableSolution))
+ {
+ var data = new ReagentEntitySourceData(
+ new() { DefaultGrindCategory },
+ entProto,
+ grindableSolution);
+ foreach (var (id, _) in grindableSolution.Contents)
+ {
+ _reagentSources[id.Prototype].Add(data);
+ }
+ usedNames.Add(entProto.Name);
+ }
+ }
+ }
+
+ public List GetReagentSources(string id)
+ {
+ return _reagentSources.GetValueOrDefault(id) ?? new List();
+ }
}
+
+///
+/// A generic class meant to hold information about a reagent source.
+///
+public abstract class ReagentSourceData
+{
+ ///
+ /// The mixing type that applies to this source.
+ ///
+ public readonly IReadOnlyList> MixingType;
+
+ ///
+ /// The number of distinct outputs. Used for primary ordering.
+ ///
+ public abstract int OutputCount { get; }
+
+ ///
+ /// A text string corresponding to this source. Typically a name. Used for secondary ordering.
+ ///
+ public abstract string IdentifierString { get; }
+
+ protected ReagentSourceData(List> mixingType)
+ {
+ MixingType = mixingType;
+ }
+}
+
+///
+/// Used to store a reagent source that's an entity with a corresponding solution.
+///
+public sealed class ReagentEntitySourceData : ReagentSourceData
+{
+ public readonly EntityPrototype SourceEntProto;
+
+ public readonly Solution Solution;
+
+ public override int OutputCount => Solution.Contents.Count;
+
+ public override string IdentifierString => SourceEntProto.Name;
+
+ public ReagentEntitySourceData(List> mixingType, EntityPrototype sourceEntProto, Solution solution)
+ : base(mixingType)
+ {
+ SourceEntProto = sourceEntProto;
+ Solution = solution;
+ }
+}
+
+///
+/// Used to store a reagent source that comes from a reaction between multiple reagents.
+///
+public sealed class ReagentReactionSourceData : ReagentSourceData
+{
+ public readonly ReactionPrototype ReactionPrototype;
+
+ public override int OutputCount => ReactionPrototype.Products.Count + ReactionPrototype.Reactants.Count(r => r.Value.Catalyst);
+
+ public override string IdentifierString => ReactionPrototype.ID;
+
+ public ReagentReactionSourceData(List> mixingType, ReactionPrototype reactionPrototype)
+ : base(mixingType)
+ {
+ ReactionPrototype = reactionPrototype;
+ }
+}
+
+///
+/// Used to store a reagent source that comes from gas condensation.
+///
+public sealed class ReagentGasSourceData : ReagentSourceData
+{
+ public readonly GasPrototype GasPrototype;
+
+ public override int OutputCount => 1;
+
+ public override string IdentifierString => Loc.GetString(GasPrototype.Name);
+
+ public ReagentGasSourceData(List> mixingType, GasPrototype gasPrototype)
+ : base(mixingType)
+ {
+ GasPrototype = gasPrototype;
+ }
+}
+
diff --git a/Content.Client/Guidebook/Controls/GuideReagentEmbed.xaml b/Content.Client/Guidebook/Controls/GuideReagentEmbed.xaml
index 7b1beeeb65..752c9cc6c2 100644
--- a/Content.Client/Guidebook/Controls/GuideReagentEmbed.xaml
+++ b/Content.Client/Guidebook/Controls/GuideReagentEmbed.xaml
@@ -17,12 +17,25 @@
+
+
+
+
+
+
+
+
diff --git a/Content.Client/Guidebook/Controls/GuideReagentEmbed.xaml.cs b/Content.Client/Guidebook/Controls/GuideReagentEmbed.xaml.cs
index cf5a1b6e59..e2b09386df 100644
--- a/Content.Client/Guidebook/Controls/GuideReagentEmbed.xaml.cs
+++ b/Content.Client/Guidebook/Controls/GuideReagentEmbed.xaml.cs
@@ -6,10 +6,8 @@ using Content.Client.Message;
using Content.Client.UserInterface.ControlExtensions;
using Content.Shared.Chemistry.Reaction;
using Content.Shared.Chemistry.Reagent;
-using Content.Shared.Localizations;
using JetBrains.Annotations;
using Robust.Client.AutoGenerated;
-using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
@@ -99,7 +97,7 @@ public sealed partial class GuideReagentEmbed : BoxContainer, IDocumentTag, ISea
#region Recipe
var reactions = _prototype.EnumeratePrototypes()
- .Where(p => p.Products.ContainsKey(reagent.ID))
+ .Where(p => !p.Source && p.Products.ContainsKey(reagent.ID))
.OrderBy(p => p.Priority)
.ThenBy(p => p.Products.Count)
.ToList();
@@ -108,8 +106,7 @@ public sealed partial class GuideReagentEmbed : BoxContainer, IDocumentTag, ISea
{
foreach (var reactionPrototype in reactions)
{
- var ctrl = GetRecipeGuide(reactionPrototype);
- RecipesDescriptionContainer.AddChild(ctrl);
+ RecipesDescriptionContainer.AddChild(new GuideReagentReaction(reactionPrototype, _prototype, _systemManager));
}
}
else
@@ -159,6 +156,8 @@ public sealed partial class GuideReagentEmbed : BoxContainer, IDocumentTag, ISea
}
#endregion
+ GenerateSources(reagent);
+
FormattedMessage description = new();
description.AddText(reagent.LocalizedDescription);
description.PushNewline();
@@ -167,64 +166,45 @@ public sealed partial class GuideReagentEmbed : BoxContainer, IDocumentTag, ISea
ReagentDescription.SetMessage(description);
}
- private GuideReagentReaction GetRecipeGuide(ReactionPrototype reactionPrototype)
+ private void GenerateSources(ReagentPrototype reagent)
{
- var control = new GuideReagentReaction();
-
- var reactantMsg = new FormattedMessage();
- var reactantsCount = reactionPrototype.Reactants.Count;
- var i = 0;
- foreach (var (product, reactant) in reactionPrototype.Reactants)
- {
- reactantMsg.AddMarkup(Loc.GetString("guidebook-reagent-recipes-reagent-display",
- ("reagent", _prototype.Index(product).LocalizedName), ("ratio", reactant.Amount)));
- i++;
- if (i < reactantsCount)
- reactantMsg.PushNewline();
- }
- reactantMsg.Pop();
- control.ReactantsLabel.SetMessage(reactantMsg);
-
- var productMsg = new FormattedMessage();
- var productCount = reactionPrototype.Products.Count;
- var u = 0;
- foreach (var (product, ratio) in reactionPrototype.Products)
+ var sources = _chemistryGuideData.GetReagentSources(reagent.ID);
+ if (sources.Count == 0)
{
- productMsg.AddMarkup(Loc.GetString("guidebook-reagent-recipes-reagent-display",
- ("reagent", _prototype.Index(product).LocalizedName), ("ratio", ratio)));
- u++;
- if (u < productCount)
- productMsg.PushNewline();
+ SourcesContainer.Visible = false;
+ return;
}
- productMsg.Pop();
- control.ProductsLabel.SetMessage(productMsg);
+ SourcesContainer.Visible = true;
- var mixingCategories = new List();
- if (reactionPrototype.MixingCategories != null)
+ var orderedSources = sources
+ .OrderBy(o => o.OutputCount)
+ .ThenBy(o => o.IdentifierString);
+ foreach (var source in orderedSources)
{
- foreach (var category in reactionPrototype.MixingCategories)
+ if (source is ReagentEntitySourceData entitySourceData)
{
- mixingCategories.Add(_prototype.Index(category));
+ SourcesDescriptionContainer.AddChild(new GuideReagentReaction(
+ entitySourceData.SourceEntProto,
+ entitySourceData.Solution,
+ entitySourceData.MixingType,
+ _prototype,
+ _systemManager));
+ }
+ else if (source is ReagentReactionSourceData reactionSourceData)
+ {
+ SourcesDescriptionContainer.AddChild(new GuideReagentReaction(
+ reactionSourceData.ReactionPrototype,
+ _prototype,
+ _systemManager));
+ }
+ else if (source is ReagentGasSourceData gasSourceData)
+ {
+ SourcesDescriptionContainer.AddChild(new GuideReagentReaction(
+ gasSourceData.GasPrototype,
+ gasSourceData.MixingType,
+ _prototype,
+ _systemManager));
}
}
-
- // only use the first one for the icon.
- if (mixingCategories.FirstOrDefault() is { } primaryCategory)
- {
- control.MixTexture.Texture = _systemManager.GetEntitySystem().Frame0(primaryCategory.Icon);
- }
-
- var mixingVerb = mixingCategories.Count == 0
- ? Loc.GetString("guidebook-reagent-recipes-mix")
- : ContentLocalizationManager.FormatList(mixingCategories.Select(p => Loc.GetString(p.VerbText)).ToList());
-
- var text = Loc.GetString("guidebook-reagent-recipes-mix-info",
- ("verb", mixingVerb),
- ("minTemp", reactionPrototype.MinimumTemperature),
- ("maxTemp", reactionPrototype.MaximumTemperature),
- ("hasMax", !float.IsPositiveInfinity(reactionPrototype.MaximumTemperature)));
-
- control.MixLabel.SetMarkup(text);
- return control;
}
}
diff --git a/Content.Client/Guidebook/Controls/GuideReagentReaction.xaml b/Content.Client/Guidebook/Controls/GuideReagentReaction.xaml
index 69c14a59af..becffbdc6d 100644
--- a/Content.Client/Guidebook/Controls/GuideReagentReaction.xaml
+++ b/Content.Client/Guidebook/Controls/GuideReagentReaction.xaml
@@ -1,12 +1,14 @@

-
+ HorizontalExpand="True"
+ Margin="0 0 0 5">
+
+ Access="Public"
+ Visible="False"/>
+ Access="Public"
+ Visible="False"/>
diff --git a/Content.Client/Guidebook/Controls/GuideReagentReaction.xaml.cs b/Content.Client/Guidebook/Controls/GuideReagentReaction.xaml.cs
index fbc6bf13fc..168f352d1a 100644
--- a/Content.Client/Guidebook/Controls/GuideReagentReaction.xaml.cs
+++ b/Content.Client/Guidebook/Controls/GuideReagentReaction.xaml.cs
@@ -1,13 +1,206 @@
+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)
+ {
+ var reactantsLabel = ReactantsLabel;
+ SetReagents(prototype.Reactants, ref reactantsLabel, protoMan);
+ var productLabel = ProductsLabel;
+ var products = new Dictionary(prototype.Products);
+ foreach (var (reagent, reactantProto) in prototype.Reactants)
+ {
+ if (reactantProto.Catalyst)
+ products.Add(reagent, reactantProto.Amount);
+ }
+ SetReagents(products, ref productLabel, protoMan);
+
+ 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);
+
+ var productLabel = ProductsLabel;
+ SetReagents(solution.Contents, ref productLabel, protoMan);
+ SetMixingCategory(categories, null, sysMan);
+ }
+
+ public GuideReagentReaction(GasPrototype prototype,
+ IReadOnlyList> categories,
+ IPrototypeManager protoMan,
+ IEntitySystemManager sysMan) : this(protoMan)
+ {
+ ReactantsLabel.Visible = true;
+ ReactantsLabel.SetMarkup(Loc.GetString("guidebook-reagent-sources-gas-wrapper",
+ ("name", Loc.GetString(prototype.Name).ToLower())));
+
+ if (prototype.Reagent != null)
+ {
+ var quantity = new Dictionary
+ {
+ { prototype.Reagent, FixedPoint2.New(0.21f) }
+ };
+ var productLabel = ProductsLabel;
+ SetReagents(quantity, ref productLabel, protoMan);
+ }
+ SetMixingCategory(categories, null, sysMan);
+ }
+
+ private void SetReagents(List reagents, ref RichTextLabel label, IPrototypeManager protoMan)
+ {
+ var amounts = new Dictionary();
+ foreach (var (reagent, quantity) in reagents)
+ {
+ amounts.Add(reagent.Prototype, quantity);
+ }
+ SetReagents(amounts, ref label, protoMan);
+ }
+
+ private void SetReagents(
+ Dictionary reactants,
+ ref RichTextLabel label,
+ IPrototypeManager protoMan)
+ {
+ var amounts = new Dictionary();
+ foreach (var (reagent, reactantPrototype) in reactants)
+ {
+ amounts.Add(reagent, reactantPrototype.Amount);
+ }
+ SetReagents(amounts, ref label, protoMan);
+ }
+
+ [PublicAPI]
+ private void SetReagents(
+ Dictionary, ReactantPrototype> reactants,
+ ref RichTextLabel label,
+ IPrototypeManager protoMan)
+ {
+ var amounts = new Dictionary();
+ foreach (var (reagent, reactantPrototype) in reactants)
+ {
+ amounts.Add(reagent, reactantPrototype.Amount);
+ }
+ SetReagents(amounts, ref label, protoMan);
+ }
+
+ private void SetReagents(Dictionary reagents, ref RichTextLabel label, IPrototypeManager protoMan)
+ {
+ var msg = new FormattedMessage();
+ var reagentCount = reagents.Count;
+ var i = 0;
+ foreach (var (product, amount) in reagents.OrderByDescending(p => p.Value))
+ {
+ msg.AddMarkup(Loc.GetString("guidebook-reagent-recipes-reagent-display",
+ ("reagent", protoMan.Index(product).LocalizedName), ("ratio", amount)));
+ i++;
+ if (i < reagentCount)
+ msg.PushNewline();
+ }
+ msg.Pop();
+ label.SetMessage(msg);
+ label.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);
diff --git a/Content.Server/Kitchen/Components/ExtractableComponent.cs b/Content.Server/Kitchen/Components/ExtractableComponent.cs
deleted file mode 100644
index a1949b87b3..0000000000
--- a/Content.Server/Kitchen/Components/ExtractableComponent.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using Content.Server.Kitchen.EntitySystems;
-using Content.Shared.Chemistry.Components;
-
-namespace Content.Server.Kitchen.Components
-{
- ///
- /// Tag component that denotes an entity as Extractable
- ///
- [RegisterComponent]
- [Access(typeof(ReagentGrinderSystem))]
- public sealed partial class ExtractableComponent : Component
- {
- [DataField("juiceSolution")]
- public Solution? JuiceSolution;
-
- [DataField("grindableSolutionName")]
- public string? GrindableSolution;
- }
-}
diff --git a/Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs b/Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs
index cd9a82a072..e4766b4ab9 100644
--- a/Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs
+++ b/Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs
@@ -9,6 +9,7 @@ using Content.Shared.Containers.ItemSlots;
using Content.Shared.FixedPoint;
using Content.Shared.Interaction;
using Content.Shared.Kitchen;
+using Content.Shared.Kitchen.Components;
using Content.Shared.Popups;
using Content.Shared.Random;
using Content.Shared.Stacks;
diff --git a/Content.Shared/Chemistry/Reaction/ReactionPrototype.cs b/Content.Shared/Chemistry/Reaction/ReactionPrototype.cs
index 7541784905..f4e9619b17 100644
--- a/Content.Shared/Chemistry/Reaction/ReactionPrototype.cs
+++ b/Content.Shared/Chemistry/Reaction/ReactionPrototype.cs
@@ -83,6 +83,17 @@ namespace Content.Shared.Chemistry.Reaction
[DataField("priority")]
public int Priority;
+ ///
+ /// Determines whether or not this reaction creates a new chemical (false) or if it's a breakdown for existing chemicals (true)
+ /// Used in the chemistry guidebook to make divisions between recipes and reaction sources.
+ ///
+ ///
+ /// Mixing together two reagents to get a third -> false
+ /// Heating a reagent to break it down into 2 different ones -> true
+ ///
+ [DataField]
+ public bool Source;
+
///
/// Comparison for creating a sorted set of reactions. Determines the order in which reactions occur.
///
diff --git a/Content.Shared/Kitchen/Components/ExtractableComponent.cs b/Content.Shared/Kitchen/Components/ExtractableComponent.cs
new file mode 100644
index 0000000000..bff2166280
--- /dev/null
+++ b/Content.Shared/Kitchen/Components/ExtractableComponent.cs
@@ -0,0 +1,17 @@
+using Content.Shared.Chemistry.Components;
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Kitchen.Components;
+
+///
+/// Tag component that denotes an entity as Extractable
+///
+[RegisterComponent, NetworkedComponent]
+public sealed partial class ExtractableComponent : Component
+{
+ [DataField("juiceSolution")]
+ public Solution? JuiceSolution;
+
+ [DataField("grindableSolutionName")]
+ public string? GrindableSolution;
+};
diff --git a/Resources/Locale/en-US/chemistry/components/mixing-component.ftl b/Resources/Locale/en-US/chemistry/components/mixing-component.ftl
index 1ad9958804..a486ed8ede 100644
--- a/Resources/Locale/en-US/chemistry/components/mixing-component.ftl
+++ b/Resources/Locale/en-US/chemistry/components/mixing-component.ftl
@@ -1,4 +1,8 @@
# Types
+mixing-verb-default-mix = mix
+mixing-verb-default-grind = grind
+mixing-verb-default-juice = juice
+mixing-verb-default-condense = condense
mixing-verb-centrifuge = centrifugation
mixing-verb-electrolysis = electrolyze
mixing-verb-holy = bless
diff --git a/Resources/Locale/en-US/guidebook/chemistry/core.ftl b/Resources/Locale/en-US/guidebook/chemistry/core.ftl
index 7b39a63175..8bb7868184 100644
--- a/Resources/Locale/en-US/guidebook/chemistry/core.ftl
+++ b/Resources/Locale/en-US/guidebook/chemistry/core.ftl
@@ -10,16 +10,18 @@
guidebook-reagent-name = [bold][color={$color}]{CAPITALIZE($name)}[/color][/bold]
guidebook-reagent-recipes-header = Recipe
guidebook-reagent-recipes-reagent-display = [bold]{$reagent}[/bold] \[{$ratio}\]
-guidebook-reagent-recipes-mix = Mix
+guidebook-reagent-sources-header = Sources
+guidebook-reagent-sources-ent-wrapper = [bold]{$name}[/bold] \[1\]
+guidebook-reagent-sources-gas-wrapper = [bold]{$name} (gas)[/bold] \[1\]
guidebook-reagent-effects-header = Effects
guidebook-reagent-effects-metabolism-group-rate = [bold]{$group}[/bold] [color=gray]({$rate} units per second)[/color]
guidebook-reagent-physical-description = [italic]Seems to be {$description}.[/italic]
guidebook-reagent-recipes-mix-info = {$minTemp ->
[0] {$hasMax ->
- [true] {$verb} below {$maxTemp}K
- *[false] {$verb}
+ [true] {CAPITALIZE($verb)} below {$maxTemp}K
+ *[false] {CAPITALIZE($verb)}
}
- *[other] {$verb} {$hasMax ->
+ *[other] {CAPITALIZE($verb)} {$hasMax ->
[true] between {$minTemp}K and {$maxTemp}K
*[false] above {$minTemp}K
}
diff --git a/Resources/Prototypes/Chemistry/mixing_types.yml b/Resources/Prototypes/Chemistry/mixing_types.yml
index dbf14c19c1..20d58e70ab 100644
--- a/Resources/Prototypes/Chemistry/mixing_types.yml
+++ b/Resources/Prototypes/Chemistry/mixing_types.yml
@@ -1,3 +1,36 @@
+# Default Mixing
+# Not actually used in reactions: only meant for guidebook display purposes.
+
+- type: mixingCategory
+ id: DummyMix
+ verbText: mixing-verb-default-mix
+ icon:
+ sprite: Objects/Specific/Chemistry/beaker_large.rsi
+ state: beakerlarge
+
+- type: mixingCategory
+ id: DummyGrind
+ verbText: mixing-verb-default-grind
+ icon:
+ sprite: Structures/Machines/juicer.rsi
+ state: juicer0
+
+- type: mixingCategory
+ id: DummyJuice
+ verbText: mixing-verb-default-juice
+ icon:
+ sprite: Structures/Machines/juicer.rsi
+ state: juicer0
+
+- type: mixingCategory
+ id: DummyCondense
+ verbText: mixing-verb-default-condense
+ icon:
+ sprite: Structures/Piping/Atmospherics/condenser.rsi
+ state: display
+
+# Alternative Mixing Methods
+
- type: mixingCategory
id: Centrifuge
verbText: mixing-verb-centrifuge
diff --git a/Resources/Prototypes/Entities/Objects/Materials/parts.yml b/Resources/Prototypes/Entities/Objects/Materials/parts.yml
index 15159ba69d..76c1f20460 100644
--- a/Resources/Prototypes/Entities/Objects/Materials/parts.yml
+++ b/Resources/Prototypes/Entities/Objects/Materials/parts.yml
@@ -26,7 +26,7 @@
- type: entity
parent: PartBase
id: PartRodMetal
- name: metal rods
+ name: metal rod
suffix: Full
components:
- type: PhysicalComposition
diff --git a/Resources/Prototypes/Recipes/Reactions/biological.yml b/Resources/Prototypes/Recipes/Reactions/biological.yml
index b126a23abe..4e94b8d85b 100644
--- a/Resources/Prototypes/Recipes/Reactions/biological.yml
+++ b/Resources/Prototypes/Recipes/Reactions/biological.yml
@@ -1,5 +1,6 @@
- type: reaction
id: BloodBreakdown
+ source: true
requiredMixerCategories:
- Centrifuge
reactants:
@@ -14,6 +15,7 @@
- type: reaction
id: SlimeBloodBreakdown
+ source: true
requiredMixerCategories:
- Centrifuge
reactants:
@@ -25,6 +27,7 @@
- type: reaction
id: CopperBloodBreakdown
+ source: true
requiredMixerCategories:
- Centrifuge
reactants:
@@ -39,6 +42,7 @@
- type: reaction
id: ZombieBloodBreakdown
+ source: true
requiredMixerCategories:
- Centrifuge
reactants:
diff --git a/Resources/Prototypes/Recipes/Reactions/chemicals.yml b/Resources/Prototypes/Recipes/Reactions/chemicals.yml
index b2fb6a8752..df21e7bac3 100644
--- a/Resources/Prototypes/Recipes/Reactions/chemicals.yml
+++ b/Resources/Prototypes/Recipes/Reactions/chemicals.yml
@@ -10,6 +10,7 @@
- type: reaction
id: CelluloseBreakdown
+ source: true
requiredMixerCategories:
- Electrolysis
reactants:
@@ -217,6 +218,7 @@
- type: reaction
id: TableSaltBreakdown
+ source: true
requiredMixerCategories:
- Electrolysis
reactants:
diff --git a/Resources/Prototypes/Recipes/Reactions/drinks.yml b/Resources/Prototypes/Recipes/Reactions/drinks.yml
index 73cc10cf85..d278ef24c4 100644
--- a/Resources/Prototypes/Recipes/Reactions/drinks.yml
+++ b/Resources/Prototypes/Recipes/Reactions/drinks.yml
@@ -262,6 +262,7 @@
- type: reaction
id: EthanolBreakdown
+ source: true
requiredMixerCategories:
- Electrolysis
reactants:
@@ -895,6 +896,7 @@
- type: reaction
id: WaterBreakdown
+ source: true
requiredMixerCategories:
- Electrolysis
reactants:
diff --git a/Resources/Prototypes/Recipes/Reactions/food.yml b/Resources/Prototypes/Recipes/Reactions/food.yml
index 39bf0d2001..fbbf65c535 100644
--- a/Resources/Prototypes/Recipes/Reactions/food.yml
+++ b/Resources/Prototypes/Recipes/Reactions/food.yml
@@ -300,6 +300,7 @@
- type: reaction
id: BananaBreakdown
+ source: true
requiredMixerCategories:
- Centrifuge
reactants:
@@ -311,12 +312,13 @@
#- type: reaction
# id: SugarBreakdown
-# minTemp: 520
- # reactants:
- # Sugar:
- # amount: 4
- # products:
- # Carbon: 1
- # Oxygen: 1
- # Hydrogen: 2
+# source: true
+# minTemp: 520
+# reactants:
+# Sugar:
+# amount: 4
+# products:
+# Carbon: 1
+# Oxygen: 1
+# Hydrogen: 2
diff --git a/Resources/Prototypes/Recipes/Reactions/fun.yml b/Resources/Prototypes/Recipes/Reactions/fun.yml
index 35ec500590..818030a3b3 100644
--- a/Resources/Prototypes/Recipes/Reactions/fun.yml
+++ b/Resources/Prototypes/Recipes/Reactions/fun.yml
@@ -148,6 +148,7 @@
- type: reaction
id: FiberBreakdown
+ source: true
requiredMixerCategories:
- Centrifuge
reactants:
diff --git a/Resources/Prototypes/Recipes/Reactions/gas.yml b/Resources/Prototypes/Recipes/Reactions/gas.yml
index 9cc6db1b64..3dc6654d68 100644
--- a/Resources/Prototypes/Recipes/Reactions/gas.yml
+++ b/Resources/Prototypes/Recipes/Reactions/gas.yml
@@ -1,5 +1,6 @@
- type: reaction
id: CarbonDioxideBreakdown
+ source: true
requiredMixerCategories:
- Electrolysis
reactants:
@@ -11,6 +12,7 @@
- type: reaction
id: NitrousOxideBreakdown
+ source: true
requiredMixerCategories:
- Electrolysis
reactants:
diff --git a/Resources/Prototypes/Recipes/Reactions/pyrotechnic.yml b/Resources/Prototypes/Recipes/Reactions/pyrotechnic.yml
index b0f71b4c68..6b1aff4be6 100644
--- a/Resources/Prototypes/Recipes/Reactions/pyrotechnic.yml
+++ b/Resources/Prototypes/Recipes/Reactions/pyrotechnic.yml
@@ -63,6 +63,7 @@
- type: reaction
id: WeldingFuelBreakdown
+ source: true
requiredMixerCategories:
- Centrifuge
reactants:
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/display.png b/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/display.png
new file mode 100644
index 0000000000..4dc1017fc7
Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/display.png differ
diff --git a/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/meta.json b/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/meta.json
index 591c223e5c..05a1e617a5 100644
--- a/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/meta.json
+++ b/Resources/Textures/Structures/Piping/Atmospherics/condenser.rsi/meta.json
@@ -35,6 +35,9 @@
"name":"pipe",
"directions":4
},
+ {
+ "name":"display"
+ },
{
"name":"fill-1"
},