diff --git a/Content.Shared/Buckle/BuckleDoafterEvent.cs b/Content.Shared/Buckle/BuckleDoafterEvent.cs new file mode 100644 index 0000000000..268ddfe261 --- /dev/null +++ b/Content.Shared/Buckle/BuckleDoafterEvent.cs @@ -0,0 +1,11 @@ +using Content.Shared.Cuffs.Components; +using Content.Shared.DoAfter; +using Robust.Shared.Serialization; + +namespace Content.Shared.Buckle; + +[Serializable, NetSerializable] +public sealed partial class BuckleDoAfterEvent : SimpleDoAfterEvent +{ + +} diff --git a/Content.Shared/Buckle/Components/StrapComponent.cs b/Content.Shared/Buckle/Components/StrapComponent.cs index a16d15f8a2..b8186e2b79 100644 --- a/Content.Shared/Buckle/Components/StrapComponent.cs +++ b/Content.Shared/Buckle/Components/StrapComponent.cs @@ -84,6 +84,12 @@ public sealed partial class StrapComponent : Component /// [DataField] public ProtoId BuckledAlertType = "Buckled"; + + /// + /// How long it takes to buckle someone else into a chair + /// + [DataField] + public float BuckleDoafterTime = 2f; } public enum StrapPosition diff --git a/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs b/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs index 4f91a29ebe..83c24016ce 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs @@ -2,7 +2,9 @@ using System.Diagnostics.CodeAnalysis; using System.Numerics; using Content.Shared.Alert; using Content.Shared.Buckle.Components; +using Content.Shared.Cuffs.Components; using Content.Shared.Database; +using Content.Shared.DoAfter; using Content.Shared.Hands.Components; using Content.Shared.IdentityManagement; using Content.Shared.Movement.Events; @@ -51,6 +53,12 @@ public abstract partial class SharedBuckleSystem SubscribeLocalEvent(OnBuckleThrowPushbackAttempt); SubscribeLocalEvent(OnBuckleUpdateCanMove); + SubscribeLocalEvent(OnBuckleDoafter); + SubscribeLocalEvent>((uid, comp, ev) => + { + BuckleDoafterEarly((uid, comp), ev.Event, ev); + }); + SubscribeLocalEvent(OnGetState); } @@ -516,4 +524,39 @@ public abstract partial class SharedBuckleSystem RaiseLocalEvent(strap, ref unstrapAttempt); return !unstrapAttempt.Cancelled; } + + /// + /// Once the do-after is complete, try to buckle target to chair/bed + /// + /// The person being put in the chair/bed + /// The person putting a person in a chair/bed + /// The chair/bed + + private void OnBuckleDoafter(Entity entity, ref BuckleDoAfterEvent args) + { + if (args.Cancelled || args.Handled || args.Target == null || args.Used == null) + return; + + args.Handled = TryBuckle(args.Target.Value, args.User, args.Used.Value, popup: false); + } + + /// + /// If the target being buckled to a chair/bed goes crit or is cuffed + /// Cancel the do-after time and try to buckle the target immediately + /// + /// The person being put in the chair/bed + /// The person putting a person in a chair/bed + /// The chair/bed + private void BuckleDoafterEarly(Entity entity, BuckleDoAfterEvent args, CancellableEntityEventArgs ev) + { + if (args.Target == null || args.Used == null) + return; + + if (TryComp(args.Target, out var targetCuffableComp) && targetCuffableComp.CuffedHandCount > 0 + || _mobState.IsIncapacitated(args.Target.Value)) + { + ev.Cancel(); + TryBuckle(args.Target.Value, args.User, args.Used.Value, popup: false); + } + } } diff --git a/Content.Shared/Buckle/SharedBuckleSystem.Interaction.cs b/Content.Shared/Buckle/SharedBuckleSystem.Interaction.cs index 463e0d5596..a4cfc9c8c4 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.Interaction.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.Interaction.cs @@ -1,4 +1,6 @@ -using Content.Shared.Buckle.Components; +using Content.Shared.Buckle.Components; +using Content.Shared.Cuffs.Components; +using Content.Shared.DoAfter; using Content.Shared.DragDrop; using Content.Shared.IdentityManagement; using Content.Shared.Interaction; @@ -32,7 +34,24 @@ public abstract partial class SharedBuckleSystem if (!StrapCanDragDropOn(uid, args.User, uid, args.Dragged, component)) return; - args.Handled = TryBuckle(args.Dragged, args.User, uid, popup: false); + if (args.Dragged == args.User) + { + if (!TryComp(args.User, out BuckleComponent? buckle)) + return; + + args.Handled = TryBuckle(args.User, args.User, uid, buckle); + } + else + { + var doAfterArgs = new DoAfterArgs(EntityManager, args.User, component.BuckleDoafterTime, new BuckleDoAfterEvent(), args.User, args.Dragged, uid) + { + BreakOnMove = true, + BreakOnDamage = true, + AttemptFrequency = AttemptFrequency.EveryTick + }; + + _doAfter.TryStartDoAfter(doAfterArgs); + } } private bool StrapCanDragDropOn( diff --git a/Content.Shared/Buckle/SharedBuckleSystem.cs b/Content.Shared/Buckle/SharedBuckleSystem.cs index 770fababde..d190f685ed 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.cs @@ -1,6 +1,7 @@ using Content.Shared.ActionBlocker; using Content.Shared.Administration.Logs; using Content.Shared.Alert; +using Content.Shared.DoAfter; using Content.Shared.Interaction; using Content.Shared.Mobs.Systems; using Content.Shared.Popups; @@ -36,6 +37,7 @@ public abstract partial class SharedBuckleSystem : EntitySystem [Dependency] private readonly StandingStateSystem _standing = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; [Dependency] private readonly SharedRotationVisualsSystem _rotationVisuals = default!; + [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; /// public override void Initialize()