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;
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;
+++ /dev/null
-using System.Numerics;
-
-namespace Content.Server.Traits.Assorted;
-
-/// <summary>
-/// This is used for the narcolepsy trait.
-/// </summary>
-[RegisterComponent, Access(typeof(NarcolepsySystem))]
-public sealed partial class NarcolepsyComponent : Component
-{
- /// <summary>
- /// The random time between incidents, (min, max).
- /// </summary>
- [DataField("timeBetweenIncidents", required: true)]
- public Vector2 TimeBetweenIncidents { get; private set; }
-
- /// <summary>
- /// The duration of incidents, (min, max).
- /// </summary>
- [DataField("durationOfIncident", required: true)]
- public Vector2 DurationOfIncident { get; private set; }
-
- public float NextIncidentTime;
-}
+++ /dev/null
-using Content.Shared.Bed.Sleep;
-using Content.Shared.StatusEffectNew;
-using Robust.Shared.Random;
-
-namespace Content.Server.Traits.Assorted;
-
-/// <summary>
-/// This handles narcolepsy, causing the affected to fall asleep uncontrollably at a random interval.
-/// </summary>
-public sealed class NarcolepsySystem : EntitySystem
-{
- [Dependency] private readonly StatusEffectsSystem _statusEffects = default!;
- [Dependency] private readonly IRobustRandom _random = default!;
-
- /// <inheritdoc/>
- public override void Initialize()
- {
- SubscribeLocalEvent<NarcolepsyComponent, ComponentStartup>(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<NarcolepsyComponent>();
- 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));
- }
- }
-}
/// The # of seconds the effect resets the narcolepsy timer to
/// </summary>
[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));
--- /dev/null
+using Robust.Shared.GameStates;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
+
+namespace Content.Shared.Traits.Assorted;
+
+/// <summary>
+/// This is used for the narcolepsy trait.
+/// </summary>
+[RegisterComponent, NetworkedComponent]
+[AutoGenerateComponentState(fieldDeltas: true), AutoGenerateComponentPause]
+[Access(typeof(NarcolepsySystem))]
+public sealed partial class NarcolepsyComponent : Component
+{
+ /// <summary>
+ /// The maximum time between incidents.
+ /// </summary>
+ [DataField(required: true), AutoNetworkedField]
+ public TimeSpan MaxTimeBetweenIncidents;
+
+ /// <summary>
+ /// The minimum time between incidents.
+ /// </summary>
+ [DataField(required: true), AutoNetworkedField]
+ public TimeSpan MinTimeBetweenIncidents;
+
+ /// <summary>
+ /// The maximum duration of incidents.
+ /// </summary>
+ [DataField(required: true), AutoNetworkedField]
+ public TimeSpan MaxDurationOfIncident;
+
+ /// <summary>
+ /// The minimum duration of incidents.
+ /// </summary>
+ [DataField(required: true), AutoNetworkedField]
+ public TimeSpan MinDurationOfIncident;
+
+ /// <summary>
+ /// Next time indcident happens.
+ /// </summary>
+ [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
+ [AutoNetworkedField, AutoPausedField]
+ public TimeSpan NextIncidentTime = TimeSpan.Zero;
+}
--- /dev/null
+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;
+
+/// <summary>
+/// This handles narcolepsy, causing the affected to fall asleep uncontrollably at a random interval.
+/// </summary>
+public sealed class NarcolepsySystem : EntitySystem
+{
+ [Dependency] private readonly StatusEffectsSystem _statusEffects = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly IGameTiming _timing = default!;
+
+ /// <inheritdoc/>
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent<NarcolepsyComponent, MapInitEvent>(OnMapInit);
+ }
+
+ private void OnMapInit(Entity<NarcolepsyComponent> 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));
+ }
+
+ /// <summary>
+ /// Changes the time until the next incident.
+ /// </summary>
+ public void AdjustNarcolepsyTimer(Entity<NarcolepsyComponent?> 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<NarcolepsyComponent>();
+
+ 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);
+ }
+ }
+}
category: Disabilities
components:
- type: Narcolepsy
- timeBetweenIncidents: 300, 600
- durationOfIncident: 10, 30
+ maxTimeBetweenIncidents: 600
+ minTimeBetweenIncidents: 300
+ maxDurationOfIncident: 30
+ minDurationOfIncident: 10
- type: trait
id: Unrevivable