From 972adcee21d9b25c2ca63b90c2649bd564fb6f9a Mon Sep 17 00:00:00 2001
From: Winkarst-cpu <74284083+Winkarst-cpu@users.noreply.github.com>
Date: Tue, 16 Sep 2025 21:29:48 +0300
Subject: [PATCH] ``NarcolepsySystem`` refactor (#40305)
* Refactor
* Update
* Update
---
.../EntityEffects/EntityEffectSystem.cs | 2 +-
.../Traits/Assorted/NarcolepsyComponent.cs | 24 -------
.../Traits/Assorted/NarcolepsySystem.cs | 59 ----------------
.../EntityEffects/Effects/ResetNarcolepsy.cs | 2 +-
.../Traits/Assorted/NarcolepsyComponent.cs | 44 ++++++++++++
.../Traits/Assorted/NarcolepsySystem.cs | 69 +++++++++++++++++++
Resources/Prototypes/Traits/disabilities.yml | 6 +-
7 files changed, 119 insertions(+), 87 deletions(-)
delete mode 100644 Content.Server/Traits/Assorted/NarcolepsyComponent.cs
delete mode 100644 Content.Server/Traits/Assorted/NarcolepsySystem.cs
create mode 100644 Content.Shared/Traits/Assorted/NarcolepsyComponent.cs
create mode 100644 Content.Shared/Traits/Assorted/NarcolepsySystem.cs
diff --git a/Content.Server/EntityEffects/EntityEffectSystem.cs b/Content.Server/EntityEffects/EntityEffectSystem.cs
index 4e447c7fab..3a86941a34 100644
--- a/Content.Server/EntityEffects/EntityEffectSystem.cs
+++ b/Content.Server/EntityEffects/EntityEffectSystem.cs
@@ -18,7 +18,6 @@ using Content.Server.Speech.Components;
using Content.Server.Spreader;
using Content.Server.Temperature.Components;
using Content.Server.Temperature.Systems;
-using Content.Server.Traits.Assorted;
using Content.Server.Zombies;
using Content.Shared.Atmos;
using Content.Shared.Atmos.Components;
@@ -33,6 +32,7 @@ using Content.Shared.Maps;
using Content.Shared.Mind.Components;
using Content.Shared.Popups;
using Content.Shared.Random;
+using Content.Shared.Traits.Assorted;
using Content.Shared.Zombies;
using Robust.Server.GameObjects;
using Robust.Shared.Audio;
diff --git a/Content.Server/Traits/Assorted/NarcolepsyComponent.cs b/Content.Server/Traits/Assorted/NarcolepsyComponent.cs
deleted file mode 100644
index efa3458495..0000000000
--- a/Content.Server/Traits/Assorted/NarcolepsyComponent.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using System.Numerics;
-
-namespace Content.Server.Traits.Assorted;
-
-///
-/// This is used for the narcolepsy trait.
-///
-[RegisterComponent, Access(typeof(NarcolepsySystem))]
-public sealed partial class NarcolepsyComponent : Component
-{
- ///
- /// The random time between incidents, (min, max).
- ///
- [DataField("timeBetweenIncidents", required: true)]
- public Vector2 TimeBetweenIncidents { get; private set; }
-
- ///
- /// The duration of incidents, (min, max).
- ///
- [DataField("durationOfIncident", required: true)]
- public Vector2 DurationOfIncident { get; private set; }
-
- public float NextIncidentTime;
-}
diff --git a/Content.Server/Traits/Assorted/NarcolepsySystem.cs b/Content.Server/Traits/Assorted/NarcolepsySystem.cs
deleted file mode 100644
index 159e953369..0000000000
--- a/Content.Server/Traits/Assorted/NarcolepsySystem.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-using Content.Shared.Bed.Sleep;
-using Content.Shared.StatusEffectNew;
-using Robust.Shared.Random;
-
-namespace Content.Server.Traits.Assorted;
-
-///
-/// This handles narcolepsy, causing the affected to fall asleep uncontrollably at a random interval.
-///
-public sealed class NarcolepsySystem : EntitySystem
-{
- [Dependency] private readonly StatusEffectsSystem _statusEffects = default!;
- [Dependency] private readonly IRobustRandom _random = default!;
-
- ///
- public override void Initialize()
- {
- SubscribeLocalEvent(SetupNarcolepsy);
- }
-
- private void SetupNarcolepsy(EntityUid uid, NarcolepsyComponent component, ComponentStartup args)
- {
- component.NextIncidentTime =
- _random.NextFloat(component.TimeBetweenIncidents.X, component.TimeBetweenIncidents.Y);
- }
-
- public void AdjustNarcolepsyTimer(EntityUid uid, int TimerReset, NarcolepsyComponent? narcolepsy = null)
- {
- if (!Resolve(uid, ref narcolepsy, false))
- return;
-
- narcolepsy.NextIncidentTime = TimerReset;
- }
-
- public override void Update(float frameTime)
- {
- base.Update(frameTime);
-
- var query = EntityQueryEnumerator();
- while (query.MoveNext(out var uid, out var narcolepsy))
- {
- narcolepsy.NextIncidentTime -= frameTime;
-
- if (narcolepsy.NextIncidentTime >= 0)
- continue;
-
- // Set the new time.
- narcolepsy.NextIncidentTime +=
- _random.NextFloat(narcolepsy.TimeBetweenIncidents.X, narcolepsy.TimeBetweenIncidents.Y);
-
- var duration = _random.NextFloat(narcolepsy.DurationOfIncident.X, narcolepsy.DurationOfIncident.Y);
-
- // Make sure the sleep time doesn't cut into the time to next incident.
- narcolepsy.NextIncidentTime += duration;
-
- _statusEffects.TryAddStatusEffectDuration(uid, SleepingSystem.StatusEffectForcedSleeping, TimeSpan.FromSeconds(duration));
- }
- }
-}
diff --git a/Content.Shared/EntityEffects/Effects/ResetNarcolepsy.cs b/Content.Shared/EntityEffects/Effects/ResetNarcolepsy.cs
index 71d228aece..009cf914d5 100644
--- a/Content.Shared/EntityEffects/Effects/ResetNarcolepsy.cs
+++ b/Content.Shared/EntityEffects/Effects/ResetNarcolepsy.cs
@@ -12,7 +12,7 @@ public sealed partial class ResetNarcolepsy : EventEntityEffect
/// The # of seconds the effect resets the narcolepsy timer to
///
[DataField("TimerReset")]
- public int TimerReset = 600;
+ public TimeSpan TimerReset = TimeSpan.FromSeconds(600);
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
=> Loc.GetString("reagent-effect-guidebook-reset-narcolepsy", ("chance", Probability));
diff --git a/Content.Shared/Traits/Assorted/NarcolepsyComponent.cs b/Content.Shared/Traits/Assorted/NarcolepsyComponent.cs
new file mode 100644
index 0000000000..ae94908925
--- /dev/null
+++ b/Content.Shared/Traits/Assorted/NarcolepsyComponent.cs
@@ -0,0 +1,44 @@
+using Robust.Shared.GameStates;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
+
+namespace Content.Shared.Traits.Assorted;
+
+///
+/// This is used for the narcolepsy trait.
+///
+[RegisterComponent, NetworkedComponent]
+[AutoGenerateComponentState(fieldDeltas: true), AutoGenerateComponentPause]
+[Access(typeof(NarcolepsySystem))]
+public sealed partial class NarcolepsyComponent : Component
+{
+ ///
+ /// The maximum time between incidents.
+ ///
+ [DataField(required: true), AutoNetworkedField]
+ public TimeSpan MaxTimeBetweenIncidents;
+
+ ///
+ /// The minimum time between incidents.
+ ///
+ [DataField(required: true), AutoNetworkedField]
+ public TimeSpan MinTimeBetweenIncidents;
+
+ ///
+ /// The maximum duration of incidents.
+ ///
+ [DataField(required: true), AutoNetworkedField]
+ public TimeSpan MaxDurationOfIncident;
+
+ ///
+ /// The minimum duration of incidents.
+ ///
+ [DataField(required: true), AutoNetworkedField]
+ public TimeSpan MinDurationOfIncident;
+
+ ///
+ /// Next time indcident happens.
+ ///
+ [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
+ [AutoNetworkedField, AutoPausedField]
+ public TimeSpan NextIncidentTime = TimeSpan.Zero;
+}
diff --git a/Content.Shared/Traits/Assorted/NarcolepsySystem.cs b/Content.Shared/Traits/Assorted/NarcolepsySystem.cs
new file mode 100644
index 0000000000..7bce80c703
--- /dev/null
+++ b/Content.Shared/Traits/Assorted/NarcolepsySystem.cs
@@ -0,0 +1,69 @@
+using Content.Shared.Bed.Sleep;
+using Content.Shared.Random.Helpers;
+using Content.Shared.StatusEffectNew;
+using Robust.Shared.Random;
+using Robust.Shared.Timing;
+
+namespace Content.Shared.Traits.Assorted;
+
+///
+/// This handles narcolepsy, causing the affected to fall asleep uncontrollably at a random interval.
+///
+public sealed class NarcolepsySystem : EntitySystem
+{
+ [Dependency] private readonly StatusEffectsSystem _statusEffects = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly IGameTiming _timing = default!;
+
+ ///
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnMapInit);
+ }
+
+ private void OnMapInit(Entity ent, ref MapInitEvent args)
+ {
+ ent.Comp.NextIncidentTime = _timing.CurTime + _random.Next(ent.Comp.MinTimeBetweenIncidents, ent.Comp.MaxTimeBetweenIncidents);
+ DirtyField(ent, ent.Comp, nameof(ent.Comp.NextIncidentTime));
+ }
+
+ ///
+ /// Changes the time until the next incident.
+ ///
+ public void AdjustNarcolepsyTimer(Entity ent, TimeSpan time)
+ {
+ if (!Resolve(ent, ref ent.Comp, false))
+ return;
+
+ ent.Comp.NextIncidentTime = _timing.CurTime + time;
+ DirtyField(ent, ent.Comp, nameof(ent.Comp.NextIncidentTime));
+ }
+
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ var query = EntityQueryEnumerator();
+
+ while (query.MoveNext(out var uid, out var narcolepsy))
+ {
+ if (narcolepsy.NextIncidentTime > _timing.CurTime)
+ continue;
+
+ // TODO: Replace with RandomPredicted once the engine PR is merged
+ var seed = SharedRandomExtensions.HashCodeCombine(new() { (int)_timing.CurTick.Value, GetNetEntity(uid).Id });
+ var rand = new System.Random(seed);
+
+ var duration = narcolepsy.MinDurationOfIncident + (narcolepsy.MaxDurationOfIncident - narcolepsy.MinDurationOfIncident) * rand.NextDouble();
+
+ // Set the new time.
+ narcolepsy.NextIncidentTime +=
+ narcolepsy.MinTimeBetweenIncidents + (narcolepsy.MaxTimeBetweenIncidents - narcolepsy.MinTimeBetweenIncidents) * rand.NextDouble() + duration;
+ DirtyField(uid, narcolepsy, nameof(narcolepsy.NextIncidentTime));
+
+ _statusEffects.TryAddStatusEffectDuration(uid, SleepingSystem.StatusEffectForcedSleeping, duration);
+ }
+ }
+}
diff --git a/Resources/Prototypes/Traits/disabilities.yml b/Resources/Prototypes/Traits/disabilities.yml
index c5356149f2..51993d3dd1 100644
--- a/Resources/Prototypes/Traits/disabilities.yml
+++ b/Resources/Prototypes/Traits/disabilities.yml
@@ -32,8 +32,10 @@
category: Disabilities
components:
- type: Narcolepsy
- timeBetweenIncidents: 300, 600
- durationOfIncident: 10, 30
+ maxTimeBetweenIncidents: 600
+ minTimeBetweenIncidents: 300
+ maxDurationOfIncident: 30
+ minDurationOfIncident: 10
- type: trait
id: Unrevivable