1
0

LightReplacerSystem.cs 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. using System.Linq;
  2. using Content.Server.Light.Components;
  3. using Content.Shared.Examine;
  4. using Content.Shared.Interaction;
  5. using Content.Shared.Light.EntitySystems;
  6. using Content.Shared.Light.Components;
  7. using Content.Shared.Popups;
  8. using Content.Shared.Storage;
  9. using JetBrains.Annotations;
  10. using Robust.Shared.Audio;
  11. using Robust.Shared.Audio.Systems;
  12. using Robust.Shared.Containers;
  13. namespace Content.Server.Light.EntitySystems;
  14. [UsedImplicitly]
  15. public sealed class LightReplacerSystem : SharedLightReplacerSystem
  16. {
  17. [Dependency] private readonly PoweredLightSystem _poweredLight = default!;
  18. [Dependency] private readonly SharedAudioSystem _audio = default!;
  19. [Dependency] private readonly SharedContainerSystem _container = default!;
  20. [Dependency] private readonly SharedPopupSystem _popupSystem = default!;
  21. public override void Initialize()
  22. {
  23. base.Initialize();
  24. SubscribeLocalEvent<LightReplacerComponent, ExaminedEvent>(OnExamined);
  25. SubscribeLocalEvent<LightReplacerComponent, MapInitEvent>(OnMapInit);
  26. SubscribeLocalEvent<LightReplacerComponent, ComponentInit>(OnInit);
  27. SubscribeLocalEvent<LightReplacerComponent, InteractUsingEvent>(HandleInteract);
  28. SubscribeLocalEvent<LightReplacerComponent, AfterInteractEvent>(HandleAfterInteract);
  29. }
  30. private void OnExamined(EntityUid uid, LightReplacerComponent component, ExaminedEvent args)
  31. {
  32. using (args.PushGroup(nameof(LightReplacerComponent)))
  33. {
  34. if (!component.InsertedBulbs.ContainedEntities.Any())
  35. {
  36. args.PushMarkup(Loc.GetString("comp-light-replacer-no-lights"));
  37. return;
  38. }
  39. args.PushMarkup(Loc.GetString("comp-light-replacer-has-lights"));
  40. var groups = new Dictionary<string, int>();
  41. var metaQuery = GetEntityQuery<MetaDataComponent>();
  42. foreach (var bulb in component.InsertedBulbs.ContainedEntities)
  43. {
  44. var metaData = metaQuery.GetComponent(bulb);
  45. groups[metaData.EntityName] = groups.GetValueOrDefault(metaData.EntityName) + 1;
  46. }
  47. foreach (var (name, amount) in groups)
  48. {
  49. args.PushMarkup(Loc.GetString("comp-light-replacer-light-listing", ("amount", amount), ("name", name)));
  50. }
  51. }
  52. }
  53. private void OnMapInit(EntityUid uid, LightReplacerComponent component, MapInitEvent args)
  54. {
  55. var xform = Transform(uid);
  56. foreach (var spawn in EntitySpawnCollection.GetSpawns(component.Contents))
  57. {
  58. var ent = Spawn(spawn, xform.Coordinates);
  59. TryInsertBulb(uid, ent, replacer: component);
  60. }
  61. }
  62. private void OnInit(EntityUid uid, LightReplacerComponent replacer, ComponentInit args)
  63. {
  64. replacer.InsertedBulbs = _container.EnsureContainer<Container>(uid, "light_replacer_storage");
  65. }
  66. private void HandleAfterInteract(EntityUid uid, LightReplacerComponent component, AfterInteractEvent eventArgs)
  67. {
  68. if (eventArgs.Handled)
  69. return;
  70. // standard interaction checks
  71. if (!eventArgs.CanReach)
  72. return;
  73. // behaviour will depends on target type
  74. if (eventArgs.Target != null)
  75. {
  76. var targetUid = (EntityUid) eventArgs.Target;
  77. // replace broken light in fixture?
  78. if (TryComp<PoweredLightComponent>(targetUid, out var fixture))
  79. eventArgs.Handled = TryReplaceBulb(uid, targetUid, eventArgs.User, component, fixture);
  80. // add new bulb to light replacer container?
  81. else if (TryComp<LightBulbComponent>(targetUid, out var bulb))
  82. eventArgs.Handled = TryInsertBulb(uid, targetUid, eventArgs.User, true, component, bulb);
  83. }
  84. }
  85. private void HandleInteract(EntityUid uid, LightReplacerComponent component, InteractUsingEvent eventArgs)
  86. {
  87. if (eventArgs.Handled)
  88. return;
  89. var usedUid = eventArgs.Used;
  90. // want to insert a new light bulb?
  91. if (TryComp<LightBulbComponent>(usedUid, out var bulb))
  92. eventArgs.Handled = TryInsertBulb(uid, usedUid, eventArgs.User, true, component, bulb);
  93. // add bulbs from storage?
  94. else if (TryComp<StorageComponent>(usedUid, out var storage))
  95. eventArgs.Handled = TryInsertBulbsFromStorage(uid, usedUid, eventArgs.User, component, storage);
  96. }
  97. /// <summary>
  98. /// Try to replace a light bulb in <paramref name="fixtureUid"/>
  99. /// using light replacer. Light fixture should have <see cref="PoweredLightComponent"/>.
  100. /// </summary>
  101. /// <returns>True if successfully replaced light, false otherwise</returns>
  102. public bool TryReplaceBulb(EntityUid replacerUid, EntityUid fixtureUid, EntityUid? userUid = null,
  103. LightReplacerComponent? replacer = null, PoweredLightComponent? fixture = null)
  104. {
  105. if (!Resolve(replacerUid, ref replacer))
  106. return false;
  107. if (!Resolve(fixtureUid, ref fixture))
  108. return false;
  109. // check if light bulb is broken or missing
  110. var fixtureBulbUid = _poweredLight.GetBulb(fixtureUid, fixture);
  111. if (fixtureBulbUid != null)
  112. {
  113. if (!TryComp<LightBulbComponent>(fixtureBulbUid.Value, out var fixtureBulb))
  114. return false;
  115. if (fixtureBulb.State == LightBulbState.Normal)
  116. return false;
  117. }
  118. // try get first inserted bulb of the same type as targeted light fixtutre
  119. var bulb = replacer.InsertedBulbs.ContainedEntities.FirstOrDefault(
  120. e => CompOrNull<LightBulbComponent>(e)?.Type == fixture.BulbType);
  121. // found bulb in inserted storage
  122. if (bulb.Valid) // FirstOrDefault can return default/invalid uid.
  123. {
  124. // try to remove it
  125. var hasRemoved = _container.Remove(bulb, replacer.InsertedBulbs);
  126. if (!hasRemoved)
  127. return false;
  128. }
  129. else
  130. {
  131. if (userUid != null)
  132. {
  133. var msg = Loc.GetString("comp-light-replacer-missing-light",
  134. ("light-replacer", replacerUid));
  135. _popupSystem.PopupEntity(msg, replacerUid, userUid.Value);
  136. }
  137. return false;
  138. }
  139. // insert it into fixture
  140. var wasReplaced = _poweredLight.ReplaceBulb(fixtureUid, bulb, fixture);
  141. if (wasReplaced)
  142. {
  143. _audio.PlayPvs(replacer.Sound, replacerUid);
  144. }
  145. return wasReplaced;
  146. }
  147. /// <summary>
  148. /// Try to insert a new bulb inside light replacer
  149. /// </summary>
  150. /// <returns>True if successfully inserted light, false otherwise</returns>
  151. public bool TryInsertBulb(EntityUid replacerUid, EntityUid bulbUid, EntityUid? userUid = null, bool showTooltip = false,
  152. LightReplacerComponent? replacer = null, LightBulbComponent? bulb = null)
  153. {
  154. if (!Resolve(replacerUid, ref replacer))
  155. return false;
  156. if (!Resolve(bulbUid, ref bulb))
  157. return false;
  158. // only normal (non-broken) bulbs can be inserted inside light replacer
  159. if (bulb.State != LightBulbState.Normal)
  160. {
  161. if (showTooltip && userUid != null)
  162. {
  163. var msg = Loc.GetString("comp-light-replacer-insert-broken-light");
  164. _popupSystem.PopupEntity(msg, replacerUid, userUid.Value);
  165. }
  166. return false;
  167. }
  168. // try insert light and show message
  169. var hasInsert = _container.Insert(bulbUid, replacer.InsertedBulbs);
  170. if (hasInsert && showTooltip && userUid != null)
  171. {
  172. var msg = Loc.GetString("comp-light-replacer-insert-light",
  173. ("light-replacer", replacerUid), ("bulb", bulbUid));
  174. _popupSystem.PopupEntity(msg, replacerUid, userUid.Value, PopupType.Medium);
  175. }
  176. return hasInsert;
  177. }
  178. /// <summary>
  179. /// Try to insert all light bulbs from storage (for example light tubes box)
  180. /// </summary>
  181. /// <returns>
  182. /// Returns true if storage contained at least one light bulb
  183. /// which was successfully inserted inside light replacer
  184. /// </returns>
  185. public bool TryInsertBulbsFromStorage(EntityUid replacerUid, EntityUid storageUid, EntityUid? userUid = null,
  186. LightReplacerComponent? replacer = null, StorageComponent? storage = null)
  187. {
  188. if (!Resolve(replacerUid, ref replacer))
  189. return false;
  190. if (!Resolve(storageUid, ref storage))
  191. return false;
  192. var insertedBulbs = 0;
  193. var storagedEnts = storage.Container.ContainedEntities.ToArray();
  194. foreach (var ent in storagedEnts)
  195. {
  196. if (TryComp<LightBulbComponent>(ent, out var bulb) &&
  197. TryInsertBulb(replacerUid, ent, userUid, false, replacer, bulb))
  198. {
  199. insertedBulbs++;
  200. }
  201. }
  202. // show some message if success
  203. if (insertedBulbs > 0 && userUid != null)
  204. {
  205. var msg = Loc.GetString("comp-light-replacer-refill-from-storage", ("light-replacer", replacerUid));
  206. _popupSystem.PopupEntity(msg, replacerUid, userUid.Value, PopupType.Medium);
  207. }
  208. return insertedBulbs > 0;
  209. }
  210. }