diff --git a/Content.Server/_White/_Engi/DirectBallsHit/DirectBallsHitComponent.cs b/Content.Server/_White/_Engi/DirectBallsHit/DirectBallsHitComponent.cs new file mode 100644 index 0000000000..8c7d981789 --- /dev/null +++ b/Content.Server/_White/_Engi/DirectBallsHit/DirectBallsHitComponent.cs @@ -0,0 +1,22 @@ +using Content.Shared.Standing.Systems; + +namespace Content.Server._White._Engi.DirectBallsHit; + +[RegisterComponent] +public sealed partial class DirectBallsHitComponent : Component +{ + [DataField] + public TimeSpan KnockdownTime = TimeSpan.FromSeconds(2.0f); + + [DataField] + public TimeSpan JitterTime = TimeSpan.FromSeconds(2.0f); + + [DataField] + public TimeSpan StutterTime = TimeSpan.FromSeconds(2.0f); + + [DataField] + public SharedStandingStateSystem.DropHeldItemsBehavior KnockDownBehavior = SharedStandingStateSystem.DropHeldItemsBehavior.AlwaysDrop; + + [DataField] + public bool RequireWield = true; +} diff --git a/Content.Server/_White/_Engi/DirectBallsHit/DirectBallsHitSystem.cs b/Content.Server/_White/_Engi/DirectBallsHit/DirectBallsHitSystem.cs new file mode 100644 index 0000000000..49d2feb519 --- /dev/null +++ b/Content.Server/_White/_Engi/DirectBallsHit/DirectBallsHitSystem.cs @@ -0,0 +1,68 @@ +using Content.Shared.Stunnable; +using Content.Shared.Weapons.Melee.Events; +using Content.Shared.Wieldable.Components; +using Content.Shared.Jittering; +using Content.Shared.Speech.EntitySystems; +using Content.Shared.StatusEffect; +using Content.Shared.Standing; +using Content.Shared.Electrocution; +using Content.Shared.Popups; +using Content.Shared._White.Implants.NeuroControl; +using Robust.Shared.Timing; +using Content.Server.Chat.Systems; + +namespace Content.Server._White._Engi.DirectBallsHit; + +public sealed class DirectBallsHitSystem : EntitySystem +{ + [Dependency] private readonly SharedStunSystem _stun = default!; + [Dependency] private readonly SharedJitteringSystem _jitter = default!; + [Dependency] private readonly SharedStutteringSystem _stutter = default!; + [Dependency] private readonly SharedElectrocutionSystem _electrocution = default!; + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; + [Dependency] private readonly ChatSystem _chat = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnHit); + } + + private void OnHit(Entity ent, ref MeleeHitEvent args) + { + if (ent.Comp.RequireWield) + { + if (!TryComp(args.Weapon, out var weapon)) + return; + + if (!weapon.Wielded) + return; + } + + foreach (var uid in args.HitEntities) + { + _popupSystem.PopupEntity( + Loc.GetString("direct-balls-hit", ("uid", uid)), + uid, + PopupType.SmallCaution); + + Timer.Spawn(TimeSpan.FromSeconds(0.5f), () => _chat.TryEmoteWithChat(uid, "Scream")); + + if (HasComp(uid)) + { + _electrocution.TryDoElectrocution(uid, null, 30, TimeSpan.FromSeconds(1), false, 0.5f, null, true); + continue; + } + + if (TryComp(uid, out StandingStateComponent? standingState) && standingState.CanLieDown) + _stun.TryKnockdown(uid, ent.Comp.KnockdownTime, true, behavior: ent.Comp.KnockDownBehavior); + + if (TryComp(uid, out StatusEffectsComponent? statusEffects)) + { + _jitter.DoJitter(uid, ent.Comp.JitterTime, true, status: statusEffects); + _stutter.DoStutter(uid, ent.Comp.StutterTime, true, statusEffects); + } + } + } +} diff --git a/Content.Shared/_White/Item/KnockDownOnHit/KnockDownOnHitSystem.cs b/Content.Shared/_White/Item/KnockDownOnHit/KnockDownOnHitSystem.cs index 891049ae98..912d1867e3 100644 --- a/Content.Shared/_White/Item/KnockDownOnHit/KnockDownOnHitSystem.cs +++ b/Content.Shared/_White/Item/KnockDownOnHit/KnockDownOnHitSystem.cs @@ -26,17 +26,17 @@ public sealed class KnockDownOnHitSystem : EntitySystem if (time <= TimeSpan.Zero) return; + if (ent.Comp.RequireWield) + { + if (!TryComp(args.Weapon, out var weapon)) + return; + + if (!weapon.Wielded) + return; + } + foreach (var uid in args.HitEntities) { - if (ent.Comp.RequireWield) - { - if (!TryComp(args.Weapon, out var weapon)) - continue; - - if (!weapon.Wielded) - continue; - } - _stun.TryKnockdown(uid, time, true, behavior: ent.Comp.KnockDownBehavior); } } diff --git a/Resources/Locale/ru-RU/_Engi/direct-balls-hit.ftl b/Resources/Locale/ru-RU/_Engi/direct-balls-hit.ftl new file mode 100644 index 0000000000..08d01b81a3 --- /dev/null +++ b/Resources/Locale/ru-RU/_Engi/direct-balls-hit.ftl @@ -0,0 +1 @@ +direct-balls-hit = { CAPITALIZE($uid) } получает точный удар в пах! diff --git a/Resources/Prototypes/_White/_Engi/Entities/Objects/Misc/cane.yml b/Resources/Prototypes/_White/_Engi/Entities/Objects/Misc/cane.yml new file mode 100644 index 0000000000..8791b624db --- /dev/null +++ b/Resources/Prototypes/_White/_Engi/Entities/Objects/Misc/cane.yml @@ -0,0 +1,41 @@ +- type: entity + parent: BaseItem + id: OldCane + name: трость старика + description: Изношенная деревянная трость. + components: + - type: Sprite + sprite: Objects/Weapons/Melee/cane.rsi + state: cane + - type: Item + size: Normal + storedRotation: -44 + shape: + - 0,0,0,2 + sprite: Objects/Weapons/Melee/cane.rsi + - type: Appearance + - type: MeleeWeapon + wideAnimationRotation: 45 + damage: + types: + Blunt: 5 + - type: StaminaDamageOnHit + damage: 25 + - type: Wieldable + - type: IncreaseDamageOnWield + damage: + types: + Blunt: 5 + - type: DirectBallsHit + - type: MeleeThrowOnHit + lifetime: 0.1 + speed: 3 + requireWield: true + - type: UseDelay + delay: 1 + - type: Prying + - type: Tool + qualities: + - Prying + useSound: + path: /Audio/Items/crowbar.ogg