@brass-lantern/mcp 0.0.1-stage → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +37 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +19 -0
- package/dist/docs/llms.txt +35 -0
- package/dist/docs/pages/guide/building-worlds/index.md +218 -0
- package/dist/docs/pages/guide/building-worlds/recipes.md +1406 -0
- package/dist/docs/pages/guide/building-worlds/two-rooms.md +339 -0
- package/dist/docs/pages/guide/coding-agents.md +124 -0
- package/dist/docs/pages/guide/deploying.md +56 -0
- package/dist/docs/pages/guide/getting-started.md +72 -0
- package/dist/docs/pages/guide/how-it-works.md +152 -0
- package/dist/docs/pages/guide/intent-server.md +92 -0
- package/dist/docs/pages/guide/porting-zork.md +115 -0
- package/dist/docs/pages/guide/testing.md +100 -0
- package/dist/docs/pages/guide/using-the-library.md +272 -0
- package/dist/docs/pages/guide/your-first-world.md +206 -0
- package/dist/docs/pages/guide/z-machine.md +96 -0
- package/dist/docs/pages/index.md +58 -0
- package/dist/docs/pages/reference/cartridges.md +47 -0
- package/dist/docs/pages/reference/commands.md +79 -0
- package/dist/docs/pages/reference/conditions-and-events.md +129 -0
- package/dist/docs/pages/reference/world-schema.md +592 -0
- package/dist/docs/pages.json +74 -0
- package/dist/docs.d.ts +21 -0
- package/dist/docs.js +89 -0
- package/dist/engine.d.ts +16 -0
- package/dist/engine.js +42 -0
- package/dist/job.d.ts +22 -0
- package/dist/job.js +29 -0
- package/dist/load.d.ts +22 -0
- package/dist/load.js +106 -0
- package/dist/run.d.ts +16 -0
- package/dist/run.js +57 -0
- package/dist/server.d.ts +47 -0
- package/dist/server.js +97 -0
- package/dist/stdio.d.ts +25 -0
- package/dist/stdio.js +75 -0
- package/dist/tools.d.ts +8 -0
- package/dist/tools.js +82 -0
- package/dist/worker.d.ts +1 -0
- package/dist/worker.js +6 -0
- package/package.json +47 -1
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Cartridges and storage
|
|
2
|
+
|
|
3
|
+
## Cartridges
|
|
4
|
+
|
|
5
|
+
Cartridges are what you pass in `GameOptions.cartridges` (see [Using the library](https://mrballistic.github.io/brass-lantern/guide/using-the-library#every-option)). The types, `Cartridge`, `WorldCartridge` and `ZCodeCartridge`, are exported from both `@brass-lantern/engine` and `@brass-lantern/vue`.
|
|
6
|
+
|
|
7
|
+
**A native world:**
|
|
8
|
+
|
|
9
|
+
| Field | Type | Notes |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| `kind` | `'world'` | |
|
|
12
|
+
| `id` | string | Unique; part of the save key. |
|
|
13
|
+
| `title` | string | The menu and the header. |
|
|
14
|
+
| `world` | `World` | See the [world schema](https://mrballistic.github.io/brass-lantern/reference/world-schema). |
|
|
15
|
+
| `saveKey?` | string | Overrides the save key, e.g. to keep loading saves written under an older key. |
|
|
16
|
+
|
|
17
|
+
**A Z-machine story file:**
|
|
18
|
+
|
|
19
|
+
| Field | Type | Notes |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| `kind` | `'zcode'` | |
|
|
22
|
+
| `id` | string | Unique; part of the transcript key. |
|
|
23
|
+
| `title` | string | The menu and the header. |
|
|
24
|
+
| `story` | string | The file’s URL, relative to `GameOptions.storyBaseUrl` (default `/`), e.g. `stories/zork1.z3`. |
|
|
25
|
+
| `format` | string | Shown in the menu, e.g. `Z-machine v3`. |
|
|
26
|
+
|
|
27
|
+
Stories a player loads with LOAD become cartridges too, with `local: true` and an id like `local-r119-880429-bf44` (release, serial number, checksum). You don’t write those.
|
|
28
|
+
|
|
29
|
+
With one cartridge, the terminal boots straight into it: no menu, no EJECT, no LOAD. With more, it opens on the menu, and a reload goes straight back to the last cartridge if it has a game in progress.
|
|
30
|
+
|
|
31
|
+
## Browser storage
|
|
32
|
+
|
|
33
|
+
Everything is in the player’s browser, under `storagePrefix`:
|
|
34
|
+
|
|
35
|
+
| Key | What |
|
|
36
|
+
|---|---|
|
|
37
|
+
| `<prefix>:save:<id>` | A native world’s save, with up to 500 lines of history. Or the cartridge’s `saveKey`. |
|
|
38
|
+
| `<save key>:named:<name>` | A native world’s named SAVE. |
|
|
39
|
+
| `<prefix>:theme` | The player’s THEME, BLOOM and EFFECTS choices. |
|
|
40
|
+
| `<prefix>:cartridge` | The last cartridge inserted. EJECT clears it, so a reload after EJECT shows the menu. |
|
|
41
|
+
| `<prefix>:z:<id>:transcript` | A story’s screen, up to 500 lines, so a reload can redraw it. |
|
|
42
|
+
| `<prefix>:z:auto:<signature>` | A story’s autosave, written every turn and cleared when it ends. |
|
|
43
|
+
| `<prefix>:z:file:save:<gameid>:<name>` | A named SAVE in a story. |
|
|
44
|
+
|
|
45
|
+
Stories loaded with LOAD are in IndexedDB, in a database named `<prefix>:stories`.
|
|
46
|
+
|
|
47
|
+
The library stores nothing else. Anything your app keeps (an analytics consent answer, say) is its own: the demo site, for example, keeps its consent answer at `<prefix>:analytics-consent` and, only after consent, an anonymous Google Analytics client ID at `<prefix>:ga-cid` (and the session ID, `<prefix>:ga-sid`, in sessionStorage).
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Player commands
|
|
2
|
+
|
|
3
|
+
The built-in verbs are fixed; a world gives them things to act on, and can add verbs of its own. Anything the regex parser doesn’t recognize, or recognizes but can’t act on, can go to the [intent server](https://mrballistic.github.io/brass-lantern/guide/intent-server), which maps loose phrasing onto these.
|
|
4
|
+
|
|
5
|
+
| Command | Also | Notes |
|
|
6
|
+
|---|---|---|
|
|
7
|
+
| GO *place* | `n` `s` `e` `w` `ne` `nw` `se` `sw` `u` `d` `in` `out`, `walk/head/run/move to …`, a bare exit label | Matches the room’s exit labels. |
|
|
8
|
+
| ENTER [*place*] | `go into` | An exit by name, the way in, or the exit through a door you name. |
|
|
9
|
+
| CLIMB [*thing*] | `climb up`, `climb down` | Up, or the room’s `climb` exit. |
|
|
10
|
+
| LOOK | `l` | Describes the room again. |
|
|
11
|
+
| TAKE *item* | `get` `grab` `pick up` | |
|
|
12
|
+
| DROP *item* | `put down` `leave` | |
|
|
13
|
+
| TAKE ALL, DROP ALL, PUT ALL IN / ON *thing* | `everything`; `… but X and Y`, `… except X, Y` | One line per thing: “lamp: Taken.”. TAKE ALL takes what’s in reach and not inside something you carry (in Infocom style, what’s directly in the room, with a reason for anything that can’t be taken). |
|
|
14
|
+
| EXAMINE *thing* | `x` `inspect` `look at` | Items and people, and what’s inside or on an item. In the dark you can’t examine people either (“It’s too dark to see.”). |
|
|
15
|
+
| FOLLOW *person* | | Bare FOLLOW asks what to follow. With no rule of the world’s, a person (say, Floyd) gets “You’d rather Floyd came to you. Try FLOYD, FOLLOW ME.” and a thing “You can’t follow that.” To bring someone along, order them: *person*, FOLLOW ME. See [FOLLOW](https://mrballistic.github.io/brass-lantern/reference/world-schema#follow). |
|
|
16
|
+
| READ *thing* | | The item’s text. |
|
|
17
|
+
| OPEN / CLOSE *thing* | `shut` | Containers and doors. |
|
|
18
|
+
| LOCK / UNLOCK *thing* WITH *key* | | |
|
|
19
|
+
| PUT *item* IN / ON *thing* | `insert`, `place`, `set` | Into an open container with room, or onto a surface. UNDER and BEHIND are asked of the world’s rules (in Infocom style, otherwise “You can’t do that.” / “That hiding place is too obvious.”). |
|
|
20
|
+
| TAKE *item* FROM *thing* | `get … out of`, `remove … from` | |
|
|
21
|
+
| LOOK IN *thing* | `search` | What’s inside. |
|
|
22
|
+
| TURN ON / OFF *thing* | `switch on`, `light`; `extinguish`, `douse`, `blow out`, `put out` | Switchable items. LIGHT on something already burning with no switch (a torch) says “It’s already lit.” |
|
|
23
|
+
| BURN *thing* WITH *item* | `light … with`, `burn down`, `ignite`, `incinerate` | Something burnable, with something burning. The thing’s rules answer first (lighting candles with a match). |
|
|
24
|
+
| TURN *thing* WITH *tool* | `to`, `for`; SET *thing* TO *x* | A rule on the thing decides; otherwise “This has no effect.” TURN ON … WITH … is TURN ON. The second object can be a number: TURN DIAL TO 4, SET YEAR TO 776 (digits up to 1000, or H:MM); with no rule for it, that answers “This has no effect.” in Infocom style, and elsewhere the intent server gets a turn. Digits that name something here (locker 12) are that thing, not the number. |
|
|
25
|
+
| PLUG *thing* WITH *item* | | The same: a rule, or “This has no effect.” |
|
|
26
|
+
| BOARD *vehicle* | `get in`, `climb in`, `sit in` | Into a vehicle on the ground here. See [vehicles](https://mrballistic.github.io/brass-lantern/reference/world-schema#vehicles). |
|
|
27
|
+
| DISEMBARK [*vehicle*] | `get out`, `get off`, `stand` | Out again, if it’s safe. EXIT on its own does this while you’re aboard, and is a direction (out) otherwise. |
|
|
28
|
+
| USE *item* [ON *thing*] | `push` `pull` `press` `operate` `attach X to Y` | See [use rules](https://mrballistic.github.io/brass-lantern/reference/world-schema#userule). OPEN and PUT fall back to an item’s use rules when it isn’t a container. |
|
|
29
|
+
| GIVE *item* TO *person* | `hand` `offer` `return` | With one person present, GIVE *item* is enough. `GIVE <someone> <item>` works too (`GIVE LUMBERGH THE REPORT`). |
|
|
30
|
+
| TALK TO *person* | `speak/chat with`, `question` | With one person present, TALK is enough. |
|
|
31
|
+
| ASK *person* ABOUT *topic* | `tell … about …` | The person’s answer on that topic, if the world gives it [topics](https://mrballistic.github.io/brass-lantern/reference/world-schema#npc); otherwise what TALK TO says. ABOUT ME and ABOUT MYSELF reach a topic keyed or aliased `me` or `myself`. |
|
|
32
|
+
| *person*, *command* | `tell/order/ask … to …` | An order (a bare TELL *person* is one too). *person*, FOLLOW ME is one too, answered by the character’s `orders.follow` rules. A character the world lets obey carries out GO, TAKE, DROP and GIVE ME, or answers a rule (“robot, push the button”); others answer or ignore it. An order to such a character ends the rest of the line. |
|
|
33
|
+
| WEAR *item* | `put on` | A thing in sight but not held is taken first: (first taking the shirt). |
|
|
34
|
+
| SMASH *thing* [WITH *item*] | `break` `destroy` `wreck` `whack` `beat` | |
|
|
35
|
+
| ATTACK *someone* WITH *weapon* | `kill` `hit` `fight` `stab` | At a character who fights, combat; at anything else, SMASH (in a world without combat). In Infocom style, `kill troll` picks the one weapon you hold, or asks. |
|
|
36
|
+
| THROW *item* [AT *target*] | `toss` `hurl`; OFF, OVER | A rule on the target decides; otherwise it lands on the floor. OFF and OVER, with no rule: Zork’s refusal in Infocom style; elsewhere the intent server gets a turn. |
|
|
37
|
+
| PUSH *thing* *direction* | PUSH *thing* TO *x*; READ *thing* THROUGH *x* | Only a world’s rules answer these (otherwise “You can’t push things to that.” in Infocom style; elsewhere the intent server gets a turn); READ THROUGH reads it. |
|
|
38
|
+
| DIAGNOSE | | Your wounds, and how much more you could take. |
|
|
39
|
+
| WAIT / SIT | `z`, `sit down` `relax` | Takes a `wait` / `sit` exit if the room has one. |
|
|
40
|
+
| INVENTORY | `i` `inv` | |
|
|
41
|
+
| HINT | `hints` `clue` | |
|
|
42
|
+
| VERBOSE / BRIEF / SUPERBRIEF | | Full descriptions always, on first visits only, or never (LOOK still shows them). Takes no game time. |
|
|
43
|
+
| SCORE | | |
|
|
44
|
+
| AGAIN | `g` | Repeats the last command, meaning the same things. |
|
|
45
|
+
| OOPS *word* | | Replaces the word nobody understood in your last line, and tries it again: `examine lanturn`, then `oops lantern`. |
|
|
46
|
+
| UNDO | | Takes back the last move, up to 50 moves. Not kept across a reload, a RESTART or a RESTORE. Takes no game time. |
|
|
47
|
+
| QUIT | | Prints the world’s `quit` reply; the game carries on. |
|
|
48
|
+
| SAVE [*name*] | | Saves the game under a name (`save before the troll`). Without a name, asks for one. Names are lowercase letters, digits, spaces, `-` and `_`, up to 32. |
|
|
49
|
+
| RESTORE [*name*] | | Goes back to a named save. Without a name, lists them and asks which. |
|
|
50
|
+
| LOAD | | Goes back to the automatic save, which is kept after every move. |
|
|
51
|
+
| RESTART | | Wipes the automatic save and starts over. Named saves are kept. |
|
|
52
|
+
| SCRIPT / UNSCRIPT | | Starts a transcript, then downloads it as a text file. |
|
|
53
|
+
| VERSION | | The app’s version, then the world’s title and credits. |
|
|
54
|
+
| THEME [*name*] | | Lists the color themes, or switches to one (`crt-amber`, `crt-green`, `simple`, `simple-light`, `simple-dark`, plus any the game adds). Remembered in the browser. Takes no game time. Works at the cartridge menu and in story files too, like BLOOM and EFFECTS. |
|
|
55
|
+
| BLOOM ON / OFF | | Turns the phosphor glow on or off. |
|
|
56
|
+
| EFFECTS ON / OFF | | Turns every screen effect on or off. |
|
|
57
|
+
| COOKIES | `privacy` | Analytics settings, when analytics are configured. |
|
|
58
|
+
| EJECT | | Back to the cartridge menu (builds with more than one cartridge). |
|
|
59
|
+
| LOAD (at the menu) | `open`, or drop a file on the terminal | Play a Z-machine story file from your computer. In a native world, LOAD restores your save instead. |
|
|
60
|
+
| REMOVE *number* (at the menu) | `forget` | Take a story you loaded off the shelf. |
|
|
61
|
+
| PLAY | | Start a story file again after it ends. |
|
|
62
|
+
| CANCEL | | At a SAVE or RESTORE prompt, or a story file’s. |
|
|
63
|
+
| HELP | `?` | |
|
|
64
|
+
|
|
65
|
+
**World verbs:** a world can add its own (SNOOZE, PRAY, MOVE, Zork’s ULYSSES …); they’re listed in its HELP. See [World verbs](https://mrballistic.github.io/brass-lantern/reference/world-schema#world-verbs).
|
|
66
|
+
|
|
67
|
+
**Typed words:** a world’s SAY, ANSWER or INCANT (see [World verbs](https://mrballistic.github.io/brass-lantern/reference/world-schema#world-verbs)) takes the rest of the line, quoted or not: `answer “a well”`. A quoted phrase is never split at its full stops, commas or `and`, and the text verb ends the line: `say "well". west` says “well” and drops WEST, as in Zork.
|
|
68
|
+
|
|
69
|
+
**ME:** `me` and `myself` mean you where a thing is expected, and so do `self` and `yourself` unless something here is called that. In an order, “robot, give me the key” hands it to you, and “robot, push yourself” means the robot. A world decides what, if anything, happens; with nothing to say, the reply is the usual one for a word that names nothing here (“You don’t see a “me” here.”).
|
|
70
|
+
|
|
71
|
+
**Chaining:** `take key and wallet`, `north then look`, `west. take lamp.` Each piece runs separately (and gets its own intent-server retry if it misses). A name that contains “and” stays whole: in a world where “lost and found” is a thing’s name or one of its aliases, `take flair from lost and found and go north` is two commands, not three. Words that only appear in a description don’t count.
|
|
72
|
+
|
|
73
|
+
**Pronouns:** `it`, `them` and `that` mean the last thing you acted on, as in `take the mug then give it to gary`; `him` and `her` mean the last person.
|
|
74
|
+
|
|
75
|
+
**Names:** every word of three or more letters you type has to be in the thing’s name or one of its other words: `take red ball` doesn’t find a thing the world calls only “ball”. Shorter words are ignored, and a word can be shortened (`lant` for lantern). In brass style a close misspelling of a word in the name matches too (`lunberg` for Lumbergh). See [How names are matched](https://mrballistic.github.io/brass-lantern/guide/building-worlds/#how-names-are-matched).
|
|
76
|
+
|
|
77
|
+
**Questions:** when a word matches more than one thing, the game asks which (“Which do you mean: the wooden door or the trap door?”, or in Infocom style “Which door do you mean, the wooden door or the trap door?”), and when a verb is missing its object, what (“What do you want to take?”). Answer with just the missing words (`trap`, `the sword`), or type a new command to move on. Answer BOTH (or ALL, EACH) to act on each, for TAKE, DROP and PUT; other verbs answer “One at a time: …?”. Questions take no game time, and answers are never sent to the intent server.
|
|
78
|
+
|
|
79
|
+
**Keys:** Up and Down step through your last 100 commands, keeping whatever you’d started typing. Enter on an empty line, or any letter, finishes the text that’s typing out.
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Conditions and events
|
|
2
|
+
|
|
3
|
+
## Conditions
|
|
4
|
+
|
|
5
|
+
Conditions are strings, used by `requires`, exits (`if`, `denials`), room `descriptions`, `onEnter`, rules (`instead`, `after`, `onUse`), dialogue keys, hints, scoring, daemons, the finale’s epilogue and ambient lines. One parser handles all of them. A missing or blank condition always holds, so a trigger (`onEnter` and the like) may leave out `if`.
|
|
6
|
+
|
|
7
|
+
| Condition | True when |
|
|
8
|
+
|---|---|
|
|
9
|
+
| `flag:NAME` | the flag is set |
|
|
10
|
+
| `has:ITEM` | the item is in the inventory |
|
|
11
|
+
| `held:ITEM` | the item is carried at any depth: directly, or inside something carried (Zork’s HELD?). `has:` means carried directly |
|
|
12
|
+
| `in:ROOM` | the player is in that room |
|
|
13
|
+
| `visited:ROOM` | the player has been there |
|
|
14
|
+
| `inside:ITEM:PLACE` | the item is directly in PLACE: a room, another item, or `player` |
|
|
15
|
+
| `open:ITEM` | the container or door is open |
|
|
16
|
+
| `locked:ITEM` | it’s locked |
|
|
17
|
+
| `on:ITEM` | it’s switched on |
|
|
18
|
+
| `here:ITEM` | the player can reach it (in the room, carried, or in something open) |
|
|
19
|
+
| `var:NAME<op>N` | a numeric variable compared with `=`, `<`, `>`, `<=` or `>=` (unset is 0) |
|
|
20
|
+
| `carrying<op>N` | how many things the player holds directly |
|
|
21
|
+
| `target:ID`, `indirect:ID` | that slot of the command being run resolved to that ID (`player` for ME and MYSELF, and SELF or YOURSELF when nothing here is called that); false otherwise |
|
|
22
|
+
| `direction:DIR` | the direction typed in `PUSH X NORTH` (compass, `up`, `down`), or, in an `orders.go` rule, the place the character was told to go, as typed: “milton, go to the basement” is `direction:basement`. Any lowercase word passes the audit |
|
|
23
|
+
| `number:N`, `number<op>N` | the number typed in the command being run (`TURN DIAL TO 4`, `SET DIAL TO 776`); false when the command has none. A rule with `with: 'number'` matches that command |
|
|
24
|
+
| `said:WORDS` | the words typed after a text verb (`target: 'text'`, e.g. `ANSWER A WELL`), compared as lowercase whole words with punctuation and quotes ignored; false when the command has none |
|
|
25
|
+
| `heaviest<op>N` | the weight of the heaviest thing the player holds directly, counting what’s inside it (Zork’s narrow passage: `heaviest<=4`) |
|
|
26
|
+
| `score<op>N` | the score, as SCORE reports it (Zork wins at `score>=350`); a `scoring` entry can’t test it |
|
|
27
|
+
| `lit:here`, `lit:ROOM` | the room has light |
|
|
28
|
+
| `following:NPC` | the character is following the player (`{ follow }` set it; a character’s `follows` condition is separate) |
|
|
29
|
+
| `alive:NPC` | the character isn’t dead |
|
|
30
|
+
| `awake:NPC` | alive and conscious |
|
|
31
|
+
| `fighting:NPC` | in a fight with the player (and conscious) |
|
|
32
|
+
| `with:NPC` | in the player’s room (hidden or not) |
|
|
33
|
+
| `seen:NPC` | in the player’s room and not hidden |
|
|
34
|
+
| `aboard`, `aboard:ITEM` | the player is in a vehicle (that one) |
|
|
35
|
+
| `water:here`, `water:ROOM` | the room is water now |
|
|
36
|
+
| `terrain:NAME`, `terrain:NAME:ROOM` | the room (default: the player’s) is that terrain now: `land`, `water`, `air`, or one of the world’s own |
|
|
37
|
+
| `!…` | negates any of the above |
|
|
38
|
+
| `a & b` | every part holds: `in:break_room & !flag:lunch_freed` |
|
|
39
|
+
|
|
40
|
+
There’s no “or”. Write two rules, or two dialogue keys, instead. An unrecognized condition is false in play. `auditWorld` reports it, and a condition naming an item or room that doesn’t exist, in rules, triggers, exits, `requires`, daemons, hints and scoring (it doesn’t check dialogue keys, ambient lines or room descriptions).
|
|
41
|
+
|
|
42
|
+
## Events and effects
|
|
43
|
+
|
|
44
|
+
An event is a named list of steps, run in order. A string is printed. An object is an effect:
|
|
45
|
+
|
|
46
|
+
| Effect | Does |
|
|
47
|
+
|---|---|
|
|
48
|
+
| `{ say: 'text' }` | Prints, like a plain string. |
|
|
49
|
+
| `{ set: 'flag' }`, `{ clear: 'flag' }` | Turns a flag on or off. |
|
|
50
|
+
| `{ move: 'item', to: 'room' }` | Moves an item to a room, `'player'`, `'here'` (the player’s room), another item, a character, or `null` (offstage). |
|
|
51
|
+
| `{ moveNpc: 'npc', to: 'room' }` | Moves a character, or `null` (gone). |
|
|
52
|
+
| `{ follow: 'npc' }`, `{ unfollow: 'npc' }` | Sets or clears the character’s `following` state (`npcs.<id>.following` in the game state; no flag): the character then goes where the player goes (GO, doors, ENTER, CLIMB; not scripted moves), like a `follows` condition on the character. |
|
|
53
|
+
| `{ npcState: 'npc', fighting?, staggered?, strength?, hidden?, scenery? }` | Sets a character’s combat state, hides and reveals it, or (`scenery`) keeps it out of the room’s list and puts it back (Zork’s NDESCBIT in play). |
|
|
54
|
+
| `{ script: 'name', arg? }` | Runs one of the world’s [scripts](https://mrballistic.github.io/brass-lantern/reference/world-schema#scripts) and the steps it returns. |
|
|
55
|
+
| `{ hide: 'item' }`, `{ reveal: 'item' }` | Hides an item where it is (not seen, listed or taken), or shows it again. |
|
|
56
|
+
| `{ board: 'item' }`, `{ disembark: true }` | Puts the player in a vehicle that’s in the room, or takes them out. |
|
|
57
|
+
| `{ touch: 'item' }` | Marks an item handled (Zork’s TOUCHBIT): its first-seen sentence is over. |
|
|
58
|
+
| `{ unlist: 'item' }`, `{ relist: 'item' }` | Keeps an item where it is, seen and usable but out of the room’s list, or lists it again (the tied rope). |
|
|
59
|
+
| `{ open }`, `{ close }`, `{ lock }`, `{ unlock }` | Changes a container’s or door’s state. |
|
|
60
|
+
| `{ switch: 'item', on: true }` | Switches a light (or anything switchable). |
|
|
61
|
+
| `{ add: 'var', by: n }`, `{ setVar: 'var', to: n }` | Changes a numeric variable. |
|
|
62
|
+
| `{ setVar: 'var', from: 'number' }` | Sets it to the number typed in the command (0 if none). |
|
|
63
|
+
| `{ score: n }` | Adds to the score. |
|
|
64
|
+
| `{ go: 'room' }` | Moves the player there and describes it. With `quiet: true`, without describing it (Zork’s mirror). |
|
|
65
|
+
| `{ look: true }` | Describes the player’s room in full, as LOOK does. |
|
|
66
|
+
| `{ unvisit: 'room' }` | Forgets the player has been there, so the next arrival shows the full description (Zork clears TOUCHBIT when the dam drains). |
|
|
67
|
+
| `{ schedule: 'event', in: n }`, `{ cancel: 'event' }` | Runs an event after `n` turns, or stops it. |
|
|
68
|
+
| `{ chance: 80, then: [...], else: [...] }` | Picks a branch at random (from a seeded generator, so saves replay exactly). |
|
|
69
|
+
| `{ if: 'condition', then: [...], else: [...] }` | Picks a branch by a [condition](#conditions). `else` is optional. |
|
|
70
|
+
| `{ stopLine: true }`, `{ stopLine: 'text' }` | Drops the rest of the command line (Zork’s P-CONT). The text, if any, is said only if commands were left. |
|
|
71
|
+
| `{ moveVehicle: 'item', to: 'room' }` | Moves a vehicle to a room. If the player is aboard they arrive with it, as on any arrival; otherwise its `leave` and `arrive` lines are said when the player sees it go or come. It isn’t a move the player makes, so followers stay behind. |
|
|
72
|
+
| `{ free: true }` | The turn takes no time: no move, no timers or daemons (a capture’s echo). |
|
|
73
|
+
| `{ noDarkLine: true }` | A line already said the light went out, so the engine doesn’t add its own. |
|
|
74
|
+
| `{ run: 'event' }` | Runs another event here. |
|
|
75
|
+
| `{ die: 'cause' }` | Kills the player. See [Death](https://mrballistic.github.io/brass-lantern/reference/world-schema#death). Nothing after it runs. |
|
|
76
|
+
| `{ end: 'ending' }` | Plays an ending. See [Endings](https://mrballistic.github.io/brass-lantern/reference/world-schema#endings). Nothing after it runs. |
|
|
77
|
+
|
|
78
|
+
Effects print nothing unless they say so. An effect naming something that doesn’t exist does nothing in play, and `auditWorld` reports it. It also checks the events named by rules, `onEnter`, `onTake`, `onWear`, `onSmash`, `onGive`, daemons and the finale.
|
|
79
|
+
|
|
80
|
+
### Templates
|
|
81
|
+
|
|
82
|
+
`{var:NAME}` (the variable, 0 when unset) and `{number}` (the number typed in the command; left as written when there is none) fill in when a line is printed: event lines, descriptions, and an item’s `initialDescription` and `roomDescription` wherever the engine lists it (in the room, in a container or on a surface, or when opening a container shows it):
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
vars: { tally: 3 },
|
|
86
|
+
items: {
|
|
87
|
+
tally: { name: 'tally board', description: 'Chalk marks.', portable: false, tags: [], roomDescription: 'A tally board on the wall reads {var:tally}.' },
|
|
88
|
+
},
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
> look
|
|
93
|
+
📍 Hall
|
|
94
|
+
A hall. The study is north.
|
|
95
|
+
A tally board on the wall reads 3.
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Bracket lines (the older form)
|
|
99
|
+
|
|
100
|
+
Some lines are printed **and** change the game. They still work, and in an Infocom-style world they act without being shown:
|
|
101
|
+
|
|
102
|
+
| Line | Effect |
|
|
103
|
+
|---|---|
|
|
104
|
+
| `[Flag set: Gary is happy]` | Sets the flag `flagLabels['gary is happy']` names. An unmapped label does nothing, so test for it. |
|
|
105
|
+
| `[Added to inventory: badge]` | Gives the player the item whose `name` is “badge”. |
|
|
106
|
+
| `[Badge consumed]` | Removes the item whose `name` is “badge” from the inventory. |
|
|
107
|
+
|
|
108
|
+
Facts worth knowing:
|
|
109
|
+
|
|
110
|
+
- **Events from `onEnter`, `onTake`, `onWear`, `onSmash` and the finale’s `bareHanded` fire once per game.** Events from a use rule’s `then` and from `onGive` run every time the rule matches, so guard them with a `!flag:` condition if they should happen once.
|
|
111
|
+
- **Bracket lines only turn flags on.** To turn one off, use the `{ clear: 'flag' }` effect.
|
|
112
|
+
- **Item lines match display names**, not IDs. To upgrade an item, consume the old one and add the new: `[Lamp consumed]`, then `[Added to inventory: lit lamp]`.
|
|
113
|
+
- **`intro`** plays when a new game starts. A chapter break is just a line, such as `✨ CHAPTER 2: THE AFTERNOON`.
|
|
114
|
+
|
|
115
|
+
## How lines are styled
|
|
116
|
+
|
|
117
|
+
Every line the player sees is classified by how it starts, which sets its look and typewriter speed:
|
|
118
|
+
|
|
119
|
+
| Starts with | Style | Use it for |
|
|
120
|
+
|---|---|---|
|
|
121
|
+
| `📍` | room header | added by the engine; don’t start your own lines with it |
|
|
122
|
+
| `💼 🌀 👔 💕 💻 💾 🔨 💥 📎 ✨ 🪄 🤜 😖 😴 🐟 🌺 📬 📞` | scripted moment | events (18ms/char) |
|
|
123
|
+
| `═` or `“` | banner, narration | 12ms/char |
|
|
124
|
+
| `[` | system | flags, inventory, hints, score (instant) |
|
|
125
|
+
| anything else | prose | descriptions, replies (10ms/char) |
|
|
126
|
+
|
|
127
|
+
A line starting with an emoji that isn’t in the list renders as prose. The set is fixed in this version, so pick from the list for scripted moments.
|
|
128
|
+
|
|
129
|
+
**Copy style:** the built-in replies use curly quotes and apostrophes (“ ” ’). Your world will read best if it does too.
|