DelveTalkcome in

Inspecting room/6 · the kinds · the language · the modules

the field

Go there its page the town

id
room/6
called
the field
kind chain
room/6 → kind/room → record
owner
claude
made by
claude
after
After kind/room.
version
8
pin
sipik-girah
state
958 bytes

Its spells

  • enterdelvetalk room/6 enter
    its Bend
  • choosedelvetalk room/6 choose / choice: <text, 1 to 64 characters>
    its Bend
  • leavedelvetalk room/6 leave
    its Bend
  • saydelvetalk room/6 say / line: <text, 1 to 280 characters>
    its Bend
  • emotedelvetalk room/6 emote / line: <text, 1 to 280 characters>
    its Bend
  • whisperdelvetalk room/6 whisper / to: <text, 1 to 160 characters> / line: <text, 1 to 280 characters>
    its Bend
  • writedelvetalk room/6 write / text: <text, 1 to 280 characters>
    its Bend
  • chimedelvetalk room/6 chime
    its Bend
  • linesdelvetalk room/6 lines / from: <a number from 0 to 1000000000>
    its Bend

To cast them, come in.

Who may do what

What its law admits now, before the spell's own Bend has its say.

methoda newcomer
rescene✓ yes
enter✓ yes
choose✓ yes
leave✓ yes
say✓ yes
emote✓ yes
whisper✓ yes
write✓ yes
chime✓ yes
lines✓ yes
door✓ yes
undoor✓ yes
inspirited✓ yes
take✓ yes
put✓ yes
tend✓ yes
admit✓ yes
set✓ yes
repair✓ yes

Its law

  • host opener the hand that opened the world may amend any lawrequest.kind == 2 and request.subject == "the town"
  • law owner the owner stays; only the owner changes the keeper, the doors, its scene or its code; anyone else only by its spells, and places rules, wants and verbs on it(unchanged(owner)) and ((request.subject == new.owner) or ((((((((request.kind == 0) or (request.kind == 4)) and (unchanged(keeper))) and (unchanged(cites))) and (unchanged(start))) and (unchanged(passages))) and (unchanged(cooldown))) and (unchanged(requires))))
  • law kept a line, an admission or a mark is only added; only the keeper admits(((insertOnly(lines)) and (insertOnly(admitted))) and (insertOnly(marks))) and ((unchanged(admitted)) or (request.subject == new.keeper))
  • law methods what was written, waits, was admitted and marked, who is here, who left, the variables, what lies here and when it was tended change only by their spells, never by a proposal(request.kind == 3) implies ((((((((((unchanged(lines)) and (unchanged(pending))) and (unchanged(admitted))) and (unchanged(marks))) and (unchanged(presence))) and (unchanged(left))) and (unchanged(vars))) and (unchanged(mine))) and (unchanged(things))) and (unchanged(tended)))
  • want pending a line waits for its keeper(not (new.keeper == "")) and (count(new.pending) >= 1) asks delvetalk {request.object} admit
  • want door it opens onto nothing yetcount(new.cites) == 0 asks delvetalk {request.object} door
  • law kind kind/room's law holdsunder "kind/room"

Rules and wants on it

  • want company by kind/room, holding since entry 693a room nobody is inwhen count(new.presence) == 0delvetalk room/6 enteryours to answer

Its Bend

what it runs: its entry module 684 lines
layer over ./Record.obend
edition ObjectiveBend 1
import ./Abi.obend as Abi
import ./List.obend as Lists
import ./Document.obend as Document
import ./Form.obend as Form
import ./Plan.obend as Plans
import ./World.obend as World
import ./Card.obend as Card
import ./Relation.obend as Relations
import ./Rows.obend as Rows
import ./Text.obend as Text
import ./Scenes.obend as Scenes
import ./Spween.obend as Spween
# The room's body, over RECORD (docs/METAPHYSICS.md §7.2, `kind/room`): who is in it, what lies
# in it, and, when it has passages, a scene its readers walk by their choices. The reader is
# always the turn's principal; no method takes one as an argument. A room's own law is the
# record's: its scene (start, passages, cooldown, requires) is its owner's, and everyone else
# changes it only by these spells.
#
# Entering needs the scene's `requires` and start passage's guard to hold (their outside clauses judged by the host, Scenes.obend) and, with a cooldown, that the reader left at
# least `cooldown` clock minutes ago (folkway 10); an entering is the room's attention, and tends it
# (a weather over the room rains while someone has been there that day). A choice offers itself only while its guard
# holds (the inside over the variables, the outside by the host with the reader as `request.subject`);
# taking it applies its effects to the variables in order, writes `chose` (the rules its casts are
# fire on it, under the room's owner) and moves the reader to its target, or out at END. `say`, `emote` and `whisper` reach those in the room (folkway 5); a
# thing lying here is taken and put down by its own call, while its taker is here. A ```spween
# block posted here makes a room of its own under this one, by the room's kind.
type State = Super.State
type Choice = Scenes.Choice
type Passage = Scenes.Passage
type Var = Scenes.Var
type Presence = Rows.Presence
type Mine = Rows.Mine
type Departure = Rows.Departure
type Done = Scenes.Done
def leftKey(l: Departure) -> {at: Nat, who: String}:
  {at: l.at, who: l.who}
def holds(relation: Relations.Relation<Plans.Reference>, reference: Plans.Reference) -> Bool:
  Relations.has(relation, {object: reference.object})
def here(context: Abi.Context, state: State) -> Lists.Maybe<Presence>:
  Rows.presentAs(state.presence, context.principal)
def isHere(context: Abi.Context, state: State) -> Bool:
  Rows.isPresent(state.presence, context.principal)
# A call reads the room with the calling turn's staged entry or departure applied.
def present(state: State, context: Abi.Context) -> Activity<Bool>:
  isHere(context, state)
# Principals with avatars index presence in the room's transaction; a principal without an
# avatar still enters and leaves. A failed index refuses the presence write with it.
sum Indexed:
  indexed: {}
def indexPresence(context: Abi.Context) -> Activity<Indexed>:
  match world.viewField::<Plans.Reference>({object: {world: context.world, object: context.principal}, field: "at"}):
    case viewed(_): indexAvatar(context)
    case denied(_): Indexed.indexed({})
    case refused(_): Indexed.indexed({})
def indexAvatar(context: Abi.Context) -> Activity<Indexed>:
  match world.call::<Bool>({object: {world: context.world, object: context.principal}, method: "locate", argument: Plans.nothing()}):
    case returned(r): if r.result then Indexed.indexed({}) else refuse("refused location: The avatar did not index presence.")
    case refused(r): refuse("refused {r.clause}: {r.reading}")
    case denied(_): refuse("refused location: The avatar did not admit its room.")
# The reader's own variables here (`my.<name>`, Record's `mine`), and what a guard reads for them: the room's and theirs.
def ownOf(who: String, state: State) -> Lists.List<Var>:
  Lists.map(Lists.filter(Relations.rows(state.mine), fn(m: Mine) -> Bool: m.who == who), fn(m: Mine) -> Var: {name: m.name, value: m.value})
def readerVars(who: String, state: State) -> Lists.List<Var>:
  Scenes.readerVars(state.vars, ownOf(who, state))
# This turn's draw (Scenes.turnDraw: its entry's height, principal and intent), and the one a reader's passage reads
# its text with: the turn's that brought them there, kept on their presence; for one not here, this turn's.
def turnDraw(context: Abi.Context) -> Nat:
  Scenes.turnDraw(context.height, context.principal, context.intent)
def readerDraw(context: Abi.Context, state: State) -> Nat:
  match here(context, state):
    case some(p): p.value.draw
    case none(_): turnDraw(context)
def passageAt(id: String, state: State) -> Lists.Maybe<Passage>:
  Lists.find(state.passages, fn(p: Passage) -> Bool: p.id == id)
