Information Topics

General Information

ZZT World Support



History of ZZT

The first official release of ZZT occurred in 1990, although most of the officially released ZZT games would come about in 1991. Four full games were developed and published in the registered version of ZZT: Town of ZZT, Caves of ZZT, Dungeons of ZZT, and City of ZZT. The company Epic Megagames, first known as Potomac Computer Systems, was a one-man company then, belonging to Tim Sweeney.

The ZZT engine was soon followed by a slightly more advanced engine, Super ZZT. Three games were officially released for Super ZZT: Proving Grounds, Lost Forest, and Monster Zoo.

Both of these game engines were packaged with a world editor, which is largely seen as ZZT's most remarkable feature. However, the original ZZT engine placed no barriers to editing, while Super ZZT required the use of a command-line switch /e. Also, ZZT in-game documentation for the editor was superb, while Super ZZT's documentation was nonexistent.

As far as graphics and sound are concerned, none of the games were "epic." But as a game creator, ZZT was absolutely "epic." Its success guaranteed that we would see more from Epic Megagames. We did.

I would like to say that the rest is history...but it wasn't.


People created their own worlds in ZZT. Oh, did they create more worlds. But a funny thing happened--people started crashing against the upper limits of what ZZT could offer as a game creator. For whatever reasons, when you put new power in the hands of an unskilled but ambitious individual, said individual tends to think bigger than what the world can support.

In 1994, Alexis Janson created a derivative of ZZT, called MegaZeux. This game creator gave game developers significantly more capabilities, while still retaining the same "text mode noir" as ZZT. While it was a decent editor, MegaZeux didn't maintain any sort of ZZT "standard." This game creator was designed to exist in its own right, with its own formats and syntaxes.

Building a Better Engine

Numerous attempts have been made to create an "Open ZZT" engine that can exist anywhere and everywhere. The most notable attempt to faithfully reproduce ZZT from the original assembly is Lyon, for the .NET platform. There are a few others, such as Tyger, Dream ZZT, and Direct ZZT, although these projects lack completeness.

In terms of web-based ZZT, it appears ZZT Ultra is the first real attempt to build the game engine in Flash.

The Making of ZZT Ultra

After I had worked on porting the entire Kroz series to Flash (see Cruz), I started a new job that kept me extra busy. Eventually, for reasons unknown, my attention returned to the ZZT scene.

Since revamping old text-mode games seems to be my forte, I decided to take a crack at making an online version of ZZT. This, like many other projects, involved design-via-observation. To misquote a famous philosopher, "I see, therefore, I make."

I am no stranger to reverse engineering. However, I thought that trying to rebuild ZZT in a perfect rendition of its original behavior was missing the point. The integrity of the engine is paramount, but the overall experience cannot be sacrificed.

So, in starting ZZT Ultra, I wanted to up the ante in terms of ambition. The engine would run any ZZT or Super ZZT game, but it would run it in a special way--its code base would encapsulate the functionality, while at the same time, being far more powerful than it needed to be, for the purpose of extensibility.

Technical Specifications

The original ZZT had very simple requirements. Roughly speaking...

  • IBM PC 8086/8088 or better CPU
  • MS-DOS 3.0 or better
  • 400 KB RAM or higher
  • Monochrome or color monitor (for 80x25 or 40x25 text mode)
  • IBM PC speaker
  • 101/102-key keyboard
  • Mouse (optional)

The "new" requirements for ZZT Ultra should work on any modern web browser:

  • Adobe Flash 10 or better
  • 1.00 GHz processor or better
  • 800x600 screen resolution or better

ZZT Ultra is not very ambitious in terms of graphics. This makes sense given that ZZT was never ambitious graphically, either. The sound is a different matter--the sound is dynamically generated to ensure accurate reproduction of PC-speaker-like effects. This is one reason that a fast processor is desired, because low-latency dynamic sound generation ensures the best reproduction possible.

ZZT Ultra Components

  • 80x25 and 40x25 text-mode graphical emulation pane
  • Dynamic sound system
  • File parsing system (legacy and modern)
  • ZZT-OOP compiler
  • ZZT-OOP interpreter
  • Real-time object manager
  • World/Board manager
  • Message dispatch system
  • Integrated GUI editor
  • Integrated world editor

