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