CompostingSystem.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. using Content.Shared.Composting;
  2. using Content.Shared.Examine;
  3. using Content.Shared.Hands.Components;
  4. using Content.Shared.Hands.EntitySystems;
  5. using Content.Shared.Interaction;
  6. using Content.Shared.Popups;
  7. using Robust.Shared.Prototypes;
  8. using Robust.Shared.Timing;
  9. using System.Linq;
  10. using Content.Shared.Tag;
  11. using Content.Shared.Destructible;
  12. namespace Content.Server.Composting;
  13. public sealed partial class CompostingSystem : EntitySystem
  14. {
  15. [Dependency] private readonly IGameTiming _gameTiming = default!;
  16. [Dependency] private readonly IPrototypeManager _prototype = default!;
  17. [Dependency] private readonly SharedHandsSystem _hands = default!;
  18. [Dependency] private readonly SharedPopupSystem _popup = default!;
  19. public override void Initialize()
  20. {
  21. base.Initialize();
  22. SubscribeLocalEvent<CompostingComponent, InteractUsingEvent>(OnInteractUsing);
  23. SubscribeLocalEvent<CompostingComponent, InteractHandEvent>(OnInteractHand);
  24. SubscribeLocalEvent<CompostingComponent, ExaminedEvent>(OnExamined);
  25. SubscribeLocalEvent<CompostingComponent, DestructionEventArgs>(OnDestroyed);
  26. }
  27. /// <summary>
  28. /// Handles inserting a compostable item into the composter.
  29. /// </summary>
  30. private void OnInteractUsing(EntityUid uid, CompostingComponent component, InteractUsingEvent args)
  31. {
  32. if (args.Handled)
  33. return;
  34. var item = args.Used;
  35. if (!IsCompostable(item, component))
  36. {
  37. _popup.PopupEntity($"This item cannot be used to make {component.OutputName}.", uid, args.User);
  38. return;
  39. }
  40. // Calculates actual load inside (composting + ready compost)
  41. var currentLoad = component.CompostingItems.Count + component.ReadyCompost;
  42. if (currentLoad >= component.MaxCapacity)
  43. {
  44. _popup.PopupEntity("It wont fit.", uid, args.User);
  45. return;
  46. }
  47. // Add item to composting process and delete it from the world
  48. component.CompostingItems[item] = _gameTiming.CurTime + TimeSpan.FromMinutes(component.CompostTime);
  49. QueueDel(item);
  50. _popup.PopupEntity("You add the item.", uid, args.User);
  51. args.Handled = true;
  52. }
  53. /// <summary>
  54. /// Checks if an item is compostable based on its tags.
  55. /// </summary>
  56. private bool IsCompostable(EntityUid item, CompostingComponent component)
  57. {
  58. var tagComponent = Comp<TagComponent>(item);
  59. var tags = tagComponent?.Tags.Select(tag => tag.Id).ToArray() ?? Array.Empty<string>();
  60. return component.Whitelist.Any(tag => tags.Contains(tag));
  61. }
  62. /// <summary>
  63. /// Handles collecting finished compost with an empty hand.
  64. /// </summary>
  65. private void OnInteractHand(EntityUid uid, CompostingComponent component, InteractHandEvent args)
  66. {
  67. if (args.Handled || component.ReadyCompost <= 0)
  68. return;
  69. // Spawn compost and try to place it in the player's hand
  70. var compost = Spawn(component.OutputPrototype, Transform(uid).MapPosition);
  71. if (_hands.TryPickupAnyHand(args.User, compost))
  72. {
  73. component.ReadyCompost--;
  74. _popup.PopupEntity($"You collect a unit of {component.OutputName}.", uid, args.User);
  75. }
  76. else
  77. {
  78. _popup.PopupEntity("Your hands are full.", uid, args.User);
  79. }
  80. args.Handled = true;
  81. }
  82. /// <summary>
  83. /// Updates composting progress and converts finished items to ready compost.
  84. /// </summary>
  85. public override void Update(float frameTime)
  86. {
  87. base.Update(frameTime);
  88. var query = EntityQueryEnumerator<CompostingComponent>();
  89. while (query.MoveNext(out var uid, out var component))
  90. {
  91. var currentTime = _gameTiming.CurTime;
  92. var toRemove = new List<EntityUid>();
  93. foreach (var (item, endTime) in component.CompostingItems)
  94. {
  95. if (currentTime >= endTime)
  96. {
  97. toRemove.Add(item);
  98. component.ReadyCompost++;
  99. }
  100. }
  101. foreach (var item in toRemove)
  102. {
  103. component.CompostingItems.Remove(item);
  104. }
  105. }
  106. }
  107. /// <summary>
  108. /// Displays the amount of ready compost when examining the composter.
  109. /// </summary>
  110. /// <summary>
  111. /// Displays the status of the compost bin when examined.
  112. /// </summary>
  113. private void OnExamined(EntityUid uid, CompostingComponent component, ExaminedEvent args)
  114. {
  115. if (!args.IsInDetailsRange)
  116. return;
  117. var compostingCount = component.CompostingItems.Count;
  118. var readyCompost = component.ReadyCompost;
  119. if (compostingCount == 0 && readyCompost == 0)
  120. {
  121. args.PushMarkup("It's empty.");
  122. return;
  123. }
  124. if (compostingCount > 0)
  125. {
  126. args.PushMarkup($"Its currently processing.");
  127. }
  128. if (readyCompost > 0)
  129. {
  130. args.PushMarkup($"There are {readyCompost} units of {component.OutputName} ready.");
  131. }
  132. }
  133. private void OnDestroyed(EntityUid uid, CompostingComponent component, DestructionEventArgs args)
  134. {
  135. // Drops all ready compost
  136. for (int i = 0; i < component.ReadyCompost; i++)
  137. {
  138. Spawn(component.OutputPrototype, Transform(uid).MapPosition);
  139. }
  140. }
  141. }