From 10d1a1f5ac7f091111422234b9c105c42caaa8d3 Mon Sep 17 00:00:00 2001 From: KakarotCake <61133727+KakarottoCake@users.noreply.github.com> Date: Sun, 27 Sep 2026 19:10:47 -0400 Subject: [PATCH 1/6] Correct NPC animation distance and refine collision and event code --- include/NPC/NpcBase.hpp | 32 +++++++++++++++++--------------- src/NPC/NpcCollision.cpp | 4 ++-- src/NPC/NpcEvent.cpp | 7 ++++--- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/include/NPC/NpcBase.hpp b/include/NPC/NpcBase.hpp index 01755ee40..c33044f8c 100644 --- a/include/NPC/NpcBase.hpp +++ b/include/NPC/NpcBase.hpp @@ -243,26 +243,28 @@ class TBaseNPC : public TSpineEnemy { } f32 getAnmOffDist_() { - bool bVar3 = false; - f32 fVar1 = gpCamera->mFar; - u32 uVar5 = unkD0->getCurrentAnmKind(); - f32 fVar2 = mPtrSaveNormal->mSLDanceAnmOffDist.get(); + bool useDanceDistance = false; + f32 distance = gpCamera->mFar; + int animationKind = unkD0->getCurrentAnmKind(); + f32 danceDistance = mPtrSaveNormal->mSLDanceAnmOffDist.get(); if (checkActionFlag(NPC_ACTION_HAPPY | NPC_ACTION_DANCE) - || mActorType == 0x400000D || uVar5 || uVar5 == 23) { - bVar3 = true; + || mActorType == 0x400000D + || animationKind == NPC_ANM_KIND_MAD + || animationKind == NPC_ANM_KIND_UNK17) { + useDanceDistance = true; } - if (!isNerveMaybeDontCalcAnim0() && !isNerveMaybeDontCalcAnim1()) { - fVar1 = mIndividualParams->mWaitAnmOffDist1.get(); - if (bVar3 && fVar1 < fVar2) - fVar1 = fVar2; - } else { - fVar1 = mIndividualParams->mWaitAnmOffDist0.get(); - if (bVar3 && fVar1 < fVar2) - fVar1 = fVar2; + if (isNerveMaybeDontCalcAnim0()) { + distance = mIndividualParams->mWaitAnmOffDist0.get(); + if (useDanceDistance) + distance = danceDistance > distance ? danceDistance : distance; + } else if (isNerveMaybeDontCalcAnim1()) { + distance = mIndividualParams->mWaitAnmOffDist1.get(); + if (useDanceDistance) + distance = danceDistance > distance ? danceDistance : distance; } - return fVar1; + return distance; } void setNpcAnm_(EnumNpcAnmKind, EnumNpcStopMotionBlendOnOff); void requestNpcAnm_(EnumNpcAnmKind, EnumNpcStopMotionBlendOnOff); diff --git a/src/NPC/NpcCollision.cpp b/src/NPC/NpcCollision.cpp index 0b362dae2..e5be2b87b 100644 --- a/src/NPC/NpcCollision.cpp +++ b/src/NPC/NpcCollision.cpp @@ -97,11 +97,11 @@ void TBaseNPC::execNpcObjCollision_() void TBaseNPC::setVariableDamageRadius_() { const TNpcInitInfo* initInfo = SMSGetNpcInitData(mActorType - 0x4000001); - f32 fVar6 = mScaling.x * initInfo->mDamageRadius; + f32 fVar6 = initInfo->mDamageRadius * mScaling.x; if (isBeTrampledNpc() && !SMS_IsMarioTouchGround4cm() && SMS_GetMarioPos().y > mPosition.y) { JGeometry::TVec3 diff; - diff.sub(mPosition, SMS_GetMarioPos()); + diff.sub(SMS_GetMarioPos(), mPosition); diff.y = 0.0f; if (diff.squared() < CLBSquared(fVar6 * 3.0f)) fVar6 = mIndividualParams->mSLDamageRadiusSmall.get(); diff --git a/src/NPC/NpcEvent.cpp b/src/NPC/NpcEvent.cpp index 6dbc23d84..325f16ce2 100644 --- a/src/NPC/NpcEvent.cpp +++ b/src/NPC/NpcEvent.cpp @@ -377,20 +377,21 @@ void TNpcEvent::reviveOneSunflower() TBaseNPC* npc = static_cast(JDrama::TNameRefGen::search(acStack_50)); --mDownSunflowerNum; + JGeometry::TVec3* position = &npc->unk1B8; static const char* sCameraNames[] = { "ひまわりカメラ0", "ひまわりカメラ1", "ひまわりカメラ2", "ひまわりカメラ3", "ひまわりカメラ4", }; - gpMarDirector->fireStartDemoCamera(sCameraNames[idx], &npc->unk1B8, -1, + gpMarDirector->fireStartDemoCamera(sCameraNames[idx], position, -1, 0.0f, true, &ReviveSunflowerCallBack, (uintptr_t)npc, nullptr, 0); if (mDownSunflowerNum == 0) { gpItemManager->makeShineAppearWithDemo( - "ひまわり用シャイン", "ひまわりシャインカメラ", npc->unk1B8.x, - npc->unk1B8.y + 500.0f, npc->unk1B8.z); + "ひまわり用シャイン", "ひまわりシャインカメラ", position->x, + position->y + 500.0f, position->z); TFlagManager::getInstance()->setBool(false, 0x50003); } } From 663df983f8c4387fca7990ff0ec9d252445db6ec Mon Sep 17 00:00:00 2001 From: KakarotCake <61133727+KakarottoCake@users.noreply.github.com> Date: Sun, 27 Sep 2026 19:15:41 -0400 Subject: [PATCH 2/6] Match NPC demo camera callback and improve recovery code --- src/NPC/NpcAnm.cpp | 3 +-- src/NPC/NpcEvent.cpp | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/NPC/NpcAnm.cpp b/src/NPC/NpcAnm.cpp index d00b84f76..767eec58d 100644 --- a/src/NPC/NpcAnm.cpp +++ b/src/NPC/NpcAnm.cpp @@ -409,8 +409,6 @@ void TBaseNPC::npcFallIn() bool TBaseNPC::npcRecoverFromSinking() { - bool result = false; - if (!checkLiveFlag(LIVE_FLAG_UNK8000000)) { if (mMActor->getFrameCtrl(ANM_TYPE_BCK)->checkPass(32.0f)) { onLiveFlag(LIVE_FLAG_UNK8000000); @@ -428,6 +426,7 @@ bool TBaseNPC::npcRecoverFromSinking() } } + bool result = false; if (mMActor->isCurAnmAlreadyEnd(ANM_TYPE_BCK)) { result = true; offLiveFlag(LIVE_FLAG_AIRBORNE); diff --git a/src/NPC/NpcEvent.cpp b/src/NPC/NpcEvent.cpp index 325f16ce2..02331ed36 100644 --- a/src/NPC/NpcEvent.cpp +++ b/src/NPC/NpcEvent.cpp @@ -281,7 +281,8 @@ static void evFireStartDemoCamera(TSpcTypedInterp* interp, { interp->verifyArgNum(1, &arg_num); const char* cameraName = interp->pop().getDataString(); - gpMarDirector->fireStartDemoCamera(cameraName, nullptr, -1, 0.0f, true, + TMarDirector* director = gpMarDirector; + director->fireStartDemoCamera(cameraName, nullptr, -1, 0.0f, true, nullptr, 0, nullptr, JDrama::TFlagT()); interp->push(); From 932fc5fd9deacf6836b2a137369777db57857b76 Mon Sep 17 00:00:00 2001 From: KakarotCake <61133727+KakarottoCake@users.noreply.github.com> Date: Sun, 27 Sep 2026 19:20:54 -0400 Subject: [PATCH 3/6] Correct NPC graph timer ranges and cache nerve actor type --- include/NPC/NpcBase.hpp | 15 ++++++++++++--- src/NPC/NpcNerve.cpp | 12 +++++++----- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/include/NPC/NpcBase.hpp b/include/NPC/NpcBase.hpp index c33044f8c..9dc1b4510 100644 --- a/include/NPC/NpcBase.hpp +++ b/include/NPC/NpcBase.hpp @@ -432,11 +432,20 @@ class TBaseNPC : public TSpineEnemy { void doThing() { - int iVar13 = mPtrSaveNormal->mSLGraphWanderMinFrame.get(); - int sVar1 = mPtrSaveNormal->mSLGraphWanderMaxFrame.get(); + int maxFrame = mPtrSaveNormal->mSLGraphWanderMaxFrame.get(); + int minFrame = mPtrSaveNormal->mSLGraphWanderMinFrame.get(); unk0 = 0; - unk4 = MsRandI(sVar1, iVar13); + unk4 = MsRandI(minFrame, maxFrame); + } + + void startGraphWait() + { + int maxFrame = mPtrSaveNormal->mSLGraphWaitMaxFrame.get(); + int minFrame = mPtrSaveNormal->mSLGraphWaitMinFrame.get(); + + unk0 = 0; + unk4 = MsRandI(minFrame, maxFrame); } bool doThing2() diff --git a/src/NPC/NpcNerve.cpp b/src/NPC/NpcNerve.cpp index dc528825d..10b2563ce 100644 --- a/src/NPC/NpcNerve.cpp +++ b/src/NPC/NpcNerve.cpp @@ -77,7 +77,7 @@ DEFINE_NERVE(TNerveNPCGraphWait, TLiveActor) TBaseNPC* self = (TBaseNPC*)spine->getBody(); if (spine->getTime() == 0) - self->unk22C->doThing(); + self->unk22C->startGraphWait(); if (self->getMarchSpeed() < 0.001f) { if (self->unk22C->doThing2()) { @@ -114,13 +114,14 @@ DEFINE_NERVE(TNerveNPCWaitMarioApproach, TLiveActor) return true; } - if (self->getActorType() - 0x400001C > 1) { + u32 actorType = self->getActorType(); + if (actorType - 0x400001C > 1) { if (!self->isPeachTired()) { if (self->isSunflowerReviving()) { self->sunflowerReviving(); - } else if (self->getActorType() == 0x4000006) { + } else if (actorType == 0x4000006) { self->monteMESetAnmWhenFar(); self->execTurnToFirstState(); } else { @@ -149,11 +150,12 @@ DEFINE_NERVE(TNerveNPCTurnToMario, TLiveActor) return true; } - if (self->getActorType() - 0x400001C > 1) { + u32 actorType = self->getActorType(); + if (actorType - 0x400001C > 1) { if (!self->isPeachTired()) { if (self->isSunflowerReviving()) { self->sunflowerReviving(); - } else if (self->getActorType() == 0x4000006) { + } else if (actorType == 0x4000006) { self->monteMESetAnmWhenNear(); self->execTurnToFirstState(); } else if (self->isTurnToMarioWhenApproach()) { From ac4e1fdc4d50eb06f6004c536e399205f7e8b5cf Mon Sep 17 00:00:00 2001 From: KakarotCake <61133727+KakarottoCake@users.noreply.github.com> Date: Sun, 27 Sep 2026 19:24:18 -0400 Subject: [PATCH 4/6] Format NPC changes --- include/NPC/NpcBase.hpp | 9 ++++----- src/NPC/NpcEvent.cpp | 5 ++--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/include/NPC/NpcBase.hpp b/include/NPC/NpcBase.hpp index 9dc1b4510..ed08303ad 100644 --- a/include/NPC/NpcBase.hpp +++ b/include/NPC/NpcBase.hpp @@ -244,12 +244,11 @@ class TBaseNPC : public TSpineEnemy { f32 getAnmOffDist_() { bool useDanceDistance = false; - f32 distance = gpCamera->mFar; - int animationKind = unkD0->getCurrentAnmKind(); - f32 danceDistance = mPtrSaveNormal->mSLDanceAnmOffDist.get(); + f32 distance = gpCamera->mFar; + int animationKind = unkD0->getCurrentAnmKind(); + f32 danceDistance = mPtrSaveNormal->mSLDanceAnmOffDist.get(); if (checkActionFlag(NPC_ACTION_HAPPY | NPC_ACTION_DANCE) - || mActorType == 0x400000D - || animationKind == NPC_ANM_KIND_MAD + || mActorType == 0x400000D || animationKind == NPC_ANM_KIND_MAD || animationKind == NPC_ANM_KIND_UNK17) { useDanceDistance = true; } diff --git a/src/NPC/NpcEvent.cpp b/src/NPC/NpcEvent.cpp index 02331ed36..e85e33c98 100644 --- a/src/NPC/NpcEvent.cpp +++ b/src/NPC/NpcEvent.cpp @@ -282,9 +282,8 @@ static void evFireStartDemoCamera(TSpcTypedInterp* interp, interp->verifyArgNum(1, &arg_num); const char* cameraName = interp->pop().getDataString(); TMarDirector* director = gpMarDirector; - director->fireStartDemoCamera(cameraName, nullptr, -1, 0.0f, true, - nullptr, 0, nullptr, - JDrama::TFlagT()); + director->fireStartDemoCamera(cameraName, nullptr, -1, 0.0f, true, nullptr, + 0, nullptr, JDrama::TFlagT()); interp->push(); } From 57225f351fc3c8666f83e051dc0df292e25c27b0 Mon Sep 17 00:00:00 2001 From: KakarotCake <61133727+KakarottoCake@users.noreply.github.com> Date: Sun, 27 Sep 2026 19:31:58 -0400 Subject: [PATCH 5/6] Correct NPC nerve change conditions --- src/NPC/NpcChange.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/NPC/NpcChange.cpp b/src/NPC/NpcChange.cpp index 07c444f4b..0b6ca1498 100644 --- a/src/NPC/NpcChange.cpp +++ b/src/NPC/NpcChange.cpp @@ -65,6 +65,7 @@ bool TBaseNPC::isNerveMaybeDontCalcAnim1() const return result; } +#pragma dont_inline on bool TBaseNPC::isNerveCanGoToTalk() const { bool result = false; @@ -85,6 +86,7 @@ bool TBaseNPC::isNerveCanGoToTalk() const } return result; } +#pragma dont_inline off bool TBaseNPC::isNerveCanGoToWet() const { @@ -464,15 +466,15 @@ void TBaseNPC::changeNerveProc_() | LIVE_FLAG_SINK_BOTTOM | LIVE_FLAG_UNK400000) && !checkActionFlag(NPC_ACTION_BURNING) && isClean()) { - if (isSunflowerReviving() && isNerveCanGoToTalk() + if (!isSunflowerReviving() && isNerveCanGoToTalk() && (mActorType != 0x4000006 || unkD0->getCurrentAnmKind() == NPC_ANM_KIND_UNK4) && !SMS_IsMarioOpeningDoor()) { if (gpMarDirector->mMap == 7) { JGeometry::TVec3 local_58 = mPosition; local_58.y += 75.0f; - if (SMS_IsInSameCameraCube(local_58)) - bVar5 = true; + if (!SMS_IsInSameCameraCube(local_58)) + goto L_skipTalk; } f32 fVar1; @@ -507,9 +509,11 @@ void TBaseNPC::changeNerveProc_() } } + L_skipTalk: if (bVar5) { onLiveFlag(LIVE_FLAG_UNK20000); if (checkLiveFlag(LIVE_FLAG_UNK40000)) { + bVar4 = true; offLiveFlag(LIVE_FLAG_UNK40000); const TNerveBase* current = mSpine->getCurrentNerve(); @@ -550,7 +554,7 @@ void TBaseNPC::changeNerveProc_() unk15C->unk0 = 0; if (latestNerve == &TNerveNPCSink::theNerve()) { - if (gpPollution->isPolluted(mPosition.x, mPosition.y, mPosition.z)) + if (gpPollution->isPolluted(mPosition.x, unk1C4, mPosition.z)) return; mSpine->setNext(&TNerveNPCRecoverFromSink::theNerve()); From f50655722928a8c61b0551bb7e0a3b19100a103b Mon Sep 17 00:00:00 2001 From: KakarotCake <61133727+KakarottoCake@users.noreply.github.com> Date: Sun, 27 Sep 2026 19:51:39 -0400 Subject: [PATCH 6/6] Address NPC review comments --- src/NPC/NpcChange.cpp | 60 +++++++++++++++++++++---------------------- src/NPC/NpcEvent.cpp | 6 ++--- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/NPC/NpcChange.cpp b/src/NPC/NpcChange.cpp index 0b6ca1498..befa74809 100644 --- a/src/NPC/NpcChange.cpp +++ b/src/NPC/NpcChange.cpp @@ -65,7 +65,6 @@ bool TBaseNPC::isNerveMaybeDontCalcAnim1() const return result; } -#pragma dont_inline on bool TBaseNPC::isNerveCanGoToTalk() const { bool result = false; @@ -86,7 +85,6 @@ bool TBaseNPC::isNerveCanGoToTalk() const } return result; } -#pragma dont_inline off bool TBaseNPC::isNerveCanGoToWet() const { @@ -470,46 +468,48 @@ void TBaseNPC::changeNerveProc_() && (mActorType != 0x4000006 || unkD0->getCurrentAnmKind() == NPC_ANM_KIND_UNK4) && !SMS_IsMarioOpeningDoor()) { + bool inCameraCube = true; if (gpMarDirector->mMap == 7) { JGeometry::TVec3 local_58 = mPosition; local_58.y += 75.0f; - if (!SMS_IsInSameCameraCube(local_58)) - goto L_skipTalk; + inCameraCube = SMS_IsInSameCameraCube(local_58); } - f32 fVar1; - f32 fVar2; - if (mThrowCtrl != nullptr) { - fVar1 = mPtrSaveNormal->mSLThrowTalkAcceptHeight.get(); - fVar2 = mPtrSaveNormal->mSLThrowTalkAcceptDist.get(); - } else { - if (mActorType == 0x400001A) { - fVar2 = mPtrSaveNormal->mSLSunflowerLTalkDist.get(); + if (inCameraCube) { + f32 fVar1; + f32 fVar2; + if (mThrowCtrl != nullptr) { + fVar1 = mPtrSaveNormal->mSLThrowTalkAcceptHeight.get(); + fVar2 = mPtrSaveNormal->mSLThrowTalkAcceptDist.get(); } else { - fVar2 = mPtrSaveNormal->mTalkAcceptDist.get(); + if (mActorType == 0x400001A) { + fVar2 = mPtrSaveNormal->mSLSunflowerLTalkDist.get(); + } else { + fVar2 = mPtrSaveNormal->mTalkAcceptDist.get(); + } + fVar1 = mPtrSaveNormal->mTalkAcceptHeight.get(); } - fVar1 = mPtrSaveNormal->mTalkAcceptHeight.get(); - } - f32 fVar3; - if ((checkActionFlag(NPC_ACTION_UNK400 | NPC_ACTION_UNK1)) - || isSunflower() || mActorType == 0x400001D) { - fVar3 = mPtrSaveNormal->mSLSitTalkAcceptDegree.get(); - } else { - fVar3 = mPtrSaveNormal->mTalkAcceptDegree.get(); - } + f32 fVar3; + if ((checkActionFlag(NPC_ACTION_UNK400 | NPC_ACTION_UNK1)) + || isSunflower() || mActorType == 0x400001D) { + fVar3 = mPtrSaveNormal->mSLSitTalkAcceptDegree.get(); + } else { + fVar3 = mPtrSaveNormal->mTalkAcceptDegree.get(); + } - if (abs(SMS_GetMarioPos().y - mPosition.y) < fVar1 - && isInSight(SMS_GetMarioPos(), fVar2, fVar3, -1.0f) - && MsIsInSight( - SMS_GetMarioPos(), SHORTANGLE2DEG(*gpMarioAngleY), - mPosition, fVar2, - mPtrSaveNormal->mSLMarioTalkAcceptDegree.get(), 0.0f)) - bVar5 = true; + if (abs(SMS_GetMarioPos().y - mPosition.y) < fVar1 + && isInSight(SMS_GetMarioPos(), fVar2, fVar3, -1.0f) + && MsIsInSight( + SMS_GetMarioPos(), SHORTANGLE2DEG(*gpMarioAngleY), + mPosition, fVar2, + mPtrSaveNormal->mSLMarioTalkAcceptDegree.get(), + 0.0f)) + bVar5 = true; + } } } - L_skipTalk: if (bVar5) { onLiveFlag(LIVE_FLAG_UNK20000); if (checkLiveFlag(LIVE_FLAG_UNK40000)) { diff --git a/src/NPC/NpcEvent.cpp b/src/NPC/NpcEvent.cpp index e85e33c98..c447d1cce 100644 --- a/src/NPC/NpcEvent.cpp +++ b/src/NPC/NpcEvent.cpp @@ -281,9 +281,9 @@ static void evFireStartDemoCamera(TSpcTypedInterp* interp, { interp->verifyArgNum(1, &arg_num); const char* cameraName = interp->pop().getDataString(); - TMarDirector* director = gpMarDirector; - director->fireStartDemoCamera(cameraName, nullptr, -1, 0.0f, true, nullptr, - 0, nullptr, JDrama::TFlagT()); + SMSGetMarDirector()->fireStartDemoCamera(cameraName, nullptr, -1, 0.0f, + true, nullptr, 0, nullptr, + JDrama::TFlagT()); interp->push(); }