diff --git a/Content.Client/Stunnable/StunbatonSystem.cs b/Content.Client/Stunnable/StunbatonSystem.cs new file mode 100644 index 0000000000..e589dae5f0 --- /dev/null +++ b/Content.Client/Stunnable/StunbatonSystem.cs @@ -0,0 +1,7 @@ +using Content.Shared.Stunnable; + +namespace Content.Client.Stunnable; + +public sealed class StunbatonSystem : SharedStunbatonSystem +{ +} diff --git a/Content.Server/Stunnable/Components/StunbatonComponent.cs b/Content.Server/Stunnable/Components/StunbatonComponent.cs deleted file mode 100644 index ca5b98c9bb..0000000000 --- a/Content.Server/Stunnable/Components/StunbatonComponent.cs +++ /dev/null @@ -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"); - } -} diff --git a/Content.Server/Stunnable/Systems/StunbatonSystem.cs b/Content.Server/Stunnable/Systems/StunbatonSystem.cs index f32ba611af..1fef8f1159 100644 --- a/Content.Server/Stunnable/Systems/StunbatonSystem.cs +++ b/Content.Server/Stunnable/Systems/StunbatonSystem.cs @@ -4,20 +4,19 @@ using Content.Server.Power.EntitySystems; using Content.Server.Power.Events; using Content.Server.Stunnable.Components; using Content.Shared.Audio; -using Content.Shared.Damage; using Content.Shared.Damage.Events; using Content.Shared.Examine; using Content.Shared.Interaction.Events; using Content.Shared.Item; using Content.Shared.Popups; +using Content.Shared.Stunnable; using Content.Shared.Toggleable; -using Content.Shared.Weapons.Melee.Events; using Robust.Shared.Audio; using Robust.Shared.Player; namespace Content.Server.Stunnable.Systems { - public sealed class StunbatonSystem : EntitySystem + public sealed class StunbatonSystem : SharedStunbatonSystem { [Dependency] private readonly SharedItemSystem _item = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; @@ -31,16 +30,6 @@ namespace Content.Server.Stunnable.Systems SubscribeLocalEvent(OnExamined); SubscribeLocalEvent(OnSolutionChange); SubscribeLocalEvent(OnStaminaHitAttempt); - SubscribeLocalEvent(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) @@ -52,8 +41,6 @@ namespace Content.Server.Stunnable.Systems return; } - args.HitSoundOverride = component.StunSound; - if (battery.CurrentCharge < component.EnergyPerUse) { 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)); comp.Activated = false; + Dirty(comp); } 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)); comp.Activated = true; + Dirty(comp); } // https://github.com/space-wizards/space-station-14/pull/17288#discussion_r1241213341 diff --git a/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs b/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs index 39c97f4749..767846fb2d 100644 --- a/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs +++ b/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs @@ -166,7 +166,6 @@ public sealed class MeleeWeaponSystem : SharedMeleeWeaponSystem var eventArgs = new DisarmedEvent { Target = target, Source = user, PushProbability = 1 - chance }; RaiseLocalEvent(target, eventArgs); - RaiseNetworkEvent(new ColorFlashEffectEvent(Color.Aqua, new List() { target })); return true; } diff --git a/Content.Shared/Damage/Components/StaminaDamageOnCollideComponent.cs b/Content.Shared/Damage/Components/StaminaDamageOnCollideComponent.cs index 1cb37e44b0..a5a6e1bb8a 100644 --- a/Content.Shared/Damage/Components/StaminaDamageOnCollideComponent.cs +++ b/Content.Shared/Damage/Components/StaminaDamageOnCollideComponent.cs @@ -1,3 +1,5 @@ +using Robust.Shared.Audio; + namespace Content.Shared.Damage.Components; /// @@ -8,4 +10,7 @@ public sealed class StaminaDamageOnCollideComponent : Component { [ViewVariables(VVAccess.ReadWrite), DataField("damage")] public float Damage = 55f; + + [DataField("sound")] + public SoundSpecifier? Sound; } diff --git a/Content.Shared/Damage/Components/StaminaDamageOnHitComponent.cs b/Content.Shared/Damage/Components/StaminaDamageOnHitComponent.cs index 94fc40d112..578acce410 100644 --- a/Content.Shared/Damage/Components/StaminaDamageOnHitComponent.cs +++ b/Content.Shared/Damage/Components/StaminaDamageOnHitComponent.cs @@ -1,3 +1,5 @@ +using Robust.Shared.Audio; + namespace Content.Shared.Damage.Components; [RegisterComponent] @@ -5,4 +7,7 @@ public sealed class StaminaDamageOnHitComponent : Component { [ViewVariables(VVAccess.ReadWrite), DataField("damage")] public float Damage = 30f; + + [DataField("sound")] + public SoundSpecifier? Sound; } diff --git a/Content.Shared/Damage/Events/StaminaDamageOnHitAttemptEvent.cs b/Content.Shared/Damage/Events/StaminaDamageOnHitAttemptEvent.cs index 9c9a587320..33f4c7333f 100644 --- a/Content.Shared/Damage/Events/StaminaDamageOnHitAttemptEvent.cs +++ b/Content.Shared/Damage/Events/StaminaDamageOnHitAttemptEvent.cs @@ -1,19 +1,7 @@ -using Robust.Shared.Audio; - namespace Content.Shared.Damage.Events; /// -/// Attempting to apply stamina damage on a melee hit to an entity. +/// Attempting to apply stamina damage on entity. /// [ByRefEvent] -public struct StaminaDamageOnHitAttemptEvent -{ - public bool Cancelled; - public SoundSpecifier? HitSoundOverride; - - public StaminaDamageOnHitAttemptEvent(bool cancelled, SoundSpecifier? hitSoundOverride) - { - Cancelled = cancelled; - HitSoundOverride = hitSoundOverride; - } -} +public record struct StaminaDamageOnHitAttemptEvent(bool Cancelled); diff --git a/Content.Shared/Damage/Systems/StaminaSystem.cs b/Content.Shared/Damage/Systems/StaminaSystem.cs index cb9ba4e242..eaa041d6d2 100644 --- a/Content.Shared/Damage/Systems/StaminaSystem.cs +++ b/Content.Shared/Damage/Systems/StaminaSystem.cs @@ -5,15 +5,19 @@ using Content.Shared.CombatMode; using Content.Shared.Damage.Components; using Content.Shared.Damage.Events; using Content.Shared.Database; +using Content.Shared.Effects; using Content.Shared.IdentityManagement; using Content.Shared.Popups; using Content.Shared.Projectiles; using Content.Shared.Rejuvenate; using Content.Shared.Rounding; using Content.Shared.Stunnable; +using Content.Shared.Throwing; using Content.Shared.Weapons.Melee.Events; using JetBrains.Annotations; +using Robust.Shared.Audio; using Robust.Shared.GameStates; +using Robust.Shared.Network; using Robust.Shared.Player; using Robust.Shared.Random; using Robust.Shared.Serialization; @@ -30,6 +34,8 @@ public sealed partial class StaminaSystem : EntitySystem [Dependency] private readonly MetaDataSystem _metadata = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly SharedStunSystem _stunSystem = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly INetManager _net = default!; /// /// 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(OnDisarmed); SubscribeLocalEvent(OnRejuvenate); - SubscribeLocalEvent(OnCollide); - SubscribeLocalEvent(OnHit); + SubscribeLocalEvent(OnProjectileHit); + SubscribeLocalEvent(OnThrowHit); + SubscribeLocalEvent(OnMeleeHit); } private void OnStamUnpaused(EntityUid uid, StaminaComponent component, ref EntityUnpausedEvent args) @@ -159,7 +166,7 @@ public sealed partial class StaminaSystem : EntitySystem args.Handled = true; } - private void OnHit(EntityUid uid, StaminaDamageOnHitComponent component, MeleeHitEvent args) + private void OnMeleeHit(EntityUid uid, StaminaDamageOnHitComponent component, MeleeHitEvent args) { if (!args.IsHit || !args.HitEntities.Any() || @@ -170,11 +177,9 @@ public sealed partial class StaminaSystem : EntitySystem var ev = new StaminaDamageOnHitAttemptEvent(); RaiseLocalEvent(uid, ref ev); - if (ev.Cancelled) return; - args.HitSoundOverride = ev.HitSoundOverride; var stamQuery = GetEntityQuery(); var toHit = new List<(EntityUid Entity, StaminaComponent Component)>(); @@ -201,18 +206,28 @@ public sealed partial class StaminaSystem : EntitySystem foreach (var (ent, comp) in toHit) { - var oldDamage = comp.StaminaDamage; - 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); - } + TakeStaminaDamage(ent, damage / toHit.Count, comp, source: args.User, with: args.Weapon, sound: component.Sound); } } - 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) @@ -240,11 +255,12 @@ public sealed partial class StaminaSystem : EntitySystem if (oldStam + value > component.CritThreshold || component.Critical) return false; - TakeStaminaDamage(uid, value, component, source, with); + TakeStaminaDamage(uid, value, component, source, with, visual: false); 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)) return; @@ -309,6 +325,16 @@ public sealed partial class StaminaSystem : EntitySystem { _adminLogger.Add(LogType.Stamina, $"{ToPrettyString(uid):target} took {value} stamina damage"); } + + if (visual) + { + RaiseNetworkEvent(new ColorFlashEffectEvent(Color.Aqua, new List() { uid })); + } + + if (_net.IsServer) + { + _audio.PlayPvs(sound, uid); + } } public override void Update(float frameTime) diff --git a/Content.Shared/Stunnable/SharedStunbatonSystem.cs b/Content.Shared/Stunnable/SharedStunbatonSystem.cs new file mode 100644 index 0000000000..c964a9427d --- /dev/null +++ b/Content.Shared/Stunnable/SharedStunbatonSystem.cs @@ -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(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(); + } +} diff --git a/Content.Shared/Stunnable/StunbatonComponent.cs b/Content.Shared/Stunnable/StunbatonComponent.cs new file mode 100644 index 0000000000..1cbba641be --- /dev/null +++ b/Content.Shared/Stunnable/StunbatonComponent.cs @@ -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"); +} diff --git a/Resources/Locale/en-US/damage/stamina.ftl b/Resources/Locale/en-US/damage/stamina.ftl index ce45d76c69..0d14a52c1e 100644 --- a/Resources/Locale/en-US/damage/stamina.ftl +++ b/Resources/Locale/en-US/damage/stamina.ftl @@ -1,2 +1 @@ -stamina-resist = Resisted melee-stamina = Not enough stamina diff --git a/Resources/Prototypes/Entities/Objects/Weapons/security.yml b/Resources/Prototypes/Entities/Objects/Weapons/security.yml index e33787954e..851b9f9f11 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/security.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/security.yml @@ -20,6 +20,10 @@ animation: WeaponArcSlash - type: StaminaDamageOnHit damage: 55 + sound: /Audio/Weapons/egloves.ogg + - type: StaminaDamageOnCollide + damage: 55 + sound: /Audio/Weapons/egloves.ogg - type: Battery maxCharge: 1000 startingCharge: 1000