From Wiki of ZZT
Jump to navigation Jump to search
ZZT-OOP namekey
Internal ID8 (0x08)
Character#char 12 (0x0C)
Other traits
Effect on movementpushable
Uses ZZT-OOP color names?yes

The key element is one of the built-in puzzle elements of ZZT. A key can be used to open a door of the corresponding color; together, they allow a designer to create a simple lock-and-key puzzle. When the player collects a key, the engine prints "You now have the X key." where X is the key color, adds the key to the "Keys" counter on the HUD, and leaves an identically-colored empty where the key was. If the player already has a key of a certain color, the game prints "You already have a X key!" where X is the color, and prevents the player from collecting it. A number of modern worlds have exploited this attribute to create puzzles where the player is blocked by multiple keys of the same color and must find enough correctly-colored doors in order to consume each one.

Keys can be placed in any of the default colors recognized by ZZT-OOP, as well as the darker colors enabled by external editors. The foreground color is used to determine what the color of the key is when it is collected. The engine treats the dark colors the same as the default bright colors when collected, with the side effect that a brown key will be treated and addressed as a yellow key when collected.

Unlike other items, a key cannot be given directly to the player through ZZT-OOP; an object must first use #put, #change or #become to create a key for the player to collect.

While keys are pushable, they cannot be pushed by a player since attempting to do so will collect them. However, a player can move them by pushing a boulder against them, or letting a pusher shove them.

Black keys

While keys can be placed in all of the available colors, black keys and dark-grey keys will have glitched behavior when collected:

  1. The engine will print a garbled mess in place of the key color that includes "Blue", "Green", "Cyan" and "Red";
  2. The gems counter will be incremented by 256.

Both of these are out-of-bounds errors related to the arrays used for keys, as follows:

Color naming

The color naming for pickup messages is handled by the ColorNames array in GAME.PAS line 92, which has entries for color indexes 1 to 7 of the CGA color palette. This is an array of strings up to eight characters in length. When the engine attempts to access the color name for index 0, the color black, it attempts to access the entry prior to the first entry, Blue, and goes out of bounds into where the preceding ProgressAnimStrings array exists in memory. It then fails to detect when an entry ends, and prints as much of the succeeding portion of memory as it can fit in a message string after the initial "You now have the ", producing the glitched message. When editing the engine, the bug can be fixed by changing the array range from 1 .. 7 to 0 .. 7 and adding 'Black', to the start of the array before 'Blue',.


The key counter in the world format is defined in GAMEVARS.PAS line 111, under TWorldInfo, as a boolean array named Keys which ranges from 1 to 7, covering CGA color indexes 1 to 7. Collecting the keys of these colors sets their equivalent boolean to "true", which is indicated internally as 01; when used, they are set to false, or 00. When the engine attempts to access the entry of this array for color index 0, the color black, it adds 01 in the byte prior to that of the Blue key, and in doing so goes out of bounds into the second byte of the gems counter, a 16-bit signed integer that thus uses the second byte to indicate units of 256. Because of this, the player's gems counter is increased by 256. The bug can be fixed by changing the Keys array range from 1..7 to 0..7, but doing so will also change the world format, making all standard world files incompatible with the engine.

Note that attempting to collect a black key while already having 256 or more gems will fail, as the would-be boolean will already be set to 01 (or beyond).