NinjaSuitSystem.cs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. using Content.Server.Emp;
  2. using Content.Server.Ninja.Events;
  3. using Content.Server.Power.Components;
  4. using Content.Server.PowerCell;
  5. using Content.Shared.Hands.EntitySystems;
  6. using Content.Shared.Ninja.Components;
  7. using Content.Shared.Ninja.Systems;
  8. using Content.Shared.Popups;
  9. using Content.Shared.PowerCell.Components;
  10. using Robust.Shared.Containers;
  11. namespace Content.Server.Ninja.Systems;
  12. /// <summary>
  13. /// Handles power cell upgrading and actions.
  14. /// </summary>
  15. public sealed class NinjaSuitSystem : SharedNinjaSuitSystem
  16. {
  17. [Dependency] private readonly EmpSystem _emp = default!;
  18. [Dependency] private readonly SharedHandsSystem _hands = default!;
  19. [Dependency] private readonly SpaceNinjaSystem _ninja = default!;
  20. [Dependency] private readonly PowerCellSystem _powerCell = default!;
  21. [Dependency] private readonly SharedTransformSystem _transform = default!;
  22. // How much the cell score should be increased per 1 AutoRechargeRate.
  23. private const int AutoRechargeValue = 100;
  24. public override void Initialize()
  25. {
  26. base.Initialize();
  27. SubscribeLocalEvent<NinjaSuitComponent, ContainerIsInsertingAttemptEvent>(OnSuitInsertAttempt);
  28. SubscribeLocalEvent<NinjaSuitComponent, EmpAttemptEvent>(OnEmpAttempt);
  29. SubscribeLocalEvent<NinjaSuitComponent, RecallKatanaEvent>(OnRecallKatana);
  30. SubscribeLocalEvent<NinjaSuitComponent, NinjaEmpEvent>(OnEmp);
  31. }
  32. protected override void NinjaEquipped(Entity<NinjaSuitComponent> ent, Entity<SpaceNinjaComponent> user)
  33. {
  34. base.NinjaEquipped(ent, user);
  35. _ninja.SetSuitPowerAlert(user);
  36. // raise event to let ninja components get starting battery
  37. _ninja.GetNinjaBattery(user.Owner, out var uid, out var _);
  38. if (uid is not {} battery_uid)
  39. return;
  40. var ev = new NinjaBatteryChangedEvent(battery_uid, ent.Owner);
  41. RaiseLocalEvent(ent, ref ev);
  42. RaiseLocalEvent(user, ref ev);
  43. }
  44. // TODO: if/when battery is in shared, put this there too
  45. // TODO: or put MaxCharge in shared along with powercellslot
  46. private void OnSuitInsertAttempt(EntityUid uid, NinjaSuitComponent comp, ContainerIsInsertingAttemptEvent args)
  47. {
  48. // this is for handling battery upgrading, not stopping actions from being added
  49. // if another container like ActionsContainer is specified, don't handle it
  50. if (TryComp<PowerCellSlotComponent>(uid, out var slot) && args.Container.ID != slot.CellSlotId)
  51. return;
  52. // no power cell for some reason??? allow it
  53. if (!_powerCell.TryGetBatteryFromSlot(uid, out var batteryUid, out var battery))
  54. return;
  55. if (!TryComp<BatteryComponent>(args.EntityUid, out var inserting))
  56. {
  57. args.Cancel();
  58. return;
  59. }
  60. var user = Transform(uid).ParentUid;
  61. // can only upgrade power cell, not swap to recharge instantly otherwise ninja could just swap batteries with flashlights in maints for easy power
  62. if (GetCellScore(inserting.Owner, inserting) <= GetCellScore(battery.Owner, battery))
  63. {
  64. args.Cancel();
  65. Popup.PopupEntity(Loc.GetString("ninja-cell-downgrade"), user, user);
  66. return;
  67. }
  68. // tell ninja abilities that use battery to update it so they don't use charge from the old one
  69. if (!_ninja.IsNinja(user))
  70. return;
  71. var ev = new NinjaBatteryChangedEvent(args.EntityUid, uid);
  72. RaiseLocalEvent(uid, ref ev);
  73. RaiseLocalEvent(user, ref ev);
  74. }
  75. // this function assigns a score to a power cell depending on the capacity, to be used when comparing which cell is better.
  76. private float GetCellScore(EntityUid uid, BatteryComponent battcomp)
  77. {
  78. // if a cell is able to automatically recharge, boost the score drastically depending on the recharge rate,
  79. // this is to ensure a ninja can still upgrade to a micro reactor cell even if they already have a medium or high.
  80. if (TryComp<BatterySelfRechargerComponent>(uid, out var selfcomp) && selfcomp.AutoRecharge)
  81. return battcomp.MaxCharge + (selfcomp.AutoRechargeRate*AutoRechargeValue);
  82. return battcomp.MaxCharge;
  83. }
  84. private void OnEmpAttempt(EntityUid uid, NinjaSuitComponent comp, EmpAttemptEvent args)
  85. {
  86. // ninja suit (battery) is immune to emp
  87. // powercell relays the event to suit
  88. args.Cancel();
  89. }
  90. protected override void UserUnequippedSuit(Entity<NinjaSuitComponent> ent, Entity<SpaceNinjaComponent> user)
  91. {
  92. base.UserUnequippedSuit(ent, user);
  93. // remove power indicator
  94. _ninja.SetSuitPowerAlert(user);
  95. }
  96. private void OnRecallKatana(Entity<NinjaSuitComponent> ent, ref RecallKatanaEvent args)
  97. {
  98. var (uid, comp) = ent;
  99. var user = args.Performer;
  100. if (!_ninja.NinjaQuery.TryComp(user, out var ninja) || ninja.Katana == null)
  101. return;
  102. args.Handled = true;
  103. var katana = ninja.Katana.Value;
  104. var coords = _transform.GetWorldPosition(katana);
  105. var distance = (_transform.GetWorldPosition(user) - coords).Length();
  106. var chargeNeeded = distance * comp.RecallCharge;
  107. if (!_ninja.TryUseCharge(user, chargeNeeded))
  108. {
  109. Popup.PopupEntity(Loc.GetString("ninja-no-power"), user, user);
  110. return;
  111. }
  112. if (CheckDisabled(ent, user))
  113. return;
  114. // TODO: teleporting into belt slot
  115. var message = _hands.TryPickupAnyHand(user, katana)
  116. ? "ninja-katana-recalled"
  117. : "ninja-hands-full";
  118. Popup.PopupEntity(Loc.GetString(message), user, user);
  119. }
  120. private void OnEmp(Entity<NinjaSuitComponent> ent, ref NinjaEmpEvent args)
  121. {
  122. var (uid, comp) = ent;
  123. args.Handled = true;
  124. var user = args.Performer;
  125. if (!_ninja.TryUseCharge(user, comp.EmpCharge))
  126. {
  127. Popup.PopupEntity(Loc.GetString("ninja-no-power"), user, user);
  128. return;
  129. }
  130. if (CheckDisabled(ent, user))
  131. return;
  132. var coords = _transform.GetMapCoordinates(user);
  133. _emp.EmpPulse(coords, comp.EmpRange, comp.EmpConsumption, comp.EmpDuration);
  134. }
  135. }