mirror of
https://github.com/space-syndicate/space-station-14.git
synced 2026-10-09 10:21:18 +03:00
* ready * oop forgot the HUD stuff * woooo examinable generalized tooooo * oop I forgot to rename the files * bungled the merge, I guess * this is called hubris * Verin's comments * PR comments how did I use `ProtoId<> Hunger` in more than a few spots but then just say "thirst can stay a literal :^)"? also changed a few spots to my beloved ``` functionInvocation( one param per line ) ``` ``` * Satiation effect condition now with ADDED FUNCTIONALITY?? :o * tfw you trust the markov chain recommendation because long generic type names are tough q-q * TFW YOU TRUST THE MARKOV CHAIN BUT IT DOESN'T UNDERSTAND THE DIFFERING SEMANTICS OF MAX AND MIN AHHHHH * tfw you think to yourself "i need to fix the effects", but then forget to and the code doesn't even compile. * centralize satiation constants * other small comments * The enum is dead. But at what cost? * oop * like 12 more ooperses * green checks are mine by right; I have performed the rites; I have done my part; you will not deny me this succor * oops I changed the semantics from `<=` to just `<` and didn't update the tests :) * serialization has bested me :agony: also PR comments * never trust the auto merge :agony: * literally just this * force engine back to master because idk why it's different * fix randomness and update master * submodule fuckery * fall before my might * okay I ran the linter, ARE YOU HAPPY?? * cursed ovis, trouble me no more * protoman stuff * inb4 linter bonks me * break non-critical stuff from the main satiation proto *  inb4 this breaks something somewhere lmao * my two greatest PRs COLLIDE I wonder why robust says it's changed :hmmclueless * sanity is at an all-time low * serialization, I guess * I don't believe you * field deltas on class \w*satiation\w*components * PR comments * 我做泥團子 😔 * doc + kill one property that's trivially accessible after the threshold caching changes * fixes --------- Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com> Co-authored-by: AJCM-git <ajcm_mail@disroot.org>
140 lines
5.5 KiB
C#
140 lines
5.5 KiB
C#
using Content.Shared.Body;
|
|
using Content.Shared.Body.Components;
|
|
using Content.Shared.Body.Systems;
|
|
using Content.Shared.Chemistry.Components;
|
|
using Content.Shared.Chemistry.EntitySystems;
|
|
using Content.Shared.Chemistry.Reagent;
|
|
using Content.Shared.Fluids;
|
|
using Content.Shared.Forensics.Systems;
|
|
using Content.Shared.IdentityManagement;
|
|
using Content.Shared.Mobs.Systems;
|
|
using Content.Shared.Movement.Systems;
|
|
using Content.Shared.Nutrition.Components;
|
|
using Content.Shared.Nutrition.EntitySystems;
|
|
using Content.Shared.Nutrition.Prototypes;
|
|
using Content.Shared.Popups;
|
|
using Robust.Shared.Audio;
|
|
using Robust.Shared.Audio.Systems;
|
|
using Robust.Shared.Network;
|
|
using Robust.Shared.Prototypes;
|
|
|
|
namespace Content.Shared.Medical;
|
|
|
|
public sealed partial class VomitSystem : EntitySystem
|
|
{
|
|
[Dependency] private INetManager _netManager = default!;
|
|
[Dependency] private MobStateSystem _mobState = default!;
|
|
[Dependency] private MovementModStatusSystem _movementMod = default!;
|
|
[Dependency] private SharedAudioSystem _audio = default!;
|
|
[Dependency] private SharedBloodstreamSystem _bloodstream = default!;
|
|
[Dependency] private SharedForensicsSystem _forensics = default!;
|
|
[Dependency] private SharedPopupSystem _popup = default!;
|
|
[Dependency] private SharedPuddleSystem _puddle = default!;
|
|
[Dependency] private SatiationSystem _satiation = default!;
|
|
[Dependency] private SharedSolutionContainerSystem _solutionContainer = default!;
|
|
|
|
public override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
|
|
SubscribeLocalEvent<StomachComponent, BodyRelayedEvent<TryVomitEvent>>(TryVomitSolution);
|
|
}
|
|
|
|
private const float ChemMultiplier = 0.1f;
|
|
|
|
private static readonly ProtoId<SoundCollectionPrototype> VomitCollection = "Vomit";
|
|
|
|
private static readonly ProtoId<ReagentPrototype> VomitPrototype = "Vomit"; // TODO: Dehardcode vomit prototype
|
|
|
|
private readonly SoundSpecifier _vomitSound = new SoundCollectionSpecifier(VomitCollection,
|
|
AudioParams.Default.WithVariation(0.2f).WithVolume(-4f));
|
|
|
|
private void TryVomitSolution(Entity<StomachComponent> ent, ref BodyRelayedEvent<TryVomitEvent> args)
|
|
{
|
|
if (!_solutionContainer.ResolveSolution(ent.Owner,
|
|
StomachSystem.DefaultSolutionName,
|
|
ref ent.Comp.Solution,
|
|
out var sol))
|
|
return;
|
|
|
|
// Empty stomach solution into the new vomit solution
|
|
args.Args.Sol.AddSolution(sol, ProtoMan);
|
|
sol.RemoveAllSolution();
|
|
|
|
// Remind the stomach that it's empty.
|
|
_solutionContainer.UpdateChemicals(ent.Comp.Solution.Value);
|
|
args.Args = args.Args with { Handled = true };
|
|
}
|
|
|
|
/// <summary>
|
|
/// Make an entity vomit, if they have a stomach.
|
|
/// </summary>
|
|
public void Vomit(EntityUid uid, float thirstAdded = -40f, float hungerAdded = -40f, bool force = false)
|
|
{
|
|
// Vomit only if entity is alive
|
|
// Ignore condition if force was set to true
|
|
if (!force && _mobState.IsDead(uid))
|
|
return;
|
|
|
|
// TODO: Need decals
|
|
var solution = new Solution();
|
|
|
|
var ev = new TryVomitEvent(solution, force);
|
|
RaiseLocalEvent(uid, ref ev);
|
|
|
|
if (!ev.Handled)
|
|
return;
|
|
|
|
// Vomiting makes you hungrier and thirstier
|
|
if (TryComp<SatiationComponent>(uid, out var satiation))
|
|
{
|
|
Entity<SatiationComponent> entity = (uid, satiation);
|
|
_satiation.ModifyValue(entity, SatiationSystem.Hunger, hungerAdded);
|
|
_satiation.ModifyValue(entity, SatiationSystem.Thirst, thirstAdded);
|
|
}
|
|
|
|
// It fully empties the stomach, this amount from the chem stream is relatively small
|
|
var solutionSize = (MathF.Abs(thirstAdded) + MathF.Abs(hungerAdded)) / 6;
|
|
|
|
// Apply a bit of slowdown
|
|
_movementMod.TryUpdateMovementSpeedModDuration(uid, MovementModStatusSystem.VomitingSlowdown, TimeSpan.FromSeconds(solutionSize), 0.5f);
|
|
|
|
// Adds a tiny amount of the chem stream from earlier along with vomit
|
|
if (TryComp<BloodstreamComponent>(uid, out var bloodStream))
|
|
{
|
|
var vomitAmount = solutionSize;
|
|
|
|
// Flushes small portion of the chemicals removed from the bloodstream stream
|
|
if (_solutionContainer.ResolveSolution(uid, bloodStream.BloodSolutionName, ref bloodStream.BloodSolution))
|
|
{
|
|
var vomitChemstreamAmount = _bloodstream.FlushChemicals((uid, bloodStream), vomitAmount);
|
|
|
|
if (vomitChemstreamAmount != null)
|
|
{
|
|
vomitChemstreamAmount.ScaleSolution(ChemMultiplier);
|
|
solution.AddSolution(vomitChemstreamAmount, ProtoMan);
|
|
vomitAmount -= (float)vomitChemstreamAmount.Volume;
|
|
}
|
|
}
|
|
|
|
// Makes a vomit solution the size of 90% of the chemicals removed from the chemstream
|
|
solution.AddReagent(new ReagentId(VomitPrototype, _bloodstream.GetEntityBloodData((uid, bloodStream))), vomitAmount);
|
|
}
|
|
|
|
if (_puddle.TrySpillAt(uid, solution, out var puddle, false))
|
|
{
|
|
_forensics.TransferDna(puddle, uid, false);
|
|
}
|
|
|
|
|
|
if (!_netManager.IsServer)
|
|
return;
|
|
|
|
// Force sound to play as spill doesn't work if solution is empty.
|
|
_audio.PlayPvs(_vomitSound, uid);
|
|
_popup.PopupEntity(Loc.GetString("disease-vomit", ("person", Identity.Entity(uid, EntityManager))), uid);
|
|
}
|
|
}
|
|
|
|
[ByRefEvent]
|
|
public record struct TryVomitEvent(Solution Sol, bool Forced = false, bool Handled = false);
|