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>
This commit is contained in:
Leonid Pershin
2026-08-20 03:49:40 +03:00
co-authored by Cursor
parent d8f4958167
commit 8e7ab46e79
40 changed files with 1008 additions and 39 deletions
+6
View File
@@ -142,6 +142,12 @@ public sealed class RoomDef : Def
/// <summary>Game minutes spent occupying this room when walking through it.</summary>
public float TravelMinutes { get; init; }
/// <summary>
/// Outdoor like the yard: porch, crossing between buildings. Indoor rooms stay warmer than
/// the street by the climate preset's wall offset.
/// </summary>
public bool Outdoor { get; init; }
}
public sealed class BuildingDef : Def;
+39
View File
@@ -30,6 +30,11 @@ internal static class PeopleDefValidator
ValidateCountry(country, catalog);
}
foreach (var preset in catalog.ClimatePresets.Values)
{
ValidateClimatePreset(preset);
}
foreach (var subject in catalog.Subjects.Values)
{
ValidateSubject(subject, catalog);
@@ -576,6 +581,40 @@ internal static class PeopleDefValidator
ValidateNameSet(country.Names ?? new NameSetDef(), catalog, country.DefName);
}
private static void ValidateClimatePreset(ClimatePresetDef preset)
{
if (preset.Abstract)
{
return;
}
if (preset.MonthlyNorms.Count != 12)
{
throw new ContentLoadException(
$"ClimatePresetDef '{preset.DefName}' monthlyNorms must list 12 months.");
}
if (preset.DaySpread < 0 || preset.HourSpread < 0)
{
throw new ContentLoadException($"ClimatePresetDef '{preset.DefName}' spreads cannot be negative.");
}
if (preset.PrecipitationChance < 0 || preset.PrecipitationChance > 1)
{
throw new ContentLoadException($"ClimatePresetDef '{preset.DefName}' precipitationChance must be 01.");
}
if (preset.ComfortHalfWidthC < 0)
{
throw new ContentLoadException($"ClimatePresetDef '{preset.DefName}' comfortHalfWidthC cannot be negative.");
}
if (preset.InsulationPerC < 0)
{
throw new ContentLoadException($"ClimatePresetDef '{preset.DefName}' insulationPerC cannot be negative.");
}
}
private static void ValidateNameSet(NameSetDef names, DefCatalog catalog, string countryDefName)
{
if (!NameGrammar.IsKnownPatronymic(names.PatronymicRule))
+41 -4
View File
@@ -184,6 +184,12 @@ public sealed class TraitDef : Def
/// Extra minutes of commute slack. Positive arrives earlier; negative cuts it closer.
/// </summary>
public int CommuteMinutes { get; init; }
/// <summary>
/// Shifts the warmth comfort band, in °C. Heat-loving is positive (suffers cold earlier);
/// cold-loving is negative.
/// </summary>
public float ComfortTemperatureOffset { get; init; }
}
public sealed class StaffingDef : Def
@@ -309,6 +315,12 @@ public sealed class NeedDef : Def
/// restores overnight; hunger does not keep falling at home.
/// </summary>
public bool RestoredOffCampus { get; init; }
/// <summary>
/// When true, campus drain is not <see cref="DecayPerHour"/> per hour. Warmth uses it as the
/// drop per °C of mismatch against the place temperature.
/// </summary>
public bool Environmental { get; init; }
}
public sealed class CaseTable
@@ -407,7 +419,7 @@ public sealed class NameSetDef
/// <summary>
/// What the player picks at create: nested names plus climate-preset ids. Weather numbers live
/// on <see cref="ClimatePresetDef"/> and stay unused until phase 32.
/// on <see cref="ClimatePresetDef"/>.
/// </summary>
public sealed class CountryDef : Def
{
@@ -417,7 +429,32 @@ public sealed class CountryDef : Def
}
/// <summary>
/// Outdoor climate a country may roll. Monthly temperatures land in phase 32; the id is enough
/// to persist which preset a school was born with.
/// Outdoor climate a country may roll. Monthly norms, day/hour spread and precipitation chance
/// are the numbers the school uses to sample the street; indoor offset is walls without a technician.
/// </summary>
public sealed class ClimatePresetDef : Def;
public sealed class ClimatePresetDef : Def
{
/// <summary>Mean outdoor °C for months 112. Concrete presets must list all twelve.</summary>
public IReadOnlyList<float> MonthlyNorms { get; init; } = [];
/// <summary>How far a day's mean may wander from the monthly norm, °C.</summary>
public float DaySpread { get; init; }
/// <summary>How far the hour wanders from that day's mean, °C. Coldest around 03:00, warmest 15:00.</summary>
public float HourSpread { get; init; }
/// <summary>Chance of precipitation this hour, 01. Below 0 °C the same roll is snow.</summary>
public float PrecipitationChance { get; init; }
/// <summary>Added to indoor temperature vs the street. Walls hold heat; this is not comfort.</summary>
public float IndoorOffset { get; init; } = 8f;
/// <summary>Centre of the clothing comfort band, °C, before trait offsets.</summary>
public float ComfortC { get; init; } = 21f;
/// <summary>Half-width of the comfort band, °C. Inside it warmth barely drops.</summary>
public float ComfortHalfWidthC { get; init; } = 3f;
/// <summary>How many °C of protection one insulation point is worth.</summary>
public float InsulationPerC { get; init; } = 1f;
}