NAME

rezrov - a pure Perl Infocom (z-code) game interpreter

SYNOPSIS

rezrov game.dat [flags]

DESCRIPTION

Rezrov is a program that lets you play Infocom game data files. Infocom's data files (e.g. "zork1.dat") are actually platform-independent "z-code" programs written for a virtual machine known as the "z-machine". Rezrov is a z-code interpreter which can run programs written in z-code versions 3 through 5 (nearly complete support) and 8 (limited support).

Rezrov's chief distinguishing feature among z-code interpreters is its cheat commands.

INTERFACES

I/O operations have been abstracted to allow the games to be playable through any of several front-end interfaces. Normally rezrov tries to use the "best" interface depending on the Perl modules available on your system, but you can force the use of any of them manually.

Dumb

Designed to work on almost any perl installation. Optionally uses Term::ReadKey and/or local system commands to guess the terminal size, clear the screen, and read the keyboard. While there is no status line or multiple window support, this interface is perfectly adequate for playing most version 3 games. Can be forced with "-dumb".

Termcap

Makes use of the standard Term::Cap module to provide support for a status line and multiple windows. I've had difficulties making the last line on the display usable while reading from STDIN or Term::ReadLine; it seems the line-terminating newline entered by the user scrolls the screen, wiping out the status line. Maybe there's a simple termcap feature to help with this; advice would be appreciated.

So, by default the termcap interface avoids using the last line on your display. There's an experimental workaround you can try that doesn't seem to work on all systems; enable it by specifying "-flaky 1" on the command line. This will only work if the program can figure out how to read characters one at a time from the terminal, and it also breaks Term::ReadLine support.

Usage of the Termcap interface can be forced with "-termcap".

Curses

Use the Curses module to improve upon the features available in the Termcap interface, adding support for color, clean access to all the lines on the screen, better keyboard handling, and some support for character graphics. Some problems remain: if you specify screen colors, the terminal may not be reset correctly when the program exits. Also, I've only tested this with a few versions of Curses (Linux/ncurses and Digital Unix's OEM curses), and was unpleasantly surprised by the difficulties I encountered getting this to work properly under both of them. Can be forced with "-curses".

Windows console

Uses the Win32::Console module to act much like the Curses version. Only works under win32 (Windows 95, 98, etc). Force with "-win32".

Tk

Uses the Tk module; supports variable-width fonts and color. Requires the 800+ series of Tk; tested under Linux and the ActiveState binary distribution of perl under win32. Force with "-tk".

FEATURES

Advanced command emulation

Rezrov emulates a number of in-game commands which were either not or only sporadically available in version 3 games:

  • undo: undoes your previous turn. This allows you to recover from foolish or irresponsible behavior (walking around in the dark, jumping off cliffs, etc) without a saved game. You can undo multiple turns by repeatedly entering "undo"; the -undo switch can be used to specify the maximum number of turns that may be undone (default is 10).

  • oops: allows you to specify the correct spelling for a word you misspelled on the previous line. For example:

    >give lmap to troll
    I don't know the word "lmap".
    
    >oops lamp
    The troll, who is not overly proud, graciously accepts the
    gift and not having the most discriminating tastes,       
    gleefully eats it.                                        
    You are left in the dark...   
  • notify: has the game tell you when your score goes up or down. This is especially useful when playing without a status line (ie with the "dumb" interface).

  • #reco: Writes a transcript of the commands you enter to the file you specify.

  • #unre: Stops transcripting initiated by the #reco command.

  • #comm: Plays back commands from the transcript file you specify. You can also start a game with recorded commands by specifying the "-playback" command-line option.

Rezrov also expands the following "shortcut" commands for games that do not support them:

x = "examine"
g = "again"
z = "wait"
l = "look"
o = "oops"

Cheating

