Fix stun baton throwing and visual effect (#18777)

This commit is contained in:
Slava0135
2023-08-08 23:19:31 +03:00
committed by GitHub
parent 2714101ad7
commit 375f487d94
12 changed files with 117 additions and 75 deletions

View File

@@ -0,0 +1,7 @@
using Content.Shared.Stunnable;
namespace Content.Client.Stunnable;
public sealed class StunbatonSystem : SharedStunbatonSystem
{
}

View File

@@ -1,29 +0,0 @@
using Content.Server.Stunnable.Systems;
using Content.Shared.Timing;
using Robust.Shared.Audio;
namespace Content.Server.Stunnable.Components
{
[RegisterComponent, Access(typeof(StunbatonSystem))]
public sealed class StunbatonComponent : Component
{
public bool Activated = false;
[ViewVariables(VVAccess.ReadWrite)]
[DataField("energyPerUse")]
public float EnergyPerUse { get; set; } = 350;
[ViewVariables(VVAccess.ReadWrite)]
[DataField("onThrowStunChance")]
public float OnThrowStunChance { get; set; } = 0.20f;
[DataField("stunSound")]
public SoundSpecifier StunSound { get; set; } = new SoundPathSpecifier("/Audio/Weapons/egloves.ogg");
[DataField("sparksSound")]
public SoundSpecifier SparksSound { get; set; } = new SoundCollectionSpecifier("sparks");
[DataField("turnOnFailSound")]
public SoundSpecifier TurnOnFailSound { get; set; } = new SoundPathSpecifier("/Audio/Machines/button.ogg");
}
}

View File

@@ -4,20 +4,19 @@ using Content.Server.Power.EntitySystems;
using Content.Server.Power.Events; using Content.Server.Power.Events;
using Content.Server.Stunnable.Components; using Content.Server.Stunnable.Components;
using Content.Shared.Audio; using Content.Shared.Audio;
using Content.Shared.Damage;
using Content.Shared.Damage.Events; using Content.Shared.Damage.Events;
using Content.Shared.Examine; using Content.Shared.Examine;
using Content.Shared.Interaction.Events; using Content.Shared.Interaction.Events;
using Content.Shared.Item; using Content.Shared.Item;
using Content.Shared.Popups; using Content.Shared.Popups;
using Content.Shared.Stunnable;
using Content.Shared.Toggleable; using Content.Shared.Toggleable;
using Content.Shared.Weapons.Melee.Events;
using Robust.Shared.Audio; using Robust.Shared.Audio;
using Robust.Shared.Player; using Robust.Shared.Player;
namespace Content.Server.Stunnable.Systems namespace Content.Server.Stunnable.Systems
{ {
public sealed class StunbatonSystem : EntitySystem public sealed class StunbatonSystem : SharedStunbatonSystem
{ {
[Dependency] private readonly SharedItemSystem _item = default!; [Dependency] private readonly SharedItemSystem _item = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
@@ -31,16 +30,6 @@ namespace Content.Server.Stunnable.Systems
SubscribeLocalEvent<StunbatonComponent, ExaminedEvent>(OnExamined); SubscribeLocalEvent<StunbatonComponent, ExaminedEvent>(OnExamined);
SubscribeLocalEvent<StunbatonComponent, SolutionChangedEvent>(OnSolutionChange); SubscribeLocalEvent<StunbatonComponent, SolutionChangedEvent>(OnSolutionChange);
SubscribeLocalEvent<StunbatonComponent, StaminaDamageOnHitAttemptEvent>(OnStaminaHitAttempt); SubscribeLocalEvent<StunbatonComponent, StaminaDamageOnHitAttemptEvent>(OnStaminaHitAttempt);
SubscribeLocalEvent<StunbatonComponent, GetMeleeDamageEvent>(OnGetMeleeDamage);
}
private void OnGetMeleeDamage(EntityUid uid, StunbatonComponent component, ref GetMeleeDamageEvent args)
{
if (!component.Activated)
return;
// Don't apply damage if it's activated; just do stamina damage.
args.Damage = new DamageSpecifier();
} }
private void OnStaminaHitAttempt(EntityUid uid, StunbatonComponent component, ref StaminaDamageOnHitAttemptEvent args) private void OnStaminaHitAttempt(EntityUid uid, StunbatonComponent component, ref StaminaDamageOnHitAttemptEvent args)
@@ -52,8 +41,6 @@ namespace Content.Server.Stunnable.Systems
return; return;
} }
args.HitSoundOverride = component.StunSound;
if (battery.CurrentCharge < component.EnergyPerUse) if (battery.CurrentCharge < component.EnergyPerUse)
{ {
SoundSystem.Play(component.SparksSound.GetSound(), Filter.Pvs(component.Owner, entityManager: EntityManager), uid, AudioHelpers.WithVariation(0.25f)); SoundSystem.Play(component.SparksSound.GetSound(), Filter.Pvs(component.Owner, entityManager: EntityManager), uid, AudioHelpers.WithVariation(0.25f));
@@ -99,6 +86,7 @@ namespace Content.Server.Stunnable.Systems
SoundSystem.Play(comp.SparksSound.GetSound(), Filter.Pvs(comp.Owner), comp.Owner, AudioHelpers.WithVariation(0.25f)); SoundSystem.Play(comp.SparksSound.GetSound(), Filter.Pvs(comp.Owner), comp.Owner, AudioHelpers.WithVariation(0.25f));
comp.Activated = false; comp.Activated = false;
Dirty(comp);
} }
private void TurnOn(EntityUid uid, StunbatonComponent comp, EntityUid user) private void TurnOn(EntityUid uid, StunbatonComponent comp, EntityUid user)
@@ -131,6 +119,7 @@ namespace Content.Server.Stunnable.Systems
SoundSystem.Play(comp.SparksSound.GetSound(), playerFilter, comp.Owner, AudioHelpers.WithVariation(0.25f)); SoundSystem.Play(comp.SparksSound.GetSound(), playerFilter, comp.Owner, AudioHelpers.WithVariation(0.25f));
comp.Activated = true; comp.Activated = true;
Dirty(comp);
} }
// https://github.com/space-wizards/space-station-14/pull/17288#discussion_r1241213341 // https://github.com/space-wizards/space-station-14/pull/17288#discussion_r1241213341

