BatteryDrainerSystem.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. using Content.Server.Ninja.Events;
  2. using Content.Server.Power.Components;
  3. using Content.Server.Power.EntitySystems;
  4. using Content.Shared.DoAfter;
  5. using Content.Shared.Interaction;
  6. using Content.Shared.Ninja.Components;
  7. using Content.Shared.Ninja.Systems;
  8. using Content.Shared.Popups;
  9. using Robust.Shared.Audio;
  10. using Robust.Shared.Audio.Systems;
  11. namespace Content.Server.Ninja.Systems;
  12. /// <summary>
  13. /// Handles the doafter and power transfer when draining.
  14. /// </summary>
  15. public sealed class BatteryDrainerSystem : SharedBatteryDrainerSystem
  16. {
  17. [Dependency] private readonly BatterySystem _battery = default!;
  18. [Dependency] private readonly SharedAudioSystem _audio = default!;
  19. [Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
  20. [Dependency] private readonly SharedPopupSystem _popup = default!;
  21. public override void Initialize()
  22. {
  23. base.Initialize();
  24. SubscribeLocalEvent<BatteryDrainerComponent, BeforeInteractHandEvent>(OnBeforeInteractHand);
  25. SubscribeLocalEvent<BatteryDrainerComponent, NinjaBatteryChangedEvent>(OnBatteryChanged);
  26. }
  27. /// <summary>
  28. /// Start do after for draining a power source.
  29. /// Can't predict PNBC existing so only done on server.
  30. /// </summary>
  31. private void OnBeforeInteractHand(Entity<BatteryDrainerComponent> ent, ref BeforeInteractHandEvent args)
  32. {
  33. var (uid, comp) = ent;
  34. var target = args.Target;
  35. if (args.Handled || comp.BatteryUid is not {} battery || !HasComp<PowerNetworkBatteryComponent>(target))
  36. return;
  37. // handles even if battery is full so you can actually see the poup
  38. args.Handled = true;
  39. if (_battery.IsFull(battery))
  40. {
  41. _popup.PopupEntity(Loc.GetString("battery-drainer-full"), uid, uid, PopupType.Medium);
  42. return;
  43. }
  44. var doAfterArgs = new DoAfterArgs(EntityManager, uid, comp.DrainTime, new DrainDoAfterEvent(), target: target, eventTarget: uid)
  45. {
  46. MovementThreshold = 0.5f,
  47. BreakOnMove = true,
  48. CancelDuplicate = false,
  49. AttemptFrequency = AttemptFrequency.StartAndEnd
  50. };
  51. _doAfter.TryStartDoAfter(doAfterArgs);
  52. }
  53. private void OnBatteryChanged(Entity<BatteryDrainerComponent> ent, ref NinjaBatteryChangedEvent args)
  54. {
  55. SetBattery((ent, ent.Comp), args.Battery);
  56. }
  57. /// <inheritdoc/>
  58. protected override void OnDoAfterAttempt(Entity<BatteryDrainerComponent> ent, ref DoAfterAttemptEvent<DrainDoAfterEvent> args)
  59. {
  60. base.OnDoAfterAttempt(ent, ref args);
  61. if (ent.Comp.BatteryUid is not {} battery || _battery.IsFull(battery))
  62. args.Cancel();
  63. }
  64. /// <inheritdoc/>
  65. protected override bool TryDrainPower(Entity<BatteryDrainerComponent> ent, EntityUid target)
  66. {
  67. var (uid, comp) = ent;
  68. if (comp.BatteryUid == null || !TryComp<BatteryComponent>(comp.BatteryUid.Value, out var battery))
  69. return false;
  70. if (!TryComp<BatteryComponent>(target, out var targetBattery) || !TryComp<PowerNetworkBatteryComponent>(target, out var pnb))
  71. return false;
  72. if (MathHelper.CloseToPercent(targetBattery.CurrentCharge, 0))
  73. {
  74. _popup.PopupEntity(Loc.GetString("battery-drainer-empty", ("battery", target)), uid, uid, PopupType.Medium);
  75. return false;
  76. }
  77. var available = targetBattery.CurrentCharge;
  78. var required = battery.MaxCharge - battery.CurrentCharge;
  79. // higher tier storages can charge more
  80. var maxDrained = pnb.MaxSupply * comp.DrainTime;
  81. var input = Math.Min(Math.Min(available, required / comp.DrainEfficiency), maxDrained);
  82. if (!_battery.TryUseCharge(target, input, targetBattery))
  83. return false;
  84. var output = input * comp.DrainEfficiency;
  85. _battery.SetCharge(comp.BatteryUid.Value, battery.CurrentCharge + output, battery);
  86. // TODO: create effect message or something
  87. Spawn("EffectSparks", Transform(target).Coordinates);
  88. _audio.PlayPvs(comp.SparkSound, target);
  89. _popup.PopupEntity(Loc.GetString("battery-drainer-success", ("battery", target)), uid, uid);
  90. // repeat the doafter until battery is full
  91. return !_battery.IsFull(ent, battery);
  92. }
  93. }