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((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);
}
}
}