]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Add a sleep delay to Nocturine (NewStatusEffect version) (#40231)
authorSlamBamActionman <83650252+SlamBamActionman@users.noreply.github.com>
Fri, 26 Sep 2025 20:05:34 +0000 (22:05 +0200)
committerGitHub <noreply@github.com>
Fri, 26 Sep 2025 20:05:34 +0000 (13:05 -0700)
* Initial commit

* Minor fix

* Why is this uncommented here? Hmmm

* No wait this can't be here, oops

* Do better time

* Also guidebook

* Review changes

* Add rejuvination, fix mispredicts

Content.Shared/Bed/Sleep/SleepingSystem.cs
Content.Shared/EntityEffects/Effects/StatusEffects/ModifyStatusEffect.cs
Content.Shared/StatusEffectNew/Components/StatusEffectComponent.cs
Content.Shared/StatusEffectNew/StatusEffectSystem.API.cs
Content.Shared/StatusEffectNew/StatusEffectsSystem.cs
Resources/Locale/en-US/guidebook/chemistry/effects.ftl
Resources/Prototypes/Reagents/narcotics.yml

index 141a130053a0c849f06d49d0e7efb888c22574ad..eca6a8befa9b4194c22e16fa1446ffb2f3ef56ac 100644 (file)
@@ -14,6 +14,7 @@ using Content.Shared.Mobs;
 using Content.Shared.Mobs.Components;
 using Content.Shared.Pointing;
 using Content.Shared.Popups;
+using Content.Shared.Rejuvenate;
 using Content.Shared.Slippery;
 using Content.Shared.Sound;
 using Content.Shared.Sound.Components;
@@ -57,7 +58,7 @@ public sealed partial class SleepingSystem : EntitySystem
         SubscribeLocalEvent<SleepingComponent, DamageChangedEvent>(OnDamageChanged);
         SubscribeLocalEvent<SleepingComponent, EntityZombifiedEvent>(OnZombified);
         SubscribeLocalEvent<SleepingComponent, MobStateChangedEvent>(OnMobStateChanged);
-        SubscribeLocalEvent<SleepingComponent, MapInitEvent>(OnMapInit);
+        SubscribeLocalEvent<SleepingComponent, ComponentInit>(OnCompInit);
         SubscribeLocalEvent<SleepingComponent, SpeakAttemptEvent>(OnSpeakAttempt);
         SubscribeLocalEvent<SleepingComponent, CanSeeAttemptEvent>(OnSeeAttempt);
         SubscribeLocalEvent<SleepingComponent, PointAttemptEvent>(OnPointAttempt);
@@ -68,6 +69,7 @@ public sealed partial class SleepingSystem : EntitySystem
         SubscribeLocalEvent<SleepingComponent, InteractHandEvent>(OnInteractHand);
         SubscribeLocalEvent<SleepingComponent, StunEndAttemptEvent>(OnStunEndAttempt);
         SubscribeLocalEvent<SleepingComponent, StandUpAttemptEvent>(OnStandUpAttempt);
+        SubscribeLocalEvent<SleepingComponent, RejuvenateEvent>(OnRejuvenate);
 
         SubscribeLocalEvent<ForcedSleepingStatusEffectComponent, StatusEffectAppliedEvent>(OnStatusEffectApplied);
         SubscribeLocalEvent<SleepingComponent, UnbuckleAttemptEvent>(OnUnbuckleAttempt);
@@ -133,7 +135,7 @@ public sealed partial class SleepingSystem : EntitySystem
         RemComp<SpamEmitSoundComponent>(ent);
     }
 
-    private void OnMapInit(Entity<SleepingComponent> ent, ref MapInitEvent args)
+    private void OnCompInit(Entity<SleepingComponent> ent, ref ComponentInit args)
     {
         var ev = new SleepStateChangedEvent(true);
         RaiseLocalEvent(ent, ref ev);
@@ -185,6 +187,11 @@ public sealed partial class SleepingSystem : EntitySystem
         args.Cancelled = true;
     }
 
