ludic/packages/ludic.things
2026-09-28 16:29:33 +03:00
..
tests ludic.things: a fact's record kept, in two halves swapped when a fact finds the queue empty 2026-09-28 12:45:40 +03:00
chunks.ludic ludic.compass: the marks' pools made with the state (512), compass_at's empty mark kept; ludic.base imap_clear in place; ludic.things' kept lists through kept_push; ludic.net's once-per-room and STUN log lines declared 2026-09-28 16:22:48 +03:00
dispatch.ludic ludic.compass: the marks' pools made with the state (512), compass_at's empty mark kept; ludic.base imap_clear in place; ludic.things' kept lists through kept_push; ludic.net's once-per-room and STUN log lines declared 2026-09-28 16:22:48 +03:00
facts.ludic ludic.compass: the marks' pools made with the state (512), compass_at's empty mark kept; ludic.base imap_clear in place; ludic.things' kept lists through kept_push; ludic.net's once-per-room and STUN log lines declared 2026-09-28 16:22:48 +03:00
index.ludic ludic.things: a fact's record kept, in two halves swapped when a fact finds the queue empty 2026-09-28 12:45:40 +03:00
kinds.ludic feat(ecs): ludic.base Table<T> - dense rows of hot columns, generational handles, a spatial grid, kind indexes and an id map kept current by the setters; ludic.things on it 2026-09-27 15:52:51 +03:00
moves.ludic feat(ecs): chunks as a grouping - IntIndex takes sparse values; ludic.things' chunk column and things_drop_chunk 2026-09-27 22:07:26 +03:00
near.ludic feat(ecs): thing_nearest_within - the nearest of a kind strictly within a radius, from the grid or the kind's list 2026-09-27 22:25:34 +03:00
package.ludic feat(packages): ludic.things - placed things in a world: a Thing record, an open registry of kinds whose behaviour is function values, spatial queries, spawn / put / remove / move verbs, facts and a save section by kind key 2026-09-25 06:14:32 +03:00
port.ludic feat(packages): ludic.things - placed things in a world: a Thing record, an open registry of kinds whose behaviour is function values, spatial queries, spawn / put / remove / move verbs, facts and a save section by kind key 2026-09-25 06:14:32 +03:00
queries.ludic feat(ecs): ludic.base Table<T> - dense rows of hot columns, generational handles, a spatial grid, kind indexes and an id map kept current by the setters; ludic.things on it 2026-09-27 15:52:51 +03:00
README.md ludic.things: a fact's record kept, in two halves swapped when a fact finds the queue empty 2026-09-28 12:45:40 +03:00
spare.ludic ludic.compass, inventory, shop, base, things: the compass's lists are state defaults and push through kept_push; the pack clears in place; setup, bind and load paths say so in @alloc_ok 2026-09-28 16:29:33 +03:00
store.ludic ludic.things: a fact's record kept, in two halves swapped when a fact finds the queue empty 2026-09-28 12:45:40 +03:00
system.ludic ludic.compass, inventory, shop, base, things: the compass's lists are state defaults and push through kept_push; the pack clears in place; setup, bind and load paths say so in @alloc_ok 2026-09-28 16:29:33 +03:00
verbs.ludic ludic.things: a removed Thing's record placed again, oldest first past a lag of 32; things_reserve sizes the grid once 2026-09-28 11:52:23 +03:00

ludic.things

The things placed in a world - a tent, a fire ring, a branch on the ground, a snare - and the kinds they are. The game names the kinds and draws them; the package keeps every Thing, answers where they are, asks a kind what it does, reports what happened, and saves the ones worth keeping. Uses ludic.base and nothing else.

import "ludic.things"

A Thing

property Thing {
  uid, kind, id          # unique for the run; its place in ThingKinds; what the kind says it means
  look                   # how the game draws it ("" is not drawn)
  x, y, z, yaw
  owner                  # whoever put it down, -1 the world's own
  active                 # false: taken, hidden, used up for now
  reach                  # how close it is used from (0: its kind's)
  timer, used, n         # state the kind decides the meaning of
  sx, sz, syaw           # where using it puts the user, and which way that faces
  shared                 # the game copies it to others (a party)
}

