diff --git a/Content.Server/Body/Components/StomachComponent.cs b/Content.Server/Body/Components/StomachComponent.cs index fe93468f74e..821f4e7afaf 100644 --- a/Content.Server/Body/Components/StomachComponent.cs +++ b/Content.Server/Body/Components/StomachComponent.cs @@ -1,4 +1,4 @@ -using Content.Server.Body.Systems; +using Content.Server.Body.Systems; using Content.Server.Nutrition.EntitySystems; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Reagent; @@ -64,5 +64,17 @@ public ReagentDelta(ReagentQuantity reagentQuantity) public void Increment(float delta) => Lifetime += delta; } + + /// + /// Frontier - Used by goblin for fliping the food quility effects + /// + [DataField] + public bool ReverseFoodQuality; + + /// + /// Frontier - Allow eating trash + /// + [DataField] + public bool TrashDigestion; } } diff --git a/Content.Server/Nutrition/Components/FoodComponent.cs b/Content.Server/Nutrition/Components/FoodComponent.cs index 5ead67a12b2..25e4f3a0c95 100644 --- a/Content.Server/Nutrition/Components/FoodComponent.cs +++ b/Content.Server/Nutrition/Components/FoodComponent.cs @@ -7,6 +7,30 @@ namespace Content.Server.Nutrition.Components; +public enum Quality : byte // Frontier +{ + High, + Normal, + Junk, + Nasty, + Toxin, + Trash, + MailOpened, + MailClosed +} + +public enum FinalQuality : byte // Frontier +{ + High, + Normal, + Junk, + Nasty, + Toxin, + Trash, + MailOpened, + MailClosed +} + [RegisterComponent, Access(typeof(FoodSystem))] public sealed partial class FoodComponent : Component { @@ -74,4 +98,15 @@ public sealed partial class FoodComponent : Component /// [DataField, ViewVariables(VVAccess.ReadWrite)] public bool RequireDead = true; + + /// + /// Frontier - Nasty food, used for goblins to know if they can eat it or not + /// + [ViewVariables(VVAccess.ReadWrite), DataField] // Frontier + public Quality Quality = Quality.Normal; + + /// + /// Frontier - Edited by the system to find the final quility results + /// + public FinalQuality FinalQuality = FinalQuality.Normal; } diff --git a/Content.Server/Nutrition/EntitySystems/FoodSystem.cs b/Content.Server/Nutrition/EntitySystems/FoodSystem.cs index 2b627151339..ced6e5c0656 100644 --- a/Content.Server/Nutrition/EntitySystems/FoodSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/FoodSystem.cs @@ -30,6 +30,12 @@ using Robust.Shared.Audio.Systems; using Robust.Shared.Utility; using System.Linq; +using Content.Server.Medical; // Frontier +using Content.Shared.Speech.EntitySystems; // Frontier +using Robust.Shared.Random; // Frontier +using Content.Shared.Jittering; // Frontier +using Content.Server.Chat.Systems; // Frontier +using Content.Shared.Tag; // Frontier namespace Content.Server.Nutrition.EntitySystems; @@ -54,6 +60,12 @@ public sealed class FoodSystem : EntitySystem [Dependency] private readonly StackSystem _stack = default!; [Dependency] private readonly StomachSystem _stomach = default!; [Dependency] private readonly UtensilSystem _utensil = default!; + [Dependency] private readonly VomitSystem _vomit = default!; // Frontier + [Dependency] private readonly SharedStutteringSystem _stuttering = default!; // Frontier + [Dependency] protected readonly IRobustRandom RobustRandom = default!; // Frontier + [Dependency] private readonly SharedJitteringSystem _jittering = default!; // Frontier + [Dependency] private readonly ChatSystem _chat = default!; // Frontier + [Dependency] private readonly TagSystem _tag = default!; // Frontier public const float MaxFeedDistance = 1.0f; @@ -230,6 +242,7 @@ private void OnDoAfter(Entity entity, ref ConsumeDoAfterEvent arg // Get the stomach with the highest available solution volume var highestAvailable = FixedPoint2.Zero; StomachComponent? stomachToUse = null; + var reverseFoodQuality = false; // Frontier foreach (var (stomach, _) in stomachs) { var owner = stomach.Owner; @@ -244,6 +257,7 @@ private void OnDoAfter(Entity entity, ref ConsumeDoAfterEvent arg stomachToUse = stomach; highestAvailable = stomachSol.AvailableVolume; + reverseFoodQuality = stomachToUse.ReverseFoodQuality; // Frontier } // No stomach so just popup a message that they can't eat. @@ -257,6 +271,143 @@ private void OnDoAfter(Entity entity, ref ConsumeDoAfterEvent arg _reaction.DoEntityReaction(args.Target.Value, solution, ReactionMethod.Ingestion); _stomach.TryTransferSolution(stomachToUse.Owner, split, stomachToUse); + /// Frontier - Goblin food system + if (entity.Comp.Quality == Quality.High) + entity.Comp.FinalQuality = FinalQuality.High; + else if (entity.Comp.Quality == Quality.Normal) + entity.Comp.FinalQuality = FinalQuality.Normal; + else if (entity.Comp.Quality == Quality.Junk) + entity.Comp.FinalQuality = FinalQuality.Junk; + else if (entity.Comp.Quality == Quality.Nasty) + entity.Comp.FinalQuality = FinalQuality.Nasty; + else if (entity.Comp.Quality == Quality.Toxin) + entity.Comp.FinalQuality = FinalQuality.Toxin; + else if (entity.Comp.Quality == Quality.Trash) + entity.Comp.FinalQuality = FinalQuality.Trash; + + if (reverseFoodQuality) + { + if (entity.Comp.Quality == Quality.High) + entity.Comp.FinalQuality = FinalQuality.Toxin; + else if (entity.Comp.Quality == Quality.Normal) + entity.Comp.FinalQuality = FinalQuality.Nasty; + else if (entity.Comp.Quality == Quality.Nasty) + entity.Comp.FinalQuality = FinalQuality.Normal; + else if (entity.Comp.Quality == Quality.Toxin) + entity.Comp.FinalQuality = FinalQuality.High; + } + + // TODO: Add detection for fried food on nasty to update it to toxin for goblins. + // TODO: Add inspect food but only for goblin eyes to see, goblins can tell food quality. + + string[] toxinsRegent = { "Toxin", "CarpoToxin", "Mold", "Amatoxin", "SulfuricAcid" }; + var speedRegent = "Stimulants"; + var damagingRegent = "Toxin"; + var emoteId = "Laugh"; + + TryComp(args.Target.Value, out var bloodStream); + + switch (entity.Comp.FinalQuality) + { + case FinalQuality.High: + if (reverseFoodQuality) + { + if (_solutionContainer.ResolveSolution(stomachToUse.Owner, stomachToUse.BodySolutionName, ref stomachToUse.Solution)) + { + foreach (var reagent in toxinsRegent) + _solutionContainer.RemoveReagent(stomachToUse.Solution.Value, reagent, FixedPoint2.New((int) transferAmount)); // Remove from body before it goes to blood + _solutionContainer.RemoveReagent(stomachToUse.Solution.Value, "Flavorol", FixedPoint2.New((int) transferAmount)); // Remove from body before it goes to blood + } + if (_solutionContainer.ResolveSolution(args.Target.Value, bloodStream!.ChemicalSolutionName, ref bloodStream.ChemicalSolution)) + _solutionContainer.TryAddReagent(bloodStream.ChemicalSolution.Value, speedRegent, FixedPoint2.New((int) transferAmount / 3), out _); // Add to blood + } + else + { + + } + break; + case FinalQuality.Normal: + if (reverseFoodQuality) + { + if (_solutionContainer.ResolveSolution(stomachToUse.Owner, stomachToUse.BodySolutionName, ref stomachToUse.Solution)) + { + foreach (var reagent in toxinsRegent) + _solutionContainer.RemoveReagent(stomachToUse.Solution.Value, reagent, FixedPoint2.New((int) transferAmount)); // Remove from body before it goes to blood + _solutionContainer.RemoveReagent(stomachToUse.Solution.Value, "Flavorol", FixedPoint2.New((int) transferAmount)); // Remove from body before it goes to blood + } + if (_solutionContainer.ResolveSolution(args.Target.Value, bloodStream!.ChemicalSolutionName, ref bloodStream.ChemicalSolution)) + _solutionContainer.TryAddReagent(bloodStream.ChemicalSolution.Value, speedRegent, FixedPoint2.New((int) transferAmount / 5), out _); // Add to blood + } + else + { + + } + break; + case FinalQuality.Junk: + if (reverseFoodQuality) + { + if (_solutionContainer.ResolveSolution(stomachToUse.Owner, stomachToUse.BodySolutionName, ref stomachToUse.Solution)) + { + foreach (var reagent in toxinsRegent) + _solutionContainer.RemoveReagent(stomachToUse.Solution.Value, reagent, FixedPoint2.New((int) transferAmount)); // Remove from body before it goes to blood + _solutionContainer.RemoveReagent(stomachToUse.Solution.Value, "Flavorol", FixedPoint2.New((int) transferAmount)); // Remove from body before it goes to blood + } + if (_solutionContainer.ResolveSolution(args.Target.Value, bloodStream!.ChemicalSolutionName, ref bloodStream.ChemicalSolution)) + _solutionContainer.TryAddReagent(bloodStream.ChemicalSolution.Value, speedRegent, FixedPoint2.New((int) transferAmount / 7), out _); // Add to blood + } + else + { + + } + break; + case FinalQuality.Nasty: + if (reverseFoodQuality) + { + if (_solutionContainer.ResolveSolution(stomachToUse.Owner, stomachToUse.BodySolutionName, ref stomachToUse.Solution)) + _solutionContainer.RemoveReagent(stomachToUse.Solution.Value, "Flavorol", FixedPoint2.New((int) transferAmount)); // Remove from body before it goes to blood + if (_solutionContainer.ResolveSolution(args.Target.Value, bloodStream!.ChemicalSolutionName, ref bloodStream.ChemicalSolution)) + _solutionContainer.TryAddReagent(bloodStream.ChemicalSolution.Value, damagingRegent, FixedPoint2.New((int) transferAmount / 5), out _); // Add to blood + _stuttering.DoStutter(args.Target.Value, TimeSpan.FromSeconds(5), false); // Gives stuttering + _jittering.DoJitter(args.Target.Value, TimeSpan.FromSeconds(5), true, 40f, 4f, true, null); + } + else + { + + } + break; + case FinalQuality.Toxin: + if (reverseFoodQuality) + { + if (_solutionContainer.ResolveSolution(stomachToUse.Owner, stomachToUse.BodySolutionName, ref stomachToUse.Solution)) + _solutionContainer.RemoveReagent(stomachToUse.Solution.Value, "Flavorol", FixedPoint2.New((int) transferAmount)); // Remove from body before it goes to blood + if (_solutionContainer.ResolveSolution(args.Target.Value, bloodStream!.ChemicalSolutionName, ref bloodStream.ChemicalSolution)) + _solutionContainer.TryAddReagent(bloodStream.ChemicalSolution.Value, damagingRegent, FixedPoint2.New((int) transferAmount / 3), out _); // Add to blood + _stuttering.DoStutter(args.Target.Value, TimeSpan.FromSeconds(5), false); // Gives stuttering + _jittering.DoJitter(args.Target.Value, TimeSpan.FromSeconds(5), true, 80f, 8f, true, null); + _chat.TryEmoteWithoutChat(args.Target.Value, emoteId); + + if (RobustRandom.Prob(.05f)) // 5% to puke + _vomit.Vomit(args.Target.Value); + } + else + { + + } + break; + case FinalQuality.Trash: + if (_solutionContainer.ResolveSolution(stomachToUse.Owner, stomachToUse.BodySolutionName, ref stomachToUse.Solution)) + { + foreach (var reagent in toxinsRegent) + _solutionContainer.RemoveReagent(stomachToUse!.Solution.Value, reagent, FixedPoint2.New((int) transferAmount)); // Remove from body before it goes to blood + _solutionContainer.RemoveReagent(stomachToUse!.Solution.Value, "Flavorol", FixedPoint2.New((int) transferAmount)); // Remove from body before it goes to blood + } + if (_solutionContainer.ResolveSolution(args.Target.Value, bloodStream!.ChemicalSolutionName, ref bloodStream.ChemicalSolution)) + _solutionContainer.TryAddReagent(bloodStream.ChemicalSolution.Value, speedRegent, FixedPoint2.New((int) transferAmount), out _); // Add to blood + break; + default: + throw new ArgumentOutOfRangeException($"No implemented mask radio behavior for {entity.Comp.Quality}!"); + } /// Frontier + var flavors = args.FlavorMessage; if (forceFeed) @@ -402,6 +553,11 @@ private bool IsDigestibleBy(EntityUid food, FoodComponent component, List<(Stoma // Run through the mobs' stomachs foreach (var (comp, _) in stomachs) { + // Frontier - Allow trash eating + if (!comp.TrashDigestion && component.Quality == Quality.Trash) + return false; + // Frontier - Allow trash eating + // Find a stomach with a SpecialDigestible if (comp.SpecialDigestible == null) continue; diff --git a/Resources/Locale/en-US/_NF/flavors/flavor-profiles.ftl b/Resources/Locale/en-US/_NF/flavors/flavor-profiles.ftl new file mode 100644 index 00000000000..24494b508e3 --- /dev/null +++ b/Resources/Locale/en-US/_NF/flavors/flavor-profiles.ftl @@ -0,0 +1 @@ +flavor-base-trashjuice = trashy diff --git a/Resources/Locale/en-US/_NF/reagents/foods.ftl b/Resources/Locale/en-US/_NF/reagents/foods.ftl index c4e85782ce8..bd9ed7bcfc9 100644 --- a/Resources/Locale/en-US/_NF/reagents/foods.ftl +++ b/Resources/Locale/en-US/_NF/reagents/foods.ftl @@ -1 +1,4 @@ -reagent-name-flaverol = Flaverol \ No newline at end of file +reagent-name-flaverol = Flaverol + +reagent-name-trashjuice = trash juices +reagent-desc-trashjuice = Do you really want to know what it is? diff --git a/Resources/Locale/en-US/_NF/reagents/physical-desc.ftl b/Resources/Locale/en-US/_NF/reagents/physical-desc.ftl new file mode 100644 index 00000000000..24bb74a5ea4 --- /dev/null +++ b/Resources/Locale/en-US/_NF/reagents/physical-desc.ftl @@ -0,0 +1 @@ +reagent-physical-desc-trashjuice = ... Wait.. Did it just move?