+    private void OnRejuvenate(Entity<SleepingComponent> ent, ref RejuvenateEvent args)
+    {
+        TryWaking((ent.Owner, ent.Comp), true);
+    }
+
     private void OnExamined(Entity<SleepingComponent> ent, ref ExaminedEvent args)
     {
         if (args.IsInDetailsRange)
index a232d34925d057f5ddae6feb636331ed750d560e..cb010b648c9932d04e5d09d7e5e3f507b866e72c 100644 (file)
@@ -19,6 +19,12 @@ public sealed partial class ModifyStatusEffect : EntityEffect
     [DataField]
     public float Time = 2.0f;
 
+    /// <summary>
+    /// Delay before the effect starts. If another effect is added with a shorter delay, it takes precedence.
+    /// </summary>
+    [DataField]
+    public float Delay = 0f;
+
     /// <remarks>
     /// true - refresh status effect time (update to greater value), false - accumulate status effect time.
     /// </remarks>
@@ -45,22 +51,30 @@ public sealed partial class ModifyStatusEffect : EntityEffect
         {
             case StatusEffectMetabolismType.Add:
                 if (Refresh)
-                    statusSys.TryUpdateStatusEffectDuration(args.TargetEntity, EffectProto, duration);
+                    statusSys.TryUpdateStatusEffectDuration(args.TargetEntity, EffectProto, duration, Delay > 0 ? TimeSpan.FromSeconds(Delay) : null);
                 else
-                    statusSys.TryAddStatusEffectDuration(args.TargetEntity, EffectProto, duration);
+                    statusSys.TryAddStatusEffectDuration(args.TargetEntity, EffectProto, duration, Delay > 0 ? TimeSpan.FromSeconds(Delay) : null);
                 break;
             case StatusEffectMetabolismType.Remove:
                 statusSys.TryAddTime(args.TargetEntity, EffectProto, -duration);
                 break;
             case StatusEffectMetabolismType.Set:
-                statusSys.TrySetStatusEffectDuration(args.TargetEntity, EffectProto, duration);
+                statusSys.TrySetStatusEffectDuration(args.TargetEntity, EffectProto, duration, TimeSpan.FromSeconds(Delay));
                 break;
         }
     }
 
     /// <inheritdoc />
-    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
-        => Loc.GetString(
+    protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) =>
+        Delay > 0
+        ? Loc.GetString(
+            "reagent-effect-guidebook-status-effect-delay",
+            ("chance", Probability),
+            ("type", Type),
+            ("time", Time),
+            ("key", prototype.Index(EffectProto).Name),
+            ("delay", Delay))
+        : Loc.GetString(
             "reagent-effect-guidebook-status-effect",
             ("chance", Probability),
             ("type", Type),
index 67ff8b3e616961263ad7beb0138343f249f44996..27764b3aee0adde82dd7b0b4a986dc921f6a1a33 100644 (file)
@@ -9,7 +9,7 @@ namespace Content.Shared.StatusEffectNew.Components;
 /// Marker component for all status effects - every status effect entity should have it.
 /// Provides a link between the effect and the affected entity, and some data common to all status effects.
 /// </summary>
-[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause]
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(fieldDeltas: true), AutoGenerateComponentPause]
 [Access(typeof(StatusEffectsSystem))]
 [EntityCategory("StatusEffects")]
 public sealed partial class StatusEffectComponent : Component
@@ -20,12 +20,24 @@ public sealed partial class StatusEffectComponent : Component
     [DataField, AutoNetworkedField]
     public EntityUid? AppliedTo;
 
+    /// <summary>
+    /// When this effect will start. Set to Timespan.Zero to start the effect immediately.
+    /// </summary>
+    [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoPausedField, AutoNetworkedField]
+    public TimeSpan StartEffectTime;
+
     /// <summary>
     /// When this effect will end. If Null, the effect lasts indefinitely.
     /// </summary>
     [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoPausedField, AutoNetworkedField]
     public TimeSpan? EndEffectTime;
 
+    /// <summary>
+    /// If true, this status effect has been applied. Used to ensure that <see cref="StatusEffectAppliedEvent"/> only fires once.
+    /// </summary>
+    [DataField, AutoNetworkedField]
+    public bool Applied;
+
     /// <summary>
     /// Whitelist, by which it is determined whether this status effect can be imposed on a particular entity.
     /// </summary>
