diff --git a/Content.Server/Ghost/Roles/Components/GhostRoleComponent.cs b/Content.Server/Ghost/Roles/Components/GhostRoleComponent.cs index 93e7e9efaa650e..abb26a8c8bc158 100644 --- a/Content.Server/Ghost/Roles/Components/GhostRoleComponent.cs +++ b/Content.Server/Ghost/Roles/Components/GhostRoleComponent.cs @@ -11,7 +11,7 @@ public sealed partial class GhostRoleComponent : Component [DataField("description")] private string _roleDescription = "Unknown"; - [DataField("rules")] private string _roleRules = ""; + [DataField("rules")] private string _roleRules = "ghost-role-component-default-rules"; [DataField("requirements")] public HashSet? Requirements; diff --git a/Content.Server/Ghost/Roles/GhostRoleSystem.cs b/Content.Server/Ghost/Roles/GhostRoleSystem.cs index cd04e3fb3734f4..0649e68a317c22 100644 --- a/Content.Server/Ghost/Roles/GhostRoleSystem.cs +++ b/Content.Server/Ghost/Roles/GhostRoleSystem.cs @@ -56,7 +56,8 @@ public override void Initialize() SubscribeLocalEvent(OnMindAdded); SubscribeLocalEvent(OnMindRemoved); SubscribeLocalEvent(OnMobStateChanged); - SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnStartup); SubscribeLocalEvent(OnShutdown); SubscribeLocalEvent(OnPaused); SubscribeLocalEvent(OnUnpaused); @@ -317,17 +318,14 @@ private void OnUnpaused(EntityUid uid, GhostRoleComponent component, ref EntityU UpdateAllEui(); } - private void OnInit(Entity ent, ref ComponentInit args) + private void OnMapInit(Entity ent, ref MapInitEvent args) { - var role = ent.Comp; - if (role.Probability < 1f && !_random.Prob(role.Probability)) - { - RemComp(ent); - return; - } + if (ent.Comp.Probability < 1f && !_random.Prob(ent.Comp.Probability)) + RemCompDeferred(ent); + } - if (role.RoleRules == "") - role.RoleRules = Loc.GetString("ghost-role-component-default-rules"); + private void OnStartup(Entity ent, ref ComponentStartup args) + { RegisterGhostRole(ent); } diff --git a/Content.Server/Tools/ToolSystem.Welder.cs b/Content.Server/Tools/ToolSystem.Welder.cs index 98e29c763a8019..1eabd6c6d2c64e 100644 --- a/Content.Server/Tools/ToolSystem.Welder.cs +++ b/Content.Server/Tools/ToolSystem.Welder.cs @@ -152,9 +152,9 @@ private void OnWelderAfterInteract(Entity entity, ref AfterInte { _popup.PopupEntity(Loc.GetString("welder-component-no-fuel-in-tank", ("owner", args.Target)), entity, args.User); } - } - args.Handled = true; + args.Handled = true; + } } private void OnWelderToolUseAttempt(Entity entity, ref DoAfterAttemptEvent args) diff --git a/Content.Shared/Cuffs/Components/HandcuffComponent.cs b/Content.Shared/Cuffs/Components/HandcuffComponent.cs index 77a77cf2f84f95..30577da064f7da 100644 --- a/Content.Shared/Cuffs/Components/HandcuffComponent.cs +++ b/Content.Shared/Cuffs/Components/HandcuffComponent.cs @@ -52,6 +52,14 @@ public sealed partial class HandcuffComponent : Component [DataField] public bool Removing; + /// + /// Whether the cuffs are currently being used to cuff someone. + /// We need the extra information for when the virtual item is deleted because that can happen when you simply stop + /// pulling them on the ground. + /// + [DataField] + public bool Used; + /// /// The path of the RSI file used for the player cuffed overlay. /// @@ -87,7 +95,7 @@ public sealed partial class HandcuffComponent : Component } /// -/// Event fired on the User when the User attempts to cuff the Target. +/// Event fired on the User when the User attempts to uncuff the Target. /// Should generate popups on the User. /// [ByRefEvent] diff --git a/Content.Shared/Cuffs/SharedCuffableSystem.cs b/Content.Shared/Cuffs/SharedCuffableSystem.cs index ca903719c448d4..0077f5a358efb6 100644 --- a/Content.Shared/Cuffs/SharedCuffableSystem.cs +++ b/Content.Shared/Cuffs/SharedCuffableSystem.cs @@ -3,12 +3,10 @@ using Content.Shared.Administration.Components; using Content.Shared.Administration.Logs; using Content.Shared.Alert; -using Content.Shared.Atmos.Piping.Unary.Components; using Content.Shared.Buckle.Components; using Content.Shared.Cuffs.Components; using Content.Shared.Database; using Content.Shared.DoAfter; -using Content.Shared.Effects; using Content.Shared.Hands; using Content.Shared.Hands.Components; using Content.Shared.Hands.EntitySystems; @@ -19,7 +17,6 @@ using Content.Shared.Inventory.Events; using Content.Shared.Inventory.VirtualItem; using Content.Shared.Item; -using Content.Shared.Mobs.Systems; using Content.Shared.Movement.Events; using Content.Shared.Movement.Pulling.Events; using Content.Shared.Popups; @@ -29,12 +26,12 @@ using Content.Shared.Timing; using Content.Shared.Verbs; using Content.Shared.Weapons.Melee.Events; -using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; using Robust.Shared.Network; using Robust.Shared.Player; using Robust.Shared.Serialization; +using Robust.Shared.Utility; using PullableComponent = Content.Shared.Movement.Pulling.Components.PullableComponent; namespace Content.Shared.Cuffs @@ -47,8 +44,6 @@ public abstract partial class SharedCuffableSystem : EntitySystem [Dependency] private readonly ISharedAdminLogManager _adminLog = default!; [Dependency] private readonly ActionBlockerSystem _actionBlocker = default!; [Dependency] private readonly AlertsSystem _alerts = default!; - [Dependency] private readonly SharedColorFlashEffectSystem _color = default!; - [Dependency] private readonly MobStateSystem _mobState = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedContainerSystem _container = default!; [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; @@ -95,9 +90,8 @@ public override void Initialize() private void OnUncuffAttempt(ref UncuffAttemptEvent args) { if (args.Cancelled) - { return; - } + if (!Exists(args.User) || Deleted(args.User)) { // Should this even be possible? @@ -109,23 +103,29 @@ private void OnUncuffAttempt(ref UncuffAttemptEvent args) // This is because the CanInteract blocking of the cuffs prevents self-uncuff. if (args.User == args.Target) { - // This UncuffAttemptEvent check should probably be In MobStateSystem, not here? - if (_mobState.IsIncapacitated(args.User)) - { - args.Cancelled = true; - } - else + if (!TryComp(args.User, out var cuffable)) { - // TODO Find a way for cuffable to check ActionBlockerSystem.CanInteract() without blocking itself + DebugTools.Assert($"{args.User} tried to uncuff themselves but they are not cuffable."); + return; } + + // We temporarily allow interactions so the cuffable system does not block itself. + // It's assumed that this will always be false. + // Otherwise they would not be trying to uncuff themselves. + cuffable.CanStillInteract = true; + Dirty(args.User, cuffable); + + if (!_actionBlocker.CanInteract(args.User, args.User)) + args.Cancelled = true; + + cuffable.CanStillInteract = false; + Dirty(args.User, cuffable); } else { // Check if the user can interact. if (!_actionBlocker.CanInteract(args.User, args.Target)) - { args.Cancelled = true; - } } if (args.Cancelled) @@ -310,6 +310,7 @@ private void OnAddCuffDoAfter(EntityUid uid, HandcuffComponent component, AddCuf if (!args.Cancelled && TryAddNewCuffs(target, user, uid, cuffable)) { + component.Used = true; _audio.PlayPredicted(component.EndCuffSound, uid, user); _popup.PopupEntity(Loc.GetString("handcuff-component-cuff-observer-success-message", @@ -613,7 +614,7 @@ public void Uncuff(EntityUid target, EntityUid? user, EntityUid cuffsToRemove, C if (!Resolve(target, ref cuffable) || !Resolve(cuffsToRemove, ref cuff)) return; - if (cuff.Removing || TerminatingOrDeleted(cuffsToRemove) || TerminatingOrDeleted(target)) + if (!cuff.Used || cuff.Removing || TerminatingOrDeleted(cuffsToRemove) || TerminatingOrDeleted(target)) return; if (user != null) @@ -625,10 +626,9 @@ public void Uncuff(EntityUid target, EntityUid? user, EntityUid cuffsToRemove, C } cuff.Removing = true; + cuff.Used = false; _audio.PlayPredicted(cuff.EndUncuffSound, target, user); - var isOwner = user == target; - _container.Remove(cuffsToRemove, cuffable.Container); if (_net.IsServer) @@ -644,43 +644,42 @@ public void Uncuff(EntityUid target, EntityUid? user, EntityUid cuffsToRemove, C { _hands.PickupOrDrop(user, cuffsToRemove); } + } + + if (cuffable.CuffedHandCount == 0) + { + if (user != null) + _popup.PopupPredicted(Loc.GetString("cuffable-component-remove-cuffs-success-message"), user.Value, user.Value); - // Only play popups on server because popups suck - if (cuffable.CuffedHandCount == 0) + if (target != user && user != null) + { + _popup.PopupPredicted(Loc.GetString("cuffable-component-remove-cuffs-by-other-success-message", + ("otherName", Identity.Name(user.Value, EntityManager, user))), target, target); + _adminLog.Add(LogType.Action, LogImpact.Medium, + $"{ToPrettyString(user):player} has successfully uncuffed {ToPrettyString(target):player}"); + } + else { - if (user != null) - _popup.PopupEntity(Loc.GetString("cuffable-component-remove-cuffs-success-message"), user.Value, user.Value); - - if (target != user && user != null) - { - _popup.PopupEntity(Loc.GetString("cuffable-component-remove-cuffs-by-other-success-message", - ("otherName", Identity.Name(user.Value, EntityManager, user))), target, target); - _adminLog.Add(LogType.Action, LogImpact.Medium, - $"{ToPrettyString(user):player} has successfully uncuffed {ToPrettyString(target):player}"); - } - else - { - _adminLog.Add(LogType.Action, LogImpact.Medium, - $"{ToPrettyString(user):player} has successfully uncuffed themselves"); - } + _adminLog.Add(LogType.Action, LogImpact.Medium, + $"{ToPrettyString(user):player} has successfully uncuffed themselves"); } - else if (user != null) + } + else if (user != null) + { + if (user != target) + { + _popup.PopupPredicted(Loc.GetString("cuffable-component-remove-cuffs-partial-success-message", + ("cuffedHandCount", cuffable.CuffedHandCount), + ("otherName", Identity.Name(user.Value, EntityManager, user.Value))), user.Value, user.Value); + _popup.PopupPredicted(Loc.GetString( + "cuffable-component-remove-cuffs-by-other-partial-success-message", + ("otherName", Identity.Name(user.Value, EntityManager, user.Value)), + ("cuffedHandCount", cuffable.CuffedHandCount)), target, target); + } + else { - if (user != target) - { - _popup.PopupEntity(Loc.GetString("cuffable-component-remove-cuffs-partial-success-message", - ("cuffedHandCount", cuffable.CuffedHandCount), - ("otherName", Identity.Name(user.Value, EntityManager, user.Value))), user.Value, user.Value); - _popup.PopupEntity(Loc.GetString( - "cuffable-component-remove-cuffs-by-other-partial-success-message", - ("otherName", Identity.Name(user.Value, EntityManager, user.Value)), - ("cuffedHandCount", cuffable.CuffedHandCount)), target, target); - } - else - { - _popup.PopupEntity(Loc.GetString("cuffable-component-remove-cuffs-partial-success-message", - ("cuffedHandCount", cuffable.CuffedHandCount)), user.Value, user.Value); - } + _popup.PopupPredicted(Loc.GetString("cuffable-component-remove-cuffs-partial-success-message", + ("cuffedHandCount", cuffable.CuffedHandCount)), user.Value, user.Value); } } cuff.Removing = false; diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 68ae2414b904f2..1bae524d59d068 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Volotomite - changes: - - message: Flippo can burn plasma now! - type: Fix - id: 5735 - time: '2024-01-18T00:28:32.0000000+00:00' - url: https://api.github.com/repos/space-wizards/space-station-14/pulls/24207 - author: Ubaser changes: - message: The paramedic's void suit now has a helmet toggle. @@ -3791,3 +3784,11 @@ id: 6234 time: '2024-03-26T04:44:56.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/26441 +- author: nikthechampiongr + changes: + - message: Handcuffs will no longer try to uncuff themselves when they stop being + dragged. + type: Fix + id: 6235 + time: '2024-03-26T19:15:08.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/26434 diff --git a/Resources/Prototypes/Entities/Objects/Devices/door_remote.yml b/Resources/Prototypes/Entities/Objects/Devices/door_remote.yml index e63c7f2e0303d7..25ac56a6daba2e 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/door_remote.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/door_remote.yml @@ -9,7 +9,7 @@ sprite: Objects/Devices/door_remote.rsi - type: Item storedRotation: -90 - - type: Access #No access, useless + - type: Access - type: DoorRemote - type: StealTarget stealGroup: DoorRemote @@ -28,7 +28,7 @@ color: "#9f9f00" - type: Access groups: - - AllAccess #Cap must be able to control the station + - Command - type: entity parent: DoorRemoteDefault diff --git a/RobustToolbox b/RobustToolbox index ff38e9f12a50d5..8607ba1f16ce67 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit ff38e9f12a50d5e83b29c21f74a50dea46660f49 +Subproject commit 8607ba1f16ce676a849b59a41efd389a6e467f5c