The kinds

ThingKinds is an open registry, filled by the game - usually one def per kind in one file, so TH_<KEY> is the order they are written in. A kind's behaviour is function values; a null one is a question the kind ignores.

def ThingKinds fire { name: "The campfire", prompt: fn fire_prompt, use: fn fire_use }
def ThingKinds lure { name_of: fn bait_name, tick: fn bait_wear, put_down: true, saved: true }
field
name, name_of: fn(Thing) -> string what it is called (name_of answering "" falls back to name)
prompt: fn(Thing) -> string, use: fn(Thing) what using it would do, and doing it
tick: fn(Thing, float) hours of the world's clock, for every active one
reach, reach_of: fn(Thing) -> float how close it is used from
personal one belongs to whoever put it down
saved the save section keeps a placed one (the port has the last word)
put_down set down by someone rather than grown by the world: a restock leaves it (the port has the last word)
keeps keeps its used through a restock

A removed Thing's record is placed again. Ludic frees nothing, and a world places and takes away Things all day, so thing_remove keeps the record and thing_put / thing_spawn make the oldest one again - set back as new, with a new uid - once 32 are waiting. Hold a Thing across a removal only by its uid (thing_by_uid), never by the record.

A fact's record (things_facts()) is kept too: it comes back two drains after it was handed out, so read a drained list before the drain after next, and copy what must last longer.

The port

Every member has a default, so any may be left out of the bind:

export port ThingsWorld {
  ground: fn(float, float) -> float   # the height a Thing stands at (unbound: 0)
  placed: fn(Thing)                   # it exists now: draw it
  removed: fn(Thing)                  # gone for good: stop drawing it
  shown: fn(Thing)                    # its `active` changed
  moved: fn(Thing)                    # it stands somewhere else
  keeps: fn(Thing) -> bool            # the save carries it (unbound: its kind's `saved`)
  put_down: fn(Thing) -> bool         # a restock leaves it be (unbound: its kind's `put_down`)
  restored: fn(Thing)                 # a load put it back, after `placed`
}

placed, removed, shown and moved are called at once, inside the verb, so the game can make the actor the moment the Thing exists (a caller often scales or tints it on the next line).

API

thing_spawn(kind, look, x, y, z, yaw, id) -> Thing, thing_put(kind, look, x, z, yaw, sink, reach, id) -> Thing a new Thing, at a height or on the ground set into it by sink
thing_remove(t), things_drop(gone: fn(Thing) -> bool), things_clear() gone for good (told to the port); a new world, quietly
things_reserve(n), things_spare_count() room in the grid for n Things, made once at the start; how many removed records wait to be placed again
thing_move(t, x, z, yaw), thing_move_to(t, x, y, z, yaw) on the ground there, or at a height
thing_hide(t), thing_show(t), thing_set_active(t, on) active, told to the port
things_all(), things_count(), things_ready(), thing_by_uid(uid) every Thing, in the order placed; whether a world was ever set out
thing_find(kind, id), thing_nearest(kind, x, z), things_within(x, z, r), things_each(kind), things_each_all(kind), thing_dist2(t, x, z) where they are: only active ones answer except the _all; a kind below 0 is any; within is nearest first
thing_name(t), thing_prompt(t), thing_use(t), thing_can_use(t), thing_reach(t), thing_kind(t), thing_is_personal(t), thing_is_put_down(t) the dispatcher
things_tick(hours), things_restock() every active kind that ticks; every Thing the world grew back and unused
things_facts() -> Queue<ThingFact> { what, uid, kind, id, owner, x, z }: THING_PLACED, THING_REMOVED, THING_USED
thing_kind_ok(k), thing_kind_by_key(key) the kinds
things_system() -> System "things", PH_COMMIT: its save section - every active Thing the port keeps, its kind by KEY, so the game may reorder its kinds - and a reset that removes the kept ones for the load to put back

Tests

ludic test packages/ludic.things