ninja hotfixes (#20032)

* check that slot is power cell slot

* add BatteryChangedEvent

* use BatteryChangedEvent when enabling gloves and replacing battery

* sort gloves dependencies

* increase stun duration and cooldown

* play sound when stunning people

* remove dirty for non networked field

* NinjaBatteryChangedEvent

* real

* fake

---------

Co-authored-by: deltanedas <@deltanedas:kde.org>
This commit is contained in:
deltanedas
2023-09-12 21:54:18 +01:00
committed by GitHub
parent ef869b1cff
commit b53e5d6661
6 changed files with 58 additions and 11 deletions

View File

@@ -0,0 +1,7 @@
namespace Content.Server.Ninja.Events;
/// <summary>
/// Raised on the ninja when the suit has its powercell changed.
/// </summary>
[ByRefEvent]
public record struct NinjaBatteryChangedEvent(EntityUid Battery, EntityUid BatteryHolder);

View File

@@ -1,3 +1,4 @@
using Content.Server.Ninja.Events;
using Content.Server.Power.Components; using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems; using Content.Server.Power.EntitySystems;
using Content.Shared.DoAfter; using Content.Shared.DoAfter;
@@ -24,6 +25,7 @@ public sealed class BatteryDrainerSystem : SharedBatteryDrainerSystem
base.Initialize(); base.Initialize();
SubscribeLocalEvent<BatteryDrainerComponent, BeforeInteractHandEvent>(OnBeforeInteractHand); SubscribeLocalEvent<BatteryDrainerComponent, BeforeInteractHandEvent>(OnBeforeInteractHand);
SubscribeLocalEvent<BatteryDrainerComponent, NinjaBatteryChangedEvent>(OnBatteryChanged);
} }
/// <summary> /// <summary>
@@ -56,6 +58,11 @@ public sealed class BatteryDrainerSystem : SharedBatteryDrainerSystem
_doAfter.TryStartDoAfter(doAfterArgs); _doAfter.TryStartDoAfter(doAfterArgs);
} }
private void OnBatteryChanged(EntityUid uid, BatteryDrainerComponent comp, ref NinjaBatteryChangedEvent args)
{
SetBattery(uid, args.Battery, comp);
}
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnDoAfterAttempt(EntityUid uid, BatteryDrainerComponent comp, DoAfterAttemptEvent<DrainDoAfterEvent> args) protected override void OnDoAfterAttempt(EntityUid uid, BatteryDrainerComponent comp, DoAfterAttemptEvent<DrainDoAfterEvent> args)
{ {

View File

@@ -1,7 +1,7 @@
using Content.Server.Communications; using Content.Server.Communications;
using Content.Server.DoAfter; using Content.Server.DoAfter;
using Content.Server.Mind; using Content.Server.Mind;
using Content.Server.Ninja.Systems; using Content.Server.Ninja.Events;
using Content.Server.Power.Components; using Content.Server.Power.Components;
using Content.Server.Roles; using Content.Server.Roles;
using Content.Shared.Communications; using Content.Shared.Communications;
@@ -22,11 +22,10 @@ namespace Content.Server.Ninja.Systems;
public sealed class NinjaGlovesSystem : SharedNinjaGlovesSystem public sealed class NinjaGlovesSystem : SharedNinjaGlovesSystem
{ {
[Dependency] private readonly EmagProviderSystem _emagProvider = default!; [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 CommsHackerSystem _commsHacker = default!;
[Dependency] private readonly MindSystem _mind = default!; [Dependency] private readonly MindSystem _mind = default!;
[Dependency] private readonly SharedStunProviderSystem _stunProvider = default!;
[Dependency] private readonly SpaceNinjaSystem _ninja = default!;
public override void Initialize() public override void Initialize()
{ {
@@ -73,6 +72,10 @@ public sealed class NinjaGlovesSystem : SharedNinjaGlovesSystem
private void EnableGloves(EntityUid uid, NinjaGlovesComponent comp, EntityUid user, SpaceNinjaComponent ninja) 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; comp.User = user;
Dirty(uid, comp); Dirty(uid, comp);
_ninja.AssignGloves(user, uid, ninja); _ninja.AssignGloves(user, uid, ninja);
@@ -82,8 +85,8 @@ public sealed class NinjaGlovesSystem : SharedNinjaGlovesSystem
_stunProvider.SetNoPowerPopup(user, "ninja-no-power", stun); _stunProvider.SetNoPowerPopup(user, "ninja-no-power", stun);
if (_ninja.GetNinjaBattery(user, out var battery, out var _)) if (_ninja.GetNinjaBattery(user, out var battery, out var _))
{ {
_drainer.SetBattery(user, battery, drainer); var ev = new NinjaBatteryChangedEvent(battery.Value, ninja.Suit.Value);
_stunProvider.SetBattery(user, battery, stun); RaiseLocalEvent(user, ref ev);
} }
var emag = EnsureComp<EmagProviderComponent>(user); var emag = EnsureComp<EmagProviderComponent>(user);

View File

@@ -1,4 +1,5 @@
using Content.Server.Emp; using Content.Server.Emp;
using Content.Server.Ninja.Events;
using Content.Server.Popups; using Content.Server.Popups;
using Content.Server.Power.Components; using Content.Server.Power.Components;
using Content.Server.PowerCell; using Content.Server.PowerCell;
@@ -8,6 +9,7 @@ using Content.Shared.Hands.EntitySystems;
using Content.Shared.Ninja.Components; using Content.Shared.Ninja.Components;
using Content.Shared.Ninja.Systems; using Content.Shared.Ninja.Systems;
using Content.Shared.Popups; using Content.Shared.Popups;
using Content.Shared.PowerCell.Components;
using Robust.Shared.Containers; using Robust.Shared.Containers;
namespace Content.Server.Ninja.Systems; namespace Content.Server.Ninja.Systems;
@@ -47,6 +49,11 @@ public sealed class NinjaSuitSystem : SharedNinjaSuitSystem
// TODO: or put MaxCharge in shared along with powercellslot // TODO: or put MaxCharge in shared along with powercellslot
private void OnSuitInsertAttempt(EntityUid uid, NinjaSuitComponent comp, ContainerIsInsertingAttemptEvent args) 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<PowerCellSlotComponent>(uid, out var slot) && args.Container.ID != slot.CellSlotId)
return;
// no power cell for some reason??? allow it // no power cell for some reason??? allow it
if (!_powerCell.TryGetBatteryFromSlot(uid, out var battery)) if (!_powerCell.TryGetBatteryFromSlot(uid, out var battery))
return; return;
@@ -57,7 +64,13 @@ public sealed class NinjaSuitSystem : SharedNinjaSuitSystem
args.Cancel(); 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<SpaceNinjaComponent>(user))
return;
var ev = new NinjaBatteryChangedEvent(args.EntityUid, uid);
RaiseLocalEvent(user, ref ev);
} }
private void OnEmpAttempt(EntityUid uid, NinjaSuitComponent comp, EmpAttemptEvent args) private void OnEmpAttempt(EntityUid uid, NinjaSuitComponent comp, EmpAttemptEvent args)

View File

@@ -1,10 +1,12 @@
using Content.Server.Ninja.Events;
using Content.Server.Power.EntitySystems;
using Content.Shared.Electrocution; using Content.Shared.Electrocution;
using Content.Shared.Interaction; using Content.Shared.Interaction;
using Content.Shared.Ninja.Components; using Content.Shared.Ninja.Components;
using Content.Shared.Ninja.Systems; using Content.Shared.Ninja.Systems;
using Content.Shared.Popups; using Content.Shared.Popups;
using Content.Shared.Whitelist; using Content.Shared.Whitelist;
using Content.Server.Power.EntitySystems; using Robust.Shared.Audio;
using Robust.Shared.Timing; using Robust.Shared.Timing;
namespace Content.Server.Ninja.Systems; namespace Content.Server.Ninja.Systems;
@@ -16,6 +18,7 @@ public sealed class StunProviderSystem : SharedStunProviderSystem
{ {
[Dependency] private readonly BatterySystem _battery = default!; [Dependency] private readonly BatterySystem _battery = default!;
[Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedElectrocutionSystem _electrocution = default!; [Dependency] private readonly SharedElectrocutionSystem _electrocution = default!;
[Dependency] private readonly SharedNinjaGlovesSystem _gloves = default!; [Dependency] private readonly SharedNinjaGlovesSystem _gloves = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly SharedPopupSystem _popup = default!;
@@ -25,6 +28,7 @@ public sealed class StunProviderSystem : SharedStunProviderSystem
base.Initialize(); base.Initialize();
SubscribeLocalEvent<StunProviderComponent, BeforeInteractHandEvent>(OnBeforeInteractHand); SubscribeLocalEvent<StunProviderComponent, BeforeInteractHandEvent>(OnBeforeInteractHand);
SubscribeLocalEvent<StunProviderComponent, NinjaBatteryChangedEvent>(OnBatteryChanged);
} }
/// <summary> /// <summary>
@@ -49,12 +53,18 @@ public sealed class StunProviderSystem : SharedStunProviderSystem
return; return;
} }
_audio.PlayPvs(comp.Sound, target);
// not holding hands with target so insuls don't matter // not holding hands with target so insuls don't matter
_electrocution.TryDoElectrocution(target, uid, comp.StunDamage, comp.StunTime, false, ignoreInsulation: true); _electrocution.TryDoElectrocution(target, uid, comp.StunDamage, comp.StunTime, false, ignoreInsulation: true);
// short cooldown to prevent instant stunlocking // short cooldown to prevent instant stunlocking
comp.NextStun = _timing.CurTime + comp.Cooldown; comp.NextStun = _timing.CurTime + comp.Cooldown;
Dirty(uid, comp);
args.Handled = true; args.Handled = true;
} }
private void OnBatteryChanged(EntityUid uid, StunProviderComponent comp, ref NinjaBatteryChangedEvent args)
{
SetBattery(uid, args.Battery, comp);
}
} }

