SharedItemRecallSystem.cs 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. using Content.Shared.Actions;
  2. using Content.Shared.Hands.Components;
  3. using Content.Shared.Hands.EntitySystems;
  4. using Content.Shared.IdentityManagement;
  5. using Content.Shared.Popups;
  6. using Content.Shared.Projectiles;
  7. using Robust.Shared.GameStates;
  8. using Robust.Shared.Player;
  9. namespace Content.Shared.ItemRecall;
  10. /// <summary>
  11. /// System for handling the ItemRecall ability for wizards.
  12. /// </summary>
  13. public abstract partial class SharedItemRecallSystem : EntitySystem
  14. {
  15. [Dependency] private readonly ISharedPlayerManager _player = default!;
  16. [Dependency] private readonly SharedPvsOverrideSystem _pvs = default!;
  17. [Dependency] private readonly SharedActionsSystem _actions = default!;
  18. [Dependency] private readonly SharedHandsSystem _hands = default!;
  19. [Dependency] private readonly MetaDataSystem _metaData = default!;
  20. [Dependency] private readonly SharedPopupSystem _popups = default!;
  21. [Dependency] private readonly SharedProjectileSystem _proj = default!;
  22. public override void Initialize()
  23. {
  24. base.Initialize();
  25. SubscribeLocalEvent<ItemRecallComponent, MapInitEvent>(OnMapInit);
  26. SubscribeLocalEvent<ItemRecallComponent, OnItemRecallActionEvent>(OnItemRecallActionUse);
  27. SubscribeLocalEvent<RecallMarkerComponent, ComponentShutdown>(OnRecallMarkerShutdown);
  28. }
  29. private void OnMapInit(Entity<ItemRecallComponent> ent, ref MapInitEvent args)
  30. {
  31. ent.Comp.InitialName = Name(ent);
  32. ent.Comp.InitialDescription = Description(ent);
  33. }
  34. private void OnItemRecallActionUse(Entity<ItemRecallComponent> ent, ref OnItemRecallActionEvent args)
  35. {
  36. if (ent.Comp.MarkedEntity == null)
  37. {
  38. if (!TryComp<HandsComponent>(args.Performer, out var hands))
  39. return;
  40. var markItem = _hands.GetActiveItem((args.Performer, hands));
  41. if (markItem == null)
  42. {
  43. _popups.PopupClient(Loc.GetString("item-recall-item-mark-empty"), args.Performer, args.Performer);
  44. return;
  45. }
  46. if (HasComp<RecallMarkerComponent>(markItem))
  47. {
  48. _popups.PopupClient(Loc.GetString("item-recall-item-already-marked", ("item", markItem)), args.Performer, args.Performer);
  49. return;
  50. }
  51. _popups.PopupClient(Loc.GetString("item-recall-item-marked", ("item", markItem.Value)), args.Performer, args.Performer);
  52. TryMarkItem(ent, markItem.Value);
  53. return;
  54. }
  55. RecallItem(ent.Comp.MarkedEntity.Value);
  56. args.Handled = true;
  57. }
  58. private void RecallItem(Entity<RecallMarkerComponent?> ent)
  59. {
  60. if (!Resolve(ent.Owner, ref ent.Comp, false))
  61. return;
  62. if (!TryComp<InstantActionComponent>(ent.Comp.MarkedByAction, out var instantAction))
  63. return;
  64. var actionOwner = instantAction.AttachedEntity;
  65. if (actionOwner == null)
  66. return;
  67. if (TryComp<EmbeddableProjectileComponent>(ent, out var projectile))
  68. _proj.EmbedDetach(ent, projectile, actionOwner.Value);
  69. _popups.PopupPredicted(Loc.GetString("item-recall-item-summon-self", ("item", ent)),
  70. Loc.GetString("item-recall-item-summon-others", ("item", ent), ("name", Identity.Entity(actionOwner.Value, EntityManager))),
  71. actionOwner.Value, actionOwner.Value);
  72. _popups.PopupPredictedCoordinates(Loc.GetString("item-recall-item-disappear", ("item", ent)), Transform(ent).Coordinates, actionOwner.Value);
  73. _hands.TryForcePickupAnyHand(actionOwner.Value, ent);
  74. }
  75. private void OnRecallMarkerShutdown(Entity<RecallMarkerComponent> ent, ref ComponentShutdown args)
  76. {
  77. TryUnmarkItem(ent);
  78. }
  79. private void TryMarkItem(Entity<ItemRecallComponent> ent, EntityUid item)
  80. {
  81. if (!TryComp<InstantActionComponent>(ent, out var instantAction))
  82. return;
  83. var actionOwner = instantAction.AttachedEntity;
  84. if (actionOwner == null)
  85. return;
  86. AddToPvsOverride(item, actionOwner.Value);
  87. var marker = AddComp<RecallMarkerComponent>(item);
  88. ent.Comp.MarkedEntity = item;
  89. Dirty(ent);
  90. marker.MarkedByAction = ent.Owner;
  91. UpdateActionAppearance(ent);
  92. Dirty(item, marker);
  93. }
  94. private void TryUnmarkItem(EntityUid item)
  95. {
  96. if (!TryComp<RecallMarkerComponent>(item, out var marker))
  97. return;
  98. if (!TryComp<InstantActionComponent>(marker.MarkedByAction, out var instantAction))
  99. return;
  100. if (TryComp<ItemRecallComponent>(marker.MarkedByAction, out var action))
  101. {
  102. // For some reason client thinks the station grid owns the action on client and this doesn't work. It doesn't work in PopupEntity(mispredicts) and PopupPredicted either(doesnt show).
  103. // I don't have the heart to move this code to server because of this small thing.
  104. // This line will only do something once that is fixed.
  105. if (instantAction.AttachedEntity != null)
  106. {
  107. _popups.PopupClient(Loc.GetString("item-recall-item-unmark", ("item", item)), instantAction.AttachedEntity.Value, instantAction.AttachedEntity.Value, PopupType.MediumCaution);
  108. RemoveFromPvsOverride(item, instantAction.AttachedEntity.Value);
  109. }
  110. action.MarkedEntity = null;
  111. UpdateActionAppearance((marker.MarkedByAction.Value, action));
  112. Dirty(marker.MarkedByAction.Value, action);
  113. }
  114. RemCompDeferred<RecallMarkerComponent>(item);
  115. }
  116. private void UpdateActionAppearance(Entity<ItemRecallComponent> action)
  117. {
  118. if (!TryComp<InstantActionComponent>(action, out var instantAction))
  119. return;
  120. if (action.Comp.MarkedEntity == null)
  121. {
  122. if (action.Comp.InitialName != null)
  123. _metaData.SetEntityName(action, action.Comp.InitialName);
  124. if (action.Comp.InitialDescription != null)
  125. _metaData.SetEntityDescription(action, action.Comp.InitialDescription);
  126. _actions.SetEntityIcon(action, null, instantAction);
  127. }
  128. else
  129. {
  130. if (action.Comp.WhileMarkedName != null)
  131. _metaData.SetEntityName(action, Loc.GetString(action.Comp.WhileMarkedName,
  132. ("item", action.Comp.MarkedEntity.Value)));
  133. if (action.Comp.WhileMarkedDescription != null)
  134. _metaData.SetEntityDescription(action, Loc.GetString(action.Comp.WhileMarkedDescription,
  135. ("item", action.Comp.MarkedEntity.Value)));
  136. _actions.SetEntityIcon(action, action.Comp.MarkedEntity, instantAction);
  137. }
  138. }
  139. private void AddToPvsOverride(EntityUid uid, EntityUid user)
  140. {
  141. if (!_player.TryGetSessionByEntity(user, out var mindSession))
  142. return;
  143. _pvs.AddSessionOverride(uid, mindSession);
  144. }
  145. private void RemoveFromPvsOverride(EntityUid uid, EntityUid user)
  146. {
  147. if (!_player.TryGetSessionByEntity(user, out var mindSession))
  148. return;
  149. _pvs.RemoveSessionOverride(uid, mindSession);
  150. }
  151. }