diff --git a/Content.Server/Ninja/Events/BatteryChangedEvent.cs b/Content.Server/Ninja/Events/BatteryChangedEvent.cs
new file mode 100644
index 0000000000..45bfedfee7
--- /dev/null
+++ b/Content.Server/Ninja/Events/BatteryChangedEvent.cs
@@ -0,0 +1,7 @@
+namespace Content.Server.Ninja.Events;
+
+///
+/// Raised on the ninja when the suit has its powercell changed.
+///
+[ByRefEvent]
+public record struct NinjaBatteryChangedEvent(EntityUid Battery, EntityUid BatteryHolder);
diff --git a/Content.Server/Ninja/Systems/BatteryDrainerSystem.cs b/Content.Server/Ninja/Systems/BatteryDrainerSystem.cs
index d5871c147d..37bf0eade1 100644
--- a/Content.Server/Ninja/Systems/BatteryDrainerSystem.cs
+++ b/Content.Server/Ninja/Systems/BatteryDrainerSystem.cs
@@ -1,3 +1,4 @@
+using Content.Server.Ninja.Events;
using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems;
using Content.Shared.DoAfter;
@@ -24,6 +25,7 @@ public sealed class BatteryDrainerSystem : SharedBatteryDrainerSystem
base.Initialize();
SubscribeLocalEvent(OnBeforeInteractHand);
+ SubscribeLocalEvent(OnBatteryChanged);
}
///
@@ -56,6 +58,11 @@ public sealed class BatteryDrainerSystem : SharedBatteryDrainerSystem
_doAfter.TryStartDoAfter(doAfterArgs);
}
+ private void OnBatteryChanged(EntityUid uid, BatteryDrainerComponent comp, ref NinjaBatteryChangedEvent args)
+ {
+ SetBattery(uid, args.Battery, comp);
+ }
+
///
protected override void OnDoAfterAttempt(EntityUid uid, BatteryDrainerComponent comp, DoAfterAttemptEvent args)
{
diff --git a/Content.Server/Ninja/Systems/NinjaGlovesSystem.cs b/Content.Server/Ninja/Systems/NinjaGlovesSystem.cs
index 402650d6a6..119aaa7434 100644
--- a/Content.Server/Ninja/Systems/NinjaGlovesSystem.cs
+++ b/Content.Server/Ninja/Systems/NinjaGlovesSystem.cs
@@ -1,7 +1,7 @@
using Content.Server.Communications;
using Content.Server.DoAfter;
using Content.Server.Mind;
-using Content.Server.Ninja.Systems;
+using Content.Server.Ninja.Events;
using Content.Server.Power.Components;
using Content.Server.Roles;
using Content.Shared.Communications;
@@ -22,11 +22,10 @@ namespace Content.Server.Ninja.Systems;
public sealed class NinjaGlovesSystem : SharedNinjaGlovesSystem
{
[Dependency] private readonly EmagProviderSystem _emagProvider = default!;
- [Dependency] private readonly SharedBatteryDrainerSystem _drainer = default!;
- [Dependency] private readonly SharedStunProviderSystem _stunProvider = default!;
- [Dependency] private readonly SpaceNinjaSystem _ninja = default!;
[Dependency] private readonly CommsHackerSystem _commsHacker = default!;
[Dependency] private readonly MindSystem _mind = default!;
+ [Dependency] private readonly SharedStunProviderSystem _stunProvider = default!;
+ [Dependency] private readonly SpaceNinjaSystem _ninja = default!;
public override void Initialize()
{
@@ -73,6 +72,10 @@ public sealed class NinjaGlovesSystem : SharedNinjaGlovesSystem
private void EnableGloves(EntityUid uid, NinjaGlovesComponent comp, EntityUid user, SpaceNinjaComponent ninja)
{
+ // can't use abilities if suit is not equipped, this is checked elsewhere but just making sure to satisfy nullability
+ if (ninja.Suit == null)
+ return;
+
comp.User = user;
Dirty(uid, comp);
_ninja.AssignGloves(user, uid, ninja);
@@ -82,8 +85,8 @@ public sealed class NinjaGlovesSystem : SharedNinjaGlovesSystem
_stunProvider.SetNoPowerPopup(user, "ninja-no-power", stun);
if (_ninja.GetNinjaBattery(user, out var battery, out var _))
{
- _drainer.SetBattery(user, battery, drainer);
- _stunProvider.SetBattery(user, battery, stun);
+ var ev = new NinjaBatteryChangedEvent(battery.Value, ninja.Suit.Value);
+ RaiseLocalEvent(user, ref ev);
}
var emag = EnsureComp(user);
diff --git a/Content.Server/Ninja/Systems/NinjaSuitSystem.cs b/Content.Server/Ninja/Systems/NinjaSuitSystem.cs
index f6ad646d22..61beed9481 100644
--- a/Content.Server/Ninja/Systems/NinjaSuitSystem.cs
+++ b/Content.Server/Ninja/Systems/NinjaSuitSystem.cs
@@ -1,4 +1,5 @@
using Content.Server.Emp;
+using Content.Server.Ninja.Events;
using Content.Server.Popups;
using Content.Server.Power.Components;
using Content.Server.PowerCell;
@@ -8,6 +9,7 @@ using Content.Shared.Hands.EntitySystems;
using Content.Shared.Ninja.Components;
using Content.Shared.Ninja.Systems;
using Content.Shared.Popups;
+using Content.Shared.PowerCell.Components;
using Robust.Shared.Containers;
namespace Content.Server.Ninja.Systems;
@@ -47,6 +49,11 @@ public sealed class NinjaSuitSystem : SharedNinjaSuitSystem
// TODO: or put MaxCharge in shared along with powercellslot
private void OnSuitInsertAttempt(EntityUid uid, NinjaSuitComponent comp, ContainerIsInsertingAttemptEvent args)
{
+ // this is for handling battery upgrading, not stopping actions from being added
+ // if another container like ActionsContainer is specified, don't handle it
+ if (TryComp(uid, out var slot) && args.Container.ID != slot.CellSlotId)
+ return;
+
// no power cell for some reason??? allow it
if (!_powerCell.TryGetBatteryFromSlot(uid, out var battery))
return;
@@ -57,7 +64,13 @@ public sealed class NinjaSuitSystem : SharedNinjaSuitSystem
args.Cancel();
}
- // TODO: raise event on ninja telling it to update battery
+ // tell ninja abilities that use battery to update it so they don't use charge from the old one
+ var user = Transform(uid).ParentUid;
+ if (!HasComp(user))
+ return;
+
+ var ev = new NinjaBatteryChangedEvent(args.EntityUid, uid);
+ RaiseLocalEvent(user, ref ev);
}
private void OnEmpAttempt(EntityUid uid, NinjaSuitComponent comp, EmpAttemptEvent args)
diff --git a/Content.Server/Ninja/Systems/StunProviderSystem.cs b/Content.Server/Ninja/Systems/StunProviderSystem.cs
index 21e8b2042f..70182e0e36 100644
--- a/Content.Server/Ninja/Systems/StunProviderSystem.cs
+++ b/Content.Server/Ninja/Systems/StunProviderSystem.cs
@@ -1,10 +1,12 @@
+using Content.Server.Ninja.Events;
+using Content.Server.Power.EntitySystems;
using Content.Shared.Electrocution;
using Content.Shared.Interaction;
using Content.Shared.Ninja.Components;
using Content.Shared.Ninja.Systems;
using Content.Shared.Popups;
using Content.Shared.Whitelist;
-using Content.Server.Power.EntitySystems;
+using Robust.Shared.Audio;
using Robust.Shared.Timing;
namespace Content.Server.Ninja.Systems;
@@ -16,6 +18,7 @@ public sealed class StunProviderSystem : SharedStunProviderSystem
{
[Dependency] private readonly BatterySystem _battery = default!;
[Dependency] private readonly IGameTiming _timing = default!;
+ [Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedElectrocutionSystem _electrocution = default!;
[Dependency] private readonly SharedNinjaGlovesSystem _gloves = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
@@ -25,6 +28,7 @@ public sealed class StunProviderSystem : SharedStunProviderSystem
base.Initialize();
SubscribeLocalEvent(OnBeforeInteractHand);
+ SubscribeLocalEvent(OnBatteryChanged);
}
///
@@ -49,12 +53,18 @@ public sealed class StunProviderSystem : SharedStunProviderSystem
return;
}
+ _audio.PlayPvs(comp.Sound, target);
+
// not holding hands with target so insuls don't matter
_electrocution.TryDoElectrocution(target, uid, comp.StunDamage, comp.StunTime, false, ignoreInsulation: true);
// short cooldown to prevent instant stunlocking
comp.NextStun = _timing.CurTime + comp.Cooldown;
- Dirty(uid, comp);
args.Handled = true;
}
+
+ private void OnBatteryChanged(EntityUid uid, StunProviderComponent comp, ref NinjaBatteryChangedEvent args)
+ {
+ SetBattery(uid, args.Battery, comp);
+ }
}
diff --git a/Content.Shared/Ninja/Components/StunProviderComponent.cs b/Content.Shared/Ninja/Components/StunProviderComponent.cs
index 653b125478..e8eb25a1b6 100644
--- a/Content.Shared/Ninja/Components/StunProviderComponent.cs
+++ b/Content.Shared/Ninja/Components/StunProviderComponent.cs
@@ -1,5 +1,6 @@
using Content.Shared.Ninja.Systems;
using Content.Shared.Whitelist;
+using Robust.Shared.Audio;
using Robust.Shared.GameStates;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
@@ -19,6 +20,12 @@ public sealed partial class StunProviderComponent : Component
[DataField("batteryUid"), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
public EntityUid? BatteryUid;
+ ///
+ /// Sound played when stunning someone.
+ ///
+ [DataField("sound"), ViewVariables(VVAccess.ReadWrite)]
+ public SoundSpecifier Sound = new SoundCollectionSpecifier("sparks");
+
///
/// Joules required in the battery to stun someone. Defaults to 10 uses on a small battery.
///
@@ -35,13 +42,13 @@ public sealed partial class StunProviderComponent : Component
/// Time that someone is stunned for, stacks if done multiple times.
///
[DataField("stunTime"), ViewVariables(VVAccess.ReadWrite)]
- public TimeSpan StunTime = TimeSpan.FromSeconds(3);
+ public TimeSpan StunTime = TimeSpan.FromSeconds(5);
///
/// How long stunning is disabled after stunning something.
///
[DataField("cooldown"), ViewVariables(VVAccess.ReadWrite)]
- public TimeSpan Cooldown = TimeSpan.FromSeconds(1);
+ public TimeSpan Cooldown = TimeSpan.FromSeconds(2);
///
/// Locale string to popup when there is no power