Pikmin
Nintendo EAD's 2001 real-time strategy game for the GameCube, read through the projectPiki decompilation of USA Rev 1.
On this page
Pikmin came out for the GameCube in 20011. The atlas reads it through the projectPiki decompilation, C++ that compiles to the USA Rev 1 release’s own code2. Names and comments quoted here are theirs. Most tuning is read at run time from parameter files on the disc, so the claims give each rule by its parameter’s name, with the code’s default value, which the files can replace.
Each day starts at 7:00 and ends when the clock reaches 19:00, and the clock’s speed comes from a parameter file3. At sunset in the story’s days, any Pikmin that isn’t following the captain, entering or leaving an Onion, turning to look at the captain, or in free mode near an Onion or the ship is killed. The rule is skipped in challenge mode, the tutorial, and the game’s ending4. The game allows 30 days to recover the ship’s parts, and how many the player holds after the 30th picks the ending5.
A buried sprout grows from leaf to bud to flower on timers, and a flower left in the ground wilts back to a leaf6. A Pikmin that drinks nectar becomes a flower at once7. Pellets and enemy bodies carried to an Onion turn into new sprouts, as many as the item’s settings give for a match with the Onion’s color or for a mismatch8. Where Dune II’s refinery pays credits for a harvester’s load9, the Onion pays in units. Fire sets every Pikmin but a red one burning, and bubbles and water catch every Pikmin but a blue one, with exceptions for Pikmin already caught or dying10.
Mechanics
| Mechanic | Kind | How |
|---|---|---|
| Time of day | Game clock | a day runs from 7:00 to 19:00 on a clock paced by a parameter file, and at sunset, outside challenge mode, the tutorial, and the ending, every Pikmin not following the captain, at an Onion, or in free mode near an Onion or the ship is lost |
| Day limit | Ending by progress | 30 days to recover the ship's parts; all 30 give the good ending, and the 25 parts other than five optional ones give the neutral one |
| Unit growth | Timed stages · sprouts | a buried sprout steps from leaf to bud to flower on timers, and a flower left in the ground wilts back to a leaf |
| Unit growth | Fed · Pikmin | a leaf or bud Pikmin that drinks nectar becomes a flower at once |
| Resource harvesting | Carried loads | Pikmin carry pellets and enemy bodies to an Onion, which pays in sprouts of its color: one count for a pellet of its own type, another for the rest |
Every claim about this game, by concept (9)
References
- ^Pikmin came out for the GameCube on October 26, 2001 in Japan and on December 2, 2001 in North America.WikidataWikidata
How we know
+2001-10-26T00:00:00Z
Q1198484, publication date (P577), qualified place of publication (P291) Japan (Q17), platform (P400) GameCube (Q182172) · archived copy ↗ +2001-12-02T00:00:00Z
Q1198484, publication date (P577), qualified place of publication (P291) United States (Q49), platform (P400) GameCube (Q182172) · archived copy ↗ The quote matches our archived copy.
Checked by a second AI model, 2026-10-22.
- ^projectPiki/pikmin is "A complete matching decompilation of Pikmin (GameCube, 2001)" that builds five releases; its configure.py builds USA Rev 1 (
GPIE01_01) by default, and every file the atlas cites is marked Matching there. The repo holds "no game assets", and the game's tuning parameters are read at run time from disc files it doesn't include, so their code defaults can differ from the shipped values.CodeprojectPiki/pikminHow we know
14A complete matching decompilation of Pikmin (GameCube, 2001). ⋮ 18- `GPIE01_01`: USA (Rev 1) - Default Version
README.MD lines 14–18 at 9a21636 · upstream ↗ 28Note: this repository contains **no game assets** - an existing copy of the game is required.README.MD line 28 at 9a21636 · upstream ↗ 30DEFAULT_VERSION = 5 ⋮ 37 "GPIE01_01", # USA Rev 1
configure.py lines 29–37 at 9a21636 · upstream ↗ 596 /// Constructs parameters - default values are overwritten on file read.include/gameflow.h line 596 at 9a21636 · upstream ↗ 594 load("parms/", "gamePrms.bin", 1);src/plugPikiColin/gameflow.cpp line 594 at 9a21636 · upstream ↗ 81 load("parms/", "pikiMgr.bin", 1);src/plugPikiKando/pikiMgr.cpp line 81 at 9a21636 · upstream ↗ 1581 load("parms/", "pelMgr.bin", 1);src/plugPikiKando/pelletMgr.cpp line 1581 at 9a21636 · 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.
- ^ abThe clock advances by the frame's real time (
gsys->getFrameTime()), and a 24-hour game day lasts 60 ×daySpeed×day_multiplyreal seconds:daySpeed(p00) comes from parms/gamePrms.bin, with a code default of 20 minutes that a decompilation comment gives as 27 in the file, andday_multiplycomes from the stage file, 1 if it has none. Each day starts atstartHour(t00, default 7.0) and ends when the time of day reachesendHour(t01, default 19.0), so the playable span is 12 ÷ 24 of a game day (computed): withday_multiplyat 1, 10 real minutes at the code defaults and 13.5 at the comment's 27. The clock advances only while no reset is pending (gsys->resetPending()), no menu is open outside a cutscene, nothing is paused (mPauseAll), no window is over the screen (mIsUIOverlayActive), no cutscene plays, the section's update flags includeUPDATE_WORLD_CLOCK, and the game isn't in the tutorial (isTutorial()).CodeprojectPiki/pikminrevisedHow we know
599 , mStartHour(this, 7.0f, 0.0f, 0.0f, "t00", "startHour") 600 , mEndHour(this, 19.0f, 0.0f, 0.0f, "t01", "endHour") 601 , mRealMinutesPerGameDay(this, 20.0f, 0.0f, 0.0f, "p00", "daySpeed")
include/gameflow.h lines 599–601 at 9a21636 · upstream ↗ 619 Parm<f32> mRealMinutesPerGameDay; ///< _24, p00 - how many real-life minutes correspond to one (24-hr) in-game "day" - def: 27 mins.include/gameflow.h line 619 at 9a21636 · upstream ↗ 594 load("parms/", "gamePrms.bin", 1);src/plugPikiColin/gameflow.cpp line 594 at 9a21636 · upstream ↗ 737 gameflow.mWorldClock.mRealSecsPerGameDay = 60.0f * (gameflow.mTimeMultiplier * gameflow.mParameters->mRealMinutesPerGameDay()); 738 gameflow.mWorldClock.mRealSecsPerGameHour = gameflow.mWorldClock.mRealSecsPerGameDay / gameflow.mWorldClock.mHoursInDay;
include/gameflow.h lines 737–738 at 9a21636 · upstream ↗ 2226 gameflow.mTimeMultiplier = 1.0f; ⋮ 2236 } else if (stream->isToken("day_multiply")) { 2237 sscanf(stream->getToken(true), "%f", &gameflow.mTimeMultiplier);
src/plugPikiColin/newPikiGame.cpp lines 2226–2237 at 9a21636 · upstream ↗ 204 mRealSecsIntoHour += gsys->getFrameTime() * playRate; 205 if (mRealSecsIntoHour >= mRealSecsPerGameHour) { 206 mRealSecsIntoHour -= mRealSecsPerGameHour; 207 mCurrentGameHour++; ⋮ 215 mTimeOfDay = mCurrentGameHour + mRealSecsIntoHour / mRealSecsPerGameHour;
src/plugPikiColin/gameflow.cpp lines 204–215 at 9a21636 · upstream ↗ 2155 if (!gsys->resetPending() && (!mActiveMenu || gameflow.mMoviePlayer->mIsActive)) { 2156 if (!gameflow.mPauseAll && !gameflow.mIsUIOverlayActive) { 2157 if (!gameflow.mMoviePlayer->mIsActive && (mUpdateFlags & UPDATE_WORLD_CLOCK) && !playerState->isTutorial()) { ⋮ 2159 gameflow.mWorldClock.update(1.0f);
src/plugPikiColin/newPikiGame.cpp lines 2155–2159 at 9a21636 · upstream ↗ 286 // handle story mode world map screen if we've made a decision ⋮ 299 enterCourse(stage); ⋮ 302 gameflow.mWorldClock.setTime(gameflow.mParameters->mStartHour());
src/plugPikiColin/mapSelect.cpp lines 286–302 at 9a21636 · upstream ↗ 864 if (!gameflow.mIsDayEndActive && !gameflow.mMoviePlayer->mIsActive 865 && gameflow.mWorldClock.mTimeOfDay >= gameflow.mParameters->mEndHour()) { ⋮ 870 gameflow.mIsDayEndTriggered = TRUE;
src/plugPikiColin/newPikiGame.cpp lines 864–870 at 9a21636 · 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.
- ^When a day ends (
GameCoreSection::cleanupDayEnd), outside challenge mode, the tutorial, and the game's ending (isEnding(): the 30th day, or all 30 ship parts), every Pikmin is killed and counted as left behind unless it is entering or leaving an Onion, or in itsLookAtstate, or following the captain (formation mode) in a state other than drowning, burning, swallowed, bubbled, dying, or flicked, or in free mode (FreeMode, in any state) withinmSunsetSafetyRange(p60, "日没生き残り範囲", code default 200, read from parms/pikiMgr.bin) of an Onion or of the ship, measured byqdist2's ground-plane approximation (|dx| + |dz| − ½ min). Pikmin with mushroom heads die too. If any were left behind, the take-off cutscene plays its enemy-attack version. The survivors then all go into their color's Onion (exitDayEnd), and a Pikmin with no Onion of its color is killed.CodeprojectPiki/pikminrevisedHow we know
598 PRINT("STEP (2) : remove objects (teki/boss/pellet/free pikis)\n"); ⋮ 600 if (!playerState->isChallengeMode() && !playerState->isTutorial() && !playerState->isEnding()) { ⋮ 607 if (piki->isKinoko()) { ⋮ 614 piki->kill(false);
src/plugPikiKando/gameCoreSection.cpp lines 598–618 at 9a21636 · upstream ↗ 630 if (mode == PikiMode::FormationMode) { 631 if (state == PIKISTATE_Drown || state == PIKISTATE_Fired || state == PIKISTATE_Dead || state == PIKISTATE_Swallowed 632 || state == PIKISTATE_Bubble || state == PIKISTATE_Dying || state == PIKISTATE_Flick || !piki->isAlive()) { 633 // do nothing 634 } else { 635 continue; ⋮ 638 if (mode == PikiMode::ExitMode || mode == PikiMode::EnterMode) { 639 continue; 640 } else if (state == PIKISTATE_LookAt) { 641 continue; ⋮ 645 if (piki->mMode == PikiMode::FreeMode) { ⋮ 650 <= pikiMgr->mPikiParms->mPikiParms.mSunsetSafetyRange()) { ⋮
src/plugPikiKando/gameCoreSection.cpp lines 629–676 at 9a21636 · upstream ↗ 112 , mSunsetSafetyRange(this, 200.0f, 0.0f, 5000.0f, "p60", "日没生き残り範囲")include/PikiMgr.h line 112 at 9a21636 · upstream ↗ 81 load("parms/", "pikiMgr.bin", 1);src/plugPikiKando/pikiMgr.cpp line 81 at 9a21636 · upstream ↗ 511 if (x1 > y1) { 512 min = y1; 513 } else { 514 min = x1; ⋮ 517 return (x1 + y1) - (0.5f * min);
src/sysCommon/sysMath.cpp lines 511–517 at 9a21636 · upstream ↗ 110bool PlayerState::isEnding() ⋮ 112 if (getCurrDay() >= (MAX_DAYS - 1)) { 113 // we've hit our 30-day limit 114 return true; ⋮ 116 } else if (getCurrParts() >= MAX_UFO_PARTS) { ⋮ 118 return true;
src/plugPikiKando/playerState.cpp lines 110–118 at 9a21636 · upstream ↗ 1507 if (dayEndObjFlags == 0) { 1508 // no dead pikmin! use correct (frustrated/neutral) animation 1509 dayEndObjFlags |= CAF_DayEndEnemyNoDeaths; 1510 } else { 1511 // dead pikmin :( use killing animation 1512 dayEndObjFlags |= CAF_DayEndEnemyAttack;
src/plugPikiColin/newPikiGame.cpp lines 1507–1512 at 9a21636 · upstream ↗ 362 if (piki->isAlive()) { 363 GoalItem* item = itemMgr->getContainer(piki->mColor); 364 if (item) { 365 item->enterGoal(piki); 366 entered++; 367 } else { 368 piki->kill(false);
src/plugPikiKando/gameCoreSection.cpp lines 362–369 at 9a21636 · 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.
- ^The game allows
MAX_DAYS= 30 days, counted bymCurrentDay(getCurrDay()returns it minus 1). At the end of a day with all 30 ship parts (MAX_UFO_PARTS) the good ending plays. Otherwise, a day count below 30 goes up by 1 with the end-of-day results, and once it has reached 30, the ending is the neutral one if the player holds at leastMIN_HAPPY_END_PARTS= 25 parts, counted without five named parts (the Nova Blaster, Space Float, Massage Machine, Secret Safe, and UV Lamp), and the bad one if not. Computed: of 30 parts with 5 not counted, 25 means every one of the other 25.CodeprojectPiki/pikminHow we know
9#define MAX_UFO_PARTS (30) ⋮ 11#define MAX_DAYS (30) ⋮ 13#define MIN_HAPPY_END_PARTS (25) // NB: also need to edit the hard-coded IDs in PlayerState::getUfoParts
include/GlobalGameOptions.h lines 9–13 at 9a21636 · upstream ↗ 1565 if (playerState->getCurrParts() == MAX_UFO_PARTS) { 1566 // we collected all the parts! play the good ending take off :) 1567 gameflow.mMoviePlayer->startMovie(DEMOID_GoodEndingTakeOff, 0, nullptr, nullptr, nullptr, CAF_AllVisibleMask, true); ⋮ 1569 } else if (gameflow.mWorldClock.mCurrentDay < MAX_DAYS) {
src/plugPikiColin/newPikiGame.cpp lines 1565–1569 at 9a21636 · upstream ↗ 1586 // advance the day and handle the end-of-day results entries 1587 gameflow.mWorldClock.mCurrentDay++;
src/plugPikiColin/newPikiGame.cpp lines 1586–1587 at 9a21636 · upstream ↗ 1624 // we've hit max days, and haven't collected 30 parts :( 1625 if (playerState->happyEndable()) { ⋮ 1627 flowCont.mEndingType = ENDING_Neutral; 1628 gameflow.mMoviePlayer->startMovie(DEMOID_NeutralEndingLeaveOK, 0, nullptr, nullptr, nullptr, CAF_AllVisibleMask, true); 1629 } else { ⋮ 1631 gameflow.mMoviePlayer->startMovie(DEMOID_BadEndingFailEscape, 0, nullptr, nullptr, nullptr, CAF_AllVisibleMask, true);
src/plugPikiColin/newPikiGame.cpp lines 1624–1631 at 9a21636 · upstream ↗ 273bool PlayerState::happyEndable() ⋮ 275 return mRequiredUfoPartCount >= MIN_HAPPY_END_PARTS;
src/plugPikiKando/playerState.cpp lines 273–275 at 9a21636 · upstream ↗ 1090 if (partID != UFOID_NovaBlaster && partID != UFOID_SpaceFloat && partID != UFOID_MassageMachine && partID != UFOID_SecretSafe 1091 && partID != UFOID_UVLamp) { 1092 mRequiredUfoPartCount++;
src/plugPikiKando/playerState.cpp lines 1090–1092 at 9a21636 · upstream ↗ 778int PlayerState::getCurrDay() ⋮ 780 return gameflow.mWorldClock.mCurrentDay - 1;
src/plugPikiKando/playerState.cpp lines 778–780 at 9a21636 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^A buried sprout (
PikiHeadItem) waitsmGrowUpTime(p51, "growupTime(秒)") plus 0 to 2 seconds at random, then plays its growth animation and moves one stage, leaf to bud or bud to flower ((mFlowerStage + 1) % 3). A flower waitsmWiltTime(p52, "kareTime(秒)") plus 0 to 2 seconds, then wilts: it becomes a leaf, and aftermRebirthSeedTime(p53) plus 0 to 2 seconds it goes back to the buried state. The three times are read from parms/pikiMgr.bin; their code defaults are 4, 4, and 1 seconds. A plucked Pikmin keeps its sprout's stage.CodeprojectPiki/pikminHow we know
305void PikiHeadAI::WaitInit::act(AICreature* item) ⋮ 309 if (obj->mFlowerStage == Flower) { 310 item->mSAICtx.mCurrentItemHealth = pikiMgr->mPikiParms->mPikiParms.mWiltTime() + gsys->getRand(1.0f) * 2.0f; 311 } else { 312 item->mSAICtx.mCurrentItemHealth = pikiMgr->mPikiParms->mPikiParms.mGrowUpTime() + gsys->getRand(1.0f) * 2.0f;
src/plugPikiKando/itemAI.cpp lines 305–313 at 9a21636 · upstream ↗ 326 f32& health = item->mSAICtx.mCurrentItemHealth; 327 health -= gsys->getFrameTime(); 328 if (health < 0.0f) { 329 if (obj->mFlowerStage == Flower) { 330 item->mSAICtx.mStateMachine->transit(item, PIKIHEAD_Unk10); 331 } else { 332 item->mSAICtx.mStateMachine->transit(item, PIKIHEAD_Unk7);
src/plugPikiKando/itemAI.cpp lines 326–332 at 9a21636 · upstream ↗ 163 addState(PIKIHEAD_Unk7, PikiHeadMotion::UgGrow); 164 addState(PIKIHEAD_Growuped, PANI_NO_MOTION, new GrowupedExec); ⋮ 166 addState(PIKIHEAD_Unk10, PikiHeadMotion::Sioreru); 167 addState(PIKIHEAD_Kareta, PANI_NO_MOTION, new KaretaInit, new KaretaExec); ⋮ 173 addArrow(PIKIHEAD_Unk7, saiMotionAction0Event, PIKIHEAD_Growuped); 174 addArrow(PIKIHEAD_Growuped, saiMotionDoneEvent, PIKIHEAD_Wait); 175 addArrow(PIKIHEAD_Unk10, saiMotionDoneEvent, PIKIHEAD_Kareta);
src/plugPikiKando/itemAI.cpp lines 163–175 at 9a21636 · upstream ↗ 349 obj->mFlowerStage = (obj->mFlowerStage + 1) % 3;src/plugPikiKando/itemAI.cpp line 349 at 9a21636 · upstream ↗ 381 item->mSAICtx.mCurrentItemHealth = pikiMgr->mPikiParms->mPikiParms.mRebirthSeedTime() + 2.0f * gsys->getRand(1.0f); 382 obj->mFlowerStage = Leaf; ⋮ 393 item->mSAICtx.mStateMachine->transit(item, PIKIHEAD_Bury);
src/plugPikiKando/itemAI.cpp lines 381–393 at 9a21636 · upstream ↗ 101 , mGrowUpTime(this, 4.0f, 0.0f, 300.0f, "p51", "growupTime(秒)") 102 , mWiltTime(this, 4.0f, 0.0f, 300.0f, "p52", "kareTime(秒)") 103 , mRebirthSeedTime(this, 1.0f, 0.0f, 300.0f, "p53", "rebirthTime(秒)")
include/PikiMgr.h lines 101–103 at 9a21636 · upstream ↗ 66enum PikiHappa { 67 Leaf = 0, 68 Bud = 1, 69 Flower = 2,
include/GlobalGameOptions.h lines 66–69 at 9a21636 · upstream ↗ 2581 piki->setFlower(navi->mSproutToPluck->mFlowerStage);src/plugPikiKando/naviState.cpp line 2581 at 9a21636 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^A Pikmin that isn't yet a flower drinks when it touches a nectar puddle in its normal state, unless it is damaged, carrying (transport mode), or mushroom-headed; the puddle is an
OBJTYPE_Waterobject, which a decompilation comment calls nectar. If it drank, its growth animation makes it a flower (setFlower(Flower)) at once, from leaf or bud.CodeprojectPiki/pikminHow we know
407 if (!piki->isKinoko()) { ⋮ 411 if (!piki->isDamaged() && piki->mMode != PikiMode::TransportMode) { ⋮ 414 case OBJTYPE_Water: ⋮ 416 // Nectar puddles are modeled as water; non-flower Pikmin can drink to grow. 417 if (piki->mHappa != Flower) { 418 piki->changeMode(PikiMode::FreeMode, piki->mNavi); 419 piki->mCurrNectar = collider; 420 transit(piki, PIKISTATE_Absorb);
src/plugPikiKando/pikiState.cpp lines 407–420 at 9a21636 · upstream ↗ 516 if (mHasAbsorbedNectar) { 517 transit(piki, PIKISTATE_GrowUp);
src/plugPikiKando/pikiState.cpp lines 516–517 at 9a21636 · upstream ↗ 2402 case KEY_Action0: ⋮ 2404 piki->mFloweringTimer++; 2405 seSystem->playPikiSound(SEF_PIKI_GROW4, piki->mSRT.t); 2406 piki->setFlower(Flower);
src/plugPikiKando/pikiState.cpp lines 2402–2406 at 9a21636 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^ abWhen a pellet or an enemy body (both
Pellets with a config from parms/pelMgr.bin) finishes being drawn into an Onion,GoalItem::suckMeadds the config'smMatchingOnyonSeeds(p06) to the Onion's pending count if the config's type (p00) equals the Onion's color, andmNonMatchingOnyonSeeds(p07) otherwise; the code defaults are 1 and 1, and a negative value sets off fireworks instead. The Onion then fires one sprout of its own color per pending count, which lands and buries itself as a leaf; when no sprout object can be created, it stores a leaf Pikmin inside instead. Ship parts take the ship's path, not this one. In the decompilation's enum the type for bodies,PELTYPE_Corpse, is 0, the same value asPELTYPE_Blue, which the comparison would read as a blue match; the shipped configs' p00 values are data.CodeprojectPiki/pikminHow we know
344void GoalItem::suckMe(Pellet* item) ⋮ 346 PelletConfig* config = item->mConfig; 347 int pikiNum; 348 if (mOnionColour == config->mPelletType()) { 349 pikiNum = config->mMatchingOnyonSeeds(); 350 } else { 351 pikiNum = config->mNonMatchingOnyonSeeds(); ⋮ 354 if (pikiNum < 0) { 355 mSAICtx.mCounter += 2; ⋮ 360 } else { 361 mSAICtx.mCurrAnimId += pikiNum;
src/plugPikiKando/goalItem.cpp lines 344–365 at 9a21636 · upstream ↗ 110 , mPelletType(this, PELTYPE_Blue, 0, 0, "p00", "type(0-2:pel 3:ufo)") ⋮ 118 , mMatchingOnyonSeeds(this, 1, 0, 0, "p06", "intParm1") 119 , mNonMatchingOnyonSeeds(this, 1, 0, 0, "p07", "intParm2")
src/plugPikiKando/pelletMgr.cpp lines 110–119 at 9a21636 · upstream ↗ 1581 load("parms/", "pelMgr.bin", 1);src/plugPikiKando/pelletMgr.cpp line 1581 at 9a21636 · upstream ↗ 346 if (mSuckProgress >= 1.0f) { 347 if (pelt->mConfig->mPelletType() == PELTYPE_UfoPart) { 348 pelt->mTargetGoal->finishSuck(pelt); 349 } else { 350 pelt->mTargetGoal->suckMe(pelt);
src/plugPikiKando/pelletState.cpp lines 346–350 at 9a21636 · upstream ↗ 853 if (item->mSAICtx.mCurrAnimId > 0) { ⋮ 860 PikiHeadItem* seed = static_cast<PikiHeadItem*>(itemMgr->birth(OBJTYPE_Pikihead)); ⋮ 866 seed->setColor(obj->mOnionColour); ⋮ 872 C_SAI(seed)->start(seed, PikiHeadAI::PIKIHEAD_Flying); 873 } else { 874 pikiInfMgr.incPiki(obj->mOnionColour, Leaf); 875 obj->mHeldPikis[Leaf]++; ⋮ 886 obj->mSAICtx.mCurrAnimId--;
src/plugPikiKando/itemAI.cpp lines 853–886 at 9a21636 · upstream ↗ 170 addArrow(PIKIHEAD_Flying, saiBounceEvent, PIKIHEAD_Bounce); 171 addArrow(PIKIHEAD_Bounce, saiMotionDoneEvent, PIKIHEAD_Bury);
src/plugPikiKando/itemAI.cpp lines 170–171 at 9a21636 · upstream ↗ 147void PelletView::becomePellet(u32 id, Vector3f NRef pos, f32 direction) ⋮ 154 Pellet* pellet = pelletMgr->newPellet(id, this);
src/plugPikiKando/pelletMgr.cpp lines 147–154 at 9a21636 · upstream ↗ 37enum PelletType { 38 // Easier to label this separate, these will also have PelletColor as -1 39 PELTYPE_Corpse = 0, ⋮ 41 // Blue, Red, Yellow pellets 42 PELTYPE_Blue = 0, 43 PELTYPE_Red = 1, 44 PELTYPE_Yellow = 2,
include/Pellet.h lines 37–44 at 9a21636 · upstream ↗ 52enum PikiColor { 53 Blue = 0, 54 Red = 1, 55 Yellow = 2,
include/GlobalGameOptions.h lines 52–55 at 9a21636 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^A refinery empties a docked harvester a step at a time: each call to
Script_Structure_RefineSpicemoves up to 3 load units at full health, 2 once damaged, and 1 below 171/256 of full health (computed fromhp × 256 / max × 3 / 256, at least 1), and pays 7 credits per unit to the player, or 6 to 9 at random per call to a computer house; the next call waits 6 script ticks. Computed: a full harvester (100) is worth 700 credits to the player.CodeOpenDUNEHow we know
125 harvesterStep = (s->o.hitpoints * 256 / si->o.hitpoints) * 3 / 256; ⋮ 128 if (u->amount != 0 && harvesterStep < 1) harvesterStep = 1; ⋮ 131 creditsStep = 7; 132 if (u->o.houseID != g_playerHouseID) { 133 creditsStep += (Tools_Random_256() % 4) - 1; ⋮ 136 creditsStep *= harvesterStep;
src/script/structure.c lines 125–136 at ebea79a · upstream ↗ 147 h->credits += creditsStep; 148 u->amount -= harvesterStep; ⋮ 151 s->o.script.delay = 6;
src/script/structure.c lines 146–151 at ebea79a · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-22.
- ^Fire (
InteractFire) sets a live Pikmin burning (startFire) unless it is red. A bubble attack (InteractBubble) puts a live Pikmin in its bubble state unless it is blue, or already bubbled, dying, or dead. A Pikmin that lands on a water surface, or rides an object standing on water within 10 units of its height, starts drowning unless it is blue, itsmInWaterTimerisn't 0 (it has already touched water), or it is dying, dead, pressed (PIKISTATE_Pressed), or hanging over water (PIKISTATE_WaterHanged). Yellow Pikmin get no exemption in these three checks.CodeprojectPiki/pikminrevisedHow we know
168 if (!piki->isAlive()) { 169 return false; ⋮ 174 if (state == PIKISTATE_Dying || state == PIKISTATE_Dead || state == PIKISTATE_Bubble) { 175 return false; ⋮ 178 // blue pikmin are immune to bubble 179 if (piki->mColor != Blue) { 180 piki->changeMode(0, piki->mNavi); 181 piki->mFSM->transit(piki, PIKISTATE_Bubble); ⋮ 184 return false; ⋮ 192 if (!piki->isAlive()) { 193 return false; ⋮ 196 // red pikmin are immune to fire ⋮
src/plugPikiKando/interactBattle.cpp lines 168–199 at 9a21636 · upstream ↗ 1790 if (attr == ATTR_Water && mInWaterTimer == 0 && mColor != Blue) { 1791 isDrownSurface = true; 1792 } else if (isStickTo() && mInWaterTimer == 0 && mColor != Blue) { ⋮ 1795 if (absF(obj->mSRT.t.y - mSRT.t.y) < 10.0f) { 1796 isDrownSurface = true; ⋮ 1801 if (isDrownSurface && isAlive() && state != PIKISTATE_Dead && state != PIKISTATE_Dying && state != PIKISTATE_Pressed 1802 && state != PIKISTATE_WaterHanged) { ⋮ 1805 mFSM->transit(this, PIKISTATE_Drown); ⋮ 1812 mInWaterTimer = 1;
src/plugPikiKando/piki.cpp lines 1790–1812 at 9a21636 · 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
- projectPiki. 2026. “pikmin: a decompilation of Pikmin (projectPiki/pikmin).” Commit 9a21636. projectPiki/pikmin @ 9a21636 · licence, all uses
- OpenDUNE contributors. 2026. “OpenDUNE: a C re-creation of Dune II from its DOS executable (OpenDUNE/OpenDUNE).” Commit ebea79a. OpenDUNE/OpenDUNE @ ebea79a · licence, all uses
Secondary
- Wikidata contributors. 2026. “Wikidata.” Wikimedia Foundation. original · licence, all uses