From 4c7290774d151b2e164c0f5af241cab04eca92d1 Mon Sep 17 00:00:00 2001 From: KakarotCake <61133727+KakarottoCake@users.noreply.github.com> Date: Sun, 2 Aug 2026 21:10:58 -0400 Subject: [PATCH 01/18] Enemy/bosstelesa: reconstruct BossTelesa TU scaffolding --- include/Enemy/BossTelesa.hpp | 284 +++++++++++++++ include/M3DUtil/MActor.hpp | 1 + src/Enemy/bosstelesa.cpp | 664 +++++++++++++++++++++++++++++++++++ 3 files changed, 949 insertions(+) create mode 100644 include/Enemy/BossTelesa.hpp diff --git a/include/Enemy/BossTelesa.hpp b/include/Enemy/BossTelesa.hpp new file mode 100644 index 000000000..f3d3995d5 --- /dev/null +++ b/include/Enemy/BossTelesa.hpp @@ -0,0 +1,284 @@ +#ifndef ENEMY_BOSS_TELESA_HPP +#define ENEMY_BOSS_TELESA_HPP + +#include +#include +#include +#include +#include + +class TBossTelesa; +class TBubble; + +/* The boss uses the same spine state objects as the regular Telesa, but has + * its own state machine for the roulette, tongue and bubble attacks. */ +DECLARE_NERVE(TNerveBossTelesaFallDemo, TLiveActor); +DECLARE_NERVE(TNerveBossTelesaFreeze, TLiveActor); +DECLARE_NERVE(TNerveBossTelesaPrepareSlot, TLiveActor); +DECLARE_NERVE(TNerveBossTelesaSpitSlotItem, TLiveActor); +DECLARE_NERVE(TNerveBossTelesaSlotStart, TLiveActor); +DECLARE_NERVE(TNerveBossTelesaAppear, TLiveActor); +DECLARE_NERVE(TNerveBossTelesaHideWait, TLiveActor); +DECLARE_NERVE(TNerveBossTelesaHide, TLiveActor); +DECLARE_NERVE(TNerveBossTelesaSpit, TLiveActor); +DECLARE_NERVE(TNerveBossTelesaDie, TLiveActor); +DECLARE_NERVE(TNerveBubbleSplit, TLiveActor); +DECLARE_NERVE(TNerveBubbleLive, TLiveActor); + +class TBossTelesaSaveLoadParams : public TSpineEnemyParams { +public: + TBossTelesaSaveLoadParams(const char* path); + + /* 0x0A8 */ TParamRT mSLDamageRadius; + /* 0x0BC */ TParamRT mSLDamageHeight; + /* 0x0D0 */ TParamRT mSLAttackRadius; + /* 0x0E4 */ TParamRT mSLAttackHeight; + /* 0x0F8 */ TParamRT mSLGenAttackerTime; + /* 0x10C */ TParamRT mSLGenBubbleTime; + /* 0x120 */ TParamRT mSLHitAngle; + /* 0x134 */ TParamRT mSLNumGenBubble; + /* 0x148 */ TParamRT mSL1stBubbleSp; + /* 0x15C */ TParamRT mSLHideAreaRadius; + /* 0x170 */ TParamRT mSLSlotItemNum; + /* 0x184 */ TParamRT mSLSlotFruitNum; + /* 0x198 */ TParamRT mSLSlotFirstHitCollectRate; + /* 0x1AC */ TParamRT mSLSlotHitCollectRate; + /* 0x1C0 */ TParamRT mSLTransYOffset; + /* 0x1D4 */ TParamRT mSLStopSlotTime0; + /* 0x1E8 */ TParamRT mSLStopSlotTime1; + /* 0x1FC */ TParamRT mSLStopSlotTime2; + /* 0x210 */ TParamRT mSLSpicyTime; +}; + +class TBubbleSaveLoadParams : public TSpineEnemyParams { +public: + TBubbleSaveLoadParams(const char* path); + + /* 0x0A8 */ TParamRT mSLLiveTime; + /* 0x0BC */ TParamRT mSLNumDivision; + /* 0x0D0 */ TParamRT mSLMaxScale; + /* 0x0E4 */ TParamRT mSLAddPosBase; + /* 0x0F8 */ TParamRT mSLRateExpand; + /* 0x10C */ TParamRT mSLDeadHeight; +}; + +/* TSlotDrum already owns the geometry, angle and neon material fields. */ +class TTelesaSlot : public TSlotDrum { +public: + TTelesaSlot(const char* name); + + virtual void calcRootMatrix(); + virtual void moveObject(); + virtual void initMapObj(); + virtual u32 touchWater(THitActor*); + virtual void initNeonMatColor() { } + + int getForcastResult(int); + int getResultFromAng(f32); + int getSlotResult(); + u8 isRollDrum(); + void forceStopSlot(int); + void moveStart(); + void randomReset(); + void entryObjCollision(); + void calcObjCollision(); + int getDrumResult(int); + + /* 0x198 */ u8 mRoll0; + /* 0x199 */ u8 mRoll1; + /* 0x19A */ u8 mRoll2; + /* 0x19B */ s8 mRolling; + /* 0x19C */ u8 mForceStop; + /* 0x1A0 */ TBossTelesa* mOwner; + /* 0x1A4 */ s32 mForceResult; + /* 0x1A8 */ s8 mStop0; + /* 0x1A9 */ s8 mStop1; + /* 0x1AA */ s8 mStop2; + /* 0x1DC */ TMapCollisionMove* mMapCollisionMove; + /* 0x1E0 */ u8 mNeonState; +}; + +class TBossTelesa : public TSpineEnemy { +public: + TBossTelesa(const char* name = "ボステレサ"); + + virtual void loadAfter(); + virtual void perform(u32 cue, JDrama::TGraphics* graphics); + virtual BOOL receiveMessage(THitActor*, u32); + virtual void init(TLiveManager*); + virtual void calcRootMatrix(); + virtual void moveObject(); + virtual void kill(); + virtual const char** getBasNameTable() const; + virtual void reset(); + + void forceHide(); + void fanfale(); + bool isForceRestart(); + void rollRouletteCircle(); + void forceAllItemKill(); + bool checkAllItemDead(); + bool checkSlot(); + void fruitCollisionOn(); + void generateSlotItem(); + int checkSlotResult(); + void slotStop(); + void slotStart(); + bool isInDamage(); + void setBckAnm(int); + void offAllCollision(); + void onAllCollision(); + void openWaterPlace(); + void tongueHitWater(); + BOOL checkMessage(THitActor*, u32); + void prepareGenerate(); + void rouletteStart(); + void genAttacker(); + void flashItem(int); + u8 slotFall(); + u8 rouletteFall(); + void damageRecover(); + void setSpicy(TLiveActor*); + BOOL checkHitObject(THitActor*); + MtxPtr getTakingMtx(); + + static f32 mEnemyGenRate; + static f32 mItemGenRate; + static u8 mNormalAlpha; + static f32 mBaseHoseiPosY; + static f32 mRouletteUpRate; + static s32 mTelesaGenerateInterval; + static f32 mCameraMoveLimit; + static f32 mCameraMoveSp; + + /* 0x150 */ s32 mBattleState; + /* 0x154 */ s32 mBattleTimer; + /* 0x158 */ s32 mBattlePhase; + /* 0x15C */ TLiveActor* mMario; + /* 0x160 */ s32 mCurrentItem; + /* 0x164 */ s32 mCurrentFruit; + /* 0x168 */ f32 mFallSpeed; + /* 0x16C */ THitActor* mBodyCollision; + /* 0x170 */ THitActor* mTongueCollision; + /* 0x174 */ THitActor* mKillSmallEnemy; + /* 0x178 */ void* mItemList; + /* 0x17C */ void* mBubbleList; + /* 0x180 */ TBossTelesaSaveLoadParams* mSaveParams; + /* 0x184 */ TTelesaSlot* mSlot; + /* 0x188 */ JDrama::TViewObj* mTakingActor; + /* 0x18C */ u8 mIsSpicy; + /* 0x19C */ f32 mDamageBlend; + /* 0x1A0 */ f32 mDamageBlendSpeed; + /* 0x1A4 */ f32 mDamageBlendTarget; + /* 0x1A8 */ s32 mDamageTimer; + /* 0x274 */ s32 mStateTimer; + /* 0x348 */ u8 mItem0; + /* 0x349 */ u8 mItem1; + /* 0x34A */ u8 mItem2; + /* 0x34B */ u8 mItem3; + /* 0x34C */ u8 mFruit0; + /* 0x34D */ u8 mFruit1; + /* 0x34E */ u8 mFruit2; + /* 0x34F */ u8 mAlpha; + /* 0x350 */ u8 mDamage; + /* 0x354 */ s32 mGenerateTimer; + /* 0x358 */ s16 mMarioHP; + /* 0x35A */ u8 mForceRestart; + /* 0x35B */ u8 mInDamage; + /* 0x35C */ s32 mRouletteTimer; + /* 0x360 */ f32 mRoulettePosY; + /* 0x364 */ f32 mRouletteSp; + /* 0x368 */ s32 mSlotResult; + /* 0x36C */ s32 mSlotItemCount; + /* 0x370 */ u8 mSlotStop; + /* 0x374 */ JGeometry::TVec3 mEffectPos; + /* 0x384 */ s8 mDead; +}; + +class TBossTelesaKillSmallEnemy : public THitActor { +public: + TBossTelesaKillSmallEnemy(TBossTelesa* owner = nullptr) + : THitActor("ボステレサ小敵キラー"), mOwner(owner), mHit(false) + { + } + + virtual BOOL receiveMessage(THitActor* sender, u32 message); + void checkHit(); + + /* 0x68 */ TBossTelesa* mOwner; + /* 0x6C */ bool mHit; +}; + +class TBossTelesaTongue : public THitActor { +public: + TBossTelesaTongue(TBossTelesa* owner = nullptr) + : THitActor("ボステレサ舌"), mOwner(owner) + { + } + + virtual BOOL receiveMessage(THitActor*, u32); + void checkHit(); + TBossTelesa* mOwner; +}; + +class TBossTelesaBody : public THitActor { +public: + TBossTelesaBody(TBossTelesa* owner = nullptr) + : THitActor("ボステレサ本体"), mOwner(owner) + { + } + + virtual BOOL receiveMessage(THitActor*, u32); + void checkHit(); + TBossTelesa* mOwner; +}; + +class TBossTelesaManager : public TEnemyManager { +public: + TBossTelesaManager(const char* name = "ボステレサマネージャー"); + + virtual void load(JSUMemoryInputStream&); + virtual void perform(u32 cue, JDrama::TGraphics* graphics); + virtual void createModelData(); + virtual TSpineEnemy* createEnemyInstance(); + virtual void clipEnemies(JDrama::TGraphics*) { } +}; + +class TBubble : public TWalkerEnemy { +public: + TBubble(const char* name = "バブル"); + + virtual void init(TLiveManager*); + virtual void calcRootMatrix(); + virtual void behaveToWater(THitActor*); + virtual void kill(); + virtual f32 getGravityY() const; + virtual const char** getBasNameTable() const; + virtual void reset(); + + void appendEnemy(); + void appendItem(); + void setDeadAnm(); + void attackToMario(); + void split(); + void setAfterDeadEffect() { } + MtxPtr getTakingMtx(); + + /* 0x194 */ TBubbleSaveLoadParams* mSaveParams; + /* 0x198 */ TSmallEnemy* mCarriedEnemy; + /* 0x1CC */ f32 mHeight; + /* 0x1D0 */ u8 mIsSplit; + /* 0x1D1 */ u8 mIsMoving; + /* 0x1D2 */ u8 mNoEffect; +}; + +class TBubbleManager : public TSmallEnemyManager { +public: + TBubbleManager(const char* name = "バブルマネージャー"); + + virtual void load(JSUMemoryInputStream&); + virtual void createModelData(); + virtual TSmallEnemy* createEnemyInstance(); +}; + +#endif diff --git a/include/M3DUtil/MActor.hpp b/include/M3DUtil/MActor.hpp index 8a941dd61..268b3a4b7 100644 --- a/include/M3DUtil/MActor.hpp +++ b/include/M3DUtil/MActor.hpp @@ -93,6 +93,7 @@ class MActor { // fabricated MActorAnmBase* getUnk28(int i) { return unk28[i]; } MActorAnmBck* getAnmBck() { return unkC; } + MActorAnmBck* getCurBckAnmPtr(); J3DModel* getModel() const { return unk4; } void unmarkUnk40() { unk40 = false; } BOOL curAnmEndsNext() { return curAnmEndsNext(0, 0); } diff --git a/src/Enemy/bosstelesa.cpp b/src/Enemy/bosstelesa.cpp index 8b1378917..cb2052229 100644 --- a/src/Enemy/bosstelesa.cpp +++ b/src/Enemy/bosstelesa.cpp @@ -1 +1,665 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Boss Telesa is the casino boss in Sirena Beach. The retail TU is a good + * deal denser than the ordinary Telesa TU: one actor owns three roulette + * drums, two hit proxies and a small bubble manager. Keep the data and + * state-machine names here even while the long animation routines are being + * brought over from the matching assembly. + */ + +static const char* btelesa_bastable[] = { + "/scene/btelesa/bas/btelesa_appear.bas", + "/scene/btelesa/bas/btelesa_bero_hit.bas", + "/scene/btelesa/bas/btelesa_damage.bas", + nullptr, + nullptr, + nullptr, + nullptr, + "/scene/btelesa/bas/btelesa_lick.bas", + nullptr, + nullptr, + nullptr, + "/scene/btelesa/bas/btelesa_roll.bas", + "/scene/btelesa/bas/btelesa_spicy.bas", + nullptr, + nullptr, + "/scene/btelesa/bas/btelesa_wait.bas", + "/scene/btelesa/bas/btelesa_wet.bas", +}; + +static const char* bubble_bastable[] = { + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + "/scene/btelesa/bas/btelesa_lick.bas", + "/scene/btelesa/bas/btelesa_roll.bas", + nullptr, + nullptr, +}; + +static const TModelDataLoadEntry btelesa_model_data[] = { + { "btelesa.bmd", 0x15300000, 0 }, + { nullptr, 0, 0 }, +}; + +static const TModelDataLoadEntry bubble_model_data[] = { + { "btelesa_osenbubbles_ind.bmd", 0x11020000, 0 }, + { nullptr, 0, 0 }, +}; + +MActorAnmBck* MActor::getCurBckAnmPtr() { return unkC; } + +f32 TBossTelesa::mEnemyGenRate = 0.1f; +f32 TBossTelesa::mItemGenRate = 0.1f; +u8 TBossTelesa::mNormalAlpha = 0xFF; +f32 TBossTelesa::mBaseHoseiPosY = 350.0f; +f32 TBossTelesa::mRouletteUpRate = 0.1f; +s32 TBossTelesa::mTelesaGenerateInterval = 600; +f32 TBossTelesa::mCameraMoveLimit = 300.0f; +f32 TBossTelesa::mCameraMoveSp = 2.0f; + +TBossTelesaSaveLoadParams::TBossTelesaSaveLoadParams(const char* path) + : TSpineEnemyParams(path) + , PARAM_INIT(mSLDamageRadius, 200) + , PARAM_INIT(mSLDamageHeight, 100) + , PARAM_INIT(mSLAttackRadius, 220) + , PARAM_INIT(mSLAttackHeight, 120) + , PARAM_INIT(mSLGenAttackerTime, 500) + , PARAM_INIT(mSLGenBubbleTime, 600) + , PARAM_INIT(mSLHitAngle, 20.0f) + , PARAM_INIT(mSLNumGenBubble, 5) + , PARAM_INIT(mSL1stBubbleSp, 10.0f) + , PARAM_INIT(mSLHideAreaRadius, 500.0f) + , PARAM_INIT(mSLSlotItemNum, 5) + , PARAM_INIT(mSLSlotFruitNum, 10) + , PARAM_INIT(mSLSlotFirstHitCollectRate, 0.1f) + , PARAM_INIT(mSLSlotHitCollectRate, 0.1f) + , PARAM_INIT(mSLTransYOffset, 350.0f) + , PARAM_INIT(mSLStopSlotTime0, 3000) + , PARAM_INIT(mSLStopSlotTime1, 2000) + , PARAM_INIT(mSLStopSlotTime2, 1000) + , PARAM_INIT(mSLSpicyTime, 2000) +{ + TParams::load(mPrmPath); +} + +TBubbleSaveLoadParams::TBubbleSaveLoadParams(const char* path) + : TSpineEnemyParams(path) + , PARAM_INIT(mSLLiveTime, 1200) + , PARAM_INIT(mSLNumDivision, 3) + , PARAM_INIT(mSLMaxScale, 1.0f) + , PARAM_INIT(mSLAddPosBase, 20.0f) + , PARAM_INIT(mSLRateExpand, 0.01f) + , PARAM_INIT(mSLDeadHeight, 300.0f) +{ + TParams::load(mPrmPath); +} + +/* The slot angle table is deliberately kept as the retail eight-way split. */ +int TTelesaSlot::getResultFromAng(f32 angle) +{ + if (angle < 44.0f) + return 0; + if (angle < 89.0f) + return 1; + if (angle < 134.0f) + return 3; + if (angle < 179.0f) + return 2; + if (angle < 224.0f) + return 0; + if (angle < 269.0f) + return 1; + if (angle < 314.0f) + return 3; + return 2; +} + +int TTelesaSlot::getForcastResult(int drum) +{ + /* The actual animation advances in 45-degree steps. Forecasting only + * needs the final quantized result, so use the same normalization here. */ + f32 angle = unk13C[drum] + unk138[drum]; + while (angle >= 360.0f) + angle -= 360.0f; + while (angle <= 0.0f) + angle += 360.0f; + return getResultFromAng(45.0f * (s32)(angle / 45.0f)); +} + +int TTelesaSlot::getSlotResult() +{ + int result = getResultFromAng(unk13C[0]); + for (int i = 1; i < 3; ++i) { + if (result != getResultFromAng(unk13C[i])) + return -1; + } + return result; +} + +u8 TTelesaSlot::isRollDrum() +{ + if (mRoll0 || mRoll1 || mRoll2) + return 1; + mRolling = 0; + return 0; +} + +void TTelesaSlot::moveStart() +{ + mForceStop = 1; + mRolling = 1; + mRoll0 = 1; + mRoll1 = 1; + mRoll2 = 1; + mStop0 = mStop1 = mStop2 = 0; + unk138[0] = -unk158; + unk138[1] = -0.8f * unk158; + unk138[2] = unk158; +} + +void TTelesaSlot::randomReset() +{ + for (int i = 0; i < 3; ++i) { + unk13C[i] = unk168 * (s32)MsRandF(0.0f, 8.0f); + ((&mStop0)[i]) = 0; + } +} + +u32 TTelesaSlot::touchWater(THitActor*) { return 0; } + +void TTelesaSlot::forceStopSlot(int drum) +{ + if (!mForceStop) + return; + mForceResult = getForcastResult(drum); + ((&mRoll0)[drum]) = 0; + mForceStop = 0; +} + +void TTelesaSlot::calcRootMatrix() { TSlotDrum::calcRootMatrix(); } + +void TTelesaSlot::moveObject() { TSlotDrum::moveObject(); } + +void TTelesaSlot::initMapObj() +{ + TSlotDrum::initMapObj(); + mLiveFlag |= 0x10; + unk14C = 160.0f; + unk150 = mPosition.y; + unk154 = 2.0f; + unk158 = 2.0f; + unk15C = 0.01f; + unk160 = 0.5f; + unk168 = 45; + randomReset(); +} + +void TTelesaSlot::entryObjCollision() { } + +void TTelesaSlot::calcObjCollision() { } + +int TTelesaSlot::getDrumResult(int drum) +{ + return getResultFromAng(unk13C[drum]); +} + +TBossTelesa::TBossTelesa(const char* name) + : TSpineEnemy(name) + , mBattleState(1) + , mBattleTimer(0) + , mBattlePhase(0) + , mMario(nullptr) + , mCurrentItem(-1) + , mCurrentFruit(-1) + , mFallSpeed(0.0f) + , mBodyCollision(nullptr) + , mTongueCollision(nullptr) + , mKillSmallEnemy(nullptr) + , mItemList(nullptr) + , mBubbleList(nullptr) + , mSaveParams(nullptr) + , mSlot(nullptr) + , mTakingActor(nullptr) + , mIsSpicy(false) + , mDamageBlend(0.0f) + , mDamageBlendSpeed(0.0f) + , mDamageBlendTarget(0.0f) + , mDamageTimer(0) + , mStateTimer(0) + , mItem0(0) + , mItem1(0) + , mItem2(0) + , mItem3(0) + , mFruit0(0) + , mFruit1(0) + , mFruit2(0) + , mAlpha(mNormalAlpha) + , mDamage(0) + , mGenerateTimer(0) + , mMarioHP(1) + , mForceRestart(1) + , mInDamage(1) + , mRouletteTimer(0) + , mRoulettePosY(0.0f) + , mRouletteSp(0.0f) + , mSlotResult(0) + , mSlotItemCount(0) + , mSlotStop(0) + , mEffectPos() + , mDead(0) +{ +} + +const char** TBossTelesa::getBasNameTable() const { return btelesa_bastable; } + +void TBossTelesa::forceHide() +{ + mDead = 1; + offLiveFlag(LIVE_FLAG_UNK200); + onLiveFlag(LIVE_FLAG_HIDDEN); +} + +void TBossTelesa::fanfale() { } + +bool TBossTelesa::isForceRestart() { return mForceRestart != 0; } + +void TBossTelesa::rollRouletteCircle() +{ + if (mSlot) + mSlot->moveStart(); +} + +void TBossTelesa::forceAllItemKill() +{ + mItem0 = mItem1 = mItem2 = mItem3 = 0; + mFruit0 = mFruit1 = mFruit2 = 0; +} + +bool TBossTelesa::checkAllItemDead() +{ + return mItem0 == 0 && mItem1 == 0 && mItem2 == 0 && mItem3 == 0; +} + +bool TBossTelesa::checkSlot() { return mSlot != nullptr; } + +void TBossTelesa::fruitCollisionOn() { mSlotStop = 0; } + +void TBossTelesa::generateSlotItem() +{ + ++mSlotItemCount; + mGenerateTimer = 0; +} + +int TBossTelesa::checkSlotResult() { return mSlot ? mSlotResult : -1; } + +void TBossTelesa::slotStop() +{ + if (mSlot) + mSlot->forceStopSlot(0); +} + +void TBossTelesa::slotStart() { rouletteStart(); } + +bool TBossTelesa::isInDamage() { return mInDamage != 0; } + +void TBossTelesa::setBckAnm(int index) +{ + if (getMActor()) + getMActor()->setBckFromIndex(index); +} + +void TBossTelesa::offAllCollision() +{ + if (mBodyCollision) + mBodyCollision->offHitFlag(HIT_FLAG_NO_COLLISION); + if (mTongueCollision) + mTongueCollision->offHitFlag(HIT_FLAG_NO_COLLISION); +} + +void TBossTelesa::onAllCollision() +{ + if (mBodyCollision) + mBodyCollision->onHitFlag(HIT_FLAG_NO_COLLISION); + if (mTongueCollision) + mTongueCollision->onHitFlag(HIT_FLAG_NO_COLLISION); +} + +void TBossTelesa::openWaterPlace() { } + +void TBossTelesa::tongueHitWater() { } + +BOOL TBossTelesa::checkMessage(THitActor* sender, u32 message) +{ + return receiveMessage(sender, message); +} + +void TBossTelesa::prepareGenerate() { mGenerateTimer = 0; } + +void TBossTelesa::rouletteStart() +{ + mRouletteTimer = 0; + mSlotStop = 0; + if (mSlot) + mSlot->moveStart(); +} + +void TBossTelesa::genAttacker() { mGenerateTimer = mSaveParams ? mSaveParams->mSLGenAttackerTime.get() : 500; } + +void TBossTelesa::flashItem(int item) +{ + mSlotResult = item; + mDamageTimer = 0; +} + +u8 TBossTelesa::slotFall() +{ + if (!mSlot) + return 1; + return mSlot->isRollDrum() == 0; +} + +u8 TBossTelesa::rouletteFall() +{ + if (mRouletteTimer > 0) + --mRouletteTimer; + return mRouletteTimer == 0; +} + +void TBossTelesa::damageRecover() +{ + if (mDamageTimer > 0) + --mDamageTimer; + if (mDamageTimer == 0) + mDamage = 0; +} + +void TBossTelesa::setSpicy(TLiveActor* actor) +{ + if (actor) + actor->onLiveFlag(LIVE_FLAG_UNK10); + mIsSpicy = 1; +} + +BOOL TBossTelesa::checkHitObject(THitActor* actor) +{ + return actor != nullptr && actor->checkActorType(ACTOR_TYPE_PLAYER); +} + +BOOL TBossTelesa::receiveMessage(THitActor*, u32) { return TRUE; } + +void TBossTelesa::perform(u32 cue, JDrama::TGraphics* graphics) +{ + TSpineEnemy::perform(cue, graphics); + if (cue & CUE_MOVE) + damageRecover(); +} + +void TBossTelesa::calcRootMatrix() { TSpineEnemy::calcRootMatrix(); } + +MtxPtr TBossTelesa::getTakingMtx() { return getModel() ? getModel()->getBaseTRMtx() : nullptr; } + +void TBossTelesa::kill() +{ + if (!checkLiveFlag(LIVE_FLAG_DEAD)) { + mDead = 1; + TSpineEnemy::kill(); + } +} + +void TBossTelesa::moveObject() +{ + TSpineEnemy::moveObject(); + if (mGenerateTimer > 0) + --mGenerateTimer; +} + +void TBossTelesa::reset() +{ + TSpineEnemy::reset(); + mDead = 0; + mDamage = 0; + mGenerateTimer = 0; + forceAllItemKill(); +} + +void TBossTelesa::loadAfter() +{ + mMarioHP = 1; + if (!mSaveParams) + mSaveParams = static_cast(getSaveParam()); +} + +void TBossTelesa::init(TLiveManager* manager) +{ + TSpineEnemy::init(manager); + mSaveParams = static_cast(getSaveParam()); + mBodyCollision = new TBossTelesaBody(this); + mTongueCollision = new TBossTelesaTongue(this); + mKillSmallEnemy = new TBossTelesaKillSmallEnemy(this); +} + +BOOL TBossTelesaKillSmallEnemy::receiveMessage(THitActor* sender, u32 message) +{ + return THitActor::receiveMessage(sender, message); +} + +void TBossTelesaKillSmallEnemy::checkHit() +{ + mHit = gpMarioPos != nullptr && mPosition.distance(*gpMarioPos) < 300.0f; + if (mHit && mOwner) + mOwner->forceHide(); +} + +BOOL TBossTelesaTongue::receiveMessage(THitActor* sender, u32 message) +{ + return THitActor::receiveMessage(sender, message); +} + +void TBossTelesaTongue::checkHit() { } + +BOOL TBossTelesaBody::receiveMessage(THitActor* sender, u32 message) +{ + if (mOwner && (message == HIT_MESSAGE_TRAMPLE || message == HIT_MESSAGE_SPRAYED_BY_WATER)) + mOwner->damageRecover(); + return THitActor::receiveMessage(sender, message); +} + +void TBossTelesaBody::checkHit() { } + +TBossTelesaManager::TBossTelesaManager(const char* name) : TEnemyManager(name) { } + +void TBossTelesaManager::perform(u32 cue, JDrama::TGraphics* graphics) +{ + TEnemyManager::perform(cue, graphics); +} + +void TBossTelesaManager::createModelData() { createModelDataArray(btelesa_model_data); } + +TSpineEnemy* TBossTelesaManager::createEnemyInstance() { return new TBossTelesa; } + +void TBossTelesaManager::load(JSUMemoryInputStream& stream) +{ + unk38 = new TBossTelesaSaveLoadParams("/enemy/bosstelesa.prm"); + TEnemyManager::load(stream); +} + +TBubble::TBubble(const char* name) + : TWalkerEnemy(name) + , mSaveParams(nullptr) + , mCarriedEnemy(nullptr) + , mHeight(0.0f) + , mIsSplit(0) + , mIsMoving(1) + , mNoEffect(0) +{ +} + +const char** TBubble::getBasNameTable() const { return bubble_bastable; } + +MtxPtr TBubble::getTakingMtx() +{ + return getModel() ? getModel()->getBaseTRMtx() : nullptr; +} + +f32 TBubble::getGravityY() const +{ + if (mIsSplit) + return mIsMoving ? 0.001f : 0.0f; + return mGravity; +} + +void TBubble::setDeadAnm() { setBckAnm(9); } + +void TBubble::attackToMario() +{ + sendAttackMsgToMario(); + kill(); +} + +void TBubble::appendEnemy() { mCarriedEnemy = nullptr; } + +void TBubble::appendItem() { } + +void TBubble::calcRootMatrix() +{ + if (!isEaten()) + mPosition.y = 150.0f + mHeight; + TWalkerEnemy::calcRootMatrix(); +} + +void TBubble::behaveToWater(THitActor*) +{ + if (mIsMoving) + kill(); +} + +void TBubble::kill() +{ + if (!checkLiveFlag(LIVE_FLAG_DEAD)) + TSmallEnemy::kill(); +} + +void TBubble::split() { mIsSplit = 1; } + +void TBubble::reset() +{ + TWalkerEnemy::reset(); + mHeight = MsRandF(50.0f, 150.0f); + mIsSplit = 0; + mIsMoving = 1; + mNoEffect = 0; + mCarriedEnemy = nullptr; +} + +void TBubble::init(TLiveManager* manager) +{ + TWalkerEnemy::init(manager); + mSaveParams = static_cast(getSaveParam()); +} + +TBubbleManager::TBubbleManager(const char* name) : TSmallEnemyManager(name) { } + +void TBubbleManager::createModelData() { createModelDataArray(bubble_model_data); } + +TSmallEnemy* TBubbleManager::createEnemyInstance() { return new TBubble; } + +void TBubbleManager::load(JSUMemoryInputStream& stream) +{ + unk38 = new TBubbleSaveLoadParams("/enemy/bubble.prm"); + TSmallEnemyManager::load(stream); +} + +/* The retail nerve bodies are intentionally kept small here. The important + * transition points (hide, roulette start, spit and bubble split) are now + * named and can be filled in independently without reintroducing anonymous + * assembly-only classes. */ +DEFINE_NERVE(TNerveBossTelesaFallDemo, TLiveActor) +{ + TBossTelesa* boss = static_cast(spine->getBody()); + if (spine->getTime() == 0) + boss->rouletteStart(); + return boss->rouletteFall() && boss->slotFall(); +} + +DEFINE_NERVE(TNerveBossTelesaFreeze, TLiveActor) +{ + return spine->getTime() > 0 && spine->getBody()->checkCurAnmEnd(0); +} + +DEFINE_NERVE(TNerveBossTelesaPrepareSlot, TLiveActor) +{ + return spine->getTime() > 30; +} + +DEFINE_NERVE(TNerveBossTelesaSpitSlotItem, TLiveActor) +{ + return spine->getTime() > 20; +} + +DEFINE_NERVE(TNerveBossTelesaSlotStart, TLiveActor) +{ + if (spine->getTime() == 0) + static_cast(spine->getBody())->rouletteStart(); + return spine->getTime() > 60; +} + +DEFINE_NERVE(TNerveBossTelesaAppear, TLiveActor) +{ + return spine->getTime() > 30; +} + +DEFINE_NERVE(TNerveBossTelesaHideWait, TLiveActor) +{ + return spine->getTime() > 60; +} + +DEFINE_NERVE(TNerveBossTelesaHide, TLiveActor) +{ + if (spine->getTime() == 0) + static_cast(spine->getBody())->forceHide(); + return spine->getTime() > 30; +} + +DEFINE_NERVE(TNerveBossTelesaSpit, TLiveActor) +{ + return spine->getTime() > 20; +} + +DEFINE_NERVE(TNerveBossTelesaDie, TLiveActor) +{ + if (spine->getTime() == 0) + static_cast(spine->getBody())->kill(); + return false; +} + +DEFINE_NERVE(TNerveBubbleSplit, TLiveActor) +{ + if (spine->getTime() == 0) + static_cast(spine->getBody())->split(); + return spine->getTime() > 10; +} + +DEFINE_NERVE(TNerveBubbleLive, TLiveActor) +{ + return spine->getTime() > 80; +} + +/* Keep a named TU initializer so the list of state singletons has a stable + * home when the remaining retail constructors are enabled. */ +extern "C" static void __sinit_bosstelesa_cpp() { } From 2f3ab37c5260b30f25d75e2c4230a0c44f230d12 Mon Sep 17 00:00:00 2001 From: KakarotCake <61133727+KakarottoCake@users.noreply.github.com> Date: Sun, 2 Aug 2026 21:37:17 -0400 Subject: [PATCH 02/18] Enemy/bosstelesa: fix CI order and actor layouts --- include/Enemy/BossTelesa.hpp | 46 +- src/Enemy/bosstelesa.cpp | 813 ++++++++++++++++++----------------- 2 files changed, 462 insertions(+), 397 deletions(-) diff --git a/include/Enemy/BossTelesa.hpp b/include/Enemy/BossTelesa.hpp index f3d3995d5..71e32f612 100644 --- a/include/Enemy/BossTelesa.hpp +++ b/include/Enemy/BossTelesa.hpp @@ -50,16 +50,16 @@ class TBossTelesaSaveLoadParams : public TSpineEnemyParams { /* 0x210 */ TParamRT mSLSpicyTime; }; -class TBubbleSaveLoadParams : public TSpineEnemyParams { +class TBubbleSaveLoadParams : public TWalkerEnemyParams { public: TBubbleSaveLoadParams(const char* path); - /* 0x0A8 */ TParamRT mSLLiveTime; - /* 0x0BC */ TParamRT mSLNumDivision; - /* 0x0D0 */ TParamRT mSLMaxScale; - /* 0x0E4 */ TParamRT mSLAddPosBase; - /* 0x0F8 */ TParamRT mSLRateExpand; - /* 0x10C */ TParamRT mSLDeadHeight; + /* 0x32C */ TParamRT mSLLiveTime; + /* 0x340 */ TParamRT mSLNumDivision; + /* 0x354 */ TParamRT mSLMaxScale; + /* 0x368 */ TParamRT mSLAddPosBase; + /* 0x37C */ TParamRT mSLRateExpand; + /* 0x390 */ TParamRT mSLDeadHeight; }; /* TSlotDrum already owns the geometry, angle and neon material fields. */ @@ -94,8 +94,13 @@ class TTelesaSlot : public TSlotDrum { /* 0x1A8 */ s8 mStop0; /* 0x1A9 */ s8 mStop1; /* 0x1AA */ s8 mStop2; + /* 0x1AB */ u8 mPad1AB[0x31]; /* 0x1DC */ TMapCollisionMove* mMapCollisionMove; /* 0x1E0 */ u8 mNeonState; + /* 0x1E1 */ u8 mPad1E1[3]; + /* 0x1E4 */ f32 mUnk1E4; + /* 0x1E8 */ f32 mUnk1E8; + /* 0x1EC */ f32 mUnk1EC; }; class TBossTelesa : public TSpineEnemy { @@ -151,10 +156,11 @@ class TBossTelesa : public TSpineEnemy { static f32 mCameraMoveLimit; static f32 mCameraMoveSp; - /* 0x150 */ s32 mBattleState; + /* 0x150 */ u8 mBattleState; + /* 0x151 */ u8 mPad151[3]; /* 0x154 */ s32 mBattleTimer; /* 0x158 */ s32 mBattlePhase; - /* 0x15C */ TLiveActor* mMario; + /* 0x15C */ TBossTelesaSaveLoadParams* mSaveParams; /* 0x160 */ s32 mCurrentItem; /* 0x164 */ s32 mCurrentFruit; /* 0x168 */ f32 mFallSpeed; @@ -163,15 +169,18 @@ class TBossTelesa : public TSpineEnemy { /* 0x174 */ THitActor* mKillSmallEnemy; /* 0x178 */ void* mItemList; /* 0x17C */ void* mBubbleList; - /* 0x180 */ TBossTelesaSaveLoadParams* mSaveParams; + /* 0x180 */ void* mUnk180; /* 0x184 */ TTelesaSlot* mSlot; /* 0x188 */ JDrama::TViewObj* mTakingActor; - /* 0x18C */ u8 mIsSpicy; + /* 0x18C */ s8 mIsSpicy; + /* 0x18D */ u8 mPad18D[0xF]; /* 0x19C */ f32 mDamageBlend; /* 0x1A0 */ f32 mDamageBlendSpeed; /* 0x1A4 */ f32 mDamageBlendTarget; /* 0x1A8 */ s32 mDamageTimer; + /* 0x1AC */ u8 mPad1AC[0xC8]; /* 0x274 */ s32 mStateTimer; + /* 0x278 */ u8 mPad278[0xD0]; /* 0x348 */ u8 mItem0; /* 0x349 */ u8 mItem1; /* 0x34A */ u8 mItem2; @@ -191,14 +200,20 @@ class TBossTelesa : public TSpineEnemy { /* 0x368 */ s32 mSlotResult; /* 0x36C */ s32 mSlotItemCount; /* 0x370 */ u8 mSlotStop; + /* 0x371 */ u8 mPad371[3]; /* 0x374 */ JGeometry::TVec3 mEffectPos; + /* 0x380 */ s32 mUnk380; /* 0x384 */ s8 mDead; + /* 0x385 */ u8 mPad385[3]; + /* 0x388 */ s32 mUnk388; }; class TBossTelesaKillSmallEnemy : public THitActor { public: TBossTelesaKillSmallEnemy(TBossTelesa* owner = nullptr) - : THitActor("ボステレサ小敵キラー"), mOwner(owner), mHit(false) + : THitActor("ボステレサ小敵キラー") + , mOwner(owner) + , mHit(false) { } @@ -212,7 +227,8 @@ class TBossTelesaKillSmallEnemy : public THitActor { class TBossTelesaTongue : public THitActor { public: TBossTelesaTongue(TBossTelesa* owner = nullptr) - : THitActor("ボステレサ舌"), mOwner(owner) + : THitActor("ボステレサ舌") + , mOwner(owner) { } @@ -224,7 +240,8 @@ class TBossTelesaTongue : public THitActor { class TBossTelesaBody : public THitActor { public: TBossTelesaBody(TBossTelesa* owner = nullptr) - : THitActor("ボステレサ本体"), mOwner(owner) + : THitActor("ボステレサ本体") + , mOwner(owner) { } @@ -266,6 +283,7 @@ class TBubble : public TWalkerEnemy { /* 0x194 */ TBubbleSaveLoadParams* mSaveParams; /* 0x198 */ TSmallEnemy* mCarriedEnemy; + /* 0x19C */ TMtx34f mTakingMatrix; /* 0x1CC */ f32 mHeight; /* 0x1D0 */ u8 mIsSplit; /* 0x1D1 */ u8 mIsMoving; diff --git a/src/Enemy/bosstelesa.cpp b/src/Enemy/bosstelesa.cpp index cb2052229..73920418b 100644 --- a/src/Enemy/bosstelesa.cpp +++ b/src/Enemy/bosstelesa.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -62,364 +63,427 @@ static const TModelDataLoadEntry bubble_model_data[] = { { nullptr, 0, 0 }, }; -MActorAnmBck* MActor::getCurBckAnmPtr() { return unkC; } - -f32 TBossTelesa::mEnemyGenRate = 0.1f; -f32 TBossTelesa::mItemGenRate = 0.1f; -u8 TBossTelesa::mNormalAlpha = 0xFF; -f32 TBossTelesa::mBaseHoseiPosY = 350.0f; -f32 TBossTelesa::mRouletteUpRate = 0.1f; +f32 TBossTelesa::mEnemyGenRate = 0.1f; +f32 TBossTelesa::mItemGenRate = 0.1f; +u8 TBossTelesa::mNormalAlpha = 0xFF; +f32 TBossTelesa::mBaseHoseiPosY = 350.0f; +f32 TBossTelesa::mRouletteUpRate = 0.1f; s32 TBossTelesa::mTelesaGenerateInterval = 600; -f32 TBossTelesa::mCameraMoveLimit = 300.0f; -f32 TBossTelesa::mCameraMoveSp = 2.0f; +f32 TBossTelesa::mCameraMoveLimit = 300.0f; +f32 TBossTelesa::mCameraMoveSp = 2.0f; -TBossTelesaSaveLoadParams::TBossTelesaSaveLoadParams(const char* path) - : TSpineEnemyParams(path) - , PARAM_INIT(mSLDamageRadius, 200) - , PARAM_INIT(mSLDamageHeight, 100) - , PARAM_INIT(mSLAttackRadius, 220) - , PARAM_INIT(mSLAttackHeight, 120) - , PARAM_INIT(mSLGenAttackerTime, 500) - , PARAM_INIT(mSLGenBubbleTime, 600) - , PARAM_INIT(mSLHitAngle, 20.0f) - , PARAM_INIT(mSLNumGenBubble, 5) - , PARAM_INIT(mSL1stBubbleSp, 10.0f) - , PARAM_INIT(mSLHideAreaRadius, 500.0f) - , PARAM_INIT(mSLSlotItemNum, 5) - , PARAM_INIT(mSLSlotFruitNum, 10) - , PARAM_INIT(mSLSlotFirstHitCollectRate, 0.1f) - , PARAM_INIT(mSLSlotHitCollectRate, 0.1f) - , PARAM_INIT(mSLTransYOffset, 350.0f) - , PARAM_INIT(mSLStopSlotTime0, 3000) - , PARAM_INIT(mSLStopSlotTime1, 2000) - , PARAM_INIT(mSLStopSlotTime2, 1000) - , PARAM_INIT(mSLSpicyTime, 2000) -{ - TParams::load(mPrmPath); -} +/* The slot angle table is deliberately kept as the retail eight-way split. */ + +/* The retail nerve bodies are intentionally kept small here. The important + * transition points (hide, roulette start, spit and bubble split) are now + * named and can be filled in independently without reintroducing anonymous + * assembly-only classes. */ + +/* Keep a named TU initializer so the list of state singletons has a stable + * home when the remaining retail constructors are enabled. */ + +extern "C" static void __sinit_bosstelesa_cpp() { } TBubbleSaveLoadParams::TBubbleSaveLoadParams(const char* path) - : TSpineEnemyParams(path) - , PARAM_INIT(mSLLiveTime, 1200) - , PARAM_INIT(mSLNumDivision, 3) - , PARAM_INIT(mSLMaxScale, 1.0f) - , PARAM_INIT(mSLAddPosBase, 20.0f) - , PARAM_INIT(mSLRateExpand, 0.01f) - , PARAM_INIT(mSLDeadHeight, 300.0f) + : TWalkerEnemyParams(path) + , PARAM_INIT(mSLLiveTime, 1200) + , PARAM_INIT(mSLNumDivision, 5) + , PARAM_INIT(mSLMaxScale, 1.5f) + , PARAM_INIT(mSLAddPosBase, 50.0f) + , PARAM_INIT(mSLRateExpand, 1.001f) + , PARAM_INIT(mSLDeadHeight, 300.0f) { TParams::load(mPrmPath); } -/* The slot angle table is deliberately kept as the retail eight-way split. */ -int TTelesaSlot::getResultFromAng(f32 angle) +TBubbleManager::TBubbleManager(const char* name) + : TSmallEnemyManager(name) { - if (angle < 44.0f) - return 0; - if (angle < 89.0f) - return 1; - if (angle < 134.0f) - return 3; - if (angle < 179.0f) - return 2; - if (angle < 224.0f) - return 0; - if (angle < 269.0f) - return 1; - if (angle < 314.0f) - return 3; - return 2; } -int TTelesaSlot::getForcastResult(int drum) +void TBubbleManager::load(JSUMemoryInputStream& stream) { - /* The actual animation advances in 45-degree steps. Forecasting only - * needs the final quantized result, so use the same normalization here. */ - f32 angle = unk13C[drum] + unk138[drum]; - while (angle >= 360.0f) - angle -= 360.0f; - while (angle <= 0.0f) - angle += 360.0f; - return getResultFromAng(45.0f * (s32)(angle / 45.0f)); + unk38 = new TBubbleSaveLoadParams("/enemy/bubble.prm"); + TSmallEnemyManager::load(stream); } -int TTelesaSlot::getSlotResult() +TSmallEnemy* TBubbleManager::createEnemyInstance() { return new TBubble; } + +void TBubbleManager::createModelData() { - int result = getResultFromAng(unk13C[0]); - for (int i = 1; i < 3; ++i) { - if (result != getResultFromAng(unk13C[i])) - return -1; - } - return result; + createModelDataArray(bubble_model_data); } -u8 TTelesaSlot::isRollDrum() +TBubble::TBubble(const char* name) + : TWalkerEnemy(name) + , mCarriedEnemy(nullptr) + , mTakingMatrix() + , mHeight(0.0f) + , mIsSplit(0) + , mIsMoving(0) { - if (mRoll0 || mRoll1 || mRoll2) - return 1; - mRolling = 0; - return 0; } -void TTelesaSlot::moveStart() +void TBubble::init(TLiveManager* manager) { - mForceStop = 1; - mRolling = 1; - mRoll0 = 1; - mRoll1 = 1; - mRoll2 = 1; - mStop0 = mStop1 = mStop2 = 0; - unk138[0] = -unk158; - unk138[1] = -0.8f * unk158; - unk138[2] = unk158; + TWalkerEnemy::init(manager); + mActorType = 0x10000020; + unk150 = 0x11; + mSaveParams = static_cast(getSaveParam()); + mSpine->initWith(&TNerveBubbleLive::theNerve()); + mMActor->setLightType(3); } -void TTelesaSlot::randomReset() +void TBubble::reset() { - for (int i = 0; i < 3; ++i) { - unk13C[i] = unk168 * (s32)MsRandF(0.0f, 8.0f); - ((&mStop0)[i]) = 0; - } + TWalkerEnemy::reset(); + onLiveFlag(LIVE_FLAG_UNK8); + mHeight = MsRandF(50.0f, 150.0f); + mIsSplit = 0; + mIsMoving = 1; + mNoEffect = 0; + mCarriedEnemy = nullptr; } -u32 TTelesaSlot::touchWater(THitActor*) { return 0; } +void TBubble::split() { mIsSplit = 1; } -void TTelesaSlot::forceStopSlot(int drum) +f32 TBubble::getGravityY() const { - if (!mForceStop) - return; - mForceResult = getForcastResult(drum); - ((&mRoll0)[drum]) = 0; - mForceStop = 0; + if (mIsSplit) + return mIsMoving ? 0.001f : 0.0f; + return mGravity; } -void TTelesaSlot::calcRootMatrix() { TSlotDrum::calcRootMatrix(); } +void TBubble::kill() +{ + if (!checkLiveFlag(LIVE_FLAG_DEAD)) + TSmallEnemy::kill(); +} -void TTelesaSlot::moveObject() { TSlotDrum::moveObject(); } +void TBubble::behaveToWater(THitActor*) +{ + if (mIsMoving) + kill(); +} -void TTelesaSlot::initMapObj() +void TBubble::attackToMario() { - TSlotDrum::initMapObj(); - mLiveFlag |= 0x10; - unk14C = 160.0f; - unk150 = mPosition.y; - unk154 = 2.0f; - unk158 = 2.0f; - unk15C = 0.01f; - unk160 = 0.5f; - unk168 = 45; - randomReset(); + sendAttackMsgToMario(); + kill(); } -void TTelesaSlot::entryObjCollision() { } +void TBubble::calcRootMatrix() +{ + if (!isEaten()) { + mPosition.y = 150.0f + (mGroundHeight + mHeight); + MsMtxSetXYZRPH(getMActor()->getModel()->getBaseTRMtx(), mPosition.x, + mPosition.y, mPosition.z, mRotation.x, mRotation.y, + mRotation.z); + getMActor()->getModel()->setBaseScale(mScaling); + } +} -void TTelesaSlot::calcObjCollision() { } +void TBubble::setDeadAnm() { setBckAnm(9); } -int TTelesaSlot::getDrumResult(int drum) +MtxPtr TBubble::getTakingMtx() { - return getResultFromAng(unk13C[drum]); + return getMActor()->getModel()->getBaseTRMtx(); } -TBossTelesa::TBossTelesa(const char* name) - : TSpineEnemy(name) - , mBattleState(1) - , mBattleTimer(0) - , mBattlePhase(0) - , mMario(nullptr) - , mCurrentItem(-1) - , mCurrentFruit(-1) - , mFallSpeed(0.0f) - , mBodyCollision(nullptr) - , mTongueCollision(nullptr) - , mKillSmallEnemy(nullptr) - , mItemList(nullptr) - , mBubbleList(nullptr) - , mSaveParams(nullptr) - , mSlot(nullptr) - , mTakingActor(nullptr) - , mIsSpicy(false) - , mDamageBlend(0.0f) - , mDamageBlendSpeed(0.0f) - , mDamageBlendTarget(0.0f) - , mDamageTimer(0) - , mStateTimer(0) - , mItem0(0) - , mItem1(0) - , mItem2(0) - , mItem3(0) - , mFruit0(0) - , mFruit1(0) - , mFruit2(0) - , mAlpha(mNormalAlpha) - , mDamage(0) - , mGenerateTimer(0) - , mMarioHP(1) - , mForceRestart(1) - , mInDamage(1) - , mRouletteTimer(0) - , mRoulettePosY(0.0f) - , mRouletteSp(0.0f) - , mSlotResult(0) - , mSlotItemCount(0) - , mSlotStop(0) - , mEffectPos() - , mDead(0) +const char** TBubble::getBasNameTable() const { return bubble_bastable; } + +const TNerveBubbleLive& TNerveBubbleLive::theNerve() { + static TNerveBubbleLive instance; + return instance; } -const char** TBossTelesa::getBasNameTable() const { return btelesa_bastable; } +void TBubble::appendItem() { } -void TBossTelesa::forceHide() +void TBubble::appendEnemy() { mCarriedEnemy = nullptr; } + +BOOL TNerveBubbleLive::execute(TSpineBase* spine) const { - mDead = 1; - offLiveFlag(LIVE_FLAG_UNK200); - onLiveFlag(LIVE_FLAG_HIDDEN); + return spine->getTime() > 80; } -void TBossTelesa::fanfale() { } +DEFINE_NERVE(TNerveBubbleSplit, TLiveActor) +{ + if (spine->getTime() == 0) + static_cast(spine->getBody())->split(); + return spine->getTime() > 10; +} -bool TBossTelesa::isForceRestart() { return mForceRestart != 0; } +TBossTelesaSaveLoadParams::TBossTelesaSaveLoadParams(const char* path) + : TSpineEnemyParams(path) + , PARAM_INIT(mSLDamageRadius, 200) + , PARAM_INIT(mSLDamageHeight, 100) + , PARAM_INIT(mSLAttackRadius, 220) + , PARAM_INIT(mSLAttackHeight, 120) + , PARAM_INIT(mSLGenAttackerTime, 500) + , PARAM_INIT(mSLGenBubbleTime, 600) + , PARAM_INIT(mSLHitAngle, 20.0f) + , PARAM_INIT(mSLNumGenBubble, 5) + , PARAM_INIT(mSL1stBubbleSp, 10.0f) + , PARAM_INIT(mSLHideAreaRadius, 500.0f) + , PARAM_INIT(mSLSlotItemNum, 5) + , PARAM_INIT(mSLSlotFruitNum, 10) + , PARAM_INIT(mSLSlotFirstHitCollectRate, 0.1f) + , PARAM_INIT(mSLSlotHitCollectRate, 0.1f) + , PARAM_INIT(mSLTransYOffset, 350.0f) + , PARAM_INIT(mSLStopSlotTime0, 3000) + , PARAM_INIT(mSLStopSlotTime1, 2000) + , PARAM_INIT(mSLStopSlotTime2, 1000) + , PARAM_INIT(mSLSpicyTime, 2000) +{ + TParams::load(mPrmPath); +} -void TBossTelesa::rollRouletteCircle() +TBossTelesaManager::TBossTelesaManager(const char* name) + : TEnemyManager(name) { - if (mSlot) - mSlot->moveStart(); } -void TBossTelesa::forceAllItemKill() +void TBossTelesaManager::load(JSUMemoryInputStream& stream) { - mItem0 = mItem1 = mItem2 = mItem3 = 0; - mFruit0 = mFruit1 = mFruit2 = 0; + unk38 = new TBossTelesaSaveLoadParams("/enemy/bosstelesa.prm"); + TEnemyManager::load(stream); } -bool TBossTelesa::checkAllItemDead() +TSpineEnemy* TBossTelesaManager::createEnemyInstance() { - return mItem0 == 0 && mItem1 == 0 && mItem2 == 0 && mItem3 == 0; + return new TBossTelesa; } -bool TBossTelesa::checkSlot() { return mSlot != nullptr; } +void TBossTelesaManager::createModelData() +{ + createModelDataArray(btelesa_model_data); +} -void TBossTelesa::fruitCollisionOn() { mSlotStop = 0; } +void TBossTelesaManager::perform(u32 cue, JDrama::TGraphics* graphics) +{ + TEnemyManager::perform(cue, graphics); +} -void TBossTelesa::generateSlotItem() +BOOL TBossTelesaBody::receiveMessage(THitActor* sender, u32 message) { - ++mSlotItemCount; - mGenerateTimer = 0; + if (mOwner + && (message == HIT_MESSAGE_TRAMPLE + || message == HIT_MESSAGE_SPRAYED_BY_WATER)) + mOwner->damageRecover(); + return THitActor::receiveMessage(sender, message); } -int TBossTelesa::checkSlotResult() { return mSlot ? mSlotResult : -1; } +void TBossTelesaBody::checkHit() { } -void TBossTelesa::slotStop() +MActorAnmBck* MActor::getCurBckAnmPtr() { return unkC; } + +void TBossTelesaTongue::checkHit() { } + +BOOL TBossTelesaTongue::receiveMessage(THitActor* sender, u32 message) { - if (mSlot) - mSlot->forceStopSlot(0); + return THitActor::receiveMessage(sender, message); } -void TBossTelesa::slotStart() { rouletteStart(); } - -bool TBossTelesa::isInDamage() { return mInDamage != 0; } +void TBossTelesaKillSmallEnemy::checkHit() +{ + mHit = gpMarioPos != nullptr && mPosition.distance(*gpMarioPos) < 300.0f; + if (mHit && mOwner) + mOwner->forceHide(); +} -void TBossTelesa::setBckAnm(int index) +BOOL TBossTelesaKillSmallEnemy::receiveMessage(THitActor* sender, u32 message) { - if (getMActor()) - getMActor()->setBckFromIndex(index); + return THitActor::receiveMessage(sender, message); } -void TBossTelesa::offAllCollision() +void TTelesaSlot::initMapObj() { - if (mBodyCollision) - mBodyCollision->offHitFlag(HIT_FLAG_NO_COLLISION); - if (mTongueCollision) - mTongueCollision->offHitFlag(HIT_FLAG_NO_COLLISION); + TSlotDrum::initMapObj(); + mLiveFlag |= 0x10; + unk14C = 160.0f; + unk150 = mPosition.y; + unk154 = 2.0f; + unk158 = 2.0f; + unk15C = 0.01f; + unk160 = 0.5f; + unk168 = 45; + randomReset(); } -void TBossTelesa::onAllCollision() +void TTelesaSlot::randomReset() { - if (mBodyCollision) - mBodyCollision->onHitFlag(HIT_FLAG_NO_COLLISION); - if (mTongueCollision) - mTongueCollision->onHitFlag(HIT_FLAG_NO_COLLISION); + for (int i = 0; i < 3; ++i) { + unk13C[i] = unk168 * (s32)MsRandF(0.0f, 8.0f); + ((&mStop0)[i]) = 0; + } } -void TBossTelesa::openWaterPlace() { } +void TTelesaSlot::calcRootMatrix() { TSlotDrum::calcRootMatrix(); } -void TBossTelesa::tongueHitWater() { } +void TTelesaSlot::moveObject() { TSlotDrum::moveObject(); } -BOOL TBossTelesa::checkMessage(THitActor* sender, u32 message) +void TTelesaSlot::moveStart() { - return receiveMessage(sender, message); + mForceStop = 1; + mRolling = 1; + mRoll0 = 1; + mRoll1 = 1; + mRoll2 = 1; + mStop0 = mStop1 = mStop2 = 0; + unk138[0] = -unk158; + unk138[1] = -0.8f * unk158; + unk138[2] = unk158; } -void TBossTelesa::prepareGenerate() { mGenerateTimer = 0; } +u32 TTelesaSlot::touchWater(THitActor*) { return 0; } -void TBossTelesa::rouletteStart() +void TTelesaSlot::forceStopSlot(int drum) { - mRouletteTimer = 0; - mSlotStop = 0; - if (mSlot) - mSlot->moveStart(); + if (!mForceStop) + return; + mForceResult = getForcastResult(drum); + ((&mRoll0)[drum]) = 0; + mForceStop = 0; } -void TBossTelesa::genAttacker() { mGenerateTimer = mSaveParams ? mSaveParams->mSLGenAttackerTime.get() : 500; } +u8 TTelesaSlot::isRollDrum() +{ + if (mRoll0) + return 1; + if (mRoll1) + return 1; + if (mRoll2) + return 1; + mRolling = 0; + return 0; +} -void TBossTelesa::flashItem(int item) +int TTelesaSlot::getSlotResult() { - mSlotResult = item; - mDamageTimer = 0; + int result = getResultFromAng(unk13C[0]); + int i = 1; + do { + if (result != getResultFromAng(unk13C[i])) + return -1; + ++i; + } while (i < 3); + return result; } -u8 TBossTelesa::slotFall() +int TTelesaSlot::getDrumResult(int drum) { - if (!mSlot) - return 1; - return mSlot->isRollDrum() == 0; + return getResultFromAng(unk13C[drum]); } -u8 TBossTelesa::rouletteFall() +int TTelesaSlot::getForcastResult(int drum) { - if (mRouletteTimer > 0) - --mRouletteTimer; - return mRouletteTimer == 0; + f32 angle = unk13C[drum]; + f32 speed = unk138[drum]; + + do { + if (fabsf(speed) > unk160) { + angle += speed; + if (speed > 0.0f) + speed -= unk15C; + else + speed += unk15C; + + if (angle >= 360.0f) + angle -= 360.0f; + if (angle <= 0.0f) + angle += 360.0f; + continue; + } + + angle += speed; + if (angle >= 360.0f) + angle -= 360.0f; + if (angle <= 0.0f) + angle += 360.0f; + } while ((s32)fabsf(angle) % unk168 != 0); + + return getResultFromAng((f32)(unk168 * (s32)(angle / (f32)unk168))); } -void TBossTelesa::damageRecover() +int TTelesaSlot::getResultFromAng(f32 angle) { - if (mDamageTimer > 0) - --mDamageTimer; - if (mDamageTimer == 0) - mDamage = 0; + if (angle < 44.0f) + return 0; + if (angle < 89.0f) + return 1; + if (angle < 134.0f) + return 3; + if (angle < 179.0f) + return 2; + if (angle < 224.0f) + return 0; + if (angle < 269.0f) + return 1; + if (angle < 314.0f) + return 3; + if (angle < 359.0f) + return 2; + return 2; } -void TBossTelesa::setSpicy(TLiveActor* actor) +void TTelesaSlot::calcObjCollision() { } + +void TTelesaSlot::entryObjCollision() { } + +TBossTelesa::TBossTelesa(const char* name) + : TSpineEnemy(name) + , mBattleState(1) + , mBattleTimer(0) + , mBattlePhase(0) + , mSaveParams(nullptr) + , mCurrentItem(-1) + , mCurrentFruit(-1) + , mFallSpeed(0.0f) + , mBodyCollision(nullptr) + , mSlot(nullptr) + , mTakingActor(nullptr) + , mIsSpicy(0) + , mDamageTimer(0) + , mStateTimer(0) + , mDamage(0) + , mGenerateTimer(0) + , mMarioHP(0) + , mForceRestart(1) + , mInDamage(1) + , mRouletteTimer(0) + , mRoulettePosY(0.0f) + , mRouletteSp(0.0f) + , mSlotResult(0) + , mSlotItemCount(0) + , mSlotStop(3) + , mDead(0) { - if (actor) - actor->onLiveFlag(LIVE_FLAG_UNK10); - mIsSpicy = 1; } -BOOL TBossTelesa::checkHitObject(THitActor* actor) +void TBossTelesa::init(TLiveManager* manager) { - return actor != nullptr && actor->checkActorType(ACTOR_TYPE_PLAYER); + TSpineEnemy::init(manager); + mSaveParams = static_cast(getSaveParam()); + mBodyCollision = new TBossTelesaBody(this); + mTongueCollision = new TBossTelesaTongue(this); + mKillSmallEnemy = new TBossTelesaKillSmallEnemy(this); } -BOOL TBossTelesa::receiveMessage(THitActor*, u32) { return TRUE; } - -void TBossTelesa::perform(u32 cue, JDrama::TGraphics* graphics) +void TBossTelesa::loadAfter() { - TSpineEnemy::perform(cue, graphics); - if (cue & CUE_MOVE) - damageRecover(); + mMarioHP = 1; + if (!mSaveParams) + mSaveParams = static_cast(getSaveParam()); } -void TBossTelesa::calcRootMatrix() { TSpineEnemy::calcRootMatrix(); } - -MtxPtr TBossTelesa::getTakingMtx() { return getModel() ? getModel()->getBaseTRMtx() : nullptr; } - -void TBossTelesa::kill() +void TBossTelesa::reset() { - if (!checkLiveFlag(LIVE_FLAG_DEAD)) { - mDead = 1; - TSpineEnemy::kill(); - } + TSpineEnemy::reset(); + mDead = 0; + mDamage = 0; + mGenerateTimer = 0; + forceAllItemKill(); } void TBossTelesa::moveObject() @@ -429,198 +493,181 @@ void TBossTelesa::moveObject() --mGenerateTimer; } -void TBossTelesa::reset() +void TBossTelesa::kill() { - TSpineEnemy::reset(); - mDead = 0; - mDamage = 0; - mGenerateTimer = 0; - forceAllItemKill(); + if (!checkLiveFlag(LIVE_FLAG_DEAD)) { + mDead = 1; + TSpineEnemy::kill(); + } } -void TBossTelesa::loadAfter() +MtxPtr TBossTelesa::getTakingMtx() { - mMarioHP = 1; - if (!mSaveParams) - mSaveParams = static_cast(getSaveParam()); + return getModel() ? getModel()->getBaseTRMtx() : nullptr; } -void TBossTelesa::init(TLiveManager* manager) -{ - TSpineEnemy::init(manager); - mSaveParams = static_cast(getSaveParam()); - mBodyCollision = new TBossTelesaBody(this); - mTongueCollision = new TBossTelesaTongue(this); - mKillSmallEnemy = new TBossTelesaKillSmallEnemy(this); -} +void TBossTelesa::prepareGenerate() { mGenerateTimer = 0; } -BOOL TBossTelesaKillSmallEnemy::receiveMessage(THitActor* sender, u32 message) +void TBossTelesa::calcRootMatrix() { TSpineEnemy::calcRootMatrix(); } + +void TBossTelesa::perform(u32 cue, JDrama::TGraphics* graphics) { - return THitActor::receiveMessage(sender, message); + TSpineEnemy::perform(cue, graphics); + if (cue & CUE_MOVE) + damageRecover(); } -void TBossTelesaKillSmallEnemy::checkHit() +BOOL TBossTelesa::receiveMessage(THitActor*, u32) { return TRUE; } + +BOOL TBossTelesa::checkMessage(THitActor* sender, u32 message) { - mHit = gpMarioPos != nullptr && mPosition.distance(*gpMarioPos) < 300.0f; - if (mHit && mOwner) - mOwner->forceHide(); + return receiveMessage(sender, message); } -BOOL TBossTelesaTongue::receiveMessage(THitActor* sender, u32 message) +BOOL TBossTelesa::checkHitObject(THitActor* actor) { - return THitActor::receiveMessage(sender, message); + return actor != nullptr && actor->checkActorType(ACTOR_TYPE_PLAYER); } -void TBossTelesaTongue::checkHit() { } - -BOOL TBossTelesaBody::receiveMessage(THitActor* sender, u32 message) +void TBossTelesa::setSpicy(TLiveActor* actor) { - if (mOwner && (message == HIT_MESSAGE_TRAMPLE || message == HIT_MESSAGE_SPRAYED_BY_WATER)) - mOwner->damageRecover(); - return THitActor::receiveMessage(sender, message); + if (actor) + actor->onLiveFlag(LIVE_FLAG_UNK10); + mIsSpicy = 1; } -void TBossTelesaBody::checkHit() { } - -TBossTelesaManager::TBossTelesaManager(const char* name) : TEnemyManager(name) { } - -void TBossTelesaManager::perform(u32 cue, JDrama::TGraphics* graphics) +void TBossTelesa::damageRecover() { - TEnemyManager::perform(cue, graphics); + if (mDamageTimer > 0) + --mDamageTimer; + if (mDamageTimer == 0) + mDamage = 0; } -void TBossTelesaManager::createModelData() { createModelDataArray(btelesa_model_data); } - -TSpineEnemy* TBossTelesaManager::createEnemyInstance() { return new TBossTelesa; } +void TBossTelesa::tongueHitWater() { } -void TBossTelesaManager::load(JSUMemoryInputStream& stream) +u8 TBossTelesa::rouletteFall() { - unk38 = new TBossTelesaSaveLoadParams("/enemy/bosstelesa.prm"); - TEnemyManager::load(stream); + if (mRouletteTimer > 0) + --mRouletteTimer; + return mRouletteTimer == 0; } -TBubble::TBubble(const char* name) - : TWalkerEnemy(name) - , mSaveParams(nullptr) - , mCarriedEnemy(nullptr) - , mHeight(0.0f) - , mIsSplit(0) - , mIsMoving(1) - , mNoEffect(0) +u8 TBossTelesa::slotFall() { + if (!mSlot) + return 1; + return mSlot->isRollDrum() == 0; } -const char** TBubble::getBasNameTable() const { return bubble_bastable; } +void TBossTelesa::openWaterPlace() { } -MtxPtr TBubble::getTakingMtx() +void TBossTelesa::flashItem(int item) { - return getModel() ? getModel()->getBaseTRMtx() : nullptr; + mSlotResult = item; + mDamageTimer = 0; } -f32 TBubble::getGravityY() const +void TBossTelesa::onAllCollision() { - if (mIsSplit) - return mIsMoving ? 0.001f : 0.0f; - return mGravity; + if (mBodyCollision) + mBodyCollision->onHitFlag(HIT_FLAG_NO_COLLISION); + if (mTongueCollision) + mTongueCollision->onHitFlag(HIT_FLAG_NO_COLLISION); } -void TBubble::setDeadAnm() { setBckAnm(9); } - -void TBubble::attackToMario() +void TBossTelesa::offAllCollision() { - sendAttackMsgToMario(); - kill(); + if (mBodyCollision) + mBodyCollision->offHitFlag(HIT_FLAG_NO_COLLISION); + if (mTongueCollision) + mTongueCollision->offHitFlag(HIT_FLAG_NO_COLLISION); } -void TBubble::appendEnemy() { mCarriedEnemy = nullptr; } - -void TBubble::appendItem() { } +const char** TBossTelesa::getBasNameTable() const { return btelesa_bastable; } -void TBubble::calcRootMatrix() +void TBossTelesa::genAttacker() { - if (!isEaten()) - mPosition.y = 150.0f + mHeight; - TWalkerEnemy::calcRootMatrix(); + mGenerateTimer = mSaveParams ? mSaveParams->mSLGenAttackerTime.get() : 500; } -void TBubble::behaveToWater(THitActor*) +void TBossTelesa::setBckAnm(int index) { - if (mIsMoving) - kill(); + if (getMActor()) + getMActor()->setBckFromIndex(index); } -void TBubble::kill() +bool TBossTelesa::isInDamage() { return mInDamage != 0; } + +void TBossTelesa::rouletteStart() { - if (!checkLiveFlag(LIVE_FLAG_DEAD)) - TSmallEnemy::kill(); + mRouletteTimer = 0; + mSlotStop = 0; + if (mSlot) + mSlot->moveStart(); } -void TBubble::split() { mIsSplit = 1; } +void TBossTelesa::slotStart() { rouletteStart(); } -void TBubble::reset() +void TBossTelesa::slotStop() { - TWalkerEnemy::reset(); - mHeight = MsRandF(50.0f, 150.0f); - mIsSplit = 0; - mIsMoving = 1; - mNoEffect = 0; - mCarriedEnemy = nullptr; + if (mSlot) + mSlot->forceStopSlot(0); } -void TBubble::init(TLiveManager* manager) +int TBossTelesa::checkSlotResult() { return mSlot ? mSlotResult : -1; } + +void TBossTelesa::generateSlotItem() { - TWalkerEnemy::init(manager); - mSaveParams = static_cast(getSaveParam()); + ++mSlotItemCount; + mGenerateTimer = 0; } -TBubbleManager::TBubbleManager(const char* name) : TSmallEnemyManager(name) { } - -void TBubbleManager::createModelData() { createModelDataArray(bubble_model_data); } +void TBossTelesa::fruitCollisionOn() { mSlotStop = 0; } -TSmallEnemy* TBubbleManager::createEnemyInstance() { return new TBubble; } +bool TBossTelesa::checkSlot() { return mSlot != nullptr; } -void TBubbleManager::load(JSUMemoryInputStream& stream) +bool TBossTelesa::checkAllItemDead() { - unk38 = new TBubbleSaveLoadParams("/enemy/bubble.prm"); - TSmallEnemyManager::load(stream); + return mItem0 == 0 && mItem1 == 0 && mItem2 == 0 && mItem3 == 0; } -/* The retail nerve bodies are intentionally kept small here. The important - * transition points (hide, roulette start, spit and bubble split) are now - * named and can be filled in independently without reintroducing anonymous - * assembly-only classes. */ -DEFINE_NERVE(TNerveBossTelesaFallDemo, TLiveActor) +void TBossTelesa::forceAllItemKill() { - TBossTelesa* boss = static_cast(spine->getBody()); - if (spine->getTime() == 0) - boss->rouletteStart(); - return boss->rouletteFall() && boss->slotFall(); + mItem0 = mItem1 = mItem2 = mItem3 = 0; + mFruit0 = mFruit1 = mFruit2 = 0; } -DEFINE_NERVE(TNerveBossTelesaFreeze, TLiveActor) +void TBossTelesa::rollRouletteCircle() { - return spine->getTime() > 0 && spine->getBody()->checkCurAnmEnd(0); + if (mSlot) + mSlot->moveStart(); } -DEFINE_NERVE(TNerveBossTelesaPrepareSlot, TLiveActor) -{ - return spine->getTime() > 30; -} +bool TBossTelesa::isForceRestart() { return mForceRestart != 0; } -DEFINE_NERVE(TNerveBossTelesaSpitSlotItem, TLiveActor) +void TBossTelesa::forceHide() { - return spine->getTime() > 20; + mDead = 1; + offLiveFlag(LIVE_FLAG_UNK200); + onLiveFlag(LIVE_FLAG_HIDDEN); } -DEFINE_NERVE(TNerveBossTelesaSlotStart, TLiveActor) +void TBossTelesa::fanfale() { } + +DEFINE_NERVE(TNerveBossTelesaDie, TLiveActor) { if (spine->getTime() == 0) - static_cast(spine->getBody())->rouletteStart(); - return spine->getTime() > 60; + static_cast(spine->getBody())->kill(); + return false; } -DEFINE_NERVE(TNerveBossTelesaAppear, TLiveActor) +DEFINE_NERVE(TNerveBossTelesaSpit, TLiveActor) { return spine->getTime() > 20; } + +DEFINE_NERVE(TNerveBossTelesaHide, TLiveActor) { + if (spine->getTime() == 0) + static_cast(spine->getBody())->forceHide(); return spine->getTime() > 30; } @@ -629,37 +676,37 @@ DEFINE_NERVE(TNerveBossTelesaHideWait, TLiveActor) return spine->getTime() > 60; } -DEFINE_NERVE(TNerveBossTelesaHide, TLiveActor) +DEFINE_NERVE(TNerveBossTelesaAppear, TLiveActor) { - if (spine->getTime() == 0) - static_cast(spine->getBody())->forceHide(); return spine->getTime() > 30; } -DEFINE_NERVE(TNerveBossTelesaSpit, TLiveActor) +DEFINE_NERVE(TNerveBossTelesaSlotStart, TLiveActor) { - return spine->getTime() > 20; + if (spine->getTime() == 0) + static_cast(spine->getBody())->rouletteStart(); + return spine->getTime() > 60; } -DEFINE_NERVE(TNerveBossTelesaDie, TLiveActor) +DEFINE_NERVE(TNerveBossTelesaSpitSlotItem, TLiveActor) { - if (spine->getTime() == 0) - static_cast(spine->getBody())->kill(); - return false; + return spine->getTime() > 20; } -DEFINE_NERVE(TNerveBubbleSplit, TLiveActor) +DEFINE_NERVE(TNerveBossTelesaPrepareSlot, TLiveActor) { - if (spine->getTime() == 0) - static_cast(spine->getBody())->split(); - return spine->getTime() > 10; + return spine->getTime() > 30; } -DEFINE_NERVE(TNerveBubbleLive, TLiveActor) +DEFINE_NERVE(TNerveBossTelesaFreeze, TLiveActor) { - return spine->getTime() > 80; + return spine->getTime() > 0 && spine->getBody()->checkCurAnmEnd(0); } -/* Keep a named TU initializer so the list of state singletons has a stable - * home when the remaining retail constructors are enabled. */ -extern "C" static void __sinit_bosstelesa_cpp() { } +DEFINE_NERVE(TNerveBossTelesaFallDemo, TLiveActor) +{ + TBossTelesa* boss = static_cast(spine->getBody()); + if (spine->getTime() == 0) + boss->rouletteStart(); + return boss->rouletteFall() && boss->slotFall(); +} From 04471e8c47dff3abde4d2d5c36d0dc4f42760d96 Mon Sep 17 00:00:00 2001 From: KakarotCake <61133727+KakarottoCake@users.noreply.github.com> Date: Sun, 2 Aug 2026 22:03:37 -0400 Subject: [PATCH 03/18] Enemy/bosstelesa: decompile boss behavior --- include/Enemy/BossTelesa.hpp | 323 ++-- include/Strategic/HitActor.hpp | 4 + src/Enemy/bosstelesa.cpp | 2850 ++++++++++++++++++++++++++++---- 3 files changed, 2720 insertions(+), 457 deletions(-) diff --git a/include/Enemy/BossTelesa.hpp b/include/Enemy/BossTelesa.hpp index 71e32f612..d933ea4d9 100644 --- a/include/Enemy/BossTelesa.hpp +++ b/include/Enemy/BossTelesa.hpp @@ -1,33 +1,18 @@ #ifndef ENEMY_BOSS_TELESA_HPP #define ENEMY_BOSS_TELESA_HPP +#include #include -#include -#include +#include +#include +#include #include -#include - -class TBossTelesa; -class TBubble; - -/* The boss uses the same spine state objects as the regular Telesa, but has - * its own state machine for the roulette, tongue and bubble attacks. */ -DECLARE_NERVE(TNerveBossTelesaFallDemo, TLiveActor); -DECLARE_NERVE(TNerveBossTelesaFreeze, TLiveActor); -DECLARE_NERVE(TNerveBossTelesaPrepareSlot, TLiveActor); -DECLARE_NERVE(TNerveBossTelesaSpitSlotItem, TLiveActor); -DECLARE_NERVE(TNerveBossTelesaSlotStart, TLiveActor); -DECLARE_NERVE(TNerveBossTelesaAppear, TLiveActor); -DECLARE_NERVE(TNerveBossTelesaHideWait, TLiveActor); -DECLARE_NERVE(TNerveBossTelesaHide, TLiveActor); -DECLARE_NERVE(TNerveBossTelesaSpit, TLiveActor); -DECLARE_NERVE(TNerveBossTelesaDie, TLiveActor); -DECLARE_NERVE(TNerveBubbleSplit, TLiveActor); -DECLARE_NERVE(TNerveBubbleLive, TLiveActor); +#include +#include class TBossTelesaSaveLoadParams : public TSpineEnemyParams { public: - TBossTelesaSaveLoadParams(const char* path); + TBossTelesaSaveLoadParams(const char*); /* 0x0A8 */ TParamRT mSLDamageRadius; /* 0x0BC */ TParamRT mSLDamageHeight; @@ -50,66 +35,69 @@ class TBossTelesaSaveLoadParams : public TSpineEnemyParams { /* 0x210 */ TParamRT mSLSpicyTime; }; -class TBubbleSaveLoadParams : public TWalkerEnemyParams { -public: - TBubbleSaveLoadParams(const char* path); - - /* 0x32C */ TParamRT mSLLiveTime; - /* 0x340 */ TParamRT mSLNumDivision; - /* 0x354 */ TParamRT mSLMaxScale; - /* 0x368 */ TParamRT mSLAddPosBase; - /* 0x37C */ TParamRT mSLRateExpand; - /* 0x390 */ TParamRT mSLDeadHeight; -}; +class TBossTelesa; -/* TSlotDrum already owns the geometry, angle and neon material fields. */ class TTelesaSlot : public TSlotDrum { public: - TTelesaSlot(const char* name); + TTelesaSlot(const char* name) + : TSlotDrum(name) + , unk1A0(nullptr) + , unk1A4(0) + { + unk198 = 0; + unk199 = 0; + unk19A = 0; + unk19B = 0; + unk19C = 0; + unk1A8 = 0; + unk1A9 = 0; + unk1AA = 0; + } virtual void calcRootMatrix(); - virtual void moveObject(); virtual void initMapObj(); + virtual void moveObject(); virtual u32 touchWater(THitActor*); virtual void initNeonMatColor() { } + void randomReset(); + void moveStart(); + void forceStopSlot(int); + BOOL isRollDrum(); + int getSlotResult(); int getForcastResult(int); int getResultFromAng(f32); - int getSlotResult(); - u8 isRollDrum(); - void forceStopSlot(int); - void moveStart(); - void randomReset(); + f32* getDrumSpeeds() const { return unk138; } void entryObjCollision(); void calcObjCollision(); int getDrumResult(int); - /* 0x198 */ u8 mRoll0; - /* 0x199 */ u8 mRoll1; - /* 0x19A */ u8 mRoll2; - /* 0x19B */ s8 mRolling; - /* 0x19C */ u8 mForceStop; - /* 0x1A0 */ TBossTelesa* mOwner; - /* 0x1A4 */ s32 mForceResult; - /* 0x1A8 */ s8 mStop0; - /* 0x1A9 */ s8 mStop1; - /* 0x1AA */ s8 mStop2; - /* 0x1AB */ u8 mPad1AB[0x31]; - /* 0x1DC */ TMapCollisionMove* mMapCollisionMove; - /* 0x1E0 */ u8 mNeonState; - /* 0x1E1 */ u8 mPad1E1[3]; - /* 0x1E4 */ f32 mUnk1E4; - /* 0x1E8 */ f32 mUnk1E8; - /* 0x1EC */ f32 mUnk1EC; + /* 0x198 */ u8 unk198; + /* 0x199 */ u8 unk199; + /* 0x19A */ u8 unk19A; + /* 0x19B */ u8 unk19B; + /* 0x19C */ u8 unk19C; + /* 0x19D */ u8 unk19D[3]; + /* 0x1A0 */ void* unk1A0; + /* 0x1A4 */ s32 unk1A4; + /* 0x1A8 */ u8 unk1A8; + /* 0x1A9 */ u8 unk1A9; + /* 0x1AA */ u8 unk1AA; + /* 0x1AB */ u8 unk1AB[0x31]; + /* 0x1DC */ TMapCollisionMove* unk1DC; + /* 0x1E0 */ u8 unk1E0; + /* 0x1E1 */ u8 unk1E1[3]; + /* 0x1E4 */ f32 unk1E4[3]; }; class TBossTelesa : public TSpineEnemy { public: - TBossTelesa(const char* name = "ボステレサ"); + TBossTelesa(const char*); virtual void loadAfter(); - virtual void perform(u32 cue, JDrama::TGraphics* graphics); + virtual void perform(u32, JDrama::TGraphics*); virtual BOOL receiveMessage(THitActor*, u32); + virtual MtxPtr getTakingMtx(); virtual void init(TLiveManager*); virtual void calcRootMatrix(); virtual void moveObject(); @@ -129,174 +117,201 @@ class TBossTelesa : public TSpineEnemy { int checkSlotResult(); void slotStop(); void slotStart(); + void rouletteStart(); bool isInDamage(); void setBckAnm(int); + void genAttacker(); void offAllCollision(); void onAllCollision(); + void flashItem(int); void openWaterPlace(); + BOOL slotFall(); + BOOL rouletteFall(); void tongueHitWater(); - BOOL checkMessage(THitActor*, u32); - void prepareGenerate(); - void rouletteStart(); - void genAttacker(); - void flashItem(int); - u8 slotFall(); - u8 rouletteFall(); void damageRecover(); void setSpicy(TLiveActor*); - BOOL checkHitObject(THitActor*); - MtxPtr getTakingMtx(); + void checkHitObject(THitActor*); + BOOL checkMessage(THitActor*, u32); + void prepareGenerate(); static f32 mEnemyGenRate; static f32 mItemGenRate; static u8 mNormalAlpha; static f32 mBaseHoseiPosY; static f32 mRouletteUpRate; - static s32 mTelesaGenerateInterval; + static u32 mTelesaGenerateInterval; static f32 mCameraMoveLimit; static f32 mCameraMoveSp; - /* 0x150 */ u8 mBattleState; - /* 0x151 */ u8 mPad151[3]; - /* 0x154 */ s32 mBattleTimer; - /* 0x158 */ s32 mBattlePhase; - /* 0x15C */ TBossTelesaSaveLoadParams* mSaveParams; - /* 0x160 */ s32 mCurrentItem; - /* 0x164 */ s32 mCurrentFruit; - /* 0x168 */ f32 mFallSpeed; - /* 0x16C */ THitActor* mBodyCollision; - /* 0x170 */ THitActor* mTongueCollision; - /* 0x174 */ THitActor* mKillSmallEnemy; - /* 0x178 */ void* mItemList; - /* 0x17C */ void* mBubbleList; - /* 0x180 */ void* mUnk180; - /* 0x184 */ TTelesaSlot* mSlot; - /* 0x188 */ JDrama::TViewObj* mTakingActor; - /* 0x18C */ s8 mIsSpicy; - /* 0x18D */ u8 mPad18D[0xF]; - /* 0x19C */ f32 mDamageBlend; - /* 0x1A0 */ f32 mDamageBlendSpeed; - /* 0x1A4 */ f32 mDamageBlendTarget; - /* 0x1A8 */ s32 mDamageTimer; - /* 0x1AC */ u8 mPad1AC[0xC8]; - /* 0x274 */ s32 mStateTimer; - /* 0x278 */ u8 mPad278[0xD0]; - /* 0x348 */ u8 mItem0; - /* 0x349 */ u8 mItem1; - /* 0x34A */ u8 mItem2; - /* 0x34B */ u8 mItem3; - /* 0x34C */ u8 mFruit0; - /* 0x34D */ u8 mFruit1; - /* 0x34E */ u8 mFruit2; - /* 0x34F */ u8 mAlpha; - /* 0x350 */ u8 mDamage; - /* 0x354 */ s32 mGenerateTimer; - /* 0x358 */ s16 mMarioHP; - /* 0x35A */ u8 mForceRestart; - /* 0x35B */ u8 mInDamage; - /* 0x35C */ s32 mRouletteTimer; - /* 0x360 */ f32 mRoulettePosY; - /* 0x364 */ f32 mRouletteSp; - /* 0x368 */ s32 mSlotResult; - /* 0x36C */ s32 mSlotItemCount; - /* 0x370 */ u8 mSlotStop; - /* 0x371 */ u8 mPad371[3]; - /* 0x374 */ JGeometry::TVec3 mEffectPos; - /* 0x380 */ s32 mUnk380; - /* 0x384 */ s8 mDead; - /* 0x385 */ u8 mPad385[3]; - /* 0x388 */ s32 mUnk388; +public: + /* 0x150 */ u8 unk150; + /* 0x151 */ u8 unk151[0x3]; + /* 0x154 */ TTelesaSlot* unk154; + /* 0x158 */ void* unk158; + /* 0x15C */ void* unk15C; + /* 0x160 */ s32 unk160; + /* 0x164 */ s32 unk164; + /* 0x168 */ f32 unk168; + /* 0x16C */ THitActor* unk16C; + /* 0x170 */ THitActor* unk170; + /* 0x174 */ THitActor* unk174; + /* 0x178 */ TRoulette* unk178; + /* 0x17C */ TRoulette* unk17C; + /* 0x180 */ TRoulette* unk180; + /* 0x184 */ TTelesaSlot* unk184; + /* 0x188 */ JDrama::TViewObj* unk188; + /* 0x18C */ u8 unk18C; + /* 0x18D */ u8 unk18D[0xF]; + /* 0x19C */ JGeometry::TVec3 unk19C; + /* 0x1A8 */ s32 unk1A8; + /* 0x1AC */ TLiveActor* unk1AC[50]; + /* 0x274 */ s32 unk274; + /* 0x278 */ JGeometry::TMatrix34 > unk278; + /* 0x2A8 */ TLiveActor* unk2A8[20]; + /* 0x2F8 */ TLiveActor* unk2F8[10]; + /* 0x320 */ TLiveActor* unk320[10]; + /* 0x348 */ GXColor unk348; + /* 0x34C */ GXColor unk34C; + /* 0x350 */ u8 unk350; + /* 0x351 */ u8 unk351[0x3]; + /* 0x354 */ TObjManager* unk354; + /* 0x358 */ u16 unk358; + /* 0x35A */ u8 unk35A; + /* 0x35B */ u8 unk35B; + /* 0x35C */ s32 unk35C; + /* 0x360 */ f32 unk360; + /* 0x364 */ f32 unk364; + /* 0x368 */ s32 unk368; + /* 0x36C */ s32 unk36C; + /* 0x370 */ u8 unk370; + /* 0x371 */ u8 unk371[0x3]; + /* 0x374 */ JGeometry::TVec3 unk374; + /* 0x380 */ s32 unk380; + /* 0x384 */ u8 unk384; + /* 0x385 */ u8 unk385[0x3]; + /* 0x388 */ s32 unk388; }; -class TBossTelesaKillSmallEnemy : public THitActor { +class TBossTelesaBody : public THitActor { public: - TBossTelesaKillSmallEnemy(TBossTelesa* owner = nullptr) - : THitActor("ボステレサ小敵キラー") - , mOwner(owner) - , mHit(false) + TBossTelesaBody(const char* name) + : THitActor(name) + , unk6C(0) { } - virtual BOOL receiveMessage(THitActor* sender, u32 message); + virtual BOOL receiveMessage(THitActor*, u32); void checkHit(); - /* 0x68 */ TBossTelesa* mOwner; - /* 0x6C */ bool mHit; +public: + /* 0x68 */ TBossTelesa* unk68; + /* 0x6C */ u8 unk6C; }; class TBossTelesaTongue : public THitActor { public: - TBossTelesaTongue(TBossTelesa* owner = nullptr) - : THitActor("ボステレサ舌") - , mOwner(owner) + TBossTelesaTongue(const char* name) + : THitActor(name) { } virtual BOOL receiveMessage(THitActor*, u32); void checkHit(); - TBossTelesa* mOwner; + +public: + /* 0x68 */ TBossTelesa* unk68; }; -class TBossTelesaBody : public THitActor { +class TBossTelesaKillSmallEnemy : public THitActor { public: - TBossTelesaBody(TBossTelesa* owner = nullptr) - : THitActor("ボステレサ本体") - , mOwner(owner) + TBossTelesaKillSmallEnemy(const char* name) + : THitActor(name) + , unk68(nullptr) + , unk6C(0) { } - virtual BOOL receiveMessage(THitActor*, u32); void checkHit(); - TBossTelesa* mOwner; + +public: + /* 0x68 */ TBossTelesa* unk68; + /* 0x6C */ u8 unk6C; }; class TBossTelesaManager : public TEnemyManager { public: - TBossTelesaManager(const char* name = "ボステレサマネージャー"); + TBossTelesaManager(const char*); virtual void load(JSUMemoryInputStream&); - virtual void perform(u32 cue, JDrama::TGraphics* graphics); + virtual void perform(u32, JDrama::TGraphics*); virtual void createModelData(); virtual TSpineEnemy* createEnemyInstance(); virtual void clipEnemies(JDrama::TGraphics*) { } }; +class TBubbleSaveLoadParams : public TWalkerEnemyParams { +public: + TBubbleSaveLoadParams(const char*); + + /* 0x32C */ TParamRT mSLLiveTime; + /* 0x340 */ TParamRT mSLNumDivision; + /* 0x354 */ TParamRT mSLMaxScale; + /* 0x368 */ TParamRT mSLAddPosBase; + /* 0x37C */ TParamRT mSLRateExpand; + /* 0x390 */ TParamRT mSLDeadHeight; +}; + class TBubble : public TWalkerEnemy { public: TBubble(const char* name = "バブル"); + virtual MtxPtr getTakingMtx(); virtual void init(TLiveManager*); virtual void calcRootMatrix(); - virtual void behaveToWater(THitActor*); virtual void kill(); virtual f32 getGravityY() const; virtual const char** getBasNameTable() const; virtual void reset(); + virtual void behaveToWater(THitActor*); + virtual void setDeadAnm(); + virtual void attackToMario(); + virtual void setAfterDeadEffect() { } void appendEnemy(); void appendItem(); - void setDeadAnm(); - void attackToMario(); void split(); - void setAfterDeadEffect() { } - MtxPtr getTakingMtx(); - - /* 0x194 */ TBubbleSaveLoadParams* mSaveParams; - /* 0x198 */ TSmallEnemy* mCarriedEnemy; - /* 0x19C */ TMtx34f mTakingMatrix; - /* 0x1CC */ f32 mHeight; - /* 0x1D0 */ u8 mIsSplit; - /* 0x1D1 */ u8 mIsMoving; - /* 0x1D2 */ u8 mNoEffect; + +public: + /* 0x194 */ TBubbleSaveLoadParams* unk194; + /* 0x198 */ TLiveActor* unk198; + /* 0x19C */ JGeometry::TMatrix34 > unk19C; + /* 0x1CC */ f32 unk1CC; + /* 0x1D0 */ u8 unk1D0; + /* 0x1D1 */ u8 unk1D1; + /* 0x1D2 */ u8 unk1D2; + /* 0x1D3 */ u8 unk1D3; }; class TBubbleManager : public TSmallEnemyManager { public: - TBubbleManager(const char* name = "バブルマネージャー"); + TBubbleManager(const char*); virtual void load(JSUMemoryInputStream&); virtual void createModelData(); virtual TSmallEnemy* createEnemyInstance(); }; +DECLARE_NERVE(TNerveBossTelesaFallDemo, TLiveActor); +DECLARE_NERVE(TNerveBossTelesaFreeze, TLiveActor); +DECLARE_NERVE(TNerveBossTelesaPrepareSlot, TLiveActor); +DECLARE_NERVE(TNerveBossTelesaSpitSlotItem, TLiveActor); +DECLARE_NERVE(TNerveBossTelesaSlotStart, TLiveActor); +DECLARE_NERVE(TNerveBossTelesaAppear, TLiveActor); +DECLARE_NERVE(TNerveBossTelesaHideWait, TLiveActor); +DECLARE_NERVE(TNerveBossTelesaHide, TLiveActor); +DECLARE_NERVE(TNerveBossTelesaSpit, TLiveActor); +DECLARE_NERVE(TNerveBossTelesaDie, TLiveActor); +DECLARE_NERVE(TNerveBubbleSplit, TLiveActor); +DECLARE_NERVE(TNerveBubbleLive, TLiveActor); + #endif diff --git a/include/Strategic/HitActor.hpp b/include/Strategic/HitActor.hpp index 03b2056aa..f1b8627ca 100644 --- a/include/Strategic/HitActor.hpp +++ b/include/Strategic/HitActor.hpp @@ -68,6 +68,10 @@ class THitActor : public JDrama::TActor { // fabricated u32 getActorType() const { return mActorType; } + u8 isActorTypeOf(u32 base) const + { + return (mActorType - base) == 1 ? 1 : 0; + } bool checkActorType(u32 flag) const { return mActorType & flag ? true : false; diff --git a/src/Enemy/bosstelesa.cpp b/src/Enemy/bosstelesa.cpp index 73920418b..b52c3e57d 100644 --- a/src/Enemy/bosstelesa.cpp +++ b/src/Enemy/bosstelesa.cpp @@ -1,23 +1,50 @@ #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 #include -#include -#include -#include - -/* - * Boss Telesa is the casino boss in Sirena Beach. The retail TU is a good - * deal denser than the ordinary Telesa TU: one actor owns three roulette - * drums, two hit proxies and a small bubble manager. Keep the data and - * state-machine names here even while the long animation routines are being - * brought over from the matching assembly. - */ +#include +#include +#include +#include +#include +#include static const char* btelesa_bastable[] = { "/scene/btelesa/bas/btelesa_appear.bas", @@ -39,54 +66,33 @@ static const char* btelesa_bastable[] = { "/scene/btelesa/bas/btelesa_wet.bas", }; -static const char* bubble_bastable[] = { - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - "/scene/btelesa/bas/btelesa_lick.bas", - "/scene/btelesa/bas/btelesa_roll.bas", - nullptr, - nullptr, -}; - -static const TModelDataLoadEntry btelesa_model_data[] = { - { "btelesa.bmd", 0x15300000, 0 }, - { nullptr, 0, 0 }, -}; - -static const TModelDataLoadEntry bubble_model_data[] = { - { "btelesa_osenbubbles_ind.bmd", 0x11020000, 0 }, - { nullptr, 0, 0 }, -}; - -f32 TBossTelesa::mEnemyGenRate = 0.1f; +f32 TBossTelesa::mEnemyGenRate = 0.5f; f32 TBossTelesa::mItemGenRate = 0.1f; -u8 TBossTelesa::mNormalAlpha = 0xFF; -f32 TBossTelesa::mBaseHoseiPosY = 350.0f; -f32 TBossTelesa::mRouletteUpRate = 0.1f; -s32 TBossTelesa::mTelesaGenerateInterval = 600; -f32 TBossTelesa::mCameraMoveLimit = 300.0f; -f32 TBossTelesa::mCameraMoveSp = 2.0f; - -/* The slot angle table is deliberately kept as the retail eight-way split. */ +u8 TBossTelesa::mNormalAlpha = 0x96; +f32 TBossTelesa::mBaseHoseiPosY = -300.0f; +f32 TBossTelesa::mRouletteUpRate = 0.03f; +u32 TBossTelesa::mTelesaGenerateInterval = 400; +f32 TBossTelesa::mCameraMoveLimit = 1000.0f; +f32 TBossTelesa::mCameraMoveSp = 0.02f; -/* The retail nerve bodies are intentionally kept small here. The important - * transition points (hide, roulette start, spit and bubble split) are now - * named and can be filled in independently without reintroducing anonymous - * assembly-only classes. */ +static inline TBossTelesa* getBoss(TSpineBase* spine) +{ + return (TBossTelesa*)spine->getBody(); +} -/* Keep a named TU initializer so the list of state singletons has a stable - * home when the remaining retail constructors are enabled. */ +static inline TBubble* getBubble(TSpineBase* spine) +{ + return (TBubble*)spine->getBody(); +} -extern "C" static void __sinit_bosstelesa_cpp() { } +static inline TBossTelesa* getSlotOwner(TTelesaSlot* slot) +{ + return (TBossTelesa*)slot->unk1A0; +} TBubbleSaveLoadParams::TBubbleSaveLoadParams(const char* path) : TWalkerEnemyParams(path) - , PARAM_INIT(mSLLiveTime, 1200) + , PARAM_INIT(mSLLiveTime, 200) , PARAM_INIT(mSLNumDivision, 5) , PARAM_INIT(mSLMaxScale, 1.5f) , PARAM_INIT(mSLAddPosBase, 50.0f) @@ -111,59 +117,120 @@ TSmallEnemy* TBubbleManager::createEnemyInstance() { return new TBubble; } void TBubbleManager::createModelData() { - createModelDataArray(bubble_model_data); + static TModelDataLoadEntry entry[] = { + { "btelesa_osenbubbles_ind.bmd", 0x11020000, 0 }, + { nullptr, 0, 0 }, + }; + createModelDataArray(entry); } TBubble::TBubble(const char* name) : TWalkerEnemy(name) - , mCarriedEnemy(nullptr) - , mTakingMatrix() - , mHeight(0.0f) - , mIsSplit(0) - , mIsMoving(0) + , unk198(nullptr) + , unk1CC(0.0f) + , unk1D0(0) + , unk1D1(0) { } void TBubble::init(TLiveManager* manager) { TWalkerEnemy::init(manager); - mActorType = 0x10000020; - unk150 = 0x11; - mSaveParams = static_cast(getSaveParam()); + mActorType = 0x10000020; + unk150 = 0x11; + unk194 = (TBubbleSaveLoadParams*)getSaveParam(); mSpine->initWith(&TNerveBubbleLive::theNerve()); mMActor->setLightType(3); + + TScreenTexture* tex + = JDrama::TNameRefGen::search("スクリーンテクスチャ"); + SMS_ChangeTextureAll(mMActor->getModel()->getModelData(), "H_ma_rak_dummy", + *tex->getTexture()->getTexInfo()); } void TBubble::reset() { TWalkerEnemy::reset(); onLiveFlag(LIVE_FLAG_UNK8); - mHeight = MsRandF(50.0f, 150.0f); - mIsSplit = 0; - mIsMoving = 1; - mNoEffect = 0; - mCarriedEnemy = nullptr; + + TMsRange scaleRange(50.0f, 150.0f); + unk1CC = scaleRange.rand(); + unk1D0 = 0; + unk1D1 = 1; + unk1D2 = 0; + unk198 = 0; + mSpine->initWith(&TNerveBubbleLive::theNerve()); } -void TBubble::split() { mIsSplit = 1; } +void TBubble::split() +{ + s32 numDivision = unk194->mSLNumDivision.get(); + for (int i = 0; i < numDivision; ++i) { + TBubble* bubble = (TBubble*)gpConductor->makeOneEnemyAppear( + mPosition, "バブルマネージャー", 1); + if (!bubble) + break; + + bubble->reset(); + bubble->mPosition = mPosition; + bubble->mPosition.y += unk1CC; + bubble->unk1CC = 0.0f; + bubble->unk1D0 = 1; + + TMsRange velocityRange(-2.0f, 2.0f); + JGeometry::TVec3 velocity; + velocity.x = velocityRange.rand(); + velocity.y = velocityRange.rand(); + velocity.z = velocityRange.rand(); + + bubble->mVelocity = velocity; + } +} f32 TBubble::getGravityY() const { - if (mIsSplit) - return mIsMoving ? 0.001f : 0.0f; + if (unk1D0) { + if (unk1D1) + return 0.001f; + return 0.0f; + } return mGravity; } void TBubble::kill() { - if (!checkLiveFlag(LIVE_FLAG_DEAD)) - TSmallEnemy::kill(); + if (checkLiveFlag(LIVE_FLAG_DEAD)) + return; + + if (unk198) { + if (unk1D2) + unk198->receiveMessage(this, HIT_MESSAGE_THROWN); + else + unk198->kill(); + unk198 = nullptr; + } + + mHitPoints = 1; + if (mSpine->getCurrentNerve() != &TNerveSmallEnemyDie::theNerve()) { + mSpine->reset(); + mSpine->setNext(&TNerveSmallEnemyDie::theNerve()); + mSpine->pushAfterCurrent(mSpine->getDefault()); + } + + onLiveFlag(LIVE_FLAG_UNK20000); + onLiveFlag(LIVE_FLAG_UNK40); } void TBubble::behaveToWater(THitActor*) { - if (mIsMoving) + if (mSpine->getCurrentNerve() == &TNerveBubbleLive::theNerve() + && mMActor->checkCurBckFromIndex(10)) { kill(); + TMapObjBase* item = gpItemManager->makeObjAppear( + mPosition.x, mPosition.y + 50.0f, mPosition.z, 0x20000002, true); + if (item) + ((TItem*)item)->killByTimer(0x4B0); + } } void TBubble::attackToMario() @@ -175,22 +242,22 @@ void TBubble::attackToMario() void TBubble::calcRootMatrix() { if (!isEaten()) { - mPosition.y = 150.0f + (mGroundHeight + mHeight); - MsMtxSetXYZRPH(getMActor()->getModel()->getBaseTRMtx(), mPosition.x, - mPosition.y, mPosition.z, mRotation.x, mRotation.y, - mRotation.z); - getMActor()->getModel()->setBaseScale(mScaling); + mPosition.y = mGroundHeight + unk1CC + 150.0f; + + MtxPtr mtx = mMActor->getModel()->getBaseTRMtx(); + MsMtxSetXYZRPH(mtx, mPosition.x, mPosition.y, mPosition.z, + (s16)(mRotation.x * 182.04445f), + (s16)(mRotation.y * 182.04445f), + (s16)(mRotation.z * 182.04445f)); + mMActor->getModel()->setBaseScale(mScaling); } } void TBubble::setDeadAnm() { setBckAnm(9); } -MtxPtr TBubble::getTakingMtx() -{ - return getMActor()->getModel()->getBaseTRMtx(); -} +MtxPtr TBubble::getTakingMtx() { return mMActor->unk4->unk20; } -const char** TBubble::getBasNameTable() const { return bubble_bastable; } +const char** TBubble::getBasNameTable() const { return btelesa_bastable; } const TNerveBubbleLive& TNerveBubbleLive::theNerve() { @@ -200,18 +267,129 @@ const TNerveBubbleLive& TNerveBubbleLive::theNerve() void TBubble::appendItem() { } -void TBubble::appendEnemy() { mCarriedEnemy = nullptr; } +void TBubble::appendEnemy() +{ + unk198 = nullptr; + + TMsRange enemyKindRange(0.0f, 100.0f); + f32 randValue = enemyKindRange.rand(); + + TSmallEnemy* enemy; + if (randValue < 50.0f) { + enemy = (TSmallEnemy*)gpConductor->makeOneEnemyAppear( + mPosition, "ポポマネージャー", 1); + enemy->unk154 = 0.6f; + enemy->reset(); + } else if (randValue < 100.0f) { + enemy = (TSmallEnemy*)gpConductor->makeOneEnemyAppear( + mPosition, "ボム兵マネージャー", 1); + enemy->unk154 = 0.3f; + enemy->reset(); + } else if (randValue < 150.0f) { + enemy = (TSmallEnemy*)gpConductor->makeOneEnemyAppear( + mPosition, "テレサマネージャー", 1); + if (!enemy) + return; + enemy->unk154 = 0.6f; + enemy->reset(); + ((TTelesa*)enemy)->setAttacker(); + } else { + enemy = (TSmallEnemy*)gpConductor->makeOneEnemyAppear( + mPosition, "パックンマネージャー", 1); + enemy->unk154 = 0.6f; + enemy->reset(); + } + + if (enemy && enemy->receiveMessage(this, HIT_MESSAGE_TAKE)) { + enemy->onHitFlag(HIT_FLAG_UNK8000000); + mHeldObject = enemy; + JGeometry::TVec3 velocity; + velocity.set(0.0f, 1.0f, -1.0f); + enemy->mVelocity = velocity; + enemy->onLiveFlag(LIVE_FLAG_AIRBORNE); + unk198 = enemy; + } +} BOOL TNerveBubbleLive::execute(TSpineBase* spine) const { - return spine->getTime() > 80; + TBubble* bubble = getBubble(spine); + if (spine->getTime() == 0) { + bubble->offHitFlag(HIT_FLAG_NO_COLLISION); + + if (bubble->unk1D0) { + bubble->setBckAnm(10); + bubble->setGoalPathMario(); + } else { + bubble->setBckAnm(8); + } + + J3DFrameCtrl* frameCtrl = bubble->mMActor->getFrameCtrl(0); + TMsRange frameRange(0.0f, 20.0f); + frameCtrl->setFrame(frameRange.rand()); + bubble->onLiveFlag(LIVE_FLAG_UNK8); + } else if (bubble->checkCurAnmEnd(0)) { + bubble->offHitFlag(HIT_FLAG_NO_COLLISION); + bubble->setBckAnm(10); + } + + if (!bubble->unk1D0) { + if (bubble->unk1CC < bubble->unk194->mSLAddPosBase.get()) + bubble->unk1CC += 1.0f; + } else { + if (spine->getTime() > 40 && bubble->unk1D1) { + JGeometry::TVec3 velocity = bubble->mVelocity; + velocity.scale(0.98f); + bubble->mVelocity = velocity; + } else { + bubble->walkBehavior(0, 0.8f); + } + + if (spine->getTime() == 80) { + bubble->unk1D1 = 0; + bubble->mVelocity.set(0.0f, 0.0f, 0.0f); + } + } + + bubble->unk1CC += 0.001f; + if (bubble->unk1CC + > bubble->mPosition.y + bubble->unk194->mSLDeadHeight.get()) { + bubble->unk1D2 = 0; + bubble->kill(); + } + + if (bubble->mScaling.x < bubble->unk194->mSLMaxScale.get()) { + f32 scale = bubble->mScaling.z * bubble->unk194->mSLRateExpand.get(); + bubble->mScaling.z = scale; + bubble->mScaling.y = scale; + bubble->mScaling.x = scale; + } + + if (spine->getTime() > bubble->unk194->mSLLiveTime.get()) { + spine->pushAfterCurrent(&TNerveBubbleSplit::theNerve()); + return TRUE; + } + + return FALSE; } DEFINE_NERVE(TNerveBubbleSplit, TLiveActor) { - if (spine->getTime() == 0) - static_cast(spine->getBody())->split(); - return spine->getTime() > 10; + TBubble* bubble = getBubble(spine); + if (spine->getTime() == 0) { + bubble->onHitFlag(HIT_FLAG_NO_COLLISION); + bubble->split(); + } + + if (spine->getTime() == 10) + bubble->setBckAnm(9); + + if (bubble->checkCurAnmEnd(0) && bubble->mMActor->checkCurBckFromIndex(9)) { + bubble->unk1D2 = 0; + bubble->kill(); + } + + return FALSE; } TBossTelesaSaveLoadParams::TBossTelesaSaveLoadParams(const char* path) @@ -252,26 +430,51 @@ void TBossTelesaManager::load(JSUMemoryInputStream& stream) TSpineEnemy* TBossTelesaManager::createEnemyInstance() { - return new TBossTelesa; + return new TBossTelesa("ボステレサ"); } void TBossTelesaManager::createModelData() { - createModelDataArray(btelesa_model_data); + static TModelDataLoadEntry entry[] = { + { "btelesa.bmd", 0x15300000, 0 }, + { nullptr, 0, 0 }, + }; + createModelDataArray(entry); } -void TBossTelesaManager::perform(u32 cue, JDrama::TGraphics* graphics) +const f32 bossTelesaDirectionTable[] = { + 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, +}; + +void TBossTelesaManager::perform(u32 flags, JDrama::TGraphics* gfx) { - TEnemyManager::perform(cue, graphics); + TEnemyManager::perform(flags, gfx); } BOOL TBossTelesaBody::receiveMessage(THitActor* sender, u32 message) { - if (mOwner - && (message == HIT_MESSAGE_TRAMPLE - || message == HIT_MESSAGE_SPRAYED_BY_WATER)) - mOwner->damageRecover(); - return THitActor::receiveMessage(sender, message); + TBossTelesa* boss = unk68; + + if (message == HIT_MESSAGE_TRAMPLE) { + bool isMario; + if (sender->mActorType == (ACTOR_TYPE_PLAYER | 1)) + isMario = true; + else + isMario = false; + if (!isMario) { + if (boss->mSpine->getCurrentNerve() + == &TNerveBossTelesaPrepareSlot::theNerve()) + boss->mSpine->pushNerve(&TNerveBossTelesaSpit::theNerve()); + } + } + + if (message == HIT_MESSAGE_SPRAYED_BY_WATER) { + if (boss->mSpine->getCurrentNerve() + == &TNerveBossTelesaPrepareSlot::theNerve()) + boss->mSpine->pushNerve(&TNerveBossTelesaFreeze::theNerve()); + } + + return TRUE; } void TBossTelesaBody::checkHit() { } @@ -280,149 +483,369 @@ MActorAnmBck* MActor::getCurBckAnmPtr() { return unkC; } void TBossTelesaTongue::checkHit() { } -BOOL TBossTelesaTongue::receiveMessage(THitActor* sender, u32 message) +BOOL TBossTelesaTongue::receiveMessage(THitActor*, u32 message) { - return THitActor::receiveMessage(sender, message); + if (message == HIT_MESSAGE_SPRAYED_BY_WATER) { + TBossTelesa* boss = unk68; + if (boss->mSpine->getCurrentNerve() + == &TNerveBossTelesaAppear::theNerve()) + boss->mSpine->pushNerve(&TNerveBossTelesaSlotStart::theNerve()); + } + return TRUE; } void TBossTelesaKillSmallEnemy::checkHit() { - mHit = gpMarioPos != nullptr && mPosition.distance(*gpMarioPos) < 300.0f; - if (mHit && mOwner) - mOwner->forceHide(); -} + unk6C = 0; + + for (int i = 0; i < mColCount; ++i) { + THitActor* collision = mCollisions[i]; + bool isEnemy; + if (collision->mActorType & ACTOR_TYPE_ENEMY) + isEnemy = true; + else + isEnemy = false; + if (isEnemy) { + THitActor* actor = collision; + if (actor->mActorType == (ACTOR_TYPE_ENEMY | 0x13)) + ((THamuKuri*)actor)->selectCapHolder(); + ((TLiveActor*)actor)->kill(); + } + } -BOOL TBossTelesaKillSmallEnemy::receiveMessage(THitActor* sender, u32 message) -{ - return THitActor::receiveMessage(sender, message); + JGeometry::TVec3 diff = *gpMarioPos; + diff -= mPosition; + diff.y = 0.0f; + if (MsVECMag2(&diff) < 300.0f) { + unk68->forceHide(); + unk6C = 1; + } } void TTelesaSlot::initMapObj() { TSlotDrum::initMapObj(); - mLiveFlag |= 0x10; + onLiveFlag(LIVE_FLAG_UNK10); unk14C = 160.0f; unk150 = mPosition.y; unk154 = 2.0f; unk158 = 2.0f; unk15C = 0.01f; unk160 = 0.5f; + unk164 = 0; unk168 = 45; - randomReset(); + unk140 = mDamageRadius / 3.0f; + unk144 = mDamageHeight; + unk1DC = new TMapCollisionMove(); + unk1DC->init(2, 0, 0, nullptr); + + TMsRange indexRange(0, 8); + for (int i = 0; i < 3; ++i) { + unk13C[i] = (f32)(unk168 * indexRange.rand()); + *(&unk198 + i) = 0; + } } +#pragma dont_inline on void TTelesaSlot::randomReset() { + TMsRange indexRange(0, 8); + for (int i = 0; i < 3; ++i) { - unk13C[i] = unk168 * (s32)MsRandF(0.0f, 8.0f); - ((&mStop0)[i]) = 0; + unk13C[i] = (f32)(unk168 * indexRange.rand()); + *(&unk198 + i) = 0; } } +#pragma dont_inline off + +void TTelesaSlot::calcRootMatrix() +{ + u8 rolling = 0; -void TTelesaSlot::calcRootMatrix() { TSlotDrum::calcRootMatrix(); } + if (getDrumSpeeds()[0] != 0.0f) + rolling = 1; + if (getDrumSpeeds()[1] != 0.0f) + rolling = 1; + if (getDrumSpeeds()[2] != 0.0f) + rolling = 1; -void TTelesaSlot::moveObject() { TSlotDrum::moveObject(); } + if (rolling) { + if (unk1E0) { + if (gpMSound->gateCheck(0x308D)) { + MSoundSESystem::MSoundSE::startSoundActor(0x308D, &mPosition, 0, + nullptr, 0, 4); + } + } + + unk1E0 = 1 - unk1E0; + } + TSlotDrum::calcRootMatrix(); +} + +void TTelesaSlot::moveObject() +{ + TLiveActor::moveObject(); + + for (int i = 0; i < unk148; ++i) { + u8* isRolling = &unk198 + i; + u8* doStop = &unk1A8 + i; + + if (*doStop) { + if (getForcastResult(i) == unk1A4) { + *isRolling = 0; + *doStop = 0; + } + } + + f32 speed = unk138[i]; + if (speed == 0.0f) + continue; + + if (fabsf(speed) > unk160) { + unk13C[i] += speed; + + if (!*isRolling) { + if (unk138[i] > 0.0f) + unk138[i] -= unk15C; + else + unk138[i] += unk15C; + } + + if (unk13C[i] >= 360.0f) + unk13C[i] -= 360.0f; + if (unk13C[i] <= 0.0f) + unk13C[i] += 360.0f; + } else { + unk13C[i] += speed; + + if (unk13C[i] >= 360.0f) + unk13C[i] -= 360.0f; + if (unk13C[i] <= 0.0f) + unk13C[i] += 360.0f; + + if (*isRolling) + continue; + + if ((int)fabsf(unk13C[i]) % unk168 != 0) + continue; + + unk13C[i] = unk168 * (int)(unk13C[i] / (f32)unk168); + unk138[i] = 0.0f; + + if (gpMSound->gateCheck(0x292C)) { + MSoundSESystem::MSoundSE::startSoundActor(0x292C, &mPosition, 0, + nullptr, 0, 4); + } + + for (int j = 0; j < unk148; ++j) { + u8* otherRolling = &unk198 + j; + if (*otherRolling) { + f32 min = 0.0f; + f32 max = 1.0f; + TBossTelesa* owner = getSlotOwner(this); + TBossTelesaSaveLoadParams* params + = (TBossTelesaSaveLoadParams*)owner->unk15C; + f32 rate = params->mSLSlotHitCollectRate.get(); + + if (min + (max - min) * (rand() * 0.000030517578f) + <= rate) { + *(&unk1A8 + j) = 1; + } else { + *otherRolling = 0; + } + } + } + + u8 allStopped = 1; + if (unk138[0] != 0.0f) + allStopped = 0; + if (unk138[1] != 0.0f) + allStopped = 0; + if (unk138[2] != 0.0f) + allStopped = 0; + + if (allStopped) { + TBossTelesa* owner = getSlotOwner(this); + TTelesaSlot* slot = (TTelesaSlot*)owner->unk184; + + if (slot->getSlotResult() == 2 || slot->getSlotResult() == 0) { + owner->unk374.x = 0.0f; + owner->unk374.y = 0.0f; + owner->unk374.z = 0.0f; + gpMarioParticleManager->emit(0xE1, &owner->unk374, 0, + nullptr); + + if (slot->getSlotResult() == 2) { + if (gpMSound->gateCheck(0x293F)) { + MSoundSESystem::MSoundSE::startSoundActor( + 0x293F, &owner->mPosition, 0, nullptr, 0, 4); + } + } else { + if (gpMSound->gateCheck(0x2940)) { + MSoundSESystem::MSoundSE::startSoundActor( + 0x2940, &owner->mPosition, 0, nullptr, 0, 4); + } + } + } else { + if (gpMSound->gateCheck(0x294D)) { + MSoundSESystem::MSoundSE::startSoundActor( + 0x294D, &owner->mPosition, 0, nullptr, 0, 4); + } + } + } + } + } +} + +#pragma dont_inline on void TTelesaSlot::moveStart() { - mForceStop = 1; - mRolling = 1; - mRoll0 = 1; - mRoll1 = 1; - mRoll2 = 1; - mStop0 = mStop1 = mStop2 = 0; - unk138[0] = -unk158; - unk138[1] = -0.8f * unk158; - unk138[2] = unk158; + unk19C = 1; + unk19B = 1; + + for (int i = 0; i < 3; ++i) { + *(&unk198 + i) = 1; + *(&unk1A8 + i) = 0; + + f32 speed = 1.0f; + if (i == 0) + speed = -1.0f; + if (i == 1) + speed = -0.8f; + + unk138[i] = speed * unk158; + } } +#pragma dont_inline off -u32 TTelesaSlot::touchWater(THitActor*) { return 0; } +u32 TTelesaSlot::touchWater(THitActor*) { return FALSE; } -void TTelesaSlot::forceStopSlot(int drum) +#pragma dont_inline on +void TTelesaSlot::forceStopSlot(int idx) { - if (!mForceStop) + volatile f32 min = 0.0f; + volatile f32 max = 1.0f; + f32 range; + f32 collectRate; + + if (!unk19C) return; - mForceResult = getForcastResult(drum); - ((&mRoll0)[drum]) = 0; - mForceStop = 0; + + TBossTelesaSaveLoadParams* params + = (TBossTelesaSaveLoadParams*)getSlotOwner(this)->unk15C; + collectRate = params->mSLSlotFirstHitCollectRate.get(); + + if (SMS_GetMarioHP() == 1) + collectRate = 0.9f; + + range = max - min; + f32 randomValue = range * (rand() * 0.000030517578f); + randomValue = min + randomValue; + if (randomValue <= collectRate) { + unk1A4 = 2; + if (SMS_GetMarioHP() <= 3) + unk1A4 = 0; + *(&unk1A8 + idx) = 1; + } else { + unk1A4 = getForcastResult(idx); + *(&unk198 + idx) = 0; + } + + if (unk1A4 == getSlotOwner(this)->unk1A8) + unk1A4 = 3; + + if (unk1A4 == 0) { + if (getSlotOwner(this)->unk370 == 0) + unk1A4 = 1; + else if (SMS_GetMarioHP() >= 6) + unk1A4 = 3; + } + + unk19C = 0; } +#pragma dont_inline off -u8 TTelesaSlot::isRollDrum() +#pragma dont_inline on +BOOL TTelesaSlot::isRollDrum() { - if (mRoll0) - return 1; - if (mRoll1) - return 1; - if (mRoll2) - return 1; - mRolling = 0; - return 0; + if (unk198) + return TRUE; + if (unk199) + return TRUE; + if (unk19A) + return TRUE; + + unk19B = 0; + return FALSE; } +#pragma dont_inline off +#pragma dont_inline on int TTelesaSlot::getSlotResult() { int result = getResultFromAng(unk13C[0]); - int i = 1; - do { - if (result != getResultFromAng(unk13C[i])) + for (int i = 1; i < 3; ++i) { + if (getResultFromAng(unk13C[i]) != result) return -1; - ++i; - } while (i < 3); + } return result; } +#pragma dont_inline off -int TTelesaSlot::getDrumResult(int drum) +int TTelesaSlot::getDrumResult(int index) { - return getResultFromAng(unk13C[drum]); + return getResultFromAng(unk13C[index]); } -int TTelesaSlot::getForcastResult(int drum) +int TTelesaSlot::getForcastResult(int idx) { - f32 angle = unk13C[drum]; - f32 speed = unk138[drum]; + f32 ang = unk13C[idx]; + f32 cur = unk138[idx]; - do { - if (fabsf(speed) > unk160) { - angle += speed; - if (speed > 0.0f) - speed -= unk15C; + for (;;) { + if (fabsf(cur) > unk160) { + ang += cur; + if (cur > 0.0f) + cur -= unk15C; else - speed += unk15C; - - if (angle >= 360.0f) - angle -= 360.0f; - if (angle <= 0.0f) - angle += 360.0f; - continue; + cur += unk15C; + + if (ang >= 360.0f) + ang -= 360.0f; + if (ang <= 0.0f) + ang += 360.0f; + } else { + ang += cur; + if (ang >= 360.0f) + ang -= 360.0f; + if (ang <= 0.0f) + ang += 360.0f; + if ((int)fabsf(ang) % unk168 == 0) + break; } + } - angle += speed; - if (angle >= 360.0f) - angle -= 360.0f; - if (angle <= 0.0f) - angle += 360.0f; - } while ((s32)fabsf(angle) % unk168 != 0); - - return getResultFromAng((f32)(unk168 * (s32)(angle / (f32)unk168))); + return getResultFromAng(unk168 * (int)(ang / (f32)unk168)); } -int TTelesaSlot::getResultFromAng(f32 angle) +int TTelesaSlot::getResultFromAng(f32 ang) { - if (angle < 44.0f) + if (ang < 44.0f) return 0; - if (angle < 89.0f) + if (ang < 89.0f) return 1; - if (angle < 134.0f) + if (ang < 134.0f) return 3; - if (angle < 179.0f) + if (ang < 179.0f) return 2; - if (angle < 224.0f) + if (ang < 224.0f) return 0; - if (angle < 269.0f) + if (ang < 269.0f) return 1; - if (angle < 314.0f) + if (ang < 314.0f) return 3; - if (angle < 359.0f) + if (ang < 359.0f) return 2; return 2; } @@ -433,280 +856,2101 @@ void TTelesaSlot::entryObjCollision() { } TBossTelesa::TBossTelesa(const char* name) : TSpineEnemy(name) - , mBattleState(1) - , mBattleTimer(0) - , mBattlePhase(0) - , mSaveParams(nullptr) - , mCurrentItem(-1) - , mCurrentFruit(-1) - , mFallSpeed(0.0f) - , mBodyCollision(nullptr) - , mSlot(nullptr) - , mTakingActor(nullptr) - , mIsSpicy(0) - , mDamageTimer(0) - , mStateTimer(0) - , mDamage(0) - , mGenerateTimer(0) - , mMarioHP(0) - , mForceRestart(1) - , mInDamage(1) - , mRouletteTimer(0) - , mRoulettePosY(0.0f) - , mRouletteSp(0.0f) - , mSlotResult(0) - , mSlotItemCount(0) - , mSlotStop(3) - , mDead(0) + , unk150(1) + , unk154(nullptr) + , unk158(nullptr) + , unk15C(nullptr) + , unk160(-1) + , unk164(-1) + , unk168(0.0f) + , unk16C(nullptr) + , unk184(nullptr) + , unk188(nullptr) + , unk18C(0) + , unk1A8(0) + , unk274(0) + , unk350(0) + , unk354(0) + , unk358(0) + , unk35A(1) + , unk35B(1) + , unk35C(0) + , unk360(0.0f) + , unk364(0.0f) + , unk368(0) + , unk36C(0) + , unk370(3) + , unk384(0) { } void TBossTelesa::init(TLiveManager* manager) { - TSpineEnemy::init(manager); - mSaveParams = static_cast(getSaveParam()); - mBodyCollision = new TBossTelesaBody(this); - mTongueCollision = new TBossTelesaTongue(this); - mKillSmallEnemy = new TBossTelesaKillSmallEnemy(this); + mManager = manager; + manager->manageActor(this); + mMActorKeeper = new TMActorKeeper(manager, 1); + mMActor = mMActorKeeper->createMActor("btelesa.bmd", 3); + + onLiveFlag(LIVE_FLAG_DEAD); + onHitFlag(HIT_FLAG_NO_COLLISION); + + TSpineEnemyParams* params = getSaveParam(); + if (params) { + mBodyRadius = params->mSLBodyRadius.get(); + mWallRadius = params->mSLWallRadius.get(); + mHeadHeight = params->mSLHeadHeight.get(); + mScaledBodyRadius = mBodyScale * mBodyRadius; + mHitPoints = getSaveParam() ? getSaveParam()->mSLHitPointMax.get() : 1; + } + + initHitActor(0, 5, 0x98000000, mBodyRadius, mHeadHeight, mBodyRadius, + mHeadHeight); + mGroundPlane = TMap::getIllegalCheckData(); + setGoalPathMario(); + initAnmSound(); + unk15C = getSaveParam(); + mActorType = 0x08000013; + onHitFlag(0xD0000000); + mSpine->initWith(&TNerveBossTelesaFallDemo::theNerve()); + onLiveFlag(LIVE_FLAG_UNK8); + + mMActor->setLightType(1); + mMActor->unk40 = 1; + if (mMActor->unkC) + mMActor->unkC->initNormalMotionBlend(); + + J3DModel* model = mMActor->getModel(); + if (!model->getSkinDeform()) + model->setSkinDeform(new J3DSkinDeform, J3D_DEFORM_ATTACH_FLAG_UNK_1); + mMActor->resetDL(); + + unk348.r = 0xFF; + unk348.g = 0xFF; + unk348.b = 0xFF; + unk348.a = 0xFF; + + unk34C.r = mNormalAlpha; + unk34C.g = mNormalAlpha; + unk34C.b = mNormalAlpha; + unk34C.a = mNormalAlpha; + + J3DModelData* modelData = model->getModelData(); + for (u16 i = 0; i < modelData->getMaterialNum(); ++i) { + s32 bodyMatIndex + = getModel()->getModelData()->getMaterialName()->getIndex( + "_mat_body"); + if (i == bodyMatIndex) { + SMS_InitPacket_TwoTevKColor(model, i, GX_KCOLOR0, &unk34C, + GX_KCOLOR1, &unk348); + } else { + SMS_InitPacket_OneTevKColor(model, i, GX_KCOLOR0, &unk34C); + } + } + + reset(); + + for (int i = 0; i < gpMapObjManager->getObjNum(); ++i) { + TMapObjBase* actor = gpMapObjManager->getObj(i); + if (actor->mActorType == 0x4000019A) { + unk154 = nullptr; + unk158 = nullptr; + mPosition = actor->mPosition; + } + } + + if (mInstanceIndex == 0) { + for (u8 i = 0; i < mMActor->getModel()->getModelData()->getJointNum(); + ++i) { } + } + + unk16C = new TBossTelesaBody("ボステレサ体コリジョン"); + TIdxGroupObj* enemyGroup + = JDrama::TNameRefGen::search("敵グループ"); + enemyGroup->getChildren().push_back(unk16C); + unk16C->initHitActor(0x08000013, 5, 0xD1000000, 350.0f, 550.0f, 300.0f, + 500.0f); + ((TBossTelesaBody*)unk16C)->unk68 = this; + unk16C->offHitFlag(HIT_FLAG_NO_COLLISION); + + unk170 = new TBossTelesaTongue("ボステレサ舌コリジョン"); + enemyGroup = JDrama::TNameRefGen::search("敵グループ"); + enemyGroup->getChildren().push_back(unk170); + unk170->initHitActor(0x08000013, 5, 0xC0000000, 180.0f, 350.0f, 180.0f, + 350.0f); + ((TBossTelesaTongue*)unk170)->unk68 = this; + unk170->offHitFlag(HIT_FLAG_NO_COLLISION); + + unk174 = new TBossTelesaKillSmallEnemy("ボステレサ雑魚敵死コリジョン"); + enemyGroup = JDrama::TNameRefGen::search("敵グループ"); + enemyGroup->getChildren().push_back(unk174); + unk174->initHitActor(0x1000000C, 5, 0x10000000, 400.0f, 300.0f, 400.0f, + 300.0f); + unk174->offHitFlag(HIT_FLAG_NO_COLLISION); + ((TBossTelesaKillSmallEnemy*)unk174)->unk68 = this; + + mMActor->setLightType(3); + + JDrama::TViewObj* screenTex + = JDrama::TNameRefGen::search("スクリーンテクスチャ"); + void* dataOwner = *(void**)((u8*)screenTex + 0x10); + ResTIMG* texture = *(ResTIMG**)((u8*)dataOwner + 0x20); + SMS_ChangeTextureAll(mMActor->unk4->mModelData, "H_ma_rak_dummy", *texture); + + unk358 = SMS_GetMarioHP(); } void TBossTelesa::loadAfter() { - mMarioHP = 1; - if (!mSaveParams) - mSaveParams = static_cast(getSaveParam()); + u32 rouletteType = 0x4000019A; + if ((u32)gpMapObjManager->getObjNumWithActorType(rouletteType) != 0) { + int found = 0; + for (int i = 0; i < gpMapObjManager->getObjNum(); ++i) { + TMapObjBase* actor = gpMapObjManager->getObj(i); + bool isRoulette = false; + if (actor->mActorType == rouletteType) + isRoulette = true; + if (isRoulette) { + ((TRoulette**)&unk178)[found] = (TRoulette*)actor; + found++; + } + } + } + + u32 slotType = 0x400001A6; + if ((u32)gpMapObjManager->getObjNumWithActorType(slotType) != 0) { + for (int i = 0; i < gpMapObjManager->getObjNum(); ++i) { + TMapObjBase* actor = gpMapObjManager->getObj(i); + bool isSlot = false; + if (actor->mActorType == slotType) + isSlot = true; + if (isSlot) { + unk184 = (TTelesaSlot*)actor; + unk184->unk1A0 = this; + } + } + } + + JGeometry::TVec3 position(0.0f, 0.0f, 0.0f); + JGeometry::TVec3 rotation(0.0f, 0.0f, 0.0f); + JGeometry::TVec3 scale(1.0f, 1.0f, 1.0f); + int fruitIndex = 0; + for (int i = 0; i < 6; ++i) + unk2A8[fruitIndex++] = TMapObjBaseManager::newAndRegisterObj( + "FruitCoconut", position, rotation, scale); + for (int i = 0; i < 6; ++i) + unk2A8[fruitIndex++] = TMapObjBaseManager::newAndRegisterObj( + "FruitPapaya", position, rotation, scale); + for (int i = 0; i < 2; ++i) + unk2A8[fruitIndex++] = TMapObjBaseManager::newAndRegisterObj( + "FruitPine", position, rotation, scale); + for (int i = 0; i < 6; ++i) + unk2A8[fruitIndex++] = TMapObjBaseManager::newAndRegisterObj( + "FruitDurian", position, rotation, scale); + + for (int i = 0; i < 20; ++i) { + TMapObjBase* actor = (TMapObjBase*)unk2A8[i]; + actor->onMapObjFlag(0x04000000); + actor->makeObjDead(); + } + + unk2F8[0] = JDrama::TNameRefGen::search("唐辛子 0"); + unk2F8[1] = JDrama::TNameRefGen::search("唐辛子 1"); + unk2F8[2] = JDrama::TNameRefGen::search("唐辛子 2"); + unk2F8[3] = JDrama::TNameRefGen::search("唐辛子 3"); + unk2F8[4] = JDrama::TNameRefGen::search("唐辛子 4"); + unk2F8[5] = JDrama::TNameRefGen::search("唐辛子 5"); + unk2F8[6] = JDrama::TNameRefGen::search("唐辛子 6"); + unk2F8[7] = JDrama::TNameRefGen::search("唐辛子 7"); + unk2F8[8] = JDrama::TNameRefGen::search("唐辛子 8"); + unk2F8[9] = JDrama::TNameRefGen::search("唐辛子 9"); + for (int i = 0; i < 10; ++i) + ((TMapObjBase*)unk2F8[i])->makeObjDead(); + + unk320[0] = JDrama::TNameRefGen::search("コイン 0"); + unk320[1] = JDrama::TNameRefGen::search("コイン 1"); + unk320[2] = JDrama::TNameRefGen::search("コイン 2"); + unk320[3] = JDrama::TNameRefGen::search("コイン 3"); + unk320[4] = JDrama::TNameRefGen::search("コイン 4"); + unk320[5] = JDrama::TNameRefGen::search("コイン 5"); + unk320[6] = JDrama::TNameRefGen::search("コイン 6"); + unk320[7] = JDrama::TNameRefGen::search("コイン 7"); + unk320[8] = JDrama::TNameRefGen::search("コイン 8"); + unk320[9] = JDrama::TNameRefGen::search("コイン 9"); + for (int i = 0; i < 10; ++i) + ((TMapObjBase*)unk320[i])->makeObjDead(); + + TTelesaSlot* slot = (TTelesaSlot*)unk184; + slot->unk1E4[0] = 0.0f; + slot->unk1E4[1] = 0.0f; + slot->unk1E4[2] = 0.0f; + + unk354 = JDrama::TNameRefGen::search("テレサマネージャー"); + + for (int i = 0; i < 5; ++i) + TMapObjBaseManager::newAndRegisterObj("bottle_large", position, + rotation, scale); + + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_fhit.jpa", 0xD7); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_fhit_pe.jpa", 0xD8); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_fhit_gr.jpa", 0xD9); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_fhit_or.jpa", 0xDA); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_damage.jpa", 0xDB); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_down.jpa", 0xDC); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_down_pe.jpa", 0xDD); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_down_gr.jpa", 0xDE); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_down_or.jpa", 0xDF); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_spicy_hit.jpa", 0xE0); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_fubuki.jpa", 0xE1); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_yodare1.jpa", 0x19E); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_yodare2.jpa", 0x19F); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_yodare3.jpa", 0x1A0); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_ase.jpa", 0x1A1); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_spicy_a.jpa", 0x1A2); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_spicy_b.jpa", 0x1A3); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_spicy_d.jpa", 0x1A4); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_chika_a.jpa", 0x1A5); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_chika_b.jpa", 0x1A6); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_glow.jpa", 0x1A7); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_spicy_c.jpa", 0x1F0); + + void* res = JKRFileLoader::getGlbResource("/scene/btelesa/srot_waku.bmd"); + SDLModelData* data + = new SDLModelData(J3DModelLoaderDataBase::load(res, 0x10220000)); + unk188 + = new TSharedParts((TLiveActor*)unk184, 0, data, 3, ""); + + TLiveActor* gesso0 = JDrama::TNameRefGen::search("ゲッソー 0"); + if (gesso0) + gesso0->onLiveFlag(LIVE_FLAG_DEAD); + + TLiveActor* gesso1 = JDrama::TNameRefGen::search("ゲッソー 1"); + if (gesso1) + gesso1->onLiveFlag(LIVE_FLAG_DEAD); + + JDrama::TNameRef::loadAfter(); } void TBossTelesa::reset() { TSpineEnemy::reset(); - mDead = 0; - mDamage = 0; - mGenerateTimer = 0; - forceAllItemKill(); + onHitFlag(HIT_FLAG_NO_COLLISION); + onLiveFlag(LIVE_FLAG_UNK8); + onLiveFlag(LIVE_FLAG_UNK10); + onLiveFlag(LIVE_FLAG_HIDDEN); + + unk18C = 0; + + TBossTelesaSaveLoadParams* params = (TBossTelesaSaveLoadParams*)unk15C; + setHitParams(params->mSLAttackRadius.get(), params->mSLAttackHeight.get(), + params->mSLDamageRadius.get(), params->mSLDamageHeight.get()); + + TMarDirector* director = gpMarDirector; + director->fireStartDemoCamera("btelesa_roll_camera", nullptr, -1, 0.0f, + true, nullptr, 0, nullptr, + JDrama::TFlagT(0)); } void TBossTelesa::moveObject() { - TSpineEnemy::moveObject(); - if (mGenerateTimer > 0) - --mGenerateTimer; + if (mLiveFlag & LIVE_FLAG_DEAD) + return; + + JGeometry::TVec3 cameraPos; + cameraPos.set(gpCamera->unk124); + JGeometry::TVec3 marioDiff = *gpMarioPos; + marioDiff.sub(cameraPos); + f32 cameraDist = marioDiff.length(); + + if (cameraDist < mCameraMoveLimit) { + unk360 += mCameraMoveSp * (gpMarioPos->y - gpCamera->unk148.y); + gpCamera->unk290 = unk360; + } else if (__fabsf(unk360) > 1.0f) { + unk360 *= mCameraMoveSp; + gpCamera->unk290 = unk360; + } + + if (*gpMarioFlag & 0x400) { + if (gpMSound->gateCheck(0x28D4)) { + MSoundSESystem::MSoundSE::startSoundActor(0x28D4, &mPosition, 0, + nullptr, 0, 4); + } + } + + if (mSpine->getCurrentNerve() == &TNerveBossTelesaFallDemo::theNerve()) { + if (unk178 && unk17C + && unk178->mPosition.y > unk17C->mPosition.y + 5.0f) { + unk184->mPosition = unk178->mPosition; + unk184->mPosition.y += 300.0f; + } + } + + if (mSpine->getCurrentNerve() != &TNerveBossTelesaPrepareSlot::theNerve()) { + mMActor->setFrameRate(0.0f, 3); + mMActor->getFrameCtrl(3)->setFrame(0.0f); + } + + if (mSpine->getCurrentNerve() == &TNerveBossTelesaDie::theNerve()) { + u8 maxHp = getSaveParam() ? getSaveParam()->mSLHitPointMax.get() : 1; + u8 targetAlpha = mNormalAlpha + (maxHp - mHitPoints) * 30; + if (targetAlpha > 0xFE) + targetAlpha = 0xFE; + + if ((mMActor->checkCurBckFromIndex(7) + && mMActor->getFrameCtrl(0)->getFrame() > 50.0f) + || mMActor->checkCurBckFromIndex(6)) { + if (unk34C.a > targetAlpha) + --unk34C.a; + } else if (unk34C.a < 0xFF) { + ++unk34C.a; + } + } + + JGeometry::TVec3 cameraDiff = *gpMarioPos; + cameraDiff.sub(gpCamera->unk124); + unk19C = unk178->mPosition; + unk19C.x += 0.67f * cameraDiff.x; + unk19C.z += 0.67f * cameraDiff.z; + + int movingRoulettes = 0; + if (unk178->unk13C != 0.0f) + ++movingRoulettes; + if (unk17C->unk13C != 0.0f) + ++movingRoulettes; + if (unk180->unk13C != 0.0f) + ++movingRoulettes; + + switch (movingRoulettes) { + case 1: + if (gpMSound->gateCheck(0x30B7)) { + MSoundSESystem::MSoundSE::startSoundActor(0x30B7, &unk19C, 0, + nullptr, 0, 4); + } + break; + case 2: + if (gpMSound->gateCheck(0x30B6)) { + MSoundSESystem::MSoundSE::startSoundActor(0x30B6, &unk19C, 0, + nullptr, 0, 4); + } + break; + case 3: + if (gpMSound->gateCheck(0x30B5)) { + MSoundSESystem::MSoundSE::startSoundActor(0x30B5, &unk19C, 0, + nullptr, 0, 4); + } + break; + } + + mLinearVelocity.zero(); + mAngularVelocity.zero(); + control(); + + for (int i = 0; i < mColCount; ++i) { + if (mCollisions[i]->isActorTypeOf(ACTOR_TYPE_PLAYER)) + SMS_SendMessageToMario(this, HIT_MESSAGE_ATTACK); + } + + bind(); + mPosition += mLinearVelocity; + mRotation += mAngularVelocity; + mPosition.y = mGroundHeight + 300.0f; + + unk168 = MsClamp(unk168 - 0.05f, 0.0f, 1.0f); + if (mMActor->unkC) + mMActor->unkC->setMotionBlendRatio(unk168); + + if (mLiveFlag & LIVE_FLAG_CLIPPED_OUT) { + unk16C->mPosition = mPosition; + unk170->mPosition = mPosition; + unk174->mPosition = mPosition; + } else { + J3DModel* model = mMActor->getModel(); + MtxPtr node1 = model->mNodeMatrices[1]; + MtxPtr node7 = model->mNodeMatrices[7]; + + unk16C->mPosition.set(node1[0][3], node1[1][3] - 200.0f, node1[2][3]); + unk174->mPosition.set(node1[0][3], mPosition.y - 350.0f, node1[2][3]); + unk170->mPosition.set(node7[0][3], node7[1][3] - 350.0f, node7[2][3]); + } + + TBossTelesaBody* body = (TBossTelesaBody*)unk16C; + body->unk6C = 0; + for (int i = 0; i < body->mColCount; ++i) { + THitActor* actor = body->mCollisions[i]; + if (actor->isActorTypeOf(ACTOR_TYPE_PLAYER)) + SMS_SendMessageToMario(body, HIT_MESSAGE_ATTACK); + else + body->unk68->checkHitObject(actor); + } + + TBossTelesaTongue* tongue = (TBossTelesaTongue*)unk170; + for (int i = 0; i < tongue->mColCount; ++i) { + THitActor* actor = tongue->mCollisions[i]; + if (actor->isActorTypeOf(ACTOR_TYPE_PLAYER)) { + SMS_SendMessageToMario(tongue, HIT_MESSAGE_ATTACK); + } else if (actor->mActorType == 0x40000395) { + tongue->unk68->setSpicy((TLiveActor*)actor); + } else if (tongue->mPosition.y + 100.0f < actor->mPosition.y) { + tongue->unk68->checkHitObject(actor); + } + } + + ((TBossTelesaKillSmallEnemy*)unk174)->checkHit(); } void TBossTelesa::kill() { - if (!checkLiveFlag(LIVE_FLAG_DEAD)) { - mDead = 1; - TSpineEnemy::kill(); - } + if (mSpine->getCurrentNerve() != &TNerveBossTelesaDie::theNerve()) + mSpine->pushNerve(&TNerveBossTelesaDie::theNerve()); } MtxPtr TBossTelesa::getTakingMtx() { - return getModel() ? getModel()->getBaseTRMtx() : nullptr; -} + unk278.set(unk178->mMActor->unk4->mNodeMatrices[1]); + unk278.mMtx[1][3] = unk178->mPosition.y - 120.0f; + return unk278.mMtx; +} + +void TBossTelesa::prepareGenerate() { unk35C = 0; } + +void TBossTelesa::calcRootMatrix() +{ + mMActor->getModel()->setBaseScale(mScaling); + + f32 offsetY = unk364; + if (offsetY > 0.0f) + offsetY = 0.0f; + else if (offsetY < mBaseHoseiPosY) + offsetY = mBaseHoseiPosY; + + TPosition3f translateMtx; + translateMtx.translation( + mPosition.x, + mPosition.y + + ((TBossTelesaSaveLoadParams*)unk15C)->mSLTransYOffset.get() + + offsetY, + mPosition.z); + + Mtx rotateMtx; + MsMtxSetRotRPH(rotateMtx, mRotation.x, mRotation.y, mRotation.z); + PSMTXConcat(translateMtx, rotateMtx, translateMtx); + PSMTXCopy(translateMtx, mMActor->getModel()->getBaseTRMtx()); + + TTelesaSlot* slot = (TTelesaSlot*)unk184; + if (slot) { + slot->mRotation = mRotation; + + f32 slotOffsetY = -700.0f; + MtxPtr slotMtx; + if (mMActor->checkCurBckFromIndex(4) || mMActor->checkCurBckFromIndex(0) + || mMActor->checkCurBckFromIndex(2) + || mMActor->checkCurBckFromIndex(5)) { + slotMtx = mMActor->getModel()->mNodeMatrices[1]; + if (!mMActor->checkCurBckFromIndex(0)) + slotOffsetY = -2400.0f; + } else { + slotMtx = mMActor->getModel()->mNodeMatrices[0]; + } + + slot->mPosition.x = slotMtx[0][3]; + slot->mPosition.y = unk364 + slotMtx[1][3] + slotOffsetY; + slot->mPosition.z = slotMtx[2][3]; + } + + for (u16 i = 0; i < mMActor->getModel()->getModelData()->getMaterialNum(); + ++i) { + Mtx lightMtx; + SMS_GetLightPerspectiveForEffectMtx(lightMtx); + mMActor->getModel() + ->getModelData() + ->getMaterialNodePointer(i) + ->getTexMtx(1) + ->setEffectMtx(lightMtx); + } + + unk374.set(0.0f, 0.0f, 0.0f); + gpMarioParticleManager->emit(0x1A5, &unk374, 1, this); + gpMarioParticleManager->emit(0x1A6, &unk374, 1, this); + + MtxPtr baseMtx = mMActor->getModel()->mNodeMatrices[1]; + unk374.set(baseMtx[0][3], baseMtx[1][3], baseMtx[2][3]); + gpMarioParticleManager->emitAndBindToPosPtr(0x1A7, &unk374, 1, this); + + if (!mMActor->checkCurBckFromIndex(4) && !mMActor->checkCurBckFromIndex(6) + && !mMActor->checkCurBckFromIndex(12) + && !mMActor->checkCurBckFromIndex(13)) { + gpMarioParticleManager->emitAndBindToMtxPtr( + 0x19E, mMActor->getModel()->mNodeMatrices[5], 1, this); + gpMarioParticleManager->emitAndBindToMtxPtr( + 0x19F, mMActor->getModel()->mNodeMatrices[5], 1, this); + gpMarioParticleManager->emitAndBindToMtxPtr( + 0x1A0, mMActor->getModel()->mNodeMatrices[10], 1, this); + } -void TBossTelesa::prepareGenerate() { mGenerateTimer = 0; } + if (mMActor->checkCurBckFromIndex(1) + && mMActor->getFrameCtrl(0)->getFrame() < 20.0f) { + gpMarioParticleManager->emitAndBindToMtxPtr( + 0xE0, mMActor->getModel()->mNodeMatrices[5], 0, nullptr); + } -void TBossTelesa::calcRootMatrix() { TSpineEnemy::calcRootMatrix(); } + if (mMActor->checkCurBckFromIndex(12)) { + if (gpMSound->gateCheck(0x20FE)) { + MSoundSESystem::MSoundSE::startSoundActor(0x20FE, &mPosition, 0, + nullptr, 0, 4); + } + + gpMarioParticleManager->emitAndBindToMtxPtr( + 0x1A1, mMActor->getModel()->mNodeMatrices[1], 1, this); + gpMarioParticleManager->emitAndBindToMtxPtr( + 0x1A2, mMActor->getModel()->mNodeMatrices[9], 1, this); + gpMarioParticleManager->emitAndBindToMtxPtr( + 0x1A3, mMActor->getModel()->mNodeMatrices[9], 1, this); + gpMarioParticleManager->emitAndBindToMtxPtr( + 0x1A4, mMActor->getModel()->mNodeMatrices[9], 1, this); + gpMarioParticleManager->emitAndBindToMtxPtr( + 0x1F0, mMActor->getModel()->mNodeMatrices[9], 3, this); + } -void TBossTelesa::perform(u32 cue, JDrama::TGraphics* graphics) + if (mMActor->checkCurBckFromIndex(14) + && mMActor->getFrameCtrl(0)->checkPass(40.0f)) { + if (mSpine->getCurrentNerve() + == &TNerveBossTelesaSpitSlotItem::theNerve()) { + generateSlotItem(); + } else { + genAttacker(); + } + } +} + +void TBossTelesa::perform(u32 flags, JDrama::TGraphics* gfx) { - TSpineEnemy::perform(cue, graphics); - if (cue & CUE_MOVE) - damageRecover(); + if ((flags & 0x200) + && !(mLiveFlag & (LIVE_FLAG_DEAD | LIVE_FLAG_CLIPPED_OUT))) { + if (mSpine->getCurrentNerve() == &TNerveBossTelesaDie::theNerve() + && unk350) { + mMActor->offMakeDL(); + SMS_AddDamageFogEffect(mMActor->unk4->mModelData, mPosition, gfx); + } + } + + offLiveFlag(LIVE_FLAG_CLIPPED_OUT); + TSpineEnemy::perform(flags, gfx); + + unk16C->THitActor::perform(flags, gfx); + unk170->THitActor::perform(flags, gfx); + unk174->THitActor::perform(flags, gfx); + if (unk184) + unk184->testPerform(flags, gfx); + if (unk188) + unk188->testPerform(flags, gfx); } -BOOL TBossTelesa::receiveMessage(THitActor*, u32) { return TRUE; } +BOOL TBossTelesa::receiveMessage(THitActor*, u32) { return FALSE; } -BOOL TBossTelesa::checkMessage(THitActor* sender, u32 message) +BOOL TBossTelesa::checkMessage(THitActor* actor, u32 message) { - return receiveMessage(sender, message); + return receiveMessage(actor, message); } -BOOL TBossTelesa::checkHitObject(THitActor* actor) +void TBossTelesa::checkHitObject(THitActor* actor) { - return actor != nullptr && actor->checkActorType(ACTOR_TYPE_PLAYER); + unk380 = -1; + + if ((actor->mActorType & ACTOR_TYPE_MASK) != ACTOR_TYPE_UNK40000000) + return; + if (mSpine->getCurrentNerve() != &TNerveBossTelesaPrepareSlot::theNerve()) + return; + + switch (actor->mActorType) { + case 0x40000390: + unk348.r = 0xE6; + unk348.g = 0x64; + unk348.b = 0xB4; + unk380 = 0xD8; + kill(); + break; + case 0x40000391: + case 0x40000392: + unk348.r = 0xE6; + unk348.g = 0xB4; + unk348.b = 0; + unk380 = 0xDA; + kill(); + break; + case 0x40000393: + unk348.r = 0x96; + unk348.g = 0x32; + unk348.b = 0xE6; + unk380 = 0xD9; + kill(); + break; + case 0x40000395: + break; + default: + return; + } + + if (!unk350 && actor->mActorType != 0x40000395) { + if (unk35A) { + unk35A = 0; + gpMarDirector->mConsole->startAppearBalloon(0xE000F, true); + } + unk35C++; + if (unk35C > 2) + gpMarDirector->mConsole->startAppearBalloon(0xE0010, true); + } else { + unk35C = 0; + } + + unk374 = actor->mPosition; + gpMarioParticleManager->emit(0xD7, &unk374, 0, nullptr); + if (unk380 >= 0) + gpMarioParticleManager->emit(unk380, &unk374, 0, nullptr); + + if (unk350) { + gpMarioParticleManager->emit(0xDB, &unk374, 0, nullptr); + } else { + if (gpMSound->gateCheck(0x2944)) { + MSoundSESystem::MSoundSE::startSoundActor(0x2944, &mPosition, 0, + nullptr, 0, 4); + } + } + + ((TMapObjBase*)actor)->makeObjDead(); } void TBossTelesa::setSpicy(TLiveActor* actor) { - if (actor) - actor->onLiveFlag(LIVE_FLAG_UNK10); - mIsSpicy = 1; + if (mSpine->getCurrentNerve() == &TNerveBossTelesaSpitSlotItem::theNerve()) + return; + if (mMActor->checkCurBckFromIndex(1)) + return; + + unk350 = 1; + unk36C = 0; + unk164 = mMActor->getCurAnmIdx(0); + unk160 = 1; + unk168 = 1.0f; + + J3DAnmTransform* oldAnm = nullptr; + if (mMActor->unkC) + oldAnm = mMActor->unkC->unk24; + if (mMActor->unkC) + mMActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + + mMActor->setBckFromIndex(1); + if (mMActor->unkC) + mMActor->unkC->setMotionBlendRatio(unk168); + + const char** basTable = getBasNameTable(); + setAnmSound(basTable ? basTable[1] : nullptr); + + if (unk35B) { + unk35B = 0; + gpMarDirector->mConsole->startAppearBalloon(0xE0011, true); + } + + actor->kill(); } void TBossTelesa::damageRecover() { - if (mDamageTimer > 0) - --mDamageTimer; - if (mDamageTimer == 0) - mDamage = 0; + f32 zero = 0.0f; + + for (int i = 0; i < 20; ++i) { + TLiveActor* actor = unk2A8[i]; + if (!(actor->mLiveFlag & LIVE_FLAG_DEAD)) { + if (actor->mHolder == nullptr) + SMS_SendMessageToMario(actor, HIT_MESSAGE_UNK8); + + ((TMapObjBase*)actor)->makeObjDead(); + gpMarioParticleManager->emit(0xCD, &actor->mPosition, 0, nullptr); + actor->mPosition.set(zero, zero, zero); + } + } + + for (int i = 0; i < 10; ++i) { + TLiveActor* actor = unk2F8[i]; + if (!(actor->mLiveFlag & LIVE_FLAG_DEAD)) { + if (actor->mHolder == nullptr) + SMS_SendMessageToMario(actor, HIT_MESSAGE_UNK8); + + ((TMapObjBase*)actor)->makeObjDead(); + gpMarioParticleManager->emit(0xCD, &actor->mPosition, 0, nullptr); + actor->mPosition.set(zero, zero, zero); + } + + actor = unk320[i]; + if (!(actor->mLiveFlag & LIVE_FLAG_DEAD)) { + ((TMapObjBase*)actor)->makeObjDead(); + gpMarioParticleManager->emit(0xCD, &actor->mPosition, 0, nullptr); + actor->mPosition.set(zero, zero, zero); + } + } + + if (unk350) { + if (gpMSound->gateCheck(0x2968)) { + MSoundSESystem::MSoundSE::startSoundActor(0x2968, &mPosition, 0, + nullptr, 0, 4); + } + } else { + if (gpMSound->gateCheck(0x28D5)) { + MSoundSESystem::MSoundSE::startSoundActor(0x28D5, &mPosition, 0, + nullptr, 0, 4); + } + } + + mSpine->pushAfterCurrent(&TNerveBossTelesaHide::theNerve()); + unk368 = 0; } void TBossTelesa::tongueHitWater() { } -u8 TBossTelesa::rouletteFall() +BOOL TBossTelesa::rouletteFall() { - if (mRouletteTimer > 0) - --mRouletteTimer; - return mRouletteTimer == 0; + TRoulette* roulette0 = (TRoulette*)unk178; + TRoulette* roulette1 = (TRoulette*)unk17C; + + if (roulette0->mPosition.y > roulette1->mPosition.y) { + roulette0->mPosition.y -= 1.0f; + roulette0->mMActor->setBck("rulet00"); + } else { + roulette0->mPosition.y = roulette1->mPosition.y; + return TRUE; + } + + if (roulette0->mPosition.y > roulette1->mPosition.y + 3.0f) { + if (SMS_SendMessageToMario(this, HIT_MESSAGE_TAKE)) + mHeldObject = (TTakeActor*)SMS_GetMarioHitActor(); + } else { + if (SMS_SendMessageToMario(this, HIT_MESSAGE_UNK8)) { + if (gpMSound->gateCheck(0x2926)) { + MSoundSESystem::MSoundSE::startSoundActor(0x2926, &mPosition, 0, + nullptr, 0, 4); + } + mHeldObject = nullptr; + } + } + + if (gpMSound->gateCheck(0x28DC)) { + MSoundSESystem::MSoundSE::startSoundActor(0x28DC, &mPosition, 0, + nullptr, 0, 4); + } + + if (gpMSound->gateCheck(0x2125)) { + MSoundSESystem::MSoundSE::startSoundActor(0x2125, &mPosition, 0, + nullptr, 0, 4); + } + + gpMarioOriginal->mGamePad->onNeutralMarioKey(); + return FALSE; } -u8 TBossTelesa::slotFall() +BOOL TBossTelesa::slotFall() { - if (!mSlot) - return 1; - return mSlot->isRollDrum() == 0; + if (unk184->mPosition.y > unk178->mPosition.y - 800.0f) { + unk184->mPosition.y -= 5.0f; + return FALSE; + } + + unk184->mPosition.y -= 1.0f; + + if (unk184->mPosition.y < unk178->mPosition.y - 900.0f) { + int rolling = 0; + if (unk178->unk13C != 0.0f) + rolling = 1; + if (unk17C->unk13C != 0.0f) + ++rolling; + if (unk180->unk13C != 0.0f) + ++rolling; + + if (rolling != 3) + rouletteStart(); + } + + if (unk184->mPosition.y < unk178->mPosition.y - 1100.0f) + return TRUE; + + THitActor* switchActor = unk178->unk150; + switchActor->mAttackRadius = 280.0f; + switchActor->mAttackHeight = 100.0f; + switchActor->mDamageRadius = 280.0f; + switchActor->mDamageHeight = 100.0f; + switchActor->calcEntryRadius(); + + switchActor = unk17C->unk150; + switchActor->mAttackRadius = 280.0f; + switchActor->mAttackHeight = 100.0f; + switchActor->mDamageRadius = 280.0f; + switchActor->mDamageHeight = 100.0f; + switchActor->calcEntryRadius(); + + return FALSE; } void TBossTelesa::openWaterPlace() { } -void TBossTelesa::flashItem(int item) +void TBossTelesa::flashItem(int result) { - mSlotResult = item; - mDamageTimer = 0; + int phase = result % 16; + + int index = 0; + for (int i = 0; i < 5; ++i) { + TLiveActor* actor = unk2A8[index++]; + u32* liveFlag = &actor->mLiveFlag; + if (!(*liveFlag & LIVE_FLAG_DEAD) && actor->mHolder == nullptr) { + if (phase < 8) + *liveFlag |= LIVE_FLAG_HIDDEN; + else + *liveFlag &= ~LIVE_FLAG_HIDDEN; + } + + actor = unk2A8[index++]; + liveFlag = &actor->mLiveFlag; + if (!(*liveFlag & LIVE_FLAG_DEAD) && actor->mHolder == nullptr) { + if (phase < 8) + *liveFlag |= LIVE_FLAG_HIDDEN; + else + *liveFlag &= ~LIVE_FLAG_HIDDEN; + } + + actor = unk2A8[index++]; + liveFlag = &actor->mLiveFlag; + if (!(*liveFlag & LIVE_FLAG_DEAD) && actor->mHolder == nullptr) { + if (phase < 8) + *liveFlag |= LIVE_FLAG_HIDDEN; + else + *liveFlag &= ~LIVE_FLAG_HIDDEN; + } + + actor = unk2A8[index++]; + liveFlag = &actor->mLiveFlag; + if (!(*liveFlag & LIVE_FLAG_DEAD) && actor->mHolder == nullptr) { + if (phase < 8) + *liveFlag |= LIVE_FLAG_HIDDEN; + else + *liveFlag &= ~LIVE_FLAG_HIDDEN; + } + } + + for (int i = 0; i < 10; ++i) { + TLiveActor* actor = unk2F8[i]; + u32* liveFlag = &actor->mLiveFlag; + if (!(*liveFlag & LIVE_FLAG_DEAD) && actor->mHolder == nullptr) { + if (phase < 8) + *liveFlag |= LIVE_FLAG_HIDDEN; + else + *liveFlag &= ~LIVE_FLAG_HIDDEN; + } + + actor = unk320[i]; + liveFlag = &actor->mLiveFlag; + if (!(*liveFlag & LIVE_FLAG_DEAD)) { + if (phase < 8) + *liveFlag |= LIVE_FLAG_HIDDEN; + else + *liveFlag &= ~LIVE_FLAG_HIDDEN; + } + } } void TBossTelesa::onAllCollision() { - if (mBodyCollision) - mBodyCollision->onHitFlag(HIT_FLAG_NO_COLLISION); - if (mTongueCollision) - mTongueCollision->onHitFlag(HIT_FLAG_NO_COLLISION); + offHitFlag(HIT_FLAG_NO_COLLISION); + unk16C->offHitFlag(HIT_FLAG_NO_COLLISION); + unk170->offHitFlag(HIT_FLAG_NO_COLLISION); + unk174->offHitFlag(HIT_FLAG_NO_COLLISION); } void TBossTelesa::offAllCollision() { - if (mBodyCollision) - mBodyCollision->offHitFlag(HIT_FLAG_NO_COLLISION); - if (mTongueCollision) - mTongueCollision->offHitFlag(HIT_FLAG_NO_COLLISION); + onHitFlag(HIT_FLAG_NO_COLLISION); + unk16C->onHitFlag(HIT_FLAG_NO_COLLISION); + unk170->onHitFlag(HIT_FLAG_NO_COLLISION); + unk174->onHitFlag(HIT_FLAG_NO_COLLISION); } const char** TBossTelesa::getBasNameTable() const { return btelesa_bastable; } void TBossTelesa::genAttacker() { - mGenerateTimer = mSaveParams ? mSaveParams->mSLGenAttackerTime.get() : 500; + if (unk150) { + TTelesa* telesa = (TTelesa*)gpConductor->makeOneEnemyAppear( + mPosition, "テレサマネージャー", 1); + if (telesa) + telesa->initAttacker(this); + return; + } + + TBossTelesaSaveLoadParams* params = (TBossTelesaSaveLoadParams*)unk15C; + s32 count = params->mSLNumGenBubble.get(); + MtxPtr rootMtx = mMActor->unk4->mNodeMatrices[5]; + f32 angleStep = 180.0f / count; + f32 angleOffset = count * 0.5f; + + for (int i = 0; i < count; ++i) { + TBubble* bubble = (TBubble*)gpConductor->makeOneEnemyAppear( + mPosition, "バブルマネージャー", 1); + if (!bubble) + return; + + Mtx rot; + Vec velocity; + velocity.x = 0.0f; + velocity.y = 0.0f; + velocity.z = -50.0f; + MsMtxSetRotRPH(rot, mRotation.x, + mRotation.y - angleOffset + angleStep * i, mRotation.z); + PSMTXMultVec(rot, &velocity, &velocity); + MsVECNormalize(&velocity, &velocity); + + velocity.y = 2.0f; + f32 speed = params->mSL1stBubbleSp.get(); + velocity.x *= speed; + velocity.z *= speed; + + bubble->mPosition.x = rootMtx[0][3]; + bubble->mPosition.y = rootMtx[1][3] - 50.0f; + bubble->mPosition.z = rootMtx[2][3]; + bubble->mVelocity = velocity; + bubble->mPosition.y += 10.0f; + bubble->onLiveFlag(LIVE_FLAG_AIRBORNE); + + f32 itemRoll = rand() * 0.000030517578f; + if (itemRoll < mItemGenRate) { + bubble->unk198 = nullptr; + TMapObjBase* item = gpItemManager->makeObjAppear( + bubble->mPosition.x, bubble->mPosition.y, bubble->mPosition.z, + 0x20000008, true); + if (item && item->receiveMessage(bubble, HIT_MESSAGE_TAKE)) { + item->appear(); + item->mPosition = bubble->mPosition; + item->mVelocity.set(0.0f, 15.0f, 0.0f); + item->offLiveFlag(LIVE_FLAG_UNK10); + bubble->mHeldObject = item; + bubble->unk198 = item; + } + } else { + f32 enemyRoll = rand() * 0.000030517578f; + if (enemyRoll < mEnemyGenRate) + bubble->appendEnemy(); + } + } } void TBossTelesa::setBckAnm(int index) { - if (getMActor()) - getMActor()->setBckFromIndex(index); + if (mMActor) + mMActor->setBckFromIndex(index); } -bool TBossTelesa::isInDamage() { return mInDamage != 0; } +bool TBossTelesa::isInDamage() { return unk35B != 0; } void TBossTelesa::rouletteStart() { - mRouletteTimer = 0; - mSlotStop = 0; - if (mSlot) - mSlot->moveStart(); + TMsRange speedRange(0.05f, 0.1f); + TMsRange directionRange(-1.0f, 1.0f); + f32 dir = directionRange.rand(); + + TSpineEnemyParams* params = getSaveParam(); + u8 maxHitPoints = params ? getSaveParam()->mSLHitPointMax.get() : 1; + f32 hpSpeed = (maxHitPoints - mHitPoints) * TBossTelesa::mRouletteUpRate; + + for (int i = 0; i < 3; ++i) { + f32 direction = 1.0f; + if (dir > 0.0f) + direction = -1.0f; + if (i == 0 || i == 2) + direction = -direction; + + f32 speed = speedRange.rand(); + ((TRoulette**)&unk178)[i]->unk144 = direction * (speed + hpSpeed); + + speed = speedRange.rand(); + unk184->unk1E4[i] = direction * (speed + hpSpeed); + } + + for (int i = 0; i < 3; ++i) + ((TRoulette**)&unk178)[i]->setRollSp(unk184->unk1E4[i]); + + SMSRumbleMgr->start(0x14, 0xf, (f32*)nullptr); + gpCameraShake->startShake((EnumCamShakeMode)0x23, 1.0f); } void TBossTelesa::slotStart() { rouletteStart(); } void TBossTelesa::slotStop() { - if (mSlot) - mSlot->forceStopSlot(0); + if (unk184) + unk184->forceStopSlot(0); } -int TBossTelesa::checkSlotResult() { return mSlot ? mSlotResult : -1; } +int TBossTelesa::checkSlotResult() +{ + return unk184 ? unk184->getSlotResult() : -1; +} void TBossTelesa::generateSlotItem() { - ++mSlotItemCount; - mGenerateTimer = 0; + static const char* manNameTable[] = { + "バブルマネージャー", "ハムクリマネージャー", + "ヤキグリマネージャー", "ボム兵マネージャー", + "ポイハナマネージャー", "電気ノコノコマネージャー", + "ポポマネージャー", "ゲッソーマネージャー", + "とびプクマネージャー", + }; + + unk368 = 0; + unk274 = 0; + + TTelesaSlot* slot = (TTelesaSlot*)unk184; + s32 result = slot->getResultFromAng(slot->unk13C[0]); + for (int i = 1; i < 3; ++i) { + if (slot->getResultFromAng(slot->unk13C[i]) != result) { + result = -1; + break; + } + } + unk1A8 = result; + + TBossTelesaSaveLoadParams* params = (TBossTelesaSaveLoadParams*)unk15C; + s32 slotItemNum = params->mSLSlotItemNum.get(); + MtxPtr rootMtx = mMActor->unk4->mNodeMatrices[5]; + f32 angleStep = 120.0f / slotItemNum; + f32 angleOffset = angleStep * slotItemNum * 0.5f; + + if (unk1A8 == 2) { + s32 numFruit = params->mSLSlotFruitNum.get(); + if (numFruit > 20) + numFruit = 20; + + s32 angleIndex = (s32)(numFruit * (rand() * 0.000030517578f)); + + for (int i = 0; i < numFruit; ++i) { + if (unk2A8[i]->mHolder) + continue; + + Mtx rot; + Vec dir; + Vec normalizedDir; + dir.x = 0.0f; + dir.y = 0.0f; + dir.z = 200.0f; + + f32 fruitAngleStep = 160.0f / numFruit; + MsMtxSetRotRPH(rot, mRotation.x, + mRotation.y - angleOffset + + fruitAngleStep * angleIndex, + mRotation.z); + + if (numFruit > 0) { + angleIndex += i; + while (angleIndex >= numFruit) + angleIndex -= numFruit; + while (angleIndex < 0) + angleIndex += numFruit; + } else { + angleIndex = 0; + } + + PSMTXMultVec(rot, &dir, &dir); + MsVECNormalize(&dir, &normalizedDir); + + TMapObjBase* actor; + if (i == 0 || i == 4) + actor = (TMapObjBase*)unk2F8[i]; + else + actor = (TMapObjBase*)unk2A8[i]; + + Vec velocity; + TMsRange fruitSpeedRange(6.0f, 10.0f); + + if (i == 0 || i == 4) { + actor->makeObjAppeared(); + actor->offLiveFlag(LIVE_FLAG_HIDDEN); + + velocity.x = normalizedDir.x * fruitSpeedRange.rand(); + velocity.y = -2.0f; + velocity.z = normalizedDir.z * fruitSpeedRange.rand(); + if (i == 0) { + velocity.x + = normalizedDir.x * fruitSpeedRange.rand() * 2.0f; + velocity.z + = normalizedDir.z * fruitSpeedRange.rand() * 2.0f; + } + + actor->mVelocity = velocity; + actor->offLiveFlag(LIVE_FLAG_UNK10); + actor->mRotation.set(0.0f, 90.0f, 0.0f); + } else { + actor->makeObjAppeared(); + actor->offLiveFlag(LIVE_FLAG_HIDDEN); + + velocity.x = normalizedDir.x * fruitSpeedRange.rand(); + velocity.y = -2.0f; + velocity.z = normalizedDir.z * fruitSpeedRange.rand(); + + actor->mVelocity = velocity; + actor->offLiveFlag(LIVE_FLAG_UNK10); + } + + unk1AC[unk274] = actor; + unk1AC[i]->onHitFlag(HIT_FLAG_NO_COLLISION); + unk1AC[i]->mScaling.set(1.5f, 1.5f, 1.5f); + unk1AC[unk274]->mPosition.x = rootMtx[0][3] + dir.x; + unk1AC[unk274]->mPosition.y = rootMtx[1][3] - 50.0f; + unk1AC[unk274]->mPosition.z = rootMtx[2][3] + dir.z; + unk274++; + } + } else if (unk1A8 == 0) { + s32 numItems = params->mSLSlotFruitNum.get(); + if (numItems > 10) + numItems = 10; + + if (unk370) + unk370--; + else + unk370 = 0; + + f32 itemAngleStep = 120.0f / numItems; + f32 itemAngleOffset = itemAngleStep * numItems * 0.5f; + for (int i = 0; i < numItems; ++i) { + if (i >= 10) + return; + + Mtx rot; + Vec dir; + dir.x = 0.0f; + dir.y = 0.0f; + dir.z = 250.0f; + MsMtxSetRotRPH(rot, mRotation.x, + mRotation.y - itemAngleOffset + itemAngleStep * i, + mRotation.z); + PSMTXMultVec(rot, &dir, &dir); + MsVECNormalize(&dir, &dir); + dir.y = 10.0f; + + Vec velocity; + TMsRange itemSpeedRange(0.8f, 3.5f); + f32 speed = params->mSL1stBubbleSp.get(); + velocity.x = dir.x * speed * itemSpeedRange.rand(); + velocity.y = dir.y; + velocity.z = dir.z * speed * itemSpeedRange.rand(); + + TMapObjBase* item = gpItemManager->makeObjAppeared(0x2000000E); + item->mPosition.x = rootMtx[0][3]; + item->mPosition.y = rootMtx[1][3] - 250.0f; + item->mPosition.z = rootMtx[2][3]; + item->mVelocity = velocity; + item->offLiveFlag(LIVE_FLAG_UNK10); + item->mScaling.set(0.0f, 0.0f, 0.0f); + ((TItem*)item)->killByTimer(0x3C0); + + unk1AC[unk274] = unk320[i]; + unk1AC[unk274]->offLiveFlag(LIVE_FLAG_HIDDEN); + unk274++; + } + } else { + s32 count = slotItemNum; + s32 kind = 0; + if (unk1A8 == -1) { + count *= 2; + kind = 0; + } else if (unk1A8 == 1) { + if (mHitPoints > 2) + kind = 1; + else + kind = 2; + } + + s32 maxKind = 7; + if (mHitPoints == 1) + maxKind = 8; + + s32 randomKind = 1 + (s32)((maxKind - 1) * (rand() * 0.000030517578f)); + + for (int i = 0; i < count; ++i) { + if (unk1A8 == 3) { + if ((i & 1) == 0) + randomKind++; + if (randomKind > maxKind) + randomKind = 1; + kind = randomKind; + } + + TSmallEnemy* enemy = (TSmallEnemy*)gpConductor->makeOneEnemyAppear( + mPosition, manNameTable[kind], 2); + if (!enemy) + continue; + + if (kind != 0) { + unk1AC[unk274] = enemy; + unk274++; + } + + Mtx rot; + Vec dir; + dir.x = 0.0f; + dir.y = 0.0f; + dir.z = 200.0f; + MsMtxSetRotRPH(rot, mRotation.x, + mRotation.y - angleOffset + angleStep * i, + mRotation.z); + PSMTXMultVec(rot, &dir, &dir); + MsVECNormalize(&dir, &dir); + dir.y = 2.0f; + + Vec velocity; + TMsRange enemySpeedRange(0.5f, 1.0f); + f32 speed = params->mSL1stBubbleSp.get(); + velocity.x = dir.x * speed * enemySpeedRange.rand(); + velocity.y = dir.y * (2.0f + enemySpeedRange.rand()); + velocity.z = dir.z * speed * enemySpeedRange.rand(); + + enemy->mPosition.x = rootMtx[0][3]; + enemy->mPosition.y = rootMtx[1][3] - 250.0f; + enemy->mPosition.z = rootMtx[2][3]; + enemy->mVelocity = velocity; + enemy->mPosition.y += 10.0f; + enemy->onLiveFlag(LIVE_FLAG_AIRBORNE); + PSMTXCopy(rootMtx, enemy->mMActor->unk4->unk20); + enemy->mMActor->calc(); + enemy->initAttacker(this); + } + } } -void TBossTelesa::fruitCollisionOn() { mSlotStop = 0; } +void TBossTelesa::fruitCollisionOn() { unk370 = 0; } -bool TBossTelesa::checkSlot() { return mSlot != nullptr; } +bool TBossTelesa::checkSlot() { return unk184 != nullptr; } bool TBossTelesa::checkAllItemDead() { - return mItem0 == 0 && mItem1 == 0 && mItem2 == 0 && mItem3 == 0; + for (int i = 0; i < unk274; ++i) + if (!(unk1AC[i]->mLiveFlag & LIVE_FLAG_DEAD)) + return false; + return true; } +#pragma dont_inline on void TBossTelesa::forceAllItemKill() { - mItem0 = mItem1 = mItem2 = mItem3 = 0; - mFruit0 = mFruit1 = mFruit2 = 0; + f32 zero = 0.0f; + + for (int i = 0; i < unk274; ++i) { + if (unk1AC[i]->mHolder) { + SMS_SendMessageToMario(unk1AC[i], HIT_MESSAGE_UNK8); + unk1AC[i]->mHolder = nullptr; + } + + unk1AC[i]->mPosition.set(zero, zero, zero); + unk1AC[i]->onHitFlag(HIT_FLAG_NO_COLLISION); + + if (!(unk1AC[i]->mLiveFlag & LIVE_FLAG_DEAD)) { + unk1AC[i]->kill(); + gpMarioParticleManager->emit(0xCD, &unk1AC[i]->mPosition, 0, + nullptr); + } + } } +#pragma dont_inline off void TBossTelesa::rollRouletteCircle() { - if (mSlot) - mSlot->moveStart(); + if (unk184) + unk184->moveStart(); } -bool TBossTelesa::isForceRestart() { return mForceRestart != 0; } +bool TBossTelesa::isForceRestart() { return unk35A != 0; } void TBossTelesa::forceHide() { - mDead = 1; - offLiveFlag(LIVE_FLAG_UNK200); - onLiveFlag(LIVE_FLAG_HIDDEN); + if (mSpine->getCurrentNerve() == &TNerveBossTelesaDie::theNerve()) + return; + if (mMActor->checkCurBckFromIndex(4)) + return; + if (mMActor->checkCurBckFromIndex(0)) + return; + + forceAllItemKill(); + unk368 = 0; + + if (unk350) { + if (gpMSound->gateCheck(0x2968)) { + MSoundSESystem::MSoundSE::startSoundActor(0x2968, &mPosition, 0, + nullptr, 0, 4); + } + } else { + if (gpMSound->gateCheck(0x28D5)) { + MSoundSESystem::MSoundSE::startSoundActor(0x28D5, &mPosition, 0, + nullptr, 0, 4); + } + } + + mSpine->reset(); + mSpine->setNext(&TNerveBossTelesaHide::theNerve()); } void TBossTelesa::fanfale() { } DEFINE_NERVE(TNerveBossTelesaDie, TLiveActor) { - if (spine->getTime() == 0) - static_cast(spine->getBody())->kill(); + TBossTelesa* boss = getBoss(spine); + if (spine->getTime() == 0) { + boss->unk388 = 0; + if (boss->unk350 && boss->mHitPoints != 0) + --boss->mHitPoints; + + boss->onHitFlag(HIT_FLAG_NO_COLLISION); + boss->unk16C->onHitFlag(HIT_FLAG_NO_COLLISION); + boss->unk170->onHitFlag(HIT_FLAG_NO_COLLISION); + + if (boss->mHitPoints != 0) { + if (boss->unk350) { + boss->mMActor->setBrkFromIndex(1); + boss->unk164 = boss->mMActor->getCurAnmIdx(0); + boss->unk160 = 2; + boss->unk168 = 1.0f; + + J3DAnmTransform* oldAnm = nullptr; + if (boss->mMActor->unkC) + oldAnm = boss->mMActor->unkC->unk24; + if (boss->mMActor->unkC) + boss->mMActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + + boss->mMActor->setBckFromIndex(2); + if (boss->mMActor->unkC) + boss->mMActor->unkC->setMotionBlendRatio(boss->unk168); + + const char** basTable = boss->getBasNameTable(); + boss->setAnmSound(basTable ? basTable[2] : nullptr); + gpCameraShake->startShake((EnumCamShakeMode)0x1F, 1.0f); + } else { + boss->unk164 = boss->mMActor->getCurAnmIdx(0); + boss->unk160 = 5; + boss->unk168 = 1.0f; + + J3DAnmTransform* oldAnm = nullptr; + if (boss->mMActor->unkC) + oldAnm = boss->mMActor->unkC->unk24; + if (boss->mMActor->unkC) + boss->mMActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + + boss->mMActor->setBckFromIndex(5); + if (boss->mMActor->unkC) + boss->mMActor->unkC->setMotionBlendRatio(boss->unk168); + + const char** basTable = boss->getBasNameTable(); + boss->setAnmSound(basTable ? basTable[5] : nullptr); + boss->mMActor->setBrkFromIndex(0); + gpCameraShake->startShake((EnumCamShakeMode)0x20, 1.0f); + } + } else { + MSBgm::stopBGM(0x8001000D, 10); + gpCameraShake->startShake((EnumCamShakeMode)0x21, 1.0f); + boss->unk164 = boss->mMActor->getCurAnmIdx(0); + boss->unk160 = 3; + boss->unk168 = 1.0f; + + J3DAnmTransform* oldAnm = nullptr; + if (boss->mMActor->unkC) + oldAnm = boss->mMActor->unkC->unk24; + if (boss->mMActor->unkC) + boss->mMActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + + boss->mMActor->setBckFromIndex(3); + if (boss->mMActor->unkC) + boss->mMActor->unkC->setMotionBlendRatio(boss->unk168); + + const char** basTable = boss->getBasNameTable(); + boss->setAnmSound(basTable ? basTable[3] : nullptr); + boss->mMActor->setBrkFromIndex(1); + boss->unk184->mScaling.set(0.0f, 0.0f, 0.0f); + + if (gpMSound->gateCheck(0x28DB)) { + MSoundSESystem::MSoundSE::startSoundActor( + 0x28DB, &boss->mPosition, 0, nullptr, 0, 4); + } + } + } + + if (boss->mHitPoints == 0) { + if (boss->checkCurAnmEnd(0)) { + if (boss->unk388 == 0) { + MtxPtr mtx = boss->mMActor->getModel()->mNodeMatrices[1]; + boss->unk374.set(mtx[0][3], mtx[1][3], mtx[2][3]); + + gpMarioParticleManager->emit(0xDC, &boss->unk374, 0, nullptr); + if (boss->unk380 == 0xD8) { + gpMarioParticleManager->emit(0xDD, &boss->unk374, 0, + nullptr); + } else if (boss->unk380 == 0xD9) { + gpMarioParticleManager->emit(0xDE, &boss->unk374, 0, + nullptr); + } else { + gpMarioParticleManager->emit(0xDF, &boss->unk374, 0, + nullptr); + } + + boss->forceAllItemKill(); + boss->unk178->unk144 = 0.0f; + boss->unk184->unk1E4[0] = 0.0f; + boss->unk17C->unk144 = 0.0f; + boss->unk184->unk1E4[1] = 0.0f; + boss->unk180->unk144 = 0.0f; + boss->unk184->unk1E4[2] = 0.0f; + boss->unk178->setRollSp(boss->unk184->unk1E4[0]); + boss->unk17C->setRollSp(boss->unk184->unk1E4[1]); + boss->unk180->setRollSp(boss->unk184->unk1E4[2]); + } + + if (boss->unk388 > 240) { + boss->unk388 = 0; + gpItemManager->makeShineAppearWithDemo( + "シャイン(ボス用)", "ボスシャインカメラ", + boss->mPosition.x, boss->mPosition.y, boss->mPosition.z); + boss->onLiveFlag(LIVE_FLAG_DEAD); + boss->onLiveFlag(LIVE_FLAG_UNK8); + boss->offLiveFlag(LIVE_FLAG_UNK10000); + boss->mHolder = nullptr; + boss->onHitFlag(HIT_FLAG_NO_COLLISION); + boss->unk16C->onHitFlag(HIT_FLAG_NO_COLLISION); + boss->unk170->onHitFlag(HIT_FLAG_NO_COLLISION); + boss->stopAnmSound(); + spine->reset(); + return TRUE; + } + + boss->unk388++; + } + return FALSE; + } + + if (boss->checkCurAnmEnd(0)) { + if (boss->mMActor->checkCurBckFromIndex(5)) { + boss->mMActor->setBrkFromIndex(2); + boss->unk164 = boss->mMActor->getCurAnmIdx(0); + boss->unk160 = 7; + boss->unk168 = 1.0f; + + J3DAnmTransform* oldAnm = nullptr; + if (boss->mMActor->unkC) + oldAnm = boss->mMActor->unkC->unk24; + if (boss->mMActor->unkC) + boss->mMActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + + boss->mMActor->setBckFromIndex(7); + if (boss->mMActor->unkC) + boss->mMActor->unkC->setMotionBlendRatio(boss->unk168); + + const char** basTable = boss->getBasNameTable(); + boss->setAnmSound(basTable ? basTable[7] : nullptr); + } else if (boss->mMActor->checkCurBckFromIndex(7)) { + boss->unk164 = boss->mMActor->getCurAnmIdx(0); + boss->unk160 = 6; + boss->unk168 = 1.0f; + + J3DAnmTransform* oldAnm = nullptr; + if (boss->mMActor->unkC) + oldAnm = boss->mMActor->unkC->unk24; + if (boss->mMActor->unkC) + boss->mMActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + + boss->mMActor->setBckFromIndex(6); + if (boss->mMActor->unkC) + boss->mMActor->unkC->setMotionBlendRatio(boss->unk168); + + const char** basTable = boss->getBasNameTable(); + boss->setAnmSound(basTable ? basTable[6] : nullptr); + } else { + SMS_ResetDamageFogEffect(boss->mMActor->getModel()->getModelData()); + + if (boss->mMActor->checkCurBckFromIndex(6)) { + boss->offHitFlag(HIT_FLAG_NO_COLLISION); + boss->unk16C->offHitFlag(HIT_FLAG_NO_COLLISION); + boss->unk170->offHitFlag(HIT_FLAG_NO_COLLISION); + + boss->unk164 = boss->mMActor->getCurAnmIdx(0); + boss->unk160 = 15; + boss->unk168 = 1.0f; + + J3DAnmTransform* oldAnm = nullptr; + if (boss->mMActor->unkC) + oldAnm = boss->mMActor->unkC->unk24; + if (boss->mMActor->unkC) + boss->mMActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + + boss->mMActor->setBckFromIndex(15); + if (boss->mMActor->unkC) + boss->mMActor->unkC->setMotionBlendRatio(boss->unk168); + + const char** basTable = boss->getBasNameTable(); + boss->setAnmSound(basTable ? basTable[15] : nullptr); + boss->mMActor->setBtpFromIndex(2); + spine->pushAfterCurrent( + &TNerveBossTelesaPrepareSlot::theNerve()); + } else { + boss->damageRecover(); + } + return TRUE; + } + } + + return FALSE; +} + +DEFINE_NERVE(TNerveBossTelesaSpit, TLiveActor) +{ + TBossTelesa* boss = getBoss(spine); + if (spine->getTime() == 0 || !boss->mMActor->checkCurBckFromIndex(14)) { + boss->unk164 = boss->mMActor->getCurAnmIdx(0); + boss->unk160 = 14; + boss->unk168 = 1.0f; + + MActor* oldAnmActor = boss->mMActor; + J3DAnmTransform* oldAnm; + if (!oldAnmActor->unkC) + oldAnm = nullptr; + else + oldAnm = oldAnmActor->unkC->unk24; + if (oldAnmActor->unkC) + oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + + boss->mMActor->setBckFromIndex(14); + MActor* blendActor = boss->mMActor; + f32 blendRatio = boss->unk168; + if (blendActor->unkC) + blendActor->unkC->setMotionBlendRatio(blendRatio); + + const char** basTable = boss->getBasNameTable(); + const char* basName; + if (!basTable) + basName = nullptr; + else + basName = basTable[14]; + boss->setAnmSound(basName); + } else { + if (boss->mMActor->getFrameCtrl(0)->checkPass(40.0f)) + boss->genAttacker(); + } + + if (boss->checkCurAnmEnd(0)) + return true; return false; } -DEFINE_NERVE(TNerveBossTelesaSpit, TLiveActor) { return spine->getTime() > 20; } - DEFINE_NERVE(TNerveBossTelesaHide, TLiveActor) { - if (spine->getTime() == 0) - static_cast(spine->getBody())->forceHide(); - return spine->getTime() > 30; + TBossTelesa* boss = getBoss(spine); + if (!boss->mMActor->checkCurBckFromIndex(4)) { + boss->unk164 = boss->mMActor->getCurAnmIdx(0); + boss->unk160 = 4; + boss->unk168 = 1.0f; + + MActor* oldAnmActor = boss->mMActor; + J3DAnmTransform* oldAnm; + if (!oldAnmActor->unkC) + oldAnm = nullptr; + else + oldAnm = oldAnmActor->unkC->unk24; + if (oldAnmActor->unkC) + oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + + boss->mMActor->setBckFromIndex(4); + if (boss->mMActor->unkC) + boss->mMActor->unkC->setMotionBlendRatio(boss->unk168); + + const char** basTable = boss->getBasNameTable(); + const char* basName; + if (!basTable) + basName = nullptr; + else + basName = basTable[4]; + boss->setAnmSound(basName); + boss->mMActor->setBtpFromIndex(2); + } + + if (boss->checkCurAnmEnd(0)) { + boss->onHitFlag(HIT_FLAG_NO_COLLISION); + boss->unk16C->onHitFlag(HIT_FLAG_NO_COLLISION); + boss->unk170->onHitFlag(HIT_FLAG_NO_COLLISION); + SMSRumbleMgr->start(0x14, 0xF, (f32*)nullptr); + boss->rouletteStart(); + spine->pushAfterCurrent(&TNerveBossTelesaHideWait::theNerve()); + return TRUE; + } + return FALSE; } DEFINE_NERVE(TNerveBossTelesaHideWait, TLiveActor) { - return spine->getTime() > 60; + TBossTelesa* boss = getBoss(spine); + if (spine->getTime() == 0) { + boss->onLiveFlag(LIVE_FLAG_HIDDEN); + boss->unk350 = 0; + + u8 maxHp = boss->getSaveParam() + ? boss->getSaveParam()->mSLHitPointMax.get() + : 1; + u8 alpha = TBossTelesa::mNormalAlpha + (maxHp - boss->mHitPoints) * 30; + alpha = MsClamp(alpha, 0, 0xFE); + boss->unk34C.a = alpha; + + boss->unk184->mScaling.set(0.0f, 0.0f, 0.0f); + boss->mMActor->setBrkFromIndex(2); + s16 endFrame = boss->mMActor->getFrameCtrl(5)->getEnd(); + boss->mMActor->getFrameCtrl(5)->setFrame((f32)endFrame); + } else { + JGeometry::TVec3 pos = boss->mPosition; + pos.sub(*gpMarioPos); + + if (spine->getTime() > 400 + && ((TBossTelesaKillSmallEnemy*)boss->unk174)->unk6C == 0) { + spine->pushAfterCurrent(&TNerveBossTelesaAppear::theNerve()); + boss->offLiveFlag(LIVE_FLAG_HIDDEN); + return TRUE; + } + } + + return FALSE; } DEFINE_NERVE(TNerveBossTelesaAppear, TLiveActor) { - return spine->getTime() > 30; + TBossTelesa* boss = getBoss(spine); + if (spine->getTime() == 0) { + if (!boss->mMActor->checkCurBckFromIndex(0)) { + boss->unk164 = boss->mMActor->getCurAnmIdx(0); + boss->unk160 = 0; + boss->unk168 = 1.0f; + + J3DAnmTransform* oldAnm = nullptr; + if (boss->mMActor->unkC) + oldAnm = boss->mMActor->unkC->unk24; + if (boss->mMActor->unkC) + boss->mMActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + + boss->mMActor->setBckFromIndex(0); + if (boss->mMActor->unkC) + boss->mMActor->unkC->setMotionBlendRatio(boss->unk168); + + const char** basTable = boss->getBasNameTable(); + boss->setAnmSound(basTable ? basTable[0] : nullptr); + + if (!boss->unk384) { + boss->unk384 = 1; + MSBgm::startBGM(0x8001000D); + } + + boss->unk184->mScaling.set(1.0f, 1.0f, 1.0f); + boss->unk184->randomReset(); + boss->offHitFlag(HIT_FLAG_NO_COLLISION); + boss->unk16C->offHitFlag(HIT_FLAG_NO_COLLISION); + boss->unk170->offHitFlag(HIT_FLAG_NO_COLLISION); + } + } else if (boss->checkCurAnmEnd(0) + && !boss->mMActor->checkCurBckFromIndex(15)) { + boss->unk164 = boss->mMActor->getCurAnmIdx(0); + boss->unk160 = 15; + boss->unk168 = 1.0f; + + J3DAnmTransform* oldAnm = nullptr; + if (boss->mMActor->unkC) + oldAnm = boss->mMActor->unkC->unk24; + if (boss->mMActor->unkC) + boss->mMActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + + boss->mMActor->setBckFromIndex(15); + if (boss->mMActor->unkC) + boss->mMActor->unkC->setMotionBlendRatio(boss->unk168); + + const char** basTable = boss->getBasNameTable(); + boss->setAnmSound(basTable ? basTable[15] : nullptr); + boss->mMActor->setBtpFromIndex(2); + } + + if (boss->mMActor->checkCurBckFromIndex(0) + && boss->mMActor->getFrameCtrl(0)->checkPass(78.0f)) { + gpCameraShake->startShake((EnumCamShakeMode)0x22, 1.0f); + if (gpMSound->gateCheck(0x292A)) { + MSoundSESystem::MSoundSE::startSoundActor(0x292A, &boss->mPosition, + 0, nullptr, 0, 4); + } + } + + if (spine->getTime() > 800) { + u8 maxHp = boss->getSaveParam() + ? boss->getSaveParam()->mSLHitPointMax.get() + : 1; + int interval = TBossTelesa::mTelesaGenerateInterval + + (maxHp - boss->mHitPoints) * 100; + if (spine->getTime() % interval == 1) { + boss->unk164 = boss->mMActor->getCurAnmIdx(0); + boss->unk160 = 14; + boss->unk168 = 1.0f; + + J3DAnmTransform* oldAnm = nullptr; + if (boss->mMActor->unkC) + oldAnm = boss->mMActor->unkC->unk24; + if (boss->mMActor->unkC) + boss->mMActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + + boss->mMActor->setBckFromIndex(14); + if (boss->mMActor->unkC) + boss->mMActor->unkC->setMotionBlendRatio(boss->unk168); + + const char** basTable = boss->getBasNameTable(); + boss->setAnmSound(basTable ? basTable[14] : nullptr); + } + } + + boss->unk364 *= 0.96f; + return FALSE; } DEFINE_NERVE(TNerveBossTelesaSlotStart, TLiveActor) { - if (spine->getTime() == 0) - static_cast(spine->getBody())->rouletteStart(); - return spine->getTime() > 60; + TBossTelesa* boss = getBoss(spine); + if (spine->getTime() == 0) { + boss->unk164 = boss->mMActor->getCurAnmIdx(0); + boss->unk160 = 11; + boss->unk168 = 1.0f; + + J3DAnmTransform* oldAnm = nullptr; + if (boss->mMActor->unkC) + oldAnm = boss->mMActor->unkC->unk24; + if (boss->mMActor->unkC) + boss->mMActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + + boss->mMActor->setBckFromIndex(11); + if (boss->mMActor->unkC) + boss->mMActor->unkC->setMotionBlendRatio(boss->unk168); + + const char** basTable = boss->getBasNameTable(); + boss->setAnmSound(basTable ? basTable[11] : nullptr); + } + + if (boss->mMActor->checkCurBckFromIndex(11)) { + if (boss->mMActor->getFrameCtrl(0)->checkPass(53.0f)) { + boss->unk18C = 1; + boss->unk184->moveStart(); + ((TTelesaManager*)boss->unk354)->telesaForceKill(); + } + + if (boss->checkCurAnmEnd(0)) { + boss->unk164 = boss->mMActor->getCurAnmIdx(0); + boss->unk160 = 15; + boss->unk168 = 1.0f; + + J3DAnmTransform* oldAnm = nullptr; + if (boss->mMActor->unkC) + oldAnm = boss->mMActor->unkC->unk24; + if (boss->mMActor->unkC) + boss->mMActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + + boss->mMActor->setBckFromIndex(15); + if (boss->mMActor->unkC) + boss->mMActor->unkC->setMotionBlendRatio(boss->unk168); + + const char** basTable = boss->getBasNameTable(); + boss->setAnmSound(basTable ? basTable[15] : nullptr); + boss->mMActor->setBtpFromIndex(2); + boss->unk184->forceStopSlot(1); + } + } + + if (!boss->unk184->isRollDrum() && boss->unk18C) { + boss->unk18C = 0; + boss->mSpine->pushAfterCurrent( + &TNerveBossTelesaSpitSlotItem::theNerve()); + return TRUE; + } + + boss->unk364 *= 0.99f; + return FALSE; } DEFINE_NERVE(TNerveBossTelesaSpitSlotItem, TLiveActor) { - return spine->getTime() > 20; + TBossTelesa* boss = getBoss(spine); + if (!boss->mMActor->checkCurBckFromIndex(14) + && boss->unk364 < TBossTelesa::mBaseHoseiPosY - 200.0f) { + boss->unk164 = boss->mMActor->getCurAnmIdx(0); + boss->unk160 = 14; + boss->unk168 = 1.0f; + + MActor* oldAnmActor = boss->mMActor; + J3DAnmTransform* oldAnm; + if (!oldAnmActor->unkC) + oldAnm = nullptr; + else + oldAnm = oldAnmActor->unkC->unk24; + if (oldAnmActor->unkC) + oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + + boss->mMActor->setBckFromIndex(14); + MActor* blendActor = boss->mMActor; + f32 blendRatio = boss->unk168; + if (blendActor->unkC) + blendActor->unkC->setMotionBlendRatio(blendRatio); + + const char** basTable = boss->getBasNameTable(); + const char* basName; + if (!basTable) + basName = nullptr; + else + basName = basTable[14]; + boss->setAnmSound(basName); + } else if (boss->checkCurAnmEnd(0) && spine->getTime() > 600) { + spine->pushAfterCurrent(&TNerveBossTelesaPrepareSlot::theNerve()); + boss->unk368 = 0; + for (int i = 0; i < boss->unk274; ++i) { + TLiveActor* actor = boss->unk1AC[i]; + if (!(actor->mLiveFlag & LIVE_FLAG_DEAD) + && !actor->isActorType(0x2000000E) + && !actor->isActorType(0x20000002)) + actor->offHitFlag(HIT_FLAG_NO_COLLISION); + } + return TRUE; + } else if (spine->getTime() > 200) { + boss->unk364 -= 100.0f; + } + return FALSE; } DEFINE_NERVE(TNerveBossTelesaPrepareSlot, TLiveActor) { - return spine->getTime() > 30; + TBossTelesa* boss = getBoss(spine); + if (spine->getTime() == 0) { + boss->unk164 = boss->mMActor->getCurAnmIdx(0); + boss->unk160 = 15; + boss->unk168 = 1.0f; + + J3DAnmTransform* oldAnm = nullptr; + if (boss->mMActor->unkC) + oldAnm = boss->mMActor->unkC->unk24; + if (boss->mMActor->unkC) + boss->mMActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + + boss->mMActor->setBckFromIndex(15); + if (boss->mMActor->unkC) + boss->mMActor->unkC->setMotionBlendRatio(boss->unk168); + + const char** basTable = boss->getBasNameTable(); + boss->setAnmSound(basTable ? basTable[15] : nullptr); + boss->mMActor->setBtpFromIndex(2); + } + + if (boss->unk350) { + boss->unk36C++; + if (boss->checkCurAnmEnd(0)) { + if (boss->mMActor->checkCurBckFromIndex(1)) { + boss->unk164 = boss->mMActor->getCurAnmIdx(0); + boss->unk160 = 12; + boss->unk168 = 1.0f; + + J3DAnmTransform* oldAnm = nullptr; + if (boss->mMActor->unkC) + oldAnm = boss->mMActor->unkC->unk24; + if (boss->mMActor->unkC) + boss->mMActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + + boss->mMActor->setBckFromIndex(12); + if (boss->mMActor->unkC) + boss->mMActor->unkC->setMotionBlendRatio(boss->unk168); + + const char** basTable = boss->getBasNameTable(); + boss->setAnmSound(basTable ? basTable[12] : nullptr); + boss->mMActor->setBtpFromIndex(1); + } else if (boss->mMActor->checkCurBckFromIndex(12)) { + TBossTelesaSaveLoadParams* params + = (TBossTelesaSaveLoadParams*)boss->unk15C; + if (boss->unk36C > params->mSLSpicyTime.get()) { + boss->unk164 = boss->mMActor->getCurAnmIdx(0); + boss->unk160 = 13; + boss->unk168 = 1.0f; + + J3DAnmTransform* oldAnm = nullptr; + if (boss->mMActor->unkC) + oldAnm = boss->mMActor->unkC->unk24; + if (boss->mMActor->unkC) + boss->mMActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + + boss->mMActor->setBckFromIndex(13); + if (boss->mMActor->unkC) + boss->mMActor->unkC->setMotionBlendRatio(boss->unk168); + + const char** basTable = boss->getBasNameTable(); + boss->setAnmSound(basTable ? basTable[13] : nullptr); + } + } else { + boss->unk36C = 0; + boss->unk350 = 0; + + u8 maxHp = boss->getSaveParam() + ? boss->getSaveParam()->mSLHitPointMax.get() + : 1; + u8 alpha = TBossTelesa::mNormalAlpha + + (maxHp - boss->mHitPoints) * 30; + if (alpha > 0xFE) + alpha = 0xFE; + + boss->unk34C.a = alpha; + + boss->unk164 = boss->mMActor->getCurAnmIdx(0); + boss->unk160 = 15; + boss->unk168 = 1.0f; + + J3DAnmTransform* oldAnm = nullptr; + if (boss->mMActor->unkC) + oldAnm = boss->mMActor->unkC->unk24; + if (boss->mMActor->unkC) + boss->mMActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + + boss->mMActor->setBckFromIndex(15); + if (boss->mMActor->unkC) + boss->mMActor->unkC->setMotionBlendRatio(boss->unk168); + + const char** basTable = boss->getBasNameTable(); + boss->setAnmSound(basTable ? basTable[15] : nullptr); + boss->mMActor->setBtpFromIndex(2); + } + } + } + + boss->unk368++; + + TBossTelesaSaveLoadParams* params + = (TBossTelesaSaveLoadParams*)boss->unk15C; + int waitTime = params->mSLStopSlotTime0.get(); + if (boss->mHitPoints == 2) + waitTime = params->mSLStopSlotTime1.get(); + if (boss->mHitPoints == 1) + waitTime = params->mSLStopSlotTime2.get(); + + if (boss->unk184->getSlotResult() == 0) + waitTime = waitTime * 0.5f; + + if (boss->unk368 > waitTime - 120) + boss->flashItem(waitTime - boss->unk368); + + if (boss->mMActor->checkCurBckFromIndex(15)) { + BOOL done; + if (boss->unk1A8 == -1) { + done = TRUE; + } else { + done = TRUE; + for (int i = 0; i < boss->unk274; ++i) { + if (!(boss->unk1AC[i]->mLiveFlag & LIVE_FLAG_DEAD)) { + done = FALSE; + break; + } + } + } + + if (done || boss->unk368 > waitTime) { + boss->unk368 = 0; + boss->forceAllItemKill(); + + if (boss->unk350) { + if (gpMSound->gateCheck(0x2968)) { + MSoundSESystem::MSoundSE::startSoundActor( + 0x2968, &boss->mPosition, 0, nullptr, 0, 4); + } + } else { + if (gpMSound->gateCheck(0x28D5)) { + MSoundSESystem::MSoundSE::startSoundActor( + 0x28D5, &boss->mPosition, 0, nullptr, 0, 4); + } + } + + spine->setNext(&TNerveBossTelesaHide::theNerve()); + spine->pushAfterCurrent(&TNerveBossTelesaHide::theNerve()); + return TRUE; + } + } + + return FALSE; } DEFINE_NERVE(TNerveBossTelesaFreeze, TLiveActor) { - return spine->getTime() > 0 && spine->getBody()->checkCurAnmEnd(0); + TBossTelesa* boss = getBoss(spine); + if (boss->mMActor->checkCurBckFromIndex(16)) { + if (boss->checkCurAnmEnd(0)) { + boss->unk350 = 0; + + u8 maxHp = boss->getSaveParam() + ? boss->getSaveParam()->mSLHitPointMax.get() + : 1; + u8 alpha + = TBossTelesa::mNormalAlpha + (maxHp - boss->mHitPoints) * 30; + alpha = MsClamp(alpha, 0, 0xFE); + + boss->unk34C.a = alpha; + return TRUE; + } + } else { + boss->unk164 = boss->mMActor->getCurAnmIdx(0); + boss->unk160 = 16; + boss->unk168 = 1.0f; + + MActor* oldAnmActor = boss->mMActor; + J3DAnmTransform* oldAnm; + if (!oldAnmActor->unkC) + oldAnm = nullptr; + else + oldAnm = oldAnmActor->unkC->unk24; + if (oldAnmActor->unkC) + oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + + boss->mMActor->setBckFromIndex(16); + MActor* blendActor = boss->mMActor; + f32 blendRatio = boss->unk168; + if (blendActor->unkC) + blendActor->unkC->setMotionBlendRatio(blendRatio); + + const char** basTable = boss->getBasNameTable(); + const char* basName; + if (!basTable) + basName = nullptr; + else + basName = basTable[16]; + boss->setAnmSound(basName); + + if (gpMSound->gateCheck(0x28E7)) { + MSoundSESystem::MSoundSE::startSoundActor(0x28E7, &boss->mPosition, + 0, nullptr, 0, 4); + } + } + + return FALSE; } DEFINE_NERVE(TNerveBossTelesaFallDemo, TLiveActor) { - TBossTelesa* boss = static_cast(spine->getBody()); - if (spine->getTime() == 0) - boss->rouletteStart(); - return boss->rouletteFall() && boss->slotFall(); + TBossTelesa* boss = getBoss(spine); + if (spine->getTime() == 0) { + boss->onLiveFlag(LIVE_FLAG_HIDDEN); + if (SMS_SendMessageToMario(boss, HIT_MESSAGE_TAKE)) + boss->mHeldObject = (TTakeActor*)SMS_GetMarioHitActor(); + boss->mMActor->setFrameRate(0.0f, 0); + boss->unk184->mScaling.set(0.0f, 0.0f, 0.0f); + } + + if (boss->rouletteFall()) { + JGeometry::TVec3 diff = boss->mPosition; + diff.sub(*gpMarioPos); + + if (boss->slotFall()) { + boss->offHitFlag(HIT_FLAG_NO_COLLISION); + boss->unk16C->offHitFlag(HIT_FLAG_NO_COLLISION); + boss->unk170->offHitFlag(HIT_FLAG_NO_COLLISION); + spine->reset(); + spine->setNext(&TNerveBossTelesaHideWait::theNerve()); + spine->pushAfterCurrent(&TNerveBossTelesaHideWait::theNerve()); + return TRUE; + } + } + + return FALSE; } From 9fc1aa3992b54d6ae68f35546e44663e2582c24e Mon Sep 17 00:00:00 2001 From: KakarotCake <61133727+KakarottoCake@users.noreply.github.com> Date: Mon, 3 Aug 2026 03:30:56 -0400 Subject: [PATCH 04/18] Enemy/bosstelesa: improve loadAfter matching --- src/Enemy/bosstelesa.cpp | 49 +++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/src/Enemy/bosstelesa.cpp b/src/Enemy/bosstelesa.cpp index b52c3e57d..683f66710 100644 --- a/src/Enemy/bosstelesa.cpp +++ b/src/Enemy/bosstelesa.cpp @@ -113,7 +113,10 @@ void TBubbleManager::load(JSUMemoryInputStream& stream) TSmallEnemyManager::load(stream); } -TSmallEnemy* TBubbleManager::createEnemyInstance() { return new TBubble; } +TSmallEnemy* TBubbleManager::createEnemyInstance() +{ + return new TBubble("バブル"); +} void TBubbleManager::createModelData() { @@ -1006,11 +1009,13 @@ void TBossTelesa::loadAfter() int found = 0; for (int i = 0; i < gpMapObjManager->getObjNum(); ++i) { TMapObjBase* actor = gpMapObjManager->getObj(i); - bool isRoulette = false; + u8 isRoulette; if (actor->mActorType == rouletteType) - isRoulette = true; + isRoulette = 1; + else + isRoulette = 0; if (isRoulette) { - ((TRoulette**)&unk178)[found] = (TRoulette*)actor; + (&unk178)[found] = (TRoulette*)actor; found++; } } @@ -1020,9 +1025,11 @@ void TBossTelesa::loadAfter() if ((u32)gpMapObjManager->getObjNumWithActorType(slotType) != 0) { for (int i = 0; i < gpMapObjManager->getObjNum(); ++i) { TMapObjBase* actor = gpMapObjManager->getObj(i); - bool isSlot = false; + u8 isSlot; if (actor->mActorType == slotType) - isSlot = true; + isSlot = 1; + else + isSlot = 0; if (isSlot) { unk184 = (TTelesaSlot*)actor; unk184->unk1A0 = this; @@ -1030,27 +1037,31 @@ void TBossTelesa::loadAfter() } } - JGeometry::TVec3 position(0.0f, 0.0f, 0.0f); - JGeometry::TVec3 rotation(0.0f, 0.0f, 0.0f); - JGeometry::TVec3 scale(1.0f, 1.0f, 1.0f); int fruitIndex = 0; for (int i = 0; i < 6; ++i) unk2A8[fruitIndex++] = TMapObjBaseManager::newAndRegisterObj( - "FruitCoconut", position, rotation, scale); + "FruitCoconut", JGeometry::TVec3(0.0f, 0.0f, 0.0f), + JGeometry::TVec3(0.0f, 0.0f, 0.0f), + JGeometry::TVec3(1.0f, 1.0f, 1.0f)); for (int i = 0; i < 6; ++i) unk2A8[fruitIndex++] = TMapObjBaseManager::newAndRegisterObj( - "FruitPapaya", position, rotation, scale); + "FruitPapaya", JGeometry::TVec3(0.0f, 0.0f, 0.0f), + JGeometry::TVec3(0.0f, 0.0f, 0.0f), + JGeometry::TVec3(1.0f, 1.0f, 1.0f)); for (int i = 0; i < 2; ++i) unk2A8[fruitIndex++] = TMapObjBaseManager::newAndRegisterObj( - "FruitPine", position, rotation, scale); + "FruitPine", JGeometry::TVec3(0.0f, 0.0f, 0.0f), + JGeometry::TVec3(0.0f, 0.0f, 0.0f), + JGeometry::TVec3(1.0f, 1.0f, 1.0f)); for (int i = 0; i < 6; ++i) unk2A8[fruitIndex++] = TMapObjBaseManager::newAndRegisterObj( - "FruitDurian", position, rotation, scale); + "FruitDurian", JGeometry::TVec3(0.0f, 0.0f, 0.0f), + JGeometry::TVec3(0.0f, 0.0f, 0.0f), + JGeometry::TVec3(1.0f, 1.0f, 1.0f)); for (int i = 0; i < 20; ++i) { - TMapObjBase* actor = (TMapObjBase*)unk2A8[i]; - actor->onMapObjFlag(0x04000000); - actor->makeObjDead(); + ((TMapObjBase*)unk2A8[i])->onMapObjFlag(0x04000000); + ((TMapObjBase*)unk2A8[i])->makeObjDead(); } unk2F8[0] = JDrama::TNameRefGen::search("唐辛子 0"); @@ -1087,8 +1098,10 @@ void TBossTelesa::loadAfter() unk354 = JDrama::TNameRefGen::search("テレサマネージャー"); for (int i = 0; i < 5; ++i) - TMapObjBaseManager::newAndRegisterObj("bottle_large", position, - rotation, scale); + TMapObjBaseManager::newAndRegisterObj( + "bottle_large", JGeometry::TVec3(0.0f, 0.0f, 0.0f), + JGeometry::TVec3(0.0f, 0.0f, 0.0f), + JGeometry::TVec3(1.0f, 1.0f, 1.0f)); SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_fhit.jpa", 0xD7); SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_fhit_pe.jpa", 0xD8); From 2c791f741452d33c30e440a9c6ff629071011336 Mon Sep 17 00:00:00 2001 From: KakarotCake <61133727+KakarottoCake@users.noreply.github.com> Date: Mon, 3 Aug 2026 03:47:29 -0400 Subject: [PATCH 05/18] Enemy/bosstelesa: match slot item ranges and audio init --- src/Enemy/bosstelesa.cpp | 47 +++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/src/Enemy/bosstelesa.cpp b/src/Enemy/bosstelesa.cpp index 683f66710..268bf12aa 100644 --- a/src/Enemy/bosstelesa.cpp +++ b/src/Enemy/bosstelesa.cpp @@ -29,8 +29,10 @@ #include #include #include -#include #include +#include +#include +#include #include #include #include @@ -1936,7 +1938,8 @@ void TBossTelesa::generateSlotItem() if (numFruit > 20) numFruit = 20; - s32 angleIndex = (s32)(numFruit * (rand() * 0.000030517578f)); + TMsRange angleIndexRange(0, numFruit); + s32 angleIndex = angleIndexRange.rand(); for (int i = 0; i < numFruit; ++i) { if (unk2A8[i]->mHolder) @@ -1968,18 +1971,12 @@ void TBossTelesa::generateSlotItem() PSMTXMultVec(rot, &dir, &dir); MsVECNormalize(&dir, &normalizedDir); - TMapObjBase* actor; - if (i == 0 || i == 4) - actor = (TMapObjBase*)unk2F8[i]; - else - actor = (TMapObjBase*)unk2A8[i]; - Vec velocity; TMsRange fruitSpeedRange(6.0f, 10.0f); if (i == 0 || i == 4) { - actor->makeObjAppeared(); - actor->offLiveFlag(LIVE_FLAG_HIDDEN); + ((TMapObjBase*)unk2F8[i])->makeObjAppeared(); + ((TMapObjBase*)unk2F8[i])->offLiveFlag(LIVE_FLAG_HIDDEN); velocity.x = normalizedDir.x * fruitSpeedRange.rand(); velocity.y = -2.0f; @@ -1991,22 +1988,23 @@ void TBossTelesa::generateSlotItem() = normalizedDir.z * fruitSpeedRange.rand() * 2.0f; } - actor->mVelocity = velocity; - actor->offLiveFlag(LIVE_FLAG_UNK10); - actor->mRotation.set(0.0f, 90.0f, 0.0f); + ((TMapObjBase*)unk2F8[i])->mVelocity = velocity; + ((TMapObjBase*)unk2F8[i])->offLiveFlag(LIVE_FLAG_UNK10); + ((TMapObjBase*)unk2F8[i])->mRotation.set(0.0f, 90.0f, 0.0f); + unk1AC[unk274] = unk2F8[i]; } else { - actor->makeObjAppeared(); - actor->offLiveFlag(LIVE_FLAG_HIDDEN); + ((TMapObjBase*)unk2A8[i])->makeObjAppeared(); + ((TMapObjBase*)unk2A8[i])->offLiveFlag(LIVE_FLAG_HIDDEN); velocity.x = normalizedDir.x * fruitSpeedRange.rand(); velocity.y = -2.0f; velocity.z = normalizedDir.z * fruitSpeedRange.rand(); - actor->mVelocity = velocity; - actor->offLiveFlag(LIVE_FLAG_UNK10); + ((TMapObjBase*)unk2A8[i])->mVelocity = velocity; + ((TMapObjBase*)unk2A8[i])->offLiveFlag(LIVE_FLAG_UNK10); + unk1AC[unk274] = unk2A8[i]; } - unk1AC[unk274] = actor; unk1AC[i]->onHitFlag(HIT_FLAG_NO_COLLISION); unk1AC[i]->mScaling.set(1.5f, 1.5f, 1.5f); unk1AC[unk274]->mPosition.x = rootMtx[0][3] + dir.x; @@ -2065,21 +2063,26 @@ void TBossTelesa::generateSlotItem() } else { s32 count = slotItemNum; s32 kind = 0; - if (unk1A8 == -1) { + switch (unk1A8) { + case -1: count *= 2; - kind = 0; - } else if (unk1A8 == 1) { + break; + case 1: if (mHitPoints > 2) kind = 1; else kind = 2; + break; + case 3: + break; } s32 maxKind = 7; if (mHitPoints == 1) maxKind = 8; - s32 randomKind = 1 + (s32)((maxKind - 1) * (rand() * 0.000030517578f)); + TMsRange randomKindRange(1, maxKind); + s32 randomKind = randomKindRange.rand(); for (int i = 0; i < count; ++i) { if (unk1A8 == 3) { From 9b0934133c0647aaedca27faa7aba271e3fffe59 Mon Sep 17 00:00:00 2001 From: KakarotCake <61133727+KakarottoCake@users.noreply.github.com> Date: Fri, 14 Aug 2026 00:12:23 -0400 Subject: [PATCH 06/18] Enemy/bosstelesa: improve matching of boss/bubble nerves and helpers --- include/Enemy/BossTelesa.hpp | 6 +- src/Enemy/bosstelesa.cpp | 450 ++++++++++++++++++++++++----------- 2 files changed, 310 insertions(+), 146 deletions(-) diff --git a/include/Enemy/BossTelesa.hpp b/include/Enemy/BossTelesa.hpp index d933ea4d9..88b58f2fb 100644 --- a/include/Enemy/BossTelesa.hpp +++ b/include/Enemy/BossTelesa.hpp @@ -63,7 +63,7 @@ class TTelesaSlot : public TSlotDrum { void randomReset(); void moveStart(); void forceStopSlot(int); - BOOL isRollDrum(); + bool isRollDrum(); int getSlotResult(); int getForcastResult(int); int getResultFromAng(f32); @@ -125,8 +125,8 @@ class TBossTelesa : public TSpineEnemy { void onAllCollision(); void flashItem(int); void openWaterPlace(); - BOOL slotFall(); - BOOL rouletteFall(); + bool slotFall(); + bool rouletteFall(); void tongueHitWater(); void damageRecover(); void setSpicy(TLiveActor*); diff --git a/src/Enemy/bosstelesa.cpp b/src/Enemy/bosstelesa.cpp index 268bf12aa..a63a89398 100644 --- a/src/Enemy/bosstelesa.cpp +++ b/src/Enemy/bosstelesa.cpp @@ -322,11 +322,11 @@ BOOL TNerveBubbleLive::execute(TSpineBase* spine) const if (spine->getTime() == 0) { bubble->offHitFlag(HIT_FLAG_NO_COLLISION); - if (bubble->unk1D0) { + if (!bubble->unk1D0) { + bubble->setBckAnm(8); + } else { bubble->setBckAnm(10); bubble->setGoalPathMario(); - } else { - bubble->setBckAnm(8); } J3DFrameCtrl* frameCtrl = bubble->mMActor->getFrameCtrl(0); @@ -351,8 +351,8 @@ BOOL TNerveBubbleLive::execute(TSpineBase* spine) const } if (spine->getTime() == 80) { - bubble->unk1D1 = 0; - bubble->mVelocity.set(0.0f, 0.0f, 0.0f); + bubble->unk1D1 = 0; + bubble->mVelocity = JGeometry::TVec3(0.0f, 0.0f, 0.0f); } } @@ -772,7 +772,7 @@ void TTelesaSlot::forceStopSlot(int idx) #pragma dont_inline off #pragma dont_inline on -BOOL TTelesaSlot::isRollDrum() +bool TTelesaSlot::isRollDrum() { if (unk198) return TRUE; @@ -1546,18 +1546,28 @@ void TBossTelesa::setSpicy(TLiveActor* actor) unk160 = 1; unk168 = 1.0f; - J3DAnmTransform* oldAnm = nullptr; - if (mMActor->unkC) - oldAnm = mMActor->unkC->unk24; - if (mMActor->unkC) - mMActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* oldAnmActor = mMActor; + J3DAnmTransform* oldAnm; + if (!oldAnmActor->unkC) + oldAnm = nullptr; + else + oldAnm = oldAnmActor->unkC->unk24; + if (oldAnmActor->unkC) + oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); mMActor->setBckFromIndex(1); - if (mMActor->unkC) - mMActor->unkC->setMotionBlendRatio(unk168); + MActor* blendActor = mMActor; + f32 blendRatio = unk168; + if (blendActor->unkC) + blendActor->unkC->setMotionBlendRatio(blendRatio); const char** basTable = getBasNameTable(); - setAnmSound(basTable ? basTable[1] : nullptr); + const char* basName; + if (!basTable) + basName = nullptr; + else + basName = basTable[1]; + setAnmSound(basName); if (unk35B) { unk35B = 0; @@ -1620,7 +1630,7 @@ void TBossTelesa::damageRecover() void TBossTelesa::tongueHitWater() { } -BOOL TBossTelesa::rouletteFall() +bool TBossTelesa::rouletteFall() { TRoulette* roulette0 = (TRoulette*)unk178; TRoulette* roulette1 = (TRoulette*)unk17C; @@ -1660,7 +1670,7 @@ BOOL TBossTelesa::rouletteFall() return FALSE; } -BOOL TBossTelesa::slotFall() +bool TBossTelesa::slotFall() { if (unk184->mPosition.y > unk178->mPosition.y - 800.0f) { unk184->mPosition.y -= 5.0f; @@ -1830,7 +1840,8 @@ void TBossTelesa::genAttacker() bubble->mPosition.y += 10.0f; bubble->onLiveFlag(LIVE_FLAG_AIRBORNE); - f32 itemRoll = rand() * 0.000030517578f; + TMsRange itemRange(0.0f, 1.0f); + f32 itemRoll = itemRange.rand(); if (itemRoll < mItemGenRate) { bubble->unk198 = nullptr; TMapObjBase* item = gpItemManager->makeObjAppear( @@ -1845,7 +1856,8 @@ void TBossTelesa::genAttacker() bubble->unk198 = item; } } else { - f32 enemyRoll = rand() * 0.000030517578f; + TMsRange enemyRange(0.0f, 1.0f); + f32 enemyRoll = enemyRange.rand(); if (enemyRoll < mEnemyGenRate) bubble->appendEnemy(); } @@ -2227,36 +2239,56 @@ DEFINE_NERVE(TNerveBossTelesaDie, TLiveActor) boss->unk160 = 2; boss->unk168 = 1.0f; - J3DAnmTransform* oldAnm = nullptr; - if (boss->mMActor->unkC) - oldAnm = boss->mMActor->unkC->unk24; - if (boss->mMActor->unkC) - boss->mMActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* oldAnmActor = boss->mMActor; + J3DAnmTransform* oldAnm; + if (!oldAnmActor->unkC) + oldAnm = nullptr; + else + oldAnm = oldAnmActor->unkC->unk24; + if (oldAnmActor->unkC) + oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); boss->mMActor->setBckFromIndex(2); - if (boss->mMActor->unkC) - boss->mMActor->unkC->setMotionBlendRatio(boss->unk168); + MActor* blendActor = boss->mMActor; + f32 blendRatio = boss->unk168; + if (blendActor->unkC) + blendActor->unkC->setMotionBlendRatio(blendRatio); const char** basTable = boss->getBasNameTable(); - boss->setAnmSound(basTable ? basTable[2] : nullptr); + const char* basName; + if (!basTable) + basName = nullptr; + else + basName = basTable[2]; + boss->setAnmSound(basName); gpCameraShake->startShake((EnumCamShakeMode)0x1F, 1.0f); } else { boss->unk164 = boss->mMActor->getCurAnmIdx(0); boss->unk160 = 5; boss->unk168 = 1.0f; - J3DAnmTransform* oldAnm = nullptr; - if (boss->mMActor->unkC) - oldAnm = boss->mMActor->unkC->unk24; - if (boss->mMActor->unkC) - boss->mMActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* oldAnmActor = boss->mMActor; + J3DAnmTransform* oldAnm; + if (!oldAnmActor->unkC) + oldAnm = nullptr; + else + oldAnm = oldAnmActor->unkC->unk24; + if (oldAnmActor->unkC) + oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); boss->mMActor->setBckFromIndex(5); - if (boss->mMActor->unkC) - boss->mMActor->unkC->setMotionBlendRatio(boss->unk168); + MActor* blendActor = boss->mMActor; + f32 blendRatio = boss->unk168; + if (blendActor->unkC) + blendActor->unkC->setMotionBlendRatio(blendRatio); const char** basTable = boss->getBasNameTable(); - boss->setAnmSound(basTable ? basTable[5] : nullptr); + const char* basName; + if (!basTable) + basName = nullptr; + else + basName = basTable[5]; + boss->setAnmSound(basName); boss->mMActor->setBrkFromIndex(0); gpCameraShake->startShake((EnumCamShakeMode)0x20, 1.0f); } @@ -2267,18 +2299,28 @@ DEFINE_NERVE(TNerveBossTelesaDie, TLiveActor) boss->unk160 = 3; boss->unk168 = 1.0f; - J3DAnmTransform* oldAnm = nullptr; - if (boss->mMActor->unkC) - oldAnm = boss->mMActor->unkC->unk24; - if (boss->mMActor->unkC) - boss->mMActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* oldAnmActor = boss->mMActor; + J3DAnmTransform* oldAnm; + if (!oldAnmActor->unkC) + oldAnm = nullptr; + else + oldAnm = oldAnmActor->unkC->unk24; + if (oldAnmActor->unkC) + oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); boss->mMActor->setBckFromIndex(3); - if (boss->mMActor->unkC) - boss->mMActor->unkC->setMotionBlendRatio(boss->unk168); + MActor* blendActor = boss->mMActor; + f32 blendRatio = boss->unk168; + if (blendActor->unkC) + blendActor->unkC->setMotionBlendRatio(blendRatio); const char** basTable = boss->getBasNameTable(); - boss->setAnmSound(basTable ? basTable[3] : nullptr); + const char* basName; + if (!basTable) + basName = nullptr; + else + basName = basTable[3]; + boss->setAnmSound(basName); boss->mMActor->setBrkFromIndex(1); boss->unk184->mScaling.set(0.0f, 0.0f, 0.0f); @@ -2314,9 +2356,9 @@ DEFINE_NERVE(TNerveBossTelesaDie, TLiveActor) boss->unk184->unk1E4[1] = 0.0f; boss->unk180->unk144 = 0.0f; boss->unk184->unk1E4[2] = 0.0f; - boss->unk178->setRollSp(boss->unk184->unk1E4[0]); - boss->unk17C->setRollSp(boss->unk184->unk1E4[1]); - boss->unk180->setRollSp(boss->unk184->unk1E4[2]); + for (int i = 0; i < 3; ++i) + ((TRoulette**)&boss->unk178)[i]->setRollSp( + boss->unk184->unk1E4[i]); } if (boss->unk388 > 240) { @@ -2348,35 +2390,55 @@ DEFINE_NERVE(TNerveBossTelesaDie, TLiveActor) boss->unk160 = 7; boss->unk168 = 1.0f; - J3DAnmTransform* oldAnm = nullptr; - if (boss->mMActor->unkC) - oldAnm = boss->mMActor->unkC->unk24; - if (boss->mMActor->unkC) - boss->mMActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* oldAnmActor = boss->mMActor; + J3DAnmTransform* oldAnm; + if (!oldAnmActor->unkC) + oldAnm = nullptr; + else + oldAnm = oldAnmActor->unkC->unk24; + if (oldAnmActor->unkC) + oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); boss->mMActor->setBckFromIndex(7); - if (boss->mMActor->unkC) - boss->mMActor->unkC->setMotionBlendRatio(boss->unk168); + MActor* blendActor = boss->mMActor; + f32 blendRatio = boss->unk168; + if (blendActor->unkC) + blendActor->unkC->setMotionBlendRatio(blendRatio); const char** basTable = boss->getBasNameTable(); - boss->setAnmSound(basTable ? basTable[7] : nullptr); + const char* basName; + if (!basTable) + basName = nullptr; + else + basName = basTable[7]; + boss->setAnmSound(basName); } else if (boss->mMActor->checkCurBckFromIndex(7)) { boss->unk164 = boss->mMActor->getCurAnmIdx(0); boss->unk160 = 6; boss->unk168 = 1.0f; - J3DAnmTransform* oldAnm = nullptr; - if (boss->mMActor->unkC) - oldAnm = boss->mMActor->unkC->unk24; - if (boss->mMActor->unkC) - boss->mMActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* oldAnmActor = boss->mMActor; + J3DAnmTransform* oldAnm; + if (!oldAnmActor->unkC) + oldAnm = nullptr; + else + oldAnm = oldAnmActor->unkC->unk24; + if (oldAnmActor->unkC) + oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); boss->mMActor->setBckFromIndex(6); - if (boss->mMActor->unkC) - boss->mMActor->unkC->setMotionBlendRatio(boss->unk168); + MActor* blendActor = boss->mMActor; + f32 blendRatio = boss->unk168; + if (blendActor->unkC) + blendActor->unkC->setMotionBlendRatio(blendRatio); const char** basTable = boss->getBasNameTable(); - boss->setAnmSound(basTable ? basTable[6] : nullptr); + const char* basName; + if (!basTable) + basName = nullptr; + else + basName = basTable[6]; + boss->setAnmSound(basName); } else { SMS_ResetDamageFogEffect(boss->mMActor->getModel()->getModelData()); @@ -2389,18 +2451,28 @@ DEFINE_NERVE(TNerveBossTelesaDie, TLiveActor) boss->unk160 = 15; boss->unk168 = 1.0f; - J3DAnmTransform* oldAnm = nullptr; - if (boss->mMActor->unkC) - oldAnm = boss->mMActor->unkC->unk24; - if (boss->mMActor->unkC) - boss->mMActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* oldAnmActor = boss->mMActor; + J3DAnmTransform* oldAnm; + if (!oldAnmActor->unkC) + oldAnm = nullptr; + else + oldAnm = oldAnmActor->unkC->unk24; + if (oldAnmActor->unkC) + oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); boss->mMActor->setBckFromIndex(15); - if (boss->mMActor->unkC) - boss->mMActor->unkC->setMotionBlendRatio(boss->unk168); + MActor* blendActor = boss->mMActor; + f32 blendRatio = boss->unk168; + if (blendActor->unkC) + blendActor->unkC->setMotionBlendRatio(blendRatio); const char** basTable = boss->getBasNameTable(); - boss->setAnmSound(basTable ? basTable[15] : nullptr); + const char* basName; + if (!basTable) + basName = nullptr; + else + basName = basTable[15]; + boss->setAnmSound(basName); boss->mMActor->setBtpFromIndex(2); spine->pushAfterCurrent( &TNerveBossTelesaPrepareSlot::theNerve()); @@ -2472,8 +2544,10 @@ DEFINE_NERVE(TNerveBossTelesaHide, TLiveActor) oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); boss->mMActor->setBckFromIndex(4); - if (boss->mMActor->unkC) - boss->mMActor->unkC->setMotionBlendRatio(boss->unk168); + MActor* blendActor = boss->mMActor; + f32 blendRatio = boss->unk168; + if (blendActor->unkC) + blendActor->unkC->setMotionBlendRatio(blendRatio); const char** basTable = boss->getBasNameTable(); const char* basName; @@ -2539,18 +2613,28 @@ DEFINE_NERVE(TNerveBossTelesaAppear, TLiveActor) boss->unk160 = 0; boss->unk168 = 1.0f; - J3DAnmTransform* oldAnm = nullptr; - if (boss->mMActor->unkC) - oldAnm = boss->mMActor->unkC->unk24; - if (boss->mMActor->unkC) - boss->mMActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* oldAnmActor = boss->mMActor; + J3DAnmTransform* oldAnm; + if (!oldAnmActor->unkC) + oldAnm = nullptr; + else + oldAnm = oldAnmActor->unkC->unk24; + if (oldAnmActor->unkC) + oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); boss->mMActor->setBckFromIndex(0); - if (boss->mMActor->unkC) - boss->mMActor->unkC->setMotionBlendRatio(boss->unk168); + MActor* blendActor = boss->mMActor; + f32 blendRatio = boss->unk168; + if (blendActor->unkC) + blendActor->unkC->setMotionBlendRatio(blendRatio); const char** basTable = boss->getBasNameTable(); - boss->setAnmSound(basTable ? basTable[0] : nullptr); + const char* basName; + if (!basTable) + basName = nullptr; + else + basName = basTable[0]; + boss->setAnmSound(basName); if (!boss->unk384) { boss->unk384 = 1; @@ -2569,18 +2653,28 @@ DEFINE_NERVE(TNerveBossTelesaAppear, TLiveActor) boss->unk160 = 15; boss->unk168 = 1.0f; - J3DAnmTransform* oldAnm = nullptr; - if (boss->mMActor->unkC) - oldAnm = boss->mMActor->unkC->unk24; - if (boss->mMActor->unkC) - boss->mMActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* oldAnmActor = boss->mMActor; + J3DAnmTransform* oldAnm; + if (!oldAnmActor->unkC) + oldAnm = nullptr; + else + oldAnm = oldAnmActor->unkC->unk24; + if (oldAnmActor->unkC) + oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); boss->mMActor->setBckFromIndex(15); - if (boss->mMActor->unkC) - boss->mMActor->unkC->setMotionBlendRatio(boss->unk168); + MActor* blendActor = boss->mMActor; + f32 blendRatio = boss->unk168; + if (blendActor->unkC) + blendActor->unkC->setMotionBlendRatio(blendRatio); const char** basTable = boss->getBasNameTable(); - boss->setAnmSound(basTable ? basTable[15] : nullptr); + const char* basName; + if (!basTable) + basName = nullptr; + else + basName = basTable[15]; + boss->setAnmSound(basName); boss->mMActor->setBtpFromIndex(2); } @@ -2604,18 +2698,28 @@ DEFINE_NERVE(TNerveBossTelesaAppear, TLiveActor) boss->unk160 = 14; boss->unk168 = 1.0f; - J3DAnmTransform* oldAnm = nullptr; - if (boss->mMActor->unkC) - oldAnm = boss->mMActor->unkC->unk24; - if (boss->mMActor->unkC) - boss->mMActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* oldAnmActor = boss->mMActor; + J3DAnmTransform* oldAnm; + if (!oldAnmActor->unkC) + oldAnm = nullptr; + else + oldAnm = oldAnmActor->unkC->unk24; + if (oldAnmActor->unkC) + oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); boss->mMActor->setBckFromIndex(14); - if (boss->mMActor->unkC) - boss->mMActor->unkC->setMotionBlendRatio(boss->unk168); + MActor* blendActor = boss->mMActor; + f32 blendRatio = boss->unk168; + if (blendActor->unkC) + blendActor->unkC->setMotionBlendRatio(blendRatio); const char** basTable = boss->getBasNameTable(); - boss->setAnmSound(basTable ? basTable[14] : nullptr); + const char* basName; + if (!basTable) + basName = nullptr; + else + basName = basTable[14]; + boss->setAnmSound(basName); } } @@ -2631,18 +2735,28 @@ DEFINE_NERVE(TNerveBossTelesaSlotStart, TLiveActor) boss->unk160 = 11; boss->unk168 = 1.0f; - J3DAnmTransform* oldAnm = nullptr; - if (boss->mMActor->unkC) - oldAnm = boss->mMActor->unkC->unk24; - if (boss->mMActor->unkC) - boss->mMActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* oldAnmActor = boss->mMActor; + J3DAnmTransform* oldAnm; + if (!oldAnmActor->unkC) + oldAnm = nullptr; + else + oldAnm = oldAnmActor->unkC->unk24; + if (oldAnmActor->unkC) + oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); boss->mMActor->setBckFromIndex(11); - if (boss->mMActor->unkC) - boss->mMActor->unkC->setMotionBlendRatio(boss->unk168); + MActor* blendActor = boss->mMActor; + f32 blendRatio = boss->unk168; + if (blendActor->unkC) + blendActor->unkC->setMotionBlendRatio(blendRatio); const char** basTable = boss->getBasNameTable(); - boss->setAnmSound(basTable ? basTable[11] : nullptr); + const char* basName; + if (!basTable) + basName = nullptr; + else + basName = basTable[11]; + boss->setAnmSound(basName); } if (boss->mMActor->checkCurBckFromIndex(11)) { @@ -2657,18 +2771,28 @@ DEFINE_NERVE(TNerveBossTelesaSlotStart, TLiveActor) boss->unk160 = 15; boss->unk168 = 1.0f; - J3DAnmTransform* oldAnm = nullptr; - if (boss->mMActor->unkC) - oldAnm = boss->mMActor->unkC->unk24; - if (boss->mMActor->unkC) - boss->mMActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* oldAnmActor = boss->mMActor; + J3DAnmTransform* oldAnm; + if (!oldAnmActor->unkC) + oldAnm = nullptr; + else + oldAnm = oldAnmActor->unkC->unk24; + if (oldAnmActor->unkC) + oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); boss->mMActor->setBckFromIndex(15); - if (boss->mMActor->unkC) - boss->mMActor->unkC->setMotionBlendRatio(boss->unk168); + MActor* blendActor = boss->mMActor; + f32 blendRatio = boss->unk168; + if (blendActor->unkC) + blendActor->unkC->setMotionBlendRatio(blendRatio); const char** basTable = boss->getBasNameTable(); - boss->setAnmSound(basTable ? basTable[15] : nullptr); + const char* basName; + if (!basTable) + basName = nullptr; + else + basName = basTable[15]; + boss->setAnmSound(basName); boss->mMActor->setBtpFromIndex(2); boss->unk184->forceStopSlot(1); } @@ -2741,18 +2865,28 @@ DEFINE_NERVE(TNerveBossTelesaPrepareSlot, TLiveActor) boss->unk160 = 15; boss->unk168 = 1.0f; - J3DAnmTransform* oldAnm = nullptr; - if (boss->mMActor->unkC) - oldAnm = boss->mMActor->unkC->unk24; - if (boss->mMActor->unkC) - boss->mMActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* oldAnmActor = boss->mMActor; + J3DAnmTransform* oldAnm; + if (!oldAnmActor->unkC) + oldAnm = nullptr; + else + oldAnm = oldAnmActor->unkC->unk24; + if (oldAnmActor->unkC) + oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); boss->mMActor->setBckFromIndex(15); - if (boss->mMActor->unkC) - boss->mMActor->unkC->setMotionBlendRatio(boss->unk168); + MActor* blendActor = boss->mMActor; + f32 blendRatio = boss->unk168; + if (blendActor->unkC) + blendActor->unkC->setMotionBlendRatio(blendRatio); const char** basTable = boss->getBasNameTable(); - boss->setAnmSound(basTable ? basTable[15] : nullptr); + const char* basName; + if (!basTable) + basName = nullptr; + else + basName = basTable[15]; + boss->setAnmSound(basName); boss->mMActor->setBtpFromIndex(2); } @@ -2764,18 +2898,28 @@ DEFINE_NERVE(TNerveBossTelesaPrepareSlot, TLiveActor) boss->unk160 = 12; boss->unk168 = 1.0f; - J3DAnmTransform* oldAnm = nullptr; - if (boss->mMActor->unkC) - oldAnm = boss->mMActor->unkC->unk24; - if (boss->mMActor->unkC) - boss->mMActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* oldAnmActor = boss->mMActor; + J3DAnmTransform* oldAnm; + if (!oldAnmActor->unkC) + oldAnm = nullptr; + else + oldAnm = oldAnmActor->unkC->unk24; + if (oldAnmActor->unkC) + oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); boss->mMActor->setBckFromIndex(12); - if (boss->mMActor->unkC) - boss->mMActor->unkC->setMotionBlendRatio(boss->unk168); + MActor* blendActor = boss->mMActor; + f32 blendRatio = boss->unk168; + if (blendActor->unkC) + blendActor->unkC->setMotionBlendRatio(blendRatio); const char** basTable = boss->getBasNameTable(); - boss->setAnmSound(basTable ? basTable[12] : nullptr); + const char* basName; + if (!basTable) + basName = nullptr; + else + basName = basTable[12]; + boss->setAnmSound(basName); boss->mMActor->setBtpFromIndex(1); } else if (boss->mMActor->checkCurBckFromIndex(12)) { TBossTelesaSaveLoadParams* params @@ -2785,18 +2929,28 @@ DEFINE_NERVE(TNerveBossTelesaPrepareSlot, TLiveActor) boss->unk160 = 13; boss->unk168 = 1.0f; - J3DAnmTransform* oldAnm = nullptr; - if (boss->mMActor->unkC) - oldAnm = boss->mMActor->unkC->unk24; - if (boss->mMActor->unkC) - boss->mMActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* oldAnmActor = boss->mMActor; + J3DAnmTransform* oldAnm; + if (!oldAnmActor->unkC) + oldAnm = nullptr; + else + oldAnm = oldAnmActor->unkC->unk24; + if (oldAnmActor->unkC) + oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); boss->mMActor->setBckFromIndex(13); - if (boss->mMActor->unkC) - boss->mMActor->unkC->setMotionBlendRatio(boss->unk168); + MActor* blendActor = boss->mMActor; + f32 blendRatio = boss->unk168; + if (blendActor->unkC) + blendActor->unkC->setMotionBlendRatio(blendRatio); const char** basTable = boss->getBasNameTable(); - boss->setAnmSound(basTable ? basTable[13] : nullptr); + const char* basName; + if (!basTable) + basName = nullptr; + else + basName = basTable[13]; + boss->setAnmSound(basName); } } else { boss->unk36C = 0; @@ -2816,18 +2970,28 @@ DEFINE_NERVE(TNerveBossTelesaPrepareSlot, TLiveActor) boss->unk160 = 15; boss->unk168 = 1.0f; - J3DAnmTransform* oldAnm = nullptr; - if (boss->mMActor->unkC) - oldAnm = boss->mMActor->unkC->unk24; - if (boss->mMActor->unkC) - boss->mMActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* oldAnmActor = boss->mMActor; + J3DAnmTransform* oldAnm; + if (!oldAnmActor->unkC) + oldAnm = nullptr; + else + oldAnm = oldAnmActor->unkC->unk24; + if (oldAnmActor->unkC) + oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); boss->mMActor->setBckFromIndex(15); - if (boss->mMActor->unkC) - boss->mMActor->unkC->setMotionBlendRatio(boss->unk168); + MActor* blendActor = boss->mMActor; + f32 blendRatio = boss->unk168; + if (blendActor->unkC) + blendActor->unkC->setMotionBlendRatio(blendRatio); const char** basTable = boss->getBasNameTable(); - boss->setAnmSound(basTable ? basTable[15] : nullptr); + const char* basName; + if (!basTable) + basName = nullptr; + else + basName = basTable[15]; + boss->setAnmSound(basName); boss->mMActor->setBtpFromIndex(2); } } From a515f94b4beda4ef076b291aad18486de6d01d5f Mon Sep 17 00:00:00 2001 From: KakarotCake <61133727+KakarottoCake@users.noreply.github.com> Date: Fri, 14 Aug 2026 21:29:27 -0400 Subject: [PATCH 07/18] Enemy/bosstelesa: address Mrkol cleanup feedback - route sounds through SMSGetMSound()->startSoundActor + SoundEffects enum - add boss telesa particle enum entries, use them in emit/load - use MsMtxSetXYZRPH f32 overload in TBubble::calcRootMatrix - drop fabricated isActorTypeOf, use direct actor-type comparisons - rename MActor::getAnmBck -> getCurBckAnmPtr (real map name) - unk198/unk1A8 -> bool[3] arrays (remove pointer fakematch) - rolling/allStopped -> bool, MsWrap-free 360 wraps restored - fabsf instead of __fabsf, CAM_SHAKE_MODE enum, SMSGetMarDirector --- include/Camera/CameraShake.hpp | 5 + include/Enemy/BossTelesa.hpp | 24 +- include/M3DUtil/MActor.hpp | 3 +- include/Strategic/HitActor.hpp | 4 - include/System/Particles.hpp | 192 ++++++++------- src/Enemy/bosstelesa.cpp | 416 ++++++++++++++++----------------- src/Enemy/gatekeeper.cpp | 4 +- src/Enemy/hinokuri2.cpp | 6 +- src/NPC/NpcInitPrg.cpp | 4 +- 9 files changed, 332 insertions(+), 326 deletions(-) diff --git a/include/Camera/CameraShake.hpp b/include/Camera/CameraShake.hpp index 6f5904895..77ca7829b 100644 --- a/include/Camera/CameraShake.hpp +++ b/include/Camera/CameraShake.hpp @@ -20,6 +20,11 @@ enum EnumCamShakeMode { CAM_SHAKE_MODE_UNK1C = 0x1C, CAM_SHAKE_MODE_UNK1D = 0x1D, CAM_SHAKE_MODE_UNK1E = 0x1E, + CAM_SHAKE_MODE_UNK1F = 0x1F, + CAM_SHAKE_MODE_UNK20 = 0x20, + CAM_SHAKE_MODE_UNK21 = 0x21, + CAM_SHAKE_MODE_UNK22 = 0x22, + CAM_SHAKE_MODE_UNK23 = 0x23, CAM_SHAKE_MODE_UNK24 = 0x24, }; diff --git a/include/Enemy/BossTelesa.hpp b/include/Enemy/BossTelesa.hpp index 88b58f2fb..46feb1d98 100644 --- a/include/Enemy/BossTelesa.hpp +++ b/include/Enemy/BossTelesa.hpp @@ -44,14 +44,14 @@ class TTelesaSlot : public TSlotDrum { , unk1A0(nullptr) , unk1A4(0) { - unk198 = 0; - unk199 = 0; - unk19A = 0; - unk19B = 0; - unk19C = 0; - unk1A8 = 0; - unk1A9 = 0; - unk1AA = 0; + unk198[0] = false; + unk198[1] = false; + unk198[2] = false; + unk19B = 0; + unk19C = 0; + unk1A8[0] = false; + unk1A8[1] = false; + unk1A8[2] = false; } virtual void calcRootMatrix(); @@ -72,17 +72,13 @@ class TTelesaSlot : public TSlotDrum { void calcObjCollision(); int getDrumResult(int); - /* 0x198 */ u8 unk198; - /* 0x199 */ u8 unk199; - /* 0x19A */ u8 unk19A; + /* 0x198 */ bool unk198[3]; /* 0x19B */ u8 unk19B; /* 0x19C */ u8 unk19C; /* 0x19D */ u8 unk19D[3]; /* 0x1A0 */ void* unk1A0; /* 0x1A4 */ s32 unk1A4; - /* 0x1A8 */ u8 unk1A8; - /* 0x1A9 */ u8 unk1A9; - /* 0x1AA */ u8 unk1AA; + /* 0x1A8 */ bool unk1A8[3]; /* 0x1AB */ u8 unk1AB[0x31]; /* 0x1DC */ TMapCollisionMove* unk1DC; /* 0x1E0 */ u8 unk1E0; diff --git a/include/M3DUtil/MActor.hpp b/include/M3DUtil/MActor.hpp index 268b3a4b7..8e3514d2a 100644 --- a/include/M3DUtil/MActor.hpp +++ b/include/M3DUtil/MActor.hpp @@ -92,8 +92,7 @@ class MActor { // fabricated MActorAnmBase* getUnk28(int i) { return unk28[i]; } - MActorAnmBck* getAnmBck() { return unkC; } - MActorAnmBck* getCurBckAnmPtr(); + MActorAnmBck* getCurBckAnmPtr() { return unkC; } J3DModel* getModel() const { return unk4; } void unmarkUnk40() { unk40 = false; } BOOL curAnmEndsNext() { return curAnmEndsNext(0, 0); } diff --git a/include/Strategic/HitActor.hpp b/include/Strategic/HitActor.hpp index f1b8627ca..03b2056aa 100644 --- a/include/Strategic/HitActor.hpp +++ b/include/Strategic/HitActor.hpp @@ -68,10 +68,6 @@ class THitActor : public JDrama::TActor { // fabricated u32 getActorType() const { return mActorType; } - u8 isActorTypeOf(u32 base) const - { - return (mActorType - base) == 1 ? 1 : 0; - } bool checkActorType(u32 flag) const { return mActorType & flag ? true : false; diff --git a/include/System/Particles.hpp b/include/System/Particles.hpp index 9629ff185..1682b4004 100644 --- a/include/System/Particles.hpp +++ b/include/System/Particles.hpp @@ -97,81 +97,92 @@ enum E_SMS_EFFECT_ONETIME_NORMAL /* 0 */ { PARTICLE_MS_M_SPHIPD_HIT_C = 0x45, PARTICLE_MS_M_SPHIPD_HIT_D = 0x46, - MAP_POLLUTION_MS_M_ASHIOS = 0x50, - MAP_MAP_GATE_MS_MARIOWP_SENKO = 0x51, - PARTICLE_MS_POI_SAND = 0x53, - MAPOBJ_MS_WATCOIN_HIT = 0x57, - MAPOBJ_MS_WATCOIN_KIRA = 0x58, - MAP_MAP_MS_OBJUP_SLOPE_A = 0x59, - MAPOBJ_MS_EX_HAHEN = 0x63, - MAP_POLLUTION_MS_NEWFIRE_A = 0x65, - MAP_MAP_MS_OBJUP_MANIYA_A = 0x66, - MAP_MAP_MS_OBJUP_TOUDAI_A = 0x67, - MAP_MAP_MS_OBJUP_HOTEL_A = 0x68, - MAP_MAP_MS_MARE_OBJUP_A = 0x69, - MAPOBJ_SANDSTEAM = 0x6A, - PARTICLE_MS_EX_CUBE_DISA = 0x6D, - MAP_MAP_MS_M_FILEBLOCK = 0x6E, - MAP_POLLUTION_MS_THUNDER_S = 0x6F, - PARTICLE_MS_MNT_KIRA = 0x70, - PARTICLE_MS_MARE_KIRA = 0x71, - PARTICLE_MS_MNT_YOGORE_B = 0x72, - PARTICLE_MS_MNT_YOGORE_F = 0x73, - PARTICLE_MS_MARE_YOGORE = 0x74, - PARTICLE_MS_KINO_YOGORE = 0x75, - COLUMSAND_JPA_MS_BOHA_CRASH_A = 0x7E, - PARTICLE_MS_DEADNAMEKLI_N = 0x83, - PARTICLE_MS_DEADNAMEKLI_O = 0x84, - COLUMWATER_JPA_MS_ENEHAMON_A = 0x89, - COLUMWATER_JPA_MS_ENEHAMON_B = 0x8A, - PARTICLE_MS_MOE_FIRE_OFF = 0x8B, - BGESO_JPA_MS_BOGE_ATTACK_A = 0x8C, - BGESO_JPA_MS_BOGE_ATTACK_B = 0x8D, - BGESO_JPA_MS_BOGE_ATTACK_C = 0x8E, - BGESO_JPA_MS_BOGE_ATTACK_D = 0x8F, - BGESO_JPA_MS_BOGE_CANON_A = 0x93, - BGESO_JPA_MS_BOGE_CANON_B = 0x94, - BGESO_JPA_MS_BOGE_HIT_A = 0x97, - BGESO_JPA_MS_BOGE_HIT_B = 0x98, - BGESO_JPA_MS_BOGE_HIT_C = 0x99, - BGESO_JPA_MS_BOGE_HITDOWN = 0x9A, - BGESO_JPA_MS_BOGE_JUMP = 0x9B, - BGESO_JPA_MS_BOGE_KIZETSU = 0x9C, - BGESO_JPA_MS_BOGE_KIZETSU_R = 0x9D, - BGESO_JPA_MS_BOGE_ODANHIT_A = 0x9E, - BGESO_JPA_MS_BOGE_ODANHIT_B = 0x9F, - BGESO_JPA_MS_BOGE_OSEN = 0xA0, - PARTICLE_MS_POPO_BOMB_B = 0xA2, - GATEKEEPER_JPA_MS_GKPA_DEAD = 0xA7, - GATEKEEPER_JPA_MS_GKPA_DEADSMOKE = 0xA8, - PARTICLE_MS_SMB_AP_ROCK = 0xB6, - PARTICLE_MS_SMB_AP_SMOKE = 0xB7, - PARTICLE_MS_GESO_OSENHIT_A = 0xBC, - PARTICLE_MS_GESO_OSENHIT_B = 0xBD, - PARTICLE_MS_POI_DEAD = 0xC0, - EXPLOSION_JPA_MS_BOMB_SMOKE = 0xC4, - EXPLOSION_JPA_MS_BOMB_BOMB = 0xC5, - EXPLOSION_JPA_MS_BOMB_HAHEN = 0xC6, - PARTICLE_MS_CHO_ASE = 0xC9, - PARTICLE_MS_TAMA_FLOWER = 0xCC, - PARTICLE_MS_TLS_CHANGE = 0xCD, - PARTICLE_MS_GENE_DEAD = 0xD0, - BOSSEEL_JPA_MS_MEO_AWA_TOOTH = 0xD3, - BOSSEEL_JPA_MS_MEO_AWA_MOUTH = 0xD4, - BOSSEELTEARS_MS_MEO_TEAR_BOMB = 0xD5, - BOSSEELTEARS_MS_MEO_TEAR_AWAGET = 0xD6, - PARTICLE_MS_ENM_WALLHIT = 0xE2, - PARTICLE_MS_ENM_WALLHIT_O = 0xE3, - PARTICLE_MS_ENM_DISAP_A = 0xE4, - PARTICLE_MS_ENM_DISAP_A_W = 0xE5, - PARTICLE_MS_ENM_DISAP_B = 0xE6, - PARTICLE_MS_ENM_WATHIT = 0xE7, - SCENE_KAGEMARIO_JPA_MS_KGM_CHANGE = 0xED, - SCENE_MANTA_JPA_MS_MAN_DEAD = 0xF8, - SCENE_MANTA_JPA_MS_MAN_DIV1 = 0xF9, - SCENE_MANTA_JPA_MS_MAN_DIV2 = 0xFA, - SCENE_MANTA_JPA_MS_MAN_DIV3 = 0xFB, - SCENE_MANTA_JPA_MS_MAN_DIV4 = 0xFC, + MAP_POLLUTION_MS_M_ASHIOS = 0x50, + MAP_MAP_GATE_MS_MARIOWP_SENKO = 0x51, + PARTICLE_MS_POI_SAND = 0x53, + MAPOBJ_MS_WATCOIN_HIT = 0x57, + MAPOBJ_MS_WATCOIN_KIRA = 0x58, + MAP_MAP_MS_OBJUP_SLOPE_A = 0x59, + MAPOBJ_MS_EX_HAHEN = 0x63, + MAP_POLLUTION_MS_NEWFIRE_A = 0x65, + MAP_MAP_MS_OBJUP_MANIYA_A = 0x66, + MAP_MAP_MS_OBJUP_TOUDAI_A = 0x67, + MAP_MAP_MS_OBJUP_HOTEL_A = 0x68, + MAP_MAP_MS_MARE_OBJUP_A = 0x69, + MAPOBJ_SANDSTEAM = 0x6A, + PARTICLE_MS_EX_CUBE_DISA = 0x6D, + MAP_MAP_MS_M_FILEBLOCK = 0x6E, + MAP_POLLUTION_MS_THUNDER_S = 0x6F, + PARTICLE_MS_MNT_KIRA = 0x70, + PARTICLE_MS_MARE_KIRA = 0x71, + PARTICLE_MS_MNT_YOGORE_B = 0x72, + PARTICLE_MS_MNT_YOGORE_F = 0x73, + PARTICLE_MS_MARE_YOGORE = 0x74, + PARTICLE_MS_KINO_YOGORE = 0x75, + COLUMSAND_JPA_MS_BOHA_CRASH_A = 0x7E, + PARTICLE_MS_DEADNAMEKLI_N = 0x83, + PARTICLE_MS_DEADNAMEKLI_O = 0x84, + COLUMWATER_JPA_MS_ENEHAMON_A = 0x89, + COLUMWATER_JPA_MS_ENEHAMON_B = 0x8A, + PARTICLE_MS_MOE_FIRE_OFF = 0x8B, + BGESO_JPA_MS_BOGE_ATTACK_A = 0x8C, + BGESO_JPA_MS_BOGE_ATTACK_B = 0x8D, + BGESO_JPA_MS_BOGE_ATTACK_C = 0x8E, + BGESO_JPA_MS_BOGE_ATTACK_D = 0x8F, + BGESO_JPA_MS_BOGE_CANON_A = 0x93, + BGESO_JPA_MS_BOGE_CANON_B = 0x94, + BGESO_JPA_MS_BOGE_HIT_A = 0x97, + BGESO_JPA_MS_BOGE_HIT_B = 0x98, + BGESO_JPA_MS_BOGE_HIT_C = 0x99, + BGESO_JPA_MS_BOGE_HITDOWN = 0x9A, + BGESO_JPA_MS_BOGE_JUMP = 0x9B, + BGESO_JPA_MS_BOGE_KIZETSU = 0x9C, + BGESO_JPA_MS_BOGE_KIZETSU_R = 0x9D, + BGESO_JPA_MS_BOGE_ODANHIT_A = 0x9E, + BGESO_JPA_MS_BOGE_ODANHIT_B = 0x9F, + BGESO_JPA_MS_BOGE_OSEN = 0xA0, + PARTICLE_MS_POPO_BOMB_B = 0xA2, + GATEKEEPER_JPA_MS_GKPA_DEAD = 0xA7, + GATEKEEPER_JPA_MS_GKPA_DEADSMOKE = 0xA8, + PARTICLE_MS_SMB_AP_ROCK = 0xB6, + PARTICLE_MS_SMB_AP_SMOKE = 0xB7, + PARTICLE_MS_GESO_OSENHIT_A = 0xBC, + PARTICLE_MS_GESO_OSENHIT_B = 0xBD, + PARTICLE_MS_POI_DEAD = 0xC0, + EXPLOSION_JPA_MS_BOMB_SMOKE = 0xC4, + EXPLOSION_JPA_MS_BOMB_BOMB = 0xC5, + EXPLOSION_JPA_MS_BOMB_HAHEN = 0xC6, + PARTICLE_MS_CHO_ASE = 0xC9, + PARTICLE_MS_TAMA_FLOWER = 0xCC, + PARTICLE_MS_TLS_CHANGE = 0xCD, + PARTICLE_MS_GENE_DEAD = 0xD0, + BOSSEEL_JPA_MS_MEO_AWA_TOOTH = 0xD3, + BOSSEEL_JPA_MS_MEO_AWA_MOUTH = 0xD4, + BOSSEELTEARS_MS_MEO_TEAR_BOMB = 0xD5, + BOSSEELTEARS_MS_MEO_TEAR_AWAGET = 0xD6, + SCENE_BTELESA_JPA_MS_BTLS_FHIT = 0xD7, + SCENE_BTELESA_JPA_MS_BTLS_FHIT_PE = 0xD8, + SCENE_BTELESA_JPA_MS_BTLS_FHIT_GR = 0xD9, + SCENE_BTELESA_JPA_MS_BTLS_FHIT_OR = 0xDA, + SCENE_BTELESA_JPA_MS_BTLS_DAMAGE = 0xDB, + SCENE_BTELESA_JPA_MS_BTLS_DOWN = 0xDC, + SCENE_BTELESA_JPA_MS_BTLS_DOWN_PE = 0xDD, + SCENE_BTELESA_JPA_MS_BTLS_DOWN_GR = 0xDE, + SCENE_BTELESA_JPA_MS_BTLS_DOWN_OR = 0xDF, + SCENE_BTELESA_JPA_MS_BTLS_SPICY_HIT = 0xE0, + SCENE_BTELESA_JPA_MS_BTLS_FUBUKI = 0xE1, + PARTICLE_MS_ENM_WALLHIT = 0xE2, + PARTICLE_MS_ENM_WALLHIT_O = 0xE3, + PARTICLE_MS_ENM_DISAP_A = 0xE4, + PARTICLE_MS_ENM_DISAP_A_W = 0xE5, + PARTICLE_MS_ENM_DISAP_B = 0xE6, + PARTICLE_MS_ENM_WATHIT = 0xE7, + SCENE_KAGEMARIO_JPA_MS_KGM_CHANGE = 0xED, + SCENE_MANTA_JPA_MS_MAN_DEAD = 0xF8, + SCENE_MANTA_JPA_MS_MAN_DIV1 = 0xF9, + SCENE_MANTA_JPA_MS_MAN_DIV2 = 0xFA, + SCENE_MANTA_JPA_MS_MAN_DIV3 = 0xFB, + SCENE_MANTA_JPA_MS_MAN_DIV4 = 0xFC, }; enum E_SMS_EFFECT_LOOP_NORMAL /* 1 */ { @@ -258,6 +269,16 @@ enum E_SMS_EFFECT_LOOP_NORMAL /* 1 */ { BOSSEEL_JPA_MS_MEO_TOOTH_KIRA = 0x19B, BOSSEEL_JPA_MS_MEO_TOOTH_ALWAYS = 0x19C, BOSSEELTEARS_MS_MEO_TEAR_AWA = 0x19D, + SCENE_BTELESA_JPA_MS_BTLS_YODARE1 = 0x19E, + SCENE_BTELESA_JPA_MS_BTLS_YODARE2 = 0x19F, + SCENE_BTELESA_JPA_MS_BTLS_YODARE3 = 0x1A0, + SCENE_BTELESA_JPA_MS_BTLS_ASE = 0x1A1, + SCENE_BTELESA_JPA_MS_BTLS_SPICY_A = 0x1A2, + SCENE_BTELESA_JPA_MS_BTLS_SPICY_B = 0x1A3, + SCENE_BTELESA_JPA_MS_BTLS_SPICY_D = 0x1A4, + SCENE_BTELESA_JPA_MS_BTLS_CHIKA_A = 0x1A5, + SCENE_BTELESA_JPA_MS_BTLS_CHIKA_B = 0x1A6, + SCENE_BTELESA_JPA_MS_BTLS_GLOW = 0x1A7, SCENE_KAGEMARIO_JPA_MS_KGM_MOVE_A = 0x1AA, SCENE_KAGEMARIO_JPA_MS_KGM_MOVE_B = 0x1AB, PARTICLE_MS_MAP_FIRE_A = 0x1C4, @@ -293,16 +314,17 @@ enum /* 2 */ }; enum E_SMS_EFFECT_LOOP_INDIRECT /* 3 */ { - PARTICLE_MS_M_HAMON_B = 0x1E8, - PARTICLE_MS_M_MZBHAMON_B = 0x1E9, - PARTICLE_MS_TEPPANFIRE_B = 0x1F1, - FIREWANWAN_JPA_MS_CAN_YUGAMI = 0x1F4, - PARTICLE_MS_MAP_FIRE_C = 0x1F5, - SCENE_MAPOBJ_MS_OBJ_HAMON_B = 0x1F6, - PARTICLE_MS_NPC_HAMON_B = 0x1F7, - PARTICLE_MS_GESOSURF_A = 0x1E7, - PARTICLE_MS_M_WATSLIDE_A = 0x1EA, - PARTICLE_MS_MOE_FIRE_C = 0x1ED, + PARTICLE_MS_M_HAMON_B = 0x1E8, + PARTICLE_MS_M_MZBHAMON_B = 0x1E9, + SCENE_BTELESA_JPA_MS_BTLS_SPICY_C = 0x1F0, + PARTICLE_MS_TEPPANFIRE_B = 0x1F1, + FIREWANWAN_JPA_MS_CAN_YUGAMI = 0x1F4, + PARTICLE_MS_MAP_FIRE_C = 0x1F5, + SCENE_MAPOBJ_MS_OBJ_HAMON_B = 0x1F6, + PARTICLE_MS_NPC_HAMON_B = 0x1F7, + PARTICLE_MS_GESOSURF_A = 0x1E7, + PARTICLE_MS_M_WATSLIDE_A = 0x1EA, + PARTICLE_MS_MOE_FIRE_C = 0x1ED, }; // NOTE: doing this makes inlining work out, specializations DON'T. diff --git a/src/Enemy/bosstelesa.cpp b/src/Enemy/bosstelesa.cpp index a63a89398..342bb11c1 100644 --- a/src/Enemy/bosstelesa.cpp +++ b/src/Enemy/bosstelesa.cpp @@ -250,10 +250,8 @@ void TBubble::calcRootMatrix() mPosition.y = mGroundHeight + unk1CC + 150.0f; MtxPtr mtx = mMActor->getModel()->getBaseTRMtx(); - MsMtxSetXYZRPH(mtx, mPosition.x, mPosition.y, mPosition.z, - (s16)(mRotation.x * 182.04445f), - (s16)(mRotation.y * 182.04445f), - (s16)(mRotation.z * 182.04445f)); + MsMtxSetXYZRPH(mtx, mPosition.x, mPosition.y, mPosition.z, mRotation.x, + mRotation.y, mRotation.z); mMActor->getModel()->setBaseScale(mScaling); } } @@ -484,8 +482,6 @@ BOOL TBossTelesaBody::receiveMessage(THitActor* sender, u32 message) void TBossTelesaBody::checkHit() { } -MActorAnmBck* MActor::getCurBckAnmPtr() { return unkC; } - void TBossTelesaTongue::checkHit() { } BOOL TBossTelesaTongue::receiveMessage(THitActor*, u32 message) @@ -546,8 +542,8 @@ void TTelesaSlot::initMapObj() TMsRange indexRange(0, 8); for (int i = 0; i < 3; ++i) { - unk13C[i] = (f32)(unk168 * indexRange.rand()); - *(&unk198 + i) = 0; + unk13C[i] = (f32)(unk168 * indexRange.rand()); + unk198[i] = false; } } @@ -557,29 +553,27 @@ void TTelesaSlot::randomReset() TMsRange indexRange(0, 8); for (int i = 0; i < 3; ++i) { - unk13C[i] = (f32)(unk168 * indexRange.rand()); - *(&unk198 + i) = 0; + unk13C[i] = (f32)(unk168 * indexRange.rand()); + unk198[i] = false; } } #pragma dont_inline off void TTelesaSlot::calcRootMatrix() { - u8 rolling = 0; + bool rolling = false; if (getDrumSpeeds()[0] != 0.0f) - rolling = 1; + rolling = true; if (getDrumSpeeds()[1] != 0.0f) - rolling = 1; + rolling = true; if (getDrumSpeeds()[2] != 0.0f) - rolling = 1; + rolling = true; if (rolling) { if (unk1E0) { - if (gpMSound->gateCheck(0x308D)) { - MSoundSESystem::MSoundSE::startSoundActor(0x308D, &mPosition, 0, - nullptr, 0, 4); - } + SMSGetMSound()->startSoundActor(MSD_SE_OBJ_SLOT_SPIN, &mPosition, 0, + nullptr, 0, 4); } unk1E0 = 1 - unk1E0; @@ -593,13 +587,10 @@ void TTelesaSlot::moveObject() TLiveActor::moveObject(); for (int i = 0; i < unk148; ++i) { - u8* isRolling = &unk198 + i; - u8* doStop = &unk1A8 + i; - - if (*doStop) { + if (unk1A8[i]) { if (getForcastResult(i) == unk1A4) { - *isRolling = 0; - *doStop = 0; + unk198[i] = false; + unk1A8[i] = false; } } @@ -610,7 +601,7 @@ void TTelesaSlot::moveObject() if (fabsf(speed) > unk160) { unk13C[i] += speed; - if (!*isRolling) { + if (!unk198[i]) { if (unk138[i] > 0.0f) unk138[i] -= unk15C; else @@ -629,7 +620,7 @@ void TTelesaSlot::moveObject() if (unk13C[i] <= 0.0f) unk13C[i] += 360.0f; - if (*isRolling) + if (unk198[i]) continue; if ((int)fabsf(unk13C[i]) % unk168 != 0) @@ -638,37 +629,32 @@ void TTelesaSlot::moveObject() unk13C[i] = unk168 * (int)(unk13C[i] / (f32)unk168); unk138[i] = 0.0f; - if (gpMSound->gateCheck(0x292C)) { - MSoundSESystem::MSoundSE::startSoundActor(0x292C, &mPosition, 0, - nullptr, 0, 4); - } + SMSGetMSound()->startSoundActor(MSD_SE_BS_TELESA_SLT_STOP, + &mPosition, 0, nullptr, 0, 4); for (int j = 0; j < unk148; ++j) { - u8* otherRolling = &unk198 + j; - if (*otherRolling) { - f32 min = 0.0f; - f32 max = 1.0f; + if (unk198[j]) { TBossTelesa* owner = getSlotOwner(this); TBossTelesaSaveLoadParams* params = (TBossTelesaSaveLoadParams*)owner->unk15C; f32 rate = params->mSLSlotHitCollectRate.get(); - if (min + (max - min) * (rand() * 0.000030517578f) - <= rate) { - *(&unk1A8 + j) = 1; + TMsRange collectRange(0.0f, 1.0f); + if (collectRange.rand() <= rate) { + unk1A8[j] = true; } else { - *otherRolling = 0; + unk198[j] = false; } } } - u8 allStopped = 1; + bool allStopped = true; if (unk138[0] != 0.0f) - allStopped = 0; + allStopped = false; if (unk138[1] != 0.0f) - allStopped = 0; + allStopped = false; if (unk138[2] != 0.0f) - allStopped = 0; + allStopped = false; if (allStopped) { TBossTelesa* owner = getSlotOwner(this); @@ -678,25 +664,23 @@ void TTelesaSlot::moveObject() owner->unk374.x = 0.0f; owner->unk374.y = 0.0f; owner->unk374.z = 0.0f; - gpMarioParticleManager->emit(0xE1, &owner->unk374, 0, - nullptr); + gpMarioParticleManager->emit( + SCENE_BTELESA_JPA_MS_BTLS_FUBUKI, &owner->unk374, 0, + nullptr); if (slot->getSlotResult() == 2) { - if (gpMSound->gateCheck(0x293F)) { - MSoundSESystem::MSoundSE::startSoundActor( - 0x293F, &owner->mPosition, 0, nullptr, 0, 4); - } + SMSGetMSound()->startSoundActor( + MSD_SE_BS_TELESA_FANFALE_1, &owner->mPosition, 0, + nullptr, 0, 4); } else { - if (gpMSound->gateCheck(0x2940)) { - MSoundSESystem::MSoundSE::startSoundActor( - 0x2940, &owner->mPosition, 0, nullptr, 0, 4); - } + SMSGetMSound()->startSoundActor( + MSD_SE_BS_TELESA_FANFALE_2, &owner->mPosition, 0, + nullptr, 0, 4); } } else { - if (gpMSound->gateCheck(0x294D)) { - MSoundSESystem::MSoundSE::startSoundActor( - 0x294D, &owner->mPosition, 0, nullptr, 0, 4); - } + SMSGetMSound()->startSoundActor(MSD_SE_BS_TELESA_FANFALE_3, + &owner->mPosition, 0, + nullptr, 0, 4); } } } @@ -710,8 +694,8 @@ void TTelesaSlot::moveStart() unk19B = 1; for (int i = 0; i < 3; ++i) { - *(&unk198 + i) = 1; - *(&unk1A8 + i) = 0; + unk198[i] = true; + unk1A8[i] = false; f32 speed = 1.0f; if (i == 0) @@ -729,9 +713,6 @@ u32 TTelesaSlot::touchWater(THitActor*) { return FALSE; } #pragma dont_inline on void TTelesaSlot::forceStopSlot(int idx) { - volatile f32 min = 0.0f; - volatile f32 max = 1.0f; - f32 range; f32 collectRate; if (!unk19C) @@ -744,17 +725,16 @@ void TTelesaSlot::forceStopSlot(int idx) if (SMS_GetMarioHP() == 1) collectRate = 0.9f; - range = max - min; - f32 randomValue = range * (rand() * 0.000030517578f); - randomValue = min + randomValue; + TMsRange collectRange(0.0f, 1.0f); + f32 randomValue = collectRange.rand(); if (randomValue <= collectRate) { unk1A4 = 2; if (SMS_GetMarioHP() <= 3) unk1A4 = 0; - *(&unk1A8 + idx) = 1; + unk1A8[idx] = true; } else { - unk1A4 = getForcastResult(idx); - *(&unk198 + idx) = 0; + unk1A4 = getForcastResult(idx); + unk198[idx] = false; } if (unk1A4 == getSlotOwner(this)->unk1A8) @@ -774,15 +754,15 @@ void TTelesaSlot::forceStopSlot(int idx) #pragma dont_inline on bool TTelesaSlot::isRollDrum() { - if (unk198) - return TRUE; - if (unk199) - return TRUE; - if (unk19A) - return TRUE; + if (unk198[0]) + return true; + if (unk198[1]) + return true; + if (unk198[2]) + return true; unk19B = 0; - return FALSE; + return false; } #pragma dont_inline off @@ -1105,28 +1085,50 @@ void TBossTelesa::loadAfter() JGeometry::TVec3(0.0f, 0.0f, 0.0f), JGeometry::TVec3(1.0f, 1.0f, 1.0f)); - SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_fhit.jpa", 0xD7); - SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_fhit_pe.jpa", 0xD8); - SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_fhit_gr.jpa", 0xD9); - SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_fhit_or.jpa", 0xDA); - SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_damage.jpa", 0xDB); - SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_down.jpa", 0xDC); - SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_down_pe.jpa", 0xDD); - SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_down_gr.jpa", 0xDE); - SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_down_or.jpa", 0xDF); - SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_spicy_hit.jpa", 0xE0); - SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_fubuki.jpa", 0xE1); - SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_yodare1.jpa", 0x19E); - SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_yodare2.jpa", 0x19F); - SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_yodare3.jpa", 0x1A0); - SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_ase.jpa", 0x1A1); - SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_spicy_a.jpa", 0x1A2); - SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_spicy_b.jpa", 0x1A3); - SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_spicy_d.jpa", 0x1A4); - SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_chika_a.jpa", 0x1A5); - SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_chika_b.jpa", 0x1A6); - SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_glow.jpa", 0x1A7); - SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_spicy_c.jpa", 0x1F0); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_fhit.jpa", + SCENE_BTELESA_JPA_MS_BTLS_FHIT); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_fhit_pe.jpa", + SCENE_BTELESA_JPA_MS_BTLS_FHIT_PE); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_fhit_gr.jpa", + SCENE_BTELESA_JPA_MS_BTLS_FHIT_GR); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_fhit_or.jpa", + SCENE_BTELESA_JPA_MS_BTLS_FHIT_OR); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_damage.jpa", + SCENE_BTELESA_JPA_MS_BTLS_DAMAGE); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_down.jpa", + SCENE_BTELESA_JPA_MS_BTLS_DOWN); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_down_pe.jpa", + SCENE_BTELESA_JPA_MS_BTLS_DOWN_PE); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_down_gr.jpa", + SCENE_BTELESA_JPA_MS_BTLS_DOWN_GR); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_down_or.jpa", + SCENE_BTELESA_JPA_MS_BTLS_DOWN_OR); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_spicy_hit.jpa", + SCENE_BTELESA_JPA_MS_BTLS_SPICY_HIT); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_fubuki.jpa", + SCENE_BTELESA_JPA_MS_BTLS_FUBUKI); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_yodare1.jpa", + SCENE_BTELESA_JPA_MS_BTLS_YODARE1); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_yodare2.jpa", + SCENE_BTELESA_JPA_MS_BTLS_YODARE2); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_yodare3.jpa", + SCENE_BTELESA_JPA_MS_BTLS_YODARE3); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_ase.jpa", + SCENE_BTELESA_JPA_MS_BTLS_ASE); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_spicy_a.jpa", + SCENE_BTELESA_JPA_MS_BTLS_SPICY_A); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_spicy_b.jpa", + SCENE_BTELESA_JPA_MS_BTLS_SPICY_B); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_spicy_d.jpa", + SCENE_BTELESA_JPA_MS_BTLS_SPICY_D); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_chika_a.jpa", + SCENE_BTELESA_JPA_MS_BTLS_CHIKA_A); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_chika_b.jpa", + SCENE_BTELESA_JPA_MS_BTLS_CHIKA_B); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_glow.jpa", + SCENE_BTELESA_JPA_MS_BTLS_GLOW); + SMS_LoadParticle("/scene/btelesa/jpa/ms_btls_spicy_c.jpa", + SCENE_BTELESA_JPA_MS_BTLS_SPICY_C); void* res = JKRFileLoader::getGlbResource("/scene/btelesa/srot_waku.bmd"); SDLModelData* data @@ -1159,10 +1161,9 @@ void TBossTelesa::reset() setHitParams(params->mSLAttackRadius.get(), params->mSLAttackHeight.get(), params->mSLDamageRadius.get(), params->mSLDamageHeight.get()); - TMarDirector* director = gpMarDirector; - director->fireStartDemoCamera("btelesa_roll_camera", nullptr, -1, 0.0f, - true, nullptr, 0, nullptr, - JDrama::TFlagT(0)); + SMSGetMarDirector()->fireStartDemoCamera("btelesa_roll_camera", nullptr, -1, + 0.0f, true, nullptr, 0, nullptr, + JDrama::TFlagT(0)); } void TBossTelesa::moveObject() @@ -1179,16 +1180,14 @@ void TBossTelesa::moveObject() if (cameraDist < mCameraMoveLimit) { unk360 += mCameraMoveSp * (gpMarioPos->y - gpCamera->unk148.y); gpCamera->unk290 = unk360; - } else if (__fabsf(unk360) > 1.0f) { + } else if (fabsf(unk360) > 1.0f) { unk360 *= mCameraMoveSp; gpCamera->unk290 = unk360; } if (*gpMarioFlag & 0x400) { - if (gpMSound->gateCheck(0x28D4)) { - MSoundSESystem::MSoundSE::startSoundActor(0x28D4, &mPosition, 0, - nullptr, 0, 4); - } + SMSGetMSound()->startSoundActor(MSD_SE_BS_TELESA_V_LAUGH1, &mPosition, + 0, nullptr, 0, 4); } if (mSpine->getCurrentNerve() == &TNerveBossTelesaFallDemo::theNerve()) { @@ -1236,22 +1235,16 @@ void TBossTelesa::moveObject() switch (movingRoulettes) { case 1: - if (gpMSound->gateCheck(0x30B7)) { - MSoundSESystem::MSoundSE::startSoundActor(0x30B7, &unk19C, 0, - nullptr, 0, 4); - } + SMSGetMSound()->startSoundActor(MSD_SE_BS_TELESA_RLT_MOVE1, &unk19C, 0, + nullptr, 0, 4); break; case 2: - if (gpMSound->gateCheck(0x30B6)) { - MSoundSESystem::MSoundSE::startSoundActor(0x30B6, &unk19C, 0, - nullptr, 0, 4); - } + SMSGetMSound()->startSoundActor(MSD_SE_BS_TELESA_RLT_MOVE2, &unk19C, 0, + nullptr, 0, 4); break; case 3: - if (gpMSound->gateCheck(0x30B5)) { - MSoundSESystem::MSoundSE::startSoundActor(0x30B5, &unk19C, 0, - nullptr, 0, 4); - } + SMSGetMSound()->startSoundActor(MSD_SE_BS_TELESA_RLT_MOVE3, &unk19C, 0, + nullptr, 0, 4); break; } @@ -1260,7 +1253,7 @@ void TBossTelesa::moveObject() control(); for (int i = 0; i < mColCount; ++i) { - if (mCollisions[i]->isActorTypeOf(ACTOR_TYPE_PLAYER)) + if (mCollisions[i]->mActorType == ACTOR_TYPE_PLAYER) SMS_SendMessageToMario(this, HIT_MESSAGE_ATTACK); } @@ -1291,7 +1284,7 @@ void TBossTelesa::moveObject() body->unk6C = 0; for (int i = 0; i < body->mColCount; ++i) { THitActor* actor = body->mCollisions[i]; - if (actor->isActorTypeOf(ACTOR_TYPE_PLAYER)) + if (actor->mActorType == ACTOR_TYPE_PLAYER) SMS_SendMessageToMario(body, HIT_MESSAGE_ATTACK); else body->unk68->checkHitObject(actor); @@ -1300,7 +1293,7 @@ void TBossTelesa::moveObject() TBossTelesaTongue* tongue = (TBossTelesaTongue*)unk170; for (int i = 0; i < tongue->mColCount; ++i) { THitActor* actor = tongue->mCollisions[i]; - if (actor->isActorTypeOf(ACTOR_TYPE_PLAYER)) { + if (actor->mActorType == ACTOR_TYPE_PLAYER) { SMS_SendMessageToMario(tongue, HIT_MESSAGE_ATTACK); } else if (actor->mActorType == 0x40000395) { tongue->unk68->setSpicy((TLiveActor*)actor); @@ -1383,46 +1376,56 @@ void TBossTelesa::calcRootMatrix() } unk374.set(0.0f, 0.0f, 0.0f); - gpMarioParticleManager->emit(0x1A5, &unk374, 1, this); - gpMarioParticleManager->emit(0x1A6, &unk374, 1, this); + gpMarioParticleManager->emit(SCENE_BTELESA_JPA_MS_BTLS_CHIKA_A, &unk374, 1, + this); + gpMarioParticleManager->emit(SCENE_BTELESA_JPA_MS_BTLS_CHIKA_B, &unk374, 1, + this); MtxPtr baseMtx = mMActor->getModel()->mNodeMatrices[1]; unk374.set(baseMtx[0][3], baseMtx[1][3], baseMtx[2][3]); - gpMarioParticleManager->emitAndBindToPosPtr(0x1A7, &unk374, 1, this); + gpMarioParticleManager->emitAndBindToPosPtr(SCENE_BTELESA_JPA_MS_BTLS_GLOW, + &unk374, 1, this); if (!mMActor->checkCurBckFromIndex(4) && !mMActor->checkCurBckFromIndex(6) && !mMActor->checkCurBckFromIndex(12) && !mMActor->checkCurBckFromIndex(13)) { gpMarioParticleManager->emitAndBindToMtxPtr( - 0x19E, mMActor->getModel()->mNodeMatrices[5], 1, this); + SCENE_BTELESA_JPA_MS_BTLS_YODARE1, + mMActor->getModel()->mNodeMatrices[5], 1, this); gpMarioParticleManager->emitAndBindToMtxPtr( - 0x19F, mMActor->getModel()->mNodeMatrices[5], 1, this); + SCENE_BTELESA_JPA_MS_BTLS_YODARE2, + mMActor->getModel()->mNodeMatrices[5], 1, this); gpMarioParticleManager->emitAndBindToMtxPtr( - 0x1A0, mMActor->getModel()->mNodeMatrices[10], 1, this); + SCENE_BTELESA_JPA_MS_BTLS_YODARE3, + mMActor->getModel()->mNodeMatrices[10], 1, this); } if (mMActor->checkCurBckFromIndex(1) && mMActor->getFrameCtrl(0)->getFrame() < 20.0f) { gpMarioParticleManager->emitAndBindToMtxPtr( - 0xE0, mMActor->getModel()->mNodeMatrices[5], 0, nullptr); + SCENE_BTELESA_JPA_MS_BTLS_SPICY_HIT, + mMActor->getModel()->mNodeMatrices[5], 0, nullptr); } if (mMActor->checkCurBckFromIndex(12)) { - if (gpMSound->gateCheck(0x20FE)) { - MSoundSESystem::MSoundSE::startSoundActor(0x20FE, &mPosition, 0, - nullptr, 0, 4); - } + SMSGetMSound()->startSoundActor(MSD_SE_BS_TELESA_FIRE, &mPosition, 0, + nullptr, 0, 4); gpMarioParticleManager->emitAndBindToMtxPtr( - 0x1A1, mMActor->getModel()->mNodeMatrices[1], 1, this); + SCENE_BTELESA_JPA_MS_BTLS_ASE, + mMActor->getModel()->mNodeMatrices[1], 1, this); gpMarioParticleManager->emitAndBindToMtxPtr( - 0x1A2, mMActor->getModel()->mNodeMatrices[9], 1, this); + SCENE_BTELESA_JPA_MS_BTLS_SPICY_A, + mMActor->getModel()->mNodeMatrices[9], 1, this); gpMarioParticleManager->emitAndBindToMtxPtr( - 0x1A3, mMActor->getModel()->mNodeMatrices[9], 1, this); + SCENE_BTELESA_JPA_MS_BTLS_SPICY_B, + mMActor->getModel()->mNodeMatrices[9], 1, this); gpMarioParticleManager->emitAndBindToMtxPtr( - 0x1A4, mMActor->getModel()->mNodeMatrices[9], 1, this); + SCENE_BTELESA_JPA_MS_BTLS_SPICY_D, + mMActor->getModel()->mNodeMatrices[9], 1, this); gpMarioParticleManager->emitAndBindToMtxPtr( - 0x1F0, mMActor->getModel()->mNodeMatrices[9], 3, this); + SCENE_BTELESA_JPA_MS_BTLS_SPICY_C, + mMActor->getModel()->mNodeMatrices[9], 3, this); } if (mMActor->checkCurBckFromIndex(14) @@ -1480,7 +1483,7 @@ void TBossTelesa::checkHitObject(THitActor* actor) unk348.r = 0xE6; unk348.g = 0x64; unk348.b = 0xB4; - unk380 = 0xD8; + unk380 = SCENE_BTELESA_JPA_MS_BTLS_FHIT_PE; kill(); break; case 0x40000391: @@ -1488,14 +1491,14 @@ void TBossTelesa::checkHitObject(THitActor* actor) unk348.r = 0xE6; unk348.g = 0xB4; unk348.b = 0; - unk380 = 0xDA; + unk380 = SCENE_BTELESA_JPA_MS_BTLS_FHIT_OR; kill(); break; case 0x40000393: unk348.r = 0x96; unk348.g = 0x32; unk348.b = 0xE6; - unk380 = 0xD9; + unk380 = SCENE_BTELESA_JPA_MS_BTLS_FHIT_GR; kill(); break; case 0x40000395: @@ -1517,17 +1520,17 @@ void TBossTelesa::checkHitObject(THitActor* actor) } unk374 = actor->mPosition; - gpMarioParticleManager->emit(0xD7, &unk374, 0, nullptr); + gpMarioParticleManager->emit(SCENE_BTELESA_JPA_MS_BTLS_FHIT, &unk374, 0, + nullptr); if (unk380 >= 0) gpMarioParticleManager->emit(unk380, &unk374, 0, nullptr); if (unk350) { - gpMarioParticleManager->emit(0xDB, &unk374, 0, nullptr); + gpMarioParticleManager->emit(SCENE_BTELESA_JPA_MS_BTLS_DAMAGE, &unk374, + 0, nullptr); } else { - if (gpMSound->gateCheck(0x2944)) { - MSoundSESystem::MSoundSE::startSoundActor(0x2944, &mPosition, 0, - nullptr, 0, 4); - } + SMSGetMSound()->startSoundActor(MSD_SE_BS_TELESA_FRUIT_HIT, &mPosition, + 0, nullptr, 0, 4); } ((TMapObjBase*)actor)->makeObjDead(); @@ -1588,7 +1591,8 @@ void TBossTelesa::damageRecover() SMS_SendMessageToMario(actor, HIT_MESSAGE_UNK8); ((TMapObjBase*)actor)->makeObjDead(); - gpMarioParticleManager->emit(0xCD, &actor->mPosition, 0, nullptr); + gpMarioParticleManager->emit(PARTICLE_MS_TLS_CHANGE, + &actor->mPosition, 0, nullptr); actor->mPosition.set(zero, zero, zero); } } @@ -1600,28 +1604,26 @@ void TBossTelesa::damageRecover() SMS_SendMessageToMario(actor, HIT_MESSAGE_UNK8); ((TMapObjBase*)actor)->makeObjDead(); - gpMarioParticleManager->emit(0xCD, &actor->mPosition, 0, nullptr); + gpMarioParticleManager->emit(PARTICLE_MS_TLS_CHANGE, + &actor->mPosition, 0, nullptr); actor->mPosition.set(zero, zero, zero); } actor = unk320[i]; if (!(actor->mLiveFlag & LIVE_FLAG_DEAD)) { ((TMapObjBase*)actor)->makeObjDead(); - gpMarioParticleManager->emit(0xCD, &actor->mPosition, 0, nullptr); + gpMarioParticleManager->emit(PARTICLE_MS_TLS_CHANGE, + &actor->mPosition, 0, nullptr); actor->mPosition.set(zero, zero, zero); } } if (unk350) { - if (gpMSound->gateCheck(0x2968)) { - MSoundSESystem::MSoundSE::startSoundActor(0x2968, &mPosition, 0, - nullptr, 0, 4); - } + SMSGetMSound()->startSoundActor(MSD_SE_BS_TELESA_ESCAPE, &mPosition, 0, + nullptr, 0, 4); } else { - if (gpMSound->gateCheck(0x28D5)) { - MSoundSESystem::MSoundSE::startSoundActor(0x28D5, &mPosition, 0, - nullptr, 0, 4); - } + SMSGetMSound()->startSoundActor(MSD_SE_BS_TELESA_DISAPPEAR, &mPosition, + 0, nullptr, 0, 4); } mSpine->pushAfterCurrent(&TNerveBossTelesaHide::theNerve()); @@ -1648,23 +1650,17 @@ bool TBossTelesa::rouletteFall() mHeldObject = (TTakeActor*)SMS_GetMarioHitActor(); } else { if (SMS_SendMessageToMario(this, HIT_MESSAGE_UNK8)) { - if (gpMSound->gateCheck(0x2926)) { - MSoundSESystem::MSoundSE::startSoundActor(0x2926, &mPosition, 0, - nullptr, 0, 4); - } + SMSGetMSound()->startSoundActor(MSD_SE_BS_TELESA_RLT_SET, + &mPosition, 0, nullptr, 0, 4); mHeldObject = nullptr; } } - if (gpMSound->gateCheck(0x28DC)) { - MSoundSESystem::MSoundSE::startSoundActor(0x28DC, &mPosition, 0, - nullptr, 0, 4); - } + SMSGetMSound()->startSoundActor(MSD_SE_BS_TELESA_V_LAUGH1B, &mPosition, 0, + nullptr, 0, 4); - if (gpMSound->gateCheck(0x2125)) { - MSoundSESystem::MSoundSE::startSoundActor(0x2125, &mPosition, 0, - nullptr, 0, 4); - } + SMSGetMSound()->startSoundActor(MSD_SE_BS_TELESA_RLT_DOWN, &mPosition, 0, + nullptr, 0, 4); gpMarioOriginal->mGamePad->onNeutralMarioKey(); return FALSE; @@ -1900,7 +1896,7 @@ void TBossTelesa::rouletteStart() ((TRoulette**)&unk178)[i]->setRollSp(unk184->unk1E4[i]); SMSRumbleMgr->start(0x14, 0xf, (f32*)nullptr); - gpCameraShake->startShake((EnumCamShakeMode)0x23, 1.0f); + gpCameraShake->startShake(CAM_SHAKE_MODE_UNK23, 1.0f); } void TBossTelesa::slotStart() { rouletteStart(); } @@ -2175,8 +2171,8 @@ void TBossTelesa::forceAllItemKill() if (!(unk1AC[i]->mLiveFlag & LIVE_FLAG_DEAD)) { unk1AC[i]->kill(); - gpMarioParticleManager->emit(0xCD, &unk1AC[i]->mPosition, 0, - nullptr); + gpMarioParticleManager->emit(PARTICLE_MS_TLS_CHANGE, + &unk1AC[i]->mPosition, 0, nullptr); } } } @@ -2203,15 +2199,11 @@ void TBossTelesa::forceHide() unk368 = 0; if (unk350) { - if (gpMSound->gateCheck(0x2968)) { - MSoundSESystem::MSoundSE::startSoundActor(0x2968, &mPosition, 0, - nullptr, 0, 4); - } + SMSGetMSound()->startSoundActor(MSD_SE_BS_TELESA_ESCAPE, &mPosition, 0, + nullptr, 0, 4); } else { - if (gpMSound->gateCheck(0x28D5)) { - MSoundSESystem::MSoundSE::startSoundActor(0x28D5, &mPosition, 0, - nullptr, 0, 4); - } + SMSGetMSound()->startSoundActor(MSD_SE_BS_TELESA_DISAPPEAR, &mPosition, + 0, nullptr, 0, 4); } mSpine->reset(); @@ -2261,7 +2253,7 @@ DEFINE_NERVE(TNerveBossTelesaDie, TLiveActor) else basName = basTable[2]; boss->setAnmSound(basName); - gpCameraShake->startShake((EnumCamShakeMode)0x1F, 1.0f); + gpCameraShake->startShake(CAM_SHAKE_MODE_UNK1F, 1.0f); } else { boss->unk164 = boss->mMActor->getCurAnmIdx(0); boss->unk160 = 5; @@ -2290,11 +2282,11 @@ DEFINE_NERVE(TNerveBossTelesaDie, TLiveActor) basName = basTable[5]; boss->setAnmSound(basName); boss->mMActor->setBrkFromIndex(0); - gpCameraShake->startShake((EnumCamShakeMode)0x20, 1.0f); + gpCameraShake->startShake(CAM_SHAKE_MODE_UNK20, 1.0f); } } else { MSBgm::stopBGM(0x8001000D, 10); - gpCameraShake->startShake((EnumCamShakeMode)0x21, 1.0f); + gpCameraShake->startShake(CAM_SHAKE_MODE_UNK21, 1.0f); boss->unk164 = boss->mMActor->getCurAnmIdx(0); boss->unk160 = 3; boss->unk168 = 1.0f; @@ -2324,10 +2316,8 @@ DEFINE_NERVE(TNerveBossTelesaDie, TLiveActor) boss->mMActor->setBrkFromIndex(1); boss->unk184->mScaling.set(0.0f, 0.0f, 0.0f); - if (gpMSound->gateCheck(0x28DB)) { - MSoundSESystem::MSoundSE::startSoundActor( - 0x28DB, &boss->mPosition, 0, nullptr, 0, 4); - } + SMSGetMSound()->startSoundActor(MSD_SE_BS_TELESA_DOWN, + &boss->mPosition, 0, nullptr, 0, 4); } } @@ -2337,16 +2327,20 @@ DEFINE_NERVE(TNerveBossTelesaDie, TLiveActor) MtxPtr mtx = boss->mMActor->getModel()->mNodeMatrices[1]; boss->unk374.set(mtx[0][3], mtx[1][3], mtx[2][3]); - gpMarioParticleManager->emit(0xDC, &boss->unk374, 0, nullptr); - if (boss->unk380 == 0xD8) { - gpMarioParticleManager->emit(0xDD, &boss->unk374, 0, - nullptr); - } else if (boss->unk380 == 0xD9) { - gpMarioParticleManager->emit(0xDE, &boss->unk374, 0, - nullptr); + gpMarioParticleManager->emit(SCENE_BTELESA_JPA_MS_BTLS_DOWN, + &boss->unk374, 0, nullptr); + if (boss->unk380 == SCENE_BTELESA_JPA_MS_BTLS_FHIT_PE) { + gpMarioParticleManager->emit( + SCENE_BTELESA_JPA_MS_BTLS_DOWN_PE, &boss->unk374, 0, + nullptr); + } else if (boss->unk380 == SCENE_BTELESA_JPA_MS_BTLS_FHIT_GR) { + gpMarioParticleManager->emit( + SCENE_BTELESA_JPA_MS_BTLS_DOWN_GR, &boss->unk374, 0, + nullptr); } else { - gpMarioParticleManager->emit(0xDF, &boss->unk374, 0, - nullptr); + gpMarioParticleManager->emit( + SCENE_BTELESA_JPA_MS_BTLS_DOWN_OR, &boss->unk374, 0, + nullptr); } boss->forceAllItemKill(); @@ -2680,11 +2674,9 @@ DEFINE_NERVE(TNerveBossTelesaAppear, TLiveActor) if (boss->mMActor->checkCurBckFromIndex(0) && boss->mMActor->getFrameCtrl(0)->checkPass(78.0f)) { - gpCameraShake->startShake((EnumCamShakeMode)0x22, 1.0f); - if (gpMSound->gateCheck(0x292A)) { - MSoundSESystem::MSoundSE::startSoundActor(0x292A, &boss->mPosition, - 0, nullptr, 0, 4); - } + gpCameraShake->startShake(CAM_SHAKE_MODE_UNK22, 1.0f); + SMSGetMSound()->startSoundActor(MSD_SE_BS_TELESA_SLT_LAND, + &boss->mPosition, 0, nullptr, 0, 4); } if (spine->getTime() > 800) { @@ -2846,8 +2838,8 @@ DEFINE_NERVE(TNerveBossTelesaSpitSlotItem, TLiveActor) for (int i = 0; i < boss->unk274; ++i) { TLiveActor* actor = boss->unk1AC[i]; if (!(actor->mLiveFlag & LIVE_FLAG_DEAD) - && !actor->isActorType(0x2000000E) - && !actor->isActorType(0x20000002)) + && actor->mActorType != 0x2000000E + && actor->mActorType != 0x20000002) actor->offHitFlag(HIT_FLAG_NO_COLLISION); } return TRUE; @@ -3032,15 +3024,13 @@ DEFINE_NERVE(TNerveBossTelesaPrepareSlot, TLiveActor) boss->forceAllItemKill(); if (boss->unk350) { - if (gpMSound->gateCheck(0x2968)) { - MSoundSESystem::MSoundSE::startSoundActor( - 0x2968, &boss->mPosition, 0, nullptr, 0, 4); - } + SMSGetMSound()->startSoundActor(MSD_SE_BS_TELESA_ESCAPE, + &boss->mPosition, 0, nullptr, 0, + 4); } else { - if (gpMSound->gateCheck(0x28D5)) { - MSoundSESystem::MSoundSE::startSoundActor( - 0x28D5, &boss->mPosition, 0, nullptr, 0, 4); - } + SMSGetMSound()->startSoundActor(MSD_SE_BS_TELESA_DISAPPEAR, + &boss->mPosition, 0, nullptr, 0, + 4); } spine->setNext(&TNerveBossTelesaHide::theNerve()); @@ -3097,10 +3087,8 @@ DEFINE_NERVE(TNerveBossTelesaFreeze, TLiveActor) basName = basTable[16]; boss->setAnmSound(basName); - if (gpMSound->gateCheck(0x28E7)) { - MSoundSESystem::MSoundSE::startSoundActor(0x28E7, &boss->mPosition, - 0, nullptr, 0, 4); - } + SMSGetMSound()->startSoundActor(MSD_SE_BS_TELESA_THANKYOU, + &boss->mPosition, 0, nullptr, 0, 4); } return FALSE; diff --git a/src/Enemy/gatekeeper.cpp b/src/Enemy/gatekeeper.cpp index 12859e5c4..cc8418184 100644 --- a/src/Enemy/gatekeeper.cpp +++ b/src/Enemy/gatekeeper.cpp @@ -426,11 +426,11 @@ void TBiancoGateKeeper::changeBck(int param_1) || (cur == 7 && param_1 == 7) || (cur == 7 && param_1 == 0x12) || (cur == 0xF && param_1 == 0x10) || (cur == 0x10 && param_1 == 0xC)) { unk178->setAnm(param_1); - mMActor->getAnmBck()->setFrameCtrl(param_1); + mMActor->getCurBckAnmPtr()->setFrameCtrl(param_1); unk158 = 0.0f; } else { unk178->joinAnm(param_1); - mMActor->getAnmBck()->setFrameCtrl(param_1); + mMActor->getCurBckAnmPtr()->setFrameCtrl(param_1); J3DFrameCtrl* fc = mMActor->getFrameCtrl(0); if (fc != NULL) { f32 v = 0.25f * (f32)fc->getEnd(); diff --git a/src/Enemy/hinokuri2.cpp b/src/Enemy/hinokuri2.cpp index 2ddb9bfd0..d2e38e2ca 100644 --- a/src/Enemy/hinokuri2.cpp +++ b/src/Enemy/hinokuri2.cpp @@ -558,8 +558,8 @@ void THinokuri2::init(TLiveManager* param_1) mHitPoints = calcHitPoints(); J3DMtxCalc* calc = unk1A0; - if (getMActor()->getAnmBck()) { - MActorAnmBck* bck = getMActor()->getAnmBck(); + if (getMActor()->getCurBckAnmPtr()) { + MActorAnmBck* bck = getMActor()->getCurBckAnmPtr(); bck->unk38 = calc; bck->unk2A = 3; } @@ -737,7 +737,7 @@ void THinokuri2::changeBck(int param_1) param_1)); } - getMActor()->getAnmBck()->setFrameCtrl(param_1); + getMActor()->getCurBckAnmPtr()->setFrameCtrl(param_1); } mCurrentBck = param_1; diff --git a/src/NPC/NpcInitPrg.cpp b/src/NPC/NpcInitPrg.cpp index 11b4fe091..89d5db306 100644 --- a/src/NPC/NpcInitPrg.cpp +++ b/src/NPC/NpcInitPrg.cpp @@ -181,8 +181,8 @@ void TBaseNPC::init(TLiveManager* param_1) onLiveFlag(LIVE_FLAG_UNK10); } - if (mMActor->getAnmBck()) - mMActor->getAnmBck()->initNormalMotionBlend(); + if (mMActor->getCurBckAnmPtr()) + mMActor->getCurBckAnmPtr()->initNormalMotionBlend(); if (isPollutionNpc()) initSinkNpc_(); From 6c5786fa0921344b29b61b3d06a5b3042ddb0c98 Mon Sep 17 00:00:00 2001 From: KakarotCake <61133727+KakarottoCake@users.noreply.github.com> Date: Thu, 20 Aug 2026 17:02:34 -0400 Subject: [PATCH 08/18] Enemy/bosstelesa: use MActor motion-blend accessors Replace 42 hand-expanded copies of the bck motion-blend boilerplate with the MActor wrappers that already exist for them, matching the idiom Mrkol used when cleaning up bosseel: actor->setBckOldMotionBlendAnmPtr(actor->getBckAnm()); actor->setBckFromIndex(n); actor->setMotionBlendRatioForBck(ratio); No raw ->unkC accesses are left in the TU. Net -183 lines, and the match improves 92.242% -> 92.414% (TNerveBossTelesaAppear 99.5 -> 99.9, TNerveBossTelesaHide 96.3 -> 99.0, setSpicy 95.7 -> 97.7, moveObject 78.2 -> 80.1). Co-Authored-By: Claude Opus 5 --- src/Enemy/bosstelesa.cpp | 305 ++++++++------------------------------- 1 file changed, 61 insertions(+), 244 deletions(-) diff --git a/src/Enemy/bosstelesa.cpp b/src/Enemy/bosstelesa.cpp index 342bb11c1..42411af61 100644 --- a/src/Enemy/bosstelesa.cpp +++ b/src/Enemy/bosstelesa.cpp @@ -901,8 +901,7 @@ void TBossTelesa::init(TLiveManager* manager) mMActor->setLightType(1); mMActor->unk40 = 1; - if (mMActor->unkC) - mMActor->unkC->initNormalMotionBlend(); + mMActor->initNormalMotionBlend(); J3DModel* model = mMActor->getModel(); if (!model->getSkinDeform()) @@ -1263,8 +1262,7 @@ void TBossTelesa::moveObject() mPosition.y = mGroundHeight + 300.0f; unk168 = MsClamp(unk168 - 0.05f, 0.0f, 1.0f); - if (mMActor->unkC) - mMActor->unkC->setMotionBlendRatio(unk168); + mMActor->setMotionBlendRatioForBck(unk168); if (mLiveFlag & LIVE_FLAG_CLIPPED_OUT) { unk16C->mPosition = mPosition; @@ -1549,20 +1547,10 @@ void TBossTelesa::setSpicy(TLiveActor* actor) unk160 = 1; unk168 = 1.0f; - MActor* oldAnmActor = mMActor; - J3DAnmTransform* oldAnm; - if (!oldAnmActor->unkC) - oldAnm = nullptr; - else - oldAnm = oldAnmActor->unkC->unk24; - if (oldAnmActor->unkC) - oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + mMActor->setBckOldMotionBlendAnmPtr(mMActor->getBckAnm()); mMActor->setBckFromIndex(1); - MActor* blendActor = mMActor; - f32 blendRatio = unk168; - if (blendActor->unkC) - blendActor->unkC->setMotionBlendRatio(blendRatio); + mMActor->setMotionBlendRatioForBck(unk168); const char** basTable = getBasNameTable(); const char* basName; @@ -2231,20 +2219,11 @@ DEFINE_NERVE(TNerveBossTelesaDie, TLiveActor) boss->unk160 = 2; boss->unk168 = 1.0f; - MActor* oldAnmActor = boss->mMActor; - J3DAnmTransform* oldAnm; - if (!oldAnmActor->unkC) - oldAnm = nullptr; - else - oldAnm = oldAnmActor->unkC->unk24; - if (oldAnmActor->unkC) - oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* anmActor = boss->mMActor; + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); boss->mMActor->setBckFromIndex(2); - MActor* blendActor = boss->mMActor; - f32 blendRatio = boss->unk168; - if (blendActor->unkC) - blendActor->unkC->setMotionBlendRatio(blendRatio); + boss->mMActor->setMotionBlendRatioForBck(boss->unk168); const char** basTable = boss->getBasNameTable(); const char* basName; @@ -2259,20 +2238,11 @@ DEFINE_NERVE(TNerveBossTelesaDie, TLiveActor) boss->unk160 = 5; boss->unk168 = 1.0f; - MActor* oldAnmActor = boss->mMActor; - J3DAnmTransform* oldAnm; - if (!oldAnmActor->unkC) - oldAnm = nullptr; - else - oldAnm = oldAnmActor->unkC->unk24; - if (oldAnmActor->unkC) - oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* anmActor = boss->mMActor; + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); boss->mMActor->setBckFromIndex(5); - MActor* blendActor = boss->mMActor; - f32 blendRatio = boss->unk168; - if (blendActor->unkC) - blendActor->unkC->setMotionBlendRatio(blendRatio); + boss->mMActor->setMotionBlendRatioForBck(boss->unk168); const char** basTable = boss->getBasNameTable(); const char* basName; @@ -2291,20 +2261,11 @@ DEFINE_NERVE(TNerveBossTelesaDie, TLiveActor) boss->unk160 = 3; boss->unk168 = 1.0f; - MActor* oldAnmActor = boss->mMActor; - J3DAnmTransform* oldAnm; - if (!oldAnmActor->unkC) - oldAnm = nullptr; - else - oldAnm = oldAnmActor->unkC->unk24; - if (oldAnmActor->unkC) - oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* anmActor = boss->mMActor; + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); boss->mMActor->setBckFromIndex(3); - MActor* blendActor = boss->mMActor; - f32 blendRatio = boss->unk168; - if (blendActor->unkC) - blendActor->unkC->setMotionBlendRatio(blendRatio); + boss->mMActor->setMotionBlendRatioForBck(boss->unk168); const char** basTable = boss->getBasNameTable(); const char* basName; @@ -2384,20 +2345,11 @@ DEFINE_NERVE(TNerveBossTelesaDie, TLiveActor) boss->unk160 = 7; boss->unk168 = 1.0f; - MActor* oldAnmActor = boss->mMActor; - J3DAnmTransform* oldAnm; - if (!oldAnmActor->unkC) - oldAnm = nullptr; - else - oldAnm = oldAnmActor->unkC->unk24; - if (oldAnmActor->unkC) - oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* anmActor = boss->mMActor; + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); boss->mMActor->setBckFromIndex(7); - MActor* blendActor = boss->mMActor; - f32 blendRatio = boss->unk168; - if (blendActor->unkC) - blendActor->unkC->setMotionBlendRatio(blendRatio); + boss->mMActor->setMotionBlendRatioForBck(boss->unk168); const char** basTable = boss->getBasNameTable(); const char* basName; @@ -2411,20 +2363,11 @@ DEFINE_NERVE(TNerveBossTelesaDie, TLiveActor) boss->unk160 = 6; boss->unk168 = 1.0f; - MActor* oldAnmActor = boss->mMActor; - J3DAnmTransform* oldAnm; - if (!oldAnmActor->unkC) - oldAnm = nullptr; - else - oldAnm = oldAnmActor->unkC->unk24; - if (oldAnmActor->unkC) - oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* anmActor = boss->mMActor; + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); boss->mMActor->setBckFromIndex(6); - MActor* blendActor = boss->mMActor; - f32 blendRatio = boss->unk168; - if (blendActor->unkC) - blendActor->unkC->setMotionBlendRatio(blendRatio); + boss->mMActor->setMotionBlendRatioForBck(boss->unk168); const char** basTable = boss->getBasNameTable(); const char* basName; @@ -2445,20 +2388,11 @@ DEFINE_NERVE(TNerveBossTelesaDie, TLiveActor) boss->unk160 = 15; boss->unk168 = 1.0f; - MActor* oldAnmActor = boss->mMActor; - J3DAnmTransform* oldAnm; - if (!oldAnmActor->unkC) - oldAnm = nullptr; - else - oldAnm = oldAnmActor->unkC->unk24; - if (oldAnmActor->unkC) - oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* anmActor = boss->mMActor; + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); boss->mMActor->setBckFromIndex(15); - MActor* blendActor = boss->mMActor; - f32 blendRatio = boss->unk168; - if (blendActor->unkC) - blendActor->unkC->setMotionBlendRatio(blendRatio); + boss->mMActor->setMotionBlendRatioForBck(boss->unk168); const char** basTable = boss->getBasNameTable(); const char* basName; @@ -2488,20 +2422,11 @@ DEFINE_NERVE(TNerveBossTelesaSpit, TLiveActor) boss->unk160 = 14; boss->unk168 = 1.0f; - MActor* oldAnmActor = boss->mMActor; - J3DAnmTransform* oldAnm; - if (!oldAnmActor->unkC) - oldAnm = nullptr; - else - oldAnm = oldAnmActor->unkC->unk24; - if (oldAnmActor->unkC) - oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* anmActor = boss->mMActor; + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); boss->mMActor->setBckFromIndex(14); - MActor* blendActor = boss->mMActor; - f32 blendRatio = boss->unk168; - if (blendActor->unkC) - blendActor->unkC->setMotionBlendRatio(blendRatio); + boss->mMActor->setMotionBlendRatioForBck(boss->unk168); const char** basTable = boss->getBasNameTable(); const char* basName; @@ -2528,20 +2453,11 @@ DEFINE_NERVE(TNerveBossTelesaHide, TLiveActor) boss->unk160 = 4; boss->unk168 = 1.0f; - MActor* oldAnmActor = boss->mMActor; - J3DAnmTransform* oldAnm; - if (!oldAnmActor->unkC) - oldAnm = nullptr; - else - oldAnm = oldAnmActor->unkC->unk24; - if (oldAnmActor->unkC) - oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* anmActor = boss->mMActor; + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); boss->mMActor->setBckFromIndex(4); - MActor* blendActor = boss->mMActor; - f32 blendRatio = boss->unk168; - if (blendActor->unkC) - blendActor->unkC->setMotionBlendRatio(blendRatio); + boss->mMActor->setMotionBlendRatioForBck(boss->unk168); const char** basTable = boss->getBasNameTable(); const char* basName; @@ -2607,20 +2523,11 @@ DEFINE_NERVE(TNerveBossTelesaAppear, TLiveActor) boss->unk160 = 0; boss->unk168 = 1.0f; - MActor* oldAnmActor = boss->mMActor; - J3DAnmTransform* oldAnm; - if (!oldAnmActor->unkC) - oldAnm = nullptr; - else - oldAnm = oldAnmActor->unkC->unk24; - if (oldAnmActor->unkC) - oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* anmActor = boss->mMActor; + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); boss->mMActor->setBckFromIndex(0); - MActor* blendActor = boss->mMActor; - f32 blendRatio = boss->unk168; - if (blendActor->unkC) - blendActor->unkC->setMotionBlendRatio(blendRatio); + boss->mMActor->setMotionBlendRatioForBck(boss->unk168); const char** basTable = boss->getBasNameTable(); const char* basName; @@ -2647,20 +2554,11 @@ DEFINE_NERVE(TNerveBossTelesaAppear, TLiveActor) boss->unk160 = 15; boss->unk168 = 1.0f; - MActor* oldAnmActor = boss->mMActor; - J3DAnmTransform* oldAnm; - if (!oldAnmActor->unkC) - oldAnm = nullptr; - else - oldAnm = oldAnmActor->unkC->unk24; - if (oldAnmActor->unkC) - oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* anmActor = boss->mMActor; + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); boss->mMActor->setBckFromIndex(15); - MActor* blendActor = boss->mMActor; - f32 blendRatio = boss->unk168; - if (blendActor->unkC) - blendActor->unkC->setMotionBlendRatio(blendRatio); + boss->mMActor->setMotionBlendRatioForBck(boss->unk168); const char** basTable = boss->getBasNameTable(); const char* basName; @@ -2690,20 +2588,11 @@ DEFINE_NERVE(TNerveBossTelesaAppear, TLiveActor) boss->unk160 = 14; boss->unk168 = 1.0f; - MActor* oldAnmActor = boss->mMActor; - J3DAnmTransform* oldAnm; - if (!oldAnmActor->unkC) - oldAnm = nullptr; - else - oldAnm = oldAnmActor->unkC->unk24; - if (oldAnmActor->unkC) - oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* anmActor = boss->mMActor; + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); boss->mMActor->setBckFromIndex(14); - MActor* blendActor = boss->mMActor; - f32 blendRatio = boss->unk168; - if (blendActor->unkC) - blendActor->unkC->setMotionBlendRatio(blendRatio); + boss->mMActor->setMotionBlendRatioForBck(boss->unk168); const char** basTable = boss->getBasNameTable(); const char* basName; @@ -2727,20 +2616,11 @@ DEFINE_NERVE(TNerveBossTelesaSlotStart, TLiveActor) boss->unk160 = 11; boss->unk168 = 1.0f; - MActor* oldAnmActor = boss->mMActor; - J3DAnmTransform* oldAnm; - if (!oldAnmActor->unkC) - oldAnm = nullptr; - else - oldAnm = oldAnmActor->unkC->unk24; - if (oldAnmActor->unkC) - oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* anmActor = boss->mMActor; + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); boss->mMActor->setBckFromIndex(11); - MActor* blendActor = boss->mMActor; - f32 blendRatio = boss->unk168; - if (blendActor->unkC) - blendActor->unkC->setMotionBlendRatio(blendRatio); + boss->mMActor->setMotionBlendRatioForBck(boss->unk168); const char** basTable = boss->getBasNameTable(); const char* basName; @@ -2763,20 +2643,11 @@ DEFINE_NERVE(TNerveBossTelesaSlotStart, TLiveActor) boss->unk160 = 15; boss->unk168 = 1.0f; - MActor* oldAnmActor = boss->mMActor; - J3DAnmTransform* oldAnm; - if (!oldAnmActor->unkC) - oldAnm = nullptr; - else - oldAnm = oldAnmActor->unkC->unk24; - if (oldAnmActor->unkC) - oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* anmActor = boss->mMActor; + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); boss->mMActor->setBckFromIndex(15); - MActor* blendActor = boss->mMActor; - f32 blendRatio = boss->unk168; - if (blendActor->unkC) - blendActor->unkC->setMotionBlendRatio(blendRatio); + boss->mMActor->setMotionBlendRatioForBck(boss->unk168); const char** basTable = boss->getBasNameTable(); const char* basName; @@ -2810,20 +2681,11 @@ DEFINE_NERVE(TNerveBossTelesaSpitSlotItem, TLiveActor) boss->unk160 = 14; boss->unk168 = 1.0f; - MActor* oldAnmActor = boss->mMActor; - J3DAnmTransform* oldAnm; - if (!oldAnmActor->unkC) - oldAnm = nullptr; - else - oldAnm = oldAnmActor->unkC->unk24; - if (oldAnmActor->unkC) - oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* anmActor = boss->mMActor; + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); boss->mMActor->setBckFromIndex(14); - MActor* blendActor = boss->mMActor; - f32 blendRatio = boss->unk168; - if (blendActor->unkC) - blendActor->unkC->setMotionBlendRatio(blendRatio); + boss->mMActor->setMotionBlendRatioForBck(boss->unk168); const char** basTable = boss->getBasNameTable(); const char* basName; @@ -2857,20 +2719,11 @@ DEFINE_NERVE(TNerveBossTelesaPrepareSlot, TLiveActor) boss->unk160 = 15; boss->unk168 = 1.0f; - MActor* oldAnmActor = boss->mMActor; - J3DAnmTransform* oldAnm; - if (!oldAnmActor->unkC) - oldAnm = nullptr; - else - oldAnm = oldAnmActor->unkC->unk24; - if (oldAnmActor->unkC) - oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* anmActor = boss->mMActor; + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); boss->mMActor->setBckFromIndex(15); - MActor* blendActor = boss->mMActor; - f32 blendRatio = boss->unk168; - if (blendActor->unkC) - blendActor->unkC->setMotionBlendRatio(blendRatio); + boss->mMActor->setMotionBlendRatioForBck(boss->unk168); const char** basTable = boss->getBasNameTable(); const char* basName; @@ -2890,20 +2743,11 @@ DEFINE_NERVE(TNerveBossTelesaPrepareSlot, TLiveActor) boss->unk160 = 12; boss->unk168 = 1.0f; - MActor* oldAnmActor = boss->mMActor; - J3DAnmTransform* oldAnm; - if (!oldAnmActor->unkC) - oldAnm = nullptr; - else - oldAnm = oldAnmActor->unkC->unk24; - if (oldAnmActor->unkC) - oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* anmActor = boss->mMActor; + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); boss->mMActor->setBckFromIndex(12); - MActor* blendActor = boss->mMActor; - f32 blendRatio = boss->unk168; - if (blendActor->unkC) - blendActor->unkC->setMotionBlendRatio(blendRatio); + boss->mMActor->setMotionBlendRatioForBck(boss->unk168); const char** basTable = boss->getBasNameTable(); const char* basName; @@ -2921,20 +2765,11 @@ DEFINE_NERVE(TNerveBossTelesaPrepareSlot, TLiveActor) boss->unk160 = 13; boss->unk168 = 1.0f; - MActor* oldAnmActor = boss->mMActor; - J3DAnmTransform* oldAnm; - if (!oldAnmActor->unkC) - oldAnm = nullptr; - else - oldAnm = oldAnmActor->unkC->unk24; - if (oldAnmActor->unkC) - oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* anmActor = boss->mMActor; + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); boss->mMActor->setBckFromIndex(13); - MActor* blendActor = boss->mMActor; - f32 blendRatio = boss->unk168; - if (blendActor->unkC) - blendActor->unkC->setMotionBlendRatio(blendRatio); + boss->mMActor->setMotionBlendRatioForBck(boss->unk168); const char** basTable = boss->getBasNameTable(); const char* basName; @@ -2962,20 +2797,11 @@ DEFINE_NERVE(TNerveBossTelesaPrepareSlot, TLiveActor) boss->unk160 = 15; boss->unk168 = 1.0f; - MActor* oldAnmActor = boss->mMActor; - J3DAnmTransform* oldAnm; - if (!oldAnmActor->unkC) - oldAnm = nullptr; - else - oldAnm = oldAnmActor->unkC->unk24; - if (oldAnmActor->unkC) - oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* anmActor = boss->mMActor; + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); boss->mMActor->setBckFromIndex(15); - MActor* blendActor = boss->mMActor; - f32 blendRatio = boss->unk168; - if (blendActor->unkC) - blendActor->unkC->setMotionBlendRatio(blendRatio); + boss->mMActor->setMotionBlendRatioForBck(boss->unk168); const char** basTable = boss->getBasNameTable(); const char* basName; @@ -3064,20 +2890,11 @@ DEFINE_NERVE(TNerveBossTelesaFreeze, TLiveActor) boss->unk160 = 16; boss->unk168 = 1.0f; - MActor* oldAnmActor = boss->mMActor; - J3DAnmTransform* oldAnm; - if (!oldAnmActor->unkC) - oldAnm = nullptr; - else - oldAnm = oldAnmActor->unkC->unk24; - if (oldAnmActor->unkC) - oldAnmActor->unkC->setOldMotionBlendAnmPtr(oldAnm); + MActor* anmActor = boss->mMActor; + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); boss->mMActor->setBckFromIndex(16); - MActor* blendActor = boss->mMActor; - f32 blendRatio = boss->unk168; - if (blendActor->unkC) - blendActor->unkC->setMotionBlendRatio(blendRatio); + boss->mMActor->setMotionBlendRatioForBck(boss->unk168); const char** basTable = boss->getBasNameTable(); const char* basName; From c6078852c406c1418252ebbc299141474eda2618 Mon Sep 17 00:00:00 2001 From: KakarotCake <61133727+KakarottoCake@users.noreply.github.com> Date: Thu, 20 Aug 2026 17:07:29 -0400 Subject: [PATCH 09/18] Enemy/bosstelesa: reconstruct the inlined checkHit bodies TBossTelesaBody::checkHit and TBossTelesaTongue::checkHit are UNUSED in mario.MAP -- they are real functions that the compiler fully inlined and the linker then stripped. Their bodies were open-coded inside TBossTelesa::moveObject instead of living in the methods themselves. Move each loop into its own method and let moveObject just call them, the same way TBGCork::perform was pulled out of TBossGesso::perform. Body's out-of-line copy now matches the map size exactly (0xa0); Tongue is at 0xec of 0x23c, so it still has code left to recover. Also use the actor-type inlines rather than open-coded comparisons: checkActorType(ACTOR_TYPE_ENEMY) for the "is an enemy" test Mrkol pointed at, and isActorType(0x80000001) for the Mario checks -- the boss's own collision loop was comparing against ACTOR_TYPE_PLAYER (0x80000000) rather than the 0x80000001 the game actually uses. unk16C/unk170/unk174 now carry their real types instead of THitActor*. moveObject 78.2% -> 85.3%; TU 92.414% -> 92.712%. Co-Authored-By: Claude Opus 5 --- include/Enemy/BossTelesa.hpp | 9 +++-- src/Enemy/bosstelesa.cpp | 66 +++++++++++++++++------------------- 2 files changed, 37 insertions(+), 38 deletions(-) diff --git a/include/Enemy/BossTelesa.hpp b/include/Enemy/BossTelesa.hpp index 46feb1d98..fdce5b70b 100644 --- a/include/Enemy/BossTelesa.hpp +++ b/include/Enemy/BossTelesa.hpp @@ -36,6 +36,9 @@ class TBossTelesaSaveLoadParams : public TSpineEnemyParams { }; class TBossTelesa; +class TBossTelesaBody; +class TBossTelesaTongue; +class TBossTelesaKillSmallEnemy; class TTelesaSlot : public TSlotDrum { public: @@ -148,9 +151,9 @@ class TBossTelesa : public TSpineEnemy { /* 0x160 */ s32 unk160; /* 0x164 */ s32 unk164; /* 0x168 */ f32 unk168; - /* 0x16C */ THitActor* unk16C; - /* 0x170 */ THitActor* unk170; - /* 0x174 */ THitActor* unk174; + /* 0x16C */ TBossTelesaBody* unk16C; + /* 0x170 */ TBossTelesaTongue* unk170; + /* 0x174 */ TBossTelesaKillSmallEnemy* unk174; /* 0x178 */ TRoulette* unk178; /* 0x17C */ TRoulette* unk17C; /* 0x180 */ TRoulette* unk180; diff --git a/src/Enemy/bosstelesa.cpp b/src/Enemy/bosstelesa.cpp index 42411af61..1a2740ef6 100644 --- a/src/Enemy/bosstelesa.cpp +++ b/src/Enemy/bosstelesa.cpp @@ -480,9 +480,31 @@ BOOL TBossTelesaBody::receiveMessage(THitActor* sender, u32 message) return TRUE; } -void TBossTelesaBody::checkHit() { } +void TBossTelesaBody::checkHit() +{ + unk6C = 0; -void TBossTelesaTongue::checkHit() { } + for (int i = 0; i < mColCount; ++i) { + THitActor* actor = mCollisions[i]; + if (actor->isActorType(0x80000001)) + SMS_SendMessageToMario(this, HIT_MESSAGE_ATTACK); + else + unk68->checkHitObject(actor); + } +} + +void TBossTelesaTongue::checkHit() +{ + for (int i = 0; i < mColCount; ++i) { + THitActor* actor = mCollisions[i]; + if (actor->isActorType(0x80000001)) + SMS_SendMessageToMario(this, HIT_MESSAGE_ATTACK); + else if (actor->isActorType(0x40000395)) + unk68->setSpicy((TLiveActor*)actor); + else if (mPosition.y + 100.0f < actor->mPosition.y) + unk68->checkHitObject(actor); + } +} BOOL TBossTelesaTongue::receiveMessage(THitActor*, u32 message) { @@ -500,15 +522,9 @@ void TBossTelesaKillSmallEnemy::checkHit() unk6C = 0; for (int i = 0; i < mColCount; ++i) { - THitActor* collision = mCollisions[i]; - bool isEnemy; - if (collision->mActorType & ACTOR_TYPE_ENEMY) - isEnemy = true; - else - isEnemy = false; - if (isEnemy) { - THitActor* actor = collision; - if (actor->mActorType == (ACTOR_TYPE_ENEMY | 0x13)) + THitActor* actor = mCollisions[i]; + if (actor->checkActorType(ACTOR_TYPE_ENEMY)) { + if (actor->isActorType(0x10000013)) ((THamuKuri*)actor)->selectCapHolder(); ((TLiveActor*)actor)->kill(); } @@ -1252,7 +1268,7 @@ void TBossTelesa::moveObject() control(); for (int i = 0; i < mColCount; ++i) { - if (mCollisions[i]->mActorType == ACTOR_TYPE_PLAYER) + if (mCollisions[i]->isActorType(0x80000001)) SMS_SendMessageToMario(this, HIT_MESSAGE_ATTACK); } @@ -1278,29 +1294,9 @@ void TBossTelesa::moveObject() unk170->mPosition.set(node7[0][3], node7[1][3] - 350.0f, node7[2][3]); } - TBossTelesaBody* body = (TBossTelesaBody*)unk16C; - body->unk6C = 0; - for (int i = 0; i < body->mColCount; ++i) { - THitActor* actor = body->mCollisions[i]; - if (actor->mActorType == ACTOR_TYPE_PLAYER) - SMS_SendMessageToMario(body, HIT_MESSAGE_ATTACK); - else - body->unk68->checkHitObject(actor); - } - - TBossTelesaTongue* tongue = (TBossTelesaTongue*)unk170; - for (int i = 0; i < tongue->mColCount; ++i) { - THitActor* actor = tongue->mCollisions[i]; - if (actor->mActorType == ACTOR_TYPE_PLAYER) { - SMS_SendMessageToMario(tongue, HIT_MESSAGE_ATTACK); - } else if (actor->mActorType == 0x40000395) { - tongue->unk68->setSpicy((TLiveActor*)actor); - } else if (tongue->mPosition.y + 100.0f < actor->mPosition.y) { - tongue->unk68->checkHitObject(actor); - } - } - - ((TBossTelesaKillSmallEnemy*)unk174)->checkHit(); + unk16C->checkHit(); + unk170->checkHit(); + unk174->checkHit(); } void TBossTelesa::kill() From ae5425789a21c39b9a04ebdf1cacd96f34d34192 Mon Sep 17 00:00:00 2001 From: KakarotCake <61133727+KakarottoCake@users.noreply.github.com> Date: Fri, 21 Aug 2026 18:22:52 -0400 Subject: [PATCH 10/18] Enemy/bosstelesa: match TBubble::kill The 0x20000 live flag is set inside the nerve check, not after it. The ROM's early-exit branch lands on the 0x40 flag block and skips the 0x20000 one, so when the current nerve is already TNerveSmallEnemyDie only 0x40 gets set. TBubble::kill() now matches 100%. --- src/Enemy/bosstelesa.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Enemy/bosstelesa.cpp b/src/Enemy/bosstelesa.cpp index 1a2740ef6..508fde5fd 100644 --- a/src/Enemy/bosstelesa.cpp +++ b/src/Enemy/bosstelesa.cpp @@ -220,9 +220,9 @@ void TBubble::kill() mSpine->reset(); mSpine->setNext(&TNerveSmallEnemyDie::theNerve()); mSpine->pushAfterCurrent(mSpine->getDefault()); + onLiveFlag(LIVE_FLAG_UNK20000); } - onLiveFlag(LIVE_FLAG_UNK20000); onLiveFlag(LIVE_FLAG_UNK40); } From 5dcaf9bd6606ab13cd53502ab49461881af4029e Mon Sep 17 00:00:00 2001 From: KakarotCake <61133727+KakarottoCake@users.noreply.github.com> Date: Fri, 21 Aug 2026 18:28:38 -0400 Subject: [PATCH 11/18] Enemy/bosstelesa: reconstruct the tongueHitWater and checkMessage wrappers Both collision-actor receiveMessage overrides forward to a TBossTelesa method rather than touching the spine directly. Both of those methods are UNUSED in mario.MAP, so they are fully inlined back into the caller and the emitted code is unchanged in size. The extra layer is what makes the nerve singletons match. Reaching pushNerve directly put TNerveBase::TNerveBase() at inline pass 3, where its 2 statements fit the budget of 3 and it was inlined. Going through the wrapper pushes it to pass 4, which never runs, so it stays an out-of-line call exactly as the ROM has it. TBossTelesaTongue::receiveMessage and TBossTelesaBody::receiveMessage both now match 100%. --- src/Enemy/bosstelesa.cpp | 58 +++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/src/Enemy/bosstelesa.cpp b/src/Enemy/bosstelesa.cpp index 508fde5fd..6bb95e28f 100644 --- a/src/Enemy/bosstelesa.cpp +++ b/src/Enemy/bosstelesa.cpp @@ -456,28 +456,7 @@ void TBossTelesaManager::perform(u32 flags, JDrama::TGraphics* gfx) BOOL TBossTelesaBody::receiveMessage(THitActor* sender, u32 message) { - TBossTelesa* boss = unk68; - - if (message == HIT_MESSAGE_TRAMPLE) { - bool isMario; - if (sender->mActorType == (ACTOR_TYPE_PLAYER | 1)) - isMario = true; - else - isMario = false; - if (!isMario) { - if (boss->mSpine->getCurrentNerve() - == &TNerveBossTelesaPrepareSlot::theNerve()) - boss->mSpine->pushNerve(&TNerveBossTelesaSpit::theNerve()); - } - } - - if (message == HIT_MESSAGE_SPRAYED_BY_WATER) { - if (boss->mSpine->getCurrentNerve() - == &TNerveBossTelesaPrepareSlot::theNerve()) - boss->mSpine->pushNerve(&TNerveBossTelesaFreeze::theNerve()); - } - - return TRUE; + return unk68->checkMessage(sender, message); } void TBossTelesaBody::checkHit() @@ -508,12 +487,8 @@ void TBossTelesaTongue::checkHit() BOOL TBossTelesaTongue::receiveMessage(THitActor*, u32 message) { - if (message == HIT_MESSAGE_SPRAYED_BY_WATER) { - TBossTelesa* boss = unk68; - if (boss->mSpine->getCurrentNerve() - == &TNerveBossTelesaAppear::theNerve()) - boss->mSpine->pushNerve(&TNerveBossTelesaSlotStart::theNerve()); - } + if (message == HIT_MESSAGE_SPRAYED_BY_WATER) + unk68->tongueHitWater(); return TRUE; } @@ -1460,7 +1435,26 @@ BOOL TBossTelesa::receiveMessage(THitActor*, u32) { return FALSE; } BOOL TBossTelesa::checkMessage(THitActor* actor, u32 message) { - return receiveMessage(actor, message); + if (message == HIT_MESSAGE_TRAMPLE) { + bool isMario; + if (actor->mActorType == (ACTOR_TYPE_PLAYER | 1)) + isMario = true; + else + isMario = false; + if (!isMario) { + if (mSpine->getCurrentNerve() + == &TNerveBossTelesaPrepareSlot::theNerve()) + mSpine->pushNerve(&TNerveBossTelesaSpit::theNerve()); + } + } + + if (message == HIT_MESSAGE_SPRAYED_BY_WATER) { + if (mSpine->getCurrentNerve() + == &TNerveBossTelesaPrepareSlot::theNerve()) + mSpine->pushNerve(&TNerveBossTelesaFreeze::theNerve()); + } + + return TRUE; } void TBossTelesa::checkHitObject(THitActor* actor) @@ -1614,7 +1608,11 @@ void TBossTelesa::damageRecover() unk368 = 0; } -void TBossTelesa::tongueHitWater() { } +void TBossTelesa::tongueHitWater() +{ + if (mSpine->getCurrentNerve() == &TNerveBossTelesaAppear::theNerve()) + mSpine->pushNerve(&TNerveBossTelesaSlotStart::theNerve()); +} bool TBossTelesa::rouletteFall() { From fb21273eea24561f0a130a4b59e111777b5f3885 Mon Sep 17 00:00:00 2001 From: KakarotCake <61133727+KakarottoCake@users.noreply.github.com> Date: Fri, 21 Aug 2026 18:33:34 -0400 Subject: [PATCH 12/18] Enemy/bosstelesa: reconstruct checkSlot The tail of the SlotStart nerve is a bool-returning TBossTelesa method, not an inline early return. checkSlot is UNUSED in mario.MAP at 0xd4, which is large enough for the isRollDrum test, the unk18C reset and the whole SpitSlotItem nerve singleton block. Routing through it fixes two things at once: the inlined bool result is materialised and then tested, which is the li/b/li/clrlwi./beq sequence the ROM emits, and the extra call layer pushes TNerveBase::TNerveBase() out to inline pass 4 so it stays an out-of-line call. TNerveBossTelesaSlotStart::execute now differs only in stack frame size. --- src/Enemy/bosstelesa.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/Enemy/bosstelesa.cpp b/src/Enemy/bosstelesa.cpp index 6bb95e28f..c907c2cf5 100644 --- a/src/Enemy/bosstelesa.cpp +++ b/src/Enemy/bosstelesa.cpp @@ -2127,7 +2127,16 @@ void TBossTelesa::generateSlotItem() void TBossTelesa::fruitCollisionOn() { unk370 = 0; } -bool TBossTelesa::checkSlot() { return unk184 != nullptr; } +bool TBossTelesa::checkSlot() +{ + if (!unk184->isRollDrum() && unk18C) { + unk18C = 0; + mSpine->pushAfterCurrent(&TNerveBossTelesaSpitSlotItem::theNerve()); + return true; + } + + return false; +} bool TBossTelesa::checkAllItemDead() { @@ -2655,12 +2664,8 @@ DEFINE_NERVE(TNerveBossTelesaSlotStart, TLiveActor) } } - if (!boss->unk184->isRollDrum() && boss->unk18C) { - boss->unk18C = 0; - boss->mSpine->pushAfterCurrent( - &TNerveBossTelesaSpitSlotItem::theNerve()); + if (boss->checkSlot()) return TRUE; - } boss->unk364 *= 0.99f; return FALSE; From dd9bcdcf5dc1bcfa82ae8b907feee5374472f351 Mon Sep 17 00:00:00 2001 From: KakarotCake <61133727+KakarottoCake@users.noreply.github.com> Date: Fri, 21 Aug 2026 18:53:16 -0400 Subject: [PATCH 13/18] Enemy/bosstelesa: reconstruct slotStart, drop four dont_inline pragmas moveStart is 19 statements, so a call to it at inline pass 0 (which has no limit) was being expanded; the pragma existed only to stop that. The SlotStart nerve reaches it through TBossTelesa::slotStart(), which is UNUSED in mario.MAP at 0x40 -- exactly the three statements it needs. Going through the wrapper puts moveStart at pass 1, where 19 statements exceed the budget of 10 and it stays an out-of-line call on its own. The pragmas around isRollDrum, getSlotResult and forceAllItemKill turn out to do nothing at all: those three are byte-identical with or without them. Verified by diffing the full nonmatching symbol set before and after: identical, no regressions. Two pragmas remain, around randomReset (its caller TNerveBossTelesaAppear::execute drops to 80% without it) and forceStopSlot. --- src/Enemy/bosstelesa.cpp | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/Enemy/bosstelesa.cpp b/src/Enemy/bosstelesa.cpp index c907c2cf5..1db13b312 100644 --- a/src/Enemy/bosstelesa.cpp +++ b/src/Enemy/bosstelesa.cpp @@ -678,7 +678,6 @@ void TTelesaSlot::moveObject() } } -#pragma dont_inline on void TTelesaSlot::moveStart() { unk19C = 1; @@ -697,7 +696,6 @@ void TTelesaSlot::moveStart() unk138[i] = speed * unk158; } } -#pragma dont_inline off u32 TTelesaSlot::touchWater(THitActor*) { return FALSE; } @@ -742,7 +740,6 @@ void TTelesaSlot::forceStopSlot(int idx) } #pragma dont_inline off -#pragma dont_inline on bool TTelesaSlot::isRollDrum() { if (unk198[0]) @@ -755,9 +752,7 @@ bool TTelesaSlot::isRollDrum() unk19B = 0; return false; } -#pragma dont_inline off -#pragma dont_inline on int TTelesaSlot::getSlotResult() { int result = getResultFromAng(unk13C[0]); @@ -767,7 +762,6 @@ int TTelesaSlot::getSlotResult() } return result; } -#pragma dont_inline off int TTelesaSlot::getDrumResult(int index) { @@ -1881,7 +1875,12 @@ void TBossTelesa::rouletteStart() gpCameraShake->startShake(CAM_SHAKE_MODE_UNK23, 1.0f); } -void TBossTelesa::slotStart() { rouletteStart(); } +void TBossTelesa::slotStart() +{ + unk18C = 1; + unk184->moveStart(); + ((TTelesaManager*)unk354)->telesaForceKill(); +} void TBossTelesa::slotStop() { @@ -2146,7 +2145,6 @@ bool TBossTelesa::checkAllItemDead() return true; } -#pragma dont_inline on void TBossTelesa::forceAllItemKill() { f32 zero = 0.0f; @@ -2167,7 +2165,6 @@ void TBossTelesa::forceAllItemKill() } } } -#pragma dont_inline off void TBossTelesa::rollRouletteCircle() { @@ -2636,9 +2633,7 @@ DEFINE_NERVE(TNerveBossTelesaSlotStart, TLiveActor) if (boss->mMActor->checkCurBckFromIndex(11)) { if (boss->mMActor->getFrameCtrl(0)->checkPass(53.0f)) { - boss->unk18C = 1; - boss->unk184->moveStart(); - ((TTelesaManager*)boss->unk354)->telesaForceKill(); + boss->slotStart(); } if (boss->checkCurAnmEnd(0)) { From 03146e1c07e72af6e4ca80de1c9792bf578cca65 Mon Sep 17 00:00:00 2001 From: KakarotCake <61133727+KakarottoCake@users.noreply.github.com> Date: Fri, 21 Aug 2026 19:06:27 -0400 Subject: [PATCH 14/18] M3DUtil/MActor: fix the getCurBckAnmPtr naming mario.MAP records getCurBckAnmPtr__6MActorFv at 0x1c (28 bytes), but the accessor we had under that name was `return unkC;`, which compiles to 8. 28 bytes is the shape of the null-checked `unkC->unk24` body we had named getBckAnm, so the two were swapped. Per Mrkol: getCurBckAnmPtr is the null-checked one returning J3DAnmTransformKey*, and the 8-byte `return unkC;` getter is ours to name, so it becomes getUnkC() alongside the existing fabricated getUnk28(). They are not interchangeable -- different return types and different callers -- so this is a rename of both, not a merge. 8 references to the old getCurBckAnmPtr (gatekeeper, hinokuri2, NpcInitPrg) and 27 to getBckAnm (CameraBck, bosseel, bosstelesa) updated. No change to the nonmatching set in any of the six affected translation units, CameraBck included, which is at 0. This does not yet clear the validator's MISSING report for the symbol: the map wants bosstelesa.o to define a weak out-of-line copy, and that only appears once some call to it fails to inline. --- include/M3DUtil/MActor.hpp | 4 ++-- src/Camera/CameraBck.cpp | 2 +- src/Enemy/bosseel.cpp | 10 +++++----- src/Enemy/bosstelesa.cpp | 40 +++++++++++++++++++------------------- src/Enemy/gatekeeper.cpp | 4 ++-- src/Enemy/hinokuri2.cpp | 6 +++--- src/NPC/NpcInitPrg.cpp | 4 ++-- 7 files changed, 35 insertions(+), 35 deletions(-) diff --git a/include/M3DUtil/MActor.hpp b/include/M3DUtil/MActor.hpp index 8e3514d2a..cc7b79487 100644 --- a/include/M3DUtil/MActor.hpp +++ b/include/M3DUtil/MActor.hpp @@ -92,7 +92,7 @@ class MActor { // fabricated MActorAnmBase* getUnk28(int i) { return unk28[i]; } - MActorAnmBck* getCurBckAnmPtr() { return unkC; } + MActorAnmBck* getUnkC() { return unkC; } J3DModel* getModel() const { return unk4; } void unmarkUnk40() { unk40 = false; } BOOL curAnmEndsNext() { return curAnmEndsNext(0, 0); } @@ -166,7 +166,7 @@ class MActor { unkC->initNormalMotionBlend(); } - J3DAnmTransformKey* getBckAnm() + J3DAnmTransformKey* getCurBckAnmPtr() { if (!unkC) return nullptr; diff --git a/src/Camera/CameraBck.cpp b/src/Camera/CameraBck.cpp index bcbc1059c..31c3f124b 100644 --- a/src/Camera/CameraBck.cpp +++ b/src/Camera/CameraBck.cpp @@ -104,7 +104,7 @@ bool TCameraBck::updateDemo(JGeometry::TVec3* pos, up->set(unkC[0][1], unkC[1][1], unkC[2][1]); if (out_y_scale != nullptr) { - J3DAnmTransformKey* anm = unk0->getBckAnm(); + J3DAnmTransformKey* anm = unk0->getCurBckAnmPtr(); if (anm != nullptr) { J3DTransformInfo info; anm->getTransform((u16)unk8, &info); diff --git a/src/Enemy/bosseel.cpp b/src/Enemy/bosseel.cpp index 94a664f63..849e5ae6d 100644 --- a/src/Enemy/bosseel.cpp +++ b/src/Enemy/bosseel.cpp @@ -1076,7 +1076,7 @@ TBossEelEye::TBossEelEye(const TLiveActor* owner, int jointIndex, mPreviousBckIndex = getMActor()->getCurAnmIdx(0); mAnimationMode = 0; mBlendRatio = 1.0f; - getMActor()->setBckOldMotionBlendAnmPtr(getMActor()->getBckAnm()); + getMActor()->setBckOldMotionBlendAnmPtr(getMActor()->getCurBckAnmPtr()); getMActor()->setBckFromIndex(0); getMActor()->setMotionBlendRatioForBck(mBlendRatio); } @@ -1112,7 +1112,7 @@ void TBossEelEye::perform(u32 cue, JDrama::TGraphics* graphics) mAnimationMode = 0; mBlendRatio = 1.0f; getMActor()->setBckOldMotionBlendAnmPtr( - getMActor()->getBckAnm()); + getMActor()->getCurBckAnmPtr()); getMActor()->setBckFromIndex(0); getMActor()->setMotionBlendRatioForBck(mBlendRatio); @@ -1122,7 +1122,7 @@ void TBossEelEye::perform(u32 cue, JDrama::TGraphics* graphics) paired->mAnimationMode = 0; paired->mBlendRatio = 1.0f; paired->getMActor()->setBckOldMotionBlendAnmPtr( - paired->getMActor()->getBckAnm()); + paired->getMActor()->getCurBckAnmPtr()); paired->getMActor()->setBckFromIndex(0); paired->getMActor()->setMotionBlendRatioForBck( paired->mBlendRatio); @@ -1138,7 +1138,7 @@ void TBossEelEye::setBckAnm(int index) mPreviousBckIndex = getMActor()->getCurAnmIdx(0); mAnimationMode = 1; mBlendRatio = 1.0f; - getMActor()->setBckOldMotionBlendAnmPtr(getMActor()->getBckAnm()); + getMActor()->setBckOldMotionBlendAnmPtr(getMActor()->getCurBckAnmPtr()); getMActor()->setBckFromIndex(index); getMActor()->setMotionBlendRatioForBck(mBlendRatio); } @@ -1917,7 +1917,7 @@ void TBossEel::setBckAnm(int index) mPreviousBckIndex = getMActor()->getCurAnmIdx(0); mCurrentBckIndex = index; mBckBlendRatio = 1.0f; - getMActor()->setBckOldMotionBlendAnmPtr(getMActor()->getBckAnm()); + getMActor()->setBckOldMotionBlendAnmPtr(getMActor()->getCurBckAnmPtr()); getMActor()->setBckFromIndex(index); getMActor()->setMotionBlendRatioForBck(mBckBlendRatio); getMActor()->getFrameCtrl(0)->setRate(0.25f * SMSGetAnmFrameRate()); diff --git a/src/Enemy/bosstelesa.cpp b/src/Enemy/bosstelesa.cpp index 1db13b312..bedf332ad 100644 --- a/src/Enemy/bosstelesa.cpp +++ b/src/Enemy/bosstelesa.cpp @@ -1531,7 +1531,7 @@ void TBossTelesa::setSpicy(TLiveActor* actor) unk160 = 1; unk168 = 1.0f; - mMActor->setBckOldMotionBlendAnmPtr(mMActor->getBckAnm()); + mMActor->setBckOldMotionBlendAnmPtr(mMActor->getCurBckAnmPtr()); mMActor->setBckFromIndex(1); mMActor->setMotionBlendRatioForBck(unk168); @@ -2220,7 +2220,7 @@ DEFINE_NERVE(TNerveBossTelesaDie, TLiveActor) boss->unk168 = 1.0f; MActor* anmActor = boss->mMActor; - anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getCurBckAnmPtr()); boss->mMActor->setBckFromIndex(2); boss->mMActor->setMotionBlendRatioForBck(boss->unk168); @@ -2239,7 +2239,7 @@ DEFINE_NERVE(TNerveBossTelesaDie, TLiveActor) boss->unk168 = 1.0f; MActor* anmActor = boss->mMActor; - anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getCurBckAnmPtr()); boss->mMActor->setBckFromIndex(5); boss->mMActor->setMotionBlendRatioForBck(boss->unk168); @@ -2262,7 +2262,7 @@ DEFINE_NERVE(TNerveBossTelesaDie, TLiveActor) boss->unk168 = 1.0f; MActor* anmActor = boss->mMActor; - anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getCurBckAnmPtr()); boss->mMActor->setBckFromIndex(3); boss->mMActor->setMotionBlendRatioForBck(boss->unk168); @@ -2346,7 +2346,7 @@ DEFINE_NERVE(TNerveBossTelesaDie, TLiveActor) boss->unk168 = 1.0f; MActor* anmActor = boss->mMActor; - anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getCurBckAnmPtr()); boss->mMActor->setBckFromIndex(7); boss->mMActor->setMotionBlendRatioForBck(boss->unk168); @@ -2364,7 +2364,7 @@ DEFINE_NERVE(TNerveBossTelesaDie, TLiveActor) boss->unk168 = 1.0f; MActor* anmActor = boss->mMActor; - anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getCurBckAnmPtr()); boss->mMActor->setBckFromIndex(6); boss->mMActor->setMotionBlendRatioForBck(boss->unk168); @@ -2389,7 +2389,7 @@ DEFINE_NERVE(TNerveBossTelesaDie, TLiveActor) boss->unk168 = 1.0f; MActor* anmActor = boss->mMActor; - anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getCurBckAnmPtr()); boss->mMActor->setBckFromIndex(15); boss->mMActor->setMotionBlendRatioForBck(boss->unk168); @@ -2423,7 +2423,7 @@ DEFINE_NERVE(TNerveBossTelesaSpit, TLiveActor) boss->unk168 = 1.0f; MActor* anmActor = boss->mMActor; - anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getCurBckAnmPtr()); boss->mMActor->setBckFromIndex(14); boss->mMActor->setMotionBlendRatioForBck(boss->unk168); @@ -2454,7 +2454,7 @@ DEFINE_NERVE(TNerveBossTelesaHide, TLiveActor) boss->unk168 = 1.0f; MActor* anmActor = boss->mMActor; - anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getCurBckAnmPtr()); boss->mMActor->setBckFromIndex(4); boss->mMActor->setMotionBlendRatioForBck(boss->unk168); @@ -2524,7 +2524,7 @@ DEFINE_NERVE(TNerveBossTelesaAppear, TLiveActor) boss->unk168 = 1.0f; MActor* anmActor = boss->mMActor; - anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getCurBckAnmPtr()); boss->mMActor->setBckFromIndex(0); boss->mMActor->setMotionBlendRatioForBck(boss->unk168); @@ -2555,7 +2555,7 @@ DEFINE_NERVE(TNerveBossTelesaAppear, TLiveActor) boss->unk168 = 1.0f; MActor* anmActor = boss->mMActor; - anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getCurBckAnmPtr()); boss->mMActor->setBckFromIndex(15); boss->mMActor->setMotionBlendRatioForBck(boss->unk168); @@ -2589,7 +2589,7 @@ DEFINE_NERVE(TNerveBossTelesaAppear, TLiveActor) boss->unk168 = 1.0f; MActor* anmActor = boss->mMActor; - anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getCurBckAnmPtr()); boss->mMActor->setBckFromIndex(14); boss->mMActor->setMotionBlendRatioForBck(boss->unk168); @@ -2617,7 +2617,7 @@ DEFINE_NERVE(TNerveBossTelesaSlotStart, TLiveActor) boss->unk168 = 1.0f; MActor* anmActor = boss->mMActor; - anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getCurBckAnmPtr()); boss->mMActor->setBckFromIndex(11); boss->mMActor->setMotionBlendRatioForBck(boss->unk168); @@ -2642,7 +2642,7 @@ DEFINE_NERVE(TNerveBossTelesaSlotStart, TLiveActor) boss->unk168 = 1.0f; MActor* anmActor = boss->mMActor; - anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getCurBckAnmPtr()); boss->mMActor->setBckFromIndex(15); boss->mMActor->setMotionBlendRatioForBck(boss->unk168); @@ -2676,7 +2676,7 @@ DEFINE_NERVE(TNerveBossTelesaSpitSlotItem, TLiveActor) boss->unk168 = 1.0f; MActor* anmActor = boss->mMActor; - anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getCurBckAnmPtr()); boss->mMActor->setBckFromIndex(14); boss->mMActor->setMotionBlendRatioForBck(boss->unk168); @@ -2714,7 +2714,7 @@ DEFINE_NERVE(TNerveBossTelesaPrepareSlot, TLiveActor) boss->unk168 = 1.0f; MActor* anmActor = boss->mMActor; - anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getCurBckAnmPtr()); boss->mMActor->setBckFromIndex(15); boss->mMActor->setMotionBlendRatioForBck(boss->unk168); @@ -2738,7 +2738,7 @@ DEFINE_NERVE(TNerveBossTelesaPrepareSlot, TLiveActor) boss->unk168 = 1.0f; MActor* anmActor = boss->mMActor; - anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getCurBckAnmPtr()); boss->mMActor->setBckFromIndex(12); boss->mMActor->setMotionBlendRatioForBck(boss->unk168); @@ -2760,7 +2760,7 @@ DEFINE_NERVE(TNerveBossTelesaPrepareSlot, TLiveActor) boss->unk168 = 1.0f; MActor* anmActor = boss->mMActor; - anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getCurBckAnmPtr()); boss->mMActor->setBckFromIndex(13); boss->mMActor->setMotionBlendRatioForBck(boss->unk168); @@ -2792,7 +2792,7 @@ DEFINE_NERVE(TNerveBossTelesaPrepareSlot, TLiveActor) boss->unk168 = 1.0f; MActor* anmActor = boss->mMActor; - anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getCurBckAnmPtr()); boss->mMActor->setBckFromIndex(15); boss->mMActor->setMotionBlendRatioForBck(boss->unk168); @@ -2885,7 +2885,7 @@ DEFINE_NERVE(TNerveBossTelesaFreeze, TLiveActor) boss->unk168 = 1.0f; MActor* anmActor = boss->mMActor; - anmActor->setBckOldMotionBlendAnmPtr(anmActor->getBckAnm()); + anmActor->setBckOldMotionBlendAnmPtr(anmActor->getCurBckAnmPtr()); boss->mMActor->setBckFromIndex(16); boss->mMActor->setMotionBlendRatioForBck(boss->unk168); diff --git a/src/Enemy/gatekeeper.cpp b/src/Enemy/gatekeeper.cpp index cc8418184..dcb0c16fb 100644 --- a/src/Enemy/gatekeeper.cpp +++ b/src/Enemy/gatekeeper.cpp @@ -426,11 +426,11 @@ void TBiancoGateKeeper::changeBck(int param_1) || (cur == 7 && param_1 == 7) || (cur == 7 && param_1 == 0x12) || (cur == 0xF && param_1 == 0x10) || (cur == 0x10 && param_1 == 0xC)) { unk178->setAnm(param_1); - mMActor->getCurBckAnmPtr()->setFrameCtrl(param_1); + mMActor->getUnkC()->setFrameCtrl(param_1); unk158 = 0.0f; } else { unk178->joinAnm(param_1); - mMActor->getCurBckAnmPtr()->setFrameCtrl(param_1); + mMActor->getUnkC()->setFrameCtrl(param_1); J3DFrameCtrl* fc = mMActor->getFrameCtrl(0); if (fc != NULL) { f32 v = 0.25f * (f32)fc->getEnd(); diff --git a/src/Enemy/hinokuri2.cpp b/src/Enemy/hinokuri2.cpp index d2e38e2ca..1e462635f 100644 --- a/src/Enemy/hinokuri2.cpp +++ b/src/Enemy/hinokuri2.cpp @@ -558,8 +558,8 @@ void THinokuri2::init(TLiveManager* param_1) mHitPoints = calcHitPoints(); J3DMtxCalc* calc = unk1A0; - if (getMActor()->getCurBckAnmPtr()) { - MActorAnmBck* bck = getMActor()->getCurBckAnmPtr(); + if (getMActor()->getUnkC()) { + MActorAnmBck* bck = getMActor()->getUnkC(); bck->unk38 = calc; bck->unk2A = 3; } @@ -737,7 +737,7 @@ void THinokuri2::changeBck(int param_1) param_1)); } - getMActor()->getCurBckAnmPtr()->setFrameCtrl(param_1); + getMActor()->getUnkC()->setFrameCtrl(param_1); } mCurrentBck = param_1; diff --git a/src/NPC/NpcInitPrg.cpp b/src/NPC/NpcInitPrg.cpp index 89d5db306..2288985d9 100644 --- a/src/NPC/NpcInitPrg.cpp +++ b/src/NPC/NpcInitPrg.cpp @@ -181,8 +181,8 @@ void TBaseNPC::init(TLiveManager* param_1) onLiveFlag(LIVE_FLAG_UNK10); } - if (mMActor->getCurBckAnmPtr()) - mMActor->getCurBckAnmPtr()->initNormalMotionBlend(); + if (mMActor->getUnkC()) + mMActor->getUnkC()->initNormalMotionBlend(); if (isPollutionNpc()) initSinkNpc_(); From 1cb40c4c0597c8209b32633ee09e11cb6443a717 Mon Sep 17 00:00:00 2001 From: KakarotCake <61133727+KakarottoCake@users.noreply.github.com> Date: Fri, 21 Aug 2026 19:21:12 -0400 Subject: [PATCH 15/18] Enemy/BossTelesa: fix CI build and formatting main removed the base-class LIVE_FLAG_UNK10000 because 0x10000 is overloaded between derived classes, so declare a class-scoped one on TBossTelesa and qualify the use, following TBossEel. Also reflow the six setBckOldMotionBlendAnmPtr calls that went over the 80-column limit after the getCurBckAnmPtr rename. Co-Authored-By: Claude Opus 5 --- include/Enemy/BossTelesa.hpp | 4 ++++ src/Enemy/bosstelesa.cpp | 20 +++++++++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/include/Enemy/BossTelesa.hpp b/include/Enemy/BossTelesa.hpp index fdce5b70b..fca84a57f 100644 --- a/include/Enemy/BossTelesa.hpp +++ b/include/Enemy/BossTelesa.hpp @@ -142,6 +142,10 @@ class TBossTelesa : public TSpineEnemy { static f32 mCameraMoveLimit; static f32 mCameraMoveSp; + enum { + LIVE_FLAG_UNK10000 = 0x10000, + }; + public: /* 0x150 */ u8 unk150; /* 0x151 */ u8 unk151[0x3]; diff --git a/src/Enemy/bosstelesa.cpp b/src/Enemy/bosstelesa.cpp index bedf332ad..aa08b1aed 100644 --- a/src/Enemy/bosstelesa.cpp +++ b/src/Enemy/bosstelesa.cpp @@ -2220,7 +2220,8 @@ DEFINE_NERVE(TNerveBossTelesaDie, TLiveActor) boss->unk168 = 1.0f; MActor* anmActor = boss->mMActor; - anmActor->setBckOldMotionBlendAnmPtr(anmActor->getCurBckAnmPtr()); + anmActor->setBckOldMotionBlendAnmPtr( + anmActor->getCurBckAnmPtr()); boss->mMActor->setBckFromIndex(2); boss->mMActor->setMotionBlendRatioForBck(boss->unk168); @@ -2239,7 +2240,8 @@ DEFINE_NERVE(TNerveBossTelesaDie, TLiveActor) boss->unk168 = 1.0f; MActor* anmActor = boss->mMActor; - anmActor->setBckOldMotionBlendAnmPtr(anmActor->getCurBckAnmPtr()); + anmActor->setBckOldMotionBlendAnmPtr( + anmActor->getCurBckAnmPtr()); boss->mMActor->setBckFromIndex(5); boss->mMActor->setMotionBlendRatioForBck(boss->unk168); @@ -2323,7 +2325,7 @@ DEFINE_NERVE(TNerveBossTelesaDie, TLiveActor) boss->mPosition.x, boss->mPosition.y, boss->mPosition.z); boss->onLiveFlag(LIVE_FLAG_DEAD); boss->onLiveFlag(LIVE_FLAG_UNK8); - boss->offLiveFlag(LIVE_FLAG_UNK10000); + boss->offLiveFlag(TBossTelesa::LIVE_FLAG_UNK10000); boss->mHolder = nullptr; boss->onHitFlag(HIT_FLAG_NO_COLLISION); boss->unk16C->onHitFlag(HIT_FLAG_NO_COLLISION); @@ -2389,7 +2391,8 @@ DEFINE_NERVE(TNerveBossTelesaDie, TLiveActor) boss->unk168 = 1.0f; MActor* anmActor = boss->mMActor; - anmActor->setBckOldMotionBlendAnmPtr(anmActor->getCurBckAnmPtr()); + anmActor->setBckOldMotionBlendAnmPtr( + anmActor->getCurBckAnmPtr()); boss->mMActor->setBckFromIndex(15); boss->mMActor->setMotionBlendRatioForBck(boss->unk168); @@ -2738,7 +2741,8 @@ DEFINE_NERVE(TNerveBossTelesaPrepareSlot, TLiveActor) boss->unk168 = 1.0f; MActor* anmActor = boss->mMActor; - anmActor->setBckOldMotionBlendAnmPtr(anmActor->getCurBckAnmPtr()); + anmActor->setBckOldMotionBlendAnmPtr( + anmActor->getCurBckAnmPtr()); boss->mMActor->setBckFromIndex(12); boss->mMActor->setMotionBlendRatioForBck(boss->unk168); @@ -2760,7 +2764,8 @@ DEFINE_NERVE(TNerveBossTelesaPrepareSlot, TLiveActor) boss->unk168 = 1.0f; MActor* anmActor = boss->mMActor; - anmActor->setBckOldMotionBlendAnmPtr(anmActor->getCurBckAnmPtr()); + anmActor->setBckOldMotionBlendAnmPtr( + anmActor->getCurBckAnmPtr()); boss->mMActor->setBckFromIndex(13); boss->mMActor->setMotionBlendRatioForBck(boss->unk168); @@ -2792,7 +2797,8 @@ DEFINE_NERVE(TNerveBossTelesaPrepareSlot, TLiveActor) boss->unk168 = 1.0f; MActor* anmActor = boss->mMActor; - anmActor->setBckOldMotionBlendAnmPtr(anmActor->getCurBckAnmPtr()); + anmActor->setBckOldMotionBlendAnmPtr( + anmActor->getCurBckAnmPtr()); boss->mMActor->setBckFromIndex(15); boss->mMActor->setMotionBlendRatioForBck(boss->unk168); From b26637279d910363f9050f88c9903a0700a92d0e Mon Sep 17 00:00:00 2001 From: KakarotCake <61133727+KakarottoCake@users.noreply.github.com> Date: Fri, 21 Aug 2026 19:47:16 -0400 Subject: [PATCH 16/18] Enemy/bosstelesa: reconstruct setBckAnm, emit getCurBckAnmPtr setBckAnm was a two-statement stub with no callers; the map wants 0xd4. Its real body is the animation-switch block that was open-coded in setSpicy, so move it there and have setSpicy call setBckAnm(1). That also fixes the missing getCurBckAnmPtr__6MActorFv weak copy the map expects from this TU. getCurBckAnmPtr is 4 statements, so it is only refused at inline pass 3 (budget 3). Writing the block in setSpicy put it at pass 2; routing through setBckAnm and letting setSpicy inline into TBossTelesaTongue::checkHit puts it at pass 3, where MWCC gives up and emits the out-of-line copy. setBckAnm has to stay under the pass-1 budget of 10 statements for that to happen, hence the ternary for the bas name. All four sizes now land exactly on the map: setBckAnm 0xd4 (212) setSpicy 0x19c (412) TBossTelesaTongue::checkHit 0x23c (572), was 0xec getCurBckAnmPtr 0x1c (28), was absent check-changed-symbol-order.py goes from FAIL (1 missing symbol, 20 UNUSED size mismatches) to PASS with 18. No change to the nonmatching set. Co-Authored-By: Claude Opus 5 --- src/Enemy/bosstelesa.cpp | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/src/Enemy/bosstelesa.cpp b/src/Enemy/bosstelesa.cpp index aa08b1aed..84ef52a60 100644 --- a/src/Enemy/bosstelesa.cpp +++ b/src/Enemy/bosstelesa.cpp @@ -1527,22 +1527,7 @@ void TBossTelesa::setSpicy(TLiveActor* actor) unk350 = 1; unk36C = 0; - unk164 = mMActor->getCurAnmIdx(0); - unk160 = 1; - unk168 = 1.0f; - - mMActor->setBckOldMotionBlendAnmPtr(mMActor->getCurBckAnmPtr()); - - mMActor->setBckFromIndex(1); - mMActor->setMotionBlendRatioForBck(unk168); - - const char** basTable = getBasNameTable(); - const char* basName; - if (!basTable) - basName = nullptr; - else - basName = basTable[1]; - setAnmSound(basName); + setBckAnm(1); if (unk35B) { unk35B = 0; @@ -1838,8 +1823,17 @@ void TBossTelesa::genAttacker() void TBossTelesa::setBckAnm(int index) { - if (mMActor) - mMActor->setBckFromIndex(index); + unk164 = mMActor->getCurAnmIdx(0); + unk160 = index; + unk168 = 1.0f; + + mMActor->setBckOldMotionBlendAnmPtr(mMActor->getCurBckAnmPtr()); + + mMActor->setBckFromIndex(index); + mMActor->setMotionBlendRatioForBck(unk168); + + const char** basTable = getBasNameTable(); + setAnmSound(!basTable ? nullptr : basTable[index]); } bool TBossTelesa::isInDamage() { return unk35B != 0; } From 0aa5dbd2d4462dc39f3e7b884236764e6d2b9025 Mon Sep 17 00:00:00 2001 From: KakarotCake <61133727+KakarottoCake@users.noreply.github.com> Date: Sat, 22 Aug 2026 03:45:22 -0400 Subject: [PATCH 17/18] Enemy/bosstelesa: address review feedback - reconstruct TBubble::appendItem from the block open-coded at the bubble generation site, symmetric with appendEnemy; lands on the map's 0xd8 - offAllCollision/onAllCollision had a fourth collision actor the map does not account for. Dropping unk174 puts both at the map's 0x30, and the three open-coded sites now call offAllCollision() - use MActor/J3DModel accessors instead of mMActor->unk4->unk20 - use the MTX* wrapper macros instead of PSMTX* throughout - use checkLiveFlag() instead of testing mLiveFlag directly - hardcode the composed actor types rather than composing them from the ACTOR_TYPE_ macros - give unk2A8 and unk2F8 their real TMapObjBase* type and drop the twelve casts at the use sites; likewise hoist the TItem* cast in slotFall UNUSED size mismatches 18 -> 15. No change to the matched set: 61/100 functions and 8672 bytes before and after, per-function percentages identical. mario.dol: OK. Co-Authored-By: Claude Opus 5 --- include/Enemy/BossTelesa.hpp | 4 +- src/Enemy/bosstelesa.cpp | 134 +++++++++++++++++------------------ 2 files changed, 66 insertions(+), 72 deletions(-) diff --git a/include/Enemy/BossTelesa.hpp b/include/Enemy/BossTelesa.hpp index fca84a57f..05977a4f7 100644 --- a/include/Enemy/BossTelesa.hpp +++ b/include/Enemy/BossTelesa.hpp @@ -170,8 +170,8 @@ class TBossTelesa : public TSpineEnemy { /* 0x1AC */ TLiveActor* unk1AC[50]; /* 0x274 */ s32 unk274; /* 0x278 */ JGeometry::TMatrix34 > unk278; - /* 0x2A8 */ TLiveActor* unk2A8[20]; - /* 0x2F8 */ TLiveActor* unk2F8[10]; + /* 0x2A8 */ TMapObjBase* unk2A8[20]; + /* 0x2F8 */ TMapObjBase* unk2F8[10]; /* 0x320 */ TLiveActor* unk320[10]; /* 0x348 */ GXColor unk348; /* 0x34C */ GXColor unk34C; diff --git a/src/Enemy/bosstelesa.cpp b/src/Enemy/bosstelesa.cpp index 84ef52a60..94cd44713 100644 --- a/src/Enemy/bosstelesa.cpp +++ b/src/Enemy/bosstelesa.cpp @@ -258,7 +258,7 @@ void TBubble::calcRootMatrix() void TBubble::setDeadAnm() { setBckAnm(9); } -MtxPtr TBubble::getTakingMtx() { return mMActor->unk4->unk20; } +MtxPtr TBubble::getTakingMtx() { return mMActor->getModel()->getBaseTRMtx(); } const char** TBubble::getBasNameTable() const { return btelesa_bastable; } @@ -268,7 +268,20 @@ const TNerveBubbleLive& TNerveBubbleLive::theNerve() return instance; } -void TBubble::appendItem() { } +void TBubble::appendItem() +{ + unk198 = nullptr; + TMapObjBase* item = gpItemManager->makeObjAppear( + mPosition.x, mPosition.y, mPosition.z, 0x20000008, true); + if (item && item->receiveMessage(this, HIT_MESSAGE_TAKE)) { + item->appear(); + item->mPosition = mPosition; + item->mVelocity.set(0.0f, 15.0f, 0.0f); + item->offLiveFlag(LIVE_FLAG_UNK10); + mHeldObject = item; + unk198 = item; + } +} void TBubble::appendEnemy() { @@ -1026,22 +1039,22 @@ void TBossTelesa::loadAfter() JGeometry::TVec3(1.0f, 1.0f, 1.0f)); for (int i = 0; i < 20; ++i) { - ((TMapObjBase*)unk2A8[i])->onMapObjFlag(0x04000000); - ((TMapObjBase*)unk2A8[i])->makeObjDead(); - } - - unk2F8[0] = JDrama::TNameRefGen::search("唐辛子 0"); - unk2F8[1] = JDrama::TNameRefGen::search("唐辛子 1"); - unk2F8[2] = JDrama::TNameRefGen::search("唐辛子 2"); - unk2F8[3] = JDrama::TNameRefGen::search("唐辛子 3"); - unk2F8[4] = JDrama::TNameRefGen::search("唐辛子 4"); - unk2F8[5] = JDrama::TNameRefGen::search("唐辛子 5"); - unk2F8[6] = JDrama::TNameRefGen::search("唐辛子 6"); - unk2F8[7] = JDrama::TNameRefGen::search("唐辛子 7"); - unk2F8[8] = JDrama::TNameRefGen::search("唐辛子 8"); - unk2F8[9] = JDrama::TNameRefGen::search("唐辛子 9"); + unk2A8[i]->onMapObjFlag(0x04000000); + unk2A8[i]->makeObjDead(); + } + + unk2F8[0] = JDrama::TNameRefGen::search("唐辛子 0"); + unk2F8[1] = JDrama::TNameRefGen::search("唐辛子 1"); + unk2F8[2] = JDrama::TNameRefGen::search("唐辛子 2"); + unk2F8[3] = JDrama::TNameRefGen::search("唐辛子 3"); + unk2F8[4] = JDrama::TNameRefGen::search("唐辛子 4"); + unk2F8[5] = JDrama::TNameRefGen::search("唐辛子 5"); + unk2F8[6] = JDrama::TNameRefGen::search("唐辛子 6"); + unk2F8[7] = JDrama::TNameRefGen::search("唐辛子 7"); + unk2F8[8] = JDrama::TNameRefGen::search("唐辛子 8"); + unk2F8[9] = JDrama::TNameRefGen::search("唐辛子 9"); for (int i = 0; i < 10; ++i) - ((TMapObjBase*)unk2F8[i])->makeObjDead(); + unk2F8[i]->makeObjDead(); unk320[0] = JDrama::TNameRefGen::search("コイン 0"); unk320[1] = JDrama::TNameRefGen::search("コイン 1"); @@ -1152,7 +1165,7 @@ void TBossTelesa::reset() void TBossTelesa::moveObject() { - if (mLiveFlag & LIVE_FLAG_DEAD) + if (checkLiveFlag(LIVE_FLAG_DEAD)) return; JGeometry::TVec3 cameraPos; @@ -1249,7 +1262,7 @@ void TBossTelesa::moveObject() unk168 = MsClamp(unk168 - 0.05f, 0.0f, 1.0f); mMActor->setMotionBlendRatioForBck(unk168); - if (mLiveFlag & LIVE_FLAG_CLIPPED_OUT) { + if (checkLiveFlag(LIVE_FLAG_CLIPPED_OUT)) { unk16C->mPosition = mPosition; unk170->mPosition = mPosition; unk174->mPosition = mPosition; @@ -1303,8 +1316,8 @@ void TBossTelesa::calcRootMatrix() Mtx rotateMtx; MsMtxSetRotRPH(rotateMtx, mRotation.x, mRotation.y, mRotation.z); - PSMTXConcat(translateMtx, rotateMtx, translateMtx); - PSMTXCopy(translateMtx, mMActor->getModel()->getBaseTRMtx()); + MTXConcat(translateMtx, rotateMtx, translateMtx); + MTXCopy(translateMtx, mMActor->getModel()->getBaseTRMtx()); TTelesaSlot* slot = (TTelesaSlot*)unk184; if (slot) { @@ -1405,7 +1418,7 @@ void TBossTelesa::calcRootMatrix() void TBossTelesa::perform(u32 flags, JDrama::TGraphics* gfx) { if ((flags & 0x200) - && !(mLiveFlag & (LIVE_FLAG_DEAD | LIVE_FLAG_CLIPPED_OUT))) { + && !checkLiveFlag(LIVE_FLAG_DEAD | LIVE_FLAG_CLIPPED_OUT)) { if (mSpine->getCurrentNerve() == &TNerveBossTelesaDie::theNerve() && unk350) { mMActor->offMakeDL(); @@ -1431,7 +1444,7 @@ BOOL TBossTelesa::checkMessage(THitActor* actor, u32 message) { if (message == HIT_MESSAGE_TRAMPLE) { bool isMario; - if (actor->mActorType == (ACTOR_TYPE_PLAYER | 1)) + if (actor->mActorType == 0x80000001) isMario = true; else isMario = false; @@ -1455,7 +1468,7 @@ void TBossTelesa::checkHitObject(THitActor* actor) { unk380 = -1; - if ((actor->mActorType & ACTOR_TYPE_MASK) != ACTOR_TYPE_UNK40000000) + if ((actor->mActorType & 0xFFFF0000) != 0x40000000) return; if (mSpine->getCurrentNerve() != &TNerveBossTelesaPrepareSlot::theNerve()) return; @@ -1543,7 +1556,7 @@ void TBossTelesa::damageRecover() for (int i = 0; i < 20; ++i) { TLiveActor* actor = unk2A8[i]; - if (!(actor->mLiveFlag & LIVE_FLAG_DEAD)) { + if (!actor->checkLiveFlag(LIVE_FLAG_DEAD)) { if (actor->mHolder == nullptr) SMS_SendMessageToMario(actor, HIT_MESSAGE_UNK8); @@ -1556,7 +1569,7 @@ void TBossTelesa::damageRecover() for (int i = 0; i < 10; ++i) { TLiveActor* actor = unk2F8[i]; - if (!(actor->mLiveFlag & LIVE_FLAG_DEAD)) { + if (!actor->checkLiveFlag(LIVE_FLAG_DEAD)) { if (actor->mHolder == nullptr) SMS_SendMessageToMario(actor, HIT_MESSAGE_UNK8); @@ -1567,7 +1580,7 @@ void TBossTelesa::damageRecover() } actor = unk320[i]; - if (!(actor->mLiveFlag & LIVE_FLAG_DEAD)) { + if (!actor->checkLiveFlag(LIVE_FLAG_DEAD)) { ((TMapObjBase*)actor)->makeObjDead(); gpMarioParticleManager->emit(PARTICLE_MS_TLS_CHANGE, &actor->mPosition, 0, nullptr); @@ -1740,7 +1753,6 @@ void TBossTelesa::onAllCollision() offHitFlag(HIT_FLAG_NO_COLLISION); unk16C->offHitFlag(HIT_FLAG_NO_COLLISION); unk170->offHitFlag(HIT_FLAG_NO_COLLISION); - unk174->offHitFlag(HIT_FLAG_NO_COLLISION); } void TBossTelesa::offAllCollision() @@ -1748,7 +1760,6 @@ void TBossTelesa::offAllCollision() onHitFlag(HIT_FLAG_NO_COLLISION); unk16C->onHitFlag(HIT_FLAG_NO_COLLISION); unk170->onHitFlag(HIT_FLAG_NO_COLLISION); - unk174->onHitFlag(HIT_FLAG_NO_COLLISION); } const char** TBossTelesa::getBasNameTable() const { return btelesa_bastable; } @@ -1782,7 +1793,7 @@ void TBossTelesa::genAttacker() velocity.z = -50.0f; MsMtxSetRotRPH(rot, mRotation.x, mRotation.y - angleOffset + angleStep * i, mRotation.z); - PSMTXMultVec(rot, &velocity, &velocity); + MTXMultVec(rot, &velocity, &velocity); MsVECNormalize(&velocity, &velocity); velocity.y = 2.0f; @@ -1800,18 +1811,7 @@ void TBossTelesa::genAttacker() TMsRange itemRange(0.0f, 1.0f); f32 itemRoll = itemRange.rand(); if (itemRoll < mItemGenRate) { - bubble->unk198 = nullptr; - TMapObjBase* item = gpItemManager->makeObjAppear( - bubble->mPosition.x, bubble->mPosition.y, bubble->mPosition.z, - 0x20000008, true); - if (item && item->receiveMessage(bubble, HIT_MESSAGE_TAKE)) { - item->appear(); - item->mPosition = bubble->mPosition; - item->mVelocity.set(0.0f, 15.0f, 0.0f); - item->offLiveFlag(LIVE_FLAG_UNK10); - bubble->mHeldObject = item; - bubble->unk198 = item; - } + bubble->appendItem(); } else { TMsRange enemyRange(0.0f, 1.0f); f32 enemyRoll = enemyRange.rand(); @@ -1951,15 +1951,15 @@ void TBossTelesa::generateSlotItem() angleIndex = 0; } - PSMTXMultVec(rot, &dir, &dir); + MTXMultVec(rot, &dir, &dir); MsVECNormalize(&dir, &normalizedDir); Vec velocity; TMsRange fruitSpeedRange(6.0f, 10.0f); if (i == 0 || i == 4) { - ((TMapObjBase*)unk2F8[i])->makeObjAppeared(); - ((TMapObjBase*)unk2F8[i])->offLiveFlag(LIVE_FLAG_HIDDEN); + unk2F8[i]->makeObjAppeared(); + unk2F8[i]->offLiveFlag(LIVE_FLAG_HIDDEN); velocity.x = normalizedDir.x * fruitSpeedRange.rand(); velocity.y = -2.0f; @@ -1971,20 +1971,20 @@ void TBossTelesa::generateSlotItem() = normalizedDir.z * fruitSpeedRange.rand() * 2.0f; } - ((TMapObjBase*)unk2F8[i])->mVelocity = velocity; - ((TMapObjBase*)unk2F8[i])->offLiveFlag(LIVE_FLAG_UNK10); - ((TMapObjBase*)unk2F8[i])->mRotation.set(0.0f, 90.0f, 0.0f); + unk2F8[i]->mVelocity = velocity; + unk2F8[i]->offLiveFlag(LIVE_FLAG_UNK10); + unk2F8[i]->mRotation.set(0.0f, 90.0f, 0.0f); unk1AC[unk274] = unk2F8[i]; } else { - ((TMapObjBase*)unk2A8[i])->makeObjAppeared(); - ((TMapObjBase*)unk2A8[i])->offLiveFlag(LIVE_FLAG_HIDDEN); + unk2A8[i]->makeObjAppeared(); + unk2A8[i]->offLiveFlag(LIVE_FLAG_HIDDEN); velocity.x = normalizedDir.x * fruitSpeedRange.rand(); velocity.y = -2.0f; velocity.z = normalizedDir.z * fruitSpeedRange.rand(); - ((TMapObjBase*)unk2A8[i])->mVelocity = velocity; - ((TMapObjBase*)unk2A8[i])->offLiveFlag(LIVE_FLAG_UNK10); + unk2A8[i]->mVelocity = velocity; + unk2A8[i]->offLiveFlag(LIVE_FLAG_UNK10); unk1AC[unk274] = unk2A8[i]; } @@ -2019,7 +2019,7 @@ void TBossTelesa::generateSlotItem() MsMtxSetRotRPH(rot, mRotation.x, mRotation.y - itemAngleOffset + itemAngleStep * i, mRotation.z); - PSMTXMultVec(rot, &dir, &dir); + MTXMultVec(rot, &dir, &dir); MsVECNormalize(&dir, &dir); dir.y = 10.0f; @@ -2030,14 +2030,14 @@ void TBossTelesa::generateSlotItem() velocity.y = dir.y; velocity.z = dir.z * speed * itemSpeedRange.rand(); - TMapObjBase* item = gpItemManager->makeObjAppeared(0x2000000E); + TItem* item = (TItem*)gpItemManager->makeObjAppeared(0x2000000E); item->mPosition.x = rootMtx[0][3]; item->mPosition.y = rootMtx[1][3] - 250.0f; item->mPosition.z = rootMtx[2][3]; item->mVelocity = velocity; item->offLiveFlag(LIVE_FLAG_UNK10); item->mScaling.set(0.0f, 0.0f, 0.0f); - ((TItem*)item)->killByTimer(0x3C0); + item->killByTimer(0x3C0); unk1AC[unk274] = unk320[i]; unk1AC[unk274]->offLiveFlag(LIVE_FLAG_HIDDEN); @@ -2094,7 +2094,7 @@ void TBossTelesa::generateSlotItem() MsMtxSetRotRPH(rot, mRotation.x, mRotation.y - angleOffset + angleStep * i, mRotation.z); - PSMTXMultVec(rot, &dir, &dir); + MTXMultVec(rot, &dir, &dir); MsVECNormalize(&dir, &dir); dir.y = 2.0f; @@ -2111,7 +2111,7 @@ void TBossTelesa::generateSlotItem() enemy->mVelocity = velocity; enemy->mPosition.y += 10.0f; enemy->onLiveFlag(LIVE_FLAG_AIRBORNE); - PSMTXCopy(rootMtx, enemy->mMActor->unk4->unk20); + MTXCopy(rootMtx, enemy->mMActor->getModel()->getBaseTRMtx()); enemy->mMActor->calc(); enemy->initAttacker(this); } @@ -2134,7 +2134,7 @@ bool TBossTelesa::checkSlot() bool TBossTelesa::checkAllItemDead() { for (int i = 0; i < unk274; ++i) - if (!(unk1AC[i]->mLiveFlag & LIVE_FLAG_DEAD)) + if (!unk1AC[i]->checkLiveFlag(LIVE_FLAG_DEAD)) return false; return true; } @@ -2152,7 +2152,7 @@ void TBossTelesa::forceAllItemKill() unk1AC[i]->mPosition.set(zero, zero, zero); unk1AC[i]->onHitFlag(HIT_FLAG_NO_COLLISION); - if (!(unk1AC[i]->mLiveFlag & LIVE_FLAG_DEAD)) { + if (!unk1AC[i]->checkLiveFlag(LIVE_FLAG_DEAD)) { unk1AC[i]->kill(); gpMarioParticleManager->emit(PARTICLE_MS_TLS_CHANGE, &unk1AC[i]->mPosition, 0, nullptr); @@ -2202,9 +2202,7 @@ DEFINE_NERVE(TNerveBossTelesaDie, TLiveActor) if (boss->unk350 && boss->mHitPoints != 0) --boss->mHitPoints; - boss->onHitFlag(HIT_FLAG_NO_COLLISION); - boss->unk16C->onHitFlag(HIT_FLAG_NO_COLLISION); - boss->unk170->onHitFlag(HIT_FLAG_NO_COLLISION); + boss->offAllCollision(); if (boss->mHitPoints != 0) { if (boss->unk350) { @@ -2321,9 +2319,7 @@ DEFINE_NERVE(TNerveBossTelesaDie, TLiveActor) boss->onLiveFlag(LIVE_FLAG_UNK8); boss->offLiveFlag(TBossTelesa::LIVE_FLAG_UNK10000); boss->mHolder = nullptr; - boss->onHitFlag(HIT_FLAG_NO_COLLISION); - boss->unk16C->onHitFlag(HIT_FLAG_NO_COLLISION); - boss->unk170->onHitFlag(HIT_FLAG_NO_COLLISION); + boss->offAllCollision(); boss->stopAnmSound(); spine->reset(); return TRUE; @@ -2467,9 +2463,7 @@ DEFINE_NERVE(TNerveBossTelesaHide, TLiveActor) } if (boss->checkCurAnmEnd(0)) { - boss->onHitFlag(HIT_FLAG_NO_COLLISION); - boss->unk16C->onHitFlag(HIT_FLAG_NO_COLLISION); - boss->unk170->onHitFlag(HIT_FLAG_NO_COLLISION); + boss->offAllCollision(); SMSRumbleMgr->start(0x14, 0xF, (f32*)nullptr); boss->rouletteStart(); spine->pushAfterCurrent(&TNerveBossTelesaHideWait::theNerve()); @@ -2690,7 +2684,7 @@ DEFINE_NERVE(TNerveBossTelesaSpitSlotItem, TLiveActor) boss->unk368 = 0; for (int i = 0; i < boss->unk274; ++i) { TLiveActor* actor = boss->unk1AC[i]; - if (!(actor->mLiveFlag & LIVE_FLAG_DEAD) + if (!actor->checkLiveFlag(LIVE_FLAG_DEAD) && actor->mActorType != 0x2000000E && actor->mActorType != 0x20000002) actor->offHitFlag(HIT_FLAG_NO_COLLISION); @@ -2832,7 +2826,7 @@ DEFINE_NERVE(TNerveBossTelesaPrepareSlot, TLiveActor) } else { done = TRUE; for (int i = 0; i < boss->unk274; ++i) { - if (!(boss->unk1AC[i]->mLiveFlag & LIVE_FLAG_DEAD)) { + if (!(boss->unk1AC[i]->checkLiveFlag(LIVE_FLAG_DEAD))) { done = FALSE; break; } From fe7bed2c79ed7cc1b583d2628080af46bbd49f10 Mon Sep 17 00:00:00 2001 From: KakarotCake <61133727+KakarottoCake@users.noreply.github.com> Date: Sun, 23 Aug 2026 02:55:41 -0400 Subject: [PATCH 18/18] Enemy/bosstelesa: the three roulettes are an array unk178/unk17C/unk180 were three adjacent TRoulette* fields that four different sites already treated as an array, three of them by casting: ((TRoulette**)&unk178)[i]->setRollSp(unk184->unk1E4[i]); (&unk178)[found] = (TRoulette*)actor; Declaring `TRoulette* unk178[3]` says what those sites are doing and removes all three casts. The original almost certainly declared it this way, since indexing three separately-named pointers is not something the code would do by choice. No effect on the match: 61 of 100 functions byte-identical and 8672 bytes before and after, per-function percentages unchanged. mario.dol: OK. Co-Authored-By: Claude Opus 5 --- include/Enemy/BossTelesa.hpp | 4 +-- src/Enemy/bosstelesa.cpp | 55 ++++++++++++++++++------------------ 2 files changed, 28 insertions(+), 31 deletions(-) diff --git a/include/Enemy/BossTelesa.hpp b/include/Enemy/BossTelesa.hpp index 05977a4f7..8f24b6d28 100644 --- a/include/Enemy/BossTelesa.hpp +++ b/include/Enemy/BossTelesa.hpp @@ -158,9 +158,7 @@ class TBossTelesa : public TSpineEnemy { /* 0x16C */ TBossTelesaBody* unk16C; /* 0x170 */ TBossTelesaTongue* unk170; /* 0x174 */ TBossTelesaKillSmallEnemy* unk174; - /* 0x178 */ TRoulette* unk178; - /* 0x17C */ TRoulette* unk17C; - /* 0x180 */ TRoulette* unk180; + /* 0x178 */ TRoulette* unk178[3]; /* 0x184 */ TTelesaSlot* unk184; /* 0x188 */ JDrama::TViewObj* unk188; /* 0x18C */ u8 unk18C; diff --git a/src/Enemy/bosstelesa.cpp b/src/Enemy/bosstelesa.cpp index 94cd44713..aa38bb5b3 100644 --- a/src/Enemy/bosstelesa.cpp +++ b/src/Enemy/bosstelesa.cpp @@ -994,7 +994,7 @@ void TBossTelesa::loadAfter() else isRoulette = 0; if (isRoulette) { - (&unk178)[found] = (TRoulette*)actor; + unk178[found] = (TRoulette*)actor; found++; } } @@ -1188,9 +1188,9 @@ void TBossTelesa::moveObject() } if (mSpine->getCurrentNerve() == &TNerveBossTelesaFallDemo::theNerve()) { - if (unk178 && unk17C - && unk178->mPosition.y > unk17C->mPosition.y + 5.0f) { - unk184->mPosition = unk178->mPosition; + if (unk178[0] && unk178[1] + && unk178[0]->mPosition.y > unk178[1]->mPosition.y + 5.0f) { + unk184->mPosition = unk178[0]->mPosition; unk184->mPosition.y += 300.0f; } } @@ -1218,16 +1218,16 @@ void TBossTelesa::moveObject() JGeometry::TVec3 cameraDiff = *gpMarioPos; cameraDiff.sub(gpCamera->unk124); - unk19C = unk178->mPosition; + unk19C = unk178[0]->mPosition; unk19C.x += 0.67f * cameraDiff.x; unk19C.z += 0.67f * cameraDiff.z; int movingRoulettes = 0; - if (unk178->unk13C != 0.0f) + if (unk178[0]->unk13C != 0.0f) ++movingRoulettes; - if (unk17C->unk13C != 0.0f) + if (unk178[1]->unk13C != 0.0f) ++movingRoulettes; - if (unk180->unk13C != 0.0f) + if (unk178[2]->unk13C != 0.0f) ++movingRoulettes; switch (movingRoulettes) { @@ -1289,8 +1289,8 @@ void TBossTelesa::kill() MtxPtr TBossTelesa::getTakingMtx() { - unk278.set(unk178->mMActor->unk4->mNodeMatrices[1]); - unk278.mMtx[1][3] = unk178->mPosition.y - 120.0f; + unk278.set(unk178[0]->mMActor->unk4->mNodeMatrices[1]); + unk278.mMtx[1][3] = unk178[0]->mPosition.y - 120.0f; return unk278.mMtx; } @@ -1608,8 +1608,8 @@ void TBossTelesa::tongueHitWater() bool TBossTelesa::rouletteFall() { - TRoulette* roulette0 = (TRoulette*)unk178; - TRoulette* roulette1 = (TRoulette*)unk17C; + TRoulette* roulette0 = (TRoulette*)unk178[0]; + TRoulette* roulette1 = (TRoulette*)unk178[1]; if (roulette0->mPosition.y > roulette1->mPosition.y) { roulette0->mPosition.y -= 1.0f; @@ -1642,37 +1642,37 @@ bool TBossTelesa::rouletteFall() bool TBossTelesa::slotFall() { - if (unk184->mPosition.y > unk178->mPosition.y - 800.0f) { + if (unk184->mPosition.y > unk178[0]->mPosition.y - 800.0f) { unk184->mPosition.y -= 5.0f; return FALSE; } unk184->mPosition.y -= 1.0f; - if (unk184->mPosition.y < unk178->mPosition.y - 900.0f) { + if (unk184->mPosition.y < unk178[0]->mPosition.y - 900.0f) { int rolling = 0; - if (unk178->unk13C != 0.0f) + if (unk178[0]->unk13C != 0.0f) rolling = 1; - if (unk17C->unk13C != 0.0f) + if (unk178[1]->unk13C != 0.0f) ++rolling; - if (unk180->unk13C != 0.0f) + if (unk178[2]->unk13C != 0.0f) ++rolling; if (rolling != 3) rouletteStart(); } - if (unk184->mPosition.y < unk178->mPosition.y - 1100.0f) + if (unk184->mPosition.y < unk178[0]->mPosition.y - 1100.0f) return TRUE; - THitActor* switchActor = unk178->unk150; + THitActor* switchActor = unk178[0]->unk150; switchActor->mAttackRadius = 280.0f; switchActor->mAttackHeight = 100.0f; switchActor->mDamageRadius = 280.0f; switchActor->mDamageHeight = 100.0f; switchActor->calcEntryRadius(); - switchActor = unk17C->unk150; + switchActor = unk178[1]->unk150; switchActor->mAttackRadius = 280.0f; switchActor->mAttackHeight = 100.0f; switchActor->mDamageRadius = 280.0f; @@ -1855,15 +1855,15 @@ void TBossTelesa::rouletteStart() if (i == 0 || i == 2) direction = -direction; - f32 speed = speedRange.rand(); - ((TRoulette**)&unk178)[i]->unk144 = direction * (speed + hpSpeed); + f32 speed = speedRange.rand(); + unk178[i]->unk144 = direction * (speed + hpSpeed); speed = speedRange.rand(); unk184->unk1E4[i] = direction * (speed + hpSpeed); } for (int i = 0; i < 3; ++i) - ((TRoulette**)&unk178)[i]->setRollSp(unk184->unk1E4[i]); + unk178[i]->setRollSp(unk184->unk1E4[i]); SMSRumbleMgr->start(0x14, 0xf, (f32*)nullptr); gpCameraShake->startShake(CAM_SHAKE_MODE_UNK23, 1.0f); @@ -2299,15 +2299,14 @@ DEFINE_NERVE(TNerveBossTelesaDie, TLiveActor) } boss->forceAllItemKill(); - boss->unk178->unk144 = 0.0f; + boss->unk178[0]->unk144 = 0.0f; boss->unk184->unk1E4[0] = 0.0f; - boss->unk17C->unk144 = 0.0f; + boss->unk178[1]->unk144 = 0.0f; boss->unk184->unk1E4[1] = 0.0f; - boss->unk180->unk144 = 0.0f; + boss->unk178[2]->unk144 = 0.0f; boss->unk184->unk1E4[2] = 0.0f; for (int i = 0; i < 3; ++i) - ((TRoulette**)&boss->unk178)[i]->setRollSp( - boss->unk184->unk1E4[i]); + boss->unk178[i]->setRollSp(boss->unk184->unk1E4[i]); } if (boss->unk388 > 240) {