InventorySystem.Relay.cs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. using Content.Shared.Armor;
  2. using Content.Shared.Chat;
  3. using Content.Shared.Chemistry;
  4. using Content.Shared.Chemistry.Hypospray.Events;
  5. using Content.Shared.Climbing.Events;
  6. using Content.Shared.Damage;
  7. using Content.Shared.Electrocution;
  8. using Content.Shared.Explosion;
  9. using Content.Shared.Eye.Blinding.Systems;
  10. using Content.Shared.Gravity;
  11. using Content.Shared.IdentityManagement.Components;
  12. using Content.Shared.Inventory.Events;
  13. using Content.Shared.Movement.Events;
  14. using Content.Shared.Movement.Systems;
  15. using Content.Shared.NameModifier.EntitySystems;
  16. using Content.Shared.Overlays;
  17. using Content.Shared.Radio;
  18. using Content.Shared.Slippery;
  19. using Content.Shared.Strip.Components;
  20. using Content.Shared.Temperature;
  21. using Content.Shared.Verbs;
  22. using Content.Shared.Weapons.Ranged.Events;
  23. namespace Content.Shared.Inventory;
  24. public partial class InventorySystem
  25. {
  26. public void InitializeRelay()
  27. {
  28. SubscribeLocalEvent<InventoryComponent, DamageModifyEvent>(RelayInventoryEvent);
  29. SubscribeLocalEvent<InventoryComponent, ElectrocutionAttemptEvent>(RelayInventoryEvent);
  30. SubscribeLocalEvent<InventoryComponent, SlipAttemptEvent>(RelayInventoryEvent);
  31. SubscribeLocalEvent<InventoryComponent, RefreshMovementSpeedModifiersEvent>(RelayInventoryEvent);
  32. SubscribeLocalEvent<InventoryComponent, BeforeStripEvent>(RelayInventoryEvent);
  33. SubscribeLocalEvent<InventoryComponent, SeeIdentityAttemptEvent>(RelayInventoryEvent);
  34. SubscribeLocalEvent<InventoryComponent, ModifyChangedTemperatureEvent>(RelayInventoryEvent);
  35. SubscribeLocalEvent<InventoryComponent, GetDefaultRadioChannelEvent>(RelayInventoryEvent);
  36. SubscribeLocalEvent<InventoryComponent, RefreshNameModifiersEvent>(RelayInventoryEvent);
  37. SubscribeLocalEvent<InventoryComponent, TransformSpeakerNameEvent>(RelayInventoryEvent);
  38. SubscribeLocalEvent<InventoryComponent, SelfBeforeHyposprayInjectsEvent>(RelayInventoryEvent);
  39. SubscribeLocalEvent<InventoryComponent, TargetBeforeHyposprayInjectsEvent>(RelayInventoryEvent);
  40. SubscribeLocalEvent<InventoryComponent, SelfBeforeGunShotEvent>(RelayInventoryEvent);
  41. SubscribeLocalEvent<InventoryComponent, SelfBeforeClimbEvent>(RelayInventoryEvent);
  42. SubscribeLocalEvent<InventoryComponent, CoefficientQueryEvent>(RelayInventoryEvent);
  43. // by-ref events
  44. SubscribeLocalEvent<InventoryComponent, GetExplosionResistanceEvent>(RefRelayInventoryEvent);
  45. SubscribeLocalEvent<InventoryComponent, IsWeightlessEvent>(RefRelayInventoryEvent);
  46. SubscribeLocalEvent<InventoryComponent, GetSpeedModifierContactCapEvent>(RefRelayInventoryEvent);
  47. SubscribeLocalEvent<InventoryComponent, GetSlowedOverSlipperyModifierEvent>(RefRelayInventoryEvent);
  48. SubscribeLocalEvent<InventoryComponent, ModifySlowOnDamageSpeedEvent>(RefRelayInventoryEvent);
  49. // Eye/vision events
  50. SubscribeLocalEvent<InventoryComponent, CanSeeAttemptEvent>(RelayInventoryEvent);
  51. SubscribeLocalEvent<InventoryComponent, GetEyeProtectionEvent>(RelayInventoryEvent);
  52. SubscribeLocalEvent<InventoryComponent, GetBlurEvent>(RelayInventoryEvent);
  53. SubscribeLocalEvent<InventoryComponent, SolutionScanEvent>(RelayInventoryEvent);
  54. // ComponentActivatedClientSystems
  55. SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowJobIconsComponent>>(RefRelayInventoryEvent);
  56. SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowHealthBarsComponent>>(RefRelayInventoryEvent);
  57. SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowHealthIconsComponent>>(RefRelayInventoryEvent);
  58. SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowHungerIconsComponent>>(RefRelayInventoryEvent);
  59. SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowThirstIconsComponent>>(RefRelayInventoryEvent);
  60. SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowMindShieldIconsComponent>>(RefRelayInventoryEvent);
  61. SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowSyndicateIconsComponent>>(RefRelayInventoryEvent);
  62. SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowCriminalRecordIconsComponent>>(RefRelayInventoryEvent);
  63. SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowFactionIconsComponent>>(RefRelayInventoryEvent);
  64. SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowFrenchFactionIconsComponent>>(RefRelayInventoryEvent);
  65. SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowEnglishFactionIconsComponent>>(RefRelayInventoryEvent);
  66. SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowGermanFactionIconsComponent>>(RefRelayInventoryEvent);
  67. SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowSovietFactionIconsComponent>>(RefRelayInventoryEvent);
  68. SubscribeLocalEvent<InventoryComponent, GetVerbsEvent<EquipmentVerb>>(OnGetEquipmentVerbs);
  69. }
  70. protected void RefRelayInventoryEvent<T>(EntityUid uid, InventoryComponent component, ref T args) where T : IInventoryRelayEvent
  71. {
  72. RelayEvent((uid, component), ref args);
  73. }
  74. protected void RelayInventoryEvent<T>(EntityUid uid, InventoryComponent component, T args) where T : IInventoryRelayEvent
  75. {
  76. RelayEvent((uid, component), args);
  77. }
  78. public void RelayEvent<T>(Entity<InventoryComponent> inventory, ref T args) where T : IInventoryRelayEvent
  79. {
  80. if (args.TargetSlots == SlotFlags.NONE)
  81. return;
  82. // this copies the by-ref event if it is a struct
  83. var ev = new InventoryRelayedEvent<T>(args);
  84. var enumerator = new InventorySlotEnumerator(inventory, args.TargetSlots);
  85. while (enumerator.NextItem(out var item))
  86. {
  87. RaiseLocalEvent(item, ev);
  88. }
  89. // and now we copy it back
  90. args = ev.Args;
  91. }
  92. public void RelayEvent<T>(Entity<InventoryComponent> inventory, T args) where T : IInventoryRelayEvent
  93. {
  94. if (args.TargetSlots == SlotFlags.NONE)
  95. return;
  96. var ev = new InventoryRelayedEvent<T>(args);
  97. var enumerator = new InventorySlotEnumerator(inventory, args.TargetSlots);
  98. while (enumerator.NextItem(out var item))
  99. {
  100. RaiseLocalEvent(item, ev);
  101. }
  102. }
  103. private void OnGetEquipmentVerbs(EntityUid uid, InventoryComponent component, GetVerbsEvent<EquipmentVerb> args)
  104. {
  105. // Automatically relay stripping related verbs to all equipped clothing.
  106. var ev = new InventoryRelayedEvent<GetVerbsEvent<EquipmentVerb>>(args);
  107. var enumerator = new InventorySlotEnumerator(component);
  108. while (enumerator.NextItem(out var item, out var slotDef))
  109. {
  110. if (!_strippable.IsStripHidden(slotDef, args.User) || args.User == uid)
  111. RaiseLocalEvent(item, ev);
  112. }
  113. }
  114. }
  115. /// <summary>
  116. /// Event wrapper for relayed events.
  117. /// </summary>
  118. /// <remarks>
  119. /// This avoids nested inventory relays, and makes it easy to have certain events only handled by the initial
  120. /// target entity. E.g. health based movement speed modifiers should not be handled by a hat, even if that hat
  121. /// happens to be a dead mouse. Clothing that wishes to modify movement speed must subscribe to
  122. /// InventoryRelayedEvent&lt;RefreshMovementSpeedModifiersEvent&gt;
  123. /// </remarks>
  124. public sealed class InventoryRelayedEvent<TEvent> : EntityEventArgs
  125. {
  126. public TEvent Args;
  127. public InventoryRelayedEvent(TEvent args)
  128. {
  129. Args = args;
  130. }
  131. }
  132. public interface IClothingSlots
  133. {
  134. SlotFlags Slots { get; }
  135. }
  136. /// <summary>
  137. /// Events that should be relayed to inventory slots should implement this interface.
  138. /// </summary>
  139. public interface IInventoryRelayEvent
  140. {
  141. /// <summary>
  142. /// What inventory slots should this event be relayed to, if any?
  143. /// </summary>
  144. /// <remarks>
  145. /// In general you may want to exclude <see cref="SlotFlags.POCKET"/>, given that those items are not truly
  146. /// "equipped" by the user.
  147. /// </remarks>
  148. public SlotFlags TargetSlots { get; }
  149. }