ZZT.EXE Modification
by David Hammond (Nanobot)

This file will help to explain how some things in the ZZT.EXE binary work and how to edit them. Please note that it is by far incomplete, but hopefully it will get you in the mindset to be able to understand some of the code and how to modify it correctly.

 COMPRESSION

First of all, ZZT.EXE has been compressed using LZEXE v0.91. You will need an EXE decompressor, like UNLZEXE, to more easily recognise parts of the program. You may find a copy of UNLZEXE along with ZZTPATCH, in Z2's Utilities section.

 MODIFICATION

To edit the EXE, you will need a binary editor. Something like notepad will NOT work. EDIT.COM, which comes with most computers, has an option to open a file as a binary. Problems may occur if you try to open and save it as a regular text file.

 STRING LENGTH PREFIXES

When there is a string of text that is to appear on the screen, it is almost always preceded by a single character that specifies the length of the string. Character #1 reads the following character, #2 reads the two following characters, etc. Be sure that if you shorten a string such as a command or built-in label whose size ZZT is dependant on to make it work, you reduce the length indicator as well.

 BUILT-IN SOUND EFFECTS

Sound effects are stored in a very simple system. The odd characters in a string of sound, relative to the start of the string, are the notes, and the even characters are the note lengths.

The notes are laid out in a simple 16-based system. Each octave begins on a multiple of 16. Number 48 (0) is C in the default octave. From there, each higher multiple adds a "+" sign, and each lower multiple adds a "-" sign, in terms of ZZT-OOP musical strings. The next single value from a multiple of 16 is C#. It then goes D, D#, E, F, F#, etc. Notice there are four left over at each multiple of 16. These don't produce any sound. Percussions are put in the last multiple of 16 that may be stored in a byte (240-255). 240 is Percussion #0, 241 is #1, etc.

The note lengths, too, are in a simple system. Instead of thinking of T being a thirty-secondth of a note, think of it as 1/2 of a cycle. Character #1 is T. #2 is S, but let's think of that as 1. #3 is 1 1/2 (S.), #4 is 2 (I). Now here's why you should think of it as raising by 1/2 rather than raising in T/S/I/Q/H/W length: #5 is 2 1/2. ZZT cannot play that length in a regular PLAY command. Here's a quick reference table if you don't want to bother counting:


CHR|LENGTH|CYCLES
1  | T    |  0.5
2  | S    |  1.0
3  | S.   |  1.5
4  | I    |  2.0
5  |      |  2.5
6  | I.   |  3.0
7  |      |  3.5
8  | Q    |  4.0
9  | I..  |  4.5
10 |      |  5.0
11 |      |  5.5
12 | Q.   |  6.0
13 |      |  6.5
14 |      |  7.0
15 |      |  7.5
16 | H    |  8.0
17 |      |  8.5
18 | Q..  |  9.0
19 |      |  9.5
20 |      | 10.0
21 |      | 10.5
22 |      | 11.0
23 |      | 11.5
24 | H.   | 12.0
25 |      | 12.5
26 |      | 13.0
27 | Q... | 13.5
28 |      | 14.0
29 |      | 14.5
30 |      | 15.0
31 |      | 15.5
32 | W    | 16.0

It's easy to recognise strings of sound in ZZT.EXE if you know what to look for. First of all, the note lengths usually remain pretty consistant in the built-in sounds, so if you see one specific char repeated every other byte for a short length, it's probably a sound. Also, because every note comes with a note length character and vis-versa, the string length indicator will always be an even number character directly before a string of notes. Remember to use to the string length indicator to make sure you're seeing all of the notes in the string and none more.