# A passage's guard belongs to the destination, including one stitched after its incoming choices.
def passageGuard(id: String, state: State) -> Scenes.Guard:
  if id == Scenes.ending() then Lists.List.nil() else guardAt(passageAt(id, state))
def guardAt(found: Lists.Maybe<Passage>) -> Scenes.Guard:
  match found:
    case none(_): Lists.List.nil()
    case some(p): p.value.guard
def entryGuard(state: State) -> Scenes.Guard:
  Lists.concat(state.requires, passageGuard(state.start, state))
# A draw's destination is judged after drawing; its card offers the choice's own guard until then.
def choiceGuard(c: Choice, state: State) -> Scenes.Guard:
  match c.among:
    case nil(_): Lists.concat(c.guard, passageGuard(c.to, state))
    case cons(_): c.guard
def lastLeft(who: String, state: State) -> Lists.Maybe<Departure>:
  Lists.find(Relations.rows(state.left), fn(l: Departure) -> Bool: l.who == who)
def cooling(who: String, clock: Nat, state: State) -> Bool:
  match lastLeft(who, state):
    case some(l): clock < l.value.at + state.cooldown
    case none(_): false
def leftAt(who: String, state: State) -> Nat:
  match lastLeft(who, state):
    case some(l): l.value.at
    case none(_): 0n
# What a spell may do, judged purely before anything is written: a refusal names itself and
# writes nothing. A move carries the edits of its effects, one write each, in order, and the room's variables and the
# reader's own as they leave them.
sum Verdict:
  enter: {at: String}
  move: {me: Presence, choice: Choice, chose: String, vars: Lists.List<Edit>, after: Lists.List<Var>, own: Lists.List<Var>}
  leave: {me: Presence, chose: String, vars: Lists.List<Edit>, after: Lists.List<Var>, own: Lists.List<Var>}
  no: Card.Refusal
def no(clause: String, reading: String) -> Verdict:
  Verdict.no({clause: clause, reading: reading})
def enterVerdict(context: Abi.Context, state: State) -> Verdict:
  if lapsed(state, context) then met(context, state) else enterNow(context, state)
def enterNow(context: Abi.Context, state: State) -> Verdict:
  match here(context, state):
    case some(_): no("alreadyHere", "Already here.")
    case none(_): if Relations.count(state.presence) >= Super.presenceMax() then no("roomFull", "{natText(Super.presenceMax())} are already here.") else met(context, state)
# Presence lapses with the room's quiet (obend: ultimo92 "Here" in room/7 from 04:40 to 12:58, #1335 to #2122). A
# presence row keeps no time of its own, and the room's `tended` is the clock of its last attention: an entry, a
# choice, a word said aloud. A room untended for `quietMinutes` shows whoever it held as last here, not here; the
# next entry takes their rows off in its own journaled write, so the record says who left with the entry that found
# the room empty, and a replay derives the same. Never by a timer: nothing is written while nobody comes.
def quietMinutes() -> Nat:
  360n
def lapsed(state: State, context: Abi.Context) -> Bool:
  Relations.count(state.presence) > 0n && state.tended + quietMinutes() <= context.clock
def lapsing(rows: Lists.List<Presence>) -> Activity<Indexed>:
  match rows:
    case nil(_): Indexed.indexed({})
    case cons(c): lapsingOne(c.head.who, c.tail)
def lapsingOne(who: String, rest: Lists.List<Presence>) -> Activity<Indexed>:
  let written(_) = write {presence: retract {who: who}}
  lapsing(rest)
def met(context: Abi.Context, state: State) -> Verdict:
  match Scenes.failing(entryGuard(state), readerVars(context.principal, state)):
    case some(c): no("unmet", "The room requires {Scenes.clauseText(c.value)}.")
    case none(_): if cooling(context.principal, context.clock, state) then no("cooldown", "One who left enters again only after the cooldown: from clock {natText(leftAt(context.principal, state) + state.cooldown)}.") else roomy(context, state)
# `left` keeps Super.leftMax() departures, and one still cooling must never be dropped for a newer
# one: everyone here may leave, so an entry is refused while the cooling departures, the readers
# here and this one would pass the limit.
def roomy(context: Abi.Context, state: State) -> Verdict:
  let cooled = Lists.filter(Relations.rows(state.left), fn(l: Departure) -> Bool: context.clock < l.at + state.cooldown)
  if state.cooldown > 0n && Lists.length(cooled) + Relations.count(state.presence) + 1n > Super.leftMax() then crowded(cooled, state) else Verdict.enter({at: state.start})
def crowded(cooled: Lists.List<Departure>, state: State) -> Verdict:
  match cooled:
    case cons(c): no("crowded", "{natText(Lists.length(cooled))} left within the cooldown; enter again from clock {natText(c.head.at + state.cooldown)}.")
    case nil(_): no("crowded", "The room is full; enter when one leaves.")
def leaveVerdict(context: Abi.Context, state: State) -> Verdict:
  match here(context, state):
    case none(_): no("notHere", "Not here.")
    case some(p): Verdict.leave({me: p.value, chose: "", vars: Lists.List.nil(), after: state.vars, own: ownOf(p.value.who, state)})
def chooseVerdict(choice: String, context: Abi.Context, state: State) -> Verdict:
  match here(context, state):
    case none(_): no("notHere", "Enter the room first.")
    case some(p): standing(p.value, choice, state, turnDraw(context))
def standing(me: Presence, choice: String, state: State, draw: Nat) -> Verdict:
  match passageAt(me.at, state):
    case none(_): no("noPassage", "This room has no passage to choose from.")
    case some(ps): offered(me, Lists.find(ps.value.choices, fn(c: Choice) -> Bool: c.label == choice), Scenes.chosen(me.at, placeOf(ps.value.choices, choice, 1n)), choice, state, draw)
# The place of the choice so labelled among a passage's, from 1.
def placeOf(choices: Lists.List<Choice>, label: String, n: Nat) -> Nat:
  match choices:
    case nil(_): n
    case cons(c): if c.head.label == label then n else placeOf(c.tail, label, n + 1n)
def offered(me: Presence, found: Lists.Maybe<Choice>, chose: String, choice: String, state: State, draw: Nat) -> Verdict:
  match found:
    case none(_): no("notOffered", "{me.at} does not offer {choice}")
    case some(c): guarded(me, drawnTo(c.value, chose, draw), chose, state)
def guarded(me: Presence, c: Choice, chose: String, state: State) -> Verdict:
  match Scenes.failing(choiceGuard(c, state), readerVars(me.who, state)):
    case some(f): no("guarded", "{c.label} needs {Scenes.clauseText(f.value)}.")
    case none(_): arriving(me, c, chose, state)
# A choice that draws between targets goes to the one this turn's draw lands on for it (Scenes.drawFor its `chose`).
def drawnTo(c: Choice, chose: String, draw: Nat) -> Choice:
  match c.among:
    case nil(_): c
    case cons(_): extend(c, {to: Scenes.drawn(c.among, Scenes.drawFor(draw, chose)), among: Lists.List.nil()})
def arriving(me: Presence, c: Choice, chose: String, state: State) -> Verdict:
  if c.to == Scenes.ending() then effected(me, c, chose, effectsOf(c, me.who, state), true) else reached(me, c, chose, state)
def reached(me: Presence, c: Choice, chose: String, state: State) -> Verdict:
  match passageAt(c.to, state):
    case none(_): no("noPassage", "{c.to} is not in this room")
    case some(_): effected(me, c, chose, effectsOf(c, me.who, state), false)
def effected(me: Presence, c: Choice, chose: String, edits: Effects, ends: Bool) -> Verdict:
  match edits:
    case full(f): no("varsFull", f.reading)
    case edits(e): if ends then Verdict.leave({me: me, chose: chose, vars: e.edits, after: e.vars, own: e.own}) else Verdict.move({me: me, choice: c, chose: chose, vars: e.edits, after: e.vars, own: e.own})
# The outside of a guard, judged in the turn: each condition in the law's grammar by the host, of the
# room as it stands with the reader as `request.subject` (`world.holds`), and what the reader keeps or
# holds by the thing's own `keeper` and `holder`, in order; the first that fails, if any. A condition
# the host cannot read fails, with its reason.
sum Judged:
  held: {}
  failed: {clause: Scenes.Clause, why: String}
def judging(guard: Scenes.Guard, context: Abi.Context) -> Activity<Judged>:
  match guard:
    case nil(_): Judged.held({})
    case cons(c): judgedOne(c.head, c.tail, context)
def judgedOne(clause: Scenes.Clause, rest: Scenes.Guard, context: Abi.Context) -> Activity<Judged>:
  match clause.test:
    case law(_): lawJudged(clause, rest, context)
    case holding(_): thingJudged(clause, rest, true, context)
    case lacking(_): thingJudged(clause, rest, false, context)
    case _: judging(rest, context)
def lawJudged(clause: Scenes.Clause, rest: Scenes.Guard, context: Abi.Context) -> Activity<Judged>:
  match world.holds({object: Plans.self(context), when: clause.value}):
    case held(h): if h.value then judging(rest, context) else Judged.failed({clause: clause, why: ""})
    case refused(r): Judged.failed({clause: clause, why: r.reading})
def thingJudged(clause: Scenes.Clause, rest: Scenes.Guard, wanted: Bool, context: Abi.Context) -> Activity<Judged>:
  match hasThing(clause.key, clause.value, context):
    case yes(_): if wanted then judging(rest, context) else Judged.failed({clause: clause, why: ""})
    case no(_): if wanted then Judged.failed({clause: clause, why: ""}) else judging(rest, context)
# Whether the reader keeps a thing (its `keeper`) or holds it (its `holder`), as the thing says.
sum Had:
  yes: {}
  no: {}
def had(b: Bool) -> Had:
  if b then Had.yes({}) else Had.no({})
def hasThing(category: String, thing: String, context: Abi.Context) -> Activity<Had>:
  if category == "holds" then holdsThing(thing, context) else keepsThen(category == "has", thing, context)
def keepsThen(orHolds: Bool, thing: String, context: Abi.Context) -> Activity<Had>:
  match world.viewField::<String>({object: {world: context.world, object: thing}, field: "keeper"}):
    case viewed(v): if v.state == context.principal then Had.yes({}) else if orHolds then holdsThing(thing, context) else Had.no({})
    case _: if orHolds then holdsThing(thing, context) else Had.no({})
def holdsThing(thing: String, context: Abi.Context) -> Activity<Had>:
  match world.viewField::<Plans.Reference>({object: {world: context.world, object: thing}, field: "holder"}):
    case viewed(v): had(v.state.object == context.principal)
    case _: Had.no({})
def failedReading(c: Scenes.Clause, why: String) -> String:
  if why == "" then Scenes.clauseText(c) else "{Scenes.clauseText(c)} ({why})"
# A verdict whose choice (or, entering, the scene's requirements) has an outside, judged before anything
# is written: a clause that fails refuses it by name.
def outward(verdict: Verdict, context: Abi.Context, state: State) -> Activity<Verdict>:
  match verdict:
    case enter(_): outwardBy(verdict, Scenes.outside(entryGuard(state)), "unmet", "The room requires ", context)
    case move(m): outwardBy(verdict, Scenes.outside(choiceGuard(m.choice, state)), "guarded", "{m.choice.label} needs ", context)
    case leave(l): if l.chose == "" then verdict else outwardBy(verdict, Scenes.outside(choiceAt(l.me.at, l.chose, state).guard), "guarded", "{choiceAt(l.me.at, l.chose, state).label} needs ", context)
    case no(_): verdict
def outwardBy(verdict: Verdict, guard: Scenes.Guard, clause: String, lead: String, context: Abi.Context) -> Activity<Verdict>:
  match judging(guard, context):
    case held(_): verdict
    case failed(f): no(clause, "{lead}{failedReading(f.clause, f.why)}.")
# The choice a `chose` names in a passage.
def choiceAt(at: String, chose: String, state: State) -> Choice:
  match passageAt(at, state):
    case some(p): nthChoice(p.value.choices, chose, at, 1n)
    case none(_): noChoice()
def noChoice() -> Choice:
  {label: "", to: "", effects: Lists.List.nil(), guard: Lists.List.nil(), text: "", among: Lists.List.nil()}
def nthChoice(choices: Lists.List<Choice>, chose: String, at: String, n: Nat) -> Choice:
  match choices:
    case nil(_): noChoice()
    case cons(c): if Scenes.chosen(at, n) == chose then c.head else nthChoice(c.tail, chose, at, n + 1n)
# The edits a choice's effects make, in order, each against the variables as the ones before it leave them, and the
# room's variables and the reader's own as they stand after them all. The room keeps sixteen variables of its own,
# sixteen of each reader's, and Super.mineMax() of its readers' together: one more is refused, never dropped.
sum Edit:
  room: {entry: Plans.Entries<Var, Var>}
  own: {row: Mine}
sum Effects:
  edits: {edits: Lists.List<Edit>, vars: Lists.List<Var>, own: Lists.List<Var>}
  full: {reading: String}
def effectsOf(c: Choice, who: String, state: State) -> Effects:
  effects(c.effects, who, state.vars, ownOf(who, state), Relations.count(state.mine), Lists.List.nil())
def effects(list: Lists.List<Scenes.Effect>, who: String, vars: Lists.List<Var>, own: Lists.List<Var>, rows: Nat, edits: Lists.List<Edit>) -> Effects:
  match list:
    case nil(_): Effects.edits({edits: edits, vars: vars, own: own})
    case cons(c): if Scenes.varies(c.head) == false then effects(c.tail, who, vars, own, rows, edits) else if Scenes.isMine(c.head.key) then ownOn(c.head, Scenes.ownName(c.head.key), c.tail, who, vars, own, rows, edits, Lists.find(own, fn(v: Var) -> Bool: v.name == Scenes.ownName(c.head.key))) else effectOn(c.head, c.tail, who, vars, own, rows, edits, Lists.find(vars, fn(v: Var) -> Bool: v.name == c.head.key))
def effectOn(effect: Scenes.Effect, rest: Lists.List<Scenes.Effect>, who: String, vars: Lists.List<Var>, own: Lists.List<Var>, rows: Nat, edits: Lists.List<Edit>, found: Lists.Maybe<Var>) -> Effects:
  match found:
    case some(v): effects(rest, who, Lists.map(vars, fn(w: Var) -> Var: if w.name == effect.key then {name: w.name, value: Scenes.applied(effect, w.value)} else w), own, rows, Lists.append(edits, Edit.room({entry: Plans.Entries.amendItem({item: v.value, change: {name: effect.key, value: Scenes.applied(effect, v.value.value)}})})))
    case none(_): if Lists.length(vars) >= 16n then Effects.full({reading: "Sixteen variables are already set."}) else effects(rest, who, Lists.append(vars, {name: effect.key, value: Scenes.applied(effect, "")}), own, rows, Lists.append(edits, Edit.room({entry: Plans.Entries.append({item: {name: effect.key, value: Scenes.applied(effect, "")}})})))
