Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
1de2285
Add PlantNutrientPrototype
Wolfkey-SomeoneElseTookMyUsername Jun 17, 2026
2261401
Move PlantNutrientPrototype.cs to Shared
Wolfkey-SomeoneElseTookMyUsername Jun 17, 2026
a245f3a
Basic guidebook functionality
Wolfkey-SomeoneElseTookMyUsername Jun 18, 2026
bc09495
Trays can now store PlantNutrients
Wolfkey-SomeoneElseTookMyUsername Jun 20, 2026
085db4d
PlantAdjustNutrientEntityEffect added.
Wolfkey-SomeoneElseTookMyUsername Jun 21, 2026
125222c
Capitalisation fix
Wolfkey-SomeoneElseTookMyUsername Jun 21, 2026
be6d513
Remove the word "reagent" from plant nutrient guidebook code
Wolfkey-SomeoneElseTookMyUsername Jun 22, 2026
60d0eda
Plant nutrient guidebook sources tab
Wolfkey-SomeoneElseTookMyUsername Jun 23, 2026
311f848
Add NutrientRequirement struct
Wolfkey-SomeoneElseTookMyUsername Jun 23, 2026
c64d4c6
Fix requirements being lost when seedData is cloned.
Wolfkey-SomeoneElseTookMyUsername Jun 23, 2026
e126e65
Show nutrient requirements in hydroponic tray descriptions
Wolfkey-SomeoneElseTookMyUsername Jun 24, 2026
4cd9ba4
Bonus nutrient display no longer turns red when not fulfilled
Wolfkey-SomeoneElseTookMyUsername Jun 26, 2026
0074cc1
Plants now use up nutrients when harvested, and gain bonus reagents. …
Wolfkey-SomeoneElseTookMyUsername Jun 26, 2026
a7ef817
Add a lot of new plant nutrients, and make reagents give them to plants.
Wolfkey-SomeoneElseTookMyUsername Jun 29, 2026
7a7e120
Fix typo
Wolfkey-SomeoneElseTookMyUsername Jun 30, 2026
b98d4d5
Fix typo made while fixing typo
Wolfkey-SomeoneElseTookMyUsername Jun 30, 2026
c605935
Remove depricated entity effects
Wolfkey-SomeoneElseTookMyUsername Jun 30, 2026
61399db
Refactor heat and pressure tolerances. Seperate improper heat/pressur…
Wolfkey-SomeoneElseTookMyUsername Jun 30, 2026
7acc56c
Fixed low pressure warning being based off of maximum pressure instea…
Wolfkey-SomeoneElseTookMyUsername Jun 30, 2026
eb295a1
Low temperature alert is now no longer just "low level alert"
Wolfkey-SomeoneElseTookMyUsername Jun 30, 2026
fe9babd
Change how temperature and pressure work again, make health loss scal…
Wolfkey-SomeoneElseTookMyUsername Jun 30, 2026
980a5b9
Damage from improper heat now properly scales with a plants ideal heat.
Wolfkey-SomeoneElseTookMyUsername Jun 30, 2026
fab362e
Split seeds.yml into multiple files
Wolfkey-SomeoneElseTookMyUsername Jun 30, 2026
a959b4f
Fix nutrient ID capitilization
Wolfkey-SomeoneElseTookMyUsername Jul 1, 2026
789692d
Convert root vegetables to the new nutrient system
Wolfkey-SomeoneElseTookMyUsername Jul 1, 2026
1a36e71
Soybeans moved to other.yml, Grains converted to new system
Wolfkey-SomeoneElseTookMyUsername Jul 1, 2026
0e1e161
Add comments to more easily see which seeds i have updated.
Wolfkey-SomeoneElseTookMyUsername Jul 1, 2026
7377061
Change default nutrient source icon to hydroponics tray
Wolfkey-SomeoneElseTookMyUsername Jul 2, 2026
dec9a26
Refactor total plant nutrients and environmental tolerances to be sto…
Wolfkey-SomeoneElseTookMyUsername Jul 6, 2026
f5065c0
Fix some crashes caused by the refactor
Wolfkey-SomeoneElseTookMyUsername Jul 7, 2026
faf922a
Towercaps & Steelcaps converted to the new system.
Wolfkey-SomeoneElseTookMyUsername Jul 7, 2026
bb99b50
Unfinished fruit.yml changes
Wolfkey-SomeoneElseTookMyUsername Jul 8, 2026
5af187c
More fruit changes
Wolfkey-SomeoneElseTookMyUsername Jul 16, 2026
25340b3
Extradimensional orange YAML
Wolfkey-SomeoneElseTookMyUsername Jul 20, 2026
b483948
all fruit except for gatfruit, capfruit, and anomaly berries converte…
Wolfkey-SomeoneElseTookMyUsername Jul 24, 2026
15025d9
banana and lemoon
Wolfkey-SomeoneElseTookMyUsername Jul 24, 2026
0e33e98
replace idealHeat with baseIdealHeat in others.yml, update sugarcane
Wolfkey-SomeoneElseTookMyUsername Jul 24, 2026
242cce7
replace idealHeat with baseIdealHeat in all YAML files
Wolfkey-SomeoneElseTookMyUsername Jul 24, 2026
f5e1f2d
Merge branch 'persistence_testing' into plant_nutrient_rework_2
Wolfkey-SomeoneElseTookMyUsername Jul 26, 2026
ba1121a
Port omnizine change
Wolfkey-SomeoneElseTookMyUsername Jul 26, 2026
97c6172
Merge remote-tracking branch 'origin/persistence_testing' into plant_…
Wolfkey-SomeoneElseTookMyUsername Jul 28, 2026
7c426a9
tray & soil YAML changes. toxins & pests removed from plant analyzers
Wolfkey-SomeoneElseTookMyUsername Jul 28, 2026
0b6dba4
Trays and soil can now absorb radiation
Wolfkey-SomeoneElseTookMyUsername Jul 28, 2026
e04397c
Plants absorb radiation faster
Wolfkey-SomeoneElseTookMyUsername Jul 29, 2026
f832881
Add TODO comments to randomMutations.yml
Wolfkey-SomeoneElseTookMyUsername Jul 29, 2026
7ec90cc
Easy leaves done
Wolfkey-SomeoneElseTookMyUsername Jul 31, 2026
6cf0cdf
Philosophor's stone based gold recipe and required nutrients added.
Wolfkey-SomeoneElseTookMyUsername Aug 7, 2026
db92cae
Golden apples don't juice into gold. TODO Comment added to produce.yml
Wolfkey-SomeoneElseTookMyUsername Aug 7, 2026
c7e9c92
Comment out several mutations in randomMutations.yml
Wolfkey-SomeoneElseTookMyUsername Aug 7, 2026
79e868c
Added comments indicating changed code to PlantHolderSystem.cs
Wolfkey-SomeoneElseTookMyUsername Aug 7, 2026
91ad840
Remove extra dependancy added in BotanySwabSystem.cs
Wolfkey-SomeoneElseTookMyUsername Aug 7, 2026
aabfb94
Comments added to MutationSystem.cs
Wolfkey-SomeoneElseTookMyUsername Aug 7, 2026
e4d1132
Plant respiration added to reagents
Wolfkey-SomeoneElseTookMyUsername Aug 7, 2026
8bd361e
Plant respiration added to the guidebook
Wolfkey-SomeoneElseTookMyUsername Aug 8, 2026
6607b4e
More comments in PlantHolderComponent.cs
Wolfkey-SomeoneElseTookMyUsername Aug 8, 2026
2a57170
Adjust amount of nutrients that will be added by gasses.
Wolfkey-SomeoneElseTookMyUsername Aug 8, 2026
4522d62
Rudimentary gas nutrient implementation
Wolfkey-SomeoneElseTookMyUsername Aug 8, 2026
2162392
Move seeds to _Persistence14
Wolfkey-SomeoneElseTookMyUsername Aug 8, 2026
3526f47
Fix crash
Wolfkey-SomeoneElseTookMyUsername Aug 9, 2026
56efbd7
Proper gas absorption
Wolfkey-SomeoneElseTookMyUsername Aug 9, 2026
f5164bb
Remove plant respiration from reagents
Wolfkey-SomeoneElseTookMyUsername Aug 9, 2026
796f29b
Remove plant respiration from guidebook reagent embeds
Wolfkey-SomeoneElseTookMyUsername Aug 9, 2026
2d37908
Merge branch 'persistence_testing' into plant_nutrient_rework_2
Wolfkey-SomeoneElseTookMyUsername Aug 9, 2026
c1a1c53
Plant respiration as a guidebook source
Wolfkey-SomeoneElseTookMyUsername Aug 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 0 additions & 16 deletions Content.Client/Botany/PlantAnalyzer/PlantAnalyzerWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -71,22 +71,6 @@
<Label Margin="12 0 0 0" Name="GtFieldIfTolerances2" />
<Label HorizontalAlignment="Right" Name="NutritionConsumptionLabel" />
<Label Text=" · " />
<Label Text="{Loc 'plant-analyzer-component-toxins'}" />
<Label SetWidth="8" />
<Label FontColorOverride="yellowgreen" HorizontalAlignment="Right" Name="ToxinsLabel" />
<Label Text=" / " />
<Label HorizontalAlignment="Right" Text="100.00" />
<Label Margin="12 0 0 0" Name="LtFieldIfTolerances1" />
<Label HorizontalAlignment="Right" Name="ToxinsResistanceLabel" />
<Label Text=" · " />
<Label Text="{Loc 'plant-analyzer-component-pests'}" />
<Label SetWidth="8" />
<Label FontColorOverride="magenta" HorizontalAlignment="Right" Name="PestLevelLabel" />
<Label Text=" / " />
<Label HorizontalAlignment="Right" Text="10.00" />
<Label Margin="12 0 0 0" Name="LtFieldIfTolerances2" />
<Label HorizontalAlignment="Right" Name="PestResistanceLabel" />
<Label Text=" · " />
<Label Text="{Loc 'plant-analyzer-component-weeds'}" />
<Label SetWidth="8" />
<Label FontColorOverride="red" HorizontalAlignment="Right" Name="WeedLevelLabel" />
Expand Down
12 changes: 2 additions & 10 deletions Content.Client/Botany/PlantAnalyzer/PlantAnalyzerWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,38 +88,30 @@ public void Populate(PlantAnalyzerScannedUserMessage msg)
{
WaterLevelLabel.Text = msg.TrayData.WaterLevel.ToString("0.00");
NutritionLevelLabel.Text = msg.TrayData.NutritionLevel.ToString("0.00");
ToxinsLabel.Text = msg.TrayData.Toxins.ToString("0.00");
PestLevelLabel.Text = msg.TrayData.PestLevel.ToString("0.00");
WeedLevelLabel.Text = msg.TrayData.WeedLevel.ToString("0.00");

// Section 3.1: Tolerances part 1.
if (msg.TolerancesData is not null)
{
GtFieldIfTolerances1.Text = ">";
LtFieldIfTolerances1.Text = "<";
LtFieldIfTolerances3.Text = "<";

WaterConsumptionLabel.Text = msg.TolerancesData.WaterConsumption.ToString("0.00");
NutritionConsumptionLabel.Text = msg.TolerancesData.NutrientConsumption.ToString("0.00");
// Technically would be "x + epsilon" for toxin and pest.
// But it makes no difference here since I only display two digits.
ToxinsResistanceLabel.Text = msg.TolerancesData.ToxinsTolerance.ToString("0.00");
PestResistanceLabel.Text = msg.TolerancesData.PestTolerance.ToString("0.00");
WeedResistanceLabel.Text = msg.TolerancesData.WeedTolerance.ToString("0.00");
}
else
{
GtFieldIfTolerances1.Text = "";
LtFieldIfTolerances1.Text = "";
LtFieldIfTolerances3.Text = "";

WaterConsumptionLabel.Text = "";
NutritionConsumptionLabel.Text = "";
ToxinsResistanceLabel.Text = "";
PestResistanceLabel.Text = "";
WeedResistanceLabel.Text = "";
}
GtFieldIfTolerances2.Text = GtFieldIfTolerances1.Text;
LtFieldIfTolerances2.Text = LtFieldIfTolerances1.Text;
LtFieldIfTolerances3.Text = LtFieldIfTolerances1.Text;

ContainerGrid.Visible = true;
}
Expand Down
43 changes: 43 additions & 0 deletions Content.Client/Guidebook/Controls/GuidePlantNutrientEmbed.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<BoxContainer xmlns="https://spacestation14.io"
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
Orientation="Vertical"
Margin="5 5 5 5">
<PanelContainer HorizontalExpand="True">
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BorderThickness="1" BorderColor="#777777"/>
</PanelContainer.PanelOverride>
<BoxContainer Orientation="Vertical">
<PanelContainer Name="NameBackground" HorizontalExpand="True" VerticalExpand="False">
<RichTextLabel Name="NutrientName" HorizontalAlignment="Center"/>
</PanelContainer>
<BoxContainer Name="SourcesContainer" HorizontalExpand="True">
<Collapsible HorizontalExpand="True">
<CollapsibleHeading Title="{Loc 'guidebook-reagent-sources-header'}"/>
<CollapsibleBody>
<GridContainer Name="SourcesDescriptionContainer"
Margin="10 0 10 0"
Columns="1"
HSeparationOverride="0"
HorizontalAlignment="Stretch"
HorizontalExpand="True"/>
</CollapsibleBody>
</Collapsible>
</BoxContainer><!--
<BoxContainer Name="EffectsContainer" HorizontalExpand="True">
<Collapsible>
<CollapsibleHeading Title="{Loc 'guidebook-reagent-effects-header'}"/>
<CollapsibleBody>
<BoxContainer Name="EffectsDescriptionContainer"
Orientation="Vertical"
Margin="10 0 10 0"
HorizontalExpand="True"/>
</CollapsibleBody>
</Collapsible>
</BoxContainer> !-->
<BoxContainer Margin="10 5 10 10" HorizontalExpand="True">
<!-- The troublemaker !-->
<RichTextLabel Name="NutrientDescription" HorizontalAlignment="Left"/>
</BoxContainer>
</BoxContainer>
</PanelContainer>
</BoxContainer>
237 changes: 237 additions & 0 deletions Content.Client/Guidebook/Controls/GuidePlantNutrientEmbed.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
using Content.Client.Chemistry.EntitySystems;
using Content.Client.Guidebook.Richtext;
using Content.Client.Message;
using Content.Client.UserInterface.ControlExtensions;
using Content.Client._Persistence14.Botany;
using Content.Shared.CCVar;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Botany;
using Content.Shared.Localizations;
using Content.Shared.Metabolism;
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.Configuration;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Content.Shared.EntityEffects;
using Content.Shared.EntityEffects.Effects.Botany;

namespace Content.Client.Guidebook.Controls;

/// <summary>
/// Control for embedding a plant nutrient into a guidebook.
/// </summary>
[UsedImplicitly, GenerateTypedNameReferences]
public sealed partial class GuidePlantNutrientEmbed : BoxContainer, IDocumentTag, ISearchableControl, IPrototypeRepresentationControl
{
[Dependency] private readonly IEntitySystemManager _systemManager = default!;
[Dependency] private readonly ILogManager _logManager = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly IConfigurationManager _config = default!;

private readonly BotanyGuideDataSystem _botanyGuideData;
private readonly ISawmill _sawmill;

public IPrototype? RepresentedPrototype { get; private set; }

public GuidePlantNutrientEmbed()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
_sawmill = _logManager.GetSawmill("guidebook.plantNutrient");
_botanyGuideData = _systemManager.GetEntitySystem<BotanyGuideDataSystem>();
MouseFilter = MouseFilterMode.Stop;
}

public GuidePlantNutrientEmbed(string nutrient) : this()
{
GenerateControl(_prototype.Index<PlantNutrientPrototype>(nutrient));
}

public GuidePlantNutrientEmbed(PlantNutrientPrototype nutrient) : this()
{
GenerateControl(nutrient);
}

public bool CheckMatchesSearch(string query)
{
return this.ChildrenContainText(query);
}

