ZZT Format
Contents |
Credits
A large portion of this information was gathered from documents written by Kev Vance (original ZZT format documentation), David Hammond (Mystical Winds Encyclopedia), and WiL (SuperZZT format documentation). A few errors have been corrected and the information has been tested in an attempt to create the most comprehensive document of both the ZZT and Super ZZT formats.
General Information
A world file (.ZZT, .SZT) contains information about a game world, status of the player, and all its boards. Saved games (.SAV) are the same format as world files with a different extension and a different setting for the Lock byte.
While there are built-in editors for these games, they do not provide full editing functionality.
Limits
ZZT and Super ZZT have limits imposed either by the game itself or by the data types used to store information about the world's contents.
| Limitation | ZZT | Super ZZT |
|---|---|---|
| Board count (including title screen) | 101 | 33 |
| Board size (in bytes) | 32767 | 32767 |
| Board size (in tiles) | 60x25 | 96x80 |
| Status Elements per board (including Player) | 151 | 129 |
| Flag strings | 10 | 16 |
Realistically, the original ZZT can only support boards up to around 20k due to the code itself. ZZT 4.0 by WiL, a hack of the original game executable, can support the full 32k.
World Format
There are two formats for a world file. One is for ZZT and the other is for SuperZZT. The formats are very similar. All 8-bit (byte) values are unsigned. All 16-bit (short) values are signed. Boolean values (such as a player's keys) are represented with 0 for false and 1 for true; any other values may cause inconsistent behavior.
World Name is used by the game to determine which file to load after the player quits and restarts the game. Therefore if a world contains a world name that is actually the filename of another world, after the player quits and restarts the game, the world with the matching filename will be loaded!
Common world information
The storage of this information is the same between the two formats. After this part of the file, the format will differ slightly.
| Offset | Data type | Description |
|---|---|---|
| 0 | SINT16 | WorldType Used to identify the world's format. ZZT uses -1 (FF FF) and SuperZZT uses -2 (FE FF). |
| 2 | SINT16 | NumBoards Number of boards in the world, not including the title screen. Increment by 1 for the real number of stored boards. A value of 0 means only the title screen exists. |
| 4 | SINT16 | PlayerAmmo Player's ammunition. |
| 6 | SINT16 | PlayerGems Player's gems. |
| 8 | UINT8[7] | PlayerKeys Player's keys. A nonzero value means the player has the specified key. The keys are in this order: Blue, Green, Cyan, Red, Purple, Yellow, White. |
| 15 | SINT16 | PlayerHealth Player's health. |
| 17 | SINT16 | PlayerBoard In a world file, this will be the starting board for the player (the title screen, board 0, is always shown first). In a saved game, this will be the board that the player is currently on. |
ZZT world header
This is the second half of the header specific to a .ZZT file. After this information, storage of the boards starts at byte offset 512.
| Offset | Data type | Description |
|---|---|---|
| 19 | SINT16 | PlayerTorches Player's torches. |
| 21 | SINT16 | TorchCycles Game cycles left for a torch to remain lit. |
| 23 | SINT16 | EnergyCycles Game cycles left for an energizer to be effective. |
| 25 | SINT16 | (unused) Always 0. |
| 27 | SINT16 | PlayerScore Player's score. |
| 29 | UINT8 | WorldNameLength Length of the internal name of the world. |
| 30 | UINT8[20] | WorldName Internal name of the world. |
| 50 | UINT8 | Flag0Length Length of the name of Flag 0. |
| 51 | UINT8[20] | Flag0 Name of Flag 0. |
| 71 | UINT8 | Flag1Length Length of the name of Flag 1. |
| 72 | UINT8[20] | Flag1 Name of Flag 1. |
| 92 | UINT8 | Flag2Length Length of the name of Flag 2. |
| 93 | UINT8[20] | Flag2 Name of Flag 2. |
| 113 | UINT8 | Flag3Length Length of the name of Flag 3. |
| 114 | UINT8[20] | Flag3 Name of Flag 3. |
| 134 | UINT8 | Flag4Length Length of the name of Flag 4. |
| 135 | UINT8[20] | Flag4 Name of Flag 4. |
| 155 | UINT8 | Flag5Length Length of the name of Flag 5. |
| 156 | UINT8[20] | Flag5 Name of Flag 5. |
| 176 | UINT8 | Flag6Length Length of the name of Flag 6. |
| 177 | UINT8[20] | Flag6 Name of Flag 6. |
| 197 | UINT8 | Flag7Length Length of the name of Flag 7. |
| 198 | UINT8[20] | Flag7 Name of Flag 7. |
| 218 | UINT8 | Flag8Length Length of the name of Flag 8. |
| 219 | UINT8[20] | Flag8 Name of Flag 8. |
| 239 | UINT8 | Flag9Length Length of the name of Flag 9. |
| 240 | UINT8[20] | Flag9 Name of Flag 9. |
| 260 | SINT16 | TimePassed Amount of time in seconds that has passed on the current board. Only applicable if the board the player is on has a time limit. |
| 262 | SINT16 | PlayerData This stores a runtime memory location that points to the status element currently being used by the player. Its value is not used when loading worlds, and is always set to 0 when saving worlds. |
| 264 | UINT8 | Locked A nonzero value indicates the world is actually a saved game. Additionally, worlds with a nonzero Locked byte can't be edited using the built-in editor. |
Super ZZT world header
This is the second half of the header specific to a .SZT file. After this information, storage of the boards starts at byte offset 1024.
| Offset | Data type | Description |
|---|---|---|
| 19 | SINT16 | (unused) Always 0. |
| 21 | SINT16 | PlayerScore Player's score. |
| 23 | SINT16 | (unused) Always 0. |
| 25 | SINT16 | EnergyCycles Game cycles left for an energizer to be effective. |
| 27 | UINT8 | WorldNameLength Length of the internal name of the world. |
| 28 | UINT8[20] | WorldName Internal name of the world. |
| 48 | UINT8 | Flag0Length Length of the name of Flag 0. |
| 49 | UINT8[20] | Flag0 Name of Flag 0. |
| 69 | UINT8 | Flag1Length Length of the name of Flag 1. |
| 70 | UINT8[20] | Flag1 Name of Flag 1. |
| 90 | UINT8 | Flag2Length Length of the name of Flag 2. |
| 91 | UINT8[20] | Flag2 Name of Flag 2. |
| 111 | UINT8 | Flag3Length Length of the name of Flag 3. |
| 112 | UINT8[20] | Flag3 Name of Flag 3. |
| 132 | UINT8 | Flag4Length Length of the name of Flag 4. |
| 133 | UINT8[20] | Flag4 Name of Flag 4. |
| 153 | UINT8 | Flag5Length Length of the name of Flag 5. |
| 154 | UINT8[20] | Flag5 Name of Flag 5. |
| 174 | UINT8 | Flag6Length Length of the name of Flag 6. |
| 175 | UINT8[20] | Flag6 Name of Flag 6. |
| 195 | UINT8 | Flag7Length Length of the name of Flag 7. |
| 196 | UINT8[20] | Flag7 Name of Flag 7. |
| 216 | UINT8 | Flag8Length Length of the name of Flag 8. |
| 217 | UINT8[20] | Flag8 Name of Flag 8. |
| 237 | UINT8 | Flag9Length Length of the name of Flag 9. |
| 238 | UINT8[20] | Flag9 Name of Flag 9. |
| 258 | UINT8 | Flag10Length Length of the name of Flag 10. |
| 259 | UINT8[20] | Flag10 Name of Flag 10. |
| 279 | UINT8 | Flag11Length Length of the name of Flag 11. |
| 280 | UINT8[20] | Flag11 Name of Flag 11. |
| 300 | UINT8 | Flag12Length Length of the name of Flag 12. |
| 301 | UINT8[20] | Flag12 Name of Flag 12. |
| 321 | UINT8 | Flag13Length Length of the name of Flag 13. |
| 322 | UINT8[20] | Flag13 Name of Flag 13. |
| 342 | UINT8 | Flag14Length Length of the name of Flag 14. |
| 343 | UINT8[20] | Flag14 Name of Flag 14. |
| 363 | UINT8 | Flag15Length Length of the name of Flag 15. |
| 364 | UINT8[20] | Flag15 Name of Flag 15. |
| 384 | SINT16 | TimePassed Amount of time in seconds that has passed on the current board. Only applicable if the board the player is on has a time limit. |
| 386 | SINT16 | PlayerData This stores a runtime memory location that points to the status element currently being used by the player. Its value is not used when loading worlds, and is always set to 0 when saving worlds. |
| 388 | UINT8 | Locked A nonzero value indicates the world is actually a saved game. Additionally, worlds with a nonzero Locked byte can't be edited using the built-in editor. |
| 389 | SINT16 | PlayerStones Player's stones of power. If this value is negative, no information is shown in-game about them. If this value is >= 0, it uses a flag to describe this value in the status bar of the game. The flag used is the first one found that is preceded with a Z. "The Lost Forest" contains a flag called "ZSTONES" which shows as "STONES" on the status bar, for example. |
Board Format
Boards can be stored individually in .BRD files. Since ZZT and Super ZZT use the same extension for boards and there is no world information stored with them, it isn't immediately apparent whether the board is a ZZT or a Super ZZT board. Testing the validity of the board information with both world types should be a good way to determine the type of world a board belongs to.
Format layout
Boards consist of 4 parts: Board Header, RLE Tiles, Board Properties, and Status Element Properties. Status Elements are elements on the board that the game actively processes - these include the player, enemies, any animating blocks, and Scrolls and Objects which can contain ZZT-OOP code.
ZZT board header
ZZT boards are 60x25 tiles.
| Offset | Data type | Description |
|---|---|---|
| 0 | SINT16 | BoardSize Size of the board, in bytes. Even if the board was corrupted by the built-in editor (which happens sometimes) this value will be correct; the rest of the boards remain intact and in place. |
| 2 | UINT8 | BoardNameLength Length of the board's name. |
| 3 | UINT8[50] | BoardName Board's name. |
| 53 | ZZT_RLE | Tiles Start of the RLE tile data. |
Super ZZT board header
Super ZZT boards are 96x80 tiles.
| Offset | Data type | Description |
|---|---|---|
| 0 | SINT16 | BoardSize Size of the board, in bytes. Even if the board was corrupted by the built-in editor (which happens sometimes) this value will be correct; the rest of the boards remain intact and in place. |
| 2 | UINT8 | BoardNameLength Length of the board's name. |
| 3 | UINT8[60] | BoardName Board's name. |
| 63 | ZZT_RLE | Tiles Start of the RLE tile data. |
Run-length encoded tile data
Tile data is represented as sets of 3 bytes. These sets are repeated until the board is completely filled. For ZZT, this will be 60*25=1500 tiles. For SuperZZT, this will be 96*80=7680 tiles. The tiles are unpacked from left to right, top to bottom.
| Data type | Description |
|---|---|
| UINT8 | Count Number of tiles. |
| UINT8 | Element Element of the tiles. |
| UINT8 | Color Color of the tiles. |
A small quirk of this RLE format is when the number of tiles is set to zero. Due to the way the decoder is set up, a Count of 0 means there are actually 256 tiles encoded. The built-in editor does not encode tiles using this value despite being decoded correctly in the game, and it will probably crash some older external editors.
ZZT board properties
This information follows directly after the tile RLE data.
| Offset | Data type | Description |
|---|---|---|
| 0 | UINT8 | MaxPlayerShots Maximum number of player-owned projectiles allowed at once. |
| 1 | UINT8 | IsDark When set to 1, the board is covered in darkness which can only be revealed by using a torch. |
| 2 | UINT8 | ExitNorth Board # that is traveled to when moving off the North side of the board. |
| 3 | UINT8 | ExitSouth Board # that is traveled to when moving off the South side of the board. |
| 4 | UINT8 | ExitWest Board # that is traveled to when moving off the West side of the board. |
| 5 | UINT8 | ExitEast Board # that is traveled to when moving off the East side of the board. |
| 6 | UINT8 | RestartOnZap When set to 1, the player will teleport to the location where they entered the board whenever they are hurt. |
| 7 | UINT8 | MessageLength Length of the on-screen message. |
| 8 | UINT8[58] | Message On-screen message. This is used internally and is not loaded by the game. |
| 66 | UINT8 | PlayerEnterX X-coordinate of the tile where the player entered the board. |
| 67 | UINT8 | PlayerEnterY Y-coordinate of the tile where the player entered the board. |
| 68 | SINT16 | TimeLimit Time limit of the board, in seconds. The player is hurt when time runs out. |
| 70 | UINT8[16] | (unused) |
| 86 | SINT16 | StatElementCount Number of Status Elements on the board, not including the player. Increment by 1 to get the real stored number of status elements. |
Super ZZT board properties
This information follows directly after the tile RLE data.
| Offset | Data type | Description |
|---|---|---|
| 0 | UINT8 | MaxPlayerShots Maximum number of player-owned projectiles allowed at once. |
| 1 | UINT8 | ExitNorth Board # that is traveled to when moving off the North side of the board. |
| 2 | UINT8 | ExitSouth Board # that is traveled to when moving off the South side of the board. |
| 3 | UINT8 | ExitWest Board # that is traveled to when moving off the West side of the board. |
| 4 | UINT8 | ExitEast Board # that is traveled to when moving off the East side of the board. |
| 5 | UINT8 | RestartOnZap When set to 1, the player will teleport to the location where they entered the board whenever they are hurt. |
| 6 | UINT8 | PlayerEnterX X-coordinate of the tile where the player entered the board. |
| 7 | UINT8 | PlayerEnterY Y-coordinate of the tile where the player entered the board. |
| 8 | SINT16 | CameraX X-coordinate of the viewport. This value is not used when loading worlds. |
| 10 | SINT16 | CameraY Y-coordinate of the viewport. This value is not used when loading worlds. |
| 12 | SINT16 | TimeLimit Time limit of the board, in seconds. The player is hurt when time runs out. |
| 14 | UINT8[14] | (unused) |
| 28 | SINT16 | StatElementCount Number of Status Elements on the board, not including the player. Increment by 1 to get the real stored number of status elements. |
Status Elements
This follows directly after board properties. It is repeated for each Status Element. The first element stored is always the player-controlled element. This element may contain strange values for Step, Leader and Follower information - this is because these values are used internally by the game.
| Offset | Data type | Description |
|---|---|---|
| 0 | UINT8 | LocationX X-coordinate. Location coordinates are 1-based, unlike any other coordinates in the file. |
| 1 | UINT8 | LocationY Y-coordinate. |
| 2 | SINT16 | StepX X-step value. This pair of values represents a vector that typically points in one of the four cardinal directions. Its use differs for each type of element. |
| 4 | SINT16 | StepY Y-step value. |
| 6 | SINT16 | Cycle Cycle. This represents the frequency, in ticks, at which the game will process this status element. |
| 8 | UINT8 | P1 Parameter 1. Its use will differ depending on the type of element. |
| 9 | UINT8 | P2 Parameter 2. Its use will differ depending on the type of element. |
| 10 | UINT8 | P3 Parameter 3. Its use will differ depending on the type of element. |
| 11 | SINT16 | Follower Follower status element. Its value determines if another status element is linked behind this one. Typically used for linking centipedes. |
| 13 | SINT16 | Leader Leader status element. Its value determines if another status element is linked in front of this one. Typically used for linking centipedes. |
| 15 | UINT8 | UnderID Element of the tile under this status element. |
| 16 | UINT8 | UnderColor Color of the tile under this status element. |
| 17 | SINT32 | Pointer Stores the location in memory of the code that this status element is using. Status elements typically point to their own code until they #BIND the code of another - in which case this memory location value is replaced with the new one. ZZT does not use this value when loading worlds, and always sets it to 0 when saving worlds. |
| 21 | SINT16 | CurrentInstruction The offset in bytes of the code block to execute ZZT-OOP from. Only Objects and Scrolls can execute ZZT-OOP. |
| 23 | SINT16 | Length There are two uses for this value: If this value is positive, it represents the number of bytes that are in the code block. If this value is negative, the absolute value of this value represents the Status Element number to copy code from. This saves space by removing redundant code duplication. Since code is shared in this way, all modifications to code will affect any other Status Elements using it. |
In ZZT (not Super ZZT), 8 bytes of padding will follow.
If "Length" is positive, the code will be stored here.
Element Lists
This is a list of all valid built-in elements that can be used.
ZZT elements
| Value | Element |
|---|---|
| 0 | Empty |
| 1 | Board Edge |
| 2 | Messenger |
| 3 | Monitor |
| 4 | Player |
| 5 | Ammo |
| 6 | Torch |
| 7 | Gem |
| 8 | Key |
| 9 | Door |
| 10 | Scroll |
| 11 | Passage |
| 12 | Duplicator |
| 13 | Bomb |
| 14 | Energizer |
| 15 | Star |
| 16 | Conveyor, Clockwise |
| 17 | Conveyor, Counterclockwise |
| 18 | Bullet |
| 19 | Water |
| 20 | Forest |
| 21 | Solid Wall |
| 22 | Normal Wall |
| 23 | Breakable Wall |
| 24 | Boulder |
| 25 | Slider, North-South |
| 26 | Slider, East-West |
| 27 | Fake Wall |
| 28 | Invisible Wall |
| 29 | Blink Wall |
| 30 | Transporter |
| 31 | Line Wall |
| 32 | Ricochet |
| 33 | Blink Ray, Horizontal |
| 34 | Bear |
| 35 | Ruffian |
| 36 | Object |
| 37 | Slime |
| 38 | Shark |
| 39 | Spinning Gun |
| 40 | Pusher |
| 41 | Lion |
| 42 | Tiger |
| 43 | Blink Ray, Vertical |
| 44 | Centipede Head |
| 45 | Centipede Segment |
| 47 | Text, Blue |
| 48 | Text, Green |
| 49 | Text, Cyan |
| 50 | Text, Red |
| 51 | Text, Purple |
| 52 | Text, Brown |
| 53 | Text, Black |
Super ZZT elements
| Value | Element |
|---|---|
| 0 | Empty |
| 1 | Board Edge |
| 2 | Messenger |
| 3 | Monitor |
| 4 | Player |
| 5 | Ammo |
| 7 | Gem |
| 8 | Key |
| 9 | Door |
| 10 | Scroll |
| 11 | Passage |
| 12 | Duplicator |
| 13 | Bomb |
| 14 | Energizer |
| 16 | Conveyor, Clockwise |
| 17 | Conveyor, Counterclockwise |
| 19 | Lava |
| 20 | Forest |
| 21 | Solid Wall |
| 22 | Normal Wall |
| 23 | Breakable Wall |
| 24 | Boulder |
| 25 | Slider, North-South |
| 26 | Slider, East-West |
| 27 | Fake Wall |
| 28 | Invisible Wall |
| 29 | Blink Wall |
| 30 | Transporter |
| 31 | Line |
| 32 | Ricochet |
| 34 | Bear |
| 35 | Ruffian |
| 36 | Object |
| 37 | Slime |
| 38 | Shark |
| 39 | Spinning Gun |
| 40 | Pusher |
| 41 | Lion |
| 42 | Tiger |
| 44 | Centipede Head |
| 45 | Centipede Segment |
| 47 | Floor |
| 48 | Water, North |
| 49 | Water, South |
| 50 | Water, West |
| 51 | Water, East |
| 59 | Roton |
| 60 | Dragon Pup |
| 61 | Pairer |
| 62 | Spider |
| 63 | Web |
| 64 | Stone of Power |
| 69 | Bullet |
| 70 | Blink Ray, Horizontal |
| 71 | Blink Ray, Vertical |
| 72 | Star |
| 73 | Text, Blue |
| 74 | Text, Green |
| 75 | Text, Cyan |
| 76 | Text, Red |
| 77 | Text, Purple |
| 78 | Text, Brown |
| 79 | Text, White |