HZC is a collision format used in some Nintendo DS and Nintendo 3DS games developed by Firebrand Games such as Cartoon Network Racing DS and Race Driver: Create & Race.
File Format
The file byte order is always little endian.
The file starts with the following header:
| Offset |
Type |
Description
|
| 0x00 |
UInt16 |
Version number. The low byte is the minor version, and the high byte is the major version (always 1).
|
| 0x02 |
UInt16 |
Number of vertices (V).
|
| 0x04 |
UInt16 |
Number of triangles (T).
|
| 0x06 |
UInt16 |
Number of custom attributes (A).
|
| If version ≥ 1.18
|
| 0x08 |
UInt16 |
Vertex extra count (VE), unknown exact meaning. Usually equal to V or 0.
|
| If version ≥ 1.23
|
| 0x0A |
Byte[10] |
Unknown.
|
Vertex Data
Followed by the header, there's plain vertex position data stored as a sequence of groups of 3 values (one per axis). On the DS versions, the values are integers and need to be divided by 4096.
| Offset |
Type |
Description
|
| If version ≥ 1.18
|
| 0x00 |
Float32[3][V] |
Vertex XYZ coordinates.
|
| Else
|
| 0x00 |
Int32[3][V] |
Vertex XYZ coordinates.
|
Triangle Index Data
After the vertex data, there's a list of T * 3 UInt16s that correspond to the indices of each triangle.
| Offset |
Type |
Description
|
| 0x00 |
UInt16[3][T] |
Triangle indices.
|
Triangle Normal Data
Versions 1.3 and 1.5 only. Directly after the triangle indices there are the triangle's face normals, consisting of 3 Int32s per triangle that divide by 4096. They seem to match the cross product of the triangle's first two edges with a magnitude of 4096.
| Offset |
Type |
Description
|
| If version == 1.3 OR 1.5
|
| 0x00 |
Int32[3][T] |
Triangle XYZ normals.
|
Triangle Adjacency Data
Version 1.5 only. Directly after the triangle normals there is an additional set of 3 UInt16s per triangle. The values appear to be the indices of the three neighboring triangles, with 0xFFFF for open edges.
| Offset |
Type |
Description
|
| If version == 1.5
|
| 0x00 |
UInt16[3][T] |
Neighbor triangle indices.
|
Versions 1.18 and up only. After the triangle data there is a block of VE x 4 bytes. The purpose is not fully known, but the values are commonly 01 01 01 01 per entry. This block is absent when VE is 0.
| Offset |
Type |
Description
|
| If version ≥ 1.18
|
| 0x00 |
UInt32[VE] |
Unknown.
|
Grid
A spatial grid of 3D cells is used for faster collision detection. Each cell holds an index into the Linked List Array, or 0xFFFF when the cell is empty. The grid is made of three blocks: the cell array, the Grid Info, and the Linked List Array. On versions 1.22 and up the order is reversed (the Linked List Array comes first, then the Grid Info, and then the cell array).
| Offset |
Type |
Description
|
| 0x00 |
Int32 |
Number of cells (C).
|
| 0x04 |
UInt16[C] |
Cell indices. Each index is the head index of that cell's chain in the Linked List Array. 0xFFFF if the cell is empty.
|
Grid Info
| Offset |
Type |
Description
|
| 0x00 |
Int32[3] |
Number of cells in the grid's XYZ dimensions.
|
| If version ≥ 1.18
|
| 0x0C |
Float32[3] |
Grid bounding box minimum XYZ position.
|
| 0x18 |
Float32[3] |
Grid bounding box maximum XYZ position.
|
| Else
|
| 0x0C |
Int32[3] |
Grid bounding box minimum XYZ position. Divide by 4096.
|
| 0x18 |
Int32[3] |
Grid bounding box maximum XYZ position. Divide by 4096.
|
| If version == 1.3 (Cartoon Network Racing only)
|
| 0x24 |
Int32 |
Unknown. Always 0.
|
Linked List Array
After the grid data there's an array of triangle/cell links. Each cell stores the index of the first entry of its chain, and each entry names a triangle and the index of the next entry in the same chain, ending at 0xFFFF. A triangle is added to every cell it overlaps.
| Offset |
Type |
Description
|
| If version == 1.18 OR 1.19
|
| 0x00 |
UInt16 |
Number of links (L).
|
| 0x02 |
UInt16[2][L] |
Triangle index/next index. The next index is 0xFFFF at the end of a cell's chain, otherwise another index into this same array.
|
| Else
|
| 0x00 |
Int32 |
Number of links (L).
|
| 0x04 |
UInt16[2][L] |
Triangle index/next index. The next index is 0xFFFF at the end of a cell's chain, otherwise another index into this same array.
|
Custom Attribute Table
This section is only present if A > 0. Version 1.14 stores a single surface type byte per triangle and has no string table. Not all attributes may be used, as some files have been seen with unused attribute strings.
| Offset |
Type |
Description
|
| If version == 1.14
|
| 0x00 |
Byte[T] |
Surface type.
|
| Else
|
| 0x00 |
UInt16[T] |
Attribute IDs. 0xFFFF if none.
|
String Table
Not present in version 1.14.
Key-Value Attribute
| Offset |
Type |
Description
|
| 0x00 |
UInt16 |
Key string length (AK).
|
| 0x02 |
String (Char[AK]) |
Attribute key.
|
| 0x02 + AK |
UInt16 |
Value string length (AV).
|
| 0x04 + AK |
String (Char[AV]) |
Attribute value. Seen as float(SurfaceType)=X.000000 in Cartoon Network Racing DS.
|
Seen attributes (Cartoon Network Racing DS)
| Key |
Value |
Found in
|
| COL_grass
|
float(SurfaceType)=1.000000
|
- CrossTown.hzc
- evilGlade.hzc
- IslandDash.hzc
|
| grass
|
float(SurfaceType)=1.000000
|
Townsville.hzc
|
| Grass
|
float(SurfaceType)=1.000000
|
- AronSpeed.hzc
- MandarkLab.hzc
- MidNowhere.hzc
|
| heavyTerrain
|
float(SurfaceType)=2.000000
|
- CrossTown.hzc
- MandarkLab.hzc
- SnowSunday.hzc
|
| HeavyTerrain
|
float(SurfaceType)=3.000000
|
- IslandDash.hzc
- MandarkLab.hzc
|
| MudPuddle
|
float(SurfaceType)=5.000000
|
IslandDash.hzc
|
| not_track
|
- float(SurfaceType)=1.000000
- float(SurfaceType)=4.000000
|
- MandarkLab.hzc
- MidNowhere.hzc
- Townsville.hzc
|
| raceTrackFloor
|
—
|
DextersLab.hzc
|
| raceTrackWalls
|
—
|
DextersLab.hzc
|
| RoughGround
|
- float(SurfaceType)=0.000000
- float(SurfaceType)=4.000000
|
- AronSpeed.hzc
- MandarkLab.hzc
- MidNowhere.hzc
|
| terrainLight
|
float(SurfaceType)=0.000000
|
- MandarkLab.hzc
- MountRush.hzc
|
Version List
Tools
The following tools can handle HZC files: