refactor(packages): the mechanic packages use ludic_base only, and ask through ports
ludic.clock, .effects, .inventory, .wallet, .weather and .tracks say 'uses ludic_base' (ludic.base uses nothing). ClockWorld, PackRules, WeatherWorld and TracksWorld are export ports whose defaults are the old fallbacks; clock_bind, inv_bind, weather_bind and tracks_bind are gone, and the tests bind their fakes. The base README's toy does the same. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
f4062010e9
commit
63e29f024c
31 changed files with 130 additions and 149 deletions
|
|
@ -39,7 +39,7 @@ property WeatherKind {
|
|||
## The port
|
||||
|
||||
```ludic
|
||||
property WeatherWorld {
|
||||
export port WeatherWorld { # every member has a default, so any may be left out
|
||||
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
|
||||
|
|
@ -47,10 +47,16 @@ property WeatherWorld {
|
|||
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
|
||||
seed: fn() -> int # a new trip's dice (unbound: 1)
|
||||
}
|
||||
```
|
||||
|
||||
The game fills it once, where it is put together - a declaration, not a call:
|
||||
|
||||
```ludic
|
||||
bind WeatherWorld { owns_world: fn ses_owns_world, hours: fn clock_hours, odds: fn sky_odds }
|
||||
```
|
||||
|
||||
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
|
||||
|
|
@ -60,7 +66,7 @@ it wants them (daylight, a tarp up, a stars job open).
|
|||
|
||||
| | |
|
||||
| --- | --- |
|
||||
| `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` |
|
||||
| `bind WeatherWorld { ... }`, `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 |
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@
|
|||
# rain could wait a week for it; so while the world says it wants a front, one is forecast and
|
||||
# arrives within the hour and a half, and while it wants clear sky, the sky clears and holds.
|
||||
function wx_front_kind() -> int {
|
||||
if wx_world != null and wx_world.front != null { return wx_world.front() }
|
||||
return wx_first_wet()
|
||||
return WeatherWorld.front()
|
||||
}
|
||||
|
||||
function wx_want_wet() -> void {
|
||||
|
|
|
|||
|
|
@ -32,25 +32,13 @@ function wx_first_wet() -> int {
|
|||
return 0
|
||||
}
|
||||
|
||||
function wx_owns() -> bool {
|
||||
if wx_world == null or wx_world.owns_world == null { return true }
|
||||
return wx_world.owns_world()
|
||||
}
|
||||
function wx_owns() -> bool { return WeatherWorld.owns_world() }
|
||||
|
||||
function wx_hours() -> float {
|
||||
if wx_world == null or wx_world.hours == null { return 12.0 }
|
||||
return wx_world.hours()
|
||||
}
|
||||
function wx_hours() -> float { return WeatherWorld.hours() }
|
||||
|
||||
function wx_night() -> bool {
|
||||
if wx_world == null or wx_world.is_night == null { return false }
|
||||
return wx_world.is_night()
|
||||
}
|
||||
function wx_night() -> bool { return WeatherWorld.is_night() }
|
||||
|
||||
function wx_bias() -> int {
|
||||
if wx_world == null or wx_world.bias == null { return WEATHER_NO_BIAS }
|
||||
return wx_world.bias()
|
||||
}
|
||||
function wx_bias() -> int { return WeatherWorld.bias() }
|
||||
|
||||
function wx_wrap(a: float) -> float {
|
||||
var d = a
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# ludic.weather - the sky as a chain of spells: each kind is data the game hands in, the next is
|
||||
# drawn from odds the game may lean on, and what changed is a fact on a queue
|
||||
module ludic_weather
|
||||
module ludic_weather uses ludic_base
|
||||
numbers float
|
||||
import "ludic.base"
|
||||
import "state.ludic"
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
# pick.ludic - the next spell, drawn from weights, and how long one lasts. The weights are the
|
||||
# kind's own unless the world leans on them (a season, a wet week); every draw is this package's
|
||||
function wx_odds(from: int) -> []float {
|
||||
if wx_world != null and wx_world.odds != null { return wx_world.odds(from) }
|
||||
return wx_kinds[from].odds
|
||||
return WeatherWorld.odds(from)
|
||||
}
|
||||
|
||||
# the kind a set of weights lands on; no weights (or all zero) keeps the kind it came from
|
||||
|
|
|
|||
|
|
@ -7,8 +7,7 @@ function wx_turn() -> void {
|
|||
wx_left = wx_spell_hours(wx_state)
|
||||
if wx_forced {
|
||||
wx_forced = false
|
||||
var least = 5.0
|
||||
if wx_world != null and wx_world.front_hours != null { least = Math.max(least, wx_world.front_hours()) }
|
||||
let least = Math.max(5.0, WeatherWorld.front_hours())
|
||||
if wx_left < least { wx_left = least }
|
||||
}
|
||||
if wx_state == was { return }
|
||||
|
|
|
|||
|
|
@ -1,16 +1,24 @@
|
|||
# state.ludic - the port, the kinds, the facts, and what the sky holds
|
||||
# what the weather asks the world. Any field may be left null: the answer is then "yes, it is
|
||||
# mine", noon and daylight, the kind's own odds, no bias, the first wet kind, and a seed of 1.
|
||||
export property WeatherWorld {
|
||||
owns_world: fn() -> bool = null
|
||||
hours: fn() -> float = null
|
||||
is_night: fn() -> bool = null
|
||||
odds: fn(int) -> []float = null # weights for the next spell, per kind, from this kind
|
||||
bias: fn() -> int = null # what the story wants now: WEATHER_* below
|
||||
front: fn() -> int = null # the kind a wanted front comes as
|
||||
front_hours: fn() -> float = null # the least a wanted front lasts once it arrives
|
||||
seed: fn() -> int = null
|
||||
# what the weather asks the world. Any member may be left out of the bind: the answer is then
|
||||
# "yes, it is mine", noon and daylight, the kind's own odds, no bias, the first wet kind, and a
|
||||
# seed of 1.
|
||||
export port WeatherWorld {
|
||||
owns_world: fn() -> bool = fn wx_owns_alone
|
||||
hours: fn() -> float = fn wx_noon
|
||||
is_night: fn() -> bool = fn wx_daylight
|
||||
odds: fn(int) -> []float = fn wx_own_odds # weights for the next spell, per kind, from this kind
|
||||
bias: fn() -> int = fn wx_no_bias # what the story wants now: WEATHER_* below
|
||||
front: fn() -> int = fn wx_first_wet # the kind a wanted front comes as
|
||||
front_hours: fn() -> float = fn wx_no_hours # the least a wanted front lasts once it arrives
|
||||
seed: fn() -> int = fn wx_seed_one
|
||||
}
|
||||
function wx_owns_alone() -> bool { return true }
|
||||
function wx_noon() -> float { return 12.0 }
|
||||
function wx_daylight() -> bool { return false }
|
||||
function wx_own_odds(from: int) -> []float { return wx_kinds[from].odds }
|
||||
function wx_no_bias() -> int { return WEATHER_NO_BIAS }
|
||||
function wx_no_hours() -> float { return 0.0 }
|
||||
function wx_seed_one() -> int { return 1 }
|
||||
|
||||
# what the story may ask of the sky
|
||||
export const WEATHER_NO_BIAS: int = 0
|
||||
|
|
@ -45,7 +53,6 @@ export property WeatherFact {
|
|||
from: int = 0
|
||||
}
|
||||
|
||||
var wx_world: WeatherWorld = null
|
||||
var wx_kinds: []WeatherKind = null
|
||||
var wx_state: int = 0
|
||||
var wx_next: int = 0
|
||||
|
|
@ -64,8 +71,6 @@ var wx_wet_yesterday: bool = false
|
|||
var wx_dice: Rng = null
|
||||
var wx_facts: Queue<WeatherFact> = null
|
||||
|
||||
export function weather_bind(w: WeatherWorld) -> void { wx_world = w }
|
||||
|
||||
# the facts, oldest first; the game drains them into its notices and sounds
|
||||
export function weather_facts() -> Queue<WeatherFact> {
|
||||
if wx_facts == null { wx_facts = queue_new("weather.facts") }
|
||||
|
|
|
|||
|
|
@ -46,6 +46,16 @@ program WeatherTest {
|
|||
return k
|
||||
}
|
||||
|
||||
bind WeatherWorld {
|
||||
owns_world: fn fake_owns
|
||||
hours: fn fake_hours
|
||||
is_night: fn fake_night
|
||||
bias: fn fake_bias
|
||||
seed: fn fake_seed
|
||||
odds: fn fake_odds
|
||||
front_hours: fn fake_front_hours
|
||||
}
|
||||
|
||||
# clear, rain and storm: clear always goes to rain, rain to storm, storm to clear
|
||||
function fresh() -> void {
|
||||
owns = true
|
||||
|
|
@ -57,15 +67,6 @@ program WeatherTest {
|
|||
push(ks, kind("rain", true, false, odds3(0.0, 0.0, 1.0)))
|
||||
push(ks, kind("storm", true, true, odds3(1.0, 0.0, 0.0)))
|
||||
weather_kinds(ks)
|
||||
let w = new WeatherWorld
|
||||
w.owns_world = fn fake_owns
|
||||
w.hours = fn fake_hours
|
||||
w.is_night = fn fake_night
|
||||
w.bias = fn fake_bias
|
||||
w.seed = fn fake_seed
|
||||
w.odds = fn fake_odds
|
||||
w.front_hours = fn fake_front_hours
|
||||
weather_bind(w)
|
||||
weather_config_wind(0.5, 2.5, 10.0, 19.0)
|
||||
weather_reset()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
# verbs.ludic - the only way the sky changes from outside: a morning, a reset, the host's word
|
||||
# a new trip: clear sky, a still-ish wind, nothing forecast; the dice from the world's seed
|
||||
export function weather_reset() -> void {
|
||||
var seed = 1
|
||||
if wx_world != null and wx_world.seed != null { seed = wx_world.seed() }
|
||||
wx_dice = rng_new(seed)
|
||||
wx_dice = rng_new(WeatherWorld.seed())
|
||||
let clear = wx_clear_kind()
|
||||
wx_state = clear
|
||||
wx_next = clear
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue