zmachine game compatibility plan ================================= goal: round out the hybrid z-machine interpreter by testing against a variety of freely available IF games. find what breaks, fix it, build confidence that the interpreter handles the spec correctly rather than just the two games we built it against. background ---------- the interpreter was shaped by tracing two specific games: - Zork 1 (V3, 69 opcodes) — the Infocom classic - Lost Pig (V8/V5, 61 opcodes) — modern Inform, 101K instructions this means the implementation is biased toward what those two games exercise. other games will hit different opcode combinations, edge cases in string encoding, parser behaviors, object tree structures, and screen model usage. version coverage ~~~~~~~~~~~~~~~~ V3, V5, and V8 cover essentially everything worth playing: - V3: the Infocom catalog (Zork, Hitchhiker's, Planetfall, etc) - V5: most modern Inform-compiled games (Photopia, Curses, Spider and Web) - V8: V5 with x8 packed addresses (Lost Pig, some larger Inform games) versions we are NOT targeting: - V1/V2: original mainframe Zork only. almost nothing uses these. - V4: tiny transitional version. Trinity is the notable game. maybe 5 games total ever published. if a V4 game trips a bug we'll fix it (the version gates already include V4 in the 4-5 range) but we're not seeking them out. - V6: graphical z-machine. mouse, pictures, complex screen model. only a handful of late Infocom titles (Zork Zero, Shogun, Arthur, Journey). out of scope — the MUD is text. - V7: almost nonexistent. maybe 1-2 games ever. not worth thinking about. known stub opcodes ~~~~~~~~~~~~~~~~~~ the dispatch table is complete for V3/V5/V8, but ~12 opcodes have "TODO" docstrings — they're registered but may not work correctly:: op_set_colour — color setting (can likely remain a no-op for MUD) op_throw — throw to catch frame (needs real implementation) op_print_ret — print embedded string + newline + return true op_save_v4 — V4 save (store result, not branch) op_restore_v4 — V4 restore (store result, not branch) op_piracy — always branch true (standard behavior, stub is fine) op_sread_v4 — V4 input (like V3 sread but with timing) op_erase_line — erase current line (display op, can be no-op) op_get_cursor — get cursor position (display op, needs stub) op_not_v5 — bitwise NOT, VAR form (should be trivial) op_encode_text — encode ZSCII to dictionary format op_print_table — formatted table output some of these are fine as no-ops (color, erase_line). others need real implementations if games use them (throw, print_ret, encode_text). phase 1 — acquire games ------------------------ download freely available z-machine games from the IF Archive (https://ifarchive.org). all games below are free to distribute. priority targets (well-known, diverse, good coverage): V3 games:: Hitchhiker's Guide to the Galaxy — Infocom, nasty parser edge cases NOTE: check if freely available. Infocom titles are abandonware but not legally free. skip if we can't get a legit copy. V5 games:: Curses — Graham Nelson, 1993. first Inform game. large, exercises many opcodes. freely available. Photopia — Adam Cadre, 1998. minimal puzzles, narrative heavy, lots of text output. free. Spider and Web — Andrew Plotkin, 1998. notoriously clever parser tricks, unreliable narrator mechanic. free. Shade — Andrew Plotkin, 2000. small, atmospheric, good smoke test. free. Anchorhead — Michael Gentry, 1998. horror, larger game, heavy object manipulation. original z-machine version is free (later Inform 7 version is commercial — use the original). Bronze — Emily Short, 2006. tutorial-style, good for testing standard patterns. free. Counterfeit Monkey — Emily Short, 2012. complex, large, exercises advanced Inform features. free. V8 games:: (Lost Pig already working — look for other V8 titles on IF Archive to broaden coverage if any exist) also worth checking: games compiled with different Inform versions (Inform 5, 6, 7-to-Z) to catch compiler-specific patterns. the agent doing this work should: 1. find each game on ifarchive.org or the author's site 2. download the story file (.z3, .z5, .z8) 3. verify the z-machine version byte (byte 0 of story file) 4. place in content/stories/ with a note about source/license phase 2 — smoke test each game ------------------------------- for each acquired game, run it through the interpreter and record results. use the existing trace infrastructure:: scripts/trace_zmachine.py — V3 opcode tracing scripts/trace_lostpig.py — V5/V8 opcode tracing for each game: 1. run the trace script (or adapt it for the game) 2. record: how many instructions execute, which opcodes are used, where it crashes (if it crashes) 3. try interactive play for at least 10-15 commands 4. categorize the result: - WORKS: plays correctly, no crashes - CRASHES: hits an unimplemented or buggy opcode (record which one) - MISBEHAVES: runs but output is wrong (garbled text, wrong responses, display issues) - BLOCKS ON INPUT: hangs or mishandles input in some way build a results table like:: game | version | result | notes ------------------|---------|------------|--------------------------- Curses | V5 | CRASHES | op_encode_text at 0x1234 Photopia | V5 | WORKS | 45K instructions to prompt Spider and Web | V5 | MISBEHAVES | status line garbled ... phase 3 — fix failures ----------------------- group failures by type and fix them: missing/stub opcodes ~~~~~~~~~~~~~~~~~~~~ for each "TODO" opcode that a real game exercises: 1. read the z-machine spec (``zmach06e.pdf`` or inform-fiction.org/zmachine) 2. implement per spec 3. add a unit test 4. verify the game that triggered it now works spec compliance bugs ~~~~~~~~~~~~~~~~~~~~ for opcodes that are implemented but behave wrong: 1. compare our implementation against the spec 2. check edge cases (signed vs unsigned, overflow, zero-length strings) 3. fix and add regression test display/screen model issues ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ V5+ games use the screen model more aggressively than Zork or Lost Pig: - window splitting, cursor positioning, text styles - status line formatting - output stream selection (stream 3 = memory table) these may need MudScreen improvements. the MUD doesn't need pixel-perfect screen emulation but it needs to not crash and should produce readable output. string encoding edge cases ~~~~~~~~~~~~~~~~~~~~~~~~~~ different games exercise different parts of ZSCII: - alphabet table switching (A0/A1/A2) - abbreviations (V3 has 32, V5+ has 96) - unicode extensions - custom alphabet tables (some games define their own) phase 4 — regression harness ----------------------------- once games are working, build automated smoke tests: - for each game, a script that feeds N commands and checks for crashes - run as part of ``just check`` or a separate ``just smoke`` target - catches regressions when we change the interpreter the test doesn't need to verify game output is correct — just that the interpreter doesn't crash, produces output, and reaches the input prompt. something like:: @pytest.mark.parametrize("game,commands", [ ("zork1.z3", ["look", "open mailbox", "read leaflet"]), ("curses.z5", ["look", "inventory", "north"]), ("photopia.z5", ["look", "yes"]), ]) def test_game_smoke(game, commands): """Run game through interpreter, feed commands, verify no crash.""" ... success criteria ---------------- - 5+ freely available games beyond Zork 1 and Lost Pig run without crashes - all "TODO" stub opcodes that real games exercise have real implementations - automated smoke tests prevent regressions - the interpreter handles V3 and V5/V8 games from different compilers non-goals --------- - pixel-perfect screen emulation (we're a text MUD) - V6 graphical games - V1/V2 support - multiplayer z-machine (separate effort, see mojozork-audit.rst) - perfect Infocom compatibility (we care about freely available games first) related documents ----------------- - ``docs/how/if-journey.rst`` — integration vision and roadmap - ``docs/how/mojozork-audit.rst`` — multiplayer z-machine audit - ``docs/how/zmachine-performance.rst`` — performance profiling and optimization - ``scripts/trace_zmachine.py`` — V3 opcode tracing - ``scripts/trace_lostpig.py`` — V5/V8 opcode tracing