Table of Contents

ZXT Extension Format Specification

Version 1.0.0

By Adrian “asie” Siekierka

Special thanks: endgame, GreaseMonkey, Lancer-X, Noser, The Mysterious KM, WiL, zzo38

The specification follows a MAJOR.MINOR.PATCH numbering scheme, where:

For example, a ZXT 1.1.x world which doesn't utilize functionality specific to ZXT 1.1.x would be expected to work as-is in a ZXT 1.0.x engine implementation; there is no such requirement placed on a ZXT 2.0.x world.

Introduction

Extending and tweaking the functionality of the ZZT game engines 1) has always been an undercurrent in their world development community. While many games relying on edited executables or TSRs 2) have been released in the past, they ran into key problems, keeping their count small and the overall idea unpopular:

However, the release of the Reconstruction of ZZT in 2020 greatly lowered the bar for creating such modified engine versions, solving the first problem. With it, interest in creating game-specific forks and providing enhanced functionality has reappeared. Nonetheless, the remaining issues persisted and, as such, a standardized way to declare engine extensions utilized by a given world was deemed necessary.

The following use cases were considered:

The following categories of worlds were considered:

Coverage

The specification covers:

Notably, the specification currently does NOT cover:

Definitions

These definitions may be used freely in extension standards without re-introduction.

Where the specification mentions the terms ZZT game engine or .ZZT, one may substitute Super ZZT game engine and .SZT respectively.

File Format

Attachment

The extension data can be provided in one of two ways:

The two approaches are made with specific intents in mind, but may be used in any way the creator sees fit:

If a .ZXT file is being loaded, a .ZAX file should be ignored - .ZAX files apply for .ZZT files, not .ZXT files.

The behaviour of multiple concatenated extension headers contained within one .ZXT or .ZAX file is undefined; distributed .ZXT or .ZAX files MUST NOT rely on it.

Extension Header

The extension header's format is as follows:

Offset Type Name Description
0 u16 magic 0xF227 for ZZT-style worlds, 0xF527 for Super ZZT-style worlds, 0xB227 for ZZT-style boards, 0xB527 for Super ZZT-style boards.
2 u32 block_count The number of extension blocks which immediately follow.

After the header follow block_count extension blocks, in sequence:

Offset Type Name Description
0 u16 flags Extension flags; defined below.
2 u32 owner_id Extension owner ID.
6 u16 selector_id Extension selector ID.
8 u8 reserved_0 Reserved; must be set to 0.
9 u16 field_length Field length. Values between 0 and 65534 refer to the length in bytes; if set to 65535, an u32 containing the 32-bit field length in bytes follows.
11 u8[field_length] field_data Field data. Extension-defined.

An extension being “understood” is defined as one for whose ID pair the engine provides an implementation compliant with its standard.

The extension flags are as follows:

Bit Name Description Behaviour Layman's terms
0 parsing_must Required for parsing. If set, an implementation which does not understand this extension MUST NOT continue parsing of the extension block. Generally, this one will be set to 0.
1 reading_must Required for reading. If set, an implementation which does not understand this extension MUST NOT read the world file, but may continue parsing the extension block. If you're changing the world format in a breaking way, set this to 1.
2 writing_must Required for writing. If set, an implementation which does not understand this extension MUST NOT try to write the world file. If you're changing the world format in a partially-breaking way, set this to 1. (For instance, Variety redefines the flag section of a .ZZT file in a way which breaks reading only if at least two flags are set; however, a written world could have modified these flags, so we must prevent that. Another example would be re-using the padding fields.)
3 playing_should Recommended for playing. If set, an implementation which does not understand this extension SHOULD signal this to the end user if an attempt at playing the world is made. Non-strictly-breaking gameplay changes. For example, modified messages or sound effects. Sometimes, modified charsets or palettes.
4 playing_must Required for playing. If set, an implementation which does not understand this extension MUST signal this to the end user and prevent an attempt at playing the world. Breaking gameplay changes. New OOP commands if required, new element IDs, etc.
5 editing_should Recommended for editing. If set, an implementation which does not understand this extension SHOULD signal this to the end user if an attempt at editing the world is made. An engine does not have to make any effort to support such a world further. Non-format-breaking (format-breaking go into writing_must, reading_must or both) editor-side changes. Unknown element IDs count, for example.
6 preserve_should Recommended to preserve on resave. If set, an implementation SHOULD preserve the extension unchanged upon resave; if cleared, an implementation MUST NOT do so, and MUST discard the extension. Generally, you want this set to 1 - unless the field data relies on other board, world or extension data outside itself. Meant in particular for metadata.
7 vanilla_behavior Is this extension something ZZT does anyway? If set, an unmodified implementation of ZZT 3.2 or Super ZZT 2.0 may be assumed to support the playing_must and playing_should conditions without further additional support. This is meant for extensions which either (a) impose additional restrictions on the engine implementation not present in regular ZZT, or (b) depend on ZZT 3.2/Super ZZT 2.0 implementation details which are not required for an otherwise ZXT-compliant implementation. The intent is for external tooling to be able to declare a world ZZT 3.2-compatible.
8 .. 15 reserved Reserved. If set, an implementation MUST NOT continue parsing of the extension block.

It is important to note that the flags can be distinct from the ID pair; for instance, the same ZZT-OOP extension can be defined as “recommended for playing” if optional for gameplay, but “mandatory for playing” if required for gameplay. However, an extension standard may require you to set or clear certain bits for compliance.

Extension IDs

Extension IDs are allocated on a per-owner ID basis. Within one owner ID, selector IDs SHOULD be used in a “one per extension” manner.

Owner ID Ranges

Interactions

Cross-Extension Interactions

Any interactions not explicitly defined and not part of any enabled extension's specification are undefined behaviour and MUST NOT be relied upon. For example:

World Format

Engine Extension Scope

Engine Accuracy

Engines are expected to be accurate to the ZZT game engine's intended behaviour. However, preserving ZZT's memory and stack layouts - and the respective bugs - are OPTIONAL, with the following exceptions:

Field Value
X 0
Y 1
Step X 256
Step Y 256
Cycle 256
P1 0
P2 1
P3 0
Follower 1
Leader 1
Under Element 1, Color 0x00
Data Pos 1
Data Len 1

Note that any feature which crashes regular ZZT (or causes double-frees, particularly double #BIND) remains undefined behaviour. ZXT-compliant implementations may choose to fix them.

Of course, any of the assumptions in this section can be overridden by an extension.

Best Practices

This is not a formal part of the specification - it's more of an “advice” section.

World Developers

Extension Specification Authors

Engine Developers

Side Notes

This is not a formal part of the specification - rather, it provides insight into some contested decisions.

Implementations

This is not a formal part of the specification.

Libraries

ZXT 1.0.x

Tools

ZXT 1.0.x

Engines

TBD

1)
ZZT and Super ZZT
2)
Terminate-Stay Resident programs