Tools‎ > ‎zzromtool‎ > ‎

zzromtool manual

This manual currently covers the following topics:
  • Filesystem specification
  • overlay conf
  • scene conf
  • code1
  • Routes
  • Entrance cutscenes
  • Animation banks
  • misc directory
  • repoint.tsv
  • route.txt
  • Sounds and music
  • Adapting old tutorials
  • scene TEXT-DATA

Filesystem specification

zzromtool isn't magic. It expects folders to follow a certain specification, and if they don't, it may crash. When you dump a rom, the following files and folders are created. As you make changes, keep these things in mind about each.

actorThis folder contains every actor overlay in the game.

Every folder within this folder must start with a number. For example, '2' and '2 - Stalfos' are both suitable names. 'Stalfos - 2' is not.

Within each folder, the name 'actor.zovl' is expected for the actor, with initialization values and other settings being stored within 'conf.txt'. If zzromtool fails to locate either, the entry will be skipped.

conf.txt must remain below 1 KB. If parsing it fails, the program will complain and exit. Values in conf.txt are assumed to be decimal unless preceded by 0x for hex.

The actor overlay itself has the magic string scubadiver in place of the first part of its initialization data so the program can find them during import. The affected values are Type, Room, Flags, and Object. These get pulled from conf.txt during import. Keep this in mind when working with custom actors.

Read overlay conf for information on the other parts.

anim
This folder contains Link's external animation data. See Animation banks for more info.

cache
When building a compressed rom, this folder is created to store a compressed copy of every file in the game. The initial compression should take no longer than 5 minutes. Subsequent compressions will reference this cache for files that have not been changed, cutting compression time from minutes to seconds.

misc
Contains miscellaneous files such as Link's animation data, all the game's text, the font, etc. See misc directory for more info.

object
This folder contains every object file in the game.

Every folder within this folder must start with a number. For example, '50' and '50 - Stalfos' are both suitable names. 'Stalfos - 50' is not.

Within each folder, the name 'object.zobj' is expected for the object. If zzromtool fails to locate it, the entry will be skipped.

particle
This folder contains every particle effect in the game.

The folder structure is the same as actor, with some slight differences.

The first four bytes of initialization data are overwritten with the magic string tuna so the program can find them during import. When writing custom particle overlays, keep this in mind.

Read overlay conf for a generalized explanation.

patch
Novelty feature for compartmentalizing multiple edits to the same file. Read patch directory for an example. Introduced in revision 0.

scene
This folder contains every scene (map) in the game.

Every folder within this folder must start with a number. For example, '85' and '85 - Kokiri Forest' are both suitable names. 'Kokiri Forest - 85' is not.

Within each folder, the name scene.zscene is expected for the scene. If zzromtool fails to locate scene.zscene, it will choose whatever file with the extension .zscene (case sensitive) it finds first. If zzromtool still fails to locate a scene, the entry will be skipped.

Also within each folder, room_x.zmap is expected for each room, with x starting at 0 and incrementing by 1 for each. If filenames of the form room_x.zmap are not found, it will search for files with the extension .zmap (case sensitive) and use the last number found in the filename for x. If it finds a scene but no rooms, it will complain.

External scene settings will be stored in conf.txt. See Adding scenes (maps) for an explanation of how it works.

An optional title.png can be included in a scene's folder to use as the title card when entering an area.

shader
These are more formally considered "scene render initialization functions", but that's a mouthful.

Each sub-folder name is expected to start with a number. Counting starts at 0 and numbers should not be skipped. This is the order in which they are indexed and referenced by scenes, so keep that in mind.

A file shader.bin is expected in each folder. If one is not found, the entry is skipped.

Shader assembly should contain only one jr ra, and at the end of the function. Shaders are how scrolling textures, day/night textures, pulsing colors in places like Death Mountain Crater, etc are possible.

When a guide for custom shaders is written, a link will be added here.

skybox
Currently unused

This folder contains every sky box in the game.

Inspect the contents of this folder. They are self-explanatory. You are limited to editing existing sky boxes only. Adding new sky boxes will break the program.


