Zelda GCN: STB Cutscene Files
NOTE: This page is so outdated it's not even funny. I'll have to go through and fix this mess ASAP.
The Legend of Zelda: The Wind Waker stores cut scene data in files with the suffix .stb. These files contain camera directions, actor X/Y/Z data and animations, text, particles and music. All of these are stored under different sections somewhat randomly scattered throughout the file.
The first three bytes of the file are the ASCII letters STB, followed by the values 00 FE FF and 00 03. The four bytes after that are reserved for file size in hex.
|0x00||4||"STB\0"||Format magic number, indicates that the file is indeed a cutscene file.|
|0x04||2||0xFEFF||Byte order marker|
|0x06||2||0x0003||Unknown (Could be version)|
|0x08||4||varies||Total length of the file|
|0x0C||4||varies||How many sections are in the file.|
The JACT header is used for actor-related data. It typically follows this format:
xx xx xx xx J A C T 00 00 00 uu yy yy yy zz zz zz zz zz zz zz zz zz zz zz zz zz zz zz zz zz zz zz zz zz zz zz zz zz zz zz zz zz zz 04 07
x = Size of the entry
y = ID of actor
z = X/Y/Z coordinate and rotation data. This needs to be separated into X, Y and Z.
Note that the size of the actor ID and coordinates vary from section to section.
The rest of the data in JACT is typically animation data. It follows this format:
59 00 uu 00 xx 00 04 08 62 00 00 00 yy 00 04 07 63 41 F0 00 00 02 00 00 C8 80 00 00 20 00 04 09 62 41 A0 00 00 04 07
x = Animation. This is the what number the .bck is in the archive, starting from 0x01 (IE, if an animation was the first file after all the header information, it would be indexed as '1').
y = Loop type
u = Unknown
Note that these entries do not have a uniform size and vary from section to section.
JFVB holds data used for animated actions. Typically these actions are only related to the camera (JCMR), but it's possible that
other objects could use it, too.
Different commands utilize the entries in the FVB object for different things. The animated Field of View and Roll commands use
1 entry, while the animated camera and target positioning commands use 3 - one entry for each axis (X/Y/Z).
JFVB consists of a header that is 18 (hex)/20 (dec) bytes long, and a variable number of entires, which themselves are variably sized. The header begins at offset 0x20 (hex)/32 (dec) in an STB file, and follows this format:
/*+0x00*/ int totalSize; //size of the object from 0x00 /*+0x04*/ string "JFVB"; /*+0x08*/ string "FVB"; /*+0x0C*/ Unknown; //shouldn't worry about it, it's the same everywhere /*+0x10*/ int fvbSize; //size of the section from 0x08. I dunno, it's weird /*+0x14*/ int numEntries;
The entries themselves seem to mimic the other objects in that they are technically composed of commands, but the structure is the same across nearly all of them. The first entry in an FVB object is at 0x18 in the object, or 0x38 in the entire STB file. These fields are common for all entry types:
/*+0x00*/ int entrySize; /*+0x04*/ int16 entryType;
The entry type seems to determine something, but I don't know what yet. The majority of the entries have a type of 5, but some
have a type of 6. There are major differences in commands between the two.
In a type 5 entry, there are typically 3 commands - animLength, interpType, and data. While these follow the command syntax found in the other object types, I will forego explaining it here in favor of doing it elsewhere where it would be more useful. The offsets of the commands are as follows:
+0x08 animLength +0x14 interpType +0x1C data
animLength is C (hex)/12 (dec) bytes long, and seems to give an inconsequential estimate as to how long the animation is in-game.
The relavent floating point data can be found at 0x08 relative to the command, or 0x10 relative to the start of the entry itself.
interpType seems to be how the engine interpolates between the points. The default value is 3, which is a smooth spline
running through each of the coords. The data here begins at 0x04 relative to the start of the command.
data holds what JFVB was designed to hold - floating point coords. It is structured like so:
/*+0x00*/ int16 loadLength; //length of the command starting from 0x04 /*+0x02*/ int16 commandType; //this just indicates that it holds the coord data /*+0x04*/ int numCoordPairs;
Coords start at 0x08 relative to the command, and 0x24 to the entry. They are 8 bytes long. The first 4 are the
interpolation timestamp, and the last four make up the actual coordinate.
The timestamp controls when the engine interpolates to the coordinate that it preceeds, which controls the speed
and smoothness of the animation. They act as a sort of timeline, giving the engine at what time since the animation started
it should be at the coord. The data is length in seconds, encoded in floating point.
Every entry is padded at the end by 4 null bytes. These are counted in totalSize and fvbSize, but NOT in the data command.
Source: Sage of Mirrors
Text pointers. To do.
Particles from the .jpc particle banks. To do.
Unknown. To do.
Sound effects and music. To do.
Details how the camera will behave during the cutscene.
00 0C 03 x2
This command defines coordinates. Its load is always 3 four-byte fields, but their purposes differ depending on the value of x.
If x is either 0 or 8, the load will be three floats. 0 defines the actual position of the camera, while 8 defines the point in space that the camera is looking at. x values of 1 or 9, however, determine that the coordinates are actually in the FVB element. In this case, the load is actually the index of the FVB entry to grab the coordinates from. 1 is analogous to 0, and 9 is analogous to 8.
00 0C 03 82 | C3 B7 80 00 43 B3 00 00 42 48 00 00
00 04 04 x2
This has a variety of uses, and the exact purpose of the command is determined by the value of x. It will always have a load of four bytes.
0xC is camera rotation, determined by a float. A zeroed-out load is common for for this value, and means that the camera is right-side up.
0xD is an animated version of 0xC. The load here is the index of the FVB entry that holds the values to use for the animation.
0xE means that the load is one float. This float sets the camera's field of view. It stays in effect until it is redefined or the section ends.
0xF is the FVB-entry version of 0xE. With the FoV data provided by the specified FVB entry, it'll make a smooth zoom out or zoom in.
00 04 04 E2 | 42 20 66 66
Sage of Mirrors (AKA Gamma, Zeal)