From b9fb66f00526f6d8fbcb0bd303ccdfb1bc6fd439 Mon Sep 17 00:00:00 2001 From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Sun, 4 Jun 2023 16:45:02 -0400 Subject: [PATCH] Chem guidebook (#17123) * im good at atomizing. welcome to half-finished chem guides. * wagh * e * save work * aa * woweee UI * finishing the last of it * don't actually update the engine :( --------- Co-authored-by: moonheart08 --- .../EntitySystems/ChemistryGuideDataSystem.cs | 29 ++ .../Guidebook/Controls/GuideReagentEmbed.xaml | 58 ++++ .../Controls/GuideReagentEmbed.xaml.cs | 176 ++++++++++ .../Controls/GuideReagentGroupEmbed.xaml | 4 + .../Controls/GuideReagentGroupEmbed.xaml.cs | 60 ++++ .../Commands/DumpReagentGuideText.cs | 47 +++ .../EntitySystems/ChemistryGuideDataSystem.cs | 67 ++++ .../ReactionEffects/AreaReactionEffect.cs | 4 + .../CreateEntityReactionEffect.cs | 6 + .../ExplosionReactionEffect.cs | 6 +- .../SmokeAreaReactionEffect.cs | 1 + .../SolutionTemperatureEffects.cs | 14 +- .../BodyTemperature.cs | 10 +- .../HasTagCondition.cs | 7 + .../MobStateCondition.cs | 6 + .../ReagentEffectConditions/OrganType.cs | 8 + .../ReagentThreshold.cs | 13 + .../SolutionTemperature.cs | 8 + .../ReagentEffectConditions/TotalDamage.cs | 8 + .../ReagentEffects/ActivateArtifact.cs | 4 + .../ReagentEffects/AddToSolutionReaction.cs | 4 + .../Chemistry/ReagentEffects/AdjustAlert.cs | 4 + .../Chemistry/ReagentEffects/AdjustReagent.cs | 22 ++ .../ReagentEffects/AdjustTemperature.cs | 7 + .../ReagentEffects/ChemCleanBoodstream.cs | 5 + .../ReagentEffects/ChemHealEyeDamage.cs | 4 + .../Chemistry/ReagentEffects/ChemVomit.cs | 4 + .../Chemistry/ReagentEffects/CreateGas.cs | 12 + .../Chemistry/ReagentEffects/Drunk.cs | 4 + .../Chemistry/ReagentEffects/Electrocute.cs | 4 + .../Chemistry/ReagentEffects/Emote.cs | 5 + .../ReagentEffects/ExtinguishReaction.cs | 4 + .../ReagentEffects/FlammableReaction.cs | 5 + .../Chemistry/ReagentEffects/HealthChange.cs | 35 ++ .../Chemistry/ReagentEffects/Ignite.cs | 5 + .../Chemistry/ReagentEffects/MakeSentient.cs | 5 + .../ReagentEffects/ModifyBleedAmount.cs | 5 + .../ReagentEffects/ModifyBloodLevel.cs | 5 + .../Chemistry/ReagentEffects/ModifyLungGas.cs | 5 + .../ReagentEffects/MovespeedModifier.cs | 9 + .../Chemistry/ReagentEffects/Oxygenate.cs | 5 + .../Chemistry/ReagentEffects/Paralyze.cs | 6 + .../PlantMetabolism/PlantAdjustAttribute.cs | 3 + .../PlantMetabolism/PlantCryoxadone.cs | 3 + .../PlantMetabolism/PlantDiethylamine.cs | 3 + .../PlantMetabolism/RobustHarvest.cs | 3 + .../Chemistry/ReagentEffects/PopupMessage.cs | 5 + .../ReagentEffects/ResetNarcolepsy.cs | 4 + .../Chemistry/ReagentEffects/SatiateHunger.cs | 8 +- .../Chemistry/ReagentEffects/SatiateThirst.cs | 8 +- .../StatusEffects/GenericStatusEffect.cs | 8 + .../ReagentEffects/StatusEffects/Jitter.cs | 4 + .../ReagentEffects/WashCreamPieReaction.cs | 4 + .../Prototypes/MetabolizerTypePrototype.cs | 3 + .../Chemistry/Reagent/ReagentEffect.cs | 26 +- .../Reagent/ReagentEffectCondition.cs | 8 + .../Chemistry/Reagent/ReagentPrototype.cs | 45 ++- .../SharedChemistryGuideDataSystem.cs | 42 +++ .../ContentLocalizationManager.cs | 94 +++++- .../en-US/guidebook/chemistry/conditions.ftl | 50 +++ .../Locale/en-US/guidebook/chemistry/core.ftl | 16 + .../en-US/guidebook/chemistry/effects.ftl | 316 ++++++++++++++++++ .../guidebook/chemistry/healthchange.ftl | 5 + .../guidebook/chemistry/statuseffects.ftl | 11 + Resources/Locale/en-US/guidebook/guides.ftl | 1 + .../Chemistry/metabolizer_types.yml | 8 + .../Entities/Structures/Dispensers/chem.yml | 3 + .../Prototypes/Guidebook/shiftandcrew.yml | 5 + Resources/Prototypes/Guidebook/ss14.yml | 1 + Resources/ServerInfo/Guidebook/Chemicals.xml | 34 ++ .../Textures/Interface/Misc/beakerlarge.png | Bin 0 -> 239 bytes RobustToolbox | 2 +- 72 files changed, 1411 insertions(+), 12 deletions(-) create mode 100644 Content.Client/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs create mode 100644 Content.Client/Guidebook/Controls/GuideReagentEmbed.xaml create mode 100644 Content.Client/Guidebook/Controls/GuideReagentEmbed.xaml.cs create mode 100644 Content.Client/Guidebook/Controls/GuideReagentGroupEmbed.xaml create mode 100644 Content.Client/Guidebook/Controls/GuideReagentGroupEmbed.xaml.cs create mode 100644 Content.Server/Chemistry/Commands/DumpReagentGuideText.cs create mode 100644 Content.Server/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs create mode 100644 Content.Server/Chemistry/ReactionEffects/SmokeAreaReactionEffect.cs create mode 100644 Content.Shared/Chemistry/SharedChemistryGuideDataSystem.cs create mode 100644 Resources/Locale/en-US/guidebook/chemistry/conditions.ftl create mode 100644 Resources/Locale/en-US/guidebook/chemistry/core.ftl create mode 100644 Resources/Locale/en-US/guidebook/chemistry/effects.ftl create mode 100644 Resources/Locale/en-US/guidebook/chemistry/healthchange.ftl create mode 100644 Resources/Locale/en-US/guidebook/chemistry/statuseffects.ftl create mode 100644 Resources/ServerInfo/Guidebook/Chemicals.xml create mode 100644 Resources/Textures/Interface/Misc/beakerlarge.png diff --git a/Content.Client/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs b/Content.Client/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs new file mode 100644 index 0000000000..736e22f834 --- /dev/null +++ b/Content.Client/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs @@ -0,0 +1,29 @@ +using Content.Shared.Chemistry; + +namespace Content.Client.Chemistry.EntitySystems; + +/// +public sealed class ChemistryGuideDataSystem : SharedChemistryGuideDataSystem +{ + /// + public override void Initialize() + { + base.Initialize(); + + SubscribeNetworkEvent(OnReceiveRegistryUpdate); + } + + private void OnReceiveRegistryUpdate(ReagentGuideRegistryChangedEvent message) + { + var data = message.Changeset; + foreach (var remove in data.Removed) + { + Registry.Remove(remove); + } + + foreach (var (key, val) in data.GuideEntries) + { + Registry[key] = val; + } + } +} diff --git a/Content.Client/Guidebook/Controls/GuideReagentEmbed.xaml b/Content.Client/Guidebook/Controls/GuideReagentEmbed.xaml new file mode 100644 index 0000000000..e8a36d57f4 --- /dev/null +++ b/Content.Client/Guidebook/Controls/GuideReagentEmbed.xaml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Content.Client/Guidebook/Controls/GuideReagentEmbed.xaml.cs b/Content.Client/Guidebook/Controls/GuideReagentEmbed.xaml.cs new file mode 100644 index 0000000000..4b832be02b --- /dev/null +++ b/Content.Client/Guidebook/Controls/GuideReagentEmbed.xaml.cs @@ -0,0 +1,176 @@ +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Content.Client.Chemistry.EntitySystems; +using Content.Client.Guidebook.Richtext; +using Content.Client.Message; +using Content.Shared.Chemistry.Reaction; +using Content.Shared.Chemistry.Reagent; +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.Guidebook.Controls; + +/// +/// Control for embedding a reagent into a guidebook. +/// +[UsedImplicitly, GenerateTypedNameReferences] +public sealed partial class GuideReagentEmbed : BoxContainer, IDocumentTag +{ + [Dependency] private readonly IEntitySystemManager _systemManager = default!; + [Dependency] private readonly IPrototypeManager _prototype = default!; + + private readonly ChemistryGuideDataSystem _chemistryGuideData; + + public GuideReagentEmbed() + { + RobustXamlLoader.Load(this); + IoCManager.InjectDependencies(this); + _chemistryGuideData = _systemManager.GetEntitySystem(); + MouseFilter = MouseFilterMode.Stop; + } + + public GuideReagentEmbed(string reagent) : this() + { + GenerateControl(_prototype.Index(reagent)); + } + + public GuideReagentEmbed(ReagentPrototype reagent) : this() + { + GenerateControl(reagent); + } + + public bool TryParseTag(Dictionary args, [NotNullWhen(true)] out Control? control) + { + control = null; + if (!args.TryGetValue("Reagent", out var id)) + { + Logger.Error("Reagent embed tag is missing reagent prototype argument"); + return false; + } + + if (!_prototype.TryIndex(id, out var reagent)) + { + Logger.Error($"Specified reagent prototype \"{id}\" is not a valid reagent prototype"); + return false; + } + + GenerateControl(reagent); + + control = this; + return true; + } + + private void GenerateControl(ReagentPrototype reagent) + { + NameBackground.PanelOverride = new StyleBoxFlat + { + BackgroundColor = reagent.SubstanceColor + }; + + var textColor = Color.ToHsl(reagent.SubstanceColor).Z > 0.45 + ? Color.Black + : Color.White; + + ReagentName.SetMarkup(Loc.GetString("guidebook-reagent-name", + ("color", textColor), ("name", reagent.LocalizedName))); + + #region Recipe + // by default, we assume that the reaction has the same ID as the reagent. + // if this isn't true, we'll loop through reactions. + if (!_prototype.TryIndex(reagent.ID, out var reactionPrototype)) + { + reactionPrototype = _prototype.EnumeratePrototypes() + .FirstOrDefault(p => p.Products.ContainsKey(reagent.ID)); + } + + if (reactionPrototype != null) + { + 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(); + ReactantsLabel.SetMessage(reactantMsg); + + var productMsg = new FormattedMessage(); + var productCount = reactionPrototype.Products.Count; + var u = 0; + foreach (var (product, ratio) in reactionPrototype.Products) + { + productMsg.AddMarkup(Loc.GetString("guidebook-reagent-recipes-reagent-display", + ("reagent", _prototype.Index(product).LocalizedName), ("ratio", ratio))); + u++; + if (u < productCount) + productMsg.PushNewline(); + } + productMsg.Pop(); + ProductsLabel.SetMessage(productMsg); + } + else + { + RecipesContainer.Visible = false; + } + #endregion + + #region Effects + if (_chemistryGuideData.ReagentGuideRegistry.TryGetValue(reagent.ID, out var guideEntryRegistry) && + guideEntryRegistry.GuideEntries != null && + guideEntryRegistry.GuideEntries.Values.Any(pair => pair.EffectDescriptions.Any())) + { + EffectsDescriptionContainer.Children.Clear(); + foreach (var (group, effect) in guideEntryRegistry.GuideEntries) + { + if (!effect.EffectDescriptions.Any()) + continue; + + var groupLabel = new RichTextLabel(); + groupLabel.SetMarkup(Loc.GetString("guidebook-reagent-effects-metabolism-group-rate", + ("group", group), ("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.AddMarkup(effectString); + i++; + if (i < descriptionsCount) + descMsg.PushNewline(); + } + descriptionLabel.SetMessage(descMsg); + + EffectsDescriptionContainer.AddChild(groupLabel); + EffectsDescriptionContainer.AddChild(descriptionLabel); + } + } + else + { + EffectsContainer.Visible = false; + } + #endregion + + FormattedMessage description = new(); + description.AddText(reagent.LocalizedDescription); + description.PushNewline(); + description.AddText(Loc.GetString("guidebook-reagent-physical-description", + ("description", reagent.LocalizedPhysicalDescription))); + ReagentDescription.SetMessage(description); + } +} diff --git a/Content.Client/Guidebook/Controls/GuideReagentGroupEmbed.xaml b/Content.Client/Guidebook/Controls/GuideReagentGroupEmbed.xaml new file mode 100644 index 0000000000..da671adaa7 --- /dev/null +++ b/Content.Client/Guidebook/Controls/GuideReagentGroupEmbed.xaml @@ -0,0 +1,4 @@ + + + diff --git a/Content.Client/Guidebook/Controls/GuideReagentGroupEmbed.xaml.cs b/Content.Client/Guidebook/Controls/GuideReagentGroupEmbed.xaml.cs new file mode 100644 index 0000000000..0c9356eccb --- /dev/null +++ b/Content.Client/Guidebook/Controls/GuideReagentGroupEmbed.xaml.cs @@ -0,0 +1,60 @@ +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Content.Client.Guidebook.Richtext; +using Content.Shared.Chemistry.Reagent; +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; + +namespace Content.Client.Guidebook.Controls; + +/// +/// Control for embedding a reagent into a guidebook. +/// +[UsedImplicitly, GenerateTypedNameReferences] +public sealed partial class GuideReagentGroupEmbed : BoxContainer, IDocumentTag +{ + [Dependency] private readonly IPrototypeManager _prototype = default!; + + public GuideReagentGroupEmbed() + { + RobustXamlLoader.Load(this); + IoCManager.InjectDependencies(this); + MouseFilter = MouseFilterMode.Stop; + } + + public GuideReagentGroupEmbed(string group) : this() + { + var prototypes = _prototype.EnumeratePrototypes() + .Where(p => p.Group.Equals(group)).OrderBy(p => p.LocalizedName); + foreach (var reagent in prototypes) + { + var embed = new GuideReagentEmbed(reagent); + GroupContainer.AddChild(embed); + } + } + + public bool TryParseTag(Dictionary args, [NotNullWhen(true)] out Control? control) + { + control = null; + if (!args.TryGetValue("Group", out var group)) + { + Logger.Error("Reagent group embed tag is missing group argument"); + return false; + } + + var prototypes = _prototype.EnumeratePrototypes() + .Where(p => p.Group.Equals(group)).OrderBy(p => p.LocalizedName); + foreach (var reagent in prototypes) + { + var embed = new GuideReagentEmbed(reagent); + GroupContainer.AddChild(embed); + } + + control = this; + return true; + } +} diff --git a/Content.Server/Chemistry/Commands/DumpReagentGuideText.cs b/Content.Server/Chemistry/Commands/DumpReagentGuideText.cs new file mode 100644 index 0000000000..70a79254d6 --- /dev/null +++ b/Content.Server/Chemistry/Commands/DumpReagentGuideText.cs @@ -0,0 +1,47 @@ +using Content.Server.Administration; +using Content.Shared.Administration; +using Content.Shared.Chemistry.Reagent; +using Robust.Shared.Console; +using Robust.Shared.Prototypes; + +namespace Content.Server.Chemistry.Commands; + +[AdminCommand(AdminFlags.Debug)] +public sealed class DumpReagentGuideText : IConsoleCommand +{ + [Dependency] private readonly IPrototypeManager _prototype = default!; + [Dependency] private readonly IEntitySystemManager _entSys = default!; + + public string Command => "dumpreagentguidetext"; + public string Description => "Dumps the guidebook text for a reagent to the console"; + public string Help => "dumpreagentguidetext "; + + public void Execute(IConsoleShell shell, string argStr, string[] args) + { + if (args.Length != 1) + { + shell.WriteError("Must have only 1 argument"); + return; + } + + if (!_prototype.TryIndex(args[0], out var reagent)) + { + shell.WriteError($"Invalid prototype: {args[0]}"); + return; + } + + if (reagent.Metabolisms is null) + { + shell.WriteLine("Nothing to dump."); + return; + } + + foreach (var (_, entry) in reagent.Metabolisms) + { + foreach (var effect in entry.Effects) + { + shell.WriteLine(effect.GuidebookEffectDescription(_prototype, _entSys) ?? $"[skipped effect of type {effect.GetType()}]"); + } + } + } +} diff --git a/Content.Server/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs b/Content.Server/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs new file mode 100644 index 0000000000..8cbdd82f07 --- /dev/null +++ b/Content.Server/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs @@ -0,0 +1,67 @@ +using Content.Shared.Chemistry; +using Content.Shared.Chemistry.Reagent; +using Robust.Server.Player; +using Robust.Shared.Enums; +using Robust.Shared.Prototypes; + +namespace Content.Server.Chemistry.EntitySystems; + + +public sealed class ChemistryGuideDataSystem : SharedChemistryGuideDataSystem +{ + [Dependency] private readonly IPlayerManager _player = default!; + + /// + public override void Initialize() + { + base.Initialize(); + + PrototypeManager.PrototypesReloaded += PrototypeManagerReload; + + _player.PlayerStatusChanged += OnPlayerStatusChanged; + + InitializeServerRegistry(); + } + + private void InitializeServerRegistry() + { + var changeset = new ReagentGuideChangeset(new Dictionary(), new HashSet()); + foreach (var proto in PrototypeManager.EnumeratePrototypes()) + { + var entry = new ReagentGuideEntry(proto, PrototypeManager, EntityManager.EntitySysManager); + changeset.GuideEntries.Add(proto.ID, entry); + Registry[proto.ID] = entry; + } + + var ev = new ReagentGuideRegistryChangedEvent(changeset); + RaiseNetworkEvent(ev); + } + + private void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e) + { + if (e.NewStatus != SessionStatus.Connected) + return; + + var sendEv = new ReagentGuideRegistryChangedEvent(new ReagentGuideChangeset(Registry, new HashSet())); + RaiseNetworkEvent(sendEv, e.Session); + } + + private void PrototypeManagerReload(PrototypesReloadedEventArgs obj) + { + if (!obj.ByType.TryGetValue(typeof(ReagentPrototype), out var reagents)) + return; + + var changeset = new ReagentGuideChangeset(new Dictionary(), new HashSet()); + + foreach (var (id, proto) in reagents.Modified) + { + var reagentProto = (ReagentPrototype) proto; + var entry = new ReagentGuideEntry(reagentProto, PrototypeManager, EntityManager.EntitySysManager); + changeset.GuideEntries.Add(id, entry); + Registry[id] = entry; + } + + var ev = new ReagentGuideRegistryChangedEvent(changeset); + RaiseNetworkEvent(ev); + } +} diff --git a/Content.Server/Chemistry/ReactionEffects/AreaReactionEffect.cs b/Content.Server/Chemistry/ReactionEffects/AreaReactionEffect.cs index 8db6ef2f93..8c1c3f4835 100644 --- a/Content.Server/Chemistry/ReactionEffects/AreaReactionEffect.cs +++ b/Content.Server/Chemistry/ReactionEffects/AreaReactionEffect.cs @@ -45,6 +45,10 @@ namespace Content.Server.Chemistry.ReactionEffects [DataField("sound", required: true)] private SoundSpecifier _sound = default!; public override bool ShouldLog => true; + + protected override string ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + => Loc.GetString("reagent-effect-guidebook-missing"); + public override LogImpact LogImpact => LogImpact.High; public override void Effect(ReagentEffectArgs args) diff --git a/Content.Server/Chemistry/ReactionEffects/CreateEntityReactionEffect.cs b/Content.Server/Chemistry/ReactionEffects/CreateEntityReactionEffect.cs index 52a00399c4..e87b4ca771 100644 --- a/Content.Server/Chemistry/ReactionEffects/CreateEntityReactionEffect.cs +++ b/Content.Server/Chemistry/ReactionEffects/CreateEntityReactionEffect.cs @@ -19,6 +19,12 @@ public sealed class CreateEntityReactionEffect : ReagentEffect [DataField("number")] public uint Number = 1; + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + => Loc.GetString("reagent-effect-guidebook-create-entity-reaction-effect", + ("chance", Probability), + ("entname", IoCManager.Resolve().Index(Entity).Name), + ("amount", Number)); + public override void Effect(ReagentEffectArgs args) { var transform = args.EntityManager.GetComponent(args.SolutionEntity); diff --git a/Content.Server/Chemistry/ReactionEffects/ExplosionReactionEffect.cs b/Content.Server/Chemistry/ReactionEffects/ExplosionReactionEffect.cs index 0230949bad..7b5c0bfce7 100644 --- a/Content.Server/Chemistry/ReactionEffects/ExplosionReactionEffect.cs +++ b/Content.Server/Chemistry/ReactionEffects/ExplosionReactionEffect.cs @@ -3,6 +3,7 @@ using Content.Server.Explosion.EntitySystems; using Content.Shared.Chemistry.Reagent; using Content.Shared.Database; using Content.Shared.Explosion; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Server.Chemistry.ReactionEffects @@ -24,7 +25,7 @@ namespace Content.Server.Chemistry.ReactionEffects [DataField("maxIntensity")] [JsonIgnore] public float MaxIntensity = 5; - + /// /// How quickly intensity drops off as you move away from the epicenter /// @@ -51,6 +52,9 @@ namespace Content.Server.Chemistry.ReactionEffects public float IntensityPerUnit = 1; public override bool ShouldLog => true; + + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + => Loc.GetString("reagent-effect-guidebook-explosion-reaction-effect", ("chance", Probability)); public override LogImpact LogImpact => LogImpact.High; public override void Effect(ReagentEffectArgs args) diff --git a/Content.Server/Chemistry/ReactionEffects/SmokeAreaReactionEffect.cs b/Content.Server/Chemistry/ReactionEffects/SmokeAreaReactionEffect.cs new file mode 100644 index 0000000000..5f282702bb --- /dev/null +++ b/Content.Server/Chemistry/ReactionEffects/SmokeAreaReactionEffect.cs @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Content.Server/Chemistry/ReactionEffects/SolutionTemperatureEffects.cs b/Content.Server/Chemistry/ReactionEffects/SolutionTemperatureEffects.cs index 4d30ec4643..d768935466 100644 --- a/Content.Server/Chemistry/ReactionEffects/SolutionTemperatureEffects.cs +++ b/Content.Server/Chemistry/ReactionEffects/SolutionTemperatureEffects.cs @@ -16,6 +16,10 @@ namespace Content.Server.Chemistry.ReactionEffects /// [DataField("temperature", required: true)] private float _temperature; + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + => Loc.GetString("reagent-effect-guidebook-set-solution-temperature-effect", + ("chance", Probability), ("temperature", _temperature)); + public override void Effect(ReagentEffectArgs args) { var solution = args.Source; @@ -52,6 +56,10 @@ namespace Content.Server.Chemistry.ReactionEffects /// [DataField("scaled")] private bool _scaled; + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + => Loc.GetString("reagent-effect-guidebook-adjust-solution-temperature-effect", + ("chance", Probability), ("deltasign", MathF.Sign(_delta)), ("mintemp", _minTemp), ("maxtemp", _maxTemp)); + public override void Effect(ReagentEffectArgs args) { var solution = args.Source; @@ -101,11 +109,15 @@ namespace Content.Server.Chemistry.ReactionEffects var heatCap = solution.GetHeatCapacity(null); var deltaT = _scaled - ? _delta / heatCap * (float) args.Quantity + ? _delta / heatCap * (float) args.Quantity : _delta / heatCap; solution.Temperature = Math.Clamp(solution.Temperature + deltaT, _minTemp, _maxTemp); } + + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + => Loc.GetString("reagent-effect-guidebook-adjust-solution-temperature-effect", + ("chance", Probability), ("deltasign", MathF.Sign(_delta)), ("mintemp", _minTemp), ("maxtemp", _maxTemp)); } } diff --git a/Content.Server/Chemistry/ReagentEffectConditions/BodyTemperature.cs b/Content.Server/Chemistry/ReagentEffectConditions/BodyTemperature.cs index 313d1eb629..057d2ebdb8 100644 --- a/Content.Server/Chemistry/ReagentEffectConditions/BodyTemperature.cs +++ b/Content.Server/Chemistry/ReagentEffectConditions/BodyTemperature.cs @@ -1,5 +1,6 @@ using Content.Server.Temperature.Components; using Content.Shared.Chemistry.Reagent; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffectConditions { @@ -13,7 +14,7 @@ namespace Content.Server.Chemistry.ReagentEffectConditions public float Min = 0; [DataField("max")] - public float Max = float.MaxValue; + public float Max = float.PositiveInfinity; public override bool Condition(ReagentEffectArgs args) { if (args.EntityManager.TryGetComponent(args.SolutionEntity, out TemperatureComponent? temp)) @@ -24,5 +25,12 @@ namespace Content.Server.Chemistry.ReagentEffectConditions return false; } + + public override string GuidebookExplanation(IPrototypeManager prototype) + { + return Loc.GetString("reagent-effect-condition-guidebook-body-temperature", + ("max", float.IsPositiveInfinity(Max) ? (float) int.MaxValue : Max), + ("min", Min)); + } } } diff --git a/Content.Server/Chemistry/ReagentEffectConditions/HasTagCondition.cs b/Content.Server/Chemistry/ReagentEffectConditions/HasTagCondition.cs index 2c57bda77e..dccf4f33eb 100644 --- a/Content.Server/Chemistry/ReagentEffectConditions/HasTagCondition.cs +++ b/Content.Server/Chemistry/ReagentEffectConditions/HasTagCondition.cs @@ -1,6 +1,7 @@ using Content.Shared.Chemistry.Reagent; using Content.Shared.Tag; using JetBrains.Annotations; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Server.Chemistry.ReagentEffectConditions; @@ -21,4 +22,10 @@ public sealed class HasTag : ReagentEffectCondition return false; } + + public override string GuidebookExplanation(IPrototypeManager prototype) + { + // this should somehow be made (much) nicer. + return Loc.GetString("reagent-effect-condition-guidebook-has-tag", ("tag", Tag), ("invert", Invert)); + } } diff --git a/Content.Server/Chemistry/ReagentEffectConditions/MobStateCondition.cs b/Content.Server/Chemistry/ReagentEffectConditions/MobStateCondition.cs index 45d8ddda07..b76e8fac3c 100644 --- a/Content.Server/Chemistry/ReagentEffectConditions/MobStateCondition.cs +++ b/Content.Server/Chemistry/ReagentEffectConditions/MobStateCondition.cs @@ -1,6 +1,7 @@ using Content.Shared.Chemistry.Reagent; using Content.Shared.Mobs; using Content.Shared.Mobs.Components; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffectConditions { @@ -21,6 +22,11 @@ namespace Content.Server.Chemistry.ReagentEffectConditions return false; } + + public override string GuidebookExplanation(IPrototypeManager prototype) + { + return Loc.GetString("reagent-effect-condition-guidebook-mob-state-condition", ("state", mobstate)); + } } } diff --git a/Content.Server/Chemistry/ReagentEffectConditions/OrganType.cs b/Content.Server/Chemistry/ReagentEffectConditions/OrganType.cs index d494b07089..cbb0ec2f52 100644 --- a/Content.Server/Chemistry/ReagentEffectConditions/OrganType.cs +++ b/Content.Server/Chemistry/ReagentEffectConditions/OrganType.cs @@ -1,6 +1,7 @@ using Content.Server.Body.Components; using Content.Shared.Body.Prototypes; using Content.Shared.Chemistry.Reagent; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Server.Chemistry.ReagentEffectConditions @@ -30,5 +31,12 @@ namespace Content.Server.Chemistry.ReagentEffectConditions return ShouldHave; return !ShouldHave; } + + public override string GuidebookExplanation(IPrototypeManager prototype) + { + return Loc.GetString("reagent-effect-condition-guidebook-organ-type", + ("name", prototype.Index(Type).Name), + ("shouldhave", ShouldHave)); + } } } diff --git a/Content.Server/Chemistry/ReagentEffectConditions/ReagentThreshold.cs b/Content.Server/Chemistry/ReagentEffectConditions/ReagentThreshold.cs index c97b29a94c..befefd1f53 100644 --- a/Content.Server/Chemistry/ReagentEffectConditions/ReagentThreshold.cs +++ b/Content.Server/Chemistry/ReagentEffectConditions/ReagentThreshold.cs @@ -1,5 +1,6 @@ using Content.Shared.Chemistry.Reagent; using Content.Shared.FixedPoint; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffectConditions { @@ -35,5 +36,17 @@ namespace Content.Server.Chemistry.ReagentEffectConditions return quant >= Min && quant <= Max; } + + public override string GuidebookExplanation(IPrototypeManager prototype) + { + ReagentPrototype? reagentProto = null; + if (Reagent is not null) + prototype.TryIndex(Reagent, out reagentProto); + + return Loc.GetString("reagent-effect-condition-guidebook-reagent-threshold", + ("reagent", reagentProto?.LocalizedName ?? "this reagent"), + ("max", Max == FixedPoint2.MaxValue ? (float) int.MaxValue : Max.Float()), + ("min", Min.Float())); + } } } diff --git a/Content.Server/Chemistry/ReagentEffectConditions/SolutionTemperature.cs b/Content.Server/Chemistry/ReagentEffectConditions/SolutionTemperature.cs index da646fb1c7..6b370fb9a4 100644 --- a/Content.Server/Chemistry/ReagentEffectConditions/SolutionTemperature.cs +++ b/Content.Server/Chemistry/ReagentEffectConditions/SolutionTemperature.cs @@ -1,4 +1,5 @@ using Content.Shared.Chemistry.Reagent; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffectConditions { @@ -24,5 +25,12 @@ namespace Content.Server.Chemistry.ReagentEffectConditions return true; } + + public override string GuidebookExplanation(IPrototypeManager prototype) + { + return Loc.GetString("reagent-effect-condition-guidebook-solution-temperature", + ("max", float.IsPositiveInfinity(Max) ? (float) int.MaxValue : Max), + ("min", Min)); + } } } diff --git a/Content.Server/Chemistry/ReagentEffectConditions/TotalDamage.cs b/Content.Server/Chemistry/ReagentEffectConditions/TotalDamage.cs index 4758bccea5..8c62dd7ce0 100644 --- a/Content.Server/Chemistry/ReagentEffectConditions/TotalDamage.cs +++ b/Content.Server/Chemistry/ReagentEffectConditions/TotalDamage.cs @@ -1,6 +1,7 @@ using Content.Shared.Chemistry.Reagent; using Content.Shared.Damage; using Content.Shared.FixedPoint; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffectConditions { @@ -23,5 +24,12 @@ namespace Content.Server.Chemistry.ReagentEffectConditions return false; } + + public override string GuidebookExplanation(IPrototypeManager prototype) + { + return Loc.GetString("reagent-effect-condition-guidebook-total-damage", + ("max", Max == FixedPoint2.MaxValue ? (float) int.MaxValue : Max.Float()), + ("min", Min.Float())); + } } } diff --git a/Content.Server/Chemistry/ReagentEffects/ActivateArtifact.cs b/Content.Server/Chemistry/ReagentEffects/ActivateArtifact.cs index 04ae4ca6f5..bd89e8ec45 100644 --- a/Content.Server/Chemistry/ReagentEffects/ActivateArtifact.cs +++ b/Content.Server/Chemistry/ReagentEffects/ActivateArtifact.cs @@ -1,5 +1,6 @@ using Content.Server.Xenoarchaeology.XenoArtifacts; using Content.Shared.Chemistry.Reagent; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffects; @@ -10,4 +11,7 @@ public sealed class ActivateArtifact : ReagentEffect var artifact = args.EntityManager.EntitySysManager.GetEntitySystem(); artifact.TryActivateArtifact(args.SolutionEntity); } + + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => + Loc.GetString("reagent-effect-guidebook-activate-artifact", ("chance", Probability)); } diff --git a/Content.Server/Chemistry/ReagentEffects/AddToSolutionReaction.cs b/Content.Server/Chemistry/ReagentEffects/AddToSolutionReaction.cs index f687f19e7d..5ec0b2a08b 100644 --- a/Content.Server/Chemistry/ReagentEffects/AddToSolutionReaction.cs +++ b/Content.Server/Chemistry/ReagentEffects/AddToSolutionReaction.cs @@ -1,6 +1,7 @@ using Content.Server.Chemistry.EntitySystems; using Content.Shared.Chemistry.Reagent; using JetBrains.Annotations; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffects { @@ -24,5 +25,8 @@ namespace Content.Server.Chemistry.ReagentEffects .TryAddReagent(args.SolutionEntity, solutionContainer, args.Reagent.ID, args.Quantity, out var accepted)) args.Source?.RemoveReagent(args.Reagent.ID, accepted); } + + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => + Loc.GetString("reagent-effect-guidebook-missing", ("chance", Probability)); } } diff --git a/Content.Server/Chemistry/ReagentEffects/AdjustAlert.cs b/Content.Server/Chemistry/ReagentEffects/AdjustAlert.cs index 44f33a6bb5..acae2e0153 100644 --- a/Content.Server/Chemistry/ReagentEffects/AdjustAlert.cs +++ b/Content.Server/Chemistry/ReagentEffects/AdjustAlert.cs @@ -1,5 +1,6 @@ using Content.Shared.Alert; using Content.Shared.Chemistry.Reagent; +using Robust.Shared.Prototypes; using Robust.Shared.Timing; namespace Content.Server.Chemistry.ReagentEffects; @@ -18,6 +19,9 @@ public sealed class AdjustAlert : ReagentEffect [DataField("time")] public float Time; + //JUSTIFICATION: This just changes some visuals, doesn't need to be documented. + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => null; + public override void Effect(ReagentEffectArgs args) { var alertSys = EntitySystem.Get(); diff --git a/Content.Server/Chemistry/ReagentEffects/AdjustReagent.cs b/Content.Server/Chemistry/ReagentEffects/AdjustReagent.cs index 7e716928ec..c29459b30f 100644 --- a/Content.Server/Chemistry/ReagentEffects/AdjustReagent.cs +++ b/Content.Server/Chemistry/ReagentEffects/AdjustReagent.cs @@ -60,5 +60,27 @@ namespace Content.Server.Chemistry.ReagentEffects } } } + + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + { + if (Reagent is not null && prototype.TryIndex(Reagent, out ReagentPrototype? reagentProto)) + { + return Loc.GetString("reagent-effect-guidebook-adjust-reagent-reagent", + ("chance", Probability), + ("deltasign", MathF.Sign(Amount.Float())), + ("reagent", reagentProto.LocalizedName), + ("amount", MathF.Abs(Amount.Float()))); + } + else if (Group is not null && prototype.TryIndex(Group, out MetabolismGroupPrototype? groupProto)) + { + return Loc.GetString("reagent-effect-guidebook-adjust-reagent-group", + ("chance", Probability), + ("deltasign", MathF.Sign(Amount.Float())), + ("group", groupProto.ID), + ("amount", MathF.Abs(Amount.Float()))); + } + + throw new NotImplementedException(); + } } } diff --git a/Content.Server/Chemistry/ReagentEffects/AdjustTemperature.cs b/Content.Server/Chemistry/ReagentEffects/AdjustTemperature.cs index 45c07fa2a3..b96d2a0469 100644 --- a/Content.Server/Chemistry/ReagentEffects/AdjustTemperature.cs +++ b/Content.Server/Chemistry/ReagentEffects/AdjustTemperature.cs @@ -1,6 +1,7 @@ using Content.Server.Temperature.Components; using Content.Server.Temperature.Systems; using Content.Shared.Chemistry.Reagent; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffects { @@ -9,6 +10,12 @@ namespace Content.Server.Chemistry.ReagentEffects [DataField("amount")] public float Amount; + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + => Loc.GetString("reagent-effect-guidebook-adjust-temperature", + ("chance", Probability), + ("deltasign", MathF.Sign(Amount)), + ("amount", MathF.Abs(Amount))); + public override void Effect(ReagentEffectArgs args) { if (args.EntityManager.TryGetComponent(args.SolutionEntity, out TemperatureComponent? temp)) diff --git a/Content.Server/Chemistry/ReagentEffects/ChemCleanBoodstream.cs b/Content.Server/Chemistry/ReagentEffects/ChemCleanBoodstream.cs index 376398d7b7..132315663f 100644 --- a/Content.Server/Chemistry/ReagentEffects/ChemCleanBoodstream.cs +++ b/Content.Server/Chemistry/ReagentEffects/ChemCleanBoodstream.cs @@ -1,6 +1,7 @@ using Content.Shared.Chemistry.Reagent; using JetBrains.Annotations; using Content.Server.Body.Systems; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReactionEffects { @@ -12,6 +13,10 @@ namespace Content.Server.Chemistry.ReactionEffects { [DataField("cleanseRate")] public float CleanseRate = 3.0f; + + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + => Loc.GetString("reagent-effect-guidebook-chem-clean-bloodstream", ("chance", Probability)); + public override void Effect(ReagentEffectArgs args) { if (args.Source == null || args.Reagent == null) diff --git a/Content.Server/Chemistry/ReagentEffects/ChemHealEyeDamage.cs b/Content.Server/Chemistry/ReagentEffects/ChemHealEyeDamage.cs index 0826e99110..f95c52ba40 100644 --- a/Content.Server/Chemistry/ReagentEffects/ChemHealEyeDamage.cs +++ b/Content.Server/Chemistry/ReagentEffects/ChemHealEyeDamage.cs @@ -2,6 +2,7 @@ using Content.Shared.Chemistry.Reagent; using Content.Shared.Eye.Blinding; using Content.Shared.Eye.Blinding.Systems; using JetBrains.Annotations; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffects { @@ -17,6 +18,9 @@ namespace Content.Server.Chemistry.ReagentEffects [DataField("amount")] public int Amount = -1; + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + => Loc.GetString("reagent-effect-guidebook-cure-eye-damage", ("chance", Probability), ("deltasign", MathF.Sign(Amount))); + public override void Effect(ReagentEffectArgs args) { if (args.Scale != 1f) // huh? diff --git a/Content.Server/Chemistry/ReagentEffects/ChemVomit.cs b/Content.Server/Chemistry/ReagentEffects/ChemVomit.cs index 8e923e06bf..74ecfefff4 100644 --- a/Content.Server/Chemistry/ReagentEffects/ChemVomit.cs +++ b/Content.Server/Chemistry/ReagentEffects/ChemVomit.cs @@ -1,6 +1,7 @@ using Content.Shared.Chemistry.Reagent; using Content.Server.Medical; using JetBrains.Annotations; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffects { @@ -17,6 +18,9 @@ namespace Content.Server.Chemistry.ReagentEffects [DataField("hungerAmount")] public float HungerAmount = -40f; + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + => Loc.GetString("reagent-effect-guidebook-chem-vomit", ("chance", Probability)); + public override void Effect(ReagentEffectArgs args) { if (args.Scale != 1f) diff --git a/Content.Server/Chemistry/ReagentEffects/CreateGas.cs b/Content.Server/Chemistry/ReagentEffects/CreateGas.cs index a2a0c61124..0778c0727f 100644 --- a/Content.Server/Chemistry/ReagentEffects/CreateGas.cs +++ b/Content.Server/Chemistry/ReagentEffects/CreateGas.cs @@ -2,6 +2,7 @@ using Content.Shared.Atmos; using Content.Shared.Chemistry.Reagent; using Content.Shared.Database; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffects; @@ -17,6 +18,17 @@ public sealed class CreateGas : ReagentEffect public float Multiplier = 3f; public override bool ShouldLog => true; + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + { + var atmos = entSys.GetEntitySystem(); + var gasProto = atmos.GetGas(Gas); + + return Loc.GetString("reagent-effect-guidebook-create-gas", + ("chance", Probability), + ("moles", Multiplier), + ("gas", gasProto.Name)); + } + public override LogImpact LogImpact => LogImpact.High; public override void Effect(ReagentEffectArgs args) diff --git a/Content.Server/Chemistry/ReagentEffects/Drunk.cs b/Content.Server/Chemistry/ReagentEffects/Drunk.cs index c5d24e362d..dedf984b2b 100644 --- a/Content.Server/Chemistry/ReagentEffects/Drunk.cs +++ b/Content.Server/Chemistry/ReagentEffects/Drunk.cs @@ -1,5 +1,6 @@ using Content.Shared.Chemistry.Reagent; using Content.Shared.Drunk; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffects; @@ -17,6 +18,9 @@ public sealed class Drunk : ReagentEffect [DataField("slurSpeech")] public bool SlurSpeech = true; + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + => Loc.GetString("reagent-effect-guidebook-drunk", ("chance", Probability)); + public override void Effect(ReagentEffectArgs args) { var boozePower = BoozePower; diff --git a/Content.Server/Chemistry/ReagentEffects/Electrocute.cs b/Content.Server/Chemistry/ReagentEffects/Electrocute.cs index 08b2df966e..b6d2d58e28 100644 --- a/Content.Server/Chemistry/ReagentEffects/Electrocute.cs +++ b/Content.Server/Chemistry/ReagentEffects/Electrocute.cs @@ -1,5 +1,6 @@ using Content.Server.Electrocution; using Content.Shared.Chemistry.Reagent; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffects; @@ -14,6 +15,9 @@ public sealed class Electrocute : ReagentEffect /// [DataField("refresh")] public bool Refresh = true; + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + => Loc.GetString("reagent-effect-guidebook-electrocute", ("chance", Probability), ("time", ElectrocuteTime)); + public override bool ShouldLog => true; public override void Effect(ReagentEffectArgs args) diff --git a/Content.Server/Chemistry/ReagentEffects/Emote.cs b/Content.Server/Chemistry/ReagentEffects/Emote.cs index fa3cf937d0..753435a599 100644 --- a/Content.Server/Chemistry/ReagentEffects/Emote.cs +++ b/Content.Server/Chemistry/ReagentEffects/Emote.cs @@ -2,6 +2,7 @@ using Content.Server.Chat.Systems; using Content.Shared.Chat.Prototypes; using Content.Shared.Chemistry.Reagent; using JetBrains.Annotations; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Server.Chemistry.ReagentEffects; @@ -18,6 +19,10 @@ public sealed class Emote : ReagentEffect [DataField("showInChat")] public bool ShowInChat; + // JUSTIFICATION: Emoting is flavor, so same reason popup messages are not in here. + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + => null; + public override void Effect(ReagentEffectArgs args) { if (EmoteId == null) diff --git a/Content.Server/Chemistry/ReagentEffects/ExtinguishReaction.cs b/Content.Server/Chemistry/ReagentEffects/ExtinguishReaction.cs index 6b7c56518a..eb2aefd444 100644 --- a/Content.Server/Chemistry/ReagentEffects/ExtinguishReaction.cs +++ b/Content.Server/Chemistry/ReagentEffects/ExtinguishReaction.cs @@ -2,12 +2,16 @@ using Content.Server.Atmos.Components; using Content.Server.Atmos.EntitySystems; using Content.Shared.Chemistry.Reagent; using JetBrains.Annotations; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffects { [UsedImplicitly] public sealed class ExtinguishReaction : ReagentEffect { + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + => Loc.GetString("reagent-effect-guidebook-extinguish-reaction", ("chance", Probability)); + public override void Effect(ReagentEffectArgs args) { if (!args.EntityManager.TryGetComponent(args.SolutionEntity, out FlammableComponent? flammable)) return; diff --git a/Content.Server/Chemistry/ReagentEffects/FlammableReaction.cs b/Content.Server/Chemistry/ReagentEffects/FlammableReaction.cs index 54d3689135..0cf28d1ac1 100644 --- a/Content.Server/Chemistry/ReagentEffects/FlammableReaction.cs +++ b/Content.Server/Chemistry/ReagentEffects/FlammableReaction.cs @@ -3,6 +3,7 @@ using Content.Server.Atmos.EntitySystems; using Content.Shared.Chemistry.Reagent; using Content.Shared.Database; using JetBrains.Annotations; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffects { @@ -13,6 +14,10 @@ namespace Content.Server.Chemistry.ReagentEffects public float Multiplier = 0.05f; public override bool ShouldLog => true; + + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + => Loc.GetString("reagent-effect-guidebook-flammable-reaction", ("chance", Probability)); + public override LogImpact LogImpact => LogImpact.Medium; public override void Effect(ReagentEffectArgs args) diff --git a/Content.Server/Chemistry/ReagentEffects/HealthChange.cs b/Content.Server/Chemistry/ReagentEffects/HealthChange.cs index ec5ffa32ab..59f11695fa 100644 --- a/Content.Server/Chemistry/ReagentEffects/HealthChange.cs +++ b/Content.Server/Chemistry/ReagentEffects/HealthChange.cs @@ -1,8 +1,11 @@ +using System.Linq; using System.Text.Json.Serialization; using Content.Shared.Chemistry.Reagent; using Content.Shared.Damage; using Content.Shared.FixedPoint; +using Content.Shared.Localizations; using JetBrains.Annotations; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffects { @@ -31,6 +34,38 @@ namespace Content.Server.Chemistry.ReagentEffects [JsonPropertyName("ignoreResistances")] public bool IgnoreResistances = true; + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + { + var damages = new List(); + var heals = false; + var deals = false; + + // TODO: This should be smarter. Namely, not showing a damage type as being in a group unless every damage type in the group is present and equal in value. + foreach (var (kind, amount) in Damage.GetDamagePerGroup()) + { + var sign = MathF.Sign(amount.Float()); + + if (sign < 0) + heals = true; + if (sign > 0) + deals = true; + + damages.Add( + Loc.GetString("health-change-display", + ("kind", kind), + ("amount", MathF.Abs(amount.Float())), + ("deltasign", sign) + )); + } + + var healsordeals = heals ? (deals ? "both" : "heals") : (deals ? "deals" : "none"); + + return Loc.GetString("reagent-effect-guidebook-health-change", + ("chance", Probability), + ("changes", ContentLocalizationManager.FormatList(damages)), + ("healsordeals", healsordeals)); + } + public override void Effect(ReagentEffectArgs args) { var scale = ScaleByQuantity ? args.Quantity : FixedPoint2.New(1); diff --git a/Content.Server/Chemistry/ReagentEffects/Ignite.cs b/Content.Server/Chemistry/ReagentEffects/Ignite.cs index 5eb19297b4..c24183bbde 100644 --- a/Content.Server/Chemistry/ReagentEffects/Ignite.cs +++ b/Content.Server/Chemistry/ReagentEffects/Ignite.cs @@ -1,6 +1,7 @@ using Content.Server.Atmos.EntitySystems; using Content.Shared.Chemistry.Reagent; using Content.Shared.Database; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffects; @@ -10,6 +11,10 @@ namespace Content.Server.Chemistry.ReagentEffects; public sealed class Ignite : ReagentEffect { public override bool ShouldLog => true; + + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + => Loc.GetString("reagent-effect-guidebook-ignite", ("chance", Probability)); + public override LogImpact LogImpact => LogImpact.Medium; public override void Effect(ReagentEffectArgs args) diff --git a/Content.Server/Chemistry/ReagentEffects/MakeSentient.cs b/Content.Server/Chemistry/ReagentEffects/MakeSentient.cs index 93684df7d7..5919ae3edb 100644 --- a/Content.Server/Chemistry/ReagentEffects/MakeSentient.cs +++ b/Content.Server/Chemistry/ReagentEffects/MakeSentient.cs @@ -2,11 +2,16 @@ using Content.Server.Ghost.Roles.Components; using Content.Server.Mind.Components; using Content.Server.Speech.Components; using Content.Shared.Chemistry.Reagent; +using Content.Server.Ghost.Roles.Components; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffects; public sealed class MakeSentient : ReagentEffect { + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + => Loc.GetString("reagent-effect-guidebook-make-sentient", ("chance", Probability)); + public override void Effect(ReagentEffectArgs args) { var entityManager = args.EntityManager; diff --git a/Content.Server/Chemistry/ReagentEffects/ModifyBleedAmount.cs b/Content.Server/Chemistry/ReagentEffects/ModifyBleedAmount.cs index a80a4d8868..f50bcc4a27 100644 --- a/Content.Server/Chemistry/ReagentEffects/ModifyBleedAmount.cs +++ b/Content.Server/Chemistry/ReagentEffects/ModifyBleedAmount.cs @@ -1,6 +1,7 @@ using Content.Server.Body.Components; using Content.Server.Body.Systems; using Content.Shared.Chemistry.Reagent; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffects; @@ -12,6 +13,10 @@ public sealed class ModifyBleedAmount : ReagentEffect [DataField("amount")] public float Amount = -1.0f; + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + => Loc.GetString("reagent-effect-guidebook-modify-bleed-amount", ("chance", Probability), + ("deltasign", MathF.Sign(Amount))); + public override void Effect(ReagentEffectArgs args) { if (args.EntityManager.TryGetComponent(args.SolutionEntity, out var blood)) diff --git a/Content.Server/Chemistry/ReagentEffects/ModifyBloodLevel.cs b/Content.Server/Chemistry/ReagentEffects/ModifyBloodLevel.cs index f5125fcce3..6a125436a2 100644 --- a/Content.Server/Chemistry/ReagentEffects/ModifyBloodLevel.cs +++ b/Content.Server/Chemistry/ReagentEffects/ModifyBloodLevel.cs @@ -2,6 +2,7 @@ using Content.Server.Body.Systems; using Content.Shared.Chemistry.Reagent; using Content.Shared.FixedPoint; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffects; @@ -13,6 +14,10 @@ public sealed class ModifyBloodLevel : ReagentEffect [DataField("amount")] public FixedPoint2 Amount = 1.0f; + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + => Loc.GetString("reagent-effect-guidebook-modify-blood-level", ("chance", Probability), + ("deltasign", MathF.Sign(Amount.Float()))); + public override void Effect(ReagentEffectArgs args) { if (args.EntityManager.TryGetComponent(args.SolutionEntity, out var blood)) diff --git a/Content.Server/Chemistry/ReagentEffects/ModifyLungGas.cs b/Content.Server/Chemistry/ReagentEffects/ModifyLungGas.cs index 63ab04bd66..7cecac7e6b 100644 --- a/Content.Server/Chemistry/ReagentEffects/ModifyLungGas.cs +++ b/Content.Server/Chemistry/ReagentEffects/ModifyLungGas.cs @@ -1,6 +1,7 @@ using Content.Server.Body.Components; using Content.Shared.Atmos; using Content.Shared.Chemistry.Reagent; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffects; @@ -9,6 +10,10 @@ public sealed class ModifyLungGas : ReagentEffect [DataField("ratios", required: true)] private Dictionary _ratios = default!; + // JUSTIFICATION: This is internal magic that players never directly interact with. + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + => null; + public override void Effect(ReagentEffectArgs args) { if (args.EntityManager.TryGetComponent(args.OrganEntity, out var lung)) diff --git a/Content.Server/Chemistry/ReagentEffects/MovespeedModifier.cs b/Content.Server/Chemistry/ReagentEffects/MovespeedModifier.cs index 9026c03a60..6564346b87 100644 --- a/Content.Server/Chemistry/ReagentEffects/MovespeedModifier.cs +++ b/Content.Server/Chemistry/ReagentEffects/MovespeedModifier.cs @@ -1,6 +1,7 @@ using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Reagent; using Content.Shared.Movement.Systems; +using Robust.Shared.Prototypes; using Robust.Shared.Timing; namespace Content.Server.Chemistry.ReagentEffects @@ -29,6 +30,14 @@ namespace Content.Server.Chemistry.ReagentEffects [DataField("statusLifetime")] public float StatusLifetime = 2f; + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + { + return Loc.GetString("reagent-effect-guidebook-movespeed-modifier", + ("chance", Probability), + ("walkspeed", WalkSpeedModifier), + ("time", StatusLifetime)); + } + /// /// Remove reagent at set rate, changes the movespeed modifiers and adds a MovespeedModifierMetabolismComponent if not already there. /// diff --git a/Content.Server/Chemistry/ReagentEffects/Oxygenate.cs b/Content.Server/Chemistry/ReagentEffects/Oxygenate.cs index 4fa6c834e8..f642c1c8a6 100644 --- a/Content.Server/Chemistry/ReagentEffects/Oxygenate.cs +++ b/Content.Server/Chemistry/ReagentEffects/Oxygenate.cs @@ -1,6 +1,7 @@ using Content.Server.Body.Components; using Content.Server.Body.Systems; using Content.Shared.Chemistry.Reagent; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffects; @@ -9,6 +10,10 @@ public sealed class Oxygenate : ReagentEffect [DataField("factor")] public float Factor = 1f; + // JUSTIFICATION: This is internal magic that players never directly interact with. + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + => null; + public override void Effect(ReagentEffectArgs args) { if (args.EntityManager.TryGetComponent(args.SolutionEntity, out var resp)) diff --git a/Content.Server/Chemistry/ReagentEffects/Paralyze.cs b/Content.Server/Chemistry/ReagentEffects/Paralyze.cs index 60ffe022f1..8a27de9b07 100644 --- a/Content.Server/Chemistry/ReagentEffects/Paralyze.cs +++ b/Content.Server/Chemistry/ReagentEffects/Paralyze.cs @@ -1,5 +1,6 @@ using Content.Shared.Chemistry.Reagent; using Content.Server.Stunnable; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffects; @@ -12,6 +13,11 @@ public sealed class Paralyze : ReagentEffect /// [DataField("refresh")] public bool Refresh = true; + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + => Loc.GetString("reagent-effect-guidebook-paralyze", + ("chance", Probability), + ("time", ParalyzeTime)); + public override void Effect(ReagentEffectArgs args) { var paralyzeTime = ParalyzeTime; diff --git a/Content.Server/Chemistry/ReagentEffects/PlantMetabolism/PlantAdjustAttribute.cs b/Content.Server/Chemistry/ReagentEffects/PlantMetabolism/PlantAdjustAttribute.cs index b6b59ff213..e8146d0bcc 100644 --- a/Content.Server/Chemistry/ReagentEffects/PlantMetabolism/PlantAdjustAttribute.cs +++ b/Content.Server/Chemistry/ReagentEffects/PlantMetabolism/PlantAdjustAttribute.cs @@ -1,6 +1,7 @@ using System.Diagnostics.CodeAnalysis; using Content.Server.Botany.Components; using Content.Shared.Chemistry.Reagent; +using Robust.Shared.Prototypes; using Robust.Shared.Random; namespace Content.Server.Chemistry.ReagentEffects.PlantMetabolism @@ -35,5 +36,7 @@ namespace Content.Server.Chemistry.ReagentEffects.PlantMetabolism // Dependencies are never injected for reagents if you intend to do that for this. return !(Prob <= 0f) && IoCManager.Resolve().Prob(Prob); } + + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => Loc.GetString("reagent-effect-guidebook-missing", ("chance", Probability)); } } diff --git a/Content.Server/Chemistry/ReagentEffects/PlantMetabolism/PlantCryoxadone.cs b/Content.Server/Chemistry/ReagentEffects/PlantMetabolism/PlantCryoxadone.cs index 3585f99622..127690ed75 100644 --- a/Content.Server/Chemistry/ReagentEffects/PlantMetabolism/PlantCryoxadone.cs +++ b/Content.Server/Chemistry/ReagentEffects/PlantMetabolism/PlantCryoxadone.cs @@ -1,6 +1,7 @@ using Content.Server.Botany.Components; using Content.Shared.Chemistry.Reagent; using JetBrains.Annotations; +using Robust.Shared.Prototypes; using Robust.Shared.Random; namespace Content.Server.Chemistry.ReagentEffects.PlantMetabolism @@ -26,5 +27,7 @@ namespace Content.Server.Chemistry.ReagentEffects.PlantMetabolism plantHolderComp.SkipAging++; plantHolderComp.ForceUpdate = true; } + + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => Loc.GetString("reagent-effect-guidebook-missing", ("chance", Probability)); } } diff --git a/Content.Server/Chemistry/ReagentEffects/PlantMetabolism/PlantDiethylamine.cs b/Content.Server/Chemistry/ReagentEffects/PlantMetabolism/PlantDiethylamine.cs index b913bd2270..dbba70dfff 100644 --- a/Content.Server/Chemistry/ReagentEffects/PlantMetabolism/PlantDiethylamine.cs +++ b/Content.Server/Chemistry/ReagentEffects/PlantMetabolism/PlantDiethylamine.cs @@ -2,6 +2,7 @@ using Content.Server.Botany.Components; using Content.Server.Botany.Systems; using Content.Shared.Chemistry.Reagent; using JetBrains.Annotations; +using Robust.Shared.Prototypes; using Robust.Shared.Random; namespace Content.Server.Chemistry.ReagentEffects.PlantMetabolism @@ -34,5 +35,7 @@ namespace Content.Server.Chemistry.ReagentEffects.PlantMetabolism plantHolderComp.Seed.Endurance++; } } + + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => Loc.GetString("reagent-effect-guidebook-missing", ("chance", Probability)); } } diff --git a/Content.Server/Chemistry/ReagentEffects/PlantMetabolism/RobustHarvest.cs b/Content.Server/Chemistry/ReagentEffects/PlantMetabolism/RobustHarvest.cs index a13edcad5a..81dd072a62 100644 --- a/Content.Server/Chemistry/ReagentEffects/PlantMetabolism/RobustHarvest.cs +++ b/Content.Server/Chemistry/ReagentEffects/PlantMetabolism/RobustHarvest.cs @@ -2,6 +2,7 @@ using Content.Server.Botany.Components; using Content.Server.Botany.Systems; using Content.Shared.Chemistry.Reagent; using JetBrains.Annotations; +using Robust.Shared.Prototypes; using Robust.Shared.Random; namespace Content.Server.Chemistry.ReagentEffects.PlantMetabolism @@ -47,5 +48,7 @@ namespace Content.Server.Chemistry.ReagentEffects.PlantMetabolism plantHolderComp.Seed.Yield--; } } + + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => Loc.GetString("reagent-effect-guidebook-missing", ("chance", Probability)); } } diff --git a/Content.Server/Chemistry/ReagentEffects/PopupMessage.cs b/Content.Server/Chemistry/ReagentEffects/PopupMessage.cs index 15e12046e2..9d06032307 100644 --- a/Content.Server/Chemistry/ReagentEffects/PopupMessage.cs +++ b/Content.Server/Chemistry/ReagentEffects/PopupMessage.cs @@ -1,6 +1,7 @@ using Content.Shared.Chemistry.Reagent; using Content.Shared.Popups; using Robust.Shared.Player; +using Robust.Shared.Prototypes; using Robust.Shared.Random; namespace Content.Server.Chemistry.ReagentEffects @@ -16,6 +17,10 @@ namespace Content.Server.Chemistry.ReagentEffects [DataField("visualType")] public PopupType VisualType = PopupType.Small; + // JUSTIFICATION: This is purely cosmetic. + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + => null; + public override void Effect(ReagentEffectArgs args) { var popupSys = args.EntityManager.EntitySysManager.GetEntitySystem(); diff --git a/Content.Server/Chemistry/ReagentEffects/ResetNarcolepsy.cs b/Content.Server/Chemistry/ReagentEffects/ResetNarcolepsy.cs index eeaffb8149..20044d4037 100644 --- a/Content.Server/Chemistry/ReagentEffects/ResetNarcolepsy.cs +++ b/Content.Server/Chemistry/ReagentEffects/ResetNarcolepsy.cs @@ -1,6 +1,7 @@ using Content.Server.Traits.Assorted; using Content.Shared.Chemistry.Reagent; using JetBrains.Annotations; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffects; @@ -16,6 +17,9 @@ public sealed class ResetNarcolepsy : ReagentEffect [DataField("TimerReset")] public int TimerReset = 600; + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + => Loc.GetString("reagent-effect-guidebook-reset-narcolepsy", ("chance", Probability)); + public override void Effect(ReagentEffectArgs args) { if (args.Scale != 1f) diff --git a/Content.Server/Chemistry/ReagentEffects/SatiateHunger.cs b/Content.Server/Chemistry/ReagentEffects/SatiateHunger.cs index 7ef11578ad..a0d00c538e 100644 --- a/Content.Server/Chemistry/ReagentEffects/SatiateHunger.cs +++ b/Content.Server/Chemistry/ReagentEffects/SatiateHunger.cs @@ -2,6 +2,7 @@ using Content.Shared.Chemistry.Reagent; using Content.Shared.Nutrition.Components; using Content.Shared.Nutrition.EntitySystems; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffects { @@ -11,10 +12,12 @@ namespace Content.Server.Chemistry.ReagentEffects /// public sealed class SatiateHunger : ReagentEffect { + private const float DefaultNutritionFactor = 3.0f; + /// /// How much hunger is satiated when 1u of the reagent is metabolized /// - [DataField("factor")] public float NutritionFactor { get; set; } = 3.0f; + [DataField("factor")] public float NutritionFactor { get; set; } = DefaultNutritionFactor; //Remove reagent at set rate, satiate hunger if a HungerComponent can be found public override void Effect(ReagentEffectArgs args) @@ -24,5 +27,8 @@ namespace Content.Server.Chemistry.ReagentEffects return; entman.System().ModifyHunger(args.SolutionEntity, NutritionFactor * (float) args.Quantity, hunger); } + + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + => Loc.GetString("reagent-effect-guidebook-satiate-hunger", ("chance", Probability), ("relative", NutritionFactor / DefaultNutritionFactor)); } } diff --git a/Content.Server/Chemistry/ReagentEffects/SatiateThirst.cs b/Content.Server/Chemistry/ReagentEffects/SatiateThirst.cs index 43e9f051a0..79911110a9 100644 --- a/Content.Server/Chemistry/ReagentEffects/SatiateThirst.cs +++ b/Content.Server/Chemistry/ReagentEffects/SatiateThirst.cs @@ -1,6 +1,7 @@ using Content.Server.Nutrition.Components; using Content.Shared.Chemistry.Reagent; using Content.Server.Nutrition.EntitySystems; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffects { @@ -10,10 +11,12 @@ namespace Content.Server.Chemistry.ReagentEffects /// public sealed class SatiateThirst : ReagentEffect { + private const float DefaultHydrationFactor = 3.0f; + /// How much thirst is satiated each metabolism tick. Not currently tied to /// rate or anything. [DataField("factor")] - public float HydrationFactor { get; set; } = 3.0f; + public float HydrationFactor { get; set; } = DefaultHydrationFactor; /// Satiate thirst if a ThirstComponent can be found public override void Effect(ReagentEffectArgs args) @@ -21,5 +24,8 @@ namespace Content.Server.Chemistry.ReagentEffects if (args.EntityManager.TryGetComponent(args.SolutionEntity, out ThirstComponent? thirst)) EntitySystem.Get().UpdateThirst(thirst, HydrationFactor); } + + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + => Loc.GetString("reagent-effect-guidebook-satiate-thirst", ("chance", Probability), ("relative", HydrationFactor / DefaultHydrationFactor)); } } diff --git a/Content.Server/Chemistry/ReagentEffects/StatusEffects/GenericStatusEffect.cs b/Content.Server/Chemistry/ReagentEffects/StatusEffects/GenericStatusEffect.cs index 8727ae2511..982606194a 100644 --- a/Content.Server/Chemistry/ReagentEffects/StatusEffects/GenericStatusEffect.cs +++ b/Content.Server/Chemistry/ReagentEffects/StatusEffects/GenericStatusEffect.cs @@ -1,6 +1,7 @@ using Content.Shared.Chemistry.Reagent; using Content.Shared.StatusEffect; using JetBrains.Annotations; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffects.StatusEffects { @@ -57,6 +58,13 @@ namespace Content.Server.Chemistry.ReagentEffects.StatusEffects statusSys.TrySetTime(args.SolutionEntity, Key, TimeSpan.FromSeconds(time)); } } + + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => Loc.GetString( + "reagent-effect-guidebook-status-effect", + ("chance", Probability), + ("type", Type), + ("time", Time), + ("key", $"reagent-effect-status-effect-{Key}")); } public enum StatusEffectMetabolismType diff --git a/Content.Server/Chemistry/ReagentEffects/StatusEffects/Jitter.cs b/Content.Server/Chemistry/ReagentEffects/StatusEffects/Jitter.cs index bd060c439a..3aa81e20f6 100644 --- a/Content.Server/Chemistry/ReagentEffects/StatusEffects/Jitter.cs +++ b/Content.Server/Chemistry/ReagentEffects/StatusEffects/Jitter.cs @@ -1,5 +1,6 @@ using Content.Shared.Chemistry.Reagent; using Content.Shared.Jittering; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffects.StatusEffects { @@ -33,5 +34,8 @@ namespace Content.Server.Chemistry.ReagentEffects.StatusEffects args.EntityManager.EntitySysManager.GetEntitySystem() .DoJitter(args.SolutionEntity, TimeSpan.FromSeconds(time), Refresh, Amplitude, Frequency); } + + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) => + Loc.GetString("reagent-effect-guidebook-jittering", ("chance", Probability)); } } diff --git a/Content.Server/Chemistry/ReagentEffects/WashCreamPieReaction.cs b/Content.Server/Chemistry/ReagentEffects/WashCreamPieReaction.cs index fdd21c8335..6e2e871d2d 100644 --- a/Content.Server/Chemistry/ReagentEffects/WashCreamPieReaction.cs +++ b/Content.Server/Chemistry/ReagentEffects/WashCreamPieReaction.cs @@ -2,12 +2,16 @@ using Content.Server.Nutrition.EntitySystems; using Content.Shared.Chemistry.Reagent; using Content.Shared.Nutrition.Components; using JetBrains.Annotations; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffects { [UsedImplicitly] public sealed class WashCreamPieReaction : ReagentEffect { + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + => Loc.GetString("reagent-effect-guidebook-wash-cream-pie-reaction", ("chance", Probability)); + public override void Effect(ReagentEffectArgs args) { if (!args.EntityManager.TryGetComponent(args.SolutionEntity, out CreamPiedComponent? creamPied)) return; diff --git a/Content.Shared/Body/Prototypes/MetabolizerTypePrototype.cs b/Content.Shared/Body/Prototypes/MetabolizerTypePrototype.cs index bee2301b28..e5eee21185 100644 --- a/Content.Shared/Body/Prototypes/MetabolizerTypePrototype.cs +++ b/Content.Shared/Body/Prototypes/MetabolizerTypePrototype.cs @@ -7,5 +7,8 @@ namespace Content.Shared.Body.Prototypes { [IdDataField] public string ID { get; } = default!; + + [DataField("name", required: true)] + public string Name { get; } = default!; } } diff --git a/Content.Shared/Chemistry/Reagent/ReagentEffect.cs b/Content.Shared/Chemistry/Reagent/ReagentEffect.cs index 9140c44f15..1ece3afc13 100644 --- a/Content.Shared/Chemistry/Reagent/ReagentEffect.cs +++ b/Content.Shared/Chemistry/Reagent/ReagentEffect.cs @@ -1,8 +1,11 @@ -using System.Text.Json.Serialization; +using System.Linq; +using System.Text.Json.Serialization; using Content.Shared.Chemistry.Components; using Content.Shared.Database; using Content.Shared.FixedPoint; +using Content.Shared.Localizations; using JetBrains.Annotations; +using Robust.Shared.Prototypes; using Robust.Shared.Random; namespace Content.Shared.Chemistry.Reagent @@ -23,6 +26,10 @@ namespace Content.Shared.Chemistry.Reagent [DataField("conditions")] public ReagentEffectCondition[]? Conditions; + public virtual string ReagentEffectFormat => "guidebook-reagent-effect-description"; + + protected abstract string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys); // => Loc.GetString("reagent-effect-guidebook-missing", ("chance", Probability)); + /// /// What's the chance, from 0 to 1, that this effect will occur? /// @@ -42,6 +49,23 @@ namespace Content.Shared.Chemistry.Reagent public virtual bool ShouldLog { get; } = false; public abstract void Effect(ReagentEffectArgs args); + + /// + /// Produces a localized, bbcode'd guidebook description for this effect. + /// + /// + public string? GuidebookEffectDescription(IPrototypeManager prototype, IEntitySystemManager entSys) + { + var effect = ReagentEffectGuidebookText(prototype, entSys); + if (effect is null) + return null; + + return Loc.GetString(ReagentEffectFormat, ("effect", effect), ("chance", Probability), + ("conditionCount", Conditions?.Length ?? 0), + ("conditions", + ContentLocalizationManager.FormatList(Conditions?.Select(x => x.GuidebookExplanation(prototype)).ToList() ?? + new List()))); + } } public static class ReagentEffectExt diff --git a/Content.Shared/Chemistry/Reagent/ReagentEffectCondition.cs b/Content.Shared/Chemistry/Reagent/ReagentEffectCondition.cs index 13d1cb37ee..708fe24c70 100644 --- a/Content.Shared/Chemistry/Reagent/ReagentEffectCondition.cs +++ b/Content.Shared/Chemistry/Reagent/ReagentEffectCondition.cs @@ -1,5 +1,6 @@ using System.Text.Json.Serialization; using JetBrains.Annotations; +using Robust.Shared.Prototypes; namespace Content.Shared.Chemistry.Reagent { @@ -10,5 +11,12 @@ namespace Content.Shared.Chemistry.Reagent [JsonPropertyName("id")] private protected string _id => this.GetType().Name; public abstract bool Condition(ReagentEffectArgs args); + + /// + /// Effect explanations are of the form "[chance to] [action] when [condition] and [condition]" + /// + /// + /// + public abstract string GuidebookExplanation(IPrototypeManager prototype); } } diff --git a/Content.Shared/Chemistry/Reagent/ReagentPrototype.cs b/Content.Shared/Chemistry/Reagent/ReagentPrototype.cs index 001bfd6e00..51bd6c4fe6 100644 --- a/Content.Shared/Chemistry/Reagent/ReagentPrototype.cs +++ b/Content.Shared/Chemistry/Reagent/ReagentPrototype.cs @@ -1,4 +1,5 @@ -using System.Text.Json.Serialization; +using System.Linq; +using System.Text.Json.Serialization; using Content.Shared.Administration.Logs; using Content.Shared.Body.Prototypes; using Content.Shared.Chemistry.Components; @@ -9,6 +10,7 @@ using Robust.Shared.Audio; using Robust.Shared.Map; using Robust.Shared.Prototypes; using Robust.Shared.Random; +using Robust.Shared.Serialization; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Array; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary; @@ -157,6 +159,23 @@ namespace Content.Shared.Chemistry.Reagent } } + [Serializable, NetSerializable] + public struct ReagentGuideEntry + { + public string ReagentPrototype; + + public Dictionary? GuideEntries; + + public ReagentGuideEntry(ReagentPrototype proto, IPrototypeManager prototype, IEntitySystemManager entSys) + { + ReagentPrototype = proto.ID; + GuideEntries = proto.Metabolisms? + .Select(x => (x.Key, x.Value.MakeGuideEntry(prototype, entSys))) + .ToDictionary(x => x.Key, x => x.Item2); + } + } + + [DataDefinition] public sealed class ReagentEffectsEntry { @@ -173,6 +192,30 @@ namespace Content.Shared.Chemistry.Reagent [JsonPropertyName("effects")] [DataField("effects", required: true)] public ReagentEffect[] Effects = default!; + + public ReagentEffectsGuideEntry MakeGuideEntry(IPrototypeManager prototype, IEntitySystemManager entSys) + { + return new ReagentEffectsGuideEntry(MetabolismRate, + Effects + .Select(x => x.GuidebookEffectDescription(prototype, entSys)) // hate. + .Where(x => x is not null) + .Select(x => x!) + .ToArray()); + } + } + + [Serializable, NetSerializable] + public struct ReagentEffectsGuideEntry + { + public FixedPoint2 MetabolismRate; + + public string[] EffectDescriptions; + + public ReagentEffectsGuideEntry(FixedPoint2 metabolismRate, string[] effectDescriptions) + { + MetabolismRate = metabolismRate; + EffectDescriptions = effectDescriptions; + } } [DataDefinition] diff --git a/Content.Shared/Chemistry/SharedChemistryGuideDataSystem.cs b/Content.Shared/Chemistry/SharedChemistryGuideDataSystem.cs new file mode 100644 index 0000000000..391134bcf0 --- /dev/null +++ b/Content.Shared/Chemistry/SharedChemistryGuideDataSystem.cs @@ -0,0 +1,42 @@ +using Content.Shared.Chemistry.Reagent; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; + +namespace Content.Shared.Chemistry; + +/// +/// This handles the chemistry guidebook and caching it. +/// +public abstract class SharedChemistryGuideDataSystem : EntitySystem +{ + [Dependency] protected readonly IPrototypeManager PrototypeManager = default!; + + protected readonly Dictionary Registry = new(); + + public IReadOnlyDictionary ReagentGuideRegistry => Registry; +} + +[Serializable, NetSerializable] +public sealed class ReagentGuideRegistryChangedEvent : EntityEventArgs +{ + public ReagentGuideChangeset Changeset; + + public ReagentGuideRegistryChangedEvent(ReagentGuideChangeset changeset) + { + Changeset = changeset; + } +} + +[Serializable, NetSerializable] +public sealed class ReagentGuideChangeset +{ + public Dictionary GuideEntries; + + public HashSet Removed; + + public ReagentGuideChangeset(Dictionary guideEntries, HashSet removed) + { + GuideEntries = guideEntries; + Removed = removed; + } +} diff --git a/Content.Shared/Localizations/ContentLocalizationManager.cs b/Content.Shared/Localizations/ContentLocalizationManager.cs index c3069ccd4d..f974eb0785 100644 --- a/Content.Shared/Localizations/ContentLocalizationManager.cs +++ b/Content.Shared/Localizations/ContentLocalizationManager.cs @@ -1,4 +1,7 @@ using System.Globalization; +using System.Linq; +using System.Text.RegularExpressions; +using Robust.Shared.Utility; namespace Content.Shared.Localizations { @@ -31,13 +34,96 @@ namespace Content.Shared.Localizations _loc.AddFunction(culture, "UNITS", FormatUnits); _loc.AddFunction(culture, "TOSTRING", args => FormatToString(culture, args)); _loc.AddFunction(culture, "LOC", FormatLoc); + _loc.AddFunction(culture, "NATURALFIXED", FormatNaturalFixed); + _loc.AddFunction(culture, "NATURALPERCENT", FormatNaturalPercent); + + + /* + * The following language functions are specific to the english localization. When working on your own + * localization you should NOT modify these, instead add new functions specific to your language/culture. + * This ensures the english translations continue to work as expected when fallbacks are needed. + */ + var cultureEn = new CultureInfo("en-US"); + + _loc.AddFunction(cultureEn, "MAKEPLURAL", FormatMakePlural); + _loc.AddFunction(cultureEn, "MANY", FormatMany); + } + + private ILocValue FormatMany(LocArgs args) + { + var count = ((LocValueNumber) args.Args[1]).Value; + + if (Math.Abs(count - 1) < 0.0001f) + { + return (LocValueString) args.Args[0]; + } + else + { + return (LocValueString) FormatMakePlural(args); + } + } + + private ILocValue FormatNaturalPercent(LocArgs args) + { + var number = ((LocValueNumber) args.Args[0]).Value * 100; + var maxDecimals = (int)Math.Floor(((LocValueNumber) args.Args[1]).Value); + var formatter = (NumberFormatInfo)NumberFormatInfo.GetInstance(CultureInfo.GetCultureInfo(Culture)).Clone(); + formatter.NumberDecimalDigits = maxDecimals; + return new LocValueString(string.Format(formatter, "{0:N}", number).TrimEnd('0').TrimEnd('.') + "%"); + } + + private ILocValue FormatNaturalFixed(LocArgs args) + { + var number = ((LocValueNumber) args.Args[0]).Value; + var maxDecimals = (int)Math.Floor(((LocValueNumber) args.Args[1]).Value); + var formatter = (NumberFormatInfo)NumberFormatInfo.GetInstance(CultureInfo.GetCultureInfo(Culture)).Clone(); + formatter.NumberDecimalDigits = maxDecimals; + return new LocValueString(string.Format(formatter, "{0:N}", number).TrimEnd('0').TrimEnd('.')); + } + + private static readonly Regex PluralEsRule = new("^.*(s|sh|ch|x|z)$"); + + private ILocValue FormatMakePlural(LocArgs args) + { + var text = ((LocValueString) args.Args[0]).Value; + var split = text.Split(" ", 1); + var firstWord = split[0]; + if (PluralEsRule.IsMatch(firstWord)) + { + if (split.Length == 1) + return new LocValueString($"{firstWord}es"); + else + return new LocValueString($"{firstWord}es {split[1]}"); + } + else + { + if (split.Length == 1) + return new LocValueString($"{firstWord}s"); + else + return new LocValueString($"{firstWord}s {split[1]}"); + } + } + + // TODO: allow fluent to take in lists of strings so this can be a format function like it should be. + /// + /// Formats a list as per english grammar rules. + /// + public static string FormatList(List list) + { + return list.Count switch + { + <= 0 => string.Empty, + 1 => list[0], + 2 => $"{list[0]} and {list[1]}", + > 2 => $"{string.Join(", ", list.GetRange(0, list.Count - 2))}, and {list[^1]}" + }; } private static ILocValue FormatLoc(LocArgs args) { - var id = ((LocValueString)args.Args[0]).Value; + var id = ((LocValueString) args.Args[0]).Value; - return new LocValueString(Loc.GetString(id)); + return new LocValueString(Loc.GetString(id, args.Options.Select(x => (x.Key, x.Value.Value!)).ToArray())); } private static ILocValue FormatToString(CultureInfo culture, LocArgs args) @@ -115,8 +201,8 @@ namespace Content.Shared.Localizations // // Note that the closing brace isn't replaced so that format specifiers can be applied. var res = String.Format( - fmtstr.Replace("{UNIT", "{" + $"{fargs.Length - 1}"), - fargs + fmtstr.Replace("{UNIT", "{" + $"{fargs.Length - 1}"), + fargs ); return new LocValueString(res); diff --git a/Resources/Locale/en-US/guidebook/chemistry/conditions.ftl b/Resources/Locale/en-US/guidebook/chemistry/conditions.ftl new file mode 100644 index 0000000000..807b5591a8 --- /dev/null +++ b/Resources/Locale/en-US/guidebook/chemistry/conditions.ftl @@ -0,0 +1,50 @@ +reagent-effect-condition-guidebook-total-damage = + { $max -> + [2147483648] it has at least {NATURALFIXED($min, 2)} total damage + *[other] { $min -> + [0] it has at most {NATURALFIXED($max, 2)} total damage + *[other] it has between {NATURALFIXED($min, 2)} and {NATURALFIXED($max, 2)} total damage + } + } + +reagent-effect-condition-guidebook-reagent-threshold = + { $max -> + [2147483648] there's at least {NATURALFIXED($min, 2)}u of {$reagent} + *[other] { $min -> + [0] there's at most {NATURALFIXED($max, 2)}u of {$reagent} + *[other] there's between {NATURALFIXED($min, 2)}u and {NATURALFIXED($max, 2)}u of {$reagent} + } + } + +reagent-effect-condition-guidebook-mob-state-condition = + the mob is { $state } + +reagent-effect-condition-guidebook-solution-temperature = + the solution's temperature is { $max -> + [2147483648] at least {NATURALFIXED($min, 2)}k + *[other] { $min -> + [0] at most {NATURALFIXED($max, 2)}k + *[other] between {NATURALFIXED($min, 2)}k and {NATURALFIXED($max, 2)}k + } + } + +reagent-effect-condition-guidebook-body-temperature = + the body's temperature is { $max -> + [2147483648] at least {NATURALFIXED($min, 2)}k + *[other] { $min -> + [0] at most {NATURALFIXED($max, 2)}k + *[other] between {NATURALFIXED($min, 2)}k and {NATURALFIXED($max, 2)}k + } + } + +reagent-effect-condition-guidebook-organ-type = + the metabolizing organ { $shouldhave -> + [true] is + *[false] is not + } {INDEFINITE($name)} {$name} organ + +reagent-effect-condition-guidebook-has-tag = + the target { $invert -> + [true] does not have + *[false] has + } the tag {$tag} diff --git a/Resources/Locale/en-US/guidebook/chemistry/core.ftl b/Resources/Locale/en-US/guidebook/chemistry/core.ftl new file mode 100644 index 0000000000..185595826d --- /dev/null +++ b/Resources/Locale/en-US/guidebook/chemistry/core.ftl @@ -0,0 +1,16 @@ +guidebook-reagent-effect-description = + {$chance -> + [1] { $effect } + *[other] Has a { NATURALPERCENT($chance, 2) } chance to { $effect } + }{ $conditionCount -> + [0] . + *[other] {" "}when { $conditions }. + } + +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-effects-header = Effects +guidebook-reagent-effects-metabolism-group-rate = [bold]{$group}[/bold] [color=gray]({$rate} units per second)[/color] +guidebook-reagent-physical-description = Seems to be {$description}. diff --git a/Resources/Locale/en-US/guidebook/chemistry/effects.ftl b/Resources/Locale/en-US/guidebook/chemistry/effects.ftl new file mode 100644 index 0000000000..e004cc1590 --- /dev/null +++ b/Resources/Locale/en-US/guidebook/chemistry/effects.ftl @@ -0,0 +1,316 @@ +-create-3rd-person = + { $chance -> + [1] Creates + *[other] create + } + +-cause-3rd-person = + { $chance -> + [1] Causes + *[other] cause + } + +-satiate-3rd-person = + { $chance -> + [1] Satiates + *[other] satiate + } + +reagent-effect-guidebook-create-entity-reaction-effect = + { $chance -> + [1] Creates + *[other] create + } { $amount -> + [1] {INDEFINITE($entname)} + *[other] {$amount} {MAKEPLURAL($entname)} + } + +reagent-effect-guidebook-explosion-reaction-effect = + { $chance -> + [1] Causes + *[other] cause + } an explosion + +reagent-effect-guidebook-foam-area-reaction-effect = + { $chance -> + [1] Creates + *[other] create + } large quantities of foam + +reagent-effect-guidebook-foam-area-reaction-effect = + { $chance -> + [1] Creates + *[other] create + } large quantities of smoke + +reagent-effect-guidebook-satiate-thirst = + { $chance -> + [1] Satiates + *[other] satiate + } { $relative -> + [1] thirst averagely + *[other] thirst at {NATURALFIXED($relative, 3)}x the average rate + } + +reagent-effect-guidebook-satiate-hunger = + { $chance -> + [1] Satiates + *[other] satiate + } { $relative -> + [1] hunger averagely + *[other] hunger at {NATURALFIXED($relative, 3)}x the average rate + } + +reagent-effect-guidebook-health-change = + { $chance -> + [1] { $healsordeals -> + [heals] Heals + [deals] Deals + *[both] Modifies health by + } + *[other] { $healsordeals -> + [heals] heal + [deals] deal + *[both] modify health by + } + } { $changes } + +reagent-effect-guidebook-status-effect = + { $type -> + [add] { $chance -> + [1] Causes + *[other] cause + } {LOC($key)} for at least {NATURALFIXED($time, 3)} {MANY("second", $time)} with accumulation + *[set] { $chance -> + [1] Causes + *[other] cause + } {LOC($key)} for at least {NATURALFIXED($time, 3)} {MANY("second", $time)} without accumulation + [remove]{ $chance -> + [1] Removes + *[other] remove + } {NATURALFIXED($time, 3)} {MANY("second", $time)} of {LOC($key)} + } + +reagent-effect-guidebook-activate-artifact = + { $chance -> + [1] Attempts + *[other] attempt + } to activate an artifact + +reagent-effect-guidebook-set-solution-temperature-effect = + { $chance -> + [1] Sets + *[other] set + } the solution temperature to exactly {NATURALFIXED($temperature, 2)}k + +reagent-effect-guidebook-adjust-solution-temperature-effect = + { $chance -> + [1] { $deltasign -> + [1] Adds + *[-1] Removes + } + *[other] + { $deltasign -> + [1] add + *[-1] remove + } + } heat from the solution until it reaches { $deltasign -> + [1] at most {NATURALFIXED($maxtemp, 2)}k + *[-1] at least {NATURALFIXED($mintemp, 2)}k + } + +reagent-effect-guidebook-adjust-reagent-reagent = + { $chance -> + [1] { $deltasign -> + [1] Adds + *[-1] Removes + } + *[other] + { $deltasign -> + [1] add + *[-1] remove + } + } {NATURALFIXED($amount, 2)}u of {$reagent} { $deltasign -> + [1] to + *[-1] from + } the solution + +reagent-effect-guidebook-adjust-reagent-group = + { $chance -> + [1] { $deltasign -> + [1] Adds + *[-1] Removes + } + *[other] + { $deltasign -> + [1] add + *[-1] remove + } + } {NATURALFIXED($amount, 2)}u of reagents in the group {$group} { $deltasign -> + [1] to + *[-1] from + } the solution + +reagent-effect-guidebook-adjust-temperature = + { $chance -> + [1] { $deltasign -> + [1] Adds + *[-1] Removes + } + *[other] + { $deltasign -> + [1] add + *[-1] remove + } + } {POWERJOULES($amount)} of heat { $deltasign -> + [1] to + *[-1] from + } the body it's in + +reagent-effect-guidebook-chem-cause-disease = + { $chance -> + [1] Causes + *[other] cause + } the disease { $disease } + +reagent-effect-guidebook-chem-cause-random-disease = + { $chance -> + [1] Causes + *[other] cause + } the diseases { $diseases } + +reagent-effect-guidebook-jittering = + { $chance -> + [1] Causes + *[other] cause + } jittering + +reagent-effect-guidebook-chem-clean-bloodstream = + { $chance -> + [1] Cleanses + *[other] cleanse + } the bloodstream of other chemicals + +reagent-effect-guidebook-cure-disease = + { $chance -> + [1] Cures + *[other] cure + } diseases + +reagent-effect-guidebook-cure-eye-damage = + { $chance -> + [1] { $deltasign -> + [1] Heals + *[-1] Deals + } + *[other] + { $deltasign -> + [1] heal + *[-1] deal + } + } eye damage + +reagent-effect-guidebook-chem-vomit = + { $chance -> + [1] Causes + *[other] cause + } vomiting + +reagent-effect-guidebook-create-gas = + { $chance -> + [1] Creates + *[other] create + } { $moles } { $moles -> + [1] mole + *[other] moles + } of { $gas } + +reagent-effect-guidebook-drunk = + { $chance -> + [1] Causes + *[other] cause + } drunkness + +reagent-effect-guidebook-electrocute = + { $chance -> + [1] Electrocutes + *[other] electrocute + } the metabolizer for {NATURALFIXED($time, 3)} {MANY("second", $time)} + +reagent-effect-guidebook-extinguish-reaction = + { $chance -> + [1] Extinguishes + *[other] extinguish + } fire + +reagent-effect-guidebook-flammable-reaction = + { $chance -> + [1] Increases + *[other] increase + } flammability + +reagent-effect-guidebook-ignite = + { $chance -> + [1] Ignites + *[other] ignite + } the metabolizer + +reagent-effect-guidebook-make-sentient = + { $chance -> + [1] Makes + *[other] make + } the metabolizer sentient + +reagent-effect-guidebook-modify-bleed-amount = + { $chance -> + [1] { $deltasign -> + [1] Induces + *[-1] Reduces + } + *[other] { $deltasign -> + [1] induce + *[-1] reduce + } + } bleeding + +reagent-effect-guidebook-modify-blood-level = + { $chance -> + [1] { $deltasign -> + [1] Increases + *[-1] Decreases + } + *[other] { $deltasign -> + [1] increases + *[-1] decreases + } + } blood level + +reagent-effect-guidebook-paralyze = + { $chance -> + [1] Paralyzes + *[other] paralyze + } the metabolizer for at least {NATURALFIXED($time, 3)} {MANY("second", $time)} + +reagent-effect-guidebook-movespeed-modifier = + { $chance -> + [1] Modifies + *[other] modify + } movement speed by {NATURALFIXED($walkspeed, 3)}x for at least {NATURALFIXED($time, 3)} {MANY("second", $time)} + +reagent-effect-guidebook-reset-narcolepsy = + { $chance -> + [1] Temporarily staves + *[other] temporarily stave + } off narcolepsy + +reagent-effect-guidebook-wash-cream-pie-reaction = + { $chance -> + [1] Washes + *[other] wash + } off cream pie from one's face + +reagent-effect-guidebook-missing = + { $chance -> + [1] Causes + *[other] cause + } an unknown effect as nobody has written this effect yet diff --git a/Resources/Locale/en-US/guidebook/chemistry/healthchange.ftl b/Resources/Locale/en-US/guidebook/chemistry/healthchange.ftl new file mode 100644 index 0000000000..d5eba5b02c --- /dev/null +++ b/Resources/Locale/en-US/guidebook/chemistry/healthchange.ftl @@ -0,0 +1,5 @@ +health-change-display = + { $deltasign -> + [-1] [color=green]{NATURALFIXED($amount, 2)}[/color] {$kind} + *[1] [color=red]{NATURALFIXED($amount, 2)}[/color] {$kind} + } diff --git a/Resources/Locale/en-US/guidebook/chemistry/statuseffects.ftl b/Resources/Locale/en-US/guidebook/chemistry/statuseffects.ftl new file mode 100644 index 0000000000..8cedbcabb6 --- /dev/null +++ b/Resources/Locale/en-US/guidebook/chemistry/statuseffects.ftl @@ -0,0 +1,11 @@ +reagent-effect-status-effect-Stun = stunning +reagent-effect-status-effect-KnockedDown = knockdown +reagent-effect-status-effect-Jitter = jittering +reagent-effect-status-effect-TemporaryBlindness = blindess +reagent-effect-status-effect-SeeingRainbows = hallucinations +reagent-effect-status-effect-Muted = inability to speak +reagent-effect-status-effect-Stutter = stuttering +reagent-effect-status-effect-ForcedSleep = unconsciousness +reagent-effect-status-effect-Drunk = drunkness +reagent-effect-status-effect-PressureImmunity = pressure immunity +reagent-effect-status-effect-Pacified = combat pacification diff --git a/Resources/Locale/en-US/guidebook/guides.ftl b/Resources/Locale/en-US/guidebook/guides.ftl index 5a688dd565..805eac357d 100644 --- a/Resources/Locale/en-US/guidebook/guides.ftl +++ b/Resources/Locale/en-US/guidebook/guides.ftl @@ -14,6 +14,7 @@ guide-entry-radio = Radio guide-entry-jobs = Jobs guide-entry-salvage = Salvage guide-entry-survival = Survival +guide-entry-chemicals = Chemicals guide-entry-ss14 = Space Station 14 guide-entry-janitorial = Janitorial diff --git a/Resources/Prototypes/Chemistry/metabolizer_types.yml b/Resources/Prototypes/Chemistry/metabolizer_types.yml index 11242bb7b8..1aa19f6084 100644 --- a/Resources/Prototypes/Chemistry/metabolizer_types.yml +++ b/Resources/Prototypes/Chemistry/metabolizer_types.yml @@ -3,24 +3,32 @@ - type: metabolizerType id: Animal + name: animal - type: metabolizerType id: Dragon + name: dragon - type: metabolizerType id: Human + name: human - type: metabolizerType id: Slime + name: slime - type: metabolizerType id: Vox + name: vox - type: metabolizerType id: Rat + name: rat - type: metabolizerType id: Plant + name: plant - type: metabolizerType id: Dwarf + name: dwarf diff --git a/Resources/Prototypes/Entities/Structures/Dispensers/chem.yml b/Resources/Prototypes/Entities/Structures/Dispensers/chem.yml index 44babe2411..27a2cd53be 100644 --- a/Resources/Prototypes/Entities/Structures/Dispensers/chem.yml +++ b/Resources/Prototypes/Entities/Structures/Dispensers/chem.yml @@ -32,3 +32,6 @@ - type: UpgradePowerDraw powerDrawMultiplier: 0.75 scaling: Exponential + - type: GuideHelp + guides: + - Chemicals diff --git a/Resources/Prototypes/Guidebook/shiftandcrew.yml b/Resources/Prototypes/Guidebook/shiftandcrew.yml index 39e580e052..fc37b330bf 100644 --- a/Resources/Prototypes/Guidebook/shiftandcrew.yml +++ b/Resources/Prototypes/Guidebook/shiftandcrew.yml @@ -15,6 +15,11 @@ name: guide-entry-survival text: "/ServerInfo/Guidebook/Survival.xml" +- type: guideEntry + id: Chemicals + name: guide-entry-chemicals + text: "/ServerInfo/Guidebook/Chemicals.xml" + - type: guideEntry id: Janitorial name: guide-entry-janitorial diff --git a/Resources/Prototypes/Guidebook/ss14.yml b/Resources/Prototypes/Guidebook/ss14.yml index bb98b11fcf..bcf474b773 100644 --- a/Resources/Prototypes/Guidebook/ss14.yml +++ b/Resources/Prototypes/Guidebook/ss14.yml @@ -6,3 +6,4 @@ - Controls - Jobs - Survival + - Chemicals diff --git a/Resources/ServerInfo/Guidebook/Chemicals.xml b/Resources/ServerInfo/Guidebook/Chemicals.xml new file mode 100644 index 0000000000..e157dbb437 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/Chemicals.xml @@ -0,0 +1,34 @@ + +# Chemicals + +Chemicals are a powerful tool that can cause a variety of effects when consumed. Some can be found in plants, purchased from cargo, or be synthesized through combination with other chemicals. + +Knowing different types of chemicals and their effects is important for being able to manage injury and danger. + +## Elements + + +## Medicine + + +## Narcotics + + +## Pyrotechnics + + +## Toxins + + +## Foods + + +## Botanical + + +## Biological + + +## Other + + diff --git a/Resources/Textures/Interface/Misc/beakerlarge.png b/Resources/Textures/Interface/Misc/beakerlarge.png new file mode 100644 index 0000000000000000000000000000000000000000..4e0fb0fc0619fad51251435287c6ec77c25a08e0 GIT binary patch literal 239 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJZJsWUAr*6y6C_v{Cy4Yk1sWV^ zm>9zQZ7TbG!Jy&|cjLMuK1X