View File

@@ -166,7 +166,6 @@ public sealed class MeleeWeaponSystem : SharedMeleeWeaponSystem
var eventArgs = new DisarmedEvent { Target = target, Source = user, PushProbability = 1 - chance }; var eventArgs = new DisarmedEvent { Target = target, Source = user, PushProbability = 1 - chance };
RaiseLocalEvent(target, eventArgs); RaiseLocalEvent(target, eventArgs);
RaiseNetworkEvent(new ColorFlashEffectEvent(Color.Aqua, new List<EntityUid>() { target }));
return true; return true;
} }

View File

@@ -1,3 +1,5 @@
using Robust.Shared.Audio;
namespace Content.Shared.Damage.Components; namespace Content.Shared.Damage.Components;
/// <summary> /// <summary>
@@ -8,4 +10,7 @@ public sealed class StaminaDamageOnCollideComponent : Component
{ {
[ViewVariables(VVAccess.ReadWrite), DataField("damage")] [ViewVariables(VVAccess.ReadWrite), DataField("damage")]
public float Damage = 55f; public float Damage = 55f;
[DataField("sound")]
public SoundSpecifier? Sound;
} }

View File

@@ -1,3 +1,5 @@
using Robust.Shared.Audio;
namespace Content.Shared.Damage.Components; namespace Content.Shared.Damage.Components;
[RegisterComponent] [RegisterComponent]
@@ -5,4 +7,7 @@ public sealed class StaminaDamageOnHitComponent : Component
{ {
[ViewVariables(VVAccess.ReadWrite), DataField("damage")] [ViewVariables(VVAccess.ReadWrite), DataField("damage")]
public float Damage = 30f; public float Damage = 30f;
[DataField("sound")]
public SoundSpecifier? Sound;
} }

View File

@@ -1,19 +1,7 @@
using Robust.Shared.Audio;
namespace Content.Shared.Damage.Events; namespace Content.Shared.Damage.Events;
/// <summary> /// <summary>
/// Attempting to apply stamina damage on a melee hit to an entity. /// Attempting to apply stamina damage on entity.
/// </summary> /// </summary>
[ByRefEvent] [ByRefEvent]
public struct StaminaDamageOnHitAttemptEvent public record struct StaminaDamageOnHitAttemptEvent(bool Cancelled);
{
public bool Cancelled;
public SoundSpecifier? HitSoundOverride;
public StaminaDamageOnHitAttemptEvent(bool cancelled, SoundSpecifier? hitSoundOverride)
{
Cancelled = cancelled;
HitSoundOverride = hitSoundOverride;
}
}

View File

