1
0

VomitSystem.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. using Content.Server.Body.Components;
  2. using Content.Server.Body.Systems;
  3. using Content.Server.Fluids.EntitySystems;
  4. using Content.Server.Forensics;
  5. using Content.Server.Popups;
  6. using Content.Server.Stunnable;
  7. using Content.Shared.Chemistry.EntitySystems;
  8. using Content.Shared.Chemistry.Components;
  9. using Content.Shared.Chemistry.Reagent;
  10. using Content.Shared.IdentityManagement;
  11. using Content.Shared.Nutrition.Components;
  12. using Content.Shared.Nutrition.EntitySystems;
  13. using Content.Shared.StatusEffect;
  14. using Robust.Server.Audio;
  15. using Robust.Shared.Audio;
  16. using Robust.Shared.Prototypes;
  17. namespace Content.Server.Medical
  18. {
  19. public sealed class VomitSystem : EntitySystem
  20. {
  21. [Dependency] private readonly IPrototypeManager _proto = default!;
  22. [Dependency] private readonly AudioSystem _audio = default!;
  23. [Dependency] private readonly BodySystem _body = default!;
  24. [Dependency] private readonly HungerSystem _hunger = default!;
  25. [Dependency] private readonly PopupSystem _popup = default!;
  26. [Dependency] private readonly PuddleSystem _puddle = default!;
  27. [Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!;
  28. [Dependency] private readonly StunSystem _stun = default!;
  29. [Dependency] private readonly ThirstSystem _thirst = default!;
  30. [Dependency] private readonly ForensicsSystem _forensics = default!;
  31. [Dependency] private readonly BloodstreamSystem _bloodstream = default!;
  32. [ValidatePrototypeId<SoundCollectionPrototype>]
  33. private const string VomitCollection = "Vomit";
  34. private readonly SoundSpecifier _vomitSound = new SoundCollectionSpecifier(VomitCollection,
  35. AudioParams.Default.WithVariation(0.2f).WithVolume(-4f));
  36. /// <summary>
  37. /// Make an entity vomit, if they have a stomach.
  38. /// </summary>
  39. public void Vomit(EntityUid uid, float thirstAdded = -40f, float hungerAdded = -40f)
  40. {
  41. // Main requirement: You have a stomach
  42. var stomachList = _body.GetBodyOrganEntityComps<StomachComponent>(uid);
  43. if (stomachList.Count == 0)
  44. return;
  45. // Vomiting makes you hungrier and thirstier
  46. if (TryComp<HungerComponent>(uid, out var hunger))
  47. _hunger.ModifyHunger(uid, hungerAdded, hunger);
  48. if (TryComp<ThirstComponent>(uid, out var thirst))
  49. _thirst.ModifyThirst(uid, thirst, thirstAdded);
  50. // It fully empties the stomach, this amount from the chem stream is relatively small
  51. var solutionSize = (MathF.Abs(thirstAdded) + MathF.Abs(hungerAdded)) / 6;
  52. // Apply a bit of slowdown
  53. if (TryComp<StatusEffectsComponent>(uid, out var status))
  54. _stun.TrySlowdown(uid, TimeSpan.FromSeconds(solutionSize), true, 0.5f, 0.5f, status);
  55. // TODO: Need decals
  56. var solution = new Solution();
  57. // Empty the stomach out into it
  58. foreach (var stomach in stomachList)
  59. {
  60. if (_solutionContainer.ResolveSolution(stomach.Owner, StomachSystem.DefaultSolutionName, ref stomach.Comp1.Solution, out var sol))
  61. {
  62. solution.AddSolution(sol, _proto);
  63. sol.RemoveAllSolution();
  64. _solutionContainer.UpdateChemicals(stomach.Comp1.Solution.Value);
  65. }
  66. }
  67. // Adds a tiny amount of the chem stream from earlier along with vomit
  68. if (TryComp<BloodstreamComponent>(uid, out var bloodStream))
  69. {
  70. const float chemMultiplier = 0.1f;
  71. var vomitAmount = solutionSize;
  72. // Takes 10% of the chemicals removed from the chem stream
  73. if (_solutionContainer.ResolveSolution(uid, bloodStream.ChemicalSolutionName, ref bloodStream.ChemicalSolution))
  74. {
  75. var vomitChemstreamAmount = _solutionContainer.SplitSolution(bloodStream.ChemicalSolution.Value, vomitAmount);
  76. vomitChemstreamAmount.ScaleSolution(chemMultiplier);
  77. solution.AddSolution(vomitChemstreamAmount, _proto);
  78. vomitAmount -= (float)vomitChemstreamAmount.Volume;
  79. }
  80. // Makes a vomit solution the size of 90% of the chemicals removed from the chemstream
  81. solution.AddReagent(new ReagentId("Vomit", _bloodstream.GetEntityBloodData(uid)), vomitAmount); // TODO: Dehardcode vomit prototype
  82. }
  83. if (_puddle.TrySpillAt(uid, solution, out var puddle, false))
  84. {
  85. _forensics.TransferDna(puddle, uid, false);
  86. }
  87. // Force sound to play as spill doesn't work if solution is empty.
  88. _audio.PlayPvs(_vomitSound, uid);
  89. _popup.PopupEntity(Loc.GetString("disease-vomit", ("person", Identity.Entity(uid, EntityManager))), uid);
  90. }
  91. }
  92. }