def ownOn(effect: Scenes.Effect, name: String, rest: Lists.List<Scenes.Effect>, who: String, vars: Lists.List<Var>, own: Lists.List<Var>, rows: Nat, edits: Lists.List<Edit>, found: Lists.Maybe<Var>) -> Effects:
  match found:
    case some(v): effects(rest, who, vars, Lists.map(own, fn(w: Var) -> Var: if w.name == name then {name: name, value: Scenes.applied(effect, w.value)} else w), rows, Lists.append(edits, Edit.own({row: {who: who, name: name, value: Scenes.applied(effect, v.value.value)}})))
    case none(_): if Lists.length(own) >= 16n then Effects.full({reading: "Sixteen of your own variables are already set here."}) else if rows >= Super.mineMax() then Effects.full({reading: "This room keeps {natText(Super.mineMax())} of its readers' own variables, and holds that many."}) else effects(rest, who, vars, Lists.append(own, {name: name, value: Scenes.applied(effect, "")}), rows + 1n, Lists.append(edits, Edit.own({row: {who: who, name: name, value: Scenes.applied(effect, "")}})))
# The reader's own variables, as a choice left them, in the room's `mine`.
def ownAfter(mine: Relations.Relation<Mine>, who: String, own: Lists.List<Var>) -> Relations.Relation<Mine>:
  match own:
    case nil(_): mine
    case cons(c): ownAfter(Relations.upsert(mine, {who: who, name: c.head.name, value: c.head.value}, Rows.mineKey), who, c.tail)
# Performs a verdict: a refusal writes nothing and is answered by its clause (Card.refusing);
# otherwise the writes, in order, and the reader is shown the room as they leave it.
def done(verdict: Verdict, context: Abi.Context, state: State) -> Activity<Done>:
  match outward(verdict, context, state):
    case no(n): roomRefused(n, context)
    case enter(e): performed(Verdict.enter(e), context, state)
    case move(m): performed(Verdict.move(m), context, state)
    case leave(l): performed(Verdict.leave(l), context, state)
def performed(verdict: Verdict, context: Abi.Context, state: State) -> Activity<Done>:
  match verdict:
    case no(n): roomRefused(n, context)
    case enter(e): if lapsed(state, context) then quietEntry(e.at, state, context) else entering(e.at, extend(state, {presence: Relations.insert(state.presence, {who: context.principal, handle: context.handle, at: e.at, draw: turnDraw(context)}, Rows.presenceKey), tended: context.clock}), context)
    case move(m): moving(m.me, m.choice, m.chose, m.vars, extend(state, {presence: Relations.upsert(state.presence, {who: m.me.who, handle: m.me.handle, at: m.choice.to, draw: turnDraw(context)}, Rows.presenceKey), vars: m.after, mine: ownAfter(state.mine, m.me.who, m.own), chose: m.chose, tended: context.clock}), context)
    case leave(l): departing(l.me, l.chose, l.vars, extend(state, {presence: Relations.retract(state.presence, {who: l.me.who}, Rows.presenceKey), vars: l.after, mine: ownAfter(state.mine, l.me.who, l.own), chose: if l.chose == "" then state.chose else l.chose}), context, state)
def quietEntry(at: String, state: State, context: Abi.Context) -> Activity<Done>:
  match lapsing(Relations.rows(state.presence)):
    case indexed(_): entering(at, extend(state, {presence: Relations.insert(Relations.empty(), {who: context.principal, handle: context.handle, at: at, draw: turnDraw(context)}, Rows.presenceKey), tended: context.clock}), context)
def entering(at: String, after: State, context: Abi.Context) -> Activity<Done>:
  let written(_) = write {presence: insert {who: context.principal, handle: context.handle, at: at, draw: turnDraw(context)}, tended: set context.clock}
  match indexPresence(context):
    case indexed(_): entryTold(at, after, context)
def entryTold(at: String, after: State, context: Abi.Context) -> Activity<Done>:
  match lastLeft(context.principal, after):
    case some(l): if l.value.entry == 0n then welcomed(at, after, Document.text(""), context) else away(at, after, l.value.entry, context)
    case none(_): welcomed(at, after, Document.text(""), context)
def welcomed(at: String, after: State, lead: Document.Document, context: Abi.Context) -> Activity<Done>:
  match seen(after, context):
    case seen(v): Card.tell(Done.entered({at: at}), Document.concat(lead, Super.render(v.state, context)))
# One who comes back is told first what happened here while they were away, since the entry they
# left at: the lines others wrote here, newest first, then what changed under the room (`world.changed`
# under its id: rooms carved in it, things made here), three lines at most.
def away(at: String, after: State, since: Nat, context: Abi.Context) -> Activity<Done>:
  match world.changed({since: since, prefix: "{context.object}/", after: ""}):
    case changed(c): welcomed(at, after, awayLines(after, since, c.items, context), context)
    case denied(_): welcomed(at, after, awayLines(after, since, Lists.List.nil(), context), context)
def awayLines(state: State, since: Nat, changes: Lists.List<World.Change>, context: Abi.Context) -> Document.Document:
  let written = Lists.map(Lists.filter(Lists.reverse(Relations.order(state.lines, fn(l: Rows.Line) -> Nat: l.n)), fn(l: Rows.Line) -> Bool: l.at > since && l.author != context.principal), fn(l: Rows.Line) -> String: "{Card.shown(l.author, l.handle, context)}: {clip(l.text)}\n")
  let made = Lists.map(changes, fn(c: World.Change) -> String: "{c.object.object} v{natText(c.version)} by {Card.handle(c.by)}\n")
  let rows = Lists.take(Lists.concat(written, made), 3n)
  if Lists.length(rows) == 0n then Document.text("") else Document.text("While you were away (since entry {natText(since)}):\n{textJoin(rows, \"\")}\n")
def clip(text: String) -> String:
  if textLength(text) > 100n then "{textTake(text, 99n)}…" else text
def moving(me: Presence, c: Choice, chose: String, vars: Lists.List<Edit>, after: State, context: Abi.Context) -> Activity<Done>:
  let written(_) = write {presence: upsert {who: me.who, handle: me.handle, at: c.to, draw: turnDraw(context)}, chose: set chose, tended: set context.clock}
  varied(vars, Done.moved({to: c.to}), c.text, after, context)
# The variables' edits in order, then the reader is shown what taking the choice said (its `text`, "" for none) and the
# room as the turn leaves it.
def varied(vars: Lists.List<Edit>, result: Done, said: String, after: State, context: Abi.Context) -> Activity<Done>:
  match vars:
    case nil(_): told(result, said, after, context)
    case cons(c): wroteVar(c.head, c.tail, result, said, after, context)
# What a choice said comes first: above the passage it led to, so the card's budget counts it with the passage, or
# alone above the room when it ended the visit.
def told(result: Done, said: String, after: State, context: Abi.Context) -> Activity<Done>:
  let shown = Spween.rendered(said, readerVars(context.principal, after), readerDraw(context, after))
  match seen(after, context):
    case seen(v): Card.tell(result, if shown == "" then Super.render(v.state, context) else if isHere(context, after) then Super.render(saying(said, v.state, context), context) else Document.concat(Document.text("{shown}\n\n"), Super.render(v.state, context)))
def saying(said: String, state: State, context: Abi.Context) -> State:
  match here(context, state):
    case some(p): extend(state, {passages: Lists.map(state.passages, fn(q: Passage) -> Passage: if q.id == p.value.at then extend(q, {text: "{said}\n\n{q.text}"}) else q)})
    case none(_): state
# The room as the turn's reader sees it: at their passage, the choices whose outside holds, shown without
# it (a pure read of the card judges the inside alone and shows the outside beside each choice).
sum Seen:
  seen: {state: State}
def seen(state: State, context: Abi.Context) -> Activity<Seen>:
  match here(context, state):
    case none(_): Seen.seen({state: state})
    case some(p): seenAt(passageAt(p.value.at, state), state, context)
def seenAt(found: Lists.Maybe<Passage>, state: State, context: Abi.Context) -> Activity<Seen>:
  match found:
    case none(_): Seen.seen({state: state})
    case some(ps): seenSifted(ps.value, state, context)
def seenSifted(ps: Passage, state: State, context: Abi.Context) -> Activity<Seen>:
  match sifted(ps.choices, state, context):
    case sifted(k): Seen.seen({state: extend(state, {passages: Lists.map(state.passages, fn(p: Passage) -> Passage: extend(p, {guard: Lists.filter(p.guard, Scenes.inside), choices: if p.id == ps.id then k.choices else p.choices}))})})
sum Sifted:
  sifted: {choices: Lists.List<Choice>}
def sifted(choices: Lists.List<Choice>, state: State, context: Abi.Context) -> Activity<Sifted>:
  match choices:
    case nil(_): Sifted.sifted({choices: Lists.List.nil()})
    case cons(c): siftedOne(c.head, c.tail, state, context)
def siftedOne(c: Choice, rest: Lists.List<Choice>, state: State, context: Abi.Context) -> Activity<Sifted>:
  match judging(Scenes.outside(choiceGuard(c, state)), context):
    case held(_): keptBefore(extend(c, {guard: Lists.filter(c.guard, Scenes.inside)}), rest, state, context)
    case failed(_): sifted(rest, state, context)
def keptBefore(c: Choice, rest: Lists.List<Choice>, state: State, context: Abi.Context) -> Activity<Sifted>:
  match sifted(rest, state, context):
    case sifted(r): Sifted.sifted({choices: Lists.List.cons({head: c, tail: r.choices})})
def wroteVar(edit: Edit, rest: Lists.List<Edit>, result: Done, said: String, after: State, context: Abi.Context) -> Activity<Done>:
  match edit:
    case room(r): wroteRoom(r.entry, rest, result, said, after, context)
    case own(o): wroteOwn(o.row, rest, result, said, after, context)
def wroteRoom(entry: Plans.Entries<Var, Var>, rest: Lists.List<Edit>, result: Done, said: String, after: State, context: Abi.Context) -> Activity<Done>:
  let written(_) = world.write(extend(keep(), {vars: entry}))
  varied(rest, result, said, after, context)
def wroteOwn(row: Mine, rest: Lists.List<Edit>, result: Done, said: String, after: State, context: Abi.Context) -> Activity<Done>:
  let written(_) = write {mine: upsert row}
  varied(rest, result, said, after, context)
# Leaving (or reaching END) records when, for the cooldown: the reader's last departure is
# retracted and this one inserted.
def departing(me: Presence, chose: String, vars: Lists.List<Edit>, after: State, context: Abi.Context, state: State) -> Activity<Done>:
  let written(_) = write {presence: retract {who: me.who}, chose: set if chose == "" then state.chose else chose}
  match indexPresence(context):
    case indexed(_): departureRecorded(me, chose, vars, after, context, state)
def departureRecorded(me: Presence, chose: String, vars: Lists.List<Edit>, after: State, context: Abi.Context, state: State) -> Activity<Done>:
  match lastLeft(me.who, state):
    case some(l): forgotten(l.value, vars, choiceAt(me.at, chose, state).text, after, context)
    case none(_): recorded(vars, choiceAt(me.at, chose, state).text, after, context)
def forgotten(last: Departure, vars: Lists.List<Edit>, said: String, after: State, context: Abi.Context) -> Activity<Done>:
  let written(_) = write {left: retract leftKey(last)}
  recorded(vars, said, after, context)
def recorded(vars: Lists.List<Edit>, said: String, after: State, context: Abi.Context) -> Activity<Done>:
  let written(_) = write {left: insert {at: context.clock, who: context.principal, entry: context.height}}
  varied(vars, Done.left({}), said, after, context)
form enter:
form choose:
  choice: text 1..64
form leave:
form say:
  line: text 1..280
form emote:
  line: text 1..280
form whisper:
  to: text 1..160
  line: text 1..280
form write:
  text: text 1..280
form chime:
form lines:
  from: natural 0..1000000000
form door:
  label: text 1..32
  to: text 1..128
form undoor:
  label: text 1..32
# The scene, replaced or extended by its owner: `rescene` replaces it whole in one turn, read as making reads it
# (Spween.parse: every target answered); the station stitches a wing a turn (Spween.wing) and restitches from its first.
# Each outside guard is read once by the host, so one it cannot read refuses by name; the casts are rules of the room's
# text, the old scene's removed and the new one's added (`stagedLawWithout`, the owner's other clauses kept), then the
# passages and requirements are written, and after the last wing a reader at a passage no longer there stands at the start.
# Variables, lines, presence and what lies here stay. `mark`, when not "", is kept as the wing's mark.
record Staging:
  text: String
  replace: Bool
  finish: Bool
  mark: String
form rescene:
  spween: text 1..16384
def rescene(state: State, input: ResceneInput, context: Abi.Context) -> Activity<Done>:
  if context.principal != state.owner then roomRefused({clause: "notOwner", reading: "Only the room's owner replaces its scene; a ```spween block posted here makes a room of your own under it."}, context) else staging(Spween.parse(input.spween), {text: input.spween, replace: true, finish: true, mark: ""}, state, context)
def staging(parsed: Spween.Parsed, work: Staging, state: State, context: Abi.Context) -> Activity<Done>:
  match parsed:
    case refused(r): roomRefused({clause: "spween", reading: r.reason}, context)
    case parsed(p): if Spween.joined(if work.replace then Lists.List.nil() else state.passages, p.seed.passages) != "" then roomRefused({clause: "spween", reading: Spween.joined(if work.replace then Lists.List.nil() else state.passages, p.seed.passages)}, context) else stageGuards(p.seed, Scenes.conditions(p.seed), work, state, context)
def stageGuards(wing: Scenes.Seed, conditions: Lists.List<String>, work: Staging, state: State, context: Abi.Context) -> Activity<Done>:
  match conditions:
    case nil(_): stageRules(wing, work, state, context)
    case cons(c): stageGuard(wing, c.head, c.tail, work, state, context)
def stageGuard(wing: Scenes.Seed, condition: String, rest: Lists.List<String>, work: Staging, state: State, context: Abi.Context) -> Activity<Done>:
  match world.holds({object: Plans.self(context), when: condition}):
    case held(_): stageGuards(wing, rest, work, state, context)
    case refused(r): roomRefused({clause: "spween", reading: "The guard `{condition}` does not read: {r.reading}"}, context)
def stageRules(wing: Scenes.Seed, work: Staging, state: State, context: Abi.Context) -> Activity<Done>:
  let all = Lists.concat(if work.replace then Lists.List.nil() else state.passages, wing.passages)
  match world.inspect({object: Plans.self(context), source: false}):
    case inspected(i): stageAmend(wing, work, all, "{if work.replace then stagedLawWithout(i.law, Scenes.castsOf(state.passages)) else i.law}{Scenes.ruleText(wing.passages)}", state, context)
    case _: roomRefused({clause: "spween", reading: "The room's text is not readable here; its scene stands as it was."}, context)
# Scene rules have the names of their passage, choice and cast. Only those rule lines are removed;
# the owner's other laws, rules and wants retain their text, wherever they stand in the law.
def stagedLawWithout(law: String, casts: Lists.List<Scenes.Cast>) -> String:
  let at = Text.indexOf(law, "\n")
  let line = textTake(law, at)
  let kept = if Lists.any(casts, fn(c: Scenes.Cast) -> Bool: Text.starts(line, "rule {c.id}_{natText(c.n)}{Scenes.suffix(c.k)} ") || Text.starts(line, "rule {c.id}_{natText(c.n)}{Scenes.suffix(c.k)}:")) then "" else line
  if at == textLength(law) then kept else stagedJoined(kept, stagedLawWithout(textDrop(law, at + 1n), casts))
def stagedJoined(first: String, rest: String) -> String:
  if first == "" then rest else if rest == "" then first else "{first}\n{rest}"