@@ -5,15 +5,19 @@ using Content.Shared.CombatMode;
using Content.Shared.Damage.Components; using Content.Shared.Damage.Components;
using Content.Shared.Damage.Events; using Content.Shared.Damage.Events;
using Content.Shared.Database; using Content.Shared.Database;
using Content.Shared.Effects;
using Content.Shared.IdentityManagement; using Content.Shared.IdentityManagement;
using Content.Shared.Popups; using Content.Shared.Popups;
using Content.Shared.Projectiles; using Content.Shared.Projectiles;
using Content.Shared.Rejuvenate; using Content.Shared.Rejuvenate;
using Content.Shared.Rounding; using Content.Shared.Rounding;
using Content.Shared.Stunnable; using Content.Shared.Stunnable;
using Content.Shared.Throwing;
using Content.Shared.Weapons.Melee.Events; using Content.Shared.Weapons.Melee.Events;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Shared.Audio;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using Robust.Shared.Network;
using Robust.Shared.Player; using Robust.Shared.Player;
using Robust.Shared.Random; using Robust.Shared.Random;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
@@ -30,6 +34,8 @@ public sealed partial class StaminaSystem : EntitySystem
[Dependency] private readonly MetaDataSystem _metadata = default!; [Dependency] private readonly MetaDataSystem _metadata = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly SharedStunSystem _stunSystem = default!; [Dependency] private readonly SharedStunSystem _stunSystem = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly INetManager _net = default!;
/// <summary> /// <summary>
/// How much of a buffer is there between the stun duration and when stuns can be re-applied. /// How much of a buffer is there between the stun duration and when stuns can be re-applied.
@@ -50,8 +56,9 @@ public sealed partial class StaminaSystem : EntitySystem
SubscribeLocalEvent<StaminaComponent, DisarmedEvent>(OnDisarmed); SubscribeLocalEvent<StaminaComponent, DisarmedEvent>(OnDisarmed);
SubscribeLocalEvent<StaminaComponent, RejuvenateEvent>(OnRejuvenate); SubscribeLocalEvent<StaminaComponent, RejuvenateEvent>(OnRejuvenate);
SubscribeLocalEvent<StaminaDamageOnCollideComponent, ProjectileHitEvent>(OnCollide); SubscribeLocalEvent<StaminaDamageOnCollideComponent, ProjectileHitEvent>(OnProjectileHit);
SubscribeLocalEvent<StaminaDamageOnHitComponent, MeleeHitEvent>(OnHit); SubscribeLocalEvent<StaminaDamageOnCollideComponent, ThrowDoHitEvent>(OnThrowHit);
SubscribeLocalEvent<StaminaDamageOnHitComponent, MeleeHitEvent>(OnMeleeHit);
} }
private void OnStamUnpaused(EntityUid uid, StaminaComponent component, ref EntityUnpausedEvent args) private void OnStamUnpaused(EntityUid uid, StaminaComponent component, ref EntityUnpausedEvent args)
@@ -159,7 +166,7 @@ public sealed partial class StaminaSystem : EntitySystem
args.Handled = true; args.Handled = true;
} }
private void OnHit(EntityUid uid, StaminaDamageOnHitComponent component, MeleeHitEvent args) private void OnMeleeHit(EntityUid uid, StaminaDamageOnHitComponent component, MeleeHitEvent args)
{ {
if (!args.IsHit || if (!args.IsHit ||
!args.HitEntities.Any() || !args.HitEntities.Any() ||
@@ -170,11 +177,9 @@ public sealed partial class StaminaSystem : EntitySystem
var ev = new StaminaDamageOnHitAttemptEvent(); var ev = new StaminaDamageOnHitAttemptEvent();
RaiseLocalEvent(uid, ref ev); RaiseLocalEvent(uid, ref ev);
if (ev.Cancelled) if (ev.Cancelled)
return; return;
args.HitSoundOverride = ev.HitSoundOverride;
var stamQuery = GetEntityQuery<StaminaComponent>(); var stamQuery = GetEntityQuery<StaminaComponent>();
var toHit = new List<(EntityUid Entity, StaminaComponent Component)>(); var toHit = new List<(EntityUid Entity, StaminaComponent Component)>();
@@ -201,18 +206,28 @@ public sealed partial class StaminaSystem : EntitySystem
foreach (var (ent, comp) in toHit) foreach (var (ent, comp) in toHit)
{ {
var oldDamage = comp.StaminaDamage; TakeStaminaDamage(ent, damage / toHit.Count, comp, source: args.User, with: args.Weapon, sound: component.Sound);
TakeStaminaDamage(ent, damage / toHit.Count, comp, source: args.User, with: args.Weapon);
if (comp.StaminaDamage.Equals(oldDamage))
{
_popup.PopupClient(Loc.GetString("stamina-resist"), ent, args.User);
}
} }
} }
private void OnCollide(EntityUid uid, StaminaDamageOnCollideComponent component, ref ProjectileHitEvent args) private void OnProjectileHit(EntityUid uid, StaminaDamageOnCollideComponent component, ref ProjectileHitEvent args)
{ {
TakeStaminaDamage(args.Target, component.Damage, source: uid); OnCollide(uid, component, args.Target);
}
private void OnThrowHit(EntityUid uid, StaminaDamageOnCollideComponent component, ThrowDoHitEvent args)
{
OnCollide(uid, component, args.Target);
}
private void OnCollide(EntityUid uid, StaminaDamageOnCollideComponent component, EntityUid target)
{
var ev = new StaminaDamageOnHitAttemptEvent();
RaiseLocalEvent(uid, ref ev);
if (ev.Cancelled)
return;
TakeStaminaDamage(target, component.Damage, source: uid, sound: component.Sound);
} }
private void SetStaminaAlert(EntityUid uid, StaminaComponent? component = null) private void SetStaminaAlert(EntityUid uid, StaminaComponent? component = null)
@@ -240,11 +255,12 @@ public sealed partial class StaminaSystem : EntitySystem
if (oldStam + value > component.CritThreshold || component.Critical) if (oldStam + value > component.CritThreshold || component.Critical)
return false; return false;
TakeStaminaDamage(uid, value, component, source, with); TakeStaminaDamage(uid, value, component, source, with, visual: false);
return true; return true;
} }
public void TakeStaminaDamage(EntityUid uid, float value, StaminaComponent? component = null, EntityUid? source = null, EntityUid? with = null) public void TakeStaminaDamage(EntityUid uid, float value, StaminaComponent? component = null,
EntityUid? source = null, EntityUid? with = null, bool visual = true, SoundSpecifier? sound = null)
{ {
if (!Resolve(uid, ref component, false)) if (!Resolve(uid, ref component, false))
return; return;
@@ -309,6 +325,16 @@ public sealed partial class StaminaSystem : EntitySystem
{ {
_adminLogger.Add(LogType.Stamina, $"{ToPrettyString(uid):target} took {value} stamina damage"); _adminLogger.Add(LogType.Stamina, $"{ToPrettyString(uid):target} took {value} stamina damage");
} }
if (visual)
{
RaiseNetworkEvent(new ColorFlashEffectEvent(Color.Aqua, new List<EntityUid>() { uid }));
}
if (_net.IsServer)
{
_audio.PlayPvs(sound, uid);
}
} }
public override void Update(float frameTime) public override void Update(float frameTime)

