StomachSystem.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. using Content.Server.Body.Components;
  2. using Content.Shared.Chemistry.EntitySystems;
  3. using Content.Shared.Body.Organ;
  4. using Content.Shared.Chemistry.Components;
  5. using Content.Shared.Chemistry.Components.SolutionManager;
  6. using Robust.Shared.Timing;
  7. using Robust.Shared.Utility;
  8. namespace Content.Server.Body.Systems
  9. {
  10. public sealed class StomachSystem : EntitySystem
  11. {
  12. [Dependency] private readonly IGameTiming _gameTiming = default!;
  13. [Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!;
  14. public const string DefaultSolutionName = "stomach";
  15. public override void Initialize()
  16. {
  17. SubscribeLocalEvent<StomachComponent, MapInitEvent>(OnMapInit);
  18. SubscribeLocalEvent<StomachComponent, EntityUnpausedEvent>(OnUnpaused);
  19. SubscribeLocalEvent<StomachComponent, ApplyMetabolicMultiplierEvent>(OnApplyMetabolicMultiplier);
  20. }
  21. private void OnMapInit(Entity<StomachComponent> ent, ref MapInitEvent args)
  22. {
  23. ent.Comp.NextUpdate = _gameTiming.CurTime + ent.Comp.UpdateInterval;
  24. }
  25. private void OnUnpaused(Entity<StomachComponent> ent, ref EntityUnpausedEvent args)
  26. {
  27. ent.Comp.NextUpdate += args.PausedTime;
  28. }
  29. public override void Update(float frameTime)
  30. {
  31. var query = EntityQueryEnumerator<StomachComponent, OrganComponent, SolutionContainerManagerComponent>();
  32. while (query.MoveNext(out var uid, out var stomach, out var organ, out var sol))
  33. {
  34. if (_gameTiming.CurTime < stomach.NextUpdate)
  35. continue;
  36. stomach.NextUpdate += stomach.UpdateInterval;
  37. // Get our solutions
  38. if (!_solutionContainerSystem.ResolveSolution((uid, sol), DefaultSolutionName, ref stomach.Solution, out var stomachSolution))
  39. continue;
  40. if (organ.Body is not { } body || !_solutionContainerSystem.TryGetSolution(body, stomach.BodySolutionName, out var bodySolution))
  41. continue;
  42. var transferSolution = new Solution();
  43. var queue = new RemQueue<StomachComponent.ReagentDelta>();
  44. foreach (var delta in stomach.ReagentDeltas)
  45. {
  46. delta.Increment(stomach.UpdateInterval);
  47. if (delta.Lifetime > stomach.DigestionDelay)
  48. {
  49. if (stomachSolution.TryGetReagent(delta.ReagentQuantity.Reagent, out var reagent))
  50. {
  51. if (reagent.Quantity > delta.ReagentQuantity.Quantity)
  52. reagent = new(reagent.Reagent, delta.ReagentQuantity.Quantity);
  53. stomachSolution.RemoveReagent(reagent);
  54. transferSolution.AddReagent(reagent);
  55. }
  56. queue.Add(delta);
  57. }
  58. }
  59. foreach (var item in queue)
  60. {
  61. stomach.ReagentDeltas.Remove(item);
  62. }
  63. _solutionContainerSystem.UpdateChemicals(stomach.Solution.Value);
  64. // Transfer everything to the body solution!
  65. _solutionContainerSystem.TryAddSolution(bodySolution.Value, transferSolution);
  66. }
  67. }
  68. private void OnApplyMetabolicMultiplier(
  69. Entity<StomachComponent> ent,
  70. ref ApplyMetabolicMultiplierEvent args)
  71. {
  72. if (args.Apply)
  73. {
  74. ent.Comp.UpdateInterval *= args.Multiplier;
  75. return;
  76. }
  77. // This way we don't have to worry about it breaking if the stasis bed component is destroyed
  78. ent.Comp.UpdateInterval /= args.Multiplier;
  79. }
  80. public bool CanTransferSolution(
  81. EntityUid uid,
  82. Solution solution,
  83. StomachComponent? stomach = null,
  84. SolutionContainerManagerComponent? solutions = null)
  85. {
  86. return Resolve(uid, ref stomach, ref solutions, logMissing: false)
  87. && _solutionContainerSystem.ResolveSolution((uid, solutions), DefaultSolutionName, ref stomach.Solution, out var stomachSolution)
  88. // TODO: For now no partial transfers. Potentially change by design
  89. && stomachSolution.CanAddSolution(solution);
  90. }
  91. public bool TryTransferSolution(
  92. EntityUid uid,
  93. Solution solution,
  94. StomachComponent? stomach = null,
  95. SolutionContainerManagerComponent? solutions = null)
  96. {
  97. if (!Resolve(uid, ref stomach, ref solutions, logMissing: false)
  98. || !_solutionContainerSystem.ResolveSolution((uid, solutions), DefaultSolutionName, ref stomach.Solution)
  99. || !CanTransferSolution(uid, solution, stomach, solutions))
  100. {
  101. return false;
  102. }
  103. _solutionContainerSystem.TryAddSolution(stomach.Solution.Value, solution);
  104. // Add each reagent to ReagentDeltas. Used to track how long each reagent has been in the stomach
  105. foreach (var reagent in solution.Contents)
  106. {
  107. stomach.ReagentDeltas.Add(new StomachComponent.ReagentDelta(reagent));
  108. }
  109. return true;
  110. }
  111. }
  112. }