1
0

SharedDeliverySystem.cs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. using System.Linq;
  2. using Content.Shared.Shuttles.Components;
  3. using Content.Shared.Examine;
  4. using Content.Shared.FingerprintReader;
  5. using Content.Shared.Hands.EntitySystems;
  6. using Content.Shared.IdentityManagement;
  7. using Content.Shared.Interaction.Events;
  8. using Content.Shared.NameModifier.EntitySystems;
  9. using Content.Shared.Objectives.Components;
  10. using Content.Shared.Popups;
  11. using Content.Shared.Tag;
  12. using Content.Shared.Verbs;
  13. using Robust.Shared.Audio.Systems;
  14. using Robust.Shared.Containers;
  15. namespace Content.Shared.Delivery;
  16. /// <summary>
  17. /// Shared side of the DeliverySystem.
  18. /// This covers for letters/packages, as well as spawning a reward for the player upon opening.
  19. /// </summary>
  20. public abstract class SharedDeliverySystem : EntitySystem
  21. {
  22. [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
  23. [Dependency] private readonly SharedAudioSystem _audio = default!;
  24. [Dependency] private readonly SharedPopupSystem _popup = default!;
  25. [Dependency] private readonly FingerprintReaderSystem _fingerprintReader = default!;
  26. [Dependency] private readonly TagSystem _tag = default!;
  27. [Dependency] private readonly SharedContainerSystem _container = default!;
  28. [Dependency] private readonly SharedHandsSystem _hands = default!;
  29. [Dependency] private readonly NameModifierSystem _nameModifier = default!;
  30. public override void Initialize()
  31. {
  32. base.Initialize();
  33. SubscribeLocalEvent<DeliveryComponent, ExaminedEvent>(OnExamine);
  34. SubscribeLocalEvent<DeliveryComponent, UseInHandEvent>(OnUseInHand);
  35. SubscribeLocalEvent<DeliveryComponent, GetVerbsEvent<AlternativeVerb>>(OnGetVerbs);
  36. }
  37. private void OnExamine(Entity<DeliveryComponent> ent, ref ExaminedEvent args)
  38. {
  39. var jobTitle = ent.Comp.RecipientJobTitle ?? Loc.GetString("delivery-recipient-no-job");
  40. var recipientName = ent.Comp.RecipientName ?? Loc.GetString("delivery-recipient-no-name");
  41. if (ent.Comp.IsOpened)
  42. {
  43. args.PushText(Loc.GetString("delivery-already-opened-examine"));
  44. }
  45. args.PushText(Loc.GetString("delivery-recipient-examine", ("recipient", recipientName), ("job", jobTitle)));
  46. }
  47. private void OnUseInHand(Entity<DeliveryComponent> ent, ref UseInHandEvent args)
  48. {
  49. args.Handled = true;
  50. if (ent.Comp.IsOpened)
  51. return;
  52. if (ent.Comp.IsLocked)
  53. TryUnlockDelivery(ent, args.User);
  54. else
  55. OpenDelivery(ent, args.User);
  56. }
  57. private void OnGetVerbs(Entity<DeliveryComponent> ent, ref GetVerbsEvent<AlternativeVerb> args)
  58. {
  59. if (!args.CanAccess || !args.CanInteract || args.Hands == null || ent.Comp.IsOpened)
  60. return;
  61. if (_hands.IsHolding(args.User, ent))
  62. return;
  63. var user = args.User;
  64. args.Verbs.Add(new AlternativeVerb()
  65. {
  66. Act = () =>
  67. {
  68. if (ent.Comp.IsLocked)
  69. TryUnlockDelivery(ent, user);
  70. else
  71. OpenDelivery(ent, user, false);
  72. },
  73. Text = ent.Comp.IsLocked ? Loc.GetString("delivery-unlock-verb") : Loc.GetString("delivery-open-verb"),
  74. });
  75. }
  76. private bool TryUnlockDelivery(Entity<DeliveryComponent> ent, EntityUid user, bool rewardMoney = true)
  77. {
  78. // Check fingerprint access if there is a reader on the mail
  79. if (TryComp<FingerprintReaderComponent>(ent, out var reader) && !_fingerprintReader.IsAllowed((ent, reader), user))
  80. return false;
  81. var deliveryName = _nameModifier.GetBaseName(ent.Owner);
  82. _audio.PlayPredicted(ent.Comp.UnlockSound, user, user);
  83. ent.Comp.IsLocked = false;
  84. UpdateAntiTamperVisuals(ent, ent.Comp.IsLocked);
  85. DirtyField(ent, ent.Comp, nameof(DeliveryComponent.IsLocked));
  86. var ev = new DeliveryUnlockedEvent(user);
  87. RaiseLocalEvent(ent, ref ev);
  88. if (rewardMoney)
  89. GrantSpesoReward(ent.AsNullable());
  90. _popup.PopupPredicted(Loc.GetString("delivery-unlocked-self", ("delivery", deliveryName)),
  91. Loc.GetString("delivery-unlocked-others", ("delivery", deliveryName), ("recipient", Identity.Name(user, EntityManager)), ("possadj", user)), user, user);
  92. return true;
  93. }
  94. private void OpenDelivery(Entity<DeliveryComponent> ent, EntityUid user, bool attemptPickup = true)
  95. {
  96. var deliveryName = _nameModifier.GetBaseName(ent.Owner);
  97. _audio.PlayPredicted(ent.Comp.OpenSound, user, user);
  98. var ev = new DeliveryOpenedEvent(user);
  99. RaiseLocalEvent(ent, ref ev);
  100. if (attemptPickup)
  101. _hands.TryDrop(user, ent);
  102. ent.Comp.IsOpened = true;
  103. _appearance.SetData(ent, DeliveryVisuals.IsTrash, ent.Comp.IsOpened);
  104. _tag.AddTags(ent, "Trash", "Recyclable");
  105. EnsureComp<SpaceGarbageComponent>(ent);
  106. RemComp<StealTargetComponent>(ent); // opened mail should not count for the objective
  107. DirtyField(ent.Owner, ent.Comp, nameof(DeliveryComponent.IsOpened));
  108. _popup.PopupPredicted(Loc.GetString("delivery-opened-self", ("delivery", deliveryName)),
  109. Loc.GetString("delivery-opened-others", ("delivery", deliveryName), ("recipient", Identity.Name(user, EntityManager)), ("possadj", user)), user, user);
  110. if (!_container.TryGetContainer(ent, ent.Comp.Container, out var container))
  111. return;
  112. if (attemptPickup)
  113. {
  114. foreach (var entity in container.ContainedEntities.ToArray())
  115. {
  116. _hands.PickupOrDrop(user, entity);
  117. }
  118. }
  119. else
  120. {
  121. _container.EmptyContainer(container, true, Transform(ent.Owner).Coordinates);
  122. }
  123. }
  124. // TODO: generic updateVisuals from component data
  125. private void UpdateAntiTamperVisuals(EntityUid uid, bool isLocked)
  126. {
  127. _appearance.SetData(uid, DeliveryVisuals.IsLocked, isLocked);
  128. // If we're trying to unlock, always remove the priority tape
  129. if (!isLocked)
  130. _appearance.SetData(uid, DeliveryVisuals.IsPriority, false);
  131. }
  132. protected virtual void GrantSpesoReward(Entity<DeliveryComponent?> ent) { }
  133. }
  134. /// <summary>
  135. /// Event raised on the delivery when it is unlocked.
  136. /// </summary>
  137. [ByRefEvent]
  138. public readonly record struct DeliveryUnlockedEvent(EntityUid User);
  139. /// <summary>
  140. /// Event raised on the delivery when it is opened.
  141. /// </summary>
  142. [ByRefEvent]
  143. public readonly record struct DeliveryOpenedEvent(EntityUid User);