diff --git a/Content.Shared/Lock/LockComponent.cs b/Content.Shared/Lock/LockComponent.cs
index 174818c4e8..b3c4659749 100644
--- a/Content.Shared/Lock/LockComponent.cs
+++ b/Content.Shared/Lock/LockComponent.cs
@@ -1,3 +1,4 @@
+using Content.Shared.DoAfter;
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
@@ -50,6 +51,26 @@ public sealed partial class LockComponent : Component
[DataField("breakOnEmag")]
[AutoNetworkedField]
public bool BreakOnEmag = true;
+
+ ///
+ /// Amount of do-after time needed to lock the entity.
+ ///
+ ///
+ /// If set to zero, no do-after will be used.
+ ///
+ [DataField]
+ [AutoNetworkedField]
+ public TimeSpan LockTime;
+
+ ///
+ /// Amount of do-after time needed to unlock the entity.
+ ///
+ ///
+ /// If set to zero, no do-after will be used.
+ ///
+ [DataField]
+ [AutoNetworkedField]
+ public TimeSpan UnlockTime;
}
///
@@ -64,3 +85,31 @@ public record struct LockToggleAttemptEvent(EntityUid User, bool Silent = false,
///
[ByRefEvent]
public readonly record struct LockToggledEvent(bool Locked);
+
+///
+/// Used to lock a lockable entity that has a lock time configured.
+///
+///
+///
+[Serializable, NetSerializable]
+public sealed partial class LockDoAfter : DoAfterEvent
+{
+ public override DoAfterEvent Clone()
+ {
+ return this;
+ }
+}
+
+///
+/// Used to unlock a lockable entity that has an unlock time configured.
+///
+///
+///
+[Serializable, NetSerializable]
+public sealed partial class UnlockDoAfter : DoAfterEvent
+{
+ public override DoAfterEvent Clone()
+ {
+ return this;
+ }
+}
diff --git a/Content.Shared/Lock/LockSystem.cs b/Content.Shared/Lock/LockSystem.cs
index 7babc6a9c0..e5f53b4080 100644
--- a/Content.Shared/Lock/LockSystem.cs
+++ b/Content.Shared/Lock/LockSystem.cs
@@ -1,5 +1,6 @@
using Content.Shared.Access.Components;
using Content.Shared.Access.Systems;
+using Content.Shared.DoAfter;
using Content.Shared.Emag.Systems;
using Content.Shared.Examine;
using Content.Shared.Hands.Components;
@@ -26,6 +27,7 @@ public sealed class LockSystem : EntitySystem
[Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedPopupSystem _sharedPopupSystem = default!;
+ [Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
///
public override void Initialize()
@@ -38,6 +40,8 @@ public sealed class LockSystem : EntitySystem
SubscribeLocalEvent(OnExamined);
SubscribeLocalEvent>(AddToggleLockVerb);
SubscribeLocalEvent(OnEmagged);
+ SubscribeLocalEvent(OnDoAfterLock);
+ SubscribeLocalEvent(OnDoAfterUnlock);
}
private void OnStartup(EntityUid uid, LockComponent lockComp, ComponentStartup args)
@@ -86,11 +90,15 @@ public sealed class LockSystem : EntitySystem
///
/// Attmempts to lock a given entity
///
+ ///
+ /// If the lock is set to require a do-after, a true return value only indicates that the do-after started.
+ ///
/// The entity with the lock
/// The person trying to lock it
///
+ /// If true, skip the required do-after if one is configured.
/// If locking was successful
- public bool TryLock(EntityUid uid, EntityUid user, LockComponent? lockComp = null)
+ public bool TryLock(EntityUid uid, EntityUid user, LockComponent? lockComp = null, bool skipDoAfter = false)
{
if (!Resolve(uid, ref lockComp))
return false;
@@ -101,6 +109,16 @@ public sealed class LockSystem : EntitySystem
if (!HasUserAccess(uid, user, quiet: false))
return false;
+ if (!skipDoAfter && lockComp.LockTime != TimeSpan.Zero)
+ {
+ return _doAfter.TryStartDoAfter(
+ new DoAfterArgs(EntityManager, user, lockComp.LockTime, new LockDoAfter(), uid, uid)
+ {
+ BreakOnDamage = true, BreakOnTargetMove = true, BreakOnUserMove = true, RequireCanInteract = true,
+ NeedHand = true
+ });
+ }
+
_sharedPopupSystem.PopupClient(Loc.GetString("lock-comp-do-lock-success",
("entityName", Identity.Name(uid, EntityManager))), uid, user);
_audio.PlayPredicted(lockComp.LockSound, uid, user);
@@ -117,6 +135,9 @@ public sealed class LockSystem : EntitySystem
///
/// Forces a given entity to be unlocked
///
+ ///
+ /// This does not process do-after times.
+ ///
/// The entity with the lock
/// The person unlocking it. Can be null
///
@@ -145,11 +166,15 @@ public sealed class LockSystem : EntitySystem
///
/// Attmempts to unlock a given entity
///
+ ///
+ /// If the lock is set to require a do-after, a true return value only indicates that the do-after started.
+ ///
/// The entity with the lock
/// The person trying to unlock it
///
+ /// If true, skip the required do-after if one is configured.
/// If locking was successful
- public bool TryUnlock(EntityUid uid, EntityUid user, LockComponent? lockComp = null)
+ public bool TryUnlock(EntityUid uid, EntityUid user, LockComponent? lockComp = null, bool skipDoAfter = false)
{
if (!Resolve(uid, ref lockComp))
return false;
@@ -160,6 +185,16 @@ public sealed class LockSystem : EntitySystem
if (!HasUserAccess(uid, user, quiet: false))
return false;
+ if (!skipDoAfter && lockComp.UnlockTime != TimeSpan.Zero)
+ {
+ return _doAfter.TryStartDoAfter(
+ new DoAfterArgs(EntityManager, user, lockComp.LockTime, new UnlockDoAfter(), uid, uid)
+ {
+ BreakOnDamage = true, BreakOnTargetMove = true, BreakOnUserMove = true, RequireCanInteract = true,
+ NeedHand = true
+ });
+ }
+
Unlock(uid, user, lockComp);
return true;
}
@@ -219,5 +254,21 @@ public sealed class LockSystem : EntitySystem
RemComp(uid); //Literally destroys the lock as a tell it was emagged
args.Handled = true;
}
+
+ private void OnDoAfterLock(EntityUid uid, LockComponent component, LockDoAfter args)
+ {
+ if (args.Cancelled)
+ return;
+
+ TryLock(uid, args.User, skipDoAfter: true);
+ }
+
+ private void OnDoAfterUnlock(EntityUid uid, LockComponent component, UnlockDoAfter args)
+ {
+ if (args.Cancelled)
+ return;
+
+ TryUnlock(uid, args.User, skipDoAfter: true);
+ }
}
diff --git a/Resources/Prototypes/Entities/Objects/Specific/Security/barrier.yml b/Resources/Prototypes/Entities/Objects/Specific/Security/barrier.yml
index 035185487d..3a31edf7f1 100644
--- a/Resources/Prototypes/Entities/Objects/Specific/Security/barrier.yml
+++ b/Resources/Prototypes/Entities/Objects/Specific/Security/barrier.yml
@@ -45,6 +45,8 @@
- type: Lock
locked: false
lockOnClick: true # toggle lock just by clicking on barrier
+ lockTime: 5
+ unlockTime: 5
- type: Damageable
damageContainer: Inorganic
damageModifierSet: Metallic