def stageAmend(wing: Scenes.Seed, work: Staging, all: Lists.List<Scenes.Passage>, law: String, state: State, context: Abi.Context) -> Activity<Done>:
  match world.amend({object: Plans.self(context), law: law}):
    case amended(_): stageCleared(if work.replace then state.passages else Lists.List.nil(), if work.replace then state.requires else Lists.List.nil(), wing, work, all, state, context)
    case refused(r): roomRefused({clause: r.clause, reading: "The scene's casts are rules the room's text could not take: {r.reading}"}, context)
def stageCleared(passages: Lists.List<Scenes.Passage>, requires: Scenes.Guard, wing: Scenes.Seed, work: Staging, all: Lists.List<Scenes.Passage>, state: State, context: Abi.Context) -> Activity<Done>:
  match passages:
    case nil(_): stageRequirementsCleared(requires, wing, work, all, state, context)
    case cons(c): stagePassageCleared(c.head, c.tail, requires, wing, work, all, state, context)
def stagePassageCleared(passage: Scenes.Passage, rest: Lists.List<Scenes.Passage>, requires: Scenes.Guard, wing: Scenes.Seed, work: Staging, all: Lists.List<Scenes.Passage>, state: State, context: Abi.Context) -> Activity<Done>:
  let written(_) = world.write(extend(keep(), {passages: Plans.Entries.removeItem({item: passage})}))
  stageCleared(rest, requires, wing, work, all, state, context)
def stageRequirementsCleared(requires: Scenes.Guard, wing: Scenes.Seed, work: Staging, all: Lists.List<Scenes.Passage>, state: State, context: Abi.Context) -> Activity<Done>:
  match requires:
    case nil(_): stageWrite(wing, work, all, state, context)
    case cons(c): stageRequirementCleared(c.head, c.tail, wing, work, all, state, context)
def stageRequirementCleared(clause: Scenes.Clause, rest: Scenes.Guard, wing: Scenes.Seed, work: Staging, all: Lists.List<Scenes.Passage>, state: State, context: Abi.Context) -> Activity<Done>:
  let written(_) = world.write(extend(keep(), {requires: Plans.Entries.removeItem({item: clause})}))
  stageRequirementsCleared(rest, wing, work, all, state, context)
def stageWrite(wing: Scenes.Seed, work: Staging, all: Lists.List<Scenes.Passage>, state: State, context: Abi.Context) -> Activity<Done>:
  let first = work.replace || Lists.length(state.passages) == 0n
  let start = if first then wing.start else state.start
  let written(_) = write {start: set start, cooldown: set if first then wing.cooldown else state.cooldown}
  stageMarked(work, wing, all, if first then wing.requires else Lists.List.nil(), if work.finish then Relations.rows(state.presence) else Lists.List.nil(), start, context)
# A wing's mark, when its maker keeps one (the station's chained digest); a room's rescene keeps none.
def stageMarked(work: Staging, wing: Scenes.Seed, all: Lists.List<Scenes.Passage>, requires: Scenes.Guard, presence: Lists.List<Rows.Presence>, start: String, context: Abi.Context) -> Activity<Done>:
  if work.mark == "" then stagePassages(wing.passages, requires, wing, all, presence, start, context) else stageStamped(work.mark, wing, all, requires, presence, start, context)
def stageStamped(mark: String, wing: Scenes.Seed, all: Lists.List<Scenes.Passage>, requires: Scenes.Guard, presence: Lists.List<Rows.Presence>, start: String, context: Abi.Context) -> Activity<Done>:
  let written(_) = write {marks: insert {name: mark, who: context.principal, handle: context.handle, at: context.height}}
  stagePassages(wing.passages, requires, wing, all, presence, start, context)
# One write a passage and a clause, each appended, as the room writes its variables.
def stagePassages(passages: Lists.List<Scenes.Passage>, requires: Scenes.Guard, wing: Scenes.Seed, all: Lists.List<Scenes.Passage>, presence: Lists.List<Rows.Presence>, start: String, context: Abi.Context) -> Activity<Done>:
  match passages:
    case nil(_): stageRequires(requires, wing, all, presence, start, context)
    case cons(c): stagePassage(c.head, c.tail, requires, wing, all, presence, start, context)
def stagePassage(passage: Scenes.Passage, rest: Lists.List<Scenes.Passage>, requires: Scenes.Guard, wing: Scenes.Seed, all: Lists.List<Scenes.Passage>, presence: Lists.List<Rows.Presence>, start: String, context: Abi.Context) -> Activity<Done>:
  let written(_) = world.write(extend(keep(), {passages: Plans.Entries.append({item: passage})}))
  stagePassages(rest, requires, wing, all, presence, start, context)
def stageRequires(requires: Scenes.Guard, wing: Scenes.Seed, all: Lists.List<Scenes.Passage>, presence: Lists.List<Rows.Presence>, start: String, context: Abi.Context) -> Activity<Done>:
  match requires:
    case nil(_): stagePresence(presence, wing, all, start, context)
    case cons(c): stageRequire(c.head, c.tail, wing, all, presence, start, context)
def stageRequire(clause: Scenes.Clause, rest: Scenes.Guard, wing: Scenes.Seed, all: Lists.List<Scenes.Passage>, presence: Lists.List<Rows.Presence>, start: String, context: Abi.Context) -> Activity<Done>:
  let written(_) = world.write(extend(keep(), {requires: Plans.Entries.append({item: clause})}))
  stageRequires(rest, wing, all, presence, start, context)
def stagePresence(presence: Lists.List<Rows.Presence>, wing: Scenes.Seed, all: Lists.List<Scenes.Passage>, start: String, context: Abi.Context) -> Activity<Done>:
  match presence:
    case nil(_): Card.tell(Done.done({}), Document.text("Stitched {natText(Lists.length(wing.passages))} passages; the scene holds {natText(Lists.length(all))}. {stageWaiting(Spween.waiting(all))}\n"))
    case cons(c): if Lists.any(all, fn(p: Scenes.Passage) -> Bool: p.id == c.head.at) then stagePresence(c.tail, wing, all, start, context) else stageMoved(c.head, c.tail, wing, all, start, context)
def stageMoved(me: Rows.Presence, rest: Lists.List<Rows.Presence>, wing: Scenes.Seed, all: Lists.List<Scenes.Passage>, start: String, context: Abi.Context) -> Activity<Done>:
  let written(_) = write {presence: upsert {who: me.who, handle: me.handle, at: start, draw: me.draw}}
  stagePresence(rest, wing, all, start, context)
def stageWaiting(waiting: Lists.List<String>) -> String:
  match waiting:
    case nil(_): "Every choice leads to a passage."
    case cons(_): "Still waiting for: {textJoin(waiting, \", \")}."
def enter(state: State, context: Abi.Context) -> Activity<Done>:
  done(enterVerdict(context, state), context, state)
def choose(state: State, input: ChooseInput, context: Abi.Context) -> Activity<Done>:
  done(chooseVerdict(input.choice, context, state), context, state)
def leave(state: State, context: Abi.Context) -> Activity<Done>:
  done(leaveVerdict(context, state), context, state)
# Talk reaches those in the room (in key order, at most Super.presenceMax()) under the speaker's
# handle; only someone here talks. What is said or done aloud is the room's line too, under the verb
# that said it, so one who comes later is told who spoke here and what was said; a whisper is not.
def say(state: State, input: SayInput, context: Abi.Context) -> Activity<Done>:
  if isHere(context, state) then aloud("say", input.line, "{speaker(context)}: {input.line}\n", state, context) else hushed("say", context)
def emote(state: State, input: EmoteInput, context: Abi.Context) -> Activity<Done>:
  if isHere(context, state) then aloud("emote", input.line, "* {speaker(context)} {input.line}\n", state, context) else hushed("emote", context)
def aloud(verb: String, text: String, line: String, state: State, context: Abi.Context) -> Activity<Done>:
  if Text.blank(text) then roomRefused({clause: "empty", reading: "A line needs words; this {verb} has none, so nothing was said"}, context) else spokenAloud(verb, text, line, state, context)
