data/claims/mk64.yamlMario Kart 64 (the n64decomp decompilation, n64decomp/mk64)
Game: Mario Kart 64.
In 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. mk64/item-roulette
About: Mario Kart 64 Item distribution
Value: 100 slots per place
Codemk64: a decompilation of Mario Kart 64 (n64decomp/mk64) ·src/update_objects.c#L3665-L3671u8 gen_random_item(s16 rank, s16 isCpu) {
u16 rand = random_int(100);
…
sRandomItemIndex = ((u32) rand + (sRandomItemIndex + gControllerRandom) + gRaceFrameCounter) % 100U;mk64: a decompilation of Mario Kart 64 (n64decomp/mk64) · src/update_objects.c#L3673-L3685if (gModeSelection == VERSUS) {
switch (gPlayerCountSelection1) {
case TWO_PLAYERS_SELECTED:
…
case THREE_PLAYERS_SELECTED:
…
case FOUR_PLAYERS_SELECTED:
…
randomItem = *((rank * 100) + curve + sRandomItemIndex);mk64: a decompilation of Mario Kart 64 (n64decomp/mk64) · src/update_objects.c#L3687-L3696} else if (gModeSelection == BATTLE) {
curve = segmented_to_virtual((void*) common_battle_item_curve);
randomItem = curve[sRandomItemIndex];
} else { // GP Mode
if (isCpu == 0) {
curve = segmented_to_virtual((void*) common_grand_prix_human_item_curve);
} else {
curve = segmented_to_virtual((void*) common_grand_prix_cpu_item_curve);
}
randomItem = *((rank * 100) + curve + sRandomItemIndex);mk64: a decompilation of Mario Kart 64 (n64decomp/mk64) · src/update_objects.c#L3702-L3714u8 gen_random_item_human(UNUSED s16 arg0, s16 rank) {
return gen_random_item(rank, false);
…
u8 cpu_gen_random_item(UNUSED s32 arg0, s16 rank) {
return gen_random_item(rank, true);
…
randomItem = gen_random_item_human(gLapCountByPlayerId[arg1], gGPCurrentRaceRankByPlayerId[arg1]);mk64: a decompilation of Mario Kart 64 (n64decomp/mk64) · src/cpu_vehicles_camera_path.c#L3918-L3920cpu_decisions_branch_item(playerId, &cpuStrategy->branch,
cpu_gen_random_item((s16) gLapCountByPlayerId[playerId],
gGPCurrentRaceRankByPlayerId[playerId]));mk64: a decompilation of Mario Kart 64 (n64decomp/mk64) · src/code_80057C60.c#L1205-L1215void randomize_seed_from_controller(s32 arg0) {
…
if ((controller->button & A_BUTTON) != 0) {
gControllerRandom++;
…
if ((controller->button & B_BUTTON) != 0) {
…
if ((controller->button & R_TRIG) != 0) {mk64: a decompilation of Mario Kart 64 (n64decomp/mk64) · src/racing/math_util.c#L1269-L1270u16 random_int(u16 arg0) {
return arg0 * (((f32) random_u16()) / 65535.0);Checked by claude, 2026-10-22 — read gen_random_item whole, its two wrappers, the human caller at L3714 and the CPU caller in the item strategy, randomize_seed_from_controller, and random_int; the place passed is gGPCurrentRaceRankByPlayerId and the lap argument is unused; no VERSION_ conditional in the fileThe tables are game data the build extracts from the ROM, so their bytes aren't in the repo and the chance of each item per place isn't read here. The decompilers' extraction map (yamls/us/common_data.yml, outside the fetched paths) gives the human Grand Prix table 800 bytes, eight rows of 100. random_int(100) can return 100 only when random_u16 returns 65535; the mod keeps the slot below 100 either way.
Cited by: Diddy Kong Racing, Item distribution, Mario Kart 64, Mario Kart: Double Dash!!
In 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. mk64/mini-turbo
About: Mario Kart 64 Drift boost
Value
{
"steps-to-boost": 2,
"first-step": 18,
"later-steps": 8,
"overheld": 100,
"boost-updates": 31,
"boost-term": 580
}src/player_controller.c#L1148-L1170void update_drift_state_counter(Player* player, s8 playerIndex) {
if (((s16) player->unk_0C0 / DEGREES(1)) > 0) {
if (((s32) player->steerPosition >> 16) <= -10) {
if (player->driftStateCounter <= 100) {
player->driftStateCounter++;
…
if ((player->driftStateCounter >= 18) && (player->driftStateCounter < 100)) {
if (player->driftState < 3) {
player->driftState++;
…
if ((player->driftStateCounter >= 10) && (player->driftStateCounter < 100)) {
player->driftStateCounter = 10;
…mk64: a decompilation of Mario Kart 64 (n64decomp/mk64) · src/player_controller.c#L4166if (((player->effects & HOP_EFFECT) != HOP_EFFECT) && ((player->effects & DRIFTING_EFFECT) != DRIFTING_EFFECT)) {mk64: a decompilation of Mario Kart 64 (n64decomp/mk64) · src/player_controller.c#L4194-L4214} else if (((player->effects & MIDAIR_EFFECT) != MIDAIR_EFFECT) && ((player->effects & HOP_EFFECT) != HOP_EFFECT)) {
if ((((s16) player->unk_0C0) / DEGREES(1)) > 0) {
…
if ((player->steerPosition >> 16) <= -40) {
player->effects |= DRIFT_OUTSIDE_EFFECT;
…
update_drift_state_counter(player, playerIndex);
…
if ((player->steerPosition >> 16) >= 40) {
player->effects |= DRIFT_OUTSIDE_EFFECT;
…
update_drift_state_counter(player, playerIndex);mk64: a decompilation of Mario Kart 64 (n64decomp/mk64) · include/defines.h#L487#define DRIFT_OUTSIDE_EFFECT 0x20000000 // drifting toward the outside of your turnmk64: a decompilation of Mario Kart 64 (n64decomp/mk64) · include/common_structs.h#L278/* 0x007C */ s32 steerPosition; // Where the kart is steering, related to joystick position. Basically, in [-53 to 53], but shifted 16 bits leftmk64: a decompilation of Mario Kart 64 (n64decomp/mk64) · src/player_controller.c#L3956-L3960clamped_x = get_clamped_stickX_with_deadzone(controller);
…
player->steerPosition = (clamped_x << 16) & 0xFFFF0000;mk64: a decompilation of Mario Kart 64 (n64decomp/mk64) · src/player_controller.c#L4862-L4869if (temp_stickX > 0x35) {
temp_stickY = (temp_stickY * 0x0035) / temp_stickX;
temp_stickX = 0x0035;
}
if (temp_stickX < -0x35) {
temp_stickY = (temp_stickY * 0x0035) / -temp_stickX;
temp_stickX = -0x0035;mk64: a decompilation of Mario Kart 64 (n64decomp/mk64) · src/player_controller.c#L1123-L1143void func_8002A79C(Player* player, s8 playerIndex) {
if (((player->effects & MINI_TURBO_EFFECT) != MINI_TURBO_EFFECT) &&
((player->effects & DRIFTING_EFFECT) != DRIFTING_EFFECT) && (player->driftState >= 2)) {
player->effects |= MINI_TURBO_EFFECT;
player->unk_23A = 0;
…
} else if ((player->effects & MINI_TURBO_EFFECT) == MINI_TURBO_EFFECT) {
player->unk_23A += 1;
if (player->unk_23A >= 0x1F) {
player->unk_23A = 0;
player->effects &= ~MINI_TURBO_EFFECT;mk64: a decompilation of Mario Kart 64 (n64decomp/mk64) · src/player_controller.c#L2139-L2140if ((player->type & PLAYER_HUMAN) == PLAYER_HUMAN) {
func_8002A79C(player, playerId);mk64: a decompilation of Mario Kart 64 (n64decomp/mk64) · src/player_controller.c#L3093-L3107if ((player->type & PLAYER_HUMAN) == PLAYER_HUMAN) {
if (((player->effects & MINI_TURBO_EFFECT) == MINI_TURBO_EFFECT) &&
((player->effects & DRIFTING_EFFECT) != DRIFTING_EFFECT)) {
move_f32_towards(&player->unk_0E8, 580.0f, 0.2f);
} else {
move_f32_towards(&player->unk_0E8, 0.0f, 0.01f);
…
var_f2 = (player->unk_08C + player->unk_0E8 + player->boostPower + player->unk_0E4) - player->unk_0A0;mk64: a decompilation of Mario Kart 64 (n64decomp/mk64) · src/render_player.c#L863-L864void move_f32_towards(f32* startingValue, f32 targetValue, f32 somePercent) {
*startingValue -= ((*startingValue - targetValue) * somePercent);mk64: a decompilation of Mario Kart 64 (n64decomp/mk64) · src/player_controller.c#L2742-L2748spF4[2] = func_80030150(player, playerId);
mtxf_transform_vec3f_mat3(spF4, player->orientationMatrix);
…
newVelocity[2] += (((spF4[2] + sp7C) + spD0[2]) - (newVelocity[2] * (0.12 * player->kartFriction))) / 6000.0;Checked by claude, 2026-10-25 — read get_clamped_stickX_with_deadzone (L4827-L4878), which caps the stick at ±0x35 (53), and its store into steerPosition (L3956-L3960); read update_drift_state_counter whole (both drift directions), the steering function's drifting branch (the else of the not-hopping-and-not-drifting test at L4166, on the ground) and its outside test, func_8002A79C and its human-only call, and the force sum in func_80030150 (L2990) that one movement routine turns by the kart's orientation into velocityThe counter steps once per call of update_drift_state_counter, one per player update; how updates map to displayed frames isn't read. "Toward the outside" follows the sign of the DRIFT_OUTSIDE_EFFECT tests in the same branch: a drift with unk_0C0 positive counts steerPosition at -10 or below, and marks -40 or below as the outside. The 31 is computed: the update that starts the boost sets unk_23A to 0, and the 31st after clears the effect. driftState also goes into the drift's particles (src/code_80057C60.c#L2865-L2883).
Cited by: Drift boost, Mario Kart 64
In 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. mk64/top-speed
About: Mario Kart 64 Engine class
Value
{
"50cc": [
290,
294
],
"100cc": [
310,
314
],
"150cc": [
320,
324
],
"extra": [
310,
314
],
"battle": [
245,
245
]
}src/data/kart_attributes.c#L63-L86// Mario Luigi Yoshi Toad D.K. Wario Peach Bowser
f32 gTopSpeed50cc[] = {
// 50CC
290.0, 290.0, 294.0, 294.0, 290.0, 290.0, 294.0, 290.0,
…
f32 gTopSpeed100cc[] = {
// 100CC
310.0, 310.0, 314.0, 314.0, 310.0, 310.0, 314.0, 310.0,
…
f32 gTopSpeed150cc[] = {
// 150CC
320.0, 320.0, 324.0, 324.0, 320.0, 320.0, 324.0, 320.0,
…mk64: a decompilation of Mario Kart 64 (n64decomp/mk64) · src/spawn_players.c#L89-L110switch (gModeSelection) {
case GRAND_PRIX:
case VERSUS:
…
player->topSpeed = gTopSpeedTable[gCCSelection][player->characterId];
…
// Uses 100CC values
case TIME_TRIALS:
…
player->topSpeed = gTopSpeedTable[CC_100][player->characterId];
…
case BATTLE:
…mk64: a decompilation of Mario Kart 64 (n64decomp/mk64) · include/defines.h#L160-L164#define CC_50 0
#define CC_100 1
#define CC_150 2
#define CC_EXTRA 3
#define CC_BATTLE 4mk64: a decompilation of Mario Kart 64 (n64decomp/mk64) · include/defines.h#L187-L194#define MARIO 0
#define LUIGI 1
#define YOSHI 2
#define TOAD 3
#define DK 4
#define WARIO 5
#define PEACH 6
#define BOWSER 7Checked by claude, 2026-10-22 — read the five top-speed rows and their pointer table, the spawn switch that indexes it by class or mode, and the class and character defines that order the rows and columnstopSpeed scales the acceleration steps (in player_accelerate_during_start_sequence each tenth of it has its own rate, src/player_controller.c#L3639-L3667); the unit is the game's own. The same spawn switch reads two more per-class tables, unnamed (D_800E2400, D_800E24B4), and a third (D_800E2568) that also favors the three light drivers.
Cited by: Engine class, Mario Kart 64
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. mk64/rubber-band
About: Mario Kart 64 Rubber-band AI
Value: 380
Codemk64: a decompilation of Mario Kart 64 (n64decomp/mk64) ·include/defines.h#L479#define CPU_FAST_EFFECT 0x200000 // CPU Rubberbanding flagmk64: a decompilation of Mario Kart 64 (n64decomp/mk64) · src/player_controller.c#L3086-L3092if ((player->type & PLAYER_HUMAN) != PLAYER_HUMAN) {
if ((player->effects & CPU_FAST_EFFECT) == CPU_FAST_EFFECT) {
move_f32_towards(&player->unk_0E8, 380.0f, 0.5f);
} else {
move_f32_towards(&player->unk_0E8, 0.0f, 0.1f);mk64: a decompilation of Mario Kart 64 (n64decomp/mk64) · src/player_controller.c#L3107var_f2 = (player->unk_08C + player->unk_0E8 + player->boostPower + player->unk_0E4) - player->unk_0A0;mk64: a decompilation of Mario Kart 64 (n64decomp/mk64) · src/render_player.c#L863-L864void move_f32_towards(f32* startingValue, f32 targetValue, f32 somePercent) {
*startingValue -= ((*startingValue - targetValue) * somePercent);mk64: a decompilation of Mario Kart 64 (n64decomp/mk64) · src/cpu_vehicles_camera_path/cpu_speed_control.inc.c#L203-L216if (var_a1 != 1) {
if (speed < targetSpeed) {
…
} else if (func_800088D8(playerId, gLapCountByPlayerId[playerId],
gGPCurrentRaceRankByPlayerIdDup[playerId]) == true) {
player->effects |= CPU_FAST_EFFECT;
player_accelerate_alternative(player);
} else {
player->effects &= ~CPU_FAST_EFFECT;
player_decelerate_alternative(player, 1.0f);Checked by claude, 2026-10-22 — read the flag's define, the CPU branch of func_80030150 that moves unk_0E8 and the sum that adds it to the force, move_f32_towards, and regulate_cpu_speed's normal branch; func_800088D8 itself read but not traced (see notes)The statement leaves out when func_800088D8 returns true, because its inputs are mostly unnamed. As read: Time Trials and human players always pass; a CPU driver in first place fails when its lead over the best-placed human, in path points, passes a per-course allowance times the class index plus one, once its speed reads 20 or more (src/cpu_vehicles_camera_path.c#L1016-L1040); other places pass when the gap to the driver in D_80163344[0] exceeds a per-place allowance from a course table (L1043-L1089). Other branches of regulate_cpu_speed set the flag too (cpu_speed_control.inc.c#L172-L176 and L188-L190, and func_80007D04). A human mini-turbo drives the same unk_0E8 term toward 580 (mk64/mini-turbo).
Cited by: Mario Kart 64, Rubber-band AI
In 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. mk64/start-boost
About: Mario Kart 64 Rocket start
Value
{
"window": 8,
"window-time-trials": 20,
"spinout-at": 0.9,
"boost-timer": 80
}src/update_objects.c#L3037-L3063case 7:
if (set_and_run_timer_object(objectIndex, 0x00000014) != 0) {
…
play_sound2(SOUND_ACTION_COUNTDOWN_LIGHT);
…
case 9:
if ((set_and_run_timer_object(objectIndex, 8) != 0) && (arg1 == 0)) {
play_sound2(SOUND_ACTION_COUNTDOWN_LIGHT);
…
case 10:
if ((func_80072E54(objectIndex, 0x00000010, 0x00000017, 1, 6, 0) != 0) && (arg1 == 0)) {
D_801656F0 = 1;
…mk64: a decompilation of Mario Kart 64 (n64decomp/mk64) · src/player_controller.c#L4749-L4759} else if (D_8018D168 == 1) {
if (D_801656F0 == 1) {
if (D_801652E0[playerIndex] == 0) {
D_801652E0[playerIndex] = gRaceFrameCounter;
…
if (controller->button & A_BUTTON) {
player_accelerate_during_start_sequence(player);
} else {
player_decelerate_during_start_sequence(player, 5.0f);mk64: a decompilation of Mario Kart 64 (n64decomp/mk64) · src/player_controller.c#L3669-L3685if (D_801656F0 == 1) {
time_delta = gRaceFrameCounter - D_801652E0[playerIndex];
if (gModeSelection == TIME_TRIALS) {
var_v0 = 0x14;
} else {
var_v0 = 8;
…
if ((time_delta < var_v0) && ((player->kartProps & THROTTLE) != THROTTLE)) {
player->triggers |= START_BOOST_TRIGGER;
} else if ((player->topSpeed * 0.9f) <= player->currentSpeed) {
if ((player->triggers & START_BOOST_TRIGGER) != START_BOOST_TRIGGER) {
player->triggers |= START_SPINOUT_TRIGGER;
…mk64: a decompilation of Mario Kart 64 (n64decomp/mk64) · src/player_controller.c#L3703-L3704player->triggers &= ~START_BOOST_TRIGGER;
player->kartProps &= ~THROTTLE;mk64: a decompilation of Mario Kart 64 (n64decomp/mk64) · src/player_controller.c#L1392-L1393if ((player->triggers & START_BOOST_TRIGGER) == START_BOOST_TRIGGER) {
func_8002A704(player, playerId);mk64: a decompilation of Mario Kart 64 (n64decomp/mk64) · src/player_controller.c#L1112-L1120void func_8002A704(Player* player, s8 playerIndex) {
player->effects |= MUSHROOM_EFFECT;
player->triggers &= ~START_BOOST_TRIGGER;
…
player->boostTimer = 0x0050;mk64: a decompilation of Mario Kart 64 (n64decomp/mk64) · src/effects.c#L522-L544void trigger_shroom(Player* player, s8 playerIndex) {
…
player->effects |= MUSHROOM_EFFECT;
…
player->boostTimer = 0x50;mk64: a decompilation of Mario Kart 64 (n64decomp/mk64) · include/defines.h#L441#define START_SPINOUT_TRIGGER 0x10000000 // Spinning out by holding gas at start of racemk64: a decompilation of Mario Kart 64 (n64decomp/mk64) · src/code_80057C60.c#L1253-L1256if (gIsGamePaused == false) {
func_8008C1D8(&D_80165678);
gRaceFrameCounter++;Checked by claude, 2026-10-22 — read the Lakitu countdown's states 7 to 11 (the only countdown-light sounds are in states 7 and 9), the start-sequence input branch that records each player's first frame with the window open, player_accelerate_during_start_sequence's window test, the decelerate routine that clears the trigger and THROTTLE, func_8002A704 beside trigger_shroom, and the race frame counter's stepTHROTTLE is set at the end of each accelerating update and cleared by each decelerating one, so the test needs A up on the update before the press. The window counts the race frame counter, which steps once per unpaused call of func_80059AC8; its rate against displayed frames, and the countdown's timing in seconds, aren't read. The flag and the per-player first frame (D_801656F0, D_801652E0) are unnamed in the decompilation. The demo sets the trigger directly for some drivers (src/cpu_vehicles_camera_path.c#L2224-L2229).
Cited by: Diddy Kong Racing, Mario Kart 64, Rocket start