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:

File header of a BOL file
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:
  • 0: No drifting.
  • 1: AI karts drift to the left.
  • 2: AI karts drift to the right.

(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:
  • -3: AI karts swerve to the left (abruptly)
  • -2: AI karts swerve to the left (less subtly)
  • -1: AI karts swerve to the left (subtly)
  • 0: No swerving
  • 1: AI karts swerve to the right (subtly)
  • 2: AI karts swerve to the right (less subtly)
  • 3: AI karts swerve to the right (abruptly)
0x15 Byte Group setting if start of group. Otherwise 0.
  • 0: Enemy and items can enter group.
  • 1: Items can enter group.
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 RivalBodyCtrl::initDrift() when AI karts reach the enemy point. In assembly, the value is then added to the overall value that was previously calculated with the rest of the settings.

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:

Groups
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:

Points
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.
Game Mode Presence Flag
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 Types
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 Types
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 KartPipe::DoPipeCrl(), and later consumed by CrsData::getCameraData(), but the return value of that function is unused.

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;
}


Tools

References