diff --git a/Content.Client/Inventory/StrippableBoundUserInterface.cs b/Content.Client/Inventory/StrippableBoundUserInterface.cs index 6d18bd6bda..f9a6cd46d6 100644 --- a/Content.Client/Inventory/StrippableBoundUserInterface.cs +++ b/Content.Client/Inventory/StrippableBoundUserInterface.cs @@ -190,7 +190,7 @@ namespace Content.Client.Inventory if (EntMan.TryGetComponent(heldEntity, out var virt)) { button.Blocked = true; - if (EntMan.TryGetComponent(Owner, out var cuff) && _cuffable.GetAllCuffs(cuff).Contains(virt.BlockingEntity)) + if (_cuffable.TryGetAllCuffs(Owner, out var cuffs) && cuffs.Contains(virt.BlockingEntity)) button.BlockedRect.MouseFilter = MouseFilterMode.Ignore; } diff --git a/Content.Server/Cuffs/CuffableSystem.cs b/Content.Server/Cuffs/CuffableSystem.cs index 2c28603c3f..622eabd953 100644 --- a/Content.Server/Cuffs/CuffableSystem.cs +++ b/Content.Server/Cuffs/CuffableSystem.cs @@ -15,7 +15,7 @@ namespace Content.Server.Cuffs SubscribeLocalEvent(OnCuffableGetState); } - private void OnCuffableGetState(EntityUid uid, CuffableComponent component, ref ComponentGetState args) + private void OnCuffableGetState(Entity entity, ref ComponentGetState args) { // there are 2 approaches i can think of to handle the handcuff overlay on players // 1 - make the current RSI the handcuff type that's currently active. all handcuffs on the player will appear the same. @@ -23,12 +23,12 @@ namespace Content.Server.Cuffs // approach #2 would be more difficult/time consuming to do and the payoff doesn't make it worth it. // right now we're doing approach #1. HandcuffComponent? cuffs = null; - if (component.CuffedHandCount > 0) - TryComp(component.LastAddedCuffs, out cuffs); - args.State = new CuffableComponentState(component.CuffedHandCount, - component.CanStillInteract, + if (TryGetLastCuff((entity, entity.Comp), out var cuff)) + TryComp(cuff, out cuffs); + args.State = new CuffableComponentState(entity.Comp.CuffedHandCount, + entity.Comp.CanStillInteract, cuffs?.CuffedRSI, - $"{cuffs?.BodyIconState}-{component.CuffedHandCount}", + $"{cuffs?.BodyIconState}-{entity.Comp.CuffedHandCount}", cuffs?.Color); // the iconstate is formatted as blah-2, blah-4, blah-6, etc. // the number corresponds to how many hands are cuffed. diff --git a/Content.Shared/Cuffs/Components/CuffableComponent.cs b/Content.Shared/Cuffs/Components/CuffableComponent.cs index a7eba34d8c..046dd504c0 100644 --- a/Content.Shared/Cuffs/Components/CuffableComponent.cs +++ b/Content.Shared/Cuffs/Components/CuffableComponent.cs @@ -24,12 +24,6 @@ public sealed partial class CuffableComponent : Component [ViewVariables] public int CuffedHandCount => Container.ContainedEntities.Count * 2; - /// - /// The last pair of cuffs that was added to this entity. - /// - [ViewVariables] - public EntityUid LastAddedCuffs => Container.ContainedEntities[^1]; - /// /// Container of various handcuffs currently applied to the entity. /// diff --git a/Content.Shared/Cuffs/SharedCuffableSystem.cs b/Content.Shared/Cuffs/SharedCuffableSystem.cs index ff4201acaf..f8efa20afa 100644 --- a/Content.Shared/Cuffs/SharedCuffableSystem.cs +++ b/Content.Shared/Cuffs/SharedCuffableSystem.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Linq; using Content.Shared.ActionBlocker; using Content.Shared.Administration.Components; @@ -260,7 +261,7 @@ namespace Content.Shared.Cuffs { if (args.Handled) return; - TryUncuff(ent, ent, cuffable: ent.Comp); + TryUncuff((ent, ent.Comp), ent); args.Handled = true; } @@ -278,7 +279,7 @@ namespace Content.Shared.Cuffs Verb verb = new() { - Act = () => TryUncuff(uid, args.User, cuffable: component), + Act = () => TryUncuff((uid, component), args.User), DoContactInteraction = true, Text = Loc.GetString("uncuff-verb-get-data-text") }; @@ -585,41 +586,31 @@ namespace Content.Shared.Cuffs return true; } + /// + public void TryUncuff(Entity target, EntityUid user) + { + if (!TryGetLastCuff(target, out var cuff)) + return; + + TryUncuff(target, user, cuff.Value); + } + /// /// Attempt to uncuff a cuffed entity. Can be called by the cuffed entity, or another entity trying to help uncuff them. /// If the uncuffing succeeds, the cuffs will drop on the floor. /// - /// - /// The cuffed entity - /// Optional param for the handcuff entity to remove from the cuffed entity. If null, uses the most recently added handcuff entity. - /// - /// - public void TryUncuff(EntityUid target, EntityUid user, EntityUid? cuffsToRemove = null, CuffableComponent? cuffable = null, HandcuffComponent? cuff = null) + /// The entity we're trying to remove cuffs from. + /// The entity doing the cuffing. + /// The handcuff entity we're attempting to remove. + public void TryUncuff(Entity target, EntityUid user, Entity cuff) { - if (!Resolve(target, ref cuffable)) + if (!Resolve(target, ref target.Comp) || !Resolve(cuff, ref cuff.Comp)) return; - var isOwner = user == target; + var isOwner = user == target.Owner; - if (cuffsToRemove == null) - { - if (cuffable.Container.ContainedEntities.Count == 0) - { - return; - } - - cuffsToRemove = cuffable.LastAddedCuffs; - } - else - { - if (!cuffable.Container.ContainedEntities.Contains(cuffsToRemove.Value)) - { - Log.Warning("A user is trying to remove handcuffs that aren't in the owner's container. This should never happen!"); - } - } - - if (!Resolve(cuffsToRemove.Value, ref cuff)) - return; + if (!target.Comp.Container.ContainedEntities.Contains(cuff)) + Log.Warning("A user is trying to remove handcuffs that aren't in the owner's container. This should never happen!"); var attempt = new UncuffAttemptEvent(user, target); RaiseLocalEvent(user, ref attempt, true); @@ -629,29 +620,28 @@ namespace Content.Shared.Cuffs return; } - if (!isOwner && !_interaction.InRangeUnobstructed(user, target)) + if (!isOwner && !_interaction.InRangeUnobstructed(user, target.Owner)) { _popup.PopupClient(Loc.GetString("cuffable-component-cannot-remove-cuffs-too-far-message"), user, user); return; } - - var ev = new ModifyUncuffDurationEvent(user, target, isOwner ? cuff.BreakoutTime : cuff.UncuffTime); + var ev = new ModifyUncuffDurationEvent(user, target, isOwner ? cuff.Comp.BreakoutTime : cuff.Comp.UncuffTime); RaiseLocalEvent(user, ref ev); var uncuffTime = ev.Duration; if (isOwner) { - if (!TryComp(cuffsToRemove.Value, out UseDelayComponent? useDelay)) + if (!TryComp(cuff, out UseDelayComponent? useDelay)) return; - if (!_delay.TryResetDelay((cuffsToRemove.Value, useDelay), true)) + if (!_delay.TryResetDelay((cuff, useDelay), true)) { return; } } - var doAfterEventArgs = new DoAfterArgs(EntityManager, user, uncuffTime, new UnCuffDoAfterEvent(), target, target, cuffsToRemove) + var doAfterEventArgs = new DoAfterArgs(EntityManager, user, uncuffTime, new UnCuffDoAfterEvent(), target, target, cuff) { BreakOnMove = true, BreakOnWeightlessMove = false, @@ -666,7 +656,7 @@ namespace Content.Shared.Cuffs _adminLog.Add(LogType.Action, LogImpact.High, $"{ToPrettyString(user):player} is trying to uncuff {ToPrettyString(target):subject}"); - var popupText = user == target + var popupText = user == target.Owner ? "cuffable-component-start-uncuffing-self-observer" : "cuffable-component-start-uncuffing-observer"; _popup.PopupEntity( @@ -678,7 +668,7 @@ namespace Content.Shared.Cuffs .RemoveWhere(e => e.AttachedEntity == target || e.AttachedEntity == user), true); - if (target == user) + if (isOwner) { _popup.PopupClient(Loc.GetString("cuffable-component-start-uncuffing-self"), user, user); } @@ -694,7 +684,7 @@ namespace Content.Shared.Cuffs target); } - _audio.PlayPredicted(isOwner ? cuff.StartBreakoutSound : cuff.StartUncuffSound, target, user); + _audio.PlayPredicted(isOwner ? cuff.Comp.StartBreakoutSound : cuff.Comp.StartUncuffSound, target, user); } public void Uncuff(EntityUid target, EntityUid? user, EntityUid cuffsToRemove, CuffableComponent? cuffable = null, HandcuffComponent? cuff = null) @@ -818,9 +808,56 @@ namespace Content.Shared.Cuffs #endregion - public IReadOnlyList GetAllCuffs(CuffableComponent component) + /// + /// Tries to get a list of all the handcuffs stored in an entity's . + /// + /// The cuffable entity in question. + /// A list of cuffs if it exists. + /// True if a list of cuffs with cuffs exists. False if no list exists or if it is empty. + public bool TryGetAllCuffs(Entity entity, out IReadOnlyList cuffs) { - return component.Container.ContainedEntities; + cuffs = GetAllCuffs(entity); + + return cuffs.Count > 0; + } + + /// + /// Tries to get a list of all the handcuffs stored in a entity's . + /// + /// The cuffable entity in question. + /// A list of cuffs if it exists, or null if there are no cuffs. + public IReadOnlyList GetAllCuffs(Entity entity) + { + if (!Resolve(entity, ref entity.Comp)) + return []; + + return entity.Comp.Container.ContainedEntities; + } + + /// + /// Tries to get the most recently added pair of handcuffs added to an entity with . + /// + /// The cuffable entity in question. + /// The most recently added cuff. + /// Returns true if a cuff exists and false if one doesn't. + public bool TryGetLastCuff(Entity entity, [NotNullWhen(true)] out EntityUid? cuff) + { + cuff = GetLastCuffOrNull(entity); + + return cuff != null; + } + + /// + /// Tries to get the most recently added pair of handcuffs added to an entity with . + /// + /// The cuffable entity in question. + /// The most recently added cuff or null if none exists. + public EntityUid? GetLastCuffOrNull(Entity entity) + { + if (!Resolve(entity, ref entity.Comp)) + return null; + + return entity.Comp.Container.ContainedEntities.Count == 0 ? null : entity.Comp.Container.ContainedEntities.Last(); } } diff --git a/Content.Shared/Strip/SharedStrippableSystem.cs b/Content.Shared/Strip/SharedStrippableSystem.cs index aca0e42945..fe9c4adb83 100644 --- a/Content.Shared/Strip/SharedStrippableSystem.cs +++ b/Content.Shared/Strip/SharedStrippableSystem.cs @@ -128,10 +128,10 @@ public abstract class SharedStrippableSystem : EntitySystem // Is the target a handcuff? if (TryComp(heldEntity, out var virtualItem) && - TryComp(target.Owner, out var cuffable) && - _cuffableSystem.GetAllCuffs(cuffable).Contains(virtualItem.BlockingEntity)) + _cuffableSystem.TryGetAllCuffs(target.Owner, out var cuffs) && + cuffs.Contains(virtualItem.BlockingEntity)) { - _cuffableSystem.TryUncuff(target.Owner, user, virtualItem.BlockingEntity, cuffable); + _cuffableSystem.TryUncuff(target.Owner, user, virtualItem.BlockingEntity); return; } diff --git a/Content.Shared/Trigger/Systems/UncuffOnTriggerSystem.cs b/Content.Shared/Trigger/Systems/UncuffOnTriggerSystem.cs index ebcfc05de4..ab012ecd90 100644 --- a/Content.Shared/Trigger/Systems/UncuffOnTriggerSystem.cs +++ b/Content.Shared/Trigger/Systems/UncuffOnTriggerSystem.cs @@ -10,10 +10,10 @@ public sealed class UncuffOnTriggerSystem : XOnTriggerSystem ent, EntityUid target, ref TriggerEvent args) { - if (!TryComp(target, out var cuffs) || cuffs.Container.ContainedEntities.Count < 1) + if (!TryComp(target, out var cuffs) || !_cuffable.TryGetLastCuff(target, out var cuff)) return; - _cuffable.Uncuff(target, args.User, cuffs.LastAddedCuffs); + _cuffable.Uncuff(target, args.User, cuff.Value); args.Handled = true; } }