system
This folder contains files most people won't be tampering with. Edit them only if you know what you're doing. Some of these files support being made larger, but not all.

repoint.tsv
Contains a list of pointers to update across files that have hard-coded references to other files. See the repoint.tsv section of this document.

route.txt
Configures how scenes are to be routed together. See Routes section of this document.

entrance-cutscenes.txt
Configures when and where entrance cutscenes should play. See Entrance cutscenes section of this document.


overlay conf

The conf.txt within an actor folder looks like this:

Initialization
    Type    0x01
    Room    0x00
    Flags   0x00000000
    Object  402
Allocation        0x00000000
Reserve           0x00000000 (disabled as of revision 3)
VRAM              0x80B959D0

Everything indented below Initialization gets written into actor.zovl during import, when the program finds the magic string scubadiver within the actor. The reason for this is to make it easier to share assets between projects, and also make it possible for the program to have a means of detecting where the initialization data is stored within the actor. Otherwise, you'd have to point to the initialization data directly, and every time you rebuild the actor (assuming it's custom), the initialization data may move, and thus there would be an extra step after each rebuild: manually adjusting the pointer within conf.txt. This is to avoid such madness. tl;dr: In your custom actor's source, use the string scubadiver in the appropriate section of the initialization data.

As of 0.01 revision 2, an additional search method is available:
In an actor's initialization data, the first two bytes, which normally represent the actor's number, should be replaced with the bytes 0xDEAD. Ten bytes later are two unused padding bytes, which we replace with 0xBEEF. See seagull.c for an example of this applied in C. You may also omit the Initialization section of conf.txt.
* During import, 0xDEAD is replaced with the number of the folder the actor is in, and 0xBEEF is replaced with 0x0000.

Allocation is for allocation type, described on the wiki.

Reserve is a hackish setup for how many bytes follow the overlays in VRAM. Some overlays reserve a few bytes beyond the end of themselves. For relaying information between multiple instances, I would assume. ex: the Lizalfos tag-team
Disabled as of revision 3 (it turned out to be unnecessary clutter.)

VRAM is basically the relative start address that was used when compiling the actor. If you change this value for an actor, you'll have to rebuild it from source. If you're writing a custom actor, this will most likely be 0x80800000 and you'll never worry about it beyond that.

The same rules apply for particle overlays, but the magic string is tuna instead of scubadiver, and the only parts of conf.txt are Reserve and VRAM. They work the same way as described above.

Custom actor and particle overlay examples will be posted below as they are made.

scene conf

The conf.txt within a scene folder looks like this:

   unk-a: 0
   unk-b: 0
  shader: 4
    save: 85
restrict: 16

unk-a and unk-b refer to unknown parts of the scene format. See the wiki for more information on that.

shader refers to the scene render initialization function used for the scene, or shader for short. In this example, the value 4 indicates that the shader in the folder shader/4/shader.bin is the one used here.

save refers to the save data slot used by the scene, for storing flags like cleared puzzles. By default, every scene in the game has its own save data slot, but due to the nature of the save file format, we won't be expanding it any time soon, meaning the best way to add new scenes to the game and still have flag storage available for them is to have scenes share save data slots. This is feasible because most outdoor scenes in the game use little to no flags. Dungeons, which are very flag-heavy, should not share flags, but you're free to make even dungeons share flags if you want to. This value should not exceed 100.

restrict is a decimal value containing restriction flags. Read more about restriction flags here. A helper utility for generating restriction flags would be nice, perhaps something that would embed into a webpage. I'm looking at you, CrookedPoe.

Numbers are all decimal, not hexadecimal.

code1

Thanks to the one-and-only CloudMax, we have an additional code file, which we'll dub as code1. The max on this is 1 MB (0x100000 bytes). All custom assembly should go in this file. Custom shader functions will automatically be appended to code1 during the build process, so try to keep it a few KB short of 1 MB. It is recommended to keep this file small and only expand as needed. code1 starts at 80700000 in ram, so a function or data stored at the offset 0x50 (to make an example) would be accessed through the ram address 80700050. code1 is located in the system folder.