View File

@@ -1,5 +1,6 @@
using Content.Shared.Ninja.Systems; using Content.Shared.Ninja.Systems;
using Content.Shared.Whitelist; using Content.Shared.Whitelist;
using Robust.Shared.Audio;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
@@ -19,6 +20,12 @@ public sealed partial class StunProviderComponent : Component
[DataField("batteryUid"), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] [DataField("batteryUid"), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
public EntityUid? BatteryUid; public EntityUid? BatteryUid;
/// <summary>
/// Sound played when stunning someone.
/// </summary>
[DataField("sound"), ViewVariables(VVAccess.ReadWrite)]
public SoundSpecifier Sound = new SoundCollectionSpecifier("sparks");
/// <summary> /// <summary>
/// Joules required in the battery to stun someone. Defaults to 10 uses on a small battery. /// Joules required in the battery to stun someone. Defaults to 10 uses on a small battery.
/// </summary> /// </summary>
@@ -35,13 +42,13 @@ public sealed partial class StunProviderComponent : Component
/// Time that someone is stunned for, stacks if done multiple times. /// Time that someone is stunned for, stacks if done multiple times.
/// </summary> /// </summary>
[DataField("stunTime"), ViewVariables(VVAccess.ReadWrite)] [DataField("stunTime"), ViewVariables(VVAccess.ReadWrite)]
public TimeSpan StunTime = TimeSpan.FromSeconds(3); public TimeSpan StunTime = TimeSpan.FromSeconds(5);
/// <summary> /// <summary>
/// How long stunning is disabled after stunning something. /// How long stunning is disabled after stunning something.
/// </summary> /// </summary>
[DataField("cooldown"), ViewVariables(VVAccess.ReadWrite)] [DataField("cooldown"), ViewVariables(VVAccess.ReadWrite)]
public TimeSpan Cooldown = TimeSpan.FromSeconds(1); public TimeSpan Cooldown = TimeSpan.FromSeconds(2);
/// <summary> /// <summary>
/// Locale string to popup when there is no power /// Locale string to popup when there is no power