BOL (File Format)
This page describes the .bol format, as found in course.arc files .bol is used for course data.
File Format
Literally copied from Tockdom
File Header
The file header is a 0x7C byte structure, as follows:
Offset | Type | Description |
---|---|---|
0x00 | String | File magic. Always 0015 in ASCII. |
0x04 | Byte | Tilt settings. Normally 0x00 for no tilt. Set to 0x01 to enable the moving objects in Daisy Cruiser. Set to 0x02 to enable the whole stage tilt in Tilt-A-Kart |
0x05 | Byte[3] | Forms an RGB Ambient Color. All 3 values are set to 0x64 if 0. |
0x08 | Byte[4] | Forms an RGBA Light Color. All 4 values are set to 0xFF if 0. |
0x0C | Float[3] | Light source position. |
0x18 | Byte | Number of laps. |
0x19 | Byte | Course ID - also used for music |
0x1A | UInt16 | Number of Route entries. |
0x1C | UInt16 | Number of Checkpoint groups. |
0x1E | UInt16 | Number of Object entries. |
0x20 | UInt16 | Number of Area entries. |
0x22 | UInt16 | Number of Camera entries |
0x24 | UInt16 | Number of Path entries. |
0x26 | UInt16 | Number of Respawn entries. |
0x28 | Byte | Fog Type. |
0x29 | Byte[3] | Fog Color. |
0x2C | Float | Fog Start Z. |
0x30 | Float | Fog End Z. |
0x34 | Byte | LOD Bias on (0x01) or off (0x00). |
0x35 | Byte | Unknown. In stock courses, either 0x00 or 0x01. Seemingly relates to the GeoStartline object. |
0x36 | Byte | Set to 0x01 to enable Sherbet Land snow effects. |
0x37 | Byte | Shadow opacity. Values in stock courses ranging from 20 to 35. |
0x38 | Byte[3] | Forms an RGB Shadow Color. |
0x3B | Byte | Number of Starting Points entries. |
0x3C | Byte | Sky Follow flag. Only set in Ending and in Sherbet Land. Different matrix operations are applied to the skydome, meaning that the the skybox will follow a player with an offset. |
0x3D | Byte | Number of LightParam entries. |
0x3E | Byte | Number of MGParam entries. Should be 0x08 for battle courses. |
0x3F | Byte | Padding. Always 0x00 in all stock BOL files. |
0x40 | UInt32 | Start of the file, always 0x00. |
0x44 | UInt32 | Routes offset, always 0x7C. |
0x48 | UInt32 | Checkpoint Groupings offset. |
0x4C | UInt32 | Paths offset. |
0x50 | UInt32 | Path Points offset. |
0x54 | UInt32 | Objects offset. |
0x58 | UInt32 | Starting Points offset. |
0x5C | UInt32 | Areas offset. |
0x60 | UInt32 | Cameras offset. |
0x64 | UInt32 | Respawn Points offset. |
0x68 | UInt32 | LightParams offset. |
0x6C | UInt32 | MGParams offset. |
0x70 | Byte[12] | Padding. |
Sections
The file consists of a series of sections, each describing a different aspect of the course setup.
Section 1: Enemy/Item points
Section 1 describes enemy/item points; the routes of CPU racers and items such as red shells. The CPU racers and items attempt to follow the path described by each group of points. Each entry is a 0x20 byte structure as follows:
Offset | Type | Description |
---|---|---|
0x00 | Float[3] | A 3D position vector of the position. |
0x0C | UInt16 | Drift direction:
(See drift acuteness and drift duration below.) |
0x0E | Int16 | At the start of the group non Unique Group ID.
At the end of the group link to next non Unique Group ID. Otherwise -1. |
0x10 | Float | Scale of the point. This determines how far away from the origin of the point that the items / racers can bias from. |
0x14 | Signed Byte | Swerve:
|
0x15 | Byte | Group setting if start of group. Otherwise 0.
|
0x16 | Byte | Unique Group ID. |
0x17 | Byte | Drift acuteness.
In the stock courses, in the range [10, 180]. If 0, drifting is disabled. Smaller values provide a more acute drifting. For example, 10 is used in the two hairpin curves in Baby Park; 180 is used in the greatest, wide curve in Dry Dry Desert. |
0x18 | Byte | Drift duration.
In the stock courses, in the range [30, 250]. The greater the value, the greater the duration of the drifting of the AI karts. |
0x19 | Byte | Drift supplement.
Values seen in the stock courses are: 0 (most common), 25 (once in Mushroom City), 10 (once in Rainbow Road). The value is read from |
0x1A | Byte | No mushroom zone. The flag is seen in enemy points where it is not convenient to consume a mushroom, such as before hairpin curves, road boosts, jumps, before or after barrel cannons, etc. |
0x1B | Byte[5] | Padding. |
NOTE: Even when drifting is configured, it's still up to the AI kart to start drifting or not, depending on current speed, entry angle, etc. On the other hand, swerving is fully dictated by the setting: AI karts will swerve if configured.
Section 2: Checkpoints
The first part of Section 2 describes checkpoint grouping; how the routes of checkpoints link together. Each entry is a 0x14 byte structure as follows:
Offset | Type | Description |
---|---|---|
0x00 | UInt16 | Point length. The number of points in this group. |
0x02 | UInt16 | Group link. |
0x04 | Int16[4] | Previous group. The indices of up to 4 group links that follow to this one. Unneeded slots are set to value -1. |
0x0C | Int16[4] | Next group. The indices of up to 4 group links to follow after this one. Unneeded slots are set to value -1. |
The second part of Section 2 describes checkpoints; the routes players must follow to count laps. The racers must follow the path described by each group of points (as determined by the first part of Section 2). Each entry is a 0x1C byte structure as follows:
Offset | Type | Description |
---|---|---|
0x00 | Float[3] | A 3D position vector of the start of the check point line. |
0x0C | Float[3] | A 3D position vector of the end of check point line. |
0x18 | Byte | Used to define checkpoint groups as optional for lap progression. See below for details. |
0x19 | Byte | Unknown. If not 0, considered invalid by Sector::isInvalid() |
0x1A | Byte | Unknown. If not 0, enables a Reverse Search via isRevSearchEnable() |
0x1B | Byte | Unknown. |
The byte at 0x18 allows for developer-intended shortcuts. Checkpoints that share a non-zero value at this offset will be thought of as optional for lap progression, that is, the lap progression will halt upon entering the checkpoint boxes associated with these checkpoints and jump to where it should be when the checkpoint box region is exited. In vanilla, only consecutive checkpoint share non-zero values, but if applied to nonconsecutive checkpoints, all checkpoints between the two will be counted in the same group.
Section 3: Paths
Section 3 describes paths; these are paths for many things including cameras and objects. Each entry is a 0x10 byte structure as follows:
Offset | Type | Description |
---|---|---|
0x00 | UInt16 | Point length. The number of Route Point entries in this group. |
0x02 | UInt16 | Point start. The index of the first Route Point entry in this group. |
0x04 | Byte[3] | Padding. |
0x07 | Byte | Possibly a loop flag? Only used as 1. |
0x08 | Byte[8] | Padding. |
Section 4: Path Points
Section 4 describes path points. Each entry is a 0x20 byte structure as follows:
Offset | Type | Description |
---|---|---|
0x00 | Float[3] | A 3D position vector of the route position. |
0x0C | UInt32 | Link Point. Allows GeoCar objects to travel to a specified point from the last path point in its path. For this to be used, the path must not be closed. |
0x10 | Byte[16] | Padding. |
Section 5: Objects
Section 5 describes objects. Each entry is a 0x40 byte structure as follows:
Offset | Type | Description |
---|---|---|
0x00 | Float[3] | A 3D position vector of the object. |
0x0C | Float[3] | A 3D scale vector of the object. |
0x18 | Int32[3] | A 3D rotation vector of the object. |
0x24 | UInt16 | Object ID. |
0x26 | Int16 | Path ID. Links to Paths. 0xFFFF if no path is used. |
0x28 | Int16 | Unknown. Always 0 in stock courses.
|
0x2A | Int16 | Point Index in Route. -1 when not set. Used heavily in Mushroom Bridge and Mushroom City to spread cars around while having them reuse the same routes.
|
0x2C | Byte | Presence filter. Determines if an object shows up in Time Trial / Grand Prix / Different battle modes. See below table. |
0x2D | Byte | Presence flag. 0x00 = all game modes disabled, 0x01 = single screen, 0x02 = split screen, 0x03 = all game modes. |
0x2E | Byte | Collision flag. Determines if an object has collision or not. |
0x2F | Byte | Unknown. Always 0 in stock courses.
|
0x30 | Int16 | Varies. |
0x32 | Int16 | Varies. |
0x34 | Int16 | Varies. |
0x36 | Int16 | Varies. |
0x38 | Int16 | Varies. |
0x3A | Int16 | Varies. |
0x3C | Int16 | Varies. |
0x3E | Int16 | Varies. |
Byte (0 = least significant) | Game Mode Enables |
---|---|
0 | Balloon Battle |
1 | Robbery (Not used) |
2 | Bom-omb Blast |
3 | Shine Thief |
7 | Time Trials |
The usage of the values at offsets 0x30 - 0x3E differ from object to object - a full documentation can be found in the Objects page.
Section 6: Kart Start Points
Section 6 describes kart points; the starting positions of racers. Each entry is a 0x28 byte structure as follows:
Offset | Type | Description |
---|---|---|
0x00 | Float[3] | A 3D position vector of the start position. |
0x0C | Float[3] | A 3D scale vector of the start position. |
0x18 | Int32[3] | A 3D rotation vector of the start position. |
0x24 | Byte | 0: Pole position is left 1: Pole position is right. |
0x25 | Byte | Player ID. In courses with multiple start positions (such as battle courses), this determines which players start here. Otherwise set to 0xFF to set all players start positions to this point. |
0x26 | UInt16 | Padding. |
Section 7: Areas
Section 7 describes areas; used to determine for example which camera to use. Each entry is a 0x38 byte structure as follows:
Offset | Type | Description |
---|---|---|
0x00 | Float[3] | A 3D position vector of the area. |
0x0C | Float[3] | A 3D scale vector of the area. |
0x18 | Int32[3] | A 3D rotation vector of the area. |
0x24 | Byte | Shape (0 = box, 1 = cylinder). |
0x25 | Byte | Area Type. |
0x26 | Int16 | Index into Cameras only if Area Type is 0x01. Otherwise, -1. This byte is also sometimes set with Area Type 0x05. |
0x28 | UInt32 | Feather value. |
0x2C | UInt32 | Feather value. |
0x30 | Int16 | Unknown. Used in type 2 areas (ceilings). Values seen in stock courses are: 0 , 1 , 50 , and 100 .
|
0x32 | Int16 | Unknown. Always 0 in stock courses.
|
0x34 | UInt16 | Shadow ID. |
0x36 | UInt16 | Index into a LightParam entry. |
Area Type | Description | Connects To |
---|---|---|
0 | Shadows | Shadow ID |
1 | Camera | Camera |
2 | Ceilings, stop SL effects | - |
3 | Disables dead zones. Seen in Waluigi Stadium to disable dead zone under the last big jump. | - |
4 | Not used. | - |
5 | Unknown. Appears in places where karts would be airborne. | In some instances, byte 0x26 (currently documented as "camera index") is populated. |
6 | Enables sound effects. These are cheering sounds in Waluigi Stadium, or ghost sounds in Luigi's Mansion. This area type is also seen in Mushroom City, DK Mountain, or Dino Dino Jungle, but does not show any effect there. |
- |
7 | Lighting Effects | LightParam |
Section 8: Cameras
Section 8 describes Cameras. Each entry is a 0x48 byte structure as follows:
Offset | Type | Description |
---|---|---|
0x00 | Float[3] | A 3D position vector of the first view point. |
0x0C | Int32[3] | A 3D rotation vector. |
0x18 | Float[3] | A 3D position vector of the second view point. |
0x24 | Float[3] | A 3D position vector of the third view point. |
0x30 | UInt8 | Follow Player Flag. If 1, the camera will focus on the player. Used with camera types 0, 1, 2, and 3. |
0x31 | UInt8 | Camera Type. |
0x32 | UInt16 | Start field of view |
0x34 | UInt16 | Camera Duration (in 1/60 second units). |
0x36 | UInt16 | Start camera check (is the start camera when not 0). |
0x38 | UInt16 | Unknown - called ShimmerZ0. |
0x3A | UInt16 | Unknown - called ShimmerZ1. |
0x3C | Int16 | Linked Route ID (-1 if none). |
0x3E | UInt16 | Route Speed. |
0x40 | UInt16 | End field of view. |
0x42 | Int16 | Next Camera (-1 if none). |
0x44 | String | Camera Name? (Most of the time "null" or "para"). |
Note: Replay cameras can be used as opening cameras.
Camera Type | Opening vs Replay | Routed | Description |
---|---|---|---|
0 (Fix / FixSearch / StartFix) | Replay | No | Basic unrouted replay camera |
1 (FixPath / ChasePath / StartChasePath) | Replay/Opening | Yes | Basic routed camera. View direction remains parallel to the camera object's direction. |
2 (FixChase / Chase) | Replay | No | Unknown |
3 (FixSpl / ChaseSpl) | Replay | No | Unknown |
4 (StartFixPath) | Opening | Yes | Travels along a route, but only focus on the Start Point. |
5 (DemoPath / StartPath) | Opening | Yes | Travels along a route, changing its view from the Start Point to the End Point |
6 (StartLookPath) | Opening | No | From its position, changes its view from the Start Point to the End Point |
7 (FixPala) | Replay | Optional | Unknown |
8 | Replay | No | Possibly used as the replay camera when a kart is in no Type 1 area. Is identical in all vanilla courses. |
Section 9: Respawn Points
Section 9 describes Jugem points; the respawn positions. Each entry is a 0x20 byte structure as follows:
Offset | Type | Description |
---|---|---|
0x00 | Float[3] | A 3D position vector of the respawn position. |
0x0C | Int32[3] | A 3D rotation vector of the respawn position. |
0x18 | UInt16 | Respawn ID |
0x1A | UInt16 | Link to next Enemy/Item point. |
0x1C | Int16 | Link to a Camera.
Always set to -1 except in one single respawn point in Mushroom Bridge, where it is set to 2. The value is read from |
0x1E | Int16 | Index of the previous checkpoint (not used by all points) |
Section 10: Lights
Unknown, but referenced as LightParam.
Offset | Type | Description |
---|---|---|
0x00 | Byte[4] | Forms an RGBA Light Color. |
0x04 | Float[3] | 3D Light Source Position. |
0x10 | Byte[4] | Forms an RGBA Ambient Color. |
Section 11
This section is referenced as "MG" which can possibly stand for MiniGame. The section is always 0x40 bytes long, with each entry being 0x08 bytes long. After further reverse engineering, it has been found that this section is unused in the game. There's a game mode that is referenced as Rabbit, that has a check named isRidingBossPakkun, which means that this may have been Renegade Roundup, which appears in Mario Kart 8 Deluxe.
Offset | Type | Description |
---|---|---|
0x00 | Int16 | Unknown. |
0x02 | Int16 | Unknown. |
0x04 | Int16 | Unknown. |
0x06 | Int16 | Padding. |
Rotation Vector
The Mario Kart: Double Dash!! rotation vector consists of 3 Int32 values. The first two values form a two-dimensional direction vector with the first pointing in X-direction and the second pointing in Z-direction. The third value represents the length of the vector (it is quite inaccurate, though). Its value is usually 0x27100000 (655360000 in base 10). Using trigonometry, the rotation angle around the Y-axis can be calculated as follows:
angle (in degree) = sign(value1 + 0.5) * arccos(value2 / value3) * (180 / pi)
This C# snippet can properly determine the value as well:
public static double returnRotations(int xrot, int yrot, int zrot) { double radToDeg = 57.2957795d; double angle1 = radToDeg * Math.Atan2((double)yrot / (double)zrot, (double)xrot / (double)zrot); angle1 = 90 - angle1; return angle1; }