The "-cheat" command-line parameter enables the interpretation of several fun new verbs. Using these commands in a game you haven't played honestly will most likely ruin the experience for you. However, they can be entertaining to play around with in games you already know well. Note that none of them work if the game understands the word they use; for example, "Zork I" defines "frotz" in its dictionary (alternate verbs are available). You can turn cheating on and off from within the game by entering "#cheat".

  • teleport, #teleport: moves you to any room in the game. For example: "teleport living room". Location names are guessed so they all might not be available; see "rooms" command below. If you specify the name of an item, rezrov will attempt to take you to the room where the item is located.

  • pilfer: moves any item in the game to your current location, and then attempts to move it into your inventory. For example: "pilfer sword". Doesn't work for some objects (for example, the thief from Zork I). Can be dangerous -- for example, pilfering the troll from Zork I can be hazardous to your health.

    Robot Shop
    This room, with exits west and northwest, is filled with
    robot-like devices of every conceivable description, all in
    various states of disassembly.
    Only one robot, about four feet high, looks even remotely
    close to being in working order.
    
    >open robot
    In one of the robot's compartments you find and take a
    magnetic-striped card embossed "Loowur Elavaatur Akses
    Kard."
    
    >turn on robot
    Nothing happens.
    
    >wait
    Time passes...
    
    Suddenly, the robot comes to life and its head starts
    swivelling about. It notices you and bounds over. "Hi! I'm
    B-19-7, but to everyperson I'm called Floyd. Are you a
    doctor-person or a planner-person? That's a nice lower
    elevator access card you are having there. Let's play
    Hider-and-Seeker you with me."
    
    >show access card to floyd
    "I've got one just like that!" says Floyd. He looks
    through several of his compartments, then glances at you
    suspiciously.
    
                                        - "Planetfall", 1983

    I'd be very curious to know about any easter eggs this command might uncover. For example, in Planetfall there is a blacked-out room you can't see anything in. There's a lamp in the game, but it's located in a lab full of deadly radiation. You can enter the lab and take the lamp, but will die of radiation poisoning before you can make it back to the darkened room.

    I always wondered, if you could get the lamp somehow, what was in the dark room? Now you can find out.

  • bamf: makes the object you specify disappear from the game. For example: "bamf troll". This works nicely for some objects but less so for others. For example, in Zork I the troll disappears obligingly, but the bamf'ing the cyclops doesn't help.

  • frotz, futz, lumen: attempts to emulate the "frotz" spell from Enchanter, which means "cause something to give off light." It can turn any item into a light source, thus obviating the need to worry about your lamp/torch running out while you wander around in the dark. I would have liked to just use the word "frotz"; unfortunately Zorks I-III define that word in their dictionaries (interesting, as these games predate Enchanter), and I am reluctant to interfere with its "original" use in those games (if any?).

    While this is just a simple tweak, turning on a particular object property, exactly *which* property varies by game and I know of no easy way to determine this dynamically, so at present this only works in a few games: Zork I, Zork II, Zork III, Zork: The Undiscovered Underground, Infidel, and Planetfall (I'm taking requests).

  • tail: follow a character in the game -- as they move from room to room, so do you. Also allows you to follow characters where you ordinarily aren't allowed to, for example the unlucky Veronica from "Suspect".

  • travis: attempts to fool the game into thinking the object you specify is a weapon. Like "frotz" this is very game-specific; it only works in Zork I at present:

    >i
    You are carrying:                        
      A brass lantern (providing light)
      A leaflet
    
    >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.
    
    >kill troll with leaflet                         
    Trying to attack the troll with a leaflet is suicidal.
    
    >travis leaflet
    The leaflet glows wickedly.                             
    
    >kill troll
    (with the leaflet)                                         
    Your leaflet misses the troll by an inch.                               
    The axe crashes against the rock, throwing sparks!
    
    >g
    You charge, but the troll jumps nimbly aside.
    The troll's axe barely misses your ear.
    
    >g
    It's curtains for the troll as your leaflet removes his head.
    Almost as soon as the troll breathes his last breath, a
    cloud of sinister black fog envelops him, and when the fog
    lifts, the carcass has disappeared.
    
    >
  • lummox: Removes all practical limitations on the weight and total number of items you can carry. Very game-specific; only works in Zorks I-III and Planetfall for now.

  • systolic: Lowers your blood pressure in the game "Bureaucracy". In "Bureaucracy," using a word unknown to the game or entering an empty line bumps up your character's blood pressure. A few such missteps and you drop dead of a stroke. Bureaucracy is too effective by half; this "feature" alone irritated me so much I never got far in the game. This cheat should make the game a little more bearable to play.

  • lingo: prints out all the words in the dictionary.

  • spiel: attempts to decode all the text in the game by brute force. This basically walks through every memory location in the game and tries to decode it as if it were encoded z-characters. There are a lot of hacks here to attempt to filter out junky text. I put this in to try and uncover easter eggs or funny things in games that I'd never run into while playing. For example, here's a little tidbit from Zork I that I'd never seen before, probably a message for an "impossible" case that you were never supposed to encounter:

    It takes a talented person to be killed while already dead. YOU are
    such a talent. Unfortunately, it takes a talented person to deal
    with it. I am not such a talent. Sorry.

    spiel takes up to 3 arguments, all optional. The first argument is the memory address to start decoding text. The default is the start of static memory, which is often a bit early. 20000 is usually a good starting point for version 3 games. The second argument is the level of detail to show. This is a number from 1 to 4:

    1: Unconditionally show whatever's decoded from each possible address.

    2: Like 1, but if a chunk of text is decoded that passes the various junk filters, continues decoding after it rather than at the next byte. Still shows "bad" text.

    3: don't show text I suspect is junky. Subjective but pretty effective.

    4: only show text we're highly confident of. This is the default setting.

    The third argument is the minimum number of decoded words that must be present in a fragment to consider it good under most circumstances. Defaults to 3.

  • rooms: print a list of rooms/locations in the game. This is a rough guess based on descriptions taken from the game's object table, and so may contain a few mistakes.

  • items: print a list of items in the game. Like "rooms", this is a rough guess based on descriptions taken from the game's object table.

  • omap: prints a report of the objects in the game, indented by parent-child relationship.

  • embezzle: sets your score in version 3 games to the value you specify. Useful for "finishing" games in a hurry. You could use this to quickly see the effects of the Tandy bit on the ending of Zork I, for example.

Snooping

Several command-line flags allow you to observe some of the internal machinations of your game as it is running. These options will probably be of limited interest to most people, but may be the foundation of future trickery.

-snoop-obj

Whenever an object in the game is moved, it tells you the name of the object and where it was moved to. Using this feature you can, among other things, see the name Infocom assigned to the "player" object in a number of their early games:

West of House
There is a small mailbox here.

>north
[Move "cretin" to "North of House"]
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.
-snoop-properties

Each object in the game has a list of properties associated with it. This flag lets you see when object properties are changed. As an example, in my version of Zork 1 the "blue glow" given off by the sword in the presence of enemies is property number 12 (1 for "a faint blue glow" and 2 for "glowing very brightly").

-snoop-attr-set

Likewise, each object has an associated list of single-bit attributes. This flag lets you observe when object attributes are set. As an example, in my version of Zork I the "providing light" attribute is number 20. Tweaking of this attribute is the foundation of "frotz" emulation (see "Cheating" below).

-snoop-attr-test

This option lets you see when object attributes are tested.

-snoop-attr-clear

This option lets you see when object attributes are cleared.

-highlight-objects

Highlights object descriptions in the text printed out via the print_obj opcode (1OP, 0x0a).

Interface flags

-fg, -bg

If the interface you want to use supports colored text, this allows you to specify foreground (text) and background colors used in the game. If you specify one you must specify the other, i.e. you cannot specify just the foreground or background color. Example: "-fg white -bg blue".

When using the Curses interface, allowable colors are black, blue, cyan, green, magenta, red, white, and yellow.

When using the Win32::Console interface, allowable colors are black, blue, lightblue, red, lightred, green, lightgreen, magenta, lightmagenta, cyan, lightcyan, brown, yellow, gray, and white. Note that the program tries to shift to lighter colors to simulate "bold" text attributes: bold blue text uses lightblue, bold gray text uses white, etc. For this reason it looks best if you not use white or any of the "light" colors directly (for "white" text, specify "gray").

-sfg, -sbg

Specifies the foreground and background colors use for the status line in version 3 games; the same restrictions apply as to -fg and -bg. These must also be used as a pair, and -fg and -bg must be specified as well. Example: "-fg white -bg blue -sbg black -sfg white".

-cc

Specifies the color of the cursor. At present this only works for the Tk interface, and defaults to black. Note that if the game changes the screen's background color to the cursor color, the cursor color will be changed to the foreground color to prevent it from "disappearing". This happens in "photopia", for example.

-columns, -rows

Allows you to manually specify the number of columns and/or lines in your display.

-max-scroll

Updates the screen with every line printed, so scrolling is always visible. As this disables any screen buffering provided by the I/O interface it will slow things down a bit, but some people might like the visual effect.

Tk-specific flags

-family [name]

Specifies the font family to use for variable-width fonts. Under win32, this defaults to "Times New Roman". On other platforms defaults to "times".

-fontsize [points]

Specifies the size of the font to use, as described in Tk::Font. Under win32 this defaults to 10, on other platforms it defaults to 18. If your fonts have a "jagged" appearance under X you should probably experiment with this value; for best results this should match a native font point size on your system. You might also try using the "xfstt" TrueType font server, which I've had very good results with under Linux.

Specifies the blink rate of the cursor, in milliseconds. The default is 1000 (one second). To disable blinking entirely, specify a value of 0 (zero).

-x [pixels]

Specifies the width of the text canvas, in pixels. The default is 70% of the screen's width.

-y [pixels]

Specifies the height of the text canvas, in pixels. The default is 60% of the screen's height.

Term::ReadLine support

If you have the Term::ReadLine module installed, support for it is available in the dumb, termcap, and curses interfaces. By default support is enabled in the "dumb" module, and disabled in the termcap and curses interfaces (because it doesn't work right :P ). You can enable/disable support for it with the "-readline" flag: "-readline 1" enables support, and "-readline 0" disables it.

Miscellaneous flags

-24h

Displays the game time in "time" games (Deadline, Suspect, etc) in 24-hour format rather than 12-hour AM/PM format.

-no-graphics

Disables usage of the "font 3" character graphics font. Generally only has meaning in Beyond Zork when using the Tk or Curses interfaces. Font 3 support is incomplete so you'll probably need this if you're playing Beyond Zork for any length of time.

-debug [file]

Writes a log of the opcodes being executed and their arguments. If a filename is specified, the log is written to that file, otherwise it is sent to STDERR.

-count-opcodes

Prints a count and summary of the opcodes executed by the game between your commands.

-undo turns

Specifies the number of turns that can be undone when emulating the "undo" command; the default is 10 turns.

Undo emulation works by creating a temporary saved game in memory between every command you enter. To disable undo emulation entirely, specify a value of zero (0).

-playback file

When the game starts, reads commands from the file specified instead of the keyboard. Control is returned to the keyboard when there are no more commands left in the file.

-no-title

Disables rezrov's attempts to guess the name of the game you're playing for use in the title bar. To guess the title, rezrov actually hijacks the interpreter before your first command, submitting a "version" command and parsing the game's output. This can slow the start of your game by a second or so, which is why you might want to turn it off. This also currently causes problems with the Infocom Sampler (sampler1_R55.z3) and Beyond Zork.

-id

Specifies the ID number used by the interpreter to identify itself to the game. These are the machine ID numbers from section 11.1.3 of Graham Nelson's z-machine specification (see acknowledgments section):

1   DECSystem-20     5   Atari ST           9   Apple IIc
2   Apple IIe        6   IBM PC            10   Apple IIgs
3   Macintosh        7   Commodore 128     11   Tandy Color
4   Amiga            8   Commodore 64

The default is 6, IBM PC. This only seems to affect gameplay for a few games, notably "Beyond Zork".

GOALS

My primary goal has been to write a z-code interpreter in Perl which is competent enough to play my favorite old Infocom games, which are mostly z-code version 3. Infocom's version 3 games are Ballyhoo, Cutthroats, Deadline, Enchanter, The Hitchhiker's Guide To The Galaxy, Hollywood Hijinx, Infidel, Leather Goddesses of Phobos, The Lurking Horror, Moonmist, Planetfall, Plundered Hearts, Seastalker, Sorcerer, Spellbreaker, Starcross, Stationfall, Suspect, Suspended, Wishbringer, The Witness, and Zork I, II, and III. These all seem to work pretty well under the current interpreter.

Version 4 and later games introduce more complex screen handling and difficult-to-keep-portable features such as timed input. Later games also introduce a dramatic increase in the number of opcodes executed between commands, making a practical implementation more problematic. For example, consider the number of opcodes executed by the interpreter to process a single "look" command:

                            Zork 1 (version 3):  387 opcodes
                           Trinity (version 4):  905 opcodes
Zork: The Undiscovered Underground (version 5): 2186 opcodes (!)

While rezrov can run most of these games, if you seriously want to *play* them I recommend you use an interpreter written in C, such as frotz or zip; these are much faster and more accurate than rezrov.

A secondary goal has been to produce a relatively clean, compartmentalized implementation of the z-machine that can be read along with the Specification (see acknowledgments section). Though the operations of the interpreter are broken into logical packages, performance considerations have kept me from strict OOP; more static data remains than is Pretty. The core StoryFile.pm package, formerly quasi-OO, has been flattened to plain functional style in a crass attempt to make the program run faster. The Perl version is actually based on my original version of rezrov, which was written in Java.

ACKNOWLEDGMENTS

rezrov would not have been possible to write without the work of the following individuals:

  • Graham Nelson for his amazing z-machine specification:

    http://www.gnelson.demon.co.uk/zspec/
  • Marnix Klooster for "The Z-Machine, and How to Emulate It", a critical second point of view on the spec:

    ftp://ftp.gmd.de/if-archive/infocom/interpreters/specification/zmach06e.txt
  • Mark Howell for his "zip" interpreter, whose source code made debugging all my stupid mistakes possible:

    ftp://ftp.gmd.de/if-archive/infocom/interpreters/zip
  • Martin Frost for his Quetzal universal save-game file format, which is implemented by rezrov:

    ftp://ftp.gmd.de/if-archive/infocom/interpreters/specification/savefile_14.txt
  • Andrew Plotkin for "TerpEtude" (etude.z5), his suite of z-machine torture tests.

  • Torbjorn Andersson for his "strictz.z5", a suite of torture tests for the (nonexistent) object 0.

  • The folks at the IF-archive for their repository:

    ftp://ftp.gmd.de/if-archive/README
  • William Seltzer for Curses.pm, "sanders@bsdi.com" for Term::Cap, Aldo Calpini for Win32::Console, and of course Larry Wall and the perl development team for Perl.

  • And lastly, the mighty Implementers:

    >read dusty book
    The first page of the book was the table of contents. Only
    two chapter names can be read: The Legend of the Unseen   
    Terror and The Legend of the Great Implementers.          
    
    >read legend of the implementers
    This legend, written in an ancient tongue, speaks of the
    creation of the world. A more absurd account can hardly be
    imagined. The universe, it seems, was created by          
    "Implementers" who directed the running of great engines. 
    These engines produced this world and others, strange and 
    wondrous, as a test or puzzle for others of their kind. It
    goes on to state that these beings stand ready to aid those
    entrapped within their creation. The great                 
    magician-philosopher Helfax notes that a creation of this  
    kind is morally and logically indefensible and discards the
    theory as "colossal claptrap and kludgery."                
    
                                         - "Enchanter", 1983

BUGS

Bug? Not in a flawless program like this! (Cough, cough).
                                   - Zork I

While I've tried, the interpreter is not fully compliant with the specification in some areas. With that said, I currently know of no flaws that prevent version 3 games from being perfectly playable. Version 4 games (A Mind Forever Voyaging, Bureaucracy, Nord and Bert Couldn't Make Head or Tail of It, and Trinity) I'm less sure about, this complicated by the fact that I haven't completed any of them :) Version 5 games (Beyond Zork, Border Zone, Sherlock) seem to work to the limited extent I've played them, but there are a few unimplemented opcodes that I have yet to see used. The only version 8 game I've tried has been "anchorhead", which runs, but is unbearably slow on my P133. YMMV.

