feat(ludic.base): the vocabulary mechanic packages share - Tick, phases, Queue<T>, rng streams, the save tree, the system runner
A mechanic package depends on ludic.base and nothing else: ports (records of function values for now) for questions, queues for facts, verbs for changes, phases for order and its own versioned save section. The runner inits, resets, saves and loads systems in the order added and ticks them phase by phase; a missing save section is a reset. Tests for each piece and a worked route between two toy mechanics live under tests/. The old ludic.core (engine ECS components) is used by examples/library and stays. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
ec9a650e65
commit
dd6a449921
16 changed files with 928 additions and 0 deletions
36
packages/ludic.base/tests/toys/fishing/index.ludic
Normal file
36
packages/ludic.base/tests/toys/fishing/index.ludic
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
# a toy mechanic: casting a line. It uses ludic.base and nothing else.
|
||||
module toy_fishing
|
||||
numbers float
|
||||
import "ludic.base"
|
||||
export property Caught { species: int = 0, weight: float = 0.0 }
|
||||
export property FishingWorld { is_water: fn(float, float) -> bool = null } # its port
|
||||
var world: FishingWorld = null
|
||||
var dice: Rng = null
|
||||
var casts: int = 0
|
||||
export var caught: Queue<Caught> = null # its facts
|
||||
export function fishing_bind(w: FishingWorld) -> void { world = w }
|
||||
export function fishing_cast(x: float, z: float) -> bool { # its verb
|
||||
if not world.is_water(x, z) { return false }
|
||||
casts += 1
|
||||
return true
|
||||
}
|
||||
function fishing_reset() -> void {
|
||||
casts = 0
|
||||
dice = rng_new(7)
|
||||
caught = q_new("fishing.caught")
|
||||
}
|
||||
function fishing_tick(t: Tick) -> void {
|
||||
while casts > 0 {
|
||||
let c = new Caught
|
||||
c.species = rng_between(dice, 0, 2)
|
||||
c.weight = 0.5 + rng_float(dice)
|
||||
q_push(caught, c)
|
||||
casts -= 1
|
||||
}
|
||||
}
|
||||
export function fishing_system() -> System {
|
||||
let s = system_new("fishing", PH_SIMULATE)
|
||||
s.reset = fn fishing_reset
|
||||
s.tick = fn fishing_tick
|
||||
return s
|
||||
}
|
||||
28
packages/ludic.base/tests/toys/pack/index.ludic
Normal file
28
packages/ludic.base/tests/toys/pack/index.ludic
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
# a toy mechanic: a pack of counts by kind, saved in its own section
|
||||
module toy_pack
|
||||
numbers float
|
||||
import "ludic.base"
|
||||
var counts: []int = null
|
||||
export function pack_add(kind: int, n: int) -> void { counts[kind] = counts[kind] + n }
|
||||
export function pack_count(kind: int) -> int { return counts[kind] }
|
||||
function pack_reset() -> void {
|
||||
counts = new []int
|
||||
for i in 0 .. 3 { push(counts, 0) }
|
||||
}
|
||||
function pack_save() -> Val {
|
||||
let v = Value.object()
|
||||
sv_put_ints(v, "counts", counts)
|
||||
return v
|
||||
}
|
||||
function pack_load(v: Val, version: int) -> void {
|
||||
pack_reset()
|
||||
let xs = sv_ints(v, "counts")
|
||||
for i in 0 .. len(xs) { if i < len(counts) { counts[i] = xs[i] } }
|
||||
}
|
||||
export function pack_system() -> System {
|
||||
let s = system_new("pack", PH_COMMIT)
|
||||
s.reset = fn pack_reset
|
||||
s.save = fn pack_save
|
||||
s.load = fn pack_load
|
||||
return s
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue