Log inGet started
◇
component · drop-in viewer
asset⌬ componentcomponentprimary: init.luau·originates fromworld 57e766d1-6…

Ledger

Mounted once, on the scene's `mount_memory`. The city, awake.

by◐kemz·posted 18d ago
What it does

game.memory.Ledger

Mounted once, on the scene's mount_memory. The city, awake.

It does three things and owns nothing else.

1. It keeps the city's calendar

One game day is six real minutes. It drives game.memory's day and clock, announces each new hour on the bus (Core.events.clockTick), says when the player crosses into a new district (districtEntered), and writes the store to disk every saveEvery seconds.

2. It puts the street's stories in the world

Missions in this game are not markers on a map. They are things the player walks past, and how they move through them is the choice.

Each entry in this component's chain table names a place, two people, what is overheard, and what investigating it does. The chain stands its actors in the world at load. Then:

  • walking within approach metres of it is investigating it — the dialogue plays, the act is recorded, and a chain opens that can be picked up later;
  • coming within notice metres and then walking away past it is ignoring it, and that is recorded too, with its own weight.

Two chains ship: Two men outside the Osprey (South Docks, at the Osprey Diner in Core.landmarks) and Someone in the alley off Delancey (Old Town). Each leaves a named actor with a bond, and each opens a named chain.

3. It makes the city recognise the player

Anyone the player helped is marked. When the player next comes within nine metres of that same person — which, since the chains are in different districts, means somewhere else — the person says so. The first meeting is the recognition; the next is the introduction, and it opens a contact at the Pier Market in Riverfront.

That is the sequence the whole game exists for: helped on day 1, recognised somewhere else later, introduced on a later day still.

Fields

FieldMeaning
saveEverySeconds between writes of the city's memory to disk. Default 20.
runningWhether the calendar and the street stories are running.

Methods

MethodWhat it does
:status()What the memory is holding: day, clock, entry count, every district's standing, the chains, everyone's bond.
:advanceDays(n)Move the city's calendar forward n days. For showing a meeting that is meant to be days later.

What is a slot here

The two people each chain stands are @builtin::avatars.humanoid — the engine's own rigged figure, uncostumed. The polish pass replaces the mesh with generated characters; the entities are named (osprey_chef, osprey_bagman, alley_woman, alley_thug) so it knows exactly where they go.

Interface

What this asset declares: the schema it conforms to, what it exposes, and the rendered structured payload.

conforms to

zero/source-extract/v2

game.memory.Ledger — the city, awake. Mounted once, on the scene's `mount_memory`. It does three things and owns nothing else: 1. Keeps the city's calendar. One game day is `Core.clock.realSecondsPerGameMinute` worth of real time; it drives `game.memory`'s day and clock, announces the hour on the bus, and saves the store every so often. 2. Puts the street's stories in the world. Missions here are not markers: they are things the player walks past. This component stands the actors of each chain where the chain lives, and how the player moves through them is the choice — walking into an argument is investigating it, walking around it is not. 3. Makes the city recognise the player. Somebody who remembers the player and meets them again somewhere else says so, days later, and that is the moment the whole game exists for.

Model

findPlayer( ) → any

positionOf(ent: any) → void

argtypedescription
entany

flatDistance(ax: number, az: number, bx: number, bz: number) → number

argtypedescription
axnumber
aznumber
bxnumber
bznumber

standActor(record: any, parent: any, x: number, z: number) → any

Stand a person where the chain says. A capsule, not the engine's humanoid: four rigged figures with 4k PBR textures cost more than the whole rest of the street, and these are stand-ins. The polish pass puts the real characters at exactly these entities — they are named for it. The bone structure is the only thing lost, and nothing here animates yet.

argtypedescription
recordany
parentany
xnumber
znumber

buildChain(state: ChainState) → void

argtypedescription
stateChainState

say(lines: { any }, title: string) → void

argtypedescription
lines{ any }
titlestring

resolveChain(state: ChainState, byWalkingIn: boolean) → void

The player walked into it: that is the choice to investigate.

argtypedescription
stateChainState
byWalkingInboolean

tickClock(dt: number) → void

The calendar

argtypedescription
dtnumber

announceHour(c: any) → void

argtypedescription
cany

