feat(ludic.weather): spells of weather as a mechanic package
The kinds and their odds are data the game hands in; a port asks whether this machine owns the world, the hour, the night, the odds from a kind, what the story wants of the sky (a front, a hold, a clear night), the front's kind and length, and a seed. Its own dice; a new spell, a clearing, lightning and a wanted front are facts on weather_facts(); its own save section. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
a2012a5afe
commit
093ca0d260
12 changed files with 746 additions and 0 deletions
80
packages/ludic.weather/README.md
Normal file
80
packages/ludic.weather/README.md
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
# ludic.weather
|
||||
|
||||
The sky as a chain of spells: clear, cloud, rain, a storm, snow - or whatever kinds the game
|
||||
hands in. Each spell lasts a few game hours, eases in and out at its edges, sets the wind and
|
||||
wets the ground, and gives way to the next by odds the game may lean on (a season, a wet week).
|
||||
A forecast is drawn each morning, and the story can ask for a front or for a clear night. Uses
|
||||
[`ludic.base`](../ludic.base/README.md) and nothing else.
|
||||
|
||||
```ludic
|
||||
import "ludic.weather"
|
||||
```
|
||||
|
||||
A kind is the game's number: its place in the list handed to `weather_kinds`. The package knows
|
||||
what a kind DOES (it is wet, it throws lightning, it holds the cold) and never what it is called
|
||||
in a sentence; the game draws the sky and says the notices.
|
||||
|
||||
Only the machine that owns the world runs the spells. Every machine eases the ground's wetness
|
||||
and throws its own lightning out of a storm it is told of (`weather_told`), from the package's
|
||||
own dice - never the world's.
|
||||
|
||||
## The kinds
|
||||
|
||||
```ludic
|
||||
property WeatherKind {
|
||||
name: string # for weather_name
|
||||
clear: bool # the kind a sky eases out to (amount 0); the first one starts a trip
|
||||
wet: bool # rain or snow is falling (weather_wet)
|
||||
soak: float # how wet the ground gets under it, 0..1
|
||||
overcast: float # times the amount: weather_overcast
|
||||
cold: float # times the amount: weather_cold, in the game's units
|
||||
wind: float # the strength the wind builds toward
|
||||
wind_dir: float # radians the wind blows toward; below 0, the valley's daily turn
|
||||
thunder: bool # a storm: lightning every 9-34 s while the amount is over a half
|
||||
spell_lo, spell_hi # game hours a spell lasts
|
||||
odds: []float # weights for the next spell, one per kind
|
||||
}
|
||||
```
|
||||
|
||||
## The port
|
||||
|
||||
```ludic
|
||||
property WeatherWorld {
|
||||
owns_world: fn() -> bool # does this machine run the world? (unbound: yes)
|
||||
hours: fn() -> float # the hour, for the wind's daily turn (unbound: noon)
|
||||
is_night: fn() -> bool # a front clearing at night is no WEATHER_CLEARED
|
||||
odds: fn(int) -> []float # the next spell's weights from a kind (unbound: the kind's own)
|
||||
bias: fn() -> int # what the story wants now: WEATHER_NO_BIAS, _WANT_WET, _HOLD, _WANT_CLEAR
|
||||
front: fn() -> int # the kind a wanted front comes as (unbound: the first wet kind)
|
||||
front_hours: fn() -> float # the least a wanted front lasts (never under 5)
|
||||
seed: fn() -> int # a new trip's dice
|
||||
}
|
||||
```
|
||||
|
||||
The bias is asked every tick on the owner. `WANT_WET` on a dry sky forecasts a front
|
||||
(`WEATHER_FRONT`), due within an hour and a half; `HOLD` keeps the current spell going at least
|
||||
1.2 hours more; `WANT_CLEAR` clears within half an hour and keeps it clear. The game decides WHEN
|
||||
it wants them (daylight, a tarp up, a stars job open).
|
||||
|
||||
## API
|
||||
|
||||
| | |
|
||||
| --- | --- |
|
||||
| `weather_bind(w)`, `weather_kinds(ks)`, `weather_config_wind(down, up, from, to)` | the port, the kinds, and the valley's wind: toward `down` by night, toward `up` from `from` to `to` |
|
||||
| `weather_run(dt, gh)` | one step (the system's tick does this from `Tick.dt` and `Tick.hours`) |
|
||||
| `weather_morning()` | a new day's forecast: seven times in ten it becomes the next spell |
|
||||
| `weather_reset()` | a new trip: the first clear kind, nothing forecast, dice from the seed |
|
||||
| `weather_set(kind, next, left)`, `weather_set_wind(s, dir)`, `weather_set_ground(w)`, `weather_set_flash(f)` | the sky outright (staging, tests) |
|
||||
| `weather_told(kind, next, left, amount, wind, dir, forecast)` | what the owner says the sky is; a new spell is a fact here too |
|
||||
| `weather_state()`, `weather_next()`, `weather_left()`, `weather_amount()`, `weather_forecast()`, `weather_forced()` | the spell |
|
||||
| `weather_wet()`, `weather_overcast()`, `weather_cold()`, `weather_wind()`, `weather_dir()`, `weather_ground_wet()`, `weather_flash()` | what it does |
|
||||
| `weather_after_front()`, `weather_wet_yesterday()` | the half hour of clear light after a front; whether yesterday had rain or snow in it |
|
||||
| `weather_kind(k)`, `weather_kind_count()`, `weather_name(k)`, `weather_draw_from(w, from, roll)` | the kinds, and the draw itself |
|
||||
| `weather_facts() -> Queue<WeatherFact>` | `{ what, kind, from }`: `WEATHER_BEGAN` (a new spell), `WEATHER_CLEARED` (a wet spell gave way to clear sky by day), `WEATHER_THUNDER`, `WEATHER_FRONT` (a wanted front is forecast) |
|
||||
| `weather_system() -> System` | `"weather"`, `PH_SIMULATE`: reset, tick, and its save section (`weather_save`, `weather_load`: the spell, the forecast, the wind's direction, the ground, the dice) |
|
||||
|
||||
## Tests
|
||||
|
||||
```bash
|
||||
ludic build packages/ludic.weather/tests/weather_test.ludic --headless -o /tmp/weather_test && /tmp/weather_test
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue