From e3e8a5a511ea3c373dbf986a53d3836cb54b858f Mon Sep 17 00:00:00 2001 From: Minty-Meeo <45425365+Minty-Meeo@users.noreply.github.com> Date: Fri, 29 May 2026 12:44:57 -0500 Subject: [PATCH 1/9] Nitpicks --- include/Font.h | 2 ++ include/Texture.h | 6 +++++- src/card/CARDFormat.c | 4 ++-- src/jaudio/hvqm_play.c | 4 ++-- src/pad/Pad.c | 6 +++--- src/plugPikiKando/aiBridge.cpp | 2 +- src/si/SISamplingRate.c | 2 +- src/vi/vi.c | 16 ++++++++-------- 8 files changed, 24 insertions(+), 18 deletions(-) diff --git a/include/Font.h b/include/Font.h index d62088dc..f609531c 100644 --- a/include/Font.h +++ b/include/Font.h @@ -11,6 +11,8 @@ struct Texture; /** * @brief TODO + * + * @note Size: 0x1C. */ struct FontChar { FontChar() diff --git a/include/Texture.h b/include/Texture.h index bbfe2f09..9ee4e4fb 100644 --- a/include/Texture.h +++ b/include/Texture.h @@ -187,6 +187,7 @@ struct Texture : public GfxObject { virtual void makeResident() { } // _10 (weak) u8 getAlpha(int x, int y); + u8 getRed(int x, int y); void read(RandomAccessStream& input); void createBuffer(int width, int height, int texFmt, void* buf); void grabBuffer(int width, int height, bool doClear, bool useMIPmap); @@ -194,7 +195,10 @@ struct Texture : public GfxObject { // unused/inlined: void offsetGLtoGX(int, int); - u8 getRed(int, int); + static void offsetGXtoGL(int, int, int, int); + void offsetGXtoGL(int, int); + void write(Stream*); + static void decodeS3TC(int, int, u8*, u8*); // _00 = VTBL u16 mTexFormat; // _04, see TexImgFormat enum diff --git a/src/card/CARDFormat.c b/src/card/CARDFormat.c index a3b453bb..f915cd92 100644 --- a/src/card/CARDFormat.c +++ b/src/card/CARDFormat.c @@ -66,7 +66,7 @@ s32 __CARDFormatRegionAsync(s32 chan, u16 encode, CARDCallback callback) id = (CARDID*)card->workArea; memset(id, 0xff, CARD_SYSTEM_BLOCK_SIZE); - viDTVStatus = __VIRegs[55]; + viDTVStatus = __VIRegs[VI_DTV_STAT]; id->encode = encode; @@ -148,7 +148,7 @@ s32 CARDFormatAsync(s32 channel, CARDCallback callback) id = &card->workArea->header.id; memset(id, 0xff, CARD_SYSTEM_BLOCK_SIZE); - viDTVStatus = __VIRegs[55]; + viDTVStatus = __VIRegs[VI_DTV_STAT]; id->encode = OSGetFontEncode(); diff --git a/src/jaudio/hvqm_play.c b/src/jaudio/hvqm_play.c index 0c7597bf..d40207e9 100644 --- a/src/jaudio/hvqm_play.c +++ b/src/jaudio/hvqm_play.c @@ -543,7 +543,7 @@ int Jac_GetPicture(void* data, int* x, int* y) if (playback_first_wait) { *(int*)data = 0; - return TRUE; + return 1; } int frame = StreamGetCurrentFrame(0, 2); @@ -604,7 +604,7 @@ int Jac_GetPicture(void* data, int* x, int* y) StreamSyncStopAudio(0); } *(int*)data = 0; - return FALSE; + return 0; } /** diff --git a/src/pad/Pad.c b/src/pad/Pad.c index 8b91516b..05a2b2ac 100644 --- a/src/pad/Pad.c +++ b/src/pad/Pad.c @@ -1,4 +1,5 @@ #include "Dolphin/pad.h" +#include "Dolphin/hw_regs.h" #include "Dolphin/os.h" #include "Dolphin/vi.h" #include @@ -33,7 +34,6 @@ static BOOL OnReset(BOOL f); extern u16 __OSWirelessPadFixMode AT_ADDRESS(OS_BASE_CACHED | 0x30E0); extern u8 GameChoice AT_ADDRESS(OS_BASE_CACHED | 0x30E3); -extern u16 DAT_CC00206C AT_ADDRESS(0xCC00206C); // Which hardware register? static BOOL Initialized = FALSE; @@ -1022,7 +1022,7 @@ void PADSetSamplingRate(u32 msec) } } #if OS_BUILD_VERSION >= 20011002L - SISetXY(((DAT_CC00206C & 1) ? 2 : 1) * xy[msec].line, xy[msec].count); + SISetXY((__VIRegs[VI_CLOCK_SEL] & 1 ? 2u : 1u) * xy[msec].line, xy[msec].count); #else SISetXY(xy[msec].line, xy[msec].count); #endif @@ -1036,7 +1036,7 @@ void PADSetSamplingRate(u32 msec) #if OS_BUILD_VERSION >= 20011002L && OS_BUILD_VERSION < 20011217L /** - * @TODO: Documentation + * This implementation was moved to SISamplingRate.c (`SIRefreshSamplingRate`) */ void __PADRefreshSamplingRate(void) { diff --git a/src/plugPikiKando/aiBridge.cpp b/src/plugPikiKando/aiBridge.cpp index c2fa0361..908ee894 100644 --- a/src/plugPikiKando/aiBridge.cpp +++ b/src/plugPikiKando/aiBridge.cpp @@ -463,7 +463,7 @@ void ActBridge::newInitWork() mCollisionCount = 0; _2A = 0; - if (mActionCounter) { + if (mActionCounter != 0) { return; } diff --git a/src/si/SISamplingRate.c b/src/si/SISamplingRate.c index 55547520..ca4c60f0 100644 --- a/src/si/SISamplingRate.c +++ b/src/si/SISamplingRate.c @@ -51,7 +51,7 @@ void SISetSamplingRate(u32 msec) break; } - SISetXY((__VIRegs[54] & 1 ? 2u : 1u) * xy[msec].line, xy[msec].count); + SISetXY((__VIRegs[VI_CLOCK_SEL] & 1 ? 2u : 1u) * xy[msec].line, xy[msec].count); OSRestoreInterrupts(enabled); } diff --git a/src/vi/vi.c b/src/vi/vi.c index 0f57916a..6a19b521 100644 --- a/src/vi/vi.c +++ b/src/vi/vi.c @@ -469,7 +469,7 @@ void VIInit(void) HorVer.panSizeX = 0x280; HorVer.panSizeY = 0x1E0; HorVer.xfbMode = 0; - dspCfg = __VIRegs[1]; + dspCfg = __VIRegs[VI_DISP_CONFIG]; HorVer.nonInter = (s32)((dspCfg >> 2U) & 1); HorVer.tv = (u32)((dspCfg >> 8U) & 3); tv = (HorVer.tv == 3) ? 0 : HorVer.tv; @@ -482,10 +482,10 @@ void VIInit(void) HorVer.isBlack = 1; HorVer.is3D = 0; OSInitThreadQueue(&retraceQueue); - value = __VIRegs[24]; + value = __VIRegs[VI_DISP_INT_0]; value &= ~0x8000; value = (u16)value; - __VIRegs[24] = value; + __VIRegs[VI_DISP_INT_0] = value; value = __VIRegs[VI_DISP_INT_1]; value = (((u32)(value)) & ~0x00008000) | (((0)) << 15); @@ -993,11 +993,11 @@ static u32 getCurrentHalfLine(void) tm = HorVer.timing; #endif - vcount = __VIRegs[22] & 0x7FF; + vcount = __VIRegs[VI_VERT_COUNT] & 0x7FF; do { vcount0 = vcount; - hcount = __VIRegs[23] & 0x7FF; - vcount = __VIRegs[22] & 0x7FF; + hcount = __VIRegs[VI_HORIZ_COUNT] & 0x7FF; + vcount = __VIRegs[VI_VERT_COUNT] & 0x7FF; } while (vcount0 != vcount); #if OS_BUILD_VERSION >= 20011112L @@ -1024,10 +1024,10 @@ static u32 getCurrentFieldEvenOdd() return 1; } #else - if (__VIRegs[54] & 1) { + if (__VIRegs[VI_CLOCK_SEL] & 1) { tm = getTiming(VI_TVMODE_NTSC_PROG); } else { - value = __VIRegs[1]; + value = __VIRegs[VI_DISP_CONFIG]; nin = ((value >> 2U) & 1); fmt = ((value >> 8U) & 3); tvMode = (fmt << 2) + nin; From c603ea7268d5c043561110fad4b4f19c82d01bdd Mon Sep 17 00:00:00 2001 From: Minty-Meeo <45425365+Minty-Meeo@users.noreply.github.com> Date: Fri, 29 May 2026 12:56:48 -0500 Subject: [PATCH 2/9] Match `Texture::read` for GPIJ01 --- src/sysDolphin/texture.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/sysDolphin/texture.cpp b/src/sysDolphin/texture.cpp index 3272a5f2..5911648c 100644 --- a/src/sysDolphin/texture.cpp +++ b/src/sysDolphin/texture.cpp @@ -167,9 +167,7 @@ void Texture::read(RandomAccessStream& input) TexImg* img = new TexImg; img->importBti(this, input, nullptr); } else { - // this is wrong, but I cant figure it out - size_t len = strlen(input.mPath); - ERROR("Unknown texture extension (%s)!!\n", input.mPath - 3 + len); + ERROR("Unknown texture extension (%s)!!\n", strlen(input.mPath) - 3 + input.mPath); } gsys->addTexture(this, input.mPath); } From 02c71e78fb8e4f30332efc06310065713a16bdc9 Mon Sep 17 00:00:00 2001 From: Minty-Meeo <45425365+Minty-Meeo@users.noreply.github.com> Date: Fri, 29 May 2026 13:59:47 -0500 Subject: [PATCH 3/9] Match `SimpleAI::addArrow` `SimpleAI::getState` was a fake inline (confirmed via DLL + ILK). --- include/SimpleAI.h | 2 -- src/plugPikiKando/simpleAI.cpp | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/include/SimpleAI.h b/include/SimpleAI.h index a41b2b98..c972c6ab 100644 --- a/include/SimpleAI.h +++ b/include/SimpleAI.h @@ -225,8 +225,6 @@ struct SimpleAI : public StateMachine { void start(AICreature*, int); void checkEvent(AICreature*); - inline SAIState* getState(int idx) { return static_cast(mStates[idx]); } - // _00 = VTBL // _00-_1C = StateMachine }; diff --git a/src/plugPikiKando/simpleAI.cpp b/src/plugPikiKando/simpleAI.cpp index 07a75fcf..7e14cae7 100644 --- a/src/plugPikiKando/simpleAI.cpp +++ b/src/plugPikiKando/simpleAI.cpp @@ -168,7 +168,7 @@ SAIArrow* SimpleAI::addArrow(int stateIdId, SAIEvent* event, int nextStateId) return nullptr; } - SAIState* state = getState(stateIdx); + SAIState* state = static_cast(mStates[stateIdx]); arrow->mArrowIdx = state->mArrowCount; state->mRootArrow.add(arrow); state->mArrowCount++; From c1b4d95355eb05b82490800e9cf0c2c7ee1f1a90 Mon Sep 17 00:00:00 2001 From: Minty-Meeo <45425365+Minty-Meeo@users.noreply.github.com> Date: Fri, 29 May 2026 14:43:24 -0500 Subject: [PATCH 4/9] ILK Sleuthing: `SAIContext` This previously undocumented struct was found thanks to its constructor appearing in the DLL and being named in the ILK. --- include/AICreature.h | 82 ++++++++------ include/SimpleAI.h | 2 +- src/plugPikiKando/actor.cpp | 8 +- src/plugPikiKando/aiPut.cpp | 10 +- src/plugPikiKando/bombItem.cpp | 6 +- src/plugPikiKando/creature.cpp | 4 +- src/plugPikiKando/demoEvent.cpp | 4 +- src/plugPikiKando/goalItem.cpp | 30 +++--- src/plugPikiKando/interactBattle.cpp | 6 +- src/plugPikiKando/itemAI.cpp | 156 +++++++++++++-------------- src/plugPikiKando/itemGem.cpp | 10 +- src/plugPikiKando/itemMgr.cpp | 36 +++---- src/plugPikiKando/mizuItem.cpp | 8 +- src/plugPikiKando/piki.cpp | 8 +- src/plugPikiKando/pikiState.cpp | 8 +- src/plugPikiKando/pikiheadItem.cpp | 14 +-- src/plugPikiKando/plantMgr.cpp | 6 +- src/plugPikiKando/simpleAI.cpp | 40 +++---- 18 files changed, 225 insertions(+), 213 deletions(-) diff --git a/include/AICreature.h b/include/AICreature.h index 2bdef7d2..44ff033e 100644 --- a/include/AICreature.h +++ b/include/AICreature.h @@ -12,8 +12,40 @@ struct AState; template struct StateMachine; +struct AICreature; struct CollEvent; +/** + * @brief TODO + * + * @note Size: 0x48. + */ +struct SAIContext { + SAIContext() + { + mCollidingCreature = nullptr; + _08.set(0.0f, 0.0f, 0.0f); + mCounter = 0; + mCurrAnimId = 0; + mCurrentState = nullptr; + mCurrentItemHealth = 0.0f; + } + + Creature* mCollidingCreature; // _00 + Creature* mTargetCreature; // _04 + Vector3f _08; // _08 + int mCurrAnimId; // _14, to do with bombs + int mCounter; // _18, used by `SluiceAI`, `PikiHeadAI`, and `GoalAI`. + f32 mCurrentItemHealth; // _1C + f32 _20; // _20 + f32 mMaxItemHealth; // _24 + AState* mCurrentState; // _28 + StateMachine* mStateMachine; // _2C + int mCurrentEventCount; // _30 + int mMaxEventCount; // _34 + bool mEventFlags[16]; // _38 +}; + /** * @brief TODO * @@ -22,24 +54,24 @@ struct CollEvent; struct AICreature : public Creature, public PaniAnimKeyListener { AICreature(CreatureProp*); - virtual void collisionCallback(immut CollEvent&); // _A8 - virtual void bounceCallback(); // _AC - virtual void refresh(Graphics&) = 0; // _EC - virtual void doKill() = 0; // _10C - virtual AState* getCurrState() { return mCurrentState; } // _120 (weak) - virtual void setCurrState(AState* state) { mCurrentState = state; } // _124 (weak) - virtual void playSound(int) { } // _128 (weak) - virtual void playEffect(int) { } // _12C (weak) - virtual void startMotion(int) { } // _130 (weak) - virtual void finishMotion() { } // _134 (weak) - virtual void finishMotion(f32) { } // _138 (weak) - virtual void startMotion(int, f32) { } // _13C (weak) - virtual immut char* getCurrentMotionName() { return "noname"; } // _140 (weak) - virtual f32 getCurrentMotionCounter() { return -123.4f; } // _144 (weak) - virtual f32 getMotionSpeed() { return -123.4f; } // _148 (weak) - virtual void setMotionSpeed(f32) { } // _14C (weak) - virtual void stopMotion() { } // _150 (weak) - virtual void animationKeyUpdated(immut PaniAnimKeyEvent&); // _154 (weak) + virtual void collisionCallback(immut CollEvent&); // _A8 + virtual void bounceCallback(); // _AC + virtual void refresh(Graphics&) = 0; // _EC + virtual void doKill() = 0; // _10C + virtual AState* getCurrState() { return mSAICtx.mCurrentState; } // _120 (weak) + virtual void setCurrState(AState* state) { mSAICtx.mCurrentState = state; } // _124 (weak) + virtual void playSound(int) { } // _128 (weak) + virtual void playEffect(int) { } // _12C (weak) + virtual void startMotion(int) { } // _130 (weak) + virtual void finishMotion() { } // _134 (weak) + virtual void finishMotion(f32) { } // _138 (weak) + virtual void startMotion(int, f32) { } // _13C (weak) + virtual immut char* getCurrentMotionName() { return "noname"; } // _140 (weak) + virtual f32 getCurrentMotionCounter() { return -123.4f; } // _144 (weak) + virtual f32 getMotionSpeed() { return -123.4f; } // _148 (weak) + virtual void setMotionSpeed(f32) { } // _14C (weak) + virtual void stopMotion() { } // _150 (weak) + virtual void animationKeyUpdated(immut PaniAnimKeyEvent&); // _154 (weak) void clearEventFlags(); void setEventFlag(int, bool); @@ -50,19 +82,7 @@ struct AICreature : public Creature, public PaniAnimKeyListener { // _00 = VTBL // _00-_2B8 = Creature // _2B8-_2BC = PaniAnimKeyListener - Creature* mCollidingCreature; // _2BC - Creature* mTargetCreature; // _2C0, 'target'? - Vector3f _2C4; // _2C4, could just be floats - int mCurrAnimId; // _2D0, to do with bombs - int mCounter; // _2D4, used to track stages of gates - f32 mCurrentItemHealth; // _2D8 - f32 _2DC; // _2DC - f32 mMaxItemHealth; // _2E0 - AState* mCurrentState; // _2E4 - StateMachine* mStateMachine; // _2E8 - int mCurrentEventCount; // _2EC - int mMaxEventCount; // _2F0 - bool mEventFlags[16]; // _2F4 + SAIContext mSAICtx; // _2BC }; #endif diff --git a/include/SimpleAI.h b/include/SimpleAI.h index c972c6ab..6f5749c0 100644 --- a/include/SimpleAI.h +++ b/include/SimpleAI.h @@ -5,7 +5,7 @@ #include "StateMachine.h" #include "types.h" -#define C_SAI(obj) static_cast(obj->mStateMachine) +#define C_SAI(obj) static_cast(obj->mSAICtx.mStateMachine) struct SAIEvent; diff --git a/src/plugPikiKando/actor.cpp b/src/plugPikiKando/actor.cpp index 4a8b0126..39db3e9d 100644 --- a/src/plugPikiKando/actor.cpp +++ b/src/plugPikiKando/actor.cpp @@ -36,7 +36,7 @@ void Actor::setType(int /*unused*/, PikiShapeObject* shape, CreatureProp* props, mPikiAnimMgr.startMotion(PaniMotionInfo(PIKIANIM_Wait, nullptr), PaniMotionInfo(PIKIANIM_Wait)); - mStateMachine = ai; + mSAICtx.mStateMachine = ai; } /** @@ -45,7 +45,7 @@ void Actor::setType(int /*unused*/, PikiShapeObject* shape, CreatureProp* props, */ void Actor::startAI(int state) { - ((SimpleAI*)mStateMachine)->start(this, state); + C_SAI(this)->start(this, state); } /** @@ -94,8 +94,8 @@ void Actor::doAnimation() */ void Actor::doAI() { - if (mStateMachine) { - mStateMachine->exec(this); + if (mSAICtx.mStateMachine) { + mSAICtx.mStateMachine->exec(this); } } diff --git a/src/plugPikiKando/aiPut.cpp b/src/plugPikiKando/aiPut.cpp index 00069859..a5de8866 100644 --- a/src/plugPikiKando/aiPut.cpp +++ b/src/plugPikiKando/aiPut.cpp @@ -333,7 +333,7 @@ void ActPutBomb::initPut() held->mVelocity.add(vel); MsgUser msg(0); BombItem* bomb = static_cast(held); - static_cast(bomb->mStateMachine)->procMsg(bomb, &msg); + C_SAI(bomb)->procMsg(bomb, &msg); mAnimationFinished = false; mState = STATE_Put; } @@ -368,10 +368,10 @@ int ActPutBomb::exeThrow() InteractRelease release(mPiki, 1.0f); Creature* held = mPiki->getHoldCreature(); held->stimulate(release); - held->mVelocity = throwVel; - held->mTargetVelocity = throwVel; - BombItem* bomb = static_cast(held); - bomb->mCurrAnimId = 0; + held->mVelocity = throwVel; + held->mTargetVelocity = throwVel; + BombItem* bomb = static_cast(held); + bomb->mSAICtx.mCurrAnimId = 0; C_SAI(bomb)->start(bomb, BombAI::BOMB_Unk1); bomb->disableFixPos(); diff --git a/src/plugPikiKando/bombItem.cpp b/src/plugPikiKando/bombItem.cpp index e027e53f..af56d9c5 100644 --- a/src/plugPikiKando/bombItem.cpp +++ b/src/plugPikiKando/bombItem.cpp @@ -81,7 +81,7 @@ BombItem::BombItem(CreatureProp* props, ItemShapeObject* shape, SimpleAI* ai) { mLifeGauge.mSnapToTargetHealth = true; mItemShapeObject = shape; - mStateMachine = ai; + mSAICtx.mStateMachine = ai; mLifeGauge.mRenderStyle = LifeGauge::Wheel; } @@ -142,7 +142,7 @@ void BombItem::update() if (state != BombAI::BOMB_Die && state != BombAI::BOMB_Bomb && state != BombAI::BOMB_Mizu && mGroundTriangle && MapCode::getAttribute(mGroundTriangle) == ATTR_Water) { PRINT("BOMB WATER START **********\n"); - mStateMachine->transit(this, BombAI::BOMB_Mizu); + mSAICtx.mStateMachine->transit(this, BombAI::BOMB_Mizu); } if (state == BombAI::BOMB_Unk1 && mGroundTriangle) { @@ -165,7 +165,7 @@ void BombItem::refresh2d(Graphics& gfx) int state = getCurrState()->getID(); if (state == 2) { - mLifeGauge.updValue(mCurrentItemHealth, mMaxItemHealth); + mLifeGauge.updValue(mSAICtx.mCurrentItemHealth, mSAICtx.mMaxItemHealth); mLifeGauge.mPosition = mSRT.t; mLifeGauge.mScale = 5000.0f / gfx.mCamera->mNear; mLifeGauge.refresh(gfx); diff --git a/src/plugPikiKando/creature.cpp b/src/plugPikiKando/creature.cpp index 8630bab2..be30db28 100644 --- a/src/plugPikiKando/creature.cpp +++ b/src/plugPikiKando/creature.cpp @@ -512,8 +512,8 @@ void Creature::kill(bool) if (ai->getCurrState()->getID() != 1) { BombItem* bomb = static_cast(held); MsgUser msg(1); - bomb->mCurrAnimId = 1; - static_cast(bomb->mStateMachine)->procMsg(bomb, &msg); + bomb->mSAICtx.mCurrAnimId = 1; + C_SAI(bomb)->procMsg(bomb, &msg); } } } diff --git a/src/plugPikiKando/demoEvent.cpp b/src/plugPikiKando/demoEvent.cpp index 8201db2f..04740c4a 100644 --- a/src/plugPikiKando/demoEvent.cpp +++ b/src/plugPikiKando/demoEvent.cpp @@ -170,7 +170,7 @@ void DemoEventMgr::act(int cmd, int type) switch (type) { case 0: { - goal->mCurrAnimId++; + goal->mSAICtx.mCurrAnimId++; goal->emitPiki(); break; } @@ -224,7 +224,7 @@ void DemoEventMgr::act(int cmd, int type) if (playerState->hasContainer(goalID) && GameStat::allPikis[goalID] == 0) { PRINT("***** SUPPLY 1 PiKI (COLOR = %d)\n", goalID); playerState->mResultFlags.setOn(zen::RESFLAG_PikminSeedStageUp); - goal->mCurrAnimId++; + goal->mSAICtx.mCurrAnimId++; goal->emitPiki(); } break; diff --git a/src/plugPikiKando/goalItem.cpp b/src/plugPikiKando/goalItem.cpp index 6d0df5d7..48d02cf5 100644 --- a/src/plugPikiKando/goalItem.cpp +++ b/src/plugPikiKando/goalItem.cpp @@ -351,13 +351,13 @@ void GoalItem::suckMe(Pellet* item) } if (pikiNum < 0) { - mCounter += 2; + mSAICtx.mCounter += 2; MsgUser msg(0); C_SAI(this)->procMsg(this, &msg); playEventSound(this, SE_CONTAINER_HANABI); playEventSound(this, SE_CONTAINER_PELLETIN2); } else { - mCurrAnimId += pikiNum; + mSAICtx.mCurrAnimId += pikiNum; MsgUser msg(0); C_SAI(this)->procMsg(this, &msg); playEventSound(this, SE_CONTAINER_PELLETIN2); @@ -459,17 +459,17 @@ bool GoalItem::needShadow() GoalItem::GoalItem(CreatureProp* prop, ItemShapeObject* shape1, ItemShapeObject* shape2, ItemShapeObject* shape3, SimpleAI* ai) : Suckable(16, prop) { - mOnionColour = 0; - mItemShapeObject = nullptr; - _438[0] = shape1; - _438[1] = shape2; - _438[2] = shape3; - mItemShapeObject = _438[0]; - mStateMachine = ai; - mCollInfo = new CollInfo(15); - mHaloEfx = nullptr; - mSpotEfx = nullptr; - mSuckEfx = nullptr; + mOnionColour = 0; + mItemShapeObject = nullptr; + _438[0] = shape1; + _438[1] = shape2; + _438[2] = shape3; + mItemShapeObject = _438[0]; + mSAICtx.mStateMachine = ai; + mCollInfo = new CollInfo(15); + mHaloEfx = nullptr; + mSpotEfx = nullptr; + mSuckEfx = nullptr; } /** @@ -618,8 +618,8 @@ void GoalItem::startAI(int) Vector3f(rotateX[0], rotateY[0], rotateZ[0])); f32 scale = 1.0f; mSRT.s.set(scale, scale, scale); - mCurrAnimId = 0; - mCounter = 0; + mSAICtx.mCurrAnimId = 0; + mSAICtx.mCounter = 0; int i; for (i = 0; i < 3; i++) { diff --git a/src/plugPikiKando/interactBattle.cpp b/src/plugPikiKando/interactBattle.cpp index eb5959e4..0daa04e3 100644 --- a/src/plugPikiKando/interactBattle.cpp +++ b/src/plugPikiKando/interactBattle.cpp @@ -542,9 +542,9 @@ bool InteractPress::actPiki(Piki* piki) immut bomb->resetStateGrabbed(); if (bomb->mObjType == OBJTYPE_Bomb) { MsgUser msg(1); - BombItem* bombItem = static_cast(bomb); - bombItem->mCurrAnimId = 0; - static_cast(bombItem->mStateMachine)->procMsg(bombItem, &msg); + BombItem* bombItem = static_cast(bomb); + bombItem->mSAICtx.mCurrAnimId = 0; + C_SAI(bombItem)->procMsg(bombItem, &msg); PRINT("bomb immediately\n"); } } diff --git a/src/plugPikiKando/itemAI.cpp b/src/plugPikiKando/itemAI.cpp index 1bce2994..9c38d366 100644 --- a/src/plugPikiKando/itemAI.cpp +++ b/src/plugPikiKando/itemAI.cpp @@ -68,8 +68,8 @@ SluiceAI::SluiceAI() */ void SluiceAI::Init::act(AICreature* item) { - item->mCounter = 0; - item->mStateMachine->transit(item, Sluice_WaitInit); + item->mSAICtx.mCounter = 0; + item->mSAICtx.mStateMachine->transit(item, Sluice_WaitInit); } /** @@ -77,14 +77,14 @@ void SluiceAI::Init::act(AICreature* item) */ void SluiceAI::MotionDone::act(AICreature* item) { - PRINT("GATE ** MOTION DONE ** %d\n", item->mCounter); + PRINT("GATE ** MOTION DONE ** %d\n", item->mSAICtx.mCounter); - if (item->mCounter <= 0) { - item->mCounter = 0; - item->mStateMachine->transit(item, Sluice_WaitInit); + if (item->mSAICtx.mCounter <= 0) { + item->mSAICtx.mCounter = 0; + item->mSAICtx.mStateMachine->transit(item, Sluice_WaitInit); } else { - item->mCounter--; - item->mStateMachine->transit(item, Sluice_ChangeInit); + item->mSAICtx.mCounter--; + item->mSAICtx.mStateMachine->transit(item, Sluice_ChangeInit); } } @@ -93,8 +93,8 @@ void SluiceAI::MotionDone::act(AICreature* item) */ void SluiceAI::AddCount::act(AICreature* item) { - PRINT("GATE ** COUNTER became %d\n", item->mCounter); - item->mCounter++; + PRINT("GATE ** COUNTER became %d\n", item->mSAICtx.mCounter); + item->mSAICtx.mCounter++; } /** @@ -122,15 +122,15 @@ void SluiceAI::WaitInit::act(AICreature* item) void SluiceAI::ChangeInit::act(AICreature* item) { BuildingItem* obj = (BuildingItem*)item; - PRINT("******* CHANGE INIT ******** aiContext.int=%d curr=%d\n", obj->mCurrStage, obj->mCurrAnimId); + PRINT("******* CHANGE INIT ******** aiContext.int=%d curr=%d\n", obj->mCurrStage, obj->mSAICtx.mCurrAnimId); item->setMotionSpeed(30.0f); - item->startMotion(obj->mCurrAnimId); + item->startMotion(obj->mSAICtx.mCurrAnimId); obj->startBreakEffect(); - if (obj->mCurrAnimId == obj->mNumStages - 1) { + if (obj->mSAICtx.mCurrAnimId == obj->mNumStages - 1) { obj->mWayPoint->setFlag(true); } - obj->mCurrAnimId++; + obj->mSAICtx.mCurrAnimId++; } /** @@ -142,7 +142,7 @@ void SluiceAI::DamageInit::act(AICreature* item) if (obj->mCurrStage < obj->mNumStages) { item->setMotionSpeed(30.0f); - item->startMotion(obj->mCurrAnimId + 3); + item->startMotion(obj->mSAICtx.mCurrAnimId + 3); } } @@ -249,7 +249,7 @@ void PikiHeadAI::BuryExec2::act(AICreature* item) PRINT("to save or not to save ....\n"); // Alright mr shakespeare over here PikiHeadItem* obj = (PikiHeadItem*)item; - obj->mStateMachine->transit(item, PIKIHEAD_Dead); + obj->mSAICtx.mStateMachine->transit(item, PIKIHEAD_Dead); } /** @@ -259,8 +259,8 @@ void PikiHeadAI::BuryInit::act(AICreature* item) { PikiHeadItem* obj = (PikiHeadItem*)item; obj->startFix(); - obj->mFlowerStage = Leaf; - obj->mCurrentItemHealth = pikiMgr->mPikiParms->mPikiParms.mSeedUpTime() + gsys->getRand(1.0f) * 2.0f; + obj->mFlowerStage = Leaf; + obj->mSAICtx.mCurrentItemHealth = pikiMgr->mPikiParms->mPikiParms.mSeedUpTime() + gsys->getRand(1.0f) * 2.0f; STACK_PAD_VAR(2); } @@ -271,11 +271,11 @@ void PikiHeadAI::BuryInit::act(AICreature* item) void PikiHeadAI::BuryExec::act(AICreature* item) { // stupid but fixes a regswap - f32& health = item->mCurrentItemHealth; + f32& health = item->mSAICtx.mCurrentItemHealth; health -= gsys->getFrameTime(); if (health < 0.0f) { item->startMotion(PikiHeadMotion::TaneUp); - item->mStateMachine->transit(item, PIKIHEAD_Tane); + item->mSAICtx.mStateMachine->transit(item, PIKIHEAD_Tane); } } @@ -284,7 +284,7 @@ void PikiHeadAI::BuryExec::act(AICreature* item) */ void PikiHeadAI::TaneInit::act(AICreature* item) { - item->mCurrentItemHealth = pikiMgr->mPikiParms->mPikiParms.mPluckWaitTime() + gsys->getRand(1.0f) * 2.0f; + item->mSAICtx.mCurrentItemHealth = pikiMgr->mPikiParms->mPikiParms.mPluckWaitTime() + gsys->getRand(1.0f) * 2.0f; } /** @@ -292,10 +292,10 @@ void PikiHeadAI::TaneInit::act(AICreature* item) */ void PikiHeadAI::TaneExec::act(AICreature* item) { - f32& health = item->mCurrentItemHealth; + f32& health = item->mSAICtx.mCurrentItemHealth; health -= gsys->getFrameTime(); if (health < 0.0f) { - item->mStateMachine->transit(item, PIKIHEAD_Unk5); + item->mSAICtx.mStateMachine->transit(item, PIKIHEAD_Unk5); } } @@ -307,11 +307,11 @@ void PikiHeadAI::WaitInit::act(AICreature* item) PikiHeadItem* obj = (PikiHeadItem*)item; if (obj->mFlowerStage == Flower) { - item->mCurrentItemHealth = pikiMgr->mPikiParms->mPikiParms.mWiltTime() + gsys->getRand(1.0f) * 2.0f; + item->mSAICtx.mCurrentItemHealth = pikiMgr->mPikiParms->mPikiParms.mWiltTime() + gsys->getRand(1.0f) * 2.0f; } else { - item->mCurrentItemHealth = pikiMgr->mPikiParms->mPikiParms.mGrowUpTime() + gsys->getRand(1.0f) * 2.0f; + item->mSAICtx.mCurrentItemHealth = pikiMgr->mPikiParms->mPikiParms.mGrowUpTime() + gsys->getRand(1.0f) * 2.0f; } - item->mCounter = 0; + item->mSAICtx.mCounter = 0; } /** @@ -323,20 +323,20 @@ void PikiHeadAI::WaitExec::act(AICreature* item) PikiHeadItem* obj = (PikiHeadItem*)item; - f32& health = item->mCurrentItemHealth; + f32& health = item->mSAICtx.mCurrentItemHealth; health -= gsys->getFrameTime(); if (health < 0.0f) { if (obj->mFlowerStage == Flower) { - item->mStateMachine->transit(item, PIKIHEAD_Unk10); + item->mSAICtx.mStateMachine->transit(item, PIKIHEAD_Unk10); } else { - item->mStateMachine->transit(item, PIKIHEAD_Unk7); + item->mSAICtx.mStateMachine->transit(item, PIKIHEAD_Unk7); } - } else if (health < 2.0f && obj->mCounter == 0 && obj->mFlowerStage != Flower) { + } else if (health < 2.0f && obj->mSAICtx.mCounter == 0 && obj->mFlowerStage != Flower) { Vector3f pos = obj->mSRT.t; pos.y += 13.0f; EffectParm parm(pos); utEffectMgr->cast(KandoEffect::PikiGrowup1, parm); - obj->mCounter = 1; + obj->mSAICtx.mCounter = 1; } } @@ -368,7 +368,7 @@ void PikiHeadAI::GrowupedExec::act(AICreature* item) */ void PikiHeadAI::GrowEffect::act(AICreature* item) { - item->mStateMachine->transit(item, PIKIHEAD_Wait); + item->mSAICtx.mStateMachine->transit(item, PIKIHEAD_Wait); } /** @@ -378,8 +378,8 @@ void PikiHeadAI::KaretaInit::act(AICreature* item) { PikiHeadItem* obj = (PikiHeadItem*)item; - item->mCurrentItemHealth = pikiMgr->mPikiParms->mPikiParms.mRebirthSeedTime() + 2.0f * gsys->getRand(1.0f); - obj->mFlowerStage = Leaf; + item->mSAICtx.mCurrentItemHealth = pikiMgr->mPikiParms->mPikiParms.mRebirthSeedTime() + 2.0f * gsys->getRand(1.0f); + obj->mFlowerStage = Leaf; } /** @@ -387,10 +387,10 @@ void PikiHeadAI::KaretaInit::act(AICreature* item) */ void PikiHeadAI::KaretaExec::act(AICreature* item) { - f32& health = item->mCurrentItemHealth; + f32& health = item->mSAICtx.mCurrentItemHealth; health -= gsys->getFrameTime(); if (health < 0.0f) { - item->mStateMachine->transit(item, PIKIHEAD_Bury); + item->mSAICtx.mStateMachine->transit(item, PIKIHEAD_Bury); } } @@ -430,9 +430,9 @@ BombAI::BombAI() */ void BombAI::SetInit::act(AICreature* item) { - item->mCurrentItemHealth = pikiMgr->mPikiParms->mPikiParms.mBombSetFuseTime() * (gsys->getRand(1.0f) * 0.05f + 1.0f); - item->mMaxItemHealth = item->mCurrentItemHealth; - PRINT("BOMB * %f/%f\n", item->mCurrentItemHealth, item->mMaxItemHealth); + item->mSAICtx.mCurrentItemHealth = pikiMgr->mPikiParms->mPikiParms.mBombSetFuseTime() * (gsys->getRand(1.0f) * 0.05f + 1.0f); + item->mSAICtx.mMaxItemHealth = item->mSAICtx.mCurrentItemHealth; + PRINT("BOMB * %f/%f\n", item->mSAICtx.mCurrentItemHealth, item->mSAICtx.mMaxItemHealth); if (item->mObjType != OBJTYPE_Bomb) { ERROR("this is not bomb %s\n", "setInit"); @@ -444,12 +444,12 @@ void BombAI::SetInit::act(AICreature* item) */ void BombAI::SetExec::act(AICreature* item) { - item->mCurrentItemHealth -= gsys->getFrameTime(); - PRINT("BOMB TIMER = %.1f\n", item->mCurrentItemHealth); - if (item->mCurrentItemHealth < 0.0f) { + item->mSAICtx.mCurrentItemHealth -= gsys->getFrameTime(); + PRINT("BOMB TIMER = %.1f\n", item->mSAICtx.mCurrentItemHealth); + if (item->mSAICtx.mCurrentItemHealth < 0.0f) { PRINT("send bomb event ... %x\n", item); MsgUser msg(1); - item->mCurrAnimId = 0; + item->mSAICtx.mCurrAnimId = 0; C_SAI(item)->procMsg(item, &msg); } @@ -477,7 +477,7 @@ void BombAI::BombInit::act(AICreature* item) playerState->mResultFlags.setOn(zen::RESFLAG_YellowWithBomb); rumbleMgr->start(RUMBLE_Unk8, 0, item->mSRT.t); EffectParm parm(item->mSRT.t); - if (item->mCurrAnimId == 1) { + if (item->mSAICtx.mCurrAnimId == 1) { utEffectMgr->cast(KandoEffect::BombLight, parm); PRINT("USE LIGHTWEIGHT BOMB EFFECT\n"); } else { @@ -489,7 +489,7 @@ void BombAI::BombInit::act(AICreature* item) playerState->mDemoFlags.setTimer(1.5f, DEMOFLAG_FirstBombExplode, nullptr); } item->playEventSound(item, SE_BOMB); - item->mCurrentItemHealth = 0.0f; + item->mSAICtx.mCurrentItemHealth = 0.0f; Iterator naviIt(naviMgr); CI_LOOP(naviIt) @@ -620,7 +620,7 @@ void BombAI::BombInit::act(AICreature* item) */ void BombAI::BombExec::act(AICreature* item) { - item->mStateMachine->transit(item, BOMB_Die); + item->mSAICtx.mStateMachine->transit(item, BOMB_Die); } /** @@ -628,7 +628,7 @@ void BombAI::BombExec::act(AICreature* item) */ void BombAI::MizuInit::act(AICreature* item) { - item->mCurrentItemHealth = 1.0f; + item->mSAICtx.mCurrentItemHealth = 1.0f; } /** @@ -636,11 +636,11 @@ void BombAI::MizuInit::act(AICreature* item) */ void BombAI::MizuExec::act(AICreature* item) { - item->mCurrentItemHealth -= gsys->getFrameTime(); - PRINT("bomb in water ! %f\n", item->mCurrentItemHealth); - f32 health = item->mCurrentItemHealth; + item->mSAICtx.mCurrentItemHealth -= gsys->getFrameTime(); + PRINT("bomb in water ! %f\n", item->mSAICtx.mCurrentItemHealth); + f32 health = item->mSAICtx.mCurrentItemHealth; if (health <= 0.0f) { - item->mStateMachine->transit(item, BOMB_Die); + item->mSAICtx.mStateMachine->transit(item, BOMB_Die); } item->mSRT.s.set(health, health, health); } @@ -650,7 +650,7 @@ void BombAI::MizuExec::act(AICreature* item) */ void BombAI::DieInit::act(AICreature* item) { - item->mCurrentItemHealth = 5.0f; + item->mSAICtx.mCurrentItemHealth = 5.0f; item->mSRT.s.set(0.0f, 0.0f, 0.0f); } @@ -661,8 +661,8 @@ void BombAI::DieExec::act(AICreature* item) { f32 time = gsys->getFrameTime(); item->setMotionSpeed(0.0f); - item->mCurrentItemHealth -= time; - if (item->mCurrentItemHealth <= 0.0f) { + item->mSAICtx.mCurrentItemHealth -= time; + if (item->mSAICtx.mCurrentItemHealth <= 0.0f) { item->kill(false); } } @@ -703,7 +703,7 @@ GoalAI::GoalAI() */ bool GoalAI::NotFinished::satisfy(AICreature* item) { - if (item->mCurrAnimId > 0 || item->mCounter > 0) { + if (item->mSAICtx.mCurrAnimId > 0 || item->mSAICtx.mCounter > 0) { return true; } return false; @@ -835,7 +835,7 @@ void GoalAI::EmitPiki::act(AICreature* item) { GoalItem* obj = (GoalItem*)item; - if (item->mCounter > 0) { + if (item->mSAICtx.mCounter > 0) { Vector3f pos = item->mSRT.t; pos.y += 110.0f; @@ -847,10 +847,10 @@ void GoalAI::EmitPiki::act(AICreature* item) effectMgr->create(EffectMgr::EFF_Onyon_FireworkMain, item->mSRT.t, nullptr, nullptr); effectMgr->create(EffectMgr::EFF_Onyon_FireworkKisek, item->mSRT.t, nullptr, nullptr); effectMgr->create(EffectMgr::EFF_Onyon_FireworkSmall, item->mSRT.t, nullptr, nullptr); - item->mCounter--; + item->mSAICtx.mCounter--; } - if (item->mCurrAnimId > 0) { + if (item->mSAICtx.mCurrAnimId > 0) { if (item->mObjType != OBJTYPE_Goal) { char buf[256]; sprintf(buf, "%d : not goal", item->mObjType); @@ -883,9 +883,9 @@ void GoalAI::EmitPiki::act(AICreature* item) PRINT("COUNTER UP!\n"); } - obj->mCurrAnimId--; + obj->mSAICtx.mCurrAnimId--; } - if (obj->mCurrAnimId == 0 && obj->mCounter == 0) { + if (obj->mSAICtx.mCurrAnimId == 0 && obj->mSAICtx.mCounter == 0) { obj->finishMotion(); } @@ -931,16 +931,16 @@ GemAI::GemAI() */ void GemAI::RiseInit::act(AICreature* item) { - item->mCurrentItemHealth = 0.0f; - item->mMaxItemHealth = 1.5f; + item->mSAICtx.mCurrentItemHealth = 0.0f; + item->mSAICtx.mMaxItemHealth = 1.5f; item->disableGravity(); Vector3f pos = item->mSRT.t; EffectParm parm(pos); utEffectMgr->cast(KandoEffect::Goal, parm); - item->playEventSound(item->mTargetCreature, SE_CONTAINER_PELLETIN); - item->mVelocity.y = 0.0f; - item->mCurrAnimId = 0; + item->playEventSound(item->mSAICtx.mTargetCreature, SE_CONTAINER_PELLETIN); + item->mVelocity.y = 0.0f; + item->mSAICtx.mCurrAnimId = 0; } /** @@ -948,34 +948,34 @@ void GemAI::RiseInit::act(AICreature* item) */ void GemAI::RiseExec::act(AICreature* item) { - if (item->mTargetCreature->mObjType != OBJTYPE_Goal) { + if (item->mSAICtx.mTargetCreature->mObjType != OBJTYPE_Goal) { ERROR("mail to good monkey!\n"); } - if (item->mMaxItemHealth > 0.0f) { + if (item->mSAICtx.mMaxItemHealth > 0.0f) { item->mVelocity.set(0.0f, 0.0f, 0.0f); - item->mMaxItemHealth -= gsys->getFrameTime(); + item->mSAICtx.mMaxItemHealth -= gsys->getFrameTime(); return; } - if (item->mCurrAnimId == 0) { - item->mCurrAnimId = 1; + if (item->mSAICtx.mCurrAnimId == 0) { + item->mSAICtx.mCurrAnimId = 1; } - Vector3f diff = item->mTargetCreature->mSRT.t - item->mSRT.t; + Vector3f diff = item->mSAICtx.mTargetCreature->mSRT.t - item->mSRT.t; diff.y = 0.0f; diff.normalise(); diff = diff * 60.0f; item->mVelocity.x = diff.x; item->mVelocity.z = diff.z; - item->mCurrentItemHealth += gsys->getFrameTime() * item->mVelocity.y; + item->mSAICtx.mCurrentItemHealth += gsys->getFrameTime() * item->mVelocity.y; item->mVelocity.y += gsys->getFrameTime() * 720.0f; - f32 div = item->mCurrentItemHealth / 74.0f; + f32 div = item->mSAICtx.mCurrentItemHealth / 74.0f; f32 b = 1.0f - div * 1.0f; item->mSRT.s.set(b, b, b); if (div >= 1.0f) { - item->mStateMachine->transit(item, GEM_Die); + item->mSAICtx.mStateMachine->transit(item, GEM_Die); GameStat::getPellets.inc(); } } @@ -986,7 +986,7 @@ void GemAI::RiseExec::act(AICreature* item) void GemAI::Die::act(AICreature* item) { GemItem* obj = (GemItem*)item; - GoalItem* goal = (GoalItem*)item->mTargetCreature; + GoalItem* goal = (GoalItem*)item->mSAICtx.mTargetCreature; int seeds; if (goal->mOnionColour == obj->mColor) { seeds = obj->mMatchingSeeds; @@ -995,9 +995,9 @@ void GemAI::Die::act(AICreature* item) } MsgUser msg(0); PRINT("gem item : ### add %d pikis\n", seeds); - goal->mCurrAnimId += seeds; + goal->mSAICtx.mCurrAnimId += seeds; - if (goal->mStateMachine) { + if (goal->mSAICtx.mStateMachine) { C_SAI(goal)->procMsg(goal, &msg); } obj->mIsAlive = false; @@ -1033,7 +1033,7 @@ WaterAI::WaterAI() */ bool WaterAI::CollideChar::satisfy(AICreature* item) { - if (item->mCollidingCreature->mObjType == OBJTYPE_Navi) { + if (item->mSAICtx.mCollidingCreature->mObjType == OBJTYPE_Navi) { seSystem->playPlayerSe(SE_PLAYER_TOUCHHONEY); return true; } diff --git a/src/plugPikiKando/itemGem.cpp b/src/plugPikiKando/itemGem.cpp index 0bdc5ad8..45ddae61 100644 --- a/src/plugPikiKando/itemGem.cpp +++ b/src/plugPikiKando/itemGem.cpp @@ -73,11 +73,11 @@ GemItem::GemItem(CreatureProp* props, int gemType, Shape** shapes, Shape**, Shap : ItemCreature(OBJTYPE_GemItem, props, nullptr) , mGemCollInfo(0) { - mGemType = gemType; - mColor = 0; - mItemShapeObject = itemMgr->getPelletShapeObject(mColor, gemType); - mStateMachine = ai; - mSizeScale = sizeScale; + mGemType = gemType; + mColor = 0; + mItemShapeObject = itemMgr->getPelletShapeObject(mColor, gemType); + mSAICtx.mStateMachine = ai; + mSizeScale = sizeScale; const GemTable& tableEntry = table[mGemType]; diff --git a/src/plugPikiKando/itemMgr.cpp b/src/plugPikiKando/itemMgr.cpp index f68a850d..311a7fe1 100644 --- a/src/plugPikiKando/itemMgr.cpp +++ b/src/plugPikiKando/itemMgr.cpp @@ -574,9 +574,9 @@ ItemCreature::ItemCreature(int objType, CreatureProp* props, Shape* shape) resetCreatureFlag(CF_DisableAutoFaceDir); setCreatureFlag(CF_Unk1); mSearchBuffer.init(mItemSearchData, 8); - mObjType = (EObjType)objType; - mItemShapeObject = nullptr; - mStateMachine = nullptr; + mObjType = (EObjType)objType; + mItemShapeObject = nullptr; + mSAICtx.mStateMachine = nullptr; } /** @@ -700,8 +700,8 @@ void ItemCreature::update() */ void ItemCreature::doAI() { - if (mStateMachine && !isCreatureFlag(CF_IsAiDisabled)) { - mStateMachine->exec(this); + if (mSAICtx.mStateMachine && !isCreatureFlag(CF_IsAiDisabled)) { + mSAICtx.mStateMachine->exec(this); } } @@ -872,12 +872,12 @@ bool InteractBomb::actItem(ItemCreature* item) immut if (item->mObjType == OBJTYPE_Bomb) { BombItem* bomb = static_cast(item); - int state = item->mStateMachine->getCurrID(item); + int state = item->mSAICtx.mStateMachine->getCurrID(item); PRINT("bomb got bomb interaction!\n"); if (state != BombAI::BOMB_Bomb && state != BombAI::BOMB_Mizu && state != BombAI::BOMB_Die) { MsgUser msg(1); PRINT("bomb renbaku!\n"); - item->mCurrAnimId = 1; + item->mSAICtx.mCurrAnimId = 1; C_SAI(item)->procMsg(item, &msg); } } @@ -962,7 +962,7 @@ BuildingItem::BuildingItem(int objType, CreatureProp* props, ItemShapeObject* it , mBuildCollision(0) { mItemShapeObject = itemShape; - mStateMachine = ai; + mSAICtx.mStateMachine = ai; mLifeGauge.mRenderStyle = LifeGauge::Wheel; } @@ -987,10 +987,10 @@ f32 BuildingItem::getBoundingSphereRadius() void BuildingItem::startAI(int) { mItemShapeObject->mShape->makeInstance(mAnimatedMaterials, 0); - mCounter = 0; - mCurrAnimId = 0; - _3C4 = true; - mSeContext = &mBuildSFX; + mSAICtx.mCounter = 0; + mSAICtx.mCurrAnimId = 0; + _3C4 = true; + mSeContext = &mBuildSFX; mSeContext->setContext(this, JACEVENT_Build); PRINT("*** \n"); enableFaceDirAdjust(); @@ -1135,7 +1135,7 @@ void BuildingItem::doSave(RandomAccessStream& output) output.writeFloat(mMaxHealth); output.writeInt(mCurrStage); output.writeInt(mNumStages); - output.writeInt(mCurrAnimId); + output.writeInt(mSAICtx.mCurrAnimId); PRINT_KANDO("\t life=%.1f maxLife=%.1f curr/num=%d/%d\n", mHealth, mMaxHealth, mCurrStage, mNumStages); } @@ -1144,11 +1144,11 @@ void BuildingItem::doSave(RandomAccessStream& output) */ void BuildingItem::doLoad(RandomAccessStream& input) { - mHealth = input.readFloat(); - mMaxHealth = input.readFloat(); - mCurrStage = input.readInt(); - mNumStages = input.readInt(); - mCurrAnimId = input.readInt(); + mHealth = input.readFloat(); + mMaxHealth = input.readFloat(); + mCurrStage = input.readInt(); + mNumStages = input.readInt(); + mSAICtx.mCurrAnimId = input.readInt(); PRINT_KANDO("currStage %d numStages %d\n", mCurrStage, mNumStages); diff --git a/src/plugPikiKando/mizuItem.cpp b/src/plugPikiKando/mizuItem.cpp index 2e0ce48a..649008ca 100644 --- a/src/plugPikiKando/mizuItem.cpp +++ b/src/plugPikiKando/mizuItem.cpp @@ -22,8 +22,8 @@ DEFINE_PRINT("matoItem") MizuItem::MizuItem(int objType, CreatureProp* props, ItemShapeObject* shape, SimpleAI* ai) : ItemCreature(objType, props, nullptr) { - mItemShapeObject = shape; - mStateMachine = ai; + mItemShapeObject = shape; + mSAICtx.mStateMachine = ai; } /** @@ -34,8 +34,8 @@ void MizuItem::update() ItemCreature::update(); if (mGroundTriangle && mObjType == OBJTYPE_FallWater) { MsgGround msg; - if (static_cast(mStateMachine)) { - static_cast(mStateMachine)->procMsg(this, &msg); + if (mSAICtx.mStateMachine) { + C_SAI(this)->procMsg(this, &msg); } } } diff --git a/src/plugPikiKando/piki.cpp b/src/plugPikiKando/piki.cpp index dfd11371..2c5a1425 100644 --- a/src/plugPikiKando/piki.cpp +++ b/src/plugPikiKando/piki.cpp @@ -2640,10 +2640,10 @@ void Piki::realAI() held->dump(); AICreature* aiC = static_cast(held); PRINT("---- aiContext ---\n"); - PRINT(" creature=%x target=%x\n", aiC->mCollidingCreature, aiC->mTargetCreature); - PRINT(" int=%d int2=%d real=%f real1=%f real2=%f\n", aiC->mCurrAnimId, aiC->mCounter, aiC->mCurrentItemHealth, aiC->_2DC, - aiC->mMaxHealth); - PRINT(" currState=%x\n", aiC->mCurrentState); + PRINT(" creature=%x target=%x\n", aiC->mSAICtx.mCollidingCreature, aiC->mSAICtx.mTargetCreature); + PRINT(" int=%d int2=%d real=%f real1=%f real2=%f\n", aiC->mSAICtx.mCurrAnimId, aiC->mSAICtx.mCounter, + aiC->mSAICtx.mCurrentItemHealth, aiC->mSAICtx._20, aiC->mMaxHealth); + PRINT(" currState=%x\n", aiC->mSAICtx.mCurrentState); PRINT("============================================\n"); dump(); PRINT("**** ==========\n"); diff --git a/src/plugPikiKando/pikiState.cpp b/src/plugPikiKando/pikiState.cpp index 8fc6f838..3c25d36b 100644 --- a/src/plugPikiKando/pikiState.cpp +++ b/src/plugPikiKando/pikiState.cpp @@ -467,8 +467,8 @@ void PikiAbsorbState::exec(Piki* piki) { if (mNectar->isAlive()) { MsgUser msg(0); - MizuItem* nectar = static_cast(mNectar); - nectar->mCollidingCreature = piki; + MizuItem* nectar = static_cast(mNectar); + nectar->mSAICtx.mCollidingCreature = piki; C_SAI(nectar)->procMsg(nectar, &msg); } @@ -1382,8 +1382,8 @@ void PikiFallMeckState::procBounceMsg(Piki* piki, MsgBounce*) AICreature* ai = (AICreature*)held; if (ai->getCurrState()->getID() != 1) { MsgUser msg(1); - BombItem* bomb = (BombItem*)held; - bomb->mCurrAnimId = 1; + BombItem* bomb = (BombItem*)held; + bomb->mSAICtx.mCurrAnimId = 1; C_SAI(bomb)->procMsg(bomb, &msg); } } diff --git a/src/plugPikiKando/pikiheadItem.cpp b/src/plugPikiKando/pikiheadItem.cpp index 650b31ad..d5b9443d 100644 --- a/src/plugPikiKando/pikiheadItem.cpp +++ b/src/plugPikiKando/pikiheadItem.cpp @@ -108,13 +108,13 @@ bool PikiHeadItem::isAlive() PikiHeadItem::PikiHeadItem(CreatureProp* props, ItemShapeObject* shape, SimpleAI* ai) : ItemCreature(15, props, nullptr) { - mItemShapeObject = shape; - mStateMachine = ai; - mSeedColor = 0; - mFlowerStage = 0; - mParentOnion = nullptr; - mFreeLightEfx = new FreeLightEffect; - mRippleEfx = new RippleEffect; + mItemShapeObject = shape; + mSAICtx.mStateMachine = ai; + mSeedColor = 0; + mFlowerStage = 0; + mParentOnion = nullptr; + mFreeLightEfx = new FreeLightEffect; + mRippleEfx = new RippleEffect; } /** diff --git a/src/plugPikiKando/plantMgr.cpp b/src/plugPikiKando/plantMgr.cpp index f9ffc616..c8ce38aa 100644 --- a/src/plugPikiKando/plantMgr.cpp +++ b/src/plugPikiKando/plantMgr.cpp @@ -57,7 +57,7 @@ void Plant::reset(int plantType) mPlantAnimator.init(&shape->mAnimContext, shape->mAnimMgr, plantMgr->mMotionTable); mMotionSpeed = 0.0f; mCollInfo->initInfo(shape->mShape, nullptr, nullptr); - mStateMachine = plantMgr->mAI; + mSAICtx.mStateMachine = plantMgr->mAI; } /** @@ -168,7 +168,7 @@ PlantAI::PlantAI() */ bool PlantAI::OpponentMove::satisfy(AICreature* plant) { - Creature* collider = plant->mCollidingCreature; + Creature* collider = plant->mSAICtx.mCollidingCreature; f32 dist = collider->mVelocity.length(); if (dist > 40.0f) { return true; @@ -200,7 +200,7 @@ void PlantAI::TouchInit::act(AICreature* plant) { STACK_PAD_VAR(1); if (static_cast(plant)->mPlantType != PLANT_Mizukusa) { - if (plant->mCollidingCreature->mObjType == OBJTYPE_Navi) { + if (plant->mSAICtx.mCollidingCreature->mObjType == OBJTYPE_Navi) { SeSystem::playPlayerSe(SE_ORIMA_TOUCHPLANTS); } diff --git a/src/plugPikiKando/simpleAI.cpp b/src/plugPikiKando/simpleAI.cpp index 7e14cae7..4af0cdc8 100644 --- a/src/plugPikiKando/simpleAI.cpp +++ b/src/plugPikiKando/simpleAI.cpp @@ -20,16 +20,8 @@ DEFINE_PRINT("simpleAI"); AICreature::AICreature(CreatureProp* props) : Creature(props) { - // this is all apparently the ctor of a struct - mCollidingCreature = 0; - _2C4.set(0.0f, 0.0f, 0.0f); - mCurrAnimId = mCounter = 0; - mCurrentState = nullptr; - mCurrentItemHealth = 0.0f; - - // then this is THIS ctor - mCurrentState = nullptr; // hm. - mMaxEventCount = 16; + mSAICtx.mCurrentState = nullptr; // hm. + mSAICtx.mMaxEventCount = ARRAY_SIZE(mSAICtx.mEventFlags); clearEventFlags(); } @@ -40,9 +32,9 @@ void AICreature::collisionCallback(immut CollEvent& event) { Creature* collider = event.mCollider; MsgCollide msg(event); - mCollidingCreature = collider; - if (mStateMachine) { - static_cast(mStateMachine)->procMsg(this, &msg); + mSAICtx.mCollidingCreature = collider; + if (mSAICtx.mStateMachine) { + C_SAI(this)->procMsg(this, &msg); } } @@ -52,8 +44,8 @@ void AICreature::collisionCallback(immut CollEvent& event) void AICreature::bounceCallback() { MsgBounce msg(Vector3f(0.0f, 1.0f, 0.0f)); - if (mStateMachine) { - static_cast(mStateMachine)->procMsg(this, &msg); + if (mSAICtx.mStateMachine) { + C_SAI(this)->procMsg(this, &msg); } } @@ -66,8 +58,8 @@ void AICreature::animationKeyUpdated(immut PaniAnimKeyEvent& event) MsgAnim msg(&event); - if (mStateMachine) { - static_cast(mStateMachine)->procMsg(this, &msg); + if (mSAICtx.mStateMachine) { + C_SAI(this)->procMsg(this, &msg); } if (event.mEventType == KEY_PlaySound) { @@ -84,11 +76,11 @@ void AICreature::animationKeyUpdated(immut PaniAnimKeyEvent& event) */ void AICreature::clearEventFlags() { - for (int i = 0; i < mMaxEventCount; i++) { - mEventFlags[i] = 0; + for (int i = 0; i < mSAICtx.mMaxEventCount; i++) { + mSAICtx.mEventFlags[i] = false; } - mCurrentEventCount = 0; + mSAICtx.mCurrentEventCount = 0; } /** @@ -96,16 +88,16 @@ void AICreature::clearEventFlags() */ void AICreature::setEventFlag(int flagID, bool value) { - if (mCurrentEventCount >= mMaxEventCount) { + if (mSAICtx.mCurrentEventCount >= mSAICtx.mMaxEventCount) { PRINT("############ too many events!\n"); ERROR("too many events"); return; } - if (flagID >= mMaxEventCount) { + if (flagID >= mSAICtx.mMaxEventCount) { ERROR("EVENT %d flag = %s\n", flagID, value ? "true" : "false"); } - mEventFlags[flagID] = value; + mSAICtx.mEventFlags[flagID] = value; } /** @@ -118,7 +110,7 @@ bool AICreature::checkEventFlag(int flag) PRINT("##### idx == -1 : checkEventFlag!\n"); ERROR("checkEventFlg -1"); } - return mEventFlags[flag]; + return mSAICtx.mEventFlags[flag]; } /** From e4eb1430a021941eb92c271b6d6df2c26f0ab9a6 Mon Sep 17 00:00:00 2001 From: Minty-Meeo <45425365+Minty-Meeo@users.noreply.github.com> Date: Fri, 29 May 2026 15:35:11 -0500 Subject: [PATCH 5/9] Match `PlayerState::update` for GPIJ01 And link playerState.cpp for more versions. --- configure.py | 2 +- src/plugPikiKando/playerState.cpp | 17 +++++------------ 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/configure.py b/configure.py index 10d31c54..be886bea 100644 --- a/configure.py +++ b/configure.py @@ -498,7 +498,7 @@ def MatchingFor(*versions): Object(Equivalent, "plugPikiKando/simpleAI.cpp"), Object(Matching, "plugPikiKando/formationMgr.cpp"), Object(Matching, "plugPikiKando/globalShapes.cpp"), - Object(not MatchingFor("GPIJ01_01", "GPIJ01_02", "DPIJ01_PIKIDEMO"), "plugPikiKando/playerState.cpp"), + Object(Matching, "plugPikiKando/playerState.cpp"), Object(Matching, "plugPikiKando/gameDemo.cpp"), Object(Matching, "plugPikiKando/demoInvoker.cpp"), Object(Matching, "plugPikiKando/demoEvent.cpp"), diff --git a/src/plugPikiKando/playerState.cpp b/src/plugPikiKando/playerState.cpp index ac64b943..a231b9af 100644 --- a/src/plugPikiKando/playerState.cpp +++ b/src/plugPikiKando/playerState.cpp @@ -650,9 +650,6 @@ bool PlayerState::hasUfoParts(u32 idx) */ void PlayerState::update() { - - STACK_PAD_VAR(2); - bool isCM = isChallengeMode(); if (!isCM) { mDemoFlags.update(); @@ -664,15 +661,11 @@ void PlayerState::update() GameStat::update(); mLastUpdatedTime = time; - // When I'm in a WTF competition and my opponent is this - int* b = (int*)(&GameStat::allPikis) + Blue; - int* r = (int*)(&GameStat::allPikis) + Red; - int* y = (int*)(&GameStat::allPikis) + Yellow; - - mPerHourGraph.set(mLastUpdatedTime, Blue, *b); - mPerHourGraph.set(mLastUpdatedTime, Red, *r); - mPerHourGraph.set(mLastUpdatedTime, Yellow, *y); - PRINT("record (%d %d %d) = %d\n", GameStat::allPikis, GameStat::allPikis[0], GameStat::allPikis[1], GameStat::allPikis[2]); + mPerHourGraph.set(mLastUpdatedTime, Blue, GameStat::allPikis[Blue]); + mPerHourGraph.set(mLastUpdatedTime, Red, GameStat::allPikis[Red]); + mPerHourGraph.set(mLastUpdatedTime, Yellow, GameStat::allPikis[Yellow]); + PRINT("record (%d %d %d) = %d\n", GameStat::allPikis[Blue], GameStat::allPikis[Red], GameStat::allPikis[Yellow], + (int)GameStat::allPikis); } } } From 6800d8ec152b7c1393d87f903ede0c172000252c Mon Sep 17 00:00:00 2001 From: Minty-Meeo <45425365+Minty-Meeo@users.noreply.github.com> Date: Fri, 29 May 2026 17:34:56 -0500 Subject: [PATCH 6/9] Closer `ActBridge::newExeWork` --- src/plugPikiKando/aiBridge.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/plugPikiKando/aiBridge.cpp b/src/plugPikiKando/aiBridge.cpp index 908ee894..60229817 100644 --- a/src/plugPikiKando/aiBridge.cpp +++ b/src/plugPikiKando/aiBridge.cpp @@ -543,16 +543,15 @@ int ActBridge::newExeWork() return ACTOUT_Continue; } - STACK_PAD_TERNARY(this, 3); - if (absF(xDist) > 0.3f * mBridge->getStageWidth()) { + STACK_PAD_STRUCT(2); // Vector3f unused(xVec); // This would be more accurate, but it makes the stack worse. if (xDist < 0.0f) { xVec.multiply(-1.0f); } zVec = zVec + xVec; zVec.normalise(); } - mBridge->getStageDepth(); + f32 unused = mBridge->getStageDepth(); // It looks like this unused result was stored in a variable in the DLL. mPiki->setSpeed(0.5f, zVec); return ACTOUT_Continue; /* From c1dc4c8a12475e4f52ad26eb2938505566456ae8 Mon Sep 17 00:00:00 2001 From: Minty-Meeo <45425365+Minty-Meeo@users.noreply.github.com> Date: Sun, 31 May 2026 19:43:26 -0500 Subject: [PATCH 7/9] Match "system.cpp" for JPN Demo --- configure.py | 2 +- include/system.h | 13 ++++++++++-- src/plugPikiColin/gameflow.cpp | 2 +- src/sysDolphin/system.cpp | 36 +++++++++++++++++++++++++++------- 4 files changed, 42 insertions(+), 11 deletions(-) diff --git a/configure.py b/configure.py index be886bea..007b0d2f 100644 --- a/configure.py +++ b/configure.py @@ -441,7 +441,7 @@ def MatchingFor(*versions): "progress_category": "game", "objects": [ Object(Equivalent, "sysDolphin/texture.cpp"), - Object(not MatchingFor("DPIJ01_PIKIDEMO"), "sysDolphin/system.cpp"), + Object(Matching, "sysDolphin/system.cpp"), Object(Matching, "sysDolphin/sysNew.cpp"), Object(Matching, "sysDolphin/controllerMgr.cpp"), Object(not MatchingFor("GPIJ01_01", "GPIJ01_02", "G98P01_PIKIDEMO", "DPIJ01_PIKIDEMO"), "sysDolphin/dgxGraphics.cpp"), diff --git a/include/system.h b/include/system.h index 74f95d5d..04ec2f7b 100644 --- a/include/system.h +++ b/include/system.h @@ -345,6 +345,15 @@ enum { WrongDisc = 5 // Non-Pikmin disc inserted } END_ENUM_TYPE; +/** + * @brief FABRICATED - No other class we currently know of has a virtual table like this. + */ +struct System_Class_250 { + virtual void method(Graphics& gfx) = 0; // _00 + + // _00 = VTBL +}; + /** * @brief FABRICATED - Singly-linked list of symbolic information (See `ParseMapFile`) */ @@ -393,7 +402,7 @@ struct System : public StdSystem { RandomAccessStream* createFile(immut char*, BOOL); // unused/inlined: - void findAddress(u32); + immut char* findAddress(u32); bool hasDebugInfo(); static void halt(immut char* file, int line, immut char* message); @@ -411,7 +420,7 @@ struct System : public StdSystem { u32 mHeapStart; // _244 u32 mHeapEnd; // _248 Graphics* mDGXGfx; // _24C, cast to DGXGraphics in DOL - u32 _250; // _250, unknown/unused - set to 0 by GameFlow::softReset. + System_Class_250* _250; // _250, a vestigial pointer related to `System::halt` Delegate1* mDvdErrorCallback; // _254 int mDvdErrorCode; // _258 u32 mDvdBufferSize; // _25C diff --git a/src/plugPikiColin/gameflow.cpp b/src/plugPikiColin/gameflow.cpp index 9a470766..65f445f2 100644 --- a/src/plugPikiColin/gameflow.cpp +++ b/src/plugPikiColin/gameflow.cpp @@ -701,7 +701,7 @@ void GameFlow::softReset() PRINT("doing start load!\n"); gsys->startLoading(nullptr, true, 60); } - gsys->_250 = 0; + gsys->_250 = nullptr; mGameInterface = nullptr; gsys->getHeap(SYSHEAP_Message)->inactivate(); mGameSection->init(); diff --git a/src/sysDolphin/system.cpp b/src/sysDolphin/system.cpp index d2323efd..eefcf126 100644 --- a/src/sysDolphin/system.cpp +++ b/src/sysDolphin/system.cpp @@ -538,9 +538,17 @@ static void ParseMapFile() * @todo: Documentation * @note UNUSED Size: 000040 */ -void System::findAddress(u32) +immut char* System::findAddress(u32 address) { - // UNUSED FUNCTION + SymbolInfo* curr = mBuildMapFuncList; + while (curr != nullptr) { + u32 minAddr = curr->mVirtualAddress; + u32 maxAddr = curr->mNext->mVirtualAddress; + if (address >= minAddr && address < maxAddr) + return curr->mDemangledName; + curr = curr->mNext; + } + return nullptr; } /** @@ -988,23 +996,37 @@ bool System::hasDebugInfo() /** * @todo: Documentation - * @note UNUSED Size: 0000b8 + * @note UNUSED Size: 000030 (VERSION_GPIJ01 || VERSION_GPIE01 || VERSION_GPIP01) + * @note UNUSED Size: 0000b8 (VERSION_PIKIDEMO) */ void System::halt(immut char* file, int line, immut char* message) { -#if 0 // DLL's version +#ifdef WIN32 char buffer[2048]; sprintf(buffer, "%s\n\nClick OK to quit now !", message); MessageBox(NULL, buffer, "Error!", MB_ICONEXCLAMATION); exit(0); // Failure! #else -#if defined(VERSION_GPIJ01) - OSErrorLine(1075, message); - return; +#if defined(VERSION_PIKIDEMO) || defined(DEVELOP) + if (gsys->_250) { + gsys->_250->method(*gsys->mDGXGfx); + const int startTick = OSGetTick(); + while (OSGetTick() - startTick < OS_TIMER_CLOCK * 5) { } + } + OSDumpContext(&gsys->mCurrentThread->context); + static_cast(gsys->mDGXGfx)->showError(message, file, line); #endif + +#if defined(VERSION_GPIJ01) || defined(VERSION_GPIE01) || defined(VERSION_GPIP01) + OSErrorLine(1075, message); +#elif defined(VERSION_PIKIDEMO) + OSErrorLine(1077, message); +#else OSPanic(file, line, message); #endif + +#endif } /** From ef3a88344c5f121212d6af4ed0db1de3a3454d73 Mon Sep 17 00:00:00 2001 From: Minty-Meeo <45425365+Minty-Meeo@users.noreply.github.com> Date: Mon, 1 Jun 2026 15:44:25 -0500 Subject: [PATCH 8/9] Closer "Texture.cpp" for DPIJ01 --- src/sysDolphin/texture.cpp | 71 +++++++++++++++++++++++++++++++++----- 1 file changed, 62 insertions(+), 9 deletions(-) diff --git a/src/sysDolphin/texture.cpp b/src/sysDolphin/texture.cpp index 5911648c..a420a4cf 100644 --- a/src/sysDolphin/texture.cpp +++ b/src/sysDolphin/texture.cpp @@ -52,31 +52,47 @@ void Texture::offsetGLtoGX(int, int) /** * @todo: Documentation + * @note NONMATCHING */ u8 Texture::getAlpha(int x, int y) { + // These two switch cases seem like they should contain identical math, with the only difference being the size of a pixel (u8 vs u16). switch (mTexFormat) { case TEX_FMT_IA4: { + // int a = (x / mTileSizeX * mTileSizeX) * mTileSizeY; + // int b = (x % mTileSizeX); + // int c = (y / mTileSizeY * mTileSizeY) * (mWidth / mTileSizeX * mTileSizeX); + // int d = (y % mTileSizeY) * mTileSizeX; + // u8 pixel = ((u8*)mPixelData)[a + b + d + c]; + int tileArea = mTileSizeX * mTileSizeY; int x2 = x / mTileSizeX; int y2 = y / mTileSizeY; - return ((u8*)mPixelData)[x2 * tileArea + (x % mTileSizeX) + mTileSizeX * (y % mTileSizeY) + y2 * ((mWidth / mTileSizeX) * tileArea)] - & 0xF0; + u8 pixel + = ((u8*)mPixelData)[x2 * tileArea + (x % mTileSizeX) + mTileSizeX * (y % mTileSizeY) + y2 * ((mWidth / mTileSizeX) * tileArea)]; + + return pixel & 0xF0; } - default: + default: // TEX_FMT_RGB5A3 assumed { + // int a = (x / mTileSizeX * mTileSizeX) * mTileSizeY; + // int b = (x % mTileSizeX); + // int c = (y / mTileSizeY * mTileSizeY) * (mWidth / mTileSizeX * mTileSizeX); + // int d = (y % mTileSizeY) * mTileSizeX; + // u16 pixel = ((u16*)mPixelData)[a + b + d + c]; + int tileArea = mTileSizeX * mTileSizeY; int blockX = (x / mTileSizeX) * (mWidth / mTileSizeX) * tileArea; int blockY = (y / mTileSizeY) * tileArea; x %= mTileSizeX; y %= mTileSizeY; - u16 alpha = ((u16*)mPixelData)[blockX + x + mTileSizeX * y + blockY]; + u16 pixel = ((u16*)mPixelData)[blockX + x + mTileSizeX * y + blockY]; - if (alpha & 0x8000) { + if (pixel & 0x8000) { return 255; } - return (alpha >> 7) & 0xE0; + return (pixel >> 7) & 0xE0; } } @@ -147,12 +163,49 @@ u8 Texture::getAlpha(int x, int y) /** * @todo: Documentation * @note UNUSED Size: 0000D4 + * @note NONMATCHING */ -u8 Texture::getRed(int, int) +u8 Texture::getRed(int x, int y) { - // TODO: this is present in JPN Demo + // These two switch cases seem like they should contain identical math, with the only difference being the size of a pixel (u8 vs u16). + switch (mTexFormat) { + case TEX_FMT_IA4: + { + // int a = (x / mTileSizeX * mTileSizeX) * mTileSizeY; + // int b = (x % mTileSizeX); + // int c = (y / mTileSizeY * mTileSizeY) * (mWidth / mTileSizeX * mTileSizeX); + // int d = (y % mTileSizeY) * mTileSizeX; + // u8 pixel = ((u8*)mPixelData)[a + b + d + c]; - // UNUSED FUNCTION + int tileArea = mTileSizeX * mTileSizeY; + int x2 = x / mTileSizeX; + int y2 = y / mTileSizeY; + u8 pixel + = ((u8*)mPixelData)[x2 * tileArea + (x % mTileSizeX) + mTileSizeX * (y % mTileSizeY) + y2 * ((mWidth / mTileSizeX) * tileArea)]; + + return pixel & 0x0F; + } + default: // TEX_FMT_RGB5A3 assumed + { + // int a = (x / mTileSizeX * mTileSizeX) * mTileSizeY; + // int b = (x % mTileSizeX); + // int c = (y / mTileSizeY * mTileSizeY) * (mWidth / mTileSizeX * mTileSizeX); + // int d = (y % mTileSizeY) * mTileSizeX; + // u16 pixel = ((u16*)mPixelData)[a + b + d + c]; + + int tileArea = mTileSizeX * mTileSizeY; + int blockX = (x / mTileSizeX) * (mWidth / mTileSizeX) * tileArea; + int blockY = (y / mTileSizeY) * tileArea; + x %= mTileSizeX; + y %= mTileSizeY; + u16 pixel = ((u16*)mPixelData)[blockX + x + mTileSizeX * y + blockY]; + + if (pixel & 0x8000) { + return (pixel & 0x7c00) >> 7; + } + return (pixel & 0x0f00) >> 4; + } + } } /** From 86b550f72a8cd51d4027467eb7a6b788f5f4e7d3 Mon Sep 17 00:00:00 2001 From: Minty-Meeo <45425365+Minty-Meeo@users.noreply.github.com> Date: Mon, 1 Jun 2026 17:09:08 -0500 Subject: [PATCH 9/9] Garbage `dgxGraphics.pp` work for JPN Demo FFS, I couldn't match a single function. --- src/sysDolphin/dgxGraphics.cpp | 111 ++++++++++++++++++++++++++------- 1 file changed, 87 insertions(+), 24 deletions(-) diff --git a/src/sysDolphin/dgxGraphics.cpp b/src/sysDolphin/dgxGraphics.cpp index 394427cc..ae7e1827 100644 --- a/src/sysDolphin/dgxGraphics.cpp +++ b/src/sysDolphin/dgxGraphics.cpp @@ -2125,12 +2125,30 @@ void DGXGraphics::showCrash(u16, OSContext*) /** * @todo: Documentation * @note UNUSED Size: 000184 - */ -void DGXGraphics::showError(immut char* msg1, immut char* fileName, int line) -{ - OSReport("ERROR: %s", msg1); - OSReport("ERROR: in %s at line %d", fileName, line); - // UNUSED FUNCTION + * @note In Dolphin Emulator, this effect looks best with "Store XFB Copies to Texture Only" off. + */ +void DGXGraphics::showError(immut char* msg, immut char* file, int line) +{ + RectArea window(32, mScreenWidth - 32, 100, mScreenHeight - 100); + directErase(window, false); + directPrint(window.mMinX + 8, window.mMinY + 8, "ERROR: %s", msg); + directPrint(window.mMinX + 8, window.mMinY + 8 + 16, "ERROR: in %s at line %d", file, line); + int y = 36; + int x = 0; + u32* sp = (u32*)OSGetStackPointer(); + for (int i = 0; *sp != nullptr && *sp != 0xffffffff && i++ < 16;) { + if (i > 2) { + const char* name = gsys->findAddress(sp[1]); + char buffer[PATH_MAX]; + if (name) + sprintf(buffer, "%08x", sp[1]); + else + sprintf(buffer, "%s", name); + directPrint(window.mMinX + 8, window.mMinY + y, "<< %s", buffer); + y += 14; + } + sp = (u32*)*sp; + } } static char sAsciiTable[] = { @@ -2169,19 +2187,58 @@ void DGXGraphics::directDrawChar(int, int, int) /** * @todo: Documentation * @note UNUSED Size: 0000F8 + * @note In Dolphin Emulator, this effect looks best with "Store XFB Copies to Texture Only" off. */ -void DGXGraphics::directDrawChar(RectArea&, RectArea&) +void DGXGraphics::directDrawChar(RectArea& screenArea, RectArea& textureArea) { - // UNUSED FUNCTION + Texture* tex = gsys->mConsFont->mTexture; + u16* screen = (u16*)(mDisplayBuffer + screenArea.mMinY * 0x500 + screenArea.mMinX * 2); + for (int i = 0; i < textureArea.height(); ++i) { + int width = textureArea.width(); + for (int j = 0; j < width; ++j) { + if (tex->getAlpha(textureArea.mMinX + j, textureArea.mMinY + i) != 0) { + screen[j] = (tex->getRed(textureArea.mMinX + j, textureArea.mMinY + i) != 0) ? 0xeb80 : 0x80; + } + } + screen += 0x280 - width; + } + FORCE_DONT_INLINE; } /** * @todo: Documentation * @note UNUSED Size: 0001D8 + * @note In Dolphin Emulator, this effect looks best with "Store XFB Copies to Texture Only" off. */ -void DGXGraphics::directPrint(int, int, immut char*, ...) +void DGXGraphics::directPrint(int x, int y, immut char* fmt, ...) { - // UNUSED FUNCTION + char buffer[PATH_MAX]; + va_list args; + va_start(args, fmt); + + int length = vsprintf(buffer, fmt, args); + Font* font = gsys->mConsFont; + +#define CHARFACTS(i) font->mChars[font->charToIndex(buffer[i])] // WHY WOULD YOU DO THIS? + + if (font) { + for (int i = 0; i < length; ++i) { + int index = font->charToIndex(buffer[i]); + if (index >= 0) { + directDrawChar( + RectArea(x - CHARFACTS(i).mLeftOffset, y, x - CHARFACTS(i).mLeftOffset + CHARFACTS(i).mWidth, y + CHARFACTS(i).mHeight), + CHARFACTS(i).mTextureCoords); + x += CHARFACTS(i).mCharSpacing; + if (x > 600) + break; + } + } + } + +#undef CHARFACTS + + DCFlushRange(mDisplayBuffer, sFrameSize); + va_end(args); } // idk about these names @@ -2192,28 +2249,34 @@ void DGXGraphics::directPrint(int, int, immut char*, ...) /** * @todo: Documentation * @note UNUSED Size: 000108 + * @note In Dolphin Emulator, this effect looks best with "Store XFB Copies to Texture Only" off. */ void DGXGraphics::directErase(RectArea& bounds, bool set) { // NON-MATCHING (JP) - u16* screen = (u16*)(mDisplayBuffer + u32(bounds.mMinX + bounds.mMinY * 640 << 1)); + u16* screen = (u16*)mDisplayBuffer + (bounds.mMinX + bounds.mMinY * 640); for (int i = 0; i < bounds.height(); i++) { - u16* screenPtr = screen; + int j = 0; if (set) { - for (int i = 0; i < bounds.width(); i++) { - screenPtr[i] = PACK_DISPLAY_BYTE(0, 0); + // for (; j < bounds.width(); j++) { + // screen[i] = PACK_DISPLAY_BYTE(0, 0); + // } + + int a = 0x10; + a <<= 8; + a |= 0x80; + for (; j < bounds.width(); j++) { + screen[j] = a; + } + } else { + for (; j < bounds.width(); j++) { + int val12 = UNPACK_DISPLAY_BYTE_1(screen[j]); + val12 >>= 2; + int val31 = UNPACK_DISPLAY_BYTE_2(screen[j]); + val31 >>= 2; + screen[j] = PACK_DISPLAY_BYTE(val12, val31); } - continue; - } - - for (int i = 0; i < bounds.width(); i++) { - int val12 = UNPACK_DISPLAY_BYTE_1(screenPtr[i]); - val12 >>= 2; - int val31 = UNPACK_DISPLAY_BYTE_2(screenPtr[i]); - val31 >>= 2; - screenPtr[i] = PACK_DISPLAY_BYTE(val12, val31); } - screen += 640; }