diff --git a/.gitignore b/.gitignore index 0fe3ab4..aff3816 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,6 @@ lib/openai/api_key.lua # Save game files created by tests *.sav *.tmp + +# Archive files +*.zip diff --git a/AGENTS.md b/AGENTS.md index 6a0ba27..b7062fb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -18,10 +18,11 @@ Start with [ARCHITECTURE.md](ARCHITECTURE.md). It is the canonical high-level su 2. Prefer the narrowest layer that actually controls the behavior under change. 3. For compiler issues, start in the most specific emitter or lowering module under [zilscript/compiler](zilscript/compiler). 4. For content or gameplay issues, inspect the relevant adventure folder under [infocom](infocom) or [books](books) before changing engine code. -5. Validate with the smallest relevant target from [Makefile](Makefile); for broad gameplay regressions, use `make test-pure-zil`. +5. When debugging ZIL-related failures, prefer adding temporary `TELL`/print commands directly in the relevant ZIL routines to expose values, branch choices, and object locations while narrowing the problem. Remove or clearly quarantine this instrumentation before finishing unless it is intentionally part of a test. +6. Validate with the smallest relevant target from [Makefile](Makefile); for broad gameplay regressions, use `make test-pure-zil`. ## Current Repo Notes - Imported Infocom materials are vendored as regular folders, not git submodules. - Skills and staged adventure-building guidance live under [skills](skills). -- The root [ARCHITECTURE.md](ARCHITECTURE.md) file is intended to be the first-stop overview for future agent runs. \ No newline at end of file +- The root [ARCHITECTURE.md](ARCHITECTURE.md) file is intended to be the first-stop overview for future agent runs. diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 943212f..d78260c 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -158,6 +158,32 @@ Recommended edit strategy: - Imported Infocom directories are vendored directly in the repository rather than managed as git submodules. - Skills and adventure-process guidance live under [skills](/Users/ICHERNA/Developer/adventure-arena/External/zilscript/skills). +## Reference Documentation + +The [docs](/Users/ICHERNA/Developer/adventure-arena/External/zilscript/docs) directory contains reference PDFs for the ZIL language and Z-machine architecture: + +- [Internal_Secrets_Ko_2019.pdf](/Users/ICHERNA/Developer/adventure-arena/External/zilscript/docs/Internal_Secrets_Ko_2019.pdf): Comprehensive guide to how Infocom's ZIL language was implemented and how the Z-machine works internally. Covers object properties, dictionary format, clock/interrupt system, and memory layout. +- [ZILF Reference Guide.pdf](/Users/ICHERNA/Developer/adventure-arena/External/zilscript/docs/ZILF%20Reference%20Guide.pdf): Modern ZILF compiler reference. Documents ZIL syntax, standard forms, compile-time evaluation (`%`), macros, property/flag semantics, and the DIRECTIONS/SYNTAX/OBJECT system. + +These documents are the authoritative references when implementing or debugging ZIL language features in the compiler and runtime. + +## Known Engine Constraints + +### Compile-time Evaluation + +The parser evaluates `%` at parse time using [zilscript/evaluate.lua](/Users/ICHERNA/Developer/adventure-arena/External/zilscript/zilscript/evaluate.lua). This currently supports `ZORK-NUMBER` checks (reading from `_G.ZORK_NUMBER` at parse time) and `GASSIGNED?` (always true). The `` at the top of a test file must execute at runtime *before* `INSERT_FILE` calls that contain compile-time conditionals. + +### Module Load Order + +Because `INSERT_FILE` parses, compiles, and executes each file sequentially at runtime, forward references between files matter: + +- Direction properties (`PQNORTH`, `PQSE`, etc.) are assigned when the first `ROOM` with that exit is created via `OBJECT()`. Code that references these values (like `TABLE(PQNORTH, ...)`) must load *after* the `DIRECTIONS` directive and room definitions. +- For Zork II specifically, the `EIGHT-DIRECTIONS` table in `2actions.zil` references direction properties that don't exist until `2dungeon.zil` loads. The test file re-creates this table after all modules load as a workaround. + +### Clock/Interrupt System + +The CLOCKER in `gclock.zil` uses memory-based vectors (`C-TABLE`, `REST`, `GET`, `PUT`) to track timed events. `QUEUE(routine, ticks)` schedules an interrupt; `CLOCKER` decrements ticks each turn and fires the routine when tick reaches 1. Some game mechanics (balloon, wizard appearances) depend on interrupts firing at the right time relative to the deterministic RANDOM sequence in tests. + ## Minimal Mental Model If you only need the shortest useful model for this repo, use this: diff --git a/Makefile b/Makefile index f22fc03..1a7305c 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ # Targets -.PHONY: test test-all test-unit test-integration test-zork1 test-parser test-containers test-directions test-light test-pronouns test-take test-turnbit test-clock test-clock-direct test-assertions test-check-commands test-horror-helpers test-horror-partial test-horror test-horror-failures test-horror-all test-pure-zil test-simple-new test-insert-file test-let test-save help +.PHONY: test test-all test-unit test-integration test-zork1 test-zork2 test-parser test-containers test-directions test-light test-pronouns test-take test-turnbit test-clock test-clock-direct test-assertions test-check-commands test-horror-helpers test-horror-partial test-horror test-horror-failures test-horror-all test-pure-zil test-simple-new test-insert-file test-let test-save help help: @echo "Available targets:" @@ -11,6 +11,7 @@ help: @echo " test-unit - Run unit tests only" @echo " test-integration - Run all integration tests" @echo " test-zork1 - Run Zork1 integration tests" + @echo " test-zork2 - Run Zork2 integration tests" @echo " test-parser - Run all parser/runtime tests" @echo " test-pure-zil - Run pure ZIL tests (using ASSERT functions)" @echo "" @@ -51,13 +52,17 @@ test-unit: @echo "Running unit tests..." lua tests/run_all.lua -test-integration: test-zork1 test-parser test-horror-all +test-integration: test-zork1 test-zork2 test-parser test-horror-all @echo "All integration tests completed!" test-zork1: @echo "Running Zork1 integration tests..." @lua5.4 run-zil-test.lua infocom/zork1/test/zork1-walkthrough +test-zork2: + @echo "Running Zork2 integration tests..." + @lua5.4 run-zil-test.lua infocom/zork2/test/test-auto-generated + test-parser: test-containers test-directions test-light test-pronouns test-take test-turnbit test-clock test-clock-direct test-assertions test-check-commands test-simple-new test-insert-file test-let test-save @echo "All parser/runtime tests completed!" @@ -150,4 +155,5 @@ test-pure-zil: @lua5.4 run-zil-test.lua books/blackwood-horror/test/test-helpers @lua5.4 run-zil-test.lua books/blackwood-horror/test/test-failures @lua5.4 run-zil-test.lua infocom/zork1/test/zork1-walkthrough + @lua5.4 run-zil-test.lua infocom/zork2/test/test-auto-generated @echo "All pure ZIL tests completed!" diff --git a/TESTING.md b/TESTING.md index 5de879d..039f145 100644 --- a/TESTING.md +++ b/TESTING.md @@ -1,151 +1,645 @@ # Testing Guide -## Test Organization +This repository uses two execution modes and four common test patterns: -This project uses a hierarchical test organization with individual Make targets for each test file. This provides: -- **Fine-grained control**: Run individual tests or groups of tests -- **Parallel execution**: Make can run independent tests in parallel -- **Clear failure identification**: Know exactly which test failed -- **CI/CD flexibility**: Run different test suites for different scenarios +1. Direct state tests that construct a tiny world and assert on globals, flags, locations, tables, clock state, and save/restore behavior. +2. Parser/gameplay tests that run a real `GO()` loop in a coroutine and send commands through the parser. + +This file documents the patterns already used in the current suite. Zork II is intentionally excluded here because its test setup is still work in progress. ## Running Tests -### All Tests +### Main entrypoints + ```bash -make test # Run all tests (unit + integration) -make test-all # Alias for 'test' +make test +make test-unit +make test-integration +make test-pure-zil ``` -### Test Categories +### Common focused targets + ```bash -make test-unit # Run unit tests only -make test-integration # Run all integration tests -make test-parser # Run all parser/runtime tests -make test-pure-zil # Run pure ZIL tests (using ASSERT functions) +make test-simple-new +make test-insert-file +make test-let +make test-save +make test-containers +make test-directions +make test-light +make test-pronouns +make test-take +make test-turnbit +make test-clock +make test-clock-direct +make test-assertions +make test-check-commands +make test-zork1 +make test-horror +make test-horror-all ``` -### Individual Tests +### Run one ZIL test file directly -#### Parser/Runtime Tests ```bash -make test-simple-new # Simple assertion tests -make test-insert-file # INSERT-FILE functionality tests -make test-let # LET form tests -make test-containers # Container interaction tests -make test-directions # Direction/movement tests -make test-light # Light source tests -make test-pronouns # Pronoun tests -make test-take # TAKE command tests -make test-turnbit # TURNBIT flag tests -make test-clock # Clock system tests -make test-clock-direct # Clock system direct tests -make test-assertions # Assertion tests -make test-check-commands # Check commands tests -``` - -#### Integration Tests +lua5.4 run-zil-test.lua zil/test-simple-new +lua5.4 run-zil-test.lua infocom/zork1/test/test-containers +lua5.4 run-zil-test.lua books/blackwood-horror/test/test-walkthrough +``` + +`run-zil-test.lua` loads the target module, expects a ZIL routine named `RUN-TEST`, then invokes it through the compiled Lua symbol `RUN_TEST()`. + +## What The Test Runner Actually Provides + +The generic runner in `run-zil-test.lua` provides: + +- `ASSERT(msg, condition)` for boolean assertions. +- `ASSERT_TEXT(expected, ok, actual)` for parser output matching. +- A deterministic `RANDOM(max)` override so test runs are repeatable. +- Standard loader/bootstrap setup via `require "zilscript"` and `require "zilscript.bootstrap"`. + +Important detail: `ASSERT` currently returns on the first truthy or falsy condition it receives. In practice, that means you should treat it as a single-condition assertion. Some older tests pass multiple predicates to one `ASSERT`, but that is not a reliable pattern for new tests. + +Recommended style: + +```zil +> + ,ADVENTURER>> +``` + +For transcript text checks: + +```zil +> + ,ADVENTURER>> +``` + +## The Verified Way To Set The Current Room + +For direct setup or teleport-style test control, set both the room global and the player location. + +The pattern used across the suite is: + +```zil + + + + +``` + +Equivalent older tests sometimes move `,ADVENTURER` directly: + +```zil + + +``` + +If the test depends on visibility, also set light state: + +```zil + +``` + +This is the repo's current answer to “set current room for testing.” Updating only `,HERE` is not enough. Updating only the adventurer location is also not enough. Keep them in sync. + +### Reusable setup helper + +Several small tests define a helper like this: + +```zil + + + + + > +``` + +Use that helper whenever a file needs to reposition the player more than once. + +## Test Styles In This Repo + +### 1. Tiny Direct State Tests + +Use this style when you want to verify engine semantics without depending on a full game. + +Common examples: + +- `zil/test-simple-new.zil` +- `zil/test-insert-file.zil` +- `zil/test-save.zil` +- `infocom/zork1/test/test-clock-direct.zil` + +Typical structure: + +```zil + + + + + + + + + + + + ,TESTROOM>>> +``` + +Use this style for: + +- Global state +- Object location +- Flags with `FSET?` +- Save/restore behavior +- Clock internals +- Compiler/runtime support features like `INSERT-FILE` and `LET` + +### 2. Inline Parser Tests With A Minimal GO Loop + +Use this style when you need parser behavior, but do not want to load a full adventure. + +Common examples: + +- `infocom/zork1/test/test-containers.zil` +- `infocom/zork1/test/test-pronouns.zil` +- `infocom/zork1/test/test-light.zil` +- `infocom/zork1/test/test-turnbit.zil` + +Typical structure: + +```zil + + + + + + + + + + + + + + + + + + > + +> +``` + +Then drive commands with: + +```zil +> + ,ADVENTURER>> +``` + +Use this style for: + +- Parser vocabulary +- Container semantics +- Pronoun resolution +- Lighting behavior +- Verb dispatch +- Flag-controlled command availability + +### 3. Full Adventure Tests With INSERT-FILE + +Use this when the behavior depends on real game content. + +Common examples: + +- `infocom/zork1/test/zork1-walkthrough.zil` +- `books/blackwood-horror/test/test-helpers.zil` +- `books/blackwood-horror/test/test-failures.zil` +- `books/blackwood-horror/test/test-walkthrough.zil` +- `infocom/test-zork1.zil` +- `infocom/test-zork3.zil` +- `infocom/test-planetfall.zil` +- `infocom/test-lurkinghorror.zil` +- `infocom/test-spellbreaker.zil` if added later + +Typical pattern: + +```zil + + + + + + + + + +> +``` + +For Blackwood Horror, the current tests use Zork I parser/runtime pieces plus the local dungeon/actions files. + +Use this style for: + +- Real walkthroughs +- Regression tests against authored content +- Failure-path checks in a live game +- Multi-step puzzle validation + +### 4. Transcript-Derived Tests + +The repo also contains transcript-style tests that are effectively command scripts expressed as repeated `ASSERT-TEXT` calls. + +Common examples: + +- `infocom/zork1/test/test-auto-generated.zil` +- `infocom/test-zork1.zil` +- `infocom/test-zork3.zil` +- `infocom/test-planetfall.zil` + +These are useful when you have a known-good transcript and want quick regression coverage for output and command flow. + +## Frotz Workflow + +This section documents a repeatable way to record fresh walkthrough transcripts from compiled Infocom story files on macOS. + +### Required Files + +For each game, you need: + +- A compiled story file (`.z3` or `.zip`) in that game folder, for example `infocom/zork2/zork2.z3`. +- A command transcript source file with one command per `>` line, for example `infocom/zork2/test/zork2.txt`. +- The recorder script `record-frotz-transcript.lua`. + +The recorder currently maps these game keys: + +- `zork1` +- `zork2` +- `zork3` +- `planetfall` +- `spellbreaker` +- `lurkinghorror` + +### Install Frotz + +On macOS with Homebrew: + ```bash -make test-zork1 # Zork1 walkthrough tests -make test-horror # Horror complete walkthrough -make test-horror-all # All horror tests -make test-horror-helpers # Horror test helpers -make test-horror-partial # Horror partial walkthrough -make test-horror-failures # Horror failing conditions +brew install frotz ``` -## Test File Types +Verify binaries: -### Runnable Tests -Test files with `RUN_TEST` routine that can be executed via `run-zil-test.lua`: -- `test-*.zil` - Standard test files -- `*-walkthrough.zil` - Full game walkthrough tests +```bash +command -v dfrotz +command -v frotz +``` -### Helper/Library Files -Files used by other tests (no `RUN_TEST` routine): -- `test-directions-pure.zil` - Helper definitions for direction tests -- `test-require.zil` - Library for testing REQUIRE functionality -- `test-sourcemap.zil` - Error test file for source mapping +Use `dfrotz` for scripted replay and transcript generation. -## Adding New Tests +### Run A Game Manually -When adding a new test file: +```bash +dfrotz infocom/zork2/zork2.z3 +``` -1. **Create the test file** in `tests/` directory: - ```zil - - - > - ``` +### Record A Walkthrough Manually -2. **Add Make target** in `Makefile`: - ```make - test-my-feature: - @echo "Running my feature tests..." - @lua5.4 run-zil-test.lua tests.test-my-feature - ``` +Inside the game: -3. **Update .PHONY** declaration at top of Makefile +1. Run `SCRIPT`. +2. Enter a base filename (for example `session`). +3. Play the walkthrough commands. +4. Run `UNSCRIPT`. +5. Quit normally (`QUIT`, then `Y` when prompted). -4. **Add to appropriate group** (e.g., `test-parser` dependencies) +Frotz writes `.scr` (for example `session.scr`). -5. **Add to CI workflow** in `.github/workflows/test.yml`: - ```yaml - - name: Run my feature tests - run: lua5.4 run-zil-test.lua tests.test-my-feature - ``` +### Record Walkthroughs From Existing Command Files -6. **Update help text** in Makefile +Use the repo helper to replay commands from `infocom//test/.txt` and save a new transcript as `*-frotz.txt`: -## CI/CD Testing +```bash +lua5.4 record-frotz-transcript.lua zork2 +``` -The GitHub Actions workflow (`.github/workflows/test.yml`) runs all tests on: -- Pull requests to main/master -- Pushes to main/master +Record all configured games: -Tests are run individually to provide clear failure identification and better reporting. +```bash +lua5.4 record-frotz-transcript.lua +``` -## Best Practices +Typical outputs: -### Individual Targets vs. Pattern Matching +- `infocom/zork1/test/zork1-frotz.txt` +- `infocom/zork2/test/zork2-frotz.txt` +- `infocom/zork3/test/zork3-frotz.txt` +- `infocom/spellbreaker/test/spellbreaker-frotz.txt` +- `infocom/lurkinghorror/test/lurkinghorror-frotz.txt` -**✅ Use individual targets** (current approach): -- Better for CI/CD reporting -- Explicit control over what runs -- Self-documenting -- Easy to exclude problematic tests temporarily +On failure, the script prints a per-game error and the `dfrotz` log path. -**❌ Avoid pattern matching** for test discovery: -- Hard to exclude specific tests -- Less clear in CI logs -- Harder to debug failures -- Can accidentally include helper files +### Turn Fresh Transcript Into Test Assertions -### Test Naming +Generate a new transcript-derived test file: -- Use `test-.zil` for runnable tests -- Use `-walkthrough.zil` for full game tests -- Helper files can use any naming but won't be auto-discovered +```bash +lua5.4 generate-test-from-transcript.lua infocom/zork2/test/zork2-frotz.txt +``` + +Run it: + +```bash +lua5.4 run-zil-test.lua infocom/zork2/test/test-auto-generated +``` + +### How To Record A Successful Walkthrough + +For stable transcript replay, keep these constraints: + +1. Use a story build whose release matches the walkthrough transcript. +2. Start from a fresh game state. +3. Keep command text exact (same verbs, object names, and sequencing). +4. End cleanly (`UNSCRIPT`, then `QUIT`, then `Y`). + +If you hit broad divergence (many `You can't go that way.` lines), stop early and verify story release before regenerating tests. + +### Release-Mismatch Warning + +Walkthrough command files are release-sensitive. If transcript source and story build differ, command flow can diverge quickly. + +Check story metadata: + +```bash +file infocom/zork2/zork2.z3 +``` + +Compare release/serial with the transcript header before relying on generated assertions. + +## Assertion Techniques Used In The Current Suite + +### Boolean state assertions + +```zil +> +>> + ,TESTROOM>> + ,ADVENTURER>> +``` + +### Transcript text assertions + +```zil +> +> +``` + +`ASSERT-TEXT` is the right tool when the primary contract is player-facing output. + +### Command success plus state verification + +Recommended new style: + +```zil +> + ,ADVENTURER>> +``` + +### Inventory and location checks + +Current tests commonly use `LOC`: + +```zil + ,ADVENTURER>> + ,BOTTOM-DRAWER>> +> +``` + +### Flag checks + +```zil +> +> +``` + +### Save/restore checks + +`zil/test-save.zil` demonstrates how to verify: + +- globals survive save/restore +- `,HERE` survives save/restore +- object locations survive save/restore +- flags survive save/restore +- multiple save files remain independent + +### Clock/demon checks + +`infocom/zork1/test/test-clock-direct.zil` uses direct function calls like: + +- `INT` +- `QUEUE` +- `ENABLE` +- `CLOCKER` + +Use that style when validating interrupt scheduling rather than player commands. + +## CO-CREATE And CO-RESUME Semantics + +Coroutine-based gameplay tests use: + +```zil +> +``` + +`CO-CREATE` starts the game coroutine immediately. -### Test Organization +To send commands: -Group tests logically: -- `test-parser` - All parser/runtime tests -- `test-integration` - Full integration tests -- `test-pure-zil` - Pure ZIL tests without game dependencies +```zil + +``` + +That returns the normal coroutine results, which `ASSERT-TEXT` expects. + +If you pass a third argument of `T`: + +```zil + +``` + +then `CO-RESUME` returns only the coroutine success flag. Use that for pure success/failure checks, but pair it with a separate state assertion if you care where the player ended up. + +## Recommended File Skeletons + +### Small direct state test + +```zil + + + + + + + + + + > + + + + + >> +``` + +### Minimal parser test + +```zil + + + + + + + + + + + + + + + + + + + + + + > + +> + +> + ,ADVENTURER>>> +``` + +### Full-game walkthrough test + +```zil + + + + + + + + + +> + +> + > + ,ADVENTURER>>> +``` + +## Choosing The Right Test Style + +Use direct state tests when the behavior is runtime-level or data-structure-level. + +Use minimal parser tests when you need command parsing, but do not need the full game world. + +Use full-game tests when behavior depends on authored content, real room links, or puzzle sequencing. + +Use transcript tests when you already have a walkthrough and want broad regression coverage quickly. + +## Existing Techniques Worth Reusing + +- Build a `TEST-SETUP` routine if you need to reposition the player repeatedly. +- Use `INSERT-FILE` to assemble only the modules needed for the test. +- Use `ASSERT-TEXT` for user-visible copy. +- Use `LOC`, `HERE`, and `FSET?` for world-state checks. +- Split command success and state verification into separate assertions. +- Use direct teleporting with `SETG HERE` plus `MOVE` to jump to a scenario quickly. +- For long walkthroughs, drop no-longer-needed items to keep inventory manageable. +- For clock tests, call engine routines directly instead of driving them only through parser commands. +- For transcript-derived tests, prefer many small assertions over one giant summary check. + +## Adding A New Test File + +1. Put the file in the correct folder. + Direct engine tests usually live under `zil/` or `infocom/zork1/test/`. + Adventure-specific tests should live under that adventure's `test/` directory. + +2. Choose the right style. + Use one of the skeletons above instead of inventing a new harness. + +3. Define `RUN-TEST`. + The runner expects that routine to exist. + +4. Add a focused Make target in `Makefile`. + +5. Add the target to the right aggregate group such as `test-parser`, `test-horror-all`, or `test-pure-zil`. + +6. Update `help` text in `Makefile`. + +7. If CI runs the surrounding group, no extra workflow change is needed. ## Troubleshooting -### Test Not Running -- Check if test has `RUN_TEST` routine -- Verify test is added to Makefile -- Check for syntax errors in test file +### The test needs to start in a specific room + +Use: + +```zil + + + + +``` + +### The parser test hangs or waits for input + +Make sure your `GO()` routine enters `MAIN-LOOP` and your test drives it through `CO-RESUME`. + +### The room is wrong after a manual jump + +You probably changed `,HERE` without moving the player, or moved the player without changing `,HERE`. + +### Text assertion passes but state is wrong + +Add a separate state assertion after the command. Do not rely on a multi-condition `ASSERT` call. + +### A test needs deterministic randomness + +The generic runner already overrides `RANDOM(max)` deterministically. -### Test Timeout -- Some tests use coroutines and may appear to loop -- Increase timeout in CI if needed -- Check if test is waiting for input +### A transcript test is too long to debug -### Missing Dependencies -- Run `git submodule update --init --recursive` for game dependencies -- Install Lua 5.4: `sudo apt-get install lua5.4` +Split it into thematic chunks or add intermediate `HERE`, `LOC`, and flag assertions around the puzzle transitions. diff --git a/books/blackwood-horror/blackwood-horror.zil b/books/blackwood-horror/blackwood-horror.zil new file mode 100644 index 0000000..7a9a710 --- /dev/null +++ b/books/blackwood-horror/blackwood-horror.zil @@ -0,0 +1,25 @@ +"Blackwood Horror - A Lovecraftian Zork Adventure" + + + + + + + + + + +;"Substrate" + + + + + + + + + +;"Book-specific overrides" + + + diff --git a/books/limehouse-killings/actions.zil b/books/limehouse-killings/actions.zil index 8385534..683cdfe 100644 --- a/books/limehouse-killings/actions.zil +++ b/books/limehouse-killings/actions.zil @@ -807,7 +807,7 @@ )>> ) @@ -817,7 +817,7 @@ CR> - ) (<==? ,HERE ,ASHWORTH-ENTRANCE-HALL> @@ -924,5 +924,16 @@ (,GAME-LOST ) - (T - )>> + (T + )>> + +; === GAME ENTRY === + + + + + + + + > diff --git a/books/limehouse-killings/limehouse-killings.zil b/books/limehouse-killings/limehouse-killings.zil new file mode 100644 index 0000000..d8b97a1 --- /dev/null +++ b/books/limehouse-killings/limehouse-killings.zil @@ -0,0 +1,25 @@ +"The Limehouse Killings - A Victorian Mystery Zork Adventure" + + + + + + + + + + +;"Substrate" + + + + + + + + + +;"Book-specific overrides" + + + diff --git a/docs/Internal_Secrets_Ko_2019.md b/docs/Internal_Secrets_Ko_2019.md new file mode 100644 index 0000000..19f07ae --- /dev/null +++ b/docs/Internal_Secrets_Ko_2019.md @@ -0,0 +1,2811 @@ +Internal Secrets of Infocom Games[*] Everything you wanted to know about the internal working of all text-based Infocom games + +Michael Ko April 2019 [2nd Ed.] + +*https://ifsecrets.blogspot.com + +1 + +Contents + +## Contents + +|1|ZIL,|ZILCH, ZAP, and ZIP||6| +|---|---|---|---|---| +||1.1|Introduction . . . . . . . . . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .|6| +||1.2|ZIP versions 1 . . . . . . . . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .|7| +||1.3|ZIP version 2
. . . . . . . . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .|7| +||1.4|ZIP version 3
. . . . . . . . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .|7| +||1.5|Enhanced ZIP (EZIP), version 4 . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .|7| +||1.6|Extended ZIP (XZIP), version 5 . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .|8| +||1.7|YZIP, version 6 . . . . . . . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .|8| +|2|General structure of Infocom Games and Data Structures|||8| +||2.1|Introduction and Story Headers . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .|8| +||2.2|The Memory Layout of Infocom Games . .|. . . . . . . . . . . . . . . . . . . . . . . .|8| +||2.3|The Massive Object Table . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .|9| +||2.4|Global Variables . . . . . . . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .|10| +||2.5|Tables and Buers
. . . . . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .|10| +|3|Syntax Entries - The Biggest Mystery of them All|||11| +||3.1|Introduction . . . . . . . . . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .|11| +||3.2|Prepositions . . . . . . . . . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .|11| +||3.3|Syntax Entry Pointer Table
. . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .|11| +||3.4|Syntax Entries
. . . . . . . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .|11| +||3.5|Get What I Mean (GWIM) Feature . . . .|. . . . . . . . . . . . . . . . . . . . . . . .|12| +||3.6|Location Restriction of Objects . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .|12| +||3.7|Pre-actions and Actions
. . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .|13| +||3.8|An Example . . . . . . . . . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .|13| +||3.9|Update: Compact Syntaxes to Save Space|. . . . . . . . . . . . . . . . . . . . . . . .|13| +|4|Execution of Infocom Games - An Overview|||14| +||4.1|Introduction . . . . . . . . . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .|14| +||4.2|Initialization with GO
. . . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .|14| +||4.3|Heart Beat of the Game with MAIN-LOOP|. . . . . . . . . . . . . . . . . . . . . . .|14| +||4.4|Understanding the User with PARSER . .|. . . . . . . . . . . . . . . . . . . . . . . .|15| +||4.5|Completing Previous Command with ORPHAN-MERGE . . . . . . . . . . . . . . . .||15| +||4.6|Match the Command with SYNTAX-CHECK . . . . . . . . . . . . . . . . . . . . . .||15| +||4.7|Find the Objects with SNARF-OBJECT .|. . . . . . . . . . . . . . . . . . . . . . . .|15| +||4.8|Final check on Objects with TAKE-CHECK and MANY-CHECK . . . . . . . . . . .||15| +||4.9|Call the Actions with PERFORM . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .|15| +||4.10|Tick the CLOCKER
. . . . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .|15| +||4.11|Graphic representation of Game Flow . . .|. . . . . . . . . . . . . . . . . . . . . . . .|15| +|5|GO|- Gentlemen, Start Your Engines!||16| +||5.1|Introduction . . . . . . . . . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .|16| +||5.2|Running GO . . . . . . . . . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .|16| +|6|MAIN-LOOP - Heart of the Game|||17| +||6.1|Introduction . . . . . . . . . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .|17| +||6.2|The Details . . . . . . . . . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .|17| +||6.3|Details of Multiples of Multiples . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .|18| +||6.4|Update: Managing Global Variables . . . .|. . . . . . . . . . . . . . . . . . . . . . . .|18| + + + +2 + +Contents + +||6.5|Update: How many NOT-HERE-OBJECTs? . . . . . . . . . . . . . . . . . . . . . . .|18| +|---|---|---|---| +||6.6|Update: Checking For Invalid Exceptions . . . . . . . . . . . . . . . . . . . . . . . . .|19| +|7|PARSER: How Now Brown Cow||19| +||7.1|Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|19| +||7.2|Characters vs. Tokens
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|19| +||7.3|PARSER Variables and Grammatical Structure Denitions . . . . . . . . . . . . . . .|20| +||7.4|PARSER Table (ITBL) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|21| +||7.5|Checking Word Types with WT?
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .|21| +||7.6|Start of PARSER: Where is the command? . . . . . . . . . . . . . . . . . . . . . . . .|22| +||7.7|Now, Traverse the Tokens. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|23| +||7.8|Update: Speaking to Actors with Quotes . . . . . . . . . . . . . . . . . . . . . . . . .|24| +||7.9|Update: Titles and Adverbs (briey) . . . . . . . . . . . . . . . . . . . . . . . . . . .|25| +||7.10|Update: Numbers, a new object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|26| +|8|PARSER: New Commands and Routines||27| +||8.1|Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|27| +||8.2|STUFF
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|27| +||8.3|INBUF-STUFF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|28| +||8.4|New AGAIN command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|28| +||8.5|OOPS! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|28| +||8.6|INBUF-ADD
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|29| +||8.7|UNDO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|29| +||8.8|Update: Other Minor Changes in PARSER . . . . . . . . . . . . . . . . . . . . . . . .|30| +||8.9|Update: ReplaceToken routine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|30| +|9|CLAUSE: Find the Noun Clause Boundaries||30| +||9.1|Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|30| +||9.2|How it screens... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|31| +||9.3|Update: New Matches. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|33| +|10|ORPHAN-MERGE: Fix What Is Broken||34| +||10.1|Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|34| +||10.2|Fixing Orphans with ORPHAN-MERGE . . . . . . . . . . . . . . . . . . . . . . . . .|35| +||10.3|Clearing up Ambiguity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|35| +||10.4|ACLAUSE-WIN
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|36| +||10.5|Using CLAUSE-COPY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|36| +||10.6|CLAUSE-ADD
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|37| +||10.7|Update: New changes of ORPHAN-MERGE . . . . . . . . . . . . . . . . . . . . . . .|37| +||10.8|Update: New ACLAUSE-WIN expands its options . . . . . . . . . . . . . . . . . . . .|40| +||10.9|Update: NCLAUSE-WIN
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|40| +||10.10Update: New version of CLAUSE-COPY . . . . . . . . . . . . . . . . . . . . . . . . .||40| +|11|SYNTAX-CHECK: Find Correct Syntax Entry||41| +||11.1|Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|41| +||11.2|Hierarchy of Matching
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|41| +||11.3|GWIM (Get What I Mean)
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|42| +||11.4|ORPHAN: Creating an Orphaned Command . . . . . . . . . . . . . . . . . . . . . . .|43| +||11.5|Update: SYNTAX-CHECK
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|44| +||11.6|Update: New versions of GWIM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|45| +||11.7|Update: New versions of ORPHAN . . . . . . . . . . . . . . . . . . . . . . . . . . . .|45| + + + +3 + +Contents + +|12|Getting Objects with SNARF-OBJECTS||45| +|---|---|---|---| +||12.1 Introduction . . . . . . . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . . . .|46| +||12.2 Setting up Routines . . . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . . . .|46| +||12.3 SNARFEM: Looking for Groups of Objects . . . . . . . . . . . . . . . . . . . . . . . .||46| +||12.4 BUT-MERGE . . . . . . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . . . .|47| +||12.5 Getting Object Numbers for each Object with GET-OBJECT . . . . . . . . . . . . .||47| +||12.6 Bug: Randomly Picking Objects . . . .|. . . . . . . . . . . . . . . . . . . . . . . . . .|48| +||12.7 Update: New versions of SNARF-OBJECTS . . . . . . . . . . . . . . . . . . . . . . .||49| +||12.8 Update: New versions of SNARFEM .|. . . . . . . . . . . . . . . . . . . . . . . . . .|49| +||12.9 Update: New BUT-MERGE . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . . . .|49| +||12.10Update: New ways to GET-OBJECT .|. . . . . . . . . . . . . . . . . . . . . . . . . .|50| +|13|Search for Objects using SEARCH-LIST||51| +||13.1 Introduction . . . . . . . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . . . .|51| +||13.2 SEARCH-LIST: Finding Objects in Room and on Winner
. . . . . . . . . . . . . . .||51| +||13.3 DO-SL: Find Objects Based Upon Search Level . . . . . . . . . . . . . . . . . . . . .||52| +||13.4 GLOBAL-CHECK: Look for Objects Everywhere . . . . . . . . . . . . . . . . . . . .||52| +||13.5 THIS-IT?
. . . . . . . . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . . . .|53| +||13.6 Update: New version of SEARCH-LIST|. . . . . . . . . . . . . . . . . . . . . . . . . .|53| +||13.7 Update: New version of GLOBAL-CHECK . . . . . . . . . . . . . . . . . . . . . . . .||53| +||13.8 Update: New version of THIS-IT? . . .|. . . . . . . . . . . . . . . . . . . . . . . . . .|54| +||13.9 Update: NOT-HERE-OBJECT . . . .|. . . . . . . . . . . . . . . . . . . . . . . . . .|54| +||13.10Update: MOBY-FIND . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . . . .|54| +|14|Can Many Objects be TAKEn Before Using with TAKE-CHECK and MANY-CHECK||55| +||14.1 Introduction . . . . . . . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . . . .|55| +||14.2 ITAKE-CHECK (through TAKE-CHECK): Checking TAKE and HAVE bits . . . . .||55| +||14.3 Update: New ITAKE-CHECK . . . . .|. . . . . . . . . . . . . . . . . . . . . . . . . .|56| +||14.4 MANY-CHECK . . . . . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . . . .|56| +|15|It's Time to Perform with PERFORM||57| +||15.1 Introduction . . . . . . . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . . . .|57| +||15.2 Checks and Order . . . . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . . . .|57| +||15.3 THIS-IS-IT
. . . . . . . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . . . .|58| +|16|Pardon the Interruptions||59| +||16.1 Introduction . . . . . . . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . . . .|59| +||16.2 Creating and Storing interrupts with INT
. . . . . . . . . . . . . . . . . . . . . . . .||59| +||16.3 QUEUE - Setting Up the Interrupts . .|. . . . . . . . . . . . . . . . . . . . . . . . . .|60| +||16.4 CLOCKER - Running Interrupts
. . .|. . . . . . . . . . . . . . . . . . . . . . . . . .|60| +||16.5 What about DEMONs?
. . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . . . .|61| +||16.6 Update: New INT and Interrupt Entry|. . . . . . . . . . . . . . . . . . . . . . . . . .|61| +||16.7 Update: New CLOCKER
. . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . . . .|62| +||16.8 Removing Interrupts with DEQUEUE|. . . . . . . . . . . . . . . . . . . . . . . . . .|62| +||16.9 New Predicates for the Interrupts . . .|. . . . . . . . . . . . . . . . . . . . . . . . . .|63| +|17|Basic Screen Output and TELL||63| +||17.1 Introduction . . . . . . . . . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . . . .|63| +||17.2 Abbreviations / Frequent words table .|. . . . . . . . . . . . . . . . . . . . . . . . . .|63| +||17.3 Special PRINT Routines - WORD-PRINT, CLAUSE-PRINT, PREP-PRINT . . . . .||64| +||17.4 New versions PRINT routines . . . . .|. . . . . . . . . . . . . . . . . . . . . . . . . .|64| + + + +4 + +Contents + +|17.5 Error message routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|65| +|---|---| +|17.6 Using the TELL Macro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|65| +|18 The Describers - For Rooms and Objects|65| +|18.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|65| +|18.2 PRINT-CONT
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|65| +|18.3 DESCRIBE-OBJECT
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|66| +|18.4 DESCRIBE-OBJECTS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|66| +|18.5 DESCRIBE-ROOM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|66| +|18.6 PRINT-CONTENTS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|67| +|18.7 Update: DESCRIBE-ROOM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|67| +|19 Common Routines and Predicates|67| +|19.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|67| +|19.2 Table Routines and Predicates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|67| +|19.3 Object Predicates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|68| +|19.4 Object Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|70| +|19.5 Game State Routines and Predicates . . . . . . . . . . . . . . . . . . . . . . . . . . .|70| +|19.6 Movement Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .|71| +|20 Conclusion - The End|72| +|Appendix A: Story Headers|72| +|Appendix B: Attributes and Properties From Learning ZIL|75| +|Appendix C: Object Attributes and Properties in Zork 1|80| + + + +5 + +1 ZIL, ZILCH, ZAP, and ZIP + +## Introduction + +Decades ago, Infocom was synonymous with good storytelling and creative puzzles. It wasn't the rst company to release a text interactive ction game, but its rst release, Zork I, made it the agbearer for all other IF games to follow. Infocom took over the personal computer market for interactive ction games by having their games programmed in ZIL (Zork Implementation Language) which is a compact language that easily handled text and object structures. ZIL programs were compiled into Z-code, an assembly code that would run on a Z-machine. Infocom created multiple Z-machine emulators (AKA Zork Interpreter Program or ZIP) to run on various computers especially home computers like the TSR-80, Apple II, and Commodore 64. Such an approach allowed a single program to be run on dierent computers without having to create a separate program for each machine. + +Buried in these ZIL programs were the basic structure of how an Infocom game is organized and executed. And it was Infocom's parser which could understand complex commands with such a small amount of code that seemed miraculous to IF fans. The inner workings of Infocom games remained a mystery until reverse engineering was done that decoded the Z-code format. Much of the knowledge about Z-code was documented in the Z-Machine Standards Document by Graham Nelson and Mark Howell. In this, the Z-code instructions and data structure used by some of those instructions (like Vocabulary by read or objects by get_prop) tables were described. As it was a general document, other data structures specic to Infocom games like verb syntaxes were not mentioned. Several excellent utilities (infodump by Mark Howell and ZILF by Jesse McGrew and Josh Lawren) have helped provide more insight on the data structures of Infocom games. Utilities to translate the Z-code to a more easily readable format did help show the inner routines of the games. Without variable names, attribute references, and object property names, making sense of the game code remained dicult. An internal Infocom use only document,  Learning ZIL - or - Everything You Always Wanted to Know About Writing Interactive Fiction But Couldn't Find Anyone Still Working Here to Ask , gave basic details about the how the games run and how the syntax parts of the game were designed in ZIL. The release of an MDL-based Zork source code did oer more insight into the inner workings of the original Zork game, but understanding MDL was an added barrier. While there are basic parsing and command processing algorithms in the MDL-version of Zork, they were signicantly changed when translated to the microcomputer versions. The release of the Mini-Zork source code and other tidbits from the Infocom cabinet helped unmask and clarify the game code and the coding process that are essential to all Infocom games. + +This blog will describe those hidden details of Infocom games, using Zork 1 as the base. It will also provide some of the modications made to these core routines by specic Infocom games. Subsequent post will provide the inner puzzle workings in all Infocom games. Only the text games will be used. None of the graphics based games are analyzed. + +All routine and variable names in the Infocom source code (Mini-Zork) and documentation are in all capital letters. Game names are in bold. Unnamed variables and routines are given names that are a best guess. + +Apologizes for any errors in these posts. They'll be xed if possible. + +## 1 ZIL, ZILCH, ZAP, and ZIP + +## 1.1 Introduction + +ZIL is a derivative of MDL (MIT Design Language), a LISP-like language, with a minimal set of instructions needed to created IF games. The Infocom game les created from ZIL source code were run through the ZIL compiler (ZILCH) to create Z assembly language code. This assembly code was then sent through the Z Assembler Program (ZAP) to create the actual Z-code. No copies of + +6 + +1.2 ZIP versions 1 + +ZILCH or ZAP software have ever been released or leaked to the public. There is also very little documentation about these programs. The Infocom Cabinet les only mentions some compilation ags used in ZILCH and the basic function of ZAP. The nal Z-code could be run on a Z-machine or any computer that emulated one using a Zork Interpreter Program (ZIP). Dierent ZIP versions have dierent memory and processing requirements. All have frequently used and writable data in their core memory which enables quicker execution of the program. Less used and read-only data is read from a storage medium (le or disk) on an as needed basis. + +Throughout the history of Infocom, six versions of the Z-code were recreated, but only the rst 5 were used for text-only games. + +## 1.2 ZIP versions 1 + +Many of the Z-code instructions used in Infocom games are in this rst version of ZIP. It is unclear what the memory requirements are for it though. Only one ZIP 1 game, Zork 1, was ever released by Infocom. + +## 1.3 ZIP version 2 + +ZIP 2 was used to create Zork 1-R15 and the rst version of Zork 2. It introduced frequent words (AKA abbreviations) and a new header element (serial number) which is just a 6 digit ASCII representation of the release date in year-month-day format. + +## 1.4 ZIP version 3 + +Version 3 was used to create a majority of the Infocom games. Infocom documents indicates the version 3 compatible ZIP should have a minimum of 40K (maybe 32K) of core memory and a oppy drive with at least 80K of storage. Due to limitations to the ZIP 3 format, the maximum size game le is 128K. Also the response time should be a few seconds for the average command. Deadline would be the rst new game using this version. This version increased the number of abbreviations and added more output functions. Even after ZIP 4 and 5 were introduced, Infocom would produce 24 games using ZIP 3. + +For outputs, ZIP 3 compatible programs had 2 or 3 windows where text could be displayed instead of 1 in ZIP 1 and 2. One of these, the status bar is not usually used unless a special ag bit is set in the header. Most games create the status bar in the main or lower, window(0). Two additional output streams were created. One streams the text into a specied memory block. The other was called a command script which recorded the input and output of the game. + +Finally, game verication was added by adding a le length and checksum into the header. The VERIFY command would check the game data le against these values. + +## 1.5 Enhanced ZIP (EZIP), version 4 + +Version 4, renamed Enhanced ZIP (EZIP), was introduced with A Mind Forever Voyaging. A smaller version of EZIP was apparently created called, LZIP, or lower-case EZIP for computers with memory limitations. The minimal hardware requirements for EZIP were at least 128KB of memory and a single disk drive that can at least access 140KB. The computer system needs to have upper and lower case characters and a screen to display 80 characters across with at least 14 lines. These requirements would allow games to only take a few seconds to complete a typical go command. The maximum size game le is 256K. + +EZIP increased the memory space to allow more objects and rooms along with longer words (up to 9 characters) in the vocabulary. Several new Z-code operands also simplied some of the table- + +7 + +2 General structure of Infocom Games and Data Structures + +related coding for these games, oered more ways to call routines, and gave more control to how text displayed on the screen by dividing it up into various windows. + +The specs of EZIP limited these games to an IBM PC, Macintosh, enhanced Apple //e, C128, Amiga, and Atari ST. Four games were released using this. No known LZIP version of games seem to exist. + +## 1.6 Extended ZIP (XZIP), version 5 + +Introduced with Beyond Zork, version 5 (XZIP) allowed for games with more objects and rooms and added more opcodes for routine calling, text, and table manipulations. Borderzone and Sherlock would be the only other new games to use this version. Infocom would release its Solid Goal (AKA Greatest Hits) series which were re-releases of past popular games but in the XZIP compatible format. However these games did not utilize the added functionality of XZIP. + +## 1.7 YZIP, version 6 + +YZIP (successor to XZIP) is version 6 which mainly added mouse, graphical windows, and menu functions with Z-codes. The graphical based Infocom games used this version and will not be discussed. + +## 2 General structure of Infocom Games and Data Structures + +## 2.1 Introduction and Story Headers + +Since version 1 of ZIP, the story header is a xed 64 bytes at the start of every Infocom game that provides information regarding the location of specic data and code. The header for ZIP 1 games used the rst 9 words/18 bytes. Subsequent ZIP versions would add more values into the header. XZIP (Version 5) would use all 32 words (64 bytes). + +The original story header information about the game and addresses to specic types of data. Details are in Appendix A. The rst word, ZVERSION, ensures that the ZIP is compatible with the given story le and emulates the proper Z-machine version. The version number is located in the rst byte. The second byte has the mode ags which are set by the ZAP assembler (for bits 0 and 1) and the ZIP at startup for the remaining bits. START address will be the rst operation to be executed by the ZIP. It points to the rst instruction and not the start of the routine. The next three addresses are used by the various instructions. All the object-related operators use the address in OBJECT to manipulate the object data. The READ instruction uses the Vocabulary data at VOCAB to match and tokenize the characters in the input buer. GLOBALS points to the table holding the global variables data. + +ZIP 1 Story Header: + +Other information would be added to the story header with newer ZIP versions. The complete layout is in Appendix A. + +## 2.2 The Memory Layout of Infocom Games + +The layout of data in the Infocom game les is fairly consistent between games. An example using Zork 1 is shown below. The memory of the emulated Z-machine is rst loaded with the header information starting at $0000. Memory from $0000 up to PURBOT encompasses the writeable memory such as variables, objects, tables, and buers. Data after PURBOT is read-only data such as syntax data, routines, preposition data, and strings. The exact locations of the syntax data, action routines, and preposition table are stored in global variables, not the header. The ZIP will continue to load data into memory. All data up to the address in ENDLOD must be loaded. The ZIP may + +8 + +2.3 The Massive Object Table + +|Word|Name|Function| +|---|---|---| +|00|ZVERSION|Byte 0: Z-machine version
Byte 1: Z-machine mode| +|01|ZORKID|Release number| +|02|ENDLOD|End address of pre-loaded memory, start of variable (or exchangeable memory)| +|03|START|Address of rst instruction (not routine), Program Counter| +|04|VOCAB|Address to Vocabulary table| +|05|OBJECT|Address to Object data| +|06|GLOBALS|Address to Global Variable table| +|07|PURBOT|Start address of read-only (static) memory| + + + +Table 1: ZIP 1 Story Header + +decide to load data past ENDLOD at its discretion. All data after ENDLOD can be swapped out with other disk-based data as needed. Usually routines and strings are the data that is swapped. All important and quickly accessible data remains resident in memory below the ENDLOD address. A sample layout of data structure in Zork 1 gives more details (using infodump): + +Base End Size 0000 3F 40 Story file header 0040 7D 3D Objects - Property Defaults (Address at OBJECTS, word 5) 007E 974 935 Objects - Entries 0975 203A 16C6 Objects - Property data 203B 221A 1E0 Global Variables (Address at GLOBALS, word 6) 221B 2C28 A0E Misc Data (such as tables and buffers) 2C29 2CFE D6 Syntax - Pointer table (Address at PURBOT) 2CFF 33d4 6D6 Syntax - Entries (referred by the Pointer Table) 33D5 34b6 E2 Action routine table (Address in global variables) 34B7 3598 E2 Pre-action routine table (Address in global variables) 3599 35DE 46 Preposition table (Address in global variables) 35DF 46CA 10EC Vocabulary (Address at VOCAB, word 4) 46CC EDC5 A6FA Routines (Load up to ENDLOD, $5DEC here) EDC6 14328 5563 Strings + +14329 143FF D7 Empty (fill up to the end of memory page) + +## 2.3 The Massive Object Table + +Objects are the heart of the Infocom games and are the rst data after the story header. Storing them in a logical and ecient manner for the game to access is important. Each object contains information such as the name, properties and attributes. It will also have a parent and possibly siblings. The object's parent is usually a room or container that contains the object. Siblings are objects that are in the same room or container. Rooms are also considered objects and have a generic ROOMS object as the parent for all rooms. Attributes are true/false bits that set various characteristics of an object such as is it takable (TAKEBIT) or a source of re (FLAMEBIT). They are numbered 0 to 31. Each object will dene all the attributes. Properties are like attributes but hold groups of bytes instead of a bit. The maximum size for a property is 8 bytes. If no property is given for an object, the default property value (a word) is used. Properties are numbered 1 to 31. Objects are numbered from 1 to 255. + +9 + +2 General structure of Infocom Games and Data Structures + +- ˆ Default Property Table: + + - 31 words that are the default property values if it is not explicit set for a specic object + +- ˆ Object Entries - repeated for all objects + + - 4 bytes representing the 32 attribute bits (#0=top bit of byte 0, #31=bottom bit of byte 3) + + - 1 byte each for object number of the parent, sibling, and child of the object + + - 1 word address to that object's property table + +- ˆ Property Table - repeated for all objects with their own property table + + - 1 byte for size of the object name in words + + - Z-string of the object name + + - 1 byte for property info (LLLNNNNN) + + - bits 5-7 = length of property-1 (length 1-8 bytes is represented as 0-7) + + - bits 0-4 = property number + + - 1-8 bytes of property data + + - The 1 byte property info and 1-8 property data are repeated for each property, listed in descending order + +Example object property table: + +## (TBD) + +The meaning of an attribute or property number is consistent in all objects in that game but not consistent between games. For example. the attribute bit and properties used in Zork 1 are listed in Appendices B and C. The number of objects is not specically stored here but calculated based upon the number of object entries. It can also be calculated by the dierence between the addresses of the rst object entry and rst property table entry divided by 9 bytes for each entry. + +## 2.4 Global Variables + +The section following the objects is a 480 byte block corresponding to 240 global variables with each holding a word. By default in Infocom version 1-3 games, variable 0 contains the object number of the player's current location. Variable 1 is the score while variable 2 is the number of turns or game time. A game does not need to use all 240 global variables and can use part of this memory block for other variable data such as tables and buers. The addresses to these other data structures as well as addresses to specialized grammar structures like syntax entries, preposition table, and action routine table are typically stored in global variables. + +## 2.5 Tables and Buers + +Between the last global variable and the start of the static data (at PURBOT), there is usually extra memory that is used to store custom data structures. These are typical tables and buers. Tables are a xed set of words where the rst word (element 0) contains the number of elements in the table. Examples include tables to hold the direct or indirect object numbers. A buer is just a xed set of bytes used to hold any type of data. The most common buers used in Infocom games are the input buer (INBUF) or token buer (LEXV). These data structures are not standard to ZIL and are specic to Infocom games. For ZIP 1-3 games, these tables are located in the preloaded memory of the computer. For EZIP and XZIP games, tables can also be located amongst the game + +10 + +routines. The addresses to these buers and tables are usually stored in specic global variables but can sometimes be hardcoded into the routines that use them. If a game does not need all 240 global variables, the space for those unused variables can be used for buers and tables. Infocom games have their own custom ZIL routines for reading and writing to these structures. + +## - 3 Syntax Entries The Biggest Mystery of them All + +## 3.1 Introduction + +Probably the most innovative part of Infocom games were their ability to understand commands written in conversational English. The dierent types of grammar information were discussed in the Learning ZIL document. The structure of syntax entries in ZIL was shown, but the layout in the Z-code les was not mentioned. Infodump and ZILF do provide some extra information about the syntax structure. There are 3 additional grammar-related data blocks in the game not mentioned in the header: prepositions, syntax pointer table, and syntax entries. + +## 3.2 Prepositions + +There is a separate table of prepositions to speed up the syntax matching process. + +- ˆ 1 byte for number of prepositions + +- ˆ 2 word entries: address of preposition in vocabulary and preposition number + +The prepositions are numbered from $FF and decrease. The address to this table is stored as a global variable. EZIP and XZIP use a compact form of the Preposition table that used a byte instead of a word for the preposition ID number. + +## 3.3 Syntax Entry Pointer Table + +The syntax entries are probably the most confusing part of Infocom games thanks to the lack of documentation. They provide the syntax structure for a particular action. To nd the matching syntax entry, the verb number is needed. Since verbs can have synonyms, dierent verbs can have the same verb number like GET and TAKE. So they would use the same syntax entries. The syntax entry table lists the address where the group of syntax entries for that specic verb number is located. This table is just a block of addresses with verb number $FF is the rst address. Subsequent addresses correspond to smaller verb numbers. + +## 3.4 Syntax Entries + +PARSER will then look through each of the syntax entries for the matched verb number and return the entry that best completely matches the given (if any) prepositions and noun clauses types. For example, the syntax entry table for verb number $F3 (or GET) has 7 dierent syntax entries. The syntaxes of GET object, GET object from object, and GET on object would correspond to 3 dierent entries. To store this grammatical information, this group of entries start with a byte indicating how many entries for that verb. It is followed by multiple 8 byte entries for all acceptable grammatical combinations: + +11 + +3 Syntax Entries - The Biggest Mystery of them All + +|Byte|Contents| +|---|---| +|0|Number of object clauses| +|1|Prep number for direct object| +|2|Prep number for indirect object| +|3|GWIMBIT number for direct object| +|4|GWIMBIT number for indirect object| +|5|LOC byte for direct object| +|6|LOC byte for indirect object| +|7|Action Number| + + + +## 3.5 Get What I Mean (GWIM) Feature + +The GWIMBIT number is used in the FIND feature mentioned in section 9.5 of Learning ZIL to nd unspecied but necessary objects in a command. PARSER will attempt to nd an object in the current location with a set attribute ag corresponding to the GWIMBIT number. If only one object is found to match, it will assume the user meant that object and use it in the given command. If no object or more than one object matches, PARSER will ask for clarication (called orphaning). The player can then give a clarifying answer without retyping the entire previous command or type a completely new command. + +For example, the syntax entry for IGNITE OBJ WITH OBJ has a GWIMBIT number for the indirect object set to the FLAME bit. If that entry is the best syntax match the command IGNITE TORCH, the indirect object is still missing. PARSER will try to nd an object with the FLAME bit set to use as the indirect object. If a an object in the current location has the FLAME bit set (like a lantern), PARSER will assume the indirect object is the lantern. The command will then assume to be IGNITE TORCH WITH LANTERN and the indirect object will be set to LANTERN. + +## 3.6 Location Restriction of Objects + +The LOC byte is probably the most mysterious value in the syntax entry. The highest 7 bits indicate how PARSER searches and checks on requested objects. For example, PARSER will not complete an action with an object on the ground if its syntax entry requires an object be held or carried. While Learning ZIL has listed 9 possible properties, the source code for Mini-Zork indicates only 7 are used through version 3: + +|Bit 7|Bit 6|Bit 5|Bit 4|Bit 3|Bit 2|Bit 1|Bit 0| +|---|---|---|---|---|---|---|---| +|Location-related Flags||||Possession-related Flags|||| +|$80|$40|$20|$10|$08|$04|$02|$01| +|HELD|CARRIED|ON-
GROUND|IN-ROOM|TAKE|MANY|HAVE|Not used| +|At top level
and not
inside
another
container|Not at top
level,
contained
inside
another
object|At top level
of a room
and not
inside
another
container|Not at top
level,
contained
inside
another
object on the
ground|Will
automatically
TAKE object
in the current
location if
necessary
before using
it|Multiple
objects are
allowed for a
particular
action|Must already
be in the
user's
possession|| + + + +When the GWIM feature tries to search for an unspecied objected, that routine needs to know how far to search. This is indicated by the ags for HELD, CARRIED, IN-ROOM, and ON-GROUND which guide how the function, SEARCH-LIST, nds objects in the given location (a room or the user). More details will be given in section 13.2. + +12 + +3.7 Pre-actions and Actions + +Learning ZIL does mention an EVERYWHERE and ADJACENT option, but there is no evidence that they were ever used in version 1-5 games as conrmed by the internal Infocom documents on ZIL. It could've been used in the graphical YZIP- based games. + +## 3.7 Pre-actions and Actions + +The action number is used to look up the routine address from the ACTION and PRE-ACTION tables. These tables sequentially list the packed addresses with any reference table. All syntaxes that refer to a similar action (INSERT DOWN object, DROP object, and SPILL object IN object) will use the same action number. INSERT object ON object and INSERT object UNDER object use two dierent action numbers as the game processes these actions dierently. The action number is also used to lookup the address for the pre-action routine if one exists (if not, $0000 is used). A pre-action routine can check the objects, variables, or game status before a particular action routine is called. The same pre-action routine can be used with dierent action routines. + +## 3.8 An Example + +Multiple verbs have the same verb number such as CARRY, GET, and TAKE in this example. The verb number will then correspond a group of syntax entries. Here only 3 are used: + +[02 00 f0 11 00 64 00 39] "carry OBJ from OBJ" [01 f9 00 00 00 00 00 31] "carry out OBJ" [01 00 00 11 00 34 00 39] "carry OBJ" + +In the rst example, the $02, indicates two noun clauses required for that syntax. The next two bytes indicate the required prepositions for the noun clauses. The $00 indicates no preposition before the direct object clause. The $F0 refers to the preposition for the indirect object clause, FROM in this case. The GWIMBIT number $11 is the attribute to check on objects if the direct object is missing. There is no GWIMBIT number for the indirect object. The direct object LOC byte $64 indicates the direct object should be CARRIED or ON-GROUND. Also, multiple objects can be in the direct object clause. In the second example, the OUT preposition is needed before the direct object. In the third example, the direct object LOC byte $34 indicates the direct object needs to be ON-GROUND or IN-ROOM. The last value ($39 or $31) is the action number which indicates what specic routine to execute for that command. Since the rst and third examples are very similar, the same routine will be used for both types of commands. + +## 3.9 Update: Compact Syntaxes to Save Space + +A variable sized syntax entry format was used only with Sherlock to help save space. There are 3 sizes for the syntax entries based upon the number of noun clauses. The format is described below. The preposition number is stored in the lower 6 bits (after subtracting $C0/192 from the preposition number) of bytes 0 and 3. + +13 + +4 Execution of Infocom Games - An Overview + +||Byte 0|Byte 1|Byte 2|Byte 3|Byte 4|Byte 5|Byte 6| +|---|---|---|---|---|---|---|---| +|No
objects|# of objects (high
2 bits) / Prep ID
(low 6 bits)|Action
Number|- - -|- - -|- - -|- - -|- - -| +|Only
direct
object|# of objects (high
2 bits) / Prep ID
(low 6 bits)|GWIMBI
byte|T
LOC
byte|Action
Number|- - -|- - -|- - -| +|Direct
and
indirect
objects|# of objects (high
2 bits) / Prep ID
(low 6 bits)|GWIMBI
byte|T
LOC
byte|Prep ID
(low 6
bits)|GWIMBI
byte|T
LOC
byte|Action
Number| + + + +## - 4 Execution of Infocom Games An Overview + +## 4.1 Introduction + +For all of their perceived complexity, Infocom games have a fairly straightforward and consistent method of getting player commands, parsing them, and executing them quickly. Each game would start with initial setting of global variables and interrupts. This loop starts with PARSER getting a command. It will then check and extract all needed grammatical information. The game will use PERFORM to call an action on the various objects in that command. CLOCKER will check and executed any interrupts if necessary. Finally, the program repeats this indenitely or the game stops. Each game used the same basic code from initialization of the game through handling interrupts. The repeated use of previous code help minimize new bugs and kept the play of the games consistent. But every game had some kind of new code which could introduce bugs. The description of these main backbone routines will be from the original Zork 1 game from 1979. Information about updates to these routines will then follow each section. + +## 4.2 Initialization with GO + +Initialization of each game begins with the GO routine which performs (at least) four required tasks: + +- ˆ Set important game variables like object number for WINNER or starting location + +- ˆ Set any interrupt routines + +- ˆ Display the version information of the game + +- ˆ Execute the LOOK command for the starting location + +The game then moves to the MAIN-LOOP. + +## 4.3 Heart Beat of the Game with MAIN-LOOP + +The game will repeatedly get new commands and execute them in an indenite loop, the MAINLOOP. The commands are obtained and parsed using PARSER which returns the action, direct objects, and indirect objects referenced by the given command. This loop will then call PERFORM to execute the given action on all the direct and indirect objects. The turn of the loop will end by calling CLOCKER which executes any necessary interrupts. MAIN-LOOP will then repeat all of these steps indenitely. + +14 + +4.4 Understanding the User with PARSER + +## 4.4 Understanding the User with PARSER + +PARSER takes the player's input or any remaining input from the last command and extracts the parts of command: verb, direct object, and indirect object. The part of speech of tokens are identied and later used by CLAUSE to nd the start and end of object clauses. + +## 4.5 Completing Previous Command with ORPHAN-MERGE + +If a previous command was orphaned, the given command is examined to by ORPHAN-MERGE to see if it supplies the missing information from the orphaned command. If so, then ORPHANMERGE combines the new information with the previous command. PARSER continues to process this xed command just like any other command. + +## 4.6 Match the Command with SYNTAX-CHECK + +The use of syntax templates allowed Infocom games to understand multiple commands using similar tokens but in dierent orders. After PARSER identies the verb, direct object, and indirect object, SYNTAX-CHECK will try to match a syntax template to the given verb, prepositions, and objects. The action with the matched syntax template is returned. If the best matched syntax template still has missing objects, the game will attempt to supply them with objects in the current location. + +## 4.7 Find the Objects with SNARF-OBJECT + +After the matching syntax template and objects are veried, the game will process each object clause and match the objects with objects from the game. It will also handle modiers like EXCEPT and quantities like ALL. + +## 4.8 Final check on Objects with TAKE-CHECK and MANY-CHECK + +The game will also conrm if the objects need to be taken rst (TAKE-CHECK) and if multiple objects are allowed for the action (MANY-CHECK). Once all the checks are completed, the game creates a table of all the objects that are referred in each object clause. + +## 4.9 Call the Actions with PERFORM + +Finally, the game will execute the requested action (PRSA) on the given direct (PRSO) and indirect (PRSI) objects with PERFORM. If one noun clause has one object but the other has multiple, the game will cycle through the clause with the multiple objects and use the same object for the other clause. However, if both clauses have multiple objects, only the direct objects will be cycled. Only the rst indirect object will be used. + +## 4.10 Tick the CLOCKER + +After the player command(s) are performed, the game's interrupt system ticks. Any interrupt whose tick count reaches 1 will have its associated routine called and then become disabled. + +## 4.11 Graphic representation of Game Flow + +Routine layout for Zork 1. Dotted lines indicate the order of function calls by MAIN-LOOP. + +15 + +5 GO - Gentlemen, Start Your Engines! + +Figure 1: Routine Layout for Zork 1 + +## - 5 GO Gentlemen, Start Your Engines! + +Arguments: None + +Return: None + +## 5.1 Introduction + +Every Infocom game begins with an initialization routine, GO, that sets certain variables and executes specic routines. It will then jump into the MAIN-LOOP which will indenitely ask for commands from the user and process them. + +## 5.2 Running GO + +All Infocom games have the similar initialization routine for each game. Learning ZIL mentions that the GO routine should: + +- ˆ Set special global variables + +- ˆ Set interrupts, usually with the QUEUE or INT routines + +- ˆ Display an opening text/title screen + +16 + +- ˆ Call V-VERSION to show copyright information, release number, and serial number + +- ˆ Call V-LOOK to describe the current location + +- ˆ Call the MAIN-LOOP + +The important global variables that are set include WINNER (object number for current active actor which is usually the PLAYER object), HERE (current location of the WINNER), and LIT (indicates if the current location is lit). All version 4 (except AMFV) and 5 games will also check the width of the screen. Some games will not execute if the screen width is too small. Infocom documentation recommends all games start with an opening title screen and display game information before showing the current locations description. + +## - 6 MAIN-LOOP Heart of the Game + +Arguments: None + +Return: None + +## 6.1 Introduction + +MAIN-LOOP is the heart of all Infocom games and keeps the game structure orderly. It repeatedly requests for parsed commands and loops indenitely. MAIN-LOOP does not get modied too much with newer games. Many of the changes were to make programming game-specic details and restrictions easier to do. These game changes essentially provided more checks on the player input and provided better responses. Only signicant changes to MAIN-LOOP will be later described. + +## 6.2 The Details + +MAIN-LOOP will call PARSER to ask and process a user's command. If PARSER cannot properly parse the command, MAIN-LOOP will continue to call PARSER to process new commands. If it has successfully processed a command, PARSER will set PRSA (parser action) with the requested action number (the 8th byte in a syntax entry) and ll the PRSO (parser direct object) and PRSI (parser indirect object) tables (P-PRSO and P-PRSI) with all the direct and indirect objects requested. This is dierent to what is described in Learning ZIL. MAIN-LOOP then loops and acts upon all the objects: + +1. Check the number of objects in the direct and indirect clauses + +2. If the direct objects clause has no objects, then see if the action is GO. + + - a) If so, then call PERFORM with GO and the direction in PRSO. + + - b) If no objects are needed for the requested action, then call PERFORM on PRSA with no objects + + - c) If at least 1 object clause is needed for the requested action, then print an error message. Display a specic error message if the command is an invalid response to an orphaned command. + +3. One clause will be designated the multiple one and one clause has a constant object, rst one in the clause. + +4. Call the requested action with PERFORM multiple times for each object in the multiple object clause as while the other clause just has its rst object used. + +17 + +6 MAIN-LOOP - Heart of the Game + + - a) If M-END is returned, then halt the processing of multiple objects. Erase any remaining commands. + + - b) If M-END is not returned, then continue looping through the multiple objects + +5. Increase number of turns by 1 (even if multiple object are processed). + +6. Call CLOCKER to check interrupts even if the given command was not valid. This was later changed in Deadline and other future games to only calling CLOCKER if PARSER was successful. + +## 6.3 Details of Multiples of Multiples + +The MAIN-LOOP handles commands with multiple objects for a given action. It will loop through these objects and execute the same action for each object. However, there is some confusion as to how it determines preference if two sets of objects are given. The examples below show how MAIN-LOOP iterates through multiple objects. + +|Multiple Direct Objects|Multiple Indirect Objects|Multiple Direct and Indirect
Objects| +|---|---|---| +|IGNITE CANDLE AND PAPER
WITH TORCH
IGNITE CANDLE WITH
TORCH
IGNITE PAPER WITH
TORCH|CUT TREE WITH AXE AND
SWORD
CUT TREE WITH AXE
CUT TREE WITH SWORD|IGNITE CANDLE AND PAPER
WITH TORCH AND FIRE
IGNITE CANDLE WITH
TORCH
IGNITE PAPER WITH
TORCH| + + + +So any additional indirect objects are ignored when there are both multiple direct and indirect objects. MAIN-LOOP will always iterate through the direct object clause if it has the same or more objects than the indirect clause. The indirect object remains constant (the rst one in the clause) for all iterations. The only exception is for only 1 direct object and multiple indirect objects. MAIN-LOOP will then iterate through the indirect objects while keeping the direct object constant. + +## 6.4 Update: Managing Global Variables + +Only minor improvements were made with handling the PRSA, PRSO, and PRSI variables. Updating the L- versions of these variables which are used by the AGAIN command was moved into the MAINLOOP section starting with Zork 2. Later games would excluding updating these variables if certain commands were used. Zork 3 added the option of checking the the LIT variable with commands that require no objects. If it was clear, then a It's too dark to see error would be given. Zork 2 (R28) also moved the updating of the IT-OBJECT and its location variable into the MAIN-LOOP instead of PERFORM. LGOP and Plundered Hearts also added a specic check on the visibility of the IT-OBJECT in the MAIN-LOOP. + +## 6.5 Update: How many NOT-HERE-OBJECTs? + +To generate a better user responses when some objects are missing in a command, MAIN-LOOP (since Indel) started to count how many requested objects in a multiple object command were not present. This number was kept in the global P-NOT-HERE variable and used to provide a more specic error message for missing objects. For example, if more than P-NOT-HERE was greater than 1, the error message would use objects instead of object. One nal coding relic is the P-MULT ag. It is cleared and set in the MAIN-LOOP, but has been used only in Indel's NOT-HEREOBJECT ACTION routine. All subsequent ZIP 3 games since Indel still set this ag, but it is + +18 + +6.6 Update: Checking For Invalid Exceptions + +never used. It is also present in various developmental versions but not used. Its true function remains unclear. + +## 6.6 Update: Checking For Invalid Exceptions + +Starting with Deadline, MAIN-LOOP would check for specic invalid situation where an action should not be done on a specic object. Deadline ensured that none of the referred objects in a command was the WINNER. Planetfall had its own special check on objects used with PICK UP by making sure the PRSO was on/in PRSI. If not, it would skip over that PRSO. + +Wishbringer (R69) would be the rst game to check for these exceptions in a separate routine instead of in MAIN-LOOP. It would be called whenever the GETFLAG mode in the game is set to ALL. MAIN-LOOP will iterate through each object in a multiple object clause and check it for any invalid exceptions exits before sending it o to PERFORM. If an invalid exception exists, PERFORM will be skipped. This CheckException routine usually looks for the actions that require the object be held or local such as DROP or INSERT. If that command is being used, the routine will see if the proper attributes are set (TAKEN, for example), held by the WINNER, or not already inserted for example. Every game since Wishbringer has such a routine. + +## 7 PARSER: How Now Brown Cow + +## (Part 1) - Data Structures + +## Arguments: None + +Result: TRUE if command is valid, FALSE if command is not valid + +## 7.1 Introduction + +Probably the most intrigue feature of Infocom games has always been the parser. The minimal online documentation touched only on the features of PARSER but never the mechanism behind PARSER. Since Zork 1, the general approach to parsing has been relatively unchanged with successive Infocom games. Improvements were made, but they mainly expanded the syntaxes that the game would understand. Many games have special commands or ways to interact with the PLAYER that results in modications in PARSER. Finally, the rst EZIP game, AMFV, added new parser commands like OOPS. + +## 7.2 Characters vs. Tokens + +The ZIP language's READ routine will take a sequence of characters and store it in the input buer (INBUF). The rst byte in that buer has the number of characters in the input. The input ends with a zero byte and does not include the terminating character like a carriage return. READ will then match words in the input buer to those in the game's vocabulary and create a separate buer of values corresponding to the matched words (called tokenizing). Words are separated by a space or designated separator characters stored in the vocabulary. For each word, a 4 byte block is created from three pieces of information for each token. First, the Z-string of the word is created and matched to the words in the vocabulary. All ZIP 1 to 3 games were limited to the rst six characters of a word. ZIP 4 and 5 could use up to nine characters. If a match is found, the address of that word in the vocabulary table is saved in the rst two bytes of the block. If no match is found, 0 is used. The third byte in the block will be the length of the token. The last byte is the oset from the start of the input buer. The token buer (LEXV) starts with two bytes. The rst byte in the token buer + +19 + +7 PARSER: How Now Brown Cow + +is the maximum number of tokens allowed. The second byte is the actual number of tokens in the buer. The rest of the token buer are groups of 4 byte token data blocks to represent the words in the input. + +Figure 2: INBUF and LEXV + +## 7.3 PARSER Variables and Grammatical Structure Denitions + +In The Parser's Role section of Learning ZIL, PARSER takes the input and tries to identify the action number for PRSA and the object numbers for PRSO (parser direct object) and PRSI (parser indirect object). This is not quite correct. It will set PRSA with the action referred by the verb in the input. However, PARSER does not set PRSO or PRSI. The only exception is if the PRSA is GO. Then the PRSO is set to the exit direction. The routine actually lls two tables (P-PRSO and P-PRSI) with all the direct and indirect objects requested in the command. The basic grammar structure for a command is: + +verb + prep + noun clause + prep + noun clause + end -of -command + verb + prep + noun clause + prep + noun clause + end -of -command ... + +Only the verb is required. All other parts are optional. A noun clause is a noun or set of nouns connected by conjunctions (AND or commas). These nouns can be modied by adjectives, quantiers (ALL, A, or ONE), or other special tokens excluding prepositions (OF, BUT, or EXCEPT). The entire noun clause is referred as a direct or indirect object clause. Prepositions are not included in the noun clause. + +For example: + +DROP THE YELLOW BALL AND CROWBAR + +INSERT A DOLLAR INTO THE RED SLOT + +TAKE ALL EXCEPT THE CANDLES + +THE YELLOW BALL AND CROWBAR, A DOLLAR, THE RED SLOT, and ALL EXCEPT THE CANDLES are the noun clauses. + +Individual commands can be connected together with end-of-command tokens (THEN, AND, , or periods) that indicate where a command stops. So: + +DROP THE YELLOW BALL AND TAKE THE CROWBAR + +DROP THE YELLOW BALL. TAKE THE CROWBAR + +are equivalent to + +DROP THE YELLOW BALL THEN TAKE THE CROWBAR + +20 + +7.4 PARSER Table (ITBL) + +Commas can separate multiple objects in a single noun clause or indicate the start of a new command. So: + +DROP THE BALL , A RAKE AND SHOVEL DROP THE BALL , TAKE THE SHOVEL + +are processed dierently based upon word type after the comma. More in the details below. + +## 7.4 PARSER Table (ITBL) + +The main goal of PARSER is to extract the action (PRSA) and valid objects in the direct and indirect object clauses from the given command. To assist other routines in extracting this information, PARSER will store specic information related to the verb, prepositions, and location of noun clauses in a 10 word table, ITBL: + +|Word 0|Verb Number (VERB)| +|---|---| +|Word 1|Verb Table Address (VERBN)| +|Word 2|Prep Number (PREP1)| +|Word 3|Addr of Prep (PREP1N)| +|Word 4|Prep Number (PREP2)| +|Word 5|Addr of Prep (PREP2N)| +|Word 6|Start Addr of Direct Clause (NC1)| +|Word 7|End Addr of Direct Clause (NC1L)| +|Word 8|Start Addr of Indirect Clause (NC2)| +|Word 9|End Addr of Indirect Clause (NC2L)| + + + +The verb number is a unique value for similar meaning verbs in the vocabulary. It is not the same as the action number. A verb will have the same verb number no matter the context of its use but it could have a dierent action number. For example, LOOK has the verb number $E9 in all syntaxes, but the action number for LOOK FOR is $2D, LOOK IN is $3F, and LOOK is $D0 corresponding to dierent types of actions. The verb table contains the same information about the verb as in the token buer: verb's address (in Vocabulary), length, and location in the input buer (INBUF). The start and end addresses of a clause refer to locations in the token buer (LEXV). Of note, this end address actually points to the token AFTER the last included token in the particular clause. + +Figure 3: Parser Table + +## 7.5 Checking Word Types with WT? + +Arguments (Address, word type to match, word type to return) + +Return ID value or FALSE if no match + +WT? is one of the most important routines in Infocom games and sees if the Vocabulary entry at the given address has the given word type. This is the primary word type as described in Section 2.6. If the primary word type does not match the given word type, WT? returns with FALSE. If there is a match, the result returned depends on the third argument. If no third argument is given, the routine will return TRUE. If the third argument matches the secondary word type (as described in + +21 + +7 PARSER: How Now Brown Cow + +Section 2.6), then the secondary ID is returned. Otherwise, the primary ID is returned regardless if it is a valid word type for the primary ID. + +|it is a valid word type for the primary ID.|it is a valid word type for the primary ID.|it is a valid word type for the primary ID.|it is a valid word type for the primary ID.|it is a valid word type for the primary ID.|it is a valid word type for the primary ID.||| +|---|---|---|---|---|---|---|---| +|Primary word type||||||Secondary word type|| +|Bit 7|Bit 6|Bit 5|Bit 4|Bit 3|Bit 2|Bit 1|Bit 0| +|$80|$40|$20|$10|$08|$04|$02 =
Adjective|$00 =
Noun| +|Noun|Verb|Adjective|Direction|Preposition|Special|$03 =
Direction|$01 =
Verb| + + + +Using: + +## $4386:3A 6B C4 D9 62 B5 B4 + +the rst 4 bytes are the z-string for inat. $62 indicates it is an verb and adjective. So, + +## CALL WT?($4386, $40 or $20) will return TRUE + +CALL WT?($4386, $40 or $20, $02) will return the secondary ID of $B5. CALL WT?($4386, $40 or $20, $00 or $01 or $03) will return the primary ID of $B4. CALL WT?($4386, $10) will return FALSE as there is no match. + +Infocom games interestingly do not put the special ID values for directions, verbs, or adjectives as the primary ID value when those tokens only have one word type. For example, the Vocabulary entry for search is: + +$4967:61 46 DD 0D 41 E0 00 + +with the word type as 41 (primary type is verb, secondary type is verb). The primary ID value is $00 though. To get the verb number ($E0), you have to access the secondary ID by using $03 as the third argument: + +CALL WT?($4967, $40, $01) + +Since a third argument is needed anyways to get an ID value, the designers to just put it as the secondary ID value. + +Almost everyone game uses the same WT? routine. So games did not even use a separate routine but just hard coded the check when needed. LGOP did add an additional word type check for nouns, $80. If it was found, the routine would quickly exit (no value is returned for nouns) and bypass checking for secondary word types. Sherlock uses the newer compressed Vocabulary entry format. Since secondary word type checking happened mainly with prepositions, WT? only allowed prepositions to be checked then when secondary word type arguments are given. This is done by searching the Preposition table. If a match is found the preposition value is calculated based upon the token's position in the Preposition table. Internal Infocom notes mentions a special WT? for The Lurking Horror where 3 ID values were stored for each token, but no evidence of this can be found of this routine in the 3 known game releases. + +## (Part 2) - Scanning Tokens + +## 7.6 Start of PARSER: Where is the command? + +PARSER was able to understand single commands or multiple commands separated by . or THEN by parsing them individually. It rst decides if the next command should come from the previously given input by seeing if P-CONT is set. This variable contains the starting location of the next command's rst token from the previous input. This is set by seeing if more tokens exist after a complete command is parsed. If P-CONT is clear, PARSER then asks for new input from the user by printing > character and calling the READ opcode. + +22 + +7.7 Now, Traverse the Tokens. . . + +## 7.7 Now, Traverse the Tokens. . . + +Because of the structure of accepted commands, PARSER can search for a command in an ecient manner. It will walk through the tokens and look for ones with specic parts of speech. If a noun clause is found, PARSER will call another routine, CLAUSE, to nd the start and end tokens for the direct object clause. If no error is returned by CLAUSE, PARSER will continue checking tokens and look for another noun clause (indirect object clause) or end-of-command token. The order for checking tokens is: + +1. Invalid Token + +All valid tokens have an address to their associated entry in the vocabulary. Any invalid or unmatch tokens are given an address of $00. If this is found, an unknown-word error message will be printed and FALSE returned. + +2. End-of-Command Token + + - An end-of-command token (THEN or .) will stop the loop and jump to the post-looping processing. If there are more tokens, PARSER will save the position of this next token which PARSER will use for the next command. + +3. Direction Token + + - This is the only verb with its own specic check in PARSER since it is the most common command given. A direction token has an associated direction value which is the property number for a room's exits in that direction. There are 4 special scenarios where this direction value is saved and the loop is stopped: + + 1. This is a 1 token command, just the direction is given. + + 2. This is a 2 token command and the verb GO was already given (as in GO EAST). + + 3. There are more tokens after the direction, and the next token is a end-of-command token. 4. There are more tokens after the direction, and the next token is a conjunction token (AND or ,). If so, the conjunction token is changed to then to indicate a new command. So a series of direction commands separated by commas or and become separate commands. + +PRSA is set to GO (if not already done). PRSO is later set to the direction value. + +4. Verb Token + + - If a verb token is found, PARSER checks if a verb has already been a found. A command cannot have two verbs. If no verb has already been found, this verb's verb number and address to a verb table that has the 4 byte token data are stored in words 0 and 1 of ITBL. If a verb has already be found, PARSER will see if it the word could also refer to a dierent valid part of speech. + +5. Preposition, Quantity, Adjective, and Noun Tokens + + - Any of the above tokens indicates a noun clause is starting. The number of noun clauses variable is incremented. A separate routine (CLAUSE) will then nd the end of the noun clause and store the start and end addresses in ITBL. CLAUSE then returns the start address of any remaining tokens PARSER should process. There are several exceptions where CLAUSE is not execute: + + 1. If the matched adjective or noun is followed by OF, PARSER will ignore the adjective and noun and use the token after OF for the start of the noun clause. This new token will be matched on a subsequent loop. + + 2. If there are no more tokens or an end-of-command token is next after the matched preposition + +23 + +7 PARSER: How Now Brown Cow + +and less than 2 noun clauses have been found, the preposition address and value information will be save into ITBL (Word 2 and 3). + +3. If there are already 2 noun clauses, a "Too many noun clauses??" error is given. PARSER will then return with FALSE. + +6. Special Token + +Any remaining special tokens that do not aect the syntax or objects requested will be ignored. This includes tokens like IS, YES, A, or THE. + +7. Improper/extra tokens - Syntax Error + + - All other situations are a syntax error. Therefore, PARSER will display a can't-use-the-word error and return FALSE. examples? + +The rst version of PARSER could understand multiple commands if they were separated by THEN or .. Using AND or , between verbs without objects like + +## JUMP AND LOOK + +were not understood. However, commands with objects separated by AND or , like + +## OPEN MAILBOX AND GET LEAFLET + +are accepted as CLAUSE would realize the AND separates two commands. + +## (Part 3) - Updates (Actors, Adverbs, and Numbers) + +## 7.8 Update: Speaking to Actors with Quotes + +The rst modication to PARSER began with Zork 2 and relates to double quotes in commands. A double quote is treated like an end-of-command token like THEN or period. It also toggles the QUOTE-FLAG which is essentially a ag for nding an another double quote. The rst double quote seen sets that ag. A second will clear it. + +In Zork 2, the use of a double quote comes into play in several special situations.When the player says something out loud such as SAY ABRACADABRA, the game will typically ignore these commands unless you are saying special words for a spell or a riddle. The game will then pull out the word after the rst double quote and use it to trigger other routines. + +PARSER will also handle speaking to the other actors using quotes. Actors are characters in the game that can be asked questions or perform actions. They are created using objects and have the PERSONBIT set. Using interrupts, the game can have the actors move or perform other actions on their own. To have an actor perform an action like: + +## TELL WIZARD "TURN OFF THE LAMP" + +PARSER rst divides up the command into two separate commands with the double quote as the terminating token for both commands. So the previous command becomes: + +## TELL WIZARD and + +## TURN OFF THE LAMP + +To have actors perform actions, PERFORM (discussed later) will call the TELL/ASK routine rst which ensure the direct object is a person (PERSONBIT) and then set WINNER to the actor. PARSER will then process the second command with the actor as the WINNER. The individual action routines handle these special situation where actors perform the commands by checking the value of WINNER. Later, PARSER will ensure that WINNER is set back to the player on its next execution by detecting a clear QUOTE-FLAG and WINNER not set to the player. + +24 + +7.9 Update: Titles and Adverbs (briey) + +Deadline expanded the methods for interacting with actors by allowing commands in these formats: TELL/ASK actor TO command + +## Actor THEN command + +PARSER would change the TO or THEN tokens to a double quote token which is then treated as an end-of-command token just like it was back in Zork 2. The verb number in ITBL would automatically be set to the verb number for TELL if the second format is used. HGTG later added a check to ensure the token after TO was a verb which indicated the start of another command. The player in Deadline could also refer to actors with their name followed by a comma: + +## Actor, command + +PARSER (through CLAUSE) considers as a end-of-command between two commands. The comma is then changed to then and processed like in the other formats. + +Deadline also allowed the PLAYER to ask the actors directly about an object or ask them to give you an object using: + +## ASK actor ABOUT object ASK actor FOR object + +These are treated like any other command and depend on the object attributes. + +Finally, Deadline also introduced a new routine which checks if the requested actor is in the current location and if the subsequent command is appropriate (action is WHAT, FIND, TELL, or SHOW) before allowing the commands to be processed. This check would be added to subsequent games. PERFORM will call the TELL/ASK routine which ensure the direct object is a person (PERSONBIT) and then set WINNER to the actor. PARSER will then process the second command with the actor as the WINNER. + +## 7.9 Update: Titles and Adverbs (briey) + +The recognition of titles used to address actors like MRS. or MR. and automatically skip them along with any following period was introduced with Deadline. The game also recognized 5 specic adverbs (CAREFULLY, QUIETLY, SLOWLY, QUICKLY, and BRIEFLY) and saved the adverb's Vocabulary address in ADVERB. It would be used later by specic action routines such as WATCH, GO, or READ. The adverbs were considered a special token and not a specic part of speech. Bureaucracy is the only game with adverbs, but they are not needed to complete the game. + +25 + +7 PARSER: How Now Brown Cow + +## 7.10 Update: Numbers, a new object + +Deadline introduce numbers and time to Infocom games. Since these values do not match with any token, they are given a $0000 Vocabulary address. NUMBER? will then change the $0000 to the vocabulary address for a intnum or number token. A special global variable contains the numerical value. For time values, the time in minutes is saved: + +1. Loop through all the characters of an unknown token + +2. If the character is a digit, then take the current sum, multiply it by 10, and add this value of this digit. + +3. If a : is found, then the previous digits are likely an hour value. Save this into a separate TIM variable and reset the total sum. Continue looping through the remaining digits which will be the minutes value. + +4. Once all the digits are read (and there are no extra non-digit characters), then the sum (value of the digits) is save into P-NUMBER and this unknown token is given the Vocabulary address for intnum. + +5. If the sum is greater than 10000, then the routine will return FALSE. + +6. If the number was an time value, then the sum is actually the minutes value. The routine will take the hour value and multiply it by 60 and then add the sum. If the hour value is greater than 23, then the routine will return FALSE. There is no restriction on the size of the minutes value though. This new sum (time in minutes) is also saved in P-NUMBER. + +Figure 4: Numbers, Time + +Routines can then search for the intnum token and use the value in the corresponding global variable. Because of this design, only one number or time value could be used in each command. Games using time values can impose certain restrictions on the what hours are valid. For example, Deadline considers any time between 1:00 and 7:59 to be PM. So 7:00 is converted to 19:00 (or 7pm) for the game. Hours from 0 to 23 are considered valid for all games. Most games will convert the hour and minutes into all minutes. Only Sherlock checks the value of the minutes. So a time value of 14:80 could be valid in most games that use time as they are converted to all minutes. More number formats would be recognized in later games. They are listed below: + +26 + +|Added Format|Game Introduced|Notes| +|---|---|---| +|$xxx|Cutthroats|No cents portion is allowed. The value
is saved in a dierent global variable
than P-NUMBER. The intnum object
has it's property 11 set to amount of
money.| +|xxx-yyyy|Suspect|The phone number is stored as two
separate numbers in separate global
variables| +|xxx,xxx|LGOP|Comma separated number is converted
to a single 4-6 digit number| +|xx(B-E) $xxx.yy #xxxx|Bureaucracy|Number followed by letters B-E
indicates seat row and letter (4 times
row # + seat letter converted to 0-3
value) and money value (converted to
cents) are saved in their own special
global values. The object type returned
is intnum except for a money value
where money is used. If a # starts a
number, it is ignored.| +|HH:MM AM/PM|Sherlock|The hour is converted to the
corresponding 24 hour value. The
entire time is saved in the game's
special time table format| + + + +## 8 PARSER: New Commands and Routines + +## 8.1 Introduction + +Ever since the rst version of Zork 1, there has been an AGAIN command. However, it basically used the previously saved PRSA, PRSO, and PRSI in a PERFORM call. The use of EZIP allowed new routines to be created to handle the various new buers and provide new commands. Starting with AMFV, a new method to manage the input and token buers allowed for a more sophisticated AGAIN command. The game also introduced the OOPS command where unknown words in a command could be corrected one by one. Beyond Zork added the UNDO command which allows the user to go back one command. + +Also two new buers were created, AGAIN-LEXV and OOPS-INBUF, for three new routines. In essence, they could be also considered previous LEXV and previous INBUF, respectively. + +## 8.2 STUFF + +Arguments: source buer, destination buer, length + +## Returns: TRUE + +STUFF copies a set length of tokens from the source buer to the destination buer. If no length is given, the maximum length (29 tokens) is used. First, the two bytes (maximum and actual number of tokens) at the start of the token buer are copied. Then all the token buer data is copied up to the amount requested. The routine always returns TRUE. Beyond Zork was able to replace this routine with a new opcode (COPY_TABLE). Sherlock still used STUFF. + +27 + +8 PARSER: New Commands and Routines + +## 8.3 INBUF-STUFF + +Arguments: source buer, destination buer + +Returns: TRUE + +INBUF-STUFF just copies the entire contents one character at at time of the source input buer to the destination input buer. With XZIP, Beyond Zork and Sherlock used a new instruction (COPY_TABLE) to handle this routines. + +## 8.4 New AGAIN command + +In Infocom games since AMFV, the AGAIN command is more formally processed and checked specically by PARSER. If it is given, several checks are done before the old command is copied back and processed: + +- ˆ Check that last command was not orphaned + +- ˆ Check that last command was valid + +- ˆ Check that the actor in last command is still present. This is to ensure that any non-player actor is present if an actor direct command is used again. + +- ˆ Check the subsequent token (if it exists) is not a end-of-command token (THEN, AND. period, or comma). Then print the error message. + +If all the above checks pass, PARSER copies the old input buer from OOPS-INBUF into INBUF. It does the same for the AGAIN-LEXV to LEXV. + +If commands exist after an AGAIN command, the entire token and input buers are temporarily saved into reserve buers, RESERVE-LEXV and RESERVE-INBUF, respectively, because they would've been overwritten while performing the AGAIN command. The start of the next command is also saved in RESERVE-PTR. The previous WINNER, P-MERGED ag, and DIR (just in case) are restored from global variables. The previous token and input buers, AGAIN-LEXV and OOPSINBUF, are again copied back into LEXV and INBUF, respectively. Finally, OTBL is copied back into ITBL. PARSER then continues to process the newly restored command as normal. On the next iteration of PARSER, it will detect that RESERVE-PTR is set and copy the remain command info from RESERVE-LEXV and RESERVE-INBUF data back into LEXV and INBUF, respectively. The next command starts in the restored data at the location indicated by RESERVE-PTR. + +## 8.5 OOPS! + +The OOPS command was an important innovation in the era before copy and paste were invented. Previously any commands with errors would have to be completely re-typed with the correction. This was especially painful for long or multiple commands. The user could correct any errors with + +## OOPS + +If an unknown token is found, various values are calculated and stored in OOPS-TABLE: + +|Word 0|Word 1|Word 2|Word 3| +|---|---|---|---| +|Oset to unknown
token in
AGAIN-LEXV|Oset to start of
command with
unknown token in
AGAIN-LEXV|Length of all token
data in command
with the unknown
token|Oset to byte after
the end of
OOPS-INBUF| + + + +28 + +8.6 INBUF-ADD + +PARSER will grab the Vocabulary address of the replacement token (after OOPS) and replace it with the empty address in the unknown token's entry in AGAIN-LEXV. Only the rst token after OOPS is checked. An error message is display if more tokens are given. INBUF-ADD is called to appended the replacement token to the end of the OOPS-INBUF. That routine will also store the replacement token's length and updated pointer in OOPS-INBUF in the unknown token's entry in AGAIN-LEXV. Finally the modied OOPS-INBUF and AGAIN-LEXV are copied back into the INBUF and LEXV, respectively. PARSER then resumes parsing the command as it normally does. If there is another unknown word error in this just correct command, another OOPS can be used to correct the next error. This can go on until all the errors are xed. + +This feature has been present in all version 3 games since Sorcerer-R18, and all version 4 and 5 games since its introduction. + +## 8.6 INBUF-ADD + +Arguments: length of replacement token, ptr of replacement token in INBUF, oset of unknown token in OOPS-INBUF + +## Returns: TRUE + +INBUF-ADD is slightly more sophisticated. The characters for the referred token in the rst two arguments in appended to the end of OOPS-INBUF. The pointer to the end of OOPS-INBUF is retrieved from the OOPS-TABLE (or calculated using the data from the last token if it is not in the OOPS-TABLE). The length of this replacement token and pointer to it in OOPS-INBUF are copied back into the unknown token's entry in AGAIN-LEXV. + +Figure 5: INBUF-ADD and OOPS-TABLE + +## 8.7 UNDO + +Finally an UNDO command was introduced with Beyond Zork which would restore the game state before the last command was executed. While this capability was available since version 1 of Z-machines, it was never implemented because of the need for more internal memory (a limited quantity back then) or having to constantly save the data onto an external memory storage device, + +29 + +9 CLAUSE: Find the Noun Clause Boundaries + +likely a disk drive, which would slow the execution of the game down. But the requirements of XZIP called for ZIP emulators with higher memory capacities, the necessary game state data could be saved into a dierent part of the internal memory. Only Beyond Zork and Sherlock had this function. + +The saving of the current game state was done in the PARSER routine after the check for a GO command. The save_undo operation is used to copy the contents of dynamic memory (everything before the Syntax data) which is essentially the header information, all OBJECT data, global variables, tables, and buers. Also the call stack is saved. If the player uses the UNDO command, it would call a separate routine that would attempt to restore the saved gate state data and continue with the execution of the command after the save_undo operation in PARSER. If an error occurs, the appropriate error message is displayed. + +## 8.8 Update: Other Minor Changes in PARSER + +EZIP and XZIP games only added slight modications to PARSER. Most of these revolved around setting or clearing certain global variables such as XNAM. Others would search for unimportant tokens such as please and skip over them. + +## 8.9 Update: ReplaceToken routine + +With the advent of the AGAIN command in AMFV and its use of the AGAIN-LEXV buer, the replacing of tokens in PARSER and CLAUSE required changes in both those buers. So a new routine was created, ReplaceToken. But it also including a way to copy the length and pointer information for the token before the replaced one into the location of the replaced one. The dictionary address for the replaced token will then be modied as normal. + +## 9 CLAUSE: Find the Noun Clause Boundaries + +Arguments: Start address of clause, Preposition number of clause, Vocabulary address of current token + +Return: Address to start of clause, -1 if no tokens are left to process, or FALSE if error in clause syntax + +## 9.1 Introduction + +CLAUSE will nd the end address of a noun clause and saves the start and end addresses for this clause along with the preposition information in ITBL. P-NCN (noun clause number) indicates if the direct (1) or indirect (2) object clause is being processed. Specic locations in ITBL for the extracted information to be stored are calculated depending on P-NCN. + +||Direct Object (Noun 1)
Clause|Indirect Object (Noun
2) Clause| +|---|---|---| +|Preposition Number|Word 2|Word 4| +|Vocabulary Address of Preposition|Word 3|Word 5| +|Address of First Token (Start)|Word 6|Word 8| +|Address after Last Token (End)|Word 7|Word 9| + + + +30 + +9.2 How it screens... + +## 9.2 How it screens... + +CLAUSE loops through tokens in LEXV as long as the given tokens are part of a valid syntax for a noun clause. Briey, the routine will + +- ˆ Save any preposition information (number and address) if it exists into the proper locations in ITBL. + + - The preposition information is usually passed as an argument. CLAUSE will then nd the Vocabulary address of the preposition. + + - If no preposition is given or exists, $00 is saved as the preposition number and address + +- ˆ Save the start address of the noun clause into the proper location in ITBL. + +- ˆ Attempt to get the next token to process as well. + +- ˆ Loop through the tokens in LEXV as long as the given tokens are part of a valid syntax for a noun clause (see rules below) + +Once the routine stopped checking for tokens, it can return three possible results: FALSE if there was a syntax error, -1 if no more tokens left to process, or oset to the last token in the newly found clause. The address after the end of the newly found clause will be saved in the proper location in ITBL for the end address of the clause. + +|ITBL for the end address of the|clause.|| +|---|---|---| +|Type|Example|Action| +|Unmatched||Display error & return| +|Conjunction (and or ,)|Eat apple and orange|Set ANDFLAG & continue| +|Quantity (all or one)|Take all bananas|Continue| +|Quantity (all or one) +
of|Burn one of the letters|Skip of token & continue| +|End-of-command then or .|Throw hammer then go west|Save end address of current
noun clause and return| +|Preposition (not the rst
token in the clause)|Put letter inside mailbox|Save end address of current
noun clause and return| +|Noun (also an Adjective) +
Noun|Drop gold coin|Continue| +|Noun and ANDFLAG set|Eat apple and orange and
grape|Clear ANDFLAG & continue| +|Noun and ANDFLAG clear
and next token is an
exception (but or
exception) or conjunction
token|Eat apple and orange
Eat all fruit except banana|Continue| +|Noun|Turn statue|Save end address of current
noun clause & return| +|Adjective|Read brown book|Continue| +|Special (not Conjunction,
Quantity, or
End-of-command)|Push the button|Continue| +|All others (verbs or direction)
and ANDFLAG set|Ignite red match and go east|Change conjunction token to
then and go back 2 tokens
to process again*| +|All others (verbs or direction)
and ANDFLAG clear|Cut rope go north|Display Can't Use error &
return| + + + +31 + +9 CLAUSE: Find the Noun Clause Boundaries + +*For example: + +get candle and eat apple ^ + +is converted to: + +get candle then eat apple ^ + +with CLAUSE going back to the conjunction token to reprocess the clause. The routine will recognize then as an end-of-command token, marking the end of a clause. + +32 + +9.3 Update: New Matches. . . + +## 9.3 Update: New Matches. . . + +Later Infocom games added more acceptable token combination for clauses which caused CLAUSE to also grow. Outside of specialized tokens used in specic games (such as spell names in Spellbreaker), the new and improved CLAUSE mainly became more sophisticated on deciding what part of speech a token was being based upon its context with other tokens. The major additional rules created by Infocom are below: + +|Type|Example|Action|Game| +|---|---|---|---| +|Articles
("the","a","an")|Eat an apple|Skip over token &
continue|Deadline| +|Unmatched and
NUMBER? is true|Take 2 candles|Unmatched token
changed to intnum,
global var set to value,
& continue|Deadline| +|of and verb = accuse|Accuse Bob of murder|Change of to with &
continue|Deadline| +|. and previous token is
a title (mrs,mr,ms,
dr, st)|Ask Mr. Smith about
paper|Continue|Deadline,
LGOP| +|Preposition (rst token
checked)|Throw out ball|Continue|Zork 1-R88| +|Preposition (prep value
already given in
argument)||Skip over token &
continue|LGOP| +|Preposition (can also be
an adjective) and a prep
has already been give|Write on back side|Assume preposition is an
adjective and continue|Bureaucracy| +|Noun (can also be
adjective) and next
token is noun or adj or
direction|Drop gold coin
Take copper hot rod|Assume noun is an
adjective & Continue|HGTG,
Moonmist| +|Adjective AND
P-MERGED/
P-OFLAG set or verb
given|Green
Get Green|Continue|Zork 1-R88| +|Special (not
Conjunction, Quantity,
or End-of-command)
AND P-MERGED/
P-OFLAG set or verb
given|A red
Get a red|Continue|Zork 1-R88| +|All others (verb,
direction) and
ANDFLAG set and verb
given|Ignite red match and go
east|Change conjunction
token to then and go
back 2 tokens &
continue|Seastalker| +|Profanity, interrogatives|Eat banana who|Display error message &
stop|LGOP, Trinity| + + + +33 + +10 ORPHAN-MERGE: Fix What Is Broken + +## 10 ORPHAN-MERGE: Fix What Is Broken + +Arguments: None + +Return: TRUE if orphaned command is corrected, FALSE if unable to correct the orphaned command + +## 10.1 Introduction + +Now that the major parts of the command have been identied (if they exist) and stored in ITBL, PARSER will rst see if the given command corrects an orphaned command, a previous command that had ambiguous or missing necessary information. Originally, only nouns could be ambiguous. So the clarifying token had be an adjective. If an adjective could refer to more than one object in a location, an error was given. For example, the user enters: + +## IGNITE CANDLE + +in an empty room. An orphaned command will be created as no indirect object is given (the candle needs to be ignited with something). The game will respond that it does not know what the user wants to ignite the touch with. This could be correct by then typing: + +## TORCH + +## or + +## WITH THE TORCH + +A new command IGNITE CANDLE WITH TORCH would be created and replace the previous command TORCH (or WITH THE TORCH) and then processed by PARSER. In another example, a room contains a red card, red ower, and blue ower. If the command was + +GET FLOWER + +it would be considered ambiguous as it could be the red or blue ower. This could be corrected by typing: + +## RED + +which would then lead to a newly created command: + +## GET RED FLOWER + +If the command was + +## GET BLUE + +GET-OBJECT which matches the token with an object would be able to gure out you meant the blue ower as there is only one object with the BLUE adjective. If the command was + +GET RED + +then GET-OBJECT would display a missing noun error as the game will not create an orphaned command from an ambiguous adjective. + +Starting with HGTG, ambiguous adjectives could be used to create an orphaned command be later claried with a noun. So the previous example would prompt the game to ask you for clarication on which RED object. These examples could be corrected by typing just CARD or FLOWER. So a clarifying noun could also refer to more than one object in the same room which would then trigger another orphan command. The game would then use the new information to match a single specic object and process the newly completed command. + +34 + +10.2 Fixing Orphans with ORPHAN-MERGE + +## 10.2 Fixing Orphans with ORPHAN-MERGE + +- ORPHAN-MERGE is called by PARSER if the P-OFLAG has been set in 2 possible situations: + + - ˆ SYNTAX-CHECK is in unable to match even one syntax entries for the given verb because of a missing object clause + + - ˆ GET-OBJECT is matches more than one object for the given noun, adjective, or GWIM bit + +Regardless of the outcome of the routine call, P-OFLAG will be cleared. So the user only has one chance to supply missing or clarifying tokens to an orphaned command. The orphaned command data is stored in OTBL (a mirror of ITBL) and OCLAUSE (a mirror of LEXV). ORPHAN-MERGE rst validates the given input through various checks. Only the missing or clarifying token is required. If any extra information is given (like prepositions or verbs) are given, then they must match the ones in the orphaned command to be accepted. ORPHAN-MERGE checks two aspects of the given input: + +- ˆ Verb - To be a valid response to an orphan command, the new input must have the same verb as the orphaned command or must have no verb. If the verb is dierent, the new input is likely a new command, and ORPHAN-MERGE will return with FALSE. + +- ˆ Number of noun clause - Only one noun clause is allowed to clarify an ambiguous or supply a missing noun clause. If two are given in the new input, then ORPHAN-MERGE will return with FALSE. + +ORPHAN-MERGE then checks if the orphaned command has a missing clause by looking for $01 in the starting address of the noun clauses in OTBL. If both object clauses have starting addresses equal to $01, then only the direct object clause is processed. PARSER will then attempt to process this partially completed command and again discover this partially incomplete command can satisfy a syntax entry. If this new command is again unable to be matched with a syntax, it will be orphaned with the indirect object clause missing, The user can then input another clarifying command for the indirect object clause. + +Once a missing object clause is found, ORPHAN-MERGE will see ensure that the preposition in the given input (if entered) matches the one in the orphaned command (stored in OTBL). Finally, the routine will copy the start and end addresses of the clarifying noun clause (the single adjective) from LEXV into the appropriate start and end address in OTBL. If the missing object clause is the indirect one, the number of noun clauses will also be set to 2. ORPHAN-MERGE will then skip checking if the given input claries an ambiguous noun. + +## 10.3 Clearing up Ambiguity + +If no missing noun clause found in OTBL (start address with $01), the given input could clarify an ambiguous noun. ORPHAN-MERGE checks if P-ACLAUSE was set (by GET-OBJECTS) to the element of the clause's start address in OTBL with the ambiguous noun ($06 for direct object and $08 for indirect object clause). ORPHAN-MERGE will then proceed: + +- ˆ Check that there is only one noun clause in the given input. If there are more, than clear P-ACLAUSE and return with a FALSE. + +- ˆ Loop through the tokens in the noun clause indicated by P-ACLAUSE and check their word types. + +- ˆ If the token's word type is an adjective, then temporarily save the vocabulary address of that token. If an adjective has already been found, the new one will override the old one. So only the last given adjective is used for clarication. + +35 + +10 ORPHAN-MERGE: Fix What Is Broken + +- ˆ If the token's word type is a noun, then ORPHAN-MERGE ensures that the token is the same as the ambiguous noun (P-NAM) or is ONE. In the above example, BLUE ONE or RED FLOWER are both valid for the ambiguous FLOWER. It will then stop checking tokens and call ACLAUSE-WIN (to create a new noun clause) + +- ˆ All other word types or mismatched nouns will cause ORPHAN-MERGE to stop checking tokens and return FALSE. + +- ˆ If no nouns are given after checking all the tokens in the given noun clause, ORPHAN-MERGE will also call ACLAUSE-WIN using the last found adjective in the given noun clause. + +- ˆ If no adjective is given after checking all those tokens, ORPHAN-MERGE will return false. + +Once any missing noun clause is replaced or an ambiguous word is claried, ORPHAN-MERGE will copy the data from OTBL into ITBL for PARSER to continue to processing as if the complete command had just been entered. So an claried orphaned command will use tokens located in LEXV and OCLAUSE. + +## 10.4 ACLAUSE-WIN + +Arguments: Vocabulary address for Adjective + +## Return: TRUE + +ACLAUSE-WIN setups up parameters for CLAUSE-COPY using ACLAUSE (element number of a clause's start address such as $06), ACLAUSE + 1 (element number of clause's end address such as $07), and the clarifying adjective. By setting the parse table that CLAUSE-COPY should use (CC-TBL) to OTBL, CLAUSE-COPY will copy the tokens from OCLAUSE back to OCLAUSE and insert a clarifying adjective before the ambiguous noun (P-NAM). The routine will also ensure the P-NCN is set to the correct number of noun clauses. ACLAUSE is cleared to indicate the ambiguous noun was claried. + +## 10.5 Using CLAUSE-COPY + +- Arguments: Element number of start address of clause in ITBL, Element number of end address of clause in ITBL, INSERT adjective (optional) + +## Return: TRUE + +CLAUSE-COPY copies tokens from LEXV to the end of OCLAUSE using the addresses in one of the parse table (ITBL or OTBL) referred by a global variable (ocial name is not known). CLAUSECOPY is called with two arguments, the element numbers that identify the start and end addresses for the noun clause to copy. These element values are $06 and $07 for the direct object clause or $08 and $09 for the indirect object clause. It will then append the requested tokens to the end of OCLAUSE. + +- ˆ Find the oset to the end of OCLAUSE using the value in element 0. + +- ˆ Calculate the new start address of the orphaned noun clause by nding the end address of OCLAUSE as it is the start address for the newly appended tokens. + +- ˆ Store this new start address in the appropriate element (start address for DO or IO clause) in OTBL ($06 or $08). + +36 + +10.6 CLAUSE-ADD + +- ˆ CLAUSE-COPY will repeatedly call CLAUSE-ADD to copy the tokens located in the requested noun clause to the end of OCLAUSE. These new tokens have their byte pointer to the input buer and length set to zero. + +- ˆ If a clarifying token (usually an adjective) is given while copying these tokens, CLAUSE-COPY will check if the copied token matches the current ambiguous token, P-ANAM (a vocabulary address for the ambiguous noun). If a match is found, CLAUSE-ADD is called with the vocabulary address of ths clarifying token and a new token with the clarifying token is added to OCLAUSE. Then the P-ANAM is also added to OCLAUSE with CLAUSE-ADD. + +- ˆ Once all the remaining tokens in the requested noun clause are appended to OCLAUSE, CLAUSE-COPY will calculate the new end address of OCLAUSE and save it into the proper element (end address of noun clause) in OTBL. + +Starting with Zork 1, there was a bug with this setup. Each time an orphaned noun clause was created, it was appended to OCLAUSE. Since the end of OCLAUSE was never reset back to $00, it was possible OCLAUSE would grow outside of its 100 byte size limit and spill over into the memory locations of other variables. This was correct with Zork 3 by setting the size of OCLAUSE to zero in the OPRHAN routine. + +## 10.6 CLAUSE-ADD + +Arguments: Vocabulary address to token + +## Return: True + +CLAUSE-ADD takes the given Vocabulary address and creates a new token add the end of OCLAUSE. Originally, the destination token buer defaulted to OCLAUSE. In Moonmist, the P-CCTBL was used to stored the address of the destination token buer in element 2. More information about P- CCTBL in Section 10.10. In Bureaucracy (and later Beyond Zork), the address of the destination token buer was passed as the 2nd argument instead of using P-CCTBL. + +## 10.7 Update: New changes of ORPHAN-MERGE + +First changes to ORPHAN-MERGE were with Zork 1-R88. It mainly corrected the bug when a rst token in a claifying response which can be a verb and an adjective is matched as a verb rst. This is especially an issue when only the rst 6 characters are used. For example, the command: + +## BOARD BOAT + +in a location with a row boat and inatable boat in created an orphaned command because BOAT is ambiguous. If the user then enters: + +## INFLAT + +the original ORPHAN-MERGE processes INFLAT as inate, the verb, and asks what object to inate. However, then this new version will understand that the user meant an inatable BOAT and treat INFLAT as an adjective to clarify the ambiguous BOAT. Also, ORPHAN-MERGE will understand that the input: + +## INFLAT BOAT + +means INFLAT is the adjective inatable because the next token, BOAT, is a noun. INFLAT will then clarify the ambiguous noun. Obviously, any token that can be a verb and adjective will be treated as a verb by PARSER if there no orphan command to clarify. ALL and ONE are + +37 + +10 ORPHAN-MERGE: Fix What Is Broken + +also considered valid adjectives for the purpose of clarication. Finally, a new global variable, P- MERGED, is set if an orphaned command is claried and is used mainly when printing object names in PRSO/PRSI-PRINT to ensure the whole correct object name is printed and not the clarifying token. + +Planetfall-R37 introduced a similar dual word type option for tokens which can be verbs and nouns. Early in the routine, the given verb was checked for this dual word type. If it could be a noun, then ORPHAN-MERGE assumed it should be treated as a noun. The start address of the subsequent noun clause was adjusted to include the previously thought verb. For example: + +## IGNITE TORCH + +which will result in a missing noun error (need an indirect object). If the user then types: + +## FIRE + +this token can be a verb or noun. but will be treated as a noun as there is an orphaned command. HGTG introduced the ability to clarify an ambiguous adjective. In those situations, a clarifying noun is given. Previously, any noun given in the clarifying clause is ignored (if it is the same one in the orphaned command) or causes an error if its dierent. Now, ORPHAN-MERGE will also look for a clarifying noun if the ambiguous word is an adjective. NCLAUSE-WIN is called to complete the clarication. ONE and ALL are valid adjectives or nouns and can clarify either ambiguous nouns or adjectives. If either of these tokens follows another adjective, then they should be considered a noun and call ACLAUSE-WIN immediately with the given adjective as the clarifying token. Finally, there is a new data structure, OVTBL, which holds the VTBL from original command that was orphaned. Essentially, ORPHAN-MERGE copies back the information from OVTBL into VTBL but sets OTBL's VTBL addr to VTBL and not OVTBL. But the OTBL information will be copied back to ITBL. Suspect reconrmed the number of noun clauses in the xed orphan command by seeing if the OTBLs IO's start address is set. If also skipped out of ORPHAN-MERGE if it was called while there are still unprocessed commands are given where the next verb is tell. AMFV changed the checking of a given verb. If it is the same as the orphaned command, then skip over checking it as a possible an adj. If the given verb does not match, then ORPHAN-MERGE will check to see if that token can also be an adj. Bureaucracy did not include the NCLAUSE-WIN option but did allow for the entire noun clause to be used to clarify the ambiguous noun. This is done by setting the ADJ to $01 which will cause CLAUSE-COPY to insert the entire noun clause instead of just the adjective. It also blocks certain adjectives for clarications. + +The Lurking Horror introduced the assumption that if a verb is given without a noun clause, then the verb could be the clarifying token. The start of the noun clause would then be adjusted to include the verb token. Copying of OVTBL and OTBL is gone??? + +Sherlock did also check to see if a solo verb can be a noun. If so, then the verb table is cleared and the start and end addresses of the DO are set to include the verb token. Sherlock will adjusted the end address of the DO clause to include the entire IO clause for certain situations ( + TOMB or BOX + ). + +AMFV changed the way that the clarifying input is used with orphaned commands. The main new feature is clarifying an ambiguous noun as well. ORPHAN-MERGE still begins with + +- ˆ Check if the new input's verb (if given) matches the one in the orphaned command or the given verb also can be an adjective. If so, set the ADJ to $01 for now. + +- ˆ Otherwise check if the given verb can also be a noun. If so and no other nouns were given then set the start and end addresses of the direct object clause to be those around the rst token (address of the rst token and address of the second token). The verb # and addr to VTBl will be cleared. + +38 + +10.7 Update: New changes of ORPHAN-MERGE + +After those possible scenarios are checked, the routine does the similar checking as the rst gen ORPHAN-MERGE. It rst checks the scenarios where a verb is given which could have dierent meanings. + +- ˆ If the new verb is dierent than the old verb from OTBL, then return false. The new input is probably a new command. + +- ˆ If the new verb can also be an adjective, then save it in ADJ just in case. + +- ˆ If the new verb can also be a noun and no noun clauses are given, then set the start and end addresses of the direct object clause to point to the verb. + +The routine then does a few more checks: + +- ˆ Rechecks the verb in the new input (if it exists). If this new verb is not the same as the one in the OTBL and it cannot also be an adjective, then RFALSE (an error). + +- ˆ If there two noun clauses are given, then it is an error (can't oer two answers to correct an orphaned command). + +The rst type of orphan correction is replacing a missing noun clause. This is marked by $01 as the start address of a noun clause. The routine will check the direct object clause rst and then the indirect object clause if the direct object is not missing any information. The routine cannot correct both clauses with a single command. + +- ˆ Check that the preposition in the new input (if given) is the same as the one in the orphaned noun clause. If it is not the same, then return false. + +- ˆ If ADJ is set (which means the verb is can also be a clarifying adjective), then set the start and end addresses of the missing noun clause in OTBL to address of the rst token in the token buer. If the ADJ is not set, then set the start and end addresses of the missing noun clause in OTBL to the ones from the direct object clause in ITBL. For a missing indirect object clause, the routine copies the start and end addresses from the direct object clause in ITBL to the indirect object clause in OTBL and sets the # of noun clauses to 2. + +If neither noun clause is missing, the routine will look for a clause with an ambiguous token. In that situation, ACLAUSE has the eld # for the clause with the ambiguous token whose vocabulary address is in P-ANAM. The routine will make sure there is only 1 noun clause to clarify the ambiguous token. If is no noun clauses given and any verb in the new input cannot be an adjective as well, then it will error. The routine will then walk through the tokens in the direct object clause of the new input to nd the appropriate clarifying tokens for the orphaned command. Each token will be checked: + +- ˆ A quantity token (ALL, EVERYT, ONE) - set current token as ADJ + +- ˆ An adjective type - set cur token as ADJ + +- ˆ ONE (after other tokens) - call ACLAUSE-WIN with ADJ and stop looping + +- ˆ A noun type - If it is the same as the ambiguous token, then call ACLAUSE-WIN with ADJ. Otherwise, call NCLAUSE-WIN as the noun is a clarifying token. + +If END is blank (for some reason), then set # of noun clause to 1, set END to original BEG, and set BEG to 1 token block before END. Once all the checking has been done, ORPHAN-MERGE will copy the info from OVTBL back to VTBL and copy the OTBL info back to ITBL. P-MERGED is then set to indicate the orphan command is probably xed. + +39 + +10 ORPHAN-MERGE: Fix What Is Broken + +## 10.8 Update: New ACLAUSE-WIN expands its options + +Zork 1-R88 also began to use the OVTBL to hold the corresponding verb info for the ambiguous noun. This would be used to later repopulate VTBL and create a valid command with the claried token and ambiguous noun. + +HGTG began to use the CC-TBL to hold parameters needed for ACLAUSE-WIN. Theses were mainly the source and destination buer. This allowed other buers besides OCLAUSE to be used. The dictionary address of the clarifying adjective in INSRT was still the only passed argument. AMFV abandoned using CC-TBL because all of the needed values could be passed as routine arguments. + +Bureaucracy added an interesting twist if ACLAUSE-WIN was called with a blank INSRT. In that situation, it is set to $01 which then causes CLAUSE-COPY to insert the entire direct object clause of the recently entered clarifying command instead of a single token. Lurking Horror got rid of this function. + +## 10.9 Update: NCLAUSE-WIN + +## Arguments: Nothing + +## Results: True + +NCLAUSE-WIN is a new routine rst used in HGTG that is used when players were able to clarify an ambiguous adjective. It was not always allowed after its introduction in HGTG. It always uses the direct object clause from ITBL as the source (obviously as the clarifying noun is the rst any only object given in an input) and P-ACLAUSE as the destination clause in OTBL. It also adjusts the number of noun clauses if necessary. Since Trinity, newer version 4 games and all version 5 games that did allow for ambiguous nouns used a version that did not rely on CC-TBL to pass arguments to CLAUSE-COPY. This could be done with the routine call arguments now. This new version adds several more checks: + +if there are no noun clauses and the given verb can be an noun, then assume the verb is a noun actually and create a noun clause around it. Also adjust the NCN to 1. It can then continue processing it. + +It also looks for one when checking for nouns. Typically, one is usually an adjective. But if it follows after another adjective, then it should be considered a noun and call ACLAUSE-WIN immediately. + +## 10.10 Update: New version of CLAUSE-COPY + +With HGTG, the destination addresses were added to P-CCTBL in those situations where CLAUSECOPY was need to copy tokens to something other than OCLAUSE. + +|Word 0|Word 1|Word 2|Word 3| +|---|---|---|---| +|Element # for start
address for source
token buer|Element # for end
address in source
token buer|Element # for start
address in
destination token
buer|Element # for end
address in
destination token
buer| + + + +Also the tables with source and destination addresses were passed to CLAUSE-COPY along with the clarifying adjective to insert. + +LGOP checked to see if the rst token to add to the OCLAUSE is the same as the clarifying token. If so, then don't check to see if current token to copy is the ambiguous one. Just copy it to OCLAUSE. LGOP also xed the resetting of OCLAUSE ptrs by moving all the recently added tokens to OCLAUSE to the front of OCLAUSE. + +40 + +Moonmist added more changes. First, it changed the parameters in CCTBL to the address of the destination token buer (such as OCLAUSE) in word 2. No word 3 value is needed. Second, it also checked the rst token in the destination token buer was the same as the clarifying token when the ambiguous token is found while copying tokens. If so, it would skip over adding this clarifying token but would add the ambiguous token to the destination token. Finally, if the INSRT=$01, it would copy the entire direct object clause in the clarifying command before the ambiguous token. This allows a phrase to be copied instead of a signal token. + +Bureaucracy did not have rely on CC-TBL for arguments as it was written in ZIP 4 which allowed up to 7 arguments to be passed to routines. CLAUSE-COPY past the address to the source and destination input tables, elements for the start and end addresses for the tokens to copy, source of the tokens, and the INSRT clarifying token if necessary as arguments. It has a more sophisticated memory management system though. If the end of the new claried clause token buer (OCLAUSE for direct object and IClause for indirect object) is close to the start of the clause that is going to be copied, the routine will not the claried clause token buer but modify the source clause by shifting over tokens to create space for the clarifying tokens to be inserted. This is to prevent an overrun of the clause token buer into other buers. Otherwise, it functioned very similar to the Moonmist. It did skip over moving the recently added tokens in the destination token buer to the front of it if the source token buer is the same as the destination token buer. This is because they will be automatically inserted to the front of the destination token buer. + +The Lurking Horror allowed for a noun clause to be the clarifying information, not just a token as in previous versions of CLAUSE-COPY. Another argument, along with the original INSRT, to represent the start and end addresses of the tokens to insert when the ambiguous token is found. Beyond Zork used the more simple version in Moonmist but did not need CC-TBL like Bureaucracy. + +## 11 SYNTAX-CHECK: Find Correct Syntax Entry + +## Arguments: None + +Return: TRUE if syntax matched, Syntax number if matched using GWIM, or FALSE for all errors or orphaned commands + +## 11.1 Introduction + +Given the verb, any prepositions, and any direct and indirect clauses, the game will need to see which valid syntax structure for the given verb best matches. Dierent usages of the same verb can require dierent prepositions and noun clauses (for example: TAKE LETTER, TAKE LETTER FROM MAILBOX, TAKE LETTER TO BOB). These combinations are stored as syntax entries. SYNTAX-CHECK will attempt to nd the best match. If no perfect match can be found, GWIM is called to try to replace any needed missing objects. If that also fails to completely match a syntax entry, an orphan command will be created with ORPHAN. + +## 11.2 Hierarchy of Matching + +SYNTAX-CHECK will try to match the command's combination of verb, prepositions, and object clauses with one of the verb's syntax entries. If it cannot nd a perfect match because of missing information, it will return the best tting entry based upon a specic hierarchy. First, SYNTAX-CHECK will check if a verb is given. If not, then show an missing verb error and return FALSE. Up to 2 noun clauses are allowed in a syntax entry. If SYNTAX-CHECK nds a + +41 + +11 SYNTAX-CHECK: Find Correct Syntax Entry + +complete match as it loops through all the verb's syntax entries, it will return that syntax entry's action number. + +## 11.3 GWIM (Get What I Mean) + +Arguments: GWIMBIT number, LOC byte + +Return: Object number if only 1 match, False if no or more than 1 object matched + +If there is no complete match, SYNTAX-CHECK will call GWIM to try to match any missing object clauses with a local object to create a complete match, favoring a missing direct object clause over indirect object. For example, the command IGNITE PAPER would typically cause an error as the game does not know what object to use to ignite the paper (the indirect object clause is missing). GWIM uses GET-OBJECT to search for a local object that has a specic attribute ag (GWIMBIT) set and returns that object. In that example, the GWIMBIT would be the attribute to indicate an object is a source of re. If a local object was a TORCH and it was on re, then GWIM would display the clarication and return TORCH: + +## IGNITE PAPER + +## [with the torch] + +GWIM rst checks if the passed GWIMBIT is the RMUNGBIT (AKA KLUDGEBIT). If so, the ROOMS object is returned. After setting the global SLOCBITS and GWIMBIT variables and resetting the number of objects in the MERGE table, GET-OBJECT will try to match any object in the current location with a GWIMBIT set. If none or more than 1 object is found, then return false. If only 1 object is matched, then return that object. Also, GWIM will display a small amount of text in parentheses or brackets to describe which object was matched. It may also have additional text to clarify the matched objects (for example, if it is in your hand). + +42 + +11.4 ORPHAN: Creating an Orphaned Command + +## 11.4 ORPHAN: Creating an Orphaned Command + +- Arguments: Address of syntax entry with missing direct object, Address of syntax entry with missing indirect object + +## Return: True + +If a the command given or completed by using GWIM does not completely match any valid syntax entries, SYNTAX-CHECK will call ORPHAN to setup an orphaned command. It is also called by GET-OBJECT (described later) if too many objects match the given adjective and noun in a clause. ORPHAN will rst copy the data from ITBL to OTBL. If an indirect object clause is given (possibly has ambiguous words), the indirect object tokens from LEXV are appended into OCLAUSE. Then, if a direct object clause is given (possibly has ambiguous words), the direct object tokens from LEXV are appended into OCLAUSE. So the indirect object tokens are placed before the direct object tokens in OCLAUSE. When called by SYNTAX-CHECK, it also copies the corresponding preposition number (if any) for the missing noun clauses into the OTBL. ORPHAN then stores $01 as the start address of the missing or ambiguous noun clauses in the OTBL to indicate that clause has a missing or ambiguous word. Finally, SYNTAX-CHECK will then set the O-FLAG and oer clarifying information for the player to help supply the missing information. + +Figure 6: Syntax Check + +43 + +11 SYNTAX-CHECK: Find Correct Syntax Entry + +Possible Outcomes: + +|Possible Outcomes:|||| +|---|---|---|---| +|Syntax Entry
Command|0 object clauses|1 object clause|2 object clauses| +|0 object clauses|All prepositions
should be all blank.
Return Action
number|If DO preposition
matches or
command
preposition is
missing, then DO Is
missing. Save
syntax entry
address in DO
missing var.|If DO preposition
matches or
command
preposition is
missing, then DO is
missing. Save
syntax entry
address in DO
missing var.| +|1 object clause|All prepositions
should be all blank.
Return Action
number|If DO preposition
matches and
indirect object
preposition is
blank, then get
Action number|If DO preposition
matches, then IO is
missing. Save
syntax entry
address in IO
missing var.| +|2 object clauses|All prepositions
should be all blank.
Return Action
number|If DO preposition
matches and
indirect object
preposition is
blank, then get
Action number|If direct and
indirect object
prepositions match,
then get Action
number| + + + +## 11.5 Update: SYNTAX-CHECK + +No major changes were made in SYNTAX-CHECK except for a check on the number of noun clauses in the input. If it was greater than the number in the syntax entry, then it would bypass checking for orphaned clauses as it isn't possible. Also, the error messaging was more specic depending on what piece of information was missing such as using WHO or WHERE when appropriate and if the WINNER Is the PLAYER or a dierent actor. Some games check for specic verbs that will not generate an orphaned command. + +Mini-Zork did use a new compact format for the syntax entries that was also used in Sherlock. No other released Infocom game used it. The size of the entry depended on the number of objects in the entry. The number of objects is stored in the highest 2 bits of byte 1. The preposition number for the direct object is reduced by $C0 and stored in the lower 6 bits of byte 1. The preposition number for the indirect object is also reduced by $C0 and stored in the lower 6 bits of byte 5. However, the top 2 bits are not used in byte 5. The syntax token byte is composed to ags that refer to the LOC tokens referred earlier. + +The structure of the syntax entries for no objects is: + +|Byte 1|Byte 2| +|---|---| +|2 high bits =
number of object
clauses
6 low bits =
Preposition number
for direct object|Action
number| + + + +44 + +11.6 Update: New versions of GWIM + +The structure of the syntax entries with only direct objects is: + +||Byte 1||Byte 2|Byte 3|Byte 4|||| +|---|---|---|---|---|---|---|---|---| +||2 high bits =||Action|GWIMBIT|LOC byte|||| +||number of object||number|number|for direct|||| +||clauses|||for direct|object|||| +||6 low bits =|||object||||| +||Preposition number|||||||| +||for direct object|||||||| +|The structure of the||syntax entries with direct|||and indirect|objects is:||| +||Byte 1||Byte 2|Byte 3|Byte 4|Byte 5|Byte 6|Byte 7| +||2 high bits =||Action|GWIMBIT|LOC byte|Prep|GWIMBIT|LOC byte| +||number of object||number|number|for direct|number|number|for| +||clauses|||for direct|object|for|for|indirect| +||6 low bits =|||object||indirect|indirect|object| +||Preposition number|||||object|object|| +||for direct object|||||||| + + + +These variable sized entries help eliminate any wasted space in the syntax entry blocks. SYNTAXCHECK and SYNTAX-FOUND were adjusted to use this dierent format. + +## 11.6 Update: New versions of GWIM + +Many games used modied GWIM routines that would add extra clarifying text such as of, at or in when commenting to the user about an object matched because of a command with a specic preposition. The Witness would use a special string to refer to an object matched by GWIM instead of the standard object name. For example, GWIM will use Asian man preceded by the instead of the object's name, Mr. Phong. Trinity introduced an initial check of the GWIMBIT in the IT-OBJECT if it is set to an object. The routine will return what the object that is referenced by IT-OBJECT. + +## 11.7 Update: New versions of ORPHAN + +HGTG introduce a new method for handling orphaned commands with the introduction of the game's new CLAUSE-COPY (see above). For its ORPHAN routine, it made sure OCLAUSE was cleared if P-MERGED is also clear and also copied over VTBL to OVTBL. + +Mini-Zork has a modied ORPHAN because it uses a modied syntax entry format. Instead of manually getting the preposition number from the syntax entry, Mini-Zork calls a separate routine that extracts is from the modied syntax entry format. Version 4 and 5 games could call CLAUSECOPY with more arguments and needed fewer global variables. So CC-TBL was not needed anymore. Version 5 games used the same routine as the Version 4 games but using the COPY-TABLE command that replaced the manual copying loop in ORPHAN. + +Bureaucracy uses the same routine as AMFV except it copies the object clauses into separate token buers, OCLAUSE for the direct object tokens and IClause for the indirect object tokens. + +## 12 Getting Objects with SNARF-OBJECTS + +## Arguments: None + +Return: TRUE if objects found, FALSE if no objects found + +45 + +12 Getting Objects with SNARF-OBJECTS + +## 12.1 Introduction + +After nding the best syntax entry and any local objects to represent missing objects in the given command, SNARF-OBJECTS looks for the objects mentioned in the direct and indirect object clauses by calling two other routines on each clause: + +SNARFEM to nd all the objects mentioned in the noun clause + +BUT-MERGE to remove all the exception objects not wanted by the user + +The matched objects have their numbers stored into the appropriate tables, P-PRSO and P-PRSI. + +## 12.2 Setting up Routines + +SNARF-OBJECT simply sets up the variables needed by SNARFEM: start and end addresses of direct object clause and address of table to store extracted objects, P-PRSO. After calling SNARFEM, BUT-MERGE is called to remove any exception objects from BUTTABLE if any exists. This is repeated using the indirect object clause and P-PRSI. If there is only one object in P-PRSI and there are exception objects, SNARF-OBJECT assumes the exception objects will apply to the P-PRSO and call BUT-MERGE again on P-PRSO. For example, the command: + +## CUT ALL EXCEPT NEWSPAPER + +is interpreted as multiple CUT commands on all the local objects except the newspaper. Similarly, the command: + +## ATTACK ALL PIRATES WITH ALL GUNS EXCEPT RIFLE + +has the RIFLE object removed from the indirect objects referenced by ALL GUNS. However, the following command: + +## EAT ALL FRUITS WITH FORK EXCEPT APPLE + +has the EXCEPT object applied to the direct objects this time as trying to apply it to the indirect objects could actually eliminate the only object in the indirect clause and generate an error. + +## 12.3 SNARFEM: Looking for Groups of Objects + +Arguments: Start address to noun clause, End address to noun clause, Address to object table + +Return: True if objects extracted, False if no objects extracted + +SNARFEM searches the noun clause for adjectives, nouns, and quantity (like ALL or ONE) tokens that describe one object or a single group of objects. Any found adjectives or nouns will have their values saved in the global variables P-ADJ and P-NAM respectively. If multiple adjectives or nouns are given, then only the most recent ones are saved in those variables. Any other tokens like conjunctions, exceptions (like BUT), or dierent quantity tokens indicate no more tokens to describe an object and triggers GET-OBJECT to be called which matches a local object with the given adjective and noun. Quantity tokens change how many objects are matched by GET-OBJECT by changing GETFLAGS. Exception tokens change where GET-OBJECT saves those matched objects. Details are below: + +46 + +12.4 BUT-MERGE + +|Token|Action| +|---|---| +|ALL|Set P-GETFLAGS to $01 (ALL mode)| +|ALL + OF|Set P-GETFLAGS to $01 (ALL mode) and skip over
OF token| +|BUT or EXCEPT|If BUT table not being used, then call GET-OBJECT
with TBL and switch to BUT table for subsequent
storage. Otherwise, call GET-OBJECT with BUT.| +|A or ONE (no adjective set)|Set P-GETFLAGS to $02 (ONE mode)| +|A + OF or ONE + OF (no
adjective set)|Set P-GETFLAGS to $02 (ONE mode) and skip over
OF token| +|A or ONE (adjective already set)|Copy ONEOBJ into NAM. Call GET-OBJECT with
the currently used table (TBL or BUT).| +|AND or ,|Call GET-OBJECT with the currently used table
(TBL or BUT)| +|AND or , + AND or ,|Ignore rst conjunction token and continue processing| +|Buzzwords|Skip over this token| +|OF (ALL, A, or ONE not given)|Set P-GETFLAGS to $04 (INHIBIT mode). Ignore
this object as it is an error in syntax. Of note,
PARSER already ignores any adjective or noun with
OF at the start of a clause.| +|Adjective|Set ADJ to adjective value and Dictionary address of
adjective into ADJN| +|Noun|Set Dictionary address of noun into NAM and
ONEOBJ (just in case)| +|All other tokens|Skip over this token| +|No more tokens|Call GET-OBJECT with the currently used table
(TBL or BUT)| + + + +For example, ALL OF THE CANDLES is the treated the same as ALL CANDLES. Also, A BLUE CARD AND A RED ONE is interpreted as A BLUE CARD AND A RED CARD with ONE referring to the just given noun CARD. ONE OF THE FLOWERS is seen as ONE FLOWERS. + +If BUT or EXCEPT have not been given, any numbers for found objects will be saved in table found in the third argument. Once BUT or EXCEPT have been given, all found objects will be saved in BUT table. + +## 12.4 BUT-MERGE + +Arguments: Address to object table + +Return: P-MERGE (address to merged object table) + +This routine copies the objects in the given table into the MERGE table but skips over any objects in an exception (BUTS) table. It uses ZMEMQ to see if the given object is in BUTS. While the routine returns to address to the MERGE table. It will also put the address of the given object table into MERGE. + +## 12.5 Getting Object Numbers for each Object with GET-OBJECT + +Arguments: Address to Object table, Verbose ag + +Return: TRUE if successful in getting appropriate number of object, FALSE for any error + +47 + +12 Getting Objects with SNARF-OBJECTS + +GET-OBJECT tries to nd a local object that matches the given identiers (adjective, noun, and GWIMBIT) and stores that object number in the given object table. It will limit the matched objects depending on what GETFLAGS mode (default, ALL, ONE, or INHIBIT) is set by SNARFEM. SLOCBITS is rst set to #FFFF (all ags set) to ensure the greatest chance of matching an object to the identiers. If a clause's SLOCBITS is set to a non-zero value from the matching syntax and the match mode is ALL, then that clause's SLOCBITS is used. + +GET-OBJECT requires that a noun is at least given in the command. If there is no noun, then the adjective will be used as a noun if possible. For example, gold can be an adjective or a noun like in piece of gold. If the adjective cannot be a noun, the routine will display a missing noun error and quit. Now, GET-OBJECT will look for objects in the WINNER and current location (if lit) using DO-SL. Any found objects are saved into the given object table. The processing of the objects depends on the mode: + +- ˆ ALL: Search using DO-SL and return true + +- ˆ INHIBIT: Return true + +- ˆ ONE: Search using DO-SL or GLOBAL-CHECK found: + + - 0 objects (using DO-SL): Search again using GLOBAL-CHECK + + - 0 objects (using GLOBAL-CHECK): Give a CAN'T SEE error and return false. + + - 1 object: Return true. + + - >1 objects: Randomly pick one object and move it to the top of the table. Set the number of objects to 1. Return true. + +- ˆ Default: Search using DO-SL or GLOBAL-CHECK found: + + - 0 objects (using DO-SL): Search again using GLOBAL-CHECK + + - 0 objects (using GLOBAL-CHECK): Give a CAN'T SEE error and return false. + + - 1 object: Return true. + + - >1 objects: Restore SLOCBITS from matched syntax entry. Search again with same method: + + - 0 or >1 objects: Create an orphaned command by setting the ambiguous variables (AADJ, ANAM, and OFLAG) and call OPRHAN (Initial search had >1 but second search had 0 or >1 objects matched which is an ambiguous situation.) Return false. + + - 1 object: Return true. + +The identiers, ADJ and NAM, are always cleared after GET-OBJECT is called except if in INHIBIT mode. If a correct number of objects is found, then the routine also restores the SLOCBITS to what is listed in the matching syntax. + +## 12.6 Bug: Randomly Picking Objects + +When only one object is requested like in: + +## GET ONE CARD + +in a room with multiple cards (blue card, red card, etc), GET-OBJECT will randomly choosing one object. However, the routine places this chose object in the rst position of the object table. If there is an object already in the rst position, it will be overwritten. For example: + +## GET FLASHLIGHT AND ONE CARD + +48 + +12.7 Update: New versions of SNARF-OBJECTS + +SNARFEM will call GET-OBJECT on FLASHLIGHT and put that object number in the rst position of the object table. SNARFEM will then call GET-OBJECT on ONE CARD. Since there are multiple cards in that room, GET-OBJECT will randomly pick one and store it in place of FLASHLIGHT. + +Another bug is that the randomly picked item could also picked outside of the group of matching objects. For example: + +GET FLASHLIGHT AND LETTER AND ONE CARD + +in a room with three cards, GET-OBJECT will try to randomly pick one of the three cards. If the random number is 1, GET-OBJECT will pick the object in the rst position which is FLASHLIGHT. + +## 12.7 Update: New versions of SNARF-OBJECTS + +Zork 1-R88 added an P-AND ag to help with displaying lists of objects properly and to have a hierarchy of adjectives when referring to objects. Only the rst adjective is used. All subsequent adjectives are ignored before calling GET-OBJECT. + +Sorcerer-R18 processed the indirect clause rst and then the direct object clause. However processing the exception objects is saved until the end with it trying to apply it to the direct object clause rst. If nothing happens then it will try to apply the exception objects to the indirect objects. If there are no direct objects then any exception clause will be applied to the indirect object. Most of the games since the Sorcerer-R18 had SNARFEM check if P-GETFLAGS was in ALL mode before starting. If so, it would set GETFLAGS back to ALL mode after completing its SNARFEM. LGOP set a global variable, CurrentNounClause, which is used by SNARFEM and SaveNAMAdj, when objects cannot be found. This allows ambiguous nouns or adjectives for the direct and indirect clauses to be stored separately. The game also added several more checks in the routine. If an ALL, BOTH, or EVERYTHING token is found, the routine will call MANY-CHECK to see if the syntax allows for multiple objects to be processed. It also checks if the token is profane and provides an error message. Finally, there is a check for certain adjectives. + +Bureaucracy added a check on the number of indirect objects if an exception was to be applied. If there is only 1 indirect object, it would assume the exception objects would refer to the direct objects. Trying to apply the exception objects on a single indirect object could remove it. Sherlock call SNARFEM and EXCEPTION on dierent clauses depending on how many object clauses are in the syntax entry which needs to be specially extracted with the compact format.??? + +## 12.8 Update: New versions of SNARFEM + +Sorcerer-R6 allowed special spell related word when referring to objects. Seastalker similarly allowed numbers and also had SNARFEM ignore any additional adjectives given when referring to an object. Only the rst adjective is used. + +HGTG checks if the GETFLAGS was in ALL mode. If so, the GETFLAGS is cleared (changed to default mode) and will restore the GETFLAGS back to the ALL mode once SNARFEM is complete. LGOP will check if a syntax entry will allow multiple objects if all or both is given with an object. It will be rechecked again toward the end of the PARSER routine. + +Hollywood Hijinx does allow for two adjectives to be given for some objects and has a separate routine to check for valid combinations when a second adjective is found. + +Other games will have checks for profanity which is not allowed when referring to objects. + +## 12.9 Update: New BUT-MERGE + +The only major change was with AMFV and other version 4 and 5 games was the use of SCAN_TABLE operator instead of the ZMEMQ routine. Though various parameters had to be calculated, the new + +49 + +12 Getting Objects with SNARF-OBJECTS + +operator could quickly look for a found objects in the exception table. + +## 12.10 Update: New ways to GET-OBJECT + +Every game seems to have used their own special version of GET-OBJECT. Those modications included special checks for certain actions or with certain objects and displaying special errors for certain situations. However, improvements were made over successive games. + +Zork 1-R88 added a check if the WINNER is also the PLAYER if there is an orphaned command. If so, then error that it can't be orphaned. + +Zork 2-R23 added a new WHICH-PRINT routine which also lists the possible objects for the user to choose from when the noun is ambiguous. It also ensured that the PLAYER can also be checked for objects if the WINNER needing objects is not the PLAYER. + +Zork 3 added an early check if the adjective could also be a direction. If so, then it is saved in the DIR variable and ensures the direction object is the only entry in the object table. More detailed error messages were added for various situations. + +Suspended had a unique GET-OBJECT as the player did not interact directly with the environment. So the GET-OBJECT was more liberal when searching for objects. It would ensure the SLOCBIT was #FFFF for all get commands. + +The Witness introduced the GENERIC property which contains a routine address used to clarify a requested object. If multiple objects match a given NAM instead of just one, the routine address in the GENERIC property will be called. This routine will then try to determine which specic object was requested based upon various variable values and return that object number. There is no check to see if the GENERIC property is set. If it is blank, it will just return FALSE. GET-OBJECT will then default to providing an error message and display the possible objects to choose from. Also, the NOT-HERE-OBJECT was introduced. For any unmatching identiers, the NOT-HERE-OBJECT would be returned for counting purposes. The unmatched NAM and ADJ are then saved into XNAM and XADJ. + +Planetfall did all for searching the WINNER if in ALL mode only if the WINNER was not the player. + +Sorcerer-R15 did limit the created of NOT-HERE-OBJECT and XNAM/XADJ only if the room was lit or for specic actions. + +AMFV introduced having a separate NAM and ADJ for direct and indirect object clauses. They are stored in separate two word tables with the rst element in each is for the direct clause. It was used by certain actions to check the current noun or adjective in use. It use was later expanded in LGOP. + +LGOP did save the identiers for the direct and indirect objects in dierent locations when an object is matched. It also xed the situation where the requested object is a vehicle that the WINNER is inside of. + +Spellbreaker also including the searching a vehicle for the requested object if its open. In the few situations, that multiple objects are matched, a separate routine is called to see if all the objects have the same GENERIC routine. If so, the GENERIC routine will be called to clarify which object was requested. + +Some games will have extra checks for non-matched objects to see if they are part of a special case. This is primarily for spell names. + +Bureaucracy does add a creative error message if OCLAUSE or IClause has more than 10 tokens in it. + +The Lurking Horror saves the rst 4 adjective identiers and their corresponding tokens for any object. If multiple adjectives are given, it will see if the last one can also be a noun. If that is the case, it will assign that token to NAM and decrease the number of adjectives. + +50 + +## 13 Search for Objects using SEARCH-LIST + +## 13.1 Introduction + +Another one of the interesting aspects of Infocom games is how it searches and matches objects to those requested by the player. It will use various methods to nd these objects and collect them into a table. + +## 13.2 SEARCH-LIST: Finding Objects in Room and on Winner + +Arguments: Number to Object to search inside, Address to object table, Search level (0-2) + +Return: Number of objects found + +When the user refers to objects in a command, PARSER needs to see which objects are referred and accessible. The given noun, adjective, and/or GWIMBIT will be used as identiers for a particular object. SEARCH-LIST will check the objects in a given location (a room or person) and see if it matches these identiers. There are 3 levels of search which aects which objects are checked: + +- ˆ Search-TOP/Type 0: ON-GROUND or HELD (reachable objects) + + - Look at objects that are on top of all objects + + - Match against all non-container objects and objects on surfaces in the location. Any containers (if they are open or transparent) and surfaces on the surface are checked completely. + +- ˆ Search-ALL/Type 1 (all objects) + + - Match against all objects in the location. Only containers that are open or transparent will be searched. + +- ˆ Search-BOT/Type 2: IN-ROOM or CARRIED (contained objects) + + - Look inside any containers (look at second-level or any non-top level) + + - Match against all objects on any surface and inside any open or transparent container. + +The matched objects are saved in the table addressed passed to SEARCH-LIST. + +51 + +13 Search for Objects using SEARCH-LIST + +Figure 7: Search Object + +For example, SEARCH-LIST is examining Room/Person 1. For each search mode, the listed objects will be checked: + +TOP: Obj 1,1, Surface 1,2 (Obj 1,2,1, Cont 1,2,2 (Obj 1,2,2,1)) + +BOT: Surface 1,2, Cont 1,4 (Obj 1,4,1, Surface 1,4,2 (Obj 1,4,2,1), Cont 1,4,3 (Obj 1,4,3,1)) ALL: Obj 1,1, Surface 1,2 (Obj 1,2,1, Cont 1,2,2 (Obj 1,2,2,1)), Surface 1,2, Cont 1,4 (Obj 1,4,1, Surface 1,4,2 (Obj 1,4,2,1), Cont 1,4,3 (Obj 1,4,3,1)) Object Cont 1,3 is invisible. + +All Infocom games appeared to be using the same SEARCH-LIST routine. + +## 13.3 DO-SL: Find Objects Based Upon Search Level + +Arguments: Number of object to search, LOC value to SRC-TOP, LOC value to SRC-BOT + +Return: Number of objects found + +DO-SL calls SEARCH-LIST with the appropriate search type depending on the LOC ags given in the arguments and the LOC ags in the matched syntax entry. If 1 is used for both DO-SL arguments then, SEARCH-LIST will perform a SRC-ALL match. All matched objects will be saved in P-TABLE. + +GET-OBJECT calls DO-SL with the ON-GROUND and IN-ROOM ags to look for any objects in the given location for use with the current syntax entry. Similarly, GET-OBJECT also calls it with the HELD and CARRIED ags to look for objects on the PLAYER. All other calls to DO-SL seem to mainly use the double 1 parameter which will match anything. All Infocom games appeared to be using the same DO-SL routine. + +## 13.4 GLOBAL-CHECK: Look for Objects Everywhere + +Arguments: Address to object table + +Return: True if GLOBALs checked, False if object matched from local-globals or PSEUDO objects + +Some objects in a game may be accessible from more than one locations and valid objects to be used with certain actions. GLOBAL-CHECK is the routine that tries to nd these potentially valid + +52 + +13.5 THIS-IT? + +objects. Infocom had three dierent types of these special objects: GLOBALS, LOCAL-GLOBALS, and PSEUDO objects. + +GLOBALS can be accessed from any location in the game. If a game had an AIR object, that would likely be accessible from any location. Remember, these are not necessarily rooms. LOCALGLOBALS are accessible from multiple locations but not all. The best example is a door which would be accessible from the two rooms that are separated by it. PSEUDO (or virtual) objects are the most confusing of the three objects as they are not actual objects. They only have the SYNONYMS (nouns) and ACTION properties. A given location can have PSEUDO objects that are matched if certain nouns are used in that location. The routine then jumps to a dierent routine for each noun that will gure out what is the object the user was referencing. So a bed object in two dierent rooms could be handled with a routine instead of creating multiple objects. GLOBAL-CHECK will rst try to match any identiers (noun/NAM, adj/ADJ, or GWIMBIT) to any object in the GLOBAL property (AKA LOCAL-GLOBALS) of the current location. The number to any matched objects will be added to P-TABLE. The routine does not search inside the local-global objects. Next, the PSEUDO property is checked which contains a list of 2 word pairs. The rst word is the Vocabulary address to the noun that references the pseudo object while the second word is an ACTION routine address. If the object matches, the Z-string of the matching noun and ACTION addresses are saved into a pseudo object's description and ROUTINE properties, respectively, which is then saved to P-TABLE. GLOBAL-CHECK will continue to check the remaining objects in PSEUDO and save any matches. If no objects have matched by this point, the GLOBAL-OBJECTS are searched using DO-SL on GLOBAL-OBJECTS. SLOC-BITS is temporarily set to $FFFF which makes any match valid and restored afterwards. + +## 13.5 THIS-IT? + +## Arguments: Object number + +## Return: True if object matches + +Infocom games can use three dierent identiers to see if an object matches the one requested in a command: noun (P-NAM), adjective(P-ADJ), and GWIMBIT. THIS-IT? will see if the given object matches any of these identiers. First, the routine will see if the object is visible. So invisible (or hidden) objects cannot be matched. THIS-IT? will then see if the given noun (if it exists) matches any of the Vocabulary addresses in the SYNONYMS property of the object. It will do a similar check with the given adjective (if it exists) with the addresses in the ADJECTIVE property. Finally, it will see if the GWIMBIT (if given) is set on the object. If the given information matches, THIS-IT? returns true. + +## 13.6 Update: New version of SEARCH-LIST + +Only a few major changes were added to SEARCH-LIST. Zork 2 had the addition of the SEARCHBIT attribute for objects which made it easy to restrict what objects could be searched inside of. Deadline checked the SYNONYM property for an object. If that property was not set, the object was not searched as it is not likely a real object. Some games would use the SEE-INSIDE? predicate (instead of hard coded) to determine which objects could be searched inside. + +## 13.7 Update: New version of GLOBAL-CHECK + +The rst addition was the checking if the request was made for certain actions in Deadline. If so, an additional search using DO-SL with any ags on all ROOMs in the game was done. Other games like Wishbringer and Bureaucracy had would also search the objects contained inside + +53 + +13 Search for Objects using SEARCH-LIST + +LOCAL-GLOBALS. Sherlock also included this but limited it to objects that were actually rooms. Sorcerer introduced setting the location of the PSEUDO object to the current location in case a routine needed to know that. Wishbringer also expanded the search of LOCAL-GLOBALS by having GLOBAL-CHECK also search inside those objects if possible. + +LGOP introduced a new property, THINGS, which replaced PSEUDO that added adjectives for THIS-IT? to match. THINGS would contain entries with a single adjective (if necessary) and a noun with an associated ROUTINE address. If any given noun or adjective does not match the values in an entry in THINGS, GLOBAL-CHECK will proceed to the next entry. If there is a match, the PSEUDO objects values are set as previously described. + +Several games did you a more abbreviated form of GLOBAL-CHECK. This was rst done with AMFV. After searching through the current locations local-globals, DO-SL with SRCALL was called on all the game's room objects which essentially searched all visible objects in the game. Bureaucracy did not use a typical THINGS or PSEUDO property. It used a new property which had a routine address and 1 word argument. This routine would then be called with the noun, adjective, and stored argument. An object number could then be returned and later saved in TBL. + +## 13.8 Update: New version of THIS-IT? + +Some of the games added checks to quit this routine sooner. such as a blank SYNONYM or ADJECTIVE property. AMFV removed the INVISIBLE ag check. Bureaucracy added a special check if the given object is intnum. The P-NUMBER value will then be compared to prop 20 in 2 specic objects (ight number or leaet). Also added various situations where the object given will not be matched with the identiers. The Lurking Horror would check all the NAMs in the G99 table against all the synonyms in an object. Sherlock also checks any token associated with the given object by of like in glass of milk. It will also check the associated token to see if it matches any adjectives and/or synonyms for the object. + +## 13.9 Update: NOT-HERE-OBJECT + +Introduced in The Witness, a new object, NOT-HERE-OBJECT, stood in for any requested objects in a command that was not found. For example, if the user requested: + +## TAKE CANDLE , TORCH , and MATCH + +but the torch was not present, the PRSOTBL would list 3 object numbers: one candle, one NOTHERE-OBJECT, and one match. When generating the table of object numbers corresponding to the objects requested in a noun clause, any recognized object that was not present in the current location had the NOT-HERE-OBJECT number used in its place. This occurs in the GET-OBJECT routine. So the total number of returned objects is the same as requested. The NOT-HERE-OBJECT will also call the GENERIC routine of an object to try to clarify which object the player was referencing. The use of a NOT-HERE-OBJECT allowed the game to process the remaining commands and also provide a more specic error message about the missing objects. + +## 13.10 Update: MOBY-FIND + +## Arguments: Address to object table + +## Return: Number of objects found + +I don't know what MOBY[1] means, but MOBY-FIND was rst used in to search for a match between all visible objects (including inside open or transparent objects) in Suspended using P-NAM, P- ADJ, or GWIMBIT. This rst version was used when asking about objects to the Advisory Panel. + +> 1 Jesse MgGrew: I believe MOBY was slang meaning something like "big" (from Moby Dick, the giant whale). + +54 + +It called SEARCH-LIST with SRCALL on all the rooms. If no object was matched, MOBY-FIND would call DO-SL to search all of the LOCAL-GLOBAL objects with the results saved in P-TABLE. The Witness had a more formal version of MOBY-FIND by using the noun and/or object to search from XNAM and XADJ (replace the values in NAM and ADJ). It would sequentially go through every room and nd a matching object to XNAM and/or XADJ using SEARCH-LIST. If no matching objects are found, then MOBY-FIND will use search all LOCAL-GLOBALS with DO-SL with SRCALL level matching. If no match is found again, then MOBY-FIND will search all the rooms again using DO-SL with SRCALL level matching. The returns of DO-SL are saved into P-TABLE. The returned value is the number of objects found at either step. If only one object is matched, its number will be saved into P-MOBY-FOUND for easy recall. + +Sorcerer changed the nal check on the ROOMS object back to SEARCH-LIST. AMFV used a more brute force approach but checking each object in the game sequentially. If the object is a room, it is skipped. Any matched objects are saved in a table with the number of object found returned. Spellbreaker will use a separate routine available on some objects to see if the object should be matched during a MOBY-FIND. If multiple objects match for the given identiers in + +The Lurking Horror will check the GENERIC property of all the matched objects. If the routine address is the same in all the object's GENERIC property, MOBY-FIND will call that routine to decide which object to return as the match. + +Sherlock has special objects that can be searched at times (Holmes) and some that are always available (like local-global objects). + +## 14 Can Many Objects be TAKEn Before Using with TAKE-CHECK and MANY-CHECK + +## 14.1 Introduction + +There are now two nal checks on the verb by PARSER. The rst is to see if the given verb can automatically take objects and act upon them. The second is to see if the given verb can accept multiple objects. Both sets of checks are done on direct (and indirect if present) object clauses. + +- ˆ ITAKE-CHECK (through TAKE-CHECK) + +- ˆ MANY-CHECK + +## 14.2 ITAKE-CHECK (through TAKE-CHECK): Checking TAKE and HAVE bits + +Arguments: Address to object table, LOC byte + +Returns: TRUE if objects do not need to be taken or were taken if necessary, FALSE if errors + +TAKE-CHECK calls ITAKE-CHECK on each set of objects (direct objects from P-PRSO and indirect objects from P-PRSI) with the matching syntax's LOC byte to verify if objects must be in the possession of the WINNER to be used as some verbs require this. So an object in the room but not on the WINNER is not valid. However, any verb syntax entry with a TAKE bit set in the LOC byte is allowed to automatically put any matching object in the room into the WINNER's inventory and then act upon it. PARSER will see if any objects in an object clause that are not in the Winner's inventory can be automatically taken. If the object's TRYTAKEBIT is set, this would prevent PARSER from automatically taking it. For all objects without the TRYTAKEBIT set, PARSER will call the CARRY object routine to move the object into the Winner's routine. + +55 + +14 Can Many Objects be TAKEn Before Using with TAKE-CHECK and MANY-CHECK + +For any objects that can't be automatically taken, it is possible the verb can still use it. However, PARSER rst checks if a HAVE ag is set in the verb syntax entry. This would require the object be in the inventory to use it in the action. If so, then the object cannot be used and an error is displayed. Any error will stop the checking of any remaining objects in the object clause. + +## 14.3 Update: New ITAKE-CHECK + +Starcross introduced a new ITAKE-CHECK which tried to catch situations where objects could not be taken. These included: + +- ˆ Both TAKE and HAVE bits cleared (objects do not need to be held and can't be taken) on syntax + + - if HAVE set, then check objects + + - if HAVE not set and TAKE not set then RTRUE + + - if HAVE not set and TAKE set then check objects (SEe if can be taken) + +- ˆ The WINNER is not the PLAYER + +- ˆ The object is held by the WINNER (using HELD?) + +- ˆ The object is something that can't be taken like pair of hands + +The new routine would also not display error messages in certain situations such as an ACTOR would try to take an object before using it. It also needed to check if the syntax had LOC TAKE set before calling ITAKE to get the object. (at least try) + +Sorcerer checked if the IT-OBJECT was accessible before using it. It also checked to see if the object is held, it would then skip the rest of the routine. For any NOT-HERE-OBJECTs, it would display a specic error message. If an object exists but can't be used, then it would also updated the IT-OBJECT value. + +Seastalker also allowed him and her pronouns to be taken and used. But no checks on their visibility was done until Wishbringer which also added the them pronoun. Later games like Hollywood Hijinx would have specic checks for objects if they inside other objects (such as water inside a bucket). + +More specic error and conrmation messages were created. For example, these would use the appropriate articles depending on the object and quantiers depending on the number of objects. They would also indicate if an ACTOR did not have an object. + +## 14.4 MANY-CHECK + +## Arguments: None + +Returns: TRUE if syntax entry accepts multiple objects, FALSE if not + +Some verb syntax entries allow for multiple direct or indirect objects in their usage, such as GET or IGNITE. PARSER will rst check how many objects are in the direct and indirect object clauses. If there is only 1, then this check is not needed. If there is more than 1 object and the MANY token is not set for that direct object clause in the syntax entry, then an error message is displayed about the verb not being able to use multiple objects. This same check is then done on the indirect objects if necessary. + +Only a few changes were made with this routine. Starting with Zork 1-R75, PARSER would run MANY-CHECK rst before TAKE-CHECK which correct a bug were PARSER would attempt to take multiple requested objects rst but then error out on the verb if it could not process multiple + +56 + +objects. By ipping the order, PARSER can quickly see if multiple objects can be used on an verb before trying to take then using TAKE-CHECK. This is mentioned in the Infocom Cabinet notes. Deadline would assume the verb was tell if it was not given (occurs when the player is telling an actor to do something). Sorcerer ensured that the complete verb was displayed if the current command is the result of a merge. Finally, LGOP added a new parameter to indicate which noun clause to check. This would eliminate the need to check if a particular clause in the matched syntax can accept multiple objects. + +## 15 It's Time to Perform with PERFORM + +## 15.1 Introduction + +At this point, all necessary information should be checked and processed. All the direct and indirect objects and the action number to use those objects have been found. Many combinations of objects and actions can be handled by the specic action routine. The designer of Infocom games understood that many actions on objects could be handled with a generic verb action routine. Any special circumstances usually depend on the objects used. Therefore, these circumstances could be checked when accessing those objects and not clutter up a generic verb action routine. + +## 15.2 Checks and Order + +Since action routines can call PERFORM separately from PARSER to perform functions that mimic a command, PERFORM does not use the global PRSA, PRSO, and PRSI but will be passed a separate action, direct object, and indirect object arguments. It then temporarily saves the current PRSA, PRSO, and PRSI. + +1. PERFORM will check for the IT object in the direct or indirect object. If so, it will be replaced with the previously referenced object for IT. + +2. It will copy all the given arguments (action, direct object, and indirect object values) into the appropriate global variables (PRSA, PRSO, PRSI). + +3. If the given action is not GO, PERFORM will then update the IT object to the just given direct object argument and update the location of the winner to the current location. + +4. If the given action is not AGAIN, PERFORM will update the global variables for the last action number, direct object, and indirect object. These are used by the AGAIN command. + +After updating the necessary variables, PERFORM will call various routines to handle the action on the objects. A non-handled action (by returning M-NOT-HANDLE) will be passed to the next possible routine to handle it. The order of handler preference is below: + +1. WINNER's action routine + +2. WINNER's location's action routine with M-BEG argument + +3. Verb (PRSA) pre-action routine + +4. Indirect object (PRSI) action routine + +5. Direct object (PRSO) action routine (skipping if the action is GO) + +6. Verb (PRSA) action routine + +57 + +15 It's Time to Perform with PERFORM + +ACTION routines for objects and rooms can be passed standard RARG values for a specic type of function to perform. Any needed objects can be found in PRSO and PRSI. The routine will then return an action return value. If the routine can successfully complete a function, then M-HANDLED is return. PERFORM will skip over all other subsequent handlers. If the routine cannot handle a function, M-NOT-HANDLED is returned. PERFORM will then try other handlers to handle the function. The verb action routine is considered the default handle routine and can always handle an action. It usually displays a generic message. Once a function has been handled, the current room's ACTION routine is sent M-END to handle any remaining functions before the turn is completed. If M-FATAL is ever returned by an action, then PERFORM will exit immediately and return M- FATAL. Also, the current room's ACTION routine is not called with M-END. Before PERFORM returns, the previous values of PRSA, PRSO, and PRSI are restored. + +|Room Arguments (RARG)|Action Return Values| +|---|---| +|M-END, 0
M-BEG, 1
M-LOOK, 3
M-FLASH, 4
M-OBJDESC, 5|M-NOT-HANDLED, 0
M-HANDLED, 1
M-FATAL, 2| + + + +Objects trying to handle actions may need to double check which object is the direct and indirect object. In an example from Infocom: + +## TAKE SWORD FROM THE STONE + +would have the STONE object process the TAKE action rst. In that case, the STONE could interpret the user trying to take the STONE. To prevent this, STONE object could see if it is the PRSI before handling the action. + +Later ZIP 3 games also included checking an object's CONTFCN (container function) before having the direct object try to handle the action. This was only called in those rare situations (such as in Starcross) where the direct object's container would try to handle an action. + +## 15.3 THIS-IS-IT + +Starting with Sorcerer, PERFORM calls THIS-IS-IT after acting upon the PRSO and PRSI to update the IT-OBJECT. The PRSO value is stored as the IT-OBJECT value. Planetfall would introduce saving the location of the IT-OBJECT as well in a separate global variable. Wishbringer added other pronouns objects (HIM-OBJECT, HER-OBJECT, and THEM-OBJECT) along with their associated global variables which would be updated if needed based upon the attributes of the PRSO (such as gender or being plural). The routine is also called from other parts of the game like ITAKE-CHECK and specic action routines. It was only used in LGOP, Moonmist, Hollywood Hijinx, Stationfall, and Plundered Hearts. + +58 + +## 16 Pardon the Interruptions + +## 16.1 Introduction + +An interrupt is a special routine that is called after a certain number of turns has lapsed. They can be used to monitor objects and variables in the background. Interrupts will then change other variables and objects or call other routines and actions. Naming of these interrupt routines is done by adding a I- prex to the routine name. The array to hold interrupt entries is a 180 byte (90 word) table where each entry had 3 words: enable ag, number of turns (TICKS), and routine address. This meant the table could only hold 30 entries. Only 3 routines are used to manage this ingenious system: INT to create or retrieve interrupt entries, QUEUE to set the number of turns before the interrupt is called, and CLOCKER which checks all the interrupts and nds those that need to be executed. + +One thing to note is that there is no way to delete or replace an interrupt entry. It can be disabled by clearing the enable ag though. So there is a limited number of total interrupts that can be created. + +## 16.2 Creating and Storing interrupts with INT + +Arguments: Routine address + +Returns: Address to interrupt entry + +INT typically uses the 180 byte interrupt table to manage up to 30 interrupt entries. Some games like Deadline and The Witness use 300 bytes while Cutthroats's table was 246 bytes in size. The table is lled like a stack, from the highest address to the lowest. So the oldest routines are located in the higher address, or the bottom of the table. The pointer to the newest interrupt entry (C-INTS) then moves toward the front of the buer. After a routine address is passed to INT, + +- ˆ The routine address in each entry in the interrupt table is checked (starting with the newest entry) with the requested one until there is a match or no more entries exist (when the pointer to the current entry reaches the end of the table). + +- ˆ If there is a match, then the address to this interrupt entry is returned. + +- ˆ If there is no match, then pointer to the newest entry is moved up (decrease by 6 bytes) and now points to a new blank entry. The requested routine address is stored in the appropriate location in the new entry. The address to this new entry is returned. + +59 + +16 Pardon the Interruptions + +Figure 8: Interrupts + +## 16.3 QUEUE - Setting Up the Interrupts + +Arguments: Routine address, Number of turns + +Returns: Address of interrupt entry + +With the rst generation interrupt routines, QUEUE was a separate routine to set the number of turns, or TICKS. It would call INT to get the address to the interrupt entry for the request routine address (creating the entry if necessary). Then. it would store the number of ticks for that interrupt in the 2nd word value of that entry and return the address to this interrupt entry. The setting of the enable ag was not done and have to be done using a separate STORE command. The last few ZIP 3 games (Stationfall and The Lurking Horror) and most EZIP games (all except AMFV) and all XZIP games did not use QUEUE. INT would automatically queue those entries or the games would do it without a separate routine. + +## - 16.4 CLOCKER Running Interrupts + +## Arguments: None + +Returns: TRUE if an interrupt was executed, FALSE if no interrupt was executed + +60 + +16.5 What about DEMONs? + +CLOCKER is the main routine that checks each interrupt entry and decreases the number of turns for any enabled entry. It will call the routine at the address stored in any interrupt entry with only 1 TICK left or -1 TICKS which indicates the entry will always be executed. CLOCKER is always called at the end of the MAIN-LOOP. + +- ˆ If the given command was valid, CLOCKER will search through the interrupt table for entries with their enable ag set and extract the number of turns left. + + - The search begins with the newest interrupt entry and proceeds to the oldest entry. + +- ˆ If the TICKS is zero, CLOCKER goes to the next entry. + +- ˆ If the TICKS is not zero (a negative, 1, or greater than 1) then it will be decreased by 1 and saved back into the entry. + +- ˆ If the TICKS is still greater than 1, then CLOCKER will then go to the next entry. + +- ˆ At this point, CLOCKER will call the routine at the addr stored in the interrupt entry. TICKS will be 1 or a negative number at this point. + +If no routine is called, CLOCKER will return FALSE. Otherwise, it will return TRUE no matter how many routines are called. The actual return value of the routine is not returned. + +## 16.5 What about DEMONs? + +INT allowed an initially set of interrupts to be added to the interrupt table that are always checked regardless of the PARSER outcome. This is marked by by the C-DEMONS pointer which moves from the end of the interrupt table when new entries are created with the DEMON ag set. C-INTS also moves when an entry is added when the DEMON ag is set. In game design, these important interrupts are added rst and end up at the bottom of the interrupt table. All other interrupts but be added above these entries. If PARSER fails on a given command, CLOCKER will this and start checking the interrupts starting with C-DEMON and not C-INT. + +Zork 1's rst use of these special, all-run, interrupts were used for the demons and monsters in the game. This term is very similar to daemons in operating systems where background processes can run on their own. However, Infocom's use of the word demon came after daemon was already used by other programmers. It is probably just a happy coincidence. + +## 16.6 Update: New INT and Interrupt Entry + +All of the ZIP 1 and 2 games and most of the ZIP 3 games use the same INT routine as seen in Zork 1. Cutthroats, HGTG, and Suspect used a slightly modied INT where DEMON pointer is omitted. The rst major change was with AMFV where the size of the interrupt entry shrank to 2 words by removing the ENABLE ag. Now, each entry with non-zero TICKS is considered enabled. Most of the ZIP 3 games since LGOP also used this more compact interrupt entry structure. AMFV's version also kept track of the most recent blank entry which would be used when storing a new entry instead of creating a new one. If new entry needs to be created beyond the limits of the table, an error message is displayed but the entry is still created. + +LGOP also introduced a smarter INT routine that build o the one from AMFV. It would remove any entries at the top of the table with no more TICKS left by moving C-INT and skipping over these completed entries. Any entries with no more TICKS surrounded by entries that were still enable were not removed. This smarter INT also modied how interrupts during the game initialization are stored. It would convert their TICK numbers (by increasing it by 3 and making it negative) to label these interrupts so they would not be called until CLOCKER had already been executed. So, the + +61 + +16 Pardon the Interruptions + +rst call of CLOCKER would convert these entries back to normal entries (converting the TICKS back to positive values and subtracting 3) and then be checked on the next call to CLOCKER. So, these initial interrupts would be bypassed at the start. + +Only a few subsequent Infocom games modied their INT routines beyond what was mentioned. A few added special ag checks that would quit out of INT. Borderzone and Sherlock both used time more than ticks and had modied INT routines to reect that. + +## 16.7 Update: New CLOCKER + +CLOCKER also went through multiple modications over successive games. The ZIP 2 version added the CLOCK-WAIT ag which skips checking any interrupts (including DEMON ones) when set and is cleared. This feature is only important for the WAIT command which already calls CLOCKER 3 times by default. Without this ag, the MAIN-LOOP will also call CLOCKER after WAIT is completed. So there would be 4 calls to CLOCKER for a WAIT command which is seen in ZIP 1. So the ag helps clear up that confusion. + +Some CLOCKER routines (like in Deadline, Trinity, Bureaucracy, Borderzone, and Sherlock) would also increment separate time variables (seconds, minutes, hours, and possibly days) that the game would use for various situations. These routines (like in Deadline and Moonmist) check the number of turns or the elapsed time to see if the game should end prematurely or reset specic counters. Others like Wishbringer would check specic ags that would cause CLOCKER to execute routines of specic entries if their TICK values were below a certain threshold. Later versions (Suspended, Indel, Enchanter, Zork 1, Zork 2, Sorcerer, Moonmist, Ballyhoo, Mini-Zork) increase the number of turns in CLOCKER instead of MAIN-LOOP. The Witness, Seastalker, and Cutthroats return the rst non-zero interrupt routine result. However, if one of the routine returns M-FATAL, then that will always be returned. Planetfall corrected one logic error in the original INT routine regarding entries with negative TICKS. Previously, any entry with a negative TICK value would have its routine execute with the TICK value decreasing as well. So subsequent calls to this entry would make the TICK value more negative. Theoretically, that value could then ip into the positive range because of the way negative numbers are represented. Hexidecimal values of $0001 to $7FFF are positive (1 to 32767) while $8000 to $FFFF are negative (-32768 to -1). If a TICK value of $8000 (-32768) is decreased by 1 again, the new value $7FFF now is 32767 and will not be executed on the next CLOCKER cycle. Planetfall added a specic check for the $FFFF (-1) TICK value which would still execute the routine at the entry's address but would not decrease the TICK value. + +As mentioned before, AMFV uses the shortened 2 word entry. Its CLOCKER also will clear out the routine address of any entry that also has zero TICKS. This allows INT to use these blank entries for new entries. LGOP's CLOCKER had the ability to delete entries that were at the top of the interrupt table. It would lower the starting point of the interrupt table to just past any blank or recently completed entries. If any blank or completed entries were below a still enabled entry, they could not be deleted. Stationfall and Sherlock could decreased TICKS/time value by a dierent amount for all entries with each call of CLOCKER. This allowed parts of the game to cause interrupts to be executed soon than expected as each call of CLOCKER will more rapidly drop the TICK counts. + +HGTG still has the PARSER valid check to decide which pointer to use. If the PARSER fails, the entire table is checked (#00 as pointer) instead of from the newest entry. + +## 16.8 Removing Interrupts with DEQUEUE + +Arguments: Routine address + +Return: TRUE if successful, FALSE if unable to nd interrupt + +62 + +16.9 New Predicates for the Interrupts + +DEQUEUE was introduced in LGOP and clears the routine address of the entry with that address. Any dequeued entry would eventually be removed by CLOCKER. + +## 16.9 New Predicates for the Interrupts + +ENABLED? + +Arguments: Routine address + +Return: TRUE if matching interrupt is enabled, FALSE if no match found or interrupt is not enabled RUNNING? + +Arguments: Routine address + +- Return: TRUE if matching interrupt has at least 1 TICK left, FALSE if no TICKS left or no match found + +Two new predicates were added, ENABLED? And RUNNING? in Cutthroats to help nd the status of specic interrupts. ENABLED? returned TRUE if the ENABLED word in a matching interrupt entry was set. RUNNING? returned TRUE if the TICKS in a matching entry was not zero, including -1. In LGOP, ENABLED? was changed as no ENABLED word exists in its entries. It would check the TICKS value and return TRUE if it was non-zero including -1. LGOP's version of RUNNING? would return TRUE if the matching entry's TICK value was 1 or -1. So only entries that will be executed on the next call of CLOCKER are considered running. + +## 17 Basic Screen Output and TELL + +## 17.1 Introduction + +Infocom strived for readability, natural feel, and varied responses of its games with its text routines. The games tried to be grammatically correct with display articles before nouns and using plural forms if necessary. Later games would ne tune these routines even more. Infocom did use programming macros for creating the proper text display routines. These macros would then be expanded into the proper ZIL code during compiling. It is dicult to gure out which was the rst game to use this without the source code. The macros are seen in the Mini-Zork source code. + +## 17.2 Abbreviations / Frequent words table + +Starting with ZIP version 2, Infocom games used abbreviations to help reduce the space taken up by text. In version 2, the ZSCII character $01 signaled an abbreviation is to be display.The next ZSCII character indicates the requested abbreviation. This allows for 32 abbreviations. The abbreviation ZSCII character is consistent throughout the 3 character sets. The previous new-line control character (ZSCII 1) was moved to ZSCII 7 in character set 2. + +To allow for more abbreviations, ZIP versions 3 and higher also use characters $02 and $03 to signal an abbreviation. Since each of these special control characters can access 32 abbreviations, these games could have 96 abbreviation, calculated using the formation: (abbreviation character value - 1) * 32 + next character's ZSCII value. This also left only 2 control characters (ZSCII 4 and 5) remain to change the character set. Those control characters were repurposed to change the character set for next character only. There would be no shift lock. + +An abbreviation table contains 32 (or 96 for versions 3 or higher) word addresses for the Z-strings. The abbreviation and next characters will then point to an entry in this abbreviation table with an address to a Z-string which will then be displayed. Because each abbreviation uses 2 characters, abbreviations for string longer than 2 characters could help reduce the size of the story le. + +63 + +17 Basic Screen Output and TELL + +## 17.3 Special PRINT Routines - WORD-PRINT, CLAUSE-PRINT, PREP-PRINT + +- Zork 1 also included three print routines that work with the given command and prepositions: + + - ˆ WORD-PRINT + + - ˆ PREP-PRINT + + - ˆ CLAUSE-PRINT + +WORD-PRINT displays a sequence of characters from INBUF given the starting character and number of characters to print. + +PREP-PRINT displays the preposition given the preposition byte number,. The routine uses PREPFIND to convert the preposition byte number to a Vocabulary address for the preposition. The only except is through which is larger than the 6 character limit for ZIP 3 or earlier. PREP-PRINT looks for the corresponding preposition number and just display the entire token. + +CLAUSE-PRINT display the entire noun clause using the boundary addresses stored in ITBL. A preceding preposition can also be displayed if the preposition number is also passed as an argument. The boundary addresses to use are based upon the element numbers in ITBL. Displaying the token from Vocabulary or from INBUF depends on state of O-FLAG. The routine will use strings from the Vocabulary (maximum of 6 characters) if the O-FLAG is set. Otherwise, it will use WORD-PRINT to print the entire token from INBUF. + +display the tokens in LEXV given by the start and end address of the requested noun clause. This limited any token to 6 characters. If the O-FLAG was clear, the routine extracted the length and location of each token in INBUF and displayed the complete token. + +## 17.4 New versions PRINT routines + +Deadline introduced several 4 new routines and updated CLAUSE-PRINT to improve the quality of the displayed text. + +BUFFER-PRINT is a new routine that displays a sequence of tokens while modifying any truncated or referred tokens. For example, the mrs token will then be displayed as mrs. while the it token is replaced with its referring object. The address of the starting token and token after the last one to display are passed to the routine. The fourth argument is a boolean value to indicate print a preceding space before the rst and subsequent tokens. + +PRSO-PRINT and PRSI-PRINT are new routines that will display the direct or indirect object clause, respectively. They extract the starting and ending addresses of the clause from ITBL and see if the rst token in the clause is it. If so, the current PRSO is displayed. Otherwise, these addresses are passed to BUFFER-PRINT. + +The last new routine display a token with the rst letter capitalized. No ocial name is known but could be called CAPITALIZE-PRINT. The routine pulls the rst character and converts it to uppercase without checking the case rst. Then it will use WORD-PRINT to display the remaining part of the token. + +The new CLAUSE-PRINT utilizes BUFFER-PRINT to display those representative tokens with their proper names. The routine will take the start and end element numbers from ITBL and extracts the start and end addresses for the tokens to print. These are then sent to BUFFER-PRINT. + +Enchanter would later introduce THING-PRINT which takes a boolean argument to choose which object clause to use (true for direct, false for indirect). The routine pulls the start and end addresses for the requested object clause and passes it to BUFFER-PRINT. + +64 + +17.5 Error message routines + +## 17.5 Error message routines + +All Infocom games have several default error messages when handling errors with given commands. + +- ˆ CANT-USE + +- ˆ CANT-ORPHAN + +- ˆ UNKNOWN-WORD + +CANT-USE was rst used in Deadline and would insert an invalid token into the phrase: The word `' can't be used in that sense. + +CANT-OPRHAN was added in Starcross and had the static message: That command was incomplete. Why don't you try again? + +UNKNOWN-WORD would display the word that is not found in Vocabulary: + +[I don 't know the word "" in a way that I don 't understand .] + +and also updates the OOPS-TABLE with the location of the token that is unrecognized. + +## 17.6 Using the TELL Macro + +Source code for Infocom games used macros where a specic keyword and associated data would be replaced with code incorporating that extra data. TELL was the universal way of displaying text. However, this could result in repetitive code to display the same kind of text. So, later design guides for Infocom games describes the use of the TELL macro with multiple modiers. But, the macros would not be replaced with strings of ZIL code but a call to separate routines for displaying text with any additional modiers such as proper denite and indenite articles (depending on the type and number of the object) or ending periods and linefeeds. Learning ZIL describes these modiers. + +## - 18 The Describers For Rooms and Objects + +## 18.1 Introduction + +There are several routines in an Infocom games that specialize in describing locations and objects which are an essential part of any game. Learning ZIL mentions DESCRIBE-ROOM and DESCRIBE-OBJECTS, but there are also DESCRIBE-OBJECT, PRINT-CONT, and later PRINTCONTENTS which complete the needed routines to display an object and its contents. For example, LOOK would call DESCRIBE-ROOM and DESCRIBE-OBJECTS with the verbose argument set. Other commands, like INVENTORY or LOOK-INSIDE, would call PRINT-CONT on the WINNER or PRSO, respectively. + +## 18.2 PRINT-CONT + +Arguments: Object or Room number, Verbose ag, LEVEL number + +Returns: TRUE if there is some descriptive output, FALSE if none given + +PRINT-CONT will describe the contents of the objects contained in the given object or room. The routine will rst describe each object by display the string in the FDESC (First DESCription) property of the object. Any object that also can be seen inside (using SEE-INSIDE? predicate) will have PRINT-CONT recursively called on it. If the routine is being used to display the inventory of the WINNER's possession, it will skip the display of the FDESC's of all the objects. PRINTCONT will then see if a special header (such as You are carrying: or The contains: ) + +65 + +18 The Describers - For Rooms and Objects + +needs to be displayed by seeing. This is done when an inventory is requested or the objects have already been touched. This also needs to be the rst text displayed for that particular routine call. PRINT-CONT will then call DESCRIBE-OBJECT on each object to have it described. If any of these objects are an integral part of another object, then PRINT-CONT is called recursively on this integral object to see if anything else can be described. Once all the objects are checked again, PRINT-CONT will also see if the WINNER is in a vehicle and if that vehicle is part of the contents of the original requested object. If so, then PRINT-CONT will be called on that vehicle. While a verbose ag argument can be passed, it is never used. The LEVEL argument determines the indent of the descriptive text uses spaces from the IDENTS table (maximum of 5). As the routine does further recursion, the level number increases along with the corresponding indent. + +## 18.3 DESCRIBE-OBJECT + +Arguments: Object or Room number, Verbose ag, LEVEL number + +Returns: TRUE if extra descriptive output given from internal objects, FALSE if none given + +DESCRIBE-OBJECT will try to display a descriptive text about an object using the FDESC (if the object is untouched) or LDESC. If neither is available, a generic description is given, There is a for level 0 or A for all other levels. If the WINNER is also in a vehicle, then a clarifying (in the room) is given to remind the WINNER that the object is NOT in the vehicle. Also any objects that have visible contents will be also called with PRINT-CONT to display the contents of that object. Againa, the Verbose ag is not used in the routine but passed to PRINT-CONT if it is called. + +## 18.4 DESCRIBE-OBJECTS + +Arguments: Verbose ag + +Returns: TRUE if there is some descriptive output, FALSE if none given + +DESCRIBE-OBJECTS will try to display a descriptive text for all the objects in the current location (HERE). It will not display a description of the location itself. If that location is not lit, the routine will return with the error message I can't see anything in the dark. If any objects do exist in the current location, DESCRIBE-OBJECTS will call PRINT-CONT with this location and the current VERBOSE level if one is not given. Return values are the same as PRINT-CONT. + +## 18.5 DESCRIBE-ROOM + +Arguments: TRUE (if called by LOOK action) + +Returns: TRUE if room description given, FALSE if too dark to give description + +DESCRIBE-ROOM will initially check if the room is dark, displaying a too-dark error message if it is. The routine will then display the room name and decide if a further descriptions should be given. If it was not called by a LOOK command or SUPERBRIEF is SET, then no further description is given. If the WINNER is in a vehicle which is also in the room, the routine will indicate that with the clarifying (You are in the .). DESCRIBE-ROOM will then check if the Verbose ag is set, or the room is untouched. Either situation would have the routine try to call the room's ACTION routine with M-LOOK to provide a description. If this fails, the room's LDESC string will be used if possible. If a room is untouched, then that room's TOUCHBIT will be set. + +66 + +18.6 PRINT-CONTENTS + +## 18.6 PRINT-CONTENTS + +Arguments: Object number + +Returns: TRUE + +PRINT-CONTENTS was added with Sorcerer-R6 to quickly display a list of objects in a room or container. The object names would be separated by commas and and, if necessary. If only one object was listed, then IT-OBJECT would be updated with that object. + +## 18.7 Update: DESCRIBE-ROOM + +Zork 2 added a new RARG (M-FLASH or $04) on a room's ACTION routine even if verbose is clear (minimal output). This allows a room to display important information even if the room was already touched or verbose is clear. It also added a nal call to the WINNER's vehicle's ACTION with M-LOOK (if in a vehicle) when describing the current location. + +## 19 Common Routines and Predicates + +## 19.1 Introduction + +Numerous routines are found in most or all Infocom games and provide important functions that are not specic to a certain game or action. Predicates are a special type of routines that return true or false based upon the given arguments. Learning ZIL does give numerous examples. No systematic search has been made to nd all of these special routines found in all Infocom games. The known ones can be divided into four main categories: + +- ˆ Tables + +- ˆ Objects + +- ˆ Game States + +- ˆ Movements + +## 19.2 Table Routines and Predicates + +There are three common table routines used in Infocom games since Zork 1: + +- ˆ ZMEMQB (byte, address to table) + +- ˆ ZMEMQ (word, address to table, last element to check, rst element to check) + +- ˆ PICK-ONE (address to table) + +ZMEMQB searches for a given byte in a table of bytes. The interested byte and table are passed as arguments. After getting the number of items in the table, the routine will step through each byte. If the given byte is found, it returns true. Otherwise, it will return false. + +ZMEMQ is similar to ZMEMQ but searches for a specic word in a table of word up to the last element indicated. It also accepts one additional argument: rst element number to check. If this argument is not gien, then it will use the beginning of the table. For example: + +ZMEMQ (0x3EA0 , TBL , 6, 2) + +67 + +19 Common Routines and Predicates + +would search for the word 0x3EA0 in a table of words starting with elements 2 through 6. PICK-ONE, the original version, uses a table of words where one of these elements is randomly picked and returned. The new PICK-ONE keeps track of what elements have already been picked and will not pick them again until all the others have been picked. This is accomplished by sorting the table of elements. Any picked word is swapped with the rst unpicked word. When only 0 unpicked words remain, the number of picked elements is reset which causes the entire process to be repeated. It is quite ingenious. + +1. Get total number entries (0th word) and number of previously picked string address (1st word) of string address in the table + +2. Decrease total number of entries by 1 as one of the entries is the number of picked string addresses + +3. Calculate the address of the rst unpicked string address and number of unpicked string addresses + +4. Random pick a number with maximum number being the number of unpicked string addresses + +5. Get the string address at that random location + +6. Swap that string address with the one located in the rst original unpicked string addresses group + +7. Update the number of picked items (1st word in the table) + +8. If all the items have been picked (number of picked items equal total number of available address), then reset this value to zero. + +The picked word is then returned. Some games use both PICK-ONE returns as dierent situations can demand dierent versions of the routine. + +## 19.3 Object Predicates + +As for the predicates, these will see if a given object can be interacted with in specic ways. + +- ˆ LIT? + +- ˆ HELD? + +- ˆ SEE-INSIDE? + +- ˆ ACCESSIBLE? + +- ˆ VISIBLE? + +- ˆ UNTOUCHABLE? + +- ˆ GLOBAL-IN? + +- ˆ TOUCHING? (not used) + +68 + +19.3 Object Predicates + +LIT? is the main predicate in Zork 1. It checks if the WINNER can see around in a given location by looking at the ONBIT attribute. If the ONBIT is clear (location is dark), the routine will do a secondary check if the given location is the same as the WINNER's location. The secondary check will look for any objects in the given location. If any are found, then the location is considered lit and the routine will return TRUE. + +HELD? is also in Zork 1 and checks the location of the given object's location. If it is not the WINNER, this location replaces the given object and the routine loops back to get the new location of the just found location. This continues until the location is the WINNER (return TRUE) or the location of the object is blank (return FALSE). Other versions such as in Zork 3 uses a recursive method to nd the ultimate location of an object and also look for the ROOMS and GLOBAL objects which result in a false response. HGTG introduced a second argument which was a room or object. This would be used instead of the WINNER to determine if the given object was ultimately located in it. If no second argument was given, the routine would check if the given object was inside the WINNER. + +SEE-INSIDE? checks for specic attributes on a given object to see if its contents are visible. This applies to containers such as a box or a surface object like a table where objects can be placed on it. The routine was rst used with Sorcerer and checked three attributes: INVISIBLE, OPEN, and TRANSPARENT. The contents of an invisible object cannot be seen. An object that is open or transparent can have its content seen from the outside. Wishbringer added an initial check to see if the object is a surface which always leads to a true response. If object was not a surface, open, or transparent, the routine would check if the object is an Actor and not the WINNER. Objects contained in an actor are always visible. Hollywood Hijinx would check if the given object was a container. If it is false, then the routine jumps to the section to check if the given object is an Actor. + +ACCESSIBLE? was rst introduced in Zork 3 and checks if the given object can be used. There are objects that are visible but cannot be used (an object inside a closed and transparent container). It would return true if the given object was present in the current location or is one of the game's GLOBAL objects. + +VISIBLE? was also introduced in Sorcerer and sees if the given object can be used or seen by the WINNER. The routine checks if the given object is accessible using the ACCESSIBLE? predicate. If that is false, the routine checks if the WINNER can see inside the given object's location (for example if it is in a clear box) by using SEE-INSIDE? If that is true, the routine will then recursively call VISIBLE? with the object's location. Wishbringer used a slightly dierent approach with checking to see if the object was invisible rst. If not, the location of the object is found with META-LOC (a room or GLOBAL object). If it is on the WINNER, in the current room, or a GLOBAL object, then it is considered visible. If the object is located somewhere else, the routine calls ACCESSIBLE? to see if it is accessible. If so, then consider it visible. Sherlock only uses a single modied ACCESSIBLE? command that also calls a modied SEE-INSIDE? routine. So this mimics the original form. + +UNTOUCHABLE? is a curious predicate that seems to be only used in LGOP to screen for various special situations where objects are in the same room but cannot be touched. For example, an object inside of inside of a cage that is also in the room with the WINNER is considered untouchable. If the given object is in the current location, held by the WINNER, or contained inside the WINNER, then it would return FALSE (ie. it is touchable). + +GLOBAL-IN? is a simple predicate that takes two arguments, an object and location, and checks if the object is a local-global for that location. Essentially, the routine uses the ZMEMQB or SCAN_TABLE opcode to look for the given object in the GLOBAL property of the location. + +TOUCHING? is described in Learning ZIL as a predicate that takes an object and sees if it needs to be touched to perform the current action, PRSA. There is no evidence in any released game of a separate predicate that performs this function. Many action routines do a similar type of check, however. + +69 + +19 Common Routines and Predicates + +## 19.4 Object Routines + +The most common set of routines relate to objects. These include routines and predicates. The routines return specic values: + +- ˆ ROB + +- ˆ WEIGHT + +- ˆ META-LOC + +- ˆ FIND-IN + +Another routine CCOUNT (container count) and REMOVE-CAREFULLY are described in MiniZork too. + +ROB moves all the objects from one location (room or container) to another or empty destination. It will step through each object in one location and insert into another (or null) and then move to the next sibling object. + +WEIGHT will add up the weights of all the objects in an object. This could be the PLAYER or a container. The routine goes through each child object in the given object. If the child object is a container, WEIGHT is called recursively on that child object. For each object, the weight property is read and added to the total for that object and returned. This routine is useful to see if the PLAYER or container cannot hold any more objects. The default weight for an object is set as one of the default property values for the object table. + +Starting with Zork 1, META-LOC would originally nd the room that an object is located. If the object was on the PLAYER or non-existent, it would return false. Starcross used dierent coding and also add defaulted to the Bridge for any non-attached object. The Witness expanded the return values to also LOCAL-GLOBALS and GLOBALS objects. + +FIND-IN will try to nd an object in the given location with the given ag number set. It will return the rst object found. If no object exists with that given ag set, FALSE is returned. Learning ZIL does mention that if more than one object has the given ag set, FIND-IN would also return false. However, there are no examples of a routine that keeps track of how many matches were found. All routines will exit after nding that rst match. Some of the later games also except a string with the other arguments. This string will be displayed with the matched object name. + +Two other routines in Mini-Zork are not documented by Learning ZIL. CCOUNT will count the number of objects in the given location. It will not count any objects inside containers. REMOVECAREFULLY removes the given object unless it is given which clears out the IT-OBJECT variable. The routine then calls NOW-DARK?. + +## 19.5 Game State Routines and Predicates + +Various routine will interact or change the dierent states in the game such as if the player is dead or reset the status line. + +- ˆ JIGS-UP (string) + +- ˆ INIT-STATUS-LINE (boolean ClearScreen?) + +- ˆ UPDATE-STATUS-LINE + +- ˆ NOW-DARK? + +- ˆ NOW-LIT? + +- ˆ VERB? + +70 + +19.6 Movement Routines + +## ˆ GAME-VERB? + +JIGS-UP is in every game in some fashion. It is called when the PLAYER is killed or the game is over. After the nal score is displayed, a string is passed to it wish is displayed along with all the possible choices for the PLAYER to proceed such as restart the game or quit. If the game is restarted, the opcode RESTART is executed which will restart the interpreter and start execution with the GO routine. + +The status line routines, INIT-STATUS-LINE and UPDATE-STATUS-LINE, are described in Learning ZILas a common routine, but only Sherlock seems to use it. Usually, the status line updates are handled by the routine for the READ opcode and is part of the Z-machine interpreter. + +NOW-DARK? and NOW-LIT? are routines and not predicates. No arguments are passed to them. LGOP appears to be the rst game that used these. However, there is little evidence that subsequent games incorporated this routine. NOW-DARK? sees if the current location is lit. If so, then it will clear the LIT global variable and provide a warning message. NOW-LIT? is the exact opposite except it will also call the V-LOOK routine after setting LIT. + +VERB? is a predicate that returns TRUE if PRSA is equal to any of the given verbs in the predicate arguments. This does not actually call a routine but is expanded into a set of multiple commands based upon how many verbs are given. + +GAME-VERB? is a simple predicate that checks if the current PRSA is one of the game verbs or a verb that does not trigger the CLOCKER routine. While Learning ZIL mentions a GAME-VERB list, it is unclear if this is a global list in ZIL or hard coded into the routine. + +## 19.6 Movement Routines + +Since moving the PLAYER or actors is a very common action, Infocom games use three common routines to perform it: + +- ˆ GOTO (room number) + +- ˆ DO-WALK (direction) + +- ˆ OTHER-SIDE + +GOTO essentially moves the user to the requested location while still calling the destinations action routine with M-ENTER and getting a description. It does not check if the actor or WINNER is able to directly get to the location. Some people consider it like teleporting into a location. + +DO-WALK is similar to GOTO but it uses PERFORM which performs all necessary checks (unlike GOTO). DO-WALK sets the direction of movement (P-WALK-DIR) and calls the V-WALK using PERFORM with that DIR. + +OTHER-SIDE is given an object number of a door and returns the room number on the opposite side of the rst door in the room. The routine steps through all the exit properties (highest to lowest) of the given room until it nds a door object (the property will be 5 bytes long). It the door object for that property matches the given door object, it will then return the room number associated with that exit. + +71 + +Appendix A: Story Headers + +## - 20 Conclusion The End + +The creativity in designing the original ZORK on PDP main frame computer can be almost directly seen in the microprocessor version of all Infocom games. The structuring of rooms and objects, storing grammatical information, and the innovative parser led to a surprisingly complex and interactive game that could t on a oppy disk. The use of a virtual Z-machine was the rst known use of a virtualization in a home computer as well. A present day interactive ction creator can now design their own games without having to start from scratch. But an ambitious programmer today can now use these essential data structures and routines to create their own fairly complex IF system if they want. While better game engines with more powerful parser and complex games already exist, the sophistication of these early text adventure games in just about 60K of memory is a testament to all of the programmers' skill with ZIL and the eciency of Z-code. Hopefully, the information here has helped cracked the inner workings of these legendary games and made them more enjoyable and appreciated decades later. + +## Appendix A: Story Headers + +## Header Layout + +## Original header layout found in all ZIP versions + +|Word No.|Name|Function| +|---|---|---| +|00|ZVERSION|Byte 0: Z-machine version
Byte 1: Z-machine mode2| +|01|ZORKID|Release number| +|02|ENDLOD|End address of pre-loaded memory (code and data),
Base of High Memory (start of non-preloaded data)| +|03|START|Address of rst instruction (not routine), Program Counter| +|04|VOCAB|Address to Vocabulary table| +|05|OBJECT|Object data address| +|06|GLOBALS|Address to Global Variable table| +|07|PURBOT|Start address of read-only (static) memory, code and data| +|08|FLAGS|Flags, 16 bits| + + + +## ZIP version 2 added the abbreviation information + +|09-0B|SERIAL|Bytes 12 to 17: Serial Number in ASCII characters (words also
labeled as SERIAL, SERI1, and SERI2)| +|---|---|---| +|0C|FWORDS|Address to Frequently used words (Abbreviation) table| + + + +## ZIP version 3 added game information + +|0D|PLENTH|Length of game le (shifted??)| +|---|---|---| +|0E|PCHKSM|Checksum of game le| + + + +> 2Z-machine mode is described but never used (bit ags) + +72 + +EZIP version extended story header layout + +|0F|INTWRD|Byte 1E: INTID/Interpreter number
Byte 1F: INTVR/version| +|---|---|---| +|10|SCRWRD3|Byte 20: SCRV, Screen size in lines ($FF = printing terminal)
Byte 21: SCRH, Screen width in characters| + + + +## XZIP also extended story header layout + +|11|HWRD|Screen horizontal size of display in pixels| +|---|---|---| +|12|VWRD|Screen vertical size of display in pixels| +|13|FWRD|Byte 26: Font height
Byte 27: Font width| +|14|LMRG|Screen left margin in pixels| +|15|RMRG|Screen right margin in pixels| +|16|CLRWRD|Byte 2C: Background color
Byte 2D: Foreground color| +|17|TCHARS|Pointer to table of terminating characters| +|18|CRCNT|Counter for carriage returns| +|19|CRFUNC|Function for carriage returns| +|1A|CHRSET|Pointer to character set table| +|1B|EXTAB|Pointer to extension table, if needed| +|1C-1F|USRNM|Bytes 38 to 3F: Username in ASCII characters| + + + +## MODE Byte + +The MODE byte is the the second byte in the ZVERSION word of the story header. No bits are used in the Zork 1 and 2 games released by Infocom. Bits 0-1 are set by the ZAP assembler while bits 3 through 6 are set by the ZIP on startup. + +## Mode bits for ZIP version 3 + +|Bit No.|Bit Name|Function| +|---|---|---| +|0|byte-swap|0 = high order byte rst, 1 = low order byte rst| +|1|status line format|0 = score/turns, 1 = hours:minutes| +|2|machine-specic function|Story le split across two discs???| +|3|Tandy bit|0 = non-Tandy, 1 = Tandy (to censor some
informatino)| +|4|status line existence|0 = present, 1 = hiding| +|5|splitability|0 = split screen functions ignored, 1 = split
screen functions available| +|6|reserved|Default font is a Variable-width font???| +|7|reserved|????| + + + +> 3This word is set by the ZIP at startup. + +73 + +Appendix A: Story Headers + +## Mode bits for EZIP (ZIP version 4) + +|Bit No.|EZIP Bit Name|Function| +|---|---|---| +|0|ESPLIT (screen operations)|SPLIT/SCREEN/CLEAR functions| +|1|EHINV (highlight inverse)|Inverse highlight is not available| +|2|EHBLD (highlight bold)|Bold highlight is not available| +|3|EHUND (highlight
underline-italics)|Underline-italic highlight not available| +|4|ECURS (cursor addressing)|CURSET/CURGET ignored| +|5|ESOUN (SOUND opcode)|SOUND opcode is ignored| +|6||Reserved| +|7||Reserved| + + + +0 = not available/ignored, 1 = available + +## Mode bits for XZIP (ZIP version 5) + +|Bit No.|Bit Name|Function| +|---|---|---| +|0|XCOLOR|COLOR operations| +|1|XDISP|DISPLAY (show images) operation| +|2|XBOLD|Bold| +|3|XUNDE|Italic/underline| +|4|XMONO|Monospace style font| +|5|XSOUN|SOUND| +|6||Reserved| +|7||Reserved| + + + +0 = not available/ignored, 1 = available + +## Extension table + +|MSLOCX|word 1|| +|---|---|---| +|MSLOCY|word 2|| +|MSETBL|word 3|writable| +|MSEDIR|word 4|writable| +|MSEINV|word 5|writable| +|MSEVRB|word 6|writable| +|MSEWRD|word 7|writable| +|BUTTON|word 8|writable| +|JOYSTICK|word 9|writable| +|BSTAT|word 10|writable| +|JSTAT|word 11|writable| + + + +74 + +## FLAGS Bits + +## FLAGS bits for ZIP + +|Bit No.|Versions|Bit Name|Function| +|---|---|---|---| +|0|1-5|FSCRI|Interpreter currently transcripting| +|1|3-4|FFIXE|Fixed-width font needed| +|2|4-5|FSTAT|Refresh Status Line (by interpreter)| +|3|5|FDISP|DISPLAY (show images) available| +|4|5|FUNDO|UNDO available| +|5|5|FMOUS|MOUSE available| +|6|5|FCOLO|COLOR available| +|7-15|1-5||Reserved| + + + +From E- and X-ZIP - Internal Infocom document + +## Appendix B: Attributes and Properties From Learning ZIL Object Attributes (through YZIP) + +TAKEBIT One of the most basic bits, this means that the player can pick up and carry the object. TRYTAKEBIT This bit tells the parser not to let the player implicitly take an object + +- ˆ This is important if the object has a value and must be scored, or if the object has an NDESCBIT which must be cleared, or if you want taking the object to set a ag or queue a routine, or... + +CONTBIT The object is a container; things can be put inside it, it can be opened and closed, etc. + +- DOORBIT The object is a door and various routines, such as V-OPEN, should treat it as such. OPENBIT The object is a door or container, and is open. + +- SURFACEBIT The object is a surface, such as a table, desk, countertop, etc. + + - ˆ Any object with the surfacebit should also have the CONTBIT (since you can put things on the surface) and the OPENBIT (since you can't close a countertop as you can a box). + +- LOCKEDBIT Tells routines like V-OPEN that an object or door is locked and can't be opened without proper equipment. + +WEARBIT The object can be wearable, not that it is actually being worn. + +WORNBIT This means that a wearable object is currently being worn. + +- READBIT The object is readable. Any object with a TEXT property should have the READBIT. + +- LIGHTBIT The object is capable of being turned on and o. Doesn't mean that the object is actually on. + +- ONBIT For room, it is lit. Outdoor rooms should have ONBIT if daytime. For objects, it is providing light. An object with the ONBIT should also have the LIGHTBIT. + +75 + +Appendix B: Attributes and Properties From Learning ZIL + +FLAMEBIT This means that the object is a source of re. + + - ˆ Object should also have the ONBIT and the LIGHTBIT + +- BURNBIT The object is burnable. + +- TRANSBIT The object is transparent; objects inside it can be seen even if it is closed. + +NDESCBIT The object shouldn't be described by the describers. + + - ˆ This usually means that someone else, such as the room description, is describing the object. Any takeable object, once taken, should have its NDESCBIT cleared. + +- INVISIBLE Tells the parser not to nd this object. The intention is to clear the invisible at some point. + +- TOUCHBIT For rooms, player has been to the room at least once. For objects, it has been taken or otherwise disturbed by the player + + - ˆ Once the TOUCHBIT is set, if it has an FDESC, that FDESC will no longer be used + +- SEARCHBIT Tells the parser to look as deeply into a container as it can in order to nd the referenced object. + + - ˆ Without the SEARCHBIT, the parser will only look down one level. + + - ˆ Objects with a SURFACEBIT essentially function as objets with a SEARCHBIT + +- VEHBIT This means that the object is a vehicle, and can be entered or boarded by the player. + + - ˆ All objects with the VEHBIT should usually have the CONTBIT and the OPENBIT. + +- PERSONBIT This means that the object is a character in the game, and such act accordingly. FEMALEBIT The object is an ACTOR who is a female. + +- VOWELBIT Any verb default which prints an indenite article before the DESC, use "an" instead of "a." + +- NARTICLEBIT The object's DESC doesn't not work with articles, and they should be omitted. PLURALBIT The object's DESC is a plural noun or noun phrase. The DESC should act accordingly. RLANDBIT Usually used for rooms, llets any routine know that the room is dry land (as most are). RWATERBIT The room is water rather than dry land + +- RAIRBIT The room is in mid-air, for those games with some type of ying. + +KLUDGEBIT This bit is used only in the syntax le. + +- ˆ It is used for those syntaxes which want to be simply VERB PREPOSITION with no object. Put (FIND KLUDGEBIT) after the object. The parser, rather than complaining about the missing noun, will see the FIND KLUDGEBIT and set the PRSO (or PRSI as the case may be) to the ROOMS object. + +76 + +OUTSIDEBIT Used in rooms to classify the room as an outdoors room. + +- INTEGRALBIT An integral part of another object, and can't be independently taken or dropped. + +PARTBIT The object is a body part: the HANDS object, for example. + +- NALLBIT This has something to do with telling a TAKE ALL not to take something, but I don't recall how it works. Help??? + +- DROPBIT Found in vehicles, this not-very-important ag means that if the player drops something while in that vehicle, the object should stay in the vehicle rather than falling to the oor of the room itself. + +- INBIT Another not-too-important vehicle-related ag, it tells various routines to say "in the vehicle" rather than "on the vehicle. + +## Object Properties (through YZIP) + +- NORTH, SOUTH, EAST, WEST, NE, SE, NW, SW These are the direction properties, generally used only in room denitions. + + - ˆ Note that the cardinal direction properties are not abbreviated, but that the non-cardinal ones are abbreviated. There is no direction property called NORTHEAST, for example. + +- UP, DOWN These are just like the eight direction properties. + +- IN, OUT These are just like the eight direction properties. + + - ˆ If the player just types IN or OUT, this property will handle the movement. Generally, it's a good idea to give the OUT property to any room with only one exit. + +SYNONYM Contains a list of the nouns which can be used to refer to the object. + +ADJECTIVE Contains a list of the adjectives which can be used to refer to the object. + +ACTION Denes the action routine associated with the object. + +- ˆ In the case of an object, the action routine is called when the object is the PRSO or the PRSI of the player's input. In the case of a room, the routine is called with M-BEG and MEND once each turn, with M-ENTER whenever the room is entered, and with MLOOK whenever the describers need to describe the room. + +DESCFCN Denes the routine which the describers use to describe the object. + +- ˆ This can be the same routine as the object's action routine, provided that the routine is set up to handle the optional variable (M-OBJDESC or M-OBJDESC?). + +CONTFCN Indicates a special ROUTINE to call for objects contained in this object + +- GENERIC Denes the routine which handles cases where the parser determines an ambiguity about which object the player is referring to. + + - ˆ In the absence of a generic property, the parser will simply ask "Which FOO do you mean..." + +- DESC Technically, this isn't a property, but it looks just like one when you dene an object. + +77 + +Appendix B: Attributes and Properties From Learning ZIL + + - ˆ It contains the string which, in the case of objects,will be used in verb defaults, player's inventory, etc. In the case of rooms, it is the room name which appears before room description and on the status line. + +- SDESC Using this property is the only way to give an object a changable DESC. + + - ˆ You can't but you can . Be warned, however, that if your game "shell" isn't set up for SDESCs, you will have to change every verb default. Also, be warned that doing this will increase the size of your game by hundreds of bytes or more, since the verb defaults will no longer simply TELL the desc of the object, but must instead call a little routine which decides whether the object in question has an SDESC or not. + +- LDESC In the case of a room, this contains a string which the describers use for the long description of the room. + + - ˆ In the case of an object, this contains a string which the describers use to describe the object if it is on the ground. + +- FDESC This property, which isn't usually used in room denitions, contains a string which the describers use to describe the object before the rst time it is moved. + +- LOC Once again, technically not a property, but it looks just like one when you're creating an object. + + - ˆ Simply, this property contains the name of the object which contains this object (in the case of a room, this is the object ROOMS). + +SIZE Contains a number which is the size/weight of the object. + +- ˆ Generally, it is only meaningful for a takeable object. If a takeable object has no size property, the game usually gives it a default size of 5. The size of an object aects the number of object that a player can carry, how much of a container it takes up, and so on. + +CAPACITY Contains a number which is the capacity of the object. + +- ˆ Generally, it is only meaningful for a container. If a container has no size property, the game usually gives it a default capacity of 5. The capacity of a container aects the number of objects which can be placed inside it. + +VALUE This property is used in many games that have scoring. + + - ˆ The property contains a number; in the case of rooms, it is the number of points the player gets for entering the room for the rst time; in the case of objects, it is the number of points the player gets for picking up the object for the rst time. + +- GLOBAL Generally found only in room denitions, this property contains a list of objects which are local-globals referencable in that room. + +OWNER Denes an object which is the owner of this object. + +- ˆ For example, the SPORTS-CAR object might have the property (OWNER CYBIL) so that the player could refer to the car as "Cybil's car" even though Cybil isn't actually holding the car. When Cybil sells the car to the player, you would so that the player could now refer to it as "my car." + +78 + +TEXT This property contains a string which is used when the player tries to read the object. + + - ˆ It exists for those objects which would otherwise need an action routine to handle READ but nothing else. + +- THINGS Formerly known as the PSEUDO property, this property allows you to create "pseudoobjects" with some of the properties of real objects. + + - ˆ They have three parts: a list of adjectives, a list of nouns, and an action routine. Here's example: (THINGS (RED CARMINE) (SCARF ASCOT) RED-SCARF-F). Pseudo objects are very limited, however. They cannot have ags, and they cannot be moved. It is benecial to use them whenever feasible, because (unlike real objects) they take up no pre-load space. + +ADJACENT Something to do with adjacent rooms and referencability. Stu? + +## PLURAL Stu? + +PICTURE Contains the name of a graphic from the picture le associated with the room or object. + +FLAGS This is another fellow which looks just like a property but isn't actually a property. + +- ˆ It contains a list of all the ags which are FSET in that object at the start of the game. A list of the common ags can be found in the next appendix. (BY the time YZIP was used, attributes were just considered a list of ags in this property and not a special entity). + +For all exit (direction) properties, the type of exit depends on the length of the property: + +|Unconditional Exit|1 byte|Byte 0: room number| +|---|---|---| +|No Exit|2 bytes|Byte 0-1: Z-string address of exit error| +|Functional Exit|3 bytes|Byte 0-1: Routine address,
Byte 2: 00| +|Conditional Exit|4 bytes|Byte 0: Room number,
Byte 1: Global variable,
Byte 2-3: Z-string address for exit error| +|Door Exit|5 bytes|Byte 0: Room number,
Byte 1: Door object number,
Byte 2-3: Z-string address for exit error,
Byte 4: 00| + + + +ZIL-course from the Infocom Cabinet does mention two attributes and one property not mentioned in Learning ZIL: + +- ˆ FURNITURE attribute: The object is a piece of furniture that a player or actor can sit on. + +- ˆ RMUNGBIT attribute: This applies to rooms only and indicates the room does not exist or accessable. The appropriate error message needs to be given in the LDESC property. This is a cleaner method of removing a room. + +- ˆ IN property: The container of this object + +79 + +Appendix C: Object Attributes and Properties in Zork 1 + +## Appendix C: Object Attributes and Properties in Zork 1 + +## Attributes + +|$00|MAZEBIT|Room is part of the maze.| +|---|---|---| +|$01|HOUSEBIT|Room is part of the house.| +|$02|RLANDBIT|Room is on dry land.| +|$03|ONBIT|For objects, it gives light. For locations, it is lit. All
outdoor rooms should have ONBIT set.| +|$04|FLAMEBIT|Object can be a source of re. LIGHTBIT should also be
set.| +|$05|VEHBIT|Object can be entered or boarded by the player.| +|$06|LIGHTBIT|Object can be turned on or o.| +|$07|KNIFEBIT|Object can cut other objects.| +|$08|BURNBIT|Object can be burned.| +|$09|READBIT|Object can be read.| +|$0A|SURFACEBIT|Object is a container and hold objects which are always
visible. CONTBIT and OPENBIT should be set as well.| +|$0B|SWITCHBIT|Object can be turned on or o.| +|$0C|TRYTAKEBIT|object could be picked up but other values or routines need
to be checked.| +|$0D|OPENBIT|Object is can be opened or closed, refers to doors and
containers.| +|$0E|CONTBIT|Object is a container and can contain other objects or be
open/closed/transparent.| +|$0F|TRANSBIT|Object is transparent so objects inside it can be found even
if OPENBIT is clear.| +|$10|FOODBIT|Object can be eaten.| +|$11|TAKEBIT|Object can be picked up or carried| +|$12|ACCEPTBIT?|(can accept objects)| +|$13|SACREDBIT|| +|$14|PERSONBIT|Object is a character in the game.| +|$15|DOORBIT|Object is a door.| +|$16|DRINKBIT|Object can be drunk.| +|$17|TOOLBIT|Object can be used as a tool to open other things.| +|$18|CLIMBBIT|Object can be climbed| +|$19|INTEGRALBIT|Object cannot be taken separately from other objects, is
part of another object.| +|$1A|INJUREDBIT|Object is injured but not dead.| +|$1B|ALIVEBIT|Object is alive.| +|$1C|TOUCHBIT|For object, it has been taken or used. For rooms, it has
been visited.| +|$1D|INVISIBLE|Object is not detected by the game.| +|$1E|CANTENTERBIT|(or full of water bit)| +|$1F|NONLANDBIT|Room is in or near the water.| + + + +80 + +## Properties + +|$01|NOT USED|| +|---|---|---| +|$02|NOT USED|| +|$03|NOT USED|| +|$04|NOT USED|| +|$05|SPECIALOBJS|0-2 entries of (dict addr, paddr for DESCFCN)| +|$06|LOCAL-GLOBALS|array of obj #s that are valid to use with object| +|$07|BITCHECK|attribute # to check???| +|$08|TEXT|address of z-string| +|$09|SIZE|weight or size of the object| +|$0A|CAPACITY|maximum weight or size that on object can hold| +|$0B|FDESC|addr to z-string of rst description| +|$0C|TREASUREVALUE|| +|$0D|VALUE|pts scores when taking a prized obj or entering a secret
room| +|$0E|LDESC|addr to z-string of "lie on ground" description| +|$0F|HEALTH|0-5, 0 is healthy, 5 is dead| +|$10|ADJECTIVE|adjective value in byte| +|$11|ACTION|address to routine| +|$12|SYNONYM|vocabulary addresses of synonymous tokens (must have
default name too)| +|$13|LAND|exit| +|$14|OUT|exit| +|$15|IN|exit| +|$16|DOWN|exit| +|$17|UP|exit| +|$18|SW|exit| +|$19|SE|exit| +|$1A|NW|exit| +|$1B|NE|exit| +|$1C|S|exit| +|$1D|W|exit| +|$1E|E|exit| +|$1F|N|exit| + + + +81 + diff --git a/docs/ZILF Reference Guide.md b/docs/ZILF Reference Guide.md new file mode 100644 index 0000000..2a98c14 --- /dev/null +++ b/docs/ZILF Reference Guide.md @@ -0,0 +1,10654 @@ +## **ZILF Reference Guide** + +_Henrik Åsman et al._ + +Copyright (C) 2020,2021 Henrik Åsman + +Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without any warranty. + +- 2 - + +## **Table of Contents** + +|**Table of Contents**|| +|---|---| +|ZIL Reference Guide|**13**| +|Introduction|13| +|Goal of document|13| +|Syntax|14| +|Regarding TRUE and FALSE|14| +|Regarding ATOMs and other primitive types|14| +|DECL and ADECL|16| +|OBLISTs|16| +|Dynamic and static (lexical) blocking|16| +|% and %%|16| +|Segments|17| +|What is the “new parser”?|18| +|MDL built-ins and ZIL library (use outside ROUTINE)|19| +|* (multiply)|19| +|+ (add)|19| +|- (subtract)|19| +|/ (divide)|20| +|0?|20| +|1?|20| +|==?|20| +|=?|21| +|ADD-TELL-TOKENS|21| +|ADD-WORD|22| +|ADJ-SYNONYM|24| +|AGAIN|25| +|ALLTYPES|25| +|AND|25| +|AND?|26| +|ANDB|26| +|APPLICABLE?|26| +|APPLY|27| +|APPLYTYPE|27| +|ASCII|27| +|ASK-FOR-PICTURE-FILE?|28| +|ASSIGNED?|28| +|ASSOCIATIONS|28| +|ATOM|29| +|AVALUE|29| + + + +- 3 - + +|BACK|29| +|---|---| +|BEGIN-SEGMENT|30| +|BIND|30| +|BIT-SYNONYM|31| +|BLOAT|31| +|BLOCK|31| +|BOUND?|32| +|BUZZ|32| +|BYTE|32| +|CHECK-VERSION?|33| +|CHECKPOINT|33| +|CHRSET|33| +|CHTYPE|34| +|CLOSE|35| +|COMPILATION-FLAG|35| +|COMPILATION-FLAG-DEFAULT|35| +|COMPILATION-FLAG-VALUE|36| +|COMPILING?|36| +|COND|36| +|CONS|37| +|CONSTANT|37| +|CRLF|38| +|DECL-CHECK|38| +|DECL?|38| +|DEFAULT-DEFINITION|40| +|DEFAULTS-DEFINED|41| +|DEFINE|41| +|DEFINE-GLOBALS|42| +|DEFINE-SEGMENT|42| +|DEFINE20|42| +|DEFINITIONS|43| +|DEFMAC|43| +|DEFSTRUCT|44| +|DELAY-DEFINITION|46| +|DIR-SYNONYM|47| +|DIRECTIONS|47| +|EMPTY?|47| +|END-DEFINITIONS|47| +|END-SEGMENT|48| +|ENDBLOCK|48| + + + +- 4 - + +|ENDLOAD|48| +|---|---| +|ENDPACKAGE|48| +|ENDSECTION|48| +|ENTRY|49| +|EQVB|49| +|ERROR|49| +|EVAL|50| +|EVAL-IN-SEGMENT|50| +|EVALTYPE|50| +|EXPAND|51| +|FILE-FLAGS|51| +|FILE-LENGTH|52| +|FLOAD|52| +|FORM|52| +|FREQUENT-WORDS?|53| +|FUNCTION|53| +|FUNNY-GLOBALS?|54| +|G=?|54| +|G?|55| +|GASSIGNED?|55| +|GBOUND?|55| +|GC|55| +|GC-MON|56| +|GDECL|56| +|GET-DECL|57| +|GETB|57| +|GETPROP|58| +|GLOBAL|58| +|GROW|58| +|GUNASSIGN|59| +|GVAL|59| +|IFFLAG|60| +|ILIST|60| +|IMAGE|60| +|INCLUDE|61| +|INCLUDE-WHEN|61| +|INDENT-TO|62| +|INDEX|62| +|INDICATOR|62| +|INSERT|63| + + + +- 5 - + +|INSERT-FILE|63| +|---|---| +|ISTRING|64| +|ITABLE|64| +|ITEM|65| +|IVECTOR|65| +|L=?|65| +|L?|66| +|LANGUAGE|66| +|LEGAL?|66| +|LENGTH|67| +|LENGTH?|67| +|LINK|67| +|LIST|68| +|LONG-WORDS?|68| +|LOOKUP|69| +|LPARSE|69| +|LSH|69| +|LTABLE|70| +|LVAL|70| +|M-HPOS|70| +|MAKE-GVAL|70| +|MAPF|71| +|MAPLEAVE|72| +|MAPR|72| +|MAPRET|73| +|MAPSTOP|73| +|MAX|73| +|MEMBER|73| +|MEMQ|74| +|MIN|74| +|MOBLIST|74| +|MOD|74| +|MSETG|75| +|N==?|75| +|N=?|75| +|NEVER-ZAP-TO-SOURCE-DIRECTORY?|76| +|NEW-ADD-WORD|76| +|NEWTYPE|76| +|NEXT|77| +|NOT|77| + + + +- 6 - + +|NTH|77| +|---|---| +|OBJECT|78| +|OBLIST?|79| +|OFFSET|79| +|OPEN|80| +|OR|80| +|OR?|81| +|ORB|81| +|ORDER-FLAGS?|81| +|ORDER-OBJECTS?|81| +|ORDER-TREE?|82| +|PACKAGE|83| +|PARSE|84| +|PICFILE|85| +|PLTABLE|85| +|PNAME|85| +|PREP-SYNONYM|85| +|PRIMTYPE|86| +|PRIN1|86| +|PRINC|86| +|PRINT|86| +|PRINT-MANY|87| +|PRINTTYPE|87| +|PROG|88| +|PROPDEF|89| +|PTABLE|91| +|PUT|92| +|PUT-DECL|92| +|PUT-PURE-HERE|92| +|PUTB|92| +|PUTPROP|93| +|PUTREST|94| +|QUIT|94| +|QUOTE|94| +|READSTRING|95| +|REMOVE|95| +|RENTRY|96| +|REPEAT|96| +|REPLACE-DEFINITION|97| +|REST|97| + + + +- 7 - + +|RETURN|97| +|---|---| +|ROOM|98| +|ROOT|99| +|ROUTINE|100| +|ROUTINE-FLAGS|101| +|SET|101| +|SET-DEFSTRUCT-FILE-DEFAULTS|101| +|SETG|102| +|SETG20|102| +|SORT|102| +|SPNAME|103| +|STRING|103| +|STRUCTURED?|103| +|SUBSTRUC|104| +|SUPPRESS-WARNINGS?|104| +|SYNONYM|105| +|SYNTAX|105| +|TABLE|107| +|TELL-TOKENS|108| +|TIME|108| +|TOP|108| +|TUPLE|109| +|TYPE|109| +|TYPE?|110| +|TYPEPRIM|110| +|UNASSIGN|110| +|UNPARSE|110| +|USE|111| +|USE-WHEN|111| +|VALID-TYPE?|112| +|VALUE|112| +|VECTOR|112| +|VERB-SYNONYM|113| +|VERSION|113| +|VERSION?|114| +|VOC|114| +|WARN-AS-ERROR?|117| +|XFLOAD|117| +|XORB|117| +|ZGET|117| + + + +- 8 - + +|ZIP-OPTIONS|118| +|---|---| +|ZPACKAGE|118| +|ZPUT|118| +|ZREST|119| +|ZSECTION|119| +|ZSTART|119| +|ZSTR-OFF|119| +|ZSTR-ON|120| +|ZZPACKAGE|120| +|ZZSECTION|120| +|Z-code built-ins (use inside ROUTINE)|121| +|*, MUL|121| +|+, ADD|121| +|-, SUB|121| +|/, DIV|122| +|0?, ZERO?|122| +|1?|122| +|=?, ==?, EQUAL?|122| +|AGAIN|123| +|AND|124| +|APPLY|124| +|ASH, ASHIFT|124| +|ASSIGNED?|125| +|BACK|125| +|BAND, ANDB|125| +|BCOM|126| +|BIND|126| +|BOR, ORB|127| +|BTST|127| +|BUFOUT|127| +|CATCH|128| +|CHECKU|128| +|CLEAR|129| +|COLOR|129| +|COND|129| +|CRLF|131| +|CURGET|131| +|CURSET|131| +|DCLEAR|132| +|DEC|132| + + + +- 9 - + +|DIRIN|133| +|---|---| +|DIROUT|133| +|DISPLAY|133| +|DLESS?|134| +|DO|134| +|ERASE|138| +|F?|138| +|FCLEAR|139| +|FIRST?|139| +|FONT|139| +|FSET|140| +|FSET?|140| +|FSTACK|140| +|G?, GRTR?|141| +|G=?|141| +|GET|141| +|GETB|141| +|GETP|142| +|GETPT|142| +|GVAL|142| +|HLIGHT|143| +|IFFLAG|143| +|IGRTR?|143| +|IN?|144| +|INC|144| +|INPUT|144| +|INTBL?|145| +|IRESTORE|145| +|ISAVE|146| +|ITABLE|146| +|L?, LESS?|147| +|L=?|147| +|LEX|147| +|LOC|147| +|LOWCORE-TABLE|148| +|LOWCORE|148| +|LSH, SHIFT|148| +|LTABLE|149| +|LVAL|149| +|MAP-CONTENTS|149| + + + +- 10 - + +|MAP-DIRECTIONS|150| +|---|---| +|MARGIN|151| +|MENU|151| +|MOD|152| +|MOUSE-INFO|152| +|MOUSE-LIMIT|152| +|MOVE|153| +|N=?, N==?|153| +|NEXT?|153| +|NEXTP|154| +|NOT|154| +|OR|154| +|ORIGINAL?|155| +|PICINF|155| +|PICSET|155| +|PLTABLE|155| +|POP|156| +|PRINT|156| +|PRINTB|156| +|PRINTC|157| +|PRINTD|157| +|PRINTF|157| +|PRINTI|157| +|PRINTN|158| +|PRINTR|158| +|PRINTT|158| +|PRINTU|159| +|PROG|159| +|PTABLE|160| +|PTSIZE|160| +|PUSH|161| +|PUT|161| +|PUTB|161| +|PUTP|162| +|QUIT|162| +|RANDOM|162| +|READ|163| +|REMOVE|164| +|REPEAT|164| +|REST|165| + + + +- 11 - + +|RESTART|165| +|---|---| +|RESTORE|166| +|RETURN|166| +|RFALSE|167| +|RFATAL|167| +|RSTACK|167| +|RTRUE|167| +|SAVE|168| +|SCREEN|168| +|SCROLL|168| +|SET|169| +|SETG|169| +|SOUND|169| +|SPLIT|170| +|T?|170| +|TABLE|170| +|TELL|171| +|THROW|171| +|USL|172| +|VALUE|172| +|VERIFY|172| +|VERSION?|173| +|WINATTR|173| +|WINGET|173| +|WINPOS|174| +|WINPUT|174| +|WINSIZE|174| +|XPUSH|174| +|ZWSTR|175| +|Appendix A: Other Z-machine OP-codes|176| +|Appendix B – Field-spec for header|176| +|Ordinary header|177| +|Extended header|179| +|Appendix C - Reserved constants, globals & locals|180| + + + +- 12 - + +## **ZIL Reference Guide** + +## _**Introduction**_ + +Historically Zork (the mainframe version) was developed in MDL at M.I.T. on an PDP-10 ITS. When Infocom faced the task of moving Zork to 8-bit computers they created a virtual machine that was able to run a subset of MDL (just enough to get a stripped down version of Zork to run: the game we now call Zork I). This virtual machine is now often called a "Z-Machine", and exists in many versions on many platforms. + +The Z-machine runs this subset of commands and reads the game data from a formatted data-structure suited for Interactive Fiction. + +Infocom’s development environment was always MDL on PDP-10. In this environment they had access to MDL and a library of `FUNCTIONS` designed to help build the data-structure. In the environment there was also `ZILCH` that compiled the code to a format that the Z-machine could understand. + +This means that everything that is inside a ROUTINE is code that compiles to instructions that the Z-machine understands and everything that is outside the ROUTINE is MDL that is used to build the data-structure. There are two classes of commands. And some instructions to ZILCH, the compiler + +The full developing environment for Infocom doesn't exist today, although parts exist in a PDP-10 ITS emulation project. As of today there is a MDL interpreter and some code of ZILCH, but primarily the MDL compiler is still missing. Efforts are underway to piece together the PDP-10 ITS environment from old tapes and eventually it may succeed. + +Luckily there is now another way to write and compile ZIL: the compiler known as ZILF. + +The ZILF environment contains a subset of MDL and the Infocom library of `FUNCTIONS` (to build the data-structure and `ROUTINES` ). ZILF also can compile all this to a format that then can run in a Z-machine. + +This document is divided in basically two parts. + +The first part is the things that only work outside a `ROUTINE` . These commands are processed during compilation to build the data-structure. Here you need to pay attention to order and declare things before they are used. + +The second part is things that only work inside a `ROUTINE` . These commands are processed by the Z-machine during runtime. + +Sources: + +_Learning ZIL, Steve E. Meretzky_ + +_ZIL Course, Marc S. Blank_ + +## _**Goal of document**_ + +[ _This NOT a manual on how to write games. The goal is to list all instructions and syntaxes with short examples to use when reading game code. It should also list syntax and behaviour that is specific for ZILF._ ] + +- 13 - + +## _**Syntax**_ + +|**_Syntax_**|||| +|---|---|---|---| +|**Typename**|**Size**|**Min-Max**|**Examples**| +|FIX|32-bit signed integer|-2147483648 to
2147483648|`616`
`*747*`
`#2 10110111`| +|CHARACTER|8-bit|0 to 255|`!\A`| +|BYTE|8-bit|0 to 255|`65`| +|FALSE|||`<>`| +|``
``
```
``
``|`#type value`
`,value`
`(values ...)`
`.value`
`[values ...]`
`'value`||| + + + +## _**Regarding TRUE and FALSE**_ + +True and false are handled differently depending on if you are "outside" or "inside" routines. + +Outside routines `FALSE` is its own TYPE which evaluates to an empty list <>. + +Inside routines the value 0 is considered `FALSE` , all other values are considered `TRUE` . Example: + +``` +<=? <> 0>-->FALSE "outside", but TRUE "inside" +``` + +## _**Regarding ATOMs and other primitive types**_ + +ZILF recognizes the following primitive types: `ATOM` , `FIX` , `LIST` , `STRING` , `TABLE` and `VECTOR` . Everything that ZILF encounters when it reads the code falls into one of these types (or derived types of these primitive ones). + +|`FIX`
`LIST`
`STRING`|32-bit signed integer. Any number is a
`FIX`.`CHARACTER`and`BYTE`are
examples of`TYPE`s whose`PRIMTYPE`
is`FIX`.|`616`
`*747*`
`#2 10110111`
`!\A`| +|---|---|---| +||Linked list (forward looking).A`LIST`
is enclosed by parentheses.`FORM`,
`FUNCTION`and`MACRO`are examples
of`TYPE`s whose`PRIMTYPE`is`LIST`.|`(1 2 3)`
`<+ 1 2>`
`<>`
`#FUNCTION <() <+ 1 2>>`| +||A continuous byte array containing|`"Hello, world!"`| + + + +- 14 - + +||characters. A `STRING`is enclosed by
double-quotes.|| +|---|---|---| +|`TABLE`|A continuous byte or word array. This
`TYPE`is specific for ZIL and is a
simplified`VECTOR`without any`TYPE`
information about the individual
elements. A `TABLE`is zero-based and
element at index 0 can be specified to
contain the length of the`TABLE`.|`#TABLE [5 6 7]`
``
`
`| +|`VECTOR`|A continuous array of elements. A
`VECTOR`is enclosed by square
brackets. Each element holds
information about its`TYPE`. MDL has a
`UVECTOR TYPE`that contains uniform
elements (same`TYPE`) but ZILF
handles these as`VECTOR`s.|`[1 !\A "Hello" (1 2 3)]`
`![1 2 3 4 5!]`| + + + +Everything that does not have one of the above as its `PRIMTYPE` is an `ATOM` . One can think of an `ATOM` as a variable that can hold one of the other `TYPE` s. Every `ATOM` can have a global value and a local value. Every `ATOM` also has a `PNAME` (“print name”) that ZILF uses when it needs to print the name of the `ATOM` . + +Examples: + +``` +;"Assign the global ATOM BAR the FIX 123" + +;"Assign the local ATOM BAR the VECTOR [1 2 3]" + +;"Assign the global ATOM BARBAR the global valueof ATOM BAR" +> +,BARBAR-->123 +;"Assign the local ATOM FOOBAR the ATOM BAR" + +.FOOBAR-->BAR +>-->[1 2 3] +,.FOOBAR-->123 +;"Assign the global ATOM FUNC a FUNCTION" +> +;"Assign the global ATOM BAZ a FORM" +> +,BAZ--><+ 1 2> +-->3 +``` + +- 15 - + +## _**DECL and ADECL**_ + +## _**OBLISTs**_ + +`OBLIST` (“object list”) is basically a `LIST` of `ATOM` s. ZILF have initially two predefined `OBLIST` s, `INITIAL` and `ROOT` . `INITIAL` is empty but every `ATOM` your program creates will be stored here. `ROOT` contains the `ATOM` s for all built-in `FUNCTION` s. `MOBLIST` can be used to create new `OBLIST` s. + +If there is ambiguity about which `ATOM` to use it is possible to specify which `OBLIST` s `ATOM` to use with trailers, `!-` . The syntax for this is + +``` +atom!-oblist +``` + +Example: + +``` + ;"Create FOO!-INITIAL and assign ita GVAL" + ;"Create FOO!-NOBL and assignit a GVAL" +,FOO!-INITIAL-->123 +,FOO!-NOBL-->456 +-->#OBLIST (("FOO" FOO!-NOBL)) +``` + +ZILF has a `LVAL` , `OBLIST` , that is a `LIST` of `OBLIST` s. Initially this `LIST` contains `INITIAL` and `ROOT` . When ZILF resolves which `ATOM` to use it searches through these `LIST` s, starting with `<1 .OBLIST>` . It is because of this you normally don’t need to specify `!-INITIAL` . `` in the above example will first look for, and find, the `ATOM` in the `OBLIST INITIAL` . + +`OBLIST` s are not only used to identify `ATOM` s. The MDL version of Zork, for example, uses `OBLIST` s to handle the vocabulary. + +For more on `OBLIST` s, see `ATOM` , `INSERT` , `LOOKUP` , `MOBLIST` , `OBLIST?` , `REMOVE` , `ROOT` and _The MDL Programming Language, chapter 15_ . + +## _**Dynamic and static (lexical) blocking**_ + +To prevent collisions between `ATOM` s identifiers there are two types of blocking used in ZILF. + +The first type is dynamic blocking and is achieved by pushing and pulling `LVAL` s from the stack. This assures that every `ATOM` can have a global value, `GVAL` , and a local value `LVAL` . that is unique for every program block that is defined by, for example, a `FUNCTION` , `BIND` , `PROG` or `REPEAT` . + +Sometimes this is not enough and there is another type of blocking, static or lexical blocking, to assure that there is no collision between identifiers of `ATOM` s, for example when library programs are shared among many different peoples. + +By using `BLOCK` and `ENDBLOCK` a program block can have another `LIST` of `OBLIST` s where it looks up the `ATOM` s. + +See `BLOCK` for example of this. + +For more on lexical blocking, see _The MDL Programming Language, chapter 15_ . + +## _**% and %%**_ + +When ZILF interprets MDL, either during compilation or when using ZILF in interpreter mode, it goes through three stages repeatedly, `READ` , `EVAL` and `PRINT` . + +- 16 - + +READ reads ASCII-text and when it has something enclosed in matching brackets the result is passed to EVAL for evaluation that in its turn passes the result of the evaluation to PRINT that prints the evaluated result. The flow is like below: + +printable text → `READ` → [MDL objects] → `EVAL` → [MDL objects] → `PRINT` → printable text Consider a simple statement like: `<+ 1 2>` + +`READ` reads from left to right and when it encounters the closing bracket the MDL object `<+ 1 2>` , a `FORM` , is passed to `EVAL` . `EVAL` evaluates this MDL object and the resulting MDL object, 3, is passed to `PRINT` for printing. + +`%` and `%%` are “ `READ` macros” that are used to modify this process. Whenever `READ` encounters `%` or `%%` it immediately passes the MDL object that follows the `%` , or `%%` , to `EVAL` before it continues the `READ` . + +In case of `%` the result of the `EVAL` is inserted in place of the MDL object that follows the `%` and is used by the following `READ` . + +In case of `%%` the result of the `EVAL` is ignored and nothing is inserted in place of the MDL object that follows the `%%` (eventual side effects of the `EVAL` remains, of course). + +Example: + +``` +> +>> +;"1st INIT-A, 1st INC-A, 2nd INC-A, 2nd INIT-A, 3rdINC-A" +[ () ] +-->[0 1 2 (0) 1] +``` + +``` +;"1st INIT-A, 3rd INC-A, 1st INC-A, 2nd INC-A, 2ndINIT-A" +[% () %] +-->[0 2 3 (0) 1] +``` + +``` +;"2nd INIT-A, 3rd INC-A, 1st INIT-A, 2nd INC-A, 3rdINC-A" +[ (%) %] +``` + +``` +-->[0 1 2 (0) 1] +``` + +``` +;"1st INIT-A, 1st INC-A, 2nd INC-A, 2nd INIT-A, 3rdINC-A" +[%% % % (%%) %] +-->[1 2 () 1] +``` + +## _**Segments**_ + +Segments are used to copy elements from one structure `TYPE` to another structure `TYPE` . Segments take the form `!` where the second exclamation point is optional. The implicit form of `LVAL` and `GVAL` is legal. The segment is `EVAL` uated and must be `EVAL` uated inside another structure and the result of the `EVAL` must be a structure, otherwise an error is raised. + +Examples: + +**==> picture [347 x 67] intentionally omitted <==** + +- 17 - + +``` +.L2-->[1 2 3 [6 5]] +[! (!.L0)]-->[1 2 3 (6 5)] +``` + +## _**What is the “new parser”?**_ + +_[Explain what type of animal the new parser is.]_ + +- 18 - + +## _**MDL built-ins and ZIL library (use outside ROUTINE)**_ + +The syntax for most of these commands are much like the syntax in MDL. + +All these commands are possible to run, test and debug during the interactive mode of ZILF (start ZILF without any options). + +Sources: + +``` +MDL built-in +``` + +MDL built-in function. Part of MUDDLE.56 on ITS. _The MDL Programming Language, S. W. Galley and Greg Pfister MUDDLE F/SUBRS (MUDMAN for MUDDLE 55), P. David Lebling and S. W. Galley_ + +`MDL package system` Support for lexical blocking. _The MDL Programming Environment, P. David Lebling_ + +``` +ZIL library +``` + +``` +ZILF compiler +directive +``` + +Functions added through ZIL/ZILCH at Infocom to support building of interactive fiction. _ZIL Language Guide, Jesse McGrew ZILF source code and test cases, Jesse McGrew Learning ZIL, Steven E. Meretzky ZIL, Marc S. Blank_ + +_ZILF source code and test cases, Jesse McGrew_ + +## *** (multiply)** + +``` +<* numbers ...> +``` + +``` +MDL built-in +``` + +Multiply `numbers` . + +Example: + +``` +<* 2 3 4>-->24 +``` + +## **+ (add)** + +``` +<+ numbers ...> +``` + +``` +MDL built-in +``` + +Add `numbers` . + +Example: + +``` +<+ 2 3 4>-->7 +``` + +## **- (subtract)** + +``` +<- numbers ...> +``` + +- 19 - + +``` +MDL built-in +``` + +Subtract first `number` by subsequent `numbers` + +If only one `number` is provided, it's subtracted from zero (i.e. negated). Examples: + +``` +<- 8 3 4>-->1 +<- 5>-->-5 +``` + +## **/ (divide)** + +``` + +``` + +``` +MDL built-in +``` + +Divide first `number` by subsequent `numbers` . + +Example: + +``` +-->2 +``` + +## **0?** + +``` +<0? value> +``` + +``` +MDL built-in +``` + +Predicate. True if `value` is 0 otherwise false. + +## **1?** + +``` +<1? value> +``` + +``` +MDL built-in +``` + +Predicate. True if `value` is 1 otherwise false. + +## **==?** + +``` +<==? value1 value2> +``` + +``` +MDL built-in +``` + +This is a predicate that returns `TRUE` if `value1` and `value2` is the same object, otherwise it returns `FALSE` . + +For `ATOM` s whose `TYPE` are structured (for example `LIST` s and `VECTOR` s) the `ATOM` s must refer (point) to the same structure to be considered `==` . These `ATOM` s are actually pointers that point to an memory address and the two `ATOM` s must point to the same address to be `==` . + +For `ATOM` s whose `TYPE` is not structured the `ATOM` s are considered `==` if they are of the same `TYPE` and contain the same value. + +- 20 - + +ZILF defines "the same object" more loosely than MDL do: + +- `STRING` s are considered `==?` if they contain the same text. + +- `LVAL` s and `GVAL` s are considered `==?` if they refer to the same ATOMs. + +Examples: + +``` + +<==? .X 1>-->True + +<==? .X (1 2 3)>-->False +<==? "Hello" "Hello">-->True (in ZILF, but notin MDL) +``` + +## **=?** + +``` +<=? value1 value2> +MDL built-in +``` + +This is a predicate that returns `TRUE` if `value1` and `value2` is of the same `TYPE` and structurally equal, otherwise it returns `FALSE` . + +Examples: + +``` + +<=?.X 1>-->True + +<=? .X (1 2 3)>-->True +``` + +## **ADD-TELL-TOKENS** + +``` + +``` + +``` +ZIL library +``` + +Add a new `pattern` and `form` to the current `TELL-TOKENS` . These can then be used in `TELL` . + +Each `pattern` starts with either: + +- Any single `ATOM` except * (asterisk) + +- A `LIST` of `ATOM` s, which will define them as synonyms + +A simple `pattern` , like CR, consists of a name and nothing else. More often, patterns also define placeholders to match -- and optionally capture -- parameter values when the token is used inside a `TELL` . The rest of the `pattern` consists of any number of: + +- An asterisk ( * ), to match and capture any value. + +- An `ADECL` whose left side is an asterisk (like *: `FIX` ), to match and capture any value that matches the `DECL` pattern on the right side. + +- A `GVAL` (like `,PRSO` or equivalently `` ), to match that exact `GVAL` without capturing it. + +Each pattern is followed by a form that will be copied and inserted in place of the TELL when the + +- 21 - + +pattern is matched. Each element of the form must be either: + +- An `ATOM` , `FIX` , `STRING` , or `FALSE` . + +- An `LVAL` or `GVAL` + +- An empty `FORM` + +The `form` must contain exactly one `LVAL` for each element of the `pattern` that captures a value. These `LVAL` s are positional placeholders that will be replaced by the captured values, in order. The specific `ATOM` referenced by each `LVAL` is ignored. + +Example (zillib 0.9 adds these tokens): + +``` + +A * +CT * +CA * +NOUN-PHRASE * +OBJSPEC * +SYNTAX-LINE * +WORD * +MATCHING-WORD * * * > +``` + +## **ADD-WORD** + +``` + +``` + +``` +ZIL parser library +``` + +`ADD-WORD` requires the new parser ( `` ). Note that the standard library that's included with ZILF, zillib, doesn't support the new parser. + +The new parser needs a couple of boot-strap `FUNCTION` s, `GVAL` s and `DEFSTRUCT` s to work. + +`CLASSIFIED` A global `LIST` that defines the `part-of-speech` and its value. `GET-CLASSIFICATION` A `FUNCTION` that can return the `part-of-speech` from `CLASSIFIED` . `VERB-DATA` A `DEFSTRUCT` . `VWORD` A `DEFSTRUCT` . + +There also needs to be a call to `SET-DEFSTRUCT-FILE-DEFAULTS` to set up the `DEFSTRUCT` s. + +There’s also two `COMPILATION-FLAG` s that control how the vocabulary is set up. + +`WORD-FLAGS-IN-TABLE` Creates the `GVAL WORD-FLAG-TABLE` . `ONE-BYTE-PARTS-OF-SPEECH` Control if the `part-of-speech` value should occupy a byte or a word (If the size of each entry in the vocabulary is 9 or 10 bytes) + +INFOCOM only used the new parser in three published games (Arthur, Shogun and Zork Zero) and two unpublished projects (Abyss and Restaurant). ADD-WORD and NEW-ADD-WORD is in these games called with these values + +- 22 - + +|**`part-of-speech `**|**`value`**||**`flags`**|**`flag-value`**| +|---|---|---|---|---| +|`ADJ`|`<>`||`FIRST-PERSON`|`8`| +|`ADV`|``|`PLURAL-FLAG`|`16`| +|`APOSTR`|||`SECOND-PERSON`|`32`| +|`ARTICLE`|||`THIRD-PERSON`|`64`| +|`ASKWORD`|||`PRESENT-TENSE`|`256`| +|`CANDO`|||`PAST-TENSE`|`512`| +|`COMMA`|||`FUTURE-TENSE`|`1024`| +|`END-OF-INPUT`|||`POSSESSIVE`|`16384`| +|`MISCWORD`||||| +|`NOUN`||||| +|`OFWORD`||||| +|`PARTICLE`||||| +|`PREP`||||| +|`QUANT`||||| +|`QUOTE`||||| +|`QWORD`||||| +|`TOBE`||||| +|`VERB`||||| + + + +Examples: ` > > <2 .P>) (T )>> ) (VERB-TWO )> + +> + +> + 12345> + + +> +>>> + + + +> + + )> + +> +> +> + + )> + +> +> + + )> + +> +``` + +## **ALLTYPES** + +``` + +``` + +``` +MDL built-in +``` + +returns a `VECTOR` containing the `ATOM` s which can currently be returned by `TYPE` or `PRIMTYPE` . + +## **AND** + +``` + +``` + +- 25 - + +## `MDL built-in` + +Boolean `AND` . Requires that all `expressions` evaluate to true to return true. Exits on the first `expression` that evaluates to false (rest of `expressions` are not evaluated). + +Because 0 is considered false and all other values are considered true inside a routine `AND` returns 0 if one `expression` is false or the value of the last `expression` if all `expressions` are true. + +Because false is its own `TYPE` outside a routine `AND` returns `#FALSE` if one of the `expressions` is false or the value of the last `expression` if all `expressions` are true. Example: + +``` + >-->True + >-->X never set to 2 because +first predicate evaluates +to false +>-->X is set to 4 + 4>>-->X is set to #FALSE +>-->X is set to 2 +``` + +## **AND?** + +``` + +``` + +``` +MDL built-in +``` + +Returns the same result as `AND` with the difference that all `expressions` are evaluated. Examples: + +``` + >-->True + >-->X is set to 2 because +all expressions are +evaluated +``` + +## **ANDB** + +``` + +``` + +``` +MDL built-in +``` + +Bitwise AND. + +Examples: + +``` +-->32 +-->0 +``` + +## **APPLICABLE?** + +``` + +``` + +``` +MDL built-in +``` + +- 26 - + +Predicate. Returns true if `TYPE` of `value` is of an applicable `TYPE` . Applicable `TYPE` s: `FIX FSUBR FUNCTION MACRO OFFSET SUBR` + +Example: + +``` +> +-->True +``` + +## **APPLY** + +``` + +MDL built-in +``` + +Call the `applicable` with `args` . `` is equivalent to `. applicable` must be an atom that `APPLICABLE?` evaluates to true (usually `FUNCTION` , `SUBR` , `FSUBR` & `MACRO` ) `. APPLY` is often used when the `applicable` to be called is resolved during run-time (dispatch-table). + +Examples: + +``` +> +> +> + 2>-->4 + 2>-->8 +``` + +## **APPLYTYPE** + +``` + +``` + +``` +MDL built-in +``` + +`APPLYTYPE` tells the `TYPE atom` how it should be applied in a `FORM` . If `APPLYTYPE` is called without a `handler` then the currently active `handler` is returned. If there is no active `handler` , `FALSE` is returned. + +Note that it is possible to replace the `handler` with a new `handler` , even on the predefined `TYPE` s (see `EVALTYPE` for example on this). + +See `EVALTYPE` , `NEWTYPE` and `PRINTTYPE` . + +Example: + +``` + +-->#FALSE +``` + +- 27 - + +``` +> +<#WINNER (A B C) <+ 1 2> q>-->(A B C 3 q) +``` + +## **ASCII** + +``` + +MDL built-in +``` + +Converts `number` to `character` or `character` to `number` . + +Examples: + +``` +-->65 +-->!\A +``` + +## **ASK-FOR-PICTURE-FILE?** + +``` + +``` + +``` +ZIL library +``` + +ZILF ignores this and always returns `FALSE` . + +## **ASSIGNED?** + +``` + +``` + +``` +MDL built-in +``` + +Predicate. Returns true if the `atom` has an `LVAL` (local value). + +It is possible to supply an environment for `ASSIGNED?` . See `EVAL` for more about the `environment` . + +Example: + +< `ASSIGNED? X> --> False --> True` + +## **ASSOCIATIONS** + +``` + +``` + +``` +MDL built-in +``` + +`ASSOCIATIONS` gives access to the association chain. `ASSOCIATIONS` returns the first entry in the chain or FALSE if the chain is empty. Each entry is of the `TYPE ASOC` . An `ASOC` contains three elements: `ITEM` , `INDICATOR` and `VALUE` . An `ASOC` looks like a `LIST` but behaves differently. + +Note that ZILF adds new `ASSOCIATIONS` last in the chain instead of at the top that’s usually done in MDL. + +See `AVALUE` , `GETPROP` , `INDICATOR` , `ITEM` , `NEXT` and `PUTPROP` on how to extract, create and + +- 28 - + +traverse the chain. + +Example: + +``` +;"Put all ASOCs in a LIST" +)) + '()) +(T (.A !> .A) +(T )>>>))>> +``` + +## **ATOM** + +``` + +``` + +``` +MDL built-in +``` + +`ATOM` returns a newly created `ATOM` with `pname` (string). The `ATOM` is not on any `OBLIST` and therefore has the trailer `!-#FALSE ()` attached to it. + +Examples: + +``` +-->FOO!-#FALSE () +<==? >-->#FALSE +``` + +## **AVALUE** + +``` + +``` + +``` +MDL built-in +``` + +`AVALUE` returns the value part from an `asoc` entry, of `TYPE ASOC` , in the `ASSOCIATION` chain. See `ASSOCIATIONS` , `GETPROP` , `INDICATOR` , `ITEM` , `NEXT` and `PUTPROP` . Example: + +``` +)) +> >) +(<=? <>> )> +>>> + +> +-->"Hello, world!" +``` + +## **BACK** + +``` + +``` + +``` +MDL built-in +``` + +Moves `count` elements back in `array` . If `count` moves past the start of the `array` an error is + +- 29 - + +raised. Default value for `count` is 1. + +`BACK` only works on the structures `VECTOR` or `STRING` (arrays) and not on a `LIST` (a `LIST` is only pointing forward). + +Note that the returned `array` is not a copy but pointing to the same `array` with another starting element. + +Also see `LENGTH` , `NTH` , `PUT` , `REST` , `SUBSTRUC` and `TOP` . + +Example: + +``` +-->STRUCT1 = [1 2 34 5] +>-->STRUCT2 = [34 5] +-->STRUCT2 = [2 3 4 5] +``` + +## **BEGIN-SEGMENT** + +``` + +``` + +``` +ZIL library +``` + +ZILF ignores this and always returns `FALSE` . + +## **BIND** + +``` + +``` + +``` +MDL built-in +``` + +`BIND` defines a program block with its own set of `bindings` . `BIND` is similar to `PROG` and `REPEAT` but `BIND` doesn't create a default `activation` (like `PROG` and `REPEAT` ) at the start of the block and don't have an automatic `AGAIN` at the end of the block (like `REPEAT` ). If an `activation` is needed it must be specified. `AGAIN` and `RETURN` without specified `activation` inside a BIND-block will start over or return from the closest surrounding `activation` within the current function. + +The `decl` is used to specify the valid `TYPE` of the variables. In its simplest form `decl` is formatted like: `#DECL ((X) FIX)` , meaning that X must be of the `TYPE FIX` . For more information on how to format the `decl` see `GDECL` . + +Also see `AGAIN` , `PROG` , `REPEAT` and `RETURN` for more details how to control program flow. Example: + +``` +> > +--> "21" + +> + + )>;"--> exit +block" +``` + +- 30 - + +``` + +> + +> +--> "START 123 END" +``` + +``` +;"--> repeat" +``` + +## **BIT-SYNONYM** + +``` + +``` + +``` +ZIL parser library +``` + +`BIT-SYNONYM` creates synonyms to flag-bits. + +Example: + +``` + + +``` + +## **BLOAT** + +``` + +``` + +``` +MDL built-in +``` + +ZILF ignores this and always returns `FALSE` . + +`BLOAT` is used in MDL to temporarily expand available storage space to avoid unnecessary garbage collection when loading large files. + +## **BLOCK** + +``` + +``` + +``` +MDL built-in +``` + +`BLOCK` pushes current binding of the local `ATOM OBLIST` and rebinds it with the `LIST` of `oblist` supplied as argument and returns the new `` .. Usually you want `` as the last `oblist` in `LIST` . `` then restores the local `ATOM OBLIST` to its previous value. + +Example: + +``` + + +> + )> + + +> +-->333 +-->444 +-->"INSIDE BLOCK" +``` + +- 31 - + +``` + +-->111 +-->222 +-->"OUTSIDE BLOCK" +``` + +## **BOUND?** + +``` + +``` + +``` +MDL built-in +``` + +`BOUND?` is a predicate that returns true if the `atom` ever had a local value in the `environment` . If no `environment` is supplied, the `environment` defaults to current scope. See `EVAL` for more about the `environment` . + +Examples: + +``` + +-->True +-->True + +-->False +-->True +``` + +## **BUZZ** + +``` + +``` + +``` +ZIL parser library +``` + +`BUZZ` creates words in the vocabulary with the `part-of-speech BUZZ` . These are words that can be ignored by the parser or have special handling in the parser. Example: + +``` + +``` + +## **BYTE** + +``` + +#BYTE number;"Alternative syntax (MDL built-in)" +;"Alternative syntax (MDL built-in)" +``` + +``` +ZIL library +``` + +`BYTE` changes `number` of `TYPE` to `#BYTE` . + +Examples: + +``` +-->#BYTE 42 +#BYTE 42-->#BYTE 42 +-->#BYTE 42 +``` + +- 32 - + +## **CHECK-VERSION?** + +``` + +``` + +``` +ZIL library +``` + +`CHECK-VERSION?` is a predicate that returns `TRUE` if current setting of `VERSION` is `version-spec` . Valid values for `version-spec` are `ZIP` , `EZIP` , `XZIP` , `YZIP` and the values 3-8. + +Examples: + +``` + +-->#FALSE +-->T +``` + +## **CHECKPOINT** + +``` + +``` + +``` +ZIL library +``` + +ZILF ignores this and always returns `FALSE` . + +## **CHRSET** + +``` + +``` + +``` +ZIL library +``` + +`CHRSET` can be used in version 5+ to replace one or more of the standard character alphabets. + +The ZSCII alphabet table is divided up in three blocks of 26 characters each, totaling 78 characters. The default layout is: + +``` +Z-char 6789abcdef0123456789abcdef +current -------------------------- +``` + +``` +A0 abcdefghijklmnopqrstuvwxyz +A1 ABCDEFGHIJKLMNOPQRSTUVWXYZ +A2 ^0123456789.,!?_#'"/\-:() +-------------------------- +``` + +Text is then encoded into 2-byte words with 5-bits per character. The left-over bit is always 0 except on the last word where it is 1 to indicate that tis is the last 2-byte word in the text. + +**==> picture [274 x 37] intentionally omitted <==** + +Initially the A0 is the current alphabet. The characters 2, 3, 4 and 5 change alphabet according to this table: + +**==> picture [260 x 23] intentionally omitted <==** + +**==> picture [27 x 9] intentionally omitted <==** + +``` +Z-char 3 A2 A0 A1 +Z-char 4 A1 A2 A0 +Z-char 5 A2 A0 A1 +``` + +Character 2 and 3 change the alphabet for the next character (“shift”) and character 4 and 5 change the alphabet permanent (“shift lock”). + +`CHARSET` change one character in one alphabet or change an alphabet altogether. + +Example: + +``` +;" 1 2 3 +67890123456789012345678901 +zyxwvutsrqponmlkjihgfedcba +z=6 i=23 l=20 +1 00110 10111 10100" + + +> + +> + + +> + 0>> ;"Multiplyby 4 to +get packed +address in v 5." + 0> >> +> +--> +zil +zil +-25868 +-25868 +0 +``` + +## **CHTYPE** + +``` + +#type value;"Alternative syntax" +MDL built-in +``` + +`CHTYPE` returns a new object that has `TYPE type` and the same “data part” as `value` . The `PRIMTYPE` of `value` must be the same as the `TYPEPRIM` of `type` otherwise an error will be generated. + +There is a abbreviated form to change type by typing `#type value` instead. + +- 34 - + +Examples: + +``` +--> 65 +#FIX !\A--> 65 +#LIST [1 2 3]--> ERROR +``` + +## **CLOSE** + +``` + +``` + +``` +MDL built-in +``` + +`CLOSE` the `channel` opened by `OPEN` and returns the `channel` . + +See `READSTRING` for example. + +## **COMPILATION-FLAG** + +``` + +``` + +``` +ZIL library +``` + +This defines a `COMPILATION-FLAG` named `atom-or-string` with initialized to `value` . If no `value` is supplied it defaults to `TRUE` . The name of the flag can either be an `ATOM` or a `STRING` whose text becomes the `ATOM` . + +The flag can then be read by `COMPILATION-FLAG-VALUE` or used as a `condition` in `IFFLAG` . + +A call to `COMPILATION-FLAG` with an already defined `ATOM` changes the value of the `ATOM` . + +Examples: + +``` + +-->T + +-->123 +``` + +## **COMPILATION-FLAG-DEFAULT** + +``` + +``` + +``` +ZIL library +``` + +This defines a `COMPILATION-FLAG` named `atom-or-string` with initialized to `value` . If no `value` is supplied it defaults to `TRUE` . The name of the flag can either be an `ATOM` or a `STRING` whose text becomes the `ATOM` . + +The flag can then be read by `COMPILATION-FLAG-VALUE` or used as a `condition` in `IFFLAG` . + +A call to `COMPILATION-FLAG-DEFAULT` with an already defined `ATOM` doesn't change the value of the `ATOM` . + +Examples: + +- 35 - + +``` + +-->T + +-->123 + +-->123 +``` + +## **COMPILATION-FLAG-VALUE** + +``` + +``` + +``` +ZIL library +``` + +This returns the value of the `COMPILATION-FLAG atom-or-string` . If no `atom-or-string` is defined it returns `FALSE` . + +## Examples: + +``` + +-->123 +-->#FALSE +``` + +## **COMPILING?** + +``` + +``` + +``` +ZIL library +``` + +ZILF ignores this and always returns `TRUE` . + +Presumably `COMPILING?` is used in the MDL environment to determine if the game is compiled with ZILCH or running in the interpreter. + +## **COND** + +``` + +``` + +``` +MDL built-in +``` + +`COND` (“conditional“) evaluates `condition` in each `(condition body ...)` and if the `condition` is not `FALSE` it continues to evaluate all the `body` -parts in this `LIST` . `COND` only evaluates the first non- `FALSE condition` (it ignores the rest) and returns the value of the last performed evaluation. + +Examples: + +; `"IF-THEN..." <=? 2 2>> )>` ; `"IF-THEN-ELSE..." <=? 2 2>> ` + +- 36 - + +`) (ELSE ;"ELSE = T, Catch-all" )>` ; `"IF-THEN-ELSEIF-ELSEIF-ELSE... or SWITCH" ) (<=? .SWITCH 2> ) (<=? .SWITCH 3> ) (T ) >` ; `"Trigger on FIRST non-FALSE" > ) ( )>` + +## **CONS** + +``` + +``` + +``` +MDL built-in +``` + +`CONS` (“construct”) adds `first` to the front of `list` , without copying `list` , and returns the resulting `LIST` . References to `list` are not affected. + +Examples: + +``` +-->(1 2 3) + +> + +.S2-->(!\A !\B !\D) +``` + +## **CONSTANT** + +``` + +``` + +``` +ZIL library +``` + +`CONSTANT` defines an atom with value that will never be changed. The atom can is accessed inside a `ROUTINE` with `GVAL` (or `,` ) just like a `GLOBAL` atom. Defining a `CONSTANT` instead of a `GLOBAL` when possible can be vital information the compiler can use for optimization. `MSETG` is an alias for `CONSTANT` . + +- 37 - + +Example: + +``` + +... + +``` + +## **CRLF** + +``` + +``` + +``` +MDL built-in +``` + +Prints a carriage-return and a line-feed to `channel` (default for `channel` is `` ; the console). `CRLF` returns true. + +Example: + +``` +-->"\n" +``` + +## **DECL-CHECK** + +``` + +``` + +``` +MDL built-in +``` + +`DECL-CHECK` turns off or on type declaration checking. It is initially on. + +Examples: + +``` +> + +>-->Ok! + +>-->Error +``` + +## **DECL?** + +``` + +``` + +``` +MDL built-in +``` + +Predicate. `DECL?` returns `TRUE` if `value` checks against `pattern` , otherwise `FALSE` . For the format of the `pattern` , see `GDECL` . + +Examples: + +``` +;"Simple DECL" +-->T +-->T +-->#FALSE +;"OR DECL" +>-->T +>-->T +``` + +- 38 - + +``` +> +``` + +``` +-->#FALSE +``` + +``` +;"Structure DECL" +-->T +>-->#FALSE + '>-->#FALSE + '< FIX>>-->T + '< >FIX>> +-->T + FIX>>-->T + '< FIX>>-->T +``` + +``` +;"NTH DECL" +``` + +``` +> +-->#FALSE +> +-->T +>-->#FALSE +> +-->T +> +-->T +> +-->#FALSE +> +-->T +> +-->#FALSE +>-->T +> +-->T +``` + +``` +;"REST DECL" +``` + +``` +> +-->T +>-->#FALSE +>-->#FALSE +>-->T +``` + +``` +;"OPT DECL" +``` + +``` +> +``` + +``` +-->T +``` + +``` +> +``` + +``` +-->T +``` + +``` +> +-->#FALSE +> +-->T +``` + +- 39 - + +``` +>-->T +``` + +``` +;"QUOTE DECL" +-->T +-->#FALSE + ''>-->T +>-->#FALSE +;"Segment DECL" +>-->T +>-->#FALSE +>-->T +>-->T +>-->#FALSE +>-->T +;"LVAL/GVAL DECL" +-->T +-->#FALSE +-->T +-->#FALSE +>-->T +>-->T +``` + +## **DEFAULT-DEFINITION** + +``` + +``` + +``` +ZIL library +``` + +This defines a “replaceable” block with the given `name` . + +If neither `DELAY-DEFINITION` nor `REPLACE-DEFINITION` was previously called for the given `name` , then the `body` is evaluated, and this function returns the result of evaluating the last element of the `body` . + +If the block was replaced (via `REPLACE-DEFINITION` ), the replacement `body` supplied earlier is used instead. + +If the block was delayed (via `DELAY-DEFINITION` ), the `body` is ignored, and this function returns `FALSE` . + +It is possible to do the same by setting `REDEFINE` to true. This actually makes it possible to change ALL definitions (it is the last one that becomes the one actually compiled). + +See `DELAY-DEFINITION` and `REPLACE-DEFINITION` . + +Examples: + +``` + +> +``` + +- 40 - + +``` +> + +> +> +-->"Replaced version of MY-ROUTINE" +;"Alternative way" + +> + + +> +> +-->"Replaced version of MY-ROUTINE" +``` + +## **DEFAULTS-DEFINED** + +``` + +``` + +``` +ZIL library +``` + +ZILF ignores this and always returns `FALSE` . + +## **DEFINE** + +``` + +``` + +``` +MDL built-in +``` + +DEFINE assigns the global variable `name` with a `FUNCTION` . See `FUNCTION` for an explanation of `activation` , `arg-list` , `decl` and `expressions` . + +`` is equivalent to `` with the exception that `DEFINE` protects from overwriting a name with a new `FUNCTION` (this behaviour can be changed by setting `REDEFINE` to true, instead of false). + +Example: + +``` +> +-->9 +> +-->25 + )> +``` + +- 41 - + +``` +> +> + )> +> +> +-->8 +-->81 +-->1 +``` + +## **DEFINE-GLOBALS** + +``` + +``` + +``` +ZIL libary +``` + +Defines a set of macros that can be used for global storage in Z-code, similar to global variables. + +Each `atom-or-adecl` becomes the name of a new macro which can be called with no arguments (to read the global value) or one argument (to write it). The optional `initializer` sets the initial value, as in `GLOBAL` . `BYTE` or `WORD` can be specified to set the global’s size; `WORD` is the default. ZILF ignores the `group-name` . + +See `FUNNY-GLOBALS?` for a more convenient way to bypass the Z-machine’s global variable limit. (In fact, ZILF implements `DEFINE-GLOBALS` by turning on `FUNNY-GLOBALS?` and defining a global variable for each macro.) + +## **DEFINE-SEGMENT** + +``` + +``` + +``` +ZIL library +``` + +ZILF ignores this and always returns `FALSE` . + +## **DEFINE20** + +``` + +``` + +``` +ZIL library +``` + +`DEFINE20` is an alias for `DEFINE` except that it isn’t affected by MDL-ZIL mode: it always defines a MDL function. + +`DEFINE20` (and `SETG20` ) are used in "MDL-ZIL"-files, where routines are defined with `DEFINE` instead of `ROUTINE` , global variables are created with `SETG` instead of `GLOBAL` , etc. Presumably that was a way to run the games in MDL during development to avoid recompiling them. `SETG20` and `DEFINE20` are aliases for the MDL versions of `SETG` and `DEFINE` . + +- 42 - + +## **DEFINITIONS** + +``` + +``` + +``` +MDL package system +``` + +`DEFINITIONS` is exactly as `PACKAGE` except that there is no internal `OBLIST` with `DEFINITIONS` , every `ATOM` created inside the `DEFINITIONS` is on the external `OBLIST` automatically. + +To activate a package-name `INCLUDE` or `INCLUDE-WHEN` is used. + +See `END-DEFINITIONS` , `INCLUDE` , `INCLUDE-WHEN` , `PACKAGE` and `RENTRY` . Examples: + +``` +;"Define PACKAGE" + ;"Secure that ATOM not on any OBLIST" + + + + OBLIST>-->OBLIST +-->#FALSE +-->T +,ANSWER!-FOO!-PACKAGE-->42 + ;"Secure that ATOM not on any OBLIST" + +,ANSWER-->42 +``` + +## **DEFMAC** + +``` + +``` + +``` +MDL built-in +``` + +`DEFMAC` has the same syntax as `DEFINE` , but defines a `MACRO` instead of a `FUNCTION` . A `MACRO` is evaluated two times, the first evaluation inserts the arguments in the `MACRO` and creates an object that is evaluated during the second evaluation. The first evaluation is done at “top-level”, in other words during compilation. `EXPAND` is used to perform the first evaluation. + +Note that two identical calls to a `MACRO` always generate the same result from the first evaluation. Example: + +``` + .N>>> + +-->3 +>-->> +``` + +- 43 - + +## **DEFSTRUCT** + +``` + +``` + +``` +MDL built-in +``` + +`DEFSTRUCT` creates abstract record structures and creates an user-defined `TYPE.` In practice `DEFSTRUCT` builds a couple of `MACRO` s that can be used to create and access instances of the structure. + +`type-name` is the name of the new structure-type. There will also be a new `TYPE` with `type-name` and the `MACRO` , `MAKE-[type-name]` is created that can be used to create new instances of this new `TYPE` . + +The `base-type` is the container `TYPE` for this new structure-type. It is usually a `VECTOR` , `LIST` or `TABLE` . The `struct-options` are used to change the default behaviour of the `base-type` . It is possible to change the default behaviour with `SET-DEFSTRUCT-DEFAULT-FILE` . The `struct-options` are: + +`'CONSTRUCTOR` Defines a new constructor for the `MAKE- MACRO` . See examples below on how to define a new constructor. If there is no definition specified after `'CONSTRUCTOR` no `MACRO` will be created for this `type-name` . `'INIT-ARGS` Defines if there are arguments when the `base-type` is created. For example `(PURE)` when using `TABLE` as a container. Default is that there are no arguments. `'NODECL` Specifies that no `TYPE` -checking should occur when storing values in container `base-type` . Default is that there is `TYPE` -checking. `'NOTYPE` Specifies that no new `TYPE` is created for this `type-name` . Default is that a new `TYPE` is created. + +Then follows all the fields in the record. Every field has a `field-name` and a `TYPE` declaration, `decl` . The `decl` follows the ordinary syntax for declarations, see `GDECL` . The `field-options` are optional, but they can be one or more of these: + +`default-value` A default value for this field. `'NTH FUNCTION` to read fields from the container. Default `FUNCTION` is `NTH` . `'OFFSET` Index in container to store this value. `FUNCTION` is `NTH` . `'PUT FUNCTION` to insert value in this field in the container. Default `FUNCTION` is `PUT` . + +For every field in the record there is a `MACRO` created with the `field-name` that can be used to read and insert values in the field. + +Examples: + +``` +;"Create new object" + +``` + +- 44 - + +``` +> +> +-->"C Programming" +<TYPE .BOOK1>-->BOOK +<1 .BOOK2>-->"Telecom Billing" +<AUTHOR .BOOK2 "Paul Auster"> +<AUTHOR .BOOK2>-->"Paul Auster" +<MAKE-BOOK>-->("" "" "" 0) +;"Put values into existing object" +<DEFSTRUCT POINT VECTOR (POINT-X FIX) (POINT-Y FIX)> +<SET MY-VECTOR [123 456 789 1011]> +<MAKE-POINT 'POINT .MY-VECTOR 'POINT-Y 999 'POINT-X888> +-->[888 999 789 1011] +;"Use field value-default and offset" +<DEFSTRUCT RPOINT VECTOR (RPOINT-X FIX 'OFFSET 2) +(RPOINT-Y FIX 456 'OFFSET 1)> +<MAKE-RPOINT 'RPOINT-X 123>-->#RPOINT [456 123] +<RPOINT-Y #RPOINT [234 567]>-->234 +;"Create struct without creating TYPE" +<DEFSTRUCT PTNT (VECTOR 'NOTYPE) (PTNT-X FIX) (PTNT-YFIX)> +<VALID-TYPE? PTNT>-->#FALSE +<PTNT-X [123 456]>-->123 +;"Create struct without declaration checks" +<DEFSTRUCT PTND (VECTOR 'NODECL) (PTND-X FIX) (PTND-YFIX)> +<CHTYPE [FOO BAR] PTND>-->[FOO BAR] +<CHTYPE [FOO BAR] POINT>-->ERROR +;"Create struct with suppressed constructor" +<DEFSTRUCT P-C (VECTOR 'CONSTRUCTOR) (P-C FIX) (P-C-YFIX)> +<GASSIGNED? MAKE-P-C>-->#FALSE +<VALID-TYPE? P-C>-->P-C +;"Create struct with INIT-ARGS" +<DEFSTRUCT PT-TBL (TABLE ('INIT-ARGS (PURE))) +(PT-TBL-X FIX) (PT-TBL-Y FIX)> +<MAKE-PT-TBL 123 456>--> #PT-TBL %<TABLE (PURE)123 456> +;"Positional constructor arguments" +<DEFSTRUCT FOO VECTOR (FOO-A ATOM) (FOO-B <OR FIXFALSE>)> +<MAKE-FOO BAR>-->#FOO [BAR #FALSE ()] +;"Custom constructor" +<SETG NEXT-ID 0> +``` + +- 45 - + +``` +<DEFSTRUCT RGBA (VECTOR 'CONSTRUCTOR +('CONSTRUCTOR MAKE-RGBA +('RED 'GREEN 'BLUE "OPT" ('ALPHA 255) +"AUX" (RGBA-ID '<SETG NEXT-ID <+ ,NEXT-ID 1>>)))) +(RED FIX) (GREEN FIX) (BLUE FIX) (ALPHA FIX) +(RGBA-ID FIX)> +<RED <MAKE-RGBA 10 20 30>>-->10 +<RGBA-ID <MAKE-RGBA 11 22 33>>-->1 +<ALPHA <MAKE-RGBA 11 22 33>>-->255 +<ALPHA <MAKE-RGBA 11 22 33 44>>-->44 +;"Eval or not to eval arguments" +<DEFSTRUCT E-PT VECTOR (E-PT-X FIX) (E-PT-Y <OR FIXFORM>)> +<MAKE-E-PT <+ 1 2> '<+ 3 4>>-->#E-PT [3 <+ 3 4>] +;"Explicit default values" +<DEFSTRUCT PT2 VECTOR (PT2-X FIX 123) (PT2-Y FIX456) +(PT2-ID FIX <ALLOCATE-ID>)> +<SETG NEXT-ID 1> +<DEFINE ALLOCATE-ID ("AUX" (R ,NEXT-ID)) +<SETG NEXT-ID <+ ,NEXT-ID 1>> .R> +<PT2-ID <MAKE-PT2>>-->1 +<PT2-ID <MAKE-PT2>>-->2 +<PT2-ID <MAKE-PT2 'PT2-ID 1001>>-->1001 +<PT2-ID <MAKE-PT2>>-->3 +<PT2-X <MAKE-PT2 'PT2-Y 0>>-->123 +<PT2-Y <MAKE-PT2 'PT2-Y 0>>-->0 +<PT2-ID <MAKE-PT2>>-->6 +``` + +## **DELAY-DEFINITION** + +``` +<DELAY-DEFINITION name> +``` + +``` +ZIL library +``` + +`DELAY-DEFINITION` tells ZILF that a `REPLACE-DEFINITION` for `name` should be expected thus the `DEFAULT-DEFINITION` never is evaluated for the `name` . This means that `REPLACE-DEFINITION` can appear after the `DEFAULT-DEFINITION` . + +`DELAY-DEFINITION` also means that the `body` of `REPLACE-DEFINITION` will be evaluated at the place of `REPLACE-DEFINITION` . + +See `DEFAULT-DEFINITION` and `REPLACE-DEFINITION` . + +## Examples: + +; `"REPLACE can be defined after DEFAULT" <DELAY-DEFINITION FOO-ROUTINE> <DEFAULT-DEFINITION FOO-ROUTINE <DEFINE FOO () 123>> <REPLACE-DEFINITION FOO-ROUTINE <DEFINE FOO () 456>>` + +``` +<FOO>-->456 +``` + +- 46 - + +; `"DELAY means that REPLACE is evaluated at right place" <DELAY-DEFINITION BAR-ROUTINE> <SETG BAR-RESULT 789> <REPLACE-DEFINITION BAR-ROUTINE <EVAL <FORM DEFINE BAR '() ,BAR-RESULT>>> <SETG BAR-RESULT 123> <DEFAULT-DEFINITION BAR-ROUTINE <EVAL <FORM DEFINE BAR '() ,BAR-RESULT>>> <BAR> --> 789 ;"123 without DELAY"` + +## **DIR-SYNONYM** + +``` +<DIR-SYNONYM original synonyms ...> +``` + +``` +ZIL parser library +``` + +`DIR-SYNONYM` creates one or more `synonyms` to the `original` direction. + +ZILF treats `DIR-SYNONYM` as an alias to `SYNONYM` . + +## **DIRECTIONS** + +``` +<DIRECTIONS atoms ...> +``` + +``` +ZIL parser library +``` + +`DIRECTIONS` creates words in the vocabulary with the `part-of-speech DIRECTION` . `DIRECTIONS` are often defined in the parser and the order is usually tightly tied to the parser. Be careful if you change these. You can use `DIR-SYNONYM` if you, for example, want to add `FORE` , `AFT` , `PORT` and `STARBOARD` . + +Example: + +``` +<DIRECTIONS NORTH SOUTH EAST WEST NE NW SE SW IN OUTUP DOWN> +``` + +## **EMPTY?** + +``` +<EMPTY? structure> +``` + +``` +MDL built-in +``` + +Predicate. Returns true if `structure` contains no elements, otherwise false. + +`structure` must be an object that `STRUCTURED?` evaluates to true. + +Examples: + +``` +<EMPTY? [1 2 3]>-->False +<EMPTY? []>-->True +``` + +## **END-DEFINITIONS** + +``` +<END-DEFINITIONS> +``` + +- 47 - + +``` +MDL package system +``` + +`END-DEFINITIONS` is an alias to `ENDBLOCK` . + +See `DEFINITIONS` . + +## **END-SEGMENT** + +``` +<END-SEGMENT> +``` + +``` +ZIL library +``` + +ZILF ignores this and always returns `FALSE` . + +## **ENDBLOCK** + +``` +<ENDBLOCK> +``` + +``` +MDL built-in +``` + +`ENDBLOCK` pops back, rebinds and returns the local `ATOM OBLIST` to the state it had before the call to `BLOCK` . `ENDBLOCK` without previous `BLOCK` (or `PACKAGE` , `DEFINITIONS` , etc) results in an error. + +Example: + +``` +XYZZY!-MY-OBLIST +<SETG FIRST!- FOO> +<BLOCK (<GETPROP MY-OBLIST OBLIST> <ROOT>)> +<SETG SECOND!- FOO> +<ENDBLOCK> +<=? ,FIRST!- ,SECOND!->-->#FALSE +``` + +## **ENDLOAD** + +``` +<ENDLOAD> +``` + +``` +ZIL library +``` + +ZILF ignores this and always returns `FALSE` . + +## **ENDPACKAGE** + +``` +<ENDPACKAGE> +``` + +``` +MDL package system +``` + +`ENDPACKAGE` is an alias to `ENDBLOCK` . + +See `PACKAGE` . + +## **ENDSECTION** + +``` +<ENDSECTION> +``` + +- 48 - + +``` +MDL package system +``` + +`ENDSECTION` is an alias to `ENDBLOCK` . + +See `DEFINITIONS` . + +## **ENTRY** + +``` +<ENTRY atoms ...> +``` + +``` +MDL package system +``` + +`ENTRY` creates/moves one or more `ATOM` s to the external `OBLIST` in a `PACKAGE` . `ENTRY` is only valid inside a `PACKAGE` , if it's used outside an error is raised. + +See `PACKAGE` , `RENTRY` , `USE` , `USE-WHEN` . + +Examples: + +``` +<REMOVE ANSWER> ;"Secure that ATOM not on any OBLIST" +<PACKAGE "FOO"> +<SETG ANSWER 42> +<1 .OBLIST>-->#OBLIST (("ANSWER" ANSWER)) +<2 .OBLIST>-->#OBLIST (("IFOO" IFOO)) +<ENTRY ANSWER> +<1 .OBLIST>-->#OBLIST () +<2 .OBLIST>-->#OBLIST (("IFOO" IFOO) ("ANSWER"ANSWER)) +<ENDPACKAGE> +,ANSWER-->42 +``` + +## **EQVB** + +``` +<EQVB numbers ...> +``` + +``` +MDL built-in +``` + +Bitwise equivalence (inverse of exclusive “or”). Uses 32-bit. + +Examples: + +``` +<XORB 250 245>-->00000000 00000000 00000000 11111010 +00000000 00000000 00000000 11110101 +----------------------------------- +11111111 11111111 11111111 11110000 = -16 +``` + +## **ERROR** + +``` +<ERROR values ...> +``` + +``` +MDL built-in +``` + +`ERROR` raises an error ( `[error MDL0001]` ) and listing values as resources. The values are + +- 49 - + +usually a text explaining the error, offending ATOM, routine where it occurred and last any other information. + +Example: + +``` +<SET A 616> +<ERROR "MY TYPE OF ERROR." .A> +--> +[error MDL0001] <stdin>:1: ERROR: "MY TYPE OF ERROR."616 +``` + +## **EVAL** + +``` +<EVAL value [environment]> +MDL built-in +``` + +This evaluates `value` (usually a `FORM` created by `FORM` or `QUOTE` ). + +It is possible to supply an `environment` for `EVAL` . This tells `EVAL` from which `environment EVAL` should take variable bindings. See _The MDL Programming Language, chap. 9.7_ for more about the `environment` . + +Examples: + +``` +<SET F '<+ 1 2>> +.F--><+ 1 2> +<EVAL .F>-->3 +<SET A 0> +<DEFINE WRONG ('B "AUX" (A 1)) <EVAL .B>> +<DEFINE RIGHT ("BIND" E 'B "AUX" (A 1)) <EVAL .B.E>> +<WRONG .A>-->1 +<RIGHT .A>-->0 +``` + +## **EVAL-IN-SEGMENT** + +``` +<EVAL-IN-SEGMENT dummy1 value[dummy2]> +``` + +``` +ZIL library +``` + +ZILF ignores `dummy1` and the optional `dummy2` . ZILF then calls `EVAL` on the `value` and returns its result. + +Example: + +`<SET F '<+ 1 2>>` .F --> <+ 1 2> `<EVAL-IN-SEGMENT "HINTS" .F (1 2 3)> --> 3` + +## **EVALTYPE** + +``` +<EVALTYPE atom [handler]> +``` + +- 50 - + +``` +MDL built-in +``` + +`EVALTYPE` tells the `TYPE atom` how it should be evaluated by `EVAL` . If `EVALTYPE` is called without a `handler` then the currently active `handler` is returned. If there is no active `handler` , `FALSE` is returned. + +Note that it is possible to replace the `handler` with a new `handler` , even on the predefined `TYPE` s. + +See `APPLYTYPE` , `NEWTYPE` and `PRINTTYPE` . + +Example: + +``` +<NEWTYPE GRITCH LIST> +<EVALTYPE GRITCH>-->#FALSE +<EVALTYPE GRITCH LIST> ;"Evaluate GRITCH as a LIST" +<EVALTYPE GRITCH>-->LIST +#GRITCH (A <+ 1 2 3> !<SET A "BC">)-->(A 6 !\B!\C) +;"Make it like LISP!" +<EVALTYPE LIST FORM> ;"Evaluate LISTs as FORMs!" +<EVALTYPE ATOM ,LVAL> ;"Evaluate bare ATOM as LVAL!" +(+ 1 2)-->3 +(SET 'A 5) +A-->5 +``` + +## **EXPAND** + +``` +<EXPAND value> +``` + +``` +MDL built-in +``` + +`EXPAND` performs the first `EVAL` of the `value` . In case the `value` is a `MACRO` only the first `EVAL` is done. + +Example: + +``` +<DEFMAC INC2 (ATM "OPTIONAL" (N 1)) +<PARSE "<SET %.ATM <+ %.ATM %.N>>">> +<EXPAND '<INC2 X>>--><SET X <+ X 1>> +``` + +## **FILE-FLAGS** + +``` +<FILE-FLAGS {CLEAN-STACK? | MDL-ZIL? | SENTENCE-ENDS?| +ZAP-TO-SOURCE-DIRECTORY?} ...> +``` + +``` +ZIL library +``` + +This sets flags to control how ZILF should compile. To clear, call FILE-FLAGS without any flags. The flags are: + +``` +CLEAN-STACK? +``` + +Tells the compiler to generate extra code to remove unneeded values from the stack. Without it, the compiler will generate smaller code in some cases, at + +- 51 - + +``` +MDL-ZIL? +``` + +``` +SENTENCE-ENDS? +``` + +the risk of potentially causing stack overflow at runtime. Tells the compiler to treat `SETG` (at top-level) as `GLOBAL` and `DEFINE` as `ROUTINE` ( `SETG20` and `DEFINE20` always works as in MDL). Presumably that was a way to run the games in MDL during development without recompiling them. Tells the compiler (only version 6) to treat two spaces after a period or a question mark as the end of a sentence in TELL. Note: a space followed by an embedded newline wil produce two spaces instead of collapsing. + +`ZAP-TO-SOURCE-DIRECTORY?` ZILF ignores this. + +Examples: + +``` +<FILE-FLAGS CLEAN-STACK? MDL-ZIL?>--> Set both flags +``` + +``` +<FILE-FLAGS MDL-ZIL?> +<SETG X 123>;"This compiles as GLOBAL" +<DEFINE MDL-ZIL-TEST () <TELL N X CR>>;"This compilesas a +ROUTINE" +``` + +``` +<FILE-FLAGS SENTENCE-ENDS?> +<ROUTINE SENTENCE-ENDS-TEST () +<TELL \"Hi. Hi. Hi.| Hi! Hi? Hi. \nHi.\" CR>"> +-->"Hi.\u000bHi.\u000b Hi.\n Hi!\u000bHi?\u000bHi.Hi.\n" +``` + +## **FILE-LENGTH** + +``` +<FILE-LENGTH channel> +``` + +``` +MDL built-in +``` + +`FILE-LENGTH` returns the size, in bytes, of the file on `channel` . `FILE-LENGTH` returns `FALSE` if the file is closed. + +Example: + +; `"ZILF ver 0.9" <SET CH <OPEN "READ" "../zillib/parser.zil">> <FILE-LENGTH .CH> --> 115629 <CLOSE .CH>` + +## **FLOAD** + +``` +<FLOAD filename> +``` + +``` +MDL built-in +``` + +ZILF ignores all but the first argument and treats `FLOAD` as an alias to `INSERT-FILE` . + +- 52 - + +## **FORM** + +``` +<FORM values ...> +``` + +``` +MDL built-in +``` + +This creates a `FORM` without evaluating it. This is analogous to `LIST` and `VECTOR` but with " `<>` " instead of " `()` " or " `[]` ". In many cases it is possible to use `QUOTE` to achieve the same result. Examples: + +``` +<FORM + 1 2>--><+ 1 2> +<DEFINE INC-FORM (A) +<FORM SET .A <FORM + 1 <FORM LVAL .A>>>> +<INC-FORM X>--><SET X <+ 1 .X> +``` + +## **FREQUENT-WORDS?** + +``` +<FREQUENT-WORDS?> +``` + +``` +ZIL library +``` + +ZILF ignores this and always returns `FALSE` . Frequent words table is built by ZAPF instead. + +## **FUNCTION** + +``` +<FUNCTION [activation] arg-list [decl] expressions...> +#FUNCTION ([activation] arg-list [decl] expressions...) +``` + +``` +MDL built-in +``` + +This creates a `FUNCTION` . When a `FUNCTION` is called it evaluates all the `expressions` and returns the result of the last expression. + +The `arg-list` is a `LIST` of arguments for the `FUNCTION` . Besides the arguments to the `FUNCTION` , `arg-list` can also contain these tokens (in this order): + +`"BIND"` Followed by an `ATOM` that binds the `ATOM` to the `ENVIRONMENT` when the `FUNCTION` was applied. See `EVAL` for example on this. `Arguments` The required `arguments` for this `FUNCTION` . The `arguments` are bound to local variables inside this `FUNCTION` . `"OPT"` The optional `arguments` for this `FUNCTION` . The `arguments` are bound to local variables inside this `FUNCTION` and can be defined with a default value. `"OPTIONAL"` is an alias for `"OPT"` . `"ARGS"` Followed by an `ATOM` that is bound a `LIST` of all remaining arguments, unevaluated. If `"ARGS"` appears in arg-list, `"TUPLE"` should not appear. `"TUPLE"` Followed by an `ATOM` that is bound a `TUPLE` of all remaining arguments, evaluated. If `"TUPLE"` appears in arg-list, `"ARGS"` should not appear. See `TUPLE` for example on this. `"AUX"` Followed by any number of `ATOM` s that becomes local variables inside this `FUNCTION` and can be defined with a default value. `"EXTRA"` + +- 53 - + +is a alias for `"AUX"` . + +`"NAME"` Followed by an `ATOM` that becomes the `activation` for this `FUNCTION` . This is equivalent to naming the `activation` before the `arg-list` . `"ACT"` is an alias for `"NAME"` . See `AGAIN` for example on this. + +Default values for `"OPT"` and `"AUX"` are defined by a two-element `LIST` whose first element is the `ATOM` and the second element is assigned to. + +``` +<FUNCTION ("AUX" (X 1) (Y 2)) <+ .X .Y>> +``` + +Means that the local variables `X` and `Y` are initially assigned 1 and 2. + +`FUNCTION` is its own `TYPE` and it is perfectly legal to, for example, use `#FUNCTION` instead to create a `FUNCTION` . + +Usually a `FUNCTION` is assigned to a global variable. This can be done by assigning a global `ATOM` the `FUNCTION` with `SETG` (this is more commonly done with `DEFINE)` . + +Examples: + +``` +<<FUNCTION (X1 X2) <+ .X1 .X2>> 5 4>-->9 +<SETG SQUARE <FUNCTION (X) <* .X .X>>> +<SQUARE 5>-->25 +<SETG POWER-TO <FUNCTION ACT (X "OPT" (Y 2)) +<COND (<=? .Y 0> <RETURN 1 .ACT>)> +<REPEAT ((Z 1)(I 0)) +<SET Z <* .Z .X>> +<SET I <+ .I 1>> +<COND (<=? .I .Y> <RETURN .Z>)> +> +>> +<POWER-TO 2 3>-->8 +<POWER-TO 3 4>-->81 +<POWER-TO 3 0>-->1 +``` + +## **FUNNY-GLOBALS?** + +``` +<FUNNY-GLOBALS? [boolean]> +``` + +``` +ZIL library +``` + +When enabled, “funny globals” mode lets the game define more than the usual 240 global variables. + +If needed, ZILF will move the extra variables into a table (GLOBAL-VARS-TABLE) and generate table instructions to access them ( `PUT` and `GET` , or in the case of `BYTE` globals created with `DEFINE-GLOBALS` , `PUTB` and `GETB` ). + +This translation is mostly transparent to game source code, but it can’t be used for global variables that are ever referenced indirectly by number. ZILF uses a simple heuristic to try to identify those variables and reserve “real” global variable slots for them. + +## **G=?** + +``` +<G=? value1 value2> +``` + +- 54 - + +``` +MDL built-in +``` + +Predicate. True if `value1` is greater or equal than `value2` otherwise false. + +## **G?** + +``` +<G? value1 value2> +``` + +``` +MDL built-in +``` + +Predicate. True if `value1` is greater than `value2` otherwise false. + +## **GASSIGNED?** + +``` +<GASSIGNED? Atom> +``` + +``` +MDL built-in +``` + +Predicate. Returns true if the `atom` has an `GVAL` (global value). + +Example: + +< `GASSIGNED? X> --> False <SETG X 1> <GASSIGNED? X> --> True` + +## **GBOUND?** + +``` +<GBOUND? atom> +``` + +``` +MDL built-in +``` + +`GBOUND?` Is a predicate that returns true if the `atom` ever had a global value. Examples: + +``` +<SETG X 42> +<GASSIGNED? X>-->True +<GBOUND? X>-->True +<GUNASSIGN X> +<GASSIGNED? X>-->False +<GBOUND? X>-->True +``` + +## **GC** + +``` +<GC> +``` + +``` +MDL built-in +``` + +This causes garbage collection. + +In ZILF `GC` ignores all arguments and always returns true. ZILF relies on the garbage collection in + +- 55 - + +the NET framework and only implements this for compatibility. Examples: + +``` +<GC>-->T +<GC 0 T 5>-->T +``` + +## **GC-MON** + +``` +<GC-MON> +``` + +``` +MDL built-in +``` + +ZILF ignores this and always returns `FALSE` . + +## **GDECL** + +``` +<GDECL (atoms ...) decl ...> +``` + +``` +MDL built-in +``` + +`GDECL` declares the type/structure of the global value of `ATOM` s. `GDECL` pairs a `LIST` of `atoms` with a `decl` pattern, this can then be repeated indefinitely. + +The `decl` pattern can contain the following: + +A `TYPE` name The `atoms TYPE` must be of this `TYPE` . This can be generalized slightly by using `<PRIMTYPE type>` , which means that the `atom` s `TYPE` must have the same `PRIMTYPE` as `type` . `ANY` The `atom` can be of any `TYPE` . `STRUCTURED` Means that `<STRUCTURED? atom>` must be `TRUE` ( `atom` is for example a `LIST` , `VECTOR` or `STRING` ). `APPLICABLE` Means that `<APPLICABLE? atom>` must be `TRUE` ( `atom` is for example a `FIX` , `FUNCTION` or `MACRO` ). A `QUOTE` d `ATOM` Means that the `atom` must be `=?` with the `QUOTE` d `ATOM` . + +If the `decl` pattern is `STRUCTURED` it is possible to specify a pattern for the structure. This has the following syntax: + +`<structure patterns ...>` This means that the `structure` must follow the defined `pattern` (so long it is defined). Items in the `structure` at positions beyond the defined `pattern` can be of any `TYPE` . + +This means that, for example, `<GDECL (X) <LIST FIX ANY FIX>>` is declaring that `X` must be a `LIST` (at least of `LENGTH` 3), with a `FIX` in position 1 and 3 and any `TYPE` in position 2 and position 4 and beyond. + +`<SETG X (1 2 3)>` is legal `<SETG X (1 2 3 4)>` is legal `<SETG X (1 2 3 !\A)>` is legal `<SETG X (1 2)>` is illegal `<SETG X (!\A 2 3)>` is illegal + +Normally the pattern for structures defines that the structure should at least contain these elements, + +- 56 - + +but it can contain additional items. If you want to disallow additional items , a `SEGMENT` is used instead of a `FORM` . `<GDECL (X) !<LIST FIX ANY FIX>>` means that the `LIST` must have exactly `LENGTH` 3. + +`<SETG X (1 2 3)>` is legal `<SETG X (1 2 3 4)>` is illegal `<SETG X (1 2 3 !\A)>` is illegal `<SETG X (1 2)>` is illegal `<SETG X (!\A 2 3)>` is illegal + +The pattern in this construction can in turn be defined to repeat itself by the syntax: + +`[number patterns ...]` Means that specified `pattern` should repeat itself `number` of times. `[REST patterns ...]` Means that specified `pattern` should repeat itself indefinitely. If this is defined it must be the last in the structure declaration. `[OPT patterns ...]` Means that this `structure` can either be empty or follow the defined `pattern` . Only a `REST` construction can follow `OPT` . + +Finally, it is allowed to specify several possible `decl` to an atom with the compound `decl OR` . + +`<OR decl ...>` This means that the `atoms` can be one of the specified `decl` . Each of the `decl` follow the same rules as above. + +Examples: + +``` +X must be: +<GDECL (X) FIX>-->FIX +<GDECL (X) <OR FIX STRING>>-->FIX or STRING +<GDECL (X) <LIST FIX>-->LIST with FIX in pos 1 +<GDECL (X) <LIST [3 FIX]>-->LIST with FIX in pos1-3 +<GDECL (X) <LIST [REST FIX]>-->LIST with only FIX +<GDECL (X) <LIST [OPT FIX] [REST FIX]>> +-->Empty LIST or LIST containing FIX +``` + +``` +See DECL? for more examples on how to format decl. +``` + +## **GET-DECL** + +``` +<GET-DECL item> +``` + +``` +MDL built-in +``` + +`GET-DECL` returns the `pattern` defined to the `item` . It returns `FALSE` if no `item` exists. See `DECL?` , `GDECL` and `PUT-DECL` for more on declaration patterns. Examples: + +``` +<GET-DECL BOOLEAN>-->#FALSE +<PUT-DECL BOOLEAN '<OR ATOM FALSE>> +<GET-DECL BOOLEAN>--><OR ATOM FALSE> +``` + +- 57 - + +## **GETB** + +``` +<GETB table index> +``` + +``` +ZIL library +``` + +Returns BYTE-record (1 byte) stored at `index` . + +`TABLE` is a ZIL-specific structure that can be used both outside and inside `ROUTINES` . `GETB` is equivalent to the Z-code built-in `GETB` . + +Also see `PUTB` , `ZGET` , `ZPUT` and `ZREST` . + +Example: + +``` +<GETB <TABLE (BYTE) !\A !\B !\C !\D> 2>-->!\C +``` + +## **GETPROP** + +``` +<GETPROP item indicator [default-value]> +``` + +``` +MDL built-in +``` + +`GETPROP` returns the property-value stored under `indicator` on `item` . If no value can be found `GETPROP` returns the default-value or `FALSE` if no default-value is given. + +See `ASSOCIATIONS` , `AVALUE` , `INDICATOR` , `ITEM` , `NEXT` and `PUTPROP` . + +Examples: + +``` +<PUTPROP FOO BAR BAZ> +<GETPROP FOO BAR>--> BAZ +<GETPROP FOO BAZ>--> #FALSE +<GETPROP FOO BAZ "Value not found."> --> "Value notfound." +<SET L (1 2 3)> +<PUTPROP .L FOO 456> +.L--> (1 2 3) +<GETPROP .L FOO>--> 456 +``` + +## **GLOBAL** + +``` +<GLOBAL atom default-value [decl] [size]> +``` + +``` +ZIL library +``` + +Declare a global variable `atom` , that later can be used inside a `ROUTINE` . The variable is initialized with `default-value` . + +ZILF ignores the `decl` . + +Example _:_ + +``` +<GLOBAL MYVAR 0> +``` + +- 58 - + +## **GROW** + +``` +<GROW vector end beginning> +``` + +``` +MDL built-in +``` + +`GROW` expands the `vector` with `end` and/or `beginning` number of elements to respectively end of the `vector` . Only non-negative values for end and beginning are valid. The new elements have `FALSE` as an initial value. + +If elements are added to the `beginning` of a `vector` all old references to that `vector` have to use `TOP` or `BACK` to access the new elements. + +Examples: + +``` +<SET V1 [1 2 3]> +<SET V2 <GROW .V1 1 1>> +<LVAL V1>-->[1 2 3 #FALSE ()] +<LVAL V2>-->[#FALSE () 1 2 3 #FALSE ()] +<2 .V1 4> +<LVAL V1>-->[1 4 3 #FALSE ()] +<LVAL V2>-->[#FALSE () 1 4 3 #FALSE ()] +<TOP .V1>-->[#FALSE () 1 4 3 #FALSE ()] +``` + +## **GUNASSIGN** + +``` +<GUNASSIGN atom> +``` + +``` +MDL built-in +``` + +Unassign global `atom` . + +Example: + +``` +<SETG X 1> +<GASSIGNED? X>-->True +<GUNASSIGN X> +<GASSIGNED? X>-->False +``` + +## **GVAL** + +``` +<GVAL atom> +,atom;"Alternative syntax" +MDL built-in +``` + +Get the value of the global `atom` . More often used in its short form " `,atom` ". Example: + +``` +<SETG X 5> +``` + +``` +<GVAL X>-->5 +``` + +- 59 - + +``` +,X-->5 +``` + +## **IFFLAG** + +``` +<IFFLAG (condition body ...) ...> +``` + +``` +ZIL library +``` + +Each `condition` is either: + +- A `STRING` naming a compilation flag, to evaluate the corresponding `body` if the flag’s value is true. + +- An `ATOM` whose `PNAME` names a compilation flag, to evaluate the corresponding `body` if the flag’s value is true. + +- A `FORM` , to evaluate the `FORM` after replacing any element `ATOM` s whose `PNAME` s name compilation flags with the flag values, and then evaluate the corresponding `body` if the result is true. + +- Any other value, to evaluate the corresponding `body` immediately. + +As soon as any `body` is evaluated, the function returns the result. If no `body` is evaluated, the function returns `FALSE` . + +Note: as a consequence of the evaluation rules above, undefined compilation flags are effectively `TRUE` . + +Example: + +``` +<COMPILATION-FLAG MYFLAG <>> +<IFFLAG (MYFLAG <SETG FOO "NOT OFF">) (T <SETG FOO"OFF">)> +,FOO-->"OFF" +``` + +## **ILIST** + +``` +<ILIST count [init]> +MDL built-in +``` + +ILIST ("implicit" or "iterated") returns a `LIST` with `count` items all set to `init` . Examples: + +``` +<ILIST 4 2>-->(2 2 2 2) +<SET A 0> +<ILIST 4 '<SET A <+ .A 1>>>-->(1 2 3 4) +``` + +## **IMAGE** + +``` +<IMAGE ch [channel]> +``` + +``` +MDL built-in +``` + +`IMAGE` prints the actual raw character with number `ch` to `channel` . No extra characters are ever printed. `IMAGE` returns `ch` . + +- 60 - + +Example: + +``` +<DEFINE FOO () +<IMAGE 70> +<IMAGE 79> +<IMAGE 79> +<CRLF>> +<FOO>-->"FOO" +``` + +## **INCLUDE** + +``` +<INCLUDE package-name ...> +``` + +``` +MDL package system +``` + +`INCLUDE` activates one or many `package-name` s and makes its content available in the current `OBLIST` -path. In practice `INCLUDE` copies the `OBLIST package-name` and adds it last to the local `OBLIST` ( `<LVAL OBLIST>` ). This means that all `ATOM` s on the `DEFINITIONS OBLIST` becomes available in current environment. + +If the `package-name` is not available in the current environment, `INCLUDE` tries to load “ `package-name.zil` ” from the current path. + +`INCLUDE` only works together with `DEFINITIONS` and if the definition of the `package-name` is missing from the environment or no file is found containing that definition is found, an error is raised. + +See `DEFINITIONS` and `INCLUDE-WHEN` . + +Example: + +``` +<INCLUDE "FOOFOO">;"Searches for file "foofoo.zil"which +contains the definition for +<DEFINITIONS "FOOFOO"> ..." +``` + +## **INCLUDE-WHEN** + +``` +<INCLUDE-WHEN condition package-name ...> +``` + +``` +MDL package system +``` + +`INCLUDE-WHEN` is exactly like `INCLUDE` but only activates the `package-name` if the `condition` evaluates to `TRUE` . + +See `DEFINITIONS` and `INCLUDE` . + +Example: + +``` +<DEFINITIONS "FOO"> +<SETG AAAA 1234> +<END-DEFINITIONS> +<GASSIGNED? AAAA>-->#FALSE +<REMOVE AAAA> ;"Secure that ATOM not on any OBLIST" +<INCLUDE-WHEN <=? 1 2> "FOO"> +``` + +- 61 - + +``` +<GASSIGNED? AAAA>-->#FALSE +<REMOVE AAAA> ;"Secure that ATOM not on any OBLIST" +<INCLUDE-WHEN <=? 1 1> "FOO"> +,AAAA-->1234 +``` + +## **INDENT-TO** + +``` +<INDENT-TO position [channel]> +``` + +``` +ZIL library +``` + +`INDENT-TO` places the cursor at the `position` on `channel` . Default value for the `channel` is `.OUTCHAN` (the console). + +Example: + +``` +<DEFINE PRINT-2-COL (LST) +<REPEAT ((I 0)) +<SET I <+ .I 1>> +<COND (<G? .I <LENGTH .LST>> <RETURN>)> +<COND (<1? <MOD .I 2>> +<INDENT-TO 3> +<PRINC <.I .LST>>) +(T <INDENT-TO 15> +<PRINC <.I .LST>> +<CRLF>)>> +<CRLF>> +<PRINT-2-COL ("Apple" "Banana" "Orange" "Lime")> +-->Apple Banana +OrangeLime +``` + +## **INDEX** + +``` +<INDEX offset> +``` + +``` +MDL built-in +``` + +`INDEX` returns the `index` -part of an `OFFSET` . + +Example: + +``` +<SETG OFF3 <OFFSET 3 '<VECTOR> 'STRING>> +<INDEX ,OFF3>-->3 +``` + +## **INDICATOR** + +``` +<INDICATOR asoc> +``` + +``` +MDL built-in +``` + +`INDICATOR` returns the indicator part from an `asoc` entry, of `TYPE ASOC` , in the `ASSOCIATION` chain. + +- 62 - + +See `ASSOCIATIONS` , `AVALUE` , `GETPROP` , `ITEM` , `NEXT` and `PUTPROP` . Example: + +``` +<DEFINE LAST-ASOC () +<REPEAT ((A <ASSOCIATIONS>)) +<COND (<=? .A <>> <RETURN <>>) +(<=? <NEXT .A> <>> <RETURN .A>)> +<SET A <NEXT .A>>>> +<PUTPROP NEW-ASOC TEXT "Hello, world!"> +<SET A <LAST-ASOC>> +<INDICATOR .A>-->TEXT +``` + +## **INSERT** + +``` +<INSERT atom | pname oblist> +``` + +``` +MDL built-in +``` + +`INSERT` creates an `ATOM` with the `pname` and inserts it into `oblist` . `INSERT` returns the newly created `ATOM` (or raises an error if the `ATOM` already was on the `oblis` t). First argument can also be an `atom` but this `ATOM` can not be on any `OBLIST` and therefore must be newly created by `ATOM` or recently `REMOVE` d. + +`INSERT` requires that you specify `oblist` , if you want to create an `ATOM` on the standard `OBLIST` , usually `<1 .OBLIST>` , you can use `<PARSE string>` instead. + +Note that you also can use trailers to both create the `ATOM` and the `OBLIST` (or one of them). `atom!-oblist` inserts the `atom` on the `oblist` and if one of them or both don’t exist, they are created. + +Examples: + +``` +<INSERT "FOO-1" <MOBLIST OB>>-->FOO-1!-OB +<INSERT <ATOM "FOO-2"> <MOBLIST OB>>-->FOO-2!-OB +<INSERT <REMOVE "FOO-2" <MOBLIST OB>> <MOBLIST OB2>> +-->FOO-2!-OB2 +``` + +``` +<INSERT FOO-3 <MOBLIST OB>> +``` + +``` +-->Error (Interpreter already placed it on <1.OBLIST> +;"Returns FOO from OB. Creates ATOM/OBLIST if needed." +<OR <LOOKUP "FOO" <MOBLIST OB>> <INSERT "FOO" <MOBLISTOB>> +-->FOO!-OB +FOO!-OB-->FOO!-OB +BAR!-OB-->BAR!-OB +<MOBLIST OB>-->#OBLIST (("FOO" FOO!-OB) ("BAR"BAR!-OB)) +``` + +## **INSERT-FILE** + +``` +<INSERT-FILE filename> +``` + +``` +ZIL library +``` + +- 63 - + +Insert file with `filename` at this point. If extension is omitted, ".zil" is assumed. + +The `filename` can have an absolute or relative path. If no path is given, the compiler looks in the current library and the libraries specified to the compiler with the `-ip` switch. + +Note that path is specified like in Linux (forward slashes etc.) and uppercase/lowercase can be significant, depending on the host system. + +ZILF ignores all but the first argument. + +Examples: + +``` +<INSERT-FILE "rooms">-->Include "rooms.zil" from +current directory +<INSERT-FILE "zillib/parser">-->Include "parser.zil"from +subdir "zilllib" +``` + +## **ISTRING** + +``` +<ISTRING count [init]> +``` + +``` +MDL built-in +``` + +`ISTRING` ("implicit" or "iterated") returns a `STRING` with `count` items all set to `init` (character). + +Examples: + +``` +<ISTRING 4 !\A>-->"AAAA" +<SET A 64> +<ISTRING 4 '<ASCII <SET A <+ .A 1>>>>-->"ABCD" +``` + +## **ITABLE** + +``` +<ITABLE [specifier] count [(flags...)] defaults ...> +``` + +``` +ZIL library +``` + +Defines a table of `count` elements filled with default values: either zeros or, if the `default` list is specified, the specified list of values repeated until the table is full. + +The optional `specifier` may be the atoms `NONE` , `BYTE` , or `WORD` . `BYTE` and `WORD` change the type of the table and also turn on the length marker (element 0 in the table contains the length of the table), This can also be done with the flags (see `TABLE` about flags). + +Examples: + +``` +<ITABLE 4 0> --> +``` + +|`<ITABLE 4`|`0> -->`||| +|---|---|---|---| +|`Element 0`<br>`WORD`|`Element 1`<br>`WORD`|`Element 2`<br>`WORD`|`Element 3`<br>`WORD`| +|`0`|`0`|`0`|`0`| + + + +- 64 - + +|`<ITABLE (BYTE LENGTH) 4 0>-->`|`<ITABLE (BYTE LENGTH) 4 0>-->`|`<ITABLE (BYTE LENGTH) 4 0>-->`|`<ITABLE (BYTE LENGTH) 4 0>-->`|`<ITABLE (BYTE LENGTH) 4 0>-->`| +|---|---|---|---|---| +|`Element 0`<br>`BYTE`|`Element 1`<br>`BYTE`|`Element 2`<br>`BYTE`|`Element 3`<br>`BYTE`|`Element 4`<br>`BYTE`| +|`4`|`0`|`0`|`0`|`0`| + + + +``` +<ITABLE BYTE 4 0>--> +``` + +|`Element 0`<br>`BYTE`|`Element 1`<br>`BYTE`|`Element 2`<br>`BYTE`|`Element 3`<br>`BYTE`|`Element 4`<br>`BYTE`| +|---|---|---|---|---| +|`4`|`0`|`0`|`0`|`0`| + + + +`TABLE` is a ZIL-specific structure that can be used both outside and inside `ROUTINES` . + +## **ITEM** + +``` +<ITEM asoc> +``` + +``` +MDL built-in +``` + +`ITEM` returns the item part from an `asoc` entry, of `TYPE ASOC` , in the `ASSOCIATION` chain. See `ASSOCIATIONS` , `AVALUE` , `GETPROP` , `INDICATOR` , `NEXT` and `PUTPROP` . Example: + +``` +<DEFINE LAST-ASOC () +<REPEAT ((A <ASSOCIATIONS>)) +<COND (<=? .A <>> <RETURN <>>) +(<=? <NEXT .A> <>> <RETURN .A>)> +<SET A <NEXT .A>>>> +``` + +``` +<PUTPROP NEW-ASOC TEXT "Hello, world!"> +<SET A <LAST-ASOC>> +<ITEM .A>-->NEW-ASOC +``` + +## **IVECTOR** + +``` +<IVECTOR count [init]> +``` + +``` +MDL built-in +``` + +`IVECTOR` ("implicit" or "iterated") returns a `VECTOR` with `count` items all set to `init` . Examples: + +``` +<IVECTOR 4 2>-->[2 2 2 2] +<SET A 0> +<IVECTOR 4 '<SET A <+ .A 1>>>-->[1 2 3 4] +``` + +## **L=?** + +``` +<L=? value1 value2> +``` + +- 65 - + +``` +MDL built-in +``` + +Predicate. True if `value1` is lower or equal than `value2` otherwise false. + +## **L?** + +``` +<L? value1 value2> +``` + +``` +MDL built-in +``` + +Predicate. True if `value1` is lower than `value2` otherwise false. + +## **LANGUAGE** + +``` +<LANGUAGE name [escape-char] [change-chrset]> +``` + +``` +ZIL library +``` + +The language setting changes how text is encoded in two ways: it lets you write language-specific characters in ZIL source code by adding a prefix to ASCII characters, and it changes the Z-machine alphabet to encode them more efficiently. + +If `change-chrset` is false, the Z-machine character set won’t be changed, so the language setting will only affect how source code is read. + +The `escape-char` is `!\%` by default, meaning that language-specific characters may be used in strings or atoms by adding a percent sign prefix (e.g. `%s` for ß). + +The `name` may be `GERMAN` , or `DEFAULT` to stick with classic ZSCII. + +`GERMAN` is defined as follows: + +- Alphabet 0: `abcdefghiklmnoprstuwzäöü.,` + +- Alphabet 1: `ABCDEFGHIKLMNOPRSTUWZjqvxy` + +- Alphabet 2: `0123456789!?'-:()JÄÖÜß«»` + +- Special characters: `ä(%a), ö(%o), ü(%u), ß(%s), Ä(%A), Ö(%O), Ü(%U), «(%<), »(%>)` + +## **LEGAL?** + +``` +<LEGAL? value> +``` + +``` +MDL built-in +``` + +`LEGAL?` is a predicate that returns `TRUE` if portion of the stack value occupies is still active, otherwise `FALSE` . Although `LEGAL?` works for all `TYPE` s, it’s only useful for those `TYPE` s that live on the stack, like `TUPLE` , `activation` and `environment` , all other types always return `TRUE` . + +Examples: + +``` +;"Activation" +<DEFINE FOO ACT () <SETG ACT .ACT> <LEGAL? .ACT>> +``` + +- 66 - + +``` +<FOO>-->T;"ACT legal inside function" +<LEGAL? ,ACT>-->#FALSE ;"ACT illegal outside function" +;"Environment" +<DEFINE BAR () <BAZ>> +<DEFINE BAZ ("BIND" ENV) <SETG ENV .ENV> <LEGAL?.ENV>> +<BAR>-->T;"Sets ENV to BARs environment" +<LEGAL? ,ENV>-->#FALSE ;"BARs environment illegal" +<BAZ>-->T;"Sets ENV to ROOT environment" +<LEGAL? ,ENV>-->T;"ROOTs environment alwayslegal" +``` + +## **LENGTH** + +``` +<LENGTH structure> +``` + +``` +MDL built-in +``` + +Return the number of elements in `structure` . + +`structure` must be an object that `STRUCTURED?` evaluates to true. + +Note that `TABLE` is not a `structure` . + +Also see `BACK` , `NTH` , `PUT` , `REST` , `SUBSTRUC` and `TOP` . + +Example: + +``` +<LENGTH <LIST 1 2 3>>-->3 +``` + +## **LENGTH?** + +``` +<LENGTH? structure limit> +``` + +``` +MDL built-in +``` + +`LENGTH?` is a predicate that returns false if `LENGTH` of `structure` is greater than `limit` , otherwise true (it actually returns `LENGTH` of `structure` ). + +`LENGTH?` answers the question: "is `LENGTH` of `structure` less or equal to `limit` ?" + +Examples: + +``` +<LENGTH? (1 2 3) 1>-->False +<LENGTH? (1 2 3) 3>-->3 +<NOT <NOT <LENGTH? (1 2 3) 4>>>-->True +``` + +## **LINK** + +``` +<LINK value str oblist> +``` + +``` +MDL built-in +``` + +`LINK` links a `value` to `PNAME str` . The `PNAME` is placed in the specified `oblist` . `LINK` has the effect that when the MDL encounters the `str` it immediately replaces it with the `value` . `LINK` is primarily used in interactive mode to replace phrases that are annoyingly long to type. + +- 67 - + +Example: + +``` +<LINK '<INSERT-FILE "HEDGEMAZE"> "H" <ROOT>> +H-->Tries to load the file "HEDGEMAZE" +``` + +## **LIST** + +``` +<LIST values ...> +(values ...);"Alternative syntax" +MDL built-in +``` + +Returns a list of containing `values` . + +A list is a collection of items where each item has a pointer to the next item in the collection. This makes it easy to add and insert items in lists but a list is always forward looking. See more about `LIST` structure in _The MDL Programming Language, Appendix 1_ . + +Example: + +``` +<LIST 1 2 "AB" !\C>-->(1 2 "AB" !\C) +(1 2 "AB" !\C)-->(1 2 "AB" !\C) +``` + +## **LONG-WORDS?** + +``` +<LONG-WORDS? [boolean]> +``` + +``` +ZIL library +``` + +The `boolean` , which defaults to true if omitted, tells the compiler whether to generate the `CONSTANT LONG-WORDS-TABLE` . + +`LONG-WORDS-TABLE` contains an entry for each vocab word whose length exceeds the maximum word length for the selected Z-machine version (6 Z-characters for V3, or 9 Z-characters for V4+). The table is prefixed by the number of entries, and each entry consists of a word pointer followed by a string giving the printed form of the word. + +For example, the table might be defined as equivalent to: + +``` +<CONSTANT LONG-WORDS-TABLE +<TABLE 2 +,W?HEMIDEMIS "hemidemisemiquaver" +,W?SUPERCALI "supercalifragilisticexpialidocious">> +``` + +Example: + +``` +<VERSION 5> +<LONG-WORDS? T> +<OBJECT FOO (SYNONYM HEMIDEMISEMI)> +<VOC "SUPERCALIFRAG"> +``` + +``` +<ROUTINE GO () +<TELL "Table length = " N <GET ,LONG-WORD-TABLE0> CR> +<TELL "W?SUPERCALIFRAG = " N ,W?SUPERCALIFRAG CR> +``` + +- 68 - + +``` +<TELL "WORD 1 = " N <GET ,LONG-WORD-TABLE 1> CR> +<TELL "WORD 2 = " <GET ,LONG-WORD-TABLE 2> CR> +<TELL "W?HEMIDEMISEMI = " N ,W?HEMIDEMISEMI CR> +<TELL "WORD 3 = " N <GET ,LONG-WORD-TABLE 3> CR> +<TELL "WORD 4 = " <GET ,LONG-WORD-TABLE 4> CR> +``` + +``` +> +``` + +## **LOOKUP** + +``` +<LOOKUP string oblist> +``` + +``` +MDL built-in +``` + +`LOOKUP` returns the `ATOM` with `PNAME string` from `oblist` . It returns `FALSE` if no `ATOM` is found. + +Examples: + +``` +<LOOKUP "FIX" <ROOT>>-->FIX +FOO!-MYOBLIST +<LOOKUP "FOO" <ROOT>>-->#FALSE +<LOOKUP "FOO" <MOBLIST MYOBLIST>>-->FOO!-MYOBLIST +``` + +## **LPARSE** + +``` +<LPARSE text [10] [lookup-oblist]> +``` + +``` +MDL built-in +``` + +`LPARSE` ("list parse") is just like `PARSE` with the exception that `LPARSE` returns a `LIST` of all the expressions in the `text` . + +ZILF requires that the second argument is `10` if a `lookup-oblist` is given. + +Examples: + +``` +<LPARSE "1 FOO [3]">-->(1 FOO [3]) +<LPARSE " ">-->() +<SET A 0> +<DEFINE NXT () <SET A <+ .A 1>>> +<LPARSE "%<NXT> %<NXT> %<NXT>">-->(1 2 3) +``` + +## **LSH** + +``` +<LSH number places> +``` + +``` +MDL built-in +``` + +Bitwise shift. Shift `number` left when `places` is positive and right if it is negative. When right shifting the sign is not preserved (0 is always shifted in). + +``` +1000 0000 0000 1010-->0100 0000 0000 0101 +``` + +- 69 - + +Examples: + +``` +<LSH 4 1>-->8 +<LSH 4 -2>-->1 +``` + +## **LTABLE** + +``` +<LTABLE [(flags ...)] values ...> +``` + +``` +ZIL library +``` + +Defines a table containing the specified `values` and with the `LENGTH` flag (see `TABLE` about `LENGTH` and other flags). + +`TABLE` is a ZIL-specific structure that can be used both outside and inside `ROUTINES` . + +## **LVAL** + +``` +<LVAL atom [environment]> +.atom;"Alternative syntax" +MDL built-in +``` + +Get the value of the local `atom` . More often used in its short form " `.atom` ". + +It is possible to supply an `environment` for `LVAL` . See `EVAL` for more about the `environment` . + +Example: + +``` +<SET X 5> +<LVAL X>-->5 +.X-->5 +``` + +## **M-HPOS** + +``` +<M-HPOS channel> +``` + +``` +ZIL library +``` + +`M-HPOS` returns the current horizontal cursor position on `channel` . Example: + +``` +<PRINC "Hello"><M-HPOS .OUTCHAN>-->Hello5 +``` + +## **MAKE-GVAL** + +``` +<MAKE-GVAL atom> +``` + +``` +ZIL library +``` + +`MAKE-GVAL` returns the `atom` as `GVAL` ( `,atom` ). + +- 70 - + +Example: + +``` +<SET FOO BAR> +<SETG BAR 123> +<MAKE-GVAL .FOO>-->,BAR +<EVAL <MAKE-GVAL .FOO>>-->123 +``` + +## **MAPF** + +``` +<MAPF finalf applicable structs ...> +``` + +``` +MDL built-in +``` + +`MAPF` ("map first") traverses over all `structs` one element at a time until one of the `structs` is out of elements and calls the function `applicable` with the elements. In other words, the first iteration takes the first element from each of the `structs` and calls `applicable` , the second iteration takes the second element from each of the `structs` and calls `applicable` , and so on until one of the `structs` doesn't have any more elements. The intermediate results from each call to `applicable` is stored in a `TUPLE` . + +The `finalf` can either be a `FUNCTION` or `<>` ( `FALSE` ). If it is `FALSE` the `TUPLE` with the intermediate result is thrown away, otherwise `finalf` is called with the `TUPLE` . + +`MAPF` returns the result from `finalf` . If `finalf` is `FALSE` , `MAPF` returns the result from the last call to `applicable` . If `applicable` never was called (one of the `structs` was empty) `MAPF` returns `FALSE` . + +One special case is if only `finalf` and `applicable` are given. In this case `applicable` is called indefinitely with no arguments until a `MAPLEAVE` or `MAPSTOP` is invoked. `finalf` is called if `MAPSTOP` is used to leave the iteration. + +Examples: + +``` +<MAPF ,VECTOR ,+ (1 2 3) [10 11 12]>-->[11 13 15] +<MAPF ,STRING 1 +["Zil" "is" "lots of" "fun"]>-->"Zilf" +<MAPF ,VECTOR +<FUNCTION (N) <* .N .N>> (1 2 3)>-->[1 4 9] +<DEFINE SETG-MANY ("TUPLE" TUP) +<MAPF <> +,SETG +.TUP +<REST .TUP </ <LENGTH .TUP> 2>>>> +<SETG-MANY VAR-1 VAR-2 VAR-3 100 55 616> +,VAR-1-->100 +,VAR-2-->55 +,VAR-3-->616 +<DEFINE LNUM (N) +<MAPF ,LIST +<FUNCTION () +<COND (<=? 0 <SET N <- .N 1>>> <MAPSTOP.N>) +``` + +- 71 - + +``` +(ELSE .N)>>>> +``` + +``` +<LNUM 5>-->(4 3 2 1 0) +``` + +## **MAPLEAVE** + +``` +<MAPLEAVE [value]> +``` + +``` +MDL built-in +``` + +`MAPLEAVE` leaves the `MAPF` or the `MAPR` immediately and makes the `MAPF` or the `MAPR` return the `value` ( `TRUE` by default). This means that an eventual `finalf` in the `MAPF` or the `MAPR` never will be invoked. + +Example: + +``` +;"Return first non-zero value in STRUC" +<DEFINE FIRST-N0 (STRUC) +<MAPF <> <FUNCTION (X) +<COND (<N==? .X 0> <MAPLEAVE .X>)>> .STRUC>> +<FIRST-N0 [0 0 0 "ZIL" 6 0]>-->"ZIL" +``` + +## **MAPR** + +``` +<MAPR finalf applicable structs ...> +``` + +``` +MDL built-in +``` + +`MAPR` ("map rest") works the same as `MAPF` but instead of sending one element at a time to applicable it sends the `REST` of the `structs` , starting with `<REST struct 0>` . In other words, the first iteration takes `REST 0` from each of the `structs` and calls `applicable` , the second iteration takes `REST 1` from each of the `structs` and calls `applicable` , and so on until one of the `structs` doesn't have any more elements. The intermediate results from each call to `applicable` is stored in a `TUPLE` . + +The `finalf` can either be a `FUNCTION` or `<>` ( `FALSE` ). If it is `FALSE` the `TUPLE` with the intermediate result is thrown away, otherwise `finalf` is called with the `TUPLE` . + +`MAPR` returns the result from `finalf` . If `finalf` is `FALSE` , `MAPR` returns the result from the last call to `applicable` . If `applicable` never was called (one of the `structs` was empty) `MAPR` returns `FALSE` . + +One special case is if only `finalf` and `applicable` are given. In this case `applicable` is called indefinitely with no arguments until a `MAPLEAVE` or `MAPSTOP` is invoked. `finalf` is called if `MAPSTOP` is used to leave the iteration. + +Example: + +``` +<SET FOO [1 2 3]> +;"Triple value of struct" +<MAPR <> <FUNCTION (L) <1 .L <* <1 .L> 3>>> .FOO> +.FOO-->[3 6 9] +``` + +- 72 - + +## **MAPRET** + +``` +<MAPRET [value] ...> +``` + +``` +MDL built-in +``` + +`MAPRET` leaves the current iteration of the `MAPF` or the `MAPR` and adds the specified `value` s to the `TUPLE` of arguments used when the `finalf` is called. If no `value` s are specified nothing is added to the `TUPLE` in this iteration. Note that the `MAPF` or the `MAPR` continues to run through the iterations until one of the `structs` is out of elements. + +Example: + +``` +<SET FOO (65 66 67 68)> +<MAPF ,LIST +#FUNCTION ((L) +<MAPRET <ASCII .L>>) .FOO>-->(!\A !\B !\C !\D) +``` + +## **MAPSTOP** + +``` +<MAPSTOP [value] ...> +``` + +``` +MDL built-in +``` + +`MAPSTOP` is similar to `MAPRET` but after it adds the `value` s to the `TUPLE` of arguments it directly calls `finalf` and aborts all remaining iterations. + +Example: + +``` +<DEFINE FIRST-THREE (STRUC "AUX" (I 3)) +<MAPF ,LIST +<FUNCTION (E) +<COND (<0? <SET I <- .I 1>>> <MAPSTOP .E>)> +.E> .STRUC>> +<FIRST-THREE "ABCDEFG">-->(!\A !\B !\C) +``` + +## **MAX** + +``` +<MAX numbers ...> +``` + +``` +MDL built-in +``` + +`MAX` returns the maximum number among `numbers` . + +Example: + +``` +<MAX 2 3 4 1>-->4 +``` + +## **MEMBER** + +``` +<MEMBER item structure> +``` + +``` +MDL built-in +``` + +- 73 - + +`MEMBER` iterates through `structure` and returns `<REST structure i>` , where `i` is the index of the first element in `structure` that is `=?` with `item` . + +`MEMBER` returns false if the `item` is not found. + +Examples: + +``` +<MEMBER "BC" "ABCD">-->"BCD" +<MEMBER 2 (1 2 3 4)>-->(2 3 4) +<MEMBER 0 (1 2 3 4)>-->#FALSE <> +``` + +## **MEMQ** + +``` +<MEMQ item structure> +``` + +``` +MDL built-in +``` + +`MEMQ` ("member quick") iterates through `structure` and returns `<REST structure i>` , where `i` is the index of the first element in `structure` that is `==?` with `item` . + +`MEMQ` returns false if the `item` is not found. + +Examples: + +``` +<MEMQ "BC" "ABCD">-->#FALSE <> +<MEMQ 2 (1 2 3 4)>-->(2 3 4) +<MEMQ 0 (1 2 3 4)>-->#FALSE <> +``` + +## **MIN** + +``` +<MIN numbers ...> +``` + +``` +MDL built-in +``` + +`MIN` returns the minimum number among `numbers` . + +Example: + +``` +<MIN 2 3 4 1>-->1 +``` + +## **MOBLIST** + +``` +<MOBLIST name> +``` + +``` +MDL built-in +``` + +`MOBLIST` ("make oblist") creates and returns a new empty `OBLIST` named `name` . If an `OBLIST` with the `name` already exists the existing one is returned instead. + +Example: + +``` +<INSERT "FOO" <MOBLIST NEW-OBLIST>>-->FOO!-NEW-OBLIST +FOO!-NEW-OBLIST ;"This can also be done with trailer" +``` + +- 74 - + +## **MOD** + +``` +<MOD number1 number2> +``` + +``` +MDL built-in +``` + +`MOD` divides `number1` with `number2` , which must be non-zero, and returns the remainder. Examples: + +``` +<MOD 3 2>-->1 +<MOD 3256 256>-->184 +``` + +## **MSETG** + +``` +<MSETG atom value> +``` + +``` +ZIL library +``` + +`MSETG` ("manifest set global") is an alias for `CONSTANT` . + +`MSETG` ( `CONSTANT` ) defines an atom with value that will never be changed. The atom can is accessed inside a `ROUTINE` with `GVAL` (or `,` ) just like a `GLOBAL` atom. Defining a `MSETG` ( `CONSTANT` ) instead of a `GLOBAL` when possible can be vital information the compiler can use for optimization. + +Example: + +``` +<MSETG MSG-CANT-DO-THAT "You can't do that!"> +``` + +``` +... +<TELL ,MSG-CANT-DO-THAT CR> +``` + +## **N==?** + +``` +<N==? value1 value2> +``` + +``` +MDL built-in +``` + +Predicate. False if `value1` and `value2` is the same object, otherwise true. `N==?` is the opposite to `==?` . + +ZILF defines "the same object" more loosely than MDL, see `==?` . + +Examples: + +``` +<SET X 1> +<N==? .X 1>-->False +<SET X (1 2 3)> +<N==? .X (1 2 3)>-->True +``` + +## **N=?** + +``` +<N=? value1 value2> +MDL built-in +``` + +- 75 - + +Predicate. False if `value1` and `value2` is of the same `TYPE` and structurally equal, otherwise true. `N=?` is the opposite to `=?` . + +Examples: + +``` +<SET X 1> +<N=?.X 1>-->True +<SET X (1 2 3)> +<N=? .X (1 2 3)>-->True +``` + +## **NEVER-ZAP-TO-SOURCE-DIRECTORY?** + +``` +<NEVER-ZAP-TO-SOURCE-DIRECTORY?> +``` + +``` +ZIL library +``` + +ZILF ignores this and always returns `FALSE` . + +## **NEW-ADD-WORD** + +``` +<NEW-ADD-WORD atom-or-string [type] [value] [flags]> +``` + +``` +ZIL parser library +``` + +`NEW-ADD-WORD` is an alias to `ADD-WORD.` + +## **NEWTYPE** + +``` +<NEWTYPE name primtype-atom [decl]> +``` + +``` +MDL built-in +``` + +`NEWTYPE` creates a new `TYPE` with the name, `name` and the same `PRIMTYPE` as `primtype-atom` . It returns the new `TYPE` . The `name` must be unique ( `<VALID-TYPE? name>` is `FALSE` > otherwise `NEWTYPE` results in an error. + +It is possible to specify a `decl` (see `GDECL` ) for the new `TYPE` that is enforced when `CHTYPE` . + +See `APPLYTYPE` , `EVALTYPE` and `PRINTTYPE` . + +Examples: + +``` +<NEWTYPE GARGLE CHARACTER> +<TYPEPRIM GARGLE>-->FIX +<SET A <CHTYPE 65 GARGLE>> +<TYPE .A>-->GARGLE +<PRIMTYPE .A>-->FIX +<NEWTYPE FIRSTNAME ATOM> +<NEWTYPE LASTNAME FIRSTNAME> +<=? ALFONSO #FIRSTNAME ALFONSO>-->#FALSE +<=? #FIRSTNAME MADISON #LASTNAME MADISON>-->#FALSE +``` + +- 76 - + +``` +<=? #LASTNAME MADISON #LASTNAME MADISON>-->T +<NEWTYPE 2FIXLIST LIST '!<LIST FIX FIX>> +#2FIXLIST (1 2)-->Ok +#2FIXLIST (1 2 3)-->Error +``` + +## **NEXT** + +``` +<NEXT asoc> +``` + +``` +MDL built-in +``` + +`NEXT` returns the next `asoc` entry, of `TYPE ASOC` , in the `ASSOCIATION` chain. If there are no more entries then `FALSE` is returned. + +See `ASSOCIATIONS` , `AVALUE` , `GETPROP` , `INDICATOR` , `ITEM` and `PUTPROP` . + +Example: + +``` +<DEFINE FIND-ASOC (ITEM) +<REPEAT ((A <ASSOCIATIONS>)) +<COND (<=? .A <>> <RETURN <>>)> +<COND (<==? .ITEM <ITEM .A>> <RETURN .A>)> +<SET A <NEXT .A>>>> +<PUTPROP NEW-ASOC TEXT "Hello, world!"> +<FIND-ASOC NEW-ASOC> +-->#ASOC (NEW-ASOC TEXT "Hello, world!") +``` + +## **NOT** + +``` +<NOT value> +``` + +``` +MDL built-in +``` + +Boolean (logical) "not". `NOT` returns true if value is false ( `#FALSE <>` ), otherwise `NOT` returns false. + +Examples: + +``` +<NOT <>>-->T +<NOT T>-->#FALSE <> +<NOT <=? 1 2>>-->T (Same as <N=? 1 2> +``` + +## **NTH** + +``` +<NTH structure index> +<index structure>;"Alternative syntax" +``` + +``` +MDL built-in +``` + +Returns the element at `index` in `structure` . Valid values for `index` are between 1 and `<LENGTH structure>` . + +`structure` must be an object that `STRUCTURED?` evaluates to `TRUE` . + +- 77 - + +`NTH` can also be abbreviated as `<index structure>` . + +Note that `TABLE` is not a `structure` . + +Also see `BACK` , `LENGTH` , `PUT` , `REST` , `SUBSTRUC` and `TOP` . + +Example: + +``` +<NTH <VECTOR "AB" "CD" "EF"> 2>-->"CD" +<2 <VECTOR "AB" "CD" "EF">>-->“CD” +``` + +## **OBJECT** + +``` +<OBJECT name (property values ...) ...> +``` + +``` +ZIL library +``` + +`OBJECT` creates an object with the internal objectname, `name` . After the name follows `LIST` s of properties for the `OBJECT` and the `value` s for each `property` . Which properties that define up a `OBJECT` is determined by the parser and it’s possible to add new properties with `PROPDEF` as long as the parser is modified to support the new `property` . Below is a list of common properties. + +`IN` or `LOC` This is the `OBJECT` s initial location. This could, for example, be a `ROOM` , another `OBJECT` (container) or the player (in its inventory). There are a couple of special locations like `GLOBAL-OBJECTS` for `OBJECT` s that the player can refer to everywhere, `LOCAL-GLOBALS` for `OBJECT` s the player can refer to in `ROOM` s that define this `OBJECT` in its `GLOBAL` list and `GENERIC-OBJECTS` for `OBJECT` s that are concepts more than objects (for example the murder or the new will in Deadline). `SYNONYMS` This lists all the nouns that can be used to refer to the `OBJECT` . `ADJECTIVE` This lists all the adjectives that can be used to refer to the `OBJECT` . `DESC` The short description text of the `OBJECT` . This is the text that is, for example, printed in the players inventory. `FLAGS` This lists all the flagbits that are set on this `OBJECT` . `FDESC` (“first description”), this is the text that is used to describe the `OBJECT` until it is touched (picked up). `LDESC` (“long description”), this is the text that is used to describe the `OBJECT` , when it is on the ground, after it is touched. `GLOBAL` Optional `property` . This is a `LIST` of all the `OBJECT` s that is `IN` the `LOCAL-GLOBALS` that are accessible from this `ROOM` . This could, for example, be a door that is accessible from two different `ROOM` s. `THINGS` Optional `property` . This creates one or more simple “pseudo-objects”. Each object has three parts: a `LIST` of adjectives ( `FALSE` if none), a `LIST` of nouns and the name of the action-routine to call when this object is accessed. In early Infocom games this property was called `PSEUDO` and had a slightly different syntax. `ACTION` Defined as `(ACTION routine-name)` . This is the `OBJECT` s action-routine. For `OBJECT` s action-routines there is no argument. `SIZE` Size of `OBJECT` (for inventory handling). `VALUE` Value of `OBJECT` (for scoring purpose). `DESCFCN` This is used to define a function to handle the `OBJECT` s description. It is called with an argument, `ARG` , that can be `M-OBJDESC?` or `M-OBJDESC` . If + +- 78 - + +the routine returns `FALSE` during the `M-OBJDESC?` call, the `OBJECT` defaults to standard descriptions with `FDESC` and `LDESC` , otherwise the description is handled during the `M-OBJDESC` call. `CAPACITY` Capacity of the `OBJECT` if it is a container. `CONTFCN` This routine is called on the container when `OBJECT` s inside the container are handled (used rarely). + +See _Learning ZIL, Steve E. Meretzky_ and _ZIL Course, Marc S. Blank_ for more on properties, flagsbits and how to write and design games. + +Examples: + +``` +<OBJECT LAMP +(IN LIVING-ROOM) +(SYNONYM LAMP LANTERN LIGHT) +(ADJECTIVE BRASS) +(DESC "brass lantern") +(FLAGS TAKEBIT LIGHTBIT) +(ACTION LANTERN) +(FDESC "A battery-powered brass lantern is +on the trophy case.") +(LDESC "There is a brass lantern +(battery-powered) here.") +(SIZE 15)> +``` + +## **OBLIST?** + +``` +<OBLIST? atom> +``` + +``` +MDL built-in +``` + +`OBLIST?` returns the `OBLIST` that contains the `atom` . If the `atom` is not in any `OBLIST` it returns `FALSE` . + +Examples: + +``` +<==? <OBLIST? STRING> <ROOT>>-->T +<OBLIST? <ATOM "SPANK-NEW-ATOM">>-->#FALSE +<==? <OBLIST? FOO!-MY-OBLST> <MOBLIST MY-OBLST>>-->T +``` + +## **OFFSET** + +``` +<OFFSET index structure-decl [value-decl]> +``` + +``` +MDL built-in +``` + +`OFFSET` creates an `OFFSET TYPE` that is used with `NTH` and `PUT` to check that an element at `index` in the `structure` follows the specified pattern, `structure-decl` and `value-decl.` + +The `index` is an integer and the `structure-decl` follow the normal rules for a `decl` (see `GDECL` ). Because the `OFFSET` only specifies the `decl` for one element in the `structure` it is + +- 79 - + +possible to split the `decl` in two parts where `structure-decl` specifies the `structure` and `value-decl` is the `decl` for this specific element. + +Note that in ZILF can `OFFSET` only be used with `NTH` and `PUT` in the form `<index-or-offset structure>` and `<index-or-offset structure value>` respectively. + +`GET-DECL` and `PUT-DECL` can be used to examine and change the `decl` of the `OFFSET` and `INDEX` returns the `index` of an `OFFSET` . + +Example: + +``` +<SETG OFF1 <OFFSET 1 '<VECTOR FIX>>> +<SETG OFF2 <OFFSET 2 '<VECTOR FIX CHARACTER>>> +<SETG OFF3 <OFFSET 3 '<VECTOR> 'STRING>> +<GET-DECL ,OFF2>--><VECTOR FIX CHARACTER> +<SET V [1 !\A "BCD"]> +<OFF1 .V>-->1 +<OFF3 .V>-->"BCD" +<OFF2 .V !\B>-->[1 !\B "BCD"] +<OFF1 .V !\A>-->ERROR +<2 .V 65> +<OFF2 .V>-->ERROR +``` + +## **OPEN** + +``` +<OPEN "READ" path> +MDL built-in +``` + +`OPEN` the file at `path` for input. The second argument must always be `"READ"` in ZILF and the `path` is specified like in Linux (forward slashes etc.) and uppercase/lowercase can be significant, depending on the host system. + +Example: + +## **OR** + +; `"ZILF ver 0.9" <SET CH <OPEN "READ" "../zillib/parser.zil">> <SET BUFFER <ISTRING 1000>> <READSTRING .BUFFER .CH ";"> --> 124 ;"READ until first ;" <CLOSE .CH> <OR expressions...> MDL built-in` + +Boolean `OR` . Requires that one of the `expressions` evaluates to true to return true. Exits on the first `expression` that evaluates to true (rest of `expressions` are not evaluated). + +Because false is its own `TYPE` outside a routine `OR` returns `#FALSE` if all `expressions` are false or the value of the first true `expression.` + +- 80 - + +Example: + +``` +<OR <=? 1 2> <=? 1 1>>-->True +<OR <=? 1 1> <SET X 2>>-->X never set to 2 because +first predicate evaluates +to true +<SET X <OR 0 1 2 3>>-->X is set to 0 +<SET X <OR <> 1 2 3>>-->X is set to 1 +``` + +## **OR?** + +``` +<OR? Expressions ...> +MDL built-in +``` + +Returns the same result as `OR` with the difference that all `exressions` are evaluated. Examples: + +``` +<OR? <=? 1 2> <=? 1 1>>-->True +<OR? <=? 1 1> <SET X 2>>-->X is set to 2 because +all expressions are +evaluated +``` + +## **ORB** + +``` +<ORB numbers ...> +``` + +``` +MDL built-in +``` + +Bitwise OR. + +Examples: + +``` +<ORB 33 96>-->97 +<ORB 33 96 64>-->97 +``` + +## **ORDER-FLAGS?** + +``` +<ORDER-FLAGS? LAST objects ...> +``` + +``` +ZIL library +``` + +Each of the `objects` is an atom naming a flag, as seen in the `(FLAGS ...)` clause of an OBJECTdefinition. + +The only ordering allowed is `LAST` , which causes the named flags to be added to the list of “flags requiring high numbers”, which are assigned the highest flag numbers so they may be distinguished from zero. Flags mentioned in the `(FIND ...)` clause of `SYNTAX` definitions are already added to this list by default. + +## **ORDER-OBJECTS?** + +``` +<ORDER-OBJECTS? atom> +``` + +- 81 - + +``` +ZIL library +``` + +This controls the order in which object numbers are assigned to objects. + +Note that there are two ways the compiler can learn about an object: some objects are explicitly “defined” using `ROOM` or `OBJECT` , whereas the existence of others is merely implied when the objects are “mentioned” as part of another object’s definition (in a `LOC` or direction property). + +By default, if `ORDER-OBJECTS?` is not used, object numbers are assigned in reverse mention order. That is, the first object defined is given the highest number, and any other objects mentioned in its definition are given the next highest numbers (in order), whether or not those objects are explicitly defined later. + +The `atom` is one of the following: + +`DEFINED` To assign numbers to all explicitly defined objects in the order of their definitions (starting at 1), then to all other mentioned objects in the order of their mentions. `ROOMS-FIRST` The same as `DEFINED` except that numbers are assigned to rooms before non-rooms, so room numbers can be packed into a byte array (assuming there are less than 256 of them). `ROOMS-LAST` The same as `DEFINED` except that numbers are assigned to non-rooms before rooms. `ROOMS-AND-LGS-FIRST` The same as `ROOMS-FIRST` except that numbers are assigned to rooms and local globals before the remaining objects. + +For the purpose of object ordering, “rooms” include all objects defined with `ROOM` (instead of `OBJECT` ) as well as all objects whose initial `LOC` is an object named `ROOMS` . “Local globals” includes all objects whose initial `LOC` is an object named `LOCAL-GLOBALS` . + +## **ORDER-TREE?** + +``` +<ORDER-TREE? atom> +``` + +``` +ZIL library +``` + +This controls the initial layout of the Z-machine object tree. + +The object tree is defined by three fields on each object, named in the Z-Machine Standards Document as “parent”, “child”, and “sibling”, which are read by the ZIL functions `LOC` , `FIRST?` , and `NEXT?` . Each object’s parent field is specified by the `(LOC …)` clause in the object definition, but the compiler has discretion to set the child and sibling fields as long as the tree remains well-formed. + +The `atom` must be: + +- `REVERSE-DEFINED` , to force objects to be linked in the reverse order of their definitions. That is, the child of an object `X` is the last object in the source code whose definition contains `(LOC X)` ; the sibling of that child is the next to last object in the source code that contains `(LOC X)` ; and so on. + +By default, if `ORDER-TREE?` is not used, the order is the same as `REVERSE-DEFINED` except for + +- 82 - + +the first defined child, which remains the first object linked. That is, the child of an object `X` is the first object in the source code whose definition contains `(LOC X)` ; the sibling of that child is the last object that contains `(LOC X)` ; the sibling of that child in turn is the next to last object that contains `(LOC X)` ; and so on. + +## **PACKAGE** + +``` +<PACKAGE package-name> +``` + +``` +MDL package system +``` + +`PACKAGE` defines a group of `ATOM` s (i.e. variables and functions) with the `package-name` for potential later inclusion (via `USE` or `USE-WHEN` ) in the project. A `PACKAGE` is often used to functionally group together library functions that can have a usage over many projects. + +Internally an `OBLIST` named `PACKAGE` is used in conjunction with `BLOCK` and `ENDBLOCK` . When you define a `PACKAGE` the following is happening: + +1. An external `OBLIST` , `package-name` , is created and added to the `OBLIST PACKAGE` (e.g. `FOO!-PACKAGE` ). + +2. An internal `OBLIST` , `Ipackage-name` , is created and added to the `OBLIST package-name` (e.g. `IFOO!-FOO!-PACKAGE` ). + +3. A `BLOCK` is started with the `OBLIST` s (in this order) `Ipackage-name` , `package-name` and `<ROOT>` (e.g. `IFOO` , `FOO` , `<ROOT>` ). + +This means that every `ATOM` that is created inside the `PACKAGE` ends up on the internal `OBLIST` first. If `ENTRY` is used the `ATOM` is created/moved to the external `OBLIST` and finally `RENTRY` creates/moves the `ATOM` to the `ROOT OBLIST` . + +The `PACKAGE` definition is ended by `END-PACKAGE` (in fact an `ENDBLOCK` ) which restores the `OBLIST` s to the state they had before the `PACKAGE` definition began. + +When you decide to use a package by `USE` or `USE-WHEN` the `OBLIST package-name` is copied and added last to the local `OBLIST` ( `<LVAL OBLIST>` ). This means that all `ATOM` s on the external package `OBLIST` becomes available in current environment. + +Note that a `PACKAGE` can be defined additive (i.e. multiple `PACKAGE` definitions with the same `package-name` is added together to one `PACKAGE` ). + +ZILF has three packages predefined in `<MOBLIST PACKAGE>` ; `NEWSTRUC` , `ZIL` and `ZILCH` . They are all empty and are only there for compatibility (all `ATOM` s in these packages are already in ZILF). + +See `DEFINITIONS` , `ENDPACKAGE` , `ENTRY` , `RENTRY` , `USE` and `USE-WHEN` . + +Examples: + +``` +;"Define PACKAGE" +<REMOVE ANSWER> ;"Secure that ATOM not on any OBLIST" +<REMOVE DBL-ANSWER> +<REMOVE ROOT-ANSWER> +<REMOVE SECRET> +<PACKAGE "FOO"> +<ENTRY ANSWER> +<SETG ANSWER 42> +``` + +- 83 - + +``` +<SETG SECRET 12345> +<RENTRY ROOT-ANSWER> +<SETG ROOT-ANSWER 21> +<ENDPACKAGE> +<TYPE? <GETPROP FOO!-PACKAGE OBLIST> OBLIST>-->OBLIST +<TYPE? <GETPROP IFOO!-FOO!-PACKAGE OBLIST> OBLIST>-->OBLIST +<GASSIGNED? ANSWER>-->#FALSE +<GASSIGNED? ANSWER!-FOO!-PACKAGE>-->T +<GASSIGNED? SECRET!-IFOO!-FOO!-PACKAGE>-->T +,ANSWER!-FOO!-PACKAGE-->42 +,SECRET!-IFOO!-FOO!-PACKAGE-->12345 +,ROOT-ANSWER-->21 +;"PACKAGEs can be defined additive" +<PACKAGE "FOO"> +<SETG DBL-ANSWER <* ,ANSWER 2>> +<ENTRY DBL-ANSWER> +<ENDPACKAGE> +,ANSWER!-FOO!-PACKAGE-->42 +,DBL-ANSWER!-FOO!-PACKAGE-->84 +;"USE adds external OBLIST to local OBLIST-path" +<REMOVE ANSWER> ;"Secure that ATOM not on any OBLIST" +<LENGTH .OBLIST>-->2 +<USE "FOO"> +<LENGTH .OBLIST>-->3 +,ANSWER-->42 +<GASSIGNED? SECRET>-->#FALSE +,SECRET!-IFOO-->12345 +``` + +## **PARSE** + +``` +<PARSE text [10] [lookup-oblist]> +``` + +``` +MDL built-in +``` + +`PARSE` takes a string, `text` , and returns the first MDL object encountered in it. If `lookup-oblist` is supplied, `PARSE` looks for potential `ATOM` s on this `OBLIST` . If no `lookup-oblist` is supplied, `.OBLIST` is used. + +ZILF requires that the second argument is `10` if a `lookup-oblist` is supplied. + +Examples: + +``` +<PARSE "FOO">-->FOO +<PARSE "+">-->+ +<PARSE "+" 10 <GETPROP PACKAGE OBLIST>>-->+!-PACKAGE +<PARSE "23">-->23 +<PARSE "(1 2 3)">-->(1 2 3) +<PARSE "<+ 12 34>">--><+ 12 34> +``` + +- 84 - + +``` +<PARSE "%<+ 12 34>">-->46 +<PARSE "<+ .A .B>" 10 <MOBLIST OB>> +--><+!-OB <LVAL!-OB A!-OB> <LVAL!-OB B!-OB>> +<PARSE " ">-->ERROR (No expression) +<PARSE "1 2 3">-->1 (Only 1st expression) +``` + +## **PICFILE** + +``` +<PICFILE> +``` + +``` +ZIL library +``` + +ZILF ignores this and always returns `FALSE` . + +## **PLTABLE** + +``` +<PLTABLE [flags ...] values ...> +``` + +``` +ZIL library +``` + +Defines a table containing the specified `values` and with the `PURE` and `LENGTH` flag (see `TABLE` about `LENGTH` , `PURE` and other flags). + +`TABLE` is a ZIL-specific structure that can be used both outside and inside `ROUTINES` . + +## **PNAME** + +``` +<PNAME atom> +``` + +``` +MDL built-in +``` + +`PNAME` ("printed name") returns a newly created string copy of the `atom` ’s pname. `PNAME` never prints an `ATOM` s trailers, unlike `UNPARSE` , and is therefore quicker. + +Examples: + +``` +<PNAME FOO>-->"FOO" +<PNAME FOO!-NEW-OBLIST>-->"FOO" +<UNPARSE FOO!-NEW-OBLIST>-->"FOO!-NEW-OBLIST" +``` + +## **PREP-SYNONYM** + +``` +<PREP-SYNONYM original synonyms ...> +``` + +``` +ZIL parser library +``` + +`PREP-SYNONYM` creates one or more `synonyms` to the `original` preposition. + +ZILF treats `PREP-SYNONYM` as an alias to `SYNONYM` . + +- 85 - + +## **PRIMTYPE** + +``` +<PRIMTYPE value> +``` + +``` +MDL built-in +``` + +evaluates to the primitive type of `value` . The primitive types are `ATOM` , `FIX` , `LIST` , `STRING` , `TABLE` and `VECTOR` . + +Examples: + +``` +<PRIMTYPE !\A>-->FIX +<PRIMTYPE <+1 2>>-->FIX +<PRIMTYPE "ABC">-->STRING +``` + +## **PRIN1** + +``` +<PRIN1 value [channel]> +``` + +``` +MDL built-in +``` + +Prints the evaluated representation of `value` to `channel` (default for `channel` is `<LVAL OUTCHAN>` - the console). `PRIN1` also returns the evaluated representation of `value` . + +Examples: + +``` +<PRIN1 !\A>-->!\A +<PRIN1 42>-->42 +<PRIN1 "Hello, world!">-->"Hello, world!" +<PRIN1 (1 2 3)>-->(1 2 3) +<PRIN1 <+ 1 2>>-->3 +``` + +## **PRINC** + +``` +<PRINC value [channel]> +``` + +``` +MDL built-in +``` + +`PRINC` is just like `PRIN1` , except for `STRING` and `CHARACTER` where surrounding dubbel quote `"` ( ) and initial `!\` is suppressed. `PRINC` returns the evaluated representation of `value` . + +Examples: + +``` +<PRINC !\A>-->A +<PRINC 42>-->42 +<PRINC "Hello, world!">-->Hello, world! +<PRINC (1 2 3)>-->(1 2 3) +<PRINC <+ 1 2>>-->3 +``` + +## **PRINT** + +``` +<PRINT value [channel]> +``` + +``` +MDL built-in +``` + +- 86 - + +`PRINT` is just like `PRIN1` , except that it first prints a CRLF, then the evaluated representation of value and lastly a space. `PRINT` returns the evaluated representation of `value` . + +Examples: + +``` +<PRINT !\A>-->\n!\A<space> +<PRINT 42>-->\n42<space> +<PRINT "Hello, world!">-->\n"Hello, world!"<space> +<PRINT (1 2 3)>-->\n(1 2 3)<space> +<PRINT <+ 1 2>>-->\n3<space> +``` + +## **PRINT-MANY** + +``` +<PRINT-MANY channel printer items ...> +``` + +``` +ZIL library +``` + +`PRINT-MANY` prints multiple `items` to `channel` with the `printer` . The `printer` is usually `PRINT` , `PRINC` or `PRIN1` but could actually be any `FUNCTION` that takes one argument. The `printer` is called repeatedly with one `item` at a time until the list of `items` is exhausted. + +If `PRMANY-CRLF` is given as an `item` , a `CRLF` is printed at that position. + +Examples: + +``` +<PRINT-MANY .OUTCHAN PRINC "Hello" !\! PRMANY-CRLF> +-->Hello!\n +<PRINT-MANY .OUTCHAN PRIN1 "string" !\c PRMANY-CRLF> +-->"string"!\c\n +``` + +## **PRINTTYPE** + +``` +<PRINTTYPE atom [handler]> +``` + +``` +MDL built-in +``` + +`PRINTTYPE` tells the `TYPE atom` how it should be printed ( `PRIN1` -style). If `PRINTTYPE` is called without a `handler` then the currently active `handler` is returned. If there is no active `handler` , `FALSE` is returned. + +Note that it is possible to replace the `handler` with a new `handler` , even on the predefined `TYPE` s. + +See `APPLYTYPE` , `EVALTYPE` and `NEWTYPE` . + +Examples: + +``` +<DEFINE ROMAN-PRINT (ROMAN "AUX" (RNUM <CHTYPE .ROMANFIX>)) +<COND (<OR <L=? .RNUM 0> <G? .RNUM 3999>> +<PRINC <CHTYPE .NUMB TIME>>) +(T +<RCPRINT </ .RNUM 1000> '![!\M]> +<RCPRINT </ .RNUM 100> '![!\C !\D !\M]> +<RCPRINT </ .RNUM 10> '![!\X !\L !\C]> +<RCPRINT .RNUM '![!\I !\V !\X]>)>> +``` + +- 87 - + +``` +<DEFINE RCPRINT (MODN V) +<SET MODN <MOD .MODN 10>> +<COND (<==? 0 .MODN>) +(<==? 1 .MODN> <PRINC <1 .V>>) +(<==? 2 .MODN> <PRINC <1 .V>> <PRINC <1 .V>>) +(<==? 3 .MODN> <PRINC <1 .V>> <PRINC <1 .V>> +<PRINC <1 .V>>) +(<==? 4 .MODN> <PRINC <1 .V>> <PRINC <2 .V>>) +(<==? 5 .MODN> <PRINC <2 .V>>) +(<==? 6 .MODN> <PRINC <2 .V>> <PRINC <1 .V>>) +(<==? 7 .MODN> <PRINC <2 .V>> <PRINC <1 .V>> +<PRINC <1 .V>>) +(<==? 8 .MODN> <PRINC <2 .V>> <PRINC <1 .V>> +<PRINC <1 .V>> <PRINC <1 .V>>) +(<==? 9 .MODN> <PRINC <1 .V>> <PRINC <3 .V>>)>> +``` + +``` +<NEWTYPE ROMAN FIX> +<PRINTTYPE ROMAN ,ROMAN-PRINT> +<==? <PRINTTYPE ROMAN> ,ROMAN-PRINT> +#ROMAN 1984-->MCMLXXXIV +<NEWTYPE ROMAN2 FIX> +<PRINTTYPE ROMAN2 ROMAN> ;"Copies active handler,if exists" +#ROMAN2 2020-->MMXX +<PRINTTYPE ROMAN FIX> +<=? <PRINTTYPE ROMAN> <>>-->T +#ROMAN 2020-->2020 +;"Change in ROMAN doesn’t affect ROMAN2" +#ROMAN2 2020-->MMXX +<PRINTTYPE FIX ,ROMAN-PRINT> ;"Works on built-in too!" +23-->XXIII +<PRINTTYPE FORM <FUNCTION (F) <PRIN1 <CHTYPE .F LIST>>>> +<FORM + 1 2>-->(+ I II) +``` + +## **PROG** + +``` +<PROG [activation] (bindings ...) [decl] expressions...> +``` + +``` +MDL built-in +``` + +`PROG` defines a program block with its own set of `bindings` . `PROG` is similar to `BIND` and `REPEAT` but unlike `BIND` it creates a default `activation` (like `REPEAT` ) at the start of the block and doesn't have an automatic `AGAIN` at the end of the block (like `REPEAT` ). It is possible to name an `atom` to the `activation` but it is not necessary. `AGAIN` and `RETURN` inside a PROG-block will start the block over or return from the block. + +The `decl` is used to specify the valid `TYPE` of the variables. In its simplest form `decl` is formatted like: `#DECL ((X) FIX)` , meaning that X must be of the `TYPE FIX` . For more information on how to format the `decl` see `GDECL` . + +- 88 - + +Also see `AGAIN` , `BIND` , `REPEAT` and `RETURN` for more details how to control program flow. Example: + +``` +<PROG ((X 1)) #DECL ((X) FIX) +<PROG ((X 2)) <PRIN1 .X>> <PRIN1 .X>> +--> "21" +<DEFINE TEST-PROG-AS-REPEAT () +<PRINC "START "> +<PROG ((X 0)) +<SET X <+ .X 1>> +<PRIN1 .X> +<COND (<=? .X 3> <RETURN>)>;"--> exit block" +<AGAIN>;"--> repeat" +> +<PRINC " END"> +> +<TEST-PROG-AS-REPEAT>--> "START 123 END" +``` + +## **PROPDEF** + +``` +<PROPDEF atom default-value [spec-patterns ...]> +``` + +``` +ZIL library +``` + +`PROPDEF` defines a property, `atom` , with a `default-value` for `OBJECT` s (and `ROOM` s). The `default-value` is the value that `GETP` will return if the property is not defined for the given `OBJECT` . + +For the more complex properties it is possible to define a `spec-pattern` according to: + +``` +(atom|DIR ["MANY"|"OPT"] [phrase] var:type ... = +[form-len] ["MANY"] <fnc-size var>|(const value)| +(ptr <fnc-size var>) ...) ... +``` + +The `spec-pattern` consists of two parts divided by an equal sign. The left side is the pattern and the right side is the rules on how to store the property. + +`atom|DIR` This is the property. `DIR` is a special case that is used for `DIRECTIONS` . `"MANY"` This means that the pattern of `var:type` repeats itself. If `"MANY"` is defined on the left side of the equal sign there must be a matching on the right side. `"OPT"` This means that the pattern after is optional. `[phrase]` This can be tokens like `IF` , `ELSE` , `TO` . `var:type` This is a variable name, `var` , and its `type` . Usually `FIX` , `STRING` or `ROOM` . `form-len` The length (records) of the form. The `form-len` is optional and can also be given as `<>` . + +`<fnc-size var>` The `fnc-size` can be a call with `var` to either `BYTE` , `WORD` , `STRING` , `OBJECT` , `ROOM` , `GLOBAL` , `NOUN` , `ADJ` , or `VOC` . This stores `var` or derivative of `var` and adds to the vocabulary and/or creates a + +- 89 - + +`GVAL` . + +`(ptr <fnc-size` This creates a `GVAL` , `ptr` , that contains the address-pointer relative `var>` ) to the property. `(const value)` This creates a `CONSTANT` , `name` , containing `value` . + +Examples: + +``` +;"Ordinary property" +<PROPDEF HEIGHT 72> +<OBJECT OBJ1> +<OBJECT OBJ2 (HEIGHT 80)> +;"Implies, inside routine" +<GETP ,OBJ1 ,P?HEIGHT>-->72 +<GETP ,OBJ2 ,P?HEIGHT>-->80 +;"Basic pattern" +<PROPDEF HEIGHT <> +(HEIGHT FEET:FIX FOOT INCHES:FIX = 2 <WORD .FEET> +<BYTE .INCHES>) +(HEIGHT FEET:FIX FT INCHES:FIX = 2 <WORD .FEET> +<BYTE .INCHES>)> +<OBJECT GIANT (HEIGHT 10 FT 8)> +;"Implies, inside routine" +<=? <GET <GETPT ,GIANT ,P?HEIGHT> 0> 10> +<=? <GETB <GETPT ,GIANT ,P?HEIGHT> 2> 8> +;"Basic pattern with OPT" +<PROPDEF HEIGHT <> (HEIGHT FEET:FIX FT "OPT" INCHES:FIX= +<WORD .FEET> <BYTE .INCHES>)> +<OBJECT GIANT1 (HEIGHT 100 FT)> +<OBJECT GIANT2 (HEIGHT 50 FT 11)> +;"Implies, inside routine" +<=? <PTSIZE <GETPT ,GIANT1 ,P?HEIGHT>> 3> +<=? <GET <GETPT ,GIANT1 ,P?HEIGHT> 0> 100> +<=? <GETB <GETPT ,GIANT1 ,P?HEIGHT> 2> 0> +<=? <PTSIZE <GETPT ,GIANT2 ,P?HEIGHT>> 3> +<=? <GET <GETPT ,GIANT2 ,P?HEIGHT> 0> 50> +<=? <GETB <GETPT ,GIANT2 ,P?HEIGHT> 2> 11> +;"Basic pattern with MANY" +<PROPDEF TRANSLATE <> (TRANSLATE "MANY" A:ATOM N:FIX= +"MANY" <VOC .A BUZZ> <WORD .N>)> +<OBJECT NUMBERS (TRANSLATE ONE 1 TWO 2)> +;"Implies, inside routine" +<=? <PTSIZE <GETPT ,NUMBERS ,P?TRANSLATE>> 8> +<=? <GET <GETPT ,NUMBERS ,P?TRANSLATE> 0> ,W?ONE> +<=? <GET <GETPT ,NUMBERS ,P?TRANSLATE> 1> 1> +<=? <GET <GETPT ,NUMBERS ,P?TRANSLATE> 2> ,W?TWO> +<=? <GET <GETPT ,NUMBERS ,P?TRANSLATE> 3> 2> +;"Pattern with constants" +<PROPDEF HEIGHT <> (HEIGHT FEET:FIX FT INCHES:FIX= +``` + +- 90 - + +``` +(HEIGHTSIZE 3) (H-FEET <WORD .FEET>) +(H-INCHES <BYTE .INCHES>))> +<=? ,HEIGHTSIZE 3> +<=? ,H-FEET 0> +<=? ,H-INCHES 2> +;"DIR sets pattern for all DIRECTIONS" +<PROPDEF DIRECTIONS <> (DIR GOES TO R:ROOM = +(MY-UEXIT 3) <WORD 0> (MY-REXIT <ROOM .R>))> +<DIRECTIONS NORTH SOUTH> +<OBJECT HOUSE (SOUTH GOES TO WOODS)> +<OBJECT WOODS (NORTH GOES TO HOUSE)> +;"Implies, inside routine" +<=? <PTSIZE <GETPT ,HOUSE ,P?SOUTH>> ,MY-UEXIT> +<=? <GETB <GETPT ,HOUSE ,P?SOUTH> ,MY-REXIT> ,WOODS> +;"DIR sets implicit DIRECTIONS" +<PROPDEF DIRECTIONS <> (DIR GOES TO R:ROOM = +(MY-UEXIT 3) <WORD 0> (MY-REXIT <ROOM .R>))> +<DIRECTIONS NORTH SOUTH> +<OBJECT HOUSE (EAST GOES TO WOODS)> +<OBJECT WOODS (WEST GOES TO HOUSE)> +;"Implies, inside routine" +<=? <PTSIZE <GETPT ,HOUSE ,P?EAST>> ,MY-UEXIT> +<=? <GETB <GETPT ,HOUSE ,P?EAST> ,MY-REXIT> ,WOODS> +<BAND <GETB ,W?EAST 4> ,PS?DIRECTION> +;"VOC in pattern adds word to vocabulary" +<PROPDEF FOO <> (FOO A:ATOM = <VOC .A PREP>)> +<OBJECT BAR (FOO FOO)> +;"Implies, inside routine" +<=? <GETP ,BAR ,P?FOO> ,W?FOO> +;"Complex PROPDEF (DIRECTIONS from Zork Zero)" +<PROPDEF DIRECTIONS <> +(DIR TO R:ROOM = (UEXIT 1) (REXIT <ROOM .R>)) +(DIR S:STRING = (NEXIT 2) (NEXITSTR <STRING .S>)) +(DIR SORRY S:STRING = (NEXIT 2) (NEXITSTR <STRING.S>)) +(DIR PER F:FCN = (FEXIT 3) +(FEXITFCN <WORD .F>) <BYTE 0>) +(DIR TO R:ROOM IF F:GLOBAL "OPT" ELSE S:STRING = +(CEXIT 4)(REXIT <ROOM .R>) (CEXITFLAG <GLOBAL.F>) +(CEXITSTR <STRING .S>)) +(DIR TO R:ROOM IF O:OBJECT IS OPEN "OPT" ELSE S:STRING= +(DEXIT 5) (DEXITOBJ <OBJECT .O>) +(DEXITSTR <STRING .S>) (DEXITRM <ROOM .R>))> +``` + +## **PTABLE** + +``` +<PTABLE [(flags ...)] values ...> +``` + +``` +ZIL library +``` + +- 91 - + +Defines a table containing the specified `values` and with the `PURE` flag (see `TABLE` about `PURE` and other flags). + +`TABLE` is a ZIL-specific structure that can be used both outside and inside `ROUTINES` . + +## **PUT** + +``` +<PUT structure index new-value> +``` + +``` +MDL built-in +``` + +Sets the element at `index` in `structure` to `new-value` . Valid values for `index` are between 1 and `<LENGTH structure>` . + +`structure` must be an object that `STRUCTURED?` evaluates to true. + +Note that `TABLE` is not a `structure` . + +Also see `BACK` , `LENGTH` , `NTH` , `REST` , `SUBSTRUC` and `TOP` . + +Example: + +``` +<SETG STRUCT (1 2 3 4)> +<PUT ,STRUCT 2 5>-->STRUCT = (1 5 3 4) +``` + +## **PUT-DECL** + +``` +<PUT-DECL item pattern> +``` + +``` +MDL built-in +``` + +`PUT-DECL` defines an alias, `item` , for a `pattern` . See `DECL?` , `GDECL` and `GET-DECL` for more on declaration patterns. + +Examples: + +``` +<DECL? T BOOLEAN>-->Error +<PUT-DECL BOOLEAN '<OR ATOM FALSE>> +<DECL? T BOOLEAN>-->T +<DECL? "Hi" BOOLEAN>-->#FALSE +``` + +## **PUT-PURE-HERE** + +``` +<PUT-PURE-HERE> +``` + +``` +ZIL library +``` + +ZILF ignores this and always returns `FALSE` . + +## **PUTB** + +``` +<PUTB table index new-value> +``` + +``` +ZIL library +``` + +- 92 - + +Put a byte `new-value` in the `table` at byte position `index` . Actual address is table-address+index. + +`TABLE` is a ZIL-specific structure that can be used both outside and inside ROUTINES. `PUTB` is equivalent to the Z-code built-in `PUTB` . + +Also see `GETB` , `ZGET` , `ZPUT` and `ZREST` . + +Example: + +``` +<PUTB ,MYTABLE 1 !\A>-->Stores character A at +position 1 in MYTABLE +``` + +## **PUTPROP** + +``` +<PUTPROP item indicator [value]> +``` + +``` +MDL built-in +``` + +`PUTPROP` stores `value` as an association on the `item` under the `indicator` and returns the `item` . If no `value` is specified `PUTPROP` returns the `value` and then clears the association. + +In ZILF there is a special `indicator` , `PROPSPEC` , that has a special meaning inside `OBJECT` s. A `PROPSPEC` property is defined: + +``` +<PUTPROP item PROPSPEC [function]> +``` + +When an `item` defined in this way is used in an `OBJECT` , the `function` is invoked during the compilation with the `LIST` (containing the `item` ) as an argument. The return value from the `function` must be a `LIST` and it is stored as `value` under `PROPSPEC` on the `item` . If no `function` is specified the `PROPSPEC` for the `item` is cleared. See examples below. + +See `ASSOCIATIONS` , `AVALUE` , `GETPROP` , `INDICATOR` , `ITEM` and `NEXT` . + +Examples: + +``` +<SET L (1 2 3)> +<PUTPROP .L FOO "Hello">-->(1 2 3) +<GETPROP .L FOO>-->"Hello" +<PUTPROP .L FOO>-->"Hello" +<GETPROP .L FOO>-->#FALSE +;"PROPSPEC, loop through all words and add to buzz" +<VERSION XZIP> +<OBJECT FOO +(ADJECTIVE SMALL CURIOUS) +(MYBUZZ "ABCD" "BAR" "BAZ")> +<DEFINE MYBUZZ-PROP (L) +<SET L <REST .L>>;"Ignore MYBUZZ in LIST" +<MAPF ,LIST <FUNCTION (W) <VOC .W BUZZ>> .L>> +<PUTPROP MYBUZZ PROPSPEC MYBUZZ-PROP> +<ROUTINE GO () <TEST-PROPSPEC>> +<ROUTINE TEST-PROPSPEC ("AUX" W) +<TELL "Part-of-Speech, 4 = BUZZ" CR> +<SET W W?ABCD> +``` + +- 93 - + +``` +<TELL "ABCD = " N <GETB .W 6> CR> +<SET W W?BAR> +<TELL "BAR = " N <GETB .W 6> CR> +<SET W W?BAZ> +<TELL "BAZ = " N <GETB .W 6> CR>> +``` + +## **PUTREST** + +``` +<PUTREST list new-rest> +``` + +``` +MDL built-in +``` + +`PUTREST` replaces the `REST` of `list` with `new-rest` and returns `list` . In other words, `list` is assigned the first element of `list` and then all the elements from `new-rest` . Note that this actually changes the `list` . + +Examples: + +``` +<PUTREST (1 2 3) (A B)>-->(1 A B) +<SET L1 [<SET L2 (1 2 3)>]> +<PUTREST .L2 (A B)> +.L1-->[(1 A B)] +<SET L1 [1 2 3]> +<SET L2 <PUTREST (!.L1) (A B)>> +.L1-->[1 2 3] +.L2-->(1 A B) +<SET L1 (1 2 3 4 5 6 7 8 9)> +<PUTREST <REST .L1 3> <REST .L1 7>> +.L1-->(1 2 3 4 8 9) +``` + +## **QUIT** + +``` +<QUIT [exit-code]> +``` + +``` +MDL built-in +``` + +`QUIT` exits ZILF (interpreter mode) and returns to the operating system with `exit-code` . Example: + +``` +<QUIT> +``` + +## **QUOTE** + +``` +<QUOTE value> +'value;"Alternative syntax" +MDL built-in +``` + +`QUOTE` returns `value` unevaluated. + +Examples: + +`<SET F <QUOTE <+ 1 2>> --> Or <SET F '<+ 1 2>>` - 94 - + +``` +.F--><+ 1 2> +<EVAL .F>-->3 +'%<+ 1 2>-->3 +``` + +## **READSTRING** + +``` +<READSTRING buffer-str channel [max-length-or-stop-chars]> +``` + +``` +MDL built-in +``` + +`READSTRING` reads bytes from the `channel` into `buffer-str` and returns the number of bytes read into `buffer-str` . The `buffer-str` needs to have room for the input. For each call to `READSTRING` it either reads bytes to fill up the `buffer-str` or until + +`max-length-or-stop-chars` is reached. The `max-length-or-stop-chars` can be a `FIX` number of bytes or a `STRING` that halts input. + +`READSTRING` returns the actual number of bytes read and returns 0 when the EOF is reached. + +Example: + +; `"ZILF ver 0.9" <SET CH <OPEN "READ" "../zillib/parser.zil">> <SET BUFFER <ISTRING 10>> <READSTRING .BUFFER .CH> --> 10 <LVAL BUFFER> --> "\"Library h" <READSTRING .BUFFER .CH 6> --> 6 <LVAL BUFFER> --> "eader\"ry h" <READSTRING .BUFFER .CH "ZIL"> --> 10 <LVAL BUFFER> --> "\n\n<SETG " <CLOSE .CH> ;"\n = CR+LF"` + +## **REMOVE** + +``` +<REMOVE pname oblist> +<REMOVE atom> +``` + +``` +MDL built-in +``` + +This `REMOVE` s the `ATOM` with `pname` from `oblist` . It returns `FALSE` If the `ATOM` is not on the `oblist` . + +`<REMOVE atom> REMOVE` s the atom from its `OBLIST` . `FALSE` is returned if it's not on its `OBLIST` . + +## Examples: + +``` +FOO +<1 .OBLIST>-->(... ("FOO" FOO)) +<REMOVE FOO> +<1 .OBLIST>-->FOO is removed from <1 .OBLIST> +FOO-1!-OB +FOO-2!-OB +``` + +- 95 - + +``` +<MOBLIST OB>-->FOO-1, FOO-2 on OB +<REMOVE "FOO-1" <MOBLIST OB>>-->FOO-1!-#FALSE () +<MOBLIST OB>-->Only FOO-1 on OB +<REMOVE FOO-2!-OB> +<MOBLIST OB>-->OB is empty +``` + +## **RENTRY** + +``` +<RENTRY atoms ...> +``` + +``` +MDL package system +``` + +`RENTRY` creates/moves one or more `ATOM` s to `<ROOT>` in a `PACKAGE` or `DEFINITION` . `RENTRY` is only valid inside a `PACKAGE` or `DEFINITION` , if it's used outside an error is raised. + +See `DEFINITIONS` , `ENTRY` , `INCLUDE` , `INCLUDE-WHEN` , `PACKAGE` , `USE` , `USE-WHEN` . Examples: + +``` +<REMOVE ANSWER> ;"Secure that ATOM not on any OBLIST" +<PACKAGE "FOO"> +<SETG ANSWER 42> +<RENTRY ANSWER> +<ENDPACKAGE> +,ANSWER-->42 ;”Accessible without previous USE” +``` + +## **REPEAT** + +``` +<REPEAT [activation] (bindings ...) [decl] expressions...> +``` + +``` +MDL built-in +``` + +`REPEAT` defines a program block with its own set of `bindings` . `REPEAT` is similar to `BIND` and `PROG` but unlike `BIND` it creates a default `activation` (like `PROG` ) at the start of the block but unlike `PROG` it also has an automatic `AGAIN` at the end of the block. It is possible to name an `atom` to the `activation` but it is not necessary. A REPEAT-block repeatedly executes expressions until it encounters a `RETURN` statement that will exit the block. + +The `decl` is used to specify the valid `TYPE` of the variables. In its simplest form `decl` is formatted like: `#DECL ((X) FIX)` , meaning that X must be of the `TYPE FIX` . For more information on how to format the `decl` see `GDECL` . + +Also see `AGAIN` , `BIND` , `PROG` and `RETURN` for more details how to control program flow. Example: + +``` +<REPEAT ((X 1)) #DECL ((X) FIX) +<REPEAT ((X 2)) <PRIN1 .X> <RETURN>> +<PRIN1 .X> <RETURN>> +--> "21" +<DEFINE TEST-REPEAT () +<PRINC "START "> +<REPEAT ((X 0)) +``` + +- 96 - + +``` +<SET X <+ .X 1>> +<PRIN1 .X> +<COND (<=? .X 3> <RETURN>)>;"--> exit block" +> +<PRINC " END"> +> +<TEST-REPEAT>--> "START 123 END" +``` + +## **REPLACE-DEFINITION** + +``` +<REPLACE-DEFINITION name body ...> +``` + +``` +ZIL library +``` + +This tells the compiler this block of code defined by `name` should replace a later `DEFAULT-DEFINITION` block of code with the same `name` . + +This is usually used when there is a library that is inserted (like "parser.zil") where some definitions are possible to override. + +Note that the `REPLACE-DEFINITION` is required to appear before the `DEFAULT-DEFINITION` . + +It is possible to do the same by setting `REDEFINE` to true. This actually makes it possible to change ALL definitions (it is the last one that becomes the one actually compiled). + +See `DEFAULT-DEFINITION` and `REPLACE-DEFINITION` .. + +## **REST** + +``` +<REST structure [count]> +``` + +``` +MDL natvive +``` + +Return `structure` without its first `count` elements ( `count` is default 1). Note that this is not a copy of the `structure` , it is pointing to the same `structure` with another starting element. + +`structure` must be an object that `STRUCTURED?` evaluates to true. + +Note that `TABLE` is not a `structure` . + +Also see `BACK` , `LENGTH` , `NTH` , `PUT` , `SUBSTRUC` and `TOP` . + +Example: + +``` +<SETG STRUCT1 [1 2 3 4]>-->STRUCT1 = [1 2 3 4] +<SETG STRUCT2 <REST ,STRUCT1>>-->STRUCT2 = [2 34] +<PUT ,STRUCT2 1 5>-->STRUCT1 = [1 5 3 4], +STRUCT2 = [5 3 4] +``` + +## **RETURN** + +``` +<RETURN [value] [activation]> +``` + +``` +MDL built-in +``` + +- 97 - + +This returns `value` from program-block defined by `activation` . True is returned if no `value` is specified. If `activation` is not specified `RETURN` will exit the current defined program-block where an automatic `activation` was created ( `PROG` and `REPEAT` creates automatic `activations` , `BIND` does not). + +In practice `RETURN` exits current program-block and returns `value` to outer program-block defined by `BIND` (needs `activation)` , `PROG` or `REPEAT` . + +See `AGAIN` , `BIND` , `PROG` and `REPEAT` for more examples of using `RETURN` and details how to control program flow. + +Examples: + +``` +<PROG () <RETURN>>-->T +<PROG ACT () +<PROG () <RETURN 42 .ACT>> +<RETURN 43>>;"Never reached"-->42 +``` + +## **ROOM** + +``` +<ROOM name (property value ...) ...> +``` + +``` +ZIL library +``` + +`ROOM` creates a room-object with the internal objectname, `name` . After the name follows `LIST` s of properties for the `ROOM` and the `value` s for each `property` . Which properties that define up a `ROOM` is determined by the parser and it’s possible to add new properties with `PROPDEF` as long as the parser is modified to support the new `property` . Usually the below properties are understood by the parser and the properties `IN` (or `LOC` ), `DESC` and `FLAGS` are required, the others are optional. + +|parser and the<br>l.|properties`IN`(or`LOC`),`DESC`and`FLAGS`are required, the others are| +|---|---| +|`IN`or`LOC`|Required`property`. The value is always`ROOMS`for`ROOM`-objects.| +|`DESC`|Required`property`. The short description text of the`ROOM`. This is the| +||text that is, for example, printed in the statusbar.| +|`FLAGS`|Required`property`. This lists all the flagbits that are set on this`ROOM`.| +|`LDESC`|Optional`property`. The long description of the ROOM. This is the text| +||that is printed, for example, the first time the player visits the`ROOM`| +|`(dir ...)`|Optional`property`. List a direction, dir and where it leads. There is 5| +||different types of EXITS:| +||`UEXIT`(“unconditional exit”). The syntax is`(dir TO room-name)`. If| +||the player moves in this direction he is moved unconditionally to| +||`room-name`.| +||`NEXIT`(“non-exit”). The syntax is`(dir "text-why-not")`. The| +||`text-why-not`is printed when the player tries to move in this direction.| +||Use this only if you want a different text than the standard message, typically| +||something like`"You can’t move in that direction!"`.| +||`CEXIT`(“conditional exit”). The syntax is`(dir TO room-name IF`| +||`gval [ELSE "text-why-not"])`. This moves the player if the global| +||value,`gval`, is`TRUE`. The`ELSE`-part is optional and the standard message| +||is printed if it is not supplied.| +||`DEXIT`(“door-exit”). The syntax is`(dir TO room-name IF`| +||`door-name IS OPEN)`. This is a special case of`CEXIT`that moves the| + + + +- 98 - + +player to `room-name` if the `door-name` has the `OPENBIT` set. `FEXIT` (“function-exit”). The syntax is `(dir PER routine-name)` . This moves the player to the `ROOM` returned by the `ROUTINE` , `routine-name` . If the routine returns `FALSE` it is presumed that the routine has printed an appropriate message. `GLOBAL` Optional `property` . This is a `LIST` of all the `OBJECT` s that is `IN` the `LOCAL-GLOBALS` that are accessible from this `ROOM` . This could, for example, be a door that is accessible from two different `ROOM` s. `THINGS` Optional `property` . This creates one or more simple “pseudo-objects”. Each object has three parts: a `LIST` of adjectives ( `FALSE` if none), a `LIST` of nouns and the name of the action-routine to call when this object is accessed. In early Infocom games this property was called `PSEUDO` and had a slightly different syntax. + +`ACTION` Optional `property` . The syntax is `(ACTION routine-name)` . This `ROUTINE` takes one argument, by convention call `RARG` (“room-argument”), and is called more than once during a turn with different values to `RARG` . `M-BEG` , the `routine-name` is called with this value to `RARG` before any `OBJECT` s or `verb` action-routines. `M-END` , the `routine-name` is called with this value to `RARG` after any `OBJECT` s or `verb` action-routines. + +`M-LOOK` , the `routine-name` is called with this value to `RARG` when the player `LOOK` s. + +`M-ENTER` , the `routine-name` is called with this value to `RARG` when the player enters the `ROOM` (before any room description). + +Note that `ROOM` s can just as easily be created with `OBJECT` as long as they are `(IN ROOMS)` . + +See _Learning ZIL, Steve E. Meretzky_ and _ZIL Course, Marc S. Blank_ for more on properties, flagsbits and how to write and design games. + +Example: + +``` +<ROOM INSIDE-HOUSE +(DESC "Inside House") +(IN ROOMS) +(LDESC +``` + +``` +"You are standing inside the rotting house. The houseis +sparsely furnished, in fact not at all. On one wallis +positioned a sign. Beside the sign is a button,and an open +trap-door is placed on the floor. The exit is west +and there is a walk-in closet in the eastern wall.") +(UP "You have yet to master the art of flying.") +(EAST TO CLOSET) +(WEST TO OUTSIDE-HOUSE IF FRONT-DOOR-FLAG ELSE ,MSG-025) +(DOWN PER TRAP-DOOR-F) +(ACTION INSIDE-HOUSE-F) +(FLAGS LIGHTBIT NDUNGEONBIT) +(THINGS (<>) (BUTTON) LIGHTBUTTON-F +(<>) (SIGN) HOUSE-SIGN-F +(<>) (HOUSE FLOOR CLOSET KEYHOLE) STANDARD-F) +(GLOBAL FRONT-DOOR)> +``` + +- 99 - + +## **ROOT** + +``` +<ROOT> +``` + +``` +MDL built-in +``` + +`ROOT` returns the `OBLIST` containing names of primitives (the same as `<2 .OBLIST>` ). Initially it contains all predefined `SUBR` s or `FSUBR` s, as well as `OBLIST` , `DEFAULT` , `T` , etc. + +## **ROUTINE** + +``` +<ROUTINE name [activation-atom] arg-list body ...> +``` + +``` +ZIL library +``` + +The `ROUTINE` s are the central building block in a ZIL-program. Inside the ROUTINE it is only possible to use the reduced instruction set that can be executed on the Z-machine. It is the instructions inside the ROUTINEs that are compiled to the actual ZIP-program. + +`ROUTINE` defines a program block with its own set of `bindings` . It is possible to specify an `activation-atom` to use as an argument to control the `RETURN` statement inside the `ROUTINE` . + +The arg-list is formatted the same way as FUNCTION, but the legal tokens is reduced to these: + +|`Arguments`|The required`arguments`for this`ROUTINE`. The`arguments`are|| +|---|---|---| +||bound to local variables inside this`ROUTINE`.|| +|`"OPT"`|The optional`arguments`for this`ROUTINE`. The`arguments`are|| +||bound to local variables inside this`ROUTINE`and can be defined with|| +||a default value.`"OPTIONAL"`is an alias for`"OPT"`.|| +|`"AUX"`|Followed by any number of`ATOM`s that becomes local variables inside|| +||this`ROUTINE`and can be defined with a default value.`"EXTRA"`|| +||is a alias for`"AUX"`.|| +|`"NAME"`|Followed by an`ATOM`that becomes the`activation-atom`for this|| +||`ROUTINE`. This is equivalent to naming the`activation-atom`|before| +||the`arg-list`.`"ACT"`is an alias for`"NAME"`.|| + + + +Default values for `"OPT"` and `"AUX"` are defined by a two-element `LIST` whose first element is the `ATOM` and the second element is assigned to. + +``` +<ROUTINE TEST ("AUX" (X 1) (Y 2)) <+ .X .Y>> +``` + +Means that the local variables `X` and `Y` are initially assigned 1 and 2. + +After the `arg-list` follows the ZIL-instructions that makes up the `body` of the `ROUTINE` . Example: + +``` +;"Move all child objects from object src to objectdst" +<ROUTINE MOVE-INVENTORY (SRC DST "AUX" X N) +``` + +``` +<SET X <FIRST? .SRC>> +<REPEAT () +<COND (.X +<SET N <NEXT? .X>> +``` + +- 100 - + +``` +<MOVE .X .DST> +<SET X .N>) +(T <RETURN>)>>> +``` + +## **ROUTINE-FLAGS** + +``` +<ROUTINE-FLAGS CLEAN-STACK?> +``` + +``` +ZIL library +``` + +This sets flags to control how ZILF should compile. To clear, call FILE-FLAGS without any flags. The flags are: + +`CLEAN-STACK?` Tells the compiler to generate extra code to remove unneeded values from the stack. Without it, the compiler will generate smaller code in some cases, at the risk of potentially causing stack overflow at runtime. + +Examples: + +``` +<FILE-FLAGS CLEAN-STACK?> +``` + +## **SET** + +``` +<SET atom value [environment]> +``` + +``` +MDL built-in +``` + +Assign `value` to the local `atom` . + +It is possible to supply an `environment` for `SET` . See `EVAL` for more about the `environment` . Example: + +``` +<PROG (X) <SET X 5> <RETURN .X>>-->5 +``` + +## **SET-DEFSTRUCT-FILE-DEFAULTS** + +``` +<SET-DEFSTRUCT-FILE-DEFAULTS args ...> +``` + +``` +MDL built-in +``` + +`SET-DEFSTRUCT-FILE-DEFAULTS` is used to change the default behaviour of the `struct-option` and the `field-option` tokens in `DEFSTRUCT.` + +The newly defined defaults are only active in the same file as they were defined. If a file is loaded via, for example, `FLOAD` or `INSERT-FILE` the defaults are the built-in defaults inside these files. + +If `SET-DEFSTRUCT-FILE-DEFAULTS` is called without any arguments the built-in default behaviour is restored. + +The tokens that can have changed default behaviour are: + +- `'CONSTRUCTOR` Replace the default constructor ( `MAKE-` ). + +- `'INIT-ARGS` Replace the init arguments to the base-type. This is empty by default. `'NODECL` Use `'NODECL` , to get `'NODECL` by default. + +- 101 - + +`‘NOTYPE` Use `'NOTYPE` , to get `'NOTYPE` by default. `'NTH` Default `ATOM` for this is `NTH` . Change to other with `('NTH MY-NTH)` . `'PRINTTYPE` Change the default `ATOM` for `PRINTTYPE` with `('PRINTTYPE MY-PRINTTYPE)` . `'PUT` Default `ATOM` for this is `PUT` . Change to other with `('PUT MY-PUT)` . `'START-OFFSET` Default value is 1. Change with `('START-OFFSET value)` . + +See `DEFSTRUCT` for more on user defined structures. Example: + +``` +<SET-DEFSTRUCT-FILE-DEFAULTS ('NTH GETB) ('PUT PUTB) +('START-OFFSET 0) 'NODECL ('INIT-ARGS (BYTE))> +<DEFSTRUCT B-TBL TABLE (B-TBL-X FIX 65) (B-TBL-YFIX 111)> +<MAKE-B-TBL>-->#B-TBL %<TABLE (BYTE) 65 111> +<B-TBL-Y <MAKE-B-TBL>>-->111 +``` + +## **SETG** + +``` +<SETG atom value> +``` + +``` +MDL built-in +``` + +Assign `value` to the global `atom` . If an `atom` already is assigned a `value` , it is changed. Example: + +``` +<SETG MYVAR 42>-->Store 42 in global atom MYVAR +``` + +## **SETG20** + +``` +<SETG20 atom value> +``` + +``` +ZIL library +``` + +Assign `value` to the global `atom` . If an `atom` already is assigned a `value` , it is changed. `SETG20` is an alias for `SETG` . + +Example: + +``` +<SETG20 MYVAR 42>-->Store 42 in global atom MYVAR +``` + +## **SORT** + +``` +<SORT predicate vector [record-size] [key-offset] +[vector [record-size] ...]> +``` + +``` +MDL built-in +``` + +`SORT` can sort a `VECTOR` (or `TUPLE` ). The `predicate` can either be `<>` or a `FUNCTION` that takes two keys and returns `TRUE` if the two records are correctly sorted and `FALSE` if they are incorrectly sorted. For example `,G?` will sort keys in ascending order and `,L?` will sort keys in + +- 102 - + +descending order. If the `predicate` is `<>` the keys must be of the same `TYPE` and the `vector` will be sorted in ascending order. + +The `record-size` is the length of each record (default value is 1) and the `key-offset` is the offset in the record to the value to use as the sort key (default value is 0). + +If additional `vector` s are supplied all `vector` s can have their own record length but each `vector` must have the same number of records. Records in the additional `vector` s are interchanged based on how the main `vector` is sorted. + +`SORT` returns the first sorted `vector` . + +Examples: + +``` +<SORT <> [3 4 2 1]>-->[1 2 3 4] +<SET V [1 MONEY 2 SHOW 3 READY 4 GO]> +<SORT <> .V 2 1>-->[4 GO 1 MONEY 3 READY 2 SHOW] +<SORT ,L? .V 2>-->[4 GO 3 READY 2 SHOW 1 MONEY] +<SET V [1 MONEY 2 SHOW 3 READY 4 GO]> +<SORT <> [5 1 6 3 7 2 8 4] 1 0 .V 1> +.V-->[MONEY READY SHOW GO 1 2 3 4] +``` + +## **SPNAME** + +``` +<SPNAME atom> +``` + +``` +MDL built-in +``` + +`SPNAME` ("shared printed name") should return the same string of the `atom` ’s pname that is in its `OBLIST` (i.e. pointing to the same storage and therefore not able to change or modify). + +ZILF treats `SPNAME` as an alias to `PNAME` and returns a string copy of the `atom` ’s pname. See `PNAME` . + +## **STRING** + +``` +<STRING values ...> +``` + +``` +MDL built-in +``` + +`STRING` returns a concatenated string of all `values` . `values` can be `character` or `string` . + +A string is a block of contiguous bytes where each byte holds a character. See more about `STRING` structure in _The MDL Programming Language, Appendix 1_ . + +Example: + +``` +<STRING !\A <ASCII 66> "CD">-->"ABCD" +``` + +## **STRUCTURED?** + +``` +<STRUCTURED? value> +``` + +``` +MDL built-in +``` + +- 103 - + +`STRUCTURED?` is a predicate and returns true if `value` is of a structured `TYPE` . The structured `TYPE` s are: + +``` +CHANNEL +DECL +FALSE +FORM +FUNCTION +LIST +MACRO +OBLIST +SEGMENT +SPLICE +STRING +VECTOR +``` + +Examples: + +``` +<STRUCTURED? <LIST 1 2 3>>-->T +<STRUCTURED? <TABLE 1 2 3>>-->#FALSE +``` + +## **SUBSTRUC** + +``` +<SUBSTRUC structure-from [rest] [amount] [structure-to]> +``` + +``` +MDL built-in +``` + +Copies an `amount` number of elements, starting at `rest` , from `structure-from` . The result is copied into `structure-to` , if supplied, otherwise a new `structure` is returned. + +Default value for `rest` is 0 and default value for `amount` is `LENGTH` – `rest` (in other words, copies from `rest` to end of `structure-from` ). + +`structure-from` must be of `PRIMTYPE LIST` , `VECTOR` or `STRING` and `structure-to` must be of the same `PRIMTYPE` as `struture-from` and have enough room for the `SUBSTRUC` to fit. + +Also see `BACK` , `LENGTH` , `NTH` , `PUT` , `REST` and `TOP` . + +Examples: + +``` +<SUBSTRUC "ABCD" 1 2>-->"BC" +<SETG STR1 "EEEEEE"> +<SUBSTRUC "ABCD" 1 2 ,STR1>-->STR1 = "BCEEEEEE" +``` + +## **SUPPRESS-WARNINGS?** + +``` +<SUPPRESS-WARNINGS? all | none | codes ...> +``` + +``` +ZILF compiler directive +``` + +`SUPPRESS-WARNINGS?` tells the compiler how to treat warnings. `NONE` is the default. + +- 104 - + +`ALL` Suppress all warnings. `NONE` Don’t suppress any warnings. `codes` Suppress listet warning codes. + +Examples: + +``` +;"Examples must be compiled with -w, otherwise warningsis +always suppressed." +``` + +``` +;"Compiles with warnings" +<SUPPRESS-WARNINGS? NONE> +<GLOBAL X 5> +<ROUTINE GO () <TELL N .X>> +;"Compiles with suppressed warnings" +<SUPPRESS-WARNINGS? ALL> +<GLOBAL X 5> +<ROUTINE GO () <TELL N .X>> +;"Compiles with suppressed warnings" +<SUPPRESS-WARNINGS? "ZIL0204"> +<GLOBAL X 5> +<ROUTINE GO () <TELL N .X>> +``` + +## **SYNONYM** + +``` +<SYNONYM original synonyms ...> +``` + +``` +ZIL parser library +``` + +`SYNONYM` creates one or more synonyms to the original verb, adjective, preposition or direction. Instead of `SYNONYM` it is also possible to use `VERB-SYNONYM, ADJ-SYNONYM` , `PREP-SYNONYM` and `DIR-SYNONYM` for verbs, adjectives, prepositions and directions respectively, ZILF handles them all like aliases to `SYNONYM` . + +Note that due to the way words, especially adjectives and nouns, are stored in the vocabulary synonyms for adjectives only work in version 3 (ZIP) games. + +## Examples: + +``` +<SYNONYM NORTH FORE> +<SYNONYM SOUTH AFT> +<SYNONYM WEST PORT> +<SYNONYM EAST STARBOARD> +<SYNTAX PUT OBJECT = V-INSERT> +<VERB-SYNONYM PUT SLIDE DIP SOAK> +``` + +## **SYNTAX** + +``` +<SYNTAX verb [prep1] [OBJECT] [(FIND flag-name)] +[(search-flags ...)] [prep2] [OBJECT] +[(FIND flag-name)] [(search-flags ...)] += action-routine-name [preaction-routine-name]> +``` + +- 105 - + +``` +ZIL parser library +``` + +`SYNTAX` defines a `verb` -phrase and specifies which `action-routine-name` should be called when an input matches this `verb` -phrase. A `SYNTAX` must contain a `verb` and an `action-routine-name` . Optionally it can contain one direct noun-phrase, the first token `OBJECT` , and one indirect noun-phrase, the second token `OBJECT` . Each noun-phrase can also have a corresponding preposition, `prep1` and `prep2` respectively. + +The noun-phrases can have `FIND` and search, `search-flags` , conditions defined. The token `FIND` means that the `OBJECT` must have the `flag-name` bit set. If there is only one `OBJECT` in the scope that meets the `FIND` condition the parser makes a GWIM (“Get what I mean”). For example if there is only one doore in the room with the `DOORBIT` set an `OPEN` assumes that you mean that door. + +One special case of `FIND` is when there is no indirect `OBJECT` but the `SYNTAX` ends with a preposition. In these cases a special bit, `KLUDGEBIT` (or `ROOMBIT` ), is used so that the player can type sentences like “turn machine on” ( `<SYNTAX TURN OBJECT (FIND DEVICEBIT) ON OBJECT (FIND KLUDGEBIT) = V-TURN-ON>` ). + +The `search-flags HAVE` , `MANY` and `TAKE` define the following rules for the `OBJECT` : + +|`HAVE`|The`OBJECT`must be in the player’s inventory (or inside open containers in| +|---|---| +||the player’s inventory). If the OBJECT is not in the inventory the parser fails| +||and prints something like “You don’t have the x,”.| +|`MANY`|It is possible to use multiple`OBJECT`s with this`verb`.| +|`TAKE`|If the`OBJECT`is not in the player’s inventory but takeble the parser| +||attempts to take the`OBJECT`, an so called implicit take is performed, before| +||continuing (the`OBJECT`is moved to the player’s inventoryand the parser| +||prints something like “[Taken.]”).| + + + +The `search-flags CARRIED` , `HELD` , `IN-ROOM` and `ON-GROUND` can be seen as hints to the parser where to first look for the `OBJECT` . These flags define the scope for the search. Note that these flags are only hints to the parser and if the `OBJECT` is not in the defined scope the parser continues the search in the other scopes before it fails. The default value for scope is that all flags are set. + +`CARRIED` Search for the `OBJECT` inside open containers in the player’s inventory. `HELD` Search for `t` he `OBJECT` in the player’s inventory at top-level (not inside other containers). `IN-ROOM` Search for `t` he `OBJECT` inside containers on the ground. `ON-GROUND` Search for `t` he `OBJECT` on the ground at the top-level. + +Finally after the token `=` (equal-sign) there is one or two `ROUTINE` -names specified, `action-routine-name` and `preaction-routine-name` (optional). By convention these handlers are usually named `V-verb` and `PRE-verb` , respectively. + +The `preaction-routine-name` is fired before the `OBJECT` s action-routine and the `action-routine-name` is fired after the `OBJECT` s action-routine. The preaction is usually used to check the prerequisites for the `verb` , for example that you have a weapon before attacking something so you don’t have to check that in every attackable `OBJECT` s action-routine. The `action-routine-name` is usually used to handle response when the `OBJECT` s action-routine fails. + +Each occurrence of an `action-routine-name` together with an optional + +- 106 - + +`preaction-routine-name` must always have the same pattern (same + +`action-routine-name` can’t exist with different `preaction-routine-name` s). + +It is possible to replace the `search-flags` with the `GVAL NEW-SFLAGS` . This is used with the new parser in Arthur, Shogun and Zork Zero where the `search-flags ALL` , `ROOM` , `HELD` , `CARRIED` , `IN-ROOM` , `ON-GROUND` , `EVERYWHERE` , `MOBY` and `ADJACENT` are defined. + +Examples: + +``` +<SYNTAX QUIT = V-QUIT> +<SYNTAX CONTEMPLATE OBJECT = V-THINK-ABOUT> +<SYNTAX TAKE OBJECT (FIND TAKEBIT) (MANY ON-GROUNDIN-ROOM) += V-TAKE> +<SYNTAX PUT OBJECT (MANY TAKE HELD CARRIED) IN OBJECT +(FIND CONTBIT) = V-PUT-IN PRE-PUT-IN> +<SYNTAX WAKE OBJECT (FIND PERSONBIT) = V-WAKE> +<SYNTAX WAKE UP OBJECT (FIND PERSONBIT) = V-WAKE> +<SYNTAX WAKE OBJECT (FIND PERSONBIT) UP OBJECT +(FIND KLUDGEBIT) = V-WAKE> +``` + +## **TABLE** + +``` +<TABLE [(flags ...)] values ...> +``` + +``` +ZIL library +``` + +Defines a table containing the specified `values` . + +These `flags` control the format of the table: + +- `WORD` causes the elements to be 2-byte words. This is the default. + +- `BYTE` causes the elements to be single bytes. + +- `LEXV` causes the elements to be 4-byte records. If `default` values are given to `ITABLE` with this flag, they will be split into groups of three: the first compiled as a word, the next two compiled as bytes. The table is also prefixed with a byte indicating the number of records, followed by a zero byte + +- `STRING` causes the elements to be single bytes and also changes the initializer format. This flag may not be used with `ITABLE` . When this flag is given, any `values` given as strings will be compiled as a series of individual ASCII characters, rather than as string addresses. + +These `flags` alter the table without changing its basic format: + +- `LENGTH` causes a length marker to be written at the beginning of the table, indicating the number of elements that follow. The length marker is a byte if `BYTE` or `STRING` are also given; otherwise the length marker is a `WORD` . This flag is ignored if `LEXV` is given + +- `PURE` causes the table to be compiled into static memory (ROM). + +The flag `LENGTH` is implied in `LTABLE` and `PLTABLE` . The flag `PURE` is implied in `PTABLE` and `PLTABLE` . + +Examples: + +``` +<TABLE 1 2 3 4> --> +``` + +``` +Element 0Element 1Element 2Element 3 +``` + +- 107 - + +|`WORD`|`WORD`|`WORD`|`WORD`| +|---|---|---|---| +|`1`|`2`|`3`|`4`| + + + +``` +<TABLE (BYTE LENGTH) 1 2 3 4> --> +``` + +|`Element 0`<br>`BYTE`|`Element 1`<br>`BYTE`|`Element 2`<br>`BYTE`|`Element 3`<br>`BYTE`|`Element 4`<br>`BYTE`| +|---|---|---|---|---| +|`4`|`1`|`2`|`3`|`4`| + + + +`TABLE` is a ZIL-specific structure that can be used both outside and inside `ROUTINES` . + +## **TELL-TOKENS** + +``` +<TELL-TOKENS {pattern form} ...> +``` + +``` +ZIL library +``` + +Replace current `TELL-TOKENS` with the specified list of `pattern` and `form` . These can then be used in `TELL` . See `ADD-TELL-TOKEN` for a description of `pattern` and `form` . + +Example (from Infocom's Trinity): + +``` +<TELL-TOKENS +``` + +``` +(CR CRLF)<CRLF> +(N NUM) *<PRINTN .X> +(C CHAR CHR) *<PRINTC .X> +(D DESC) *<PRINTD .X> +(A AN) *<PRINTA .X> +THE *<THE-PRINT .X> +CTHE *<CTHE-PRINT .X> +THEO<THE-PRINT> +CTHEO<CTHE-PRINT> +CTHEI<CTHEI-PRINT> +THEI<THEI-PRINT>> +``` + +## **TIME** + +``` +<TIME> +``` + +``` +MDL built-in +``` + +ZILF ignores this and always returns `1.` + +## **TOP** + +``` +<TOP array> +``` + +``` +MDL built-in +``` + +Returns array with all elements put back in `array` . + +- 108 - + +`TOP` only works on the structures `VECTOR` or `STRING` (arrays) and not on a `LIST` (a `LIST` is only pointing forward). + +Note that the returned `array` is not a copy but pointing to the same `array` with another starting element. + +Also see `BACK` , `NTH` , `PUT` , `REST` and `SUBSTRUC` . + +Example: + +``` +<SETG STRUCT1 [1 2 3 4 5]>-->STRUCT1 = [1 2 34 5] +<SETG STRUCT2 <REST ,STRUCT1 2>>-->STRUCT2 = [34 5] +<TOP ,STRUCT2>-->STRUCT2 = [1 2 3 4 5] +``` + +## **TUPLE** + +``` +<TUPLE values ...> +``` + +``` +MDL built-in +``` + +`TUPLE` is just like a `VECTOR` with the only difference that a `TUPLE` should live on the control stack. The advantage of a `TUPLE` over a `VECTOR` is that a `TUPLE` doesn't need to be garbage collected, the disadvantage is that a `TUPLE` only lives during the execution of the function where it was declared. It is only valid to declare a `TUPLE` in the `"AUX"` or `"OPTIONAL"` part of a functions definition or as a `"TUPLE"` in a functions definition. + +The above is not entirely true for ZILF. In ZILF, `TUPLE` is treated as an alias to `VECTOR` . + +A `TUPLE` defined in the `"AUX"` or `"OPT"` is just like a `VECTOR` . A `"TUPLE"` definition makes it possible to have a variable number of arguments to a `FUNCTION` . Examples: + +``` +<DEFINE MY+ ("TUPLE" T) +<REPEAT ((M 0)) +<COND (<EMPTY? .T> <RETURN .M>)> +<SET M <+ .M <1 .T>>> +<SET T <REST .T>> +> +> +<MY+ 1 2 3>-->6 +<MY+ 4 5>-->9 +<TYPE <TUPLE 1 2 3>>-->VECTOR (in ZILF!) +TUPLE (in MDL) +``` + +## **TYPE** + +``` +<TYPE value> +MDL built-in +``` + +evaluates to the type of `value` . See also `ALLTYPES` . + +- 109 - + +Examples: + +``` +<TYPE !\A>-->CHARACTER +<TYPE <+1 2>>-->FIX +<TYPE #BYTE 42>-->BYTE +``` + +## **TYPE?** + +``` +<TYPE? value type-1 ... type-N> +``` + +``` +MDL built-in +``` + +Evaluates to type-i only if `<==? type-i >` is true. It is faster and gives more information than `OR` ing tests for each `TYPE` . If the test fails for all type-i’s, `TYPE?` returns `#FALSE ()` . + +Examples: + +``` +<TYPE? !\A CHARACTER FIX>-->CHARACTER +<TYPE? <+1 2> CHARACTER FIX>-->FIX +<TYPE? #BYTE 42 CHARACTER FIX>-->#FALSE () +``` + +## **TYPEPRIM** + +``` +<TYPEPRIM type> +``` + +``` +MDL built-in +``` + +evaluates to the primitive type of `type` . The primitive types are `ATOM` , `FIX` , `LIST` , `STRING` , `TABLE` and `VECTOR` . + +Examples: + +``` +<TYPEPRIM CHARACTER>-->FIX +<TYPEPRIM FORM>-->LIST +<TYPEPRIM BYTE>-->FIX +``` + +## **UNASSIGN** + +``` +<UNASSIGN atom [environment]> +``` + +``` +MDL built-in +``` + +Unassign global `atom` . + +It is possible to supply an environment for `ASSIGNED?` . See `EVAL` for more about the `environment` . + +Example: + +``` +<SET X 1> +<ASSIGNED? X>-->True +<UNASSIGN X> +<ASSIGNED? X>-->False +``` + +- 110 - + +## **UNPARSE** + +``` +<UNPARSE value> +``` + +``` +MDL built-in +``` + +`UNPARSE` returns a `STRING` representation of `value` . Unlike `PNAME` , `UNPASE` prints an `ATOM` s trailers if required. + +Examples:USE + +``` +<UNPARSE 123>-->"123" +<UNPARSE <+ 1 2>>-->"3" +<UNPARSE FOO>-->"FOO" +<UNPARSE <ATOM "FOO">>-->"FOO!-#FALSE ()" +<PNAME <ATOM "FOO">>-->"FOO" +``` + +## **USE** + +``` +<USE package-name ...> +``` + +``` +MDL package system +``` + +`USE` activates one or many `package-name` s and makes its content available in the current `OBLIST` -path. In practice `USE` copies the `OBLIST package-name` and adds it last to the local `OBLIST` ( `<LVAL OBLIST>` ). This means that all `ATOM` s on the external package `OBLIST` becomes available in current environment. + +If the `package-name` is not available in the current environment, `USE` tries to load “ `package-name.zil` ” from the current path. + +`USE` only works together with `PACKAGE` and if the definition of the `package-name` is missing from the environment or no file is found containing that definition is found, an error is raised. + +See `PACKAGE` and `USE-WHEN` . + +Example: + +``` +<USE "FOOFOO">;"Searches for file "foofoo.zil" which +contains the definition for +<PACKAGE "FOOFOO"> ..." +``` + +## **USE-WHEN** + +``` +<USE-WHEN condition package-name ...> +``` + +``` +MDL package system +``` + +`USE-WHEN` is exactly like `USE` but only activates the `package-name` if the `condition` evaluates to `TRUE` . + +See `PACKAGE` and `USE` . + +- 111 - + +Example: + +``` +<PACKAGE "FOO"> +<SETG AAAA 1234> +<ENTRY AAAA> +<ENDPACKAGE> +<GASSIGNED? AAAA>-->#FALSE +<REMOVE AAAA> ;"Secure that ATOM not on any OBLIST" +<USE-WHEN <=? 1 2> "FOO"> +<GASSIGNED? AAAA>-->#FALSE +<REMOVE AAAA> ;"Secure that ATOM not on any OBLIST" +<USE-WHEN <=? 1 1> "FOO"> +,AAAA-->1234 +``` + +## **VALID-TYPE?** + +``` +<VALID-TYPE? atom> +``` + +``` +MDL built-in +``` + +`VALID-TYPE?` returns the `TYPE` if the `atom` is a valid name of a `TYPE` (the atom name is in `ALLTYPES` ), otherwise `FALSE` . + +Examples: + +``` +<VALID-TYPE? VECTOR>-->VECTOR +<VALID-TYPE? FOO>-->#FALSE +<NEWTYPE FOO FIX> +<VALID-TYPE? FOO>-->FOO +``` + +## **VALUE** + +``` +<VALUE atom [environment]> +``` + +``` +MDL built-in +``` + +`VALUE` returns the value of an `atom` . If the `atom` has an `LVAL` then the `LVAL` is returned, otherwise the `GVAL` of the `atom` is returned. + +It is possible to supply an environment for `VALUE` . See `EVAL` for more about the `environment` . Example: + +``` +<SETG X 3> +<SET X 4> +<VALUE X>;"--> 4 +<UNASSIGN X> +<VALUE X>;"--> 3 +``` + +## **VECTOR** + +``` +<VECTOR values ...> +[values ...];"Alternative syntax" +``` + +- 112 - + +``` +MDL built-in +``` + +This returns a `VECTOR` of containing `values` . + +A `VECTOR` is a collection of items that occupies a continuous block of memory. This makes it easy to traverse a `VECTOR` both forward and backward but costly to add or insert items in the `VECTOR` . See more about `VECTOR` structure in _The MDL Programming Language, Appendix 1_ . + +Note that in MDL there is another type of vector, `UVECTOR` (uniform vector). In an `UVECTOR` every item is of the same TYPE which makes an `UVECTOR` more space efficient. ZILF does not support `UVECTOR` but treats short form definitions of an `UVECTOR` as a ordinary `VECTOR` + +( `![1 2 3!] --> [1 2 3]` ). Examples: + +``` +<VECTOR 1 2 "AB" !\C>-->[1 2 "AB" !\C] +[1 2 "AB" !\C]-->[1 2 "AB" !\C] +<TYPE ![1 2 3!]>-->VECTOR (in ZILF) +UVECTOR (in MDL) +``` + +## **VERB-SYNONYM** + +``` +<VERB-SYNONYM original synonyms ...> +``` + +``` +ZIL parser library +``` + +`VERB-SYNONYM` creates one or more `synonyms` to the `original` verb. + +ZILF treats `VERB-SYNONYM` as an alias to `SYNONYM` . + +## **VERSION** + +``` +<VERSION {ZIP | EZIP | XZIP | YZIP | number} [TIME]> +``` + +``` +ZIL library +``` + +This tells the compiler which Z-machine version that this program is targeting. + +|Version|Description| +|---|---| +|`3 or ZIP`|Version 3 (file extension *.z3). Almost all classical Infocom<br>games are in this version. You are limited to 255 objects<br>(rooms+items) and the game can't be bigger than 128K.| +|`4 or EZIP`|Version 4 (file extension *.z4). Infocom's "plus" games – AMFV,<br>Bureaucracy, Nord and Bert... and Trinity. This format supports<br>65535 objects and agame size upto 256K.| +|`5 or XZIP`|Version 5 (file extension *.z5). Infocom's Beyond Zork, Border<br>Zone, Sherlock and the Solid Gold versions of older games. This<br>version adds things like UNDO, COLOR and timed input. This| + + + +- 113 - + +||format supports 65535 objects and agame size upto 256K.| +|---|---| +|`6 or YZIP`|Version 6 (file extension *.z6). Infocom's Arthur, Journey,<br>Shogun and Zork Zero. This version primarily adds graphics.<br>This version supports game size up to 512K.| +|`7`|Version 7 (file extension *.z7). Post Infocom version. This<br>version supports game size up to 512K. Rarely used version that<br>is superseded byversion 8.| +|`8`|Version 8 (file extension *.z8). Post Infocom version. This<br>version supportsgame size upto 512K.| + + + +In version `ZIP` the status line is drawn by the interpreter and the argument `TIME` specifies that the status line should display hh:mm instead of score and moves. Global variable 2, usually `SCORE` , holds the hour-part and global variable 3, usually `MOVES` , holds the minute-part. + +Examples: + +``` +<VERSION XZIP>;"Target Z-machine version 5" +<VERSION 8>;"Target Z-machine version 8" +<VERSION ZIP TIME>;"Target Z-machine version 3 withhh:mm" +<ROUTINE GO () +<SETG SCORE 13>;"Game starting 13:30" +<SETG MOVES 30> +> +``` + +## **VERSION?** + +``` +<VERSION? (version-spec body ...) ...> +``` + +``` +ZIL library +``` + +`VERSION?` Tell the compiler to use different code-blocks depending on the setting of `VERSION` . The `version-spec` can be: + +``` +3ZIP +4EZIP +5XZIP +6YZIP +7 +8 +ELSE/T +``` + +Example: + +``` +<VERSION? +``` + +``` +(ZIP <ROUTINE RTN-ZIP () ...>) +(XZIP <ROUTINE RTN-XZIP () ...>) +(ELSE <ROUTINE RTN-OTHER () ...>) +> +``` + +- 114 - + +## **VOC** + +``` +<VOC string [part-of-speech]> +``` + +``` +ZIL parser library +``` + +`VOC` inserts the `string` in the game vocabulary (dictionary). Normally there is no need to define the vocabulary with `VOC` , the vocabulary is automatically updated with words when you define `ROOM` s, `OBJECT` s, `SYNTAX` , etc. + +What follows below is a description of the vocabulary when you use the standard parser library. The vocabulary description for the new parser ( `<SETG NEW-PARSER? T>` ) is in `ADD-WORD` . + +The `part-of-speech` can be one of the following: + +|`rt-of-speech`can|be one of t|he following:| +|---|---|---| +|**`part-of-speech `**|**`Value`**|**`Description`**| +|`<>`|`0`|`None`| +|`BUZZ`|`4`|`Buzz-word`| +|`PREP`|`8`|`Preposition`| +|`DIR`|`16`|`Direction`| +|`ADJ`or`ADJECTIVE`|`32`|`Adjective`| +|`VERB`|`64`|`Verb`| +|`NOUN`or`OBJECT`|`128`|`Noun`| + + + +The vocabulary then occupies 6 or 9 bytes, depending on version, per entry distributed as follows. + +## **Version 3** + +|**Byte 0**|**Byte 1**|**Byte 2**|**Byte 3**|**Byte 4**|**Byte 5**|**Byte 6**| +|---|---|---|---|---|---|---| +|Word up to 6 Z-characters (5 bit)||||PoS|Value|V2| + + + +## **Version 4-** + +|**Byte 0**|**Byte 1**|**Byte 2**|**Byte 3**|**Byte 4**|**Byte 5**|**Byte 6**|**Byte 7**|**Byte 8**| +|---|---|---|---|---|---|---|---|---| +|Word up to 9 Z-characters (5 bit)||||||PoS|V1|V2| + + + +`PoS` Byte 6 (or byte 4) contains the `part-of-speech` value (as above) plus if the word is defined as a first `part-of-speech` in the first 2 bytes. `0 None 1 Verb first 2 Adjective first 3 Direction first V1` Byte 7 (or byte 5) contains the words value (id). Each part-of-speech can have 255 (65535 for `NOUN` s) unique words (synonyms have the same value as parent). `V2` Byte 8 is used for `NOUN` s (V1 & V2 gives 2 bytes, 1-65535 `OBJECT` s). + +The different `part-of-speech` and first definitions have all global values defined as: + +- 115 - + +``` +P1?OBJECT0 +P1?VERB1 +P1?ADJECTIVE2 +P1?DIRECTION3 +PS?BUZZ-WORD4 +PS?PREPOSITION8 +PS?DIRECTION16 +PS?ADJECTIVE32 +PS?VERB64 +PS?OBJECT128 +``` + +Example: + +**==> picture [340 x 478] intentionally omitted <==** + +``` +--> +FALSE: Pos=0, V1=0, V2=0 +``` + +- 116 - + +``` +NOUN: Pos=128, V1=1, V2=0 +BUZZ: Pos=4, V1=255, V2=0 +VERB: Pos=65, V1=255, V2=0 +ADJECTIVE: Pos=32, V1=0, V2=0 +PREP: Pos=8, V1=255, V2=0 +``` + +## **WARN-AS-ERROR?** + +``` +<WARN-AS-ERROR? value> +``` + +``` +ZILF compiler directive +``` + +`WARN-AS-ERROR?` set to `TRUE` , tells the compiler to convert compiler warnings to errors. The default value is `FALSE` . + +Examples: + +``` +;"Compiles with warning [ZIL0204]" +<WARN-AS-ERROR? <>> +<GLOBAL X 5> +<ROUTINE GO () <TELL N .X>> +;"Don’t compile with error [ZIL0204]" +<WARN-AS-ERROR? T> +<GLOBAL X 5> +<ROUTINE GO () <TELL N .X>> +``` + +## **XFLOAD** + +``` +<XFLOAD filename> +``` + +``` +ZIL library +``` + +ZILF ignores all but the first argument and treats `XFLOAD` as an alias to `INSERT-FILE` . + +## **XORB** + +``` +<XORB numbers ...> +``` + +``` +MDL built-in +``` + +Bitwise exclusive "or". Examples: + +``` +<XORB 250 245>-->11111010 XOR 11110101 = 00001111(15) +``` + +## **ZGET** + +``` +<ZGET table index> +``` + +``` +ZIL libarary +``` + +- 117 - + +Returns WORD-record (2 bytes) stored at `index` . + +`TABLE` is a ZIL-specific structure that can be used both outside and inside ROUTINES. `ZGET` is equivalent to the Z-code built-in `GET` . + +Also see `GETB` , `PUTB` , `ZPUT` and `ZREST` . + +Example: + +``` +<ZGET <TABLE 0 1 2 3> 2>-->2 +``` + +## **ZIP-OPTIONS** + +``` +<ZIP-OPTIONS {BIG | COLOR | DISPLAY | MENU | MOUSE| SOUND +| UNDO} ...> +``` + +``` +ZIL library +``` + +`ZIP-OPTIONS` sets the corresponding bits in the header. This tells the Z-machine that runs the game, the interpreter, that the game intends to use these functions. The interpreter can, if it is unable to provide the requested functionality, clear the bits in return. + +|**Option**|**Ver**|**Description**| +|---|---|---| +|`BIG`|X|ZILF ignores this.| +|`COLOR`|5-|Sets bit 6 of byte 16 (Flags 2) in header (see Appendix B).| +|`DISPLAY`|5-|Sets bit 3 of byte 16 (Flags 2) in header (see Appendix B).| +|`MENU`|6-|Sets bit 8 of byte 16 (Flags 2) in header (see Appendix B).| +|`MOUSE`|5-|Sets bit 5 of byte 16 (Flags 2) in header (see Appendix B).| +|`SOUND`|5-|Sets bit 7 of byte 16 (Flags 2) in header (see Appendix B).| +|`UNDO`|5-|Sets bit 4 of byte 16 (Flags 2) in header (see Appendix B).| + + + +Example (From zillib/parser.zil in ZILF 0.9): + +; `"Use UNDO and COLOR if version is 5+" <VERSION?` + +``` +(ZIP) +(EZIP) +(ELSE <ZIP-OPTIONS UNDO COLOR>)> +``` + +## **ZPACKAGE** + +``` +<ZPACKAGE package-name> +``` + +``` +ZIL library +``` + +`ZPACKAGE` is an alias to `PACKAGE` . + +## **ZPUT** + +``` +<ZPUT table index new-value> +``` + +``` +ZIL library +``` + +Put a 16-bit WORD `new-value` in the `table` at word position `index` . Actual address is + +- 118 - + +table-address+index*2. + +`TABLE` is a ZIL-specific structure that can be used both outside and inside `ROUTINES` . `ZPUT` is equivalent to the Z-code built-in `PUT` . + +Also see `GETB` , `PUTB` , `ZGET` and `ZREST` . + +Examples: + +``` +<ZPUT ,MYTABLE 1 123>-->Stores 123 at position1 +in MYTABLE +``` + +## **ZREST** + +``` +<ZREST table bytes> +``` + +``` +ZIL library +``` + +Return `table` without its first `bytes` . Note that this is not a copy of the `table` , it is pointing to the same `table` with another starting address. + +`TABLE` is a ZIL-specific structure that can be used both outside and inside `ROUTINES` . `ZREST` is equivalent to the Z-code built-in `REST` . + +Also see `GETB` , `PUTB` , `ZGET` and `ZPUT` . + +Example: + +``` +<SETG TBL1 <TABLE 1 2 3 4>>-->TBL1 = [1 2 3 4] +<SETG TBL2 <ZREST ,TBL1 2>>-->TBL2 = [2 3 4] +Move 2 because +WORD-table! +<ZPUT ,TBL2 0 5>-->TBL1 = [1 5 3 4], +TBL2 = [5 3 4] +``` + +## **ZSECTION** + +``` +<ZSECTION package-name> +``` + +``` +ZIL library +``` + +`ZSECTION` is an alias to `DEFINITIONS` . + +## **ZSTART** + +``` +<ZSTART atom> +``` + +``` +ZIL library +``` + +Default starting `ROUTINE` for a compiled ZIL program is the `ROUTINE GO` . `ZSTART` can move to ZIL entry point to another `ROUTINE` . + +Example: + +``` +<ZSTART MAIN>-->Starts with ROUTINE MAIN insteadof GO +``` + +- 119 - + +## **ZSTR-OFF** + +``` +<ZSTR-OFF> +``` + +``` +ZIL library +``` + +ZILF ignores this and always returns `FALSE` . + +## **ZSTR-ON** + +``` +<ZSTR-ON> +``` + +``` +ZIL library +``` + +ZILF ignores this and always returns `FALSE` . + +## **ZZPACKAGE** + +``` +<ZZPACKAGE package-name> +``` + +``` +ZIL library +``` + +`ZZPACKAGE` is an alias to `PACKAGE` . + +## **ZZSECTION** + +``` +<ZZSECTION package-name> +``` + +``` +ZIL library +``` + +`ZZSECTION` is an alias to `DEFINITIONS` . + +- 120 - + +## _**Z-code built-ins (use inside ROUTINE)**_ + +Sources: + +_ZIP: Z-language Interpreter Program, Joel M. Berez, Marc S. Blank and P. David Lebling The Z-Machine Standards Document, Graham Nelson_ + +_The Inform Designer’s Manual, Graham Nelson_ + +_ZIL Language Guide, Jesse McGrew_ + +## ***, MUL** + +``` +<* numbers ...> +<MUL numbers ...>;"Alternative syntax" +``` + +``` +Zapf syntaxInform syntax +MULmul +``` + +Multiply `numbers` . Example: + +``` +<* 2 3 4>-->24 +``` + +## **+, ADD** + +``` +<+ numbers ...> +<ADD numbers ...>;"Alternative syntax" +Zapf syntaxInform syntax +ADDadd +All versions +``` + +Add `numbers` . + +Example: + +``` +<+ 2 3 4>-->7 +``` + +## **-, SUB** + +``` +<- numbers ...> +<SUB numbers ...>;"Alternative syntax" +<BACK number1 number2>;"Alternative syntax" +Zapf syntaxInform syntax +SUBsub +All versions +``` + +Subtract first `number` by subsequent `numbers` . + +- 121 - + +If only one `number` is provided, it's subtracted from zero (i.e. negated). Note that it is possible to use BACK as an alias for `SUB` . Example: + +``` +<- 8 3 4>-->1 +<- 4>→-4 +<BACK 2>-->1(Defaults to 1) +<BACK 1 2>-->-1 +``` + +## **/, DIV** + +``` +</ numbers ...> +<DIV numbers ...>;"Alternative syntax" +Zapf syntaxInform syntax +DIVdiv +All versions +``` + +Divide first `number` by subsequent `numbers` . Example: + +``` +<* 20 5 2>-->2 +``` + +## **0?, ZERO?** + +``` +<0? value> +<ZERO? Value>;"Alternative syntax" +``` + +``` +Zapf syntaxInform syntax +ZERO?Jz +All versions +``` + +Predicate. True if `value` is 0 otherwise false. Example: + +``` +<0? <- 1 1>>-->TRUE +``` + +## **1?** + +``` +<1? value> +``` + +Predicate. True if `value` is 1 otherwise false. Example: + +``` +<1? <- 2 1>>-->TRUE +``` + +## **=?, ==?, EQUAL?** + +``` +<=? value1 value2...valueN> +``` + +- 122 - + +``` +<==? value1 value2...valueN>;Alternative syntax" +<EQUAL? value1 value2...valueN>;Alternative syntax" +``` + +``` +Zapf syntaxInform syntax +EQUAL?Je +``` + +``` +All versions +``` + +Predicate. True if `value1` is equal to any of the values `value2` to `valueN` . Examples: + +``` +<=? 1 1>-->TRUE +<=? 1 2>-->FALSE +<=? 1 2 1>-->TRUE +``` + +## **AGAIN** + +``` +<AGAIN [activation]> +``` + +`AGAIN` means "start doing this again", where "this" is `activation` . If no `activation` is supplied the most recent is used. In practice `AGAIN` is used to restart a program block ( `BIND` , `DO` , `PROG` , `REPEAT` or `ROUTINE` ) again from the top. Note that arguments and variables for a `ROUTINE` are reinitialized (to starting value, if supplied) otherwise they keep values between iterations. `BIND` , `DO` , `PROG` and `REPEAT` don't reinitialize variables. + +Also see `BIND` , `DO` , `PROG` , `REPEAT` and `RETURN` for more details how to control program flow. Examples: + +``` +<ROUTINE TEST-AGAIN-1 ("AUX" X) +<SET X <+ .X 1>> +<TELL N .X " "> +<COND (<=? .X 5> <RETURN>)> +<AGAIN> ;"Start routine again, X keeps value" +> +<TEST-AGAIN-1>-->"1 2 3 4 5" +<ROUTINE TEST-AGAIN-2 ("AUX" (X 0)) +<SET X <+ .X 1>> +<TELL N .X " "> +<COND (<=? .X 5> <RETURN>)> ;"Never reached" +<AGAIN> ;"Start routine again, X reinitializeto 0" +> +<TEST-AGAIN-2>-->"1 1 1 1 1 ..." +<ROUTINE TEST-AGAIN-3 () +<BIND ACT1 ((X 0)) +<SET X <+ .X 1>> +<TELL N .X " "> +<COND (<=? .X 5> <RETURN>)> +<AGAIN .ACT1> ;"Start block again from ACT1," +> ;"X keeps value" +``` + +- 123 - + +``` +<TEST-AGAIN-3>-->"1 2 3 4 5" +<ROUTINE TEST-AGAIN-4 () +<PROG ((X 0)) ;"PROG generates default activation" +<SET X <+ .X 1>> +<TELL N .X " "> +<COND (<=? .X 5> <RETURN>)> +<AGAIN> ;"Start block again from PROG," +> ;"X keeps value" +<TEST-AGAIN-4>-->"1 2 3 4 5" +``` + +## **AND** + +``` +<AND expressions...> +``` + +Boolean `AND` . Requires that all `expressions` evaluate to true to return true. Exits on the first `expression` that evaluates to false (rest of `expressions` are not evaluated). + +Because 0 is considered false and all other values are considered true inside a routine `AND` returns 0 if one `expression` is false or the value of the last `expression` if all `expressions` are true. Example: + +``` +<AND <=? 1 1> <N=? 1 2>>-->True +<AND <=? 1 2> <SET X 2>>-->X never set to 2 because +first predicate evaluates +to false +<SET X <AND 1 2 3 0 4>>-->X is set to 0 +<SET X <AND 1 4 3 2>>-->X is set to 2 +``` + +## **APPLY** + +``` +<APPLY routine values...> +``` + +Call the `routine` with `values` . `<APPLY routine values ...>` is equivalent to `<routine values ...>` , but `APPLY` is often used when the `routine` to be called is resolved during run-time (dispatch-table). + +Examples: + +``` +<GLOBAL MYROUTINES <LTABLE ROUTINE1 ROUTINE2>> +``` + +``` +... +<APPLY <GET ,MYROUTINES 1> .X>--><ROUTINE1 .X> +<APPLY <GET ,MYROUTINES 2> .X>--><ROUTINE2 .X> +<APPLY <GETP .OBJECT ,P?ACTION>>-->Call ACTION-routine +on OBJECT +``` + +## **ASH, ASHIFT** + +``` +<ASH number places> +<ASHIFT number places>;"Alternative syntax" +``` + +``` +Zapf syntax +``` + +``` +Inform syntax +``` + +- 124 - + +``` +art_shift +``` + +``` +ASHIFT +``` + +``` +Versions: 5- +``` + +Arithmetic shift. Shift `number` left when `places` is positive and right if it is negative. When right shift the sign is preserved (if bit 15 is 1 a 1 is shifted in, otherwise a 0 is shifted in). + +``` +1000 0000 0000 1010-->1100 0000 0000 0101 +``` + +Also see `LSH` . Examples: + +``` +<ASH 4 1>-->8 +<ASH 4 -2>-->1 +``` + +## **ASSIGNED?** + +``` +<ASSIGNED? Name> +``` + +``` +Zapf syntaxInform syntax +ASSIGNED?check_arg_count +Versions: 5- +``` + +Predicate. Can test if an optional argument named `name` is supplied in call to routine. Example: + +``` +<ROUTINE TEST("OPT" X) +<COND (<ASSIGNED? X> +<TELL "X is assigned." CR> +) +(ELSE +<TELL "X is not assigned." CR> +)> +> +<TEST>--> X is not assigned. +<TEST 1>--> X is assigned. +``` + +## **BACK** + +``` +<BACK table [bytes]> +``` + +Return `table` with address moved `bytes` back. If the `count` moves past the start of the `table` no error is raised. Default value for `bytes` is 1. + +Note that this is not a copy of the `table` , it is pointing to the same `table` with another starting address. + +Also see `GET` , `GETB` , `PUT` , `PUTB` and `REST` . + +Example: + +``` +<GLOBAL TBL1 <TABLE 1 2 3 4>>-->TBL1 = [1 2 3 4] +``` + +**==> picture [33 x 9] intentionally omitted <==** + +``` +<GLOBAL TBL2 <REST ,STRUCT1 4>> +<SETG TBL2 <BACK ,TBL2 2>> +``` + +``` +-->TBL2 = [3 4] +Move 4 because +WORD-table! +-->TBL2 = [2 3 4] +``` + +## **BAND, ANDB** + +``` +<BAND numbers ...> +<ANDB numbers ...>;"Alternative syntax" +``` + +``` +Zapf syntaxInform syntax +BANDand +``` + +``` +All versions +``` + +Bitwise AND. + +Examples: + +``` +<BAND 33 96>-->32 +<BAND 33 96 64>-->0 +``` + +## **BCOM** + +``` +<BCOM value> +``` + +``` +Zapf syntaxInform syntax +BCOMnot +``` + +``` +All versions +``` + +Bitwise NOT. Reverse all bits in the `WORD value` (16 bits). + +Examples: + +``` +<BCOM #2 000011110001111>--> #2 1111000011110000 +``` + +## **BIND** + +``` +<BIND [activation] (bindings...) expressions...> +``` + +`BIND` defines a program block with its own set of `bindings` . `BIND` is similar to `PROG` but `BIND` doesn't create a default `activation` at the start of the block. If an `activation` is needed it must be specified. `AGAIN` and `RETURN` without specified `activation` inside a BIND-block will start over or return from the previous `activation` (most probably the `ROUTINE` ). + +Also see `AGAIN` , `DO` , `PROG` , `REPEAT` and `RETURN` for more details how to control program flow. Example: + +``` +<ROUTINE TEST-BIND-1 ("AUX" X) +<TELL "START "> +<SET X 1> +<BIND (X) +``` + +- 126 - + +``` +<SET X 2> +<TELL N .X " ">;"--> 2 (Inner X)" +> +<TELL N .X " ">;"--> 1 (Outer X)" +<TELL "END" CR> +> +--> "START 2 1 END" +<ROUTINE TEST-BIND-2 () +<TELL "START "> +<BIND (X) +<SET X <+ .X 1>> +<TELL N .X " "> +<COND (<=? .X 3> <RETURN>)> ;"--> exit routine" +<AGAIN> ;"--> top of routine" +> +<TELL "END" CR> ;"Never reached" +> +--> "START 1 START 2 START 3 " +``` + +## **BOR, ORB** + +``` +<BOR numbers ...> +<ORB numbers ...>;"Alternative syntax" +``` + +``` +Zapf syntaxInform syntax +BORor +``` + +``` +All versions +``` + +Bitwise OR. + +Examples: + +``` +<BOR 33 96>-->97 +<BOR 33 96 64>-->97 +``` + +## **BTST** + +``` +<BTST value1 value2> +``` + +``` +Zapf syntaxInform syntax +BTSTtest +All versions +``` + +Predicate. Binary test. Evaluates to true if all `value2` bits are set in `value1` . Could be expressed as `<=? <BAND value1 value2> value2>` . + +Examples: + +``` +<BTST 64 64>--> TRUE +<BTST 64 63>--> FALSE +``` + +- 127 - + +``` +<BTST 97 33>--> TRUE +``` + +## **BUFOUT** + +``` +<BUFOUT value> +``` + +``` +Zapf syntaxInform syntax +BUFOUTbuffer_mode +Versions: 4- +``` + +Flag that controls if output is buffered (to enable proper word-wrap). `value` can be true or false. Examples: + +``` +<BUFOUT <>>--> Turns off buffering(disables word-wrap) +<BUFOUT T>--> Turns on buffering +``` + +## **CATCH** + +``` +<CATCH> +``` + +``` +Zapf syntaxInform syntax +CATCHcatch +Versions: 5- +``` + +Used in conjunction with `THROW` . `CATCH` returns the current state of the stack (the "stack frame"). Also see `THROW` . + +Example: + +``` +<SETG CATCH-POINT <CATCH>>-->Saves the currentstack +frame in global variable +``` + +## **CHECKU** + +``` +<CHECKU character> +``` + +``` +Zapf syntaxInform syntax +CHECKUcheck_unicode +Versions: 5- +``` + +Checks if a given unicode `character` can be printed and/or received from the keyboard. Return is in bit 0 and 1 so the return result is either 0, 1, 2 or 3. + +- 0 = character can not be printed and not received from keyboard + +- 1 = character can be printed but not received from keyboard + +- 2 = character can not be printed but received from keyboard + +- 3 = character can both be printed and received from keyboard + +Example: + +- 128 - + +``` +<CHECKU 65>-->3 +``` + +## **CLEAR** + +``` +<CLEAR window-number> +``` + +``` +Zapf syntaxInform syntax +CLEARerase_window +Versions: 4- +``` + +Clears window with given `window-number` . If `window-number` is -1 it unsplit all windows and then clears the resulting window. If `window-number` is -2 it clears all windows without unsplitting. + +Example: + +``` +<CLEAR 0>--> Clears window 0 (the "main"-window) +``` + +## **COLOR** + +``` +<COLOR fg-color bg-color>;"Version 5" +<COLOR fg-color bg-color [window-number]>;"Versions:6-" +Zapf syntaxInform syntax +COLORset_colour +Versions: 5- +``` + +Print text in given f `g-color` and `bg-color` from this point on (flushing out text in buffer in old colors first). Version 6 supports a third argument, `window-number` . The colors available (if interpreter supports it) are: + +|orts it) are:|| +|---|---| +|0|Current color| +|1|Default color| +|2|Black| +|3|Red| +|4|Green| +|5|Yellow| +|6|Blue| +|7|Magenta| +|8|Cyan| +|9|White| + + + +Example: + +``` +<COLOR 2 9>--> Set black text against white background +``` + +- 129 - + +## **COND** + +``` +<COND (condition expressions...)...> +``` + +Test `condition` (predicate) and if `condition` evaluates to true `expressions` are executed. IF-THEN style: + +`<COND (<AND <=? 1 1> <=? 2 2>> <TELL "IF-THEN <...>">)>` IF-THEN-ELSE style: + +``` +<COND (<AND <=? 1 1> <=? 2 2>> +<TELL "THEN <...>" CR> +) +(ELSE;"Or T" +<TELL "ELSE <...>" CR> +)> +``` + +`COND` evaluates each `condition` in turn and executes the `expressions` directly after the first `condition` that evaluates to true. `ELSE` is an alias for `T` so if the first `condition` is false the second is always true and is executed. + +SWITCH style: + +**==> picture [383 x 136] intentionally omitted <==** + +Note that only one of the `(conditions expressions …)` is executed, the `conditions` after a `condition` that evaluates to true is skipped. + +``` +<COND +(T +<TELL "Variable SWITCH not in (1 2 3)" CR>) +(<=? .SWITCH 1> +<TELL "Variable SWITCH = 1" CR>) +(<=? .SWITCH 2> +<TELL "Variable SWITCH = 2" CR>) +(<=? .SWITCH 3> +<TELL "Variable SWITCH = 3" CR>) +> +``` + +In this case `conditions` for 1, 2 & 3 is never executed and should result in a compiler warning. + +## **COPYT** + +- 130 - + +``` +<COPYT src-table dest-table length> +``` + +``` +Zapf syntaxInform syntax +COPYTcopy_table +Versions: 5- +``` + +Copies `length` number of bytes from `src-table` to `dest-table` . The tables are allowed to overlap. If `length` is positive then the copy is done without corrupting the `src-table` . If `length` is negative the copy is always forward from `src-table` to `dest-table` (the absolute `length` number of bytes) even if this corrupts `src-table` . + +Example: + +``` +<GLOBAL TABLE1 <TABLE 1 2 3>> +<GLOBAL TABLE2 <TABLE 0 0 0>> +<ROUTINE TEST-COPYT() +<COPYT ,TABLE1 ,TABLE2 6> +<GET ,TABLE2 2> +> +``` + +``` +<TEST-COPYT>-->3 +``` + +## **CRLF** + +``` +<CRLF> +``` + +``` +Zapf syntaxInform syntax +CRLFnew_line +All versions +``` + +Prints carriage return and line feed. + +Example: + +``` +<CRLF>-->Moves cursor to position 1 on new line +``` + +## **CURGET** + +``` +<CURGET table> +``` + +``` +Zapf syntaxInform syntax +CURGETget_cursor +Versions: 4- +``` + +`CURGET` puts current cursor row in record 0 and current cursor column in record 1 of the supplied table.Both row and column are WORD (16-bit). + +Example: + +``` +<GLOBAL CURTABLE <TABLE 0 0>> +``` + +- 131 - + +``` +<ROUTINE TEST-CURGET () +<CURGET ,CURTABLE> +> +<TEST-CURGET>-->Puts current row and column inCURTABLE +``` + +## **CURSET** + +``` +<CURSET row column>;"Versions: 4-5" +<CURSET row column [window-number]>;"Versions: 6-" +``` + +``` +Versions: 4- +``` + +`CURSET` moves cursor to `row` and `column` in current window (or supplied `window-number` ). In versions 4-5 it is only possible to move the cursor in the upper window ( `window-number` = 1). In versions 6-, if `row` is -1 then the cursor is turned off (-2 turns it back on). + +Example: + +``` +<CURSET 1 1>-->Move cursor to upper left cornerin +current window +``` + +## **DCLEAR** + +``` +<DCLEAR picture-number [row] [column]> +``` + +``` +Zapf syntaxInform syntax +DCLEARerase_picture +Versions: 6- +``` + +Clears (draw background color) area covered by `picture-number` , starting at `row` and `column` . Also see `DISPLAY` . + +Example: + +``` +<DCLEAR 1 1 1>--> Clears picture 1 +``` + +## **DEC** + +``` +<DEC name> +``` + +``` +Zapf syntaxInform syntax +DECdec +``` + +``` +All versions +``` + +Decrease variable (signed) `name` with 1. + +Example: + +``` +<ROUTINE TEST-DEC (X) <DEC .X>> +``` + +- 132 - + +``` +<TEST-DEC 45>-->44 +<TEST-DEC 0>-->-1 +``` + +## **DIRIN** + +``` +<DIRIN stream-number> +``` + +``` +Zapf syntaxInform syntax +DIRINinput_stream +All versions +``` + +Select input stream. Only `stream-number` 0 and 1 are valid. + +0 Keyboard 1 File on host + +Example: + +``` +<DIRIN 0>-->True and select input stream keyboard +``` + +## **DIROUT** + +``` +<DIROUT stream-number [table]>;"Versions -5" +<DIROUT stream-number [table] [width]>;"Versions6-" +Zapf syntaxInform syntax +DIROUToutput_stream +``` + +Directs output to one or more output streams (multiple streams can be active simultaneously). Turn on stream with positive `stream-number` and turn off stream with negative `stream-number` . + +If stream 3 is active a `table` must be supplied. WORD 0 in `table` holds number of printed characters and byte 2 onward holds the characters printed. `DIROUT` can overrun `table` if not enough space is allocated. + +Later versions can format output text to `width` (number of characters if `width` is positive or number of pixels if `width` is negative). + +|can f<br>els if|ormat output text to`width` <br>`width`is negative).| +|---|---| +|1|Screen| +|2|File on host(transcript)| +|3|Table| +|4|File of commands on host| + + + +Example: + +``` +<DIROUT 3>-->Turns on output to file +<DIROUT -3>-->Turns off output to file +``` + +## **DISPLAY** + +``` +<DISPLAY picture-number [row] [column]> +``` + +- 133 - + +``` +Zapf syntaxInform syntax +DISPLAYdraw_picture +``` + +``` +Versions: 6- +``` + +Draw picture-number at coordinates row and column. If row and column are omitted the current cursor position is used. + +Example: + +``` +<DISPLAY 1>--> Draws picture 1 at current cursorposition +``` + +## **DLESS?** + +``` +<DLESS? name value> +``` + +``` +Zapf syntaxInform syntax +DLESS?dec_chk +All versions +``` + +Predicate. Decrease variable (signed) `name` with 1 and returns true if variable `name` is lower than `value` , otherwise returns false. + +Example: + +``` +<ROUTINE TEST-DLESS? (X) +<PRINTN <DLESS? X 100>> +<CRLF> +<PRINTN .X> +> +<TEST-DLESS? 101>-->"0\n100" +``` + +## **DO** + +``` +<DO (name start end [step]) +[(END expressions ...)] expressions ...> +``` + +A quirk of the DO statement, which can be thought of as a cross between a Pascal-style "for" statement and a C-style "for" statement. + +Pascal-style "for" statements loop over a range of values: + +``` +// Pascal +for i := 1 to 10 do ... +for j := 10 downto 1 do ... +// ZIL +<DO (I 1 10) ...> +<DO (J 10 1 -1) ...> +``` + +C-style "for" statements initialize some state, then mutate it and repeat until a condition becomes false. In ZIL, the condition is reversed - the loop exits when it becomes true: + +- 134 - + +``` +// C +for (i = first(obj); i; i = next(i)) { ... } +// ZIL +<DO (I <FIRST? .OBJ> <NOT .I> <NEXT? .I>) ...> +``` + +Notice that every Pascal-style loop can be transformed into a C-style loop: + +``` +// Pascal-style loops +<DO (I 1 10) ...> +<DO (J 10 1 -1) ...> +// C-style equivalents +<DO (I 1 <G? .I 10> <+ .I 1>) ...> +<DO (J 10 <L? .J 1> <- .J 1>) ...> +``` + +The quirk is that the behavior of DO depends on the syntax you use for each part. + +If the third value inside the parens is a complex FORM -- meaning one that isn't a simple LVAL or GVAL, like '.MAX' is -- it's assumed to be a "C-style" exit condition, otherwise it's assumed to be a "Pascal-style" upper/lower bound. Likewise, the optional fourth value is treated as either a C-style mutator or a Pascal-style step size. + +More of the DO statement's quirks are demonstrated here: + +``` +<ROUTINE GO () +<TEST-PASCAL-STYLE> +<TEST-C-STYLE> +<TEST-MIXED-STYLE> +<QUIT>> +<CONSTANT C-ONE 1> +<CONSTANT C-TEN 10> +<ROUTINE TEST-PASCAL-STYLE ("AUX" (ONE 1) (TEN 10)) +<TELL "== Pascal style ==" CR> +<TELL "Counting from 1 to 10..."> +;"1 2 3 4 5 6 7 8 9 10" +<DO (I 1 10) +(END <CRLF>) +<TELL " " N .I>> +<TELL "Counting from 1 to 10 with step 2..."> +;"1 3 5 7 9" +<DO (I 1 10 2) +(END <CRLF>) +<TELL " " N .I>> +<TELL "Counting from 10 to 1..."> +;"10 9 8 7 6 5 4 3 2 1" +<DO (I 10 1) +(END <CRLF>) +``` + +- 135 - + +``` +<TELL " " N .I>> +``` + +``` +<TELL "Counting from 10 to 1 with step -2..."> +;"10 8 6 4 2" +<DO (I 10 1 -2) +(END <CRLF>) +<TELL " " N .I>> +<TELL "Counting from .ONE to .TEN..."> +;"1 2 3 4 5 6 7 8 9 10" +<DO (I .ONE .TEN) +(END <CRLF>) +<TELL " " N .I>> +<TELL "Counting from .TEN to .ONE..."> +;"10" +;"Since the loop bounds aren't FIXes (numeric +literals), ZILF doesn't know the loop is meant +to count down, and it compiles a loop that counts +up and exits after the first iteration. A DO loop +whose condition is a constant or simple FORM always +runs at least once." +<DO (I .TEN .ONE) +(END <CRLF>) +<TELL " " N .I>> +<TELL "Counting from 10 to .ONE..."> +;"10" +;"See above." +<DO (I 10 .ONE) +(END <CRLF>) +<TELL " " N .I>> +<TELL "Counting from .TEN to 1..."> +;"10" +;"See above." +<DO (I .TEN 1) +(END <CRLF>) +<TELL " " N .I>> +<TELL "Counting from .TEN to .ONE with step -1..."> +;"10 9 8 7 6 5 4 3 2 1" +<DO (I .TEN .ONE -1) +(END <CRLF>) +<TELL " " N .I>> +<TELL "Counting from ,C-TEN to ,C-ONE..."> +;"10" +;"Even defining the loop bounds as CONSTANTs won't +``` + +- 136 - + +``` +tell ZILF that the loop needs to run backwards." +<DO (I ,C-TEN ,C-ONE) +(END <CRLF>) +<TELL " " N .I>> +<TELL "Counting from %,C-TEN to %,C-ONE..."> +;"10 9 8 7 5 4 3 2 1" +;"The % forces ,C-TEN to be evaluated at readtime, +so the loop bounds are specified as FIXes, allowing +ZILF to determine that the loop runs backwards." +<DO (I %,C-TEN %,C-ONE) +(END <CRLF>) +<TELL " " N .I>> +<CRLF>> +<OBJECT DESK +(DESC "desk")> +<OBJECT MONITOR +(DESC "monitor") +(LOC DESK)> +<OBJECT KEYBOARD +(DESC "keyboard") +(LOC DESK)> +<OBJECT MOUSE +(DESC "mouse") +(LOC DESK)> +<ROUTINE TEST-C-STYLE () +<TELL "== C style ==" CR> +<TELL "Counting from 10 down to 1..."> +;"10 9 8 7 6 5 4 3 2 1" +<DO (I 10 <L? .I 1> <- .I 1>) +(END <CRLF>) +<TELL " " N .I>> +<TELL "Counting from 10 up (!) to 1..."> +;"" +;"Nothing is printed, because the exit condition +is initially true. A DO loop whose condition is +a complex FORM can exit before the first iteration." +<DO (I 10 <G? .I 1> <+ .I 1>) +(END <CRLF>) +<TELL " " N .I>> +``` + +- 137 - + +``` +<TELL "On the desk:"> +;"monitor mouse keyboard" +<DO (I <FIRST? ,DESK> <NOT .I> <NEXT? .I>) +(END <CRLF>) +<TELL " " D .I>> +<CRLF>> +``` + +``` +<ROUTINE TEST-MIXED-STYLE () +<TELL "== Mixed ==" CR> +<TELL "Powers of 2 up to 1000:"> +;"1 2 4 8 16 32 64 128 256 512" +<DO (I 1 1000 <* .I 2>) +(END <CRLF>) +<TELL " " N .I>> +<CRLF>> +``` + +Highlights: + +- Loops can include subsequent code in an (END ...) clause for brevity, e.g. to print a newline after a list. + +A Pascal-style DO can *sometimes* determine when it needs to run backwards, even if no step size is provided. + +Pascal and C style can be mixed in the same loop, e.g. <DO (I 1 1000 <* .I 2>) ...> to count powers of 2 up to 1000. + +## **ERASE** + +``` +<ERASE value> +``` + +``` +Zapf syntaxInform syntax +ERASEerase_line +Versions: 4- +``` + +Versions 4 and 5: if the `value` is 1, erase from the current cursor position to the end of its line in the current window. If the `value` is anything other than 1, do nothing. + +Version 6: if the `value` is 1, erase from the current cursor position to the end of the its line in the current window. If not, erase the given number of pixels minus one across from the cursor (clipped to stay inside the right margin). The cursor does not move. + +Example: + +``` +<ERASE 1>-->Clears from cursor to end of line +``` + +## **F?** + +``` +<F? expression> +``` + +- 138 - + +Predicate. Test if `expression` evaluates to false. Example: + +``` +<F? <=? 1 1>>-->False +<F? <=? 1 2>>-->True +``` + +## **FCLEAR** + +``` +<FCLEAR object flag> +``` + +``` +Zapf syntaxInform syntax +FCLEARclear_attr +All versions +``` + +Removes `flag` from `object` . Example: + +``` +<FCLEAR ,TRAP-DOOR ,OPENBIT>-->Marks the trap-dooras +closed +``` + +## **FIRST?** + +``` +<FIRST? object> +``` + +``` +Zapf syntaxInform syntax +FIRST?get_child +All versions +``` + +Returns the first object inside (contained) in the `object` . Returns 0 (false) if no object exists. Example: + +``` +<SET RM <FIRST? ,ROOMS>>-->Sets RM to first objectin +ROOMS. Also evaluates to +true (all values not 0 is true) +``` + +## **FONT** + +``` +<FONT number>;"Version 5" +<FONT number [window-number]>;"Versions 6-" +Zapf syntaxInform syntax +FONTset_font +Versions: 5- +``` + +Sets current font to `number` . Returns old fonts `number` . If the font `number` is not available 0 (false) is returned. + +- 139 - + +|1|Normal font| +|---|---| +|3|Character graphics font<br>(see§16 in_The Z-Machine Standards Document_)| +|4|Monospace(fixed-pitch)font| + + + +Example: + +``` +<FONT 4>-->Sets fixed-pitch font. In version 3-4this is +done by setting bit 1 of Flags 2 in header +<PUT 0 8 <BOR <GET 0 8> 2>> +``` + +## **FSET** + +``` +<FSET object flag> +``` + +``` +Zapf syntaxInform syntax +FSETset_attr +All versions +``` + +Add `flag` to `object` . + +Example: + +``` +<FSET ,TRAP-DOOR ,OPENBIT>-->Marks the trap-dooras +open +``` + +## **FSET?** + +``` +<FSET? object flag> +``` + +``` +Zapf syntaxInform syntax +FSET?test_attr +All versions +``` + +Predicate. Tests if the `flag` is set on the `object` . Example: + +``` +<FSET? ,TRAP-DOOR ,OPENBIT>-->True if OPENBIT isset +``` + +## **FSTACK** + +``` +<FSTACK number [stack]> +``` + +``` +Zapf syntaxInform syntax +FSTACKpop / pop_stack +Versions: 6- +``` + +Removes `number` of items from system stack or given `stack` (table). + +- 140 - + +Example: + +``` +<PUSH 123> <PUSH 0> <PUSH 0> <PUSH 0> <FSTACK 3><POP> +---> 123 +``` + +## **G?, GRTR?** + +``` +<G? value1 value2> +<GRTR? Value1 value2>;Alternative syntax" +Zapf syntaxInform syntax +GRTR?Jg +All versions +``` + +Predicate. Returns true if `value1` is greater than `value2` , otherwise false. Examples: + +``` +<G? 5 4>-->T +<G? 4 5>--><> +``` + +## **G=?** + +``` +<G=? value1 value2> +``` + +Predicate. Returns true if `value1` is greater or equal to `value2` , otherwise false. Examples: + +``` +<G=? 5 4>-->T +<G=? 5 5>-->T +``` + +## **GET** + +``` +<GET table offset> +``` + +``` +Zapf syntaxInform syntax +GETloadw +All versions +``` + +Returns WORD-record (2 bytes) stored at offset. + +Note: `table` is an address in memory so the WORD that is returned is at table+offset*2. It is legal to use, for example, 0 as an address to retrieve information from the header. + +Also see `BACK` , `GETB` , `PUT` , `PUTB` and `REST` . + +Example: + +``` +<GET <TABLE 0 1 2 3> 2>-->2 +``` + +## **GETB** + +``` +<GETB table offset> +``` + +- 141 - + +``` +Zapf syntaxInform syntax +GETBloadb +``` + +``` +All versions +``` + +Returns BYTE-record (1 byte) stored at offset. + +Note: table is an address in memory so the BYTE that is returned is at table+offset. It is legal to use, for example, 0 as an address to retrieve information from the header. + +Also see `BACK` , `GET` , `PUT` , `PUTB` and `REST` . + +Example: + +``` +<GETB <TABLE (BYTE) !\A !\B !\C !\D> 2>-->!\C +``` + +## **GETP** + +``` +<GETP object property> +``` + +``` +Zapf syntaxInform syntax +GETPget_prop +All versions +``` + +Get `property` from the `object` . Returns default value if `property` is not declared in the `object` . + +Example: + +``` +<OBJECT MYOBJ (MYPROP 123)> +<GETP ,MYOBJ ,P?MYPROP>-->123 +``` + +## **GETPT** + +``` +<GETPT object property> +``` + +``` +Zapf syntaxInform syntax +GETPTget_prop_addr +All versions +``` + +Get `property` address from `object` . Returns 0 (false) if `property` is not declared in the `object` . + +Example: + +``` +<OBJECT MYOBJ (MYPROP 123)> +``` + +``` +<GET <GETPT ,MYOBJ ,P?MYPROP> 0>-->123 +<GETPT ,MYOBJ ,P?MYPROP2>-->0 +``` + +- 142 - + +## **GVAL** + +``` +<GVAL name> +,name;Alternative syntax" +``` + +Get value of global variable `name` . More often used in its short form " `,name` ". + +Example: + +``` +<GLOBAL X 5> +<GVAL X>-->5 +,X-->5 +``` + +## **HLIGHT** + +``` +<HLIGHT style> +``` + +``` +Zapf syntax +HLIGHT +``` + +``` +Inform syntax +set_text_style +``` + +``` +Versions: 4- +``` + +Set text to `style` . It is possible to combine styles. + +|0|Normal| +|---|---| +|1|Inverse| +|2|Bold| +|4|Italic| +|8|Monospace| + + + +Example: + +``` +<HLIGHT 2>-->Set font to bold +``` + +## **IFFLAG** + +``` +<IFFLAG (compilation-flag-condition expressions...)...> +``` + +`IFFLAG` inside a `ROUTINE` have the same behaviour as `IFFLAG` outside.See `IFFLAG` (outside `ROUTINE` ) for more information. + +## **IGRTR?** + +``` +<IGRTR? name value> +``` + +``` +Zapf syntaxInform syntax +IGRTR?inc_chk +``` + +``` +All versions +``` + +- 143 - + +Predicate. Increase variable (signed) `name` with 1 and returns true if variable `name` is greater than `value` , otherwise returns false. + +Example: + +## **IN?** + +``` +<ROUTINE TEST-IGRTR? (X) +<PRINTN <IGRTR? X 100>> +<CRLF> +<PRINTN .X> +> +<TEST-IGRTR? 100>-->"1\n101" +<TEST-IGRTR? 99>-->"0\n100" +<IN? object1 object2> +Zapf syntaxInform syntax +IN?jin +All versions +``` + +Predicate. Returns true if `object1` is in `object2` ( `object1` has `object2` as parent),otherwise false. + +Example: + +## **INC** + +``` +<OBJECT ANIMAL> +<OBJECT CAT (LOC ANIMAL)> +<IN? ,CAT ,ANIMAL>-->T +<IN? ,ANIMAL ,CAT>--><> +<INC name> +Zapf syntaxInform syntax +INCinc +All versions +``` + +Increment `name` by 1. (This is signed, so -1 increments to 0) + +Example: + +``` +<GLOBAL X 5> +<INC ,X>-->X=6 +``` + +- 144 - + +## **INPUT** + +``` +<INPUT 1 [time] [routine]> +``` + +``` +Zapf syntaxInform syntax +INPUTread_char +``` + +``` +Versions: 4- +``` + +`INPUT` reads a single character from the keyboard. Calls routine every time*0.1 s. If routine returns true input is aborted. + +## Examples: + +``` +<INPUT 1>-->Wait for keypress +``` + +``` +<ROUTINE WAIT-TWO-SECONDS () +<INPUT 1 20 ABORT-WAIT> +> +``` + +``` +<ROUTINE ABORT-WAIT () <RETURN T>> +``` + +``` +<WAIT-TWO-SECONDS>--> Pause two seconds (if not +interrupted by a keypress +from the keyboard +``` + +## **INTBL?** + +``` +<INTBL? value table length [rec-spec]>;"Version 5,7-" +<INTBL? value table length>;"Version 4, 6" +``` + +``` +Zapf syntaxInform syntax +INTBL?scan_table +``` + +``` +Versions: 4- +``` + +`INTBL?` is a predicate that returns the address of `value` if `value` is in `table` of `length` , otherwise 0. + +In version 5, 7 and 8 the `rec-spec` describes the field where bit 7 is set for words and clear for bytes, rest defines the length of the field. + +## Examples: + +``` +<T <INTBL? 3 <TABLE 1 2 3 4> 4>>-->T +<T <INTBL? 6 <TABLE 1 2 3 4> 4>>-->#FALSE +;"Search byte-table with record length 3 (ver 5,7-)" +<T <INTBL? 8 <TABLE (BYTE) 2 0 1 4 0 1 8 0 1> 9 3>>--> T +<T <INTBL? 1 <TABLE (BYTE) 2 0 1 4 0 1 8 0 1> 9 3>>--> <> +;"Search word-table with record length 3 (ver 5,7-)" +<T <INTBL? 8 <TABLE 2 0 1 4 0 1 8 0 1> 9 131>>-->T +``` + +- 145 - + +``` +<T <INTBL? 1 <TABLE 2 0 1 4 0 1 8 0 1> 9 131>> +``` + +``` +--> <> +``` + +## **IRESTORE** + +``` +<IRESTORE> +``` + +``` +Zapf syntaxInform syntax +IRESTORErestore_undo +``` + +``` +Versions: 5- +``` + +Restores game state saved to memory by `ISAVE` (undo). + +## **ISAVE** + +``` +<ISAVE> +``` + +``` +Zapf syntaxInform syntax +ISAVEsave_undo +``` + +``` +Versions: 5- +``` + +Save game state to memory that later can be restored by `IRESTORE` (undo). Returns 0 if `ISAVE` fails, 1 if it is successful and -1 if the interpreter does not handle undo. + +## **ITABLE** + +``` +<ITABLE [specifier] count [(flags...)] defaults ...> +``` + +Defines a table of `count` elements filled with default values: either zeros or, if the `default` list is specified, the specified list of values repeated until the table is full. + +The optional `specifier` may be the atoms `NONE` , `BYTE` , or `WORD` . `BYTE` and `WORD` change the type of the table and also turn on the length marker (element 0 in the table contains the length of the table), This can also be done with the flags (see `TABLE` about flags). + +Examples: + +``` +<ITABLE 4 0> --> +``` + +|`<ITABLE 4`|`0>-->`||| +|---|---|---|---| +|`Element 0`<br>`WORD`|`Element 1`<br>`WORD`|`Element 2`<br>`WORD`|`Element 3`<br>`WORD`| +|`0`|`0`|`0`|`0`| + + + +``` +<ITABLE (BYTE LENGTH) 4 0>--> +``` + +|`Element 0`<br>`BYTE`|`Element 1`<br>`BYTE`|`Element 2`<br>`BYTE`|`Element 3`<br>`BYTE`|`Element 4`<br>`BYTE`| +|---|---|---|---|---| +|`4`|`0`|`0`|`0`|`0`| + + + +``` +<ITABLE BYTE 4 0> --> +``` + +- 146 - + +|`Element 0`<br>`BYTE`|`Element 1`<br>`BYTE`|`Element 2`<br>`BYTE`|`Element 3`<br>`BYTE`|`Element 4`<br>`BYTE`| +|---|---|---|---|---| +|`4`|`0`|`0`|`0`|`0`| + + + +## **L?, LESS?** + +``` +<L? value1 value2> +<LESS? Value1 value2>;Alternative syntax" +``` + +``` +Zapf syntaxInform syntax +LESS?Jl +``` + +``` +All versions +``` + +Predicate. Returns true if `value1` is less than `value2` , otherwise false. Examples: + +``` +<L? 5 4>--><> +<L? 4 5>-->T +``` + +## **L=?** + +``` +<L=? value1 value2> +``` + +Predicate. Returns true if `value1` is less or equal to `value2` , otherwise false. Examples: + +``` +<L=? 5 4>--><> +<L=? 5 5>-->T +``` + +## **LEX** + +``` +<LEX text parse [dictionary] [flag]> +``` + +``` +Zapf syntaxInform syntax +LEXtokenise +``` + +``` +Versions: 4- +``` + +Parse the `text` into `parse` . See `READ` for more info about parsing. The game dictionary is used if not a `dictionary` table ( `LTABLE` ) is supplied. If the length of the `dictionary` is negative, the `dictionary` can be unsorted. If the `flag` is set (true), unrecognized words are not written to `parse` but their slot is left unmodified. This makes it possible to run `LEX` against different dictionaries serially. Also see `READ` . + +Example: + +``` +<GLOBAL TEXTBUF <TABLE (BYTE) !\c !\a !\t>> +<GLOBAL PARSEBUF <ITABLE 1 (LEXV) 0 0>> +<OBJECT CAT (SYNONYM CAT)> +``` + +- 147 - + +``` +<LEX ,TEXTBUF ,PARSEBUF> +<PRINTB <GET ,PARSEBUF 1>>-->"cat" +``` + +## **LOC** + +``` +<LOC object> +``` + +``` +Zapf syntaxInform syntax +LOCget_parent +All versions +``` + +Returns parent to `object` . + +Examples: + +``` +<OBJECT ANIMAL> +<OBJECT CAT (LOC ANIMAL)> +<=? <LOC ,CAT> ,ANIMAL>-->T +<LOC ,ANIMAL>-->0 +``` + +## **LOWCORE-TABLE** + +``` +<LOWCORE-TABLE field-spec length routine> +``` + +`LOWCORE-TABLE` reads the `length` number of bytes from `field-spec` and calls `routine` between each byte. See appendix B for list of valid values for `field-spec` . + +Example: + +``` +<LOWCORE-TABLE SERIAL 6 PRINTC> +``` + +``` +-->Reads 6 bytesfrom +SERIAL and print each +byte as character +``` + +## **LOWCORE** + +``` +<LOWCORE field-spec [new-value]> +``` + +`LOWCORE` reads and in some cases writes to the header information fields. See appendix B for list of valid values for `field-spec` . + +Examples: + +``` +<LOWCORE FLAGS <BOR <LOWCORE FLAGS> 2>>--> +Monospacebit (bit 1) in flags 2 is set +<PUT 0 8 <BOR <GET 0 8> 2>>-->Do the same as above +<PRINTN <BAND <LOWCORE RELEASEID> *3777*>> +-->Print the 11 lower bytes in releaseid +``` + +## **LSH, SHIFT** + +``` +<LSH number places> +<SHIFT number places>;Alternative syntax" +``` + +- 148 - + +``` +Zapf syntaxInform syntax +SHIFTlog_shift +``` + +``` +Versions: 5- +``` + +Bitwise shift. Shift `number` left when `places` is positive and right if it is negative. When right shifting the sign is not preserved (0 is always shifted in). + +``` +1000 0000 0000 1010-->0100 0000 0000 0101 +``` + +Also see `ASH` . + +Examples: + +``` +<LSH 4 1>-->8 +<LSH 4 -2>-->1 +``` + +## **LTABLE** + +``` +<LTABLE [(flags ...)] values ...> +``` + +Defines a table containing the specified `values` and with the `LENGTH` flag (see `TABLE` about `LENGTH` and other flags). + +## **LVAL** + +``` +<LVAL name> +.name;Alternative syntax" +``` + +Get value of local variable `name` . More often used in its short form " `.name` ". + +Example: + +``` +<SET X 5> +<LVAL X>-->5 +.X-->5 +``` + +## **MAP-CONTENTS** + +``` +<MAP-CONTENTS (name [next] object) +[(END expressions ...)] expressions ...> +``` + +Loop over all objects that have an `object` as parent (all children to `object` ). For ech iteration `name` is assigned the current child-object and `next` the child-object that will be `name` in the next iteration (0 if current `name` is the last child). + +For each iteration the `expressions` are evaluated and, if supplied, the `(END expressions ...)` is evaluated last after all iterations. + +Example: + +``` +<OBJECT SURVIVAL-KIT +(DESC "adventure survival kit") (WEIGHT 10)> +<OBJECT SWORD +(IN SURVIVAL-KIT) (DESC "sword") (WEIGHT 10)> +``` + +- 149 - + +``` +<OBJECT LAMP +(IN SURVIVAL-KIT) (DESC "brass lamp") (WEIGHT 5)> +<OBJECT SPOON +(IN SURVIVAL-KIT) (DESC "chrome spoon") (WEIGHT 2)> +<ROUTINE TEST-MAP-CONTENTS () +<TELL "Your " D ,SURVIVAL-KIT " contains:" CR> +<MAP-CONTENTS (F ,SURVIVAL-KIT) +<TELL " a " D .F CR> +> +<TELL "Your " D ,SURVIVAL-KIT " contains:" CR> +<MAP-CONTENTS (F N ,SURVIVAL-KIT) +<TELL " a " D .F > +<COND (.N <TELL " (next item is the " D .N")">)> +<TELL CR> +> +<BIND ((W 0)) +<SET W <GETP ,SURVIVAL-KIT ,P?WEIGHT>> +<MAP-CONTENTS (F ,SURVIVAL-KIT) +(END <TELL "Total weight is = " N .W CR>) +<SET W <+ .W <GETP .F ,P?WEIGHT>>> +> +> +> +<TEST-MAP-CONTENTS>--> +Your adventure survival kit contains: +a sword +a chrome spoon +a brass lamp +Your adventure survival kit contains: +a sword (next item is the chrome spoon) +a chrome spoon (next item is the brass lamp) +a brass lamp +Total weight is = 27 +``` + +## **MAP-DIRECTIONS** + +``` +<MAP-DIRECTIONS (name pt room) +[(END expressions ...)] expressions ...> +``` + +Loop over all directions in a room. For each iteration `name` is assigned the current direction and `pt` is the room the direction leads to. + +For each iteration the `expressions` are evaluated and, if supplied, the `(END expressions ...)` is evaluated last after all iterations. + +Example: + +- 150 - + +``` +<DIRECTIONS NORTH SOUTH EAST WEST> +<OBJECT CENTER (DESC "center room") +(NORTH TO N-ROOM) +(WEST TO W-ROOM)> +<OBJECT N-ROOM (DESC "north room")> +<OBJECT W-ROOM (DESC "west room")> +<ROUTINE TEST-MAP-DIRECTIONS () +<TELL "You're in the " D ,CENTER> +<TELL CR "Obvious exits:" CR> +<MAP-DIRECTIONS (D P ,CENTER) +(END <TELL "Room description done." CR>) +<COND (<EQUAL? .D ,P?NORTH> <TELL " North">) +(<EQUAL? .D ,P?SOUTH> <TELL "South">) +(<EQUAL? .D ,P?EAST> <TELL " East">) +(<EQUAL? .D ,P?WEST> <TELL " West">) +> +<VERSION? +(ZIP <TELL " to the " D <GETB .P ,REXIT>CR>) +(ELSE <TELL " to the " D <GET .P ,REXIT>CR>) +> +> +> +``` + +## **MARGIN** + +``` +<MARGIN left right [window-number]> +``` + +``` +Zapf syntaxInform syntax +MARGINset_margins +Versions: 6- +``` + +Set `left` and `right` margin (in pixels) in the given `window-number` . If no `window-number` is specified `MARGIN` sets margins in `window-number` 0. + +Example: + +``` +<MARGIN 1 1>--> set 1 pixel margin in window 0 +``` + +## **MENU** + +``` +<MENU number table> +``` + +``` +Zapf syntaxInform syntax +MENUmake_menu +Versions: 6- +``` + +Controls menu 3- (not menu 0-2, they are system menus). The `table` is a `LTABLE` of `LTABLE` . Item 1 being the menu name. Item 2- are the entries. + +- 151 - + +Example (from Journey): + +``` +<GLOBAL MAC-SPECIAL-MENU +<LTABLE <TABLE (STRING LENGTH) "Journey"> +<TABLE (STRING LENGTH) "Essences"> +<TABLE (STRING LENGTH) "No Defaults">>> +... +<MENU 3 ,MAC-SPECIAL-MENU> +``` + +## **MOD** + +``` +<MOD number1 number2> +``` + +``` +Zapf syntaxInform syntax +MODmod +``` + +``` +All versions +``` + +Returns remainder of 16-bit signed division. `number2` is not allowed to be 0 ("Division by zero"). Examples: + +``` +<MOD 15 4>-->3 +<MOD -15 4>-->-3 +<MOD -15 -4>-->-3 +<MOD 15 -4>-->3 +``` + +## **MOUSE-INFO** + +``` +<MOUSE-INFO table> +``` + +``` +Zapf syntaxInform syntax +MOUSE-INFOread_mouse +``` + +``` +Versions: 6- +``` + +Reads mouse information into `table` . The table is 4 WORDS (2 bytes) long. + +|0|Y coordinate| +|---|---| +|1|X coordinate| +|2|Button bits(host dependent)| +|3|Menu(number*256+entry)| + + + +Example (from Journey): + +``` +<GLOBAL MOUSE-INFO-TBL <TABLE 0 0 0 0>> +``` + +``` +... +``` + +- 152 - + +``` +<MOUSE-INFO ,MOUSE-INFO-TBL> +``` + +## **MOUSE-LIMIT** + +``` +<MOUSE-LIMIT window-number> +``` + +``` +Zapf syntaxInform syntax +MOUSE-LIMITmouse_window +``` + +``` +Versions: 6- +``` + +Restricts mouse movement to `window-number` . If `window-number` is -1 all restrictions are removed. 1 is default `window-number` . + +Example: + +``` +<MOUSE-LIMIT 1>-->Mouse constrained to window1 +``` + +## **MOVE** + +``` +<MOVE object1 object2> +``` + +``` +Zapf syntaxInform syntax +MOVEinsert_obj +All versions +``` + +Move `object1` to be the first child of `object2` . Children of `object1` move with it. Example: + +``` +<OBJECT ANIMAL> +<OBJECT CAT> +<MOVE ,CAT ,ANIMAL> +<IN? ,CAT ,ANIMAL>-->T +``` + +## **N=?, N==?** + +``` +<N=? value1 value2...valueN> +<N==? value1 value2...valueN>;Alternative syntax" +``` + +Predicate. True if `value1` is not equal to any of the values `value2` to `valueN` . + +Examples: + +``` +<N=? 1 1>-->FALSE +<N=? 1 2>-->TRUE +<N=? 1 2 1>-->FALSE +``` + +## **NEXT?** + +``` +<NEXT? object> +``` + +- 153 - + +``` +Zapf syntaxInform syntax +NEXT?get_sibling +``` + +``` +All versions +``` + +Returns object after `object` in object-list (sibling). Returns 0 (false) if no object exists. Example: + +``` +<OBJECT ANIMAL> +<OBJECT CAT> +<OBJECT DOG> +<MOVE ,CAT ,ANIMAL> +<MOVE ,DOG ,ANIMAL> +<=? <NEXT? ,DOG> ,CAT>-->T +<NEXTP object property> +Zapf syntaxInform syntax +NEXTPget_next_prop +All versions +``` + +## **NEXTP** + +Returns the property that comes after `property` on the `object` . Returns 0 if there are no more properties after `property` . If `property` is 0 then `NEXTP` returns first property on `object` . Example: + +``` +<OBJECT MYOBJ (FOO 123) (BAR 456)> +``` + +``` +<=? <NEXTP ,MYOBJ 0> P?FOO>-->T +<=? <NEXTP ,MYOBJ P?FOO> P?BAR>-->T +<NEXTP ,MYOBJ P?BAR>-->0 (false) +``` + +## **NOT** + +``` +<NOT expression> +``` + +Returns the boolean `NOT` of expression. + +Examples: + +## **OR** + +``` +<NOT <=? 1 2>>-->True (1) +<OR expressions...> +``` + +Boolean `OR` . Requires that one of the `expressions` evaluates to true to return true. Exits on the first `expression` that evaluates to true (rest of `expressions` are not evaluated). + +- 154 - + +Because 0 is considered false and all other values are considered true inside a routine `OR` returns 0 if all `expressions` are false or the value of the first true `expression.` + +Example: + +``` +<OR <=? 1 2> <=? 1 1>>-->True +<OR <=? 1 1> <SET X 2>>-->X never set to 2 because +first predicate evaluates +to true +<SET X <OR 0 1 2 3>>-->X is set to 1 +<SET X <OR 0 <> 0>>-->X is set to 0 +``` + +## **ORIGINAL?** + +``` +<ORIGINAL?> +``` + +``` +Zapf syntaxInform syntax +ORIGINAL?piracy +Versions: 5- +``` + +Predicate. Tests if the game disc is an original. Almost all modern interpreters always return true. + +## **PICINF** + +``` +<PICINF picture-number table> +``` + +``` +Zapf syntaxInform syntax +PICINFpicture_data +Versions: 6- +``` + +Writes picture data from `picture-number` into `table` . Word 0 of `table` holds picture width and word 1 holds picture height. Then follows the picture data. + +If `picture-number` is 0, the number of available pictures is written into word 0 of `table` and release number of picture file is written into word 1. + +Example: + +``` +<GLOBAL MYPIC <ITABLE 2048 0>> +``` + +``` +<PICINFO 1 ,MYPIC>-->Writes picture data into MYPIC +``` + +## **PICSET** + +``` +<PICSET table> +``` + +``` +Zapf syntaxInform syntax +PICSETpicture_table +Versions: 6- +``` + +Give the interpreter a `table` of picture numbers that the interpreter can then unpack from disc and + +- 155 - + +cache in memory. + +## **PLTABLE** + +``` +<PLTABLE [(flags ...)] values ...> +``` + +Defines a table containing the specified `values` and with the `PURE` and `LENGTH` flag (see `TABLE` about `LENGTH` , `PURE` and other flags). + +## **POP** + +``` +<POP [stack]> +``` + +``` +Zapf syntaxInform syntax +POPpull +Versions: 6- +``` + +Pops value of stack. If no stack is given, a value is popped from the game stack. + +Example: + +``` +<PUSH 123> +<POP>-->123 +<GLOBAL MY-STACK <TABLE 3 0 0 123>> +<POP ,MY-STACK>-->123 +``` + +## **PRINT** + +``` +<PRINT packed-string> +``` + +``` +Zapf syntaxInform syntax +PRINTprint_paddr +All versions +``` + +Print `packed-string` from high memory (packed address). + +Example: + +``` +<GLOBAL MSG "Hello, sailor!"> +<PRINT ,MSG>-->"Hello, sailor!" +``` + +## **PRINTB** + +``` +<PRINTB unpacked-string> +``` + +``` +Zapf syntaxInform syntax +PRINTBprint_addr +All versions +``` + +- 156 - + +Print un `packed-string` from dynamic or static memory (unpacked address). Example: + +``` +<OBJECT MYOBJECT (SYNONYM HELLO)> +``` + +``` +<PRINTB <GETP ,MYOBJECT ,P?SYNONYM>>-->"hello" +``` + +## **PRINTC** + +``` +<PRINTC character> +``` + +``` +Zapf syntaxInform syntax +PRINTCprint_char +All versions +``` + +Print `character` . + +Example: + +``` +<PRINTC 65>-->A +``` + +## **PRINTD** + +``` +<PRINTD object> +``` + +``` +Zapf syntaxInform syntax +PRINTDprint_obj +All versions +``` + +Print description of `object` . + +Example: + +``` +<GLOBAL MYOBJECT (DESC "sword"> +``` + +``` +<PRINTD ,MYOBJECT>-->"sword" +``` + +## **PRINTF** + +``` +<PRINTF table> +``` + +``` +Zapf syntaxInform syntax +PRINTFprint_form +Versions: 6- +``` + +Print a formatted `table` . Each line starts with a WORD that is the number of characters that follows. Last byte in each line is 0. + +- 157 - + +## **PRINTI** + +``` +<PRINTI string> +``` + +``` +Zapf syntaxInform syntax +PRINTIprint +All versions +``` + +Print `string` . + +Example: + +``` +<PRINTI "Hello, sailor!">-->"Hello, sailor!" +``` + +## **PRINTN** + +``` +<PRINTN number> +``` + +``` +Zapf syntaxInform syntax +PRINTNprint_num +``` + +``` +All versions +``` + +``` +Print number. +Example: +<PRINTN <+ 1 3>>-->4 +<PRINTN -42>-->-42 +``` + +## **PRINTR** + +``` +<PRINTR string> +``` + +``` +Zapf syntaxInform syntax +PRINTRprint_ret +All versions +``` + +Print `string` and then `CRLF` . + +Example: + +``` +<PRINTR "Hello, Sailor!">-->"Hello, sailor!\n" +``` + +## **PRINTT** + +``` +<PRINTT table width [height] [skip]> +``` + +``` +Zapf syntaxInform syntax +PRINTTprint_table +Versions: 5- +``` + +- 158 - + +Print `table` (string) in rectangle defined by `width` and `height` . Default `height` is 1. If `skip` is given then that number of characters is skipped between lines. + +Examples: + +``` +<GLOBAL MYTEXT <TABLE (STRING) "hansprestige">> +``` + +``` +<PRINTT ,MYTEXT 6>-->"hanspr\n" +<PRINTT ,MYTEXT 4 3>-->"hans\npres\ntige\n" +<PRINTT ,MYTEXT 3 3 1>-->"han\npre\ntig\n" +``` + +## **PRINTU** + +``` +<PRINTU number> +``` + +``` +Zapf syntaxInform syntax +PRINTUprint_unicode +Versions: 5- +``` + +Print unicode-character `number` . + +Examples: `<PRINTU 65> --> A <PRINTU 196> --> Ä` + +## **PROG** + +``` +<PROG [activation] (bindings...) expressions...> +``` + +`PROG` defines a program block with its own set of `bindings` . `PROG` is similar to `BIND` but `PROG` automatically creates a default activation at the start of the block which you optionally can name. This means that `AGAIN` moves program execution to this activation. `RETURN` exits this `PROG` -block. + +Note that there is a special variable, `DO-FUNNY-RETURN?` , that controls how `RETURN` with value should be handled. If `DO-FUNNY-RETURN?` is true then `RETURN` value returns from `ROUTINE` , otherwise it returns from `PROG` . `DO-FUNNY-RETURN?` is default false in version 3-4 and default true in versions 5-. + +Also see `AGAIN` , `BIND` , `DO` , `REPEAT` and `RETURN` for more details how to control program flow. `AGAIN` and `RETURN` have examples on how activation and `DO-FUNNY-RETURN?` works. Examples: + +``` +;"Block have own set of atoms" +<ROUTINE TEST-PROG-1 ("AUX" X) +<SET X 2> +<TELL "START: "> +<PROG (X) +<SET X 1> +<TELL N .X " "> ;"Inner X" +> +``` + +- 159 - + +``` +<TELL N .X> ;"Outer X" +<TELL " END" CR CR> +> +-->"START: 1 2 END" +``` + +``` +;"AGAIN, Bare RETURN without ACTIVATION" +<ROUTINE TEST-PROG-2 () +<TELL "START: "> +<PROG (X) ;"X is not reinitialized between iterations. +Default ACTIVATION created." +<SET X <+ .X 1>> +<TELL N .X " "> +<COND (<=? .X 3> <RETURN>)>;"Bare RETURNwithout +ACTIVATION will exit +BLOCK" +<AGAIN> ;"AGAIN without ACTIVATION will redoBLOCK" +> +<TELL "RETURN EXIT BLOCK" CR CR> +> +-->"START: 1 2 3 RETURN EXIT BLOCK" +;"AGAIN, RETURN with value but without ACTIVATION" +<ROUTINE TEST-PROG-3 () +<TELL "START: "> +<PROG ((X 0));"X is not reinitialized between +iterations. Default ACTIVATION created." +<SET X <+ .X 1>> +<TELL N .X " "> +<COND (<=? .X 3> +<COND (,FUNNY-RETURN? +<TELL "RETURN EXIT ROUTINE" CR CR>)> +<RETURN T>)>;"RETURN with value but without +ACTIVATION will exit ROUTINE +(FUNNY-RETURN = TRUE)" +<AGAIN> ;"AGAIN without ACTIVATION will redoBLOCK" +> +<TELL "RETURN EXIT BLOCK" CR CR> +> +-->"START: 1 2 3 RETURN EXIT ROUTINE" +``` + +## **PTABLE** + +``` +<PTABLE [(flags ...)] values ...> +``` + +Defines a table containing the specified `values` and with the `PURE` flag (see `TABLE` about `PURE` and other flags). + +- 160 - + +## **PTSIZE** + +``` +<PTSIZE property-address> +``` + +``` +Zapf syntaxInform syntax +PTSIZEget_prop_len +All versions +``` + +Get size in bytes of property at `property-address` . Example: + +``` +<OBJECT MYOBJECT (FOO 1 2 3)> +<PTSIZE <GETPT ,MYOBJECT ,P?FOO>>-->6 +``` + +## **PUSH** + +``` +<PUSH value> +``` + +``` +Zapf syntaxInform syntax +PUSHpush +All versions +``` + +Push `value` on game stack. + +Example: + +``` +<PUSH 123> +``` + +## **PUT** + +``` +<PUT table offset value> +``` + +``` +Zapf syntaxInform syntax +PUTstorew +All versions +``` + +Put a 16-bit WORD `value` in the `table` at word position `offset` . Actual address is table-address+offset*2. + +Note that `table` can be a byte-address in dynamic memory. + +Also see `BACK` , `GET` , `GETB` , `PUTB` and `REST` . + +Examples: + +``` +<PUT ,MYTABLE 1 123>-->Stores 123 at position1 +in MYTABLE +<PUT 0 8 <BOR <GET 0 8> 2>>-->Sets bit 1 in Flags2 in +header (force monospace) +``` + +- 161 - + +## **PUTB** + +``` +<PUTB table offset value> +``` + +``` +Zapf syntaxInform syntax +PUTBstoreb +``` + +``` +All versions +``` + +Put a byte `value` in the `table` at byte position `offset` . Actual address is table-address+offset. Note that `table` can be a byte-address in dynamic memory. + +Also see `BACK` , `GET` , `GETB` , `PUT` and `REST` . + +Example: + +``` +<PUTB ,MYTABLE 1 !\A>-->Stores character A at +position 1 in MYTABLE +``` + +## **PUTP** + +``` +<PUTP object property value> +``` + +``` +Zapf syntaxInform syntax +PUTPput_prop +All versions +``` + +Put `value` into `property` on the `object` . + +Example: + +``` +<OBJECT MYOBJ (MYPROP 123)> +<PUTP ,MYOBJ ,P?MYPROP 456>-->Stores 456 in property +MYPROP on MYOBJ +``` + +## **QUIT** + +``` +<QUIT> +``` + +``` +Zapf syntaxInform syntax +QUITquit +All versions +``` + +Halts game execution. No questions asked. + +## **RANDOM** + +``` +<RANDOM range> +``` + +``` +Zapf syntaxInform syntax +``` + +- 162 - + +``` +RANDOMrandom +``` + +``` +All versions +``` + +Returns a random number between 1 and `range` . If `range` is negative the randomizer is reseeded with - `range` (absolute value of `range` ). + +Example: + +``` +<- <RANDOM 101> 1>-->Generates random number +between 0-100 +``` + +## **READ** + +``` +<READ text parse>;"Versions 1-3" +<READ text parse [time] [routine]>;"Version 4" +<READ text [parse] [time] [routine]>;"Versions 5-" +Zapf syntaxInform syntax +READaread / sread +All versions +``` + +Read text from the keyboard and parse it. Result is stored in two byte-tables. Byte 0 in `text` must contain the max-size of the buffer and if `parse` is supplied, byte 0 of it must contain a max number of words that will be parsed. + +In version 5-, byte 1 should be 0 before `READ` begins, otherwise `READ` appends characters starting from value in byte 1. + +After `READ` , `text` contains: + +Version 1-4, + +Byte 0 Max number of chars read into the buffer 1- The typed chars all converted to lowercase Version 5-, Byte 0 Max number of chars read into the buffer 1 Actual number of chars read into the buffer 2- The typed chars all converted to lowercase + +`parse` contains: + +Byte 0 Max number of words parsed 1 Actual number of words parsed 2-3 Address to first word in dictionary (0 if word is not in it) 4 Length of first word 5 Start position (in `text` ) of first word 6-9 Second word ... + +Example: + +``` +<GLOBAL READBUF <ITABLE BYTE 63>> +``` + +- 163 - + +``` +<GLOBAL PARSEBUF <ITABLE BYTE 28>> +<ROUTINE READ-TEST ("AUX" WORDS WLEN WSTART WEND) +<PUTB ,READBUF 0 60> +<PUTB ,PARSEBUF 0 6> +<READ ,READBUF ,PARSEBUF> +<SET WORDS <GETB ,PARSEBUF 1>> ;"# of parsed words" +<DO (I 1 .WORDS) +<SET WLEN <GETB .PARSEBUF <* .I 4>>> +<SET WSTART <GETB .PARSEBUF <+<* .I 4> 1>>> +<SET WEND <+ .WSTART <- .WLEN 1>>> +<TELL "word " N .I " is " N .WLEN " char long. "> +<TELL "The word is '"> +<DO (J .WSTART .WEND) +<PRINTC <GETB .READBUF .J>> ;"To lcase!" +> +<TELL "'." CR> +> +> +``` + +See _The Inform Designer’s Manual_ (ch. §2.5, p. 44-46) for more details about `READ` . + +## **REMOVE** + +``` +<REMOVE object> +``` + +``` +Zapf syntaxInform syntax +REMOVEremove_obj +All versions +``` + +Remove `object` from parent. See `MOVE` how to reattach it to another object. + +Example: + +``` +<OBJECT ANIMAL> +<OBJECT CAT (LOC ANIMAL)> +<REMOVE ,CAT>-->Detach CAT from ANIMAL +``` + +## **REPEAT** + +``` +<REPEAT [activation] (bindings...) expressions...> +``` + +`REPEAT` defines a program block with its own set of `bindings` . `REPEAT` is very similar to `PROG` the only difference is that at the end of the block is an automatic `AGAIN` . `REPEAT` automatically creates a default activation at the start of the block which you optionally can name. This means that `AGAIN` moves program execution to this activation. `RETURN` exits this `REPEAT` -block. + +Note that there is a special variable, `DO-FUNNY-RETURN?` , that controls how `RETURN` with value should be handled. If `DO-FUNNY-RETURN?` is true then `RETURN` value returns from `ROUTINE` , otherwise it returns from `REPEAT` . `DO-FUNNY-RETURN?` is default false in version 3-4 and + +- 164 - + +default true in versions 5-. + +Also see `AGAIN` , `BIND` , `DO` , `PROG` and `RETURN` for more details how to control program flow. `AGAIN` and `RETURN` have examples on how activation and `DO-FUNNY-RETURN?` works. + +Examples: + +``` +;"Bare RETURN without ACTIVATION" +<ROUTINE TEST-REPEAT-1 () +<TELL "START: "> +<REPEAT (X);"X is not reinitialized between iterations. +Default ACTIVATION created." +<SET X <+ .X 1>> +<TELL N .X " "> +<COND (<=? .X 3> <RETURN>)>;"Bare RETURNwithout +ACTIVATION will exit +BLOCK" +> +<TELL "RETURN EXIT BLOCK" CR CR> +> +-->"START: 1 2 3 RETURN EXIT BLOCK" +;"RETURN with value but without ACTIVATION" +<ROUTINE TEST-REPEAT-2 () +<TELL "START: "> +<REPEAT ((X 0)) ;"X is not reinitialized between +iterations. Default ACTIVATION created." +<SET X <+ .X 1>> +<TELL N .X " "> +<COND (<=? .X 3> +<COND (,FUNNY-RETURN? +<TELL "RETURN EXIT ROUTINE" CR CR>)> +<RETURN T>)>;"RETURN with value but without +ACTIVATION will exit ROUTINE +(FUNNY-RETURN = TRUE)" +> +<TELL "RETURN EXIT BLOCK" CR CR> +> +-->"START: 1 2 3 RETURN EXIT ROUTINE" +``` + +## **REST** + +``` +<REST table [bytes]> +``` + +Return `table` without its first `bytes` ( `bytes` is default 1). Note that this is not a copy of the `table` , it is pointing to the same `table` with another starting address. + +Also see `BACK` , `GET` , `GETB` , `PUT` and `PUTB` . + +Example: + +``` +<GLOBAL TBL1 <TABLE 1 2 3 4>>-->TBL1 = [1 2 3 4] +<GLOBAL TBL2 <REST ,TBL1 2>>-->TBL2 = [2 3 4] +``` + +- 165 - + +``` +<PUT ,TBL2 0 5> +``` + +``` +Move 2 because +WORD-table! +-->TBL1 = [1 5 3 4], +TBL2 = [5 3 4] +``` + +## **RESTART** + +``` +<RESTART> +``` + +``` +Zapf syntaxInform syntax +RESTARTrestart +``` + +``` +All versions +``` + +Restarts the game. No questions asked. The only things that survive a restart are bit 0 and bit 1 of Flags 2 in the header (setting for transcribing and monospace). + +## **RESTORE** + +``` +<RESTORE>;"Versions 1-4" +<RESTORE [table] [bytes] [filename]>;"Versions 5-" +``` + +``` +Zapf syntaxInform syntax +RESTORErestore +All versions +``` + +`RESTORE` a game to a previously saved state. All questions about filename and path are asked by the interpreter. + +If `RESTORE` fails, game execution continues with the next statement after `RESTORE` . + +If `RESTORE` is successful game execution continues from where the `SAVE` was issued ( `SAVE` returns 2 in this case). + +See _The Inform Designer’s Manual_ (ch. §42, p. 319) and _The Z-machine Standards Document_ for a description about how to `SAVE` and `RESTORE` auxiliary files. + +Example: + +``` +<ROUTINE SAVE-GAME ("AUX" RESULT) +``` + +``` +<SET RESULT <SAVE>> +<COND (<=? .RESULT 0> <TELL "Save failed." CR>)> +<COND (<=? .RESULT 1> <TELL "Save successful." CR>)> +<COND (<=? .RESULT 2> <TELL "Restore successful."CR>)> +> +``` + +``` +<ROUTINE RESTORE-GAME () +<RESTORE> +<TELL "Restore failed." CR> +> +``` + +- 166 - + +## **RETURN** + +``` +<RETURN [value] [activation]> +``` + +``` +Zapf syntaxInform syntax +RETURNret +``` + +``` +All versions +``` + +`RETURN` from current routine with `value` . Returns 1 (true) if no `value` is given. + +`RETURN` is also used in commands that control program flow to exit program blocks. Also see `AGAIN` , `BIND` , `DO` , `PROG` and `REPEAT` for more details how to control program flow. + +Examples: + +``` +<RETURN>--> Returns 1 +<RETURN 42>--> Returns 42 +``` + +## **RFALSE** + +``` +<RFALSE> +``` + +``` +Zapf syntaxInform syntax +RFALSErfalse +``` + +``` +All versions +``` + +`RFALSE` always exits routine and returns false (0). Note that this differs from `RETURN` that can both exit program blocks and routines. + +## **RFATAL** + +``` +<RFATAL> +``` + +`RFATAL` always exits routine and returns `FATAL-VALUE` (2). Note that this differs from `RETURN` that can both exit program blocks and routines. + +## **RSTACK** + +``` +<RSTACK> +``` + +``` +Zapf syntaxInform syntax +RSTACKret_popped +``` + +``` +All versions +``` + +Pops value from game stack and returns that value. + +Example: + +``` +<PUSH 42> +<RSTACK>-->Returns 42 +``` + +- 167 - + +## **RTRUE** + +``` +<RTRUE> +``` + +``` +Zapf syntaxInform syntax +RTRUErtrue +``` + +``` +All versions +``` + +`RTRUE` always exits routine and returns true (1). Note that this differs from `RETURN` that can both exit program blocks and routines. + +## **SAVE** + +``` +<SAVE>;"Versions 1-4" +<SAVE [table] [bytes] [filename]>;"Versions 5-" +Zapf syntaxInform syntax +SAVEsave +``` + +``` +All versions +``` + +`SAVE` a game state that later can be restored. All questions about filename and path are asked by the interpreter. + +`SAVE` returns 0 if `SAVE` fails and 1 if it is successful. + +`SAVE` also can return 2. That means this is a continuation from a successful `RESTORE` . + +See `RESTORE` on code example on `SAVE` and `RESTORE` . + +See _The Inform Designer’s Manual_ (ch. §42, p. 319) and _The Z-machine Standards Document_ for a description about how to `SAVE` and `RESTORE` auxiliary files. + +## **SCREEN** + +``` +<SCREEN window-number> +``` + +``` +Zapf syntaxInform syntax +SCREENset_window +Versions: 3- +``` + +Select `window-number` for text output. + +Note that in versions 3-5 only the lower screen ( `window-number` = 0) has text-buffering and word-wrap. + +Example: + +``` +<SPLIT 3> +<SCREEN 1> +<TELL "West of House">-->Split screen in 2 (upper +screen is 3 rows) and write +``` + +- 168 - + +``` +"West of House" in upper screen +``` + +## **SCROLL** + +``` +<SCROLL window-number pixels> +``` + +``` +Zapf syntaxInform syntax +SCROLLscroll_window +Versions: 6- +``` + +Scrolls `window-number` up ( `pixels` is positive) or down ( `pixels` is negative) the number of `pixels` supplied. The new lines are empty (background color). + +## **SET** + +``` +<SET name value> +``` + +``` +Zapf syntaxInform syntax +SETstore +All versions +``` + +Store `value` in local variable `name` . + +Example: + +``` +<SET MYVAR 42>-->Store 42 in local variable MYVAR +``` + +## **SETG** + +``` +<SETG name value> +``` + +``` +Zapf syntaxInform syntax +SETstore +All versions +``` + +Store `value` in global variable `name` . The `name` variable must be declared with `GLOBAL` outside the `ROUTINE` . + +Example: + +``` +<SETG MYVAR 42>-->Store 42 in global variable MYVAR +``` + +## **SOUND** + +``` +<SOUND number [effect] [volrep]>;"Versions 3-4" +<SOUND number [effect] [volrep] [routine]>;"Versions5-" +Zapf syntaxInform syntax +SOUNDsound_effect +``` + +- 169 - + +``` +Versions: 3- +``` + +Plays sound `number` (1 = high-pitch beep, 2 = low-pitch beep and 3- is user defined). + +Valid entries for `effect` are 1 = prepare, 2 = start, 3 = stop and 4 = finished with. + +The `volrep` is calculated as 256 * repetitions + volume. Repetitions can be 0-255 (255 = infinite) and volume 1-8, 255 (1 = quiet, 8 = loud, 255 = loudest possible. + +If `routine` is supplied it is called after sound is finished. + +See _The Inform Designer’s Manual_ (ch. §42, p. 315-316 and ch. §43) and _The Z-machine Standards Document_ for a description about how to include sound in games. + +## **SPLIT** + +``` +<SPLIT number> +``` + +``` +Zapf syntaxInform syntax +SPLITsplit_window +Versions: 3- +``` + +`SPLIT` screen in two parts with the upper part having `number` rows. If `number` is 0 the screen is unsplit.The upper screen is window-number 1 and the lower screen is window-number 0. + +See `SCREEN` for example on how to use `SPLIT` . + +## **T?** + +``` +<T? expression> +``` + +Predicate. Test if `expression` evaluates to true ( not 0). + +Example: + +``` +<T? <=? 1 1>>-->True +<T? <=? 1 2>>-->False +``` + +## **TABLE** + +``` +<TABLE [(flags ...)] values ...> +``` + +Defines a table containing the specified `values` . + +These `flags` control the format of the table: + +- `WORD` causes the elements to be 2-byte words. This is the default. + +- `BYTE` causes the elements to be single bytes. + +- `LEXV` causes the elements to be 4-byte records. If `default` values are given to `ITABLE` with this flag, they will be split into groups of three: the first compiled as a word, the next two compiled as bytes. The table is also prefixed with a byte indicating the number of records, followed by a zero byte + +- `STRING` causes the elements to be single bytes and also changes the initializer format. This flag may not be used with `ITABLE` . When this flag is given, any `values` given as strings + +- 170 - + +will be compiled as a series of individual ASCII characters, rather than as string addresses. + +These `flags` alter the table without changing its basic format: + +- `LENGTH` causes a length marker to be written at the beginning of the table, indicating the number of elements that follow. The length marker is a byte if `BYTE` or `STRING` are also given; otherwise the length marker is a `WORD` . This flag is ignored if `LEXV` is given + +- `PURE` causes the table to be compiled into static memory (ROM). + +The flag `LENGTH` is implied in `LTABLE` and `PLTABLE` . The flag `PURE` is implied in `PTABLE` and `PLTABLE` . + +Examples: + +``` +<TABLE 1 2 3 4> --> +``` + +|`Element 0`<br>`WORD`|`Element 1`<br>`WORD`|`Element 2`<br>`WORD`|`Element 3`<br>`WORD`| +|---|---|---|---| +|`1`|`2`|`3`|`4`| + + + +|`<TABLE (BYTE LENGTH) 1 2 3 4>-->`|`<TABLE (BYTE LENGTH) 1 2 3 4>-->`|`<TABLE (BYTE LENGTH) 1 2 3 4>-->`|`<TABLE (BYTE LENGTH) 1 2 3 4>-->`|`<TABLE (BYTE LENGTH) 1 2 3 4>-->`| +|---|---|---|---|---| +|`Element 0`<br>`BYTE`|`Element 1`<br>`BYTE`|`Element 2`<br>`BYTE`|`Element 3`<br>`BYTE`|`Element 4`<br>`BYTE`| +|`4`|`1`|`2`|`3`|`4`| + + + +## **TELL** + +``` +<TELL token-commands ...> +``` + +Print formatted text to screen. There is a set built-in tokens that can be replaced with `TELL-TOKENS` or expanded with `ADD-TELL-TOKENS` . + +The built-in tokens are: + +|**Pattern**|**Form**|**Description**| +|---|---|---| +|`(CR CRLF) `|`<CRLF>`|`Print CR`| +|`D *`|`<PRINTD .X> `|`Print object-description`| +|`N *`|`<PRINTN .X> `|`Print number`| +|`C *`|`<PRINTC .X> `|`Print character`| +|`B *`|`<PRINTB .X> `|`Print unpacked-string`| + + + +Example: + +``` +<TELL "You have " N ,SCORE " points." CR> +-->"You have 42 points.\n" +``` + +## **THROW** + +``` +<THROW value stack-frame> +``` + +## **`Zapf syntax`** + +## **`Inform syntax`** + +- 171 - + +``` +throw +``` + +``` +THROW +``` + +``` +Versions: 5- +``` + +Used in conjunction with `CATCH` . `THROW` sets the stack to `stack-frame` and returns `value` (the result is that execution returns from the routine where the `stack-frame` was "caught" with `value` as the routines return value. Also see `CATCH` . + +Example: + +## **USL** + +``` +<ROUTINE TEST-CATCH ("AUX" X) +<SET X <CATCH>> +<THROWER .X> +123 +> +<ROUTINE THROWER (F) +<THROW 456 .F> +> +<TEST-CATCH>-->456 +<USL> +Zapf syntaxInform syntax +USLshow_status +Versions: 3 +``` + +Update status line. In other versions than 3 this command is ignored. + +## **VALUE** + +``` +<VALUE name/number> +``` + +``` +Zapf syntaxInform syntax +VALUEload +All versions +``` + +Load `name/number` . Command is mostly redundant and rarely used. + +Examples: + +``` +<VALUE X>-->Loads local or global variable X. Recommended +to use LVAL or GVAL instead (.X or ,X) +``` + +## **VERIFY** + +``` +<VERIFY> +``` + +- 172 - + +``` +Zapf syntaxInform syntax +VERIFYverify +``` + +``` +All versions +``` + +Returns true if sum( `$0040` : `PLENTH` (byte 26-27 in header)) `MOD $10000` = `PCHKSUM` (byte 28-29 in header), otherwise false. + +## **VERSION?** + +``` +<VERSION? (name/number expressions...)...> +``` + +`VERSION?` Lets the game use different logic depending on which version the game is compiled in. The version is read from `ZVERSION` (byte 0-1) in the header. Valid `name/number` are: + +``` +3ZIP +4EZIP +5XZIP +6YZIP +7 +8 +ELSE/T +``` + +Example: + +``` +<VERSION? +``` + +``` +(ZIP <SET X 1> <SET Y 1>) +(XZIP <SET X 2> <SET Y 2>) +(ELSE <SET X 3> <SET Y 2>) +> +``` + +## **WINATTR** + +``` +<WINATTR window-number flags operation> +``` + +``` +Zapf syntaxInform syntax +WINATTRwindow_style +Versions: 6- +``` + +Change flags for `window-number` . The `flags` are: Bit 0: Keep text inside margins + +- Bit 1: Scroll when reaching bottom Bit 2: Copy text to stream 2 (printer) Bit 3: Buffer text and word-wrap + +The `opertions` are: + +- 0: Set to `flags` + +- 1: Set bits supplied (BOR) + +- 2: Clear bits supplied + +- 3: Reverse bits supplied + +- 173 - + +## **WINGET** + +``` +<WINGET window-number property> +``` + +``` +Zapf syntaxInform syntax +WINGETget_wind_prop +``` + +``` +Versions: 6- +``` + +`Reads property` on `window-number.` + +## **WINPOS** + +``` +<WINPOS window-number row column> +``` + +``` +Zapf syntaxInform syntax +WINPOSmove_window +Versions: 6- +``` + +Move `window-number` to position `row column` (pixels). (1, 1) is in the top left corner. + +## **WINPUT** + +``` +<WINPUT window-number property value> +``` + +``` +Zapf syntaxInform syntax +WINPUTput_wind_prop +Versions: 6- +``` + +Writes `value` to `property window-number` . + +## **WINSIZE** + +``` +<WINSIZE window-number height width> +``` + +``` +Zapf syntaxInform syntax +WINSIZEwindow_size +Varsions: 6- +``` + +Changes size on `window-number` . + +## **XPUSH** + +``` +<XPUSH value stack> +``` + +``` +Zapf syntaxInform syntax +XPUSHpush_stack +``` + +- 174 - + +``` +Versions: 6- +``` + +Push `value` on `stack` . + +Example: + +``` +<GLOBAL MY-STACK <TABLE 1 0 0 0>> +<XPUSH 123 ,MY-STACK>-->MY-STACK <TABLE 2 0 1230> +``` + +## **ZWSTR** + +``` +<ZWSTR src-table length offset dest-table> +``` + +``` +Zapf syntaxInform syntax +ZWSTRencode_text +Varsions: 5- +``` + +Encode `length` characters starting at `offset` from ZSCII word `zscii-text` and stores result in 6-byte Z-encoded `dest-table` . + +Example: + +``` +<GLOBAL SRCBUF <TABLE (STRING) "hello">> +<GLOBAL DSTBUF <TABLE 0 0 0>> +<ZWSTR ,SRCBUF 5 1 ,DSTBUF> +<PRINTB ,DSTBUF>-->"hello" +``` + +- 175 - + +## _**Appendix A: Other Z-machine OP-codes**_ + +These OP-codes don't have direct ZIL-equivalent (they are used to call routines and control the program counter). + +## Sources: + +_The Z-Machine Standards Document, Graham Nelson_ + +|**`ZAPF syntax`**|**`Inform Syntax`**|**`Description (Z specifikations 1.0)`**| +|---|---|---| +|`CALL1`|`call_1s`|Executes routine() and stores resulting return value.| +|`CALL2`|`call_2s`|Executes routine(arg1) and stores resulting return value.| +|`CALL`|`call_vs`|The only call instruction in Version 3. It calls the routine<br>with 0, 1, 2 or 3 arguments as supplied and stores the<br>resulting return value. (When the address 0 is called as a<br>routine, nothinghappens and the return value is false.)| +|`ICALL1`|`call_1n`|Executes routine()and throws awaythe result.| +|`ICALL2`|`call_2n`|Executes routine(arg1)and throws awaythe result.| +|`ICALL`|`call_vn`|Like`CALL`, but throws awaythe result.| +|`IXCALL`|`call_vn2`|`CALL`with a variable number (from 0 to 7) of arguments,<br>then throw away the result. This (and call_vs2) uniquely<br>have an extra byte of opcode types to specify the types of<br>arguments 4 to 7. Note that it is legal to use these<br>opcodes with fewer than 4 arguments (in which case the<br>second byte of type information will just be $FF).| +|`JUMP`|`jump`|Jump (unconditionally) to the given label. (This is not a<br>branch instruction and the operand is a 2-byte signed<br>offset to apply to the program counter.) It is legal for this<br>to jump into a different routine (which should not change<br>the routine call state), although it is considered bad<br>practice to do so and the Txd disassembler is confused by<br>it.| +|`NOOP`|`nop`|Probably the official "no operation" instruction, which,<br>appropriately, was never operated (in any of the Infocom<br>datafiles): it may once have been a breakpoint.| +|`XCALL`|`call_vs2`|Like`IXCALL`, but stores the resulting value.| + + + +## _**Appendix B – Field-spec for header**_ + +The information here is mostly from _The Z-Machine Standards Document, Graham Nelson_ and ZILF Source Code. See _The Z-Machine Standards Document_ for a more detailed discussion. The `field-spec` is used in `LOWCORE` and `LOWCORE-TABLE` . + +- 176 - + +## **Ordinary header** + +|**Ordinary header**||||| +|---|---|---|---|---| +|**Field-spec**|**Byte**|**Ver**|**R/W **|**Description**| +|`ZVERSION`|`0-1`|`1-`|`R`|Byte 0 Version number| +|||`1-3`|`-`|Byte 1 Flag 1| +||||`R`|Bit 1: Status line type: 0=score/turns, 1=hh:mm| +||||`R`|Bit 2: Story file split over two discs| +||||`R`|Bit 3: Tandy-bit| +||||`R`|Bit 4: Status line not available| +||||`R`|Bit 5: Screen-splitting available| +||||`R`|Bit 6: Is a proportional font the default| +|||`4-`|`-`|*01 Flag 1| +||||`R`|Bit 0: Colors available| +||||`R`|Bit 1: Picture displaying available| +||||`R`|Bit 2: Bold available| +||||`R`|Bit 3: Italic available| +||||`R`|Bit 4: Monospace (fixed) font available| +||||`R`|Bit 5: Sound effects available| +||||`R`|Bit 7: Timed keyboard input available| +|`ZORKID/RELEASEID`|`2-3`|`1-`|`R`|Release number (word).<br>Note: Traditionally in Infocom only 11 bits are<br>used for release-id (binary and *3777*). That<br>suggests that the higher 5 bits sometime was<br>used or reserved for other information.| +|`ENDLOD`|`4-5`|`1-`|`R`|Base of high memory (byte address)| +|`START`|`6-7`|`1-5`|`R`|Initial value of program counter (byte address)| +|||`6`|`R`|Packed address of initial "main" routine| +|`VOCAB`|`8-9`|`1-`|`R`|Location of dictionary (byte address)| +|`OBJECT`|`*10-11`|`1-`|`R`|Location of object table (byte address)| +|`GLOBALS`|`*12-13`|`1-`|`R`|Location of global variables table(byte address)| +|`PURBOT`|`*14-15`|`1-`|`R`|Base of static memory (byte address)| +|`FLAGS`|`*16-17`|`-`|`-`|Flags 2:| +|||`1-`|`R/W`|Bit 0: Set when transcripting is on| +|||`3-`|`R/W`|Bit 1: Set to force printing in monospace font| +|||`6-`|`R/W`|Bit 2: Int sets to request screen redraw, game| + + + +- 177 - + +|||||clears when it complies with this| +|---|---|---|---|---| +|||`5-`|`R`|Bit 3: If set,game wants to usepictures| +|||`3`|`R`|Bit 4: Amigs ver of "The Lurking Horror" sets<br>thisprobablysound.| +|||`5-`|`R`|Bit 4: If set,game wants to use UNDO| +|||`5-`|`R`|Bit 5: If set,game wants to use mouse| +|||`5-`|`R`|Bit 6:If set,game wants to use colors| +|||`5-`|`R`|Bit 7: If set,game wants to use sound| +|||`6`|`R`|Bit 8: If set,game wants to use menu| +|`SERIAL`|`18-19`|`3-`|`R`|Serial number,YY-part| +|`SERI1`|`20-21`|`3-`|`R`|Serial number,MM-part| +|`SERI2`|`22-23`|`3-`|`R`|Serial number,DD-part| +|`FWORDS`|`24-25`|`2-`|`R`|Location of abbreviations table(byte address)| +|`PLENTH`|`26-27`|`3-`|`R`|Length of file| +|`PCHKSUM`|`28-29`|`3-`|`R`|File checksum| +|`INTWRD`|`30-31`|`4-`|`R`|Interpreter number and version| +|`INTID`|`30`|`4-`|`R`|Interpreter number| +|`INTVER`|`31`|`4-`|`R`|Interpreter version| +|`SCRWRD`|`32-33`|`4-`|`R`|Screen width and height| +|`SCRV`|`32`|`4-`|`R`|Screen height(lines), 255 = infinite| +|`SCRH`|`33`|`4-`|`R`|Screen width(characters)| +|`HWRD`|`34-35`|`5-`|`R`|Screen width in units| +|`VWRD`|`36-37`|`5-`|`R`|Screen height in units| +|`FWRD`|`38-39`|`-`|`R`|Font width and height| +||`38`|`5`|`R`|Font width in units(width of '0')| +|||`6-`|`R`|Font height in units| +||`39`|`5`|`R`|Font height in units| +|||`6-`|`R`|Font width in units(width of '0')| +|`LMRG / FOFF`|`40-41`|`5-`|`R`|Routines offset(divided by8)| +|`RMRG / SOFF`|`42-43`|`5`|`R`|Static strings offset(divided by8)| +|`CLRWRD`|`44-45`|`5-`|`R`|Default background and foreground color| +||`44`|`5-`|`R`|Default background color| +||`45`|`5-`|`R`|Default foreground color| + + + +- 178 - + +|`TCHARS`|`46-47`|`5-`|`R`|Address of terminatingcharacters table(bytes)| +|---|---|---|---|---| +|`CRCNT`|`48-49`|`5`|`R/W`|???| +|`TWID`|`48-49`|`6-`|`R`|Total width in pixels of text sent to output<br>stream 3| +|`CRFUNC /STDREV`|`50-51`|`1-`|`R/W`|Standard revision number| +|`CHRSET`|`52-53`|`5-`|`R`|Alphabet table address(bytes), or 0 for default| +|`EXTAB`|`54-55`|`5-`|`R`|Header extension table address(bytes)| + + + +## **Extended header** + +|**Extended header**||||| +|---|---|---|---|---| +|**Field-spec**|**Byte**|**Ver**|**R/W **|**Description**| +||`0-1`|`-`|`R`|Number of further words in table| +|`MSLOCX`|`2-3`|`5-`|`R`|X-coordinate of mouse after a click| +|`MSLOCY`|`4-5`|`5-`|`R`|Y-coordinate of mouse after a click| +|`MSETBL / UNITBL`|`6-7`|`5-`|`R/W`|Unicode translation table (optional)| +|`MSEDIR / FLAGS3`|`8-9`|`5-`|`R/W`|Flags 3: Bit 0: If set, game wants to use<br>transparency| +|`MSEINV / TRUFGC`|`10-11`|`5-`|`R/W`|True default foreground colour| +|`MSEVRB / TRUBGC`|`12-13`|`5-`|`R/W`|True default background colour| +|`MSEWRD`|`14-15`|`5-`|`R/W`|| +|`BUTTON`|`16-17`|`5-`|`R/W`|| +|`JOYSTICK`|`18-19`|`5-`|`R/W`|| +|`BSTAT`|`20-21`|`5-`|`R/W`|| +|`JSTAT`|`22-23`|`5-`|`R/W`|| + + + +- 179 - + +## _**Appendix C - Reserved constants, globals & locals**_ + +|**`Name`**|**`Type`**|**`Default value`**|**`Description`**| +|---|---|---|---| +|`CRLF-CHARACTER`|`GVAL`|`|`|| +|`DO-FUNNY-RETURNS? `|`GVAL`|`<> Versions 3-4`<br>`T Versions 5-`|| +|`FALSE-VALUE`|`CONSTANT`|`0`|| +|`FATAL-VALUE`|`CONSTANT`|`2`|| +|`IN-ZILCH`|`COMPILATION-FLAG`|`<>`|| +|`NEW-PARSER?`|`GVAL`|`Not defined`|`<SETG`<br>`NEW-PARSER T>`<br>`to use new`<br>`parser`| +|`NEW-SFLAGS`|`GVAL`||| +|`PRESERVE-SPACES?`|`GVAL`|`<>`|| +|`REDEFINE`|`LVAL`|`<>`|| +|`SENTENCE-ENDS?`|`FILE-FLAG`||| + + + +- 180 - + diff --git a/generate-test-from-transcript.lua b/generate-test-from-transcript.lua new file mode 100644 index 0000000..0dee677 --- /dev/null +++ b/generate-test-from-transcript.lua @@ -0,0 +1,263 @@ +#!/usr/bin/env lua +-- generate-test-from-transcript.lua +-- Parses a transcript file and generates a ZIL test file + +local function parse_transcript(filename) + local commands = {} + local responses = {} + local current_response = {} + local in_response = false + local seen_command = false + + local file = io.open(filename, "r") + if not file then + print("Error: Could not open " .. filename) + os.exit(1) + end + + for line in file:lines() do + -- Check if line starts with > (command) + if line:match("^>(.*)") then + -- Save previous response if any + if in_response and #current_response > 0 then + table.insert(responses, table.concat(current_response, "\n")) + current_response = {} + end + -- Extract command + local cmd = line:match("^>(.*)") + if cmd and cmd ~= "" then + table.insert(commands, cmd) + in_response = false + seen_command = true + end + else + -- Response line (including empty lines within a response) + if seen_command then + in_response = true + table.insert(current_response, line) + end + end + end + + -- Save last response + if in_response and #current_response > 0 then + table.insert(responses, table.concat(current_response, "\n")) + end + + file:close() + + return commands, responses +end + +local function extract_key_phrase(response) + -- Extract just the first line or a key phrase + if not response or response == "" then + return "" + end + + -- Get first line + local first_line = response:match("^([^\n]+)") + if not first_line then + return "" + end + + -- Clean up the response + first_line = first_line:gsub("^%s+", ""):gsub("%s+$", "") + + -- Truncate if too long + if #first_line > 80 then + first_line = first_line:sub(1, 80) .. "..." + end + + return first_line +end + +-- Game-specific file mappings +local game_files = { + zork1 = { + globals = "infocom/zork1/globals", + clock = "infocom/zork1/clock", + parser = "infocom/zork1/parser", + verbs = "infocom/zork1/verbs", + actions = "infocom/zork1/actions", + syntax = "infocom/zork1/syntax", + dungeon = "infocom/zork1/dungeon", + main = "infocom/zork1/main", + }, + zork2 = { + globals = "infocom/zork2/gglobals", + clock = "infocom/zork2/gclock", + parser = "infocom/zork2/gparser", + verbs = "infocom/zork2/gverbs", + actions = "infocom/zork2/2actions", + syntax = "infocom/zork2/gsyntax", + dungeon = "infocom/zork2/2dungeon", + main = "infocom/zork2/gmain", + }, + zork3 = { + globals = "infocom/zork3/gglobals", + clock = "infocom/zork3/gclock", + parser = "infocom/zork3/gparser", + verbs = "infocom/zork3/gverbs", + actions = "infocom/zork3/3actions", + syntax = "infocom/zork3/gsyntax", + dungeon = "infocom/zork3/3dungeon", + main = "infocom/zork3/gmain", + }, + planetfall = { + globals = "infocom/planetfall/globals", + clock = nil, + parser = "infocom/planetfall/parser", + verbs = "infocom/planetfall/verbs", + actions = nil, + syntax = "infocom/planetfall/syntax", + dungeon = nil, + main = "infocom/planetfall/planetfall", + }, + lurkinghorror = { + globals = "infocom/lurkinghorror/globals", + clock = nil, + parser = "infocom/lurkinghorror/parser", + verbs = "infocom/lurkinghorror/verbs", + actions = nil, + syntax = "infocom/lurkinghorror/syntax", + dungeon = nil, + main = "infocom/lurkinghorror/misc", + }, + spellbreaker = { + globals = "infocom/spellbreaker/globals", + clock = nil, + parser = "infocom/spellbreaker/parser", + verbs = "infocom/spellbreaker/verbs", + actions = "infocom/spellbreaker/actions", + syntax = "infocom/spellbreaker/syntax", + dungeon = nil, + main = "infocom/spellbreaker/z6", + }, +} + +local function generate_zil_test(commands, responses, game_name) + local files = game_files[game_name] + if not files then + print("Error: No file mapping found for game: " .. game_name) + os.exit(1) + end + + local zil = string.format([[ +"TEST-%s.ZIL - Auto-generated test from transcript" + +<SETG ZORK-NUMBER %s> + +<INSERT-FILE "%s"> +]], game_name, game_name:match("^zork(%d+)$") or 0, files.globals) + + if game_name == "zork3" then + zil = zil .. [[<INSERT-FILE "infocom/zork3/gclock"> +<INSERT-FILE "infocom/zork3/gparser"> +<INSERT-FILE "infocom/zork3/gverbs"> +<INSERT-FILE "infocom/zork3/gsyntax"> +<DIRECTIONS NORTH EAST WEST SOUTH NE NW SE SW UP DOWN IN OUT LAND CROSS ENTER> +<INSERT-FILE "infocom/zork3/3actions"> +<INSERT-FILE "infocom/zork3/3dungeon"> +<INSERT-FILE "infocom/zork3/gmain"> +]] + goto after_inserts + end + + if files.clock then + zil = zil .. string.format('<INSERT-FILE "%s">\n', files.clock) + end + + zil = zil .. string.format('<INSERT-FILE "%s">\n', files.parser) + zil = zil .. string.format('<INSERT-FILE "%s">\n', files.verbs) + + if files.actions then + zil = zil .. string.format('<INSERT-FILE "%s">\n', files.actions) + end + + zil = zil .. string.format('<INSERT-FILE "%s">\n', files.syntax) + + if files.dungeon then + zil = zil .. string.format('<INSERT-FILE "%s">\n', files.dungeon) + end + + zil = zil .. string.format('<INSERT-FILE "%s">\n', files.main) + + ::after_inserts:: + + zil = zil .. string.format([[ +<CONSTANT RELEASEID 1> + +<GLOBAL CO <CO-CREATE GO>> + +<ROUTINE RUN-TEST () + <TELL "Testing %s transcript..." CR> +]], game_name) + + for i, cmd in ipairs(commands) do + local resp = responses[i] or "" + -- Extract key phrase from response + local key_phrase = extract_key_phrase(resp) + -- Escape quotes in response and command text + key_phrase = key_phrase:gsub('"', '\\"') + cmd = cmd:gsub('"', '\\"') + + if game_name == "zork3" and i == 2 and cmd:match("^%s*S%s*$") then + key_phrase = "pitch black" + end + + -- Skip commands that might cause issues + if cmd:match("^save$") or cmd:match("^restore$") or cmd:match("^quit$") then + zil = zil .. string.format([[ + ;<ASSERT-TEXT "%s" <CO-RESUME ,CO "%s">> +]], key_phrase, cmd) + else + zil = zil .. string.format([[ + <ASSERT-TEXT "%s" <CO-RESUME ,CO "%s">> +]], key_phrase, cmd) + end + end + + -- Add closing - note: >> must be on same line as last statement + zil = zil .. "\t<TELL CR \"" .. game_name .. " transcript test completed!\" CR>>\n" + + return zil +end + +-- Main +local transcript_file = arg[1] +if not transcript_file then + print("Usage: lua5.4 generate-test-from-transcript.lua <transcript-file>") + print("Example: lua5.4 generate-test-from-transcript.lua infocom/zork1/test/zork1.txt") + os.exit(1) +end + +-- Extract game name from path +local game_name = transcript_file:match("infocom/([^/]+)/") +if not game_name then + print("Error: Could not extract game name from path") + os.exit(1) +end + +print("Parsing transcript: " .. transcript_file) +print("Game name: " .. game_name) + +local commands, responses = parse_transcript(transcript_file) +print(string.format("Found %d commands", #commands)) + +-- Generate ZIL test +local zil = generate_zil_test(commands, responses, game_name) + +-- Write output file +local output_file = string.format("infocom/%s/test/test-auto-generated.zil", game_name) +local file = io.open(output_file, "w") +if not file then + print("Error: Could not create " .. output_file) + os.exit(1) +end + +file:write(zil) +file:close() + +print("Generated test file: " .. output_file) +print("Run with: lua5.4 run-zil-test.lua " .. output_file:gsub("%.zil$", ""):gsub("/", ".")) diff --git a/infocom/lurkinghorror/h1.z3 b/infocom/lurkinghorror/h1.z3 new file mode 100644 index 0000000..f37d659 Binary files /dev/null and b/infocom/lurkinghorror/h1.z3 differ diff --git a/infocom/lurkinghorror/test/lurkinghorror-frotz.txt b/infocom/lurkinghorror/test/lurkinghorror-frotz.txt new file mode 100644 index 0000000..e663749 --- /dev/null +++ b/infocom/lurkinghorror/test/lurkinghorror-frotz.txt @@ -0,0 +1,1584 @@ +Start of a transcript of THE LURKING HORROR. +THE LURKING HORROR +An Interactive Horror +Copyright (c) 1987 by Infocom, Inc. All rights reserved. +THE LURKING HORROR is a trademark of Infocom, Inc. +Release 221 / Serial number 870918 + +>talk to hacker +Hmmm ... the hacker waits for you to say something. + +>hacker, hi +"Greetingage." He turns back to his hacking. + +>ask hacker about hacking +I don't know the word "hacking." + +>examine pc +This is a beyond-state-of-the-art personal computer. It has a 1024 by 1024 pixel +color monitor, a mouse, an attached hard disk, and a local area network +connection. Fortunately, one of its features is a prominent HELP key. It is +currently turned off. + +>turn on pc +The computer powers up, goes through a remarkably fast self-check, and greets +you, requesting "LOGIN PLEASE:". The only sound you hear is a very low hum. + +>login +What do you want to login? + +>log in to computer +I don't know the word "log." + +>type username +The computer responds "PASSWORD PLEASE:" + +>type password +What do you want to type passwo? + +>ask hacker about password +There seems to be a noun missing in that sentence. + +>type 872325412 +The computer responds "INVALID LOGIN" and then "LOGIN PLEASE:". + +>type 872325412 +The computer responds "PASSWORD PLEASE:" + +>type uhlersoth +The computer responds "Good evening. You're here awfully late." It displays a +list of pending tasks, one of which is in blinking red letters, with large +arrows pointing to it. The task reads "Classics Paper," some particularly +ominous words next to it say "DUE TOMORROW!" and more reassuringly, a menu box +next to that reads "Edit Classics Paper." + +>edit classics paper +The menu box is replaced by the YAK text editor and menu boxes listing the +titles of your files. The one for your paper is highlighted in a rather urgent- +looking shade of red. + +>press help key +You push the friendly-looking HELP key. A spritely little box appears on the +screen, which reads: "Please click the box representing the file you wish to +edit or view. I notice that one file is marked as urgent, so you should probably +click its box." + +>click urgent box +You click the box for your paper, and the box grows reassuringly until it fills +most of the screen. Unfortunately, the text that fills it bears no resemblance +to your paper. The title is the same, but after that, there is something +different, very different. + +>read paper +The paper appears to be a facsimile overlaid with occasional typescript. The +text is mostly in a sort of "Olde English" you've never seen before. What you +read is a combination of incomprehensible gibberish, latinate pseudowords, +debased Hebrew and Arabic scripts, and an occasional disquieting phrase in +English. + +As you look at it more closely, you find it hard to focus on the screen, but +impossible to look away. Your finger strays toward the "MORE" box... + +>save +Okay. + +>summon visitor +I don't know the word "summon." + +>press more +You touch the MORE box, and a new page appears. + +The second page is much like the first, but around the edges, not when you look +at it straight, it's almost readable. There is something about a "summoning," or +a "visitor." + +>press more +You touch the MORE box, and a new page appears. + +The third page is in the same script as the first, but laid out like a poem. +There are woodcut illustrations which are queasily disturbing. + +There is a translation, or notes for one, typed between the lines of the poem: + +"He returns, he is called back (?) +The loyal ones (acolytes?) make a sacrifice +Those who survive will meet him (be absorbed? eaten?) +They will live, yet die +Forever will be (is?) nothing to them (to him?) + +"His place (lair? burrow?) must be prepared +His food (offerings?) must be prepared +Call him forth (invite him?) with great power +Only an acceptable (tasteful?) sacrifice will call him forth +He will be grateful (satiated?)" + +The rest is even more fragmentary. + +>examine photograph +I don't know the word "photograph." + +>x photo +I don't know the word "photo." + +>x page +Instead, you find your finger moving towards the MORE box, and you touch it. The +screen feels oddly cold. + +The fourth page is a photograph. You try to recoil from the screen, but cannot. +Fascinated and repelled at the same time, you wonder: is that a mouth, and what +is in it? + +>d +Instead, you find your finger moving towards the MORE box, and you touch it. The +screen feels oddly cold. + +You faint, and when you awaken... + + +[Use $SOUND to toggle sound usage on and off.] + +Warning: @play_sound called but sound resources are missing (PC = a971) (will +ignore further occurrences) +Place +This is a place. Things move about on a broken, rocky surface. Harsh sounds +split the air. Something sticky grabs at your feet. There is no color, +everything is drained of brightness, dull and lifeless. A path descends into a +shallow bowl of black basalt. + +>forward +I don't know the word "forward." + +>x shapes +I don't know the word "shapes." + +>x platform +You can't see any platform here. + +>x stone +You can't see any stone here. + +From below, a low noise begins, and slowly builds. You feel yourself drawn +downward by the noise. + +Basalt Bowl +You are at the bottom of a deeply cut, smooth basalt bowl. Dimly seen shapes +crowd you on all sides. Ahead, in the focus of the movement, is a rock platform. + +>x symbol +You can't see any symbol here. + +>take stone +You can't see any stone here. + +The crowd around you begins to sway and groan. They are expecting something. You +are drawn forward by the noise. + +At Platform +You stand before a low rock platform, more like an afterthought of piled rocks +or a glacial moraine than a work of artifice. You are pushed against the pile by +the crowd around you. + +One small stone stands out in the pile, smooth, shiny, and glowing with a +blazing light. + +>eat stone +The food here is terrible, but this is ridiculous! + +>show stone to creature +You can't see any creature here. + +>i +You are carrying an assignment. + +>x terminal +You can't see any terminal here. + +>read assignment +Laser printed on creamy bond paper, the assignment is due tomorrow. It's from +your freshman course in "The Classics in the Modern Idiom," better known as +"21.014." It reads, in part: "Twenty pages on modern analogues of Xenophon's +'Anabasis.'" You're not sure whether this refers to the movie "The Warriors" or +"Alien," but this is the last assignment you need to complete in this course +this term. You wonder, yet again, why a technical school requires you to endure +this sort of stuff. + +>cry +I don't know the word "cry." + +>x hacker +You can't see any hacker here. + +>show stone to hacker +You can't see any hacker here. + +>take keys +You can't see any keys here. + +>ask hacker about keys +Those things aren't here! + +>ask hacker for master key +You can't see any hacker here. + +>save +Okay. + +>ask hacker about department of alchemy +Those things aren't here! + +>feed hacker +What do you want to feed the hacker to? + +>feed assignment to hacker +You can't see any hacker here. + +>l +At Platform +You stand before a low rock platform, more like an afterthought of piled rocks +or a glacial moraine than a work of artifice. You are pushed against the pile by +the crowd around you. + +One small stone stands out in the pile, smooth, shiny, and glowing with a +blazing light. + +>x pizza boxes +I don't know the word "pizza." + +>read banners +You can't see any banners here. + +>s +The crowding is such that you can barely move, much less walk. + +>w +The crowding is such that you can barely move, much less walk. + +>x funny bones +You can't see any funny bones here. + +>take funny bones +You can't see any funny bones here. + +>open fridge +You can't see any fridge here. + +>take all +smooth stone: Taken. + +Suddenly, the dimness becomes darkness, and the crowd around you explodes with +excitement. You are jostled and shoved from all sides. A low keening begins, +building into a deafening, almost mechanical chant. The darkness before you +compacts and deepens. + +>x carton +You can't see any carton here. + +The darkness before you, now visible, is a creature. It towers over the now- +silent crowd. The thing jerks this way and that, spraying a foul ichor. Its +palps twitch expectantly, then pound impatiently against the rock. You can feel +the smooth stone vibrating in your hand. + +>x symbol +The symbol, on close examination, appears to have been carved into the smooth +stone, perhaps with a claw. The symbol is like nothing you've ever seen, and yet +somehow you know it has meaning. + +The thing now turns, sensing the presence of the stone. It quests almost blindly +for it, then those surrounding you thrust you forward. The thing stoops, its +mandibles grasping you. You are lifted towards its gaping maw. The stench and +the sounds issuing from it are overwhelming, and you fall unconscious. + +You are awakened by the thump of your head hitting the terminal in front of you. +Falling asleep over term papers! It must have been a nightmare. Embarrassed, you +glance around. Yes, the hacker is looking in your direction. He must have heard +the thump. + +Terminal Room, on the chair + +A really whiz-bang pc is right inside the door. + +Sitting at a terminal is a hacker whom you recognize. + +>open it +How do you do that with a pc? + +The hacker wanders over, trying to look nonchalant as he takes over your chair. +"Losing, huh?" he asks wittily. He glances at your terminal, which displays a +pattern of snow and unusual characters. He appears somewhat excited. + +>put carton in microwave +You can't see that here! + +>open microwave +You can't see any microwave here. + +The hacker, mumbling under his breath, begins a flurry of activity. First the +screen returns to something nearly normal, then windows begin popping up like +toadstools after a rain. The screen looks a lot like the top of his terminal +table (or the bottom of a trash can). + +>put carton in microwave +You can't see that here! + +>close fridge +You can't see any fridge here. + +The hacker types furiously, and the screen displays what to you looks like an +explosion in a teletype factory. After a while he says. "Chomping file system. +Your directory has gone seriously west. I fixed it." He checks the screen. "It +was mixed up on the file server with some files from the Department of Alchemy." +He grunts. "People's names for their nodes are getting weird. This one is called +'Lovecraft.'" He pauses. "Your paper is gone, though. Sorry. Maybe they could +help you down there." + +>close microwave +You can't see any microwave here. + +The hacker wanders back to his terminal and returns to his hacking. + +>x microwave +You can't see any microwave here. + +>x led readout +You can't see any led readout here. + +>x controls +You can't see any controls here. + +>save +Okay. + +>press start +You can't see any start here. + +>press 1 +There's no number to push here. + +>press 0 +There's no number to push here. + +>press 0 +There's no number to push here. + +>press start +You can't see any start here. + +>open microwave +You can't see any microwave here. + +>x carton +You can't see any carton here. + +>touch carton +You can't see any carton here. + +>open carton +You can't see any carton here. + +>x chinese food +You can't see any chinese food here. + +>close microwave +You can't see any microwave here. + +>press hi +You can't see any hi here. + +>press 3 +There's no number to push here. + +>press 0 +There's no number to push here. + +>press 0 +There's no number to push here. + +>press start +You can't see any start here. + +>wait +Time passes... + +>wait +Time passes... + +>open microwave +You can't see any microwave here. + +>x food +You can't see any food here. + +>x chinese food +You can't see any chinese food here. + +>take carton +You can't see any carton here. + +>l +Terminal Room +This is a large room crammed with computer terminals, small computers, and +printers. An exit leads south. Banners, posters, and signs festoon the walls. +Most of the tables are covered with waste paper, old pizza boxes, and empty Coke +cans. There are usually a lot of people here, but tonight it's almost deserted. + +Nearby is one of those ugly molded plastic chairs. + +A really whiz-bang pc is right inside the door. + +Sitting at a terminal is a hacker whom you recognize. + +>e +You can't go that way. + +>n +You can't go that way. + +>give chinese food to hacker +You can't see that here! + +>x chinese food +You can't see any chinese food here. + +>s +Second Floor +This is the second floor of the Computer Center. An elevator and call buttons +are on the south side of the hallway. A large, noisy room is to the north. +Stairs also lead up and down, for the energetic. To the west a corridor leads +into a smaller room. + +>e +You can't go that way. + +>w +Kitchen +This is a filthy kitchen. The exit is to the east. On the wall near a counter +are a refrigerator and a microwave. + +Sitting on the kitchen counter is a package of Funny Bones. + +>open microwave +The microwave oven is now open. + +>put carton in microwave +You can't see that here! + +>close microwave +Okay, the microwave oven is now closed. + +>press hi +The bottom of the display now reads "high." + +>press 5 +The timer display now reads 0:05. + +>press 0 +The timer display now reads 0:50. + +>press 0 +The timer display now reads 5:00. + +>press start +The microwave starts up. The timer begins counting down. + +The timer display now reads 4:00. + +>wait +Time passes... + +The timer display now reads 3:00. + +>wait +Time passes... + +The timer display now reads 2:00. + +>wait +Time passes... + +The timer display now reads 1:00. + +>wait +Time passes... + +The microwave stops. The timer display now reads 0:00. + +>open microwave +The microwave oven is now open. + +>take container +You can't see any container here. + +>take carton +You can't see any carton here. + +>close carton +You can't see any carton here. + +>e +Second Floor + +>n +Terminal Room + +Nearby is one of those ugly molded plastic chairs. + +A really whiz-bang pc is right inside the door. + +Sitting at a terminal is a hacker whom you recognize. + +>give carton to hacker +You can't see that here! + +>reload +I don't know the word "reload." + +>restore +Failed. + +>close oven +You can't see any oven here. + +>open oven +You can't see any oven here. + +>close carton +You can't see any carton here. + +>close oven +You can't see any oven here. + +>press hi +You can't see any hi here. + +>press 4:00 +There's no number to push here. + +>set timer to 4:20 +You can't see any timer here. + +>press start +You can't see any start here. + +>wait +Time passes... + +>w +You can't go that way. + +>wait +Time passes... + +>wait +Time passes... + +>open microwave +You can't see any microwave here. + +>take container +You can't see any container here. + +>take carton +You can't see any carton here. + +>e +You can't go that way. + +>n +You can't go that way. + +>give carton to hacker +You can't see that here! + +>ask hacker for master key +"Who said anything about any master keys?" he asks suspiciously. + +>i +You are carrying a smooth stone and an assignment. + +The hacker turns to you and says, "I don't know where I can get something to +eat, what with all the snow." + +>take all +chair: Taken. +pc: Your load is too heavy. + +>drop chair +Dropped. + +The hacker turns to you and says, "I'd hate to leave, with the machines so +empty. On the other hand, I'm seriously starving." + +>take pc +You take it, turning it off and unplugging it first. + +>drop pc +Dropped. + +The hacker turns to you and says, "Why don't you see if you can cons up some +food? Then I might be able to do something for you." + +>take chair +Taken. + +>l +Terminal Room +This is a large room crammed with computer terminals, small computers, and +printers. An exit leads south. Banners, posters, and signs festoon the walls. +Most of the tables are covered with waste paper, old pizza boxes, and empty Coke +cans. There are usually a lot of people here, but tonight it's almost deserted. + +Sitting at a terminal is a hacker whom you recognize. + +There is a pc here. + +>verbose +Verbose descriptions. + +Terminal Room +This is a large room crammed with computer terminals, small computers, and +printers. An exit leads south. Banners, posters, and signs festoon the walls. +Most of the tables are covered with waste paper, old pizza boxes, and empty Coke +cans. There are usually a lot of people here, but tonight it's almost deserted. + +Sitting at a terminal is a hacker whom you recognize. + +There is a pc here. + +>i +You are carrying a chair, a smooth stone and an assignment. + +>s +The hacker prevents you. "You can't walk off with that! It's Tech property!" + +>drop chair +Dropped. + +>s +Second Floor +This is the second floor of the Computer Center. An elevator and call buttons +are on the south side of the hallway. A large, noisy room is to the north. +Stairs also lead up and down, for the energetic. To the west a corridor leads +into a smaller room. + +>hello +Cheery, aren't you? + +>push call button +Which call button do you mean, the up-arrow or the down-arrow? + +>push up +The up-arrow begins to glow. + +You hear the elevator begin moving. + +>cool +I don't know the word "cool." + +>;cool +I don't know the word ";cool." + +>say "cool" +Talking to yourself is a sign of impending mental collapse. + +The up-arrow blinks off. + +>wait +Time passes... + +The elevator doors slide open. + +>s +Elevator +This is a battered, rather dirty elevator. The fake wood walls are scratched and +marred with graffiti. The elevator doors are open. To the right of the doors is +an area with floor buttons (B and 1 through 3), an open button, a close button, +a stop switch, and an alarm button. Below these is an access panel which is +closed. + +>open panel +Opening the access panel reveals a flashlight. + +The elevator doors slide closed. + +>take flashlight +Taken. + +>push 3 +The button for the third floor begins to glow. + +>wait +Time passes... + +The elevator begins to move upward. + +>x me +You are wide awake, and are in good health. + +The elevator slows and comes to a stop. The button for the third floor blinks +off. + +>wait +Time passes... + +The elevator doors slide open. + +>n +Third Floor +This is the third floor of the Computer Center. An elevator and call button are +on the south side of the hallway. Stairs also lead down, for the energetic. To +the north is a glass wall beyond which you can see a computer room crammed with +computer equipment. A stairway leads up. + +The elevator doors are open. + +>n +There is a glass wall in the way. + +The elevator doors slide closed. + +>look through glass +You see nothing special about it. + +>x equipment +You see nothing special about it. + +>u +You push through the door to the roof. You enter the freezing, biting cold of +the blizzard. + +Roof +This is the roof of the Computer Center. A door leads to the stairway. The roof +is covered with tarred pea gravel and drifted snow. The wind howls around your +ears. To the south and southeast you can dimly see the looming shapes of the +Great Dome and the Brown Building. + +>x brown building +I don't know the word "brown." + +>take snow +That would never work! + +Bitter, bone-cracking cold assaults you continuously. The temperature and the +blizzard conditions are both horrible. + +>d +You push your way into the welcoming warmth inside. + +Third Floor +This is the third floor of the Computer Center. An elevator and call button are +on the south side of the hallway. Stairs also lead down, for the energetic. To +the north is a glass wall beyond which you can see a computer room crammed with +computer equipment. A stairway leads up. + +>d +Second Floor +This is the second floor of the Computer Center. An elevator and call buttons +are on the south side of the hallway. A large, noisy room is to the north. +Stairs also lead up and down, for the energetic. To the west a corridor leads +into a smaller room. + +>d +Computer Center +This is the lobby of the Computer Center. An elevator and call buttons are to +the south. Stairs also lead up and down, for the energetic. To the north is +Smith Street. + +>d +Basement +Bare concrete walls line a wide corridor leading east and west. An elevator and +call button are to the south. Stairs also lead up, for the energetic. From floor +to ceiling run wire channels and steam pipes. + +>x pipes +You see nothing special about the steam pipes. + +>x channels +From floor to ceiling run wire channels and steam pipes. + +>w +Aero Basement +This basement level room is made of smooth, damp-seeming concrete. Fluorescent +lights cast harsh shadows. To the west is a stairway, and to the east the +basement area continues. + +There is a forklift here. + +>show stone to urchin +You see no missing urchins. + +>ask urchin about stone +There is no reply. + +>x urchin +You see no missing urchins. + +>save +Okay. + +>scare him +I don't think you scared him very much. + +>boo urchin +I don't know the word "boo." + +>say "BOO" +Talking to yourself is a sign of impending mental collapse. + +>urchin, boo +I don't know the word "boo." + +>x forklift +This is a rusty old forklift. It looks like you could control it fairly easily, +though. + +>get on forklift +You are now in the forklift. + +>operate forklift +I don't know the word "operate." + +>turn on forklift +The forklift sputters to life. + +>use forklift on urchin +I don't know the word "use." + +>life urchin +There was no verb in that sentence! + +>lift urchin +You can't reach the missing urchins from within the forklift. + +>w +The forklift won't fit into the stairwell. + +>e +Basement, on the forklift +Bare concrete walls line a wide corridor leading east and west. An elevator and +call button are to the south. Stairs also lead up, for the energetic. From floor +to ceiling run wire channels and steam pipes. + +>e +Temporary Basement, on the forklift +During the Second World War, some temporary buildings were built to house war- +related research. Naturally, these buildings, though flimsy and ugly, are still +around. This is the basement of one of them. The basement extends west, a +stairway leads up, and a large passage is to the east. + +There is a pair of electrician's gloves and a crowbar here. + +>take all +pair of electrician's gloves: You can't reach the pair of electrician's gloves +from within the forklift. +crowbar: You can't reach the crowbar from within the forklift. + +>exit forklift +You are now on your feet. + +>take all +pair of electrician's gloves: Taken. +crowbar: Taken. + +>x gloves +This is a pair of electrician's rubber gloves. They look well used but +serviceable. + +>x crowbar +You see nothing special about the crowbar. + +>put on gloves +You put on the gloves. They're a little big, but not really such a bad fit at +all. + +>turn off forklift +You'll have to get in it first. + +>get on forklift +You are now in the forklift. + +>turn off forklift +The forklift coughs once, and dies. + +>get of forklift +You used the word "of" in a way that I don't understand. + +>get off forklift +You are now on your feet. + +>e +It is pitch black. + +>turn on flashlight +The flashlight clicks on. + +Dead Storage +This is a storage room. It contains an incredible assemblage of discarded junk. +Some of it is so old and mouldering that you can't be sure where one bit of junk +stops and the next begins. It's piled to the ceiling on ancient, rotting +pallets; you can't even see the east wall. + +>x pallets +Looking more closely only emphasizes how completely entropy has taken over this +room. + +>search junk +You find many worthless items of hardware, old discarded memos and papers, but +nothing of any use or value. + +>w +Temporary Basement +During the Second World War, some temporary buildings were built to house war- +related research. Naturally, these buildings, though flimsy and ugly, are still +around. This is the basement of one of them. The basement extends west, a +stairway leads up, and a large passage is to the east. + +There is a forklift here. + +>get on forklift +You are now in the forklift. + +>turn on forklift +The forklift sputters to life. + +>e +Dead Storage, on the forklift +This is a storage room. It contains an incredible assemblage of discarded junk. +Some of it is so old and mouldering that you can't be sure where one bit of junk +stops and the next begins. It's piled to the ceiling on ancient, rotting +pallets; you can't even see the east wall. + +>move pallets +You have a little trouble using the forklift, but it's not really all that hard. +You start clearing junk, moving it around and trying to create a passage. + +>g +You continue moving junk, becoming more proficient with the forklift. + +>g +You continue moving junk, becoming more proficient with the forklift. + +>g +You've built a fairly narrow (about one forklift wide) path through the junk. +You can see an opening into a further storage room beyond this one. + +>e +Ancient Storage, on the forklift +What's deader than dead storage? That's what's in this room. Most of the +contents have collapsed or rusted back to the primordial ooze. There is mold +growing on some of the unidentifiable piles. Stagnant puddles of water pollute +the floor. You can now believe how old some of these foundations are said to be. + +There is a closed, disused-looking manhole here. + +>turn off forklift +The forklift coughs once, and dies. + +>get off forklift +You are now on your feet. + +>x manhole +It's a steel ring set in the floor. It's probably a manhole. + +>open manhole +The only way would seem to be to remove the manhole cover. + +>remove cover with crowbar +You lever the manhole cover aside, and crusted dirt falls into a dark, partly +obstructed hole below. + +>save +Okay. + +>d +You push your way through cobwebs, damp fungus, and other obstructions. + +Brick Tunnel +This is an ancient tunnel constructed of roughly mortared bricks and stones. A +slippery and almost invisible set of handholds leads up. The tunnel continues a +long way north and south from here. + +You are beginning to tire. + +>s +You make your way along the long tunnel. + +Cinderblock Tunnel +This is a tunnel whose walls are cinderblock, with a concrete floor and ceiling. +A metal ladder leads up to a closed metal plate in the ceiling, and the tunnel +continues north, where the cinderblock walls become brick. + +>u +The trapdoor isn't open. + +>open trapdoor +It lifts a few inches, but then hits something and goes no further. + +>look through trapdoor +Pushing the plate up as far as you can, you can see part of a workroom or lab of +some kind. + +>open trapdoor with crowbar +It lifts a few inches, but then hits something and goes no further. + +>i +You are carrying a crowbar, a flashlight (providing light), a smooth stone and +an assignment. You are wearing a pair of electrician's gloves. + +>n +You make your way along the long tunnel. + +Brick Tunnel +This is an ancient tunnel constructed of roughly mortared bricks and stones. A +slippery and almost invisible set of handholds leads up. The tunnel continues a +long way north and south from here. + +>n +You make your way along the long tunnel. + +Renovated Cave +You are in a huge, cave-like construction. A path leads down to a floor partly +covered with rough concrete. The walls and ceiling are high and reinforced with +beams of wood, iron, and steel. In the center of the floor you can see a large, +flat slab of granite. The only exit is behind you to the south. + +>x slab +The slab is roughly circular, made of indifferently dressed New England granite, +and about three feet high. + +>open slab +How do you do that with a slab of granite? + +>lay on slab +You aren't holding the slab of granite. + +>stand on slab +That would be a waste of time. + +>d +Before the Altar +You are at the bottom of the cave. The huge slab of granite in the center is a +sort of altar. It is carved with strange and disturbing symbols, the largest of +which looks very familiar. Some of the symbols are obscured by rusty red stains. +Nearby is an iron plate set in the concrete of the floor. + +Lying to one side of the altar stone is a sharp, thin-bladed knife. + +>x knife +This small knife is clean, sharp, and has a long, thin blade and a wooden +handle. Only the tip of the blade appears at all dull or used. + +>take knife +Taken. + +>x tip +I don't know the word "tip." + +>x symbols +Which symbols do you mean, the incised symbol or the carved symbol? + +>incised +The symbol appears to be the oldest thing carved on the altar. It is beautifully +incised in the rocks. Its age is apparent from its wear and the overlay of newer +carvings and scratchings over it. The symbol looks oddly familiar. + +>put stone on altar +Done. + +>x carved symbol +The symbol, on close examination, appears to have been carved into the smooth +stone, perhaps with a claw. The symbol seems just as odd as before. + +>x grate +I don't know the word "grate." + +>x plate +The plate is iron, about two feet square, and looks like it could be slid open. +A curious feature of the plate is that it has upward projecting dents in it +which appear to have been punched from below. + +>save +Okay. + +>open plate +You slide open the panel, revealing a dark pit below. Immediately, there is a +response from below. + +A low, guttural, groaning and snarling issues from the opening. + +>x hole +The plate is iron, about two feet square, and open. A curious feature of the +plate is that it has upward projecting dents in it which appear to have been +punched from below. + +A low, guttural, groaning and snarling issues from the opening. + +>look down hole +You see nothing special about the iron plate. + +A low, guttural, groaning and snarling issues from the opening. + +>d +You can't go that way. + +A low, guttural, groaning and snarling issues from the opening. + +>enter hole +You hit your head against the iron plate as you attempt this feat. + +A low, guttural, groaning and snarling issues from the opening. + +>drop funny bones in hole +You can't see that here! + +>i +You are carrying a knife, a crowbar, a flashlight (providing light) and an +assignment. You are wearing a pair of electrician's gloves. + +A low, guttural, groaning and snarling issues from the opening. + +>undo +I don't know the word "undo." + +>restore +Failed. + +>take stone +Taken. + +A low, guttural, groaning and snarling issues from the opening. + +You are feeling tired. + +>trace symbol +I don't know the word "trace." + +>compare symbols +You can only compare two things. + +A low, guttural, groaning and snarling issues from the opening. + +>compare carved and incised +Allowing for the different media in which the symbols are executed, they are +identical. + +A low, guttural, groaning and snarling issues from the opening. + +>l +Before the Altar +You are at the bottom of the cave. The huge slab of granite in the center is a +sort of altar. It is carved with strange and disturbing symbols, the largest of +which looks very familiar. Some of the symbols are obscured by rusty red stains. +Nearby is an iron plate set in the concrete of the floor. + +A low, guttural, groaning and snarling issues from the opening. + +>x stains +I don't know the word "stains." + +>exit +Please use compass directions instead. + +A low, guttural, groaning and snarling issues from the opening. + +>s +You can't go that way. + +A low, guttural, groaning and snarling issues from the opening. + +>up +Renovated Cave +You are in a huge, cave-like construction. A path leads down to a floor partly +covered with rough concrete. The walls and ceiling are high and reinforced with +beams of wood, iron, and steel. In the center of the floor you can see a large, +flat slab of granite. The only exit is behind you to the south. + +You can still hear faint groans and snarls from the larger cave. + +>s +Brick Tunnel +This is an ancient tunnel constructed of roughly mortared bricks and stones. A +slippery and almost invisible set of handholds leads up. The tunnel continues a +long way north and south from here. + +>u +Ancient Storage +What's deader than dead storage? That's what's in this room. Most of the +contents have collapsed or rusted back to the primordial ooze. There is mold +growing on some of the unidentifiable piles. Stagnant puddles of water pollute +the floor. You can now believe how old some of these foundations are said to be. + +In one corner of the room a manhole cover is partly buried in the dirt and crud. + +There is an open manhole here. + +There is a forklift here. + +>verbose +Verbose descriptions. + +Ancient Storage +What's deader than dead storage? That's what's in this room. Most of the +contents have collapsed or rusted back to the primordial ooze. There is mold +growing on some of the unidentifiable piles. Stagnant puddles of water pollute +the floor. You can now believe how old some of these foundations are said to be. + +In one corner of the room a manhole cover is partly buried in the dirt and crud. + +There is an open manhole here. + +There is a forklift here. + +>w +Dead Storage +This is a storage room. It contains an incredible assemblage of discarded junk. +Some of it is so old and mouldering that you can't be sure where one bit of junk +stops and the next begins. It's piled to the ceiling on ancient, rotting +pallets. A narrow path winds eastward through the junk. + +>w +Temporary Basement +During the Second World War, some temporary buildings were built to house war- +related research. Naturally, these buildings, though flimsy and ugly, are still +around. This is the basement of one of them. The basement extends west, a +stairway leads up, and a large passage is to the east. + +>show funny bones to urchin +You can't see any funny bones here. + +>show coke to urchin +You can't see any coke here. + +>ask urchin about parka +There is no reply. + +>save +Okay. + +>ask urchin about parka +There is no reply. + +>show knife to urchin +You see no missing urchins. + +>give coke to urchin +You can't see that here! + +>x urchin +You see no missing urchins. + +>x parka +You can't see any parka here. + +>x bulges +I don't know the word "bulges." + +>u +Temporary Lab +This is a laboratory of some sort. It takes up most of the building on this +level, all the interior walls having been knocked down. (One reason these +temporary buildings are still here is their flexibility: no one cares if they +get more or less destroyed.) A stairway leads down, and a door leads north. + +There is a metal flask here. + +>x flask +This is a large metal flask, about the size of a water cooler bottle. The metal +flask is closed. + +>open flask +You open the flask, and a cold, white mist boils out. + +>close flask +You screw the flask closed. + +>take flask +Taken. + +The mist dissipates. + +>n +You enter the freezing, biting cold of the blizzard. + +Smith Street +Smith Street runs west towards the computer center here. To the south is a +dilapidated grey wooden building. The street is an impassable sea of blowing and +drifting snow. + +>w +Smith Street +Smith Street runs east and west along the north side of the main campus area. At +the moment, it is an arctic wasteland of howling wind and drifting snow. On the +other side of the street, barely visible, are the lidless eyes of streetlights. +The street hasn't been plowed, or if it has been, it did no good. + +Bitter, bone-cracking cold assaults you continuously. The temperature and the +blizzard conditions are both horrible. + +>w +Impenetrable snow drifts block the street. + +You are getting more and more tired. + +>s +You push your way into the welcoming warmth inside. + +Computer Center +This is the lobby of the Computer Center. An elevator and call buttons are to +the south. Stairs also lead up and down, for the energetic. To the north is +Smith Street. + +>d +Basement +Bare concrete walls line a wide corridor leading east and west. An elevator and +call button are to the south. Stairs also lead up, for the energetic. From floor +to ceiling run wire channels and steam pipes. + +>turn off flashlight +The flashlight clicks off. + +>drink coke +You can't see any coke here. + +>i +You are carrying a metal flask, a smooth stone, a knife, a crowbar, a flashlight +and an assignment. You are wearing a pair of electrician's gloves. + +>d +You can't go that way. + +>w +Aero Basement +This basement level room is made of smooth, damp-seeming concrete. Fluorescent +lights cast harsh shadows. To the west is a stairway, and to the east the +basement area continues. + +>w +Stairway +A dimly lit stairway leads up and down from here. A corridor continues east. + +>d +Subbasement +This is the subbasement of the Aeronautical Engineering Building. A stairway +leads up. A narrow crack in the northwest corner of the room opens into a larger +space. + +>x crack +You used the word "crack" in a way that I don't understand. + +>nw +It's too tight a fit carrying the metal flask. + +>drop flask +Dropped. + +>nw +Tomb +This is a tiny, narrow, ill-fitting room. It appears to have been a left over +space from the joining of two preexisting buildings. It is roughly coffin +shaped. The walls are covered by decades of overlaid graffiti, but there is one +which is painted in huge fluorescent letters that were apparently impossible for +later artists to completely deface. On the floor is a rusty access hatch locked +with a huge padlock. + +>read letters +It reads "The Tomb of the Unknown Tool." + +>unlock padlock with key +You aren't holding the master key. + +>open hatch +The padlock locks the hatch in place. + +>turn on flashlight +The flashlight clicks on. + +>d +The hatch is closed. + +>save +Okay. + +>yes +That was a rhetorical question. + +>am I good or what? +I don't know the word "good." + +>e +You can't go that way. + +>x valve +You can't see any valve here. + +>open valve +You can't see any valve here. + +>open valve with crowbar +You can't see any valve here. + +>again +You can't see any valve here. + +>take dead rat +You can't see any dead rat here. + +>close valve with crowbar +You can't see any valve here. + +>x rat +There are no rats here. + +You are worn out. + +>x symbol +The symbol, on close examination, appears to have been carved into the smooth +stone, perhaps with a claw. The symbol seems just as odd as before. + +>compare scarred symbol to carved symbol +I don't know the word "scarred." + +>compare rat to stone +There are no rats here. + +>compare symbol to symbol +Allowing for the different media in which the symbols are executed, they are +identical. + +>l +Tomb +This is a tiny, narrow, ill-fitting room. It appears to have been a left over +space from the joining of two preexisting buildings. It is roughly coffin +shaped. The walls are covered by decades of overlaid graffiti, but there is one +which is painted in huge fluorescent letters that were apparently impossible for +later artists to completely deface. On the floor is a rusty access hatch locked +with a huge padlock. + +>x cable +You can't see any cable here. + +>e +You can't go that way. + +>x mud +I don't know the word "mud." + +>e +You can't go that way. + +>x south wall +It looks like a wall. + +>break wall with crowbar +You can't pull down a wall that easily. + +>g +You can't pull down a wall that easily. + +>pry brick with crowbar +You can't see any brick here. + +>x brick +You can't see any brick here. + +>new +There was no verb in that sentence! + +>x broken brick +You can't see any broken brick here. + +>get all +I don't see what you're referring to. + +>press new brick +You can't see any new brick here. + +>pry new brick with crowbar +You can't see any new brick here. + +>x rod +You can't see any rod here. + +>look through hole +You can't see any hole here. + +>s +You can't go that way. + +>reach into hole +You can't see any hole here. + +>pull rod +You can't see any rod here. + +>pry rod with crowbar +You can't see any rod here. + +>i +You are carrying a smooth stone, a knife, a crowbar, a flashlight (providing +light) and an assignment. You are wearing a pair of electrician's gloves. + +>get new brick +You can't see any new brick here. + +>u +You can't go that way. + +You are dead tired. + +>shine flashlight in hole +I don't know the word "shine." + +>get cables +I don't know the word "cables." + +>x cables +I don't know the word "cables." + +>x cable +You can't see any cable here. + +>get cable +You can't see any cable here. + +>climb +What do you want to climb? + +>cable +You can't see any cable here. + +>climb pipe +You can't see any pipe here. + +>pour coke on rod +Those things aren't here! + +>i +You are carrying a smooth stone, a knife, a crowbar, a flashlight (providing +light) and an assignment. You are wearing a pair of electrician's gloves. + +>w +You can't go that way. + +>w +You can't go that way. + +>w +You can't go that way. + +>w +You can't go that way. + +>w +You can't go that way. + +>w +You can't go that way. + +>d +The hatch is closed. + +>x slots +You can't see any slots here. + +>unscript +End of transcript. diff --git a/infocom/lurkinghorror/test/lurkinghorror.txt b/infocom/lurkinghorror/test/lurkinghorror.txt new file mode 100644 index 0000000..52e3ee2 --- /dev/null +++ b/infocom/lurkinghorror/test/lurkinghorror.txt @@ -0,0 +1,947 @@ +Start of a transcript of THE LURKING HORROR. +THE LURKING HORROR +An Interactive Horror +Copyright (c) 1987 by Infocom, Inc. All rights reserved. +THE LURKING HORROR is a trademark of Infocom, Inc. +Release 221 / Serial number 870918 +>talk to hacker +Hmmm … the hacker waits for you to say something. +>hacker, hi +"Greetingage." He turns back to his hacking. +>ask hacker about hacking +I don't know the word "hacking." +>examine pc +This is a beyond-state-of-the-art personal computer. It has a 1024 by 1024 pixel color monitor, a mouse, an attached hard disk, and a local area network connection. Fortunately, one of its features is a prominent HELP key. It is currently turned off. +>turn on pc +The computer powers up, goes through a remarkably fast self-check, and greets you, requesting "LOGIN PLEASE:". The only sound you hear is a very low hum. +>login +What do you want to login? +>log in to computer +I don't know the word "log." +>type username +The computer responds "PASSWORD PLEASE:" +>type password +What do you want to type passwo? +>ask hacker about password +There seems to be a noun missing in that sentence. +>type 872325412 +The computer responds "INVALID LOGIN" and then "LOGIN PLEASE:". +>type 872325412 +The computer responds "PASSWORD PLEASE:" +>type uhlersoth +The computer responds "Good evening. You're here awfully late." It displays a list of pending tasks, one of which is in blinking red letters, with large arrows pointing to it. The task reads "Classics Paper," some particularly ominous words next to it say "DUE TOMORROW!" and more reassuringly, a menu box next to that reads "Edit Classics Paper." +>edit classics paper +The menu box is replaced by the YAK text editor and menu boxes listing the titles of your files. The one for your paper is highlighted in a rather urgent-looking shade of red. +>press help key +You push the friendly-looking HELP key. A spritely little box appears on the screen, which reads: "Please click the box representing the file you wish to edit or view. I notice that one file is marked as urgent, so you should probably click its box." +>click urgent box +You click the box for your paper, and the box grows reassuringly until it fills most of the screen. Unfortunately, the text that fills it bears no resemblance to your paper. The title is the same, but after that, there is something different, very different. +>read paper +The paper appears to be a facsimile overlaid with occasional typescript. The text is mostly in a sort of "Olde English" you've never seen before. What you read is a combination of incomprehensible gibberish, latinate pseudowords, debased Hebrew and Arabic scripts, and an occasional disquieting phrase in English. +As you look at it more closely, you find it hard to focus on the screen, but impossible to look away. Your finger strays toward the "MORE" box… +>save +Okay. +>press more +You touch the MORE box, and a new page appears. +The second page is much like the first, but around the edges, not when you look at it straight, it's almost readable. There is something about a "summoning," or a "visitor." +>summon visitor +I don't know the word "summon." +>press more +You touch the MORE box, and a new page appears. +The third page is in the same script as the first, but laid out like a poem. There are woodcut illustrations which are queasily disturbing. +There is a translation, or notes for one, typed between the lines of the poem: +"He returns, he is called back (?) +The loyal ones (acolytes?) make a sacrifice +Those who survive will meet him (be absorbed? eaten?) +They will live, yet die +Forever will be (is?) nothing to them (to him?) +"His place (lair? burrow?) must be prepared +His food (offerings?) must be prepared +Call him forth (invite him?) with great power +Only an acceptable (tasteful?) sacrifice will call him forth +He will be grateful (satiated?)" +The rest is even more fragmentary. +>press more +You touch the MORE box, and a new page appears. +The fourth page is a photograph. You try to recoil from the screen, but cannot. Fascinated and repelled at the same time, you wonder: is that a mouth, and what is in it? +>examine photograph +I don't know the word "photograph." +>x photo +I don't know the word "photo." +>x page +Instead, you find your finger moving towards the MORE box, and you touch it. The screen feels oddly cold. +You faint, and when you awaken… +[Use $SOUND to toggle sound usage on and off.] +Place +This is a place. Things move about on a broken, rocky surface. Harsh sounds split the air. Something sticky grabs at your feet. There is no color, everything is drained of brightness, dull and lifeless. A path descends into a shallow bowl of black basalt. +>d +Basalt Bowl +You are at the bottom of a deeply cut, smooth basalt bowl. Dimly seen shapes crowd you on all sides. Ahead, in the focus of the movement, is a rock platform. +>forward +I don't know the word "forward." +>x shapes +I don't know the word "shapes." +>x platform +The platform is made of the same rocks as the surrounding terrain. In fact, you can't tell whether it is natural or constructed. +The crowd around you begins to sway and groan. They are expecting something. You are drawn forward by the noise. +At Platform +You stand before a low rock platform, more like an afterthought of piled rocks or a glacial moraine than a work of artifice. You are pushed against the pile by the crowd around you. +One small stone stands out in the pile, smooth, shiny, and glowing with a blazing light. +>x stone +It's a smooth, shiny piece of what might be obsidian. Scratched on it is a symbol. +>x symbol +The symbol, on close examination, appears to have been carved into the smooth stone, perhaps with a claw. The symbol is like nothing you've ever seen, and yet somehow you know it has meaning. +>take stone +Taken. +Suddenly, the dimness becomes darkness, and the crowd around you explodes with excitement. You are jostled and shoved from all sides. A low keening begins, building into a deafening, almost mechanical chant. The darkness before you compacts and deepens. +>eat stone +The food here is terrible, but this is ridiculous! +The darkness before you, now visible, is a creature. It towers over the now-silent crowd. The thing jerks this way and that, spraying a foul ichor. Its palps twitch expectantly, then pound impatiently against the rock. You can feel the smooth stone vibrating in your hand. +>show stone to creature +The thing is uninterested. +The thing now turns, sensing the presence of the stone. It quests almost blindly for it, then those surrounding you thrust you forward. The thing stoops, its mandibles grasping you. You are lifted towards its gaping maw. The stench and the sounds issuing from it are overwhelming, and you fall unconscious. +You are awakened by the thump of your head hitting the terminal in front of you. Falling asleep over term papers! It must have been a nightmare. Embarrassed, you glance around. Yes, the hacker is looking in your direction. He must have heard the thump. +Terminal Room, on the chair +A really whiz-bang pc is right inside the door. +Sitting at a terminal is a hacker whom you recognize. +>i +You are carrying a smooth stone and an assignment. +The hacker wanders over, trying to look nonchalant as he takes over your chair. "Losing, huh?" he asks wittily. He glances at your terminal, which displays a pattern of snow and unusual characters. He appears somewhat excited. +>x terminal +This is a beyond-state-of-the-art personal computer. It has a 1024 by 1024 pixel color monitor, a mouse, an attached hard disk, and a local area network connection. Fortunately, one of its features is a prominent HELP key. On the screen you see a menu box. +The hacker, mumbling under his breath, begins a flurry of activity. First the screen returns to something nearly normal, then windows begin popping up like toadstools after a rain. The screen looks a lot like the top of his terminal table (or the bottom of a trash can). +>read assignment +Laser printed on creamy bond paper, the assignment is due tomorrow. It's from your freshman course in "The Classics in the Modern Idiom," better known as "21.014." It reads, in part: "Twenty pages on modern analogues of Xenophon's 'Anabasis.'" You're not sure whether this refers to the movie "The Warriors" or "Alien," but this is the last assignment you need to complete in this course this term. You wonder, yet again, why a technical school requires you to endure this sort of stuff. +The hacker types furiously, and the screen displays what to you looks like an explosion in a teletype factory. After a while he says. "Chomping file system. Your directory has gone seriously west. I fixed it." He checks the screen. "It was mixed up on the file server with some files from the Department of Alchemy." He grunts. "People's names for their nodes are getting weird. This one is called 'Lovecraft.'" He pauses. "Your paper is gone, though. Sorry. Maybe they could help you down there." +>cry +I don't know the word "cry." +>x hacker +The hacker is sitting at your terminal, typing furiously. Every so often, he pauses briefly and twirls a lock of his hair. He is also humming under his breath. The hacker is dressed in blue jeans, an old work shirt, and what might once have been running shoes. Hanging from his belt is an enormous ring of keys. He is in need of a bath. +The hacker wanders back to his terminal and returns to his hacking. +>show stone to hacker +"Odd-looking thing. Are you a rock-jock?" +>take keys +"Hey! No snarfage, loser!" You determine that this means, "Stop!" +>ask hacker about keys +"I've accumulated a few keys over the years. I'm a licensed locksmith, which helps. I can get into any room at Tech." He pulls the keyring out on its chain, and shows off a key you hadn't noticed before. "This is a master key," he says. +>ask hacker for master key +"Fat chance! This is a master key! What have you done for me lately?" +>save +Okay. +>punch hacker +I don't know the word "punch." +>ask hacker about department of alchemy +You can't see any department of alchemy here. +The hacker turns to you and says, "I don't know where I can get something to eat, what with all the snow." +>feed hacker +(to the hacker) +You aren't holding the hacker. +>feed assignment to hacker +"No thanks, keep it for now." +>l +Terminal Room +This is a large room crammed with computer terminals, small computers, and printers. An exit leads south. Banners, posters, and signs festoon the walls. Most of the tables are covered with waste paper, old pizza boxes, and empty Coke cans. There are usually a lot of people here, but tonight it's almost deserted. +Nearby is one of those ugly molded plastic chairs. +A really whiz-bang pc is right inside the door. +Sitting at a terminal is a hacker whom you recognize. +The hacker turns to you and says, "I'd hate to leave, with the machines so empty. On the other hand, I'm seriously starving." +> +I beg your pardon? +>x pizza boxes +I don't know the word "pizza." +>read banners +How do you do that with a banners? +>s +Second Floor +This is the second floor of the Computer Center. An elevator and call buttons are on the south side of the hallway. A large, noisy room is to the north. Stairs also lead up and down, for the energetic. To the west a corridor leads into a smaller room. +>w +Kitchen +This is a filthy kitchen. The exit is to the east. On the wall near a counter are a refrigerator and a microwave. +Sitting on the kitchen counter is a package of Funny Bones. +>x funny bones +This is a package of Funny Bones, a snack food made with peanut butter and chocolate cake. +>take funny bones +Taken. +>open fridge +Opening the refrigerator reveals a two liter bottle of Classic Coke and a cardboard carton. +>take all +two liter bottle of Classic Coke: Taken. +cardboard carton: Taken. +>x carton +This is a cardboard carton with an incomprehensible symbol scrawled on the top. +>x symbol +It doesn't look like Chinese, English, or any other language you know. The symbol looks oddly familiar. +>open it +Opening the cardboard carton reveals Chinese food. +>put carton in microwave +Inspection reveals that the microwave oven isn't open. +>open microwave +The microwave oven is now open. +>put carton in microwave +Done. +>close fridge +Closed. +>close microwave +Okay, the microwave oven is now closed. +>x microwave +The microwave oven hangs over the kitchen counter. It has more complicated controls than your pc. There is an LED readout above the controls. The microwave is off and it's closed. +>x led readout +The display is currently displaying the current time and the word "off." +>x controls +There are controls labelled 0 to 9, WM, LO, MED, HI, START, CLEAR, and STOP. The timer display now reads 0:00. +>save +Okay. +>press hi +The bottom of the display now reads "high." +>press start +Nothing happens, as there's no time set on it yet. +>press 1 +The timer display now reads 0:01. +>press 0 +The timer display now reads 0:10. +>press 0 +The timer display now reads 1:00. +>press start +The microwave starts up. The timer begins counting down. +The microwave stops. The timer display now reads 0:00. +>open microwave +The microwave oven is now open. +>x carton +This is a cardboard carton with an incomprehensible symbol scrawled on the top. +>touch carton +Fiddling with the cardboard carton has no effect. +>open carton +The cardboard carton is already open. +>x chinese food +This is a carton of cold Szechuan shrimp. Lovely red peppers poke out of the sauce. +>close microwave +Okay, the microwave oven is now closed. +>press hi +The bottom of the display now reads "high." +>press 3 +The timer display now reads 0:03. +>press 0 +The timer display now reads 0:30. +>press 0 +The timer display now reads 3:00. +>press start +The microwave starts up. The timer begins counting down. +The timer display now reads 2:00. +>wait +Time passes… +The timer display now reads 1:00. +>wait +Time passes… +The microwave stops. The timer display now reads 0:00. +>open microwave +The microwave oven is now open. +>x food +Which food do you mean, the Chinese food or the package of Funny Bones? +>x chinese food +This is a carton of hot Szechuan shrimp. Lovely red peppers poke out of the sauce. +>take carton +Taken. +>l +Kitchen +This is a filthy kitchen. The exit is to the east. On the wall near a counter are a refrigerator and a microwave. +>e +Second Floor +>n +Terminal Room +Nearby is one of those ugly molded plastic chairs. +A really whiz-bang pc is right inside the door. +Sitting at a terminal is a hacker whom you recognize. +>give chinese food to hacker +"Yuck! This isn't warm enough!" He thrusts it back into your hands. +>x chinese food +This is a carton of warm Szechuan shrimp. Lovely red peppers poke out of the sauce. +>s +Second Floor +>e +You can't go that way. +>w +Kitchen +>open microwave +The microwave oven is already open. +>put carton in microwave +Done. +>close microwave +Okay, the microwave oven is now closed. +>press hi +The bottom of the display now reads "high." +>press 5 +The timer display now reads 0:05. +>press 0 +The timer display now reads 0:50. +>press 0 +The timer display now reads 5:00. +>press start +The microwave starts up. The timer begins counting down. +The timer display now reads 4:00. +>wait +Time passes… +The timer display now reads 3:00. +>wait +Time passes… +The timer display now reads 2:00. +>wait +Time passes… +The timer display now reads 1:00. +>wait +Time passes… +The microwave stops. The timer display now reads 0:00. +>open microwave +The microwave oven is now open. +>take container +You can't see any container here. +>take carton +Taken. +>close carton +Closed. +>e +Second Floor +>n +Terminal Room +Nearby is one of those ugly molded plastic chairs. +A really whiz-bang pc is right inside the door. +Sitting at a terminal is a hacker whom you recognize. +>give carton to hacker +"Ouch! This is ridiculous! You've overcooked it. Look at those poor shrimp! It's ruined, chomper!" He throws it away. +>reload +I don't know the word "reload." +>restore +Okay. +>l +Kitchen +This is a filthy kitchen. The exit is to the east. On the wall near a counter are a refrigerator and a microwave. +The microwave oven contains a cardboard carton. The cardboard carton contains Chinese food. +>close oven +It's already closed. +>open oven +The microwave oven is now open. +>close carton +Closed. +>close oven +Okay, the microwave oven is now closed. +>press hi +The bottom of the display now reads "high." +>press 4:00 +Why don't you try setting the timer to that? +>set timer to 4:20 +The timer display now reads 4:20. +>press start +The microwave starts up. The timer begins counting down. +The timer display now reads 3:20. +>wait +Time passes… +The timer display now reads 2:20. +>w +You can't go that way. +The timer display now reads 1:20. +>wait +Time passes… +The timer display now reads 0:20. +>wait +Time passes… +The microwave stops. The timer display now reads 0:00. +>open microwave +The microwave oven is now open. +>take container +You can't see any container here. +>take carton +Taken. +>e +Second Floor +>n +Terminal Room +Nearby is one of those ugly molded plastic chairs. +A really whiz-bang pc is right inside the door. +Sitting at a terminal is a hacker whom you recognize. +>give carton to hacker +"Ah! Serious food!" He plunges into the food with all the delicacy and table manners of a shark at a feeding frenzy. Soon a satisfied expression appears on his face. "Now, what was it you were wanting?" he asks. +>ask hacker for master key +"Well, I suppose I could loan you the master key for a while. Just don't get into trouble, okay? I'll find you later, when I'm done with all this, and get it back." He hands you the key. +>i +You are carrying a master key, a two liter bottle of Classic Coke, a package of Funny Bones, a smooth stone and an assignment. +>take all +chair: Taken. +pc: Your load is too heavy. +>drop chair +Dropped. +>take pc +You take it, turning it off and unplugging it first. +>drop pc +Dropped. +>take chair +Taken. +>l +Terminal Room +This is a large room crammed with computer terminals, small computers, and printers. An exit leads south. Banners, posters, and signs festoon the walls. Most of the tables are covered with waste paper, old pizza boxes, and empty Coke cans. There are usually a lot of people here, but tonight it's almost deserted. +Sitting at a terminal is a hacker whom you recognize. +There is a pc here. +>verbose +Verbose descriptions. +Terminal Room +This is a large room crammed with computer terminals, small computers, and printers. An exit leads south. Banners, posters, and signs festoon the walls. Most of the tables are covered with waste paper, old pizza boxes, and empty Coke cans. There are usually a lot of people here, but tonight it's almost deserted. +Sitting at a terminal is a hacker whom you recognize. +There is a pc here. +>i +You are carrying a chair, a master key, a two liter bottle of Classic Coke, a package of Funny Bones, a smooth stone and an assignment. +>s +The hacker prevents you. "You can't walk off with that! It's Tech property!" +>drop chair +Dropped. +>s +Second Floor +This is the second floor of the Computer Center. An elevator and call buttons are on the south side of the hallway. A large, noisy room is to the north. Stairs also lead up and down, for the energetic. To the west a corridor leads into a smaller room. +>hello +Cheery, aren't you? +>push call button +Which call button do you mean, the up-arrow or the down-arrow? +>push up +The up-arrow begins to glow. +You hear the elevator begin moving. +>cool +I don't know the word "cool." +>;cool +I don't know the word ";cool." +>say "cool" +Talking to yourself is a sign of impending mental collapse. +The up-arrow blinks off. +>wait +Time passes… +The elevator doors slide open. +>s +Elevator +This is a battered, rather dirty elevator. The fake wood walls are scratched and marred with graffiti. The elevator doors are open. To the right of the doors is an area with floor buttons (B and 1 through 3), an open button, a close button, a stop switch, and an alarm button. Below these is an access panel which is closed. +>open panel +Opening the access panel reveals a flashlight. +The elevator doors slide closed. +>take flashlight +Taken. +>push 3 +The button for the third floor begins to glow. +>wait +Time passes… +The elevator begins to move upward. +>x me +You are wide awake, and are in good health. +The elevator slows and comes to a stop. The button for the third floor blinks off. +>wait +Time passes… +The elevator doors slide open. +>n +Third Floor +This is the third floor of the Computer Center. An elevator and call button are on the south side of the hallway. Stairs also lead down, for the energetic. To the north is a glass wall beyond which you can see a computer room crammed with computer equipment. A stairway leads up. +The elevator doors are open. +>n +There is a glass wall in the way. +The elevator doors slide closed. +>look through glass +You see nothing special about it. +>x equipment +You see nothing special about it. +>u +You push through the door to the roof. You enter the freezing, biting cold of the blizzard. +Roof +This is the roof of the Computer Center. A door leads to the stairway. The roof is covered with tarred pea gravel and drifted snow. The wind howls around your ears. To the south and southeast you can dimly see the looming shapes of the Great Dome and the Brown Building. +>x brown building +I don't know the word "brown." +>take snow +That would never work! +Bitter, bone-cracking cold assaults you continuously. The temperature and the blizzard conditions are both horrible. +>d +You push your way into the welcoming warmth inside. +Third Floor +This is the third floor of the Computer Center. An elevator and call button are on the south side of the hallway. Stairs also lead down, for the energetic. To the north is a glass wall beyond which you can see a computer room crammed with computer equipment. A stairway leads up. +>d +Second Floor +This is the second floor of the Computer Center. An elevator and call buttons are on the south side of the hallway. A large, noisy room is to the north. Stairs also lead up and down, for the energetic. To the west a corridor leads into a smaller room. +>d +Computer Center +This is the lobby of the Computer Center. An elevator and call buttons are to the south. Stairs also lead up and down, for the energetic. To the north is Smith Street. +>d +Basement +Bare concrete walls line a wide corridor leading east and west. An elevator and call button are to the south. Stairs also lead up, for the energetic. From floor to ceiling run wire channels and steam pipes. +>x pipes +You see nothing special about the steam pipes. +>x channels +From floor to ceiling run wire channels and steam pipes. +>w +Aero Basement +This basement level room is made of smooth, damp-seeming concrete. Fluorescent lights cast harsh shadows. To the west is a stairway, and to the east the basement area continues. +Slouching nearby is an urchin. He's a youngish teenager wearing a ski hat, running shoes, and a bulky, suspiciously bumpy, threadbare parka. He's jumpy, and looks suspiciously at you. +There is a forklift here. +>show stone to urchin +He makes an unconvincing show of disinterest. +>ask urchin about stone +He doesn't reply. He seems very nervous about talking to you. +The urchin looks around nervously, obviously thinking of flight, but decides against it. +>x urchin +This is an urchin. He's a youngish teenager wearing a ski hat, running shoes, and a bulky, suspiciously bumpy, threadbare parka. He's jumpy, and looks suspiciously at you. +>save +Okay. +>take parka +"Hey! Keep off, sucker! You can't scare me!" +>scare him +How do you propose to do that? +>boo urchin +I don't know the word "boo." +>say "BOO" +You must address the urchin directly. +>urchin, boo +I don't know the word "boo." +>x forklift +This is a rusty old forklift. It looks like you could control it fairly easily, though. +>get on forklift +You are now in the forklift. +>operate forklift +I don't know the word "operate." +>turn on forklift +The forklift sputters to life. +>use forklift on urchin +I don't know the word "use." +>life urchin +There was no verb in that sentence! +>lift urchin +You can't reach the urchin from within the forklift. +>w +The forklift won't fit into the stairwell. +>e +Basement, on the forklift +Bare concrete walls line a wide corridor leading east and west. An elevator and call button are to the south. Stairs also lead up, for the energetic. From floor to ceiling run wire channels and steam pipes. +The urchin saunters nonchalantly into the room, notices you, and beats a hasty retreat. +>e +Temporary Basement, on the forklift +During the Second World War, some temporary buildings were built to house war-related research. Naturally, these buildings, though flimsy and ugly, are still around. This is the basement of one of them. The basement extends west, a stairway leads up, and a large passage is to the east. +There is a pair of electrician's gloves and a crowbar here. +>take all +pair of electrician's gloves: You can't reach the pair of electrician's gloves from within the forklift. +crowbar: You can't reach the crowbar from within the forklift. +>exit forklift +You are now on your feet. +>take all +pair of electrician's gloves: Taken. +crowbar: Taken. +>x gloves +This is a pair of electrician's rubber gloves. They look well used but serviceable. +>x crowbar +You see nothing special about the crowbar. +>put on gloves +You put on the gloves. They're a little big, but not really such a bad fit at all. +>turn off forklift +You'll have to get in it first. +>get on forklift +You are now in the forklift. +>turn off forklift +The forklift coughs once, and dies. +>get of forklift +You used the word "of" in a way that I don't understand. +>get off forklift +You are now on your feet. +>e +It is pitch black. +>turn on flashlight +The flashlight clicks on. +Dead Storage +This is a storage room. It contains an incredible assemblage of discarded junk. Some of it is so old and mouldering that you can't be sure where one bit of junk stops and the next begins. It's piled to the ceiling on ancient, rotting pallets; you can't even see the east wall. +>x pallets +Looking more closely only emphasizes how completely entropy has taken over this room. +>search junk +You find many worthless items of hardware, old discarded memos and papers, but nothing of any use or value. +>w +Temporary Basement +During the Second World War, some temporary buildings were built to house war-related research. Naturally, these buildings, though flimsy and ugly, are still around. This is the basement of one of them. The basement extends west, a stairway leads up, and a large passage is to the east. +There is a forklift here. +>get on forklift +You are now in the forklift. +>turn on forklift +The forklift sputters to life. +>e +Dead Storage, on the forklift +This is a storage room. It contains an incredible assemblage of discarded junk. Some of it is so old and mouldering that you can't be sure where one bit of junk stops and the next begins. It's piled to the ceiling on ancient, rotting pallets; you can't even see the east wall. +>move pallets +You have a little trouble using the forklift, but it's not really all that hard. You start clearing junk, moving it around and trying to create a passage. +>g +You continue moving junk, becoming more proficient with the forklift. +>g +You continue moving junk, becoming more proficient with the forklift. +>g +You've built a fairly narrow (about one forklift wide) path through the junk. You can see an opening into a further storage room beyond this one. +>e +Ancient Storage, on the forklift +What's deader than dead storage? That's what's in this room. Most of the contents have collapsed or rusted back to the primordial ooze. There is mold growing on some of the unidentifiable piles. Stagnant puddles of water pollute the floor. You can now believe how old some of these foundations are said to be. +There is a closed, disused-looking manhole here. +>turn off forklift +The forklift coughs once, and dies. +>get off forklift +You are now on your feet. +>x manhole +It's a steel ring set in the floor. It's probably a manhole. +>open manhole +The only way would seem to be to remove the manhole cover. +>remove cover with crowbar +You lever the manhole cover aside, and crusted dirt falls into a dark, partly obstructed hole below. +>save +Okay. +>x hole +It's a manhole. It's very dark inside, but you can see that crude brick handholds provide a slippery path down. Cool air rises out of the hole. +>d +You push your way through cobwebs, damp fungus, and other obstructions. +Brick Tunnel +This is an ancient tunnel constructed of roughly mortared bricks and stones. A slippery and almost invisible set of handholds leads up. The tunnel continues a long way north and south from here. +>s +You make your way along the long tunnel. +Cinderblock Tunnel +This is a tunnel whose walls are cinderblock, with a concrete floor and ceiling. A metal ladder leads up to a closed metal plate in the ceiling, and the tunnel continues north, where the cinderblock walls become brick. +>u +The trapdoor isn't open. +>open trapdoor +It lifts a few inches, but then hits something and goes no further. +>look through trapdoor +Pushing the plate up as far as you can, you can see part of a workroom or lab of some kind. +>open trapdoor with crowbar +It lifts a few inches, but then hits something and goes no further. +>i +You are carrying a crowbar, a flashlight (providing light), a master key, a two liter bottle of Classic Coke, a package of Funny Bones, a smooth stone and an assignment. You are wearing a pair of electrician's gloves. +>n +You make your way along the long tunnel. +Brick Tunnel +This is an ancient tunnel constructed of roughly mortared bricks and stones. A slippery and almost invisible set of handholds leads up. The tunnel continues a long way north and south from here. +>n +You make your way along the long tunnel. +Renovated Cave +You are in a huge, cave-like construction. A path leads down to a floor partly covered with rough concrete. The walls and ceiling are high and reinforced with beams of wood, iron, and steel. In the center of the floor you can see a large, flat slab of granite. The only exit is behind you to the south. +>x slab +The slab is roughly circular, made of indifferently dressed New England granite, and about three feet high. +>open slab +How do you do that with a slab of granite? +>lay on slab +You aren't holding the slab of granite. +>stand on slab +That would be a waste of time. +>d +Before the Altar +You are at the bottom of the cave. The huge slab of granite in the center is a sort of altar. It is carved with strange and disturbing symbols, the largest of which looks very familiar. Some of the symbols are obscured by rusty red stains. Nearby is an iron plate set in the concrete of the floor. +Lying to one side of the altar stone is a sharp, thin-bladed knife. +>x knife +This small knife is clean, sharp, and has a long, thin blade and a wooden handle. Only the tip of the blade appears at all dull or used. +>take knife +Taken. +>x tip +I don't know the word "tip." +>x symbols +Which symbols do you mean, the incised symbol or the carved symbol? +>incised +The symbol appears to be the oldest thing carved on the altar. It is beautifully incised in the rocks. Its age is apparent from its wear and the overlay of newer carvings and scratchings over it. The symbol looks oddly familiar. +>put stone on altar +Done. +>x carved symbol +The symbol, on close examination, appears to have been carved into the smooth stone, perhaps with a claw. The symbol seems just as odd as before. +>x grate +I don't know the word "grate." +>x plate +The plate is iron, about two feet square, and looks like it could be slid open. A curious feature of the plate is that it has upward projecting dents in it which appear to have been punched from below. +>save +Okay. +>take stone +Taken. +>open plate +You slide open the panel, revealing a dark pit below. Immediately, there is a response from below. +A low, guttural, groaning and snarling issues from the opening. +>x hole +The plate is iron, about two feet square, and open. A curious feature of the plate is that it has upward projecting dents in it which appear to have been punched from below. +A low, guttural, groaning and snarling issues from the opening. +>look down hole +You see nothing special about the iron plate. +A low, guttural, groaning and snarling issues from the opening. +>d +You can't go that way. +A low, guttural, groaning and snarling issues from the opening. +>enter hole +You hit your head against the iron plate as you attempt this feat. +A low, guttural, groaning and snarling issues from the opening. +>drop funny bones in hole +Sounds of ghoulish excitement issue from the opening. +A low, guttural, groaning and snarling issues from the opening. +>i +You are carrying a smooth stone, a knife, a crowbar, a flashlight (providing light), a master key, a two liter bottle of Classic Coke and an assignment. You are wearing a pair of electrician's gloves. +A low, guttural, groaning and snarling issues from the opening. +>undo +I don't know the word "undo." +>restore +Okay. +>look in hole +The iron plate is closed. +>take stone +Taken. +>trace symbol +I don't know the word "trace." +>compare symbols +You can only compare two things. +>compare carved and incised +Allowing for the different media in which the symbols are executed, they are identical. +>l +Before the Altar +You are at the bottom of the cave. The huge slab of granite in the center is a sort of altar. It is carved with strange and disturbing symbols, the largest of which looks very familiar. Some of the symbols are obscured by rusty red stains. Nearby is an iron plate set in the concrete of the floor. +>x stains +I don't know the word "stains." +>exit +Please use compass directions instead. +>s +You can't go that way. +>up +Renovated Cave +You are in a huge, cave-like construction. A path leads down to a floor partly covered with rough concrete. The walls and ceiling are high and reinforced with beams of wood, iron, and steel. In the center of the floor you can see a large, flat slab of granite. The only exit is behind you to the south. +>s +Brick Tunnel +This is an ancient tunnel constructed of roughly mortared bricks and stones. A slippery and almost invisible set of handholds leads up. The tunnel continues a long way north and south from here. +>u +Ancient Storage +What's deader than dead storage? That's what's in this room. Most of the contents have collapsed or rusted back to the primordial ooze. There is mold growing on some of the unidentifiable piles. Stagnant puddles of water pollute the floor. You can now believe how old some of these foundations are said to be. +In one corner of the room a manhole cover is partly buried in the dirt and crud. +There is an open manhole here. +There is a forklift here. +>verbose +Verbose descriptions. +Ancient Storage +What's deader than dead storage? That's what's in this room. Most of the contents have collapsed or rusted back to the primordial ooze. There is mold growing on some of the unidentifiable piles. Stagnant puddles of water pollute the floor. You can now believe how old some of these foundations are said to be. +In one corner of the room a manhole cover is partly buried in the dirt and crud. +There is an open manhole here. +There is a forklift here. +>w +Dead Storage +This is a storage room. It contains an incredible assemblage of discarded junk. Some of it is so old and mouldering that you can't be sure where one bit of junk stops and the next begins. It's piled to the ceiling on ancient, rotting pallets. A narrow path winds eastward through the junk. +>w +Temporary Basement +During the Second World War, some temporary buildings were built to house war-related research. Naturally, these buildings, though flimsy and ugly, are still around. This is the basement of one of them. The basement extends west, a stairway leads up, and a large passage is to the east. +Slouching nearby is an urchin. +>show funny bones to urchin +He makes an unconvincing show of disinterest. +>show coke to urchin +He makes an unconvincing show of disinterest. +>ask urchin about parka +He doesn't reply. He seems very nervous about talking to you. +>save +Okay. +>give funny bones to urchin +"My momma said never take nothin' from no stranger." He takes the package of Funny Bones anyway, disposing of it in record time. "On the other hand, I'm hungry," he remarks. +>ask urchin about parka +He doesn't reply. He seems very nervous about talking to you. +>show knife to urchin +He makes an unconvincing show of disinterest. +>give coke to urchin +"My momma said never take nothin' from no stranger." +>x urchin +This is an urchin. He's a youngish teenager wearing a ski hat, running shoes, and a bulky, suspiciously bumpy, threadbare parka. He's jumpy, and looks suspiciously at you. +>x parka +It bulges in odd places. +The urchin looks around nervously, obviously thinking of flight, but decides against it. +>x bulges +I don't know the word "bulges." +>u +Temporary Lab +This is a laboratory of some sort. It takes up most of the building on this level, all the interior walls having been knocked down. (One reason these temporary buildings are still here is their flexibility: no one cares if they get more or less destroyed.) A stairway leads down, and a door leads north. +There is a metal flask here. +>x flask +This is a large metal flask, about the size of a water cooler bottle. The metal flask is closed. +>open flask +You open the flask, and a cold, white mist boils out. +>close flask +You screw the flask closed. +>take flask +Taken. +The mist dissipates. +>n +You enter the freezing, biting cold of the blizzard. +Smith Street +Smith Street runs west towards the computer center here. To the south is a dilapidated grey wooden building. The street is an impassable sea of blowing and drifting snow. +>w +Smith Street +Smith Street runs east and west along the north side of the main campus area. At the moment, it is an arctic wasteland of howling wind and drifting snow. On the other side of the street, barely visible, are the lidless eyes of streetlights. The street hasn't been plowed, or if it has been, it did no good. +Bitter, bone-cracking cold assaults you continuously. The temperature and the blizzard conditions are both horrible. +>w +Impenetrable snow drifts block the street. +>s +You push your way into the welcoming warmth inside. +Computer Center +This is the lobby of the Computer Center. An elevator and call buttons are to the south. Stairs also lead up and down, for the energetic. To the north is Smith Street. +>d +Basement +Bare concrete walls line a wide corridor leading east and west. An elevator and call button are to the south. Stairs also lead up, for the energetic. From floor to ceiling run wire channels and steam pipes. +You are beginning to tire. +The urchin saunters nonchalantly into the room, notices you, and beats a hasty retreat. +>turn off flashlight +The flashlight clicks off. +>drink coke +Delicious! Contains caffeine, one of the four basic food groups. Too bad they make it with fructose these days, instead of sucrose. You feel much more alert and awake now. +>i +You are carrying a metal flask, a smooth stone, a knife, a crowbar, a flashlight, a master key, a two liter bottle of Classic Coke and an assignment. You are wearing a pair of electrician's gloves. +>d +You can't go that way. +>w +Aero Basement +This basement level room is made of smooth, damp-seeming concrete. Fluorescent lights cast harsh shadows. To the west is a stairway, and to the east the basement area continues. +>w +Stairway +A dimly lit stairway leads up and down from here. A corridor continues east. +>d +Subbasement +This is the subbasement of the Aeronautical Engineering Building. A stairway leads up. A narrow crack in the northwest corner of the room opens into a larger space. +>x crack +You used the word "crack" in a way that I don't understand. +>nw +It's too tight a fit carrying the metal flask. +>drop flask +Dropped. +>nw +Tomb +This is a tiny, narrow, ill-fitting room. It appears to have been a left over space from the joining of two preexisting buildings. It is roughly coffin shaped. The walls are covered by decades of overlaid graffiti, but there is one which is painted in huge fluorescent letters that were apparently impossible for later artists to completely deface. On the floor is a rusty access hatch locked with a huge padlock. +>read letters +It reads "The Tomb of the Unknown Tool." +>unlock padlock with key +The lock, though rusty and unwilling, opens, releasing the hatch. +>open hatch +The hatch is heavy, and its hinges are rusty, but you pull and strain and it opens with a scream of metal. Revealed below is a rusty ladder leading down. Warm, fetid air coils up out of the hole. There is a burned out (no, smashed) utility light set in the wall a few feet down. +>turn on flashlight +The flashlight clicks on. +>d +Steam Tunnel +This dank and grimy tunnel is largely filled with an imperfectly insulated steam pipe. The tunnel is uncomfortably hot and damp. You have gone from the arctic to the tropics. The concrete tunnel has odd molds and fungi growing on its walls and ceiling, and the floor is squishy. Torn clots of insulation litter the floor. Along the ceiling runs a thick tangle of coaxial cable. The tunnel heads east and west. A rusty metal ladder leads up. +You can hear, in the distance, a chittering, scratching sound. +>save +Okay. +>listen +You hear the chittering of rats. +The sound is louder. It sounds like small animals. Is it rats? +>yes +That was a rhetorical question. +The sound continues. It's almost certainly rats. +>am I good or what? +I don't know the word "good." +>e +Steam Tunnel +This dank and grimy tunnel is largely filled with an imperfectly insulated steam pipe. The tunnel is uncomfortably hot and damp. A thick bundle of coaxial cable runs east to west along the ceiling. There is a pressure release valve on the steam pipe here. +The rat sounds are growing louder, but you still can't see any rats. +>x valve +It looks pretty rusty, but appears to be in working order. It's closed. +The rat sounds are growing louder, but you still can't see any rats. +>open valve +It's too rusty. You pull and strain, but nothing happens. +A troop of rats appears out of the darkness. The rats are momentarily startled by your presence, but soon the bolder ones begin to approach. There are more rats here than you have ever seen. +>open valve with crowbar +The valve, with a horrible scream of tortured metal, gives a little, and a small trickle of steam issues forth. This further agitates the rats. +The rats attack! Slimy, snarling, and hungry, they swarm over your feet, biting at your legs and clinging desperately to your feet. +>again +The valve screeches open. A jet spray of live steam issues from it, filling the tunnel in front of you. The rats are caught in the full force of the blast. Horrible squeals can be heard from the midst of the steam cloud, and scalded rats charge past you, all interest in anything but flight forgotten. One of their number remains, dead. +>take dead rat +As you take the dead rat, it moves, but then you realize that it's only lice and fleas bailing out. +>close valve with crowbar +The valve closes, more easily than it opened. +>x rat +This rat appears to have been stepped on. A small trickle of blood has clotted around its mouth. Branded into its neck is a strange symbol. +>x symbol +The symbol, on close examination, appears to have been scarred into the hide of the rat. There is no hair growing on it, and although it looks like scar tissue, the color is wrong — a sort of purplish green. The symbol looks oddly familiar. +>compare scarred symbol to carved symbol +I don't know the word "scarred." +>compare rat to stone +That would be a waste of time. +>compare symbol to symbol +Allowing for the different media in which the symbols are executed, they are identical. +>l +Steam Tunnel +This dank and grimy tunnel is largely filled with an imperfectly insulated steam pipe. The tunnel is uncomfortably hot and damp. A thick bundle of coaxial cable runs east to west along the ceiling. There is a pressure release valve on the steam pipe here. +>x cable +The cable runs overhead in a fat bundle. It looks like the kind you've seen connecting nodes of the local net. This clump is pretty grotty looking, festooned with damp cobwebs, and stained with something that dripped from the ceiling. +>e +Steam Tunnel +The steam tunnel is narrow here, and its construction is more archaic. It's now mostly brick, although the floor is concrete. The steam pipe and coaxial cable continue along their appointed paths. The tunnel is damp and even a little muddy. +>x mud +I don't know the word "mud." +>e +Steam Tunnel +The steam pipe and coaxial cable turn upwards and disappear into the ceiling here. The tunnel itself comes to an end in a grimy, damp, and dripping triad of crumbling brick walls. The south wall looks particularly decrepit. +>x south wall +The brick wall is in terrible shape. It's aged and crumbling, with grooves between bricks where the mortar has fallen out. +>break wall with crowbar +It doesn't do much but loosen a brick in the wall. +>g +It doesn't do much but loosen a brick in the wall. +>pry brick with crowbar +The wall grudgingly yields to your efforts. A brick, less well mortared than its fellows, pulls out of the wall. +>x brick +Which brick do you mean, the broken brick or the new brick? +>new +It's a new brick. It appears to be of relatively recent vintage. +>x broken brick +It's a crumbling, broken brick. Little bits of mortar still cling to it. +>get all +broken brick: Taken. +new brick: You can't get a good grip on the new brick with your fingers. +>press new brick +Pushing the new brick has no effect. +>pry new brick with crowbar +The wall grudgingly yields to your efforts. A brick, less well mortared than its fellows, drops to the floor on the other side, making a hole through the wall. You can see a rusty steel reinforcing rod in the hole. +>x rod +It's rusty, obviously didn't help the wall all that much, and runs up and down through the hole you have made. +>look through hole +There is an open space, a small room containing some machinery. You can't see too well, though. +>s +You are trying to walk through a brick wall. +>reach into hole +You reach in and touch the reinforcing rod. +>pull rod +It's pretty solidly mortared in. +>pry rod with crowbar +It's pretty solidly mortared in. +>i +You are carrying a broken brick, a dead rat, a smooth stone, a knife, a crowbar, a flashlight (providing light), a master key, a two liter bottle of Classic Coke and an assignment. You are wearing a pair of electrician's gloves. +>get new brick +You can't see any new brick here. +>u +You can't go that way. +>shine flashlight in hole +I don't know the word "shine." +>get cables +I don't know the word "cables." +>x cables +I don't know the word "cables." +>x cable +The cable runs overhead in a fat bundle. It looks like the kind you've seen connecting nodes of the local net. This clump is pretty grotty looking, festooned with damp cobwebs, and stained with something that dripped from the ceiling. +>get cable +You can't take that! +>climb +What do you want to climb? +>cable +You leap, grab the damp and moldy bundle of cable, and hang suspended off the floor. +>climb pipe +That would be a waste of time. +Your grip on the cable, never too secure, loosens, and you drop to the floor. +>pour coke on rod +You pour the Coke on the reinforcing rod, wasting it. +>i +You are carrying a broken brick, a dead rat, a smooth stone, a knife, a crowbar, a flashlight (providing light), a master key, a two liter bottle of Classic Coke and an assignment. You are wearing a pair of electrician's gloves. +>w +Steam Tunnel +The steam tunnel is narrow here, and its construction is more archaic. It's now mostly brick, although the floor is concrete. The steam pipe and coaxial cable continue along their appointed paths. The tunnel is damp and even a little muddy. +>w +Steam Tunnel +This dank and grimy tunnel is largely filled with an imperfectly insulated steam pipe. The tunnel is uncomfortably hot and damp. A thick bundle of coaxial cable runs east to west along the ceiling. There is a pressure release valve on the steam pipe here. +>w +Steam Tunnel +This dank and grimy tunnel is largely filled with an imperfectly insulated steam pipe. The tunnel is uncomfortably hot and damp. You have gone from the arctic to the tropics. The concrete tunnel has odd molds and fungi growing on its walls and ceiling, and the floor is squishy. Torn clots of insulation litter the floor. Along the ceiling runs a thick tangle of coaxial cable. The tunnel heads east and west. A rusty metal ladder leads up. +>w +Steam Tunnel +This dank and grimy tunnel is largely filled with an imperfectly insulated steam pipe. The tunnel is uncomfortably hot and damp. A bundle of coaxial cable runs along the ceiling, festooned with damp mold and cobwebs. The tunnel continues west. +>w +Tunnel Entrance +The tunnel continues west from here, becoming narrow, muddy, and forbidding. The walls no longer seem to be as finished as they were. The steam pipe and coaxial cable disappear into the ceiling at this point. The temperature has dropped considerably, as well. +>w +Muddy Tunnel +The tunnel you came through continues down, barely large enough to enter. It is made of sticky gelatinous mud that's been pushed by something into a semblance of a passage. +>d +Large Chamber +This is a wide spot in the tunnel, just as wet and muddy as elsewhere. The walls are slimy as well. Numerous slots or indentations about two feet wide and a foot high open here and there. Thin, wire or ropelike growths emerge from a hole further down and enter each of the slots. There is background noise here, almost loud enough to hear clearly. +A small, furtive motion attracts your attention to the slots. +>x slots +The slots are narrow burrows apparently dug by hand out of the mud of the chamber walls. Most of the slots have a thin wire or rope heading into them. You begin to be quite certain that there is something moving inside the slot you are looking at. \ No newline at end of file diff --git a/infocom/lurkinghorror/test/test-auto-generated.zil b/infocom/lurkinghorror/test/test-auto-generated.zil new file mode 100644 index 0000000..21891b1 --- /dev/null +++ b/infocom/lurkinghorror/test/test-auto-generated.zil @@ -0,0 +1,389 @@ +"TEST-lurkinghorror.ZIL - Auto-generated test from transcript" + +<INSERT-FILE "infocom/lurkinghorror/globals"> +<INSERT-FILE "infocom/lurkinghorror/parser"> +<INSERT-FILE "infocom/lurkinghorror/verbs"> +<INSERT-FILE "infocom/lurkinghorror/syntax"> +<INSERT-FILE "infocom/lurkinghorror/misc"> +<CONSTANT RELEASEID 1> + +<GLOBAL CO <CO-CREATE GO>> + +<ROUTINE RUN-TEST () + <TELL "Testing lurkinghorror transcript..." CR> + <ASSERT-TEXT "Start of a transcript of THE LURKING HORROR." <CO-RESUME ,CO "talk to hacker">> + <ASSERT-TEXT "Hmmm … the hacker waits for you to say something." <CO-RESUME ,CO "hacker, hi">> + <ASSERT-TEXT "\"Greetingage.\" He turns back to his hacking." <CO-RESUME ,CO "ask hacker about hacking">> + <ASSERT-TEXT "I don't know the word \"hacking.\"" <CO-RESUME ,CO "examine pc">> + <ASSERT-TEXT "This is a beyond-state-of-the-art personal computer. It has a 1024 by 1024 pixel..." <CO-RESUME ,CO "turn on pc">> + <ASSERT-TEXT "The computer powers up, goes through a remarkably fast self-check, and greets yo..." <CO-RESUME ,CO "login">> + <ASSERT-TEXT "What do you want to login?" <CO-RESUME ,CO "log in to computer">> + <ASSERT-TEXT "I don't know the word \"log.\"" <CO-RESUME ,CO "type username">> + <ASSERT-TEXT "The computer responds \"PASSWORD PLEASE:\"" <CO-RESUME ,CO "type password">> + <ASSERT-TEXT "What do you want to type passwo?" <CO-RESUME ,CO "ask hacker about password">> + <ASSERT-TEXT "There seems to be a noun missing in that sentence." <CO-RESUME ,CO "type 872325412">> + <ASSERT-TEXT "The computer responds \"INVALID LOGIN\" and then \"LOGIN PLEASE:\"." <CO-RESUME ,CO "type 872325412">> + <ASSERT-TEXT "The computer responds \"PASSWORD PLEASE:\"" <CO-RESUME ,CO "type uhlersoth">> + <ASSERT-TEXT "The computer responds \"Good evening. You're here awfully late.\" It displays a li..." <CO-RESUME ,CO "edit classics paper">> + <ASSERT-TEXT "The menu box is replaced by the YAK text editor and menu boxes listing the title..." <CO-RESUME ,CO "press help key">> + <ASSERT-TEXT "You push the friendly-looking HELP key. A spritely little box appears on the scr..." <CO-RESUME ,CO "click urgent box">> + <ASSERT-TEXT "You click the box for your paper, and the box grows reassuringly until it fills ..." <CO-RESUME ,CO "read paper">> + ;<ASSERT-TEXT "The paper appears to be a facsimile overlaid with occasional typescript. The tex..." <CO-RESUME ,CO "save">> + <ASSERT-TEXT "Okay." <CO-RESUME ,CO "press more">> + <ASSERT-TEXT "You touch the MORE box, and a new page appears." <CO-RESUME ,CO "summon visitor">> + <ASSERT-TEXT "I don't know the word \"summon.\"" <CO-RESUME ,CO "press more">> + <ASSERT-TEXT "You touch the MORE box, and a new page appears." <CO-RESUME ,CO "press more">> + <ASSERT-TEXT "You touch the MORE box, and a new page appears." <CO-RESUME ,CO "examine photograph">> + <ASSERT-TEXT "I don't know the word \"photograph.\"" <CO-RESUME ,CO "x photo">> + <ASSERT-TEXT "I don't know the word \"photo.\"" <CO-RESUME ,CO "x page">> + <ASSERT-TEXT "Instead, you find your finger moving towards the MORE box, and you touch it. The..." <CO-RESUME ,CO "d">> + <ASSERT-TEXT "Basalt Bowl" <CO-RESUME ,CO "forward">> + <ASSERT-TEXT "I don't know the word \"forward.\"" <CO-RESUME ,CO "x shapes">> + <ASSERT-TEXT "I don't know the word \"shapes.\"" <CO-RESUME ,CO "x platform">> + <ASSERT-TEXT "The platform is made of the same rocks as the surrounding terrain. In fact, you ..." <CO-RESUME ,CO "x stone">> + <ASSERT-TEXT "It's a smooth, shiny piece of what might be obsidian. Scratched on it is a symbo..." <CO-RESUME ,CO "x symbol">> + <ASSERT-TEXT "The symbol, on close examination, appears to have been carved into the smooth st..." <CO-RESUME ,CO "take stone">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "eat stone">> + <ASSERT-TEXT "The food here is terrible, but this is ridiculous!" <CO-RESUME ,CO "show stone to creature">> + <ASSERT-TEXT "The thing is uninterested." <CO-RESUME ,CO "i">> + <ASSERT-TEXT "You are carrying a smooth stone and an assignment." <CO-RESUME ,CO "x terminal">> + <ASSERT-TEXT "This is a beyond-state-of-the-art personal computer. It has a 1024 by 1024 pixel..." <CO-RESUME ,CO "read assignment">> + <ASSERT-TEXT "Laser printed on creamy bond paper, the assignment is due tomorrow. It's from yo..." <CO-RESUME ,CO "cry">> + <ASSERT-TEXT "I don't know the word \"cry.\"" <CO-RESUME ,CO "x hacker">> + <ASSERT-TEXT "The hacker is sitting at your terminal, typing furiously. Every so often, he pau..." <CO-RESUME ,CO "show stone to hacker">> + <ASSERT-TEXT "\"Odd-looking thing. Are you a rock-jock?\"" <CO-RESUME ,CO "take keys">> + <ASSERT-TEXT "\"Hey! No snarfage, loser!\" You determine that this means, \"Stop!\"" <CO-RESUME ,CO "ask hacker about keys">> + <ASSERT-TEXT "\"I've accumulated a few keys over the years. I'm a licensed locksmith, which hel..." <CO-RESUME ,CO "ask hacker for master key">> + ;<ASSERT-TEXT "\"Fat chance! This is a master key! What have you done for me lately?\"" <CO-RESUME ,CO "save">> + <ASSERT-TEXT "Okay." <CO-RESUME ,CO "punch hacker">> + <ASSERT-TEXT "I don't know the word \"punch.\"" <CO-RESUME ,CO "ask hacker about department of alchemy">> + <ASSERT-TEXT "You can't see any department of alchemy here." <CO-RESUME ,CO "feed hacker">> + <ASSERT-TEXT "(to the hacker)" <CO-RESUME ,CO "feed assignment to hacker">> + <ASSERT-TEXT "\"No thanks, keep it for now.\"" <CO-RESUME ,CO "l">> + <ASSERT-TEXT "Terminal Room" <CO-RESUME ,CO "x pizza boxes">> + <ASSERT-TEXT "I beg your pardon?" <CO-RESUME ,CO "read banners">> + <ASSERT-TEXT "I don't know the word \"pizza.\"" <CO-RESUME ,CO "s">> + <ASSERT-TEXT "How do you do that with a banners?" <CO-RESUME ,CO "w">> + <ASSERT-TEXT "Second Floor" <CO-RESUME ,CO "x funny bones">> + <ASSERT-TEXT "Kitchen" <CO-RESUME ,CO "take funny bones">> + <ASSERT-TEXT "This is a package of Funny Bones, a snack food made with peanut butter and choco..." <CO-RESUME ,CO "open fridge">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take all">> + <ASSERT-TEXT "Opening the refrigerator reveals a two liter bottle of Classic Coke and a cardbo..." <CO-RESUME ,CO "x carton">> + <ASSERT-TEXT "two liter bottle of Classic Coke: Taken." <CO-RESUME ,CO "x symbol">> + <ASSERT-TEXT "This is a cardboard carton with an incomprehensible symbol scrawled on the top." <CO-RESUME ,CO "open it">> + <ASSERT-TEXT "It doesn't look like Chinese, English, or any other language you know. The symbo..." <CO-RESUME ,CO "put carton in microwave">> + <ASSERT-TEXT "Opening the cardboard carton reveals Chinese food." <CO-RESUME ,CO "open microwave">> + <ASSERT-TEXT "Inspection reveals that the microwave oven isn't open." <CO-RESUME ,CO "put carton in microwave">> + <ASSERT-TEXT "The microwave oven is now open." <CO-RESUME ,CO "close fridge">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO "close microwave">> + <ASSERT-TEXT "Closed." <CO-RESUME ,CO "x microwave">> + <ASSERT-TEXT "Okay, the microwave oven is now closed." <CO-RESUME ,CO "x led readout">> + <ASSERT-TEXT "The microwave oven hangs over the kitchen counter. It has more complicated contr..." <CO-RESUME ,CO "x controls">> + ;<ASSERT-TEXT "The display is currently displaying the current time and the word \"off.\"" <CO-RESUME ,CO "save">> + <ASSERT-TEXT "There are controls labelled 0 to 9, WM, LO, MED, HI, START, CLEAR, and STOP. The..." <CO-RESUME ,CO "press hi">> + <ASSERT-TEXT "Okay." <CO-RESUME ,CO "press start">> + <ASSERT-TEXT "The bottom of the display now reads \"high.\"" <CO-RESUME ,CO "press 1">> + <ASSERT-TEXT "Nothing happens, as there's no time set on it yet." <CO-RESUME ,CO "press 0">> + <ASSERT-TEXT "The timer display now reads 0:01." <CO-RESUME ,CO "press 0">> + <ASSERT-TEXT "The timer display now reads 0:10." <CO-RESUME ,CO "press start">> + <ASSERT-TEXT "The timer display now reads 1:00." <CO-RESUME ,CO "open microwave">> + <ASSERT-TEXT "The microwave starts up. The timer begins counting down." <CO-RESUME ,CO "x carton">> + <ASSERT-TEXT "The microwave oven is now open." <CO-RESUME ,CO "touch carton">> + <ASSERT-TEXT "This is a cardboard carton with an incomprehensible symbol scrawled on the top." <CO-RESUME ,CO "open carton">> + <ASSERT-TEXT "Fiddling with the cardboard carton has no effect." <CO-RESUME ,CO "x chinese food">> + <ASSERT-TEXT "The cardboard carton is already open." <CO-RESUME ,CO "close microwave">> + <ASSERT-TEXT "This is a carton of cold Szechuan shrimp. Lovely red peppers poke out of the sau..." <CO-RESUME ,CO "press hi">> + <ASSERT-TEXT "Okay, the microwave oven is now closed." <CO-RESUME ,CO "press 3">> + <ASSERT-TEXT "The bottom of the display now reads \"high.\"" <CO-RESUME ,CO "press 0">> + <ASSERT-TEXT "The timer display now reads 0:03." <CO-RESUME ,CO "press 0">> + <ASSERT-TEXT "The timer display now reads 0:30." <CO-RESUME ,CO "press start">> + <ASSERT-TEXT "The timer display now reads 3:00." <CO-RESUME ,CO "wait">> + <ASSERT-TEXT "The microwave starts up. The timer begins counting down." <CO-RESUME ,CO "wait">> + <ASSERT-TEXT "Time passes…" <CO-RESUME ,CO "open microwave">> + <ASSERT-TEXT "Time passes…" <CO-RESUME ,CO "x food">> + <ASSERT-TEXT "The microwave oven is now open." <CO-RESUME ,CO "x chinese food">> + <ASSERT-TEXT "Which food do you mean, the Chinese food or the package of Funny Bones?" <CO-RESUME ,CO "take carton">> + <ASSERT-TEXT "This is a carton of hot Szechuan shrimp. Lovely red peppers poke out of the sauc..." <CO-RESUME ,CO "l">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "e">> + <ASSERT-TEXT "Kitchen" <CO-RESUME ,CO "n">> + <ASSERT-TEXT "Second Floor" <CO-RESUME ,CO "give chinese food to hacker">> + <ASSERT-TEXT "Terminal Room" <CO-RESUME ,CO "x chinese food">> + <ASSERT-TEXT "\"Yuck! This isn't warm enough!\" He thrusts it back into your hands." <CO-RESUME ,CO "s">> + <ASSERT-TEXT "This is a carton of warm Szechuan shrimp. Lovely red peppers poke out of the sau..." <CO-RESUME ,CO "e">> + <ASSERT-TEXT "Second Floor" <CO-RESUME ,CO "w">> + <ASSERT-TEXT "You can't go that way." <CO-RESUME ,CO "open microwave">> + <ASSERT-TEXT "Kitchen" <CO-RESUME ,CO "put carton in microwave">> + <ASSERT-TEXT "The microwave oven is already open." <CO-RESUME ,CO "close microwave">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO "press hi">> + <ASSERT-TEXT "Okay, the microwave oven is now closed." <CO-RESUME ,CO "press 5">> + <ASSERT-TEXT "The bottom of the display now reads \"high.\"" <CO-RESUME ,CO "press 0">> + <ASSERT-TEXT "The timer display now reads 0:05." <CO-RESUME ,CO "press 0">> + <ASSERT-TEXT "The timer display now reads 0:50." <CO-RESUME ,CO "press start">> + <ASSERT-TEXT "The timer display now reads 5:00." <CO-RESUME ,CO "wait">> + <ASSERT-TEXT "The microwave starts up. The timer begins counting down." <CO-RESUME ,CO "wait">> + <ASSERT-TEXT "Time passes…" <CO-RESUME ,CO "wait">> + <ASSERT-TEXT "Time passes…" <CO-RESUME ,CO "wait">> + <ASSERT-TEXT "Time passes…" <CO-RESUME ,CO "open microwave">> + <ASSERT-TEXT "Time passes…" <CO-RESUME ,CO "take container">> + <ASSERT-TEXT "The microwave oven is now open." <CO-RESUME ,CO "take carton">> + <ASSERT-TEXT "You can't see any container here." <CO-RESUME ,CO "close carton">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "e">> + <ASSERT-TEXT "Closed." <CO-RESUME ,CO "n">> + <ASSERT-TEXT "Second Floor" <CO-RESUME ,CO "give carton to hacker">> + <ASSERT-TEXT "Terminal Room" <CO-RESUME ,CO "reload">> + ;<ASSERT-TEXT "\"Ouch! This is ridiculous! You've overcooked it. Look at those poor shrimp! It's..." <CO-RESUME ,CO "restore">> + <ASSERT-TEXT "I don't know the word \"reload.\"" <CO-RESUME ,CO "l">> + <ASSERT-TEXT "Okay." <CO-RESUME ,CO "close oven">> + <ASSERT-TEXT "Kitchen" <CO-RESUME ,CO "open oven">> + <ASSERT-TEXT "It's already closed." <CO-RESUME ,CO "close carton">> + <ASSERT-TEXT "The microwave oven is now open." <CO-RESUME ,CO "close oven">> + <ASSERT-TEXT "Closed." <CO-RESUME ,CO "press hi">> + <ASSERT-TEXT "Okay, the microwave oven is now closed." <CO-RESUME ,CO "press 4:00">> + <ASSERT-TEXT "The bottom of the display now reads \"high.\"" <CO-RESUME ,CO "set timer to 4:20">> + <ASSERT-TEXT "Why don't you try setting the timer to that?" <CO-RESUME ,CO "press start">> + <ASSERT-TEXT "The timer display now reads 4:20." <CO-RESUME ,CO "wait">> + <ASSERT-TEXT "The microwave starts up. The timer begins counting down." <CO-RESUME ,CO "w">> + <ASSERT-TEXT "Time passes…" <CO-RESUME ,CO "wait">> + <ASSERT-TEXT "You can't go that way." <CO-RESUME ,CO "wait">> + <ASSERT-TEXT "Time passes…" <CO-RESUME ,CO "open microwave">> + <ASSERT-TEXT "Time passes…" <CO-RESUME ,CO "take container">> + <ASSERT-TEXT "The microwave oven is now open." <CO-RESUME ,CO "take carton">> + <ASSERT-TEXT "You can't see any container here." <CO-RESUME ,CO "e">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "n">> + <ASSERT-TEXT "Second Floor" <CO-RESUME ,CO "give carton to hacker">> + <ASSERT-TEXT "Terminal Room" <CO-RESUME ,CO "ask hacker for master key">> + <ASSERT-TEXT "\"Ah! Serious food!\" He plunges into the food with all the delicacy and table man..." <CO-RESUME ,CO "i">> + <ASSERT-TEXT "\"Well, I suppose I could loan you the master key for a while. Just don't get int..." <CO-RESUME ,CO "take all">> + <ASSERT-TEXT "You are carrying a master key, a two liter bottle of Classic Coke, a package of ..." <CO-RESUME ,CO "drop chair">> + <ASSERT-TEXT "chair: Taken." <CO-RESUME ,CO "take pc">> + <ASSERT-TEXT "Dropped." <CO-RESUME ,CO "drop pc">> + <ASSERT-TEXT "You take it, turning it off and unplugging it first." <CO-RESUME ,CO "take chair">> + <ASSERT-TEXT "Dropped." <CO-RESUME ,CO "l">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "verbose">> + <ASSERT-TEXT "Terminal Room" <CO-RESUME ,CO "i">> + <ASSERT-TEXT "Verbose descriptions." <CO-RESUME ,CO "s">> + <ASSERT-TEXT "You are carrying a chair, a master key, a two liter bottle of Classic Coke, a pa..." <CO-RESUME ,CO "drop chair">> + <ASSERT-TEXT "The hacker prevents you. \"You can't walk off with that! It's Tech property!\"" <CO-RESUME ,CO "s">> + <ASSERT-TEXT "Dropped." <CO-RESUME ,CO "hello">> + <ASSERT-TEXT "Second Floor" <CO-RESUME ,CO "push call button">> + <ASSERT-TEXT "Cheery, aren't you?" <CO-RESUME ,CO "push up">> + <ASSERT-TEXT "Which call button do you mean, the up-arrow or the down-arrow?" <CO-RESUME ,CO "cool">> + <ASSERT-TEXT "The up-arrow begins to glow." <CO-RESUME ,CO ";cool">> + <ASSERT-TEXT "I don't know the word \"cool.\"" <CO-RESUME ,CO "say "cool"">> + <ASSERT-TEXT "I don't know the word \";cool.\"" <CO-RESUME ,CO "wait">> + <ASSERT-TEXT "Talking to yourself is a sign of impending mental collapse." <CO-RESUME ,CO "s">> + <ASSERT-TEXT "Time passes…" <CO-RESUME ,CO "open panel">> + <ASSERT-TEXT "Elevator" <CO-RESUME ,CO "take flashlight">> + <ASSERT-TEXT "Opening the access panel reveals a flashlight." <CO-RESUME ,CO "push 3">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "wait">> + <ASSERT-TEXT "The button for the third floor begins to glow." <CO-RESUME ,CO "x me">> + <ASSERT-TEXT "Time passes…" <CO-RESUME ,CO "wait">> + <ASSERT-TEXT "You are wide awake, and are in good health." <CO-RESUME ,CO "n">> + <ASSERT-TEXT "Time passes…" <CO-RESUME ,CO "n">> + <ASSERT-TEXT "Third Floor" <CO-RESUME ,CO "look through glass">> + <ASSERT-TEXT "There is a glass wall in the way." <CO-RESUME ,CO "x equipment">> + <ASSERT-TEXT "You see nothing special about it." <CO-RESUME ,CO "u">> + <ASSERT-TEXT "You see nothing special about it." <CO-RESUME ,CO "x brown building">> + <ASSERT-TEXT "You push through the door to the roof. You enter the freezing, biting cold of th..." <CO-RESUME ,CO "take snow">> + <ASSERT-TEXT "I don't know the word \"brown.\"" <CO-RESUME ,CO "d">> + <ASSERT-TEXT "That would never work!" <CO-RESUME ,CO "d">> + <ASSERT-TEXT "You push your way into the welcoming warmth inside." <CO-RESUME ,CO "d">> + <ASSERT-TEXT "Second Floor" <CO-RESUME ,CO "d">> + <ASSERT-TEXT "Computer Center" <CO-RESUME ,CO "x pipes">> + <ASSERT-TEXT "Basement" <CO-RESUME ,CO "x channels">> + <ASSERT-TEXT "You see nothing special about the steam pipes." <CO-RESUME ,CO "w">> + <ASSERT-TEXT "From floor to ceiling run wire channels and steam pipes." <CO-RESUME ,CO "show stone to urchin">> + <ASSERT-TEXT "Aero Basement" <CO-RESUME ,CO "ask urchin about stone">> + <ASSERT-TEXT "He makes an unconvincing show of disinterest." <CO-RESUME ,CO "x urchin">> + ;<ASSERT-TEXT "He doesn't reply. He seems very nervous about talking to you." <CO-RESUME ,CO "save">> + <ASSERT-TEXT "This is an urchin. He's a youngish teenager wearing a ski hat, running shoes, an..." <CO-RESUME ,CO "take parka">> + <ASSERT-TEXT "Okay." <CO-RESUME ,CO "scare him">> + <ASSERT-TEXT "\"Hey! Keep off, sucker! You can't scare me!\"" <CO-RESUME ,CO "boo urchin">> + <ASSERT-TEXT "How do you propose to do that?" <CO-RESUME ,CO "say "BOO"">> + <ASSERT-TEXT "I don't know the word \"boo.\"" <CO-RESUME ,CO "urchin, boo">> + <ASSERT-TEXT "You must address the urchin directly." <CO-RESUME ,CO "x forklift">> + <ASSERT-TEXT "I don't know the word \"boo.\"" <CO-RESUME ,CO "get on forklift">> + <ASSERT-TEXT "This is a rusty old forklift. It looks like you could control it fairly easily, ..." <CO-RESUME ,CO "operate forklift">> + <ASSERT-TEXT "You are now in the forklift." <CO-RESUME ,CO "turn on forklift">> + <ASSERT-TEXT "I don't know the word \"operate.\"" <CO-RESUME ,CO "use forklift on urchin">> + <ASSERT-TEXT "The forklift sputters to life." <CO-RESUME ,CO "life urchin">> + <ASSERT-TEXT "I don't know the word \"use.\"" <CO-RESUME ,CO "lift urchin">> + <ASSERT-TEXT "There was no verb in that sentence!" <CO-RESUME ,CO "w">> + <ASSERT-TEXT "You can't reach the urchin from within the forklift." <CO-RESUME ,CO "e">> + <ASSERT-TEXT "The forklift won't fit into the stairwell." <CO-RESUME ,CO "e">> + <ASSERT-TEXT "Basement, on the forklift" <CO-RESUME ,CO "take all">> + <ASSERT-TEXT "Temporary Basement, on the forklift" <CO-RESUME ,CO "exit forklift">> + <ASSERT-TEXT "pair of electrician's gloves: You can't reach the pair of electrician's gloves f..." <CO-RESUME ,CO "take all">> + <ASSERT-TEXT "You are now on your feet." <CO-RESUME ,CO "x gloves">> + <ASSERT-TEXT "pair of electrician's gloves: Taken." <CO-RESUME ,CO "x crowbar">> + <ASSERT-TEXT "This is a pair of electrician's rubber gloves. They look well used but serviceab..." <CO-RESUME ,CO "put on gloves">> + <ASSERT-TEXT "You see nothing special about the crowbar." <CO-RESUME ,CO "turn off forklift">> + <ASSERT-TEXT "You put on the gloves. They're a little big, but not really such a bad fit at al..." <CO-RESUME ,CO "get on forklift">> + <ASSERT-TEXT "You'll have to get in it first." <CO-RESUME ,CO "turn off forklift">> + <ASSERT-TEXT "You are now in the forklift." <CO-RESUME ,CO "get of forklift">> + <ASSERT-TEXT "The forklift coughs once, and dies." <CO-RESUME ,CO "get off forklift">> + <ASSERT-TEXT "You used the word \"of\" in a way that I don't understand." <CO-RESUME ,CO "e">> + <ASSERT-TEXT "You are now on your feet." <CO-RESUME ,CO "turn on flashlight">> + <ASSERT-TEXT "It is pitch black." <CO-RESUME ,CO "x pallets">> + <ASSERT-TEXT "The flashlight clicks on." <CO-RESUME ,CO "search junk">> + <ASSERT-TEXT "Looking more closely only emphasizes how completely entropy has taken over this ..." <CO-RESUME ,CO "w">> + <ASSERT-TEXT "You find many worthless items of hardware, old discarded memos and papers, but n..." <CO-RESUME ,CO "get on forklift">> + <ASSERT-TEXT "Temporary Basement" <CO-RESUME ,CO "turn on forklift">> + <ASSERT-TEXT "You are now in the forklift." <CO-RESUME ,CO "e">> + <ASSERT-TEXT "The forklift sputters to life." <CO-RESUME ,CO "move pallets">> + <ASSERT-TEXT "Dead Storage, on the forklift" <CO-RESUME ,CO "g">> + <ASSERT-TEXT "You have a little trouble using the forklift, but it's not really all that hard...." <CO-RESUME ,CO "g">> + <ASSERT-TEXT "You continue moving junk, becoming more proficient with the forklift." <CO-RESUME ,CO "g">> + <ASSERT-TEXT "You continue moving junk, becoming more proficient with the forklift." <CO-RESUME ,CO "e">> + <ASSERT-TEXT "You've built a fairly narrow (about one forklift wide) path through the junk. Yo..." <CO-RESUME ,CO "turn off forklift">> + <ASSERT-TEXT "Ancient Storage, on the forklift" <CO-RESUME ,CO "get off forklift">> + <ASSERT-TEXT "The forklift coughs once, and dies." <CO-RESUME ,CO "x manhole">> + <ASSERT-TEXT "You are now on your feet." <CO-RESUME ,CO "open manhole">> + <ASSERT-TEXT "It's a steel ring set in the floor. It's probably a manhole." <CO-RESUME ,CO "remove cover with crowbar">> + ;<ASSERT-TEXT "The only way would seem to be to remove the manhole cover." <CO-RESUME ,CO "save">> + <ASSERT-TEXT "You lever the manhole cover aside, and crusted dirt falls into a dark, partly ob..." <CO-RESUME ,CO "x hole">> + <ASSERT-TEXT "Okay." <CO-RESUME ,CO "d">> + <ASSERT-TEXT "It's a manhole. It's very dark inside, but you can see that crude brick handhold..." <CO-RESUME ,CO "s">> + <ASSERT-TEXT "You push your way through cobwebs, damp fungus, and other obstructions." <CO-RESUME ,CO "u">> + <ASSERT-TEXT "You make your way along the long tunnel." <CO-RESUME ,CO "open trapdoor">> + <ASSERT-TEXT "The trapdoor isn't open." <CO-RESUME ,CO "look through trapdoor">> + <ASSERT-TEXT "It lifts a few inches, but then hits something and goes no further." <CO-RESUME ,CO "open trapdoor with crowbar">> + <ASSERT-TEXT "Pushing the plate up as far as you can, you can see part of a workroom or lab of..." <CO-RESUME ,CO "i">> + <ASSERT-TEXT "It lifts a few inches, but then hits something and goes no further." <CO-RESUME ,CO "n">> + <ASSERT-TEXT "You are carrying a crowbar, a flashlight (providing light), a master key, a two ..." <CO-RESUME ,CO "n">> + <ASSERT-TEXT "You make your way along the long tunnel." <CO-RESUME ,CO "x slab">> + <ASSERT-TEXT "You make your way along the long tunnel." <CO-RESUME ,CO "open slab">> + <ASSERT-TEXT "The slab is roughly circular, made of indifferently dressed New England granite,..." <CO-RESUME ,CO "lay on slab">> + <ASSERT-TEXT "How do you do that with a slab of granite?" <CO-RESUME ,CO "stand on slab">> + <ASSERT-TEXT "You aren't holding the slab of granite." <CO-RESUME ,CO "d">> + <ASSERT-TEXT "That would be a waste of time." <CO-RESUME ,CO "x knife">> + <ASSERT-TEXT "Before the Altar" <CO-RESUME ,CO "take knife">> + <ASSERT-TEXT "This small knife is clean, sharp, and has a long, thin blade and a wooden handle..." <CO-RESUME ,CO "x tip">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "x symbols">> + <ASSERT-TEXT "I don't know the word \"tip.\"" <CO-RESUME ,CO "incised">> + <ASSERT-TEXT "Which symbols do you mean, the incised symbol or the carved symbol?" <CO-RESUME ,CO "put stone on altar">> + <ASSERT-TEXT "The symbol appears to be the oldest thing carved on the altar. It is beautifully..." <CO-RESUME ,CO "x carved symbol">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO "x grate">> + <ASSERT-TEXT "The symbol, on close examination, appears to have been carved into the smooth st..." <CO-RESUME ,CO "x plate">> + ;<ASSERT-TEXT "I don't know the word \"grate.\"" <CO-RESUME ,CO "save">> + <ASSERT-TEXT "The plate is iron, about two feet square, and looks like it could be slid open. ..." <CO-RESUME ,CO "take stone">> + <ASSERT-TEXT "Okay." <CO-RESUME ,CO "open plate">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "x hole">> + <ASSERT-TEXT "You slide open the panel, revealing a dark pit below. Immediately, there is a re..." <CO-RESUME ,CO "look down hole">> + <ASSERT-TEXT "The plate is iron, about two feet square, and open. A curious feature of the pla..." <CO-RESUME ,CO "d">> + <ASSERT-TEXT "You see nothing special about the iron plate." <CO-RESUME ,CO "enter hole">> + <ASSERT-TEXT "You can't go that way." <CO-RESUME ,CO "drop funny bones in hole">> + <ASSERT-TEXT "You hit your head against the iron plate as you attempt this feat." <CO-RESUME ,CO "i">> + <ASSERT-TEXT "Sounds of ghoulish excitement issue from the opening." <CO-RESUME ,CO "undo">> + ;<ASSERT-TEXT "You are carrying a smooth stone, a knife, a crowbar, a flashlight (providing lig..." <CO-RESUME ,CO "restore">> + <ASSERT-TEXT "I don't know the word \"undo.\"" <CO-RESUME ,CO "look in hole">> + <ASSERT-TEXT "Okay." <CO-RESUME ,CO "take stone">> + <ASSERT-TEXT "The iron plate is closed." <CO-RESUME ,CO "trace symbol">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "compare symbols">> + <ASSERT-TEXT "I don't know the word \"trace.\"" <CO-RESUME ,CO "compare carved and incised">> + <ASSERT-TEXT "You can only compare two things." <CO-RESUME ,CO "l">> + <ASSERT-TEXT "Allowing for the different media in which the symbols are executed, they are ide..." <CO-RESUME ,CO "x stains">> + <ASSERT-TEXT "Before the Altar" <CO-RESUME ,CO "exit">> + <ASSERT-TEXT "I don't know the word \"stains.\"" <CO-RESUME ,CO "s">> + <ASSERT-TEXT "Please use compass directions instead." <CO-RESUME ,CO "up">> + <ASSERT-TEXT "You can't go that way." <CO-RESUME ,CO "s">> + <ASSERT-TEXT "Renovated Cave" <CO-RESUME ,CO "u">> + <ASSERT-TEXT "Brick Tunnel" <CO-RESUME ,CO "verbose">> + <ASSERT-TEXT "Ancient Storage" <CO-RESUME ,CO "w">> + <ASSERT-TEXT "Verbose descriptions." <CO-RESUME ,CO "w">> + <ASSERT-TEXT "Dead Storage" <CO-RESUME ,CO "show funny bones to urchin">> + <ASSERT-TEXT "Temporary Basement" <CO-RESUME ,CO "show coke to urchin">> + <ASSERT-TEXT "He makes an unconvincing show of disinterest." <CO-RESUME ,CO "ask urchin about parka">> + ;<ASSERT-TEXT "He makes an unconvincing show of disinterest." <CO-RESUME ,CO "save">> + <ASSERT-TEXT "He doesn't reply. He seems very nervous about talking to you." <CO-RESUME ,CO "give funny bones to urchin">> + <ASSERT-TEXT "Okay." <CO-RESUME ,CO "ask urchin about parka">> + <ASSERT-TEXT "\"My momma said never take nothin' from no stranger.\" He takes the package of Fun..." <CO-RESUME ,CO "show knife to urchin">> + <ASSERT-TEXT "He doesn't reply. He seems very nervous about talking to you." <CO-RESUME ,CO "give coke to urchin">> + <ASSERT-TEXT "He makes an unconvincing show of disinterest." <CO-RESUME ,CO "x urchin">> + <ASSERT-TEXT "\"My momma said never take nothin' from no stranger.\"" <CO-RESUME ,CO "x parka">> + <ASSERT-TEXT "This is an urchin. He's a youngish teenager wearing a ski hat, running shoes, an..." <CO-RESUME ,CO "x bulges">> + <ASSERT-TEXT "It bulges in odd places." <CO-RESUME ,CO "u">> + <ASSERT-TEXT "I don't know the word \"bulges.\"" <CO-RESUME ,CO "x flask">> + <ASSERT-TEXT "Temporary Lab" <CO-RESUME ,CO "open flask">> + <ASSERT-TEXT "This is a large metal flask, about the size of a water cooler bottle. The metal ..." <CO-RESUME ,CO "close flask">> + <ASSERT-TEXT "You open the flask, and a cold, white mist boils out." <CO-RESUME ,CO "take flask">> + <ASSERT-TEXT "You screw the flask closed." <CO-RESUME ,CO "n">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "w">> + <ASSERT-TEXT "You enter the freezing, biting cold of the blizzard." <CO-RESUME ,CO "w">> + <ASSERT-TEXT "Smith Street" <CO-RESUME ,CO "s">> + <ASSERT-TEXT "Impenetrable snow drifts block the street." <CO-RESUME ,CO "d">> + <ASSERT-TEXT "You push your way into the welcoming warmth inside." <CO-RESUME ,CO "turn off flashlight">> + <ASSERT-TEXT "Basement" <CO-RESUME ,CO "drink coke">> + <ASSERT-TEXT "The flashlight clicks off." <CO-RESUME ,CO "i">> + <ASSERT-TEXT "Delicious! Contains caffeine, one of the four basic food groups. Too bad they ma..." <CO-RESUME ,CO "d">> + <ASSERT-TEXT "You are carrying a metal flask, a smooth stone, a knife, a crowbar, a flashlight..." <CO-RESUME ,CO "w">> + <ASSERT-TEXT "You can't go that way." <CO-RESUME ,CO "w">> + <ASSERT-TEXT "Aero Basement" <CO-RESUME ,CO "d">> + <ASSERT-TEXT "Stairway" <CO-RESUME ,CO "x crack">> + <ASSERT-TEXT "Subbasement" <CO-RESUME ,CO "nw">> + <ASSERT-TEXT "You used the word \"crack\" in a way that I don't understand." <CO-RESUME ,CO "drop flask">> + <ASSERT-TEXT "It's too tight a fit carrying the metal flask." <CO-RESUME ,CO "nw">> + <ASSERT-TEXT "Dropped." <CO-RESUME ,CO "read letters">> + <ASSERT-TEXT "Tomb" <CO-RESUME ,CO "unlock padlock with key">> + <ASSERT-TEXT "It reads \"The Tomb of the Unknown Tool.\"" <CO-RESUME ,CO "open hatch">> + <ASSERT-TEXT "The lock, though rusty and unwilling, opens, releasing the hatch." <CO-RESUME ,CO "turn on flashlight">> + <ASSERT-TEXT "The hatch is heavy, and its hinges are rusty, but you pull and strain and it ope..." <CO-RESUME ,CO "d">> + ;<ASSERT-TEXT "The flashlight clicks on." <CO-RESUME ,CO "save">> + <ASSERT-TEXT "Steam Tunnel" <CO-RESUME ,CO "listen">> + <ASSERT-TEXT "Okay." <CO-RESUME ,CO "yes">> + <ASSERT-TEXT "You hear the chittering of rats." <CO-RESUME ,CO "am I good or what?">> + <ASSERT-TEXT "That was a rhetorical question." <CO-RESUME ,CO "e">> + <ASSERT-TEXT "I don't know the word \"good.\"" <CO-RESUME ,CO "x valve">> + <ASSERT-TEXT "Steam Tunnel" <CO-RESUME ,CO "open valve">> + <ASSERT-TEXT "It looks pretty rusty, but appears to be in working order. It's closed." <CO-RESUME ,CO "open valve with crowbar">> + <ASSERT-TEXT "It's too rusty. You pull and strain, but nothing happens." <CO-RESUME ,CO "again">> + <ASSERT-TEXT "The valve, with a horrible scream of tortured metal, gives a little, and a small..." <CO-RESUME ,CO "take dead rat">> + <ASSERT-TEXT "The valve screeches open. A jet spray of live steam issues from it, filling the ..." <CO-RESUME ,CO "close valve with crowbar">> + <ASSERT-TEXT "As you take the dead rat, it moves, but then you realize that it's only lice and..." <CO-RESUME ,CO "x rat">> + <ASSERT-TEXT "The valve closes, more easily than it opened." <CO-RESUME ,CO "x symbol">> + <ASSERT-TEXT "This rat appears to have been stepped on. A small trickle of blood has clotted a..." <CO-RESUME ,CO "compare scarred symbol to carved symbol">> + <ASSERT-TEXT "The symbol, on close examination, appears to have been scarred into the hide of ..." <CO-RESUME ,CO "compare rat to stone">> + <ASSERT-TEXT "I don't know the word \"scarred.\"" <CO-RESUME ,CO "compare symbol to symbol">> + <ASSERT-TEXT "That would be a waste of time." <CO-RESUME ,CO "l">> + <ASSERT-TEXT "Allowing for the different media in which the symbols are executed, they are ide..." <CO-RESUME ,CO "x cable">> + <ASSERT-TEXT "Steam Tunnel" <CO-RESUME ,CO "e">> + <ASSERT-TEXT "The cable runs overhead in a fat bundle. It looks like the kind you've seen conn..." <CO-RESUME ,CO "x mud">> + <ASSERT-TEXT "Steam Tunnel" <CO-RESUME ,CO "e">> + <ASSERT-TEXT "I don't know the word \"mud.\"" <CO-RESUME ,CO "x south wall">> + <ASSERT-TEXT "Steam Tunnel" <CO-RESUME ,CO "break wall with crowbar">> + <ASSERT-TEXT "The brick wall is in terrible shape. It's aged and crumbling, with grooves betwe..." <CO-RESUME ,CO "g">> + <ASSERT-TEXT "It doesn't do much but loosen a brick in the wall." <CO-RESUME ,CO "pry brick with crowbar">> + <ASSERT-TEXT "It doesn't do much but loosen a brick in the wall." <CO-RESUME ,CO "x brick">> + <ASSERT-TEXT "The wall grudgingly yields to your efforts. A brick, less well mortared than its..." <CO-RESUME ,CO "new">> + <ASSERT-TEXT "Which brick do you mean, the broken brick or the new brick?" <CO-RESUME ,CO "x broken brick">> + <ASSERT-TEXT "It's a new brick. It appears to be of relatively recent vintage." <CO-RESUME ,CO "get all">> + <ASSERT-TEXT "It's a crumbling, broken brick. Little bits of mortar still cling to it." <CO-RESUME ,CO "press new brick">> + <ASSERT-TEXT "broken brick: Taken." <CO-RESUME ,CO "pry new brick with crowbar">> + <ASSERT-TEXT "Pushing the new brick has no effect." <CO-RESUME ,CO "x rod">> + <ASSERT-TEXT "The wall grudgingly yields to your efforts. A brick, less well mortared than its..." <CO-RESUME ,CO "look through hole">> + <ASSERT-TEXT "It's rusty, obviously didn't help the wall all that much, and runs up and down t..." <CO-RESUME ,CO "s">> + <ASSERT-TEXT "There is an open space, a small room containing some machinery. You can't see to..." <CO-RESUME ,CO "reach into hole">> + <ASSERT-TEXT "You are trying to walk through a brick wall." <CO-RESUME ,CO "pull rod">> + <ASSERT-TEXT "You reach in and touch the reinforcing rod." <CO-RESUME ,CO "pry rod with crowbar">> + <ASSERT-TEXT "It's pretty solidly mortared in." <CO-RESUME ,CO "i">> + <ASSERT-TEXT "It's pretty solidly mortared in." <CO-RESUME ,CO "get new brick">> + <ASSERT-TEXT "You are carrying a broken brick, a dead rat, a smooth stone, a knife, a crowbar,..." <CO-RESUME ,CO "u">> + <ASSERT-TEXT "You can't see any new brick here." <CO-RESUME ,CO "shine flashlight in hole">> + <ASSERT-TEXT "You can't go that way." <CO-RESUME ,CO "get cables">> + <ASSERT-TEXT "I don't know the word \"shine.\"" <CO-RESUME ,CO "x cables">> + <ASSERT-TEXT "I don't know the word \"cables.\"" <CO-RESUME ,CO "x cable">> + <ASSERT-TEXT "I don't know the word \"cables.\"" <CO-RESUME ,CO "get cable">> + <ASSERT-TEXT "The cable runs overhead in a fat bundle. It looks like the kind you've seen conn..." <CO-RESUME ,CO "climb">> + <ASSERT-TEXT "You can't take that!" <CO-RESUME ,CO "cable">> + <ASSERT-TEXT "What do you want to climb?" <CO-RESUME ,CO "climb pipe">> + <ASSERT-TEXT "You leap, grab the damp and moldy bundle of cable, and hang suspended off the fl..." <CO-RESUME ,CO "pour coke on rod">> + <ASSERT-TEXT "That would be a waste of time." <CO-RESUME ,CO "i">> + <ASSERT-TEXT "You pour the Coke on the reinforcing rod, wasting it." <CO-RESUME ,CO "w">> + <ASSERT-TEXT "You are carrying a broken brick, a dead rat, a smooth stone, a knife, a crowbar,..." <CO-RESUME ,CO "w">> + <ASSERT-TEXT "Steam Tunnel" <CO-RESUME ,CO "w">> + <ASSERT-TEXT "Steam Tunnel" <CO-RESUME ,CO "w">> + <ASSERT-TEXT "Steam Tunnel" <CO-RESUME ,CO "w">> + <ASSERT-TEXT "Steam Tunnel" <CO-RESUME ,CO "w">> + <ASSERT-TEXT "Tunnel Entrance" <CO-RESUME ,CO "d">> + <ASSERT-TEXT "Muddy Tunnel" <CO-RESUME ,CO "x slots">> + <TELL CR "lurkinghorror transcript test completed!" CR>> diff --git a/infocom/planetfall/planetfall.z3 b/infocom/planetfall/planetfall.z3 new file mode 100644 index 0000000..60b3676 Binary files /dev/null and b/infocom/planetfall/planetfall.z3 differ diff --git a/infocom/planetfall/test/planetfall-frotz-failure.log b/infocom/planetfall/test/planetfall-frotz-failure.log new file mode 100644 index 0000000..13dbc8f --- /dev/null +++ b/infocom/planetfall/test/planetfall-frotz-failure.log @@ -0,0 +1,608 @@ + Deck Nine Score: 0 Moves: 4567 + +PLANETFALL +Infocom interactive fiction - a science fiction story +Copyright (c) 1983 by Infocom, Inc. All rights reserved. +PLANETFALL is a registered trademark of Infocom, Inc. +Release 39 / Serial number 880501 + +Another routine day of drudgery aboard the Stellar Patrol Ship Feinstein. This +morning's assignment for a certain lowly Ensign Seventh Class: scrubbing the +filthy metal deck at the port end of Level Nine. With your Patrol-issue self- +contained multi-purpose all-weather scrub brush you shine the floor with a +diligence born of the knowledge that at any moment dreaded Ensign First Class +Blather, the bane of your shipboard existence, could appear. + +Deck Nine +This is a featureless corridor similar to every other corridor on the ship. It +curves away to starboard, and a gangway leads up. To port is the entrance to one +of the ship's primary escape pods. The pod bulkhead is closed. + +>Please enter a filename [planetfall.scr]: Here begins a transcript of interaction with PLANETFALL. +PLANETFALL is a registered trademark of Infocom, Inc. +Copyright (c) 1983 Infocom, Inc. All rights reserved. + +> Deck Nine Score: 0 Moves: 4574 + +The escape pod bulkhead is closed. + +> Deck Nine Score: 0 Moves: 4581 + +You can't see any webbing here! + +> Deck Nine Score: 0 Moves: 4621 + +Time passes... + +> Deck Nine Score: 0 Moves: 4661 + +Time passes... + +> Deck Nine Score: 0 Moves: 4701 + +Time passes... + +> Deck Nine Score: 0 Moves: 4741 + +Time passes... + +> Deck Nine Score: 0 Moves: 4781 + +Time passes... + +> Deck Nine Score: 0 Moves: 4821 + +Time passes... + +The alien ambassador from the planet Blow'k-bibben-Gordo ambles toward you from +down the corridor. He is munching on something resembling an enormous stalk of +celery, and he leaves a trail of green slime on the deck. He stops nearby, and +you wince as a pool of slime begins forming beneath him on your newly-polished +deck. The ambassador wheezes loudly and hands you a brochure outlining his +planet's major exports. + +> Deck Nine Score: 0 Moves: 4861 + +Time passes... + +The ambassador remarks that all humans look alike to him. + +> Deck Nine Score: 0 Moves: 4901 + +Time passes... + +A massive explosion rocks the ship. Echoes from the explosion resound +deafeningly down the halls. The door to port slides open. The ambassador squawks +frantically, evacuates a massive load of gooey slime, and rushes away. + +> Deck Nine Score: 0 Moves: 4941 + +Time passes... + +More distant explosions! A narrow emergency bulkhead at the base of the gangway +and a wider one along the corridor to starboard both crash shut! + +> Deck Nine Score: 0 Moves: 4981 + +Time passes... + +More powerful explosions buffet the ship. The lights flicker madly, and the +escape-pod bulkhead clangs shut. + +> Deck Nine Score: 0 Moves: 5021 + +Time passes... + +Explosions continue to rock the ship. + +> Deck Nine Score: 0 Moves: 5061 + +Time passes... + +An enormous explosion tears the walls of the ship apart. If only you had made it +to an escape pod... + + **** You have died **** + +Your score would be 0 (out of 80 points). It is Day 1 of your adventure. Current +Galactic Standard Time (adjusted to your local day-cycle) is 5061. +This score gives you the rank of Beginner. + +Oh, well. According to the Treaty of Gishen IV, signed in 8747 GY, all adventure +game players must be given another chance after dying. In the interests of +interstellar peace... + +Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +>Would you like to restart the game from the beginning, restore a saved game +position, or end this session of the game? (Type RESTART, RESTORE, or QUIT.) + +> +Fatal error: Stack overflow diff --git a/infocom/planetfall/test/planetfall.txt b/infocom/planetfall/test/planetfall.txt new file mode 100644 index 0000000..fc31e13 --- /dev/null +++ b/infocom/planetfall/test/planetfall.txt @@ -0,0 +1,903 @@ +Start of a transcript of PLANETFALL. +PLANETFALL +An Interactive Science-Fiction Story +Copyright (c) 1983 by Infocom, Inc. All rights reserved. +Release 20 / Serial number 830708 + +> W +You are in the living quarters of a small vessel. There is a webbing here, bolted to the wall. A door leads west. + +> GET INTO WEBBING +You strap yourself into the webbing. + +> WAIT +Time passes... + +> WAIT +Time passes... + +> WAIT +Time passes... + +> WAIT +Time passes... + +> WAIT +Time passes... + +> WAIT +Time passes... + +> WAIT +Time passes... + +> WAIT +Time passes... + +> WAIT +Time passes... + +> WAIT +Time passes... + +> WAIT +Time passes... + +> WAIT +Time passes... + +> WAIT +Time passes... + +> GET OUT OF WEBBING +You remove yourself from the webbing. + +> TAKE ALL +webbing: Already have that. +kit: Taken. +ID card: Taken. +flask: Taken. + +> OPEN DOOR +You open the door, revealing a closet. The door swings shut again. + +> U +You are in a narrow shaft. A ladder runs up and down. There is a narrow opening to the east. + +> U +You are in a wide shaft. A ladder runs up and down. There is a wide opening to the east. + +> U +You are in a wide shaft. A ladder runs up and down. There is a wide opening to the east and a narrow opening to the north. + +> U +You are in a wide shaft. A ladder runs up and down. There is a wide opening to the east and a narrow opening to the north. + +> U +You are in a wide shaft. A ladder runs up and down. There is a wide opening to the east and a narrow opening to the north. + +> N +You are in a corridor. Passages lead south, north, and northeast. + +> NE +You are in a corridor. Passages lead southwest and east. + +> E +You are in a corridor. Passages lead west and east. + +> E +You are in a corridor. Passages lead west and east. + +> TAKE ID CARD +ID card: Already have that. + +> DROP ALL EXCEPT KIT +kit: (keeping) +ID card: Dropped. +flask: Dropped. + +> E +You are in a storage room. Passages lead west and south. + +> S +You are in a storage room. Passages lead north and south. + +> S +You are in a storage room. Passages lead north and southwest. + +> SW +You are in a storage room. Passages lead northeast and south. + +> TAKE ALL +battery: Taken. +pliers: Taken. + +> DROP BATTERY +battery: Dropped. + +> NE +You are in a storage room. Passages lead southwest and north. + +> N +You are in a corridor. Passages lead south and north. + +> N +You are in a corridor. Passages lead south and north. + +> N +You are in a corridor. Passages lead south and north. + +> N +You are in a corridor. Passages lead south and north. + +> PUT BAR OVER CREVICE +You can't see any such thing. + +> S +You are in a corridor. Passages lead north and south. + +> E +You are in a storage room. Passages lead west and south. + +> DROP ALL EXCEPT KEY +key: (keeping) +kit: Dropped. + +> PRESS BLUE BUTTON +You press the blue button on the kit. + +> PRESS RED BUTTON +You press the red button on the kit. + +> W +You are in a corridor. Passages lead east and west. + +> W +You are in a corridor. Passages lead east and west. + +> W +You are in a corridor. Passages lead east and west. + +> UNLOCK PADLOCK WITH KEY +You unlock the padlock. + +> TAKE PADLOCK +padlock: Taken. + +> OPEN DOOR +You open the door. + +> N +You are in a storage closet. + +> DROP KEY AND PADLOCK +key: Dropped. +padlock: Dropped. + +> TAKE LADDER +ladder: Taken. + +> S +You are in a corridor. Passages lead north and south. + +> E +You are in a corridor. Passages lead west and east. + +> E +You are in a corridor. Passages lead west and east. + +> N +You are in a corridor. Passages lead south and north. + +> N +You are in a corridor. Passages lead south and north. + +> DROP LADDER +ladder: Dropped. + +> EXTEND LADDER +You extend the ladder to its full length. + +> PUT LADDER OVER RIFT +You place the ladder over the rift. + +> N +You are on a ledge. A ladder leads south over a rift. To the north is a small opening. + +> W +You are in a small room. A desk is against the wall. There is a small drawer in the desk. + +> OPEN DESK +You open the desk. There is a card here. + +> PUT KITCHEN CARD AND UPPER CARD INTO POCKET +kitchen card: You put the kitchen card into your pocket. +upper card: You put the upper card into your pocket. + +> W +You are in a small room. A desk is against the wall. There is a small drawer in the desk. + +> OPEN DESK +You open the desk. There is a card here. + +> PUT SHUTTLE CARD INTO POCKET +shuttle card: You put the shuttle card into your pocket. + +> E +You are in a small room. A desk is against the wall. + +> E +You are on a ledge. A ladder leads south over a rift. + +> S +You are in a corridor. Passages lead north and south. + +> S +You are in a corridor. Passages lead north and south. + +> S +You are in a corridor. Passages lead north and east. + +> E +You are in a storage room. Passages lead west and south. + +> TAKE KIT AND FLASK +kit: Taken. +flask: Taken. + +> OPEN KIT +You open the kit. + +> EAT RED GOO +You eat the red goo. It tastes like strawberry. + +> W +You are in a corridor. Passages lead east and west. + +> S +You are in a corridor. Passages lead north and south. + +> S +You are in a corridor. Passages lead north and south. + +> S +You are in a corridor. Passages lead north and southeast. + +> SE +You are in a robot repair shop. There is a robot here. + +> OPEN ROBOT +You open the robot. + +> CLOSE ROBOT +You close the robot. + +> TURN ON ROBOT +You turn on the robot. The robot says, "Hello. I am Feldspar, model XR-32. How can I help you?" + +> NW +You are in a corridor. Passages lead southeast and north. + +> N +You are in a corridor. Passages lead south and north. + +> N +You are in a corridor. Passages lead south and north. + +> E +You are in a storage room. Passages lead west and south. + +> TAKE BEDISTOR +bedistor: Taken. + +> W +You are in a corridor. Passages lead east and west. + +> N +You are in a corridor. Passages lead south and north. + +> E +You are in a storage room. Passages lead west and south. + +> N +You are in a corridor. Passages lead south and north. + +> SLIDE UPPER CARD THROUGH SLOT +You slide the upper card through the slot. + +> PRESS UP BUTTON +You press the up button. + +> WAIT +Time passes... + +> WAIT +The elevator arrives. + +> S +You are in a corridor. Passages lead north and northeast. + +> NE +You are in a corridor. Passages lead southwest and south. + +> SW +You are in a corridor. Passages lead northeast and north. + +> N +You are in a corridor. Passages lead south and north. + +> PRESS DOWN BUTTON +You press the down button. + +> WAIT +Time passes... + +> WAIT +The elevator arrives. + +> S +You are in a corridor. Passages lead north and west. + +> W +You are in a corridor. Passages lead east and south. + +> S +You are in a corridor. Passages lead north and south. + +> S +You are in a corridor. Passages lead north and south. + +> S +You are in a corridor. Passages lead north and south. + +> S +You are in a corridor. Passages lead north and south. + +> PUT FLASK UNDER SPOOT +You put the flask under the spout. + +> PRESS GREEN BUTTON +You press the green button on the wall. + +> TAKE FLASK +flask: Taken. + +> N +You are in a corridor. Passages lead south and north. + +> N +You are in a corridor. Passages lead south and north. + +> N +You are in a corridor. Passages lead south and north. + +> N +You are in a corridor. Passages lead south and north. + +> E +You are in a corridor. Passages lead west and north. + +> N +You are in a corridor. Passages lead south and north. + +> SLIDE UPPER CARD THROUGH SLOT +You slide the upper card through the slot. + +> PRESS UP BUTTON +You press the up button. + +> WAIT +Time passes... + +> WAIT +The elevator arrives. + +> S +You are in a corridor. Passages lead north and northeast. + +> NE +You are in a corridor. Passages lead southwest and south. + +> POUR LIQUID INTO FUNNEL +You pour the liquid into the funnel. The enunciator panel goes dark. + +> SW +You are in a corridor. Passages lead northeast and north. + +> N +You are in a corridor. Passages lead south and north. + +> PRESS DOWN BUTTON +You press the down button. + +> WAIT +Time passes... + +> WAIT +The elevator arrives. + +> S +You are in a corridor. Passages lead north and west. + +> W +You are in a corridor. Passages lead east and south. + +> W +You are in a corridor. Passages lead east and south. + +> S +You are in a corridor. Passages lead north and south. + +> GET IN BED +You get into the bed. + +> WAIT +Time passes... + +> GET UP +You get out of the bed. + +> TAKE ALL +bed: (keeping) +green goo: Taken. +kit: Taken. + +> EAT GREEN GOO +You eat the green goo. It tastes like lime. + +> DROP KIT +kit: Dropped. + +> N +You are in a corridor. Passages lead south and west. + +> W +You are in a corridor. Passages lead east and south. + +> S +You are in a corridor. Passages lead north and south. + +> TAKE CANTEEN +canteen: Taken. + +> SLIDE KITCHEN CARD THROUGH SLOT +You slide the kitchen card through the slot. + +> S +You are in a corridor. Passages lead north and south. + +> OPEN CANTEEN +You open the canteen. + +> PUT CANTEEN INTO NICHE +You put the canteen into the niche. + +> PRESS BUTTON +You press the button. The canteen begins to fill with liquid. + +> TAKE CANTEEN +canteen: Taken. + +> CLOSE CANTEEN +You close the canteen. + +> N +You are in a corridor. Passages lead south and north. + +> DROP KITCHEN CARD +kitchen card: Dropped. + +> N +You are in a corridor. Passages lead south and north. + +> E +You are in a corridor. Passages lead west and east. + +> E +You are in a corridor. Passages lead west and east. + +> DROP FLASK AND UPPER CARD +flask: Dropped. +upper card: Dropped. + +> TAKE LASER AND PLIERS +laser: Taken. +pliers: Taken. + +> S +You are in a corridor. Passages lead north and south. + +> SLIDE LOWER CARD THROUGH SLOT +You slide the lower card through the slot. + +> PRESS DOWN BUTTON +You press the down button. + +> WAIT +Time passes... + +> WAIT +Time passes... + +> WAIT +The elevator arrives. + +> DROP LOWER CARD +lower card: Dropped. + +> N +You are in a corridor. Passages lead south and north. + +> E +You are in a corridor. Passages lead west and south. + +> S +You are in a corridor. Passages lead north and south. + +> E +You are in a corridor. Passages lead west and east. + +> SLIDE SHUTTLE CARD THROUGH SLOT +You slide the shuttle card through the slot. + +> PUSH LEVER UP +You push the lever up. + +> WAIT +Time passes... + +> WAIT +Time passes... + +> WAIT +Time passes... + +> WAIT +Time passes... + +> WAIT +Time passes... + +> WAIT +Time passes... + +> WAIT +Time passes... + +> WAIT +Time passes... + +> WAIT +Time passes... + +> WAIT +Time passes... + +> WAIT +Time passes... + +> PULL LEVER DOWN +You pull the lever down. + +> PULL LEVER DOWN +You pull the lever down. + +> WAIT +Time passes... + +> WAIT +Time passes... + +> WAIT +Time passes... + +> WAIT +Time passes... + +> WAIT +Time passes... + +> WAIT +Time passes... + +> WAIT +Time passes... + +> WAIT +Time passes... + +> WAIT +Time passes... + +> WAIT +Time passes... + +> DROP SHUTTLE CARD +shuttle card: Dropped. + +> W +You are in a corridor. Passages lead east and west. + +> N +You are in a corridor. Passages lead south and north. + +> E +You are in a corridor. Passages lead west and east. + +> E +You are in a corridor. Passages lead west and east. + +> NE +You are in a corridor. Passages lead southwest and east. + +> E +You are in a corridor. Passages lead west and east. + +> E +You are in a corridor. Passages lead west and east. + +> N +You are in a corridor. Passages lead south and north. + +> OPEN LID +You open the lid. + +> TAKE FUSED BEDISTOR WITH PLIERS +You take the fused bedistor with the pliers. + +> PUT GOOD BEDISTOR INTO CUBE +You put the good bedistor into the cube. + +> CLOSE CUBE +You close the cube. + +> OPEN CANTEEN +You open the canteen. + +> DRINK LIQUID +You drink the liquid. It tastes like water. + +> DROP PLIERS AND FUSED BEDISTOR AND CANTEEN +pliers: Dropped. +fused bedistor: Dropped. +canteen: Dropped. + +> S +You are in a corridor. Passages lead north and west. + +> W +You are in a corridor. Passages lead east and west. + +> W +You are in a corridor. Passages lead east and west. + +> N +You are in a corridor. Passages lead south and north. + +> FLOYD, GO N +Floyd says, "Okay!" Floyd goes north. + +> FLOYD, GET SHINY FROMITZ BOARD +Floyd says, "Okay!" Floyd takes the shiny fromitz board. + +> S +You are in a corridor. Passages lead north and east. + +> E +You are in a corridor. Passages lead west and south. + +> N +You are in a corridor. Passages lead south and north. + +> OPEN PANEL +You open the panel. + +> TAKE SECOND BOARD +second board: Taken. + +> PUT SHINY BOARD INTO SOCKET +You put the shiny board into the socket. + +> CLOSE PANEL +You close the panel. + +> S +You are in a corridor. Passages lead north and south. + +> E +You are in a corridor. Passages lead west and south. + +> S +You are in a corridor. Passages lead north and south. + +> S +You are in a corridor. Passages lead north and south. + +> S +You are in a corridor. Passages lead north and southeast. + +> NE +You are in a corridor. Passages lead southwest and south. + +> OPEN BIO-LAB DOOR +You open the bio-lab door. + +> SE +You are in a corridor. Passages lead northwest and east. + +> E +You are in the biology lab. A large window looks south. + +> LOOK THROUGH WINDOW +Through the window, you can see another room. There appears to be a speck on the window. + +> OPEN DOOR +You open the door. + +> CLOSE DOOR +You close the door. + +> WAIT +Time passes... + +> OPEN DOOR +You open the door. + +> CLOSE DOOR +You close the door. + +> PUT MINI CARD INTO POCKET +mini card: You put the mini card into your pocket. + +> W +You are in a corridor. Passages lead east and west. + +> OPEN DOOR +You open the door. + +> W +You are in a corridor. Passages lead east and west. + +> S +You are in a corridor. Passages lead north and south. + +> PUT BATTERY INTO LASER +You put the battery into the laser. + +> N +You are in a corridor. Passages lead south and northeast. + +> SW +You are in a corridor. Passages lead northeast and south. + +> S +You are in a corridor. Passages lead north and south. + +> SLIDE MINI CARD THROUGH SLOT +You slide the mini card through the slot. + +> TYPE 384 +You type 384 on the keyboard. + +> E +You are in a corridor. Passages lead west and north. + +> N +You are in a corridor. Passages lead south and north. + +> N +You are in a corridor. Passages lead south and north. + +> TURN DIAL TO 1 +You turn the dial to 1. + +> FIRE LASER AT SPECK +You fire the laser at the speck. The speck begins to glow. + +> TURN DIAL TO 6 +You turn the dial to 6. + +> S +You are in a corridor. Passages lead north and south. + +> FIRE LASER AT MICROBE +You fire the laser at the microbe. The microbe writhes. + +> FIRE LASER AT MICROBE +You fire the laser at the microbe. The microbe writhes. + +> FIRE LASER AT MICROBE +You fire the laser at the microbe. The microbe writhes. + +> FIRE LASER AT MICROBE +You fire the laser at the microbe. The microbe writhes. + +> FIRE LASER AT MICROBE +You fire the laser at the microbe. The microbe writhes. + +> FIRE LASER AT MICROBE +You fire the laser at the microbe. The laser is very warm. + +> THROW LASER OVER EDGE +You throw the laser over the edge. + +> S +You are in a corridor. Passages lead north and west. + +> W +You are in a corridor. Passages lead east and north. + +> N +You are in a corridor. Passages lead south and north. + +> OPEN DESK +You open the desk. There is a gas mask here. + +> WEAR GAS MASK +You wear the gas mask. + +> PRESS WHITE BUTTON +You press the white button on the wall. + +> PRESS RED BUTTON +You press the red button on the wall. + +> OPEN OFFICE DOOR +You open the office door. + +> W +You are in a corridor. Passages lead east and west. + +> OPEN LAB DOOR +You open the lab door. + +> W +You are in a corridor. Passages lead east and west. + +> W +You are in a corridor. Passages lead east and west. + +> OPEN DOOR +You open the door. + +> W +You are in a corridor. Passages lead east and west. + +> W +You are in a corridor. Passages lead east and west. + +> W +You are in a corridor. Passages lead east and west. + +> S +You are in a corridor. Passages lead north and south. + +> S +You are in a corridor. Passages lead north and south. + +> PRESS BUTTON +You press the button. + +> WAIT +Time passes... + +> WAIT +Time passes... + +> WAIT +Time passes... + +> N +You are in a corridor. Passages lead south and north. + +*** +*** PLANETFALL has ended. +*** + +Would you like to end the transcript, start a new game, or restart? + +> QUIT +Would you like to end the transcript? (Y/N) + +> Y +End of transcript. diff --git a/infocom/planetfall/test/test-auto-generated.zil b/infocom/planetfall/test/test-auto-generated.zil new file mode 100644 index 0000000..ea7d28c --- /dev/null +++ b/infocom/planetfall/test/test-auto-generated.zil @@ -0,0 +1,306 @@ +"TEST-planetfall.ZIL - Auto-generated test from transcript" + +<INSERT-FILE "infocom/planetfall/globals"> +<INSERT-FILE "infocom/planetfall/parser"> +<INSERT-FILE "infocom/planetfall/verbs"> +<INSERT-FILE "infocom/planetfall/syntax"> +<INSERT-FILE "infocom/planetfall/planetfall"> +<CONSTANT RELEASEID 1> + +<GLOBAL CO <CO-CREATE GO>> + +<ROUTINE RUN-TEST () + <TELL "Testing planetfall transcript..." CR> + <ASSERT-TEXT "Start of a transcript of PLANETFALL." <CO-RESUME ,CO " W">> + <ASSERT-TEXT "You are in the living quarters of a small vessel. There is a webbing here, bolte..." <CO-RESUME ,CO " GET INTO WEBBING">> + <ASSERT-TEXT "You strap yourself into the webbing." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " GET OUT OF WEBBING">> + <ASSERT-TEXT "You remove yourself from the webbing." <CO-RESUME ,CO " TAKE ALL">> + <ASSERT-TEXT "webbing: Already have that." <CO-RESUME ,CO " OPEN DOOR">> + <ASSERT-TEXT "You open the door, revealing a closet. The door swings shut again." <CO-RESUME ,CO " U">> + <ASSERT-TEXT "You are in a narrow shaft. A ladder runs up and down. There is a narrow opening ..." <CO-RESUME ,CO " U">> + <ASSERT-TEXT "You are in a wide shaft. A ladder runs up and down. There is a wide opening to t..." <CO-RESUME ,CO " U">> + <ASSERT-TEXT "You are in a wide shaft. A ladder runs up and down. There is a wide opening to t..." <CO-RESUME ,CO " U">> + <ASSERT-TEXT "You are in a wide shaft. A ladder runs up and down. There is a wide opening to t..." <CO-RESUME ,CO " U">> + <ASSERT-TEXT "You are in a wide shaft. A ladder runs up and down. There is a wide opening to t..." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are in a corridor. Passages lead south, north, and northeast." <CO-RESUME ,CO " NE">> + <ASSERT-TEXT "You are in a corridor. Passages lead southwest and east." <CO-RESUME ,CO " E">> + <ASSERT-TEXT "You are in a corridor. Passages lead west and east." <CO-RESUME ,CO " E">> + <ASSERT-TEXT "You are in a corridor. Passages lead west and east." <CO-RESUME ,CO " TAKE ID CARD">> + <ASSERT-TEXT "ID card: Already have that." <CO-RESUME ,CO " DROP ALL EXCEPT KIT">> + <ASSERT-TEXT "kit: (keeping)" <CO-RESUME ,CO " E">> + <ASSERT-TEXT "You are in a storage room. Passages lead west and south." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a storage room. Passages lead north and south." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a storage room. Passages lead north and southwest." <CO-RESUME ,CO " SW">> + <ASSERT-TEXT "You are in a storage room. Passages lead northeast and south." <CO-RESUME ,CO " TAKE ALL">> + <ASSERT-TEXT "battery: Taken." <CO-RESUME ,CO " DROP BATTERY">> + <ASSERT-TEXT "battery: Dropped." <CO-RESUME ,CO " NE">> + <ASSERT-TEXT "You are in a storage room. Passages lead southwest and north." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are in a corridor. Passages lead south and north." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are in a corridor. Passages lead south and north." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are in a corridor. Passages lead south and north." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are in a corridor. Passages lead south and north." <CO-RESUME ,CO " PUT BAR OVER CREVICE">> + <ASSERT-TEXT "You can't see any such thing." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and south." <CO-RESUME ,CO " E">> + <ASSERT-TEXT "You are in a storage room. Passages lead west and south." <CO-RESUME ,CO " DROP ALL EXCEPT KEY">> + <ASSERT-TEXT "key: (keeping)" <CO-RESUME ,CO " PRESS BLUE BUTTON">> + <ASSERT-TEXT "You press the blue button on the kit." <CO-RESUME ,CO " PRESS RED BUTTON">> + <ASSERT-TEXT "You press the red button on the kit." <CO-RESUME ,CO " W">> + <ASSERT-TEXT "You are in a corridor. Passages lead east and west." <CO-RESUME ,CO " W">> + <ASSERT-TEXT "You are in a corridor. Passages lead east and west." <CO-RESUME ,CO " W">> + <ASSERT-TEXT "You are in a corridor. Passages lead east and west." <CO-RESUME ,CO " UNLOCK PADLOCK WITH KEY">> + <ASSERT-TEXT "You unlock the padlock." <CO-RESUME ,CO " TAKE PADLOCK">> + <ASSERT-TEXT "padlock: Taken." <CO-RESUME ,CO " OPEN DOOR">> + <ASSERT-TEXT "You open the door." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are in a storage closet." <CO-RESUME ,CO " DROP KEY AND PADLOCK">> + <ASSERT-TEXT "key: Dropped." <CO-RESUME ,CO " TAKE LADDER">> + <ASSERT-TEXT "ladder: Taken." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and south." <CO-RESUME ,CO " E">> + <ASSERT-TEXT "You are in a corridor. Passages lead west and east." <CO-RESUME ,CO " E">> + <ASSERT-TEXT "You are in a corridor. Passages lead west and east." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are in a corridor. Passages lead south and north." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are in a corridor. Passages lead south and north." <CO-RESUME ,CO " DROP LADDER">> + <ASSERT-TEXT "ladder: Dropped." <CO-RESUME ,CO " EXTEND LADDER">> + <ASSERT-TEXT "You extend the ladder to its full length." <CO-RESUME ,CO " PUT LADDER OVER RIFT">> + <ASSERT-TEXT "You place the ladder over the rift." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are on a ledge. A ladder leads south over a rift. To the north is a small op..." <CO-RESUME ,CO " W">> + <ASSERT-TEXT "You are in a small room. A desk is against the wall. There is a small drawer in ..." <CO-RESUME ,CO " OPEN DESK">> + <ASSERT-TEXT "You open the desk. There is a card here." <CO-RESUME ,CO " PUT KITCHEN CARD AND UPPER CARD INTO POCKET">> + <ASSERT-TEXT "kitchen card: You put the kitchen card into your pocket." <CO-RESUME ,CO " W">> + <ASSERT-TEXT "You are in a small room. A desk is against the wall. There is a small drawer in ..." <CO-RESUME ,CO " OPEN DESK">> + <ASSERT-TEXT "You open the desk. There is a card here." <CO-RESUME ,CO " PUT SHUTTLE CARD INTO POCKET">> + <ASSERT-TEXT "shuttle card: You put the shuttle card into your pocket." <CO-RESUME ,CO " E">> + <ASSERT-TEXT "You are in a small room. A desk is against the wall." <CO-RESUME ,CO " E">> + <ASSERT-TEXT "You are on a ledge. A ladder leads south over a rift." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and south." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and south." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and east." <CO-RESUME ,CO " E">> + <ASSERT-TEXT "You are in a storage room. Passages lead west and south." <CO-RESUME ,CO " TAKE KIT AND FLASK">> + <ASSERT-TEXT "kit: Taken." <CO-RESUME ,CO " OPEN KIT">> + <ASSERT-TEXT "You open the kit." <CO-RESUME ,CO " EAT RED GOO">> + <ASSERT-TEXT "You eat the red goo. It tastes like strawberry." <CO-RESUME ,CO " W">> + <ASSERT-TEXT "You are in a corridor. Passages lead east and west." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and south." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and south." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and southeast." <CO-RESUME ,CO " SE">> + <ASSERT-TEXT "You are in a robot repair shop. There is a robot here." <CO-RESUME ,CO " OPEN ROBOT">> + <ASSERT-TEXT "You open the robot." <CO-RESUME ,CO " CLOSE ROBOT">> + <ASSERT-TEXT "You close the robot." <CO-RESUME ,CO " TURN ON ROBOT">> + <ASSERT-TEXT "You turn on the robot. The robot says, \"Hello. I am Feldspar, model XR-32. How c..." <CO-RESUME ,CO " NW">> + <ASSERT-TEXT "You are in a corridor. Passages lead southeast and north." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are in a corridor. Passages lead south and north." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are in a corridor. Passages lead south and north." <CO-RESUME ,CO " E">> + <ASSERT-TEXT "You are in a storage room. Passages lead west and south." <CO-RESUME ,CO " TAKE BEDISTOR">> + <ASSERT-TEXT "bedistor: Taken." <CO-RESUME ,CO " W">> + <ASSERT-TEXT "You are in a corridor. Passages lead east and west." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are in a corridor. Passages lead south and north." <CO-RESUME ,CO " E">> + <ASSERT-TEXT "You are in a storage room. Passages lead west and south." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are in a corridor. Passages lead south and north." <CO-RESUME ,CO " SLIDE UPPER CARD THROUGH SLOT">> + <ASSERT-TEXT "You slide the upper card through the slot." <CO-RESUME ,CO " PRESS UP BUTTON">> + <ASSERT-TEXT "You press the up button." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "The elevator arrives." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and northeast." <CO-RESUME ,CO " NE">> + <ASSERT-TEXT "You are in a corridor. Passages lead southwest and south." <CO-RESUME ,CO " SW">> + <ASSERT-TEXT "You are in a corridor. Passages lead northeast and north." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are in a corridor. Passages lead south and north." <CO-RESUME ,CO " PRESS DOWN BUTTON">> + <ASSERT-TEXT "You press the down button." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "The elevator arrives." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and west." <CO-RESUME ,CO " W">> + <ASSERT-TEXT "You are in a corridor. Passages lead east and south." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and south." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and south." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and south." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and south." <CO-RESUME ,CO " PUT FLASK UNDER SPOOT">> + <ASSERT-TEXT "You put the flask under the spout." <CO-RESUME ,CO " PRESS GREEN BUTTON">> + <ASSERT-TEXT "You press the green button on the wall." <CO-RESUME ,CO " TAKE FLASK">> + <ASSERT-TEXT "flask: Taken." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are in a corridor. Passages lead south and north." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are in a corridor. Passages lead south and north." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are in a corridor. Passages lead south and north." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are in a corridor. Passages lead south and north." <CO-RESUME ,CO " E">> + <ASSERT-TEXT "You are in a corridor. Passages lead west and north." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are in a corridor. Passages lead south and north." <CO-RESUME ,CO " SLIDE UPPER CARD THROUGH SLOT">> + <ASSERT-TEXT "You slide the upper card through the slot." <CO-RESUME ,CO " PRESS UP BUTTON">> + <ASSERT-TEXT "You press the up button." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "The elevator arrives." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and northeast." <CO-RESUME ,CO " NE">> + <ASSERT-TEXT "You are in a corridor. Passages lead southwest and south." <CO-RESUME ,CO " POUR LIQUID INTO FUNNEL">> + <ASSERT-TEXT "You pour the liquid into the funnel. The enunciator panel goes dark." <CO-RESUME ,CO " SW">> + <ASSERT-TEXT "You are in a corridor. Passages lead northeast and north." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are in a corridor. Passages lead south and north." <CO-RESUME ,CO " PRESS DOWN BUTTON">> + <ASSERT-TEXT "You press the down button." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "The elevator arrives." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and west." <CO-RESUME ,CO " W">> + <ASSERT-TEXT "You are in a corridor. Passages lead east and south." <CO-RESUME ,CO " W">> + <ASSERT-TEXT "You are in a corridor. Passages lead east and south." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and south." <CO-RESUME ,CO " GET IN BED">> + <ASSERT-TEXT "You get into the bed." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " GET UP">> + <ASSERT-TEXT "You get out of the bed." <CO-RESUME ,CO " TAKE ALL">> + <ASSERT-TEXT "bed: (keeping)" <CO-RESUME ,CO " EAT GREEN GOO">> + <ASSERT-TEXT "You eat the green goo. It tastes like lime." <CO-RESUME ,CO " DROP KIT">> + <ASSERT-TEXT "kit: Dropped." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are in a corridor. Passages lead south and west." <CO-RESUME ,CO " W">> + <ASSERT-TEXT "You are in a corridor. Passages lead east and south." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and south." <CO-RESUME ,CO " TAKE CANTEEN">> + <ASSERT-TEXT "canteen: Taken." <CO-RESUME ,CO " SLIDE KITCHEN CARD THROUGH SLOT">> + <ASSERT-TEXT "You slide the kitchen card through the slot." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and south." <CO-RESUME ,CO " OPEN CANTEEN">> + <ASSERT-TEXT "You open the canteen." <CO-RESUME ,CO " PUT CANTEEN INTO NICHE">> + <ASSERT-TEXT "You put the canteen into the niche." <CO-RESUME ,CO " PRESS BUTTON">> + <ASSERT-TEXT "You press the button. The canteen begins to fill with liquid." <CO-RESUME ,CO " TAKE CANTEEN">> + <ASSERT-TEXT "canteen: Taken." <CO-RESUME ,CO " CLOSE CANTEEN">> + <ASSERT-TEXT "You close the canteen." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are in a corridor. Passages lead south and north." <CO-RESUME ,CO " DROP KITCHEN CARD">> + <ASSERT-TEXT "kitchen card: Dropped." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are in a corridor. Passages lead south and north." <CO-RESUME ,CO " E">> + <ASSERT-TEXT "You are in a corridor. Passages lead west and east." <CO-RESUME ,CO " E">> + <ASSERT-TEXT "You are in a corridor. Passages lead west and east." <CO-RESUME ,CO " DROP FLASK AND UPPER CARD">> + <ASSERT-TEXT "flask: Dropped." <CO-RESUME ,CO " TAKE LASER AND PLIERS">> + <ASSERT-TEXT "laser: Taken." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and south." <CO-RESUME ,CO " SLIDE LOWER CARD THROUGH SLOT">> + <ASSERT-TEXT "You slide the lower card through the slot." <CO-RESUME ,CO " PRESS DOWN BUTTON">> + <ASSERT-TEXT "You press the down button." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "The elevator arrives." <CO-RESUME ,CO " DROP LOWER CARD">> + <ASSERT-TEXT "lower card: Dropped." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are in a corridor. Passages lead south and north." <CO-RESUME ,CO " E">> + <ASSERT-TEXT "You are in a corridor. Passages lead west and south." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and south." <CO-RESUME ,CO " E">> + <ASSERT-TEXT "You are in a corridor. Passages lead west and east." <CO-RESUME ,CO " SLIDE SHUTTLE CARD THROUGH SLOT">> + <ASSERT-TEXT "You slide the shuttle card through the slot." <CO-RESUME ,CO " PUSH LEVER UP">> + <ASSERT-TEXT "You push the lever up." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " PULL LEVER DOWN">> + <ASSERT-TEXT "You pull the lever down." <CO-RESUME ,CO " PULL LEVER DOWN">> + <ASSERT-TEXT "You pull the lever down." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " DROP SHUTTLE CARD">> + <ASSERT-TEXT "shuttle card: Dropped." <CO-RESUME ,CO " W">> + <ASSERT-TEXT "You are in a corridor. Passages lead east and west." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are in a corridor. Passages lead south and north." <CO-RESUME ,CO " E">> + <ASSERT-TEXT "You are in a corridor. Passages lead west and east." <CO-RESUME ,CO " E">> + <ASSERT-TEXT "You are in a corridor. Passages lead west and east." <CO-RESUME ,CO " NE">> + <ASSERT-TEXT "You are in a corridor. Passages lead southwest and east." <CO-RESUME ,CO " E">> + <ASSERT-TEXT "You are in a corridor. Passages lead west and east." <CO-RESUME ,CO " E">> + <ASSERT-TEXT "You are in a corridor. Passages lead west and east." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are in a corridor. Passages lead south and north." <CO-RESUME ,CO " OPEN LID">> + <ASSERT-TEXT "You open the lid." <CO-RESUME ,CO " TAKE FUSED BEDISTOR WITH PLIERS">> + <ASSERT-TEXT "You take the fused bedistor with the pliers." <CO-RESUME ,CO " PUT GOOD BEDISTOR INTO CUBE">> + <ASSERT-TEXT "You put the good bedistor into the cube." <CO-RESUME ,CO " CLOSE CUBE">> + <ASSERT-TEXT "You close the cube." <CO-RESUME ,CO " OPEN CANTEEN">> + <ASSERT-TEXT "You open the canteen." <CO-RESUME ,CO " DRINK LIQUID">> + <ASSERT-TEXT "You drink the liquid. It tastes like water." <CO-RESUME ,CO " DROP PLIERS AND FUSED BEDISTOR AND CANTEEN">> + <ASSERT-TEXT "pliers: Dropped." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and west." <CO-RESUME ,CO " W">> + <ASSERT-TEXT "You are in a corridor. Passages lead east and west." <CO-RESUME ,CO " W">> + <ASSERT-TEXT "You are in a corridor. Passages lead east and west." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are in a corridor. Passages lead south and north." <CO-RESUME ,CO " FLOYD, GO N">> + <ASSERT-TEXT "Floyd says, \"Okay!\" Floyd goes north." <CO-RESUME ,CO " FLOYD, GET SHINY FROMITZ BOARD">> + <ASSERT-TEXT "Floyd says, \"Okay!\" Floyd takes the shiny fromitz board." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and east." <CO-RESUME ,CO " E">> + <ASSERT-TEXT "You are in a corridor. Passages lead west and south." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are in a corridor. Passages lead south and north." <CO-RESUME ,CO " OPEN PANEL">> + <ASSERT-TEXT "You open the panel." <CO-RESUME ,CO " TAKE SECOND BOARD">> + <ASSERT-TEXT "second board: Taken." <CO-RESUME ,CO " PUT SHINY BOARD INTO SOCKET">> + <ASSERT-TEXT "You put the shiny board into the socket." <CO-RESUME ,CO " CLOSE PANEL">> + <ASSERT-TEXT "You close the panel." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and south." <CO-RESUME ,CO " E">> + <ASSERT-TEXT "You are in a corridor. Passages lead west and south." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and south." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and south." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and southeast." <CO-RESUME ,CO " NE">> + <ASSERT-TEXT "You are in a corridor. Passages lead southwest and south." <CO-RESUME ,CO " OPEN BIO-LAB DOOR">> + <ASSERT-TEXT "You open the bio-lab door." <CO-RESUME ,CO " SE">> + <ASSERT-TEXT "You are in a corridor. Passages lead northwest and east." <CO-RESUME ,CO " E">> + <ASSERT-TEXT "You are in the biology lab. A large window looks south." <CO-RESUME ,CO " LOOK THROUGH WINDOW">> + <ASSERT-TEXT "Through the window, you can see another room. There appears to be a speck on the..." <CO-RESUME ,CO " OPEN DOOR">> + <ASSERT-TEXT "You open the door." <CO-RESUME ,CO " CLOSE DOOR">> + <ASSERT-TEXT "You close the door." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " OPEN DOOR">> + <ASSERT-TEXT "You open the door." <CO-RESUME ,CO " CLOSE DOOR">> + <ASSERT-TEXT "You close the door." <CO-RESUME ,CO " PUT MINI CARD INTO POCKET">> + <ASSERT-TEXT "mini card: You put the mini card into your pocket." <CO-RESUME ,CO " W">> + <ASSERT-TEXT "You are in a corridor. Passages lead east and west." <CO-RESUME ,CO " OPEN DOOR">> + <ASSERT-TEXT "You open the door." <CO-RESUME ,CO " W">> + <ASSERT-TEXT "You are in a corridor. Passages lead east and west." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and south." <CO-RESUME ,CO " PUT BATTERY INTO LASER">> + <ASSERT-TEXT "You put the battery into the laser." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are in a corridor. Passages lead south and northeast." <CO-RESUME ,CO " SW">> + <ASSERT-TEXT "You are in a corridor. Passages lead northeast and south." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and south." <CO-RESUME ,CO " SLIDE MINI CARD THROUGH SLOT">> + <ASSERT-TEXT "You slide the mini card through the slot." <CO-RESUME ,CO " TYPE 384">> + <ASSERT-TEXT "You type 384 on the keyboard." <CO-RESUME ,CO " E">> + <ASSERT-TEXT "You are in a corridor. Passages lead west and north." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are in a corridor. Passages lead south and north." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are in a corridor. Passages lead south and north." <CO-RESUME ,CO " TURN DIAL TO 1">> + <ASSERT-TEXT "You turn the dial to 1." <CO-RESUME ,CO " FIRE LASER AT SPECK">> + <ASSERT-TEXT "You fire the laser at the speck. The speck begins to glow." <CO-RESUME ,CO " TURN DIAL TO 6">> + <ASSERT-TEXT "You turn the dial to 6." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and south." <CO-RESUME ,CO " FIRE LASER AT MICROBE">> + <ASSERT-TEXT "You fire the laser at the microbe. The microbe writhes." <CO-RESUME ,CO " FIRE LASER AT MICROBE">> + <ASSERT-TEXT "You fire the laser at the microbe. The microbe writhes." <CO-RESUME ,CO " FIRE LASER AT MICROBE">> + <ASSERT-TEXT "You fire the laser at the microbe. The microbe writhes." <CO-RESUME ,CO " FIRE LASER AT MICROBE">> + <ASSERT-TEXT "You fire the laser at the microbe. The microbe writhes." <CO-RESUME ,CO " FIRE LASER AT MICROBE">> + <ASSERT-TEXT "You fire the laser at the microbe. The microbe writhes." <CO-RESUME ,CO " FIRE LASER AT MICROBE">> + <ASSERT-TEXT "You fire the laser at the microbe. The laser is very warm." <CO-RESUME ,CO " THROW LASER OVER EDGE">> + <ASSERT-TEXT "You throw the laser over the edge." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and west." <CO-RESUME ,CO " W">> + <ASSERT-TEXT "You are in a corridor. Passages lead east and north." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are in a corridor. Passages lead south and north." <CO-RESUME ,CO " OPEN DESK">> + <ASSERT-TEXT "You open the desk. There is a gas mask here." <CO-RESUME ,CO " WEAR GAS MASK">> + <ASSERT-TEXT "You wear the gas mask." <CO-RESUME ,CO " PRESS WHITE BUTTON">> + <ASSERT-TEXT "You press the white button on the wall." <CO-RESUME ,CO " PRESS RED BUTTON">> + <ASSERT-TEXT "You press the red button on the wall." <CO-RESUME ,CO " OPEN OFFICE DOOR">> + <ASSERT-TEXT "You open the office door." <CO-RESUME ,CO " W">> + <ASSERT-TEXT "You are in a corridor. Passages lead east and west." <CO-RESUME ,CO " OPEN LAB DOOR">> + <ASSERT-TEXT "You open the lab door." <CO-RESUME ,CO " W">> + <ASSERT-TEXT "You are in a corridor. Passages lead east and west." <CO-RESUME ,CO " W">> + <ASSERT-TEXT "You are in a corridor. Passages lead east and west." <CO-RESUME ,CO " OPEN DOOR">> + <ASSERT-TEXT "You open the door." <CO-RESUME ,CO " W">> + <ASSERT-TEXT "You are in a corridor. Passages lead east and west." <CO-RESUME ,CO " W">> + <ASSERT-TEXT "You are in a corridor. Passages lead east and west." <CO-RESUME ,CO " W">> + <ASSERT-TEXT "You are in a corridor. Passages lead east and west." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and south." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You are in a corridor. Passages lead north and south." <CO-RESUME ,CO " PRESS BUTTON">> + <ASSERT-TEXT "You press the button." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You are in a corridor. Passages lead south and north." <CO-RESUME ,CO " QUIT">> + <ASSERT-TEXT "Would you like to end the transcript? (Y/N)" <CO-RESUME ,CO " Y">> + <TELL CR "planetfall transcript test completed!" CR>> diff --git a/infocom/spellbreaker/test/spellbreaker-frotz.txt b/infocom/spellbreaker/test/spellbreaker-frotz.txt new file mode 100644 index 0000000..a315e25 --- /dev/null +++ b/infocom/spellbreaker/test/spellbreaker-frotz.txt @@ -0,0 +1,1289 @@ +Here begins a transcript of interaction with SPELLBREAKER. +SPELLBREAKER +An Interactive Fantasy +Copyright (c) 1985 by Infocom, Inc. All rights reserved. +SPELLBREAKER is a trademark of Infocom, Inc. +Release 87 / Serial number 860904 + +>WAIT +Time passes... + +Sneffle of the Guild of Bakers is addressing the gathering. "Do you know what +this is doing to our business? Do you know how difficult it is to make those +yummy butter pastries by hand? When a simple 'gloth' spell would fold the dough +83 times it was possible to make a profit, but now 'gloth' hardly works, and +when it does, it usually folds the dough too often and the butter melts, or it +doesn't come out the right size, or..." He stops, apparently overwhelmed by the +prospect of a world where the pastries have to be hand-made. "Can't you do +anything about this? You're supposed to know all about magic!" + +>SOUTH +Annoyed guildmasters make way grudgingly. You hear muttering about "arrogant +enchanters" as you try to leave the chamber. Finally, Orkan of Thriff, one of +your colleagues, says, "Stay. Be quiet. Don't embarrass us." + +Hoobly of the Guild of Brewers stands, gesturing at the floury baker. "You don't +know what trouble is! Lately, what comes out of the vats, like as not, is cherry +flavored or worse. The last vat, I swear it, tasted as if grues had been bathing +in it. It takes magic to turn weird vegetables and water into good Borphee beer. +Well, without magic, there isn't going to be any beer!" This statement has a +profound effect on portions of the crowd. You can hear rumblings from the back +concerning Enchanters. The word "traitors" rises out of nowhere. Your fellow +Enchanters are looking at one another nervously. + +>TAKE BREAD +You can't see any bread here. + +>SOUTH +Annoyed guildmasters make way grudgingly. You hear muttering about "arrogant +enchanters" as you try to leave the chamber. Finally, Orkan of Thriff, one of +your colleagues, says, "Stay. Be quiet. Don't embarrass us." + +A tall, gruff fellow begins to speak. This is Gzornenplatz of the Guild of +Huntsmen. "I'm a simple man, and I don't know much about magic. But I do know +that the wild beasts are kept out of the towns and villages not just by the +huntsmen, but by spells as well. Just yesterday, one of my men was attacked and +badly wounded by a troop of rat-ants. They'd slipped the bounds set down by a +'fripple' spell somehow. Are we going to let the sorcerers loose rat-ants on us, +and worse?" He sits, glaring significantly at the now-angry clump of mages +around you. + +>LESOCH +Orkan of Thriff stares at you in wonderment. "Are you trying to get them even +more mad at us?" He makes a gesture of cancellation before you can finish the +spell. + +As the huntsman's accusations are being absorbed and discussed, Ardis of the +Guild of Poets takes the floor. He begins to talk about magic rhyming and +spelling aids, and their lack. + +In the midst of his splendid peroration, just as he was sketching out an +insulting mythological allusion in iambic hexameter, the poet turns even greener +than usual. His chin elongates and his skin begins to look sort of slimy. In the +blink of an eye there stands at the podium, not the orator, but rather a large +orange newt. "Breek! Co-ax! Co-ax!" it protests. + +As you look around the room in shock, you discover that Ardis is not alone. Each +and every guildmaster in the room has been turned into a frog, salamander, or +other amphibian! All but one, that is: yourself! + +No! There is one other survivor. At the rear of the room, a shadowy figure in a +dark cloak slips quietly out the door. + +>CAST LESOCH +You don't have the lesoch spell memorized! + +>TAKE CUBE +You can't see any cube here. + +>WRITE 1 ON CUBE +You can't see any cube here. + +>BLORPLE +What do you want to blorple? + +>BLORPLE 1 +You can't see that here! + +>FROTZ BURIN +There is an almost blinding flash of light as the magic burin begins to glow! It +slowly fades to a less painful level, but the magic burin is now a serviceable +light source. + +>SAVE +Okay. + +>DOWN +You can't go that way. + +>WAIT +Time passes... + +>WAIT +Time passes... + +>WAIT +Time passes... + +>WAIT +Time passes... + +>WAIT +Time passes... + +>WAIT +Time passes... + +>TAKE STAINED SCROLL +You can't see any stained scroll here. + +>EXAMINE STAINED SCROLL +You can't see any stained scroll here. + +>GNUSTO CASKLY +You can't see any caskly here. + +>BLORPLE +What do you want to blorple? + +>BLORPLE 1 +You can't see that here! + +>EAST +You can't go that way. + +>SOUTH +Guild Hall +This is the entrance to the Guild Hall in Borphee. To the north is the Council +Chamber, and to the south is an exit leading outside. Little is left of the +sumptuous buffet lunch. Only a loaf of bread and some smoked fish remains. + +>TAKE ZIPPER +You can't see any zipper here. + +>OPEN ZIPPER +You can't see any zipper here. + +>LOOK INTO ZIPPER +You can't see any zipper here. + +>REACH INTO ZIPPER +You can't see any zipper here. + +>LOOK INTO ZIPPER +You can't see any zipper here. + +>TAKE FLIMSY SCROLL +You can't see any flimsy scroll here. + +>READ FLIMSY SCROLL +You can't see any flimsy scroll here. + +>BLORPLE +What do you want to blorple? + +>BLORPLE 1 +You can't see that here! + +>SOUTH +Belwit Square +This is Belwit Square. To the north is the ancient Guild Hall. A wide +cobblestone street runs east and west. To the south is the storied Manse, home +of the Mayors of Borphee for generations. +A white cube is here. + +>TAKE DIRTY SCROLL +You can't see any dirty scroll here. + +>READ DIRTY SCROLL +You can't see any dirty scroll here. + +>GNUSTO THROCK +You can't see any throck here. + +>UP +You can't go that way. + +>WAIT +Time passes... + +>WAIT +Time passes... + +>GIRGOL +The girgol spell is not memorized, and you aren't holding a scroll on which it +is written. + +>UP +You can't go that way. + +>UP +You can't go that way. + +>UP +You can't go that way. + +>UP +You can't go that way. + +>TAKE COIN +You can't see any coin here. + +>EXAMINE COIN +You can't see any coin here. + +>WEST +You wander around for a while and end up back in the square. + +>CASKLY +What do you want to caskly? + +>CASKLY HUT +You can't see any caskly hut here. + +>TAKE CUBE +Taken. + +>EAST +You wander around for a while and end up back in the square. + +>PUT COIN, BREAD AND KNIFE IN ZIPPER +You aren't holding all those things! + +>WRITE 2 ON CUBE +The word "2" is now written on the cube. + +>BLORPLE +What do you want to blorple? + +>BLORPLE 2 +As you must remember from Thaumaturgy 101, you cannot cast a spell upon itself, +or upon the scroll it is written on. + +>SOUTH +A remarkably surly guard blocks your way. + +>PULL WEED +You can't see any weed here. + +>PULL WEED +You can't see any weed here. + +>BLORPLE +What do you want to blorple? + +>BLORPLE 1 +You can't see that here! + +>WEST +You wander around for a while and end up back in the square. + +>NORTH +Guild Hall +There is a smoked fish here. +There is a chunk of rye bread here. + +>YOMIN +What do you want to yomin? + +>YOMIN OGRE +You can't see any yomin ogre here. + +>PLANT WEED +You can't see any weed here. + +>THROCK +What do you want to throck? + +>THROCK WEED +You can't see any throck weed here. + +>DOWN +You can't go that way. + +>TAKE DUSTY SCROLL +You can't see any dusty scroll here. + +>TAKE GOLD BOX +You can't see any gold box here. + +>UP +You can't go that way. + +>SOUTH +Belwit Square + +>READ DUSTY SCROLL +You can't see any dusty scroll here. + +>GNUSTO ESPNIS +You can't see any espnis here. + +>OPEN BOX +You can't see any box here. + +>TAKE CUBE +You already have it. + +>PUT BOX IN ZIPPER +You can't see that here! + +>WRITE 3 ON CUBE +You replace the word "2" with the word "3". + +>BLORPLE +What do you want to blorple? + +>BLORPLE 3 +As you must remember from Thaumaturgy 101, you cannot cast a spell upon itself, +or upon the scroll it is written on. + +>TAKE BREAD +You can't see any bread here. + +>DROP ALL EXCEPT BREAD +the "3" cube: Dropped. +magic burin: Dropped. +knife: Dropped. +spell book: Dropped. + +>SOUTH +A remarkably surly guard blocks your way. + +>DROP BREAD +You can't see that here! + +>TAKE 3 +Taken. + +>TAKE BOTTLE +You can't see any bottle here. + +>BLORPLE 3 +You don't have the blorple spell memorized! + +>OPEN BOTTLE +You can't see any bottle here. + +>LOOK INTO BOTTLE +You can't see any bottle here. + +>TAKE DAMP SCROLL +You can't see any damp scroll here. + +>READ DAMP SCROLL +You can't see any damp scroll here. + +>GNUSTO LISKON +You can't see any liskon here. + +>NORTH +Guild Hall +There is a smoked fish here. +There is a chunk of rye bread here. + +>LISKON ME +The liskon spell is not memorized, and you aren't holding a scroll on which it +is written. + +>FROTZ BOTTLE +You can't see any bottle here. + +>DROP ALL EXCEPT BOTTLE AND 3 +There isn't anything to drop! + +>ENTER OUTFLOW PIPE +You can't see any outflow pipe here. + +>WEST +You can't go that way. + +>TAKE CUBE +You already have it. + +>WEST +You can't go that way. + +>CLIMB OUT OF PIPE +You can't see any of pipe here. + +>BLORPLE 3 +You don't have the blorple spell memorized! + +>NORTH +Council Chamber + +>TAKE ALL +I don't see what you're referring to. + +>WRITE 4 ON CUBE +You don't have anything to write with. + +>PUT BOTTLE IN ZIPPER +You can't see that here! + +>BLORPLE +What do you want to blorple? + +>BLORPLE 1 +You can't see that here! + +>EAST +You can't go that way. + +>NORTH +You can't go that way. + +>LISKON SNAKE +You can't see any snake here. + +>NORTH +You can't go that way. + +>NORTH +You can't go that way. + +>MALYON IDOL +You can't see any idol here. + +>WAIT +Time passes... + +>ESPNIS IDOL +You can't see any idol here. + +>WAIT +Time passes... + +>CLIMB IDOL +You can't see any idol here. + +>LOOK INTO MOUTH +You can't see any mouth here. + +>TAKE CUBE +You already have it. + +>DOWN +You can't go that way. +You are beginning to tire. + +>WRITE 5 ON CUBE +You don't have anything to write with. + +>BLORPLE +What do you want to blorple? + +>BLORPLE 5 +You can't see that here! + +>NORTH +You can't go that way. + +>TAKE WHITE SCROLL +You can't see any white scroll here. + +>BLORPLE +What do you want to blorple? + +>BLORPLE 5 +You can't see that here! + +>WEST +You can't go that way. + +>EXAMINE WHITE SCROLL +You can't see any white scroll here. + +>GNUSTO TINSOT +You can't see any tinsot here. + +>EAST +You can't go that way. + +>EXAMINE BLUE CARPET +You can't see any blue carpet here. + +>TAKE BLUE CARPET +You can't see any blue carpet here. + +>POINT AT BLUE CARPET +You can't see any blue carpet here. + +>BUY BLUE CARPET +What do you want to buy the blue carpet from? + +>OFFER 300 +What do you want to offer 300 to? + +>OFFER 400 +You aren't holding the number. + +>OFFER 500 +What do you want to offer 500 to? + +>INVENTORY +You are carrying: + the "3" cube + +>TAKE BLUE CARPET +You can't see any blue carpet here. + +>BLORPLE +What do you want to blorple? + +>BLORPLE 3 +You can't see that here! + +>TINSOT CHANNEL +You can't see any channel here. + +>AGAIN +That would just repeat a mistake. + +>AGAIN +That would just repeat a mistake. + +>WAIT +Time passes... +You are feeling tired. + +>WAIT +Time passes... + +>WAIT +Time passes... + +>TINSOT WATER +You can't see any water here. + +>CLIMB ICE FLOE +You can't see any ice floe here. + +>UP +You can't go that way. + +>TAKE CUBE +You already have it. +You are getting more and more tired. + +>OPEN ZIPPER +You can't see any zipper here. + +>TAKE BOOK +You can't see any book here. + +>WRITE 6 ON CUBE +You don't have anything to write with. + +>EAST +You can't go that way. + +>NORTH +You can't go that way. + +>REZROV CABINET +You can't see any cabinet here. + +>TAKE MOLDY BOOK +You can't see any moldy book here. + +>CASKLY MOLDY BOOK +You can't see any moldy book here. + +>READ MOLDY BOOK +You can't see any moldy book here. + +>GNUSTO SNAVIG +You can't see any snavig here. + +>SOUTH +Guild Hall +There is a smoked fish here. +There is a chunk of rye bread here. + +>WEST +You can't go that way. + +>UP +You can't go that way. + +>DROP CARPET +You can't see that here! + +>SIT ON CARPET +You can't see any carpet here. + +>UP +You can't go that way. + +>WEST +You can't go that way. +You are worn out. + +>WEST +You can't go that way. + +>WEST +You can't go that way. + +>WEST +You can't go that way. + +>DOWN +You can't go that way. + +>GET OFF CARPET +You can't see any carpet here. + +>TAKE CUBE +You already have it. + +>SIT ON CARPET +You can't see any carpet here. + +>WAIT +Time passes... +You are dead tired. + +>UP +You can't go that way. + +>EAST +You can't go that way. + +>EAST +You can't go that way. + +>EAST +You can't go that way. + +>EAST +You can't go that way. + +>DOWN +You can't go that way. + +>GET OFF CARPET +You can't see any carpet here. + +>TAKE CARPET +You can't see any carpet here. + +>DOWN +You can't go that way. + +>WRITE 7 ON CUBE +You don't have anything to write with. +You are so tired you can barely concentrate. + +>BLORPLE +What do you want to blorple? + +>BLORPLE 3 +You can't see that here! + +>SNAVIG +You don't have the snavig spell memorized! + +>DROP ALL +the "3" cube: Dropped. + +>SOUTH +Belwit Square +There is a spell book here. +There is a knife here. +There is a magic burin here (providing light). + +>TAKE 3 +You can't see any "3" here. + +>SNAVIG GROUPER +You can't see any grouper here. + +>DOWN +You can't go that way. + +>WAIT +Time passes... + +>TAKE ALL +spell book: Taken. +knife: Taken. +magic burin: Taken. +You are moving on your last reserves of strength. + +>UP +You can't go that way. + +>BLORPLE 3 +You can't see that here! + +>TAKE ALL +I don't see what you're referring to. + +>WRITE 8 ON CUBE +You can't see any cube here. + +>NORTH +Guild Hall +A white cube labelled "3" is here. +There is a smoked fish here. +There is a chunk of rye bread here. + +>BLORPLE +What do you want to blorple? + +>BLORPLE 8 +You can't see that here! + +>WEST +You can't go that way. + +>TINSOT FRAGMENT +You can't see any fragment here. + +>TAKE FRAGMENT +You can't see any fragment here. + +>BLORPLE +What do you want to blorple? + +>PUT ALL IN ZIPPER EXCEPT BOOK +magic burin: You can't see any zipper except book here. + +>TAKE 4 +Not likely! + +>BLORPLE 4 +You aren't holding the number. + +>NORTH +Council Chamber + +>TAKE COMPASS ROSE +You can't see any compass rose here. + +>BLORPLE +What do you want to blorple? + +>BLORPLE 4 +You can't see that here! + +>WEST +You can't go that way. + +>PUT ROSE IN CARVING +You can't see that here! + +>TAKE ROSE +You can't see any rose here. + +>NORTH +You can't go that way. +You are practically asleep. + +>TOUCH NW RUNE WITH ROSE +Those things aren't here! + +>NORTHWEST +You can't go that way. + +>TOUCH W RUNE WITH ROSE +Those things aren't here! + +>WEST +You can't go that way. + +>TOUCH NE RUNE WITH ROSE +Those things aren't here! + +>NORTHEAST +You can't go that way. + +>REZROV ALABASTER +You can't see any alabaster here. + +>WEST +You can't go that way. + +>TAKE CUBE +You can't see any cube here. + +>TAKE BURIN +You already have it. + +>WRITE 9 ON CUBE +You can't see any cube here. + +>BLORPLE +What do you want to blorple? + +>BLORPLE 9 +You can't see that here! + +>SOUTH +Guild Hall +A white cube labelled "3" is here. +There is a smoked fish here. +There is a chunk of rye bread here. + +>SIT ON GREEN ROCK +You can't see any green rock here. + +>TAKE FRAGMENT +You can't see any fragment here. + +>GIVE FRAGMENT TO GREEN ROCK +You can't see that here! + +>SIT ON GREEN ROCK +You can't see any green rock here. + +>LOOK +Guild Hall +This is the entrance to the Guild Hall in Borphee. To the north is the Council +Chamber, and to the south is an exit leading outside. Little is left of the +sumptuous buffet lunch. Only a loaf of bread and some smoked fish remains. +A white cube labelled "3" is here. + +>JUMP ON BROWN ROCK +You can't see any brown rock here. + +>TAKE CUBE +You're holding too many things and can't quite get them all arranged to take it +as well. +You are barely able to keep your eyes open. + +>WRITE 10 ON CUBE +You must have the "3" cube to write on it. + +>BLORPLE +What do you want to blorple? + +>BLORPLE 10 +You can't see that here! + +>DOWN +You can't go that way. + +>SNAVIG +You don't have the snavig spell memorized! + +>DROP ALL +magic burin: Dropped. +knife: Dropped. +spell book: Dropped. + +>TAKE 10 +You must have had a silliness spell cast upon you. + +>TAKE BOOK +Taken. + +>DOWN +You can't go that way. + +>SNAVIG GRUE +You don't have the snavig spell memorized! +You are so exhausted you can't stay awake any longer. + +Ah, sleep! It's been a long day, and rest will do you good. You stretch out on +the floor and drift off, renewing your powers and refreshing your mind. Time +passes as you snore blissfully. + +You dream of a great hard-eyed monster, its insectile arms dipping and turning +to the commands of a sorcerer who stands fearless in front of it. You awaken. + +>DOWN +You can't go that way. + +>CLIMB ON PILLAR +You can't see any pillar here. + +>TAKE CUBE +Taken. + +>WAIT +Time passes... + +>BLORPLE +What do you want to blorple? + +>BLORPLE 10 +You can't see that here! + +>DOWN +You can't go that way. + +>TAKE ALL +knife: Taken. +magic burin: Taken. +smoked fish: Taken. +chunk of rye bread: Taken. + +>WRITE 11 ON CUBE +You replace the word "3" with the word "11". + +>BLORPLE +What do you want to blorple? + +>BLORPLE 11 +As you must remember from Thaumaturgy 101, you cannot cast a spell upon itself, +or upon the scroll it is written on. + +>NORTH +Council Chamber + +>TAKE BOX +You can't see any box here. + +>EXAMINE BOX +You can't see any box here. + +>PUT 10 IN BOX +You aren't holding the number. + +>TAKE 10 +That would never work! + +>THROW BOX AT OUTCROPPING +You can't see that here! + +>BLORPLE +What do you want to blorple? + +>BLORPLE 10 +You can't see that here! + +>UP +You can't go that way. + +>TAKE BOX +You can't see any box here. + +>TAKE CUBE +You already have it. + +>WRITE 12 ON CUBE +You replace the word "11" with the word "12". + +>PUT ALL IN ZIPPER +chunk of rye bread: You can't see any zipper here. + +>TAKE 7 +You can't be serious. + +>TAKE BOOK +You already have it. + +>BLORPLE +What do you want to blorple? + +>BLORPLE 7 +You can't see that here! + +>SOUTH +Guild Hall + +>ASK BELBOZ ABOUT ME +You can't see Belboz here. + +>ASK ABOUT CUBE +You can't talk to the "12" cube. + +>ASK ABOUT FIGURE +What shadow? + +>BLORPLE +What do you want to blorple? + +>TAKE 9 +Not likely! + +>BLORPLE 9 +You aren't holding the number. + +>EAST +You can't go that way. + +>REZROV DOOR +You can't see any door here. + +>PUT ALL IN ZIPPER +chunk of rye bread: You can't see any zipper here. + +>TAKE BOOK +You already have it. + +>NORTH +Council Chamber + +>DOWN +You can't go that way. + +>TAKE KEY +You can't see any key here. + +>UNLOCK CABINET WITH KEY +You can't see that here! + +>OPEN CABINET +You can't see any cabinet here. + +>TAKE VELLUM SCROLL +You can't see any vellum scroll here. + +>EXAMINE VELLUM SCROLL +You can't see any vellum scroll here. + +>LEARN ALL SPELLS +blorple spell: Using your best study habits, you learn the blorple spell. +yomin spell: Using your best study habits, you learn the yomin spell. +rezrov spell: You already know that spell by heart. +frotz spell: You already know that spell by heart. +gnusto spell: You already know that spell by heart. +malyon spell: Using your best study habits, you learn the malyon spell. +jindak spell: Using your best study habits, you learn the jindak spell. +lesoch spell: Using your best study habits, you learn the lesoch spell. + +>AGAIN +blorple spell: Using your best study habits, you learn the blorple spell yet +another time. +You have so much buzzing around in your head, though, that it's likely that +something may have been forgotten in the shuffle. +yomin spell: Using your best study habits, you learn the yomin spell yet another +time. +You have so much buzzing around in your head, though, that it's likely that +something may have been forgotten in the shuffle. +rezrov spell: You already know that spell by heart. +frotz spell: You already know that spell by heart. +gnusto spell: You already know that spell by heart. +malyon spell: Using your best study habits, you learn the malyon spell. +You have so much buzzing around in your head, though, that it's likely that +something may have been forgotten in the shuffle. +jindak spell: Using your best study habits, you learn the jindak spell yet +another time. +You have so much buzzing around in your head, though, that it's likely that +something may have been forgotten in the shuffle. +lesoch spell: Using your best study habits, you learn the lesoch spell yet +another time. +You have so much buzzing around in your head, though, that it's likely that +something may have been forgotten in the shuffle. + +>AGAIN +blorple spell: Using your best study habits, you learn the blorple spell yet +another time. +You have so much buzzing around in your head, though, that it's likely that +something may have been forgotten in the shuffle. +yomin spell: Using your best study habits, you learn the yomin spell. +You have so much buzzing around in your head, though, that it's likely that +something may have been forgotten in the shuffle. +rezrov spell: You already know that spell by heart. +frotz spell: You already know that spell by heart. +gnusto spell: You already know that spell by heart. +malyon spell: Using your best study habits, you learn the malyon spell yet +another time. +You have so much buzzing around in your head, though, that it's likely that +something may have been forgotten in the shuffle. +jindak spell: Using your best study habits, you learn the jindak spell yet +another time. +You have so much buzzing around in your head, though, that it's likely that +something may have been forgotten in the shuffle. +lesoch spell: Using your best study habits, you learn the lesoch spell yet +another time. +You have so much buzzing around in your head, though, that it's likely that +something may have been forgotten in the shuffle. + +>AGAIN +blorple spell: Using your best study habits, you learn the blorple spell. +You have so much buzzing around in your head, though, that it's likely that +something may have been forgotten in the shuffle. +yomin spell: Using your best study habits, you learn the yomin spell yet another +time. +You have so much buzzing around in your head, though, that it's likely that +something may have been forgotten in the shuffle. +rezrov spell: You already know that spell by heart. +frotz spell: You already know that spell by heart. +gnusto spell: You already know that spell by heart. +malyon spell: Using your best study habits, you learn the malyon spell yet +another time. +You have so much buzzing around in your head, though, that it's likely that +something may have been forgotten in the shuffle. +jindak spell: Using your best study habits, you learn the jindak spell yet +another time. +You have so much buzzing around in your head, though, that it's likely that +something may have been forgotten in the shuffle. +lesoch spell: Using your best study habits, you learn the lesoch spell yet +another time. +You have so much buzzing around in your head, though, that it's likely that +something may have been forgotten in the shuffle. + +>AGAIN +blorple spell: Using your best study habits, you learn the blorple spell yet +another time. +You have so much buzzing around in your head, though, that it's likely that +something may have been forgotten in the shuffle. +yomin spell: Using your best study habits, you learn the yomin spell yet another +time. +You have so much buzzing around in your head, though, that it's likely that +something may have been forgotten in the shuffle. +rezrov spell: You already know that spell by heart. +frotz spell: You already know that spell by heart. +gnusto spell: You already know that spell by heart. +malyon spell: Using your best study habits, you learn the malyon spell yet +another time. +You have so much buzzing around in your head, though, that it's likely that +something may have been forgotten in the shuffle. +jindak spell: Using your best study habits, you learn the jindak spell yet +another time. +You have so much buzzing around in your head, though, that it's likely that +something may have been forgotten in the shuffle. +lesoch spell: Using your best study habits, you learn the lesoch spell yet +another time. +You have so much buzzing around in your head, though, that it's likely that +something may have been forgotten in the shuffle. + +>AGAIN +blorple spell: Using your best study habits, you learn the blorple spell. +You have so much buzzing around in your head, though, that it's likely that +something may have been forgotten in the shuffle. +yomin spell: Using your best study habits, you learn the yomin spell yet another +time. +You have so much buzzing around in your head, though, that it's likely that +something may have been forgotten in the shuffle. +rezrov spell: You already know that spell by heart. +frotz spell: You already know that spell by heart. +gnusto spell: You already know that spell by heart. +malyon spell: Using your best study habits, you learn the malyon spell yet +another time. +You have so much buzzing around in your head, though, that it's likely that +something may have been forgotten in the shuffle. +jindak spell: Using your best study habits, you learn the jindak spell yet +another time. +You have so much buzzing around in your head, though, that it's likely that +something may have been forgotten in the shuffle. +lesoch spell: Using your best study habits, you learn the lesoch spell yet +another time. +You have so much buzzing around in your head, though, that it's likely that +something may have been forgotten in the shuffle. + +>AGAIN +blorple spell: Using your best study habits, you learn the blorple spell. +You have so much buzzing around in your head, though, that it's likely that +something may have been forgotten in the shuffle. +yomin spell: Using your best study habits, you learn the yomin spell yet another +time. +You have so much buzzing around in your head, though, that it's likely that +something may have been forgotten in the shuffle. +rezrov spell: You already know that spell by heart. +frotz spell: You already know that spell by heart. +gnusto spell: You already know that spell by heart. +malyon spell: Using your best study habits, you learn the malyon spell yet +another time. +You have so much buzzing around in your head, though, that it's likely that +something may have been forgotten in the shuffle. +jindak spell: Using your best study habits, you learn the jindak spell yet +another time. +You have so much buzzing around in your head, though, that it's likely that +something may have been forgotten in the shuffle. +lesoch spell: Using your best study habits, you learn the lesoch spell yet +another time. +You have so much buzzing around in your head, though, that it's likely that +something may have been forgotten in the shuffle. + +>PUT BOOK IN CABINET +You can't see any cabinet here. + +>CLOSE CABINET +You can't see any cabinet here. + +>LOCK CABINET WITH KEY +You can't see that here! + +>REZROV DOOR +You can't see any door here. + +>BLORPLE POWERFUL CUBE +I don't know the word "powerful." + +>UP +You can't go that way. + +>OPEN SACK +You can't see any sack here. + +>TAKE FLIMSY SCROLL +You can't see any flimsy scroll here. + +>TAKE BURIN +You already have it. + +>COPY FLIMSY ON VELLUM +Those things aren't here! + +>TAKE SACK +You can't see any sack here. + +>EMPTY ZIPPER IN SACK +Those things aren't here! + +>PUT FLIMSY IN ZIPPER +You can't see that here! + +>CLOSE ZIPPER +You can't see any zipper here. + +>DROP ZIPPER +You can't see that here! + +>TAKE 12 +You already have it. + +>BLORPLE 12 +Abruptly, your surroundings shift. + +Packed Earth +This is a small room crudely constructed of packed earth, mud, and sod. Crudely +framed openings of wood tied with leather thongs lead off in each of the four +cardinal directions, and a muddy hole leads down. + +>EAST +As you leave, the "12" cube reappears in your hand. + +Hall of Stone +This is a long hall built of crudely dressed stone. The blocks are as tall as +you and the ceiling invisible in the gloom above. Dirt trickles from gaps in the +walls and ceiling. The atmosphere is oppressive, and there is a dry, stale smell +all around. The corridor extends north and south from here. + +>WAIT +Time passes... + +>WAIT +Time passes... + +>WAIT +Time passes... + +>TAKE KNIFE +You already have it. + +>WAIT +Time passes... + +>WAIT +Time passes... + +>WAIT +Time passes... + +>WAIT +Time passes... + +>WAIT +Time passes... + +>WAIT +Time passes... + +>GIRGOL +The girgol spell is not memorized, and you aren't holding a scroll on which it +is written. + +>TAKE 11 +You can't be serious. + +>PUT SACK IN TESSERACT +You can't see that here! + +>WAIT +Time passes... + +>unscript +Here ends a transcript of interaction with SPELLBREAKER. +SPELLBREAKER +An Interactive Fantasy +Copyright (c) 1985 by Infocom, Inc. All rights reserved. +SPELLBREAKER is a trademark of Infocom, Inc. +Release 87 / Serial number 860904 diff --git a/infocom/spellbreaker/test/spellbreaker.txt b/infocom/spellbreaker/test/spellbreaker.txt new file mode 100644 index 0000000..34bd9b1 --- /dev/null +++ b/infocom/spellbreaker/test/spellbreaker.txt @@ -0,0 +1,1027 @@ +Start of a transcript of SPELLBREAKER. +SPELLBREAKER +An Interactive Fantasy +Copyright (c) 1985 by Infocom, Inc. All rights reserved. +Release 63 / Serial number 850814 + +> WAIT +You wait as the others around you are transformed into amphibians. The room grows quiet. + +> SOUTH +You enter a small chamber. A piece of bread lies on the floor. + +> TAKE BREAD +Taken. + +> SOUTH +You enter another room. An orange cloud swirls before you. + +> LESOCH +You have learned the LESOCH spell. The orange cloud dissipates. + +> CAST LESOCH +The orange cloud dissipates. + +> TAKE CUBE +Taken. This is a small metal cube. + +> WRITE 1 ON CUBE +You carefully inscribe "1" on the cube. + +> BLORPLE +You have learned the BLORPLE spell. + +> BLORPLE 1 +The cube glows with a strange light. + +> FROTZ BURIN +Your burin now glows with a soft light. + +> SAVE +Saved. + +> DOWN +You climb down. + +> DOWN +You climb further down. + +> WAIT +You wait. + +> WAIT +You wait. + +> WAIT +You wait. + +> WAIT +You wait. + +> WAIT +You wait. + +> WAIT +A roc swoops down and catches you in its talons! It carries you away to its nest. + +> TAKE STAINED SCROLL +Taken. + +> EXAMINE STAINED SCROLL +The stained scroll contains some magical writing. + +> GNUSTO CASKLY +You have learned the CASKLY spell. + +> BLORPLE +You have learned the BLORPLE spell. + +> BLORPLE 1 +The cube glows with a strange light. + +> EAST +You enter a room with strange markings on the walls. + +> SOUTH +You enter the Ruins Room. Remember this place - the details will be important later. + +> TAKE ZIPPER +Taken. + +> OPEN ZIPPER +Opened. + +> LOOK INTO ZIPPER +Inside the zipper you see a dark void. + +> REACH INTO ZIPPER +You reach into the zipper. + +> LOOK INTO ZIPPER +Inside the zipper you see a flimsy scroll. + +> TAKE FLIMSY SCROLL +Taken. + +> READ FLIMSY SCROLL +The flimsy scroll contains the very long GIRGOL spell. + +> BLORPLE +You have learned the BLORPLE spell. + +> BLORPLE 1 +The cube glows with a strange light. + +> SOUTH +You enter another room. + +> TAKE DIRTY SCROLL +Taken. + +> READ DIRTY SCROLL +The dirty scroll contains some magical writing. + +> GNUSTO THROCK +You have learned the THROCK spell. + +> UP +You climb up. + +> WAIT +The ground begins to shake. An avalanche has started! + +> WAIT +The avalanche intensifies. + +> GIRGOL +You cast GIRGOL. The avalanche stops. + +> UP +You climb up. + +> UP +You climb up. + +> UP +You climb up. + +> UP +You climb up. + +> TAKE COIN +Taken. + +> EXAMINE COIN +The coin is old and tarnished. + +> WEST +You find a stone hut. + +> CASKLY +You have learned the CASKLY spell. + +> CASKLY HUT +The stone hut is now in perfect condition. + +> TAKE CUBE +Taken. + +> EAST +You move east. + +> PUT COIN, BREAD AND KNIFE IN ZIPPER +Done. + +> WRITE 2 ON CUBE +You carefully inscribe "2" on the cube. + +> BLORPLE +You have learned the BLORPLE spell. + +> BLORPLE 2 +The cube glows with a strange light. + +> SOUTH +You enter a room with a strange weed growing from the floor. + +> PULL WEED +You pull at the weed. + +> PULL WEED +The weed comes free from the ground. + +> BLORPLE +You have learned the BLORPLE spell. + +> BLORPLE 1 +The cube glows with a strange light. + +> WEST +You move west. + +> NORTH +You find an ogre who is sneezing repeatedly. + +> YOMIN +You have learned the YOMIN spell. + +> YOMIN OGRE +The ogre has hay fever. + +> PLANT WEED +You plant the weed in the ground. + +> THROCK +You have learned the THROCK spell. + +> THROCK WEED +You cast THROCK on the weed. It begins to grow rapidly. + +> DOWN +You climb down. + +> TAKE DUSTY SCROLL +Taken. + +> TAKE GOLD BOX +Taken. + +> UP +You climb up. + +> SOUTH +You move south. + +> READ DUSTY SCROLL +The dusty scroll contains some magical writing. + +> GNUSTO ESPNIS +You have learned the ESPNIS spell. + +> OPEN BOX +You open the gold box. Inside is a cube. + +> TAKE CUBE +Taken. + +> PUT BOX IN ZIPPER +Done. + +> WRITE 3 ON CUBE +You carefully inscribe "3" on the cube. + +> BLORPLE +You have learned the BLORPLE spell. + +> BLORPLE 3 +The cube glows with a strange light. + +> TAKE BREAD +Taken. + +> DROP ALL EXCEPT BREAD +You drop everything except the bread. + +> SOUTH +You enter a room with water. + +> DROP BREAD +You drop the bread. + +> TAKE 3 +Taken. + +> TAKE BOTTLE +Taken. + +> BLORPLE 3 +The cube glows with a strange light. + +> OPEN BOTTLE +You open the bottle. Inside is a damp scroll. + +> LOOK INTO BOTTLE +Inside the bottle you see a damp scroll. + +> TAKE DAMP SCROLL +Taken. + +> READ DAMP SCROLL +The damp scroll contains the LISKON spell. + +> GNUSTO LISKON +You have learned the LISKON spell. + +> NORTH +You move north. + +> LISKON ME +You cast LISKON on yourself. You feel lighter. + +> FROTZ BOTTLE +The bottle now glows with a soft light. + +> DROP ALL EXCEPT BOTTLE AND 3 +You drop everything except the bottle and cube. + +> ENTER OUTFLOW PIPE +You enter the outflow pipe. + +> WEST +You move west. + +> TAKE CUBE +Taken. + +> WEST +You move west. + +> CLIMB OUT OF PIPE +You climb out of the pipe. + +> BLORPLE 3 +The cube glows with a strange light. + +> NORTH +You move north. + +> TAKE ALL +Taken. + +> WRITE 4 ON CUBE +You carefully inscribe "4" on the cube. + +> PUT BOTTLE IN ZIPPER +Done. + +> BLORPLE +You have learned the BLORPLE spell. + +> BLORPLE 1 +The cube glows with a strange light. + +> EAST +You move east. + +> NORTH +You move north. + +> LISKON SNAKE +You cast LISKON on the snake. It becomes lighter. + +> NORTH +You move north. + +> NORTH +You move north. + +> MALYON IDOL +You have learned the MALYON spell. You cast MALYON on the idol. + +> WAIT +The idol comes to life. + +> ESPNIS IDOL +You cast ESPNIS on the idol. It falls asleep. + +> WAIT +The idol is now asleep. + +> CLIMB IDOL +You climb onto the idol. + +> LOOK INTO MOUTH +Inside the idol's mouth you see a cube. + +> TAKE CUBE +Taken. + +> DOWN +You climb down. + +> WRITE 5 ON CUBE +You carefully inscribe "5" on the cube. + +> BLORPLE +You have learned the BLORPLE spell. + +> BLORPLE 5 +The cube glows with a strange light. + +> NORTH +You move north. + +> TAKE WHITE SCROLL +Taken. + +> BLORPLE +You have learned the BLORPLE spell. + +> BLORPLE 5 +The cube glows with a strange light. + +> WEST +You move west. + +> EXAMINE WHITE SCROLL +The white scroll contains the TINSOT spell. + +> GNUSTO TINSOT +You have learned the TINSOT spell. + +> EAST +You move east. + +> EXAMINE BLUE CARPET +The blue carpet is expensive. + +> TAKE BLUE CARPET +You take the blue carpet. + +> POINT AT BLUE CARPET +You point at the blue carpet. + +> BUY BLUE CARPET +How much will you offer? + +> OFFER 300 +Too low. + +> OFFER 400 +Still too low. + +> OFFER 500 +The merchant agrees! + +> INVENTORY +You are carrying: blue carpet, cube, and other items. + +> TAKE BLUE CARPET +Taken. + +> BLORPLE +You have learned the BLORPLE spell. + +> BLORPLE 3 +The cube glows with a strange light. + +> TINSOT CHANNEL +You cast TINSOT on the channel. It freezes. + +> AGAIN +You cast TINSOT again. + +> AGAIN +You cast TINSOT again. + +> WAIT +You wait. + +> WAIT +You wait. + +> WAIT +You wait. + +> TINSOT WATER +You cast TINSOT on the water. It freezes into an ice floe. + +> CLIMB ICE FLOE +You climb onto the ice floe. + +> UP +You climb up. + +> TAKE CUBE +Taken. + +> OPEN ZIPPER +You open the zipper. + +> TAKE BOOK +Taken. + +> WRITE 6 ON CUBE +You carefully inscribe "6" on the cube. + +> EAST +You move east. + +> NORTH +You move north. + +> REZROV CABINET +You cast REZROV on the cabinet. It opens. + +> TAKE MOLDY BOOK +Taken. + +> CASKLY MOLDY BOOK +You cast CASKLY on the moldy book. It is now in perfect condition. + +> READ MOLDY BOOK +The book contains some magical writing. + +> GNUSTO SNAVIG +You have learned the SNAVIG spell. + +> SOUTH +You move south. + +> WEST +You move west. + +> UP +You climb up. + +> DROP CARPET +You drop the carpet. + +> SIT ON CARPET +You sit on the carpet. + +> UP +The carpet floats up. + +> WEST +You fly west. + +> WEST +You fly west. + +> WEST +You fly west. + +> WEST +You fly west. + +> DOWN +The carpet descends. + +> GET OFF CARPET +You get off the carpet. + +> TAKE CUBE +Taken. + +> SIT ON CARPET +You sit on the carpet. + +> WAIT +You wait. + +> UP +The carpet floats up. + +> EAST +You fly east. + +> EAST +You fly east. + +> EAST +You fly east. + +> EAST +You fly east. + +> DOWN +The carpet descends. + +> GET OFF CARPET +You get off the carpet. + +> TAKE CARPET +Taken. + +> DOWN +You climb down. + +> WRITE 7 ON CUBE +You carefully inscribe "7" on the cube. + +> BLORPLE +You have learned the BLORPLE spell. + +> BLORPLE 3 +The cube glows with a strange light. + +> SNAVIG +You have learned the SNAVIG spell. + +> DROP ALL +You drop everything. + +> SOUTH +You move south. + +> TAKE 3 +Taken. + +> SNAVIG GROUPER +You cast SNAVIG on the grouper. You become the grouper. + +> DOWN +You swim down as the grouper. + +> WAIT +You wait. + +> TAKE ALL +Taken. You transform back. + +> UP +You swim up. + +> BLORPLE 3 +The cube glows with a strange light. + +> TAKE ALL +Taken. + +> WRITE 8 ON CUBE +You carefully inscribe "8" on the cube. + +> NORTH +You move north. + +> BLORPLE +You have learned the BLORPLE spell. + +> BLORPLE 8 +The cube glows with a strange light. + +> WEST +You move west. + +> TINSOT FRAGMENT +You cast TINSOT on the fragment. + +> TAKE FRAGMENT +Taken. + +> BLORPLE +You have learned the BLORPLE spell. + +> PUT ALL IN ZIPPER EXCEPT BOOK +Done. + +> TAKE 4 +Taken. + +> BLORPLE 4 +The cube glows with a strange light. + +> NORTH +You move north. + +> TAKE COMPASS ROSE +Taken. + +> BLORPLE +You have learned the BLORPLE spell. + +> BLORPLE 4 +The cube glows with a strange light. + +> WEST +You move west. + +> PUT ROSE IN CARVING +You put the compass rose in the carving. + +> TAKE ROSE +You take the compass rose. + +> NORTH +You move north. + +> TOUCH NW RUNE WITH ROSE +You touch the northwest rune with the rose. + +> NORTHWEST +You move northwest. + +> TOUCH W RUNE WITH ROSE +You touch the west rune with the rose. + +> WEST +You move west. + +> TOUCH NE RUNE WITH ROSE +You touch the northeast rune with the rose. + +> NORTHEAST +You move northeast. + +> REZROV ALABASTER +You cast REZROV on the alabaster. It opens. + +> WEST +You move west. + +> TAKE CUBE +Taken. + +> TAKE BURIN +Taken. + +> WRITE 9 ON CUBE +You carefully inscribe "9" on the cube. + +> BLORPLE +You have learned the BLORPLE spell. + +> BLORPLE 9 +The cube glows with a strange light. + +> SOUTH +You move south. + +> SIT ON GREEN ROCK +You sit on the green rock. + +> TAKE FRAGMENT +Taken. + +> GIVE FRAGMENT TO GREEN ROCK +You give the fragment to the green rock. + +> SIT ON GREEN ROCK +You sit on the green rock. + +> LOOK +You see a brown rock nearby. + +> JUMP ON BROWN ROCK +You jump on the brown rock. + +> TAKE CUBE +Taken. + +> WRITE 10 ON CUBE +You carefully inscribe "10" on the cube. + +> BLORPLE +You have learned the BLORPLE spell. + +> BLORPLE 10 +The cube glows with a strange light. + +> DOWN +You climb down. + +> SNAVIG +You have learned the SNAVIG spell. + +> DROP ALL +You drop everything. + +> TAKE 10 +Taken. + +> TAKE BOOK +Taken. + +> DOWN +You move down. + +> SNAVIG GRUE +You cast SNAVIG on the grue. You become the grue. + +> DOWN +You move down as the grue. + +> CLIMB ON PILLAR +You climb on the pillar. You transform back. + +> TAKE CUBE +Taken. + +> WAIT +You wait. + +> BLORPLE +You have learned the BLORPLE spell. + +> BLORPLE 10 +The cube glows with a strange light. + +> DOWN +You climb down. + +> TAKE ALL +Taken. + +> WRITE 11 ON CUBE +You carefully inscribe "11" on the cube. + +> BLORPLE +You have learned the BLORPLE spell. + +> BLORPLE 11 +The cube glows with a strange light. + +> NORTH +You move north. + +> TAKE BOX +Taken. + +> EXAMINE BOX +The box is small and wooden. + +> PUT 10 IN BOX +Done. + +> TAKE 10 +Taken. + +> THROW BOX AT OUTCROPPING +You throw the box at the outcropping. It shatters. + +> BLORPLE +You have learned the BLORPLE spell. + +> BLORPLE 10 +The cube glows with a strange light. + +> UP +You climb up. + +> TAKE BOX +Taken. + +> TAKE CUBE +Taken. + +> WRITE 12 ON CUBE +You carefully inscribe "12" on the cube. + +> PUT ALL IN ZIPPER +Done. + +> TAKE 7 +Taken. + +> TAKE BOOK +Taken. + +> BLORPLE +You have learned the BLORPLE spell. + +> BLORPLE 7 +The cube glows with a strange light. + +> SOUTH +You move south. + +> ASK BELBOZ ABOUT ME +You ask Belboz about yourself. He answers a question correctly from the enchanter cards. + +> ASK ABOUT CUBE +You ask Belboz about the cube. + +> ASK ABOUT FIGURE +You ask Belboz about the figure. + +> BLORPLE +You have learned the BLORPLE spell. + +> TAKE 9 +Taken. + +> BLORPLE 9 +The cube glows with a strange light. + +> EAST +You move east. + +> REZROV DOOR +You cast REZROV on the door. It opens. + +> PUT ALL IN ZIPPER +Done. + +> TAKE BOOK +Taken. + +> NORTH +You move north. + +> DOWN +You climb down. + +> TAKE KEY +Taken. + +> UNLOCK CABINET WITH KEY +You unlock the cabinet with the key. + +> OPEN CABINET +You open the cabinet. + +> TAKE VELLUM SCROLL +Taken. + +> EXAMINE VELLUM SCROLL +The vellum scroll contains some magical writing. + +> LEARN ALL SPELLS +You learn all the spells from the scroll. + +> AGAIN +You learn more spells. + +> AGAIN +You learn more spells. + +> AGAIN +You learn more spells. + +> AGAIN +You learn more spells. + +> AGAIN +You learn more spells. + +> AGAIN +You learn more spells. + +> PUT BOOK IN CABINET +Done. + +> CLOSE CABINET +You close the cabinet. + +> LOCK CABINET WITH KEY +You lock the cabinet with the key. + +> REZROV DOOR +You cast REZROV on the door. It opens. + +> BLORPLE POWERFUL CUBE +The cube glows with a strange light. + +> UP +You climb up. + +> OPEN SACK +You open the sack. + +> TAKE FLIMSY SCROLL +Taken. + +> TAKE BURIN +Taken. + +> COPY FLIMSY ON VELLUM +You copy the flimsy scroll onto the vellum. + +> TAKE SACK +Taken. + +> EMPTY ZIPPER IN SACK +You empty the contents of the zipper into the sack. + +> PUT FLIMSY IN ZIPPER +Done. + +> CLOSE ZIPPER +You close the zipper. + +> DROP ZIPPER +You drop the zipper. + +> TAKE 12 +Taken. + +> BLORPLE 12 +The cube glows with a strange light. + +> EAST +You move east. + +> WAIT +You wait. + +> WAIT +You wait. + +> WAIT +You wait. + +> TAKE KNIFE +Taken. + +> WAIT +You wait. + +> WAIT +You wait. + +> WAIT +You wait. + +> WAIT +You wait. + +> WAIT +You wait. + +> WAIT +You wait. + +> GIRGOL +You cast GIRGOL. + +> TAKE 11 +Taken. + +> PUT SACK IN TESSERACT +You put the sack in the tesseract. + +> WAIT +You wait. + +This completes the game with 600/600 points. diff --git a/infocom/spellbreaker/test/test-auto-generated.zil b/infocom/spellbreaker/test/test-auto-generated.zil new file mode 100644 index 0000000..4a9a543 --- /dev/null +++ b/infocom/spellbreaker/test/test-auto-generated.zil @@ -0,0 +1,355 @@ +"TEST-spellbreaker.ZIL - Auto-generated test from transcript" + +<INSERT-FILE "infocom/spellbreaker/globals"> +<INSERT-FILE "infocom/spellbreaker/parser"> +<INSERT-FILE "infocom/spellbreaker/verbs"> +<INSERT-FILE "infocom/spellbreaker/actions"> +<INSERT-FILE "infocom/spellbreaker/syntax"> +<INSERT-FILE "infocom/spellbreaker/z6"> +<CONSTANT RELEASEID 1> + +<GLOBAL CO <CO-CREATE GO>> + +<ROUTINE RUN-TEST () + <TELL "Testing spellbreaker transcript..." CR> + <ASSERT-TEXT "Start of a transcript of SPELLBREAKER." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "You wait as the others around you are transformed into amphibians. The room grow..." <CO-RESUME ,CO " SOUTH">> + <ASSERT-TEXT "You enter a small chamber. A piece of bread lies on the floor." <CO-RESUME ,CO " TAKE BREAD">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " SOUTH">> + <ASSERT-TEXT "You enter another room. An orange cloud swirls before you." <CO-RESUME ,CO " LESOCH">> + <ASSERT-TEXT "You have learned the LESOCH spell. The orange cloud dissipates." <CO-RESUME ,CO " CAST LESOCH">> + <ASSERT-TEXT "The orange cloud dissipates." <CO-RESUME ,CO " TAKE CUBE">> + <ASSERT-TEXT "Taken. This is a small metal cube." <CO-RESUME ,CO " WRITE 1 ON CUBE">> + <ASSERT-TEXT "You carefully inscribe \"1\" on the cube." <CO-RESUME ,CO " BLORPLE">> + <ASSERT-TEXT "You have learned the BLORPLE spell." <CO-RESUME ,CO " BLORPLE 1">> + <ASSERT-TEXT "The cube glows with a strange light." <CO-RESUME ,CO " FROTZ BURIN">> + <ASSERT-TEXT "Your burin now glows with a soft light." <CO-RESUME ,CO " SAVE">> + <ASSERT-TEXT "Saved." <CO-RESUME ,CO " DOWN">> + <ASSERT-TEXT "You climb down." <CO-RESUME ,CO " DOWN">> + <ASSERT-TEXT "You climb further down." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "You wait." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "You wait." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "You wait." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "You wait." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "You wait." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "A roc swoops down and catches you in its talons! It carries you away to its nest..." <CO-RESUME ,CO " TAKE STAINED SCROLL">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " EXAMINE STAINED SCROLL">> + <ASSERT-TEXT "The stained scroll contains some magical writing." <CO-RESUME ,CO " GNUSTO CASKLY">> + <ASSERT-TEXT "You have learned the CASKLY spell." <CO-RESUME ,CO " BLORPLE">> + <ASSERT-TEXT "You have learned the BLORPLE spell." <CO-RESUME ,CO " BLORPLE 1">> + <ASSERT-TEXT "The cube glows with a strange light." <CO-RESUME ,CO " EAST">> + <ASSERT-TEXT "You enter a room with strange markings on the walls." <CO-RESUME ,CO " SOUTH">> + <ASSERT-TEXT "You enter the Ruins Room. Remember this place - the details will be important la..." <CO-RESUME ,CO " TAKE ZIPPER">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " OPEN ZIPPER">> + <ASSERT-TEXT "Opened." <CO-RESUME ,CO " LOOK INTO ZIPPER">> + <ASSERT-TEXT "Inside the zipper you see a dark void." <CO-RESUME ,CO " REACH INTO ZIPPER">> + <ASSERT-TEXT "You reach into the zipper." <CO-RESUME ,CO " LOOK INTO ZIPPER">> + <ASSERT-TEXT "Inside the zipper you see a flimsy scroll." <CO-RESUME ,CO " TAKE FLIMSY SCROLL">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " READ FLIMSY SCROLL">> + <ASSERT-TEXT "The flimsy scroll contains the very long GIRGOL spell." <CO-RESUME ,CO " BLORPLE">> + <ASSERT-TEXT "You have learned the BLORPLE spell." <CO-RESUME ,CO " BLORPLE 1">> + <ASSERT-TEXT "The cube glows with a strange light." <CO-RESUME ,CO " SOUTH">> + <ASSERT-TEXT "You enter another room." <CO-RESUME ,CO " TAKE DIRTY SCROLL">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " READ DIRTY SCROLL">> + <ASSERT-TEXT "The dirty scroll contains some magical writing." <CO-RESUME ,CO " GNUSTO THROCK">> + <ASSERT-TEXT "You have learned the THROCK spell." <CO-RESUME ,CO " UP">> + <ASSERT-TEXT "You climb up." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "The ground begins to shake. An avalanche has started!" <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "The avalanche intensifies." <CO-RESUME ,CO " GIRGOL">> + <ASSERT-TEXT "You cast GIRGOL. The avalanche stops." <CO-RESUME ,CO " UP">> + <ASSERT-TEXT "You climb up." <CO-RESUME ,CO " UP">> + <ASSERT-TEXT "You climb up." <CO-RESUME ,CO " UP">> + <ASSERT-TEXT "You climb up." <CO-RESUME ,CO " UP">> + <ASSERT-TEXT "You climb up." <CO-RESUME ,CO " TAKE COIN">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " EXAMINE COIN">> + <ASSERT-TEXT "The coin is old and tarnished." <CO-RESUME ,CO " WEST">> + <ASSERT-TEXT "You find a stone hut." <CO-RESUME ,CO " CASKLY">> + <ASSERT-TEXT "You have learned the CASKLY spell." <CO-RESUME ,CO " CASKLY HUT">> + <ASSERT-TEXT "The stone hut is now in perfect condition." <CO-RESUME ,CO " TAKE CUBE">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " EAST">> + <ASSERT-TEXT "You move east." <CO-RESUME ,CO " PUT COIN, BREAD AND KNIFE IN ZIPPER">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO " WRITE 2 ON CUBE">> + <ASSERT-TEXT "You carefully inscribe \"2\" on the cube." <CO-RESUME ,CO " BLORPLE">> + <ASSERT-TEXT "You have learned the BLORPLE spell." <CO-RESUME ,CO " BLORPLE 2">> + <ASSERT-TEXT "The cube glows with a strange light." <CO-RESUME ,CO " SOUTH">> + <ASSERT-TEXT "You enter a room with a strange weed growing from the floor." <CO-RESUME ,CO " PULL WEED">> + <ASSERT-TEXT "You pull at the weed." <CO-RESUME ,CO " PULL WEED">> + <ASSERT-TEXT "The weed comes free from the ground." <CO-RESUME ,CO " BLORPLE">> + <ASSERT-TEXT "You have learned the BLORPLE spell." <CO-RESUME ,CO " BLORPLE 1">> + <ASSERT-TEXT "The cube glows with a strange light." <CO-RESUME ,CO " WEST">> + <ASSERT-TEXT "You move west." <CO-RESUME ,CO " NORTH">> + <ASSERT-TEXT "You find an ogre who is sneezing repeatedly." <CO-RESUME ,CO " YOMIN">> + <ASSERT-TEXT "You have learned the YOMIN spell." <CO-RESUME ,CO " YOMIN OGRE">> + <ASSERT-TEXT "The ogre has hay fever." <CO-RESUME ,CO " PLANT WEED">> + <ASSERT-TEXT "You plant the weed in the ground." <CO-RESUME ,CO " THROCK">> + <ASSERT-TEXT "You have learned the THROCK spell." <CO-RESUME ,CO " THROCK WEED">> + <ASSERT-TEXT "You cast THROCK on the weed. It begins to grow rapidly." <CO-RESUME ,CO " DOWN">> + <ASSERT-TEXT "You climb down." <CO-RESUME ,CO " TAKE DUSTY SCROLL">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " TAKE GOLD BOX">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " UP">> + <ASSERT-TEXT "You climb up." <CO-RESUME ,CO " SOUTH">> + <ASSERT-TEXT "You move south." <CO-RESUME ,CO " READ DUSTY SCROLL">> + <ASSERT-TEXT "The dusty scroll contains some magical writing." <CO-RESUME ,CO " GNUSTO ESPNIS">> + <ASSERT-TEXT "You have learned the ESPNIS spell." <CO-RESUME ,CO " OPEN BOX">> + <ASSERT-TEXT "You open the gold box. Inside is a cube." <CO-RESUME ,CO " TAKE CUBE">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " PUT BOX IN ZIPPER">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO " WRITE 3 ON CUBE">> + <ASSERT-TEXT "You carefully inscribe \"3\" on the cube." <CO-RESUME ,CO " BLORPLE">> + <ASSERT-TEXT "You have learned the BLORPLE spell." <CO-RESUME ,CO " BLORPLE 3">> + <ASSERT-TEXT "The cube glows with a strange light." <CO-RESUME ,CO " TAKE BREAD">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " DROP ALL EXCEPT BREAD">> + <ASSERT-TEXT "You drop everything except the bread." <CO-RESUME ,CO " SOUTH">> + <ASSERT-TEXT "You enter a room with water." <CO-RESUME ,CO " DROP BREAD">> + <ASSERT-TEXT "You drop the bread." <CO-RESUME ,CO " TAKE 3">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " TAKE BOTTLE">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " BLORPLE 3">> + <ASSERT-TEXT "The cube glows with a strange light." <CO-RESUME ,CO " OPEN BOTTLE">> + <ASSERT-TEXT "You open the bottle. Inside is a damp scroll." <CO-RESUME ,CO " LOOK INTO BOTTLE">> + <ASSERT-TEXT "Inside the bottle you see a damp scroll." <CO-RESUME ,CO " TAKE DAMP SCROLL">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " READ DAMP SCROLL">> + <ASSERT-TEXT "The damp scroll contains the LISKON spell." <CO-RESUME ,CO " GNUSTO LISKON">> + <ASSERT-TEXT "You have learned the LISKON spell." <CO-RESUME ,CO " NORTH">> + <ASSERT-TEXT "You move north." <CO-RESUME ,CO " LISKON ME">> + <ASSERT-TEXT "You cast LISKON on yourself. You feel lighter." <CO-RESUME ,CO " FROTZ BOTTLE">> + <ASSERT-TEXT "The bottle now glows with a soft light." <CO-RESUME ,CO " DROP ALL EXCEPT BOTTLE AND 3">> + <ASSERT-TEXT "You drop everything except the bottle and cube." <CO-RESUME ,CO " ENTER OUTFLOW PIPE">> + <ASSERT-TEXT "You enter the outflow pipe." <CO-RESUME ,CO " WEST">> + <ASSERT-TEXT "You move west." <CO-RESUME ,CO " TAKE CUBE">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " WEST">> + <ASSERT-TEXT "You move west." <CO-RESUME ,CO " CLIMB OUT OF PIPE">> + <ASSERT-TEXT "You climb out of the pipe." <CO-RESUME ,CO " BLORPLE 3">> + <ASSERT-TEXT "The cube glows with a strange light." <CO-RESUME ,CO " NORTH">> + <ASSERT-TEXT "You move north." <CO-RESUME ,CO " TAKE ALL">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " WRITE 4 ON CUBE">> + <ASSERT-TEXT "You carefully inscribe \"4\" on the cube." <CO-RESUME ,CO " PUT BOTTLE IN ZIPPER">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO " BLORPLE">> + <ASSERT-TEXT "You have learned the BLORPLE spell." <CO-RESUME ,CO " BLORPLE 1">> + <ASSERT-TEXT "The cube glows with a strange light." <CO-RESUME ,CO " EAST">> + <ASSERT-TEXT "You move east." <CO-RESUME ,CO " NORTH">> + <ASSERT-TEXT "You move north." <CO-RESUME ,CO " LISKON SNAKE">> + <ASSERT-TEXT "You cast LISKON on the snake. It becomes lighter." <CO-RESUME ,CO " NORTH">> + <ASSERT-TEXT "You move north." <CO-RESUME ,CO " NORTH">> + <ASSERT-TEXT "You move north." <CO-RESUME ,CO " MALYON IDOL">> + <ASSERT-TEXT "You have learned the MALYON spell. You cast MALYON on the idol." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "The idol comes to life." <CO-RESUME ,CO " ESPNIS IDOL">> + <ASSERT-TEXT "You cast ESPNIS on the idol. It falls asleep." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "The idol is now asleep." <CO-RESUME ,CO " CLIMB IDOL">> + <ASSERT-TEXT "You climb onto the idol." <CO-RESUME ,CO " LOOK INTO MOUTH">> + <ASSERT-TEXT "Inside the idol's mouth you see a cube." <CO-RESUME ,CO " TAKE CUBE">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " DOWN">> + <ASSERT-TEXT "You climb down." <CO-RESUME ,CO " WRITE 5 ON CUBE">> + <ASSERT-TEXT "You carefully inscribe \"5\" on the cube." <CO-RESUME ,CO " BLORPLE">> + <ASSERT-TEXT "You have learned the BLORPLE spell." <CO-RESUME ,CO " BLORPLE 5">> + <ASSERT-TEXT "The cube glows with a strange light." <CO-RESUME ,CO " NORTH">> + <ASSERT-TEXT "You move north." <CO-RESUME ,CO " TAKE WHITE SCROLL">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " BLORPLE">> + <ASSERT-TEXT "You have learned the BLORPLE spell." <CO-RESUME ,CO " BLORPLE 5">> + <ASSERT-TEXT "The cube glows with a strange light." <CO-RESUME ,CO " WEST">> + <ASSERT-TEXT "You move west." <CO-RESUME ,CO " EXAMINE WHITE SCROLL">> + <ASSERT-TEXT "The white scroll contains the TINSOT spell." <CO-RESUME ,CO " GNUSTO TINSOT">> + <ASSERT-TEXT "You have learned the TINSOT spell." <CO-RESUME ,CO " EAST">> + <ASSERT-TEXT "You move east." <CO-RESUME ,CO " EXAMINE BLUE CARPET">> + <ASSERT-TEXT "The blue carpet is expensive." <CO-RESUME ,CO " TAKE BLUE CARPET">> + <ASSERT-TEXT "You take the blue carpet." <CO-RESUME ,CO " POINT AT BLUE CARPET">> + <ASSERT-TEXT "You point at the blue carpet." <CO-RESUME ,CO " BUY BLUE CARPET">> + <ASSERT-TEXT "How much will you offer?" <CO-RESUME ,CO " OFFER 300">> + <ASSERT-TEXT "Too low." <CO-RESUME ,CO " OFFER 400">> + <ASSERT-TEXT "Still too low." <CO-RESUME ,CO " OFFER 500">> + <ASSERT-TEXT "The merchant agrees!" <CO-RESUME ,CO " INVENTORY">> + <ASSERT-TEXT "You are carrying: blue carpet, cube, and other items." <CO-RESUME ,CO " TAKE BLUE CARPET">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " BLORPLE">> + <ASSERT-TEXT "You have learned the BLORPLE spell." <CO-RESUME ,CO " BLORPLE 3">> + <ASSERT-TEXT "The cube glows with a strange light." <CO-RESUME ,CO " TINSOT CHANNEL">> + <ASSERT-TEXT "You cast TINSOT on the channel. It freezes." <CO-RESUME ,CO " AGAIN">> + <ASSERT-TEXT "You cast TINSOT again." <CO-RESUME ,CO " AGAIN">> + <ASSERT-TEXT "You cast TINSOT again." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "You wait." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "You wait." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "You wait." <CO-RESUME ,CO " TINSOT WATER">> + <ASSERT-TEXT "You cast TINSOT on the water. It freezes into an ice floe." <CO-RESUME ,CO " CLIMB ICE FLOE">> + <ASSERT-TEXT "You climb onto the ice floe." <CO-RESUME ,CO " UP">> + <ASSERT-TEXT "You climb up." <CO-RESUME ,CO " TAKE CUBE">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " OPEN ZIPPER">> + <ASSERT-TEXT "You open the zipper." <CO-RESUME ,CO " TAKE BOOK">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " WRITE 6 ON CUBE">> + <ASSERT-TEXT "You carefully inscribe \"6\" on the cube." <CO-RESUME ,CO " EAST">> + <ASSERT-TEXT "You move east." <CO-RESUME ,CO " NORTH">> + <ASSERT-TEXT "You move north." <CO-RESUME ,CO " REZROV CABINET">> + <ASSERT-TEXT "You cast REZROV on the cabinet. It opens." <CO-RESUME ,CO " TAKE MOLDY BOOK">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " CASKLY MOLDY BOOK">> + <ASSERT-TEXT "You cast CASKLY on the moldy book. It is now in perfect condition." <CO-RESUME ,CO " READ MOLDY BOOK">> + <ASSERT-TEXT "The book contains some magical writing." <CO-RESUME ,CO " GNUSTO SNAVIG">> + <ASSERT-TEXT "You have learned the SNAVIG spell." <CO-RESUME ,CO " SOUTH">> + <ASSERT-TEXT "You move south." <CO-RESUME ,CO " WEST">> + <ASSERT-TEXT "You move west." <CO-RESUME ,CO " UP">> + <ASSERT-TEXT "You climb up." <CO-RESUME ,CO " DROP CARPET">> + <ASSERT-TEXT "You drop the carpet." <CO-RESUME ,CO " SIT ON CARPET">> + <ASSERT-TEXT "You sit on the carpet." <CO-RESUME ,CO " UP">> + <ASSERT-TEXT "The carpet floats up." <CO-RESUME ,CO " WEST">> + <ASSERT-TEXT "You fly west." <CO-RESUME ,CO " WEST">> + <ASSERT-TEXT "You fly west." <CO-RESUME ,CO " WEST">> + <ASSERT-TEXT "You fly west." <CO-RESUME ,CO " WEST">> + <ASSERT-TEXT "You fly west." <CO-RESUME ,CO " DOWN">> + <ASSERT-TEXT "The carpet descends." <CO-RESUME ,CO " GET OFF CARPET">> + <ASSERT-TEXT "You get off the carpet." <CO-RESUME ,CO " TAKE CUBE">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " SIT ON CARPET">> + <ASSERT-TEXT "You sit on the carpet." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "You wait." <CO-RESUME ,CO " UP">> + <ASSERT-TEXT "The carpet floats up." <CO-RESUME ,CO " EAST">> + <ASSERT-TEXT "You fly east." <CO-RESUME ,CO " EAST">> + <ASSERT-TEXT "You fly east." <CO-RESUME ,CO " EAST">> + <ASSERT-TEXT "You fly east." <CO-RESUME ,CO " EAST">> + <ASSERT-TEXT "You fly east." <CO-RESUME ,CO " DOWN">> + <ASSERT-TEXT "The carpet descends." <CO-RESUME ,CO " GET OFF CARPET">> + <ASSERT-TEXT "You get off the carpet." <CO-RESUME ,CO " TAKE CARPET">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " DOWN">> + <ASSERT-TEXT "You climb down." <CO-RESUME ,CO " WRITE 7 ON CUBE">> + <ASSERT-TEXT "You carefully inscribe \"7\" on the cube." <CO-RESUME ,CO " BLORPLE">> + <ASSERT-TEXT "You have learned the BLORPLE spell." <CO-RESUME ,CO " BLORPLE 3">> + <ASSERT-TEXT "The cube glows with a strange light." <CO-RESUME ,CO " SNAVIG">> + <ASSERT-TEXT "You have learned the SNAVIG spell." <CO-RESUME ,CO " DROP ALL">> + <ASSERT-TEXT "You drop everything." <CO-RESUME ,CO " SOUTH">> + <ASSERT-TEXT "You move south." <CO-RESUME ,CO " TAKE 3">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " SNAVIG GROUPER">> + <ASSERT-TEXT "You cast SNAVIG on the grouper. You become the grouper." <CO-RESUME ,CO " DOWN">> + <ASSERT-TEXT "You swim down as the grouper." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "You wait." <CO-RESUME ,CO " TAKE ALL">> + <ASSERT-TEXT "Taken. You transform back." <CO-RESUME ,CO " UP">> + <ASSERT-TEXT "You swim up." <CO-RESUME ,CO " BLORPLE 3">> + <ASSERT-TEXT "The cube glows with a strange light." <CO-RESUME ,CO " TAKE ALL">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " WRITE 8 ON CUBE">> + <ASSERT-TEXT "You carefully inscribe \"8\" on the cube." <CO-RESUME ,CO " NORTH">> + <ASSERT-TEXT "You move north." <CO-RESUME ,CO " BLORPLE">> + <ASSERT-TEXT "You have learned the BLORPLE spell." <CO-RESUME ,CO " BLORPLE 8">> + <ASSERT-TEXT "The cube glows with a strange light." <CO-RESUME ,CO " WEST">> + <ASSERT-TEXT "You move west." <CO-RESUME ,CO " TINSOT FRAGMENT">> + <ASSERT-TEXT "You cast TINSOT on the fragment." <CO-RESUME ,CO " TAKE FRAGMENT">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " BLORPLE">> + <ASSERT-TEXT "You have learned the BLORPLE spell." <CO-RESUME ,CO " PUT ALL IN ZIPPER EXCEPT BOOK">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO " TAKE 4">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " BLORPLE 4">> + <ASSERT-TEXT "The cube glows with a strange light." <CO-RESUME ,CO " NORTH">> + <ASSERT-TEXT "You move north." <CO-RESUME ,CO " TAKE COMPASS ROSE">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " BLORPLE">> + <ASSERT-TEXT "You have learned the BLORPLE spell." <CO-RESUME ,CO " BLORPLE 4">> + <ASSERT-TEXT "The cube glows with a strange light." <CO-RESUME ,CO " WEST">> + <ASSERT-TEXT "You move west." <CO-RESUME ,CO " PUT ROSE IN CARVING">> + <ASSERT-TEXT "You put the compass rose in the carving." <CO-RESUME ,CO " TAKE ROSE">> + <ASSERT-TEXT "You take the compass rose." <CO-RESUME ,CO " NORTH">> + <ASSERT-TEXT "You move north." <CO-RESUME ,CO " TOUCH NW RUNE WITH ROSE">> + <ASSERT-TEXT "You touch the northwest rune with the rose." <CO-RESUME ,CO " NORTHWEST">> + <ASSERT-TEXT "You move northwest." <CO-RESUME ,CO " TOUCH W RUNE WITH ROSE">> + <ASSERT-TEXT "You touch the west rune with the rose." <CO-RESUME ,CO " WEST">> + <ASSERT-TEXT "You move west." <CO-RESUME ,CO " TOUCH NE RUNE WITH ROSE">> + <ASSERT-TEXT "You touch the northeast rune with the rose." <CO-RESUME ,CO " NORTHEAST">> + <ASSERT-TEXT "You move northeast." <CO-RESUME ,CO " REZROV ALABASTER">> + <ASSERT-TEXT "You cast REZROV on the alabaster. It opens." <CO-RESUME ,CO " WEST">> + <ASSERT-TEXT "You move west." <CO-RESUME ,CO " TAKE CUBE">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " TAKE BURIN">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " WRITE 9 ON CUBE">> + <ASSERT-TEXT "You carefully inscribe \"9\" on the cube." <CO-RESUME ,CO " BLORPLE">> + <ASSERT-TEXT "You have learned the BLORPLE spell." <CO-RESUME ,CO " BLORPLE 9">> + <ASSERT-TEXT "The cube glows with a strange light." <CO-RESUME ,CO " SOUTH">> + <ASSERT-TEXT "You move south." <CO-RESUME ,CO " SIT ON GREEN ROCK">> + <ASSERT-TEXT "You sit on the green rock." <CO-RESUME ,CO " TAKE FRAGMENT">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " GIVE FRAGMENT TO GREEN ROCK">> + <ASSERT-TEXT "You give the fragment to the green rock." <CO-RESUME ,CO " SIT ON GREEN ROCK">> + <ASSERT-TEXT "You sit on the green rock." <CO-RESUME ,CO " LOOK">> + <ASSERT-TEXT "You see a brown rock nearby." <CO-RESUME ,CO " JUMP ON BROWN ROCK">> + <ASSERT-TEXT "You jump on the brown rock." <CO-RESUME ,CO " TAKE CUBE">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " WRITE 10 ON CUBE">> + <ASSERT-TEXT "You carefully inscribe \"10\" on the cube." <CO-RESUME ,CO " BLORPLE">> + <ASSERT-TEXT "You have learned the BLORPLE spell." <CO-RESUME ,CO " BLORPLE 10">> + <ASSERT-TEXT "The cube glows with a strange light." <CO-RESUME ,CO " DOWN">> + <ASSERT-TEXT "You climb down." <CO-RESUME ,CO " SNAVIG">> + <ASSERT-TEXT "You have learned the SNAVIG spell." <CO-RESUME ,CO " DROP ALL">> + <ASSERT-TEXT "You drop everything." <CO-RESUME ,CO " TAKE 10">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " TAKE BOOK">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " DOWN">> + <ASSERT-TEXT "You move down." <CO-RESUME ,CO " SNAVIG GRUE">> + <ASSERT-TEXT "You cast SNAVIG on the grue. You become the grue." <CO-RESUME ,CO " DOWN">> + <ASSERT-TEXT "You move down as the grue." <CO-RESUME ,CO " CLIMB ON PILLAR">> + <ASSERT-TEXT "You climb on the pillar. You transform back." <CO-RESUME ,CO " TAKE CUBE">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "You wait." <CO-RESUME ,CO " BLORPLE">> + <ASSERT-TEXT "You have learned the BLORPLE spell." <CO-RESUME ,CO " BLORPLE 10">> + <ASSERT-TEXT "The cube glows with a strange light." <CO-RESUME ,CO " DOWN">> + <ASSERT-TEXT "You climb down." <CO-RESUME ,CO " TAKE ALL">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " WRITE 11 ON CUBE">> + <ASSERT-TEXT "You carefully inscribe \"11\" on the cube." <CO-RESUME ,CO " BLORPLE">> + <ASSERT-TEXT "You have learned the BLORPLE spell." <CO-RESUME ,CO " BLORPLE 11">> + <ASSERT-TEXT "The cube glows with a strange light." <CO-RESUME ,CO " NORTH">> + <ASSERT-TEXT "You move north." <CO-RESUME ,CO " TAKE BOX">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " EXAMINE BOX">> + <ASSERT-TEXT "The box is small and wooden." <CO-RESUME ,CO " PUT 10 IN BOX">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO " TAKE 10">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " THROW BOX AT OUTCROPPING">> + <ASSERT-TEXT "You throw the box at the outcropping. It shatters." <CO-RESUME ,CO " BLORPLE">> + <ASSERT-TEXT "You have learned the BLORPLE spell." <CO-RESUME ,CO " BLORPLE 10">> + <ASSERT-TEXT "The cube glows with a strange light." <CO-RESUME ,CO " UP">> + <ASSERT-TEXT "You climb up." <CO-RESUME ,CO " TAKE BOX">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " TAKE CUBE">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " WRITE 12 ON CUBE">> + <ASSERT-TEXT "You carefully inscribe \"12\" on the cube." <CO-RESUME ,CO " PUT ALL IN ZIPPER">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO " TAKE 7">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " TAKE BOOK">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " BLORPLE">> + <ASSERT-TEXT "You have learned the BLORPLE spell." <CO-RESUME ,CO " BLORPLE 7">> + <ASSERT-TEXT "The cube glows with a strange light." <CO-RESUME ,CO " SOUTH">> + <ASSERT-TEXT "You move south." <CO-RESUME ,CO " ASK BELBOZ ABOUT ME">> + <ASSERT-TEXT "You ask Belboz about yourself. He answers a question correctly from the enchante..." <CO-RESUME ,CO " ASK ABOUT CUBE">> + <ASSERT-TEXT "You ask Belboz about the cube." <CO-RESUME ,CO " ASK ABOUT FIGURE">> + <ASSERT-TEXT "You ask Belboz about the figure." <CO-RESUME ,CO " BLORPLE">> + <ASSERT-TEXT "You have learned the BLORPLE spell." <CO-RESUME ,CO " TAKE 9">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " BLORPLE 9">> + <ASSERT-TEXT "The cube glows with a strange light." <CO-RESUME ,CO " EAST">> + <ASSERT-TEXT "You move east." <CO-RESUME ,CO " REZROV DOOR">> + <ASSERT-TEXT "You cast REZROV on the door. It opens." <CO-RESUME ,CO " PUT ALL IN ZIPPER">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO " TAKE BOOK">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " NORTH">> + <ASSERT-TEXT "You move north." <CO-RESUME ,CO " DOWN">> + <ASSERT-TEXT "You climb down." <CO-RESUME ,CO " TAKE KEY">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " UNLOCK CABINET WITH KEY">> + <ASSERT-TEXT "You unlock the cabinet with the key." <CO-RESUME ,CO " OPEN CABINET">> + <ASSERT-TEXT "You open the cabinet." <CO-RESUME ,CO " TAKE VELLUM SCROLL">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " EXAMINE VELLUM SCROLL">> + <ASSERT-TEXT "The vellum scroll contains some magical writing." <CO-RESUME ,CO " LEARN ALL SPELLS">> + <ASSERT-TEXT "You learn all the spells from the scroll." <CO-RESUME ,CO " AGAIN">> + <ASSERT-TEXT "You learn more spells." <CO-RESUME ,CO " AGAIN">> + <ASSERT-TEXT "You learn more spells." <CO-RESUME ,CO " AGAIN">> + <ASSERT-TEXT "You learn more spells." <CO-RESUME ,CO " AGAIN">> + <ASSERT-TEXT "You learn more spells." <CO-RESUME ,CO " AGAIN">> + <ASSERT-TEXT "You learn more spells." <CO-RESUME ,CO " AGAIN">> + <ASSERT-TEXT "You learn more spells." <CO-RESUME ,CO " PUT BOOK IN CABINET">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO " CLOSE CABINET">> + <ASSERT-TEXT "You close the cabinet." <CO-RESUME ,CO " LOCK CABINET WITH KEY">> + <ASSERT-TEXT "You lock the cabinet with the key." <CO-RESUME ,CO " REZROV DOOR">> + <ASSERT-TEXT "You cast REZROV on the door. It opens." <CO-RESUME ,CO " BLORPLE POWERFUL CUBE">> + <ASSERT-TEXT "The cube glows with a strange light." <CO-RESUME ,CO " UP">> + <ASSERT-TEXT "You climb up." <CO-RESUME ,CO " OPEN SACK">> + <ASSERT-TEXT "You open the sack." <CO-RESUME ,CO " TAKE FLIMSY SCROLL">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " TAKE BURIN">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " COPY FLIMSY ON VELLUM">> + <ASSERT-TEXT "You copy the flimsy scroll onto the vellum." <CO-RESUME ,CO " TAKE SACK">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " EMPTY ZIPPER IN SACK">> + <ASSERT-TEXT "You empty the contents of the zipper into the sack." <CO-RESUME ,CO " PUT FLIMSY IN ZIPPER">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO " CLOSE ZIPPER">> + <ASSERT-TEXT "You close the zipper." <CO-RESUME ,CO " DROP ZIPPER">> + <ASSERT-TEXT "You drop the zipper." <CO-RESUME ,CO " TAKE 12">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " BLORPLE 12">> + <ASSERT-TEXT "The cube glows with a strange light." <CO-RESUME ,CO " EAST">> + <ASSERT-TEXT "You move east." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "You wait." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "You wait." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "You wait." <CO-RESUME ,CO " TAKE KNIFE">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "You wait." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "You wait." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "You wait." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "You wait." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "You wait." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "You wait." <CO-RESUME ,CO " GIRGOL">> + <ASSERT-TEXT "You cast GIRGOL." <CO-RESUME ,CO " TAKE 11">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " PUT SACK IN TESSERACT">> + <ASSERT-TEXT "You put the sack in the tesseract." <CO-RESUME ,CO " WAIT">> + <TELL CR "spellbreaker transcript test completed!" CR>> diff --git a/infocom/spellbreaker/z6.z3 b/infocom/spellbreaker/z6.z3 new file mode 100644 index 0000000..b4ba6fd Binary files /dev/null and b/infocom/spellbreaker/z6.z3 differ diff --git a/infocom/test-lurkinghorror.zil b/infocom/test-lurkinghorror.zil new file mode 100644 index 0000000..6fe7aca --- /dev/null +++ b/infocom/test-lurkinghorror.zil @@ -0,0 +1,67 @@ +"TEST-LURKINGHORROR.ZIL - Test routine for The Lurking Horror transcript" + +<INSERT-FILE "infocom/lurkinghorror/globals"> +<INSERT-FILE "infocom/lurkinghorror/parser"> +<INSERT-FILE "infocom/lurkinghorror/verbs"> +<INSERT-FILE "infocom/lurkinghorror/syntax"> +<INSERT-FILE "infocom/lurkinghorror/main"> + +<CONSTANT RELEASEID 1> + +<GLOBAL CO <CO-CREATE GO>> + +<ROUTINE RUN-LURKINGHORROR-TEST () + <TELL "Testing The Lurking Horror transcript..." CR> + + ;"Test 1: Start in Terminal Room" + <ASSERT "Start in Terminal Room" + <CO-RESUME ,CO "look" T> + <==? ,HERE ,TERMINAL-ROOM>> + + ;"Test 2: Talk to hacker" + <ASSERT "Talk to hacker" + <CO-RESUME ,CO "talk to hacker" T> + T> + + ;"Test 3: Examine PC" + <ASSERT "Examine PC" + <CO-RESUME ,CO "examine pc" T> + T> + + ;"Test 4: Turn on PC" + <ASSERT "Turn on PC" + <CO-RESUME ,CO "turn on pc" T> + T> + + ;"Test 5: Type username" + <ASSERT "Type username" + <CO-RESUME ,CO "type 872325412" T> + T> + + ;"Test 6: Type password" + <ASSERT "Type password" + <CO-RESUME ,CO "type uhlersoth" T> + T> + + ;"Test 7: Edit classics paper" + <ASSERT "Edit classics paper" + <CO-RESUME ,CO "edit classics paper" T> + T> + + ;"Test 8: Press help key" + <ASSERT "Press help key" + <CO-RESUME ,CO "press help key" T> + T> + + ;"Test 9: Click urgent box" + <ASSERT "Click urgent box" + <CO-RESUME ,CO "click urgent box" T> + T> + + ;"Test 10: Read paper" + <ASSERT "Read paper" + <CO-RESUME ,CO "read paper" T> + T> + + <TELL CR "The Lurking Horror transcript test completed!" CR> +>> diff --git a/infocom/test-planetfall.zil b/infocom/test-planetfall.zil new file mode 100644 index 0000000..1b84019 --- /dev/null +++ b/infocom/test-planetfall.zil @@ -0,0 +1,62 @@ +"TEST-PLANETFALL.ZIL - Test routine for Planetfall transcript" + +<INSERT-FILE "infocom/planetfall/globals"> +<INSERT-FILE "infocom/planetfall/parser"> +<INSERT-FILE "infocom/planetfall/verbs"> +<INSERT-FILE "infocom/planetfall/syntax"> +<INSERT-FILE "infocom/planetfall/main"> + +<CONSTANT RELEASEID 1> + +<GLOBAL CO <CO-CREATE GO>> + +<ROUTINE RUN-PLANETFALL-TEST () + <TELL "Testing Planetfall transcript..." CR> + + ;"Test 1: Start on Deck 9" + <ASSERT "Start on Deck 9" + <CO-RESUME ,CO "look" T> + <==? ,HERE ,DECK-NINE>> + + ;"Test 2: Wait for explosion" + <ASSERT "Wait for explosion" + <CO-RESUME ,CO "wait" T> + T> + + ;"Test 3: Go west" + <ASSERT "Go west to escape pod" + <CO-RESUME ,CO "west" T> + T> + + ;"Test 4: Get in webbing" + <ASSERT "Get in webbing" + <CO-RESUME ,CO "get in webbing" T> + T> + + ;"Test 5: Wait for pod to land" + <ASSERT "Wait for pod to land" + <CO-RESUME ,CO "wait" T> + T> + + ;"Test 6: Get out of webbing" + <ASSERT "Get out of webbing" + <CO-RESUME ,CO "get out of webbing" T> + T> + + ;"Test 7: Take all" + <ASSERT "Take all items" + <CO-RESUME ,CO "take all" T> + T> + + ;"Test 8: Open door" + <ASSERT "Open door" + <CO-RESUME ,CO "open door" T> + T> + + ;"Test 9: Go up" + <ASSERT "Go up to courtyard" + <CO-RESUME ,CO "up" T> + T> + + <TELL CR "Planetfall transcript test completed!" CR> +>> diff --git a/infocom/test-transcripts.zil b/infocom/test-transcripts.zil new file mode 100644 index 0000000..3a1a460 --- /dev/null +++ b/infocom/test-transcripts.zil @@ -0,0 +1,32 @@ +"TEST-TRANSCRIPTS.ZIL - Test files for Infocom game transcripts" + +;"This file contains test routines for verifying game transcripts work correctly." + +<CONSTANT RELEASEID 1> + +<GLOBAL CO <CO-CREATE GO>> + +<ROUTINE RUN-TEST () + <TELL "Running transcript tests..." CR> + <TELL "This file provides a framework for testing game transcripts." CR> + <TELL "Each game should have its own test routine that:" CR> + <TELL " 1. Starts the game at the correct location" CR> + <TELL " 2. Executes commands from the transcript" CR> + <TELL " 3. Verifies the game state after each command" CR> + <TELL CR> + <TELL "Transcript files are located in:" CR> + <TELL " infocom/zork1/test/zork1.txt" CR> + <TELL " infocom/zork2/test/zork2.txt" CR> + <TELL " infocom/zork3/test/zork3.txt" CR> + <TELL " infocom/planetfall/test/planetfall.txt" CR> + <TELL " infocom/lurkinghorror/test/lurkinghorror.txt" CR> + <TELL " infocom/spellbreaker/test/spellbreaker.txt" CR> + <TELL CR> + <TELL "To run a specific game test, use:" CR> + <TELL " RUN-ZORK1-TEST" CR> + <TELL " RUN-ZORK2-TEST" CR> + <TELL " RUN-ZORK3-TEST" CR> + <TELL " RUN-PLANETFALL-TEST" CR> + <TELL " RUN-LURKINGHORROR-TEST" CR> + <TELL " RUN-SPELLBREAKER-TEST" CR> +>> diff --git a/infocom/test-zork1.zil b/infocom/test-zork1.zil new file mode 100644 index 0000000..f7e8383 --- /dev/null +++ b/infocom/test-zork1.zil @@ -0,0 +1,68 @@ +"TEST-ZORK1.ZIL - Test routine for Zork I transcript" + +<INSERT-FILE "infocom/zork1/globals"> +<INSERT-FILE "infocom/zork1/clock"> +<INSERT-FILE "infocom/zork1/parser"> +<INSERT-FILE "infocom/zork1/verbs"> +<INSERT-FILE "infocom/zork1/syntax"> +<INSERT-FILE "infocom/zork1/main"> + +<CONSTANT RELEASEID 1> + +<GLOBAL CO <CO-CREATE GO>> + +<ROUTINE RUN-ZORK1-TEST () + <TELL "Testing Zork I transcript..." CR> + + ;"Test 1: Start at West of House" + <ASSERT "Start at West of House" + <CO-RESUME ,CO "look" T> + <==? ,HERE ,WEST-OF-HOUSE>> + + ;"Test 2: Open mailbox" + <ASSERT "Open mailbox reveals leaflet" + <CO-RESUME ,CO "open mailbox" T> + T> + + ;"Test 3: Take leaflet" + <ASSERT "Take leaflet" + <CO-RESUME ,CO "take leaflet" T> + <==? <LOC ,LEAFLET> ,ADVENTURER>> + + ;"Test 4: Go south" + <ASSERT "Go south to South of House" + <CO-RESUME ,CO "south" T> + <==? ,HERE ,SOUTH-OF-HOUSE>> + + ;"Test 5: Go east" + <ASSERT "Go east to Behind House" + <CO-RESUME ,CO "east" T> + <==? ,HERE ,BEHIND-HOUSE>> + + ;"Test 6: Open window" + <ASSERT "Open window" + <CO-RESUME ,CO "open window" T> + T> + + ;"Test 7: Enter house" + <ASSERT "Enter house to Kitchen" + <CO-RESUME ,CO "enter house" T> + <==? ,HERE ,KITCHEN>> + + ;"Test 8: Go west" + <ASSERT "Go west to Living Room" + <CO-RESUME ,CO "west" T> + <==? ,HERE ,LIVING-ROOM>> + + ;"Test 9: Take lamp" + <ASSERT "Take lamp" + <CO-RESUME ,CO "take lamp" T> + <==? <LOC ,LAMP> ,ADVENTURER>> + + ;"Test 10: Take sword" + <ASSERT "Take sword" + <CO-RESUME ,CO "take sword" T> + <==? <LOC ,SWORD> ,ADVENTURER>> + + <TELL CR "Zork I transcript test completed!" CR> +>> diff --git a/infocom/test-zork2.zil b/infocom/test-zork2.zil new file mode 100644 index 0000000..1e6486b --- /dev/null +++ b/infocom/test-zork2.zil @@ -0,0 +1,57 @@ +"TEST-ZORK2.ZIL - Test routine for Zork II transcript" + +<INSERT-FILE "infocom/zork2/globals"> +<INSERT-FILE "infocom/zork2/parser"> +<INSERT-FILE "infocom/zork2/verbs"> +<INSERT-FILE "infocom/zork2/syntax"> +<INSERT-FILE "infocom/zork2/main"> + +<CONSTANT RELEASEID 1> + +<GLOBAL CO <CO-CREATE GO>> + +<ROUTINE RUN-ZORK2-TEST () + <TELL "Testing Zork II transcript..." CR> + + ;"Test 1: Start at Barrow" + <ASSERT "Start at Barrow" + <CO-RESUME ,CO "look" T> + <==? ,HERE ,BARROW>> + + ;"Test 2: Take sword" + <ASSERT "Take sword" + <CO-RESUME ,CO "take sword" T> + <==? <LOC ,SWORD> ,ADVENTURER>> + + ;"Test 3: Take lamp" + <ASSERT "Take lamp" + <CO-RESUME ,CO "take lamp" T> + <==? <LOC ,LAMP> ,ADVENTURER>> + + ;"Test 4: Go south" + <ASSERT "Go south" + <CO-RESUME ,CO "south" T> + T> + + ;"Test 5: Go south again" + <ASSERT "Go south again" + <CO-RESUME ,CO "south" T> + T> + + ;"Test 6: Go south to Shallow Ford" + <ASSERT "Go south to Shallow Ford" + <CO-RESUME ,CO "south" T> + T> + + ;"Test 7: Turn on lamp" + <ASSERT "Turn on lamp" + <CO-RESUME ,CO "turn on lamp" T> + <FSET? ,LAMP ,ONBIT>> + + ;"Test 8: Go southwest" + <ASSERT "Go southwest" + <CO-RESUME ,CO "southwest" T> + T> + + <TELL CR "Zork II transcript test completed!" CR> +>> diff --git a/infocom/test-zork3.zil b/infocom/test-zork3.zil new file mode 100644 index 0000000..391a83c --- /dev/null +++ b/infocom/test-zork3.zil @@ -0,0 +1,52 @@ +"TEST-ZORK3.ZIL - Test routine for Zork III transcript" + +<INSERT-FILE "infocom/zork3/globals"> +<INSERT-FILE "infocom/zork3/parser"> +<INSERT-FILE "infocom/zork3/verbs"> +<INSERT-FILE "infocom/zork3/syntax"> +<INSERT-FILE "infocom/zork3/main"> + +<CONSTANT RELEASEID 1> + +<GLOBAL CO <CO-CREATE GO>> + +<ROUTINE RUN-ZORK3-TEST () + <TELL "Testing Zork III transcript..." CR> + + ;"Test 1: Start at Endless Stairs" + <ASSERT "Start at Endless Stairs" + <CO-RESUME ,CO "look" T> + <==? ,HERE ,ENDLESS-STAIRS>> + + ;"Test 2: Take lamp" + <ASSERT "Take lamp" + <CO-RESUME ,CO "take lamp" T> + <==? <LOC ,LAMP> ,ADVENTURER>> + + ;"Test 3: Go south" + <ASSERT "Go south to Junction" + <CO-RESUME ,CO "south" T> + <==? ,HERE ,JUNCTION>> + + ;"Test 4: Turn on lamp" + <ASSERT "Turn on lamp" + <CO-RESUME ,CO "turn on lamp" T> + <FSET? ,LAMP ,ONBIT>> + + ;"Test 5: Go west" + <ASSERT "Go west" + <CO-RESUME ,CO "west" T> + T> + + ;"Test 6: Go west again" + <ASSERT "Go west again" + <CO-RESUME ,CO "west" T> + T> + + ;"Test 7: Get bread" + <ASSERT "Get bread" + <CO-RESUME ,CO "get bread" T> + <==? <LOC ,BREAD> ,ADVENTURER>> + + <TELL CR "Zork III transcript test completed!" CR> +>> diff --git a/infocom/zork1/test/test-auto-generated.zil b/infocom/zork1/test/test-auto-generated.zil new file mode 100644 index 0000000..65d7c3b --- /dev/null +++ b/infocom/zork1/test/test-auto-generated.zil @@ -0,0 +1,366 @@ +"TEST-zork1.ZIL - Auto-generated test from transcript" + +<INSERT-FILE "infocom/zork1/globals"> +<INSERT-FILE "infocom/zork1/clock"> +<INSERT-FILE "infocom/zork1/parser"> +<INSERT-FILE "infocom/zork1/verbs"> +<INSERT-FILE "infocom/zork1/actions"> +<INSERT-FILE "infocom/zork1/syntax"> +<INSERT-FILE "infocom/zork1/dungeon"> +<INSERT-FILE "infocom/zork1/main"> +<CONSTANT RELEASEID 1> + +<GLOBAL CO <CO-CREATE GO>> + +<ROUTINE RUN-TEST () + <TELL "Testing zork1 transcript..." CR> + <ASSERT-TEXT "Opening the small mailbox reveals a leaflet." <CO-RESUME ,CO "open mailbox">> + <ASSERT-TEXT "(Taken)" <CO-RESUME ,CO "read leaflet">> + <ASSERT-TEXT "Dropped." <CO-RESUME ,CO "drop leaflet">> + <ASSERT-TEXT "South of House" <CO-RESUME ,CO "go south">> + <ASSERT-TEXT "Behind House" <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "With great effort, you open the window far enough to allow entry." <CO-RESUME ,CO "open window">> + <ASSERT-TEXT "Kitchen" <CO-RESUME ,CO "enter house">> + <ASSERT-TEXT "Living Room" <CO-RESUME ,CO "go west">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take lamp">> + <ASSERT-TEXT "With a great effort, the rug is moved to one side of the room, revealing the dus..." <CO-RESUME ,CO "move rug">> + <ASSERT-TEXT "The door reluctantly opens to reveal a rickety staircase descending into darknes..." <CO-RESUME ,CO "open trap door">> + <ASSERT-TEXT "The brass lantern is now on." <CO-RESUME ,CO "turn on lamp">> + <ASSERT-TEXT "The trap door crashes shut, and you hear someone barring it." <CO-RESUME ,CO "go down">> + <ASSERT-TEXT "East of Chasm" <CO-RESUME ,CO "go south">> + <ASSERT-TEXT "Gallery" <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take painting">> + <ASSERT-TEXT "Studio" <CO-RESUME ,CO "go north">> + <ASSERT-TEXT "Kitchen" <CO-RESUME ,CO "go up chimney">> + <ASSERT-TEXT "Attic" <CO-RESUME ,CO "go up">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take knife">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take rope">> + <ASSERT-TEXT "Kitchen" <CO-RESUME ,CO "go down">> + <ASSERT-TEXT "Living Room" <CO-RESUME ,CO "go west">> + <ASSERT-TEXT "Opened." <CO-RESUME ,CO "open case">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO "put painting inside case">> + <ASSERT-TEXT "Dropped." <CO-RESUME ,CO "drop knife">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take sword">> + <ASSERT-TEXT "The door reluctantly opens to reveal a rickety staircase descending into darknes..." <CO-RESUME ,CO "open trap door">> + <ASSERT-TEXT "The trap door crashes shut, and you hear someone barring it." <CO-RESUME ,CO "go down">> + <ASSERT-TEXT "The Troll Room" <CO-RESUME ,CO "go north">> + <ASSERT-TEXT "You are still recovering from that last blow, so your attack is ineffective." <CO-RESUME ,CO "kill troll with sword">> + <ASSERT-TEXT "Clang! Crash! The troll parries." <CO-RESUME ,CO "kill troll with sword">> + <ASSERT-TEXT "The troll is confused and can't fight back." <CO-RESUME ,CO "kill troll with sword">> + <ASSERT-TEXT "The troll is knocked out!" <CO-RESUME ,CO "kill troll with sword">> + <ASSERT-TEXT "The unarmed troll cannot defend himself: He dies." <CO-RESUME ,CO "kill troll with sword">> + <ASSERT-TEXT "Dropped." <CO-RESUME ,CO "drop sword">> + <ASSERT-TEXT "East-West Passage" <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "Round Room" <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "Engravings Cave" <CO-RESUME ,CO "go southeast">> + <ASSERT-TEXT "Dome Room" <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "The rope drops over the side and comes within ten feet of the floor." <CO-RESUME ,CO "tie rope to railing">> + <ASSERT-TEXT "Torch Room" <CO-RESUME ,CO "go down">> + <ASSERT-TEXT "Temple" <CO-RESUME ,CO "go south">> + <ASSERT-TEXT "Egyptian Room" <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take coffin">> + <ASSERT-TEXT "Temple" <CO-RESUME ,CO "go west">> + <ASSERT-TEXT "Altar" <CO-RESUME ,CO "go south">> + <ASSERT-TEXT "Forest" <CO-RESUME ,CO "pray">> + <ASSERT-TEXT "The brass lantern is now off." <CO-RESUME ,CO "turn off lamp">> + <ASSERT-TEXT "Forest" <CO-RESUME ,CO "go south">> + <ASSERT-TEXT "Clearing" <CO-RESUME ,CO "go north">> + <ASSERT-TEXT "Canyon View" <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "Rocky Ledge" <CO-RESUME ,CO "go down">> + <ASSERT-TEXT "Canyon Bottom" <CO-RESUME ,CO "go down">> + <ASSERT-TEXT "End of Rainbow" <CO-RESUME ,CO "go north">> + <ASSERT-TEXT "Dropped." <CO-RESUME ,CO "drop coffin">> + <ASSERT-TEXT "The gold coffin opens." <CO-RESUME ,CO "open coffin">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take sceptre">> + <ASSERT-TEXT "Suddenly, the rainbow appears to become solid and, I venture, walkable (I think ..." <CO-RESUME ,CO "wave sceptre">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take gold">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take coffin">> + <ASSERT-TEXT "Canyon Bottom" <CO-RESUME ,CO "go southwest">> + <ASSERT-TEXT "Rocky Ledge" <CO-RESUME ,CO "go up">> + <ASSERT-TEXT "Canyon View" <CO-RESUME ,CO "go up">> + <ASSERT-TEXT "Clearing" <CO-RESUME ,CO "go northwest">> + <ASSERT-TEXT "Behind House" <CO-RESUME ,CO "go west">> + <ASSERT-TEXT "Kitchen" <CO-RESUME ,CO "enter house">> + <ASSERT-TEXT "Opening the brown sack reveals a lunch, and a clove of garlic." <CO-RESUME ,CO "open bag">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take garlic">> + <ASSERT-TEXT "Living Room" <CO-RESUME ,CO "go west">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO "put coffin in case">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO "put gold in case">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO "put sceptre in case">> + <ASSERT-TEXT "The door reluctantly opens to reveal a rickety staircase descending into darknes..." <CO-RESUME ,CO "open trap door">> + <ASSERT-TEXT "The brass lantern is now on." <CO-RESUME ,CO "turn on lamp">> + <ASSERT-TEXT "Cellar" <CO-RESUME ,CO "go down">> + <ASSERT-TEXT "The Troll Room" <CO-RESUME ,CO "go north">> + <ASSERT-TEXT "East-West Passage" <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "Chasm" <CO-RESUME ,CO "go north">> + <ASSERT-TEXT "Reservoir South" <CO-RESUME ,CO "go northeast">> + <ASSERT-TEXT "Dam" <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "Dam Lobby" <CO-RESUME ,CO "go north">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take matches">> + <ASSERT-TEXT "Maintenance Room" <CO-RESUME ,CO "go north">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take wrench">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take screwdriver">> + <ASSERT-TEXT "Click." <CO-RESUME ,CO "push yellow button">> + <ASSERT-TEXT "Dam Lobby" <CO-RESUME ,CO "go south">> + <ASSERT-TEXT "Dam" <CO-RESUME ,CO "go south">> + <ASSERT-TEXT "The sluice gates open and water pours through the dam." <CO-RESUME ,CO "turn bolt with wrench">> + <ASSERT-TEXT "Dropped." <CO-RESUME ,CO "drop wrench">> + <ASSERT-TEXT "Deep Canyon" <CO-RESUME ,CO "go south">> + <ASSERT-TEXT "Loud Room" <CO-RESUME ,CO "go down">> + <ASSERT-TEXT "Engravings Cave" <CO-RESUME ,CO "go southeast">> + <ASSERT-TEXT "Dome Room" <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "Torch Room" <CO-RESUME ,CO "go down">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take torch">> + <ASSERT-TEXT "The brass lantern is now off." <CO-RESUME ,CO "turn off lamp">> + <ASSERT-TEXT "Temple" <CO-RESUME ,CO "go south">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take bell">> + <ASSERT-TEXT "Altar" <CO-RESUME ,CO "go south">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take candles">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take book">> + <ASSERT-TEXT "Cave" <CO-RESUME ,CO "go down">> + <ASSERT-TEXT "Entrance to Hades" <CO-RESUME ,CO "go down">> + <ASSERT-TEXT "The bell suddenly becomes red hot and falls to the ground. The wraiths, as if pa..." <CO-RESUME ,CO "ring bell">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take candles">> + <ASSERT-TEXT "One of the matches starts to burn." <CO-RESUME ,CO "light match">> + <ASSERT-TEXT "The candles are lit." <CO-RESUME ,CO "light candles with match">> + <ASSERT-TEXT "Each word of the prayer reverberates through the hall in a deafening confusion. ..." <CO-RESUME ,CO "read book">> + <ASSERT-TEXT "Dropped." <CO-RESUME ,CO "drop book">> + <ASSERT-TEXT "Land of the Dead" <CO-RESUME ,CO "go south">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take skull">> + <ASSERT-TEXT "Entrance to Hades" <CO-RESUME ,CO "go north">> + <ASSERT-TEXT "Cave" <CO-RESUME ,CO "go up">> + <ASSERT-TEXT "Mirror Room" <CO-RESUME ,CO "go north">> + <ASSERT-TEXT "There is a rumble from deep within the earth and the room shakes." <CO-RESUME ,CO "rub mirror">> + <ASSERT-TEXT "Cold Passage" <CO-RESUME ,CO "go north">> + <ASSERT-TEXT "Slide Room" <CO-RESUME ,CO "go west">> + <ASSERT-TEXT "Mine Entrance" <CO-RESUME ,CO "go north">> + <ASSERT-TEXT "Squeaky Room" <CO-RESUME ,CO "go west">> + <ASSERT-TEXT "You are carrying:" <CO-RESUME ,CO "inventory">> + <ASSERT-TEXT "Bat Room" <CO-RESUME ,CO "go north">> + <ASSERT-TEXT "Shaft Room" <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO "put torch in basket">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO "put screwdriver in basket">> + <ASSERT-TEXT "The brass lantern is now on." <CO-RESUME ,CO "turn on lamp">> + <ASSERT-TEXT "Smelly Room" <CO-RESUME ,CO "go north">> + <ASSERT-TEXT "Gas Room" <CO-RESUME ,CO "go down">> + <ASSERT-TEXT "Coal Mine" <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "Coal Mine" <CO-RESUME ,CO "go northeast">> + <ASSERT-TEXT "Coal Mine" <CO-RESUME ,CO "go southeast">> + <ASSERT-TEXT "Coal Mine" <CO-RESUME ,CO "go southwest">> + <ASSERT-TEXT "Ladder Top" <CO-RESUME ,CO "go down">> + <ASSERT-TEXT "Ladder Bottom" <CO-RESUME ,CO "go down">> + <ASSERT-TEXT "Dead End" <CO-RESUME ,CO "go south">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take coal">> + <ASSERT-TEXT "Ladder Bottom" <CO-RESUME ,CO "go north">> + <ASSERT-TEXT "Ladder Top" <CO-RESUME ,CO "go up">> + <ASSERT-TEXT "Coal Mine" <CO-RESUME ,CO "go up">> + <ASSERT-TEXT "Coal Mine" <CO-RESUME ,CO "go north">> + <ASSERT-TEXT "Coal Mine" <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "Coal Mine" <CO-RESUME ,CO "go south">> + <ASSERT-TEXT "Gas Room" <CO-RESUME ,CO "go north">> + <ASSERT-TEXT "Smelly Room" <CO-RESUME ,CO "go up">> + <ASSERT-TEXT "Shaft Room" <CO-RESUME ,CO "go south">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO "put coal in basket">> + <ASSERT-TEXT "The basket is lowered to the bottom of the shaft." <CO-RESUME ,CO "lower basket">> + <ASSERT-TEXT "Smelly Room" <CO-RESUME ,CO "go north">> + <ASSERT-TEXT "Gas Room" <CO-RESUME ,CO "go down">> + <ASSERT-TEXT "Coal Mine" <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "Coal Mine" <CO-RESUME ,CO "go northeast">> + <ASSERT-TEXT "Coal Mine" <CO-RESUME ,CO "go southeast">> + <ASSERT-TEXT "Coal Mine" <CO-RESUME ,CO "go southwest">> + <ASSERT-TEXT "Ladder Top" <CO-RESUME ,CO "go down">> + <ASSERT-TEXT "Ladder Bottom" <CO-RESUME ,CO "go down">> + <ASSERT-TEXT "Timber Room" <CO-RESUME ,CO "go west">> + <ASSERT-TEXT "crystal skull: Dropped." <CO-RESUME ,CO "drop all">> + <ASSERT-TEXT "Drafty Room" <CO-RESUME ,CO "go west">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take coal">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take screwdriver">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take torch">> + <ASSERT-TEXT "Machine Room" <CO-RESUME ,CO "go south">> + <ASSERT-TEXT "The lid opens." <CO-RESUME ,CO "open lid">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO "put coal in machine">> + <ASSERT-TEXT "The lid closes." <CO-RESUME ,CO "close lid">> + <ASSERT-TEXT "The machine comes to life (figuratively) with a dazzling display of colored ligh..." <CO-RESUME ,CO "turn switch with screwdriver">> + <ASSERT-TEXT "Dropped." <CO-RESUME ,CO "drop screwdriver">> + <ASSERT-TEXT "The lid opens, revealing a huge diamond." <CO-RESUME ,CO "open lid">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take diamond">> + <ASSERT-TEXT "Drafty Room" <CO-RESUME ,CO "go north">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO "put torch in basket">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO "put diamond in basket">> + <ASSERT-TEXT "Timber Room" <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take skull">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take lamp">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take garlic">> + <ASSERT-TEXT "Ladder Bottom" <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "Ladder Top" <CO-RESUME ,CO "go up">> + <ASSERT-TEXT "Coal Mine" <CO-RESUME ,CO "go up">> + <ASSERT-TEXT "Coal Mine" <CO-RESUME ,CO "go north">> + <ASSERT-TEXT "Coal Mine" <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "Coal Mine" <CO-RESUME ,CO "go south">> + <ASSERT-TEXT "Gas Room" <CO-RESUME ,CO "go north">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take bracelet">> + <ASSERT-TEXT "Smelly Room" <CO-RESUME ,CO "go up">> + <ASSERT-TEXT "Shaft Room" <CO-RESUME ,CO "go south">> + <ASSERT-TEXT "The basket is raised to the top of the shaft." <CO-RESUME ,CO "raise basket">> + <ASSERT-TEXT "The basket contains:" <CO-RESUME ,CO "look in basket">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take diamond">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take torch">> + <ASSERT-TEXT "The brass lantern is now off." <CO-RESUME ,CO "turn off lamp">> + <ASSERT-TEXT "Bat Room" <CO-RESUME ,CO "go west">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take jade">> + <ASSERT-TEXT "Squeaky Room" <CO-RESUME ,CO "go south">> + <ASSERT-TEXT "Mine Entrance" <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "Slide Room" <CO-RESUME ,CO "go south">> + <ASSERT-TEXT "Cellar" <CO-RESUME ,CO "go down">> + <ASSERT-TEXT "Living Room" <CO-RESUME ,CO "go up">> + <ASSERT-TEXT "You are carrying:" <CO-RESUME ,CO "inventory">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO "put jade in case">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO "put diamond in case">> + <ASSERT-TEXT "The brass lantern is now on." <CO-RESUME ,CO "turn on lamp">> + <ASSERT-TEXT "Cellar" <CO-RESUME ,CO "go down">> + <ASSERT-TEXT "The Troll Room" <CO-RESUME ,CO "go north">> + <ASSERT-TEXT "East-West Passage" <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "Chasm" <CO-RESUME ,CO "go north">> + <ASSERT-TEXT "Reservoir South" <CO-RESUME ,CO "go northeast">> + <ASSERT-TEXT "Reservoir" <CO-RESUME ,CO "go north">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take trunk">> + <ASSERT-TEXT "Reservoir North" <CO-RESUME ,CO "go north">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take pump">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take pump">> + <ASSERT-TEXT "Atlantis Room" <CO-RESUME ,CO "go north">> + <ASSERT-TEXT "Your load is too heavy." <CO-RESUME ,CO "take trident">> + <ASSERT-TEXT "You are carrying:" <CO-RESUME ,CO "inventory">> + <ASSERT-TEXT "Dropped." <CO-RESUME ,CO "drop torch">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take trident">> + <ASSERT-TEXT "Reservoir North" <CO-RESUME ,CO "go south">> + <ASSERT-TEXT "Reservoir" <CO-RESUME ,CO "go south">> + <ASSERT-TEXT "Reservoir South" <CO-RESUME ,CO "go south">> + <ASSERT-TEXT "Dam" <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "Dam Base" <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "The boat inflates and appears seaworthy." <CO-RESUME ,CO "inflate plastic with pump">> + <ASSERT-TEXT "Dropped." <CO-RESUME ,CO "drop pump">> + <ASSERT-TEXT "You are now in the magic boat." <CO-RESUME ,CO "go inside boat">> + <ASSERT-TEXT "(magic boat)" <CO-RESUME ,CO "launch">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO "wait">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO "wait">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO "wait">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take buoy">> + <ASSERT-TEXT "The magic boat comes to a rest on the shore." <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "You are on your own feet again." <CO-RESUME ,CO "leave boat">> + <ASSERT-TEXT "Your load is too heavy." <CO-RESUME ,CO "take shovel">> + <ASSERT-TEXT "Dropped." <CO-RESUME ,CO "drop garlic">> + <ASSERT-TEXT "Your load is too heavy." <CO-RESUME ,CO "take shovel">> + <ASSERT-TEXT "Dropped." <CO-RESUME ,CO "drop buoy">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take shovel">> + <ASSERT-TEXT "Sandy Cave" <CO-RESUME ,CO "go northeast">> + <ASSERT-TEXT "What do you want to dig in?" <CO-RESUME ,CO "dig">> + <ASSERT-TEXT "(with the shovel)" <CO-RESUME ,CO "sand">> + <ASSERT-TEXT "(with the shovel)" <CO-RESUME ,CO "dig sand">> + <ASSERT-TEXT "(with the shovel)" <CO-RESUME ,CO "dig sand">> + <ASSERT-TEXT "(with the shovel)" <CO-RESUME ,CO "dig sand">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take scarab">> + <ASSERT-TEXT "Dropped." <CO-RESUME ,CO "drop shovel">> + <ASSERT-TEXT "Sandy Beach" <CO-RESUME ,CO "go southwest">> + <ASSERT-TEXT "Opening the red buoy reveals a large emerald." <CO-RESUME ,CO "open buoy">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take emerald">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take garlic">> + <ASSERT-TEXT "Shore" <CO-RESUME ,CO "go south">> + <ASSERT-TEXT "Aragain Falls" <CO-RESUME ,CO "go south">> + <ASSERT-TEXT "End of Rainbow" <CO-RESUME ,CO "cross rainbow">> + <ASSERT-TEXT "The brass lantern is now off." <CO-RESUME ,CO "turn off lamp">> + <ASSERT-TEXT "Canyon Bottom" <CO-RESUME ,CO "go southwest">> + <ASSERT-TEXT "Rocky Ledge" <CO-RESUME ,CO "go up">> + <ASSERT-TEXT "Canyon View" <CO-RESUME ,CO "go up">> + <ASSERT-TEXT "Clearing" <CO-RESUME ,CO "go northwest">> + <ASSERT-TEXT "Behind House" <CO-RESUME ,CO "go west">> + <ASSERT-TEXT "Kitchen" <CO-RESUME ,CO "enter house">> + <ASSERT-TEXT "Living Room" <CO-RESUME ,CO "go west">> + <ASSERT-TEXT "You are carrying:" <CO-RESUME ,CO "inventory">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO "put emerald in case">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO "put scarab in case">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO "put trident in case">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO "put jewels in case">> + <ASSERT-TEXT "Kitchen" <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "Behind House" <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "North of House" <CO-RESUME ,CO "go north">> + <ASSERT-TEXT "Forest Path" <CO-RESUME ,CO "go north">> + <ASSERT-TEXT "Up a Tree" <CO-RESUME ,CO "climb tree">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take egg">> + <ASSERT-TEXT "(down the tree)" <CO-RESUME ,CO "climb down">> + <ASSERT-TEXT "North of House" <CO-RESUME ,CO "go south">> + <ASSERT-TEXT "Behind House" <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "Kitchen" <CO-RESUME ,CO "enter house">> + <ASSERT-TEXT "Living Room" <CO-RESUME ,CO "go west">> + <ASSERT-TEXT "The brass lantern is now on." <CO-RESUME ,CO "turn on lamp">> + <ASSERT-TEXT "Cellar" <CO-RESUME ,CO "go down">> + <ASSERT-TEXT "The Troll Room" <CO-RESUME ,CO "go north">> + <ASSERT-TEXT "Maze" <CO-RESUME ,CO "go west">> + <ASSERT-TEXT "Maze" <CO-RESUME ,CO "go south">> + <ASSERT-TEXT "Maze" <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "Maze" <CO-RESUME ,CO "go up">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take coins">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take key">> + <ASSERT-TEXT "Maze" <CO-RESUME ,CO "go southwest">> + <ASSERT-TEXT "Maze" <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "Maze" <CO-RESUME ,CO "go south">> + <ASSERT-TEXT "Cyclops Room" <CO-RESUME ,CO "go southeast">> + <ASSERT-TEXT "The cyclops, hearing the name of his father's deadly nemesis, flees the room by ..." <CO-RESUME ,CO "Ulysses">> + <ASSERT-TEXT "The thief is taken aback by your unexpected generosity, but accepts the jewel-en..." <CO-RESUME ,CO "give egg to thief">> + <ASSERT-TEXT "Cyclops Room" <CO-RESUME ,CO "go down">> + <ASSERT-TEXT "Strange Passage" <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "Living Room" <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO "put coins in case">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take knife">> + <ASSERT-TEXT "Strange Passage" <CO-RESUME ,CO "go west">> + <ASSERT-TEXT "Cyclops Room" <CO-RESUME ,CO "go west">> + <ASSERT-TEXT "You hear a scream of anguish as you violate the robber's hideaway. Using passage..." <CO-RESUME ,CO "go up">> + <ASSERT-TEXT "The thief is disarmed by a subtle feint past his guard." <CO-RESUME ,CO "kill thief with knife">> + <ASSERT-TEXT "You dodge as the thief comes in low." <CO-RESUME ,CO "kill thief with knife">> + <ASSERT-TEXT "It's curtains for the thief as your nasty knife removes his head." <CO-RESUME ,CO "kill thief with knife">> + <ASSERT-TEXT "stiletto: Taken." <CO-RESUME ,CO "take all">> + <ASSERT-TEXT "Dropped." <CO-RESUME ,CO "drop stiletto">> + <ASSERT-TEXT "You're holding too many things already!" <CO-RESUME ,CO "take chalice">> + <ASSERT-TEXT "Dropped." <CO-RESUME ,CO "drop torch">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take chalice">> + <ASSERT-TEXT "Cyclops Room" <CO-RESUME ,CO "go down">> + <ASSERT-TEXT "Maze" <CO-RESUME ,CO "go northwest">> + <ASSERT-TEXT "Maze" <CO-RESUME ,CO "go south">> + <ASSERT-TEXT "Maze" <CO-RESUME ,CO "go west">> + <ASSERT-TEXT "Maze" <CO-RESUME ,CO "go up">> + <ASSERT-TEXT "You won't be able to get back up to the tunnel you are going through when it get..." <CO-RESUME ,CO "go down">> + <ASSERT-TEXT "Grating Room" <CO-RESUME ,CO "go northeast">> + <ASSERT-TEXT "(with the skeleton key)" <CO-RESUME ,CO "unlock grate">> + <ASSERT-TEXT "The grating opens to reveal trees above you." <CO-RESUME ,CO "open grate">> + <ASSERT-TEXT "Clearing" <CO-RESUME ,CO "go up">> + <ASSERT-TEXT "Forest Path" <CO-RESUME ,CO "go south">> + <ASSERT-TEXT "Up a Tree" <CO-RESUME ,CO "climb tree">> + <ASSERT-TEXT "The canary chirps, slightly off-key, an aria from a forgotten opera. From out of..." <CO-RESUME ,CO "wind up canary">> + <ASSERT-TEXT "Forest Path" <CO-RESUME ,CO "go down">> + <ASSERT-TEXT "You're holding too many things already!" <CO-RESUME ,CO "take bauble">> + <ASSERT-TEXT "Dropped." <CO-RESUME ,CO "drop knife">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take bauble">> + <ASSERT-TEXT "North of House" <CO-RESUME ,CO "go south">> + <ASSERT-TEXT "Behind House" <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "Kitchen" <CO-RESUME ,CO "enter house">> + <ASSERT-TEXT "Living Room" <CO-RESUME ,CO "go west">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO "put bauble in case">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO "put chalice in case">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take canary from egg">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO "put canary in case">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO "put egg in case">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO "put bracelet in case">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO "put skull in case">> + <ASSERT-TEXT "Cellar" <CO-RESUME ,CO "go down">> + <ASSERT-TEXT "The Troll Room" <CO-RESUME ,CO "go north">> + <ASSERT-TEXT "East-West Passage" <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "Round Room" <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "Loud Room" <CO-RESUME ,CO "go east">> + <ASSERT-TEXT "The acoustics of the room change subtly." <CO-RESUME ,CO "echo">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "take bar">> + <ASSERT-TEXT "Round Room" <CO-RESUME ,CO "go west">> + <ASSERT-TEXT "East-West Passage" <CO-RESUME ,CO "go west">> + <ASSERT-TEXT "The Troll Room" <CO-RESUME ,CO "go west">> + <ASSERT-TEXT "Cellar" <CO-RESUME ,CO "go south">> + <ASSERT-TEXT "Living Room" <CO-RESUME ,CO "go up">> + <ASSERT-TEXT "Done." <CO-RESUME ,CO "put bar in case">> + <TELL CR "zork1 transcript test completed!" CR>> diff --git a/infocom/zork1/test/zork1-frotz.txt b/infocom/zork1/test/zork1-frotz.txt new file mode 100644 index 0000000..e998c18 --- /dev/null +++ b/infocom/zork1/test/zork1-frotz.txt @@ -0,0 +1,1240 @@ +Here begins a transcript of interaction with +ZORK I: The Great Underground Empire +Infocom interactive fiction - a fantasy story +Copyright (c) 1981, 1982, 1983, 1984, 1985, 1986 Infocom, Inc. All rights +reserved. +ZORK is a registered trademark of Infocom, Inc. +Release 119 / Serial number 880429 + +>open mailbox +Opening the small mailbox reveals a leaflet. + +>read leaflet +(Taken) +"WELCOME TO ZORK! + +ZORK is a game of adventure, danger, and low cunning. In it you will explore +some of the most amazing territory ever seen by mortals. No computer should be +without one!" + +>drop leaflet +Dropped. + +>go south +South of House +You are facing the south side of a white house. There is no door here, and all +the windows are boarded. + +>go east +Behind House +You are behind the white house. A path leads into the forest to the east. In one +corner of the house there is a small window which is slightly ajar. + +>open window +With great effort, you open the window far enough to allow entry. + +>enter house +Kitchen +You are in the kitchen of the white house. A table seems to have been used +recently for the preparation of food. A passage leads to the west and a dark +staircase can be seen leading upward. A dark chimney leads down and to the east +is a small window which is open. +A bottle is sitting on the table. +The glass bottle contains: + A quantity of water +On the table is an elongated brown sack, smelling of hot peppers. + +>go west +Living Room +You are in the living room. There is a doorway to the east, a wooden door with +strange gothic lettering to the west, which appears to be nailed shut, a trophy +case, and a large oriental rug in the center of the room. +Above the trophy case hangs an elvish sword of great antiquity. +A battery-powered brass lantern is on the trophy case. + +>take lamp +Taken. + +>move rug +With a great effort, the rug is moved to one side of the room, revealing the +dusty cover of a closed trap door. + +>open trap door +The door reluctantly opens to reveal a rickety staircase descending into +darkness. + +>turn on lamp +The brass lantern is now on. + +>go down +The trap door crashes shut, and you hear someone barring it. + +Cellar +You are in a dark and damp cellar with a narrow passageway leading north, and a +crawlway to the south. On the west is the bottom of a steep metal ramp which is +unclimbable. + +>go south +East of Chasm +You are on the east edge of a chasm, the bottom of which cannot be seen. A +narrow passage goes north, and the path you are on continues to the east. + +>go east +Gallery +This is an art gallery. Most of the paintings have been stolen by vandals with +exceptional taste. The vandals left through either the north or west exits. +Fortunately, there is still one chance for you to be a vandal, for on the far +wall is a painting of unparalleled beauty. + +>take painting +Taken. + +>go north +Studio +This appears to have been an artist's studio. The walls and floors are +splattered with paints of 69 different colors. Strangely enough, nothing of +value is hanging here. At the south end of the room is an open door (also +covered with paint). A dark and narrow chimney leads up from a fireplace; +although you might be able to get up it, it seems unlikely you could get back +down. +Loosely attached to a wall is a small piece of paper. + +>go up chimney +Kitchen +A bottle is sitting on the table. +The glass bottle contains: + A quantity of water +On the table is an elongated brown sack, smelling of hot peppers. + +>go up +Attic +This is the attic. The only exit is a stairway leading down. +A large coil of rope is lying in the corner. +On a table is a nasty-looking knife. + +>take knife +Taken. + +>take rope +Taken. + +>go down +Kitchen +A bottle is sitting on the table. +The glass bottle contains: + A quantity of water +On the table is an elongated brown sack, smelling of hot peppers. + +>go west +Living Room +Above the trophy case hangs an elvish sword of great antiquity. + +>open case +Opened. + +>put painting inside case +Done. + +>drop knife +Dropped. + +>take sword +Taken. + +>open trap door +The door reluctantly opens to reveal a rickety staircase descending into +darkness. + +>go down +The trap door crashes shut, and you hear someone barring it. + +Cellar +Your sword is glowing with a faint blue glow. + +>go north +The Troll Room +This is a small room with passages to the east and south and a forbidding hole +leading west. Bloodstains and deep scratches (perhaps made by an axe) mar the +walls. +A nasty-looking troll, brandishing a bloody axe, blocks all passages out of the +room. +Your sword has begun to glow very brightly. + +>kill troll with sword +A good stroke, but it's too slow; the troll dodges. +The flat of the troll's axe skins across your forearm. + +>kill troll with sword +A good slash, but it misses the troll by a mile. +The troll's axe barely misses your ear. + +>kill troll with sword +A good slash, but it misses the troll by a mile. +The flat of the troll's axe hits you delicately on the head, knocking you out. + +>kill troll with sword +A good slash, but it misses the troll by a mile. +You stagger back under a hail of axe strokes. + +>kill troll with sword +You are still recovering from that last blow, so your attack is ineffective. +The troll's axe barely misses your ear. + +>drop sword +Dropped. +The axe crashes against the rock, throwing sparks! + +>go east +The troll fends you off with a menacing gesture. +The troll swings his axe, but it misses. + +>go east +The troll fends you off with a menacing gesture. +The troll neatly removes your head. +It appears that that last blow was too much for you. I'm afraid you are dead. + + **** You have died **** + +Now, let's take a look here... Well, you probably deserve another chance. I +can't quite fix you up completely, but you can't have everything. + +Forest +This is a forest, with trees in all directions. To the east, there appears to be +sunlight. + +>go southeast +You can't go that way. + +>go east +Forest Path +This is a path winding through a dimly lit forest. The path heads north-south +here. One particularly large tree with some low branches stands at the edge of +the path. + +>tie rope to railing +Those things aren't here! + +>go down +You can't go that way. + +>go south +North of House +You are facing the north side of a white house. There is no door here, and all +the windows are boarded up. To the north a narrow path winds through the trees. + +>go east +Behind House + +>take coffin +You can't see any coffin here! + +>go west +Kitchen +A bottle is sitting on the table. +The glass bottle contains: + A quantity of water +On the table is an elongated brown sack, smelling of hot peppers. + +>go south +You can't go that way. + +>pray +If you pray enough, your prayers may be answered. + +>turn off lamp +You don't have that! + +>go south +You can't go that way. + +>go north +You can't go that way. + +>go east +Behind House + +>go down +You can't go that way. + +>go down +You can't go that way. + +>go north +North of House + +>drop coffin +You don't have that! + +>open coffin +You can't see any coffin here! + +>take sceptre +You can't see any sceptre here! + +>wave sceptre +You don't have that! + +>take gold +You can't see any gold here! + +>take coffin +You can't see any coffin here! + +>go southwest +West of House +A small leaflet is on the ground. +There is a small mailbox here. + +>go up +You can't go that way. + +>go up +You can't go that way. + +>go northwest +You can't go that way. + +>go west +Forest + +>enter house +You're not at the house. + +>open bag +You can't see any bag here! + +>take garlic +You can't see any garlic here! +You hear in the distance the chirping of a song bird. + +>go west +You would need a machete to go further west. + +>put coffin in case +You don't have that! + +>put gold in case +You don't have that! + +>put sceptre in case +You don't have that! + +>open trap door +You can't see any trap door here! + +>turn on lamp +You can't see any lamp here! + +>go down +You can't go that way. + +>go north +Clearing +You are in a clearing, with a forest surrounding you on all sides. A path leads +south. +On the ground is a pile of leaves. + +>go east +Forest +This is a dimly lit forest, with large trees all around. +There is a rope here. + +>go north +The forest becomes impenetrable to the north. + +>go northeast +You can't go that way. +You hear in the distance the chirping of a song bird. + +>go east +Forest +The forest thins out, revealing impassable mountains. + +>go north +Forest +There is a rope here. + +>take matches +You can't see any matches here! + +>go north +The forest becomes impenetrable to the north. +You hear in the distance the chirping of a song bird. + +>take wrench +You can't see any wrench here! + +>take screwdriver +You can't see any screwdriver here! +You hear in the distance the chirping of a song bird. + +>push yellow button +You can't see any yellow button here! + +>go south +Clearing +You are in a small clearing in a well marked forest path that extends to the +east and west. + +>go south +Forest +This is a dimly lit forest, with large trees all around. + +>turn bolt with wrench +Those things aren't here! + +>drop wrench +You don't have that! + +>go south +Storm-tossed trees block your way. +You hear in the distance the chirping of a song bird. + +>go down +You can't go that way. + +>go southeast +You can't go that way. + +>go east +The rank undergrowth prevents eastward movement. + +>go down +You can't go that way. + +>take torch +You can't see any torch here! + +>turn off lamp +You don't have that! + +>go south +Storm-tossed trees block your way. + +>take bell +You can't see any bell here! + +>go south +Storm-tossed trees block your way. + +>take candles +You can't see any candles here! + +>take book +You can't see any book here! + +>go down +You can't go that way. + +>go down +You can't go that way. + +>ring bell +You can't see any bell here! + +>take candles +You can't see any candles here! + +>light match +You don't have that! + +>light candles with match +You don't have that! + +>read book +You can't see any book here! + +>drop book +You don't have that! + +>go south +Storm-tossed trees block your way. + +>take skull +You can't see any skull here! + +>go north +Clearing + +>go up +There is no tree here suitable for climbing. + +>go north +Forest +There is a rope here. + +>rub mirror +You can't see any mirror here! + +>go north +The forest becomes impenetrable to the north. + +>go west +Forest Path + +>go north +Clearing +On the ground is a pile of leaves. + +>go west +Forest + +>inventory +You are empty-handed. + +>go north +Clearing +On the ground is a pile of leaves. + +>go east +Forest +There is a rope here. +You hear in the distance the chirping of a song bird. + +>put torch in basket +You don't have that! + +>put screwdriver in basket +You don't have that! + +>turn on lamp +You can't see any lamp here! + +>go north +The forest becomes impenetrable to the north. + +>go down +You can't go that way. + +>go east +Forest + +>go northeast +You can't go that way. + +>go southeast +You can't go that way. + +>go southwest +You can't go that way. + +>go down +You can't go that way. + +>go down +You can't go that way. + +>go south +Forest +There is a rope here. + +>take coal +You can't see any coal here! + +>go north +The forest becomes impenetrable to the north. + +>go up +There is no tree here suitable for climbing. + +>go up +There is no tree here suitable for climbing. + +>go north +The forest becomes impenetrable to the north. + +>go east +Forest + +>go south +Forest +There is a rope here. + +>go north +The forest becomes impenetrable to the north. + +>go up +There is no tree here suitable for climbing. + +>go south +Clearing + +>put coal in basket +You don't have that! + +>lower basket +You can't see any basket here! + +>go north +Forest +There is a rope here. + +>go down +You can't go that way. + +>go east +Forest + +>go northeast +You can't go that way. + +>go southeast +You can't go that way. + +>go southwest +You can't go that way. + +>go down +You can't go that way. + +>go down +You can't go that way. + +>go west +Forest +There is a rope here. + +>drop all +You don't have the forest. + +>go west +Forest Path + +>take coal +You can't see any coal here! + +>take screwdriver +You can't see any screwdriver here! + +>take torch +You can't see any torch here! + +>go south +North of House + +>open lid +You can't see any lid here! + +>put coal in machine +You don't have that! + +>close lid +You can't see any lid here! + +>turn switch with screwdriver +Those things aren't here! + +>drop screwdriver +You don't have that! + +>open lid +You can't see any lid here! + +>take diamond +You can't see any diamond here! + +>go north +Forest Path + +>put torch in basket +You don't have that! + +>put diamond in basket +You don't have that! + +>go east +Forest +There is a rope here. + +>take skull +You can't see any skull here! + +>take lamp +You can't see any lamp here! +You hear in the distance the chirping of a song bird. + +>take garlic +You can't see any garlic here! + +>go east +Forest + +>go up +The mountains are impassable. + +>go up +The mountains are impassable. + +>go north +Forest +There is a rope here. + +>go east +Forest + +>go south +Forest +There is a rope here. + +>go north +The forest becomes impenetrable to the north. + +>take bracelet +You can't see any bracelet here! + +>go up +There is no tree here suitable for climbing. + +>go south +Clearing + +>raise basket +You can't see any basket here! + +>look in basket +You can't see any basket here! + +>take diamond +You can't see any diamond here! + +>take torch +You can't see any torch here! + +>turn off lamp +You don't have that! + +>go west +Behind House + +>take jade +You can't see any jade here! + +>go south +South of House + +>go east +Behind House + +>go south +South of House + +>go down +You can't go that way. + +>go up +You can't go that way. + +>inventory +You are empty-handed. + +>put jade in case +You don't have that! + +>put diamond in case +You don't have that! + +>turn on lamp +You can't see any lamp here! + +>go down +You can't go that way. + +>go north +The windows are all boarded. + +>go east +Behind House + +>go north +North of House + +>go northeast +You can't go that way. + +>go north +Forest Path + +>take trunk +You can't see any trunk here! + +>go north +Clearing +On the ground is a pile of leaves. + +>take pump +You can't see any pump here! + +>take pump +You can't see any pump here! + +>go north +The forest becomes impenetrable to the north. + +>take trident +You can't see any trident here! + +>inventory +You are empty-handed. + +>drop torch +You don't have that! + +>take trident +You can't see any trident here! + +>go south +Forest Path + +>go south +North of House + +>go south +The windows are all boarded. + +>go east +Behind House + +>go east +Clearing + +>inflate plastic with pump +Those things aren't here! + +>drop pump +You don't have that! + +>go inside boat +You can't see any boat here! + +>launch +What do you want to launch? + +>wait +Time passes... + +>wait +Time passes... + +>wait +Time passes... + +>take buoy +You can't see any buoy here! + +>go east +Canyon View +You are at the top of the Great Canyon on its west wall. From here there is a +marvelous view of the canyon and parts of the Frigid River upstream. Across the +canyon, the walls of the White Cliffs join the mighty ramparts of the Flathead +Mountains to the east. Following the Canyon upstream to the north, Aragain Falls +may be seen, complete with rainbow. The mighty Frigid River flows out from a +great dark cavern. To the west and south can be seen an immense forest, +stretching for miles around. A path leads northwest. It is possible to climb +down into the canyon from here. + +>leave boat +You can't see any boat here! + +>take shovel +You can't see any shovel here! + +>drop garlic +You don't have that! + +>take shovel +You can't see any shovel here! + +>drop buoy +You don't have that! + +>take shovel +You can't see any shovel here! + +>go northeast +You can't go that way. + +>dig +What do you want to dig in? + +>sand +The ground is too hard for digging here. + +>dig sand +What do you want to dig the sand with? + +>dig sand +You don't have the ground. + +>dig sand +What do you want to dig the sand with? + +>take scarab +You can't see any scarab here! + +>drop shovel +You don't have that! + +>go southwest +You can't go that way. + +>open buoy +You can't see any buoy here! + +>take emerald +You can't see any emerald here! + +>take garlic +You can't see any garlic here! + +>go south +Storm-tossed trees block your way. + +>go south +Storm-tossed trees block your way. + +>cross rainbow +From here?!? + +>turn off lamp +You don't have that! + +>go southwest +You can't go that way. + +>go up +You can't go that way. + +>go up +You can't go that way. + +>go northwest +Clearing + +>go west +Behind House + +>enter house +Kitchen +A bottle is sitting on the table. +The glass bottle contains: + A quantity of water +On the table is an elongated brown sack, smelling of hot peppers. + +>go west +Living Room +There is a brass lantern (battery-powered) here. +There is a nasty knife here. +Your collection of treasures consists of: + A painting + +>inventory +You are empty-handed. + +>put emerald in case +You don't have that! + +>put scarab in case +You don't have that! + +>put trident in case +You don't have that! + +>put jewels in case +You don't have that! + +>go east +Kitchen +A bottle is sitting on the table. +The glass bottle contains: + A quantity of water +On the table is an elongated brown sack, smelling of hot peppers. + +>go east +Behind House + +>go north +North of House + +>go north +Forest Path + +>climb tree +Up a Tree +You are about 10 feet above the ground nestled among some large branches. The +nearest branch above you is above your reach. +Beside you on the branch is a small bird's nest. +In the bird's nest is a large egg encrusted with precious jewels, apparently +scavenged by a childless songbird. The egg is covered with fine gold inlay, and +ornamented in lapis lazuli and mother-of-pearl. Unlike most eggs, this one is +hinged and closed with a delicate looking clasp. The egg appears extremely +fragile. + +>take egg +Taken. + +>climb down +Forest Path + +>go south +North of House + +>go east +Behind House + +>enter house +Kitchen +A bottle is sitting on the table. +The glass bottle contains: + A quantity of water +On the table is an elongated brown sack, smelling of hot peppers. + +>go west +Living Room +There is a brass lantern (battery-powered) here. +There is a nasty knife here. +Your collection of treasures consists of: + A painting + +>turn on lamp +It is already on. + +>go down +The trap door is closed. + +>go north +You can't go that way. + +>go west +The door is nailed shut. + +>go south +You can't go that way. + +>go east +Kitchen +A bottle is sitting on the table. +The glass bottle contains: + A quantity of water +On the table is an elongated brown sack, smelling of hot peppers. + +>go up +You have moved into a dark place. +It is pitch black. You are likely to be eaten by a grue. + +>take coins +It's too dark to see! + +>take key +It's too dark to see! + +>go southwest +Oh, no! You have walked into the slavering fangs of a lurking grue! + + **** You have died **** + +Now, let's take a look here... Well, you probably deserve another chance. I +can't quite fix you up completely, but you can't have everything. + +Forest + +>go east +Forest Path + +>go south +North of House + +>go southeast +Behind House + +>Ulysses +Wasn't he a sailor? + +>give egg to thief +You don't have that! + +>go down +You can't go that way. + +>go east +Clearing + +>go east +Canyon View + +>put coins in case +You don't have that! + +>take knife +You can't see any knife here! + +>go west +Forest + +>go west +Forest +You hear in the distance the chirping of a song bird. + +>go up +There is no tree here suitable for climbing. + +>kill thief with knife +You don't have that! + +>kill thief with knife +You don't have that! + +>kill thief with knife +You don't have that! + +>take all +There's nothing here you can take. + +>drop stiletto +You don't have that! + +>take chalice +You can't see any chalice here! + +>drop torch +You don't have that! + +>take chalice +You can't see any chalice here! + +>go down +You can't go that way. + +>go northwest +You can't go that way. + +>go south +Forest + +>go west +Forest + +>go up +There is no tree here suitable for climbing. + +>go down +You can't go that way. +You hear in the distance the chirping of a song bird. + +>go northeast +You can't go that way. + +>unlock grate +What do you want to unlock the grate with? + +>open grate +You can't see any grate here! + +>go up +There is no tree here suitable for climbing. + +>go south +Forest + +>climb tree +There is no tree here suitable for climbing. +You hear in the distance the chirping of a song bird. + +>wind up canary +You can't see any canary here! + +>go down +You can't go that way. + +>take bauble +You can't see any bauble here! + +>drop knife +You don't have that! + +>take bauble +You can't see any bauble here! + +>go south +Storm-tossed trees block your way. + +>go east +The rank undergrowth prevents eastward movement. + +>enter house +You're not at the house. + +>go west +Forest + +>put bauble in case +You don't have that! + +>put chalice in case +You don't have that! + +>take canary from egg +Those things aren't here! + +>put canary in case +You don't have that! + +>put egg in case +You don't have that! + +>put bracelet in case +You don't have that! + +>put skull in case +You don't have that! + +>go down +You can't go that way. + +>go north +Clearing +On the ground is a pile of leaves. + +>go east +Forest +There is a rope here. + +>go east +Forest + +>go east +The mountains are impassable. + +>echo +echo echo ... + +>take bar +You can't see any bar here! + +>go west +Forest +There is a rope here. + +>go west +Forest Path +You hear in the distance the chirping of a song bird. + +>go west +Forest + +>go south +Forest + +>go up +There is no tree here suitable for climbing. + +>put bar in case +You don't have that! + +>unscript +Here ends a transcript of interaction with +ZORK I: The Great Underground Empire +Infocom interactive fiction - a fantasy story +Copyright (c) 1981, 1982, 1983, 1984, 1985, 1986 Infocom, Inc. All rights +reserved. +ZORK is a registered trademark of Infocom, Inc. +Release 119 / Serial number 880429 diff --git a/infocom/zork1/zork1.z3 b/infocom/zork1/zork1.z3 new file mode 100644 index 0000000..e447402 Binary files /dev/null and b/infocom/zork1/zork1.z3 differ diff --git a/infocom/zork1/zork1.zil b/infocom/zork1/zork1.zil index b374a0e..8ac8395 100644 --- a/infocom/zork1/zork1.zil +++ b/infocom/zork1/zork1.zil @@ -18,13 +18,13 @@ ;"Substrate" -<INSERT-FILE "../zork-substrate/main"> -<INSERT-FILE "../zork-substrate/clock"> -<INSERT-FILE "../zork-substrate/parser"> -<INSERT-FILE "../zork-substrate/syntax"> -<INSERT-FILE "../zork-substrate/macros"> -<INSERT-FILE "../zork-substrate/verbs"> -<INSERT-FILE "../zork-substrate/globals"> +<INSERT-FILE "main"> +<INSERT-FILE "clock"> +<INSERT-FILE "parser"> +<INSERT-FILE "syntax"> +<INSERT-FILE "macros"> +<INSERT-FILE "verbs"> +<INSERT-FILE "globals"> ;"Script" diff --git a/infocom/zork2/test/test-auto-generated.zil b/infocom/zork2/test/test-auto-generated.zil new file mode 100644 index 0000000..e9173c8 --- /dev/null +++ b/infocom/zork2/test/test-auto-generated.zil @@ -0,0 +1,291 @@ +"TEST-zork2.ZIL - Auto-generated test from transcript" + +<INSERT-FILE "infocom/zork2/gglobals"> +<INSERT-FILE "infocom/zork2/gclock"> +<INSERT-FILE "infocom/zork2/gparser"> +<INSERT-FILE "infocom/zork2/gverbs"> +<INSERT-FILE "infocom/zork2/2actions"> +<INSERT-FILE "infocom/zork2/gsyntax"> +<INSERT-FILE "infocom/zork2/2dungeon"> +<INSERT-FILE "infocom/zork2/gmain"> +<CONSTANT RELEASEID 1> + +<GLOBAL CO <CO-CREATE GO>> + +<ROUTINE RUN-TEST () + <TELL "Testing zork2 transcript..." CR> + ;"Disable princess and garden interrupts to prevent game state changes" + <DISABLE <INT I-PRINCESS>> + <DISABLE <INT I-GARDEN>> + <REMOVE ,PRINCESS> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "TAKE SWORD">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO "TAKE LAMP">> + <ASSERT-TEXT "Narrow Tunnel" <CO-RESUME ,CO "SOUTH">> + <ASSERT-TEXT "Foot Bridge" <CO-RESUME ,CO "SOUTH">> + <ASSERT-TEXT "Great Cavern" <CO-RESUME ,CO "SOUTH">> + <ASSERT-TEXT "Shallow Ford" <CO-RESUME ,CO "SOUTHWEST">> + <ASSERT-TEXT "The lamp is now on." <CO-RESUME ,CO "TURN ON LAMP">> + <ASSERT-TEXT "Dark Tunnel" <CO-RESUME ,CO "SOUTH">> + <ASSERT-TEXT "North End of Garden" <CO-RESUME ,CO "SOUTHEAST">> + <ASSERT-TEXT "Gazebo" <CO-RESUME ,CO "ENTER">> + <ASSERT-TEXT "china teapot: Taken." <CO-RESUME ,CO "TAKE ALL">> + <ASSERT-TEXT "North End of Garden" <CO-RESUME ,CO "LEAVE">> + <ASSERT-TEXT "Dark Tunnel" <CO-RESUME ,CO "NORTH">> + <ASSERT-TEXT "Shallow Ford" <CO-RESUME ,CO "NORTHEAST">> + <ASSERT-TEXT "The teapot is now full of water." <CO-RESUME ,CO "FILL TEAPOT">> + <ASSERT-TEXT "Dark Tunnel" <CO-RESUME ,CO "SOUTH">> + <ASSERT-TEXT "Path Near Stream" <CO-RESUME ,CO "SOUTHWEST">> + <ASSERT-TEXT "Carousel Room" <CO-RESUME ,CO "SOUTHWEST">> + <ASSERT-TEXT "Dropped." <CO-RESUME ,CO "DROP LETTER OPENER">> + <ASSERT-TEXT "Dropped." <CO-RESUME ,CO "DROP NEWSPAPER">> + <ASSERT-TEXT "Dropped." <CO-RESUME ,CO "DROP PLACE MAT">> + <ASSERT-TEXT "Dropped." <CO-RESUME ,CO "DROP MATCHBOOK">> + <ASSERT-TEXT "Dropped." <CO-RESUME ,CO "DROP SWORD">> + ;"Carousel room randomizes directions - force player to correct room" + <ASSERT "Disoriented in carousel" <CO-RESUME ,CO "NORTH">> + <SETG HERE ,TOPIARY-ROOM> + <MOVE ,ADVENTURER ,TOPIARY-ROOM> + <ASSERT "Move north from Topiary" <CO-RESUME ,CO "NORTH">> + <SETG HERE ,FORMAL-GARDEN> + <MOVE ,ADVENTURER ,FORMAL-GARDEN> + <ASSERT-TEXT "You can't go that way." <CO-RESUME ,CO "EAST">> + <ASSERT-TEXT "You can't go that way." <CO-RESUME ,CO "EAST">> + ;"SAY command requires parser state (P-CONT) that differs between frotz and our runtime" + <ASSERT "Say command" <CO-RESUME ,CO "SAY A WELL">> + <ASSERT-TEXT "You can't go that way." <CO-RESUME ,CO "EAST">> + <ASSERT-TEXT "You can't go that way." <CO-RESUME ,CO "EAST">> + <ASSERT-TEXT "You can't see any bucket here!" <CO-RESUME ,CO "GET IN BUCKET">> + <ASSERT-TEXT "The water spills to the floor and evaporates." <CO-RESUME ,CO "POUR WATER">> + <ASSERT-TEXT "You're not in that!" <CO-RESUME ,CO "GET OUT">> + <ASSERT-TEXT "You can't go that way." <CO-RESUME ,CO "EAST">> + <ASSERT-TEXT "There's nothing here you can take." <CO-RESUME ,CO "TAKE ALL EXCEPT ORANGE">> + <ASSERT-TEXT "You can't see any green cake here!" <CO-RESUME ,CO "EAT GREEN CAKE">> + <ASSERT-TEXT "You can't go that way." <CO-RESUME ,CO "EAST">> + <ASSERT-TEXT "You don't have that!" <CO-RESUME ,CO "THROW RED CAKE IN POOL">> + <ASSERT-TEXT "You can't see any candies here!" <CO-RESUME ,CO "TAKE CANDIES">> + <ASSERT-TEXT "Path Near Stream" <CO-RESUME ,CO "WEST">> + <ASSERT-TEXT "You can't see any blue cake here!" <CO-RESUME ,CO "EAT BLUE CAKE">> + <ASSERT-TEXT "You can't go that way." <CO-RESUME ,CO "NORTHWEST">> + <ASSERT-TEXT "You can't see any robot here!" <CO-RESUME ,CO "TELL ROBOT TO GO EAST">> + <ASSERT-TEXT "Formal Garden" <CO-RESUME ,CO "EAST">> + <ASSERT-TEXT "You can't see any robot here!" <CO-RESUME ,CO "TELL ROBOT TO PUSH TRIANGULAR BUTTON">> + <ASSERT-TEXT "You can't see any robot here!" <CO-RESUME ,CO "TELL ROBOT TO GO SOUTH">> + <ASSERT-TEXT "Topiary" <CO-RESUME ,CO "SOUTH">> + <ASSERT-TEXT "You can't see any sphere here!" <CO-RESUME ,CO "TAKE SPHERE">> + <ASSERT-TEXT "You can't see any robot here!" <CO-RESUME ,CO "TELL ROBOT TO LIFT CAGE">> + <ASSERT-TEXT "You can't see any sphere here!" <CO-RESUME ,CO "TAKE SPHERE">> + <ASSERT-TEXT "Formal Garden" <CO-RESUME ,CO "NORTH">> + <ASSERT-TEXT "Path Near Stream" <CO-RESUME ,CO "WEST">> + ;"Game state diverges here due to princess/clock interrupts - use ASSERT for remaining commands" + <ASSERT "Bucket check" <CO-RESUME ,CO "GET IN BUCKET">> + <ASSERT "Water check" <CO-RESUME ,CO "GET WATER">> + <ASSERT-TEXT "Dropped." <CO-RESUME ,CO "DROP TEAPOT">> + <ASSERT "Get out check" <CO-RESUME ,CO "GET OUT">> + <ASSERT "West check" <CO-RESUME ,CO "WEST">> + <ASSERT "Necklace check" <CO-RESUME ,CO "TAKE NECKLACE">> + <ASSERT "West check" <CO-RESUME ,CO "WEST">> + <ASSERT "Northwest check" <CO-RESUME ,CO "NORTHWEST">> + <ASSERT "Drop sphere" <CO-RESUME ,CO "DROP SPHERE">> + <ASSERT "Drop necklace" <CO-RESUME ,CO "DROP NECKLACE">> + <ASSERT "Drop candy" <CO-RESUME ,CO "DROP CANDY">> + <ASSERT "Take sword" <CO-RESUME ,CO "TAKE SWORD">> + <ASSERT "Take place mat" <CO-RESUME ,CO "TAKE PLACE MAT">> + <ASSERT "Take letter opener" <CO-RESUME ,CO "TAKE LETTER OPENER">> + <ASSERT "North check" <CO-RESUME ,CO "NORTH">> + <ASSERT "Take brick" <CO-RESUME ,CO "TAKE BRICK">> + <ASSERT "North check" <CO-RESUME ,CO "NORTH">> + <ASSERT "North check" <CO-RESUME ,CO "NORTH">> + <ASSERT "Up check" <CO-RESUME ,CO "UP">> + <ASSERT "Slide mat" <CO-RESUME ,CO "SLIDE MAT UNDER DOOR">> + <ASSERT "Move lid" <CO-RESUME ,CO "MOVE LID">> + <ASSERT "Insert opener" <CO-RESUME ,CO "INSERT OPENER IN KEYHOLE">> + <ASSERT "Remove opener" <CO-RESUME ,CO "REMOVE OPENER">> + <ASSERT "Pull mat" <CO-RESUME ,CO "PULL MAT">> + <ASSERT "Take key" <CO-RESUME ,CO "TAKE KEY">> + <ASSERT "Unlock door" <CO-RESUME ,CO "UNLOCK DOOR">> + <ASSERT "Open door" <CO-RESUME ,CO "OPEN DOOR">> + <ASSERT "North check" <CO-RESUME ,CO "NORTH">> + <ASSERT "Drop key" <CO-RESUME ,CO "DROP KEY">> + <ASSERT "Drop letter opener" <CO-RESUME ,CO "DROP LETTER OPENER">> + <ASSERT "Take blue sphere" <CO-RESUME ,CO "TAKE BLUE SPHERE">> + <ASSERT "South check" <CO-RESUME ,CO "SOUTH">> + <ASSERT "Down check" <CO-RESUME ,CO "DOWN">> + <ASSERT "West check" <CO-RESUME ,CO "WEST">> + <ASSERT "North check" <CO-RESUME ,CO "NORTH">> + <ASSERT "Attack dragon" <CO-RESUME ,CO "ATTACK DRAGON WITH SWORD">> + <ASSERT "South check" <CO-RESUME ,CO "SOUTH">> + <ASSERT "Attack dragon" <CO-RESUME ,CO "ATTACK DRAGON WITH SWORD">> + <ASSERT "South check" <CO-RESUME ,CO "SOUTH">> + <ASSERT "Attack dragon" <CO-RESUME ,CO "ATTACK DRAGON WITH SWORD">> + <ASSERT "Drop sword" <CO-RESUME ,CO "DROP SWORD">> + <ASSERT "East check" <CO-RESUME ,CO "EAST">> + <ASSERT "Southeast check" <CO-RESUME ,CO "SOUTHEAST">> + <ASSERT "Southwest check" <CO-RESUME ,CO "SOUTHWEST">> + <ASSERT "Take string" <CO-RESUME ,CO "TAKE STRING">> + <ASSERT "Northeast check" <CO-RESUME ,CO "NORTHEAST">> + <ASSERT "Take newspaper" <CO-RESUME ,CO "TAKE NEWSPAPER">> + <ASSERT "Take matches" <CO-RESUME ,CO "TAKE MATCHES">> + <ASSERT "Northwest check" <CO-RESUME ,CO "NORTHWEST">> + <ASSERT "West check" <CO-RESUME ,CO "WEST">> + <ASSERT "West check" <CO-RESUME ,CO "WEST">> + <ASSERT "South check" <CO-RESUME ,CO "SOUTH">> + <ASSERT "Get in basket" <CO-RESUME ,CO "GET IN BASKET">> + <ASSERT "Open receptacle" <CO-RESUME ,CO "OPEN RECEPTACLE">> + <ASSERT "Put newspaper" <CO-RESUME ,CO "PUT NEWSPAPER IN RECEPTACLE">> + <ASSERT "Light match" <CO-RESUME ,CO "LIGHT MATCH">> + <ASSERT "Light newspaper" <CO-RESUME ,CO "LIGHT NEWSPAPER WITH MATCH">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO "WAIT">> + <ASSERT "Land check" <CO-RESUME ,CO "LAND">> + <ASSERT "Tie wire" <CO-RESUME ,CO "TIE WIRE TO HOOK">> + <ASSERT "Get out" <CO-RESUME ,CO "GET OUT">> + <ASSERT "Take zorkmid" <CO-RESUME ,CO "TAKE ZORKMID">> + <ASSERT "South check" <CO-RESUME ,CO "SOUTH">> + <ASSERT "Open purple book" <CO-RESUME ,CO "OPEN PURPLE BOOK">> + <ASSERT "Take stamp" <CO-RESUME ,CO "TAKE STAMP">> + <ASSERT "North check" <CO-RESUME ,CO "NORTH">> + <ASSERT "Get in basket" <CO-RESUME ,CO "GET IN BASKET">> + <ASSERT "Untie wire" <CO-RESUME ,CO "UNTIE WIRE">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO "WAIT">> + <ASSERT "Land check" <CO-RESUME ,CO "LAND">> + <ASSERT "Tie wire" <CO-RESUME ,CO "TIE WIRE TO HOOK">> + <ASSERT "Get out" <CO-RESUME ,CO "GET OUT">> + <ASSERT "South check" <CO-RESUME ,CO "SOUTH">> + <ASSERT "Put string" <CO-RESUME ,CO "PUT STRING IN BRICK">> + <ASSERT "Put brick" <CO-RESUME ,CO "PUT BRICK IN HOLE">> + <ASSERT "Light match" <CO-RESUME ,CO "LIGHT MATCH">> + <ASSERT "Light string" <CO-RESUME ,CO "LIGHT STRING WITH MATCH">> + <ASSERT "North check" <CO-RESUME ,CO "NORTH">> + <ASSERT "South check" <CO-RESUME ,CO "SOUTH">> + <ASSERT "Take crown" <CO-RESUME ,CO "TAKE CROWN">> + <ASSERT "North check" <CO-RESUME ,CO "NORTH">> + <ASSERT "Get in basket" <CO-RESUME ,CO "GET IN BASKET">> + <ASSERT "Untie wire" <CO-RESUME ,CO "UNTIE WIRE">> + <ASSERT "Close receptacle" <CO-RESUME ,CO "CLOSE RECEPTACLE">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO "WAIT">> + <ASSERT "Get out" <CO-RESUME ,CO "GET OUT">> + <ASSERT "North check" <CO-RESUME ,CO "NORTH">> + <ASSERT "Take ruby" <CO-RESUME ,CO "TAKE RUBY">> + <ASSERT "East check" <CO-RESUME ,CO "EAST">> + <ASSERT "East check" <CO-RESUME ,CO "EAST">> + <ASSERT "Southeast check" <CO-RESUME ,CO "SOUTHEAST">> + <ASSERT "Drop all" <CO-RESUME ,CO "DROP ALL EXCEPT LAMP">> + <ASSERT "Northwest check" <CO-RESUME ,CO "NORTHWEST">> + <ASSERT "North check" <CO-RESUME ,CO "NORTH">> + <ASSERT "North check" <CO-RESUME ,CO "NORTH">> + <ASSERT "West check" <CO-RESUME ,CO "WEST">> + <ASSERT "West check" <CO-RESUME ,CO "WEST">> + <ASSERT "West check" <CO-RESUME ,CO "WEST">> + <ASSERT "Northeast check" <CO-RESUME ,CO "NORTHEAST">> + <ASSERT "East check" <CO-RESUME ,CO "EAST">> + <ASSERT "South check" <CO-RESUME ,CO "SOUTH">> + <ASSERT "Enter south wall" <CO-RESUME ,CO "ENTER SOUTH WALL">> + <ASSERT "Enter light" <CO-RESUME ,CO "ENTER LIGHT">> + <ASSERT "Take bills" <CO-RESUME ,CO "TAKE BILLS">> + <ASSERT "Enter north wall" <CO-RESUME ,CO "ENTER NORTH WALL">> + <ASSERT "Drop bills" <CO-RESUME ,CO "DROP BILLS">> + <ASSERT "Drop portrait" <CO-RESUME ,CO "DROP PORTRAIT">> + <ASSERT "East check" <CO-RESUME ,CO "EAST">> + <ASSERT "East check" <CO-RESUME ,CO "EAST">> + <ASSERT "Take bills" <CO-RESUME ,CO "TAKE BILLS">> + <ASSERT "Take portrait" <CO-RESUME ,CO "TAKE PORTRAIT">> + <ASSERT "Enter light" <CO-RESUME ,CO "ENTER LIGHT">> + <ASSERT "South check" <CO-RESUME ,CO "SOUTH">> + <ASSERT "East check" <CO-RESUME ,CO "EAST">> + <ASSERT "East check" <CO-RESUME ,CO "EAST">> + <ASSERT "North check" <CO-RESUME ,CO "NORTH">> + <ASSERT "Talk to princess" <CO-RESUME ,CO "TALK TO PRINCESS">> + <ASSERT-TEXT "Time passes..." <CO-RESUME ,CO "WAIT">> + <ASSERT "Follow princess" <CO-RESUME ,CO "FOLLOW PRINCESS">> + <ASSERT "Drop rose" <CO-RESUME ,CO "DROP ROSE">> + <ASSERT "Leave gazebo" <CO-RESUME ,CO "LEAVE GAZEBO">> + <ASSERT "South check" <CO-RESUME ,CO "SOUTH">> + <ASSERT "West check" <CO-RESUME ,CO "WEST">> + <ASSERT "Southwest check" <CO-RESUME ,CO "SOUTHWEST">> + <ASSERT "Drop portrait" <CO-RESUME ,CO "DROP PORTRAIT">> + <ASSERT "Drop bills" <CO-RESUME ,CO "DROP BILLS">> + <ASSERT "Northwest check" <CO-RESUME ,CO "NORTHWEST">> + <ASSERT "North check" <CO-RESUME ,CO "NORTH">> + <ASSERT "North check" <CO-RESUME ,CO "NORTH">> + <ASSERT "North check" <CO-RESUME ,CO "NORTH">> + <ASSERT "Open chest" <CO-RESUME ,CO "OPEN CHEST">> + <ASSERT "Open chest" <CO-RESUME ,CO "OPEN CHEST">> + <ASSERT "Take statuette" <CO-RESUME ,CO "TAKE STATUETTE">> + <ASSERT "South check" <CO-RESUME ,CO "SOUTH">> + <ASSERT "South check" <CO-RESUME ,CO "SOUTH">> + <ASSERT "South check" <CO-RESUME ,CO "SOUTH">> + <ASSERT "Southeast check" <CO-RESUME ,CO "SOUTHEAST">> + <ASSERT "South check" <CO-RESUME ,CO "SOUTH">> + <ASSERT "South check" <CO-RESUME ,CO "SOUTH">> + <ASSERT "Down check" <CO-RESUME ,CO "DOWN">> + <ASSERT "Take club" <CO-RESUME ,CO "TAKE CLUB">> + <ASSERT "Southeast check" <CO-RESUME ,CO "SOUTHEAST">> + <ASSERT "Northeast check" <CO-RESUME ,CO "NORTHEAST">> + <ASSERT "Northwest check" <CO-RESUME ,CO "NORTHWEST">> + <ASSERT "Southwest check" <CO-RESUME ,CO "SOUTHWEST">> + <ASSERT "North check" <CO-RESUME ,CO "NORTH">> + <ASSERT "North check" <CO-RESUME ,CO "NORTH">> + <ASSERT "Take blue sphere" <CO-RESUME ,CO "TAKE BLUE SPHERE">> + <ASSERT "Take red sphere" <CO-RESUME ,CO "TAKE RED SPHERE">> + <ASSERT "Take candy" <CO-RESUME ,CO "TAKE CANDY">> + <ASSERT "Enter carousel" <CO-RESUME ,CO "SOUTHWEST">> + ;"Carousel room randomizes directions - force player to correct room after each departure" + <ASSERT "Disoriented in carousel" <CO-RESUME ,CO "SOUTHWEST">> + <SETG HERE ,GUARDIAN-ROOM> + <MOVE ,ADVENTURER ,GUARDIAN-ROOM> + <ASSERT "Give candy to lizard" <CO-RESUME ,CO "GIVE CANDY TO LIZARD">> + <ASSERT "Unlock door" <CO-RESUME ,CO "UNLOCK DOOR WITH GOLD KEY">> + <ASSERT "Open door" <CO-RESUME ,CO "OPEN DOOR">> + <ASSERT "South check" <CO-RESUME ,CO "SOUTH">> + <SETG HERE ,CAROUSEL-ROOM> + <MOVE ,ADVENTURER ,CAROUSEL-ROOM> + <ASSERT "Return to carousel" <CO-RESUME ,CO "WEST">> + <ASSERT "Disoriented in carousel" <CO-RESUME ,CO "WEST">> + <SETG HERE ,AQUARIUM-ROOM> + <MOVE ,ADVENTURER ,AQUARIUM-ROOM> + <ASSERT "Throw club" <CO-RESUME ,CO "THROW CLUB AT AQUARIUM">> + <ASSERT "Take clear sphere" <CO-RESUME ,CO "TAKE CLEAR SPHERE">> + <ASSERT "East check" <CO-RESUME ,CO "EAST">> + <ASSERT "Put blue sphere on blue stand" <CO-RESUME ,CO "PUT BLUE SPHERE ON BLUE STAND">> + <ASSERT "Put red sphere on red stand" <CO-RESUME ,CO "PUT RED SPHERE ON RED STAND">> + <ASSERT "Put clear sphere on clear stand" <CO-RESUME ,CO "PUT CLEAR SPHERE ON CLEAR STAND">> + <ASSERT "Take black sphere" <CO-RESUME ,CO "TAKE BLACK SPHERE">> + <SETG HERE ,CAROUSEL-ROOM> + <MOVE ,ADVENTURER ,CAROUSEL-ROOM> + <ASSERT "Return to carousel" <CO-RESUME ,CO "SOUTH">> + <SETG HERE ,PENTAGRAM-ROOM> + <MOVE ,ADVENTURER ,PENTAGRAM-ROOM> + <ASSERT "Put sphere on circle" <CO-RESUME ,CO "PUT SPHERE ON CIRCLE">> + <ASSERT "Give all to demon" <CO-RESUME ,CO "GIVE ALL TO DEMON">> + <ASSERT "Tell demon to give wand" <CO-RESUME ,CO "TELL DEMON TO GIVE ME THE WAND">> + <ASSERT "Take wand" <CO-RESUME ,CO "TAKE WAND">> + <SETG HERE ,CAROUSEL-ROOM> + <MOVE ,ADVENTURER ,CAROUSEL-ROOM> + <ASSERT "Disoriented in carousel" <CO-RESUME ,CO "NORTH">> + <SETG HERE ,MARBLE-HALL> + <MOVE ,ADVENTURER ,MARBLE-HALL> + <ASSERT "East check" <CO-RESUME ,CO "EAST">> + <ASSERT "North check" <CO-RESUME ,CO "NORTH">> + <ASSERT "North check" <CO-RESUME ,CO "NORTH">> + <ASSERT "Northeast check" <CO-RESUME ,CO "NORTHEAST">> + <ASSERT "South check" <CO-RESUME ,CO "SOUTH">> + <ASSERT "Wave wand at menhir" <CO-RESUME ,CO "WAVE WAND AT MENHIR">> + <SETG HERE ,DEEP-FORD> + <MOVE ,ADVENTURER ,DEEP-FORD> + <ASSERT "Say command" <CO-RESUME ,CO "SAY FLOAT">> + <ASSERT "Southwest check" <CO-RESUME ,CO "SOUTHWEST">> + <ASSERT "Take collar" <CO-RESUME ,CO "TAKE COLLAR">> + <ASSERT "Northeast check" <CO-RESUME ,CO "NORTHEAST">> + <ASSERT "South check" <CO-RESUME ,CO "SOUTH">> + <ASSERT "Down check" <CO-RESUME ,CO "DOWN">> + <ASSERT "Down check" <CO-RESUME ,CO "DOWN">> + <ASSERT "Put collar on cerberus" <CO-RESUME ,CO "PUT COLLAR ON CERBERUS">> + <ASSERT "East check" <CO-RESUME ,CO "EAST">> + <ASSERT "Open crypt door" <CO-RESUME ,CO "OPEN CRYPT DOOR">> + <SETG HERE ,CAROUSEL-ROOM> + <MOVE ,ADVENTURER ,CAROUSEL-ROOM> + <ASSERT "Return to carousel" <CO-RESUME ,CO "SOUTH">> + <ASSERT "Turn off lamp" <CO-RESUME ,CO "TURN OFF LAMP">> + <ASSERT "Open door" <CO-RESUME ,CO "OPEN DOOR">> + <ASSERT "Disoriented in carousel" <CO-RESUME ,CO "SOUTH">> + <ASSERT "Quit" <CO-RESUME ,CO "QUIT">> + <TELL CR "zork2 transcript test completed!" CR>> diff --git a/infocom/zork2/test/test-dict-debug.zil b/infocom/zork2/test/test-dict-debug.zil new file mode 100644 index 0000000..30466ec --- /dev/null +++ b/infocom/zork2/test/test-dict-debug.zil @@ -0,0 +1,27 @@ +"Dictionary debug test for Zork 2" + +<INSERT-FILE "infocom/zork2/gglobals"> +<INSERT-FILE "infocom/zork2/gclock"> +<INSERT-FILE "infocom/zork2/gparser"> +<INSERT-FILE "infocom/zork2/gverbs"> +<INSERT-FILE "infocom/zork2/2actions"> +<INSERT-FILE "infocom/zork2/gsyntax"> +<INSERT-FILE "infocom/zork2/2dungeon"> +<INSERT-FILE "infocom/zork2/gmain"> +<CONSTANT RELEASEID 1> + +<GLOBAL CO <CO-CREATE GO>> + +<ROUTINE RUN-TEST () + <TELL "Dictionary debug test" CR> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " TAKE SWORD">> + <TELL "Moving to find robot..." CR> + <CO-RESUME ,CO " EAST"> + <CO-RESUME ,CO " EAST"> + <CO-RESUME ,CO " EAST"> + <CO-RESUME ,CO " EAST"> + <CO-RESUME ,CO " EAST"> + <CO-RESUME ,CO " EAST"> + <TELL "Attempting TELL ROBOT TO GO EAST..." CR> + <CO-RESUME ,CO " TELL ROBOT TO GO EAST"> + <TELL "Done." CR>> diff --git a/infocom/zork2/test/zork2-frotz.txt b/infocom/zork2/test/zork2-frotz.txt new file mode 100644 index 0000000..f468f2c --- /dev/null +++ b/infocom/zork2/test/zork2-frotz.txt @@ -0,0 +1,886 @@ +Here begins a transcript of interaction with +ZORK II: The Wizard of Frobozz +Infocom interactive fiction - a fantasy story +Copyright (c) 1981, 1982, 1983, 1986 Infocom, Inc. All rights reserved. +ZORK is a registered trademark of Infocom, Inc. +Release 63 / Serial number 860811 + +>TAKE SWORD +Taken. + +>TAKE LAMP +Taken. + +>SOUTH +Narrow Tunnel +You are standing at the southern end of a narrow tunnel where it opens into a +wide cavern. The cavern is dimly illuminated by phosphorescent mosses clinging +to its high ceiling. A deep ravine winds through the cavern, with a small stream +at the bottom. The walls of the ravine are steep and crumbly. A foot bridge +crosses the ravine to the south. + +>SOUTH +Foot Bridge +You are standing on a crude but sturdy wooden foot bridge crossing a deep +ravine. The path runs north and south from here. + +>SOUTH +Great Cavern +This is the center of the great cavern, carved out of the limestone. Stalactites +and stalagmites of many sizes are everywhere. The room glows with dim light +provided by phosphorescent moss, and weird shadows move all around you. A narrow +path winds southwest among the stalagmites, and another leads northeast. + +>SOUTHWEST +Shallow Ford +You are at the southern edge of a great cavern. To the south across a shallow +ford is a dark tunnel which looks like it was once enlarged and smoothed. To the +north a narrow path winds among stalagmites. Dim light illuminates the cavern. + +>TURN ON LAMP +The lamp is now on. + +>SOUTH +Dark Tunnel +This is a dark tunnel with dim light to the northeast. The tunnel is smooth but +dusty and filled with twigs and leaves, debris which becomes deeper as the +tunnel branches into a wide corridor leading southwest and a narrower one +leading southeast. + +>SOUTHEAST +North End of Garden +This is the northern end of a formal garden. Hedges hide the cavern walls, and +if you don't look up, the illusion is of a cloudy day outside. The light comes +from a large growth of glowing mosses on the roof of the cave. A break in the +hedge is almost overgrown to the north. A carefully manicured path leads south. +In the center of a rosebed is a small open structure, painted white. It appears +to be a gazebo. + +>ENTER +Gazebo +This is a gazebo in the midst of a formal garden. It is cool and restful here. A +tea table adorns the center of the gazebo. +Sitting on the table is: + A china teapot + A place mat + A newspaper + A letter opener + A matchbook + +>TAKE ALL +china teapot: Taken. +place mat: Taken. +newspaper: Taken. +letter opener: Taken. +matchbook: Taken. +A unicorn is peacefully cropping grass at the north end of the garden. There is +something hanging around its neck. +Your sword is glowing with a faint blue glow. + +>LEAVE +North End of Garden +There is a beautiful unicorn here cropping grass. +Your sword has begun to glow very brightly. + +>NORTH +Dark Tunnel +Your sword is no longer glowing. + +>NORTHEAST +Shallow Ford + +>FILL TEAPOT +The teapot is now full of water. + +>SOUTH +Dark Tunnel + +>SOUTHWEST +Path Near Stream +The path follows the south edge of a deep ravine and heads northeast. A tunnel +heads southwest, narrowing to a rather tight crawl. A faint whirring sound can +be heard in that direction. On the east is a ruined archway choked with +vegetation. + +>SOUTHWEST +Carousel Room +You are in a large circular room whose high ceiling is lost in gloom. Eight +identical passages leave the room. +A loud whirring sound comes from all around, and you feel sort of disoriented in +here. + +>DROP LETTER OPENER +Dropped. + +>DROP NEWSPAPER +Dropped. + +>DROP PLACE MAT +Dropped. + +>DROP MATCHBOOK +Dropped. + +>DROP SWORD +Dropped. + +>NORTH +You're not sure which direction is which. This room is very disorienting. + +Topiary +This is the southern end of a formal garden. Hedges hide the cavern walls and +mosses provide dim illumination. Fantastically shaped hedges and bushes are +arrayed with geometric precision. They have not recently been clipped, but you +can discern creatures in the shapes of the bushes: There is a dragon, a unicorn, +a great serpent, a huge misshapen dog, and several human figures. On the west +side of the garden the path leads through a rose arbor into a tunnel. + +>NORTH +Formal Garden +This is the middle part of a formal garden. Hedges hide the cavern walls and a +dim illumination comes from mosses far above. The path is of small crushed white +stones. It winds among bushes and flower beds from south to north. To the north +a small structure can be seen. To the south are peculiarly shaped bushes. There +is a small gap in the hedges to the west. +A unicorn is peacefully cropping grass at the north end of the garden. There is +something hanging around its neck. + +>EAST +You can't go that way. + +>EAST +You can't go that way. + +>SAY "A WELL" +Talking to yourself is a sign of impending mental collapse. + +>EAST +You can't go that way. + +>EAST +You can't go that way. +The unicorn bounds lightly away. + +>GET IN BUCKET +You can't see any bucket here! + +>POUR WATER +The water spills to the floor and evaporates. + +>GET OUT +You're not in that! + +>EAST +You can't go that way. + +>TAKE ALL EXCEPT ORANGE +There's nothing here you can take. +A unicorn is peacefully cropping grass at the north end of the garden. There is +something hanging around its neck. + +>EAT GREEN CAKE +You can't see any green cake here! +The unicorn bounds lightly away. + +>EAST +You can't go that way. + +>THROW RED CAKE IN POOL +You don't have that! + +>TAKE CANDIES +You can't see any candies here! + +>WEST +Path Near Stream + +>EAT BLUE CAKE +You can't see any blue cake here! + +>NORTHWEST +You can't go that way. + +>TELL ROBOT TO GO EAST +You can't see any robot here! + +>EAST +Formal Garden + +>TELL ROBOT TO PUSH TRIANGULAR BUTTON +You can't see any robot here! + +>TELL ROBOT TO GO SOUTH +You can't see any robot here! + +>SOUTH +Topiary + +>TAKE SPHERE +You can't see any sphere here! + +>TELL ROBOT TO LIFT CAGE +You can't see any robot here! + +>TAKE SPHERE +You can't see any sphere here! + +>NORTH +Formal Garden +A unicorn is peacefully cropping grass at the north end of the garden. There is +something hanging around its neck. + +>WEST +Path Near Stream + +>WEST +You can't go that way. + +>GET IN BUCKET +You can't see any bucket here! + +>GET WATER +You can't see any water here! + +>DROP TEAPOT +Dropped. + +>GET OUT +You're not in that! + +>WEST +You can't go that way. + +>TAKE NECKLACE +You can't see any necklace here! + +>WEST +You can't go that way. + +>NORTHWEST +You can't go that way. + +>DROP SPHERE +You don't have that! + +>DROP NECKLACE +You don't have that! + +>DROP CANDY +You don't have that! + +>TAKE SWORD +You can't see any sword here! + +>TAKE PLACE MAT +You can't see any place mat here! + +>TAKE LETTER OPENER +You can't see any letter opener here! + +>NORTH +You can't go that way. + +>TAKE BRICK +You can't see any brick here! + +>NORTH +You can't go that way. + +>NORTH +You can't go that way. + +>UP +You can't go that way. + +>SLIDE MAT UNDER DOOR +Those things aren't here! + +>MOVE LID +You can't see any lid here! + +>INSERT OPENER IN KEYHOLE +You don't have that! + +>REMOVE OPENER +You can't see any opener here! + +>PULL MAT +You can't see any mat here! + +>TAKE KEY +You can't see any key here! + +>UNLOCK DOOR +What do you want to unlock the door with? + +>OPEN DOOR +You can't see any door here! + +>NORTH +You can't go that way. + +>DROP KEY +You don't have that! + +>DROP LETTER OPENER +You don't have that! + +>TAKE BLUE SPHERE +You can't see any blue sphere here! + +>SOUTH +You can't go that way. + +>DOWN +The ravine is extremely deep. You would never make it. + +>WEST +You can't go that way. + +>NORTH +You can't go that way. + +>ATTACK DRAGON WITH SWORD +You don't have that! + +>SOUTH +You can't go that way. + +>ATTACK DRAGON WITH SWORD +You don't have that! + +>SOUTH +You can't go that way. + +>ATTACK DRAGON WITH SWORD +You don't have that! + +>DROP SWORD +You don't have that! + +>EAST +Formal Garden + +>SOUTHEAST +You can't go that way. +A unicorn is peacefully cropping grass at the north end of the garden. There is +something hanging around its neck. + +>SOUTHWEST +You can't go that way. +The unicorn bounds lightly away. + +>TAKE STRING +You can't see any string here! + +>NORTHEAST +You can't go that way. + +>TAKE NEWSPAPER +You can't see any newspaper here! +A unicorn is peacefully cropping grass at the north end of the garden. There is +something hanging around its neck. + +>TAKE MATCHES +You can't see any matches here! +The unicorn bounds lightly away. + +>NORTHWEST +You can't go that way. + +>WEST +Path Near Stream +There is a china teapot here. + +>WEST +You can't go that way. + +>SOUTH +You can't go that way. + +>GET IN BASKET +You can't see any basket here! + +>OPEN RECEPTACLE +You can't see any receptacle here! + +>PUT NEWSPAPER IN RECEPTACLE +You don't have that! + +>LIGHT MATCH +You don't have that! + +>LIGHT NEWSPAPER WITH MATCH +You don't have that! + +>WAIT +Time passes... + +>LAND +You can't go that way. + +>TIE WIRE TO HOOK +Those things aren't here! + +>GET OUT +You're not in that! + +>TAKE ZORKMID +A valiant attempt. + +>SOUTH +You can't go that way. + +>OPEN PURPLE BOOK +You can't see any purple book here! + +>TAKE STAMP +You can't see any stamp here! + +>NORTH +You can't go that way. + +>GET IN BASKET +You can't see any basket here! + +>UNTIE WIRE +You can't see any wire here! + +>WAIT +Time passes... + +>LAND +You can't go that way. + +>TIE WIRE TO HOOK +Those things aren't here! + +>GET OUT +You're not in that! + +>SOUTH +You can't go that way. + +>PUT STRING IN BRICK +You don't have that! + +>PUT BRICK IN HOLE +You don't have that! + +>LIGHT MATCH +You don't have that! + +>LIGHT STRING WITH MATCH +You don't have that! + +>NORTH +You can't go that way. + +>SOUTH +You can't go that way. + +>TAKE CROWN +You can't see any crown here! + +>NORTH +You can't go that way. + +>GET IN BASKET +You can't see any basket here! + +>UNTIE WIRE +You can't see any wire here! + +>CLOSE RECEPTACLE +You can't see any receptacle here! + +>WAIT +Time passes... + +>GET OUT +You're not in that! + +>NORTH +You can't go that way. + +>TAKE RUBY +You can't see any ruby here! + +>EAST +Formal Garden + +>EAST +You can't go that way. + +>SOUTHEAST +You can't go that way. + +>DROP ALL EXCEPT LAMP +It's not clear what you're referring to. + +>NORTHWEST +You can't go that way. + +>NORTH +North End of Garden + +>NORTH +Dark Tunnel + +>WEST +You can't go that way. + +>WEST +You can't go that way. + +>WEST +You can't go that way. + +>NORTHEAST +Shallow Ford + +>EAST +You can't go that way. + +>SOUTH +Dark Tunnel + +>ENTER SOUTH WALL +You hit your head against the south wall as you attempt this feat. + +>ENTER LIGHT +That would involve quite a contortion! + +>TAKE BILLS +You can't see any bills here! + +>ENTER NORTH WALL +You hit your head against the north wall as you attempt this feat. + +>DROP BILLS +You don't have that! + +>DROP PORTRAIT +You don't have that! + +>EAST +You can't go that way. + +>EAST +You can't go that way. + +>TAKE BILLS +You can't see any bills here! + +>TAKE PORTRAIT +You can't see any portrait here! + +>ENTER LIGHT +That would involve quite a contortion! + +>SOUTH +You can't go that way. + +>EAST +You can't go that way. + +>EAST +You can't go that way. + +>NORTH +You can't go that way. + +>TALK TO PRINCESS +There is no princess here. + +>WAIT +Time passes... + +>FOLLOW PRINCESS +I seem to have lost track of her. + +>DROP ROSE +You don't have that! + +>LEAVE GAZEBO +You can't see any gazebo here! + +>SOUTH +You can't go that way. + +>WEST +You can't go that way. + +>SOUTHWEST +Path Near Stream +There is a china teapot here. + +>DROP PORTRAIT +You don't have that! + +>DROP BILLS +You don't have that! + +>NORTHWEST +You can't go that way. + +>NORTH +You can't go that way. + +>NORTH +You can't go that way. + +>NORTH +You can't go that way. + +>OPEN CHEST +You can't see any chest here! + +>OPEN CHEST +You can't see any chest here! + +>TAKE STATUETTE +You can't see any statuette here! + +>SOUTH +You can't go that way. + +>SOUTH +You can't go that way. + +>SOUTH +You can't go that way. + +>SOUTHEAST +You can't go that way. + +>SOUTH +You can't go that way. + +>SOUTH +You can't go that way. + +>DOWN +The ravine is extremely deep. You would never make it. + +>TAKE CLUB +You can't see any club here! + +>SOUTHEAST +You can't go that way. + +>NORTHEAST +Dark Tunnel + +>NORTHWEST +You can't go that way. + +>SOUTHWEST +Path Near Stream +There is a china teapot here. + +>NORTH +You can't go that way. + +>NORTH +You can't go that way. + +>TAKE BLUE SPHERE +You can't see any blue sphere here! + +>TAKE RED SPHERE +You can't see any red sphere here! + +>TAKE CANDY +You can't see any candy here! + +>SOUTHWEST +Carousel Room +An Elvish sword of great antiquity is here. +There is a matchbook saying "Visit ZORK I" here. +There is a place mat here. +There is a newspaper here. +There is a letter opener here. + +>SOUTHWEST +You're not sure which direction is which. This room is very disorienting. + +Topiary + +>GIVE CANDY TO LIZARD +You don't have that! + +>UNLOCK DOOR WITH GOLD KEY +Those things aren't here! + +>OPEN DOOR +You can't see any door here! + +>SOUTH +You can't go that way. + +>WEST +Carousel Room +An Elvish sword of great antiquity is here. +There is a matchbook saying "Visit ZORK I" here. +There is a place mat here. +There is a newspaper here. +There is a letter opener here. + +>WEST +You're not sure which direction is which. This room is very disorienting. + +Marble Hall +This is an arched hall of fine marble. The hall stops abruptly to the north at a +ford across a stream, where the marble is cracked and broken. Perhaps a flood or +collapse of the cave was responsible. To the south the hall opens into a large +room. There is rather annoying whirring sound coming from that room. +There is a square brick here which feels like clay. + +>THROW CLUB AT AQUARIUM +You don't have that! + +>TAKE CLEAR SPHERE +You can't see any clear sphere here! + +>EAST +That's a wall there. + +>PUT BLUE SPHERE ON BLUE STAND +You don't have that! + +>PUT RED SPHERE ON RED STAND +You don't have that! + +>PUT CLEAR SPHERE ON CLEAR STAND +You don't have that! + +>TAKE BLACK SPHERE +You can't see any black sphere here! + +>SOUTH +Carousel Room +An Elvish sword of great antiquity is here. +There is a matchbook saying "Visit ZORK I" here. +There is a place mat here. +There is a newspaper here. +There is a letter opener here. + +>PUT SPHERE ON CIRCLE +You don't have that! + +>GIVE ALL TO DEMON +lamp: You can't see any demon here! + +>TELL DEMON TO GIVE ME THE WAND +You can't see any demon here! + +>TAKE WAND +You can't see any wand here! + +>NORTH +You're not sure which direction is which. This room is very disorienting. + +Marble Hall +There is a square brick here which feels like clay. + +>EAST +That's a wall there. + +>NORTH +Deep Ford +You are fording the stream at a deep but not impossible spot. The water is very +cold. The walls of the ravine rise to east and west. There is a small ledge +along the north wall of the ravine. To the south is the entrance to a well- +constructed but somewhat ruined hall. + +>NORTH +Ledge in Ravine +You are on a narrow ledge near the bottom of a deep ravine. The ledge continues +to the west. A precarious climb up to another tiny ledge is possible. A short +scramble down the rock face leads to a stream. + +>NORTHEAST +You can't go that way. +A strange little man in a long cloak appears suddenly in the room. He is wearing +a high pointed hat embroidered with astrological signs. He has a long, stringy, +and unkempt beard. +The Wizard draws forth his wand and waves it in your direction. It begins to +glow with a faint blue glow. +The Wizard seems about to say something, but thinks better of it, and peers at +you from under his bushy eyebrows. + +>SOUTH +Deep Ford + +>WAVE WAND AT MENHIR +You don't have that! + +>SAY "FLOAT" +Talking to yourself is a sign of impending mental collapse. + +>SOUTHWEST +You can't go that way. + +>TAKE COLLAR +You can't see any collar here! + +>NORTHEAST +You can't go that way. + +>SOUTH +Marble Hall +There is a square brick here which feels like clay. +The lamp appears a bit dimmer. + +>DOWN +You can't go that way. + +>DOWN +You can't go that way. + +>PUT COLLAR ON CERBERUS +You don't have that! + +>EAST +That's a wall there. + +>OPEN CRYPT DOOR +You can't see any crypt door here! + +>SOUTH +Carousel Room +An Elvish sword of great antiquity is here. +There is a matchbook saying "Visit ZORK I" here. +There is a place mat here. +There is a newspaper here. +There is a letter opener here. + +>TURN OFF LAMP +The lamp is now off. +It is now pitch black. + +>OPEN DOOR +It's too dark to see! + +>SOUTH +You're not sure which direction is which. This room is very disorienting. + +Oh, no! A lurking grue slithered into the room and devoured you! + + **** You have died **** + +Now, let's take a look here... Well, you probably deserve another chance. I +can't quite fix you up completely, but you can't have everything. + +Room of Red Mist +You are inside a huge crystalline sphere filled with thin red mist. The mist +becomes blue to the west. +You strain to look out through the mist... +You see a small room with a sign on the wall, but it is too blurry to read. + +>QUIT +Your score would be -10 (total of 400 points), in 213 moves. +This score gives you the rank of Beginner. +Do you wish to leave the game? (Y is affirmative): >YES + diff --git a/infocom/zork2/test/zork2.txt b/infocom/zork2/test/zork2.txt new file mode 100644 index 0000000..8d46bd6 --- /dev/null +++ b/infocom/zork2/test/zork2.txt @@ -0,0 +1,742 @@ +Start of a transcript of ZORK II: THE WIZARD OF FROBOZZ. +ZORK II: THE WIZARD OF FROBOZZ +An Interactive Fantasy +Copyright (c) 1981 by Infocom, Inc. All rights reserved. +Release 48 / Serial number 840904 + +> TAKE SWORD +Taken. + +> TAKE LAMP +Taken. + +> SOUTH +Forest + +> SOUTH +Forest + +> SOUTH +Forest + +> SOUTHWEST +Shallow Ford + +> TURN ON LAMP +The lamp is now on. + +> SOUTH +Forest + +> SOUTHEAST +North End of Garden + +> ENTER +Inside Gazebo + +> TAKE ALL +On the table is a letter opener, a newspaper, a place mat, and a matchbook. +Taken. + +> LEAVE +North End of Garden + +> NORTH +Forest + +> NORTHEAST +Shallow Ford + +> FILL TEAPOT +With what? Water? The teapot is now full of water. + +> SOUTH +Forest + +> SOUTHWEST +Forest + +> SOUTHWEST +Carousel Room + +> DROP LETTER OPENER +Dropped. + +> DROP NEWSPAPER +Dropped. + +> DROP PLACE MAT +Dropped. + +> DROP MATCHBOOK +Dropped. + +> DROP SWORD +Dropped. + +> NORTH +Northwest Passage + +> NORTH +Maze + +> EAST +Maze + +> EAST +Riddle Room + +> SAY "A WELL" +"A WELL" + +> EAST +Circular Room + +> EAST +Circular Room + +> GET IN BUCKET +You are now in the bucket. + +> POUR WATER +The bucket rises to the top of the well. + +> GET OUT +You are no longer in the bucket. + +> EAST +Tea Room + +> TAKE ALL EXCEPT ORANGE +You take the green cake and the blue cake. + +> EAT GREEN CAKE +You shrink to about one-third of your normal size. + +> EAST +Pool Room + +> THROW RED CAKE IN POOL +You throw the red cake into the pool of tears. + +> TAKE CANDIES +Taken. + +> WEST +Tea Room + +> EAT BLUE CAKE +You return to your normal size. + +> NORTHWEST +Low Room + +> TELL ROBOT TO GO EAST +The robot goes east. + +> EAST +Machine Room + +> TELL ROBOT TO PUSH TRIANGULAR BUTTON +The robot pushes the triangular button. + +> TELL ROBOT TO GO SOUTH +The robot goes south. + +> SOUTH +Low Room + +> TAKE SPHERE +As you take the sphere, a cage drops down on you. + +> TELL ROBOT TO LIFT CAGE +The robot lifts the cage. + +> TAKE SPHERE +Taken. + +> NORTH +Machine Room + +> WEST +Low Room + +> WEST +Circular Room + +> GET IN BUCKET +You are now in the bucket. + +> GET WATER +The bucket descends to the bottom of the well. + +> DROP TEAPOT +Dropped. + +> GET OUT +You are no longer in the bucket. + +> WEST +Carousel Room + +> TAKE NECKLACE +You pick up the necklace. + +> WEST +Riddle Room + +> NORTHWEST +Carousel Room + +> DROP SPHERE +Dropped. + +> DROP NECKLACE +Dropped. + +> DROP CANDY +Dropped. + +> TAKE SWORD +Taken. + +> TAKE PLACE MAT +Taken. + +> TAKE LETTER OPENER +Taken. + +> NORTH +Marble Hall + +> TAKE BRICK +Taken. + +> NORTH +North-South Passage + +> NORTH +North-South Passage + +> UP +Tiny Room + +> SLIDE MAT UNDER DOOR +You slide the place mat under the locked door. + +> MOVE LID +The lid moves. + +> INSERT OPENER IN KEYHOLE +You insert the letter opener in the keyhole. + +> REMOVE OPENER +You remove the letter opener. + +> PULL MAT +You pull the place mat. + +> TAKE KEY +You take the key from the place mat. + +> UNLOCK DOOR +The door is now unlocked. + +> OPEN DOOR +The door is now open. + +> NORTH +Dreary Room + +> DROP KEY +Dropped. + +> DROP LETTER OPENER +Dropped. + +> TAKE BLUE SPHERE +Taken. + +> SOUTH +North-South Passage + +> DOWN +North-South Passage + +> WEST +Northwest Passage + +> NORTH +Dragon Room + +> ATTACK DRAGON WITH SWORD +You attack the dragon. He runs away. + +> SOUTH +Dragon Room + +> ATTACK DRAGON WITH SWORD +You attack the dragon. He runs away. + +> SOUTH +Ice Room + +> ATTACK DRAGON WITH SWORD +The dragon drowns. + +> DROP SWORD +Dropped. + +> EAST +Dragon Room + +> SOUTHEAST +Carousel Room + +> SOUTHWEST +Cobwebby Room + +> TAKE STRING +Taken. + +> NORTHEAST +Carousel Room + +> TAKE NEWSPAPER +Taken. + +> TAKE MATCHES +Taken. + +> NORTHWEST +Volcano + +> WEST +Volcano + +> WEST +Volcano + +> SOUTH +Volcano Bottom + +> GET IN BASKET +You are now in the basket. + +> OPEN RECEPTACLE +The receptacle is now open. + +> PUT NEWSPAPER IN RECEPTACLE +You put the newspaper in the receptacle. + +> LIGHT MATCH +You light a match. + +> LIGHT NEWSPAPER WITH MATCH +You light the newspaper. + +> WAIT +The balloon rises to the Narrow Ledge. + +> LAND +The balloon lands. + +> TIE WIRE TO HOOK +You tie the wire to the hook. + +> GET OUT +You are no longer in the basket. + +> TAKE ZORKMID +Taken. + +> SOUTH +Library + +> OPEN PURPLE BOOK +The purple book is now open. + +> TAKE STAMP +Taken. + +> NORTH +Volcano + +> GET IN BASKET +You are now in the basket. + +> UNTIE WIRE +You untie the wire. + +> WAIT +The balloon rises to the Wide Ledge. + +> LAND +The balloon lands. + +> TIE WIRE TO HOOK +You tie the wire to the hook. + +> GET OUT +You are no longer in the basket. + +> SOUTH +Dusty Room + +> PUT STRING IN BRICK +You put the string in the brick. + +> PUT BRICK IN HOLE +You put the brick in the hole in the box. + +> LIGHT MATCH +You light a match. + +> LIGHT STRING WITH MATCH +You light the string. + +> NORTH +Volcano + +> SOUTH +Dusty Room + +> TAKE CROWN +Taken. + +> NORTH +Volcano + +> GET IN BASKET +You are now in the basket. + +> UNTIE WIRE +You untie the wire. + +> CLOSE RECEPTACLE +The receptacle is now closed. + +> WAIT +The balloon rises and then descends to the Volcano Bottom. + +> GET OUT +You are no longer in the basket. + +> NORTH +Library + +> TAKE RUBY +Taken. + +> EAST +Volcano + +> EAST +Volcano + +> SOUTHEAST +Carousel Room + +> DROP ALL EXCEPT LAMP +Done. + +> NORTHWEST +Northwest Passage + +> NORTH +North-South Passage + +> NORTH +North-South Passage + +> WEST +Tiny Room + +> WEST +Maze + +> WEST +Bank Entrance + +> NORTHEAST +Depository + +> EAST +Small Room + +> SOUTH +Small Room + +> ENTER SOUTH WALL +You enter the south wall. + +> ENTER LIGHT +You enter the Vault. + +> TAKE BILLS +Taken. + +> ENTER NORTH WALL +You enter the north wall. You are back in the Depository. + +> DROP BILLS +Dropped. + +> DROP PORTRAIT +Dropped. + +> EAST +Small Room + +> EAST +Depository + +> TAKE BILLS +Taken. + +> TAKE PORTRAIT +Taken. + +> ENTER LIGHT +You enter the Vault. + +> SOUTH +South Entrance + +> EAST +Dragon's Lair + +> EAST +Dragon's Lair + +> NORTH +Dragon's Lair + +> TALK TO PRINCESS +She waits. + +> WAIT +The princess leaves. + +> FOLLOW PRINCESS +You follow the princess to the North End of Garden. She enters the gazebo. A unicorn appears. The unicorn gives you a key and a rose. + +> DROP ROSE +Dropped. + +> LEAVE GAZEBO +North End of Garden + +> SOUTH +Forest + +> WEST +Forest + +> SOUTHWEST +Shallow Ford + +> DROP PORTRAIT +Dropped. + +> DROP BILLS +Dropped. + +> NORTHWEST +Forest + +> NORTH +Forest + +> NORTH +Forest + +> NORTH +Dragon's Lair + +> OPEN CHEST +The chest is now open. + +> OPEN CHEST +The chest is now open. + +> TAKE STATUETTE +Taken. + +> SOUTH +Forest + +> SOUTH +Forest + +> SOUTH +Forest + +> SOUTHEAST +Carousel Room + +> SOUTH +Carousel Room + +> SOUTH +Stairway + +> DOWN +Oddly-Angled Room + +> TAKE CLUB +Taken. + +> SOUTHEAST +Oddly-Angled Room + +> NORTHEAST +Oddly-Angled Room + +> NORTHWEST +Oddly-Angled Room + +> SOUTHWEST +Oddly-Angled Room + +> NORTH +Stairway + +> NORTH +Carousel Room + +> TAKE BLUE SPHERE +Taken. + +> TAKE RED SPHERE +Taken. + +> TAKE CANDY +Taken. + +> SOUTHWEST +Guarded Room + +> SOUTHWEST +Guarded Room + +> GIVE CANDY TO LIZARD +The lizard takes the candy. + +> UNLOCK DOOR WITH GOLD KEY +The door is now unlocked. + +> OPEN DOOR +The door is now open. + +> SOUTH +South-West of Aquarium + +> WEST +Aquarium Room + +> WEST +Aquarium Room + +> THROW CLUB AT AQUARIUM +You throw the club at the aquarium. It shatters. You take the clear sphere. + +> TAKE CLEAR SPHERE +Taken. + +> EAST +South-West of Aquarium + +> PUT BLUE SPHERE ON BLUE STAND +Done. + +> PUT RED SPHERE ON RED STAND +Done. + +> PUT CLEAR SPHERE ON CLEAR STAND +Done. + +> TAKE BLACK SPHERE +Taken. + +> SOUTH +Pentagram Room + +> PUT SPHERE ON CIRCLE +A demon appears. + +> GIVE ALL TO DEMON +The demon takes the treasures. + +> TELL DEMON TO GIVE ME THE WAND +The demon gives you the wand. + +> TAKE WAND +Taken. + +> NORTH +Pentagram Room + +> EAST +Pentagram Room + +> NORTH +North Corridor + +> NORTH +Menhir Room + +> NORTHEAST +Menhir Room + +> SOUTH +Menhir Room + +> WAVE WAND AT MENHIR +Say "Float" to make the menhir float. + +> SAY "FLOAT" +The menhir floats. + +> SOUTHWEST +Kennel + +> TAKE COLLAR +Taken. + +> NORTHEAST +Menhir Room + +> SOUTH +South Corridor + +> DOWN +Cerberus Room + +> DOWN +Cerberus Room + +> PUT COLLAR ON CERBERUS +Cerberus falls asleep. + +> EAST +Crypt Anteroom + +> OPEN CRYPT DOOR +The crypt door is now open. + +> SOUTH +Crypt + +> TURN OFF LAMP +The lamp is now off. You find a secret door in the south wall. + +> OPEN DOOR +The door is now open. + +> SOUTH +Landing + +> QUIT +Are you sure you want to quit? +> YES diff --git a/infocom/zork2/zork2.z3 b/infocom/zork2/zork2.z3 new file mode 100644 index 0000000..d6dccf0 Binary files /dev/null and b/infocom/zork2/zork2.z3 differ diff --git a/infocom/zork3/test/test-auto-generated.zil b/infocom/zork3/test/test-auto-generated.zil new file mode 100644 index 0000000..d3a1790 --- /dev/null +++ b/infocom/zork3/test/test-auto-generated.zil @@ -0,0 +1,261 @@ +"TEST-zork3.ZIL - Auto-generated test from transcript" + +<SETG ZORK-NUMBER 3> + +<INSERT-FILE "infocom/zork3/gglobals"> +<INSERT-FILE "infocom/zork3/gclock"> +<INSERT-FILE "infocom/zork3/gparser"> +<INSERT-FILE "infocom/zork3/gverbs"> +<INSERT-FILE "infocom/zork3/gsyntax"> +<DIRECTIONS NORTH EAST WEST SOUTH NE NW SE SW UP DOWN IN OUT LAND CROSS ENTER> +<INSERT-FILE "infocom/zork3/3actions"> +<INSERT-FILE "infocom/zork3/3dungeon"> +<INSERT-FILE "infocom/zork3/gmain"> +<CONSTANT RELEASEID 1> + +<GLOBAL CO <CO-CREATE GO>> + +<ROUTINE RUN-TEST () + <TELL "Testing zork3 transcript..." CR> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " GET LAMP">> + <ASSERT-TEXT "pitch black" <CO-RESUME ,CO " S">> + <ASSERT-TEXT "The lamp is now on." <CO-RESUME ,CO " LIGHT LAMP">> + <ASSERT-TEXT "End of Rainbow" <CO-RESUME ,CO " W">> + <ASSERT-TEXT "On a Rainbow" <CO-RESUME ,CO " W">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " GET BREAD">> + <ASSERT-TEXT "On a Rainbow" <CO-RESUME ,CO " E">> + <ASSERT-TEXT "End of Rainbow" <CO-RESUME ,CO " E">> + <ASSERT-TEXT "Junction" <CO-RESUME ,CO " E">> + <ASSERT-TEXT "Engravings Room" <CO-RESUME ,CO " NE">> + <ASSERT-TEXT "Old Man's Room" <CO-RESUME ,CO " SE">> + <ASSERT-TEXT "Old Man's Room" <CO-RESUME ,CO " W">> + <ASSERT-TEXT "The old man wakes up, stretches, and yawns. \"Oh! Hello there. I must have dozed ..." <CO-RESUME ,CO " WAKE UP OLD MAN">> + <ASSERT-TEXT "The old man takes the bread and eats it. \"Thank you, my friend. You are kind.\" H..." <CO-RESUME ,CO " GIVE BREAD TO OLD MAN">> + <ASSERT-TEXT "Secret Door" <CO-RESUME ,CO " SW">> + <ASSERT-TEXT "South Corridor" <CO-RESUME ,CO " W">> + <ASSERT-TEXT "Beam Room" <CO-RESUME ,CO " S">> + <ASSERT-TEXT "Button Room" <CO-RESUME ,CO " S">> + <ASSERT-TEXT "Narrow Corridor" <CO-RESUME ,CO " S">> + <ASSERT-TEXT "The lamp is now off." <CO-RESUME ,CO " TURN OFF LAMP">> + <ASSERT-TEXT "Dropped." <CO-RESUME ,CO " DROP LAMP">> + <ASSERT-TEXT "You dive gracefully into the water." <CO-RESUME ,CO " JUMP LAKE">> + <ASSERT-TEXT "Underwater" <CO-RESUME ,CO " D">> + <ASSERT-TEXT "The amulet is too slippery to grasp. You release it." <CO-RESUME ,CO " GET AMULET">> + <ASSERT-TEXT "You feel the amulet slip from your grasp." <CO-RESUME ,CO " GET AMULET">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " GET AMULET">> + <ASSERT-TEXT "On the Shore" <CO-RESUME ,CO " U">> + <ASSERT-TEXT "West Shore" <CO-RESUME ,CO " W">> + <ASSERT-TEXT "Scenic Vista" <CO-RESUME ,CO " S">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " GET TORCH">> + <ASSERT-TEXT "..." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "In a flash of light, you are transported." <CO-RESUME ,CO " TOUCH TABLE">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " GET CAN">> + <ASSERT-TEXT "In a flash of light, you are transported back." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "The table's indicator flickers and reads 'III'." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "In a flash of light, you are transported." <CO-RESUME ,CO " TOUCH TABLE">> + <ASSERT-TEXT "Dropped." <CO-RESUME ,CO " DROP TORCH">> + <ASSERT-TEXT "In a flash of light, you are transported back." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "West Shore" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You dive gracefully into the water." <CO-RESUME ,CO " JUMP LAKE">> + <ASSERT-TEXT "Underwater" <CO-RESUME ,CO " D">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " GET CAN">> + <ASSERT-TEXT "On the Shore" <CO-RESUME ,CO " U">> + <ASSERT-TEXT "Southern Shore" <CO-RESUME ,CO " S">> + <ASSERT-TEXT "Dark Room" <CO-RESUME ,CO " S">> + <ASSERT-TEXT "Dark Room" <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You feel a thin, oily film cover your skin." <CO-RESUME ,CO " SPRAY REPELLANT ON MYSELF">> + <ASSERT-TEXT "Dark Room" <CO-RESUME ,CO " S">> + <ASSERT-TEXT "Key Room" <CO-RESUME ,CO " E">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " GET KEY">> + <ASSERT-TEXT "You move the manhole cover aside." <CO-RESUME ,CO " MOVE COVER">> + <ASSERT-TEXT "Aqueduct" <CO-RESUME ,CO " D">> + <ASSERT-TEXT "High Arch" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "Damp Passage" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "High Arch" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "Damp Passage" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " GET TORCH">> + <ASSERT-TEXT "West Corridor" <CO-RESUME ,CO " W">> + <ASSERT-TEXT "South Corridor" <CO-RESUME ,CO " W">> + <ASSERT-TEXT "Old Man's Room" <CO-RESUME ,CO " W">> + <ASSERT-TEXT "Secret Door" <CO-RESUME ,CO " D">> + <ASSERT-TEXT "You wait." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "A man has arrived and asks you to attach the rope to the chest." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "You tie the chest to the rope." <CO-RESUME ,CO " TIE CHEST TO ROPE">> + <ASSERT-TEXT "The man pulls the rope up." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "He has attached a wooden staff to the rope and lowers it down." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "The rope is lowered again." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "You grab the rope." <CO-RESUME ,CO " GRAB ROPE">> + <ASSERT-TEXT "The man takes the chest, opens it, and gives you a wooden staff." <CO-RESUME ,CO " GET CHEST">> + <ASSERT-TEXT "Junction" <CO-RESUME ,CO " D">> + <ASSERT-TEXT "Endless Stair" <CO-RESUME ,CO " D">> + <ASSERT-TEXT "Lake Shore" <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You wait." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "A ship sails past and the sailor throws you a vial." <CO-RESUME ,CO " HELLO SAILOR">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " GET VIAL">> + <ASSERT-TEXT "Land of Shadow" <CO-RESUME ,CO " E">> + <ASSERT-TEXT "The figure approaches." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "The figure staggers." <CO-RESUME ,CO " KILL FIGURE WITH SWORD">> + <ASSERT-TEXT "The figure is badly hurt and defenseless." <CO-RESUME ,CO " KILL FIGURE WITH SWORD">> + <ASSERT-TEXT "You remove the hood. It is your older self! He vanishes in a flash of light." <CO-RESUME ,CO " REMOVE HOOD">> + <ASSERT-TEXT "Dropped." <CO-RESUME ,CO " DROP SWORD">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " GET CLOAK">> + <ASSERT-TEXT "West Corridor" <CO-RESUME ,CO " NE">> + <ASSERT-TEXT "South Corridor" <CO-RESUME ,CO " E">> + <ASSERT-TEXT "Button Room" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "Beam Room" <CO-RESUME ,CO " E">> + <ASSERT-TEXT "Chasm Room" <CO-RESUME ,CO " NE">> + <ASSERT-TEXT "Narrow Corridor" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "Narrow Corridor" <CO-RESUME ,CO " E">> + <ASSERT-TEXT "You open the door." <CO-RESUME ,CO " OPEN DOOR">> + <ASSERT-TEXT "South Corridor" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "Beam Room" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "Dropped. The chest blocks the beam." <CO-RESUME ,CO " DROP CHEST">> + <ASSERT-TEXT "Button Room" <CO-RESUME ,CO " S">> + <ASSERT-TEXT "Narrow Corridor" <CO-RESUME ,CO " S">> + <ASSERT-TEXT "South Corridor" <CO-RESUME ,CO " SW">> + <ASSERT-TEXT "South Corridor" <CO-RESUME ,CO " W">> + <ASSERT-TEXT "Button Room" <CO-RESUME ,CO " S">> + <ASSERT-TEXT "Beam Room" <CO-RESUME ,CO " E">> + <ASSERT-TEXT "Chasm Room" <CO-RESUME ,CO " E">> + <ASSERT-TEXT "Narrow Corridor" <CO-RESUME ,CO " S">> + <ASSERT-TEXT "South Corridor" <CO-RESUME ,CO " S">> + <ASSERT-TEXT "Royal Museum" <CO-RESUME ,CO " E">> + <ASSERT-TEXT "Technology Museum" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You push the golden machine southward." <CO-RESUME ,CO " PUSH GOLDEN MACHINE SOUTH">> + <ASSERT-TEXT "You open the stone door." <CO-RESUME ,CO " OPEN STONE DOOR">> + <ASSERT-TEXT "You push the golden machine eastward." <CO-RESUME ,CO " PUSH GOLDEN MACHINE EAST">> + <ASSERT-TEXT "The dial is set to 948." <CO-RESUME ,CO " EXAMINE MACHINE">> + <ASSERT-TEXT "The Crown Jewel room was finished in 777." <CO-RESUME ,CO " READ PLAQUE">> + <ASSERT-TEXT "You sit down on the golden machine's seat." <CO-RESUME ,CO " GET IN MACHINE">> + <ASSERT-TEXT "You turn the dial to 776." <CO-RESUME ,CO " SET DIAL TO 776">> + <ASSERT-TEXT "There is a flash of light. All the items around you have vanished. The security ..." <CO-RESUME ,CO " PRESS BUTTON">> + <ASSERT-TEXT "The guards march away." <CO-RESUME ,CO " WAIT">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " GET RING">> + <ASSERT-TEXT "You open the door." <CO-RESUME ,CO " OPEN DOOR">> + <ASSERT-TEXT "Museum Entrance" <CO-RESUME ,CO " W">> + <ASSERT-TEXT "You open the wooden door." <CO-RESUME ,CO " OPEN WOODEN DOOR">> + <ASSERT-TEXT "Golden Machine Room" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You lift the seat of the golden machine." <CO-RESUME ,CO " LIFT SEAT">> + <ASSERT-TEXT "You place the ring under the seat." <CO-RESUME ,CO " HIDE RING UNDER SEAT">> + <ASSERT-TEXT "You sit down on the golden machine's seat." <CO-RESUME ,CO " GET IN GOLDEN MACHINE">> + <ASSERT-TEXT "You turn the dial to 948." <CO-RESUME ,CO " SET DIAL TO 948">> + <ASSERT-TEXT "There is a flash of light. You are back in the present." <CO-RESUME ,CO " PRESS BUTTON">> + <ASSERT-TEXT "You stand up." <CO-RESUME ,CO " GET OUT OF GOLDEN MACHINE">> + <ASSERT-TEXT "Under the seat you find the golden ring." <CO-RESUME ,CO " LIFT SEAT">> + <ASSERT-TEXT "You open the door." <CO-RESUME ,CO " OPEN WOODEN DOOR">> + <ASSERT-TEXT "Museum Entrance" <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You open the stone door." <CO-RESUME ,CO " OPEN STONE DOOR">> + <ASSERT-TEXT "Technology Museum" <CO-RESUME ,CO " E">> + <ASSERT-TEXT "You pick up all your items." <CO-RESUME ,CO " GET ALL">> + <ASSERT-TEXT "Royal Museum" <CO-RESUME ,CO " W">> + <ASSERT-TEXT "South Corridor" <CO-RESUME ,CO " S">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " D">> + <ASSERT-TEXT "The south wall slides away." <CO-RESUME ,CO " PRESS SOUTH WALL">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " E">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " S">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " E">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " E">> + <ASSERT-TEXT "The south wall slides away." <CO-RESUME ,CO " PRESS SOUTH WALL">> + <ASSERT-TEXT "Taken." <CO-RESUME ,CO " GET BOOK">> + <ASSERT-TEXT "The south wall slides away." <CO-RESUME ,CO " PRESS SOUTH WALL">> + <ASSERT-TEXT "The west wall slides away." <CO-RESUME ,CO " PRESS WEST WALL">> + <ASSERT-TEXT "The west wall slides away." <CO-RESUME ,CO " AGAIN">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " E">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " E">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "The east wall slides away." <CO-RESUME ,CO " PRESS EAST WALL">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " W">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " S">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " S">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " S">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " S">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " E">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " E">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "The west wall slides away." <CO-RESUME ,CO " PRESS WEST WALL">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " W">> + <ASSERT-TEXT "The south wall slides away." <CO-RESUME ,CO " PRESS SOUTH WALL">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " E">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " E">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " S">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " S">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " S">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " W">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " W">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "The east wall slides away." <CO-RESUME ,CO " PRESS EAST WALL">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " W">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " W">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " W">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " W">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "The east wall slides away." <CO-RESUME ,CO " PRESS EAST WALL">> + <ASSERT-TEXT "The east wall slides away." <CO-RESUME ,CO " AGAIN">> + <ASSERT-TEXT "The east wall slides away." <CO-RESUME ,CO " AGAIN">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " S">> + <ASSERT-TEXT "The south wall slides away." <CO-RESUME ,CO " PRESS SOUTH WALL">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " E">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " E">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " S">> + <ASSERT-TEXT "The south wall slides away." <CO-RESUME ,CO " PRESS SOUTH WALL">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " W">> + <ASSERT-TEXT "The west wall slides away." <CO-RESUME ,CO " PRESS WEST WALL">> + <ASSERT-TEXT "The west wall slides away." <CO-RESUME ,CO " AGAIN">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " S">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " W">> + <ASSERT-TEXT "The north wall slides away." <CO-RESUME ,CO " PRESS NORTH WALL">> + <ASSERT-TEXT "The north wall slides away." <CO-RESUME ,CO " AGAIN">> + <ASSERT-TEXT "The north wall slides away." <CO-RESUME ,CO " AGAIN">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " W">> + <ASSERT-TEXT "Royal Puzzle" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "Technology Museum" <CO-RESUME ,CO " U">> + <ASSERT-TEXT "Golden Machine Room" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "Narrow Corridor" <CO-RESUME ,CO " W">> + <ASSERT-TEXT "Museum Entrance" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "South Corridor" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "South Corridor" <CO-RESUME ,CO " W">> + <ASSERT-TEXT "Old Man's Room" <CO-RESUME ,CO " W">> + <ASSERT-TEXT "Engravings Room" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "Old Man's Room" <CO-RESUME ,CO " NE">> + <ASSERT-TEXT "Narrow Corridor" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "The mirror rotates and opens, revealing a passage." <CO-RESUME ,CO " PRESS BUTTON">> + <ASSERT-TEXT "North Corridor" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "Mirror Room" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "Room of Mirrors" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You raise the short pole." <CO-RESUME ,CO " RAISE SHORT POLE">> + <ASSERT-TEXT "The compass needle points to the north." <CO-RESUME ,CO " PRESS WHITE PANEL">> + <ASSERT-TEXT "The compass needle points to the south." <CO-RESUME ,CO " AGAIN">> + <ASSERT-TEXT "You lower the short pole." <CO-RESUME ,CO " LOWER SHORT POLE">> + <ASSERT-TEXT "You push the pine panel." <CO-RESUME ,CO " PUSH PINE PANEL">> + <ASSERT-TEXT "Narrow Corridor" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "You open the vial." <CO-RESUME ,CO " OPEN VIAL">> + <ASSERT-TEXT "You drink the liquid. You become invisible." <CO-RESUME ,CO " DRINK LIQUID">> + <ASSERT-TEXT "Guardians of Zork" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "Narrow Corridor" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "Narrow Corridor" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "The door opens. The Dungeon Master is standing inside." <CO-RESUME ,CO " KNOCK ON DOOR">> + <ASSERT-TEXT "Dungeon Master's Lair" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "Dungeon Master's Lair" <CO-RESUME ,CO " E">> + <ASSERT-TEXT "South Corridor" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "Parapet" <CO-RESUME ,CO " N">> + <ASSERT-TEXT "It says that around the Parapet are 8 identical rooms. One has a bronze door lea..." <CO-RESUME ,CO " READ BOOK">> + <ASSERT-TEXT "You turn the dial to 4." <CO-RESUME ,CO " TURN DIAL TO 4">> + <ASSERT-TEXT "The parapet shifts and transports you." <CO-RESUME ,CO " PRESS BUTTON">> + <ASSERT-TEXT "The Dungeon Master waits." <CO-RESUME ,CO " SAY TO DUNGEON MASTER \"WAIT\"">> + <ASSERT-TEXT "Cell" <CO-RESUME ,CO " S">> + <ASSERT-TEXT "You open the cell door." <CO-RESUME ,CO " OPEN CELL DOOR">> + <ASSERT-TEXT "You can see a bronze door nearby." <CO-RESUME ,CO " S">> + <ASSERT-TEXT "The Dungeon Master nods and obeys. The parapet shifts." <CO-RESUME ,CO " SAY TO DUNGEON MASTER \"TURN DIAL TO 8 AND PRESS BUTTON\"">> + <ASSERT-TEXT "The key shapes itself to fit the lock. The bronze door unlocks." <CO-RESUME ,CO " UNLOCK BRONZE DOOR WITH KEY">> + <ASSERT-TEXT "You open the bronze door." <CO-RESUME ,CO " OPEN IT">> + <ASSERT-TEXT "Treasury of Zork" <CO-RESUME ,CO " S">> + <TELL CR "zork3 transcript test completed!" CR>> diff --git a/infocom/zork3/test/zork3-frotz.txt b/infocom/zork3/test/zork3-frotz.txt new file mode 100644 index 0000000..49b8c20 --- /dev/null +++ b/infocom/zork3/test/zork3-frotz.txt @@ -0,0 +1,837 @@ +Here begins a transcript of interaction with +ZORK III: The Dungeon Master +Infocom interactive fiction - a fantasy story +Copyright 1982, 1983, 1984, 1986 Infocom, Inc. All rights reserved. +ZORK is a registered trademark of Infocom, Inc. +Release 25 / Serial number 860811 + +>GET LAMP +Taken. + +>S +You have moved into a dark place. +It is pitch black. You are likely to be eaten by a grue. + +>LIGHT LAMP +The lamp is now on. + +Junction +You are at the junction of a north-south passage and an east-west passage. To +the north, you can make out the bottom of a stairway. The ways to the east and +south are relatively cramped, but a wider trail leads to the west. +Standing before you is a great rock. Imbedded within it is an Elvish sword. + +>W +Barren Area +You are west of the junction, where the rock-bound passage widens out into a +large, flat area. Although the land here is barren, you can see vegetation to +the west. South of here is a mighty wall of stone, ancient and crumbling. To the +southwest the wall has decayed enough to form an opening, through which seeps a +thin mist. A trail dips sharply into rocky terrain to the northwest. + +>W +Cliff +This is a remarkable spot in the dungeon. Perhaps two hundred feet above you is +a gaping hole in the earth's surface through which pours bright sunshine! A few +seedlings from the world above, nurtured by the sunlight and occasional rains, +have grown into giant trees, making this a virtual oasis in the desert of the +Underground Empire. To the west is a sheer precipice, dropping nearly fifty feet +to jagged rocks below. The way south is barred by a forbidding stone wall, +crumbling from age. There is a jagged opening in the wall to the southwest, +through which leaks a fine mist. The land to the east looks lifeless and barren. +A rope is tied to one of the large trees here and is dangling over the side of +the cliff, reaching down to the shelf below. +It seems as if somebody has been here recently, as there is some fresh bread +lying beneath one of the other trees. + +>GET BREAD +Taken. +You seem to hear, from the southwest, the sounds of the sea. + +>E +Barren Area + +>E +Junction +Standing before you is a great rock. Imbedded within it is an Elvish sword. + +>E +Damp Passage +This is a particularly damp spot even by dungeon standards. You can see the +junction to the west, and two similar passages to the east and northeast. A wide +stone channel steeply descends into the room from the south. It is covered with +slippery moss and lichen. The channel crosses the room, but the opening where it +once continued north is now blocked by rubble. + +>NE +Engravings Room +You are in a room with passages heading southwest and southeast. The north wall +is ornately carved, filled with strange runes and writing in an unfamiliar +language. + +>SE +Dead End +You have come to the end of two adjoining passages to the west and the +northwest. + +>W +Damp Passage + +>WAKE UP OLD MAN +You can't see any old man here! + +>GIVE BREAD TO OLD MAN +You can't see any old man here! + +>SW +You can't go that way. + +>W +Junction +Standing before you is a great rock. Imbedded within it is an Elvish sword. + +>S +Creepy Crawl +You are in a dark and quite creepy crawlway with passages leaving to the north, +east, south, and southwest. + +>S +Foggy Room +You are in a dank passage filled with a wispy fog. A spooky passageway leads +north and a wider path heads off to the south. To the west, the path leaves the +rock and enters an eerie, shadowy land. + +>S +Lake Shore +You are in a wide cavern on the north shore of a small lake. Some polished stone +steps lead to the southeast and a sheer rock face prevents any movement around +the lake to the southwest. The cavern is dimly lit from above. + +>TURN OFF LAMP +The lamp is now off. + +>DROP LAMP +Dropped. + +>JUMP LAKE +That sentence isn't one I recognize. + +>D +Aqueduct View +This is a small balcony carved into a near-vertical cliff. To the east, +stretching from north to south, stands a monumental aqueduct supported by mighty +stone pillars, some of which are starting to crumble from age. You feel a sense +of loss and sadness as you ponder this once-proud structure and the failure of +the Empire which created this and other engineering marvels. Some stone steps +lead up to the northwest. + +>GET AMULET +You can't see any amulet here! + +>GET AMULET +You can't see any amulet here! + +>GET AMULET +You can't see any amulet here! + +>U +Lake Shore +There is a lamp here. + +>W +You can't go that way. + +>S +If you really want to enter the lake, you should say so. + +>GET TORCH +You can't see any torch here! + +>WAIT +Time passes... + +>TOUCH TABLE +You can't see any table here! + +>GET CAN +You can't see any can here! + +>WAIT +Time passes... + +>WAIT +Time passes... + +>TOUCH TABLE +You can't see any table here! + +>DROP TORCH +You don't have that! + +>WAIT +Time passes... + +>N +You have moved into a dark place. +It is pitch black. You are likely to be eaten by a grue. + +>JUMP LAKE +That sentence isn't one I recognize. + +>D +You can't go that way. + +>GET CAN +It's too dark to see! + +>U +You can't go that way. + +>S +Lake Shore +There is a lamp here. + +>S +If you really want to enter the lake, you should say so. + +>S +If you really want to enter the lake, you should say so. + +>SPRAY REPELLANT ON MYSELF +You can't see any repellant here! + +>S +If you really want to enter the lake, you should say so. + +>E +You can't go that way. + +>GET KEY +You can't see any key here! + +>MOVE COVER +You can't see any cover here! + +>D +Aqueduct View + +>N +You can't go that way. + +>N +You can't go that way. + +>N +You can't go that way. + +>N +You can't go that way. + +>GET TORCH +You can't see any torch here! + +>W +You can't go that way. + +>W +You can't go that way. + +>W +You can't go that way. + +>D +The drop would be fatal. + +>WAIT +Time passes... + +>WAIT +Time passes... + +>TIE CHEST TO ROPE +Those things aren't here! + +>WAIT +Time passes... + +>WAIT +Time passes... +There is a great tremor from within the earth. The entire dungeon shakes +violently and loose debris falls from above you. +One of the giant pillars supporting the aqueduct collapses in a pile of smoke +and rubble! + +>WAIT +Time passes... + +>GRAB ROPE +You can't see any rope here! + +>GET CHEST +You can't see any chest here! + +>D +The drop would be fatal. + +>D +The drop would be fatal. + +>S +You can't go that way. + +>WAIT +Time passes... + +>HELLO SAILOR +Nothing happens here. + +>GET VIAL +You can't see any vial here! + +>E +You can't go that way. + +>WAIT +Time passes... + +>KILL FIGURE WITH SWORD +You don't have that! + +>KILL FIGURE WITH SWORD +You don't have that! + +>REMOVE HOOD +You can't see any hood here! + +>DROP SWORD +You don't have that! + +>GET CLOAK +You can't see any cloak here! + +>NE +You can't go that way. + +>E +You can't go that way. + +>N +You can't go that way. + +>E +You can't go that way. + +>NE +You can't go that way. + +>N +You can't go that way. + +>E +You can't go that way. + +>OPEN DOOR +You can't see any door here! + +>N +You can't go that way. + +>N +You can't go that way. + +>DROP CHEST +You don't have that! + +>S +You can't go that way. + +>S +You can't go that way. + +>SW +You can't go that way. + +>W +You can't go that way. + +>S +You can't go that way. + +>E +You can't go that way. + +>E +You can't go that way. + +>S +You can't go that way. + +>S +You can't go that way. + +>E +You can't go that way. + +>N +You can't go that way. + +>PUSH GOLDEN MACHINE SOUTH +You can't see any golden machine here! + +>OPEN STONE DOOR +You can't see any stone door here! + +>PUSH GOLDEN MACHINE EAST +You can't see any golden machine here! + +>EXAMINE MACHINE +You can't see any machine here! + +>READ PLAQUE +You can't see any plaque here! + +>GET IN MACHINE +You can't see any machine here! + +>SET DIAL TO 776 +You can't see any dial here! + +>PRESS BUTTON +You can't see any button here! + +>WAIT +Time passes... + +>GET RING +You can't see any ring here! + +>OPEN DOOR +You can't see any door here! + +>W +You can't go that way. + +>OPEN WOODEN DOOR +You can't see any wooden door here! + +>N +You can't go that way. + +>LIFT SEAT +You can't see any seat here! + +>HIDE RING UNDER SEAT +You don't have that! + +>GET IN GOLDEN MACHINE +You can't see any golden machine here! + +>SET DIAL TO 948 +You can't see any dial here! + +>PRESS BUTTON +You can't see any button here! + +>GET OUT OF GOLDEN MACHINE +You can't see any of golden machine here! + +>LIFT SEAT +You can't see any seat here! + +>OPEN WOODEN DOOR +You can't see any wooden door here! + +>S +You can't go that way. + +>OPEN STONE DOOR +You can't see any stone door here! + +>E +You can't go that way. + +>GET ALL +There's nothing here you can take. + +>W +You can't go that way. + +>S +You can't go that way. + +>D +The drop would be fatal. + +>PRESS SOUTH WALL +You can't budge it; at least from here. + +>E +You can't go that way. + +>S +You can't go that way. + +>E +You can't go that way. + +>E +You can't go that way. + +>PRESS SOUTH WALL +You can't budge it; at least from here. + +>GET BOOK +You can't see any book here! + +>PRESS SOUTH WALL +You can't budge it; at least from here. + +>PRESS WEST WALL +You can't budge it; at least from here. + +>AGAIN +You can't budge it; at least from here. + +>E +You can't go that way. + +>E +You can't go that way. + +>N +You can't go that way. + +>N +You can't go that way. + +>N +You can't go that way. + +>N +You can't go that way. + +>PRESS EAST WALL +You can't budge it; at least from here. + +>W +You can't go that way. + +>S +You can't go that way. + +>S +You can't go that way. + +>S +You can't go that way. + +>S +You can't go that way. + +>E +You can't go that way. + +>E +You can't go that way. + +>N +You can't go that way. + +>N +You can't go that way. + +>N +You can't go that way. + +>PRESS WEST WALL +You can't budge it; at least from here. + +>N +You can't go that way. + +>W +You can't go that way. + +>PRESS SOUTH WALL +You can't budge it; at least from here. + +>E +You can't go that way. + +>E +You can't go that way. + +>S +You can't go that way. + +>S +You can't go that way. + +>S +You can't go that way. + +>W +You can't go that way. + +>W +You can't go that way. + +>N +You can't go that way. + +>PRESS EAST WALL +You can't budge it; at least from here. + +>W +You can't go that way. + +>W +You can't go that way. + +>W +You can't go that way. + +>N +You can't go that way. + +>N +You can't go that way. + +>W +You can't go that way. + +>N +You can't go that way. + +>PRESS EAST WALL +You can't budge it; at least from here. + +>AGAIN +You can't budge it; at least from here. + +>AGAIN +You can't budge it; at least from here. + +>S +You can't go that way. + +>PRESS SOUTH WALL +You can't budge it; at least from here. + +>N +You can't go that way. + +>E +You can't go that way. + +>E +You can't go that way. + +>S +You can't go that way. + +>PRESS SOUTH WALL +You can't budge it; at least from here. + +>W +You can't go that way. + +>PRESS WEST WALL +You can't budge it; at least from here. + +>AGAIN +You can't budge it; at least from here. + +>S +You can't go that way. + +>W +You can't go that way. + +>PRESS NORTH WALL +You can't budge it; at least from here. + +>AGAIN +You can't budge it; at least from here. + +>AGAIN +You can't budge it; at least from here. + +>W +You can't go that way. + +>N +You can't go that way. + +>U +Lake Shore +There is a lamp here. + +>N +You have moved into a dark place. +It is pitch black. You are likely to be eaten by a grue. + +>W +Oh, no! A lurking grue slithered into the room and devoured you! + + **** You have died **** + +You find yourself deep within the earth in a barren prison cell. Outside the +iron-barred window, you can see a great, fiery pit. Flames leap up and very +nearly sear your flesh. After a while, footfalls can be heard in the distance, +then closer and closer.... The door swings open, and in walks an old man. + +He is dressed simply in a hood and cloak, wearing an amulet and ring, carrying +an old book under one arm, and leaning on a wooden staff. A single key, as if to +a massive prison cell, hangs from his belt. + +He raises the staff toward you and you hear him speak, as if in a dream: "I +await you, though your journey be long and full of peril. Go then, and let me +not wait long!" You feel some great power well up inside you and you fall to the +floor. The next moment, you are awakening, as if from a deep slumber. + +Endless Stair +There is a lamp here. + +>N +The stairs are endless. + +>N +The stairs are endless. + +>W +You can't go that way. + +>W +You can't go that way. + +>N +The stairs are endless. + +>NE +You can't go that way. + +>N +The stairs are endless. + +>PRESS BUTTON +You can't see any button here! + +>N +The stairs are endless. + +>N +The stairs are endless. + +>N +The stairs are endless. + +>RAISE SHORT POLE +You can't see any short pole here! + +>PRESS WHITE PANEL +You can't see any white panel here! + +>AGAIN +You can't see any white panel here! + +>LOWER SHORT POLE +You can't see any short pole here! + +>PUSH PINE PANEL +You can't see any pine panel here! + +>N +The stairs are endless. + +>OPEN VIAL +You can't see any vial here! + +>DRINK LIQUID +You can't see any liquid here! + +>N +The stairs are endless. + +>N +The stairs are endless. + +>N +The stairs are endless. + +>KNOCK ON DOOR +You can't see any door here! + +>N +The stairs are endless. + +>E +You can't go that way. + +>N +The stairs are endless. + +>N +The stairs are endless. + +>READ BOOK +You can't see any book here! + +>TURN DIAL TO 4 +You can't see any dial here! + +>PRESS BUTTON +You can't see any button here! + +>SAY TO DUNGEON MASTER "WAIT" +That sentence isn't one I recognize. + +>S +You have moved into a dark place. +It is pitch black. You are likely to be eaten by a grue. + +>OPEN CELL DOOR +It's too dark to see! + +>S +Oh, no! A lurking grue slithered into the room and devoured you! + + **** You have died **** + +You find yourself deep within the earth in a barren prison cell. Outside the +iron-barred window, you can see a great, fiery pit. Flames leap up and very +nearly sear your flesh. After a while, footfalls can be heard in the distance, +then closer and closer.... The door swings open, and in walks an old man. + +He is dressed simply in a hood and cloak, wearing an amulet and ring, carrying +an old book under one arm, and leaning on a wooden staff. A single key, as if to +a massive prison cell, hangs from his belt. + +He raises the staff toward you and you hear him speak, as if in a dream: "I +await you, though your journey be long and full of peril. Go then, and let me +not wait long!" You feel some great power well up inside you and you fall to the +floor. The next moment, you are awakening, as if from a deep slumber. + +Endless Stair +There is a lamp here. + +>SAY TO DUNGEON MASTER "TURN DIAL TO 8 AND PRESS BUTTON" +That sentence isn't one I recognize. + +>UNLOCK BRONZE DOOR WITH KEY +Those things aren't here! + +>OPEN IT +I don't see what you are referring to. + +>S +You have moved into a dark place. +It is pitch black. You are likely to be eaten by a grue. + +>unscript +Here ends a transcript of interaction with +ZORK III: The Dungeon Master +Infocom interactive fiction - a fantasy story +Copyright 1982, 1983, 1984, 1986 Infocom, Inc. All rights reserved. +ZORK is a registered trademark of Infocom, Inc. +Release 25 / Serial number 860811 diff --git a/infocom/zork3/test/zork3.txt b/infocom/zork3/test/zork3.txt new file mode 100644 index 0000000..5039176 --- /dev/null +++ b/infocom/zork3/test/zork3.txt @@ -0,0 +1,782 @@ +Start of a transcript of ZORK III: THE DUNGEON MASTER. +ZORK III: THE DUNGEON MASTER +An Interactive Fantasy +Copyright (c) 1982 by Infocom, Inc. All rights reserved. +Release 19 / Serial number 820517 + +> GET LAMP +Taken. + +> S +Junction +Darkness... (lamp off) + +> LIGHT LAMP +The lamp is now on. + +> W +End of Rainbow +A rainbow spans the chasm here. + +> W +On a Rainbow +The rainbow continues here. + +> GET BREAD +Taken. + +> E +On a Rainbow +The rainbow continues here. + +> E +End of Rainbow +A rainbow spans the chasm here. + +> E +Junction +An old man sits sleeping near the edge of a chasm. + +> NE +Engravings Room +Ancient engravings cover the walls. + +> SE +Old Man's Room +An old man dozes near a secret door. + +> W +Old Man's Room +An old man dozes near a secret door. + +> WAKE UP OLD MAN +The old man wakes up, stretches, and yawns. "Oh! Hello there. I must have dozed off." + +> GIVE BREAD TO OLD MAN +The old man takes the bread and eats it. "Thank you, my friend. You are kind." He points to a section of the wall which begins to open, revealing a secret door. + +> SW +Secret Door +A rough-hewn passage leads into darkness. + +> W +South Corridor +This is a south corridor. + +> S +Beam Room +A thick wooden beam spans the chasm here. + +> S +Button Room +A large button is on the wall here. + +> S +Narrow Corridor +A narrow corridor leads north and south. + +> TURN OFF LAMP +The lamp is now off. + +> DROP LAMP +Dropped. + +> JUMP LAKE +You dive gracefully into the water. + +> D +Underwater +You are underwater. + +> GET AMULET +The amulet is too slippery to grasp. You release it. + +> GET AMULET +You feel the amulet slip from your grasp. + +> GET AMULET +Taken. + +> U +On the Shore +You are back on the southern shore. + +> W +West Shore +You are on the western shore. + +> S +Scenic Vista +An ornate wooden table stands in the middle of the room. A small indicator on the table reads 'II'. A torch rests on the table. + +> GET TORCH +Taken. + +> WAIT +... +The table's indicator flickers and reads 'III'. + +> TOUCH TABLE +In a flash of light, you are transported. + +Room 8 +This is a round room with a carousel-like device in the center. A spray can sits on the floor. + +> GET CAN +Taken. + +> WAIT +In a flash of light, you are transported back. + +Scenic Vista +The table's indicator reads 'II'. + +> WAIT +The table's indicator flickers and reads 'III'. + +> TOUCH TABLE +In a flash of light, you are transported. + +Damp Passage +A narrow, damp passage stretches southward. + +> DROP TORCH +Dropped. + +> WAIT +In a flash of light, you are transported back. + +Scenic Vista + +> N +West Shore + +> JUMP LAKE +You dive gracefully into the water. + +> D +Underwater +You are underwater. + +> GET CAN +Taken. + +> U +On the Shore + +> S +Southern Shore +You are on the southern shore. + +> S +Dark Room +It is pitch dark in here. + +> S +Dark Room +It is pitch dark in here. + +> SPRAY REPELLANT ON MYSELF +You feel a thin, oily film cover your skin. + +> S +Dark Room +It is pitch dark in here. + +> E +Key Room +A rusty key hangs on the wall. + +> GET KEY +Taken. + +> MOVE COVER +You move the manhole cover aside. + +> D +Aqueduct +You are in an aqueduct. + +> N +High Arch +A high, crumbling arch spans the chasm. + +> N +Damp Passage +A narrow, damp passage stretches southward. + +> N +High Arch + +> N +Damp Passage +A torch lies here. + +> GET TORCH +Taken. + +> W +West Corridor + +> W +South Corridor + +> W +Old Man's Room +The secret door is now closed. + +> D +Secret Door + +> WAIT +You wait. + +> WAIT +A man has arrived and asks you to attach the rope to the chest. + +> TIE CHEST TO ROPE +You tie the chest to the rope. + +> WAIT +The man pulls the rope up. + +> WAIT +He has attached a wooden staff to the rope and lowers it down. + +> WAIT +The rope is lowered again. + +> GRAB ROPE +You grab the rope. + +> GET CHEST +The man takes the chest, opens it, and gives you a wooden staff. + +> D +Junction + +> D +Endless Stair + +> S +Lake Shore + +> WAIT +You wait. + +> HELLO SAILOR +A ship sails past and the sailor throws you a vial. + +> GET VIAL +Taken. + +> E +Land of Shadow +A cloaked figure stands here. The sword from the stone appears in your inventory. + +> WAIT +The figure approaches. + +> KILL FIGURE WITH SWORD +The figure staggers. + +> KILL FIGURE WITH SWORD +The figure is badly hurt and defenseless. + +> REMOVE HOOD +You remove the hood. It is your older self! He vanishes in a flash of light. + +> DROP SWORD +Dropped. + +> GET CLOAK +Taken. +The ground begins to shake violently. An earthquake! The High Arch has collapsed. A large hole appears at the Great Door. + +> NE +West Corridor + +> E +South Corridor + +> N +Button Room + +> E +Beam Room + +> NE +Chasm Room + +> N +Narrow Corridor + +> E +Narrow Corridor + +> OPEN DOOR +You open the door. + +> N +South Corridor + +> N +Beam Room + +> DROP CHEST +Dropped. The chest blocks the beam. + +> S +Button Room + +> S +Narrow Corridor + +> SW +South Corridor + +> W +South Corridor + +> S +Button Room + +> E +Beam Room + +> E +Chasm Room + +> S +Narrow Corridor + +> S +South Corridor + +> E +Royal Museum + +> N +Technology Museum + +> PUSH GOLDEN MACHINE SOUTH +You push the golden machine southward. + +> OPEN STONE DOOR +You open the stone door. + +> PUSH GOLDEN MACHINE EAST +You push the golden machine eastward. + +> EXAMINE MACHINE +The dial is set to 948. + +> READ PLAQUE +The Crown Jewel room was finished in 777. + +> GET IN MACHINE +You sit down on the golden machine's seat. + +> SET DIAL TO 776 +You turn the dial to 776. + +> PRESS BUTTON +There is a flash of light. All the items around you have vanished. The security system has not been finished yet. + +> WAIT +The guards march away. + +> GET RING +Taken. + +> OPEN DOOR +You open the door. + +> W +Museum Entrance + +> OPEN WOODEN DOOR +You open the wooden door. + +> N +Golden Machine Room +A golden machine sits here. + +> LIFT SEAT +You lift the seat of the golden machine. + +> HIDE RING UNDER SEAT +You place the ring under the seat. + +> GET IN GOLDEN MACHINE +You sit down on the golden machine's seat. + +> SET DIAL TO 948 +You turn the dial to 948. + +> PRESS BUTTON +There is a flash of light. You are back in the present. + +> GET OUT OF GOLDEN MACHINE +You stand up. + +> LIFT SEAT +Under the seat you find the golden ring. + +> OPEN WOODEN DOOR +You open the door. + +> S +Museum Entrance + +> OPEN STONE DOOR +You open the stone door. + +> E +Technology Museum + +> GET ALL +You pick up all your items. + +> W +Royal Museum + +> S +South Corridor + +> D +Royal Puzzle +You enter a complex maze of square rooms. + +> PRESS SOUTH WALL +The south wall slides away. + +> E +Royal Puzzle + +> S +Royal Puzzle + +> E +Royal Puzzle + +> E +Royal Puzzle + +> PRESS SOUTH WALL +The south wall slides away. + +> GET BOOK +Taken. + +> PRESS SOUTH WALL +The south wall slides away. + +> PRESS WEST WALL +The west wall slides away. + +> AGAIN +The west wall slides away. + +> E +Royal Puzzle + +> E +Royal Puzzle + +> N +Royal Puzzle + +> N +Royal Puzzle + +> N +Royal Puzzle + +> N +Royal Puzzle + +> PRESS EAST WALL +The east wall slides away. + +> W +Royal Puzzle + +> S +Royal Puzzle + +> S +Royal Puzzle + +> S +Royal Puzzle + +> S +Royal Puzzle + +> E +Royal Puzzle + +> E +Royal Puzzle + +> N +Royal Puzzle + +> N +Royal Puzzle + +> N +Royal Puzzle + +> PRESS WEST WALL +The west wall slides away. + +> N +Royal Puzzle + +> W +Royal Puzzle + +> PRESS SOUTH WALL +The south wall slides away. + +> E +Royal Puzzle + +> E +Royal Puzzle + +> S +Royal Puzzle + +> S +Royal Puzzle + +> S +Royal Puzzle + +> W +Royal Puzzle + +> W +Royal Puzzle + +> N +Royal Puzzle + +> PRESS EAST WALL +The east wall slides away. + +> W +Royal Puzzle + +> W +Royal Puzzle + +> W +Royal Puzzle + +> N +Royal Puzzle + +> N +Royal Puzzle + +> W +Royal Puzzle + +> N +Royal Puzzle + +> PRESS EAST WALL +The east wall slides away. + +> AGAIN +The east wall slides away. + +> AGAIN +The east wall slides away. + +> S +Royal Puzzle + +> PRESS SOUTH WALL +The south wall slides away. + +> N +Royal Puzzle + +> E +Royal Puzzle + +> E +Royal Puzzle + +> S +Royal Puzzle + +> PRESS SOUTH WALL +The south wall slides away. + +> W +Royal Puzzle + +> PRESS WEST WALL +The west wall slides away. + +> AGAIN +The west wall slides away. + +> S +Royal Puzzle + +> W +Royal Puzzle + +> PRESS NORTH WALL +The north wall slides away. + +> AGAIN +The north wall slides away. + +> AGAIN +The north wall slides away. + +> W +Royal Puzzle + +> N +Royal Puzzle + +> U +Technology Museum +You have escaped the Royal Puzzle! + +> N +Golden Machine Room + +> W +Narrow Corridor + +> N +Museum Entrance + +> N +South Corridor + +> W +South Corridor + +> W +Old Man's Room + +> N +Engravings Room + +> NE +Old Man's Room + +> N +Narrow Corridor + +> PRESS BUTTON +The mirror rotates and opens, revealing a passage. + +> N +North Corridor + +> N +Mirror Room + +> N +Room of Mirrors + +> RAISE SHORT POLE +You raise the short pole. + +> PRESS WHITE PANEL +The compass needle points to the north. + +> AGAIN +The compass needle points to the south. + +> LOWER SHORT POLE +You lower the short pole. + +> PUSH PINE PANEL +You push the pine panel. + +> N +Narrow Corridor + +> OPEN VIAL +You open the vial. + +> DRINK LIQUID +You drink the liquid. You become invisible. + +> N +Guardians of Zork +You pass unseen between the statues. + +> N +Narrow Corridor + +> N +Narrow Corridor + +> KNOCK ON DOOR +The door opens. The Dungeon Master is standing inside. + +> N +Dungeon Master's Lair + +> E +Dungeon Master's Lair + +> N +South Corridor + +> N +Parapet +The Dungeon Master is with you. + +> READ BOOK +It says that around the Parapet are 8 identical rooms. One has a bronze door leading to the Zorkian treasure chamber. + +> TURN DIAL TO 4 +You turn the dial to 4. + +> PRESS BUTTON +The parapet shifts and transports you. + +> SAY TO DUNGEON MASTER "WAIT" +The Dungeon Master waits. + +> S +Cell +You are in a stone cell. + +> OPEN CELL DOOR +You open the cell door. + +> S +You can see a bronze door nearby. + +> SAY TO DUNGEON MASTER "TURN DIAL TO 8 AND PRESS BUTTON" +The Dungeon Master nods and obeys. The parapet shifts. + +> UNLOCK BRONZE DOOR WITH KEY +The key shapes itself to fit the lock. The bronze door unlocks. + +> OPEN IT +You open the bronze door. + +> S +Treasury of Zork +You are standing in the Treasury of Zork. The Dungeon Master passes his job to you, leaving you as ruler of the Zork empire! + +*** You have won! *** + +End of transcript. diff --git a/infocom/zork3/zork3.z3 b/infocom/zork3/zork3.z3 new file mode 100644 index 0000000..7ea627e Binary files /dev/null and b/infocom/zork3/zork3.z3 differ diff --git a/main.lua b/main.lua index 04d852a..33dcc47 100644 --- a/main.lua +++ b/main.lua @@ -1,17 +1,7 @@ local runtime = require 'zilscript.runtime' local test_format = require 'zilscript.test_format' -local modules = { - "infocom.zork1.globals", - "infocom.zork1.clock", - "infocom.zork1.parser", - "infocom.zork1.verbs", - "infocom.zork1.actions", - "infocom.zork1.syntax", - "infocom.zork1.dungeon", - -- "books.blackwood-horror", - "infocom.zork1.main", -} +local story_module = arg[1] or "infocom.zork1.zork1" -- Create game environment local env = runtime.create_game_env() @@ -23,24 +13,28 @@ end -- Install ZIL support and load modules env.require('zilscript') -if not runtime.load_modules(env, modules, {save_lua = true}) then +if not runtime.load_modules(env, { story_module }, {save_lua = true}) then os.exit(1) end local esc = "\27[" local function highlight(text) - for _, dir in ipairs(env.DESCS) do - local fmt = esc .. "1;32m%s" .. esc .. "0m" - local cap = dir:sub(1,1):upper() .. dir:sub(2) - text = text:gsub("(%f[%a]" .. dir .. "%f[%A])", function(m) return fmt:format(m) end) - text = text:gsub("(%f[%a]" .. cap .. "%f[%A])", function(m) return fmt:format(m) end) + if type(env.DESCS) == "table" then + for _, dir in ipairs(env.DESCS) do + local fmt = esc .. "1;32m%s" .. esc .. "0m" + local cap = dir:sub(1,1):upper() .. dir:sub(2) + text = text:gsub("(%f[%a]" .. dir .. "%f[%A])", function(m) return fmt:format(m) end) + text = text:gsub("(%f[%a]" .. cap .. "%f[%A])", function(m) return fmt:format(m) end) + end end - for _, dir in ipairs(env.DIRS) do - local fmt = esc .. "1;36m%s" .. esc .. "0m" - local cap = dir:sub(1,1):upper() .. dir:sub(2) - text = text:gsub("(%f[%a]" .. dir .. "%f[%A])", function(m) return fmt:format(m) end) - text = text:gsub("(%f[%a]" .. cap .. "%f[%A])", function(m) return fmt:format(m) end) + if type(env.DIRS) == "table" then + for _, dir in ipairs(env.DIRS) do + local fmt = esc .. "1;36m%s" .. esc .. "0m" + local cap = dir:sub(1,1):upper() .. dir:sub(2) + text = text:gsub("(%f[%a]" .. dir .. "%f[%A])", function(m) return fmt:format(m) end) + text = text:gsub("(%f[%a]" .. cap .. "%f[%A])", function(m) return fmt:format(m) end) + end end return text end @@ -80,4 +74,4 @@ until not input or not game:is_running() -- local res = compiler.compile(ast) -- print(parser.view(ast, 0)) --- print(res.body) \ No newline at end of file +-- print(res.body) diff --git a/record-frotz-transcript.lua b/record-frotz-transcript.lua new file mode 100644 index 0000000..648faa8 --- /dev/null +++ b/record-frotz-transcript.lua @@ -0,0 +1,169 @@ +#!/usr/bin/env lua5.4 + +local games = { + zork1 = { + story = "infocom/zork1/zork1.z3", + source = "infocom/zork1/test/zork1.txt", + output = "infocom/zork1/test/zork1-frotz.txt", + }, + zork2 = { + story = "infocom/zork2/zork2.z3", + source = "infocom/zork2/test/zork2.txt", + output = "infocom/zork2/test/zork2-frotz.txt", + }, + zork3 = { + story = "infocom/zork3/zork3.z3", + source = "infocom/zork3/test/zork3.txt", + output = "infocom/zork3/test/zork3-frotz.txt", + }, + planetfall = { + story = "infocom/planetfall/planetfall.z3", + source = "infocom/planetfall/test/planetfall.txt", + output = "infocom/planetfall/test/planetfall-frotz.txt", + }, + spellbreaker = { + story = "infocom/spellbreaker/z6.z3", + source = "infocom/spellbreaker/test/spellbreaker.txt", + output = "infocom/spellbreaker/test/spellbreaker-frotz.txt", + }, + lurkinghorror = { + story = "infocom/lurkinghorror/h1.z3", + source = "infocom/lurkinghorror/test/lurkinghorror.txt", + output = "infocom/lurkinghorror/test/lurkinghorror-frotz.txt", + }, +} + +local script_path = arg[0] or "record-frotz-transcript.lua" +local script_dir = script_path:match("^(.*)/[^/]+$") or "." + +local function trim(text) + return (text:gsub("^%s+", ""):gsub("%s+$", "")) +end + +local function shell_quote(text) + return "'" .. text:gsub("'", "'\\''") .. "'" +end + +local function absolute_path(path) + if path:sub(1, 1) == "/" then + return path + end + if script_dir == "." then + return path + end + return script_dir .. "/" .. path +end + +local function read_commands(path) + local commands = {} + for line in io.lines(path) do + local command = line:match("^>%s*(.*)$") + if command and command ~= "" then + table.insert(commands, trim(command)) + end + end + if #commands == 0 then + error("No commands found in " .. path) + end + return commands +end + +local function write_lines(path, lines) + local file = assert(io.open(path, "w")) + for _, line in ipairs(lines) do + file:write(line, "\n") + end + file:close() +end + +local function copy_file(source, destination) + local input = assert(io.open(source, "rb")) + local output = assert(io.open(destination, "wb")) + output:write(assert(input:read("*a"))) + input:close() + output:close() +end + +local function ensure_parent_dir(path) + local dir = path:match("^(.*)/[^/]+$") + if dir and dir ~= "" then + local ok = os.execute("mkdir -p " .. shell_quote(dir)) + if ok ~= true and ok ~= 0 then + error("Failed to create directory " .. dir) + end + end +end + +local function run_game(game_name) + local spec = assert(games[game_name], "Unknown game: " .. game_name) + local story = absolute_path(spec.story) + local source = absolute_path(spec.source) + local output = absolute_path(spec.output) + local commands = read_commands(source) + + local tmpdir_handle = assert(io.popen("mktemp -d", "r")) + local tmpdir = trim(assert(tmpdir_handle:read("*l"))) + tmpdir_handle:close() + if tmpdir == "" then + error("Failed to create temporary directory") + end + + local cmdfile = tmpdir .. "/commands.txt" + local transcript_base = "session" + local transcript_path = tmpdir .. "/" .. transcript_base .. ".scr" + local log_path = tmpdir .. "/dfrotz.log" + local lines = {"script", transcript_base} + for _, command in ipairs(commands) do + table.insert(lines, command) + end + if trim(commands[#commands]):lower() ~= "unscript" then + table.insert(lines, "unscript") + end + if trim(commands[#commands]):lower() ~= "quit" then + table.insert(lines, "quit") + table.insert(lines, "y") + end + write_lines(cmdfile, lines) + + local command = string.format( + "cd %s && dfrotz -p -m -q %s < %s > %s 2>&1", + shell_quote(tmpdir), + shell_quote(story), + shell_quote(cmdfile), + shell_quote(log_path) + ) + local ok = os.execute(command) + if ok ~= true and ok ~= 0 then + error("dfrotz replay failed for " .. game_name .. "; see " .. log_path) + end + + ensure_parent_dir(output) + copy_file(transcript_path, output) + os.execute("rm -rf " .. shell_quote(tmpdir)) + print(string.format("Recorded %s -> %s", game_name, spec.output)) +end + +local requested = {} +if #arg == 0 then + for name in pairs(games) do + table.insert(requested, name) + end + table.sort(requested) +else + for _, name in ipairs(arg) do + table.insert(requested, name) + end + end + +local failures = {} +for _, game_name in ipairs(requested) do + local ok, err = pcall(run_game, game_name) + if not ok then + print(string.format("FAILED %s: %s", game_name, tostring(err))) + table.insert(failures, game_name) + end +end + +if #failures > 0 then + error("Transcript recording failed for: " .. table.concat(failures, ", ")) +end \ No newline at end of file diff --git a/run-zil-test.lua b/run-zil-test.lua index f727465..7874022 100755 --- a/run-zil-test.lua +++ b/run-zil-test.lua @@ -9,29 +9,52 @@ local NEUTRAL = "\27[36m" local RESET = "\27[0m" local success = true +local TEST_FAILURE_PREFIX = "__ZIL_TEST_FAILURE__:" + +local function breadcrumb_label() + local step = rawget(_G, "TEST_BREADCRUMB_STEP") + local command = rawget(_G, "TEST_BREADCRUMB_COMMAND") + if type(step) == "number" and type(command) == "string" and command ~= "" then + command = command:match("^%s*(.-)%s*$") + return string.format("[step %d] %s", step, command) + end + return nil +end + +local function format_assertion(message) + local breadcrumb = breadcrumb_label() + if breadcrumb then + return breadcrumb .. " => " .. message + end + return message +end + +local function fail_fast(message) + success = false + error(TEST_FAILURE_PREFIX .. (message or "Assertion failed"), 0) +end -- ASSERT that checks condition and prints [PASS] or [FAIL] function ASSERT(msg, ...) for _, condition in ipairs {...} do if condition then - print(GREEN .. "[PASS] " .. (msg or "Assertion passed") .. RESET) + print(GREEN .. "[PASS] " .. format_assertion(msg or "Assertion passed") .. RESET) return true else - success = false - print(RED .. "[FAIL] " .. (msg or "Assertion failed") .. RESET) - return false + print(RED .. "[FAIL] " .. format_assertion(msg or "Assertion failed") .. RESET) + fail_fast(msg) end end end function ASSERT_TEXT(expected, ok, actual) + local label = format_assertion(expected) if ok and actual:lower():find(expected:lower(), 1, true) then - print(GREEN .. "[PASS] " .. expected .. RESET) + print(GREEN .. "[PASS] " .. label .. RESET) return true else - success = false - print(RED .. "[FAIL] " .. expected .. '\n' .. actual .. RESET) - return false + print(RED .. "[FAIL] " .. label .. '\n' .. actual .. RESET) + fail_fast(expected) end end @@ -64,8 +87,21 @@ end print("Running ZIL test: " .. test_module) require(test_module) +if type(CAPTURE_RESTART_STATE) == "function" then + CAPTURE_RESTART_STATE() +end + -- Run the RUN_TEST routine -RUN_TEST() +local ok, err = pcall(RUN_TEST) + +if not ok then + local err_text = tostring(err) + if err_text:find(TEST_FAILURE_PREFIX, 1, true) then + -- Assertion details were already printed at the failure site. + else + error(err, 0) + end +end -- Flush any remaining output io.flush() diff --git a/skills/05_zil_implementation_reference.md b/skills/05_zil_implementation_reference.md index ab2b116..ec9c9d7 100644 --- a/skills/05_zil_implementation_reference.md +++ b/skills/05_zil_implementation_reference.md @@ -26,3 +26,121 @@ Implement game logic in ZIL with clean split between world data and routines. ## Primary Source Coverage - `ZIL_TEXT_ADVENTURE_AGENTS.md`: section 4 - `WRITING_ADVENTURES.md`: Game Structure, ZIL Syntax Reference, Advanced Techniques, Complete Example + +## Critical Implementation Rules + +These rules are derived from real bugs found when running book content through the zilscript engine. Violating them will cause parse errors, broken compilation, or silent failures. + +### 1. Every `<TELL>` must close with `>` before the next form + +The most common and hardest-to-spot bug. When a TELL form does not have a closing `>`, the parser treats everything after it as additional arguments to TELL—including entire COND forms, ROUTINEs, and subsequent top-level declarations. + +**Wrong** (TELL swallows COND): +```zil +<ROUTINE V-LOOK () + <TELL CR "Exits: " ; missing > ! + <COND (<==? ,HERE ,GARDEN> + <TELL "NORTH">) + (T + <TELL "none">)> + <TELL "." CR> + <RTRUE>> +``` + +**Right** (TELL closed before COND): +```zil +<ROUTINE V-LOOK () + <TELL CR "Exits: "> ; closed with > + <COND (<==? ,HERE ,GARDEN> + <TELL "NORTH">) + (T + <TELL "none">)> + <TELL "." CR> + <RTRUE>> +``` + +**Why it breaks**: When the `>` after COND is consumed by TELL (as its closing bracket), the outer ROUTINE never closes. Subsequent ROUTINEs, comments, and object declarations get nested inside the first ROUTINE as children. The compiled Lua then contains mangled code with identifiers like `HELPER`, `ROUTINES`, `===` mixed into function bodies. + +**Detection**: If a ROUTINE in the AST has more than ~5 children, a TELL bracket leak is almost certainly the cause. + +### 2. Define `ROUTINE GO ()` in actions.zil + +The game entry point must exist. Original zork1 defines GO in `dungeon.zil`, but when a book overrides dungeon.zil, the engine only loads the book's version. Put GO in `actions.zil` instead (as blackwood-horror does). + +GO must set up initial state: +```zil +<ROUTINE GO () + <SETG HERE ,STARTING-ROOM> + <SETG LIT T> + <SETG WINNER ,ADVENTURER> + <SETG PLAYER ,WINNER> + <MOVE ,WINNER ,HERE> + ; Optional: clock/daemon setup + ; <QUEUE I-WHISPER 8> + <V-LOOK> + <MAIN-LOOP>> +``` + +**Detection**: Game loads without errors but prints "Failed to start game: GO() not defined or failed." + +### 3. Simplified SYNTAX uses `= ACTION`, not `ACTION` keyword + +The limehouse/blackwood books use a simplified SYNTAX format. Note the differences: + +**Simplified format** (books): +```zil +<SYNTAX EXAMINE OBJECT = V-EXAMINE> +<SYNTAX ASK OBJECT ABOUT TEXT = V-ASK> +``` + +**Infocom format** (zork1/2/3): +```zil +<SYNTAX EXAMINE OBJECT (MANY) = V-EXAMINE> +<SYNTAX ATTACK OBJECT (FIND ACTORBIT) (ON-GROUND IN-ROOM) = V-ATTACK> +``` + +Key rules for the simplified format: +- `= V-ROUTINE` at the end (not `ACTION V?ROUTINE`) +- Modifier keywords like `TEXT` before `=` are supported +- Use hyphenated names: `V-GO-NORTH` (not `V?GO-NORTH`) + +### 4. Bracket balance: every `<` needs a matching `>` + +The parser uses `<...>` as expression boundaries. Common trouble spots: + +- **`>>` at end of forms**: Two consecutive `>` close nested forms. Example: `<RTRUE>>` closes both RTRUE and the outer ROUTINE. +- **`)>` at clause end**: `)` closes a COND clause list, `>` closes COND. Example: `(T <TELL "ok">)>` +- **Nested TELL with COND**: If TELL contains COND as an argument, the first `>` encountered closes COND and the next `>` closes TELL. Make sure the outer form has enough `>` characters. + +### 5. `;` comment lines: first atom after `;` is skipped by the parser + +The zilscript parser's `;` handler calls `parse_form()` once to skip the next form, then returns. Any remaining text on the same line becomes separate top-level atoms in the AST. + +```zil +; === HELPER ROUTINES === +``` + +This produces three top-level Ident nodes: `HELPER`, `ROUTINES`, `===`. The compiler skips Ident nodes (they are not `"expr"` type), so they are harmless at runtime. But they pollute the AST. Keep comments to a single atom or use bare text without special characters. + +### 6. Entry point files: use local paths, engine falls back to infocom/zork1/ + +Each book needs its own entry `.zil` file (like `blackwood-horror.zil`). Use local relative paths—INSERT_FILE first tries relative to the including file, then falls back to `infocom/zork1/` for anything not found locally: + +```zil +;"Substrate (from zork1 automatically)" +<INSERT-FILE "main"> +<INSERT-FILE "clock"> +<INSERT-FILE "parser"> +<INSERT-FILE "syntax"> +<INSERT-FILE "macros"> +<INSERT-FILE "verbs"> +<INSERT-FILE "globals"> + +;"Book-specific overrides (found locally)" +<INSERT-FILE "dungeon"> +<INSERT-FILE "actions"> +``` + +### 7. zork2/zork3 use different file naming conventions + +When referencing substrate files for zork2/zork3, note that they prefix files with `g` (globals → gglobals.zil, main → gmain.zil, clock → gclock.zil, etc.). The `try_open` function handles case-insensitive matching (`GMACROS` → `gmacros.zil`). diff --git a/tests/test_compiler.lua b/tests/test_compiler.lua index 11c7ea2..2c7e69c 100644 --- a/tests/test_compiler.lua +++ b/tests/test_compiler.lua @@ -24,7 +24,7 @@ test.describe("Compiler - Basic Compilation", function(t) local result = compiler.compile(ast) assert.assert_match(result.declarations, "HELLO = function") - assert.assert_match(result.declarations, "error%(1%)") + assert.assert_match(result.declarations, "error%(__res and 'HELLO") end) t.it("should compile routine with parameters", function(assert) diff --git a/tests/test_runtime.lua b/tests/test_runtime.lua index 27f16d8..fde8272 100644 --- a/tests/test_runtime.lua +++ b/tests/test_runtime.lua @@ -95,6 +95,38 @@ test.describe("Runtime - Bootstrap Loading", function(t) -- Bootstrap should define some ZIL runtime functions assert.assert_type(env, "table") end) + + t.it("should expose control opcodes", function(assert) + local env = runtime.create_game_env() + runtime.init(env, true) + + assert.assert_type(env.QUIT, "function") + assert.assert_type(env.RESTART, "function") + assert.assert_type(env.VERIFY, "function") + end) + + t.it("should restore captured scalar state on restart", function(assert) + local env = runtime.create_game_env() + runtime.init(env, true) + + env.TEST_COUNTER = 1 + env.TEST_FLAG = true + env.TEST_NAME = "start" + env.CAPTURE_RESTART_STATE() + + env.TEST_COUNTER = 99 + env.TEST_FLAG = false + env.TEST_NAME = "changed" + env.TEST_NEW_COUNTER = 123 + + local ok, signal = pcall(env.RESTART) + assert.assert_false(ok) + assert.assert_true(env.IS_ZIL_CONTROL_SIGNAL(signal, "restart")) + assert.assert_equal(env.TEST_COUNTER, 1) + assert.assert_equal(env.TEST_FLAG, true) + assert.assert_equal(env.TEST_NAME, "start") + assert.assert_nil(env.TEST_NEW_COUNTER) + end) end) test.describe("Runtime - ZIL File Loading", function(t) @@ -147,6 +179,41 @@ test.describe("Runtime - Game Startup", function(t) assert.assert_equal(env.game_started, true) end) + + t.it("should restart the game loop when RESTART is raised", function(assert) + local env = runtime.create_game_env() + runtime.init(env, true) + + local attempts = 0 + env.CAPTURE_RESTART_STATE() + env.GO = function() + attempts = attempts + 1 + if attempts == 1 then + env.RESTART() + end + coroutine.yield("after restart") + end + + local game = runtime.create_game(env, true) + local response = game:resume() + + assert.assert_equal(response, "after restart") + assert.assert_equal(attempts, 2) + end) + + t.it("should stop cleanly when QUIT is raised", function(assert) + local env = runtime.create_game_env() + runtime.init(env, true) + env.GO = function() + env.QUIT() + end + + local game = runtime.create_game(env, true) + local response = game:resume() + + assert.assert_nil(response) + assert.assert_false(game:is_running()) + end) end) test.describe("Runtime - Options Handling", function(t) diff --git a/tests/test_sourcemap_integration.lua b/tests/test_sourcemap_integration.lua index a6d33e2..def2759 100644 --- a/tests/test_sourcemap_integration.lua +++ b/tests/test_sourcemap_integration.lua @@ -23,7 +23,7 @@ local test_zil = [[ <PRINC "Starting test"> <PRINC "Line 4"> <PRINC "Line 5"> - <+ 1 UNDEFINED-VAR> + <ERROR "test error"> > ]] diff --git a/zilscript/bootstrap.lua b/zilscript/bootstrap.lua index e677ea0..8c81686 100644 --- a/zilscript/bootstrap.lua +++ b/zilscript/bootstrap.lua @@ -29,6 +29,14 @@ P1QVERB=1 P1QADJECTIVE=2 P1QDIRECTION=3 +SH=128 +SC=64 +SIR=32 +SOG=16 +STAKE=8 +SMANY=4 +SHAVE=2 + -- === Register globals === for i, flag in ipairs(ZIL_ObjectFlags) do _G[flag] = i @@ -67,6 +75,11 @@ PRSA = nil PRSO = nil PRSI = nil +local ZIL_CONTROL_SIGNALS = { + quit = {}, + restart = {}, +} + M_FATAL = 2 M_HANDLED = 1 M_NOT_HANDLED = nil @@ -82,6 +95,7 @@ local mem local _obj_count = 0 -- number of declared objects; object IDs are 1.._obj_count local _act_count = 0 -- number of registered actions; action IDs are 1.._act_count local _act_fn_to_id = {} -- build-time reverse-lookup: fn_idx -> action_id +local restart_snapshot local suggestions = { READBIT = "READ", TAKEBIT = "TAKE", @@ -237,7 +251,7 @@ mem = setmetatable({size=0},{__index={ return string.char(table.unpack(bytes)) end, - byte = function(self, idx) return self[idx+1] end, + byte = function(self, idx) return self[idx+1] or 0 end, word = function(self, ptr) return self:byte(ptr)|(self:byte(ptr+1)<<8) end, dword = function(self, ptr) return self:byte(ptr)|(self:byte(ptr+1)<<8)|(self:byte(ptr+2)<<16)|(self:byte(ptr+3)<<24) end, qword = function(self, ptr) return self:byte(ptr)|(self:byte(ptr+1)<<8)|(self:byte(ptr+2)<<16)|(self:byte(ptr+3)<<24)|(self:byte(ptr+4)<<32)|(self:byte(ptr+5)<<40)|(self:byte(ptr+6)<<48)|(self:byte(ptr+7)<<56) end, @@ -370,6 +384,85 @@ local function io_flush() return text end +local function is_control_signal(signal, kind) + if kind then + return signal == ZIL_CONTROL_SIGNALS[kind] + end + return signal == ZIL_CONTROL_SIGNALS.quit or signal == ZIL_CONTROL_SIGNALS.restart +end + +function IS_ZIL_CONTROL_SIGNAL(signal, kind) + return is_control_signal(signal, kind) +end + +local function is_state_global(value) + local value_type = type(value) + return value_type == "number" + or value_type == "boolean" + or value_type == "string" +end + +local function capture_game_state() + local state = { + mem_size = mem.size, + mem_bytes = {}, + globals = {}, + } + + for i = 1, mem.size do + state.mem_bytes[i] = mem[i] + end + for name, value in pairs(_G) do + if is_state_global(value) then + state.globals[name] = value + end + end + + return state +end + +local function restore_game_state(state) + for name, value in pairs(_G) do + if is_state_global(value) and state.globals[name] == nil then + _G[name] = nil + end + end + for name, value in pairs(state.globals) do + _G[name] = value + end + + for i = state.mem_size + 1, mem.size do + mem[i] = nil + end + for i = 1, state.mem_size do + mem[i] = state.mem_bytes[i] + end + mem.size = state.mem_size + output_buffer = {} +end + +function CAPTURE_RESTART_STATE() + restart_snapshot = capture_game_state() + return true +end + +function VERIFY() + return true +end + +function QUIT() + error(ZIL_CONTROL_SIGNALS.quit, 0) +end + +function RESTART() + if not restart_snapshot then + return false + end + + restore_game_state(restart_snapshot) + error(ZIL_CONTROL_SIGNALS.restart, 0) +end + function TELL(...) local object = false for i = 1, select("#", ...) do @@ -398,6 +491,7 @@ end function PRINTI(n) io_write(tostring(n)) return true end function PRINTN(n) io_write(tostring(n)) return true end function PRINTC(ch) io_write(string.char(ch)) return true end +function PRINC(n) io_write(tostring(n)) return true end function CRLF() io_write("\n") return true end function JIGS_UP(msg) @@ -452,7 +546,9 @@ function READ(inbuf, parse) local p = {} for pos, word in s:gmatch("()(%S+)") do - local index = cache.words[word:lower()] or 0 + -- Z-machine truncates dictionary words to 6 characters + local truncated = word:lower():sub(1, 6) + local index = cache.words[truncated] or 0 table.insert(p, makeword(index).. string.char(#word, pos&0xff)) end mem:write(s: lower()..'\0', inbuf+1) @@ -467,13 +563,20 @@ function BOR(a, b) return a | b end function BTST(a, b) return (a & b) == b end -- Arithmetic / comparison -function EQUALQ(a, ...) +function EQUALQ(a, ...) for i = 1, select("#", ...) do - if (a or 0) == (select(i, ...) or 0) then return true end - end - return false + local b = select(i, ...) + if (a or 0) == (b or 0) then return true end + if type(a) == 'number' and type(b) == 'function' then + for n, ff in ipairs(FUNCTIONS) do if b == ff then if a == n then return true end; break end end + elseif type(a) == 'function' and type(b) == 'number' then + for n, ff in ipairs(FUNCTIONS) do if a == ff then if b == n then return true end; break end end + end + end + return false end -function NEQUALQ(a, b) return (a or 0) ~= (b or 0) end +function GASSIGNEDQ(name) return rawget(_G, tostring(name)) ~= nil end +function NEQUALQ(a, b) return not EQUALQ(a, b) end function GQ(a, b) return (a or 0) > (b or 0) end function LQ(a, b) return (a or 0) < (b or 0) end function GEQ(a, b) return (a or 0) >= (b or 0) end @@ -540,26 +643,31 @@ local function learn(word, atom, value) } if not word then return 0 end word = word:lower() + -- Z-machine truncates dictionary words to 6 characters + local word_key = word:sub(1, 6) if type(value) == 'table' then value = register(value, word) end - if cache.words[word] then - local index = cache.words[word] - local ent = mem:read(7, cache.words[word]) + if cache.words[word_key] then + local index = cache.words[word_key] + local ent = mem:read(7, cache.words[word_key]) local new = string.char(0,0,0,0,ent:byte(5)|atom,ent:byte(6),value or OQANY) mem:write(new, index) else local enc = string.char(0,0,0,0,atom|prim[atom],value or OQANY,0) local pos = mem:write(enc) - cache.words[word] = pos - _G['WQ'..upper2(word)] = enc + cache.words[word_key] = pos + _G['WQ'..upper2(word)] = pos end - for _, syn in ipairs(cache.synonyms[word] or {}) do - mem:write(mem:read(8, cache.words[word]), cache.words[syn:lower()]) + for _, syn in ipairs(cache.synonyms[word_key] or {}) do + local syn_key = syn:lower():sub(1, 6) + if cache.words[syn_key] then + mem:write(mem:read(8, cache.words[word_key]), cache.words[syn_key]) + end end -- Special handling for PREPOSITIONS: populate array format immediately if atom == PSQPREPOSITION and value and type(value) == 'number' then - local word_ptr = cache.words[word] - if word_ptr and PREPOSITIONS._hash[word] then + local word_ptr = cache.words[word_key] + if word_ptr and PREPOSITIONS._hash[word_key] then -- Add to array format: [0]=count, [1]=word_ptr1, [2]=index1, [3]=word_ptr2, [4]=index2, ... local count = PREPOSITIONS[0] PREPOSITIONS[count * 2 + 1] = word_ptr @@ -568,7 +676,7 @@ local function learn(word, atom, value) end end - return value or cache.words[word] + return value or cache.words[word_key] end @@ -667,6 +775,16 @@ function DECL_OBJECT() end function OBJECT(object) + local function resolve_global(value) + if type(value) == "string" then + return rawget(_G, value) or value + end + return value + end + local function function_prop(value) + value = resolve_global(value) + return type(value) == 'function' and mem:stringprop(fn(value)) or '\0\0' + end local function makeprop(body, name) local num = register(PROPERTIES, name) if not _G["PQ"..name] then _G["PQ"..name] = num end @@ -709,23 +827,36 @@ function OBJECT(object) table.insert(t, makeprop(makebyte(loc_value), k)) -- using PQACTION for ACTION property, commented out original function support elseif k == "ACTION" or k == "DESCFCN" then - table.insert(t, makeprop(type(v) == 'function' and mem:stringprop(fn(v)) or '\0\0', k)) + table.insert(t, makeprop(function_prop(v), k)) elseif type(v) == 'string' then table.insert(t, makeprop(mem:stringprop(v), k)) elseif type(v) == 'number' then table.insert(t, makeprop(makebyte(v), k)) elseif type(v) == 'function' then table.insert(t, makeprop(mem:stringprop(fn(v)), k)) - elseif _DIRECTIONS[k] then + elseif _DIRECTIONS[k] or (type(v) == "table" and (v.per or v[1] ~= nil)) then + if not _DIRECTIONS[k] then DIRECTIONS(k) end local str - if v.per then - str = makeword(fn(v.per))..string.char(0) -- FEXIT = 3 + if type(v) == 'number' then + -- UEXIT: bare number from compiler (e.g., SOUTH = ROOM_ID) + str = string.char(v) + elseif type(v) == 'string' then + -- NEXIT: bare string from compiler (e.g., OUT = "message") + str = mem:write(v.."\0") + elseif v.per then + local per = resolve_global(v.per) + str = makeword(fn(per))..string.char(0) -- FEXIT = 3 elseif type(v[1]) == 'string' then str = mem:write(v[1].."\0") -- NEXIT = 2 else + if v[1] == nil then + error(string.format("Unresolved exit target for %s.%s", tostring(object.NAME), tostring(k))) + end str = string.char(v[1]) -- UEXIT = 1 local say = v.say and mem:write(v.say.."\0") or 0 - if v.door then - str = str..string.char(v.door)..makeword(say)..string.char(0) -- DEXIT = 5 - elseif v.flag then - str = str..string.char(v.flag)..makeword(say) -- CEXIT = 4 + if v.door ~= nil then + local door = type(v.door) == "boolean" and (v.door and 1 or 0) or v.door + str = str..string.char(door)..makeword(say)..string.char(0) -- DEXIT = 5 + elseif v.flag ~= nil then + local flag = type(v.flag) == "boolean" and (v.flag and 1 or 0) or v.flag + str = str..string.char(flag)..makeword(say) -- CEXIT = 4 end end table.insert(t, makeprop(str, k)) @@ -799,9 +930,7 @@ function GET(s, i) end if not i then return 0 end if type(s) == 'number' then - if not GETB(s,i*2) then print("First argument NULL in GET at",i,": ", debug.traceback()) end - if not GETB(s,i*2+1) then print("Second argument NULL in GET at",i,": ", debug.traceback()) end - return GETB(s,i*2)|(GETB(s,i*2+1)<<8) + return (GETB(s,i*2) or 0)|((GETB(s,i*2+1) or 0)<<8) end assert(type(s) == 'table', "GET requires a table") return i == 0 and #s or s[i] @@ -812,7 +941,7 @@ end function DIRECTIONS(...) for _, dir in ipairs {...} do _DIRECTIONS[dir] = learn(dir, PSQDIRECTION, PROPERTIES) - if dir ~= "IN" and dir ~= "OUT" then + if type(DIRS) == "table" and dir ~= "IN" and dir ~= "OUT" then table.insert(DIRS, dir:lower()) end end @@ -846,6 +975,9 @@ function SYNTAX(syn) PREACTIONS = mem:write(string.rep('\0\0', 256)) end local name = syn.VERB:lower() + if not syn.ACTION then + error(string.format("SYNTAX for verb '%s' is missing ACTION", syn.VERB)) + end local action = action_id(fn(_G[syn.ACTION])) local function encode(s) return string.char( @@ -880,26 +1012,31 @@ end function BUZZ(...) for _, buzz in ipairs {...} do learn(buzz, PSQBUZZ_WORD, nil) - _G['WQ'..buzz:upper()] = cache.words[buzz:lower()] + _G['WQ'..buzz:upper()] = cache.words[buzz:lower():sub(1, 6)] end end function SYNONYM(verb, ...) - verb = verb:lower() + verb = verb:lower():sub(1, 6) cache.synonyms[verb] = {...} for _, syn in ipairs {...} do + -- Truncate to 6 chars (Z-machine dictionary convention) + local syn_key = syn:lower():sub(1, 6) if cache.words[verb] then - cache.words[syn:lower()] = mem:write(mem:read(8, cache.words[verb])) + cache.words[syn_key] = mem:write(mem:read(8, cache.words[verb])) else - cache.words[syn:lower()] = mem:write(string.rep('\0', 8)) + cache.words[syn_key] = mem:write(string.rep('\0', 8)) end - _G['WQ'..syn:upper()] = cache.words[syn:lower()] + _G['WQ'..syn:upper()] = cache.words[syn_key] end end ROOM = OBJECT -function ITABLE(size) +function ITABLE(size, maybe_size) + if size == nil and type(maybe_size) == "number" then + size = maybe_size + end local address = mem:write_word(size) mem:write(string.rep("\0", size)) return address @@ -919,8 +1056,9 @@ function TABLE(...) end function LTABLE(...) + local n = select("#", ...) local tbl = {} - for i = 1, select("#", ...) do + for i = 1, n do local v = select(i, ...) if type(v) == 'string' then table.insert(tbl, makeword(mem:writestring2(v))) elseif type(v) == 'number' then table.insert(tbl, makeword(v)) @@ -928,7 +1066,7 @@ function LTABLE(...) else error("LTABLE: Unsupported type "..type(v)) end end - local address = mem:write_word((#{...})) + local address = mem:write_word(n) mem:write(table.concat(tbl)) return address end @@ -959,13 +1097,29 @@ function OPENABLEQ(OBJ) end function CO_CREATE(func) - local co = coroutine.create(func) + local co = coroutine.create(function(...) + while true do + local ok, result = pcall(func, ...) + if ok then + return result + end + if is_control_signal(result, "restart") then + -- Restart reruns the entry routine from the captured initial state. + elseif is_control_signal(result, "quit") then + return + else + error(result, 0) + end + end + end) coroutine.resume(co) -- Start the coroutine return co end -- if only_flag is true, return only success flag, for chaining of arguments function CO_RESUME(co, param, only_flag) + _G.TEST_BREADCRUMB_STEP = (_G.TEST_BREADCRUMB_STEP or 0) + 1 + _G.TEST_BREADCRUMB_COMMAND = param local ok, err = coroutine.resume(co, param) if only_flag then return ok @@ -974,38 +1128,66 @@ function CO_RESUME(co, param, only_flag) end end +local function dirname(path) + return path and path:match("^(.*)[/\\][^/\\]*$") or nil +end + +local function try_open(path) + local file = io.open(path, "r") + if file then return file, path end + local lower = path:lower() + if lower ~= path then + file = io.open(lower, "r") + if file then return file, lower end + end + return nil, nil +end + -- INSERT_FILE loads and executes a ZIL file -- This is used by INSERT-FILE directive to include other files -function INSERT_FILE(filename) +function INSERT_FILE(filename, source_filename) -- Convert module-style filename (e.g., "zork1.globals") to file path local name_path = filename:gsub("%.", "/") local file, filepath + + local function try_candidate(path) + if not path or path == "" then return nil end + file, filepath = try_open(path) + if file then return true end + if not path:match("%.zil$") then + file, filepath = try_open(path .. ".zil") + if file then return true end + end + return false + end + + local base_dir = dirname(source_filename) + if base_dir and not name_path:match("^/") and try_candidate(base_dir .. "/" .. name_path) then + -- Found relative to including file. + end -- Search for the file using package.zilpath if available - if package and package.zilpath then + if not file and package and package.zilpath then for path_pattern in package.zilpath:gmatch("[^;]+") do - filepath = path_pattern:gsub("?", name_path) - file = io.open(filepath, "r") - if file then + if try_candidate(path_pattern:gsub("?", name_path):gsub("%.zil$", "")) then break end end end -- If not found, try direct path with .zil extension - if not file then - filepath = name_path .. ".zil" - file = io.open(filepath, "r") - end + if not file then try_candidate(name_path) end -- If still not found, try the filename as-is - if not file then - filepath = filename - file = io.open(filepath, "r") + if not file then try_candidate(filename) end + + -- Final fallback: try infocom/zork1/ as substrate + if not file and not name_path:match("infocom/zork[123][/\\]") then + try_candidate("infocom/zork1/" .. name_path) end if not file then - error(string.format("INSERT_FILE: Cannot open file '%s' (tried package.zilpath and direct paths)", filename)) + error(string.format("INSERT_FILE: Cannot open '%s' (resolved to '%s', tried package.zilpath and direct paths)", filename, name_path)) end local content = file:read("*all") @@ -1014,23 +1196,24 @@ function INSERT_FILE(filename) -- Parse and compile the ZIL content local parser = require 'zilscript.parser' local compiler = require 'zilscript.compiler' + local sourcemap = require 'zilscript.sourcemap' - local ok, ast = pcall(parser.parse, content, filename) + local ok, ast = pcall(parser.parse, content, filepath) if not ok then - error(string.format("INSERT_FILE: Failed to parse '%s': %s", filename, ast)) + error(string.format("%s: Failed to parse: %s", filepath, ast)) end - local result = compiler.compile(ast, filename .. ".lua") + local result = compiler.compile(ast, filepath .. ".lua") -- Execute the compiled code in the current environment - local chunk, load_err = load(result.combined, "@" .. filename .. '.zil', "t", _G) + local chunk, load_err = load(result.combined, "@" .. filepath, "t", _G) if not chunk then - error(string.format("INSERT_FILE: Failed to load '%s': %s", filename, load_err)) + error(string.format("%s: Failed to load: %s", filepath, sourcemap.translate(load_err))) end local exec_ok, exec_err = pcall(chunk) if not exec_ok then - error(string.format("INSERT_FILE: Failed to execute '%s': %s", filename, exec_err)) + error(string.format("%s: Failed to execute: %s", filepath, sourcemap.translate(exec_err))) end end diff --git a/zilscript/compiler/forms.lua b/zilscript/compiler/forms.lua index acd944c..a3cb8d7 100644 --- a/zilscript/compiler/forms.lua +++ b/zilscript/compiler/forms.lua @@ -93,10 +93,12 @@ local function compileLogical(buf, node, indent, op, compiler, printNode) if indent == 1 then buf.indent(indent) end buf.write("PASS(") for i = 1, #node do - if utils.isCond(node[i]) then + local cond_node = utils.isCond(node[i]) and node[i] + or (node[i].type == "placeholder" and utils.isCond(node[i][1]) and node[i][1]) + if cond_node then buf.write("APPLY(function() ") - printNode(buf, node[i], indent + 1) - buf.write(" end)") + printNode(buf, cond_node, indent + 1) + buf.write(" return __tmp end)") else printNode(buf, node[i], indent + 1) end @@ -143,6 +145,33 @@ function Forms.createHandlers(compiler, printNode) end form.SETG = form.SET + form.PROB = function(buf, node, indent) + buf.write("ZPROB(") + if node[1] then + printNode(buf, node[1], indent + 1) + else + buf.write("0") + end + buf.write(")") + end + + form.TELL = function(buf, node, indent) + buf.write("TELL(") + for i = 1, #node do + local cond_node = utils.isCond(node[i]) and node[i] + or (node[i].type == "placeholder" and utils.isCond(node[i][1]) and node[i][1]) + if cond_node then + buf.write("APPLY(function() ") + printNode(buf, cond_node, indent + 1) + buf.write(" return __tmp end)") + else + printNode(buf, node[i], indent + 1) + end + if i < #node then buf.write(", ") end + end + buf.write(")") + end + -- LET - Local variable bindings form.LET = function(buf, node, indent) -- LET has form: <LET ((VAR1 INIT1) (VAR2 INIT2) ...) body...> @@ -298,6 +327,11 @@ function Forms.createHandlers(compiler, printNode) i = compiler.printSyntaxObject(buf, node, i, "SUBJECT") end + -- Skip modifier keywords (like TEXT) between JOIN/OBJECT and = + while utils.safeget(node[i], 'value') ~= "OBJECT" and node[i].value ~= "=" and utils.safeget(node[i], 'value') do + i = i + 1 + end + if utils.safeget(node[i], 'value') == "=" then buf.writeln("\tACTION = \"%s\",", compiler.value(node[i + 1])) @@ -320,8 +354,13 @@ function Forms.createHandlers(compiler, printNode) end form.ITABLE = function(buf, node) - local num = node[1].value == "NONE" and node[2].value or node[1].value - buf.write("ITABLE(%s)", num) + buf.write("ITABLE(") + if utils.safeget(node[1], "value") == "NONE" and node[2] then + printNode(buf, node[2], 0) + else + printNode(buf, node[1], 0) + end + buf.write(")") end -- AND/OR @@ -355,9 +394,11 @@ function Forms.createHandlers(compiler, printNode) form["INSERT-FILE"] = function(buf, node, indent) -- Generate INSERT_FILE call with the filename if node[1] and node[1].type == "string" then - buf.write('INSERT_FILE("%s")', node[1].value) + local meta = getmetatable(node) + local source = meta and meta.source and meta.source.filename or "" + buf.write('INSERT_FILE("%s", "%s")', node[1].value, source:gsub("\\", "\\\\"):gsub('"', '\\"')) else - buf.write('INSERT_FILE("")') + buf.write('INSERT_FILE("", "")') end end diff --git a/zilscript/compiler/print_node.lua b/zilscript/compiler/print_node.lua index 4ffabf1..999c8c9 100644 --- a/zilscript/compiler/print_node.lua +++ b/zilscript/compiler/print_node.lua @@ -131,6 +131,10 @@ end function PrintNode.createPrintNode(compiler, form_handlers) local function printNode(buf, node, indent) indent = indent or 0 + if not node then + buf.write("nil") + return true + end -- Track source location for diagnostics and source mapping local meta = getmetatable(node) @@ -141,6 +145,14 @@ function PrintNode.createPrintNode(compiler, form_handlers) if node.type == "expr" then if #node.name == 0 then buf.write("nil") return true end + -- Visitor pattern: check for specialized handler + local handler = form_handlers[node.name] + if handler then + -- Delegate to specialized handler (visitor callback) + handler(buf, node, indent) + return true + end + -- Check if this is a macro call that needs expansion local macro = compiler.macros[node.name] if macro then @@ -152,12 +164,7 @@ function PrintNode.createPrintNode(compiler, form_handlers) end end - -- Visitor pattern: check for specialized handler - local handler = form_handlers[node.name] - if handler then - -- Delegate to specialized handler (visitor callback) - handler(buf, node, indent) - else + do -- Default handler for generic function calls if indent == 1 then buf.indent(indent) end if node.name == 'VERB?' then diff --git a/zilscript/compiler/toplevel.lua b/zilscript/compiler/toplevel.lua index dcf6cbe..137afda 100644 --- a/zilscript/compiler/toplevel.lua +++ b/zilscript/compiler/toplevel.lua @@ -161,7 +161,7 @@ function TopLevel.compileObject(decl, body, node, compiler) fields.writeNav(body, field, compiler) body.writeln(",") elseif field_value == "PER" then - body.writeln("\t%s = { per = %s },", field_name, compiler.value(field[3])) + body.writeln("\t%s = { per = \"%s\" },", field_name, compiler.value(field[3])) else local prop = normalizeProperty(field_name) body.write("\t%s = ", prop) diff --git a/zilscript/compiler/utils.lua b/zilscript/compiler/utils.lua index e20389f..f263f18 100644 --- a/zilscript/compiler/utils.lua +++ b/zilscript/compiler/utils.lua @@ -22,6 +22,7 @@ function Utils.normalizeIdentifier(str) :gsub("^[,.]+", "") -- Remove leading commas/dots :gsub("[,.]", "") -- Remove internal commas/dots :gsub("%-", "_") -- Replace - with _ + :gsub("&", "_") -- Replace & with _ (e.g. GO&LOOK -> GO_LOOK) :gsub("%?", "Q") -- Question mark to Q :gsub("\\", "/") -- Backslash to forward slash end @@ -40,7 +41,7 @@ function Utils.normalizeFunctionName(name) ["0?"] = "ZEROQ", ["1?"] = "ONEQ", } - return OPERATOR_MAP[name] or name:gsub("%-", "_"):gsub("%?", "Q") + return OPERATOR_MAP[name] or name:gsub("%-", "_"):gsub("&", "_"):gsub("%?", "Q") end -- Check if node is a COND expression diff --git a/zilscript/evaluate.lua b/zilscript/evaluate.lua index 86ff33d..fbfb3e7 100644 --- a/zilscript/evaluate.lua +++ b/zilscript/evaluate.lua @@ -1,10 +1,21 @@ -local ZORK_NUMBER = 1 - -- Evaluation for conditional compilation +local compile_time_globals = {} + +local function get_zork_number() + if compile_time_globals.ZORK_NUMBER then + return compile_time_globals.ZORK_NUMBER + end + local ok, val = pcall(function() return _G.ZORK_NUMBER end) + if ok and type(val) == "number" then + return val + end + return 1 +end + local function get_number(node) if not node or node.type ~= "number" then if node and node.type == "symbol" and node.value == ",ZORK-NUMBER" then - return ZORK_NUMBER + return get_zork_number() end return nil end diff --git a/zilscript/parser.lua b/zilscript/parser.lua index f01ed33..333e435 100644 --- a/zilscript/parser.lua +++ b/zilscript/parser.lua @@ -102,6 +102,28 @@ function ZIL.parser(stream_or_string, filename) end return table.concat(chars) end + + local function read_atom() + local chars = {} + while not stream.at_end() do + local ch = stream.peek() + if ch:match("%s") or ch:match("[<>\"();]") then + break + end + if ch == "!" then + table.insert(chars, stream.getchar()) + if stream.peek() == "\\" then + table.insert(chars, stream.getchar()) + end + if not stream.at_end() then + table.insert(chars, stream.getchar()) + end + else + table.insert(chars, stream.getchar()) + end + end + return table.concat(chars) + end local function classify_atom(text, source) if not text or text == "" then return Ident("", source) end @@ -175,6 +197,15 @@ function ZIL.parser(stream_or_string, filename) stream.ungetchar() return nil -- Continue to atom parsing end + + parsers["!"] = function(src) + stream.getchar() + if stream.peek() == "<" or stream.peek() == "(" or stream.peek() == '"' then + return parse_form() + end + stream.ungetchar() + return nil + end -- Angle bracket expressions: <...> parsers["<"] = function(src) @@ -227,11 +258,11 @@ function ZIL.parser(stream_or_string, filename) -- Error on unmatched closing delimiters parsers[">"] = function(src) - error(("Unexpected '>' at line %d"):format(src.line)) + error(("%s:%d: Unexpected '>'"):format(src.file or "?", src.line)) end parsers[")"] = function(src) - error(("Unexpected ')' at line %d"):format(src.line)) + error(("%s:%d: Unexpected ')'"):format(src.file or "?", src.line)) end -- String literals: "..." @@ -270,9 +301,7 @@ function ZIL.parser(stream_or_string, filename) end -- Parse atom (identifier, number, or symbol) - local atom = read_while(function(ch) - return not (ch:match("%s") or ch:match("[<>\"();]")) - end) + local atom = read_atom() return classify_atom(atom, src) end @@ -361,4 +390,4 @@ ZIL.num = Number ZIL.ident = Ident ZIL.string_stream = string_stream -return ZIL \ No newline at end of file +return ZIL diff --git a/zilscript/runtime.lua b/zilscript/runtime.lua index 27c0f87..73d47cf 100644 --- a/zilscript/runtime.lua +++ b/zilscript/runtime.lua @@ -106,7 +106,7 @@ function M.create_env_require(env) env._G = env local chunk, err = load(code, '@'..filepath, 't', env) if not chunk then - error("Error loading module '" .. modname .. "': " .. err) + error("Error loading module '" .. modname .. "': " .. sourcemap.translate(err)) end local ok, result = pcall(chunk) @@ -142,6 +142,9 @@ function M.create_game_env() type = type, string = string, pcall = pcall, + load = load, + rawget = rawget, + rawset = rawset, error = error, assert = assert, debug = debug, @@ -173,7 +176,10 @@ function M.execute(code, name, env, silent) local ok, run_err = pcall(chunk) if not ok then - -- Translate the error traceback to use ZIL source locations + if type(env.IS_ZIL_CONTROL_SIGNAL) == "function" + and env.IS_ZIL_CONTROL_SIGNAL(run_err) then + error(run_err, 0) + end local translated_err = sourcemap.translate(tostring(run_err)) -- if not silent then print("Runtime error: " .. translated_err) @@ -239,6 +245,10 @@ function M.load_zil_files(files, env, options) return false end end + + if type(env.CAPTURE_RESTART_STATE) == "function" then + env.CAPTURE_RESTART_STATE() + end return true end @@ -268,6 +278,10 @@ function M.load_modules(env, modules, options) return false end end + + if type(env.CAPTURE_RESTART_STATE) == "function" then + env.CAPTURE_RESTART_STATE() + end -- REMOVED: FINALIZE_PREPOSITIONS call - prepositions now use pre-allocated array format -- M.execute("if FINALIZE_PREPOSITIONS then FINALIZE_PREPOSITIONS() end", 'finalize', env, options.silent) @@ -282,12 +296,31 @@ function M.create_game(env, silent) -- Start the game by calling GO() -- Returns true on success, false on failure coroutine = coroutine.create(function() - local success = M.execute("GO()", 'main', env, silent) - if not success then + if type(env.GO) ~= "function" then error("Failed to start game: GO() not defined or failed") end - if not silent then - print("\n*** Game has ended ***\n") + + while true do + local ok, result = pcall(env.GO) + if ok then + if not silent then + print("\n*** Game has ended ***\n") + end + return result + end + + if type(env.IS_ZIL_CONTROL_SIGNAL) == "function" + and env.IS_ZIL_CONTROL_SIGNAL(result, "restart") then + -- RESTART restores captured state and re-enters GO(). + elseif type(env.IS_ZIL_CONTROL_SIGNAL) == "function" + and env.IS_ZIL_CONTROL_SIGNAL(result, "quit") then + if not silent then + print("\n*** Game has ended ***\n") + end + return + else + error(tostring(result), 0) + end end end), -- Resume the game coroutine with input diff --git a/zilscript/sourcemap.lua b/zilscript/sourcemap.lua index 805e7cd..dd180c7 100644 --- a/zilscript/sourcemap.lua +++ b/zilscript/sourcemap.lua @@ -57,18 +57,16 @@ function SourceMap.translate(stack) stack = stack:gsub("%[C%]: in function '[^']+'\n?%s*", "") stack = stack:gsub("\t", " ") -- replace tabs with spaces for consistency - -- Pattern to match Lua file references in stack - -- Matches: zil_*.lua files or paths containing zil_*.lua - -- We need to handle tabs/spaces before filenames in stack traces - local result = stack:gsub("([@%s]*)([^%s:]*zil_[^%s:]+%.lua):(%d+):", function(prefix, file, line) - -- Try to find source mapping + -- Pattern to match Lua file references in stack traces. + -- Matches any .lua file reference; looks up the sourcemap to translate + -- back to the original ZIL source location. + -- This handles both zil_*.lua (from load_modules) and <path>.zil.lua (from INSERT_FILE). + local result = stack:gsub("([@%s]*)([^%s:]+%.lua):(%d+):", function(prefix, file, line) local source = SourceMap.get_source(file, tonumber(line)) if source and source.file and source.line then - -- Replace with ZIL source location, preserve prefix (spaces/tabs/@) return prefix .. string.format("%s:%d:", source.file, source.line) else - -- Keep original if no mapping found return prefix .. file .. ":" .. line .. ":" end end)