Files
TheriapolisV3/Theriapolis.Core/Time/WorldClock.cs
T

49 lines
1.9 KiB
C#
Raw Normal View History

namespace Theriapolis.Core.Time;
public enum Season : byte { Spring, Summer, Autumn, Winter }
/// <summary>
/// Single in-game time counter. Measured in whole seconds so it serializes
/// trivially and stays deterministic — no floating-point drift over a long
/// playthrough.
///
/// Phase 4 callers advance the clock from world-map travel and tactical
/// stepping. Phase 8 weather/seasons reads from it.
/// </summary>
public sealed class WorldClock
{
/// <summary>In-game seconds since world creation. Game time, not real time.</summary>
public long InGameSeconds { get; private set; }
// Calendar constants. A 96-day year (24 days × 4 seasons) keeps the math
// tight; a real-world year would mean each season is a 90-hour playthrough.
public const int SecondsPerMinute = 60;
public const int SecondsPerHour = 3600;
public const int SecondsPerDay = SecondsPerHour * 24;
public const int DaysPerSeason = 24;
public const int DaysPerYear = DaysPerSeason * 4;
public int Day => (int)(InGameSeconds / SecondsPerDay);
public int Hour => (int)((InGameSeconds % SecondsPerDay) / SecondsPerHour);
public int Minute => (int)((InGameSeconds % SecondsPerHour) / SecondsPerMinute);
public int Year => Day / DaysPerYear;
public Season Season => (Season)((Day / DaysPerSeason) % 4);
public void Advance(long seconds)
{
if (seconds < 0) throw new ArgumentOutOfRangeException(nameof(seconds));
InGameSeconds += seconds;
}
public WorldClockState CaptureState() => new() { InGameSeconds = InGameSeconds };
public void RestoreState(WorldClockState s) => InGameSeconds = s.InGameSeconds;
/// <summary>Pretty-print like "Y0 Spring D5 14:23".</summary>
public string Format() => $"Y{Year} {Season} D{Day % DaysPerSeason} {Hour:D2}:{Minute:D2}";
}
public sealed class WorldClockState
{
public long InGameSeconds;
}