InventorySystem.Relay.cs 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  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, GetVerbsEvent<EquipmentVerb>>(OnGetEquipmentVerbs);
  64. }
  65. protected void RefRelayInventoryEvent<T>(EntityUid uid, InventoryComponent component, ref T args) where T : IInventoryRelayEvent
  66. {
  67. RelayEvent((uid, component), ref args);
  68. }
  69. protected void RelayInventoryEvent<T>(EntityUid uid, InventoryComponent component, T args) where T : IInventoryRelayEvent
  70. {
  71. RelayEvent((uid, component), args);
  72. }
  73. public void RelayEvent<T>(Entity<InventoryComponent> inventory, ref T args) where T : IInventoryRelayEvent
  74. {
  75. if (args.TargetSlots == SlotFlags.NONE)
  76. return;
  77. // this copies the by-ref event if it is a struct
  78. var ev = new InventoryRelayedEvent<T>(args);
  79. var enumerator = new InventorySlotEnumerator(inventory, args.TargetSlots);
  80. while (enumerator.NextItem(out var item))
  81. {
  82. RaiseLocalEvent(item, ev);
  83. }
  84. // and now we copy it back
  85. args = ev.Args;
  86. }
  87. public void RelayEvent<T>(Entity<InventoryComponent> inventory, T args) where T : IInventoryRelayEvent
  88. {
  89. if (args.TargetSlots == SlotFlags.NONE)
  90. return;
  91. var ev = new InventoryRelayedEvent<T>(args);
  92. var enumerator = new InventorySlotEnumerator(inventory, args.TargetSlots);
  93. while (enumerator.NextItem(out var item))
  94. {
  95. RaiseLocalEvent(item, ev);
  96. }
  97. }
  98. private void OnGetEquipmentVerbs(EntityUid uid, InventoryComponent component, GetVerbsEvent<EquipmentVerb> args)
  99. {
  100. // Automatically relay stripping related verbs to all equipped clothing.
  101. var ev = new InventoryRelayedEvent<GetVerbsEvent<EquipmentVerb>>(args);
  102. var enumerator = new InventorySlotEnumerator(component);
  103. while (enumerator.NextItem(out var item, out var slotDef))
  104. {
  105. if (!_strippable.IsStripHidden(slotDef, args.User) || args.User == uid)
  106. RaiseLocalEvent(item, ev);
  107. }
  108. }
  109. }
  110. /// <summary>
  111. /// Event wrapper for relayed events.
  112. /// </summary>
  113. /// <remarks>
  114. /// This avoids nested inventory relays, and makes it easy to have certain events only handled by the initial
  115. /// target entity. E.g. health based movement speed modifiers should not be handled by a hat, even if that hat
  116. /// happens to be a dead mouse. Clothing that wishes to modify movement speed must subscribe to
  117. /// InventoryRelayedEvent&lt;RefreshMovementSpeedModifiersEvent&gt;
  118. /// </remarks>
  119. public sealed class InventoryRelayedEvent<TEvent> : EntityEventArgs
  120. {
  121. public TEvent Args;
  122. public InventoryRelayedEvent(TEvent args)
  123. {
  124. Args = args;
  125. }
  126. }
  127. public interface IClothingSlots
  128. {
  129. SlotFlags Slots { get; }
  130. }
  131. /// <summary>
  132. /// Events that should be relayed to inventory slots should implement this interface.
  133. /// </summary>
  134. public interface IInventoryRelayEvent
  135. {
  136. /// <summary>
  137. /// What inventory slots should this event be relayed to, if any?
  138. /// </summary>
  139. /// <remarks>
  140. /// In general you may want to exclude <see cref="SlotFlags.POCKET"/>, given that those items are not truly
  141. /// "equipped" by the user.
  142. /// </remarks>
  143. public SlotFlags TargetSlots { get; }
  144. }