Tools‎ > ‎zzplayas‎ > ‎

zzplayas manual


If you're having issues, please confirm the following things:

  • You're using zzconvert's "Embed manifest" and "Link hierarchy" options.
  • The custom model uses Link's default skeleton and is in the default rest pose.
  • You have applied location, rotation, and scale to the object and skeleton before exporting.
  • You aren't scaling to a value either too small or too large.
  • Your object group names match those defined in the manifest you're using.
  • Everything is cAsE-sEnSiTivE.
  • If you have no idea what any of this means, please read the Blender Play-As tutorial!

Manifest Terminology

  • Bank object: An already-existing Link object that contains all of Link's pieces
  • Manifest: A basic scripting file that tells zzplayas what to do
  • Display list: A model part; many of these combine together to display Link in-game
  • Custom Link: A new Link file generated by zzconvert

Manifest Format

Manifest files intended for use with zzplayas are divided into three sections: DICTIONARY, OBJECT, and REPOINT. Each section always has a line containing END to specify its end. This is all case-sensitive. Place // before something and it will be regarded as a comment.

Dictionary Section

This is where variables are defined. The names of some entries must remain unchanged (HIERARCHY_CODE, SEG, VROM_CODE, and VROM_OBJ). To define a variable, include its name, offset, and an optional ASCII identifier all on the same line, in that order. Here is an example:

DL_HAMMER            0x0184A8    "Hammer" // Megaton Hammer

Entries prefixed with DL_ are treated as display lists, so follow that naming convention for all model parts.

In DL_ entries, the offset provided is the offset of a display list that exists in the bank object, in case the custom import lacks a display list that matches the provided ASCII identifier. In the above example, the Megaton Hammer from Link's original file will be used if the custom Link doesn't contain a display list of the name "Hammer".

VROM_ARMS_HOOK        A_102        // Arms_Hook

This shorthand applies to only the OoT debug rom at this time, but an address can also be specified as an actor number (prefix A_), an effect (particle) number (prefix E_), or an object number (prefix O_). This is helpful in case these files are ever moved, as the manifest remains relevant even after modifying the rom. As of revision 1, this shorthand will be used to locate files within a zzromtool project tree. A, E, and O correspond to the actor, particle, and object folders, respectively.

As of revision 1, you can do this:

VROM_CODE     0xA94000     "system/code"

What's going on here is, VROM_CODE is being defined as starting at 0xA94000 in the debug rom, and in the case a zzromtool project tree has been provided to zzplayas, a relative path to the file to edit. To take advantage of this feature, the label name must start with the text VROM. The labels VROM_CODE and VROM_PLAYER will default to system/code and system/ovl_player_actor.zovl respectively if no files are specified.

For obvious reasons, please do not name an entry END. The tool will not know what to do.

Object Section

This is where additional code to include in the customized Link object can be written. Similar to the dictionary section, entries will be defined here and called by name in a later section. Unlike the dictionary section, entry names must be followed by a colon (:).

As of revision 2, you can specify a pool for the object section to use by writing POOL=0xStart,0xLength on the same line as OBJECT. For example, OBJECT POOL=0x5000,0x800. It must be formatted exactly like that (no spaces except for before POOL, one comma, hexadecimal, etc). This particular value pair will cause the contents of the object section to be written starting at 0x5000 in the play-as ZOBJ. If it happens to run into enough data that it exceeds the 0x800 byte limit, it will provide diagnostics. To ensure empty space will always exist at 0x5000, just edit Link's mouth texture list to contain additional blank 32x32 textures after his primary four. Each one you add extends the pool by 0x400 bytes. This is useful for creating display list aliases so you can hot swap all ZOBJs generated from the same manifest.

Allowed functions:

Matrix(XR, YR, ZR, XT, YT, ZT, XS, YS, ZS);
Write a 0x40 byte matrix following the Nintendo 64's matrix specification. You can specify rotation, translation, and scale along all three axes.

Reference a previously-defined matrix by name.

Reference a previously-defined display list from either the dictionary or object section by name.

Will undo x matrices.

HexString(00 01 02 03 etc);
Write bytes to file. The only real application for this in this section is to use pre-compiled matrices. When using this, make sure the bytes you write end up totaling a number evenly divisible by 8, because it will not do any alignment for you. Be careful not to shoot yourself in the foot using this function.

Practical example:

Matrix( 0, 0, 0, -715, -310, 78, 1, 1, 1 );

Matrix( 0, 0, 180, 935, 94, 29, 1, 1, 1 );

CallList( DL_SWORD_HILT );
PopMatrix( 1 );



Repoint Section

This is the section that contains the instructions for patching the generated object into the rom.

Allowed functions:

Go to an offset within the rom. Previous entries can be specified by name, or absolute addresses can be provided. The addition (+) operator can be used to add offsets together.
Set how many bytes the cursor should advance in the rom after each write. Because the rom pointers for both Links are stored in an interlaced fashion, using this feature to skip the other Link's entries keeps the manifest cleaner.
Write a 32-bit value to the rom (4 bytes)
Write a 24-bit value to the rom (3 bytes)
Write a 16-bit value to the rom (2 bytes)
Write an 8-bit value to the rom (1 byte)
Write the upper half of a 32-bit pointer, altered for assembly purposes.
Write the lower half of a 32-bit pointer, altered for assembly purposes.
Writes a floating point in IEEE-754 notation
HexString(00 01 02 03 etc)
Write bytes to rom. Useful for embedding assembly patches, but be careful not to shoot yourself in the foot with this. SetAdvance rules are ignored by this function. One byte read means one byte advanced.

Practical example:

GoTo( VROM_CODE+0x001091BC );
SetAdvance( 4 );
Write32( DL_BOOT_LIRON ); //Left Iron Boot
Write32( DL_BOOT_RIRON ); //Right Iron Boot
Write32( DL_BOOT_LHOVER ); //Left Hover Boot
Write32( DL_BOOT_RHOVER ); //Right Hover Boot

// Arms_Hook
GoTo( VROM_ARMS_HOOK+0x00000A6E ); //Hookshot / Longshot Spike
GoTo( VROM_ARMS_HOOK+0x00000A72 );

GoTo( VROM_ARMS_HOOK+0x00000B8A ); //Hookshot / Longshot Chain
GoTo( VROM_ARMS_HOOK+0x00000B8E );

GoTo( VROM_ARMS_HOOK+0x00000BE8 ); //Hookshot / Longshot Object File
Write16( OBJ_BOY );

// ovl_Effect_Ss_Stick
GoTo( VROM_SS_STICK+0x0000035C ); //Broken Piece of Giant's Knife

GoTo( VROM_SS_STICK+0x00000358 ); //Giant's Knife / Biggoron Sword Object File
Write16( OBJ_BOY );