View File

@@ -0,0 +1,24 @@
using Content.Server.Stunnable.Components;
using Content.Shared.Damage;
using Content.Shared.Weapons.Melee.Events;
namespace Content.Shared.Stunnable;
public abstract class SharedStunbatonSystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<StunbatonComponent, GetMeleeDamageEvent>(OnGetMeleeDamage);
}
private void OnGetMeleeDamage(EntityUid uid, StunbatonComponent component, ref GetMeleeDamageEvent args)
{
if (!component.Activated)
return;
// Don't apply damage if it's activated; just do stamina damage.
args.Damage = new DamageSpecifier();
}
}

View File

@@ -0,0 +1,25 @@
using Content.Shared.Stunnable;
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
namespace Content.Server.Stunnable.Components;
[RegisterComponent, NetworkedComponent]
[AutoGenerateComponentState]
[Access(typeof(SharedStunbatonSystem))]
public sealed partial class StunbatonComponent : Component
{
[DataField("activated"), ViewVariables(VVAccess.ReadWrite)]
[AutoNetworkedField]
public bool Activated = false;
[DataField("energyPerUse"), ViewVariables(VVAccess.ReadWrite)]
[AutoNetworkedField]
public float EnergyPerUse = 350;
[DataField("sparksSound")]
public SoundSpecifier SparksSound = new SoundCollectionSpecifier("sparks");
[DataField("turnOnFailSound")]
public SoundSpecifier TurnOnFailSound = new SoundPathSpecifier("/Audio/Machines/button.ogg");
}

View File

@@ -1,2 +1 @@
stamina-resist = Resisted
melee-stamina = Not enough stamina melee-stamina = Not enough stamina

View File

@@ -20,6 +20,10 @@
animation: WeaponArcSlash animation: WeaponArcSlash
- type: StaminaDamageOnHit - type: StaminaDamageOnHit
damage: 55 damage: 55
sound: /Audio/Weapons/egloves.ogg
- type: StaminaDamageOnCollide
damage: 55
sound: /Audio/Weapons/egloves.ogg
- type: Battery - type: Battery
maxCharge: 1000 maxCharge: 1000
startingCharge: 1000 startingCharge: 1000