public void SetHiddenState(bool state, string query)
{
Visible = CheckMatchesSearch(query) ? state : !state;
}

public bool TryParseTag(Dictionary<string, string> args, [NotNullWhen(true)] out Control? control)
{
control = null;
if (!args.TryGetValue("Nutrient", out var id))
{
_sawmill.Error("Plant nutrient embed tag is missing nutrient prototype argument");
return false;
}

if (!_prototype.TryIndex<PlantNutrientPrototype>(id, out var nutrient))
{
_sawmill.Error($"Specified plant nutrient prototype \"{id}\" is not a valid plant nutrient prototype");
return false;
}

GenerateControl(nutrient);

control = this;
return true;
}

private void GenerateControl(PlantNutrientPrototype nutrient)
{
RepresentedPrototype = nutrient;

NameBackground.PanelOverride = new StyleBoxFlat
{
BackgroundColor = nutrient.SubstanceColor
};

var r = nutrient.SubstanceColor.R;
var g = nutrient.SubstanceColor.G;
var b = nutrient.SubstanceColor.B;

var textColor = 0.2126f * r + 0.7152f * g + 0.0722f * b > 0.5
? Color.Black
: Color.White;

NutrientName.SetMarkup(Loc.GetString("guidebook-reagent-name",
("color", textColor), ("name", nutrient.LocalizedName)));

#region Effects
/*if (_chemistryGuideData.ReagentGuideRegistry.TryGetValue(reagent.ID, out var guideEntryRegistry) &&
guideEntryRegistry.GuideEntries != null &&
guideEntryRegistry.GuideEntries.Values.Any(pair => pair.EffectDescriptions.Any() || pair.Metabolites?.Any() == true))
{
EffectsDescriptionContainer.Children.Clear();
foreach (var (stage, effect) in guideEntryRegistry.GuideEntries)
{
var hasMetabolites = effect.Metabolites?.Any() == true;
if (!effect.EffectDescriptions.Any() && !hasMetabolites)
continue;

var groupLabel = new RichTextLabel();
groupLabel.SetMarkup(Loc.GetString("guidebook-reagent-effects-metabolism-stage-rate",
("stage", _prototype.Index<MetabolismStagePrototype>(stage).LocalizedName), ("rate", effect.MetabolismRate)));
var descriptionLabel = new RichTextLabel
{
Margin = new Thickness(25, 0, 10, 0)
};

var descMsg = new FormattedMessage();
var descriptionsCount = effect.EffectDescriptions.Length;
var i = 0;
foreach (var effectString in effect.EffectDescriptions)
{
descMsg.AddMarkupOrThrow(effectString);
i++;
if (i < descriptionsCount || hasMetabolites)
descMsg.PushNewline();
}
if (hasMetabolites)
{
var metabolites = new List<string>();
foreach (var (metabolite, ratio) in effect.Metabolites!)
{
metabolites.Add(Loc.GetString("guidebook-reagent-effects-metabolite-item", ("rate", (double)ratio), ("reagent", _prototype.Index(metabolite).LocalizedName)));
}
metabolites.Sort();

descMsg.AddMarkupOrThrow(Loc.GetString("guidebook-reagent-effects-metabolites", ("items", ContentLocalizationManager.FormatList(metabolites))));
}
descriptionLabel.SetMessage(descMsg);

EffectsDescriptionContainer.AddChild(groupLabel);
EffectsDescriptionContainer.AddChild(descriptionLabel);
}
}
else
{
EffectsContainer.Visible = false;
}*/
#endregion

#region Recipe
var reagents = _prototype.EnumeratePrototypes<ReagentPrototype>()
.Where(p => CheckReagentPlantMetabolisms(p.PlantMetabolisms, nutrient.ID))
//.OrderBy(p => p.Priority)
//.ThenBy(p => p.Products.Count)
.ToList();

if (reagents.Any())
{
foreach (var reagentPrototype in reagents)
{
SourcesDescriptionContainer.AddChild(new GuidePlantNutrientSource(reagentPrototype, _prototype, _systemManager));
}
}
else
{
SourcesContainer.Visible = false;
}
#endregion

GenerateSources(nutrient);

FormattedMessage description = new();
description.AddText(nutrient.LocalizedDescription);
description.PushNewline();

NutrientDescription.SetMessage(description);
}

