diff --git a/include/Camera/Camera.hpp b/include/Camera/Camera.hpp index 34c42907..7b5b845b 100644 --- a/include/Camera/Camera.hpp +++ b/include/Camera/Camera.hpp @@ -17,7 +17,7 @@ class CPolarSubCamera : public JDrama::TLookAtCamera { void execSecureView_(s16, Vec*); bool isLButtonCameraSpecifyMode(int) const; void isLButtonCameraInbetween() const; - void isJetCoaster1stCamera() const; + bool isJetCoaster1stCamera() const; void isTalkCameraSpecifyMode(int) const; void isTalkCameraInbetween() const; void isNormalCameraSpecifyMode(int) const; @@ -131,7 +131,9 @@ class CPolarSubCamera : public JDrama::TLookAtCamera { public: /* 0x50 */ int mMode; - /* 0x54 */ char unk54[0x120 - 0x54]; + /* 0x54 */ char unk54[0xA4 - 0x54]; + /* 0xA4 */ s16 unkA4; + /* 0xA6 */ char unkA6[0x120 - 0xA6]; /* 0x120 */ TMarioGamePad* unk120; /* 0x124 */ JGeometry::TVec3 unk124; /* 0x130 */ char unk130[0xC]; diff --git a/include/JSystem/J3D/J3DGraphAnimator/J3DModel.hpp b/include/JSystem/J3D/J3DGraphAnimator/J3DModel.hpp index 6b5fd6d9..f4137185 100644 --- a/include/JSystem/J3D/J3DGraphAnimator/J3DModel.hpp +++ b/include/JSystem/J3D/J3DGraphAnimator/J3DModel.hpp @@ -255,8 +255,8 @@ class J3DModel { /* 0x08 */ u32 unk8; /* 0x0C */ J3DCalcCallBack unkC; char pad1[0x4]; - /* 0x14 */ Vec unk14; - /* 0x20 */ Mtx unk20; + /* 0x14 */ Vec unk14; // mBaseScale + /* 0x20 */ Mtx unk20; // mBaseMtx /* 0x50 */ u8* mScaleFlagArr; /* 0x54 */ u8* mEvlpScaleFlagArr; /* 0x58 */ Mtx* mNodeMatrices; diff --git a/include/M3DUtil/MActor.hpp b/include/M3DUtil/MActor.hpp index a503db80..4bdd0606 100644 --- a/include/M3DUtil/MActor.hpp +++ b/include/M3DUtil/MActor.hpp @@ -22,6 +22,15 @@ class MActorAnmBlk; class MActor { public: + enum ANM_TYPE { + ANM_TYPE_BCK, + ANM_TYPE_BLK, + ANM_TYPE_BPK, + ANM_TYPE_BTP, + ANM_TYPE_BTK, + ANM_TYPE_BRK + }; + MActor(MActorAnmData*); void setMActorAnmData(MActorAnmData*); diff --git a/include/Player/MarioMain.hpp b/include/Player/MarioMain.hpp index 1bf5b65f..001bfac5 100644 --- a/include/Player/MarioMain.hpp +++ b/include/Player/MarioMain.hpp @@ -6,8 +6,10 @@ #include #include #include +#include class TLiveActor; +class TWaterGun; class TBGCheckData; class J3DAnmTexPattern; class J3DModelData; @@ -17,6 +19,23 @@ struct TBGWallCheckRecord; // TODO: where should this be? enum E_SIDEWALK_TYPE {}; +enum E_MARIO_FLAG { + MARIO_FLAG_ABOVE_SEWER_FLOOR = (1 << 0), + MARIO_FLAG_VISIBLE = (1 << 1), + MARIO_FLAG_NPC_TALKING = (1 << 3), + MARIO_FLAG_RECENTLY_LEFT_WATER = (1 << 4), + MARIO_FLAG_GAME_OVER = (1 << 10), + MARIO_FLAG_GROUND_POUND_SIT_UP = (1 << 11), + MARIO_FLAG_HELMET_FLW_CAMERA = (1 << 12), + MARIO_FLAG_HELMET = (1 << 13), + MARIO_FLAG_FLUDD_EMITTING = (1 << 14), + MARIO_FLAG_HAS_FLUDD = (1 << 15), + MARIO_FLAG_IN_SHALLOW_WATER = (1 << 16), + MARIO_FLAG_IN_WATER = (1 << 17), + MARIO_FLAG_HAS_SHIRT = (1 << 20), + MARIO_FLAG_IS_PERFORMING = (1 << 21), +}; + struct TRidingInfo { const TLiveActor* unk0; Vec localPos; @@ -651,7 +670,7 @@ class TMario : public TTakeActor, public TDrawSyncCallback { bool isWearingCap(); void setDivHelm(); void getWallAngle() const; - void getPumpFrame() const; + f32 getPumpFrame() const; void getCenterAnmMtx(); void getRootAnmMtx(); void getHeadRot(); @@ -781,7 +800,7 @@ class TMario : public TTakeActor, public TDrawSyncCallback { void canBendBody(); void considerRotateJumpStart(); void addVelocity(f32); - u32 onYoshi() const; + s32 onYoshi() const; void getGroundJumpPower() const; void windMove(const JGeometry::TVec3&); void flowMove(const JGeometry::TVec3&); @@ -1079,6 +1098,21 @@ class TMario : public TTakeActor, public TDrawSyncCallback { TBGCheckData* getGroundPlane() const { return mGroundPlane; } + // Fabricated + bool checkFlag(u32 attribute) const + { + return unk118 & attribute ? true : false; + } + + // Fabricated + bool fabricatedActionInline() const + { + if (mAction >= 0x168 && 0x16c >= mAction) { + return true; + } + return false; + } + public: /* 0x74 */ u32 mInput; /* 0x78 */ u32 unk78; @@ -1114,7 +1148,7 @@ class TMario : public TTakeActor, public TDrawSyncCallback { /* 0xF6 */ u16 unkF6; /* 0xF8 */ u16 mLightID; - // u16 _0FA; + /* 0xFA */ u16 unk0FA; /* 0xFC */ u32 unkFC[2]; @@ -1122,7 +1156,7 @@ class TMario : public TTakeActor, public TDrawSyncCallback { /* 0x108 */ u32 unk108[4]; - /* 0x118 */ u32 unk118; // gpMarioFlag points here; + /* 0x118 */ u32 unk118; /* 0x11C */ u32 unk11C; @@ -1140,18 +1174,18 @@ class TMario : public TTakeActor, public TDrawSyncCallback { /* 0x38A */ char unk38A[0x5A]; - /* 0x3E4 */ void* mWaterGun; // TWaterGun + /* 0x3E4 */ TWaterGun* mWaterGun; /* 0x3E8 */ u32 unk3E8; /* 0x3EC */ u32 unk3EC; - /* 0x3F0 */ void* mYoshi; // TYoshi 0x3F0 + /* 0x3F0 */ TYoshi* mYoshi; /* 0x3F4 */ char unk3F4[0x0FC]; /* 0x4F0 */ JGeometry::TVec3 unk4F0; - void* mGamePad; // TMarioGamePad + /* 0x4FC */ TMarioGamePad* mGamePad; /* 0x500 */ char unk500[0x74]; @@ -1248,5 +1282,6 @@ class TMario : public TTakeActor, public TDrawSyncCallback { }; extern TMario* gpMarioOriginal; +extern TMario* gpMarioForCallBack; #endif diff --git a/include/Player/NozzleBase.hpp b/include/Player/NozzleBase.hpp new file mode 100644 index 00000000..9a039a1f --- /dev/null +++ b/include/Player/NozzleBase.hpp @@ -0,0 +1,131 @@ +#ifndef NOZZLEBASE_HPP +#define NOZZLEBASE_HPP + +#include +#include +#include + +class TWaterGun; + +class TNozzleBase { +public: + struct TEmitParams : public TParams { + TEmitParams(const char* prm) + : TParams(prm) + , PARAM_INIT(mRocketType, 0) + , PARAM_INIT(mNum, 1.0f) + , PARAM_INIT(mAttack, 1) + , PARAM_INIT(mDirTremble, 0.0099999998) + , PARAM_INIT(mEmitPow, 40.0) + , PARAM_INIT(mEmitCtrl, 1.0f) + , PARAM_INIT(mPowTremble, 1.0f) + , PARAM_INIT(mSize, 40.0f) + , PARAM_INIT(mSizeTremble, 16.0f) + , PARAM_INIT(mAmountMax, 0x834) + , PARAM_INIT(mReactionPow, 0.0f) + , PARAM_INIT(mReactionY, 0.0f) + , PARAM_INIT(mDecRate, 0) + , PARAM_INIT(mTriggerRate, 0x100) + , PARAM_INIT(mDamageLoss, 0xfa) + , PARAM_INIT(mSuckRate, 0.1f) + , PARAM_INIT(mHitRadius, 50.0f) + , PARAM_INIT(mHitHeight, 80.0f) + , PARAM_INIT(mLAngleBase, 0x1000) + , PARAM_INIT(mLAngleNormal, 12000) + , PARAM_INIT(mLAngleSquat, 12000) + , PARAM_INIT(mLAngleMin, -0x2000) + , PARAM_INIT(mLAngleMax, 0x2000) + , PARAM_INIT(mLAngleChase, 0.1f) + , PARAM_INIT(mSizeMinPressure, 0.0f) + , PARAM_INIT(mSizeMaxPressure, 1.0f) + , PARAM_INIT(mNumMin, 1.0f) + , PARAM_INIT(mAttackMin, 1) + , PARAM_INIT(mDirTrembleMin, 0.0099999998) + , PARAM_INIT(mEmitPowMin, 40.0f) + , PARAM_INIT(mSizeMin, 40.0f) + , PARAM_INIT(mMotorPowMin, 5.0f) + , PARAM_INIT(mMotorPowMax, 25.0f) + , PARAM_INIT(mReactionPowMin, 0.0f) + , PARAM_INIT(mInsidePressureDec, 100.0f) + , PARAM_INIT(mInsidePressureMax, 4500.0f) + , PARAM_INIT(mTriggerTime, 1) + , PARAM_INIT(mType, 0) + , PARAM_INIT(mSideAngleMaxSide, 0x4000) + , PARAM_INIT(mSideAngleMaxFront, 0x4000) + , PARAM_INIT(mSideAngleMaxBack, 0x2000) + , PARAM_INIT(mRButtonMult, 10000.0) + , PARAM_INIT(mEmitPowScale, 10.0f) + + { + } + // TODO: Validate these offsets... + /* 0x00 */ TParamRT mRocketType; + /* 0x14 */ TParamRT mNum; + /* 0x28 */ TParamRT mAttack; + /* 0x3C */ TParamRT mDirTremble; + /* 0x50 */ TParamRT mEmitPow; + /* 0x64 */ TParamRT mEmitCtrl; + /* 0x78 */ TParamRT mPowTremble; + /* 0x8C */ TParamRT mSize; + /* 0xA0 */ TParamRT mSizeTremble; + /* 0xB4 */ TParamRT mAmountMax; + /* 0xC8 */ TParamRT mReactionPow; + /* 0xDC */ TParamRT mReactionY; + /* 0xF0 */ TParamRT mDecRate; + /* 0x104 */ TParamRT mTriggerRate; + /* 0x118 */ TParamRT mDamageLoss; + /* 0x12C */ TParamRT mSuckRate; + /* 0x140 */ TParamRT mHitRadius; + /* 0x154 */ TParamRT mHitHeight; + /* 0x168 */ TParamRT mLAngleBase; + /* 0x17C */ TParamRT mLAngleNormal; + /* 0x190 */ TParamRT mLAngleSquat; + /* 0x1A4 */ TParamRT mLAngleMin; + /* 0x1B8 */ TParamRT mLAngleMax; + /* 0x1CC */ TParamRT mLAngleChase; + /* 0x1E0 */ TParamRT mSizeMinPressure; + /* 0x1F4 */ TParamRT mSizeMaxPressure; + /* 0x208 */ TParamRT mNumMin; + /* 0x21C */ TParamRT mAttackMin; + /* 0x230 */ TParamRT mDirTrembleMin; + /* 0x244 */ TParamRT mEmitPowMin; + /* 0x258 */ TParamRT mSizeMin; + /* 0x26C */ TParamRT mMotorPowMin; + /* 0x280 */ TParamRT mMotorPowMax; + /* 0x294 */ TParamRT mReactionPowMin; + /* 0x2C0 */ TParamRT mInsidePressureDec; // These should be correct + /* 0x2D4 */ TParamRT mInsidePressureMax; + /* 0x2E8 */ TParamRT mTriggerTime; + /* 0x2E4 */ TParamRT mType; + /* 0x2F8 */ TParamRT mSideAngleMaxSide; + /* 0x30C */ TParamRT mSideAngleMaxFront; + /* 0x320 */ TParamRT mSideAngleMaxBack; + /* 0x334 */ TParamRT mRButtonMult; + /* 0x348 */ TParamRT mEmitPowScale; + } mEmitParams; // 0x0000 + + TNozzleBase(const char* name, const char* prm, TWaterGun* fludd); + + virtual void init(); + virtual inline s32 getNozzleKind() const; + virtual inline s16 getGunAngle() { return unk36E; } + virtual inline s16 getWaistAngle() { return unk370; } + virtual void movement(const TMarioControllerWork&); + virtual void emitCommon(int, TWaterEmitInfo*); + virtual void emit(int); + virtual void animation(int); + + void calcGunAngle(const TMarioControllerWork&); + + /* 0x368 */ TWaterGun* mFludd; + /* 0x36C */ u16 unk36C; // Some animation state + /* 0x36E */ s16 unk36E; // Gun angle + /* 0x370 */ s16 unk370; // Waist angle + /* 0x372 */ u16 unk372; + /* 0x374 */ f32 unk374; + /* 0x378 */ f32 unk378; + /* 0x37C */ f32 unk37C; + /* 0x380 */ MActor* unk380; // MActor +}; + +#endif diff --git a/include/Player/NozzleDeform.hpp b/include/Player/NozzleDeform.hpp new file mode 100644 index 00000000..607176fc --- /dev/null +++ b/include/Player/NozzleDeform.hpp @@ -0,0 +1,23 @@ +#ifndef NOZZLEDEFORM_HPP +#define NOZZLEDEFORM_HPP + +#include + +class TNozzleDeform : public TNozzleBase { +public: + TNozzleDeform(const char* name, const char* prm, TWaterGun* fludd) + : TNozzleBase(name, prm, fludd) + , mBomb(name, "/Mario/WaterGun/NozzleDeformBomb.prm", fludd) + { + init(); + } + + virtual s32 getNozzleKind() const { return 3; } + virtual void movement(const TMarioControllerWork&); + virtual void emit(int); + virtual void animation(int); + + /* 0x384 */ TNozzleTrigger mBomb; +}; + +#endif diff --git a/include/Player/NozzleTrigger.hpp b/include/Player/NozzleTrigger.hpp new file mode 100644 index 00000000..456b6272 --- /dev/null +++ b/include/Player/NozzleTrigger.hpp @@ -0,0 +1,37 @@ +#ifndef NOZZLETRIGGER_HPP +#define NOZZLETRIGGER_HPP + +#include +#include + +class TNozzleTrigger : public TNozzleBase { +public: + TNozzleTrigger(const char* name, const char* prm, TWaterGun* fludd) + : TNozzleBase(name, prm, fludd) + { + unk38C = 0xffffffff; + unk384 = false; + unk385 = INACTIVE; + unk36C = 0; + unk386 = 0; + unk388 = 0.0f; + } + + virtual void init(); + virtual s32 getNozzleKind() const { return 1; }; + virtual void movement(const TMarioControllerWork&); + virtual void emit(int); + virtual void animation(int); + + // Inactive = not holding R, Active = charging R, Dead = R Waiting to be + // depressed + enum SPRAYSTATE { INACTIVE, ACTIVE, DEAD }; + + /* 0x384 */ bool unk384; // mRumbleOnCharge + /* 0x385 */ s8 unk385; // mSprayState, Current spray state + /* 0x386 */ s16 unk386; // Quarter frames left of spray (i think) + /* 0x388 */ f32 unk388; // mTriggerFill - How far the trigger has gotten + /* 0x38C */ u32 unk38C; // mSoundID - The sound to play when triggering +}; + +#endif diff --git a/include/Player/Watergun.hpp b/include/Player/Watergun.hpp new file mode 100644 index 00000000..1667118b --- /dev/null +++ b/include/Player/Watergun.hpp @@ -0,0 +1,213 @@ +#ifndef WATERGUN_HPP +#define WATERGUN_HPP + +#include +#include +#include +#include +#include +#include +#include + +class TWaterGunParams : public TParams { +public: + TWaterGunParams(const char* prm) + : TParams(prm) + , PARAM_INIT(mRocketHeight, 1500.0f) + , PARAM_INIT(mHoverHeight, 160.0f) + , PARAM_INIT(mLAngleNormal, 60.0f) + , PARAM_INIT(mNozzleAngleYSpeed, 1.0f) + , PARAM_INIT(mNozzleAngleYBrake, 0.995f) + , PARAM_INIT(mNozzleAngleYSpeedMax, 0x2000) + , PARAM_INIT(mHoverRotMax, 0x2000) + , PARAM_INIT(mHoverSmooth, 0.05f) + , PARAM_INIT(mChangeSpeed, 0.1f) {}; + TParamRT mRocketHeight; + TParamRT mHoverHeight; + TParamRT mLAngleNormal; + TParamRT mNozzleAngleYSpeed; + TParamRT mNozzleAngleYBrake; + TParamRT mNozzleAngleYSpeedMax; + TParamRT mHoverRotMax; + TParamRT mHoverSmooth; + TParamRT mChangeSpeed; +}; + +struct NozzleJointData { + u8 flags; // TODO: This is likely an enum. 0x1 is used, 0x4 is disabled. + u8 jointIndex; +}; + +struct NozzleData { + /* 0x00 */ u32 _00; // Number of water streams emitted by this nozzle + /* 0x04 */ u32 _04; // Unused padding + /* 0x08 */ const char* mHelmetPath; // Path to optional helmet model (used + // by underwater nozzle) + /* 0x0C */ const char* mPath; // Path to base nozzle model directory + /* 0x10 */ const char* mBmdPath; // Full path to nozzle's BMD model file + /* 0x14 */ u8 mNumEmitters; // Number of water emitter points on the nozzle + /* 0x15 */ u8 _15; // Unknown/padding + /* 0x16 */ NozzleJointData mJoints[3]; // Array of joint data for the nozzle +}; + +// Data structure containing model paths and configuration for each FLUDD nozzle +// type +class TNozzleBmdData { +public: + u8 getEmitterCount(int index) const { return mNozzles[index].mNumEmitters; } + + u8 getFlags(int index, int jointIndex) const + { + return mNozzles[index].mJoints[jointIndex].flags; + } + + u8 getJointIndex(int index, int jointIndex) const + { + return mNozzles[index].mJoints[jointIndex].jointIndex; + } + + u8 setJointIndex(int index, int jointIndex, s32 value) + { + return mNozzles[index].mJoints[jointIndex].jointIndex = value; + } + + const char* getPath(int index) const { return mNozzles[index].mPath; } + const char* getBmdPath(int index) const { return mNozzles[index].mBmdPath; } + + NozzleData mNozzles[6]; +}; + +extern TNozzleBmdData nozzleBmdData; + +class TWaterGun { +public: + // TODO: I wish these could be combined + // If i make it a named enum, it defaults to 4 bytes size (i think) + typedef s8 TNozzleType; + enum { Spray = 0, Rocket, Underwater, Yoshi, Hover, Turbo }; + + TWaterGun(TMario* mario); + + virtual void perform(u32, JDrama::TGraphics*); + + void changeBackup(); + void calcAnimation(JDrama::TGraphics*); + void changeNozzle(TNozzleType, bool); + bool damage(); + void emit(); + TNozzleBase* getCurrentNozzle() const; + MtxPtr getEmitMtx(int); + void getEmitPosDirSpeed(int, JGeometry::TVec3* pos, + JGeometry::TVec3* dir, + JGeometry::TVec3* speed); + MtxPtr getNozzleMtx(); + f32 getPressure(); + f32 getPressureMax(); + void init(); + void initInLoadAfter(); + bool isEmitting(); + bool isPressureOn(); + void movement(); + void rotateProp(f32); + void setAmountToRate(f32); + void setBaseTRMtx(Mtx); + bool suck(); + void triggerPressureMovement(const TMarioControllerWork&); + + J3DModel* getModel() { return mFluddModel->unk4; } + + // Fabricated + // Probably inlined from Yoshi + inline MtxPtr getYoshiMtx() + { + TYoshi* yoshi = (TYoshi*)mMario->mYoshi; + return yoshi->mActor->unk4->getAnmMtx(yoshi->mJoint); + } + + // Fabricated + // TODO: Definitely not from watergun + inline void playSoundWithInfo(u32 id, const Vec* pos, u32 _unk, f32 _unk2) + { + if (gpMSound->gateCheck(id)) { + MSoundSESystem::MSoundSE::startSoundActorWithInfo( + id, pos, nullptr, _unk2, _unk, 0, nullptr, 0, 4); + } + } + + // Fabricated + inline bool hasFlag(u16 flag) + { + bool hasFlag; + if ((mFlags & flag) != 0) { + hasFlag = true; + } else { + hasFlag = false; + } + return hasFlag; + } + + // Fabricated + s32 getSuckRate() + { + return mCurrentPressure + * getCurrentNozzle()->mEmitParams.mSuckRate.get(); + } + + // Fabricated + TNozzleBase* getNozzle(u8 index) { return mNozzleList[index]; } + + // Fabricated + bool hasWater() const { return mCurrentWater > 0; } + + /* 0x0000 */ u16 mFlags; + /* 0x0008 */ TMario* mMario; + /* 0x000C */ TNozzleDeform mNozzleDeform; + /* 0x0720 */ TNozzleTrigger mNozzleRocket; + /* 0x0AB0 */ TNozzleBase mNozzleUnderWater; + /* 0x0E34 */ TNozzleDeform mNozzleYoshiDeform; + /* 0x1548 */ TNozzleTrigger mNozzleHover; + /* 0x18D8 */ TNozzleTrigger mNozzleTurbo; + /* 0x1C68 */ TNozzleBase* mNozzleList[6]; + /* 0x1C80 */ s32 mCurrentWater; + /* 0x1C84 */ u8 mCurrentNozzle; + /* 0x1C85 */ u8 mSecondNozzle; + /* 0x1C86 */ bool mIsEmitWater; + /* 0x1C87 */ u8 unk1C87; + /* 0x1C88 */ u32 unk1C88; + /* 0x1C8C */ u8 mCurrentPressure; + /* 0x1C8D */ u8 mPreviousPressure; + /* 0x1C8E */ u8 unk1C8E; + /* 0x1C8F */ u8 unk1C8F; + /* 0x1C90 */ JGeometry::TVec3 mEmitPos[4]; + /* 0x1CC0 */ s16 unk1CC0; + /* 0x1CC2 */ s16 unk1CC2; + /* 0x1CC4 */ s16 unk1CC4; + /* 0x1CC6 */ s16 unk1CC6; + /* 0x1CC8 */ f32 unk1CC8; // mNozzleSpeedY + /* 0x1CCC */ f32 unk1CCC; // mNozzleSpeedZ + /* 0x1CD0 */ s16 unk1CD0; + /* 0x1CD2 */ s16 unk1CD2; + /* 0x1CD4 */ MActor* mFluddModel; // MActor* + /* 0x1CD8 */ u8 unk1CD8; // mCurFluddTransformIdx + /* 0x1CD9 */ u8 unk1CD9; + /* 0x1CDA */ u16 unk1CDA; + /* 0x1CDC */ f32 unk1CDC; + /* 0x1CE0 */ f32 unk1CE0; + /* 0x1CE4 */ u32 unk1CE4; + /* 0x1CE8 */ u32 unk1CE8; + /* 0x1CEC */ f32 unk1CEC; + /* 0x1CF0 */ f32 unk1CF0; + /* 0x1CF4 */ f32 unk1CF4; + /* 0x1CF8 */ u16 unk1CF8; + /* 0x1CFA */ u16 unk1CFA; + /* 0x1CFC */ f32 unk1CFC; // mFluddSwitchTween + /* 0x1D00 */ f32 unk1D00; + /* 0x1D04 */ s16 unk1D04; + /* 0x1D06 */ s16 unk1D06; + /* 0x1D08 */ u32 unk1D08; + /* 0x1D0C */ TWaterEmitInfo* mEmitInfo; // TWaterEmitInfo + /* 0x1D10 */ TMirrorActor* unk1D10; + /* 0x1D14 */ TWaterGunParams mWatergunParams; +}; + +#endif diff --git a/include/Player/Yoshi.hpp b/include/Player/Yoshi.hpp new file mode 100644 index 00000000..47eb6894 --- /dev/null +++ b/include/Player/Yoshi.hpp @@ -0,0 +1,76 @@ +#ifndef YOSHI_HPP +#define YOSHI_HPP + +#include +#include +#include + +class TMario; + +class TYoshi { +public: + enum Color { GREEN, ORANGE, PURPLE, PINK }; + enum State { EGG = 0, DROWNING = 3, DYING = 4, UNMOUNTED = 6, MOUNTED = 8 }; + + bool appearFromEgg(const JGeometry::TVec3&); + void calcAnim(); + void changeAnimation(int id); + bool disappear(); + void doEat(u32 fruitID); + void doSearch(); + void entry(); + void getEmitPosDir(JGeometry::TVec3*, JGeometry::TVec3*) const; + J3DFrameCtrl* getFrameCtrl() const; + MtxPtr getMtxPtrFootL() const; + MtxPtr getMtxPtrFootR() const; + void getOff(bool knockedOff); + void init(TMario*); + void initInLoadAfter(); + void kill(); + void movement(); + bool onYoshi(); + void ride(); + void setEggYoshiPtr(void*); // TEggYoshi* + void thinkAnimation(); + void thinkBtp(int); + void thinkHoldOut(); + void thinkUpper(); + void viewCalc(); + + s8 mState; // 0x0000 + u16 mSubState; // 0x0002 ?? + u32 _01; // 0x0004 + s32 mMaxJuice; // 0x0008 + s32 mCurJuice; // 0x000C + TMario* mMario; // 0x0010 + u32 _02[0xC / 4]; // 0x0014 + JGeometry::TVec3 mTranslation; // 0x0020 + u32 _03[0x8 / 4]; // 0x002C + MActor* mActor; // 0x0034 + u32 _38; // 0x0038 + u16 mJoint; // 0x003c + u16 _3e; // 0x003e + u32 _04[0x44 / 4]; // 0x0040 + f32 mRedComponent; // 0x0084 + f32 mGreenComponent; // 0x0088 + f32 mBlueComponent; // 0x008C + u32 _05[0x28 / 4]; // 0x0090 + u8 mFlutterState; // 0x00B8 + u8 _06; // 0x00B9 + u16 mFlutterTimer; // 0x00BA + u16 mMaxFlutterTimer; // 0x00BC + u16 _07; // 0x00BE + f32 mMaxVSpdStartFlutter; // 0x00C0 + f32 mFlutterAcceleration; // 0x00C4 + u32 _08[0x8 / 4]; // 0x00C8 + s8 mType; // 0x00D0 + u8 _09; // 0x00D1 + u16 _10; // 0x00D2 + u32 _11[0x1C / 4]; // 0x00D4 + void* mEgg; // 0x00F0 + u32 _F4[0x30 / 4]; +}; + +extern JUtility::TColor bodyColor[4]; + +#endif diff --git a/include/System/MarioGamePad.hpp b/include/System/MarioGamePad.hpp index 403db2fe..f9daf517 100644 --- a/include/System/MarioGamePad.hpp +++ b/include/System/MarioGamePad.hpp @@ -25,8 +25,8 @@ struct TMarioControllerWork { /* 0x10 */ f32 mStickH; /* 0x14 */ f32 mStickV; /* 0x18 */ f32 mStickDist; - /* 0x1C */ f32 mAnalogL; - /* 0x20 */ f32 mAnalogR; + /* 0x1C */ f32 mAnalogR; + /* 0x20 */ f32 mAnalogL; }; class TMarioGamePad : public JUTGamePad { diff --git a/include/System/ParamInst.hpp b/include/System/ParamInst.hpp index 92bc2541..11ca6e48 100644 --- a/include/System/ParamInst.hpp +++ b/include/System/ParamInst.hpp @@ -31,7 +31,17 @@ template class TParamRT : public TParamT { { } - inline void set(T param) {}; + inline void set(T param) { value = param; }; + + // Fabricated + TParamRT& operator=(const TParamRT& other) + { + this->keyCode = other.keyCode; + this->name = other.name; + this->next = other.next; + this->value = other.value; + return *this; + } }; class TParamVec : public TParamT > { diff --git a/src/Map/BathWaterManager.cpp b/src/Map/BathWaterManager.cpp index 115b9bf8..229cacd5 100644 --- a/src/Map/BathWaterManager.cpp +++ b/src/Map/BathWaterManager.cpp @@ -21,7 +21,7 @@ static void draw_mist(u16 x, u16 y, u16 wd, u16 ht, void* buffer) f32 offset_x = (4.0f / f_wd); f32 offset_y = (2.0f / f_ht); - C_MTXOrtho(m, f_left, f_right, f_top, f_bottom, 0.0f, 1.0f); + C_MTXOrtho(m, f_top, f_bottom, f_left, f_right, 0.0f, 1.0f); PSMTXIdentity(e_m); GXSetTexCopySrc(x, y, wd, ht); GXSetCopyFilter(GX_FALSE, 0, GX_TRUE, vFilter); diff --git a/src/Player/WaterGun.cpp b/src/Player/WaterGun.cpp index e69de29b..4751df4c 100644 --- a/src/Player/WaterGun.cpp +++ b/src/Player/WaterGun.cpp @@ -0,0 +1,1370 @@ +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include +#include +#include + +extern size_t gpMarioAddress; + +TNozzleBmdData nozzleBmdData = { + { + { + 0, // _00 + 0, // _04 + nullptr, // mHelmetPath + "/mario/watergun2/normal_wg", // mPath + "/mario/watergun2/normal_wg/normal_wg.bmd", // mBmdPath + 1, // mNumEmitters + 2, // _15 + { + { 1, 0 }, + { 4, 0 }, + { 4, 0 }, + }, + }, + { + 0, // _00 + 0, // _04 + nullptr, // mHelmetPath + "/mario/watergun2/rocket_wg", // mPath + "/mario/watergun2/rocket_wg/rocket_wg.bmd", // mBmdPath + 1, // mNumEmitters + 2, // _15 + { + { 2, 1 }, + { 4, 0 }, + { 4, 0 }, + }, + }, + { + 0, // _00 + 0, // _04 + "/mario/bmd/wg_hel_diver.bmd", // mHelmetPath + "/mario/watergun2/hover_wg", // mPath + "/mario/watergun2/hover_wg/hover_wg.bmd", // mBmdPath + 2, // mNumEmitters + 0xc, // _15 + { + { 1, 0 }, + { 1, 0 }, + { 4, 0 }, + }, + }, + { + 0, // _00 + 0, // _04 + nullptr, // mHelmetPath + "/mario/watergun2/dummy_wg", // mPath + "/mario/watergun2/dummy_wg/dummy_wg.bmd", // mBmdPath + 1, // mNumEmitters + 2, // _15 + { + { 3, 0 }, + { 4, 0 }, + { 4, 0 }, + }, + }, + { + 0, // _00 + 0, // _04 + nullptr, // mHelmetPath + "/mario/watergun2/hover_wg", // mPath + "/mario/watergun2/hover_wg/hover_wg.bmd", // mBmdPath + 2, // mNumEmitters + 0xc, // _15 + { + { 1, 0 }, + { 1, 0 }, + { 4, 0 }, + }, + }, + { + 0, // _00 + 0, // _04 + nullptr, // mHelmetPath + "/mario/watergun2/back_wg", // mPath + "/mario/watergun2/back_wg/back_wg.bmd", // mBmdPath + 1, // mNumEmitters + 2, // _15 + { + { 1, 0 }, + { 4, 0 }, + { 4, 0 }, + }, + }, + }, +}; + +TWaterGun::TWaterGun(TMario* mario) + : mNozzleDeform("normal_wg", "/Mario/WaterGun/NozzleDeform.prm", this) + , mNozzleRocket(nullptr, "/Mario/WaterGun/NozzleTrgRocket.prm", this) + , mNozzleUnderWater("hover_wg", "/Mario/WaterGun/NozzleDiving.prm", this) + , mNozzleYoshiDeform("dummy_wg", "/Mario/WaterGun/NozzleYoshiMouth.prm", + this) + , mNozzleHover("hover_wg", "/Mario/WaterGun/NozzleTrgHover.prm", this) + , mNozzleTurbo("back_wg", "/Mario/WaterGun/NozzleTrgTurbo.prm", this) + , mWatergunParams("/Mario/WaterGun.prm") + , mMario(mario) +{ + mWatergunParams.load(mWatergunParams.mPrmPath); + mMario = mario; +} + +static bool NozzleCtrl(J3DNode* node, BOOL param_2) +{ + // TODO: Inlined stack space + if (!param_2) { + if (gpMarioForCallBack != nullptr) { + s16 gunAngle = gpMarioForCallBack->mWaterGun + ->mNozzleList[gpMarioForCallBack->mWaterGun + ->mCurrentNozzle] + ->getGunAngle(); + if (gunAngle < 0) { + Mtx mtx; + // Unused stack space + // volatile u32 unused2[6]; + MsMtxSetRotRPH(mtx, 0.0f, 0.0f, 0.005493164f * gunAngle); + MTXConcat(J3DSys::mCurrentMtx, mtx, J3DSys::mCurrentMtx); + } + } + } + return true; +} + +static bool RotateCtrl(J3DNode* node, BOOL param_2) +{ + if (!param_2 && gpMarioForCallBack != nullptr) { + s16 local1cd0 = gpMarioForCallBack->mWaterGun->unk1CD0; + Mtx mtx; + // Unused stack space + // volatile u32 unused2[7]; + MsMtxSetRotRPH(mtx, 0.005493164f * local1cd0, 0.0f, 0.0f); + MTXConcat(J3DSys::mCurrentMtx, mtx, J3DSys::mCurrentMtx); + } + return true; +} + +static bool WaterGunDivingCtrlL(J3DNode* node, BOOL param_2) +{ + if (!param_2) { + // This looks very weird to me, probably because of some inline? + // I could imagine some s32 getNozzleSpeedY() and + // s16 localXXX = -getNozzleSpeedY(); + s32 nozzleSpeedY = gpMarioForCallBack->mWaterGun->unk1CC8; + s16 neg = -nozzleSpeedY; + Mtx mtx; + // Unused stack space + // volatile u32 unused2[7]; + MsMtxSetRotRPH(mtx, 0.0f, 0.0f, 0.005493164f * neg); + MTXConcat(J3DSys::mCurrentMtx, mtx, J3DSys::mCurrentMtx); + } + return true; +} + +static bool WaterGunDivingCtrlR(J3DNode* node, BOOL param_2) +{ + if (!param_2) { + // This looks very weird to me, probably because of some inline? + // I could imagine some s32 getNozzleSpeedY() and + // s16 localXXX = -getNozzleSpeedY(); + s32 nozzleSpeedY = gpMarioForCallBack->mWaterGun->unk1CCC; + s16 neg = -nozzleSpeedY; + Mtx mtx; + // Unused stack space + // volatile u32 unused2[7]; + MsMtxSetRotRPH(mtx, 0.0f, 0.0f, 0.005493164f * neg); + MTXConcat(J3DSys::mCurrentMtx, mtx, J3DSys::mCurrentMtx); + } + return true; +} + +// TODO: Nozzle deform + +void TWaterGun::init() +{ + mFlags = 0; + mNozzleList[Spray] = &mNozzleDeform; + mNozzleList[Rocket] = &mNozzleRocket; + mNozzleList[Underwater] = &mNozzleUnderWater; + mNozzleList[Yoshi] = &mNozzleYoshiDeform; + mNozzleList[Hover] = &mNozzleHover; + mNozzleList[Turbo] = &mNozzleTurbo; + mCurrentNozzle = Spray; + mSecondNozzle = Hover; + mNozzleRocket.unk38C = 0x81b; + mNozzleTurbo.unk38C = 0x814; + mNozzleDeform.mBomb.unk38C = 0x813; + mCurrentWater = mNozzleList[mCurrentNozzle]->mEmitParams.mAmountMax.get(); + mIsEmitWater = false; + unk1C88 = 0.0f; + mCurrentPressure = 0; + mPreviousPressure = 0; + unk1CEC = 1.0f; + unk1CF0 = 0.1f; + unk1CF4 = 0.0049999999f; + unk1CF8 = 0x168; + unk1CFA = 0; + unk1CFC = 0.0f; + unk1D00 = 0.0f; + unk1D04 = 0; + unk1D06 = -0x1800; + unk1D08 = 0; + + // mEmitInfo = new TWaterEmitInfo; TODO + + unk1D08 = 0; + mNozzleDeform.mBomb.unk384 = true; + mNozzleYoshiDeform.mBomb.unk384 = true; + + mEmitPos[3].x = mMario->mPosition.x; + mEmitPos[3].y = mMario->mPosition.y; + mEmitPos[3].z = mMario->mPosition.z; + + unk1CC0 = 0; + unk1CC2 = 0; + unk1CC4 = 0; + + unk1CC8 = 0.0f; + unk1CD0 = 0; + unk1CD2 = 0; + + // This is definitely an inlined funciton. Creating a model seems quite + // useful + // TODO: Check if already exists + MActorAnmData* watergunAnmData = new MActorAnmData(); + watergunAnmData->init("/mario/watergun2/body", nullptr); + mFluddModel = new MActor(watergunAnmData); + + void* fluddModelData + = JKRFileLoader::getGlbResource("/mario/watergun2/body/wg_mdl1.bmd"); + J3DModel* fluddModel = new J3DModel( + J3DModelLoaderDataBase::load(fluddModelData, 0x10040000), 0, 1); + mFluddModel->setModel(fluddModel, 0); + + // Requires M3UModelMario at 0x3a8 in TMario + // Missing decompilation + // MTXCopy( + // mMario->mModelMario->unk8->mJointArray[mMario->mBindBoneIDArray[0]], + // mFluddModel->unk4->unk20); + + mFluddModel->unk4->initialize(); + + s32 handleIdx + = mFluddModel->unk4->mModelData->unkB0->getIndex("jnt_G_handle"); + + // unk1CDC is TMultiMtxEffect, but confused from implementation atm + + unk1CD8 = mFluddModel->unk4->mModelData->unkB0->getIndex("nozzle_center"); + + for (int i = 0; i < 6; ++i) { + if (!nozzleBmdData.getPath(i)) { + mNozzleList[i]->unk380 = nullptr; + continue; + } + + MActorAnmData* nozzleData = new MActorAnmData(); + nozzleData->init(nozzleBmdData.getPath(i), nullptr); + mNozzleList[i]->unk380 = new MActor(nozzleData); + + void* nozzleModelData + = JKRFileLoader::getGlbResource(nozzleBmdData.getBmdPath(i)); + J3DModel* nozzleModel = new J3DModel( + J3DModelLoaderDataBase::load(nozzleModelData, 0x10040000), 0, 1); + mNozzleList[i]->unk380->setModel(nozzleModel, 0); + + // TODO: Figure out + // ResTIMG* img = mFluddModel->unk4->mModelData->unkAC->getResTIMG(0); + // SMS_ChangeTextureAll(mNozzleList[i]->unk380->unk4->mModelData, + // "H_watergun_main_dummy", img); + + mNozzleList[i]->unk380->initDL(); + // Definitely inline potential + if (nozzleBmdData.getFlags(i, 0) != 4) { + s32 jointIdx + = mNozzleList[i]->unk380->unk4->mModelData->unkB0->getIndex( + "null_G_muzzle"); + nozzleBmdData.setJointIndex(i, 0, jointIdx); + } + if (nozzleBmdData.getFlags(i, 1) != 4) { + s32 jointIdx + = mNozzleList[i]->unk380->unk4->mModelData->unkB0->getIndex( + "null_G_muzzle2"); + nozzleBmdData.setJointIndex(i, 1, jointIdx); + } + if (nozzleBmdData.getFlags(i, 2) != 4) { + s32 jointIdx + = mNozzleList[i]->unk380->unk4->mModelData->unkB0->getIndex( + "null_G_muzzle3"); + nozzleBmdData.setJointIndex(i, 2, jointIdx); + } + } + + s32 jointIdx + = mNozzleList[Spray]->unk380->unk4->mModelData->unkB0->getIndex( + "chn_muzzle_l"); + // mNozzleList[Spray] + // ->unk380->unk4->mModelData->mJointNodePointer[jointIdx] + // ->mCallBack = functionPtr; + // 5 more of these + + // MTXCopy that requires M3UModelMario at 0x3a8 in TMario + + unk1D10 = new TMirrorActor("水鉄砲in鏡"); + unk1D10->init(mFluddModel->unk4, 4); + + // TODO: Definitely an inlined function + // Another function does the exact same thing + for (int i = 0; i < nozzleBmdData.getEmitterCount(mCurrentNozzle); ++i) { + MtxPtr emitMtx = getEmitMtx(i); + if (emitMtx != nullptr) { + mEmitPos[i].x = emitMtx[0][3]; + mEmitPos[i].y = emitMtx[1][3]; + mEmitPos[i].z = emitMtx[2][3]; + } + } + + // TODO: Continue +} + +void TWaterGun::calcAnimation(JDrama::TGraphics* graphics) +{ + // TODO: Inlined stack space + volatile u32 unused2[12]; + + gpMarioForCallBack = mMario; + J3DFrameCtrl* frameCtrl = mFluddModel->getFrameCtrl(MActor::ANM_TYPE_BCK); + if (mMario == nullptr) { + return; + } + + s32 var380 = mMario->unk380; + if ((var380 & 0x8000) != 0) { + var380 = 0; + } + + // Definitely wrong, possibly a swtich statement, but couldn't make that + // work either + if (var380 == 5) { + // Unused + } else if (var380 >= 5) { + // Unused + } else if (2 <= var380) { + } else { + if (var380 >= 0) { + } else { + if (unk1CEC == 0.0f) { + if (mMario->fabricatedActionInline()) { + mFluddModel->setBck("wg_fepmp"); + } else if (mMario->checkFlag(MARIO_FLAG_IN_SHALLOW_WATER + | MARIO_FLAG_IN_WATER)) { + mFluddModel->setBck("wg_swpmp"); + } else { + // TODO: Cast would be weird here, probably an inlined + // getter that converts to s32 + if ((s32)mMario->unk0FA != 0x33) { + mFluddModel->setBck("wg_hgpmp"); + } else { + mFluddModel->setBck("wg_pump"); + } + } + frameCtrl->setSpeed(0.0f); + frameCtrl->setFrame(mMario->getPumpFrame()); + unk1CFA = unk1CF8; + } else { + mFluddModel->setBck("wg_house"); + if ((0.0f < unk1CEC) + && (unk1CEC = unk1CEC - 0.1f, unk1CEC <= 0.0f)) { + unk1CEC = 0.0f; + } + frameCtrl->setSpeed(0.0f); + frameCtrl->setFrame(unk1CEC * frameCtrl->getEndFrame()); + } + return; + } + } + + if (unk1CFA == 0) { + if (unk1CEC < 1.0f) { + unk1CEC = unk1CEC + unk1CF4; + mFluddModel->setBck("wg_house"); + frameCtrl->setSpeed(0.0f); + frameCtrl->setFrame(unk1CEC * frameCtrl->getEndFrame()); + } else { + unk1CEC = 1.0f; + mFluddModel->setBck("wg_house"); + frameCtrl->setSpeed(0.0f); + frameCtrl->setFrame(unk1CEC * frameCtrl->getEndFrame()); + } + } else { + unk1CFA = unk1CFA - 1; + } +} + +// TODO: Do i really need to explcitly say this? +#pragma dont_inline on +MtxPtr TWaterGun::getEmitMtx(int jointIndex) +{ + volatile u32 unused2[24]; // TODO: A lot of stack space, possibly a lot of + // inlined functions. + MtxPtr result; + if (!mMario->onYoshi()) { + result = getYoshiMtx(); + } else { + // This entire block is likely an inlined function. + u8 currentNozzle = mCurrentNozzle; + s8 flag = nozzleBmdData.getFlags(currentNozzle, jointIndex); + if (flag < 3) { + return getCurrentNozzle()->unk380->unk4->getAnmMtx( + nozzleBmdData.getJointIndex(mCurrentNozzle, jointIndex)); + } else if (flag == 3) { + return getYoshiMtx(); + } + } + return result; +} +#pragma dont_inline off + +MtxPtr TWaterGun::getNozzleMtx() +{ + return mFluddModel->unk4->getAnmMtx(unk1CD8); +} + +void TWaterGun::initInLoadAfter() { } + +bool TWaterGun::isEmitting() { return false; } + +void TWaterGun::changeNozzle(TNozzleType nozzleType, bool animate) +{ + f32 usedWater = mCurrentWater + / mNozzleList[mCurrentNozzle]->mEmitParams.mAmountMax.get(); + if (nozzleType == Spray) { + if (animate) { + unk1CFC = 0.0f; + } + } else { + mSecondNozzle = nozzleType; + if (animate) { + unk1CFC = 1.0f; + } + } + mCurrentNozzle = nozzleType; + mNozzleList[mCurrentNozzle]->init(); + if (nozzleType == Yoshi) { + mCurrentWater = mMario->mYoshi->_11[0]; + } else { + mCurrentWater + = usedWater + * mNozzleList[mCurrentNozzle]->mEmitParams.mAmountMax.get(); + } +} + +void TWaterGun::movement() +{ + volatile u32 unused2[69]; // TODO: A lot of stack space, possibly a lot of + + bool canSpray; // Not sure if this is correct variable name + if (mCurrentWater == 0) { + canSpray = false; + } else { + s32 kind = getCurrentNozzle()->getNozzleKind(); + if (kind == 1) { + TNozzleTrigger* triggerNozzle + = (TNozzleTrigger*)mNozzleList[mCurrentNozzle]; + if (triggerNozzle->unk385 == TNozzleTrigger::ACTIVE) { + canSpray = true; + } else { + canSpray = false; + } + } else if (getCurrentNozzle()->unk378 > 0.0f) { + canSpray = true; + } else { + canSpray = false; + } + } + + if (!canSpray) { + unk1CC2 = 0; + unk1CC4 = 0; + } + + unk1CC8 += (unk1CC2 - unk1CC8) * mWatergunParams.mChangeSpeed.get(); + unk1CCC += (unk1CC4 - unk1CCC) * mWatergunParams.mChangeSpeed.get(); + + TNozzleBase* currentNozzle = getCurrentNozzle(); + + rotateProp(currentNozzle->unk378); + + // They do the same thing again?... This is the exact same code as + // rotateProp + if (mCurrentNozzle == 5) { + unk1CD2 += mNozzleList[mCurrentNozzle]->unk378 + * mWatergunParams.mNozzleAngleYSpeed.get(); + unk1CD2 *= mWatergunParams.mNozzleAngleYBrake.get(); + if (mWatergunParams.mHoverRotMax.get() < unk1CD2) { + unk1CD2 = mWatergunParams.mHoverRotMax.get(); + } + unk1CD0 = unk1CD0 + unk1CD2; + } else { + unk1CD2 = 0; + unk1CD0 = 0; + } + + // Yoshi nozzle + if (mCurrentNozzle == 3) { + mCurrentWater = getCurrentNozzle()->mEmitParams.mAmountMax.get(); + } + + if (SMS_isDivingMap()) { + mCurrentWater = getCurrentNozzle()->mEmitParams.mAmountMax.get(); + } + + if (mCurrentNozzle == 3) { + unk1CEC = 0.0f; + } + + // Nozzle swapping + if (unk1D00 != 0.0f) { + f32 unk = unk1CFC; + f32 sum = unk + unk1D00; + unk1CFC = sum; + if ((unk < 0.5f) && (0.5f <= sum)) { + u8 curNozzle = mCurrentNozzle; + s32 currentWater = mCurrentWater; + u8 secondNozzle = mSecondNozzle; + f32 maxWater = currentNozzle->mEmitParams.mAmountMax.get(); + f32 waterPercentage = currentWater / maxWater; + + if (secondNozzle != 0) { + mSecondNozzle = secondNozzle; + } + mCurrentNozzle = secondNozzle; + + currentNozzle = getCurrentNozzle(); + currentNozzle->init(); // TODO: 2 vtable entry + + if (secondNozzle == 3) { + mCurrentWater + = mMario->mYoshi->_11[0]; // TODO: Proper yoshi stuff + } else { + mCurrentWater = waterPercentage + * currentNozzle->mEmitParams.mAmountMax.get(); + } + } + if ((sum < 0.5f) && (0.5f <= unk)) { + f32 currentWater = (f32)mCurrentWater; + f32 maxWater = currentNozzle->mEmitParams.mAmountMax.get(); + f32 waterPercentage = currentWater / maxWater; + + mCurrentNozzle = 0; + + currentNozzle = getCurrentNozzle(); + currentNozzle->init(); // TODO: 2 vtable entry + + mCurrentWater + = waterPercentage * currentNozzle->mEmitParams.mAmountMax.get(); + } + + if (unk1CFC < 0.0) { + unk1CFC = 0.0f; + unk1D00 = 0.0f; + } + if (1.0f < unk1CFC) { + unk1CFC = 1.0f; + unk1D00 = 0.0f; + } + } + currentNozzle->animation(mCurrentNozzle); +} + +void TNozzleBase::emitCommon(int param_1, TWaterEmitInfo* param_2) +{ + param_2->mAlive.set( + gpModelWaterManager->mWaterParticleTypes[mEmitParams.mType.get()] + ->mAlive.get()); + + JGeometry::TVec3 pos; + JGeometry::TVec3 dir; + JGeometry::TVec3 speed; + mFludd->getEmitPosDirSpeed(param_1, &pos, &dir, &speed); + + // TODO: This feels wrong + // TODO: Fix asm + param_2->mPos.value = pos; + param_2->mV.value = speed; + param_2->mDir.value = dir; + + param_2->mDirTremble = mEmitParams.mDirTremble; + param_2->mPowTremble = mEmitParams.mPowTremble; + param_2->mSize = mEmitParams.mSize; + param_2->mSizeTremble = mEmitParams.mSizeTremble; + param_2->mType = mEmitParams.mType; + param_2->mHitRadius = mEmitParams.mHitRadius; + param_2->mHitHeight = mEmitParams.mHitHeight; +} + +void TNozzleBase::emit(int param_1) +{ + if (mFludd->mCurrentWater > 0 && unk378 != 0.0f) { + TWaterEmitInfo* emitInfo = mFludd->mEmitInfo; + emitCommon(param_1, emitInfo); + + unk37C = unk37C + mEmitParams.mNum.get(); + s32 local37cInt = (s32)unk37C; + if (local37cInt != 0) { + unk37C = unk37C - (f32)local37cInt; + emitInfo->mNum.set(local37cInt); + emitInfo->mAttack = mEmitParams.mAttack; + f32 emitCtrl = mEmitParams.mEmitCtrl.get(); + f32 emitPow = mEmitParams.mEmitPow.get(); + emitInfo->mPow.set(emitCtrl * emitPow * unk378 + + emitPow * (1.0f - emitCtrl)); + emitInfo->mFlag.set(0x40); + u16 flags = mFludd->mFlags; + u32 flagResult; + if ((flags & 2) != 0) { + flagResult = 1; + } else { + flagResult = 0; + } + if (flagResult != 0) { + emitInfo->mFlag.set(emitInfo->mFlag.get() | 0x80); + } + + int emittedWater = gpModelWaterManager->emitRequest(*emitInfo); + u32 emittedWaterU32 = (u32)emittedWater & 0xFF; + mFludd->mIsEmitWater = (u8)emittedWater; + f32* unk1C88Ptr = (f32*)&mFludd->unk1C88; + f32 unk1C88 = *unk1C88Ptr; + u8 currentNozzle = mFludd->mCurrentNozzle; + TNozzleBase** nozzleList = mFludd->mNozzleList; + TNozzleBase* currentNozzlePtr = nozzleList[currentNozzle]; + u32 unk1C88U32 = (u32)mFludd->unk1C88; + s16 decRate = currentNozzlePtr->mEmitParams.mDecRate.get(); + f32 emittedWaterF = (f32)emittedWaterU32; + f32 decRateF = (f32)decRate; + f32 unk1C88OldF = (f32)unk1C88U32; + f32 temp = emittedWaterF * decRateF; + f32 temp2 = temp / unk1C88OldF; + *unk1C88Ptr = 10.0f * temp2 + unk1C88; + if (emittedWaterU32 == 0) { + goto skip_velocity; + } + mFludd->mCurrentWater + -= emittedWaterU32 * mEmitParams.mDecRate.get(); + if (mFludd->mCurrentWater < 0) { + mFludd->mCurrentWater = 0; + } + + f32* powPtr = &emitInfo->mPow.value; + JGeometry::TVec3* dirPtr = &emitInfo->mDir.value; + f32 powVal = *powPtr; + s16 faceAngleY = mFludd->mMario->mFaceAngle.y; + f32 cosAngle = JMASCos(faceAngleY); + f32 sinAngle = JMASSin(faceAngleY); + f32 dirX = -dirPtr->x; + f32 dirZ = dirPtr->z; + f32 dirY = dirPtr->y; + f32 reactionPow = powVal * mEmitParams.mReactionPow.get(); + f32 reactionY = mEmitParams.mReactionY.get(); + f32 unkE0 = mEmitParams.mReactionPow.value; + f32 unkF4 = mEmitParams.mReactionY.value; + f32 f31 = powVal * unkE0; + + mFludd->mMario->addVelocity((dirX * sinAngle - dirZ * cosAngle) + * reactionPow); + + f32* velX = &mFludd->mMario->mVel.x; + *velX = -dirPtr->x * reactionPow - *velX; + f32* velZ = &mFludd->mMario->mVel.z; + *velZ = -dirPtr->z * reactionPow - *velZ; + f32* velY = &mFludd->mMario->mVel.y; + *velY = *velY - dirY * powVal * unkF4 * reactionY; + skip_velocity:; + } + } +} + +void TWaterGun::setBaseTRMtx(Mtx mtx) +{ + volatile u32 unused1[10]; + f32 initialAngle = mtx[1][0]; + if (initialAngle < 0.0f) { + initialAngle = -initialAngle; + } + + // Seemingly some adjustment of fluddpack angle + f32 baseAngle = unk1D06; + f32 angleDiff = unk1D04 - unk1D06; + + s16 angle = initialAngle * angleDiff + baseAngle; + + Mtx result; + Vec unused2; + MsMtxSetRotRPH(result, 0.0f, 0.0f, 0.005493164f * angle); + + MTXConcat(mtx, result, result); + MTXCopy(result, mFluddModel->unk4->unk20); +} + +// Not sure why this get's inlined aggressively +#pragma dont_inline on +TNozzleBase::TNozzleBase(const char* name, const char* prm, TWaterGun* fludd) + : mEmitParams(prm) + , mFludd(fludd) +{ + mEmitParams.load(mEmitParams.mPrmPath); + unk36C = 2; + unk36E = 0; + unk372 = 0; + unk378 = 0.0f; + unk37C = 0.0f; +} +#pragma dont_inline off + +void TNozzleBase::init() +{ + unk36C = 2; + unk36E = 0; + unk372 = 0; + unk378 = 0.0f; + unk37C = 0.0f; +} + +void TNozzleBase::calcGunAngle(const TMarioControllerWork& work) +{ + // volatile u32 unused1[17]; + if ((size_t)mFludd->mMario == gpMarioAddress + && (gpCamera->isLButtonCameraSpecifyMode(gpCamera->mMode) + || gpCamera->isJetCoaster1stCamera())) { + unk36E = gpCamera->unkA4; + return; + } + + s16 angle; + if (mFludd->mMario->mAction == 0xC008220) { + // TODO: Wrong reguster used, using r3 instead of r4 + angle = unk36E + + (s16)(mFludd->mMario->mGamePad->mCompSPos[0].y + * mEmitParams.mRButtonMult.get()); + } else { + angle = -mEmitParams.mLAngleBase.get(); + } + + if (angle < mEmitParams.mLAngleMin.get()) { + angle = mEmitParams.mLAngleMin.get(); + } + + if (angle > mEmitParams.mLAngleMax.get()) { + angle = mEmitParams.mLAngleMax.get(); + } + + f32 diff = angle - unk36E; + unk36E += diff * mEmitParams.mLAngleChase.get(); +} + +// TODO: This has a lot of inline functions, find them and update them +// properly +void TNozzleBase::animation(int param_1) +{ + if (param_1 != 2) { + return; + } + + if (0.0f < mFludd->unk1D00) { + unk36C = 4; + } + + if (mFludd->unk1D00 < 0.0f) { + unk36C = 3; + } + + switch (unk36C) { + case 0: { + + if (!unk380->checkCurBckFromIndex(4)) { + unk380->setBckFromIndex(4); + } + J3DFrameCtrl* ctrl = unk380->getFrameCtrl(MActor::ANM_TYPE_BCK); + if (ctrl->mCurrentFrame <= (ctrl->mEndFrame - 0.1) + && (ctrl->mFlags & 3) == 0) { + return; + } + unk36C = 1; + break; + } + case 1: { + + if (!unk380->checkCurBckFromIndex(2)) { + unk380->setBckFromIndex(2); + } + + TWaterGun* fludd = mFludd; + bool updateAnimation = false; + if (fludd->mCurrentWater == 0) { + updateAnimation = false; + } else { + u8 gameState = gpMarDirector->unk124; + if (gameState != 3 && gameState != 4) { + updateAnimation = true; + if (gameState != 1 && gameState != 2) { + updateAnimation = true; + } + + if (!updateAnimation) { + updateAnimation = true; + u32 nozzleKind = fludd->getCurrentNozzle()->getNozzleKind(); + if (nozzleKind == 1) { + TNozzleTrigger* trigger + = (TNozzleTrigger*)fludd->getCurrentNozzle(); + if (trigger->unk385 == TNozzleTrigger::ACTIVE) { + updateAnimation = true; + } else { + updateAnimation = false; + } + + } else if (fludd->getCurrentNozzle()->unk378 <= 0.0f) { + updateAnimation = false; + } else { + updateAnimation = true; + } + } + } + } + + if (updateAnimation) { + return; + } + + unk36C = 2; + break; + } + case 2: { + + if (!unk380->checkCurBckFromIndex(3)) { + unk380->setBckFromIndex(3); + } + TWaterGun* fludd = mFludd; + bool updateAnimation = false; + if (fludd->mCurrentWater == 0) { + updateAnimation = false; + } else { + u8 gameState = gpMarDirector->unk124; + if (gameState != 3 && gameState != 4) { + updateAnimation = true; + if (gameState != 1 && gameState != 2) { + updateAnimation = true; + } + + if (!updateAnimation) { + updateAnimation = true; + u32 nozzleKind = fludd->getCurrentNozzle()->getNozzleKind(); + if (nozzleKind == 1) { + TNozzleTrigger* trigger + = (TNozzleTrigger*)fludd->getCurrentNozzle(); + if (trigger->unk385 == TNozzleTrigger::ACTIVE) { + updateAnimation = true; + } else { + updateAnimation = false; + } + + } else if (fludd->getCurrentNozzle()->unk378 <= 0.0f) { + updateAnimation = false; + } else { + updateAnimation = true; + } + } + } + } + + if (updateAnimation) { + unk36C = 0; + } + break; + } + + case 3: { + + J3DFrameCtrl* ctrl = unk380->getFrameCtrl(MActor::ANM_TYPE_BCK); + if (!unk380->checkCurBckFromIndex(1)) { + unk380->setBckFromIndex(1); + } + + // Use external tween value + ctrl->mCurrentFrame = mFludd->unk1CFC * ctrl->mEndFrame; + ctrl->mSpeed = 0.0f; + break; + } + case 4: { + + J3DFrameCtrl* ctrl = unk380->getFrameCtrl(MActor::ANM_TYPE_BCK); + if (!unk380->checkCurBckFromIndex(0)) { + unk380->setBckFromIndex(0); + } + + // Use external tween value + ctrl->mCurrentFrame = mFludd->unk1CFC * ctrl->mEndFrame; + ctrl->mSpeed = 0.0f; + + if (mFludd->unk1CFC < 1.0f) { + return; + } + unk36C = 0; + break; + } + } +} + +void TNozzleTrigger::init() +{ + unk384 = false; + unk385 = 0; + unk36C = 0; + unk386 = 0; + unk388 = 0.0f; +} + +void TNozzleTrigger::movement(const TMarioControllerWork& controllerWork) +{ + // TODO: Missing stack space + volatile u32 unused[54]; + + if (mFludd->mCurrentWater <= 0) { + unk385 = TNozzleTrigger::INACTIVE; + unk386 = 0; + unk388 = 0.0f; + return; + } + + if (unk385 == TNozzleTrigger::ACTIVE) { + unk386 -= 1; + + // Very likely an inline + bool check; + if (mFludd->mMario->unk380 == 0) { + check = true; + } else { + check = false; + } + if (!check || unk386 <= 0) { + unk385 = TNozzleTrigger::DEAD; + unk388 = 0.0f; + unk386 = 0; + } + } + // Spam spray sound? + if ((unk384 == true + && (controllerWork.mFrameInput & TMarioControllerWork::A) != 0 + && (controllerWork.mInput & TMarioControllerWork::R) != 0) + && unk385 == TNozzleTrigger::INACTIVE) { + unk385 = TNozzleTrigger::ACTIVE; + if (unk38C != 0xffffffff) { + u32 soundId; + if (unk378 < 1.0f) { + soundId = 0x806; + } else { + soundId = 0x805; + } + bool canPlay = gpMSound->gateCheck(soundId); + if (canPlay) { + MSoundSESystem::MSoundSE::startSoundActor( + soundId, mFludd->mEmitPos[0], 0, nullptr, 0, 4); + } + } + unk386 = mEmitParams.mTriggerTime.get(); + } + + TMario* mario = mFludd->mMario; + + // Most likely some inlined stuff, not matching + bool canSpray; + bool other = true; + if (mario->unk380 == 0) { + canSpray = true; + } else { + canSpray = false; + } + if ((mario->unk118 & 0x30000) == 0 + && mFludd->mCurrentWater < mEmitParams.mAmountMax.get()) { + canSpray = false; + } + + if (other && canSpray == true) { + unk388 += 150.0f * controllerWork.mAnalogR; + if (!unk384 && unk385 == TNozzleTrigger::INACTIVE) { + // Pretty certain there is some inline function shenanigans here + // Also what? + // if(gpMarDirector->unk58 == (gpMarDirector->unk58 / mario->unk568) + // * mario->unk568) { + // SMSRumbleMgr->start((int)0x14, (int)mario->unk564, + // (f32*)nullptr); + //} + } + if (unk384 && unk385 == TNozzleTrigger::INACTIVE + && controllerWork.mAnalogR > 0.0f) { + bool canPlay = gpMSound->gateCheck(0x4022); + if (canPlay) { + MSoundSESystem::MSoundSE::startSoundActor( + 0x4022, mFludd->mEmitPos[0], 0, nullptr, 0, 4); + } + } + } + unk388 -= mEmitParams.mInsidePressureDec.get(); + if (unk388 < 0.0f) { + unk388 = 0.0f; + } + + if (unk388 > mEmitParams.mInsidePressureMax.get()) { + unk388 = mEmitParams.mInsidePressureMax.get(); + if (!unk384 && unk385 == TNozzleTrigger::INACTIVE) { + unk385 = TNozzleTrigger::ACTIVE; + unk386 = mEmitParams.mTriggerTime.get(); + u32 soundId = unk38C; + if (soundId != 0xffffffff) { + // Non matching: Produces mr r4, r29 instead of addi r4, r29, 0 + const Vec* soundPos = (Vec*)(&mFludd->mEmitPos[0]); + bool canPlay = gpMSound->gateCheck(soundId); + if (canPlay) { + MSoundSESystem::MSoundSE::startSoundActor(soundId, soundPos, + 0, nullptr, 0, 4); + } + } + if (mFludd->mCurrentNozzle == (s8)TWaterGun::Hover) { + SMSRumbleMgr->start((int)0x15, 0x8, (f32*)nullptr); + } + if (mFludd->mCurrentNozzle == (s8)TWaterGun::Rocket + || mFludd->mCurrentNozzle == (s8)TWaterGun::Turbo) { + SMSRumbleMgr->start((int)0x15, 0x14, (f32*)nullptr); + } + } + } + + if (unk385 == TNozzleTrigger::DEAD) { + unk388 = 0.0f; + if (controllerWork.mAnalogR == 0.0f) { + unk385 = TNozzleTrigger::INACTIVE; + } + } + + calcGunAngle(controllerWork); +} + +void TNozzleBase::movement(const TMarioControllerWork& controllerWork) +{ + // TODO: Missing stack space + volatile u32 unused2[2]; + + if (mFludd->mCurrentWater <= 0) { + return; + } + s32 var1 = 256.0f * controllerWork.mAnalogR * 150.0f; + + if (var1 > unk372) { + unk378 = (var1 - unk372) * 0.000015258789f; + unk374 = unk378; + unk372 = unk372 + mEmitParams.mTriggerRate.get(); + if (var1 < unk372) { + unk372 = var1; + } + } else { + unk378 = 0.0f; + unk372 = var1; + } + calcGunAngle(controllerWork); +} + +void TWaterGun::perform(u32 flags, JDrama::TGraphics* graphics) +{ + // TODO: Missing stack space + // volatile u32 unused2[24]; + + if ((flags & 0x1) != 0) { + if ((mFlags & 0x10) != 0) { + mCurrentWater = 0; + } + movement(); + } + + if ((flags & 0x2) != 0) { + calcAnimation(graphics); + } + + mFluddModel->perform(flags, graphics); + + if ((flags & 0x2) != 0) { + MActor* p2 = getCurrentNozzle()->unk380; + if (p2 != nullptr) { + MTXCopy(getModel()->getAnmMtx(unk1CD8), p2->unk4->unk20); + } + + for (s32 index = 0; + index < nozzleBmdData.getEmitterCount(mCurrentNozzle); index++) { + MtxPtr p1 = getEmitMtx(index); + if (p1 != nullptr) { + mEmitPos[index].x = p1[0][3]; + mEmitPos[index].y = p1[1][3]; + mEmitPos[index].z = p1[2][3]; + } + } + } + + if (getCurrentNozzle()->unk380) { + getCurrentNozzle()->unk380->perform(flags, graphics); + } +} + +TNozzleBase* TWaterGun::getCurrentNozzle() const +{ + return mNozzleList[mCurrentNozzle]; +} + +void TWaterGun::setAmountToRate(f32 rate) +{ + // volatile u32 unused2[7]; // TODO: possibly inlined function + if (mCurrentNozzle == 3) { + TNozzleBase* currentNozzle = getCurrentNozzle(); + s32 amountMax = currentNozzle->mEmitParams.mAmountMax.get(); + mCurrentWater = amountMax; + } else { + TNozzleBase* currentNozzle = getCurrentNozzle(); + mCurrentWater = rate * currentNozzle->mEmitParams.mAmountMax.get(); + } +} + +bool TWaterGun::isPressureOn() +{ + // volatile u32 unused2[6]; + if (getCurrentNozzle()->getNozzleKind() == 1) { + TNozzleTrigger* triggerNozzle = (TNozzleTrigger*)getCurrentNozzle(); + if (triggerNozzle->unk388 > 0.0f) { + return true; + } + } + return false; +} + +f32 TWaterGun::getPressure() +{ + // TODO: Missing stack space + // volatile u32 unused2[5]; + if (getCurrentNozzle()->getNozzleKind() == 1) { + TNozzleTrigger* triggerNozzle = (TNozzleTrigger*)getCurrentNozzle(); + return triggerNozzle->unk388; + } + return 0.0f; +} + +f32 TWaterGun::getPressureMax() +{ + // TODO: Missing stack space + // volatile u32 unused2[6]; + + if (getCurrentNozzle()->getNozzleKind() == 1) { + return getCurrentNozzle()->mEmitParams.mInsidePressureMax.get(); + } + + return 0.0f; +} + +// TODO: Figure out why inline happens +#pragma dont_inline on +void TWaterGun::getEmitPosDirSpeed(int index, JGeometry::TVec3* pos, + JGeometry::TVec3* dir, + JGeometry::TVec3* speed) +{ + // TODO: Fix unused stack space + // volatile u32 unused2[6]; + + MtxPtr nozzleEmitMtx = getEmitMtx(index); + pos->set(mEmitPos[index]); + + if (nozzleEmitMtx != nullptr) { + dir->x = nozzleEmitMtx[0][0]; + dir->y = nozzleEmitMtx[1][0]; + dir->z = nozzleEmitMtx[2][0]; + } else { + dir->set(0.0f, 0.0f, 1.0f); + } + + speed->x = mMario->mVel.x * 0.125f; + speed->y = 0.0f; + speed->z = mMario->mVel.z * 0.125f; +} +#pragma dont_inline off + +void TWaterGun::rotateProp(f32 rotation) +{ + if (mCurrentNozzle == 5) { + unk1CD2 += rotation * mWatergunParams.mNozzleAngleYSpeed.get(); + unk1CD2 *= mWatergunParams.mNozzleAngleYBrake.get(); + if (mWatergunParams.mHoverRotMax.get() < unk1CD2) { + unk1CD2 = mWatergunParams.mHoverRotMax.get(); + } + unk1CD0 = unk1CD0 + unk1CD2; + } else { + unk1CD2 = 0; + unk1CD0 = 0; + } +} + +void TWaterGun::triggerPressureMovement( + const TMarioControllerWork& controllerWork) +{ + mCurrentPressure = controllerWork.mAnalogR * 150.0f; + + TNozzleBase* currentNozzle = getCurrentNozzle(); + currentNozzle->movement(controllerWork); + + if (mCurrentPressure > mPreviousPressure) { + mPreviousPressure = mCurrentPressure; + } else if (mPreviousPressure != 0) { + mPreviousPressure -= 1; + } else { + mPreviousPressure = 0; + } +} +void TWaterGun::emit() +{ + // TODO: Missing stack space + // volatile u32 unused1[25]; + + // TODO: Another possible inline to check if emit is possible + if (!mMario->checkFlag(MARIO_FLAG_HELMET_FLW_CAMERA) + && mMario->checkFlag(MARIO_FLAG_IN_SHALLOW_WATER + | MARIO_FLAG_IN_WATER)) { + // I can imagine this also being an inline function that checks + // if the emit point is below the water height, but i will leave + // it for now. TODO. + MtxPtr nozzleEmitMtx; + if ((nozzleEmitMtx = getEmitMtx(0)) != nullptr) { + if (nozzleEmitMtx[1][3] < mMario->mFloorPosition.z + 20.0f) { + return; + } + } + } + + if (!mMario->onYoshi()) { + if (unk1CEC > 0.0f) { + return; + } + } + + // TODO: Probably an enum + // TODO: Probably inline function? + if (hasFlag(0x4)) { + mFlags &= ~0x4; + return; + } + + u8 currentNozzleType = mCurrentNozzle; + TNozzleBase* currentNozzle = getNozzle(currentNozzleType); + for (int i = 0; i < nozzleBmdData.getEmitterCount(currentNozzleType); ++i) { + currentNozzle->emit(i); + } + if (mCurrentWater > 0) { + switch (currentNozzleType) { + case Spray: { + JGeometry::TVec3* emitPos = &mEmitPos[0]; + playSoundWithInfo(0x24, emitPos, 0, getCurrentNozzle()->unk374); + } + case Yoshi: + case Turbo: { + JGeometry::TVec3* emitPos = &mEmitPos[0]; + playSoundWithInfo(0x0, emitPos, 0, getCurrentNozzle()->unk378); + break; + } + case Underwater: { + JGeometry::TVec3* emitPos = &mEmitPos[0]; + if (gpMSound->gateCheck(0x18)) { + MSoundSESystem::MSoundSE::startSoundActor(0x18, emitPos, 0, + nullptr, 0, 4); + } + } break; + case Rocket: + break; + case Hover: + if (mIsEmitWater) { + JGeometry::TVec3* emitPos = &mEmitPos[0]; + if (gpMSound->gateCheck(0x18)) { + MSoundSESystem::MSoundSE::startSoundActor(0x18, emitPos, 0, + nullptr, 0, 4); + } + } + break; + } + } +} +bool TWaterGun::suck() +{ + // TODO: Missing stack space + // volatile u32 unused1[7]; + if (mCurrentNozzle == (s8)Yoshi) { + return false; + } else { + s32 suckRate = getSuckRate(); + if (suckRate > 0) { + mCurrentWater += suckRate; + + s32 currentWater = mCurrentWater; + s32 maxWater = getCurrentNozzle()->mEmitParams.mAmountMax.get(); + if (currentWater > maxWater) { + mCurrentWater = maxWater; + } + + if (!(mCurrentWater + >= getCurrentNozzle()->mEmitParams.mAmountMax.get())) { + JGeometry::TVec3* emitPos = &mEmitPos[0]; + MSound* sound = gpMSound; + if (sound->gateCheck(0xf)) { + MSoundSESystem::MSoundSE::startSoundActor(0xf, emitPos, 0, + nullptr, 0, 4); + } + } + return true; + } + } + return false; +} + +bool TWaterGun::damage() +{ + if (hasWater()) { + TNozzleBase* nozzle = getCurrentNozzle(); + + mCurrentWater -= nozzle->mEmitParams.mDamageLoss.value; + + if (mCurrentWater < 0) { + mCurrentWater = 0; + } + return true; + } + return false; +} + +void TWaterGun::changeBackup() +{ + // TODO: Missing stack space + // volatile u32 unused2[5]; + if (unk1CFC == 0.0f) { + if (gpMSound->gateCheck(0x812)) { + MSoundSESystem::MSoundSE::startSoundSystemSE(0x812, 0, nullptr, 0); + } + unk1D00 = mWatergunParams.mChangeSpeed.get(); + } + + if (unk1CFC == 1.0f) { + if (gpMSound->gateCheck(0x811)) { + MSoundSESystem::MSoundSE::startSoundSystemSE(0x811, 0, nullptr, 0); + } + unk1D00 = -mWatergunParams.mChangeSpeed.get(); + } +} diff --git a/src/System/Params.cpp b/src/System/Params.cpp index a5323bb2..4cca84c2 100644 --- a/src/System/Params.cpp +++ b/src/System/Params.cpp @@ -53,7 +53,7 @@ void TParams::init() void TParams::load(JSUMemoryInputStream& stream) { - if (this->mHead != nullptr) { + if (mHead != nullptr) { s32 length = stream.readS32(); for (int i = 0; i < length; i++) { u16 keyCode = stream.read16b(); @@ -61,7 +61,7 @@ void TParams::load(JSUMemoryInputStream& stream) stream.readString(buffer, 0x50); TBaseParam* param; - for (param = this->mHead; param != nullptr; param = param->next) { + for (param = mHead; param != nullptr; param = param->next) { if (keyCode == param->keyCode && !strcmp(buffer, param->name)) { param->load(stream); break;