index 56636c9601ff138b53460ea9c2fa2b46197a255e..905ad98c6c534ff3986357899bd6898b8d4b9f83 100644 (file)
@@ -13,13 +13,15 @@ public sealed partial class StatusEffectsSystem
     /// <param name="target">The target entity to which the effect should be added.</param>
     /// <param name="effectProto">ProtoId of the status effect entity. Make sure it has StatusEffectComponent on it.</param>
     /// <param name="duration">Duration of status effect. Leave null and the effect will be permanent until it is removed using <c>TryRemoveStatusEffect</c>.</param>
+    /// <param name="delay">The delay of the effect. If a start time already exists, the closest time takes precedence. Leave null for the effect to be instant.</param>
     /// <param name="statusEffect">The EntityUid of the status effect we have just created or null if it doesn't exist.</param>
     /// <returns>True if effect exists and its duration is set properly, false in case effect cannot be applied.</returns>
     public bool TryAddStatusEffectDuration(
         EntityUid target,
         EntProtoId effectProto,
         [NotNullWhen(true)] out EntityUid? statusEffect,
-        TimeSpan duration
+        TimeSpan duration,
+        TimeSpan? delay = null
     )
     {
         if (duration == TimeSpan.Zero)
@@ -30,18 +32,19 @@ public sealed partial class StatusEffectsSystem
 
         // We check to make sure time is greater than zero here because sometimes you want to use TryAddStatusEffect to remove duration instead...
         if (!TryGetStatusEffect(target, effectProto, out statusEffect))
-            return TryAddStatusEffect(target, effectProto, out statusEffect, duration);
+            return TryAddStatusEffect(target, effectProto, out statusEffect, duration, delay);
 
         AddStatusEffectTime(statusEffect.Value, duration);
+        UpdateStatusEffectDelay(statusEffect.Value, delay);
 
         return true;
     }
 
 
-    ///<inheritdoc cref="TryAddStatusEffectDuration(EntityUid,EntProtoId,out EntityUid?,TimeSpan)"/>
-    public bool TryAddStatusEffectDuration(EntityUid target, EntProtoId effectProto, TimeSpan duration)
+    ///<inheritdoc cref="TryAddStatusEffectDuration(EntityUid,EntProtoId,out EntityUid?,TimeSpan,TimeSpan?)"/>
+    public bool TryAddStatusEffectDuration(EntityUid target, EntProtoId effectProto, TimeSpan duration, TimeSpan? delay = null)
     {
-        return TryAddStatusEffectDuration(target, effectProto, out _, duration);
+        return TryAddStatusEffectDuration(target, effectProto, out _, duration, delay);
     }
 
     /// <summary>
@@ -51,13 +54,15 @@ public sealed partial class StatusEffectsSystem
     /// <param name="target">The target entity to which the effect should be added.</param>
     /// <param name="effectProto">ProtoId of the status effect entity. Make sure it has StatusEffectComponent on it.</param>
     /// <param name="duration">Duration of status effect. Leave null and the effect will be permanent until it is removed using <c>TryRemoveStatusEffect</c>.</param>
+    /// <param name="delay">The delay of the effect. If a start time already exists, the closest time takes precedence. Leave null for the effect to be instant.</param>
     /// <param name="statusEffect">The EntityUid of the status effect we have just created or null if it doesn't exist.</param>
     /// <returns>True if effect exists and its duration is set properly, false in case effect cannot be applied.</returns>
     public bool TrySetStatusEffectDuration(
         EntityUid target,
         EntProtoId effectProto,
         [NotNullWhen(true)] out EntityUid? statusEffect,
-        TimeSpan? duration = null
+        TimeSpan? duration = null,
+        TimeSpan? delay = null
     )
     {
         if (duration <= TimeSpan.Zero)
@@ -67,17 +72,22 @@ public sealed partial class StatusEffectsSystem
         }
 
         if (!TryGetStatusEffect(target, effectProto, out statusEffect))
-            return TryAddStatusEffect(target, effectProto, out statusEffect, duration);
+            return TryAddStatusEffect(target, effectProto, out statusEffect, duration, delay);
 
-        SetStatusEffectEndTime(statusEffect.Value, duration);
+        if (!_effectQuery.TryComp(statusEffect, out var statusEffectComponent))
+            return false;
+
+        var endTime = delay == null || statusEffectComponent.Applied ? _timing.CurTime + duration : _timing.CurTime + delay + duration;
+        SetStatusEffectEndTime(statusEffect.Value, endTime);
+        UpdateStatusEffectDelay(statusEffect.Value, delay);
 
         return true;
     }
 
