Files
h-school/src/HSchool.Simulation/WeatherSampler.cs
T
Leonid PershinandCursor 8e7ab46e79 Sample outdoor weather from the climate preset so people can freeze and the clock can show it.
Protocol v8 adds tenths of a °C and precipitation to the clock frame; warmth drains from insulation versus place temperature.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-20 03:49:40 +03:00

54 lines
1.8 KiB
C#

using HSchool.Content;
using HSchool.People;
namespace HSchool.Simulation;
/// <summary>
/// Outdoor temperature and precipitation from a climate preset, the school seed, and the
/// calendar. Same inputs always produce the same street. Not a tick accumulator — sample it
/// when the clock label or warmth would move.
/// </summary>
public static class WeatherSampler
{
private const int DaySalt = 0x57EA11;
private const int HourSalt = 0x57EA12;
public static OutdoorWeather Sample(ClimatePresetDef preset, int schoolSeed, DateTime time)
{
ArgumentNullException.ThrowIfNull(preset);
var utc = DateTime.SpecifyKind(time, DateTimeKind.Utc);
var month = utc.Month;
var norm = MonthNorm(preset, month);
var dayNumber = DateOnly.FromDateTime(utc).DayNumber;
var dayNoise = SignedUnit(Seed.Mix(schoolSeed, dayNumber, DaySalt)) * preset.DaySpread;
var hour = utc.Hour + utc.Minute / 60d + utc.Second / 3600d;
var diurnal = -Math.Cos((hour - 3d) / 24d * 2d * Math.PI) * preset.HourSpread;
var temperature = (float)(norm + dayNoise + diurnal);
var wet = Unit(Seed.Mix(schoolSeed, dayNumber * 24 + utc.Hour, HourSalt)) < preset.PrecipitationChance;
var precipitation = !wet
? Precipitation.None
: temperature < 0f ? Precipitation.Snow : Precipitation.Rain;
return new OutdoorWeather(temperature, precipitation);
}
private static float MonthNorm(ClimatePresetDef preset, int month)
{
if (preset.MonthlyNorms.Count != 12)
{
return 0f;
}
return preset.MonthlyNorms[month - 1];
}
private static double Unit(int mixed)
{
return (uint)mixed / (double)uint.MaxValue;
}
private static double SignedUnit(int mixed) => Unit(mixed) * 2d - 1d;
}