From f3df623e6a3785f85a5cfd365bbec426b3b6b555 Mon Sep 17 00:00:00 2001 From: gitRasheed Date: Wed, 16 Sep 2026 10:43:02 +0100 Subject: [PATCH 01/13] Enemy/hanasambo: match 65 of the TU's 95 functions from the map --- include/Enemy/HanaSambo.hpp | 318 ++++++++++++++ src/Enemy/hanasambo.cpp | 815 ++++++++++++++++++++++++++++++++++++ 2 files changed, 1133 insertions(+) create mode 100644 include/Enemy/HanaSambo.hpp diff --git a/include/Enemy/HanaSambo.hpp b/include/Enemy/HanaSambo.hpp new file mode 100644 index 000000000..f797b53cb --- /dev/null +++ b/include/Enemy/HanaSambo.hpp @@ -0,0 +1,318 @@ +#ifndef ENEMY_HANASAMBO_HPP +#define ENEMY_HANASAMBO_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class JSUMemoryInputStream; +class SDLModelData; +class THitActor; +class TLiveManager; +class TSamboHead; +class TSamboHeadManager; +class TSamboHeadSaveLoadParams; +class THanaSambo; +class THanaSamboHead; +class THanaSamboManager; +class THanaSamboSaveLoadParams; +class TSamboFlower; +class TSamboFlowerManager; +class TSamboFlowerSaveLoadParams; +class TSamboLeaf; +class TSamboFlowerCoinUnit; + +DECLARE_NERVE(TNerveSamboHeadHitWall, TLiveActor); + +DECLARE_NERVE(TNerveSamboHeadRecoverWater, TLiveActor); + +DECLARE_NERVE(TNerveSamboHeadHitWater, TLiveActor); + +DECLARE_NERVE(TNerveSamboHeadAttack, TLiveActor); + +DECLARE_NERVE(TNerveSamboHeadHide, TLiveActor); + +DECLARE_NERVE(TNerveSamboHeadAppear, TLiveActor); + +class TSamboHead : public TWalkerEnemy { +public: + TSamboHead(const char*); + + virtual void load(JSUMemoryInputStream&); + virtual void init(TLiveManager*); + virtual void calcRootMatrix(); + virtual void kill(); + virtual f32 getGravityY() const; + virtual const char** getBasNameTable() const; + virtual void reset(); + virtual void genEventCoin(); + virtual void behaveToWater(THitActor*); + virtual void setDeadAnm(); + virtual void attackToMario(); + virtual void setMActorAndKeeper(); + virtual void setAfterDeadEffect(); + + bool isUseCallBack(); + void setCrashAnm(); + void initFlower(); + static u8 mBodyJntIndex; + +public: + /* 0x194 */ void* unk194; + /* 0x198 */ s32 unk198; + /* 0x19C */ s32 unk19C; + /* 0x1A0 */ char unk1A0[0xC]; + /* 0x1AC */ f32 unk1AC; + /* 0x1B0 */ u8 unk1B0; +}; + +class TSamboHeadManager : public TSmallEnemyManager { +public: + TSamboHeadManager(const char*); + + virtual void load(JSUMemoryInputStream&); + virtual void createModelData(); + virtual TSpineEnemy* createEnemyInstance(); +}; + +class TSamboHeadSaveLoadParams : public TWalkerEnemyParams { +public: + TSamboHeadSaveLoadParams(const char*); + +public: + /* 0x32C */ TParamRT mSLAppearDist; + /* 0x340 */ TParamRT mSLHideDist; + /* 0x354 */ TParamRT mSLMoveDist; + /* 0x368 */ TParamRT mSLMoveGravity; + /* 0x37C */ TParamRT mSLJumpSp; + /* 0x390 */ TParamRT mSLJumpPrepareTime; + /* 0x3A4 */ TParamRT mSLHitJumpSpXZ; + /* 0x3B8 */ TParamRT mSLHitJumpSpY; + /* 0x3CC */ TParamRT mSLHitJumpGravity; + /* 0x3E0 */ TParamRT mSLHitJumpSpRateXZ; + /* 0x3F4 */ TParamRT mSLHitJumpSpRateY; + /* 0x408 */ TParamRT mSLJumpAngY; +}; + +DECLARE_NERVE(TNerveHanaSamboFreeze, TLiveActor); + +DECLARE_NERVE(TNerveHanaSamboDie, TLiveActor); + +DECLARE_NERVE(TNerveHanaSamboHide, TLiveActor); + +DECLARE_NERVE(TNerveHanaSamboAppear, TLiveActor); + +DECLARE_NERVE(TNerveHanaSamboAttack, TLiveActor); + +DECLARE_NERVE(TNerveHanaSamboWait, TLiveActor); + +class THanaSambo : public TSmallEnemy { +public: + THanaSambo(const char*); + + virtual void load(JSUMemoryInputStream&); + virtual void perform(u32, JDrama::TGraphics*); + virtual void init(TLiveManager*); + virtual void moveObject(); + virtual void drawObject(JDrama::TGraphics*); + virtual void kill(); + virtual const char** getBasNameTable() const; + virtual void reset(); + virtual void behaveToWater(THitActor*) { } + virtual void setDeadAnm(); + virtual void setWaitAnm(); + virtual void setMActorAndKeeper(); + virtual bool isHitValid(u32 message) + { + if (message == 0xB) + return true; + return false; + } + virtual bool isCollidMove(THitActor*) { return false; } + + void initFlower(); + void createPollen(); + void waterDamage(); + void setAttackAnm(); + static u8 mHeadJntIndex; + static u8 mPollenJntIndex; + +public: + /* 0x194 */ THitActor* unk194; + /* 0x198 */ THanaSamboSaveLoadParams* unk198; + /* 0x19C */ JGeometry::TVec3 unk19C; + /* 0x1A8 */ s32 unk1A8; + /* 0x1AC */ class TMBindShadowBody* unk1AC; + /* 0x1B0 */ u8 unk1B0; + /* 0x1B4 */ JGeometry::TVec3 unk1B4[4]; +}; + +class THanaSamboHead : public THitActor { +public: + THanaSamboHead(); // TODO: constructor not in mario.MAP for this TU + virtual BOOL receiveMessage(THitActor*, u32); + + void kill(); + bool checkHit(); + +public: + /* 0x68 */ THanaSambo* unk68; +}; + +class THanaSamboManager : public TSmallEnemyManager { +public: + THanaSamboManager(const char*); + + virtual void load(JSUMemoryInputStream&); + virtual void createModelData(); + virtual TSpineEnemy* createEnemyInstance(); +}; + +class THanaSamboSaveLoadParams : public TSmallEnemyParams { +public: + THanaSamboSaveLoadParams(const char*); + +public: + /* 0x2D4 */ TParamRT mSLAttackDist; + /* 0x2E8 */ TParamRT mSLAttackInterval; + /* 0x2FC */ TParamRT mSLHideDist; + /* 0x310 */ TParamRT mSLAppearDist; + /* 0x324 */ TParamRT mSLAttackingTime; + /* 0x338 */ TParamRT mSLHeadAttackRadius; + /* 0x34C */ TParamRT mSLHeadAttackHeight; + /* 0x360 */ TParamRT mSLHeadDamageRadius; + /* 0x374 */ TParamRT mSLHeadDamageHeight; +}; + +class TSamboFlower : public TSpineEnemy { +public: + TSamboFlower(const char* name = "サンボフラワー"); + virtual void load(JSUMemoryInputStream&); + virtual void loadAfter(); + virtual BOOL receiveMessage(THitActor*, u32); + virtual void init(TLiveManager*); + virtual void control() { } + virtual void moveObject(); + virtual void drawObject(JDrama::TGraphics*); + virtual void reset(); + virtual void setMActorAndKeeper(); + + void hide(); + bool isBloomEnd(); + void bloom(); + +public: + /* 0x150 */ u8 unk150; + /* 0x151 */ char unk151[0x3]; + /* 0x154 */ s32 unk154; + /* 0x158 */ s32 unk158; + /* 0x15C */ s32 unk15C; + /* 0x160 */ u8 unk160; + /* 0x161 */ char unk161[0x3]; + /* 0x164 */ TSamboFlowerCoinUnit* unk164; + /* 0x168 */ class TMapObjBase* unk168; + /* 0x16C */ TSpineEnemyParams* unk16C; +}; + +class TSamboFlowerManager : public TEnemyManager { +public: + TSamboFlowerManager(const char* name = "サンボフラワーマネージャー") + : TEnemyManager(name) + , unk54(0) + , unk58(0) + , unk5C(0) + , unk60(0) + { + } + + virtual void load(JSUMemoryInputStream&); + virtual void loadAfter(); + virtual void perform(u32, JDrama::TGraphics*); + virtual void createModelData(); + virtual TSpineEnemy* createEnemyInstance(); + virtual void dropLeaf(JGeometry::TVec3&, JGeometry::TVec3&); + +public: + /* 0x54 */ TSamboFlowerCoinUnit** unk54; + /* 0x58 */ s32 unk58; + /* 0x5C */ s32 unk5C; + /* 0x60 */ TSamboLeaf** unk60; + /* 0x64 */ class J3DMaterialTable* unk64; +}; + +class TSamboFlowerSaveLoadParams : public TSpineEnemyParams { +public: + TSamboFlowerSaveLoadParams(const char*); + +public: + /* 0xA8 */ TParamRT mSLLeafVelocityXZ; + /* 0xBC */ TParamRT mSLLeafVelocityY; + /* 0xD0 */ TParamRT mSLLeafGravity; + /* 0xE4 */ TParamRT mSLBudDist; + /* 0xF8 */ TParamRT mSLBloomTimer; + /* 0x10C */ TParamRT mSLCoinCircleR; + /* 0x120 */ TParamRT mSLCoinVelocityXZ; + /* 0x134 */ TParamRT mSLCoinVelocityY; + /* 0x148 */ TParamRT mSLSeedShootRange; + /* 0x15C */ TParamRT mSLSeedShootInterval; + /* 0x170 */ TParamRT mSLSeedGravity; + /* 0x184 */ TParamRT mSLSeedSpeedXZ; + /* 0x198 */ TParamRT mSLSeedSpeedY; +}; + +class TSamboLeaf : public JDrama::TViewObj { +public: + TSamboLeaf(TSamboFlowerManager*, SDLModelData*, const char*); + + virtual void perform(u32, JDrama::TGraphics*); + + void generate(JGeometry::TVec3&); + +public: + /* 0xC */ char unkC[0x4]; + /* 0x10 */ void* unk10; + /* 0x14 */ f32 unk14; + /* 0x18 */ f32 unk18; + /* 0x1C */ f32 unk1C; + /* 0x20 */ char unk20[0x4]; + /* 0x24 */ f32 unk24; + /* 0x28 */ char unk28[0x4]; + /* 0x2C */ s32 unk2C; + /* 0x30 */ s32 unk30; + /* 0x34 */ s32 unk34; + /* 0x38 */ f32 unk38; + /* 0x3C */ f32 unk3C; + /* 0x40 */ f32 unk40; + /* 0x44 */ u8 unk44; + /* 0x45 */ char unk45[0x3]; + /* 0x48 */ void* unk48; +}; + +class TSamboFlowerCoinUnit { +public: + TSamboFlowerCoinUnit(int); + + bool checkGenCoin(); + void add(TSamboFlower*); + +public: + /* 0x0 */ s32 unk0; + /* 0x4 */ s32 unk4; + /* 0x8 */ s32 unk8; + /* 0xC */ s32 unkC; + /* 0x10 */ s32 unk10; + /* 0x14 */ char unk14[0x4]; + /* 0x18 */ s32 unk18; +}; + +#endif // ENEMY_HANASAMBO_HPP diff --git a/src/Enemy/hanasambo.cpp b/src/Enemy/hanasambo.cpp index 8b1378917..98a30c970 100644 --- a/src/Enemy/hanasambo.cpp +++ b/src/Enemy/hanasambo.cpp @@ -1 +1,816 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// rogue includes needed for matching sinit & bss +#include +#include + +TSamboFlowerCoinUnit::TSamboFlowerCoinUnit(int param_1) { } + +void TSamboFlowerCoinUnit::add(TSamboFlower* param_1) { } + +bool TSamboFlowerCoinUnit::checkGenCoin() { return false; } + +TSamboLeaf::TSamboLeaf(TSamboFlowerManager* param_1, SDLModelData* param_2, + const char* param_3) + : JDrama::TViewObj(param_3) +{ +} + +void TSamboLeaf::perform(u32 param_1, JDrama::TGraphics* param_2) { } + +void TSamboLeaf::generate(JGeometry::TVec3& param_1) { } + +TSamboFlowerSaveLoadParams::TSamboFlowerSaveLoadParams(const char* param_1) + : TSpineEnemyParams(param_1) + , PARAM_INIT(mSLLeafVelocityXZ, 4.0f) + , PARAM_INIT(mSLLeafVelocityY, 6.0f) + , PARAM_INIT(mSLLeafGravity, 0.2f) + , PARAM_INIT(mSLBudDist, 2000.0f) + , PARAM_INIT(mSLBloomTimer, 300) + , PARAM_INIT(mSLCoinCircleR, 100.0f) + , PARAM_INIT(mSLCoinVelocityXZ, 12.0f) + , PARAM_INIT(mSLCoinVelocityY, 10.0f) + , PARAM_INIT(mSLSeedShootRange, 500.0f) + , PARAM_INIT(mSLSeedShootInterval, 200) + , PARAM_INIT(mSLSeedGravity, 0.1f) + , PARAM_INIT(mSLSeedSpeedXZ, 10.0f) + , PARAM_INIT(mSLSeedSpeedY, 10.0f) +{ + TParams::load(mPrmPath); +} + +void TSamboFlowerManager::load(JSUMemoryInputStream& param_1) +{ + TEnemyManager::load(param_1); + unk38 = new TSamboFlowerSaveLoadParams("/enemy/samboflower.prm"); + unk64 = J3DModelLoaderDataBase::loadMaterialTable( + JKRFileLoader::getGlbResource("/scene/samboflower/flower_orange.bmt")); +} + +void TSamboFlowerManager::createModelData() +{ + static TModelDataLoadEntry entry[] = { + { "flower.bmd", 0x10220000, 0 }, + { nullptr, 0, 0 }, + }; + createModelDataArray(entry); +} + +TSpineEnemy* TSamboFlowerManager::createEnemyInstance() +{ + return new TSamboFlower("サンボフラワー"); +} + +void TSamboFlowerManager::loadAfter() { } + +void TSamboFlowerManager::perform(u32 param_1, JDrama::TGraphics* param_2) +{ + if (unk58 > 0 && param_1 & 2) { + for (int i = 0; i < unk58; ++i) + unk54[i]->checkGenCoin(); + } + + TEnemyManager::perform(param_1, param_2); + + for (int i = 0; i < 0x12; ++i) + unk60[i]->perform(param_1, param_2); +} + +void TSamboFlowerManager::dropLeaf(JGeometry::TVec3& param_1, + JGeometry::TVec3& param_2) +{ +} + +void TSamboFlower::load(JSUMemoryInputStream& param_1) +{ + TSpineEnemy::load(param_1); + param_1.read(&unk15C, 4); + param_1.read(&unk158, 4); + unk160 = true; + reset(); + offLiveFlag(LIVE_FLAG_UNK800); +} + +void TSamboFlower::loadAfter() +{ + JDrama::TNameRef::loadAfter(); + if (unk15C < 0) + return; + + TMapObjBase* obj = TMapObjBaseManager::newAndRegisterObj( + "coin", JGeometry::TVec3(0.0f, 0.0f, 0.0f), + JGeometry::TVec3(0.0f, 0.0f, 0.0f), + JGeometry::TVec3(1.0f, 1.0f, 1.0f)); + if (obj) + unk168 = obj; +} + +void TSamboFlower::init(TLiveManager* param_1) +{ + mManager = param_1; + param_1->manageActor(this); + setMActorAndKeeper(); + unk130 = 1; + unk16C = getSaveParam(); + if (unk16C) { + mBodyRadius = unk16C->mSLBodyRadius.get(); + mWallRadius = unk16C->mSLWallRadius.get(); + mHeadHeight = unk16C->mSLHeadHeight.get(); + mScaledBodyRadius = mBodyScale * mBodyRadius; + } + + initHitActor(0x10000027, 1, 0x80000000, mBodyRadius, mHeadHeight, + mBodyRadius, mHeadHeight); + onHitFlag(HIT_FLAG_NO_COLLISION); + offLiveFlag(LIVE_FLAG_UNK400); + initAnmSound(); + mActorType = 0x10000027; + unk150 = false; + onLiveFlag(LIVE_FLAG_DEAD); +} + +void TSamboFlower::setMActorAndKeeper() +{ + mMActorKeeper = new TMActorKeeper(mManager, 1); + mMActor = mMActorKeeper->createMActor("flower.bmd", 3); + + MActor* actor = mMActor; + J3DMaterialTable* table = ((TSamboFlowerManager*)mManager)->unk64; + J3DModelData* model_data = actor->getModel()->getModelData(); + model_data->setMaterialTable(table, J3DMatCopyFlag_All); + actor->initDL(); + actor->getModel()->lock(); +} + +BOOL TSamboFlower::receiveMessage(THitActor* param_1, u32 param_2) +{ + if (param_2 == HIT_MESSAGE_SPRAYED_BY_WATER) { + if (!unk150) { + unk150 = true; + unk154 = 0; + gpMarioParticleManager->emit(0xB2, &mPosition, 0, nullptr); + mMActor->setBck("flower_hit"); + if (unk160 && unk164) { + unk164->unk0 = unk164->unk0 - 1; + u32 id = MSD_SE_OBJ_FLOWER_OPEN_0 + unk164->unk0; + if (gpMSound->gateCheck(id)) + MSoundSESystem::MSoundSE::startSoundActor(id, &mPosition, 0, + nullptr, 0, 4); + } + } + return 1; + } + + return 0; +} + +void TSamboFlower::reset() +{ + TSpineEnemy::reset(); + mMActor->setBck("flower_wait"); + offHitFlag(HIT_FLAG_NO_COLLISION); + offLiveFlag(LIVE_FLAG_UNK800); + offLiveFlag(LIVE_FLAG_DEAD); + offLiveFlag(LIVE_FLAG_UNK10); +} + +void TSamboFlower::moveObject() +{ + if (unk150) { + if (checkCurAnmEnd(0) && getMActor()->checkCurAnm("flower_hit", 0)) + getMActor()->setBck("flower_fwait"); + + if (unk160) { + unk154++; + if (unk154 + > ((TSamboFlowerSaveLoadParams*)unk16C)->mSLBloomTimer.get()) { + if (getMActor()->checkCurAnm("flower_fwait", 0)) { + unk150 = false; + if (unk164) + unk164->unk0 = unk164->unk0 + 1; + + getMActor()->setBck("flower_hit"); + getMActor() + ->getFrameCtrl(ANM_TYPE_BCK) + ->setFrame( + getMActor()->getFrameCtrl(ANM_TYPE_BCK)->getEnd()); + getMActor()->setFrameRate(-SMSGetAnmFrameRate(), + ANM_TYPE_BCK); + } else if (getMActor()->getFrameCtrl(ANM_TYPE_BCK)->getFrame() + < 1.0f) { + unk154 = 0; + getMActor()->setBck("flower_wait"); + } + } + } + } + + if (!checkLiveFlag(LIVE_FLAG_UNK10)) + mPosition.y = gpMap->checkGround(mPosition.x, mPosition.y + 100.0f, + mPosition.z, &mGroundPlane); +} + +void TSamboFlower::drawObject(JDrama::TGraphics* param_1) +{ + if (checkLiveFlag(LIVE_FLAG_DEAD)) + return; + + TCircleShadowRequest request; + request.mPosition = mPosition; + request.mRadiusX = request.mRadiusZ = 120.0f; + gpBindShadowManager->request(request, getActorType() & ACTOR_TYPE_MASK); + mMActor->setLightData(mGroundPlane, mPosition); + mMActor->entry(); +} + +void TSamboFlower::bloom() { } + +bool TSamboFlower::isBloomEnd() { return false; } + +void TSamboFlower::hide() { } + +// TODO: default values are placeholders; names and offsets are from the object. +THanaSamboSaveLoadParams::THanaSamboSaveLoadParams(const char* param_1) + : TSmallEnemyParams(param_1) + , PARAM_INIT(mSLAttackDist, 0.0f) + , PARAM_INIT(mSLAttackInterval, 0) + , PARAM_INIT(mSLHideDist, 0.0f) + , PARAM_INIT(mSLAppearDist, 0.0f) + , PARAM_INIT(mSLAttackingTime, 0) + , PARAM_INIT(mSLHeadAttackRadius, 0.0f) + , PARAM_INIT(mSLHeadAttackHeight, 0.0f) + , PARAM_INIT(mSLHeadDamageRadius, 0.0f) + , PARAM_INIT(mSLHeadDamageHeight, 0.0f) +{ + TParams::load(mPrmPath); +} + +THanaSamboManager::THanaSamboManager(const char* param_1) + : TSmallEnemyManager(param_1) +{ +} + +void THanaSamboManager::load(JSUMemoryInputStream& param_1) { } + +TSpineEnemy* THanaSamboManager::createEnemyInstance() +{ + return new THanaSambo("ハナサンボ"); +} + +void THanaSamboManager::createModelData() +{ + static TModelDataLoadEntry entry[] = { + { "sambo.bmd", 0x10220000, 0 }, + { "samboD.bmd", 0x10220000, 0 }, + { nullptr, 0, 0 }, + }; + createModelDataArray(entry); +} + +BOOL THanaSamboHead::receiveMessage(THitActor* param_1, u32 param_2) +{ + if (param_2 == HIT_MESSAGE_TRAMPLE || param_2 == HIT_MESSAGE_HIP_DROP) { + unk68->kill(); + return 1; + } + + if (param_2 == HIT_MESSAGE_SPRAYED_BY_WATER) { + unk68->waterDamage(); + return 1; + } + + return 0; +} + +bool THanaSamboHead::checkHit() { return false; } + +void THanaSamboHead::kill() { } + +THanaSambo::THanaSambo(const char* param_1) + : TSmallEnemy(param_1) + , unk194(nullptr) + , unk198(0) + , unk1A8(0) + , unk1AC(0) +{ +} + +void THanaSambo::load(JSUMemoryInputStream& param_1) +{ + TSmallEnemy::load(param_1); + reset(); + setGoalPathMario(); +} + +void THanaSambo::init(TLiveManager* param_1) { } + +void THanaSambo::setMActorAndKeeper() +{ + mMActorKeeper = new TMActorKeeper(mManager, 2); + mMActor = mMActorKeeper->createMActor("sambo.bmd", 3); + mMActorKeeper->createMActor("samboD.bmd", 3); +} + +u8 THanaSambo::mHeadJntIndex = 3; +u8 THanaSambo::mPollenJntIndex = 6; + +void THanaSambo::moveObject() +{ + TSmallEnemy::moveObject(); + + if (checkLiveFlag(LIVE_FLAG_CLIPPED_OUT)) { + unk194->mPosition = mPosition; + } else { + MtxPtr mtx = getModel()->getAnmMtx(mHeadJntIndex); + unk194->mPosition.x = mtx[0][3]; + unk194->mPosition.y = mtx[1][3]; + unk194->mPosition.z = mtx[2][3]; + } + + THitActor* head = unk194; + for (int i = 0; i < head->getColNum(); ++i) { + if (head->getCollision(i)->isActorType(0x80000001)) + SMS_SendMessageToMario(head, HIT_MESSAGE_ATTACK); + } + + mPosition.x = unk19C.x; + mPosition.z = unk19C.z; +} + +void THanaSambo::drawObject(JDrama::TGraphics* param_1) +{ + TLiveActor::drawObject(param_1); + if (!checkLiveFlag(LIVE_FLAG_DEAD | LIVE_FLAG_HIDDEN | LIVE_FLAG_UNK8)) + unk1AC->entryDrawShadow(); +} + +void THanaSambo::kill() +{ + if (checkLiveFlag(LIVE_FLAG_DEAD)) + return; + + mHitPoints = 1; + if (isBckAnm(7)) + unk18C = 3; + + if (mSpine->getCurrentNerve() != &TNerveHanaSamboDie::theNerve()) { + mSpine->reset(); + mSpine->setNext(&TNerveHanaSamboDie::theNerve()); + mSpine->pushAfterCurrent(&TNerveHanaSamboDie::theNerve()); + } + + unk194->onHitFlag(HIT_FLAG_NO_COLLISION); + onLiveFlag(LIVE_FLAG_UNK40); +} + +void THanaSambo::reset() +{ + TSmallEnemy::reset(); + unk165 = false; + unk19C = mPosition; +} + +void THanaSambo::setWaitAnm() +{ + setBckAnm(7); + unk1B0 = 0; +} + +void THanaSambo::setDeadAnm() +{ + mMActor = getActorKeeper()->getMActor("samboD.bmd"); + if (unk1B0) + setBckAnm(10); + else + setBckAnm(0); + + unk194->onHitFlag(HIT_FLAG_NO_COLLISION); + unk1B0 = 0; + onLiveFlag(LIVE_FLAG_UNK8); +} + +void THanaSambo::setAttackAnm() +{ + setBckAnm(3); + unk1B0 = 1; +} + +void THanaSambo::waterDamage() +{ + unk165 = true; + + if (changeByJuice()) + return; + + if (mSpine->getCurrentNerve() != &TNerveHanaSamboWait::theNerve()) + return; + + mSpine->pushNerve(&TNerveHanaSamboFreeze::theNerve()); +} + +static const char* sambo_bastable[] = { + "/scene/sambo/bas/sambo_down.bas", + 0, + 0, + 0, + "/scene/sambo/bas/sambo_Fhide.bas", + 0, + "/scene/sambo/bas/sambo_Fset.bas", + "/scene/sambo/bas/sambo_Fwait.bas", + "/scene/sambo/bas/sambo_hit.bas", + 0, + "/scene/sambo/bas/sambo_Ydown.bas", +}; + +const char** THanaSambo::getBasNameTable() const { return sambo_bastable; } + +void THanaSambo::perform(u32 param_1, JDrama::TGraphics* param_2) +{ + TSmallEnemy::perform(param_1, param_2); + if (!checkLiveFlag(LIVE_FLAG_DEAD | LIVE_FLAG_HIDDEN + | LIVE_FLAG_CLIPPED_OUT)) + unk194->THitActor::perform(param_1, param_2); +} + +void THanaSambo::createPollen() +{ + MtxPtr jointMtx = getMActor()->getModel()->getAnmMtx(mPollenJntIndex); + JGeometry::TVec3 pos; + pos.x = jointMtx[0][3]; + pos.y = jointMtx[1][3]; + pos.z = jointMtx[2][3]; + + Mtx mtx; + MsMtxSetRotRPH(mtx, 0.0f, 0.0f, -90.0f); + MTXConcat(jointMtx, mtx, mtx); + + JPABaseEmitter* emitter; + if (mSpine->getCurrentNerve() == &TNerveHanaSamboWait::theNerve()) { + emitter = gpMarioParticleManager->emit(0xB2, &pos, 0, nullptr); + mtx[1][3] += 200.0f; + } else { + emitter = gpMarioParticleManager->emit(0xB3, &pos, 0, nullptr); + + JGeometry::TVec3 offset(0.0f, 0.0f, 200.0f); + Mtx rot; + MsMtxSetRotRPH(rot, mRotation.x, mRotation.y, mRotation.z); + MTXMultVec(rot, &offset, &offset); + mtx[0][3] += offset.x; + mtx[1][3] += offset.y; + mtx[2][3] += offset.z; + } + + if (emitter) + emitter->setGlobalSRTMatrix(mtx); +} + +void THanaSambo::initFlower() { } + +DEFINE_NERVE(TNerveHanaSamboAppear, TLiveActor) { return false; } + +DEFINE_NERVE(TNerveHanaSamboWait, TLiveActor) { return false; } + +DEFINE_NERVE(TNerveHanaSamboAttack, TLiveActor) +{ + THanaSambo* self = (THanaSambo*)spine->getBody(); + + if (spine->getTime() == 0) { + self->setAttackAnm(); + } else if (self->checkCurAnmEnd(0)) { + if (self->isBckAnm(3)) { + self->createPollen(); + SMSGetMSound()->startSoundActor(MSD_SE_EN_SAMBO_ATTACK, + &self->mPosition, 0, nullptr, 0, 4); + + self->setBckAnm(1); + } else if (self->isBckAnm(1)) { + if (spine->getTime() > self->unk198->mSLAttackingTime.get() + && !self->unsetUnk165()) + self->setBckAnm(2); + else + self->setBckAnm(1); + } else { + spine->pushAfterCurrent(&TNerveHanaSamboWait::theNerve()); + return true; + } + } + + return false; +} + +DEFINE_NERVE(TNerveHanaSamboHide, TLiveActor) { return false; } + +DEFINE_NERVE(TNerveHanaSamboDie, TLiveActor) +{ + THanaSambo* self = (THanaSambo*)spine->getBody(); + + if (spine->getTime() == 0) { + self->onHitFlag(HIT_FLAG_NO_COLLISION); + self->setDeadAnm(); + } else if (self->checkCurAnmEnd(0) || spine->getTime() > 300) { + static int jIndexTable[] = { 1, 3, 4, 5 }; + + for (int i = 0; i < 4; ++i) { + MtxPtr mtx + = self->getMActor()->getModel()->getAnmMtx(jIndexTable[i]); + self->unk1B4[i].set(mtx[0][3], mtx[1][3], mtx[2][3]); + + if (JPABaseEmitter* emitter = gpMarioParticleManager->emit( + PARTICLE_MS_ENM_DISAP_A, &self->unk1B4[i], 0, nullptr)) + emitter->setGlobalScale(self->mScaling); + + if (JPABaseEmitter* emitter = gpMarioParticleManager->emit( + PARTICLE_MS_ENM_DISAP_B, &self->unk1B4[i], 0, nullptr)) + emitter->setGlobalScale(self->mScaling); + } + + self->onLiveFlag(LIVE_FLAG_DEAD); + self->onLiveFlag(LIVE_FLAG_UNK8); + self->offLiveFlag(LIVE_FLAG_HIDDEN); + self->offLiveFlag(TSmallEnemy::LIVE_FLAG_MELT_ON_DEATH); + self->mHolder = nullptr; + self->stopAnmSound(); + self->onHitFlag(HIT_FLAG_NO_COLLISION); + spine->reset(); + spine->setNext(&TNerveSmallEnemyDie::theNerve()); + spine->pushAfterCurrent(spine->getDefault()); + self->genRandomItem(); + } + + return false; +} + +DEFINE_NERVE(TNerveHanaSamboFreeze, TLiveActor) +{ + THanaSambo* self = (THanaSambo*)spine->getBody(); + + if (spine->getTime() == 0) + self->setBckAnm(5); + + if (self->checkCurAnmEnd(0)) { + if (self->isBckAnm(5)) { + if (self->unsetUnk165()) + self->setBckAnm(8); + } else if (self->unsetUnk165()) { + self->setBckAnm(8); + } else { + return true; + } + } + + return false; +} + +static int SamboHeadRollCallback(J3DNode* param_1, int param_2) { return 0; } + +// TODO: default values are placeholders; names and offsets are from the object. +TSamboHeadSaveLoadParams::TSamboHeadSaveLoadParams(const char* param_1) + : TWalkerEnemyParams(param_1) + , PARAM_INIT(mSLAppearDist, 0.0f) + , PARAM_INIT(mSLHideDist, 0.0f) + , PARAM_INIT(mSLMoveDist, 0.0f) + , PARAM_INIT(mSLMoveGravity, 0.0f) + , PARAM_INIT(mSLJumpSp, 0.0f) + , PARAM_INIT(mSLJumpPrepareTime, 0) + , PARAM_INIT(mSLHitJumpSpXZ, 0.0f) + , PARAM_INIT(mSLHitJumpSpY, 0.0f) + , PARAM_INIT(mSLHitJumpGravity, 0.0f) + , PARAM_INIT(mSLHitJumpSpRateXZ, 0.0f) + , PARAM_INIT(mSLHitJumpSpRateY, 0.0f) + , PARAM_INIT(mSLJumpAngY, 0.0f) +{ + TParams::load(mPrmPath); +} + +u8 TSamboHead::mBodyJntIndex; + +static TSamboHead* gpCurSamboHead; + +TSamboHeadManager::TSamboHeadManager(const char* param_1) + : TSmallEnemyManager(param_1) +{ + gpCurSamboHead = nullptr; +} + +void TSamboHeadManager::load(JSUMemoryInputStream& param_1) { } + +void TSamboHeadManager::createModelData() +{ + static TModelDataLoadEntry entry[] = { + { "samboHead.bmd", 0x10220000, 0 }, + { nullptr, 0, 0 }, + }; + createModelDataArray(entry); +} + +TSpineEnemy* TSamboHeadManager::createEnemyInstance() +{ + return new TSamboHead("サンボヘッド"); +} + +TSamboHead::TSamboHead(const char* param_1) + : TWalkerEnemy(param_1) + , unk194(nullptr) + , unk198(0) + , unk19C(0) + , unk1AC(0.0f) + , unk1B0(0) +{ +} + +void TSamboHead::load(JSUMemoryInputStream& param_1) +{ + TSmallEnemy::load(param_1); + reset(); + setGoalPathMario(); +} + +void TSamboHead::init(TLiveManager* param_1) +{ + TWalkerEnemy::init(param_1); + mActorType = 0x1000001B; + unk150 = 0x11; + unk194 = getSaveParam(); + mSpine->initWith(&TNerveSamboHeadHide::theNerve()); + setGoalPathMario(); + mMActor->setJointCallback(mBodyJntIndex, SamboHeadRollCallback); +} + +void TSamboHead::setMActorAndKeeper() +{ + mMActorKeeper = new TMActorKeeper(mManager, 1); + mMActor = mMActorKeeper->createMActor("samboHead.bmd", 3); +} + +void TSamboHead::reset() +{ + gpCurSamboHead = this; + TWalkerEnemy::reset(); + unk165 = false; + unk1B0 = 0; + unk19C = 0; + unk1AC = 0.0f; + offLiveFlag(LIVE_FLAG_UNK8); +} + +void TSamboHead::kill() +{ + mHitPoints = 1; + if (mSpine->getCurrentNerve() != &TNerveSmallEnemyDie::theNerve()) { + mSpine->reset(); + mSpine->setNext(&TNerveSmallEnemyDie::theNerve()); + mSpine->pushAfterCurrent(&TNerveSmallEnemyDie::theNerve()); + } + onLiveFlag(LIVE_FLAG_UNK40); +} + +void TSamboHead::behaveToWater(THitActor* param_1) { } + +void TSamboHead::attackToMario() +{ + sendAttackMsgToMario(); + + if (isAirborne()) { + JGeometry::TVec3 velocity(mPosition.x - gpMarioPos->x, 10.0f, + mPosition.z - gpMarioPos->z); + MsVECNormalize(&velocity, &velocity); + velocity.scale(8.0f); + setVelocity(velocity); + } else if (mSpine->getCurrentNerve() + == &TNerveSamboHeadAttack::theNerve()) { + mSpine->pushNerve(&TNerveSmallEnemyFreeze::theNerve()); + } +} + +f32 TSamboHead::getGravityY() const +{ + f32 gravity = mGravity; + + if (mSpine->getCurrentNerve() == &TNerveSamboHeadAttack::theNerve()) + gravity = ((TSamboHeadSaveLoadParams*)unk194)->mSLMoveGravity.get(); + + if (mSpine->getCurrentNerve() == &TNerveSamboHeadHitWater::theNerve()) + gravity = ((TSamboHeadSaveLoadParams*)unk194)->mSLHitJumpGravity.get(); + + return gravity; +} + +void TSamboHead::initFlower() { } + +void TSamboHead::setDeadAnm() { setBckAnm(3); } + +void TSamboHead::setAfterDeadEffect() +{ + JGeometry::TVec3 scale(1.5f); + + if (isBckAnm(1)) { + if (JPABaseEmitter* emitter = gpMarioParticleManager->emit( + PARTICLE_MS_ENM_DISAP_A_W, &mPosition, 0, nullptr)) + emitter->setGlobalScale(scale); + } else { + if (JPABaseEmitter* emitter = gpMarioParticleManager->emit( + PARTICLE_MS_ENM_DISAP_A, &mPosition, 0, nullptr)) + emitter->setGlobalScale(scale); + } + + if (JPABaseEmitter* emitter = gpMarioParticleManager->emit( + PARTICLE_MS_ENM_DISAP_B, &mPosition, 0, nullptr)) + emitter->setGlobalScale(scale); + + if (gpMSound->gateCheck(MSD_SE_EN_COMMON_SMOKE)) + MSoundSESystem::MSoundSE::startSoundActor(MSD_SE_EN_COMMON_SMOKE, + &mPosition, 0, nullptr, 0, 4); +} + +void TSamboHead::setCrashAnm() { } + +void TSamboHead::calcRootMatrix() +{ + gpCurSamboHead = this; + TSpineEnemy::calcRootMatrix(); +} + +void TSamboHead::genEventCoin() { } + +bool TSamboHead::isUseCallBack() { return false; } + +static const char* sambohead_bastable[] = { + "/scene/sambohead/bas/flower_shoot.bas", + "/scene/sambohead/bas/samboHead_crash.bas", + "/scene/sambohead/bas/samboHead_dance.bas", + "/scene/sambohead/bas/samboHead_down.bas", + "/scene/sambohead/bas/samboHead_Fhide.bas", + "/scene/sambohead/bas/samboHead_hit.bas", + "/scene/sambohead/bas/samboHead_hit_end.bas", + "/scene/sambohead/bas/samboHead_jump_end.bas", + "/scene/sambohead/bas/samboHead_jump_start.bas", + 0, + "/scene/sambohead/bas/samboHead_set.bas", + "/scene/sambohead/bas/samboHead_turn.bas", + 0, +}; + +const char** TSamboHead::getBasNameTable() const { return sambohead_bastable; } + +DEFINE_NERVE(TNerveSamboHeadAppear, TLiveActor) { return false; } + +DEFINE_NERVE(TNerveSamboHeadAttack, TLiveActor) { return false; } + +DEFINE_NERVE(TNerveSamboHeadHide, TLiveActor) { return false; } + +DEFINE_NERVE(TNerveSamboHeadHitWater, TLiveActor) { return false; } + +DEFINE_NERVE(TNerveSamboHeadRecoverWater, TLiveActor) +{ + TSamboHead* self = static_cast(spine->getBody()); + if (spine->getTime() == 0) + self->setBckAnm(12); + + self->unk1AC *= 0.99f; + if (self->checkCurAnmEnd(0) && self->unk1AC < 1.0f) + return true; + return false; +} + +DEFINE_NERVE(TNerveSamboHeadHitWall, TLiveActor) { return false; } From 58935ee02514326a50357c8495b0f3bc5e47e01b Mon Sep 17 00:00:00 2001 From: gitRasheed Date: Wed, 16 Sep 2026 22:43:52 +0100 Subject: [PATCH 02/13] Enemy/hanasambo: apply the review, real param defaults, fill the remaining stubs Existing inlines everywhere the review asked (sound, defaults omitted, named particles, >>), the two params ctors carry the defaults the manager loads store, and the eighteen stub bodies are written from the target; nine of the UNUSED helpers land at the map's size. --- include/Enemy/HanaSambo.hpp | 50 +- include/MoveBG/Item.hpp | 2 +- include/System/Particles.hpp | 4 + src/Enemy/hanasambo.cpp | 883 ++++++++++++++++++++++++++++++++--- 4 files changed, 837 insertions(+), 102 deletions(-) diff --git a/include/Enemy/HanaSambo.hpp b/include/Enemy/HanaSambo.hpp index f797b53cb..f01f84d31 100644 --- a/include/Enemy/HanaSambo.hpp +++ b/include/Enemy/HanaSambo.hpp @@ -69,9 +69,9 @@ class TSamboHead : public TWalkerEnemy { public: /* 0x194 */ void* unk194; - /* 0x198 */ s32 unk198; + /* 0x198 */ TSamboFlower* unk198; /* 0x19C */ s32 unk19C; - /* 0x1A0 */ char unk1A0[0xC]; + /* 0x1A0 */ JGeometry::TVec3 unk1A0; /* 0x1AC */ f32 unk1AC; /* 0x1B0 */ u8 unk1B0; }; @@ -148,10 +148,10 @@ class THanaSambo : public TSmallEnemy { static u8 mPollenJntIndex; public: - /* 0x194 */ THitActor* unk194; + /* 0x194 */ THanaSamboHead* unk194; /* 0x198 */ THanaSamboSaveLoadParams* unk198; /* 0x19C */ JGeometry::TVec3 unk19C; - /* 0x1A8 */ s32 unk1A8; + /* 0x1A8 */ TSamboFlower* unk1A8; /* 0x1AC */ class TMBindShadowBody* unk1AC; /* 0x1B0 */ u8 unk1B0; /* 0x1B4 */ JGeometry::TVec3 unk1B4[4]; @@ -159,7 +159,11 @@ class THanaSambo : public TSmallEnemy { class THanaSamboHead : public THitActor { public: - THanaSamboHead(); // TODO: constructor not in mario.MAP for this TU + THanaSamboHead() + : THitActor("ハナサンボ頭あたり") + { + } + virtual BOOL receiveMessage(THitActor*, u32); void kill(); @@ -219,7 +223,7 @@ class TSamboFlower : public TSpineEnemy { /* 0x15C */ s32 unk15C; /* 0x160 */ u8 unk160; /* 0x161 */ char unk161[0x3]; - /* 0x164 */ TSamboFlowerCoinUnit* unk164; + /* 0x164 */ s32* unk164; /* 0x168 */ class TMapObjBase* unk168; /* 0x16C */ TSpineEnemyParams* unk16C; }; @@ -279,40 +283,30 @@ class TSamboLeaf : public JDrama::TViewObj { void generate(JGeometry::TVec3&); public: - /* 0xC */ char unkC[0x4]; - /* 0x10 */ void* unk10; - /* 0x14 */ f32 unk14; - /* 0x18 */ f32 unk18; - /* 0x1C */ f32 unk1C; - /* 0x20 */ char unk20[0x4]; - /* 0x24 */ f32 unk24; - /* 0x28 */ char unk28[0x4]; - /* 0x2C */ s32 unk2C; - /* 0x30 */ s32 unk30; - /* 0x34 */ s32 unk34; - /* 0x38 */ f32 unk38; - /* 0x3C */ f32 unk3C; - /* 0x40 */ f32 unk40; + /* 0x10 */ class SDLModel* unk10; + /* 0x14 */ JGeometry::TVec3 unk14; + /* 0x20 */ JGeometry::TVec3 unk20; + /* 0x2C */ JGeometry::TVec3 unk2C; + /* 0x38 */ JGeometry::TVec3 unk38; /* 0x44 */ u8 unk44; /* 0x45 */ char unk45[0x3]; - /* 0x48 */ void* unk48; + /* 0x48 */ TSamboFlowerManager* unk48; }; class TSamboFlowerCoinUnit { public: TSamboFlowerCoinUnit(int); - bool checkGenCoin(); + void checkGenCoin(); void add(TSamboFlower*); public: - /* 0x0 */ s32 unk0; - /* 0x4 */ s32 unk4; - /* 0x8 */ s32 unk8; - /* 0xC */ s32 unkC; + /* 0x0 */ TSamboFlower** unk0; + /* 0x4 */ JGeometry::TVec3 unk4; /* 0x10 */ s32 unk10; - /* 0x14 */ char unk14[0x4]; - /* 0x18 */ s32 unk18; + /* 0x14 */ s32 unk14; + /* 0x18 */ class TFlowerCoin* unk18; + /* 0x1C */ s32 unk1C; }; #endif // ENEMY_HANASAMBO_HPP diff --git a/include/MoveBG/Item.hpp b/include/MoveBG/Item.hpp index 0b28b53e8..9a228c411 100644 --- a/include/MoveBG/Item.hpp +++ b/include/MoveBG/Item.hpp @@ -61,7 +61,7 @@ class TFlowerCoin : public TCoin { virtual void load(JSUMemoryInputStream&); public: - /* 0x158 */ u32 unk158; + /* 0x158 */ s32 unk158; }; class TCoinEmpty : public TCoin { diff --git a/include/System/Particles.hpp b/include/System/Particles.hpp index 9359f26bd..ab5a7559d 100644 --- a/include/System/Particles.hpp +++ b/include/System/Particles.hpp @@ -144,8 +144,12 @@ enum E_SMS_EFFECT_ONETIME_NORMAL /* 0 */ { PARTICLE_MS_POPO_BOMB_B = 0xA2, GATEKEEPER_JPA_MS_GKPA_DEAD = 0xA7, GATEKEEPER_JPA_MS_GKPA_DEADSMOKE = 0xA8, + PARTICLE_MS_SMB_KAFUN_OW = 0xB2, + PARTICLE_MS_SMB_KAFUN_OA = 0xB3, PARTICLE_MS_SMB_AP_ROCK = 0xB6, PARTICLE_MS_SMB_AP_SMOKE = 0xB7, + PARTICLE_MS_SMB_HD_ROCK = 0xB8, + PARTICLE_MS_SMB_HD_SMOKE = 0xB9, PARTICLE_MS_GESO_OSENHIT_A = 0xBC, PARTICLE_MS_GESO_OSENHIT_B = 0xBD, PARTICLE_MS_POI_DEAD = 0xC0, diff --git a/src/Enemy/hanasambo.cpp b/src/Enemy/hanasambo.cpp index 98a30c970..2421f2554 100644 --- a/src/Enemy/hanasambo.cpp +++ b/src/Enemy/hanasambo.cpp @@ -5,10 +5,13 @@ #include #include #include +#include #include +#include #include #include #include +#include #include #include #include @@ -24,7 +27,10 @@ #include #include #include +#include #include +#include +#include #include #include #include @@ -33,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -45,19 +52,144 @@ #include #include -TSamboFlowerCoinUnit::TSamboFlowerCoinUnit(int param_1) { } +TSamboFlowerCoinUnit::TSamboFlowerCoinUnit(int param_1) + : unk0(nullptr) + , unk10(0) + , unk14(param_1) + , unk18(nullptr) + , unk1C(param_1) +{ + unk0 = new TSamboFlower*[param_1]; +} + +void TSamboFlowerCoinUnit::add(TSamboFlower* param_1) +{ + if (unk10 < unk14) { + unk0[unk10] = param_1; + param_1->unk164 = &unk1C; + unk10++; + } +} + +void TSamboFlowerCoinUnit::checkGenCoin() +{ + if (!unk18) + return; + + bool bloomed = true; + for (int i = 0; i < unk10; ++i) { + bool bloomEnd = unk0[i]->isBloomEnd(); + if (!bloomEnd) + bloomed = false; + } + + if (!bloomed) + return; + + int total = 0; + for (int i = 0; i < unk10; ++i) { + TSamboFlower* flower = unk0[i]; + if (flower->unk168) + total++; + + flower->unk160 = false; + } + + if (total > 0) { + Mtx mtx; + int spawned = 0; + for (int i = 0; i < unk10; ++i) { + if (!unk0[i]->unk168) + continue; + + f32 rate = (f32)spawned / (f32)total; -void TSamboFlowerCoinUnit::add(TSamboFlower* param_1) { } + JGeometry::TVec3 offset( + 0.0f, 0.0f, + ((TSamboFlowerSaveLoadParams*)unk0[i]->unk16C) + ->mSLCoinCircleR.get()); -bool TSamboFlowerCoinUnit::checkGenCoin() { return false; } + MsMtxSetRotY(mtx, 360.0f * rate); + MTXMultVec(mtx, &offset, &offset); + + TMapObjBase* coin = unk0[i]->unk168; + if (coin->isActorType(0x2000000E)) + coin = gpItemManager->makeObjAppear(0x2000000E); + + if (coin) { + coin->appear(); + + JGeometry::TVec3 pos = unk4; + pos += offset; + coin->mPosition = pos; + + MsVECNormalize(&offset, &offset); + + TSamboFlowerSaveLoadParams* prm + = (TSamboFlowerSaveLoadParams*)unk0[i]->unk16C; + coin->mVelocity.set(offset.x * prm->mSLCoinVelocityXZ.get(), + 8.0f * rate + prm->mSLCoinVelocityY.get(), + offset.z * prm->mSLCoinVelocityXZ.get()); + coin->offLiveFlag(LIVE_FLAG_UNK10); + spawned++; + } + } + + SMSGetMSound()->startSoundSystemSE(MSD_SE_SY_COIN_APPEAR, spawned, + nullptr, 0); + } + + unk18 = nullptr; +} TSamboLeaf::TSamboLeaf(TSamboFlowerManager* param_1, SDLModelData* param_2, const char* param_3) : JDrama::TViewObj(param_3) + , unk10(nullptr) + , unk44(0) + , unk48(param_1) { + unk10 = new SDLModel(param_2, 3, 1); } -void TSamboLeaf::perform(u32 param_1, JDrama::TGraphics* param_2) { } +void TSamboLeaf::perform(u32 param_1, JDrama::TGraphics* param_2) +{ + if (!unk44) + return; + + if (param_1 & CUE_MOVE) { + unk14 += unk38; + + if (unk38.y > -20.0f) + unk38.y -= ((TSamboFlowerSaveLoadParams*)unk48->unk38) + ->mSLLeafGravity.get(); + + const TBGCheckData* ground; + if (unk14.y + < gpMap->checkGround(unk14.x, 20.0f + unk14.y, unk14.z, &ground)) + unk44 = false; + } + + if (param_1 & CUE_CALC_ANIM) { + Mtx mtx; + MsMtxSetXYZRPH(mtx, unk14.x, unk14.y, unk14.z, 0.0f, unk20.y, 0.0f); + + const JGeometry::TVec3& rot = MsGetRotFromZaxis(unk38); + Mtx rotMtx; + MsMtxSetRotZ(rotMtx, -rot.x); + MTXConcat(mtx, rotMtx, mtx); + + unk10->setBaseTRMtx(mtx); + unk10->setBaseScale(unk2C); + unk10->calc(); + } + + if (param_1 & CUE_CALC_VIEW) + unk10->viewCalc(); + + if (param_1 & CUE_ENTRY) + unk10->entry(); +} void TSamboLeaf::generate(JGeometry::TVec3& param_1) { } @@ -102,12 +234,68 @@ TSpineEnemy* TSamboFlowerManager::createEnemyInstance() return new TSamboFlower("サンボフラワー"); } -void TSamboFlowerManager::loadAfter() { } +void TSamboFlowerManager::loadAfter() +{ + void* leafRes + = JKRFileLoader::getGlbResource("/scene/samboflower/leaf.bmd"); + SDLModelData* leafData + = new SDLModelData(J3DModelLoaderDataBase::load(leafRes, 0x10210000)); + + unk60 = new TSamboLeaf*[0x12]; + for (int i = 0; i < 0x12; i++) + unk60[i] = new TSamboLeaf(this, leafData, "サンボリーフ"); + + unk58 = 0; + for (int i = 0; i < gpItemManager->getObjNum(); i++) { + if (strstr(gpItemManager->getObj(i)->getName(), "コイン(フラワー用)")) + unk58++; + } + + unk54 = new TSamboFlowerCoinUnit*[unk58]; + + int* counts = new int[unk58]; + for (int i = 0; i < unk58; i++) + counts[i] = 0; + + for (int i = 0; i < getObjNum(); i++) { + if (strstr(getObj(i)->getName(), "フラワー(コイン用)")) { + TSamboFlower* flower = (TSamboFlower*)getObj(i); + if (flower->unk158 < unk58) + counts[flower->unk158]++; + } + } + + for (int i = 0; i < unk58; i++) + unk54[i] = new TSamboFlowerCoinUnit(counts[i]); + + for (int i = 0; i < gpItemManager->getObjNum(); i++) { + if (strstr(gpItemManager->getObj(i)->getName(), + "コイン(フラワー用)")) { + TFlowerCoin* coin = (TFlowerCoin*)gpItemManager->getObj(i); + int idx = coin->unk158; + if (idx < unk58) { + unk54[idx]->unk18 = coin; + unk54[idx]->unk4 = coin->mPosition; + coin->kill(); + } + } + } + + for (int i = 0; i < getObjNum(); i++) { + if (strstr(getObj(i)->getName(), "フラワー(コイン用)")) { + TSamboFlower* flower = (TSamboFlower*)getObj(i); + if (flower->unk158 < unk58) + unk54[flower->unk158]->add(flower); + } + } + + JDrama::TNameRef::loadAfter(); +} void TSamboFlowerManager::perform(u32 param_1, JDrama::TGraphics* param_2) { if (unk58 > 0 && param_1 & 2) { - for (int i = 0; i < unk58; ++i) + for (int i = 0; i < unk58; i++) unk54[i]->checkGenCoin(); } @@ -120,13 +308,45 @@ void TSamboFlowerManager::perform(u32 param_1, JDrama::TGraphics* param_2) void TSamboFlowerManager::dropLeaf(JGeometry::TVec3& param_1, JGeometry::TVec3& param_2) { + f32 rotY[] = { 0.0f, 120.0f, 240.0f }; + + int dropped = 0; + for (int i = 0; i < 0x12; i++) { + TSamboLeaf* leaf = unk60[i]; + if (!leaf->unk44) { + leaf->unk14 = param_1; + leaf->unk14.y += 10.0f; + leaf->unk44 = true; + + TSamboFlowerSaveLoadParams* prm + = (TSamboFlowerSaveLoadParams*)unk38; + f32 velXZ = prm->mSLLeafVelocityXZ.get(); + f32 velY = prm->mSLLeafVelocityY.get(); + TMsRange speedXZ(velXZ, 1.2f * velXZ); + TMsRange speedY(velY, 1.2f * velY); + + JGeometry::TVec3 velocity(0.0f, speedY.rand(), speedXZ.rand()); + + Mtx mtx; + MsMtxSetRotRPH(mtx, 0.0f, rotY[i], 0.0f); + MTXMultVec(mtx, &velocity, &velocity); + + unk60[i]->unk20.set(0.0f, rotY[i] - 90.0f, 0.0f); + unk60[i]->unk38 = velocity; + unk60[i]->unk2C = param_2; + dropped++; + } + + if (dropped >= 3) + break; + } } void TSamboFlower::load(JSUMemoryInputStream& param_1) { TSpineEnemy::load(param_1); - param_1.read(&unk15C, 4); - param_1.read(&unk158, 4); + param_1 >> unk15C; + param_1 >> unk158; unk160 = true; reset(); offLiveFlag(LIVE_FLAG_UNK800); @@ -138,10 +358,7 @@ void TSamboFlower::loadAfter() if (unk15C < 0) return; - TMapObjBase* obj = TMapObjBaseManager::newAndRegisterObj( - "coin", JGeometry::TVec3(0.0f, 0.0f, 0.0f), - JGeometry::TVec3(0.0f, 0.0f, 0.0f), - JGeometry::TVec3(1.0f, 1.0f, 1.0f)); + TMapObjBase* obj = TMapObjBaseManager::newAndRegisterObj("coin"); if (obj) unk168 = obj; } @@ -189,14 +406,14 @@ BOOL TSamboFlower::receiveMessage(THitActor* param_1, u32 param_2) if (!unk150) { unk150 = true; unk154 = 0; - gpMarioParticleManager->emit(0xB2, &mPosition, 0, nullptr); + gpMarioParticleManager->emit(PARTICLE_MS_SMB_KAFUN_OW, &mPosition, + 0, nullptr); mMActor->setBck("flower_hit"); if (unk160 && unk164) { - unk164->unk0 = unk164->unk0 - 1; - u32 id = MSD_SE_OBJ_FLOWER_OPEN_0 + unk164->unk0; - if (gpMSound->gateCheck(id)) - MSoundSESystem::MSoundSE::startSoundActor(id, &mPosition, 0, - nullptr, 0, 4); + *unk164 = *unk164 - 1; + u32 id = MSD_SE_OBJ_FLOWER_OPEN_0 + *unk164; + SMSGetMSound()->startSoundActor(id, &mPosition, 0, nullptr, 0, + 4); } } return 1; @@ -228,7 +445,7 @@ void TSamboFlower::moveObject() if (getMActor()->checkCurAnm("flower_fwait", 0)) { unk150 = false; if (unk164) - unk164->unk0 = unk164->unk0 + 1; + *unk164 = *unk164 + 1; getMActor()->setBck("flower_hit"); getMActor() @@ -264,24 +481,46 @@ void TSamboFlower::drawObject(JDrama::TGraphics* param_1) mMActor->entry(); } -void TSamboFlower::bloom() { } +void TSamboFlower::bloom() +{ + unk150 = true; + unk154 = 0; + gpMarioParticleManager->emit(PARTICLE_MS_SMB_KAFUN_OW, &mPosition, 0, + nullptr); + mMActor->setBck("flower_hit"); + if (unk160 && unk164) { + *unk164 = *unk164 - 1; + u32 id = MSD_SE_OBJ_FLOWER_OPEN_0 + *unk164; + SMSGetMSound()->startSoundActor(id, &mPosition, 0, nullptr, 0, 4); + } +} + +bool TSamboFlower::isBloomEnd() +{ + if (getMActor()->checkCurAnm("flower_fwait", 0)) + return true; -bool TSamboFlower::isBloomEnd() { return false; } + return false; +} -void TSamboFlower::hide() { } +void TSamboFlower::hide() +{ + onHitFlag(HIT_FLAG_NO_COLLISION); + mMActor->setBck("flower_fwait"); + onLiveFlag(LIVE_FLAG_DEAD); +} -// TODO: default values are placeholders; names and offsets are from the object. THanaSamboSaveLoadParams::THanaSamboSaveLoadParams(const char* param_1) : TSmallEnemyParams(param_1) - , PARAM_INIT(mSLAttackDist, 0.0f) - , PARAM_INIT(mSLAttackInterval, 0) - , PARAM_INIT(mSLHideDist, 0.0f) - , PARAM_INIT(mSLAppearDist, 0.0f) - , PARAM_INIT(mSLAttackingTime, 0) - , PARAM_INIT(mSLHeadAttackRadius, 0.0f) - , PARAM_INIT(mSLHeadAttackHeight, 0.0f) - , PARAM_INIT(mSLHeadDamageRadius, 0.0f) - , PARAM_INIT(mSLHeadDamageHeight, 0.0f) + , PARAM_INIT(mSLAttackDist, 200.0f) + , PARAM_INIT(mSLAttackInterval, 200) + , PARAM_INIT(mSLHideDist, 800.0f) + , PARAM_INIT(mSLAppearDist, 1000.0f) + , PARAM_INIT(mSLAttackingTime, 30) + , PARAM_INIT(mSLHeadAttackRadius, 60.0f) + , PARAM_INIT(mSLHeadAttackHeight, 20.0f) + , PARAM_INIT(mSLHeadDamageRadius, 80.0f) + , PARAM_INIT(mSLHeadDamageHeight, 40.0f) { TParams::load(mPrmPath); } @@ -291,7 +530,11 @@ THanaSamboManager::THanaSamboManager(const char* param_1) { } -void THanaSamboManager::load(JSUMemoryInputStream& param_1) { } +void THanaSamboManager::load(JSUMemoryInputStream& param_1) +{ + TSmallEnemyManager::load(param_1); + unk38 = new THanaSamboSaveLoadParams("/enemy/hanasambo.prm"); +} TSpineEnemy* THanaSamboManager::createEnemyInstance() { @@ -331,7 +574,7 @@ THanaSambo::THanaSambo(const char* param_1) : TSmallEnemy(param_1) , unk194(nullptr) , unk198(0) - , unk1A8(0) + , unk1A8(nullptr) , unk1AC(0) { } @@ -343,7 +586,35 @@ void THanaSambo::load(JSUMemoryInputStream& param_1) setGoalPathMario(); } -void THanaSambo::init(TLiveManager* param_1) { } +void THanaSambo::init(TLiveManager* param_1) +{ + TSmallEnemy::init(param_1); + mActorType = 0x1000001A; + unk150 = 0x11; + unk198 = (THanaSamboSaveLoadParams*)getSaveParam(); + mSpine->initWith(&TNerveHanaSamboHide::theNerve()); + unk1AC = new TMBindShadowBody(this, getModel(), 1.5f); + setGoalPathMario(); + + if (mInstanceIndex == 0) { + // TODO: what this loop did is unknown + for (u8 i = 0; i < getActorKeeper() + ->getMActor("samboD.bmd") + ->getModel() + ->getModelData() + ->getJointNum(); + ++i) { } + } + + unk194 = new THanaSamboHead(); + ((TIdxGroupObj*)JDrama::TNameRefGen::search("敵グループ"))->add(unk194); + unk194->initHitActor(0x1000001B, 2, 0x80000000, + unk198->mSLHeadAttackRadius.get() * mBodyScale, + unk198->mSLHeadAttackHeight.get() * mBodyScale, + unk198->mSLHeadDamageRadius.get() * mBodyScale, + unk198->mSLHeadDamageHeight.get() * mBodyScale); + unk194->unk68 = this; +} void THanaSambo::setMActorAndKeeper() { @@ -487,10 +758,12 @@ void THanaSambo::createPollen() JPABaseEmitter* emitter; if (mSpine->getCurrentNerve() == &TNerveHanaSamboWait::theNerve()) { - emitter = gpMarioParticleManager->emit(0xB2, &pos, 0, nullptr); + emitter = gpMarioParticleManager->emit(PARTICLE_MS_SMB_KAFUN_OW, &pos, + 0, nullptr); mtx[1][3] += 200.0f; } else { - emitter = gpMarioParticleManager->emit(0xB3, &pos, 0, nullptr); + emitter = gpMarioParticleManager->emit(PARTICLE_MS_SMB_KAFUN_OA, &pos, + 0, nullptr); JGeometry::TVec3 offset(0.0f, 0.0f, 200.0f); Mtx rot; @@ -505,11 +778,84 @@ void THanaSambo::createPollen() emitter->setGlobalSRTMatrix(mtx); } -void THanaSambo::initFlower() { } +void THanaSambo::initFlower() +{ + if (!unk1A8) { + unk1A8 = (TSamboFlower*)gpConductor->makeOneEnemyAppear( + mPosition, "サンボフラワーマネージャー", 1); + unk1A8->reset(); + } -DEFINE_NERVE(TNerveHanaSamboAppear, TLiveActor) { return false; } + unk1A8->onLiveFlag(LIVE_FLAG_UNK10); + unk1A8->offLiveFlag(LIVE_FLAG_DEAD); + unk1A8->mPosition = mPosition; + unk1A8->mPosition.y = mGroundHeight; +} -DEFINE_NERVE(TNerveHanaSamboWait, TLiveActor) { return false; } +DEFINE_NERVE(TNerveHanaSamboAppear, TLiveActor) +{ + THanaSambo* self = (THanaSambo*)spine->getBody(); + + if (spine->getTime() == 0) { + self->offLiveFlag(LIVE_FLAG_HIDDEN); + self->offHitFlag(HIT_FLAG_NO_COLLISION); + self->setBckAnm(6); + gpMarioParticleManager->emit(PARTICLE_MS_SMB_AP_ROCK, &self->mPosition, + 0, nullptr); + gpMarioParticleManager->emit(PARTICLE_MS_SMB_AP_SMOKE, &self->mPosition, + 0, nullptr); + self->unk1A8->hide(); + } + + if (self->checkCurAnmEnd(0)) { + spine->pushAfterCurrent(&TNerveHanaSamboWait::theNerve()); + self->setWaitAnm(); + if (gpMarioPos->y < 100.0f + self->mPosition.y) { + self->updateSquareToMario(); + if (self->mDistToMarioSquared + < self->unk198->mSLAttackDist.get() + * self->unk198->mSLAttackDist.get()) + spine->pushAfterCurrent(&TNerveHanaSamboAttack::theNerve()); + } + return true; + } + + self->walkToCurPathNode(0.0f, self->getTurnSpeed() * 3.0f, 0.0f); + return false; +} + +DEFINE_NERVE(TNerveHanaSamboWait, TLiveActor) +{ + THanaSambo* self = (THanaSambo*)spine->getBody(); + + if (spine->getTime() == 0) + self->setWaitAnm(); + + if (!self->checkLiveFlag(LIVE_FLAG_CLIPPED_OUT) + && self->getMActor()->getFrameCtrl(ANM_TYPE_BCK)->checkPass(16.0f)) + self->createPollen(); + + if (spine->getTime() > self->unk198->mSLAttackInterval.get() + && gpMarioPos->y < 100.0f + self->mPosition.y) { + self->updateSquareToMario(); + if (self->mDistToMarioSquared + < self->unk198->mSLAttackDist.get() + * self->unk198->mSLAttackDist.get()) { + spine->pushAfterCurrent(&TNerveHanaSamboAttack::theNerve()); + return true; + } + } + + self->updateSquareToMario(); + if (self->mDistToMarioSquared > self->unk198->mSLAppearDist.get() + * self->unk198->mSLAppearDist.get()) { + spine->pushAfterCurrent(&TNerveHanaSamboHide::theNerve()); + return true; + } + + self->walkToCurPathNode(0.0f, self->getTurnSpeed(), 0.0f); + return false; +} DEFINE_NERVE(TNerveHanaSamboAttack, TLiveActor) { @@ -539,7 +885,38 @@ DEFINE_NERVE(TNerveHanaSamboAttack, TLiveActor) return false; } -DEFINE_NERVE(TNerveHanaSamboHide, TLiveActor) { return false; } +DEFINE_NERVE(TNerveHanaSamboHide, TLiveActor) +{ + THanaSambo* self = (THanaSambo*)spine->getBody(); + + if (spine->getTime() == 0) { + self->setBckAnm(4); + gpMarioParticleManager->emit(PARTICLE_MS_SMB_HD_ROCK, &self->mPosition, + 0, nullptr); + gpMarioParticleManager->emit(PARTICLE_MS_SMB_HD_SMOKE, &self->mPosition, + 0, nullptr); + } + + if (spine->getTime() == 75) + self->initFlower(); + + if (self->checkCurAnmEnd(0)) { + self->initFlower(); + self->onHitFlag(HIT_FLAG_NO_COLLISION); + self->setBckAnm(6); + self->getMActor()->setFrameRate(0.0f, ANM_TYPE_BCK); + self->onLiveFlag(LIVE_FLAG_HIDDEN); + } + + self->updateSquareToMario(); + if (self->mDistToMarioSquared + < self->unk198->mSLHideDist.get() * self->unk198->mSLHideDist.get()) { + spine->pushAfterCurrent(&TNerveHanaSamboAppear::theNerve()); + return true; + } + + return false; +} DEFINE_NERVE(TNerveHanaSamboDie, TLiveActor) { @@ -602,38 +979,83 @@ DEFINE_NERVE(TNerveHanaSamboFreeze, TLiveActor) return false; } -static int SamboHeadRollCallback(J3DNode* param_1, int param_2) { return 0; } +u8 TSamboHead::mBodyJntIndex; + +static TSamboHead* gpCurSamboHead; + +static int SamboHeadRollCallback(J3DNode* param_1, int param_2) +{ + if (param_2 == 0) { + if (gpCurSamboHead == nullptr || !gpCurSamboHead->isUseCallBack()) + return true; + + J3DJoint* joint = (J3DJoint*)param_1; + MtxPtr anmMtx + = gpCurSamboHead->getModel()->getAnmMtx(joint->getJntNo()); + + JGeometry::TVec3 velocity = gpCurSamboHead->mVelocity; + if (0.0f == velocity.x && 0.0f == velocity.z) + velocity.x = 0.001f; + + JGeometry::TVec3 side; + JGeometry::TVec3 up(0.0f, 1.0f, 0.0f); + VECCrossProduct(&up, &velocity, &side); + + JGeometry::TVec3 zAxis(anmMtx[0][2], anmMtx[1][2], anmMtx[2][2]); + JGeometry::TVec3 yAxis(anmMtx[0][1], anmMtx[1][1], anmMtx[2][1]); + JGeometry::TVec3 xAxis(anmMtx[0][0], anmMtx[1][0], anmMtx[2][0]); + + f32 rateZ = 0.0f; + if (0.0f != zAxis.squared()) + rateZ = side.dot(zAxis) / zAxis.squared(); + + f32 rateY = 0.0f; + if (0.0f != yAxis.squared()) + rateY = side.dot(yAxis) / yAxis.squared(); + + f32 rateX = 0.0f; + if (0.0f != xAxis.squared()) + rateX = side.dot(xAxis) / xAxis.squared(); + + JGeometry::TVec3 axis(rateX, rateY, rateZ); + + Mtx local_100; + MTXRotAxisRad(local_100, &axis, 0.017453292f * gpCurSamboHead->unk1AC); + MTXConcat(anmMtx, local_100, anmMtx); + MTXConcat(J3DSys::mCurrentMtx, local_100, J3DSys::mCurrentMtx); + } + return true; +} -// TODO: default values are placeholders; names and offsets are from the object. TSamboHeadSaveLoadParams::TSamboHeadSaveLoadParams(const char* param_1) : TWalkerEnemyParams(param_1) - , PARAM_INIT(mSLAppearDist, 0.0f) - , PARAM_INIT(mSLHideDist, 0.0f) - , PARAM_INIT(mSLMoveDist, 0.0f) - , PARAM_INIT(mSLMoveGravity, 0.0f) - , PARAM_INIT(mSLJumpSp, 0.0f) - , PARAM_INIT(mSLJumpPrepareTime, 0) - , PARAM_INIT(mSLHitJumpSpXZ, 0.0f) - , PARAM_INIT(mSLHitJumpSpY, 0.0f) - , PARAM_INIT(mSLHitJumpGravity, 0.0f) - , PARAM_INIT(mSLHitJumpSpRateXZ, 0.0f) - , PARAM_INIT(mSLHitJumpSpRateY, 0.0f) - , PARAM_INIT(mSLJumpAngY, 0.0f) + , PARAM_INIT(mSLAppearDist, 800.0f) + , PARAM_INIT(mSLHideDist, 1000.0f) + , PARAM_INIT(mSLMoveDist, 100.0f) + , PARAM_INIT(mSLMoveGravity, 0.1f) + , PARAM_INIT(mSLJumpSp, 10.0f) + , PARAM_INIT(mSLJumpPrepareTime, 20) + , PARAM_INIT(mSLHitJumpSpXZ, 12.0f) + , PARAM_INIT(mSLHitJumpSpY, 10.0f) + , PARAM_INIT(mSLHitJumpGravity, 1.0f) + , PARAM_INIT(mSLHitJumpSpRateXZ, 0.3f) + , PARAM_INIT(mSLHitJumpSpRateY, 0.3f) + , PARAM_INIT(mSLJumpAngY, 30.0f) { TParams::load(mPrmPath); } -u8 TSamboHead::mBodyJntIndex; - -static TSamboHead* gpCurSamboHead; - TSamboHeadManager::TSamboHeadManager(const char* param_1) : TSmallEnemyManager(param_1) { gpCurSamboHead = nullptr; } -void TSamboHeadManager::load(JSUMemoryInputStream& param_1) { } +void TSamboHeadManager::load(JSUMemoryInputStream& param_1) +{ + TSmallEnemyManager::load(param_1); + unk38 = new TSamboHeadSaveLoadParams("/enemy/sambohead.prm"); +} void TSamboHeadManager::createModelData() { @@ -652,7 +1074,7 @@ TSpineEnemy* TSamboHeadManager::createEnemyInstance() TSamboHead::TSamboHead(const char* param_1) : TWalkerEnemy(param_1) , unk194(nullptr) - , unk198(0) + , unk198(nullptr) , unk19C(0) , unk1AC(0.0f) , unk1B0(0) @@ -705,7 +1127,36 @@ void TSamboHead::kill() onLiveFlag(LIVE_FLAG_UNK40); } -void TSamboHead::behaveToWater(THitActor* param_1) { } +void TSamboHead::behaveToWater(THitActor* param_1) +{ + if (mSpine->getCurrentNerve() == &TNerveSamboHeadHide::theNerve()) + return; + + if (mSpine->getCurrentNerve() == &TNerveSamboHeadAppear::theNerve()) + return; + + if (mSpine->getCurrentNerve() == &TNerveSamboHeadHitWall::theNerve() + || mSpine->getCurrentNerve() == &TNerveSmallEnemyDie::theNerve()) + return; + + JGeometry::TVec3 velocity = mLinearVelocity; + velocity.y = 0.0f; + + JGeometry::TVec3 jump(mPosition.x - gpMarioPos->x, 0.0f, + mPosition.z - gpMarioPos->z); + MsVECNormalize(&jump, &jump); + jump.scale(((TSamboHeadSaveLoadParams*)unk194)->mSLHitJumpSpXZ.get()); + jump.y = ((TSamboHeadSaveLoadParams*)unk194)->mSLHitJumpSpY.get(); + + if (mSpine->getCurrentNerve() != &TNerveSamboHeadHitWater::theNerve()) + mSpine->pushNerve(&TNerveSamboHeadHitWater::theNerve()); + else + jump.add(velocity); + + setVelocity(jump); + mPosition.y += 2.0f; + onLiveFlag(LIVE_FLAG_AIRBORNE); +} void TSamboHead::attackToMario() { @@ -736,7 +1187,20 @@ f32 TSamboHead::getGravityY() const return gravity; } -void TSamboHead::initFlower() { } +void TSamboHead::initFlower() +{ + if (!unk198) { + unk198 = (TSamboFlower*)gpConductor->makeOneEnemyAppear( + mPosition, "サンボフラワーマネージャー", 1); + unk198->reset(); + } + + unk198->offHitFlag(HIT_FLAG_NO_COLLISION); + unk198->onLiveFlag(LIVE_FLAG_UNK10); + unk198->offLiveFlag(LIVE_FLAG_DEAD); + unk198->mPosition.y = mGroundHeight; + unk198->mPosition = mPosition; +} void TSamboHead::setDeadAnm() { setBckAnm(3); } @@ -758,9 +1222,8 @@ void TSamboHead::setAfterDeadEffect() PARTICLE_MS_ENM_DISAP_B, &mPosition, 0, nullptr)) emitter->setGlobalScale(scale); - if (gpMSound->gateCheck(MSD_SE_EN_COMMON_SMOKE)) - MSoundSESystem::MSoundSE::startSoundActor(MSD_SE_EN_COMMON_SMOKE, - &mPosition, 0, nullptr, 0, 4); + SMSGetMSound()->startSoundActor(MSD_SE_EN_COMMON_SMOKE, &mPosition, 0, + nullptr, 0, 4); } void TSamboHead::setCrashAnm() { } @@ -771,9 +1234,60 @@ void TSamboHead::calcRootMatrix() TSpineEnemy::calcRootMatrix(); } -void TSamboHead::genEventCoin() { } +void TSamboHead::genEventCoin() +{ + if (isBckAnm(1)) { + for (int i = 0; i < 3; ++i) { + Mtx local_38; + Vec local_2c; + f32 angle = 60.0f * i + (mRotation.y - 60.0f); + MsMtxSetRotY(local_38, angle); + + local_2c.x = 0.0f; + local_2c.y = 0.0f; + local_2c.z = 100.0f; + MTXMultVec(local_38, &local_2c, &local_2c); + + TCoin* coin; + if (i == 1 && mCoin) { + coin = mCoin; + if (coin->isActorType(0x2000000E)) + coin = (TCoin*)gpItemManager->makeObjAppear(0x2000000E); + + if (coin) { + coin->appear(); + coin->mPosition = mPosition; + } + } else { + coin = (TCoin*)gpItemManager->makeObjAppear( + mPosition.x + local_2c.x, mPosition.y, + mPosition.z + local_2c.z, 0x2000000E, true); + } -bool TSamboHead::isUseCallBack() { return false; } + if (coin) { + coin->mPosition.y = mPosition.y; + MsVECNormalize(&local_2c, &local_2c); + coin->mVelocity.set(local_2c.x * 4, + TMsRange(8.0f, 16.0f).rand(), + local_2c.z * 4); + coin->offLiveFlag(LIVE_FLAG_UNK10); + } + } + } else { + TSmallEnemy::genEventCoin(); + } +} + +bool TSamboHead::isUseCallBack() +{ + if (mSpine->getCurrentNerve() == &TNerveSamboHeadAttack::theNerve() + || mSpine->getCurrentNerve() == &TNerveSamboHeadHitWater::theNerve() + || mSpine->getCurrentNerve() + == &TNerveSamboHeadRecoverWater::theNerve()) + return true; + + return false; +} static const char* sambohead_bastable[] = { "/scene/sambohead/bas/flower_shoot.bas", @@ -793,13 +1307,195 @@ static const char* sambohead_bastable[] = { const char** TSamboHead::getBasNameTable() const { return sambohead_bastable; } -DEFINE_NERVE(TNerveSamboHeadAppear, TLiveActor) { return false; } +DEFINE_NERVE(TNerveSamboHeadAppear, TLiveActor) +{ + TSamboHead* self = (TSamboHead*)spine->getBody(); + + if (spine->getTime() == 0) { + self->offLiveFlag(LIVE_FLAG_HIDDEN); + self->offHitFlag(HIT_FLAG_NO_COLLISION); + if (self->unk198->unk150) { + self->unk198->bloom(); + self->setBckAnm(10); + } else { + self->setBckAnm(10); + } + gpMarioParticleManager->emit(PARTICLE_MS_SMB_AP_ROCK, &self->mPosition, + 0, nullptr); + gpMarioParticleManager->emit(PARTICLE_MS_SMB_AP_SMOKE, &self->mPosition, + 0, nullptr); + self->unk198->hide(); + } + + if (spine->getTime() == 20) + ((TSamboFlowerManager*)self->unk198->mManager) + ->dropLeaf(self->mPosition, self->mScaling); -DEFINE_NERVE(TNerveSamboHeadAttack, TLiveActor) { return false; } + if (self->checkCurAnmEnd(0)) { + self->setBckAnm(12); + spine->pushAfterCurrent(&TNerveSamboHeadAttack::theNerve()); + return true; + } -DEFINE_NERVE(TNerveSamboHeadHide, TLiveActor) { return false; } + return false; +} -DEFINE_NERVE(TNerveSamboHeadHitWater, TLiveActor) { return false; } +DEFINE_NERVE(TNerveSamboHeadAttack, TLiveActor) +{ + TSamboHead* self = (TSamboHead*)spine->getBody(); + + if (!self->isAirborne()) { + if (self->unk19C > ((TSamboHeadSaveLoadParams*)self->unk194) + ->mSLJumpPrepareTime.get() + && self->checkCurAnmEnd(0)) { + self->unk19C = 0; + self->updateSquareToMario(); + + JGeometry::TVec3 goal = self->getUnk104().getPoint(); + goal.set(gpMarioPos->x - self->mPosition.x, 0.0f, + gpMarioPos->z - self->mPosition.z); + if (goal.x == 0.0f && goal.y == 0.0f && goal.z == 0.0f) + goal.x += 1.0f; + + MsVECNormalize(&goal, &goal); + + f32 moveDist + = ((TSamboHeadSaveLoadParams*)self->unk194)->mSLMoveDist.get(); + goal.x = goal.x * moveDist + self->mPosition.x; + goal.z = goal.z * moveDist + self->mPosition.z; + goal.y = self->mPosition.y; + + f32 jumpSp + = ((TSamboHeadSaveLoadParams*)self->unk194)->mSLJumpSp.get(); + self->setVelocity( + self->calcVelocityToJumpToY(goal, jumpSp, self->getGravityY())); + self->mPosition.y += 2.0f; + self->onLiveFlag(LIVE_FLAG_AIRBORNE); + self->setBckAnm(8); + } else { + self->unk19C++; + } + + if (self->checkCurAnmEnd(0) && self->isBckAnm(7)) + self->setBckAnm(12); + + self->getMActor()->setFrameRate(SMSGetAnmFrameRate(), ANM_TYPE_BCK); + } else { + JGeometry::TVec3 velocity = self->mLinearVelocity; + if (velocity.y < 0.0f && self->isBckAnm(8)) { + self->setBckAnm(7); + self->getMActor()->setFrameRate(0.0f, ANM_TYPE_BCK); + } + } + + if (self->mPosition.y > 30.0f + self->mGroundHeight) { + f32 limit + = ((TSamboHeadSaveLoadParams*)self->unk194)->mSLJumpAngY.get(); + JGeometry::TVec3 velocity = self->mLinearVelocity; + self->unk1AC = MsClamp(MsGetRotFromZaxis(velocity).x, -limit, limit); + } else { + self->unk1AC *= 0.8f; + } + + f32 turnSpeed = self->getTurnSpeed(); + if (self->isAirborne()) + turnSpeed = 5.0f; + + self->walkToCurPathNode(0.0f, turnSpeed, 0.0f); + return false; +} + +DEFINE_NERVE(TNerveSamboHeadHide, TLiveActor) +{ + TSamboHead* self = (TSamboHead*)spine->getBody(); + + if (spine->getTime() == 0) { + self->setBckAnm(4); + self->onHitFlag(HIT_FLAG_NO_COLLISION); + gpMarioParticleManager->emit(PARTICLE_MS_SMB_HD_ROCK, &self->mPosition, + 0, nullptr); + gpMarioParticleManager->emit(PARTICLE_MS_SMB_HD_SMOKE, &self->mPosition, + 0, nullptr); + } else if (self->checkCurAnmEnd(0)) { + self->onLiveFlag(LIVE_FLAG_HIDDEN); + self->setBckAnm(12); + self->initFlower(); + } else if (self->isFindMario(1.0f)) { + self->updateSquareToMario(); + if (self->mDistToMarioSquared + < ((TSamboHeadSaveLoadParams*)self->unk194)->mSLAppearDist.get() + * ((TSamboHeadSaveLoadParams*)self->unk194) + ->mSLAppearDist.get()) { + spine->pushAfterCurrent(&TNerveSamboHeadAppear::theNerve()); + return true; + } + } + + self->walkToCurPathNode(0.0f, self->getTurnSpeed(), 0.0f); + return false; +} + +DEFINE_NERVE(TNerveSamboHeadHitWater, TLiveActor) +{ + TSamboHead* self = (TSamboHead*)spine->getBody(); + + if (spine->getTime() == 0) { + self->setBckAnm(5); + self->unk1A0 = self->mLinearVelocity; + } + + if (self->isHitWallInBound()) { + self->unk1AC = 0.0f; + if (self->unk1B0) + self->mRotation.y += 180.0f; + + spine->reset(); + spine->setNext(&TNerveSamboHeadHitWall::theNerve()); + spine->pushAfterCurrent(&TNerveSamboHeadHitWall::theNerve()); + return true; + } + + f32 limit = ((TSamboHeadSaveLoadParams*)self->unk194)->mSLJumpAngY.get(); + if (self->isBckAnm(6)) { + if (spine->getTime() < 100) + self->unk1AC = MsClamp(self->unk1AC - 3.0f, -limit, limit); + else + self->unk1AC = MsClamp(3.0f + self->unk1AC, -limit, 0.0f); + } else { + self->unk1AC = MsClamp(3.0f + self->unk1AC, -limit, limit); + } + + if (self->isBckAnm(5) && !self->isAirborne()) + self->setBckAnm(7); + + if (self->isBckAnm(6)) { + self->onLiveFlag(LIVE_FLAG_AIRBORNE); + self->mPosition.y = 1.0f + self->mGroundHeight; + self->setVelocity(self->unk1A0); + } + + if (!self->isAirborne()) + self->setBckAnm(6); + + if (self->checkCurAnmEnd(0) && self->isBckAnm(6)) { + f32 rate = ((TSamboHeadSaveLoadParams*)self->unk194) + ->mSLHitJumpSpRateXZ.get(); + self->setBckAnm(6); + self->unk1A0.x = self->unk1A0.x * rate; + self->unk1A0.z = self->unk1A0.z * rate; + self->unk1A0.y = 0.0f; + self->setVelocity(self->unk1A0); + self->mPosition.y = self->mGroundHeight; + self->offLiveFlag(LIVE_FLAG_AIRBORNE); + self->setBckAnm(12); + spine->setNext(&TNerveSamboHeadAttack::theNerve()); + spine->pushAfterCurrent(&TNerveSamboHeadRecoverWater::theNerve()); + return true; + } + + self->walkToCurPathNode(0.0f, self->getTurnSpeed(), 0.0f); + return false; +} DEFINE_NERVE(TNerveSamboHeadRecoverWater, TLiveActor) { @@ -813,4 +1509,45 @@ DEFINE_NERVE(TNerveSamboHeadRecoverWater, TLiveActor) return false; } -DEFINE_NERVE(TNerveSamboHeadHitWall, TLiveActor) { return false; } +DEFINE_NERVE(TNerveSamboHeadHitWall, TLiveActor) +{ + TSamboHead* self = (TSamboHead*)spine->getBody(); + + if (spine->getTime() == 0) { + self->setBckAnm(1); + + JGeometry::TVec3 scale(1.5f); + if (JPABaseEmitter* emitter = gpMarioParticleManager->emitWithRotate( + PARTICLE_MS_ENM_WALLHIT, &self->mPosition, 0, + DEG2SHORTANGLE(self->mRotation.y), 0, 0, nullptr)) + emitter->setGlobalScale(scale); + + if (JPABaseEmitter* emitter = gpMarioParticleManager->emitWithRotate( + PARTICLE_MS_ENM_WALLHIT_O, &self->mPosition, 0, + DEG2SHORTANGLE(self->mRotation.y), 0, 0, nullptr)) { + emitter->setGlobalScale(scale); + SMSSetEmitterPolColor(emitter, 6); + } + } + + int waitTime = ((TSmallEnemyManager*)self->getManager())->unk5C; + if (self->checkCurAnmEnd(0) + && spine->getTime() > waitTime + + self->getMActor() + ->getFrameCtrl(ANM_TYPE_BCK) + ->getEnd()) { + self->onLiveFlag(LIVE_FLAG_DEAD); + self->onLiveFlag(LIVE_FLAG_UNK8); + self->onLiveFlag(LIVE_FLAG_UNK20000); + self->offLiveFlag(TSmallEnemy::LIVE_FLAG_MELT_ON_DEATH); + self->mHolder = nullptr; + self->stopAnmSound(); + spine->reset(); + spine->setNext(&TNerveSmallEnemyDie::theNerve()); + spine->pushAfterCurrent(&TNerveSmallEnemyDie::theNerve()); + self->genRandomItem(); + return true; + } + + return false; +} From 002bbc2a7c4483acd510d764a79eebb1d419d4a0 Mon Sep 17 00:00:00 2001 From: gitRasheed Date: Fri, 25 Sep 2026 20:12:12 +0100 Subject: [PATCH 03/13] Enemy/hanasambo: compound assignments, no parens on a no-arg new --- src/Enemy/hanasambo.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Enemy/hanasambo.cpp b/src/Enemy/hanasambo.cpp index 2421f2554..172989992 100644 --- a/src/Enemy/hanasambo.cpp +++ b/src/Enemy/hanasambo.cpp @@ -410,8 +410,8 @@ BOOL TSamboFlower::receiveMessage(THitActor* param_1, u32 param_2) 0, nullptr); mMActor->setBck("flower_hit"); if (unk160 && unk164) { - *unk164 = *unk164 - 1; - u32 id = MSD_SE_OBJ_FLOWER_OPEN_0 + *unk164; + *unk164 -= 1; + u32 id = MSD_SE_OBJ_FLOWER_OPEN_0 + *unk164; SMSGetMSound()->startSoundActor(id, &mPosition, 0, nullptr, 0, 4); } @@ -445,7 +445,7 @@ void TSamboFlower::moveObject() if (getMActor()->checkCurAnm("flower_fwait", 0)) { unk150 = false; if (unk164) - *unk164 = *unk164 + 1; + *unk164 += 1; getMActor()->setBck("flower_hit"); getMActor() @@ -489,8 +489,8 @@ void TSamboFlower::bloom() nullptr); mMActor->setBck("flower_hit"); if (unk160 && unk164) { - *unk164 = *unk164 - 1; - u32 id = MSD_SE_OBJ_FLOWER_OPEN_0 + *unk164; + *unk164 -= 1; + u32 id = MSD_SE_OBJ_FLOWER_OPEN_0 + *unk164; SMSGetMSound()->startSoundActor(id, &mPosition, 0, nullptr, 0, 4); } } @@ -606,7 +606,7 @@ void THanaSambo::init(TLiveManager* param_1) ++i) { } } - unk194 = new THanaSamboHead(); + unk194 = new THanaSamboHead; ((TIdxGroupObj*)JDrama::TNameRefGen::search("敵グループ"))->add(unk194); unk194->initHitActor(0x1000001B, 2, 0x80000000, unk198->mSLHeadAttackRadius.get() * mBodyScale, @@ -1481,8 +1481,8 @@ DEFINE_NERVE(TNerveSamboHeadHitWater, TLiveActor) f32 rate = ((TSamboHeadSaveLoadParams*)self->unk194) ->mSLHitJumpSpRateXZ.get(); self->setBckAnm(6); - self->unk1A0.x = self->unk1A0.x * rate; - self->unk1A0.z = self->unk1A0.z * rate; + self->unk1A0.x *= rate; + self->unk1A0.z *= rate; self->unk1A0.y = 0.0f; self->setVelocity(self->unk1A0); self->mPosition.y = self->mGroundHeight; From d073f8c93a386ba98f6ea496898812a7a84c8db1 Mon Sep 17 00:00:00 2001 From: gitRasheed Date: Fri, 25 Sep 2026 20:12:31 +0100 Subject: [PATCH 04/13] Enemy/hanasambo: default the actors' names in their constructors --- include/Enemy/HanaSambo.hpp | 11 ++++++----- src/Enemy/hanasambo.cpp | 14 ++++---------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/include/Enemy/HanaSambo.hpp b/include/Enemy/HanaSambo.hpp index f01f84d31..9bff45124 100644 --- a/include/Enemy/HanaSambo.hpp +++ b/include/Enemy/HanaSambo.hpp @@ -46,7 +46,7 @@ DECLARE_NERVE(TNerveSamboHeadAppear, TLiveActor); class TSamboHead : public TWalkerEnemy { public: - TSamboHead(const char*); + TSamboHead(const char* name = "サンボヘッド"); virtual void load(JSUMemoryInputStream&); virtual void init(TLiveManager*); @@ -78,7 +78,7 @@ class TSamboHead : public TWalkerEnemy { class TSamboHeadManager : public TSmallEnemyManager { public: - TSamboHeadManager(const char*); + TSamboHeadManager(const char* name = "サンボヘッドマネージャー"); virtual void load(JSUMemoryInputStream&); virtual void createModelData(); @@ -118,7 +118,7 @@ DECLARE_NERVE(TNerveHanaSamboWait, TLiveActor); class THanaSambo : public TSmallEnemy { public: - THanaSambo(const char*); + THanaSambo(const char* name = "ハナサンボ"); virtual void load(JSUMemoryInputStream&); virtual void perform(u32, JDrama::TGraphics*); @@ -175,7 +175,7 @@ class THanaSamboHead : public THitActor { class THanaSamboManager : public TSmallEnemyManager { public: - THanaSamboManager(const char*); + THanaSamboManager(const char* name = "ハナサンボマネージャー"); virtual void load(JSUMemoryInputStream&); virtual void createModelData(); @@ -276,7 +276,8 @@ class TSamboFlowerSaveLoadParams : public TSpineEnemyParams { class TSamboLeaf : public JDrama::TViewObj { public: - TSamboLeaf(TSamboFlowerManager*, SDLModelData*, const char*); + TSamboLeaf(TSamboFlowerManager*, SDLModelData*, + const char* name = "サンボリーフ"); virtual void perform(u32, JDrama::TGraphics*); diff --git a/src/Enemy/hanasambo.cpp b/src/Enemy/hanasambo.cpp index 172989992..ca456cd07 100644 --- a/src/Enemy/hanasambo.cpp +++ b/src/Enemy/hanasambo.cpp @@ -231,7 +231,7 @@ void TSamboFlowerManager::createModelData() TSpineEnemy* TSamboFlowerManager::createEnemyInstance() { - return new TSamboFlower("サンボフラワー"); + return new TSamboFlower; } void TSamboFlowerManager::loadAfter() @@ -243,7 +243,7 @@ void TSamboFlowerManager::loadAfter() unk60 = new TSamboLeaf*[0x12]; for (int i = 0; i < 0x12; i++) - unk60[i] = new TSamboLeaf(this, leafData, "サンボリーフ"); + unk60[i] = new TSamboLeaf(this, leafData); unk58 = 0; for (int i = 0; i < gpItemManager->getObjNum(); i++) { @@ -536,10 +536,7 @@ void THanaSamboManager::load(JSUMemoryInputStream& param_1) unk38 = new THanaSamboSaveLoadParams("/enemy/hanasambo.prm"); } -TSpineEnemy* THanaSamboManager::createEnemyInstance() -{ - return new THanaSambo("ハナサンボ"); -} +TSpineEnemy* THanaSamboManager::createEnemyInstance() { return new THanaSambo; } void THanaSamboManager::createModelData() { @@ -1066,10 +1063,7 @@ void TSamboHeadManager::createModelData() createModelDataArray(entry); } -TSpineEnemy* TSamboHeadManager::createEnemyInstance() -{ - return new TSamboHead("サンボヘッド"); -} +TSpineEnemy* TSamboHeadManager::createEnemyInstance() { return new TSamboHead; } TSamboHead::TSamboHead(const char* param_1) : TWalkerEnemy(param_1) From ee942574a709efc523366eff1de450770d6d83d0 Mon Sep 17 00:00:00 2001 From: gitRasheed Date: Fri, 25 Sep 2026 20:14:56 +0100 Subject: [PATCH 05/13] Enemy/hanasambo: call bloom, checkHit and generate where they were inlined by hand checkHit, generate and setCrashAnm get their bodies; each compiles to its mario.MAP size. --- include/Enemy/HanaSambo.hpp | 2 +- src/Enemy/hanasambo.cpp | 48 ++++++++++++++++++------------------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/include/Enemy/HanaSambo.hpp b/include/Enemy/HanaSambo.hpp index 9bff45124..9fe7cb6f7 100644 --- a/include/Enemy/HanaSambo.hpp +++ b/include/Enemy/HanaSambo.hpp @@ -167,7 +167,7 @@ class THanaSamboHead : public THitActor { virtual BOOL receiveMessage(THitActor*, u32); void kill(); - bool checkHit(); + void checkHit(); public: /* 0x68 */ THanaSambo* unk68; diff --git a/src/Enemy/hanasambo.cpp b/src/Enemy/hanasambo.cpp index ca456cd07..392d8889b 100644 --- a/src/Enemy/hanasambo.cpp +++ b/src/Enemy/hanasambo.cpp @@ -191,7 +191,12 @@ void TSamboLeaf::perform(u32 param_1, JDrama::TGraphics* param_2) unk10->entry(); } -void TSamboLeaf::generate(JGeometry::TVec3& param_1) { } +void TSamboLeaf::generate(JGeometry::TVec3& param_1) +{ + unk14 = param_1; + unk14.y += 10.0f; + unk44 = true; +} TSamboFlowerSaveLoadParams::TSamboFlowerSaveLoadParams(const char* param_1) : TSpineEnemyParams(param_1) @@ -314,9 +319,7 @@ void TSamboFlowerManager::dropLeaf(JGeometry::TVec3& param_1, for (int i = 0; i < 0x12; i++) { TSamboLeaf* leaf = unk60[i]; if (!leaf->unk44) { - leaf->unk14 = param_1; - leaf->unk14.y += 10.0f; - leaf->unk44 = true; + leaf->generate(param_1); TSamboFlowerSaveLoadParams* prm = (TSamboFlowerSaveLoadParams*)unk38; @@ -403,19 +406,8 @@ void TSamboFlower::setMActorAndKeeper() BOOL TSamboFlower::receiveMessage(THitActor* param_1, u32 param_2) { if (param_2 == HIT_MESSAGE_SPRAYED_BY_WATER) { - if (!unk150) { - unk150 = true; - unk154 = 0; - gpMarioParticleManager->emit(PARTICLE_MS_SMB_KAFUN_OW, &mPosition, - 0, nullptr); - mMActor->setBck("flower_hit"); - if (unk160 && unk164) { - *unk164 -= 1; - u32 id = MSD_SE_OBJ_FLOWER_OPEN_0 + *unk164; - SMSGetMSound()->startSoundActor(id, &mPosition, 0, nullptr, 0, - 4); - } - } + if (!unk150) + bloom(); return 1; } @@ -563,7 +555,13 @@ BOOL THanaSamboHead::receiveMessage(THitActor* param_1, u32 param_2) return 0; } -bool THanaSamboHead::checkHit() { return false; } +void THanaSamboHead::checkHit() +{ + for (int i = 0; i < mColCount; ++i) { + if (mCollisions[i]->isActorType(0x80000001)) + SMS_SendMessageToMario(this, HIT_MESSAGE_ATTACK); + } +} void THanaSamboHead::kill() { } @@ -636,11 +634,7 @@ void THanaSambo::moveObject() unk194->mPosition.z = mtx[2][3]; } - THitActor* head = unk194; - for (int i = 0; i < head->getColNum(); ++i) { - if (head->getCollision(i)->isActorType(0x80000001)) - SMS_SendMessageToMario(head, HIT_MESSAGE_ATTACK); - } + unk194->checkHit(); mPosition.x = unk19C.x; mPosition.z = unk19C.z; @@ -1220,7 +1214,13 @@ void TSamboHead::setAfterDeadEffect() nullptr, 0, 4); } -void TSamboHead::setCrashAnm() { } +void TSamboHead::setCrashAnm() +{ + if (unk198->unk150) + unk198->bloom(); + + setBckAnm(10); +} void TSamboHead::calcRootMatrix() { From 9375c3b2c1cc86677b171d043ff061e97f792a03 Mon Sep 17 00:00:00 2001 From: gitRasheed Date: Fri, 25 Sep 2026 20:19:06 +0100 Subject: [PATCH 06/13] Enemy/hanasambo: THanaSamboHead::kill turns the head's collision off --- src/Enemy/hanasambo.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Enemy/hanasambo.cpp b/src/Enemy/hanasambo.cpp index 392d8889b..eb4a79cf2 100644 --- a/src/Enemy/hanasambo.cpp +++ b/src/Enemy/hanasambo.cpp @@ -563,7 +563,7 @@ void THanaSamboHead::checkHit() } } -void THanaSamboHead::kill() { } +void THanaSamboHead::kill() { onHitFlag(HIT_FLAG_NO_COLLISION); } THanaSambo::THanaSambo(const char* param_1) : TSmallEnemy(param_1) @@ -662,7 +662,7 @@ void THanaSambo::kill() mSpine->pushAfterCurrent(&TNerveHanaSamboDie::theNerve()); } - unk194->onHitFlag(HIT_FLAG_NO_COLLISION); + unk194->kill(); onLiveFlag(LIVE_FLAG_UNK40); } @@ -687,7 +687,7 @@ void THanaSambo::setDeadAnm() else setBckAnm(0); - unk194->onHitFlag(HIT_FLAG_NO_COLLISION); + unk194->kill(); unk1B0 = 0; onLiveFlag(LIVE_FLAG_UNK8); } From 18c019ea0e12f3a5ee1358300ad15a77cb9b7dc9 Mon Sep 17 00:00:00 2001 From: gitRasheed Date: Fri, 25 Sep 2026 20:22:27 +0100 Subject: [PATCH 07/13] Enemy/hanasambo: include InfectiousStrings, swap mSLAppearDist and mSLHideDist The map puts MtxCalcTypeName in this TU. The Hide nerve pushes Appear on the 0x2FC distance and the Wait nerve pushes Hide on 0x310, so 0x2FC is the appear distance. --- include/Enemy/HanaSambo.hpp | 4 ++-- src/Enemy/hanasambo.cpp | 13 +++++++------ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/include/Enemy/HanaSambo.hpp b/include/Enemy/HanaSambo.hpp index 9fe7cb6f7..3156176f9 100644 --- a/include/Enemy/HanaSambo.hpp +++ b/include/Enemy/HanaSambo.hpp @@ -189,8 +189,8 @@ class THanaSamboSaveLoadParams : public TSmallEnemyParams { public: /* 0x2D4 */ TParamRT mSLAttackDist; /* 0x2E8 */ TParamRT mSLAttackInterval; - /* 0x2FC */ TParamRT mSLHideDist; - /* 0x310 */ TParamRT mSLAppearDist; + /* 0x2FC */ TParamRT mSLAppearDist; + /* 0x310 */ TParamRT mSLHideDist; /* 0x324 */ TParamRT mSLAttackingTime; /* 0x338 */ TParamRT mSLHeadAttackRadius; /* 0x34C */ TParamRT mSLHeadAttackHeight; diff --git a/src/Enemy/hanasambo.cpp b/src/Enemy/hanasambo.cpp index eb4a79cf2..008e1e750 100644 --- a/src/Enemy/hanasambo.cpp +++ b/src/Enemy/hanasambo.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -506,8 +507,8 @@ THanaSamboSaveLoadParams::THanaSamboSaveLoadParams(const char* param_1) : TSmallEnemyParams(param_1) , PARAM_INIT(mSLAttackDist, 200.0f) , PARAM_INIT(mSLAttackInterval, 200) - , PARAM_INIT(mSLHideDist, 800.0f) - , PARAM_INIT(mSLAppearDist, 1000.0f) + , PARAM_INIT(mSLAppearDist, 800.0f) + , PARAM_INIT(mSLHideDist, 1000.0f) , PARAM_INIT(mSLAttackingTime, 30) , PARAM_INIT(mSLHeadAttackRadius, 60.0f) , PARAM_INIT(mSLHeadAttackHeight, 20.0f) @@ -838,8 +839,8 @@ DEFINE_NERVE(TNerveHanaSamboWait, TLiveActor) } self->updateSquareToMario(); - if (self->mDistToMarioSquared > self->unk198->mSLAppearDist.get() - * self->unk198->mSLAppearDist.get()) { + if (self->mDistToMarioSquared + > self->unk198->mSLHideDist.get() * self->unk198->mSLHideDist.get()) { spine->pushAfterCurrent(&TNerveHanaSamboHide::theNerve()); return true; } @@ -900,8 +901,8 @@ DEFINE_NERVE(TNerveHanaSamboHide, TLiveActor) } self->updateSquareToMario(); - if (self->mDistToMarioSquared - < self->unk198->mSLHideDist.get() * self->unk198->mSLHideDist.get()) { + if (self->mDistToMarioSquared < self->unk198->mSLAppearDist.get() + * self->unk198->mSLAppearDist.get()) { spine->pushAfterCurrent(&TNerveHanaSamboAppear::theNerve()); return true; } From ea2ec7a4f15e9db33a4413cd7677e09021524296 Mon Sep 17 00:00:00 2001 From: gitRasheed Date: Fri, 25 Sep 2026 20:23:37 +0100 Subject: [PATCH 08/13] Enemy/hanasambo: match TSamboHead::genEventCoin --- src/Enemy/hanasambo.cpp | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/Enemy/hanasambo.cpp b/src/Enemy/hanasambo.cpp index 008e1e750..33382cdbe 100644 --- a/src/Enemy/hanasambo.cpp +++ b/src/Enemy/hanasambo.cpp @@ -1232,39 +1232,35 @@ void TSamboHead::calcRootMatrix() void TSamboHead::genEventCoin() { if (isBckAnm(1)) { + Mtx mtx; + MtxPtr matrix = mtx; for (int i = 0; i < 3; ++i) { - Mtx local_38; - Vec local_2c; - f32 angle = 60.0f * i + (mRotation.y - 60.0f); - MsMtxSetRotY(local_38, angle); - - local_2c.x = 0.0f; - local_2c.y = 0.0f; - local_2c.z = 100.0f; - MTXMultVec(local_38, &local_2c, &local_2c); + MsMtxSetRotY(matrix, mRotation.y - 60.0f + 60.0f * i); + JGeometry::TVec3 offset(0.0f, 0.0f, 100.0f); + MTXMultVec(matrix, &offset, &offset); - TCoin* coin; + TMapObjBase* coin; if (i == 1 && mCoin) { coin = mCoin; if (coin->isActorType(0x2000000E)) - coin = (TCoin*)gpItemManager->makeObjAppear(0x2000000E); + coin = gpItemManager->makeObjAppear(0x2000000E); if (coin) { coin->appear(); coin->mPosition = mPosition; } } else { - coin = (TCoin*)gpItemManager->makeObjAppear( - mPosition.x + local_2c.x, mPosition.y, - mPosition.z + local_2c.z, 0x2000000E, true); + coin = gpItemManager->makeObjAppear( + mPosition.x + offset.x, mPosition.y, mPosition.z + offset.z, + 0x2000000E, true); } if (coin) { coin->mPosition.y = mPosition.y; - MsVECNormalize(&local_2c, &local_2c); - coin->mVelocity.set(local_2c.x * 4, + MsVECNormalize(&offset, &offset); + coin->mVelocity.set(offset.x * 4.0f, TMsRange(8.0f, 16.0f).rand(), - local_2c.z * 4); + offset.z * 4.0f); coin->offLiveFlag(LIVE_FLAG_UNK10); } } From e06a1834f75b968443ef98759b6319a7cff45791 Mon Sep 17 00:00:00 2001 From: gitRasheed Date: Fri, 25 Sep 2026 20:34:48 +0100 Subject: [PATCH 09/13] Enemy/hanasambo: type the head and flower params members, drop the casts --- include/Enemy/HanaSambo.hpp | 4 +-- src/Enemy/hanasambo.cpp | 60 ++++++++++++++++--------------------- 2 files changed, 27 insertions(+), 37 deletions(-) diff --git a/include/Enemy/HanaSambo.hpp b/include/Enemy/HanaSambo.hpp index 3156176f9..81d6221e1 100644 --- a/include/Enemy/HanaSambo.hpp +++ b/include/Enemy/HanaSambo.hpp @@ -68,7 +68,7 @@ class TSamboHead : public TWalkerEnemy { static u8 mBodyJntIndex; public: - /* 0x194 */ void* unk194; + /* 0x194 */ TSamboHeadSaveLoadParams* unk194; /* 0x198 */ TSamboFlower* unk198; /* 0x19C */ s32 unk19C; /* 0x1A0 */ JGeometry::TVec3 unk1A0; @@ -225,7 +225,7 @@ class TSamboFlower : public TSpineEnemy { /* 0x161 */ char unk161[0x3]; /* 0x164 */ s32* unk164; /* 0x168 */ class TMapObjBase* unk168; - /* 0x16C */ TSpineEnemyParams* unk16C; + /* 0x16C */ TSamboFlowerSaveLoadParams* unk16C; }; class TSamboFlowerManager : public TEnemyManager { diff --git a/src/Enemy/hanasambo.cpp b/src/Enemy/hanasambo.cpp index 33382cdbe..919656c54 100644 --- a/src/Enemy/hanasambo.cpp +++ b/src/Enemy/hanasambo.cpp @@ -105,10 +105,8 @@ void TSamboFlowerCoinUnit::checkGenCoin() f32 rate = (f32)spawned / (f32)total; - JGeometry::TVec3 offset( - 0.0f, 0.0f, - ((TSamboFlowerSaveLoadParams*)unk0[i]->unk16C) - ->mSLCoinCircleR.get()); + JGeometry::TVec3 offset(0.0f, 0.0f, + unk0[i]->unk16C->mSLCoinCircleR.get()); MsMtxSetRotY(mtx, 360.0f * rate); MTXMultVec(mtx, &offset, &offset); @@ -126,8 +124,7 @@ void TSamboFlowerCoinUnit::checkGenCoin() MsVECNormalize(&offset, &offset); - TSamboFlowerSaveLoadParams* prm - = (TSamboFlowerSaveLoadParams*)unk0[i]->unk16C; + TSamboFlowerSaveLoadParams* prm = unk0[i]->unk16C; coin->mVelocity.set(offset.x * prm->mSLCoinVelocityXZ.get(), 8.0f * rate + prm->mSLCoinVelocityY.get(), offset.z * prm->mSLCoinVelocityXZ.get()); @@ -373,7 +370,7 @@ void TSamboFlower::init(TLiveManager* param_1) param_1->manageActor(this); setMActorAndKeeper(); unk130 = 1; - unk16C = getSaveParam(); + unk16C = (TSamboFlowerSaveLoadParams*)getSaveParam(); if (unk16C) { mBodyRadius = unk16C->mSLBodyRadius.get(); mWallRadius = unk16C->mSLWallRadius.get(); @@ -433,8 +430,7 @@ void TSamboFlower::moveObject() if (unk160) { unk154++; - if (unk154 - > ((TSamboFlowerSaveLoadParams*)unk16C)->mSLBloomTimer.get()) { + if (unk154 > unk16C->mSLBloomTimer.get()) { if (getMActor()->checkCurAnm("flower_fwait", 0)) { unk150 = false; if (unk164) @@ -1011,10 +1007,10 @@ static int SamboHeadRollCallback(J3DNode* param_1, int param_2) JGeometry::TVec3 axis(rateX, rateY, rateZ); - Mtx local_100; - MTXRotAxisRad(local_100, &axis, 0.017453292f * gpCurSamboHead->unk1AC); - MTXConcat(anmMtx, local_100, anmMtx); - MTXConcat(J3DSys::mCurrentMtx, local_100, J3DSys::mCurrentMtx); + Mtx rotMtx; + MTXRotAxisRad(rotMtx, &axis, 0.017453292f * gpCurSamboHead->unk1AC); + MTXConcat(anmMtx, rotMtx, anmMtx); + MTXConcat(J3DSys::mCurrentMtx, rotMtx, J3DSys::mCurrentMtx); } return true; } @@ -1082,7 +1078,7 @@ void TSamboHead::init(TLiveManager* param_1) TWalkerEnemy::init(param_1); mActorType = 0x1000001B; unk150 = 0x11; - unk194 = getSaveParam(); + unk194 = (TSamboHeadSaveLoadParams*)getSaveParam(); mSpine->initWith(&TNerveSamboHeadHide::theNerve()); setGoalPathMario(); mMActor->setJointCallback(mBodyJntIndex, SamboHeadRollCallback); @@ -1134,8 +1130,8 @@ void TSamboHead::behaveToWater(THitActor* param_1) JGeometry::TVec3 jump(mPosition.x - gpMarioPos->x, 0.0f, mPosition.z - gpMarioPos->z); MsVECNormalize(&jump, &jump); - jump.scale(((TSamboHeadSaveLoadParams*)unk194)->mSLHitJumpSpXZ.get()); - jump.y = ((TSamboHeadSaveLoadParams*)unk194)->mSLHitJumpSpY.get(); + jump.scale(unk194->mSLHitJumpSpXZ.get()); + jump.y = unk194->mSLHitJumpSpY.get(); if (mSpine->getCurrentNerve() != &TNerveSamboHeadHitWater::theNerve()) mSpine->pushNerve(&TNerveSamboHeadHitWater::theNerve()); @@ -1168,10 +1164,10 @@ f32 TSamboHead::getGravityY() const f32 gravity = mGravity; if (mSpine->getCurrentNerve() == &TNerveSamboHeadAttack::theNerve()) - gravity = ((TSamboHeadSaveLoadParams*)unk194)->mSLMoveGravity.get(); + gravity = unk194->mSLMoveGravity.get(); if (mSpine->getCurrentNerve() == &TNerveSamboHeadHitWater::theNerve()) - gravity = ((TSamboHeadSaveLoadParams*)unk194)->mSLHitJumpGravity.get(); + gravity = unk194->mSLHitJumpGravity.get(); return gravity; } @@ -1336,8 +1332,7 @@ DEFINE_NERVE(TNerveSamboHeadAttack, TLiveActor) TSamboHead* self = (TSamboHead*)spine->getBody(); if (!self->isAirborne()) { - if (self->unk19C > ((TSamboHeadSaveLoadParams*)self->unk194) - ->mSLJumpPrepareTime.get() + if (self->unk19C > self->unk194->mSLJumpPrepareTime.get() && self->checkCurAnmEnd(0)) { self->unk19C = 0; self->updateSquareToMario(); @@ -1350,14 +1345,12 @@ DEFINE_NERVE(TNerveSamboHeadAttack, TLiveActor) MsVECNormalize(&goal, &goal); - f32 moveDist - = ((TSamboHeadSaveLoadParams*)self->unk194)->mSLMoveDist.get(); - goal.x = goal.x * moveDist + self->mPosition.x; - goal.z = goal.z * moveDist + self->mPosition.z; - goal.y = self->mPosition.y; + f32 moveDist = self->unk194->mSLMoveDist.get(); + goal.x = goal.x * moveDist + self->mPosition.x; + goal.z = goal.z * moveDist + self->mPosition.z; + goal.y = self->mPosition.y; - f32 jumpSp - = ((TSamboHeadSaveLoadParams*)self->unk194)->mSLJumpSp.get(); + f32 jumpSp = self->unk194->mSLJumpSp.get(); self->setVelocity( self->calcVelocityToJumpToY(goal, jumpSp, self->getGravityY())); self->mPosition.y += 2.0f; @@ -1380,8 +1373,7 @@ DEFINE_NERVE(TNerveSamboHeadAttack, TLiveActor) } if (self->mPosition.y > 30.0f + self->mGroundHeight) { - f32 limit - = ((TSamboHeadSaveLoadParams*)self->unk194)->mSLJumpAngY.get(); + f32 limit = self->unk194->mSLJumpAngY.get(); JGeometry::TVec3 velocity = self->mLinearVelocity; self->unk1AC = MsClamp(MsGetRotFromZaxis(velocity).x, -limit, limit); } else { @@ -1414,9 +1406,8 @@ DEFINE_NERVE(TNerveSamboHeadHide, TLiveActor) } else if (self->isFindMario(1.0f)) { self->updateSquareToMario(); if (self->mDistToMarioSquared - < ((TSamboHeadSaveLoadParams*)self->unk194)->mSLAppearDist.get() - * ((TSamboHeadSaveLoadParams*)self->unk194) - ->mSLAppearDist.get()) { + < self->unk194->mSLAppearDist.get() + * self->unk194->mSLAppearDist.get()) { spine->pushAfterCurrent(&TNerveSamboHeadAppear::theNerve()); return true; } @@ -1446,7 +1437,7 @@ DEFINE_NERVE(TNerveSamboHeadHitWater, TLiveActor) return true; } - f32 limit = ((TSamboHeadSaveLoadParams*)self->unk194)->mSLJumpAngY.get(); + f32 limit = self->unk194->mSLJumpAngY.get(); if (self->isBckAnm(6)) { if (spine->getTime() < 100) self->unk1AC = MsClamp(self->unk1AC - 3.0f, -limit, limit); @@ -1469,8 +1460,7 @@ DEFINE_NERVE(TNerveSamboHeadHitWater, TLiveActor) self->setBckAnm(6); if (self->checkCurAnmEnd(0) && self->isBckAnm(6)) { - f32 rate = ((TSamboHeadSaveLoadParams*)self->unk194) - ->mSLHitJumpSpRateXZ.get(); + f32 rate = self->unk194->mSLHitJumpSpRateXZ.get(); self->setBckAnm(6); self->unk1A0.x *= rate; self->unk1A0.z *= rate; From 02555fb3d8403bee5f5601bbb20d6cdff41f8cb1 Mon Sep 17 00:00:00 2001 From: gitRasheed Date: Fri, 25 Sep 2026 21:11:54 +0100 Subject: [PATCH 10/13] Enemy/hanasambo: setGoalPath through TPathNode now that setGoalPathMario is gone --- src/Enemy/hanasambo.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Enemy/hanasambo.cpp b/src/Enemy/hanasambo.cpp index 919656c54..b43255a6b 100644 --- a/src/Enemy/hanasambo.cpp +++ b/src/Enemy/hanasambo.cpp @@ -575,7 +575,7 @@ void THanaSambo::load(JSUMemoryInputStream& param_1) { TSmallEnemy::load(param_1); reset(); - setGoalPathMario(); + setGoalPath(TPathNode((THitActor*)gpMarioAddress)); } void THanaSambo::init(TLiveManager* param_1) @@ -586,7 +586,7 @@ void THanaSambo::init(TLiveManager* param_1) unk198 = (THanaSamboSaveLoadParams*)getSaveParam(); mSpine->initWith(&TNerveHanaSamboHide::theNerve()); unk1AC = new TMBindShadowBody(this, getModel(), 1.5f); - setGoalPathMario(); + setGoalPath(TPathNode((THitActor*)gpMarioAddress)); if (mInstanceIndex == 0) { // TODO: what this loop did is unknown @@ -1070,7 +1070,7 @@ void TSamboHead::load(JSUMemoryInputStream& param_1) { TSmallEnemy::load(param_1); reset(); - setGoalPathMario(); + setGoalPath(TPathNode((THitActor*)gpMarioAddress)); } void TSamboHead::init(TLiveManager* param_1) @@ -1080,7 +1080,7 @@ void TSamboHead::init(TLiveManager* param_1) unk150 = 0x11; unk194 = (TSamboHeadSaveLoadParams*)getSaveParam(); mSpine->initWith(&TNerveSamboHeadHide::theNerve()); - setGoalPathMario(); + setGoalPath(TPathNode((THitActor*)gpMarioAddress)); mMActor->setJointCallback(mBodyJntIndex, SamboHeadRollCallback); } From e782f4dc80524801081a5914f37425002855975a Mon Sep 17 00:00:00 2001 From: gitRasheed Date: Fri, 25 Sep 2026 21:19:57 +0100 Subject: [PATCH 11/13] Enemy/hanasambo: define the TSamboFlower constructor in the class It is weak in both maps, and the PAL map emits it from this TU. --- include/Enemy/HanaSambo.hpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/include/Enemy/HanaSambo.hpp b/include/Enemy/HanaSambo.hpp index 81d6221e1..3317a6039 100644 --- a/include/Enemy/HanaSambo.hpp +++ b/include/Enemy/HanaSambo.hpp @@ -200,7 +200,18 @@ class THanaSamboSaveLoadParams : public TSmallEnemyParams { class TSamboFlower : public TSpineEnemy { public: - TSamboFlower(const char* name = "サンボフラワー"); + TSamboFlower(const char* name = "サンボフラワー") + : TSpineEnemy(name) + , unk150(0) + , unk154(0) + , unk158(-1) + , unk15C(-1) + , unk160(0) + , unk164(nullptr) + , unk168(nullptr) + { + } + virtual void load(JSUMemoryInputStream&); virtual void loadAfter(); virtual BOOL receiveMessage(THitActor*, u32); From 60a9898411527c99ed4de7a3b0fb2e10fb3bf39f Mon Sep 17 00:00:00 2001 From: gitRasheed Date: Mon, 28 Sep 2026 08:48:24 +0100 Subject: [PATCH 12/13] Enemy/hanasambo: bas tables first in .data --- src/Enemy/hanasambo.cpp | 60 ++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/Enemy/hanasambo.cpp b/src/Enemy/hanasambo.cpp index b43255a6b..f14ae7d2e 100644 --- a/src/Enemy/hanasambo.cpp +++ b/src/Enemy/hanasambo.cpp @@ -53,6 +53,36 @@ #include #include +static const char* sambo_bastable[] = { + "/scene/sambo/bas/sambo_down.bas", + 0, + 0, + 0, + "/scene/sambo/bas/sambo_Fhide.bas", + 0, + "/scene/sambo/bas/sambo_Fset.bas", + "/scene/sambo/bas/sambo_Fwait.bas", + "/scene/sambo/bas/sambo_hit.bas", + 0, + "/scene/sambo/bas/sambo_Ydown.bas", +}; + +static const char* sambohead_bastable[] = { + "/scene/sambohead/bas/flower_shoot.bas", + "/scene/sambohead/bas/samboHead_crash.bas", + "/scene/sambohead/bas/samboHead_dance.bas", + "/scene/sambohead/bas/samboHead_down.bas", + "/scene/sambohead/bas/samboHead_Fhide.bas", + "/scene/sambohead/bas/samboHead_hit.bas", + "/scene/sambohead/bas/samboHead_hit_end.bas", + "/scene/sambohead/bas/samboHead_jump_end.bas", + "/scene/sambohead/bas/samboHead_jump_start.bas", + 0, + "/scene/sambohead/bas/samboHead_set.bas", + "/scene/sambohead/bas/samboHead_turn.bas", + 0, +}; + TSamboFlowerCoinUnit::TSamboFlowerCoinUnit(int param_1) : unk0(nullptr) , unk10(0) @@ -708,20 +738,6 @@ void THanaSambo::waterDamage() mSpine->pushNerve(&TNerveHanaSamboFreeze::theNerve()); } -static const char* sambo_bastable[] = { - "/scene/sambo/bas/sambo_down.bas", - 0, - 0, - 0, - "/scene/sambo/bas/sambo_Fhide.bas", - 0, - "/scene/sambo/bas/sambo_Fset.bas", - "/scene/sambo/bas/sambo_Fwait.bas", - "/scene/sambo/bas/sambo_hit.bas", - 0, - "/scene/sambo/bas/sambo_Ydown.bas", -}; - const char** THanaSambo::getBasNameTable() const { return sambo_bastable; } void THanaSambo::perform(u32 param_1, JDrama::TGraphics* param_2) @@ -1276,22 +1292,6 @@ bool TSamboHead::isUseCallBack() return false; } -static const char* sambohead_bastable[] = { - "/scene/sambohead/bas/flower_shoot.bas", - "/scene/sambohead/bas/samboHead_crash.bas", - "/scene/sambohead/bas/samboHead_dance.bas", - "/scene/sambohead/bas/samboHead_down.bas", - "/scene/sambohead/bas/samboHead_Fhide.bas", - "/scene/sambohead/bas/samboHead_hit.bas", - "/scene/sambohead/bas/samboHead_hit_end.bas", - "/scene/sambohead/bas/samboHead_jump_end.bas", - "/scene/sambohead/bas/samboHead_jump_start.bas", - 0, - "/scene/sambohead/bas/samboHead_set.bas", - "/scene/sambohead/bas/samboHead_turn.bas", - 0, -}; - const char** TSamboHead::getBasNameTable() const { return sambohead_bastable; } DEFINE_NERVE(TNerveSamboHeadAppear, TLiveActor) From 112600e1886e6e9a13b9cfb236e6eed7b249ce38 Mon Sep 17 00:00:00 2001 From: gitRasheed Date: Mon, 28 Sep 2026 08:48:37 +0100 Subject: [PATCH 13/13] Enemy/hanasambo: recover TSamboHead::setCrashAnm and call it from the hit-wall nerve --- src/Enemy/hanasambo.cpp | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/src/Enemy/hanasambo.cpp b/src/Enemy/hanasambo.cpp index f14ae7d2e..0c573bd2c 100644 --- a/src/Enemy/hanasambo.cpp +++ b/src/Enemy/hanasambo.cpp @@ -1229,10 +1229,21 @@ void TSamboHead::setAfterDeadEffect() void TSamboHead::setCrashAnm() { - if (unk198->unk150) - unk198->bloom(); + setBckAnm(1); - setBckAnm(10); + JGeometry::TVec3 scale(1.5f); + + if (JPABaseEmitter* emitter = gpMarioParticleManager->emitWithRotate( + PARTICLE_MS_ENM_WALLHIT, &mPosition, 0, DEG2SHORTANGLE(mRotation.y), + 0, 0, nullptr)) + emitter->setGlobalScale(scale); + + if (JPABaseEmitter* emitter = gpMarioParticleManager->emitWithRotate( + PARTICLE_MS_ENM_WALLHIT_O, &mPosition, 0, + DEG2SHORTANGLE(mRotation.y), 0, 0, nullptr)) { + emitter->setGlobalScale(scale); + SMSSetEmitterPolColor(emitter, 6); + } } void TSamboHead::calcRootMatrix() @@ -1494,22 +1505,8 @@ DEFINE_NERVE(TNerveSamboHeadHitWall, TLiveActor) { TSamboHead* self = (TSamboHead*)spine->getBody(); - if (spine->getTime() == 0) { - self->setBckAnm(1); - - JGeometry::TVec3 scale(1.5f); - if (JPABaseEmitter* emitter = gpMarioParticleManager->emitWithRotate( - PARTICLE_MS_ENM_WALLHIT, &self->mPosition, 0, - DEG2SHORTANGLE(self->mRotation.y), 0, 0, nullptr)) - emitter->setGlobalScale(scale); - - if (JPABaseEmitter* emitter = gpMarioParticleManager->emitWithRotate( - PARTICLE_MS_ENM_WALLHIT_O, &self->mPosition, 0, - DEG2SHORTANGLE(self->mRotation.y), 0, 0, nullptr)) { - emitter->setGlobalScale(scale); - SMSSetEmitterPolColor(emitter, 6); - } - } + if (spine->getTime() == 0) + self->setCrashAnm(); int waitTime = ((TSmallEnemyManager*)self->getManager())->unk5C; if (self->checkCurAnmEnd(0)