-    /// <inheritdoc cref="TrySetStatusEffectDuration(EntityUid,EntProtoId,out EntityUid?,TimeSpan?)"/>
-    public bool TrySetStatusEffectDuration(EntityUid target, EntProtoId effectProto, TimeSpan? duration = null)
+    /// <inheritdoc cref="TrySetStatusEffectDuration(EntityUid,EntProtoId,out EntityUid?,TimeSpan?,TimeSpan?)"/>
+    public bool TrySetStatusEffectDuration(EntityUid target, EntProtoId effectProto, TimeSpan? duration = null, TimeSpan? delay = null)
     {
-        return TrySetStatusEffectDuration(target, effectProto, out _, duration);
+        return TrySetStatusEffectDuration(target, effectProto, out _, duration, delay);
     }
 
     /// <summary>
@@ -87,13 +97,15 @@ public sealed partial class StatusEffectsSystem
     /// <param name="target">The target entity to which the effect should be added.</param>
     /// <param name="effectProto">ProtoId of the status effect entity. Make sure it has StatusEffectComponent on it.</param>
     /// <param name="duration">Duration of status effect. Leave null and the effect will be permanent until it is removed using <c>TryRemoveStatusEffect</c>.</param>
+    /// <param name="delay">The delay of the effect. If a start time already exists, the closest time takes precedence. Leave null for the effect to be instant.</param>
     /// <param name="statusEffect">The EntityUid of the status effect we have just created or null if it doesn't exist.</param>
     /// <returns>True if effect exists and its duration is set properly, false in case effect cannot be applied.</returns>
     public bool TryUpdateStatusEffectDuration(
         EntityUid target,
         EntProtoId effectProto,
         [NotNullWhen(true)] out EntityUid? statusEffect,
-        TimeSpan? duration = null
+        TimeSpan? duration = null,
+        TimeSpan? delay = null
     )
     {
         if (duration <= TimeSpan.Zero)
@@ -103,17 +115,22 @@ public sealed partial class StatusEffectsSystem
         }
 
         if (!TryGetStatusEffect(target, effectProto, out statusEffect))
-            return TryAddStatusEffect(target, effectProto, out statusEffect, duration);
+            return TryAddStatusEffect(target, effectProto, out statusEffect, duration, delay);
+
+        if (!_effectQuery.TryComp(statusEffect, out var statusEffectComponent))
+            return false;
 
-        UpdateStatusEffectTime(statusEffect.Value, duration);
+        var endTime = delay == null || statusEffectComponent.Applied ? duration : delay + duration;
+        UpdateStatusEffectTime(statusEffect.Value, endTime);
+        UpdateStatusEffectDelay(statusEffect.Value, delay);
 
         return true;
     }
 
-    /// <inheritdoc cref="TryUpdateStatusEffectDuration(EntityUid,EntProtoId,out EntityUid?,TimeSpan?)"/>
-    public bool TryUpdateStatusEffectDuration(EntityUid target, EntProtoId effectProto, TimeSpan? duration = null)
+    /// <inheritdoc cref="TryUpdateStatusEffectDuration(EntityUid,EntProtoId,out EntityUid?,TimeSpan?,TimeSpan?)"/>
+    public bool TryUpdateStatusEffectDuration(EntityUid target, EntProtoId effectProto, TimeSpan? duration = null, TimeSpan? delay = null)
     {
-        return TryUpdateStatusEffectDuration(target, effectProto, out _, duration);
+        return TryUpdateStatusEffectDuration(target, effectProto, out _, duration, delay);
     }
 
     /// <summary>
@@ -193,7 +210,7 @@ public sealed partial class StatusEffectsSystem
     public bool TryGetTime(
         EntityUid uid,
         EntProtoId effectProto,
-        out (EntityUid EffectEnt, TimeSpan? EndEffectTime) time,
+        out (EntityUid EffectEnt, TimeSpan? EndEffectTime, TimeSpan? StartEffectTime) time,
         StatusEffectContainerComponent? container = null
     )
     {
@@ -209,7 +226,7 @@ public sealed partial class StatusEffectsSystem
                 if (!_effectQuery.TryComp(effect, out var effectComp))
                     return false;
 
-                time = (effect, effectComp.EndEffectTime);
+                time = (effect, effectComp.EndEffectTime, effectComp.StartEffectTime);
                 return true;
             }
         }
