From 004a80d301c39e443e641e7663cf9d10e255cc3e Mon Sep 17 00:00:00 2001 From: SwareJonge <41187958+SwareJonge@users.noreply.github.com> Date: Wed, 7 Jan 2026 14:34:02 +0100 Subject: [PATCH 1/4] match and link StringObj --- configure.py | 4 +- include/JSystem/JGeometry/Matrix.h | 55 ++++----- include/Sato/StringObj.h | 46 ++++++-- src/Sato/StringObj.cpp | 174 +++++++++++++++++++++-------- 4 files changed, 188 insertions(+), 91 deletions(-) diff --git a/configure.py b/configure.py index 1f0015d..24be3e6 100755 --- a/configure.py +++ b/configure.py @@ -1308,7 +1308,7 @@ def MatchingFor(*versions): Object(Matching, "Sato/ItemKinoko.cpp"), Object(NonMatching, "Sato/ItemStar.cpp"), Object(NonMatching, "Sato/J3DEffectMgr.cpp"), - Object(NonMatching, "Sato/StringObj.cpp"), + Object(Matching, "Sato/StringObj.cpp"), Object(NonMatching, "Sato/ItemWanWan.cpp"), Object(NonMatching, "Sato/ItemBomb.cpp"), Object(NonMatching, "Sato/ObjUtility.cpp"), @@ -1356,7 +1356,7 @@ def MatchingFor(*versions): Object(NonMatching, "Shiraiwa/JugemGoal.cpp"), Object(NonMatching, "Shiraiwa/JugemFlag.cpp"), Object(NonMatching, "Shiraiwa/MapObjWanwan.cpp"), - Object(NonMatching, "Shiraiwa/MapObjWanwanChain.cpp"), + Object(Matching, "Shiraiwa/MapObjWanwanChain.cpp"), Object(Matching, "Shiraiwa/AnmPlayer.cpp"), Object(NonMatching, "Shiraiwa/MapObjSkyShip.cpp"), Object(NonMatching, "Shiraiwa/MapObjDonkyRockGen.cpp"), diff --git a/include/JSystem/JGeometry/Matrix.h b/include/JSystem/JGeometry/Matrix.h index 27d96a3..42b0f6a 100644 --- a/include/JSystem/JGeometry/Matrix.h +++ b/include/JSystem/JGeometry/Matrix.h @@ -82,20 +82,27 @@ namespace JGeometry { TRotation3() {} void identity33(); - void getXDir(TVec3f &rDest) const - { - rDest.set(this->mMtx[0][0], this->mMtx[1][0], this->mMtx[2][0]); - }; + // TODO: seems fakematch to me but that's a problem for later i guess + inline void getXDir(TVec3f &rDest) const { + f32 z = this->mMtx[2][0]; + f32 y = this->mMtx[1][0]; + f32 x = this->mMtx[0][0]; + rDest.set(x, y, z); + } - void getYDir(TVec3f &rDest) const - { - rDest.set(this->mMtx[0][1], this->mMtx[1][1], this->mMtx[2][1]); - }; + inline void getYDir(TVec3f &rDest) const { + f32 z = this->mMtx[2][1]; + f32 y = this->mMtx[1][1]; + f32 x = this->mMtx[0][1]; + rDest.set(x, y, z); + } - void getZDir(TVec3f &rDest) const - { - rDest.set(this->mMtx[0][2], this->mMtx[1][2], this->mMtx[2][2]); - }; + inline void getZDir(TVec3f &rDest) const { + f32 z = this->mMtx[2][2]; + f32 y = this->mMtx[1][2]; + f32 x = this->mMtx[0][2]; + rDest.set(x, y, z); + } void getXYZDir(TVec3f &rDestX, TVec3f &rDestY, TVec3f &rDestZ) const; void setXDir(const TVec3f &rSrc); @@ -186,30 +193,6 @@ namespace JGeometry { void mult33(TVec3f &) const; void mult33(const TVec3f &, TVec3f &) const; - inline void getXDirInline(TVec3f &rDest) const - { - f32 z = this->mMtx[2][0]; - f32 y = this->mMtx[1][0]; - f32 x = this->mMtx[0][0]; - rDest.set(x, y, z); - } - - inline void getYDirInline(TVec3f &rDest) const - { - f32 z = this->mMtx[2][1]; - f32 y = this->mMtx[1][1]; - f32 x = this->mMtx[0][1]; - rDest.set(x, y, z); - } - - inline void getZDirInline(TVec3f &rDest) const - { - f32 z = this->mMtx[2][2]; - f32 y = this->mMtx[1][2]; - f32 x = this->mMtx[0][2]; - rDest.set(x, y, z); - } - #ifdef NON_MATCHING inline void mult33Inline(const TVec3f &rSrc, TVec3f &rDest) const { diff --git a/include/Sato/StringObj.h b/include/Sato/StringObj.h index 7ac109b..d5a6d72 100644 --- a/include/Sato/StringObj.h +++ b/include/Sato/StringObj.h @@ -7,6 +7,7 @@ #include "JSystem/JSupport/JSUList.h" #include "Kaneshige/DarkAnmMgr.h" #include "Kaneshige/ExModel.h" +#include "Sato/ObjCollision.h" // Forward declarations class ExStringNodeManager; @@ -23,13 +24,19 @@ class StringObj { void setCurrentViewNo(u32); void drawSimpleModel(u32, Mtx, J3DUClipper *, Mtx); + // Inline/Unused + void createShadowBrk(J3DAnmTevRegKey *); + void viewCalc(u32); + void viewCalcClipOn(u32); + void viewCalcClipOff(u32); + public: // VTBL: 0x0 StringNodeManager *mStringNodeMgr; // 0x4 ExModel *mExModel; // 0x8 u32 _c; f32 mScale; // 0x10 - Mtx *_14; + MtxPtr _14; u8 _18; u8 _19[3]; // Padding? ItemDarkAnmPlayer **mItemDarkAnmPlayer; // 0x1c @@ -37,8 +44,16 @@ class StringObj { class StringNode { public: - StringNode(); - ~StringNode(); + StringNode() : _38(this) { + mVel.zero(); + mPos.zero(); + _18.zero(); + _24.zero(); + _30 = true; + _31 = false; + _34 = 0.0f; + } + ~StringNode() {} void calc(); JGeometry::TVec3f mVel; // 0x0 @@ -54,8 +69,10 @@ class StringNode { class StringNodeManager { public: - StringNodeManager(u8, f32, bool, bool, u8); - virtual ~StringNodeManager(); + StringNodeManager(u8 count, f32 speed, bool makeSoundMgr, bool makeCrsGround, u8 someFlag); + virtual ~StringNodeManager() { + delete[] _34; + } void setAllNodePos(const JGeometry::TVec3f &); void calc(); @@ -72,6 +89,17 @@ class StringNodeManager { void addNodePos(u32, JGeometry::TVec3f); void setNodePos(u32, JGeometry::TVec3f); + // Inline/Unused + void calcBetweenNodeVelAll(f32); + void calcBetweenNodeVel(StringNode *, StringNode *, f32); + void collideSphereAll(f32, ObjColSphere *, const JGeometry::TVec3f &); + void collideCylinderAll(f32, ObjColCylinder *, const JGeometry::TVec3f &); + void dispose(); + + void set_3c(u32 val) { + _3c = val; + } + // VTBL: 0x0 JSUList mStrNodeList; // 0x4 f32 _10; @@ -94,12 +122,12 @@ class StringNodeManager { class ExStringNodeManager : public StringNodeManager { public: - ExStringNodeManager(); - ~ExStringNodeManager(); + ExStringNodeManager(u8 count, f32 speed, bool makeSoundMgr, bool makeCrsGround, u8 someFlag) : StringNodeManager(count, speed, makeSoundMgr, makeCrsGround, someFlag) { + setNodeLengthAll(speed); + } + ~ExStringNodeManager() {} virtual void calcBetweenNodePosAll(f32); void setNodeLengthAll(f32); - - f32 _50; }; #endif // STRINGOBJ_H diff --git a/src/Sato/StringObj.cpp b/src/Sato/StringObj.cpp index ea0e2cc..e8fb5bb 100644 --- a/src/Sato/StringObj.cpp +++ b/src/Sato/StringObj.cpp @@ -1,11 +1,13 @@ #include "Sato/StringObj.h" #include "Inagaki/GameSoundMgr.h" +#include "JSystem/JGeometry/Matrix.h" #include "JSystem/JGeometry/Vec.h" #include "JSystem/JKernel/JKRHeap.h" #include "JSystem/JMath/JMath.h" #include "JSystem/JSupport/JSUList.h" #include "JSystem/JUtility/JUTAssert.h" #include "Kaneshige/Course/Course.h" +#include "Kaneshige/Course/CrsArea.h" #include "Kaneshige/Course/CrsGround.h" #include "Kaneshige/DarkAnmMgr.h" #include "Kaneshige/ExModel.h" @@ -13,10 +15,12 @@ #include "Kaneshige/SimpleDrawer.h" #include "Kaneshige/TexLODControl.h" #include "Sato/ObjUtility.h" +#include "Sato/stMath.h" #include "dolphin/mtx.h" #include "JSystem/JGeometry/Util.h" #include "types.h" +#include "JSystem/JAudio/JASFakeMatch2.h" StringNodeManager::StringNodeManager(u8 count, f32 speed, bool makeSoundMgr, bool makeCrsGround, u8 someFlag) { mCrsGround = nullptr; @@ -52,17 +56,6 @@ StringNodeManager::StringNodeManager(u8 count, f32 speed, bool makeSoundMgr, boo _4c = someFlag; } -StringNode::~StringNode() {} - -StringNode::StringNode() : _38(this) { - mVel.zero(); - mPos.zero(); - _18.zero(); - _24.zero(); - _30 = true; - _31 = false; - _34 = 0.0f; -} void StringNodeManager::setAllNodePos(const JGeometry::TVec3f ¶m_1) { for (u8 i = 0; i < mStrNodeList.getNumLinks(); i++) { @@ -80,31 +73,43 @@ void StringNodeManager::calc() { } } -void StringNodeManager::calcBetweenNodePosAll(f32 param_1) { +void StringNodeManager::calcBetweenNodeVelAll(const f32 f1) { + +} + +void StringNodeManager::calcBetweenNodePosAll(const f32 f1) { + JSUListIterator it = mStrNodeList.getLast()->getPrev(); + + for (JSUListIterator it2(mStrNodeList.getLast()); it != mStrNodeList.getFirst(); --it, --it2) { + calcBetweenNodePos(it2.getObject(), it.getObject(), f1, _10); + } + + it = mStrNodeList.getFirst()->getNext(); + for (JSUListIterator it2(mStrNodeList.getFirst()); it != mStrNodeList.getEnd(); ++it, ++it2) { + calcBetweenNodePos(it2.getObject(), it.getObject(), f1, _10); + } +} + +void StringNodeManager::calcBetweenNodeVel(StringNode *strNodeOne, StringNode *strNodeTwo, f32 f1) { + } -void StringNodeManager::calcBetweenNodePos(StringNode *strNodeOne, StringNode *strNodeTwo, f32 f1, f32 f2) { - JGeometry::TVec3f vecInput = strNodeTwo->mPos; // TODO: Declaration is needed, but why is this unused...? +void StringNodeManager::calcBetweenNodePos(StringNode *strNodeOne, StringNode *strNodeTwo, const f32 f1, const f32 f2) { + JGeometry::TVec3f vecInput(strNodeTwo->mPos); // TODO: Declaration is needed, but why is this unused...? JGeometry::TVec3f vecDiff; JGeometry::TVec3f vecNormalised; JGeometry::TVec3f vecScaled; JGeometry::TVec3f vecFinal; PSVECSubtract(&strNodeOne->mPos, &strNodeTwo->mPos, &vecDiff); - f32 magnitude = PSVECMag(&vecDiff); + f32 magnitude = vecDiff.length(); if (magnitude > f2) { PSVECNormalize(&vecDiff, &vecNormalised); PSVECScale(&vecNormalised, &vecScaled, -f2); PSVECAdd(&strNodeOne->mPos, &vecScaled, &strNodeTwo->mPos); - f32 fVar1 = vecDiff.squared(); - if (fVar1 <= JGeometry::TUtilf::epsilon()) { - vecFinal.zero(); - } else { - fVar1 = JGeometry::TUtilf::inv_sqrt(fVar1); - vecFinal.scale(fVar1, vecDiff); - } + vecFinal.normalize(vecDiff); f32 fVar2 = (f1 * (magnitude - f2)); f32 fVar3 = fVar2 > _44 ? _44 : fVar2; @@ -114,7 +119,21 @@ void StringNodeManager::calcBetweenNodePos(StringNode *strNodeOne, StringNode *s } } -void StringNodeManager::resetNodeAll(JGeometry::TVec3f *param_1) { +void StringNodeManager::resetNodeAll(JGeometry::TVec3f *pPos) { + for (JSUListIterator it(mStrNodeList.getFirst()); it.isAvailable(); ++it) { + if (!pPos) { + it->mPos.zero(); + it->_18.zero(); + } + else { + it->mPos = *pPos; + it->_18 = it->mPos; + } + it->mVel.zero(); + it->_24.zero(); + it->_31 = 0; + it->_34 = 0.0f; + } } void StringNodeManager::moveNodeAll() { @@ -124,10 +143,10 @@ void StringNodeManager::moveNodeAll() { } } -void StringNodeManager::doAirFricG(f32 friction, f32 globalScale) { +void StringNodeManager::doAirFricG(const f32 friction, const f32 globalScale) { for (JSULink *link = mStrNodeList.getFirst()->getNext(); link != nullptr; link = link->getNext()) { - link->getObject()->mVel.scale((f32)friction); - JMAVECScaleAdd(&_28, &link->getObject()->mVel, &link->getObject()->mVel, globalScale); + link->getObject()->mVel.scale(friction); + JMAVECScaleAdd(&_28, &link->getObject()->mVel, &link->getObject()->mVel, globalScale); // why does this not use scale mVel.scaleAdd? } } @@ -234,7 +253,16 @@ void StringNodeManager::setNodePos(u32 num, JGeometry::TVec3f newPos) { mStrNodeList.getNth(num)->getObject()->mPos = newPos; } -void ExStringNodeManager::calcBetweenNodePosAll(f32 param_1) { +void ExStringNodeManager::calcBetweenNodePosAll(const f32 p1) { + JSUListIterator it, it2; + for (it = mStrNodeList.getLast()->getPrev(), it2 = mStrNodeList.getLast(); it != mStrNodeList.getFirst(); --it, --it2) { + f32 a = it->_34; // whatever + calcBetweenNodePos(it2.getObject(), it.getObject(), p1, a); + } + + for (it2 = mStrNodeList.getFirst()->getNext(), it = mStrNodeList.getFirst(); it2.isAvailable(); ++it2, ++it) { + calcBetweenNodePos(it.getObject(), it2.getObject(), p1, it->_34); + } } void ExStringNodeManager::setNodeLengthAll(f32 newLength) { @@ -244,10 +272,18 @@ void ExStringNodeManager::setNodeLengthAll(f32 newLength) { } StringObj::StringObj(u8 nodeCount, bool someFlag) { -} + mStringNodeMgr = new ExStringNodeManager(nodeCount, someFlag, true, false, 0); + mExModel = new ExModel[nodeCount]; + _c = 0; + _18 = 1; + mItemDarkAnmPlayer = new ItemDarkAnmPlayer*[nodeCount]; + + for (u8 i = 0; i < nodeCount; i++) { + mItemDarkAnmPlayer[i] = new ItemDarkAnmPlayer(7); + } -StringNodeManager::~StringNodeManager() { - delete[] _34; + mStringNodeMgr->set_3c(0x40000); + reset(); } void StringObj::createModel(JKRSolidHeap *, u32) { @@ -259,7 +295,7 @@ void StringObj::loadmodel(J3DModelData *modelData) { u32 i = 0; while (i < mStringNodeMgr->mStrNodeList.getNumLinks()) { exModel->setModelData(modelData); - RaceMgr::sRaceManager->getCourse()->setFogInfo(exModel); + RCMGetCourse()->setFogInfo(exModel); exModel->setLODBias( TexLODControl::getManager()->getLODBias(TexLODControl::cLODBiasID_3) ); @@ -275,7 +311,63 @@ void StringObj::reset() { } void StringObj::calc() { - + mStringNodeMgr->calc(); + + JGeometry::TVec3f modelScale; + modelScale.setAll(mScale); + + ExModel *exModel = mExModel; + JSUListIterator it(mStringNodeMgr->mStrNodeList.getFirst()); + + JGeometry::TRot3f m; + PSMTXCopy(_14, m); + + f32 scale = 0.0001f; + if (mScale > 0.0f) { + scale = 1.0f / mScale; + } + PSMTXScaleApply(m, m, scale, scale, scale); + + Mtx r_m; + stMTXRotDeg(r_m, 'Z', 90.0f); + + for (u32 i = 0; i < mStringNodeMgr->mStrNodeList.getNumLinks() - 1; i++) { + if (i < mStringNodeMgr->mStrNodeList.getNumLinks() - 1) { + JGeometry::TVec3f cp, ang, vel, pos, pos2; + + m.getYDir(ang); + + mStringNodeMgr->getNodePos(i, &pos); + mStringNodeMgr->getNodePos(i + 1, &pos2); + vel.sub(pos, pos2); + + stVecNormalize(vel); + PSVECCrossProduct(&ang, &vel, &cp); + stVecNormalize(cp); + PSVECCrossProduct(&vel,&cp,&ang); + stVecNormalize(ang); + stMakeRMtx(m, cp, ang, vel); + PSMTXConcat(m, r_m, m); + + } + exModel->setBaseScale(modelScale); + + const JGeometry::TVec3f &modelPos(it->mPos); + m[0][3] = modelPos.x; + m[1][3] = modelPos.y; + m[2][3] = modelPos.z; + exModel->setBaseTRMtx(m); + exModel++; + ++it; + } + + CrsArea area; + for (u32 i = 0; i < mStringNodeMgr->mStrNodeList.getNumLinks() - 1; i++) { + JGeometry::TVec3f pos; + mStringNodeMgr->getNodePos(i, &pos); + area.search(0, pos); + mItemDarkAnmPlayer[i]->calc(area, 0.0f); + } } void StringObj::update() { @@ -286,21 +378,18 @@ void StringObj::update() { } } -void StringObj::setCurrentViewNo(u32 viewNo) { - u32 num = 0; - ExModel *exModel = mExModel; +void StringObj::setCurrentViewNo(const u32 viewNo) { - while (num < mStringNodeMgr->mStrNodeList.getNumLinks() - 1) { + ExModel *exModel = mExModel; + for (u32 i = 0; i < mStringNodeMgr->mStrNodeList.getNumLinks() - 1; i++, exModel++) { exModel->setCurrentViewNo(viewNo); JGeometry::TVec3f pos; - mStringNodeMgr->getNodePos(viewNo, &pos); + mStringNodeMgr->getNodePos(i, &pos); Mtx lightMtx; ObjUtility::getCamDependLightMtx(viewNo, pos, lightMtx); - mExModel[num].setEffectMtx(lightMtx, 0); - num++; - exModel++; + mExModel[i].setEffectMtx(lightMtx, 0); } } @@ -315,13 +404,10 @@ void StringObj::drawSimpleModel(u32 p1, Mtx mtx1, J3DUClipper *j3duClipper, Mtx for (u32 num = 0; num < mStringNodeMgr->mStrNodeList.getNumLinks() - 1; num++) { JGeometry::TVec3f pos; mStringNodeMgr->getNodePos(num, &pos); - f32 radius = pos.x; // FIX: should be `pos.z`, but this reorders instructions weirdly...? - mExModel[num].clipBySphere(p1, j3duClipper, mtx1, radius); + mExModel[num].clipBySphere(p1, j3duClipper, mtx1, mScale); mItemDarkAnmPlayer[num]->setTevColor(&mExModel[num]); mExModel[num].simpleDraw(p1, mtx2, 1); } } } - -ExStringNodeManager::~ExStringNodeManager() {} From ffc2a53258261cf033ebb7f4098ce223924ce18e Mon Sep 17 00:00:00 2001 From: SwareJonge <41187958+SwareJonge@users.noreply.github.com> Date: Wed, 7 Jan 2026 14:39:49 +0100 Subject: [PATCH 2/4] Start working on Chain Chomps --- include/Sato/GeographyObj.h | 4 +- include/Sato/J3DAnmObject.h | 35 +++- include/Shiraiwa/Coord3D.h | 19 +- .../Shiraiwa/{ => Objects}/MapObjAntLion.h | 0 include/Shiraiwa/{ => Objects}/MapObjAward.h | 2 +- .../Shiraiwa/{ => Objects}/MapObjDemoObj.h | 0 include/Shiraiwa/{ => Objects}/MapObjHanabi.h | 0 include/Shiraiwa/{ => Objects}/MapObjPool.h | 0 include/Shiraiwa/Objects/MapObjWanwan.h | 147 ++++++++++++++ include/Yamamoto/KartAnt.h | 2 +- src/Kaneshige/Course/CrsGround.cpp | 2 +- src/Kaneshige/DemoTimeKeeper.cpp | 4 +- src/Kaneshige/RaceDirector.cpp | 2 +- src/Kaneshige/RaceDrawer.cpp | 2 +- src/Sato/ItemYoshiEgg.cpp | 5 +- src/Shiraiwa/MapObjWanwan.cpp | 179 ++++++++++++++++++ src/Shiraiwa/MapObjWanwanChain.cpp | 60 ++++++ 17 files changed, 443 insertions(+), 20 deletions(-) rename include/Shiraiwa/{ => Objects}/MapObjAntLion.h (100%) rename include/Shiraiwa/{ => Objects}/MapObjAward.h (98%) rename include/Shiraiwa/{ => Objects}/MapObjDemoObj.h (100%) rename include/Shiraiwa/{ => Objects}/MapObjHanabi.h (100%) rename include/Shiraiwa/{ => Objects}/MapObjPool.h (100%) create mode 100644 include/Shiraiwa/Objects/MapObjWanwan.h diff --git a/include/Sato/GeographyObj.h b/include/Sato/GeographyObj.h index b58f546..a5756a4 100644 --- a/include/Sato/GeographyObj.h +++ b/include/Sato/GeographyObj.h @@ -229,7 +229,7 @@ class GeographyObj virtual u32 getJ3DModelDataTevStageNum() const { return 0x20000; } // 50 virtual void createColModel(J3DModelData *); // 54 virtual void createBoundsSphere(J3DModelData *); // 58 - virtual GeoAnmTableEntry *getAnmTbl() { return nullptr; } // 5C + virtual GeoAnmTableEntry *getAnmTbl() { return nullptr; } // 5C virtual u16 getSizeAnmTbl() { return 0; } // 60 virtual GeoObjSupervisor *getSupervisor() { return nullptr; } // 64 virtual void getItemThrowDirPow(JGeometry::TVec3f *, f32 *, const ItemObj &); // 68 @@ -314,7 +314,7 @@ class TMapObjHioNode : public GeographyObj public: TMapObjHioNode(u32 id) : GeographyObj(id) {} TMapObjHioNode(const CrsData::SObject &rObj) : GeographyObj(rObj) {} - virtual ~TMapObjHioNode(); + virtual ~TMapObjHioNode() {} }; #endif diff --git a/include/Sato/J3DAnmObject.h b/include/Sato/J3DAnmObject.h index 43bd521..72f55ba 100644 --- a/include/Sato/J3DAnmObject.h +++ b/include/Sato/J3DAnmObject.h @@ -2,13 +2,16 @@ #define SATO_J3DANMOBJECT_H #include "JSystem/J3D/J3DAnmBase.h" +#include "JSystem/J3D/J3DAnmCluster.h" #include "JSystem/J3D/J3DAnmColor.h" #include "JSystem/J3D/J3DAnmTransform.h" #include "JSystem/J3D/J3DFrameCtrl.h" #include "JSystem/J3D/J3DModel.h" #include "JSystem/J3D/J3DMtxCalc.h" +#include "JSystem/J3D/J3DSkinDeform.h" #include "JSystem/JUtility/JUTAssert.h" #include "Kaneshige/ExModel.h" +#include "types.h" class J3DAnmObjBase { @@ -19,10 +22,6 @@ class J3DAnmObjBase void frameProc() { mFrameCtrl.update(); } void update() { mFrameCtrl.update(); } void resetFrame() { mFrameCtrl.reset(); } - - void initFrameCtrl() { - initFrameCtrl(mAnmBase); - } J3DFrameCtrl *getFrameCtrl() { return &mFrameCtrl; } void setExModel(ExModel *model) { mModel = model; } @@ -36,9 +35,35 @@ class J3DAnmObjBase ExModel *mModel; // 04 J3DFrameCtrl mFrameCtrl; // 08 + + // TODO: does this belong here or in J3DAnmObjMaterial? it doesn't make much sense to be here but it does fix offsets for all classes that inherit J3DAnmObjBase J3DAnmBase *mAnmBase; // 1c }; // Size: 0x20 +class J3DAnmObjCluster : public J3DAnmObjBase { +public: + J3DAnmObjCluster() { + mDeformData = nullptr; + } + virtual ~J3DAnmObjCluster() {} + virtual void anmFrameProc(); + + void attach(J3DAnmCluster *); + + static void loadClusterAnmData(J3DAnmCluster **, void *); + static void loadClusterData(J3DDeformData * *, void *); + static void setDeformData(ExModel *, J3DDeformData *, bool); + + void update() { + mDeformData->setAnm((J3DAnmCluster*)mAnmBase); + mFrameCtrl.update(); + anmFrameProc(); + } + +private: + J3DDeformData *mDeformData; +}; + class J3DAnmObjMaterial : public J3DAnmObjBase { public: @@ -54,7 +79,7 @@ class J3DAnmObjMaterial : public J3DAnmObjBase template void attach(T *anm) { mAnmBase = anm; - initFrameCtrl(mAnmBase); + J3DAnmObjBase::initFrameCtrl(mAnmBase); } J3DAnmBase *getAnmBase() { return mAnmBase; } diff --git a/include/Shiraiwa/Coord3D.h b/include/Shiraiwa/Coord3D.h index 79abcff..67ecde3 100644 --- a/include/Shiraiwa/Coord3D.h +++ b/include/Shiraiwa/Coord3D.h @@ -6,8 +6,10 @@ #include "JSystem/JGeometry/Quat.h" #include "JSystem/JGeometry/Vec.h" #include "Kaneshige/Course/CrsData.h" +#include "macros.h" class TFreeMove { +public: TFreeMove(); virtual ~TFreeMove() {} void init(JGeometry::TVec3f *, JGeometry::TVec3f *, f32); @@ -24,6 +26,15 @@ class TFreeMove { void initStart(); void setTargetPosUniform(const JGeometry::TVec3f &, int); void fixCurPosition(); + +private: + JGeometry::TVec3f mTagret; + JGeometry::TVec3f *mpPos; + JGeometry::TVec3f *mpVel; + bool _18; + f32 _1c; + f32 _20; + f32 _24; }; class TPathMove { @@ -46,12 +57,14 @@ class TPathMove { void getNodeDir(u16, JGeometry::TVec3f *); protected: - const CrsData::SObject *mpObj; // 04 - short _8; // + s16 _8; // JGeometry::TVec3f *mpPos; // 0c JGeometry::TVec3f *mpVel; // 10 - + f32 _14; + f32 _18; + bool _1c; + PLACEHOLDER_BYTES(0x1d, 0x24); }; // Size: 0x24 class TFreeRotate { diff --git a/include/Shiraiwa/MapObjAntLion.h b/include/Shiraiwa/Objects/MapObjAntLion.h similarity index 100% rename from include/Shiraiwa/MapObjAntLion.h rename to include/Shiraiwa/Objects/MapObjAntLion.h diff --git a/include/Shiraiwa/MapObjAward.h b/include/Shiraiwa/Objects/MapObjAward.h similarity index 98% rename from include/Shiraiwa/MapObjAward.h rename to include/Shiraiwa/Objects/MapObjAward.h index f673d98..5db3e7a 100644 --- a/include/Shiraiwa/MapObjAward.h +++ b/include/Shiraiwa/Objects/MapObjAward.h @@ -4,7 +4,7 @@ #include "Sato/GeographyObj.h" #include "Sato/StateObserver.h" #include "Sato/Objects/GeoItemBox.h" -#include "Shiraiwa/MapObjDemoObj.h" +#include "Shiraiwa/Objects/MapObjDemoObj.h" // Inline/Unused //void JSULink::~JSULink(); diff --git a/include/Shiraiwa/MapObjDemoObj.h b/include/Shiraiwa/Objects/MapObjDemoObj.h similarity index 100% rename from include/Shiraiwa/MapObjDemoObj.h rename to include/Shiraiwa/Objects/MapObjDemoObj.h diff --git a/include/Shiraiwa/MapObjHanabi.h b/include/Shiraiwa/Objects/MapObjHanabi.h similarity index 100% rename from include/Shiraiwa/MapObjHanabi.h rename to include/Shiraiwa/Objects/MapObjHanabi.h diff --git a/include/Shiraiwa/MapObjPool.h b/include/Shiraiwa/Objects/MapObjPool.h similarity index 100% rename from include/Shiraiwa/MapObjPool.h rename to include/Shiraiwa/Objects/MapObjPool.h diff --git a/include/Shiraiwa/Objects/MapObjWanwan.h b/include/Shiraiwa/Objects/MapObjWanwan.h new file mode 100644 index 0000000..9396f74 --- /dev/null +++ b/include/Shiraiwa/Objects/MapObjWanwan.h @@ -0,0 +1,147 @@ +#ifndef MAPOBJWANWAN_H +#define MAPOBJWANWAN_H + +#include "Bando/EngineSound.h" +#include "JSystem/JParticle/JPAEmitter.h" +#include "Kaneshige/Course/CrsGround.h" +#include "Sato/GeographyObj.h" +#include "Sato/J3DAnmObject.h" +#include "Sato/StateObserver.h" +#include "Sato/StringObj.h" +#include "Shiraiwa/Coord3D.h" +#include "macros.h" +#include "types.h" + +class TMapObjWanwanChain : public GeographyObj { +public: + TMapObjWanwanChain(); // 0x802978d4 + virtual ~TMapObjWanwanChain(); // 0x80297948 + virtual void reset(); // 0x802979c8 + virtual void createColModel(J3DModelData *); // 0x80297a18 + virtual const char *getBmdFileName(); // 0x80297a1c + virtual void setCurrentViewNo(u32); // 0x80297a44 + + // Inline + virtual void calc() {} // 0x80297c1c + + static f32 sChainOneLength; // 0x80415190 +private: + PLACEHOLDER_BYTES(0x14c, 0x150); // afaik unused +}; + +class TMapObjWanwanPile : public GeographyObj { +public: + TMapObjWanwanPile(); + virtual ~TMapObjWanwanPile(); + virtual void doKartColCallBack(int); + virtual void reset(); + virtual void createColModel(J3DModelData *); + virtual const char *getBmdFileName(); + virtual void calc() {} // 0x80297c18 +}; + +class TMapObjWanwan : public TMapObjHioNode, StateObserver { // Autogenerated +public: + TMapObjWanwan(const CrsData::SObject &); // 0x80294db8 + virtual ~TMapObjWanwan(); // 0x80294f34 + void makeChain(int); // 0x80295054 + void reset(); // 0x80295118 + void getParameters(); // 0x80295230 + void resetPosition(int); // 0x802952e0 + void loadAnimation(); // 0x8029534c + const char *getShadowBmdFileName(); // 0x802953cc + void createColModel(J3DModelData *); // 0x802953f4 + void createModel(JKRSolidHeap *, u32); // 0x80295444 + const char *getBmdFileName(); // 0x802955dc + void doKartColCallBack(int); // 0x80295604 + void setCurrentViewNo(u32); // 0x80295668 + void initFunc_Wait(); // 0x802956c8 + void doFunc_Wait(); // 0x802956cc + void initFunc_Jump(); // 0x80295738 + void doFunc_Jump(); // 0x802957e0 + void initFunc_Attack(); // 0x802958b0 + void initFunc_Attacked(); // 0x80295ac8 + void doFunc_Attacked(); // 0x80295acc + void initFunc_Jumped(); // 0x80295b60 + void doFunc_Jumped(); // 0x80295b64 + void setRotate(f32); // 0x80295c1c + void doFunc_Attack(); // 0x80295d60 + void turnDown(bool); // 0x80295e04 + void initFunc_Walk(); // 0x80295e4c + void doFunc_Walk(); // 0x80295ec4 + void initFunc_Back(); // 0x80295f54 + void doFunc_Back(); // 0x80295fb8 + void fallDown(s32, bool); // 0x80296054 + void turnTo(); // 0x8029614c + void jumpStart(JGeometry::TVec3f &, f32); // 0x80296338 + void isTouchGround(); // 0x80296408 + void getCourseHeight(JGeometry::TVec3f &); // 0x8029645c + void getAngleToRand(); // 0x80296494 + void getRandRadius(u8, u8); // 0x802965c0 + void getWanwanBackPos(JGeometry::TVec3f *); // 0x80296658 + void getAngleToAttack(JGeometry::TVec3f &); // 0x802966c0 + + void searchTargetKart(); // 0x8029678c + void calc(); // 0x802967bc + void update(); // 0x80296a2c + void chainCorrect(); // 0x80296ae8 + void checkWanwanHitting(); // 0x80296eb8 + void fixChain(); // 0x80296efc + void setChainPosition(TMapObjWanwanChain *, JGeometry::TVec3f &, JGeometry::TVec3f &, f32); // 0x802971a0 + void createEmitterOnGround(JPABaseEmitter **, const char *); // 0x802974bc + + virtual void MoveExec(); // 0x80297450 + virtual void InitExec(); // 0x80296720 + + static StateFuncSet sTable[7]; // 0x803a4400 + static f32 sOffsetHeight; // 0x80415168 + static f32 sJumpHeight; // 0x8041516c + static f32 sChainBackInside; // 0x80415170 + static s16 sDefaultRingNodeNo; // 0x80415174 + static f32 sAirFriction; // 0x80415178 + static f32 sGravity; // 0x8041517c + static f32 sItemHitVelScale; // 0x80415180 + static f32 sKartHitVelScale; // 0x80415184 + static f32 sJumpVelY; // 0x80415188 + static s16 sJumpTopFrame; // 0x8041518c + static J3DAnmTransform *sWanwanBckAnmTrans; // 0x80416de0 + static J3DMtxCalc *sWanwanBckMtxCalc; // 0x80416de4 + static J3DDeformData *sWanwanBlsAnmData; // 0x80416de8 + static J3DAnmCluster *sWanwanBlkAnmData; // 0x80416dec + static int sChainJointNo; // 0x80416df0 + // Inline/Unused + //void fixPosition(); + //void fixWall(JGeometry::TVec3f &, JGeometry::TVec3f &); + //void changeState_Wall(u32); + //void getAngleToKart(); + static int sWanwanChainNum; + static f32 scChainHalfLength; + // Inline + virtual u32 getMotorType() const { return 3; }; // 0x802975cc + +private: + TMapObjWanwanChain *mpaChain[30]; + TMapObjWanwanPile *mpPile; + f32 mChainLength; + int mKartNo; + PLACEHOLDER_BYTES(0x1dc, 0x1e0); + TFreeMove mFreeMove; + CrsGround *mpGround; + f32 _20c; + s16 mWalkTimer; + s16 _212; + s16 mWalkDuration; + u8 _216; + f32 _218; + f32 mAttackAngle; + f32 mRotate; + f32 _224; + f32 mHeightOffset; + f32 _22c; + f32 _230; + s16 mRingNodeNo; + ExStringNodeManager *mpStringNodeMgr; + J3DAnmObjCluster mAnmObjCluster; + JPABaseEmitter *mpEmitter; +}; // class MapObjWanwan +#endif // MAPOBJWANWAN_H diff --git a/include/Yamamoto/KartAnt.h b/include/Yamamoto/KartAnt.h index a442347..aa5602a 100644 --- a/include/Yamamoto/KartAnt.h +++ b/include/Yamamoto/KartAnt.h @@ -3,7 +3,7 @@ #include -#include "Shiraiwa/MapObjAntLion.h" +#include "Shiraiwa/Objects/MapObjAntLion.h" #include "types.h" diff --git a/src/Kaneshige/Course/CrsGround.cpp b/src/Kaneshige/Course/CrsGround.cpp index 5b0cd6e..1f25909 100644 --- a/src/Kaneshige/Course/CrsGround.cpp +++ b/src/Kaneshige/Course/CrsGround.cpp @@ -7,7 +7,7 @@ #include "Kaneshige/Objects/GeoPuller.h" #include "Kaneshige/Objects/GeoSplash.h" #include "Kaneshige/Objects/GeoWater.h" -#include "Shiraiwa/MapObjPool.h" +#include "Shiraiwa/Objects/MapObjPool.h" #include "mathHelper.h" diff --git a/src/Kaneshige/DemoTimeKeeper.cpp b/src/Kaneshige/DemoTimeKeeper.cpp index 9e9e808..09d3582 100644 --- a/src/Kaneshige/DemoTimeKeeper.cpp +++ b/src/Kaneshige/DemoTimeKeeper.cpp @@ -12,8 +12,8 @@ #include "Sato/JPEffectMgr.h" #include "Sato/EffectScreen.h" #include "Sato/RivalSpeedCtrl.h" -#include "Shiraiwa/MapObjAward.h" -#include "Shiraiwa/MapObjHanabi.h" +#include "Shiraiwa/Objects/MapObjAward.h" +#include "Shiraiwa/Objects/MapObjHanabi.h" #include "kartEnums.h" s32 StaffRollTimeKeeper::sStartTitleCreditTime; diff --git a/src/Kaneshige/RaceDirector.cpp b/src/Kaneshige/RaceDirector.cpp index 9ee7a58..d8e917e 100644 --- a/src/Kaneshige/RaceDirector.cpp +++ b/src/Kaneshige/RaceDirector.cpp @@ -10,7 +10,7 @@ #include "Osako/system.h" #include "Sato/GeographyObjMgr.h" #include "Sato/JPEffectMgr.h" -#include "Shiraiwa/MapObjHanabi.h" +#include "Shiraiwa/Objects/MapObjHanabi.h" #include "kartEnums.h" #include "JSystem/JAudio/JASFakeMatch2.h" diff --git a/src/Kaneshige/RaceDrawer.cpp b/src/Kaneshige/RaceDrawer.cpp index 1e4bfc2..2bbf44e 100644 --- a/src/Kaneshige/RaceDrawer.cpp +++ b/src/Kaneshige/RaceDrawer.cpp @@ -23,7 +23,7 @@ #include "Sato/stEffectMgr.h" #include "Shiraiwa/Balloon.h" #include "Shiraiwa/LensFlare.h" -#include "Shiraiwa/MapObjAward.h" +#include "Shiraiwa/Objects/MapObjAward.h" #include "Shiraiwa/ZCaptureMgr.h" #include "dolphin/gx/GXEnum.h" #include "dolphin/gx/GXPixel.h" diff --git a/src/Sato/ItemYoshiEgg.cpp b/src/Sato/ItemYoshiEgg.cpp index 134d1f1..bb50981 100644 --- a/src/Sato/ItemYoshiEgg.cpp +++ b/src/Sato/ItemYoshiEgg.cpp @@ -78,8 +78,7 @@ void ItemYoshiEgg::loadAnmData(J3DModelData *mdlData) { void ItemYoshiEgg::createModel(JKRSolidHeap *heap, u32 p2, u32 p3) { mModel.createDifferedModel(heap, p2, p3 | (0x1000000 | 0x20000), false); mMat.setExModel(&mModel); - mMat.setAnmBase(sTexPattern); - mMat.initFrameCtrl(); + mMat.attach(sTexPattern); } void ItemYoshiEgg::update() { @@ -337,7 +336,7 @@ void ItemYoshiEgg::calcCreateItem(u32 *outKinds) { } //-------------------------------------------------------------- - // 4?d. Next round will draw from the three “common” entries + // 4?d. Next round will draw from the three "Common" entries // plus whatever we have just appended (0?2 entries) //-------------------------------------------------------------- listSize = appended + 3; // 3 mandatory + newly added diff --git a/src/Shiraiwa/MapObjWanwan.cpp b/src/Shiraiwa/MapObjWanwan.cpp index e69de29..dc077ec 100644 --- a/src/Shiraiwa/MapObjWanwan.cpp +++ b/src/Shiraiwa/MapObjWanwan.cpp @@ -0,0 +1,179 @@ +#include "Shiraiwa/Objects/MapObjWanwan.h" +#include "Kaneshige/Course/CrsGround.h" +#include "Kaneshige/RaceMgr.h" +#include "Sato/GeographyObj.h" +#include "Sato/StateObserver.h" +#include "types.h" + +StateObserver::StateFuncSet TMapObjWanwan::sTable[7] = { + {0, &TMapObjWanwan::initFunc_Wait, &TMapObjWanwan::doFunc_Wait}, + {1, &TMapObjWanwan::initFunc_Attack, &TMapObjWanwan::doFunc_Attack}, + {2, &TMapObjWanwan::initFunc_Walk, &TMapObjWanwan::doFunc_Walk}, + {3, &TMapObjWanwan::initFunc_Back, &TMapObjWanwan::doFunc_Back}, + {4, &TMapObjWanwan::initFunc_Jump, &TMapObjWanwan::doFunc_Jump}, + {5, &TMapObjWanwan::initFunc_Attacked, &TMapObjWanwan::doFunc_Attacked}, + {6, &TMapObjWanwan::initFunc_Jumped, &TMapObjWanwan::doFunc_Jumped}, +}; + +TMapObjWanwan::TMapObjWanwan(const CrsData::SObject &obj) : TMapObjHioNode(obj), mpPile(nullptr), mpEmitter(nullptr) { + GeographyObj::NewAnmCtrl(); + GeographyObj::createSoundMgr(); + mpGround = new CrsGround(RCMGetCourse()); + getParameters(); + makeChain(_216); + mFreeMove.init(&mPos, &mVel, 100.0f); + mpStringNodeMgr = new ExStringNodeManager(_216, 30.0f, true, false, 0); + mpStringNodeMgr->set_3c(0x40000); +} + +TMapObjWanwan::~TMapObjWanwan() { + delete mpStringNodeMgr; + delete mpGround; +} + +void TMapObjWanwan::makeChain(int) {} + +void TMapObjWanwan::reset() {} + +void TMapObjWanwan::getParameters() { + if (mObjData->mParam1 < 2) { + _216 = 21; + } + else { + _216 = mObjData->mParam1 + 1; + } + + u8 clamped = _216; + if (clamped > 30) { + clamped = 30; + } + else if (clamped < 2) { + clamped = 2; + } + + _216 = clamped; + + if (mObjData->mParam2 == 0) { + mWalkDuration = 120; + } + else { + mWalkDuration = mObjData->mParam2; + } + + if (mObjData->mParam3 == 0) { + _224 = 20.0f; + } + else { + _224 = mObjData->mParam3; + } +} + +void TMapObjWanwan::resetPosition(int) {} + +void TMapObjWanwan::loadAnimation() {} + +const char *TMapObjWanwan::getShadowBmdFileName() { + static const char *cShadowBmdName = "/Objects/Wanwan1Shadow.bmd"; + return cShadowBmdName; +} + +void TMapObjWanwan::createColModel(J3DModelData *) {} + +void TMapObjWanwan::createModel(JKRSolidHeap *heap, u32) { + + mHeightOffset = sOffsetHeight * mScale.y; +} + +const char *TMapObjWanwan::getBmdFileName() { + static const char *cBmdName = "/Objects/Wanwan1.bmd"; + return cBmdName; +} + +void TMapObjWanwan::doKartColCallBack(int) {} + +void TMapObjWanwan::setCurrentViewNo(u32) {} + +void TMapObjWanwan::initFunc_Wait() {} + +void TMapObjWanwan::doFunc_Wait() {} + +void TMapObjWanwan::initFunc_Jump() {} + +void TMapObjWanwan::doFunc_Jump() {} + +void TMapObjWanwan::initFunc_Attack() {} + +void TMapObjWanwan::initFunc_Attacked() {} + +void TMapObjWanwan::doFunc_Attacked() {} + +void TMapObjWanwan::initFunc_Jumped() {} + +void TMapObjWanwan::doFunc_Jumped() {} + +void TMapObjWanwan::setRotate(f32) {} + +void TMapObjWanwan::doFunc_Attack() {} + +void TMapObjWanwan::turnDown(bool) {} + +void TMapObjWanwan::initFunc_Walk() {} + +void TMapObjWanwan::doFunc_Walk() {} + +void TMapObjWanwan::initFunc_Back() {} + +void TMapObjWanwan::doFunc_Back() {} + +void TMapObjWanwan::fallDown(s32, bool) {} + +void TMapObjWanwan::turnTo() {} + +void TMapObjWanwan::jumpStart(JGeometry::TVec3f &, f32) {} + +void TMapObjWanwan::isTouchGround() {} + +void TMapObjWanwan::getCourseHeight(JGeometry::TVec3f &) {} + +void TMapObjWanwan::getAngleToRand() {} + +void TMapObjWanwan::getRandRadius(u8, u8) {} + +void TMapObjWanwan::getWanwanBackPos(JGeometry::TVec3f *) {} + +void TMapObjWanwan::getAngleToAttack(JGeometry::TVec3f &) {} + +void TMapObjWanwan::InitExec() { + Observer_FindAndInit(TMapObjWanwan, 7); +} + +void TMapObjWanwan::searchTargetKart() {} + +void TMapObjWanwan::calc() {} + +void TMapObjWanwan::update() { + mAnmObjCluster.update(); + + if (mAnmObjCluster.getFrameCtrl()->getFrame() == 0.0f && mAnmObjCluster.getFrameCtrl()->getRate() != 0.0f) { + mSoundMgr->setSe(0x40021); + } + mSoundMgr->frameWork(); + setModelMatrixAndScale(); + mModel.update(0); +} + +void TMapObjWanwan::chainCorrect() {} + +void TMapObjWanwan::checkWanwanHitting() {} + +void TMapObjWanwan::fixChain() {} + +void TMapObjWanwan::setChainPosition(TMapObjWanwanChain *, JGeometry::TVec3f &, JGeometry::TVec3f &, float) {} + +void TMapObjWanwan::MoveExec() { + Observer_FindAndExec(TMapObjWanwan, 7); +} + +void TMapObjWanwan::createEmitterOnGround(JPABaseEmitter **, const char *) {} + +#include "JSystem/JAudio/JASFakeMatch2.h" diff --git a/src/Shiraiwa/MapObjWanwanChain.cpp b/src/Shiraiwa/MapObjWanwanChain.cpp index e69de29..4db5deb 100644 --- a/src/Shiraiwa/MapObjWanwanChain.cpp +++ b/src/Shiraiwa/MapObjWanwanChain.cpp @@ -0,0 +1,60 @@ +#include "Sato/GeographyObj.h" +#include "Sato/ObjUtility.h" +#include "Shiraiwa/Objects/MapObjWanwan.h" + +#include "JSystem/JAudio/JASFakeMatch2.h" + +f32 TMapObjWanwanChain::sChainOneLength = 120.0f; + +TMapObjWanwanChain::TMapObjWanwanChain() : GeographyObj(0xe79) { + GeographyObj::setObjFlagSimpleDraw(); + GeographyObj::NewAnmCtrl(); +} + +TMapObjWanwanChain::~TMapObjWanwanChain() {} + +void TMapObjWanwanChain::reset() { + GeographyObj::resetObject(); + GeographyObj::clrObjFlagCheckGeoHitting(); + GeographyObj::clrObjFlagCheckItemHitting(); + GeographyObj::clrAllCheckKartHitFlag(); + _58 = 0; +} + +void TMapObjWanwanChain::createColModel(J3DModelData *) {} + +const char *TMapObjWanwanChain::getBmdFileName() { + static const char *cBmdName = "/Item/wanwan_chn.bmd"; + return cBmdName; +} + +void TMapObjWanwanChain::setCurrentViewNo(u32 viewNo) { + mModel.setCurrentViewNo(viewNo); + Mtx m; + ObjUtility::getCamDependLightMtx(viewNo, mPos, m); + mModel.setEffectMtx(m, 0); +} + +TMapObjWanwanPile::TMapObjWanwanPile() : GeographyObj(0xe7a) { + GeographyObj::setObjFlagSimpleDraw(); + GeographyObj::NewAnmCtrl(); +} + +TMapObjWanwanPile::~TMapObjWanwanPile() {} + +void TMapObjWanwanPile::doKartColCallBack(int) {} + +void TMapObjWanwanPile::reset() { + GeographyObj::resetObject(); + GeographyObj::clrObjFlagCheckGeoHitting(); + GeographyObj::clrObjFlagCheckItemHitting(); + GeographyObj::clrAllCheckKartHitFlag(); + _58 = 0; +} + +void TMapObjWanwanPile::createColModel(J3DModelData *) {} + +const char *TMapObjWanwanPile::getBmdFileName() { + static const char *cBmdName = "/Objects/Wanwan1Pile.bmd"; + return cBmdName; +} From 319f5aa22398caa0233585a6ff5e65f06afb47db Mon Sep 17 00:00:00 2001 From: SwareJonge <41187958+SwareJonge@users.noreply.github.com> Date: Sun, 11 Jan 2026 16:19:30 +0100 Subject: [PATCH 3/4] Match the majority of MapObjWanWan --- include/JSystem/JAudio/JAUAudience.h | 6 +- include/JSystem/JGeometry/Matrix.h | 31 +- include/JSystem/JGeometry/Vec.h | 28 +- include/Kaneshige/Course/CrsGround.h | 1 + include/Sato/ItemObj.h | 1 + include/Sato/J3DAnmObject.h | 9 + include/Sato/ObjCollision.h | 3 +- include/Shiraiwa/Coord3D.h | 8 + include/Shiraiwa/Objects/MapObjWanwan.h | 65 ++- src/Shiraiwa/MapObjWanwan.cpp | 671 ++++++++++++++++++++++-- 10 files changed, 728 insertions(+), 95 deletions(-) diff --git a/include/JSystem/JAudio/JAUAudience.h b/include/JSystem/JAudio/JAUAudience.h index 3212e60..a0e0d80 100644 --- a/include/JSystem/JAudio/JAUAudience.h +++ b/include/JSystem/JAudio/JAUAudience.h @@ -152,7 +152,7 @@ class JAUAudience_withSetting_doppler : public JAUAudience_withSetting { class JAUAudienceState { public: JAUAudienceState() {} - //~JAUDopplerAudienceState() {} + //~JAUAudienceState() {} void init() { Mtx m; @@ -163,7 +163,7 @@ class JAUAudienceState { JGeometry::TPos3f m; mMtx.set(in); m.setPositionFromLookAt(mMtx); - m.getTransInline(_3c); + m.getTrans(_3c); _48.set(_3c); _30.zero(); @@ -190,7 +190,7 @@ class JAUDopplerAudienceState { JGeometry::TPos3f m; mMtx.set(in); m.setPositionFromLookAt(mMtx); - m.getTransInline(_3c); + m.getTrans(_3c); _48.set(_3c); _30.zero(); } diff --git a/include/JSystem/JGeometry/Matrix.h b/include/JSystem/JGeometry/Matrix.h index 42b0f6a..7d730de 100644 --- a/include/JSystem/JGeometry/Matrix.h +++ b/include/JSystem/JGeometry/Matrix.h @@ -13,7 +13,9 @@ namespace JGeometry { { public: SMatrix34C() {} - void set(const SMatrix34C &rSrc); + void set(const SMatrix34C &rSrc) { + JMath::gekko_ps_copy12(this, rSrc); + } void set(T rxx, T ryx, T rzx, T tx, T rxy, T ryy, T rzy, T ty, T rxz, T ryz, T rzz, T tz); void scale(T); @@ -23,6 +25,8 @@ namespace JGeometry { JMath::gekko_ps_copy12(this, pSrc); } + f32 at(u32 i, u32 j) const { return mMtx[i][j]; } + T &ref(u32 i, u32 j) { return mMtx[i][j]; } inline Mtx *toMtx() @@ -82,12 +86,11 @@ namespace JGeometry { TRotation3() {} void identity33(); - // TODO: seems fakematch to me but that's a problem for later i guess + // TODO: getYDir doesn't match in StringObj with the same method as getXDir and getZDir + // however there is a chance Sato is a troll and didn't use the inline + // actually, Sato is a troll regardless inline void getXDir(TVec3f &rDest) const { - f32 z = this->mMtx[2][0]; - f32 y = this->mMtx[1][0]; - f32 x = this->mMtx[0][0]; - rDest.set(x, y, z); + rDest.set(this->at(0, 0), this->at(1, 0), this->at(2, 0)); } inline void getYDir(TVec3f &rDest) const { @@ -98,10 +101,7 @@ namespace JGeometry { } inline void getZDir(TVec3f &rDest) const { - f32 z = this->mMtx[2][2]; - f32 y = this->mMtx[1][2]; - f32 x = this->mMtx[0][2]; - rDest.set(x, y, z); + rDest.set(this->at(0, 2), this->at(1, 2), this->at(2, 2)); } void getXYZDir(TVec3f &rDestX, TVec3f &rDestY, TVec3f &rDestZ) const; @@ -210,8 +210,9 @@ namespace JGeometry { public: TPosition3() {} void getTrans(TVec3f &rDest) const { - rDest.set(this->mMtx[0][3], this->mMtx[1][3], this->mMtx[2][3]); + rDest.set(this->at(0, 3), this->at(1, 3), this->at(2, 3)); } + void setTrans(const TVec3f &rSrc); void setTrans(f32 x, f32 y, f32 z); void zeroTrans() @@ -245,14 +246,6 @@ namespace JGeometry { this->ref(2, 3) = (rLookAt[0][3] * this->mMtx[2][0]) - (rLookAt[1][3] * this->mMtx[2][1]) + rLookAt[0][3] * this->mMtx[2][2]; } void setQT(const TQuat4f &rSrcQuat, const TVec3f &rSrcTrans); - - inline void getTransInline(TVec3f &rDest) const - { - f32 z = this->mMtx[2][3]; - f32 y = this->mMtx[1][3]; - f32 x = this->mMtx[0][3]; - rDest.set(x, y, z); - } }; typedef TMatrix34 TMtx34f; diff --git a/include/JSystem/JGeometry/Vec.h b/include/JSystem/JGeometry/Vec.h index a5ff051..d19370f 100644 --- a/include/JSystem/JGeometry/Vec.h +++ b/include/JSystem/JGeometry/Vec.h @@ -261,13 +261,20 @@ namespace JGeometry { return *this; } - /*TVec3 operator+(const TVec3 &operand) + TVec3 operator-(const TVec3 &operand) + { + TVec3 tmp(*this); + tmp -= operand; + return tmp; + } + + TVec3 operator+(const TVec3 &operand) { TVec3 tmp(*this); tmp += operand; return tmp; } -*/ + TVec3 operator*(f32 scalar) const { TVec3 scaled(*this); @@ -348,7 +355,18 @@ namespace JGeometry { return 0.0f; f32 invsqrt = TUtilf::inv_sqrt(this_squared); - scale(invsqrt); + this->scale(invsqrt); + return invsqrt * this_squared; + } + + f32 normalize(f32 scalar) // fabricated + { + f32 this_squared = squared(); + if (this_squared <= TUtilf::epsilon()) + return 0.0f; + + f32 invsqrt = TUtilf::inv_sqrt(this_squared); + this->scale(invsqrt * scalar); return invsqrt * this_squared; } @@ -356,12 +374,12 @@ namespace JGeometry { { f32 sq = other.squared(); if (sq <= TUtilf::epsilon()) { - zero(); + this->zero(); return 0.0f; } f32 invsqrt = TUtilf::inv_sqrt(sq); - scale(invsqrt, other); + this->scale(invsqrt, other); return invsqrt * sq; } }; diff --git a/include/Kaneshige/Course/CrsGround.h b/include/Kaneshige/Course/CrsGround.h index c37b768..b00b487 100644 --- a/include/Kaneshige/Course/CrsGround.h +++ b/include/Kaneshige/Course/CrsGround.h @@ -43,6 +43,7 @@ class CrsGround enum EMat { // TODO + Mat_1 = 1, Mat_255 = 0xff, }; diff --git a/include/Sato/ItemObj.h b/include/Sato/ItemObj.h index ce3e8f9..564efc1 100644 --- a/include/Sato/ItemObj.h +++ b/include/Sato/ItemObj.h @@ -289,6 +289,7 @@ class ItemObj int get_1fc() const { return _1fc; } const JGeometry::TVec3f &getPos() const { return mPos; } + const JGeometry::TVec3f &getVel() const { return mVel; } const JGeometry::TVec3f getColPos() const { return mColPos; } ItemObjSuc *getSuccessionParent() const { return mSuccessionParent; } diff --git a/include/Sato/J3DAnmObject.h b/include/Sato/J3DAnmObject.h index 72f55ba..38ceedd 100644 --- a/include/Sato/J3DAnmObject.h +++ b/include/Sato/J3DAnmObject.h @@ -24,9 +24,13 @@ class J3DAnmObjBase void resetFrame() { mFrameCtrl.reset(); } J3DFrameCtrl *getFrameCtrl() { return &mFrameCtrl; } + f32 getFrame() const { return mFrameCtrl.getFrame(); } + f32 getRate() const { return mFrameCtrl.getRate(); } + void setExModel(ExModel *model) { mModel = model; } void setRate(const float &rate) { mFrameCtrl.setRate(rate); } void setFrame(float frame) { mFrameCtrl.setFrame(frame); } + void stop() { mFrameCtrl.stop(); } J3DModelData *getModelData() { return mModel->getModelData(); } @@ -54,6 +58,11 @@ class J3DAnmObjCluster : public J3DAnmObjBase { static void loadClusterData(J3DDeformData * *, void *); static void setDeformData(ExModel *, J3DDeformData *, bool); + void setExModel(ExModel *mdl, J3DDeformData *deformData) { + mModel = mdl; + mDeformData = deformData; + } + void update() { mDeformData->setAnm((J3DAnmCluster*)mAnmBase); mFrameCtrl.update(); diff --git a/include/Sato/ObjCollision.h b/include/Sato/ObjCollision.h index 5aa34b2..3358074 100644 --- a/include/Sato/ObjCollision.h +++ b/include/Sato/ObjCollision.h @@ -33,7 +33,8 @@ class ObjColBase u8 IsHitBoundPos(JGeometry::TVec3f, JGeometry::TVec3f); - void setRadius(f32 rad) { mRadius = rad; } + void setRadius(const f32 rad) { mRadius = rad; } + void scaleRadius(const f32 scale) { mRadius = scale * mRadius; } void setScale(f32 scale) { mScale = scale; } f32 getRadius() const { return mRadius; } diff --git a/include/Shiraiwa/Coord3D.h b/include/Shiraiwa/Coord3D.h index 67ecde3..0205eea 100644 --- a/include/Shiraiwa/Coord3D.h +++ b/include/Shiraiwa/Coord3D.h @@ -27,6 +27,14 @@ class TFreeMove { void setTargetPosUniform(const JGeometry::TVec3f &, int); void fixCurPosition(); + bool hasTarget() const { + return _18; + } + + void releaseTarget() { // not sure what to name this + _18 = false; + } + private: JGeometry::TVec3f mTagret; JGeometry::TVec3f *mpPos; diff --git a/include/Shiraiwa/Objects/MapObjWanwan.h b/include/Shiraiwa/Objects/MapObjWanwan.h index 9396f74..6b06abd 100644 --- a/include/Shiraiwa/Objects/MapObjWanwan.h +++ b/include/Shiraiwa/Objects/MapObjWanwan.h @@ -2,6 +2,7 @@ #define MAPOBJWANWAN_H #include "Bando/EngineSound.h" +#include "JSystem/JGeometry/Vec.h" #include "JSystem/JParticle/JPAEmitter.h" #include "Kaneshige/Course/CrsGround.h" #include "Sato/GeographyObj.h" @@ -12,6 +13,25 @@ #include "macros.h" #include "types.h" +class TMapObjWanwan; + +class TMapObjWanwanPile : public GeographyObj { +public: + TMapObjWanwanPile(); + virtual ~TMapObjWanwanPile(); + virtual void doKartColCallBack(int); + virtual void reset(); + virtual void createColModel(J3DModelData *); + virtual const char *getBmdFileName(); + virtual void calc() {} // 0x80297c18 + + void setPosition(const JGeometry::TVec3f &pos) { + mPos.set(pos); + } +private: + friend class TMapObjWanwan; +}; + class TMapObjWanwanChain : public GeographyObj { public: TMapObjWanwanChain(); // 0x802978d4 @@ -25,19 +45,18 @@ class TMapObjWanwanChain : public GeographyObj { virtual void calc() {} // 0x80297c1c static f32 sChainOneLength; // 0x80415190 -private: - PLACEHOLDER_BYTES(0x14c, 0x150); // afaik unused -}; -class TMapObjWanwanPile : public GeographyObj { -public: - TMapObjWanwanPile(); - virtual ~TMapObjWanwanPile(); - virtual void doKartColCallBack(int); - virtual void reset(); - virtual void createColModel(J3DModelData *); - virtual const char *getBmdFileName(); - virtual void calc() {} // 0x80297c18 + void setPosition(const JGeometry::TVec3f &pos) { + mPos.set(pos); + } + + void setPile(TMapObjWanwanPile *pile) { + mpPile = pile; + } + +private: + friend class TMapObjWanwan; + TMapObjWanwanPile *mpPile; }; class TMapObjWanwan : public TMapObjHioNode, StateObserver { // Autogenerated @@ -74,18 +93,18 @@ class TMapObjWanwan : public TMapObjHioNode, StateObserver { // Autogenerated void fallDown(s32, bool); // 0x80296054 void turnTo(); // 0x8029614c void jumpStart(JGeometry::TVec3f &, f32); // 0x80296338 - void isTouchGround(); // 0x80296408 - void getCourseHeight(JGeometry::TVec3f &); // 0x8029645c - void getAngleToRand(); // 0x80296494 - void getRandRadius(u8, u8); // 0x802965c0 + bool isTouchGround(); // 0x80296408 + f32 getCourseHeight(JGeometry::TVec3f &); // 0x8029645c + f32 getAngleToRand(); // 0x80296494 + f32 getRandRadius(u8, u8); // 0x802965c0 void getWanwanBackPos(JGeometry::TVec3f *); // 0x80296658 - void getAngleToAttack(JGeometry::TVec3f &); // 0x802966c0 + f32 getAngleToAttack(JGeometry::TVec3f &); // 0x802966c0 - void searchTargetKart(); // 0x8029678c + int searchTargetKart(); // 0x8029678c void calc(); // 0x802967bc void update(); // 0x80296a2c void chainCorrect(); // 0x80296ae8 - void checkWanwanHitting(); // 0x80296eb8 + bool checkWanwanHitting(); // 0x80296eb8 void fixChain(); // 0x80296efc void setChainPosition(TMapObjWanwanChain *, JGeometry::TVec3f &, JGeometry::TVec3f &, f32); // 0x802971a0 void createEmitterOnGround(JPABaseEmitter **, const char *); // 0x802974bc @@ -124,16 +143,16 @@ class TMapObjWanwan : public TMapObjHioNode, StateObserver { // Autogenerated TMapObjWanwanPile *mpPile; f32 mChainLength; int mKartNo; - PLACEHOLDER_BYTES(0x1dc, 0x1e0); + bool _1dc; TFreeMove mFreeMove; CrsGround *mpGround; f32 _20c; s16 mWalkTimer; - s16 _212; + s16 mTimesAttacked; s16 mWalkDuration; - u8 _216; + u8 mNumChains; f32 _218; - f32 mAttackAngle; + f32 mAttackAngle; // 21c f32 mRotate; f32 _224; f32 mHeightOffset; diff --git a/src/Shiraiwa/MapObjWanwan.cpp b/src/Shiraiwa/MapObjWanwan.cpp index dc077ec..4c1e603 100644 --- a/src/Shiraiwa/MapObjWanwan.cpp +++ b/src/Shiraiwa/MapObjWanwan.cpp @@ -1,9 +1,43 @@ #include "Shiraiwa/Objects/MapObjWanwan.h" +#include "JSystem/J3D/J3DFrameCtrl.h" +#include "JSystem/J3D/J3DModel.h" +#include "JSystem/JGeometry/Matrix.h" +#include "JSystem/JGeometry/Util.h" +#include "JSystem/JGeometry/Vec.h" #include "Kaneshige/Course/CrsGround.h" #include "Kaneshige/RaceMgr.h" #include "Sato/GeographyObj.h" +#include "Sato/GeographyObjMgr.h" +#include "Sato/J3DAnmObject.h" +#include "Sato/JPEffectMgr.h" +#include "Sato/ObjUtility.h" #include "Sato/StateObserver.h" +#include "Shiraiwa/SiUtil.h" +#include "Yamamoto/kartCtrl.h" +#include "dolphin/mtx.h" +#include "kartEnums.h" #include "types.h" +#include "mathHelper.h" +#include "std/math.h" +#include +#include + +J3DAnmTransform *TMapObjWanwan::sWanwanBckAnmTrans; +J3DMtxCalc *TMapObjWanwan::sWanwanBckMtxCalc; +J3DDeformData *TMapObjWanwan::sWanwanBlsAnmData; +J3DAnmCluster *TMapObjWanwan::sWanwanBlkAnmData; +int TMapObjWanwan::sChainJointNo; + +f32 TMapObjWanwan::sOffsetHeight = 300.0f; +f32 TMapObjWanwan::sJumpHeight = 8.0f; +f32 TMapObjWanwan::sChainBackInside = 30.0f; +s16 TMapObjWanwan::sDefaultRingNodeNo = 9; +f32 TMapObjWanwan::sAirFriction = 0.9999f; +f32 TMapObjWanwan::sGravity = 15.0f; +f32 TMapObjWanwan::sItemHitVelScale = 1.0f; +f32 TMapObjWanwan::sKartHitVelScale = 1.0f; +f32 TMapObjWanwan::sJumpVelY = 350.0f; +s16 TMapObjWanwan::sJumpTopFrame = 15; StateObserver::StateFuncSet TMapObjWanwan::sTable[7] = { {0, &TMapObjWanwan::initFunc_Wait, &TMapObjWanwan::doFunc_Wait}, @@ -20,9 +54,9 @@ TMapObjWanwan::TMapObjWanwan(const CrsData::SObject &obj) : TMapObjHioNode(obj), GeographyObj::createSoundMgr(); mpGround = new CrsGround(RCMGetCourse()); getParameters(); - makeChain(_216); + makeChain(mNumChains); mFreeMove.init(&mPos, &mVel, 100.0f); - mpStringNodeMgr = new ExStringNodeManager(_216, 30.0f, true, false, 0); + mpStringNodeMgr = new ExStringNodeManager(mNumChains, 30.0f, true, false, 0); mpStringNodeMgr->set_3c(0x40000); } @@ -31,19 +65,55 @@ TMapObjWanwan::~TMapObjWanwan() { delete mpGround; } -void TMapObjWanwan::makeChain(int) {} +void TMapObjWanwan::makeChain(int count) { + mpPile = (TMapObjWanwanPile *)GetGeoObjMgr()->createSubObj(0xe7a); -void TMapObjWanwan::reset() {} + count = MIN(count, 30); + + for (u8 i = 0; i < count; i++) { + mpaChain[i] = (TMapObjWanwanChain *)GetGeoObjMgr()->createSubObj(0xe79); + mpaChain[i]->setPile(mpPile); + } + mChainLength = (count - 1) * TMapObjWanwanChain::sChainOneLength; + mpaChain[0]->setObjFlagHidding(); +} + +void TMapObjWanwan::reset() { + GeographyObj::resetObject(); + GeographyObj::setObjFlagCheckItemHitting(); + _58 = 0xb; + mReaction.setFlg(7, 0); + StateObserver::ResetState(); + mAnmCtrl->Reset(); + mWalkTimer = 0; + mTimesAttacked = 0; + _20c = -10.0f; + _218 = -100.0f; + _22c = 0.05f; + mRotate = 0.0f; + mKartNo = -1; + mRingNodeNo = sDefaultRingNodeNo; + mAttackAngle = 0.0f; + _230 = 0.0f; + _1dc = true; + mpEmitter = nullptr; + mAnmObjCluster.resetFrame(); + mFreeMove.reset(); + setRotate(mAttackAngle); + resetPosition(mNumChains); + mpStringNodeMgr->resetNodeAll(nullptr); + mpStringNodeMgr->setNodeLengthAll(TMapObjWanwanChain::sChainOneLength); +} void TMapObjWanwan::getParameters() { if (mObjData->mParam1 < 2) { - _216 = 21; + mNumChains = 21; } else { - _216 = mObjData->mParam1 + 1; + mNumChains = mObjData->mParam1 + 1; } - u8 clamped = _216; + u8 clamped = mNumChains; if (clamped > 30) { clamped = 30; } @@ -51,7 +121,7 @@ void TMapObjWanwan::getParameters() { clamped = 2; } - _216 = clamped; + mNumChains = clamped; if (mObjData->mParam2 == 0) { mWalkDuration = 120; @@ -68,19 +138,51 @@ void TMapObjWanwan::getParameters() { } } -void TMapObjWanwan::resetPosition(int) {} +void TMapObjWanwan::resetPosition(int count) { + for (u8 i = 0; i < count; i++) { + if (mpaChain[i]) { + mpaChain[i]->setPosition(mPos); + } + } + + if (mpPile) { + mpPile->setPosition(mPos); + } +} + +void TMapObjWanwan::loadAnimation() { + J3DModelData *mdlData = mModel.getModelData(); + void *bca = ObjUtility::getPtrCourseArc("/Objects/Wanwan1.bca"); + J3DAnmObjTrans::setupTransAnmData(&sWanwanBckAnmTrans, &sWanwanBckMtxCalc, mdlData, bca); -void TMapObjWanwan::loadAnimation() {} + void *bls = ObjUtility::getPtrCourseArc("/Objects/Wanwan1.bls"); + J3DAnmObjCluster::loadClusterData(&sWanwanBlsAnmData, bls); + + void *bla = ObjUtility::getPtrCourseArc("/Objects/Wanwan1.bla"); + J3DAnmObjCluster::loadClusterAnmData(&sWanwanBlkAnmData, bla); +} const char *TMapObjWanwan::getShadowBmdFileName() { static const char *cShadowBmdName = "/Objects/Wanwan1Shadow.bmd"; return cShadowBmdName; } -void TMapObjWanwan::createColModel(J3DModelData *) {} - -void TMapObjWanwan::createModel(JKRSolidHeap *heap, u32) { +void TMapObjWanwan::createColModel(J3DModelData *mdlData) { + createBoundsSphere(mdlData); + mBounds[0]->scaleRadius(0.8f); +} +void TMapObjWanwan::createModel(JKRSolidHeap *heap, u32 viewNo) { + mModel.createDifferedModel(heap, viewNo, 0x200, true); + GeographyObj::getAnmCtrl()->InitRegistration(1, &mModel); + GeographyObj::getAnmCtrl()->RegisterTrans(0, sWanwanBckAnmTrans, sWanwanBckMtxCalc); + GeographyObj::getAnmCtrl()->getFrameCtrl(0)->setAttribute(2); + + J3DAnmObjCluster::setDeformData(&mModel, sWanwanBlsAnmData, false); + mAnmObjCluster.setExModel(&mModel, sWanwanBlsAnmData); + mAnmObjCluster.attach(sWanwanBlkAnmData); + mAnmObjCluster.getFrameCtrl()->setAttribute(2); + sChainJointNo = mModel.getModelData()->getJointName()->getIndex("pos_chn"); mHeightOffset = sOffsetHeight * mScale.y; } @@ -89,67 +191,432 @@ const char *TMapObjWanwan::getBmdFileName() { return cBmdName; } -void TMapObjWanwan::doKartColCallBack(int) {} +void TMapObjWanwan::doKartColCallBack(int kartNo) { + if (!(GetKartCtrl()->GetKartStatus(kartNo) & 0x40000)) return; -void TMapObjWanwan::setCurrentViewNo(u32) {} + mKartNo = kartNo; + StateObserver::setState(4); +} + +void TMapObjWanwan::setCurrentViewNo(u32 viewNo) { + mModel.setCurrentViewNo(viewNo); + + Mtx m; + ObjUtility::getCamDependLightMtx(viewNo, mPos, m); + mModel.setEffectMtx(m, 0); +} void TMapObjWanwan::initFunc_Wait() {} -void TMapObjWanwan::doFunc_Wait() {} +void TMapObjWanwan::doFunc_Wait() { + if (StateObserver::getStateCount() > 10) { + StateObserver::setState(2); + } + else if (mWalkTimer > 0) { + mWalkTimer--; + } +createEmitterOnGround(&mpEmitter, "mk_wanSmoke_a"); +} + +void TMapObjWanwan::initFunc_Jump() { + if (GeographyObj::tstItemHitting()) { + mVel.scale(sItemHitVelScale, GeographyObj::getColItemObj()->getVel()); + } + else { + ObjUtility::getKartVel(mKartNo, &mVel); + mVel.scale(sKartHitVelScale); + } + mVel.y += sJumpVelY; + mAnmObjCluster.stop(); +} -void TMapObjWanwan::initFunc_Jump() {} +void TMapObjWanwan::doFunc_Jump() { + mVel.scale(sAirFriction); + mVel.y -= sGravity; + mPos.add(mVel); -void TMapObjWanwan::doFunc_Jump() {} + JGeometry::TVec3f posdiff, backPos; + getWanwanBackPos(&backPos); -void TMapObjWanwan::initFunc_Attack() {} + posdiff.sub(backPos, mObjData->position); + + if (posdiff.length() > mChainLength) { + mVel.zero(); + StateObserver::setState(6); + } +} + +void TMapObjWanwan::initFunc_Attack() { + JGeometry::TVec3f pos; + ObjUtility::getKartPos(mKartNo, &pos); + pos.sub(mPos); + pos.scale(2.0f); + pos.add(mPos); + + JGeometry::TVec3f kartVel; + ObjUtility::getKartVel(mKartNo, &kartVel); + kartVel.y = 0.0f; + kartVel.normalize(); + + f32 velScale = GetKartCtrl()->GetCarSpeed(mKartNo); + velScale = velScale * velScale * (mScale.y * 0.2f + 0.7f); + kartVel.scale(velScale); + pos.add(kartVel); + + pos.y = mHeightOffset + getCourseHeight(pos); + pos.y = mPos.y; + mFreeMove.setTargetPos(pos, 6.0f, 70.0f); + mVel.zero(); + pos.sub(mPos); + mAttackAngle = getAngleToAttack(pos); +} void TMapObjWanwan::initFunc_Attacked() {} -void TMapObjWanwan::doFunc_Attacked() {} +void TMapObjWanwan::doFunc_Attacked() { + if (isTouchGround() && StateObserver::getStateCount() > 50) { + StateObserver::setState(3); + } + else { + if (mAnmObjCluster.getFrame() == 0.0f) { + mAnmObjCluster.setFrame(0.0f); + } + fallDown(-1, true); + } + + mTimesAttacked++; + createEmitterOnGround(&mpEmitter, "mk_wanSmoke_a"); +} void TMapObjWanwan::initFunc_Jumped() {} -void TMapObjWanwan::doFunc_Jumped() {} +void TMapObjWanwan::doFunc_Jumped() { + if (StateObserver::getStateCount() setRate(1.0f); + StateObserver::setState(2); + return; + } + + mVel.scale(sAirFriction); + mVel.y -= sGravity; + mPos.add(mVel); +} + +void TMapObjWanwan::setRotate(f32 rotate) +{ + mRotate = rotate; + const f32 x = 0; + const f32 y = mRotate; + const f32 z = _230; + + f32 dVar2 = cos(x); // f26 + f32 dVar6 = cos(y); // f31 + f32 dVar5 = cos(z); // f30 + f32 dVar4 = sin(x); // f29 + f32 dVar3 = sin(y); // f28 + f32 dVar1 = sin(z); // f7 + + f32 cxy = dVar6 * dVar2; + + mRotMtx[0][0] = (dVar1 * dVar3) * dVar4 + cxy; + mRotMtx[1][0] = (dVar4 * dVar5); + mRotMtx[2][0] = -(dVar3 * dVar2) + ((dVar1 * dVar6) * dVar4); + + mRotMtx[0][1] = ((-dVar4 * dVar6) + dVar2 * (dVar1 * dVar3)); + mRotMtx[1][1] = (dVar5 * dVar2); + mRotMtx[2][1] = (dVar3 * dVar4 + dVar1 * (cxy)); + + mRotMtx[0][2] = (dVar5 * dVar3); + mRotMtx[1][2] = (-dVar1); + mRotMtx[2][2] = (dVar5 * dVar6); +} + +void TMapObjWanwan::doFunc_Attack() { + if (mAnmObjCluster.getRate() != 0.0f && mAnmObjCluster.getFrame() == 5.0f) { + mAnmObjCluster.stop(); + } + + if (!mFreeMove.hasTarget()) { + mWalkTimer = mWalkDuration; + mTimesAttacked = 0; + mVel.zero(); + mAnmObjCluster.getFrameCtrl()->setRate(1.0f); + StateObserver::setState(5); + return; + } + + turnDown(true); + turnTo(); +} + +void TMapObjWanwan::turnDown(bool p1) { + if (p1) { + if (_230 < 0.75f) { + _230 += 0.03f; + } + } + else { + if (_230 > 0.0f) { + _230 -= 0.05f; + } + } +} + +void TMapObjWanwan::initFunc_Walk() { + if (!isTouchGround()) return; + + if (mRotate == mAttackAngle) { + mAttackAngle = getAngleToRand(); + } + + JGeometry::TVec3f t; + mRotMtx.getZDir(t); + jumpStart(t, 12.0f); +} + +void TMapObjWanwan::doFunc_Walk() { + fallDown(0, false); + if (RCMGetManager()->getRaceMode() == TIME_ATTACK) return; + + if (mWalkTimer <= 0) { + int targetKart = -1; + if (!(StateObserver::getStateCount() & 0x1f)) { + targetKart = searchTargetKart(); + } + if (targetKart != -1) { + mKartNo = targetKart; + StateObserver::setState(1); + } + return; + } + mWalkTimer--; +} + +void TMapObjWanwan::initFunc_Back() { + mAnmObjCluster.getFrameCtrl()->setRate(1.0f); + if (!isTouchGround()) return; + + JGeometry::TVec3f t; + mRotMtx.getZDir(t); + jumpStart(t, 12.0f); +} + +void TMapObjWanwan::doFunc_Back() { + fallDown(3, (mWalkDuration - mWalkTimer < 30)); + if (mWalkTimer < 0) { + mAnmObjCluster.getFrameCtrl()->setRate(1.0f); + StateObserver::setState(2); + return; + } + + if (mWalkDuration - mWalkTimer == 30) { + mAnmObjCluster.getFrameCtrl()->setRate(1.0f); + } + mWalkTimer--; +} -void TMapObjWanwan::setRotate(f32) {} +void TMapObjWanwan::fallDown(s32 nextState, bool p2) { + mPos.add(mVel); -void TMapObjWanwan::doFunc_Attack() {} + if (isTouchGround()) { + if (nextState != -1) { + StateObserver::setState(nextState); + } + } + else { + turnDown(p2); + turnTo(); + mVel.y += _20c; + if (mVel.y < _218) { + mVel.y = _218; + } + } -void TMapObjWanwan::turnDown(bool) {} + createEmitterOnGround(&mpEmitter, "mk_wanSmoke_a"); +} -void TMapObjWanwan::initFunc_Walk() {} +// Nonmatching +// https://decomp.me/scratch/N6GWY +void TMapObjWanwan::turnTo() { + f32 targetAngle = mAttackAngle; + f32 rotate = mRotate; -void TMapObjWanwan::doFunc_Walk() {} + f32 minAngle = targetAngle - 3.141593f; + f32 maxAngle = targetAngle + 3.141593f; -void TMapObjWanwan::initFunc_Back() {} + if (minAngle <= maxAngle) + { + f32 range = maxAngle - minAngle; // 2pi -void TMapObjWanwan::doFunc_Back() {} + while (rotate < minAngle) + { + rotate += range; + } -void TMapObjWanwan::fallDown(s32, bool) {} + while (rotate >= maxAngle) + { + rotate -= range; + } + } -void TMapObjWanwan::turnTo() {} + rotate = _22c; + if (StateObserver::getState() == 1) { + rotate *= 2.0f; + } -void TMapObjWanwan::jumpStart(JGeometry::TVec3f &, f32) {} + if (-rotate < targetAngle - minAngle) { + mRotate -= rotate; + } + else if (rotate > targetAngle - minAngle) { + mRotate += rotate; + } + else { + mRotate = targetAngle; + } -void TMapObjWanwan::isTouchGround() {} + setRotate(mRotate); +} -void TMapObjWanwan::getCourseHeight(JGeometry::TVec3f &) {} +void TMapObjWanwan::jumpStart(JGeometry::TVec3f &vel, f32 s) { + vel.y = 0.0f; -void TMapObjWanwan::getAngleToRand() {} + f32 scale = MAX(mScale.x, mScale.z); + vel.normalize(s * scale); -void TMapObjWanwan::getRandRadius(u8, u8) {} + vel.y = sJumpHeight * mScale.y; + mVel.set(vel); +} -void TMapObjWanwan::getWanwanBackPos(JGeometry::TVec3f *) {} +bool TMapObjWanwan::isTouchGround() { + return (mPos.y - mHeightOffset) <= getCourseHeight(mPos) ? true : false; +} -void TMapObjWanwan::getAngleToAttack(JGeometry::TVec3f &) {} +f32 TMapObjWanwan::getCourseHeight(JGeometry::TVec3f &pos) { + mpGround->search(pos); + return mpGround->getHeight(); +} + +f32 TMapObjWanwan::getAngleToRand() { + JGeometry::TVec3f posDiff, backPos; + posDiff.sub(mObjData->position, mPos); + f32 angle = mAttackAngle; + + getWanwanBackPos(&backPos); + backPos.sub(mObjData->position); + + const f32 l = posDiff.x * mRotMtx[0][2] + posDiff.z * mRotMtx[2][2]; + + if ((l < 0.0f) + && (backPos.length() > mChainLength * 0.8f)) + { + f32 a = std::atan2f(posDiff.x, posDiff.z); + a += getRandRadius(90, 20); + angle = a; + for (; angle < -F_PI; angle += F_TAU); + for (; angle >= F_PI; angle -= F_TAU); + + } + return angle; +} + +f32 TMapObjWanwan::getRandRadius(u8 max, u8 min) { + u32 range = max - min; + u32 rand = GeographyObj::getGeoRnd()->get(); + int deg = (rand % range) * 2 - range; + if (deg < 0) { + deg -= min; + } + else { + deg += min; + } + return MTXDegToRad(deg); + +} + +void TMapObjWanwan::getWanwanBackPos(JGeometry::TVec3f *out) { + if (_1dc) { + f32 x = mPos.x; + f32 y = mPos.y + mHeightOffset; + f32 z = mPos.z; + out->set(x, y, z); + return; + } + + // TODO: all matrices from J3D might already be TPos3f of itself + JGeometry::TPos3f *bumpMtx = (JGeometry::TPos3f *)mModel.getModel()->getAnmMtx(sChainJointNo); + bumpMtx->getTrans(*out); +} + +f32 TMapObjWanwan::getAngleToAttack(JGeometry::TVec3f &v) { + f32 a = std::atan2f(v.x, v.z); + for (; a < -F_PI; a += F_TAU); + for (; a >= F_PI; a -= F_TAU); + + return a; +} void TMapObjWanwan::InitExec() { Observer_FindAndInit(TMapObjWanwan, 7); } -void TMapObjWanwan::searchTargetKart() {} +int TMapObjWanwan::searchTargetKart() { + return SiUtil::searchNearKartBall(mObjData->position, _224); +} -void TMapObjWanwan::calc() {} +void TMapObjWanwan::calc() { + JGeometry::TVec3f pos(mPos); + StateObserver::ExecuteState(); + if (StateObserver::getState() == 1) { + mFreeMove.update(); + } + chainCorrect(); + mpGround->search(mPos); + if (mPos.y - mHeightOffset <= mpGround->getHeight() ) { + mpGround->search(mPos); + mPos.y = mHeightOffset + mpGround->getHeight() - 0.1f; + mVel.y = 0.0f; + } + + bool isWall = false; + mpGround->search(mPos, pos); + + + if (mpGround->getAttribute() == CrsGround::Attr_2) { + JGeometry::TVec3f wall; + + f32 wallNorm = mpGround->getWallNormal(&wall, nullptr) + 20.0f; + isWall = true; + + wall.scale(wallNorm); + mPos.add(wall); + mVel.set(wall); + } + + if (isWall) { + switch (StateObserver::getState()) { + case 2: { + mAttackAngle = std::atan2f(mVel.x, mVel.z); + mAttackAngle += getRandRadius(90, 20); + + f32 a = mAttackAngle; + for (; a < -F_PI; a += F_TAU); + for (; a >= F_PI; a -= F_TAU); + mAttackAngle = a; + } + + } + } + + if (checkWanwanHitting()) { + StateObserver::setState(4); + } + GeographyObj::moveShadowModel(); + if (_1dc) { + _1dc = false; + } +} void TMapObjWanwan::update() { mAnmObjCluster.update(); @@ -162,18 +629,134 @@ void TMapObjWanwan::update() { mModel.update(0); } -void TMapObjWanwan::chainCorrect() {} +void TMapObjWanwan::chainCorrect() { + JGeometry::TVec3f chainPos, objPos, chainOffset, zDir, vel, posDiff; + if (_1dc) { + objPos.set(mPos.x, mPos.y + mHeightOffset, mPos.z); + } + else { + const Mtx &anm_mtx = mModel.getModel()->getAnmMtx(sChainJointNo); + objPos.set(anm_mtx[0][3], anm_mtx[1][3], anm_mtx[2][3]); + } + + chainPos.sub(objPos, mObjData->position); + if (chainPos.length() > mChainLength) { + if (mFreeMove.hasTarget() && chainPos.dot(mVel) > 0.0f) { + mFreeMove.releaseTarget(); + + } + chainOffset.sub(mPos, objPos); + chainPos.normalize(mChainLength); + chainPos.add(chainOffset); + mPos.add(mObjData->position, chainPos); + } + + mpStringNodeMgr->calc(); + + mRotMtx.getZDir(zDir); + zDir.scale(sChainBackInside * mScale.z); + objPos.add(zDir); + mpStringNodeMgr->setNodePos(0, objPos); + + posDiff.sub(mPos, mObjData->position); + posDiff.normalize(); + posDiff.scaleAdd(50.0f, posDiff, mObjData->position); + posDiff.y += 50.0f; + mpStringNodeMgr->setNodePos(mNumChains - 1, posDiff); + + + vel.zero(); + mpStringNodeMgr->setNodeVel(mNumChains - 1, vel); + + + fixChain(); +} + +bool TMapObjWanwan::checkWanwanHitting() { + bool ret = false; + + if (StateObserver::getState() != 4 && GeographyObj::tstItemHitting() ) { + u32 itemKind = mColItemObj->getKind(); + if (itemKind == 7 || itemKind == 8 || itemKind == 1) { + ret = true; + } + } + return ret; +} + +void TMapObjWanwan::fixChain() { + static f32 addf = F_HALF_PI; + + f32 f = (mNumChains & 1) ? 0.0f : addf; -void TMapObjWanwan::checkWanwanHitting() {} + JGeometry::TVec3f pos, nextPos, posDiff; + for (u32 i = 0; i < mNumChains - 1; i++) { + mpStringNodeMgr->getNodePos(i, &pos); + mpStringNodeMgr->getNodePos(i + 1, &nextPos); -void TMapObjWanwan::fixChain() {} + posDiff.sub(pos, nextPos); + posDiff.normalize(); -void TMapObjWanwan::setChainPosition(TMapObjWanwanChain *, JGeometry::TVec3f &, JGeometry::TVec3f &, float) {} + setChainPosition(mpaChain[i], pos, posDiff, f); + f += addf; + } + + mpStringNodeMgr->getNodePos(mNumChains - 1, &pos); + posDiff.sub(mPos, mObjData->position); + posDiff.y = 0.0f; + posDiff.normalize(); + setChainPosition(mpaChain[mNumChains - 1], pos, posDiff, f); +} + +void TMapObjWanwan::setChainPosition(TMapObjWanwanChain *pChain, JGeometry::TVec3f &rPos, JGeometry::TVec3f &rPosDiff, f32 f) { + + JGeometry::TVec3f cp, yDir; + mRotMtx.getYDir(yDir); + pChain->setPosition(rPos); + + cp.cross(rPosDiff, yDir); + cp.normalize(); + yDir.cross(cp, rPosDiff); + yDir.normalize(); + + JGeometry::TPos3f r_m, b; + r_m.setXYZDir(cp, yDir, rPosDiff); + PSMTXIdentity(b); + + f32 s = sin(f); + f32 c = cos(f); + + b[0][0] = c; + b[0][1] = -s; + b[1][0] = s; + b[1][1] = c; + b[2][2] = 1.0; + b[2][1] = 0.0; + b[1][2] = 0.0; + b[2][0] = 0.0; + b[0][2] = 0.0; + + PSMTXConcat(r_m, b, r_m); + pChain->mRotMtx.set( r_m ); +} void TMapObjWanwan::MoveExec() { Observer_FindAndExec(TMapObjWanwan, 7); } -void TMapObjWanwan::createEmitterOnGround(JPABaseEmitter **, const char *) {} +void TMapObjWanwan::createEmitterOnGround(JPABaseEmitter **paEmitter, const char *pName) { + J3DFrameCtrl *ctrl = mAnmCtrl->getFrameCtrl(0); + if (ctrl->getFrame() != 4.0f) return; + + CrsGround ground(RCMGetCourse()); + ground.search(mPos); + if (ground.getMaterial() != CrsGround::Mat_1) return; + + *paEmitter = GetJPAMgr()->createEmt(pName, mPos); + if (*paEmitter) { + JGeometry::TVec3f scale(mScale); + (*paEmitter)->setGlobalScale(scale); + } +} #include "JSystem/JAudio/JASFakeMatch2.h" From cb7ac35341bc61b56df6a55b2e642c326f42a0ae Mon Sep 17 00:00:00 2001 From: SwareJonge <41187958+SwareJonge@users.noreply.github.com> Date: Sun, 11 Jan 2026 21:22:48 +0100 Subject: [PATCH 4/4] cleanup --- include/JSystem/JGeometry/Matrix.h | 12 ++--- src/Sato/StringObj.cpp | 5 +- src/Shiraiwa/MapObjWanwan.cpp | 79 ++++++++++++++---------------- 3 files changed, 44 insertions(+), 52 deletions(-) diff --git a/include/JSystem/JGeometry/Matrix.h b/include/JSystem/JGeometry/Matrix.h index 7d730de..6f15d80 100644 --- a/include/JSystem/JGeometry/Matrix.h +++ b/include/JSystem/JGeometry/Matrix.h @@ -86,18 +86,12 @@ namespace JGeometry { TRotation3() {} void identity33(); - // TODO: getYDir doesn't match in StringObj with the same method as getXDir and getZDir - // however there is a chance Sato is a troll and didn't use the inline - // actually, Sato is a troll regardless inline void getXDir(TVec3f &rDest) const { rDest.set(this->at(0, 0), this->at(1, 0), this->at(2, 0)); } inline void getYDir(TVec3f &rDest) const { - f32 z = this->mMtx[2][1]; - f32 y = this->mMtx[1][1]; - f32 x = this->mMtx[0][1]; - rDest.set(x, y, z); + rDest.set(this->at(0,1), this->at(1, 1), this->at(2, 1)); } inline void getZDir(TVec3f &rDest) const { @@ -209,10 +203,12 @@ namespace JGeometry { { public: TPosition3() {} + + void getTrans(TVec3f &rDest) const { rDest.set(this->at(0, 3), this->at(1, 3), this->at(2, 3)); } - + void setTrans(const TVec3f &rSrc); void setTrans(f32 x, f32 y, f32 z); void zeroTrans() diff --git a/src/Sato/StringObj.cpp b/src/Sato/StringObj.cpp index e8fb5bb..7e1457d 100644 --- a/src/Sato/StringObj.cpp +++ b/src/Sato/StringObj.cpp @@ -319,7 +319,7 @@ void StringObj::calc() { ExModel *exModel = mExModel; JSUListIterator it(mStringNodeMgr->mStrNodeList.getFirst()); - JGeometry::TRot3f m; + JGeometry::TRot3f m; // making this a matrix causes instruction swaps PSMTXCopy(_14, m); f32 scale = 0.0001f; @@ -334,8 +334,7 @@ void StringObj::calc() { for (u32 i = 0; i < mStringNodeMgr->mStrNodeList.getNumLinks() - 1; i++) { if (i < mStringNodeMgr->mStrNodeList.getNumLinks() - 1) { JGeometry::TVec3f cp, ang, vel, pos, pos2; - - m.getYDir(ang); + ang.set(m[0][1], m[1][1], m[2][1]); mStringNodeMgr->getNodePos(i, &pos); mStringNodeMgr->getNodePos(i + 1, &pos2); diff --git a/src/Shiraiwa/MapObjWanwan.cpp b/src/Shiraiwa/MapObjWanwan.cpp index 4c1e603..f909794 100644 --- a/src/Shiraiwa/MapObjWanwan.cpp +++ b/src/Shiraiwa/MapObjWanwan.cpp @@ -304,33 +304,36 @@ void TMapObjWanwan::doFunc_Jumped() { mPos.add(mVel); } -void TMapObjWanwan::setRotate(f32 rotate) -{ +void TMapObjWanwan::setRotate(f32 rotate) { mRotate = rotate; + + // might be mRotMtx.setEulerXYZ? const f32 x = 0; const f32 y = mRotate; const f32 z = _230; + f32 cr = cos(x); // f26 + f32 cp = cos(y); // f31 + f32 cy = cos(z); // f30 + f32 sr = sin(x); // f29 + f32 sp = sin(y); // f28 + f32 sy = sin(z); // f7 + + // ??? + f32 tmp = sy * sp; + f32 cpy = (cy * cp); + f32 spy = sp * sy; + + mRotMtx[0][0] = ((tmp) * sr + (cp * cr)); + mRotMtx[1][0] = (sr * cy); + mRotMtx[2][0] = -(sp * cr) + (sy * cp * sr); - f32 dVar2 = cos(x); // f26 - f32 dVar6 = cos(y); // f31 - f32 dVar5 = cos(z); // f30 - f32 dVar4 = sin(x); // f29 - f32 dVar3 = sin(y); // f28 - f32 dVar1 = sin(z); // f7 - - f32 cxy = dVar6 * dVar2; - - mRotMtx[0][0] = (dVar1 * dVar3) * dVar4 + cxy; - mRotMtx[1][0] = (dVar4 * dVar5); - mRotMtx[2][0] = -(dVar3 * dVar2) + ((dVar1 * dVar6) * dVar4); - - mRotMtx[0][1] = ((-dVar4 * dVar6) + dVar2 * (dVar1 * dVar3)); - mRotMtx[1][1] = (dVar5 * dVar2); - mRotMtx[2][1] = (dVar3 * dVar4 + dVar1 * (cxy)); + mRotMtx[0][1] = ((-sr * cp) + (spy) * cr); + mRotMtx[1][1] = (cy * cr); + mRotMtx[2][1] = (sp * sr + sy * (cp * cr)); - mRotMtx[0][2] = (dVar5 * dVar3); - mRotMtx[1][2] = (-dVar1); - mRotMtx[2][2] = (dVar5 * dVar6); + mRotMtx[0][2] = (cy * sp); + mRotMtx[1][2] = (-sy); + mRotMtx[2][2] = (cpy); } void TMapObjWanwan::doFunc_Attack() { @@ -433,7 +436,6 @@ void TMapObjWanwan::fallDown(s32 nextState, bool p2) { mVel.y = _218; } } - createEmitterOnGround(&mpEmitter, "mk_wanSmoke_a"); } @@ -506,9 +508,10 @@ f32 TMapObjWanwan::getAngleToRand() { getWanwanBackPos(&backPos); backPos.sub(mObjData->position); - const f32 l = posDiff.x * mRotMtx[0][2] + posDiff.z * mRotMtx[2][2]; - - if ((l < 0.0f) + JGeometry::TVec3f zDir; + mRotMtx.getZDir(zDir); + + if ((zDir.dotZX(posDiff) < 0.0f) && (backPos.length() > mChainLength * 0.8f)) { f32 a = std::atan2f(posDiff.x, posDiff.z); @@ -532,7 +535,6 @@ f32 TMapObjWanwan::getRandRadius(u8 max, u8 min) { deg += min; } return MTXDegToRad(deg); - } void TMapObjWanwan::getWanwanBackPos(JGeometry::TVec3f *out) { @@ -544,9 +546,8 @@ void TMapObjWanwan::getWanwanBackPos(JGeometry::TVec3f *out) { return; } - // TODO: all matrices from J3D might already be TPos3f of itself - JGeometry::TPos3f *bumpMtx = (JGeometry::TPos3f *)mModel.getModel()->getAnmMtx(sChainJointNo); - bumpMtx->getTrans(*out); + Mtx &bumpMtx = mModel.getModel()->getAnmMtx(sChainJointNo); + out->set(bumpMtx[0][3], bumpMtx[1][3], bumpMtx[2][3]); } f32 TMapObjWanwan::getAngleToAttack(JGeometry::TVec3f &v) { @@ -572,8 +573,8 @@ void TMapObjWanwan::calc() { mFreeMove.update(); } chainCorrect(); - mpGround->search(mPos); - if (mPos.y - mHeightOffset <= mpGround->getHeight() ) { + + if (isTouchGround()) { mpGround->search(mPos); mPos.y = mHeightOffset + mpGround->getHeight() - 0.1f; mVel.y = 0.0f; @@ -581,8 +582,6 @@ void TMapObjWanwan::calc() { bool isWall = false; mpGround->search(mPos, pos); - - if (mpGround->getAttribute() == CrsGround::Attr_2) { JGeometry::TVec3f wall; @@ -605,7 +604,6 @@ void TMapObjWanwan::calc() { for (; a >= F_PI; a -= F_TAU); mAttackAngle = a; } - } } @@ -667,8 +665,6 @@ void TMapObjWanwan::chainCorrect() { vel.zero(); mpStringNodeMgr->setNodeVel(mNumChains - 1, vel); - - fixChain(); } @@ -723,6 +719,7 @@ void TMapObjWanwan::setChainPosition(TMapObjWanwanChain *pChain, JGeometry::TVec r_m.setXYZDir(cp, yDir, rPosDiff); PSMTXIdentity(b); + // might be setRotate? f32 s = sin(f); f32 c = cos(f); @@ -730,11 +727,11 @@ void TMapObjWanwan::setChainPosition(TMapObjWanwanChain *pChain, JGeometry::TVec b[0][1] = -s; b[1][0] = s; b[1][1] = c; - b[2][2] = 1.0; - b[2][1] = 0.0; - b[1][2] = 0.0; - b[2][0] = 0.0; - b[0][2] = 0.0; + b[2][2] = 1.0f; + b[2][1] = 0.0f; + b[1][2] = 0.0f; + b[2][0] = 0.0f; + b[0][2] = 0.0f; PSMTXConcat(r_m, b, r_m); pChain->mRotMtx.set( r_m );