PowerWireAction.cs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. using Content.Server.Electrocution;
  2. using Content.Shared.Electrocution;
  3. using Content.Server.Power.Components;
  4. using Content.Server.Power.EntitySystems;
  5. using Content.Server.Wires;
  6. using Content.Shared.Power;
  7. using Content.Shared.Wires;
  8. namespace Content.Server.Power;
  9. // Generic power wire action. Use on anything
  10. // that requires power.
  11. public sealed partial class PowerWireAction : BaseWireAction
  12. {
  13. public override Color Color { get; set; } = Color.Red;
  14. public override string Name { get; set; } = "wire-name-power";
  15. [DataField("pulseTimeout")]
  16. private int _pulseTimeout = 30;
  17. private ElectrocutionSystem _electrocution = default!;
  18. public override object StatusKey { get; } = PowerWireActionKey.Status;
  19. public override StatusLightState? GetLightState(Wire wire)
  20. {
  21. if (WiresSystem.TryGetData<int>(wire.Owner, PowerWireActionKey.MainWire, out var main)
  22. && main != wire.Id)
  23. {
  24. return null;
  25. }
  26. if (!AllWiresMended(wire.Owner)
  27. || WiresSystem.TryGetData<bool>(wire.Owner, PowerWireActionKey.Pulsed, out var pulsed)
  28. && pulsed)
  29. {
  30. return StatusLightState.BlinkingSlow;
  31. }
  32. return AllWiresCut(wire.Owner) ? StatusLightState.Off : StatusLightState.On;
  33. }
  34. private bool AllWiresCut(EntityUid owner)
  35. {
  36. return WiresSystem.TryGetData<int?>(owner, PowerWireActionKey.CutWires, out var cut)
  37. && WiresSystem.TryGetData<int?>(owner, PowerWireActionKey.WireCount, out var count)
  38. && count == cut;
  39. }
  40. private bool AllWiresMended(EntityUid owner)
  41. {
  42. return WiresSystem.TryGetData<int?>(owner, PowerWireActionKey.CutWires, out var cut)
  43. && cut == 0;
  44. }
  45. // I feel like these two should be within ApcPowerReceiverComponent at this point.
  46. // Getting it from a dictionary is significantly more expensive.
  47. private void SetPower(EntityUid owner, bool pulsed)
  48. {
  49. if (!EntityManager.TryGetComponent(owner, out ApcPowerReceiverComponent? power))
  50. {
  51. return;
  52. }
  53. var receiverSys = EntityManager.System<PowerReceiverSystem>();
  54. if (pulsed)
  55. {
  56. receiverSys.SetPowerDisabled(owner, true, power);
  57. return;
  58. }
  59. if (AllWiresCut(owner))
  60. {
  61. receiverSys.SetPowerDisabled(owner, true, power);
  62. }
  63. else
  64. {
  65. if (WiresSystem.TryGetData<bool>(owner, PowerWireActionKey.Pulsed, out var isPulsed)
  66. && isPulsed)
  67. {
  68. return;
  69. }
  70. receiverSys.SetPowerDisabled(owner, false, power);
  71. }
  72. }
  73. private void SetWireCuts(EntityUid owner, bool isCut)
  74. {
  75. if (WiresSystem.TryGetData<int?>(owner, PowerWireActionKey.CutWires, out var cut)
  76. && WiresSystem.TryGetData<int?>(owner, PowerWireActionKey.WireCount, out var count))
  77. {
  78. if (cut == count && isCut
  79. || cut <= 0 && !isCut)
  80. {
  81. return;
  82. }
  83. cut = isCut ? cut + 1 : cut - 1;
  84. WiresSystem.SetData(owner, PowerWireActionKey.CutWires, cut);
  85. }
  86. }
  87. private void SetElectrified(EntityUid used, bool setting, ElectrifiedComponent? electrified = null)
  88. {
  89. if (electrified == null
  90. && !EntityManager.TryGetComponent(used, out electrified))
  91. return;
  92. _electrocution.SetElectrifiedWireCut((used, electrified), setting);
  93. _electrocution.SetElectrified((used, electrified), setting);
  94. }
  95. /// <returns>false if failed, true otherwise, or if the entity cannot be electrified</returns>
  96. private bool TrySetElectrocution(EntityUid user, Wire wire, bool timed = false)
  97. {
  98. if (!EntityManager.TryGetComponent<ElectrifiedComponent>(wire.Owner, out var electrified))
  99. {
  100. return true;
  101. }
  102. // always set this to true
  103. SetElectrified(wire.Owner, true, electrified);
  104. var electrifiedAttempt = _electrocution.TryDoElectrifiedAct(wire.Owner, user);
  105. // if we were electrified, then return false
  106. return !electrifiedAttempt;
  107. }
  108. private void UpdateElectrocution(Wire wire)
  109. {
  110. var allCut = AllWiresCut(wire.Owner);
  111. var activePulse = false;
  112. if (WiresSystem.TryGetData<bool>(wire.Owner, PowerWireActionKey.Pulsed, out var pulsed))
  113. {
  114. activePulse = pulsed;
  115. }
  116. // if this is actively pulsed,
  117. // and there's not already an electrification cancel occurring,
  118. // we need to start that timer immediately
  119. if (!WiresSystem.HasData(wire.Owner, PowerWireActionKey.ElectrifiedCancel)
  120. && activePulse
  121. && IsPowered(wire.Owner)
  122. && !allCut)
  123. {
  124. WiresSystem.StartWireAction(wire.Owner, _pulseTimeout, PowerWireActionKey.ElectrifiedCancel, new TimedWireEvent(AwaitElectrifiedCancel, wire));
  125. }
  126. else
  127. {
  128. if (!activePulse && allCut || AllWiresMended(wire.Owner))
  129. {
  130. SetElectrified(wire.Owner, false);
  131. }
  132. }
  133. }
  134. public override void Initialize()
  135. {
  136. base.Initialize();
  137. _electrocution = EntityManager.System<ElectrocutionSystem>();
  138. }
  139. // This should add a wire into the entity's state, whether it be
  140. // in WiresComponent or ApcPowerReceiverComponent.
  141. public override bool AddWire(Wire wire, int count)
  142. {
  143. if (!WiresSystem.HasData(wire.Owner, PowerWireActionKey.CutWires))
  144. {
  145. WiresSystem.SetData(wire.Owner, PowerWireActionKey.CutWires, 0);
  146. }
  147. if (count == 1)
  148. {
  149. WiresSystem.SetData(wire.Owner, PowerWireActionKey.MainWire, wire.Id);
  150. }
  151. WiresSystem.SetData(wire.Owner, PowerWireActionKey.WireCount, count);
  152. return true;
  153. }
  154. public override bool Cut(EntityUid user, Wire wire)
  155. {
  156. base.Cut(user, wire);
  157. if (!TrySetElectrocution(user, wire))
  158. return false;
  159. SetWireCuts(wire.Owner, true);
  160. SetPower(wire.Owner, false);
  161. return true;
  162. }
  163. public override bool Mend(EntityUid user, Wire wire)
  164. {
  165. base.Mend(user, wire);
  166. if (!TrySetElectrocution(user, wire))
  167. return false;
  168. // Mending any power wire restores shorts.
  169. WiresSystem.TryCancelWireAction(wire.Owner, PowerWireActionKey.PulseCancel);
  170. WiresSystem.TryCancelWireAction(wire.Owner, PowerWireActionKey.ElectrifiedCancel);
  171. SetWireCuts(wire.Owner, false);
  172. SetPower(wire.Owner, false);
  173. return true;
  174. }
  175. public override void Pulse(EntityUid user, Wire wire)
  176. {
  177. base.Pulse(user, wire);
  178. WiresSystem.TryCancelWireAction(wire.Owner, PowerWireActionKey.ElectrifiedCancel);
  179. var electrocuted = !TrySetElectrocution(user, wire, true);
  180. if (WiresSystem.TryGetData<bool>(wire.Owner, PowerWireActionKey.Pulsed, out var pulsedKey) && pulsedKey)
  181. return;
  182. WiresSystem.SetData(wire.Owner, PowerWireActionKey.Pulsed, true);
  183. WiresSystem.StartWireAction(wire.Owner, _pulseTimeout, PowerWireActionKey.PulseCancel, new TimedWireEvent(AwaitPulseCancel, wire));
  184. if (electrocuted)
  185. return;
  186. SetPower(wire.Owner, true);
  187. }
  188. public override void Update(Wire wire)
  189. {
  190. UpdateElectrocution(wire);
  191. if (!IsPowered(wire.Owner))
  192. {
  193. if (!WiresSystem.TryGetData<bool>(wire.Owner, PowerWireActionKey.Pulsed, out var pulsed)
  194. || !pulsed)
  195. {
  196. WiresSystem.TryCancelWireAction(wire.Owner, PowerWireActionKey.ElectrifiedCancel);
  197. WiresSystem.TryCancelWireAction(wire.Owner, PowerWireActionKey.PulseCancel);
  198. }
  199. }
  200. }
  201. private void AwaitElectrifiedCancel(Wire wire)
  202. {
  203. if (AllWiresMended(wire.Owner))
  204. {
  205. SetElectrified(wire.Owner, false);
  206. }
  207. }
  208. private void AwaitPulseCancel(Wire wire)
  209. {
  210. WiresSystem.SetData(wire.Owner, PowerWireActionKey.Pulsed, false);
  211. SetPower(wire.Owner, false);
  212. }
  213. }