From 2491ff281755b03c6c77e24ef409c3f1183570bb Mon Sep 17 00:00:00 2001 From: Spatison <137375981+Spatison@users.noreply.github.com> Date: Wed, 28 Aug 2024 03:18:09 +0300 Subject: [PATCH 1/5] add: grab --- Content.Server/Alert/Click/StopPulling.cs | 2 +- .../Body/Systems/RespiratorSystem.cs | 11 +- Content.Server/Hands/Systems/HandsSystem.cs | 24 +- .../Implants/SubdermalImplantSystem.cs | 2 +- .../Administration/AdminFrozenSystem.cs | 2 +- .../EntitySystems/AnchorableSystem.cs | 2 +- .../SharedHandsSystem.Interactions.cs | 20 +- .../Hands/EntitySystems/SharedHandsSystem.cs | 37 ++ Content.Shared/Hands/HandEvents.cs | 43 +- .../VirtualItem/SharedVirtualItemSystem.cs | 50 +- .../Pulling/Components/PullableComponent.cs | 20 + .../Pulling/Components/PullerComponent.cs | 45 ++ .../Movement/Pulling/Systems/PullingSystem.cs | 523 +++++++++++++++++- .../Systems/DeployableBarrierSystem.cs | 2 +- .../Systems/SharedPortalSystem.cs | 4 +- .../_White/Grab/GrabThrownComponent.cs | 16 + .../_White/Grab/GrabThrownSystem.cs | 102 ++++ Resources/Prototypes/Alerts/alerts.yml | 24 +- .../Interface/Alerts/pull.rsi/grab-choke.png | Bin 0 -> 1038 bytes .../Interface/Alerts/pull.rsi/grab-hard.png | Bin 0 -> 716 bytes .../Interface/Alerts/pull.rsi/grab-soft.png | Bin 0 -> 706 bytes .../Alerts/pull.rsi/grabbed-choke.png | Bin 0 -> 526 bytes .../Alerts/pull.rsi/grabbed-hard.png | Bin 0 -> 367 bytes .../Alerts/pull.rsi/grabbed-soft.png | Bin 0 -> 372 bytes .../Interface/Alerts/pull.rsi/meta.json | 45 ++ .../Interface/Alerts/pull.rsi/pulled.png | Bin 0 -> 696 bytes .../Interface/Alerts/pull.rsi/pulling.png | Bin 0 -> 525 bytes 27 files changed, 939 insertions(+), 35 deletions(-) create mode 100644 Content.Shared/_White/Grab/GrabThrownComponent.cs create mode 100644 Content.Shared/_White/Grab/GrabThrownSystem.cs create mode 100644 Resources/Textures/Interface/Alerts/pull.rsi/grab-choke.png create mode 100644 Resources/Textures/Interface/Alerts/pull.rsi/grab-hard.png create mode 100644 Resources/Textures/Interface/Alerts/pull.rsi/grab-soft.png create mode 100644 Resources/Textures/Interface/Alerts/pull.rsi/grabbed-choke.png create mode 100644 Resources/Textures/Interface/Alerts/pull.rsi/grabbed-hard.png create mode 100644 Resources/Textures/Interface/Alerts/pull.rsi/grabbed-soft.png create mode 100644 Resources/Textures/Interface/Alerts/pull.rsi/meta.json create mode 100644 Resources/Textures/Interface/Alerts/pull.rsi/pulled.png create mode 100644 Resources/Textures/Interface/Alerts/pull.rsi/pulling.png diff --git a/Content.Server/Alert/Click/StopPulling.cs b/Content.Server/Alert/Click/StopPulling.cs index 76f9569429..3941ff6873 100644 --- a/Content.Server/Alert/Click/StopPulling.cs +++ b/Content.Server/Alert/Click/StopPulling.cs @@ -20,7 +20,7 @@ public void AlertClicked(EntityUid player) if (entManager.TryGetComponent(player, out PullerComponent? puller) && entManager.TryGetComponent(puller.Pulling, out PullableComponent? pullableComp)) { - ps.TryStopPull(puller.Pulling.Value, pullableComp, user: player); + ps.TryLowerGrabStage(puller.Pulling.Value, player, true); } } } diff --git a/Content.Server/Body/Systems/RespiratorSystem.cs b/Content.Server/Body/Systems/RespiratorSystem.cs index c7266e2c46..e8b1e4b9e8 100644 --- a/Content.Server/Body/Systems/RespiratorSystem.cs +++ b/Content.Server/Body/Systems/RespiratorSystem.cs @@ -10,6 +10,8 @@ using Content.Shared.Damage; using Content.Shared.Database; using Content.Shared.Mobs.Systems; +using Content.Shared.Movement.Pulling.Components; +using Content.Shared.Movement.Pulling.Systems; using JetBrains.Annotations; using Robust.Shared.Timing; @@ -50,6 +52,13 @@ private void OnUnpaused(Entity ent, ref EntityUnpausedEvent ent.Comp.NextUpdate += args.PausedTime; } + public bool CanBreathe(EntityUid uid) + { + if (TryComp(uid, out var pullable) && pullable.GrabStage == GrabStage.Suffocate) + return false; + return true; + } + public override void Update(float frameTime) { base.Update(frameTime); @@ -82,7 +91,7 @@ public override void Update(float frameTime) } } - if (respirator.Saturation < respirator.SuffocationThreshold) + if (respirator.Saturation < respirator.SuffocationThreshold || !CanBreathe(uid)) { if (_gameTiming.CurTime >= respirator.LastGaspPopupTime + respirator.GaspPopupCooldown) { diff --git a/Content.Server/Hands/Systems/HandsSystem.cs b/Content.Server/Hands/Systems/HandsSystem.cs index bd24ddab5d..ae30b4f980 100644 --- a/Content.Server/Hands/Systems/HandsSystem.cs +++ b/Content.Server/Hands/Systems/HandsSystem.cs @@ -6,6 +6,7 @@ using Content.Shared.Body.Part; using Content.Shared.CombatMode; using Content.Shared.Explosion; +using Content.Shared.Hands; using Content.Shared.Hands.Components; using Content.Shared.Hands.EntitySystems; using Content.Shared.Input; @@ -88,7 +89,7 @@ private void OnDisarmed(EntityUid uid, HandsComponent component, DisarmedEvent a // Break any pulls if (TryComp(uid, out PullerComponent? puller) && TryComp(puller.Pulling, out PullableComponent? pullable)) - _pullingSystem.TryStopPull(puller.Pulling.Value, pullable); + _pullingSystem.TryStopPull(puller.Pulling.Value, pullable, ignoreGrab: true); if (!_handsSystem.TryDrop(uid, component.ActiveHand!, null, checkActionBlocker: false)) return; @@ -168,6 +169,18 @@ private bool HandleThrowItem(ICommonSession? playerSession, EntityCoordinates co if (playerSession?.AttachedEntity is not {Valid: true} player || !Exists(player)) return false; + if (TryGetActiveItem(player, out var item) && TryComp(item, out var virtComp)) + { + var userEv = new VirtualItemDropAttemptEvent(virtComp.BlockingEntity, player, item.Value, true); + RaiseLocalEvent(player, userEv); + + var targEv = new VirtualItemDropAttemptEvent(virtComp.BlockingEntity, player, item.Value, true); + RaiseLocalEvent(virtComp.BlockingEntity, targEv); + + if (userEv.Cancelled || targEv.Cancelled) + return false; + } + return ThrowHeldItem(player, coordinates); } @@ -211,6 +224,15 @@ hands.ActiveHandEntity is not { } throwEnt || var ev = new BeforeThrowEvent(throwEnt, direction, throwStrength, player); RaiseLocalEvent(player, ref ev); + if (TryComp(throwEnt, out var virt)) + { + var userEv = new VirtualItemThrownEvent(virt.BlockingEntity, player, throwEnt, direction); + RaiseLocalEvent(player, userEv); + + var targEv = new VirtualItemThrownEvent(virt.BlockingEntity, player, throwEnt, direction); + RaiseLocalEvent(virt.BlockingEntity, targEv); + } + if (ev.Cancelled) return true; diff --git a/Content.Server/Implants/SubdermalImplantSystem.cs b/Content.Server/Implants/SubdermalImplantSystem.cs index e8af08b2eb..46836814cf 100644 --- a/Content.Server/Implants/SubdermalImplantSystem.cs +++ b/Content.Server/Implants/SubdermalImplantSystem.cs @@ -107,7 +107,7 @@ private void OnScramImplant(EntityUid uid, SubdermalImplantComponent component, // We need stop the user from being pulled so they don't just get "attached" with whoever is pulling them. // This can for example happen when the user is cuffed and being pulled. if (TryComp(ent, out var pull) && _pullingSystem.IsPulled(ent, pull)) - _pullingSystem.TryStopPull(ent, pull); + _pullingSystem.TryStopPull(ent, pull, ignoreGrab: true); var xform = Transform(ent); var targetCoords = SelectRandomTileInRange(xform, implant.TeleportRadius); diff --git a/Content.Shared/Administration/AdminFrozenSystem.cs b/Content.Shared/Administration/AdminFrozenSystem.cs index 4ec9600b0b..30d11ecae9 100644 --- a/Content.Shared/Administration/AdminFrozenSystem.cs +++ b/Content.Shared/Administration/AdminFrozenSystem.cs @@ -44,7 +44,7 @@ private void OnStartup(EntityUid uid, AdminFrozenComponent component, ComponentS { if (TryComp(uid, out var pullable)) { - _pulling.TryStopPull(uid, pullable); + _pulling.TryStopPull(uid, pullable, ignoreGrab: true); } UpdateCanMove(uid, component, args); diff --git a/Content.Shared/Construction/EntitySystems/AnchorableSystem.cs b/Content.Shared/Construction/EntitySystems/AnchorableSystem.cs index c041cf1ba0..0ea3b0eb1f 100644 --- a/Content.Shared/Construction/EntitySystems/AnchorableSystem.cs +++ b/Content.Shared/Construction/EntitySystems/AnchorableSystem.cs @@ -133,7 +133,7 @@ private void OnAnchorComplete(EntityUid uid, AnchorableComponent component, TryA if (TryComp(uid, out var pullable) && pullable.Puller != null) { - _pulling.TryStopPull(uid, pullable); + _pulling.TryStopPull(uid, pullable, ignoreGrab: true); } // TODO: Anchoring snaps rn anyway! diff --git a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Interactions.cs b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Interactions.cs index 32339eb03a..a30c5ea496 100644 --- a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Interactions.cs +++ b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Interactions.cs @@ -95,7 +95,25 @@ private void SwapHandsPressed(ICommonSession? session) private bool DropPressed(ICommonSession? session, EntityCoordinates coords, EntityUid netEntity) { if (TryComp(session?.AttachedEntity, out HandsComponent? hands) && hands.ActiveHand != null) - TryDrop(session.AttachedEntity.Value, hands.ActiveHand, coords, handsComp: hands); + { + if (session != null) + { + var ent = session.AttachedEntity.Value; + + if (TryGetActiveItem(ent, out var item) && TryComp(item, out var virtComp)) + { + var userEv = new VirtualItemDropAttemptEvent(virtComp.BlockingEntity, ent, item.Value, false); + RaiseLocalEvent(ent, userEv); + + var targEv = new VirtualItemDropAttemptEvent(virtComp.BlockingEntity, ent, item.Value, false); + RaiseLocalEvent(virtComp.BlockingEntity, targEv); + + if (userEv.Cancelled || targEv.Cancelled) + return false; + } + TryDrop(ent, hands.ActiveHand, coords, handsComp: hands); + } + } // always send to server. return false; diff --git a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.cs b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.cs index b72a7c4eb3..4f64714aab 100644 --- a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.cs +++ b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.cs @@ -137,6 +137,43 @@ public bool TryGetEmptyHand(EntityUid uid, [NotNullWhen(true)] out Hand? emptyHa return false; } + public bool TryGetActiveHand(Entity entity, [NotNullWhen(true)] out Hand? hand) + { + if (!Resolve(entity, ref entity.Comp, false)) + { + hand = null; + return false; + } + + hand = entity.Comp.ActiveHand; + return hand != null; + } + + public bool TryGetActiveItem(Entity entity, [NotNullWhen(true)] out EntityUid? item) + { + if (!TryGetActiveHand(entity, out var hand)) + { + item = null; + return false; + } + + item = hand.HeldEntity; + return item != null; + } + + public Hand? GetActiveHand(Entity entity) + { + if (!Resolve(entity, ref entity.Comp)) + return null; + + return entity.Comp.ActiveHand; + } + + public EntityUid? GetActiveItem(Entity entity) + { + return GetActiveHand(entity)?.HeldEntity; + } + /// /// Enumerate over hands, starting with the currently active hand. /// diff --git a/Content.Shared/Hands/HandEvents.cs b/Content.Shared/Hands/HandEvents.cs index 0499c05f42..f900d92acd 100644 --- a/Content.Shared/Hands/HandEvents.cs +++ b/Content.Shared/Hands/HandEvents.cs @@ -148,11 +148,52 @@ public sealed class VirtualItemDeletedEvent : EntityEventArgs { public EntityUid BlockingEntity; public EntityUid User; + public EntityUid VirtualItem; - public VirtualItemDeletedEvent(EntityUid blockingEntity, EntityUid user) + public VirtualItemDeletedEvent(EntityUid blockingEntity, EntityUid user, EntityUid virtualItem) { BlockingEntity = blockingEntity; User = user; + VirtualItem = virtualItem; + } + } + + /// + /// Raised directed on both the blocking entity and user when + /// a virtual hand item is thrown (at least attempted to). + /// + public sealed class VirtualItemThrownEvent : EntityEventArgs + { + public EntityUid BlockingEntity; + public EntityUid User; + public EntityUid VirtualItem; + public Vector2 Direction; + public VirtualItemThrownEvent(EntityUid blockingEntity, EntityUid user, EntityUid virtualItem, Vector2 direction) + { + BlockingEntity = blockingEntity; + User = user; + VirtualItem = virtualItem; + Direction = direction; + } + } + + /// + /// Raised directed on both the blocking entity and user when + /// user tries to drop it by keybind. + /// Cancellable. + /// + public sealed class VirtualItemDropAttemptEvent : CancellableEntityEventArgs + { + public EntityUid BlockingEntity; + public EntityUid User; + public EntityUid VirtualItem; + public bool Throw; + public VirtualItemDropAttemptEvent(EntityUid blockingEntity, EntityUid user, EntityUid virtualItem, bool thrown) + { + BlockingEntity = blockingEntity; + User = user; + VirtualItem = virtualItem; + Throw = thrown; } } diff --git a/Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs b/Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs index e45530e458..b13900e2ea 100644 --- a/Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs +++ b/Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs @@ -1,9 +1,11 @@ using System.Diagnostics.CodeAnalysis; using Content.Shared.Hands; +using Content.Shared.Hands.Components; using Content.Shared.Hands.EntitySystems; using Content.Shared.Interaction; using Content.Shared.Inventory.Events; using Content.Shared.Item; +using Content.Shared.Popups; using Robust.Shared.Containers; using Robust.Shared.Network; using Robust.Shared.Prototypes; @@ -29,6 +31,7 @@ public abstract class SharedVirtualItemSystem : EntitySystem [Dependency] private readonly SharedItemSystem _itemSystem = default!; [Dependency] private readonly InventorySystem _inventorySystem = default!; [Dependency] private readonly SharedHandsSystem _handsSystem = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; [ValidatePrototypeId] private const string VirtualItem = "VirtualItem"; @@ -76,18 +79,49 @@ private void OnBeforeRangedInteract(Entity ent, ref Before /// /// The entity we will make a virtual entity copy of /// The entity that we want to insert the virtual entity - public bool TrySpawnVirtualItemInHand(EntityUid blockingEnt, EntityUid user) + public bool TrySpawnVirtualItemInHand(EntityUid blockingEnt, EntityUid user, bool dropOthers = false) { - return TrySpawnVirtualItemInHand(blockingEnt, user, out _); + return TrySpawnVirtualItemInHand(blockingEnt, user, out _, dropOthers); } /// - public bool TrySpawnVirtualItemInHand(EntityUid blockingEnt, EntityUid user, [NotNullWhen(true)] out EntityUid? virtualItem) + public bool TrySpawnVirtualItemInHand(EntityUid blockingEnt, EntityUid user, [NotNullWhen(true)] out EntityUid? virtualItem, bool dropOthers = false, Hand? empty = null) { - if (!TrySpawnVirtualItem(blockingEnt, user, out virtualItem) || !_handsSystem.TryGetEmptyHand(user, out var hand)) + virtualItem = null; + if (empty == null && !_handsSystem.TryGetEmptyHand(user, out empty)) + { + if (!dropOthers) + return false; + + foreach (var hand in _handsSystem.EnumerateHands(user)) + { + if (hand.HeldEntity is not { } held) + continue; + + if (held == blockingEnt) + continue; + + if (HasComp(held)) + continue; + + if (!_handsSystem.TryDrop(user, hand)) + continue; + + if (!TerminatingOrDeleted(held)) + _popup.PopupClient(Loc.GetString("virtual-item-dropped-other", ("dropped", held)), user, user); + + empty = hand; + break; + } + } + + if (empty == null) + return false; + + if (!TrySpawnVirtualItem(blockingEnt, user, out virtualItem)) return false; - _handsSystem.DoPickup(user, hand, virtualItem.Value); + _handsSystem.DoPickup(user, empty, virtualItem.Value); return true; } @@ -188,7 +222,7 @@ public bool TrySpawnVirtualItem(EntityUid blockingEnt, EntityUid user, [NotNullW var pos = Transform(user).Coordinates; virtualItem = Spawn(VirtualItem, pos); - var virtualItemComp = Comp(virtualItem.Value); + var virtualItemComp = EnsureComp(virtualItem.Value); virtualItemComp.BlockingEntity = blockingEnt; Dirty(virtualItem.Value, virtualItemComp); return true; @@ -199,10 +233,10 @@ public bool TrySpawnVirtualItem(EntityUid blockingEnt, EntityUid user, [NotNullW /// public void DeleteVirtualItem(Entity item, EntityUid user) { - var userEv = new VirtualItemDeletedEvent(item.Comp.BlockingEntity, user); + var userEv = new VirtualItemDeletedEvent(item.Comp.BlockingEntity, user, item.Owner); RaiseLocalEvent(user, userEv); - var targEv = new VirtualItemDeletedEvent(item.Comp.BlockingEntity, user); + var targEv = new VirtualItemDeletedEvent(item.Comp.BlockingEntity, user, item.Owner); RaiseLocalEvent(item.Comp.BlockingEntity, targEv); if (TerminatingOrDeleted(item)) diff --git a/Content.Shared/Movement/Pulling/Components/PullableComponent.cs b/Content.Shared/Movement/Pulling/Components/PullableComponent.cs index db889e7e3b..75c6bd2067 100644 --- a/Content.Shared/Movement/Pulling/Components/PullableComponent.cs +++ b/Content.Shared/Movement/Pulling/Components/PullableComponent.cs @@ -1,3 +1,4 @@ +using Content.Shared.Movement.Pulling.Systems; using Robust.Shared.GameStates; namespace Content.Shared.Movement.Pulling.Components; @@ -36,4 +37,23 @@ public sealed partial class PullableComponent : Component [Access(typeof(Systems.PullingSystem), Other = AccessPermissions.ReadExecute)] [AutoNetworkedField, DataField] public bool PrevFixedRotation; + + + [DataField] + public Dictionary PulledAlertAlertSeverity = new() + { + { GrabStage.No, 0 }, + { GrabStage.Soft, 1 }, + { GrabStage.Hard, 2 }, + { GrabStage.Suffocate, 3 }, + }; + + [AutoNetworkedField, DataField] + public GrabStage GrabStage = GrabStage.No; + + [AutoNetworkedField, DataField] + public float GrabEscapeChance = 1f; + + [AutoNetworkedField] + public TimeSpan NextEscapeAttempt = TimeSpan.Zero; } diff --git a/Content.Shared/Movement/Pulling/Components/PullerComponent.cs b/Content.Shared/Movement/Pulling/Components/PullerComponent.cs index 1fc9b731bd..db6d289ea4 100644 --- a/Content.Shared/Movement/Pulling/Components/PullerComponent.cs +++ b/Content.Shared/Movement/Pulling/Components/PullerComponent.cs @@ -38,4 +38,49 @@ public sealed partial class PullerComponent : Component /// [DataField] public bool NeedsHands = true; + + [DataField] + public Dictionary PullingAlertSeverity = new() + { + { GrabStage.No, 0 }, + { GrabStage.Soft, 1 }, + { GrabStage.Hard, 2 }, + { GrabStage.Suffocate, 3 }, + }; + + [DataField, AutoNetworkedField] + public GrabStage GrabStage = GrabStage.No; + + [DataField, AutoNetworkedField] + public GrubStageDirection GrabStageDirection = GrubStageDirection.Increase; + + [AutoNetworkedField] + public TimeSpan NextStageChange; + + [DataField] + public TimeSpan StageChangeCooldown = TimeSpan.FromSeconds(1.5f); + + [DataField] + public Dictionary EscapeChances = new() + { + { GrabStage.No, 1f }, + { GrabStage.Soft, 0.7f }, + { GrabStage.Hard, 0.4f }, + { GrabStage.Suffocate, 0.1f }, + }; + + [DataField] + public float SuffocateGrabStaminaDamage = 10f; + + [DataField] + public float GrabThrowDamageModifier = 1f; + + [ViewVariables] + public List GrabVirtualItems = new(); + + [ViewVariables] + public Dictionary GrabVirtualItemStageCount = new() + { + { GrabStage.Suffocate, 1 }, + }; } diff --git a/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs b/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs index 3c265d5a02..ed53281652 100644 --- a/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs +++ b/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs @@ -1,28 +1,43 @@ using System.Numerics; +using Content.Shared._White.Grab; using Content.Shared.ActionBlocker; using Content.Shared.Administration.Logs; using Content.Shared.Alert; using Content.Shared.Buckle.Components; +using Content.Shared.CombatMode; +using Content.Shared.Damage; +using Content.Shared.Damage.Systems; using Content.Shared.Database; +using Content.Shared.Effects; using Content.Shared.Hands; using Content.Shared.Hands.EntitySystems; +using Content.Shared.IdentityManagement; using Content.Shared.Input; using Content.Shared.Interaction; +using Content.Shared.Inventory.VirtualItem; +using Content.Shared.Item; +using Content.Shared.Mobs.Components; using Content.Shared.Movement.Events; using Content.Shared.Movement.Pulling.Components; using Content.Shared.Movement.Pulling.Events; using Content.Shared.Movement.Systems; +using Content.Shared.Popups; using Content.Shared.Pulling.Events; +using Content.Shared.Speech; using Content.Shared.Throwing; using Content.Shared.Verbs; +using Robust.Shared.Audio; +using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; using Robust.Shared.Input.Binding; using Robust.Shared.Map; +using Robust.Shared.Network; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Events; using Robust.Shared.Physics.Systems; using Robust.Shared.Player; +using Robust.Shared.Random; using Robust.Shared.Timing; namespace Content.Shared.Movement.Pulling.Systems; @@ -44,6 +59,16 @@ public sealed class PullingSystem : EntitySystem [Dependency] private readonly SharedPhysicsSystem _physics = default!; [Dependency] private readonly SharedTransformSystem _xformSys = default!; [Dependency] private readonly ThrowingSystem _throwing = default!; + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly StaminaSystem _stamina = default!; + [Dependency] private readonly SharedColorFlashEffectSystem _color = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly INetManager _netManager = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly SharedVirtualItemSystem _virtualSystem = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly GrabThrownSystem _grabThrown = default!; + [Dependency] private readonly SharedCombatModeSystem _combatMode = default!; public override void Initialize() { @@ -57,11 +82,15 @@ public override void Initialize() SubscribeLocalEvent(OnJointRemoved); SubscribeLocalEvent>(AddPullVerbs); SubscribeLocalEvent(OnPullableContainerInsert); + SubscribeLocalEvent(OnGrabbedMoveAttempt); + SubscribeLocalEvent(OnGrabbedSpeakAttempt); SubscribeLocalEvent(OnPullerContainerInsert); SubscribeLocalEvent(OnPullerUnpaused); SubscribeLocalEvent(OnVirtualItemDeleted); SubscribeLocalEvent(OnRefreshMovespeed); + SubscribeLocalEvent(OnVirtualItemThrown); + SubscribeLocalEvent(OnVirtualItemDropAttempt); CommandBinds.Builder .Bind(ContentKeyFunctions.MovePulledObject, new PointerInputCmdHandler(OnRequestMovePulledObject)) @@ -76,12 +105,17 @@ private void OnPullerContainerInsert(Entity ent, ref EntGotInse if (!TryComp(ent.Comp.Pulling.Value, out PullableComponent? pulling)) return; - TryStopPull(ent.Comp.Pulling.Value, pulling, ent.Owner); + foreach (var item in ent.Comp.GrabVirtualItems) + { + QueueDel(item); + } + + TryStopPull(ent.Comp.Pulling.Value, pulling, ent.Owner, true); } private void OnPullableContainerInsert(Entity ent, ref EntGotInsertedIntoContainerMessage args) { - TryStopPull(ent.Owner, ent.Comp); + TryStopPull(ent.Owner, ent.Comp, ignoreGrab: true); } public override void Shutdown() @@ -95,6 +129,41 @@ private void OnPullerUnpaused(EntityUid uid, PullerComponent component, ref Enti component.NextThrow += args.PausedTime; } + private void OnVirtualItemDropAttempt(EntityUid uid, PullerComponent component, VirtualItemDropAttemptEvent args) + { + if (component.Pulling == null) + return; + + if (component.Pulling != args.BlockingEntity) + return; + + if (_timing.CurTime < component.NextStageChange) + { + args.Cancel(); // VirtualItem is NOT being deleted + return; + } + + if (!args.Throw) + { + if (component.GrabStage > GrabStage.No) + { + if (EntityManager.TryGetComponent(args.BlockingEntity, out PullableComponent? comp)) + { + TryLowerGrabStage(component.Pulling.Value, uid); + args.Cancel(); // VirtualItem is NOT being deleted + } + } + } + else + { + if (component.GrabStage <= GrabStage.Soft) + { + TryLowerGrabStage(component.Pulling.Value, uid); + args.Cancel(); // VirtualItem is NOT being deleted + } + } + } + private void OnVirtualItemDeleted(EntityUid uid, PullerComponent component, VirtualItemDeletedEvent args) { // If client deletes the virtual hand then stop the pull. @@ -106,7 +175,66 @@ private void OnVirtualItemDeleted(EntityUid uid, PullerComponent component, Virt if (EntityManager.TryGetComponent(args.BlockingEntity, out PullableComponent? comp)) { - TryStopPull(args.BlockingEntity, comp, uid); + TryLowerGrabStage(component.Pulling.Value, uid); + } + } + + private void OnVirtualItemThrown(EntityUid uid, PullerComponent component, VirtualItemThrownEvent args) + { + if (component.Pulling == null) + return; + + if (component.Pulling != args.BlockingEntity) + return; + + if (EntityManager.TryGetComponent(args.BlockingEntity, out PullableComponent? comp)) + { + if (_combatMode.IsInCombatMode(uid) && + !HasComp(args.BlockingEntity) && + component.GrabStage > GrabStage.Soft) + { + var direction = args.Direction; + var vecBetween = (Transform(args.BlockingEntity).Coordinates.ToMapPos(EntityManager, _transform) - Transform(uid).WorldPosition); + + // Getting angle between us + var dirAngle = direction.ToWorldAngle().Degrees; + var betweenAngle = vecBetween.ToWorldAngle().Degrees; + + var angle = dirAngle - betweenAngle; + + if (angle < 0) + angle = -angle; + + var maxDistance = 3f; + var damageModifier = 1f; + + if (angle < 30) + { + damageModifier = 0.3f; + maxDistance = 1f; + } + else if (angle < 90) + { + damageModifier = 0.7f; + maxDistance = 1.5f; + } + else + maxDistance = 2.25f; + + var distance = Math.Clamp(args.Direction.Length(), 0.5f, maxDistance); + direction *= distance / args.Direction.Length(); + + + var damage = new DamageSpecifier(); + damage.DamageDict.Add("Blunt", 5); + damage *= damageModifier; + + TryStopPull(args.BlockingEntity, comp, uid, true); + _grabThrown.Throw(args.BlockingEntity, uid, direction * 2f, 120f, damage * component.GrabThrowDamageModifier, damage * component.GrabThrowDamageModifier); + _throwing.TryThrow(uid, -direction * 0.5f); + _audio.PlayPvs(new SoundPathSpecifier("/Audio/Effects/thudswoosh.ogg"), uid); + component.NextStageChange.Add(TimeSpan.FromSeconds(2f)); // To avoid grab and throw spamming + } } } @@ -144,7 +272,49 @@ private void AddPullVerbs(EntityUid uid, PullableComponent component, GetVerbsEv private void OnRefreshMovespeed(EntityUid uid, PullerComponent component, RefreshMovementSpeedModifiersEvent args) { - args.ModifySpeed(component.WalkSpeedModifier, component.SprintSpeedModifier); + if (TryComp(component.Pulling, out var heldMoveSpeed) && component.Pulling.HasValue) + { + var (walkMod, sprintMod) = (args.WalkSpeedModifier, args.SprintSpeedModifier); + + switch (component.GrabStage) + { + case GrabStage.No: + args.ModifySpeed(walkMod, sprintMod); + break; + case GrabStage.Soft: + args.ModifySpeed(walkMod * 0.9f, sprintMod * 0.9f); + break; + case GrabStage.Hard: + args.ModifySpeed(walkMod * 0.7f, sprintMod * 0.7f); + break; + case GrabStage.Suffocate: + args.ModifySpeed(walkMod * 0.4f, sprintMod * 0.4f); + break; + default: + args.ModifySpeed(walkMod, sprintMod); + break; + } + return; + } + + switch (component.GrabStage) + { + case GrabStage.No: + args.ModifySpeed(component.WalkSpeedModifier, component.SprintSpeedModifier); + break; + case GrabStage.Soft: + args.ModifySpeed(component.WalkSpeedModifier * 0.9f, component.SprintSpeedModifier * 0.9f); + break; + case GrabStage.Hard: + args.ModifySpeed(component.WalkSpeedModifier * 0.7f, component.SprintSpeedModifier * 0.7f); + break; + case GrabStage.Suffocate: + args.ModifySpeed(component.WalkSpeedModifier * 0.4f, component.SprintSpeedModifier * 0.4f); + break; + default: + args.ModifySpeed(component.WalkSpeedModifier, component.SprintSpeedModifier); + break; + } } private void OnPullableMoveInput(EntityUid uid, PullableComponent component, ref MoveInputEvent args) @@ -204,6 +374,10 @@ private void StopPulling(EntityUid pullableUid, PullableComponent pullableComp) var oldPuller = pullableComp.Puller; pullableComp.PullJointId = null; pullableComp.Puller = null; + pullableComp.GrabStage = GrabStage.No; + pullableComp.GrabEscapeChance = 1f; + _blocker.UpdateCanMove(pullableUid); + Dirty(pullableUid, pullableComp); // No more joints with puller -> force stop pull. @@ -212,6 +386,15 @@ private void StopPulling(EntityUid pullableUid, PullableComponent pullableComp) var pullerUid = oldPuller.Value; _alertsSystem.ClearAlert(pullerUid, AlertType.Pulling); pullerComp.Pulling = null; + + pullerComp.GrabStage = GrabStage.No; + List virtItems = pullerComp.GrabVirtualItems; + foreach (var item in virtItems) + { + QueueDel(item); + } + pullerComp.GrabVirtualItems.Clear(); + Dirty(oldPuller.Value, pullerComp); // Messaging @@ -291,7 +474,7 @@ private void OnReleasePulledObject(ICommonSession? session) return; } - TryStopPull(pullerComp.Pulling.Value, pullableComp, user: player); + TryStopPull(pullerComp.Pulling.Value, pullableComp, user: player, true); } public bool CanPull(EntityUid puller, EntityUid pullableUid, PullerComponent? pullerComp = null) @@ -351,12 +534,16 @@ public bool CanPull(EntityUid puller, EntityUid pullableUid, PullerComponent? pu public bool TogglePull(EntityUid pullableUid, EntityUid pullerUid, PullableComponent pullable) { - if (pullable.Puller == pullerUid) - { - return TryStopPull(pullableUid, pullable); - } + if (pullable.Puller != pullerUid) + return TryStartPull(pullerUid, pullableUid, pullableComp: pullable); - return TryStartPull(pullerUid, pullableUid, pullableComp: pullable); + if (TryGrab((pullableUid, pullable), pullerUid)) + return true; + + if (!_combatMode.IsInCombatMode(pullableUid)) + return TryStopPull(pullableUid, pullable, ignoreGrab: true); + + return false; } public bool TogglePull(EntityUid pullerUid, PullerComponent puller) @@ -390,7 +577,7 @@ public bool TryStartPull(EntityUid pullerUid, EntityUid pullableUid, // Ensure that the puller is not currently pulling anything. if (TryComp(pullerComp.Pulling, out var oldPullable) - && !TryStopPull(pullerComp.Pulling.Value, oldPullable, pullerUid)) + && !TryStopPull(pullerComp.Pulling.Value, oldPullable, pullerUid, true)) return false; // Stop anyone else pulling the entity we want to pull @@ -401,7 +588,37 @@ public bool TryStartPull(EntityUid pullerUid, EntityUid pullableUid, return false; if (!TryStopPull(pullableUid, pullableComp, pullableComp.Puller)) + { + // Not succeed to retake grabbed entity + if (_netManager.IsServer) + { + _popup.PopupEntity(Loc.GetString("popup-grab-retake-fail", + ("puller", Identity.Entity(pullableComp.Puller.Value, EntityManager)), + ("pulled", Identity.Entity(pullableUid, EntityManager))), + pullerUid, pullerUid, PopupType.MediumCaution); + _popup.PopupEntity(Loc.GetString("popup-grab-retake-fail-puller", + ("puller", Identity.Entity(pullerUid, EntityManager)), + ("pulled", Identity.Entity(pullableUid, EntityManager))), + pullableComp.Puller.Value, pullableComp.Puller.Value, PopupType.MediumCaution); + } return false; + } + + else if (pullableComp.GrabStage != GrabStage.No) + { + // Successful retake + if (_netManager.IsServer) + { + _popup.PopupEntity(Loc.GetString("popup-grab-retake-success", + ("puller", Identity.Entity(pullableComp.Puller.Value, EntityManager)), + ("pulled", Identity.Entity(pullableUid, EntityManager))), + pullerUid, pullerUid, PopupType.MediumCaution); + _popup.PopupEntity(Loc.GetString("popup-grab-retake-success-puller", + ("puller", Identity.Entity(pullerUid, EntityManager)), + ("pulled", Identity.Entity(pullableUid, EntityManager))), + pullableComp.Puller.Value, pullableComp.Puller.Value, PopupType.MediumCaution); + } + } } var pullAttempt = new PullAttemptEvent(pullerUid, pullableUid); @@ -447,8 +664,8 @@ public bool TryStartPull(EntityUid pullerUid, EntityUid pullableUid, // Messaging var message = new PullStartedMessage(pullerUid, pullableUid); - _alertsSystem.ShowAlert(pullerUid, AlertType.Pulling); - _alertsSystem.ShowAlert(pullableUid, AlertType.Pulled); + _alertsSystem.ShowAlert(pullerUid, AlertType.Pulling, 0); + _alertsSystem.ShowAlert(pullableUid, AlertType.Pulled, 0); RaiseLocalEvent(pullerUid, message); RaiseLocalEvent(pullableUid, message); @@ -458,10 +675,14 @@ public bool TryStartPull(EntityUid pullerUid, EntityUid pullableUid, _adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(pullerUid):user} started pulling {ToPrettyString(pullableUid):target}"); + + if (_combatMode.IsInCombatMode(pullerUid)) + TryGrab(pullableUid, pullerUid); + return true; } - public bool TryStopPull(EntityUid pullableUid, PullableComponent pullable, EntityUid? user = null) + public bool TryStopPull(EntityUid pullableUid, PullableComponent pullable, EntityUid? user = null, bool ignoreGrab = false) { var pullerUidNull = pullable.Puller; @@ -474,6 +695,23 @@ public bool TryStopPull(EntityUid pullableUid, PullableComponent pullable, Entit if (msg.Cancelled) return false; + // There are some events that should ignore grab stages + if (!ignoreGrab) + { + if (!AttemptGrabRelease(pullableUid)) + { + if (_netManager.IsServer && user != null && user.Value == pullableUid) + _popup.PopupEntity(Loc.GetString("popup-grab-release-fail-self"), pullableUid, pullableUid, PopupType.SmallCaution); + return false; + } + + if (_netManager.IsServer && user != null && user.Value == pullableUid) + { + _popup.PopupEntity(Loc.GetString("popup-grab-release-success-self"), pullableUid, pullableUid, PopupType.SmallCaution); + _popup.PopupEntity(Loc.GetString("popup-grab-release-success-puller", ("target", Identity.Entity(pullableUid, EntityManager))), pullerUidNull.Value, pullerUidNull.Value, PopupType.MediumCaution); + } + } + // Stop pulling confirmed! if (!_timing.ApplyingState) { @@ -488,4 +726,261 @@ public bool TryStopPull(EntityUid pullableUid, PullableComponent pullable, Entit StopPulling(pullableUid, pullable); return true; } + + /// + /// Trying to grab the target + /// + /// Target that would be grabbed + /// Performer of the grab + /// If true, will ignore disabled combat mode + /// + /// + public bool TryGrab(Entity pullable, Entity puller, bool ignoreCombatMode = false) + { + if (!Resolve(pullable.Owner, ref pullable.Comp)) + return false; + + if (!Resolve(puller.Owner, ref puller.Comp)) + return false; + + if (pullable.Comp.Puller != puller.Owner || + puller.Comp.Pulling != pullable.Owner) + return false; + + if (puller.Comp.NextStageChange > _timing.CurTime) + return true; + + // You can't choke crates + if (!HasComp(pullable)) + return false; + + // Delay to avoid spamming + puller.Comp.NextStageChange = _timing.CurTime + puller.Comp.StageChangeCooldown; + Dirty(puller); + + // Don't grab without grab intent + if (!ignoreCombatMode) + { + if (!_combatMode.IsInCombatMode(puller.Owner)) + return false; + } + + // It's blocking stage update, maybe better UX? + if (puller.Comp.GrabStage == GrabStage.Suffocate) + { + _stamina.TakeStaminaDamage(pullable, puller.Comp.SuffocateGrabStaminaDamage); + + Dirty(pullable); + Dirty(puller); + return true; + } + + // Update stage + // TODO: Change grab stage direction + var nextStageAddition = puller.Comp.GrabStageDirection switch + { + GrubStageDirection.Increase => 1, + GrubStageDirection.Decrease => -1, + _ => throw new ArgumentOutOfRangeException(), + }; + + var newStage = puller.Comp.GrabStage + nextStageAddition; + + if (!TrySetGrabStages((puller.Owner, puller.Comp), (pullable.Owner, pullable.Comp), newStage)) + return false; + + _color.RaiseEffect(Color.Yellow, new List { pullable }, Filter.Pvs(pullable, entityManager: EntityManager)); + return true; + } + + private bool TrySetGrabStages(Entity puller, Entity pullable, GrabStage stage) + { + puller.Comp.GrabStage = stage; + pullable.Comp.GrabStage = stage; + + if (!TryUpdateGrabVirtualItems(puller, pullable)) + return false; + + var filter = Filter.Empty() + .AddPlayersByPvs(Transform(puller)) + .RemovePlayerByAttachedEntity(puller.Owner) + .RemovePlayerByAttachedEntity(pullable.Owner); + + var popupType = stage switch + { + GrabStage.No => PopupType.Small, + GrabStage.Soft => PopupType.Small, + GrabStage.Hard => PopupType.MediumCaution, + GrabStage.Suffocate => PopupType.LargeCaution, + _ => throw new ArgumentOutOfRangeException() + }; + + pullable.Comp.GrabEscapeChance = puller.Comp.EscapeChances[stage]; + + _alertsSystem.ShowAlert(puller, AlertType.Pulling, puller.Comp.PullingAlertSeverity[stage]); + _alertsSystem.ShowAlert(pullable, AlertType.Pulled, pullable.Comp.PulledAlertAlertSeverity[stage]); + + _blocker.UpdateCanMove(pullable); + _modifierSystem.RefreshMovementSpeedModifiers(puller); + + // I'm lazy to write client code + if (!_netManager.IsServer) + return true; + + _popup.PopupEntity(Loc.GetString($"popup-grab-{puller.Comp.GrabStage.ToString().ToLower()}-target", ("puller", Identity.Entity(puller, EntityManager))), pullable, pullable, popupType); + _popup.PopupEntity(Loc.GetString($"popup-grab-{puller.Comp.GrabStage.ToString().ToLower()}-self", ("target", Identity.Entity(pullable, EntityManager))), pullable, puller, PopupType.Medium); + _popup.PopupEntity(Loc.GetString($"popup-grab-{puller.Comp.GrabStage.ToString().ToLower()}-others", ("target", Identity.Entity(pullable, EntityManager)), ("puller", Identity.Entity(puller, EntityManager))), pullable, filter, true, popupType); + + _audio.PlayPvs(new SoundPathSpecifier("/Audio/Effects/thudswoosh.ogg"), pullable); + + Dirty(pullable); + Dirty(puller); + + return true; + } + + private bool TryUpdateGrabVirtualItems(Entity puller, Entity pullable) + { + // Updating virtual items + var virtualItemsCount = puller.Comp.GrabVirtualItems.Count; + + var newVirtualItemsCount = puller.Comp.NeedsHands ? 0 : 1; + if (puller.Comp.GrabVirtualItemStageCount.TryGetValue(puller.Comp.GrabStage, out var count)) + newVirtualItemsCount += count; + + if (virtualItemsCount != newVirtualItemsCount) + { + var delta = newVirtualItemsCount - virtualItemsCount; + + // Adding new virtual items + if (delta > 0) + { + for (var i = 0; i < delta; i++) + { + if (!_virtualSystem.TrySpawnVirtualItemInHand(pullable, puller.Owner, out var item, true)) + { + // I'm lazy write client code + if (_netManager.IsServer) + _popup.PopupEntity(Loc.GetString("popup-grab-need-hand"), puller, puller, PopupType.Medium); + + return false; + } + + puller.Comp.GrabVirtualItems.Add(item.Value); + } + } + + if (delta < 0) + { + for (var i = 0; i < Math.Abs(delta); i++) + { + if (i >= puller.Comp.GrabVirtualItems.Count) + break; + + var item = puller.Comp.GrabVirtualItems[i]; + puller.Comp.GrabVirtualItems.Remove(item); + QueueDel(item); + } + } + } + + return true; + } + + /// + /// Attempts to release entity from grab + /// + /// Grabbed entity + /// + public bool AttemptGrabRelease(Entity pullable) + { + if (!Resolve(pullable.Owner, ref pullable.Comp)) + return false; + if (_timing.CurTime < pullable.Comp.NextEscapeAttempt) // No autoclickers! Mwa-ha-ha + { + return false; + } + + if (_random.Prob(pullable.Comp.GrabEscapeChance)) + return true; + + pullable.Comp.NextEscapeAttempt = _timing.CurTime.Add(TimeSpan.FromSeconds(1)); + Dirty(pullable.Owner, pullable.Comp); + return false; + } + + private void OnGrabbedMoveAttempt(EntityUid uid, PullableComponent component, UpdateCanMoveEvent args) + { + if (component.GrabStage == GrabStage.No) + return; + + args.Cancel(); + + } + + private void OnGrabbedSpeakAttempt(EntityUid uid, PullableComponent component, SpeakAttemptEvent args) + { + if (component.GrabStage != GrabStage.Suffocate) + return; + + _popup.PopupEntity(Loc.GetString("popup-grabbed-cant-speak"), uid, uid, PopupType.MediumCaution); // You cant speak while someone is choking you + + args.Cancel(); + } + + /// + /// Tries to lower grab stage for target or release it + /// + /// Grabbed entity + /// Performer + /// If true, will NOT release target if combat mode is off + /// + public bool TryLowerGrabStage(Entity pullable, Entity puller, bool ignoreCombatMode = false) + { + if (!Resolve(pullable.Owner, ref pullable.Comp)) + return false; + + if (!Resolve(puller.Owner, ref puller.Comp)) + return false; + + if (pullable.Comp.Puller != puller.Owner || + puller.Comp.Pulling != pullable.Owner) + return false; + + if (_timing.CurTime < puller.Comp.NextStageChange) + return true; + + pullable.Comp.NextEscapeAttempt = _timing.CurTime.Add(TimeSpan.FromSeconds(1f)); + Dirty(pullable); + + if (!ignoreCombatMode && _combatMode.IsInCombatMode(puller.Owner)) + { + TryStopPull(pullable, pullable.Comp, ignoreGrab: true); + return true; + } + + if (puller.Comp.GrabStage == GrabStage.No) + { + TryStopPull(pullable, pullable.Comp, ignoreGrab: true); + return true; + } + + var newStage = puller.Comp.GrabStage - 1; + TrySetGrabStages((puller.Owner, puller.Comp), (pullable.Owner, pullable.Comp), newStage); + return true; + } +} + +public enum GrabStage +{ + No = 0, + Soft = 1, + Hard = 2, + Suffocate = 3, +} + +public enum GrubStageDirection +{ + Increase, + Decrease, } diff --git a/Content.Shared/Security/Systems/DeployableBarrierSystem.cs b/Content.Shared/Security/Systems/DeployableBarrierSystem.cs index 622edc4b62..5f4493d69f 100644 --- a/Content.Shared/Security/Systems/DeployableBarrierSystem.cs +++ b/Content.Shared/Security/Systems/DeployableBarrierSystem.cs @@ -55,7 +55,7 @@ private void ToggleBarrierDeploy(EntityUid uid, bool isDeployed, DeployableBarri } if (TryComp(uid, out PullableComponent? pullable)) - _pulling.TryStopPull(uid, pullable); + _pulling.TryStopPull(uid, pullable, ignoreGrab: true); SharedPointLightComponent? pointLight = null; if (_pointLight.ResolveLight(uid, ref pointLight)) diff --git a/Content.Shared/Teleportation/Systems/SharedPortalSystem.cs b/Content.Shared/Teleportation/Systems/SharedPortalSystem.cs index 8d67aec518..dae42f9a4b 100644 --- a/Content.Shared/Teleportation/Systems/SharedPortalSystem.cs +++ b/Content.Shared/Teleportation/Systems/SharedPortalSystem.cs @@ -95,13 +95,13 @@ private void OnCollide(EntityUid uid, PortalComponent component, ref StartCollid // break pulls before portal enter so we dont break shit if (TryComp(subject, out var pullable) && pullable.BeingPulled) { - _pulling.TryStopPull(subject, pullable); + _pulling.TryStopPull(subject, pullable, ignoreGrab: true); } if (TryComp(subject, out var pullerComp) && TryComp(pullerComp.Pulling, out var subjectPulling)) { - _pulling.TryStopPull(subject, subjectPulling); + _pulling.TryStopPull(subject, subjectPulling, ignoreGrab: true); } // if they came from another portal, just return and wait for them to exit the portal diff --git a/Content.Shared/_White/Grab/GrabThrownComponent.cs b/Content.Shared/_White/Grab/GrabThrownComponent.cs new file mode 100644 index 0000000000..a7eadf7e92 --- /dev/null +++ b/Content.Shared/_White/Grab/GrabThrownComponent.cs @@ -0,0 +1,16 @@ +using Robust.Shared.GameStates; +using Content.Shared.Damage; + +namespace Content.Shared._White.Grab; + +[RegisterComponent, NetworkedComponent] +public sealed partial class GrabThrownComponent : Component +{ + public DamageSpecifier? DamageOnCollide; + + public DamageSpecifier? WallDamageOnCollide; + + public float? StaminaDamageOnCollide; + + public List IgnoreEntity = new(); +} diff --git a/Content.Shared/_White/Grab/GrabThrownSystem.cs b/Content.Shared/_White/Grab/GrabThrownSystem.cs new file mode 100644 index 0000000000..3ae770af16 --- /dev/null +++ b/Content.Shared/_White/Grab/GrabThrownSystem.cs @@ -0,0 +1,102 @@ +using Content.Shared.Damage.Systems; +using Content.Shared.Damage; +using Content.Shared.Effects; +using Content.Shared.Throwing; +using Robust.Shared.Network; +using Robust.Shared.Physics.Events; +using Robust.Shared.Player; +using System.Numerics; +using Content.Shared._White.Standing; + +namespace Content.Shared._White.Grab; + +public sealed class GrabThrownSystem : EntitySystem +{ + [Dependency] private readonly DamageableSystem _damageable = default!; + [Dependency] private readonly SharedColorFlashEffectSystem _color = default!; + [Dependency] private readonly StaminaSystem _stamina = default!; + [Dependency] private readonly ThrowingSystem _throwing = default!; + [Dependency] private readonly INetManager _netMan = default!; + [Dependency] private readonly SharedLayingDownSystem _layingDown = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(HandleCollide); + SubscribeLocalEvent(OnStopThrow); + } + + private void HandleCollide(EntityUid uid, GrabThrownComponent component, ref StartCollideEvent args) + { + if (_netMan.IsClient) // To avoid effect spam + return; + + if (!HasComp(uid)) + { + RemComp(uid); + return; + } + + Log.Error($"{args.OtherEntity}"); + + if (component.IgnoreEntity.Contains(args.OtherEntity)) + return; + + if (!HasComp(uid)) + RemComp(uid); + + component.IgnoreEntity.Add(args.OtherEntity); + + var speed = args.OurBody.LinearVelocity.Length(); + + if (component.StaminaDamageOnCollide != null) + _stamina.TakeStaminaDamage(uid, component.StaminaDamageOnCollide.Value); + + var damageScale = speed; + + if (component.WallDamageOnCollide != null) + _damageable.TryChangeDamage(args.OtherEntity, component.WallDamageOnCollide * damageScale); + + _layingDown.TryLieDown(args.OtherEntity, behavior:DropHeldItemsBehavior.AlwaysDrop); + + _color.RaiseEffect(Color.Red, new List() { uid }, Filter.Pvs(uid, entityManager: EntityManager)); + } + + private void OnStopThrow(EntityUid uid, GrabThrownComponent comp, StopThrowEvent args) // We dont need this comp to exsist after fall + { + if (comp.DamageOnCollide != null) + _damageable.TryChangeDamage(uid, comp.DamageOnCollide); + + if (HasComp(uid)) + RemComp(uid); + } + + /// + /// Throwing entity to the direction and ensures GrabThrownComponent with params + /// + /// Entity to throw + /// Entity that throws + /// Direction + /// Stamina damage on collide + /// Damage to entity on collide + /// Damage to wall or anything that was hit by entity + public void Throw( + EntityUid uid, + EntityUid thrower, + Vector2 vector, + float? staminaDamage = null, + DamageSpecifier? damageToUid = null, + DamageSpecifier? damageToWall = null) + { + _throwing.TryThrow(uid, vector, 5f, animated: false); + + var comp = EnsureComp(uid); + comp.StaminaDamageOnCollide = staminaDamage; + comp.DamageOnCollide = damageToUid; + comp.WallDamageOnCollide = damageToWall; + comp.IgnoreEntity.Add(thrower); + + _layingDown.TryLieDown(uid, behavior:DropHeldItemsBehavior.AlwaysDrop); + } +} diff --git a/Resources/Prototypes/Alerts/alerts.yml b/Resources/Prototypes/Alerts/alerts.yml index 00b799670f..4c2af4f403 100644 --- a/Resources/Prototypes/Alerts/alerts.yml +++ b/Resources/Prototypes/Alerts/alerts.yml @@ -387,17 +387,37 @@ - type: alert id: Pulled - icons: [ /Textures/Interface/Alerts/Pull/pulled.png ] + icons: + - sprite: /Textures/Interface/Alerts/pull.rsi + state: pulled + - sprite: /Textures/Interface/Alerts/pull.rsi + state: grabbed-soft + - sprite: /Textures/Interface/Alerts/pull.rsi + state: grabbed-hard + - sprite: /Textures/Interface/Alerts/pull.rsi + state: grabbed-choke onClick: !type:StopBeingPulled { } name: alerts-pulled-name description: alerts-pulled-desc + minSeverity: 0 + maxSeverity: 3 - type: alert id: Pulling - icons: [ /Textures/Interface/Alerts/Pull/pulling.png ] + icons: + - sprite: /Textures/Interface/Alerts/pull.rsi + state: pulling + - sprite: /Textures/Interface/Alerts/pull.rsi + state: grab-soft + - sprite: /Textures/Interface/Alerts/pull.rsi + state: grab-hard + - sprite: /Textures/Interface/Alerts/pull.rsi + state: grab-choke onClick: !type:StopPulling { } name: alerts-pulling-name description: alerts-pulling-desc + minSeverity: 0 + maxSeverity: 3 - type: alert id: Bleed diff --git a/Resources/Textures/Interface/Alerts/pull.rsi/grab-choke.png b/Resources/Textures/Interface/Alerts/pull.rsi/grab-choke.png new file mode 100644 index 0000000000000000000000000000000000000000..085c7c389c88794038736d91f69ef53ac81e7969 GIT binary patch literal 1038 zcmV+p1o8WcP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!~g&e!~vBn4jTXf1EWbqK~!i%?N?1` z6G0T-tdT0BMbkt?D7D&KFM9E!kVC2H!He|X!v;L$;Mt-GQoZU;h)D0bc@Tsi0-ihx zUK?sDh?q1=5HT&KalUci@UoqqnQeCCq5a_TX5Z}2H}8A%lXyos!VwNNa-rXcQt4t4 zHe=CheSPivUf6WTsQBXqkb^EhTdBdXJY1~sXMkdW<9kU&_`m#6RSeRH=f-2yc8!HY zJ0Us-nJbqr77o1+e&`1vmW=Xu9xT`3d5pKoM`QR7h6+&36@09$`LzNF#gu>dVyPlj ztWgYY7~;_w+7v^7^jlZZ`|w%wTUS6-Sttsl%J3N4rf*$g8Y6A~eCP+jmB%wzo2zMx zMZYyoA_}}eD*o7OP$1F4WkKR=P+%ndxkjTQ8|89YdV)|*PT>C1Q>o;ukrP`-k)Zt3nzgD1Ib=dU{G)7X16p08)|mJ`%@LBM>R}-EBd7xiq0vY__%% z@5i{ahxR@aABNv{2IvmK;PJ~hk{o*<__*1XUN;fM(4H<%cl?D| z$}c#LA}9f{97ugspH6-Pf2Mr~@_xUsVtf)XRAM)uk4-2FUVS?G3H&(;|Lp9nkzbtw zz>T@Nf1{;{&%WCYuFZ1VHkbY!)yH zpfaZ9uWoNEqvxnk((ejNer;_{89hgRl71VsCI2)wCM^!8KEU?94Kp({(&Aw118m=O zIIVeGHPO!#PFj5%Y}G_RPuR8kfRg|&73WD0Q+*v=D$bL3tv;X?0LhrDXsfX8dmE69 zsfxA=+rH;ex4@bC`P8oT86-U2}oWWwL=cD;7HZNCN~04AF@Zmq6r$)kV( zm~7gp*Xudce*q=Hd+|HKb+TDtVPT<<$%c<3!@w`W!w1j%3wp|FRM#EST>t<807*qo IM6N<$f<8s!l>h($ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Interface/Alerts/pull.rsi/grab-hard.png b/Resources/Textures/Interface/Alerts/pull.rsi/grab-hard.png new file mode 100644 index 0000000000000000000000000000000000000000..1e703705845540ff1b13fcdd70b9e1642143d0b2 GIT binary patch literal 716 zcmV;-0yF)IP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!~g&e!~vBn4jTXf0%1u+K~z{r?UcVu z12GiGb5$n?@mE0v5fx`QS6u|9yNg4S76b}tofQ;>inzKth-(KY!M~u0O2G=P zKS5W|d}Ch7<#N}YbrJnQc*$!o@B7|M!v6X5c+!SQr+ag98cDT!ci{RzISmmdKx~@b zIx4^(Eobxk8jue-{x4EQ2xP@K@nQ9$`)Ka!lUs*KNgIHdOxdZ$%>u0M)8}MOAHKst z1;}T^Du63i_H274&$B3y4|5FoO&{ju!|&#|HtJTu%nTV}P-S!<=5gQJXqGmBo;lWf zwt6;kKJ(is5s}xBQ}=o$An`RsCPKj6%7(~fe{)q`I|6NhMV7EUOZTfLiLJoe&S9aa zvt2CiAD`L!!mJX368Cp^FwgVYP4$uPdtw3BLkRS~A~=AL27%x}`V+S;NvBG;`3lT1ETksQ2$W{ zU=so#<^$bb?7H?KeDo%8>WT=o0NGQ2DL5GIYZC*3XdtjID8*A5;?)53`njBmfB^K6 zN^b)q2&zC!s!3RsACL(BrHsR@fUwA(PCh~FzSa-bX9V|sU-;pJh>??hC4%;gBX9;z zGnud58sPTrjlIk)iHf+q4N3rlL@^d3Y# zL;?23$K~t`tmlhGxeBj2$l57$s{ms&>)I6cU919Z8S7Xw{x(i6s7E6eQMW)Io`yNE yRM>H;WP9SR1O(vYMoAJp!1VC&k5u57!PqAx^sC)$14V@Z00008 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Interface/Alerts/pull.rsi/grab-soft.png b/Resources/Textures/Interface/Alerts/pull.rsi/grab-soft.png new file mode 100644 index 0000000000000000000000000000000000000000..03877d2c1f68754b5e566662c92249ed5e27b9b0 GIT binary patch literal 706 zcmV;z0zLhSP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!~g&e!~vBn4jTXf0#`{yK~z{r?UcJp z1Thqbv#Ww&A>I~55K(I@!56S_eF6oGMHIwFYj1_3wKgKG$acPgK7*h>!J@KwfmK&5 zY#sB*oN#6)Gn=^Eh<TVI5+xVDt)P{8sRDf(Y ztO3Y~jXv97UzAxC$%Zim_NWbGvf+Dlt&O@Bh-QY2AXFJ{!#HiNjaIEg@XRsi+45}C zY|*tzK_p&7N!{z^f%i2;CMtlX^&OST(e9?Xb_Ci0jVz&MmhM+glUjkTgOg%^PnViJ zy}pUIM;N0kWt5l5;RI*r^1LNZ^Uz;KcFD^OPNNr0!kx$I{5_62RlAZpW!?R0%eB{L3CfAnILGtG(uNn{1`%>sNvToc+B)J>dc6x!1;d(-qK>;2NEw9MJkID2zY+EoA4sef2lbaZsi zv9YPBsQmx`zmkPTR8$nG^;Oo_H9$(JB*-rqD2@sk9_`;R1eE10@Q5sCVBk9f!i-b3 z`J{mka`tp_4Ds-OJMnc{ivmvz<3@4T^4kB?bJI9DW^GG+|i*L=p@+%y$ zRQH#??tXnk%<*OYoR=+6&6-wV?{LOFaE-)FpIlK3on3uodyM~k1#4Z1&m_;M$vajWlVx8V1VGgD+a zZO^dD-m6^BHcDRcx9)z%In~wQm#Rd?3m!VY{Hc5c=cIQ5hbOz86zy79$GU^*fa!+` z#)={g>k_|6ConnQdusl0>k8MC`UmQMPCOf*DRLl5^Wvf~@0ntZ-bP26GR`i0AvodE zw%pE(PnjodK4ZN2w6X)=m9`W7wOIIJ;$;@!;rG#`tnbk3|gpP3Q7yI@;oBr;= zrDj%vzTK}p*E7gXdlCFIb7cif$<}3Cu8A;~mk4ioA1~^bEwg!+UJWpe89ZJ6T-G@y GGywoUklXzL literal 0 HcmV?d00001 diff --git a/Resources/Textures/Interface/Alerts/pull.rsi/grabbed-hard.png b/Resources/Textures/Interface/Alerts/pull.rsi/grabbed-hard.png new file mode 100644 index 0000000000000000000000000000000000000000..4d7d6a21443ddd4a27322bc4908030c0c8c139c4 GIT binary patch literal 367 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCijS1AIbU6WSKkO`O*-d(-qK>s#h*X`H=zi;vF~2Z#Uv|A(uo0ackMehUOr z+$BMN!9YPMVDR#1`~(!{EbxddW?X?_wfUrhf(JZZ978Pp&-Moj9ai9QalAdF z;y?3r){rZHMwi#?IbZnN+48FSAB%$0$!&Qr=go?`W^kU7Gi3kO>%tpaf3jJuU0D6S zfbT(^;0Eofk=@!1Q-sRq6sxE?L>J79a%qro|I~Se;falR`7!B-6Zr)8-pldmThF85 zcuBUWtZ08Ivq78LOBZ$_j-R*kKV3Xl@E{^I?SaPZXOdo)g6cunCb`yLWNEps#h*X`H=zT2@v~M8yC9|2<7ifT~*5${T?c zcS(?6Fi;Q*7`*%$KLLd~3p^r=85sDEfH31!Z9ZwB;89N(#}Etuv;7yPniV)&9k=V; z|KG^YZn9x*UiptHHh&fb)?b*<;G&XU)BjY?XNl>VVh5+qgx~MQ3)e3zI=pwv-@alI}^dPT>hvQ(vwrZ}C=h_)@i5(ez#sldJ0G zsRvcQyPG-8Z&aK-!y(YA?6>c|W5zN!!nX3{yj}FC?b^3m|J4V@eH~^kY3bqJr{R0y z!n^zfFZR!G(6ny|Wv`jYd|c~>7W28!u55Q+FuwT9>~cPx%a!Eu%R9J=WRzZ&1Fcf`1QK8IJ0)WM{ zqS0DyD-RciFzS2XoeA6hH|AKPQA$l0zSU6m}s-w>g0{;b#c z?06tul{^c^SAj?50R+%9Uypz&^iemh5T-beRd$F0bVb1_my_eume7=x34ymhPtxlir?(t1CV7e;#-829*UjpVSrK_@YN+Bh9 z;`8N% z61AKPoKB|>^CC;AKD0P9u$bCO5RocEW>6QL1WW~l#P-nkzJ@x)kOCWNCxI^ypRMyn zme8&_VIEF;tEL1lvV_bO9Yg@=e{@_b==Gt<66(t$z>$V#VEyNm{Ld^Xx*B!Us&8ao ezls}f(D57UhsCckiQ=*V0000~XQCI&5Fa=<_yjabhaI<-O zwBzJg0~p8GroUT1;IFUyOSS6r@3xO|_|*W~_H@@i-{0&Ph=q}seG>j5E(gs)}HKq0V!pBFaX%gUdFcu5GB$6EdYF83&bJpX92K# z4|5sSQNP#3K`{W>+r{yT17$}p-)8~vr(S3gpb+ zfUF|9z{`!V0$>@C?@{3S6phAL0r)5^`>p9ezbT6fPM`S({oP+ie*(ZeQ+s$?6}p=6 P00000NkvXXu0mjfJ{9Ir literal 0 HcmV?d00001 From ce83a3debf7d8e224ce3fb5404af20d47162b388 Mon Sep 17 00:00:00 2001 From: Spatison <137375981+Spatison@users.noreply.github.com> Date: Wed, 28 Aug 2024 13:09:24 +0300 Subject: [PATCH 2/5] tweak --- Content.Shared/CombatMode/SharedCombatModeSystem.cs | 5 +++++ Content.Shared/Movement/Pulling/Systems/PullingSystem.cs | 5 +++-- Content.Shared/_White/Grab/GrabThrownSystem.cs | 2 -- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Content.Shared/CombatMode/SharedCombatModeSystem.cs b/Content.Shared/CombatMode/SharedCombatModeSystem.cs index 60d1362bb0..00b84b618a 100644 --- a/Content.Shared/CombatMode/SharedCombatModeSystem.cs +++ b/Content.Shared/CombatMode/SharedCombatModeSystem.cs @@ -1,6 +1,8 @@ using Content.Shared.Actions; using Content.Shared.MouseRotator; using Content.Shared.Movement.Components; +using Content.Shared.Movement.Pulling.Components; +using Content.Shared.Movement.Pulling.Systems; using Content.Shared.Popups; using Robust.Shared.Network; using Robust.Shared.Timing; @@ -75,6 +77,9 @@ public virtual void SetInCombatMode(EntityUid entity, bool value, CombatModeComp if (component.IsInCombatMode == value) return; + if (value && TryComp(entity, out var pullable) && pullable.GrabStage != GrabStage.No) // WD EDIT + return; + component.IsInCombatMode = value; Dirty(entity, component); diff --git a/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs b/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs index ed53281652..dbb8f1728a 100644 --- a/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs +++ b/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs @@ -754,6 +754,8 @@ public bool TryGrab(Entity pullable, Entity(pullable)) return false; + _combatMode.SetInCombatMode(pullable, false); + // Delay to avoid spamming puller.Comp.NextStageChange = _timing.CurTime + puller.Comp.StageChangeCooldown; Dirty(puller); @@ -896,10 +898,9 @@ public bool AttemptGrabRelease(Entity pullable) { if (!Resolve(pullable.Owner, ref pullable.Comp)) return false; + if (_timing.CurTime < pullable.Comp.NextEscapeAttempt) // No autoclickers! Mwa-ha-ha - { return false; - } if (_random.Prob(pullable.Comp.GrabEscapeChance)) return true; diff --git a/Content.Shared/_White/Grab/GrabThrownSystem.cs b/Content.Shared/_White/Grab/GrabThrownSystem.cs index 3ae770af16..ed84ba8bea 100644 --- a/Content.Shared/_White/Grab/GrabThrownSystem.cs +++ b/Content.Shared/_White/Grab/GrabThrownSystem.cs @@ -38,8 +38,6 @@ private void HandleCollide(EntityUid uid, GrabThrownComponent component, ref Sta return; } - Log.Error($"{args.OtherEntity}"); - if (component.IgnoreEntity.Contains(args.OtherEntity)) return; From 70bcfaf6c3f0370b0fee8d3b9431a93ee1f105bc Mon Sep 17 00:00:00 2001 From: Spatison <137375981+Spatison@users.noreply.github.com> Date: Wed, 28 Aug 2024 13:37:36 +0300 Subject: [PATCH 3/5] WD EDIT --- Content.Server/Alert/Click/StopPulling.cs | 2 +- .../Body/Systems/RespiratorSystem.cs | 4 +- Content.Server/Hands/Systems/HandsSystem.cs | 6 ++- .../Implants/SubdermalImplantSystem.cs | 2 +- .../EntitySystems/AnchorableSystem.cs | 2 +- .../SharedHandsSystem.Interactions.cs | 2 + .../Hands/EntitySystems/SharedHandsSystem.cs | 2 + Content.Shared/Hands/HandEvents.cs | 8 ++-- .../VirtualItem/SharedVirtualItemSystem.cs | 14 +++--- .../Pulling/Components/PullableComponent.cs | 3 +- .../Pulling/Components/PullerComponent.cs | 2 + .../Movement/Pulling/Systems/PullingSystem.cs | 48 ++++++++++++++----- .../Systems/DeployableBarrierSystem.cs | 2 +- .../Systems/SharedPortalSystem.cs | 4 +- Resources/Prototypes/Alerts/alerts.yml | 12 +++-- 15 files changed, 79 insertions(+), 34 deletions(-) diff --git a/Content.Server/Alert/Click/StopPulling.cs b/Content.Server/Alert/Click/StopPulling.cs index 3941ff6873..ef3e2cdea6 100644 --- a/Content.Server/Alert/Click/StopPulling.cs +++ b/Content.Server/Alert/Click/StopPulling.cs @@ -20,7 +20,7 @@ public void AlertClicked(EntityUid player) if (entManager.TryGetComponent(player, out PullerComponent? puller) && entManager.TryGetComponent(puller.Pulling, out PullableComponent? pullableComp)) { - ps.TryLowerGrabStage(puller.Pulling.Value, player, true); + ps.TryLowerGrabStage(puller.Pulling.Value, player, true); // WD EDIT } } } diff --git a/Content.Server/Body/Systems/RespiratorSystem.cs b/Content.Server/Body/Systems/RespiratorSystem.cs index e8b1e4b9e8..c1138a4719 100644 --- a/Content.Server/Body/Systems/RespiratorSystem.cs +++ b/Content.Server/Body/Systems/RespiratorSystem.cs @@ -52,7 +52,7 @@ private void OnUnpaused(Entity ent, ref EntityUnpausedEvent ent.Comp.NextUpdate += args.PausedTime; } - public bool CanBreathe(EntityUid uid) + public bool CanBreathe(EntityUid uid) // WD EDIT { if (TryComp(uid, out var pullable) && pullable.GrabStage == GrabStage.Suffocate) return false; @@ -91,7 +91,7 @@ public override void Update(float frameTime) } } - if (respirator.Saturation < respirator.SuffocationThreshold || !CanBreathe(uid)) + if (respirator.Saturation < respirator.SuffocationThreshold || !CanBreathe(uid)) // WD EDIT { if (_gameTiming.CurTime >= respirator.LastGaspPopupTime + respirator.GaspPopupCooldown) { diff --git a/Content.Server/Hands/Systems/HandsSystem.cs b/Content.Server/Hands/Systems/HandsSystem.cs index ae30b4f980..b27e0df8ef 100644 --- a/Content.Server/Hands/Systems/HandsSystem.cs +++ b/Content.Server/Hands/Systems/HandsSystem.cs @@ -89,7 +89,7 @@ private void OnDisarmed(EntityUid uid, HandsComponent component, DisarmedEvent a // Break any pulls if (TryComp(uid, out PullerComponent? puller) && TryComp(puller.Pulling, out PullableComponent? pullable)) - _pullingSystem.TryStopPull(puller.Pulling.Value, pullable, ignoreGrab: true); + _pullingSystem.TryStopPull(puller.Pulling.Value, pullable, ignoreGrab: true); // WD EDIT if (!_handsSystem.TryDrop(uid, component.ActiveHand!, null, checkActionBlocker: false)) return; @@ -169,6 +169,7 @@ private bool HandleThrowItem(ICommonSession? playerSession, EntityCoordinates co if (playerSession?.AttachedEntity is not {Valid: true} player || !Exists(player)) return false; + // WD EDIT START if (TryGetActiveItem(player, out var item) && TryComp(item, out var virtComp)) { var userEv = new VirtualItemDropAttemptEvent(virtComp.BlockingEntity, player, item.Value, true); @@ -180,6 +181,7 @@ private bool HandleThrowItem(ICommonSession? playerSession, EntityCoordinates co if (userEv.Cancelled || targEv.Cancelled) return false; } + // WD EDIT END return ThrowHeldItem(player, coordinates); } @@ -224,6 +226,7 @@ hands.ActiveHandEntity is not { } throwEnt || var ev = new BeforeThrowEvent(throwEnt, direction, throwStrength, player); RaiseLocalEvent(player, ref ev); + // WD EDIT START if (TryComp(throwEnt, out var virt)) { var userEv = new VirtualItemThrownEvent(virt.BlockingEntity, player, throwEnt, direction); @@ -232,6 +235,7 @@ hands.ActiveHandEntity is not { } throwEnt || var targEv = new VirtualItemThrownEvent(virt.BlockingEntity, player, throwEnt, direction); RaiseLocalEvent(virt.BlockingEntity, targEv); } + // WD EDIT END if (ev.Cancelled) return true; diff --git a/Content.Server/Implants/SubdermalImplantSystem.cs b/Content.Server/Implants/SubdermalImplantSystem.cs index 46836814cf..8abe692701 100644 --- a/Content.Server/Implants/SubdermalImplantSystem.cs +++ b/Content.Server/Implants/SubdermalImplantSystem.cs @@ -107,7 +107,7 @@ private void OnScramImplant(EntityUid uid, SubdermalImplantComponent component, // We need stop the user from being pulled so they don't just get "attached" with whoever is pulling them. // This can for example happen when the user is cuffed and being pulled. if (TryComp(ent, out var pull) && _pullingSystem.IsPulled(ent, pull)) - _pullingSystem.TryStopPull(ent, pull, ignoreGrab: true); + _pullingSystem.TryStopPull(ent, pull, ignoreGrab: true); // WD EDIT var xform = Transform(ent); var targetCoords = SelectRandomTileInRange(xform, implant.TeleportRadius); diff --git a/Content.Shared/Construction/EntitySystems/AnchorableSystem.cs b/Content.Shared/Construction/EntitySystems/AnchorableSystem.cs index 0ea3b0eb1f..e211fc26d8 100644 --- a/Content.Shared/Construction/EntitySystems/AnchorableSystem.cs +++ b/Content.Shared/Construction/EntitySystems/AnchorableSystem.cs @@ -133,7 +133,7 @@ private void OnAnchorComplete(EntityUid uid, AnchorableComponent component, TryA if (TryComp(uid, out var pullable) && pullable.Puller != null) { - _pulling.TryStopPull(uid, pullable, ignoreGrab: true); + _pulling.TryStopPull(uid, pullable, ignoreGrab: true); // WD EDIT } // TODO: Anchoring snaps rn anyway! diff --git a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Interactions.cs b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Interactions.cs index a30c5ea496..ad65510532 100644 --- a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Interactions.cs +++ b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Interactions.cs @@ -96,6 +96,7 @@ private bool DropPressed(ICommonSession? session, EntityCoordinates coords, Enti { if (TryComp(session?.AttachedEntity, out HandsComponent? hands) && hands.ActiveHand != null) { + // WD EDIT START if (session != null) { var ent = session.AttachedEntity.Value; @@ -114,6 +115,7 @@ private bool DropPressed(ICommonSession? session, EntityCoordinates coords, Enti TryDrop(ent, hands.ActiveHand, coords, handsComp: hands); } } + // WD EDIT END // always send to server. return false; diff --git a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.cs b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.cs index 4f64714aab..572263b7b2 100644 --- a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.cs +++ b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.cs @@ -137,6 +137,7 @@ public bool TryGetEmptyHand(EntityUid uid, [NotNullWhen(true)] out Hand? emptyHa return false; } + // WD EDIT START public bool TryGetActiveHand(Entity entity, [NotNullWhen(true)] out Hand? hand) { if (!Resolve(entity, ref entity.Comp, false)) @@ -173,6 +174,7 @@ public bool TryGetActiveItem(Entity entity, [NotNullWhen(true)] { return GetActiveHand(entity)?.HeldEntity; } + // WD EDIT END /// /// Enumerate over hands, starting with the currently active hand. diff --git a/Content.Shared/Hands/HandEvents.cs b/Content.Shared/Hands/HandEvents.cs index f900d92acd..dc99ca2afc 100644 --- a/Content.Shared/Hands/HandEvents.cs +++ b/Content.Shared/Hands/HandEvents.cs @@ -148,16 +148,17 @@ public sealed class VirtualItemDeletedEvent : EntityEventArgs { public EntityUid BlockingEntity; public EntityUid User; - public EntityUid VirtualItem; + public EntityUid VirtualItem; // WD EDIT - public VirtualItemDeletedEvent(EntityUid blockingEntity, EntityUid user, EntityUid virtualItem) + public VirtualItemDeletedEvent(EntityUid blockingEntity, EntityUid user, EntityUid virtualItem) // WD EDIT { BlockingEntity = blockingEntity; User = user; - VirtualItem = virtualItem; + VirtualItem = virtualItem; // WD EDIT } } + // WD EDIT START /// /// Raised directed on both the blocking entity and user when /// a virtual hand item is thrown (at least attempted to). @@ -176,6 +177,7 @@ public VirtualItemThrownEvent(EntityUid blockingEntity, EntityUid user, EntityUi Direction = direction; } } + // WD EDIT END /// /// Raised directed on both the blocking entity and user when diff --git a/Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs b/Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs index b13900e2ea..e355f682a3 100644 --- a/Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs +++ b/Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs @@ -31,7 +31,7 @@ public abstract class SharedVirtualItemSystem : EntitySystem [Dependency] private readonly SharedItemSystem _itemSystem = default!; [Dependency] private readonly InventorySystem _inventorySystem = default!; [Dependency] private readonly SharedHandsSystem _handsSystem = default!; - [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; // WD EDIT [ValidatePrototypeId] private const string VirtualItem = "VirtualItem"; @@ -79,11 +79,12 @@ private void OnBeforeRangedInteract(Entity ent, ref Before /// /// The entity we will make a virtual entity copy of /// The entity that we want to insert the virtual entity - public bool TrySpawnVirtualItemInHand(EntityUid blockingEnt, EntityUid user, bool dropOthers = false) + public bool TrySpawnVirtualItemInHand(EntityUid blockingEnt, EntityUid user, bool dropOthers = false) // WD EDIT { - return TrySpawnVirtualItemInHand(blockingEnt, user, out _, dropOthers); + return TrySpawnVirtualItemInHand(blockingEnt, user, out _, dropOthers); // WD EDIT } + // WD EDIT START /// public bool TrySpawnVirtualItemInHand(EntityUid blockingEnt, EntityUid user, [NotNullWhen(true)] out EntityUid? virtualItem, bool dropOthers = false, Hand? empty = null) { @@ -124,6 +125,7 @@ public bool TrySpawnVirtualItemInHand(EntityUid blockingEnt, EntityUid user, [No _handsSystem.DoPickup(user, empty, virtualItem.Value); return true; } + // WD EDIT END /// /// Scan the user's hands until we find the virtual entity, if the @@ -222,7 +224,7 @@ public bool TrySpawnVirtualItem(EntityUid blockingEnt, EntityUid user, [NotNullW var pos = Transform(user).Coordinates; virtualItem = Spawn(VirtualItem, pos); - var virtualItemComp = EnsureComp(virtualItem.Value); + var virtualItemComp = EnsureComp(virtualItem.Value); // WD EDIT virtualItemComp.BlockingEntity = blockingEnt; Dirty(virtualItem.Value, virtualItemComp); return true; @@ -233,10 +235,10 @@ public bool TrySpawnVirtualItem(EntityUid blockingEnt, EntityUid user, [NotNullW /// public void DeleteVirtualItem(Entity item, EntityUid user) { - var userEv = new VirtualItemDeletedEvent(item.Comp.BlockingEntity, user, item.Owner); + var userEv = new VirtualItemDeletedEvent(item.Comp.BlockingEntity, user, item.Owner); // WD EDIT RaiseLocalEvent(user, userEv); - var targEv = new VirtualItemDeletedEvent(item.Comp.BlockingEntity, user, item.Owner); + var targEv = new VirtualItemDeletedEvent(item.Comp.BlockingEntity, user, item.Owner); // WD EDIT RaiseLocalEvent(item.Comp.BlockingEntity, targEv); if (TerminatingOrDeleted(item)) diff --git a/Content.Shared/Movement/Pulling/Components/PullableComponent.cs b/Content.Shared/Movement/Pulling/Components/PullableComponent.cs index 75c6bd2067..e03bd49a62 100644 --- a/Content.Shared/Movement/Pulling/Components/PullableComponent.cs +++ b/Content.Shared/Movement/Pulling/Components/PullableComponent.cs @@ -38,7 +38,7 @@ public sealed partial class PullableComponent : Component [AutoNetworkedField, DataField] public bool PrevFixedRotation; - + // WD EDIT START [DataField] public Dictionary PulledAlertAlertSeverity = new() { @@ -56,4 +56,5 @@ public sealed partial class PullableComponent : Component [AutoNetworkedField] public TimeSpan NextEscapeAttempt = TimeSpan.Zero; + // WD EDIT END } diff --git a/Content.Shared/Movement/Pulling/Components/PullerComponent.cs b/Content.Shared/Movement/Pulling/Components/PullerComponent.cs index db6d289ea4..8c659562a6 100644 --- a/Content.Shared/Movement/Pulling/Components/PullerComponent.cs +++ b/Content.Shared/Movement/Pulling/Components/PullerComponent.cs @@ -39,6 +39,7 @@ public sealed partial class PullerComponent : Component [DataField] public bool NeedsHands = true; + // WD EDIT START [DataField] public Dictionary PullingAlertSeverity = new() { @@ -83,4 +84,5 @@ public sealed partial class PullerComponent : Component { { GrabStage.Suffocate, 1 }, }; + // WD EDIT END } diff --git a/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs b/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs index dbb8f1728a..822dd923b6 100644 --- a/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs +++ b/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs @@ -59,6 +59,7 @@ public sealed class PullingSystem : EntitySystem [Dependency] private readonly SharedPhysicsSystem _physics = default!; [Dependency] private readonly SharedTransformSystem _xformSys = default!; [Dependency] private readonly ThrowingSystem _throwing = default!; + // WD EDIT START [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly StaminaSystem _stamina = default!; [Dependency] private readonly SharedColorFlashEffectSystem _color = default!; @@ -69,6 +70,7 @@ public sealed class PullingSystem : EntitySystem [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly GrabThrownSystem _grabThrown = default!; [Dependency] private readonly SharedCombatModeSystem _combatMode = default!; + // WD EDIT END public override void Initialize() { @@ -82,15 +84,15 @@ public override void Initialize() SubscribeLocalEvent(OnJointRemoved); SubscribeLocalEvent>(AddPullVerbs); SubscribeLocalEvent(OnPullableContainerInsert); - SubscribeLocalEvent(OnGrabbedMoveAttempt); - SubscribeLocalEvent(OnGrabbedSpeakAttempt); + SubscribeLocalEvent(OnGrabbedMoveAttempt); // WD EDIT + SubscribeLocalEvent(OnGrabbedSpeakAttempt); // WD EDIT SubscribeLocalEvent(OnPullerContainerInsert); SubscribeLocalEvent(OnPullerUnpaused); SubscribeLocalEvent(OnVirtualItemDeleted); SubscribeLocalEvent(OnRefreshMovespeed); - SubscribeLocalEvent(OnVirtualItemThrown); - SubscribeLocalEvent(OnVirtualItemDropAttempt); + SubscribeLocalEvent(OnVirtualItemThrown); // WD EDIT + SubscribeLocalEvent(OnVirtualItemDropAttempt); // WD EDIT CommandBinds.Builder .Bind(ContentKeyFunctions.MovePulledObject, new PointerInputCmdHandler(OnRequestMovePulledObject)) @@ -105,17 +107,19 @@ private void OnPullerContainerInsert(Entity ent, ref EntGotInse if (!TryComp(ent.Comp.Pulling.Value, out PullableComponent? pulling)) return; + // WD EDIT START foreach (var item in ent.Comp.GrabVirtualItems) { QueueDel(item); } TryStopPull(ent.Comp.Pulling.Value, pulling, ent.Owner, true); + // WD EDIT END } private void OnPullableContainerInsert(Entity ent, ref EntGotInsertedIntoContainerMessage args) { - TryStopPull(ent.Owner, ent.Comp, ignoreGrab: true); + TryStopPull(ent.Owner, ent.Comp, ignoreGrab: true); // WD EDIT } public override void Shutdown() @@ -129,6 +133,7 @@ private void OnPullerUnpaused(EntityUid uid, PullerComponent component, ref Enti component.NextThrow += args.PausedTime; } + // WD EDIT START private void OnVirtualItemDropAttempt(EntityUid uid, PullerComponent component, VirtualItemDropAttemptEvent args) { if (component.Pulling == null) @@ -163,6 +168,7 @@ private void OnVirtualItemDropAttempt(EntityUid uid, PullerComponent component, } } } + // WD EDIT END private void OnVirtualItemDeleted(EntityUid uid, PullerComponent component, VirtualItemDeletedEvent args) { @@ -175,10 +181,11 @@ private void OnVirtualItemDeleted(EntityUid uid, PullerComponent component, Virt if (EntityManager.TryGetComponent(args.BlockingEntity, out PullableComponent? comp)) { - TryLowerGrabStage(component.Pulling.Value, uid); + TryLowerGrabStage(component.Pulling.Value, uid); // WD EDIT } } + // WD EDIT START private void OnVirtualItemThrown(EntityUid uid, PullerComponent component, VirtualItemThrownEvent args) { if (component.Pulling == null) @@ -237,6 +244,7 @@ private void OnVirtualItemThrown(EntityUid uid, PullerComponent component, Virtu } } } + // WD EDIT END private void AddPullVerbs(EntityUid uid, PullableComponent component, GetVerbsEvent args) { @@ -272,6 +280,7 @@ private void AddPullVerbs(EntityUid uid, PullableComponent component, GetVerbsEv private void OnRefreshMovespeed(EntityUid uid, PullerComponent component, RefreshMovementSpeedModifiersEvent args) { + // WD EDIT START if (TryComp(component.Pulling, out var heldMoveSpeed) && component.Pulling.HasValue) { var (walkMod, sprintMod) = (args.WalkSpeedModifier, args.SprintSpeedModifier); @@ -315,6 +324,7 @@ private void OnRefreshMovespeed(EntityUid uid, PullerComponent component, Refres args.ModifySpeed(component.WalkSpeedModifier, component.SprintSpeedModifier); break; } + // WD EDIT END } private void OnPullableMoveInput(EntityUid uid, PullableComponent component, ref MoveInputEvent args) @@ -374,9 +384,11 @@ private void StopPulling(EntityUid pullableUid, PullableComponent pullableComp) var oldPuller = pullableComp.Puller; pullableComp.PullJointId = null; pullableComp.Puller = null; + // WD EDIT START pullableComp.GrabStage = GrabStage.No; pullableComp.GrabEscapeChance = 1f; _blocker.UpdateCanMove(pullableUid); + // WD EDIT END Dirty(pullableUid, pullableComp); @@ -387,6 +399,7 @@ private void StopPulling(EntityUid pullableUid, PullableComponent pullableComp) _alertsSystem.ClearAlert(pullerUid, AlertType.Pulling); pullerComp.Pulling = null; + // WD EDIT START pullerComp.GrabStage = GrabStage.No; List virtItems = pullerComp.GrabVirtualItems; foreach (var item in virtItems) @@ -394,6 +407,7 @@ private void StopPulling(EntityUid pullableUid, PullableComponent pullableComp) QueueDel(item); } pullerComp.GrabVirtualItems.Clear(); + // WD EDIT END Dirty(oldPuller.Value, pullerComp); @@ -474,7 +488,7 @@ private void OnReleasePulledObject(ICommonSession? session) return; } - TryStopPull(pullerComp.Pulling.Value, pullableComp, user: player, true); + TryStopPull(pullerComp.Pulling.Value, pullableComp, user: player, true); // WD EDIT } public bool CanPull(EntityUid puller, EntityUid pullableUid, PullerComponent? pullerComp = null) @@ -534,6 +548,7 @@ public bool CanPull(EntityUid puller, EntityUid pullableUid, PullerComponent? pu public bool TogglePull(EntityUid pullableUid, EntityUid pullerUid, PullableComponent pullable) { + // WD EDIT START if (pullable.Puller != pullerUid) return TryStartPull(pullerUid, pullableUid, pullableComp: pullable); @@ -544,6 +559,7 @@ public bool TogglePull(EntityUid pullableUid, EntityUid pullerUid, PullableCompo return TryStopPull(pullableUid, pullable, ignoreGrab: true); return false; + // WD EDIT END } public bool TogglePull(EntityUid pullerUid, PullerComponent puller) @@ -577,7 +593,7 @@ public bool TryStartPull(EntityUid pullerUid, EntityUid pullableUid, // Ensure that the puller is not currently pulling anything. if (TryComp(pullerComp.Pulling, out var oldPullable) - && !TryStopPull(pullerComp.Pulling.Value, oldPullable, pullerUid, true)) + && !TryStopPull(pullerComp.Pulling.Value, oldPullable, pullerUid, true)) // WD EDIT return false; // Stop anyone else pulling the entity we want to pull @@ -589,6 +605,7 @@ public bool TryStartPull(EntityUid pullerUid, EntityUid pullableUid, if (!TryStopPull(pullableUid, pullableComp, pullableComp.Puller)) { + // WD EDIT START // Not succeed to retake grabbed entity if (_netManager.IsServer) { @@ -619,6 +636,7 @@ public bool TryStartPull(EntityUid pullerUid, EntityUid pullableUid, pullableComp.Puller.Value, pullableComp.Puller.Value, PopupType.MediumCaution); } } + // WD EDIT END } var pullAttempt = new PullAttemptEvent(pullerUid, pullableUid); @@ -664,8 +682,8 @@ public bool TryStartPull(EntityUid pullerUid, EntityUid pullableUid, // Messaging var message = new PullStartedMessage(pullerUid, pullableUid); - _alertsSystem.ShowAlert(pullerUid, AlertType.Pulling, 0); - _alertsSystem.ShowAlert(pullableUid, AlertType.Pulled, 0); + _alertsSystem.ShowAlert(pullerUid, AlertType.Pulling, 0); // WD EDIT + _alertsSystem.ShowAlert(pullableUid, AlertType.Pulled, 0); // WD EDIT RaiseLocalEvent(pullerUid, message); RaiseLocalEvent(pullableUid, message); @@ -676,13 +694,15 @@ public bool TryStartPull(EntityUid pullerUid, EntityUid pullableUid, _adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(pullerUid):user} started pulling {ToPrettyString(pullableUid):target}"); + // WD EDIT START if (_combatMode.IsInCombatMode(pullerUid)) TryGrab(pullableUid, pullerUid); + // WD EDIT END return true; } - public bool TryStopPull(EntityUid pullableUid, PullableComponent pullable, EntityUid? user = null, bool ignoreGrab = false) + public bool TryStopPull(EntityUid pullableUid, PullableComponent pullable, EntityUid? user = null, bool ignoreGrab = false) // WD EDIT { var pullerUidNull = pullable.Puller; @@ -695,6 +715,7 @@ public bool TryStopPull(EntityUid pullableUid, PullableComponent pullable, Entit if (msg.Cancelled) return false; + // WD EDIT START // There are some events that should ignore grab stages if (!ignoreGrab) { @@ -711,6 +732,7 @@ public bool TryStopPull(EntityUid pullableUid, PullableComponent pullable, Entit _popup.PopupEntity(Loc.GetString("popup-grab-release-success-puller", ("target", Identity.Entity(pullableUid, EntityManager))), pullerUidNull.Value, pullerUidNull.Value, PopupType.MediumCaution); } } + // WD EDIT END // Stop pulling confirmed! if (!_timing.ApplyingState) @@ -727,6 +749,7 @@ public bool TryStopPull(EntityUid pullableUid, PullableComponent pullable, Entit return true; } + // WD EDIT START /// /// Trying to grab the target /// @@ -970,8 +993,10 @@ public bool TryLowerGrabStage(Entity pullable, Entity(subject, out var pullable) && pullable.BeingPulled) { - _pulling.TryStopPull(subject, pullable, ignoreGrab: true); + _pulling.TryStopPull(subject, pullable, ignoreGrab: true); // WD EDIT } if (TryComp(subject, out var pullerComp) && TryComp(pullerComp.Pulling, out var subjectPulling)) { - _pulling.TryStopPull(subject, subjectPulling, ignoreGrab: true); + _pulling.TryStopPull(subject, subjectPulling, ignoreGrab: true); // WD EDIT } // if they came from another portal, just return and wait for them to exit the portal diff --git a/Resources/Prototypes/Alerts/alerts.yml b/Resources/Prototypes/Alerts/alerts.yml index 4c2af4f403..ae5d92f041 100644 --- a/Resources/Prototypes/Alerts/alerts.yml +++ b/Resources/Prototypes/Alerts/alerts.yml @@ -387,6 +387,7 @@ - type: alert id: Pulled + # WD EDIT START icons: - sprite: /Textures/Interface/Alerts/pull.rsi state: pulled @@ -396,14 +397,16 @@ state: grabbed-hard - sprite: /Textures/Interface/Alerts/pull.rsi state: grabbed-choke + # WD EDIT END onClick: !type:StopBeingPulled { } name: alerts-pulled-name description: alerts-pulled-desc - minSeverity: 0 - maxSeverity: 3 + minSeverity: 0 # WD EDIT + maxSeverity: 3 # WD EDIT - type: alert id: Pulling + # WD EDIT START icons: - sprite: /Textures/Interface/Alerts/pull.rsi state: pulling @@ -413,11 +416,12 @@ state: grab-hard - sprite: /Textures/Interface/Alerts/pull.rsi state: grab-choke + # WD EDIT END onClick: !type:StopPulling { } name: alerts-pulling-name description: alerts-pulling-desc - minSeverity: 0 - maxSeverity: 3 + minSeverity: 0 # WD EDIT + maxSeverity: 3 # WD EDIT - type: alert id: Bleed From 9aaf90f03630d7f1680f820e914b6baa40f5c233 Mon Sep 17 00:00:00 2001 From: Spatison <137375981+Spatison@users.noreply.github.com> Date: Wed, 28 Aug 2024 13:41:46 +0300 Subject: [PATCH 4/5] WD EDIT --- Content.Server/Body/Systems/RespiratorSystem.cs | 4 +++- Content.Shared/Administration/AdminFrozenSystem.cs | 2 +- Content.Shared/Hands/HandEvents.cs | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Content.Server/Body/Systems/RespiratorSystem.cs b/Content.Server/Body/Systems/RespiratorSystem.cs index c1138a4719..786638a7b4 100644 --- a/Content.Server/Body/Systems/RespiratorSystem.cs +++ b/Content.Server/Body/Systems/RespiratorSystem.cs @@ -52,12 +52,14 @@ private void OnUnpaused(Entity ent, ref EntityUnpausedEvent ent.Comp.NextUpdate += args.PausedTime; } - public bool CanBreathe(EntityUid uid) // WD EDIT + // WD EDIT START + public bool CanBreathe(EntityUid uid) { if (TryComp(uid, out var pullable) && pullable.GrabStage == GrabStage.Suffocate) return false; return true; } + // WD EDIT END public override void Update(float frameTime) { diff --git a/Content.Shared/Administration/AdminFrozenSystem.cs b/Content.Shared/Administration/AdminFrozenSystem.cs index 30d11ecae9..f853934888 100644 --- a/Content.Shared/Administration/AdminFrozenSystem.cs +++ b/Content.Shared/Administration/AdminFrozenSystem.cs @@ -44,7 +44,7 @@ private void OnStartup(EntityUid uid, AdminFrozenComponent component, ComponentS { if (TryComp(uid, out var pullable)) { - _pulling.TryStopPull(uid, pullable, ignoreGrab: true); + _pulling.TryStopPull(uid, pullable, ignoreGrab: true); // WD EDIT } UpdateCanMove(uid, component, args); diff --git a/Content.Shared/Hands/HandEvents.cs b/Content.Shared/Hands/HandEvents.cs index dc99ca2afc..7ae389fb61 100644 --- a/Content.Shared/Hands/HandEvents.cs +++ b/Content.Shared/Hands/HandEvents.cs @@ -177,7 +177,6 @@ public VirtualItemThrownEvent(EntityUid blockingEntity, EntityUid user, EntityUi Direction = direction; } } - // WD EDIT END /// /// Raised directed on both the blocking entity and user when @@ -198,6 +197,7 @@ public VirtualItemDropAttemptEvent(EntityUid blockingEntity, EntityUid user, Ent Throw = thrown; } } + // WD EDIT END /// /// Raised when putting an entity into a hand slot From 4eccaa236c184a7353f12b233c9ceef0616f970a Mon Sep 17 00:00:00 2001 From: Spatison <137375981+Spatison@users.noreply.github.com> Date: Wed, 28 Aug 2024 14:29:58 +0300 Subject: [PATCH 5/5] add: Loc --- Resources/Locale/en-US/_white/grab/grab.ftl | 21 +++++++++++++++++++++ Resources/Locale/ru-RU/_white/grab/grab.ftl | 21 +++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 Resources/Locale/en-US/_white/grab/grab.ftl create mode 100644 Resources/Locale/ru-RU/_white/grab/grab.ftl diff --git a/Resources/Locale/en-US/_white/grab/grab.ftl b/Resources/Locale/en-US/_white/grab/grab.ftl new file mode 100644 index 0000000000..9a7b77bc8c --- /dev/null +++ b/Resources/Locale/en-US/_white/grab/grab.ftl @@ -0,0 +1,21 @@ +popup-grab-soft-target = {CAPITALIZE($puller)} grabbed you softly. +popup-grab-hard-target = {CAPITALIZE($puller)} grabbed you hardly. +popup-grab-suffocate-target = {CAPITALIZE($puller)} started to choke you! +popup-grab-no-target = {CAPITALIZE($puller)} stopped grabbing you. +popup-grab-soft-self = You grabbed {CAPITALIZE($target)} softly. +popup-grab-hard-self = You grabbed {CAPITALIZE($target)} hardly. +popup-grab-suffocate-self = You started to choke {CAPITALIZE($target)}. +popup-grab-no-self = You stopped grabbing {CAPITALIZE($target)}. +popup-grab-soft-others = {CAPITALIZE($puller)} grabbed {CAPITALIZE($target)} softly. +popup-grab-hard-others = {CAPITALIZE($puller)} grabbed {CAPITALIZE($target)} hardly. +popup-grab-suffocate-others = {CAPITALIZE($puller)} started to choke {CAPITALIZE($target)}! +popup-grab-no-others = {CAPITALIZE($puller)} stopped grabbing {CAPITALIZE($target)}. +popup-grab-release-fail-self = You are trying to escape. +popup-grab-release-success-self = You escaped from grab! +popup-grab-release-success-puller = {CAPITALIZE($target)} escaped! +popup-grab-retake-fail = {CAPITALIZE($puller)} is not letting you to pull {CAPITALIZE($pulled)}! +popup-grab-retake-fail-puller = {CAPITALIZE($puller)} is trying to release {CAPITALIZE($pulled)}! +popup-grab-retake-success = You released {CAPITALIZE($pulled)} from {CAPITALIZE($puller)}'s grab! +popup-grab-retake-success-puller = {CAPITALIZE($puller)} released {CAPITALIZE($pulled)} from your grab! +popup-grabbed-cant-speak = You can't breathe! +popup-grab-need-hand = You need a free hand! \ No newline at end of file diff --git a/Resources/Locale/ru-RU/_white/grab/grab.ftl b/Resources/Locale/ru-RU/_white/grab/grab.ftl new file mode 100644 index 0000000000..75b3cb5f03 --- /dev/null +++ b/Resources/Locale/ru-RU/_white/grab/grab.ftl @@ -0,0 +1,21 @@ +popup-grab-soft-target = {CAPITALIZE($puller)} взял вас в захват. +popup-grab-hard-target = {CAPITALIZE($puller)} взял вас в агресивный захват. +popup-grab-suffocate-target = {CAPITALIZE($puller)} начал душить вас! +popup-grab-no-target = {CAPITALIZE($puller)} выпустил вас из захвата. +popup-grab-soft-self = Вы взяли в захват {CAPITALIZE($target)}. +popup-grab-hard-self = Вы агресивно взяли в захват {CAPITALIZE($target)}. +popup-grab-suffocate-self = Вы начали душить {CAPITALIZE($target)}. +popup-grab-no-self = вы выпустили {CAPITALIZE($target)} из захвата. +popup-grab-soft-others = {CAPITALIZE($puller)} взял в захват {CAPITALIZE($target)}. +popup-grab-hard-others = {CAPITALIZE($puller)} взял в агресивный захват {CAPITALIZE($target)}. +popup-grab-suffocate-others = {CAPITALIZE($puller)} начал душить {CAPITALIZE($target)}! +popup-grab-no-others = {CAPITALIZE($puller)} выпустил из захвата {CAPITALIZE($target)}. +popup-grab-release-fail-self = Вы пытаетесь выбраьтся. +popup-grab-release-success-self = Вы освободились! +popup-grab-release-success-puller = {CAPITALIZE($target)} освободилс! +popup-grab-retake-fail = {CAPITALIZE($puller)} не дает тебе тянуть {CAPITALIZE($pulled)}! +popup-grab-retake-fail-puller = {CAPITALIZE($puller)} пытаеться освободить {CAPITALIZE($pulled)}! +popup-grab-retake-success = Вы осовбождаете {CAPITALIZE($pulled)} из захвата {CAPITALIZE($puller)}! +popup-grab-retake-success-puller = {CAPITALIZE($puller)} освобождает {CAPITALIZE($pulled)} из вашаего захвата! +popup-grabbed-cant-speak = Вы не можете дышать! +popup-grab-need-hand = Вым нужна свободная рука! \ No newline at end of file