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