1
0

SecretStashSystem.cs 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. using Content.Shared.Construction.EntitySystems;
  2. using Content.Shared.Destructible;
  3. using Content.Shared.Hands.Components;
  4. using Content.Shared.Hands.EntitySystems;
  5. using Content.Shared.IdentityManagement;
  6. using Content.Shared.Interaction;
  7. using Content.Shared.Item;
  8. using Content.Shared.Materials;
  9. using Content.Shared.Popups;
  10. using Content.Shared.Storage.Components;
  11. using Content.Shared.Tools.EntitySystems;
  12. using Content.Shared.Verbs;
  13. using Content.Shared.Whitelist;
  14. using Robust.Shared.Audio;
  15. using Robust.Shared.Audio.Systems;
  16. using Robust.Shared.Containers;
  17. using Robust.Shared.Map;
  18. namespace Content.Shared.Storage.EntitySystems;
  19. /// <summary>
  20. /// Secret Stash allows an item to be hidden within.
  21. /// </summary>
  22. public sealed class SecretStashSystem : EntitySystem
  23. {
  24. [Dependency] private readonly SharedPopupSystem _popupSystem = default!;
  25. [Dependency] private readonly SharedHandsSystem _handsSystem = default!;
  26. [Dependency] private readonly SharedContainerSystem _containerSystem = default!;
  27. [Dependency] private readonly SharedItemSystem _item = default!;
  28. [Dependency] private readonly SharedAudioSystem _audio = default!;
  29. [Dependency] private readonly ToolOpenableSystem _toolOpenableSystem = default!;
  30. [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
  31. public override void Initialize()
  32. {
  33. base.Initialize();
  34. SubscribeLocalEvent<SecretStashComponent, ComponentInit>(OnInit);
  35. SubscribeLocalEvent<SecretStashComponent, DestructionEventArgs>(OnDestroyed);
  36. SubscribeLocalEvent<SecretStashComponent, GotReclaimedEvent>(OnReclaimed);
  37. SubscribeLocalEvent<SecretStashComponent, InteractUsingEvent>(OnInteractUsing, after: new[] { typeof(ToolOpenableSystem), typeof(AnchorableSystem) });
  38. SubscribeLocalEvent<SecretStashComponent, InteractHandEvent>(OnInteractHand);
  39. SubscribeLocalEvent<SecretStashComponent, GetVerbsEvent<InteractionVerb>>(OnGetVerb);
  40. }
  41. private void OnInit(Entity<SecretStashComponent> entity, ref ComponentInit args)
  42. {
  43. entity.Comp.ItemContainer = _containerSystem.EnsureContainer<ContainerSlot>(entity, "stash", out _);
  44. }
  45. private void OnDestroyed(Entity<SecretStashComponent> entity, ref DestructionEventArgs args)
  46. {
  47. DropContentsAndAlert(entity);
  48. }
  49. private void OnReclaimed(Entity<SecretStashComponent> entity, ref GotReclaimedEvent args)
  50. {
  51. DropContentsAndAlert(entity, args.ReclaimerCoordinates);
  52. }
  53. private void OnInteractUsing(Entity<SecretStashComponent> entity, ref InteractUsingEvent args)
  54. {
  55. if (args.Handled || !IsStashOpen(entity))
  56. return;
  57. args.Handled = TryStashItem(entity, args.User, args.Used);
  58. }
  59. private void OnInteractHand(Entity<SecretStashComponent> entity, ref InteractHandEvent args)
  60. {
  61. if (args.Handled || !IsStashOpen(entity))
  62. return;
  63. args.Handled = TryGetItem(entity, args.User);
  64. }
  65. /// <summary>
  66. /// Tries to hide the given item into the stash.
  67. /// </summary>
  68. /// <returns>True if item was hidden inside stash and false otherwise.</returns>
  69. private bool TryStashItem(Entity<SecretStashComponent> entity, EntityUid userUid, EntityUid itemToHideUid)
  70. {
  71. if (!TryComp<ItemComponent>(itemToHideUid, out var itemComp))
  72. return false;
  73. _audio.PlayPredicted(entity.Comp.TryInsertItemSound, entity, userUid, AudioParams.Default.WithVariation(0.25f));
  74. // check if secret stash is already occupied
  75. var container = entity.Comp.ItemContainer;
  76. if (HasItemInside(entity))
  77. {
  78. var popup = Loc.GetString("comp-secret-stash-action-hide-container-not-empty");
  79. _popupSystem.PopupClient(popup, entity, userUid);
  80. return false;
  81. }
  82. // check if item is too big to fit into secret stash or is in the blacklist
  83. if (_item.GetSizePrototype(itemComp.Size) > _item.GetSizePrototype(entity.Comp.MaxItemSize) ||
  84. _whitelistSystem.IsBlacklistPass(entity.Comp.Blacklist, itemToHideUid))
  85. {
  86. var msg = Loc.GetString("comp-secret-stash-action-hide-item-too-big",
  87. ("item", itemToHideUid), ("stashname", GetStashName(entity)));
  88. _popupSystem.PopupClient(msg, entity, userUid);
  89. return false;
  90. }
  91. // try to move item from hands to stash container
  92. if (!_handsSystem.TryDropIntoContainer(userUid, itemToHideUid, container))
  93. return false;
  94. // all done, show success message
  95. var successMsg = Loc.GetString("comp-secret-stash-action-hide-success",
  96. ("item", itemToHideUid), ("stashname", GetStashName(entity)));
  97. _popupSystem.PopupClient(successMsg, entity, userUid);
  98. return true;
  99. }
  100. /// <summary>
  101. /// Try the given item in the stash and place it in users hand.
  102. /// If user can't take hold the item in their hands, the item will be dropped onto the ground.
  103. /// </summary>
  104. /// <returns>True if user received item.</returns>
  105. private bool TryGetItem(Entity<SecretStashComponent> entity, EntityUid userUid)
  106. {
  107. if (!TryComp<HandsComponent>(userUid, out var handsComp))
  108. return false;
  109. _audio.PlayPredicted(entity.Comp.TryRemoveItemSound, entity, userUid, AudioParams.Default.WithVariation(0.25f));
  110. // check if secret stash has something inside
  111. var itemInStash = entity.Comp.ItemContainer.ContainedEntity;
  112. if (itemInStash == null)
  113. return false;
  114. _handsSystem.PickupOrDrop(userUid, itemInStash.Value, handsComp: handsComp);
  115. // show success message
  116. var successMsg = Loc.GetString("comp-secret-stash-action-get-item-found-something",
  117. ("stashname", GetStashName(entity)));
  118. _popupSystem.PopupClient(successMsg, entity, userUid);
  119. return true;
  120. }
  121. private void OnGetVerb(Entity<SecretStashComponent> entity, ref GetVerbsEvent<InteractionVerb> args)
  122. {
  123. if (!args.CanInteract || !args.CanAccess || !entity.Comp.HasVerbs)
  124. return;
  125. var user = args.User;
  126. var item = args.Using;
  127. var stashName = GetStashName(entity);
  128. var itemVerb = new InteractionVerb();
  129. // This will add the verb relating to inserting / grabbing items.
  130. if (IsStashOpen(entity))
  131. {
  132. if (item != null)
  133. {
  134. itemVerb.Text = Loc.GetString("comp-secret-stash-verb-insert-into-stash");
  135. if (HasItemInside(entity))
  136. {
  137. itemVerb.Disabled = true;
  138. itemVerb.Message = Loc.GetString("comp-secret-stash-verb-insert-message-item-already-inside", ("stashname", stashName));
  139. }
  140. else
  141. {
  142. itemVerb.Message = Loc.GetString("comp-secret-stash-verb-insert-message-no-item", ("item", item), ("stashname", stashName));
  143. }
  144. itemVerb.Act = () => TryStashItem(entity, user, item.Value);
  145. }
  146. else
  147. {
  148. itemVerb.Text = Loc.GetString("comp-secret-stash-verb-take-out-item");
  149. itemVerb.Message = Loc.GetString("comp-secret-stash-verb-take-out-message-something", ("stashname", stashName));
  150. if (!HasItemInside(entity))
  151. {
  152. itemVerb.Disabled = true;
  153. itemVerb.Message = Loc.GetString("comp-secret-stash-verb-take-out-message-nothing", ("stashname", stashName));
  154. }
  155. itemVerb.Act = () => TryGetItem(entity, user);
  156. }
  157. args.Verbs.Add(itemVerb);
  158. }
  159. }
  160. #region Helper functions
  161. /// <returns>
  162. /// The stash name if it exists, or the entity name if it doesn't.
  163. /// </returns>
  164. private string GetStashName(Entity<SecretStashComponent> entity)
  165. {
  166. if (entity.Comp.SecretStashName == null)
  167. return Identity.Name(entity, EntityManager);
  168. return Loc.GetString(entity.Comp.SecretStashName);
  169. }
  170. /// <returns>
  171. /// True if the stash is open OR the there is no toolOpenableComponent attacheded to the entity
  172. /// and false otherwise.
  173. /// </returns>
  174. private bool IsStashOpen(Entity<SecretStashComponent> stash)
  175. {
  176. return _toolOpenableSystem.IsOpen(stash);
  177. }
  178. private bool HasItemInside(Entity<SecretStashComponent> entity)
  179. {
  180. return entity.Comp.ItemContainer.ContainedEntity != null;
  181. }
  182. /// <summary>
  183. /// Drop the item stored in the stash and alert all nearby players with a popup.
  184. /// </summary>
  185. private void DropContentsAndAlert(Entity<SecretStashComponent> entity, EntityCoordinates? cords = null)
  186. {
  187. var storedInside = _containerSystem.EmptyContainer(entity.Comp.ItemContainer, true, cords);
  188. if (storedInside != null && storedInside.Count >= 1)
  189. {
  190. var popup = Loc.GetString("comp-secret-stash-on-destroyed-popup", ("stashname", GetStashName(entity)));
  191. _popupSystem.PopupPredicted(popup, storedInside[0], null, PopupType.MediumCaution);
  192. }
  193. }
  194. #endregion
  195. }