index 446b3fd3b1ae12d8365dc062fac9cebf507a01e2..966878b4e38e1c49b0d6f6dea28a7d613ad38882 100644 (file)
@@ -46,6 +46,8 @@ public sealed partial class StatusEffectsSystem : EntitySystem
         var query = EntityQueryEnumerator<StatusEffectComponent>();
         while (query.MoveNext(out var ent, out var effect))
         {
+            TryApplyStatusEffect((ent, effect));
+
             if (effect.EndEffectTime is null)
                 continue;
 
@@ -88,9 +90,6 @@ public sealed partial class StatusEffectsSystem : EntitySystem
             statusComp.AppliedTo = ent;
             Dirty(args.Entity, statusComp);
         }
-
-        var ev = new StatusEffectAppliedEvent(ent);
-        RaiseLocalEvent(args.Entity, ref ev);
     }
 
     private void OnEntityRemoved(Entity<StatusEffectContainerComponent> ent, ref EntRemovedFromContainerMessage args)
@@ -121,6 +120,29 @@ public sealed partial class StatusEffectsSystem : EntitySystem
         PredictedQueueDel(ent.Owner);
     }
 
+    /// <summary>
+    /// Applies the status effect, i.e. starts it after it has been added. Ensures delayed start times trigger when they should.
+    /// </summary>
+    /// <param name="statusEffectEnt">The status effect entity.</param>
+    /// <returns>Returns true if the effect is applied.</returns>
+    private bool TryApplyStatusEffect(Entity<StatusEffectComponent> statusEffectEnt)
+    {
+        if (!statusEffectEnt.Comp.Applied &&
+            statusEffectEnt.Comp.AppliedTo != null &&
+            _timing.CurTime >= statusEffectEnt.Comp.StartEffectTime)
+        {
+            var ev = new StatusEffectAppliedEvent(statusEffectEnt.Comp.AppliedTo.Value);
+            RaiseLocalEvent(statusEffectEnt, ref ev);
+
+            statusEffectEnt.Comp.Applied = true;
+
+            DirtyField(statusEffectEnt, statusEffectEnt.Comp, nameof(StatusEffectComponent.StartEffectTime));
+            return true;
+        }
+
+        return false;
+    }
+
     public bool CanAddStatusEffect(EntityUid uid, EntProtoId effectProto)
     {
         if (!_proto.Resolve(effectProto, out var effectProtoData))
@@ -148,12 +170,14 @@ public sealed partial class StatusEffectsSystem : EntitySystem
     /// <param name="target">The target entity to which the effect should be added.</param>
     /// <param name="effectProto">ProtoId of the status effect entity. Make sure it has StatusEffectComponent on it.</param>
     /// <param name="duration">Duration of status effect. Leave null and the effect will be permanent until it is removed using <c>TryRemoveStatusEffect</c>.</param>
+    /// <param name="delay">The delay of the effect. Leave null and the effect will be immediate.</param>
     /// <param name="statusEffect">The EntityUid of the status effect we have just created or null if we couldn't create one.</param>
     private bool TryAddStatusEffect(
         EntityUid target,
         EntProtoId effectProto,
         [NotNullWhen(true)] out EntityUid? statusEffect,
-        TimeSpan? duration = null
+        TimeSpan? duration = null,
+        TimeSpan? delay = null
     )
     {
         statusEffect = null;
@@ -177,7 +201,13 @@ public sealed partial class StatusEffectsSystem : EntitySystem
             return false;
 
         statusEffect = effect;
-        SetStatusEffectEndTime((effect.Value, effectComp), _timing.CurTime + duration);
+
+        var endTime = delay == null ? _timing.CurTime + duration : _timing.CurTime + delay + duration;
+        SetStatusEffectEndTime((effect.Value, effectComp), endTime);
+        var startTime = delay == null ? TimeSpan.Zero : _timing.CurTime + delay.Value;
+        SetStatusEffectStartTime(effect.Value, startTime);
+
+        TryApplyStatusEffect((effect.Value, effectComp));
 
         return true;
     }
@@ -204,6 +234,28 @@ public sealed partial class StatusEffectsSystem : EntitySystem
         SetStatusEffectEndTime(effect, newEndTime);
     }
 