private bool CheckReagentPlantMetabolisms(List<EntityEffect> effects, string nutrientId)
{
foreach (var effect in effects)
{
if (effect is PlantAdjustNutrient adjustNutrient && adjustNutrient.Nutrient == nutrientId)
return true;
}
return false;
}
private void GenerateSources(PlantNutrientPrototype reagent)
{
var sources = _botanyGuideData.GetPlantNutrientSources(reagent.ID);
if (sources.Count == 0)
{
//SourcesContainer.Visible = false;
return;
}
SourcesContainer.Visible = true;

var orderedSources = sources
//.OrderBy(o => o.OutputCount)
.OrderBy(o => o.IdentifierString);
foreach (var source in orderedSources)
{
if (source is PlantNutrientReagentSourceData reactionSourceData)
{
SourcesDescriptionContainer.AddChild(new GuidePlantNutrientSource(
reactionSourceData.ReagentPrototype,
_prototype,
_systemManager));
}
else if (source is PlantNutrientGasSourceData gasSourceData)
{
SourcesDescriptionContainer.AddChild(new GuidePlantNutrientSource(
gasSourceData.GasPrototype,
gasSourceData.MixingType,
_prototype,
_systemManager));
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<BoxContainer xmlns="https://spacestation14.io"
Orientation="Vertical">
<BoxContainer Name="GroupContainer" Orientation="Vertical"/>
</BoxContainer>
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using Content.Client.Guidebook.Richtext;
//using Content.Shared.Chemistry.Reagent;
using Content.Shared.Botany;
using JetBrains.Annotations;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
using System.Diagnostics.CodeAnalysis;
using System.Linq;

namespace Content.Client.Guidebook.Controls;

/// <summary>
/// Control for embedding a plant nutrient into a guidebook.
/// </summary>
[UsedImplicitly, GenerateTypedNameReferences]
public sealed partial class GuidePlantNutrientGroupEmbed : BoxContainer, IDocumentTag
{
[Dependency] private readonly ILogManager _logManager = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;


public GuidePlantNutrientGroupEmbed()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
MouseFilter = MouseFilterMode.Stop;
}

public bool TryParseTag(Dictionary<string, string> args, [NotNullWhen(true)] out Control? control)
{
control = null;
var prototypes = _prototype.EnumeratePrototypes<PlantNutrientPrototype>().OrderBy(p => p.LocalizedName);
foreach (var nutrient in prototypes)
{
var embed = new GuidePlantNutrientEmbed(nutrient);
GroupContainer.AddChild(embed);
}

control = this;
return true;
}
}
Loading
Loading