As of revision 3, you can edit the CODE1VRAM=0x80700000 in the ZZRP file to any other ram address that suits your needs.

Entrance cutscenes

Find and open entrance-cutscenes.txt. Its contents are formatted as such:

Route   Age    Flag   Offset
389     2      0xA0   02013AA0

The first line in the file describes which columns do what.

Each subsequent line specifies how and when each entrance cutscene should be played.
  • Route specifies which route (decimal) Link must travel through to activate the cutscene.
  • Age specifies which Link activates the cutscene. (0 = Old, 1 = Young, 2 = Both)
  • Flag is how the game knows if the cutscene has played or not. The value used for flag specifies which slot of event_chk_inf to store this information in. This will be unique for every entrance cutscene except for the Epona escape cutscenes, which share the same value so the game knows the player has acquired Epona.
  • Offset specifies the offset (hexadecimal) of the cutscene data within the scene file. For custom maps with custom entrance cutscenes, you may not know what value to use here. Write 0_AUTO and zzromtool will use the first cutscene it finds in the scene. If it doesn't find any, it will complain. You can specify n_AUTO to use the nth cutscene found in the file. n is a decimal number. Counting starts at 0, meaning 0_AUTO is the first found. Keep in mind it is up to the map converter you use to have an implementation of TEXT-DATA in order to use the auto-detection feature. Read scene TEXT-DATA for implementation details.
  • Route   Age    Flag   Offset
    389     2      0xA0   0_AUTO
  • or...
  • Route   Age    Flag   Offset
    389     2      0xA0   1_AUTO
  • etc

Animation banks

Inside the misc folder, Link's animation data resides in the form of two files: link_animetion and link_animetion_table [sic]. Due to the nature of how Link's animation table is referenced by the game, the program does not yet offer a solution for adding animations, only replacing. On the plus side, a custom animation can still have either more or less frames than the one you're replacing.

When the Blender plug-in for generating custom Link animation data is ready, a link to a tutorial will be posted here.

misc directory

This directory contains miscellaneous files that don't really belong anywhere else. The contents of this folder are not compressed during the compression routine, much like the original game. A folder named comp exists within misc, for storing files meant to be compressed. This is intentional by design, as some files in the game are not meant to be compressed. Please do not move existing files from misc to comp unless you know what you are doing.

The order in which these files are placed in the rom is based on the contents of repoint.tsv, except that the contents of comp are loaded in after the contents of misc.

misc can contain more folders than comp. By default, the program will create skybox and another comp folder within skybox. The comp directory in this case gets compressed as well. As a general rule, any file reference containing /comp/ gets compressed. This applies even to new folders you create and the folders within them. Please reference skybox directory for more information on the naming schemes used for skyboxes.

The files in these directories should NOT have extensions.

Files not referenced within repoint.tsv will be skipped.
Examples include: test.zobj, link_animetion_table.zdata, notes.txt

repoint.tsv

Some files in the game don't belong in any kind of table and are otherwise unreferenced. Couple this with the fact that they are often referenced across multiple files via hard-coded pointers and you have a recipe for trouble when moving files around in the rom. repoint.tsv exists as a crude remedy. You can edit it in a plain text editor such as Notepad++, but you may have an easier time working in a tool that can parse TSV, such as LibreOffice Calc.

repoint.tsv should only be used to describe files stored in misc for now.

Files described outside of misc will be imported twice: once when parsing repoint.tsv, and again when dealing with the file's primary reference.

Every row follows this format:

File     High     Low     Point To     DmpSz     Notes

The meaning of each column:

File     file to modify

High     offset of the opcode containing the upper half of the pointer

Low      offset of the opcode containing the lower half of the pointer
         if FFFFFF, High is considered to be the whole pointer

Point To file of which the pointer will be written
         if .end is appended, the pointer points to the end of the file

DmpSz    the size of the file when it was dumped
              you won't be editing this and it's used internally only

Notes    store notes in this column
         this is the only column that is optional

Filenames may not contain spaces.