80x25 and 40x25 text-mode graphical emulation pane

For anyone who is familiar with text modes for the IBM PC, very little about this component is left to the imagination. The IBM PC Code Page 437 character set is used to draw characters at predefined slots over the entirety of the display. There are a total of 256 characters in this code page.

The colors are the typical 16-color palette found in the CRT color text modes. The ZZT game engines used the "blink" configuration setting, and so ZZT Ultra also implements this setting. Foreground color (what the character is painted) is one of 16 colors, while background color (what the non-character portions of the cells are painted) is one of 8 colors.

The "blink" flag (the highest-order bit of a color byte) is mostly used to render water in the game, but some third-party games use the blink flag in other contexts.

Dynamic sound system

The PC speaker was a fairly poor sound-generation device, but the ZZT engines gave it a good run by allowing individual games to define their own music and sound effect sequences, which are played through the speaker. ZZT Ultra emulates this functionality.

By keeping samples of PC speaker frequency cycles and percussion effects, ZZT Ultra can play back any original ZZT sound flawlessly. Some emulators run into problems reproducing this type of sound because the real-time nature of some of the effects makes it difficult to accurately time when pulses must be pulled in and out. In particular, the simple "tick" sound when the player moves has gotten mostly lost in emulated environments, but ZZT Ultra reproduces it faithfully.

There is a consequence to dynamically generated sound--it requires that the CPU be fast enough to handle real-time waveform generation without skips or pops. For this reason, ZZT Ultra can be subject to sound latency with slower computers. Short latency gives best performance, but might stutter if the CPU is lagging. Long latency, while most compatible, ends up throwing off the timing of the individual effects when played in rapid succession.

File parsing system (legacy and modern)

Although the integrated editors of ZZT and Super ZZT were very helpful for third parties, the binary file format itself did not lend itself to more sophisticated types of modding.

ZZT Ultra can load any world file of ZZT or SZT extension provided that it respects the original engine limitations (i.e. can load in the original program). However, this is only to support such worlds in ZZT Ultra--there is only limited support for saving in these formats. ZZT Ultra does not try to "extend" the legacy formats; they are limited to what they could do with the original editors.

ZZT Ultra readily supports a new "extended ZZT" format, which is far more conducive to modding outside of ZZT Ultra. The WAD file format, first used by id Software, is now the preferred choice for world files saved in ZZT Ultra.

ZZT-OOP compiler

Unlike the original ZZT engines, which interpreted every line of ZZT-OOP code by parsing the text in real-time, ZZT Ultra compiles code first and interprets the compiled bytecode later. Programmatically, this was a sensible decision that optimizes the overall run operations.

ZZT-OOP in the original ZZT engines only applied to the OBJECT and SCROLL types. ZZT-OOP in ZZT Ultra now applies to all object types in the game, as well as serving as a mechanism for dispatched message handlers. This allows one to effectively rewrite the engine's frontend operations in ways that were never possible with ZZT and Super ZZT.

Also, ZZT-OOP has many new commands and syntax conventions in ZZT Ultra, which makes the language far more powerful. However, these new language features do not conflict with the original ZZT-OOP code from legacy world files. This is because the compiler performs a few tricks with namespaces when it knows it is compiling code for a legacy world.

ZZT-OOP interpreter

When ZZT-OOP is compiled into bytecode, it is stored internally within ZZT Ultra for fast run operations until one of the following occurs:

  • New world file loaded (previous custom OBJECT and SCROLL code is discarded)
  • New OOP types loaded (new world files can modify OOP code for built-in types)

The concept of an "instruction pointer" or IP is used in the interpreter for executing bytecode. For more information on how the interpreter works, see the details about the message dispatch system.

Real-time object manager

Most of the animations and real-time events that occur in a ZZT board are implemented in the form of status elements, which are data structure instances containing location, cycle, IP, direction, and other miscellaneous pieces of information. These status elements are tracked independently of the individual grid squares on the board itself.