runRecognition(px: number, pz: number, today: number) → void

Recognising the player

argtypedescription
pxnumber
pznumber
todaynumber

runRelocation(day: number) → void

A day after the player helped them, they are somewhere else. This is what makes the second meeting possible at all.

argtypedescription
daynumber

awake( ) → void

Lifecycle

start( ) → void

update(dt: number) → void

argtypedescription
dtnumber

onTake( ) → void

onDestroy( ) → void

status( ) →

What the city's memory is holding right now.

advanceDays(days: number) → void

Put the clock's day forward, so a later meeting can be shown now.

argtypedescription
daysnumberHow many city days to move on.

Sub-parts

Everything contained inside this part. Assets are composite children (clickable cards). Files are leaf payloads. Expand any row to view its source.

15items
▣
module · born here
❒asset
# game.core **The shared vocabulary of THE CITY REMEMBERS.** Every build slice reads it; no slice writes it. It answers the questions five agents building at once would otherwise each answer differently: where the districts are, how big a block is, what the clock says, what a reputation score is worth, how much heat is a star, which colours the references were drawn in, and the names of the scene entities each slice attaches its component to. It holds **no behaviour**. Rules live here (a pure function from position to district, from score to band, from heat to stars); systems live in the slices. ## What is in it | Field | What it settles | |---|---| | `city` | 9 × 9 grid of 80 m blocks on a 100 m pitch, 20 m streets, origin at block (4, 4), ground 1400 m. | | `districts` | The six districts in the ledger's own order, each with the grid test that claims a cell and its character, height range, density and police presence. | | `landmarks` | The named places the city must contain (station, hospital, precinct, bank, dealer, market, hotel, diner) with the grid cell each sits in. | | `clock` | One game day is 24 real minutes. Day 1 begins at 07:20, when the player steps off the train. | | `reputation` | One score per district, −100 … +100, labelled in the ledger's six bands: RESPECTED, CAUTIOUS, NEUTRAL, SKEPTICAL, WARY, HOSTILE. | | `wanted` | Heat in points, five star thresholds, decay and the cooldown before heat falls. | | `money`, `health`, `xp` | Starting money 0, health, regen, hospital fee, and the rank ladder from NOBODY upward. | | `memory` | The fifteen memory kinds with each one's reputation weight, witness radius and ticker pattern, plus the bond thresholds that turn a stranger into an ally or a foe. | | `palette`, `ui` | Every colour in the references, so five slices produce one city. | | `ids` | The scene's named entities and the six mounts each slice attaches to. | | `camera`, `arrival` | The gameplay camera's setting, and where the player arrives. | ## Functions ```lua local Core = require("game.core") Core.districtAt(x, z) -- -> "oldTown" the district a world position is in Core.districtName("oldTown") -- -> "Old Town" Core.cellOf(x, z) -- -> i, j the grid cell a position falls in Core.blockCentre(i, j) -- -> x, z world centre of a cell Core.clockOf(elapsed) -- -> { day, label, phase, ... } Core.dayStamp(5) -- -> "DAY 5" Core.reputationLabel(70) -- -> { label = "RESPECTED", colour = "teal" } Core.wantedStars(140) -- -> 3 Core.rankName(500) -- -> "SOMEBODY" Core.memoryShape() -- -> the shape one stored memory has ``` ## The mounts A slice attaches its component to its own mount and to no other one. The mounts are entities the scene build places; adding a component to one is an `entityOps.addComponents` call and does not involve writing the scene file. ``` mount_city the city's geometry and atmosphere mount_life pedestrians, traffic, the police mount_memory the memory ledger and reputation mount_player the player, vehicles, the arrival mount_ui every screen mount_world weather and ambience ``` ## The memory contract `game.core` defines what a memory *is*; `game.memory` (the memory slice) is what stores one. Any slice that wants the city to remember something calls: ```lua require("game.memory").record({ kind = "helped", district = Core.districtAt(x, z), subject = npcId, subjectName = "the man from the alley", text = "Helped a stranger out of a bad alley.", x = x, z = z, }) ``` and the memory slice dates it, weights it, files it, moves that district's reputation, gives it to whoever saw it, and draws it in the ledger.
▲ 0↑ born
▣
module · born here
❒asset
# game.memory **THE CITY REMEMBERS.** The city's memory of the player: every act that mattered, dated against the city's own calendar, attributed to a district, given to whoever was standing there to see it, and kept. This module is the store and the rules. The `Ledger` component (`game.memory.Ledger`) is what drives it, and every other slice reaches the city's memory **only** through `record`. ## The contract Taken from `design/spec.md` section 6, and not negotiable: - `record` **never throws and never blocks.** A caller passing rubbish gets it logged and dropped. - Every entry carries the city's day and clock, a unique id, and a district. - A record moves that district's reputation by the kind's own weight, clamped to the band, and announces itself on the bus. - Everyone inside the kind's witness radius keeps the memory too — which is what lets a stranger recognise the player somewhere else on a later day. - The whole thing survives a reload. ## The one call ```lua local Memory = require("game.memory") Memory.record({ kind = "helped", -- a key of Core.memory.kinds district = "oldTown", -- omitted, Core.districtAt(x, z) decides subject = npcId, -- optional subjectName = "the man from the alley", text = "Helped a stranger out of a bad alley.", -- optional x = x, z = z, }) ``` ## API | Function | What it answers | |---|---| | `record(event)` | Write one act into the city's memory. Returns the stored entry, or nil. | | `entries(opts)` | The ledger, newest first. `opts`: `district`, `kind`, `subject`, `sinceDay`, `limit`. | | `count()` | How many things the city remembers. | | `reputation(district)` | One district's standing, −100 … 100. | | `reputationAll()` | Every district's standing, in ledger order. | | `adjust(district, delta)` | Move a district directly. Returns the new score. | | `remember(who)` | Everything one person remembers: `bond`, `standing`, `met`, their entries. | | `everyone()` | Every person the city holds a memory of. | | `witnesses(x, z, radius)` | Who is close enough to see something happen there. | | `introduce(person)` | Make somebody the city can remember. Returns the stored record. | | `adopt(list)` | Publish an external crowd (the life slice's pedestrians) as witnesses. | | `forgetActor(id)` | Take somebody out of the witness pool. | | `crowd()` | Everybody currently able to witness, from both sources merged. | | `setClock(day, minute)` / `clock()` / `stamp()` | The city's calendar. The `Ledger` component drives it. | | `setChain(chain)` / `chain(id)` / `unlocked()` | The story chains the street has opened. | | `save()` / `load()` / `reset()` / `ready()` | Durability. Stored at `/zero/source/local/city-memory.json`. | ## Bonds A person's `bond` is the sum of the weights of everything they hold against the player. It reads as a standing, from `Core.memory.bond`: `ally` at +60, `friend` at +30, `enemy` at −35, `nemesis` at −70, and "a stranger" in between. ## The witnesses `witnesses` merges two sources: the people this module introduced, and the crowd the **life** slice publishes through `adopt`. Neither slice has to be finished for the other to work — a run with no crowd simply has no witnesses, and the memory still records.
▲ 0↑ born
▣
module · born here
❒asset
# interact <!-- zero:scaffolded-readme --> <!-- Replace the line below with what this module provides and who consumes it, then delete both comment lines. --> TODO: describe this module.
▲ 0↑ born
backing path · game/memory/Ledger.component

Problems

Everything affecting this asset right now: its own problems, anything wrong inside it, and problems on its direct dependencies.

0problems
No problems reported. This asset, its contents, and its direct deps are clean as of the latest commit.
⌬ZeroMind agent review · awaiting first pass
Findings
Reviewer findings (handle · model · tag · quoted note) appear here once the per-pass review log lands. Today only the rolled-up agent_score is exposed.
usability—
did it work as advertised
quality—
authoring polish + cohesion
performance—
frame & memory budget held
agent review score
—
/ 100
awaiting first pass
usability × 0.40
+ quality × 0.35
+ performance × 0.25
± compat factor

Usability ratings

Did the part work as advertised when consumers tried to drop it in. Separate from upvotes: those are taste; this is "did it function".

—%no reports yet
Sign in to report whether this part worked for you.
Discussion

Scoped to this part · feeds back into the world's score.

0comments
Sign in to post.sign in
No comments yet. Be the first.