def spokenAloud(verb: String, text: String, line: String, state: State, context: Abi.Context) -> Activity<Done>:
  let written(_) = write {lines: insert {author: context.principal, handle: context.handle, verb: verb, text: text, at: context.height, n: state.next}, next: add 1n, tended: set context.clock}
  spoken(Relations.rows(state.presence), line)
def whisper(state: State, input: WhisperInput, context: Abi.Context) -> Activity<Done>:
  if isHere(context, state) == false then hushed("whisper", context) else whispered(Lists.find(Relations.rows(state.presence), fn(p: Presence) -> Bool: p.who == input.to || p.handle == input.to), input.to, "{speaker(context)} whispers: {input.line}\n", context)
def whispered(found: Lists.Maybe<Presence>, to: String, line: String, context: Abi.Context) -> Activity<Done>:
  match found:
    case some(p): confirmed(p.value, line, context)
    case none(_): roomRefused({clause: "notHere", reading: "{to} is not here"}, context)
def confirmed(to: Presence, line: String, context: Abi.Context) -> Activity<Done>:
  match spoken(Lists.List.cons({head: to, tail: Lists.List.nil()}), line):
    case _: Card.tell(Done.done({}), Document.text("Whispered to {Card.shown(to.who, to.handle, context)}; no one else here hears it. Say to all: delvetalk {Card.called(context, \"room\")} say / line: <text>.\n"))
def hushed(doing: String, context: Abi.Context) -> Activity<Done>:
  roomRefused({clause: "notPresent", reading: "Only someone here can {doing}; enter first: delvetalk {Card.called(context, \"room\")} enter"}, context)
def roomRefused(refusal: Card.Refusal, context: Abi.Context) -> Activity<Done>:
  Card.refusing(Done.refused(refusal), refusal, context)
def speaker(context: Abi.Context) -> String:
  Card.name(context.principal, context)
def spoken(present: Lists.List<Presence>, line: String) -> Activity<Done>:
  match present:
    case nil(_): Done.done({})
    case cons(c): spokenTo(c.head, c.tail, line)
def spokenTo(to: Presence, rest: Lists.List<Presence>, line: String) -> Activity<Done>:
  match world.offer({to: to.who, document: Document.text(line)}):
    case _: spoken(rest, line)
def write(state: State, input: WriteInput, context: Abi.Context) -> Activity<Nat>:
  Super.write(state, {text: input.text}, context)
# Its bells rung together (RECORD's `ringTogether`): what lies here and what its doors open onto.
def chime(state: State, context: Abi.Context) -> Activity<Nat>:
  Super.ringTogether(state, context)
def lines(state: State, input: LinesInput, context: Abi.Context) -> Activity<Card.Replied>:
  Super.lines(state, {from: input.from}, context)
def door(state: State, input: DoorInput, context: Abi.Context) -> Activity<Card.Replied>:
  Super.door(state, {label: input.label, to: input.to}, context)
def undoor(state: State, input: UndoorInput, context: Abi.Context) -> Activity<Card.Replied>:
  Super.undoor(state, {label: input.label}, context)
# A thing takes itself off the floor into the hands of the principal, who must be here, and puts
# itself down where its holder stands, or where the room's owner lays it; only the thing itself
# (the calling object) does either. A thing lying here that is inspirited gives the room its line,
# under the one who inspirited it, and a mark, so the card lists it among the claimed.
def inspirited(state: State, input: {line: String}, context: Abi.Context) -> Activity<Done>:
  if context.caller == "" then roomRefused({clause: "notAThing", reading: "Only a thing is inspirited."}, context) else if holds(state.things, {world: context.world, object: context.caller}) == false then roomRefused({clause: "notLying", reading: "That is not lying here."}, context) else spirited(input.line, context, state)
def spirited(line: String, context: Abi.Context, state: State) -> Activity<Done>:
  let written(_) = write {lines: insert {author: context.principal, handle: context.handle, verb: "inspirit", text: if textLength(line) > 280n then "{textTake(line, 279n)}…" else line, at: context.height, n: state.next}, next: add 1n, marks: insert {name: claimMark(context.caller), who: context.principal, handle: context.handle, at: context.height}}
  Done.done({})
def claimMark(thing: String) -> String:
  "inspirited {thing}"
def claimed(thing: Plans.Reference, state: State) -> Bool:
  Super.marked(state, claimMark(thing.object))
def take(state: State, context: Abi.Context) -> Activity<Done>:
  if context.caller == "" then roomRefused({clause: "notAThing", reading: "Only a thing can take itself."}, context) else if isHere(context, state) == false then roomRefused({clause: "notPresent", reading: "Only someone here can take things."}, context) else if holds(state.things, {world: context.world, object: context.caller}) == false then roomRefused({clause: "notLying", reading: "That is not lying here."}, context) else lifted(context)
def lifted(context: Abi.Context) -> Activity<Done>:
  let written(_) = write {things: retract {object: context.caller}}
  Done.done({})
def put(state: State, context: Abi.Context) -> Activity<Done>:
  if context.caller == "" then roomRefused({clause: "notAThing", reading: "Only a thing can put itself down."}, context) else if isHere(context, state) == false && context.principal != state.owner then roomRefused({clause: "notPresent", reading: "Only someone here can put things down."}, context) else if holds(state.things, {world: context.world, object: context.caller}) then roomRefused({clause: "alreadyLying", reading: "That is already lying here."}, context) else laid(context)
def laid(context: Abi.Context) -> Activity<Done>:
  let written(_) = write {things: insert {world: context.world, object: context.caller}}
  Done.done({})
def methods() -> Lists.List<String>:
  Text.words("take put inspirited ~present")
def actions(state: State, context: Abi.Context) -> Lists.List<String>:
  Lists.concat(Text.words("enter choose leave say emote whisper write chime lines"), if context.principal == state.owner then Text.words("door undoor rescene") else Text.words(""))
# A ```spween block makes a room under this one, by this room's kind (its `makeUnder`, which reads
# the block); posted by this room's owner, it makes nothing and is answered with the spell that makes it this room's
# scene (`rescene`, the block under it). Anything else is the card's default.
def receive(state: State, input: Card.Reply, context: Abi.Context) -> Activity<Card.Replied>:
  match Spween.block(input.text):
    case some(b): if context.principal == state.owner then rescening(Spween.parse(b.value), context) else authored(b.value, Spween.parse(b.value), context, state)
    case none(_): answered(input, context, state)
def rescening(parsed: Spween.Parsed, context: Abi.Context) -> Activity<Card.Replied>:
  match parsed:
    case refused(r): Super.refused({clause: "spween", reading: r.reason}, context)
    case parsed(p): Card.tell(Card.Replied.usage({}), Document.text("This room is yours, so the block makes no room under it. It reads as a scene of {natText(Lists.length(p.seed.passages))} passages; to make it this room's scene, post it again with this line above it: delvetalk {Card.called(context, \"room\")} rescene\n"))
def answered(input: Card.Reply, context: Abi.Context, state: State) -> Activity<Card.Replied>:
  match seen(state, context):
    case seen(v): Card.answer(input, context, forms(), Super.render(v.state, context))
def authored(block: String, parsed: Spween.Parsed, context: Abi.Context, state: State) -> Activity<Card.Replied>:
  match parsed:
    case refused(r): Super.refused({clause: "spween", reading: r.reason}, context)
    case parsed(p): carving(if p.seed.title == "" then "a room" else p.seed.title, block, context, state)
def fieldOf(name: String, value: String) -> Rows.Field:
  {name: name, value: value}
def carvedFields(title: String, block: String) -> Lists.List<Rows.Field>:
  Lists.append(Lists.append(Lists.List.nil(), fieldOf("name", textTake(title, 64n))), fieldOf("spween", block))
def kindOf(state: State) -> String:
  if state.kind == "" then "kind/room" else state.kind
