Sunday, February 17, 2019

Chapter 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 fixed 64 bytes at the start of every Infocom game that provides information regarding the location of specific data and code. The header for ZIP 1 games used the first 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 specific types of data. Details are in Appendix A. The first word, ZVERSION, ensures that the ZIP is compatible with the given story file and emulates the proper Z-machine version. The version number is located in the first byte. The second byte has the mode flags 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 first operation to be executed by the ZIP. It points to the first 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 buffer. GLOBALS points to the table holding the global variables data.

ZIP 1 Story Header:

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 first 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
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 files is fairly consistent between games. An example using Zork 1 is shown below. The “memory” of the emulated Z-machine is first loaded with the header information starting at $0000. Memory from $0000 up to PURBOT encompasses the writeable memory such as variables, objects, tables, and buffers. 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 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 first data after the story header. Storing them in a logical and efficient 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 fire (FLAMEBIT). They are numbered 0 to 31. Each object will define 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.
  • Default Property Table:
    • 31 words that are the default property values if it is not explicit set for a specific 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:



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 specifically stored here but calculated based upon the number of object entries. It can also be calculated by the difference between the addresses of the first object entry and first 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 buffers. 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 Buffers

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 buffers. Tables are a fixed set of words where the first word (element 0) contains the number of elements in the table. Examples include tables to hold the direct or indirect object numbers. A buffer is just a fixed set of bytes used to hold any type of data. The most common buffers used in Infocom games are the input buffer (INBUF) or token buffer (LEXV). These data structures are not standard to ZIL and are specific 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 routines. The addresses to these buffers and tables are usually stored in specific 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 buffers and tables. Infocom games have their own custom ZIL routines for reading and writing to these structures.

2 comments:

  1. Looks like an image is missing here: the object property table.

    ReplyDelete
  2. Which document you reference, when you mention Appendices A, B and C?

    ReplyDelete