ZZT Ultra iterates these status element objects at the appropriate rate when the game is not paused or in some other transition mode. It should be noted that the game speed setting influences how frequently these objects are updated--the original default of 9.1 Hz was modifiable in the original ZZT engines, and is also modifiable in ZZT Ultra.

The object instances themselves have a critical difference in ZZT Ultra--they support an unlimited number of additional dictionary-style members instead of the original "P1,P2,P3" fixed-size configuration. This lets one make significantly more complicated object behavior than what would have been available to designers in ZZT or Super ZZT, because any number of new "member" variables can be implemented for objects as appropriate.

World/Board manager

The internal backend storage for ZZT world and board information was relatively simple in the original ZZT engines, but is much more versatile in ZZT Ultra.

The main difference is that the original fixed-size configuration for world and board information has been discarded in ZZT Ultra, in favor of dictionary-style attributes. Such information can now be read and manipulated easily within ZZT-OOP.

By allowing the world and board to be internally modifiable, it is possible for a third party to program behavior with board sizes, camera control, lighting, and other attributes that would not have been possible in ZZT or Super ZZT.

The original hard limitations on flags for the world have been erased in ZZT Ultra. There is now a superset of the original "flag" functionality, called global variables, which contains all of the original flags. Global variables can be assigned non-boolean values in ZZT Ultra, which increases the overall versatility of the engine.

Other features that were hard-coded in the original engines are now modifiable. It is possible in ZZT Ultra to set context-sensitive rectangular regions for a board. One can also set and use customized masks for area effects (e.g. bomb and torch).

Message dispatch system

ZZT Ultra supports two types of messages used with ZZT-OOP: sent messages and dispatched messages. A sent message simply modifies the IP of the target object for when it is executed during the next real-time iteration. This behavior works the same as it did in ZZT and Super ZZT.

A dispatched message is a new concept to ZZT-OOP. Instead of working with objects in real-time, a dispatched message is sent to the interpreter to be executed immediately, and it does not resume after a movement or "idle cycle." This is because a dispatched message is designed to accomplish a specific function as opposed to execute an object-oriented action in real-time. Whereas a sent message is associated with an object instance, a dispatched message is associated with an object type.

Dispatched messages are commonly triggered by ZZT Ultra in response to various events, like keyboard, timing, world loading, etc. Most of these events are handled by the main type code (the EMPTY type). It is also possible for an object to dispatch messages to the "main" type or to other types using the new ZZT-OOP DISPATCH or DISPATCHTO commands.

Because so much of ZZT Ultra relies upon dispatched messages, the frontend "core" code is decidely thinner than it was in ZZT or Super ZZT. Instead, it is expected that ZZT-OOP code will account for a great deal of the functionality, favoring such code over hard-coded frontends with limited versatility.

Integrated GUI editor

The original ZZT engines did not let the designer customize the GUI. In ZZT Ultra, there are several ZZT-OOP commands that set or modify the GUI.

ZZT Ultra comes with a GUI editor, which gives the designer a mechanism for editing sidebar menus, title screens, and other types of GUIs.

GUI spec files are stored as text files with extension ZZTGUI. The file is easily-readable JSON, which can be useful if the designer wants to edit the GUI externally.

ZZT world files created by ZZT Ultra can incorporate GUI spec files, allowing a world file to define its own frontend.

Integrated world editor

The original ZZT engines had a world editor, and ZZT Ultra has its own world editor. All the new world-defining features of the engine are supported in this new editor.

Having the world editor be part of the same application as the game is necessary due to the nature of ZZT itself. The spirit of ZZT is only realized if third-party developers are granted control over the features of the engine, as this is something that has been expected of ZZT from the very beginning.

Fall of ZZT: The Curse of Production Quality

This adventure is going to be an exclusive to ZZT Ultra, making use of the various enhancements offered by the new engine. It will be a tongue-in-cheek revue of the early Epic Megagames titles, making light of how advancements in computer technology have caused game characters from earlier time periods to be forgotten.

The ZZT Guy plays himself, and meets the other classic, disenfranchised Epic game characters while pursuing a quest to find out where Epic had gone wrong.

Return to Table of Contents

This page is Copyright © 2016 Christopher Allen.