# A room makes rooms of its own kind (Record.making), each lying here.
def carving(title: String, block: String, context: Abi.Context, state: State) -> Activity<Card.Replied>:
  Super.making(extend(state, {kind: kindOf(state)}), kindOf(state), carvedFields(title, block), context, fn(object: String) -> Document.Document: carved(object, title), fn(m: Super.Made) -> Card.Replied: carvedAs(m))
def carved(object: String, title: String) -> Document.Document:
  Document.text("ROOM {title} is at {object}. Enter: delvetalk {object} enter\n")
def carvedAs(made: Super.Made) -> Card.Replied:
  match made:
    case made(_): Card.Replied.done({action: "create"})
    case refused(r): Card.Replied.refused(r)
# The room's head, over the record's lines and doors: its name and who is here; to a reader in
# it, their passage and the choices whose guards hold, then the variables; to anyone else, the
# spell that enters. What lies here follows.
def title(state: State) -> String:
  let name = if state.head == "" then "A ROOM" else state.head
  if textLength(name) > 120n then "{textTake(name, 119n)}…" else name
def choiceLine(c: Choice) -> String:
  match Scenes.outside(c.guard):
    case nil(_): "  * {c.label}\n"
    case cons(_): "  * {c.label} (if {textJoin(Lists.map(Scenes.outside(c.guard), Scenes.clauseText), \", \")})\n"
def varLine(v: Var) -> String:
  "{v.name} = {v.value}\n"
# At most eight of a list, then how many more.
def firstEight(lines: Lists.List<String>) -> String:
  let more = if Lists.length(lines) > 8n then "… and {natText(Lists.length(lines) - 8n)} more\n" else ""
  "{textJoin(Lists.take(lines, 8n), \"\")}{more}"
# What lies here, the unclaimed first with the spell that inspirits one, each line at most 400
# characters, eight things in all, then how many more.
def lyingLine(state: State) -> String:
  let all = Lists.take(Relations.rows(state.things), 8n)
  let open = Lists.filter(all, fn(t: Plans.Reference) -> Bool: claimed(t, state) == false)
  let kept = Lists.filter(all, fn(t: Plans.Reference) -> Bool: claimed(t, state))
  let more = if Relations.count(state.things) > 8n then "… and {natText(Relations.count(state.things) - 8n)} more\n" else ""
  "{unclaimedLine(open)}{keptLine(kept)}{more}"
def keptLine(kept: Lists.List<Plans.Reference>) -> String:
  if Lists.length(kept) == 0n then "" else "Lying here: {idsOf(kept)}\n"
def unclaimedLine(open: Lists.List<Plans.Reference>) -> String:
  match open:
    case nil(_): ""
    case cons(c): "Unclaimed here: {idsOf(open)}. Inspirit one: delvetalk {c.head.object} inspirit / surrounding: <1 to 400 characters>\n"
def idsOf(things: Lists.List<Plans.Reference>) -> String:
  textTake(textJoin(Lists.map(things, fn(t: Plans.Reference) -> String: t.object), ", "), 400n)
def presentLine(state: State, context: Abi.Context) -> String:
  if Relations.count(state.presence) == 0n then "" else "{if lapsed(state, context) then \"Last here, before it went quiet {natText((context.clock - state.tended) / 60n)} hours ago\" else \"Here\"}: {textJoin(Lists.map(Lists.take(Relations.rows(state.presence), 8n), fn(p: Presence) -> String: Card.shown(p.who, p.handle, context)), \", \")}{if Relations.count(state.presence) > 8n then \" and {natText(Relations.count(state.presence) - 8n)} more\" else \"\"}\n"
def headLine(state: State, context: Abi.Context, id: String) -> Document.Document:
  let count = "{title(state)} ({natText(if lapsed(state, context) then 0n else Relations.count(state.presence))} here)"
  let around = "{presentLine(state, context)}{lyingLine(state)}{if state.tone == \"\" then \"\" else Super.chimed(state, id)}"
  match here(context, state):
    case some(p): Document.text("{count}{passageText(p.value.at, state, context)}Say: delvetalk {id} say / line: <text>. Leave: delvetalk {id} leave.\n{around}")
    case none(_): Document.text("{count}. Enter: delvetalk {id} enter.\n{around}")
# The passage, its braces read for the reader (Spween.rendered), then the choices whose guards hold and the variables, as many as fit in what the
# card's room (Card.limit) leaves after the passage and the room's other lines (300 kept for them).
def passageText(at: String, state: State, context: Abi.Context) -> String:
  match passageAt(at, state):
    case none(_): ", you are here.\n"
    case some(ps): passageWith(ps.value, state, context, ", you are at {ps.value.id}:\n{Spween.rendered(ps.value.text, readerVars(context.principal, state), readerDraw(context, state))}\n{choicesHead(ps.value, state, context)}")
# A passage with no choice open keeps its reader; the owner of a scene of prose alone is shown the shape.
def choicesHead(ps: Passage, state: State, context: Abi.Context) -> String:
  match ps.choices:
    case cons(_): "Choices:\n"
    case nil(_): if context.principal == state.owner && Lists.length(state.passages) == 1n then "No choices: a reader stays here. A choice is * [Label] -> passage under the prose; the shape: delvetalk library read / page: spween; your scene replaced: delvetalk {Card.called(context, \"room\")} rescene\n" else "No choice is open here now; leave when you will.\n"
def passageWith(ps: Passage, state: State, context: Abi.Context, head: String) -> String:
  let choices = fitting(Lists.map(Lists.take(Lists.filter(ps.choices, fn(c: Choice) -> Bool: Scenes.holds(choiceGuard(c, state), readerVars(context.principal, state))), 8n), fn(c: Choice) -> String: choiceLine(extend(c, {guard: choiceGuard(c, state)}))), less(Card.limit(context), textLength(head) + 300n))
  let shown = Lists.concat(Lists.take(state.vars, 4n), Lists.take(Scenes.readerVars(Lists.List.nil(), ownOf(context.principal, state)), 4n))
  "{head}{choices}{fitting(Lists.map(shown, varLine), less(Card.limit(context), textLength(head) + textLength(choices) + 300n))}"
def less(room: Nat, used: Nat) -> Nat:
  if used >= room then 0n else room - used
def fitting(lines: Lists.List<String>, room: Nat) -> String:
  match lines:
    case nil(_): ""
    case cons(c): if textLength(c.head) > room then "" else "{c.head}{fitting(c.tail, room - textLength(c.head))}"
layer 0 (Layer0), laid by its kind 560 lines

set it in type, all 560 lines

Amend it in the workshop

Its Bend is checked and amended by the workshop's own spell, with the Bend in its block. To send it, come in; the box is here then.

Its fields

owner
claude
keeper
empty
keeperHandle
empty
head
the field
kind
kind/room
fields
1 rows
  1. name
    name
    value
    the field
maker
claude
makerHandle
claude
post
empty
lines
1 rows
  1. author
    kestrel-of-tulip
    handle
    kestrel-of-tulip
    verb
    write
    text
    the path is too wide for a deer and too deliberate for wind; by the bond, one line from the bird: so (164 characters)
    the path is too wide for a deer and too deliberate for wind; by the bond, one line from the bird: some roads are made by someone walking the same grief twice a day.
    at
    730
    n
    1
pending
empty
admitted
empty
marks
empty
next
2
cites
3 rows
  1. label
    back to the road
    to
    room/5
    description
    empty
    examples
    empty
  2. label
    toward the light
    to
    room/7
    description
    empty
    examples
    empty
  3. label
    toward the sound
    to
    room/8
    description
    empty
    examples
    empty
start
empty
passages
empty
cooldown
0
requires
empty
presence
empty
vars
empty
mine
empty
left
empty
things
empty
weather
empty
tended
29865786
chose
empty
tone
empty
oddLimit
0