Item distribution
The rules that choose which item a racer gets from an item box, often weighted by race position.
On this page
Item distribution decides what an item box gives. Mario Kart 64 rolls a slot in a 100-slot row for the racer’s place in Grand Prix and Versus, and one row for everyone in Battle1. Mario Kart: Double Dash!! also reads a row for the place, as weights over nine common items and the driver’s own special, and the partner’s held item rules some of them out2. In Diddy Kong Racing no roll picks a balloon’s type: the track fixes it3.
- PlacedDiddy Kong Racing (1997). Each balloon's color is fixed on the track, and taking the same color again raises the weapon up to a third level.3
- FlatMario Kart 64 (1996). Battle reads one 100-slot row whatever the place.1
- By placeMario Kart 64 (1996). Grand Prix and Versus read a 100-slot row for the driver's place, with separate tables for human and CPU drivers in Grand Prix.1Mario Kart: Double Dash!! (2003). Grand Prix and Versus weigh nine common items and the driver's own special by a row for the place, read from a disc file, with the partner's item ruling some out.2,4
Games
| Game | Year | How | Note |
|---|---|---|---|
| Diddy Kong Racing | 1997 | Placed | each balloon's color is fixed on the track, and taking the same color again raises the weapon up to a third level |
| Mario Kart 64 | 1996 | Flat | Battle reads one 100-slot row whatever the place |
| Mario Kart 64 | 1996 | By place | Grand Prix and Versus read a 100-slot row for the driver's place, with separate tables for human and CPU drivers in Grand Prix |
| Mario Kart: Double Dash!! | 2003 | By place | Grand Prix and Versus weigh nine common items and the driver's own special by a row for the place, read from a disc file, with the partner's item ruling some out |
Every claim about this mechanic, by game (4)
References
- ^ abcIn the US version of Mario Kart 64,
gen_random_itempicks 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 readcommon_grand_prix_human_item_curveand CPU driverscommon_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/mk64revisedHow 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.
- ^ abIn the doldecomp decompilation of Mario Kart: Double Dash!!, which builds a USA debug version (
MarioClub_us) and whose item manager,Sato/ItemObjMgr.cpp, does not yet match the game's code, the item pick reads byte weights from a file on the disc,/Item/ItemSlotList.dat(orItemSlotList1.datorItemSlotList2.dat, by the race's item-slot type). The file holds lists, each with a row of weights for every place, and a Grand Prix or Versus pick reads the row for the kart's place less one. Outside LAN play, Grand Prix reads a list by engine class (150cc and Mirror share one) for human players and the next list for CPU drivers, and Versus reads one list for every driver by the number of karts, two to four. The pick adds the row's weights for nine common kinds and for the driver's own special item, draws a whole number below the total (computed), and walks the running sum. The special's weight is multiplied by 1.5 when the two riders are a default pairing (isDefaultCharCombi), and the special is left out when the partner holds or stocks a special item, or when it isItemHeartand the kart already has one; four common kinds (ItemThunder,ItemStar,ItemKinokoSuc, andItemFlyTurtle, which the atlas reads as the Spiny Shell) are left out when the partner holds or stocks the same kind.startShuffleclears the flag the code calls_7, andstartItemShuffleSinglesets it when itsdoShuffleargument is true; with it set, the pick first draws among the specials alone.setDynamicRate, which copies the weights the pick reads, writes 0 for any kind whoseIsAbleToCreateItemis false (a function the decompilers comment as fabricated), and in Grand Prix multiplies the CPU list'sItemFlyTurtleweight by 1.5 whileRivalBodyCtrl::isPlayerFirst()is true. In Grand Prix, Mario Kart 64 instead reads one byte from a 100-slot row for the place, from a human or a CPU table, with no partner or character in the pick.Code notesdoldecomp/mkdd · n64decomp/mk64revisedHow we know
13WIP 1:1 Decompilation of Mario Kart Double Dash!! ⋮ 17Currently only the debug version is supported.
README.md lines 13–17 at 1d2918c · upstream ↗ 80 To use a version other than `MarioClub_us` (USA), specify it with `--version`.README.md line 80 at 1d2918c · upstream ↗ NonMatching = False
configure.py#L357 · upstream ↗ 1303 Object(NonMatching, "Sato/ItemObjMgr.cpp"),configure.py line 1303 at 1d2918c · upstream ↗ 76 static const char *getSlotList(int slotType) ⋮ 78 const char *ret = "/Item/ItemSlotList.dat"; 79 switch (slotType) ⋮ 81 case 2: 82 ret = "/Item/ItemSlotList1.dat"; 83 break; 84 case 3: 85 ret = "/Item/ItemSlotList2.dat"; 86 break;
include/Sato/ItemObjMgr.h lines 76–89 at 1d2918c · upstream ↗ 1638 u8 *slotListData = (u8 *)ResMgr::getPtr(ResMgr::mcArcMRAM, getSlotList(RCMGetManager()->getItemSlotType()));src/Sato/ItemObjMgr.cpp line 1638 at 1d2918c · upstream ↗ 1647 switch (RCMGetManager()->getRaceLevel()) ⋮ 1649 case LVL_50CC: 1650 slotCount = 0; 1651 enemySlotCount = 1; 1652 break; 1653 case LVL_100CC: 1654 slotCount = 2; 1655 enemySlotCount = 3; 1656 break; 1657 case LVL_150CC: 1658 case LVL_MIRROR: 1659 slotCount = 4; ⋮
src/Sato/ItemObjMgr.cpp lines 1647–1662 at 1d2918c · upstream ↗ 1664 if (RCMGetManager()->isLANMode()) ⋮ 1666 switch (RCMGetManager()->getKartNumber()) ⋮ 1668 case 2: 1669 slotCount = 6; 1670 break; 1671 case 3: 1672 slotCount = 7; 1673 break; 1674 case 4: 1675 slotCount = 8; 1676 break; ⋮ 1679 break; ⋮
src/Sato/ItemObjMgr.cpp lines 1664–1699 at 1d2918c · upstream ↗ 1719 u8 *defaultSlotList = slotListData + calcBufOffset(slotListData + 1, slotCount); 1720 setToList(defaultSlotList + 1, &mSlotList); ⋮ 1738 u8 *enemyList = slotListData; 1739 if (RCMGetManager()->getRaceMode() == VERSUS_RACE) ⋮ 1741 enemyList += calcBufOffset(enemyList + 1, slotCount); 1742 enemyList += 1; ⋮ 1746 enemyList += calcBufOffset(enemyList + 1, enemySlotCount); 1747 enemyList += 1; ⋮ 1749 setToList(enemyList, &mSlotListEnemy);
src/Sato/ItemObjMgr.cpp lines 1719–1749 at 1d2918c · upstream ↗ 1753u32 ItemShuffleMgr::calcBufOffset(u8 *pData, int n) ⋮ 1758 u8 playerCount = *pData++; 1759 u8 itemCount = *pData++; 1760 offset += playerCount * itemCount + 2;
src/Sato/ItemObjMgr.cpp lines 1753–1763 at 1d2918c · upstream ↗ 1766void ItemShuffleMgr::setToList(u8 *pData, ItemShuffleMgr::KartSlotData *slotData) ⋮ 1768 u8 playerCount = *pData++; 1769 u8 itemCount = *pData++; ⋮ 1776 for (u8 playerIndex = 0; playerIndex < playerCount; playerIndex++) ⋮ 1789 for (u8 itemIndex = 0; itemIndex < itemCount; itemIndex++) ⋮ 1791 for (u8 playerIndex = 0; playerIndex < playerCount; playerIndex++) ⋮ 1793 slotData->mList[playerIndex].slotTable[0][itemIndex] = *pData++;
src/Sato/ItemObjMgr.cpp lines 1766–1795 at 1d2918c · upstream ↗ 1843int ItemShuffleMgr::SlotItem(const int kart_index, const u8 driver_index) { 1844 bool hasEnemy = !ObjUtility::isPlayerDriver(kart_index); ⋮ 1846 if (!RCMGetManager()->isRaceModeGp()) { 1847 hasEnemy = false; ⋮ 1850 const KartSlotData *slotList = hasEnemy ? &mSlotListEnemy : &mSlotList; ⋮ 1852 int specialKind = ItemObj::getSpecialKind(kart_index, driver_index); 1853 int rankIdx = RCMGetKartChecker(kart_index)->getRank() - 1;
src/Sato/ItemObjMgr.cpp lines 1843–1853 at 1d2918c · upstream ↗ 1881 u8 swapped_idx = driver_index == 0 ? 1 : 0; 1882 ItemObj *equipedItem = GetItemObjMgr()->getKartEquipItem(kart_index, swapped_idx); ⋮ 1885 normalKind = equipedItem->getKind(); ⋮ 1888 normalKind = GetItemObjMgr()->getStockItem(kart_index, swapped_idx); ⋮ 1890 const bool combi = RCMGetManager()->getKartInfo(kart_index)->isDefaultCharCombi(); 1891 if (_7) { 1892 int slot = calcRndSpecialSlot(rankIdx, *slotList, combi); ⋮ 1900 return calcSlot(rdata, specialKind, normalKind, combi);
src/Sato/ItemObjMgr.cpp lines 1881–1900 at 1d2918c · upstream ↗ 1564 int sSlotItemIndex[27] = { 1565 0, 2, 13, 3, 1566 5, 18, 6, 10, 1567 15, 17, 1, 4,
src/Sato/ItemObjMgr.cpp lines 1564–1571 at 1d2918c · upstream ↗ 371 case 6: ⋮ 373 removeItem(new ItemStar(6)); ⋮ 387 case 10: ⋮ 389 removeItem(new ItemThunder(0xa)); ⋮ 399 case 13: ⋮ 401 removeItem(new ItemFlyTurtle(0xd)); ⋮ 403 case 14: ⋮ 405 removeItem(new ItemHeart(0xe)); ⋮ 422 case 18: ⋮ 424 removeItem(new ItemKinokoSuc(18));
src/Sato/ItemObjMgr.cpp lines 371–424 at 1d2918c · upstream ↗ 732int CLPointControllerFlyTurtle::findNextPointNo(CLPoint *point) { ⋮ 736 if(RCMGetKartChecker(i)->getRank() == 1) 737 groupID = GetKartCtrl()->GetKartCenterPtr(i)->getGroupID();
src/Sato/ItemFlyTurtle.cpp lines 732–737 at 1d2918c · upstream ↗ 1957void ItemShuffleMgr::calcRaceUseNormalItem(u32 *pTotal, ItemShuffleMgr::KartSlotRankDataSet *rdata, int maxId) ⋮ 1959 for (int i = 0; i < sSlotNormalItemNum; i++) ⋮ 1961 int itemIdx = sSlotItemIndex[i]; 1962 if ((((itemIdx != 10) && (itemIdx != 6) && (itemIdx != 0x12)) && (itemIdx != 0xd)) || maxId != itemIdx) ⋮ 1964 *pTotal += rdata->slotData->mList[rdata->kart_rank].slotTable[1][i];
src/Sato/ItemObjMgr.cpp lines 1957–1966 at 1d2918c · upstream ↗ 1974void ItemShuffleMgr::calcSpecialItemNum(u32 *pTotal, ItemShuffleMgr::KartSlotRankDataSet *data, int itemID1, int itemID2, bool charCombi) ⋮ 1978 for (int i = sSlotNormalItemNum; i < data->slotData->totalSlots; i++) ⋮ 1980 if (itemID1 == sSlotKindIndexArray[i]) { ⋮ 1983 if (ItemObj::IsSpecialItem(itemID2) || (itemID1 == 0xe && ItemObjMgr::getItemObjMgr()->getHeartItem(data->kart_index))) { 1984 sTempSlotUseItem[sSlotNormalItemNum] = false; ⋮ 1988 u32 chance = data->slotData->mList[data->kart_rank].slotTable[1][i]; ⋮ 1990 if (charCombi) { 1991 chance *= 1.5f; ⋮ 1993 *pTotal += chance;
src/Sato/ItemObjMgr.cpp lines 1974–1995 at 1d2918c · upstream ↗ 2024int ItemShuffleMgr::calcRank(KartSlotRankDataSet rdata) ⋮ 2027 u32 randomNum = stGetRnd(0)->getRandomMax(rdata.total - 1); ⋮ 2032 for (int i = 0; i < sSlotNormalItemNum + 1; i++, prevTotalChance = totalChance) ⋮ 2042 totalChance += sTempSlotUseItem[i] ? itemChance : 0; 2043 if ((prevTotalChance <= randomNum) && (totalChance > randomNum)) ⋮ 2045 ret = sSlotKindIndexArray[itemIdx];
src/Sato/ItemObjMgr.cpp lines 2024–2046 at 1d2918c · upstream ↗ 2059int ItemShuffleMgr::calcSlot(KartSlotRankDataSet &rdata, int p2, int p3, bool charCombi) ⋮ 2065 calcRaceUseNormalItem(&total, &rdata, p3); 2066 calcSpecialItemNum(&total, &rdata, p2, p3, charCombi); ⋮ 2070 return calcRank(rdata);
src/Sato/ItemObjMgr.cpp lines 2059–2070 at 1d2918c · upstream ↗ 511u32 stRandom::getRandomMax(u32 max) ⋮ 513 return ((max + 1) * get_ufloat_1());
src/Sato/stMath.cpp lines 511–513 at 1d2918c · upstream ↗ 217 f32 get_ufloat_1() ⋮ 226 out.s = (this->get() >> 9) | 0x3f800000; 227 return out.f - 1;
include/JSystem/JMath/JMath.h lines 217–228 at 1d2918c · upstream ↗ 526bool KartInfo::isDefaultCharCombi() ⋮ 530 if (mKartCharacters[0].getPartnerID() == mKartCharacters[1].getCharID()) 531 ret = true;
src/Kaneshige/KartInfo.cpp lines 526–531 at 1d2918c · upstream ↗ 1815void ItemShuffleMgr::setAllDynamicRate() ⋮ 1817 setDynamicRate(&mSlotList, false); 1818 if (!RCMGetManager()->isLANMode() && RCMGetManager()->getRaceMode() == GRAND_PRIX) 1819 setDynamicRate(&mSlotListEnemy, true); ⋮ 1826 if (GetItemObjMgr()->IsAbleToCreateItem(sSlotItemIndex[i])) 1827 ableToCreate = true; ⋮ 1830 if (ableToCreate) { 1831 slotData->mList[j].slotTable[1][i] = slotData->mList[j].slotTable[0][i]; 1832 if (isGrandPrix && RivalBodyCtrl::isPlayerFirst() && sSlotItemIndex[i] == 0xd) { 1833 slotData->mList[j].slotTable[1][i] *= sGPEnemyFlyTurtleItemSlotRatio; ⋮ 1836 else { 1837 slotData->mList[j].slotTable[1][i] = 0;
src/Sato/ItemObjMgr.cpp lines 1815–1838 at 1d2918c · upstream ↗ 1224bool ItemObjMgr::IsAbleToCreateItem(int itemIdx) { // UNUSED, fabricated, size mismatchsrc/Sato/ItemObjMgr.cpp line 1224 at 1d2918c · upstream ↗ 70 void startShuffle() ⋮ 72 mRollFlags |= 1; 73 _7 = false;
include/Sato/ItemObjMgr.h lines 70–73 at 1d2918c · upstream ↗ 1325void ItemObjMgr::startItemShuffleSingle(int kart_index, bool doShuffle) { ⋮ 1329 mShuffMgr[kart_index][driver_index]->startShuffle(); 1330 if(doShuffle) { 1331 mShuffMgr[kart_index][driver_index]->set_7(true);
src/Sato/ItemObjMgr.cpp lines 1325–1331 at 1d2918c · upstream ↗ 64 f32 sGPEnemyFlyTurtleItemSlotRatio = 1.5f;src/Sato/ItemObjMgr.cpp line 64 at 1d2918c · upstream ↗ 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 ↗ 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 ↗ 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.
- ^ abIn the US 1.0 version of Diddy Kong Racing, a weapon balloon's type is set by its entry in the track's object list, with no roll: the code names five types, boost, missile, trap, shield, and magnet, which the decompilers' names for the all-balloons cheats pair with blue, red, green, yellow, and rainbow. A racer that touches a balloon takes its type. If the racer already held the same type with any left, the weapon's level rises by one, up to the third (level 2); otherwise it starts at the first. In a challenge the level stops at the second, and trap balloons start there; the Maximum Power-up cheat makes every pickup third-level, and CPU-driven boss vehicles collect none. The weapon and its quantity come from a table the game loads as an asset, two bytes for each type and level, so they aren't in the repo. A CPU racer's driving routine
func_80042D20can also raise a first-level pickup by one, on a percent chance from the AI behavior table. Mario Kart 64 instead picks an item box's item in Grand Prix from a 100-slot row for the driver's place.CodeDavidSM64/Diddy-Kong-Racing · n64decomp/mk64revisedHow we know
120typedef enum BalloonType { 121 BALLOON_TYPE_BOOST, 122 BALLOON_TYPE_MISSILE, 123 BALLOON_TYPE_TRAP, 124 BALLOON_TYPE_SHIELD, 125 BALLOON_TYPE_MAGNET
include/enums.h lines 120–126 at a5eb080 · upstream ↗ 193typedef struct LevelObjectEntry_WeaponBalloon { ⋮ 196 /* 0x09 */ u8 balloonType; Hint((Enum:BalloonType))
include/level_object_entries.h lines 193–196 at a5eb080 · upstream ↗ 4658 if (cheats & CHEAT_ALL_BALLOONS_ARE_BLUE) { 4659 entry->balloonType = BALLOON_TYPE_BOOST; 4660 } else if (cheats & CHEAT_ALL_BALLOONS_ARE_RED) { 4661 entry->balloonType = BALLOON_TYPE_MISSILE; 4662 } else if (cheats & CHEAT_ALL_BALLOONS_ARE_GREEN) { 4663 entry->balloonType = BALLOON_TYPE_TRAP; 4664 } else if (cheats & CHEAT_ALL_BALLOONS_ARE_YELLOW) { 4665 entry->balloonType = BALLOON_TYPE_SHIELD; 4666 } else if (cheats & CHEAT_ALL_BALLOONS_ARE_RAINBOW) { 4667 entry->balloonType = BALLOON_TYPE_MAGNET;
src/object_functions.c lines 4658–4667 at a5eb080 · upstream ↗ 4679 obj->modelIndex = entry->balloonType; 4680 obj->properties.weaponBalloon.balloonID = obj->modelIndex;
src/object_functions.c lines 4679–4680 at a5eb080 · upstream ↗ 4745 if (racer->vehicleID < VEHICLE_BOSSES || racer->playerIndex != PLAYER_COMPUTER) { 4746 prevBalloonType = racer->balloon_type; 4747 racer->balloon_type = weaponBalloonObj->properties.weaponBalloon.balloonID; 4748 if (prevBalloonType == racer->balloon_type && racer->balloon_quantity != 0) { 4749 racer->balloon_level++; 4750 } else { 4751 racer->balloon_level = 0; ⋮ 4754 if (level_type() & RACETYPE_CHALLENGE) { 4755 if (racer->balloon_level > 1) { 4756 racer->balloon_level = 1; ⋮ 4759 if (racer->balloon_type == BALLOON_TYPE_TRAP) { 4760 racer->balloon_level = 1; ⋮
src/object_functions.c lines 4745–4775 at a5eb080 · upstream ↗ 7009 miscAsset = (s8 *) get_misc_asset(ASSET_MISC_BALLOON_DATA); 7010 weaponID = miscAsset[(racer->balloon_type * 10) + (racer->balloon_level * 2)];
src/racer.c lines 7009–7010 at a5eb080 · upstream ↗ 327 sp38 = sp54->percentages[1][0] + (((sp54->percentages[1][1] - sp54->percentages[1][0]) * (7 - var_t5)) / 7); ⋮ 332 if (racer->unk209 & 1) { 333 if (racer->unk201 == 0) { 334 if (racer->balloon_level == 0) { 335 if (roll_percent_chance(sp38)) { 336 racer->balloon_level++;
src/racer.c lines 327–337 at a5eb080 · upstream ↗ 4303 } else { 4304 racer_AI_pathing_inputs(obj, tempRacer, updateRate);
src/racer.c lines 4303–4304 at a5eb080 · upstream ↗ 750 gAIBehaviourTable = mempool_alloc_safe(temp, COLOUR_TAG_YELLOW); 751 asset_load(ASSET_AI_BEHAVIOUR, (u32) gAIBehaviourTable, temp2, temp);
src/game.c lines 750–751 at a5eb080 · 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 ↗ 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 doldecomp decompilation of Mario Kart: Double Dash!!, which builds a USA debug version (
MarioClub_us) and whose item manager,Sato/ItemObjMgr.cpp, does not yet match the game's code, King Boo and Petey (character IDs 19 and 20) get anItemRndSpecialShuffleMgrfor their item picks, as every driver does in Balloon Battle and the battle the code callsESCAPE_BATTLE; other drivers get the plainItemShuffleMgr. Where the plain pick adds one special item, the driver's own, the random-special pick adds all nine specials, each weighted from the row's columns 18 to 26, counting from 0 (slotTable[1][i + 18]for i from 0 to 8, computed) and multiplied by 1.5 for a default pairing unlessisMiniGame()is true, and leaves out the heart when the kart already has one. It leaves all nine out when the partner holds or stocks a special item. In Grand Prix, Mario Kart 64's pick takes only the place and whether the driver is a CPU.Code notesdoldecomp/mkdd · n64decomp/mk64revisedHow we know
13WIP 1:1 Decompilation of Mario Kart Double Dash!! ⋮ 17Currently only the debug version is supported.
README.md lines 13–17 at 1d2918c · upstream ↗ 1303 Object(NonMatching, "Sato/ItemObjMgr.cpp"),configure.py line 1303 at 1d2918c · upstream ↗ 101 KING_BOO = 19, 102 PETEY = 20,
include/kartEnums.h lines 101–102 at 1d2918c · upstream ↗ 176void ItemObjMgr::createShuffleMgr() ⋮ 182 if (GetGeoObjMgr()->isBalloonBattle() || GetGeoObjMgr()->isEscapeBattle()) ⋮ 184 mShuffMgr[i][j] = new ItemRndSpecialShuffleMgr(); ⋮ 186 else ⋮ 188 s32 charID = RCMGetManager()->getKartInfo(i)->getDriverCharID(j); 189 mShuffMgr[i][j] = !IsSpecialCharacter(charID) ? new ItemShuffleMgr() : new ItemRndSpecialShuffleMgr();
src/Sato/ItemObjMgr.cpp lines 176–193 at 1d2918c · upstream ↗ 1222bool ItemObjMgr::IsSpecialCharacter(s32 charID) { return charID == 0x13 || charID == 0x14; }src/Sato/ItemObjMgr.cpp line 1222 at 1d2918c · upstream ↗ 105 virtual ~ItemShuffleMgr(); // 08 106 virtual void calcRaceUseNormalItem(u32 *, KartSlotRankDataSet *, int); // 0C 107 virtual void calcSpecialItemNum(u32 *, KartSlotRankDataSet *, int, int, bool); // 10 108 virtual int calcRank(KartSlotRankDataSet); // 14 ⋮ 125class ItemRndSpecialShuffleMgr : public ItemShuffleMgr ⋮ 131 virtual void calcRaceUseNormalItem(u32 *, KartSlotRankDataSet *, int); 132 virtual void calcSpecialItemNum(u32 *, KartSlotRankDataSet *, int, int, bool); 133 virtual int calcRank(KartSlotRankDataSet);
include/Sato/ItemObjMgr.h lines 105–133 at 1d2918c · upstream ↗ 1564 int sSlotItemIndex[27] = { 1565 0, 2, 13, 3, 1566 5, 18, 6, 10, 1567 15, 17, 1, 4, 1568 21, 8, 11, 7, 1569 12, 14, 17, 1, 1570 4, 21, 8, 11, 1571 7, 12, 14};
src/Sato/ItemObjMgr.cpp lines 1564–1571 at 1d2918c · upstream ↗ 1974void ItemShuffleMgr::calcSpecialItemNum(u32 *pTotal, ItemShuffleMgr::KartSlotRankDataSet *data, int itemID1, int itemID2, bool charCombi) ⋮ 1980 if (itemID1 == sSlotKindIndexArray[i]) { ⋮ 1988 u32 chance = data->slotData->mList[data->kart_rank].slotTable[1][i];
src/Sato/ItemObjMgr.cpp lines 1974–1995 at 1d2918c · upstream ↗ 2103void ItemRndSpecialShuffleMgr::calcSpecialItemNum(u32 *pTotal, ItemShuffleMgr::KartSlotRankDataSet *data, int itemID1, int itemID2, bool charCombi) { 2104 if (ItemObj::IsSpecialItem(itemID2)) { 2105 for (int i = 0; i < sSlotSpecialItemNum; i++) { 2106 sTempSlotUseItem[i + sSlotNormalItemNum] = false; ⋮ 2108 return; ⋮ 2111 calcRndSpecialRatio(pTotal, data, charCombi);
src/Sato/ItemObjMgr.cpp lines 2103–2111 at 1d2918c · upstream ↗ 2005void ItemShuffleMgr::calcRndSpecialRatio(u32 *pTotal, ItemShuffleMgr::KartSlotRankDataSet *data, bool charCombi) { 2006 for (int i = 0; i < sSlotSpecialItemNum; i++) { 2007 if ((sSlotKindIndexArray[i + sSlotNormalItemNum] == 0xe && ItemObjMgr::getItemObjMgr()->getHeartItem(data->kart_index))) { ⋮ 2012 u32 chance = data->slotData->mList[data->kart_rank].slotTable[1][i + sSlotNormalItemNum + sSlotSpecialItemNum]; ⋮ 2014 if (!GetGeoObjMgr()->isMiniGame() && charCombi) { 2015 chance *= 1.5f; ⋮ 2017 *pTotal += chance;
src/Sato/ItemObjMgr.cpp lines 2005–2019 at 1d2918c · upstream ↗ 2135int ItemRndSpecialShuffleMgr::calcRank(KartSlotRankDataSet slotRankData) ⋮ 2143 for (int idx = 0; idx < slotRankData.slotData->totalSlots; idx++, prevTotalChance = totalChance) ⋮ 2145 u32 itemChance = idx >= sSlotNormalItemNum ? sTempSpecialRatio[idx - sSlotNormalItemNum] : slotRankData.slotData->mList[slotRankData.kart_rank].slotTable[1][idx]; ⋮ 2150 ret = sSlotKindIndexArray[idx];
src/Sato/ItemObjMgr.cpp lines 2135–2150 at 1d2918c · upstream ↗ 3665u8 gen_random_item(s16 rank, s16 isCpu) { 3666 u16 rand = random_int(100);
src/update_objects.c lines 3665–3671 at 58cfcb0 · upstream ↗ 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 3690–3696 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.
Sources
Code
- n64decomp. 2026. “mk64: a decompilation of Mario Kart 64 (n64decomp/mk64).” Commit 58cfcb0. n64decomp/mk64 @ 58cfcb0 · licence, all uses
- SwareJonge and doldecomp contributors. 2026. “mkdd: a decompilation of Mario Kart: Double Dash!! (doldecomp/mkdd).” Commit 1d2918c. doldecomp/mkdd @ 1d2918c · licence, all uses
- DavidSM64 and Diddy-Kong-Racing contributors. 2026. “Diddy-Kong-Racing: a decompilation of Diddy Kong Racing (DavidSM64/Diddy-Kong-Racing).” Commit a5eb080. DavidSM64/Diddy-Kong-Racing @ a5eb080 · licence, all uses