techbelly/elm-zmachine/1.1.0

ZMachine

A pure Elm Z-Machine interpreter for interactive fiction. Supports version 3 story files fully and version 5 partially — see the package README for the current v5 coverage.

This module is the main entry point for the library. All functions needed to load and run a .z3 or .z5 story file are here. For pattern matching on result types, also import the constructors from ZMachine.Types:

import ZMachine exposing (load, runSteps, provideInput)
import ZMachine.Types exposing (StepResult(..), OutputEvent(..))

Each StepResult variant carries the output events accumulated during the call that produced it, so the host never needs to inspect the machine's output buffer directly.

Types

type alias ZMachine =
ZMachine

The complete state of a running Z-Machine.

type alias StepResult =

Result of executing one or more instructions. See ZMachine.Types.StepResult for the constructors you will pattern match on.

Structured output events for the host to render. See ZMachine.Types.OutputEvent for the full list of constructors.

type alias LineInputInfo =
LineInputInfo

Metadata about a line-input request. Carried by the NeedInput variant of StepResult.

Errors that can halt the machine.

type alias StatusLine =
StatusLine

Status line data including location name, score, and turns.

type alias Window =

Screen window identifier (Upper or Lower).

type alias Snapshot =
Snapshot

Opaque snapshot of machine state. See ZMachine.Snapshot for operations.

Loading

load : Bytes -> Result String ZMachine

Load a .z3 story file from raw bytes and initialize the machine.

case ZMachine.load storyBytes of
    Ok machine ->
        -- ready to run
        ...


    Err err ->
        -- invalid story file
        ...

Running

step : ZMachine -> StepResult

Execute a single instruction. Returns a StepResult indicating whether the machine can continue, needs input, halted, or hit an error.

case ZMachine.step machine of
    Continue nextMachine ->
        ...


    NeedInput request machineWithOutput ->
        ...
runSteps : Int -> ZMachine -> StepResult

Execute up to n instructions, stopping early if input is needed, the machine halts, or an error occurs.

case ZMachine.runSteps 10000 machine of
    Continue nextMachine ->
        -- budget exhausted, call runSteps again to keep going
        ...


    NeedInput request machineWithOutput ->
        -- prompt the player for input
        ...
provideInput : String -> LineInputInfo -> ZMachine -> StepResult

Provide a line of input to a machine that returned NeedInput.

Writes the text into the story's text buffer, tokenizes it, and resumes execution. In V5, also stores the terminating character (13 for newline).

case ZMachine.runSteps 10000 machine of
    NeedInput info _ machineWithOutput ->
        ZMachine.provideInput "open mailbox" info machineWithOutput


    _ ->
        ...
provideChar : String -> ZMachine -> StepResult

Provide a character to a machine that returned NeedChar.

Pass a single-character string — only the first character is used. The ZSCII code is stored as the result of the read_char opcode.

case ZMachine.runSteps 10000 machine of
    NeedChar _ machineWithOutput ->
        ZMachine.provideChar "y" machineWithOutput


    _ ->
        ...

Save and restore

See ZMachine.Snapshot for building custom save schemes. A standard portable Quetzal codec is planned but not yet shipped in this release.

snapshot : ZMachine -> Snapshot

Capture a snapshot of the current machine state. Safe to call any time the host is holding a ZMachine between steps — useful for autosaves or quick-save UIs. The resulting snapshot is tagged ResumeAt, meaning on restore execution picks up at the next instruction.

To persist a snapshot, serialize it with ZMachine.Snapshot.encode. The built-in codec is a native format that round-trips cleanly but isn't cross-interpreter portable; a Quetzal codec for interop is planned.

restoreSnapshot : Snapshot -> ZMachine -> Result RestoreError ZMachine

Rehydrate a running machine from a snapshot. Used to load an autosave at startup (or any time the host wants to swap state outside of a restore opcode).

Fails with a RestoreError if the snapshot is for a different story or its dynamic-memory image is corrupt.

provideSaveResult : Bool -> ZMachine -> StepResult

Resume a machine that returned NeedSave. Pass True if the host successfully persisted the snapshot, False otherwise. The save opcode's branch is evaluated against the result.

case ZMachine.runSteps 10000 machine of
    NeedSave snap m ->
        writeToFile (ZMachine.Snapshot.encode snap)
            |> Task.map (\_ -> ZMachine.provideSaveResult True m)
provideRestoreResult : Maybe Snapshot -> ZMachine -> StepResult

Resume a machine that returned NeedRestore. Pass Just snapshot to rehydrate from the snapshot (the original save opcode's branch is taken as true); pass Nothing to report failure (the restore opcode branches false and execution continues normally). Mismatched-story snapshots are treated as failures.

Story identity

storyRelease : ZMachine -> Int

The story file's release number (header word 0x02).

Combined with storySerial and storyChecksum this uniquely identifies the story file edition — useful for tagging snapshots so a host can reject loading a save against the wrong story.

storySerial : ZMachine -> String

The story file's serial number — six ASCII bytes at header 0x12. Infocom convention is a YYMMDD build date.

storyChecksum : ZMachine -> Int

The story file's checksum (header word 0x1C). Sum of all bytes from 0x40 onward, mod 65536. Returns 0 for early V3 files that predate the checksum field.