From 7ebe16dd3d32b107bab2c9344732104055e1443a Mon Sep 17 00:00:00 2001 From: Vordenburg <114301317+Vordenburg@users.noreply.github.com> Date: Mon, 22 May 2023 17:49:37 -0400 Subject: [PATCH] Fix snares (#16699) The alert for snares will appear again. Previously it was being updated on the snare itself and not the player. It is no longer possible to infinitely ensnare someone; the maximum number is dependent on the target's legs. Only one snare at a time will be removed now. Clarified the wording and logic around CanMoveBreakout. It was inconsistent. Made multiple snares impose cumulative speed penalties. It is no longer possible to remove bolas while moving. --- Content.Server/Alert/Click/RemoveEnsnare.cs | 3 ++ .../Ensnaring/EnsnareableSystem.Ensnaring.cs | 39 ++++++++++++++----- Content.Server/Ensnaring/EnsnareableSystem.cs | 20 ++++++---- .../Components/EnsnaringComponent.cs | 9 ++++- .../Ensnaring/SharedEnsnareableSystem.cs | 7 +++- .../Objects/Weapons/Throwable/bola.yml | 1 - 6 files changed, 59 insertions(+), 20 deletions(-) diff --git a/Content.Server/Alert/Click/RemoveEnsnare.cs b/Content.Server/Alert/Click/RemoveEnsnare.cs index 1913dea905..f821ca3ca9 100644 --- a/Content.Server/Alert/Click/RemoveEnsnare.cs +++ b/Content.Server/Alert/Click/RemoveEnsnare.cs @@ -19,6 +19,9 @@ public sealed class RemoveEnsnare : IAlertClick return; entManager.EntitySysManager.GetEntitySystem().TryFree(player, player, ensnare, ensnaringComponent); + + // Only one snare at a time. + break; } } } diff --git a/Content.Server/Ensnaring/EnsnareableSystem.Ensnaring.cs b/Content.Server/Ensnaring/EnsnareableSystem.Ensnaring.cs index f65871ef99..1359e1d550 100644 --- a/Content.Server/Ensnaring/EnsnareableSystem.Ensnaring.cs +++ b/Content.Server/Ensnaring/EnsnareableSystem.Ensnaring.cs @@ -1,4 +1,8 @@ +using System.Linq; +using Content.Server.Body.Systems; using Content.Shared.Alert; +using Content.Shared.Body.Components; +using Content.Shared.Body.Part; using Content.Shared.DoAfter; using Content.Shared.Ensnaring; using Content.Shared.Ensnaring.Components; @@ -12,6 +16,7 @@ public sealed partial class EnsnareableSystem { [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; [Dependency] private readonly AlertsSystem _alerts = default!; + [Dependency] private readonly BodySystem _body = default!; public void InitializeEnsnaring() { @@ -60,12 +65,19 @@ public sealed partial class EnsnareableSystem if (!TryComp(target, out var ensnareable)) return; + var legs = _body.GetBodyChildrenOfType(target, BodyPartType.Leg).Count(); + var ensnaredLegs = (2 * ensnareable.Container.ContainedEntities.Count); + var freeLegs = legs - ensnaredLegs; + + if (freeLegs <= 0) + return; + component.Ensnared = target; ensnareable.Container.Insert(ensnare); ensnareable.IsEnsnared = true; Dirty(ensnareable); - UpdateAlert(ensnare, ensnareable); + UpdateAlert(target, ensnareable); var ev = new EnsnareEvent(component.WalkSpeed, component.SprintSpeed); RaiseLocalEvent(target, ev); } @@ -84,7 +96,7 @@ public sealed partial class EnsnareableSystem return; var freeTime = user == target ? component.BreakoutTime : component.FreeTime; - var breakOnMove = user != target || !component.CanMoveBreakout; + var breakOnMove = !component.CanMoveBreakout; var doAfterEventArgs = new DoAfterArgs(user, freeTime, new EnsnareableDoAfterEvent(), target, target: target, used: ensnare) { @@ -109,24 +121,33 @@ public sealed partial class EnsnareableSystem /// public void ForceFree(EntityUid ensnare, EnsnaringComponent component) { + if (component.Ensnared == null) + return; + if (!TryComp(component.Ensnared, out var ensnareable)) return; - ensnareable.Container.ForceRemove(ensnare); - ensnareable.IsEnsnared = false; + var target = component.Ensnared.Value; + + ensnareable.Container.Remove(ensnare, force: true); + ensnareable.IsEnsnared = ensnareable.Container.ContainedEntities.Count > 0; Dirty(ensnareable); component.Ensnared = null; - UpdateAlert(ensnare, ensnareable); - var ev = new EnsnareRemoveEvent(); + UpdateAlert(target, ensnareable); + var ev = new EnsnareRemoveEvent(component.WalkSpeed, component.SprintSpeed); RaiseLocalEvent(ensnare, ev); } - public void UpdateAlert(EntityUid ensnare, EnsnareableComponent component) + /// + /// Update the Ensnared alert for an entity. + /// + /// The entity that has been affected by a snare + public void UpdateAlert(EntityUid target, EnsnareableComponent component) { if (!component.IsEnsnared) - _alerts.ClearAlert(ensnare, AlertType.Ensnared); + _alerts.ClearAlert(target, AlertType.Ensnared); else - _alerts.ShowAlert(ensnare, AlertType.Ensnared); + _alerts.ShowAlert(target, AlertType.Ensnared); } } diff --git a/Content.Server/Ensnaring/EnsnareableSystem.cs b/Content.Server/Ensnaring/EnsnareableSystem.cs index 48e34537f8..66758eed84 100644 --- a/Content.Server/Ensnaring/EnsnareableSystem.cs +++ b/Content.Server/Ensnaring/EnsnareableSystem.cs @@ -2,6 +2,7 @@ using Content.Server.Popups; using Content.Shared.DoAfter; using Content.Shared.Ensnaring; using Content.Shared.Ensnaring.Components; +using Content.Shared.Hands.EntitySystems; using Content.Shared.Popups; using Robust.Server.Containers; using Robust.Shared.Containers; @@ -11,6 +12,7 @@ namespace Content.Server.Ensnaring; public sealed partial class EnsnareableSystem : SharedEnsnareableSystem { [Dependency] private readonly ContainerSystem _container = default!; + [Dependency] private readonly SharedHandsSystem _hands = default!; [Dependency] private readonly PopupSystem _popup = default!; public override void Initialize() @@ -30,24 +32,28 @@ public sealed partial class EnsnareableSystem : SharedEnsnareableSystem private void OnDoAfter(EntityUid uid, EnsnareableComponent component, DoAfterEvent args) { + if (args.Args.Target == null) + return; + if (args.Handled || !TryComp(args.Args.Used, out var ensnaring)) return; - if (args.Cancelled) + if (args.Cancelled || !component.Container.Remove(args.Args.Used.Value)) { - _popup.PopupEntity(Loc.GetString("ensnare-component-try-free-fail", ("ensnare", args.Args.Used)), uid, uid, PopupType.Large); + _popup.PopupEntity(Loc.GetString("ensnare-component-try-free-fail", ("ensnare", args.Args.Used)), uid, uid, PopupType.MediumCaution); return; } - component.Container.Remove(args.Args.Used.Value); - component.IsEnsnared = false; + component.IsEnsnared = component.Container.ContainedEntities.Count > 0; Dirty(component); ensnaring.Ensnared = null; - _popup.PopupEntity(Loc.GetString("ensnare-component-try-free-complete", ("ensnare", args.Args.Used)), uid, uid, PopupType.Large); + _hands.PickupOrDrop(args.Args.User, args.Args.Used.Value); - UpdateAlert(args.Args.Used.Value, component); - var ev = new EnsnareRemoveEvent(); + _popup.PopupEntity(Loc.GetString("ensnare-component-try-free-complete", ("ensnare", args.Args.Used)), uid, uid, PopupType.Medium); + + UpdateAlert(args.Args.Target.Value, component); + var ev = new EnsnareRemoveEvent(ensnaring.WalkSpeed, ensnaring.SprintSpeed); RaiseLocalEvent(uid, ev); args.Handled = true; diff --git a/Content.Shared/Ensnaring/Components/EnsnaringComponent.cs b/Content.Shared/Ensnaring/Components/EnsnaringComponent.cs index d88dd30dd0..1604f7472b 100644 --- a/Content.Shared/Ensnaring/Components/EnsnaringComponent.cs +++ b/Content.Shared/Ensnaring/Components/EnsnaringComponent.cs @@ -51,7 +51,7 @@ public sealed class EnsnaringComponent : Component public EntityUid? Ensnared; /// - /// Should movement cancel breaking out? + /// Should breaking out be possible when moving? /// [ViewVariables(VVAccess.ReadWrite)] [DataField("canMoveBreakout")] @@ -79,7 +79,14 @@ public sealed class EnsnareEvent : EntityEventArgs /// public sealed class EnsnareRemoveEvent : CancellableEntityEventArgs { + public readonly float WalkSpeed; + public readonly float SprintSpeed; + public EnsnareRemoveEvent(float walkSpeed, float sprintSpeed) + { + WalkSpeed = walkSpeed; + SprintSpeed = sprintSpeed; + } } /// diff --git a/Content.Shared/Ensnaring/SharedEnsnareableSystem.cs b/Content.Shared/Ensnaring/SharedEnsnareableSystem.cs index 86f73f8ca9..3486a29251 100644 --- a/Content.Shared/Ensnaring/SharedEnsnareableSystem.cs +++ b/Content.Shared/Ensnaring/SharedEnsnareableSystem.cs @@ -47,8 +47,8 @@ public abstract class SharedEnsnareableSystem : EntitySystem private void OnEnsnare(EntityUid uid, EnsnareableComponent component, EnsnareEvent args) { - component.WalkSpeed = args.WalkSpeed; - component.SprintSpeed = args.SprintSpeed; + component.WalkSpeed *= args.WalkSpeed; + component.SprintSpeed *= args.SprintSpeed; _speedModifier.RefreshMovementSpeedModifiers(uid); @@ -58,6 +58,9 @@ public abstract class SharedEnsnareableSystem : EntitySystem private void OnEnsnareRemove(EntityUid uid, EnsnareableComponent component, EnsnareRemoveEvent args) { + component.WalkSpeed /= args.WalkSpeed; + component.SprintSpeed /= args.SprintSpeed; + _speedModifier.RefreshMovementSpeedModifiers(uid); var ev = new EnsnaredChangedEvent(component.IsEnsnared); diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/bola.yml b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/bola.yml index c0ef1aec33..8c3651266d 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/bola.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/bola.yml @@ -46,5 +46,4 @@ walkSpeed: 0.7 #makeshift bola shouldn't slow too much sprintSpeed: 0.7 canThrowTrigger: true - canMoveBreakout: true