Time and weather
A room has an hour and a weather of its own (Game design document §5.7). The weather changes by itself, and games and missions can set it. The day turns at a pace a level, a game or a mission chooses. Both change the game, gently:
- a wet road brakes longer;
- the dark and the fog hide a player from a guard's eyes;
- rain covers footsteps and sends people home.
The night stays readable: it is never darker than the player lets it be.
The clock
The room clock (@foi/shared's clock.ts, see the City guide) counts the game minutes since the room's first midnight and only goes forward. Day two's noon is 2160.
- Setting it to a time of day (
setClock, the debug channel's hour) moves it on to the next such time. - A skip (
skipTime) moves it on by so many hours.
The time of day is that count wrapped into one day. The schedules, the light and the weather all read it.
A day lasts 24 minutes divided by the pace. Each of these sets the pace, the later ones over the earlier:
| Where | How | Example |
|---|---|---|
| A level | Its level spec's clock | { "start": "07:30", "pace": 1 }, written into the level's sky at export |
| A game | Its rules.clock | |
| A mission | setPace on its start | { "when": "mission:start", "do": [{ "setPace": 4 }] }: a day in six minutes |
The weather
The weather (@foi/shared's weather.ts) is a pure function of three things: a seed, a climate, and the clock's game minutes. Like the clock, the server sends it once and again only when something sets it. Every client and the AI work out the same weather at any moment.
Fronts. The weather changes every half an hour of game time. Each front is one of six kinds:
clearovercastrainstormfogsnow
It also has an intensity. Most fronts follow a regime of four hours; the rest are drawn by the climate's odds. A front comes in over five minutes. Because each front comes from the seed and its own number, never from the one before, a skip of three hours lands at once in the weather of then.
Climates. A climate is a set of odds over the six kinds:
| Climate | Character |
|---|---|
temperate | A town's |
meadow, forest, alpine, farmland, steppe, desert, autumn, coast | A region's biomes, named alike: alpine snows, the desert hardly rains, the coast is foggy, autumn is wet |
none | Always clear |
What it leaves. The roads' wetness and the snow on the ground are worked out over the last six hours of fronts:
| Builds up in about | Goes in about | |
|---|---|---|
| Wet roads, in the rain | 10 minutes | 40 minutes, drying |
| Snow, settling | half an hour | two hours, melting |
Where it comes from.
- The level. A level spec's
climate, or a region's biome, ortemperatefor a town. It is written into the level'sskyat export (apps/tools/src/level-sky.ts; the worker does the same for a creator's draft). A level built of blocks has no sky and is always clear. - A game's
rules.weather.climateoverrides the level's.startis the weather the room opens with, at anintensity.changessays whether it goes its own way after an hour (true, the default) or holds.
- A mission's
setWeather.- Fields:
kind,intensity,over(the game minutes it comes in over) andminutes(how long it holds; for good without). - Rules hear
weather:<kind>when the weather turns. - A condition
{ "weather": ["rain", "storm"] }tests it.
- Fields:
- The server's
FOI_WEATHER.onis the default, except on atest-*level.off: always clear, and the dark hides nobody. It is the default on test levels and on every end-to-end server.- A climate by name forces that climate.
- A game's start weather and its missions'
setWeatherapply either way.
What it does to play
The simulation reads the weather every tick into sim.sky, in steps of 1/64, and hashes it with the clock.
Tyres (
packages/sim/src/weather.ts,WEATHER_GRIP):Surface Grip kept A road soaked through 0.8 Loose ground soaked to mud 0.68 Under full snow 0.6 The share applies to the tyres' side grip, their friction circle and the brakes. The engine's traction feels only half the loss, so a car still pulls away. Dry ground is untouched, so the dry driving envelope never moves. A car brakes about a fifth longer in the wet and half again as long in the snow.
Fire. A wreck burns out twice as fast in a downpour.
Sight and hearing (
@foi/ai'svisibility.ts). These scale every sight range: a guard's and a camera's cone, a chaser's line of sight, a witness's reach.Condition Sight kept The dark of night, eased through dawn and dusk (05:30–06:30, 19:30–20:30) 0.55 At night, under a street lamp 0.9 The thickest fog 0.5 A downpour 0.75 What counts is where the one seen stands, and the night only counts where the room's sky darkens sight. Rain masks a third of every hearing range. The guards' cones on the screen and on the minimap are drawn as long as they see the player.
A street lamp knocked down (a light piece lying loose, see the driving model) is out: where it lit, the dark of night is back, for the guards and the police as on the screen (
@foi/world'slampLightAtis told which lamps are out, by@foi/sim'sisPieceLoose). A level reset plants it and lights it again.The city. In a downpour only 60 % of the crowd stays out. The traffic drives 12 % slower on a road soaked through.
A skip. It puts the people on schedules where their hour has them, as if they had walked there. A mission hears only the
time:events of the skip's last hour.
What it looks like
The client works the same weather out from the frames the server sent (weather-view.ts, night-view.ts, daylight.ts in apps/client/src/renderer).
- The light.
- The sun climbs from the east and sets in the west, warm at dawn and dusk.
- The sky light dims into a blue night.
- Clouds dim and grey it.
- At noon under a clear sky it is the light the scene always had.
- The night is never darker than Settings → Display → Brightness at night (25–100 % of the day's light, 55 % by default).
- The weather.
- Rain streaks and snowflakes fall round the player, carried by the wind, fewer without a GPU.
- Fog hazes the scene. The minimap is drawn apart and stays clear.
- Wet asphalt (streets, kerbs, roofs) darkens and shines, and mud darkens. Snow whitens loose ground most.
- A storm flashes with lightning, its thunder heard a moment later.
- The night (
night-view.ts, withwindow-lights.ts,car-lights.tsandactor-lamps.ts). See The night's lights below.- Every lit street lamp throws a soft pool of light on the ground under a halo at its head; a lamp knocked down goes out.
- A share of the windows is lit by the hour, each in its tone, the ground floors' light on the pavement.
- Every car that somebody drives throws its headlights on the road and a red glow behind it.
- With a GPU, the cars and the people passing under a lit lamp are lit by it.
- Sound. Rain hisses and the wind gusts, as hard as they go.
- The HUD.
- The weather's icon sits beside the clock (
#weather-icon). - A skip fades the screen with "3 hours later" (
#skip-toast), or the mission's own words.
- The weather's icon sits beside the clock (
The night's lights
As it gets dark (from the first twentieth of the dusk on) the city lights up. Everything below is light added to the picture, in four draw calls for a whole level; none of it is drawn, nor worked out, by day, and nothing of it is on the wire: the lamps knocked down are the loose pieces the snapshots already list, the windows are worked out from the room clock, the cars' lights from what the snapshots say of each car.
Street lamps. Every lit lamp has a pool of light on the ground round its foot (fading to nothing 7.6 m out, lying on a street that climbs) and a halo at its head, which reads from above. A lamp knocked down is out: no pool, no halo, its head as dark as its pole where it lies. The AI sees by the same lamps (above).
Windows (
lit-windows.ts). The windows of a level are found in its glass when it loads: every upright rectangle of the kits'glass,glass-lightandwindowcolours wide and tall enough to be one, the face that looks out of the building; a band or a wall of glass is cut into windows a room wide and a storey tall.glass-darknever lights. A share of them is lit by the hour:Hour Homes and offices Shops' fronts (light glass) 19:30 0.55 0.95 21:00 0.70 0.95 22:00 0.62 0.60 23:00 0.45 0.30 00:00 0.28 0.25 01:00 0.16 0.20 03:00 to 04:30 0.07 0.20 05:30 0.16 0.30 06:30 0.30 0.50 07:30 to 16:30 0 0 moving in a straight line from one row to the next. Which windows are lit is a hash of the placement's index, the window's index and the night's number (a night runs from noon to noon), never chance: the same window is lit for every player of a room at the same hour, a window lit at three in the morning was lit all evening, and the next night lights others. Each has its tone: warm for most (three of them), a strip light's cold white for one in ten, a television's blue for another, flickering slowly. A lit window is a pane of light a hair in front of its glass; the windows of a building's ground floor and of the floor above it throw a soft patch of their light on the pavement at the foot of their wall, a shop's front the most. The glass itself keeps a faint sheen. A window of a light piece (a phone booth's pane) goes dark with the piece knocked loose; a storey that fades over the player fades its windows with it.
Cars (
car-lights.ts). A car that somebody drives (the snapshot'sparkedis off, it is no wreck) throws two soft beams 15 m ahead of its nose, on the ground where it lies (they climb a hill with the road), and a red glow behind its tail. A two-wheeler has one beam, a bicycle and a trailer none; a car left by its driver puts them out. The player's own car has the same beams and, with a GPU, a real spotlight that lights the walls and the people ahead.Under the lamps (
actor-lamps.ts, with a GPU). Three point lights, made once when the level loads, stand at the heads of the lit lamps nearest to where the camera looks and light the cars and the people alone (their meshes are on a layer of their own): a car passing under a lamp is lit by it, one in the dark is not. The level's own shaders never count them. A light fades to nothing before it moves on to the next lamp.
The numbers are NIGHT (night-view.ts), WINDOW_LIGHTS, CAR_LIGHTS, ACTOR_LAMPS and the table in lit-windows.ts.
On the wire
PROTOCOL_VERSION 29.
The
weathertext frame carries the seed, the climate, whether the night darkens sight, and a script in force. It is sent at the join and whenever something sets it.The
skiptext frame says how many game minutes went by, with the mission's words if any.The client's prediction world gets the clock and the weather too, so a wet road grips the same on both sides.
The debug command
weathersets one of these on a server whose debug commands are on:- a
kindat anintensity, as if it had gone on for hours (the roads already wet); - a
climate; - whether
nightdarkens sight.
clockwithhoursskips. The legend's View tab has both.- a
Tests
Unit tests:
packages/shared/src/weather.test.ts: the fronts, the climates' odds, the wetness, the snow, the skip, the daylight;packages/sim/src/weather.test.tsandvehicle.test.ts's weather block: braking dry, wet and on snow;packages/ai/src/visibility.test.ts;packages/world/src/lamps.test.ts;packages/catalogue/src/sky.test.ts;apps/server/src/weather.test.ts: the room's weather, the frames, the debug channel, a mission's skip and fog;apps/client/src/renderer/daylight.test.ts,weather-view.test.tsandnight-view.test.ts;- the night's lights:
lit-windows.test.ts(where the windows are, the hours, the tones),window-lights.test.ts,car-lights.test.tsandactor-lamps.test.tsbeside them.
The determinism gate (
packages/sim/src/determinism.integration.test.ts) runs in an autumn downpour.The mini level
test-weather:- a straight avenue to brake on;
- a lit street (five lamps) and a dark one west and east of a crossing, with a guard posted down each;
- its game, Night Drive, skips three hours on and brings the rain when the player reaches the dark street's end.
Its e2e rows are E2E-491 to E2E-497, and the night's lights E2E-526 to E2E-528 and E2E-530 (
tests/e2e/specs/levels/test-weather): a lamp knocked down goes out, for the picture and for the guard who saw by it; the windows by the hour; the lamps' light on the actors. The cars' headlights are E2E-529, ontest-traffic-junction.The frame rate:
npm run perf'sstorm-nightscenario drives Riverbend's boulevard at eleven at night in a storm (see Performance).By hand: Testing by hand.