Please keep less than 4096 entries in this document.

The initial dump creates a repoint.tsv based on assumptions about a rom that hasn't undergone major modifications. You can get away with never modifying this file, but if you do any complex wizardry, you may find yourself changing its contents to better fit your needs.

Finally, here's an excerpt from it to drive the point home:

system/ovl_file_choose.zovl    00DCF0    00DD08    misc/title_static
system/ovl_file_choose.zovl    00DCF4    00DD04    misc/title_static.end

The pointer split between the opcodes 0xDCF0 and 0xDD08 in the file ovl_file_choose.zovl in the directory system will be updated to reflect the new start offset of the file title_static in the directory misc.

Then, the same is done for the end offset of title_static.

As of revision 0, you could can do misc/title_static.size for the size of the file.

route.txt

This file contains information on how scenes are linked together. Because the terms exit and entrance tend to confuse, we've gone with route here to confuse people even more.

Here's a direct copy and paste from the file:

#Index  Scene  Spawn  Music  Title  FadeIn  FadeOut
     0      0      0   STOP     ON       2        2
     1      0      0   STOP     ON       2        2
     2      0      0   STOP     ON       2        2
     3      0      0   STOP     ON       2        2

Let's get this out of the way first: all numbers are decimal.

Also, you can add comments by writing the # character. Anything after it on to the end of the line will be ignored when parsing.

Index: The "exit" number used on collision in maps to warp Link somewhere

Scene: The scene that this will warp Link to when he walks on it. It corresponds directly with the numbering of the scenes in the scene folder in a dumped rom.

Spawn: The spawn point within the scene specified for Link to spawn at.

Music: Will either be STOP or GO. STOP makes the music that's playing stop while warping so the next song can fade in. GO is for if the music is to remain playing. A good example of GO is when you enter the Sacred Forest Meadow from the Lost Woods. The music keeps playing.

Title: ON or OFF; determines if the title card displays or not when entering the scene specified.

FadeIn: The effect used when fading into the next scene when entering it.

FadeOut: The effect used when fading out when warping to the next scene.

Finally, a note on how these values are used and why there seem to be three additional copies for each route. Let's say you set the collision to warp Link through route 0. The game does the following:

Is it currently night?
Yes
Add 1

Is Link an adult?
Yes
Add 2

Route 0 takes you to the Deku Tree. If it's night, route 1 is used. If Link is an adult and it's day, route 2. If Link is an adult and it's night, route 3. This is why every route has so many variants: to account for these different situations. So if you edit or add any routes, it's a common pitfall to not also edit the "copies". They will always be in groups of four, unless you write an assembly hack that does otherwise.

skybox directory

Ignore this section for now. You can use dedicated texture tools to edit the raw data in the misc/skybox directory.

When the program is doing a filesystem dump, it references repoint.tsv, which contains information on how to dump sky boxes. The encoded binaries for the sky boxes go in misc/skybox/comp and their palettes go in misc/skybox. This must remain consistent due to assumptions that are made during the build process. These are converted to PNG in the main skybox directory in the project's root directory for easier editing.

When changes to these PNGs are detected, they get compiled back into the misc/skybox/comp and misc/skybox directories. Let's make an example of a custom majora.png skybox. It gets indexed and its palette gets saved as majora_pal in misc/skybox. Then, the skybox itself gets saved as majora in misc/skybox/comp. The whole thing is forced to use one 256-color palette.

If you want to have a sky box that uses a massive palette (one sub-palette per sub-image), you'd name as majora#0.png, majora#1.png, etc. This pattern is detected and majora_pal and majora files are generated accordingly.

If this is confusing, please reference the skybox directory generated when dumping a rom. Compare the contents of misc/skybox and misc/skybox/comp, and it should explain itself a little better.

Sounds and music

The audio files are stored in misc and named audiobank, audioseq, and audiotable. To use custom music, you will need to rip the modified equivalents from your edited rom and overwrite the ones in the folder.

Adapting old tutorials

Say you found a tutorial that tells you something like this.

Go to 0xB9D1A8 in the rom and write the bytes FF 99 EE to make the Kokiri Tunic pink

You can't follow these instructions, as there is no rom. You're editing the contents of the filesystem directly. If you plan on following any instructions like this, you'll have to apply them before the initial dump. You can't apply these changes after a rebuild, because the build process rearranges nearly every file.

Alternatively, you can just edit the files directly. These instructions would translate to:

Go to 0x1091A8 in the file "code" and write the bytes FF 99 EE to make the Kokiri Tunic pink

Once you rebuild the rom, you have a pink Kokiri Tunic.

How was this done? Well, if you look at the offset 0xB9D1A8, you'll notice it's between the offsets 0xA94000 and 0xBCEF30, which is the block that the file named code is stored in.

Now that we know what file the byte(s) are in, we need an offset relative to the start of that file. Open your calculator, switch to Programmer/Scientific/whatever Mode, and then switch the notation to Hex.

Now we use this formula to get the offset relative to the start of the file.

rom offset - file start = relative offset

That would be

0xB9D1A8 - 0xA94000 = 0x1091A8

I'm sure these instructions are grating for anyone who already knows this stuff, but we have to teach the next generation somehow, don't we? 8)

patch directory

Walter and Max are fighting over how to merge commits on system/ovl_player_actor.zovl. With the addition of the patch directory, they don't have to. Walter compiles his mod into a CloudPatch named system#ovl_player_actor.zovl(walter).txt, and Max labels his likewise. The two patches are dropped into the patch directory, and the file system/ovl_player_actor.zovl gets both patches applied during the build process. The original file remains unmodified so a clean file is patched each time, and the two proceed to argue over the purity of pseudo instructions.

Let's break down this path name

system#ovl_player_actor.zovl(walter).txt

Everything in parenthesis is regarded as a comment and discarded. The comment is here so we know whose is whose. Then every # character gets replaced with a / character. Finally, .txt is dropped. The .txt is how the program detects it's a CloudPatch, and more patching features may be added in time.

system/ovl_player_actor.zovl

We are left with the path to the file in question, relative to the root of the project folder.

Now here's an example of a simple patch to change the tunic color. We create a patch directory in the root project folder, and place a .txt within that we name as such:

system#code.txt

As for the contents, we do:

0x1091A8,FF99EE

0x1091A8 is the offset of the Kokiri Tunic color within the file system/code. FF99EE are the bytes we're writing. Alternatively, you could do something like this to combine multiple edits at multiple offsets into one patch file:

0x1091A8,FF
0x1091A9,99
0x1091AA,EE

This is a lot of trouble to change the tunic color, and you will most likely not even use this feature unless you're doing weird assembly stuff with big files and have multiple people placing their own code chunks at different offsets within the file.

As of revision 3, zzromtool will throw errors if there happens to be a patch that it can't find the matching file for.

scene TEXT-DATA

This is a shoddy method of storing additional information in a scene file, like entrance cutscenes, which are not referenced anywhere else within a scene file and are therefore not reliably detectable. If you would like entrance cutscenes to be automatically detected in custom maps created in your software, you'll need a TEXT-DATA implementation. It's very simple.

At the end of the scene file, and at an offset that is 16-byte-aligned (offset ends in 0x0, not 0x8), there will be the bytes:

23 40 21 54 45 58 54 2D 44 41 54 41 21 40 23 30

or, as text

#@!TEXT-DATA!@#0

where the trailing '0' character is for version tracking. It will likely never change, but it's there just in case.

Immediately after this 16-byte identifier is text data, all the way to the end of the file.

supported "commands"

entrance_cutscene(x)
x is a hexadecimal offset to cutscene data within the scene
ram segment 02 is required

example
If you want to specify the offsets 0xF9E0 and 0xFF00 as entrance cutscenes, for example, that data would be formatted within the TEXT-DATA section as such:

entrance_cutscene(0x0200F9E0)entrance_cutscene(0x0200FF00)

Finally, the TEXT-DATA section and everything after it are excluded when scenes are imported into the rom, so don't worry about any space going to waste.