techbelly/elm-zmachine/1.0.0

NOTE: the latest version is 1.1.0

ZMachine

A pure Elm Z-Machine version 3 interpreter for interactive fiction.

This module is the main entry point for the library. All functions needed to load and run a .z3 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 and ZMachine.Quetzal for the standard portable format.

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.

For the standard portable save-file format, serialize with ZMachine.Snapshot.encode (native) — or note that ZMachine.Quetzal.encode rejects ResumeAt snapshots because Quetzal has no way to represent resuming at an arbitrary instruction boundary.

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.Quetzal.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.