Exact source used by this build. SHA-256: 4d1d452253f221967b69ba18a14ef9b90795c4c2874895f81123bb80b541d5c9.

1 import type { Season, SimRules, Weather } from "../../types";
2 import { createRng } from "../../rng";
3 import { defineSystem } from "../registry";
4 /** Odds are content; a fixed type order makes serialized seeds reproducible. */
5 export function rollWeather(seed: number, season: Season, odds: NonNullable<SimRules["weatherOdds"]>): { weather: Weather; rngState: number } {
6   const weatherTypes: readonly Weather[] = ["sunny", "rain", "storm", "wind", "snow"];
7   const weights = odds[season];
8   const total = weatherTypes.reduce((sum, type) => sum + Math.max(0, weights[type]), 0);
9   if (!Number.isFinite(total) || total <= 0) throw new Error("Weather odds must have positive finite total weight");
10   const rng = createRng(seed);
11   let at = rng.next() * total;
12   for (const weather of weatherTypes) { at -= Math.max(0, weights[weather]); if (at < 0) return { weather, rngState: rng.state }; }
13   return { weather: "sunny", rngState: rng.state };
14 }
15 export function isRainy(weather: Weather): boolean { return weather === "rain" || weather === "storm"; }
16 export const weatherSystem = defineSystem({
17   id: "weather", worldDefaults: () => ({}), playerDefaults: () => ({}), intents: [], events: ["weatherChanged"],
18   initializeWorld: () => ({ weather: "sunny" }),
19   onOvernight: ({ state, rules, weatherOverride }) => {
20     if (!rules.weatherOdds) return { state, events: [] };
21     const rolled = rollWeather(state.rngState, state.clock.season, rules.weatherOdds);
22     const roll = { ...rolled, weather: weatherOverride ?? rolled.weather };
23     const areas = isRainy(roll.weather) ? Object.fromEntries(Object.entries(state.areas).map(([id, area]) => [id, area.outdoor ? { ...area, tiles: area.tiles.map((tile) => tile.tilled ? { ...tile, watered: true } : tile) } : area])) : state.areas;
24     return { state: { ...state, ...roll, areas, revision: state.revision + 1 }, events: [{ type: "weatherChanged", data: { weather: roll.weather } }] };
25   },
26 });
27