SharedGunSystem.Magazine.cs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. using Content.Shared.Examine;
  2. using Content.Shared.Interaction.Events;
  3. using Content.Shared.Verbs;
  4. using Content.Shared.Weapons.Ranged.Events;
  5. using Robust.Shared.Containers;
  6. namespace Content.Shared.Weapons.Ranged.Systems;
  7. public abstract partial class SharedGunSystem
  8. {
  9. protected const string MagazineSlot = "gun_magazine";
  10. protected virtual void InitializeMagazine()
  11. {
  12. SubscribeLocalEvent<MagazineAmmoProviderComponent, MapInitEvent>(OnMagazineMapInit);
  13. SubscribeLocalEvent<MagazineAmmoProviderComponent, TakeAmmoEvent>(OnMagazineTakeAmmo);
  14. SubscribeLocalEvent<MagazineAmmoProviderComponent, GetAmmoCountEvent>(OnMagazineAmmoCount);
  15. SubscribeLocalEvent<MagazineAmmoProviderComponent, GetVerbsEvent<AlternativeVerb>>(OnMagazineVerb);
  16. SubscribeLocalEvent<MagazineAmmoProviderComponent, EntInsertedIntoContainerMessage>(OnMagazineSlotChange);
  17. SubscribeLocalEvent<MagazineAmmoProviderComponent, EntRemovedFromContainerMessage>(OnMagazineSlotChange);
  18. SubscribeLocalEvent<MagazineAmmoProviderComponent, UseInHandEvent>(OnMagazineUse);
  19. SubscribeLocalEvent<MagazineAmmoProviderComponent, ExaminedEvent>(OnMagazineExamine);
  20. }
  21. private void OnMagazineMapInit(Entity<MagazineAmmoProviderComponent> ent, ref MapInitEvent args)
  22. {
  23. MagazineSlotChanged(ent);
  24. }
  25. private void OnMagazineExamine(EntityUid uid, MagazineAmmoProviderComponent component, ExaminedEvent args)
  26. {
  27. if (!args.IsInDetailsRange)
  28. return;
  29. var (count, _) = GetMagazineCountCapacity(uid, component);
  30. args.PushMarkup(Loc.GetString("gun-magazine-examine", ("color", AmmoExamineColor), ("count", count)));
  31. }
  32. private void OnMagazineUse(EntityUid uid, MagazineAmmoProviderComponent component, UseInHandEvent args)
  33. {
  34. // not checking for args.Handled or marking as such because we only relay the event to the magazine entity
  35. var magEnt = GetMagazineEntity(uid);
  36. if (magEnt == null)
  37. return;
  38. RaiseLocalEvent(magEnt.Value, args);
  39. UpdateAmmoCount(uid);
  40. UpdateMagazineAppearance(uid, component, magEnt.Value);
  41. }
  42. private void OnMagazineVerb(EntityUid uid, MagazineAmmoProviderComponent component, GetVerbsEvent<AlternativeVerb> args)
  43. {
  44. if (!args.CanInteract || !args.CanAccess)
  45. return;
  46. var magEnt = GetMagazineEntity(uid);
  47. if (magEnt != null)
  48. {
  49. RaiseLocalEvent(magEnt.Value, args);
  50. UpdateMagazineAppearance(magEnt.Value, component, magEnt.Value);
  51. }
  52. }
  53. protected virtual void OnMagazineSlotChange(EntityUid uid, MagazineAmmoProviderComponent component, ContainerModifiedMessage args)
  54. {
  55. if (MagazineSlot != args.Container.ID)
  56. return;
  57. MagazineSlotChanged((uid, component));
  58. }
  59. private void MagazineSlotChanged(Entity<MagazineAmmoProviderComponent> ent)
  60. {
  61. UpdateAmmoCount(ent);
  62. if (!TryComp<AppearanceComponent>(ent, out var appearance))
  63. return;
  64. var magEnt = GetMagazineEntity(ent);
  65. Appearance.SetData(ent, AmmoVisuals.MagLoaded, magEnt != null, appearance);
  66. if (magEnt != null)
  67. {
  68. UpdateMagazineAppearance(ent, ent, magEnt.Value);
  69. }
  70. }
  71. protected (int, int) GetMagazineCountCapacity(EntityUid uid, MagazineAmmoProviderComponent component)
  72. {
  73. var count = 0;
  74. var capacity = 1;
  75. var magEnt = GetMagazineEntity(uid);
  76. if (magEnt != null)
  77. {
  78. var ev = new GetAmmoCountEvent();
  79. RaiseLocalEvent(magEnt.Value, ref ev, false);
  80. count += ev.Count;
  81. capacity += ev.Capacity;
  82. }
  83. return (count, capacity);
  84. }
  85. protected EntityUid? GetMagazineEntity(EntityUid uid)
  86. {
  87. if (!Containers.TryGetContainer(uid, MagazineSlot, out var container) ||
  88. container is not ContainerSlot slot)
  89. {
  90. return null;
  91. }
  92. return slot.ContainedEntity;
  93. }
  94. private void OnMagazineAmmoCount(EntityUid uid, MagazineAmmoProviderComponent component, ref GetAmmoCountEvent args)
  95. {
  96. var magEntity = GetMagazineEntity(uid);
  97. if (magEntity == null)
  98. return;
  99. RaiseLocalEvent(magEntity.Value, ref args);
  100. }
  101. private void OnMagazineTakeAmmo(EntityUid uid, MagazineAmmoProviderComponent component, TakeAmmoEvent args)
  102. {
  103. var magEntity = GetMagazineEntity(uid);
  104. TryComp<AppearanceComponent>(uid, out var appearance);
  105. if (magEntity == null)
  106. {
  107. Appearance.SetData(uid, AmmoVisuals.MagLoaded, false, appearance);
  108. return;
  109. }
  110. // Pass the event onwards.
  111. RaiseLocalEvent(magEntity.Value, args);
  112. // Should be Dirtied by what other ammoprovider is handling it.
  113. var ammoEv = new GetAmmoCountEvent();
  114. RaiseLocalEvent(magEntity.Value, ref ammoEv);
  115. FinaliseMagazineTakeAmmo(uid, component, ammoEv.Count, ammoEv.Capacity, args.User, appearance);
  116. }
  117. private void FinaliseMagazineTakeAmmo(EntityUid uid, MagazineAmmoProviderComponent component, int count, int capacity, EntityUid? user, AppearanceComponent? appearance)
  118. {
  119. // If no ammo then check for autoeject
  120. var ejectMag = component.AutoEject && count == 0;
  121. if (ejectMag)
  122. {
  123. EjectMagazine(uid, component);
  124. Audio.PlayPredicted(component.SoundAutoEject, uid, user);
  125. }
  126. UpdateMagazineAppearance(uid, appearance, !ejectMag, count, capacity);
  127. }
  128. private void UpdateMagazineAppearance(EntityUid uid, MagazineAmmoProviderComponent component, EntityUid magEnt)
  129. {
  130. TryComp<AppearanceComponent>(uid, out var appearance);
  131. var count = 0;
  132. var capacity = 0;
  133. if (TryComp<AppearanceComponent>(magEnt, out var magAppearance))
  134. {
  135. Appearance.TryGetData<int>(magEnt, AmmoVisuals.AmmoCount, out var addCount, magAppearance);
  136. Appearance.TryGetData<int>(magEnt, AmmoVisuals.AmmoMax, out var addCapacity, magAppearance);
  137. count += addCount;
  138. capacity += addCapacity;
  139. }
  140. UpdateMagazineAppearance(uid, appearance, true, count, capacity);
  141. }
  142. private void UpdateMagazineAppearance(EntityUid uid, AppearanceComponent? appearance, bool magLoaded, int count, int capacity)
  143. {
  144. if (appearance == null)
  145. return;
  146. // Copy the magazine's appearance data
  147. Appearance.SetData(uid, AmmoVisuals.MagLoaded, magLoaded, appearance);
  148. Appearance.SetData(uid, AmmoVisuals.HasAmmo, count != 0, appearance);
  149. Appearance.SetData(uid, AmmoVisuals.AmmoCount, count, appearance);
  150. Appearance.SetData(uid, AmmoVisuals.AmmoMax, capacity, appearance);
  151. }
  152. private void EjectMagazine(EntityUid uid, MagazineAmmoProviderComponent component)
  153. {
  154. var ent = GetMagazineEntity(uid);
  155. if (ent == null)
  156. return;
  157. _slots.TryEject(uid, MagazineSlot, null, out var a, excludeUserAudio: true);
  158. }
  159. }