using Content.Shared._CP14.DayCycle; using Content.Shared._CP14.DayCycle.Components; using Robust.Shared.Map.Components; using Robust.Shared.Random; using Robust.Shared.Timing; namespace Content.Server._CP14.DayCycle; public sealed partial class CP14DayCycleSystem : CP14SharedDayCycleSystem { public const int MinTimeEntryCount = 2; private const float MaxTimeDiff = 0.05f; [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IRobustRandom _random = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnMapInitDayCycle); } private void OnMapInitDayCycle(Entity dayCycle, ref MapInitEvent args) { Init(dayCycle); if (dayCycle.Comp.StartWithRandomEntry && dayCycle.Comp.TimeEntries.Count > 1) SetTimeEntry(dayCycle, _random.Next(dayCycle.Comp.TimeEntries.Count)); } public override void Update(float frameTime) { base.Update(frameTime); var dayCycleQuery = EntityQueryEnumerator(); while (dayCycleQuery.MoveNext(out var uid, out var dayCycle, out var mapLight)) { var entity = new Entity(uid, dayCycle, mapLight); if (dayCycle.TimeEntries.Count < MinTimeEntryCount) continue; SetAmbientColor((entity, entity), GetCurrentColor(entity, _timing.CurTime.TotalSeconds)); if (_timing.CurTime <= dayCycle.EntryEndTime) continue; SetTimeEntry((uid, dayCycle), dayCycle.NextTimeEntryIndex); } } public void Init(Entity dayCycle) { if (dayCycle.Comp.TimeEntries.Count < MinTimeEntryCount) { Log.Warning($"Attempting to init a daily cycle with the number of time entries less than {MinTimeEntryCount}"); return; } dayCycle.Comp.CurrentTimeEntryIndex = 0; dayCycle.Comp.EntryStartTime = _timing.CurTime; dayCycle.Comp.EntryEndTime = _timing.CurTime + dayCycle.Comp.CurrentTimeEntry.Duration; Dirty(dayCycle); } public void AddTimeEntry(Entity dayCycle, DayCycleEntry entry) { dayCycle.Comp.TimeEntries.Add(entry); Dirty(dayCycle); } public void SetTimeEntry(Entity dayCycle, int nextEntry) { nextEntry = Math.Clamp(nextEntry, 0, dayCycle.Comp.TimeEntries.Count - 1); dayCycle.Comp.CurrentTimeEntryIndex = nextEntry; dayCycle.Comp.EntryStartTime = dayCycle.Comp.EntryEndTime; dayCycle.Comp.EntryEndTime += dayCycle.Comp.CurrentTimeEntry.Duration; var ev = new DayCycleChangedEvent(dayCycle.Comp.CurrentTimeEntry); RaiseLocalEvent(dayCycle, ref ev, true); Dirty(dayCycle); } private void SetAmbientColor(Entity light, Color color) { if (color == light.Comp.AmbientLightColor) return; light.Comp.AmbientLightColor = color; Dirty(light); } private Color GetCurrentColor(Entity dayCycle, double totalSeconds) { var timeScale = GetTimeScale(dayCycle, totalSeconds); return Color.InterpolateBetween(dayCycle.Comp.StartColor, dayCycle.Comp.EndColor, timeScale); } private float GetTimeScale(Entity dayCycle, double totalSeconds) { return GetLerpValue(dayCycle.Comp.EntryStartTime.TotalSeconds, dayCycle.Comp.EntryEndTime.TotalSeconds, totalSeconds); } private static float GetLerpValue(double start, double end, double current) { if (Math.Abs(start - end) < MaxTimeDiff) return 0f; var distanceFromStart = current - start; var totalDistance = end - start; return MathHelper.Clamp01((float)(distanceFromStart / totalDistance)); } }