Key for data types
The data types used to describe the MZX file formats are as follows:
This guide contains specifications for most MegaZeux file formats. This is a table-dense document and should be displayed in a window/viewport at least 640px wide to reduce table overflow.
The data types used to describe the MZX file formats are as follows:
This file format describes one or more MZX graphical characters. A CHR file contains raw graphical data only. Each character in the CHR file consists of 14 bytes representing each graphical row of the character.
Within the byte, each pixel of the row is encoded either as a single bit (MZX) or as two bits (SMZX). The first byte of the next character immediately follows the 14th byte of the previous character.
A typical character set file contains 256 chars (for a total size of 3584).
However, partial character sets are possible, as are character sets with
more than 256 chars. Complete and partial character sets can be loaded
from files or from MZX strings with the load char set
command.
The bytes representing a character in a character set are also the same
as the values provided to the char edit
command or to the
CHAR_BYTE
counter.
The most significant bit of the byte represents the leftmost pixel in the row and the least significant bit of the byte represents the rightmost pixel.
Example: setting the third, fifth, and seventh pixels.
(128 * 0)
+ (64 * 0)
+ (32 * 1)
+ (16 * 0)
+ (8 * 1)
+ (4 * 0)
+ (2 * 1)
+ (1 * 0) = 42
The most significant two bits of the byte represent the leftmost pixel in the row and the least significant two bits represent the rightmost pixel. The four colors are encoded as the following bit pairs and quaternary digits:
Example: setting the first and second pixels to color 2, third to color 4, and fourth to color 1.
(64 * 1)
+ (16 * 1)
+ (4 * 3)
+ (1 * 0) = 92
This file format describes an MZX palette. A PAL file contains raw palette data only. Each color in the PAL file consists of 3 bytes representing the red, green, and blue components of the color. Each RGB component of a color is a value from 0 to 63 (inclusive).
A typical MZX or SMZX mode 1 PAL file contains 16 colors (48 bytes) and a typical SMZX mode 2 or mode 3 pal file contains 256 colors (768 bytes).
The PAL file does not encode any SMZX 3 color index information (see PALIDX).
This file format describes SMZX mode 3 subpalette indices. A PALIDX file contains 256 sets of indices (one for each subpalette). Each set of indices is a sequence of four bytes (for a total of 1024 bytes per file); the first indicates color 1 of the subpalette, the second color 2, and so on.
This section documents the portions of the world and save formats that are consistent between all MZX versions.
Most world files begin with a 29-byte header. The only exceptions are locked worlds from MegaZeux 1.xx, encrypted worlds from MegaZeux 2.00 through 2.6, and rearchived MegaZeux 2.90 worlds (see the 2.90+ world format).
The following magic values are valid:
M\002\011
(octal) as hex.
| `M\x02\x32` | 2.62 and 2.62b (from octal M\002\062
)
| `M\x02\x41` | 2.65 (from decimal 65
)
| `M\x02\x44` | 2.68 (from decimal 68
) (3)
| `M\x02\x45` | 2.69 (from decimal 69
)
| `M\x02\x46` | 2.69b
| `M\x02\x48` | 2.69c
| `M\x02\x49` | 2.70
| `M\x02\x50` | 2.80X (from decimal 80
) (first port releases)
| `M\x02\x51` | 2.81X (and so on...)
| `M\x02\x52` | 2.82X
| `M\x02\x53` | 2.83
| `M\x02\x54` | 2.84X
| `M\x02\x5A` | 2.90X
| `M\x02\x5B` | 2.91X
| `M\x02\x5C` | 2.92X
| `M\x02\x5D` | 2.93X
The internal MZX version value is derived from the world magic by 1)
treating the last two bytes as a big-endian word if the magic is from
2.51s2 or later or 2) using 0x0100
, 0x0205
,
and 0x0208
for 1.00, 2.00, and 2.51s1 worlds (respectively).
In all world files with a password, the password can be decrypted with the following algorithm:
/**
* This code is copied from the MZX source code, which is GPL 2+ licensed.
*/
char magic_code[16] = "\xE6\x52\xEB\xF2\x6D\x4D\x4A\xB7\x87\xB2\x92\x88\xDE\x91\x24";
for(i = 0; i < 15; i++)
{
password[i] ^= magic_code[i];
password[i] -= 0x12 - protection_method;
password[i] ^= 0x8D;
}
In MegaZeux 2.00 through 2.6 encrypted worlds, the rest of the MZX file is XORed with a byte calculated from the password. The bundled MegaZeux utility "checkres" can output the unencrypted password and XOR value when given the -v option, if needed.
Save files use a different header from world files, but the idea is generally the same.
The internal MZX file format version is derived from the save magic the same way it is derived from the world magic, and is always the same as the MZX version that produced the save file.
The world version field (saved separately here) is always the same as the world version derived from the world magic when the world was initially loaded. Notably, this value is saved as a little endian word (whereas it is represented as a big endian word in the world magic string). In versions where this field is not present, the world version should be treated as the same as the file format version.
MegaZeux 1.00 world (.MZX) and save (.SAV) files share very similar formats, so they are documented together here. This format is sufficiently different enough from the 2.00 format that it has been given its own section.
World data immediately follows the header.
Total block length is 3890 bytes.
This block is present in save files only. Total block length is 16.
Total block length is 72.
This block is present in save files only. Total block length is 9.
Total block length is 18.
This block is only present in save files and has an variable length. The counters list begins with the number of counters.
A list of N
counters follows, each in the following format:
Following the board count byte is the board names list and the board sizes and offsets table.
For each board:
For each board:
Typically, board data immediately follows these tables.
MegaZeux 1.xx does not support overlays or board modes; these should be treated as disabled and 100x100, respectively. Boards begin immediately with the board RLE plane data. Board contents are compressed with run length encoding, which is different from its MegaZeux 2.xx counterpart. Each board always has exactly 6 planes in the following order:
Each compressed plane starts with the following fields:
The RLE data follows after, and consists entirely of pairs of run lengths and byte values. The RLE plane can be decompressed with the following algorithm:
/**
* This code fragment is a simplified version of the RLE unpacking code from
* MegaZeux's source code, and is therefore GPL 2+ licensed.
*/
int size = width * height;
int i = 0;
while(i < size)
{
runsize = *(stream++);
current_char = *(stream++);
if(runsize > size - i)
runsize = size - i; // MegaZeux emits an error if this occurs.
for(int j = 0; j < runsize; j++)
plane[i++] = current_char;
}
The RLE stream ends when (board width * board height)
bytes have been expanded from the stream, and the next compressed plane
or the board parameters block immediately follows.
The board parameters block follows the board RLE planes.
Following the board parameters are the robot, scroll, and sensor lists.
Each list is stored as a single byte N
indicating the
number of robots, scrolls, or sensors on the board (0 to 255), followed
by N
stored objects of that type. Each object in its
respective list immediately follows the prior, and the next list starts
immediately following the last object in the previous list. The board
data ends after all three lists and their objects have been read.
The board robots/scrolls/sensors in the list count from ID 1 upward, as ID 0 is the global robot and is invalid for scrolls and sensors. Since objects in the file are sequential, robot/scroll/sensor IDs may have to be reassigned when saving worlds or saves in these versions to optimize out gaps in the list.
Each robot is 37 bytes plus the length of the robot program long.
WAIT
/GO
/etc)
| 29 | b | 1 | Robot cycle
| 30 | b | 0 | Cycle counter
| 31 | b | 1 | Bullet type (0: player, 1: neutral, 2: enemy)
| 32 | b | 0 | Locked status (0: unlocked, 1: locked)
| 33 | b | 0 | Can lavawalk (0: no, 1: yes)
| 34 | b | 0 | Walk direction (0: idle)
| 35 | b | 0 | Last touch direction
| 36 | b | 0 | Last shot direction
| 37 | s... | | Robot program
Each scroll block is 10 bytes plus the length of the scroll text long.
33 8e
hex, the line will use
color 8 as the background color and color 14 as the foreground color.
Unlike 2.x scrolls, the scroll text does not begin with 01
.
Each sensor block is 31 bytes long.
MegaZeux 2.00 world (.MZX) and save (.SAV) files share very similar formats, so they are documented together here. This section also tries to note changes in these formats and when they occurred, but save format modifications between versions are somewhat of a mess, so please report any inaccuracies in this document.
World data immediately follows the header. For ease of readability, it has been broken down into several blocks. Each block starts immediately after the previous block ends.
Total block length is 4129 bytes.
This block is only present in save files. Total block length is 73 bytes plus the length of the current playing mod name.
Total block length is 72.
SWAP WORLD
| 24 | b * 3 * 16 | Palette (see Palettes)
This block is only present in save files has a length of 24 bytes.
WARNING: The format of the save blocks following this frequently changed from version to version. If there are any inaccuracies in the legacy world format documentation, they're probably below. MZX versions prior to 2.90 regularly dropped support for saves from older MZX versions due to the format changes in this part of the format being too messy to support. Difficulty in supporting changes to the world/save format are one of the main reasons the world format was replaced in MZX 2.90.
This block is only present in save files and has an variable length. The counters list begins with the number of counters.
A list of N
counters follows, each in the following format
in MZX versions 2.00 through 2.80X:
ds
instead)
In MZX versions 2.81X and up, the counters are instead stored in the following format:
MZX_SPEED
and the MZX_SPEED
locked
status. These are named "mzx_speed" and "_____lock_speed". This vile
hack was made unnecessary in MZX 2.90 by the new world format.
The strings block in versions 2.80X through 2.84X follows the counters block and is stored in a similar way.
A list of N
string definitions follows. In 2.80X the strings
were saved in the following format:
In versions 2.81b and onward (1), the following structure is used instead:
In versions that support sprites, the sprites list begins with
N
sprite definitions, where N
= 64 for MZX
2.65 through 2.69b and N
= 256 for MZX 2.69c and all releases
afterward.
The sprite data is followed by the following global sprite variables:
The sprite collision list follows. In MZX 2.65 through 2.69b it is stored as follows:
From MZX 2.69c onward, the sprite collision list is saved as words and is always 256 in length:
Strings in DOS MZX versions do not have names and are instead numbered from 1 to 16. They are saved as fixed length buffers after the sprites list (rather than before it as in port versions). The length of this block is always 16*64=1024 (these weren't saved in versions with 16 char strings).
MZX versions 2.68 through 2.70 save the math and file IO vars as follows:
MZX versions 2.80X through 2.82X save the following:
MZX 2.83 saves the following:
MZX 2.84X saves the following:
SPACELOCK
) (0: disabled, 1: enabled)
| 11 | b | Built-in message status (0: disabled, 1: enabled)
| 12 | w | Input filename length = X
| 14 | s... | Input filename (NOT null terminated)
| 14 + X | d | Input file position
| 18 + X | w | Output filename length = Y
| 20 + X | s... | Output filename (NOT null terminated)
| 20 + X + Y | d | Output file position
MZX versions 2.69 and up save the SMZX mode here.
If SMZX mode is 2 or 3 (2.81+), the SMZX palette (but NOT intensities, which were unsaved prior to 2.90) follows:
The commands value follows. MZX 2.69 through MZX 2.83 saved it as a word (despite the internal value being expanded to a dword in 2.80):
MZX 2.84X finally corrected this to a dword:
The vlayer is saved as follows in 2.69c and 2.70:
MegaZeux 2.80X saves this instead:
This was changed to the following in 2.81X:
In an unencrypted world file this will always be at offset 4230.
If the board count byte is 0, a custom SFX table is present. If there is not a custom SFX table in the world file, the world will use the MZX default SFX instead. The SFX table begins with:
Then, for each SFX (50 total):
Finally:
Following the board count byte is the board names list and the board sizes and offsets table.
For each board:
For each board:
Typically, board data immediately follows these tables, and the global robot is placed at the very end of the world file.
Each board begins with the following fields:
10000
for
each board plane. DOS MZX used the board mode field to determine what
the maximum dimensions of the board were within the available space.
MegaZeux 2.80+ ignores this field and uses the plane dimensions to
to determine the board size.
00
, the
board has an overlay and has the following extra field. As a
consequence of this, saving a world with overlay disabled and a board
width of 256 (which results in a lower byte of 00
) in
DOS MZX versions will generate a corrupt world and crash MZX. Port
versions avoid this by incrementing the board width to a non-multiple
of 256 when setting the board size in the editor.
Board and overlay contents are compressed with run length encoding. Each board has either 6 or 8 planes (depending on whether the overlay is enabled), which immediately follow the mode fields and are stored in the following order:
Each compressed plane starts with the following fields:
The RLE data follows after. Values 0 through 127 represent a single
literal value in the uncompressed data. If bit 7 is set, instead a run
of length (byte & 127)
should be filled with the next byte
in the stream. The RLE plane can be decompressed with the following
algorithm:
/**
* This code fragment is a simplified version of the RLE2 unpacking code from
* MegaZeux's source code, and is therefore GPL 2+ licensed.
*/
int size = width * height;
int i = 0;
while(i < size)
{
current_char = *(stream++);
if(!(current_char & 0x80))
{
plane[i++] = current_char;
}
else
{
int runsize = current_char & 0x7F;
current_char = *(stream++);
if(runsize > size - i)
runsize = size - i; // MegaZeux emits an error if this occurs.
for(int j = 0; j < runsize; j++)
plane[i++] = current_char;
}
}
The RLE stream ends when (board width * board height)
bytes have been expanded from the stream, and the next compressed plane
or the board parameters block immediately follows.
The board parameters block follows the board RLE planes. The following is the board parameters format for MZX versions prior to 2.83.
The board parameters block follows the board RLE planes. The following is the board format for MZX versions 2.83 and 2.84X.
This block immediately follows the playing mod:
The following block is only present in save files.
The following block is in both world files and save files.
The final block is only present in save files.
M\x02\x53
to M\x02\x52
.
Following the board parameters are the robot, scroll, and sensor lists.
Each list is stored as a single byte N
indicating the
number of robots, scrolls, or sensors on the board (0 to 255), followed
by N
stored objects of that type. Each object in its
respective list immediately follows the prior, and the next list starts
immediately following the last object in the previous list. The board
data ends after all three lists and their objects have been read.
The board robots/scrolls/sensors in the list count from ID 1 upward, as ID 0 is the global robot and is invalid for scrolls and sensors. Since objects in the file are sequential, robot/scroll/sensor IDs may have to be reassigned when saving worlds or saves in these versions to optimize out gaps in the list.
Robots are stored in world/save files in the following format. Several of these fields are only used during runtime and thus initial values used when saving worlds are also listed.
WAIT
/GO
/etc)
| 23 | b | 1 | Robot cycle
| 24 | b | 0 | Cycle counter
| 25 | b | 1 | Bullet type
| 26 | b | 0 | Locked status (0: unlocked, 1: locked) (2)
| 27 | b | 0 | Can lavawalk (0: no, 1: yes)
| 28 | b | 0 | Walk direction (0: idle) (2)
| 29 | b | 0 | Last touch direction (3)
| 30 | b | 0 | Last shot direction (3)
| 31 | ws | note 4 | X position
| 33 | ws | note 4 | Y position
| 35 | b | 0 | Status for the current board cycle (5)
| 36 | ws | 0 | Local (6)
| 38 | b | 1 | Used (1) or unused (0)
| 39 | ws | 0 | Loopcount (7)
LOCAL2
counter
was stored by using the robot walk direction as the upper byte and the
robot locked status as the lower byte. Setting LOCAL2
had
the side effects you would expect from modifying those variables.
LOCAL3
counter
was stored by using the robot last touch direction as the upper byte and
the robot last shot direction as the lower byte. Setting LOCAL3
had the side effects you would expect from modifying those variables.
end
, wait
| 2 | Same as 1 but has also been sent a label
In save files from MegaZeux 2.80 and onward, an extra data block follows:
In both world and save files, the robot program immediately follows the above block(s). The size of the program in file is the same as the program length field in the robot data.
In older worlds, robots marked unused may have uninitialized memory
saved where their program would usually go (the global robot from
Slave Pit is an example). In this situation, the Robotic program
should not be validated and should instead be ignored or replaced with
FF 00
.
Each scroll block is 7 bytes plus the length of the scroll text long.
01
hex byte, must
contain at least one line break (0A
hex), and must be
null terminated (i.e. the smallest valid scroll is
01 0A 00
with number of lines=1 and length=3).
Each sensor block is 32 bytes long.
The legacy world format was replaced starting from MegaZeux 2.90 with a ZIP-based format. The old world format was replaced for the following reasons:
MZX_SPEED
, and others, so the format needed to be
changed anyway. There were also numerous MZX features queued for
addition that required world format changes, including improved SMZX
support and vlayer editing.
ZIP-based worlds begin with the same 29-byte header that unencrypted legacy worlds do, and ZIP-based saves begin with the same 8-byte header that legacy save files do. This is possible as ZIP archives parse starting from the end of the file, so ZIP archives with prefixed data are still valid ZIP archives. The header data is stored redundantly in the world properties file so ZIP worlds can be extracted and rearchived by an external program and still work even without the header.
World and save files split their data into multiple internal files for modularization and to allow for compression of specific parts of the world data. The files supported by the world format and the order they are loaded in are as follows:
The board files (prefixed with b##
) corresponding to a
single board are all loaded before loading any files corresponding to
the next board. The first ##
in the names of these files
is the board number in hex. Examples: b00
for the title
board, b0A
for board 10, bF9
for
board 249 (the highest possible regular board number), and
bFF
for the special temporary board that may sometimes
exist in save files. This number must be exactly two hex digits long.
Extra storage data for robots, scrolls, and sensors is stored in separate
files. The file bXXrYY
corresponds to the robot on board
XX
(hex) with the robot ID YY
(also hex). Values
from 01
(for robot 1) to FF
(for robot 255) are
valid. The same applies for scrolls and sensors. The robot/scroll/sensor
must exist on the board for its corresponding properties file to be valid.
These numbers must be exactly two hex digits long.
Filenames are case-insensitive. Prior to 2.93, they were case-sensitive and had to be all lowercase (aside from board/object numbers).
World, board, sprite, and object data are all stored in a simple extensible format created for MZX files similar to RIFF or a (very) simplified EBML. All internal files labeled "properties" use this format.
These files consist of an unspecified number of blocks of "properties" in the format:
Property data contents vary between different properties, so in the
property list specifications the expected contents are explicitly
defined. Most properties expect an int
value and accept
either 1 byte (equivalent to b
), 2 bytes (w
),
or 4 bytes (ds
) (expected size and signedness are explicitly
noted). The next most common stored type is a variable length
string
with no null terminator (equivalent to s...
).
string
s that are stored with null terminators are marked
(with \0)
.
The file ends immediately when a property ID of 0x0000
is
encountered indicating the end of the file. This value is the same for
all different properties files. Unrecognized properties IDs are usually
skipped unless noted otherwise. The EOF ID should always be present at
the end of the file and there should be no data after the EOF ID.
It is possible to nest properties files to create a file with a more complex structure (though MZX currently does not do this).
Global data is stored in a properties file for both world and save files. This is a common pattern in the new world format; save data is typically implemented as either extra properties only present in save files or (occasionally) as save-exclusive raw data files.
Unlike every other properties file in the format, the world properties file is very strict: every property expected for a particular file version must exist and must be in the order listed below. Also unlike other properties files in the world format, unrecognized properties in this file will usually generate an error. An integrity check is performed to enforce this early in the load process to determine whether or not the provided file is actually a world/save.
Additionally, compressing this file should be avoided, as it may be useful in the future for MZX to be able to peek at the contents of this file prior to initializing ZIP archive data structures.
SWAP WORLD
| int(b)
| `0x8030` | SMZX mode (0: disabled) | int(b) | Save-only before 2.91
| `0x8031` | Vlayer width | int(w) | Save-only before 2.91
| `0x8032` | Vlayer height | int(w) | Save-only before 2.91
| `0x8033` | Vlayer size | int(d) | Save-only before 2.91
| `0x8040` | Mod playing | string | Save-only
| `0x8041` | MZX speed | int(b) | Save-only
| `0x8042` | MZX speed is locked? | int(b) | Save-only
| `0x8043` | Commands per cycle | int(ds) | Save-only
| `0x8044` | Commands per cycle breakpoint limit | int(ds) | Save-only
| `0x8048` | Saved positions | array((w + w + b) * 8) | Save-only
| `0x8049` | Under player ID/param/color | array(b * 3) | Save-only
| `0x804A` | Player restart X | int(w) | Save-only
| `0x804B` | Player restart Y | int(w) | Save-only
| `0x804C` | Player color | int(b) | Save-only
| `0x804D` | Keys | array(b * 16) | Save-only
| `0x8050` | Blind duration | int(d) | Save-only
| `0x8051` | Firewalker duration | int(d) | Save-only
| `0x8052` | Freeze time duration | int(d) | Save-only
| `0x8053` | Slow time duration | int(d) | Save-only
| `0x8054` | Wind duration | int(d) | Save-only
| `0x8058` | Scroll base color | int(b) | Save-only
| `0x8059` | Scroll corner color | int(b) | Save-only
| `0x805A` | Scroll pointer color | int(b) | Save-only
| `0x805B` | Scroll title color | int(b) | Save-only
| `0x805C` | Scroll arrow color | int(b) | Save-only
| `0x8060` | Message edges enabled? | int(b) | Save-only
| `0x8061` | Built-in shooting enabled? | int(b) | Save-only
| `0x8062` | Built-in messages enabled? | int(b) | Save-only
| `0x8063` | Faded state (1: faded out) | int(b) | Save-only
| `0x8070` | Input filename | string | Save-only
| `0x8074` | Input file position | int(d) | Save-only
| `0x8075` | Input file delimiter | int(ds) | Save-only
| `0x8078` | Output filename | string | Save-only
| `0x807C` | Output file position | int(d) | Save-only
| `0x807D` | Output file delimiter | int(ds) | Save-only
| `0x807E` | Output file mode | int(b) | Save-only, 2.93+ (2)
| `0x8080` | Multiplier | int(ds) | Save-only
| `0x8081` | Divider | int(ds) | Save-only
| `0x8082` | Circle divisions | int(ds) | Save-only
| `0x8090` | Maximum simultaneous sound effects | int(ds) | Save-only, 2.91+
| `0x8091` | SMZX message enabled in SMZX mode? | int(b) | Save-only, 2.91+
| `0x8092` | Joystick presses simulate keypresses?| int(b) | Save-only, 2.92+
w+b
should be reopened in mode
r+b
. The output file is currently write-only, so
wb
and ab
are used in Robotic instead
of w+b
and a+b
for now.
If this file is present, custom SFX will be enabled for the world. If this file is absent, custom SFX will be disabled.
In versions 2.93 and up, the sound effects are stored as a properties file with a 8-byte header:
025Dh
) are invalid. The properties
follow immediately:
(NUM_BUILTIN_SFX * LEGACY_SFX_SIZE
bytes, where
NUM_BUILTIN_SFX = 50
and LEGACY_SFX_SIZE = 69
(for a total of 3450
bytes prior to compression). Each
individual sound effect must be null terminated. This format is still
allowed in 2.93+ version world files. If loaded into a 2.93+ world, all
custom sound effects after the first 50 and all names will be cleared.
This file is identical in format to the exported custom SFX file format, and files in 2.90+ world and save files can be used interchangeably with files created by SFX export.
The world character sets are saved as a single raw
charset file. In 2.90+ saves and 2.91+ worlds, all
15 user charsets will be saved for a total size of 14*15*256 = 53760
bytes prior to compression. Worlds from MZX 2.90 will only save the
main charset (for a total size of 3840
bytes).
The world palettes are saved as raw palette files.
In 2.93 and up, the file pal
always contains the 16
color palette corresponding to MZX mode and SMZX mode 1. If SMZX
modes 2 or 3 are active, an additional 256 color palette will be saved
to palsmzx
. If SMZX mode 3 is enabled, the palette indices
will also be saved as a raw palette indices file
in 2.90+ save files and 2.91+ world files.
In save files, the palette intensities are also saved. The file
palint
contains a raw array of 16 unsigned little endian
dwords representing the MZX and SMZX mode 1 palette intensities. If
SMZX modes 2 or 3 are active, an additional file palints
containing the SMZX modes 2 and 3 will be saved. This file contains 256
unsigned little endian dwords.
Only one pal
and palint
file were saved.
These files always contained 256 entries, and always represented the
current active screen mode. The palette intensities were stored as
bytes, which corrupted larger intensity values.
In SMZX modes 2 and 3, the MZX palette and palette intensities were NOT saved. For worlds/saves from these versions with SMZX modes 2 or 3 active, the MZX palette should be derived from the first 16 entries of the SMZX palette (same as 2.84X and prior) and the MZX intensities should default to 100.
In 2.90X save files, the palette intensities file was stored using the internal indices order, and was incompatible with palette indices files. For each color, the two middle indices are in reverse order.
The vlayer chars and colors planes are saved as raw data in two separate
files in saves (2.90 and up) and world files (2.91 and up). These files
are expected to be (vlayer_size)
bytes long, where
vlayer_size
is specified in the world properties. If one
of these files is missing, an error will be displayed and the plane will
be zero-initialized.
Sprite data is stored in a single properties file for all sprites with the following properties:
The counter and string lists are packed in the same binary format they were in prior versions, each in their own file.
The counter list file starts with the number of counters:
A list of N
counter definitions follows:
The string list file starts with the number of strings:
A list of N
string definitions follows:
Board data is stored in a properties file with the following properties:
Each board has 6 or 8 planes (depending on if overlay is enabled) saved
in separate files as raw data of size (board width * board height)
bytes each. If any of the expected planes are missing when loading a
board, an error will display and the plane will be zero-initialized.
Robot data is stored in a properties file with the following properties:
Scroll data is stored in a properties file with the following properties:
Sensor data is stored in a properties file with the following properties:
A MegaZeux board file begins with a 4-byte header:
FF
| 1 | s3 | Magic (MB2
for 2.00 through 2.51s1, same as world magic after)
A MegaZeux 1.x board file contains the raw data for a single board in the world format (including robots, scrolls, and sensors as-needed). These board files actually do NOT contain the above header; they begin exactly at the first RLE plane. See the world format documentation for boards for more info. A 25-byte null terminated board name follows the board data.
The header is immediately followed by the raw data for a single board in the world format (including robots, scrolls, and sensors as-needed). See the world format documentation for boards for more info. A 25-byte null terminated board name follows the board data.
The header is immediately followed by a ZIP archive containing the board properties, board planes, and object properties files for a single board. The following filenames are used:
Raw blocks of board and overlay/vlayer data can be saved to and loaded from MZMs (or MZX image files). Three variants of the MZM format exist. The current MZM format is MZM3, which was introduced in MegaZeux 2.84.
An MZM3 file begins with the following 20-byte header:
MZM3
| 4 | w | Width
| 6 | w | Height
| 8 | d | Location in file of robot data | 0 if not present
| 12 | b | Number of robots in data | 0 if not present
| 13 | b | Storage mode | 0: board, 1: layer
| 14 | b | "Savegame" MZM? (includes runtime robot data) | 0 if false, 1 if true
| 15 | w | World version | See below.
| 17 | b | reserved
| 18 | b | reserved
| 19 | b | reserved
The world version is stored as a 2-byte little endian value where the upper byte is the major version number and the lower byte is the minor version number (like the world version field in the save format header). MZM3 files are forward compatible unless they contain robot information, in which case the robots in the MZM are replaced with customblocks.
The header is immediately followed by a board data block or a layer data block depending on the storage mode value indicated in the header.
The MZM data is stored in the following format if the "board" storage
mode is selected. The data is composed of (width * height)
blocks, where each block is 6 bytes and contains the following:
Signs, scrolls, sensors, players, and IDs >=128 will be replaced with spaces when an MZM is loaded. Robots in a board MZM require extra storage information.
When a board MZM is created from the overlay or vlayer, the ID is typically set to 5, the param to the char, the color to the color, and all other values are set to 0.
The MZM data is stored in the following format if the "layer" storage
mode is selected. The data is composed of (width * height)
blocks, where each block is 2 bytes and contains the following:
MZMs using the "board" storage mode may additionally include a robot data block if the MZM board data contains robots. This block will always be located after the board data, and the format of this block is based on the MZX world format corresponding to the world version indicated in the header.
MZMs created in MZX 2.84X will contain N
robot blocks as
described in the 2.00 through 2.84X world format
documentation. If this is a savegame MZM, the robots will be in the
save format instead of the world format.
MZMs created in MZX 2.90 and onward will contain a ZIP archive after
the board data containing N
robot
properties files named in the format r##
, where
##
is a hexadecimal number between 1 and 255 corresponding
to a robot ID in the board data. If this is a savegame MZM, the robots
will contain savegame properties.
MZM2 was introduced in MegaZeux 2.80 and is essentially the same as MZM3 without the version field in the header. The MZM2 header is 16 bytes long:
The board data and robot data follows exactly as MZM3 with the exception that robots are always use the MZX 2.80 through 2.83 robot format rather than newer formats.
MZMX is the original MZM format that was introduced in MZX 2.68. It is much more limited than newer MZM formats and is generally only supported for compatibility. MZMX only supports blocks with dimensions of 255 or smaller, does not save robots, and only supports storage mode 0. The MZMX header is 16 bytes long:
The board data follows as described by MZM3's Storage Mode 0.
The counters file format is a light wrapper around the MZX 2.90+ save
format counter list and string list files.
Counters files are created and loaded by the SAVE_COUNTERS
and LOAD_COUNTERS
pseudo-commands and currently have no
standard filename extension. A counters file beings with this header:
COUNTERS
)
This header is followed by a ZIP archive containing only the
counter
and string
files.
The custom SFX table file format is exactly the same as the custom SFX table described in the 2.90+ world format. MegaZeux 2.93 and up can save sound effects in either the new format or in the old raw array format. All prior versions of MegaZeux that support sound effects export (2.00 through 2.92f) use the raw array format.
This section describes the general structure of Robotic bytecode. The
specifics are out of the scope of this document. More info can be found
in the file info_mzx.txt
distributed with MegaZeux source
packages.
FF
.
LL XX ... LL
, where LL
is the length of the
bytecode command (0-255) and XX
is the command number. The
length does not include the length bytes themselves, only the command
and parameters between them.
00 XX XX
, where
XX XX
is a little-endian word, or
LL [string] 00
, where LL
is the length of the
null-terminated param string that follows (including the null
terminator). The number of required params varies between commands.
00
(indicating a command of length zero)
terminates the program.
FF 00
with a length of 2.
Copyright © 2020-2024 Lachesis — https://github.com/AliceLR/megazeux/
Permission to use, copy, modify, and distribute this document for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE DOCUMENT IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS DOCUMENT INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS DOCUMENT.