On this page
  1. Related
  2. Mechanics
  3. References
  4. Sources

The atlas reads Mario Kart 64 through the n64decomp team’s decompilation, C that builds the US and European ROMs. Names and comments quoted here are theirs, and the claims cite the code the US build compiles. Nothing has been measured in the game yet.

Each place has its own row of 100 slots1, an item box reads one slot at random, and Grand Prix keeps separate tables for human and CPU drivers1. The engine class sets top speeds of 290, 310, and 320 (4 more for light drivers)2,2. Counter-steering during a drift charges a stage after 18 counts, then 8 more3, and the second stage gives a mini-turbo when the drift ends3. The start boost takes a press of A within 8 race frame counts (20 in Time Trials)4 of its window opening4. CPU drivers carry a flag the decompilers call rubber-banding, which adds to their forward force5.

Mechanics

MechanicKindHow
Item distributionBy placeGrand Prix and Versus read a 100-slot row for the driver's place, with separate tables for human and CPU drivers in Grand Prix
Item distributionFlatBattle reads one 100-slot row whatever the place
Drift boostStick stagescounter-steering during a drift charges a stage after 18 counts and 8 more for each after; two stages give a 31-update mini-turbo
Rocket startPress windowa fresh press of A within 8 race frame counts of the window opening gives a Mushroom boost; revving to 90% of top speed without it spins the kart out
Rubber-band AIPower boosta flag the decompilers call rubber-banding pulls a CPU kart's added force toward 380 while a pacing check passes
Engine classTop speed50cc, 100cc, and 150cc set top speeds of 290, 310, and 320, with 4 more for the three light drivers
Every claim about this game, by concept (5)
Drift boostIn the US version of Mario Kart 64, while a kart drifts on the ground, holding the stick at least 10 of its 53 steps toward the outside of the turn counts up driftStateCounter. Letting the stick back after 18 to 99 counts raises driftState by one, up to 3, and sets the count to 10, so each later step takes 8 more counts (computed); letting it back before 10 counts, or at 100 or more, resets both to 0. When a human player's drift ends with driftState at 2 or more, the kart gets MINI_TURBO_EFFECT for 31 player updates (computed), during which a term in its forward force moves toward 580 by a fifth of the gap each update.Code
Engine classIn the US version of Mario Kart 64, in Grand Prix and Versus the engine class sets each kart's top speed from gTopSpeedTable when it spawns: 290 at 50cc, 310 at 100cc, and 320 at 150cc for Mario, Luigi, Donkey Kong, Wario, and Bowser, and 4 more for Yoshi, Toad, and Peach. Extra uses the 100cc numbers, Time Trials always reads the 100cc row, and Battle gives every driver 245.Code
Item distributionIn the US version of Mario Kart 64, gen_random_item picks an item as one byte from a 100-byte row of a table, the row for the driver's current place. In Grand Prix, human players read common_grand_prix_human_item_curve and CPU drivers common_grand_prix_cpu_item_curve, and that branch reads no player count. Versus picks one of three tables by the number of players (two, three, or four), and Battle reads one row whatever the place. The slot is a random number from 0 to 100 (random_int(100)) plus the previous slot, a counter that held A, B, and R buttons advance, and the race frame counter, taken mod 100.Code
Rocket startIn the US version of Mario Kart 64, the start boost's window opens when Lakitu's countdown finishes the animation after its second light sound, before the green-light sound. A press of A that begins within 8 counts of the race frame counter from the first update the window is open (20 in Time Trials) sets START_BOOST_TRIGGER, and letting go of A before the start clears it. The trigger gives the kart the Mushroom's effect and the same boost timer, 80. Once the window is open, a kart that revs to 90% of its top speed without the trigger gets START_SPINOUT_TRIGGER, the spin-out for holding the gas.Code
Rubber-band AIIn the US version of Mario Kart 64, CPU_FAST_EFFECT, which the decompilers comment as the "CPU Rubberbanding flag", raises a CPU driver's forward force: while it's set, a term in that force moves toward 380 by half the gap each update, and once it's cleared the term falls toward 0 by a tenth of the gap. regulate_cpu_speed sets the flag on a CPU driver below its target speed when the pacing check func_800088D8 returns true, and clears it otherwise.Code

