Hack64 Wiki
Other Titles
Hack64 Wiki
Other Titles
Each hole in the game is made up of seven different components that each define their own subset of the hole layout:
Where the file extensions listed above are taken from leftover debug text within the ROM. A description of each component and its file format will be provided below.
The function to load the majority of these components is:
void loadHoleComponent(int holeNumber, int courseNumber, int componentNumber) // 0x80251DFC (US version)
Where componentNumber
takes values:
1 - geometry 1 2 - geometry 2 3 - trees 4 - triangles and rings 5 - ground type map
Where coordinates are listed as shorts (geometry), the bounds of the hole are 0x1000x, 0x2000z. Where coordinates are listed as ints (pins, tees), the bounds of the hole are 0x400000x, 0x800000z. To scale between the systems, shift left or right by 10 bits as appropriate.
Both geometry files follow the same format, and consist of a file containing a number of encoded vertices. The expected number of vertices is 0x231 for .vtx files and 0x800 for .dtx files, and the files will be read either until these counts are reached or a terminator is encountered.
The vertex encoding works on the basis of having implicit x- and z-coordinates which may be overridden, while a y-coordinate is always specified. The format is a command byte followed by up to three variable-length data values:
cc [xx[xx]] [yy[yy]] [zz[zz]]
The command byte's bits are split as follows:
1 1 11 11 11 z x zs ys xs
Where:
z = implicit z flag x = implicit x flag zs = z shift type ys = y shift type xs = x shift type
The shift types determine whether the coordinate being stored should be stored as a short or a byte, and what amount of right shifting has been applied to the original value. When decoded, these values would then be left shifted by the appropriate amount. Their possible behaviours are:
Value | x, z behaviour | y behaviour |
---|---|---|
0 | » 0, store short | » 0, store short |
1 | » 8, store byte | » 0, store byte |
2 | » 5, store byte | » 1, store byte |
3 | » 6, store byte | » 2, store byte |
Note that a command byte of 0x09
is interpreted as a terminator when decoding the data, and processing of the file will stop if this value is encountered.
The x- and z-coordinates take their implicit values when no value is otherwise specified. The pattern is different for the .vtx and .dtx files.
.vtx:
x z 0000 0000 0200 0000 0400 0000 0600 0000 0800 0000 0a00 0000 0c00 0000 0e00 0000 1000 0000 0100 0000 0300 0000 0500 0000 0700 0000 0900 0000 0b00 0000 0d00 0000 0f00 0000 +0100z until 0f00x, 2000z
.dtx:
x z pattern 0080 0000 0180 0000 0000 0080 0200 0080 0000 0180 0200 0180 0080 0200 0180 0200 0080 0080 0100 0080 0180 0080 0080 0100 0180 0100 0080 0180 0100 0180 0180 0180 +0200x until 0f80x then +0200z repeat until 0f80x, 1f80z
For an example, see here.
The file begins with a single byte giving the number of tree entries contained within the file. The tree data follows immediately after, in the format:
struct treeEntry { short x; short y; short z; byte treeType; byte unused; short width; short height; }
Tree types here.
Note that data in this file is not aligned.
This file contains various hole data to initialise with. However, this is all (?) overwritten later. The file format is:
struct initHoleConditions { int pinX; int pinY; int pinZ; int teeX; int teeY; int teeZ; int windSpeed; int windDirection; int weather; int time; short sunPosition1; short sunPosition2; byte par; byte pinIndex; byte unknown1; byte unknown2; int unknown3; //0x04000000 }
This file defines the four possible pin and tee locations for the hole. Although four tees can be listed, only the first is ever used. Additionally, further vectors are listed that affect where different characters will aim their shots by default. The format is:
pin positions (int x, int y, int z) * 4 tee positions (int x, int y, int z) * 4 aim positions (int x, int y, int z) * 16 total length: 0x120 bytes
This file contains triangle definitions for drawing water and/or the walls used in mini-golf, as well as definitions for the rings present in ring shot mode. The file begins with a single byte giving the number of definitions, followed by data in the format:
struct triangleDef { byte triType; short x1; short y1; short z1; short x2; short y2; short z2; short x3; short y3; short z3; }
Where triType
is:
0 water 1 ring 2 water 3 wall
For rings, rather than the data corresponding to three vertices, x2
/y2
/z2
will be the rotation, x3
the scale, and y3
/z3
unused.
Note that data in this file is not aligned.
The ground type map is a 256*512 array that defines the ground type at each point in space. This file is compressed in ROM and will be decompressed upon transfer to RAM. The types normally in use are:
0 Fairway 1 Rough 2 Bunker 3 Bare ground 4 Cart way 5 Deep rough 6 Green 7 OB 8 Tee ground 9 Rock
Note the absence of semi-rough and green edge; these types are not included in the ground maps themselves, but are added dynamically during processing. Additionally, deep rough will be swapped out with waste area on the Shy Guy Desert course, and green is swapped with cart way and fairway in the fast and slow mini-golf courses respectively.
The ground colours and patterns are generated during processing of the ground type maps. Unfortunately, these are normally all hardcoded and difficult to modify, though the functions have been rewritten (see here and here).