HELP WANTED

Things I need:

  • Any examples of bugs or crashes.

  • Any suggestions to improve execution speed.

  • A saved game from Seastalker before the sonar scope is used. This is (I think) the only example of a version 3 game splitting the screen, and I'd like to test it (I know it won't work correctly now).

  • Command transcripts/walkthroughs for version 4 games, for testing purposes. On second thought, I should really play Trinity first.

  • Feedback and suggestions for spiffy new features.

  • Advice about termcap behavior and scrolling; see the Termcap description at the top of this document.

REZROV?

>up
Jewel Room
This fabulous room commands a magnificent view of the Lonely
Mountain which lies to the north and west. The room itself is
filled with beautiful chests and cabinets which once contained
precious jewels and other objets d'art. These are empty.
Winding stone stairs lead down to the base of the tower.
There is an ornamented egg here, both beautiful and complex. It
is carefully crafted and bears further examination.

>get egg then examine it     
Taken.

This ornamented egg is both beautiful and complex. The egg
itself is mother-of-pearl, but decorated with delicate gold
traceries inlaid with jewels and other precious metals. On the
surface are a lapis handle, an emerald knob, a silver slide, a
golden crank, and a diamond-studded button carefully and
unobtrusively imbedded in the decorations. These various
protuberances are likely to be connected with some machinery
inside.
The beautiful, ornamented egg is closed.

>read spell book

My Spell Book

The rezrov spell (open even locked or enchanted objects).
The blorb spell (safely protect a small object as though in a
strong box).
The nitfol spell (converse with the beasts in their own
tongue).
The frotz spell (cause something to give off light).
The gnusto spell (write a magic spell into a spell book).

>learn rezrov then rezrov egg 
Using your best study habits, you learn the rezrov spell.

The egg seems to come to life and each piece slides
effortlessly in the correct pattern. The egg opens, revealing a
shredded scroll inside, nestled among a profusion of shredders,
knives, and other sharp instruments, cunningly connected to the
knobs, buttons, etc. on the outside.

                                     - "Enchanter", 1983

AUTHOR

Michael Edmonson <edmonson@poboxes.com>

Rezrov homepage: http://www.voicenet.com/~mikeedmo/rezrov/

1 POD Error

The following errors were encountered while parsing the POD:

Around line 953:

You forgot a '=back' before '=head1'