FoldableSystem.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. using Content.Shared.Body.Components;
  2. using Content.Shared.Buckle;
  3. using Content.Shared.Buckle.Components;
  4. using Content.Shared.Storage.Components;
  5. using Content.Shared.Verbs;
  6. using Robust.Shared.Containers;
  7. using Robust.Shared.Serialization;
  8. using Robust.Shared.Utility;
  9. namespace Content.Shared.Foldable;
  10. public sealed class FoldableSystem : EntitySystem
  11. {
  12. [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
  13. [Dependency] private readonly SharedBuckleSystem _buckle = default!;
  14. [Dependency] private readonly SharedContainerSystem _container = default!;
  15. public override void Initialize()
  16. {
  17. base.Initialize();
  18. SubscribeLocalEvent<FoldableComponent, GetVerbsEvent<AlternativeVerb>>(AddFoldVerb);
  19. SubscribeLocalEvent<FoldableComponent, AfterAutoHandleStateEvent>(OnHandleState);
  20. SubscribeLocalEvent<FoldableComponent, ComponentInit>(OnFoldableInit);
  21. SubscribeLocalEvent<FoldableComponent, ContainerGettingInsertedAttemptEvent>(OnInsertEvent);
  22. SubscribeLocalEvent<FoldableComponent, InsertIntoEntityStorageAttemptEvent>(OnStoreThisAttempt);
  23. SubscribeLocalEvent<FoldableComponent, StorageOpenAttemptEvent>(OnFoldableOpenAttempt);
  24. SubscribeLocalEvent<FoldableComponent, StrapAttemptEvent>(OnStrapAttempt);
  25. }
  26. private void OnHandleState(EntityUid uid, FoldableComponent component, ref AfterAutoHandleStateEvent args)
  27. {
  28. SetFolded(uid, component, component.IsFolded);
  29. }
  30. private void OnFoldableInit(EntityUid uid, FoldableComponent component, ComponentInit args)
  31. {
  32. SetFolded(uid, component, component.IsFolded);
  33. }
  34. private void OnFoldableOpenAttempt(EntityUid uid, FoldableComponent component, ref StorageOpenAttemptEvent args)
  35. {
  36. if (component.IsFolded)
  37. args.Cancelled = true;
  38. }
  39. public void OnStoreThisAttempt(EntityUid uid, FoldableComponent comp, ref InsertIntoEntityStorageAttemptEvent args)
  40. {
  41. if (comp.IsFolded)
  42. args.Cancelled = true;
  43. }
  44. public void OnStrapAttempt(EntityUid uid, FoldableComponent comp, ref StrapAttemptEvent args)
  45. {
  46. if (comp.IsFolded)
  47. args.Cancelled = true;
  48. }
  49. /// <summary>
  50. /// Returns false if the entity isn't foldable.
  51. /// </summary>
  52. public bool IsFolded(EntityUid uid, FoldableComponent? component = null)
  53. {
  54. if (!Resolve(uid, ref component))
  55. return false;
  56. return component.IsFolded;
  57. }
  58. /// <summary>
  59. /// Set the folded state of the given <see cref="FoldableComponent"/>
  60. /// </summary>
  61. public void SetFolded(EntityUid uid, FoldableComponent component, bool folded)
  62. {
  63. component.IsFolded = folded;
  64. Dirty(uid, component);
  65. _appearance.SetData(uid, FoldedVisuals.State, folded);
  66. _buckle.StrapSetEnabled(uid, !component.IsFolded);
  67. var ev = new FoldedEvent(folded);
  68. RaiseLocalEvent(uid, ref ev);
  69. }
  70. private void OnInsertEvent(EntityUid uid, FoldableComponent component, ContainerGettingInsertedAttemptEvent args)
  71. {
  72. if (!component.IsFolded && !component.CanFoldInsideContainer)
  73. args.Cancel();
  74. }
  75. public bool TryToggleFold(EntityUid uid, FoldableComponent comp)
  76. {
  77. return TrySetFolded(uid, comp, !comp.IsFolded);
  78. }
  79. public bool CanToggleFold(EntityUid uid, FoldableComponent? fold = null)
  80. {
  81. if (!Resolve(uid, ref fold))
  82. return false;
  83. // Can't un-fold in any container unless enabled (locker, hands, inventory, whatever).
  84. if (_container.IsEntityInContainer(uid) && !fold.CanFoldInsideContainer)
  85. return false;
  86. var ev = new FoldAttemptEvent(fold);
  87. RaiseLocalEvent(uid, ref ev);
  88. return !ev.Cancelled;
  89. }
  90. /// <summary>
  91. /// Try to fold/unfold
  92. /// </summary>
  93. public bool TrySetFolded(EntityUid uid, FoldableComponent comp, bool state)
  94. {
  95. if (state == comp.IsFolded)
  96. return false;
  97. if (!CanToggleFold(uid, comp))
  98. return false;
  99. SetFolded(uid, comp, state);
  100. return true;
  101. }
  102. #region Verb
  103. private void AddFoldVerb(EntityUid uid, FoldableComponent component, GetVerbsEvent<AlternativeVerb> args)
  104. {
  105. if (!args.CanAccess || !args.CanInteract || args.Hands == null || !CanToggleFold(uid, component))
  106. return;
  107. AlternativeVerb verb = new()
  108. {
  109. Act = () => TryToggleFold(uid, component),
  110. Text = component.IsFolded ? Loc.GetString(component.UnfoldVerbText) : Loc.GetString(component.FoldVerbText),
  111. Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/fold.svg.192dpi.png")),
  112. // If the object is unfolded and they click it, they want to fold it, if it's folded, they want to pick it up
  113. Priority = component.IsFolded ? 0 : 2,
  114. };
  115. args.Verbs.Add(verb);
  116. }
  117. #endregion
  118. [Serializable, NetSerializable]
  119. public enum FoldedVisuals : byte
  120. {
  121. State
  122. }
  123. }
  124. /// <summary>
  125. /// Event raised on an entity to determine if it can be folded.
  126. /// </summary>
  127. /// <param name="Cancelled"></param>
  128. [ByRefEvent]
  129. public record struct FoldAttemptEvent(FoldableComponent Comp, bool Cancelled = false);
  130. /// <summary>
  131. /// Event raised on an entity after it has been folded.
  132. /// </summary>
  133. /// <param name="IsFolded"></param>
  134. [ByRefEvent]
  135. public readonly record struct FoldedEvent(bool IsFolded);