References

  1. ^ abIn the US version of Mario Kart 64, gen_random_item picks an item as one byte from a 100-byte row of a table, the row for the driver's current place. In Grand Prix, human players read common_grand_prix_human_item_curve and CPU drivers common_grand_prix_cpu_item_curve, and that branch reads no player count. Versus picks one of three tables by the number of players (two, three, or four), and Battle reads one row whatever the place. The slot is a random number from 0 to 100 (random_int(100)) plus the previous slot, a counter that held A, B, and R buttons advance, and the race frame counter, taken mod 100.Coden64decomp/mk64revised
    How we know
    3665u8 gen_random_item(s16 rank, s16 isCpu) {
    3666    u16 rand = random_int(100);
    ⋮
    3671    sRandomItemIndex = ((u32) rand + (sRandomItemIndex + gControllerRandom) + gRaceFrameCounter) % 100U;
    
    src/update_objects.c lines 3665–3671 at 58cfcb0 · upstream ↗
    3673    if (gModeSelection == VERSUS) {
    3674        switch (gPlayerCountSelection1) {
    3675            case TWO_PLAYERS_SELECTED:
    ⋮
    3678            case THREE_PLAYERS_SELECTED:
    ⋮
    3681            case FOUR_PLAYERS_SELECTED:
    ⋮
    3685        randomItem = *((rank * 100) + curve + sRandomItemIndex);
    
    src/update_objects.c lines 3673–3685 at 58cfcb0 · upstream ↗
    3687    } else if (gModeSelection == BATTLE) {
    3688        curve = segmented_to_virtual((void*) common_battle_item_curve);
    3689        randomItem = curve[sRandomItemIndex];
    3690    } else { // GP Mode
    3691        if (isCpu == 0) {
    3692            curve = segmented_to_virtual((void*) common_grand_prix_human_item_curve);
    3693        } else {
    3694            curve = segmented_to_virtual((void*) common_grand_prix_cpu_item_curve);
    ⋮
    3696        randomItem = *((rank * 100) + curve + sRandomItemIndex);
    
    src/update_objects.c lines 3687–3696 at 58cfcb0 · upstream ↗
    3702u8 gen_random_item_human(UNUSED s16 arg0, s16 rank) {
    3703    return gen_random_item(rank, false);
    ⋮
    3706u8 cpu_gen_random_item(UNUSED s32 arg0, s16 rank) {
    3707    return gen_random_item(rank, true);
    ⋮
    3714    randomItem = gen_random_item_human(gLapCountByPlayerId[arg1], gGPCurrentRaceRankByPlayerId[arg1]);
    
    src/update_objects.c lines 3702–3714 at 58cfcb0 · upstream ↗
    3918                cpu_decisions_branch_item(playerId, &cpuStrategy->branch,
    3919                                            cpu_gen_random_item((s16) gLapCountByPlayerId[playerId],
    3920                                                                gGPCurrentRaceRankByPlayerId[playerId]));
    
    src/cpu_vehicles_camera_path.c lines 3918–3920 at 58cfcb0 · upstream ↗
    1205void randomize_seed_from_controller(s32 arg0) {
    ⋮
    1208    if ((controller->button & A_BUTTON) != 0) {
    1209        gControllerRandom++;
    ⋮
    1211    if ((controller->button & B_BUTTON) != 0) {
    1212        gControllerRandom++;
    ⋮
    1214    if ((controller->button & R_TRIG) != 0) {
    1215        gControllerRandom++;
    
    src/code_80057C60.c lines 1205–1215 at 58cfcb0 · upstream ↗
    1269u16 random_int(u16 arg0) {
    1270    return arg0 * (((f32) random_u16()) / 65535.0);
    
    src/racing/math_util.c lines 1269–1270 at 58cfcb0 · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-22.

    Revised after a check by a second AI model, 2026-10-22.

    In the claim ledger

  2. ^ abIn the US version of Mario Kart 64, in Grand Prix and Versus the engine class sets each kart's top speed from gTopSpeedTable when it spawns: 290 at 50cc, 310 at 100cc, and 320 at 150cc for Mario, Luigi, Donkey Kong, Wario, and Bowser, and 4 more for Yoshi, Toad, and Peach. Extra uses the 100cc numbers, Time Trials always reads the 100cc row, and Battle gives every driver 245.Coden64decomp/mk64
    How we know
    63//  Mario  Luigi  Yoshi  Toad   D.K.   Wario  Peach  Bowser
    64f32 gTopSpeed50cc[] = {
    65    // 50CC
    66    290.0, 290.0, 294.0, 294.0, 290.0, 290.0, 294.0, 290.0,
    ⋮
    68f32 gTopSpeed100cc[] = {
    69    // 100CC
    70    310.0, 310.0, 314.0, 314.0, 310.0, 310.0, 314.0, 310.0,
    ⋮
    72f32 gTopSpeed150cc[] = {
    73    // 150CC
    74    320.0, 320.0, 324.0, 324.0, 320.0, 320.0, 324.0, 320.0,
    ⋮
    76f32 gTopSpeedExtra[] = {
    77    // Extra
    ⋮
    
    src/data/kart_attributes.c lines 63–86 at 58cfcb0 · upstream ↗
    89    switch (gModeSelection) {
    90        case GRAND_PRIX:
    91        case VERSUS:
    ⋮
    95            player->topSpeed = gTopSpeedTable[gCCSelection][player->characterId];
    ⋮
    98        // Uses 100CC values
    99        case TIME_TRIALS:
    ⋮
    103            player->topSpeed = gTopSpeedTable[CC_100][player->characterId];
    ⋮
    106        case BATTLE:
    ⋮
    110            player->topSpeed = gTopSpeedTable[CC_BATTLE][player->characterId];
    
    src/spawn_players.c lines 89–110 at 58cfcb0 · upstream ↗
    160#define CC_50 0
    161#define CC_100 1
    162#define CC_150 2
    163#define CC_EXTRA 3
    164#define CC_BATTLE 4
    
    include/defines.h lines 160–164 at 58cfcb0 · upstream ↗
    187#define MARIO 0
    188#define LUIGI 1
    189#define YOSHI 2
    190#define TOAD 3
    191#define DK 4
    192#define WARIO 5
    193#define PEACH 6
    194#define BOWSER 7
    
    include/defines.h lines 187–194 at 58cfcb0 · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-22.

    Checked by a second AI model, 2026-10-22.

    In the claim ledger

  3. ^ abIn the US version of Mario Kart 64, while a kart drifts on the ground, holding the stick at least 10 of its 53 steps toward the outside of the turn counts up driftStateCounter. Letting the stick back after 18 to 99 counts raises driftState by one, up to 3, and sets the count to 10, so each later step takes 8 more counts (computed); letting it back before 10 counts, or at 100 or more, resets both to 0. When a human player's drift ends with driftState at 2 or more, the kart gets MINI_TURBO_EFFECT for 31 player updates (computed), during which a term in its forward force moves toward 580 by a fifth of the gap each update.Coden64decomp/mk64
    How we know
    1148void update_drift_state_counter(Player* player, s8 playerIndex) {
    1149    if (((s16) player->unk_0C0 / DEGREES(1)) > 0) {
    1150        if (((s32) player->steerPosition >> 16) <= -10) {
    1151            if (player->driftStateCounter <= 100) {
    1152                player->driftStateCounter++;
    ⋮
    1157        } else {
    1158            if ((player->driftStateCounter >= 18) && (player->driftStateCounter < 100)) {
    1159                if (player->driftState < 3) {
    1160                    player->driftState++;
    ⋮
    1163            if ((player->driftStateCounter >= 10) && (player->driftStateCounter < 100)) {
    1164                player->driftStateCounter = 10;
    1165            } else {
    ⋮
    
    src/player_controller.c lines 1148–1170 at 58cfcb0 · upstream ↗
    4166    if (((player->effects & HOP_EFFECT) != HOP_EFFECT) && ((player->effects & DRIFTING_EFFECT) != DRIFTING_EFFECT)) {
    
    src/player_controller.c line 4166 at 58cfcb0 · upstream ↗
    4194    } else if (((player->effects & MIDAIR_EFFECT) != MIDAIR_EFFECT) && ((player->effects & HOP_EFFECT) != HOP_EFFECT)) {
    4195        if ((((s16) player->unk_0C0) / DEGREES(1)) > 0) {
    ⋮
    4198            if ((player->steerPosition >> 16) <= -40) {
    4199                player->effects |= DRIFT_OUTSIDE_EFFECT;
    ⋮
    4201                    player->effects |= DRIFT_OUTSIDE_EFFECT;
    ⋮
    4204            update_drift_state_counter(player, playerIndex);
    ⋮
    4208            if ((player->steerPosition >> 16) >= 40) {
    4209                player->effects |= DRIFT_OUTSIDE_EFFECT;
    ⋮
    4211                    player->effects |= DRIFT_OUTSIDE_EFFECT;
    ⋮
    4214            update_drift_state_counter(player, playerIndex);
    
    src/player_controller.c lines 4194–4214 at 58cfcb0 · upstream ↗
    487#define DRIFT_OUTSIDE_EFFECT      0x20000000 // drifting toward the outside of your turn
    
    include/defines.h line 487 at 58cfcb0 · upstream ↗
    278    /* 0x007C */ s32 steerPosition; // Where the kart is steering, related to joystick position. Basically, in [-53 to 53], but shifted 16 bits left
    
    include/common_structs.h line 278 at 58cfcb0 · upstream ↗
    3956    clamped_x = get_clamped_stickX_with_deadzone(controller);
    ⋮
    3960    player->steerPosition = (clamped_x << 16) & 0xFFFF0000;
    
    src/player_controller.c lines 3956–3960 at 58cfcb0 · upstream ↗
    4862    if (temp_stickX > 0x35) {
    4863        temp_stickY = (temp_stickY * 0x0035) / temp_stickX;
    4864        temp_stickX = 0x0035;
    ⋮
    4866    if (temp_stickX < -0x35) {
    4867        temp_stickY = (temp_stickY * 0x0035) / -temp_stickX;
    4868        temp_stickX = -0x0035;
    
    src/player_controller.c lines 4862–4869 at 58cfcb0 · upstream ↗
    1123void func_8002A79C(Player* player, s8 playerIndex) {
    1124    if (((player->effects & MINI_TURBO_EFFECT) != MINI_TURBO_EFFECT) &&
    1125        ((player->effects & DRIFTING_EFFECT) != DRIFTING_EFFECT) && (player->driftState >= 2)) {
    1126        player->effects |= MINI_TURBO_EFFECT;
    1127        player->unk_23A = 0;
    ⋮
    1137    } else if ((player->effects & MINI_TURBO_EFFECT) == MINI_TURBO_EFFECT) {
    1138        player->unk_23A += 1;
    1139        if (player->unk_23A >= 0x1F) {
    1140            player->unk_23A = 0;
    1141            player->effects &= ~MINI_TURBO_EFFECT;
    
    src/player_controller.c lines 1123–1143 at 58cfcb0 · upstream ↗
    2139    if ((player->type & PLAYER_HUMAN) == PLAYER_HUMAN) {
    2140        func_8002A79C(player, playerId);
    
    src/player_controller.c lines 2139–2140 at 58cfcb0 · upstream ↗
    3093    if ((player->type & PLAYER_HUMAN) == PLAYER_HUMAN) {
    3094        if (((player->effects & MINI_TURBO_EFFECT) == MINI_TURBO_EFFECT) &&
    3095            ((player->effects & DRIFTING_EFFECT) != DRIFTING_EFFECT)) {
    3096            move_f32_towards(&player->unk_0E8, 580.0f, 0.2f);
    3097        } else {
    3098            move_f32_towards(&player->unk_0E8, 0.0f, 0.01f);
    ⋮
    3102        } else {
    ⋮
    3107    var_f2 = (player->unk_08C + player->unk_0E8 + player->boostPower + player->unk_0E4) - player->unk_0A0;
    
    src/player_controller.c lines 3093–3107 at 58cfcb0 · upstream ↗
    863void move_f32_towards(f32* startingValue, f32 targetValue, f32 somePercent) {
    864    *startingValue -= ((*startingValue - targetValue) * somePercent);
    
    src/render_player.c lines 863–864 at 58cfcb0 · upstream ↗
    2742    spF4[2] = func_80030150(player, playerId);
    2743    mtxf_transform_vec3f_mat3(spF4, player->orientationMatrix);
    ⋮
    2748    newVelocity[2] += (((spF4[2] + sp7C) + spD0[2]) - (newVelocity[2] * (0.12 * player->kartFriction))) / 6000.0;
    
    src/player_controller.c lines 2742–2748 at 58cfcb0 · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-25.

    Checked by a second AI model, 2026-10-22.

    Checked by a second AI model, 2026-10-25.

    In the claim ledger

  4. ^ abIn the US version of Mario Kart 64, the start boost's window opens when Lakitu's countdown finishes the animation after its second light sound, before the green-light sound. A press of A that begins within 8 counts of the race frame counter from the first update the window is open (20 in Time Trials) sets START_BOOST_TRIGGER, and letting go of A before the start clears it. The trigger gives the kart the Mushroom's effect and the same boost timer, 80. Once the window is open, a kart that revs to 90% of its top speed without the trigger gets START_SPINOUT_TRIGGER, the spin-out for holding the gas.Coden64decomp/mk64revised
    How we know
    3037        case 7:
    3038            if (set_and_run_timer_object(objectIndex, 0x00000014) != 0) {
    ⋮
    3041                    play_sound2(SOUND_ACTION_COUNTDOWN_LIGHT);
    ⋮
    3048        case 9:
    3049            if ((set_and_run_timer_object(objectIndex, 8) != 0) && (arg1 == 0)) {
    3050                play_sound2(SOUND_ACTION_COUNTDOWN_LIGHT);
    ⋮
    3053        case 10:
    3054            if ((func_80072E54(objectIndex, 0x00000010, 0x00000017, 1, 6, 0) != 0) && (arg1 == 0)) {
    3055                D_801656F0 = 1;
    ⋮
    3058        case 11:
    3059            if (set_and_run_timer_object(objectIndex, 8) != 0) {
    ⋮
    3062                    play_sound2(SOUND_ACTION_GREEN_LIGHT);
    
    src/update_objects.c lines 3037–3063 at 58cfcb0 · upstream ↗
    4749        } else if (D_8018D168 == 1) {
    4750            if (D_801656F0 == 1) {
    4751                if (D_801652E0[playerIndex] == 0) {
    4752                    D_801652E0[playerIndex] = gRaceFrameCounter;
    ⋮
    4755            if (controller->button & A_BUTTON) {
    4756                player_accelerate_during_start_sequence(player);
    4757            } else {
    4758                player_decelerate_during_start_sequence(player, 5.0f);
    
    src/player_controller.c lines 4749–4759 at 58cfcb0 · upstream ↗
    3669    if (D_801656F0 == 1) {
    3670        time_delta = gRaceFrameCounter - D_801652E0[playerIndex];
    3671        if (gModeSelection == TIME_TRIALS) {
    3672            var_v0 = 0x14;
    3673        } else {
    3674            var_v0 = 8;
    ⋮
    3676        if ((time_delta < var_v0) && ((player->kartProps & THROTTLE) != THROTTLE)) {
    3677            player->triggers |= START_BOOST_TRIGGER;
    3678        } else if ((player->topSpeed * 0.9f) <= player->currentSpeed) {
    3679            if ((player->triggers & START_BOOST_TRIGGER) != START_BOOST_TRIGGER) {
    3680                player->triggers |= START_SPINOUT_TRIGGER;
    ⋮
    3685    player->kartProps |= THROTTLE;
    
    src/player_controller.c lines 3669–3685 at 58cfcb0 · upstream ↗
    3703    player->triggers &= ~START_BOOST_TRIGGER;
    3704    player->kartProps &= ~THROTTLE;
    
    src/player_controller.c lines 3703–3704 at 58cfcb0 · upstream ↗
    1392    if ((player->triggers & START_BOOST_TRIGGER) == START_BOOST_TRIGGER) {
    1393        func_8002A704(player, playerId);
    
    src/player_controller.c lines 1392–1393 at 58cfcb0 · upstream ↗
    1112void func_8002A704(Player* player, s8 playerIndex) {
    1113    player->effects |= MUSHROOM_EFFECT;
    1114    player->triggers &= ~START_BOOST_TRIGGER;
    ⋮
    1120    player->boostTimer = 0x0050;
    
    src/player_controller.c lines 1112–1120 at 58cfcb0 · upstream ↗
    522void trigger_shroom(Player* player, s8 playerIndex) {
    ⋮
    526    player->effects |= MUSHROOM_EFFECT;
    ⋮
    544    player->boostTimer = 0x50;
    
    src/effects.c lines 522–544 at 58cfcb0 · upstream ↗
    441#define START_SPINOUT_TRIGGER    0x10000000 // Spinning out by holding gas at start of race
    
    include/defines.h line 441 at 58cfcb0 · upstream ↗
    1254    if (gIsGamePaused == false) {
    1255        func_8008C1D8(&D_80165678);
    1256        gRaceFrameCounter++;
    
    src/code_80057C60.c lines 1253–1256 at 58cfcb0 · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-22.

    Revised after a check by a second AI model, 2026-10-22.

    In the claim ledger

  5. ^In the US version of Mario Kart 64, CPU_FAST_EFFECT, which the decompilers comment as the "CPU Rubberbanding flag", raises a CPU driver's forward force: while it's set, a term in that force moves toward 380 by half the gap each update, and once it's cleared the term falls toward 0 by a tenth of the gap. regulate_cpu_speed sets the flag on a CPU driver below its target speed when the pacing check func_800088D8 returns true, and clears it otherwise.Coden64decomp/mk64
    How we know
    479#define CPU_FAST_EFFECT             0x200000 // CPU Rubberbanding flag
    
    include/defines.h line 479 at 58cfcb0 · upstream ↗
    3086    if ((player->type & PLAYER_HUMAN) != PLAYER_HUMAN) {
    3087        if ((player->effects & CPU_FAST_EFFECT) == CPU_FAST_EFFECT) {
    3088            move_f32_towards(&player->unk_0E8, 380.0f, 0.5f);
    3089        } else {
    3090            move_f32_towards(&player->unk_0E8, 0.0f, 0.1f);
    
    src/player_controller.c lines 3086–3092 at 58cfcb0 · upstream ↗
    3107    var_f2 = (player->unk_08C + player->unk_0E8 + player->boostPower + player->unk_0E4) - player->unk_0A0;
    
    src/player_controller.c line 3107 at 58cfcb0 · upstream ↗
    863void move_f32_towards(f32* startingValue, f32 targetValue, f32 somePercent) {
    864    *startingValue -= ((*startingValue - targetValue) * somePercent);
    
    src/render_player.c lines 863–864 at 58cfcb0 · upstream ↗
    203                if (var_a1 != 1) {
    204                    if (speed < targetSpeed) {
    ⋮
    206                            player_accelerate_alternative(player);
    ⋮
    209                        } else if (func_800088D8(playerId, gLapCountByPlayerId[playerId],
    210                                                 gGPCurrentRaceRankByPlayerIdDup[playerId]) == true) {
    211                            player->effects |= CPU_FAST_EFFECT;
    212                            player_accelerate_alternative(player);
    213                        } else {
    214                            player->effects &= ~CPU_FAST_EFFECT;
    215                            player_decelerate_alternative(player, 1.0f);
    
    src/cpu_vehicles_camera_path/cpu_speed_control.inc.c lines 203–216 at 58cfcb0 · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-22.

    Checked by a second AI model, 2026-10-22.

    In the claim ledger

Sources

Code