From 94ca1eb207483390b5c64f1261f57428242ff64b Mon Sep 17 00:00:00 2001 From: Amrit Bhogal Date: Thu, 12 Feb 2026 03:36:55 +0000 Subject: [PATCH 01/52] mario+marioactor 95% match --- include/Game/Player/Mario.hpp | 10 +- include/Game/Player/MarioActor.hpp | 8 +- include/Game/Player/MarioShadow.hpp | 14 +- src/Game/Player/Mario.cpp | 1016 +++++++++++++++++++++-- src/Game/Player/MarioActor.cpp | 1168 +++++++++++++++++++++++++++ 5 files changed, 2151 insertions(+), 65 deletions(-) diff --git a/include/Game/Player/Mario.hpp b/include/Game/Player/Mario.hpp index 5267a1de4..0b1b7b7eb 100644 --- a/include/Game/Player/Mario.hpp +++ b/include/Game/Player/Mario.hpp @@ -100,10 +100,10 @@ class Mario : public MarioModule { void updateSoundCode(); const TVec3f& getShadowNorm() const; const TVec3f& getAirGravityVec() const; - const TVec3f& getAirFrontVec() const; + TVec3f getAirFrontVec() const; const TVec3f* getGravityVec() const; void initAfterConst(); - void writeBackPhysicalVector(); + void writeBackPhyisicalVector(); void update(); void updateLookOfs(); void actionMain(); @@ -149,7 +149,7 @@ class Mario : public MarioModule { bool checkBaseTransPoint(); bool checkHeadPoint(); const TVec3f* calcShadowPos(); - void updateBinderInfo(); + bool updateBinderInfo(); bool isThroughWall(const Triangle*) const; void checkGround(); void getCameraCubeCode() const; @@ -160,8 +160,8 @@ class Mario : public MarioModule { void decDamageAfterTimer(); bool checkDamage(); u16 getDamageAfterTimer() const; - void damageFloorCheck(); - void damageWallCheck(); + bool damageFloorCheck(); + bool damageWallCheck(); void damagePolygonCheck(const Triangle*); void flipLarge(const TVec3f&); bool isEnableAddDamage() const; diff --git a/include/Game/Player/MarioActor.hpp b/include/Game/Player/MarioActor.hpp index e6b994cb7..e27c667ec 100644 --- a/include/Game/Player/MarioActor.hpp +++ b/include/Game/Player/MarioActor.hpp @@ -99,7 +99,7 @@ class MarioActor : public LiveActor { void updateBaseScaleMtx(); void getRealMtx(MtxPtr, const char*) const NO_INLINE; void getRealPos(const char*, TVec3f*) const; - void getGlobalJointMtx(const char*); + MtxPtr getGlobalJointMtx(const char*); void calcAnimInMovement(); void forceSetBaseMtx(MtxPtr); void calcAnim(); @@ -177,6 +177,7 @@ class MarioActor : public LiveActor { void calcViewMainModel(); void initFace(); void updateFace(); + void updateHand(); void draw() const override; void drawIndirect() const; void drawIndirectModel() const; @@ -209,6 +210,10 @@ class MarioActor : public LiveActor { void calcFogLighting(); void calcViewReflectionModel(); void calcViewSearchLight(); + void calcScreenBoxRange(); + void calcSpinEffect(); + void changeHandMaterial(); + void updateRasterScroll(); void updateDarkMask(u16); void resetPadSwing(); @@ -218,6 +223,7 @@ class MarioActor : public LiveActor { TVec3f& getGravityVector() const; const TVec3f& getAirGravityVec() const; void updateGravityVec(bool, bool); + void updateBaseMtxTeresa(MtxPtr); void changeTeresaAnimation(const char*, s32); MultiEmitter* playEffect(const char*); diff --git a/include/Game/Player/MarioShadow.hpp b/include/Game/Player/MarioShadow.hpp index 512f72dea..acb7defca 100644 --- a/include/Game/Player/MarioShadow.hpp +++ b/include/Game/Player/MarioShadow.hpp @@ -1,10 +1,20 @@ #pragma once #include "Game/NameObj/NameObj.hpp" +#include -class CollisionShadow : NameObj { +class CollisionShadow : public NameObj { public: CollisionShadow(f32, f32); + void setMode(u32); + void create(const TVec3f&, const TVec3f&, const TVec3f&); - u8 _C[0x34C - 0xC]; + u8 _C[0x18 - 0xC]; + f32 _18; + f32 _1C; + f32 _20; + u8 _24[0x3C - 0x24]; + TVec3f _3C; + TVec3f _48; + u8 _54[0x34C - 0x54]; }; diff --git a/src/Game/Player/Mario.cpp b/src/Game/Player/Mario.cpp index cab03d7da..1da1c5640 100644 --- a/src/Game/Player/Mario.cpp +++ b/src/Game/Player/Mario.cpp @@ -1,8 +1,12 @@ #include "Game/Player/Mario.hpp" +#include "Game/Animation/XanimeCore.hpp" +#include "Game/Enemy/KariKariDirector.hpp" #include "Game/LiveActor/Binder.hpp" +#include "Game/LiveActor/HitSensor.hpp" #include "Game/Map/HitInfo.hpp" #include "Game/Player/MarioAbyssDamage.hpp" #include "Game/Player/MarioActor.hpp" +#include "Game/Player/MarioAnimator.hpp" #include "Game/Player/MarioBlown.hpp" #include "Game/Player/MarioBump.hpp" #include "Game/Player/MarioClimb.hpp" @@ -36,10 +40,12 @@ #include "Game/Player/MarioSwim.hpp" #include "Game/Player/MarioTalk.hpp" #include "Game/Player/MarioTeresa.hpp" +#include "Game/Player/MarioState.hpp" #include "Game/Player/MarioWait.hpp" #include "Game/Player/MarioWall.hpp" #include "Game/Player/MarioWarp.hpp" #include "Game/Util/DirectDraw.hpp" +#include "JSystem/JMath/JMATrigonometric.hpp" #include "revolution/mtx.h" Mario::Mario(MarioActor* actor) : MarioModule(actor) { @@ -456,7 +462,7 @@ void Mario::updateMorphResetTimer() { return; } -/* void Mario::doExtraServices() { +void Mario::doExtraServices() { TVec3f stack_2c; TVec3f stack_20; MarioConst* pConst = mActor->mConst; @@ -464,19 +470,19 @@ void Mario::updateMorphResetTimer() { if (MR::diffAngleAbs(_43C, mFrontVec) < pTable->mFrontAngleFixMargin) { setFrontVec(_43C); } - if (!isPlayerModeBee() && !isPlayerModeTeresa() && mMovementStates._0 && _3BC > 600 && !MR::isNearZero(getGravityVec())) { - float f1 = MR::vecKillElement(_2D4, getGravityVec(), &stack_2c); - TVec3f stack_14(getGravityVec()); + if (!isPlayerModeBee() && !isPlayerModeTeresa() && mMovementStates.jumping && _3BC > 600 && !MR::isNearZero(*getGravityVec())) { + float f1 = MR::vecKillElement(mJumpVec, *getGravityVec(), &stack_2c); + TVec3f stack_14(*getGravityVec()); stack_14.scale(f1); - _2D4 = stack_14; + mJumpVec = stack_14; } - if (!isPlayerModeBee() && !isPlayerModeTeresa() && mMovementStates._0 && _3BC > 300) { + if (!isPlayerModeBee() && !isPlayerModeTeresa() && mMovementStates.jumping && _3BC > 300) { TVec3f* pTrans = getLastSafetyTrans(nullptr); - TVec3f stack_8(_130); + TVec3f stack_8(mPosition); stack_8 -= *pTrans; MR::isNearZero(mAirGravityVec); if (MR::vecKillElement(stack_8, mAirGravityVec, &stack_20) > 28000.0f) { - if (_488 > 2499.0f || mActor->isInZeroGravitySpot()) { + if (mVerticalSpeed > 2499.0f || mActor->isInZeroGravitySpot()) { mActor->forceKill(0); } } @@ -484,7 +490,7 @@ void Mario::updateMorphResetTimer() { if (getCurrentStatus() != 0 || _3C0 != 0 || mActor->_EA4) { _10._C = 0; } -} */ +} bool Mario::isEnableCheckGround() { return !isStatusActive(6); @@ -500,6 +506,279 @@ void Mario::setGroundNorm(const TVec3f& rVec) { } } +bool Mario::checkForceGrounding() { + if ((mMovementStates._17 || _10._15) && mMovementStates._1) { + if (MR::diffAngleAbs(_368, *_45C->getNormal(0)) < 0.7853982f) { + mDrawStates._0 = 1; + } + } + + if (mMovementStates._8 || mMovementStates._19 || mMovementStates._1A || mMovementStates._15 || mMovementStates._23 || mMovementStates.debugMode || + !mMovementStates._1) { + return false; + } + + if (!mDrawStates._0) { + TVec3f negGravity(_368); + negGravity = -negGravity; + + const TVec3f* pGravity = getGravityVec(); + f32 gravityDot = pGravity->dot(negGravity); + + TVec3f killAxis; + if (gravityDot > 0.99f) { + killAxis = *pGravity; + } else { + killAxis = negGravity; + } + + f32 vertical = MR::vecKillElement(mVelocity, killAxis, &mVelocity); + + TVec3f shadowDiff(mShadowPos); + shadowDiff -= mPosition; + + gravityDot *= shadowDiff.dot(killAxis); + + if (MR::isNearZero(gravityDot) || __fabsf(gravityDot) >= 30.0f) { + return false; + } + + if (mMovementStates._8) { + vertical = gravityDot; + } + + if (vertical > gravityDot) { + vertical = gravityDot; + } + + TVec3f add(killAxis); + add.scale(vertical); + mVelocity += add; + } else { + const TVec3f* pGravity = getGravityVec(); + TVec3f horizontalVel; + f32 verticalVel = MR::vecKillElement(mVelocity, *pGravity, &horizontalVel); + f32 horizontalMag = horizontalVel.length(); + + if (mVerticalSpeed != 0.0f && verticalVel > mVerticalSpeed) { + verticalVel = mVerticalSpeed; + } + + if (!mDrawStates._4) { + if (__fabsf(verticalVel) > horizontalMag) { + horizontalMag = 0.0f; + } else { + horizontalMag = MR::sqrt< f32 >((horizontalMag * horizontalMag) - (verticalVel * verticalVel)); + } + } + + MR::normalizeOrZero(&horizontalVel); + + TVec3f gravityComponent(*pGravity); + gravityComponent.scale(verticalVel); + + TVec3f horizontalComponent(horizontalVel); + horizontalComponent.scale(horizontalMag); + + TVec3f newVel(horizontalComponent); + newVel += gravityComponent; + mVelocity = newVel; + } + + return false; +} + +void Mario::fixHeadFrontVecByGravity() { + TVec3f oldUp(_368); + + if (MR::diffAngleAbs(mActor->mCamDirZ, mActor->_FA8) <= 0.7853982f) { + if (isStickOn()) { + mDrawStates.mIsUnderwater = 1; + _10._15 = 1; + _60D = 1; + _40E = 0; + } + } + + if (_3D0 != 0 || _3D2 != 0) { + mDrawStates._D = 0; + } + + if (!_60D && mActor->_370) { + mDrawStates._D = 0; + } + + if (isStatusActive(0x1E) || isStatusActive(0x1D)) { + _60D = 1; + } + + TVec3f oldHead(mHeadVec); + TVec3f upTarget = -(*getGravityVec()); + MR::normalize(&upTarget); + + MarioConstTable* pTable = mActor->mConst->getTable(); + f32 rotateSpeed; + if (upTarget.dot(mHeadVec) < 0.0f) { + if (mActor->_334 != 0) { + f32 blend = static_cast< f32 >(mActor->_334) / 15.0f; + rotateSpeed = blend * pTable->mRotateHeadVecSpeedByGravityM + (1.0f - blend) * pTable->mRotateHeadVecSpeedByGravityL; + } else { + rotateSpeed = pTable->mRotateHeadVecSpeedByGravityL; + } + } else if (upTarget.dot(mHeadVec) < 0.99f) { + rotateSpeed = pTable->mRotateHeadVecSpeedByGravityM; + } else { + rotateSpeed = pTable->mRotateHeadVecSpeedByGravityS; + } + + if (_60D && _71C) { + if ((mMovementStates._1 || !mMovementStates.jumping) && mDrawStates._D) { + MR::isNearZero(mAirGravityVec); + TVec3f airGrav(mAirGravityVec); + if (MR::normalizeOrZero(&airGrav)) { + return; + } + + airGrav = -airGrav; + + TVec3f side; + PSVECCrossProduct(&_290, &airGrav, &side); + if (MR::normalizeOrZero(&side)) { + return; + } + + TVec3f newSide; + PSVECCrossProduct(&airGrav, &side, &newSide); + if (MR::normalizeOrZero(&newSide)) { + return; + } + + _290 = newSide; + mSideVec = _290; + MR::normalize(&mSideVec); + + if (_410 < 30) { + _410++; + } + } + + TVec3f blendedHead; + if (!MR::vecBlendSphere(mHeadVec, upTarget, &blendedHead, rotateSpeed)) { + MR::vecRotAxis(mHeadVec, upTarget, mSideVec, &blendedHead, rotateSpeed); + } + + mHeadVec = blendedHead; + MR::normalize(&mHeadVec); + fixFrontVecFromUpSide(); + + _29C = oldUp; + _290 = mSideVec; + return; + } + + TVec3f axis; + PSVECCrossProduct(&mHeadVec, &upTarget, &axis); + + bool useFrontAxis = true; + if (MR::isNearZero(axis)) { + f32 frontDot = __fabsf(upTarget.dot(mFrontVec)); + f32 sideDot = __fabsf(upTarget.dot(mSideVec)); + if (sideDot < frontDot) { + useFrontAxis = false; + } + } else { + f32 sideDot = __fabsf(axis.dot(mSideVec)); + f32 frontDot = __fabsf(axis.dot(mFrontVec)); + if (frontDot < sideDot) { + useFrontAxis = false; + } + } + + if (useFrontAxis) { + TVec3f blendedHead; + if (!MR::vecBlendSphere(mHeadVec, upTarget, &blendedHead, rotateSpeed)) { + MR::vecRotAxis(mHeadVec, upTarget, mFrontVec, &blendedHead, rotateSpeed); + } + + mHeadVec = blendedHead; + MR::normalize(&mHeadVec); + setFrontVecKeepUp(mFrontVec); + } else { + TVec3f blendedHead; + if (!MR::vecBlendSphere(mHeadVec, upTarget, &blendedHead, rotateSpeed)) { + MR::vecRotAxis(mHeadVec, upTarget, mSideVec, &blendedHead, rotateSpeed); + } + + mHeadVec = blendedHead; + MR::normalize(&mHeadVec); + fixFrontVecFromUpSide(); + } + + pTable = mActor->mConst->getTable(); + if (MR::diffAngleAbs(_43C, mFrontVec) < pTable->mFrontAngleFixMargin) { + setFrontVec(_43C); + } + + if (MR::diffAngleAbs(mHeadVec, oldHead) < pTable->mHeadAngleFixMargin) { + mHeadVec = oldHead; + MR::normalize(&mHeadVec); + } + + bool keepOldSide = _60D || !mActor->_370; + if (keepOldSide && mDrawStates._D) { + TVec3f diffA(mHeadVec); + diffA -= _290; + if (!MR::isNearZero(diffA)) { + TVec3f diffB(mHeadVec); + diffB += _290; + if (!MR::isNearZero(diffB)) { + mSideVec = _290; + MR::normalize(&mSideVec); + + f32 angle = marioAcos(oldUp.dot(_29C)); + + TVec3f axisRot; + PSVECCrossProduct(&_29C, &oldUp, &axisRot); + MR::normalizeOrZero(&axisRot); + + if (!MR::isNearZero(axisRot)) { + TVec3f sum(_29C); + sum += oldUp; + if (!MR::isNearZero(sum)) { + TVec3f diff(_29C); + diff -= oldUp; + if (!MR::isNearZero(diff)) { + TMtx34f rotMtx; + PSMTXRotAxisRad(rotMtx.toMtxPtr(), &axisRot, angle); + PSMTXMultVec(rotMtx.toMtxPtr(), &mSideVec, &mSideVec); + _29C = oldUp; + _290 = mSideVec; + _60D = 0; + fixFrontVecFromUpSide(); + return; + } + } + } + + _60D = 1; + fixFrontVecFromUpSide(); + return; + } + } + } + + TVec3f fallbackSide; + PSVECCrossProduct(&oldUp, &_22C, &fallbackSide); + MR::normalizeOrZero(&fallbackSide); + if (!MR::isNearZero(fallbackSide)) { + _290 = fallbackSide; + } else { + _290 = mSideVec; + } + + _60D = 0; +} + // Nearly matches void Mario::createMtxDir(MtxPtr mtx, const TVec3f& rFront, const TVec3f& rUp, const TVec3f& rSide) { TVec3f side; @@ -569,7 +848,7 @@ bool Mario::isNonFixHeadVec() const { return mActor->_EA4; } -/* void Mario::createDirectionMtx(MtxPtr mtx) { +void Mario::createDirectionMtx(MtxPtr mtx) { TVec3f stack_20; TVec3f stack_14; TVec3f stack_8; @@ -604,7 +883,75 @@ bool Mario::isNonFixHeadVec() const { } createMtxDir(mtx, stack_8, stack_14, stack_20); MR::setMtxTrans(mtx, 0.0f, 0.0f, 0.0f); -} */ +} + +void Mario::createCorrectionMtx(MtxPtr mtx, TVec3f* pOut) { + pOut->zero(); + + if (isNonFixHeadVec()) { + PSMTXIdentity(mtx); + return; + } + + if (MR::isNearZero(_74C) && _754 == 0) { + PSMTXIdentity(mtx); + _750 = 0; + _74C = 0.0f; + return; + } + + if (_750 == 0 && _754 == 0) { + TMtx34f rotMtx; + TVec3f frontVec; + PSMTXRotAxisRad(rotMtx.toMtxPtr(), &mHeadVec, _74C); + PSMTXMultVec(rotMtx.toMtxPtr(), &mFrontVec, &frontVec); + setFrontVecKeepUp(frontVec); + _74C = 0.0f; + } + + TVec3f yAxis(0.0f, 1.0f, 0.0f); + if (mMovementStates._37 && !isStatusActive(0x22)) { + bool flip = false; + f32 frontDot = mFrontVec.dot(getCamDirX()); + f32 headDot = _1FC.dot(getCamDirY()); + if (headDot < 0.0f) { + frontDot = -frontDot; + } + + if (frontDot < 0.0f) { + if (_74C < 0.0f) { + flip = true; + } + } else if (frontDot > 0.0f) { + if (_74C > 0.0f) { + flip = true; + } + } + + if (flip) { + PSMTXRotAxisRad(mtx, &yAxis, -_74C); + } else { + PSMTXRotAxisRad(mtx, &yAxis, _74C); + } + } else { + PSMTXRotAxisRad(mtx, &yAxis, _74C); + } + + if (_754 != 0) { + f32 step = (3.1415927f - _74C) / static_cast< f32 >(_754); + _754--; + _750 = 0; + _74C += step; + } + + if (_750 != 0) { + _74C = _74C * static_cast< f32 >(_750 - 1) / static_cast< f32 >(_750); + _750--; + if (_750 == 0) { + setFrontVecKeepUp(mFrontVec); + } + } +} void Mario::slopeTiltHead(TVec3f* pVec) { if (mMovementStates._1) { @@ -970,6 +1317,105 @@ bool Mario::isInvincible() const { } } +void Mario::inputStick() { + mActor->getStickValue(&mStickPos.x, &mStickPos.y); + + if (_10._28) { + _10._28 = 0; + mStickPos.x = 0.0f; + mStickPos.y = 0.0f; + } + + mStickPos.x = MR::clamp(1.5f * mStickPos.x, -1.0f, 1.0f); + mStickPos.y = MR::clamp(1.5f * mStickPos.y, -1.0f, 1.0f); + + _38 = mStickPos.z; + + const f32 stickX = mStickPos.x; + const f32 stickY = mStickPos.y; + mStickPos.z = MR::sqrt< f32 >((stickX * stickX) + (stickY * stickY)); + mStickPos.z = MR::clamp(mStickPos.z, 0.0f, 1.0f); + + if (MR::isNearZero(mStickPos.z, 0.01f)) { + mStickPos.z = 0.0f; + } + + f32 angle = JMath::sAtanTable.atan2_(mStickPos.x, mStickPos.y); + angle = MR::normalizeAngleAbs(angle); + + MarioConstTable* pTable = mActor->mConst->getTable(); + const f32 halfPi = 1.5707964f; + const f32 margin = pTable->mStickAngleMargin; + + s32 quarter = 0; + while (angle > halfPi) { + angle -= halfPi; + quarter++; + } + + if (angle >= (halfPi - margin)) { + angle = halfPi; + } else if (angle <= margin) { + angle = 0.0f; + } else { + angle = (angle - margin) * (halfPi / (halfPi - (2.0f * margin))); + } + + f32 quantized = angle + (halfPi * static_cast< f32 >(quarter)); + + if (!_10._11) { + f32 absAngle = quantized; + if (absAngle < 0.0f) { + absAngle = -absAngle; + } + + f32 cosScaled = absAngle * 2607.5945f; + u16 cosIdx = static_cast< u16 >(cosScaled); + f32 cosVal = JMath::sSinCosTable.table[cosIdx & (JMath::TSinCosTable< 14, f32 >::LEN - 1)].b1; + mStickPos.x = mStickPos.z * cosVal; + + f32 sinVal; + if (quantized < 0.0f) { + f32 sinScaled = quantized * -2607.5945f; + u16 sinIdx = static_cast< u16 >(sinScaled); + sinVal = -JMath::sSinCosTable.table[sinIdx & (JMath::TSinCosTable< 14, f32 >::LEN - 1)].a1; + } else { + f32 sinScaled = quantized * 2607.5945f; + u16 sinIdx = static_cast< u16 >(sinScaled); + sinVal = JMath::sSinCosTable.table[sinIdx & (JMath::TSinCosTable< 14, f32 >::LEN - 1)].a1; + } + + mStickPos.y = mStickPos.z * sinVal; + } + + _524 = _528; + _528 = quantized; + + if (mMovementStates._37) { + stick2DadjustGround(mStickPos.x, mStickPos.y); + } + + if (_10._15) { + stick2Dadjust(mStickPos.x, mStickPos.y); + } + + if (mMovementStates._3A) { + update25Dmode(); + updateAxisFromMode(_6AC); + } + + if (_10._13) { + mStickPos.y = 0.0f; + } + + if (mStickPos.z <= 0.01f) { + mMovementStates._1D = 0; + } + + calcWorldPadDir(&mWorldPadDir, mStickPos.x, mStickPos.y, false); + MR::normalizeOrZero(&mWorldPadDir); +} + bool Mario::isCeiling() const { if (_4C8->isValid() == false) { return false; @@ -1074,18 +1520,16 @@ const TVec3f& Mario::getAirGravityVec() const { return mAirGravityVec; } -/* const TVec3f &Mario::getAirFrontVec() const { - TVec3f stack_8; - MR::vecKillElement(mFrontVec, mAirGravityVec, &stack_8); - TVec3f* stack_8_pointer = &stack_8; - MR::normalizeOrZero(stack_8_pointer); - if (stack_8_pointer) { +TVec3f Mario::getAirFrontVec() const { + TVec3f airFront; + MR::vecKillElement(mFrontVec, mAirGravityVec, &airFront); + + if (MR::normalizeOrZero(&airFront)) { return mFrontVec; } - else { - return *stack_8_pointer; - } -} */ + + return airFront; +} void Mario::initAfterConst() { MarioConst* pConst = mActor->mConst; @@ -1105,7 +1549,7 @@ void Mario::initAfterConst() { _728 = getAnimationStringPointer("ヒップドロップ着地"); } -/* void Mario::writeBackPhysicalVector() { +void Mario::writeBackPhyisicalVector() { TVec3f stack_ec; TVec3f stack_e0; TVec3f stack_d4; @@ -1117,22 +1561,22 @@ void Mario::initAfterConst() { TVec3f stack_14; TVec3f stack_8; if (_1C._10) { - TVec3f stack_104(_130); - addTrans(_160, nullptr); + TVec3f stack_104(mPosition); + addTrans(mVelocity, nullptr); if (calcDistToCeil(false) < 200.0f) { - _160.zero(); + mVelocity.zero(); stopWalk(); } - _130 = stack_104; + mPosition = stack_104; } if (mMovementStates._37 || _10._15) { - TVec3f stack_f8(_130); + TVec3f stack_f8(mPosition); stack_f8 -= _688; MR::vecKillElement(stack_f8, _6A0, &stack_f8); TVec3f stack_80(_688); stack_80 += stack_f8; - _130 = stack_80; - MR::vecKillElement(_160, _6A0, &_160); + mPosition = stack_80; + MR::vecKillElement(mVelocity, _6A0, &mVelocity); TVec3f stack_74(_694); stack_74 -= _688; float f29 = MR::vecKillElement(stack_74, _6A0, &stack_ec); @@ -1147,7 +1591,7 @@ void Mario::initAfterConst() { _688 += stack_ec; } fixPositionInTower(); - if (mMovementStates._0) { + if (mMovementStates.jumping) { bool rising = false; if (isRising()) { rising = true; @@ -1160,9 +1604,9 @@ void Mario::initAfterConst() { float zero = 0.0f; float SQRT2_2 = 0.707f; for (u32 i = 0; i < _578; i++) { - if (MR::vecKillElement(_160, *_57C[i]->getNormal(0), &stack_e0) < zero) { - _160 = stack_e0; - float f28 = MR::vecKillElement(_2D4, *_57C[i]->getNormal(0), &stack_d4); + if (MR::vecKillElement(mVelocity, *_57C[i]->getNormal(0), &stack_e0) < zero) { + mVelocity = stack_e0; + float f28 = MR::vecKillElement(mJumpVec, *_57C[i]->getNormal(0), &stack_d4); if (f28 <= 0.0f) { TVec3f stack_50(*_57C[i]->getNormal(0)); stack_50.scale(f28); @@ -1170,14 +1614,14 @@ void Mario::initAfterConst() { stack_5c.scale(0.5f); TVec3f stack_68(stack_d4); stack_68 += stack_5c; - _2D4 = stack_68; + mJumpVec = stack_68; } - else if (MR::diffAngleAbs(*getGravityVec(), _2D4) < PI_30) { + else if (MR::diffAngleAbs(*getGravityVec(), mJumpVec) < PI_30) { MR::vecKillElement(*_57C[i]->getNormal(0), *getGravityVec(), &stack_c8); - float _2D4Mag = PSVECMag(&_2D4); + float mJumpVecMag = PSVECMag(&mJumpVec); MR::normalizeOrZero(&stack_c8); - _2D4 += stack_c8; - _2D4.setLength(_2D4Mag); + mJumpVec += stack_c8; + mJumpVec.setLength(mJumpVecMag); } if (rising) { if (_57C[i]->getNormal(0)->dot(*getGravityVec()) > SQRT2_2) { @@ -1201,30 +1645,30 @@ void Mario::initAfterConst() { else if (isSwimming() && !mMovementStates._22) { float SQRT2_2 = 0.707f; for (u32 i = 0; i < _578; i++) { - if (MR::vecKillElement(_160, *_57C[i]->getNormal(0), &stack_b0) < 0.0f) { - _160 = stack_b0; - float f28 = MR::vecKillElement(mSwim->_A0, *_57C[i]->getNormal(0), &mSwim->_A0); + if (MR::vecKillElement(mVelocity, *_57C[i]->getNormal(0), &stack_b0) < 0.0f) { + mVelocity = stack_b0; + float f28 = MR::vecKillElement(mSwim->mKnockbackVel, *_57C[i]->getNormal(0), &mSwim->mKnockbackVel); TVec3f stack_20(*_57C[i]->getNormal(0)); stack_20.scale(f28); TVec3f stack_2c(stack_20); stack_2c.scale(0.5f); - mSwim->_A0 += stack_2c; + mSwim->mKnockbackVel += stack_2c; } } } else if (!_1C._B && mActor->_288.dot(_368) < 0.707f && MR::isNearZero(mActor->_288)) { TVec3f stack_a4(mActor->_288); MR::normalizeOrZero(&stack_a4); - float f2 = MR::vecKillElement(_160, stack_a4, &stack_98); + float f2 = MR::vecKillElement(mVelocity, stack_a4, &stack_98); if (f2 < 0.0f) { - _160 = stack_98; + mVelocity = stack_98; MR::normalizeOrZero(&stack_a4); float f1 = 1.0f - MR::clamp((-stack_a4.dot(mFrontVec)-0.3f) * 1.4285715f, 0.0f, 1.0f); if (!mMovementStates._8 && f1 < 0.1f) { if (mMovementStates._1A) { TVec3f stack_14(getSideWallNorm()); stack_14.scale(-f2); - _160 += stack_14; + mVelocity += stack_14; } else { int s28 = mActor->mBinder->mPlaneNum; @@ -1246,13 +1690,179 @@ void Mario::initAfterConst() { } } +void Mario::update() { + OSGetTime(); + updateAndClearStrideParameter(); + checkKeyLock(); + + if (!(mMovementStates.jumping && mMovementStates._B) && _728 && isAnimationRun(_728)) { + mMovementStates.jumping = 1; + mMovementStates._14 = 1; + } + + updateCubeCode(); + + bool hasBind = updateBinderInfo(); + mMovementStates._7 = hasBind; + + checkEnforceMove(); + _A8C[0] = mVelocity; + + if (!isStatusActive(0x16) && !isStatusActive(0x5)) { + checkBaseTransPoint(); + checkHeadPoint(); + } + + if (mMovementStates._F && _544 > 1) { + createAtField(true, 150.0f); + } else { + createAtField(false, 40.0f); + } + + _72C = calcDistToCeil(true); + _1C._F = _72C < 160.0f; + if (_1C._F && _4C8->isValid()) { + damagePolygonCheck(_4C8); + } + + if (MR::getKarikariClingNum() != 0) { + _1C_WORD |= 0x04000000; + } + + OSGetTime(); + f32 wallDist = 80.0f; + if (isSwimming()) { + wallDist = 90.0f; + } + checkAllWall(mActor->_2A0, wallDist); + + OSGetTime(); + updateGroundInfo(); + OSGetTime(); + + if (mMovementStates._1 && !(mMovementStates.jumping && mMovementStates._B)) { + if (damageFloorCheck()) { + writeBackPhyisicalVector(); + return; + } + + saveLastSafetyTrans(); + if (isCurrentShadowFloorDangerAction()) { + TVec3f diff(mShadowPos); + diff -= mGroundPos; + MR::isNearZero(mAirGravityVec); + + TVec3f killed; + f32 element = MR::vecKillElement(diff, mAirGravityVec, &killed); + if (element <= 5.0f && diff.dot(mFrontVec) > 0.0f) { + mDrawStates_WORD |= 0x00200000; + diff.setLength(5.0f); + addVelocity(diff); + } + } + } + + mDrawStates_WORD |= 0x00008000; + if (damageWallCheck()) { + return; + } + mDrawStates_WORD &= ~0x00008000; + + OSGetTime(); + if (checkPressDamage()) { + return; + } + + OSGetTime(); + if (checkSliderMode()) { + startSlider(); + } + + checkAndTryForceJump(); + if (mMovementStates._2E) { + return; + } + + if (checkStartSwim()) { + writeBackPhyisicalVector(); + return; + } + + if (!mMovementStates._22) { + check2DMode(); + } + + _898 = 0; + if (!mMovementStates.debugMode && MR::testFpViewStartTrigger()) { + if (MR::isPossibleToShiftToFirstPersonCamera()) { + tryFpViewMode(); + } else if (!MR::isDemoActive()) { + if (!MR::isEqualStageName("EpilogueDemoStage")) { + MR::startSystemSE("SE_SY_CAMERA_NG", -1, -1); + } + _898 = 1; + } + } + + inputStick(); + checkLockOnHoming(); + + _A8C[1] = mVelocity; + actionMain(); + _A8C[3] = mVelocity; + + calcFrontFloor(); + + if (mMovementStates._23 && mMovementStates._1 && mMovementStates._24 && isSlipPolygon(_460)) { + const TVec3f* pNormal = _460->getNormal(0); + f32 removed = MR::vecKillElement(mVelocity, *pNormal, &mVelocity); + TVec3f diff(_368); + diff -= *pNormal; + TVec3f half(diff); + half.scale(0.5f); + removed = __fabsf(removed); + TVec3f add(half); + add.scale(removed); + mVelocity += add; + } + + _A8C[4] = mVelocity; + + tryPushToVelocity(); + powerAreaMove(); + powerRailMove(); + + _A8C[5] = mVelocity; + + addVelocity(mVelocityAfter); + _A8C[6] = mVelocity; + + checkForceGrounding(); + _A8C[7] = mVelocity; + + checkStep(); + checkBump(); + doCubeWarp(); + + if (isSwimming()) { + checkBaseTransBall(); + } + + doSpinPunchAroundPolygons(); + _A8C[8] = mVelocity; + + writeBackPhyisicalVector(); + updateTimers(); + doExtraServices(); +} + void Mario::actionMain() { - if (!mMovementStates._16) { + if (!mMovementStates.debugMode) { if (checkDamage() == false) { if (_97C) { sendStateMsg(2); } - else if (mMovementStates._0) { + else if (mMovementStates.jumping) { procJump(false); checkTornado(); checkHang(); @@ -1269,7 +1879,7 @@ void Mario::actionMain() { } } if (!mMovementStates._23) { - _1A8 = _160; + _1A8 = mVelocity; _3C2 = 0; _280 = 0.0f; _284.zero(); @@ -1280,8 +1890,8 @@ void Mario::actionMain() { if (_3C4 != 0) { _3C4--; } - _A8C[2] = _160; - if (mMovementStates._1 && !mMovementStates._0) { + _A8C[2] = mVelocity; + if (mMovementStates._1 && !mMovementStates.jumping) { if (isEnableSlopeMove()) { slopeMove(); } @@ -1299,16 +1909,16 @@ void Mario::actionMain() { beeMarioOnGround(); checkSpecialWaitAnimation(); if (!mDrawStates._16) { - retainMoveDir(_1C0.x, _1C0.y, nullptr); + retainMoveDir(mStickPos.x, mStickPos.y, nullptr); } } } -/* void Mario::updateGroundInfo() { +void Mario::updateGroundInfo() { checkMap(); if (isEnableCheckGround()) { bool b1 = false; - if (!mMovementStates._0 && !mMovementStates._1) { + if (!mMovementStates.jumping && !mMovementStates._1) { b1 = true; } checkGround(); @@ -1323,8 +1933,8 @@ void Mario::actionMain() { changeAnimation(nullptr, "基本"); } if (!isStatusActive(0x13)) { - if (!isStatusActive(0x13) && !mMovementStates._1 && mMovementStates._3E == 1 && _2D4.dot(Mario::getGravityVec()) > 0.0f - && _2D4.dot(*_45C->getNormal(0)) < 0.0f && _1FC.dot(Mario::getGravityVec()) > 0.0f && _488 < 170.0f) { + if (!isStatusActive(0x13) && !mMovementStates._1 && mMovementStates._3E == 1 && mJumpVec.dot(*Mario::getGravityVec()) > 0.0f + && mJumpVec.dot(*_45C->getNormal(0)) < 0.0f && _1FC.dot(*Mario::getGravityVec()) > 0.0f && mVerticalSpeed < 170.0f) { mMovementStates._1 = 1; setGroundNorm(*_45C->getNormal(0)); setTrans(mShadowPos, nullptr); @@ -1334,7 +1944,7 @@ void Mario::actionMain() { updateCameraPolygon(); if (mMovementStates._1) { mMovementStates._29 = 0; - if (_43A == 0 && isSlipPolygon(_464)) { + if (_43A == 0 && isSlipPolygon(mGroundPolygon)) { mDrawStates._C = 1; } } @@ -1346,7 +1956,271 @@ void Mario::actionMain() { updateOnSand(); updateOnWater(); updateOnPoison(); -} */ +} + +bool Mario::postureCtrl(MtxPtr mtx) { + TVec3f oldHeadUp(_1FC); + TVec3f targetHeadUp(mHeadVec); + + MarioConstTable* pTable = mActor->mConst->getTable(); + f32 blendRatio = pTable->mHeadRotateRatio; + + if (mMovementStates._1 && !isSlipFloorCode(_960)) { + if (_71C < 3) { + const TVec3f* pGroundNormal = mGroundPolygon->getNormal(0); + f32 angle = calcAngleD(*pGroundNormal); + if (angle < 45.0f) { + MR::isNearZero(mAirGravityVec); + targetHeadUp = -mAirGravityVec; + } else { + f32 blend = (angle - 45.0f) / 60.0f; + MR::isNearZero(mAirGravityVec); + TVec3f negGravity = -mAirGravityVec; + MR::vecBlendSphere(negGravity, targetHeadUp, &targetHeadUp, blend); + } + } else { + MR::isNearZero(mAirGravityVec); + TVec3f gravity = -*getGravityVec(); + gravity -= mAirGravityVec; + targetHeadUp = gravity; + MR::normalizeOrZero(&targetHeadUp); + } + } + + if (isAnimationRun("坂すべり上向きうつぶせ", 2)) { + targetHeadUp = _368; + } + + if (isStatusActive(0x1C)) { + if (isAnimationRun("特殊ウエイト1A")) { + f32 frame = getAnimator()->getFrame(); + f32 blend; + if (frame > 290.0f) { + blend = 1.0f; + } else if (frame > 260.0f) { + blend = 0.5f + 0.5f * ((frame - 260.0f) / 30.0f); + } else { + blend = 0.5f * (frame / 260.0f); + } + + TVec3f gravity = -_374; + MR::vecBlendSphere(gravity, targetHeadUp, &targetHeadUp, blend); + } else if (_1C._13 && _1C._14) { + targetHeadUp = -_374; + } + } + + if (!isSwimming()) { + if (isAnimationRun("水泳ジェット") || isAnimationRun("水泳スピン移動") || isAnimationRun("リングダッシュ") || isAnimationRun("水泳スピンジャンプ")) { + MR::vecBlendSphere(mHeadVec, mJumpVec, &targetHeadUp, 0.1f); + if (MR::normalizeOrZero(&targetHeadUp)) { + targetHeadUp = mHeadVec; + } + mDrawStates_WORD |= 0x00004000; + } + } + + calcTornadoTilt(); + slopeTiltHead(&targetHeadUp); + + isStatusActive(0x1D); + + f32 angle = MR::diffAngleAbs(oldHeadUp, targetHeadUp); + if (angle > pTable->mHeadAngleFixMargin) { + if (!MR::vecBlendSphere(oldHeadUp, targetHeadUp, &oldHeadUp, blendRatio)) { + TMtx34f rotMtx; + PSMTXRotAxisRad(rotMtx.toMtxPtr(), &mSideVec, 0.1f); + PSMTXMultVecSR(rotMtx.toMtxPtr(), &oldHeadUp, &oldHeadUp); + } + } + + if (!MR::normalizeOrZero(&oldHeadUp)) { + _1FC = oldHeadUp; + } + + return false; +} + +void Mario::createAngleMtx(MtxPtr mtx, bool forceNoFix) { + if (!isNonFixHeadVec() && !forceNoFix && !mMovementStates._22) { + fixHeadFrontVecByGravity(); + } + + if (updatePosture(mtx)) { + return; + } + + createDirectionMtx(mtx); + + TVec3f headUp(_1FC); + TVec3f sideVec(mSideVec); + TVec3f frontVec(mFrontVec); + + PSMTXConcat(_C4, mtx, mtx); + + HitSensor* pSensor = reinterpret_cast< HitSensor* >(mActor->_470); + if (isAnimationRun("投げ")) { + pSensor = reinterpret_cast< HitSensor* >(mActor->_474); + } + if (mActor->isPunching()) { + pSensor = mActor->_924; + } + + TVec3f sensorPos; + if (pSensor) { + sensorPos = pSensor->mPosition; + } + + if (pSensor) { + TVec3f toSensor(sensorPos); + toSensor -= mPosition; + + TVec3f sensorDir(toSensor); + MR::normalizeOrZero(&sensorDir); + if (MR::isNearZero(sensorDir)) { + return; + } + + TVec3f noUpDir; + MR::vecKillElement(sensorDir, headUp, &noUpDir); + if (MR::normalizeOrZero(&noUpDir)) { + return; + } + + f32 angle = JMAAcosRadian(noUpDir.dot(frontVec)); + + TVec3f cross; + PSVECCrossProduct(&frontVec, &noUpDir, &cross); + if (cross.dot(headUp) < 0.0f) { + angle = -angle; + } + + f32 maxAngle = 0.1f * static_cast< f32 >(_412); + if (maxAngle > 1.0471976f) { + maxAngle = 1.0471976f; + } + angle = MR::clamp(angle, -maxAngle, maxAngle); + + _58.x = angle; + _58.y = 0.0f; + _58.z = 0.0f; + MR::orderRotateMtx(0, _58, _64); + + TVec3f invAngle = -_58; + MR::orderRotateMtx(0, invAngle, _94); + _12C = 0x10; + } else { + if (_12C != 0) { + _12C--; + } + + _58.x *= 0.8f; + _58.y = 0.0f; + _58.z *= 0.8f; + + MR::orderRotateMtx(0, _58, _64); + + TVec3f invAngle = -_58; + MR::orderRotateMtx(0, invAngle, _94); + } +} + +void Mario::updateLookOfs() { + TVec3f lookOfs; + lookOfs.zero(); + + if (isStatusActive(4)) { + return; + } + + if (mActor->_934) { + MR::vecBlend(_13C, lookOfs, &_13C, 0.3f); + } + + if (_97C == nullptr) { + if (isAnimationRun("壁押し")) { + TVec3f wallDiff(_4E8); + wallDiff -= mPosition; + + TVec3f noHead; + MR::vecKillElement(wallDiff, mHeadVec, &noHead); + + f32 dist = PSVECMag(&noHead); + TVec3f wallNormal(*mFrontWallTriangle->getNormal(0)); + wallNormal.scale(dist - 35.0f); + lookOfs = wallNormal; + } + } else if (_97C->mStatusId == 6) { + TVec3f antiGravity = -*getGravityVec(); + antiGravity.scale(mSwim->mSurfaceOffset); + lookOfs += antiGravity; + } + + if (mMovementStates._1 && !mMovementStates.jumping) { + if (mVerticalSpeed > 5.0f && mVerticalSpeed < 50.0f && !isCurrentShadowFloorDangerAction()) { + TVec3f groundDiff(mGroundPos); + groundDiff -= mShadowPos; + MR::normalizeOrZero(&groundDiff); + + if (groundDiff.dot(_368) < 0.1f) { + TVec3f grav(*getGravityVec()); + grav.scale(mVerticalSpeed); + lookOfs += grav; + } else { + TVec3f moveDiff(mGroundPos); + moveDiff -= mPosition; + TVec3f noGravity; + f32 gravityDist = MR::vecKillElement(moveDiff, *getGravityVec(), &noGravity); + TVec3f grav(*getGravityVec()); + grav.scale(gravityDist); + lookOfs += grav; + } + } + } + + TVec3f headOfs; + headOfs.zero(); + if (_735 != 0) { + f32 scale = static_cast< f32 >(_735); + + TVec3f grav(*getGravityVec()); + grav.scale(scale); + grav.scale(0.00390625f); + grav.scale(120.0f); + headOfs = grav; + + TVec3f up = -_1FC; + up.scale(scale); + up.scale(0.00390625f); + up.scale(120.0f); + headOfs = up; + } + + f32 blend = 0.2f; + if (!isUseSimpleGroundCheck()) { + if (getAnimator()->isLandingAnimationRun()) { + blend = 0.01f; + } else if (_71C == 0 && _278 < 0.2f && isBlendWaitGround()) { + f32 lookMag = PSVECMag(&lookOfs); + f32 currMag = PSVECMag(&_148); + if (currMag > lookMag) { + blend = 0.5f; + } else { + blend = 300.0f * static_cast< f32 >(_3CE); + if (blend <= 0.2f) { + blend = 0.2f; + } + } + } + } + + MR::vecBlend(_148, lookOfs, &_148, blend); + MR::vecBlend(_154, headOfs, &_154, 0.2f); + + TVec3f sum(_148); + sum += _154; + _13C = sum; +} // conditionals won't behave const TVec3f* Mario::getGravityVec() const { @@ -1392,3 +2266,31 @@ void Mario::touchWater() { mMorphResetTimer = 10; } } + +namespace NrvMarioActor { +INIT_NERVE(MarioActorNrvWait); +INIT_NERVE(MarioActorNrvGameOver); +INIT_NERVE(MarioActorNrvGameOverAbyss); +INIT_NERVE(MarioActorNrvGameOverAbyss2); +INIT_NERVE(MarioActorNrvGameOverFire); +INIT_NERVE(MarioActorNrvGameOverBlackHole); +INIT_NERVE(MarioActorNrvGameOverNonStop); +INIT_NERVE(MarioActorNrvGameOverSink); +INIT_NERVE(MarioActorNrvTimeWait); +INIT_NERVE(MarioActorNrvNoRush); +} // namespace NrvMarioActor + +XjointTransform* XanimeCore::getJointTransform(u32 idx) { + if (mTransformList == nullptr) { + return nullptr; + } + return &mTransformList[idx]; +} + +void MarioState::draw3D() const { +} + +template <> +bool TriangleFilterDelegator< Mario >::isInvalidTriangle(const Triangle* pTriangle) const { + return (mParent->*mFunc)(pTriangle); +} diff --git a/src/Game/Player/MarioActor.cpp b/src/Game/Player/MarioActor.cpp index 84576c95d..d9b33ccae 100644 --- a/src/Game/Player/MarioActor.cpp +++ b/src/Game/Player/MarioActor.cpp @@ -4,6 +4,7 @@ #include "Game/Gravity.hpp" #include "Game/LiveActor/Binder.hpp" #include "Game/LiveActor/HitSensor.hpp" +#include "Game/Player/J3DModelX.hpp" #include "Game/Map/CollisionParts.hpp" #include "Game/Map/HitInfo.hpp" #include "Game/Map/WaterInfo.hpp" @@ -12,6 +13,7 @@ #include "Game/Player/MarioEffect.hpp" #include "Game/Player/MarioHolder.hpp" #include "Game/Player/MarioMessenger.hpp" +#include "Game/Player/ModelHolder.hpp" #include "Game/Player/MarioNullBck.hpp" #include "Game/Player/MarioParts.hpp" #include "Game/Player/MarioShadow.hpp" @@ -22,7 +24,10 @@ #include "Game/Util/CameraUtil.hpp" #include "Game/Util/FootPrint.hpp" #include "JSystem/JAudio2/JAIAudible.hpp" +#include "JSystem/JGeometry/TMatrix.hpp" #include "JSystem/JMath/JMath.hpp" +#include "JSystem/JMath/JMATrigonometric.hpp" +#include "JSystem/JUtility/JUTVideo.hpp" bool gIsLuigi; @@ -226,6 +231,10 @@ MarioActor::MarioActor(const char* pName) : LiveActor(pName), _1B0(0xFFFFFFFF) { _1E0 = false; } +MarioActor::~MarioActor() { + delete mMario; +} + static f32 BASE_ROTATION = 0.0f; void MarioActor::init(const JMapInfoIter& rInfo) { @@ -465,6 +474,11 @@ void MarioActor::changeNullAnimation(const char* pName, s8 num) { _B92 = num; } +void MarioActor::clearNullAnimation(s8 num) { + _B92 = num; + mNullAnimation->kill(); +} + bool MarioActor::isStopNullAnimation() const { if (!MR::isBckStopped(mNullAnimation)) { return MR::isDead(mNullAnimation); @@ -630,6 +644,36 @@ bool MarioActor::isJumpRising() const { return ret; } +bool MarioActor::isPunching() const { + if (mMario->isStatusActive(0x11)) { + return true; + } + if (mMario->mSwim->mSpinTimer || mMario->mSwim->mSpinDashTimer) { + return true; + } + if (_3E5) { + return true; + } + if (!mMario->isAnimationTerminate(nullptr)) { + if (mMario->isAnimationRun("空中ひねり")) { + return true; + } + if (mMario->isAnimationRun("アイスひねり")) { + return true; + } + if (mMario->isAnimationRun("アイスひねり空中")) { + return true; + } + if (mMario->isAnimationRun("アイスひねり静止")) { + return true; + } + if (mMario->isAnimationRun("アイスひねり移動")) { + return true; + } + } + return false; +} + bool MarioActor::isItemSwinging() const { if (mMario->isAnimationRun("テニスショット左") || mMario->isAnimationRun("テニスショット右") || mMario->isAnimationRun("テニスショット中")) { return true; @@ -670,6 +714,54 @@ bool MarioActor::isSleeping() const { return ret; } +bool MarioActor::isRefuseTalk() const { + if (!isEnableNerveChange()) { + return true; + } + if (mMario->isStatusActive(0x1C)) { + return true; + } + if (mMario->isStatusActive(0x5)) { + return true; + } + if (mMario->isStatusActive(0x13)) { + return true; + } + if (mMario->isDamaging()) { + return true; + } + if (mMario->_420 != 0) { + return true; + } + if (mMario->isPlayerModeTeresa()) { + if (_B94 != 0) { + return true; + } + if (mMario->mMovementStates.jumping) { + return true; + } + if (!mMario->mMovementStates._1) { + return true; + } + if (mMario->_3CE < 5) { + return true; + } + if (mMario->mDrawStates._4) { + return true; + } + if (mMario->_1C._15) { + return true; + } + if (mMario->_3D2 != 0) { + return true; + } + } + if (_424 != nullptr) { + return true; + } + return _480; +} + bool MarioActor::isDebugMode() const { return getMovementStates().debugMode; } @@ -1663,3 +1755,1079 @@ void MarioActor::setPunchHitTimer(u8 punchHitTime) { _944 = punchHitTime; } + +void MarioActor::getRealPos(const char* pName, TVec3f* pPos) const { + TMtx34f mtx; + getRealMtx(mtx.toMtxPtr(), pName); + MR::extractMtxTrans(mtx.toMtxPtr(), pPos); +} + +MtxPtr MarioActor::getGlobalJointMtx(const char* pName) { + const u16 jointIndex = MR::getJointIndex(this, pName); + TMtx34f* jointMtx = static_cast< TMtx34f* >(_C28); + getRealMtx(jointMtx[jointIndex].toMtxPtr(), pName); + return jointMtx[jointIndex].toMtxPtr(); +} + +void MarioActor::calcAnimInMovement() { + if (mHealth != 0) { + if (mMario->isDamaging() || mMario->getDamageAfterTimer() != 0) { + _1AA = 0; + _1A8++; + } + } else if (_1AA != 0) { + _1AA--; + } + + _1C0 = true; + updateBlink(); + calcSpinEffect(); + + if (mCurrModel == 4) { + _9C8->calcAnim(); + _A50->calcAnim(); + _A54->calcAnim(); + + f32 brkFrame = MR::getBrkFrame(_9C8); + MR::setBrkFrame(_A50, brkFrame); + MR::setBrkFrame(_A54, MR::getBrkFrame(_9C8)); + } + + if (_3DA != 0) { + _3DA--; + _1D4 = 10.0f; + + if (_3DA == 0) { + MR::endDemo(this, "マリオスーパー化"); + MR::releaseAnimFrame(this); + _1D4 = 0.0f; + MR::explainLifeUpIfAtFirst(); + } + } + + if (_3D8 != 0) { + if (mPlayerMode == 6) { + const MarioConstTable* pTable = mConst->getTable(); + if (mMario->mVerticalSpeed < pTable->mTeresaWaitHeight) { + mPosition -= getGravityVec(); + } + } + + bool isFirst = true; + switch (mPlayerMode) { + case 4: + isFirst = MR::isOnGameEventFlagBeeMarioAtFirst(); + break; + case 6: + isFirst = MR::isOnGameEventFlagTeresaMarioAtFirst(); + break; + case 5: + isFirst = MR::isOnGameEventFlagHopperMarioAtFirst(); + break; + case 2: + isFirst = MR::isOnGameEventFlagFireMarioAtFirst(); + break; + case 3: + isFirst = MR::isOnGameEventFlagIceMarioAtFirst(); + break; + case 7: + isFirst = MR::isOnGameEventFlagFlyingMarioAtFirst(); + break; + default: + break; + } + + if (!isFirst) { + struct CameraFrontTarget { + u8 _00[0x24]; + const LiveActor* mActor; + }; + + const LiveActor* pTarget = reinterpret_cast< CameraFrontTarget* >(_4A4)->mActor; + TVec3f front; + MR::calcFrontVec(&front, pTarget); + mMario->setFrontVecKeepUp(front); + + if (_336 == 0) { + MR::zoomInTargetGameCamera(); + CameraTargetArg arg(nullptr, nullptr, nullptr, this); + MR::startGlobalEventCamera("変身初出カメラ", arg, 0x3C); + + TVec3f targetPos(_2A0); + f32 cameraDist = 500.0f; + if (mPlayerMode == 6) { + cameraDist = 700.0f; + } + + const Mario::MovementStates& states = mMario->getMovementStates(); + if (states._B && !states._1) { + targetPos += mMario->mJumpVec; + } + + TVec3f camOffset(front); + camOffset.scale(cameraDist); + TVec3f cameraPos(targetPos); + cameraPos += camOffset; + TVec3f up = -_240; + MR::setProgrammableCameraParam("変身初出カメラ", targetPos, cameraPos, up, true); + } + + _336 = 1; + } + + _3D8--; + if (_3D8 == 0) { + if (mTransforming) { + MR::endDemo(this, "マリオ変身"); + mTransforming = false; + } + + MR::releaseAnimFrame(this); + _3DE = 1; + + switch (mPlayerMode) { + case 4: + MR::explainBeeMarioIfAtFirst(); + break; + case 6: + MR::explainTeresaMarioIfAtFirst(); + break; + case 5: + MR::explainHopperMarioIfAtFirst(); + break; + case 2: + MR::explainFireMarioIfAtFirst(); + break; + case 3: + MR::explainIceMarioIfAtFirst(); + break; + case 7: + MR::explainFlyingMarioIfAtFirst(); + break; + case 1: + MR::explainInvincibleMarioIfAtFirst(); + break; + default: + break; + } + + if (_336 != 0) { + _338 = 0xA; + } + _336 = 0; + } + + _3DF = 1; + } else { + mMario->updateMorphResetTimer(); + } + + if (_338 != 0) { + _338--; + if (_338 == 0) { + MR::zoomOutTargetGameCamera(); + MR::endGlobalEventCamera("変身初出カメラ", 0x3C, true); + } + } +} + +void MarioActor::calcAnim() { + if (_482) { + mBlendMtxTimer = 0; + return; + } + + if (_3DF) { + u16 mode = (_3D8 & 7) < (_3D8 >> 3) ? _3D6 : mPlayerMode; + + if (_3D8 != 0 && mPlayerMode == 0) { + if (mode != mPlayerMode && _3D6 == 6) { + if (_3D8 > 0x1A) { + _9A4->appear(); + } + + _483 = true; + updateHand(); + updateFace(); + return; + } + + if (_3D6 == 6) { + _9A4->kill(); + _483 = false; + } + } + + switch (mode) { + case 1: + changeDisplayMode(4); + _9C8->calcAnim(); + if (_3DE) { + _A6E = true; + } + break; + case 3: + changeDisplayMode(3); + break; + case 4: + case 2: + changeDisplayMode(2); + break; + case 5: + _3DF = false; + changeDisplayMode(5); + break; + default: + changeDisplayMode(0); + s32 btpFrame = 0; + if (mode == 7) { + btpFrame = 1; + } else if (mode == 2) { + btpFrame = 2; + } + + MR::startBtp(this, "ColorChange"); + MR::setBtpFrameAndStop(this, static_cast< f32 >(btpFrame)); + break; + } + + if (_3DF) { + changeHandMaterial(); + } + } + + if (mMario->isStatusActive(0xB)) { + if (mCurrModel != 1) { + _A0B = mCurrModel; + } + + if ((_37C & 0x3) != 0) { + changeDisplayMode(1); + } else { + changeDisplayMode(_A0B); + } + } else if (mCurrModel == 1 && mHealth != 0) { + changeDisplayMode(_A0B); + } + + _3DF = false; + _3DE = false; + + calcAndSetBaseMtx(); + mMarioAnim->switchMirrorMode(); + mMarioAnim->calc(); + + if (_3D8 == 0) { + switch (mPlayerMode) { + case 3: + _9C0->mPosition = mPosition; + MR::updateModelDiffDL(_9C0); + MR::updateModelDiffDL(_A40); + MR::updateModelDiffDL(_A44); + break; + case 1: + _9C8->mPosition = mPosition; + MR::updateModelDiffDL(_9C8); + MR::updateModelDiffDL(_A50); + MR::updateModelDiffDL(_A54); + break; + case 5: + _A00->mPosition = mPosition; + MR::updateModelDiffDL(_A00); + break; + default: + if (mCurrModel != 1) { + MR::updateModelDiffDL(this); + } else { + _9E4->mPosition = mPosition; + MR::updateModelDiffDL(_9E4); + } + break; + } + } else if (mCurrModel == 0) { + MR::updateModelDiffDL(this); + } + + if (MR::isHiddenModel(this) && !_482) { + MR::showModel(this); + } + + updateRealMtx(); + + if (!(mMario->mMovementStates._F && mMario->_544 > 1)) { + _214->setMode(mAlphaEnable ? 0 : 2); + + TVec3f shadowDiff(mMario->mShadowPos); + shadowDiff -= mPosition; + _214->_20 = 40.0f + shadowDiff.dot(_240); + _214->_48 = mMario->mShadowPos; + + TMtx34f handMtx; + getRealMtx(handMtx.toMtxPtr(), "HandL"); + TVec3f handPos; + MR::extractMtxTrans(handMtx.toMtxPtr(), &handPos); + + TMtx34f footMtx; + getRealMtx(footMtx.toMtxPtr(), "FootR"); + TVec3f footPos; + MR::extractMtxTrans(footMtx.toMtxPtr(), &footPos); + + TVec3f side(footPos); + side -= handPos; + f32 sideLen = PSVECMag(&side); + MR::normalizeOrZero(&side); + + TVec3f tangent; + PSVECCrossProduct(&side, &_240, &tangent); + MR::normalizeOrZero(&tangent); + PSVECCrossProduct(&_240, &tangent, &side); + if (MR::normalizeOrZero(&side)) { + mMario->mSideVec = side; + } + + _214->_3C = side; + if (mMario->isSwimming()) { + _214->_18 = 10.0f + sideLen; + _214->_1C = 140.0f; + } else { + _214->_18 = 5.0f + sideLen; + _214->_1C = 70.0f; + } + + TMtx34f centerMtx; + if (mMario->isStatusActive(5)) { + getRealMtx(centerMtx.toMtxPtr(), "Center"); + } else { + getRealMtx(centerMtx.toMtxPtr(), "All_Root"); + } + + TVec3f centerPos; + MR::extractMtxTrans(centerMtx.toMtxPtr(), ¢erPos); + _214->create(centerPos, _240, mMario->mFrontVec); + } + + if (!_1C1) { + mMario->updateLookOfs(); + } + + updateHand(); + updateFace(); + calcScreenBoxRange(); + + if (_946 != 0 || _F20 != 0 || _F21 != 0 || mMario->mMovementStates._2B) { + _94A = 0; + } else { + _94A++; + } + + if (mCurrModel != 0) { + J3DModelX* baseModel = mModels[0]; + J3DModelX* drawModel = getJ3DModel(); + + MtxPtr handLMtx = MR::getJointMtx(baseModel, "HandL0"); + PSMTXCopy(MR::getJointMtx(drawModel, "HandL0"), handLMtx); + + MtxPtr handRMtx = MR::getJointMtx(baseModel, "HandR0"); + PSMTXCopy(MR::getJointMtx(drawModel, "HandR0"), handRMtx); + + MtxPtr footLMtx = MR::getJointMtx(baseModel, "FootL"); + PSMTXCopy(MR::getJointMtx(drawModel, "FootL"), footLMtx); + + MtxPtr footRMtx = MR::getJointMtx(baseModel, "FootR"); + PSMTXCopy(MR::getJointMtx(drawModel, "FootR"), footRMtx); + + MtxPtr centerJoint = MR::getJointMtx(baseModel, "Center"); + PSMTXCopy(MR::getJointMtx(drawModel, "Center"), centerJoint); + + MtxPtr allRootJoint = MR::getJointMtx(baseModel, "All_Root"); + PSMTXCopy(MR::getJointMtx(drawModel, "All_Root"), allRootJoint); + + MtxPtr emptyJoint = MR::getJointMtx(baseModel, ""); + PSMTXCopy(MR::getJointMtx(drawModel, ""), emptyJoint); + + MtxPtr hipJoint = MR::getJointMtx(baseModel, "Hip"); + PSMTXCopy(MR::getJointMtx(drawModel, "Hip"), hipJoint); + + MtxPtr faceMtx = MR::getJointMtx(baseModel, "Face0"); + PSMTXCopy(MR::getJointMtx(drawModel, "Face0"), faceMtx); + + PSMTXCopy(drawModel->getBaseTRMtx(), baseModel->getBaseTRMtx()); + } + + updateRasterScroll(); +} + +void MarioActor::calcAndSetBaseMtx() { + if (!_1C0) { + _1C1 = true; + return; + } + + _1C1 = false; + _1C0 = false; + + TMtx34f prevBlendMtx; + PSMTXCopy(getJ3DModel()->getBaseTRMtx(), prevBlendMtx.toMtxPtr()); + + bool hasForcedBaseMtx = false; + + if (_934) { + HitSensor* sensor = getSensor("body"); + hasForcedBaseMtx = _924->receiveMessage(0xA1, sensor); + + if (hasForcedBaseMtx) { + TVec3f head; + ((TRot3f*)getBaseMtx())->getYDir(head); + MR::normalizeOrZero(&head); + mMario->setHeadVec(head); + + TVec3f front; + ((TRot3f*)getBaseMtx())->getZDir(front); + MR::normalizeOrZero(&front); + mMario->setFrontVecKeepUp(front); + mMario->_334 = front; + } + } + + if (_EA4 || _EA5) { + if (_EA5) { + PSMTXCopy(getBaseMtx(), _EA8.toMtxPtr()); + + TVec3f head; + ((TRot3f*)getBaseMtx())->getYDir(head); + mMario->setHeadVec(head); + + TVec3f front; + ((TRot3f*)getBaseMtx())->getZDir(front); + mMario->setFrontVecKeepUp(front); + + mMario->_278 = 0.0f; + mMario->_71C = false; + mMario->stopJump(); + mMario->_334 = mMario->mFrontVec; + + if (mMario->isSwimming()) { + mMario->mSwim->resetAndFixPose(); + } + + hasForcedBaseMtx = true; + if (_EA4) { + _EA6 = true; + } + } else if (_EA6) { + return; + } + } + + TMtx34f prevBaseMtx; + + if (hasForcedBaseMtx) { + TVec3f prevPos(mPosition); + MR::extractMtxTrans(getBaseMtx(), &mPosition); + mMario->invalidateRelativePosition(); + + TVec3f forceDelta(mPosition); + forceDelta -= prevPos; + _938 = forceDelta; + + PSMTXCopy(getBaseMtx(), prevBaseMtx.toMtxPtr()); + + if (mMario->mMovementStates._37) { + mMario->_688 = mPosition; + } + + updateGravityVec(true, true); + mMario->updateGroundInfo(); + } + + if (_934 && !hasForcedBaseMtx) { + TVec3f basePos; + MR::extractMtxTrans(getBaseMtx(), &basePos); + + TVec3f forceDelta(mPosition); + forceDelta -= basePos; + _938 = forceDelta; + } + + TPos3f baseMtx; + PSMTXIdentity(baseMtx.toMtxPtr()); + mMario->createAngleMtx(baseMtx.toMtxPtr(), hasForcedBaseMtx); + + if (_EA6) { + TMtx34f capMtx; + getRealMtx(capMtx.toMtxPtr(), "CapPosition"); + MR::extractMtxTrans(capMtx.toMtxPtr(), &_2AC); + + TVec3f capDiff(_2AC); + capDiff -= mPosition; + if (capDiff.length() > 500.0f) { + PSMTXCopy(getBaseMtx(), baseMtx.toMtxPtr()); + MR::setMtxTrans(baseMtx.toMtxPtr(), 0.0f, 0.0f, 0.0f); + } + } + + PSMTXConcat(baseMtx.toMtxPtr(), MR::tmpMtxRotYRad(mMario->mYAngleOffset), baseMtx.toMtxPtr()); + + if (mPlayerMode == 6) { + updateBaseMtxTeresa(baseMtx.toMtxPtr()); + } + + if (!hasForcedBaseMtx && mPlayerMode == 4 && !mMario->isStatusActive(0x16) && !mMario->isStatusActive(0x15) && !mMario->isStatusActive(0x1B) && + !mMario->mMovementStates._23 && !mMario->mMovementStates._A && !(mMario->mMovementStates._B && mMario->mMovementStates.jumping)) { + _9F4 = mMario->mAirGravityVec; + + const MarioConstTable* table = mConst->getTable(); + f32 headToFootLength = table->mBeePoseHeadToFootLength; + + TVec3f antiGravity = -getGravityVector(); + TVec3f headOffset(antiGravity); + headOffset.scale(headToFootLength); + + TVec3f headPivot = -headOffset; + MtxPtr transMtx = MR::tmpMtxTrans(headPivot); + + TVec3f delayOffset(_9F4); + delayOffset.scale(headToFootLength); + + TVec3f targetPos(mPosition); + targetPos -= delayOffset; + + TVec3f delayDir(_33C); + delayDir -= targetPos; + + f32 delayAngle = 0.0f; + TVec3f delayAxis; + if (!MR::normalizeOrZero(&delayDir)) { + PSVECCrossProduct(&mMario->mFrontVec, &delayDir, &delayAxis); + if (!MR::normalizeOrZero(&delayAxis)) { + delayAngle = MR::acosEx(_9F4.dot(delayDir)); + f32 limit = table->mBeePoseDelayAngleAir; + + if (mMario->mMovementStates._1) { + limit = table->mBeePoseDelayAngleGround; + } + + delayAngle = MR::clamp(delayAngle, 0.0f, limit); + } + } + + TMtx34f delayRotMtx; + PSMTXRotAxisRad(delayRotMtx.toMtxPtr(), &delayAxis, delayAngle); + + PSMTXConcat(transMtx, baseMtx.toMtxPtr(), baseMtx.toMtxPtr()); + PSMTXConcat(delayRotMtx.toMtxPtr(), baseMtx.toMtxPtr(), baseMtx.toMtxPtr()); + PSMTXConcat(MR::tmpMtxTrans(headOffset), baseMtx.toMtxPtr(), baseMtx.toMtxPtr()); + + TVec3f delayAccel(_9F4); + delayAccel.scale(table->mBeePoseDelayAccel); + MR::vecKillElement(delayAccel, _360, &delayAccel); + + _354 += delayAccel; + _33C += _354; + + TVec3f offsetFromHead(_9F4); + offsetFromHead.scale(headToFootLength); + + TVec3f poseBasePos(mPosition); + poseBasePos -= offsetFromHead; + + TVec3f poseVec(_33C); + poseVec -= poseBasePos; + _360 = poseVec; + + TVec3f prevPose(_360); + TVec3f normPose(_360); + MR::normalizeOrZero(&normPose); + + f32 poseAngle = MR::acosEx(_9F4.dot(normPose)); + f32 poseLimit = table->mBeePoseLimitAngleAir; + + if (mMario->mMovementStates._1) { + poseLimit = table->mBeePoseLimitAngleGround; + } + + if (poseAngle > poseLimit) { + TVec3f poseAxis; + PSVECCrossProduct(&_9F4, &normPose, &poseAxis); + + if (MR::normalizeOrZero(&poseAxis)) { + _360 = _9F4; + } else { + TMtx34f poseRotMtx; + PSMTXRotAxisRad(poseRotMtx.toMtxPtr(), &poseAxis, poseLimit); + PSMTXMultVec(poseRotMtx.toMtxPtr(), &_9F4, &_360); + } + } + + _360.setLength(headToFootLength); + + if (prevPose.length() > headToFootLength) { + TVec3f poseRest(prevPose); + poseRest -= _360; + _354 += -poseRest; + } + + TVec3f followOffset(_9F4); + followOffset.scale(headToFootLength); + + TVec3f followPos(mPosition); + followPos -= followOffset; + followPos += _360; + _33C = followPos; + + MR::normalizeOrZero(&_360); + + if (_354.length() > table->mBeePoseDelaySpeedLimit) { + _354.setLength(table->mBeePoseDelaySpeedLimit); + } + + f32 friction = table->mBeePoseFrictionStop; + if (!mMario->_71C && !isJumping()) { + friction = table->mBeePoseFrictionMove; + } + _354.scale(friction); + + if (!MR::isSameDirection(_360, mMario->mFrontVec, 0.01f)) { + TVec3f up(_360 - mMario->mFrontVec); + MR::makeMtxUpFront(&baseMtx, up, mMario->mFrontVec); + } else if (!MR::isSameDirection(mMario->_1FC, mMario->mFrontVec, 0.01f)) { + MR::makeMtxUpFront(&baseMtx, mMario->_1FC, mMario->mFrontVec); + } else { + MR::makeMtxUpFront(&baseMtx, mMario->mHeadVec, mMario->mFrontVec); + } + + if (mMario->_71C > 2 || isJumping()) { + f32 keepRatio = table->mBeePoseTransBlendingRatioMove; + f32 blendRatio = 1.0f - keepRatio; + + TVec3f blendPos(_33C); + blendPos -= mPosition; + blendPos.scale(blendRatio); + + TVec3f keepPos(_348); + keepPos.scale(keepRatio); + keepPos += blendPos; + _348 = keepPos; + + MR::setMtxTrans(baseMtx.toMtxPtr(), _348.x, _348.y, _348.z); + } else { + _348.scale(table->mBeePoseTransBlendingRatioStop); + MR::setMtxTrans(baseMtx.toMtxPtr(), _348.x, _348.y, _348.z); + } + } else { + _354.zero(); + _348.zero(); + _33C = mPosition; + _9F4 = getGravityVector(); + } + + MR::addTransMtx(baseMtx.toMtxPtr(), mPosition); + + if (hasForcedBaseMtx) { + TMtx34f invBaseMtx; + PSMTXInverse(baseMtx.toMtxPtr(), invBaseMtx.toMtxPtr()); + PSMTXConcat(invBaseMtx.toMtxPtr(), prevBaseMtx.toMtxPtr(), _E3C.toMtxPtr()); + mMarioAnim->mXanimePlayer->mCore->getJointTransform(0)->_64 = _E3C.toMtxPtr(); + } else { + TMtx34f correctionMtx; + TVec3f correctionTrans; + mMario->createCorrectionMtx(correctionMtx.toMtxPtr(), &correctionTrans); + + XjointTransform* joint1 = mMarioAnim->mXanimePlayer->mCore->getJointTransform(1); + joint1->_2C = correctionTrans.x; + joint1->_30 = correctionTrans.y; + joint1->_34 = correctionTrans.z; + + PSMTXCopy(correctionMtx.toMtxPtr(), _E3C.toMtxPtr()); + mMarioAnim->mXanimePlayer->mCore->getJointTransform(0)->_64 = _E3C.toMtxPtr(); + } + + if (_390 != 0) { + _394 = 30; + + switch (_39C) { + case 0: + case 2: + if (_390 > 0xF) { + f32 distToCeil = mMario->calcDistToCeil(false); + f32 distToPress = mMario->calcDistToCeilOnPress(); + + f32 targetScale = MR::clamp(distToCeil / 150.0f, 0.2f, 1.0f); + if (_3B0 > targetScale) { + _3B0 = targetScale; + } else { + targetScale = MR::clamp(distToPress / 150.0f, 0.2f, 1.0f); + if (_3B0 > targetScale) { + _3B0 = targetScale; + } + } + + MR::setMtxTrans(baseMtx.toMtxPtr(), mPosition.x, mPosition.y, mPosition.z); + + if (mMario->_960 != 0x1B) { + _1E0 = true; + } + } else { + _3B0 = 0.2f + ((0.8f * static_cast< f32 >(0xF - _390)) / 15.0f); + } + + if (_398 != 0) { + _3B0 += 0.02f * static_cast< f32 >(_398); + } + break; + case 1: + case 3: + if (_390 > 0xF) { + f32 distWidth = mMario->calcDistWidth(); + mPosition = mMario->mPosition; + + f32 targetScale = MR::clamp(distWidth / 80.0f, 0.2f, 1.0f); + if (_3B0 > targetScale) { + _3B0 = targetScale; + } else { + _3B0 = MR::clamp(_3B0 - 0.01f, 0.2f, 1.0f); + } + } else { + _3B0 = 0.2f + ((0.8f * static_cast< f32 >(0xF - _390)) / 15.0f); + } + + if (_398 != 0) { + _3B0 += 0.02f * static_cast< f32 >(_398); + } + break; + case 4: { + f32 angle = (static_cast< f32 >(_390) / 120.0f) * (0.5f * 3.1415927f); + if (angle < 0.0f) { + angle = -angle; + } + _3B0 = 1.0f - JMACosRadian(angle); + break; + } + default: + break; + } + } else if (_394 != 0) { + _394--; + + switch (_39C) { + case 0: + case 2: { + f32 phase = (2.0f * 3.1415927f * static_cast< f32 >(_394)) / 15.0f; + f32 wave = MR::sin(phase); + _3B0 = 1.0f + (((0.15f * static_cast< f32 >(_394)) / 30.0f) * wave); + break; + } + case 1: + case 3: { + f32 phase = (2.0f * 3.1415927f * static_cast< f32 >(_394)) / 15.0f; + f32 wave = MR::sin(phase); + _3B0 = 1.0f + (((0.15f * static_cast< f32 >(_394)) / 30.0f) * wave); + break; + } + default: + break; + } + } else if (!mMario->mMovementStates._3C) { + _3B0 = 1.0f; + } + + if (_398 != 0) { + _398--; + } + + if (mBlendMtxTimer != 0) { + f32 total = static_cast< f32 >(mBlendMtxTimer); + f32 remain = static_cast< f32 >(mBlendMtxTimer - 1); + _EA0 = 1.0f - ((1.0f - _EA0) * (remain / total)); + MR::blendMtx(prevBlendMtx.toMtxPtr(), baseMtx.toMtxPtr(), _EA0, baseMtx.toMtxPtr()); + mBlendMtxTimer--; + } + + PSMTXCopy(baseMtx.toMtxPtr(), _3EC.toMtxPtr()); + + if (_3B0 != 1.0f) { + scaleMtx(baseMtx.toMtxPtr()); + } + + J3DModelX* model = getJ3DModel(); + PSMTXCopy(baseMtx.toMtxPtr(), model->getBaseTRMtx()); + model->mBaseScale.x = mScale.x; + model->mBaseScale.y = mScale.y; + model->mBaseScale.z = mScale.z; + _EA5 = false; +} + +void MarioActor::jumpHop() { + if (!isJumping()) { + return; + } + + if (!mMario->isRising()) { + mMario->cutGravityElementFromJumpVec(true); + + TVec3f antiGravity(-_240); + antiGravity.scale(mConst->getTable()->mClapJumpBonusFalling); + mMario->mJumpVec += antiGravity; + } else { + f32 speed = -mMario->cutGravityElementFromJumpVec(true); + const MarioConstTable* table = mConst->getTable(); + if (speed < table->mHopLimit) { + speed += table->mClapJumpBonusRising; + if (speed > table->mHopLimit) { + speed = table->mHopLimit; + } + } + + TVec3f antiGravity(-_240); + antiGravity.scale(speed); + mMario->mJumpVec += antiGravity; + } + + if (mMario->_430 == 5) { + mMario->_430 = 0; + mMario->mMovementStates_LOW_WORD &= ~0x00100000; + mMario->changeAnimation("落下", (const char*)nullptr); + } + + if (mMario->_430 == 0xB) { + mMario->_430 = 0; + } + + mMario->_4B0 = mMario->mPosition; +} + +void MarioActor::calcCenterPos() { + if (_934 || _8C) { + MR::copyJointPos(this, "Spine1", &_2A0); + return; + } + + TVec3f up; + if (mMario->isStatusActive(1)) { + up = mMario->_75C; + } else if (mMario->isStatusActive(5)) { + MR::copyJointPos(this, "Spine1", &_2A0); + return; + } else if (mMario->isSwimming()) { + up = _4B8; + } else { + up = -getGravityVec(); + } + + if (mMario->mMovementStates._15) { + mBinder->mRadius = 0.8f * mBinder->mRadius + 0.2f * 40.0f; + } else { + mBinder->mRadius = 0.9f * mBinder->mRadius + 0.1f * 60.0f; + } + + f32 centerDist = mBinder->mRadius; + if (mPlayerMode == 6) { + f32 dist = 0.8f * mBinder->mRadius + 0.2f * 100.0f; + centerDist = dist + 180.0f; + mBinder->mRadius = dist; + } + + up.scale(centerDist); + + TVec3f center(mPosition); + center += up; + _2A0 = center; +} + +void MarioActor::calcHeadPos() { + TMtx34f mtx; + getRealMtx(mtx.toMtxPtr(), "CapPosition"); + MR::extractMtxTrans(mtx.toMtxPtr(), &_2AC); +} + +void MarioActor::setPress(u8 pressType, s32 pressTimer) { + if (_390 != 0) { + return; + } + + if (pressType == 0 && mMario->calcDistToCeil(false) >= 160.0f) { + return; + } + + if (mMario->_10._1D) { + return; + } + + if (_39C == 0 || _39C == 2) { + *mMario->_480 = *mMario->mGroundPolygon; + *mMario->_484 = *mMario->_4C8; + } + + if (mMario->isStatusActive(4)) { + mMario->closeStatus(nullptr); + } + + mMario->startPadVib("マリオ[つぶれ]"); + MR::forceDeleteEffectAll(this); + mVelocity.zero(); + + if (pressTimer == 0) { + pressTimer = 0xF0; + } + + _390 = pressTimer; + mMario->mMovementStates_LOW_WORD &= ~0x00100000; + mMario->mMovementStates_LOW_WORD &= ~0x00010000; + mMario->stopJump(); + mMario->mMovementStates_LOW_WORD |= 0x40000000; + + mMario->_13C.zero(); + mMario->_148.zero(); + mMario->_154.zero(); + mMario->mVerticalSpeed = 0.0f; + + mMario->stopWalk(); + mMarioAnim->setSpeed(0.0f); + + _B90 = true; + _39C = pressType; + _F44 = false; + + mMario->playSound("プレスダメージ", -1); + mMario->playSound("声大ダメージ", -1); + + _FB4 = &NrvMarioActor::MarioActorNrvGameOver::sInstance; + _FB8 = 0x3C; + + if (_39C != 4) { + _390 = 1000; + } + + for (u32 i = 0; i < 6; i++) { + decLife(0); + } + + MR::startStarPointerModeDemoMarioDeath(this); +} + +bool MarioActor::isEnableMoveMario() const { + if (isNerve(&NrvMarioActor::MarioActorNrvWait::sInstance)) { + return true; + } + if (isNerve(&NrvMarioActor::MarioActorNrvNoRush::sInstance)) { + return true; + } + return isNerve(&NrvMarioActor::MarioActorNrvGameOverNonStop::sInstance); +} + +bool MarioActor::isEnableNerveChange() const { + if (isNerve(&NrvMarioActor::MarioActorNrvWait::sInstance)) { + return true; + } + return isNerve(&NrvMarioActor::MarioActorNrvNoRush::sInstance); +} + +void MarioActor::forceGameOver() { + if (isEnableNerveChange()) { + setNerve(&NrvMarioActor::MarioActorNrvGameOver::sInstance); + } +} + +void MarioActor::forceGameOverAbyss() { + if (isEnableNerveChange()) { + setNerve(&NrvMarioActor::MarioActorNrvGameOverAbyss::sInstance); + } +} + +void MarioActor::forceGameOverBlackHole() { + if (isEnableNerveChange()) { + setNerve(&NrvMarioActor::MarioActorNrvGameOverBlackHole::sInstance); + } +} + +void MarioActor::forceGameOverNonStop() { + if (isEnableNerveChange()) { + setNerve(&NrvMarioActor::MarioActorNrvGameOverNonStop::sInstance); + } +} + +void MarioActor::forceGameOverSink() { + if (isEnableNerveChange()) { + setNerve(&NrvMarioActor::MarioActorNrvGameOverSink::sInstance); + } +} + +void MarioActor::updateCameraInfo() { + _F74 = false; + + TVec3f camZDir = MR::getCamZdir(); + if (MR::diffAngleAbs(mCamDirZ, camZDir) >= 0.5235988f) { + _F74 = true; + } + + TVec3f camPos = MR::getCamPos(); + TVec3f moveDist(mCamPos); + moveDist -= camPos; + + if (PSVECMag(&moveDist) > 500.0f) { + _F74 = true; + } + + if (_F74) { + mMario->changeAnimationInterpoleFrame(0); + stopSpinTicoEffect(true); + mBlendMtxTimer = 0; + } + + mCamPos = MR::getCamPos(); + mCamDirX = MR::getCamXdir(); + mCamDirY = MR::getCamYdir(); + + _FA8 = mCamDirZ; + mCamDirZ = MR::getCamZdir(); +} + +bool MarioActor::binderFilter(const Triangle* pTriangle) { + if (_F48 != 0 && pTriangle->mSensor == reinterpret_cast< HitSensor* >(_F48)) { + return true; + } + return false; +} + +namespace NrvMarioActor { +INIT_NERVE(MarioActorNrvWait); +INIT_NERVE(MarioActorNrvGameOver); +INIT_NERVE(MarioActorNrvGameOverAbyss); +INIT_NERVE(MarioActorNrvGameOverAbyss2); +INIT_NERVE(MarioActorNrvGameOverFire); +INIT_NERVE(MarioActorNrvGameOverBlackHole); +INIT_NERVE(MarioActorNrvGameOverNonStop); +INIT_NERVE(MarioActorNrvGameOverSink); +INIT_NERVE(MarioActorNrvTimeWait); +INIT_NERVE(MarioActorNrvNoRush); +} // namespace NrvMarioActor + +namespace MR { + s32 getFrameBufferWidth() { + return JUTVideo::getManager()->getRenderMode()->fbWidth; + } +} + +namespace JGeometry { + template <> + void TRotation3< TMatrix34< SMatrix34C< f32 > > >::getEuler(TVec3f& rDest) const { + if (this->mMtx[2][0] - 1.0f >= -0.0000038146973f) { + rDest.x = ::JMath::sAtanTable.atan2_(-this->mMtx[0][1], this->mMtx[1][1]); + rDest.y = -1.5707964f; + rDest.z = 0.0f; + } else if (this->mMtx[2][0] + 1.0f <= 0.0000038146973f) { + rDest.x = ::JMath::sAtanTable.atan2_(this->mMtx[0][1], this->mMtx[1][1]); + rDest.y = 1.5707964f; + rDest.z = 0.0f; + } else { + rDest.x = ::JMath::sAtanTable.atan2_(this->mMtx[2][1], this->mMtx[2][2]); + rDest.z = ::JMath::sAtanTable.atan2_(this->mMtx[1][0], this->mMtx[0][0]); + rDest.y = JGeometry::TUtil< f32 >::asin(-this->mMtx[2][0]); + } + } +} + +template <> +bool TriangleFilterDelegator< MarioActor >::isInvalidTriangle(const Triangle* pTriangle) const { + return (mParent->*mFunc)(pTriangle); +} From bdc00ff10d32d7efe77a09028d4b792b9aa3baa9 Mon Sep 17 00:00:00 2001 From: Frityet Date: Fri, 13 Feb 2026 00:13:47 +0000 Subject: [PATCH 02/52] l is real 2401 --- src/Game/Player/MarioMove2D.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Game/Player/MarioMove2D.cpp b/src/Game/Player/MarioMove2D.cpp index 77b6fad25..d62d18dab 100644 --- a/src/Game/Player/MarioMove2D.cpp +++ b/src/Game/Player/MarioMove2D.cpp @@ -90,7 +90,7 @@ void Mario::calcMoveDir2D(f32 a1, f32 a2, TVec3f* pOut) { TVec3f stack_8(stack_5C * a2); TVec3f stack_14(stack_68 * a1); TVec3f stack_20(stack_14); - stack_20.addInLine(stack_8); + stack_20.addInline(stack_8); *pOut = stack_20; } From fe9f534cf4a0809e5bc6171d7a242b997a329b65 Mon Sep 17 00:00:00 2001 From: Amrit Bhogal Date: Fri, 13 Feb 2026 00:52:18 +0000 Subject: [PATCH 03/52] cleanup --- include/Game/Player/Mario.hpp | 4 ++-- src/Game/Player/Mario.cpp | 4 ++-- src/Game/Player/MarioActorBlackHole.cpp | 8 ++++---- src/Game/Player/MarioActorClap.cpp | 4 ++-- src/Game/Player/MarioBump.cpp | 2 +- src/Game/Player/MarioEnforce.cpp | 24 ++++++++++++------------ src/Game/Player/MarioJump.cpp | 4 ++-- src/Game/Player/MarioSukekiyo.cpp | 6 +++--- 8 files changed, 28 insertions(+), 28 deletions(-) diff --git a/include/Game/Player/Mario.hpp b/include/Game/Player/Mario.hpp index ebf488564..2bf33ed07 100644 --- a/include/Game/Player/Mario.hpp +++ b/include/Game/Player/Mario.hpp @@ -910,8 +910,8 @@ class Mario : public MarioModule { /* 0x8BC */ TVec3f _8BC; /* 0x8C8 */ Triangle* _8C8; /* 0x8CC */ Triangle* _8CC[2]; - /* 0x8D4 */ u32 _8D4; - /* 0x8D8 */ u32 _8D8; + /* 0x8D4 */ HitSensor* _8D4; + /* 0x8D8 */ HitSensor* _8D8; /* 0x8DC */ TVec3f _8DC; /* 0x8E8 */ Triangle* _8E8; /* 0x8EC */ u8 _8EC; diff --git a/src/Game/Player/Mario.cpp b/src/Game/Player/Mario.cpp index cab03d7da..2a89270a5 100644 --- a/src/Game/Player/Mario.cpp +++ b/src/Game/Player/Mario.cpp @@ -253,8 +253,8 @@ Mario::Mario(MarioActor* actor) : MarioModule(actor) { _730 = 0; - _8D8 = 0; - _8D4 = 0; + _8D8 = nullptr; + _8D4 = nullptr; _A38 = 0; _A68 = 0; diff --git a/src/Game/Player/MarioActorBlackHole.cpp b/src/Game/Player/MarioActorBlackHole.cpp index 25cb83167..9253bc285 100644 --- a/src/Game/Player/MarioActorBlackHole.cpp +++ b/src/Game/Player/MarioActorBlackHole.cpp @@ -14,9 +14,9 @@ void MarioActor::initBlackHoleOut() { Mtx rotation; TVec3f rotateAxis; - PSVECCrossProduct(&normalisedRelativeCameraPos, &normalisedRelativePos, &rotateAxis); + rotateAxis.cross(normalisedRelativeCameraPos, normalisedRelativePos); - f32 mag = PSVECMag(&mPosRelativeToBlackHole); + f32 mag = mPosRelativeToBlackHole.length(); TVec3f killed; f32 flt = MR::vecKillElement(mCamPos - mPosition, mCamDirZ, &killed); flt *= mConst->getTable()->mBlackHoleFirstRadius; @@ -87,7 +87,7 @@ void MarioActor::exeGameOverBlackHole2() { PSMTXMultVec(rotationMatrix, &mPosRelativeToBlackHole, &mPosRelativeToBlackHole); TVec3f camDirZNegate; - JMathInlineVEC::PSVECNegate(&mCamDirZ, &camDirZNegate); + camDirZNegate = -mCamDirZ; MR::vecBlendSphere(mBlackHoleRotateAxis, camDirZNegate, &mBlackHoleRotateAxis, 0.01f); f32 distChangeFactor = 180 - getNerveStep(); @@ -96,7 +96,7 @@ void MarioActor::exeGameOverBlackHole2() { distChangeFactor = 0.0f; } - f32 newDistToBlackHole = PSVECMag(&mPosRelativeToBlackHole) * distChangeFactor / (1 + distChangeFactor); + f32 newDistToBlackHole = mPosRelativeToBlackHole.length() * distChangeFactor / (1 + distChangeFactor); mPosRelativeToBlackHole.setLength(newDistToBlackHole); diff --git a/src/Game/Player/MarioActorClap.cpp b/src/Game/Player/MarioActorClap.cpp index 5bb5a755a..0e866e876 100644 --- a/src/Game/Player/MarioActorClap.cpp +++ b/src/Game/Player/MarioActorClap.cpp @@ -6,8 +6,8 @@ void MarioActor::bodyClap() { for (u32 i = 0; i < _7DC; i++) { TVec3f stack_14(_6DC[i]->mPosition); TVec3f stack_8(stack_14); - JMathInlineVEC::PSVECSubtract2(&stack_8, &_2A0, &stack_8); - if (PSVECMag(&stack_8) < 100.0f) { + stack_8.subInline(_2A0); + if (stack_8.length() < 100.0f) { _6DC[i]->receiveMessage(0x87, getSensor("body")); } } diff --git a/src/Game/Player/MarioBump.cpp b/src/Game/Player/MarioBump.cpp index 922488065..4afd48337 100644 --- a/src/Game/Player/MarioBump.cpp +++ b/src/Game/Player/MarioBump.cpp @@ -25,7 +25,7 @@ void Mario::checkBump() { void Mario::startBump(const TVec3f& rVec) { TVec3f v18 = getTrans() - rVec; - if (PSVECMag(&v18) >= 100.0f) { + if (v18.length() >= 100.0f) { return; } diff --git a/src/Game/Player/MarioEnforce.cpp b/src/Game/Player/MarioEnforce.cpp index e6a079669..602d9be23 100644 --- a/src/Game/Player/MarioEnforce.cpp +++ b/src/Game/Player/MarioEnforce.cpp @@ -25,7 +25,7 @@ void Mario::checkEnforceMoveInner() { _184.zero(); } - _8D4 = 0; + _8D4 = nullptr; bool same = moveRelativePositionWall() | moveRelativePosition(0); if (same) { if (MR::isSameMtx(*_45C->getBaseMtx(), *_45C->getPrevBaseMtx())) { @@ -256,8 +256,8 @@ u32 Mario::moveRelativePosition(u32) { addVelocity(_184); - if (_8D4 == 0 || rTri->mSensor != mHang->mWallSensor) { - _8D4 = reinterpret_cast< u32 >(rTri->mSensor); + if (_8D4 == nullptr || rTri->mSensor != mHang->mWallSensor) { + _8D4 = rTri->mSensor; } if (!MR::isSameMtxRot(*rTri->getBaseMtx(), *rTri->getPrevBaseMtx())) { @@ -314,8 +314,8 @@ u32 Mario::moveRelativePositionWall() { mMovementStates._18 = 1; } - if (_8D4 == 0 || tri->mSensor != mHang->mWallSensor) { - _8D4 = reinterpret_cast< u32 >(tri->mSensor); + if (_8D4 == nullptr || tri->mSensor != mHang->mWallSensor) { + _8D4 = tri->mSensor; } moved = 1; @@ -408,7 +408,7 @@ void Mario::tryPushToVelocity() { pushVec += _35C; _350.zero(); _35C.zero(); - createAtField(true, PSVECMag(&pushVec)); + createAtField(true, pushVec.length()); for (u32 i = 0; i < _578; i++) { TVec3f projected; @@ -440,7 +440,7 @@ void Mario::tryPushToVelocity() { } } - _1C_WORD |= 0x400; + _1C._A = 1; } mVelocity += _35C; @@ -524,7 +524,7 @@ void Mario::recordJumpEnforceMove() { // Mario::doEnforceJump void Mario::doEnforceJump(f32 param) { if (mJumpVec.dot(_184) < 0.0f) { - mDrawStates_WORD |= 0x10; + mDrawStates._4 = 1; initActiveJumpVec(); } @@ -550,7 +550,7 @@ void Mario::doEnforceJump(f32 param) { // Mario::pushedByWind void Mario::pushedByWind() { - f32 windMag = PSVECMag(&_91C); + f32 windMag = _91C.length(); const char* noAnim = static_cast< const char* >(nullptr); TVec3f windDir(_91C); @@ -591,7 +591,7 @@ void Mario::pushedByWind() { TVec3f add(windDir); add.scale(windMag); _350 += add; - _1C_WORD |= 0x400; + _1C._A = 1; changeAnimation("向かい風ふんばり", noAnim); return; } @@ -604,7 +604,7 @@ void Mario::pushedByWind() { TVec3f add(scaled); add.scale(table->mWindForwardFriction); _350 += add; - _1C_WORD |= 0x400; + _1C._A = 1; stopAnimation("向かい風ふんばり", noAnim); stopAnimation("向かい風走り", noAnim); return; @@ -633,7 +633,7 @@ void Mario::pushedByWind() { changeAnimation("向かい風走り", noAnim); _350 += final; - _1C_WORD |= 0x400; + _1C._A = 1; } namespace NrvMarioActor { diff --git a/src/Game/Player/MarioJump.cpp b/src/Game/Player/MarioJump.cpp index 10fa3aeed..9bd6e3509 100644 --- a/src/Game/Player/MarioJump.cpp +++ b/src/Game/Player/MarioJump.cpp @@ -2135,7 +2135,7 @@ void Mario::doAirWalk() { reduceBegin = mActor->getConst().getTable()->mSquatJumpFrontReductionBTime; } - if (_10._8 && reinterpret_cast< u32 >(_45C->mSensor) == _8D8) { + if (_10._8 && _45C->mSensor == _8D8) { MtxPtr prevMtx = reinterpret_cast< MtxPtr >(_8E8->getPrevBaseMtx()); MtxPtr baseMtx = reinterpret_cast< MtxPtr >(_8E8->getBaseMtx()); if (MR::isSameMtx(baseMtx, prevMtx)) { @@ -2687,7 +2687,7 @@ void Mario::doLanding() { break; } - if (_10._17 && _45C != nullptr && _8D8 == reinterpret_cast< u32 >(_45C->mSensor)) { + if (_10._17 && _45C != nullptr && _8D8 == _45C->mSensor) { TVec3f jumpDelta(mJumpVec); jumpDelta -= _8DC; if (jumpDelta.dot(mJumpVec) < 0.0f) { diff --git a/src/Game/Player/MarioSukekiyo.cpp b/src/Game/Player/MarioSukekiyo.cpp index 67f234444..f63a616f0 100644 --- a/src/Game/Player/MarioSukekiyo.cpp +++ b/src/Game/Player/MarioSukekiyo.cpp @@ -29,7 +29,7 @@ bool MarioSukekiyo::notice() { } bool MarioSukekiyo::postureCtrl(MtxPtr mtx) { - MR::makeMtxUpSide((TPos3f*)mtx, _14, _20); + MR::makeMtxUpSide(reinterpret_cast< TPos3f* >(mtx), _14, _20); return true; } @@ -49,10 +49,10 @@ bool MarioSukekiyo::start() { getPlayer()->stopWalk(); if (mStatusId == 26) { - changeAnimation("スケキヨ", (const char*)nullptr); + changeAnimation("スケキヨ", static_cast< const char* >(nullptr)); } else { playSound("声足埋まり開始", -1); - changeAnimation("埋まり", (const char*)nullptr); + changeAnimation("埋まり", static_cast< const char* >(nullptr)); } return true; } From a6d44a83f6d073b23d0b1aeefc08924996858f08 Mon Sep 17 00:00:00 2001 From: Amrit Bhogal Date: Fri, 13 Feb 2026 01:32:08 +0000 Subject: [PATCH 04/52] cleanup --- include/Game/Player/MarioActor.hpp | 9 +-- src/Game/Player/Mario.cpp | 26 ++++---- src/Game/Player/MarioActor.cpp | 103 +++++++++++++++-------------- 3 files changed, 71 insertions(+), 67 deletions(-) diff --git a/include/Game/Player/MarioActor.hpp b/include/Game/Player/MarioActor.hpp index e27c667ec..6afa52f24 100644 --- a/include/Game/Player/MarioActor.hpp +++ b/include/Game/Player/MarioActor.hpp @@ -30,6 +30,7 @@ class FixedPosition; class ModelObj; class MultiEmitter; class IceStep; +struct CameraFrontTarget; extern bool gIsLuigi; // (cc68 - 10000)(r13) @@ -503,13 +504,13 @@ class MarioActor : public LiveActor { struct { u32 _468; HitSensor* _46C; - u32 _470; + HitSensor* _470; }; TVec3f _468Vec; }; // TVec3f _468; - u32 _474; + HitSensor* _474; f32 _478; u32 _47C; u8 _480; @@ -522,7 +523,7 @@ class MarioActor : public LiveActor { FixedPosition* _498; FixedPosition* _49C; FixedPosition* _4A0; - u32 _4A4; + CameraFrontTarget* _4A4; u32 _4A8; f32 _4AC; f32 _4B0; @@ -755,7 +756,7 @@ class MarioActor : public LiveActor { u16 _F42; bool _F44; // padding - u32 _F48; + HitSensor* _F48; BlackHole* mBlackHole; TVec3f mBlackHolePosition; TVec3f mBlackHoleRotateAxis; diff --git a/src/Game/Player/Mario.cpp b/src/Game/Player/Mario.cpp index 1da1c5640..300e8be85 100644 --- a/src/Game/Player/Mario.cpp +++ b/src/Game/Player/Mario.cpp @@ -1476,31 +1476,31 @@ bool Mario::isForceStopRush() const { goto exit_false; } u16 temp = _960; - if (temp < (s16)0xf) { - if (temp == (s16)4) { + if (temp < 0xf) { + if (temp == 4) { goto exit_true; } - if (temp < (s16)4) { - if (temp == (s16)1) { + if (temp < 4) { + if (temp == 1) { goto exit_true; } goto exit_false; } - if (temp == (s16)0xa) { + if (temp == 0xa) { goto exit_true; } goto exit_false; } - if (temp == (s16)0x18) { + if (temp == 0x18) { goto exit_true; } - if (temp < (s16)0x18) { - if (temp < (s16)0x11 == false) { + if (temp < 0x18) { + if (temp < 0x11 == false) { goto exit_false; } goto exit_true; } - if (temp == (s16)0x81 != false) { + if (temp == 0x81 != false) { goto exit_true; } goto exit_false; @@ -1900,7 +1900,7 @@ void Mario::actionMain() { } } if (isStickOn() && isAnimationRun("水泳陸うちあげ")) { - stopAnimation(nullptr, (char*)nullptr); + stopAnimation(static_cast< const char* >(nullptr), static_cast< const char* >(nullptr)); } if (!mDrawStates._4) { _3FE = 0; @@ -1930,7 +1930,7 @@ void Mario::updateGroundInfo() { _3C6 = 0; } if (b1 && mMovementStates._1 && isDefaultAnimationRun("落下")) { - changeAnimation(nullptr, "基本"); + changeAnimation(static_cast< const char* >(nullptr), "基本"); } if (!isStatusActive(0x13)) { if (!isStatusActive(0x13) && !mMovementStates._1 && mMovementStates._3E == 1 && mJumpVec.dot(*Mario::getGravityVec()) > 0.0f @@ -2058,9 +2058,9 @@ void Mario::createAngleMtx(MtxPtr mtx, bool forceNoFix) { PSMTXConcat(_C4, mtx, mtx); - HitSensor* pSensor = reinterpret_cast< HitSensor* >(mActor->_470); + HitSensor* pSensor = mActor->_470; if (isAnimationRun("投げ")) { - pSensor = reinterpret_cast< HitSensor* >(mActor->_474); + pSensor = mActor->_474; } if (mActor->isPunching()) { pSensor = mActor->_924; diff --git a/src/Game/Player/MarioActor.cpp b/src/Game/Player/MarioActor.cpp index d9b33ccae..b94be2f4c 100644 --- a/src/Game/Player/MarioActor.cpp +++ b/src/Game/Player/MarioActor.cpp @@ -31,6 +31,11 @@ bool gIsLuigi; +struct CameraFrontTarget { + u8 _00[0x24]; + const LiveActor* mActor; +}; + Triangle& Triangle::operator=(const Triangle& rOther) { mParts = rOther.mParts; mIdx = rOther.mIdx; @@ -106,9 +111,9 @@ MarioActor::MarioActor(const char* pName) : LiveActor(pName), _1B0(0xFFFFFFFF) { _3C1 = false; _211 = 0; - _46C = 0; - _470 = 0; - _474 = 0; + _46C = nullptr; + _470 = nullptr; + _474 = nullptr; _924 = nullptr; _928 = 0; _480 = 0; @@ -139,8 +144,8 @@ MarioActor::MarioActor(const char* pName) : LiveActor(pName), _1B0(0xFFFFFFFF) { _FCC = false; _FCD = false; - PSMTXIdentity((MtxPtr)&_EA8); - PSMTXIdentity((MtxPtr)&_3EC); + PSMTXIdentity(_EA8.toMtxPtr()); + PSMTXIdentity(_3EC.toMtxPtr()); _1F0.zero(); _1FC.zero(); @@ -167,8 +172,8 @@ MarioActor::MarioActor(const char* pName) : LiveActor(pName), _1B0(0xFFFFFFFF) { _934 = false; _7E2 = 0; _EF6 = 0; - _424 = 0; - _4A4 = 0; + _424 = nullptr; + _4A4 = nullptr; _6D0 = 0; _3A0 = 0; _EFC = 0; @@ -220,11 +225,11 @@ MarioActor::MarioActor(const char* pName) : LiveActor(pName), _1B0(0xFFFFFFFF) { _F24 = 0; _F28 = 0; - PSMTXIdentity((MtxPtr)&_C2C); - PSMTXIdentity((MtxPtr)&_C5C); - PSMTXIdentity((MtxPtr)&_D1C); - PSMTXIdentity((MtxPtr)&_D4C); - PSMTXIdentity((MtxPtr)&_D7C); + PSMTXIdentity(_C2C.toMtxPtr()); + PSMTXIdentity(_C5C.toMtxPtr()); + PSMTXIdentity(_D1C.toMtxPtr()); + PSMTXIdentity(_D4C.toMtxPtr()); + PSMTXIdentity(_D7C.toMtxPtr()); _1B4 = 0; _1C3 = false; @@ -348,13 +353,13 @@ void MarioActor::init2(const TVec3f& a, const TVec3f& b, s32 initialAnimation) { _B48->setTexture(MR::getTexFromArc("Footprint.bti", this)); switch (initialAnimation) { case 1: - mMario->changeAnimation("基本", (const char*)nullptr); + mMario->changeAnimation("基本", static_cast< const char* >(nullptr)); break; case 2: mMario->changeAnimationNonStop("ウォークイン"); break; default: - mMario->changeAnimation("ステージインA", (const char*)nullptr); + mMario->changeAnimation("ステージインA", static_cast< const char* >(nullptr)); break; } updateTransForCamera(); @@ -453,15 +458,15 @@ void MarioActor::changeAnimationNonStop(const char* pName) { void MarioActor::changeAnimationUpper(const char* pName) { if (!mMario->_71C) { if (isAnimationRun("基本")) { - mMario->changeAnimationUpper(pName, nullptr); + mMario->changeAnimationUpper(pName, static_cast< const char* >(nullptr)); return; } } - mMario->changeAnimation(pName, (const char*)nullptr); + mMario->changeAnimation(pName, static_cast< const char* >(nullptr)); } void MarioActor::stopAnimation(const char* pName) { - mMario->stopAnimation(pName, (const char*)nullptr); + mMario->stopAnimation(pName, static_cast< const char* >(nullptr)); } bool MarioActor::isAnimationRun(const char* pName) const { @@ -807,7 +812,7 @@ void MarioActor::exeWait() { } void MarioActor::movement() { - _46C = 0; + _46C = nullptr; _378++; _1E1 = 0; PSMTXCopy(_AE0.toMtxPtr(), _AB0.toMtxPtr()); @@ -976,7 +981,7 @@ void MarioActor::movement() { _935 = false; mMario->_2D0 = 0.0f; _F3C_vec[_F40] = mMario->mFrontVec; - _F40 = (u16)(_F40 + 1) % _F42; + _F40 = (_F40 + 1) % _F42; } void MarioActor::control() { @@ -1042,7 +1047,7 @@ void MarioActor::control2() { mBinder->_1EC._1 = true; } if (mMario->isDamaging()) { - _424 = 0; + _424 = nullptr; } } } @@ -1094,8 +1099,8 @@ void MarioActor::updateBehavior() { updateBindRatio(); updateEffect(); if (_B94 && !--_B94) { - mMario->stopAnimationUpper("ハンマー投げ回転中", nullptr); - mMario->stopAnimation("ハンマー投げ回転中", (const char*)nullptr); + mMario->stopAnimationUpper("ハンマー投げ回転中", static_cast< const char* >(nullptr)); + mMario->stopAnimation("ハンマー投げ回転中", static_cast< const char* >(nullptr)); } updatePunching(); if (!doPressing() && !doStun() && !doRush()) { @@ -1170,7 +1175,7 @@ void MarioActor::updatePunching() { } } if (mMario->isAnimationRun("ハンマー投げリリース") && mMario->getMovementStates()._1 && !_38C && !mMario->_420 && mMario->Mario::isStickOn()) { - mMario->stopAnimation(nullptr, (const char*)nullptr); + mMario->stopAnimation(static_cast< const char* >(nullptr), static_cast< const char* >(nullptr)); } } @@ -1200,11 +1205,11 @@ bool MarioActor::doRush() { s32 initial = mMario->mSwim->mSwimState; mMario->mSwim->checkWaterCube(false); if ((int)mMario->mSwim->mSwimState != initial) { - if (mMario->mSwim->mSwimState <= MarioSwim::SWIM_STATE_ENTERING && (u32)initial - 2 <= 1) { + if (mMario->mSwim->mSwimState <= MarioSwim::SWIM_STATE_ENTERING && static_cast(initial - 2) <= 1) { playEffectRT("水面ジャンプ水柱", mMario->mSwim->mSurfacePos, mMario->mSwim->mSurfaceNorm); emitEffectWaterColumn(mMario->mSwim->mSurfacePos, mMario->mSwim->mSurfaceNorm); // SWIM_STATE_UNDERWATER and SWIM_STATE_SURFACE - } else if ((u32)initial <= 1 && mMario->mSwim->mSwimState - MarioSwim::SWIM_STATE_UNDERWATER <= 1) { + } else if (static_cast(initial) <= 1 && mMario->mSwim->mSwimState - MarioSwim::SWIM_STATE_UNDERWATER <= 1) { playEffectRT("水面ジャンプ水柱", -mMario->_328, mMario->mSwim->mSurfaceNorm); emitEffectWaterColumn(mMario->mSwim->mSurfacePos, mMario->mSwim->mSurfaceNorm); } @@ -1250,7 +1255,7 @@ void MarioActor::updateSwingTimer() { _94E = 5; } if (_94E && --_94E == 0) { - mMario->startPadVib((u32)0); + mMario->startPadVib(static_cast< u32 >(0)); mMario->playSound("スピン回復終了", -1); Color8 stack_8; stack_8.set(0x50, 0x80, 0xc8, 0); @@ -1375,11 +1380,11 @@ void MarioActor::updateSwingAction() { mMario->playSound("声スピン", -1); mMario->playSound("スピンジャンプ", -1); } - mMario->changeAnimation("ハチスピン空中", (const char*)nullptr); + mMario->changeAnimation("ハチスピン空中", static_cast< const char* >(nullptr)); } else if (getMovementStates()._A || mAlphaEnable) { - mMario->changeAnimation("サマーソルト", (const char*)nullptr); + mMario->changeAnimation("サマーソルト", static_cast< const char* >(nullptr)); } else { - mMario->changeAnimation("ハチスピン", (const char*)nullptr); + mMario->changeAnimation("ハチスピン", static_cast< const char* >(nullptr)); } } if (didSpinPunch) { @@ -1410,12 +1415,12 @@ void MarioActor::updateSwingAction() { break; } if (isJumping()) { - mMario->changeAnimation("ハチスピン空中", (const char*)nullptr); + mMario->changeAnimation("ハチスピン空中", static_cast< const char* >(nullptr)); } else { if (getMovementStates()._A || mAlphaEnable) { - mMario->changeAnimation("サマーソルト", (const char*)nullptr); // Summersault + mMario->changeAnimation("サマーソルト", static_cast< const char* >(nullptr)); // Summersault } else { - mMario->changeAnimation("ハチスピン", (const char*)nullptr); + mMario->changeAnimation("ハチスピン", static_cast< const char* >(nullptr)); } } _946 = mConst->getTable()->mSpinIntervalTime + 0x22; @@ -1588,7 +1593,7 @@ bool MarioActor::doPressing() { setNerve(&NrvMarioActor::MarioActorNrvGameOver::sInstance); } if (!_390) { - mMario->changeAnimation("つぶれ解除", (const char*)nullptr); + mMario->changeAnimation("つぶれ解除", static_cast< const char* >(nullptr)); _F44 = true; } } @@ -1599,7 +1604,7 @@ bool MarioActor::doPressing() { setNerve(&NrvMarioActor::MarioActorNrvGameOver::sInstance); } if (!_390) { - mMario->changeAnimation("つぶれ解除", (const char*)nullptr); + mMario->changeAnimation("つぶれ解除", static_cast< const char* >(nullptr)); _F44 = true; } break; @@ -1667,7 +1672,7 @@ bool MarioActor::doStun() { void MarioActor::scaleMtx(MtxPtr rawMtx) { TVec3f i, j, k; - const TRot3f* pMtx = (TRot3f*)rawMtx; + const TRot3f* pMtx = reinterpret_cast(rawMtx); f32 scalar = 0.35f * (1.0f - _3B0) + 1.0f; pMtx->getXDir(i); pMtx->getYDir(j); @@ -1717,9 +1722,10 @@ void MarioActor::forceSetBaseMtx(MtxPtr mtx) { if (_482) { MR::extractMtxTrans(mtx, &mPosition); } - ((TRot3f*)mtx)->getZDir(_2DC); - ((TRot3f*)mtx)->getYDir(_2D0); - ((TRot3f*)mtx)->getXDir(_2E8); + const TRot3f* pMtx = reinterpret_cast(mtx); + pMtx->getZDir(_2DC); + pMtx->getYDir(_2D0); + pMtx->getXDir(_2E8); MR::updateHitSensorsAll(this); mMario->invalidateRelativePosition(); mMario->_8F8.zero(); @@ -1838,12 +1844,7 @@ void MarioActor::calcAnimInMovement() { } if (!isFirst) { - struct CameraFrontTarget { - u8 _00[0x24]; - const LiveActor* mActor; - }; - - const LiveActor* pTarget = reinterpret_cast< CameraFrontTarget* >(_4A4)->mActor; + const LiveActor* pTarget = _4A4->mActor; TVec3f front; MR::calcFrontVec(&front, pTarget); mMario->setFrontVecKeepUp(front); @@ -2177,12 +2178,13 @@ void MarioActor::calcAndSetBaseMtx() { if (hasForcedBaseMtx) { TVec3f head; - ((TRot3f*)getBaseMtx())->getYDir(head); + const TRot3f* pMtx = reinterpret_cast(getBaseMtx()); + pMtx->getYDir(head); MR::normalizeOrZero(&head); mMario->setHeadVec(head); TVec3f front; - ((TRot3f*)getBaseMtx())->getZDir(front); + pMtx->getZDir(front); MR::normalizeOrZero(&front); mMario->setFrontVecKeepUp(front); mMario->_334 = front; @@ -2194,11 +2196,12 @@ void MarioActor::calcAndSetBaseMtx() { PSMTXCopy(getBaseMtx(), _EA8.toMtxPtr()); TVec3f head; - ((TRot3f*)getBaseMtx())->getYDir(head); + const TRot3f* pMtx = reinterpret_cast(getBaseMtx()); + pMtx->getYDir(head); mMario->setHeadVec(head); TVec3f front; - ((TRot3f*)getBaseMtx())->getZDir(front); + pMtx->getZDir(front); mMario->setFrontVecKeepUp(front); mMario->_278 = 0.0f; @@ -2586,7 +2589,7 @@ void MarioActor::jumpHop() { if (mMario->_430 == 5) { mMario->_430 = 0; mMario->mMovementStates_LOW_WORD &= ~0x00100000; - mMario->changeAnimation("落下", (const char*)nullptr); + mMario->changeAnimation("落下", static_cast< const char* >(nullptr)); } if (mMario->_430 == 0xB) { @@ -2783,7 +2786,7 @@ void MarioActor::updateCameraInfo() { } bool MarioActor::binderFilter(const Triangle* pTriangle) { - if (_F48 != 0 && pTriangle->mSensor == reinterpret_cast< HitSensor* >(_F48)) { + if (_F48 && pTriangle->mSensor == _F48) { return true; } return false; From 8cb10fa0e4dcfad8abcf1c20a53e4ac9eeaf3b7d Mon Sep 17 00:00:00 2001 From: Amrit Bhogal Date: Sat, 14 Feb 2026 15:49:02 +0000 Subject: [PATCH 05/52] cleanup --- src/Game/Player/Mario.cpp | 73 ++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/src/Game/Player/Mario.cpp b/src/Game/Player/Mario.cpp index 00413cd78..beaecb8cb 100644 --- a/src/Game/Player/Mario.cpp +++ b/src/Game/Player/Mario.cpp @@ -162,9 +162,9 @@ Mario::Mario(MarioActor* actor) : MarioModule(actor) { _29C = _368; _548 = _128 = _124 = 0.0f; _54C = mHeadVec; - PSMTXIdentity(_C4); - PSMTXIdentity(_64); - PSMTXIdentity(_94); + _C4.identity(); + _64.identity(); + _94.identity(); clearSlope(); _910.zero(); _91C.zero(); @@ -642,13 +642,13 @@ void Mario::fixHeadFrontVecByGravity() { airGrav = -airGrav; TVec3f side; - PSVECCrossProduct(&_290, &airGrav, &side); + _290.cross(airGrav, side); if (MR::normalizeOrZero(&side)) { return; } TVec3f newSide; - PSVECCrossProduct(&airGrav, &side, &newSide); + airGrav.cross(side, newSide); if (MR::normalizeOrZero(&newSide)) { return; } @@ -677,7 +677,7 @@ void Mario::fixHeadFrontVecByGravity() { } TVec3f axis; - PSVECCrossProduct(&mHeadVec, &upTarget, &axis); + mHeadVec.cross(upTarget, axis); bool useFrontAxis = true; if (MR::isNearZero(axis)) { @@ -738,7 +738,7 @@ void Mario::fixHeadFrontVecByGravity() { f32 angle = marioAcos(oldUp.dot(_29C)); TVec3f axisRot; - PSVECCrossProduct(&_29C, &oldUp, &axisRot); + _29C.cross(oldUp, axisRot); MR::normalizeOrZero(&axisRot); if (!MR::isNearZero(axisRot)) { @@ -750,7 +750,7 @@ void Mario::fixHeadFrontVecByGravity() { if (!MR::isNearZero(diff)) { TMtx34f rotMtx; PSMTXRotAxisRad(rotMtx.toMtxPtr(), &axisRot, angle); - PSMTXMultVec(rotMtx.toMtxPtr(), &mSideVec, &mSideVec); + rotMtx.mult(mSideVec, mSideVec); _29C = oldUp; _290 = mSideVec; _60D = 0; @@ -768,7 +768,7 @@ void Mario::fixHeadFrontVecByGravity() { } TVec3f fallbackSide; - PSVECCrossProduct(&oldUp, &_22C, &fallbackSide); + oldUp.cross(_22C, fallbackSide); MR::normalizeOrZero(&fallbackSide); if (!MR::isNearZero(fallbackSide)) { _290 = fallbackSide; @@ -857,12 +857,12 @@ void Mario::createDirectionMtx(MtxPtr mtx) { stack_8 = mFrontVec; if (mDrawStates._11) { MR::normalize(&stack_14); - PSVECCrossProduct(&stack_20, &stack_14, &stack_8); + stack_20.cross(stack_14, stack_8); MR::normalizeOrZero(&stack_8); if (MR::isNearZero(stack_8)) { stack_8 = mFrontVec; } - PSVECCrossProduct(&stack_14, &stack_8, &stack_20); + stack_14.cross(stack_8, stack_20); MR::normalizeOrZero(&stack_20); if (MR::isNearZero(stack_20)) { stack_20 = mSideVec; @@ -870,12 +870,13 @@ void Mario::createDirectionMtx(MtxPtr mtx) { } else { MR::normalizeOrZero(&stack_14); - PSVECCrossProduct(&stack_14, &mFrontVec, &stack_20); + stack_14.cross(mFrontVec, stack_20); MR::normalizeOrZero(&stack_20); if (MR::isNearZero(stack_20)) { stack_20 = mSideVec; } - PSVECCrossProduct(&stack_20, &stack_14, &stack_8); + // stack_20.cross(stack_14, stack_8) + stack_20.cross(stack_14, stack_8); MR::normalizeOrZero(&stack_8); if (MR::isNearZero(stack_8)) { stack_8 = mFrontVec; @@ -904,7 +905,7 @@ void Mario::createCorrectionMtx(MtxPtr mtx, TVec3f* pOut) { TMtx34f rotMtx; TVec3f frontVec; PSMTXRotAxisRad(rotMtx.toMtxPtr(), &mHeadVec, _74C); - PSMTXMultVec(rotMtx.toMtxPtr(), &mFrontVec, &frontVec); + rotMtx.mult(mFrontVec, frontVec); setFrontVecKeepUp(frontVec); _74C = 0.0f; } @@ -994,18 +995,18 @@ void Mario::fixFrontVecByGravity() { } } else if (_1C._2) { TVec3f side2; - PSVECCrossProduct(&up, &mFrontVec, &side2); + up.cross(mFrontVec, side2); MR::normalizeOrZero(&side2); if (MR::isNearZero(side2) == false) { _344 = side2; } } TVec3f front; - PSVECCrossProduct(&_344, &up, &front); + _344.cross(up, front); if (MR::normalizeOrZero(&front) == nullptr) { setFrontVec(front); _22C = mFrontVec; - f32 _328mag = PSVECMag(&_328); + f32 _328mag = _328.length();; _328 = mFrontVec.scaleInline(_328mag); } } @@ -1013,12 +1014,12 @@ void Mario::fixFrontVecByGravity() { void Mario::fixFrontVecFromUpSide() { TVec3f frontVec; - PSVECCrossProduct((Vec*)&mSideVec, (Vec*)&mHeadVec, (Vec*)&frontVec); + mSideVec.cross(mHeadVec, frontVec); MR::normalizeOrZero(&frontVec); if (MR::isNearZero(frontVec) == false) { setFrontVec(frontVec); _22C = mFrontVec; - float scaleFactor = PSVECMag((Vec*)&_328); + float scaleFactor = _328.length();; TVec3f scaledFront(mFrontVec); // inlined when it shouldn't be scaledFront.scale(scaleFactor); _328 = scaledFront; @@ -1027,7 +1028,7 @@ void Mario::fixFrontVecFromUpSide() { void Mario::fixSideVecFromFrontUp() { TVec3f side; - PSVECCrossProduct((Vec*)&mHeadVec, (Vec*)&mFrontVec, (Vec*)&side); + mHeadVec.cross(mFrontVec, side); MR::normalizeOrZero(&side); if (MR::isNearZero(side) == false) { mSideVec = side; @@ -1132,10 +1133,10 @@ void Mario::setFrontVecKeepUp(const TVec3f& rFront) { if (MR::isNearZero(rFront) == false) { setFrontVec(rFront); } - PSVECCrossProduct(&mHeadVec, &mFrontVec, &side); + mHeadVec.cross(mFrontVec, side); if (MR::isNearZero(side)) { MR::vecBlendSphere(front, rFront, &blendedFront, 0.5f); - PSVECCrossProduct(&mHeadVec, &blendedFront, &side); + mHeadVec.cross(blendedFront, side); setFrontVec(blendedFront); if (MR::isNearZero(side)) { setFrontVecKeepSide(rFront); @@ -1145,10 +1146,10 @@ void Mario::setFrontVecKeepUp(const TVec3f& rFront) { MR::normalize(&side); mSideVec = side; MR::normalize(&mSideVec); - PSVECCrossProduct(&mSideVec, &mHeadVec, &front2); + mSideVec.cross(mHeadVec, front2); setFrontVec(front2); _22C = mFrontVec; - f32 _328mag = PSVECMag(&_328); + f32 _328mag = _328.length();; TVec3f scaledFront(mFrontVec); scaledFront.scale(_328mag); _328 = scaledFront; @@ -1161,7 +1162,7 @@ void Mario::setFrontVecKeepSide(const TVec3f& rFront) { if (MR::isNearZero(rFront) == false) { setFrontVec(rFront); } - PSVECCrossProduct(&mFrontVec, &mSideVec, &headVec); + mFrontVec.cross(mSideVec, headVec); if (MR::normalizeOrZero(&headVec) != nullptr) { const TVec3f* gravity = getGravityVec(); TVec3f up = -(*gravity); @@ -1171,10 +1172,10 @@ void Mario::setFrontVecKeepSide(const TVec3f& rFront) { mHeadVec = headVec; MR::normalize(&mHeadVec); } - PSVECCrossProduct(&mSideVec, &mHeadVec, &front); + mSideVec.cross(mHeadVec, front); setFrontVec(front); _22C = mFrontVec; - float _328mag = PSVECMag(&_328); + float _328mag = _328.length();; TVec3f scaledFront(mFrontVec); scaledFront.scale(_328mag); _328 = scaledFront; @@ -1185,8 +1186,8 @@ void Mario::setHeadAndFrontVecFromRotate(const TVec3f& rRotate) { TVec3f headVec = TVec3f(0.0f, 1.0f, 0.0f); Mtx mtx; MR::makeMtxTR(mtx, 0.0f, 0.0f, 0.0f, rRotate.x, rRotate.y, rRotate.z); - PSMTXMultVec(mtx, (Vec*)&frontVec, (Vec*)&frontVec); - PSMTXMultVecSR(mtx, (Vec*)&headVec, (Vec*)&headVec); + PSMTXMultVec(mtx, &frontVec, &frontVec); + PSMTXMultVecSR(mtx, &headVec, &headVec); mHeadVec = headVec; MR::normalize(&mHeadVec); setFrontVecKeepUp(frontVec); @@ -1214,7 +1215,7 @@ void Mario::draw() const { TDDraw::drawCylinder(mPosition, diff31C_2A0, 32.0f, 0xffff0010, 0xff000004, 8); TVec3f diff2A0_31C(mActor->_2A0); diff2A0_31C -= mShadowPos; - f32 diffMag = PSVECMag(&diff2A0_31C); + f32 diffMag = diff2A0_31C.length();; MR::normalize(&diff2A0_31C); TVec3f _31CPlusStuff(mShadowPos); f32 _37CMod10 = mActor->_37C % 0xa; @@ -1432,7 +1433,7 @@ void Mario::setGravityVec(const TVec3f& rGravity) { } _1E4.zero(); } else { - PSVECCrossProduct(&mAirGravityVec, &rGravity, &_1E4); + mAirGravityVec.cross(rGravity, _1E4); MR::normalizeOrZero(&_1E4); f32 frontDot = __fabsf(mFrontVec.dot(_1E4)); f32 sideDot = __fabsf(mSideVec.dot(_1E4)); @@ -1618,7 +1619,7 @@ void Mario::writeBackPhyisicalVector() { } else if (MR::diffAngleAbs(*getGravityVec(), mJumpVec) < PI_30) { MR::vecKillElement(*_57C[i]->getNormal(0), *getGravityVec(), &stack_c8); - float mJumpVecMag = PSVECMag(&mJumpVec); + float mJumpVecMag = mJumpVec.length();; MR::normalizeOrZero(&stack_c8); mJumpVec += stack_c8; mJumpVec.setLength(mJumpVecMag); @@ -2090,7 +2091,7 @@ void Mario::createAngleMtx(MtxPtr mtx, bool forceNoFix) { f32 angle = JMAAcosRadian(noUpDir.dot(frontVec)); TVec3f cross; - PSVECCrossProduct(&frontVec, &noUpDir, &cross); + frontVec.cross(noUpDir, cross); if (cross.dot(headUp) < 0.0f) { angle = -angle; } @@ -2145,7 +2146,7 @@ void Mario::updateLookOfs() { TVec3f noHead; MR::vecKillElement(wallDiff, mHeadVec, &noHead); - f32 dist = PSVECMag(&noHead); + f32 dist = noHead.length();; TVec3f wallNormal(*mFrontWallTriangle->getNormal(0)); wallNormal.scale(dist - 35.0f); lookOfs = wallNormal; @@ -2201,8 +2202,8 @@ void Mario::updateLookOfs() { if (getAnimator()->isLandingAnimationRun()) { blend = 0.01f; } else if (_71C == 0 && _278 < 0.2f && isBlendWaitGround()) { - f32 lookMag = PSVECMag(&lookOfs); - f32 currMag = PSVECMag(&_148); + f32 lookMag = lookOfs.length();; + f32 currMag = _148.length();; if (currMag > lookMag) { blend = 0.5f; } else { From af1170e0cc4d96cd60eedc42cb3fa67aa0e7dccf Mon Sep 17 00:00:00 2001 From: Amrit Bhogal Date: Sat, 14 Feb 2026 16:02:44 +0000 Subject: [PATCH 06/52] actor cleanup --- src/Game/Player/MarioActor.cpp | 36 +++++++++++++++++----------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/Game/Player/MarioActor.cpp b/src/Game/Player/MarioActor.cpp index b94be2f4c..b32adf8de 100644 --- a/src/Game/Player/MarioActor.cpp +++ b/src/Game/Player/MarioActor.cpp @@ -829,35 +829,35 @@ void MarioActor::movement() { TVec3f stack_11C(_288); _288 = stack_128; if (MR::isOppositeDirection(_288, stack_11C, 0.01f)) { - f32 mag_288 = PSVECMag(&_288); - f32 magStack_11C = PSVECMag(&stack_11C); + f32 mag_288 = _288.length(); + f32 magStack_11C = stack_11C.length(); if (!MR::isNearZero(mag_288) && !MR::isNearZero(magStack_11C) && MR::isNearZero(mag_288 - magStack_11C, 1.0f)) { mPosition -= _288.scaleInline(0.5f); } } - if (PSVECMag(&stack_128) > 0.1f) { + if (stack_128.length() > 0.1f) { if (!(getMovementStates()._A)) { if (!MR::isNearZero(mVelocity)) { TVec3f stack_110(_294); stack_110 -= _270; - f32 diffMag = PSVECMag(&stack_110); - f32 vMag = PSVECMag(&mVelocity); - if (PSVECMag(&stack_128) > 2.0f * (diffMag + vMag)) { + f32 diffMag = stack_110.length(); + f32 vMag = mVelocity.length(); + if (stack_128.length() > 2.0f * (diffMag + vMag)) { mMario->stopWalk(); } } } - if (getMovementStates()._23 && PSVECMag(&mVelocity) < PSVECMag(&stack_134)) { + if (getMovementStates()._23 && mVelocity.length() < stack_134.length()) { if (stack_134.dot(getGravityVec()) < -0.0f) { TVec3f stack_110; MR::vecKillElement(mVelocity, getGravityVec(), &stack_110); if (MR::isNearZero(stack_110)) { MR::vecKillElement(stack_134, getGravityVec(), &stack_110); } - stack_110.setLength(PSVECMag(&stack_134)); // needs to be inlined + stack_110.setLength(stack_134.length()); // needs to be inlined mMario->push(stack_110); if (mMario->_3BC <= 2) { - f32 scale = PSVECMag(&stack_128); + f32 scale = stack_128.length(); if (scale > 10.0f) { scale = 10.0f; } @@ -870,7 +870,7 @@ void MarioActor::movement() { TVec3f stack_F8; f32 elementA = MR::vecKillElement(stack_134, stack_104, &stack_F8); f32 elementB = MR::vecKillElement(mVelocity, stack_104, &stack_F8); - if (PSVECMag(&mVelocity) > 20.0f && elementA < elementB * 0.5f) { + if (mVelocity.length() > 20.0f && elementA < elementB * 0.5f) { if (mMario->isAnimationRun("坂すべり下向きあおむけ")) { mMario->push(mMario->mFrontVec.scaleInline(5.0f)); } else if (mMario->isAnimationRun("坂すべり上向きうつぶせ")) { @@ -1130,10 +1130,10 @@ void MarioActor::updateBehavior() { void MarioActor::updateBindRatio() { if (!_934 && !MR::isNearZero(_978 - _264)) { - f32 mag = PSVECMag(&_978); + f32 mag = _978.length(); TVec3f stack_38(_978); stack_38 -= _264; - if (mag / PSVECMag(&stack_38) < 2.0f) { + if (mag / stack_38.length() < 2.0f) { _984 += 0.1f; } else { _984 -= 0.01f; @@ -2075,13 +2075,13 @@ void MarioActor::calcAnim() { TVec3f side(footPos); side -= handPos; - f32 sideLen = PSVECMag(&side); + f32 sideLen = side.length(); MR::normalizeOrZero(&side); TVec3f tangent; - PSVECCrossProduct(&side, &_240, &tangent); + side.cross(_240, tangent); MR::normalizeOrZero(&tangent); - PSVECCrossProduct(&_240, &tangent, &side); + _240.cross(tangent, side); if (MR::normalizeOrZero(&side)) { mMario->mSideVec = side; } @@ -2301,7 +2301,7 @@ void MarioActor::calcAndSetBaseMtx() { f32 delayAngle = 0.0f; TVec3f delayAxis; if (!MR::normalizeOrZero(&delayDir)) { - PSVECCrossProduct(&mMario->mFrontVec, &delayDir, &delayAxis); + mMario->mFrontVec.cross(delayDir, delayAxis); if (!MR::normalizeOrZero(&delayAxis)) { delayAngle = MR::acosEx(_9F4.dot(delayDir)); f32 limit = table->mBeePoseDelayAngleAir; @@ -2351,7 +2351,7 @@ void MarioActor::calcAndSetBaseMtx() { if (poseAngle > poseLimit) { TVec3f poseAxis; - PSVECCrossProduct(&_9F4, &normPose, &poseAxis); + _9F4.cross(normPose, poseAxis); if (MR::normalizeOrZero(&poseAxis)) { _360 = _9F4; @@ -2767,7 +2767,7 @@ void MarioActor::updateCameraInfo() { TVec3f moveDist(mCamPos); moveDist -= camPos; - if (PSVECMag(&moveDist) > 500.0f) { + if (moveDist.length() > 500.0f) { _F74 = true; } From 22351f1a5d6b81839d35c4f1409d32c499c5140b Mon Sep 17 00:00:00 2001 From: shibbo Date: Sat, 14 Feb 2026 20:41:42 -0500 Subject: [PATCH 07/52] remove `convert.py` --- convert.py | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 convert.py diff --git a/convert.py b/convert.py deleted file mode 100644 index eb2e56164..000000000 --- a/convert.py +++ /dev/null @@ -1,12 +0,0 @@ -def convert_entry(entry): - obj_name = entry.split("[")[1].split(".o")[0] - new_path = f"JSystem/JUtility/{obj_name}.cpp" - return f'Object(NonMatching, "{new_path}"),' - -def process_file(input_filename, output_filename): - with open(input_filename, 'r') as infile, open(output_filename, 'w') as outfile: - for line in infile: - converted_line = convert_entry(line.strip()) - outfile.write(converted_line + '\n') - -process_file('input.txt', 'output.txt') From 864eb538903c58d0852cf723a16964babbf6ff49 Mon Sep 17 00:00:00 2001 From: shibbo Date: Sun, 15 Feb 2026 00:47:36 -0500 Subject: [PATCH 08/52] `DinoPackunBattleEggVs2` --- include/Game/Boss/DinoPackunBattleEggVs2.hpp | 1 + src/Game/Boss/DinoPackunBattleEggVs2.cpp | 149 +++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 src/Game/Boss/DinoPackunBattleEggVs2.cpp diff --git a/include/Game/Boss/DinoPackunBattleEggVs2.hpp b/include/Game/Boss/DinoPackunBattleEggVs2.hpp index e07c4efab..57b1c561e 100644 --- a/include/Game/Boss/DinoPackunBattleEggVs2.hpp +++ b/include/Game/Boss/DinoPackunBattleEggVs2.hpp @@ -27,4 +27,5 @@ class DinoPackunBattleEggVs2 : public DinoPackunAction { DinoPackunStateDamage* mStateDamage; // 0x14 DinoPackunTrackFireHolder* mTrackFireHolder; // 0x18 DinoPackunStateFire* mStateFire; // 0x1C + f32 _20; }; diff --git a/src/Game/Boss/DinoPackunBattleEggVs2.cpp b/src/Game/Boss/DinoPackunBattleEggVs2.cpp new file mode 100644 index 000000000..3c0e48f19 --- /dev/null +++ b/src/Game/Boss/DinoPackunBattleEggVs2.cpp @@ -0,0 +1,149 @@ +#include "Game/Boss/DinoPackunBattleEggVs2.hpp" +#include "Game/Boss/DinoPackun.hpp" +#include "Game/Boss/DinoPackunStateDamage.hpp" +#include "Game/Boss/DinoPackunStateFire.hpp" +#include "Game/Boss/DinoPackunTail.hpp" +#include "Game/Boss/DinoPackunTrackFire.hpp" +#include "Game/LiveActor/HitSensor.hpp" + +namespace { + static TVec3f sEggOutPosition = TVec3f(0.0f, 60.0f, -320.0f); +}; + +namespace NrvDinoPackunBattleEgg { + NEW_NERVE(DinoPackunBattleEggVs2NrvTurn, DinoPackunBattleEggVs2, Turn); + NEW_NERVE(DinoPackunBattleEggVs2NrvWalk, DinoPackunBattleEggVs2, Walk); + NEW_NERVE(DinoPackunBattleEggVs2NrvDamage, DinoPackunBattleEggVs2, Damage); +}; // namespace NrvDinoPackunBattleEgg + +DinoPackunBattleEggVs2::DinoPackunBattleEggVs2(DinoPackun* pPackun) : DinoPackunAction("2回戦卵バトル", pPackun) { + mStateDamage = nullptr; + mTrackFireHolder = nullptr; + mStateFire = nullptr; + _20 = 1.0f; +} + +void DinoPackunBattleEggVs2::setTrackFire(DinoPackunTrackFireHolder* pHolder) { + mTrackFireHolder = pHolder; +} + +void DinoPackunBattleEggVs2::init() { + initNerve(&NrvDinoPackunBattleEgg::DinoPackunBattleEggVs2NrvTurn::sInstance); + mStateDamage = new DinoPackunStateDamage(getHost()); + mStateDamage->setDamageEgg(); + mStateFire = new DinoPackunStateFire(getHost()); + mStateFire->init(); +} + +void DinoPackunBattleEggVs2::appear() { + mIsDead = false; + getHost()->mTail->lockNodePosition(1); + mStateFire->requestFireDirect(); + setNerve(&NrvDinoPackunBattleEgg::DinoPackunBattleEggVs2NrvTurn::sInstance); +} + +void DinoPackunBattleEggVs2::control() { + mStateFire->update(); +} + +void DinoPackunBattleEggVs2::attackSensor(HitSensor* a1, HitSensor* a2) { + if (getHost()->isSensorEgg(a1)) { + if (MR::isSensorPlayer(a2)) { + if (!MR::sendMsgEnemyAttackFire(a2, a1)) { + if (MR::sendMsgPush(a2, a1)) { + return; + } + } + } else if (!MR::sendMsgEnemyAttack(a2, a1)) { + if (MR::sendMsgPush(a2, a1)) { + return; + } + } + } +} + +bool DinoPackunBattleEggVs2::receiveMsgPlayerAttack(u32 msg, HitSensor* a2, HitSensor* a3) { + return (!getHost()->isSensorEgg(a3) ? false : MR::isMsgStarPieceReflect(msg)); +} + +bool DinoPackunBattleEggVs2::receiveMsgPush(HitSensor* a1, HitSensor* a2) { + return getHost()->isSensorEgg(a2); +} + +bool DinoPackunBattleEggVs2::receiveOtherMsg(u32 msg, HitSensor* a2, HitSensor* a3) { + if (isNerve(&NrvDinoPackunBattleEgg::DinoPackunBattleEggVs2NrvDamage::sInstance)) { + if (mStateDamage->receiveOtherMsg(msg, a2, a3)) { + mStateFire->requestCool(); + return true; + } + } else if (mStateDamage->isDamageMessage(msg)) { + mTrackFireHolder->killAll(); + setNerve(&NrvDinoPackunBattleEgg::DinoPackunBattleEggVs2NrvDamage::sInstance); + return true; + } + + return false; +} + +void DinoPackunBattleEggVs2::exeTurn() { + if (MR::isFirstStep(this)) { + MR::startBck(getHost(), "EggWalk", nullptr); + MR::startSound(getHost(), "SE_BV_D_PAKKUN_EGG_WALK", -1, -1); + MR::startSound(getHost(), "SE_BM_D_PAKKUN_LAVER", -1, -1); + } + + getHost()->adjustTailRootPosition(sEggOutPosition, 1.0f); + + if (updateTurn(30, 1.5f)) { + setNerve(&NrvDinoPackunBattleEgg::DinoPackunBattleEggVs2NrvWalk::sInstance); + } +} + +void DinoPackunBattleEggVs2::exeWalk() { + if (MR::isFirstStep(this)) { + MR::startBck(getHost(), "EggWalk", nullptr); + getHost()->mTail->_C = 1.5f; + } + + getHost()->adjustTailRootPosition(sEggOutPosition, 1.0f); + + s32 step = getNerveStep(); + f32 v3; + + s32 div = (step / 100); + if (div % 2 != 0) { + v3 = 1.0f; + } else { + v3 = -1.0f; + } + + MR::rotateDirectionGravityDegree(getHost(), &getHost()->_E8, (0.75f * v3)); + s32 v4 = getNerveStep() % 200; + if (v4 < 80) { + mStateFire->requestFire(); + } else { + if (v4 >= 180) { + mStateFire->requestFireSign(); + } else { + mStateFire->requestCool(); + } + } + + if (updateWalk(750, 0.89f, 40)) { + setNerve(&NrvDinoPackunBattleEgg::DinoPackunBattleEggVs2NrvTurn::sInstance); + } +} + +void DinoPackunBattleEggVs2::exeDamage() { + if (MR::isFirstStep(this)) { + getHost()->mTail->_C = 1.0f; + } + + if (MR::updateActorState(this, mStateDamage)) { + kill(); + } +} + +DinoPackunBattleEggVs2::~DinoPackunBattleEggVs2() { + return; +} From a568cd8c9437cfcad359c8269acd02dfab595241 Mon Sep 17 00:00:00 2001 From: shibbo Date: Sun, 15 Feb 2026 01:22:31 -0500 Subject: [PATCH 09/52] `DinoPackunBattleVs1Lv1` --- src/Game/Boss/DinoPackunBattleVs1Lv1.cpp | 193 +++++++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 src/Game/Boss/DinoPackunBattleVs1Lv1.cpp diff --git a/src/Game/Boss/DinoPackunBattleVs1Lv1.cpp b/src/Game/Boss/DinoPackunBattleVs1Lv1.cpp new file mode 100644 index 000000000..bbcf4fc9b --- /dev/null +++ b/src/Game/Boss/DinoPackunBattleVs1Lv1.cpp @@ -0,0 +1,193 @@ +#include "Game/Boss/DinoPackunBattleVs1Lv1.hpp" +#include "Game/Boss/DinoPackun.hpp" +#include "Game/Boss/DinoPackunStateDamage.hpp" +#include "Game/Util.hpp" + +namespace NrvDinoPackunBattleVs1Lv1 { + NEW_NERVE(DinoPackunBattleVs1Lv1NrvStart, DinoPackunBattleVs1Lv1, Start); + NEW_NERVE(DinoPackunBattleVs1Lv1NrvTurn, DinoPackunBattleVs1Lv1, Turn); + NEW_NERVE(DinoPackunBattleVs1Lv1NrvWalk, DinoPackunBattleVs1Lv1, Walk); + NEW_NERVE(DinoPackunBattleVs1Lv1NrvFind, DinoPackunBattleVs1Lv1, Find); + NEW_NERVE(DinoPackunBattleVs1Lv1NrvChase, DinoPackunBattleVs1Lv1, Chase); + NEW_NERVE(DinoPackunBattleVs1Lv1NrvCoolDown, DinoPackunBattleVs1Lv1, CoolDown); + NEW_NERVE(DinoPackunBattleVs1Lv1NrvAttackHit, DinoPackunBattleVs1Lv1, AttackHit); + NEW_NERVE(DinoPackunBattleVs1Lv1NrvDamage, DinoPackunBattleVs1Lv1, Damage); +}; // namespace NrvDinoPackunBattleVs1Lv1 + +DinoPackunBattleVs1Lv1::DinoPackunBattleVs1Lv1(DinoPackun* pPackun) : DinoPackunAction("2戦目", pPackun) { + mStateDamage = nullptr; + initNerve(&NrvDinoPackunBattleVs1Lv1::DinoPackunBattleVs1Lv1NrvStart::sInstance); + mStateDamage = new DinoPackunStateDamage(pPackun); + mStateDamage->setDamageNormal(); +} + +void DinoPackunBattleVs1Lv1::appear() { + if (MR::isDead(getHost())) { + getHost()->makeActorAppeared(); + } + + mIsDead = false; + setNerve(&NrvDinoPackunBattleVs1Lv1::DinoPackunBattleVs1Lv1NrvStart::sInstance); +} + +void DinoPackunBattleVs1Lv1::attackSensor(HitSensor* a1, HitSensor* a2) { + if (MR::isSensorPlayer(a2)) { + if (isNerve(&NrvDinoPackunBattleVs1Lv1::DinoPackunBattleVs1Lv1NrvChase::sInstance) && sendBlowAttackMessage(a1, a2, false)) { + setNerve(&NrvDinoPackunBattleVs1Lv1::DinoPackunBattleVs1Lv1NrvAttackHit::sInstance); + return; + } + + bool v6 = false; + + if (isNerve(&NrvDinoPackunBattleVs1Lv1::DinoPackunBattleVs1Lv1NrvWalk::sInstance) || + isNerve(&NrvDinoPackunBattleVs1Lv1::DinoPackunBattleVs1Lv1NrvTurn::sInstance) || + isNerve(&NrvDinoPackunBattleVs1Lv1::DinoPackunBattleVs1Lv1NrvFind::sInstance) || + isNerve(&NrvDinoPackunBattleVs1Lv1::DinoPackunBattleVs1Lv1NrvCoolDown::sInstance)) { + v6 = true; + } + + if (v6 && sendHitAttackMessage(a1, a2, false)) { + setNerve(&NrvDinoPackunBattleVs1Lv1::DinoPackunBattleVs1Lv1NrvAttackHit::sInstance); + return; + } else { + MR::sendMsgPush(a2, a1); + } + } else { + bool v7 = false; + if (isNerve(&NrvDinoPackunBattleVs1Lv1::DinoPackunBattleVs1Lv1NrvWalk::sInstance) || + isNerve(&NrvDinoPackunBattleVs1Lv1::DinoPackunBattleVs1Lv1NrvChase::sInstance)) { + v7 = true; + } + + if (v7) { + MR::sendMsgEnemyAttack(a2, a1); + } + } +} + +bool DinoPackunBattleVs1Lv1::receiveMsgPlayerAttack(u32 msg, HitSensor* a2, HitSensor* a3) { + if (MR::isMsgLockOnStarPieceShoot(msg)) { + return true; + } + + if (MR::isMsgStarPieceAttack(msg)) { + getHost()->startHitReaction(); + return true; + } else if (MR::isMsgPlayerSpinAttack(msg) && MR::sendMsgEnemyAttackFlipWeakJump(a2, a3)) { + MR::emitEffectHitBetweenSensors(getHost(), a2, a3, 0.0f, "InvalidHitMark"); + return false; + } + + return false; +} + +bool DinoPackunBattleVs1Lv1::receiveOtherMsg(u32 msg, HitSensor* a2, HitSensor* a3) { + if (isNerve(&NrvDinoPackunBattleVs1Lv1::DinoPackunBattleVs1Lv1NrvDamage::sInstance)) { + return mStateDamage->receiveOtherMsg(msg, a2, a3); + } + + if (mStateDamage->isDamageMessage(msg)) { + setNerve(&NrvDinoPackunBattleVs1Lv1::DinoPackunBattleVs1Lv1NrvDamage::sInstance); + return true; + } + + return false; +} + +bool DinoPackunBattleVs1Lv1::tryFind() { + if (MR::isInSightConePlayer(getHost(), getHost()->_E8, 1000.0f, 80.0f)) { + setNerve(&NrvDinoPackunBattleVs1Lv1::DinoPackunBattleVs1Lv1NrvFind::sInstance); + return true; + } + + return false; +} + +void DinoPackunBattleVs1Lv1::exeStart() { + if (MR::isFirstStep(this)) { + MR::startBck(getHost(), "Find", nullptr); + } + + if (updateStart()) { + setNerve(&NrvDinoPackunBattleVs1Lv1::DinoPackunBattleVs1Lv1NrvChase::sInstance); + } +} + +void DinoPackunBattleVs1Lv1::exeTurn() { + if (MR::isFirstStep(this)) { + if (_10 > 0.0f) { + MR::startBck(getHost(), "TurnRight", nullptr); + } else { + MR::startBck(getHost(), "TurnLeft", nullptr); + } + + MR::startSound(getHost(), "SE_BV_D_PAKKUN_EGG_WALK", -1, -1); + MR::startSound(getHost(), "SE_BM_D_PAKKUN_SLAVER", -1, -1); + } + + if (updateTurn(60, 1.0f)) { + setNerve(&NrvDinoPackunBattleVs1Lv1::DinoPackunBattleVs1Lv1NrvWalk::sInstance); + } else { + if (tryFind()) { + return; + } + } +} + +void DinoPackunBattleVs1Lv1::exeWalk() { + if (MR::isFirstStep(this)) { + MR::startBck(getHost(), "Walk", nullptr); + } + + if (updateWalk(180, 0.5f, 91)) { + setNerve(&NrvDinoPackunBattleVs1Lv1::DinoPackunBattleVs1Lv1NrvTurn::sInstance); + } else { + if (tryFind()) { + return; + } + } +} + +void DinoPackunBattleVs1Lv1::exeChase() { + if (MR::isFirstStep(this)) { + MR::startBck(getHost(), "Chase", nullptr); + MR::startSound(getHost(), "SE_BV_D_PAKKUN_CHASE", -1, -1); + MR::startSound(getHost(), "SE_BM_D_PAKKUN_SLAVER", -1, -1); + } + + bool isHit = getHost()->isHitReaction(15); + f32 v3 = isHit ? 0.0f : 1.5f; + f32 v4 = isHit ? 0.0f : 1.0f; + + if (updateChase(240, 180.0f, v4, v3, 60, 46)) { + setNerve(&NrvDinoPackunBattleVs1Lv1::DinoPackunBattleVs1Lv1NrvCoolDown::sInstance); + } +} + +void DinoPackunBattleVs1Lv1::exeDamage() { + if (MR::updateActorState(this, mStateDamage)) { + kill(); + } +} + +void DinoPackunBattleVs1Lv1::exeAttackHit() { + if (updateAttackHit()) { + setNerve(&NrvDinoPackunBattleVs1Lv1::DinoPackunBattleVs1Lv1NrvTurn::sInstance); + } +} + +void DinoPackunBattleVs1Lv1::exeCoolDown() { + if (updateCoolDown(0x5A)) { + setNerve(&NrvDinoPackunBattleVs1Lv1::DinoPackunBattleVs1Lv1NrvTurn::sInstance); + } +} + +void DinoPackunBattleVs1Lv1::exeFind() { + if (updateFind(0xE, 1.0f)) { + setNerve(&NrvDinoPackunBattleVs1Lv1::DinoPackunBattleVs1Lv1NrvChase::sInstance); + } +} + +DinoPackunBattleVs1Lv1::~DinoPackunBattleVs1Lv1() { + return; +} From 4d755ec9c74bab4a5d6ee362c4101ac90be75b8f Mon Sep 17 00:00:00 2001 From: shibbo Date: Sun, 15 Feb 2026 01:31:08 -0500 Subject: [PATCH 10/52] link in some `DinoPackun` files --- configure.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/configure.py b/configure.py index 191f56c0e..90f73808a 100644 --- a/configure.py +++ b/configure.py @@ -731,23 +731,23 @@ def JSys_J3DLib(lib_name: str, objects: List[Object]) -> Dict[str, Any]: Object(NonMatching, "Game/Boss/DinoPackunAction.cpp"), Object(NonMatching, "Game/Boss/DinoPackunBall.cpp"), Object(NonMatching, "Game/Boss/DinoPackunBattleEgg.cpp"), - Object(NonMatching, "Game/Boss/DinoPackunBattleEggVs2.cpp"), - Object(NonMatching, "Game/Boss/DinoPackunBattleVs1Lv1.cpp"), + Object(Matching, "Game/Boss/DinoPackunBattleEggVs2.cpp"), + Object(Matching, "Game/Boss/DinoPackunBattleVs1Lv1.cpp"), Object(NonMatching, "Game/Boss/DinoPackunBattleVs1Lv2.cpp"), Object(NonMatching, "Game/Boss/DinoPackunBattleVs2Lv1.cpp"), - Object(NonMatching, "Game/Boss/DinoPackunDemo.cpp"), - Object(NonMatching, "Game/Boss/DinoPackunDemoPosition.cpp"), + Object(Matching, "Game/Boss/DinoPackunDemo.cpp"), + Object(Matching, "Game/Boss/DinoPackunDemoPosition.cpp"), Object(NonMatching, "Game/Boss/DinoPackunEggShell.cpp"), - Object(NonMatching, "Game/Boss/DinoPackunFire.cpp"), + Object(Matching, "Game/Boss/DinoPackunFire.cpp"), Object(NonMatching, "Game/Boss/DinoPackunSequencer.cpp"), - Object(NonMatching, "Game/Boss/DinoPackunStateAwake.cpp"), + Object(Matching, "Game/Boss/DinoPackunStateAwake.cpp"), Object(NonMatching, "Game/Boss/DinoPackunStateDamage.cpp"), Object(NonMatching, "Game/Boss/DinoPackunStateFire.cpp"), Object(NonMatching, "Game/Boss/DinoPackunTail.cpp"), Object(NonMatching, "Game/Boss/DinoPackunTailNode.cpp"), Object(NonMatching, "Game/Boss/DinoPackunTailPart.cpp"), - Object(NonMatching, "Game/Boss/DinoPackunTailRoot.cpp"), - Object(NonMatching, "Game/Boss/DinoPackunTrackFire.cpp"), + Object(Matching, "Game/Boss/DinoPackunTailRoot.cpp"), + Object(Matching, "Game/Boss/DinoPackunTrackFire.cpp"), Object(NonMatching, "Game/Boss/DinoPackunVs1.cpp"), Object(NonMatching, "Game/Boss/DinoPackunVs2.cpp"), Object(NonMatching, "Game/Boss/Dodoryu.cpp"), From ad82b03bf96ec6c94a12726fdfd6fcb5e6197631 Mon Sep 17 00:00:00 2001 From: shibbo Date: Sun, 15 Feb 2026 01:39:12 -0500 Subject: [PATCH 11/52] some `bte` files linked --- configure.py | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/configure.py b/configure.py index 90f73808a..3106eacd7 100644 --- a/configure.py +++ b/configure.py @@ -2351,11 +2351,11 @@ def JSys_J3DLib(lib_name: str, objects: List[Object]) -> Dict[str, Any]: "bte", [ Object(NonMatching, "RVL_SDK/bte/gki_buffer.c"), - Object(NonMatching, "RVL_SDK/bte/gki_time.c"), - Object(NonMatching, "RVL_SDK/bte/gki_ppc.c"), - Object(NonMatching, "RVL_SDK/bte/hcisu_h2.c"), - Object(NonMatching, "RVL_SDK/bte/bta_dm_cfg.c"), - Object(NonMatching, "RVL_SDK/bte/bta_hh_cfg.c"), + Object(Matching, "RVL_SDK/bte/gki_time.c"), + Object(Matching, "RVL_SDK/bte/gki_ppc.c"), + Object(Matching, "RVL_SDK/bte/hcisu_h2.c"), + Object(Matching, "RVL_SDK/bte/bta_dm_cfg.c"), + Object(Matching, "RVL_SDK/bte/bta_hh_cfg.c"), Object(NonMatching, "RVL_SDK/bte/bta_sys_cfg.c"), Object(NonMatching, "RVL_SDK/bte/uusb_ppc.c"), Object(NonMatching, "RVL_SDK/bte/bte_hcisu.c"), @@ -2379,8 +2379,8 @@ def JSys_J3DLib(lib_name: str, objects: List[Object]) -> Dict[str, Any]: Object(NonMatching, "RVL_SDK/bte/btm_acl.c"), Object(NonMatching, "RVL_SDK/bte/btm_dev.c"), Object(NonMatching, "RVL_SDK/bte/btm_devctl.c"), - Object(NonMatching, "RVL_SDK/bte/btm_discovery.c"), - Object(NonMatching, "RVL_SDK/bte/btm_inq.c"), + Object(Matching, "RVL_SDK/bte/btm_discovery.c"), + Object(Matching, "RVL_SDK/bte/btm_inq.c"), Object(NonMatching, "RVL_SDK/bte/btm_main.c"), Object(NonMatching, "RVL_SDK/bte/btm_pm.c"), Object(NonMatching, "RVL_SDK/bte/btm_sco.c"), @@ -2393,16 +2393,16 @@ def JSys_J3DLib(lib_name: str, objects: List[Object]) -> Dict[str, Any]: Object(NonMatching, "RVL_SDK/bte/gap_utils.c"), Object(NonMatching, "RVL_SDK/bte/hcicmds.c"), Object(NonMatching, "RVL_SDK/bte/hidd_api.c"), - Object(NonMatching, "RVL_SDK/bte/hidd_conn.c"), - Object(NonMatching, "RVL_SDK/bte/hidd_mgmt.c"), - Object(NonMatching, "RVL_SDK/bte/hidd_pm.c"), + Object(Matching, "RVL_SDK/bte/hidd_conn.c"), + Object(Matching, "RVL_SDK/bte/hidd_mgmt.c"), + Object(Matching, "RVL_SDK/bte/hidd_pm.c"), Object(NonMatching, "RVL_SDK/bte/hidh_api.c"), Object(NonMatching, "RVL_SDK/bte/hidh_conn.c"), - Object(NonMatching, "RVL_SDK/bte/l2c_api.c"), - Object(NonMatching, "RVL_SDK/bte/l2c_csm.c"), - Object(NonMatching, "RVL_SDK/bte/l2c_link.c"), - Object(NonMatching, "RVL_SDK/bte/l2c_main.c"), - Object(NonMatching, "RVL_SDK/bte/l2c_utils.c"), + Object(Matching, "RVL_SDK/bte/l2c_api.c"), + Object(Matching, "RVL_SDK/bte/l2c_csm.c"), + Object(Matching, "RVL_SDK/bte/l2c_link.c"), + Object(Matching, "RVL_SDK/bte/l2c_main.c"), + Object(Matching, "RVL_SDK/bte/l2c_utils.c"), Object(NonMatching, "RVL_SDK/bte/port_api.c"), Object(NonMatching, "RVL_SDK/bte/port_rfc.c"), Object(NonMatching, "RVL_SDK/bte/port_utils.c"), @@ -2412,10 +2412,10 @@ def JSys_J3DLib(lib_name: str, objects: List[Object]) -> Dict[str, Any]: Object(NonMatching, "RVL_SDK/bte/rfc_port_if.c"), Object(NonMatching, "RVL_SDK/bte/rfc_ts_frames.c"), Object(NonMatching, "RVL_SDK/bte/rfc_utils.c"), - Object(NonMatching, "RVL_SDK/bte/sdp_api.c"), - Object(NonMatching, "RVL_SDK/bte/sdp_db.c"), - Object(NonMatching, "RVL_SDK/bte/sdp_discovery.c"), - Object(NonMatching, "RVL_SDK/bte/sdp_main.c"), + Object(Matching, "RVL_SDK/bte/sdp_api.c"), + Object(Matching, "RVL_SDK/bte/sdp_db.c"), + Object(Matching, "RVL_SDK/bte/sdp_discovery.c"), + Object(Matching, "RVL_SDK/bte/sdp_main.c"), Object(NonMatching, "RVL_SDK/bte/sdp_server.c"), Object(NonMatching, "RVL_SDK/bte/sdp_utils.c"), ], From 88d969a301bc2aa758841f215a18ed78d5721d97 Mon Sep 17 00:00:00 2001 From: shibbo Date: Sun, 15 Feb 2026 12:13:42 -0500 Subject: [PATCH 12/52] `DinoPackunBatttleVs1Lv2` --- src/Game/Boss/DinoPackunBattleVs1Lv2.cpp | 229 +++++++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 src/Game/Boss/DinoPackunBattleVs1Lv2.cpp diff --git a/src/Game/Boss/DinoPackunBattleVs1Lv2.cpp b/src/Game/Boss/DinoPackunBattleVs1Lv2.cpp new file mode 100644 index 000000000..49aede623 --- /dev/null +++ b/src/Game/Boss/DinoPackunBattleVs1Lv2.cpp @@ -0,0 +1,229 @@ +#include "Game/Boss/DinoPackunBattleVs1Lv2.hpp" +#include "Game/Boss/DinoPackun.hpp" +#include "Game/Boss/DinoPackunStateDamage.hpp" +#include "JSystem/JMath/JMath.hpp" + +namespace NrvDinoPackunBattleVs1Lv2 { + NEW_NERVE(DinoPackunBattleVs1Lv2NrvStart, DinoPackunBattleVs1Lv2, Start); + NEW_NERVE(DinoPackunBattleVs1Lv2NrvTurn, DinoPackunBattleVs1Lv2, Turn); + NEW_NERVE(DinoPackunBattleVs1Lv2NrvWalk, DinoPackunBattleVs1Lv2, Walk); + NEW_NERVE(DinoPackunBattleVs1Lv2NrvFind, DinoPackunBattleVs1Lv2, Find); + NEW_NERVE(DinoPackunBattleVs1Lv2NrvChase, DinoPackunBattleVs1Lv2, Chase); + NEW_NERVE(DinoPackunBattleVs1Lv2NrvCoolDown, DinoPackunBattleVs1Lv2, CoolDown); + NEW_NERVE(DinoPackunBattleVs1Lv2NrvAttackHit, DinoPackunBattleVs1Lv2, AttackHit); + NEW_NERVE(DinoPackunBattleVs1Lv2NrvDamage, DinoPackunBattleVs1Lv2, Damage); +}; // namespace NrvDinoPackunBattleVs1Lv2 + +DinoPackunBattleVs1Lv2::DinoPackunBattleVs1Lv2(DinoPackun* pPackun) : DinoPackunAction("ラス", pPackun) { + mStateDamage = nullptr; + _18 = 1; + initNerve(&NrvDinoPackunBattleVs1Lv2::DinoPackunBattleVs1Lv2NrvStart::sInstance); + mStateDamage = new DinoPackunStateDamage(pPackun); + mStateDamage->setDamageNormal(); +} + +void DinoPackunBattleVs1Lv2::appear() { + if (MR::isDead(getHost())) { + getHost()->makeActorAppeared(); + } + + mIsDead = false; + + if (_18) { + setNerve(&NrvDinoPackunBattleVs1Lv2::DinoPackunBattleVs1Lv2NrvStart::sInstance); + } else { + setNerve(&NrvDinoPackunBattleVs1Lv2::DinoPackunBattleVs1Lv2NrvFind::sInstance); + } +} + +void DinoPackunBattleVs1Lv2::attackSensor(HitSensor* a1, HitSensor* a2) { + if (MR::isSensorPlayer(a2)) { + bool v6 = false; + + if (isNerve(&NrvDinoPackunBattleVs1Lv2::DinoPackunBattleVs1Lv2NrvChase::sInstance) || + isNerve(&NrvDinoPackunBattleVs1Lv2::DinoPackunBattleVs1Lv2NrvWalk::sInstance)) { + v6 = true; + } + + if (v6 && sendBlowAttackMessage(a1, a2, false)) { + setNerve(&NrvDinoPackunBattleVs1Lv2::DinoPackunBattleVs1Lv2NrvAttackHit::sInstance); + return; + } + + bool v7 = false; + + if (isNerve(&NrvDinoPackunBattleVs1Lv2::DinoPackunBattleVs1Lv2NrvTurn::sInstance) || + isNerve(&NrvDinoPackunBattleVs1Lv2::DinoPackunBattleVs1Lv2NrvFind::sInstance) || + isNerve(&NrvDinoPackunBattleVs1Lv2::DinoPackunBattleVs1Lv2NrvCoolDown::sInstance)) { + v7 = true; + } + + if (v7 && sendHitAttackMessage(a1, a2, false)) { + setNerve(&NrvDinoPackunBattleVs1Lv2::DinoPackunBattleVs1Lv2NrvAttackHit::sInstance); + return; + } + + MR::sendMsgPush(a2, a1); + } else { + bool v8 = false; + + if (isNerve(&NrvDinoPackunBattleVs1Lv2::DinoPackunBattleVs1Lv2NrvChase::sInstance) || + isNerve(&NrvDinoPackunBattleVs1Lv2::DinoPackunBattleVs1Lv2NrvWalk::sInstance)) { + v8 = true; + } + + if (v8) { + MR::sendMsgEnemyAttack(a2, a1); + } + } +} + +bool DinoPackunBattleVs1Lv2::receiveMsgPlayerAttack(u32 msg, HitSensor* a2, HitSensor* a3) { + if (MR::isMsgLockOnStarPieceShoot(msg)) { + return true; + } + + if (MR::isMsgStarPieceAttack(msg)) { + getHost()->startHitReaction(); + return true; + } else if (MR::isMsgPlayerSpinAttack(msg) && MR::sendMsgEnemyAttackFlipWeakJump(a2, a3)) { + MR::emitEffectHitBetweenSensors(getHost(), a2, a3, 0.0f, "InvalidHitMark"); + return false; + } + + return false; +} + +bool DinoPackunBattleVs1Lv2::receiveOtherMsg(u32 msg, HitSensor* a2, HitSensor* a3) { + if (isNerve(&NrvDinoPackunBattleVs1Lv2::DinoPackunBattleVs1Lv2NrvDamage::sInstance)) { + return mStateDamage->receiveOtherMsg(msg, a2, a3); + } + + if (mStateDamage->isDamageMessage(msg)) { + setNerve(&NrvDinoPackunBattleVs1Lv2::DinoPackunBattleVs1Lv2NrvDamage::sInstance); + return true; + } + + return false; +} + +void DinoPackunBattleVs1Lv2::setMiddleBattle() { + mStateDamage->setDamageNormal(); +} + +void DinoPackunBattleVs1Lv2::setLastBattle() { + mStateDamage->setDamageLast(); +} + +void DinoPackunBattleVs1Lv2::setStartFromDemo() { + _18 = true; +} + +void DinoPackunBattleVs1Lv2::setStartContinueBattle() { + _18 = false; +} + +bool DinoPackunBattleVs1Lv2::tryFind() { + if (MR::isInSightConePlayer(getHost(), getHost()->_E8, 1000.0f, 80.0f)) { + setNerve(&NrvDinoPackunBattleVs1Lv2::DinoPackunBattleVs1Lv2NrvFind::sInstance); + return true; + } + + return false; +} + +void DinoPackunBattleVs1Lv2::exeStart() { + if (MR::isFirstStep(this)) { + MR::startBck(getHost(), "Find", nullptr); + } + + if (updateStart()) { + setNerve(&NrvDinoPackunBattleVs1Lv2::DinoPackunBattleVs1Lv2NrvChase::sInstance); + } +} + +void DinoPackunBattleVs1Lv2::exeTurn() { + if (MR::isFirstStep(this)) { + MR::startAction(getHost(), "AngryWalk"); + MR::startSound(getHost(), "SE_BV_D_PAKKUN_EGG_WALK", -1, -1); + MR::startSound(getHost(), "SE_BM_D_PAKKUN_SLAVER", -1, -1); + } + + TVec3f side; + MR::calcSideVec(&side, getHost()); + TVec3f v7; + v7.setPS(side); + v7.x *= _10; + v7.y *= _10; + v7.z *= _10; + MR::turnDirectionDegree(getHost(), &getHost()->_E8, v7, 1.0f); + MR::addVelocityMoveToDirection(getHost(), getHost()->_E8, 1.3f); + getHost()->updateRunVelocity(); + getHost()->updateFootPrintNerve(getNerveStep(), 50); + + if (MR::isGreaterStep(this, 30)) { + setNerve(&NrvDinoPackunBattleVs1Lv2::DinoPackunBattleVs1Lv2NrvWalk::sInstance); + } else { + if (tryFind()) { + return; + } + } +} + +void DinoPackunBattleVs1Lv2::exeWalk() { + if (MR::isFirstStep(this)) { + MR::startAction(getHost(), "AngryWalk"); + } + + if (updateWalk(180, 0.5f, 50)) { + setNerve(&NrvDinoPackunBattleVs1Lv2::DinoPackunBattleVs1Lv2NrvTurn::sInstance); + } else { + if (tryFind()) { + return; + } + } +} + +void DinoPackunBattleVs1Lv2::exeChase() { + if (MR::isFirstStep(this)) { + MR::startBck(getHost(), "Chase", nullptr); + MR::startSound(getHost(), "SE_BV_D_PAKKUN_CHASE", -1, -1); + MR::startSound(getHost(), "SE_BM_D_PAKKUN_SLAVER", -1, -1); + } + + bool isHit = getHost()->isHitReaction(15); + f32 v3 = isHit ? 0.0f : 1.5f; + f32 v4 = isHit ? 0.0f : 1.0f; + + if (updateChase(300, 180.0f, v4, v3, 90, 46)) { + setNerve(&NrvDinoPackunBattleVs1Lv2::DinoPackunBattleVs1Lv2NrvCoolDown::sInstance); + } +} + +void DinoPackunBattleVs1Lv2::exeDamage() { + if (MR::updateActorState(this, mStateDamage)) { + kill(); + } +} + +void DinoPackunBattleVs1Lv2::exeAttackHit() { + if (updateAttackHit()) { + setNerve(&NrvDinoPackunBattleVs1Lv2::DinoPackunBattleVs1Lv2NrvTurn::sInstance); + } +} + +void DinoPackunBattleVs1Lv2::exeCoolDown() { + if (updateCoolDown(0x1E)) { + setNerve(&NrvDinoPackunBattleVs1Lv2::DinoPackunBattleVs1Lv2NrvTurn::sInstance); + } +} + +void DinoPackunBattleVs1Lv2::exeFind() { + if (updateFind(0xE, 1.0f)) { + setNerve(&NrvDinoPackunBattleVs1Lv2::DinoPackunBattleVs1Lv2NrvChase::sInstance); + } +} + +DinoPackunBattleVs1Lv2::~DinoPackunBattleVs1Lv2() { + return; +} From cce48079112440958173fc881fb0714938e9f2fa Mon Sep 17 00:00:00 2001 From: shibbo Date: Sun, 15 Feb 2026 14:52:57 -0500 Subject: [PATCH 13/52] `DinoPackunVs1` --- include/Game/Boss/DinoPackunSequencer.hpp | 1 + include/Game/Boss/DinoPackunVs1.hpp | 9 +- src/Game/Boss/DinoPackunSequencer.cpp | 4 +- src/Game/Boss/DinoPackunVs1.cpp | 136 ++++++++++++++++++++++ 4 files changed, 148 insertions(+), 2 deletions(-) create mode 100644 src/Game/Boss/DinoPackunVs1.cpp diff --git a/include/Game/Boss/DinoPackunSequencer.hpp b/include/Game/Boss/DinoPackunSequencer.hpp index 3e07a4ca6..2bbe041e6 100644 --- a/include/Game/Boss/DinoPackunSequencer.hpp +++ b/include/Game/Boss/DinoPackunSequencer.hpp @@ -11,6 +11,7 @@ class DinoPackunSequencer : public NerveExecutor { DinoPackunSequencer(const char*, DinoPackun*); virtual ~DinoPackunSequencer(); + virtual void start(); virtual void init(); virtual bool isUseEggShell() const; diff --git a/include/Game/Boss/DinoPackunVs1.hpp b/include/Game/Boss/DinoPackunVs1.hpp index 89d3781bf..5c79d2801 100644 --- a/include/Game/Boss/DinoPackunVs1.hpp +++ b/include/Game/Boss/DinoPackunVs1.hpp @@ -1,7 +1,10 @@ #pragma once +#include "Game/Boss/DinoPackunBattleEgg.hpp" +#include "Game/Boss/DinoPackunDemo.hpp" #include "Game/Boss/DinoPackunSequencer.hpp" +class DinoPackunBattleVs1Lv1; class DinoPackunBattleVs1Lv2; class DinoPackunVs1 : public DinoPackunSequencer { @@ -12,8 +15,9 @@ class DinoPackunVs1 : public DinoPackunSequencer { virtual void start(); virtual void init(); virtual bool isUseEggShell() const; - virtual u32 getVsCount() const; + virtual s32 getVsCount() const; + void exeWaitStart(); void exeOpeningDemo(); void exeBattleEgg(); void exeCryDemo(); @@ -23,5 +27,8 @@ class DinoPackunVs1 : public DinoPackunSequencer { void exeBattleLv3(); void exeDownDemo(); + DinoPackunDemo* mDemo; // 0x10 + DinoPackunBattleEgg* mEgg; // 0x14 + DinoPackunBattleVs1Lv1* mBattleLv1; // 0x18 DinoPackunBattleVs1Lv2* mBattleLv2; // 0x1C }; diff --git a/src/Game/Boss/DinoPackunSequencer.cpp b/src/Game/Boss/DinoPackunSequencer.cpp index 18e013d8e..ca289bc15 100644 --- a/src/Game/Boss/DinoPackunSequencer.cpp +++ b/src/Game/Boss/DinoPackunSequencer.cpp @@ -71,4 +71,6 @@ bool DinoPackunSequencer::receiveOtherMsgTail(u32 msg, HitSensor* pSender, HitSe return false; } -DinoPackunSequencer::~DinoPackunSequencer() {} +DinoPackunSequencer::~DinoPackunSequencer() { + return; +} diff --git a/src/Game/Boss/DinoPackunVs1.cpp b/src/Game/Boss/DinoPackunVs1.cpp new file mode 100644 index 000000000..7119155bc --- /dev/null +++ b/src/Game/Boss/DinoPackunVs1.cpp @@ -0,0 +1,136 @@ +#include "Game/Boss/DinoPackunVs1.hpp" +#include "Game/Boss/DinoPackun.hpp" +#include "Game/Boss/DinoPackunBattleVs1Lv1.hpp" +#include "Game/Boss/DinoPackunBattleVs1Lv2.hpp" +#include "Game/LiveActor/Nerve.hpp" + +namespace NrvDinoPackunVs1 { + NEW_NERVE(DinoPackunVs1NrvWaitStart, DinoPackunVs1, WaitStart); + NEW_NERVE(DinoPackunVs1NrvOpeningDemo, DinoPackunVs1, OpeningDemo); + NEW_NERVE(DinoPackunVs1NrvBattleEgg, DinoPackunVs1, BattleEgg); + NEW_NERVE(DinoPackunVs1NrvCryDemo, DinoPackunVs1, CryDemo); + NEW_NERVE(DinoPackunVs1NrvBattleLv1, DinoPackunVs1, BattleLv1); + NEW_NERVE(DinoPackunVs1NrvAngryDemo, DinoPackunVs1, AngryDemo); + NEW_NERVE(DinoPackunVs1NrvBattleLv2, DinoPackunVs1, BattleLv2); + NEW_NERVE(DinoPackunVs1NrvBattleLv3, DinoPackunVs1, BattleLv3); + NEW_NERVE(DinoPackunVs1NrvDownDemo, DinoPackunVs1, DownDemo); +}; // namespace NrvDinoPackunVs1 + +DinoPackunVs1::DinoPackunVs1(DinoPackun* pPackun) : DinoPackunSequencer("ディノパックン1戦目進行", pPackun) { + mDemo = nullptr; + mEgg = nullptr; + mBattleLv1 = nullptr; + mBattleLv2 = nullptr; +} + +void DinoPackunVs1::init() { + initNerve(&NrvDinoPackunVs1::DinoPackunVs1NrvWaitStart::sInstance); + mDemo = new DinoPackunDemo(mParent); + mDemo->init(); + mEgg = new DinoPackunBattleEgg(mParent); + mEgg->init(); + mBattleLv1 = new DinoPackunBattleVs1Lv1(mParent); + mBattleLv1->init(); + mBattleLv2 = new DinoPackunBattleVs1Lv2(mParent); + mBattleLv2->init(); + MR::declareStarPiece(mParent, 24); +} + +void DinoPackunVs1::start() { + if (isNerve(&NrvDinoPackunVs1::DinoPackunVs1NrvWaitStart::sInstance)) { + setNerve(&NrvDinoPackunVs1::DinoPackunVs1NrvOpeningDemo::sInstance); + } +} + +void DinoPackunVs1::exeOpeningDemo() { + if (MR::isFirstStep(this)) { + mCurrentAction = nullptr; + mDemo->startOpeningDemo(); + } + + MR::updateActorStateAndNextNerve(this, mDemo, &NrvDinoPackunVs1::DinoPackunVs1NrvBattleEgg::sInstance); +} + +void DinoPackunVs1::exeBattleEgg() { + if (MR::isFirstStep(this)) { + mCurrentAction = mEgg; + } + + MR::updateActorStateAndNextNerve(this, mEgg, &NrvDinoPackunVs1::DinoPackunVs1NrvCryDemo::sInstance); +} + +void DinoPackunVs1::exeCryDemo() { + if (MR::isFirstStep(this)) { + mCurrentAction = nullptr; + mDemo->startCryDemo(); + } + + MR::updateActorStateAndNextNerve(this, mDemo, &NrvDinoPackunVs1::DinoPackunVs1NrvBattleLv1::sInstance); +} + +void DinoPackunVs1::exeBattleLv1() { + if (MR::isFirstStep(this)) { + mParent->appearStarPiece(8); + mCurrentAction = mBattleLv1; + } + + MR::updateActorStateAndNextNerve(this, mBattleLv1, &NrvDinoPackunVs1::DinoPackunVs1NrvAngryDemo::sInstance); +} + +void DinoPackunVs1::exeAngryDemo() { + if (MR::isFirstStep(this)) { + mCurrentAction = nullptr; + mDemo->startAngryDemo(); + } + + MR::updateActorStateAndNextNerve(this, mDemo, &NrvDinoPackunVs1::DinoPackunVs1NrvBattleLv2::sInstance); +} + +void DinoPackunVs1::exeBattleLv2() { + if (MR::isFirstStep(this)) { + mParent->appearStarPiece(8); + mBattleLv2->setMiddleBattle(); + mBattleLv2->setStartFromDemo(); + mCurrentAction = mBattleLv2; + } + + MR::updateActorStateAndNextNerve(this, mBattleLv2, &NrvDinoPackunVs1::DinoPackunVs1NrvBattleLv3::sInstance); +} + +void DinoPackunVs1::exeBattleLv3() { + if (MR::isFirstStep(this)) { + mParent->appearStarPiece(8); + mBattleLv2->setLastBattle(); + mBattleLv2->setStartContinueBattle(); + mCurrentAction = mBattleLv2; + } + + MR::updateActorStateAndNextNerve(this, mBattleLv2, &NrvDinoPackunVs1::DinoPackunVs1NrvDownDemo::sInstance); +} + +void DinoPackunVs1::exeDownDemo() { + if (MR::isFirstStep(this)) { + mCurrentAction = nullptr; + mDemo->startDownDemo(); + } + + if (MR::updateActorState(this, mDemo)) { + return; + } +} + +void DinoPackunVs1::exeWaitStart() { + return; +} + +DinoPackunVs1::~DinoPackunVs1() { + return; +} + +s32 DinoPackunVs1::getVsCount() const { + return 1; +} + +bool DinoPackunVs1::isUseEggShell() const { + return true; +} From 654908976e5c33afaeb111afde3d08c8a7fd71ed Mon Sep 17 00:00:00 2001 From: shibbo Date: Sun, 15 Feb 2026 17:09:18 -0500 Subject: [PATCH 14/52] `DinoPackunBattleVs2Lv1` --- include/Game/Boss/DinoPackunBattleVs2Lv1.hpp | 21 +- src/Game/Boss/DinoPackunBattleVs2Lv1.cpp | 465 +++++++++++++++++++ 2 files changed, 482 insertions(+), 4 deletions(-) create mode 100644 src/Game/Boss/DinoPackunBattleVs2Lv1.cpp diff --git a/include/Game/Boss/DinoPackunBattleVs2Lv1.hpp b/include/Game/Boss/DinoPackunBattleVs2Lv1.hpp index b49ff0205..5b8ddfd64 100644 --- a/include/Game/Boss/DinoPackunBattleVs2Lv1.hpp +++ b/include/Game/Boss/DinoPackunBattleVs2Lv1.hpp @@ -1,11 +1,13 @@ #pragma once #include "Game/Boss/DinoPackunAction.hpp" +#include "JSystem/JGeometry/TVec.hpp" class DinoPackunStateDamage; class DinoPackunTrackFireHolder; class DinoPackunFireHolder; class DinoPackunStateAwake; +class DinoPackunStateFire; class DinoPackunBattleVs2Lv1 : public DinoPackunAction { public: @@ -25,21 +27,32 @@ class DinoPackunBattleVs2Lv1 : public DinoPackunAction { void setLastBattle(); bool tryAwake(); void exeWalk(); - void endWalk(); + void endWalk() NO_INLINE; void exeTurn(); void exeFindCrazy(); void exeCrazy(); - void endCrazy(); + void endCrazy() NO_INLINE; void exeChase(); - void endChase(); + void endChase() NO_INLINE; void exeAttackHit(); - void updateOnOffFireTrail(s32, s32, s32); + void updateOnOffFireTail(s32, s32, s32); bool emitFireMouth(); bool emitFireTail(); inline void exeDamage(); + void exeAwake(); + void endAwake(); DinoPackunStateDamage* mStateDamage; // 0x14 DinoPackunStateAwake* mStateAwake; // 0x18 DinoPackunTrackFireHolder* mTrackFireHolder; // 0x1C DinoPackunFireHolder* mFireHolder; // 0x20 + DinoPackunStateFire* mStateFire; // 0x24 + TVec3f _28; + s32 _34; + u8 _38; + u8 _39; + u8 _3A; + u8 _3B; + u8 _3C; + u8 _3D; }; diff --git a/src/Game/Boss/DinoPackunBattleVs2Lv1.cpp b/src/Game/Boss/DinoPackunBattleVs2Lv1.cpp new file mode 100644 index 000000000..c8ed0434f --- /dev/null +++ b/src/Game/Boss/DinoPackunBattleVs2Lv1.cpp @@ -0,0 +1,465 @@ +#include "Game/Boss/DinoPackunBattleVs2Lv1.hpp" +#include "Game/Boss/DinoPackun.hpp" +#include "Game/Boss/DinoPackunBall.hpp" +#include "Game/Boss/DinoPackunFire.hpp" +#include "Game/Boss/DinoPackunStateAwake.hpp" +#include "Game/Boss/DinoPackunStateDamage.hpp" +#include "Game/Boss/DinoPackunStateFire.hpp" +#include "Game/Boss/DinoPackunTail.hpp" +#include "Game/Boss/DinoPackunTrackFire.hpp" +#include "Game/LiveActor/Nerve.hpp" +#include "Game/Util/LiveActorUtil.hpp" + +namespace { + static TVec3f sShotMouthFireOffset = TVec3f(150.0f, 150.0f, 0.0f); +}; + +namespace NrvDinoPackunBattleVs2Lv1 { + NEW_NERVE(DinoPackunBattleVs2Lv1NrvTurn, DinoPackunBattleVs2Lv1, Turn); + NEW_NERVE_ONEND(DinoPackunBattleVs2Lv1NrvWalk, DinoPackunBattleVs2Lv1, Walk, Walk); + NEW_NERVE(DinoPackunBattleVs2Lv1NrvFindCrazy, DinoPackunBattleVs2Lv1, FindCrazy); + NEW_NERVE_ONEND(DinoPackunBattleVs2Lv1NrvCrazy, DinoPackunBattleVs2Lv1, Crazy, Crazy); + NEW_NERVE_ONEND(DinoPackunBattleVs2Lv1NrvChase, DinoPackunBattleVs2Lv1, Chase, Chase); + NEW_NERVE_ONEND(DinoPackunBattleVs2Lv1NrvAwake, DinoPackunBattleVs2Lv1, Awake, Awake); + NEW_NERVE(DinoPackunBattleVs2Lv1NrvAttackHit, DinoPackunBattleVs2Lv1, AttackHit); + NEW_NERVE(DinoPackunBattleVs2Lv1NrvDamage, DinoPackunBattleVs2Lv1, Damage); +}; // namespace NrvDinoPackunBattleVs2Lv1 + +DinoPackunBattleVs2Lv1::DinoPackunBattleVs2Lv1(DinoPackun* pPackun) : DinoPackunAction("ラスト", pPackun) { + mStateDamage = nullptr; + mStateAwake = nullptr; + mTrackFireHolder = nullptr; + mFireHolder = nullptr; + mStateFire = nullptr; + _28.x = 0.0f; + _28.y = 0.0f; + _28.z = 0.0f; + _34 = 0; + _38 = 0; + _39 = 0; + _3A = 0; + _3B = 0; + _3C = 0; + _3D = 0; +} + +void DinoPackunBattleVs2Lv1::setTrackFire(DinoPackunTrackFireHolder* pHolder) { + mTrackFireHolder = pHolder; +} + +void DinoPackunBattleVs2Lv1::setFireBall(DinoPackunFireHolder* pHolder) { + mFireHolder = pHolder; +} + +void DinoPackunBattleVs2Lv1::setMiddleBattle() { + mStateDamage->setDamageNormal(); +} + +void DinoPackunBattleVs2Lv1::setLastBattle() { + mStateDamage->setDamageLast(); +} + +void DinoPackunBattleVs2Lv1::init() { + initNerve(&NrvDinoPackunBattleVs2Lv1::DinoPackunBattleVs2Lv1NrvAwake::sInstance); + mStateDamage = new DinoPackunStateDamage(getHost()); + mStateDamage->setDamageLast(); + mStateDamage->init(); + mStateAwake = new DinoPackunStateAwake(getHost()); + mStateAwake->init(); + mStateFire = new DinoPackunStateFire(getHost()); + mStateFire->init(); +} + +void DinoPackunBattleVs2Lv1::appear() { + if (MR::isDead(getHost())) { + getHost()->makeActorAppeared(); + } + + mIsDead = false; + if (_3C) { + mStateFire->requestFireDirect(); + } + + if (_3D) { + setNerve(&NrvDinoPackunBattleVs2Lv1::DinoPackunBattleVs2Lv1NrvFindCrazy::sInstance); + } else { + setNerve(&NrvDinoPackunBattleVs2Lv1::DinoPackunBattleVs2Lv1NrvAwake::sInstance); + } +} + +void DinoPackunBattleVs2Lv1::control() { + mStateFire->update(); +} + +void DinoPackunBattleVs2Lv1::attackSensor(HitSensor* pSender, HitSensor* pReceiver) { + if (MR::isSensorPlayer(pReceiver)) { + bool v6 = false; + + if (isNerve(&NrvDinoPackunBattleVs2Lv1::DinoPackunBattleVs2Lv1NrvChase::sInstance) || + isNerve(&NrvDinoPackunBattleVs2Lv1::DinoPackunBattleVs2Lv1NrvWalk::sInstance) || + isNerve(&NrvDinoPackunBattleVs2Lv1::DinoPackunBattleVs2Lv1NrvCrazy::sInstance)) { + v6 = true; + } + + if (v6) { + if (sendBlowAttackMessage(pSender, pReceiver, mStateFire->isFire())) { + if (_3D) { + return; + } + + setNerve(&NrvDinoPackunBattleVs2Lv1::DinoPackunBattleVs2Lv1NrvAttackHit::sInstance); + return; + } + } + + bool v8 = false; + if (isNerve(&NrvDinoPackunBattleVs2Lv1::DinoPackunBattleVs2Lv1NrvTurn::sInstance) || + isNerve(&NrvDinoPackunBattleVs2Lv1::DinoPackunBattleVs2Lv1NrvAwake::sInstance)) { + v8 = true; + } + + if (v8 && sendHitAttackMessage(pSender, pReceiver, mStateFire->isFire())) { + if (!_3D) { + setNerve(&NrvDinoPackunBattleVs2Lv1::DinoPackunBattleVs2Lv1NrvAttackHit::sInstance); + } + } else { + MR::sendMsgPush(pReceiver, pSender); + } + } else { + bool v10 = false; + if (isNerve(&NrvDinoPackunBattleVs2Lv1::DinoPackunBattleVs2Lv1NrvChase::sInstance) || + isNerve(&NrvDinoPackunBattleVs2Lv1::DinoPackunBattleVs2Lv1NrvWalk::sInstance) || + isNerve(&NrvDinoPackunBattleVs2Lv1::DinoPackunBattleVs2Lv1NrvCrazy::sInstance)) { + v10 = true; + } + + if (v10) { + MR::sendMsgEnemyAttack(pReceiver, pSender); + } + } +} + +bool DinoPackunBattleVs2Lv1::receiveMsgPlayerAttack(u32 msg, HitSensor* pSender, HitSensor* pReceiver) { + if (MR::isMsgStarPieceReflect(msg)) { + getHost()->startHitReaction(); + return true; + } else if (MR::isMsgPlayerSpinAttack(msg) && MR::sendMsgEnemyAttackFlipWeakJump(pSender, pReceiver)) { + MR::emitEffectHitBetweenSensors(getHost(), pSender, pReceiver, 0.0f, "InvalidHitMark"); + return false; + } + + return false; +} + +bool DinoPackunBattleVs2Lv1::receiveOtherMsg(u32 msg, HitSensor* pSender, HitSensor* pReceiver) { + if (isNerve(&NrvDinoPackunBattleVs2Lv1::DinoPackunBattleVs2Lv1NrvDamage::sInstance)) { + if (mStateDamage->receiveOtherMsg(msg, pSender, pReceiver)) { + mStateFire->requestCool(); + return true; + } + } else if (mStateDamage->isDamageMessage(msg)) { + mTrackFireHolder->killAll(); + mFireHolder->killAll(); + setNerve(&NrvDinoPackunBattleVs2Lv1::DinoPackunBattleVs2Lv1NrvDamage::sInstance); + return true; + } + + return false; +} + +bool DinoPackunBattleVs2Lv1::tryAwake() { + if (MR::isInSightConePlayer(getHost(), getHost()->_E8, 1050.0f, 60.0f)) { + setNerve(&NrvDinoPackunBattleVs2Lv1::DinoPackunBattleVs2Lv1NrvAwake::sInstance); + return true; + } + + return false; +} + +DinoPackunBattleVs2Lv1::~DinoPackunBattleVs2Lv1() { + return; +} + +void DinoPackunBattleVs2Lv1::exeWalk() { + if (MR::isFirstStep(this)) { + MR::startAction(getHost(), _3B ? "AngryWalk" : "Walk"); + _34 = _34 == 0; + } + + f32 val = MR::calcNerveValue(this, 30, 1.0f, 1.5f); + getHost()->mTail->_C = val; + + if (!tryAwake()) { + s32 v3 = _3B ? 75 : 100; + s32 v4 = _3B ? 15 : 20; + f32 v5 = _3B ? 1.1f : 1.2f; + + s32 step = getNerveStep(); + s32 div = (step / v3); + f32 v7; + + if (div % 2 == _34) { + v7 = -1.0f; + } else { + v7 = 1.0f; + } + + MR::rotateDirectionGravityDegree(getHost(), &getHost()->_E8, (v5 * v7)); + updateOnOffFireTail(v3, v4, 20); + + s32 v8 = _3A ? 500 : 610; + if (updateWalk(v8, 1.0f, 50)) { + if (!_34) { + _10 = 1.0f; + } else { + _10 = -1.0f; + } + + setNerve(&NrvDinoPackunBattleVs2Lv1::DinoPackunBattleVs2Lv1NrvTurn::sInstance); + } + } +} + +void DinoPackunBattleVs2Lv1::endWalk() { + getHost()->mTail->_C = 1.0f; +} + +void DinoPackunBattleVs2Lv1::exeTurn() { + if (MR::isFirstStep(this)) { + if (_10 > 0.0f) { + MR::startAction(getHost(), "TurnRight"); + } else { + MR::startAction(getHost(), "TurnLeft"); + } + + MR::startSound(getHost(), "SE_BV_D_PAKKUN_EGG_WALK", -1, -1); + MR::startSound(getHost(), "SE_BM_D_PAKKUN_SLAVER", -1, -1); + } + + emitFireTail(); + + if (updateTurn(60, 3.0f)) { + setNerve(&NrvDinoPackunBattleVs2Lv1::DinoPackunBattleVs2Lv1NrvWalk::sInstance); + } else if (MR::isInSightFanPlayer(getHost(), getHost()->_E8, 1050.0f, 40.0f, 80.0f)) { + setNerve(&NrvDinoPackunBattleVs2Lv1::DinoPackunBattleVs2Lv1NrvAwake::sInstance); + } +} + +void DinoPackunBattleVs2Lv1::exeFindCrazy() { + if (MR::isFirstStep(this)) { + MR::startAction(getHost(), "FindCrazy"); + MR::startSound(getHost(), "SE_BV_D_PAKKUN_CHASE", -1, -1); + MR::startSound(getHost(), "SE_BM_D_PAKKUN_SLAVER", -1, -1); + mStateFire->requestFire(); + } + + MR::turnDirectionToPlayerDegree(getHost(), &getHost()->_E8, 3.0f); + MR::calcNerveRate(this, 45); + MR::addVelocityMoveToDirection(getHost(), getHost()->_E8, 0.0f); + getHost()->updateNormalVelocity(); + if (MR::isActionEnd(getHost())) { + setNerve(&NrvDinoPackunBattleVs2Lv1::DinoPackunBattleVs2Lv1NrvCrazy::sInstance); + } +} + +void DinoPackunBattleVs2Lv1::exeCrazy() { + if (MR::isFirstStep(this)) { + MR::startAction(getHost(), _39 ? "FireChase" : "Chase"); + MR::startSound(getHost(), "SE_BV_D_PAKKUN_CHASE", -1, -1); + MR::startSound(getHost(), "SE_BM_D_PAKKUN_SLAVER", -1, -1); + mStateFire->requestFire(); + } + + if (MR::checkPassBckFrame(getHost(), 32.0f) || MR::checkPassBckFrame(getHost(), 132.0f)) { + emitFireMouth(); + } + + f32 val = MR::calcNerveValue(this, 30, 1.0f, 1.5f); + getHost()->mTail->_C = val; + + if (MR::isLessStep(this, 60) || MR::isInSightConePlayer(getHost(), getHost()->_E8, 2000.0f, 45.0f)) { + MR::turnDirectionToPlayerDegree(getHost(), &getHost()->_E8, 1.0f); + } else { + s32 step = getNerveStep(); + s32 div = (step / 60); + f32 v4; + + if (div % 2 != 0) { + v4 = 1.0f; + } else { + v4 = -1.0f; + } + + MR::rotateDirectionGravityDegree(getHost(), &getHost()->_E8, (2.0f * v4)); + } + + getHost()->updateFootPrintNerve(getNerveStep(), 46); + updateOnOffFireTail(60, 10, 15); + f32 rate = MR::calcNerveRate(this, 30); + MR::addVelocityMoveToDirection(getHost(), getHost()->_E8, (1.7f * rate)); + getHost()->updateRunVelocity(); + + if (MR::isGreaterStep(this, 240)) { + if (MR::isInSightConePlayer(getHost(), getHost()->_E8, 1600.0f, 45.0f)) { + setNerve(&NrvDinoPackunBattleVs2Lv1::DinoPackunBattleVs2Lv1NrvFindCrazy::sInstance); + } + } +} + +void DinoPackunBattleVs2Lv1::endCrazy() { + getHost()->mTail->_C = 1.0f; +} + +void DinoPackunBattleVs2Lv1::exeChase() { + if (MR::isFirstStep(this)) { + const char* action = (_39) ? "FireChase" : "Chase"; + MR::startAction(getHost(), action); + MR::startSound(getHost(), "SE_BV_D_PAKKUN_CHASE", -1, -1); + MR::startSound(getHost(), "SE_BM_D_PAKKUN_SLAVER", -1, -1); + mStateFire->requestFire(); + } + + if (MR::checkPassBckFrame(getHost(), 32.0f) || MR::checkPassBckFrame(getHost(), 132.0f)) { + emitFireMouth(); + } + + f32 val = MR::calcNerveValue(this, 30, 1.0f, 1.5f); + getHost()->mTail->_C = val; + if (MR::isInSightConePlayer(getHost(), getHost()->_E8, 2000.0f, 60.0f)) { + MR::turnDirectionToPlayerDegree(getHost(), &getHost()->_E8, 1.0f); + } else { + s32 step = getNerveStep(); + s32 div = (step / 60); + f32 v4; + + if (div % 2 != 0) { + v4 = 1.0f; + } else { + v4 = -1.0f; + } + + MR::rotateDirectionGravityDegree(getHost(), &getHost()->_E8, (2.0f * v4)); + } + + getHost()->updateFootPrintNerve(getNerveStep(), 46); + emitFireTail(); + f32 rate = MR::calcNerveRate(this, 45); + MR::addVelocityMoveToDirection(getHost(), getHost()->_E8, (1.8f * rate)); + getHost()->updateRunVelocity(); + + if (MR::isGreaterStep(this, 120)) { + if (!MR::isInSightConePlayer(getHost(), getHost()->_E8, 2000.0f, 60.0f)) { + setNerve(&NrvDinoPackunBattleVs2Lv1::DinoPackunBattleVs2Lv1NrvWalk::sInstance); + } + } +} + +void DinoPackunBattleVs2Lv1::endChase() { + getHost()->mTail->_C = 1.0f; +} + +void DinoPackunBattleVs2Lv1::exeAttackHit() { + if (MR::isFirstStep(this)) { + mStateFire->requestFire(); + } + + if (updateAttackHit()) { + setNerve(&NrvDinoPackunBattleVs2Lv1::DinoPackunBattleVs2Lv1NrvTurn::sInstance); + } +} + +void DinoPackunBattleVs2Lv1::updateOnOffFireTail(s32 a1, s32 a2, s32 a3) { + s32 v8 = 2 * a1; + s32 v9 = getNerveStep() % (2 * a1); + + if (v9 < a1 - a2) { + mStateFire->requestFire(); + + } else { + if (v9 >= v8 - a3) { + mStateFire->requestFireSign(); + } else { + mStateFire->requestCool(); + } + } + + if (mStateFire->isFire()) { + emitFireTail(); + } +} + +bool DinoPackunBattleVs2Lv1::emitFireMouth() { + if (!_39) { + return false; + } + + DinoPackunFire* fire; + LiveActorGroup* group = mFireHolder; + + if (group->getDeadActor() != nullptr) { + fire = static_cast< DinoPackunFire* >(group->getDeadActor()); + } else { + fire = nullptr; + } + + if (fire == nullptr) { + return false; + } + + MtxPtr mouthMtx = MR::getJointMtx(getHost(), "DownMouth1"); + TPos3f v17; + v17.setInline(mouthMtx); + TVec3f v16; + v17.mult(sShotMouthFireOffset, v16); + TVec3f v15; + v15.set< f32 >(v17(0, 0), v17(1, 0), v17(2, 0)); + MR::normalizeOrZero(&v15); + TVec3f v12(v15); + v12.x *= 50.0f; + v12.y *= 50.0f; + v12.z *= 50.0f; + fire->appearShot(v16, v12); + MR::addVelocityJump(fire, 30.0f); + MR::addVelocity(fire, getHost()->mVelocity); + return true; +} + +bool DinoPackunBattleVs2Lv1::emitFireTail() { + if (!_38) { + return false; + } + + DinoPackunTrackFire* fire; + LiveActorGroup* group = mTrackFireHolder; + + if (group->getDeadActor() != nullptr) { + fire = static_cast< DinoPackunTrackFire* >(group->getDeadActor()); + } else { + fire = nullptr; + } + + if (fire != nullptr) { + TVec3f v7(getHost()->mBall->mPosition); + if (PSVECDistance(&_28, &v7) >= 120.0f) { + _28.setPS2(v7); + fire->appearAndSetPos(v7); + return true; + } + } + + return false; +} + +void DinoPackunBattleVs2Lv1::exeDamage() { + if (MR::updateActorState(this, mStateDamage)) { + kill(); + } +} + +void DinoPackunBattleVs2Lv1::exeAwake() { + MR::updateActorStateAndNextNerve(this, mStateAwake, &NrvDinoPackunBattleVs2Lv1::DinoPackunBattleVs2Lv1NrvChase::sInstance); +} + +void DinoPackunBattleVs2Lv1::endAwake() { + mStateAwake->kill(); +} From 1ad6934749e1145c5efef014ea253c796277db89 Mon Sep 17 00:00:00 2001 From: shibbo Date: Sun, 15 Feb 2026 17:34:20 -0500 Subject: [PATCH 15/52] `DinoPackunVs2` --- include/Game/Boss/DinoPackunVs2.hpp | 35 ++++++ src/Game/Boss/DinoPackunVs2.cpp | 161 ++++++++++++++++++++++++++++ 2 files changed, 196 insertions(+) create mode 100644 include/Game/Boss/DinoPackunVs2.hpp create mode 100644 src/Game/Boss/DinoPackunVs2.cpp diff --git a/include/Game/Boss/DinoPackunVs2.hpp b/include/Game/Boss/DinoPackunVs2.hpp new file mode 100644 index 000000000..526d19800 --- /dev/null +++ b/include/Game/Boss/DinoPackunVs2.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include "Game/Boss/DinoPackunBattleEggVs2.hpp" +#include "Game/Boss/DinoPackunBattleVs2Lv1.hpp" +#include "Game/Boss/DinoPackunDemo.hpp" +#include "Game/Boss/DinoPackunFire.hpp" +#include "Game/Boss/DinoPackunSequencer.hpp" +#include "Game/Boss/DinoPackunTrackFire.hpp" + +class DinoPackunVs2 : public DinoPackunSequencer { +public: + DinoPackunVs2(DinoPackun*); + + virtual ~DinoPackunVs2(); + virtual void start(); + virtual void init(); + virtual bool isUseEggShell() const; + virtual s32 getVsCount() const; + + void exeWaitStart(); + void exeOpeningDemo(); + void exeBattleEgg(); + void exeCryDemo(); + void exeBattleLv1(); + void exeAngryDemo(); + void exeBattleLv2(); + void exeBattleLv3(); + void exeDownDemo(); + + DinoPackunDemo* mDemo; // 0x10 + DinoPackunBattleEggVs2* mEgg; // 0x14 + DinoPackunBattleVs2Lv1* mBattleLv1; // 0x18 + DinoPackunTrackFireHolder* mTrackFireHolder; // 0x1C + DinoPackunFireHolder* mFireHolder; // 0x20 +}; diff --git a/src/Game/Boss/DinoPackunVs2.cpp b/src/Game/Boss/DinoPackunVs2.cpp new file mode 100644 index 000000000..869224647 --- /dev/null +++ b/src/Game/Boss/DinoPackunVs2.cpp @@ -0,0 +1,161 @@ +#include "Game/Boss/DinoPackunVs2.hpp" +#include "Game/Boss/DinoPackun.hpp" +#include "Game/Boss/DinoPackunBall.hpp" +#include "Game/LiveActor/PartsModel.hpp" + +namespace NrvDinoPackunVs2 { + NEW_NERVE(DinoPackunVs2NrvWaitStart, DinoPackunVs2, WaitStart); + NEW_NERVE(DinoPackunVs2NrvOpeningDemo, DinoPackunVs2, OpeningDemo); + NEW_NERVE(DinoPackunVs2NrvBattleEgg, DinoPackunVs2, BattleEgg); + NEW_NERVE(DinoPackunVs2NrvCryDemo, DinoPackunVs2, CryDemo); + NEW_NERVE(DinoPackunVs2NrvBattleLv1, DinoPackunVs2, BattleLv1); + NEW_NERVE(DinoPackunVs2NrvAngryDemo, DinoPackunVs2, AngryDemo); + NEW_NERVE(DinoPackunVs2NrvBattleLv2, DinoPackunVs2, BattleLv2); + NEW_NERVE(DinoPackunVs2NrvBattleLv3, DinoPackunVs2, BattleLv3); + NEW_NERVE(DinoPackunVs2NrvDownDemo, DinoPackunVs2, DownDemo); +}; // namespace NrvDinoPackunVs2 + +DinoPackunVs2::DinoPackunVs2(DinoPackun* pPackun) : DinoPackunSequencer("ディノパックン2戦目進行", pPackun) { + mDemo = nullptr; + mEgg = nullptr; + mBattleLv1 = nullptr; + mTrackFireHolder = nullptr; +} + +void DinoPackunVs2::init() { + initNerve(&NrvDinoPackunVs2::DinoPackunVs2NrvWaitStart::sInstance); + mTrackFireHolder = new DinoPackunTrackFireHolder(64); + mFireHolder = new DinoPackunFireHolder(16); + mDemo = new DinoPackunDemo(mParent); + mDemo->init(); + mEgg = new DinoPackunBattleEggVs2(mParent); + mEgg->setTrackFire(mTrackFireHolder); + mEgg->init(); + mBattleLv1 = new DinoPackunBattleVs2Lv1(mParent); + mBattleLv1->setTrackFire(mTrackFireHolder); + mBattleLv1->setFireBall(mFireHolder); + mBattleLv1->init(); + mParent->mBall->_124 = 1; + MR::declareStarPiece(mParent, 24); +} + +void DinoPackunVs2::start() { + if (isNerve(&NrvDinoPackunVs2::DinoPackunVs2NrvWaitStart::sInstance)) { + setNerve(&NrvDinoPackunVs2::DinoPackunVs2NrvOpeningDemo::sInstance); + } +} + +void DinoPackunVs2::exeOpeningDemo() { + if (MR::isFirstStep(this)) { + mCurrentAction = nullptr; + mDemo->startOpeningDemo(); + MR::startBrk(mParent, "Awake"); + MR::emitEffect(mParent->getBallModel(), "TailFire"); + MR::startBrk(mParent->getBallModel(), "Heat"); + } + + MR::updateActorStateAndNextNerve(this, mDemo, &NrvDinoPackunVs2::DinoPackunVs2NrvBattleEgg::sInstance); +} + +void DinoPackunVs2::exeBattleEgg() { + if (MR::isFirstStep(this)) { + mCurrentAction = mEgg; + } + + MR::updateActorStateAndNextNerve(this, mEgg, &NrvDinoPackunVs2::DinoPackunVs2NrvCryDemo::sInstance); +} + +void DinoPackunVs2::exeCryDemo() { + if (MR::isFirstStep(this)) { + mCurrentAction = nullptr; + mDemo->startCryDemo(); + } + + MR::updateActorStateAndNextNerve(this, mDemo, &NrvDinoPackunVs2::DinoPackunVs2NrvBattleLv1::sInstance); +} + +void DinoPackunVs2::exeBattleLv1() { + if (MR::isFirstStep(this)) { + mParent->appearStarPiece(8); + mBattleLv1->_38 = 0; + mBattleLv1->_39 = 0; + mBattleLv1->_3D = 0; + mBattleLv1->_3B = 0; + mBattleLv1->_3A = 0; + mBattleLv1->setMiddleBattle(); + mBattleLv1->_3C = 0; + mCurrentAction = mBattleLv1; + } + + MR::updateActorStateAndNextNerve(this, mBattleLv1, &NrvDinoPackunVs2::DinoPackunVs2NrvAngryDemo::sInstance); +} + +void DinoPackunVs2::exeAngryDemo() { + if (MR::isFirstStep(this)) { + mCurrentAction = nullptr; + mDemo->startAngryDemo(); + MR::emitEffect(mParent->getBallModel(), "TailFire"); + MR::startBrk(mParent->getBallModel(), "Heat"); + } + + MR::updateActorStateAndNextNerve(this, mDemo, &NrvDinoPackunVs2::DinoPackunVs2NrvBattleLv2::sInstance); +} + +void DinoPackunVs2::exeBattleLv2() { + if (MR::isFirstStep(this)) { + mParent->appearStarPiece(8); + mBattleLv1->_38 = 1; + mBattleLv1->_39 = 0; + mBattleLv1->_3D = 0; + mBattleLv1->_3B = 1; + mBattleLv1->_3A = 1; + mBattleLv1->setMiddleBattle(); + mBattleLv1->_3C = 1; + mCurrentAction = mBattleLv1; + } + + MR::updateActorStateAndNextNerve(this, mBattleLv1, &NrvDinoPackunVs2::DinoPackunVs2NrvBattleLv3::sInstance); +} + +void DinoPackunVs2::exeBattleLv3() { + if (MR::isFirstStep(this)) { + mParent->appearStarPiece(8); + mBattleLv1->_38 = 1; + mBattleLv1->_39 = 1; + mBattleLv1->_3D = 1; + mBattleLv1->_3B = 1; + mBattleLv1->_3A = 1; + mBattleLv1->setMiddleBattle(); + mBattleLv1->_3C = 0; + mCurrentAction = mBattleLv1; + } + + MR::updateActorStateAndNextNerve(this, mBattleLv1, &NrvDinoPackunVs2::DinoPackunVs2NrvDownDemo::sInstance); +} + +void DinoPackunVs2::exeDownDemo() { + if (MR::isFirstStep(this)) { + mCurrentAction = nullptr; + mDemo->startDownDemo(); + } + + if (MR::updateActorState(this, mDemo)) { + return; + } +} + +void DinoPackunVs2::exeWaitStart() { + return; +} + +DinoPackunVs2::~DinoPackunVs2() { + return; +} + +s32 DinoPackunVs2::getVsCount() const { + return 2; +} + +bool DinoPackunVs2::isUseEggShell() const { + return true; +} From 4da21e94fe385c46c2bb3e001393632c3c9feac6 Mon Sep 17 00:00:00 2001 From: shibbo Date: Sun, 15 Feb 2026 17:35:00 -0500 Subject: [PATCH 16/52] quick call fix in `exeBattleLv3` --- src/Game/Boss/DinoPackunVs2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Game/Boss/DinoPackunVs2.cpp b/src/Game/Boss/DinoPackunVs2.cpp index 869224647..0d9535649 100644 --- a/src/Game/Boss/DinoPackunVs2.cpp +++ b/src/Game/Boss/DinoPackunVs2.cpp @@ -125,7 +125,7 @@ void DinoPackunVs2::exeBattleLv3() { mBattleLv1->_3D = 1; mBattleLv1->_3B = 1; mBattleLv1->_3A = 1; - mBattleLv1->setMiddleBattle(); + mBattleLv1->setLastBattle(); mBattleLv1->_3C = 0; mCurrentAction = mBattleLv1; } From a16b92829d77a3be0dc1e6dbab66cc9e9d2aed54 Mon Sep 17 00:00:00 2001 From: shibbo Date: Sun, 15 Feb 2026 20:35:03 -0500 Subject: [PATCH 17/52] `DinoPackun` at 95% --- include/Game/Boss/DinoPackun.hpp | 17 + include/Game/Boss/DinoPackunSequencer.hpp | 18 +- .../include/JSystem/JGeometry/TVec.hpp | 32 +- src/Game/Boss/DinoPackun.cpp | 588 ++++++++++++++++++ src/Game/Boss/DinoPackunBattleVs2Lv1.cpp | 12 +- 5 files changed, 650 insertions(+), 17 deletions(-) create mode 100644 src/Game/Boss/DinoPackun.cpp diff --git a/include/Game/Boss/DinoPackun.hpp b/include/Game/Boss/DinoPackun.hpp index 714c9552e..7298f564e 100644 --- a/include/Game/Boss/DinoPackun.hpp +++ b/include/Game/Boss/DinoPackun.hpp @@ -14,6 +14,18 @@ class DinoPackunSequencer; class DinoPackun : public LiveActor { public: + DinoPackun(const char*); + + virtual ~DinoPackun(); + virtual void init(const JMapInfoIter&); + virtual void makeActorDead(); + virtual void control(); + virtual void calcAndSetBaseMtx(); + virtual void attackSensor(HitSensor*, HitSensor*); + virtual bool receiveMsgPush(HitSensor*, HitSensor*); + virtual bool receiveMsgPlayerAttack(u32, HitSensor*, HitSensor*); + virtual bool receiveOtherMsg(u32, HitSensor*, HitSensor*); + void initTail(); void initFootPrint(); void initDemoPosition(const JMapInfoIter&); @@ -72,3 +84,8 @@ class DinoPackun : public LiveActor { s32 _10C; u8 _110; }; + +namespace MR { + NameObj* createDinoPackunVs1(const char*); + NameObj* createDinoPackunVs2(const char*); +}; // namespace MR diff --git a/include/Game/Boss/DinoPackunSequencer.hpp b/include/Game/Boss/DinoPackunSequencer.hpp index 2bbe041e6..9b79c7873 100644 --- a/include/Game/Boss/DinoPackunSequencer.hpp +++ b/include/Game/Boss/DinoPackunSequencer.hpp @@ -12,15 +12,23 @@ class DinoPackunSequencer : public NerveExecutor { virtual ~DinoPackunSequencer(); - virtual void start(); - virtual void init(); - virtual bool isUseEggShell() const; - virtual s32 getVsCount() const; + virtual void start() { + return; + } + virtual void init() { + return; + } + virtual bool isUseEggShell() const { + return true; + } + virtual s32 getVsCount() const { + return 0; + } virtual void update(); virtual void attackSensor(HitSensor* pSender, HitSensor* pReceiver); - virtual bool receiveMsgPush(HitSensor* pSender, HitSensor* pReceiver); virtual bool receiveMsgPlayerAttack(u32 msg, HitSensor* pSender, HitSensor* pReceiver); virtual bool receiveMsgEnemyAttack(u32 msg, HitSensor* pSender, HitSensor* pReceiver); + virtual bool receiveMsgPush(HitSensor* pSender, HitSensor* pReceiver); virtual bool receiveOtherMsg(u32, HitSensor*, HitSensor*); virtual void attackSensorTail(HitSensor*, HitSensor*); virtual bool receiveMsgPlayerAttackTail(u32, HitSensor*, HitSensor*); diff --git a/libs/JSystem/include/JSystem/JGeometry/TVec.hpp b/libs/JSystem/include/JSystem/JGeometry/TVec.hpp index a5ff1ead1..54576a119 100644 --- a/libs/JSystem/include/JSystem/JGeometry/TVec.hpp +++ b/libs/JSystem/include/JSystem/JGeometry/TVec.hpp @@ -685,7 +685,12 @@ namespace JGeometry { /* General operations */ template < typename A > - void set(const JGeometry::TVec4< A >&); + void set(const JGeometry::TVec4< A >& rVec) NO_INLINE { + this->x = rVec.x; + this->y = rVec.y; + this->z = rVec.z; + this->w = rVec.w; + } template < typename A > void set(A _x, A _y, A _z, A _w) NO_INLINE { @@ -742,6 +747,18 @@ namespace JGeometry { } #endif +#ifdef __MWERKS__ + template < typename A > + inline void set(const TVec4< T >& rOther) { + TVec4< T >::set(rOther); + } +#else + template < typename A > + inline void set(const TVec4< T >& rOther) { + TVec4< T >::set(rOther); + } +#endif + /* General operations */ void normalize(); void normalize(const TQuat4< T >& rSrc); @@ -761,6 +778,19 @@ namespace JGeometry { 1.0f - this->x * this->x * 2.0f - this->y * this->y * 2.0f); } + inline void rotateVec(TVec3< T >& dst, const TVec3< T >& v) const { + float nx = -this->x; + + float v9 = (this->y * v.z) - (this->z * v.y); + float v13 = (this->w * v.y) + ((nx * v.z) + (this->z * v.x)); + float v14 = (this->w * v.z) + ((this->x * v.y) - (this->y * v.x)); + float v15 = ((nx * v.x) - (this->y * v.y)) - (this->z * v.z); + + dst.set< T >((v15 * nx) + (((this->w * v.x + v9) * this->w) + (v13 * -this->z) - (v14 * -this->y)), + (v15 * -this->y) + ((v14 * nx) + ((-(this->w * v.x + v9) * -this->z) + (v13 * this->w))), + (v15 * -this->z) + ((v14 * this->w) + (((this->w * v.x + v9) * -this->y) - (v13 * nx)))); + } + void getEuler(TVec3< T >& rDest) const; void setEuler(T _x, T _y, T _z); void setEulerZ(T _z); diff --git a/src/Game/Boss/DinoPackun.cpp b/src/Game/Boss/DinoPackun.cpp new file mode 100644 index 000000000..1a4c2767d --- /dev/null +++ b/src/Game/Boss/DinoPackun.cpp @@ -0,0 +1,588 @@ +#include "Game/Boss/DinoPackun.hpp" +#include "Game/Boss/DinoPackunBall.hpp" +#include "Game/Boss/DinoPackunDemoPosition.hpp" +#include "Game/Boss/DinoPackunEggShell.hpp" +#include "Game/Boss/DinoPackunSequencer.hpp" +#include "Game/Boss/DinoPackunTail.hpp" +#include "Game/Boss/DinoPackunTailNode.hpp" +#include "Game/Boss/DinoPackunTailPart.hpp" +#include "Game/Boss/DinoPackunTailRoot.hpp" +#include "Game/Boss/DinoPackunVs1.hpp" +#include "Game/Boss/DinoPackunVs2.hpp" +#include "Game/Camera/CameraTargetMtx.hpp" +#include "Game/Enemy/AnimScaleController.hpp" +#include "Game/LiveActor/PartsModel.hpp" +#include "Game/Util/FootPrint.hpp" +#include "Game/Util/JointController.hpp" +#include "Game/Util/LiveActorUtil.hpp" +#include "Game/Util/ScreenUtil.hpp" +#include "JSystem/JGeometry/TVec.hpp" +#include "revolution/types.h" + +namespace { + static TVec3f sHeadHitOffset = TVec3f(140.0f, -110.0f, 0.0f); + static TVec3f sBodyHitOffset = TVec3f(0.0f, 200.0f, 0.0f); + static TVec3f sEggHitOffset = TVec3f(0.0f, 200.0f, 0.0f); + static TVec3f sMarioSetLocalPos = TVec3f(0.0f, -550.0f, 800.0f); + static const char* sEventCameraName = "ダメージ"; + + static const char* sJointName[7] = {"Tail1", "Tail2", "Tail3", "Tail4", "Tail5", "Tail6", "Tail7"}; + + static f32 sKeepBendPower[7] = {30.0f, 25.0f, 20.0f, 15.0f, 10.0f, 10.0f, 10.0f}; + + static f32 sJointRadius[7] = {80.0f, 70.0f, 60.0f, 55.0f, 45.0f, 50.0f}; + + class DinoPackunParam : public AnimScaleParam { + public: + DinoPackunParam() { + _0 = 0.1f; + _10 = 30.0f; + _14 = 0.60f; + _18 = 0.059f; + _1C = 3.0f; + _20 = 0.07f; + _24 = 0.12f; + _28 = 0.92f; + } + }; + + static DinoPackunParam sParam = DinoPackunParam(); + +}; // namespace + +DinoPackun::DinoPackun(const char* pName) + : LiveActor(pName), mTail(nullptr), mBall(nullptr), mFootPrint(nullptr), mShell(nullptr), mDemoPos(nullptr), mShellBreakModel(nullptr), + mTailBall(nullptr), mCamTargetMtx(nullptr), mCameraInfo(nullptr), mSequence(nullptr), _B4(nullptr), _B8(nullptr), _BC(0.0f, 0.0f, 0.0f, 1.0f), + _E8(0, 0, 1) { + _F4 = -1; + mCameraVec.x = 0.0f; + mCameraVec.y = 0.0f; + mCameraVec.z = 0.0f; + _104 = 0.0f; + _108 = 0.0f; + _10C = -1; + _110 = 0; +} + +void DinoPackun::init(const JMapInfoIter& rIter) { + MR::initDefaultPos(this, rIter); + s32 vs = mSequence->getVsCount(); + const char* v5 = "DionPackun2"; + + if (vs == 1) { + v5 = "DionPackun"; + } + + initModelManagerWithAnm(v5, nullptr, false); + MR::connectToSceneEnemy(this); + MR::initLightCtrl(this); + MR::makeQuatAndFrontFromRotate(&_BC, &_E8, this); + _CC.set< f32 >(_BC); + _DC.set< f32 >(mPosition); + initSound(8, false); + MR::onCalcGravity(this); + initHitSensor(3); + MR::addHitSensorAtJointEnemy(this, "head", "Head", 8, 270.0f, sHeadHitOffset); + MR::addHitSensorEnemy(this, "body", 8, 200.f, sBodyHitOffset); + + if (mSequence->isUseEggShell()) { + MR::addHitSensorEnemy(this, "egg", 8, 400.0f, sEggHitOffset); + } + + initBinder(150.0f, 150.0f, 0); + initEffectKeeper(0, nullptr, false); + initCamera(rIter); + initTail(); + MR::initShadowFromCSV(this, "Shadow"); + initFootPrint(); + + if (mSequence->isUseEggShell()) { + initEggShell(); + } + + initBall(); + initScaleJointController(); + initDemoPosition(rIter); + MR::declarePowerStar(this); + MR::needStageSwitchReadA(this, rIter); + MR::useStageSwitchWriteDead(this, rIter); + MR::startBck(this, "OpeningDemo", nullptr); + MR::stopBck(this); + MR::startBtp(this, "FlowerAll"); + MR::startBrk(this, "Normal"); + MR::listenStageSwitchOnA(this, MR::Functor_Inline(this, &DinoPackun::startSequence)); + MR::addBaseMatrixFollowTarget(this, rIter, nullptr, nullptr); + + if (mSequence != nullptr) { + mSequence->init(); + } + + makeActorAppeared(); + mTail->deactivate(); +} + +void DinoPackun::initTail() { + mTail = new DinoPackunTail(9); + DinoPackunTailRoot* root = new DinoPackunTailRoot("尻尾ルート", this); + root->createJointController(this, "TailRoot"); + root->initWithoutIter(); + root->mKeepBendPower = 30.0f; + mTail->addTailNode(root); + + for (u32 i = 0; i < 7; i++) { + DinoPackunTailPart* p = new DinoPackunTailPart("尻尾ジョイント", this); + MR::copyJointPos(this, sJointName[i], &p->mPosition); + p->createJointController(this, sJointName[i]); + f32 r = sJointRadius[i]; + p->mKeepBendPower = sKeepBendPower[i]; + p->_D4 = r; + + if (i >= 3) { + p->_D9 = 0; + } + + p->initWithoutIter(); + mTail->addTailNode(p); + } + + mBall = new DinoPackunBall("尻尾先端球", this); + MR::copyJointPos(this, "TailBall", &mBall->mPosition); + mBall->mLinkLength = 120.0f; + mBall->setWeakSensor(getSensor("head")); + mBall->createJointController(this, "TailBall"); + mBall->initWithoutIter(); + mTail->addTailNode(mBall); +} + +void DinoPackun::initFootPrint() { + mFootPrint = new FootPrint("足跡", 32); + mFootPrint->setTexture(MR::getTexFromArc("DinoPackunFootprint.bti", this)); + mFootPrint->_2C = 0.0f; + mFootPrint->_30 = 100.0f; + mFootPrint->_34 = 100.0f; + mFootPrint->_38 = 10.0f; +} + +void DinoPackun::initDemoPosition(const JMapInfoIter& rIter) { + mDemoPos = new DinoPackunDemoPosition("デモ位置管理"); + mDemoPos->init(rIter); +} + +void DinoPackun::initEggShell() { + mShell = new DinoPackunEggShell("卵の殻", getSensor("head"), MR::getJointMtx(this, "EggShell")); + mShell->initWithoutIter(); + + if (mSequence->getVsCount() == 1) { + MR::startBtp(mShell, "Vs1"); + MR::startBrk(mShell, "Vs1"); + } else { + MR::startBtp(mShell, "Vs2"); + MR::startBrk(mShell, "Vs2"); + } + + mShellBreakModel = MR::createPartsModelEnemy(this, "卵の殻壊れモデル", "DinoPackunEggShellBreak", MR::getJointMtx(this, "EggShell")); + MR::initLightCtrl(mShellBreakModel); + mShellBreakModel->makeActorDead(); + if (mSequence->getVsCount() == 1) { + MR::startBtp(mShellBreakModel, "Vs1"); + } else { + MR::startBtp(mShellBreakModel, "Vs2"); + } +} + +void DinoPackun::initBall() { + mTailBall = MR::createPartsModelEnemy(this, "尻尾玉モデル", "DinoPackunTailBall", MR::getJointMtx(this, "TailBall")); + MR::startBrk(mTailBall, "Normal"); + + if (mSequence->getVsCount() == 1) { + MR::startBtp(mTailBall, "Vs1"); + } else { + MR::startBtp(mTailBall, "Vs2"); + } + + mTailBall->makeActorAppeared(); +} + +void DinoPackun::initCamera(const JMapInfoIter& rIter) { + mCameraInfo = new ActorCameraInfo(rIter); + MR::initAnimCamera(this, mCameraInfo, "OpeningDemo"); + MR::initAnimCamera(this, mCameraInfo, "CryDemo"); + MR::initAnimCamera(this, mCameraInfo, "AngryDemo"); + MR::initAnimCamera(this, mCameraInfo, "DownDemo"); + MR::initMultiActorCamera(this, rIter, &mCameraInfo, sEventCameraName); + MR::getJMapInfoArg7WithInit(rIter, &_F4); + + if (_F4 != -1) { + MR::declareCameraRegisterVec(this, _F4, &mCameraVec); + } + + mCamTargetMtx = new CameraTargetMtx("カメラターゲットダミー"); +} + +void DinoPackun::initScaleJointController() { + _B8 = new AnimScaleController(&sParam); + _B4 = MR::createJointDelegatorWithNullChildFunc(this, &DinoPackun::hitScaleJoint, "Spine1"); +} + +void DinoPackun::makeActorDead() { + LiveActor::makeActorDead(); + mTail->deactivate(); + if (MR::isValidSwitchDead(this)) { + MR::onSwitchDead(this); + } +} + +void DinoPackun::startHitReaction() { + MR::startSound(this, "SE_OJ_STAR_PIECE_HIT_STOP", -1, -1); + if (_B8 != nullptr) { + _B8->startHitReaction(); + } +} + +bool DinoPackun::isHitReaction(s32 a1) const { + if (_B8 != nullptr) { + return _B8->isHitReaction(a1); + } + return false; +} + +bool DinoPackun::hitScaleJoint(TPos3f* a1, const JointControllerInfo& a2) { + TVec3f v5(_B8->_C); + TVec3f v4; + v4.x = v5.x; + v4.y = v5.y; + v4.z = v5.z; + MR::preScaleMtx(*a1, v4); + return true; +} + +DinoPackunEggShell* DinoPackun::getEggShell() { + return mShell; +} + +PartsModel* DinoPackun::getEggBrokenModel() { + return mShellBreakModel; +} + +PartsModel* DinoPackun::getBallModel() { + return mTailBall; +} + +void DinoPackun::attackSensor(HitSensor* a1, HitSensor* a2) { + if (mSequence != nullptr) { + mSequence->attackSensor(a1, a2); + } +} + +bool DinoPackun::receiveMsgPlayerAttack(u32 msg, HitSensor* a1, HitSensor* a2) { + if (mSequence != nullptr) { + return mSequence->receiveMsgPlayerAttack(msg, a1, a2); + } + + return false; +} + +bool DinoPackun::receiveMsgPush(HitSensor* a1, HitSensor* a2) { + if (mSequence != nullptr) { + return mSequence->receiveMsgPush(a1, a2); + } + + return false; +} + +bool DinoPackun::receiveOtherMsg(u32 msg, HitSensor* a1, HitSensor* a2) { + if (mSequence != nullptr) { + return mSequence->receiveOtherMsg(msg, a1, a2); + } + + return false; +} + +void DinoPackun::attackSensorTail(HitSensor* a1, HitSensor* a2) { + if (mSequence != nullptr) { + mSequence->attackSensorTail(a1, a2); + } +} + +bool DinoPackun::receiveMsgPlayerAttackTail(u32 msg, HitSensor* a1, HitSensor* a2) { + if (mSequence != nullptr) { + return mSequence->receiveMsgPlayerAttackTail(msg, a1, a2); + } + + return false; +} + +void DinoPackun::startSequence() { + if (mSequence != nullptr) { + MR::invalidateClipping(this); + mTail->activate(); + mSequence->start(); + } +} + +void DinoPackun::control() { + if (mSequence != nullptr) { + mSequence->update(); + } + + if (_B8 != nullptr) { + _B8->updateNerve(); + } + + updatePose(); + _110 = 1; + calcAnim(); + _110 = 0; + mTail->updateJoint(); + updateCameraInfo(); +} + +void DinoPackun::calcAndSetBaseMtx() { + MR::setBaseTRMtx(this, _BC); + MR::setBaseScale(this, mScale); + + if (_110) { + mTail->registerPreCalcJointCallBack(); + } else { + mTail->registerJointCallBack(); + } + + if (_B4 != nullptr) { + _B4->registerCallBack(); + } +} + +void DinoPackun::updatePose() { + TVec3f* grav = &mGravity; + f32 v3 = mGravity.dot(_E8); + JMAVECScaleAdd(grav, &_E8, &_E8, -v3); + if (MR::isNearZero(_E8)) { + _BC.getZDir(_E8); + } else { + MR::normalize(&_E8); + } + + MR::blendQuatUpFront(&_BC, -mGravity, _E8, 0.1f, 0.2f); +} + +void DinoPackun::updateFootPrintNerve(s32 a2, s32 a3) { + TVec3f v20; + _BC.getXDir(v20); + + if (!(a2 % a3)) { + TVec3f v16 = mGravity * -100.0f; + TVec3f v17 = v20 * -100.0f; + TVec3f v18(mPosition); + v18.add(v17); + TVec3f v19(v18); + v19.add(v16); + TVec3f v11 = mGravity * 200.0f; + + TVec3f v10; + TVec3f v9; + if (MR::getFirstPolyNormalOnLineToMap(&v10, v19, v11, &v9, nullptr)) { + mFootPrint->addPrint(v9, _E8, v10, false); + } + } else { + if (a3 / 2 == a2 % a3) { + TVec3f v12 = mGravity * -100.0f; + TVec3f v13 = v20 * 100.0f; + TVec3f v14(mPosition); + v14.add(v13); + TVec3f v15(v14); + v15.add(v12); + TVec3f v8 = mGravity * 200.0f; + + TVec3f v7; + TVec3f v6; + if (MR::getFirstPolyNormalOnLineToMap(&v7, v15, v8, &v6, nullptr)) { + mFootPrint->addPrint(v6, _E8, v7, true); + } + } + } +} + +void DinoPackun::updateCameraInfo() { + if (_F4 != -1) { + f32 v2 = 0.0; + f32 v3 = (_108 + _104); + _108 += _104; + + if (v3 < 0.0f) { + v3 = v3; + } else { + v2 = 1.0f; + if (v3 > 1.0f) { + v2 = v2; + } else { + v2 = v3; + } + } + + _108 = v2; + TVec3f v6(0, 0, 0); + TVec3f v5; + _BC.getYDir(v5); + JMAVECScaleAdd(&v5, &mPosition, &v6, 300.0f); + + if (_108 > 0.0f) { + TVec3f v4; + mTail->getEndTailPosition(&v4); + MR::vecBlend(v6, v4, &v6, (0.60f * _108)); + } + + mCameraVec.set< f32 >(v6); + mCamTargetMtx->mMatrix.setTrans(v6); + } +} + +void DinoPackun::updateNormalVelocity() { + if (!MR::isBindedGround(this)) { + MR::addVelocityToGravity(this, 1.0f); + } + + if (MR::isBindedWall(this)) { + MR::reboundVelocityFromCollision(this, 0.0f, 0.0f, 1.0f); + } + + MR::attenuateVelocity(this, 0.89f); +} + +void DinoPackun::updateRunVelocity() { + updateNormalVelocity(); +} + +void DinoPackun::appearStarPiece(s32 num) { + TVec3f pos; + MR::copyJointPos(this, "Head", &pos); + MR::appearStarPieceToDirection(this, pos, -mGravity, num, 50.0f, 60.0f, false); + MR::startSound(this, "SE_OJ_STAR_PIECE_BURST", -1, -1); +} + +bool DinoPackun::isSensorEgg(const HitSensor* pSensor) const { + return getSensor("egg") == pSensor; +} + +void DinoPackun::resetPosition() { + _BC.set< f32 >(_CC); + _BC.getZDir(_E8); + MR::resetPosition(this, _DC); + MR::zeroVelocity(this); + + TPos3f v28; + v28.setRotateQuaternionInline(_BC); + v28.setTrans(mPosition); + TVec3f v27; + v28.mult(sMarioSetLocalPos, v27); + TVec3f v26; + MR::calcGravityVector(this, v27, &v26, nullptr, 0); + + TVec3f v24(mPosition); + JMathInlineVEC::PSVECSubtract(&v27, &v24, &v24); + TVec3f v25; + v25 = v24; + MR::makeMtxUpFrontPos(&v28, -v26, v25, v27); + MR::setPlayerBaseMtx(v28); +} + +void DinoPackun::adjustTailRootPosition(const TVec3f& a1, f32 a2) { + TVec3f v20; + _BC.rotateVec(v20, a1); + v20.add(mPosition); + TVec3f v19; + v19 = mTail->getNode(1)->mPosition; + DinoPackunTailNode* node = mTail->getNode(1); + TVec3f v16 = v19 * (1.0f - a2); + TVec3f v17 = v20 * a2; + TVec3f v18(v17); + v18.add(v16); + node->mPosition.set< f32 >(v18); +} + +void DinoPackun::activateParts() { + mTail->activate(); +} + +void DinoPackun::onMovementParts() { + mTail->onMovement(); + MR::requestMovementOn(mDemoPos); + MR::requestMovementOn(mFootPrint); + if (mShell != nullptr) { + MR::requestMovementOn(mShell); + } + + if (mShellBreakModel != nullptr) { + MR::requestMovementOn(mShellBreakModel); + } + + if (mTailBall != nullptr) { + MR::requestMovementOn(mTailBall); + } +} + +void DinoPackun::onAimTailBall(s32 a1) { + if (a1 <= 0) { + _104 = 0.0f; + _108 = 1.0f; + } else { + _104 = 1.0f / a1; + } +} + +void DinoPackun::offAimTailBall(s32 a1) { + if (a1 <= 0) { + _104 = 0.0f; + _108 = 0.0f; + } else { + _104 = -1.0f / a1; + } +} + +void DinoPackun::startDemo() { + onMovementParts(); + MR::turnOffImageEffect(); +} + +void DinoPackun::startDemoAndReset() { + mTail->deactivate(); + resetPosition(); + mFootPrint->clear(); + onMovementParts(); + MR::turnOffImageEffect(); +} + +void DinoPackun::endDemo(const char* pName) { + MR::endDemo(this, pName); + MR::setImageEffectControlAuto(); +} + +void DinoPackun::startDamageCamera() { + CameraTargetArg arg(nullptr, mCamTargetMtx, nullptr, nullptr); + MR::startMultiActorCameraTargetOther(this, mCameraInfo, sEventCameraName, arg, -1); + _10C = 0; +} + +void DinoPackun::endDamageCamera() { + if (_10C != -1) { + MR::endMultiActorCamera(this, mCameraInfo, sEventCameraName, false, -1); + _10C = -1; + } +} + +DinoPackun::~DinoPackun() { + return; +} + +namespace MR { + NameObj* createDinoPackunVs1(const char* pName) { + DinoPackun* p = new DinoPackun(pName); + p->mSequence = new DinoPackunVs1(p); + return p; + } + + NameObj* createDinoPackunVs2(const char* pName) { + DinoPackun* p = new DinoPackun(pName); + p->mSequence = new DinoPackunVs2(p); + return p; + } +}; // namespace MR diff --git a/src/Game/Boss/DinoPackunBattleVs2Lv1.cpp b/src/Game/Boss/DinoPackunBattleVs2Lv1.cpp index c8ed0434f..b6780c058 100644 --- a/src/Game/Boss/DinoPackunBattleVs2Lv1.cpp +++ b/src/Game/Boss/DinoPackunBattleVs2Lv1.cpp @@ -194,17 +194,7 @@ void DinoPackunBattleVs2Lv1::exeWalk() { s32 v4 = _3B ? 15 : 20; f32 v5 = _3B ? 1.1f : 1.2f; - s32 step = getNerveStep(); - s32 div = (step / v3); - f32 v7; - - if (div % 2 == _34) { - v7 = -1.0f; - } else { - v7 = 1.0f; - } - - MR::rotateDirectionGravityDegree(getHost(), &getHost()->_E8, (v5 * v7)); + MR::rotateDirectionGravityDegree(getHost(), &getHost()->_E8, (v5 * ((getNerveStep() / v3) % 2 == _34 ? -1.0f : 1.0f))); updateOnOffFireTail(v3, v4, 20); s32 v8 = _3A ? 500 : 610; From 8b71e76816cc8e7c90083a7c3426c47dbc69c226 Mon Sep 17 00:00:00 2001 From: MrL314 <11429905+MrL314@users.noreply.github.com> Date: Mon, 16 Feb 2026 21:26:00 -0500 Subject: [PATCH 18/52] `TQuat4::transform` (+`DinoPackun` fix) --- .../include/JSystem/JGeometry/TVec.hpp | 41 +++++++++++-------- src/Game/Boss/DinoPackun.cpp | 19 ++++----- 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/libs/JSystem/include/JSystem/JGeometry/TVec.hpp b/libs/JSystem/include/JSystem/JGeometry/TVec.hpp index 54576a119..57ae8d632 100644 --- a/libs/JSystem/include/JSystem/JGeometry/TVec.hpp +++ b/libs/JSystem/include/JSystem/JGeometry/TVec.hpp @@ -778,19 +778,6 @@ namespace JGeometry { 1.0f - this->x * this->x * 2.0f - this->y * this->y * 2.0f); } - inline void rotateVec(TVec3< T >& dst, const TVec3< T >& v) const { - float nx = -this->x; - - float v9 = (this->y * v.z) - (this->z * v.y); - float v13 = (this->w * v.y) + ((nx * v.z) + (this->z * v.x)); - float v14 = (this->w * v.z) + ((this->x * v.y) - (this->y * v.x)); - float v15 = ((nx * v.x) - (this->y * v.y)) - (this->z * v.z); - - dst.set< T >((v15 * nx) + (((this->w * v.x + v9) * this->w) + (v13 * -this->z) - (v14 * -this->y)), - (v15 * -this->y) + ((v14 * nx) + ((-(this->w * v.x + v9) * -this->z) + (v13 * this->w))), - (v15 * -this->z) + ((v14 * this->w) + (((this->w * v.x + v9) * -this->y) - (v13 * nx)))); - } - void getEuler(TVec3< T >& rDest) const; void setEuler(T _x, T _y, T _z); void setEulerZ(T _z); @@ -810,7 +797,9 @@ namespace JGeometry { setRotate(pVec, pAngle); } - void rotate(TVec3< T >& rDest) const; + void rotate(TVec3< T >& v) const { + transform(v, v); + } void slerp(const TQuat4< T >& a1, const TQuat4< T >& a2, T a3) { this->x = a1.x; @@ -825,8 +814,28 @@ namespace JGeometry { } void slerp(const TQuat4< T >&, T); - void transform(const TVec3< T >&, TVec3< T >& rDest); - void transform(TVec3< T >& rDest) const; + + void transform(const TVec3< T >& v, TVec3< T >& rDest) const { + // transformation via hamiltonian multiplication of a unit quaternion + // q*v*q` + // where v is the input vector converted into a quaternion with w=0 + // and q` is the multiplicative inverse of q + // (eg: q = w + xi + yj + zk, q` = w - xi - yj - zk) + + TQuat4< T > r; + r.x = (this->y * v.z) - (this->z * v.y) + (this->w * v.x); + r.y = (-this->x * v.z) + (this->z * v.x) + (this->w * v.y); + r.z = (this->x * v.y) - (this->y * v.x) + (this->w * v.z); + r.w = (-this->x * v.x) - (this->y * v.y) - (this->z * v.z); + + rDest.template set< T >(r.x * this->w + r.y * -this->z - r.z * -this->y + r.w * -this->x, + -r.x * -this->z + r.y * this->w + r.z * -this->x + r.w * -this->y, + r.x * -this->y - r.y * -this->x + r.z * this->w + r.w * -this->z); + } + + void transform(TVec3< T >& v) const { + transform(v, v); + } /* Operators */ TQuat4< T >& operator=(const TQuat4< T >& rSrc); diff --git a/src/Game/Boss/DinoPackun.cpp b/src/Game/Boss/DinoPackun.cpp index 1a4c2767d..dca35e476 100644 --- a/src/Game/Boss/DinoPackun.cpp +++ b/src/Game/Boss/DinoPackun.cpp @@ -485,18 +485,15 @@ void DinoPackun::resetPosition() { MR::setPlayerBaseMtx(v28); } -void DinoPackun::adjustTailRootPosition(const TVec3f& a1, f32 a2) { - TVec3f v20; - _BC.rotateVec(v20, a1); - v20.add(mPosition); - TVec3f v19; - v19 = mTail->getNode(1)->mPosition; +void DinoPackun::adjustTailRootPosition(const TVec3f& rDir, f32 ratio) { + TVec3f newPos; + _BC.transform(rDir, newPos); + newPos.add(mPosition); + TVec3f currPos; + currPos = mTail->getNode(1)->mPosition; DinoPackunTailNode* node = mTail->getNode(1); - TVec3f v16 = v19 * (1.0f - a2); - TVec3f v17 = v20 * a2; - TVec3f v18(v17); - v18.add(v16); - node->mPosition.set< f32 >(v18); + TVec3f pos = (newPos * ratio).addOperatorInLine(currPos * (1.0f - ratio)); + node->mPosition.set(pos); } void DinoPackun::activateParts() { From 159f9ed9723adbafb7b8beb2d4b22225290f2b4a Mon Sep 17 00:00:00 2001 From: shibbo Date: Tue, 17 Feb 2026 18:29:13 -0500 Subject: [PATCH 19/52] `NWC24Manage` at 99% --- .../include/revolution/nwc24/NWC24Config.h | 45 ++++ .../include/revolution/nwc24/NWC24Download.h | 98 ++++++++ .../include/revolution/nwc24/NWC24FileApi.h | 76 ++++++ .../revolution/nwc24/NWC24FriendList.h | 27 +++ .../include/revolution/nwc24/NWC24MBoxCtrl.h | 16 ++ .../include/revolution/nwc24/NWC24Manage.h | 56 +++++ .../include/revolution/nwc24/NWC24Mime.h | 16 ++ .../include/revolution/nwc24/NWC24Schedule.h | 20 ++ .../revolution/nwc24/NWC24SecretFList.h | 22 ++ .../include/revolution/nwc24/NWC24StdApi.h | 17 ++ libs/RVL_SDK/include/revolution/types.h | 2 + libs/RVL_SDK/include/revolution/vf.h | 2 + libs/RVL_SDK/include/revolution/vf/d_vf.h | 8 + src/RVL_SDK/nwc24/NWC24Manage.c | 216 +++++++++++++++++- src/RVL_SDK/nwc24/NWC24SecretFList.c | 58 +++++ 15 files changed, 672 insertions(+), 7 deletions(-) create mode 100644 libs/RVL_SDK/include/revolution/nwc24/NWC24Config.h create mode 100644 libs/RVL_SDK/include/revolution/nwc24/NWC24Download.h create mode 100644 libs/RVL_SDK/include/revolution/nwc24/NWC24FileApi.h create mode 100644 libs/RVL_SDK/include/revolution/nwc24/NWC24FriendList.h create mode 100644 libs/RVL_SDK/include/revolution/nwc24/NWC24MBoxCtrl.h create mode 100644 libs/RVL_SDK/include/revolution/nwc24/NWC24Manage.h create mode 100644 libs/RVL_SDK/include/revolution/nwc24/NWC24Mime.h create mode 100644 libs/RVL_SDK/include/revolution/nwc24/NWC24Schedule.h create mode 100644 libs/RVL_SDK/include/revolution/nwc24/NWC24SecretFList.h create mode 100644 libs/RVL_SDK/include/revolution/nwc24/NWC24StdApi.h create mode 100644 libs/RVL_SDK/include/revolution/vf/d_vf.h create mode 100644 src/RVL_SDK/nwc24/NWC24SecretFList.c diff --git a/libs/RVL_SDK/include/revolution/nwc24/NWC24Config.h b/libs/RVL_SDK/include/revolution/nwc24/NWC24Config.h new file mode 100644 index 000000000..47f0f071e --- /dev/null +++ b/libs/RVL_SDK/include/revolution/nwc24/NWC24Config.h @@ -0,0 +1,45 @@ +#ifndef NWC24CONFIG_H +#define NWC24CONFIG_H + +#include "revolution/nwc24.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { NWC24_IDCS_INITIAL, NWC24_IDCS_GENERATED, NWC24_IDCS_REGISTERED } NWC24IDCreationStage; + +typedef struct NWC24Config { + u32 magic; // at 0x0 + u32 version; // at 0x4 + u64 userId; // at 0x8 + u32 createCount; // at 0x10 + NWC24IDCreationStage createStage; // at 0x14 + char acctDomain[64]; // at 0x18 + char password[32]; // at 0x58 + char mailchkId[36]; // at 0x78 + char acctUrl[128]; // at 0x9C + char mailchkUrl[128]; // at 0x11C + char mailrecvUrl[128]; // at 0x19C + char maildeleteUrl[128]; // at 0x21C + char mailsendUrl[128]; // at 0x29C + char UNK_0x31C[0x3F8 - 0x31C]; + BOOL allowTitleBoot; // at 0x3F8 + u32 checksum; // at 0x3FC +} NWC24Config; + +NWC24Err NWC24GetMyUserId(u64* idOut); +NWC24Err NWC24GenerateNewUserId(u64* idOut); +NWC24Err NWC24iConfigOpen(void); +NWC24Err NWC24iConfigReload(void); +NWC24Err NWC24iConfigFlush(void); +const char* NWC24GetAccountDomain(void); +const char* NWC24GetMBoxDir(void); +u32 NWC24GetAppId(void); +u16 NWC24GetGroupId(void); + +#ifdef __cplusplus +} +#endif + +#endif // NWC24CONFIG_H diff --git a/libs/RVL_SDK/include/revolution/nwc24/NWC24Download.h b/libs/RVL_SDK/include/revolution/nwc24/NWC24Download.h new file mode 100644 index 000000000..8b82fcacf --- /dev/null +++ b/libs/RVL_SDK/include/revolution/nwc24/NWC24Download.h @@ -0,0 +1,98 @@ +#ifndef NWC24DOWNLOAD_H +#define NWC24DOWNLOAD_H + +#include "revolution/nwc24.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define NWC24_DL_TASK_MAX 120 +#define NWC24_DL_SUBTASK_MAX 32 + +typedef enum { NWC24_DLTYPE_MULTIPART_V1, NWC24_DLTYPE_OCTETSTREAM_V1, NWC24_DLTYPE_MULTIPART_V2, NWC24_DLTYPE_OCTETSTREAM_V2 } NWC24DlType; + +typedef enum { + NWC24_DL_STTYPE_NONE, + NWC24_DL_STTYPE_INCREMENT, + NWC24_DL_STTYPE_TIME_HOUR, + NWC24_DL_STTYPE_TIME_DAYOFWEEK, + NWC24_DL_STTYPE_TIME_DAY +} NWC24DlSubTaskType; + +typedef enum { + NWC24_DL_STFLAG_TRAILING_FILENAME = (1 << 0), + NWC24_DL_STFLAG_TRAILING_URL = (1 << 1), + NWC24_DL_STFLAG_INTELLIGENT_UPDATE = (1 << 8), + NWC24_DL_STFLAG_RETICENT_UPDATE = (1 << 9) +} NWC24DlSubTaskFlags; + +typedef struct NWC24DlEntry { + u32 app; // at 0x0 + u32 nextTime; // at 0x4 + u32 lastAccess; // at 0x8 + u8 flags; // at 0xC + char UNK_0xD[0x10 - 0xD]; +} NWC24DlEntry; + +#pragma pack(push, 1) +typedef struct NWC24DlHeader { + u32 magic; // at 0x0 + u32 version; // at 0x4 + char UNK_0x8[0x10 - 0x8]; + u16 maxSubTasks; // at 0x10 + u16 privateTasks; // at 0x12 + u16 maxTasks; // at 0x14 + char UNK_0x16[0x80 - 0x16]; + NWC24DlEntry entries[NWC24_DL_TASK_MAX]; // at 0x80 +} NWC24DlHeader; +#pragma pack(pop) + +#pragma pack(push, 1) +typedef struct NWC24DlTask { + u16 id; // at 0x0 + u8 type; // at 0x2 + u8 priority; // at 0x3 + u32 flags; // at 0x4 + u32 appId; // at 0x8 + u32 titleIdHi; // at 0xC + u32 titleIdLo; // at 0x10 + u16 groupId; // at 0x14 + char UNK_0x16[0x2]; + s16 count; // at 0x18 + s16 errorCount; // at 0x1A + u16 interval; // at 0x1C + u16 margin; // at 0x1E + u32 lastError; // at 0x20 + u8 subTaskCounter; // at 0x24 + u8 subTaskType; // at 0x25 + u8 subTaskFlags; // at 0x26 + char UNK_0x27[0x1]; + u32 subTaskMask; // at 0x28 + u32 serverInterval; // at 0x2C + u32 lastUpdate; // at 0x30 + u32 lastUpdateSubTask[NWC24_DL_SUBTASK_MAX]; // at 0x34 + char url[236]; // at 0xB4 + char fileName[64]; // at 0x1A0 + char UNK_0x1E0[0x1F8 - 0x1E0]; + u32 userParam; // at 0x1F8 + u8 optFlags; // at 0x1FC + u8 rootCaId; // at 0x1FD + char UNK_0x1FE[0x200 - 0x1FE]; +} NWC24DlTask; +#pragma pack(pop) + +NWC24Err NWC24CheckDlTask(NWC24DlTask* task); +NWC24Err NWC24DeleteDlTaskForced(NWC24DlTask* task); +NWC24Err NWC24GetDlTask(NWC24DlTask* task, u16 i); +NWC24Err NWC24iOpenDlTaskList(void); +NWC24Err NWC24iCloseDlTaskList(void); +NWC24DlHeader* NWC24iGetCachedDlHeader(void); +NWC24Err NWC24iCheckHeaderConsistency(NWC24DlHeader* header, BOOL clear) NO_INLINE; +NWC24Err NWC24iLoadDlHeader(void); + +#ifdef __cplusplus +} +#endif + +#endif // NWC24DOWNLOAD_H diff --git a/libs/RVL_SDK/include/revolution/nwc24/NWC24FileApi.h b/libs/RVL_SDK/include/revolution/nwc24/NWC24FileApi.h new file mode 100644 index 000000000..f166895f1 --- /dev/null +++ b/libs/RVL_SDK/include/revolution/nwc24/NWC24FileApi.h @@ -0,0 +1,76 @@ +#ifndef NWC24FILEAPI_H +#define NWC24FILEAPI_H + +#include "revolution/nwc24.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + // Access + NWC24_OPEN_WRITE = (1 << 0), + NWC24_OPEN_READ = (1 << 1), + NWC24_OPEN_RW = (1 << 2), + + // Domain + NWC24_OPEN_BUFF = (1 << 3), + NWC24_OPEN_VF = (1 << 8), + + // NAND presets + NWC24_OPEN_NAND_W = NWC24_OPEN_WRITE, + NWC24_OPEN_NAND_R = NWC24_OPEN_READ, + NWC24_OPEN_NAND_RW = NWC24_OPEN_RW, + + // VF presets + NWC24_OPEN_VF_W = NWC24_OPEN_WRITE | NWC24_OPEN_VF, + NWC24_OPEN_VF_R = NWC24_OPEN_READ | NWC24_OPEN_VF, + NWC24_OPEN_VF_RW = NWC24_OPEN_RW | NWC24_OPEN_VF, + + // NAND (buffered) presets + NWC24_OPEN_NAND_WBUFF = NWC24_OPEN_NAND_W | NWC24_OPEN_BUFF, + NWC24_OPEN_NAND_RBUFF = NWC24_OPEN_NAND_R | NWC24_OPEN_BUFF, + NWC24_OPEN_NAND_RWBUFF = NWC24_OPEN_NAND_RW | NWC24_OPEN_BUFF, + + // VF (buffered) presets + NWC24_OPEN_VF_WBUFF = NWC24_OPEN_VF_W | NWC24_OPEN_BUFF, + NWC24_OPEN_VF_RBUFF = NWC24_OPEN_VF_R | NWC24_OPEN_BUFF, + NWC24_OPEN_VF_RWBUFF = NWC24_OPEN_VF_RW | NWC24_OPEN_BUFF, +} NWC24OpenMode; + +typedef enum { + NWC24_SEEK_BEG, + NWC24_SEEK_CUR, + NWC24_SEEK_END, +} NWC24SeekMode; + +typedef struct NWC24File { + u32 id; // at 0x0 + u32 mode; // at 0x4 + u32 align; // at 0x8 + NANDFileInfo nandf; // at 0xC + void* vff; // at 0x98 +} NWC24File; + +NWC24Err NWC24FOpen(NWC24File* file, const char* path, u32 mode); +NWC24Err NWC24iFOpenNand(NWC24File* file, const char* path, u32 mode); +NWC24Err NWC24iFOpenVF(NWC24File* file, const char* path, u32 mode); + +NWC24Err NWC24FClose(NWC24File* file); +NWC24Err NWC24iFCloseNand(NWC24File* file) NO_INLINE; +NWC24Err NWC24iFCloseVF(NWC24File* file); + +NWC24Err NWC24FSeek(NWC24File* file, s32 offset, NWC24SeekMode whence); +NWC24Err NWC24FRead(void* dst, s32 size, NWC24File* file); +NWC24Err NWC24FWrite(const void* src, s32 size, NWC24File* file); +NWC24Err NWC24FGetLength(NWC24File* file, u32* lengthOut); +NWC24Err NWC24FDeleteVF(const char* path); +NWC24Err NWC24MountVF(const char* drive, const char* filename); +NWC24Err NWC24UnmountVF(const char* drive); +NWC24Err NWC24CheckSizeVF(const char* drive, u32* sizeOut); + +#ifdef __cplusplus +} +#endif + +#endif // NWC24FILEAPI_H diff --git a/libs/RVL_SDK/include/revolution/nwc24/NWC24FriendList.h b/libs/RVL_SDK/include/revolution/nwc24/NWC24FriendList.h new file mode 100644 index 000000000..b221cf89e --- /dev/null +++ b/libs/RVL_SDK/include/revolution/nwc24/NWC24FriendList.h @@ -0,0 +1,27 @@ +#ifndef NWC24FRIENDLIST_H +#define NWC24FRIENDLIST_H + +#include "revolution/nwc24.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define NWC24_FRIEND_LIST_CAPACITY 100 + +typedef struct NWC24FLHeader { + u32 magic; // at 0x0 + u32 version; // at 0x4 + u32 capacity; // at 0x8 + u32 size; // at 0xC + char UNK_0x10[0x40 - 0x10]; + u64 friendCodes[NWC24_FRIEND_LIST_CAPACITY]; // at 0x40 +} NWC24FLHeader; + +NWC24Err NWC24iOpenFriendList(void); + +#ifdef __cplusplus +} +#endif + +#endif // NWC24FRIENDLIST_H diff --git a/libs/RVL_SDK/include/revolution/nwc24/NWC24MBoxCtrl.h b/libs/RVL_SDK/include/revolution/nwc24/NWC24MBoxCtrl.h new file mode 100644 index 000000000..5abdd09de --- /dev/null +++ b/libs/RVL_SDK/include/revolution/nwc24/NWC24MBoxCtrl.h @@ -0,0 +1,16 @@ +#ifndef NWC24MBOXCTRL_H +#define NWC24MBOXCTRL_H + +#include "revolution/nwc24.h" + +#ifdef __cplusplus +extern "C" { +#endif + +NWC24Err NWC24iOpenMBox(void); + +#ifdef __cplusplus +} +#endif + +#endif // NWC24MBOXCTRL_H diff --git a/libs/RVL_SDK/include/revolution/nwc24/NWC24Manage.h b/libs/RVL_SDK/include/revolution/nwc24/NWC24Manage.h new file mode 100644 index 000000000..46167d315 --- /dev/null +++ b/libs/RVL_SDK/include/revolution/nwc24/NWC24Manage.h @@ -0,0 +1,56 @@ +#ifndef NWC24MANAGE_H +#define NWC24MANAGE_H + +#include "revolution.h" +#include "revolution/nwc24/NWC24Config.h" +#include "revolution/nwc24/NWC24Download.h" +#include "revolution/nwc24/NWC24FriendList.h" +#include "revolution/nwc24/NWC24SecretFList.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define NWC24_IO_BUFFER_SIZE 512 + +#define WORK_SIZE(x) (ROUND_UP(sizeof(x), 0x100)) +typedef struct NWC24Work { + char stringWork[1024]; // at 0x0 + char WORK_0x400[0x800 - 0x400]; + char pathWork[128]; // at 0x800 + char WORK_0x880[0x900 - 0x880]; + u8 readBuffer[NWC24_IO_BUFFER_SIZE]; // at 0x900 + u8 writeBuffer[NWC24_IO_BUFFER_SIZE]; // at 0xB00 + u8 config[WORK_SIZE(NWC24Config)]; // at 0xD00 + char WORK_0x1100[128]; + char WORK_0x1180[128]; + char WORK_0x1200[128]; + char WORK_0x1280[128]; + u8 base64Work[256]; // at 0x1300 + char WORK_0x1400[0x2400 - 0x1400]; + u8 flHeader[WORK_SIZE(NWC24FLHeader)]; // at 0x2800 + u8 secretFlHeader[WORK_SIZE(NWC24SecretFLHeader)]; // at 0x2800 + u8 dlHeader[WORK_SIZE(NWC24DlHeader)]; // at 0x3000 + u8 dlTask[WORK_SIZE(NWC24DlTask)]; // at 0x3800 + u8 padding[0x4000 - 0x3A00]; +} NWC24Work; +#undef WORK_SIZE + +extern NWC24Work* NWC24WorkP; + +void NWC24iRegister(void); +NWC24Err NWC24OpenLib(NWC24Work* work); +NWC24Err NWC24CloseLib(void); +BOOL NWC24IsMsgLibOpened(void); +BOOL NWC24IsMsgLibOpenedByTool(void); +BOOL NWC24IsMsgLibOpenBlocking(void); +NWC24Err NWC24BlockOpenMsgLib(BOOL block); +NWC24Err NWC24iSetNewMsgArrived(u32 flags); +u32 NWC24GetErrorCode(void); +void NWC24iSetErrorCode(u32 code); + +#ifdef __cplusplus +} +#endif + +#endif // NWC24MANAGE_H diff --git a/libs/RVL_SDK/include/revolution/nwc24/NWC24Mime.h b/libs/RVL_SDK/include/revolution/nwc24/NWC24Mime.h new file mode 100644 index 000000000..33f643915 --- /dev/null +++ b/libs/RVL_SDK/include/revolution/nwc24/NWC24Mime.h @@ -0,0 +1,16 @@ +#ifndef NWC24MIME_H +#define NWC24MIME_H + +#include "revolution.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void NWC24InitBase64Table(u8* table); + +#ifdef __cplusplus +} +#endif + +#endif // NWC24MIME_H diff --git a/libs/RVL_SDK/include/revolution/nwc24/NWC24Schedule.h b/libs/RVL_SDK/include/revolution/nwc24/NWC24Schedule.h new file mode 100644 index 000000000..f3222bbb2 --- /dev/null +++ b/libs/RVL_SDK/include/revolution/nwc24/NWC24Schedule.h @@ -0,0 +1,20 @@ +#ifndef NWC24SCHEDULE_H +#define NWC24SCHEDULE_H + +#include "revolution/nwc24.h" + +#ifdef __cplusplus +extern "C" { +#endif + +s32 NWC24SuspendScheduler(void); +s32 NWC24ResumeScheduler(void); +NWC24Err NWC24iRequestGenerateUserId(u64* idOut, u32* arg1); +NWC24Err NWC24iTrySuspendForOpenLib(void); +NWC24Err NWC24iResumeForCloseLib(void); + +#ifdef __cplusplus +} +#endif + +#endif // NWC24SCHEDULE_H diff --git a/libs/RVL_SDK/include/revolution/nwc24/NWC24SecretFList.h b/libs/RVL_SDK/include/revolution/nwc24/NWC24SecretFList.h new file mode 100644 index 000000000..ae867c021 --- /dev/null +++ b/libs/RVL_SDK/include/revolution/nwc24/NWC24SecretFList.h @@ -0,0 +1,22 @@ +#ifndef NWC24SECRETFLIST_H +#define NWC24SECRETFLIST_H + +#include "revolution/nwc24.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct NWC24SecretFLHeader { + u32 magic; // at 0x0 + u32 version; // at 0x4 + u8 UNK_0x8[0x800 - 0x8]; +} NWC24SecretFLHeader; + +NWC24Err NWC24iOpenSecretFriendList(void); + +#ifdef __cplusplus +} +#endif + +#endif // NWC24SECRETFLIST_H diff --git a/libs/RVL_SDK/include/revolution/nwc24/NWC24StdApi.h b/libs/RVL_SDK/include/revolution/nwc24/NWC24StdApi.h new file mode 100644 index 000000000..b198323e7 --- /dev/null +++ b/libs/RVL_SDK/include/revolution/nwc24/NWC24StdApi.h @@ -0,0 +1,17 @@ +#ifndef NWC24STDAPI_H +#define NWC24STDAPI_H + +#include "revolution.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void* Mail_memset(void* dst, int ch, size_t n); + +#ifdef __cplusplus +} +#endif + +#endif // NWC24STDAPI_H diff --git a/libs/RVL_SDK/include/revolution/types.h b/libs/RVL_SDK/include/revolution/types.h index 35e76b3ff..2ae6ad930 100644 --- a/libs/RVL_SDK/include/revolution/types.h +++ b/libs/RVL_SDK/include/revolution/types.h @@ -88,6 +88,8 @@ typedef int BOOL; #define MAX(x, y) ((x) > (y) ? (x) : (y)) #define MIN(x, y) ((x) < (y) ? (x) : (y)) +#define FOURCC(c0, c1, c2, c3) (u32)((c0 & 0xFF) << 24 | (c1 & 0xFF) << 16 | (c2 & 0xFF) << 8 | (c3 & 0xFF)) + /* just some common intrinsics */ #ifndef __MWERKS__ diff --git a/libs/RVL_SDK/include/revolution/vf.h b/libs/RVL_SDK/include/revolution/vf.h index b1babb7ff..d034090af 100644 --- a/libs/RVL_SDK/include/revolution/vf.h +++ b/libs/RVL_SDK/include/revolution/vf.h @@ -1,4 +1,6 @@ #ifndef VF_H #define VF_H +#include "revolution/vf/d_vf.h" + #endif // VF_H diff --git a/libs/RVL_SDK/include/revolution/vf/d_vf.h b/libs/RVL_SDK/include/revolution/vf/d_vf.h new file mode 100644 index 000000000..ef8351fca --- /dev/null +++ b/libs/RVL_SDK/include/revolution/vf/d_vf.h @@ -0,0 +1,8 @@ +#ifndef D_VF_H +#define D_VF_H + +#include "revolution.h" + +s32 VFIsAvailable(); + +#endif // D_VF_H diff --git a/src/RVL_SDK/nwc24/NWC24Manage.c b/src/RVL_SDK/nwc24/NWC24Manage.c index e83a484ad..54e0cb341 100644 --- a/src/RVL_SDK/nwc24/NWC24Manage.c +++ b/src/RVL_SDK/nwc24/NWC24Manage.c @@ -1,8 +1,22 @@ +#include "revolution/nwc24/NWC24Manage.h" +#include "revolution/nwc24/NWC24MBoxCtrl.h" +#include "revolution/nwc24/NWC24Mime.h" +#include "revolution/nwc24/NWC24Schedule.h" #include #include +#include +#include -static int Opened = 0; -static int Registered; +#define MANAGE_ERROR_CODE_BASE 109000 + +typedef enum { NWC24_LIB_CLOSED, NWC24_LIB_OPENED, NWC24_LIB_OPENED_BY_TOOL, NWC24_LIB_BLOCKED } NWC24LibState; + +typedef enum { NWC24_FAIL_SFL = (1 << 0), NWC24_FAIL_DL_TASK = (1 << 1), NWC24_FAIL_FATAL = (1 << 2) } NWC24FailFlag; + +static NWC24LibState Opened = NWC24_LIB_CLOSED; +static u32 YouGotMail = 0; +static u32 GlobalErrorCode = 0; +static BOOL Registered = FALSE; const char* __NWC24Version = "<< RVL_SDK - NWC24 \trelease build: Dec 10 2007 10:02:25 (0x4199_60831) >>"; @@ -17,15 +31,163 @@ int NWC24IsMsgLibOpened(void) { return Opened == 1; } -//Todo Change Second Type to Struct; -int NWC24OpenLibInternal(int, int); +static NWC24Err NWC24OpenLibInternal(NWC24Work* work, NWC24LibState state); -int NWC24OpenLib(int arg1) { +NWC24Err NWC24OpenLib(NWC24Work* work) { if (Opened == 2) { return -0x1a; } - return NWC24OpenLibInternal(arg1, 1); -} + return NWC24OpenLibInternal(work, 1); +} + +static NWC24Err NWC24OpenLibInternal(NWC24Work* work, NWC24LibState state) { + NWC24Err result; + NWC24Err failErr; + u32 failFlag; + + NWC24iSetErrorCode(NWC24_OK); + + if (!VFIsAvailable()) { + return NWC24_ERR_FATAL; + } + + if (NWC24IsMsgLibOpened()) { + return NWC24_ERR_LIB_OPENED; + } + + if (NWC24IsMsgLibOpenBlocking()) { + return NWC24_ERR_BUSY; + } + + if (work == NULL) { + return NWC24_ERR_NULL; + } + + if ((uintptr_t)work % 32 != 0) { + return NWC24_ERR_ALIGNMENT; + } + + result = NWC24iTrySuspendForOpenLib(); + if (result == NWC24_OK) { + NWC24iRegister(); + + YouGotMail &= ~(1 << NWC24_MSGTYPE_RVL_MENU_SHARED); + NWC24WorkP = work; + + NWC24InitBase64Table(NWC24WorkP->base64Work); + + failFlag = 0; + failErr = NWC24_OK; + + result = NWC24iConfigOpen(); + if (result != NWC24_OK) { + failErr = result; + failFlag |= NWC24_FAIL_FATAL; + } + + result = NWC24iOpenMBox(); + if (result != NWC24_OK) { + failErr = result; + failFlag |= NWC24_FAIL_FATAL; + } + + result = NWC24iOpenFriendList(); + if (result != NWC24_OK) { + failErr = result; + failFlag |= NWC24_FAIL_FATAL; + } + + result = NWC24iOpenSecretFriendList(); + if (result != NWC24_OK) { + failErr = result; + + if (result == NWC24_ERR_FILE_NOEXISTS) { + failFlag |= NWC24_FAIL_FATAL; + } else { + failFlag |= NWC24_FAIL_SFL; + } + } + + result = NWC24iOpenDlTaskList(); + if (result < 0) { + failErr = result; + + if (result == NWC24_ERR_FILE_NOEXISTS) { + failFlag |= NWC24_FAIL_FATAL; + } else { + failFlag |= NWC24_FAIL_DL_TASK; + } + } + + if (failFlag == (NWC24_FAIL_SFL | NWC24_FAIL_DL_TASK)) { + failErr = NWC24_ERR_OLD_SYSTEM; + } + + if (failFlag != 0) { + NWC24WorkP = NULL; + NWC24iResumeForCloseLib(); + result = failErr; + } else { + Opened = state; + return NWC24_OK; + } + } + + switch (result) { + case NWC24_ERR_OLD_SYSTEM: + case NWC24_ERR_FILE_BROKEN: + case NWC24_ERR_INTERNAL_VF: + case NWC24_ERR_INTERNAL_IPC: + case NWC24_ERR_NAND_CORRUPT: + case NWC24_ERR_INPROGRESS: + case NWC24_ERR_BUSY: + case NWC24_ERR_MUTEX: + case NWC24_ERR_FILE_OTHER: + case NWC24_ERR_FILE_NOEXISTS: + case NWC24_ERR_FILE_WRITE: + case NWC24_ERR_FILE_READ: + case NWC24_ERR_FILE_CLOSE: + case NWC24_ERR_FILE_OPEN: + case NWC24_ERR_BROKEN: + case NWC24_ERR_FATAL: { + NWC24iSetErrorCode(result - MANAGE_ERROR_CODE_BASE); + break; + } + + default: { + break; + } + } + + return result; +} + +NWC24Err NWC24CloseLib(void) { + s32 result; + + if (Opened != NWC24_LIB_OPENED) { + return NWC24_ERR_LIB_NOT_OPENED; + } + + result = NWC24iConfigFlush(); + if (result != NWC24_OK) { + return result; + } + + result = NWC24iCloseDlTaskList(); + if (result < 0) { + return result; + } + + result = NWC24iResumeForCloseLib(); + if (result != NWC24_OK) { + return result; + } + + NWC24WorkP = NULL; + Opened = NWC24_LIB_CLOSED; + return result; +} int NWC24IsMsgLibOpenedByTool(void) { return Opened == 2; @@ -34,3 +196,43 @@ int NWC24IsMsgLibOpenedByTool(void) { int NWC24IsMsgLibOpenBlocking(void) { return Opened == 3; } + +NWC24Err NWC24BlockOpenMsgLib(BOOL block) { + s32 result; + BOOL enabled; + + result = NWC24_OK; + enabled = OSDisableInterrupts(); + + if (block) { + if (Opened == NWC24_LIB_CLOSED) { + Opened = NWC24_LIB_BLOCKED; + } else if (Opened == NWC24_LIB_OPENED) { + result = NWC24_ERR_LIB_OPENED; + } else { + result = NWC24_ERR_BUSY; + } + } else { + if (Opened == NWC24_LIB_BLOCKED) { + Opened = NWC24_LIB_CLOSED; + } else { + result = NWC24_ERR_LIB_NOT_OPENED; + } + } + + OSRestoreInterrupts(enabled); + return result; +} + +NWC24Err NWC24iSetNewMsgArrived(u32 flags) { + YouGotMail |= flags; + return NWC24_OK; +} + +u32 NWC24GetErrorCode() { + return GlobalErrorCode; +} + +void NWC24iSetErrorCode(u32 code) { + GlobalErrorCode = code; +} diff --git a/src/RVL_SDK/nwc24/NWC24SecretFList.c b/src/RVL_SDK/nwc24/NWC24SecretFList.c new file mode 100644 index 000000000..7616f99a5 --- /dev/null +++ b/src/RVL_SDK/nwc24/NWC24SecretFList.c @@ -0,0 +1,58 @@ +#include "revolution/nwc24/NWC24SecretFList.h" +#include "revolution/nwc24.h" +#include "revolution/nwc24/NWC24FileApi.h" +#include "revolution/nwc24/NWC24Manage.h" +#include "revolution/nwc24/NWC24StdApi.h" + +#define SECRET_FRIEND_LIST_MAGIC FOURCC('W', 'c', 'F', 's') +#define SECRET_FRIEND_LIST_VERSION 2 + +static const char* FLFilePath = "/shared2/wc24/nwc24fls.bin"; + +static NWC24Err GetCachedSecretFLHeader(NWC24SecretFLHeader** header); + +NWC24Err NWC24iOpenSecretFriendList(void) { + NWC24SecretFLHeader* header = (NWC24SecretFLHeader*)NWC24WorkP->secretFlHeader; + Mail_memset(header, 0, sizeof(NWC24SecretFLHeader)); + return GetCachedSecretFLHeader(&header); +} + +static NWC24Err GetCachedSecretFLHeader(NWC24SecretFLHeader** header) { + NWC24File file; + NWC24Err result; + NWC24Err read; + NWC24Err close; + + *header = (NWC24SecretFLHeader*)NWC24WorkP->secretFlHeader; + + if ((*header)->magic != SECRET_FRIEND_LIST_MAGIC) { + result = NWC24FOpen(&file, FLFilePath, NWC24_OPEN_NAND_R); + if (result != NWC24_OK) { + return result; + } + + NWC24FSeek(&file, 0, NWC24_SEEK_BEG); + read = NWC24FRead(*header, sizeof(NWC24SecretFLHeader), &file); + close = NWC24FClose(&file); + + if (read != NWC24_OK) { + result = read; + } else { + result = close; + } + + if (result != NWC24_OK) { + return result; + } + + if ((*header)->magic != SECRET_FRIEND_LIST_MAGIC) { + return NWC24_ERR_BROKEN; + } + + if ((*header)->version != SECRET_FRIEND_LIST_VERSION) { + return NWC24_ERR_VER_MISMATCH; + } + } + + return NWC24_OK; +} From 531a88740c068167ad4126e67fdda1d64e153106 Mon Sep 17 00:00:00 2001 From: MrL314 <11429905+MrL314@users.noreply.github.com> Date: Wed, 18 Feb 2026 00:06:47 -0500 Subject: [PATCH 20/52] Fix `setRotateQuaternionInline` and replace --- configure.py | 4 +- include/Game/Enemy/MoguStone.hpp | 2 +- .../include/JSystem/JGeometry/TMatrix.hpp | 97 +++++++++---------- .../include/JSystem/JGeometry/TVec.hpp | 24 ++++- src/Game/Boss/DinoPackun.cpp | 3 +- src/Game/Boss/DinoPackunTailNode.cpp | 11 ++- src/Game/Boss/DodoryuStateLv2.cpp | 42 +------- src/Game/Boss/SkeletalFishGuard.cpp | 54 +++-------- src/Game/Enemy/MoguStone.cpp | 7 +- src/Game/MapObj/SpinDriver.cpp | 8 +- src/Game/MapObj/StarPiece.cpp | 3 +- src/Game/Ride/Tamakoro.cpp | 5 +- 12 files changed, 101 insertions(+), 159 deletions(-) diff --git a/configure.py b/configure.py index 3106eacd7..c73f061d0 100644 --- a/configure.py +++ b/configure.py @@ -1951,12 +1951,12 @@ def JSys_J3DLib(lib_name: str, objects: List[Object]) -> Dict[str, Any]: Object(NonMatching, "Game/Ride/SpaceCocoon.cpp"), Object(NonMatching, "Game/Ride/SphereAccelSensorController.cpp"), Object(Matching, "Game/Ride/SphereController.cpp"), - Object(NonMatching, "Game/Ride/SpherePadController.cpp"), + Object(Matching, "Game/Ride/SpherePadController.cpp"), Object(Matching, "Game/Ride/SurfRay.cpp"), Object(Matching, "Game/Ride/SurfRayTutorial.cpp"), Object(NonMatching, "Game/Ride/SwingRope.cpp"), Object(Matching, "Game/Ride/SwingRopePoint.cpp"), - Object(NonMatching, "Game/Ride/Tamakoro.cpp"), + Object(Matching, "Game/Ride/Tamakoro.cpp"), Object(NonMatching, "Game/Ride/TamakoroTutorial.cpp"), Object(NonMatching, "Game/Ride/Trapeze.cpp"), ], diff --git a/include/Game/Enemy/MoguStone.hpp b/include/Game/Enemy/MoguStone.hpp index 4c280a869..173bdac90 100644 --- a/include/Game/Enemy/MoguStone.hpp +++ b/include/Game/Enemy/MoguStone.hpp @@ -26,7 +26,7 @@ class MoguStone : public ModelObj { void emit(bool, const TVec3f&, const TVec3f&, f32); TQuat4f _90; - TVec4f _A0; + TQuat4f _A0; TVec3f _B0; f32 _BC; bool _C0; diff --git a/libs/JSystem/include/JSystem/JGeometry/TMatrix.hpp b/libs/JSystem/include/JSystem/JGeometry/TMatrix.hpp index 175bec59f..36fbd102b 100644 --- a/libs/JSystem/include/JSystem/JGeometry/TMatrix.hpp +++ b/libs/JSystem/include/JSystem/JGeometry/TMatrix.hpp @@ -2,6 +2,7 @@ #include "JSystem/JGeometry/TQuat.hpp" #include "JSystem/JGeometry/TVec.hpp" +#include #include namespace JGeometry { @@ -263,7 +264,34 @@ namespace JGeometry { void setEulerZ(f32 val); void getQuat(TQuat4f& rDest) const; - void setQuat(const TQuat4f& rSrc); + void setQuat(const TQuat4f& q) { + // this is VERY weird... however, it matches. + // TODO: is there a better way to write this? + + f32 yy = 2.0f * q.y * q.y; + f32 zz = 2.0f * q.z * q.z; + f32 xx = 2.0f * q.x * q.x; + + f32 xy = 2.0f * q.x * q.y; + f32 xz = 2.0f * q.x * q.z; + f32 yz = 2.0f * q.y * q.z; + + f32 wx = 2.0f * q.w * q.x; + f32 wy = 2.0f * q.w * q.y; + f32 wz = 2.0f * q.w * q.z; + + this->mMtx[0][0] = 1.0f - yy - zz; + this->mMtx[0][1] = xy - wz; + this->mMtx[0][2] = xz + wy; + + this->mMtx[1][0] = xy + wz; + this->mMtx[1][1] = 1.0f - xx - zz; + this->mMtx[1][2] = yz - wx; + + this->mMtx[2][0] = xz - wy; + this->mMtx[2][1] = yz + wx; + this->mMtx[2][2] = 1.0f - xx - yy; + } void getScale(TVec3f& rDest) const; void setScale(const TVec3f& rSrc); @@ -280,11 +308,9 @@ namespace JGeometry { } void setRotate(const TVec3f&, f32); void setRotate(const TVec3f& v1, const TVec3f& v2) { - // warning, does not match because of the quaternion rotation inline - // though logic is correct. TQuat4f q; q.setRotate(v1, v2); - setRotateQuaternionInline(q); + setQuat(q); } void mult33(TVec3f&) const; @@ -461,51 +487,6 @@ namespace JGeometry { this->mMtx[2][2] = (negc * (z * z) + c); } - void setRotateQuaternionInline(const TQuat4f& q) { - f32 two = 2.0f; - - f32 y = q.y; - f32 x = q.x; - f32 z = q.z; - f32 w = q.w; - - // NOTE: this doesnt quite match yet, needs some - // messing around with to actually properly match... - /* - // this is the actual math going on - this->mMtx[0][0] = (1.0f - 2.0f * y * y) - 2.0f * z * z; - this->mMtx[0][1] = 2.0f * x * y - 2.0f * w * z; - this->mMtx[0][2] = 2.0f * x * z + 2.0f * w * y; - this->mMtx[1][0] = 2.0f * x * y + 2.0f * w * z; - this->mMtx[1][1] = (1.0f - 2.0f * x * x) - 2.0f * z * z; - this->mMtx[1][2] = 2.0f * z * y - 2.0f * w * x; - this->mMtx[2][0] = 2.0f * x * z - 2.0f * w * y; - this->mMtx[2][1] = 2.0f * z * y + 2.0f * w * x; - this->mMtx[2][2] = (1.0f - 2.0f * x * x) - 2.0f * y * y; - */ - - // this is the closest match I have so far - // https://decomp.me/scratch/N91r6 - this->mMtx[0][0] = (1.0f - two * y * y) - two * z * z; - this->mMtx[2][0] = two * x * z - two * w * y; - this->mMtx[0][2] = two * x * z + two * w * y; - - this->mMtx[0][1] = two * x * y - two * w * z; - this->mMtx[1][0] = two * x * y + two * w * z; - this->mMtx[1][1] = (1.0f - two * x * x) - two * z * z; - - this->mMtx[2][1] = two * z * y + two * w * x; - this->mMtx[1][2] = two * z * y - two * w * x; - this->mMtx[2][2] = (1.0f - two * x * x) - two * y * y; - } - - void setRotateQuaternionInlineAndTrans(const TQuat4f& q, const TVec3f& v) { - setRotateQuaternionInline(q); - this->mMtx[0][3] = v.x; - this->mMtx[1][3] = v.y; - this->mMtx[2][3] = v.z; - } - inline void mult33Inline(const TVec3f& rSrc, TVec3f& rDst) const { f32 a32, a22, a12, a11, a21, vx, a31, vy, a23, a33, a13; a32 = this->mMtx[2][1]; @@ -529,15 +510,27 @@ namespace JGeometry { struct TPosition3 : public TRotation3< T > { public: void getTrans(TVec3f& rDest) const; - void setTrans(const TVec3f& rSrc); + + void setTrans(const TVec3f& rSrc) { + this->mMtx[0][3] = rSrc.x; + this->mMtx[1][3] = rSrc.y; + this->mMtx[2][3] = rSrc.z; + } + void setTrans(f32 x, f32 y, f32 z); void zeroTrans(); void makeRotate(const TVec3f&, f32); - void makeQuat(const TQuat4f& rSrc); + + void makeQuat(const TQuat4f& rSrcQuat) { + zeroTrans(); + TRotation3< T >::setQuat(rSrcQuat); + } + void setPositionFromLookAt(const TPosition3< T >& rLookAt); + void setQT(const TQuat4f& rSrcQuat, const TVec3f& rSrcTrans) { - TRotation3< T >::setRotateQuaternionInline(rSrcQuat); + TRotation3< T >::setQuat(rSrcQuat); setTrans(rSrcTrans); } diff --git a/libs/JSystem/include/JSystem/JGeometry/TVec.hpp b/libs/JSystem/include/JSystem/JGeometry/TVec.hpp index 57ae8d632..1469760da 100644 --- a/libs/JSystem/include/JSystem/JGeometry/TVec.hpp +++ b/libs/JSystem/include/JSystem/JGeometry/TVec.hpp @@ -552,7 +552,13 @@ namespace JGeometry { } void scale(f32 scale); - void scale(f32, const TVec3&); + + void scale(f32 scalar, const TVec3& rVec); /*{ + this->x = rVec.x * scalar; + this->y = rVec.y * scalar; + this->z = rVec.z * scalar; + }*/ + void negate(); f32 normalize() { @@ -661,7 +667,7 @@ namespace JGeometry { f32 angle(const TVec3&) const; - inline TVec3 cross(const TVec3& b) { + inline TVec3 cross(const TVec3& b) const { TVec3 ret; PSVECCrossProduct(this, &b, &ret); return ret; @@ -782,7 +788,19 @@ namespace JGeometry { void setEuler(T _x, T _y, T _z); void setEulerZ(T _z); - void setRotate(const TVec3< T >&, const TVec3< T >&, T); + void setRotate(const TVec3< f32 >& rA, const TVec3< f32 >& rB, f32 ratio) { + TVec3< f32 > dir = rA.cross(rB); + f32 crossPart = dir.length(); + if (crossPart <= 0.0000038146973f) { + set< f32 >(0.0f, 0.0f, 0.0f, 1.0f); + } else { + f32 dotPart = rA.dot(rB); + f32 halfAngle = ratio * (JMath::sAtanTable.atan2_(crossPart, dotPart) * 0.5f); + toTvec()->scale((f32)sin(halfAngle) / crossPart, dir); + this->w = cos(halfAngle); + } + } + void setRotate(const TVec3< T >&, const TVec3< T >&); void setRotate(const TVec3< T >& pVec, f32 pAngle) { diff --git a/src/Game/Boss/DinoPackun.cpp b/src/Game/Boss/DinoPackun.cpp index dca35e476..c9f7bdb81 100644 --- a/src/Game/Boss/DinoPackun.cpp +++ b/src/Game/Boss/DinoPackun.cpp @@ -470,8 +470,7 @@ void DinoPackun::resetPosition() { MR::zeroVelocity(this); TPos3f v28; - v28.setRotateQuaternionInline(_BC); - v28.setTrans(mPosition); + v28.setQT(_BC, mPosition); TVec3f v27; v28.mult(sMarioSetLocalPos, v27); TVec3f v26; diff --git a/src/Game/Boss/DinoPackunTailNode.cpp b/src/Game/Boss/DinoPackunTailNode.cpp index 597f2b134..7396e100e 100644 --- a/src/Game/Boss/DinoPackunTailNode.cpp +++ b/src/Game/Boss/DinoPackunTailNode.cpp @@ -7,7 +7,8 @@ typedef bool (DinoPackunTailNode::*func)(TPos3f*, const JointControllerInfo&); DinoPackunTailNode::DinoPackunTailNode(const char* pName, DinoPackun* pParent) : LiveActor(pName), mParent(pParent), mNodeDirection(0, 0, 0), _9C(0, 0, 0), _A8(0.0f, 0.0f, 0.0f), _B4(nullptr), _B8(nullptr), _BC(nullptr), - _C0(nullptr), _C4(nullptr), mLinkLength(90.0f), mKeepBendPower(10.0f), _D0(0) {} + _C0(nullptr), _C4(nullptr), mLinkLength(90.0f), mKeepBendPower(10.0f), _D0(0) { +} void DinoPackunTailNode::createJointController(LiveActor* pHost, const char* pJointName) { _C4 = static_cast< Delegator* >(createJointControllerOwn(pHost, pJointName)); @@ -71,7 +72,7 @@ bool DinoPackunTailNode::turnJointLocalXDir(TPos3f* pMtx, const JointControllerI MR::normalize(&v23); MR::turnQuatXDirRad(&v24, v24, v23, M_PI); - pMtx->setRotateQuaternionInlineAndTrans(v24, mPosition); + pMtx->setQT(v24, mPosition); return true; } @@ -148,6 +149,8 @@ void DinoPackunTailNode::addNodeVelocity(const TVec3f& rVel) { mVelocity.addInline(rVel); } -void DinoPackunTailNode::requestLockPosition() {} +void DinoPackunTailNode::requestLockPosition() { +} -void DinoPackunTailNode::requestUnLockPosition() {} +void DinoPackunTailNode::requestUnLockPosition() { +} diff --git a/src/Game/Boss/DodoryuStateLv2.cpp b/src/Game/Boss/DodoryuStateLv2.cpp index 7a51b78e4..609faa714 100644 --- a/src/Game/Boss/DodoryuStateLv2.cpp +++ b/src/Game/Boss/DodoryuStateLv2.cpp @@ -852,7 +852,7 @@ void DodoryuStateLv2::addVelocity(bool snapToGround) { } void DodoryuStateLv2::calcLimitedRotateMtx(TPos3f* pMtx, const TVec3f& rFrom, const TVec3f& rTo, f32 rate) { - f32 maxAngle = rate * 3.14159f / 180.0f; + f32 maxAngle = rate * PI / 180.0f; TVec3f cross; PSVECCrossProduct(&rFrom, &rTo, &cross); f32 crossMag = cross.length(); @@ -863,43 +863,9 @@ void DodoryuStateLv2::calcLimitedRotateMtx(TPos3f* pMtx, const TVec3f& rFrom, co if (absAngle > maxAngle) { ratio = maxAngle / absAngle; } - TVec3f cross2; - PSVECCrossProduct(&rFrom, &rTo, &cross2); - f32 crossMag2 = cross2.length(); - TVec4f quat; - if (crossMag2 <= 0.001f) { - quat.x = 0.0f; - quat.y = 0.0f; - quat.z = 0.0f; - quat.w = 1.0f; - } else { - f32 dotResult2 = rFrom.dot(rTo); - f32 angle2 = JMath::sAtanTable.atan2_(crossMag2, dotResult2); - f32 halfAngle = ratio * angle2 * 0.5f; - f32 sinHalf = sin(halfAngle); - TVec3f* pQuatXYZ = (TVec3f*)&quat; - pQuatXYZ->scale(sinHalf / crossMag2, cross2); - quat.w = cos(halfAngle); - } - pMtx->zeroTrans(); - f32 xx = 2.0f * quat.x * quat.x; - f32 yy = 2.0f * quat.y * quat.y; - f32 zz = 2.0f * quat.z * quat.z; - f32 xy = 2.0f * quat.x * quat.y; - f32 xz = 2.0f * quat.x * quat.z; - f32 xw = 2.0f * quat.w * quat.z; - f32 yz = 2.0f * quat.y * quat.z; - f32 yw = 2.0f * quat.w * quat.y; - f32 zw = 2.0f * quat.w * quat.x; - pMtx->mMtx[0][0] = 1.0f - yy - zz; - pMtx->mMtx[0][1] = xy - xw; - pMtx->mMtx[0][2] = xz + yw; - pMtx->mMtx[1][0] = xy + xw; - pMtx->mMtx[1][1] = 1.0f - xx - zz; - pMtx->mMtx[1][2] = yz - zw; - pMtx->mMtx[2][0] = xz - yw; - pMtx->mMtx[2][1] = yz + zw; - pMtx->mMtx[2][2] = 1.0f - xx - yy; + TQuat4f quat; + quat.setRotate(rFrom, rTo, ratio); + pMtx->makeQuat(quat); } bool DodoryuStateLv2::isReflectSpinAttack() const { diff --git a/src/Game/Boss/SkeletalFishGuard.cpp b/src/Game/Boss/SkeletalFishGuard.cpp index 5ac73fbd1..90fa8df27 100644 --- a/src/Game/Boss/SkeletalFishGuard.cpp +++ b/src/Game/Boss/SkeletalFishGuard.cpp @@ -254,7 +254,8 @@ void SkeletalFishGuard::exeStraight() { } } -void SkeletalFishGuard::exeDefence() {} +void SkeletalFishGuard::exeDefence() { +} void SkeletalFishGuard::exeKill() { if (MR::isFirstStep(this)) { @@ -318,7 +319,6 @@ void SkeletalFishGuard::waitAttack(s32 time) { mAttackDelay = time; } -/* void SkeletalFishGuard::calcAndSetBaseMtx() { TVec3f stack_64; stack_64.multPS(mScale, mScaleController->_C); @@ -342,8 +342,7 @@ void SkeletalFishGuard::calcAndSetBaseMtx() { stack_D0.setZDir(_D0); stack_D0.setTrans(mPosition); MR::setBaseTRMtx(this, stack_D0); - } - else { + } else { TVec3f stack_30; TVec3f stack_24; JGeometry::negateInternal((f32*)&mGravity, (f32*)&stack_30); @@ -354,26 +353,15 @@ void SkeletalFishGuard::calcAndSetBaseMtx() { TPos3f stack_A0; f32 x, y, z; stack_A0.setInline_2(mtx); - x = stack_A0.mMtx[0][0]; - y = stack_A0.mMtx[1][0]; - z = stack_A0.mMtx[2][0]; - - stack_24.set(x, y, z); - z = stack_A0.mMtx[2][1]; - y = stack_A0.mMtx[1][1]; - x = stack_A0.mMtx[0][1]; - stack_30.set(x, y, z); + stack_A0.getXDirInline(stack_24); + stack_A0.getYDirInline(stack_30); TVec3f stack_18; - z = stack_A0.mMtx[2][2]; - y = stack_A0.mMtx[1][2]; - x = stack_A0.mMtx[0][2]; - stack_18.set(x, y, z); + stack_A0.getZDirInline(stack_18); TQuat4f stack_8; stack_8.setRotate(stack_18, _D0); stack_8.transform(stack_24); stack_8.transform(stack_30); - } - else { + } else { MR::normalize(&stack_24); PSVECCrossProduct(_D0, stack_24, stack_30); } @@ -386,7 +374,6 @@ void SkeletalFishGuard::calcAndSetBaseMtx() { MR::setBaseTRMtx(this, stack_70); } } -*/ void SkeletalFishGuard::exeWait() { MR::setNerveAtStep(this, &::SkeletalFishGuardNrvAppear::sInstance, _A0); @@ -476,11 +463,8 @@ void SkeletalFishGuard::rotateVertical(const TVec3f& a2, f32 a3) { } } - f32 v8 = (0.5f * v7); - f32 v9 = sin(v8); TQuat4f v10; - v10.toTvec()->scale(v9, v12); - v10.w = cos(v8); + v10.setRotate(v12, v7); v10.transform(_D0); } } @@ -528,8 +512,6 @@ bool SkeletalFishGuard::tryShiftKill() { return true; } -// very close. small instruction swap. will figure out compiler error later -/* void SkeletalFishGuard::turn(TVec3f* a1, const TVec3f& a2, const TVec3f& a3, f32 a4) { TQuat4f quat; @@ -540,24 +522,9 @@ void SkeletalFishGuard::turn(TVec3f* a1, const TVec3f& a2, const TVec3f& a3, f32 v10 = (a4 / angle); } - TVec3f v15; - PSVECCrossProduct(&a2, &a3, &v15); - f32 v11 = PSVECMag(&v15); - f32 factor = 1.0f / 262144.0f; - - if (v11 <= factor) { - quat.set(0.0f, 0.0f, 0.0f, 1.0f); - } else { - f32 v12 = a2.dot(a3); - f32 v13 = (v10 * (0.5f * JMath::sAtanTable.atan2_(v11, v12))); - f32 v14 = sin(v13); - quat.scale((v14 / v11), v15); - quat.w = cos(v13); - } - + quat.setRotate(a2, a3, v10); quat.transform(*a1); } -*/ void SkeletalFishGuard::lookToPlayer(f32 a2, f32 a3) { TVec3f pos(*MR::getPlayerCenterPos()); @@ -670,4 +637,5 @@ bool SkeletalFishGuard::tryShiftNumb(const Nerve* pNerve) { return false; } -SkeletalFishGuard::~SkeletalFishGuard() {} +SkeletalFishGuard::~SkeletalFishGuard() { +} diff --git a/src/Game/Enemy/MoguStone.cpp b/src/Game/Enemy/MoguStone.cpp index c4b1a711d..19be3b6a4 100644 --- a/src/Game/Enemy/MoguStone.cpp +++ b/src/Game/Enemy/MoguStone.cpp @@ -186,7 +186,7 @@ void MoguStone::calcAndSetBaseMtx() { mtx[1][3] = 0.0f; mtx[2][3] = 0.0f; - mtx.setRotateQuaternionInlineAndTrans(_90, mPosition); + mtx.setQT(_90, mPosition); MR::setBaseTRMtx(this, mtx); } @@ -226,10 +226,7 @@ void ThrowingIce::doBehavior() { if (MR::isFirstStep(this)) { TVec3f v1; PSVECCrossProduct(_B0, mGravity, &v1); - - f32 one_eighth = 0.125f; - _A0.toTVec3()->scale(sin(one_eighth), v1); - _A0.w = cos(one_eighth); + _A0.setRotate(v1, 0.25f); } f32 rate = MR::calcNerveRate(this, 101); diff --git a/src/Game/MapObj/SpinDriver.cpp b/src/Game/MapObj/SpinDriver.cpp index a735bca31..e6519ca5c 100644 --- a/src/Game/MapObj/SpinDriver.cpp +++ b/src/Game/MapObj/SpinDriver.cpp @@ -319,7 +319,8 @@ bool SpinDriver::trySwitchOff() { return false; } -void SpinDriver::exeTryDemo() {} +void SpinDriver::exeTryDemo() { +} void SpinDriver::exeNonActive() { if (MR::isFirstStep(this)) { @@ -612,7 +613,7 @@ void SpinDriver::updateBindActorMatrix(f32 a1) { TPos3f rotation; MR::makeMtxUpFrontPos(&rotation, _E8, _D0, mPosition); TQuat4f quat; - rotation.makeQuat(quat); + rotation.getQuat(quat); _A8.x = _98.x; _A8.y = _98.y; _A8.z = _98.z; @@ -718,4 +719,5 @@ bool SpinDriver::canBind(HitSensor *pSensor) const { } */ -SpinDriver::~SpinDriver() {} +SpinDriver::~SpinDriver() { +} diff --git a/src/Game/MapObj/StarPiece.cpp b/src/Game/MapObj/StarPiece.cpp index aef964683..6502c4a5b 100644 --- a/src/Game/MapObj/StarPiece.cpp +++ b/src/Game/MapObj/StarPiece.cpp @@ -552,7 +552,6 @@ void StarPiece::exeToTarget() { MR::normalizeOrZero(&touchTargetVec); TQuat4f rotateQuat; - // inlined TQuat4 functions, not matching because functions are not defined yet rotateQuat.setRotate(_8C, touchTargetVec, _98); rotateQuat.rotate(_8C); @@ -573,7 +572,7 @@ void StarPiece::exeToTarget() { MR::normalizeOrZero(&velNormalized); if (!MR::isNearZero(velNormalized)) { f32 dot = _8C.dot(velNormalized); - if (dot < 0.0f) { + if (0.0f < dot) { if (mFlags.isGoToPlayer) { mVelocity.add(MR::getPlayerVelocity()->scaleInline(_9C).scaleInline(dot)); } else { diff --git a/src/Game/Ride/Tamakoro.cpp b/src/Game/Ride/Tamakoro.cpp index a439670ff..be916a4d8 100644 --- a/src/Game/Ride/Tamakoro.cpp +++ b/src/Game/Ride/Tamakoro.cpp @@ -131,8 +131,6 @@ void Tamakoro::calcAndSetBaseMtx() { } void Tamakoro::updateBindActorMatrix() { - // warning, does not match because of the quaternion rotation inline - // though logic is correct. if (isUseMarioOffset()) { JMAVECScaleAdd(&mDirectionToMario, &mPosition, &mMarioPos, 150.0f); if (mMarioOffset > 0) { @@ -142,8 +140,7 @@ void Tamakoro::updateBindActorMatrix() { // quaternion rotation TPos3f mtx; - mtx.setRotateQuaternionInline(mRotateQuat); - mtx.setTrans(mMarioPos); + mtx.setQT(mRotateQuat, mMarioPos); MR::setPlayerBaseMtx(mtx); } From aa66dcd9108996839c474e3faa052afbd93a1d8b Mon Sep 17 00:00:00 2001 From: shibbo Date: Wed, 18 Feb 2026 17:19:27 -0500 Subject: [PATCH 21/52] `NWC24DateParser` at 91% --- .../revolution/nwc24/NWC24DateParser.h | 25 +++ src/RVL_SDK/nwc24/NWC24DateParser.c | 181 ++++++++++++++++++ 2 files changed, 206 insertions(+) create mode 100644 libs/RVL_SDK/include/revolution/nwc24/NWC24DateParser.h create mode 100644 src/RVL_SDK/nwc24/NWC24DateParser.c diff --git a/libs/RVL_SDK/include/revolution/nwc24/NWC24DateParser.h b/libs/RVL_SDK/include/revolution/nwc24/NWC24DateParser.h new file mode 100644 index 000000000..e24240f41 --- /dev/null +++ b/libs/RVL_SDK/include/revolution/nwc24/NWC24DateParser.h @@ -0,0 +1,25 @@ +#ifndef NWC24DATEPARSER_H +#define NWC24DATEPARSER_H + +#include "revolution/nwc24.h" + +#ifdef __cplusplus +extern "C" { +#endif + +NWC24Err NWC24iIsValidDate(u16 year, u8 month, u8 day); + +typedef struct NWC24iDate { + u16 year; + u8 month; + u8 day; + u8 hour; + u8 min; + u8 sec; +} NWC24iDate; + +#ifdef __cplusplus +} +#endif + +#endif // NWC24DATEPARSER_H diff --git a/src/RVL_SDK/nwc24/NWC24DateParser.c b/src/RVL_SDK/nwc24/NWC24DateParser.c new file mode 100644 index 000000000..bf9e6f8b1 --- /dev/null +++ b/src/RVL_SDK/nwc24/NWC24DateParser.c @@ -0,0 +1,181 @@ +#include "revolution/nwc24/NWC24DateParser.h" +#include "revolution/nwc24.h" + +const u8 DAYS_OF_MONTH[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0, 0, 0, 0}; +const u16 DAYS_OF_YEAR[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; + +s32 ConvertDateToDays(u16 year, u16 month, u16 day); +void ConvertDaysToDate(u16* year, u8* month, u8* day, s32 days); + +inline BOOL IsLeapYear(u16 year) { + return (((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) != 0); +} + +NWC24Err NWC24iDateToMinutes(s32* outMinutes, const NWC24iDate* date) { + s32 days; + s32 minutes; + u8 seconds; + + days = ConvertDateToDays(date->year, date->month, date->day); + + if (days == -1) { + return NWC24_ERR_FAILED; + } + + seconds = date->sec; + if (date->hour > 23 || seconds > 59) { + minutes = -1; + } else { + minutes = seconds + (date->hour * 60); + } + + if (minutes == -1 || date->min > 60) { + return NWC24_ERR_FAILED; + } + + *outMinutes = days * (24 * 60) + minutes; + return NWC24_OK; +} + +NWC24Err NWC24iMinutesToDate(NWC24iDate* pDate, s32 days) { + s32 v2 = days; + s32 v4; + + if (days < 0) { + v2 = 0; + } + + days = v2 / 1440; + v4 = v2 % 1440; + pDate->hour = (u8)(v4 / 60); + pDate->sec = (u8)(v4 % 60); + ConvertDaysToDate(&pDate->year, &pDate->month, &pDate->day, days); + return NWC24_OK; +} + +NWC24Err NWC24iEpochSecondsToDate(NWC24iDate* date, s64 timestamp) { + s64 adjusted = -0x7c558180U; + s32 minutes; + u32 days; + + if (0 > (timestamp + adjusted)) { + timestamp = -adjusted; + } + + timestamp += adjusted; + date->min = (u8)(timestamp % 60); + minutes = timestamp / 60; + if (minutes < 0) { + minutes = 0; + } + + days = minutes / (24 * 60); + minutes %= (24 * 60); + date->hour = (u8)(minutes / 60); + date->sec = (u8)(minutes % 60); + ConvertDaysToDate(&date->year, &date->month, &date->day, days); + return NWC24_OK; +} + +NWC24Err NWC24iDateToOSCalendarTime(OSCalendarTime* time, const NWC24iDate* date) { + s32 daysSinceEpoch; + + time->year = date->year; + time->mon = date->month - 1; + time->mday = date->day; + time->hour = date->hour; + time->min = date->sec; // Swapped? + time->sec = date->min; // Swapped? + time->msec = 0; + time->usec = 0; + time->yday = (DAYS_OF_YEAR[time->mon] + date->day) - 1; + + if (IsLeapYear(date->year) && date->month > 2) { + time->yday++; + } + + daysSinceEpoch = ConvertDateToDays(date->year, date->month, date->day); + time->wday = (daysSinceEpoch + 1) % 7; + return NWC24_OK; +} + +s32 ConvertDateToDays(u16 year, u16 month, u16 day) { + s32 dayOfYear; + s32 yearsSince1900; + s32 days; + s32 leapDays; + s32 gregorianCorrection; + + if (year < 1900 || month < 1 || month > 12) { + return -1; + } + + if (month == 2 && IsLeapYear(year)) { + if (day < 1 || day > 29) { + return -1; + } + } else { + if (day < 1 || (u16)DAYS_OF_MONTH[month - 1] < day) { + return -1; + } + } + + dayOfYear = day - 1; + dayOfYear += DAYS_OF_YEAR[month - 1]; + + if (month >= 3 && IsLeapYear(year)) { + dayOfYear++; + } + + yearsSince1900 = year - 1900; + + leapDays = (yearsSince1900 - 1) / 4 - (yearsSince1900 - 1) / 100; + gregorianCorrection = (yearsSince1900 + 299) / 400; + + days = yearsSince1900 * 365 + dayOfYear; + days += leapDays + gregorianCorrection; + + return days; +} + +void ConvertDaysToDate(u16* year, u8* month, u8* day, s32 days) { + s32 remaining; + + *year = 1900; + *month = 1; + *day = 1; + + if (days < 0) { + return; + } + + while (1) { + remaining = days; + days -= IsLeapYear(*year) ? 366 : 365; + + if (days < 0) { + days = remaining; + break; + } + + (*year)++; + } + + while (1) { + remaining = days; + + if (*month == 2 && IsLeapYear(*year)) { + days -= 29; + } else { + days -= DAYS_OF_MONTH[*month - 1]; + } + + if (days < 0) { + break; + } + + (*month)++; + } + + *day += remaining; +} From 5fa07cb168618d173a1375f6ab23fea895f9dadd Mon Sep 17 00:00:00 2001 From: shibbo Date: Wed, 18 Feb 2026 17:25:50 -0500 Subject: [PATCH 22/52] `NWC24StdApi` --- libs/RVL_SDK/include/revolution/net.h | 9 + src/RVL_SDK/nwc24/NWC24StdApi.c | 283 ++++++++++++++++++++++++++ 2 files changed, 292 insertions(+) create mode 100644 libs/RVL_SDK/include/revolution/net.h create mode 100644 src/RVL_SDK/nwc24/NWC24StdApi.c diff --git a/libs/RVL_SDK/include/revolution/net.h b/libs/RVL_SDK/include/revolution/net.h new file mode 100644 index 000000000..38e96bb0f --- /dev/null +++ b/libs/RVL_SDK/include/revolution/net.h @@ -0,0 +1,9 @@ +#ifndef NET_H +#define NET_H + +#include "revolution.h" + +void* NETMemCpy(void*, const void*, u32); +void* NETMemSet(void*, int, u32); + +#endif // NET_H diff --git a/src/RVL_SDK/nwc24/NWC24StdApi.c b/src/RVL_SDK/nwc24/NWC24StdApi.c new file mode 100644 index 000000000..4d4ef17e4 --- /dev/null +++ b/src/RVL_SDK/nwc24/NWC24StdApi.c @@ -0,0 +1,283 @@ +#include "revolution/nwc24/NWC24StdApi.h" +#include "revolution/net.h" +#include "revolution/nwc24.h" + +char* Mail_strcpy(char* dst, const char* src) { + char* backup = dst; + + while (*src != '\0') { + *dst++ = *src++; + }; + + *dst = '\0'; + return backup; +} + +size_t Mail_strlen(const char* str) { + size_t len = 0; + + while (str[len] != '\0') { + len++; + } + + return len; +} + +size_t STD_strnlen(const char* str, size_t n) { + size_t len = 0; + int i; + + for (i = 0; i < n; i++) { + if (str[len] == '\0') { + break; + } + + len++; + } + + return len; +} + +void* Mail_memcpy(void* dst, const void* src, size_t n) { + NETMemCpy(dst, src, n); +} + +void* Mail_memset(void* dst, int ch, size_t n) { + NETMemSet(dst, ch, n); +} + +char* Mail_strcat(char* dst, const char* src) { + Mail_strcpy(dst + Mail_strlen(dst), src); + return dst; +} + +char* Mail_strncat(char* dst, const char* src, size_t n) { + const size_t len = Mail_strlen(dst); + size_t i; + + for (i = 0; i < n && src[i] != '\0'; i++) { + dst[i + len] = src[i]; + }; + + dst[(int)len + (int)i] = '\0'; + return dst; +} + +inline static int Mail_strlen_inline(const char* str) { + int len = 0; + while (str[len] != '\0') { + len++; + } + return len; +} + +inline static void set_to_head(char* str, char c) { + int len = Mail_strlen_inline(str); + int i; + for (i = len; i >= 0; i--) { + str[i + 1] = str[i]; + } + *str = c; +} + +inline static void set_to_tail(char* str, char c) { + int len; + len = Mail_strlen(str); + str[len++] = c; + str[len] = '\0'; +} + +int convNum(char* dst, int number, int numberBase, char charBase, int signedFlag, int width, char specifierChar, char justifyChar) { + unsigned int workingValue; + int charsWritten; + int digitcharsWritten; + char remainder; + char digitCharBase; + char finalPadChar; + BOOL isNegative; + + if ((signedFlag != 0) && (number & 0x80000000)) { + isNegative = 1; + workingValue = -number; + } else { + isNegative = 0; + workingValue = number; + } + + digitcharsWritten = 0; + charsWritten = 0; + + while (workingValue != 0) { + remainder = workingValue % numberBase; + + workingValue /= numberBase; + digitCharBase = charBase; + set_to_head(dst, remainder + ((char)((remainder <= 9) ? (0x30) : (digitCharBase)))); + digitcharsWritten++; + charsWritten++; + } + + if ((*dst) == '\0') { + set_to_head(dst, '0'); + digitcharsWritten++; + charsWritten++; + } + + finalPadChar = specifierChar; + if (finalPadChar != '0') { + finalPadChar = ' '; + } + + digitcharsWritten += isNegative; + + while (digitcharsWritten < width) { + if (justifyChar == 'L') { + set_to_tail(dst, ' '); + charsWritten++; + } else { + set_to_head(dst, finalPadChar); + charsWritten++; + } + digitcharsWritten++; + } + + if (isNegative) { + set_to_head(dst, '-'); + } + + return charsWritten; +} + +int Mail_sprintf(char* buffer, const char* format, ...) { + va_list args; + int ret; + + va_start(args, format); + ret = Mail_vsprintf(buffer, format, args); + va_end(args); + + return ret; +} + +int Mail_vsprintf(char* str, char* format, va_list arg) { + s32 charsWritten; + BOOL isNumberFormat; + BOOL signedFlag; + s32 stringLength; + s32 numberBase; + s32 width; + char formatChar; + char justifyChar; + char specifierChar; + char charBase; + char* stringArg; + char longFlag; + u32 number; + + *str = 0; + charsWritten = 0; + + while ((formatChar = *format++) != 0) { + while (*str) { + str++; + } + + if (formatChar == '%') { + (formatChar = *format++); + if (formatChar == '%') { + set_to_tail(str++, formatChar); + charsWritten++; + } else { + justifyChar = formatChar; + if (formatChar == '-') { + formatChar = *format++; + } + + specifierChar = formatChar; + signedFlag = FALSE; + numberBase = 10; + charBase = '0'; + isNumberFormat = FALSE; + + if (formatChar == '*') { + width = va_arg(arg, int); + formatChar = *format++; + } else { + width = 0; + while ((formatChar >= '0') && (formatChar <= '9')) { + width = width * 10 + formatChar - '0'; + formatChar = *format++; + } + } + + longFlag = formatChar & 0xDF; + if (longFlag == 'L') { + formatChar = *format++; + } + + switch (formatChar) { + case 'd': + isNumberFormat = TRUE; + signedFlag = TRUE; + break; + case 'o': + isNumberFormat = TRUE; + numberBase = 8; + break; + case 'u': + isNumberFormat = TRUE; + break; + case 'x': + isNumberFormat = TRUE; + numberBase = 16; + charBase = 'a' - 10; + break; + case 'X': + isNumberFormat = TRUE; + numberBase = 16; + charBase = 'A' - 10; + break; + case 'c': + formatChar = va_arg(arg, s32); + set_to_tail(str++, formatChar); + charsWritten++; + break; + case 's': + stringArg = va_arg(arg, char*); + if (stringArg) { + stringLength = Mail_strlen(stringArg); + Mail_strcat(str, stringArg); + } else { + stringLength = 0; + } + charsWritten += stringLength; + while (stringLength < width) { + charsWritten++; + if (justifyChar == '-') { + set_to_tail(str, ' '); + } else { + set_to_head(str, ' '); + } + stringLength++; + } + break; + } + + if (isNumberFormat) { + if (longFlag == 'L') { + number = va_arg(arg, u32); + } else if (signedFlag) { + number = va_arg(arg, s32); + } else { + number = va_arg(arg, u32); + } + charsWritten += convNum(str, number, numberBase, charBase, signedFlag, width, specifierChar, justifyChar); + } + } + } else { + set_to_tail(str++, formatChar); + charsWritten++; + } + } + return charsWritten; +} From 721474a54c8554ac90e009b4620723156df4f2b3 Mon Sep 17 00:00:00 2001 From: shibbo Date: Wed, 18 Feb 2026 18:28:05 -0500 Subject: [PATCH 23/52] `NWC24MsgObj` at 51% --- .../include/revolution/nwc24/NWC24Manage.h | 4 +- .../include/revolution/nwc24/NWC24MsgObj.h | 54 ++-- .../include/revolution/nwc24/NWC24Parser.h | 19 ++ .../include/revolution/nwc24/NWC24Types.h | 66 +++-- src/RVL_SDK/nwc24/NWC24FriendList.c | 58 +++++ src/RVL_SDK/nwc24/NWC24MsgObj.c | 231 ++++++++++++++++++ 6 files changed, 369 insertions(+), 63 deletions(-) create mode 100644 libs/RVL_SDK/include/revolution/nwc24/NWC24Parser.h create mode 100644 src/RVL_SDK/nwc24/NWC24FriendList.c create mode 100644 src/RVL_SDK/nwc24/NWC24MsgObj.c diff --git a/libs/RVL_SDK/include/revolution/nwc24/NWC24Manage.h b/libs/RVL_SDK/include/revolution/nwc24/NWC24Manage.h index 46167d315..90c8ca56f 100644 --- a/libs/RVL_SDK/include/revolution/nwc24/NWC24Manage.h +++ b/libs/RVL_SDK/include/revolution/nwc24/NWC24Manage.h @@ -27,8 +27,8 @@ typedef struct NWC24Work { char WORK_0x1200[128]; char WORK_0x1280[128]; u8 base64Work[256]; // at 0x1300 - char WORK_0x1400[0x2400 - 0x1400]; - u8 flHeader[WORK_SIZE(NWC24FLHeader)]; // at 0x2800 + char WORK_0x1400[0x2a00 - 0x1400]; + u8 flHeader[WORK_SIZE(NWC24FLHeader)]; // at 0x2400 u8 secretFlHeader[WORK_SIZE(NWC24SecretFLHeader)]; // at 0x2800 u8 dlHeader[WORK_SIZE(NWC24DlHeader)]; // at 0x3000 u8 dlTask[WORK_SIZE(NWC24DlTask)]; // at 0x3800 diff --git a/libs/RVL_SDK/include/revolution/nwc24/NWC24MsgObj.h b/libs/RVL_SDK/include/revolution/nwc24/NWC24MsgObj.h index 46f86a12e..ec8e2bfca 100644 --- a/libs/RVL_SDK/include/revolution/nwc24/NWC24MsgObj.h +++ b/libs/RVL_SDK/include/revolution/nwc24/NWC24MsgObj.h @@ -1,9 +1,9 @@ #ifndef RVL_SDK_NWC24_MSG_OBJ_H #define RVL_SDK_NWC24_MSG_OBJ_H +#include #include #include #include -#include #ifdef __cplusplus extern "C" { @@ -30,34 +30,34 @@ typedef enum { } NWC24MsgType; typedef struct NWC24MsgObj { - u32 id; // at 0x0 - u32 flags; // at 0x4 - u32 length; // at 0x8 - u32 appId; // at 0xC + u32 id; // at 0x0 + u32 flags; // at 0x4 + u32 length; // at 0x8 + u32 appId; // at 0xC char UNK_0x10[0x4]; - u32 tag; // at 0x14 - u32 ledPattern; // at 0x18 - u64 fromId; // at 0x20 + u32 tag; // at 0x14 + u32 ledPattern; // at 0x18 + u64 fromId; // at 0x20 u32 WORD_0x28; u32 WORD_0x2C; NWC24Data DATA_0x30; NWC24Data DATA_0x38; - NWC24Data subject; // at 0x40 - NWC24Data text; // at 0x48 + NWC24Data subject; // at 0x40 + NWC24Data text; // at 0x48 NWC24Data DATA_0x50; NWC24Data DATA_0x58; - NWC24Charset charset; // at 0x60 - NWC24Encoding encoding; // at 0x64 - NWC24Data attached[NWC24_MSG_ATTACHMENT_MAX]; // at 0x68 - u32 attachedSize[NWC24_MSG_ATTACHMENT_MAX]; // at 0x78 - NWC24MIMEType attachedType[NWC24_MSG_ATTACHMENT_MAX]; // at 0x80 + NWC24Charset charset; // at 0x60 + NWC24Encoding encoding; // at 0x64 + NWC24Data attached[NWC24_MSG_ATTACHMENT_MAX]; // at 0x68 + u32 attachedSize[NWC24_MSG_ATTACHMENT_MAX]; // at 0x78 + NWC24MIMEType attachedType[NWC24_MSG_ATTACHMENT_MAX]; // at 0x80 union { u64 toIds[NWC24_MSG_RECIPIENT_MAX]; NWC24Data toAddrs[NWC24_MSG_RECIPIENT_MAX]; - }; // at 0x88 - u8 numTo; // at 0xC8 - u8 numAttached; // at 0xC9 - u16 groupId; // at 0xCA + }; // at 0x88 + u8 numTo; // at 0xC8 + u8 numAttached; // at 0xC9 + u16 groupId; // at 0xCA union { struct { u32 noreply : 1; @@ -67,17 +67,19 @@ typedef struct NWC24MsgObj { }; u32 raw; - } mb; // at 0xCC + } mb; // at 0xCC NWC24Data DATA_0xD0; - NWC24Data face; // at 0xD8 - NWC24Data alt; // at 0xE0 - char UNK_0xE8[0x100 - 0xE8]; + NWC24Data face; // at 0xD8 + NWC24Data alt; // at 0xE0 + u32 _E8; + u32 _EC; + u32 _F0; + char UNK_0xE8[0x100 - 0xF4]; } NWC24MsgObj; NWC24Err NWC24InitMsgObj(NWC24MsgObj* msg, NWC24MsgType type); NWC24Err NWC24SetMsgToId(NWC24MsgObj* msg, u64 id); -NWC24Err NWC24SetMsgText(NWC24MsgObj* msg, const char* text, u32 len, - NWC24Charset charset, NWC24Encoding encoding); +NWC24Err NWC24SetMsgText(NWC24MsgObj* msg, const char* text, u32 len, NWC24Charset charset, NWC24Encoding encoding); NWC24Err NWC24SetMsgFaceData(NWC24MsgObj* msg, const struct RFLCharData* data); NWC24Err NWC24SetMsgAltName(NWC24MsgObj* msg, const wchar_t* name, u32 len); NWC24Err NWC24SetMsgMBNoReply(NWC24MsgObj* msg, BOOL enable); @@ -86,4 +88,4 @@ NWC24Err NWC24SetMsgMBRegDate(NWC24MsgObj* msg, u16 year, u8 month, u8 day); #ifdef __cplusplus } #endif -#endif \ No newline at end of file +#endif diff --git a/libs/RVL_SDK/include/revolution/nwc24/NWC24Parser.h b/libs/RVL_SDK/include/revolution/nwc24/NWC24Parser.h new file mode 100644 index 000000000..4518692cb --- /dev/null +++ b/libs/RVL_SDK/include/revolution/nwc24/NWC24Parser.h @@ -0,0 +1,19 @@ +#ifndef NWC24PARSER_H +#define NWC24PARSER_H + +#include "revolution/nwc24.h" + +#ifdef __cplusplus +extern "C" { +#endif + +const char* NWC24GetMIMETypeStr(NWC24MIMEType type); +const char* NWC24iGetMIMETypeSuffix(NWC24MIMEType type); +const char* NWC24GetCharsetStr(NWC24Charset set); +const char* NWC24GetEncodingStr(NWC24Encoding enc); + +#ifdef __cplusplus +} +#endif + +#endif // NWC24PARSER_H diff --git a/libs/RVL_SDK/include/revolution/nwc24/NWC24Types.h b/libs/RVL_SDK/include/revolution/nwc24/NWC24Types.h index 73748e1c6..6d6e3d661 100644 --- a/libs/RVL_SDK/include/revolution/nwc24/NWC24Types.h +++ b/libs/RVL_SDK/include/revolution/nwc24/NWC24Types.h @@ -4,43 +4,39 @@ #include typedef enum NWC24Charset { - NWC24_US_ASCII = 0x00000000, - NWC24_UTF_8 = 0x00010008, - NWC24_UTF_16 = 0x00010010, - NWC24_UTF_16BE = 0x00010010, - NWC24_UTF_32 = 0x00010020, - NWC24_UTF_32BE = 0x00010020, - NWC24_ISO_2022_JP = 0x00020000, - NWC24_SHIFT_JIS = 0x00020001, - NWC24_EUC_JP = 0x00020002, - NWC24_ISO_8859_1 = 0x00080001, - NWC24_ISO_8859_2 = 0x00080002, - NWC24_ISO_8859_3 = 0x00080003, - NWC24_ISO_8859_5 = 0x00080005, - NWC24_ISO_8859_7 = 0x00080007, - NWC24_ISO_8859_9 = 0x00080009, - NWC24_ISO_8859_10 = 0x0008000A, - NWC24_ISO_8859_15 = 0x0008000F, - NWC24_CHARSET_UNKNOWN = 0xFFFFFFFF + NWC24_US_ASCII = 0x00000000, + NWC24_UTF_8 = 0x00010008, + NWC24_UTF_16 = 0x00010010, + NWC24_UTF_16BE = 0x00010010, + NWC24_UTF_32 = 0x00010020, + NWC24_UTF_32BE = 0x00010020, + NWC24_ISO_2022_JP = 0x00020000, + NWC24_SHIFT_JIS = 0x00020001, + NWC24_EUC_JP = 0x00020002, + NWC24_ISO_8859_1 = 0x00080001, + NWC24_ISO_8859_2 = 0x00080002, + NWC24_ISO_8859_3 = 0x00080003, + NWC24_ISO_8859_5 = 0x00080005, + NWC24_ISO_8859_7 = 0x00080007, + NWC24_ISO_8859_9 = 0x00080009, + NWC24_ISO_8859_10 = 0x0008000A, + NWC24_ISO_8859_15 = 0x0008000F, + NWC24_CHARSET_UNKNOWN = 0xFFFFFFFF } NWC24Charset; -typedef enum NWC24Encoding { - NWC24_ENC_7BIT, - NWC24_ENC_8BIT, - NWC24_ENC_BASE64, - NWC24_ENC_QUOTED_PRINTABLE, - NWC24_MAX_ENCODINGS -} NWC24Encoding; +typedef enum NWC24Encoding { NWC24_ENC_7BIT, NWC24_ENC_8BIT, NWC24_ENC_BASE64, NWC24_ENC_QUOTED_PRINTABLE, NWC24_MAX_ENCODINGS } NWC24Encoding; -typedef enum NWC24MIMEType { - NWC24_VOID_MIMETYPE = 0x00000000, - NWC24_TXT_PLAIN = 0x00010000, - NWC24_IMG_JPEG = 0x00020000, - NWC24_IMG_WII_PICTURE = 0x00020001, - NWC24_APP_OCTET_STREAM = 0x00030000, - NWC24_APP_WII_MSGBOARD = 0x00030001, - NWC24_APP_WII_MINIDATA = 0x00030002, - NWC24_MUL_MIXED = 0x000F0000 +typedef enum { + NWC24_APPLICATION_OCTET_STREAM = 0x00030000, + NWC24_X_WII_MINIDATA = 0x00030002, + NWC24_X_WII_MSGBOARD = 0x00030001, + NWC24_IMAGE_JPEG = 0x00020000, + NWC24_X_WII_PICTURE = 0x00020001, + NWC24_MULTIPART_ALTERNATIVE = 0x000F0001, + NWC24_MULTIPART_MIXED = 0x000F0000, + NWC24_MULTIPART_RELATED = 0x000F0002, + NWC24_TEXT_HTML = 0x00010001, + NWC24_TEXT_PLAIN = 0x00010000 } NWC24MIMEType; -#endif \ No newline at end of file +#endif diff --git a/src/RVL_SDK/nwc24/NWC24FriendList.c b/src/RVL_SDK/nwc24/NWC24FriendList.c new file mode 100644 index 000000000..b05a7b7e6 --- /dev/null +++ b/src/RVL_SDK/nwc24/NWC24FriendList.c @@ -0,0 +1,58 @@ +#include "revolution/nwc24/NWC24FriendList.h" +#include "revolution/nwc24/NWC24FileApi.h" +#include "revolution/nwc24/NWC24Manage.h" +#include "revolution/nwc24/NWC24StdApi.h" + + +#define FRIEND_LIST_MAGIC FOURCC('W', 'c', 'F', 'l') +#define FRIEND_LIST_VERSION 2 + +static const char* FLFilePath = "/shared2/wc24/nwc24fl.bin"; + +static NWC24Err GetCachedFLHeader(NWC24FLHeader** header); + +NWC24Err NWC24iOpenFriendList(void) { + NWC24FLHeader* header = (NWC24FLHeader*)NWC24WorkP->flHeader; + Mail_memset(header, 0, sizeof(NWC24FLHeader)); + return GetCachedFLHeader(&header); +} + +static NWC24Err GetCachedFLHeader(NWC24FLHeader** header) { + NWC24File file; + NWC24Err result; + NWC24Err read; + NWC24Err close; + + *header = (NWC24FLHeader*)NWC24WorkP->flHeader; + + if ((*header)->magic != FRIEND_LIST_MAGIC) { + result = NWC24FOpen(&file, FLFilePath, NWC24_OPEN_NAND_R); + if (result != NWC24_OK) { + return result; + } + + NWC24FSeek(&file, 0, NWC24_SEEK_BEG); + read = NWC24FRead(*header, sizeof(NWC24FLHeader), &file); + close = NWC24FClose(&file); + + if (read != NWC24_OK) { + result = read; + } else { + result = close; + } + + if (result != NWC24_OK) { + return result; + } + + if ((*header)->magic != FRIEND_LIST_MAGIC) { + return NWC24_ERR_BROKEN; + } + + if ((*header)->version != FRIEND_LIST_VERSION) { + return NWC24_ERR_VER_MISMATCH; + } + } + + return NWC24_OK; +} diff --git a/src/RVL_SDK/nwc24/NWC24MsgObj.c b/src/RVL_SDK/nwc24/NWC24MsgObj.c new file mode 100644 index 000000000..3b54c0fc8 --- /dev/null +++ b/src/RVL_SDK/nwc24/NWC24MsgObj.c @@ -0,0 +1,231 @@ +#include "revolution/nwc24.h" +#include "revolution/nwc24/NWC24Config.h" +#include "revolution/nwc24/NWC24Parser.h" +#include "revolution/nwc24/NWC24StdApi.h" +#include "revolution/nwc24/NWC24Types.h" + +#define YEAR_MIN 2000 +#define YEAR_MAX 2035 // !!! + +#define ALT_NAME_MAX 35 +#define SMTP_LINE_MAX 1000 + +typedef enum { + MSG_OBJ_FOR_RECIPIENT = (1 << 0), + MSG_OBJ_FOR_PUBLIC = (1 << 1), + MSG_OBJ_FOR_APP = (1 << 2), + MSG_OBJ_FOR_MENU = (1 << 3), + MSG_OBJ_INITIALIZED = (1 << 8), + MSG_OBJ_DELIVERING = (1 << 9) +} NWC24MsgObjFlags; + +NWC24Err NWC24InitMsgObj(NWC24MsgObj* msg, NWC24MsgType type) { + u32 i; + NWC24MsgObj* _msg = (NWC24MsgObj*)msg; + + Mail_memset(_msg, 0, sizeof(NWC24MsgObj)); + + _msg->id = 0; + _msg->flags = MSG_OBJ_INITIALIZED; + _msg->appId = NWC24GetAppId(); + _msg->ledPattern = 0; + _msg->tag = 0; + _msg->groupId = NWC24GetGroupId(); + + switch (type) { + case NWC24_MSGTYPE_RVL_MENU_SHARED: + _msg->flags |= MSG_OBJ_FOR_RECIPIENT | MSG_OBJ_FOR_APP | MSG_OBJ_FOR_MENU; + break; + case NWC24_MSGTYPE_RVL: + _msg->flags |= MSG_OBJ_FOR_RECIPIENT | MSG_OBJ_FOR_APP; + break; + case NWC24_MSGTYPE_RVL_MENU: + _msg->flags |= MSG_OBJ_FOR_RECIPIENT | MSG_OBJ_FOR_MENU; + break; + case NWC24_MSGTYPE_RVL_HIDDEN: + _msg->flags |= MSG_OBJ_FOR_RECIPIENT; + break; + case NWC24_MSGTYPE_PUBLIC: + _msg->flags |= MSG_OBJ_FOR_PUBLIC; + break; + default: + return NWC24_ERR_INVALID_VALUE; + } + + _msg->flags |= 0x200000; + _msg->WORD_0x28 = 0; + _msg->WORD_0x2C = 0; + NWC24GetMyUserId(&_msg->fromId); + _msg->numTo = 0; + + for (i = 0; i < NWC24_MSG_RECIPIENT_MAX; i++) { + if (type == NWC24_MSGTYPE_PUBLIC) { + NWC24Data_Init(&_msg->toAddrs[i]); + } else { + _msg->toIds[i] = 0; + } + } + + NWC24Data_Init(&_msg->subject); + NWC24Data_Init(&_msg->text); + _msg->charset = NWC24_US_ASCII; + _msg->encoding = NWC24_ENC_7BIT; + _msg->numAttached = 0; + + for (i = 0; i < NWC24_MSG_ATTACHMENT_MAX; i++) { + NWC24Data_Init(&_msg->attached[i]); + _msg->attachedSize[i] = 0; + _msg->attachedType[i] = NWC24_TEXT_PLAIN; + } + + NWC24Data_Init(&_msg->DATA_0x30); + NWC24Data_Init(&_msg->DATA_0x38); + NWC24Data_Init(&_msg->DATA_0x50); + NWC24Data_Init(&_msg->DATA_0x58); + NWC24Data_Init(&_msg->DATA_0xD0); + NWC24Data_Init(&_msg->face); + NWC24Data_Init(&_msg->alt); + _msg->mb.raw = 0; + + // NEW IN SMG1 + _msg->_EC = 0; + _msg->_F0 = 0x80000000; + + return NWC24_OK; +} + +NWC24Err NWC24SetMsgToId(NWC24MsgObj* msg, u64 id) { + if (!(msg->flags & MSG_OBJ_INITIALIZED) || (msg->flags & MSG_OBJ_DELIVERING)) { + return NWC24_ERR_PROTECTED; + } + + if (!(msg->flags & MSG_OBJ_FOR_RECIPIENT)) { + return NWC24_ERR_NOT_SUPPORTED; + } + + if (msg->numTo >= NWC24_MSG_RECIPIENT_MAX) { + return NWC24_ERR_FULL; + } + + msg->toIds[msg->numTo] = id; + msg->numTo++; + + return NWC24_OK; +} + +NWC24Err NWC24SetMsgText(NWC24MsgObj* msg, const char* text, u32 len, NWC24Charset charset, NWC24Encoding encoding) { + if (!(msg->flags & MSG_OBJ_INITIALIZED) || (msg->flags & MSG_OBJ_DELIVERING)) { + return NWC24_ERR_PROTECTED; + } + + if (NWC24GetCharsetStr(charset) == NULL) { + return NWC24_ERR_INVALID_VALUE; + } + + if (NWC24GetEncodingStr(encoding) == NULL) { + return NWC24_ERR_INVALID_VALUE; + } + + if (text == NULL) { + NWC24Data_Init(&msg->text); + return NWC24_OK; + } + + // NEW IN SMG1 + if (encoding == NWC24_ENC_8BIT) { + if (msg->flags & 0x2) { + return NWC24_ERR_NOT_SUPPORTED; + } + } + + if (encoding == NWC24_ENC_7BIT) { + const char* it; + u32 lineLength; + + lineLength = 0; + + for (it = text; it < text + len; it++) { + if (it[0] == '\r' && it[1] == '\n') { + lineLength = 0; + it++; + } + // Include "\r\n" in line length + else if (++lineLength > SMTP_LINE_MAX - 2) { + return NWC24_ERR_FORMAT; + } + } + } + + NWC24Data_SetDataP(&msg->text, text, len); + msg->charset = charset; + msg->encoding = encoding; + return NWC24_OK; +} + +// NWC24SetMsgAttached + +NWC24Err NWC24SetMsgTag(NWC24MsgObj* obj, u16 tag) { + if ((obj->flags & 0x100) == 0 || (obj->flags & 0x200) != 0) { + return NWC24_ERR_PROTECTED; + } + + if ((obj->flags & 0x1) == 0) { + return NWC24_ERR_NOT_SUPPORTED; + } + + obj->tag = obj->tag & 0xFFFF0000 | tag; + return NWC24_OK; +} + +NWC24Err NWC24SetMsgAltName(NWC24MsgObj* msg, const wchar_t* name, u32 len) { + if (!(msg->flags & MSG_OBJ_INITIALIZED) || (msg->flags & MSG_OBJ_DELIVERING)) { + return NWC24_ERR_PROTECTED; + } + + if (msg->alt.size > 0) { + return NWC24_ERR_FULL; + } + + if (len > ALT_NAME_MAX) { + return NWC24_ERR_INVALID_VALUE; + } + + if (name == NULL || len == 0) { + return NWC24_ERR_NULL; + } + + NWC24Data_SetDataP(&msg->alt, name, len * sizeof(wchar_t)); + return NWC24_OK; +} + +NWC24Err NWC24SetMsgMBNoReply(NWC24MsgObj* msg, BOOL enable) { + if (!(msg->flags & MSG_OBJ_INITIALIZED) || (msg->flags & MSG_OBJ_DELIVERING)) { + return NWC24_ERR_PROTECTED; + } + + if (!(msg->flags & MSG_OBJ_FOR_MENU)) { + return NWC24_ERR_NOT_SUPPORTED; + } + + if (enable) { + msg->mb.noreply = TRUE; + } else { + msg->mb.noreply = FALSE; + } + + return NWC24_OK; +} + +// NWC24SetMsgMBDelay +// NWC24SetMsgLedPattern + +NWC24Err NWC24GetMsgSize(const NWC24MsgObj* obj, u32* size) { + if ((obj->flags & 0x200) == 0) { + return NWC24_ERR_PROTECTED; + } + + *size = obj->length; + return NWC24_OK; +} + +// NWC24SetMsgDesignatedTime From 1076c44fb054440c6ac4ced809203a43d3714e97 Mon Sep 17 00:00:00 2001 From: MrL314 <11429905+MrL314@users.noreply.github.com> Date: Wed, 18 Feb 2026 21:27:28 -0500 Subject: [PATCH 24/52] `Tamakoro` cleanup --- config/RMGK01/symbols.txt | 34 +- include/Game/Ride/Tamakoro.hpp | 41 +- src/Game/Ride/SpherePadController.cpp | 32 +- src/Game/Ride/Tamakoro.cpp | 642 ++++++++++++-------------- src/Game/Scene/SceneObjHolder.cpp | 4 +- 5 files changed, 365 insertions(+), 388 deletions(-) diff --git a/config/RMGK01/symbols.txt b/config/RMGK01/symbols.txt index c69e10e46..4253797f2 100644 --- a/config/RMGK01/symbols.txt +++ b/config/RMGK01/symbols.txt @@ -57111,28 +57111,44 @@ __vt__Q212NrvSwingRope16SwingRopeNrvFree = .data:0x805D0BA4; // type:object size __vt__Q212NrvSwingRope16SwingRopeNrvStop = .data:0x805D0BB4; // type:object size:0x10 scope:global align:4 __vt__14SwingRopePoint = .data:0x805D0BC8; // type:object size:0xC scope:global align:4 lbl_805D0BD8 = .data:0x805D0BD8; // type:object size:0x9 data:string -lbl_805D0BE1 = .data:0x805D0BE1; // type:object size:0x17 +lbl_805D0BE1 = .data:0x805D0BE1; // type:object size:0x17 data:string lbl_805D0BF8 = .data:0x805D0BF8; // type:object size:0x5 data:string lbl_805D0BFD = .data:0x805D0BFD; // type:object size:0x5 data:string @63943 = .data:0x805D0C04; // type:object size:0xC scope:local align:4 data:4byte lbl_805D0C10 = .data:0x805D0C10; // type:object size:0x5 data:string lbl_805D0C15 = .data:0x805D0C15; // type:object size:0xC data:string -lbl_805D0C21 = .data:0x805D0C21; // type:object size:0x47 -lbl_805D0C68 = .data:0x805D0C68; // type:object size:0x23 +lbl_805D0C21 = .data:0x805D0C21; // type:object size:0xE data:string +lbl_805D0C2F = .data:0x805D0C2F; // type:object size:0x15 data:string +lbl_805D0C44 = .data:0x805D0C44; // type:object size:0xF data:string +lbl_805D0C53 = .data:0x805D0C53; // type:object size:0xD data:string +lbl_805D0C60 = .data:0x805D0C60; // type:object size:0x8 data:string +lbl_805D0C68 = .data:0x805D0C68; // type:object size:0x5 data:string +lbl_805D0C6D = .data:0x805D0C6D; // type:object size:0x12 data:string +lbl_805D0C7F = .data:0x805D0C7F; // type:object size:0xC data:string lbl_805D0C8B = .data:0x805D0C8B; // type:object size:0x14 data:string -lbl_805D0C9F = .data:0x805D0C9F; // type:object size:0x33 -lbl_805D0CD2 = .data:0x805D0CD2; // type:object size:0xD +lbl_805D0C9F = .data:0x805D0C9F; // type:object size:0xD data:string +lbl_805D0CAC = .data:0x805D0CAC; // type:object size:0x9 data:string +lbl_805D0CB5 = .data:0x805D0CB5; // type:object size:0xC data:string +lbl_805D0CC1 = .data:0x805D0CC1; // type:object size:0x11 data:string +lbl_805D0CD2 = .data:0x805D0CD2; // type:object size:0xD data:string lbl_805D0CDF = .data:0x805D0CDF; // type:object size:0x5 data:string lbl_805D0CE4 = .data:0x805D0CE4; // type:object size:0x9 data:string -lbl_805D0CED = .data:0x805D0CED; // type:object size:0x2C +lbl_805D0CED = .data:0x805D0CED; // type:object size:0x9 data:string +lbl_805D0CF6 = .data:0x805D0CF6; // type:object size:0xD data:string +lbl_805D0D03 = .data:0x805D0D03; // type:object size:0x16 data:string lbl_805D0D19 = .data:0x805D0D19; // type:object size:0x8 data:string lbl_805D0D21 = .data:0x805D0D21; // type:object size:0x13 data:string -lbl_805D0D34 = .data:0x805D0D34; // type:object size:0x11 +lbl_805D0D34 = .data:0x805D0D34; // type:object size:0x11 data:string lbl_805D0D45 = .data:0x805D0D45; // type:object size:0xC data:string lbl_805D0D51 = .data:0x805D0D51; // type:object size:0xC data:string -lbl_805D0D5D = .data:0x805D0D5D; // type:object size:0x2F +lbl_805D0D5D = .data:0x805D0D5D; // type:object size:0x9 data:string +lbl_805D0D66 = .data:0x805D0D66; // type:object size:0xF data:string +lbl_805D0D75 = .data:0x805D0D75; // type:object size:0x17 data:string lbl_805D0D8C = .data:0x805D0D8C; // type:object size:0xE data:string -lbl_805D0D9A = .data:0x805D0D9A; // type:object size:0x2E +lbl_805D0D9A = .data:0x805D0D9A; // type:object size:0xC data:string +lbl_805D0DA6 = .data:0x805D0DA6; // type:object size:0x6 data:string +lbl_805D0DAC = .data:0x805D0DAC; // type:object size:0xF data:string +lbl_805D0DBB = .data:0x805D0DBB; // type:object size:0xD data:string lbl_805D0DC8 = .data:0x805D0DC8; // type:object size:0x1B data:string lbl_805D0DE3 = .data:0x805D0DE3; // type:object size:0x17 data:string __vt__32JointControlDelegator<8Tamakoro> = .data:0x805D0DFC; // type:object size:0x14 scope:global align:4 diff --git a/include/Game/Ride/Tamakoro.hpp b/include/Game/Ride/Tamakoro.hpp index 18f8c205a..a0ca01447 100644 --- a/include/Game/Ride/Tamakoro.hpp +++ b/include/Game/Ride/Tamakoro.hpp @@ -1,5 +1,6 @@ #pragma once +#include "Game/LiveActor/HitSensor.hpp" #include "Game/LiveActor/LiveActor.hpp" #include @@ -60,6 +61,7 @@ class Tamakoro : public LiveActor { void exeBindEnd(); void addVelocityOperate(); f32 updateRideRail(); + void updateVelocityNormal(f32); void updateMoment(); void updateAirTime(); void updateMarioPose(f32); @@ -76,25 +78,48 @@ class Tamakoro : public LiveActor { bool isNeedTutorial() const NO_INLINE; void startRotateLevelSound(); - inline void setTutorial() { mHasTutorial = true; } + inline void setTutorial() { + mHasTutorial = true; + } + + inline bool isBindedSphereDash(HitSensor* pSender, HitSensor* pReceiver) const { + if (pReceiver->isType(ATYPE_SPHERE_DASH)) { + return pReceiver->receiveMessage(ACTMES_SPHERE_PLAYER_BINDED, pSender); + } + return false; + } + + inline bool isBindedJumpHole(HitSensor* pSender, HitSensor* pReceiver) const { + if (pReceiver->isType(ATYPE_JUMP_HOLE)) { + return pReceiver->receiveMessage(ACTMES_SPHERE_PLAYER_BINDED, pSender); + } + return false; + } + + inline bool isBindedBallRail(HitSensor* pSender, HitSensor* pReceiver) const { + if (pReceiver->isType(ATYPE_BALL_RAIL)) { + return pReceiver->receiveMessage(ACTMES_SPHERE_PLAYER_BINDED, pSender); + } + return false; + } private: /* 0x08C */ SphereAccelSensorController* mAccelSensorCtrl; /* 0x090 */ TamakoroTutorial* mTutorial; /* 0x094 */ JointController* mJointCtrl; - /* 0x098 */ TQuat4f mBaseQuat; - /* 0x0A8 */ TQuat4f mRotateQuat; + /* 0x098 */ TQuat4f mBallRotateQuat; + /* 0x0A8 */ TQuat4f mMarioRotateQuat; /* 0x0B8 */ TVec3f mRingUp; - /* 0x0C4 */ u8 _C4[0xC]; + /* 0x0C4 */ TVec3f _C4; // unused /* 0x0D0 */ TVec3f mKickVel; /* 0x0DC */ TVec3f mMarioBindRequestPos; - /* 0x0E8 */ TVec3f mMarioRotateUp; + /* 0x0E8 */ TVec3f mMarioUp; /* 0x0F4 */ TVec3f mMarioPos; /* 0x100 */ TVec3f mMoment; - /* 0x10C */ TVec3f mMarioRotateFront; + /* 0x10C */ TVec3f mMarioFront; /* 0x118 */ TVec3f mDirectionToMario; - /* 0x124 */ TVec3f mMoveVec; - /* 0x130 */ f32 mMoveSpeed; + /* 0x124 */ TVec3f mAccelDir; + /* 0x130 */ f32 mAccelRate; /* 0x134 */ f32 mMarioRotateYAngle; /* 0x138 */ f32 mMarioOffset; /* 0x13C */ f32 mMarioOffsetVelocity; diff --git a/src/Game/Ride/SpherePadController.cpp b/src/Game/Ride/SpherePadController.cpp index 280ddb991..ed4846a74 100644 --- a/src/Game/Ride/SpherePadController.cpp +++ b/src/Game/Ride/SpherePadController.cpp @@ -7,10 +7,11 @@ #include #include -SpherePadController::SpherePadController() : SphereController() {} +SpherePadController::SpherePadController() : SphereController() { +} -f32 SpherePadController::calcMoveVector(TVec3f* v1, const TVec3f& v2) { - return calcDirSphereMove(v1, v2, 0); +f32 SpherePadController::calcMoveVector(TVec3f* pMoveDir, const TVec3f& rGravity) { + return calcDirSphereMove(pMoveDir, rGravity, 0); } f32 SpherePadController::calcJumpPower() const { @@ -20,14 +21,15 @@ f32 SpherePadController::calcJumpPower() const { return 0.0f; } -void SpherePadController::update(const TVec3f&) {} +void SpherePadController::update(const TVec3f&) { +} void SpherePadController::clacXY(f32* x, f32* y) { *x = MR::getSubPadStickX(WPAD_CHAN0); *y = MR::getSubPadStickY(WPAD_CHAN0); } -f32 SpherePadController::calcDirSphereMove(TVec3f* v1, const TVec3f& v2, u32 u1) { +f32 SpherePadController::calcDirSphereMove(TVec3f* pMoveDir, const TVec3f& rBaseVec, u32 isFrontVec) { f32 x = 0.0f; f32 y = 0.0f; clacXY(&x, &y); @@ -50,29 +52,29 @@ f32 SpherePadController::calcDirSphereMove(TVec3f* v1, const TVec3f& v2, u32 u1) MR::normalizeOrZero(&dirY); MR::normalizeOrZero(&dirZ); - if ((u1 != 0 && dirZ.dot(v2) < 0.0f) || (u1 == 0 && dirY.dot(-v2) < 0.0f)) { + if ((isFrontVec != 0 && dirZ.dot(rBaseVec) < 0.0f) || (isFrontVec == 0 && dirY.dot(-rBaseVec) < 0.0f)) { dirX = -dirX; dirY = -dirY; dirZ = -dirZ; } TRot3f rotMtx; - if (u1 != 0) { - rotMtx.setRotate(dirZ, v2); + if (isFrontVec != 0) { + rotMtx.setRotate(dirZ, rBaseVec); rotMtx.mult33(dirX); rotMtx.mult33(dirY); - v1->set(-dirX * x - dirY * y); + pMoveDir->set(-dirX * x - dirY * y); } else { - rotMtx.setRotate(dirY, -v2); + rotMtx.setRotate(dirY, -rBaseVec); rotMtx.mult33(dirX); rotMtx.mult33(dirZ); - v1->set(dirX * x - dirZ * y); + pMoveDir->set(dirX * x - dirZ * y); } - MR::separateScalarAndDirection(&mag, v1, *v1); + MR::separateScalarAndDirection(&mag, pMoveDir, *pMoveDir); } else { - v1->z = 0.0f; - v1->y = 0.0f; - v1->x = 0.0f; + pMoveDir->z = 0.0f; + pMoveDir->y = 0.0f; + pMoveDir->x = 0.0f; } if (mag > 1.0f) { diff --git a/src/Game/Ride/Tamakoro.cpp b/src/Game/Ride/Tamakoro.cpp index be916a4d8..2e1e6c627 100644 --- a/src/Game/Ride/Tamakoro.cpp +++ b/src/Game/Ride/Tamakoro.cpp @@ -1,30 +1,77 @@ #include "Game/Ride/Tamakoro.hpp" #include "Game/GameAudio/AudTamakoroBgmCtrl.hpp" #include "Game/LiveActor/HitSensor.hpp" -#include "Game/LiveActor/Nerve.hpp" #include "Game/Ride/SphereAccelSensorController.hpp" #include "Game/Ride/TamakoroTutorial.hpp" #include "Game/Scene/SceneFunction.hpp" -#include "Game/Util/ActorMovementUtil.hpp" -#include "Game/Util/ActorSensorUtil.hpp" -#include "Game/Util/ActorShadowUtil.hpp" -#include "Game/Util/ActorSwitchUtil.hpp" -#include "Game/Util/CameraUtil.hpp" -#include "Game/Util/EffectUtil.hpp" -#include "Game/Util/EventUtil.hpp" #include "Game/Util/JointController.hpp" #include "Game/Util/LiveActorUtil.hpp" -#include "Game/Util/MathUtil.hpp" -#include "Game/Util/MtxUtil.hpp" -#include "Game/Util/ObjUtil.hpp" -#include "Game/Util/PlayerUtil.hpp" -#include "Game/Util/SceneUtil.hpp" -#include "Game/Util/SoundUtil.hpp" -#include "JSystem/JGeometry/TVec.hpp" -#include "JSystem/JMath/JMath.hpp" -#include "math_types.hpp" -#include "revolution/mtx.h" -#include "revolution/wpad.h" +#include +#include +#include + +namespace { + static const f32 mBaseRadius = 150.0f; + static const f32 sBindableUpperDegree = 60.0f; + static const s32 sBindStartTime = 40; + static const f32 sBindStartJumpHeight = 150.0f; + static const f32 sBindStartUpAdjustRate = 0.1f; + static const f32 sBindStartFrontAdjustRate = 0.1f; + static const s32 sBindStartLandTime = 14; + static const f32 sLandStartPositionDegree = 35.0f; + static const f32 sLandStartVelocityDegree = 40.0f; + static const f32 sGravityAccel = 2.0f; + static const f32 sGroundFric = 0.99f; + static const f32 sIdleBckRate = 1.0f; + static const f32 sSoftWalkSpeed = 0.25f; + static const f32 sSoftWalkBckRate = 1.0f; + static const f32 sWalkSpeed = 6.0f; + static const f32 sWalkBckRate = 2.0f; + static const f32 sRunSpeed = 18.0f; + static const f32 sRunBckRate = 3.0f; + static const f32 sRunMaxBckRate = 4.0f; + static const s32 sFallStartTime = 5; + static const f32 sFallOffsetSpeed = 3.0f; + static const f32 sJumpPowerV = 40.0f; + static const f32 sJumpPowerH = 7.0f; + static const f32 sJumpOffsetSpeed = 4.0f; + static const f32 sMarioJumpOffsetMax = 150.0f; + static const f32 sMarioOffsetGravityAccel = 1.0f; + static const f32 sMarioOffsetFric = 0.99f; + static const f32 sNeedLandPower = 20.0f; + static const s32 sLandTime = 2; + static const f32 sLandFric = 0.88f; + static const f32 sNeedBumpWallPower = 10.0f; + static const f32 sCollisionStrongPower = 60.0f; + static const f32 sCollisionMiddlePower = 25.0f; + static const f32 sCollisionWeakPower = 5.0f; + // static const f32 sStampReactionH = + static const f32 sStampReactionV = 30.0f; + static const f32 sStampReactionInvalidSpeed = 15.0f; + static const f32 sExplosionReactionH = 20.0f; + static const f32 sExplosionReactionV = 40.0f; + static const f32 sRaidRailFastSpeed = 30.0f; + static const f32 sRollBckRate = 1.5f; + // static const f32 sRollMaxBckRate = ; + static const s32 sDashRailTime = 40; + static const f32 sDashRailFric = 0.99f; + static const f32 sDashBallRollSpeed = 60.0f; + static const f32 sEndBindFrontPower = 5.0f; + static const f32 sEndBindJumpPower = 35.0f; + static const s32 sForceBindEndTime = 90; + static const f32 sMarioUpAdjustRate = 0.1f; + static const f32 sMarioFrontAdjustRate = 0.25f; + // static const f32 sStandDirMaxAccelDegree = ; + static const f32 sStandDirInterRate = 0.02f; + // static const ___ sMarioAccelDir = ; // ???? + static const f32 sMarioUpperYAccel = 5.0f; + static const f32 sMarioUpperYFric = 0.9f; + static const f32 sRingMaxDegree = 45.0f; + static const f32 sRingMaxAngleSpeed = 4.0f; + static const f32 sTutorialAccel = 0.5f; + static const f32 sTutorialFric = 0.95f; + static const s32 sBgmStateChangeFrames = 30; +} // namespace namespace NrvTamakoro { NEW_NERVE(TamakoroNrvStandByTutorial, Tamakoro, StandByTutorial); @@ -50,9 +97,9 @@ namespace NrvTamakoro { } // namespace NrvTamakoro Tamakoro::Tamakoro(const char* pName) - : LiveActor(pName), mAccelSensorCtrl(nullptr), mTutorial(nullptr), mJointCtrl(nullptr), mBaseQuat(0, 0, 0, 1), mRotateQuat(0, 0, 0, 1), - mRingUp(0, 1, 0), mKickVel(0, 0, 0), mMarioBindRequestPos(0, 0, 0), mMarioRotateUp(0, 1, 0), mMarioPos(0, 0, 0), mMoment(0, 0, 0), - mMarioRotateFront(0, 0, 1), mDirectionToMario(0, 0, 0), mMoveVec(0, 0, 0), mAirTime(0), mMoveSpeed(0.0f), mMarioRotateYAngle(0.0f), + : LiveActor(pName), mAccelSensorCtrl(nullptr), mTutorial(nullptr), mJointCtrl(nullptr), mBallRotateQuat(0, 0, 0, 1), mMarioRotateQuat(0, 0, 0, 1), + mRingUp(0, 1, 0), mKickVel(0, 0, 0), mMarioBindRequestPos(0, 0, 0), mMarioUp(0, 1, 0), mMarioPos(0, 0, 0), mMoment(0, 0, 0), + mMarioFront(0, 0, 1), mDirectionToMario(0, 0, 0), mAccelDir(0, 0, 0), mAirTime(0), mAccelRate(0.0f), mMarioRotateYAngle(0.0f), mMarioOffset(0.0f), mMarioOffsetVelocity(0.0f), mBgmCtrl(nullptr), mControlDisabled(false), mHasTutorial(false) { mAccelSensorCtrl = new SphereAccelSensorController(); mBgmCtrl = new AudTamakoroBgmCtrl(); @@ -60,22 +107,22 @@ Tamakoro::Tamakoro(const char* pName) void Tamakoro::init(const JMapInfoIter& rIter) { MR::initDefaultPos(this, rIter); - initModelManagerWithAnm("Tamakoro", 0, false); + initModelManagerWithAnm("Tamakoro", nullptr, false); MR::connectToScene(this, MR::MovementType_Ride, MR::CalcAnimType_Ride, MR::DrawBufferType_IndirectMapObjStrongLight, -1); - MR::makeQuatFromRotate(&mBaseQuat, this); - MR::initShadowVolumeSphere(this, 150.0f); + MR::makeQuatFromRotate(&mBallRotateQuat, this); + MR::initShadowVolumeSphere(this, mBaseRadius); initEffectKeeper(0, 0, false); initSensor(); initSound(4, false); initJointControl(); MR::onCalcGravity(this); - initBinder(150.0f, 0.0f, 16); + initBinder(mBaseRadius, 0.0f, 16); initNerve(&NrvTamakoro::TamakoroNrvStandByBind::sInstance); MR::declarePowerStar(this); bool hasPowerStar = MR::hasPowerStarInCurrentStageWithDeclarer(mName, -1); MR::startBva(this, "Tamakoro"); - MR::setBvaFrameAndStop(this, (s32)hasPowerStar); + MR::setBvaFrameAndStop(this, static_cast< s32 >(hasPowerStar)); MR::useStageSwitchWriteA(this, rIter); if (mHasTutorial) { @@ -89,9 +136,9 @@ void Tamakoro::init(const JMapInfoIter& rIter) { void Tamakoro::initSensor() { initHitSensor(3); - MR::addHitSensor(this, "Body", ATYPE_SPHERE_PLAYER, 8, 150.0f, TVec3f(0.0f, 0.0f, 0.0f)); - MR::addHitSensor(this, "Hit", ATYPE_SPHERE_PLAYER_HIT, 8, 150.0f, TVec3f(0.0f, 0.0f, 0.0f)); - MR::addHitSensor(this, "Bind", ATYPE_SPHERE_PLAYER_BIND, 8, 165.0f, TVec3f(0.0f, 0.0f, 0.0f)); + MR::addHitSensor(this, "Body", ATYPE_SPHERE_PLAYER, 8, mBaseRadius, TVec3f(0.0f, 0.0f, 0.0f)); + MR::addHitSensor(this, "Hit", ATYPE_SPHERE_PLAYER_HIT, 8, mBaseRadius, TVec3f(0.0f, 0.0f, 0.0f)); + MR::addHitSensor(this, "Bind", ATYPE_SPHERE_PLAYER_BIND, 8, mBaseRadius + 15.0f, TVec3f(0.0f, 0.0f, 0.0f)); } void Tamakoro::initJointControl() { @@ -102,10 +149,10 @@ bool Tamakoro::ringMtxCallBack(TPos3f* pMtx, const JointControllerInfo& pJointCt TVec3f trans; pMtx->getTransInline(trans); - if (MR::isNearZero(mMoveVec) || MR::isSameDirection(mMoveVec, mRingUp, 0.01f)) { + if (MR::isNearZero(mAccelDir) || MR::isSameDirection(mAccelDir, mRingUp, 0.01f)) { MR::makeMtxUpNoSupport(pMtx, mRingUp); } else { - MR::makeMtxUpFront(pMtx, mRingUp, mMoveVec); + MR::makeMtxUpFront(pMtx, mRingUp, mAccelDir); } pMtx->setTrans(trans); @@ -114,52 +161,52 @@ bool Tamakoro::ringMtxCallBack(TPos3f* pMtx, const JointControllerInfo& pJointCt void Tamakoro::control() { updateMoment(); - MR::rotateQuatMoment(&mBaseQuat, mMoment); + MR::rotateQuatMoment(&mBallRotateQuat, mMoment); updateAirTime(); updateRingUpVec(); - f32 mag = PSVECMag(&mVelocity); + f32 speed = mVelocity.length(); if (isNerve(&NrvTamakoro::TamakoroNrvJumpHole::sInstance) || isNerve(&NrvTamakoro::TamakoroNrvJumpHoleSetUp::sInstance)) { - mag = 0.0f; + speed = 0.0f; } - mBgmCtrl->control(mag, mControlDisabled, 30); + mBgmCtrl->control(speed, mControlDisabled, sBgmStateChangeFrames); mControlDisabled = false; } void Tamakoro::calcAndSetBaseMtx() { - MR::setBaseTRMtx(this, mBaseQuat); + MR::setBaseTRMtx(this, mBallRotateQuat); mJointCtrl->registerCallBack(); } void Tamakoro::updateBindActorMatrix() { if (isUseMarioOffset()) { - JMAVECScaleAdd(&mDirectionToMario, &mPosition, &mMarioPos, 150.0f); - if (mMarioOffset > 0) { + JMAVECScaleAdd(&mDirectionToMario, &mPosition, &mMarioPos, mBaseRadius); + if (mMarioOffset > 0.0f) { JMAVECScaleAdd(&mGravity, &mMarioPos, &mMarioPos, -mMarioOffset); } } // quaternion rotation TPos3f mtx; - mtx.setQT(mRotateQuat, mMarioPos); + mtx.setQT(mMarioRotateQuat, mMarioPos); MR::setPlayerBaseMtx(mtx); } void Tamakoro::updateRingUpVec() { TVec3f up = -mGravity; - if (!MR::isNearZero(mMoveVec)) { + if (!MR::isNearZero(mAccelDir)) { TVec3f v1; TVec3f up2 = -mGravity; - JMAVECScaleAdd(&mMoveVec, &up2, &v1, mMoveSpeed); + JMAVECScaleAdd(&mAccelDir, &up2, &v1, mAccelRate); MR::normalizeOrZero(&v1); - MR::turnVecToVecDegree(&up, up, v1, 45.0f, TVec3f(0, 1, 0)); + MR::turnVecToVecDegree(&up, up, v1, sRingMaxDegree, TVec3f(0, 1, 0)); } - MR::turnVecToVecDegree(&mRingUp, mRingUp, up, 4.0f, TVec3f(0, 1, 0)); + MR::turnVecToVecDegree(&mRingUp, mRingUp, up, sRingMaxAngleSpeed, TVec3f(0, 1, 0)); } void Tamakoro::attackSensor(HitSensor* pSender, HitSensor* pReceiver) { - if (pSender->isType(0x0A) && MR::tryGetItem(pSender, pReceiver)) { + if (pSender->isType(ATYPE_SPHERE_PLAYER) && MR::tryGetItem(pSender, pReceiver)) { return; } @@ -168,13 +215,13 @@ void Tamakoro::attackSensor(HitSensor* pSender, HitSensor* pReceiver) { return; } - if (isEnableEnemyAttack() && MR::isSensorEnemy(pReceiver) && pSender->isType(0x0A)) { + if (isEnableEnemyAttack() && MR::isSensorEnemy(pReceiver) && pSender->isType(ATYPE_SPHERE_PLAYER)) { if (MR::sendMsgPlayerTrample(pReceiver, pSender)) { - f32 dot = mVelocity.dot(mGravity); - if (dot < 15.0f) { - dot = -30.0f - dot; - mVelocity.add(mGravity.multiplyOperatorInline(dot)); - MR::tryRumblePadWeak(this, 0); + f32 downVel = mVelocity.dot(mGravity); + if (downVel < sStampReactionInvalidSpeed) { + downVel = -sStampReactionV - downVel; + mVelocity.add(mGravity.multiplyOperatorInline(downVel)); + MR::tryRumblePadWeak(this, WPAD_CHAN0); MR::shakeCameraNormalWeak(); } return; @@ -182,68 +229,34 @@ void Tamakoro::attackSensor(HitSensor* pSender, HitSensor* pReceiver) { } if (isEnableBallBind() && pSender == getSensor("Body")) { - // this is gross, but it matches... even though the commented - // logic below is what it's really doing, not entirely sure - // why this matches... - - bool set; - if (pReceiver->isType(0x7A)) { - set = pReceiver->receiveMessage(0xAD, pSender); - } else { - set = false; - } - if (set) { - setNerve(&NrvTamakoro::TamakoroNrvDashRail::sInstance); - return; - } - - if (pReceiver->isType(0x79)) { - set = pReceiver->receiveMessage(0xAD, pSender); - } else { - set = false; - } - if (set) { - setNerve(&NrvTamakoro::TamakoroNrvJumpHole::sInstance); - return; - } - - if (pReceiver->isType(0x7B)) { - set = pReceiver->receiveMessage(0xAD, pSender); - } else { - set = false; - } - if (set) { - setNerve(&NrvTamakoro::TamakoroNrvRideRail::sInstance); - return; - } - - /* - if (pSender->isType(0x7A) && pReceiver->receiveMessage(0xAD, pSender)) { + if (isBindedSphereDash(pSender, pReceiver)) { setNerve(&NrvTamakoro::TamakoroNrvDashRail::sInstance); return; } - if (pSender->isType(0x79) && pReceiver->receiveMessage(0xAD, pSender)) { + if (isBindedJumpHole(pSender, pReceiver)) { setNerve(&NrvTamakoro::TamakoroNrvJumpHole::sInstance); return; } - if (pSender->isType(0x7B) && pReceiver->receiveMessage(0xAD, pSender)) { + if (isBindedBallRail(pSender, pReceiver)) { setNerve(&NrvTamakoro::TamakoroNrvRideRail::sInstance); return; } - */ } } bool Tamakoro::receiveMsgPlayerAttack(u32 msg, HitSensor* pSender, HitSensor* pReceiver) { - return MR::isMsgStarPieceReflect(msg); + if (MR::isMsgStarPieceReflect(msg)) { + return true; + } + return false; } bool Tamakoro::receiveMsgEnemyAttack(u32 msg, HitSensor* pSender, HitSensor* pReceiver) { if (MR::isMsgExplosionAttack(msg) && isEnableEnemyAttack()) { - MR::tryRumblePadStrong(this, 0); - MR::setVelocitySeparateHV(this, pSender, pReceiver, 20.0, 40.0); + MR::tryRumblePadStrong(this, WPAD_CHAN0); + MR::setVelocitySeparateHV(this, pSender, pReceiver, sExplosionReactionH, sExplosionReactionV); MR::startSoundPlayer("SE_PV_UPSET", -1); return true; } @@ -260,37 +273,37 @@ bool Tamakoro::receiveOtherMsg(u32 msg, HitSensor* pSender, HitSensor* pReceiver return true; } - if (msg == 0x94) { + if (msg == ACTMES_RUSH_FORCE_CANCEL) { setNerve(&NrvTamakoro::TamakoroNrvStandByBind::sInstance); return true; } - if (msg == 0xAE && isNerve(&NrvTamakoro::TamakoroNrvJumpHole::sInstance)) { + if (msg == ACTMES_SET_UP_JUMP_HOLE && isNerve(&NrvTamakoro::TamakoroNrvJumpHole::sInstance)) { setNerve(&NrvTamakoro::TamakoroNrvJumpHoleSetUp::sInstance); return true; } - if (msg == 0xAF && isNerve(&NrvTamakoro::TamakoroNrvJumpHoleSetUp::sInstance)) { + if (msg == ACTMES_SHOOT_JUMP_HOLE && isNerve(&NrvTamakoro::TamakoroNrvJumpHoleSetUp::sInstance)) { setNerve(&NrvTamakoro::TamakoroNrvJumpHoleLaunch::sInstance); return true; } - if (msg == 0xB0 && isNerve(&NrvTamakoro::TamakoroNrvJumpHoleLaunch::sInstance)) { + if (msg == ACTMES_END_JUMP_HOLE && isNerve(&NrvTamakoro::TamakoroNrvJumpHoleLaunch::sInstance)) { setNerve(&NrvTamakoro::TamakoroNrvFall::sInstance); return true; } - if (msg == 0xB1 && isNerve(&NrvTamakoro::TamakoroNrvDashRail::sInstance)) { + if (msg == ACTMES_END_RAIL_DASH && isNerve(&NrvTamakoro::TamakoroNrvDashRail::sInstance)) { setNerve(&NrvTamakoro::TamakoroNrvDashRailEnd::sInstance); return true; } - if (msg == 0xB2 && isRideRail()) { + if (msg == ACTMES_END_BALL_RAIL && isRideRail()) { setNerve(&NrvTamakoro::TamakoroNrvWait::sInstance); return true; } - if (msg == 0xB3 && requestEndBind()) { + if (msg == ACTMES_END_BALL_BIND && requestEndBind()) { return true; } @@ -305,39 +318,38 @@ bool Tamakoro::requestBind(HitSensor* pSensor) { // check if sensor within vertical angle range TVec3f vThisToSensor = MR::getSensorPos(pSensor) - mPosition; MR::normalizeOrZero(&vThisToSensor); - f32 cosVerticalAngle = vThisToSensor.dot(-mGravity); - if (cosVerticalAngle < MR::cosDegree(60.0f)) { + f32 cosPositionDegree = vThisToSensor.dot(-mGravity); + if (cosPositionDegree < MR::cosDegree(sBindableUpperDegree)) { return false; } MR::invalidateClipping(this); - MR::makeQuatRotateDegree(&mRotateQuat, *MR::getPlayerRotate()); + MR::makeQuatRotateDegree(&mMarioRotateQuat, *MR::getPlayerRotate()); mMarioPos.set(*MR::getPlayerPos()); - mRotateQuat.getZDir(mMarioRotateFront); - TVec3f* grav = &mGravity; - JMAVECScaleAdd(grav, &mMarioRotateFront, &mMarioRotateFront, - -grav->dot(mMarioRotateFront)); // mMarioRotateFront.rejection(mMarioRotateFront, mGravity); - if (MR::normalizeOrZero(&mMarioRotateFront)) { - MR::makeAxisVerticalZX(&mMarioRotateFront, mGravity); + mMarioRotateQuat.getZDir(mMarioFront); + mMarioFront.rejection(mGravity); + if (MR::normalizeOrZero(&mMarioFront)) { + MR::makeAxisVerticalZX(&mMarioFront, mGravity); } mMarioBindRequestPos.set(mMarioPos); mMarioRotateYAngle = 0.0f; - mMoveSpeed = 0.0f; + mAccelRate = 0.0f; mMarioOffset = 0.0f; mMarioOffsetVelocity = 0.0f; - mMoveVec.zero(); + mAccelDir.zero(); MR::zeroVelocity(this); MR::invalidateHitSensor(this, "Bind"); TVec3f vel(*MR::getPlayerVelocity()); MR::normalizeOrZero(&vel); - f32 cosBetweenVelAndToThis = -vThisToSensor.dot(vel); + f32 cosVelocityDegree = -vThisToSensor.dot(vel); - if (cosBetweenVelAndToThis > MR::cosDegree(40.0f) && cosVerticalAngle > MR::cosDegree(35.0f)) { - // if angle between vel and "to this" < 40 degrees and vertical angle to sensor < 35 degrees + if (cosVelocityDegree > MR::cosDegree(sLandStartVelocityDegree) && cosPositionDegree > MR::cosDegree(sLandStartPositionDegree)) { + // if angle between vel and "to this" < sLandStartVelocityDegree (40.0f) degrees and vertical angle to sensor < sLandStartPositionDegree + // (35.0f) degrees setNerve(&NrvTamakoro::TamakoroNrvBindStartLand::sInstance); } else { setNerve(&NrvTamakoro::TamakoroNrvBindStart::sInstance); @@ -345,16 +357,13 @@ bool Tamakoro::requestBind(HitSensor* pSensor) { TVec3f v3; // vec order shenanigans... not used TVec3f vPlayerToThis; vPlayerToThis = mPosition - mMarioPos; - - TVec3f* grav = &mGravity; - JMAVECScaleAdd(grav, &vPlayerToThis, &vPlayerToThis, -grav->dot(vPlayerToThis)); // vPlayerToThis.rejection(vPlayerToThis, mGravity); + vPlayerToThis.rejection(mGravity); if (!MR::normalizeOrZero(&vPlayerToThis)) { - f32 dot = vPlayerToThis.dot(mMarioRotateFront); - if (dot > 0.0f) { - mMarioRotateFront.set(vPlayerToThis); + if (vPlayerToThis.dot(mMarioFront) > 0.0f) { + mMarioFront.set(vPlayerToThis); } else { - mMarioRotateFront.set(-vPlayerToThis); + mMarioFront.set(-vPlayerToThis); } } } @@ -367,9 +376,9 @@ bool Tamakoro::requestBind(HitSensor* pSensor) { bool Tamakoro::requestEndBind() { if (!isNerve(&NrvTamakoro::TamakoroNrvBindEnd::sInstance) && !isNerve(&NrvTamakoro::TamakoroNrvStandByBind::sInstance)) { - MR::startBckPlayer("SwingRopeSpin", (const char*)0); - MR::endBindAndPlayerForceJump(this, - mMarioRotateFront.multiplyOperatorInline(-5.0f).addOperatorInLine(mGravity.multiplyOperatorInline(-35.0f)), 0); + MR::startBckPlayer("SwingRopeSpin", static_cast< const char* >(nullptr)); + MR::endBindAndPlayerForceJump( + this, mMarioFront.multiplyOperatorInline(-sEndBindFrontPower).addOperatorInLine(mGravity.multiplyOperatorInline(-sEndBindJumpPower)), 0); MR::hideModel(this); MR::invalidateHitSensors(this); MR::invalidateClipping(this); @@ -405,7 +414,7 @@ bool Tamakoro::requestTutorialEnd() { } bool Tamakoro::tryFall() { - if (mAirTime > 5) { + if (mAirTime > sFallStartTime) { setNerve(&NrvTamakoro::TamakoroNrvFall::sInstance); return true; } @@ -421,10 +430,10 @@ bool Tamakoro::tryJump() { } bool Tamakoro::tryBumpWall() { - if (MR::calcHitPowerToWall(this) > 10.0f) { + if (MR::calcHitPowerToWall(this) > sNeedBumpWallPower) { f32 rebound = -0.6f; if (isEnebleHitCollisionMessage()) { - if (MR::sendMsgToWallSensor(0x39, getSensor("Body"))) { + if (MR::sendMsgToWallSensor(ACTMES_BALL_DASH_WALL, getSensor("Body"))) { rebound = 0.3f; } } @@ -437,24 +446,24 @@ bool Tamakoro::tryBumpWall() { } bool Tamakoro::tryLand() { - f32 f1 = MR::calcHitPowerToGround(this); + f32 power = MR::calcHitPowerToGround(this); - if (MR::calcHitPowerToGround(this) > 20.0f) { + if (MR::calcHitPowerToGround(this) > sNeedLandPower) { f32 rebound = 0.0f; if (isEnebleHitCollisionMessage()) { - if (MR::sendMsgToWallSensor(0x3A, getSensor("Body"))) { + if (MR::sendMsgToWallSensor(ACTMES_BALL_DASH_GROUND, getSensor("Body"))) { rebound = 0.3f; } } - mMarioOffsetVelocity = -f1; - mMarioOffset -= f1; + mMarioOffsetVelocity = -power; + mMarioOffset -= power; MR::reboundVelocityFromCollision(this, rebound, 0.0f, 1.0f); setNerve(&NrvTamakoro::TamakoroNrvLand::sInstance); return true; } - if (MR::isGreaterStep(this, 2) && MR::isBindedGround(this)) { - mMarioOffsetVelocity = -f1; + if (MR::isGreaterStep(this, sLandTime) && MR::isBindedGround(this)) { + mMarioOffsetVelocity = -power; setNerve(&NrvTamakoro::TamakoroNrvWait::sInstance); return true; } @@ -474,84 +483,66 @@ void Tamakoro::reactionCollision() { hitPower = groundHitPower; } - if (wallHitPower > 5.0f) { + if (wallHitPower > sCollisionWeakPower) { MR::emitEffectHit(this, *MR::getWallHitPos(this), *MR::getWallNormal(this), "WallHit"); } - if (groundHitPower > 25.0f) { + if (groundHitPower > sCollisionMiddlePower) { MR::emitEffectHit(this, *MR::getGroundHitPos(this), *MR::getGroundNormal(this), "Land"); } - if (wallHitPower > 5.0f) { + if (wallHitPower > sCollisionWeakPower) { MR::startSound(this, "SE_SM_IRONSPH_HIT", -1, -1); MR::startSoundPlayer("SE_PV_GUARD", -1); } - if (hitPower > 60.0f) { + if (hitPower > sCollisionStrongPower) { MR::tryRumblePadStrong(this, WPAD_CHAN0); MR::shakeCameraStrong(); - } else if (hitPower > 25.0f) { + } else if (hitPower > sCollisionMiddlePower) { MR::tryRumblePadMiddle(this, WPAD_CHAN0); MR::shakeCameraNormalWeak(); - } else if (hitPower > 5.0f) { + } else if (hitPower > sCollisionWeakPower) { MR::tryRumblePadWeak(this, WPAD_CHAN0); MR::shakeCameraWeak(); } } -inline void Tamakoro::exeStandByTutorial() { - TVec3f vel(mVelocity); // unused! woo! - MR::reboundVelocityFromCollision(this, 0.0f, 0.0f, 1.0f); - MR::addVelocityToGravity(this, 2.0f); - f32 attenuation; - if (MR::isBindedGround(this)) { - attenuation = 0.95f; - } else { - attenuation = 0.995f; - } - MR::attenuateVelocity(this, attenuation); +void Tamakoro::exeStandByTutorial() { + updateVelocityNormal(0.95f); } -inline void Tamakoro::exeStandByBind() { - TVec3f vel(mVelocity); // unused! woo! - MR::reboundVelocityFromCollision(this, 0.0f, 0.0f, 1.0f); - MR::addVelocityToGravity(this, 2.0f); - f32 attenuation; - if (MR::isBindedGround(this)) { - attenuation = 0.95f; - } else { - attenuation = 0.995f; - } - MR::attenuateVelocity(this, attenuation); +void Tamakoro::exeStandByBind() { + updateVelocityNormal(0.95f); } void Tamakoro::exeBindStart() { if (MR::isFirstStep(this)) { - MR::startBckPlayer("SlideStomachRecover", (const char*)0); + MR::startBckPlayer("SlideStomachRecover", static_cast< const char* >(nullptr)); MR::tryRumblePadWeak(this, WPAD_CHAN0); mDirectionToMario.set(-mGravity); - if (MR::normalizeOrZero(&mMarioRotateFront)) { - MR::makeAxisVerticalZX(&mMarioRotateFront, mGravity); + if (MR::normalizeOrZero(&mMarioFront)) { + MR::makeAxisVerticalZX(&mMarioFront, mGravity); } MR::emitEffectHit(this, mMarioPos, mMarioPos - mPosition, "TamakoroLand"); } // smoothly transition arc from bind request position // to top of the ball using the nerve rate as time - f32 time = MR::calcNerveRate(this, 40); + f32 time = MR::calcNerveRate(this, sBindStartTime); TVec3f expectMario; - JMAVECScaleAdd(&mDirectionToMario, &mPosition, &expectMario, 150.0f); + JMAVECScaleAdd(&mDirectionToMario, &mPosition, &expectMario, mBaseRadius); TVec3f horizontalVec; MR::vecBlend(mMarioBindRequestPos, expectMario, &horizontalVec, time); time = (time * 2.0f) - 1.0f; TVec3f upVec; - upVec.set(mGravity.multiplyOperatorInline(-(time * time * -150.0f + 150.0f))); + upVec.set(mGravity.multiplyOperatorInline(-(time * time * -sBindStartJumpHeight + mBaseRadius))); - MR::blendQuatUpFront(&mRotateQuat, -mGravity, mMarioRotateFront, 0.1f, 0.1f); + MR::blendQuatUpFront(&mMarioRotateQuat, -mGravity, mMarioFront, sBindStartUpAdjustRate, sBindStartFrontAdjustRate); mMarioPos.set(horizontalVec.addOperatorInLine(upVec)); - if (MR::isGreaterStep(this, 40)) { + if (MR::isGreaterStep(this, sBindStartTime)) { setNerve(&NrvTamakoro::TamakoroNrvBindStartLand::sInstance); } } @@ -574,11 +565,11 @@ void Tamakoro::exeBindStartLand() { if (MR::normalizeOrZero(&mDirectionToMario)) { mDirectionToMario.set(-mGravity); } - JMAVECScaleAdd(&mDirectionToMario, &mPosition, &mMarioPos, 150.0f); + JMAVECScaleAdd(&mDirectionToMario, &mPosition, &mMarioPos, mBaseRadius); - mMarioRotateUp = (mDirectionToMario - mGravity).multiplyOperatorInline(0.5f); - if (MR::normalizeOrZero(&mMarioRotateUp)) { - mMarioRotateUp.set(-mGravity); + mMarioUp = (mDirectionToMario - mGravity).multiplyOperatorInline(0.5f); + if (MR::normalizeOrZero(&mMarioUp)) { + mMarioUp.set(-mGravity); } MR::emitEffectHit(this, mMarioPos, mMarioPos - mPosition, "TamakoroLand"); @@ -590,9 +581,9 @@ void Tamakoro::exeBindStartLand() { } } - MR::blendQuatUpFront(&mRotateQuat, mMarioRotateUp, mMarioRotateFront, 0.1f, 0.1f); + MR::blendQuatUpFront(&mMarioRotateQuat, mMarioUp, mMarioFront, sBindStartUpAdjustRate, sBindStartFrontAdjustRate); - if (MR::isGreaterStep(this, 14)) { + if (MR::isGreaterStep(this, sBindStartLandTime)) { if (isNeedTutorial()) { mTutorial->requestStart(); setNerve(&NrvTamakoro::TamakoroNrvTutorial::sInstance); @@ -607,22 +598,22 @@ void Tamakoro::exeTutorial() { if (MR::isFirstStep(this)) { MR::startBckPlayerJ("タマコロ移動"); MR::zeroVelocity(this); - mMoveVec.zero(); - mMoveSpeed = 0.0f; + mAccelDir.zero(); + mAccelRate = 0.0f; mMoment.zero(); mKickVel.zero(); } - mMoveSpeed = mAccelSensorCtrl->calcMoveVector(&mMoveVec, mGravity); + mAccelRate = mAccelSensorCtrl->calcMoveVector(&mAccelDir, mGravity); - JMAVECScaleAdd(&mMoveVec, &mKickVel, &mKickVel, mMoveSpeed * 0.5f); + JMAVECScaleAdd(&mAccelDir, &mKickVel, &mKickVel, mAccelRate * sTutorialAccel); TVec3f moment; - MR::calcMomentRollBall(&moment, mKickVel, -mGravity, 150.0f); + MR::calcMomentRollBall(&moment, mKickVel, -mGravity, mBaseRadius); MR::vecBlend(mMoment, moment, &mMoment, 0.25f); - mKickVel.mult(0.95f); + mKickVel.mult(sTutorialFric); - updateMoveBckBlend(PSVECMag(&mMoment) * 150.0f); + updateMoveBckBlend(mMoment.length() * mBaseRadius); updateMarioPose(3.0f); updateMarioOffset(); } @@ -633,18 +624,8 @@ void Tamakoro::exeWait() { } reactionCollision(); addVelocityOperate(); - - TVec3f vel(mVelocity); // unused! woo! - MR::reboundVelocityFromCollision(this, 0.0f, 0.0f, 1.0f); - MR::addVelocityToGravity(this, 2.0f); - f32 attenuation; - if (MR::isBindedGround(this)) { - attenuation = 0.99f; - } else { - attenuation = 0.995f; - } - MR::attenuateVelocity(this, attenuation); - updateMoveBckBlend(PSVECMag(&mMoment) * 150.0f); + updateVelocityNormal(sGroundFric); + updateMoveBckBlend(mMoment.length() * mBaseRadius); updateMarioPose(3.0f); updateMarioOffset(); @@ -657,23 +638,14 @@ void Tamakoro::exeFall() { if (MR::isFirstStep(this)) { MR::startBckPlayer("Fall", "BallFall"); } - mMarioOffset += 3.0f; - mMarioOffset = MR::clamp(mMarioOffset, 0.0f, 150.0f); + mMarioOffset += sFallOffsetSpeed; + mMarioOffset = MR::clamp(mMarioOffset, 0.0f, sMarioJumpOffsetMax); reactionCollision(); if (!tryLand()) { addVelocityOperate(); - TVec3f vel(mVelocity); // unused! woo! - MR::reboundVelocityFromCollision(this, 0.0f, 0.0f, 1.0f); - MR::addVelocityToGravity(this, 2.0f); - f32 attenuation; - if (MR::isBindedGround(this)) { - attenuation = 0.99f; - } else { - attenuation = 0.995f; - } - MR::attenuateVelocity(this, attenuation); + updateVelocityNormal(sGroundFric); updateMarioPose(3.0f); } } @@ -683,12 +655,12 @@ void Tamakoro::exeJump() { MR::startBckPlayer("BallJump", "BallJump"); MR::startSoundPlayer("SE_PV_JUMP_M", -1); MR::startSound(this, "SE_SM_BALLOONSPH_JUMP", -1, -1); - MR::addVelocityToGravity(this, (-40.0f - mVelocity.dot(mGravity))); - MR::addVelocityMoveToDirection(this, mMoveVec, mMoveSpeed * 7.0f); + MR::addVelocityToGravity(this, (-sJumpPowerV - mVelocity.dot(mGravity))); + MR::addVelocityMoveToDirection(this, mAccelDir, mAccelRate * sJumpPowerH); } - mMarioOffset += 4.0f; - mMarioOffset = MR::clamp(mMarioOffset, 0.0f, 150.0f); + mMarioOffset += sJumpOffsetSpeed; + mMarioOffset = MR::clamp(mMarioOffset, 0.0f, sMarioJumpOffsetMax); reactionCollision(); @@ -697,22 +669,13 @@ void Tamakoro::exeJump() { } addVelocityOperate(); - TVec3f vel(mVelocity); // unused! woo! - MR::reboundVelocityFromCollision(this, 0.0f, 0.0f, 1.0f); - MR::addVelocityToGravity(this, 2.0f); - f32 attenuation; - if (MR::isBindedGround(this)) { - attenuation = 0.99f; - } else { - attenuation = 0.995f; - } - MR::attenuateVelocity(this, attenuation); + updateVelocityNormal(sGroundFric); updateMarioPose(3.0f); } void Tamakoro::exeBumpWall() { if (MR::isFirstStep(this)) { - MR::startBckPlayer("BallHit", (const char*)0); + MR::startBckPlayer("BallHit", static_cast< const char* >(nullptr)); MR::tryRumblePadMiddle(this, WPAD_CHAN0); MR::shakeCameraNormalWeak(); } @@ -720,18 +683,8 @@ void Tamakoro::exeBumpWall() { reactionCollision(); addVelocityOperate(); - TVec3f vel(mVelocity); // unused! woo! - MR::reboundVelocityFromCollision(this, 0.0f, 0.0f, 1.0f); - MR::addVelocityToGravity(this, 2.0f); - f32 attenuation; - if (MR::isBindedGround(this)) { - attenuation = 0.99f; - } else { - attenuation = 0.995f; - } - MR::attenuateVelocity(this, attenuation); + updateVelocityNormal(sGroundFric); updateMarioPose(3.0f); - updateMarioOffset(); if (!tryJump() && MR::isGreaterStep(this, 15)) { @@ -741,7 +694,7 @@ void Tamakoro::exeBumpWall() { void Tamakoro::exeLand() { if (MR::isFirstStep(this)) { - MR::startBckPlayer("Land", (const char*)0); + MR::startBckPlayer("Land", static_cast< const char* >(nullptr)); MR::tryRumblePadMiddle(this, WPAD_CHAN0); MR::shakeCameraNormalWeak(); MR::startSound(this, "SE_SM_IRONSPH_LAND", -1, -1); @@ -750,18 +703,8 @@ void Tamakoro::exeLand() { reactionCollision(); addVelocityOperate(); - TVec3f vel(mVelocity); // unused! woo! - MR::reboundVelocityFromCollision(this, 0.0f, 0.0f, 1.0f); - MR::addVelocityToGravity(this, 2.0f); - f32 attenuation; - if (MR::isBindedGround(this)) { - attenuation = 0.88f; // ?? - } else { - attenuation = 0.995f; - } - MR::attenuateVelocity(this, attenuation); + updateVelocityNormal(sLandFric); updateMarioPose(3.0f); - updateMarioOffset(); if (!tryJump() && MR::isGreaterStep(this, 15)) { @@ -774,11 +717,11 @@ void Tamakoro::exeJumpHole() { MR::tryRumblePadWeak(this, WPAD_CHAN0); MR::offBind(this); MR::startBckPlayerJ("タマコロしゃがみ"); - mMoveVec.zero(); - mMoveSpeed = 0.0f; + mAccelDir.zero(); + mAccelRate = 0.0f; mMarioOffsetVelocity = 0.0f; } - updateSquatBckBlend(PSVECMag(&mMoment) * 150.0f); + updateSquatBckBlend(mMoment.length() * mBaseRadius); updateMarioPose(3.0f); updateMarioOffset(); } @@ -794,7 +737,7 @@ void Tamakoro::exeJumpHoleSetUp() { void Tamakoro::exeJumpHoleLaunch() { if (MR::isFirstStep(this)) { - MR::startBckPlayer("BallJump", (const char*)0); + MR::startBckPlayer("BallJump", static_cast< const char* >(nullptr)); MR::tryRumblePadStrong(this, WPAD_CHAN0); MR::shakeCameraStrong(); MR::emitEffect(this, "BigJumpBlur"); @@ -802,7 +745,7 @@ void Tamakoro::exeJumpHoleLaunch() { mControlDisabled = true; mMarioOffset += 3.0f; - mMarioOffset = MR::clamp(mMarioOffset, 0.0f, 150.0f); + mMarioOffset = MR::clamp(mMarioOffset, 0.0f, sMarioJumpOffsetMax); updateMarioPose(3.0f); } @@ -815,17 +758,17 @@ void Tamakoro::endJumpHoleLaunch() { void Tamakoro::exeDashRail() { if (MR::isFirstStep(this)) { - MR::startBckPlayer("BallRoll", (const char*)0); + MR::startBckPlayer("BallRoll", static_cast< const char* >(nullptr)); MR::startSoundPlayer("SE_PV_JUMP_JOY", -1); MR::startSound(this, "SE_SM_IRONSPH_RAILDASH", -1, -1); MR::tryRumblePadStrong(this, WPAD_CHAN0); - mMoveVec.zero(); - mMoveSpeed = 0.0f; + mAccelDir.zero(); + mAccelRate = 0.0f; } mControlDisabled = true; updateMarioPose(10.0f); updateMarioOffset(); - MR::setBckRatePlayer(PSVECMag(&mVelocity) / 60.0f); + MR::setBckRatePlayer(mVelocity.length() / sDashBallRollSpeed); } void Tamakoro::exeDashRailEnd() { @@ -833,31 +776,22 @@ void Tamakoro::exeDashRailEnd() { mMarioOffsetVelocity = 0.0f; } - if (MR::isLessStep(this, 40)) { - MR::setBckRatePlayer(PSVECMag(&mVelocity) / 60.0f); + if (MR::isLessStep(this, sDashRailTime)) { + MR::setBckRatePlayer(mVelocity.length() / sDashBallRollSpeed); } - if (MR::isStep(this, 40)) { + if (MR::isStep(this, sDashRailTime)) { MR::startBckPlayer("Fall", "BallFall"); } mMarioOffset += 3.0f; - mMarioOffset = MR::clamp(mMarioOffset, 0.0f, 150.0f); + mMarioOffset = MR::clamp(mMarioOffset, 0.0f, sMarioJumpOffsetMax); if (tryBumpWall() || tryLand()) { return; } - TVec3f vel(mVelocity); // unused! woo! - MR::reboundVelocityFromCollision(this, 0.0f, 0.0f, 1.0f); - MR::addVelocityToGravity(this, 2.0f); - f32 attenuation; - if (MR::isBindedGround(this)) { - attenuation = 0.99f; - } else { - attenuation = 0.995f; - } - MR::attenuateVelocity(this, attenuation); + updateVelocityNormal(sDashRailFric); updateMarioPose(10.0f); } @@ -867,17 +801,17 @@ void Tamakoro::exeRideRail() { MR::tryRumblePadMiddle(this, WPAD_CHAN0); } - f32 mag = updateRideRail(); - updateMoveBckBlend(mag); - if (mag > 30.0f) { + f32 speed = updateRideRail(); + updateMoveBckBlend(speed); + if (speed > sRaidRailFastSpeed) { setNerve(&NrvTamakoro::TamakoroNrvRideRailFastStart::sInstance); } } void Tamakoro::exeRideRailFastStart() { if (MR::isFirstStep(this)) { - MR::startBckPlayer("BallRollStart", (const char*)0); - MR::setBckRatePlayer(1.5); + MR::startBckPlayer("BallRollStart", static_cast< const char* >(nullptr)); + MR::setBckRatePlayer(sRollBckRate); } updateRideRail(); mControlDisabled = true; @@ -888,23 +822,23 @@ void Tamakoro::exeRideRailFastStart() { void Tamakoro::exeRideRailFast() { if (MR::isFirstStep(this)) { - MR::startBckPlayer("BallRoll", (const char*)0); - MR::setBckRatePlayer(1.5); + MR::startBckPlayer("BallRoll", static_cast< const char* >(nullptr)); + MR::setBckRatePlayer(sRollBckRate); } mControlDisabled = true; - f32 mag = updateRideRail(); + f32 speed = updateRideRail(); - MR::setBckRatePlayer(PSVECMag(&mVelocity) / 60.0f); + MR::setBckRatePlayer(mVelocity.length() / sDashBallRollSpeed); - if (mag < 30.0f) { + if (speed < sRaidRailFastSpeed) { setNerve(&NrvTamakoro::TamakoroNrvRideRailFastEnd::sInstance); } } void Tamakoro::exeRideRailFastEnd() { if (MR::isFirstStep(this)) { - MR::startBckPlayer("BallRollEnd", (const char*)0); - MR::setBckRatePlayer(1.5); + MR::startBckPlayer("BallRollEnd", static_cast< const char* >(nullptr)); + MR::setBckRatePlayer(sRollBckRate); } updateRideRail(); if (MR::isBckStoppedPlayer()) { @@ -916,8 +850,8 @@ void Tamakoro::exeBindEnd() { if (MR::isFirstStep(this)) { MR::tryRumblePadStrong(this, WPAD_CHAN0); MR::shakeCameraStrong(); - mMoveVec.zero(); - mMoveSpeed = 0.0f; + mAccelDir.zero(); + mAccelRate = 0.0f; if (MR::isValidSwitchA(this)) { MR::offSwitchA(this); } @@ -927,7 +861,7 @@ void Tamakoro::exeBindEnd() { MR::stopStageBGM(10); } - if ((MR::isGreaterStep(this, 12) && MR::isOnGroundPlayer()) || MR::isGreaterStep(this, 90)) { + if ((MR::isGreaterStep(this, 12) && MR::isOnGroundPlayer()) || MR::isGreaterStep(this, sForceBindEndTime)) { MR::startLastStageBGM(); MR::requestAppearPowerStar(this, mPosition); kill(); @@ -935,34 +869,34 @@ void Tamakoro::exeBindEnd() { } void Tamakoro::addVelocityOperate() { - mMoveSpeed = mAccelSensorCtrl->calcMoveVector(&mMoveVec, mGravity); + mAccelRate = mAccelSensorCtrl->calcMoveVector(&mAccelDir, mGravity); TVec3f* vel = &mVelocity; // this needs to be like this to match... - f32 scale; - if (MR::isBindedGround(this)) { - scale = 0.4f; - } else { - scale = 0.2f; - } - - JMAVECScaleAdd(&mMoveVec, vel, &mVelocity, mMoveSpeed * scale); + JMAVECScaleAdd(&mAccelDir, vel, &mVelocity, mAccelRate * (MR::isBindedGround(this) ? 0.4f : 0.2f)); } f32 Tamakoro::updateRideRail() { - mMoveVec.set(mVelocity); + mAccelDir.set(mVelocity); - if (MR::normalizeOrZero(&mMoveVec)) { - mMoveSpeed = 0.5f; + if (MR::normalizeOrZero(&mAccelDir)) { + mAccelRate = 0.5f; } else { - mMoveSpeed = 0.0f; + mAccelRate = 0.0f; } - f32 mag = PSVECMag(&mMoment) * 150.0f; + f32 speed = mMoment.length() * mBaseRadius; updateMarioPose(15.0f); updateMarioOffset(); - return mag; + return speed; +} + +void Tamakoro::updateVelocityNormal(f32 friction) { + TVec3f vel(mVelocity); // unused! woo! + MR::reboundVelocityFromCollision(this, 0.0f, 0.0f, 1.0f); + MR::addVelocityToGravity(this, sGravityAccel); + MR::attenuateVelocity(this, MR::isBindedGround(this) ? friction : 0.995f); } void Tamakoro::updateMoment() { @@ -977,7 +911,7 @@ void Tamakoro::updateMoment() { up = &tmpVec; } - MR::calcMomentRollBall(&moment, mVelocity, *up, 150.0f); + MR::calcMomentRollBall(&moment, mVelocity, *up, mBaseRadius); MR::vecBlend(mMoment, moment, &mMoment, 0.25f); startRotateLevelSound(); } else { @@ -993,103 +927,103 @@ void Tamakoro::updateAirTime() { } } -void Tamakoro::updateMarioPose(f32 pDegree) { - TVec3f v1; +void Tamakoro::updateMarioPose(f32 degree) { + // TODO : rejection + TVec3f velH; // these *need* to be pointers to match... TVec3f* vel = &mVelocity; TVec3f* grav = &mGravity; f32 dot = grav->dot(*vel); - JMAVECScaleAdd(grav, vel, &v1, -dot); // v1.rejection(vel, grav); + JMAVECScaleAdd(grav, vel, &velH, -dot); // velH.rejection(vel, grav); - if (MR::isNearZero(v1)) { - if (mMoveSpeed > 0.001f) { - MR::turnDirectionDegree(this, &mMarioRotateFront, mMoveVec, pDegree * mMoveSpeed); + if (MR::isNearZero(velH)) { + if (mAccelRate > 0.001f) { + MR::turnDirectionDegree(this, &mMarioFront, mAccelDir, degree * mAccelRate); } } else { - MR::turnDirectionDegree(this, &mMarioRotateFront, v1, pDegree); + MR::turnDirectionDegree(this, &mMarioFront, velH, degree); } TVec3f zDir; TVec3f xDir; - mRotateQuat.getXDir(xDir); - mRotateQuat.getZDir(zDir); + mMarioRotateQuat.getXDir(xDir); + mMarioRotateQuat.getZDir(zDir); - if (mMoveSpeed > 0.0f) { - f32 dot = MR::normalize(1.0f - mMoveVec.dot(zDir), 0.1f, 1.0f); + if (mAccelRate > 0.0f) { + f32 dot = MR::normalize(1.0f - mAccelDir.dot(zDir), 0.1f, 1.0f); f32 sign; - if (mMoveVec.dot(xDir) >= 0.0f) { + if (mAccelDir.dot(xDir) >= 0.0f) { sign = 1.0f; } else { sign = -1.0f; } dot = sign * dot; - mMarioRotateYAngle += dot * 5.0f; + mMarioRotateYAngle += dot * sMarioUpperYAccel; } - mMarioRotateYAngle *= 0.9f; + mMarioRotateYAngle *= sMarioUpperYFric; TVec3f up; up.set(-mGravity); - mMarioRotateUp.set(-mGravity); + mMarioUp.set(-mGravity); - TVec3f v6; - PSVECCrossProduct(&mMoveVec, &mGravity, &v6); + TVec3f rotAxis = mAccelDir.cross(mGravity); - if (!MR::normalizeOrZero(&v6)) { - MR::rotateVecDegree(&up, v6, mMoveSpeed * 35.0f); - MR::rotateVecDegree(&mMarioRotateUp, v6, mMoveSpeed * 20.0f); + if (!MR::normalizeOrZero(&rotAxis)) { + MR::rotateVecDegree(&up, rotAxis, mAccelRate * 35.0f); + MR::rotateVecDegree(&mMarioUp, rotAxis, mAccelRate * 20.0f); } - MR::vecBlendSphere(mDirectionToMario, up, &mDirectionToMario, 0.02f); + MR::vecBlendSphere(mDirectionToMario, up, &mDirectionToMario, sStandDirInterRate); if (MR::normalizeOrZero(&mDirectionToMario)) { mDirectionToMario.set(-mGravity); } - MR::blendQuatUpFront(&mRotateQuat, mMarioRotateUp, mMarioRotateFront, 0.1f, 0.25f); + MR::blendQuatUpFront(&mMarioRotateQuat, mMarioUp, mMarioFront, sMarioUpAdjustRate, sMarioFrontAdjustRate); f32 rotY = mMarioRotateYAngle; - MR::setPlayerUpperRotateY(0.017453292f * rotY); // sin(1.0f) + MR::setPlayerUpperRotateY(PI_180 * rotY); } void Tamakoro::updateMarioOffset() { - f32 decay = (mMarioOffsetVelocity - 1.0f); - decay *= 0.99f; + f32 velocity = mMarioOffsetVelocity - sMarioOffsetGravityAccel; + velocity *= sMarioOffsetFric; - mMarioOffsetVelocity = decay; - mMarioOffset += decay; - mMarioOffset = MR::clamp(mMarioOffset, 0.0f, 150.0f); + mMarioOffsetVelocity = velocity; + mMarioOffset += mMarioOffsetVelocity; + mMarioOffset = MR::clamp(mMarioOffset, 0.0f, sMarioJumpOffsetMax); } void Tamakoro::updateMoveBckBlend(f32 pSpeed) { - f32 w0 = 0.0f; - f32 w1 = 0.0f; - f32 w2 = 0.0f; - f32 w3 = 0.0f; + f32 idleBckWeight = 0.0f; + f32 softWalkBckWeight = 0.0f; + f32 walkBckWeight = 0.0f; + f32 runBckWeight = 0.0f; f32 rate = 0.0f; - f32 limit1 = 0.25f; - f32 limit2 = 6.0f; - f32 limit3 = 18.0f; - - if (pSpeed < limit1) { - w1 = MR::normalize(pSpeed, 0.0f, 0.25f); - w0 = 1.0f - w1; - rate = MR::getLinerValue(w1, 1.0f, 1.0f, 1.0f); - } else if (pSpeed < limit2) { - w2 = MR::normalize(pSpeed, 0.25, 6.0f); - w1 = 1.0f - w2; - rate = MR::getLinerValue(w2, 1.0f, 2.0f, 1.0f); - } else if (pSpeed < limit3) { - w3 = MR::normalize(pSpeed, 6.0f, 18.0f); - w2 = 1.0f - w3; - rate = MR::getLinerValue(w3, 2.0f, 3.0f, 1.0f); + f32 softWalkSpeed = sSoftWalkSpeed; + f32 walkSpeed = sWalkSpeed; + f32 runSpeed = sRunSpeed; + + if (pSpeed < softWalkSpeed) { + softWalkBckWeight = MR::normalize(pSpeed, 0.0f, softWalkSpeed); + idleBckWeight = 1.0f - softWalkBckWeight; + rate = MR::getLinerValue(softWalkBckWeight, sIdleBckRate, sSoftWalkBckRate, 1.0f); + } else if (pSpeed < walkSpeed) { + walkBckWeight = MR::normalize(pSpeed, softWalkSpeed, walkSpeed); + softWalkBckWeight = 1.0f - walkBckWeight; + rate = MR::getLinerValue(walkBckWeight, sSoftWalkBckRate, sWalkBckRate, 1.0f); + } else if (pSpeed < runSpeed) { + runBckWeight = MR::normalize(pSpeed, walkSpeed, runSpeed); + walkBckWeight = 1.0f - runBckWeight; + rate = MR::getLinerValue(runBckWeight, sWalkBckRate, sRunBckRate, 1.0f); } else { - w3 = 1.0f; - rate = (pSpeed / 18.0f) * 3.0f; - if (rate > 4.0f) { - rate = 4.0f; + runBckWeight = 1.0f; + rate = (pSpeed / runSpeed) * sRunBckRate; + if (rate > sRunMaxBckRate) { + rate = sRunMaxBckRate; } } - MR::setBckBlendWeight(w0, w1, w2, w3); + MR::setBckBlendWeight(idleBckWeight, softWalkBckWeight, walkBckWeight, runBckWeight); MR::setBckRatePlayer(rate); } @@ -1163,7 +1097,7 @@ bool Tamakoro::isNeedTutorial() const { } void Tamakoro::startRotateLevelSound() { - f32 mag = PSVECMag(&mMoment); + f32 mag = mMoment.length(); if (mag <= 0.001f) { return; diff --git a/src/Game/Scene/SceneObjHolder.cpp b/src/Game/Scene/SceneObjHolder.cpp index 3e4117c84..1af31f244 100644 --- a/src/Game/Scene/SceneObjHolder.cpp +++ b/src/Game/Scene/SceneObjHolder.cpp @@ -81,7 +81,7 @@ #include "Game/Ride/FluffWind.hpp" #include "Game/Ride/PlantLeaf.hpp" #include "Game/Ride/PlantStalk.hpp" -// #include "Game/Ride/SwingRope.hpp" +#include "Game/Ride/SwingRope.hpp" #include "Game/Ride/Trapeze.hpp" #include "Game/Scene/PlacementStateChecker.hpp" #include "Game/Scene/SceneDataInitializer.hpp" @@ -303,7 +303,7 @@ NameObj* SceneObjHolder::newEachObj(int id) { case SceneObj_ShadowSurfaceDrawInit: return new ShadowSurfaceDrawInit("水面影描画初期化"); case SceneObj_SwingRopeGroup: - // return new SwingRopeGroup("スイングロープ描画"); + return new SwingRopeGroup("スイングロープ描画"); return nullptr; case SceneObj_PlantStalkDrawInit: return new PlantStalkDrawInit("植物の茎描画初期化"); From dd0068aa0c8177e058e211ef1f4d5b23a38a531c Mon Sep 17 00:00:00 2001 From: MrL314 <11429905+MrL314@users.noreply.github.com> Date: Thu, 19 Feb 2026 01:21:03 -0500 Subject: [PATCH 25/52] `WalkerStateWander` and `WalkerStateFindPlayer` --- configure.py | 4 +- include/Game/Enemy/TerritoryMover.hpp | 4 +- .../Game/Enemy/WalkerStateBindStarPointer.hpp | 1 - include/Game/Enemy/WalkerStateBlowDamage.hpp | 5 +- include/Game/Enemy/WalkerStateFindPlayer.hpp | 18 ++-- include/Game/Enemy/WalkerStateWander.hpp | 21 ++-- src/Game/Enemy/Kuribo.cpp | 18 ++-- src/Game/Enemy/WalkerStateBindStarPointer.cpp | 8 +- src/Game/Enemy/WalkerStateBlowDamage.cpp | 36 +++---- src/Game/Enemy/WalkerStateFindPlayer.cpp | 96 +++++++++++++++++++ src/Game/Enemy/WalkerStateFunction.cpp | 12 +-- src/Game/Enemy/WalkerStateWander.cpp | 77 +++++++++++++++ 12 files changed, 236 insertions(+), 64 deletions(-) create mode 100644 src/Game/Enemy/WalkerStateFindPlayer.cpp create mode 100644 src/Game/Enemy/WalkerStateWander.cpp diff --git a/configure.py b/configure.py index c73f061d0..4b6f52172 100644 --- a/configure.py +++ b/configure.py @@ -1170,9 +1170,9 @@ def JSys_J3DLib(lib_name: str, objects: List[Object]) -> Dict[str, Any]: Object(NonMatching, "Game/Enemy/Unizo.cpp"), Object(NonMatching, "Game/Enemy/UnizoLauncher.cpp"), Object(Matching, "Game/Enemy/WalkerStateBindStarPointer.cpp"), - Object(NonMatching, "Game/Enemy/WalkerStateBlowDamage.cpp"), + Object(Matching, "Game/Enemy/WalkerStateBlowDamage.cpp"), Object(Matching, "Game/Enemy/WalkerStateChase.cpp"), - Object(NonMatching, "Game/Enemy/WalkerStateFindPlayer.cpp"), + Object(Matching, "Game/Enemy/WalkerStateFindPlayer.cpp"), Object(Matching, "Game/Enemy/WalkerStateFunction.cpp"), Object(Matching, "Game/Enemy/WalkerStateParam.cpp"), Object(NonMatching, "Game/Enemy/WalkerStateRunaway.cpp"), diff --git a/include/Game/Enemy/TerritoryMover.hpp b/include/Game/Enemy/TerritoryMover.hpp index d88bb169f..5c9b17388 100644 --- a/include/Game/Enemy/TerritoryMover.hpp +++ b/include/Game/Enemy/TerritoryMover.hpp @@ -12,7 +12,9 @@ class TerritoryMover { void decideNextTargetPos(const LiveActor*); bool isReachedTarget(const LiveActor*, f32); - void setCenter(const TVec3f& rPos) { mCenter.set(rPos); } + void setCenter(const TVec3f& rPos) NO_INLINE { + mCenter.set(rPos); + } f32 _0; TVec3f mCenter; // 0x4 diff --git a/include/Game/Enemy/WalkerStateBindStarPointer.hpp b/include/Game/Enemy/WalkerStateBindStarPointer.hpp index 97ce58403..d7b7e8951 100644 --- a/include/Game/Enemy/WalkerStateBindStarPointer.hpp +++ b/include/Game/Enemy/WalkerStateBindStarPointer.hpp @@ -9,7 +9,6 @@ class WalkerStateBindStarPointer : public ActorStateBase< LiveActor > { public: WalkerStateBindStarPointer(LiveActor*, AnimScaleController*); - virtual ~WalkerStateBindStarPointer(); virtual void appear(); virtual void kill(); diff --git a/include/Game/Enemy/WalkerStateBlowDamage.hpp b/include/Game/Enemy/WalkerStateBlowDamage.hpp index d171142df..c50894b45 100644 --- a/include/Game/Enemy/WalkerStateBlowDamage.hpp +++ b/include/Game/Enemy/WalkerStateBlowDamage.hpp @@ -14,12 +14,11 @@ class WalkerStateBlowDamage : public ActorStateBase< LiveActor > { public: WalkerStateBlowDamage(LiveActor*, TVec3f*, WalkerStateBlowDamageParam*); - virtual ~WalkerStateBlowDamage(); virtual void appear(); void exeBlow(); void exeBlowLand(); - TVec3f* _10; - TVec3f _14; + /* 0x10 */ TVec3f* mDirection; + /* 0x14 */ WalkerStateBlowDamageParam* mBlowDamageParam; }; diff --git a/include/Game/Enemy/WalkerStateFindPlayer.hpp b/include/Game/Enemy/WalkerStateFindPlayer.hpp index b88bf8508..c6be28221 100644 --- a/include/Game/Enemy/WalkerStateFindPlayer.hpp +++ b/include/Game/Enemy/WalkerStateFindPlayer.hpp @@ -1,8 +1,7 @@ #pragma once +#include "Game/LiveActor/ActorStateBase.hpp" #include "Game/LiveActor/LiveActor.hpp" -#include "Game/System/NerveExecutor.hpp" -#include "JSystem/JGeometry/TVec.hpp" class WalkerStateParam; @@ -10,16 +9,15 @@ class WalkerStateFindPlayerParam { public: WalkerStateFindPlayerParam(); - u32 _0; - f32 _4; - f32 _8; + /* 0x0 */ u32 mJumpStartStep; + /* 0x4 */ f32 mJumpVelocity; + /* 0x8 */ f32 mTurnDegree; }; class WalkerStateFindPlayer : public ActorStateBase< LiveActor > { public: - WalkerStateFindPlayer(LiveActor*, TVec3f*, WalkerStateParam*, WalkerStateFindPlayerParam*); + WalkerStateFindPlayer(LiveActor* pHost, TVec3f* pPosition, WalkerStateParam* pStateParam, WalkerStateFindPlayerParam* pFindPlayerParam); - virtual ~WalkerStateFindPlayer(); virtual void appear(); void exeFind(); @@ -30,7 +28,7 @@ class WalkerStateFindPlayer : public ActorStateBase< LiveActor > { bool isFindJumpBegin() const; bool isLandStart() const; - TVec3f* _10; - WalkerStateParam* mStateParam; // 0x14 - WalkerStateFindPlayerParam* mFindPlayerParam; // 0x18 + /* 0x10 */ TVec3f* mDirection; + /* 0x14 */ WalkerStateParam* mStateParam; + /* 0x18 */ WalkerStateFindPlayerParam* mFindPlayerParam; }; diff --git a/include/Game/Enemy/WalkerStateWander.hpp b/include/Game/Enemy/WalkerStateWander.hpp index 518613d18..9d5a4e806 100644 --- a/include/Game/Enemy/WalkerStateWander.hpp +++ b/include/Game/Enemy/WalkerStateWander.hpp @@ -1,7 +1,7 @@ #pragma once +#include "Game/LiveActor/ActorStateBase.hpp" #include "Game/LiveActor/LiveActor.hpp" -#include "Game/System/NerveExecutor.hpp" class WalkerStateParam; class TerritoryMover; @@ -10,26 +10,25 @@ class WalkerStateWanderParam { public: WalkerStateWanderParam(); - s32 _0; - s32 _4; - f32 _8; - f32 _C; - f32 _10; + /* 0x00 */ s32 mWaitTime; + /* 0x04 */ s32 mWalkTime; + /* 0x08 */ f32 mSpeed; + /* 0x0C */ f32 mTurnDegree; + /* 0x10 */ f32 mTargetDistance; }; class WalkerStateWander : public ActorStateBase< LiveActor > { public: WalkerStateWander(LiveActor*, TVec3f*, WalkerStateParam*, WalkerStateWanderParam*); - virtual ~WalkerStateWander(); virtual void appear(); void setWanderCenter(const TVec3f&); void exeWait(); void exeWalk(); - TVec3f* _10; - TerritoryMover* mTerritoryMover; // 0x14 - WalkerStateParam* mStateParam; // 0x18 - WalkerStateWanderParam* mWanderParam; // 0x1C + /* 0x10 */ TVec3f* mDirection; + /* 0x14 */ TerritoryMover* mTerritoryMover; + /* 0x18 */ WalkerStateParam* mStateParam; + /* 0x1C */ WalkerStateWanderParam* mWanderParam; }; diff --git a/src/Game/Enemy/Kuribo.cpp b/src/Game/Enemy/Kuribo.cpp index ea1cd3e94..11525286c 100644 --- a/src/Game/Enemy/Kuribo.cpp +++ b/src/Game/Enemy/Kuribo.cpp @@ -37,13 +37,13 @@ namespace { mStateParam._C = 1000.0f; mStateParam._10 = 70.0f; mStateParam._14 = 30.0f; - mWanderParam._8 = 0.2f; - mWanderParam._0 = 120; - mWanderParam._4 = 120; - mWanderParam._C = 3.0f; + mWanderParam.mSpeed = 0.2f; + mWanderParam.mWaitTime = 120; + mWanderParam.mWalkTime = 120; + mWanderParam.mTurnDegree = 3.0f; mChaseParam._0 = 0.4f; - mFindPlayerParam._8 = 5.0f; - mFindPlayerParam._4 = 20.0f; + mFindPlayerParam.mTurnDegree = 5.0f; + mFindPlayerParam.mJumpVelocity = 20.0f; } static KuriboParam sParam; @@ -68,7 +68,8 @@ namespace NrvKuribo { Kuribo::Kuribo(const char* pName) : LiveActor(pName), mScaleController(nullptr), mItemGenerator(nullptr), mStateWander(nullptr), mStateFindPlayer(nullptr), - mBindStarPointer(nullptr), mStateStagger(nullptr), mStateChase(nullptr), _A8(0.0f, 0.0f, 0.0f, 1.0f), _B8(0, 0, 1), _C4(0), _C5(1) {} + mBindStarPointer(nullptr), mStateStagger(nullptr), mStateChase(nullptr), _A8(0.0f, 0.0f, 0.0f, 1.0f), _B8(0, 0, 1), _C4(0), _C5(1) { +} void Kuribo::init(const JMapInfoIter& rIter) { MR::initDefaultPos(this, rIter); @@ -796,4 +797,5 @@ namespace MR { } }; // namespace MR -Kuribo::~Kuribo() {} +Kuribo::~Kuribo() { +} diff --git a/src/Game/Enemy/WalkerStateBindStarPointer.cpp b/src/Game/Enemy/WalkerStateBindStarPointer.cpp index f66e3a952..ba11b3a71 100644 --- a/src/Game/Enemy/WalkerStateBindStarPointer.cpp +++ b/src/Game/Enemy/WalkerStateBindStarPointer.cpp @@ -1,6 +1,10 @@ #include "Game/Enemy/WalkerStateBindStarPointer.hpp" #include "Game/Enemy/AnimScaleController.hpp" +namespace { + static const s32 sPointCanceBindTime = 5; +} + namespace NrvWalkerStateBindStarPointer { NEW_NERVE(WalkerStateBindStarPointerNrvBind, WalkerStateBindStarPointer, Bind); }; @@ -60,9 +64,7 @@ void WalkerStateBindStarPointer::exeBind() { mUpdateCounter++; } - if (mUpdateCounter > 5) { + if (mUpdateCounter > sPointCanceBindTime) { update(); } } - -WalkerStateBindStarPointer::~WalkerStateBindStarPointer() {} diff --git a/src/Game/Enemy/WalkerStateBlowDamage.cpp b/src/Game/Enemy/WalkerStateBlowDamage.cpp index 96f031876..7e8906da9 100644 --- a/src/Game/Enemy/WalkerStateBlowDamage.cpp +++ b/src/Game/Enemy/WalkerStateBlowDamage.cpp @@ -1,46 +1,50 @@ #include "Game/Enemy/WalkerStateBlowDamage.hpp" -#include "Game/LiveActor/Nerve.hpp" #include "Game/Util/ActorMovementUtil.hpp" #include "Game/Util/LiveActorUtil.hpp" -#include "revolution/types.h" + +namespace { + static const f32 sAirFric = 0.99f; + static const f32 sAirGravityAccel = 1.0f; + static const f32 sDamageTurnLimit = 15.0f; + static const s32 sDamageLandTime = 5; +} // namespace namespace NrvWalkerStateBlowDamage { NEW_NERVE(WalkerStateBlowDamageNrvBlow, WalkerStateBlowDamage, Blow); NEW_NERVE(WalkerStateBlowDamageNrvBlowLand, WalkerStateBlowDamage, BlowLand); } // namespace NrvWalkerStateBlowDamage -WalkerStateBlowDamage::WalkerStateBlowDamage(LiveActor* pActor, TVec3f* pVec, WalkerStateBlowDamageParam* pBlowDamageParam) - : ActorStateBase< LiveActor >("吹き飛びダメージ状態", pActor) { +WalkerStateBlowDamage::WalkerStateBlowDamage(LiveActor* pActor, TVec3f* pDirection, WalkerStateBlowDamageParam* pBlowDamageParam) + : ActorStateBase< LiveActor >("吹き飛びダメージ状態", pActor), mDirection(pDirection), mBlowDamageParam(pBlowDamageParam) { initNerve(&NrvWalkerStateBlowDamage::WalkerStateBlowDamageNrvBlow::sInstance); } -WalkerStateBlowDamage::~WalkerStateBlowDamage() {} void WalkerStateBlowDamage::appear() { - mIsDead = 0; + mIsDead = false; setNerve(&NrvWalkerStateBlowDamage::WalkerStateBlowDamageNrvBlow::sInstance); } void WalkerStateBlowDamage::exeBlow() { if (MR::isFirstStep(this)) { - MR::startAction(this->mHost, "Damage"); + MR::startAction(getHost(), "Damage"); } - MR::attenuateVelocity(this->mHost, 0.99f); - MR::addVelocityToGravity(this->mHost, 1.0f); + MR::attenuateVelocity(getHost(), sAirFric); + MR::addVelocityToGravity(getHost(), sAirGravityAccel); TVec3f mVelocityNegate; - JMathInlineVEC::PSVECNegate(&mHost->mVelocity, &mVelocityNegate); - MR::turnDirectionDegree(this->mHost, this->_10, mVelocityNegate, 15.0f); + JMathInlineVEC::PSVECNegate(&getHost()->mVelocity, &mVelocityNegate); + MR::turnDirectionDegree(getHost(), mDirection, mVelocityNegate, sDamageTurnLimit); - if (MR::isGreaterStep(this, 5)) { - if (MR::isBindedGround(this->mHost)) { - MR::startAction(this->mHost, "DamageLand"); - MR::zeroVelocity(this->mHost); + if (MR::isGreaterStep(this, sDamageLandTime)) { + if (MR::isBindedGround(getHost())) { + MR::startAction(getHost(), "DamageLand"); + MR::zeroVelocity(getHost()); setNerve(&NrvWalkerStateBlowDamage::WalkerStateBlowDamageNrvBlowLand::sInstance); } } } -inline void WalkerStateBlowDamage::exeBlowLand() { +void WalkerStateBlowDamage::exeBlowLand() { if (MR::isGreaterStep(this, 30)) { kill(); } diff --git a/src/Game/Enemy/WalkerStateFindPlayer.cpp b/src/Game/Enemy/WalkerStateFindPlayer.cpp new file mode 100644 index 000000000..ef41f5967 --- /dev/null +++ b/src/Game/Enemy/WalkerStateFindPlayer.cpp @@ -0,0 +1,96 @@ +#include "Game/Enemy/WalkerStateFindPlayer.hpp" +#include "Game/Enemy/WalkerStateFunction.hpp" +#include "Game/Util/ActorMovementUtil.hpp" +#include "Game/Util/LiveActorUtil.hpp" +#include "Game/Util/NerveUtil.hpp" + +namespace { + WalkerStateFindPlayerParam sDefaultParam; +} + +namespace NrvWalkerStateFindPlayer { + NEW_NERVE(WalkerStateFindPlayerNrvFind, WalkerStateFindPlayer, Find); + NEW_NERVE(WalkerStateFindPlayerNrvFindJumpStart, WalkerStateFindPlayer, FindJumpStart); + NEW_NERVE(WalkerStateFindPlayerNrvFindJump, WalkerStateFindPlayer, FindJump); + NEW_NERVE(WalkerStateFindPlayerNrvFindJumpEnd, WalkerStateFindPlayer, FindJumpEnd); +} // namespace NrvWalkerStateFindPlayer + +WalkerStateFindPlayerParam::WalkerStateFindPlayerParam() : mJumpStartStep(30), mJumpVelocity(20.0f), mTurnDegree(5.0f) { +} + +WalkerStateFindPlayer::WalkerStateFindPlayer(LiveActor* pHost, TVec3f* pDirection, WalkerStateParam* pStateParam, + WalkerStateFindPlayerParam* pFindPlayerParam) + : ActorStateBase< LiveActor >("歩行型プレイヤー発見挙動", pHost), mDirection(pDirection), mStateParam(pStateParam), + mFindPlayerParam(pFindPlayerParam) { + initNerve(&NrvWalkerStateFindPlayer::WalkerStateFindPlayerNrvFind::sInstance); + if (mFindPlayerParam == nullptr) { + mFindPlayerParam = &sDefaultParam; + } +} + +void WalkerStateFindPlayer::appear() { + mIsDead = false; + setNerve(&NrvWalkerStateFindPlayer::WalkerStateFindPlayerNrvFind::sInstance); +} + +void WalkerStateFindPlayer::exeFind() { + if (MR::isFirstStep(this)) { + MR::startAction(getHost(), "Turn"); + } + + WalkerStateFunction::calcPassiveMovement(getHost(), mStateParam); + MR::turnDirectionToTargetUseGroundNormalDegree(getHost(), mDirection, *MR::getPlayerPos(), mFindPlayerParam->mTurnDegree); + + if (MR::isStep(this, mFindPlayerParam->mJumpStartStep)) { + setNerve(&NrvWalkerStateFindPlayer::WalkerStateFindPlayerNrvFindJumpStart::sInstance); + } +} + +void WalkerStateFindPlayer::exeFindJumpStart() { + if (MR::isFirstStep(this)) { + MR::startAction(getHost(), "JumpStart"); + } + + WalkerStateFunction::calcPassiveMovement(getHost(), mStateParam); + + if (MR::isBckStopped(getHost())) { + setNerve(&NrvWalkerStateFindPlayer::WalkerStateFindPlayerNrvFindJump::sInstance); + } +} + +void WalkerStateFindPlayer::exeFindJump() { + if (MR::isFirstStep(this)) { + MR::addVelocityJump(getHost(), mFindPlayerParam->mJumpVelocity); + MR::startAction(getHost(), "Jump"); + } + + WalkerStateFunction::calcPassiveMovement(getHost(), mStateParam); + + if (MR::isBindedGround(getHost()) && MR::isGreaterStep(this, 5)) { + setNerve(&NrvWalkerStateFindPlayer::WalkerStateFindPlayerNrvFindJumpEnd::sInstance); + } +} + +void WalkerStateFindPlayer::exeFindJumpEnd() { + if (MR::isFirstStep(this)) { + MR::startAction(getHost(), "Land"); + } + + WalkerStateFunction::calcPassiveMovement(getHost(), mStateParam); + + if (MR::isBckStopped(getHost())) { + kill(); + } +} + +bool WalkerStateFindPlayer::isInSightPlayer() const { + return WalkerStateFunction::isInSightPlayer(getHost(), *mDirection, mStateParam); +} + +bool WalkerStateFindPlayer::isFindJumpBegin() const { + return isNerve(&NrvWalkerStateFindPlayer::WalkerStateFindPlayerNrvFindJump::sInstance) && MR::isFirstStep(this); +} + +bool WalkerStateFindPlayer::isLandStart() const { + return isNerve(&NrvWalkerStateFindPlayer::WalkerStateFindPlayerNrvFindJumpEnd::sInstance) && MR::isFirstStep(this); +} diff --git a/src/Game/Enemy/WalkerStateFunction.cpp b/src/Game/Enemy/WalkerStateFunction.cpp index 0e62422d3..a9b5b7dfe 100644 --- a/src/Game/Enemy/WalkerStateFunction.cpp +++ b/src/Game/Enemy/WalkerStateFunction.cpp @@ -1,12 +1,10 @@ #include "Game/Enemy/WalkerStateFunction.hpp" #include "Game/Enemy/WalkerStateParam.hpp" -#include "Game/Util.hpp" #include "Game/Util/ActorMovementUtil.hpp" -#include "JSystem/JGeometry/TVec.hpp" +#include "Game/Util/LiveActorUtil.hpp" -// Required For Float Order, should get stripped when linked. -void unusedFunction() { - f32 x = 0.0f; +bool WalkerStateFunction::isInSightPlayer(const LiveActor* pActor, const TVec3f& pTVec3f, const WalkerStateParam* pParam) { + return MR::isInSightFanPlayer(pActor, pTVec3f, pParam->_C, pParam->_10, pParam->_14); } void WalkerStateFunction::calcPassiveMovement(LiveActor* pActor, const WalkerStateParam* pParam) { @@ -18,7 +16,3 @@ void WalkerStateFunction::calcPassiveMovement(LiveActor* pActor, const WalkerSta MR::attenuateVelocity(pActor, pParam->_8); } } - -bool WalkerStateFunction::isInSightPlayer(const LiveActor* pActor, const TVec3f& pTVec3f, const WalkerStateParam* pParam) { - return MR::isInSightFanPlayer(pActor, pTVec3f, pParam->_C, pParam->_10, pParam->_14); -} diff --git a/src/Game/Enemy/WalkerStateWander.cpp b/src/Game/Enemy/WalkerStateWander.cpp new file mode 100644 index 000000000..539a2b700 --- /dev/null +++ b/src/Game/Enemy/WalkerStateWander.cpp @@ -0,0 +1,77 @@ +#include "Game/Enemy/WalkerStateWander.hpp" +#include "Game/Enemy/TerritoryMover.hpp" +#include "Game/Enemy/WalkerStateFunction.hpp" +#include "Game/Enemy/WalkerStateParam.hpp" +#include "Game/Util/ActorMovementUtil.hpp" +#include "Game/Util/MapUtil.hpp" + +namespace { + WalkerStateWanderParam sDefaultParam; +} + +namespace NrvWalkerStateWander { + NEW_NERVE(WalkerStateWanderNrvWait, WalkerStateWander, Wait); + NEW_NERVE(WalkerStateWanderNrvWalk, WalkerStateWander, Walk); +} // namespace NrvWalkerStateWander + +WalkerStateWanderParam::WalkerStateWanderParam() : mWaitTime(120), mWalkTime(120), mSpeed(0.2f), mTurnDegree(3.0f), mTargetDistance(20.0f) { +} + +WalkerStateWander::WalkerStateWander(LiveActor* pActor, TVec3f* pDirection, WalkerStateParam* pStateParam, WalkerStateWanderParam* pWanderParam) + : ActorStateBase< LiveActor >("クリボー型うろつき状態", pActor), mDirection(pDirection), mTerritoryMover(nullptr), mStateParam(pStateParam), + mWanderParam(pWanderParam) { + initNerve(&NrvWalkerStateWander::WalkerStateWanderNrvWait::sInstance); + + if (mWanderParam == nullptr) { + mWanderParam = &sDefaultParam; + } + + mTerritoryMover = new TerritoryMover(500.0f); + mTerritoryMover->setCenter(getHost()->mPosition); +} + +void WalkerStateWander::appear() { + mIsDead = false; + setNerve(&NrvWalkerStateWander::WalkerStateWanderNrvWait::sInstance); +} + +void WalkerStateWander::setWanderCenter(const TVec3f& rCenter) { + mTerritoryMover->setCenter(rCenter); +} + +void WalkerStateWander::exeWait() { + if (MR::isFirstStep(this)) { + MR::startAction(getHost(), "Wait"); + } + + WalkerStateFunction::calcPassiveMovement(getHost(), mStateParam); + + if (MR::isGreaterStep(this, mWanderParam->mWaitTime)) { + mTerritoryMover->decideNextTargetPos(getHost()); + setNerve(&NrvWalkerStateWander::WalkerStateWanderNrvWalk::sInstance); + } +} + +void WalkerStateWander::exeWalk() { + if (MR::isFirstStep(this)) { + MR::startAction(getHost(), "Walk"); + } + + MR::turnDirectionToTargetUseGroundNormalDegree(getHost(), mDirection, mTerritoryMover->_10, mWanderParam->mTurnDegree); + + if (MR::isFaceToTargetHorizontalDegree(getHost(), mTerritoryMover->_10, *mDirection, 8.0f)) { + MR::addVelocityMoveToDirection(getHost(), *mDirection, mWanderParam->mSpeed); + } + + WalkerStateFunction::calcPassiveMovement(getHost(), mStateParam); + + if (MR::isFallNextMove(getHost(), 150.0f, 150.0f, 150.0f, nullptr)) { + MR::zeroVelocity(getHost()); + setNerve(&NrvWalkerStateWander::WalkerStateWanderNrvWait::sInstance); + return; + } + + if (MR::isGreaterStep(this, mWanderParam->mWalkTime) || mTerritoryMover->isReachedTarget(getHost(), mWanderParam->mTargetDistance)) { + setNerve(&NrvWalkerStateWander::WalkerStateWanderNrvWait::sInstance); + } +} From f2e910555a061356cda5fc9176be50f75047d563 Mon Sep 17 00:00:00 2001 From: MrL314 <11429905+MrL314@users.noreply.github.com> Date: Thu, 19 Feb 2026 01:31:22 -0500 Subject: [PATCH 26/52] Fix incorrect call in `WalkerStateBindStarPointer` --- src/Game/Enemy/WalkerStateBindStarPointer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Game/Enemy/WalkerStateBindStarPointer.cpp b/src/Game/Enemy/WalkerStateBindStarPointer.cpp index ba11b3a71..94378890f 100644 --- a/src/Game/Enemy/WalkerStateBindStarPointer.cpp +++ b/src/Game/Enemy/WalkerStateBindStarPointer.cpp @@ -65,6 +65,6 @@ void WalkerStateBindStarPointer::exeBind() { } if (mUpdateCounter > sPointCanceBindTime) { - update(); + kill(); } } From a2d33b3c03c7b3e3d76163dfe83d074fb4836c26 Mon Sep 17 00:00:00 2001 From: MrL314 <11429905+MrL314@users.noreply.github.com> Date: Thu, 19 Feb 2026 16:27:59 -0500 Subject: [PATCH 27/52] Match `WalkerStateStagger` --- configure.py | 4 +- include/Game/Enemy/WalkerStateStagger.hpp | 44 +++--- .../JSystem/JMath/JMATrigonometric.hpp | 46 ++++-- src/Game/Enemy/WalkerStateStagger.cpp | 140 ++++++++++++++++++ 4 files changed, 200 insertions(+), 34 deletions(-) create mode 100644 src/Game/Enemy/WalkerStateStagger.cpp diff --git a/configure.py b/configure.py index 4b6f52172..c01b13fe5 100644 --- a/configure.py +++ b/configure.py @@ -1176,8 +1176,8 @@ def JSys_J3DLib(lib_name: str, objects: List[Object]) -> Dict[str, Any]: Object(Matching, "Game/Enemy/WalkerStateFunction.cpp"), Object(Matching, "Game/Enemy/WalkerStateParam.cpp"), Object(NonMatching, "Game/Enemy/WalkerStateRunaway.cpp"), - Object(NonMatching, "Game/Enemy/WalkerStateStagger.cpp"), - Object(NonMatching, "Game/Enemy/WalkerStateWander.cpp"), + Object(Matching, "Game/Enemy/WalkerStateStagger.cpp"), + Object(Matching, "Game/Enemy/WalkerStateWander.cpp"), Object(NonMatching, "Game/Enemy/WaterBazooka.cpp"), Object(Matching, "Game/Enemy/WaterBazookaCapsule.cpp"), ], diff --git a/include/Game/Enemy/WalkerStateStagger.hpp b/include/Game/Enemy/WalkerStateStagger.hpp index 5461da4bc..215cde020 100644 --- a/include/Game/Enemy/WalkerStateStagger.hpp +++ b/include/Game/Enemy/WalkerStateStagger.hpp @@ -1,8 +1,7 @@ #pragma once -#include "Game/LiveActor/HitSensor.hpp" +#include "Game/LiveActor/ActorStateBase.hpp" #include "Game/LiveActor/LiveActor.hpp" -#include "Game/System/NerveExecutor.hpp" class WalkerStateParam; class WalkerStateStaggerParam; @@ -11,40 +10,39 @@ class WalkerStateStaggerParam { public: WalkerStateStaggerParam(); - f32 _0; - f32 _4; - f32 _8; - u32 _C; - u32 _10; - u32 _14; - u32 _18; - u32 _1C; - f32 _20; - f32 _24; - f32 _28; - f32 _2C; + /* 0x00 */ f32 mPunchPowerH; + /* 0x04 */ f32 mPunchPowerV; + /* 0x08 */ f32 mPunchPowerSideH; + /* 0x0C */ s32 mStopSceneFrames; + /* 0x10 */ s32 mKickEnableStep; + /* 0x14 */ s32 mStaggerTime; + /* 0x18 */ s32 mRotateStartTime; + /* 0x1C */ s32 mRotateEndTime; + /* 0x20 */ f32 mStaggerFrontPower; + /* 0x24 */ f32 mStaggerSidePower; + /* 0x28 */ f32 mStaggerSideCircleRateDegree; + /* 0x2C */ f32 mRotateRateDegree; }; class WalkerStateStagger : public ActorStateBase< LiveActor > { public: - WalkerStateStagger(LiveActor*, TVec3f*, WalkerStateParam*, WalkerStateStaggerParam*); + WalkerStateStagger(LiveActor* pHost, TVec3f* pDirection, WalkerStateParam* pStateParam, WalkerStateStaggerParam* pStaggerParam); - virtual ~WalkerStateStagger(); virtual void appear(); - void setPunchDirection(HitSensor*, HitSensor*); + void setPunchDirection(HitSensor* pSender, HitSensor* pReceiver); void exeStagger(); void exeStaggerEnd(); void reboundWall(); bool isEnableKick() const; bool isUpsideDown() const; bool isStaggerStart() const; - bool isSwooning(s32) const; - bool isSpinning(s32, s32) const; + bool isSwooning(s32 swoonStep) const; + bool isSpinning(s32 spinStartStep, s32 spinEndStep) const; bool isRecoverStart() const; - WalkerStateParam* mStateParam; // 0x10 - WalkerStateStaggerParam* mStaggerParam; // 0x14 - TVec3f _18; - TVec3f* _24; + /* 0x10 */ WalkerStateParam* mStateParam; + /* 0x14 */ WalkerStateStaggerParam* mStaggerParam; + /* 0x18 */ TVec3f mVelH; + /* 0x24 */ TVec3f* mDirection; }; diff --git a/libs/JSystem/include/JSystem/JMath/JMATrigonometric.hpp b/libs/JSystem/include/JSystem/JMath/JMATrigonometric.hpp index 29bb156ce..5abdc17d9 100644 --- a/libs/JSystem/include/JSystem/JMath/JMATrigonometric.hpp +++ b/libs/JSystem/include/JSystem/JMath/JMATrigonometric.hpp @@ -22,10 +22,18 @@ namespace JMath { template <> struct TAngleConstant_< f32 > { - static f32 RADIAN_DEG090() { return 1.5707964f; } - static f32 RADIAN_DEG180() { return 3.1415927f; } - static f32 RADIAN_DEG360() { return 6.2831855f; } - static f32 RADIAN_TO_DEGREE_FACTOR() { return 180.0f / RADIAN_DEG180(); } + static f32 RADIAN_DEG090() { + return 1.5707964f; + } + static f32 RADIAN_DEG180() { + return 3.1415927f; + } + static f32 RADIAN_DEG360() { + return 6.2831855f; + } + static f32 RADIAN_TO_DEGREE_FACTOR() { + return 180.0f / RADIAN_DEG180(); + } }; template < int Bits, typename T > @@ -34,8 +42,12 @@ namespace JMath { static const u32 LEN = 1 << Bits; std::pair< T, T > table[LEN]; - T sinShort(s16 v) const { return table[static_cast< u16 >(v) >> (16U - Bits)].a1; } - T cosShort(s16 v) const { return table[static_cast< u16 >(v) >> (16U - Bits)].b1; } + T sinShort(s16 v) const { + return table[static_cast< u16 >(v) >> (16U - Bits)].a1; + } + T cosShort(s16 v) const { + return table[static_cast< u16 >(v) >> (16U - Bits)].b1; + } inline f32 sinLapRad(f32 v) { if (v < 0.0f) { @@ -47,6 +59,16 @@ namespace JMath { } } + inline f32 sinLap(f32 v) { + if (v < 0.0f) { + f32 tmp = v * -45.511112f; + return -table[(u16)tmp & LEN - 1].a1; + } else { + f32 tmp = v * 45.511112f; + return table[(u16)tmp & LEN - 1].a1; + } + } + inline f32 cosLapRad(f32 v) { if (v < 0.0f) { v = -v; @@ -67,7 +89,9 @@ namespace JMath { return table[(u16)v & LEN - 1].b1; } - inline f32 get(f32 v) { return table[(u16)v & LEN - 1].b1; } + inline f32 get(f32 v) { + return table[(u16)v & LEN - 1].b1; + } }; template < s32 Len, typename T > @@ -101,7 +125,9 @@ namespace JMath { } } - T acosDegree(T x) const { return acos_(x) * TAngleConstant_< T >::RADIAN_TO_DEGREE_FACTOR(); } + T acosDegree(T x) const { + return acos_(x) * TAngleConstant_< T >::RADIAN_TO_DEGREE_FACTOR(); + } T mTable[Len]; T _1000; @@ -111,7 +137,9 @@ namespace JMath { extern TAtanTable< 1024, f32 > sAtanTable; extern TAsinAcosTable< 1024, f32 > sAsinAcosTable; - inline f32 acosDegree(f32 x) { return sAsinAcosTable.acosDegree(x); } + inline f32 acosDegree(f32 x) { + return sAsinAcosTable.acosDegree(x); + } }; // namespace JMath // inline f32 JMASSin(u16 s) { diff --git a/src/Game/Enemy/WalkerStateStagger.cpp b/src/Game/Enemy/WalkerStateStagger.cpp new file mode 100644 index 000000000..748e74cf3 --- /dev/null +++ b/src/Game/Enemy/WalkerStateStagger.cpp @@ -0,0 +1,140 @@ +#include "Game/Enemy/WalkerStateStagger.hpp" +#include "Game/Enemy/WalkerStateFunction.hpp" + +namespace { + WalkerStateStaggerParam sDefaultStaggerParam; +} + +namespace NrvWalkerStateStagger { + NEW_NERVE(WalkerStateStaggerNrvStagger, WalkerStateStagger, Stagger); + NEW_NERVE(WalkerStateStaggerNrvStaggerEnd, WalkerStateStagger, StaggerEnd); +} // namespace NrvWalkerStateStagger + +WalkerStateStaggerParam::WalkerStateStaggerParam() + : mPunchPowerH(10.0f), mPunchPowerV(10.0f), mPunchPowerSideH(10.0f), mStopSceneFrames(4), mKickEnableStep(15), mStaggerTime(180), + mRotateStartTime(60), mRotateEndTime(120), mStaggerFrontPower(0.35f), mStaggerSidePower(0.5f), mStaggerSideCircleRateDegree(3.0f), + mRotateRateDegree(40.0f) { +} + +WalkerStateStagger::WalkerStateStagger(LiveActor* pHost, TVec3f* pDirection, WalkerStateParam* pStateParam, WalkerStateStaggerParam* pStaggerParam) + : ActorStateBase< LiveActor >("歩行型よろめき状態", pHost), mStateParam(pStateParam), mStaggerParam(pStaggerParam), mVelH(0.0f, 0.0f, 1.0f), + mDirection(pDirection) { + if (mStaggerParam == nullptr) { + mStaggerParam = &sDefaultStaggerParam; + } + + initNerve(&NrvWalkerStateStagger::WalkerStateStaggerNrvStagger::sInstance); +} + +void WalkerStateStagger::appear() { + mIsDead = false; + setNerve(&NrvWalkerStateStagger::WalkerStateStaggerNrvStagger::sInstance); +} + +void WalkerStateStagger::setPunchDirection(HitSensor* pSender, HitSensor* pReceiver) { + MR::calcSensorHorizonNormalize(&mVelH, getHost()->mGravity, pSender, pReceiver); + MR::deleteEffectAll(getHost()); + MR::setVelocitySeparateHV(getHost(), pSender, pReceiver, mStaggerParam->mPunchPowerH, mStaggerParam->mPunchPowerV); + MR::addVelocityClockwiseToTarget(getHost(), MR::getSensorPos(pSender), mStaggerParam->mPunchPowerSideH); +} + +void WalkerStateStagger::exeStagger() { + if (MR::isFirstStep(this)) { + MR::startAction(getHost(), "StaggerStart"); + MR::stopScene(mStaggerParam->mStopSceneFrames); + } + + if (MR::isBckOneTimeAndStopped(getHost())) { + MR::startAction(getHost(), "Stagger"); + } + + TVec3f dir; + dir.rejection(mVelH, getHost()->mGravity); + + if (!MR::isNearZero(dir)) { + MR::normalize(dir, &mVelH); + } + + f32 t = MR::calcNerveEaseInOutValue(this, mStaggerParam->mRotateStartTime, mStaggerParam->mRotateEndTime, 1.0f, 0.0f); + MR::rotateDirectionGravityDegree(getHost(), mDirection, mStaggerParam->mRotateRateDegree * t); + + f32 angle = MR::repeatDegree(mStaggerParam->mStaggerSideCircleRateDegree * getNerveStep()); + f32 s = JMath::sSinCosTable.sinLap(angle); + + MR::addVelocityClockwiseToDirection(getHost(), mVelH, t * (mStaggerParam->mStaggerSidePower * s)); + MR::addVelocityMoveToDirection(getHost(), mVelH, mStaggerParam->mStaggerFrontPower * t); + WalkerStateFunction::calcPassiveMovement(getHost(), mStateParam); + + reboundWall(); + + if (MR::isGreaterStep(this, mStaggerParam->mStaggerTime)) { + setNerve(&NrvWalkerStateStagger::WalkerStateStaggerNrvStaggerEnd::sInstance); + } +} + +void WalkerStateStagger::exeStaggerEnd() { + if (MR::isFirstStep(this)) { + MR::startAction(getHost(), "StaggerEnd"); + } + + WalkerStateFunction::calcPassiveMovement(getHost(), mStateParam); + + if (MR::isBckStopped(getHost())) { + kill(); + } +} + +void WalkerStateStagger::reboundWall() { + if (!MR::isBindedWall(getHost())) { + return; + } + + if (MR::calcReboundVelocity(&getHost()->mVelocity, *MR::getWallNormal(getHost()), 0.9f)) { + TVec3f velH; + velH.rejection(getHost()->mVelocity, getHost()->mGravity); + if (!MR::normalizeOrZero(&velH)) { + mVelH.set(velH); + } + } +} + +bool WalkerStateStagger::isEnableKick() const { + if (mIsDead) { + return false; + } + + if (isNerve(&NrvWalkerStateStagger::WalkerStateStaggerNrvStagger::sInstance) && MR::isLessStep(this, mStaggerParam->mKickEnableStep)) { + return false; + } + + return true; +} + +bool WalkerStateStagger::isUpsideDown() const { + if (mIsDead) { + return false; + } + + if (isNerve(&NrvWalkerStateStagger::WalkerStateStaggerNrvStaggerEnd::sInstance) && MR::isGreaterStep(this, 15)) { + return false; + } + + return true; +} + +bool WalkerStateStagger::isStaggerStart() const { + return isNerve(&NrvWalkerStateStagger::WalkerStateStaggerNrvStagger::sInstance) && MR::isStep(this, 1); +} + +bool WalkerStateStagger::isSwooning(s32 swoonStep) const { + return isNerve(&NrvWalkerStateStagger::WalkerStateStaggerNrvStagger::sInstance) && MR::isGreaterEqualStep(this, swoonStep); +} + +bool WalkerStateStagger::isSpinning(s32 spinStartStep, s32 spinEndStep) const { + return isNerve(&NrvWalkerStateStagger::WalkerStateStaggerNrvStagger::sInstance) && MR::isGreaterEqualStep(this, spinStartStep) && + MR::isLessEqualStep(this, spinEndStep); +} + +bool WalkerStateStagger::isRecoverStart() const { + return isNerve(&NrvWalkerStateStagger::WalkerStateStaggerNrvStaggerEnd::sInstance) && MR::isFirstStep(this); +} From 8ee9a316c6fea2778e806423bc1a058b99c40f00 Mon Sep 17 00:00:00 2001 From: MrL314 <11429905+MrL314@users.noreply.github.com> Date: Thu, 19 Feb 2026 19:48:10 -0500 Subject: [PATCH 28/52] Match `WalkerStateRunaway`, cleanup WalkerStates --- configure.py | 2 +- .../Game/Enemy/WalkerStateBindStarPointer.hpp | 2 +- include/Game/Enemy/WalkerStateBlowDamage.hpp | 4 +- include/Game/Enemy/WalkerStateChase.hpp | 20 +- include/Game/Enemy/WalkerStateFindPlayer.hpp | 2 +- include/Game/Enemy/WalkerStateFunction.hpp | 9 +- include/Game/Enemy/WalkerStateParam.hpp | 12 +- include/Game/Enemy/WalkerStateRunaway.hpp | 70 ++++--- include/Game/Enemy/WalkerStateWander.hpp | 6 +- .../include/JSystem/JGeometry/TVec.hpp | 6 + src/Game/Enemy/Kuribo.cpp | 18 +- src/Game/Enemy/WalkerStateBindStarPointer.cpp | 30 ++- src/Game/Enemy/WalkerStateBlowDamage.cpp | 6 +- src/Game/Enemy/WalkerStateChase.cpp | 52 ++--- src/Game/Enemy/WalkerStateFindPlayer.cpp | 7 +- src/Game/Enemy/WalkerStateFunction.cpp | 13 +- src/Game/Enemy/WalkerStateParam.cpp | 10 +- src/Game/Enemy/WalkerStateRunaway.cpp | 191 +++++++----------- src/Game/Enemy/WalkerStateStagger.cpp | 3 +- src/Game/Enemy/WalkerStateWander.cpp | 10 +- 20 files changed, 200 insertions(+), 273 deletions(-) diff --git a/configure.py b/configure.py index c01b13fe5..2be3ff126 100644 --- a/configure.py +++ b/configure.py @@ -1175,7 +1175,7 @@ def JSys_J3DLib(lib_name: str, objects: List[Object]) -> Dict[str, Any]: Object(Matching, "Game/Enemy/WalkerStateFindPlayer.cpp"), Object(Matching, "Game/Enemy/WalkerStateFunction.cpp"), Object(Matching, "Game/Enemy/WalkerStateParam.cpp"), - Object(NonMatching, "Game/Enemy/WalkerStateRunaway.cpp"), + Object(Matching, "Game/Enemy/WalkerStateRunaway.cpp"), Object(Matching, "Game/Enemy/WalkerStateStagger.cpp"), Object(Matching, "Game/Enemy/WalkerStateWander.cpp"), Object(NonMatching, "Game/Enemy/WaterBazooka.cpp"), diff --git a/include/Game/Enemy/WalkerStateBindStarPointer.hpp b/include/Game/Enemy/WalkerStateBindStarPointer.hpp index d7b7e8951..73aa8a015 100644 --- a/include/Game/Enemy/WalkerStateBindStarPointer.hpp +++ b/include/Game/Enemy/WalkerStateBindStarPointer.hpp @@ -7,7 +7,7 @@ class AnimScaleController; class WalkerStateBindStarPointer : public ActorStateBase< LiveActor > { public: - WalkerStateBindStarPointer(LiveActor*, AnimScaleController*); + WalkerStateBindStarPointer(LiveActor* pHost, AnimScaleController* pController); virtual void appear(); virtual void kill(); diff --git a/include/Game/Enemy/WalkerStateBlowDamage.hpp b/include/Game/Enemy/WalkerStateBlowDamage.hpp index c50894b45..5279369a7 100644 --- a/include/Game/Enemy/WalkerStateBlowDamage.hpp +++ b/include/Game/Enemy/WalkerStateBlowDamage.hpp @@ -2,8 +2,6 @@ #include "Game/LiveActor/ActorStateBase.hpp" #include "Game/LiveActor/LiveActor.hpp" -#include "JSystem/JGeometry/TVec.hpp" -#include "revolution/types.h" class WalkerStateBlowDamageParam { public: @@ -12,7 +10,7 @@ class WalkerStateBlowDamageParam { class WalkerStateBlowDamage : public ActorStateBase< LiveActor > { public: - WalkerStateBlowDamage(LiveActor*, TVec3f*, WalkerStateBlowDamageParam*); + WalkerStateBlowDamage(LiveActor* pHost, TVec3f* pDirection, WalkerStateBlowDamageParam* pBlowDamageParam); virtual void appear(); diff --git a/include/Game/Enemy/WalkerStateChase.hpp b/include/Game/Enemy/WalkerStateChase.hpp index f94025bcb..3fce73daf 100644 --- a/include/Game/Enemy/WalkerStateChase.hpp +++ b/include/Game/Enemy/WalkerStateChase.hpp @@ -2,7 +2,6 @@ #include "Game/LiveActor/ActorStateBase.hpp" #include "Game/LiveActor/LiveActor.hpp" -#include "Game/System/NerveExecutor.hpp" class WalkerStateParam; @@ -10,25 +9,24 @@ class WalkerStateChaseParam { public: WalkerStateChaseParam(); - f32 _0; - u32 _4; - u32 _8; - f32 _C; - u32 _10; + /* 0x00 */ f32 mChaseSpeed; + /* 0x04 */ s32 mChaseTime; + /* 0x08 */ s32 mForceChaseEndTime; + /* 0x0C */ f32 mTurnMaxRateDegree; + /* 0x10 */ s32 mChaseEndWaitTime; }; class WalkerStateChase : public ActorStateBase< LiveActor > { public: - WalkerStateChase(LiveActor*, TVec3f*, WalkerStateParam*, WalkerStateChaseParam*); + WalkerStateChase(LiveActor* pHost, TVec3f* pDirection, WalkerStateParam* pStateParam, WalkerStateChaseParam* pChaseParam); - virtual ~WalkerStateChase(); virtual void appear(); void exeStart(); void exeEnd(); bool isRunning() const; - WalkerStateParam* mStateParam; // 0x10 - WalkerStateChaseParam* mChaseParam; // 0x14 - TVec3f* _18; + /* 0x10 */ WalkerStateParam* mStateParam; + /* 0x14 */ WalkerStateChaseParam* mChaseParam; + /* 0x18 */ TVec3f* mDirection; }; diff --git a/include/Game/Enemy/WalkerStateFindPlayer.hpp b/include/Game/Enemy/WalkerStateFindPlayer.hpp index c6be28221..5522a8eec 100644 --- a/include/Game/Enemy/WalkerStateFindPlayer.hpp +++ b/include/Game/Enemy/WalkerStateFindPlayer.hpp @@ -11,7 +11,7 @@ class WalkerStateFindPlayerParam { /* 0x0 */ u32 mJumpStartStep; /* 0x4 */ f32 mJumpVelocity; - /* 0x8 */ f32 mTurnDegree; + /* 0x8 */ f32 mTurnMaxRateDegree; }; class WalkerStateFindPlayer : public ActorStateBase< LiveActor > { diff --git a/include/Game/Enemy/WalkerStateFunction.hpp b/include/Game/Enemy/WalkerStateFunction.hpp index f2bebce26..8ea0bfc04 100644 --- a/include/Game/Enemy/WalkerStateFunction.hpp +++ b/include/Game/Enemy/WalkerStateFunction.hpp @@ -5,9 +5,8 @@ class LiveActor; class WalkerStateParam; -class WalkerStateFunction { -public: - static bool isInSightPlayer(const LiveActor*, const TVec3f&, const WalkerStateParam*); +namespace WalkerStateFunction { + bool isInSightPlayer(const LiveActor* pActor, const TVec3f& rDirection, const WalkerStateParam* pStateParam); - static void calcPassiveMovement(LiveActor*, const WalkerStateParam*); -}; + void calcPassiveMovement(LiveActor* pActor, const WalkerStateParam* pStateParam); +}; // namespace WalkerStateFunction diff --git a/include/Game/Enemy/WalkerStateParam.hpp b/include/Game/Enemy/WalkerStateParam.hpp index 795c5a114..685040d62 100644 --- a/include/Game/Enemy/WalkerStateParam.hpp +++ b/include/Game/Enemy/WalkerStateParam.hpp @@ -6,10 +6,10 @@ class WalkerStateParam { public: WalkerStateParam(); - f32 _0; - f32 _4; - f32 _8; - f32 _C; - f32 _10; - f32 _14; + /* 0x00 */ f32 mGravityAccel; + /* 0x04 */ f32 mAirFriction; + /* 0x08 */ f32 mGroundFriction; + /* 0x0C */ f32 mPlayerNearDistance; + /* 0x10 */ f32 mPlayerSightFanDegreeH; + /* 0x14 */ f32 mPlayerSightFanDegreeV; }; diff --git a/include/Game/Enemy/WalkerStateRunaway.hpp b/include/Game/Enemy/WalkerStateRunaway.hpp index 29e03255d..d8f9c4866 100644 --- a/include/Game/Enemy/WalkerStateRunaway.hpp +++ b/include/Game/Enemy/WalkerStateRunaway.hpp @@ -2,41 +2,40 @@ #include "Game/LiveActor/ActorStateBase.hpp" #include "Game/LiveActor/LiveActor.hpp" -#include "Game/System/NerveExecutor.hpp" +#include "Game/Util/ActorMovementUtil.hpp" class WalkerStateRunawayParam { public: WalkerStateRunawayParam(); - const char* _0; - const char* _4; - const char* _8; - f32 _C; - f32 _10; - f32 _14; - f32 _18; - s32 _1C; - f32 _20; - f32 _24; - f32 _28; - f32 _2C; - f32 _30; - u32 _34; - f32 _38; - f32 _3C; - f32 _40; - f32 _44; - s32 _48; - f32 _4C; - f32 _50; - f32 _54; + /* 0x00 */ const char* mWaitAction; + /* 0x04 */ const char* mRunawayAction; + /* 0x08 */ const char* mJumpAction; + /* 0x0C */ f32 mGroundAccel; + /* 0x10 */ f32 mAirAccel; + /* 0x14 */ f32 _14; // mGroundFriction? - fric if ._18 <= _1C + /* 0x18 */ f32 _18; // mAirFriction? - fric if ._18 > _1C + /* 0x1C */ s32 _1C; // step? + /* 0x20 */ f32 mTurnMaxRateDegree; + /* 0x24 */ f32 mRunawayDistance; + /* 0x28 */ f32 mWaitDistance; + /* 0x2C */ f32 mRunawayTurnRateMaxDegree; + /* 0x30 */ f32 mRunawayTurnRateMinDegree; + /* 0x34 */ s32 mRunawayTurnTime; + /* 0x38 */ f32 mPlayerFrontLineLength; + /* 0x3C */ f32 mRunawayBckRatio; + /* 0x40 */ f32 mMinRunawayBckRate; + /* 0x44 */ f32 mMaxRunawayBckRate; + /* 0x48 */ s32 mWallJumpTime; + /* 0x4C */ f32 mWallReboundPower; + /* 0x50 */ f32 mWallJumpPowerH; + /* 0x54 */ f32 mWallJumpPowerV; }; class WalkerStateRunaway : public ActorStateBase< LiveActor > { public: - WalkerStateRunaway(LiveActor* pActor, TVec3f* a2, WalkerStateRunawayParam* pParam); + WalkerStateRunaway(LiveActor* pHost, TVec3f* pDirection, WalkerStateRunawayParam* pRunawayParam); - virtual ~WalkerStateRunaway(); virtual void appear(); bool tryRunaway(); @@ -47,8 +46,21 @@ class WalkerStateRunaway : public ActorStateBase< LiveActor > { void exeWallJump(); bool isRunning() const; - WalkerStateRunawayParam* mParam; // 0x10 - TVec3f* _14; - s32 _18; - f32 _1C; + bool isInWaitRange(f32 range) const { + return !MR::isNearPlayer(getHost(), range); + } + + WalkerStateRunawayParam* getParam() const { + return mRunawayParam; + } + + // TODO: what are these values? + bool check18() const { + return _18 < mRunawayParam->_1C; + } + + /* 0x10 */ WalkerStateRunawayParam* mRunawayParam; + /* 0x14 */ TVec3f* mDirection; + /* 0x18 */ s32 _18; + /* 0x1C */ f32 mRunawaySpeed; }; diff --git a/include/Game/Enemy/WalkerStateWander.hpp b/include/Game/Enemy/WalkerStateWander.hpp index 9d5a4e806..845cb9cde 100644 --- a/include/Game/Enemy/WalkerStateWander.hpp +++ b/include/Game/Enemy/WalkerStateWander.hpp @@ -13,17 +13,17 @@ class WalkerStateWanderParam { /* 0x00 */ s32 mWaitTime; /* 0x04 */ s32 mWalkTime; /* 0x08 */ f32 mSpeed; - /* 0x0C */ f32 mTurnDegree; + /* 0x0C */ f32 mTurnMaxRateDegree; /* 0x10 */ f32 mTargetDistance; }; class WalkerStateWander : public ActorStateBase< LiveActor > { public: - WalkerStateWander(LiveActor*, TVec3f*, WalkerStateParam*, WalkerStateWanderParam*); + WalkerStateWander(LiveActor* pHost, TVec3f* pDirection, WalkerStateParam* pStateParam, WalkerStateWanderParam* pWanderParam); virtual void appear(); - void setWanderCenter(const TVec3f&); + void setWanderCenter(const TVec3f& rCenter); void exeWait(); void exeWalk(); diff --git a/libs/JSystem/include/JSystem/JGeometry/TVec.hpp b/libs/JSystem/include/JSystem/JGeometry/TVec.hpp index 1469760da..c8661913a 100644 --- a/libs/JSystem/include/JSystem/JGeometry/TVec.hpp +++ b/libs/JSystem/include/JSystem/JGeometry/TVec.hpp @@ -300,6 +300,12 @@ namespace JGeometry { JMathInlineVEC::PSVECAdd(this, &op, this); } + inline TVec3 addOtherInline(const TVec3& op) const { + TVec3 ret; + JMathInlineVEC::PSVECAdd(this, &op, &ret); + return ret; + } + TVec3 operator*(f32 scalar) const NO_INLINE { TVec3 ret(*this); ret.x *= scalar; diff --git a/src/Game/Enemy/Kuribo.cpp b/src/Game/Enemy/Kuribo.cpp index 11525286c..ddafb5396 100644 --- a/src/Game/Enemy/Kuribo.cpp +++ b/src/Game/Enemy/Kuribo.cpp @@ -31,18 +31,18 @@ namespace { }; KuriboParam::KuriboParam() { - mStateParam._0 = 1.5f; - mStateParam._4 = 0.99f; - mStateParam._8 = 0.93f; - mStateParam._C = 1000.0f; - mStateParam._10 = 70.0f; - mStateParam._14 = 30.0f; + mStateParam.mGravityAccel = 1.5f; + mStateParam.mAirFriction = 0.99f; + mStateParam.mGroundFriction = 0.93f; + mStateParam.mPlayerNearDistance = 1000.0f; + mStateParam.mPlayerSightFanDegreeH = 70.0f; + mStateParam.mPlayerSightFanDegreeV = 30.0f; mWanderParam.mSpeed = 0.2f; mWanderParam.mWaitTime = 120; mWanderParam.mWalkTime = 120; - mWanderParam.mTurnDegree = 3.0f; - mChaseParam._0 = 0.4f; - mFindPlayerParam.mTurnDegree = 5.0f; + mWanderParam.mTurnMaxRateDegree = 3.0f; + mChaseParam.mChaseSpeed = 0.4f; + mFindPlayerParam.mTurnMaxRateDegree = 5.0f; mFindPlayerParam.mJumpVelocity = 20.0f; } diff --git a/src/Game/Enemy/WalkerStateBindStarPointer.cpp b/src/Game/Enemy/WalkerStateBindStarPointer.cpp index 94378890f..731e8e2db 100644 --- a/src/Game/Enemy/WalkerStateBindStarPointer.cpp +++ b/src/Game/Enemy/WalkerStateBindStarPointer.cpp @@ -9,13 +9,13 @@ namespace NrvWalkerStateBindStarPointer { NEW_NERVE(WalkerStateBindStarPointerNrvBind, WalkerStateBindStarPointer, Bind); }; -WalkerStateBindStarPointer::WalkerStateBindStarPointer(LiveActor* pActor, AnimScaleController* pController) - : ActorStateBase("歩行型スターポインタ拘束", pActor), mScaleController(pController), mUpdateCounter(0), mHasEffect(false) { +WalkerStateBindStarPointer::WalkerStateBindStarPointer(LiveActor* pHost, AnimScaleController* pController) + : ActorStateBase("歩行型スターポインタ拘束", pHost), mScaleController(pController), mUpdateCounter(0), mHasEffect(false) { initNerve(&NrvWalkerStateBindStarPointer::WalkerStateBindStarPointerNrvBind::sInstance); - if (!MR::isRegisteredEffect(pActor, "Touch")) { + if (!MR::isRegisteredEffect(pHost, "Touch")) { mHasEffect = true; - MR::addEffect(pActor, "PointerTouch"); + MR::addEffect(pHost, "PointerTouch"); } } @@ -30,25 +30,23 @@ void WalkerStateBindStarPointer::kill() { mScaleController->startAnim(); } - const char* effectName = mHasEffect ? "PointerTouch" : "Touch"; - MR::deleteEffect(mHost, effectName); - if (MR::isExistBck(mHost, nullptr)) { - MR::setBckRate(mHost, 1.0f); + MR::deleteEffect(getHost(), mHasEffect ? "PointerTouch" : "Touch"); + if (MR::isExistBck(getHost(), nullptr)) { + MR::setBckRate(getHost(), 1.0f); } } bool WalkerStateBindStarPointer::tryStartPointBind() const { - return MR::isStarPointerPointing2POnPressButton(mHost, "弱", true, false); + return MR::isStarPointerPointing2POnPressButton(getHost(), "弱", true, false); } void WalkerStateBindStarPointer::exeBind() { if (MR::isFirstStep(this)) { MR::startDPDHitSound(); mUpdateCounter = 0; - const char* effectName = mHasEffect ? "PointerTouch" : "Touch"; - MR::emitEffect(mHost, effectName); - if (MR::isExistBck(mHost, nullptr)) { - MR::setBckRate(mHost, 0.0f); + MR::emitEffect(getHost(), mHasEffect ? "PointerTouch" : "Touch"); + if (MR::isExistBck(getHost(), nullptr)) { + MR::setBckRate(getHost(), 0.0f); } if (mScaleController != nullptr) { @@ -56,9 +54,9 @@ void WalkerStateBindStarPointer::exeBind() { } } - MR::startDPDFreezeLevelSound(mHost); - MR::zeroVelocity(mHost); - if (MR::isStarPointerPointing2POnPressButton(mHost, "弱", true, false)) { + MR::startDPDFreezeLevelSound(getHost()); + MR::zeroVelocity(getHost()); + if (MR::isStarPointerPointing2POnPressButton(getHost(), "弱", true, false)) { mUpdateCounter = 0; } else { mUpdateCounter++; diff --git a/src/Game/Enemy/WalkerStateBlowDamage.cpp b/src/Game/Enemy/WalkerStateBlowDamage.cpp index 7e8906da9..5f081a048 100644 --- a/src/Game/Enemy/WalkerStateBlowDamage.cpp +++ b/src/Game/Enemy/WalkerStateBlowDamage.cpp @@ -1,6 +1,4 @@ #include "Game/Enemy/WalkerStateBlowDamage.hpp" -#include "Game/Util/ActorMovementUtil.hpp" -#include "Game/Util/LiveActorUtil.hpp" namespace { static const f32 sAirFric = 0.99f; @@ -14,8 +12,8 @@ namespace NrvWalkerStateBlowDamage { NEW_NERVE(WalkerStateBlowDamageNrvBlowLand, WalkerStateBlowDamage, BlowLand); } // namespace NrvWalkerStateBlowDamage -WalkerStateBlowDamage::WalkerStateBlowDamage(LiveActor* pActor, TVec3f* pDirection, WalkerStateBlowDamageParam* pBlowDamageParam) - : ActorStateBase< LiveActor >("吹き飛びダメージ状態", pActor), mDirection(pDirection), mBlowDamageParam(pBlowDamageParam) { +WalkerStateBlowDamage::WalkerStateBlowDamage(LiveActor* pHost, TVec3f* pDirection, WalkerStateBlowDamageParam* pBlowDamageParam) + : ActorStateBase< LiveActor >("吹き飛びダメージ状態", pHost), mDirection(pDirection), mBlowDamageParam(pBlowDamageParam) { initNerve(&NrvWalkerStateBlowDamage::WalkerStateBlowDamageNrvBlow::sInstance); } diff --git a/src/Game/Enemy/WalkerStateChase.cpp b/src/Game/Enemy/WalkerStateChase.cpp index aae14b620..3af126c58 100644 --- a/src/Game/Enemy/WalkerStateChase.cpp +++ b/src/Game/Enemy/WalkerStateChase.cpp @@ -1,13 +1,6 @@ #include "Game/Enemy/WalkerStateChase.hpp" #include "Game/Enemy/WalkerStateFunction.hpp" -WalkerStateChaseParam::WalkerStateChaseParam() { - _4 = 130; - _8 = 300; - _C = 2.0f; - _10 = 30; -} - namespace { WalkerStateChaseParam sDefaultParam; }; @@ -17,13 +10,12 @@ namespace NrvWalkerStateChase { NEW_NERVE(WalkerStateChaseNrvEnd, WalkerStateChase, End); }; // namespace NrvWalkerStateChase -WalkerStateChase::WalkerStateChase(LiveActor* pActor, TVec3f* pVec, WalkerStateParam* pParam, WalkerStateChaseParam* pChaseParam) - : ActorStateBase< LiveActor >("クリボー追いかけ状態", pActor) { - mStateParam = pParam; - mChaseParam = pChaseParam; - _18 = pVec; +WalkerStateChaseParam::WalkerStateChaseParam() : mChaseTime(130), mForceChaseEndTime(300), mTurnMaxRateDegree(2.0f), mChaseEndWaitTime(30) { +} - if (pChaseParam == nullptr) { +WalkerStateChase::WalkerStateChase(LiveActor* pHost, TVec3f* pDirection, WalkerStateParam* pStateParam, WalkerStateChaseParam* pChaseParam) + : ActorStateBase< LiveActor >("クリボー追いかけ状態", pHost), mStateParam(pStateParam), mChaseParam(pChaseParam), mDirection(pDirection) { + if (mChaseParam == nullptr) { mChaseParam = &sDefaultParam; } @@ -37,46 +29,36 @@ void WalkerStateChase::appear() { void WalkerStateChase::exeStart() { if (MR::isFirstStep(this)) { - MR::startAction(mHost, "Run"); + MR::startAction(getHost(), "Run"); } - bool isInSight = WalkerStateFunction::isInSightPlayer(mHost, *_18, mStateParam); + bool isInSight = WalkerStateFunction::isInSightPlayer(getHost(), *mDirection, mStateParam); if (isInSight) { - LiveActor* parent = mHost; - MR::turnDirectionToTargetUseGroundNormalDegree(parent, _18, *MR::getPlayerPos(), mChaseParam->_C); + MR::turnDirectionToTargetUseGroundNormalDegree(getHost(), mDirection, *MR::getPlayerPos(), mChaseParam->mTurnMaxRateDegree); } - MR::addVelocityMoveToDirection(mHost, *_18, mChaseParam->_0); - WalkerStateFunction::calcPassiveMovement(mHost, mStateParam); + MR::addVelocityMoveToDirection(getHost(), *mDirection, mChaseParam->mChaseSpeed); + WalkerStateFunction::calcPassiveMovement(getHost(), mStateParam); - if (MR::isFallNextMove(mHost, 150.0f, 150.0f, 150.0f, nullptr)) { - MR::zeroVelocity(mHost); + if (MR::isFallNextMove(getHost(), 150.0f, 150.0f, 150.0f, nullptr)) { + MR::zeroVelocity(getHost()); setNerve(&NrvWalkerStateChase::WalkerStateChaseNrvEnd::sInstance); - } else if (MR::isGreaterStep(this, mChaseParam->_8) || (MR::isGreaterStep(this, mChaseParam->_4) && !isInSight)) { + } else if (MR::isGreaterStep(this, mChaseParam->mForceChaseEndTime) || (MR::isGreaterStep(this, mChaseParam->mChaseTime) && !isInSight)) { setNerve(&NrvWalkerStateChase::WalkerStateChaseNrvEnd::sInstance); } } void WalkerStateChase::exeEnd() { if (MR::isFirstStep(this)) { - MR::startAction(mHost, "Wait"); + MR::startAction(getHost(), "Wait"); } - WalkerStateFunction::calcPassiveMovement(mHost, mStateParam); - if (MR::isGreaterStep(this, mChaseParam->_10)) { + WalkerStateFunction::calcPassiveMovement(getHost(), mStateParam); + if (MR::isGreaterStep(this, mChaseParam->mChaseEndWaitTime)) { kill(); } } bool WalkerStateChase::isRunning() const { - bool isRunning = false; - if (isNerve(&NrvWalkerStateChase::WalkerStateChaseNrvStart::sInstance)) { - if (MR::isBindedGround(mHost)) { - isRunning = true; - } - } - - return isRunning; + return isNerve(&NrvWalkerStateChase::WalkerStateChaseNrvStart::sInstance) && MR::isBindedGround(getHost()); } - -WalkerStateChase::~WalkerStateChase() {} diff --git a/src/Game/Enemy/WalkerStateFindPlayer.cpp b/src/Game/Enemy/WalkerStateFindPlayer.cpp index ef41f5967..468a21585 100644 --- a/src/Game/Enemy/WalkerStateFindPlayer.cpp +++ b/src/Game/Enemy/WalkerStateFindPlayer.cpp @@ -1,8 +1,5 @@ #include "Game/Enemy/WalkerStateFindPlayer.hpp" #include "Game/Enemy/WalkerStateFunction.hpp" -#include "Game/Util/ActorMovementUtil.hpp" -#include "Game/Util/LiveActorUtil.hpp" -#include "Game/Util/NerveUtil.hpp" namespace { WalkerStateFindPlayerParam sDefaultParam; @@ -15,7 +12,7 @@ namespace NrvWalkerStateFindPlayer { NEW_NERVE(WalkerStateFindPlayerNrvFindJumpEnd, WalkerStateFindPlayer, FindJumpEnd); } // namespace NrvWalkerStateFindPlayer -WalkerStateFindPlayerParam::WalkerStateFindPlayerParam() : mJumpStartStep(30), mJumpVelocity(20.0f), mTurnDegree(5.0f) { +WalkerStateFindPlayerParam::WalkerStateFindPlayerParam() : mJumpStartStep(30), mJumpVelocity(20.0f), mTurnMaxRateDegree(5.0f) { } WalkerStateFindPlayer::WalkerStateFindPlayer(LiveActor* pHost, TVec3f* pDirection, WalkerStateParam* pStateParam, @@ -39,7 +36,7 @@ void WalkerStateFindPlayer::exeFind() { } WalkerStateFunction::calcPassiveMovement(getHost(), mStateParam); - MR::turnDirectionToTargetUseGroundNormalDegree(getHost(), mDirection, *MR::getPlayerPos(), mFindPlayerParam->mTurnDegree); + MR::turnDirectionToTargetUseGroundNormalDegree(getHost(), mDirection, *MR::getPlayerPos(), mFindPlayerParam->mTurnMaxRateDegree); if (MR::isStep(this, mFindPlayerParam->mJumpStartStep)) { setNerve(&NrvWalkerStateFindPlayer::WalkerStateFindPlayerNrvFindJumpStart::sInstance); diff --git a/src/Game/Enemy/WalkerStateFunction.cpp b/src/Game/Enemy/WalkerStateFunction.cpp index a9b5b7dfe..4f9ba46ea 100644 --- a/src/Game/Enemy/WalkerStateFunction.cpp +++ b/src/Game/Enemy/WalkerStateFunction.cpp @@ -3,16 +3,17 @@ #include "Game/Util/ActorMovementUtil.hpp" #include "Game/Util/LiveActorUtil.hpp" -bool WalkerStateFunction::isInSightPlayer(const LiveActor* pActor, const TVec3f& pTVec3f, const WalkerStateParam* pParam) { - return MR::isInSightFanPlayer(pActor, pTVec3f, pParam->_C, pParam->_10, pParam->_14); +bool WalkerStateFunction::isInSightPlayer(const LiveActor* pActor, const TVec3f& rDirection, const WalkerStateParam* pStateParam) { + return MR::isInSightFanPlayer(pActor, rDirection, pStateParam->mPlayerNearDistance, pStateParam->mPlayerSightFanDegreeH, + pStateParam->mPlayerSightFanDegreeV); } -void WalkerStateFunction::calcPassiveMovement(LiveActor* pActor, const WalkerStateParam* pParam) { +void WalkerStateFunction::calcPassiveMovement(LiveActor* pActor, const WalkerStateParam* pStateParam) { MR::reboundVelocityFromEachCollision(pActor, -1.0f, -1.0f, 0.0f, 0.0f); if (!MR::isOnGround(pActor)) { - MR::addVelocityToGravity(pActor, pParam->_0); - MR::attenuateVelocity(pActor, pParam->_4); + MR::addVelocityToGravity(pActor, pStateParam->mGravityAccel); + MR::attenuateVelocity(pActor, pStateParam->mAirFriction); } else { - MR::attenuateVelocity(pActor, pParam->_8); + MR::attenuateVelocity(pActor, pStateParam->mGroundFriction); } } diff --git a/src/Game/Enemy/WalkerStateParam.cpp b/src/Game/Enemy/WalkerStateParam.cpp index 3ef5f69b2..6676aaf90 100644 --- a/src/Game/Enemy/WalkerStateParam.cpp +++ b/src/Game/Enemy/WalkerStateParam.cpp @@ -1,10 +1,6 @@ #include "Game/Enemy/WalkerStateParam.hpp" -WalkerStateParam::WalkerStateParam() { - _0 = 1.0f; - _4 = 0.99f; - _8 = 0.93f; - _C = 1000.0f; - _10 = 80.0f; - _14 = 40.0f; +WalkerStateParam::WalkerStateParam() + : mGravityAccel(1.0f), mAirFriction(0.99f), mGroundFriction(0.93f), mPlayerNearDistance(1000.0f), mPlayerSightFanDegreeH(80.0f), + mPlayerSightFanDegreeV(40.0f) { } diff --git a/src/Game/Enemy/WalkerStateRunaway.cpp b/src/Game/Enemy/WalkerStateRunaway.cpp index 0f8884748..1ab36a07f 100644 --- a/src/Game/Enemy/WalkerStateRunaway.cpp +++ b/src/Game/Enemy/WalkerStateRunaway.cpp @@ -1,8 +1,15 @@ #include "Game/Enemy/WalkerStateRunaway.hpp" -#include "Game/Util/ActorMovementUtil.hpp" -#include "Game/Util/LiveActorUtil.hpp" -#include "Game/Util/MathUtil.hpp" -#include "Game/Util/PlayerUtil.hpp" + +// TODO: replace this call with MR::clamp +inline f32 clamp(f32 x, f32 min, f32 max) { + if (x < min) { + return min; + } else if (x > max) { + return max; + } else { + return x; + } +} namespace { static WalkerStateRunawayParam sDefaultParam; @@ -15,39 +22,34 @@ namespace NrvWalkerStateRunaway { }; // namespace NrvWalkerStateRunaway WalkerStateRunawayParam::WalkerStateRunawayParam() { - _0 = "FollowMe"; - _4 = "Run"; - _8 = "Jump"; - _C = 0.050000001f; - _10 = 1.0f; - _14 = 0.89999998f; - _18 = 0.99000001f; + mWaitAction = "FollowMe"; + mRunawayAction = "Run"; + mJumpAction = "Jump"; + mGroundAccel = 0.05f; + mAirAccel = 1.0f; + _14 = 0.9f; + _18 = 0.99f; _1C = 5; - _20 = 3.0f; - _24 = 1100.0f; - _28 = 1300.0f; - _2C = 10.0f; - _30 = 3.0f; - _34 = 30; - _38 = 25.0f; - _3C = 1.0f; - _40 = 0.89999998f; - _44 = 1.4f; - _48 = 6; - _4C = 0.30000001f; - _50 = 8.0f; - _54 = 15.0f; + mTurnMaxRateDegree = 3.0f; + mRunawayDistance = 1100.0f; + mWaitDistance = 1300.0f; + mRunawayTurnRateMaxDegree = 10.0f; + mRunawayTurnRateMinDegree = 3.0f; + mRunawayTurnTime = 30; + mPlayerFrontLineLength = 25.0f; + mRunawayBckRatio = 1.0f; + mMinRunawayBckRate = 0.9f; + mMaxRunawayBckRate = 1.4f; + mWallJumpTime = 6; + mWallReboundPower = 0.3f; + mWallJumpPowerH = 8.0f; + mWallJumpPowerV = 15.0f; } -WalkerStateRunaway::WalkerStateRunaway(LiveActor* pActor, TVec3f* a2, WalkerStateRunawayParam* pParam) - : ActorStateBase< LiveActor >("歩行型アクター逃げ", pActor) { - mParam = pParam; - _14 = a2; - _18 = 0; - _1C = 1.0f; - - if (pParam == nullptr) { - mParam = &sDefaultParam; +WalkerStateRunaway::WalkerStateRunaway(LiveActor* pHost, TVec3f* pDirection, WalkerStateRunawayParam* pRunawayParam) + : ActorStateBase< LiveActor >("歩行型アクター逃げ", pHost), mRunawayParam(pRunawayParam), mDirection(pDirection), _18(0), mRunawaySpeed(1.0f) { + if (mRunawayParam == nullptr) { + mRunawayParam = &sDefaultParam; } initNerve(&NrvWalkerStateRunaway::WalkerStateRunawayNrvWait::sInstance); @@ -60,7 +62,7 @@ void WalkerStateRunaway::appear() { } bool WalkerStateRunaway::tryRunaway() { - if (MR::isNearPlayer(mHost, mParam->_24)) { + if (MR::isNearPlayer(getHost(), mRunawayParam->mRunawayDistance)) { setNerve(&NrvWalkerStateRunaway::WalkerStateRunawayNrvRunaway::sInstance); return true; } @@ -69,8 +71,7 @@ bool WalkerStateRunaway::tryRunaway() { } bool WalkerStateRunaway::tryWait() { - bool isNear = !MR::isNearPlayer(mHost, mParam->_28); - if (isNear) { + if (isInWaitRange(mRunawayParam->mWaitDistance)) { setNerve(&NrvWalkerStateRunaway::WalkerStateRunawayNrvWait::sInstance); return true; } @@ -79,28 +80,20 @@ bool WalkerStateRunaway::tryWait() { } bool WalkerStateRunaway::tryWallJump() { - if (MR::isBindedWall(mHost) && MR::calcHitPowerToWall(mHost) > 0.0f) { + if (MR::isBindedWall(getHost()) && MR::calcHitPowerToWall(getHost()) > 0.0f) { TVec3f horiz; - MR::calcVecFromPlayerH(&horiz, mHost); + MR::calcVecFromPlayerH(&horiz, getHost()); TVec3f wallNorml; - MR::calcWallNormalHorizontal(&wallNorml, mHost); + MR::calcWallNormalHorizontal(&wallNorml, getHost()); - if (MR::isOppositeDirection(horiz, wallNorml, 0.0099999998f)) { - f32 dir; - if (MR::isHalfProbability()) { - dir = mParam->_50; - } else { - dir = -mParam->_50; - } - - MR::addVelocityClockwiseToDirection(mHost, wallNorml, dir); + if (MR::isOppositeDirection(horiz, wallNorml, 0.01f)) { + MR::addVelocityClockwiseToDirection(getHost(), wallNorml, + MR::isHalfProbability() ? mRunawayParam->mWallJumpPowerH : -mRunawayParam->mWallJumpPowerH); } else { - TVec3f dir; - JMathInlineVEC::PSVECAdd(&horiz, &wallNorml, &dir); - MR::addVelocityMoveToDirection(mHost, dir, mParam->_50); + MR::addVelocityMoveToDirection(getHost(), wallNorml.addOtherInline(horiz), mRunawayParam->mWallJumpPowerH); } - MR::addVelocityJump(mHost, mParam->_54); + MR::addVelocityJump(getHost(), mRunawayParam->mWallJumpPowerV); setNerve(&NrvWalkerStateRunaway::WalkerStateRunawayNrvWallJump::sInstance); return true; } @@ -110,28 +103,12 @@ bool WalkerStateRunaway::tryWallJump() { void WalkerStateRunaway::exeWait() { if (MR::isFirstStep(this)) { - MR::startAction(mHost, mParam->_0); - } - - MR::turnDirectionToPlayerDegree(mHost, _14, mParam->_20); - - f32 v1; - if (MR::isBindedGround(mHost)) { - v1 = mParam->_C; - } else { - v1 = mParam->_10; - } - - MR::addVelocityToGravity(mHost, v1); - - f32 v2; - if (_18 < mParam->_1C) { - v2 = mParam->_14; - } else { - v2 = mParam->_18; + MR::startAction(getHost(), mRunawayParam->mWaitAction); } - MR::attenuateVelocity(mHost, v2); + MR::turnDirectionToPlayerDegree(getHost(), mDirection, mRunawayParam->mTurnMaxRateDegree); + MR::addVelocityToGravity(getHost(), MR::isBindedGround(getHost()) ? mRunawayParam->mGroundAccel : mRunawayParam->mAirAccel); + MR::attenuateVelocity(getHost(), check18() ? mRunawayParam->_14 : mRunawayParam->_18); if (tryRunaway()) { return; @@ -140,54 +117,24 @@ void WalkerStateRunaway::exeWait() { void WalkerStateRunaway::exeRunaway() { if (MR::isFirstStep(this)) { - MR::startAction(mHost, mParam->_4); + MR::startAction(getHost(), mRunawayParam->mRunawayAction); } TVec3f v13; - JMAVECScaleAdd(MR::getPlayerVelocity(), MR::getPlayerPos(), &v13, mParam->_38); + JMAVECScaleAdd(MR::getPlayerVelocity(), MR::getPlayerPos(), &v13, mRunawayParam->mPlayerFrontLineLength); TVec3f* actorPos = &mHost->mPosition; MR::calcPerpendicFootToLineInside(&v13, *actorPos, *MR::getPlayerPos(), v13); - MR::turnDirectionFromTargetDegree(mHost, _14, v13, MR::calcNerveValue(mHost, mParam->_34, mParam->_2C, mParam->_30)); - f32 v8 = mParam->_40; - f32 v9 = (_1C / mParam->_3C); - f32 _44 = mParam->_44; - if (v9 < v8) { - v8 = v8; - } else { - if (v9 > _44) { - v8 = _44; - } else { - v8 = (_1C / mParam->_3C); - } - } + MR::turnDirectionFromTargetDegree(mHost, mDirection, v13, + MR::calcNerveValue(mHost, mRunawayParam->mRunawayTurnTime, mRunawayParam->mRunawayTurnRateMaxDegree, + mRunawayParam->mRunawayTurnRateMinDegree)); - MR::setBckRate(mHost, v8); + // TODO: MR::clamp + MR::setBckRate(getHost(), + clamp(mRunawaySpeed / mRunawayParam->mRunawayBckRatio, mRunawayParam->mMinRunawayBckRate, mRunawayParam->mMaxRunawayBckRate)); + MR::addVelocityMoveToDirection(getHost(), *mDirection, check18() ? mRunawaySpeed : 0.0f); + MR::addVelocityToGravity(getHost(), MR::isBindedGround(getHost()) ? mRunawayParam->mGroundAccel : mRunawayParam->mAirAccel); + MR::attenuateVelocity(getHost(), check18() ? mRunawayParam->_14 : mRunawayParam->_18); - f32 v10; - if (_18 < mParam->_1C) { - v10 = _1C; - } else { - v10 = 0.0f; - } - - MR::addVelocityMoveToDirection(mHost, *_14, v10); - f32 v11; - if (MR::isBindedGround(mHost)) { - v11 = mParam->_C; - } else { - v11 = mParam->_10; - } - - MR::addVelocityToGravity(mHost, v11); - - f32 v12; - if (_18 < mParam->_1C) { - v12 = mParam->_14; - } else { - v12 = mParam->_18; - } - - MR::attenuateVelocity(mHost, v12); if (!tryWait()) { if (tryWallJump()) { return; @@ -197,16 +144,16 @@ void WalkerStateRunaway::exeRunaway() { void WalkerStateRunaway::exeWallJump() { if (MR::isFirstStep(this)) { - MR::startAction(mHost, mParam->_8); + MR::startAction(getHost(), mRunawayParam->mJumpAction); } - MR::turnDirectionDegree(mHost, _14, mHost->mVelocity, 45.0f); - MR::addVelocityToGravity(mHost, mParam->_10); - MR::attenuateVelocity(mHost, mParam->_18); - MR::reboundVelocityFromEachCollision(mHost, 0.0f, mParam->_4C, 0.0f, 0.0f); + MR::turnDirectionDegree(getHost(), mDirection, getHost()->mVelocity, 45.0f); + MR::addVelocityToGravity(getHost(), mRunawayParam->mAirAccel); + MR::attenuateVelocity(getHost(), mRunawayParam->_18); + MR::reboundVelocityFromEachCollision(getHost(), 0.0f, mRunawayParam->mWallReboundPower, 0.0f, 0.0f); - if (MR::isGreaterStep(this, mParam->_48)) { - if (MR::isBindedGround(mHost)) { + if (MR::isGreaterStep(this, mRunawayParam->mWallJumpTime)) { + if (MR::isBindedGround(getHost())) { setNerve(&NrvWalkerStateRunaway::WalkerStateRunawayNrvRunaway::sInstance); } } @@ -215,5 +162,3 @@ void WalkerStateRunaway::exeWallJump() { bool WalkerStateRunaway::isRunning() const { return isNerve(&NrvWalkerStateRunaway::WalkerStateRunawayNrvRunaway::sInstance); } - -WalkerStateRunaway::~WalkerStateRunaway() {} diff --git a/src/Game/Enemy/WalkerStateStagger.cpp b/src/Game/Enemy/WalkerStateStagger.cpp index 748e74cf3..c396dee22 100644 --- a/src/Game/Enemy/WalkerStateStagger.cpp +++ b/src/Game/Enemy/WalkerStateStagger.cpp @@ -58,8 +58,7 @@ void WalkerStateStagger::exeStagger() { f32 t = MR::calcNerveEaseInOutValue(this, mStaggerParam->mRotateStartTime, mStaggerParam->mRotateEndTime, 1.0f, 0.0f); MR::rotateDirectionGravityDegree(getHost(), mDirection, mStaggerParam->mRotateRateDegree * t); - f32 angle = MR::repeatDegree(mStaggerParam->mStaggerSideCircleRateDegree * getNerveStep()); - f32 s = JMath::sSinCosTable.sinLap(angle); + f32 s = JMath::sSinCosTable.sinLap(MR::repeatDegree(mStaggerParam->mStaggerSideCircleRateDegree * getNerveStep())); MR::addVelocityClockwiseToDirection(getHost(), mVelH, t * (mStaggerParam->mStaggerSidePower * s)); MR::addVelocityMoveToDirection(getHost(), mVelH, mStaggerParam->mStaggerFrontPower * t); diff --git a/src/Game/Enemy/WalkerStateWander.cpp b/src/Game/Enemy/WalkerStateWander.cpp index 539a2b700..3fa58e8ad 100644 --- a/src/Game/Enemy/WalkerStateWander.cpp +++ b/src/Game/Enemy/WalkerStateWander.cpp @@ -2,8 +2,6 @@ #include "Game/Enemy/TerritoryMover.hpp" #include "Game/Enemy/WalkerStateFunction.hpp" #include "Game/Enemy/WalkerStateParam.hpp" -#include "Game/Util/ActorMovementUtil.hpp" -#include "Game/Util/MapUtil.hpp" namespace { WalkerStateWanderParam sDefaultParam; @@ -14,11 +12,11 @@ namespace NrvWalkerStateWander { NEW_NERVE(WalkerStateWanderNrvWalk, WalkerStateWander, Walk); } // namespace NrvWalkerStateWander -WalkerStateWanderParam::WalkerStateWanderParam() : mWaitTime(120), mWalkTime(120), mSpeed(0.2f), mTurnDegree(3.0f), mTargetDistance(20.0f) { +WalkerStateWanderParam::WalkerStateWanderParam() : mWaitTime(120), mWalkTime(120), mSpeed(0.2f), mTurnMaxRateDegree(3.0f), mTargetDistance(20.0f) { } -WalkerStateWander::WalkerStateWander(LiveActor* pActor, TVec3f* pDirection, WalkerStateParam* pStateParam, WalkerStateWanderParam* pWanderParam) - : ActorStateBase< LiveActor >("クリボー型うろつき状態", pActor), mDirection(pDirection), mTerritoryMover(nullptr), mStateParam(pStateParam), +WalkerStateWander::WalkerStateWander(LiveActor* pHost, TVec3f* pDirection, WalkerStateParam* pStateParam, WalkerStateWanderParam* pWanderParam) + : ActorStateBase< LiveActor >("クリボー型うろつき状態", pHost), mDirection(pDirection), mTerritoryMover(nullptr), mStateParam(pStateParam), mWanderParam(pWanderParam) { initNerve(&NrvWalkerStateWander::WalkerStateWanderNrvWait::sInstance); @@ -57,7 +55,7 @@ void WalkerStateWander::exeWalk() { MR::startAction(getHost(), "Walk"); } - MR::turnDirectionToTargetUseGroundNormalDegree(getHost(), mDirection, mTerritoryMover->_10, mWanderParam->mTurnDegree); + MR::turnDirectionToTargetUseGroundNormalDegree(getHost(), mDirection, mTerritoryMover->_10, mWanderParam->mTurnMaxRateDegree); if (MR::isFaceToTargetHorizontalDegree(getHost(), mTerritoryMover->_10, *mDirection, 8.0f)) { MR::addVelocityMoveToDirection(getHost(), *mDirection, mWanderParam->mSpeed); From 667b671be9813ce759b97c04bf6e7e10a06c65ef Mon Sep 17 00:00:00 2001 From: MrL314 <11429905+MrL314@users.noreply.github.com> Date: Fri, 20 Feb 2026 22:19:54 -0500 Subject: [PATCH 29/52] `LiveActorUtil` header cleanup --- .../Game/Map/CollisionCategorizedKeeper.hpp | 3 +- include/Game/Map/CollisionParts.hpp | 7 - include/Game/MapObj/ClipAreaHolder.hpp | 1 - include/Game/Util/CollisionPartsFilter.hpp | 32 ++ include/Game/Util/FurMulti.hpp | 7 + include/Game/Util/LiveActorUtil.hpp | 521 +++++++++--------- include/Game/Util/ModelUtil.hpp | 7 + include/Game/Util/SoundUtil.hpp | 2 + src/Game/Util/LiveActorUtil.cpp | 34 +- 9 files changed, 316 insertions(+), 298 deletions(-) create mode 100644 include/Game/Util/CollisionPartsFilter.hpp create mode 100644 include/Game/Util/FurMulti.hpp diff --git a/include/Game/Map/CollisionCategorizedKeeper.hpp b/include/Game/Map/CollisionCategorizedKeeper.hpp index bb5170d53..3ac54be16 100644 --- a/include/Game/Map/CollisionCategorizedKeeper.hpp +++ b/include/Game/Map/CollisionCategorizedKeeper.hpp @@ -6,6 +6,7 @@ #include class CollisionZone; +class CollisionPartsFilterBase; class CollisionCategorizedKeeper : public NameObj { public: @@ -59,4 +60,4 @@ class CollisionZone { f32 mRadius; // 0x814 TVec3f _818; TVec3f _824; -}; \ No newline at end of file +}; diff --git a/include/Game/Map/CollisionParts.hpp b/include/Game/Map/CollisionParts.hpp index 089edcb8a..692a80ff9 100644 --- a/include/Game/Map/CollisionParts.hpp +++ b/include/Game/Map/CollisionParts.hpp @@ -68,10 +68,3 @@ class CollisionParts { f32 _EC; f32 _F0; }; - -class CollisionPartsFilterBase { -public: - inline CollisionPartsFilterBase() {} - - virtual bool isInvalidParts(const CollisionParts*) const = 0; -}; \ No newline at end of file diff --git a/include/Game/MapObj/ClipAreaHolder.hpp b/include/Game/MapObj/ClipAreaHolder.hpp index f50a6d695..c8c357935 100644 --- a/include/Game/MapObj/ClipAreaHolder.hpp +++ b/include/Game/MapObj/ClipAreaHolder.hpp @@ -26,5 +26,4 @@ namespace MR { bool isActiveClipArea(); void activateClipArea(); void deactivateClipArea(); - void setBinderExceptSensorType(LiveActor*, const TVec3f*, f32); }; // namespace MR diff --git a/include/Game/Util/CollisionPartsFilter.hpp b/include/Game/Util/CollisionPartsFilter.hpp new file mode 100644 index 000000000..12b2c00df --- /dev/null +++ b/include/Game/Util/CollisionPartsFilter.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include "Game/LiveActor/LiveActor.hpp" +#include "Game/Map/CollisionParts.hpp" + +class CollisionPartsFilterBase { +public: + inline CollisionPartsFilterBase() { + } + + virtual bool isInvalidParts(const CollisionParts*) const = 0; +}; + +class CollisionPartsFilterSensor : public CollisionPartsFilterBase { +public: + inline CollisionPartsFilterSensor(const HitSensor* pSensor) : mSensor(pSensor) { + } + + virtual bool isInvalidParts(const CollisionParts* pParts) const; + + /* 0x04 */ const HitSensor* mSensor; +}; + +class CollisionPartsFilterActor : public CollisionPartsFilterBase { +public: + inline CollisionPartsFilterActor(const LiveActor* pActor) : mActor(pActor) { + } + + virtual bool isInvalidParts(const CollisionParts* pParts) const; + + /* 0x04 */ const LiveActor* mActor; +}; diff --git a/include/Game/Util/FurMulti.hpp b/include/Game/Util/FurMulti.hpp new file mode 100644 index 000000000..0fab4ac8e --- /dev/null +++ b/include/Game/Util/FurMulti.hpp @@ -0,0 +1,7 @@ +#pragma once + +#include "Game/LiveActor/LiveActor.hpp" + +namespace MR { + LiveActor* initMultiFur(LiveActor*, s32); +} diff --git a/include/Game/Util/LiveActorUtil.hpp b/include/Game/Util/LiveActorUtil.hpp index 04b72104b..167412e01 100644 --- a/include/Game/Util/LiveActorUtil.hpp +++ b/include/Game/Util/LiveActorUtil.hpp @@ -29,84 +29,217 @@ class ResTIMG; class ResourceHolder; class TexMtxCtrl; class TriangleFilterBase; +class XjointTransform; namespace MR { enum CollisionScaleType { AutoEqualScale = 0, NoScale = 1, UNKNOWN_2 = 2, UNKNOWN_3 = 3 }; bool isExistIndirectTexture(const LiveActor*); + void initMirrorReflection(LiveActor*); - bool isAnyAnimStopped(const LiveActor*, const char*); - - void validateClipping(LiveActor*); - void invalidateClipping(LiveActor*); - void setClippingTypeSphere(LiveActor*, f32); - void setClippingTypeSphere(LiveActor*, f32, const TVec3f*); - void setClippingFarMax(LiveActor*); - void setClippingFar50m(LiveActor*); - void setClippingFar200m(LiveActor*); - void startBtk(const LiveActor*, const char*); - - void setBaseScale(LiveActor*, const TVec3f&); - - MsgSharedGroup* joinToGroupArray(LiveActor*, const JMapInfoIter&, const char*, s32); - LiveActorGroup* getGroupFromArray(const LiveActor*); + CollisionParts* tryCreateCollisionMoveLimit(LiveActor*, HitSensor*); + CollisionParts* tryCreateCollisionWaterSurface(LiveActor*, HitSensor*); + CollisionParts* tryCreateCollisionSunshade(LiveActor*, HitSensor*); + const char* createLowModelObjName(const LiveActor*); + const char* createMiddleModelObjName(const LiveActor*); + PartsModel* createBloomModel(LiveActor*, MtxPtr); + PartsModel* createWaterModel(LiveActor*, MtxPtr); + PartsModel* createIndirectPlanetModel(LiveActor*, MtxPtr); + MirrorActor* tryCreateMirrorActor(LiveActor*, const char*); void copyTransRotateScale(const LiveActor*, LiveActor*); + bool isOnGround(const LiveActor*); + bool isOnGroundCos(const LiveActor*, f32); + bool isBindedGround(const LiveActor*); + bool isBindedGround(const LiveActor*, HitSensor*); + bool isBindedWall(const LiveActor*); + bool isBindedWall(const LiveActor*, HitSensor*); + bool isBindedWallOfMap(const LiveActor*); + bool isBindedWallOfMoveLimit(const LiveActor*); + bool isBindedWallOrSlopeGround(const LiveActor*, f32, TVec3f*); + bool isBindedRoof(const LiveActor*); + bool isBindedRoof(const LiveActor*, HitSensor*); + bool isBinded(const LiveActor*); + bool isBinded(const LiveActor*, HitSensor*); + bool isPressedRoofAndGround(const LiveActor*); + bool isPressedMovingWall(const LiveActor*); + void initDefaultPos(LiveActor*, const JMapInfoIter&); void initDefaultPosNoRepeat(LiveActor*, const JMapInfoIter&); + bool isValidMovement(const LiveActor*); bool isValidCalcAnim(const LiveActor*); bool isValidCalcViewAndEntry(const LiveActor*); bool isValidDraw(const LiveActor*); + void calcAnimDirect(LiveActor*); + + void setClippingTypeSphere(LiveActor*, f32); + void setClippingTypeSphere(LiveActor*, f32, const TVec3f*); + void setClippingTypeSphereContainsModelBoundingBox(LiveActor*, f32); + + void setClippingFar50m(LiveActor*); + void setClippingFar100m(LiveActor*); + void setClippingFar200m(LiveActor*); + void setClippingFar300m(LiveActor*); + void setClippingFarMax(LiveActor*); + void setClippingFar(LiveActor*, f32); + + void setGroupClipping(LiveActor*, const JMapInfoIter&, int); + void validateClipping(LiveActor*); + void invalidateClipping(LiveActor*); + + bool changeShowModelFlagSyncNearClipping(LiveActor*, f32); + bool isClipped(const LiveActor*); bool isInvalidClipping(const LiveActor*); + void setBaseTRMtx(LiveActor*, MtxPtr); + void setBaseTRMtx(LiveActor*, const TPos3f&); + void setBaseTRMtx(LiveActor*, const TQuat4f&); + void setBaseScale(LiveActor*, const TVec3f&); + ResourceHolder* getResourceHolder(const LiveActor*); ResourceHolder* getModelResourceHolder(const LiveActor*); + ResTIMG* getTexFromModel(const char*, const LiveActor*); + ResTIMG* getTexFromArc(const char*, const LiveActor*); + const char* getModelResName(const LiveActor*); - void setBinderCollisionPartsFilter(LiveActor*, CollisionPartsFilterBase*); - void setBinderExceptActor(LiveActor*, const LiveActor*); - void setBindTriangleFilter(LiveActor*, TriangleFilterBase*); - bool isExistBinder(const LiveActor*); - void onEntryDrawBuffer(LiveActor*); - void offEntryDrawBuffer(LiveActor*); - bool isDead(const LiveActor*); - bool isHiddenModel(const LiveActor*); - void showModel(LiveActor*); - void hideModel(LiveActor*); - void hideModelAndOnCalcAnim(LiveActor*); - void showModelIfHidden(LiveActor*) NO_INLINE; - void hideModelIfShown(LiveActor*); - void hideModelAndOnCalcAnimIfShown(LiveActor*); - void stopAnimFrame(LiveActor*); - void releaseAnimFrame(LiveActor*); - bool isNoCalcAnim(const LiveActor*); - void onCalcAnim(LiveActor*); - void offCalcAnim(LiveActor*); - bool isNoCalcView(const LiveActor*); - bool isNoEntryDrawBuffer(const LiveActor*); - bool isNoBind(const LiveActor*); - void onBind(LiveActor*); - void offBind(LiveActor*); - bool isCalcGravity(const LiveActor*); - void onCalcGravity(LiveActor*); - void offCalcGravity(LiveActor*); - LiveActorGroup* joinToGroup(LiveActor*, const char*); + bool isExistAnim(const LiveActor*, const char*); + bool isExistBck(const LiveActor*, const char*); + bool isExistBtk(const LiveActor*, const char*); + bool isExistBrk(const LiveActor*, const char*); + bool isExistBtp(const LiveActor*, const char*); + bool isExistBpk(const LiveActor*, const char*); + bool isExistBva(const LiveActor*, const char*); + bool isExistTexture(const LiveActor*, const char*); - const char* getModelResName(const LiveActor*); + void newDifferedDLBuffer(LiveActor*); + void initDLMakerFog(LiveActor*, bool); + void initDLMakerMatColor0(LiveActor*, const char*, const J3DGXColor*); + void initDLMakerChangeTex(LiveActor*, const char*); + TexMtxCtrl* initDLMakerTexMtx(LiveActor*, const char*); - void calcGravityOrZero(LiveActor*); + void startAction(const LiveActor*, const char*); + bool isActionEnd(const LiveActor*); + bool isActionStart(const LiveActor*, const char*); + bool tryStartAction(const LiveActor*, const char*); - void calcAnimDirect(LiveActor*); + void startAllAnim(const LiveActor*, const char*); + bool tryStartAllAnim(const LiveActor*, const char*); - void calcGravity(LiveActor*); - void calcGravity(LiveActor*, const TVec3f&); + ProjmapEffectMtxSetter* initDLMakerProjmapEffectMtxSetter(LiveActor*); + + void startBck(const LiveActor*, const char*, const char*); + void startBckWithInterpole(const LiveActor*, const char*, s32); + void startBckNoInterpole(const LiveActor*, const char*); + void startBckAtFirstStep(const LiveActor*, const char*); + bool tryStartBck(const LiveActor*, const char*, const char*); + bool tryStartBckAndBtp(const LiveActor*, const char*, const char*); + void setAllAnimFrame(const LiveActor*, const char*, f32); + void setAllAnimFrameAndStop(const LiveActor*, const char*, f32); + void setAllAnimFrameAtEnd(const LiveActor*, const char*); + bool isAnyAnimStopped(const LiveActor*, const char*); + bool isAnyAnimOneTimeAndStopped(const LiveActor*, const char*); + + bool isBckStopped(const LiveActor*); + bool isBtkStopped(const LiveActor*); + bool isBrkStopped(const LiveActor*); + bool isBtpStopped(const LiveActor*); + bool isBpkStopped(const LiveActor*); + bool isBvaStopped(const LiveActor*); + bool isBckOneTimeAndStopped(const LiveActor*); + bool isBrkOneTimeAndStopped(const LiveActor*); + bool isBckLooped(const LiveActor*); + bool checkPassBckFrame(const LiveActor*, f32); + + void setBckFrameAtRandom(const LiveActor*); + void setBtkFrameAtRandom(const LiveActor*); + void setBckFrameAndStop(const LiveActor*, f32); + void setBtkFrameAndStop(const LiveActor*, f32); + void setBrkFrameAndStop(const LiveActor*, f32); + void setBtpFrameAndStop(const LiveActor*, f32); + void setBpkFrameAndStop(const LiveActor*, f32); + void setBvaFrameAndStop(const LiveActor*, f32); + void setBrkFrameEndAndStop(const LiveActor*); + void startBtkAndSetFrameAndStop(const LiveActor*, const char*, f32); + void startBrkAndSetFrameAndStop(const LiveActor*, const char*, f32); + void startBtpAndSetFrameAndStop(const LiveActor*, const char*, f32); - void offCalcShadow(LiveActor*, const char*); + void startBtk(const LiveActor*, const char*); + void startBrk(const LiveActor*, const char*); + void startBtp(const LiveActor*, const char*); + void startBpk(const LiveActor*, const char*); + void startBva(const LiveActor*, const char*); - void zeroVelocity(LiveActor*); + bool startBckIfExist(const LiveActor*, const char*); + bool startBtkIfExist(const LiveActor*, const char*); + bool startBrkIfExist(const LiveActor*, const char*); + bool startBtpIfExist(const LiveActor*, const char*); + bool startBpkIfExist(const LiveActor*, const char*); + bool startBvaIfExist(const LiveActor*, const char*); + + bool isBtkPlaying(const LiveActor*, const char*); + bool isBrkPlaying(const LiveActor*, const char*); + bool isBtpPlaying(const LiveActor*, const char*); + bool isBpkPlaying(const LiveActor*, const char*); + bool isBvaPlaying(const LiveActor*, const char*); + bool isBckExist(const LiveActor*, const char*); + bool isBtkExist(const LiveActor*, const char*); + bool isBrkExist(const LiveActor*, const char*); + bool isBpkExist(const LiveActor*, const char*); + bool isBtpExist(const LiveActor*, const char*); + bool isBvaExist(const LiveActor*, const char*); + + void stopBck(const LiveActor*); + void stopBtk(const LiveActor*); + void stopBrk(const LiveActor*); + void stopBtp(const LiveActor*); + void stopBva(const LiveActor*); + + void setBckRate(const LiveActor*, f32); + void setBtkRate(const LiveActor*, f32); + void setBrkRate(const LiveActor*, f32); + void setBvaRate(const LiveActor*, f32); + + void setBckFrame(const LiveActor*, f32) NO_INLINE; + void setBtkFrame(const LiveActor*, f32); + void setBrkFrame(const LiveActor*, f32); + void setBtpFrame(const LiveActor*, f32); + void setBpkFrame(const LiveActor*, f32); + void setBvaFrame(const LiveActor*, f32); + + bool isBckPlaying(const LiveActor*, const char*); + + J3DFrameCtrl* getBckCtrl(const LiveActor*); + J3DFrameCtrl* getBtkCtrl(const LiveActor*); + J3DFrameCtrl* getBrkCtrl(const LiveActor*); + J3DFrameCtrl* getBtpCtrl(const LiveActor*); + J3DFrameCtrl* getBpkCtrl(const LiveActor*); + J3DFrameCtrl* getBvaCtrl(const LiveActor*); + + void updateMaterial(LiveActor*); + void setMirrorReflectionInfoFromMtxYUp(const TPos3f&); + void setMirrorReflectionInfoFromModel(LiveActor*); + void changeModelDataTexAll(LiveActor*, const char*, const ResTIMG&); + + void initJointTransform(const LiveActor*); + XjointTransform* getJointTransform(const LiveActor*, const char*); + void setJointTransformLocalMtx(const LiveActor*, const char*, MtxPtr); + + f32 getBckFrame(const LiveActor*); + f32 getBrkFrame(const LiveActor*); + f32 getBtpFrame(const LiveActor*); + f32 getBvaFrame(const LiveActor*); + f32 getBckRate(const LiveActor*); + f32 getBckFrameMax(const LiveActor*); + f32 getBtkFrameMax(const LiveActor*); + f32 getBrkFrameMax(const LiveActor*); + + const char* getPlayingBckName(const LiveActor*); + + void reflectBckCtrlData(LiveActor*, const BckCtrlData&); void initLightCtrl(LiveActor*); void initLightCtrlForPlayer(LiveActor*); @@ -119,6 +252,7 @@ namespace MR { void calcLightPos1(TVec3f*, const LiveActor*); const GXColor* getLightAmbientColor(const LiveActor*); ActorLightCtrl* getLightCtrl(const LiveActor*); + bool isStep(const LiveActor*, s32) NO_INLINE; bool isFirstStep(const LiveActor*); bool isLessStep(const LiveActor*, s32); @@ -127,6 +261,7 @@ namespace MR { bool isGreaterEqualStep(const LiveActor*, s32); bool isIntervalStep(const LiveActor*, s32); bool isNewNerve(const LiveActor*); + f32 calcNerveRate(const LiveActor*, s32); f32 calcNerveRate(const LiveActor*, s32, s32); f32 calcNerveEaseInRate(const LiveActor*, s32); @@ -141,9 +276,11 @@ namespace MR { f32 calcNerveEaseOutValue(const LiveActor*, s32, f32, f32); f32 calcNerveEaseInOutValue(const LiveActor*, s32, f32, f32); f32 calcNerveEaseInOutValue(const LiveActor*, s32, s32, f32, f32); + void setNerveAtStep(LiveActor*, const Nerve*, s32); void setNerveAtBckStopped(LiveActor*, const Nerve*); bool trySetNerve(LiveActor*, const Nerve*); + const TVec3f* getGroundNormal(const LiveActor*); const TVec3f* getWallNormal(const LiveActor*); const TVec3f* getRoofNormal(const LiveActor*); @@ -152,9 +289,7 @@ namespace MR { const TVec3f* getGroundHitPos(const LiveActor*); const TVec3f* getWallHitPos(const LiveActor*); const TVec3f* getRoofHitPos(const LiveActor*); - const TVec3f* getGroundHitPos(const LiveActor*); - const TVec3f* getWallHitPos(const LiveActor*); - const TVec3f* getRoofHitPos(const LiveActor*); + void calcWallNormalHorizontal(TVec3f*, const LiveActor*); f32 calcHitPowerToGround(const LiveActor*); f32 calcHitPowerToWall(const LiveActor*); @@ -162,130 +297,91 @@ namespace MR { const TVec3f* getBindedPlaneNormal(const LiveActor*, int); HitSensor* getBindedPlaneSensor(const LiveActor*, int); TVec3f* getBindedFixReactionVector(const LiveActor*); + void setBinderOffsetVec(LiveActor*, const TVec3f*, bool); void setBinderRadius(LiveActor*, f32); f32 getBinderRadius(const LiveActor*); + void setBinderIgnoreMovingCollision(LiveActor*); + void validateExCollisionParts(LiveActor*); + void invalidateExCollisionParts(LiveActor*); + void setBinderCollisionPartsFilter(LiveActor*, CollisionPartsFilterBase*); + void setBinderExceptActor(LiveActor*, const LiveActor*); + void setBinderExceptSensorType(LiveActor*, const TVec3f*, f32); + void setBindTriangleFilter(LiveActor*, TriangleFilterBase*); + bool isExistBinder(const LiveActor*); - void initFur(LiveActor*); - void initFurPlanet(LiveActor*); - LiveActor* initFurPlayer(LiveActor*); - void initCollisionParts(LiveActor*, const char*, HitSensor*, MtxPtr); - - void initCollisionPartsAutoEqualScale(LiveActor*, const char*, HitSensor*, MtxPtr); - - void setBaseTRMtx(LiveActor*, MtxPtr); - void setBaseTRMtx(LiveActor*, const TQuat4f&); - void setBaseTRMtx(LiveActor*, const TPos3f&); - - void setClippingFar(LiveActor*, f32); - void setClippingFar100m(LiveActor*); - - void setClippingTypeSphereContainsModelBoundingBox(LiveActor*, f32); - - void startAllAnim(const LiveActor*, const char*); - bool tryStartAllAnim(const LiveActor*, const char*); - - bool isAnyAnimOneTimeAndStopped(const LiveActor*, const char*); - - bool isBrkOneTimeAndStopped(const LiveActor*); - - void setBtkFrameAtRandom(const LiveActor*); - - bool tryStartBckAndBtp(const LiveActor*, const char*, const char*); - void setAllAnimFrame(const LiveActor*, const char*, f32); - void setAllAnimFrameAndStop(const LiveActor*, const char*, f32); - void setAllAnimFrameAtEnd(const LiveActor*, const char*); - - void startBck(const LiveActor*, const char*, const char*); - void startBckNoInterpole(const LiveActor*, const char*); - void startBckWithInterpole(const LiveActor*, const char*, s32); - void startBrk(const LiveActor*, const char*); - void startBva(const LiveActor*, const char*); - void setBvaFrameAndStop(const LiveActor*, f32); - - J3DFrameCtrl* getBckCtrl(const LiveActor*); - J3DFrameCtrl* getBrkCtrl(const LiveActor*); - J3DFrameCtrl* getBtkCtrl(const LiveActor*); - J3DFrameCtrl* getBpkCtrl(const LiveActor*); - J3DFrameCtrl* getBtpCtrl(const LiveActor*); - J3DFrameCtrl* getBvaCtrl(const LiveActor*); - - void startBrkAndSetFrameAndStop(const LiveActor*, const char*, f32); - bool tryStartBck(const LiveActor*, const char*, const char*); - void setBckRate(const LiveActor*, f32); - void setBtkRate(const LiveActor*, f32); - void setBrkRate(const LiveActor*, f32); - - void setBvaRate(const LiveActor*, f32); - - void setBckFrame(const LiveActor*, f32) NO_INLINE; - f32 getBckFrameMax(const LiveActor*); - f32 getBrkFrameMax(const LiveActor*); - f32 getBtkFrameMax(const LiveActor*); - void setBckFrameAndStop(const LiveActor*, f32); - - s16 getBrkFrameMax(const LiveActor*, const char*); - - void setBtkFrame(const LiveActor*, f32); - void setBtkFrameAndStop(const LiveActor*, f32); - - f32 getBtpFrame(const LiveActor*); - - bool isExistBck(const LiveActor*, const char*); - bool isExistBva(const LiveActor*, const char*); - bool isExistBtk(const LiveActor*, const char*); - bool isExistBpk(const LiveActor*, const char*); - bool isExistBtp(const LiveActor*, const char*); - bool isExistBrk(const LiveActor*, const char*); - - bool isBckExist(const LiveActor*, const char*); - bool isBtkExist(const LiveActor*, const char*); - bool isBrkExist(const LiveActor*, const char*); - bool isBpkExist(const LiveActor*, const char*); - bool isBtpExist(const LiveActor*, const char*); - bool isBvaExist(const LiveActor*, const char*); + void onEntryDrawBuffer(LiveActor*); + void offEntryDrawBuffer(LiveActor*); - bool isBckPlaying(const LiveActor*, const char*); - bool isBtkPlaying(const LiveActor*, const char*); - bool isBrkPlaying(const LiveActor*, const char*); - bool isBpkPlaying(const LiveActor*, const char*); - bool isBtpPlaying(const LiveActor*, const char*); - bool isBvaPlaying(const LiveActor*, const char*); + bool isDead(const LiveActor*); + bool isHiddenModel(const LiveActor*); + void showModel(LiveActor*); + void hideModel(LiveActor*); + void hideModelAndOnCalcAnim(LiveActor*); + void showModelIfHidden(LiveActor*) NO_INLINE; + void hideModelIfShown(LiveActor*); + void hideModelAndOnCalcAnimIfShown(LiveActor*); - bool isBckLooped(const LiveActor*); - bool checkPassBckFrame(const LiveActor* pActor, f32 f); + void stopAnimFrame(LiveActor*); + void releaseAnimFrame(LiveActor*); + bool isNoCalcAnim(const LiveActor*); + void onCalcAnim(LiveActor*); + void offCalcAnim(LiveActor*); - bool isBckStopped(const LiveActor*); - bool isBrkStopped(const LiveActor*); - bool isBtkStopped(const LiveActor*); - bool isBtpStopped(const LiveActor*); - bool isBpkStopped(const LiveActor*); + bool isNoCalcView(const LiveActor*); + bool isNoEntryDrawBuffer(const LiveActor*); + bool isNoBind(const LiveActor*); - bool isBckOneTimeAndStopped(const LiveActor*); + void onBind(LiveActor*); + void offBind(LiveActor*); - void setBrkFrame(const LiveActor*, f32); - void setBrkFrameAndStop(const LiveActor*, f32); - void setBrkFrameEndAndStop(const LiveActor*); + bool isCalcGravity(const LiveActor*); + void onCalcGravity(LiveActor*); + void offCalcGravity(LiveActor*); - void setBckFrameAtRandom(const LiveActor*); + LiveActorGroup* joinToGroup(LiveActor*, const char*); + MsgSharedGroup* joinToGroupArray(LiveActor*, const JMapInfoIter&, const char*, s32); + LiveActorGroup* getGroupFromArray(const LiveActor*); + LiveActor* getPairedGroupMember(const LiveActor*); - void startBtkAndSetFrameAndStop(const LiveActor*, const char*, f32); + void callMakeActorDeadAllGroupMember(const LiveActor*); + void callKillAllGroupMember(const LiveActor*); + void callMakeActorAppearedAllGroupMember(const LiveActor*); + void callAppearAllGroupMember(const LiveActor*); + void callRequestMovementOnAllGroupMember(const LiveActor*); + void callInvalidateClippingAllGroupMember(const LiveActor*); + void callValidateClippingAllGroupMember(const LiveActor*); - void setBaseTRMtx(LiveActor*, const TPos3f&); + s32 countHideGroupMember(const LiveActor*); + s32 countShowGroupMember(const LiveActor*); - void setBpkFrame(const LiveActor*, f32); - void stopBck(const LiveActor*); + void addToAttributeGroupSearchTurtle(const LiveActor*); + void addToAttributeGroupReflectSpinningBox(const LiveActor*); + bool isExistInAttributeGroupSearchTurtle(const LiveActor*); + bool isExistInAttributeGroupReflectSpinningBox(const LiveActor*); - void startBtp(const LiveActor*, const char*); - void setBtpFrame(const LiveActor*, f32); - void setBtpFrameAndStop(const LiveActor*, f32); + void calcGravity(LiveActor*); + void calcGravity(LiveActor*, const TVec3f&); + void calcGravityOrZero(LiveActor*); + void calcGravityOrZero(LiveActor*, const TVec3f&); - void startBpk(const LiveActor*, const char*); + void initFur(LiveActor*); + void initFurPlanet(LiveActor*); + LiveActor* initFurPlayer(LiveActor*); - ProjmapEffectMtxSetter* initDLMakerProjmapEffectMtxSetter(LiveActor*); - void initDLMakerFog(LiveActor*, bool); + void initCollisionParts(LiveActor*, const char*, HitSensor*, MtxPtr); + void initCollisionPartsAutoEqualScale(LiveActor*, const char*, HitSensor*, MtxPtr); + void initCollisionPartsAutoEqualScaleOne(LiveActor*, const char*, HitSensor*, MtxPtr); + void initCollisionPartsFromResourceHolder(LiveActor*, const char*, HitSensor*, ResourceHolder*, MtxPtr); - void newDifferedDLBuffer(LiveActor*); + CollisionParts* createCollisionPartsFromLiveActor(LiveActor*, const char*, HitSensor*, MR::CollisionScaleType); + CollisionParts* createCollisionPartsFromLiveActor(LiveActor*, const char*, HitSensor*, MtxPtr, MR::CollisionScaleType); + CollisionParts* createCollisionPartsFromResourceHolder(ResourceHolder*, const char*, HitSensor*, const TPos3f&, MR::CollisionScaleType); + CollisionParts* tryCreateCollisionMoveLimit(LiveActor*, MtxPtr, HitSensor*); + CollisionParts* tryCreateCollisionWaterSurface(LiveActor*, MtxPtr, HitSensor*); + CollisionParts* tryCreateCollisionSunshade(LiveActor*, MtxPtr, HitSensor*); + CollisionParts* tryCreateCollisionAllOtherCategory(LiveActor*, HitSensor*, CollisionParts**, CollisionParts**, CollisionParts**); + CollisionParts* tryCreateCollisionAllOtherCategory(LiveActor*, MtxPtr, HitSensor*, CollisionParts**, CollisionParts**, CollisionParts**); bool isExistKcl(LiveActor*, const char*); f32 getCollisionBoundingSphereRange(const LiveActor*); @@ -294,8 +390,6 @@ namespace MR { void validateCollisionParts(CollisionParts*); void invalidateCollisionParts(LiveActor*); void invalidateCollisionParts(CollisionParts*); - void validateExCollisionParts(LiveActor*); - void invalidateExCollisionParts(LiveActor*); void onUpdateCollisionParts(LiveActor*); void onUpdateCollisionPartsOnetimeImmediately(LiveActor*); void offUpdateCollisionParts(LiveActor*); @@ -305,6 +399,7 @@ namespace MR { CollisionParts* getCollisionParts(const LiveActor*); bool isExistCollisionParts(const LiveActor*); u32 getCollisionSensorType(const CollisionParts*); + ModelObj* createModelObjMapObj(const char*, const char*, MtxPtr); ModelObj* createModelObjMapObjStrongLight(const char*, const char*, MtxPtr); ModelObj* createModelObjNoSilhouettedMapObj(const char*, const char*, MtxPtr); @@ -315,6 +410,7 @@ namespace MR { ModelObj* createModelObjNpc(const char*, const char*, MtxPtr); ModelObj* createModelObjPlanetLow(const char*, const char*, MtxPtr); ModelObj* createModelObjBloomModel(const char*, const char*, MtxPtr); + PartsModel* createPartsModelMapObj(LiveActor*, const char*, const char*, MtxPtr); PartsModel* createPartsModelMapObjStrongLight(LiveActor*, const char*, const char*, MtxPtr); PartsModel* createPartsModelNoSilhouettedMapObj(LiveActor*, const char*, const char*, MtxPtr); @@ -323,109 +419,16 @@ namespace MR { PartsModel* createPartsModelIndirectNpc(LiveActor*, const char*, const char*, MtxPtr); PartsModel* createPartsModelEnemyAndFix(LiveActor*, const char*, const char*, MtxPtr, const TVec3f&, const TVec3f&, const char*); PartsModel* createPartsModelNpcAndFix(LiveActor*, const char*, const char*, const char*); + LodCtrl* createLodCtrlNPC(LiveActor*, const JMapInfoIter&); LodCtrl* createLodCtrlPlanet(LiveActor*, const JMapInfoIter&, f32, s32); LodCtrl* createLodCtrlMapObj(LiveActor*, const JMapInfoIter&, f32); + Flag* createMapFlag(const char*, const char*, const TVec3f*, const TVec3f&, f32, f32, f32, s32, s32, f32); + void stopSceneAtStep(const LiveActor*, s32, s32); + void tryRumblePadAndCameraDistanceVeryStrong(const LiveActor*, f32, f32, f32); void tryRumblePadAndCameraDistanceStrong(const LiveActor*, f32, f32, f32); void tryRumblePadAndCameraDistanceMiddle(const LiveActor*, f32, f32, f32); - - void callAppearAllGroupMember(const LiveActor*); - void callMakeActorDeadAllGroupMember(const LiveActor*); - void callRequestMovementOnAllGroupMember(const LiveActor*); - void callMakeActorAppearedAllGroupMember(const LiveActor*); - - void setGroupClipping(LiveActor*, const JMapInfoIter&, int); - - void startAction(const LiveActor*, const char*); - - bool tryStartAction(const LiveActor*, const char*); - - bool changeShowModelFlagSyncNearClipping(LiveActor*, f32); - - PartsModel* createIndirectPlanetModel(LiveActor*, MtxPtr); - MirrorActor* tryCreateMirrorActor(LiveActor*, const char*); - - CollisionParts* createCollisionPartsFromLiveActor(LiveActor*, const char*, HitSensor*, CollisionScaleType); - CollisionParts* createCollisionPartsFromLiveActor(LiveActor*, const char*, HitSensor*, MtxPtr, CollisionScaleType); - - CollisionParts* tryCreateCollisionMoveLimit(LiveActor*, HitSensor*); - CollisionParts* tryCreateCollisionMoveLimit(LiveActor*, MtxPtr, HitSensor*); - - bool isBinded(const LiveActor*); - bool isBinded(const LiveActor*, HitSensor*); - - bool isBindedGround(const LiveActor*); - bool isBindedWall(const LiveActor*); - bool isBindedWallOfMap(const LiveActor*); - - bool isBindedGroundIce(const LiveActor*); - bool isBindedGroundWater(const LiveActor*); - - bool isActionEnd(const LiveActor*); - - void setMirrorReflectionInfoFromModel(LiveActor*); - - bool isBindedRoof(const LiveActor*); - bool isOnGround(const LiveActor*); - - bool isPressedRoofAndGround(const LiveActor*); - bool isPressedMovingWall(const LiveActor*); - - void setBinderExceptSensorType(LiveActor*, const TVec3f*, f32); - - void setBinderOffsetVec(LiveActor*, const TVec3f*, bool); - void setBinderRadius(LiveActor*, f32); - - void setBinderExceptActor(LiveActor*, const LiveActor*); - - CollisionParts* tryCreateCollisionAllOtherCategory(LiveActor*, MtxPtr, HitSensor*, CollisionParts**, CollisionParts**, CollisionParts**); - CollisionParts* tryCreateCollisionAllOtherCategory(LiveActor*, HitSensor*, CollisionParts**, CollisionParts**, CollisionParts**); - - bool isExistAnim(const LiveActor*, const char*); - - void setMirrorReflectionInfoFromMtxYUp(const TPos3f&); - - const char* createLowModelObjName(const LiveActor*); - const char* createMiddleModelObjName(const LiveActor*); - - void addToAttributeGroupSearchTurtle(const LiveActor*); - bool isExistInAttributeGroupSearchTurtle(const LiveActor*); - - void initJointTransform(const LiveActor*); - - void initCollisionPartsAutoEqualScaleOne(LiveActor*, const char*, HitSensor*, MtxPtr); - void initCollisionPartsFromResourceHolder(LiveActor*, const char*, HitSensor*, ResourceHolder*, MtxPtr); - - ResTIMG* getTexFromArc(const char*, const LiveActor*); - PartsModel* createBloomModel(LiveActor*, MtxPtr); - PartsModel* createWaterModel(LiveActor*, MtxPtr); - - TexMtxCtrl* initDLMakerTexMtx(LiveActor*, const char*); - - void initDLMakerMatColor0(LiveActor*, const char*, const J3DGXColor*); - - void changeModelDataTexAll(LiveActor*, const char*, const ResTIMG&); - - void reflectBckCtrlData(LiveActor*, const BckCtrlData&); - - s32 countShowGroupMember(const LiveActor*); - s32 countHideGroupMember(const LiveActor*); - - f32 getBckFrame(const LiveActor*); - f32 getBrkFrame(const LiveActor*); - - f32 calcNerveValue(const LiveActor*, s32, s32, f32, f32); - - LiveActor* getPairedGroupMember(const LiveActor*); - - TVec3f* getBindedFixReactionVector(const LiveActor*); - - CollisionParts* tryCreateCollisionSunshade(LiveActor*, HitSensor*); - - CollisionParts* tryCreateCollisionWaterSurface(LiveActor*, HitSensor*); - - const char* getPlayingBckName(const LiveActor*); }; // namespace MR diff --git a/include/Game/Util/ModelUtil.hpp b/include/Game/Util/ModelUtil.hpp index 00f153690..484ae5edc 100644 --- a/include/Game/Util/ModelUtil.hpp +++ b/include/Game/Util/ModelUtil.hpp @@ -8,6 +8,7 @@ class J3DModel; class J3DMaterial; class LiveActor; struct ResTIMG; +class XanimePlayer; namespace MR { bool isExistModel(const char*); @@ -15,6 +16,7 @@ namespace MR { J3DModel* getJ3DModel(const LiveActor*); J3DModelData* getJ3DModelData(const LiveActor*); J3DModelData* getJ3DModelData(const char*); + ResTIMG* getResTIMG(const LiveActor*, int); void calcJ3DModel(LiveActor*); @@ -34,6 +36,8 @@ namespace MR { void showMaterial(const LiveActor*, const char*); void hideMaterial(const LiveActor*, const char*); + bool isUseTex(J3DMaterial*, u16); + void updateMaterial(LiveActor*); void syncJointAnimation(LiveActor*, const LiveActor*); @@ -53,6 +57,9 @@ namespace MR { bool isExistEffectTexMtx(LiveActor*); s16 getBckFrameMax(const LiveActor*, const char*); + s16 getBrkFrameMax(const LiveActor*, const char*); + s16 getBvaFrameMax(const LiveActor*, const char*); + bool isBckPlaying(XanimePlayer*, const char*); void updateModelManager(LiveActor*); void calcAnimModelManager(LiveActor*); diff --git a/include/Game/Util/SoundUtil.hpp b/include/Game/Util/SoundUtil.hpp index 97f6a0304..8bdcc29d9 100644 --- a/include/Game/Util/SoundUtil.hpp +++ b/include/Game/Util/SoundUtil.hpp @@ -34,6 +34,8 @@ namespace MR { void actorSoundMovement(LiveActor*); + void startBas(const LiveActor*, const char*, bool, f32, f32); + void startCSSound(const char*, const char*, s32); void startCSSound2P(const char*, const char*); void startSystemSE(const char*, s32, s32); diff --git a/src/Game/Util/LiveActorUtil.cpp b/src/Game/Util/LiveActorUtil.cpp index 2ae91791d..c73681e49 100644 --- a/src/Game/Util/LiveActorUtil.cpp +++ b/src/Game/Util/LiveActorUtil.cpp @@ -31,6 +31,8 @@ #include "Game/Util/ActorMovementUtil.hpp" #include "Game/Util/ActorSensorUtil.hpp" #include "Game/Util/AreaObjUtil.hpp" +#include "Game/Util/CollisionPartsFilter.hpp" +#include "Game/Util/FurMulti.hpp" #include "Game/Util/GravityUtil.hpp" #include "Game/Util/JMapUtil.hpp" #include "Game/Util/MapUtil.hpp" @@ -46,18 +48,6 @@ #include #include -class CollisionPartsFilterActor : public CollisionPartsFilterBase { -public: - CollisionPartsFilterActor(const LiveActor* pActor) : mActor(pActor) { - } - - virtual bool isInvalidParts(const CollisionParts* pParts) const { - return pParts->mHitSensor->mHost == mActor; - } - - const LiveActor* mActor; -}; - namespace { f32 sAnimRateScale = 1.0f; @@ -230,22 +220,6 @@ namespace { }; // namespace namespace MR { - bool isBckPlaying(XanimePlayer*, const char*); - bool isUseTex(J3DMaterial*, u16); - LiveActor* initMultiFur(LiveActor*, s32); - void initDLMakerChangeTex(LiveActor*, const char*); - void startBas(const LiveActor*, const char*, bool, f32, f32); - bool startBckIfExist(const LiveActor*, const char*); - bool startBtkIfExist(const LiveActor*, const char*); - bool startBrkIfExist(const LiveActor*, const char*); - bool startBpkIfExist(const LiveActor*, const char*); - bool startBtpIfExist(const LiveActor*, const char*); - bool startBvaIfExist(const LiveActor*, const char*); - void setBpkFrameAndStop(const LiveActor*, f32); - void calcGravity(LiveActor*, const TVec3f&); - void calcGravityOrZero(LiveActor*, const TVec3f&); - void showModelIfHidden(LiveActor*) NO_INLINE; - bool isExistIndirectTexture(const LiveActor* pActor) { const char* name = "IndDummy"; return MR::getJ3DModelData(pActor)->mMaterialTable.mTextureName->getIndex(name) != -1; @@ -1650,7 +1624,7 @@ namespace MR { pBvaCtrl->mRate = rate * sAnimRateScale; } - void setBckFrame(const LiveActor* pActor, f32 frame) NO_INLINE { + void setBckFrame(const LiveActor* pActor, f32 frame) { pActor->mModelManager->getBckCtrl()->mFrame = frame; } @@ -2205,7 +2179,7 @@ namespace MR { onCalcAnim(pActor); } - void showModelIfHidden(LiveActor* pActor) NO_INLINE { + void showModelIfHidden(LiveActor* pActor) { if (isHiddenModel(pActor)) { showModel(pActor); } From 5f944c34c2809d61f37ed41835a2f5a78196361a Mon Sep 17 00:00:00 2001 From: MrL314 <11429905+MrL314@users.noreply.github.com> Date: Fri, 20 Feb 2026 22:20:32 -0500 Subject: [PATCH 30/52] `CollisionPartsFilter` --- config/RMGK01/splits.txt | 3 ++- configure.py | 2 +- src/Game/Util/CollisionPartsFilter.cpp | 10 ++++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 src/Game/Util/CollisionPartsFilter.cpp diff --git a/config/RMGK01/splits.txt b/config/RMGK01/splits.txt index 23e37ca3e..1166164b5 100644 --- a/config/RMGK01/splits.txt +++ b/config/RMGK01/splits.txt @@ -9240,7 +9240,7 @@ Game/Util/BothDirList.cpp: Game/Util/CollisionPartsFilter.cpp: .text start:0x80401F44 end:0x80401F78 - .data start:0x805E6E30 end:0x805E6E68 + .data start:0x805E6E30 end:0x805E6E48 Game/Util/DirectDraw.cpp: .text start:0x80401F78 end:0x804044C8 @@ -9253,6 +9253,7 @@ Game/Util/DirectDrawUtil.cpp: Game/Util/FixedPosition.cpp: .text start:0x804048EC end:0x80404D68 + .data start:0x805E6E48 end:0x805E6E68 .sdata2 start:0x806C1948 end:0x806C1950 Game/Util/GeometryBindUtil.cpp: diff --git a/configure.py b/configure.py index 2be3ff126..ecb98dde6 100644 --- a/configure.py +++ b/configure.py @@ -2306,7 +2306,7 @@ def JSys_J3DLib(lib_name: str, objects: List[Object]) -> Dict[str, Any]: Object(NonMatching, "Game/Util/BaseMatrixFollowTargetHolder.cpp"), Object(NonMatching, "Game/Util/BezierSurface.cpp"), Object(Matching, "Game/Util/BothDirList.cpp"), - Object(NonMatching, "Game/Util/CollisionPartsFilter.cpp"), + Object(Matching, "Game/Util/CollisionPartsFilter.cpp"), Object(NonMatching, "Game/Util/DirectDraw.cpp"), Object(NonMatching, "Game/Util/DirectDrawUtil.cpp"), Object(NonMatching, "Game/Util/FixedPosition.cpp"), diff --git a/src/Game/Util/CollisionPartsFilter.cpp b/src/Game/Util/CollisionPartsFilter.cpp new file mode 100644 index 000000000..858a4af8e --- /dev/null +++ b/src/Game/Util/CollisionPartsFilter.cpp @@ -0,0 +1,10 @@ +#include "Game/Util/CollisionPartsFilter.hpp" +#include "Game/LiveActor/HitSensor.hpp" + +bool CollisionPartsFilterSensor::isInvalidParts(const CollisionParts* pParts) const { + return pParts->mHitSensor == mSensor; +} + +bool CollisionPartsFilterActor::isInvalidParts(const CollisionParts* pParts) const { + return pParts->mHitSensor->mHost == mActor; +} From 3d766d0321036666adbdf5ab7e0f870e05be3d88 Mon Sep 17 00:00:00 2001 From: MrL314 <11429905+MrL314@users.noreply.github.com> Date: Sat, 21 Feb 2026 01:24:47 -0500 Subject: [PATCH 31/52] `FixedPosition` at 96% --- config/RMGK01/symbols.txt | 5 +- include/Game/Util/FixedPosition.hpp | 12 +- .../include/JSystem/JGeometry/TMatrix.hpp | 41 +++++ src/Game/Enemy/IceMerameraKing.cpp | 9 +- src/Game/Enemy/Mogu.cpp | 9 +- src/Game/Enemy/MogucchiShooter.cpp | 9 +- src/Game/LiveActor/PartsModel.cpp | 6 +- src/Game/NPC/MiiFaceParts.cpp | 5 +- src/Game/Util/FixedPosition.cpp | 70 ++++++-- src/Game/Util/MtxUtil.cpp | 157 ++++++++---------- 10 files changed, 195 insertions(+), 128 deletions(-) diff --git a/config/RMGK01/symbols.txt b/config/RMGK01/symbols.txt index 4253797f2..6af72b601 100644 --- a/config/RMGK01/symbols.txt +++ b/config/RMGK01/symbols.txt @@ -59938,7 +59938,10 @@ sBezierTriangleCoefTangentT6__27@unnamed@BezierSurface_cpp@ = .data:0x805E65E4; sTrianglePatchTableGroup__27@unnamed@BezierSurface_cpp@ = .data:0x805E6D34; // type:object size:0xFC scope:global align:4 __vt__25CollisionPartsFilterActor = .data:0x805E6E30; // type:object size:0xC scope:global align:4 __vt__26CollisionPartsFilterSensor = .data:0x805E6E3C; // type:object size:0xC scope:global align:4 -lbl_805E6E48 = .data:0x805E6E48; // type:object size:0x20 +lbl_805E6E48 = .data:0x805E6E48; // type:object size:0x8 data:string +lbl_805E6E50 = .data:0x805E6E50; // type:object size:0xA data:string +lbl_805E6E5A = .data:0x805E6E5A; // type:object size:0x6 data:string +lbl_805E6E60 = .data:0x805E6E60; // type:object size:0x7 data:string lbl_805E6E68 = .data:0x805E6E68; // type:object size:0xA data:string lbl_805E6E78 = .data:0x805E6E78; // type:object size:0xC data:string lbl_805E6E84 = .data:0x805E6E84; // type:object size:0x7 data:string diff --git a/include/Game/Util/FixedPosition.hpp b/include/Game/Util/FixedPosition.hpp index b8b96e38e..6e0358edb 100644 --- a/include/Game/Util/FixedPosition.hpp +++ b/include/Game/Util/FixedPosition.hpp @@ -20,9 +20,9 @@ class FixedPosition { void copyTrans(TVec3f*) const; void copyRotate(TVec3f*) const; - MtxPtr mBaseMtx; // 0x0 - TVec3f mLocalTrans; // 0x4 - TVec3f _10; - TPos3f _1C; - bool mNormalizeScale; // 0x4C -}; \ No newline at end of file + /* 0x00 */ TMtx34f* mBaseMtx; + /* 0x04 */ TVec3f mLocalTrans; + /* 0x10 */ TVec3f mRotDegrees; + /* 0x1C */ TPos3f mMtx; + /* 0x4C */ bool mNormalizeScale; +}; diff --git a/libs/JSystem/include/JSystem/JGeometry/TMatrix.hpp b/libs/JSystem/include/JSystem/JGeometry/TMatrix.hpp index 36fbd102b..b05d8b63d 100644 --- a/libs/JSystem/include/JSystem/JGeometry/TMatrix.hpp +++ b/libs/JSystem/include/JSystem/JGeometry/TMatrix.hpp @@ -439,6 +439,47 @@ namespace JGeometry { this->mMtx[2][2] = v12 * v13; } + inline void makeMatrixFromRotAxesInline(f32 rx, f32 ry, f32 rz) { + // FIXME: this isnt 100% correct yet, caution + + f32 cosZ = cos(rz); + f32 cosY = cos(ry); + f32 cosX = cos(rx); + f32 sinZ = sin(rz); + f32 sinY = sin(ry); + f32 sinX = sin(rx); + + /* + this->mMtx[0][0] = cosY * cosZ; + this->mMtx[1][0] = cosY * sinZ; + this->mMtx[2][0] = -sinY; + + this->mMtx[0][1] = sinX * sinY * cosZ - cosX * sinZ; + this->mMtx[1][1] = sinX * sinY * sinZ + cosX * cosZ; + this->mMtx[2][1] = sinX * cosY; + + this->mMtx[0][2] = cosX * cosZ * sinY + sinX * sinZ; + this->mMtx[1][2] = cosX * sinZ * sinY - sinX * cosZ; + this->mMtx[2][2] = cosX * cosY; + */ + + this->mMtx[0][0] = cosY * cosZ; + this->mMtx[1][0] = cosY * sinZ; + this->mMtx[2][0] = -sinY; + + this->mMtx[0][1] = sinX * sinY * cosZ - cosX * sinZ; + this->mMtx[1][1] = sinX * sinY * sinZ + cosX * cosZ; + this->mMtx[2][1] = sinX * cosY; + + this->mMtx[0][2] = cosX * cosZ * sinY + sinX * sinZ; + this->mMtx[1][2] = cosX * sinZ * sinY - sinX * cosZ; + this->mMtx[2][2] = cosX * cosY; + + // this->mMtx[0][3] = rTrans.x; + // this->mMtx[1][3] = rTrans.y; + // this->mMtx[2][3] = rTrans.z; + } + inline void setRotateInline(const TVec3f& vec1, f32 r) { TVec3f vec; vec.set(vec1); diff --git a/src/Game/Enemy/IceMerameraKing.cpp b/src/Game/Enemy/IceMerameraKing.cpp index 8dbb1a07d..712577687 100644 --- a/src/Game/Enemy/IceMerameraKing.cpp +++ b/src/Game/Enemy/IceMerameraKing.cpp @@ -63,9 +63,10 @@ namespace NrvIceMerameraKing { }; // namespace NrvIceMerameraKing IceMerameraKing::IceMerameraKing(const char* pName) - : LiveActor(pName), mFixedPos(nullptr), _90(nullptr), _94(nullptr), mActor(), _A8(nullptr), _AC(nullptr), _B0(0, 0, 1), _BC(0, 1, 0), _C8(0, 0, 0), - _D4(0, 0, 0), _E0(0), _E4(0), _EC(3), _F0(0), mModelArray(nullptr), _F8(nullptr), mJointController(nullptr), _100(0, 0, 0, 1), _110(0.0f, 0.0f, 0.0f), - _11C(0.0f), _120(false), _121(false) {} + : LiveActor(pName), mFixedPos(nullptr), _90(nullptr), _94(nullptr), mActor(), _A8(nullptr), _AC(nullptr), _B0(0, 0, 1), _BC(0, 1, 0), + _C8(0, 0, 0), _D4(0, 0, 0), _E0(0), _E4(0), _EC(3), _F0(0), mModelArray(nullptr), _F8(nullptr), mJointController(nullptr), _100(0, 0, 0, 1), + _110(0.0f, 0.0f, 0.0f), _11C(0.0f), _120(false), _121(false) { +} void IceMerameraKing::init(const JMapInfoIter& rIter) { if (MR::isValidInfo(rIter)) { @@ -259,7 +260,7 @@ void IceMerameraKing::exeThrow() { if (MR::isStep(this, 22)) { _90 = getDeadWeaponAndAppear(); - mFixedPos->_1C.getTrans(_90->mPosition); + mFixedPos->mMtx.getTrans(_90->mPosition); if (!_90) { setNerve(&NrvIceMerameraKing::HostTypeNrvSearch::sInstance); return; diff --git a/src/Game/Enemy/Mogu.cpp b/src/Game/Enemy/Mogu.cpp index ec30afef6..0473e028e 100644 --- a/src/Game/Enemy/Mogu.cpp +++ b/src/Game/Enemy/Mogu.cpp @@ -47,7 +47,8 @@ namespace NrvMogu { Mogu::Mogu(const char* pName) : LiveActor(pName), mAnimScaleController(nullptr), _90(nullptr), mStone(nullptr), mHole(nullptr), mSight(0, 0, 1), _A8(0, 1, 0), _B4(true), - mIsCannonFleet(false) {} + mIsCannonFleet(false) { +} void Mogu::init(const JMapInfoIter& rIter) { if (MR::isValidInfo(rIter)) { @@ -532,9 +533,9 @@ void Mogu::calcAndSetBaseMtx() { if (isNerve(&NrvMogu::HostTypeNrvThrow::sInstance) && MR::isLessStep(this, 47)) { _90->calc(); - f32 z = _90->_1C[2][3]; - f32 y = _90->_1C[1][3]; - f32 x = _90->_1C[0][3]; + f32 z = _90->mMtx[2][3]; + f32 y = _90->mMtx[1][3]; + f32 x = _90->mMtx[0][3]; mStone->mPosition.set< f32 >(x, y, z); } } diff --git a/src/Game/Enemy/MogucchiShooter.cpp b/src/Game/Enemy/MogucchiShooter.cpp index b785b3782..83e1ca180 100644 --- a/src/Game/Enemy/MogucchiShooter.cpp +++ b/src/Game/Enemy/MogucchiShooter.cpp @@ -34,7 +34,8 @@ namespace { } // namespace MogucchiShooter::MogucchiShooter(LiveActor* pActor, const char* pName) - : PartsModel(pActor, pName, "MogucchiShooter", nullptr, MR::DrawBufferType_Enemy, false), mFront(0.0f, 0.0f, 0.0f) {} + : PartsModel(pActor, pName, "MogucchiShooter", nullptr, MR::DrawBufferType_Enemy, false), mFront(0.0f, 0.0f, 0.0f) { +} void MogucchiShooter::init(const JMapInfoIter& rIter) { initEffectKeeper(1, nullptr, false); @@ -269,12 +270,12 @@ void MogucchiShooter::calcAndSetBaseMtx() { TPos3f posMtx; TPos3f copyMtx; posMtx.identity(); - JMath::gekko_ps_copy12(©Mtx, mFixedPos->_1C); + JMath::gekko_ps_copy12(©Mtx, mFixedPos->mMtx); TVec3f up; copyMtx.getYDirInline(up); - mFixedPos->_1C.getTransInline(mPosition); + mFixedPos->mMtx.getTransInline(mPosition); MR::makeMtxUpFrontPos(&posMtx, up, mFront, mPosition); MR::setBaseTRMtx(this, posMtx); } @@ -288,7 +289,7 @@ void MogucchiShooter::resetDirection() { void MogucchiShooter::faceToMario() { if (!MR::isPlayerHidden() && !MR::isStageStateScenarioOpeningCamera() && !MR::isDemoActive()) { TPos3f mtx; - JMath::gekko_ps_copy12(&mtx, mFixedPos->_1C); + JMath::gekko_ps_copy12(&mtx, mFixedPos->mMtx); MR::turnDirectionToTargetDegree(this, &mFront, *MR::getPlayerPos(), 1.0f); TVec3f front; mtx.getZDir(front); diff --git a/src/Game/LiveActor/PartsModel.cpp b/src/Game/LiveActor/PartsModel.cpp index fc2e1a83e..088c1735b 100644 --- a/src/Game/LiveActor/PartsModel.cpp +++ b/src/Game/LiveActor/PartsModel.cpp @@ -105,7 +105,7 @@ void PartsModel::initFixedPosition(const TVec3f& rLocalTrans, const TVec3f& a2, } else { mFixedPos = new FixedPosition(mHost, rLocalTrans, a2); } - mMtx = (MtxPtr)&mFixedPos->_1C; + mMtx = (MtxPtr)&mFixedPos->mMtx; } void PartsModel::initFixedPosition(const char* pJointName) { @@ -114,12 +114,12 @@ void PartsModel::initFixedPosition(const char* pJointName) { void PartsModel::initFixedPosition(MtxPtr mtx, const TVec3f& rLocalTrans, const TVec3f& a3) { mFixedPos = new FixedPosition(mtx, rLocalTrans, a3); - mMtx = (MtxPtr)&mFixedPos->_1C; + mMtx = (MtxPtr)&mFixedPos->mMtx; } void PartsModel::loadFixedPosition(const char* pJointName) { mFixedPos = new FixedPosition(mHost, pJointName, nullptr); - mMtx = (MtxPtr)&mFixedPos->_1C; + mMtx = (MtxPtr)&mFixedPos->mMtx; } void PartsModel::offFixedPosNormalizeScale() { diff --git a/src/Game/NPC/MiiFaceParts.cpp b/src/Game/NPC/MiiFaceParts.cpp index 2e4724eab..bb9679413 100644 --- a/src/Game/NPC/MiiFaceParts.cpp +++ b/src/Game/NPC/MiiFaceParts.cpp @@ -13,7 +13,8 @@ MiiFaceParts::MiiFaceParts(const char* pName, const MiiFaceRecipe& rRecipe) MR::createSceneObj(SceneObj_MiiFacePartsHolder); } -MiiFaceParts::~MiiFaceParts() {} +MiiFaceParts::~MiiFaceParts() { +} void MiiFaceParts::init(const JMapInfoIter& rIter) { _90 = new (32) u8[mRecipe->getModelBufferSize()]; @@ -69,7 +70,7 @@ void MiiFaceParts::drawXlu(const RFLDrawCoreSetting* pSetting) const { void MiiFaceParts::initFixedPosition(MtxPtr pParam1, const TVec3f& rParam2, const TVec3f& rParam3) { _CC = new FixedPosition(pParam1, rParam2, rParam3); - _C8 = _CC->_1C; + _C8 = _CC->mMtx; } void MiiFaceParts::changeExpressionNormal() { diff --git a/src/Game/Util/FixedPosition.cpp b/src/Game/Util/FixedPosition.cpp index cd1599b94..9f8ca66d3 100644 --- a/src/Game/Util/FixedPosition.cpp +++ b/src/Game/Util/FixedPosition.cpp @@ -1,36 +1,78 @@ +#include "Game/Util/FixedPosition.hpp" #include "Game/LiveActor/LiveActor.hpp" -#include "Game/Util.hpp" +#include "Game/Util/LiveActorUtil.hpp" +#include "Game/Util/MtxUtil.hpp" +#include "Game/Util/ObjUtil.hpp" -FixedPosition::FixedPosition(const LiveActor* pActor, const char* pJointName, const TVec3f& rLocalTrans, const TVec3f& a4) { +FixedPosition::FixedPosition(const LiveActor* pActor, const char* pJointName, const TVec3f& rLocalTrans, const TVec3f& rRotAxes) { MtxPtr jointMtx = MR::getJointMtx(pActor, pJointName); - init(jointMtx, rLocalTrans, a4); + init(jointMtx, rLocalTrans, rRotAxes); } -FixedPosition::FixedPosition(const LiveActor* pActor, const TVec3f& rLocalTrans, const TVec3f& a3) { +FixedPosition::FixedPosition(const LiveActor* pActor, const TVec3f& rLocalTrans, const TVec3f& rRotAxes) { MtxPtr baseMtx = pActor->getBaseMtx(); - init(baseMtx, rLocalTrans, a3); + init(baseMtx, rLocalTrans, rRotAxes); } -FixedPosition::FixedPosition(MtxPtr mtx, const TVec3f& rLocalTrans, const TVec3f& a3) { - init(mtx, rLocalTrans, a3); +FixedPosition::FixedPosition(MtxPtr mtx, const TVec3f& rLocalTrans, const TVec3f& rRotAxes) { + init(mtx, rLocalTrans, rRotAxes); } -// FixedPosition::FixedPosition::calc() +void FixedPosition::calc() { + // FIXME: matrix creation inline problem + // https://decomp.me/scratch/Q7A0B + + mMtx.identity(); + + TVec3f rot = mRotDegrees.multInLine(PI_180); + mMtx.makeMatrixFromRotAxesInline(rot.z, rot.y, rot.x); + + mMtx.setTrans(mLocalTrans); + + if (mBaseMtx != nullptr) { + TMtx34f mtx; + mtx.setInline((const MtxPtr)mBaseMtx); + mMtx.concat(mtx, mMtx); + } + + if (mNormalizeScale) { + MR::makeMtxWithoutScale(&mMtx, mMtx); + } +} void FixedPosition::setBaseMtx(MtxPtr mtx) { - mBaseMtx = mtx; + mBaseMtx = (TMtx34f*)mtx; } void FixedPosition::setLocalTrans(const TVec3f& rLocalTrans) { mLocalTrans.set< f32 >(rLocalTrans); } -void FixedPosition::init(MtxPtr mtx, const TVec3f& rLocalTrans, const TVec3f& a3) { - mBaseMtx = mtx; +void FixedPosition::init(MtxPtr mtx, const TVec3f& rLocalTrans, const TVec3f& rRotAxes) { + setBaseMtx(mtx); mLocalTrans.set< f32 >(rLocalTrans); - _10.set< f32 >(a3); - _1C.identity(); + mRotDegrees.set< f32 >(rRotAxes); + mMtx.identity(); mNormalizeScale = true; } -// FixedPosition::FixedPosition(const LiveActor *, const char *, const LiveActor *) +FixedPosition::FixedPosition(const LiveActor* pActor, const char* pBcsvName, const LiveActor* pResourceActor) { + if (pResourceActor == nullptr) { + pResourceActor = pActor; + } + ResourceHolder* resourceHolder = MR::getResourceHolder(pResourceActor); + JMapInfo* csv = MR::tryCreateCsvParser(resourceHolder, "%s.bcsv", pBcsvName); + + const char* jointName = nullptr; + TVec3f trans(0.0f, 0.0f, 0.0f); + TVec3f rotate(0.0f, 0.0f, 0.0f); + MR::getCsvDataStrOrNULL(&jointName, csv, "JointName", 0); + MR::getCsvDataVec(&trans, csv, "Trans", 0); + MR::getCsvDataVec(&rotate, csv, "Rotate", 0); + + if (jointName == nullptr) { + init(pActor->getBaseMtx(), trans, rotate); + } else { + init(MR::getJointMtx(pActor, jointName), trans, rotate); + } +} diff --git a/src/Game/Util/MtxUtil.cpp b/src/Game/Util/MtxUtil.cpp index 5f7815544..0a3849afa 100644 --- a/src/Game/Util/MtxUtil.cpp +++ b/src/Game/Util/MtxUtil.cpp @@ -1,39 +1,17 @@ #include "Game/Util/MtxUtil.hpp" #include "Game/Util/MathUtil.hpp" -#include "JSystem/JMath/JMath.hpp" #include "JSystem/JMath/JMATrigonometric.hpp" +#include "JSystem/JMath/JMath.hpp" + +static Mtx mtrans_org = {{1.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f, 0.0f}}; + +static Mtx tmpmtx_sc = {{1.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f, 0.0f}}; + +static Mtx tmpmtx_rx = {{1.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f, 0.0f}}; -#define PI_180 0.017453292f - -static Mtx mtrans_org = { - { 1.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 1.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 1.0f, 0.0f } -}; - -static Mtx tmpmtx_sc = { - { 1.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 1.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 1.0f, 0.0f } -}; - -static Mtx tmpmtx_rx = { - { 1.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 1.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 1.0f, 0.0f } -}; - -static Mtx tmpmtx_ry = { - { 1.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 1.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 1.0f, 0.0f } -}; - -static Mtx tmpmtx_rz = { - { 1.0f, 0.0f, 0.0f, 0.0f }, - { 0.0f, 1.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 1.0f, 0.0f } -}; +static Mtx tmpmtx_ry = {{1.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f, 0.0f}}; + +static Mtx tmpmtx_rz = {{1.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f, 0.0f}}; namespace MR { void makeMtxRotate(MtxPtr mtx, s16 rx, s16 ry, s16 rz) { @@ -117,21 +95,21 @@ namespace MR { f32 cosX = JMACosDegree(rx); f32 cosY = JMACosDegree(ry); f32 cosZ = JMACosDegree(rz); - f32 sinZsinY = sinZ * sinY; - f32 cosZsinY = cosZ * sinY; - mtx[0][0] = cosZ * cosY; - mtx[0][1] = sinX * cosZsinY - cosX * sinZ; - mtx[0][2] = cosX * cosZsinY + sinX * sinZ; - mtx[0][3] = tx; + mtx[0][0] = cosZ * cosY; mtx[1][0] = sinZ * cosY; - mtx[1][1] = sinX * sinZsinY + cosX * cosZ; - mtx[1][2] = cosX * sinZsinY - sinX * cosZ; - mtx[1][3] = ty; - mtx[2][0] = -sinY; - mtx[2][1] = sinX * cosY; - mtx[2][2] = cosX * cosY; + + mtx[0][1] = cosZ * sinY * sinX - sinZ * cosX; + mtx[1][1] = sinZ * sinY * sinX + cosZ * cosX; + mtx[2][1] = cosY * sinX; + + mtx[0][2] = cosZ * sinY * cosX + sinZ * sinX; + mtx[1][2] = sinZ * sinY * cosX - cosZ * sinX; + mtx[2][2] = cosY * cosX; + + mtx[0][3] = tx; + mtx[1][3] = ty; mtx[2][3] = tz; } @@ -240,11 +218,11 @@ namespace MR { baseCopy.setInline(base); TVec3f srcTrans; baseCopy.setTrans(TVec3f(0.0f, 0.0f, 0.0f)); - + TPos3f invMtx; invMtx.invert(baseCopy); preScaleMtx(baseCopy.toMtxPtr(), rScale.x, rScale.y, rScale.z); - + extractMtxTrans(src, &srcTrans); PSMTXConcat(invMtx.toMtxPtr(), src, dst); PSMTXConcat(baseCopy.toMtxPtr(), dst, dst); @@ -561,9 +539,9 @@ namespace MR { void makeMtxUpNoSupportPos(TPos3f* pDst, const TVec3f& rUp, const TVec3f& rPos) { TVec3f support; if (MR::getMaxAbsElementIndex(rUp) == 2) { - support.set(0.0f, 1.0f, 0.0f); + support.set< f32 >(0.0f, 1.0f, 0.0f); } else { - support.set(0.0f, 0.0f, 1.0f); + support.set< f32 >(0.0f, 0.0f, 1.0f); } MR::makeMtxUpFrontPos(pDst, rUp, support, rPos); @@ -595,9 +573,9 @@ namespace MR { void makeMtxFrontNoSupportPos(TPos3f* pDst, const TVec3f& rFront, const TVec3f& rPos) { TVec3f support; if (MR::getMaxAbsElementIndex(rFront) == 1) { - support.set(1.0f, 0.0f, 0.0f); + support.set< f32 >(1.0f, 0.0f, 0.0f); } else { - support.set(0.0f, 1.0f, 0.0f); + support.set< f32 >(0.0f, 1.0f, 0.0f); } MR::makeMtxFrontUpPos(pDst, rFront, support, rPos); @@ -621,29 +599,29 @@ namespace MR { pMtx->setXYZDir(axisX, axisY, axisZ); TVec3f zDir; - zDir.set(pMtx->mMtx[0][2], pMtx->mMtx[1][2], pMtx->mMtx[2][2]); + zDir.set< f32 >(pMtx->mMtx[0][2], pMtx->mMtx[1][2], pMtx->mMtx[2][2]); f32 magAll = pMtx->mMtx[1][0] * pMtx->mMtx[1][0] + pMtx->mMtx[0][0] * pMtx->mMtx[0][0] + pMtx->mMtx[2][0] * pMtx->mMtx[2][0] + pMtx->mMtx[0][1] * pMtx->mMtx[0][1] + pMtx->mMtx[1][1] * pMtx->mMtx[1][1] + pMtx->mMtx[2][1] * pMtx->mMtx[2][1] + pMtx->mMtx[0][2] * pMtx->mMtx[0][2] + pMtx->mMtx[1][2] * pMtx->mMtx[1][2] + pMtx->mMtx[2][2] * pMtx->mMtx[2][2]; - JGeometry::TUtil::sqrt(magAll); + JGeometry::TUtil< f32 >::sqrt(magAll); if (pMtx) { f32 magX = pMtx->mMtx[0][0] * pMtx->mMtx[0][0] + pMtx->mMtx[1][0] * pMtx->mMtx[1][0] + pMtx->mMtx[2][0] * pMtx->mMtx[2][0]; - f32 invSqrtX = JGeometry::TUtil::inv_sqrt(magX); + f32 invSqrtX = JGeometry::TUtil< f32 >::inv_sqrt(magX); pMtx->mMtx[0][0] = invSqrtX * pMtx->mMtx[0][0]; pMtx->mMtx[1][0] = invSqrtX * pMtx->mMtx[1][0]; pMtx->mMtx[2][0] = invSqrtX * pMtx->mMtx[2][0]; f32 magY = pMtx->mMtx[0][1] * pMtx->mMtx[0][1] + pMtx->mMtx[1][1] * pMtx->mMtx[1][1] + pMtx->mMtx[2][1] * pMtx->mMtx[2][1]; - f32 invSqrtY = JGeometry::TUtil::inv_sqrt(magY); + f32 invSqrtY = JGeometry::TUtil< f32 >::inv_sqrt(magY); pMtx->mMtx[0][1] = invSqrtY * pMtx->mMtx[0][1]; pMtx->mMtx[1][1] = invSqrtY * pMtx->mMtx[1][1]; pMtx->mMtx[2][1] = invSqrtY * pMtx->mMtx[2][1]; f32 magZ = pMtx->mMtx[0][2] * pMtx->mMtx[0][2] + pMtx->mMtx[1][2] * pMtx->mMtx[1][2] + pMtx->mMtx[2][2] * pMtx->mMtx[2][2]; - f32 invSqrtZ = JGeometry::TUtil::inv_sqrt(magZ); + f32 invSqrtZ = JGeometry::TUtil< f32 >::inv_sqrt(magZ); pMtx->mMtx[0][2] = invSqrtZ * pMtx->mMtx[0][2]; pMtx->mMtx[1][2] = invSqrtZ * pMtx->mMtx[1][2]; pMtx->mMtx[2][2] = invSqrtZ * pMtx->mMtx[2][2]; @@ -692,7 +670,7 @@ namespace MR { f32 worldZ = axisX * pMtx->mMtx[2][0] + axisY * pMtx->mMtx[2][1] + axisZ * pMtx->mMtx[2][2]; TVec3f worldAxis; - worldAxis.set(worldX, worldY, worldZ); + worldAxis.set< f32 >(worldX, worldY, worldZ); TQuat4f quat; pMtx->getQuat(quat); @@ -835,9 +813,8 @@ namespace MR { ((TRot3f*)b)->getYDir(yDirB); bool result = false; - if (JGeometry::TUtil::epsilonEquals(yDirA.x, yDirB.x, 0.001f) && - JGeometry::TUtil::epsilonEquals(yDirA.y, yDirB.y, 0.001f) && - JGeometry::TUtil::epsilonEquals(yDirA.z, yDirB.z, 0.001f)) { + if (JGeometry::TUtil< f32 >::epsilonEquals(yDirA.x, yDirB.x, 0.001f) && JGeometry::TUtil< f32 >::epsilonEquals(yDirA.y, yDirB.y, 0.001f) && + JGeometry::TUtil< f32 >::epsilonEquals(yDirA.z, yDirB.z, 0.001f)) { result = true; } return result; @@ -944,37 +921,37 @@ namespace MR { MtxPtr first, second, third; switch (order) { - case 0: - first = mtxY; - second = mtxX; - third = mtxZ; - break; - case 1: - first = mtxZ; - second = mtxX; - third = mtxY; - break; - case 2: - first = mtxX; - second = mtxY; - third = mtxZ; - break; - case 3: - first = mtxZ; - second = mtxY; - third = mtxX; - break; - case 4: - first = mtxX; - second = mtxZ; - third = mtxZ; - break; - case 5: - default: - first = mtxY; - second = mtxZ; - third = mtxX; - break; + case 0: + first = mtxY; + second = mtxX; + third = mtxZ; + break; + case 1: + first = mtxZ; + second = mtxX; + third = mtxY; + break; + case 2: + first = mtxX; + second = mtxY; + third = mtxZ; + break; + case 3: + first = mtxZ; + second = mtxY; + third = mtxX; + break; + case 4: + first = mtxX; + second = mtxZ; + third = mtxZ; + break; + case 5: + default: + first = mtxY; + second = mtxZ; + third = mtxX; + break; } PSMTXConcat(first, second, dst); From a87a38df6813b266376e9c4c609eef986a182128 Mon Sep 17 00:00:00 2001 From: MrL314 <11429905+MrL314@users.noreply.github.com> Date: Sat, 21 Feb 2026 02:28:35 -0500 Subject: [PATCH 32/52] rename SDK files to match case (#1896) --- src/RVL_SDK/nwc24/{NWC24StdApi.c => NWC24StdAPI.c} | 0 src/RVL_SDK/wpad/{WPadMem.c => WPADMem.c} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/RVL_SDK/nwc24/{NWC24StdApi.c => NWC24StdAPI.c} (100%) rename src/RVL_SDK/wpad/{WPadMem.c => WPADMem.c} (100%) diff --git a/src/RVL_SDK/nwc24/NWC24StdApi.c b/src/RVL_SDK/nwc24/NWC24StdAPI.c similarity index 100% rename from src/RVL_SDK/nwc24/NWC24StdApi.c rename to src/RVL_SDK/nwc24/NWC24StdAPI.c diff --git a/src/RVL_SDK/wpad/WPadMem.c b/src/RVL_SDK/wpad/WPADMem.c similarity index 100% rename from src/RVL_SDK/wpad/WPadMem.c rename to src/RVL_SDK/wpad/WPADMem.c From ea12ab5cb214f6ac1fdf0d8ee1e5b97c11b62a61 Mon Sep 17 00:00:00 2001 From: shibbo Date: Sat, 21 Feb 2026 21:00:12 -0500 Subject: [PATCH 33/52] `NWC24MBoxCtrl` attempt --- .../include/revolution/nwc24/NWC24MBoxCtrl.h | 55 ++ .../include/revolution/nwc24/NWC24MsgObj.h | 2 +- .../include/revolution/nwc24/NWC24StdApi.h | 2 + src/RVL_SDK/nwc24/NWC24MBoxCtrl.c | 935 ++++++++++++++++++ 4 files changed, 993 insertions(+), 1 deletion(-) create mode 100644 src/RVL_SDK/nwc24/NWC24MBoxCtrl.c diff --git a/libs/RVL_SDK/include/revolution/nwc24/NWC24MBoxCtrl.h b/libs/RVL_SDK/include/revolution/nwc24/NWC24MBoxCtrl.h index 5abdd09de..892516360 100644 --- a/libs/RVL_SDK/include/revolution/nwc24/NWC24MBoxCtrl.h +++ b/libs/RVL_SDK/include/revolution/nwc24/NWC24MBoxCtrl.h @@ -9,6 +9,61 @@ extern "C" { NWC24Err NWC24iOpenMBox(void); +typedef struct MountInfoStruct { + u32 count; // 0x00 + s32 type; // 0x04 +} MountInfoStruct; + +typedef struct MBoxControlHeader { + u32 magic; // 0x00 + u32 version; // 0x04 + u32 msgCount; // 0x08 + u32 capacity; // 0x0C + u32 totalMsgSize; // 0x10 + u32 mailDataOffset; // 0x14 + u32 nextMsgId; // 0x18 + u32 nextFreeEntry; // 0x1C + u32 oldestMsgId; // 0x20 + u32 freeSpace; // 0x24 + char padding[0x58]; // to 0x80 +} MBoxControlHeader; + +typedef struct MBoxControlEntry { + u32 id; // 0x00 + u32 flags; // 0x04 + u32 length; // 0x08 + u32 appId; // 0x0C + u32 UNK_0x10; // 0x10 + u32 tag; // 0x14 + u32 ledPattern; // 0x18 + u32 nextFreeOrCreationMs; // 0x1C + u64 fromId; // 0x20 + u32 createTime; // 0x28 + u32 UNK_0x2C; // 0x2C + u8 numTo; // 0x30 + u8 numAttached; // 0x31 + u16 groupId; // 0x32 + u32 packedSubjectText; // 0x34 + u32 packedTextSubjectSize; // 0x38 + u32 packedSubjectTextSize; // 0x3C + u32 packedTextSizeContentType; // 0x40 + u32 packedContentTypeTransferEnc; // 0x44 + u32 textPtr; // 0x48 + u32 textSize; // 0x4C + u32 attached0Ptr; // 0x50 + u32 attached0Size; // 0x54 + u32 attached1Ptr; // 0x58 + u32 attached1Size; // 0x5C + u32 attached0OrigSize; // 0x60 + u32 attached1OrigSize; // 0x64 + u32 attached0_type; // 0x68 + u32 attached1_type; // 0x6C + u32 textOrigSize; // 0x70 + u32 UNK_0x74; // 0x74 + u32 UNK_0x78; // 0x78 + u32 UNK_0x7C; // 0x7C +} MBoxControlEntry; + #ifdef __cplusplus } #endif diff --git a/libs/RVL_SDK/include/revolution/nwc24/NWC24MsgObj.h b/libs/RVL_SDK/include/revolution/nwc24/NWC24MsgObj.h index ec8e2bfca..443dde2b7 100644 --- a/libs/RVL_SDK/include/revolution/nwc24/NWC24MsgObj.h +++ b/libs/RVL_SDK/include/revolution/nwc24/NWC24MsgObj.h @@ -34,7 +34,7 @@ typedef struct NWC24MsgObj { u32 flags; // at 0x4 u32 length; // at 0x8 u32 appId; // at 0xC - char UNK_0x10[0x4]; + s32 UNK_0x10; u32 tag; // at 0x14 u32 ledPattern; // at 0x18 u64 fromId; // at 0x20 diff --git a/libs/RVL_SDK/include/revolution/nwc24/NWC24StdApi.h b/libs/RVL_SDK/include/revolution/nwc24/NWC24StdApi.h index b198323e7..432bee4c7 100644 --- a/libs/RVL_SDK/include/revolution/nwc24/NWC24StdApi.h +++ b/libs/RVL_SDK/include/revolution/nwc24/NWC24StdApi.h @@ -10,6 +10,8 @@ extern "C" { void* Mail_memset(void* dst, int ch, size_t n); +size_t STD_strnlen(const char* str, size_t n); + #ifdef __cplusplus } #endif diff --git a/src/RVL_SDK/nwc24/NWC24MBoxCtrl.c b/src/RVL_SDK/nwc24/NWC24MBoxCtrl.c new file mode 100644 index 000000000..52cb7d3ee --- /dev/null +++ b/src/RVL_SDK/nwc24/NWC24MBoxCtrl.c @@ -0,0 +1,935 @@ +#include "revolution/nwc24/NWC24MBoxCtrl.h" +#include "revolution/nwc24.h" +#include "revolution/nwc24/NWC24FileApi.h" +#include "revolution/nwc24/NWC24Manage.h" +#include + +MountInfoStruct MountInfo; + +int Mail_sprintf(char* buffer, const char* format, ...); + +NWC24Err NWC24iOpenMBox(void); +NWC24Err NWC24iMBoxOpenNewMsg(s32 mboxType, NWC24File* file, u32* msgId); +NWC24Err NWC24iMBoxCloseMsg(NWC24File* file); +NWC24Err NWC24iMBoxCancelMsg(NWC24File* file, s32 mboxType, u32 msgId); +NWC24Err NWC24iMBoxAddMsgObj(s32 mboxType, NWC24MsgObj* msg); +NWC24Err NWC24iMBoxFlushHeader(s32 mboxType); +NWC24Err NWC24iMBoxCheck(s32 mboxType, u32 requiredSize); +static NWC24Err GetMBoxFilePath(char* buffer, s32 mboxType, u32 msgId); +static NWC24Err MakeMailPath(char* buffer, s32 mboxType); +static BOOL IsFileThere(const char* path); +NWC24Err DeleteMsg(s32 mboxType, u32 msgId, u32 flags); +NWC24Err DuplicationCheck(MBoxControlHeader* header, const NWC24MsgObj* msg, NWC24File* file, s32 mboxType); +NWC24Err GetCachedMBCHeader(s32 mboxType, MBoxControlHeader** headerOut); +static NWC24Err LoadMBCHeader(NWC24File* file, MBoxControlHeader* header); +static NWC24Err SaveMBCHeader(NWC24File* file, MBoxControlHeader* header); +NWC24Err AddMBCEntry(MBoxControlHeader* header, const NWC24MsgObj* msg, NWC24File* file); +static NWC24Err ClearMBCEntry(MBoxControlHeader* header, u32 offset, NWC24File* file); +static NWC24Err GetNewMsgId(MBoxControlHeader* header, u32* msgIdOut); +inline static s32 CompareMsgId(u32 id1, u32 id2); +NWC24Err MountVFMBox(s32 mboxType); +inline static NWC24Err UnmountVFMBox(void); +NWC24Err CopyMsgObjToMBCFmt(const NWC24MsgObj* src, MBoxControlEntry* dst); + +NWC24Err NWC24iOpenMBox(void) { + NWC24Err err; + MBoxControlHeader* header; + char* pathWork; + const char* mboxDir; + + pathWork = NWC24WorkP->pathWork; + + Mail_memset(NWC24WorkP->WORK_0x1100, 0, sizeof(MBoxControlHeader)); + err = GetCachedMBCHeader(0, &header); + if (err != NWC24_OK) { + return err; + } + + Mail_memset(NWC24WorkP->WORK_0x1180, 0, sizeof(MBoxControlHeader)); + err = GetCachedMBCHeader(1, &header); + if (err != NWC24_OK) { + return err; + } + + mboxDir = NWC24GetMBoxDir(); + if (STD_strnlen(mboxDir, 0x40) + 14 > 0x100) { + err = NWC24_ERR_NOMEM; + } else { + Mail_sprintf(pathWork, "%s%s", mboxDir, "/wc24recv.mbx"); + err = NWC24_OK; + } + + if (err != NWC24_OK) { + return err; + } + + err = IsFileThere(pathWork); + if (err != NWC24_OK) { + return err; + } + + mboxDir = NWC24GetMBoxDir(); + if (STD_strnlen(mboxDir, 0x40) + 14 > 0x100) { + err = NWC24_ERR_NOMEM; + } else { + Mail_sprintf(pathWork, "%s%s", mboxDir, "/wc24send.mbx"); + err = NWC24_OK; + } + + if (err != NWC24_OK) { + return err; + } + + err = IsFileThere(pathWork); + if (err != NWC24_OK) { + return err; + } + + MountInfo.count = 0; + MountInfo.type = 0; + return NWC24_OK; +} + +NWC24Err NWC24iMBoxOpenNewMsg(s32 mboxType, NWC24File* file, u32* msgId) { + NWC24Err err; + MBoxControlHeader* header; + char* path; + + err = GetCachedMBCHeader(mboxType, &header); + if (err != NWC24_OK) { + return err; + } + + err = GetNewMsgId(header, msgId); + if (err != NWC24_OK) { + return err; + } + + err = MountVFMBox(mboxType); + if (err != NWC24_OK) { + return err; + } + + path = NWC24WorkP->pathWork; + + err = GetMBoxFilePath(path, mboxType, *msgId); + if (err != NWC24_OK) { + return err; + } + + err = NWC24FOpen(file, path, 0x109); + return err; +} + +NWC24Err NWC24iMBoxCloseMsg(NWC24File* file) { + NWC24Err err; + u32 freeSize; + MBoxControlHeader* header; + s32 count; + NWC24Err unmountErr; + NWC24Err closeErr; + + closeErr = NWC24FClose(file); + // unmountErr = UnmountVFMBox(); + // This code could be replaced with a call to UnmountVFMBox but that causes issues with the assembly matching. + + count = MountInfo.count; + if (count == 0) { + unmountErr = NWC24_OK; + } else { + count--; + MountInfo.count = count; + if (count > 0) { + unmountErr = NWC24_OK; + } else { + err = GetCachedMBCHeader(MountInfo.type, &header); + if (err != NWC24_OK) { + unmountErr = err; + } else { + err = NWC24CheckSizeVF("@24", &freeSize); + if (err != NWC24_OK) { + unmountErr = err; + } else { + header->freeSpace = freeSize; + unmountErr = NWC24UnmountVF("@24"); + } + } + } + } + + if (closeErr != NWC24_OK && unmountErr != NWC24_OK) { + return unmountErr; + } + return closeErr; +} + +NWC24Err NWC24iMBoxCancelMsg(NWC24File* file, s32 mboxType, u32 msgId) { + s32 result; + char* pathWork; + NWC24Err tempErr; + NWC24Err deleteErr; + NWC24Err closeErr; + NWC24Err unmountErr; + + closeErr = NWC24FClose(file); + unmountErr = MountVFMBox(mboxType); + + if (unmountErr != NWC24_OK) { + result = unmountErr; + } else { + pathWork = NWC24WorkP->pathWork; + deleteErr = GetMBoxFilePath(pathWork, mboxType, msgId); + // TODO(Alex9303) Permuter fake(?)match + if ((deleteErr) != NWC24_OK) { + result = deleteErr; + } else { + deleteErr = NWC24FDeleteVF(pathWork); + tempErr = deleteErr; + unmountErr = UnmountVFMBox(); + if (tempErr != NWC24_OK) { + result = tempErr; + } else { + result = unmountErr; + } + } + } + + MountInfo.count = 1; + + unmountErr = UnmountVFMBox(); + if (closeErr != NWC24_OK) { + return closeErr; + } + if (result != NWC24_OK) { + return result; + } + if (unmountErr != NWC24_OK) { + return unmountErr; + } + return NWC24_OK; +} + +NWC24Err NWC24iMBoxAddMsgObj(s32 mboxType, NWC24MsgObj* msg) { + NWC24Err err; + NWC24Err closeErr; + MBoxControlHeader* header; + MBoxControlHeader* header2; + char* pathWork; + NWC24File file; + + err = GetCachedMBCHeader(mboxType, &header); + if (err != NWC24_OK) { + return err; + } + + if (header->msgCount == header->capacity) { + return NWC24_ERR_FULL; + } + + pathWork = NWC24WorkP->pathWork; + err = MakeMailPath(pathWork, mboxType); + if (err != NWC24_OK) { + return err; + } + + err = NWC24FOpen(&file, pathWork, 4); + if (err != NWC24_OK) { + return err; + } + + err = AddMBCEntry(header, msg, &file); + if (err == NWC24_OK) { + err = DuplicationCheck(header, msg, &file, mboxType); + if (err == NWC24_OK) { + header2 = header; + err = NWC24FSeek(&file, 0, NWC24_SEEK_BEG); + + if (err != NWC24_OK) { + return err; + } + + err = NWC24FWrite(header2, sizeof(MBoxControlHeader), &file); + } + } + + closeErr = NWC24FClose(&file); + if (err != NWC24_OK) { + return err; + } + + return closeErr; +} + +NWC24Err NWC24iMBoxFlushHeader(s32 mboxType) { + NWC24Err err; + NWC24Err closeErr; + MBoxControlHeader* header; + char* pathWork; + NWC24File file; + + err = GetCachedMBCHeader(mboxType, &header); + if (err != NWC24_OK) { + return err; + } + + pathWork = NWC24WorkP->pathWork; + err = MakeMailPath(pathWork, mboxType); + if (err != NWC24_OK) { + return err; + } + + err = NWC24FOpen(&file, pathWork, 4); + if (err != NWC24_OK) { + return err; + } + + err = SaveMBCHeader(&file, header); + closeErr = NWC24FClose(&file); + + if (err != NWC24_OK) { + return err; + } + + return closeErr; +} + +NWC24Err NWC24iMBoxCheck(s32 mboxType, u32 requiredSize) { + NWC24Err err; + MBoxControlHeader* header; + volatile long oldestMsgId; + u32 spaceWithBuffer; + + if (requiredSize >= 0x31C00) { + return NWC24_ERR_OVERFLOW; + } + + spaceWithBuffer = requiredSize + 0x4000; + + err = GetCachedMBCHeader(mboxType, &header); + if (err != NWC24_OK) { + return err; + } + + if (mboxType == 0) { + if (header->msgCount >= header->capacity) { + return NWC24_ERR_FULL; + } + if (header->freeSpace <= spaceWithBuffer) { + return NWC24_ERR_FULL; + } + } else if (mboxType == 1) { + while (header->msgCount >= header->capacity || header->freeSpace <= spaceWithBuffer) { + oldestMsgId = header->oldestMsgId; + err = DeleteMsg(mboxType, oldestMsgId, 0); + if (err != NWC24_OK) { + return err; + } + + err = GetCachedMBCHeader(mboxType, &header); + if (err != NWC24_OK) { + return err; + } + } + } else { + return NWC24_ERR_INVALID_VALUE; + } + return NWC24_OK; +} + +static NWC24Err GetMBoxFilePath(char* buffer, s32 mboxType, u32 msgId) { + const char* workDir; + NWC24Err err; + + switch (mboxType) { + case 0: + Mail_sprintf(buffer, "@24:/mb/s%07d.msg", msgId); + break; + case 1: + Mail_sprintf(buffer, "@24:/mb/r%07d.msg", msgId); + break; + default: + return NWC24_ERR_INVALID_VALUE; + } + return NWC24_OK; +} + +static NWC24Err MakeMailPath(char* buffer, s32 mboxType) { + const char* mboxDir = NWC24GetMBoxDir(); + s32 pathLen = STD_strnlen(mboxDir, 0x40); + + if (pathLen + 14 > 0x100) { + return NWC24_ERR_NOMEM; + } else { + switch (mboxType) { + case 0: + Mail_sprintf(buffer, "%s%s", mboxDir, "/wc24send.ctl"); + break; + case 1: + Mail_sprintf(buffer, "%s%s", mboxDir, "/wc24recv.ctl"); + break; + default: + return NWC24_ERR_INVALID_VALUE; + } + return NWC24_OK; + } +} + +static BOOL IsFileThere(const char* path) { + NWC24File file; + NWC24Err err; + + // NEW IN SMG1 -- checks if the open was successful before closing + err = NWC24FOpen(&file, path, NWC24_SEEK_END); + if (err == NWC24_OK) { + return NWC24FClose(&file); + } + return err; +} + +NWC24Err DeleteMsg(s32 mboxType, u32 msgId, u32 flags) { + NWC24Err err; + const char* mboxDir; + MBoxControlHeader* header; + u32 entryOffsetToDelete = 0; + MBoxControlHeader* header3; + NWC24File file; + s32 pathLen; + u32 offset; + char* pathWorkCopy; + MBoxControlHeader* header2; + int cmp; + u32 checkedCount = 0; + u32 oldestMsgId = 0; + MBoxControlEntry* entry; + NWC24Err mountErr = NWC24_OK; + NWC24Err writeErr = NWC24_OK; + NWC24Err deleteErr = NWC24_OK; + char* pathWork; + + if (!NWC24IsMsgLibOpened() && !NWC24IsMsgLibOpenedByTool()) { + return NWC24_ERR_LIB_NOT_OPENED; + } + entry = (MBoxControlEntry*)((char*)NWC24WorkP + 0x1200); + + err = GetCachedMBCHeader(mboxType, &header); + if (err != NWC24_OK) { + return err; + } + + pathWorkCopy = NWC24WorkP->pathWork; + pathWork = pathWorkCopy; + + err = MakeMailPath(pathWork, mboxType); + if (err != NWC24_OK) { + return err; + } + + err = NWC24FOpen(&file, pathWork, 4); + if (err != NWC24_OK) { + return err; + } + + err = NWC24_ERR_NOT_FOUND; + + for (offset = sizeof(MBoxControlHeader); offset < header->mailDataOffset; offset += sizeof(MBoxControlHeader)) { + NWC24Err readErr; + NWC24FSeek(&file, offset, NWC24_SEEK_BEG); + readErr = NWC24FRead(entry, sizeof(MBoxControlHeader), &file); + if (readErr != NWC24_OK) { + err = readErr; + break; + } + + if (entry->id == 0) { + continue; + } + + entryOffsetToDelete++; + + if (entry->id == msgId) { + if (flags != 0) { + if ((entry->flags & 0x2) != 0) { + if (NWC24GetAppId() - 0x48410000 != 0x4541) { + err = NWC24_ERR_PROTECTED; + break; + } + } else { + if ((entry->appId & 0xFFFFFF00) != (NWC24GetAppId() & 0xFFFFFF00)) { + if ((entry->flags & 0x8) != 0) { + if (NWC24GetAppId() - 0x48410000 == 0x4541) { + goto permission_ok; + } + } + err = NWC24_ERR_PROTECTED; + break; + } + } + } + permission_ok: + + checkedCount = offset; + err = NWC24_OK; + continue; + } + + if (oldestMsgId != 0) { + if (CompareMsgId(oldestMsgId, entry->id) <= 0) { + continue; + } + } + oldestMsgId = entry->id; + } + + if (err == NWC24_ERR_NOT_FOUND) { + if (header->msgCount != entryOffsetToDelete) { + header->msgCount = entryOffsetToDelete; + + // TODO(Alex9303) Fakematch: (possibly) Missing inline function + header3 = header; + NWC24FSeek(&file, 0, NWC24_SEEK_BEG); + NWC24FWrite(header3, sizeof(MBoxControlHeader), &file); + } + } + + if (err != NWC24_OK) { + NWC24FClose(&file); + + if (msgId == 0) { + err = NWC24_ERR_INVALID_VALUE; + } + + return err; + } + + header->oldestMsgId = oldestMsgId; + + writeErr = ClearMBCEntry(header, checkedCount, &file); + + mountErr = MountVFMBox(mboxType); + switch (mountErr) { + case NWC24_OK: + pathWork = NWC24WorkP->pathWork; + mountErr = GetMBoxFilePath(pathWork, mboxType, msgId); + switch (mountErr) { + case NWC24_OK: + deleteErr = NWC24FDeleteVF(pathWork); + mountErr = UnmountVFMBox(); + if (deleteErr != NWC24_OK) { + mountErr = deleteErr; + } + break; + } + break; + } + + // TODO(Alex9303) Fakematch: Reusing arguments msgId/mboxType as error variables to match r23/r22 + msgId = mountErr; + if (writeErr != NWC24_OK) { + msgId = writeErr; + } + + // TODO(Alex9303) Fakematch: (possibly) Missing inline function + header2 = header; + NWC24FSeek(&file, 0, NWC24_SEEK_BEG); + + mboxType = NWC24FWrite(header2, sizeof(MBoxControlHeader), &file); + if (msgId != NWC24_OK) { + mboxType = msgId; + } + + err = NWC24FClose(&file); + if (mboxType != NWC24_OK) { + err = mboxType; + } + + return err; +} + +NWC24Err DuplicationCheck(MBoxControlHeader* header, const NWC24MsgObj* msg, NWC24File* file, s32 mboxType) { + NWC24Err err; + u32 offset; + u32 checkedCount; + u32 bestMsgId; + u32 bestOffset; + u32 oldestMsgId; + MBoxControlEntry* entry; + char* pathWork; + char** pathWorkPtr; + + err = NWC24_OK; + checkedCount = 0; + bestMsgId = 0; + bestOffset = 0; + oldestMsgId = 0; + + pathWorkPtr = &pathWork; + + if (mboxType == 0) { + return NWC24_OK; + } + + entry = (MBoxControlEntry*)((char*)NWC24WorkP + 0x1200); + + for (offset = sizeof(MBoxControlHeader); offset < header->mailDataOffset; offset += sizeof(MBoxControlHeader)) { + int isDuplicate; + int cmp; + + if (checkedCount >= header->msgCount) { + break; + } + + NWC24FSeek(file, offset, NWC24_SEEK_BEG); + err = NWC24FRead(entry, sizeof(MBoxControlHeader), file); + if (err != NWC24_OK) { + break; + } + + if (entry->id == 0) { + continue; + } + + checkedCount++; + isDuplicate = 1; + + if (entry->id == msg->id) { + isDuplicate = 0; + } + + if ((entry->flags & msg->flags & 1) != 0) { + if (entry->appId != msg->appId) { + isDuplicate = 0; + } + if (entry->fromId != msg->fromId) { + isDuplicate = 0; + } + } + + if (isDuplicate) { + u32 msgTag = msg->tag & 0xFFFF; + u32 msgCreationMs; + + if (msgTag != 0) { + if ((entry->tag & 0xFFFF) == msgTag) { + bestMsgId = entry->id; + bestOffset = offset; + continue; + } + } + + msgCreationMs = ((const u32*)msg)[7]; + if (msgCreationMs != 0 && entry->nextFreeOrCreationMs == msgCreationMs && entry->flags == msg->flags && entry->length == msg->length && + entry->UNK_0x10 == ((const u32*)msg)[4] && (s32)entry->createTime == (s32)((const u32*)msg)[10]) { + bestMsgId = entry->id; + bestOffset = offset; + continue; + } + } + + if (oldestMsgId != 0) { + if (CompareMsgId(oldestMsgId, entry->id) <= 0) { + continue; + } + } + oldestMsgId = entry->id; + } + + if (err != NWC24_OK) { + return err; + } + + header->oldestMsgId = oldestMsgId; + + if (bestMsgId != 0) { + NWC24Err writeErr; + NWC24Err result; + + entry = (MBoxControlEntry*)(((char*)NWC24WorkP) + 0x1200); + pathWork = NWC24WorkP->WORK_0x1200; + + err = NWC24FSeek(file, bestOffset, NWC24_SEEK_BEG); + err = NWC24FRead(*pathWorkPtr, sizeof(MBoxControlHeader), file); + + header->msgCount--; + header->totalMsgSize -= entry->length; + + memset(entry, 0, sizeof(MBoxControlHeader)); + entry->appId = header->nextFreeEntry; + header->nextFreeEntry = bestOffset; + + err = NWC24FSeek(file, bestOffset, NWC24_SEEK_BEG); + writeErr = NWC24FWrite(entry, sizeof(MBoxControlHeader), file); + + err = MountVFMBox(mboxType); + if (err != NWC24_OK) { + result = err; + } else { + pathWork = NWC24WorkP->pathWork; + err = GetMBoxFilePath(pathWork, mboxType, bestMsgId); + if (err != NWC24_OK) { + result = err; + } else { + NWC24Err deleteErr = NWC24FDeleteVF(pathWork); + + result = UnmountVFMBox(); + if (deleteErr != NWC24_OK) { + result = deleteErr; + } + } + } + + if (writeErr != NWC24_OK) { + result = writeErr; + } + + return result; + } + + return err; +} + +NWC24Err GetCachedMBCHeader(s32 mboxType, MBoxControlHeader** headerOut) { + NWC24Err err; + const char* mboxDir; + NWC24File file; + NWC24Err result = NWC24_OK; + char* pathWork; + + if (mboxType == 0) { + *headerOut = (MBoxControlHeader*)NWC24WorkP->WORK_0x1100; + } else if (mboxType == 1) { + *headerOut = (MBoxControlHeader*)NWC24WorkP->WORK_0x1180; + } else { + *headerOut = 0; + return NWC24_ERR_INVALID_VALUE; + } + + if ((*headerOut)->magic != 0x57635466) { + pathWork = NWC24WorkP->pathWork; + err = MakeMailPath(pathWork, mboxType); + if (err != NWC24_OK) { + return err; + } + + err = NWC24FOpen(&file, pathWork, 2); + if (err != NWC24_OK) { + return err; + } + + result = LoadMBCHeader(&file, *headerOut); + err = NWC24FClose(&file); + if (result == NWC24_OK) { + if (err != NWC24_OK) { + result = err; + } + } + } + + if ((*headerOut)->version != 4) { + result = NWC24_ERR_VER_MISMATCH; + } + return result; +} + +static NWC24Err LoadMBCHeader(NWC24File* file, MBoxControlHeader* header) { + NWC24Err err; + + NWC24FSeek(file, 0, NWC24_SEEK_BEG); + err = NWC24FRead(header, sizeof(MBoxControlHeader), file); + if (err != NWC24_OK) { + return err; + } + + if (header->magic != 0x57635466) { + return NWC24_ERR_BROKEN; + } + + return NWC24_OK; +} + +static NWC24Err SaveMBCHeader(NWC24File* file, MBoxControlHeader* header) { + NWC24Err err = NWC24FSeek(file, 0, NWC24_SEEK_BEG); + if (err != NWC24_OK) { + return err; + } + + return NWC24FWrite(header, sizeof(MBoxControlHeader), file); +} + +NWC24Err AddMBCEntry(MBoxControlHeader* header, const NWC24MsgObj* msg, NWC24File* file) { + s32 entryOffset = header->nextFreeEntry; + MBoxControlEntry* entryBuffer; + s32 nextEntryOffset; + NWC24Err err; + + entryBuffer = (MBoxControlEntry*)NWC24WorkP->WORK_0x1200; + + if (entryOffset == 0) { + return NWC24_ERR_FULL; + } + + if ((u32)entryOffset >= header->mailDataOffset || ((entryOffset - sizeof(MBoxControlHeader)) & 0x7F) != 0) { + return NWC24_ERR_BROKEN; + } + + NWC24FSeek(file, entryOffset, NWC24_SEEK_BEG); + + err = NWC24FRead(entryBuffer, sizeof(MBoxControlEntry), file); + if (err != NWC24_OK) { + return err; + } + + nextEntryOffset = entryBuffer->appId; + + if ((u32)nextEntryOffset >= header->mailDataOffset || ((nextEntryOffset - sizeof(MBoxControlHeader)) & 0x7F) != 0) { + return NWC24_ERR_BROKEN; + } + + header->nextFreeEntry = nextEntryOffset; + CopyMsgObjToMBCFmt(msg, entryBuffer); + + NWC24FSeek(file, entryOffset, NWC24_SEEK_BEG); + + err = NWC24FWrite(entryBuffer, sizeof(MBoxControlEntry), file); + if (err != NWC24_OK) { + return err; + } + + if (header->msgCount == 0) { + header->oldestMsgId = msg->id; + } + + header->msgCount++; + header->totalMsgSize += msg->length; + return NWC24_OK; +} + +static NWC24Err ClearMBCEntry(MBoxControlHeader* header, u32 offset, NWC24File* file) { + MBoxControlEntry* entryBuffer; + + entryBuffer = (MBoxControlEntry*)NWC24WorkP->WORK_0x1200; + NWC24FSeek(file, offset, NWC24_SEEK_BEG); + NWC24FRead(entryBuffer, sizeof(MBoxControlEntry), file); + + header->msgCount--; + header->totalMsgSize -= entryBuffer->length; + + memset(entryBuffer, 0, sizeof(MBoxControlEntry)); + entryBuffer->appId = header->nextFreeEntry; + header->nextFreeEntry = offset; + + NWC24FSeek(file, offset, NWC24_SEEK_BEG); + return NWC24FWrite(entryBuffer, sizeof(MBoxControlEntry), file); +} + +NWC24Err GetNewMsgId(MBoxControlHeader* header, u32* msgIdOut) { + if (header->magic != 0x57635466) { + return NWC24_ERR_INVALID_VALUE; + } + + if (header->nextMsgId > 1000000) { + header->nextMsgId = 1; + } + + *msgIdOut = header->nextMsgId; + header->nextMsgId++; + + return NWC24_OK; +} + +static s32 CompareMsgId(u32 id1, u32 id2) { + if (id1 == id2) { + return 0; + } else if (id1 > 900000 && id2 < 100000) { + return -1; + } else if (id1 < 100000 && id2 > 900000) { + return 1; + } else if (id1 > id2) { + return 1; + } else { + return -1; + } +} + +NWC24Err MountVFMBox(s32 mboxType) { + s32 result; + NWC24Err err; + const char* mboxDir; + char* pathWork; + + if (MountInfo.count != 0 && MountInfo.type != mboxType) { + MountInfo.count = 1; + UnmountVFMBox(); + return NWC24_ERR_FATAL; + } + + if ((s32)(++MountInfo.count) > 1) { + return NWC24_OK; + } + + pathWork = NWC24WorkP->pathWork; + result = MakeMailPath(pathWork, mboxType); + if (result != NWC24_OK) { + return result; + } + + result = NWC24_OK; + err = NWC24MountVF("@24", pathWork); + if (err != result) { + return err; + } else { + err = result; + MountInfo.type = mboxType; + } + + return err; +} + +NWC24Err CopyMsgObjToMBCFmt(const NWC24MsgObj* src, MBoxControlEntry* dst) { + u32 packData30 = (((u32)src->DATA_0x30.ptr) & 0xFFFFF) | (src->DATA_0x30.size << 20); + u32 packData38 = (((u32)src->DATA_0x38.ptr) & 0xFFFFF) | (src->DATA_0x38.size << 20); + u32 packSubject = (((u32)src->subject.ptr) & 0xFFFFF) | (src->subject.size << 20); + u32 packContent = (((u32)src->DATA_0x50.ptr) & 0xFFFFF) | (src->DATA_0x50.size << 20); + u32 packTransfer = (((u32)src->DATA_0x58.ptr) & 0xFFFFF) | (src->DATA_0x58.size << 20); + + dst->id = src->id; + dst->flags = src->flags; + dst->length = src->length; + dst->appId = src->appId; + *(u32*)&dst->UNK_0x10 = src->UNK_0x10; + dst->tag = src->tag; + dst->ledPattern = src->ledPattern; + dst->nextFreeOrCreationMs = *(const u32*)((const u8*)src + 0x1C); + ((u32*)&dst->fromId)[0] = ((u32*)&src->fromId)[0]; + + ((u32*)&dst->fromId)[1] = ((u32*)&src->fromId)[1]; + + dst->createTime = src->WORD_0x28; + dst->UNK_0x2C = src->WORD_0x2C; + + *(u8*)&dst->numTo = src->numTo; + *(u8*)((u8*)dst + 0x31) = src->numAttached; + *(u16*)((u8*)dst + 0x32) = src->groupId; + + dst->packedSubjectText = packData30; + dst->packedTextSubjectSize = packData38; + dst->packedSubjectTextSize = packSubject; + dst->packedTextSizeContentType = packContent; + dst->packedContentTypeTransferEnc = packTransfer; + + dst->textPtr = (u32)src->text.ptr; + dst->textSize = src->text.size; + dst->textOrigSize = *(const u32*)((const u8*)src + 0xE8); + dst->UNK_0x74 = *(const u32*)((const u8*)src + 0xEC); + + dst->attached0Ptr = (u32)src->attached[0].ptr; + dst->attached0Size = src->attached[0].size; + dst->attached0OrigSize = src->attachedSize[0]; + dst->attached0_type = src->attachedType[0]; + + dst->attached1Ptr = (u32)src->attached[1].ptr; + dst->attached1Size = src->attached[1].size; + dst->attached1OrigSize = src->attachedSize[1]; + dst->attached1_type = src->attachedType[1]; + + return NWC24_OK; +} From 0a1d75ce033ac357be645b1dd7166157a8ba01f4 Mon Sep 17 00:00:00 2001 From: MrL314 <11429905+MrL314@users.noreply.github.com> Date: Mon, 23 Feb 2026 17:11:10 -0500 Subject: [PATCH 34/52] `BombHei` at 99% --- config/RMGK01/symbols.txt | 21 +- include/Game/Enemy/BombHei.hpp | 66 +- include/Game/Util/ActorMovementUtil.hpp | 2 +- .../include/JSystem/JGeometry/TMatrix.hpp | 34 + .../include/JSystem/JGeometry/TVec.hpp | 29 + src/Game/Enemy/BombHei.cpp | 817 +++++++++++++++++- 6 files changed, 959 insertions(+), 10 deletions(-) diff --git a/config/RMGK01/symbols.txt b/config/RMGK01/symbols.txt index 6af72b601..16ebc2414 100644 --- a/config/RMGK01/symbols.txt +++ b/config/RMGK01/symbols.txt @@ -46711,9 +46711,11 @@ __vt__Q215NrvBombBirdBomb20HostTypeNrvExplosion = .data:0x8057AB9C; // type:obje __vt__Q215NrvBombBirdBomb15HostTypeNrvWait = .data:0x8057ABAC; // type:object size:0x10 scope:global align:4 __vt__Q215NrvBombBirdBomb15HostTypeNrvHold = .data:0x8057ABBC; // type:object size:0x10 scope:global align:4 @64268 = .data:0x8057ABD0; // type:object size:0xC scope:local align:4 data:4byte -lbl_8057ABDC = .data:0x8057ABDC; // type:object size:0xD +lbl_8057ABDC = .data:0x8057ABDC; // type:object size:0x5 data:string +lbl_8057ABE1 = .data:0x8057ABE1; // type:object size:0x8 data:string lbl_8057ABE9 = .data:0x8057ABE9; // type:object size:0x5 data:string -lbl_8057ABEE = .data:0x8057ABEE; // type:object size:0xD +lbl_8057ABEE = .data:0x8057ABEE; // type:object size:0x8 data:string +lbl_8057ABF6 = .data:0x8057ABF6; // type:object size:0x5 data:string lbl_8057ABFB = .data:0x8057ABFB; // type:object size:0x7 data:string lbl_8057AC02 = .data:0x8057AC02; // type:object size:0x5 data:string lbl_8057AC07 = .data:0x8057AC07; // type:object size:0x5 data:string @@ -46723,8 +46725,19 @@ lbl_8057AC1A = .data:0x8057AC1A; // type:object size:0xA data:string lbl_8057AC24 = .data:0x8057AC24; // type:object size:0x12 data:string lbl_8057AC36 = .data:0x8057AC36; // type:object size:0x5 data:string lbl_8057AC3B = .data:0x8057AC3B; // type:object size:0x8 data:string -lbl_8057AC43 = .data:0x8057AC43; // type:object size:0x39 -lbl_8057AC7C = .data:0x8057AC7C; // type:object size:0xA3 +lbl_8057AC43 = .data:0x8057AC43; // type:object size:0x16 data:string +lbl_8057AC59 = .data:0x8057AC59; // type:object size:0xC data:string +lbl_8057AC65 = .data:0x8057AC65; // type:object size:0x11 data:string +lbl_8057AC76 = .data:0x8057AC76; // type:object size:0x6 data:string +lbl_8057AC7C = .data:0x8057AC7C; // type:object size:0x6 data:string +lbl_8057AC82 = .data:0x8057AC82; // type:object size:0xE data:string +lbl_8057AC90 = .data:0x8057AC90; // type:object size:0x10 data:string +lbl_8057ACA0 = .data:0x8057ACA0; // type:object size:0xA data:string +lbl_8057ACAA = .data:0x8057ACAA; // type:object size:0x15 data:string +lbl_8057ACBF = .data:0x8057ACBF; // type:object size:0x13 data:string +lbl_8057ACD2 = .data:0x8057ACD2; // type:object size:0x19 data:string +lbl_8057ACEB = .data:0x8057ACEB; // type:object size:0x1B data:string +lbl_8057AD06 = .data:0x8057AD06; // type:object size:0x19 data:string lbl_8057AD1F = .data:0x8057AD1F; // type:object size:0x11 data:string __vt__31JointControlDelegator<7BombHei> = .data:0x8057AD30; // type:object size:0x14 scope:global align:4 __vt__7BombHei = .data:0x8057AD44; // type:object size:0x78 scope:global align:4 diff --git a/include/Game/Enemy/BombHei.hpp b/include/Game/Enemy/BombHei.hpp index 2a827a0a2..0653d9e03 100644 --- a/include/Game/Enemy/BombHei.hpp +++ b/include/Game/Enemy/BombHei.hpp @@ -1,14 +1,74 @@ #pragma once -#include "Game/NameObj/NameObj.hpp" #include "Game/LiveActor/LiveActor.hpp" +class AnimScaleController; +class WalkerStateBindStarPointer; +class JointController; class BombHei : public LiveActor { public: BombHei(const char*); - virtual ~BombHei(); + + enum Type { BOMB_HEI = 0, BOMB = 1 }; + + virtual void init(const JMapInfoIter& rIter); + virtual void appear(); + virtual void kill(); + virtual void control(); + virtual void calcAndSetBaseMtx(); + virtual void attackSensor(HitSensor* pSender, HitSensor* pReceiver); + virtual bool receiveMsgPush(HitSensor* pSender, HitSensor* pReceiver); + virtual bool receiveMsgPlayerAttack(u32 msg, HitSensor* pSender, HitSensor* pReceiver); + virtual bool receiveMsgEnemyAttack(u32 msg, HitSensor* pSender, HitSensor* pReceiver); + virtual bool receiveMsgThrow(HitSensor* pSender, HitSensor* pReceiver); + virtual bool receiveOtherMsg(u32 msg, HitSensor* pSender, HitSensor* pReceiver); + + void setGroupClipping(const JMapInfoIter& rIter); + void initAfterPlacement(); + void startCountdown(); + void endCountdown(); + + void exeLaunch(); + void exeStarting(); + void exeWait(); + void exeWalk(); + void exePursue(); + void exePursueHit(); + void exeSpinHit(); + void endSpinHit(); + void exeTrample(); + void exePhysics(); + void exeStop(); + void exeTaken(); + void endTaken(); + void exeThrown(); + void endThrown(); + void exeExplode(); + void exeBindStarPointer(); + void endBindStarPointer(); + + bool calcJoint(TPos3f*, const JointControllerInfo&); + void startBoundSound(); private: - u8 mPad[(0xE0) - sizeof(LiveActor)]; + /* 0x8C */ AnimScaleController* mScaleController; + /* 0x90 */ WalkerStateBindStarPointer* mBindStarPointerState; + /* 0x94 */ TQuat4f mRotQuat; + /* 0xA4 */ TVec3f mFront; + /* 0xB0 */ TVec3f mBinderOffset; + /* 0xBC */ TVec3f mTargetFront; + /* 0xC8 */ s32 mCountdown; + /* 0xCC */ HitSensor* mCarrySensor; + /* 0xD0 */ f32 mExplodeRadius; + /* 0xD4 */ JointController* mBodyJoint; + /* 0xD8 */ Type mType; + /* 0xDC */ bool mExplosionIgnoreCollision; +}; + +struct BombHeiParam { + /* 0x00 */ f32 mSpeedH; + /* 0x04 */ f32 mGravAccel; + /* 0x08 */ f32 mFriction; + /* 0x0C */ f32 mTurnRate; }; diff --git a/include/Game/Util/ActorMovementUtil.hpp b/include/Game/Util/ActorMovementUtil.hpp index 44f838d90..e8b3a2fc4 100644 --- a/include/Game/Util/ActorMovementUtil.hpp +++ b/include/Game/Util/ActorMovementUtil.hpp @@ -96,7 +96,7 @@ namespace MR { bool addVelocityLimit(LiveActor*, const TVec3f&); void setVelocityJump(LiveActor*, f32); void addVelocityToGravity(LiveActor*, f32) NO_INLINE; - void addVelocityToGraviyOrGround(LiveActor*, f32); + void addVelocityToGravityOrGround(LiveActor*, f32); bool addVelocityToCollisionNormal(LiveActor*, f32); void addVelocityKeepHeight(LiveActor*, const TVec3f&, f32, f32); void addVelocityKeepHeight(LiveActor*, const TVec3f&, f32, f32, f32); diff --git a/libs/JSystem/include/JSystem/JGeometry/TMatrix.hpp b/libs/JSystem/include/JSystem/JGeometry/TMatrix.hpp index b05d8b63d..661cc72a2 100644 --- a/libs/JSystem/include/JSystem/JGeometry/TMatrix.hpp +++ b/libs/JSystem/include/JSystem/JGeometry/TMatrix.hpp @@ -349,6 +349,18 @@ namespace JGeometry { this->mMtx[2][2] = rSrcZ.z; } + inline void setXYZDirInline2(const TVec3f& rSrcX, const TVec3f& rSrcY, const TVec3f& rSrcZ) { + this->mMtx[0][0] = rSrcX.x; + this->mMtx[0][1] = rSrcX.y; + this->mMtx[0][2] = rSrcX.z; + this->mMtx[1][0] = rSrcY.x; + this->mMtx[1][1] = rSrcY.y; + this->mMtx[1][2] = rSrcY.z; + this->mMtx[2][0] = rSrcZ.x; + this->mMtx[2][1] = rSrcZ.y; + this->mMtx[2][2] = rSrcZ.z; + } + inline void getXYZDirInline(TVec3f& rDstX, TVec3f& rDstY, TVec3f& rDstZ) { f32 z1 = this->mMtx[2][0]; f32 y1 = this->mMtx[1][0]; @@ -583,6 +595,10 @@ namespace JGeometry { return get(x, y); } + operator TMatrix34< T >() const { + return *(TMatrix34< T >*)this; + } + inline void getTransInline(TVec3f& rDest) const { f32 z = this->mMtx[2][3]; f32 y = this->mMtx[1][3]; @@ -610,6 +626,24 @@ namespace JGeometry { this->mMtx[2][3] = a1.z; } + inline void setTransInline(const TVec3f& a1) { + this->mMtx[0][3] = a1.x; + this->mMtx[1][3] = a1.y; + this->mMtx[2][3] = a1.z; + } + + inline void zeroTransInline() { + this->mMtx[0][3] = 0.0f; + this->mMtx[1][3] = 0.0f; + this->mMtx[2][3] = 0.0f; + } + + inline void zeroTransInline2() { + this->mMtx[0][3] = 0.0f; + this->mMtx[1][3] = 0.0f; + this->mMtx[2][3] = 0.0f; + } + inline void setVecAndTransInline(const TVec3f& a1, const TVec3f& a2, const TVec3f& a3, const TVec3f& a4) { this->mMtx[0][0] = a1.x; this->mMtx[1][0] = a1.y; diff --git a/libs/JSystem/include/JSystem/JGeometry/TVec.hpp b/libs/JSystem/include/JSystem/JGeometry/TVec.hpp index c8661913a..77c6dd971 100644 --- a/libs/JSystem/include/JSystem/JGeometry/TVec.hpp +++ b/libs/JSystem/include/JSystem/JGeometry/TVec.hpp @@ -323,6 +323,13 @@ namespace JGeometry { return ret; } + // multiple copies of multiplyOperatorInline in the same instruction path dont behave well + TVec3 multiplyOperatorInline2(f32 scalar) const { + TVec3 ret(*this); + ret *= scalar; + return ret; + } + // appears to be needed in RingBeam to match stack in some places TVec3 scaleInline(f32 scalar) const { TVec3 ret(*this); @@ -339,6 +346,13 @@ namespace JGeometry { return ret; } + // in cases where multInline is used twice in the same instruction path + inline TVec3 multInLine2(f32 val) const { + TVec3 ret(*this); + ret.mult(val); + return ret; + } + TVec3 operator-() const; bool operator==(const TVec3& rVec) const { @@ -390,6 +404,12 @@ namespace JGeometry { return this; } + inline TVec3 subOtherInline(const TVec3& op) const { + TVec3 ret(*this); + ret -= op; + return ret; + } + template < typename T > void set(const TVec3< T >& rVec) { x = rVec.x; @@ -438,6 +458,12 @@ namespace JGeometry { mulInternal(&src1.x, &src2.x, &dest.x); } + TVec3 mult(const Vec& rOther) { + TVec3 ret; + mulInternal(&this->x, &rOther.x, &ret.x); + return ret; + } + template < typename T > void setAll(f32); @@ -792,6 +818,9 @@ namespace JGeometry { void getEuler(TVec3< T >& rDest) const; void setEuler(T _x, T _y, T _z); + void setEulerDegree(T _x, T _y, T _z) { + setEuler(_x * PI_180, _y * PI_180, _z * PI_180); + } void setEulerZ(T _z); void setRotate(const TVec3< f32 >& rA, const TVec3< f32 >& rB, f32 ratio) { diff --git a/src/Game/Enemy/BombHei.cpp b/src/Game/Enemy/BombHei.cpp index 954dc763e..8a3d74c68 100644 --- a/src/Game/Enemy/BombHei.cpp +++ b/src/Game/Enemy/BombHei.cpp @@ -1,5 +1,818 @@ #include "Game/Enemy/BombHei.hpp" +#include "Game/Enemy/AnimScaleController.hpp" +#include "Game/Enemy/WalkerStateBindStarPointer.hpp" +#include "Game/LiveActor/Binder.hpp" +#include "Game/LiveActor/HitSensor.hpp" +#include "Game/Map/CollisionParts.hpp" -BombHei::BombHei(const char* pName) : LiveActor(pName) {} -BombHei::~BombHei() {} +namespace { + static const s32 hStartBrkTime = 600; + static const s32 hBrkRateUpTime = 120; + static const f32 hBrkSlowRate = 0.5f; + static const f32 hBrkFastRate = 2.0f; + static const f32 hTurnLimitRadian = 3.0f; + static const f32 hGravity = 1.0f; + static const f32 hGravityPhysicsOnGround = 0.5f; + static const f32 hSpinHitJumpVel = 10.0f; + static const f32 hPushedAcc = 2.0f; + // static const f32 hNearDistance = // TODO: some combination of these two is used in exeExplode + // static const f32 hFarDistance = + static const s32 hExplodeTime = 8; + // static const s32 hHideTime = + static const s32 hWaitTime = 180; + static const s32 hWalkTime = 160; + static const f32 hWalkVel = 0.5f; + static const f32 hPursueVel = 1.5f; + static const f32 hPursueVelFast = 2.0f; + static const f32 hPrePursueJumpVel = 10.0f; + // static const f32 hPursueHitJumpVel = + // static const f32 hPursueHitBackVelH = + static const s32 hPursueHitTime = 38; + // static const f32 hRecoverRotateRate = + static const f32 hGravityThrown = 0.75; + static const f32 hThrownDampVel = 0.98f; + static const f32 hThrownReboundRate = 0.8f; + static const f32 hThrownReboundMin = 0.0f; + // static const f32 hThrownToStopValue = + static const f32 hTurnVecValue = 2.0f; + static const s32 hThrownCanNotGotTime = 120; + static const f32 hMultVelAngle = 1.0f; + static const s32 hThrownOffCalcGravityTime = 30; + static const f32 hGroundCosine = 0.75f; + // static const s32 hStaticTime = + static const f32 hStopDampValue = 0.8f; + static const f32 hToStopVelLen = 5.0f; + static const f32 hThrowVelH = 25.0f; + static const f32 hThrowVelV = 18.0f; + static const f32 hTranslateHeight = 53.0f; + static const s32 hStopFrame = 3; + static const s32 hSpinHitCanGetTime = 30; + static const s32 hTrampleTime = 60; + const BombHeiParam hNoMoveNoTurnParam = {0.0f, 2.0f, 0.8f, 0.0f}; + const BombHeiParam hWalkParam = {hWalkVel, 2.0f, 0.8f, hTurnVecValue}; + // const BombHeiParam hPursueParam = + const BombHeiParam hPursueFarParam = {hPursueVel, 2.0f, 0.8f, hTurnVecValue + 1.0f}; + const BombHeiParam hPursueFastFarParam = {hPursueVelFast, 2.0f, 0.8f, hTurnVecValue + 1.0f}; + // const BombHeiParam hPursueNearParam = + // const BombHeiParam hPursueWaitParam = + static s32 hCountTimer = hStartBrkTime; +} // namespace + +namespace NrvBombHei { + NEW_NERVE(HostTypeNrvLaunch, BombHei, Launch); + NEW_NERVE(HostTypeNrvStarting, BombHei, Starting); + NEW_NERVE(HostTypeNrvWait, BombHei, Wait); + NEW_NERVE(HostTypeNrvWalk, BombHei, Walk); + NEW_NERVE(HostTypeNrvPursue, BombHei, Pursue); + NEW_NERVE(HostTypeNrvPursueFast, BombHei, Pursue); + NEW_NERVE(HostTypeNrvPursueHit, BombHei, PursueHit); + NEW_NERVE_ONEND(HostTypeNrvSpinHit, BombHei, SpinHit, SpinHit); + NEW_NERVE(HostTypeNrvTrample, BombHei, Trample); + NEW_NERVE(HostTypeNrvPhysics, BombHei, Physics); + NEW_NERVE(HostTypeNrvStop, BombHei, Stop); + NEW_NERVE_ONEND(HostTypeNrvTaken, BombHei, Taken, Taken); + NEW_NERVE_ONEND(HostTypeNrvThrown, BombHei, Thrown, Thrown); + NEW_NERVE(HostTypeNrvExplode, BombHei, Explode); + NEW_NERVE_ONEND(HostTypeNrvBindStarPointer, BombHei, BindStarPointer, BindStarPointer); + +} // namespace NrvBombHei + +BombHei::BombHei(const char* pName) + : LiveActor(pName), mScaleController(nullptr), mBindStarPointerState(nullptr), mRotQuat(0.0f, 0.0f, 0.0f, 1.0f), mFront(0, 0, 1), + mBinderOffset(0, 1, 0), mTargetFront(0, 0, 1), mCountdown(-1), mCarrySensor(nullptr), mExplodeRadius(500.0f), mBodyJoint(nullptr), + mType(BOMB_HEI), mExplosionIgnoreCollision(false) { +} + +void BombHei::init(const JMapInfoIter& rIter) { + if (MR::isValidInfo(rIter)) { + MR::initDefaultPos(this, rIter); + + s32 detonateTime = hStartBrkTime; + MR::getJMapInfoArg0NoInit(rIter, &detonateTime); + hCountTimer = detonateTime; + + s32 rangeArg = mExplodeRadius; + MR::getJMapInfoArg1NoInit(rIter, &rangeArg); + mExplodeRadius = rangeArg; + + s32 ignoreCollisionArg = -1; + MR::getJMapInfoArg2NoInit(rIter, &ignoreCollisionArg); + if (ignoreCollisionArg != -1) { + mExplosionIgnoreCollision = true; + } + + const char* objName = nullptr; + MR::getObjectName(&objName, rIter); + if (MR::isEqualString(objName, "Bomb")) { + mType = BOMB; + } else { + mType = BOMB_HEI; + } + + setGroupClipping(rIter); + } + + MR::useStageSwitchWriteDead(this, rIter); + MR::useStageSwitchReadA(this, rIter); + + initModelManagerWithAnm("BombHei", nullptr, false); + MR::connectToSceneEnemy(this); + MR::initLightCtrl(this); + + mRotQuat.set< f32 >(0.0f, 0.0f, 0.0f, 1.0f); + mRotQuat.getZDir(mFront); + mTargetFront.set(mFront); + + initBinder(hTranslateHeight, hTranslateHeight, 0); + MR::setBinderOffsetVec(this, &mBinderOffset, false); + MR::onCalcGravity(this); + + initSound(4, false); + initEffectKeeper(1, nullptr, false); + + initHitSensor(2); + f32 scl = mScale.y; + MR::addHitSensor(this, "body", ATYPE_BOMBHEI, 16, scl * 60.0f, TVec3f(0.0f, scl * 60.0f, 0.0f)); + MR::addHitSensorEnemyAttack(this, "explode", 32, mExplodeRadius * scl, TVec3f(0.0f, scl * 200.0f, 0.0f)); + + if (mType == BOMB) { + initNerve(&NrvBombHei::HostTypeNrvPhysics::sInstance); + } else { + initNerve(&NrvBombHei::HostTypeNrvWait::sInstance); + } + + MR::initShadowVolumeSphere(this, 60.0f); + endCountdown(); + MR::validateClipping(this); + MR::initStarPointerTarget(this, 70.0f, TVec3f(0.0f, 35.0f, 0.0f)); + + mBodyJoint = MR::createJointDelegatorWithNullChildFunc(this, &BombHei::calcJoint, "Body"); + + mScaleController = new AnimScaleController(nullptr); + mScaleController->setParamTight(); + + mBindStarPointerState = new WalkerStateBindStarPointer(this, mScaleController); + + appear(); +} + +void BombHei::setGroupClipping(const JMapInfoIter& rIter) { + MR::setGroupClipping(this, rIter, 32); +} + +void BombHei::initAfterPlacement() { + MR::trySetMoveLimitCollision(this); +} + +void BombHei::appear() { + LiveActor::appear(); + getSensor("explode")->invalidate(); + getSensor("body")->validate(); + + if (mType == BOMB_HEI || mType == BOMB) { + setNerve(&NrvBombHei::HostTypeNrvLaunch::sInstance); + } + + MR::showModel(this); +} + +void BombHei::kill() { + LiveActor::kill(); + if (MR::isValidSwitchDead(this)) { + MR::onSwitchDead(this); + } + endCountdown(); +} + +void BombHei::startCountdown() { + if (mCountdown == -1) { + MR::invalidateClipping(this); + mCountdown = hCountTimer; + MR::emitEffect(this, "Ignite"); + } +} + +void BombHei::endCountdown() { + mCountdown = -1; + MR::startBrk(this, "Wait"); + MR::setBrkRate(this, 1.0f); + MR::deleteEffect(this, "Ignite"); + MR::validateClipping(this); +} + +void BombHei::exeLaunch() { + if (MR::isFirstStep(this)) { + MR::startBck(this, "Stop", nullptr); + mRotQuat.set< f32 >(0.0f, 0.0f, 0.0f, 1.0f); + } + + TVec3f velH(0, 0, 0); + MR::vecKillElement(mVelocity, mGravity, &velH); + mTargetFront.set(velH); + MR::normalizeOrZero(&mTargetFront); + + if (!MR::isNearZero(mTargetFront)) { + MR::turnVecToVecRadian(&mFront, mFront, mTargetFront, hTurnLimitRadian, mGravity); + } + + mVelocity.mult(0.98f); + + if (!MR::isOnGroundCos(this, hGroundCosine)) { + mVelocity.add(mGravity.multiplyOperatorInline(hGravity)); + f32 radius = getSensor("body")->mRadius; + MR::rotateQuatRollBall(&mRotQuat, velH.multiplyOperatorInline2(hMultVelAngle), -mGravity, radius); + } else { + startBoundSound(); + f32 radius = getSensor("body")->mRadius; + MR::rotateQuatRollBall(&mRotQuat, mVelocity, *MR::getGroundNormal(this), radius); + + if (mGravity.dot(mVelocity) < 5.0f) { + if (mType == BOMB_HEI) { + setNerve(&NrvBombHei::HostTypeNrvStarting::sInstance); + } else if (mType == BOMB) { + setNerve(&NrvBombHei::HostTypeNrvPhysics::sInstance); + } + return; + } + } + + MR::reboundVelocityFromCollision(this, 0.1f, 6.0f, 1.0f); +} + +void BombHei::exeStarting() { + if (MR::isFirstStep(this)) { + MR::validateExCollisionParts(this); + MR::startBck(this, "Starting", nullptr); + mVelocity.z = 0.0f; + mVelocity.y = 0.0f; + mVelocity.x = 0.0f; + } + + if (!MR::isNearZero(mGravity)) { + MR::blendQuatUpFront(&mRotQuat, -mGravity, mFront, 0.5f, 0.5f); + } + + if (MR::isBckStopped(this)) { + setNerve(&NrvBombHei::HostTypeNrvWait::sInstance); + } +} + +void BombHei::exeWait() { + if (MR::isFirstStep(this)) { + MR::startBck(this, "Wait", nullptr); + } + + MR::moveAndTurnToPlayer(this, &mFront, hNoMoveNoTurnParam.mSpeedH, hNoMoveNoTurnParam.mGravAccel, hNoMoveNoTurnParam.mFriction, + hNoMoveNoTurnParam.mTurnRate); + + if (MR::isGreaterStep(this, hWaitTime)) { + setNerve(&NrvBombHei::HostTypeNrvWalk::sInstance); + return; + } + + if (!MR::isNearZero(mGravity)) { + MR::blendQuatUpFront(&mRotQuat, -mGravity, mFront, 0.5f, 0.5f); + } + + if (MR::calcDistanceToPlayer(this) < 1000.0f && (!MR::isValidSwitchA(this) || MR::isOnSwitchA(this))) { + if (mCountdown > 0 && mCountdown < hBrkRateUpTime) { + setNerve(&NrvBombHei::HostTypeNrvPursueFast::sInstance); + } else { + setNerve(&NrvBombHei::HostTypeNrvPursue::sInstance); + } + } +} + +void BombHei::exeWalk() { + if (MR::isFirstStep(this)) { + MR::startBck(this, "Walk", nullptr); + TVec3f randDir; + MR::getRandomVector(&randDir, 1.0f); + MR::vecKillElement(randDir, mGravity, &randDir); + MR::normalizeOrZero(&randDir); + if (!MR::isNearZero(randDir)) { + mTargetFront.set(randDir); + } + } + + MR::moveAndTurnToDirection(this, &mFront, mTargetFront, hWalkParam.mSpeedH, hWalkParam.mGravAccel, hWalkParam.mFriction, hWalkParam.mTurnRate); + + if (MR::isGreaterStep(this, hWalkTime)) { + setNerve(&NrvBombHei::HostTypeNrvWait::sInstance); + return; + } + + if (!MR::isNearZero(mGravity)) { + MR::blendQuatUpFront(&mRotQuat, -mGravity, mFront, 0.5f, 0.5f); + } + + if (MR::calcDistanceToPlayer(this) < 1000.0f && (!MR::isValidSwitchA(this) || MR::isOnSwitchA(this))) { + if (mCountdown > 0 && mCountdown < hBrkRateUpTime) { + setNerve(&NrvBombHei::HostTypeNrvPursueFast::sInstance); + } else { + setNerve(&NrvBombHei::HostTypeNrvPursue::sInstance); + } + } +} + +void BombHei::exePursue() { + if (MR::isFirstStep(this)) { + startCountdown(); + MR::invalidateClipping(this); + mVelocity.set(mGravity.multiplyOperatorInline(-hPrePursueJumpVel)); + } + + // NOTE: this is a dummy line to emit the structure, this value is not real + if (MR::calcDistanceToPlayer(this) < 0.0f) { + } + + if (isNerve(&NrvBombHei::HostTypeNrvPursueFast::sInstance)) { + MR::tryStartBck(this, "CountDown", nullptr); + MR::moveAndTurnToPlayer(this, &mFront, hPursueFastFarParam.mSpeedH, hPursueFastFarParam.mGravAccel, hPursueFastFarParam.mFriction, + hPursueFastFarParam.mTurnRate); + } else { + MR::tryStartBck(this, "Run", nullptr); + MR::moveAndTurnToPlayer(this, &mFront, hPursueFarParam.mSpeedH, hPursueFarParam.mGravAccel, hPursueFarParam.mFriction, + hPursueFarParam.mTurnRate); + } + + if (isNerve(&NrvBombHei::HostTypeNrvPursue::sInstance) && mCountdown > 0 && mCountdown < hBrkRateUpTime) { + setNerve(&NrvBombHei::HostTypeNrvPursueFast::sInstance); + return; + } + + if (!MR::isNearZero(mGravity)) { + MR::blendQuatUpFront(&mRotQuat, -mGravity, mFront, 0.5f, 0.5f); + } +} + +void BombHei::exePursueHit() { + if (MR::isFirstStep(this)) { + MR::startBck(this, "Hit", nullptr); + MR::startSound(this, "SE_EM_BOMBHEI_HIT", -1, -1); + } + + MR::moveAndTurnToPlayer(this, &mFront, hNoMoveNoTurnParam.mSpeedH, hNoMoveNoTurnParam.mGravAccel, hNoMoveNoTurnParam.mFriction, + hNoMoveNoTurnParam.mTurnRate); + + if (!MR::isNearZero(mGravity)) { + MR::blendQuatUpFront(&mRotQuat, -mGravity, mFront, 0.5f, 0.5f); + } + + if (MR::isGreaterStep(this, hPursueHitTime)) { + if (mCountdown > 0 && mCountdown < hBrkRateUpTime) { + setNerve(&NrvBombHei::HostTypeNrvPursueFast::sInstance); + } else { + setNerve(&NrvBombHei::HostTypeNrvPursue::sInstance); + } + } +} + +void BombHei::exeSpinHit() { + if (MR::isFirstStep(this)) { + MR::startBck(this, "Spin", nullptr); + MR::startBlowHitSound(this); + mVelocity.set(mGravity.multiplyOperatorInline(-hSpinHitJumpVel)); + MR::invalidateExCollisionParts(this); + } + + MR::moveAndTurnToPlayer(this, &mFront, hNoMoveNoTurnParam.mSpeedH, hNoMoveNoTurnParam.mGravAccel, hNoMoveNoTurnParam.mFriction, + hNoMoveNoTurnParam.mTurnRate); + + if (!MR::isNearZero(mGravity)) { + MR::blendQuatUpFront(&mRotQuat, -mGravity, mFront, 0.5f, 0.5f); + } + + if (MR::isOnGroundCos(this, hGroundCosine)) { + if (MR::isBckStopped(this)) { + setNerve(&NrvBombHei::HostTypeNrvPhysics::sInstance); + } + } else { + mVelocity.add(mGravity.multiplyOperatorInline(hGravity)); + } +} + +void BombHei::endSpinHit() { +} + +void BombHei::exeTrample() { + if (MR::isFirstStep(this)) { + MR::startAction(this, "Pressed"); + MR::startSound(this, "SE_EM_BOMBHEI_TRAMPLE", -1, -1); + } + + MR::addVelocityToGravityOrGround(this, hGravity); + MR::killVelocityOnGroundCosH(this, hGroundCosine); + + if (MR::isGreaterStep(this, hTrampleTime)) { + setNerve(&NrvBombHei::HostTypeNrvPursue::sInstance); + } +} + +void BombHei::exePhysics() { + if (MR::isFirstStep(this)) { + MR::invalidateExCollisionParts(this); + } + + TVec3f velH(0, 0, 0); + MR::vecKillElement(mVelocity, mGravity, &velH); + mTargetFront.set(velH); + MR::normalizeOrZero(&mTargetFront); + + if (!MR::isNearZero(mTargetFront) && 2.0f < velH.length()) { + MR::turnVecToVecRadian(&mFront, mFront, mTargetFront, hTurnLimitRadian, mGravity); + } + + mVelocity.mult(0.98f); + + if (!MR::isOnGroundCos(this, hGroundCosine)) { + mVelocity.add(mGravity.multiplyOperatorInline(hGravity)); + f32 radius = getSensor("body")->mRadius; + MR::rotateQuatRollBall(&mRotQuat, velH.multiplyOperatorInline2(hMultVelAngle), mGravity, radius); + } else { + mVelocity.add(mGravity.multiplyOperatorInline(hGravityPhysicsOnGround)); + f32 radius = getSensor("body")->mRadius; + MR::rotateQuatRollBall(&mRotQuat, mVelocity, *MR::getGroundNormal(this), radius); + + if (MR::isBckStopped(this) && mVelocity.length() < hToStopVelLen) { + setNerve(&NrvBombHei::HostTypeNrvStop::sInstance); + return; + } + + mBinder->_1EC._5 = 1; + } + + MR::reboundVelocityFromCollision(this, 0.1f, 6.0f, 1.0f); + MR::killVelocityOnGroundCosH(this, hGroundCosine); +} + +void BombHei::exeStop() { + if (MR::isFirstStep(this)) { + MR::startBck(this, "Stop", nullptr); + } + + MR::addVelocityToGravityOrGround(this, hGravity); + MR::reboundVelocityFromCollision(this, 0.0f, 0.0f, 1.0f); + + if (MR::isOnGround(this)) { + MR::attenuateVelocity(this, hStopDampValue); + f32 radius = getSensor("body")->mRadius; + MR::rotateQuatRollBall(&mRotQuat, mVelocity, *MR::getGroundNormal(this), radius); + } else { + MR::attenuateVelocity(this, 0.98f); + f32 radius = getSensor("body")->mRadius; + MR::rotateQuatRollBall(&mRotQuat, mVelocity, -mGravity, radius); + } + + mBinder->_1EC._5 = 1; +} + +void BombHei::exeThrown() { + if (MR::isFirstStep(this)) { + MR::startBck(this, "Stop", nullptr); + MR::startSoundPlayer("SE_PV_THROW", -1); + MR::startSound(this, "SE_EM_BOMB_THROW", -1, -1); + MR::invalidateExCollisionParts(this); + MR::offCalcGravity(this); + } + + TVec3f velH(0, 0, 0); + MR::vecKillElement(mVelocity, mGravity, &velH); + f32 radius = getSensor("body")->mRadius; + MR::rotateQuatRollBall(&mRotQuat, velH.multiplyOperatorInline(hMultVelAngle), mGravity, radius); + mTargetFront.set(velH); + MR::normalizeOrZero(&mTargetFront); + + if (!MR::isNearZero(mTargetFront)) { + MR::turnVecToVecRadian(&mFront, mFront, mTargetFront, hTurnLimitRadian, mGravity); + } + + if (MR::isGreaterStep(this, hThrownOffCalcGravityTime)) { + MR::onCalcGravity(this); + } + + mVelocity.mult(hThrownDampVel); + + if (!MR::isOnGroundCos(this, hGroundCosine)) { + mVelocity.add(mGravity.multiplyOperatorInline2(hGravityThrown)); + } else { + startBoundSound(); + MR::startBck(this, "Bound", nullptr); + setNerve(&NrvBombHei::HostTypeNrvPhysics::sInstance); + return; + } + + MR::reboundVelocityFromCollision(this, 0.1f, 6.0f, 1.0f); +} + +void BombHei::endThrown() { + MR::onCalcGravity(this); +} + +void BombHei::exeTaken() { + if (MR::isFirstStep(this)) { + MR::startBck(this, "Carry", nullptr); + if (MR::sendMsgTaken(mCarrySensor, getSensor("body"))) { + getSensor("body")->invalidate(); + MR::startSoundPlayer("SE_PV_LIFT_UP", -1); + MR::startSound(this, "SE_EM_BOMB_LIFT", -1, -1); + } else { + setNerve(&NrvBombHei::HostTypeNrvPhysics::sInstance); + return; + } + } + + mRotQuat.setEulerDegree(mRotation.x, mRotation.y, mRotation.z); +} + +void BombHei::endTaken() { + getSensor("body")->validate(); +} + +void BombHei::exeExplode() { + if (MR::isFirstStep(this)) { + MR::emitEffect(this, "Explosion"); + MR::startSound(this, "SE_EM_BOMB_EXPLOSION", -1, -1); + MR::hideModel(this); + getSensor("explode")->validate(); + getSensor("body")->invalidate(); + if (mCarrySensor != nullptr) { + MR::sendArbitraryMsg(ACTMES_RUSHDROP, mCarrySensor, getSensor("body")); + MR::sendMsgEnemyAttackExplosion(mCarrySensor, getSensor("body")); + } + mCarrySensor = nullptr; + endCountdown(); + MR::tryRumblePadAndCameraDistanceStrong(this, 800.0f, 1200.0f, 2000.0f); // TODO + MR::invalidateClipping(this); + } + + getSensor("explode")->mRadius = getNerveStep() * mExplodeRadius / 8; + + if (MR::isGreaterStep(this, hExplodeTime)) { + MR::validateClipping(this); + kill(); + } +} + +void BombHei::exeBindStarPointer() { + MR::updateActorStateAndNextNerve(this, mBindStarPointerState, &NrvBombHei::HostTypeNrvWait::sInstance); +} + +void BombHei::endBindStarPointer() { + mBindStarPointerState->kill(); +} + +void BombHei::calcAndSetBaseMtx() { + TPos3f mtx; + MR::calcMtxFromGravityAndZAxis(&mtx, this, mGravity, mFront); + MR::setBaseTRMtx(this, mtx); + MR::setBaseScale(this, mScaleController->_C.mult(mScale)); + mtx.getYDirInline(mBinderOffset); + mBinderOffset.mult(hTranslateHeight); + mBodyJoint->registerCallBack(); +} + +bool BombHei::calcJoint(TPos3f* pMtx, const JointControllerInfo& rJointInfo) { + // FIXME: setQuat does not behave nicely here. + // https://decomp.me/scratch/CfmhG + + TPos3f mtx; + mtx.zeroTransInline(); + mtx.setQuat(mRotQuat); + + // interesting way to transpose a matrix + TPos3f mtx2; + TVec3f x, y, z; + mtx2.setInline(getBaseMtx()); + mtx2.getXYZDirInline(x, y, z); + TPos3f mtx3; + mtx3.setXYZDirInline2(x, y, z); + + TVec3f t; + pMtx->getTransInline(t); + + pMtx->zeroTransInline2(); + pMtx->concat(mtx3, *pMtx); + pMtx->concat(mtx, *pMtx); + pMtx->setTransInline(t); + + return true; +} + +void BombHei::control() { + mScaleController->updateNerve(); + + if (MR::isInDeath(this, TVec3f(0.0f, 0.0f, 0.0f)) && !isNerve(&NrvBombHei::HostTypeNrvExplode::sInstance)) { + setNerve(&NrvBombHei::HostTypeNrvExplode::sInstance); + return; + } + + if (mCountdown > 0) { + if (mCountdown == hCountTimer) { + MR::startBrk(this, "CountDown"); + MR::setBrkRate(this, hBrkSlowRate); + } else if (mCountdown == hBrkRateUpTime) { + MR::startBrk(this, "CountDown"); + MR::setBrkRate(this, hBrkFastRate); + } + + MR::startLevelSound(this, "SE_EM_LV_BOMB_FUSE", -1, -1, -1); + + if (mCountdown <= hBrkRateUpTime) { + MR::startLevelSound(this, "SE_EM_LV_BOMB_ALARM_FAST", -1, -1, -1); + } else if (mCountdown <= hStartBrkTime / 2) { + MR::startLevelSound(this, "SE_EM_LV_BOMB_ALARM_MIDDLE", -1, -1, -1); + } else { + MR::startLevelSound(this, "SE_EM_LV_BOMB_ALARM_SLOW", -1, -1, -1); + } + + if (--mCountdown == 0) { + setNerve(&NrvBombHei::HostTypeNrvExplode::sInstance); + return; + } + } + + if (mType != BOMB && + (isNerve(&NrvBombHei::HostTypeNrvWait::sInstance) || isNerve(&NrvBombHei::HostTypeNrvWalk::sInstance) || + isNerve(&NrvBombHei::HostTypeNrvPursue::sInstance) || isNerve(&NrvBombHei::HostTypeNrvPursueFast::sInstance) || + isNerve(&NrvBombHei::HostTypeNrvPursueHit::sInstance)) && + mBindStarPointerState->tryStartPointBind()) { + setNerve(&NrvBombHei::HostTypeNrvBindStarPointer::sInstance); + } +} + +void BombHei::attackSensor(HitSensor* pSender, HitSensor* pReceiver) { + if (getSensor("explode") == pSender) { + if (!mExplosionIgnoreCollision && MR::isExistCollisionParts(pReceiver->mHost) && MR::isValidCollisionParts(pReceiver->mHost)) { + Triangle hitPoly; + + if (!MR::getFirstPolyOnLineToMap(nullptr, &hitPoly, pSender->mPosition, pReceiver->mPosition.subOtherInline(pSender->mPosition))) { + return; + } + + if (hitPoly.mParts->mHitSensor->mHost != pReceiver->mHost) { + return; + } + } + + if (MR::isSensorPlayer(pReceiver)) { + MR::sendMsgEnemyAttackExplosion(pReceiver, pSender); + } else if (MR::isSensorEnemy(pReceiver)) { + MR::sendMsgEnemyAttackExplosion(pReceiver, pSender); + } else if (MR::isSensorMapObj(pReceiver)) { + MR::sendMsgEnemyAttackExplosion(pReceiver, pSender); + } + return; + } + + if (isNerve(&NrvBombHei::HostTypeNrvLaunch::sInstance) || isNerve(&NrvBombHei::HostTypeNrvExplode::sInstance)) { + return; + } + + if (getSensor("body") != pSender) { + return; + } + + if (MR::isSensorPlayer(pReceiver)) { + if (MR::sendMsgPushAndKillVelocityToTarget(this, pReceiver, pSender)) { + startCountdown(); + } + return; + } + + if (MR::isSensorRide(pReceiver)) { + setNerve(&NrvBombHei::HostTypeNrvExplode::sInstance); + return; + } + + if (MR::isSensorNpc(pReceiver) || MR::isSensorEnemy(pReceiver)) { + if (isNerve(&NrvBombHei::HostTypeNrvThrown::sInstance)) { + TVec3f direction(pSender->mPosition.subOtherInline(pReceiver->mPosition)); + MR::normalizeOrZero(&direction); + MR::calcReflectionVector(&mVelocity, direction, hThrownReboundRate, hThrownReboundMin); + } else { + MR::sendMsgPushAndKillVelocityToTarget(this, pReceiver, pSender); + } + } +} + +bool BombHei::receiveMsgPlayerAttack(u32 msg, HitSensor* pSender, HitSensor* pReceiver) { + if (isNerve(&NrvBombHei::HostTypeNrvExplode::sInstance)) { + return false; + } + + if (MR::isMsgStarPieceReflect(msg)) { + return true; + } + + if (MR::isMsgPlayerTrample(msg) || MR::isMsgPlayerHipDrop(msg)) { + if (isNerve(&NrvBombHei::HostTypeNrvThrown::sInstance) || isNerve(&NrvBombHei::HostTypeNrvPhysics::sInstance) || + isNerve(&NrvBombHei::HostTypeNrvStop::sInstance) || isNerve(&NrvBombHei::HostTypeNrvSpinHit::sInstance)) { + return false; + } + + if (isNerve(&NrvBombHei::HostTypeNrvLaunch::sInstance)) { + if (MR::isMsgPlayerHipDrop(msg)) { + MR::sendMsgAwayJump(pSender, pReceiver); + } + return true; + } + + startCountdown(); + setNerve(&NrvBombHei::HostTypeNrvTrample::sInstance); + if (MR::isMsgPlayerHipDrop(msg)) { + MR::sendMsgAwayJump(pSender, pReceiver); + } + return true; + } + + if (MR::isMsgPlayerSpinAttack(msg) && mType == BOMB_HEI && !isNerve(&NrvBombHei::HostTypeNrvSpinHit::sInstance)) { + setNerve(&NrvBombHei::HostTypeNrvSpinHit::sInstance); + startCountdown(); + MR::stopScene(hStopFrame); + return true; + } + + return false; +} + +bool BombHei::receiveMsgEnemyAttack(u32 msg, HitSensor* pSender, HitSensor* pReceiver) { + if (MR::isMsgExplosionAttack(msg) && !isNerve(&NrvBombHei::HostTypeNrvExplode::sInstance)) { + setNerve(&NrvBombHei::HostTypeNrvExplode::sInstance); + return true; + } + + if ((MR::isMsgEnemyAttack(msg) || MR::isMsgToEnemyAttackBlow(msg) || MR::isMsgToEnemyAttackTrample(msg)) && + !isNerve(&NrvBombHei::HostTypeNrvExplode::sInstance) && pSender->isType(ATYPE_WANWAN)) { + setNerve(&NrvBombHei::HostTypeNrvExplode::sInstance); + return true; + } + + return false; +} + +bool BombHei::receiveMsgPush(HitSensor* pSender, HitSensor* pReceiver) { + if (!MR::isSensorPlayer(pSender) && !MR::isSensorEnemy(pSender) && !MR::isSensorMapObj(pSender)) { + return false; + } + + if (isNerve(&NrvBombHei::HostTypeNrvSpinHit::sInstance)) { + return false; + } + + MR::addVelocityFromPush(this, hPushedAcc, pSender, pReceiver); + return true; +} + +bool BombHei::receiveOtherMsg(u32 msg, HitSensor* pSender, HitSensor* pReceiver) { + if (MR::isMsgItemGet(msg) && getSensor("body") == pReceiver) { + if (!isNerve(&NrvBombHei::HostTypeNrvStop::sInstance) && !isNerve(&NrvBombHei::HostTypeNrvPhysics::sInstance) && + !isNerve(&NrvBombHei::HostTypeNrvThrown::sInstance) && + !(isNerve(&NrvBombHei::HostTypeNrvSpinHit::sInstance) && MR::isGreaterStep(this, hSpinHitCanGetTime))) { + return false; + } + + if (isNerve(&NrvBombHei::HostTypeNrvThrown::sInstance) && MR::isLessEqualStep(this, hThrownCanNotGotTime)) { + return false; + } + + mCarrySensor = pSender; + setNerve(&NrvBombHei::HostTypeNrvTaken::sInstance); + startCountdown(); + return true; + } + + if (msg == ACTMES_DAMAGEDROP || msg == ACTMES_RUSHDROP || msg == ACTMES_ATTACKDROP) { + if (isNerve(&NrvBombHei::HostTypeNrvTaken::sInstance)) { + setNerve(&NrvBombHei::HostTypeNrvThrown::sInstance); + } + return true; + } + + if (msg == ACTMES_TAKE_TOUCH) { + MR::startBck(this, "Carry", nullptr); + return true; + } + + return false; +} + +bool BombHei::receiveMsgThrow(HitSensor* pSender, HitSensor* pReceiver) { + if (isNerve(&NrvBombHei::HostTypeNrvExplode::sInstance)) { + return true; + } + + setNerve(&NrvBombHei::HostTypeNrvThrown::sInstance); + mCarrySensor = nullptr; + TVec3f throwVec; + MR::getPlayerThrowVec(&throwVec); + mVelocity.set(throwVec.multInLine(hThrowVelH)); + mVelocity.add(mGravity.multInLine2(-hThrowVelV)); + return true; +} + +void BombHei::startBoundSound() { + s32 level = mGravity.dot(mVelocity) * 100.0f; + MR::startSound(this, "SE_EM_BOMB_BOUND", level, -1); +} From 687ae8e5be575927c41180bffe73e6c8101838d8 Mon Sep 17 00:00:00 2001 From: MrL314 <11429905+MrL314@users.noreply.github.com> Date: Mon, 23 Feb 2026 18:28:30 -0500 Subject: [PATCH 35/52] Match `BombHeiLauncher` --- config/RMGK01/symbols.txt | 4 +- configure.py | 2 +- include/Game/Enemy/BombHei.hpp | 3 +- include/Game/Enemy/BombHeiLauncher.hpp | 26 ++- .../include/JSystem/JGeometry/TVec.hpp | 6 + src/Game/Enemy/BombHeiLauncher.cpp | 167 +++++++++++++++++- 6 files changed, 197 insertions(+), 11 deletions(-) diff --git a/config/RMGK01/symbols.txt b/config/RMGK01/symbols.txt index 16ebc2414..defdf2770 100644 --- a/config/RMGK01/symbols.txt +++ b/config/RMGK01/symbols.txt @@ -46761,8 +46761,8 @@ __vt__Q210NrvBombHei17HostTypeNrvLaunch = .data:0x8057AE9C; // type:object size: lbl_8057AEC8 = .data:0x8057AEC8; // type:object size:0xD data:string lbl_8057AED5 = .data:0x8057AED5; // type:object size:0x10 data:string lbl_8057AEE5 = .data:0x8057AEE5; // type:object size:0x5 data:string -lbl_8057AEEA = .data:0x8057AEEA; // type:object size:0x7 -lbl_8057AEF1 = .data:0x8057AEF1; // type:object size:0x5 noreloc +lbl_8057AEEA = .data:0x8057AEEA; // type:object size:0x7 data:string +lbl_8057AEF1 = .data:0x8057AEF1; // type:object size:0x5 data:string noreloc lbl_8057AEF6 = .data:0x8057AEF6; // type:object size:0x5 data:string lbl_8057AEFB = .data:0x8057AEFB; // type:object size:0x16 data:string __vt__Q22MR57FunctorV0M = .data:0x8057AF14; // type:object size:0x10 scope:global align:4 diff --git a/configure.py b/configure.py index ecb98dde6..162129797 100644 --- a/configure.py +++ b/configure.py @@ -1086,7 +1086,7 @@ def JSys_J3DLib(lib_name: str, objects: List[Object]) -> Dict[str, Any]: Object(NonMatching, "Game/Enemy/BombBird.cpp"), Object(NonMatching, "Game/Enemy/BombBirdBomb.cpp"), Object(NonMatching, "Game/Enemy/BombHei.cpp"), - Object(NonMatching, "Game/Enemy/BombHeiLauncher.cpp"), + Object(Matching, "Game/Enemy/BombHeiLauncher.cpp"), Object(NonMatching, "Game/Enemy/BombTeresa.cpp"), Object(NonMatching, "Game/Enemy/CannonShellBase.cpp"), Object(NonMatching, "Game/Enemy/CocoNutBall.cpp"), diff --git a/include/Game/Enemy/BombHei.hpp b/include/Game/Enemy/BombHei.hpp index 0653d9e03..8c5bd38c9 100644 --- a/include/Game/Enemy/BombHei.hpp +++ b/include/Game/Enemy/BombHei.hpp @@ -13,6 +13,7 @@ class BombHei : public LiveActor { enum Type { BOMB_HEI = 0, BOMB = 1 }; virtual void init(const JMapInfoIter& rIter); + virtual void initAfterPlacement(); virtual void appear(); virtual void kill(); virtual void control(); @@ -25,7 +26,6 @@ class BombHei : public LiveActor { virtual bool receiveOtherMsg(u32 msg, HitSensor* pSender, HitSensor* pReceiver); void setGroupClipping(const JMapInfoIter& rIter); - void initAfterPlacement(); void startCountdown(); void endCountdown(); @@ -51,7 +51,6 @@ class BombHei : public LiveActor { bool calcJoint(TPos3f*, const JointControllerInfo&); void startBoundSound(); -private: /* 0x8C */ AnimScaleController* mScaleController; /* 0x90 */ WalkerStateBindStarPointer* mBindStarPointerState; /* 0x94 */ TQuat4f mRotQuat; diff --git a/include/Game/Enemy/BombHeiLauncher.hpp b/include/Game/Enemy/BombHeiLauncher.hpp index f043980d7..fab93e82d 100644 --- a/include/Game/Enemy/BombHeiLauncher.hpp +++ b/include/Game/Enemy/BombHeiLauncher.hpp @@ -1,14 +1,32 @@ #pragma once -#include "Game/NameObj/NameObj.hpp" +#include "Game/Enemy/BombHei.hpp" #include "Game/LiveActor/LiveActor.hpp" +class MapObjConnector; class BombHeiLauncher : public LiveActor { public: BombHeiLauncher(const char*); - virtual ~BombHeiLauncher(); -private: - u8 mPad[(0x9C) - sizeof(LiveActor)]; + virtual void init(const JMapInfoIter& rIter); + virtual void initAfterPlacement(); + virtual void control(); + virtual void calcAndSetBaseMtx(); + + void startCountdown(); + void onSwitchA(); + void offSwitchA(); + + void exeLauncherWait(); + void exeStop(); + + TVec3f* getBombVelocity() const { + return &mBomb->mVelocity; + } + + /* 0x8C */ BombHei* mBomb; + /* 0x90 */ s32 mCountdown; + /* 0x94 */ MapObjConnector* mConnector; + /* 0x98 */ bool mIsActive; }; diff --git a/libs/JSystem/include/JSystem/JGeometry/TVec.hpp b/libs/JSystem/include/JSystem/JGeometry/TVec.hpp index 77c6dd971..9e0cda462 100644 --- a/libs/JSystem/include/JSystem/JGeometry/TVec.hpp +++ b/libs/JSystem/include/JSystem/JGeometry/TVec.hpp @@ -583,6 +583,12 @@ namespace JGeometry { JMathInlineVEC::PSVECNegate(this, this); } + inline TVec3 invertOperatorInternal() { + TVec3 ret; + JMathInlineVEC::PSVECNegate(this, &ret); + return ret; + } + void scale(f32 scale); void scale(f32 scalar, const TVec3& rVec); /*{ diff --git a/src/Game/Enemy/BombHeiLauncher.cpp b/src/Game/Enemy/BombHeiLauncher.cpp index 55a3bfa73..0c07488d9 100644 --- a/src/Game/Enemy/BombHeiLauncher.cpp +++ b/src/Game/Enemy/BombHeiLauncher.cpp @@ -1,5 +1,168 @@ #include "Game/Enemy/BombHeiLauncher.hpp" +#include "Game/MapObj/MapObjConnector.hpp" -BombHeiLauncher::BombHeiLauncher(const char* pName) : LiveActor(pName) {} -BombHeiLauncher::~BombHeiLauncher() {} +namespace { + static const f32 hThrowVel = 35.0f; + static const f32 hThrowFrontVel = 1.0f; + static const s32 hCountTimer = 60; +} // namespace +namespace NrvBombHeiLauncher { + NEW_NERVE(HostTypeNrvLauncherWait, BombHeiLauncher, LauncherWait); + NEW_NERVE(HostTypeNrvStop, BombHeiLauncher, Stop); +} // namespace NrvBombHeiLauncher + +BombHeiLauncher::BombHeiLauncher(const char* pName) : LiveActor(pName), mBomb(nullptr), mCountdown(0), mConnector(nullptr), mIsActive(true) { + mConnector = new MapObjConnector(this); +} + +void BombHeiLauncher::init(const JMapInfoIter& rIter) { + bool isBombHeiLauncher = true; + if (MR::isValidInfo(rIter)) { + MR::initDefaultPos(this, rIter); + + const char* objectName = nullptr; + MR::getObjectName(&objectName, rIter); + if (MR::isEqualString(objectName, "BombLauncher")) { + isBombHeiLauncher = false; + } + + if (MR::useStageSwitchReadA(this, rIter)) { + mIsActive = false; + MR::listenStageSwitchOnOffA(this, MR::Functor(this, &BombHeiLauncher::onSwitchA), MR::Functor(this, &BombHeiLauncher::offSwitchA)); + } + + MR::useStageSwitchSleep(this, rIter); + } + + initModelManagerWithAnm("BombHeiLauncher", nullptr, false); + MR::connectToSceneCollisionEnemy(this); + MR::initLightCtrl(this); + MR::onCalcGravity(this); + + initSound(6, false); + initEffectKeeper(0, nullptr, false); + + initHitSensor(2); + MR::addBodyMessageSensorEnemy(this); + MR::initCollisionParts(this, "BombHeiLauncher", getSensor("body"), nullptr); + MR::onCalcGravity(this); + + initNerve(&NrvBombHeiLauncher::HostTypeNrvStop::sInstance); + mCountdown = -1; + + MR::validateClipping(this); + MR::setGroupClipping(this, rIter, 32); + makeActorDead(); + + if (isBombHeiLauncher) { + mBomb = new BombHei("ボム兵"); + mBomb->mType = BombHei::BOMB_HEI; + } else { + mBomb = new BombHei("ボム"); + mBomb->mType = BombHei::BOMB; + } + + mBomb->mPosition.set(mPosition); + mBomb->initWithoutIter(); + mBomb->setGroupClipping(rIter); + + s32 ignoreCollisionArg = -1; + MR::getJMapInfoArg2NoInit(rIter, &ignoreCollisionArg); + if (ignoreCollisionArg != -1) { + mBomb->mExplosionIgnoreCollision = true; + } + + mBomb->kill(); +} + +void BombHeiLauncher::initAfterPlacement() { + TVec3f up; + MR::calcUpVec(&up, this); + MR::resetPosition(mBomb, mPosition.addOperatorInLine(up * 30.0f)); + mBomb->mGravity.set(up.invertOperatorInternal()); + mBomb->initAfterPlacement(); + mConnector->attachToUnder(); + makeActorAppeared(); +} + +void BombHeiLauncher::startCountdown() { + if (mCountdown != -1) { + return; + } + + mCountdown = hCountTimer; +} + +void BombHeiLauncher::onSwitchA() { + mIsActive = true; + mCountdown = 0; + setNerve(&NrvBombHeiLauncher::HostTypeNrvLauncherWait::sInstance); +} + +void BombHeiLauncher::offSwitchA() { + mIsActive = false; + mCountdown = -1; + setNerve(&NrvBombHeiLauncher::HostTypeNrvStop::sInstance); + + if (mBomb != nullptr && !MR::isDead(mBomb)) { + mBomb->kill(); + } +} + +void BombHeiLauncher::exeLauncherWait() { + // FIXME: what + if (MR::isFirstStep(this)) { + } + + if (!mIsActive) { + return; + } + + if (mCountdown == 0) { + if (MR::isOnPlayerShadow(this) || MR::isOnPlayer(this)) { + return; + } + + MR::startBck(this, "Open", nullptr); + MR::startSound(this, "SE_EM_BOMBLAUN_LAUNCH", -1, -1); + + mBomb->appear(); + MR::resetPosition(mBomb, mPosition); + + TVec3f up, front; + MR::calcUpVec(&up, this); + MR::calcFrontVec(&front, this); + getBombVelocity()->set(up * hThrowVel); + getBombVelocity()->add(front * hThrowFrontVel); + setNerve(&NrvBombHeiLauncher::HostTypeNrvStop::sInstance); + return; + } + + if (MR::isDead(mBomb)) { + startCountdown(); + } +} + +void BombHeiLauncher::exeStop() { + if (MR::isFirstStep(this)) { + mCountdown = -1; + } + + if (mIsActive && MR::isGreaterStep(this, 120)) { + setNerve(&NrvBombHeiLauncher::HostTypeNrvLauncherWait::sInstance); + } +} + +void BombHeiLauncher::calcAndSetBaseMtx() { + LiveActor::calcAndSetBaseMtx(); + mConnector->connect(); +} + +void BombHeiLauncher::control() { + if (mCountdown <= 0) { + return; + } + + mCountdown--; +} From 290897b5fef78a6b7cc00499343c34e766226f14 Mon Sep 17 00:00:00 2001 From: MrL314 <11429905+MrL314@users.noreply.github.com> Date: Tue, 24 Feb 2026 22:28:51 -0500 Subject: [PATCH 36/52] Match `BombHei` via `fromQuat` --- configure.py | 2 +- .../include/JSystem/JGeometry/TMatrix.hpp | 8 +++--- .../include/JSystem/JGeometry/TVec.hpp | 26 +++++++++++++++++++ src/Game/Boss/DinoPackunTailNode.cpp | 3 ++- src/Game/Enemy/BombHei.cpp | 5 +--- 5 files changed, 35 insertions(+), 9 deletions(-) diff --git a/configure.py b/configure.py index 162129797..ef6d69ceb 100644 --- a/configure.py +++ b/configure.py @@ -1085,7 +1085,7 @@ def JSys_J3DLib(lib_name: str, objects: List[Object]) -> Dict[str, Any]: Object(NonMatching, "Game/Enemy/Birikyu.cpp"), Object(NonMatching, "Game/Enemy/BombBird.cpp"), Object(NonMatching, "Game/Enemy/BombBirdBomb.cpp"), - Object(NonMatching, "Game/Enemy/BombHei.cpp"), + Object(Matching, "Game/Enemy/BombHei.cpp"), Object(Matching, "Game/Enemy/BombHeiLauncher.cpp"), Object(NonMatching, "Game/Enemy/BombTeresa.cpp"), Object(NonMatching, "Game/Enemy/CannonShellBase.cpp"), diff --git a/libs/JSystem/include/JSystem/JGeometry/TMatrix.hpp b/libs/JSystem/include/JSystem/JGeometry/TMatrix.hpp index 661cc72a2..7c91ee6b8 100644 --- a/libs/JSystem/include/JSystem/JGeometry/TMatrix.hpp +++ b/libs/JSystem/include/JSystem/JGeometry/TMatrix.hpp @@ -265,9 +265,6 @@ namespace JGeometry { void getQuat(TQuat4f& rDest) const; void setQuat(const TQuat4f& q) { - // this is VERY weird... however, it matches. - // TODO: is there a better way to write this? - f32 yy = 2.0f * q.y * q.y; f32 zz = 2.0f * q.z * q.z; f32 xx = 2.0f * q.x * q.x; @@ -293,6 +290,11 @@ namespace JGeometry { this->mMtx[2][2] = 1.0f - xx - yy; } + inline void fromQuat(const TQuat4f& q) { + // in cases where setQuat doesnt quite work + q.makeMtx((MtxPtr)this); + } + void getScale(TVec3f& rDest) const; void setScale(const TVec3f& rSrc); void setScale(f32 x, f32 y, f32 z) NO_INLINE { diff --git a/libs/JSystem/include/JSystem/JGeometry/TVec.hpp b/libs/JSystem/include/JSystem/JGeometry/TVec.hpp index 9e0cda462..e38fcca51 100644 --- a/libs/JSystem/include/JSystem/JGeometry/TVec.hpp +++ b/libs/JSystem/include/JSystem/JGeometry/TVec.hpp @@ -896,6 +896,32 @@ namespace JGeometry { transform(v, v); } + void makeMtx(MtxPtr pMtx) const { + f32 yy = 2.0f * this->y * this->y; + f32 zz = 2.0f * this->z * this->z; + f32 xx = 2.0f * this->x * this->x; + + f32 xy = 2.0f * this->x * this->y; + f32 xz = 2.0f * this->x * this->z; + f32 yz = 2.0f * this->y * this->z; + + f32 wx = 2.0f * this->w * this->x; + f32 wy = 2.0f * this->w * this->y; + f32 wz = 2.0f * this->w * this->z; + + pMtx[0][0] = 1.0f - yy - zz; + pMtx[0][1] = xy - wz; + pMtx[0][2] = xz + wy; + + pMtx[1][0] = xy + wz; + pMtx[1][1] = 1.0f - xx - zz; + pMtx[1][2] = yz - wx; + + pMtx[2][0] = xz - wy; + pMtx[2][1] = yz + wx; + pMtx[2][2] = 1.0f - xx - yy; + } + /* Operators */ TQuat4< T >& operator=(const TQuat4< T >& rSrc); }; diff --git a/src/Game/Boss/DinoPackunTailNode.cpp b/src/Game/Boss/DinoPackunTailNode.cpp index 7396e100e..df658ec25 100644 --- a/src/Game/Boss/DinoPackunTailNode.cpp +++ b/src/Game/Boss/DinoPackunTailNode.cpp @@ -72,7 +72,8 @@ bool DinoPackunTailNode::turnJointLocalXDir(TPos3f* pMtx, const JointControllerI MR::normalize(&v23); MR::turnQuatXDirRad(&v24, v24, v23, M_PI); - pMtx->setQT(v24, mPosition); + pMtx->setQuat(v24); + pMtx->setTrans(mPosition); return true; } diff --git a/src/Game/Enemy/BombHei.cpp b/src/Game/Enemy/BombHei.cpp index 8a3d74c68..0e44d9291 100644 --- a/src/Game/Enemy/BombHei.cpp +++ b/src/Game/Enemy/BombHei.cpp @@ -574,12 +574,9 @@ void BombHei::calcAndSetBaseMtx() { } bool BombHei::calcJoint(TPos3f* pMtx, const JointControllerInfo& rJointInfo) { - // FIXME: setQuat does not behave nicely here. - // https://decomp.me/scratch/CfmhG - TPos3f mtx; mtx.zeroTransInline(); - mtx.setQuat(mRotQuat); + mtx.fromQuat(mRotQuat); // interesting way to transpose a matrix TPos3f mtx2; From 5106c460257d9b4f4c07ab39469593c897edfe79 Mon Sep 17 00:00:00 2001 From: shibbo Date: Thu, 26 Feb 2026 09:44:56 -0500 Subject: [PATCH 37/52] `NETVersion` and 91% of `nettime` --- .../revolution/nwc24/NWC24DateParser.h | 6 ++- .../include/revolution/nwc24/NWC24Time.h | 20 ++++++++++ src/RVL_SDK/net/NETVersion.c | 5 +++ src/RVL_SDK/net/nettime.c | 39 +++++++++++++++++++ 4 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 libs/RVL_SDK/include/revolution/nwc24/NWC24Time.h create mode 100644 src/RVL_SDK/net/NETVersion.c create mode 100644 src/RVL_SDK/net/nettime.c diff --git a/libs/RVL_SDK/include/revolution/nwc24/NWC24DateParser.h b/libs/RVL_SDK/include/revolution/nwc24/NWC24DateParser.h index e24240f41..350497c8e 100644 --- a/libs/RVL_SDK/include/revolution/nwc24/NWC24DateParser.h +++ b/libs/RVL_SDK/include/revolution/nwc24/NWC24DateParser.h @@ -7,8 +7,6 @@ extern "C" { #endif -NWC24Err NWC24iIsValidDate(u16 year, u8 month, u8 day); - typedef struct NWC24iDate { u16 year; u8 month; @@ -18,6 +16,10 @@ typedef struct NWC24iDate { u8 sec; } NWC24iDate; +NWC24Err NWC24iIsValidDate(u16 year, u8 month, u8 day); +NWC24Err NWC24iEpochSecondsToDate(NWC24iDate* date, s64 timestamp); +NWC24Err NWC24iDateToOSCalendarTime(OSCalendarTime* time, const NWC24iDate* date); + #ifdef __cplusplus } #endif diff --git a/libs/RVL_SDK/include/revolution/nwc24/NWC24Time.h b/libs/RVL_SDK/include/revolution/nwc24/NWC24Time.h new file mode 100644 index 000000000..57384b3bf --- /dev/null +++ b/libs/RVL_SDK/include/revolution/nwc24/NWC24Time.h @@ -0,0 +1,20 @@ +#ifndef NWC24TIME_H +#define NWC24TIME_H + +#include "revolution/nwc24.h" +#include "revolution/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +NWC24Err NWC24iGetUniversalTime(s64* timeOut); +NWC24Err NWC24iGetTimeDifference(s64* diffOut); +NWC24Err NWC24iSetRtcCounter(u32 rtc, u32 flags); +NWC24Err NWC24iSynchronizeRtcCounter(BOOL forceSave); + +#ifdef __cplusplus +} +#endif + +#endif // NWC24TIME_H diff --git a/src/RVL_SDK/net/NETVersion.c b/src/RVL_SDK/net/NETVersion.c new file mode 100644 index 000000000..0327b996a --- /dev/null +++ b/src/RVL_SDK/net/NETVersion.c @@ -0,0 +1,5 @@ +char* NETRexPPCVersionPrintableString = "<< REX-PPC 2.1.255.1 (RevoEX-2.1plus) REL 080313085908 >>"; + +char* NETGetRexPPCVersionPrintable() { + return NETRexPPCVersionPrintableString; +} diff --git a/src/RVL_SDK/net/nettime.c b/src/RVL_SDK/net/nettime.c new file mode 100644 index 000000000..d2079ab14 --- /dev/null +++ b/src/RVL_SDK/net/nettime.c @@ -0,0 +1,39 @@ +#include "revolution/nwc24/NWC24DateParser.h" +#include "revolution/nwc24/NWC24Time.h" +#include "revolution/os.h" + +// https://decomp.me/scratch/Gda4L +BOOL NETGetUniversalCalendar(OSCalendarTime* time) { + static s64 whenCached = 0; + NWC24iDate date; + s64 universalTime; + s64 now; + + now = __OSGetSystemTime(); + if (whenCached + OSSecondsToTicks(60) >= now) { + goto use_cache; + } + + if (whenCached == 0) { + goto update; + } + +update: + NWC24iSynchronizeRtcCounter(FALSE); + now = __OSGetSystemTime(); + whenCached = now; +use_cache: + if (NWC24iGetUniversalTime(&universalTime) < 0) { + goto error; + } + if (NWC24iEpochSecondsToDate(&date, universalTime) < 0) { + goto error; + } + if (NWC24iDateToOSCalendarTime(time, &date) < 0) { + goto error; + } + return TRUE; +error: + OSTicksToCalendarTime(OSGetTime(), time); + return FALSE; +} From e4c1340cf294917f828ee13f2469075b5b83c807 Mon Sep 17 00:00:00 2001 From: shibboleet Date: Thu, 26 Feb 2026 09:47:28 -0500 Subject: [PATCH 38/52] Update Discord link in CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 28716ba80..010fcfa8b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -228,4 +228,4 @@ do not mangle to the same symbol. -[Discord]: https://discord.gg/QnZ4cKkZm3 +[Discord]: https://discord.gg/ZxEqyYeZbf From e5364c1844f6cf604bd4d9169e4a82f85ec4f8ea Mon Sep 17 00:00:00 2001 From: MrL314 <11429905+MrL314@users.noreply.github.com> Date: Fri, 27 Feb 2026 05:13:15 -0500 Subject: [PATCH 39/52] `Karikari` at 99%, Match `KarikariDirector` --- config/RMGK01/splits.txt | 20 +- config/RMGK01/symbols.txt | 30 +- configure.py | 2 +- include/Game/Enemy/KariKariDirector.hpp | 43 +- include/Game/Enemy/Karikari.hpp | 58 +- .../include/JSystem/JGeometry/TMatrix.hpp | 2 + .../include/JSystem/JGeometry/TVec.hpp | 25 +- src/Game/Enemy/Karikari.cpp | 970 +++++++++++++++++- src/Game/Enemy/KarikariDirector.cpp | 179 ++++ 9 files changed, 1313 insertions(+), 16 deletions(-) create mode 100644 src/Game/Enemy/KarikariDirector.cpp diff --git a/config/RMGK01/splits.txt b/config/RMGK01/splits.txt index 1166164b5..0b1cc1d0c 100644 --- a/config/RMGK01/splits.txt +++ b/config/RMGK01/splits.txt @@ -2606,6 +2606,7 @@ Game/Enemy/FireBall.cpp: .text start:0x800EC140 end:0x800ECC34 .ctors start:0x8052EA80 end:0x8052EA84 .data start:0x8057C1E0 end:0x8057C2D0 + .sdata start:0x806B1920 end:0x806B1928 .sbss start:0x806B3E98 end:0x806B3EA0 .sdata2 start:0x806BA450 end:0x806BA488 @@ -2614,6 +2615,7 @@ Game/Enemy/FireBubble.cpp: .ctors start:0x8052EA84 end:0x8052EA88 .rodata start:0x80531F48 end:0x80531F78 .data start:0x8057C2D0 end:0x8057C558 + .sdata start:0x806B1928 end:0x806B1930 .sbss start:0x806B3EA0 end:0x806B3EC0 .sdata2 start:0x806BA488 end:0x806BA4C0 @@ -2628,6 +2630,7 @@ Game/Enemy/HammerHeadPackun.cpp: .text start:0x800EF9F4 end:0x800F17B4 .ctors start:0x8052EA8C end:0x8052EA90 .data start:0x8057C840 end:0x8057C978 + .sdata start:0x806B1930 end:0x806B1938 .sbss start:0x806B3EF0 end:0x806B3F20 .sdata2 start:0x806BA548 end:0x806BA5A0 @@ -2635,6 +2638,7 @@ Game/Enemy/Hanachan.cpp: .text start:0x800F17B4 end:0x800F58F4 .ctors start:0x8052EA90 end:0x8052EA94 .data start:0x8057C978 end:0x8057D100 + .sdata start:0x806B1938 end:0x806B1940 .sbss start:0x806B3F20 end:0x806B3FA0 .sdata2 start:0x806BA5A0 end:0x806BA648 @@ -2643,6 +2647,7 @@ Game/Enemy/HomingKiller.cpp: .ctors start:0x8052EA94 end:0x8052EA98 .rodata start:0x80531F78 end:0x80531FE0 .data start:0x8057D100 end:0x8057D290 + .sdata start:0x806B1940 end:0x806B1950 .sbss start:0x806B3FA0 end:0x806B3FC8 .sdata2 start:0x806BA648 end:0x806BA6F0 @@ -2652,6 +2657,7 @@ Game/Enemy/IceMerameraKing.cpp: .rodata start:0x80531FE0 end:0x805320C8 .data start:0x8057D290 end:0x8057D818 .bss start:0x8060A800 end:0x8060A818 + .sdata start:0x806B1950 end:0x806B1958 .sbss start:0x806B3FC8 end:0x806B4010 .sdata2 start:0x806BA6F0 end:0x806BA7A0 @@ -2685,6 +2691,7 @@ Game/Enemy/JumpBeamer.cpp: .text start:0x800FE130 end:0x800FF3A0 .ctors start:0x8052EAA8 end:0x8052EAAC .data start:0x8057DD80 end:0x8057E030 + .sdata start:0x806B1958 end:0x806B1960 .sbss start:0x806B4080 end:0x806B40B0 .sdata2 start:0x806BA860 end:0x806BA898 @@ -2692,6 +2699,7 @@ Game/Enemy/JumpGuarder.cpp: .text start:0x800FF3A0 end:0x80100ED8 .ctors start:0x8052EAAC end:0x8052EAB0 .data start:0x8057E030 end:0x8057E3F8 + .sdata start:0x806B1960 end:0x806B1968 .sbss start:0x806B40B0 end:0x806B40E0 .sdata2 start:0x806BA898 end:0x806BA900 @@ -2699,6 +2707,7 @@ Game/Enemy/JumpSpider.cpp: .text start:0x80100ED8 end:0x8010243C .ctors start:0x8052EAB0 end:0x8052EAB4 .data start:0x8057E3F8 end:0x8057E748 + .sdata start:0x806B1968 end:0x806B1970 .sbss start:0x806B40E0 end:0x806B4120 .sdata2 start:0x806BA900 end:0x806BA948 @@ -2724,6 +2733,7 @@ Game/Enemy/Kameck.cpp: .text start:0x80103DE0 end:0x80105E20 .ctors start:0x8052EABC end:0x8052EAC0 .data start:0x8057E970 end:0x8057ECA0 + .sdata start:0x806B1970 end:0x806B1978 .sbss start:0x806B4150 end:0x806B4190 .sdata2 start:0x806BA9A0 end:0x806BA9E8 @@ -2744,6 +2754,7 @@ Game/Enemy/KameckFireBall.cpp: .text start:0x801074F8 end:0x80107CC0 .ctors start:0x8052EAC4 end:0x8052EAC8 .data start:0x8057F010 end:0x8057F0B8 + .sdata start:0x806B1978 end:0x806B1980 .sbss start:0x806B41A8 end:0x806B41B8 .sdata2 start:0x806BAA00 end:0x806BAA20 @@ -2762,6 +2773,7 @@ Game/Enemy/Kanina.cpp: .text start:0x801088CC end:0x8010B2B0 .ctors start:0x8052EACC end:0x8052EAD0 .data start:0x8057F210 end:0x8057F550 + .sdata start:0x806B1980 end:0x806B1998 .sbss start:0x806B41C0 end:0x806B4218 .sdata2 start:0x806BAA58 end:0x806BAAF8 @@ -2769,27 +2781,29 @@ Game/Enemy/Karikari.cpp: .text start:0x8010B2B0 end:0x8010DFDC .ctors start:0x8052EAD0 end:0x8052EAD4 .data start:0x8057F550 end:0x8057F8D8 + .sdata start:0x806B1998 end:0x806B19A0 .sbss start:0x806B4218 end:0x806B4260 .sdata2 start:0x806BAAF8 end:0x806BAB78 Game/Enemy/KarikariDirector.cpp: .text start:0x8010DFDC end:0x8010E608 .rodata start:0x805320E8 end:0x80532178 - .data start:0x8057F8D8 end:0x8057FA40 + .data start:0x8057F8D8 end:0x8057F920 + .sdata start:0x806B19A0 end:0x806B19A8 .sdata2 start:0x806BAB78 end:0x806BAB88 Game/Enemy/Karon.cpp: .text start:0x8010E608 end:0x80110298 .ctors start:0x8052EAD4 end:0x8052EAD8 .rodata start:0x80532178 end:0x805321F8 - .data start:0x8057FA40 end:0x8057FCB0 + .data start:0x8057F920 end:0x8057FBB8 .sbss start:0x806B4260 end:0x806B42A0 .sdata2 start:0x806BAB88 end:0x806BABE0 Game/Enemy/Kiraira.cpp: .text start:0x80110298 end:0x80111470 .ctors start:0x8052EAD8 end:0x8052EADC - .data start:0x8057FCB0 end:0x8057FDA8 + .data start:0x8057FBB8 end:0x8057FDA8 .sbss start:0x806B42A0 end:0x806B42C0 .sdata2 start:0x806BABE0 end:0x806BAC38 diff --git a/config/RMGK01/symbols.txt b/config/RMGK01/symbols.txt index defdf2770..ccf2c8266 100644 --- a/config/RMGK01/symbols.txt +++ b/config/RMGK01/symbols.txt @@ -47440,10 +47440,34 @@ __vt__Q29NrvKanina26HostTypeVauntAttackSuccess = .data:0x8057F50C; // type:objec __vt__Q29NrvKanina14HostTypeAttack = .data:0x8057F51C; // type:object size:0x10 scope:global align:4 __vt__Q29NrvKanina12HostTypeWait = .data:0x8057F52C; // type:object size:0x10 scope:global align:4 __vt__Q29NrvKanina14HostTypeAppear = .data:0x8057F53C; // type:object size:0x10 scope:global align:4 -lbl_8057F550 = .data:0x8057F550; // type:object size:0x7F +lbl_8057F550 = .data:0x8057F550; // type:object size:0x15 data:string +lbl_8057F565 = .data:0x8057F565; // type:object size:0x8 data:string +lbl_8057F56D = .data:0x8057F56D; // type:object size:0x5 data:string +lbl_8057F572 = .data:0x8057F572; // type:object size:0x15 data:string +lbl_8057F587 = .data:0x8057F587; // type:object size:0x15 data:string +lbl_8057F59C = .data:0x8057F59C; // type:object size:0x14 data:string +lbl_8057F5B0 = .data:0x8057F5B0; // type:object size:0x1F data:string lbl_8057F5CF = .data:0x8057F5CF; // type:object size:0x5 data:string -lbl_8057F5D4 = .data:0x8057F5D4; // type:object size:0x49 -lbl_8057F61D = .data:0x8057F61D; // type:object size:0xE4 +lbl_8057F5D4 = .data:0x8057F5D4; // type:object size:0x5 data:string +lbl_8057F5D9 = .data:0x8057F5D9; // type:object size:0xA data:string +lbl_8057F5E3 = .data:0x8057F5E3; // type:object size:0x5 data:string +lbl_8057F5E8 = .data:0x8057F5E8; // type:object size:0x14 data:string +lbl_8057F5FC = .data:0x8057F5FC; // type:object size:0x7 data:string +lbl_8057F603 = .data:0x8057F603; // type:object size:0x5 data:string +lbl_8057F608 = .data:0x8057F608; // type:object size:0x15 data:string +lbl_8057F61D = .data:0x8057F61D; // type:object size:0x5 data:string +lbl_8057F622 = .data:0x8057F622; // type:object size:0x18 data:string +lbl_8057F63A = .data:0x8057F63A; // type:object size:0x15 data:string +lbl_8057F64F = .data:0x8057F64F; // type:object size:0x6 data:string +lbl_8057F655 = .data:0x8057F655; // type:object size:0x9 data:string +lbl_8057F65E = .data:0x8057F65E; // type:object size:0x17 data:string +lbl_8057F675 = .data:0x8057F675; // type:object size:0x6 data:string +lbl_8057F67B = .data:0x8057F67B; // type:object size:0x1E data:string +lbl_8057F699 = .data:0x8057F699; // type:object size:0x1F data:string +lbl_8057F6B8 = .data:0x8057F6B8; // type:object size:0x12 data:string +lbl_8057F6CA = .data:0x8057F6CA; // type:object size:0x1A data:string +lbl_8057F6E4 = .data:0x8057F6E4; // type:object size:0x6 data:string +lbl_8057F6EA = .data:0x8057F6EA; // type:object size:0x17 data:string lbl_8057F701 = .data:0x8057F701; // type:object size:0xE data:string lbl_8057F70F = .data:0x8057F70F; // type:object size:0x6 data:string lbl_8057F715 = .data:0x8057F715; // type:object size:0x10 data:string diff --git a/configure.py b/configure.py index ef6d69ceb..0f09c6863 100644 --- a/configure.py +++ b/configure.py @@ -1120,7 +1120,7 @@ def JSys_J3DLib(lib_name: str, objects: List[Object]) -> Dict[str, Any]: Object(NonMatching, "Game/Enemy/KameckTurtle.cpp"), Object(NonMatching, "Game/Enemy/Kanina.cpp"), Object(NonMatching, "Game/Enemy/Karikari.cpp"), - Object(NonMatching, "Game/Enemy/KarikariDirector.cpp"), + Object(Matching, "Game/Enemy/KarikariDirector.cpp"), Object(NonMatching, "Game/Enemy/Karon.cpp"), Object(NonMatching, "Game/Enemy/Kiraira.cpp"), Object(NonMatching, "Game/Enemy/KirairaChain.cpp"), diff --git a/include/Game/Enemy/KariKariDirector.hpp b/include/Game/Enemy/KariKariDirector.hpp index 62e217e10..7c0f29bfb 100644 --- a/include/Game/Enemy/KariKariDirector.hpp +++ b/include/Game/Enemy/KariKariDirector.hpp @@ -1,8 +1,49 @@ #pragma once -#include +#include "Game/LiveActor/LiveActorGroup.hpp" +#include + +class Karikari; +class FixedPosition; + +class KarikariDirector : public LiveActorGroup { +public: + KarikariDirector(const char*); + + virtual void movement(); + + bool isMaxNumCling() const; + void removeAllClingingKarikari(); + void blowOutAllClingingKarikari(const TVec3f&); + void electricKillAllClingingKarikari(); + void clearScratchInfo(); + bool requestRelease(Karikari*, TVec2f, f32); + bool registCling(Karikari*); + bool unregistCling(Karikari*); + + inline MtxPtr getClingMtx(int idx) const { + return (MtxPtr)&mClingJointMtxs[idx]; + } + + /* 0x18 */ s32 mClingNum; + /* 0x1C */ TPos3f* mClingJointMtxs; // array + /* 0x20 */ FixedPosition** mClingPositions; + /* 0x24 */ Karikari** mClingingKarikari; + /* 0x28 */ Karikari* mReleaseKarikari; + /* 0x2C */ TVec2f mReleaseVel; + /* 0x34 */ f32 mLowestReleaseDist; + /* 0x38 */ s32 mNoReleaseTime; + /* 0x3C */ s32 mRumbleTime; +}; + +struct ClingData { + /* 0x00 */ const char* mJointName; + /* 0x04 */ Vec mPos; + /* 0x10 */ Vec mRotDegree; +}; namespace MR { s32 getKarikariClingNum(); + s32 getClingNumMax(); void removeAllClingingKarikari(); }; // namespace MR diff --git a/include/Game/Enemy/Karikari.hpp b/include/Game/Enemy/Karikari.hpp index 5ed41771a..fd6b99de6 100644 --- a/include/Game/Enemy/Karikari.hpp +++ b/include/Game/Enemy/Karikari.hpp @@ -1,14 +1,64 @@ #pragma once -#include "Game/NameObj/NameObj.hpp" #include "Game/LiveActor/LiveActor.hpp" +class FixedPosition; class Karikari : public LiveActor { public: Karikari(const char*); - virtual ~Karikari(); -private: - u8 mPad[(0xA8) - sizeof(LiveActor)]; + virtual void init(const JMapInfoIter& rIter); + virtual void kill(); + virtual void makeActorDead(); + virtual void control(); + virtual void calcAndSetBaseMtx(); + virtual void attackSensor(HitSensor* pSender, HitSensor* pReceiver); + virtual bool receiveMsgPush(HitSensor* pSender, HitSensor* pReceiver); + virtual bool receiveMsgPlayerAttack(u32 msg, HitSensor* pSender, HitSensor* pReceiver); + virtual bool receiveMsgEnemyAttack(u32 msg, HitSensor* pSender, HitSensor* pReceiver); + virtual bool receiveOtherMsg(u32 msg, HitSensor* pSender, HitSensor* pReceiver); + + void applyEnvironmentInfluenceToVelocity(); + void killedInFrozenState(); + + void exeFall(); + void exeLand(); + void exeNoCalcWait(); + void exeWait(); + void exePrePursue(); + void exePursue(); + void exeWatchFor(); + void exePreCling(); + void exeCling(); + void exeRelease(); + void exeSpinAttacked(); + void exeDPDAttacked(); + void exeFrozen(); + void exeFrozenRecover(); + void exeBlowOut(); + void exeInTornado(); + void exePress(); + + bool tryBlowOut(const TVec3f&, bool); + bool tryElectricKill(); + bool tryHipDropRelease(); + bool tryDPDRelease(const TVec2f&); + bool tryDPDAttacked(); + + void setVelocityFromCursorMove(const TVec2f&); + void generateItem(s32 numStarPieces); + + void tryTurnToDirection(const TVec3f& rDir, f32 turnRatio); + + bool inClingNerve() const; + + /* 0x8C */ TVec3f mFront; + /* 0x98 */ FixedPosition* mClingPosition; + /* 0x9C */ bool mIsReadyToLandTornado; + /* 0x9D */ bool _9D; + /* 0x9E */ bool _9E; + /* 0x9F */ bool mIsPushable; + /* 0xA0 */ s32 mFrozenTime; + /* 0xA4 */ u32 _A4; }; diff --git a/libs/JSystem/include/JSystem/JGeometry/TMatrix.hpp b/libs/JSystem/include/JSystem/JGeometry/TMatrix.hpp index 7c91ee6b8..2282188a2 100644 --- a/libs/JSystem/include/JSystem/JGeometry/TMatrix.hpp +++ b/libs/JSystem/include/JSystem/JGeometry/TMatrix.hpp @@ -564,6 +564,8 @@ namespace JGeometry { template < class T > struct TPosition3 : public TRotation3< T > { public: + TPosition3(){}; + void getTrans(TVec3f& rDest) const; void setTrans(const TVec3f& rSrc) { diff --git a/libs/JSystem/include/JSystem/JGeometry/TVec.hpp b/libs/JSystem/include/JSystem/JGeometry/TVec.hpp index e38fcca51..6455ad813 100644 --- a/libs/JSystem/include/JSystem/JGeometry/TVec.hpp +++ b/libs/JSystem/include/JSystem/JGeometry/TVec.hpp @@ -86,7 +86,10 @@ namespace JGeometry { return (x >= other.x) && (y >= other.y) ? true : false; } - void sub(const TVec2< T >& rOther); + void sub(const TVec2< T >& rOther) { + x = x - rOther.x; + y = y - rOther.y; + } T length() const { return JGeometry::TUtil< T >::sqrt((x * x) + (y * y)); @@ -104,12 +107,30 @@ namespace JGeometry { return ((x - rOther.x) * (x - rOther.x)) + ((y - rOther.y) * (y - rOther.y)); } + void scale(f32 scalar) { + x *= scalar; + y *= scalar; + } + /* Operators */ - TVec2< T >& operator=(const TVec2< T >& rSrc); + void operator=(const TVec2< T >& rSrc) { + x = rSrc.x; + y = rSrc.y; + } TVec2< T >& operator+(const TVec2< T >& rOther) const; TVec2< T >& operator-(const TVec2< T >& rOther) const; TVec2< T >& operator*(f32 scale) const; + f32 setLength(f32 newlength) { + f32 oldlength = squared(); + if (oldlength <= 0.0000038146973f) { + return 0.0f; + } + f32 lengthinv = JGeometry::TUtil< f32 >::inv_sqrt(oldlength); + scale(lengthinv * newlength); + return lengthinv * oldlength; + }; + T x, y; }; diff --git a/src/Game/Enemy/Karikari.cpp b/src/Game/Enemy/Karikari.cpp index 47c030c4b..58a2e1aac 100644 --- a/src/Game/Enemy/Karikari.cpp +++ b/src/Game/Enemy/Karikari.cpp @@ -1,5 +1,971 @@ #include "Game/Enemy/Karikari.hpp" +#include "Game/Enemy/KarikariDirector.hpp" +#include "Game/LiveActor/HitSensor.hpp" -Karikari::Karikari(const char* pName) : LiveActor(pName) {} -Karikari::~Karikari() {} +namespace { + const f32 sSize = 30.0f; + static const f32 sGravity = 2.4f; + static const f32 sTurnRatio = 0.25f; + // static const f32 sTornadoPower = ; // unused + // static const f32 sTornadoUpPower = ; // unused + // static const f32 sTornadoTangentPower = ; // unused + static const f32 sVelocityDampGround = 0.8f; + static const f32 sVelocityDampAir = 0.98f; + static const f32 sStopVelocitySquared = 100.0f; + static const s32 sJumpAgainTime = 11; + static const s32 sStopSceneTime = 5; + static const f32 sScratchStrongVel = 18.0f; + static const f32 sFromCursorVelScale = 5.0f; + static const f32 sJumpToPrePursueVel = 50.0f; + static const f32 sJumpToPursueVel = 33.0f; + static const f32 sPursueVel = 10.0f; + static const f32 sJumpAnimRate = 1.0f; + static const f32 sDistToPursue = 1000.0f; + static const f32 sWatchForGravity = 1.4f; + static const f32 sWatchForJumpVel = 35.0f; + static const f32 sWatchForDistance = 500.0f; + static const s32 sWatchForJumpTime = 7; + static const s32 sWatchForLoopInterval = 45; + static const s32 sPreClingTime = 3; + static const f32 sDistToCling = 80.0f; + static const s32 sSpinAttackedTime = 8; + static const f32 sVelocityDampSpinAttacked = 0.9f; + // static const f32 sSpinAttackedVel = ; + // static const f32 sSpinAttackedVerticalVel = ; + static const s32 sBlowOutTime = 60; + static const f32 sBlowOutGravity = 1.3f; + static const f32 sBlowOutVel = 10.0f; + static const f32 sBlowOutVerticalVel = 38.0f; + static const f32 sDPDAttackedGravity = 2.4f; + static const f32 sVelocityDampAttacked = 0.9f; + static const f32 sAttackedVel = 43.0f; + static const f32 sAttackedVerticalVel = 33.0f; + static const s32 sFrozenLimitTime = 180; + // static const f32 sSpinFrozenAttackedVel = ; + // static const f32 sFrozenAttackedBySpinRadius = ; + // static const f32 sDeathEffectScale = ; + // static const f32 sIceShadowSize = ; + static const f32 sFrozenRecoverGravity = 2.4f; + static const f32 sJumpToFrozenRecoverVel = 40.0f; + static const s32 sPreWaitTime = 90; + static const s32 sBeginWaitMotionFrame = 20; + static const s32 sPressTime = 40; + static const f32 sExplosionBlowOutVel = 30.0f; + static const f32 sEnemyAttackHitVel = 30.0f; + static const f32 sSpinXAnimRate = 2.0f; + + static const f32 sGravitySpinAttacked = 0.0f; + static const s32 sIceAppearTime = 0; + + KarikariDirector* getKarikariDirector() { + return MR::getSceneObj< KarikariDirector >(SceneObj_KarikariDirector); + } +} // namespace + +namespace NrvKarikari { + NEW_NERVE(HostTypeNrvFall, Karikari, Fall); + NEW_NERVE(HostTypeNrvLand, Karikari, Land); + NEW_NERVE(HostTypeNrvNoCalcWait, Karikari, NoCalcWait); + NEW_NERVE(HostTypeNrvWait, Karikari, Wait); + NEW_NERVE(HostTypeNrvPrePursue, Karikari, PrePursue); + NEW_NERVE(HostTypeNrvPursue, Karikari, Pursue); + NEW_NERVE(HostTypeNrvWatchFor, Karikari, WatchFor); + NEW_NERVE(HostTypeNrvPreCling, Karikari, PreCling); + NEW_NERVE(HostTypeNrvCling, Karikari, Cling); + NEW_NERVE(HostTypeNrvRelease, Karikari, Release); + NEW_NERVE(HostTypeNrvSpinAttacked, Karikari, SpinAttacked); + NEW_NERVE(HostTypeNrvDPDAttacked, Karikari, DPDAttacked); + NEW_NERVE(HostTypeNrvFrozen, Karikari, Frozen); + NEW_NERVE(HostTypeNrvFrozenRecover, Karikari, FrozenRecover); + NEW_NERVE(HostTypeNrvBlowOut, Karikari, BlowOut); + NEW_NERVE(HostTypeNrvBlowOutStarPiece, Karikari, BlowOut); + NEW_NERVE(HostTypeNrvInTornado, Karikari, InTornado); + NEW_NERVE(HostTypeNrvPress, Karikari, Press); +} // namespace NrvKarikari + +Karikari::Karikari(const char* pName) + : LiveActor(pName), mFront(0.0f, 0.0f, 1.0f), mClingPosition(nullptr), mIsReadyToLandTornado(false), _9D(false), _9E(true), mIsPushable(true), + mFrozenTime(0), _A4(0) { +} + +void Karikari::init(const JMapInfoIter& rIter) { + MR::createSceneObj(SceneObj_KarikariDirector); + MR::joinToGroup(this, "カリカリディレクター"); + MR::initDefaultPos(this, rIter); + MR::useStageSwitchWriteDead(this, rIter); + if (MR::useStageSwitchReadAppear(this, rIter)) { + MR::syncStageSwitchAppear(this); + } + initModelManagerWithAnm("Karipon", nullptr, false); + MR::connectToSceneEnemy(this); + MR::initLightCtrl(this); + initSound(4, false); + f32 size = mScale.y * sSize; + initBinder(size, size, 0); + initEffectKeeper(0, nullptr, false); + + initHitSensor(1); + MR::addHitSensor(this, "body", ATYPE_KARIKARI, 32, 100.0f, TVec3f(0.0f, 30.0f, 0.0f)); + MR::initShadowVolumeSphere(this, sSize); + MR::onCalcShadowOneTime(this, nullptr); + initNerve(&NrvKarikari::HostTypeNrvFall::sInstance); + MR::initStarPointerTarget(this, 40.0f, TVec3f(0.0f, 25.0f, 0.0f)); + + if (MR::isValidSwitchAppear(this)) { + makeActorDead(); + } else { + appear(); + } + + MR::onCalcGravity(this); + MR::declareStarPiece(this, 3); +} + +void Karikari::applyEnvironmentInfluenceToVelocity() { + if (MR::isOnGround(this)) { + MR::reboundVelocityFromCollision(this, 0.0f, 0.0f, 1.0f); + mVelocity.mult(sVelocityDampGround); + TVec3f norm(*MR::getGroundNormal(this)); + TVec3f velH(mVelocity); + MR::vecKillElement(velH, norm, &velH); + if (velH.squared() < sStopVelocitySquared) { + mVelocity.scale(norm.dot(mVelocity), norm); + } + return; + } + + if (isNerve(&NrvKarikari::HostTypeNrvSpinAttacked::sInstance)) { + mVelocity.mult(sVelocityDampSpinAttacked); + return; + } + + if (isNerve(&NrvKarikari::HostTypeNrvDPDAttacked::sInstance)) { + mVelocity.mult(sVelocityDampAttacked); + return; + } + + mVelocity.mult(sVelocityDampAir); +} + +void Karikari::killedInFrozenState() { + MR::deleteEffect(this, "KarikariCrystalLight"); + MR::emitEffect(this, "KarikariCrystalBreak"); + MR::startSound(this, "SE_EM_KARIKARI_BLOW", -1, -1); + MR::startSound(this, "SE_EM_KARIKARI_CRUSH_CRYSTAL_L", -1, -1); + generateItem(3); + makeActorDead(); + MR::stopScene(sStopSceneTime); +} + +void Karikari::control() { + if (MR::isInDeath(this, TVec3f(0.0f, 0.0f, 0.0f)) || MR::isInWater(mPosition)) { + kill(); + } +} + +void Karikari::exeFall() { + if (MR::isFirstStep(this)) { + MR::startBck(this, "Wait", nullptr); + _9E = false; + mIsPushable = true; + MR::onBind(this); + MR::onCalcShadow(this, nullptr); + MR::onCalcGravity(this); + MR::startBtp(this, "Bite"); + MR::setBtpFrameAndStop(this, 0.0f); + } + + applyEnvironmentInfluenceToVelocity(); + mVelocity += mGravity.scaleInline(sGravity); + + if (MR::isOnGround(this)) { + MR::emitEffect(this, "SmokeLand"); + setNerve(&NrvKarikari::HostTypeNrvLand::sInstance); + } +} + +void Karikari::exeLand() { + applyEnvironmentInfluenceToVelocity(); + mVelocity += mGravity.scaleInline(sGravity); + + if (MR::isFirstStep(this)) { + MR::startBck(this, "Land", nullptr); + MR::startBtp(this, "Land"); + _9E = false; + mIsPushable = true; + MR::onBind(this); + MR::onCalcShadow(this, nullptr); + MR::onCalcGravity(this); + mVelocity.zero(); + } + + if (tryDPDAttacked() == true) { + return; + } + + if (MR::isGreaterStep(this, sPreWaitTime)) { + TVec3f diff(*MR::getPlayerPos()); + diff.sub(mPosition); + if (diff.squared() < sDistToPursue) { + setNerve(&NrvKarikari::HostTypeNrvPursue::sInstance); + return; + } else { + setNerve(&NrvKarikari::HostTypeNrvWait::sInstance); + return; + } + } + + if (MR::isStep(this, sBeginWaitMotionFrame)) { + MR::startBck(this, "Wait", nullptr); + MR::startBtp(this, "Bite"); + MR::setBtpFrameAndStop(this, 0.0f); + return; + } + + if (MR::isGreaterStep(this, sBeginWaitMotionFrame)) { + TVec3f toPlayerH(MR::getPlayerPos()->subOperatorInLine(mPosition)); + MR::vecKillElement(toPlayerH, mGravity, &toPlayerH); + MR::normalizeOrZero(&toPlayerH); + tryTurnToDirection(toPlayerH, sTurnRatio); + } +} + +void Karikari::exeNoCalcWait() { + if (MR::isFirstStep(this)) { + MR::offBind(this); + MR::offCalcShadow(this, nullptr); + MR::offCalcGravity(this); + _9E = false; + mIsPushable = false; + } + + mVelocity.zero(); + if (MR::calcDistanceToPlayer(mPosition) < 1000.0f) { + setNerve(&NrvKarikari::HostTypeNrvWait::sInstance); + } +} + +void Karikari::exeWait() { + applyEnvironmentInfluenceToVelocity(); + mVelocity += mGravity.scaleInline(sGravity); + + if (MR::isFirstStep(this)) { + MR::onBind(this); + MR::onCalcShadow(this, nullptr); + MR::onCalcGravity(this); + MR::validateHitSensors(this); + MR::startBck(this, "Wait", nullptr); + MR::startBtp(this, "Bite"); + MR::setBtpFrameAndStop(this, 0.0f); + _9E = true; + mIsPushable = true; + } + + if (tryDPDAttacked() == true) { + return; + } + + TVec3f diff(*MR::getPlayerPos()); + diff.sub(mPosition); + if (diff.squared() < sDistToPursue * sDistToPursue) { + setNerve(&NrvKarikari::HostTypeNrvPrePursue::sInstance); + return; + } + + if (MR::isOnGround(this)) { + setNerve(&NrvKarikari::HostTypeNrvNoCalcWait::sInstance); + } +} + +void Karikari::exePrePursue() { + if (MR::isFirstStep(this)) { + MR::onBind(this); + MR::onCalcShadow(this, nullptr); + MR::onCalcGravity(this); + MR::validateHitSensors(this); + MR::startSound(this, "SE_EM_KARIKARI_FIND", -1, -1); + MR::startBck(this, "Search", nullptr); + MR::startBtp(this, "Bite"); + MR::setBtpFrameAndStop(this, 0.0f); + _9E = true; + mIsPushable = false; + } + + applyEnvironmentInfluenceToVelocity(); + mVelocity += mGravity.scaleInline(sGravity); + + if (tryDPDAttacked() == true) { + return; + } + + if (MR::isLessStep(this, sJumpAgainTime)) { + TVec3f toPlayer(MR::getPlayerPos()->subOperatorInLine(mPosition)); + tryTurnToDirection(toPlayer, sTurnRatio); + mIsPushable = true; + return; + } + + if (MR::isStep(this, sJumpAgainTime)) { + mVelocity.sub(mGravity.scaleInline(sJumpToPrePursueVel)); + mIsPushable = false; + return; + } + + if (MR::isOnGround(this)) { + setNerve(&NrvKarikari::HostTypeNrvPursue::sInstance); + MR::emitEffect(this, "SmokeLand"); + } +} + +void Karikari::exePursue() { + if (MR::isFirstStep(this)) { + MR::onBind(this); + MR::onCalcShadow(this, nullptr); + MR::onCalcGravity(this); + MR::validateHitSensors(this); + MR::startBck(this, "Jump", nullptr); + MR::setBckRate(this, sJumpAnimRate); + MR::startBtp(this, "Bite"); + MR::setBtpFrameAndStop(this, 0.0f); + _9E = true; + mIsPushable = true; + } + + applyEnvironmentInfluenceToVelocity(); + mVelocity += mGravity.scaleInline(sGravity); + + if (tryDPDAttacked() == true) { + return; + } + + TVec3f toPlayerH(MR::getPlayerPos()->subOperatorInLine(mPosition)); + f32 dist = toPlayerH.squared(); + MR::vecKillElement(toPlayerH, mGravity, &toPlayerH); + MR::normalizeOrZero(&toPlayerH); + if (MR::isLessStep(this, sJumpAgainTime)) { + mIsPushable = true; + tryTurnToDirection(toPlayerH, sTurnRatio); + return; + } + + if (MR::isStep(this, sJumpAgainTime)) { + MR::startSound(this, "SE_EM_KARIKARI_JUMP2", -1, -1); + mVelocity.sub(mGravity.scaleInline(sJumpToPursueVel)); + toPlayerH.scale(sPursueVel); + mVelocity += toPlayerH; + return; + } + + if (MR::isOnGround(this)) { + MR::emitEffect(this, "SmokeLand"); + if (getKarikariDirector()->isMaxNumCling()) { + setNerve(&NrvKarikari::HostTypeNrvWatchFor::sInstance); + return; + } + + if (sDistToPursue < dist) { + setNerve(&NrvKarikari::HostTypeNrvWait::sInstance); + return; + } + + tryTurnToDirection(toPlayerH, sTurnRatio); + setNerve(&NrvKarikari::HostTypeNrvPursue::sInstance); + + } else { + mIsPushable = false; + } +} + +void Karikari::exeWatchFor() { + if (MR::isFirstStep(this)) { + MR::onBind(this); + MR::onCalcShadow(this, nullptr); + MR::onCalcGravity(this); + MR::validateHitSensors(this); + MR::startBck(this, "Glad", nullptr); + MR::startBtp(this, "Bite"); + MR::setBtpFrameAndStop(this, 0.0f); + _9E = false; + mIsPushable = true; + } + + applyEnvironmentInfluenceToVelocity(); + mVelocity += mGravity.scaleInline(sWatchForGravity); + + if (tryDPDAttacked() == true) { + return; + } + + if (!MR::isOnGround(this)) { + return; + } + + if (MR::isLessStep(this, sWatchForJumpTime)) { + TVec3f toPlayer(MR::getPlayerPos()->subOperatorInLine(mPosition)); + tryTurnToDirection(toPlayer, sTurnRatio); + + if (!getKarikariDirector()->isMaxNumCling() || sWatchForDistance * sWatchForDistance < toPlayer.squared()) { + setNerve(&NrvKarikari::HostTypeNrvPrePursue::sInstance); + } + return; + } + + if (MR::isStep(this, sWatchForJumpTime)) { + mVelocity.sub(mGravity.scaleInline(sWatchForJumpVel)); + return; + } + + if (MR::isGreaterStep(this, sWatchForLoopInterval)) { + setNerve(&NrvKarikari::HostTypeNrvWatchFor::sInstance); + } +} + +void Karikari::exePreCling() { + if (MR::isFirstStep(this)) { + MR::offBind(this); + MR::onCalcShadow(this, nullptr); + MR::onCalcGravity(this); + MR::validateHitSensors(this); + MR::startBck(this, "Wait", nullptr); + MR::startBtp(this, "Bite"); + MR::setBtpFrameAndStop(this, 0.0f); + _9E = false; + mIsPushable = false; + } + + if (tryDPDAttacked() == true) { + return; + } + + TVec3f toClingPos; + f32 t = getNerveStep() / static_cast< f32 >(sPreClingTime); + mClingPosition->copyTrans(&toClingPos); + toClingPos.sub(mPosition); + mVelocity = mVelocity.scaleInline(1.0f - t).translate(toClingPos.scaleInline(t)); + MR::startLevelSound(this, "SE_EM_LV_KARIKARI_CLING", -1, -1, -1); + + if (MR::isGreaterStep(this, sPreClingTime)) { + MR::onBind(this); + setNerve(&NrvKarikari::HostTypeNrvCling::sInstance); + } +} + +void Karikari::exeCling() { + if (MR::isFirstStep(this)) { + MR::offBind(this); + MR::offCalcShadow(this, nullptr); + MR::invalidateShadow(this, nullptr); + MR::offCalcGravity(this); + MR::validateHitSensors(this); + _9E = false; + mIsPushable = false; + MR::setBckRate(this, 1.0f); + MR::startBck(this, "Bite", nullptr); + MR::startBtp(this, "Bite"); + MR::startSound(this, "SE_EM_KARIKARI_TOUCH", -1, -1); + mVelocity.zero(); + } + + if (tryDPDAttacked() == true) { + return; + } + + mClingPosition->copyTrans(&mPosition); + MR::startLevelSound(this, "SE_EM_LV_KARIKARI_CLING", -1, -1, -1); +} + +void Karikari::exeRelease() { + if (MR::isFirstStep(this)) { + MR::startBtp(this, "Bite"); + MR::setBtpFrameAndStop(this, 0.0f); + } + + TVec3f away(mPosition); + away.sub(*MR::getPlayerPos()); + MR::vecKillElement(away, mGravity, &away); + away.setLength(sAttackedVel); + away.sub(mGravity.scaleInline(sAttackedVerticalVel)); + mVelocity.set(away); + setNerve(&NrvKarikari::HostTypeNrvSpinAttacked::sInstance); +} + +void Karikari::exeSpinAttacked() { + if (MR::isFirstStep(this)) { + MR::onBind(this); + MR::onCalcShadow(this, nullptr); + MR::onCalcGravity(this); + MR::validateShadow(this, nullptr); + MR::validateHitSensors(this); + MR::startBck(this, "SpinX", nullptr); + MR::setBckRate(this, sSpinXAnimRate); + MR::startBtp(this, "Bite"); + MR::setBtpFrameAndStop(this, 0.0f); + MR::startSystemME("ME_MAGIC"); + _9E = false; + mIsPushable = true; + _A4 = 0; + } + + applyEnvironmentInfluenceToVelocity(); + mVelocity += mGravity.scaleInline(sGravitySpinAttacked); + + if (MR::isGreaterStep(this, sSpinAttackedTime)) { + setNerve(&NrvKarikari::HostTypeNrvFrozen::sInstance); + } +} + +void Karikari::exeDPDAttacked() { + if (MR::isFirstStep(this)) { + MR::onBind(this); + MR::onCalcShadow(this, nullptr); + MR::onCalcGravity(this); + MR::validateShadow(this, nullptr); + MR::validateHitSensors(this); + MR::startBck(this, "SpinX", nullptr); + MR::setBckRate(this, sSpinXAnimRate); + MR::startBtp(this, "Bite"); + MR::setBtpFrameAndStop(this, 0.0f); + _9E = false; + mIsPushable = true; + _A4 = 0; + MR::startSound(this, "SE_EM_KARIKARI_RELEASE", -1, -1); + MR::emitEffect(this, "Touch"); + } + + applyEnvironmentInfluenceToVelocity(); + mVelocity += mGravity.scaleInline(sDPDAttackedGravity); + + if (MR::isOnGround(this)) { + MR::emitEffect(this, "SmokeLand"); + setNerve(&NrvKarikari::HostTypeNrvLand::sInstance); + } +} + +void Karikari::exeFrozen() { + if (MR::isFirstStep(this)) { + MR::offBind(this); + MR::offCalcShadow(this, nullptr); + MR::offCalcGravity(this); + MR::validateHitSensors(this); + _9E = true; + mIsPushable = false; + MR::startBtp(this, "Bite"); + MR::setBtpFrameAndStop(this, 0.0f); + mVelocity.zero(); + MR::startBck(this, "Wait", nullptr); + MR::setBckFrameAndStop(this, 0.0f); + MR::emitEffect(this, "KarikariCrystalLight"); + mFrozenTime = sFrozenLimitTime; + } + + if (MR::isStep(this, sIceAppearTime)) { + MR::invalidateShadow(this, nullptr); + MR::startSound(this, "SE_EM_KARIKARI_FREEZE_CRYSTAL", -1, -1); + } + + if (--mFrozenTime <= 0) { + MR::onBind(this); + setNerve(&NrvKarikari::HostTypeNrvFrozenRecover::sInstance); + } +} + +void Karikari::exeFrozenRecover() { + if (MR::isFirstStep(this)) { + MR::onBind(this); + MR::onCalcShadow(this, nullptr); + MR::onCalcGravity(this); + MR::validateShadow(this, nullptr); + MR::validateHitSensors(this); + _9E = true; + mIsPushable = true; + + mVelocity = (-mGravity).scaleInline(sJumpToFrozenRecoverVel); + + MR::deleteEffect(this, "KarikariCrystalLight"); + MR::emitEffect(this, "KarikariCrystalBreak"); + MR::startSound(this, "SE_EM_KARIKARI_CRUSH_CRYSTAL_M", -1, -1); + MR::startBck(this, "SpinX", nullptr); + MR::setBckRate(this, sSpinXAnimRate); + MR::startBtp(this, "Bite"); + MR::setBtpFrameAndStop(this, 0.0f); + } + + applyEnvironmentInfluenceToVelocity(); + mVelocity += mGravity.scaleInline(sFrozenRecoverGravity); + + if (MR::isOnGround(this)) { + MR::emitEffect(this, "KarikariSmokeLand"); + setNerve(&NrvKarikari::HostTypeNrvLand::sInstance); + } +} + +void Karikari::exeBlowOut() { + if (MR::isFirstStep(this)) { + MR::onBind(this); + MR::onCalcShadow(this, nullptr); + MR::onCalcGravity(this); + MR::validateShadow(this, nullptr); + MR::validateHitSensors(this); + _9E = false; + mIsPushable = true; + MR::startSound(this, "SE_EM_KARIKARI_BLOW", -1, -1); + MR::startBck(this, "SpinX", nullptr); + MR::setBckRate(this, sSpinXAnimRate); + MR::startBtp(this, "Bite"); + MR::setBtpFrameAndStop(this, 0.0f); + MR::startBlowHitSound(this); + } + + applyEnvironmentInfluenceToVelocity(); + mVelocity += mGravity.scaleInline(sBlowOutGravity); + + if (MR::isBinded(this) || MR::isGreaterStep(this, sBlowOutTime)) { + if (isNerve(&NrvKarikari::HostTypeNrvBlowOut::sInstance)) { + generateItem(1); + } else { + generateItem(3); + } + kill(); + } +} + +void Karikari::exeInTornado() { + if (MR::isFirstStep(this)) { + MR::onBind(this); + MR::onCalcShadow(this, nullptr); + MR::onCalcGravity(this); + MR::validateHitSensors(this); + MR::startBck(this, "Wait", nullptr); + MR::setBckRate(this, 2.0f); + MR::startBtp(this, "Bite"); + MR::setBtpFrameAndStop(this, 0.0f); + _9E = false; + mIsPushable = true; + } + + applyEnvironmentInfluenceToVelocity(); + mVelocity += mGravity.scaleInline(sGravity); + + MR::startLevelSound(this, "SE_EM_LV_KARIKARI_TORNADO", -1, -1, -1); + + if (!mIsReadyToLandTornado && MR::isOnGround(this)) { + setNerve(&NrvKarikari::HostTypeNrvWait::sInstance); + MR::emitEffect(this, "SmokeLand"); + return; + } + + mIsReadyToLandTornado = false; +} + +void Karikari::exePress() { + if (MR::isFirstStep(this)) { + MR::onBind(this); + MR::onCalcShadow(this, nullptr); + MR::onCalcGravity(this); + MR::invalidateHitSensors(this); + MR::startBck(this, "Press", nullptr); + MR::startBtp(this, "Bite"); + MR::setBtpFrameAndStop(this, 0.0f); + MR::startSound(this, "SE_EM_KARIKARI_STOMPED", -1, -1); + } + + applyEnvironmentInfluenceToVelocity(); + mVelocity += mGravity.scaleInline(sGravity); + + if (MR::isGreaterStep(this, sPressTime)) { + kill(); + } +} + +bool Karikari::inClingNerve() const { + return isNerve(&NrvKarikari::HostTypeNrvPreCling::sInstance) || isNerve(&NrvKarikari::HostTypeNrvCling::sInstance); +} + +bool Karikari::tryBlowOut(const TVec3f& rPos, bool spawnMultipleStarPieces) { + if (isNerve(&NrvKarikari::HostTypeNrvBlowOut::sInstance) || isNerve(&NrvKarikari::HostTypeNrvBlowOutStarPiece::sInstance) || + isNerve(&NrvKarikari::HostTypeNrvRelease::sInstance) || isNerve(&NrvKarikari::HostTypeNrvSpinAttacked::sInstance) || + isNerve(&NrvKarikari::HostTypeNrvDPDAttacked::sInstance) || isNerve(&NrvKarikari::HostTypeNrvPress::sInstance)) { + return false; + } + + TVec3f toPosition(mPosition); + toPosition.sub(rPos); + MR::vecKillElement(toPosition, mGravity, &toPosition); + toPosition.setLength(sBlowOutVel); + toPosition.sub(mGravity.scaleInline(sBlowOutVerticalVel)); + mVelocity = toPosition; + + MR::emitEffect(this, "Hit"); + + if (inClingNerve()) { + getKarikariDirector()->unregistCling(this); + } + + if (spawnMultipleStarPieces) { + setNerve(&NrvKarikari::HostTypeNrvBlowOutStarPiece::sInstance); + } else { + setNerve(&NrvKarikari::HostTypeNrvBlowOut::sInstance); + } + + return true; +} + +bool Karikari::tryElectricKill() { + if (!inClingNerve()) { + return false; + } + + MR::emitEffect(this, "ElectricDeath"); + makeActorDead(); + return true; +} + +bool Karikari::tryHipDropRelease() { + TVec3f away(mPosition); + away.sub(*MR::getPlayerPos()); + MR::vecKillElement(away, mGravity, &away); + away.setLength(sAttackedVel); + away.sub(mGravity.scaleInline(sAttackedVerticalVel)); + mVelocity.set(away); + setNerve(&NrvKarikari::HostTypeNrvDPDAttacked::sInstance); + return true; +} + +bool Karikari::tryDPDRelease(const TVec2f& rVel) { + setVelocityFromCursorMove(rVel); + setNerve(&NrvKarikari::HostTypeNrvDPDAttacked::sInstance); + return true; +} + +bool Karikari::tryDPDAttacked() { + // FIXME: TVec2 copy operations are done via memregs, not float regs + // https://decomp.me/scratch/W6YWF + + if (MR::isStarPointerPointing2POnPressButton(this, "弱", true, false)) { + MR::startDPDHitSound(); + s32 padChannel = *MR::getStarPointerLastPointedPort(this); + TVec2f pointerVel(*MR::getStarPointerScreenVelocity(padChannel)); + TVec2f pointingPos; + TVec2f screenPos; + MR::getCorePadPointingPosBasedOnScreen(&pointingPos, padChannel); + MR::calcScreenPosition(&screenPos, mPosition); + TVec2f fromCursorPos = screenPos; + fromCursorPos.sub(pointingPos); + TVec2f vel(pointerVel); + if (MR::isNearZero(pointerVel)) { + vel = fromCursorPos; + vel.setLength(sFromCursorVelScale); + } + + if (inClingNerve()) { + getKarikariDirector()->requestRelease(this, vel, fromCursorPos.squared()); + } else { + setVelocityFromCursorMove(vel); + setNerve(&NrvKarikari::HostTypeNrvDPDAttacked::sInstance); + } + return true; + } + + return false; +} + +void Karikari::setVelocityFromCursorMove(const TVec2f& rVel) { + TVec3f camX = MR::getCamXdir(); + TVec3f camY = -MR::getCamYdir(); + mVelocity = camX.scaleInline(rVel.x).translate(camY.scaleInline(rVel.y)); + if (mVelocity.dot(mGravity) > 0.0f) { + MR::vecKillElement(mVelocity, mGravity, &mVelocity); + } + mVelocity.setLength(sScratchStrongVel); + mVelocity.sub(mGravity.scaleInline(40.0f)); +} + +void Karikari::makeActorDead() { + LiveActor::makeActorDead(); + if (MR::isValidSwitchDead(this)) { + MR::onSwitchDead(this); + } + + if (isNerve(&NrvKarikari::HostTypeNrvPreCling::sInstance) || isNerve(&NrvKarikari::HostTypeNrvCling::sInstance)) { + getKarikariDirector()->unregistCling(this); + } +} + +void Karikari::kill() { + MR::emitEffect(this, "Death"); + MR::startSound(this, "SE_EM_EXPLODE_S", -1, -1); + LiveActor::kill(); +} + +void Karikari::generateItem(s32 numStarPieces) { + // FIXME: TVec and register order + // https://decomp.me/scratch/hBIP5 + + TVec3f pos = (-mGravity).scaleInline(80.0f); + pos += mPosition; + MR::startSound(this, "SE_OJ_STAR_PIECE_BURST", -1, -1); + MR::appearStarPiece(this, pos, numStarPieces, 10.0f, 40.0f, false); +} + +void Karikari::attackSensor(HitSensor* pSender, HitSensor* pReceiver) { + if (isNerve(&NrvKarikari::HostTypeNrvCling::sInstance) || isNerve(&NrvKarikari::HostTypeNrvPreCling::sInstance) || + isNerve(&NrvKarikari::HostTypeNrvBlowOut::sInstance) || isNerve(&NrvKarikari::HostTypeNrvBlowOutStarPiece::sInstance) || + isNerve(&NrvKarikari::HostTypeNrvSpinAttacked::sInstance)) { + return; + } + + if (!pSender->isType(ATYPE_KARIKARI)) { + return; + } + + if (mIsPushable && MR::isSensorEnemy(pReceiver)) { + MR::sendMsgPush(pReceiver, pSender); + return; + } + + if (_9E && MR::isSensorPlayer(pReceiver)) { + if (isNerve(&NrvKarikari::HostTypeNrvFrozen::sInstance)) { + killedInFrozenState(); + return; + } + + TVec3f diff = pSender->mPosition.subOperatorInLine(pReceiver->mPosition); + f32 dist = diff.squared(); + f32 clingDist = sDistToCling; + if (dist < clingDist * clingDist) { + if (getKarikariDirector()->registCling(this)) { + setNerve(&NrvKarikari::HostTypeNrvPreCling::sInstance); + mVelocity.zero(); + } + } + } +} + +bool Karikari::receiveOtherMsg(u32 msg, HitSensor* pSender, HitSensor* pReceiver) { + if (MR::isMsgHitmarkEmit(msg)) { + return true; + } + + if (MR::isMsgInhaleBlackHole(msg)) { + kill(); + return true; + } + + return false; +} + +bool Karikari::receiveMsgPlayerAttack(u32 msg, HitSensor* pSender, HitSensor* pReceiver) { + if (MR::isMsgLockOnStarPieceShoot(msg)) { + return true; + } + + if (MR::isMsgStarPieceAttack(msg)) { + return tryBlowOut(pSender->mPosition, true); + } + + if (inClingNerve()) { + return false; + } + + if (MR::isMsgPlayerHitAll(msg)) { + return tryBlowOut(pSender->mPosition, false); + } + + return false; +} + +bool Karikari::receiveMsgPush(HitSensor* pSender, HitSensor* pReceiver) { + if (pReceiver->mType != ATYPE_KARIKARI) { + return false; + } + + if (isNerve(&NrvKarikari::HostTypeNrvCling::sInstance) || isNerve(&NrvKarikari::HostTypeNrvPreCling::sInstance) || + isNerve(&NrvKarikari::HostTypeNrvBlowOut::sInstance) || isNerve(&NrvKarikari::HostTypeNrvBlowOutStarPiece::sInstance) || + isNerve(&NrvKarikari::HostTypeNrvFrozen::sInstance)) { + return false; + } + + if (MR::isSensorEnemy(pSender) || MR::isSensorMapObj(pSender)) { + TVec3f diff(mPosition); + diff.sub(pSender->mHost->mPosition); + MR::normalizeOrZero(&diff); + mVelocity += diff; + return true; + } + + return false; +} + +bool Karikari::receiveMsgEnemyAttack(u32 msg, HitSensor* pSender, HitSensor* pReceiver) { + if (isNerve(&NrvKarikari::HostTypeNrvRelease::sInstance) || isNerve(&NrvKarikari::HostTypeNrvSpinAttacked::sInstance) || + isNerve(&NrvKarikari::HostTypeNrvBlowOut::sInstance) || isNerve(&NrvKarikari::HostTypeNrvBlowOutStarPiece::sInstance) || + isNerve(&NrvKarikari::HostTypeNrvPress::sInstance)) { + return false; + } + + if (isNerve(&NrvKarikari::HostTypeNrvFrozen::sInstance)) { + killedInFrozenState(); + return true; + } + + if (MR::isMsgToEnemyAttackBlow(msg)) { + if (isNerve(&NrvKarikari::HostTypeNrvPreCling::sInstance) || isNerve(&NrvKarikari::HostTypeNrvCling::sInstance)) { + getKarikariDirector()->unregistCling(this); + } + // blow away from enemy + TVec3f vel(pReceiver->mPosition); + vel.sub(pSender->mPosition); + MR::normalizeOrZero(&vel); + vel.scale(sEnemyAttackHitVel); + mVelocity.set(vel); + setNerve(&NrvKarikari::HostTypeNrvBlowOut::sInstance); + return true; + } + + if (MR::isMsgToEnemyAttackTrample(msg)) { + if (isNerve(&NrvKarikari::HostTypeNrvPreCling::sInstance) || isNerve(&NrvKarikari::HostTypeNrvCling::sInstance)) { + getKarikariDirector()->unregistCling(this); + } + + setNerve(&NrvKarikari::HostTypeNrvPress::sInstance); + return true; + } + + if (MR::isMsgExplosionAttack(msg)) { + if (isNerve(&NrvKarikari::HostTypeNrvFrozen::sInstance)) { + killedInFrozenState(); + return true; + } + + if (isNerve(&NrvKarikari::HostTypeNrvPreCling::sInstance) || isNerve(&NrvKarikari::HostTypeNrvCling::sInstance)) { + getKarikariDirector()->unregistCling(this); + } + // blow away from explosion + TVec3f vel(pReceiver->mPosition); + vel.sub(pSender->mPosition); + vel.setLength(sExplosionBlowOutVel); + mVelocity = vel; + setNerve(&NrvKarikari::HostTypeNrvBlowOut::sInstance); + return true; + } + + return false; +} + +void Karikari::tryTurnToDirection(const TVec3f& rDir, f32 turnRatio) { + TQuat4f rot; + rot.setRotate(mFront, rDir, turnRatio); + rot.transform(mFront); +} + +void Karikari::calcAndSetBaseMtx() { + if (isNerve(&NrvKarikari::HostTypeNrvCling::sInstance)) { + MR::setBaseTRMtx(this, mClingPosition->mMtx); + return; + } + + TPos3f mtx; + MR::calcMtxFromGravityAndZAxis(&mtx, this, mGravity, mFront); + MR::setBaseTRMtx(this, mtx); +} diff --git a/src/Game/Enemy/KarikariDirector.cpp b/src/Game/Enemy/KarikariDirector.cpp new file mode 100644 index 000000000..652b6e22d --- /dev/null +++ b/src/Game/Enemy/KarikariDirector.cpp @@ -0,0 +1,179 @@ +#include "Game/Enemy/KarikariDirector.hpp" +#include "Game/Enemy/Karikari.hpp" +#include "Game/Scene/SceneObjHolder.hpp" +#include "Game/Util/FixedPosition.hpp" + +namespace { + + const ClingData cling_data[] = {{"FacePosition", {-5.86f, 35.0f, 17.0f}, {-18.63f, 8.09f, -23.03f}}, + {"ArmL2", {0.0f, 0.0f, 0.0f}, {0.0f, -27.42f, 0.0f}}, + {"Hip", {-19.04f, 5.86f, 5.86f}, {165.59f, 80.86f, 0.0f}}, + {"Spine1", {0.0f, 0.0f, 0.0f}, {0.0f, 113.55f, 0.0f}}, + {"ShoulderR", {19.04f, 0.0f, 0.0f}, {2.29f, -199.69f, 205.0f}}}; + + static const s32 hKarikariHoldingMax = ARRAY_SIZE(cling_data); + static const s32 sNoReleaseTime = 10; + static const s32 sRumbleInterval = 120; + + KarikariDirector* getKarikariDirector() { + return MR::getSceneObj< KarikariDirector >(SceneObj_KarikariDirector); + } +} // namespace + +KarikariDirector::KarikariDirector(const char* pName) + : LiveActorGroup(pName, 128), mClingNum(0), mClingJointMtxs(nullptr), mClingPositions(nullptr), mClingingKarikari(nullptr), + mReleaseKarikari(nullptr), mReleaseVel(0.0f, 0.0f), mLowestReleaseDist(999999.0f), mNoReleaseTime(0) { + MR::connectToSceneEnemyMovement(this); + mClingJointMtxs = new TPos3f[5]; + mClingPositions = new FixedPosition*[hKarikariHoldingMax]; + mClingingKarikari = new Karikari*[hKarikariHoldingMax]; + + for (s32 idx = 0; idx < hKarikariHoldingMax; idx++) { + mClingingKarikari[idx] = nullptr; + mClingPositions[idx] = new FixedPosition(getClingMtx(idx), TVec3f(cling_data[idx].mPos.x, cling_data[idx].mPos.y, cling_data[idx].mPos.z), + TVec3f(cling_data[idx].mRotDegree.x, cling_data[idx].mRotDegree.y, cling_data[idx].mRotDegree.z)); + } +} + +bool KarikariDirector::isMaxNumCling() const { + return mClingNum == hKarikariHoldingMax; +} + +void KarikariDirector::removeAllClingingKarikari() { + for (s32 idx = 0; idx < hKarikariHoldingMax; idx++) { + Karikari* karikari = mClingingKarikari[idx]; + if (karikari != nullptr) { + karikari->tryHipDropRelease(); + unregistCling(karikari); + } + } +} + +void KarikariDirector::blowOutAllClingingKarikari(const TVec3f& rPos) { + for (s32 idx = 0; idx < hKarikariHoldingMax; idx++) { + Karikari* karikari = mClingingKarikari[idx]; + if (karikari != nullptr) { + karikari->tryBlowOut(rPos, false); + } + } +} + +void KarikariDirector::electricKillAllClingingKarikari() { + for (s32 idx = 0; idx < hKarikariHoldingMax; idx++) { + Karikari* karikari = mClingingKarikari[idx]; + if (karikari != nullptr) { + karikari->tryElectricKill(); + } + } +} + +void KarikariDirector::movement() { + if (mClingNum == 0) { + mRumbleTime = 1; + return; + } + + if (MR::isPlayerSwingAction()) { + blowOutAllClingingKarikari(*MR::getPlayerPos()); + clearScratchInfo(); + } else if (MR::isPlayerParalyzing()) { + electricKillAllClingingKarikari(); + clearScratchInfo(); + } else if (MR::isPlayerInRush()) { + removeAllClingingKarikari(); + clearScratchInfo(); + } else if (mReleaseKarikari != nullptr) { + unregistCling(mReleaseKarikari); + mReleaseKarikari->tryDPDRelease(mReleaseVel); + clearScratchInfo(); + } else { + mNoReleaseTime--; + } + + mRumbleTime = (mRumbleTime + 1 + sRumbleInterval) % sRumbleInterval; + + for (s32 idx = 0; idx < hKarikariHoldingMax; idx++) { + MR::calcPlayerJointMtx(&mClingJointMtxs[idx], cling_data[idx].mJointName); + mClingPositions[idx]->calc(); + } +} + +void KarikariDirector::clearScratchInfo() { + mReleaseKarikari = nullptr; + mLowestReleaseDist = 100000000.0f; + mReleaseVel.y = 0.0f; + mReleaseVel.x = 0.0f; + mNoReleaseTime = sNoReleaseTime; +} + +bool KarikariDirector::requestRelease(Karikari* pReleaseKarikari, TVec2f releaseVel, f32 dist) { + if (mNoReleaseTime > 0) { + return false; + } + + if (mLowestReleaseDist < dist) { + return false; + } + + mReleaseKarikari = pReleaseKarikari; + mLowestReleaseDist = dist; + mReleaseVel = releaseVel; + + return true; +} + +bool KarikariDirector::registCling(Karikari* pKarikari) { + if (mClingNum >= hKarikariHoldingMax) { + return false; + } + + mClingNum++; + + for (s32 idx = 0; idx < hKarikariHoldingMax; idx++) { + if (mClingingKarikari[idx] == nullptr) { + mClingingKarikari[idx] = pKarikari; + pKarikari->mClingPosition = mClingPositions[idx]; + return true; + } + } + + return false; +} + +bool KarikariDirector::unregistCling(Karikari* pKarikari) { + mClingNum--; + + for (s32 idx = 0; idx < hKarikariHoldingMax; idx++) { + if (mClingingKarikari[idx] == pKarikari) { + mClingingKarikari[idx] = nullptr; + return true; + } + } + + return false; +} + +s32 MR::getKarikariClingNum() { + if (!MR::isExistSceneObj(SceneObj_KarikariDirector)) { + return 0; + } + + KarikariDirector* director = getKarikariDirector(); + return director->mClingNum; +} + +s32 MR::getClingNumMax() { + if (!MR::isExistSceneObj(SceneObj_KarikariDirector)) { + return 0; + } + + KarikariDirector* director = getKarikariDirector(); + return hKarikariHoldingMax; +} + +void MR::removeAllClingingKarikari() { + if (MR::isExistSceneObj(SceneObj_KarikariDirector)) { + KarikariDirector* director = getKarikariDirector(); + director->removeAllClingingKarikari(); + } +} From 77ee386805d7bbe6a417523b0d7d29d23671b6f3 Mon Sep 17 00:00:00 2001 From: shibbo Date: Fri, 27 Feb 2026 12:19:23 -0500 Subject: [PATCH 40/52] bad attempt at `NETMemSet` --- src/RVL_SDK/net/netmemset.c | 85 +++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 src/RVL_SDK/net/netmemset.c diff --git a/src/RVL_SDK/net/netmemset.c b/src/RVL_SDK/net/netmemset.c new file mode 100644 index 000000000..582b4bda3 --- /dev/null +++ b/src/RVL_SDK/net/netmemset.c @@ -0,0 +1,85 @@ +#include "revolution/types.h" +#include + +void* NETMemSet(void* buf, int ch, u32 size) { + u8* p; + u8* ret; + u32 v; + u32 align; + u32 head; + u32 blocks; + u32 words; + u32 bytes; + + ret = (u8*)buf; + p = (u8*)buf; + + if (size == 0) + return ret; + + v = (u8)ch; + v |= v << 8; + v |= v << 16; + + if (size >= 0x40) { + align = (u32)p & 0x1F; + + if (align) { + head = 32 - align; + if (head > size) + head = size; + + words = head >> 2; + while (words--) { + *(u32*)p = v; + p += 4; + } + + bytes = head & 3; + while (bytes--) { + *p++ = (u8)v; + } + + size -= head; + } + + blocks = size >> 5; + + if (v != 0) { + while (blocks--) { + __dcbz(p, 0); + + ((u32*)p)[0] = v; + ((u32*)p)[1] = v; + ((u32*)p)[2] = v; + ((u32*)p)[3] = v; + ((u32*)p)[4] = v; + ((u32*)p)[5] = v; + ((u32*)p)[6] = v; + ((u32*)p)[7] = v; + + p += 32; + } + } else { + while (blocks--) { + __dcbz(p, 0); + p += 32; + } + } + + size &= 31; + } + + words = size >> 2; + while (words--) { + *(u32*)p = v; + p += 4; + } + + bytes = size & 3; + while (bytes--) { + *p++ = (u8)v; + } + + return ret; +} From 68bdb1e0234009455e954066f6b223a6f8bcd541 Mon Sep 17 00:00:00 2001 From: MrL314 <11429905+MrL314@users.noreply.github.com> Date: Fri, 27 Feb 2026 17:49:36 -0500 Subject: [PATCH 41/52] `CamKarikariEffector` at 98% --- config/RMGK01/splits.txt | 14 ++- include/Game/Camera/CamKarikariEffector.hpp | 4 +- .../JSystem/JMath/JMATrigonometric.hpp | 25 ++++- libs/JSystem/include/JSystem/JMath/JMath.hpp | 6 - src/Game/Camera/CamKarikariEffector.cpp | 104 +++++++++++++++++- src/Game/Scene/SceneObjHolder.cpp | 4 +- 6 files changed, 140 insertions(+), 17 deletions(-) diff --git a/config/RMGK01/splits.txt b/config/RMGK01/splits.txt index 0b1cc1d0c..78fa45807 100644 --- a/config/RMGK01/splits.txt +++ b/config/RMGK01/splits.txt @@ -1511,7 +1511,7 @@ Game/Boss/TripodBossKillerGenerater.cpp: Game/Boss/TripodBossKillerGeneraterCircle.cpp: .text start:0x8008D9E0 end:0x8008DE98 - .rodata start:0x80531540 end:0x80531620 + .rodata start:0x80531540 end:0x805315B8 .data start:0x805738C8 end:0x80573998 .sdata2 start:0x806B9008 end:0x806B9018 @@ -1524,6 +1524,7 @@ Game/Boss/TripodBossKinokoOneUp.cpp: Game/Boss/TripodBossLeg.cpp: .text start:0x8008E2E8 end:0x80090694 .ctors start:0x8052E9D8 end:0x8052E9DC + .rodata start:0x805315B8 end:0x805315C0 .data start:0x80573BD8 end:0x80573D00 .sbss start:0x806B39B8 end:0x806B39E8 .sdata2 start:0x806B9018 end:0x806B9098 @@ -1531,6 +1532,7 @@ Game/Boss/TripodBossLeg.cpp: Game/Boss/TripodBossMovableArea.cpp: .text start:0x80090694 end:0x80090E60 .ctors start:0x8052E9DC end:0x8052E9E0 + .rodata start:0x805315C0 end:0x805315C8 .data start:0x80573D00 end:0x80573D18 .bss start:0x8060A6D0 end:0x8060A6F8 .sdata2 start:0x806B9098 end:0x806B90B8 @@ -1564,12 +1566,14 @@ Game/Boss/TripodBossStepStartArea.cpp: Game/Camera/CamHeliEffector.cpp: .text start:0x80091D24 end:0x800921B8 .ctors start:0x8052E9E4 end:0x8052E9E8 + .rodata start:0x805315C8 end:0x805315D0 .data start:0x80574010 end:0x805740B0 .sbss start:0x806B39F8 end:0x806B3A20 .sdata2 start:0x806B90D0 end:0x806B90F0 Game/Camera/CamKarikariEffector.cpp: .text start:0x800921B8 end:0x8009265C + .rodata start:0x805315D0 end:0x805315D8 .sdata2 start:0x806B90F0 end:0x806B9120 Game/Camera/CamPoseSphereInterpolator.cpp: @@ -1775,6 +1779,7 @@ Game/Camera/Camera.cpp: Game/Camera/CameraAnim.cpp: .text start:0x800941C8 end:0x80094F74 + .rodata start:0x805315D8 end:0x805315E0 .data start:0x805743D8 end:0x80574470 .sdata2 start:0x806B9210 end:0x806B9228 @@ -1790,6 +1795,7 @@ Game/Camera/CameraBlackHole.cpp: Game/Camera/CameraCalc.cpp: .text start:0x800956DC end:0x80095D84 + .rodata start:0x805315E0 end:0x805315F0 .sdata2 start:0x806B9250 end:0x806B9280 Game/Camera/CameraCharmedFix.cpp: @@ -1814,6 +1820,7 @@ Game/Camera/CameraCharmedVecRegTower.cpp: Game/Camera/CameraContext.cpp: .text start:0x800972D8 end:0x800979EC + .rodata start:0x805315F0 end:0x805315F8 .data start:0x80574680 end:0x805746B8 .sdata2 start:0x806B92E8 end:0x806B9310 @@ -1836,12 +1843,14 @@ Game/Camera/CameraDPD.cpp: Game/Camera/CameraDead.cpp: .text start:0x80098C58 end:0x80099220 + .rodata start:0x805315F8 end:0x80531600 .data start:0x805747A8 end:0x80574800 .sdata2 start:0x806B9390 end:0x806B93A0 Game/Camera/CameraDirector.cpp: .text start:0x80099220 end:0x8009B5E4 .ctors start:0x8052E9EC end:0x8052E9F0 + .rodata start:0x80531600 end:0x80531608 .data start:0x80574800 end:0x80574A40 .sdata start:0x806B17F8 end:0x806B1808 .sbss start:0x806B3A28 end:0x806B3A30 @@ -1865,12 +1874,14 @@ Game/Camera/CameraFixedThere.cpp: Game/Camera/CameraFollow.cpp: .text start:0x8009C5A4 end:0x8009DA78 .ctors start:0x8052E9F0 end:0x8052E9F4 + .rodata start:0x80531608 end:0x80531610 .data start:0x80574B48 end:0x80574BB0 .sbss start:0x806B3A30 end:0x806B3A38 .sdata2 start:0x806B9410 end:0x806B9480 Game/Camera/CameraFooFighter.cpp: .text start:0x8009DA78 end:0x8009E2FC + .rodata start:0x80531610 end:0x80531618 .data start:0x80574BB0 end:0x80574C08 .sdata2 start:0x806B9480 end:0x806B94B0 @@ -1892,6 +1903,7 @@ Game/Camera/CameraGround.cpp: Game/Camera/CameraHeightArrange.cpp: .text start:0x8009F568 end:0x800A0844 + .rodata start:0x80531618 end:0x80531620 .data start:0x80574D10 end:0x80574D48 .sdata2 start:0x806B9510 end:0x806B9550 diff --git a/include/Game/Camera/CamKarikariEffector.hpp b/include/Game/Camera/CamKarikariEffector.hpp index af34c00a2..4d4583975 100644 --- a/include/Game/Camera/CamKarikariEffector.hpp +++ b/include/Game/Camera/CamKarikariEffector.hpp @@ -10,5 +10,5 @@ class CamKarikariEffector { void update(CameraMan*); - u32 _0; -}; \ No newline at end of file + /* 0x00 */ s32 mCounter; +}; diff --git a/libs/JSystem/include/JSystem/JMath/JMATrigonometric.hpp b/libs/JSystem/include/JSystem/JMath/JMATrigonometric.hpp index 5abdc17d9..17856895d 100644 --- a/libs/JSystem/include/JSystem/JMath/JMATrigonometric.hpp +++ b/libs/JSystem/include/JSystem/JMath/JMATrigonometric.hpp @@ -51,10 +51,12 @@ namespace JMath { inline f32 sinLapRad(f32 v) { if (v < 0.0f) { - f32 tmp = v * (-LEN / TWO_PI); + f32 tmp = v; + tmp *= -(LEN / TWO_PI); return -table[(u16)tmp & LEN - 1].a1; } else { - f32 tmp = v * (LEN / TWO_PI); + f32 tmp = v; + tmp *= (LEN / TWO_PI); return table[(u16)tmp & LEN - 1].a1; } } @@ -161,3 +163,22 @@ inline f32 JMASCos(s16 v) { inline f32 JMASSin(s16 v) { return JMASinShort(v); } + +f32 JMAAcosRadian(f32 v); +f32 JMAAsinRadian(f32 v); + +inline f32 JMACosDegree(f32 angle) { + return JMath::sSinCosTable.cosLap(angle); +} + +inline f32 JMACosRadian(f32 angle) { + return JMath::sSinCosTable.cosLapRad(angle); +} + +inline f32 JMASinDegree(f32 angle) { + return JMath::sSinCosTable.sinLap(angle); +} + +inline f32 JMASinRadian(f32 angle) { + return JMath::sSinCosTable.sinLapRad(angle); +} diff --git a/libs/JSystem/include/JSystem/JMath/JMath.hpp b/libs/JSystem/include/JSystem/JMath/JMath.hpp index c48932c43..bd9aa64c7 100644 --- a/libs/JSystem/include/JSystem/JMath/JMath.hpp +++ b/libs/JSystem/include/JSystem/JMath/JMath.hpp @@ -3,12 +3,6 @@ #include void JMAMTXApplyScale(const Mtx, Mtx, f32, f32, f32); -f32 JMAAcosRadian(f32); -f32 JMAAsinRadian(f32); -f32 JMACosDegree(f32); -f32 JMACosRadian(f32); -f32 JMASinDegree(f32); -f32 JMASinRadian(f32); void JMAVECLerp(const Vec*, const Vec*, Vec*, f32); void JMAVECScaleAdd(const Vec*, const Vec*, Vec*, f32); void JMAQuatLerp(const Quaternion*, const Quaternion*, f32, Quaternion*); diff --git a/src/Game/Camera/CamKarikariEffector.cpp b/src/Game/Camera/CamKarikariEffector.cpp index c0a9ef134..5816bbdb3 100644 --- a/src/Game/Camera/CamKarikariEffector.cpp +++ b/src/Game/Camera/CamKarikariEffector.cpp @@ -1,5 +1,103 @@ #include "Game/Camera/CamKarikariEffector.hpp" +#include "Game/Camera/CameraLocalUtil.hpp" +#include "Game/Camera/CameraMan.hpp" +#include "Game/Enemy/KarikariDirector.hpp" +#include "Game/Util/MathUtil.hpp" +#include "Game/Util/PlayerUtil.hpp" +#include "JSystem/JMath/JMATrigonometric.hpp" -CamKarikariEffector::CamKarikariEffector() { - _0 = 0; -} \ No newline at end of file +namespace { + static const f32 sKarikariViewRate = 0.8f; + static const s32 sKarikariCounterMax = 30; + static const f32 sPlayerRadius = 75.0f; +} // namespace + +// TODO: replace call with MR::clamp01 +inline f32 clamp01(f32 val) { + if (val < 0.0f) { + return 0.0f; + } + if (val > 1.0f) { + return 1.0f; + } + return val; +} + +// TODO: replace with proper function +inline f32 toRadian(f32 degree) { + f32 pi = PI; + return degree * pi / 180.0f; +} + +CamKarikariEffector::CamKarikariEffector() : mCounter(0) { +} + +void CamKarikariEffector::update(CameraMan* pCameraMan) { + // FIXME: a few minor issues with float and register scheduling + // https://decomp.me/scratch/7CCpm + + if (MR::isPlayerDead()) { + CameraLocalUtil::setFovy(pCameraMan, CameraLocalUtil::getFovy(pCameraMan)); + return; + } + + if (MR::getKarikariClingNum() == 0) { + if (mCounter > 0) { + mCounter--; + } + } else { + if (mCounter < sKarikariCounterMax) { + mCounter++; + } + } + + // FIXME: t stored in f0 but should be in f31 + f32 t = MR::getClingNumMax() == 0 ? sKarikariViewRate : static_cast< f32 >(MR::getKarikariClingNum()) / MR::getClingNumMax(); + + if (mCounter <= 0) { + return; + } + + f32 fovRate = 1.0f - (1.0f - t) * (1.0f - t); + + TVec3f diffWatchPos = CameraLocalUtil::getWatchPos(pCameraMan) - CameraLocalUtil::getPos(pCameraMan); + TVec3f toWatchPos(diffWatchPos); + MR::normalize(&toWatchPos); + + // FIXME: register scheduling issue, result of multInLine should be preloaded before the actual mult? + TVec3f playerUp; + MR::getPlayerUpVec(&playerUp); + TVec3f playerFocusPos = *MR::getPlayerPos() + playerUp.multInLine(sPlayerRadius); + + TVec3f diffPlayerPos = playerFocusPos - CameraLocalUtil::getPos(pCameraMan); + TVec3f toPlayerPos(diffPlayerPos); + MR::normalize(&toPlayerPos); + + // Blend WatchPos to player focus pos by rotation (ease in) + + // FIXME: PI mult order wrong + // TODO: this is likely MR::clamp(val, 0.0f, 1.0f), or MR::clamp01(val) instead of MR::clamp01(ptr) + f32 rotRatio = clamp01((1.0f - JMACosRadian(mCounter * PI / sKarikariCounterMax)) * 0.5f); + TQuat4f rot; + rot.setRotate(toWatchPos, toPlayerPos, rotRatio); + rot.transform(diffWatchPos); + + CameraLocalUtil::setPos(pCameraMan, CameraLocalUtil::getPos(pCameraMan)); + CameraLocalUtil::setWatchPos(pCameraMan, diffWatchPos + CameraLocalUtil::getPos(pCameraMan)); + + TVec3f camUp(CameraLocalUtil::getUpVec(pCameraMan)); + rot.transform(camUp); + CameraLocalUtil::setUpVec(pCameraMan, camUp); + + // Blend FovY + f32 dist = diffPlayerPos.length(); + f32 fovAngle = JMAAsinRadian(75.0f / dist); + + f32 s = JMASinRadian(fovAngle); + f32 c = JMACosRadian(fovAngle); + f32 fovy = JMath::sAtanTable.atan2_((dist * (s / c)) / 0.3f, dist); + + if (fovy < toRadian(CameraLocalUtil::getFovy(pCameraMan))) { + CameraLocalUtil::setFovy(pCameraMan, (fovy * 180.0f * fovRate) / PI + (1.0f - fovRate) * CameraLocalUtil::getFovy(pCameraMan)); + } +} diff --git a/src/Game/Scene/SceneObjHolder.cpp b/src/Game/Scene/SceneObjHolder.cpp index 1af31f244..606e2f975 100644 --- a/src/Game/Scene/SceneObjHolder.cpp +++ b/src/Game/Scene/SceneObjHolder.cpp @@ -273,8 +273,7 @@ NameObj* SceneObjHolder::newEachObj(int id) { case SceneObj_BigFanHolder: return new BigFanHolder(); case SceneObj_KarikariDirector: - // return new KarikariDirector("カリカリディレクター"); - return nullptr; + return new KarikariDirector("カリカリディレクター"); case SceneObj_StarPieceDirector: return new StarPieceDirector("スターピース指揮"); case SceneObj_BegomanAttackPermitter: @@ -304,7 +303,6 @@ NameObj* SceneObjHolder::newEachObj(int id) { return new ShadowSurfaceDrawInit("水面影描画初期化"); case SceneObj_SwingRopeGroup: return new SwingRopeGroup("スイングロープ描画"); - return nullptr; case SceneObj_PlantStalkDrawInit: return new PlantStalkDrawInit("植物の茎描画初期化"); case SceneObj_PlantLeafDrawInit: From d437baabcd655e47334f3a4859c6d92017c82bc3 Mon Sep 17 00:00:00 2001 From: shibbo Date: Sat, 28 Feb 2026 11:50:00 -0500 Subject: [PATCH 42/52] attempt `DinoPackunTail::addAccelKeepBend` --- src/Game/Boss/DinoPackunTail.cpp | 38 +++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/Game/Boss/DinoPackunTail.cpp b/src/Game/Boss/DinoPackunTail.cpp index d6f6b7705..8642a9ed6 100644 --- a/src/Game/Boss/DinoPackunTail.cpp +++ b/src/Game/Boss/DinoPackunTail.cpp @@ -106,8 +106,44 @@ void DinoPackunTail::updateJoint() { } } } +void DinoPackunTail::addAccelKeepBend() { + TVec3f v20; + v20.set< f32 >(mNodes[0]->mPosition); + TVec3f v19; + v19.set< f32 >(*mNodes[0]->getNodeDirection()); + MR::normalize(&v19); -// DinoPackunTail::addAccelKeepBend + for (u32 i = 1; i < mNumNodes; i++) { + TVec3f v18; + v18.set< f32 >(mNodes[i]->mPosition); + TVec3f v17; + v17.set< f32 >(*mNodes[i]->getNodeDirection()); + + if (!MR::isNearZero(v17)) { + MR::normalize(&v17); + f32 v11; + TVec3f v16; + if (MR::makeAxisAndCosignVecToVec(&v16, &v11, v19, v17) && v11 < 1.1f) { + f32 bendPower = mNodes[i]->getKeepBendPower(); + f32 v8 = (_C * ((1.0f - MR::normalize(v11, -1.0f, 1.1f)) * bendPower)); + TVec3f v15; + PSVECCrossProduct(&v17, &v16, &v15); + MR::normalize(&v15); + mNodes[i]->addNodeVelocityHost(v15 * v8); + + if (i >= 2) { + TVec3f v14; + PSVECCrossProduct(&v19, &v16, &v14); + MR::normalize(&v14); + mNodes[i - 2]->addNodeVelocityHost(v14 * v8); + } + } + + v20.set< f32 >(v18); + v19.set< f32 >(v17); + } + } +} // https://decomp.me/scratch/aWhPK void DinoPackunTail::addAccelKeepDistance() { From 2baf9f4a9e61d8ca74ac1dd7411a2f900c0779c0 Mon Sep 17 00:00:00 2001 From: shibbo Date: Sat, 28 Feb 2026 22:28:22 -0500 Subject: [PATCH 43/52] some `KoopaFireStairs` progress --- include/Game/Boss/KoopaFireStairs.hpp | 28 ++++++++ src/Game/Boss/KoopaFireStairs.cpp | 93 +++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 include/Game/Boss/KoopaFireStairs.hpp create mode 100644 src/Game/Boss/KoopaFireStairs.cpp diff --git a/include/Game/Boss/KoopaFireStairs.hpp b/include/Game/Boss/KoopaFireStairs.hpp new file mode 100644 index 000000000..8a1fe2fca --- /dev/null +++ b/include/Game/Boss/KoopaFireStairs.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include "Game/LiveActor/LiveActor.hpp" +#include "Game/LiveActor/ModelObj.hpp" + +class KoopaBattleMapStair; + +class KoopaFireStairs : public LiveActor { +public: + KoopaFireStairs(const char*, bool); + + virtual ~KoopaFireStairs(); + virtual void init(const JMapInfoIter&); + virtual void appear(); + virtual void makeActorDead(); + virtual void calcAndSetBaseMtx(); + + void setInfo(const KoopaBattleMapStair*, const TVec3f*); + void exeFly(); + void exeBreak(); + + u8 _8C; + const KoopaBattleMapStair* mStair; // 0x90 + TVec3f _94; + TVec3f _A0; + TVec3f _AC; + ModelObj* mBreakModel; // 0xB8 +}; diff --git a/src/Game/Boss/KoopaFireStairs.cpp b/src/Game/Boss/KoopaFireStairs.cpp new file mode 100644 index 000000000..729603b6b --- /dev/null +++ b/src/Game/Boss/KoopaFireStairs.cpp @@ -0,0 +1,93 @@ +#include "Game/Boss/KoopaFireStairs.hpp" +#include "Game/Map/KoopaBattleMapStair.hpp" + +namespace NrvKoopaFireStairs { + NEW_NERVE(KoopaFireStairsNrvFly, KoopaFireStairs, Fly); + NEW_NERVE(KoopaFireStairsNrvBreak, KoopaFireStairs, Break); +}; // namespace NrvKoopaFireStairs + +KoopaFireStairs::~KoopaFireStairs() { + return; +} + +// KoopaFireStairs::KoopaFireStairs +// KoopaFireStairs::init + +void KoopaFireStairs::appear() { + LiveActor::appear(); + MR::showModel(this); + MR::emitEffect(this, "MeteorStrike"); + + if (_8C) { + MR::startSound(this, "SE_BM_KOOPAJR_SHIP_METEORSHOT_F", -1, -1); + } else { + MR::startSound(this, "SE_OJ_KOOPA_FIRE_SHOT", -1, -1); + } + + setNerve(&NrvKoopaFireStairs::KoopaFireStairsNrvFly::sInstance); +} + +void KoopaFireStairs::makeActorDead() { + LiveActor::makeActorDead(); + mBreakModel->makeActorDead(); +} + +void KoopaFireStairs::setInfo(const KoopaBattleMapStair* pStair, const TVec3f* a2) { + mStair = pStair; + _A0.set< f32 >(mPosition); + MR::calcGravity(this); + + if (a2 != nullptr) { + TVec3f v13 = mStair->mPosition - _A0; + TVec3f v12 = mStair->_AC - _A0; + TVec3f v11; + PSVECCrossProduct(&v13, &v12, &v11); + + f32 deg; + + if (v11.dot(mGravity) > 0.0f) { + deg = MR::getRandom(0.0f, 45.0f); + MR::rotateVecDegree(&_AC, *a2, deg); + } else { + deg = MR::getRandom(-45.0f, 0.0f); + MR::rotateVecDegree(&_AC, *a2, deg); + } + } + + if (_8C) { + mVelocity.zero(); + _94.set< f32 >(mStair->_AC - _A0); + MR::normalize(&_94); + } else { + s32 breakTime = mStair->calcRemainTimeToBreak(); + TVec3f v10 = mStair->_AC - mPosition; + f32 v8 = v10.length(); + mVelocity.set< f32 >(v10); + MR::normalize(&mVelocity); + _94.set< f32 >(mVelocity); + mVelocity.scale(v8 / (breakTime - 1)); + } +} + +// KoopaFireStairs::exeFly + +void KoopaFireStairs::exeBreak() { + if (MR::isFirstStep(this)) { + mBreakModel->appear(); + MR::startAction(mBreakModel, "Break"); + } + + if (MR::isActionEnd(mBreakModel)) { + kill(); + } +} + +void KoopaFireStairs::calcAndSetBaseMtx() { + TPos3f v5; + v5.identity(); + TVec3f v4; + JMathInlineVEC::PSVECNegate(&mGravity, &v4); + MR::makeMtxFrontUpPos(&v5, _94, v4, mPosition); + MR::rotateMtxLocalXDegree(v5, mRotation.x); + MR::setBaseTRMtx(this, v5); +} From 0f5bfaca676641ff8a86b907c91ef9ea53e45f82 Mon Sep 17 00:00:00 2001 From: shibbo Date: Sun, 1 Mar 2026 14:14:49 -0500 Subject: [PATCH 44/52] `KoopaFireStairs` at 92% --- include/Game/Boss/KoopaFireStairs.hpp | 2 +- src/Game/Boss/KoopaFireStairs.cpp | 81 ++++++++++++++++++++++++++- 2 files changed, 79 insertions(+), 4 deletions(-) diff --git a/include/Game/Boss/KoopaFireStairs.hpp b/include/Game/Boss/KoopaFireStairs.hpp index 8a1fe2fca..c8d220c19 100644 --- a/include/Game/Boss/KoopaFireStairs.hpp +++ b/include/Game/Boss/KoopaFireStairs.hpp @@ -19,7 +19,7 @@ class KoopaFireStairs : public LiveActor { void exeFly(); void exeBreak(); - u8 _8C; + bool _8C; const KoopaBattleMapStair* mStair; // 0x90 TVec3f _94; TVec3f _A0; diff --git a/src/Game/Boss/KoopaFireStairs.cpp b/src/Game/Boss/KoopaFireStairs.cpp index 729603b6b..e1c2fb75c 100644 --- a/src/Game/Boss/KoopaFireStairs.cpp +++ b/src/Game/Boss/KoopaFireStairs.cpp @@ -1,5 +1,6 @@ #include "Game/Boss/KoopaFireStairs.hpp" #include "Game/Map/KoopaBattleMapStair.hpp" +#include "JSystem/JMath/JMATrigonometric.hpp" namespace NrvKoopaFireStairs { NEW_NERVE(KoopaFireStairsNrvFly, KoopaFireStairs, Fly); @@ -10,8 +11,35 @@ KoopaFireStairs::~KoopaFireStairs() { return; } -// KoopaFireStairs::KoopaFireStairs -// KoopaFireStairs::init +KoopaFireStairs::KoopaFireStairs(const char* pName, bool a2) : LiveActor(pName) { + _8C = a2; + mStair = nullptr; + _94.set(0.0f, 0.0f, 1.0f); + _A0.set(0.0f); + _AC.set(0.0f, 1.0f, 0.0f); + mBreakModel = nullptr; +} + +void KoopaFireStairs::init(const JMapInfoIter& rIteR) { + initModelManagerWithAnm("MeteorStrike", nullptr, false); + MR::startBrk(this, "MeteorStrike"); + MR::connectToSceneEnemy(this); + initHitSensor(1); + TVec3f offs; + offs.set(0.0f); + MR::addHitSensorEnemyAttack(this, "Fire", 8, 100.0f, offs); + initEffectKeeper(1, nullptr, false); + MR::addEffectHitNormal(this, "Hit"); + MR::setEffectBaseScale(this, "Hit", 2.0f); + initSound(4, false); + MR::initShadowVolumeSphere(this, 60.0f); + initNerve(&NrvKoopaFireStairs::KoopaFireStairsNrvFly::sInstance); + MR::invalidateClipping(this); + mBreakModel = MR::createModelObjEnemy("クッパメテオ(壊れ)", "MeteorStrikeBreak", getBaseMtx()); + mBreakModel->kill(); + MR::invalidateClipping(mBreakModel); + makeActorDead(); +} void KoopaFireStairs::appear() { LiveActor::appear(); @@ -69,7 +97,54 @@ void KoopaFireStairs::setInfo(const KoopaBattleMapStair* pStair, const TVec3f* a } } -// KoopaFireStairs::exeFly +void KoopaFireStairs::exeFly() { + if (mStair->isBreak()) { + TVec3f v15(mVelocity); + MR::normalizeOrZero(&v15); + v15.scale(100.0f); + v15.add(mPosition); + MR::emitEffectHit(this, v15, "Hit"); + MR::emitEffect(this, "MeteorStrikeBreak"); + mVelocity.zero(); + MR::startSound(this, "SE_OJ_KOOPA_FIRE_EXPLODE", -1, -1); + MR::tryRumblePadStrong(this, 0); + MR::shakeCameraWeak(); + MR::hideModel(this); + setNerve(&NrvKoopaFireStairs::KoopaFireStairsNrvBreak::sInstance); + } else { + if (_8C) { + TVec3f v14(mPosition); + f32 rate = mStair->calcTimeRate(); + TVec3f v10(mStair->_AC); + v10.scale(rate); + TVec3f v11(_A0); + v11.scale(1.0f - rate); + TVec3f v12(v11); + v12.add(v10); + mPosition.setPS2(v12); + + f32 v5 = (100.0f * mStair->calcTimeRate()); + f32 v6 = JMath::sSinCosTable.sinLap(v5); + + TVec3f v8(_AC); + v8.scale(v6); + TVec3f v9(v8); + v9.scale(1500.0f); + mPosition.add(v9); + + TVec3f v13 = mPosition - v14; + + if (!MR::isNearZero(v13)) { + MR::normalize(&v13); + _94.set< f32 >(v13); + } + + MR::startLevelSound(this, "SE_BM_LV_KOOPAJR_SHIP_METEOR", -1, -1, -1); + } + + mRotation.x = MR::repeatDegree(mRotation.x + 15.0f); + } +} void KoopaFireStairs::exeBreak() { if (MR::isFirstStep(this)) { From 318e5ec3839d849a04b11a4c216c70dad9e9e4c9 Mon Sep 17 00:00:00 2001 From: shibbo Date: Sun, 1 Mar 2026 15:02:21 -0500 Subject: [PATCH 45/52] `KoopaPlanetShadow` --- include/Game/Boss/KoopaPlanetShadow.hpp | 17 +++++++++++++++++ src/Game/Boss/KoopaPlanetShadow.cpp | 21 +++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 include/Game/Boss/KoopaPlanetShadow.hpp create mode 100644 src/Game/Boss/KoopaPlanetShadow.cpp diff --git a/include/Game/Boss/KoopaPlanetShadow.hpp b/include/Game/Boss/KoopaPlanetShadow.hpp new file mode 100644 index 000000000..b8e8e3bad --- /dev/null +++ b/include/Game/Boss/KoopaPlanetShadow.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include "Game/LiveActor/LiveActor.hpp" + +class Koopa; + +class KoopaPlanetShadow : public LiveActor { +public: + KoopaPlanetShadow(const Koopa*); + + virtual ~KoopaPlanetShadow(); + virtual void init(const JMapInfoIter&); + virtual void calcAndSetBaseMtx(); + + const Koopa* mKoopa; // 0x8C + MtxPtr mHipMtx; // 0x90 +}; diff --git a/src/Game/Boss/KoopaPlanetShadow.cpp b/src/Game/Boss/KoopaPlanetShadow.cpp new file mode 100644 index 000000000..590aa143a --- /dev/null +++ b/src/Game/Boss/KoopaPlanetShadow.cpp @@ -0,0 +1,21 @@ +#include "Game/Boss/KoopaPlanetShadow.hpp" +#include "Game/Boss/Koopa.hpp" + +KoopaPlanetShadow::~KoopaPlanetShadow() { + return; +} + +KoopaPlanetShadow::KoopaPlanetShadow(const Koopa* pKoopa) : LiveActor("惑星用の影") { + mKoopa = pKoopa; + mHipMtx = nullptr; +} + +void KoopaPlanetShadow::init(const JMapInfoIter& rIter) { + initModelManagerWithAnm("KoopaPlanetShadow", nullptr, false); + MR::connectToSceneEnemyDecoration(this); + MR::invalidateClipping(this); + mHipMtx = MR::getJointMtx(mKoopa, "Hip1"); + makeActorDead(); +} + +// void KoopaPlanetShadow::calcAndSetBaseMtx() From c0ca9393f03e4b4a3c49ece0c42bb707c222af3d Mon Sep 17 00:00:00 2001 From: shibbo Date: Sun, 1 Mar 2026 15:03:05 -0500 Subject: [PATCH 46/52] `KoopaFireStairs::exeFly` improvement --- src/Game/Boss/KoopaFireStairs.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Game/Boss/KoopaFireStairs.cpp b/src/Game/Boss/KoopaFireStairs.cpp index e1c2fb75c..1da6f4480 100644 --- a/src/Game/Boss/KoopaFireStairs.cpp +++ b/src/Game/Boss/KoopaFireStairs.cpp @@ -142,7 +142,8 @@ void KoopaFireStairs::exeFly() { MR::startLevelSound(this, "SE_BM_LV_KOOPAJR_SHIP_METEOR", -1, -1, -1); } - mRotation.x = MR::repeatDegree(mRotation.x + 15.0f); + mRotation.x += 15.0f; + mRotation.x = MR::repeatDegree(mRotation.x); } } From 4a18c9095062b188720fde8e9e5ccdc040751123 Mon Sep 17 00:00:00 2001 From: shibbo Date: Sun, 1 Mar 2026 15:06:56 -0500 Subject: [PATCH 47/52] `KoopaRestarterVs3` --- include/Game/Boss/KoopaFunction.hpp | 4 +++- include/Game/Boss/KoopaRestarterVs3.hpp | 3 +++ src/Game/Boss/KoopaRestarterVs3.cpp | 19 +++++++++++++++++-- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/include/Game/Boss/KoopaFunction.hpp b/include/Game/Boss/KoopaFunction.hpp index a7b36de76..01e42d1cb 100644 --- a/include/Game/Boss/KoopaFunction.hpp +++ b/include/Game/Boss/KoopaFunction.hpp @@ -4,4 +4,6 @@ namespace KoopaFunction { s32 registerBattleMapStair(KoopaBattleMapStair*); -}; + + bool tryRestartKoopa(); +}; // namespace KoopaFunction diff --git a/include/Game/Boss/KoopaRestarterVs3.hpp b/include/Game/Boss/KoopaRestarterVs3.hpp index 2bfd2a7ef..2133c6c78 100644 --- a/include/Game/Boss/KoopaRestarterVs3.hpp +++ b/include/Game/Boss/KoopaRestarterVs3.hpp @@ -5,5 +5,8 @@ class KoopaRestarterVs3 : public LiveActor { public: KoopaRestarterVs3(const char*); + virtual ~KoopaRestarterVs3(); + virtual void init(const JMapInfoIter&); + virtual void appear(); }; diff --git a/src/Game/Boss/KoopaRestarterVs3.cpp b/src/Game/Boss/KoopaRestarterVs3.cpp index 0f009fd9d..867bac015 100644 --- a/src/Game/Boss/KoopaRestarterVs3.cpp +++ b/src/Game/Boss/KoopaRestarterVs3.cpp @@ -1,4 +1,19 @@ #include "Game/Boss/KoopaRestarterVs3.hpp" +#include "Game/Boss/KoopaFunction.hpp" -KoopaRestarterVs3::KoopaRestarterVs3(const char* pName) : LiveActor(pName) {} -KoopaRestarterVs3::~KoopaRestarterVs3() {} +KoopaRestarterVs3::KoopaRestarterVs3(const char* pName) : LiveActor(pName) { +} + +void KoopaRestarterVs3::init(const JMapInfoIter& rIter) { + MR::needStageSwitchReadAppear(this, rIter); + MR::syncStageSwitchAppear(this); + makeActorDead(); +} + +void KoopaRestarterVs3::appear() { + LiveActor::appear(); + KoopaFunction::tryRestartKoopa(); +} + +KoopaRestarterVs3::~KoopaRestarterVs3() { +} From fbd88b9b72ddd0a610c4ec8c993693b4631ac2ad Mon Sep 17 00:00:00 2001 From: shibbo Date: Sun, 1 Mar 2026 15:37:10 -0500 Subject: [PATCH 48/52] some work on `KoopaDemoPowerUp` --- include/Game/Boss/KoopaDemoPowerUp.hpp | 15 ++++++ include/Game/Boss/KoopaFunction.hpp | 21 +++++++- src/Game/Boss/KoopaDemoPowerUp.cpp | 66 ++++++++++++++++++++++++++ 3 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 include/Game/Boss/KoopaDemoPowerUp.hpp create mode 100644 src/Game/Boss/KoopaDemoPowerUp.cpp diff --git a/include/Game/Boss/KoopaDemoPowerUp.hpp b/include/Game/Boss/KoopaDemoPowerUp.hpp new file mode 100644 index 000000000..4b0864f64 --- /dev/null +++ b/include/Game/Boss/KoopaDemoPowerUp.hpp @@ -0,0 +1,15 @@ +#include "Game/Boss/Koopa.hpp" +#include "Game/LiveActor/ActorStateBase.hpp" + +class KoopaDemoPowerUp : public ActorStateBase< Koopa > { +public: + KoopaDemoPowerUp(Koopa*); + + virtual ~KoopaDemoPowerUp(); + virtual void init(); + virtual void appear(); + virtual void kill(); + + void exeWaitDemo(); + void exeDemo(); +}; diff --git a/include/Game/Boss/KoopaFunction.hpp b/include/Game/Boss/KoopaFunction.hpp index 01e42d1cb..1808cd65d 100644 --- a/include/Game/Boss/KoopaFunction.hpp +++ b/include/Game/Boss/KoopaFunction.hpp @@ -1,9 +1,28 @@ #pragma once -#include "Game/Map/KoopaBattleMapStair.hpp" +#include + +class LiveActor; +class Koopa; +class KoopaBattleMapStair; namespace KoopaFunction { s32 registerBattleMapStair(KoopaBattleMapStair*); + void initKoopaCamera(Koopa*, const char*); + void startKoopaTargetCamera(Koopa*, const char*); + void endKoopaCamera(Koopa*, const char*, bool, s32); + LiveActor* getKoopaPowerUpSwitch(Koopa*); + + void setKoopaPos(Koopa*, const char*); + + void startRecoverKoopaArmor(Koopa*); + void startRecoverKoopaTailThorn(Koopa*); + void endFaceCtrl(Koopa*, s32); + bool tryRestartKoopa(); + + bool isKoopaVs1(const Koopa*); + bool isKoopaVs2(const Koopa*); + bool isKoopaLv3(const Koopa*); }; // namespace KoopaFunction diff --git a/src/Game/Boss/KoopaDemoPowerUp.cpp b/src/Game/Boss/KoopaDemoPowerUp.cpp new file mode 100644 index 000000000..a4f718f23 --- /dev/null +++ b/src/Game/Boss/KoopaDemoPowerUp.cpp @@ -0,0 +1,66 @@ +#include "Game/Boss/KoopaDemoPowerUp.hpp" +#include "Game/Boss/KoopaFunction.hpp" +#include "Game/Util/ScreenUtil.hpp" + +namespace NrvKoopaDemoPowerUp { + NEW_NERVE(KoopaDemoPowerUpNrvWaitDemo, KoopaDemoPowerUp, WaitDemo); + NEW_NERVE(KoopaDemoPowerUpNrvDemo, KoopaDemoPowerUp, Demo); +}; // namespace NrvKoopaDemoPowerUp + +KoopaDemoPowerUp::~KoopaDemoPowerUp() { + return; +} + +KoopaDemoPowerUp::KoopaDemoPowerUp(Koopa* pKoopa) : ActorStateBase< Koopa >("Demo[パワーアップ]", pKoopa) { +} + +void KoopaDemoPowerUp::init() { + KoopaFunction::initKoopaCamera(getHost(), "パワーアップデモ"); + KoopaFunction::initKoopaCamera(getHost(), "最終パワーアップデモ"); + MR::createCenterScreenBlur(); + initNerve(&NrvKoopaDemoPowerUp::KoopaDemoPowerUpNrvWaitDemo::sInstance); +} + +void KoopaDemoPowerUp::appear() { + mIsDead = false; + setNerve(&NrvKoopaDemoPowerUp::KoopaDemoPowerUpNrvWaitDemo::sInstance); +} + +void KoopaDemoPowerUp::kill() { + mIsDead = true; + KoopaFunction::endKoopaCamera(getHost(), "パワーアップデモ", false, -1); + KoopaFunction::endKoopaCamera(getHost(), "最終パワーアップデモ", false, -1); +} + +void KoopaDemoPowerUp::exeWaitDemo() { + if (MR::tryStartDemoMarioPuppetable(getHost(), "パワーアップデモ")) { + if (KoopaFunction::isKoopaVs1(getHost()) || KoopaFunction::isKoopaVs2(getHost())) { + KoopaFunction::setKoopaPos(getHost(), "パワーアップデモ(クッパ)"); + MR::setPlayerPosAndWait("パワーアップデモ(マリオ"); + + if (KoopaFunction::isKoopaLv3(getHost())) { + MR::startAction(getHost(), "DemoKoopaPowerUpFinal"); + KoopaFunction::startKoopaTargetCamera(getHost(), "最終パワーアップデモ"); + MR::onSwitchB(KoopaFunction::getKoopaPowerUpSwitch(getHost())); + } else { + MR::startAction(getHost(), "DemoKoopaPowerUp"); + KoopaFunction::startKoopaTargetCamera(getHost(), "パワーアップデモ"); + MR::onSwitchA(KoopaFunction::getKoopaPowerUpSwitch(getHost())); + } + } else { + KoopaFunction::setKoopaPos(getHost(), "パワーアップデモLv3(クッパ)"); + MR::setPlayerPosAndWait("パワーアップデモLv3(マリオ)"); + MR::startAction(getHost(), "DemoKoopaPowerUpFinal"); + KoopaFunction::startKoopaTargetCamera(getHost(), "最終パワーアップデモ"); + MR::onSwitchA(KoopaFunction::getKoopaPowerUpSwitch(getHost())); + } + + MR::startBckPlayer("BattleWait", static_cast< const char* >(nullptr)); + KoopaFunction::startRecoverKoopaArmor(getHost()); + KoopaFunction::startRecoverKoopaTailThorn(getHost()); + KoopaFunction::endFaceCtrl(getHost(), -1); + setNerve(&NrvKoopaDemoPowerUp::KoopaDemoPowerUpNrvDemo::sInstance); + } +} + +// KoopaDemoPowerUp::exeDemo() From 8f55f5ea820a1ea302eebcec85ff409c8e2ef35f Mon Sep 17 00:00:00 2001 From: shibbo Date: Sun, 1 Mar 2026 15:58:27 -0500 Subject: [PATCH 49/52] some `RailGraphUtil` --- include/Game/Map/RailGraphIter.hpp | 6 ++- include/Game/Util/RailGraphUtil.hpp | 2 + src/Game/Util/RailGraphUtil.cpp | 71 +++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 src/Game/Util/RailGraphUtil.cpp diff --git a/include/Game/Map/RailGraphIter.hpp b/include/Game/Map/RailGraphIter.hpp index 6e310f12d..02f323f21 100644 --- a/include/Game/Map/RailGraphIter.hpp +++ b/include/Game/Map/RailGraphIter.hpp @@ -8,6 +8,10 @@ class RailGraphIter { public: RailGraphIter(const RailGraph*); + RailGraphIter(const RailGraphIter& rIter) NO_INLINE { + *this = rIter; + } + void moveNodeNext(); void setNode(s32); void watchStartEdge(); @@ -28,4 +32,4 @@ class RailGraphIter { s32 mSelectedEdge; // 0x8 s32 mNextEdge; // 0xC s32 _10; -}; \ No newline at end of file +}; diff --git a/include/Game/Util/RailGraphUtil.hpp b/include/Game/Util/RailGraphUtil.hpp index ccf7ebc07..5997a378e 100644 --- a/include/Game/Util/RailGraphUtil.hpp +++ b/include/Game/Util/RailGraphUtil.hpp @@ -21,4 +21,6 @@ namespace MR { bool isWatchedPrevEdge(const RailGraphIter* pRailGraphIter); s32 getWatchEdgeArg7(const RailGraphIter* pRailGraphIter); void calcWatchEdgeDirection(const RailGraphIter* pRailGraphIter, TVec3f* pVec); + + s32 getNearNodeIndex(const RailGraph*, const TVec3f&, f32, RailGraphNodeSelecter*); } // namespace MR diff --git a/src/Game/Util/RailGraphUtil.cpp b/src/Game/Util/RailGraphUtil.cpp new file mode 100644 index 000000000..3c5d1fa43 --- /dev/null +++ b/src/Game/Util/RailGraphUtil.cpp @@ -0,0 +1,71 @@ +#include "Game/Util/RailGraphUtil.hpp" +#include "Game/Map/RailGraph.hpp" +#include "Game/Util/MathUtil.hpp" + +namespace MR { + RailGraphIter* createRailGraphIter(const RailGraph* pGraph) { + return new RailGraphIter(pGraph->getIterator()); + } + + void moveNextNode(RailGraphIter* pIter) { + pIter->moveNodeNext(); + } + + void moveNodeNearPosition(RailGraphIter* pRailGraphIter, const TVec3f& rVec, f32 f, RailGraphNodeSelecter* pSelector) { + pRailGraphIter->setNode(getNearNodeIndex(pRailGraphIter->mGraph, rVec, f, pSelector)); + } + + void selectReverseEdge(RailGraphIter* pRailGraphIter) { + s32 next = pRailGraphIter->mSelectedEdge; + pRailGraphIter->moveNodeNext(); + pRailGraphIter->selectEdge(next); + } + + bool isSelectedEdge(const RailGraphIter* pRailGraphIter) { + return pRailGraphIter->isSelectedEdge(); + } + + bool isWatchedPrevEdge(const RailGraphIter* pRailGraphIter) { + return pRailGraphIter->isWatchedPrevEdge(); + } + + TVec3f* getCurrentNodePosition(const RailGraphIter* pGraph) { + return &pGraph->getCurrentNode()->_0; + } + + TVec3f* getNextNodePosition(const RailGraphIter* pIter) { + return &pIter->getNextNode()->_0; + } + + void calcWatchEdgeVector(const RailGraphIter* pIter, TVec3f* pEdge) { + pEdge->set< f32 >(pIter->getWatchNode()->_0 - pIter->getCurrentNode()->_0); + } + + void calcWatchEdgeDirection(const RailGraphIter* pRailGraphIter, TVec3f* pVec) { + calcWatchEdgeVector(pRailGraphIter, pVec); + MR::normalize(pVec); + } + + // MR::getNearNodeIndex + + s32 getSelectEdgeArg0(const RailGraphIter* pIter) { + return pIter->getCurrentEdge()->mPointArg0; + } + + s32 getSelectEdgeArg1(const RailGraphIter* pIter) { + return pIter->getCurrentEdge()->mPointArg1; + } + + s32 getSelectEdgeArg2(const RailGraphIter* pIter) { + return pIter->getCurrentEdge()->mPointArg2; + } + + s32 getSelectEdgeArg3(const RailGraphIter* pIter) { + return pIter->getCurrentEdge()->mPointArg3; + } + + s32 getWatchEdgeArg7(const RailGraphIter* pIter) { + return pIter->getWatchEdge()->mPointArg7; + } + +}; // namespace MR From 0bd1c7326d048218db0d1569f9c205ef0c584c24 Mon Sep 17 00:00:00 2001 From: shibbo Date: Sun, 1 Mar 2026 16:05:39 -0500 Subject: [PATCH 50/52] start on `SoundUtil` --- src/Game/Util/SoundUtil.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/Game/Util/SoundUtil.cpp diff --git a/src/Game/Util/SoundUtil.cpp b/src/Game/Util/SoundUtil.cpp new file mode 100644 index 000000000..2dac5c1a6 --- /dev/null +++ b/src/Game/Util/SoundUtil.cpp @@ -0,0 +1,14 @@ +#include "Game/Util/SoundUtil.hpp" +#include "Game/AudioLib/AudSoundObject.hpp" +#include "Game/AudioLib/AudWrap.hpp" +#include "Game/GameAudio/AudTalkSoundData.hpp" + +namespace MR { + void startSystemSE(JAISoundID id, s32 a2, s32 a3) { + AudWrap::getSystemSeObject()->startSoundParam(id, a2, a3); + } + + void startSystemLevelSE(const char* pSound, s32 a2, s32 a3) { + AudWrap::getSystemSeObject()->startLevelSoundParam(pSound, a2, a3); + } +}; // namespace MR From 346e988d5ab0247223ed37a3b269fdc9141a8644 Mon Sep 17 00:00:00 2001 From: Gonzalo-kebab Date: Tue, 3 Mar 2026 21:57:49 +0100 Subject: [PATCH 51/52] nearly match CocoNutBall (#1895) * update CocoNutBall splits * match 97% of CocoNutBall.cpp * fix regressions * clean up includes and use math constant * removed too many includes * improve formatting --- config/RMGK01/splits.txt | 1 + config/RMGK01/symbols.txt | 2 +- include/Game/Enemy/CocoNutBall.hpp | 52 ++ .../include/JSystem/JGeometry/TVec.hpp | 15 +- src/Game/Enemy/CocoNutBall.cpp | 530 ++++++++++++++++++ 5 files changed, 598 insertions(+), 2 deletions(-) create mode 100644 include/Game/Enemy/CocoNutBall.hpp create mode 100644 src/Game/Enemy/CocoNutBall.cpp diff --git a/config/RMGK01/splits.txt b/config/RMGK01/splits.txt index 78fa45807..f37f5b2c5 100644 --- a/config/RMGK01/splits.txt +++ b/config/RMGK01/splits.txt @@ -2572,6 +2572,7 @@ Game/Enemy/CocoNutBall.cpp: .ctors start:0x8052EA68 end:0x8052EA6C .rodata start:0x80531E30 end:0x80531E50 .data start:0x8057B348 end:0x8057B500 + .sdata start:0x806B18F0 end:0x806B18F8 .sbss start:0x806B3DA0 end:0x806B3DB8 .sdata2 start:0x806BA2A8 end:0x806BA338 diff --git a/config/RMGK01/symbols.txt b/config/RMGK01/symbols.txt index ccf2c8266..6f7028a86 100644 --- a/config/RMGK01/symbols.txt +++ b/config/RMGK01/symbols.txt @@ -62267,7 +62267,7 @@ hCountTimer__21@unnamed@BombHei_cpp@ = .sdata:0x806B18E0; // type:object size:0x lbl_806B18E4 = .sdata:0x806B18E4; // type:object size:0x4 data:string lbl_806B18E8 = .sdata:0x806B18E8; // type:object size:0x4 data:string lbl_806B18F0 = .sdata:0x806B18F0; // type:object size:0x4 data:string -lbl_806B18F4 = .sdata:0x806B18F4; // type:object size:0x4 +lbl_806B18F4 = .sdata:0x806B18F4; // type:object size:0x4 data:string lbl_806B18F8 = .sdata:0x806B18F8; // type:object size:0x4 data:string lbl_806B18FC = .sdata:0x806B18FC; // type:object size:0x4 lbl_806B1900 = .sdata:0x806B1900; // type:object size:0x4 data:string diff --git a/include/Game/Enemy/CocoNutBall.hpp b/include/Game/Enemy/CocoNutBall.hpp new file mode 100644 index 000000000..de32fa7bf --- /dev/null +++ b/include/Game/Enemy/CocoNutBall.hpp @@ -0,0 +1,52 @@ +#include "Game/LiveActor/LiveActor.hpp" + +class CocoNutBall : public LiveActor { +public: + CocoNutBall(const char* pName); + + virtual ~CocoNutBall(); + virtual void init(const JMapInfoIter& rIter); + virtual void appear(); + virtual void kill(); + virtual void calcAndSetBaseMtx(); + virtual void attackSensor(HitSensor* pSender, HitSensor* pReceiver); + virtual bool receiveMsgPlayerAttack(u32 msg, HitSensor* pSender, HitSensor* pReceiver); + + void appearAndThrow(const TVec3f&, f32); + void hitBackToPlayer(); + void demoBreak(const TVec3f&); + HitSensor* isBindedAny() const; + bool isValidReceivePunch() const; + bool isNerveTrowToOrFreeze() const; // inline used several places + bool isSensorBody(HitSensor*) const; + void calcHitBackVelocitAndGravity(); + bool isHitBackRight() const; + bool isHitBackFront() const; + void calcHitBackDstPos(TVec3f*, bool, bool); + bool tryToKill(bool); + void setVelocityToPlayer(f32, f32); + void freeze(); + bool isFreezable(); + void processApproachToPlayer(); + void exeThrow(); + void exeHitBackToHost(); + void exeHitBackToPlayer(); + void exeRebound(); + void exeFreeze(); + void exeFreezeRelease(); + + LiveActor* _8C; + TVec3f _90; + s32 _9C; + s32 _A0; + TVec3f _A4; + TVec3f _B0; + bool _BC; + bool _BD; + bool _BE; + f32 _C0; + f32 _C4; + TVec3f _C8; + f32 _D4; + bool _D8; +}; diff --git a/libs/JSystem/include/JSystem/JGeometry/TVec.hpp b/libs/JSystem/include/JSystem/JGeometry/TVec.hpp index 6455ad813..c43925c24 100644 --- a/libs/JSystem/include/JSystem/JGeometry/TVec.hpp +++ b/libs/JSystem/include/JSystem/JGeometry/TVec.hpp @@ -394,6 +394,10 @@ namespace JGeometry { return ret; } + inline void negate(const TVec3& rVec) { + JMathInlineVEC::PSVECNegate(rVec, this); + } + inline TVec3 negateOperatorInternal() const { TVec3 ret; JGeometry::negateInternal(&this->x, &ret.x); @@ -711,7 +715,16 @@ namespace JGeometry { return lengthinv * oldlength; }; - f32 setLength(const TVec3&, f32); + f32 setLength(const TVec3& rVec, f32 newlength) { + f32 oldlength = rVec.squared(); + if (oldlength <= 0.0000038146973f) { + zero(); + return 0.0f; + } + f32 lengthinv = JGeometry::TUtil< f32 >::inv_sqrt(oldlength); + scale(lengthinv * newlength, rVec); + return lengthinv * oldlength; + }; f32 length() const { return PSVECMag(this); diff --git a/src/Game/Enemy/CocoNutBall.cpp b/src/Game/Enemy/CocoNutBall.cpp new file mode 100644 index 000000000..ad968382e --- /dev/null +++ b/src/Game/Enemy/CocoNutBall.cpp @@ -0,0 +1,530 @@ +#include "Game/Enemy/CocoNutBall.hpp" +#include "Game/LiveActor/HitSensor.hpp" +#include "Game/MapObj/CocoNut.hpp" +#include "Game/Util.hpp" +#include "JSystem/JMath/JMATrigonometric.hpp" + +namespace { + const f32 cReboundVelocity[] = {0.0f, 15.0f, 5.0f}; +} + +namespace NrvCocoNutBall { + NEW_NERVE(CocoNutBallNrvThrow, CocoNutBall, Throw); + NEW_NERVE(CocoNutBallNrvHitBackToHost, CocoNutBall, HitBackToHost); + NEW_NERVE(CocoNutBallNrvHitBackToPlayer, CocoNutBall, HitBackToPlayer); + NEW_NERVE(CocoNutBallNrvRebound, CocoNutBall, Rebound); + NEW_NERVE(CocoNutBallNrvFreeze, CocoNutBall, Freeze); + NEW_NERVE(CocoNutBallNrvFreezeRelease, CocoNutBall, FreezeRelease); +} // namespace NrvCocoNutBall + +CocoNutBall::CocoNutBall(const char* pName) + : LiveActor(pName), _8C(nullptr), _90(0.0f, -1.0f, 0.0f), _9C(0), _A0(0), _A4(gZeroVec), _B0(gZeroVec), _BC(false), _BD(false), _BE(false), + _C0(450.0f), _C4(0.0f), _C8(0.0f, 1.0f, 0.0f), _D4(10000.0f), _D8(false) { +} + +void CocoNutBall::init(const JMapInfoIter& rIter) { + initModelManagerWithAnm(CocoNut::getModelName(), nullptr, false); + MR::connectToSceneNoSilhouettedMapObjStrongLight(this); + MR::initLightCtrl(this); + initHitSensor(2); + + MR::addHitSensor(this, "body", ATYPE_COCO_NUT, 8, 40.0f, TVec3f(0.0f, 0.0f, 0.0f)); + MR::addHitSensor(this, "bind", ATYPE_COCO_NUT, 8, 500.0f, TVec3f(0.0f, 0.0f, 0.0f)); + + initBinder(40.0f, 0.0f, 0); + initEffectKeeper(0, "CocoNut", false); + // some weirdness with this TVec here + MR::initStarPointerTarget(this, 150.0f, TVec3f(0.0f, 0.0f, 0.0f)); + initSound(4, false); + MR::initShadowVolumeCylinder(this, 60.0f); + MR::invalidateClipping(this); + initNerve(&NrvCocoNutBall::CocoNutBallNrvThrow::sInstance); + makeActorDead(); +} + +void CocoNutBall::appear() { + LiveActor::appear(); + _9C = 0; + MR::onBind(this); + setNerve(&NrvCocoNutBall::CocoNutBallNrvThrow::sInstance); +} + +void CocoNutBall::kill() { + MR::forceDeleteEffect(this, "CocoNutBlur"); + MR::forceDeleteEffect(this, "CocoNutLight"); + MR::startSound(this, "SE_OJ_COCONUT_BALL_BREAK", -1, -1); + + if (_9C > 0) { + MR::sendArbitraryMsg(ACTMES_RUSH_END, _8C->getSensor("body"), getSensor("body")); + } + + LiveActor::kill(); + MR::emitEffect(this, CocoNut::getBreakEffectName()); +} + +void CocoNutBall::appearAndThrow(const TVec3f& appearPos, f32 f1) { + mPosition.set(appearPos); + MR::calcGravity(this); + _C8.negate(mGravity); + setVelocityToPlayer(15.0f, f1); + _BD = MR::isHalfProbability(); + appear(); +} + +void CocoNutBall::hitBackToPlayer() { + f32 rand = MR::getRandom(12.5f, 17.5f); + + if (_BD) { + rand = -rand; + _BD = false; + } else { + _BD = true; + } + + setVelocityToPlayer(3.0f * _9C + 15.0f, rand); + setNerve(&NrvCocoNutBall::CocoNutBallNrvHitBackToPlayer::sInstance); +} + +void CocoNutBall::demoBreak(const TVec3f& pos) { + mPosition.set(pos); + mRotation.zero(); + mVelocity.zero(); + + TPos3f TRMtx; + MR::makeMtxTR(TRMtx.toMtxPtr(), this); + MR::setBaseTRMtx(this, TRMtx); + + MR::emitEffect(this, "Hit"); + MR::startSound(this, "SE_OJ_COCONUT_BALL_BREAK", -1, -1); + MR::emitEffect(this, CocoNut::getBreakEffectName()); +} + +void CocoNutBall::calcAndSetBaseMtx() { + if (!MR::isNearZero(mVelocity)) { + TVec3f velocityDirection; + MR::normalize(mVelocity, &velocityDirection); + TPos3f baseTRMtx; + MR::makeMtxFrontUpPos(&baseTRMtx, velocityDirection, _C8, mPosition); + MR::setBaseTRMtx(this, baseTRMtx); + } +} + +bool CocoNutBall::isSensorBody(HitSensor* pSensor) const { + return pSensor == getSensor("body"); +} + +void CocoNutBall::attackSensor(HitSensor* pSender, HitSensor* pReceiver) { + if (isSensorBody(pSender) && MR::isSensorPlayer(pReceiver)) { + if (isNerveTrowToOrFreeze() && MR::sendArbitraryMsg(ACTMES_ENEMY_ATTACK_FLIP_VERYWEAK, pReceiver, pSender)) { + setNerve(&NrvCocoNutBall::CocoNutBallNrvRebound::sInstance); + return; + } + } + + if (MR::isSensorEnemy(pReceiver) && isSensorBody(pSender)) { + if (pReceiver->mHost == _8C) { + if (isNerve(&NrvCocoNutBall::CocoNutBallNrvHitBackToHost::sInstance)) { + if (MR::sendMsgEnemyAttack(pReceiver, pSender)) { + MR::emitEffect(this, "Hit"); + kill(); + } + } + return; + } + + if (isNerve(&NrvCocoNutBall::CocoNutBallNrvThrow::sInstance) || isNerve(&NrvCocoNutBall::CocoNutBallNrvHitBackToHost::sInstance) || + isNerve(&NrvCocoNutBall::CocoNutBallNrvHitBackToPlayer::sInstance)) { + if (MR::sendMsgEnemyAttack(pReceiver, pSender)) { + kill(); + } + } + } +} + +bool CocoNutBall::receiveMsgPlayerAttack(u32 msg, HitSensor* pSender, HitSensor* pReceiver) { + if (MR::isMsgPlayerSpinAttack(msg)) { + if (isValidReceivePunch()) { + setNerve(&NrvCocoNutBall::CocoNutBallNrvHitBackToHost::sInstance); + return true; + } + } else if (isSensorBody(pReceiver) && MR::isMsgStarPieceReflect(msg)) { + return true; + } + + return false; +} + +HitSensor* CocoNutBall::isBindedAny() const { + if (MR::isBindedGround(this)) { + return MR::getGroundSensor(this); + } + + if (MR::isBindedWall(this)) { + return MR::getWallSensor(this); + } + + if (MR::isBindedRoof(this)) { + return MR::getRoofSensor(this); + } + + return nullptr; +} + +bool CocoNutBall::isNerveTrowToOrFreeze() const { + return isNerve(&NrvCocoNutBall::CocoNutBallNrvThrow::sInstance) || isNerve(&NrvCocoNutBall::CocoNutBallNrvHitBackToPlayer::sInstance) || + isNerve(&NrvCocoNutBall::CocoNutBallNrvFreeze::sInstance) || isNerve(&NrvCocoNutBall::CocoNutBallNrvFreezeRelease::sInstance); +} + +bool CocoNutBall::isValidReceivePunch() const { + if (MR::isDead(this) || (!isNerveTrowToOrFreeze() && !isNerve(&NrvCocoNutBall::CocoNutBallNrvRebound::sInstance))) { + return false; + } else { + return PSVECDistance(mPosition, MR::getPlayerCenterPos()) < 400.0f; + } +} + +void CocoNutBall::calcHitBackVelocitAndGravity() { + bool hitBackRight = isHitBackRight(); + bool hitBackFront = isHitBackFront(); + TVec3f hitBackDstPos; + calcHitBackDstPos(&hitBackDstPos, hitBackRight, hitBackFront); + + TVec3f dir; + dir.subInline(hitBackDstPos, mPosition); + TVec3f scaled; + scaled.scale(_C8.dot(dir), _C8); + MR::vecKillElement(dir, _C8, &dir); + f32 f1 = dir.length() / 42.0f; + MR::normalize(&dir); + TVec3f cross; + PSVECCrossProduct(_C8, dir, &cross); + MR::normalize(&cross); + _90.scale(2.2f, mGravity); + TVec3f scaled2; + scaled2.scale(42.0f, dir); + TVec3f scaled3(_90.scaleInline(f1).scaleInline(f1)); + scaled.subInline(scaled.scaleInline(2.0f)); + mVelocity.add(scaled2, scaled.scaleInline(1.0f / (2.0f * f1))); + + if (!hitBackFront) { + f32 scaleFactor = (hitBackRight ? 1.2f : -1.2f); + TVec3f scaled4; + scaled4.scale(scaleFactor * f1 * f1 / (f1 * 2.0f), cross); + mVelocity.addInline(scaled4); + scaled4.scale(scaleFactor, cross); + _90.subInline(scaled4); + } + + _BC = hitBackRight; +} + +bool CocoNutBall::isHitBackRight() const { + TVec3f vec1; + vec1.subInline(_8C->mPosition, *MR::getPlayerPos()); + + TVec3f vec2; + vec2.subInline(mPosition, *MR::getPlayerPos()); + + MR::vecKillElement(vec1, _C8, &vec1); + MR::vecKillElement(vec2, _C8, &vec2); + + MR::normalize(&vec1); + MR::normalize(&vec2); + + TVec3f cross; + PSVECCrossProduct(vec1, vec2, cross); + + return 0.0f < _C8.dot(cross); +} + +bool CocoNutBall::isHitBackFront() const { + TVec3f vec1; + vec1.subInline(*MR::getPlayerPos(), _8C->mPosition); + + TVec3f vec2; + vec2.subInline(mPosition, *MR::getPlayerPos()); + + MR::vecKillElement(vec1, _C8, &vec1); + MR::vecKillElement(vec2, _C8, &vec2); + + MR::normalize(&vec1); + MR::normalize(&vec2); + + return vec1.dot(vec2) < 0.0f; +} + +void CocoNutBall::calcHitBackDstPos(TVec3f* pOut, bool a1, bool a2) { + TVec3f vec1(0.0f, 0.0f, 0.0f); + if (!a2) { + TVec3f cross; + TVec3f vec2; + + vec2.subInline(_8C->mPosition, *MR::getPlayerPos()); + + MR::vecKillElement(vec2, _C8, &vec2); + MR::normalize(&vec2); + + PSVECCrossProduct(_C8, vec2, &cross); + + MR::vecKillElement(cross, _C8, &cross); + MR::normalize(&cross); + + vec1.scale(a1 ? 150.0f : -150.0f, cross); + } + TVec3f scaled; + + scaled.scale(100.0f, _C8); + vec1.addInline(scaled); + + pOut->add(_8C->getSensor("body")->mPosition, vec1); +} + +bool CocoNutBall::tryToKill(bool alwaysKill) { + HitSensor* bindedSensor = isBindedAny(); + + if (bindedSensor != nullptr) { + if (bindedSensor->isType(ATYPE_PUNCH_BOX) && !isNerve(&NrvCocoNutBall::CocoNutBallNrvRebound::sInstance)) { + MR::sendMsgEnemyAttack(bindedSensor, getSensor("body")); + } + kill(); + return true; + } + + if (alwaysKill) { + kill(); + return true; + } + + return false; +} + +void CocoNutBall::setVelocityToPlayer(f32 f1, f32 f2) { + TVec3f vec1; + + if (!_BE) { + vec1.scale(120.0f, _C8); + vec1.addInline(*MR::getPlayerPos()); + } else { + vec1.set(*MR::getPlayerPos()); + } + + TRot3f rotate; + f32 angle = PI_180 * f2; + rotate.makeRotateInline(_C8, angle); + TVec3f vec2; + vec2.subInline(vec1, mPosition); + rotate.mult33(vec2); + vec1.add(mPosition, vec2); + + if (_BE) { + // inline max function? + f32 val = vec1.y; + f32 val2 = _C0 + _8C->mPosition.y; + if (val >= _C4 + _8C->mPosition.y) { + val = val; + } else { + val = _C4 + _8C->mPosition.y; + } + vec1.y = val; + + f32 flt = 120.0f; + bool v1 = false; + while (vec1.y < val2 - flt) { + vec2.subInline(vec1, mPosition); + vec2.scale(1.5f); + + if (!MR::getFirstPolyOnLineToMap(nullptr, nullptr, mPosition, vec2)) { + v1 = true; + vec1.y += flt; + break; + } + + vec1.y += 60.0f; + } + + if (!v1) { + vec1.y = val2; + } + } + vec2.subInline(vec1, mPosition); + mVelocity.setLength(vec2, f1); +} + +void CocoNutBall::freeze() { + _A0 = 0; + _A4.set(mPosition); + _B0.set(mVelocity); + setNerve(&NrvCocoNutBall::CocoNutBallNrvFreeze::sInstance); +} + +bool CocoNutBall::isFreezable() { + return !MR::isHiddenModel(this) && MR::isStarPointerPointing2POnPressButton(this, "弱", true, false); +} + +void CocoNutBall::processApproachToPlayer() { + if (MR::changeShowModelFlagSyncNearClipping(this, 300.0f)) { + MR::emitEffect(this, "CocoNutLight"); + } else { + MR::deleteEffect(this, "CocoNutLight"); + } + + if (isNerve(&NrvCocoNutBall::CocoNutBallNrvFreezeRelease::sInstance) || MR::isGreaterStep(this, 20)) { + if (isFreezable()) { + freeze(); + return; + } + } + + if (tryToKill(!MR::isNear(this, _8C, _D4))) { + return; + } +} + +void CocoNutBall::exeThrow() { + if (MR::isFirstStep(this)) { + MR::startBck(this, "SpinX", nullptr); + MR::emitEffect(this, "CocoNutLight"); + } + + if (_D8) { + MR::startSound(this, "SE_BM_OTAKING_SPIT_RALLY_BALL", -1, -1); + } else { + MR::startSound(this, "SE_OJ_COCONUT_BALL_SPIT_OUT", -1, -1); + } + + processApproachToPlayer(); +} + +void CocoNutBall::exeHitBackToHost() { + if (MR::isFirstStep(this)) { + MR::setBckRate(this, 1.0); + MR::deleteEffect(this, "Touch"); + MR::emitEffect(this, "CocoNutBlur"); + MR::emitEffect(this, "CocoNutLight"); + MR::emitEffect(this, "SpinHitMark"); + MR::offBind(this); + MR::startSound(this, "SE_OJ_COCONUT_BALL_VOLLEY", -1, -1); + MR::startSpinHitSound(this); + + if (_D8 && MR::isPlayingStageBgm()) { + if (_9C == 0) { + MR::startSystemME("ME_RALLY_COMBO_FIRST"); + } else { + MR::startSystemME("ME_RALLY_COMBO_SECOND"); + } + } + + _9C++; + calcHitBackVelocitAndGravity(); + } + + if (MR::isStep(this, 1)) { + MR::stopScene(6); + } + + if (MR::isStep(this, 2)) { + MR::shakeCameraWeak(); + } + + if (MR::isGreaterEqualStep(this, 1)) { + mVelocity.addInline(_90); + } + + if (tryToKill(!MR::isNearPlayer(this, 5000.0f))) { + return; + } +} + +void CocoNutBall::exeHitBackToPlayer() { + if (MR::isFirstStep(this)) { + MR::emitEffect(this, "Hit"); + MR::startSound(this, "SE_OJ_COCONUT_BALL_VOLLEY", -1, -1); + + if (_D8 && MR::isPlayingStageBgm()) { + MR::startSystemME("ME_RALLY_COMBO_SECOND"); + } + + MR::onBind(this); + } + + processApproachToPlayer(); +} + +void CocoNutBall::exeRebound() { + if (MR::isFirstStep(this)) { + MR::setBckRate(this, 0.25f); + MR::deleteEffect(this, "CocoNutBlur"); + MR::deleteEffect(this, "CocoNutLight"); + + TVec3f vec1; + vec1.subInline(mPosition, *MR::getPlayerPos()); + + TPos3f pos; + pos.identity(); + + MR::makeMtxUpFront(&pos, _C8, vec1); + + mVelocity.x = ::cReboundVelocity[0]; + mVelocity.y = ::cReboundVelocity[1]; + mVelocity.z = ::cReboundVelocity[2]; + + pos.mult33(mVelocity); + } + + TVec3f twoGravity; + twoGravity.scale(2.0f, mGravity); + mVelocity.addInline(twoGravity); + + if (tryToKill(!MR::isNearPlayer(this, 5000.0f))) { + return; + } +} + +void CocoNutBall::exeFreeze() { + if (MR::isFirstStep(this)) { + mVelocity.zero(); + + MR::deleteEffect(this, "CocoNutBlur"); + MR::deleteEffect(this, "CocoNutLight"); + MR::emitEffect(this, "Touch"); + + if (_A0 == 0) { + MR::startDPDHitSound(); + } + } + _A0++; + MR::startDPDFreezeLevelSound(this); + + f32 cos = JMath::sSinCosTable.cosLap(MR::repeatDegree(_A0 * 75.0f)); + + f32 scaleFactor = ((7.5f * cos) * (20 - getNerveStep())) / 20.0f; + + TVec3f camXDirScaled; + camXDirScaled.set(MR::getCamXdir()); + camXDirScaled.scale(scaleFactor); + mPosition.add(_A4, camXDirScaled); + + if (MR::changeShowModelFlagSyncNearClipping(this, 300.0)) { + MR::emitEffect(this, "Touch"); + } else { + MR::deleteEffect(this, "Touch"); + } + + if (isFreezable()) { + // resets nerve step every frame i guess + setNerve(&NrvCocoNutBall::CocoNutBallNrvFreeze::sInstance); + } else if (MR::isStep(this, 20)) { + setNerve(&NrvCocoNutBall::CocoNutBallNrvFreezeRelease::sInstance); + } +} + +void CocoNutBall::exeFreezeRelease() { + if (MR::isFirstStep(this)) { + mPosition.set(_A4); + mVelocity.set(_B0); + MR::deleteEffect(this, "Touch"); + MR::emitEffect(this, "CocoNutLight"); + } + + processApproachToPlayer(); +} From ac0d96789f641943b50136bffa8e34903b403aee Mon Sep 17 00:00:00 2001 From: Amrit Bhogal Date: Thu, 12 Mar 2026 22:35:22 +0000 Subject: [PATCH 52/52] fix regressions --- src/Game/Player/MarioJump.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Game/Player/MarioJump.cpp b/src/Game/Player/MarioJump.cpp index 9bd6e3509..8d25ba555 100644 --- a/src/Game/Player/MarioJump.cpp +++ b/src/Game/Player/MarioJump.cpp @@ -470,7 +470,8 @@ void Mario::trySquatJump() { mMovementStates._21 = false; const f32 frontSpeed = mActor->getConst().getTable()->mSquatJumpFrontSpeed; - TVec3f jumpFront(getAirFrontVec()); + TVec3f airFront(getAirFrontVec()); + TVec3f jumpFront(airFront); jumpFront.scale(frontSpeed); mJumpVec = jumpFront; @@ -494,8 +495,8 @@ void Mario::trySquatJump() { addScale.scale(jumpHeight); mJumpVec += addScale; - _10._8 = false; - if (mDrawStates._14) { + _10_LOW_WORD &= 0xFFFFFEFF; + if ((mDrawStates_WORD >> 20) & 1) { recordJumpEnforceMove(); TVec3f moveKeep; @@ -511,7 +512,7 @@ void Mario::trySquatJump() { enforceScale = MR::clamp(enforceScale + jumpScale, 0.0f, 1.0f); if (mJumpVec.dot(moveKeep) < 0.0f) { - mDrawStates._4 = true; + mDrawStates._1B = true; initActiveJumpVec(); }