+    private void UpdateStatusEffectDelay(Entity<StatusEffectComponent?> effect, TimeSpan? delay)
+    {
+        if (!_effectQuery.Resolve(effect, ref effect.Comp))
+            return;
+
+        // It's already started!
+        if (_timing.CurTime >= effect.Comp.StartEffectTime)
+            return;
+
+        var newStartTime = TimeSpan.Zero;
+
+        if (delay is not null)
+        {
+            // Don't update time to a smaller timespan...
+            newStartTime = _timing.CurTime + delay.Value;
+            if (effect.Comp.StartEffectTime < newStartTime)
+                return;
+        }
+
+        SetStatusEffectStartTime(effect, newStartTime);
+    }
+
     private void AddStatusEffectTime(Entity<StatusEffectComponent?> effect, TimeSpan delta)
     {
         if (!_effectQuery.Resolve(effect, ref effect.Comp))
@@ -233,7 +285,26 @@ public sealed partial class StatusEffectsSystem : EntitySystem
         var ev = new StatusEffectEndTimeUpdatedEvent(appliedTo, endTime);
         RaiseLocalEvent(ent, ref ev);
 
-        Dirty(ent);
+        DirtyField(ent, ent.Comp, nameof(StatusEffectComponent.EndEffectTime));
+    }
+
+    private void SetStatusEffectStartTime(Entity<StatusEffectComponent?> ent, TimeSpan startTime)
+    {
+        if (!_effectQuery.Resolve(ent, ref ent.Comp))
+            return;
+
+        if (ent.Comp.StartEffectTime == startTime)
+            return;
+
+        ent.Comp.StartEffectTime = startTime;
+
+        if (ent.Comp.AppliedTo is not { } appliedTo)
+            return; // Not much we can do!
+
+        var ev = new StatusEffectStartTimeUpdatedEvent(appliedTo, startTime);
+        RaiseLocalEvent(ent, ref ev);
+
+        DirtyField(ent, ent.Comp, nameof(StatusEffectComponent.StartEffectTime));
     }
 }
 
@@ -262,3 +333,11 @@ public record struct BeforeStatusEffectAddedEvent(EntProtoId Effect, bool Cancel
 /// <param name="EndTime">The new end time of the status effect, included for convenience.</param>
 [ByRefEvent]
 public record struct StatusEffectEndTimeUpdatedEvent(EntityUid Target, TimeSpan? EndTime);
+
+/// <summary>
+/// Raised on an effect entity when its <see cref="StatusEffectComponent.StartEffectTime"/> is updated in any way.
+/// </summary>
+/// <param name="Target">The entity the effect is attached to.</param>
+/// <param name="StartTime">The new start time of the status effect, included for convenience.</param>
+[ByRefEvent]
+public record struct StatusEffectStartTimeUpdatedEvent(EntityUid Target, TimeSpan? StartTime);
index cd7bb21af2d45cb0e3b8dc388d176f7587f62043..1ab89f89a34f1532eb41770f4298b3be5fc5f577 100644 (file)
@@ -118,6 +118,22 @@ reagent-effect-guidebook-status-effect =
                 } {NATURALFIXED($time, 3)} {MANY("second", $time)} of {LOC($key)}
     }
 
+reagent-effect-guidebook-status-effect-delay =
+    { $type ->
+        [add]   { $chance ->
+                    [1] Causes
+                    *[other] cause
+                } {LOC($key)} for at least {NATURALFIXED($time, 3)} {MANY("second", $time)} with accumulation
+        *[set]  { $chance ->
+                    [1] Causes
+                    *[other] cause
+                } {LOC($key)} for at least {NATURALFIXED($time, 3)} {MANY("second", $time)} without accumulation
+        [remove]{ $chance ->
+                    [1] Removes
+                    *[other] remove
+                } {NATURALFIXED($time, 3)} {MANY("second", $time)} of {LOC($key)}
+    } after a {NATURALFIXED($delay, 3)} second delay
+
 reagent-effect-guidebook-set-solution-temperature-effect =
     { $chance ->
         [1] Sets
index 7f84790561a6b7a77eaf5bc65a8ba5a878ceed86..3658a50f50025179cd4270eb7a4b4ea1ee85f35e 100644 (file)
           min: 8
         effectProto: StatusEffectForcedSleeping
         time: 3
+        delay: 6
         type: Add
 
 - type: reagent