diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6f42c3d0..f5f5296e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -65,7 +65,7 @@ jobs: run: python configure.py && ninja - name: Run progress script - run: python progress.py --verify-obj --verify-bin --progress-summary + run: python progress.py --verify-bin --progress-summary - name: Run DTK and objdiff to generate progress file for decomp.dev run: | diff --git a/include/constants/game_constants.h b/include/constants/game_constants.h index c715c3fb..3422ad8d 100644 --- a/include/constants/game_constants.h +++ b/include/constants/game_constants.h @@ -48,10 +48,15 @@ enum DIRECTION_e { DIR_RIGHT }; +enum DIRECTION_LR_e { + DIR_LR_R, + DIR_LR_L +}; + enum LAYER_e { LAYER_1, LAYER_2, - LAYER_0, + LAYER_0 }; enum PATH_DIRECTION_e { diff --git a/include/constants/sound_list.h b/include/constants/sound_list.h index 2390cd48..0a17b7e7 100644 --- a/include/constants/sound_list.h +++ b/include/constants/sound_list.h @@ -3,6 +3,7 @@ /// @brief The identifiers for each sound effect/music track. /// @ingroup constants +/// @unofficial enum SOUND_e { SE_NULL = -1, SE_DEMO_OP_DUMMY_U, @@ -1985,3 +1986,80 @@ enum SOUND_e { SE_GAKKI_L_2_ON, SOUND_COUNT }; + +/// @brief Player voice sound IDs +/// @ingroup constants +/// @unofficial +enum VOICE_e { + VOICE_PLAYER_JOIN, + VOICE_PJ_JUMP, + VOICE_PJ_SPIN_JUMP, + VOICE_PLAYER_DECIDE, + VOICE_CS_FALL_INTO_MAP, + VOICE_CS_COURSE_IN, + VOICE_CS_COURSE_IN_MULTI, + VOICE_CS_COURSE_IN_HARD, + VOICE_CS_COURSE_MISS, + VOICE_CS_JUMP, + VOICE_CS_DECIDE_JOIN, + VOICE_CS_ENCOUNT, + VOICE_CS_SHOVED, + VOICE_CS_CHASE_SHIP, + VOICE_CS_NOTICE_JR, + VOICE_GAME_OVER, + VOICE_CONTINUE, + VOICE_CONTINUE_COURSE, + VOICE_MOTIAGE, + VOICE_NAGERU, + VOICE_MOTIAGE_PLAYER, + VOICE_JUMP_2ND, + VOICE_JUMP_3RD, + VOICE_YOSHI_JUMP, + VOICE_JR_A_BATTLE_APP, + VOICE_WALL_KICK, + VOICE_PRPL_JUMP, + VOICE_PNGN_SLIDE, + VOICE_ROPE_CATCH, + VOICE_ROPE_RELEASE, + VOICE_ROPE_FALL, + VOICE_GOAL_POLE_CATCH, + VOICE_CLIFF_DIVE, + VOICE_CLIFF_UP, + VOICE_CLIFF_DOWN, + VOICE_CANNON_SHOT_S, + VOICE_CANNON_SHOT, + VOICE_BALLOON_HELP, + VOICE_BALLOON_HELP_2, + VOICE_HUKKATSU, + VOICE_DAMAGE_LAST, + VOICE_DAMAGE_LAST_2, + VOICE_TIMEUP, + VOICE_TIMEUP_MULTI, + VOICE_SCROLL_OUT, + VOICE_DAMAGE_FIRE, + VOICE_DAMAGE_FREEZE, + VOICE_DAMAGE_POISON, + VOICE_DAMAGE_ELEC, + VOICE_DAMAGE_EATEN, + VOICE_INTO_SANDPILLAR, + VOICE_QUAKE, + VOICE_STOMPED, + VOICE_HIP_ATTACKED, + VOICE_TYUKAN, + VOICE_GET_STAR, + VOICE_ITEM_COMPLETE, + VOICE_CLEAR_NORMAL, + VOICE_CLEAR_ANOTHER, + VOICE_CLEAR_MULTI, + VOICE_CLEAR_HELPED, + VOICE_CLEAR_BOSS, + VOICE_CLEAR_LAST_BOSS, + VOICE_SAVE_PRINCESS, + VOICE_CS_COMPLETE_DEMO, + VOICE_GET_PRIZE, + VOICE_FLOOR_FALL, + VOICE_NOTICE, + VOICE_MISS_PRINCESS, + VOICE_ACTIVE_TV, + VOICE_ACTIVE_RC +}; diff --git a/include/game/bases/d_a_en_door.hpp b/include/game/bases/d_a_en_door.hpp new file mode 100644 index 00000000..7b5cf914 --- /dev/null +++ b/include/game/bases/d_a_en_door.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include + +class daEnDoor_c : public dEn_c { +public: + virtual bool isClosed(); + virtual bool isDummyOpen(); + virtual void createMdl(); + virtual void initAnm(); + virtual void initCcData(); + virtual void initialize(); + virtual void waitProc(); + virtual void setOpenAnm(); + virtual void setOpenSE(); + virtual void setCloseAnm(); + virtual void setCloseSE(); + virtual void setCloseMoveSE(); + virtual void setWaitAnm(); + + u8 mPad[0xa8]; + int m_5cc; + int m_5d0; + int m_5d4; +}; diff --git a/include/game/bases/d_a_fireball_player.hpp b/include/game/bases/d_a_fireball_player.hpp new file mode 100644 index 00000000..95987fa6 --- /dev/null +++ b/include/game/bases/d_a_fireball_player.hpp @@ -0,0 +1,6 @@ +#pragma once + +class daFireBall_Player_c { +public: + static bool CheckFireBallLimit(int playerNo, int limitMode); +}; diff --git a/include/game/bases/d_a_player.hpp b/include/game/bases/d_a_player.hpp index 3b6532a1..4ff9c806 100644 --- a/include/game/bases/d_a_player.hpp +++ b/include/game/bases/d_a_player.hpp @@ -1,24 +1,873 @@ #pragma once #include +#include +#include +#include +#include +class daYoshi_c; + +/** + * @brief The player class for Mario, Luigi and the Toads. + * @statetable + */ class dAcPy_c : public daPlBase_c { public: + /// @unofficial + enum SpinHipAttackSubstate_e { + SPIN_HIP_ATTACK_ACTION_0, + SPIN_HIP_ATTACK_ACTION_1 + }; + + /// @unofficial + enum FallSubstate_e { + FALL_ACTION_0, + FALL_ACTION_1 + }; + + /// @unofficial + enum JumpSubstate_e { + JUMP_TAKE_OFF, + JUMP_AIR + }; + + /// @unofficial + enum LandSubstate_e { + LAND_ACTION_0, + LAND_ACTION_1 + }; + + /// @unofficial + enum SpinJumpSubstate_e { + SPIN_JUMP_ACTION_0, + SPIN_JUMP_ACTION_1 + }; + + /// @unofficial + enum SitJumpSubstate_e { + SIT_JUMP_ACTION_0, + SIT_JUMP_ACTION_1 + }; + + /// @unofficial + enum CannonJumpSubstate_e { + CANNON_JUMP_ACTION_0, + CANNON_JUMP_ACTION_1, + CANNON_JUMP_ACTION_2 + }; + + /// @unofficial + enum BlockJumpSubstate_e { + BLOCK_JUMP_ACTION_0, + BLOCK_JUMP_ACTION_1 + }; + + /// @unofficial + enum RollSlipSubstate_e { + ROLL_SLIP_ACTION_0, + ROLL_SLIP_ACTION_1, + ROLL_SLIP_ACTION_2 + }; + + /// @unofficial + enum PenguinSlideSubstate_e { + PENGUIN_SLIDE_ACTION_0, + PENGUIN_SLIDE_ACTION_1, + PENGUIN_SLIDE_ACTION_2 + }; + + /// @unofficial + enum CrouchSubstate_e { + CROUCH_GROUND, + CROUCH_WATER + }; + + /// @unofficial + enum ThrowSubstate_e { + THROW_ACTION_0, + THROW_ACTION_1, + THROW_ACTION_2 + }; + + /// @unofficial + enum SwimSubstate_e { + SWIM_ACTION_0, + SWIM_ACTION_1, + SWIM_ACTION_2, + SWIM_ACTION_3 + }; + + /// @unofficial + enum VineSubstate_e { + VINE_ACTION_IVY, + VINE_ACTION_NET, + VINE_ACTION_ATTACK, + VINE_ACTION_ROLL + }; + + /// @unofficial + enum HangSubstate_e { + HANG_ACTION_START, + HANG_ACTION_WAIT, + HANG_ACTION_MOVE + }; + + /// @unofficial + enum KaniSubstate_e { + KANI_ACTION_WALK, + KANI_ACTION_HANG_INIT, + KANI_ACTION_JUMP_HANG_INIT, + KANI_ACTION_HANG, + KANI_ACTION_HANG_FALL, + KANI_ACTION_HANG_UP, + KANI_ACTION_HANG_UP_VINE + }; + + /// @unofficial + enum RopeSwingState_e { + ROPE_SWING_0, + ROPE_SWING_1, + ROPE_SWING_2, + ROPE_SWING_3, + ROPE_SWING_4, + ROPE_SWING_5, + ROPE_SWING_6, + ROPE_SWING_7, + ROPE_SWING_8, + ROPE_SWING_9, + ROPE_SWING_10 + }; + + /// @unofficial + enum DemoOutDoorState_e { + DEMO_OUT_DOOR_OPEN_DOOR, + DEMO_OUT_DOOR_MOVE_CENTER, + DEMO_OUT_DOOR_MOVE_INTER, + DEMO_OUT_DOOR_WAIT_CLOSE, + DEMO_OUT_DOOR_WAIT_ENTER, + DEMO_OUT_DOOR_FINISHED + }; + + enum QuakeMode_e { + QUAKE_MODE_0 + }; + + struct GlobalData_t { + float f1, f2, mSandSinkRate, f4, f5, f6, f7, f8; + mVec3_c mPos[3]; + float mThrowSpeed1; + float mThrowSpeed2; + float mThrowSpeedMax; + float mSpitRelated[4]; + float mVineSpeedRelated[4]; + float mKaniSpeedRelated[4]; + }; + + dAcPy_c(); + virtual ~dAcPy_c(); + + virtual int create(); + virtual int preExecute(); + virtual void postExecute(MAIN_STATE_e status); + virtual int doDelete(); + virtual int draw(); + + virtual bool isSpinLiftUpEnable(); + virtual void setSpinLiftUpActor(dActor_c *carryingActor); + + virtual void setEatTongue(dActor_c *eatingActor); + virtual void setEatTongueOff(dActor_c *eatingActor); + virtual void setEatMouth(dActor_c *eatingActor); + virtual bool setEatSpitOut(dActor_c *eatingActor); + virtual void eatMove(dActor_c *eatingActor); + + virtual void executeMain(); + virtual void executeLastPlayer(); + virtual void executeLastAll(); + virtual bool isItemKinopio(); + virtual void setPowerup(PLAYER_POWERUP_e, int); + virtual u8 getTallType(s8); + virtual const sBcPointData *getHeadBgPointData() { return &getBgPointData()->mHead; } + virtual const sBcPointData *getWallBgPointData() { return &getBgPointData()->mWall; } + virtual const sBcPointData *getFootBgPointData() { return &getBgPointData()->mFoot; } + virtual float getStandHeadBgPointY(); + virtual void checkBgCrossSub(); + virtual void postBgCross(); + virtual float getSandSinkRate(); + virtual bool setPressBgDamage(int, int); + virtual bool setBalloonInDispOut(int); + virtual bool isChange(); + virtual bool isEnableDokanInStatus(); + virtual bool setHideNotGoalPlayer(); + virtual int setDemoGoal(mVec3_c &landPos, float goalCastleX, u8 goalType); + virtual bool setDemoCannonWarp(int, short, short); + + STATE_VIRTUAL_FUNC_DECLARE(dAcPy_c, DemoStartWait); + STATE_VIRTUAL_FUNC_DECLARE(dAcPy_c, DemoDown); + + virtual void initialDoor(); + virtual void initialVine(); + virtual void initialJumpRight(); + virtual void initialJumpLeft(); + virtual void initialSwim(); + virtual void initialBlockJump(); + virtual void initialBlockJumpBelow(); + + virtual void setCreateAction(int); + virtual bool setTimeOverDemo(); + virtual void setFallDownDemo(); + virtual bool setDokanIn(DokanDir_e dir); + virtual void initDemoOutDokan(); + virtual bool updateDemoKimePose(ClearType_e clearType); + virtual void initDemoGoalBase(); + virtual void executeDemoGoal_Run(); + virtual void initializeDemoControl(); + + STATE_VIRTUAL_FUNC_DECLARE(dAcPy_c, Walk); + STATE_VIRTUAL_FUNC_DECLARE(dAcPy_c, Jump); + STATE_VIRTUAL_FUNC_DECLARE(dAcPy_c, Fall); + STATE_VIRTUAL_FUNC_DECLARE(dAcPy_c, Land); + STATE_VIRTUAL_FUNC_DECLARE(dAcPy_c, Crouch); + STATE_VIRTUAL_FUNC_DECLARE(dAcPy_c, SitJump); + STATE_VIRTUAL_FUNC_DECLARE(dAcPy_c, Slip); + STATE_VIRTUAL_FUNC_DECLARE(dAcPy_c, Turn); + STATE_VIRTUAL_FUNC_DECLARE(dAcPy_c, HipAttack); + STATE_VIRTUAL_FUNC_DECLARE(dAcPy_c, Swim); + STATE_VIRTUAL_FUNC_DECLARE(dAcPy_c, Kani); + STATE_VIRTUAL_FUNC_DECLARE(dAcPy_c, Cloud); + + virtual bool isWaitFrameCountMax(); + virtual bool checkWalkNextAction(); + virtual void setWaitActionAnm(AnmBlend_e); + virtual void setWalkActionAnm(AnmBlend_e); + virtual void walkActionInit_Wait(AnmBlend_e); + virtual void walkAction_Wait(); + virtual void walkActionInit_Move(AnmBlend_e); + virtual void walkAction_Move(); + virtual bool checkCrouch(); + virtual bool setCancelCrouch(); + virtual void setSlipAction(); + virtual void slipActionMove(int); + virtual void setHipAttack_AttackStart(); + + virtual float getCloudOffsetY(); + virtual bool setRideJrCrown(const dActor_c *); + virtual bool isRideJrCrownOwn(const dActor_c *); + virtual void setRideJrCrownMtx(const mMtx_c *); + virtual void setRideJrCrownAnm(int); + + virtual const mVec3_c *getHeadTopPosP(); + virtual const float *getGravityData(); + virtual bool isCarry() const { return mCarryActorID != BASE_ID_NULL; } + virtual bool isLiftUp(); + virtual bool isLiftUpExceptMame(); + + virtual void setStar(daPlBase_c::StarSet_e, int); + virtual void endStar(); + virtual void setVirusStar(daPlBase_c *); + + virtual bool isNoDamage(); + virtual bool setDamage(dActor_c *, DamageType_e); + virtual bool setForcedDamage(dActor_c *, DamageType_e); + virtual bool setJump(float jumpSpeed, float speedF, bool allowSteer, int keyMode, int jumpMode); + virtual bool _setJump(float jumpSpeed, float speedF, bool allowSteer, int keyMode, int jumpMode); + + virtual bool setHipAttackOnEnemy(mVec3_c *hitPos); + + virtual void clearJumpActionInfo(int); + virtual bool setSwimSpeed(float speedY, float speedF); + + virtual void set1UpKinokoEffect(); + virtual void setFlagGetEffect(); + virtual void setHipAttackEffect(); + + virtual void startQuakeShock(dQuake_c::TYPE_SHOCK_e); + virtual void startPatternRumble(const char *pattern); + + virtual bool setDamage2(dActor_c *, daPlBase_c::DamageType_e); + + virtual bool isCarryMamePlayer(); + + STATE_FUNC_DECLARE(dAcPy_c, RideOffJump); + STATE_FUNC_DECLARE(dAcPy_c, SpinHipAttack); + STATE_FUNC_DECLARE(dAcPy_c, RollSlip); ///< Flying through the air after being thrown by another player. + STATE_FUNC_DECLARE(dAcPy_c, Vine); + STATE_FUNC_DECLARE(dAcPy_c, Hang); + STATE_FUNC_DECLARE(dAcPy_c, Pole); + STATE_FUNC_DECLARE(dAcPy_c, Fire); + STATE_FUNC_DECLARE(dAcPy_c, LiftUp); ///< Lifting up another player. + STATE_FUNC_DECLARE(dAcPy_c, Throw); + STATE_FUNC_DECLARE(dAcPy_c, PropelThrow); + STATE_FUNC_DECLARE(dAcPy_c, WallJump); + STATE_FUNC_DECLARE(dAcPy_c, WallSlide); + STATE_FUNC_DECLARE(dAcPy_c, Propel); + STATE_FUNC_DECLARE(dAcPy_c, CarryPlayer); ///< Being carried by another player. + STATE_FUNC_DECLARE(dAcPy_c, RideYoshi); + STATE_FUNC_DECLARE(dAcPy_c, SpinJump); + STATE_FUNC_DECLARE(dAcPy_c, PenguinSlide); + STATE_FUNC_DECLARE(dAcPy_c, KaniJump); + STATE_FUNC_DECLARE(dAcPy_c, Quake); + STATE_FUNC_DECLARE(dAcPy_c, ElecShock); + STATE_FUNC_DECLARE(dAcPy_c, FlyDamage); + STATE_FUNC_DECLARE(dAcPy_c, IceDamage); + STATE_FUNC_DECLARE(dAcPy_c, CannonJump); + STATE_FUNC_DECLARE(dAcPy_c, TarzanRope); + STATE_FUNC_DECLARE(dAcPy_c, PlayerEat); + STATE_FUNC_DECLARE(dAcPy_c, Balloon); + STATE_FUNC_DECLARE(dAcPy_c, BlockJump); ///< Rescue Toad jumping out of his block. + STATE_FUNC_DECLARE(dAcPy_c, JrCrown); + STATE_FUNC_DECLARE(dAcPy_c, DemoInDoor); + STATE_FUNC_DECLARE(dAcPy_c, DemoInJump); + STATE_FUNC_DECLARE(dAcPy_c, DemoInVine); + STATE_FUNC_DECLARE(dAcPy_c, DemoOutDoor); + STATE_FUNC_DECLARE(dAcPy_c, DemoFallDown); + STATE_FUNC_DECLARE(dAcPy_c, DemoFireDown); + STATE_FUNC_DECLARE(dAcPy_c, DemoEatDie); + STATE_FUNC_DECLARE(dAcPy_c, DemoDokanCannon); + STATE_FUNC_DECLARE(dAcPy_c, DemoCannonWarp); + + void setSeaLandSmokeEffect(); + bool setHipAttackAction(); + void setWaterInEffect(); + void setSpinHipAttackEffect(); + void setScrollMode(s8); + dActor_c *getCarryPropelActor(); + void setPropelSpinSmokeEffect(); + void setWaterWalkFlag(); + bool setKaniActionInitHangHand(); + bool jump_common(); + void _jumpSet(jmpInf_c *); + void calcJumpCount(); + float getJumpSpeed(); + void setJumpSpeed(); + void fn_80127740(int jumpType, AnmBlend_e blendMode); ///< Jump animation set, some enum as first param @unofficial + void fn_80145fd0(int jumpType); ///< Jump voice, some enum as param @unofficial + bool checkCarryThrow(); + void jumpExeTakeOff(); + void jumpExecAir(); + void fn_801282d0(AnmBlend_e blendMode); ///< @unofficial + bool spinLiftUp(dActor_c *, bool); ///< @unofficial + void setJumpCommonBase(); + dAcPy_c *getCarryPlayer(); + bool isIceSlipAnmPlay(); + int checkWallSlideEnable(int); + bool checkWallJump(); + void setWallSlideEffect(); + void setSpinHoldReq(float targetX); + bool setSpinSpeed(float, float); + void setSpinJumpEffect(int); + void endSpinJumpEffect(); + void setSpinJumpEffectSub(int); + void setMissSpinJumpEffect(int); + void initRideSpinMove(); + void setSpinFireBall(); + void endRideSpinMove(); + bool isMissSpinEnableAnm(); + s16 getMissSpinAngle(); + void setMissSpin(); + void resetMissSpin(); + void updateMissSpin(); + void setKaniMoveSpeed(bool); + void setCrouchSmokeEffect(); + void setSlipSE(); + void setSlipEffect(); + void releaseCarryActor(); + void setInvalidKeyTimer(int, int); + void setInvalidKeyTimer_LR(int, int); + bool checkPenguinSlideJump(); + void setPenguinSlideEffect(); + void setPenguinSlideLandEffect(); + void setNormalWalkAnm(AnmBlend_e, float); + void setRunOnWaterEffect(); + void turnPowerSet(); + void setTurnSmokeEffect(); + void CrouchActionGround(); + void CrouchActionWater(); + void setWaterGroundJump(); + dActor_c *getCarryPropelBlock(); + dActor_c *getCarryHardBlock(); + float getLiftUpOffset(); + mVec3_c getLiftUpPos(); + void clearSpinLiftUpReserve(); + void checkSpinLiftUpReserve(dCc_c *cc); + void setSpinLiftUpReserve(); + void checkSpinLiftUpRoofHeight(); + void setCarryOffFall(const dAcPy_c *player); + bool checkEnableThrow(); + void initializeThrowCommonBase(); + void initializeThrowCommon(); + void finalizeThrowCommonBase(); + void finalizeThrowCommon(); + void setThrowActor(); + const sBcPlayerPointData *getBgPointData(); + void setBcData(int); + void executeThrowCommon(); + void setWaterMoveSpeed(); + void calcUzuSwimSpeed(float, float, float *); ///< @unofficial + void setUzuSpeedY(float f); + void setUzuSpeedF(float f); + bool setUzuSwimAction(); + bool setSwimAction(); + void setWaterOutEffect(); + void setPaddleSwimEffect(); + void resetPaddleSwimEffect(); + void setWaterSurfaceSwimEffect(); + void setFlutterKickEffect(); + void setInitSwimAction_FireBall(); + const sBcPlayerPointData *getBgPointData_Powerup(PLAYER_POWERUP_e, int); ///< @unofficial + bool setWaterSurfaceJump(); + void createFireBall(int); + void SwimAction_Swim(); + void setSwimAction_Swim(AnmBlend_e blendMode); + void setSwimAction_Walk(AnmBlend_e blendMode); + void setSwimAction_Penguin(AnmBlend_e blendMode); + void setSwimActionWalkAnm(); + void SwimAction_Walk(); + s16 getPenguinSwinAngleX(); + void setPenWaterMoveSpeed(int i); + bool setPenguinPaddleSwim(); + void SwimAction_Penguin(); + void setSwimAction_FireBall(); + void SwimAction_FireBall(); + bool checkSetFireBall(); + void calcPenguinSwimGroundRev(); + void setIvyHangEffect(); + bool setVineAction(); + float getHangBcOffsetY(); + bool setKaniHangToVineAction(); + bool setVineToKaniHangAction(); + void calcVineSpeed(); + bool checkVineEnd(); + void setVineWalkSE(); + void VineActionIvy(); + bool setRideOffPlayerJump(float, float); + void VineActionNet(); + void VineActionAttack(); + void VineActionRoll(); + bool checkNetPunch(); + + bool setAmiRollAction(mVec3_c *); + bool isAmiRollAction(); + void setAmiRollPos(short, float); + void setAmiRollPos(short, float, mVec3_c &); + void endAmiRollAction(short ang); + + void setCarryPlayerHang(float height); + bool setHangAction(); + void HangActionStart(); + void setHangActionWait(); + void HangActionWait(); + void setHangActionMove(); + void HangActionMove(); + + void setPoleTurnAngle(); + bool setPoleAction(); + void PoleActionStart(); + void setPoleActionWait(); + void PoleActionWait(); + void setPoleActionUp(); + void PoleActionUp(); + void setPoleActionDown(); + void PoleActionDown(); + void setPoleJump(); + bool setPoleShakeJump(); + + bool setKaniHangAction(); + void setKaniWalkEffect(); + void setKaniHangEffect(); + void setKaniCliffCatchEffect(); + void setKaniAction_Walk(); + void setKaniAction_Hang(); + void setKaniAction_HangUp(); + void setKaniAction_HangFall(); + void setKaniAction_JumpHang(); + void setKaniAction_HangUpVine(); + void setKaniAction_HangHand(); + void setKaniHangStartEffect(); + void KaniAction_Walk(); + void KaniAction_HangInit(); + void KaniAction_JumpHangInit(); + bool checkCliffHangFootGround(); + bool checkCliffHangWater(); + void KaniAction_Hang(); + void KaniAction_HangFall(); + void KaniAction_HangUp(); + void KaniAction_HangUpVine(); + + void setCatchRopeSE(); + void setClimbRopeSE(); + void setSlideRopeSE(); + void setRopeHasigoSE(); + void releasePoleCheck(); + + bool setTarzanRopeAction(); + bool setTarzanRopeJump(); + + daYoshi_c *getRideYoshi(); + bool isNotBalloonCourse(); + bool fn_801477c0(); ///< @unofficial + void setSceneChangeInfo(); + bool updateRopeAngle(); + void setRopeSwingAnm(float, float); + bool checkStartSwingUp(); + bool checkStartSwingDown(); + void updateRopeSwingAnm(); + void TarzanRopeActionStart(); + void setTarzanRopeActionWait(); + void TarzanRopeActionWait(); + void setTarzanRopeActionUp(); + void TarzanRopeActionUp(); + void setTarzanRopeActionDown(); + void TarzanRopeActionDown(); + void setTarzanRopeActionHasigoMove(); + void TarzanRopeActionHasigoMove(); + void TarzanRopeActionHasigoHangDown(); + void setTarzanRopeActionHasigoHangUp(); + void TarzanRopeActionHasigoHangUp(); + + void startQuakeAction(QuakeMode_e); + void setQuakeAction(int, QuakeMode_e); + void setQuakeActionLocal(int, QuakeMode_e); + void endQuakeAction(); + void setQuakeNumbEffect(); + + void initElecShock(); + bool executeElecShock(); + void setElecEffect(); + + bool setFlyDamageAction(int, dActor_c *); + + void initCcData(); + void initBcData(); + void calcModel(); + + void setBreakBalloonJump(u8, short); + void setDrawBalloonInPlayer(mVec3_c &pos); + bool checkAllBalloonFade(); + void setBalloonHelpVoice(); + bool setBalloonInNextgoto(); + bool setBalloonInDamage(); + bool setBalloonButtonA(); + bool setBalloonInDispOutByYoshi(int); + bool setBalloonInDispOutBase(int, int); + + void setShakeIce(float); + mVec3_c getIceDrawPos(); + + void fn_801395a0(); ///< @unofficial + void fn_801416c0(PLAYER_POWERUP_e); ///< @unofficial + + bool setRideOffYoshiJump(daPlBase_c *yoshi); + void setRideOnYoshi(daYoshi_c *yoshi); + + void setCloudStateMove(); + bool checkCloudStateCrouch(); + void setCloudStateFireCreate(); + + bool checkCarryActor(dAcPy_c *player); + bool setDropCarryPlayer(); + void setCarryPlayerMode_Move(float); + void setCarryPlayerMode_Fire(); + void setCarryPlayerMode_Crouch(); + + dAcPy_c *getRidePlayer(); + + void setYoshiBackPos(); + void setPlayerHandPos(); + void setPlayerEatPos(dActor_c *eatingActor); + void setPlayerEatReact(); + + void endPowerUpEffect(); + + void setJrCrownPos(); + void setJrCrownElecDamage(); + + bool setFireBallAction(); + bool checkFireJump(); + + bool fn_80146e40(float, float, bool); ///< @unofficial + int getSpinActionMode(); + + bool setPropelAction(); + void resetPropelFlyTime(); + void clearPropelFlyUpTime(); + void calcPropelMoveSpeedF(); + void setPropelActionFlyInit(); + void setPropelActionBigFly(); + void setPropelActionFly(); + void PropelActionFly(); + void setPropelActionFall(); + void PropelActionFall(); + void setStartPropelJumpEffect(); + bool calcPropelFallSpinEffect(); + void setPropelFallSpinEffect(); + void endPropelFlyPartsMove(); + void stopPropelFallSpinEffect(); + void updatePropelParts(); + void updatePropelFlyPartsMove(); + bool isEnablePropelJump(); + bool setSpinActionReq(); + bool setSpinAction(); + + void initPlayerDownCommon(); + void initDemo_DownPose(); + void initDemo_DownFall(); + void exeDemo_DownFall(); + void checkRest(); + void stopOtherDownDemo(); + void playOtherDownDemo(); + void setPlayerEatDie(); + void releaseEatDie(); + bool setEatDieHide(); + bool setEatDieFadeOut(); + bool setEatDieSpitOut(); + void setEatDieScreamVoice(); + + bool searchDoorActor(); + void setDemoInDoor_Walk(); + bool isDoorDemoEnable(); + bool setDoorDemo(dActor_c *); + void exeDemoOutDoor_OpenDoor(); + void initDemoOutDoor_MoveInter(); + void exeDemoOutDoor_MoveInter(); + void initDemoOutDoor_MoveCenter(); + void exeDemoOutDoor_MoveCenter(); + void exeDemoOutDoor_WaitClose(); + void exeDemoOutDoor_WaitEnter(); + + bool initDemoDokanCannon(mVec3_c &pos, int cannonMode); ///< @unofficial + void endDemoDokanCannon(mVec3_c &pos); + bool isDokanCannonIn(); + bool setCannonJump(float speedY, float speedF, int jumpType); + + void setOffYoshiInGoal(daPlBase_c *yoshi); + bool isDrawingCarryFukidashi(); - void getCcBounds(sRangeDataF &bounds); ///< @unofficial - void cancelCarry(dActor_c *carriedActor); + void getCcBounds(sRangeDataF *bounds); ///< @unofficial + bool cancelCarry(dActor_c *carriedActor); + + void setFireBallDamage(u8 type); + + bool fn_80145c00(PLAYER_POWERUP_e); ///< @unofficial + + mVec3_c getModelScaleBase(); + mVec3_c getModelScale(); + + void calcInvalidKeyTimer(); + void calcTimerProc(); + void calcStarTimer(); + + void initChangeInit(); + bool executeChangeInit(); + int change_reverse_scale_set(); + void initChangeNormal(); + bool executeChangeNormal(); + void setChange(int); + bool updateChange(); + + void maxFallSpeedSet(); + void setFollowEffect(int); + void setItemGetEffect(); + void setChukanPowerUpEffect(); + void updateItemGetEffect(); + void updateFollowEffect(); + + void setCenterOffset(); + void selectAction(); + + bool isDrawingFukidashi(); + void managePropelFukidashi(); + + void setCcAtSpin(); + void setCcAtSpinFall(); + void setCcAtSpinLiftUp(); + void setCcAtNetPunch(); + void setCcData(); + void setCcDataDirect(); + + void fn_80143060(sBcPointData &data1, sBcPointData &data2, bool); ///< @unofficial + bool fn_80143220(sBcPointData &data1, sBcPointData &data2); ///< @unofficial + void reviseBcDataCarryPlayer(sBcPointData &data1, sBcPointData &data2); ///< @unofficial + void reviseBcDataCarryHardBlock(sBcPointData &data1, sBcPointData &data2); ///< @unofficial + + void setStarBase(StarSet_e, int); + + bool searchKinopioNearPlayer(float *dist); + + void setPlayerData(); + void setSpeedData(); + void setModeGravity(); + + static bool ccCheckAttack(dCc_c *self, dCc_c *other); + static bool ccCheckStamp(dCc_c *self, dCc_c *other); + static bool ccCheckSideHit(dCc_c *self, dCc_c *other); + static void ccCallBack(dCc_c *self, dCc_c *other); + static void atCcCallBack(dCc_c *self, dCc_c *other); mVec3_c getCarryPos(); + mMtx_c getCarryMtx() { mMtx_c mtx; mtx.trans(getCarryPos()); mtx.concat(getModel()->getMtx()); return mtx; } + PLAYER_POWERUP_e getPowerupCopy() { return mPowerupCopy; } + bool isClimbing() { + return isStatus(STATUS_36) || + isStatus(STATUS_VINE) || + isStatus(STATUS_HANG) || + isStatus(STATUS_KANI_HANG) || + isStatus(STATUS_POLE); + } + float getDirSpeed() const { + return sc_DirSpeed[mDirection]; + } - bool FUN_8012e540(dActor_c *, bool); ///< @unofficial - - char mPad[0x15e8]; + int mIsRescueKinopio; + PLAYER_POWERUP_e mPowerupCopy; + PLAYER_POWERUP_e mPowerupCopy2; + mVec2_c m_0c; + sBcPointData mVineBcData; + dPc_c mPc; + int m_60; + s8 mScrollMode; + s8 mChangeType; + s8 mChangeTimer; + s8 m_67; + int m_68; + float mAmiRelated2; + int mDoorSize; + int m_74; + int m_78; + int m_7c; + int m_80; + int mWaitFrameCount; + int m_88; + int mJumpCounter; + u8 mJumpComboTimer; ///< Timer for allowing a slight delay between jumps to still count as a combo. + u8 mWallSlideCooldown; ///< Timer to disable wall sliding while active. + float m_94; + mEf::levelEffect_c mLevelEf1; + mEf::levelEffect_c mLevelEf2; + mAng m_2e8; + int m_2ec; + int m_2f0; + s16 m_2f4; + s16 mPropelRollSpeed; + s16 mIsPropelFall; + mEf::levelEffect_c mLevelEf3; + dEf::followEffect_c mFollowEf; + int m_538; + int m_53c; + int m_540; + int m_544; + int m_548; + float m_54c; + mEf::levelEffect_c mLevelEf4; + mEf::levelEffect_c mLevelEf5; + u8 mPad1[0x4]; + mVec3_c mAmiRollPos; + float mAmiXDiff; + float mAmiRelated; + s16 mAmiAng; + int m_7bc; + u16 m_7c0; + u32 m_7c4; + mEf::levelEffect_c mLevelEf6; + u8 m_8f0; + mVec2_c m_8f4; + int mPoleGrabCooldown; ///< Timer to disable grabbing a pole while active. + short m_900, m_902, m_904, m_906; + int m_908; + RopeSwingState_e m_90c; + int mTarzanRopeCooldown; ///< Timer to disable swinging on a vine while active. + int m_914; + float m_918; + int m_91c; + mEf::levelEffect_c mLevelEf7; + mEf::levelEffect_c mLevelEf8; + int m_b70; + int m_b74; + float m_b78; + int m_b7c; + int m_b80; + int m_b84; + u8 m_b88; + u8 m_b89; + float m_b8c; + mVec2_c mUzuSwimSpeed; + int m_b98; + mEf::levelEffect_c mLevelEf9; + mEf::levelEffect_c mLevelEf10; + mEf::levelEffect_c mLevelEf11; + mEf::levelEffect_c mLevelEf12; + int m_103c; + int m_1040; + int mSpinTimer; ///< Timer for the duration of a spin jump. + s16 m_1048; + u8 mPad2[0x4]; + float mSpinHoldReqTarget; ///< The target X position to move to while doing a spin in place. + u32 mSpinFireBallCooldown; ///< Timer to control how often fireballs the player automatically shoots while spinning. + u32 m_1058; + s16 m_105c; + dEf::followEffect_c mFollowEf2; + dEf::followEffect_c mFollowEf3; + u32 m_1288; + u32 m_128c; + u8 mPad3[0x8]; + int m_1298; + mVec2_c m_129c; + u8 mPad4[0x4]; + mVec3_c m_12a8; + u32 m_12b4; + int m_12b8; + u32 mAllBalloonFadeTimer; + mMtx_c mRideJrClownMtx; + int mSpinCooldown; ///< Timer to disable another spin action while active. + u8 m_12f4; + float m_12f8; + fBaseID_e m_12fc; + float m_1300; + float m_1304; + int m_1308; + int m_130c; + int m_1310[2]; + int m_1318[2]; + int mFollowType; + int mPowerUpEffectTimer; ///< Timer controlling the powerup effect duration and opacity. + int mPowerUpType; ///< 0: Touching an item, 1: Touching the midway point. + dEf::dLevelEffect_c mItemGetEffect1; + dEf::dLevelEffect_c mItemGetEffect2; + int m_157c; + int m_1580; + int m_1584; + dPyMdlMng_c mPyMdlMng; + float m_1594; + float m_1598; + float m_159c; fBaseID_e mCarryActorID; + int mFastRunFrames; ///< How many frames the player has been running at over 1 unit/frame. + int m_15a8; + /// Disables interaction with other players and enemies while the timer is non-zero. + short mNoInteractTimer; + short m_15ae; + short m_15b0; + short m_15b2; + short mWaterWalkTimer; + short m_15b6; + short m_15b8; + short mBalloonHelpVoiceCooldown; ///< Timer to only allow the help voice to play every 2 seconds. + dEf::followEffect_c mFollowEf4; + dPropelParts_c mPropelParts; + dPlayerOrchestra_c mPlayerOrchestra; + + ACTOR_PARAM_CONFIG(PlayerNo, 0, 4); + ACTOR_PARAM_CONFIG(CreateAction, 16, 8); + ACTOR_PARAM_CONFIG(Direction, 24, 1); + static const float data_802f5a0c[]; + static const float data_802f5a48[]; + static dAcPy_HIO_Speed_c m_speed_hio[2]; static const float msc_JUMP_SPEED; }; diff --git a/include/game/bases/d_a_player_base.hpp b/include/game/bases/d_a_player_base.hpp index 2c704210..ba6ac2b1 100644 --- a/include/game/bases/d_a_player_base.hpp +++ b/include/game/bases/d_a_player_base.hpp @@ -1,27 +1,44 @@ #pragma once -#include #include +#include +#include #include +#include +#include #include #include #include +#include +#include +#include -class daPlModel_c { -public: - u8 pad[0x108]; - mMtx_c mMtx; - - mMtx_c &getMtx() { return mMtx; } -}; - +/** + * @brief The base class for the player and Yoshi. + * @statetable + */ class daPlBase_c : public dActor_c { public: enum DamageType_e { - DAMAGE_NONE = 0, - DAMAGE_1, DAMAGE_2, DAMAGE_3, DAMAGE_4, - DAMAGE_5, DAMAGE_6, DAMAGE_7, DAMAGE_8, - DAMAGE_9, DAMAGE_A, DAMAGE_B, DAMAGE_C + DAMAGE_DEFAULT, + DAMAGE_BG, + DAMAGE_2, + DAMAGE_HIP_ATTACK, + DAMAGE_4, + DAMAGE_CLIMB, + DAMAGE_6, + DAMAGE_YOGAN, + DAMAGE_8, + DAMAGE_ELEC_SHOCK, + DAMAGE_POISON, + DAMAGE_SQUISH, + DAMAGE_EAT_DIE, + DAMAGE_D, + DAMAGE_E, + DAMAGE_FREEZE, + DAMAGE_10, + DAMAGE_11, + DAMAGE_POISON_FOG }; enum DokanDir_e { @@ -32,13 +49,510 @@ class daPlBase_c : public dActor_c { DOKAN_ROLL }; - enum StarSet_e {}; + enum StarSet_e { + STAR_SET_0, + STAR_SET_1, + STAR_SET_2 + }; + /// @brief Blending modes for animations. enum AnmBlend_e { - BLEND_0, - BLEND_1 + BLEND_NONE, ///< Do not blend between animations. + BLEND_DEFAULT ///< Use the default blend duration specified in the animation HIO. + }; + + enum ClearType_e { + CLEAR_TYPE_GOAL, + CLEAR_TYPE_BOSS, + CLEAR_TYPE_FINAL_BOSS + }; + + enum BgPress_e { + BG_PRESS_FOOT = 9, + BG_PRESS_HEAD, + BG_PRESS_R, + BG_PRESS_L, + BG_PRESS_COUNT + }; + + /// @unofficial + enum GroundType_e { + GROUND_TYPE_DEFAULT, + GROUND_TYPE_SNOW, + GROUND_TYPE_SAND, + GROUND_TYPE_ICE, + GROUND_TYPE_DIRT, + GROUND_TYPE_WATER, + GROUND_TYPE_CLOUD, + GROUND_TYPE_FUNSUI, + GROUND_TYPE_MANTA, + GROUND_TYPE_BEACH, + GROUND_TYPE_CARPET, + GROUND_TYPE_LEAF, + GROUND_TYPE_WOOD + }; + + /// @unofficial + enum SlipSubstate_e { + SLIP_ACTION_NONE, + SLIP_ACTION_STOOP, + SLIP_ACTION_END + }; + + /// @unofficial + enum HipSubstate_e { + HIP_ACTION_READY, + HIP_ACTION_ATTACK_START, + HIP_ACTION_ATTACK_FALL, + HIP_ACTION_GROUND, + HIP_ACTION_STAND_NORMAL, + HIP_ACTION_STAND_NORMAL_END, + HIP_ACTION_TO_STOOP + }; + + /// @unofficial + enum JumpDaiSubstate_e { + JUMP_DAI_MOVE_DOWN, ///< Moving down on the player or spring. + JUMP_DAI_HIGH_JUMP, ///< The jump button was pressed to do a higher jump. + }; + + /// @unofficial + enum FunsuiSubstate_e { + FUNSUI_ACTION_NONE, + FUNSUI_ACTION_START + }; + + /// @unofficial + enum AnimePlaySubstate_e { + ANIME_PLAY_ACTION_0, + ANIME_PLAY_ACTION_1, + ANIME_PLAY_ACTION_2 + }; + + /// @unofficial + enum DemoType_e { + DEMO_0, + DEMO_1, + DEMO_2, + DEMO_3, + DEMO_PLAYER, + DEMO_KINOPIO, + DEMO_ENDING_DANCE + }; + + /// @unofficial + enum DemoDokanMode_e { + DEMO_DOKAN_NONE, + DEMO_DOKAN_NORMAL, + DEMO_DOKAN_RAIL, + DEMO_DOKAN_WATER_TANK }; + /// @brief Arguments for transitioning to the @ref StateID_Crouch "crouch" state. + /// @unofficial + enum CrouchArg_e { + CROUCH_ARG_FROM_WALK, ///< Crouching while already on the ground. + CROUCH_ARG_FROM_OTHER, ///< Crouching after a slide or a ground pound. + CROUCH_ARG_FROM_SIT_JUMP ///< Landing from a crouch jump. + }; + + /// @brief Arguments for transitioning to the @ref StateID_HipAttack "ground pound" state. + /// @unofficial + enum HipAttackArg_e { + HIP_ATTACK_ARG_PLAYER, ///< A regular player is doing a ground pound. + HIP_ATTACK_ARG_ITEM_KINOPIO ///< The rescue Toad is doing a ground pound out of the item block. @unused + }; + + /// @brief Arguments for transitioning to the @ref StateID_Swim "swim" state. + /// @unofficial + enum SwimArg_e { + SWIM_ARG_INITIAL, ///< Already in water at the start of the swim action. + SWIM_ARG_ENTERING, ///< Just entered the water. + SWIM_ARG_FIREBALL, ///< Player was about to shoot a fireball, shoot it while in water. + SWIM_ARG_CLIFF_HANG ///< Falling from a cliff into water. + }; + + /// @brief Arguments for transitioning to the @ref StateID_Kani "cliff" state. + /// @unofficial + enum KaniArg_e { + KANI_ARG_WALK, ///< Standing on the cliff and walking. + KANI_ARG_HANG, ///< Landing high enough on the cliff to stand on it, but hang down from it instead. + KANI_ARG_JUMP_HANG, ///< Falling onto the cliff, immediately hang from it. + KANI_ARG_WALK_FORCE, ///< Standing on the cliff, disallow immediately hanging from it by holding down. + KANI_ARG_HANG_UP_VINE, ///< Climbing onto the cliff from a vine. + KANI_ARG_HANG_HAND ///< Catching the cliff from below, hang from it. + }; + + /// @brief Arguments for transitioning to the @ref StateID_AnimePlay "animation" state. + /// @unofficial + enum AnimePlayArg_e { + DEMO_ANIME_NORMAL, + DEMO_ANIME_BOSS_SET_UP, + DEMO_ANIME_BOSS_GLAD, + DEMO_ANIME_BOSS_ATTENTION, + DEMO_ANIME_BOSS_KEY_GET, + DEMO_ANIME_BOSS_GLAD_2 + }; + + /// @brief Arguments for transitioning to the @ref StateID_DemoWait "demo wait" state. + /// @unofficial + enum DemoWaitArg_e { + DEMO_WAIT_ARG_TO_NONE, + DEMO_WAIT_ARG_TO_CONTROL + }; + + /// @unofficial + enum DemoWaitSubstate_e { + DEMO_WAIT_DELAY, + DEMO_WAIT_TRANSITION + }; + + /// @unofficial + enum DokanType_e { + DOKAN_TYPE_NORMAL, + DOKAN_TYPE_CONNECTED, + DOKAN_TYPE_MINI + }; + + /// @unofficial + enum DemoDownArg_e { + DEMO_DOWN_ARG_HIT, + DEMO_DOWN_ARG_TIME_UP, + DEMO_DOWN_ARG_POISON, + DEMO_DOWN_ARG_POISON_FOG + }; + + /// @unofficial + enum DemoGoalSubstate_e { + GOAL_DEMO_ACTION_POLE, + GOAL_DEMO_ACTION_WAIT, + GOAL_DEMO_ACTION_KIME_POSE, + GOAL_DEMO_ACTION_RUN + }; + + /// @unofficial + enum DemoGoalState_Pole_e { + GOAL_DEMO_POLE_SWING, ///< Swinging around the pole to the other side. + GOAL_DEMO_WAIT_BELOW_PLAYER, ///< Waiting for the player below to slide far enough down the pole to not be in the way of this player. + GOAL_DEMO_POLE_SLIDE, ///< Sliding down the pole. + GOAL_DEMO_POLE_WAIT_JUMP, ///< Waiting at the bottom of the pole to jump off. + GOAL_DEMO_POLE_JUMP, ///< Jumping off the pole. + GOAL_DEMO_POLE_LAND, ///< Playing the landing animation after landing. + GOAL_DEMO_POLE_WAIT_TURN, ///< Waiting #sc_DemoPoleWaitTurn frames to turn toward the screen. + GOAL_DEMO_POLE_TURN, ///< Turning toward the screen. + GOAL_DEMO_POLE_WAIT_END ///< Waiting #sc_DemoPoleWaitEnd frames before transitioning to the course clear dance. + }; + + /// @unofficial + enum KimePoseMode_e { + KIME_POSE_NONE, + KIME_POSE_WITH_HAT, + KIME_POSE_PENGUIN, + KIME_POSE_NO_HAT, + KIME_POSE_PROPELLER + }; + + /// @unofficial + enum ControlDemoSubstate_e { + CONTROL_DEMO_WAIT, + CONTROL_DEMO_WALK, + CONTROL_DEMO_REGULAR_ANIM, + CONTROL_DEMO_CUTSCENE_ANIM, + CONTROL_DEMO_4, + CONTROL_DEMO_KINOPIO_WALK, + CONTROL_DEMO_KINOPIO_SWIM, + CONTROL_DEMO_KINOPIO_SINK_SAND, + CONTROL_DEMO_ENDING_DANCE, + }; + + /// @unofficial + enum PowerChangeType_e { + POWER_CHANGE_NORMAL, + POWER_CHANGE_ICE, + POWER_CHANGE_LOW_SLIP + }; + + /// @unofficial + enum SquishState_e { + SQUISH_OFF, + SQUISH_INIT, + SQUISH_SET_REDUCTION, + SQUISH_ANIMATION + }; + + /// @unofficial + enum BgCross1_e { + BGC_FOOT = BIT_FLAG(0), ///< Colliding with the foot sensor. + BGC_HEAD = BIT_FLAG(1), ///< Colliding with the head sensor. + BGC_WALL = BIT_FLAG(2), ///< Colliding with the wall sensor. + BGC_WALL_TOUCH_L = BIT_FLAG(3), + BGC_WALL_TOUCH_R = BIT_FLAG(4), + BGC_WALL_TOUCH_L_2 = BIT_FLAG(5), + BGC_WALL_TOUCH_R_2 = BIT_FLAG(6), + BGC_OBJBG_TOUCH_L = BIT_FLAG(7), ///< Touching a background object on the left. + BGC_OBJBG_TOUCH_R = BIT_FLAG(8), ///< Touching a background object on the right. + BGC_OBJBG_TOUCH_CARRIED_L = BIT_FLAG(9), ///< The touching background object on the left is being carried by a player. + BGC_OBJBG_TOUCH_CARRIED_R = BIT_FLAG(10), ///< The touching background object on the right is being carried by a player. + BGC_11 = BIT_FLAG(11), + BGC_12 = BIT_FLAG(12), + BGC_13 = BIT_FLAG(13), + BGC_WATER_SHALLOW = BIT_FLAG(14), ///< At least slightly inside of water (hip height or higher). + BGC_WATER_TOUCH = BIT_FLAG(15), ///< At least touching water. + BGC_WATER_SUBMERGED = BIT_FLAG(16), ///< Fully submerged in water. + BGC_ON_WATER_MOVE = BIT_FLAG(17), ///< On water by being mini or sliding with the penguin suit. + BGC_WATER_BUBBLE = BIT_FLAG(18), ///< Inside a floating water bubble. + BGC_SIDE_LIMIT_L = BIT_FLAG(19), + BGC_SIDE_LIMIT_R = BIT_FLAG(20), + BGC_ON_SNOW = BIT_FLAG(22), + BGC_ON_ICE = BIT_FLAG(23), + BGC_ON_ICE_LOW_SLIP = BIT_FLAG(24), + BGC_SLOPE_AND_HEAD = BIT_FLAG(25), + BGC_ON_SAND = BIT_FLAG(26), + BGC_ON_SINK_SAND = BIT_FLAG(27), + BGC_IN_SINK_SAND = BIT_FLAG(28), + BGC_INSIDE_SINK_SAND = BIT_FLAG(29), + BGC_ON_BELT_L = BIT_FLAG(30), + BGC_ON_BELT_R = BIT_FLAG(31) + }; + + /// @unofficial + enum BgCross2_e { + BGC_SEMISOLID = BIT_FLAG(0), + BGC_LIFT = BIT_FLAG(1), ///< [Figure out a better name for this]. + BGC_HANG_ROPE = BIT_FLAG(2), + BGC_AUTOSLIP = BIT_FLAG(3), + BGC_36 = BIT_FLAG(4), + BGC_GROUNDED_MOVE_UP = BIT_FLAG(5), + BGC_37 = BIT_FLAG(6), ///< Cannot wall kick or ground pound while this is set. + BGC_SLOPE = BIT_FLAG(7), + BGC_CLIFF = BIT_FLAG(8), + BGC_CLIFF_ABOVE_1 = BIT_FLAG(9), + BGC_CLIFF_ABOVE_2 = BIT_FLAG(10), + BGC_CAN_CLIMB = BIT_FLAG(11), + BGC_44 = BIT_FLAG(12), + BGC_VINE_TOUCH_FULL = BIT_FLAG(13), ///< Fully touching a vine / mesh net / rock wall. + BGC_VINE_TOUCH_U = BIT_FLAG(14), ///< Touching a vine / mesh net / rock wall on the top. + BGC_VINE_TOUCH_D = BIT_FLAG(15), ///< Touching a vine / mesh net / rock wall on the bottom. + BGC_VINE_TOUCH_2 = BIT_FLAG(16), + BGC_VINE_TOUCH = BIT_FLAG(17), ///< Touching a vine / mesh net / rock wall on any side. + BGC_VINE_TOUCH_L = BIT_FLAG(19), ///< Touching a vine / mesh net / rock wall on the left. + BGC_VINE_TOUCH_R = BIT_FLAG(20), ///< Touching a vine / mesh net / rock wall on the right. + BGC_NON_BREAK_BLOCK_HIT = BIT_FLAG(21), + BGC_54 = BIT_FLAG(22), + BGC_PRESS_HEAD_HIT = BIT_FLAG(23), + BGC_BLOCK_HIT = BIT_FLAG(24), + BGC_57 = BIT_FLAG(25), + BGC_58 = BIT_FLAG(26), + BGC_LINE_BLOCK_HIT = BIT_FLAG(27), + BGC_60 = BIT_FLAG(28), + BGC_61 = BIT_FLAG(29), + BGC_62 = BIT_FLAG(30), + BGC_63 = BIT_FLAG(31) + }; + + /// @brief The status IDs to be used with onStatus(), offStatus(), isStatus() and setStatus(). + /// @unofficial + enum Status_e { + STATUS_CREATED, ///< The player was created. + STATUS_CAN_EXECUTE, ///< The player can execute this frame or not. + STATUS_NO_ANIM, ///< Don't play any animations. + STATUS_DISABLE_STATE_CHANGE, ///< Disallow state changes. + STATUS_OUT_OF_PLAY, ///< The player is in a bubble or has died. + STATUS_ALL_DOWN_FADE, ///< All players have died and the screen is transitioning. + STATUS_STUNNED, ///< Stunned by electric shock or ice. + STATUS_07, ///< [Ice related] + STATUS_QUAKE, ///< The player was stunned by an earthquake. + STATUS_JUMP = 0x0a, ///< The player is jumping. + STATUS_CAN_PENGUIN_SLIDE, ///< If the player can start sliding as a penguin. + STATUS_STAR_JUMP, ///< The player is jumping while in star mode. + STATUS_KANI_JUMP, ///< The player is doing a crab jump on a cliff. + STATUS_SINK_SAND_JUMP, ///< The player is jumping while in sinking sand. + STATUS_SIT_JUMP, ///< The player is doing a sitting jump. + STATUS_YOSHI_DISMOUNT_JUMP, ///< The player is doing a jump to dismount Yoshi. + STATUS_CANNON_JUMP, ///< The player is flying out of a pipe cannon. + STATUS_WAIT_JUMP, ///< The player is doing a small hop after being affected by a small quake. + STATUS_WALL_SLIDE, ///< The player is sliding down a wall. + STATUS_BIG_JUMP, ///< The player is doing a jump on a spring or another player. + STATUS_SPRING_JUMP, ///< The player is doing a jump on a springboard. + STATUS_PLAYER_JUMP, ///< The player is doing a jump on another player. + STATUS_17, ///< [Dokan related] + STATUS_THROW, ///< The player is throwing something. + STATUS_KANI_WALK, ///< The player is doing a crab walk on a cliff. + STATUS_1A, + STATUS_1B, + STATUS_HIP_ATTACK_FALL, ///< The player is falling while ground pounding. + STATUS_HIP_ATTACK_LAND, ///< The player has landed after ground pounding. Only active on one frame. + STATUS_HIP_ATTACK_STAND_UP, ///< The player is standing up after ground pounding. Only active on one frame. + STATUS_SPIN_HIP_ATTACK_FALL, ///< The player is falling while doing a down spin. + STATUS_SPIN_HIP_ATTACK_LANDED, + STATUS_SPIN_HIP_ATTACK_LANDING, + STATUS_PRESS_ATTACH, ///< The player is is attached to a enemy while ground pounding or doing a down spin. [Used for the big goombas]. + STATUS_HIP_ATTACK_DAMAGE_PLAYER, ///< The player was ground pounded by another player. + STATUS_24, + STATUS_PROPEL = 0x26, ///< The player is flying with the propeller suit. + STATUS_PROPEL_UP, ///< The player is flying upwards with the propeller suit. + STATUS_PROPEL_SLOW_FALL = 0x29, ///< The player will fall slowly while spinning down with the propeller suit. + STATUS_PROPEL_NO_ROLL, ///< Don't rotate the player because of the propeller suit. + STATUS_SPIN, ///< The player is spinning, either from a spin jump, a propeller spin (upwards or downwards) or screw spinning. + STATUS_IS_SPIN_HOLD_REQ, ///< If the player spins, stay in place. [Used for the twisting screws]. + STATUS_TWIRL, ///< The player is twirling in midair. + STATUS_WAS_TWIRL, ///< The player was twirling in midair the previous frame. + STATUS_30 = 0x30, + STATUS_31, + STATUS_32, + STATUS_VINE, ///< The player is clinging to a vine / mesh net / rock wall. + STATUS_HANG, ///< The player is hanging from a ceiling rope. + STATUS_POLE, ///< The player is climbing a pole. + STATUS_36, + STATUS_KANI_HANG, ///< The player is hanging from a cliff. + STATUS_KANI_HANG_ANIMATION, ///< The player is animating into the hanging pose on a cliff. + STATUS_39, ///< [Swim related] + STATUS_SWIM, ///< The player is swimming. + STATUS_PENGUIN_SWIM, ///< The player is swimming with the penguin suit. + STATUS_PENGUIN_SLIDE, ///< The player is sliding with the penguin suit. + STATUS_PENGUIN_SLIDE_JUMP, ///< The player is doing a penguin slide jump. + STATUS_INITIAL_SLIDE, ///< The player is in an initial slide action. [Used in 6-6 to slide all the way down automatically]. + STATUS_PENGUIN_RECOIL, ///< The player is bouncing back after hitting an enemy that cannot be killed by a penguin slide. + STATUS_40, ///< [Water jump?] + STATUS_SWIM_AGAINST_JET_H, ///< The player is swimming against a horizontal water jet stream. + STATUS_SWIM_AGAINST_JET_V, ///< The player is swimming against a vertical water jet stream. + STATUS_43, + STATUS_45 = 0x45, + STATUS_46, + STATUS_47, + STATUS_48, + STATUS_49, + STATUS_4A, + STATUS_RIDE_YOSHI, ///< The player is riding Yoshi. + STATUS_JUMP_DAI_COOLDOWN = 0x4d, ///< The player recently failed to perform a big jump because of a ceiling. + STATUS_4E, + STATUS_4F, + STATUS_50, + STATUS_51, + STATUS_52, + STATUS_53, + STATUS_54, + STATUS_55, + STATUS_56, + STATUS_57, + STATUS_RIDE_NUT_2, + STATUS_RIDE_NUT, + STATUS_5A, + STATUS_5B, + STATUS_5C, + STATUS_EXTRA_PUSH_FORCE, + STATUS_5E, + STATUS_5F, + STATUS_ENEMY_STAGE_CLEAR, ///< The player has cleared an enemy ambush. + STATUS_61, + STATUS_62, + STATUS_63, + STATUS_64, + STATUS_GOAL_POLE_TOUCHED, ///< The player has touched the goal pole. + STATUS_GOAL_POLE_WAIT_BELOW_PLAYER, ///< The player is waiting for the player below to slide down the goal pole. + STATUS_67, + STATUS_GOAL_POLE_FINISHED_SLIDE_DOWN, ///< The player has reached the bottom of the goal pole after sliding down. + STATUS_GOAL_POLE_READY_FOR_JUMP_OFF, ///< The player is ready to jump off the goal pole. + STATUS_GOAL_POLE_TURN, ///< The player is turning toward the screen after jumping off the goal pole. + STATUS_6B, + STATUS_6C, + STATUS_6D, + STATUS_6E, + STATUS_GOAL_POLE_NOT_GOAL_NO_MOVE, ///< The player did not reach the goal pole in time and mustn't move anymore. + STATUS_70, + STATUS_71, + STATUS_72, + STATUS_73, + STATUS_74, + STATUS_ENDING_DANCE_AUTO, + STATUS_DEMO_NEXT_GOTO_BLOCK, ///< The player is transitioning after touching a next goto area. + STATUS_77, + STATUS_78, + STATUS_79, + STATUS_7A, + STATUS_STOP_EXECUTE = 0x7d, ///< Stop executing this player indefinitely. + STATUS_7E, + STATUS_7F, + STATUS_80, + STATUS_81, + STATUS_82, + STATUS_83, + STATUS_84, + STATUS_85, + STATUS_86, + STATUS_AUTO_BOUNCE, + STATUS_88, + STATUS_89, + STATUS_8A, + STATUS_QUAKE_BIG, ///< A big quake that stuns the player was triggered. + STATUS_QUAKE_SMALL, ///< A small quake that makes the player do a hop was triggered. + STATUS_8D, ///< [Cannon shot related] + STATUS_8E, ///< [Cannon shot related] + STATUS_CAN_LAND, ///< The player can land on Yoshi or another player. + STATUS_91 = 0x91, + STATUS_92, + STATUS_93, + STATUS_94, + STATUS_95, + STATUS_96, + STATUS_97, + STATUS_98, + STATUS_99, + STATUS_9B = 0x9b, + STATUS_9C, + STATUS_9D, + STATUS_9E, + STATUS_9F, + STATUS_A0, + STATUS_A1, + STATUS_A2, + STATUS_A3, + STATUS_A4, + STATUS_A5, ///< [Jump moving up?] + STATUS_FIREBALL_PREPARE_SHOOT, ///< The player is about to shoot a fireball. + STATUS_A7, + STATUS_A8, + STATUS_A9, + STATUS_AA, + STATUS_AB, + STATUS_FOLLOW_MAME_KURIBO, ///< Mini Goombas are attached to the player. + STATUS_IS_PENGUIN, ///< The player is in the penguin suit. + STATUS_HIP_ATTACK, ///< The player is in the ground pound action and is not yet about to stand back up. + STATUS_B3 = 0xb3, /// [Yoshi only?] + STATUS_ABOUT_TO_BE_DELETED = 0xb5, + STATUS_ITEM_KINOPIO_DISPLAY_OUT, + STATUS_B7, + STATUS_B8, + STATUS_DISPLAY_OUT_DEAD, ///< The player is outside of the screen bounds and should die as a result. + STATUS_DISPLAY_OUT_NO_DAMAGE, ///< The player is outside of the screen bounds and should not be able to be attacked. + STATUS_INVISIBLE, ///< The player is invisible. + STATUS_INVULNERABLILITY_BLINK, ///< Skip drawing the player this frame to create a blinking effect. + STATUS_BD, + STATUS_BE, + STATUS_BF, + STATUS_C0, + STATUS_CAN_WATER_WALK, ///< The player can walk on water because of the mini mushroom. + STATUS_ON_WATER_MOVE, ///< The player is on water by being mini or sliding with the penguin suit. + STATUS_CAN_WATER_SLIDE, ///< The player can slide on water because of the penguin suit. + STATUS_C4, + STATUS_C5, + STATUS_C8 = 0xc8, + STATUS_C9, + STATUS_CA + }; + + class jmpInf_c { + public: + jmpInf_c(float speed, int jumpMode, AnmBlend_e blendMode) : mSpeed(speed), mJumpMode(jumpMode), mBlendMode(blendMode) {} + virtual ~jmpInf_c() {}; + + float mSpeed; + int mJumpMode; + AnmBlend_e mBlendMode; + }; + + typedef void (daPlBase_c::*ProcFunc)(); + daPlBase_c(); virtual ~daPlBase_c(); @@ -56,9 +570,9 @@ class daPlBase_c : public dActor_c { virtual bool isItemKinopio() { return false; } virtual void setPowerup(PLAYER_POWERUP_e, int); ///< @unofficial virtual u8 getTallType(s8); - virtual void *getHeadBgPointData() { return nullptr; }; - virtual void *getWallBgPointData() { return nullptr; }; - virtual void *getFootBgPointData() { return nullptr; }; + virtual const sBcPointData *getHeadBgPointData() { return nullptr; }; + virtual const sBcPointData *getWallBgPointData() { return nullptr; }; + virtual const sBcPointData *getFootBgPointData() { return nullptr; }; virtual float getStandHeadBgPointY() { return 0.0f; } virtual void checkBgCrossSub() {} virtual void postBgCross(); @@ -71,30 +585,30 @@ class daPlBase_c : public dActor_c { virtual bool setBalloonInDispOut(int) { return false; } virtual bool isChange() { return false; } virtual void changeNextScene(int); - virtual bool isEnableDokanInStatus(void); + virtual bool isEnableDokanInStatus(); virtual bool setHideNotGoalPlayer(); - virtual int vf130(float f, mVec2_c *v, int param3); ///< @unofficial + virtual int setDemoGoal(mVec3_c &landPos, float goalCastleX, u8 goalType); virtual bool setDemoCannonWarp(int, short, short) { return false; } - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoNone); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoStartWait); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoWait); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoInDokanU); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoInDokanD); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoInDokanR); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoInDokanL); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoOutDokanU); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoOutDokanD); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoOutDokanR); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoOutDokanL); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoOutDokanRoll); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoInWaterTank); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoOutWaterTank); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoRailDokan); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoDown); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoNextGotoBlock); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoGoal); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoControl); + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoNone); ///< Default demo state, checking for pipe entry. Argument: Whether to not force execution start (@p bool). + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoStartWait); ///< Course in default state. Argument: None. + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoWait); ///< Waiting before transitioning to StateID_DemoNone or StateID_DemoControl. Argument: See DemoWaitArg_e. + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoInDokanU); ///< Entering an area via a pipe above the player. Argument: Pipe type (DokanType_e). + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoInDokanD); ///< Entering an area via a pipe below the player. Argument: Pipe type (DokanType_e). + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoInDokanR); ///< Entering an area via a pipe to the right of the player. Argument: Pipe type (DokanType_e). + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoInDokanL); ///< Entering an area via a pipe to the left of the player. Argument: Pipe type (DokanType_e). + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoOutDokanU); ///< Leaving an area via a pipe above the player. Argument: None. + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoOutDokanD); ///< Leaving an area via a pipe below the player. Argument: None. + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoOutDokanR); ///< Leaving an area via a pipe to the right of the player. Argument: None. + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoOutDokanL); ///< Leaving an area via a pipe to the left of the player. Argument: None. + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoOutDokanRoll); ///< Leaving an area via a rolling hill pipe. Argument: None. + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoInWaterTank); ///< Entering an area via a water tank pipe. @unused Argument: Pipe type (DokanType_e). + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoOutWaterTank); ///< Leaving an area via a water tank pipe. @unused Argument: None. + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoRailDokan); ///< Transitioning between two rail pipes without leaving the area. Argument: None. + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoDown); ///< Death animation. Argument: See DemoDownArg_e. + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoNextGotoBlock); ///< Transition to a new area. Argument: Lower 8 bits: next goto ID, upper 8 bits: fader type (dFader_c::fader_type_e) + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoGoal); ///< Goal pole cutscene. Argument: Is Yoshi (@p bool). + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, DemoControl); ///< Cutscene controlling the player. Argument: See ControlDemoSubstate_e. virtual void initialDokanUnder(); virtual void initialDokanUper(); @@ -123,31 +637,34 @@ class daPlBase_c : public dActor_c { virtual void setFallDownDemo() {} virtual bool setDokanIn(DokanDir_e dir); virtual void initDemoOutDokan(); - virtual bool vf284(int); ///< @unofficial + virtual bool updateDemoKimePose(ClearType_e clearType); virtual void initDemoGoalBase(); virtual void executeDemoGoal_Run(); virtual void initializeDemoControl() {} - virtual void changeState(const sStateIDIf_c &, void *); - - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, None); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, Walk); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, Jump); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, SitJump); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, Fall); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, Land); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, Crouch); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, Slip); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, Turn); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, HipAttack); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, Swim); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, JumpDai); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, PlayerJumpDai); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, Funsui); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, Kani); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, Cloud); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, AnimePlay); - STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, WaitJump); + /// @brief Transitions to a new state with the given state ID and argument. + /// @param stateID The ID of the state to transition to. + /// @param arg An optional argument to pass to the new state. The type of this argument depends on the state being transitioned to. + virtual void changeState(const sStateIDIf_c &stateID, void *arg); + + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, None); ///< Default state, does nothing. Argument: None. + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, Walk); ///< Player on the ground. Argument: Blending mode (AnmBlend_e). + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, Jump); ///< Jumping. Argument: Jump information (jmpInf_c *). + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, SitJump); ///< Crouch jump. Argument: Should initiate jump (@p bool). + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, Fall); ///< Falling. Argument: Should play animation (@p bool). + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, Land); ///< Landing after a jump. Argument: @p bool [Unknown purpose, never read from]. + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, Crouch); ///< Crouching on the ground. Argument: See CrouchArg_e. + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, Slip); ///< Sliding down a slope. Argument: None. + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, Turn); ///< Turning around after running fast. Argument: None. + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, HipAttack); ///< Ground pounding. Argument: See HipAttackArg_e. + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, Swim); ///< Swimming. Argument: See SwimArg_e. + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, JumpDai); ///< Jumping on a spring. Argument: None. + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, PlayerJumpDai); ///< Jumping on a player. Argument: None. + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, Funsui); ///< Being blown upwards by a fountain. Argument: None. + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, Kani); ///< Moving on a cliff. Argument: See KaniArg_e. + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, Cloud); ///< Riding a cloud. Argument: None. + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, AnimePlay); ///< Playing a cutscene animation. Argument: See AnimePlayArg_e. + STATE_VIRTUAL_FUNC_DECLARE(daPlBase_c, WaitJump); ///< Doing a hop caused by a small quake. Argument: None. virtual bool isWaitFrameCountMax() { return false; } virtual bool checkWalkNextAction() { return false; } @@ -172,8 +689,8 @@ class daPlBase_c : public dActor_c { virtual void setRideJrCrownMtx(const mMtx_c *) {} virtual void setRideJrCrownAnm(int) {} - virtual float *getHeadTopPosP() { return nullptr; } - virtual float *getGravityData(); // { return mGravityData; } + virtual const mVec3_c *getHeadTopPosP() { return nullptr; } + virtual const float *getGravityData() { return mGravityData; } virtual bool isCarry() const { return false; } virtual bool isLiftUp() { return false; } @@ -183,21 +700,31 @@ class daPlBase_c : public dActor_c { virtual void endStar() {} virtual void setVirusStar(daPlBase_c *) {} virtual void clearStarCount(); - virtual s8 getStarCount() const; // { return mStarCount; } + virtual s8 getStarCount() const { return mStarCount; } virtual s8 calcStarCount(int); virtual bool isNoDamage(); virtual bool setDamage(dActor_c *, DamageType_e); virtual bool setForcedDamage(dActor_c *, DamageType_e); - virtual u32 vf3fc(float, float, int, int, int); ///< @unofficial - virtual u32 vf400(float, float, int, int, int); ///< @unofficial - virtual bool setWaitJump(float); + /** + * @brief Starts a jump action with the given parameters. + * Does not start a jump if the player is in a climbing state. + * @param jumpSpeed The vertical speed of the jump. + * @param speedF The @ref mSpeedF "forward speed". + * @param allowSteer Whether the player can steer in midair. + * @param keyMode The input settings for the jump. (0: none, 1: force jump pressed, 2: force jump not pressed) + * @param jumpMode The type of jump to perform. [TODO: document the jump modes] + */ + virtual bool setJump(float jumpSpeed, float speedF, bool allowSteer, int keyMode, int jumpMode); ///< @unofficial + /// @brief Starts a jump action unconditionally. See setJump(). + virtual bool _setJump(float jumpSpeed, float speedF, bool allowSteer, int keyMode, int jumpMode); ///< @unofficial + virtual bool setWaitJump(float jumpSpeed); virtual bool setHipAttackOnEnemy(mVec3_c *); virtual void clearJumpActionInfo(int) {} - virtual bool setSwimSpeed(float, float); + virtual bool setSwimSpeed(float speedY, float speedF); virtual void setLandSE(); virtual void set1UpKinokoEffect() {} @@ -209,8 +736,8 @@ class daPlBase_c : public dActor_c { virtual void setZPositionDirect(float); virtual void offZPosSetNone(); - virtual void vf434(int, int); ///< @unofficial - virtual void vf438(int, int); ///< @unofficial + virtual void startPlayerVoice(int, int); ///< @unofficial + virtual void holdPlayerVoice(int, int); ///< @unofficial virtual void startQuakeShock(dQuake_c::TYPE_SHOCK_e); virtual void startPatternRumble(const char *pattern); @@ -221,28 +748,576 @@ class daPlBase_c : public dActor_c { virtual bool setDamage2(dActor_c *, daPlBase_c::DamageType_e); - bool isMameAction(); + void executeState(); + + /// @brief Transitions to a new state with the given state ID and argument. + /// @param stateID The ID of the state to transition to. + /// @param arg An argument to pass to the new state. + void changeDemoState(const sStateIDIf_c &stateID, int arg); + + void onStatus(int id); ///< Enables the status with the given ID. See Status_e. + void offStatus(int id); ///< Disables the status with the given ID. See Status_e. + bool isStatus(int id); ///< Checks if the status with the given ID is active. See Status_e. + /// Enables the status with the given ID and disables all others. + /// @bug The implemententation of this is broken. Presumably this was written before + /// the status bits were split up into multiple bytes, because it only clears the bits in the byte + /// where the selected status bit is and leaves the other status bytes unchanged. + void setStatus(int id); + void calcPlayerSpeedXY(); + void posMoveAnglePenguin(mVec3_c, u16); + void posMoveAnglePlayer(mVec3_c); + bool setSandMoveSpeed(); + void calcWindSpeed(); + void calcHeadAttentionAngle(); + + void calcSpeedOnIceLift(); + void calcAccOnIceLift(); + bool checkStandUpRoofOnLift(); + bool checkStandUpRoof(); + + void gravitySet(); + void powerSet(); + void moveSpeedSet(); + void airPowerSet(); + void simpleMoveSpeedSet(); + void normalPowerSet(); + void grandPowerSet(); // [misspelling of "ground"] + void slipPowerSet(int); + void icePowerChange(int); + void getPowerChangeSpeedData(sPowerChangeSpeedData &data); ///< @unofficial + void getTurnPower(sTurnPowerData &); ///< @unofficial + PowerChangeType_e getPowerChangeType(bool affectPenguin); + const sSpeedData *getSpeedData(); + + int addCalcAngleY(short, short); + short getBesideMukiAngle(u8 direction); + void turnBesideAngle(); + bool checkTurn(); + void setTurnEnd(); + + void setJumpGravity(); + void setButtonJumpGravity(); + void setNormalJumpGravity(); + float setJumpAddSpeedF(float); + float setAddLiftSpeedF(); + bool setDelayHelpJump(); + bool setCrouchJump(); + bool checkJumpTrigger(); + bool startJump(AnmBlend_e blendMode, int jumpType); ///< @unofficial + + void setStampReduction(); + void setStampPlayerJump(bool b, float yOffset); + void calcReductionScale(); + mVec3_c getReductionModelScale(); + + bool setJumpDaiRide(); + bool setPlayerJumpDai(daPlBase_c *other); + void setPlayerJumoDaiPos(); + + bool setCloudOn(dActor_c *cloudActor); + void cancelCloudOn(); + mVec3_c getCloudPos(); + bool updateCloudMove(); + + bool setFunsui(); + bool updateFunsuiPos(float, float); + bool releaseFunsui(float); + + void setRideNat(float); + void updateRideNat(); + + bool isSaka(); + bool isSlipSaka(); + bool checkSakaReverse(); + bool checkSlip(); + bool checkCrouchSlip(); + bool checkSlipEndKey(); + float getSlipMaxSpeedF(); + float getSakaMaxSpeedRatio(u8 direction); + float getSakaStopAccele(u8 direction); + float getSakaMoveAccele(u8 direction); + float getIceSakaSlipOffSpeed(); + + void changeActionSlipEnd(AnmBlend_e); + void setSlipAction_ToStoop(); + void setSlipAction_ToEnd(); + void setSlipActionEnd(); + void setSlipActionViewLimitEnd(); + + void setHipAttackDropEffect(); + void setHipBlockBreak(); + void setHipAttack_Ready(); + void setHipAttack_KinopioStart(); + void setHipAttack_AttackFall(); + void setHipAttack_StandNormal(); + void setHipAttack_StandNormalEnd(); + void setHipAttack_ToStoop(); + void HipAction_Ready(); + void HipAction_AttackStart(); + void HipAction_AttackFall(); + void HipAction_Ground(); + void HipAction_StandNormal(); + void HipAction_StandNormalEnd(); + void HipAction_ToStoop(); + + void onFollowMameKuribo(); + void clearFollowMameKuribo(); + u32 getFollowMameKuribo(); + + bool isDemo(); + bool isControlDemoAll(); + bool isDemoAll(); + bool isDemoType(DemoType_e); + bool isDemoMode() const; + void onDemo(); + void offDemo(); + bool executeDemoState(); + + bool startControlDemo(); + void setControlDemoDir(u8); + bool isControlDemoWait(); + void setControlDemoWait(); + bool isControlDemoAnm(int); + void setControlDemoAnm(int); + bool isControlDemoWalk(); + void setControlDemoCutscene(AnimePlayArg_e animID); ///< @unofficial + void setControlDemoKinopioWalk(); + void setControlDemoKinopioSwim(); + void setControlDemoEndingDance(); + void setControlDemoWalk(const float &, const float &); + void endControlDemo(int); + + void initDemoInDokan(); + void initDemoInDokanUD(u8); + void initDemoInDokanLR(u8); + void executeDemoInDokan(u8); + void endDemoInDokan(); + bool setDemoOutDokanAction(int entranceNextGotoID, DokanDir_e dir); + void initDemoOutDokanUD(u8); + void initDemoOutDokanLR(u8); + void executeDemoOutDokanUD(); + void executeDemoOutDokanLR(); + void endDemoOutDokan(); + float getWaterDokanCenterOffset(float); + bool demo_dokan_move_x(float, float); + bool demo_dokan_move_y(float, float); + void setObjDokanIn(dBg_ctr_c *, mVec3_c &, int); + void setExitRailDokan(); + void setDemoOutNextGotoBlock(int nextGotoID, int delay, int fadeType); ///< @unofficial + + void stopGoalOther(); + void playGoalOther(); + void setDemoGoalMode(int, int); + void setDemoGoal_MultiJump(); + void finalizeDemoGoalBase(); + float getDemoGoalLandPos(); + void initGoalJump(mVec3_c &, float); + bool calcGoalJump(); + void executeDemoGoal_Pole(); + void executeDemoGoal_Wait(); + void executeDemoGoal_KimePose(); + bool setEnemyStageClearDemo(); + void updateEndingDance(); + void initDemoKimePose(); + + bool isBossDemoLand(); + void DemoAnmNormal(); + void DemoAnmBossSetUp(); + void DemoAnmBossGlad(); + void DemoAnmBossAttention(); + void DemoAnmBossKeyGet(); + + void setRunFootEffect(); + void setVsPlHipAttackEffect(); + void setLandSmokeEffect(int); + void setLandSmokeEffectLight(); + void setSandEffect(); + bool setSandJumpEffect(); + bool setSandFunsuiLandEffect(); + void setStartJumpEffect(int); + void setLandJumpEffect(int); + void setSlipOnWaterEffect(mEf::levelEffect_c *effect); + void setSlipSmokeEffect(); + void setBrakeSmokeEffect(mVec3_c &offset); + void setTurnSmokeEffect(); + void fadeOutTurnEffect(); + + void startKimePoseVoice(ClearType_e clearType); + void setSoundPlyMode(); + void setItemCompleteVoice(); + void startFootSoundPlayer(unsigned long); + void setFootSound(); + void setSlipSE(); + bool suppressSound(int suppressionMode); ///< @unofficial + void startSound(ulong soundID, bool); ///< @unofficial + void startSound(ulong soundID, short, bool); ///< @unofficial + void holdSound(ulong soundID, bool); ///< @unofficial + void holdSound(ulong soundID, short, bool); ///< @unofficial + + void initCollision(sCcDatNewF *dat1, sCcDatNewF *dat2); + void entryCollision(); + void releaseCcData(); + void clearCcData(); + void clearCcPlayerRev(); + int getCcLineKind(); + void setCcAtBody(int); + void setCcAtSlip(); + void setCcAtPenguinSlip(); + void setCcAtHipAttack(); + void setCcAtStar(); + void setCcAtCannon(); + bool isActionRevisionY(); + void setCcPlayerRev(dCc_c *, dCc_c *, float, int); + bool calcCcPlayerRev(float *); + bool isEnableStampPlayerJump(dCc_c *, dCc_c *); + + void bgCheck(int); + void setOldBGCross(); + void checkBgCross(); + bool checkInsideCrossBg(float); + void clearBgCheckInfo(); + bool isCarryObjBgCarried(u8 side); + bool checkBGCrossWall(u8 direction); + void checkDamageBg(); + bool setBgDamage(); + bool checkSinkSand(); + float getWaterCheckPosY(); + void checkWater(); + bool isHitWallKinopioWalk(int); + bool isHitGroundKinopioWalk(int, float, int); ///< @unofficial + bool checkKinopioWaitBG(int); + void underOverCheck(); + void checkDispOver(); + bool checkPressBg(); + bool isBgPress(dActor_c *); + bool isEnablePressUD(); + bool isEnablePressLR(); + void checkDisplayOutDead(); + void calcDispSideLimit(); ///< @unofficial + void setBgPressReq(dActor_c *, BgPress_e); + + bool isDispOutCheckOn(); + bool calcSideLimitMultL(float); + bool calcSideLimitMultR(float); + void checkSideViewLemit(); + bool checkDispSideLemit(); + bool revSideLimitCommon(float); + + void calcTimerProc(); + void changeNormalAction(); + void stopOther(); + void playOther(); + void setAutoBounce(); ///< @unofficial + void setExtraPushForce(float f); ///< @unofficial + + daPlBase_c *getHipAttackDamagePlayer(); + void setHipAttackDamagePlayer(daPlBase_c *player); + void clearHipAttackDamagePlayer(); + + void setNoHitPlayer(const daPlBase_c *, int); + void updateNoHitPlayer(); + void setNoHitObjBg(dActor_c *, int); + void calcNoHitObjBgTimer(); + + void clearTreadCount(); + s8 calcTreadCount(int); + void clearComboCount(); + s8 calcComboCount(int); + + dPyMdlBase_c *getModel(); mVec3_c getAnkleCenterPos(); + bool isMaskDraw(); + bool isMameAction(); + bool isPlayerGameStop(); + bool checkTimeOut(); + bool checkRideActor(daPlBase_c *other); + bool isRideCheckEnable(); + + // [Needed to place getOldStateID in the correct location] + const sStateIDIf_c &getOldState() { + return *mStateMgr.getOldStateID(); + } + + bool isState(sStateIDIf_c &id) { + return mStateMgr.getStateID()->isEqual(id); + } + + bool isDemoState(sStateIDIf_c &id) { + return mDemoStateMgr.getStateID()->isEqual(id); + } + + float calcSomeAccel(float f) { return 3.0f * f; } + void set_m_d80(int side, float f) { m_d80[side] = f; } + float getModelHeight() const { return mModelHeight; } + float getCcRevOffsX() const { return mCcRevTotalOffsX; } + float getCcRevOffsY() const { return mCcRevTotalOffsY; } + float getCcRevRate() const { return mCcRevRate; } + + u32 isNowBgCross(BgCross1_e m) { return mNowBgCross1 & m; } + u32 isNowBgCross(BgCross2_e m) { return mNowBgCross2 & m; } + void onNowBgCross(BgCross1_e m) { mNowBgCross1 |= m; } + void onNowBgCross(BgCross2_e m) { mNowBgCross2 |= m; } + void offNowBgCross(BgCross1_e m) { mNowBgCross1 &= ~m; } + void offNowBgCross(BgCross2_e m) { mNowBgCross2 &= ~m; } + void clearNowBgCross() { mNowBgCross1 = mNowBgCross2 = 0; } + + u32 isOldBgCross(BgCross1_e m) { return mOldBgCross1 & m; } + u32 isOldBgCross(BgCross2_e m) { return mOldBgCross2 & m; } + void onOldBgCross(BgCross1_e m) { mOldBgCross1 |= m; } + void onOldBgCross(BgCross2_e m) { mOldBgCross2 |= m; } + void offOldBgCross(BgCross1_e m) { mOldBgCross1 &= ~m; } + void offOldBgCross(BgCross2_e m) { mOldBgCross2 &= ~m; } + void clearOldBgCross() { mOldBgCross1 = mOldBgCross2 = 0; } + + bool isOnSinkSand() { return isNowBgCross(BGC_ON_SINK_SAND) | isNowBgCross(BGC_IN_SINK_SAND); } + bool wasOnSinkSand() { return isOldBgCross(BGC_ON_SINK_SAND) | isOldBgCross(BGC_IN_SINK_SAND); } - bool isStatus(int key); + float getDirSpeed() const { return sc_DirSpeed[mDirection]; } - float getAnkleCenterX() { return getAnkleCenterPos().x; } - float getAnkleCenterY() { return getAnkleCenterPos().y; } + PLAYER_TYPE_e getPlayerType() const { return mPlayerType; } + u8 getDirection() const { return mDirection; } + PLAYER_POWERUP_e getPowerup() const { return mPowerup; } - int getTreadCount() { return mTreadCount; } + void changeState(const sStateIDIf_c &stateID) { + changeState(stateID, 0); + } - daPlModel_c *getModel(); + template + void changeState(const sStateIDIf_c &stateID, T arg) { + changeState(stateID, (void *) arg); + } - char mPad1[0xc9e]; - float mSmallScoreOffset; - char mPad2[0x1]; + void changeDemoState(const sStateIDIf_c &stateID) { + changeDemoState(stateID, 0); + } + + template + T stateArg() const { + return (T) mStateArg; + } + + SquishState_e mSquishState; ///< The player's current squish state for being jumped on by another player. + int mSquishKeyframeIdx; ///< The current target index for the squishing animation keyframes. + float mSquishScale; ///< The current scale of the player during the squish animation. + int mSquishNoMoveTimer; ///< Timer for how long to freeze the squished player in position. + int mSquishCooldownTimer; ///< Cooldown for another player to squish this player. + + const daPlBase_c *mpNoHitPlayer; ///< The player that cannot collide with this player. + int mNoHitTimer; ///< Timer for how long the no-hit status lasts. + + u32 mBgPressActive; + u32 mBgPressFlags; + fBaseID_e mBgPressIDs[13]; ///< Index into this array with BgPress_e. + float mViewLimitPadding; + + KimePoseMode_e mKimePoseMode; + s8 mDemoState; /// Value is a ControlDemoState_e. + + int mDokanEnterNextGotoID; ///< The ID of the next-goto of the pipe being entered. + /// Position of the door or pipe the player is entering. + /// Also used as the target for the player running towards the castle after touching the goal pole. + mVec3_c mWarpPos; + mVec2_c mDokanMoveSpeed; ///< Direction to move the player while entering a rolling hill pipe or a rail pipe. + short mRollDokanAngle; + DemoDokanMode_e mDokanMode; + u8 mDokanDir; + dBg_ctr_c *mpDokanBgCtr; + /// Counts up while walking to the left, and allows the + /// player to enter a pipe when it reaches #sc_DokanEnterThreshold. + u8 mDokanCounterL; + /// Counts up while walking to the right, and allows the + /// player to enter a pipe when it reaches #sc_DokanEnterThreshold. + u8 mDokanCounterR; + float mDokanOffsetY; + float mDokanShiftXEpsilon; + short mRailDokanRailIndex; + short mRailDokanNextNodeTimer; + + int mGoalDemoIndex; ///< Indicates where the player is in the order of players which have touched the goal pole, 0 being the first. + int mGoalTouchOrder; + float mGoalPoleEndY; + int mTimer_a8; ///< [Seems unused - set to 0 when leaving a rolling hill]. + mVec3_c mGoalJumpTarget; + int mGoalJumpFrameCount; + + mVec3_c mControlDemoTargetPos; + float mControlDemoSpeedF; + int mItemKinopioDirection; + int mItemKinopioTurnTimer; + + int mBossDemoLandTimer; + int mEndingDanceKeyTimers[5]; + int mEndingDanceInactivityTimer; + + int mWalkAnmState; + int mTimer_f4; + int mSlipEndTimer; + s8 mAutoSlipTimer; + dEf::followEffect_c mTurnSmokeEffect; ///< The wind effect when turning around after running. + int mTurnGroundType; + u8 mTurnEffectFade; + mEf::levelEffect_c mHitAttackDropEffect; ///< The wind effect when doing a ground pound. + int m_344; ///< [Staff credit ground pound break related] + mVec3_c mJumpDaiOffset; ///< The difference vector between this player and the player being jumped on. + float mJumpDaiSpeedF; ///< The forward speed before doing a big jump. + /// Timer for disabling another big jump after being unable to do a big jump + /// due to colliding with a ceiling. + int mJumpDaiFallTimer; + + AnimePlayArg_e mDemoAnime; + + int mIsBeingDeleted; + + /// Effect when being sent upwards by a sand fountain, + /// also used for the wall slide, water run and death smoke effect. + mEf::levelEffect_c mSmokeEffect; + mEf::levelEffect_c mSlipSmokeEffect; ///< Smoke when sliding down a slope or into a cannon. + mEf::levelEffect_c mBrakeSmokeEffect; ///< Smoke when turning around after running. + mEf::levelEffect_c mRunEffect; ///< E.g. sand particles / snowflakes when running. + mEf::levelEffect_c mQuicksandSplashEffect; ///< Sand splash effect when landing on quicksand. + mEf::levelEffect_c mQuicksandSinkEffect; ///< Sand particles when the player is submerged in quicksand. + + dPyMdlMng_c *mpMdlMng; + dAudio::SndObjctPly_c mSndObj; + dAcPyKey_c mKey; + + fBaseID_e mRideActorID; + fBaseID_e mRelatedActorID; ///< Actor that is eating the player, or the door actor. + fBaseID_e mHipAttackPlayerID; + + u32 mStatusFlags[7]; + float mModelHeight; + u8 mPrevDirection; u8 mAmiLayer; - char mPad3[0x4a]; + u8 mPlayerLayer; + + mVec3_c mLastPosDelta; + mVec3_c mLiftRelatedPos; + float mPrevSpeedF; + float mPrevSpeedY; + float mTopHeight; ///< Stores the highest Y position reached, resets when landing on the ground again. + float mAirTopHeight; ///< The highest Y position since being on the ground last. Not reset when landing on the ground. + const sSpeedData *mSpeedDataNormal; + const sSpeedData *mSpeedDataStar; + const float *mGravityData; + + int mNoGravityTimer; + int mStarTimer; + int mDamageInvulnTimer; + int mPowerupChangeInvulnTimer; + int mTimer_ce8; ///< [Related to balloon break jump] + s8 mTreadCount; - s8 m_ced; - s8 m_cee; - char mPad4[0x52]; - u32 mFlags; - u8 mPad5[0x3b4]; + s8 mStarCount; + s8 mPlComboCount; + u32 mNewFollowMameKuribo; + u32 mFollowMameKuribo; + fBaseID_e mIceActorID; + PLAYER_POWERUP_e mPowerup; + sBcPointData mHeadBcData; + sBcPointData mFootBcData; + sBcPointData mWallBcData; + mVec3_c mBgPushForce; ///< Belts, quicksand etc. + float mExtraPushForceX; + + u32 mNowBgCross1, mNowBgCross2; + u32 mOldBgCross1, mOldBgCross2; + u32 mBgFootHistory[10]; + + u32 mStandOnUnitType; + u32 mPrevStandOnUnitType; + float m_d80[2]; + GroundType_e mGroundType; + + float m_d8c; + int mNoHitObjTimer; + + short mMoveSakaAngle; + short mPrevMoveSakaAngle; + short mStillSakaAngle; + short mPrevStillSakaAngle; + short mAdjacentSlopeAngle; + + int mAirWalkTimer; ///< Timer to wait before changing to the falling state after walking off a ledge. + + float mWaterHeight; + float mPrevWaterHeight; + int mWaterDepth; + float mSinkSandHeight; + bool mIsBgDamage; + s8 mBgDamageType; + u8 mWaterType; ///< Value is a dBc_c::WATER_TYPE_e. + mVec3_c mAirWaterHitPos; + short mAirWaterHitAngle; + float mKaniHeight; ///< The height of the last cliff the player interacted with. + float mRideNutHeight; + + dCc_c mCc1, mAttCc1, mAttCc2, mAttCc3; + float mCcRevSpeedF; + float mCcRevTotalOffsX; + float mCcRevTotalOffsY; + float mCcRevRate; ///< Multiplier for position revision for colliders. 1.0f moves to the target immediately. + bool mCcRevSet; + bool mCcHasInitialRevY; + int mCcRevDisabledTimer; + + u8 mIsDispLimitR; ///< Whether the player is too far to the right and should be pushed to the left. + u8 mIsDispLimitL; ///< Whether the player is too far to the left and should be pushed to the right. + float mDispLimitAdjR; ///< The distance by which the player is too far right. + float mDispLimitAdjL; ///< The distance by which the player is too far left. + + sFStateMgr_c mDemoStateMgr; ///< The state manager for demo (cutscene) states. + int mDemoStateArg; ///< To be used as an argument to the new demo state. + int mDemoSubstate; ///< Demo states can use this as a sub-state variable (cast to some enum) + /// Demo states can use this generic timer for various purposes. + /// It is automatically decrememented in executeState() every frame. + int mDemoSubstateTimer; + bool mIsDemoMode; ///< Whether the player is currently in a demo (cutscene) state. + + sFStateMgr_c mStateMgr; ///< The state manager for regular player states. + void *mStateArg; ///< To be used as an argument to the new state. + int mSubstate; ///< States can use this as a sub-state variable (cast to some enum). + /// States can use this generic timer for various purposes. + /// It is automatically decrememented in executeState() every frame. + int mSubstateTimer; + /// States can use this field for various purposes - as a timer, boolean flag, etc. + int mSubstateValue; + + mVec3_c mPressAttachPos; + + int mWindGroundTimer; + float mWindSpeed; + float mFinalAirPushForceX; + float m_1134; + float m_1138; + float m_113c; + + PLAYER_TYPE_e mPlayerType; + + static const float sc_DirSpeed[]; + static const float sc_JumpSpeed; + static const float sc_JumpSpeedNuma1; + static const float sc_JumpSpeedNuma2; + static const float sc_WaterWalkSpeed; + static const float sc_WaterSwimSpeed; + static const float sc_WaterJumpSpeed; + static const float sc_WaterMaxFallSpeed; + static const float sc_MaxFallSpeed; + static const float sc_MaxFallSpeed_Foot; + static const float sc_MaxFallDownSpeed; + static const float scTurnPowerUpRate; + static const float scDokanInSpeedX; + static const float scDokanInWidthX; + static const float scDokanInMoveSpeed; + static const float scDokanWaitAnmFixFrame; + + // [Inofficial constants] + + /// Number of walking frames before being able to enter a pipe. + /// @see mDokanCounterL, mDokanCounterR + static const int sc_DokanEnterThreshold = 10; + static const int sc_DemoWaitDuration = 10; ///< Number of frames to wait before transitioning from StateID_DemoWait. + static const int sc_DemoPoleWaitTurn = 5; ///< Number of frames to wait before turning towards the screen in the goal pole animation. + static const int sc_DemoPoleWaitEnd = 7; ///< Number of frames to wait before doing the course clear pose in the goal pole animation. }; diff --git a/include/game/bases/d_a_player_data.hpp b/include/game/bases/d_a_player_data.hpp new file mode 100644 index 00000000..311df6b8 --- /dev/null +++ b/include/game/bases/d_a_player_data.hpp @@ -0,0 +1,37 @@ +#pragma once + +/// @unofficial +struct sAirTurnPowerData { + float mNoButton; + float mStand; + float mSlowNoDash; + float mSlowDash; + float mMedium; + float mFast; + float mTurnAround; +}; + +/// @unofficial +struct sTurnPowerData { + float mNormal; + float mSakaUp; + float mSakaDown; + float mAir; +}; + +/// @unofficial +struct sPowerChangeData { + sAirTurnPowerData mAirPower[2]; + sTurnPowerData mTurnPowerNormal[2]; + sTurnPowerData mTurnPowerIce[2]; + sTurnPowerData mTurnPowerLowSlip[2]; + float mGravityData[2][18]; + float mGravityData2[18]; + float mJumpSpeedValues1[3]; + float mJumpSpeedValues2[4]; +}; + +/// @unofficial +namespace daPlayerData_c { + extern const sPowerChangeData smc_POWER_CHANGE_DATA; +} diff --git a/include/game/bases/d_a_player_demo_manager.hpp b/include/game/bases/d_a_player_demo_manager.hpp index cf69b3e0..39d1a6cb 100644 --- a/include/game/bases/d_a_player_demo_manager.hpp +++ b/include/game/bases/d_a_player_demo_manager.hpp @@ -1,9 +1,50 @@ #pragma once +#include +#include class daPyDemoMng_c { public: - char filler[0x80]; - int mPlNo; + enum Mode_e { + MODE_0, + MODE_1, + MODE_2 + }; + + void setCourseOutList(s8 playerNo); + void clearDemoNo(s8 playerNo); + bool checkDemoNo(s8 playerNo); + void turnNextDemoNo(); + int setGoalDemoList(int playerNo); + void setDemoMode(daPyDemoMng_c::Mode_e, int); + void stopBgmGoalDemo(); + int getPoleBelowPlayer(int playerNo); + int getControlDemoPlayerNum() const; + int getNextDemoNo(); + + char mPad1[0x10]; + u32 mFlags; + u32 mGoalType; + char mPad2[0x4]; + int m_1c; + char mPad3[0x22]; + bool m_42; + char mPad4[0x2]; + mVec3_c mFireworkPos; + char mPad5[0x8]; + int m_5c; + char mPad6[0x10]; + int m_70; + char mPad7[0xc]; + int mPlayerNo; + int m_84; + int m_88; + u8 mPad8[0x8]; + int m_94; + + int getPlrNo() const { return mPlayerNo; } + void setPlrNo(int playerNo) { mPlayerNo = playerNo; } + int get_88() const { return m_88; } + void inc_88() { m_88++; } static daPyDemoMng_c *mspInstance; }; diff --git a/include/game/bases/d_a_player_hio.hpp b/include/game/bases/d_a_player_hio.hpp new file mode 100644 index 00000000..981072eb --- /dev/null +++ b/include/game/bases/d_a_player_hio.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include + +/// @unofficial +struct sPowerChangeSpeedData { + float mDefaultAccel; + float mNoInputAccel; + float mTurnNoInputAccel; + float mTurnAccel; + float mVerySlowAccel; + float mSlowAccel; + float mRunSlowAccel; + float mMediumAccel; + float mFastAccel; +}; + +/// @unofficial +struct sSpeedData { + float mLowSpeed, mMediumSpeed, mHighSpeed; + sPowerChangeSpeedData mPowerChangeNormal; + sPowerChangeSpeedData mPowerChangeIce; + sPowerChangeSpeedData mPowerChangeLowSlip; +}; + +class dAcPy_HIO_Speed_c { +public: + dAcPy_HIO_Speed_c(); + ~dAcPy_HIO_Speed_c(); + + sSpeedData mDataNormal; + sSpeedData mDataStar; +}; diff --git a/include/game/bases/d_a_player_ice.hpp b/include/game/bases/d_a_player_ice.hpp new file mode 100644 index 00000000..ad456854 --- /dev/null +++ b/include/game/bases/d_a_player_ice.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include + +class daPlyIce_c : public dActor_c { +public: + void setRevivalBreakIce(); +}; diff --git a/include/game/bases/d_a_player_manager.hpp b/include/game/bases/d_a_player_manager.hpp index d254018e..c82490dc 100644 --- a/include/game/bases/d_a_player_manager.hpp +++ b/include/game/bases/d_a_player_manager.hpp @@ -1,5 +1,7 @@ #pragma once #include +#include +#include #include class daPyMng_c { @@ -8,7 +10,39 @@ class daPyMng_c { static int getPlayerIndex(PLAYER_TYPE_e); ///< @unofficial static dAcPy_c *getPlayer(int); static dAcPy_c *getCtrlPlayer(int); + static daYoshi_c *getYoshi(int); static void addScore(int, int); + static void setHipAttackQuake(int, u8); + static int getNumInGame(); + static int getItemKinopioNum(); + static dPyMdlMng_c::ModelType_e getCourseInPlayerModelType(u8); + static void setPlayer(int, dAcPy_c *); + static bool fn_8005f570(PLAYER_POWERUP_e, int); ///< @unofficial + static void setCarryOverYoshiInfo(u8 plrNo, u8 yoshiColor, int fruitCount); + static bool addNum(int); + static bool decNum(int); + static bool addRest(int); + static bool decRest(int); + static u32 getEntryNum(); + static bool isEntryNum1() { return getEntryNum() == 1; } + static void startYoshiBGM(); + static void stopYoshiBGM(); + static void startMissBGM(int plrNo); + static void startStarBGM(); + static void stopStarBGM(); + static bool isCreateBalloon(int plrNo); + static int getYoshiColor(u8 plrNo); + static int getYoshiFruit(u8 plrNo); + static daYoshi_c *createYoshi(mVec3_c &, int, dAcPy_c *); + + static bool isItemKinopio(int plrNo) { + bool res = false; + daPlBase_c *player = getPlayer(plrNo); + if (player != nullptr && player->isItemKinopio()) { + res = true; + } + return res; + } static bool checkPlayer(u8 plrNo) { return mActPlayerInfo & (1 << plrNo); } static int getRest(PLAYER_TYPE_e plrNo) { return mRest[plrNo]; } @@ -17,10 +51,20 @@ class daPyMng_c { static nw4r::math::VEC3 getPlayerSetPos(u8 file, u8 gotoNo); static int mNum; + static u32 mPauseDisable; static u8 mActPlayerInfo; - + static int mPauseEnableInfo; + static u32 mStopTimerInfo; static PLAYER_TYPE_e mPlayerType[4]; - static int mPlayerMode[4]; + static PLAYER_POWERUP_e mPlayerMode[4]; + static PLAYER_POWERUP_e mKinopioMode; + static int mKinopioCarryCount; + static u32 mCreateItem[4]; + static int mPlayerEntry[4]; static int mRest[4]; static u32 mCtrlPlrNo; + static s16 m_star_time[4]; + static s16 m_star_count[4]; + static int mAllBalloon; + static int mTimeUpPlayerNum; }; diff --git a/include/game/bases/d_a_yoshi.hpp b/include/game/bases/d_a_yoshi.hpp index ce03bae0..150a8268 100644 --- a/include/game/bases/d_a_yoshi.hpp +++ b/include/game/bases/d_a_yoshi.hpp @@ -1,11 +1,25 @@ #pragma once #include +#include class daYoshi_c : public daPlBase_c { public: - u8 mPad[0xa0]; + u8 mPad1[0x4c]; + int m_94; + u8 mPad2[0x8]; int m_a0; + u8 mPad3[0x30]; + int mFruitCount; - void getTongueTipMtx(mMtx_c *mtx); + dYoshiMdl_c *getModel() { return (dYoshiMdl_c *) daPlBase_c::getModel(); } + + int getFruitCount() const { return mFruitCount; } + + bool checkRideOffAble(); + void setRideOffPlayer(); + bool getTongueTipMtx(mMtx_c *mtx); + bool fn_8014f030(dAcPy_c *player); ///< @unofficial + bool fn_8014eb70(dAcPy_c *player, int); ///< @unofficial void getMouthMtx(mMtx_c *mtx); + daPlBase_c *getPlayerRideOn() const; }; diff --git a/include/game/bases/d_ac_py_key.hpp b/include/game/bases/d_ac_py_key.hpp index 9f3ffc51..d9b65370 100644 --- a/include/game/bases/d_ac_py_key.hpp +++ b/include/game/bases/d_ac_py_key.hpp @@ -8,8 +8,10 @@ class dAcPyKey_c { enum STATUS_e { STATUS_NO_INPUT = 0, ///< Disable all inputs. STATUS_DISABLE_LR = 1, ///< Disable left and right directional buttons. + STATUS_2 = 2, STATUS_FORCE_JUMP = 3, ///< Force the jump button to be pressed down. STATUS_FORCE_NO_JUMP = 4, ///< Force a jump input to be ignored. + STATUS_5 = 5, STATUS_SHAKE_COOLDOWN = 6, ///< Is in cooldown for shake events STATUS_DEMO = 7, ///< Do not use inputs from the remote. STATUS_FORCE_RIGHT = 8, ///< Override the input to always only be the right button. @@ -65,8 +67,8 @@ class dAcPyKey_c { void update(); ///< Call each frame to process the inputs. void updateEnd(); ///< Get the new button states for the next frame. - void onStatus(u16 status); ///< Enables a status flag. - void offStatus(u16 status); ///< Disables a status flag. + void onStatus(u16 status); ///< Enables a status flag. @p status is a STATUS_e. + void offStatus(u16 status); ///< Disables a status flag. @p status is a STATUS_e. void clearAllKey(); ///< Clears all input state. void clearCrossKey(); ///< Clears the left and right directional buttons. @@ -103,7 +105,7 @@ class dAcPyKey_c { bool checkHipAttack(); ///< Checks whether a hip attack should be performed this frame. - u8 triggerShakeJump() const; ///< Returns whether a shake event was triggered this frame. + int triggerShakeJump() const; ///< Returns whether a shake event was triggered this frame. void clearShakeJump(); ///< Clears the shake event state. bool triggerJumpBuf(int n); ///< Returns whether a jump occurred in the last n frames. diff --git a/include/game/bases/d_actor.hpp b/include/game/bases/d_actor.hpp index 68339530..02b73698 100644 --- a/include/game/bases/d_actor.hpp +++ b/include/game/bases/d_actor.hpp @@ -102,7 +102,7 @@ class dActor_c : public dBaseActor_c { virtual void block_hit_init(); ///< Callback for when a block directly beneath the actor is hit. virtual bool vf68(dBg_ctr_c *collider) { return true; } ///< Unknown, related to collision. @unofficial - virtual s8 *getPlrNo() { return &mPlayerNo; } ///< Gets the player number associated with the actor. See #mPlayerNo. + virtual s8 &getPlrNo() { return mPlayerNo; } ///< Gets the player number associated with the actor. See #mPlayerNo. virtual mVec2_c getLookatPos() const; ///< Gets the position players look to when focused on the actor. /// @brief Returns whether the actor can be carried. @@ -370,7 +370,7 @@ class dActor_c : public dBaseActor_c { int mAttentionMode; ///< @todo Document this field and its values. u32 mAttentionFlags; ///< @todo Document this field and its values. - dPropelParts_c *mPropelParts; ///< The actor's propeller effect manager. + dPropelParts_c *mpPropelParts; ///< The actor's propeller effect manager. u8 mKind; ///< The actor's kind. Value is a STAGE_ACTOR_KIND_e. s8 mPlayerNo; ///< The player associated with the actor, @p -1 if not associated to any player. u8 mExecStopMask; ///< The mask required to disable the @p execute operation for the actor. @@ -384,6 +384,18 @@ class dActor_c : public dBaseActor_c { mMaxBound.set(smc_CULL_XLIMIT, smc_CULL_YLIMIT, smc_CULL_AREA_XLIMIT, smc_CULL_AREA_YLIMIT); } + void setVisibleArea(const mVec2_POD_c &offset, const mVec2_POD_c &size) { + mVisibleAreaOffset.set(offset.x, offset.y); + mVisibleAreaSize.set(size.x, size.y); + } + + float getVisOffsetX() { return mVisibleAreaOffset.x; } + float getVisOffsetY() { return mVisibleAreaOffset.y; } + float getVisSizeX() { return mVisibleAreaSize.x; } + float getVisSizeY() { return mVisibleAreaSize.y; } + float getVisTop() { return mPos.y + getVisOffsetY() + getVisSizeY(); } + float getVisBottom() { return mPos.y + getVisOffsetY() - getVisSizeY(); } + u8 getKindMask() { return 1 << mKind; } static const float smc_CULL_XLIMIT; ///< The default @ref mMaxBound "max bound" X offset. diff --git a/include/game/bases/d_attention.hpp b/include/game/bases/d_attention.hpp index b50fc9c1..b7c253a8 100644 --- a/include/game/bases/d_attention.hpp +++ b/include/game/bases/d_attention.hpp @@ -1,9 +1,13 @@ #pragma once +#include #include +#include class dAttention_c { public: void entry(fBaseID_e id); + fBase_c *search(mVec3_c pos); + fBase_c *searchPlayer(const dActor_c *player, mVec3_c pos); static dAttention_c *mspInstance; }; diff --git a/include/game/bases/d_audio.hpp b/include/game/bases/d_audio.hpp index df01a041..f381ec13 100644 --- a/include/game/bases/d_audio.hpp +++ b/include/game/bases/d_audio.hpp @@ -1,5 +1,7 @@ #pragma once #include +#include +#include #include #include #include @@ -8,27 +10,263 @@ /// @ingroup bases -class NMSndObjectBase : nw4r::snd::SoundActor { - u32 mNumHandles; - u32 mRemotePlayer; - void * mSnd2DCalc; // TODO: Snd2DCalc * - u32 mObjType; +class Snd2DCalc { +public: + void fn_8019ee20(float &, nw4r::math::VEC2 &, unsigned long); +}; + +class NMSndObjectBase : public nw4r::snd::SoundActor { +public: + enum OBJ_TYPE { + OBJ_TYPE_0 = 0 + }; + + NMSndObjectBase(OBJ_TYPE, nw4r::snd::SoundArchivePlayer &); + virtual ~NMSndObjectBase(); + virtual u8 vf1C(ulong, int); + + bool sendRemote(nw4r::snd::SoundHandle *p, unsigned long p1, unsigned long p2); + + u32 getTotal() const { return mTotalCount; } + + u32 mTotalCount; + u32 m_58; + Snd2DCalc *mpSnd2dCalc; + OBJ_TYPE mObjType; }; template -class NMSndObject : NMSndObjectBase { +class NMSndObject : public NMSndObjectBase { +public: + class SoundHandlePrm : public nw4r::snd::SoundHandle { + public: + SoundHandlePrm() : m_04(1.0f) {} + + float m_04; + }; + + NMSndObject() : + NMSndObjectBase(NMSndObjectBase::OBJ_TYPE_0, SndAudioMgr::sInstance->mArcPlayer), + m_64(1.0f), m_68(0), m_6c(1.0f), m_70(0.0f) + { + SetPlayableSoundCount(0, T); + mTotalCount = T + 2; + m_58 = 1; + m_ac = T + 1; + m_b0 = T + 2; + m_b4 = 0; + } + + void processParams() { + for (int idx = 0; idx < mTotalCount; idx++) { + if (!mParams[idx].IsAttachedSound()) { + continue; + } + u32 flag = SndAudioMgr::sInstance->get3DCtrlFlag(mParams[idx].GetId()); + if (~flag & 1) { + mParams[idx].SetVolume(m_64, 0); + } else if ( + SndSceneMgr::sInstance->m_14 == 3 || + (SndSceneMgr::sInstance->m_14 == 2 && SndSceneMgr::sInstance->m_10 == 3) + ) { + mParams[idx].SetVolume(m_64, 0); + } + if (~flag & 8) { + nw4r::snd::SoundArchive::SoundInfo info; + SndAudioMgr::sInstance->mpSndArc->ReadSoundInfo(mParams[idx].GetId(), &info); + if (m_68 < 0) { + mParams[idx].SetPlayerPriority(info.playerPriority + m_68); + } else { + mParams[idx].SetPlayerPriority(info.playerPriority); + } + } + if (~flag & 2) { + mParams[idx].SetPan(m_70); + } + } + } + + void calc() { + for (int i = 0; i < T; i++) { + if (GetPlayingSoundCount(i) > 0) { + mpSnd2dCalc->fn_8019ee20(m_64, mPos, 0); + processParams(); + break; + } + } + } + + virtual void calc(const nw4r::math::VEC2 &pos) { + mPos = pos; + calc(); + } + + SoundHandlePrm *findHandle(int id) { + for (int i = 0; i < mTotalCount; i++) { + if (mParams[i].IsAttachedSound()) { + if (mParams[i].GetId() == id) { + return &mParams[i]; + } + } + } + return nullptr; + } + + SoundHandlePrm *getFreeHandle() { + for (int i = 0; i < mTotalCount; i++) { + if (!mParams[i].IsAttachedSound()) { + mParams[i].m_04 = 1.0f; + return &mParams[i]; + } + } + return nullptr; + } + + virtual SoundHandlePrm *startSound(unsigned long p1, unsigned long p2) { + SoundHandlePrm *p = getFreeHandle(); + if (p != nullptr) { + detail_StartSound(p, p1, 0); + if (!p->IsAttachedSound()) { + return nullptr; + } + sendRemote(p, p1, p2); + return p; + } + return nullptr; + } + virtual SoundHandlePrm *holdSound(unsigned long p1, unsigned long p2) { + SoundHandlePrm *p = findHandle(p1); + if (p == nullptr) { + p = getFreeHandle(); + } + if (p != nullptr) { + detail_HoldSound(p, p1, 0); + if (!p->IsAttachedSound()) { + return nullptr; + } + sendRemote(p, p1, p2); + return p; + } + return nullptr; + } + + virtual SoundHandlePrm *prepareSound(unsigned long p1, unsigned long p2) { + SoundHandlePrm *p = getFreeHandle(); + if (p != nullptr) { + detail_PrepareSound(p, p1, 0); + if (!p->IsAttachedSound()) { + return nullptr; + } + sendRemote(p, p1, p2); + return p; + } + return nullptr; + } + + virtual SoundHandlePrm *startSound(unsigned long p1, short p2, unsigned long p3) { + SoundHandlePrm *p = getFreeHandle(); + if (p != nullptr) { + detail_StartSound(p, p1, 0); + if (!p->IsAttachedSound()) { + return nullptr; + } + sendRemote(p, p1, p3); + if (SndAudioMgr::sInstance->mpSndArc->GetSoundType(p1) == 1) { + nw4r::snd::SeqSoundHandle handle(p); + handle.WriteVariable(0, p2); + } + return p; + } + return nullptr; + } + virtual SoundHandlePrm *holdSound(unsigned long p1, short p2, unsigned long p3) { + SoundHandlePrm *p = findHandle(p1); + if (p == nullptr) { + p = getFreeHandle(); + } + if (p != nullptr) { + detail_HoldSound(p, p1, 0); + if (!p->IsAttachedSound()) { + return nullptr; + } + sendRemote(p, p1, p3); + if (SndAudioMgr::sInstance->mpSndArc->GetSoundType(p1) == 1) { + nw4r::snd::SeqSoundHandle handle(p); + handle.WriteVariable(0, p2); + } + return p; + } + return nullptr; + } + + virtual SoundHandlePrm *startSound(unsigned long p1, const nw4r::math::VEC2 &p2, unsigned long p3) { + SoundHandlePrm *p = getFreeHandle(); + if (p != nullptr) { + detail_StartSound(p, p1, 0); + if (!p->IsAttachedSound()) { + return nullptr; + } + SndAudioMgr::sInstance->setSoundPosition(p, p2); + sendRemote(p, p1, p3); + return p; + } + return nullptr; + } + virtual SoundHandlePrm *holdSound(unsigned long p1, const nw4r::math::VEC2 &p2, unsigned long p3) { + SoundHandlePrm *p = findHandle(p1); + if (p == nullptr) { + p = getFreeHandle(); + } + if (p != nullptr) { + detail_HoldSound(p, p1, 0); + if (!p->IsAttachedSound()) { + return nullptr; + } + SndAudioMgr::sInstance->setSoundPosition(p, p2); + sendRemote(p, p1, p3); + return p; + } + return nullptr; + } + + float m_64; + int m_68; + float m_6c; + float m_70; + SoundHandlePrm mParams[T + 2]; + nw4r::math::VEC2 mPos; + u32 m_ac; + u32 m_b0; + u8 m_b4; +}; + +class SndObjctPly : public NMSndObject<4> { public: - virtual void startSound(unsigned long, const nw4r::math::VEC2 &, unsigned long); + void calculate(const nw4r::math::VEC2 &pos) { + NMSndObject<4>::calc(pos); + } + + virtual SoundHandlePrm *startSound(ulong p1, ulong p2); + virtual SoundHandlePrm *holdSound(ulong p1, ulong p2); + virtual SoundHandlePrm *startSound(ulong p1, short p2, ulong p3); + virtual SoundHandlePrm *holdSound(ulong p1, short p2, ulong p3); + virtual SoundHandlePrm *startSound(ulong p1, const nw4r::math::VEC2 &p2, ulong p3); + virtual SoundHandlePrm *holdSound(ulong p1, const nw4r::math::VEC2 &p2, ulong p3); + + void stopPlyJumpSound(); + void startFootSound(ulong, float, ulong); + void fn_8019AAB0(ulong, int); + void fn_8019ABB0(ulong, int); }; class SndObjctCmnEmy : public NMSndObject<4> { public: - virtual void startSound(unsigned long, const nw4r::math::VEC2 &, unsigned long); + virtual SoundHandlePrm *startSound(unsigned long, const nw4r::math::VEC2 &, unsigned long); }; class SndObjctCmnMap : public NMSndObject<4> { public: - virtual void startSound(unsigned long, const nw4r::math::VEC2 &, unsigned long); + virtual SoundHandlePrm *startSound(unsigned long, const nw4r::math::VEC2 &, unsigned long); }; namespace dAudio { @@ -41,11 +279,36 @@ namespace dAudio { void loadSceneSnd(); bool isLoadedSceneSnd(); void FUN_8006a6a0(bool); ///< @unofficial + bool isBgmAccentSign(u8); + void pauseOffMove(int); + void pauseMove(int); int getRemotePlayer(int); mVec2_c cvtSndObjctPos(const mVec2_c &); mVec2_c cvtSndObjctPos(const mVec3_c &); + class SndObjctPlyBase_c : public SndObjctPly { + }; + + class SndObjctPly_c : public SndObjctPlyBase_c { + public: + virtual SoundHandlePrm *startSound(ulong p1, ulong p2) { + return SndObjctPly::startSound(p1, p2); + } + + virtual SoundHandlePrm *startSound(ulong p1, short p2, ulong p3) { + return SndObjctPly::startSound(p1, p2, p3); + } + + virtual SoundHandlePrm *holdSound(ulong p1, ulong p2) { + return SndObjctPly::holdSound(p1, p2); + } + + virtual SoundHandlePrm *holdSound(ulong p1, short p2, ulong p3) { + return SndObjctPly::holdSound(p1, p2, p3); + } + }; + class SndObjctCmnEmy_c : SndObjctCmnEmy { public: void startSound(unsigned long soundID, const nw4r::math::VEC2 &pos, int remPlayer) { diff --git a/include/game/bases/d_base_actor.hpp b/include/game/bases/d_base_actor.hpp index 7376b71c..03ebf735 100644 --- a/include/game/bases/d_base_actor.hpp +++ b/include/game/bases/d_base_actor.hpp @@ -110,10 +110,18 @@ class dBaseActor_c : public dBase_c { */ static dBaseActor_c *construct(ProfileName profName, dBase_c *parent, unsigned long param, const mVec3_c *position, const mAng3_c *rotation); + // Getters / setters + float getCenterX() const { return mPos.x + mCenterOffs.x; } float getCenterY() const { return mPos.y + mCenterOffs.y; } float getCenterZ() const { return mPos.z + mCenterOffs.z; } + float getSpeedF() const { return mSpeedF; } + float getAccelF() const { return mAccelF; } + void setAccelF(float accelF) { mAccelF = accelF; } + float absSpeedF() { return std::fabs(mSpeedF); } + float absMaxSpeedF() { return std::fabs(mMaxSpeedF); } + private: /** * @brief Sets temporary data to be used for the next actor's construction. diff --git a/include/game/bases/d_bc.hpp b/include/game/bases/d_bc.hpp index 6429e1b5..225c23cc 100644 --- a/include/game/bases/d_bc.hpp +++ b/include/game/bases/d_bc.hpp @@ -29,6 +29,52 @@ struct sBcSensorLine { }; class dBg_ctr_c; +class dBcSensor_c { +public: + u32 mFlags; + int mOffsetX; + int mOffsetY; +}; + +/// @unofficial +class sBcPointData { +public: + operator const sBcSensorBase *() const { return (sBcSensorBase *) &mFlags; } + + u32 mFlags; + long mInfMargin; + long mSupMargin; + long mOffset; +}; + +/// @unofficial +class sBcPlayerPointData { +public: + sBcPointData mFoot; + sBcPointData mHead; + sBcPointData mWall; + sBcPointData mVine; +}; + +class dBg_ctr_c { +public: + dActor_c *mpActor; + u8 mPad1[0x9c]; + mVec2_c m_a0; + mVec2_c m_ac; + u8 mPad2[0xc]; + short *mRotation; + short m_c0; + short m_c2; + u8 mPad4[0x4]; + int m_c8; + u32 mFlags; + int m_d0; + u8 mpPad5[0xc]; + int m_e0; + + void addDokanMoveDiff(mVec3_c *); +}; class dBc_c { public: @@ -87,23 +133,50 @@ class dBc_c { dBc_c(); virtual ~dBc_c(); + void init(); void set(dActor_c *, const sBcSensorBase *, const sBcSensorBase *, const sBcSensorBase *); ///< @unofficial void checkLink(); bool checkRide(); - bool checkHead(ulong); + bool checkHead(unsigned long); s16 getSakaAngle(u8); - int getSakaMoveAngle(u8); + s16 getSakaMoveAngle(u8); Flag_e checkWall(float *); Flag_e checkWallEnm(float *); Flag_e checkFoot(); Flag_e checkFootEnm(); + u16 getWallAttr(int); u16 getFootAttr(); + u32 checkCollision(sBcPointData *); ///< @unofficial + u32 checkCollision2(sBcPointData *); ///< @unofficial + bool hasSensorFoot() { return mpSensorFoot != nullptr; } bool hasSensorHead() { return mpSensorHead != nullptr; } bool hasSensorWall() { return mpSensorWall != nullptr; } + bool checkRoofPlayer(const mVec3_c *, float *); + u32 getSakaDir(); + int checkDokanLR(mVec3_c *, u8, int *, float, float); + int checkDokanDown(mVec3_c *, int *); + int checkDokanUp(mVec3_c *, int *); + void setRideOnObjBg(dBg_ctr_c *, const mVec3_c &); + bool checkWallPlayer(const mVec3_c *, const mVec3_c *, float *); + u32 checkBgPlr(dActor_c *); + u16 getHeadAttr(); + short getHeadSakaMoveAngle(u8 direction); + void clearBgcSaveAll(); + + bool getSakaUpDown(u8 direction); + short getSakaAngleBySpeed(float); + int getSakaType(); + + u32 isWallR() { return mFlags & FLAG_WALL_R; } + u32 isWallL() { return mFlags & FLAG_WALL_L; } + u32 isFoot(); // { return mFlags & FLAG_FOOT; } + u32 isHead() { return mFlags & FLAG_HEAD; } + u32 isCollision() { return mFlags & (FLAG_WALL_L | FLAG_WALL_R | FLAG_FOOT | FLAG_HEAD); } + dActor_c *mpOwner; sBcSensorBase *mpSensorFoot; sBcSensorBase *mpSensorHead; @@ -119,11 +192,11 @@ class dBc_c { float m_48; float m_4c; dRc_c *mpRc; - dActor_c *mFriendActor; - dBg_ctr_c *mCollidedBelow; - dBg_ctr_c *mCollidedAbove; - dBg_ctr_c *mCollidedAdj; - dBg_ctr_c *mCollidedAdjForDirection[2]; + dActor_c *mpNoHitActor; + dBg_ctr_c *mpCtrHead; + dBg_ctr_c *mpCtrFoot; + dBg_ctr_c *mpCtrWall; + dBg_ctr_c *mpCtrWalls[2]; dBc_c *mPrevTrigBelowSensor; dBc_c *mPrevTrigAboveSensor; dBc_c *mPrevTrigAdjSensor; @@ -131,9 +204,26 @@ class dBc_c { dBg_ctr_c *mLinkW[2]; u32 mFlags; u32 mPrevFlags; - char pad3[0x55]; + u32 mLastUnitType; + u32 mLastUnitKind; + s8 mOwningPlrNo; + s8 mRidePlrNo; + char mPad5[0x22]; + u8 mPlayerFlags; + char mPad6[0x4]; + int m_c4; + mAng mAdjacentSlopeAngle; + int mFenceType; + dBg_ctr_c *mpFenceCollision; + char mPad7[0x8]; + float mIceSpeed; + bool m_e0; + u8 m_e1; + u8 m_e2; + bool mMovingLeft; + bool mGrounded; u8 mAmiLine; - char pad4[0x2]; + char mPad9[0x2]; u8 *mpLayer; u8 mLayer; @@ -142,13 +232,14 @@ class dBc_c { static u32 checkBg(float, float, u8, u8, unsigned long); static u32 checkWireNet(float x, float y, unsigned char layer); - static u32 checkGround(const mVec3_c *, float *, u8, u8, signed char); + static u32 checkGround(const mVec3_c *, float *, u8, u8, s8); + static u32 checkGround(const mVec3_c *, float *, int *, u8, u8, s8); + static bool checkGroundAngle(const mVec3_c *, float *, s16 *, u8, u8, s8, int *, int); + static u32 checkGroundHalf(const mVec3_c *, float *, u8, u8); static u32 checkTenjou(const mVec3_c *, float *, u8, u8); - static u32 checkWall(const mVec3_c *, const mVec3_c *, float *, u8, u8, dActor_c **); - - u32 isWallR() { return mFlags & FLAG_WALL_R; } - u32 isWallL() { return mFlags & FLAG_WALL_L; } - u32 isFoot(); // { return mFlags & FLAG_FOOT; } - u32 isHead() { return mFlags & FLAG_HEAD; } - u32 isCollision() { return mFlags & (FLAG_WALL_L | FLAG_WALL_R | FLAG_FOOT | FLAG_HEAD); } + static u32 checkWall(const mVec3_c *, const mVec3_c *, float *p_hit_x, u8 layer, u8, dActor_c **p_hit_actor); + static void getAirWaterHitPos(mVec2_c *); + static void getAirWaterHitAngle(short *); + static u32 getUnitType(float x, float y, u8); + static u32 getUnitKind(float x, float y, u8); }; diff --git a/include/game/bases/d_bg.hpp b/include/game/bases/d_bg.hpp index c01f9f22..526d4dff 100644 --- a/include/game/bases/d_bg.hpp +++ b/include/game/bases/d_bg.hpp @@ -1,21 +1,44 @@ #pragma once -#include +#include class dBg_c { + class dBg_autoScroll_c { + public: + dBg_autoScroll_c() {} + ~dBg_autoScroll_c() {} + + mVec3_c mPos; + float m_0c; + float m_10; + u8 m_14, m_15, m_16, m_17; + u8 m_18; + bool m_19; + bool mActive; + }; + public: - char mPad1[0x8fea0]; + u8 mPad1[0x8fe70]; + float m_8fe00; + u8 mPad2[0x2c]; float mLoopOffset; - u8 mPad2[0x20]; + u8 mPad3[0x20]; float mLiquidHeight; - u8 mPad3[0x144]; + u8 mPad4[0x144]; float mDispScale; float m_8ffa8; float mPrevDispScale; - + u8 mPad5[0x61]; + u8 m_90009; + u8 mPad6[0x30]; + dBg_autoScroll_c mAutoscrolls[2]; + u8 mPad7[0x1a]; + u8 m_9008e; float getLiquidHeight() const { return mLiquidHeight; } void setWaterInWave(float x, float y, u8 type); + float getLeftLimit(); + float getRightLimit(); float getDispScale() { return mDispScale; } float getPrevDispScale() { return mPrevDispScale; } diff --git a/include/game/bases/d_bg_parameter.hpp b/include/game/bases/d_bg_parameter.hpp index 2585f863..0fc1f72a 100644 --- a/include/game/bases/d_bg_parameter.hpp +++ b/include/game/bases/d_bg_parameter.hpp @@ -23,10 +23,13 @@ class dBgParameter_c { u8 mPad1[0x38]; mVec2_c mPos; mVec2_c mSize; - u8 mPad2[0x38]; + float m_48; + u8 mPad2[0x34]; u8 mScrollDirX; ///< See BG_SCROLL_DIR_X_e. u8 mScrollDirY; ///< See BG_SCROLL_DIR_Y_e. + float getLoopScrollDispPosX(float x); + const mVec2_c &pos() const { return mPos; } const mVec2_c &size() const { return mSize; } diff --git a/include/game/bases/d_cc.hpp b/include/game/bases/d_cc.hpp index af043adf..4506ad95 100644 --- a/include/game/bases/d_cc.hpp +++ b/include/game/bases/d_cc.hpp @@ -43,7 +43,8 @@ enum CC_KIND_e { CC_KIND_ITEM, CC_KIND_TAMA, CC_KIND_KILLER, - CC_KIND_GOAL_POLE + CC_KIND_GOAL_POLE, + CC_KIND_COUNT = CC_KIND_GOAL_POLE // Goal pole is special and doesn't count }; ///< @unofficial @@ -70,21 +71,26 @@ enum CC_ATTACK_e { CC_ATTACK_YOSHI_BULLET, CC_ATTACK_YOSHI_FIRE, CC_ATTACK_ICE_2, - CC_ATTACK_SAND_PILLAR + CC_ATTACK_SAND_PILLAR, + CC_FLAG_ATTACK_ALL = 0xFFFFFFFF }; class dCc_c; -/** -* @brief A structure that contains information about a collider. -* @unofficial -*/ -struct sCcDatNewF { +struct sCcDatNew { mVec2_POD_c mOffset; ///< The offset of the collider. ///< @brief The size of the collider. ///< Note: This is the distance from the center to the edge, so half the actual size. mVec2_POD_c mSize; +}; + +/** +* @brief A structure that contains information about a collider. +* @unofficial +*/ +struct sCcDatNewF { + sCcDatNew mBase; ///< Base collider data. u8 mKind; ///< The type of this collider. See CC_KIND_e. u8 mAttack; ///< The attack type of this collider. See CC_ATTACK_e. @@ -250,6 +256,9 @@ class dCc_c { static bool _hitCheckDaikeiLR(dCc_c *ccTrp, dCc_c *ccBox); public: + float getXOffset(int idx) { return mCollOffsetX[idx]; } + float getYOffset(int idx) { return mCollOffsetY[idx]; } + dActor_c *mpOwner; ///< The actor this collider belongs to. dActor_c *mFriendActor; ///< A second actor that this collider will not collide with. @@ -274,17 +283,17 @@ class dCc_c { /** * @brief The X offset for a collision. * - * One entry per category. Each entry describes by how much the collider must be + * One entry per kind. Each entry describes by how much the collider must be * offset in the X direction in order to not collide with the other collider. */ - float mCollOffsetX[8]; + float mCollOffsetX[CC_KIND_COUNT]; /** * @brief The Y offset for a collision. * - * One entry per category. Each entry describes by how much the collider must be + * One entry per kind. Each entry describes by how much the collider must be * offset in the Y direction in order to not collide with the other collider. */ - float mCollOffsetY[8]; + float mCollOffsetY[CC_KIND_COUNT]; mVec2_c mCollPos; ///< The position where the last collision occurred. @@ -314,6 +323,7 @@ class dCc_c { private: bool mIsLinked; ///< Whether this collider has been placed in the collider list. +private: typedef bool (*hitCheck)(dCc_c *, dCc_c *); /** diff --git a/include/game/bases/d_cd_data.hpp b/include/game/bases/d_cd_data.hpp index 038b94b5..bdf71268 100644 --- a/include/game/bases/d_cd_data.hpp +++ b/include/game/bases/d_cd_data.hpp @@ -50,11 +50,25 @@ struct sBgData { u8 mPad[0x16]; }; +/// @unofficial +enum NextGotoFlags_e { + NEXT_GOTO_RAIL_REVERSE = BIT_FLAG(0), + NEXT_GOTO_WATER_TANK = BIT_FLAG(2), + NEXT_GOTO_RAIL = BIT_FLAG(3) +}; + /// @unofficial struct sNextGotoData { u8 mPad1[0x8]; u8 mID; - u8 mPad2[0xb]; + u8 mDestFile; + u8 mDestID; + u8 mType; + u8 mPad3[2]; + u8 mLayer; + u8 mRailID; + u16 mFlags; ///< See NextGotoFlags_e. + u8 mPad4[0x2]; }; /// @unofficial diff --git a/include/game/bases/d_effect.hpp b/include/game/bases/d_effect.hpp new file mode 100644 index 00000000..caf968d5 --- /dev/null +++ b/include/game/bases/d_effect.hpp @@ -0,0 +1,25 @@ +#pragma once +#include + +namespace dEf { +class followEffect_c : public mEf::effect_c { +public: + followEffect_c() {} + virtual ~followEffect_c() {} +}; + +class dLevelEffect_c : public mEf::levelEffect_c { +public: + dLevelEffect_c() {} + virtual ~dLevelEffect_c() {} + virtual bool isActive(); +}; + +void createPlayerEffect(int, char const *, unsigned long, const mVec3_c *, const mAng3_c *, const mVec3_c *); +void createPlayerEffect(int, mEf::levelEffect_c *, char const *, unsigned long, const mVec3_c *, const mAng3_c *, const mVec3_c *); +void createPlayerEffect(int, dEf::followEffect_c *, char const *, unsigned long, const mVec3_c *, const mAng3_c *, const mVec3_c *); +void createPlayerEffect_change(int, char const *, unsigned long, const mVec3_c *, const mAng3_c *, const mVec3_c *); +void createPlayerEffect_change(int, mEf::levelEffect_c *, char const *, unsigned long, const mVec3_c *, const mAng3_c *, const mVec3_c *); +void createPlayerEffect_change(int, dEf::followEffect_c *, char const *, unsigned long, const mVec3_c *, const mAng3_c *, const mVec3_c *); + +} // namespace dEf diff --git a/include/game/bases/d_enemy.hpp b/include/game/bases/d_enemy.hpp index 99bef027..bc2dd3bd 100644 --- a/include/game/bases/d_enemy.hpp +++ b/include/game/bases/d_enemy.hpp @@ -220,7 +220,7 @@ class dEn_c : public dActorMultiState_c { virtual void yoshifumiEffect(dActor_c *actor); void fumistepSE(dActor_c *actor); void yoshifumistepSE(dActor_c *actor); - void PlayerFumiJump(dActor_c *actor, float); + void PlayerFumiJump(dActor_c *actor, float jumpSpeed); void setFumiComboScore(dActor_c *actor); // Nonvirtuals diff --git a/include/game/bases/d_enemy_manager.hpp b/include/game/bases/d_enemy_manager.hpp index 1b2053ef..2573dfa3 100644 --- a/include/game/bases/d_enemy_manager.hpp +++ b/include/game/bases/d_enemy_manager.hpp @@ -7,11 +7,15 @@ class dEnemyMng_c { public: void breakdownSE(int, const mVec3_c &); void incQuakeComboCount(int); + void createRevivalBallon(mVec3_c &, int, int); + void demo_ivy_create(mVec3_c *); u8 mPad1[0x138]; int m_138; u8 mPad2[0x18]; int m_154; + u8 mPad3[0x4]; + int m_15c; static dEnemyMng_c *m_instance; }; diff --git a/include/game/bases/d_fader.hpp b/include/game/bases/d_fader.hpp index 31bbe49b..55fd4e2d 100644 --- a/include/game/bases/d_fader.hpp +++ b/include/game/bases/d_fader.hpp @@ -6,7 +6,12 @@ class dFader_c : public mFader_c { public: enum fader_type_e { - FADE + FADER_FADE, + FADER_CIRCLE_MIDDLE, + FADER_BOWSER, + FADER_DRIP_DOWN, + FADER_MARIO, + FADER_CIRCLE_TARGET }; static void setFader(fader_type_e type); diff --git a/include/game/bases/d_game_com.hpp b/include/game/bases/d_game_com.hpp index 7f0a9294..4fe0bde5 100644 --- a/include/game/bases/d_game_com.hpp +++ b/include/game/bases/d_game_com.hpp @@ -18,6 +18,7 @@ namespace dGameCom { void initRandomSeed(); ///< Initializes the random seed used for randomness. u32 getRandomSeed(); ///< Gets a seed used for randomness. int rndInt(size_t max); + float rnd(); //////////////////// // Game Pause API // @@ -80,6 +81,8 @@ namespace dGameCom { /// @param fukidashiAction The action prompt type to be hidden. void hideFukidashiForSession(int playerId, int fukidashiAction); + void fn_800b37b0(int playerId, int fukidashiAction); ///< @unofficial + //////////////// // Other APIs // //////////////// @@ -90,6 +93,7 @@ namespace dGameCom { void Player1upColor(LytTextBox_c *, int); void getGlbPosToLyt(mVec3_c &); bool someCheck(mVec3_c *a, sRangeDataF *b); ///< @unofficial + void FUN_800b3780(int, int); ///< @unofficial bool checkRectangleOverlap(mVec3_c *, mVec3_c *, mVec3_c *, mVec3_c *, float); ///< @unofficial diff --git a/include/game/bases/d_game_key.hpp b/include/game/bases/d_game_key.hpp index 25119029..44e3e182 100644 --- a/include/game/bases/d_game_key.hpp +++ b/include/game/bases/d_game_key.hpp @@ -37,5 +37,15 @@ class dGameKey_c { return mRemocon[plNo]->getAccVerticalAngleX() / 65536; } + // [These two functions must have different types to match] + + bool checkButtonsDown(s32 i) { + return mRemocon[i]->mDownButtons != 0; + } + + bool checkShaking(u32 i) { + return mRemocon[i]->mIsShaking != 0; + } + static dGameKey_c *m_instance; }; diff --git a/include/game/bases/d_info.hpp b/include/game/bases/d_info.hpp index 0a96b22a..d6f0c0b3 100644 --- a/include/game/bases/d_info.hpp +++ b/include/game/bases/d_info.hpp @@ -12,7 +12,7 @@ class dInfo_c { u8 mEntrance; u8 mArea; bool mIsReplay; - u32 mScreenType; + int mScreenType; u8 mWorld1; u8 mLevel1; u8 mWorld2; @@ -50,27 +50,29 @@ class dInfo_c { dCyuukan_c mCyuukan; char pad2[0x18]; int m_54; - u8 pad3[0x44]; + u8 pad3[0x14]; + bool m_6c; + u8 pad4[0x2c]; int m_9c; - u8 pad4[0x2e4]; + u8 pad5[0x2e4]; int mCharIDs[4]; bool mIsWorldSelect; ///< Whether the World Select Menu is being displayed. - u8 pad5[30]; - bool mClearCyuukan; ///< Clear the checkpoint data if this is @p true. [Used for the backdoor entrance of 7-C] + u8 pad6[0x1e]; + bool mClearCyuukan; int mDisplayCourseWorld; int mDisplayCourseNum; - u8 pad6[0x14]; + u8 pad7[0x14]; int mTextBoxMessageID; int mTextBoxMessageGroup; - u8 pad7[0x1]; + u8 pad8[0x1]; bool mExtensionAttached; u8 m_3da; - u8 pad8[0x7]; + u8 pad9[0x7]; int mCourseSelectPageNum; int mCourseSelectIndexInPage; - u8 pad9[0x712]; + u8 pad10[0x712]; bool mFukidashiActionPerformed[4][0x16]; - u32 pad10; + u32 pad11; static dInfo_c *m_instance; static unsigned int mGameFlag; ///< See GAME_FLAG_e diff --git a/include/game/bases/d_mario_mdl.hpp b/include/game/bases/d_mario_mdl.hpp new file mode 100644 index 00000000..e5796d93 --- /dev/null +++ b/include/game/bases/d_mario_mdl.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include + +class dMarioMdl_c : public dPyMdlBase_c { +public: + void fn_800cab00(int); ///< @unofficial +}; diff --git a/include/game/bases/d_mask_manager.hpp b/include/game/bases/d_mask_manager.hpp new file mode 100644 index 00000000..41998900 --- /dev/null +++ b/include/game/bases/d_mask_manager.hpp @@ -0,0 +1,6 @@ +#pragma once + +class dMaskMng { +public: + static bool isCaveMask(); +}; diff --git a/include/game/bases/d_next.hpp b/include/game/bases/d_next.hpp new file mode 100644 index 00000000..4f68a0a9 --- /dev/null +++ b/include/game/bases/d_next.hpp @@ -0,0 +1,16 @@ +#pragma once +#include +#include + +class dNext_c { +public: + bool fn_800cfed0(u8, u8); + void setChangeSceneNextDat(u8 file, u8 nextGotoID, dFader_c::fader_type_e faderType); + bool searchNextNum(u8, float, float, int *); + + u8 mPad1[0x18]; + bool m_18; + bool m_19; + + static dNext_c *m_instance; +}; diff --git a/include/game/bases/d_pc.hpp b/include/game/bases/d_pc.hpp new file mode 100644 index 00000000..c870f86e --- /dev/null +++ b/include/game/bases/d_pc.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include + +class dActor_c; + +class dPole_ctr_c { +public: + u8 mPad1[0x8]; + dPole_ctr_c *mpPrev; + dPole_ctr_c *mpNext; + u8 mPad2[0x10]; + u8 m_20; + bool m_21; + int m_24; + mVec3_c *m_28; + u8 mPad[0x8]; + short m_34[4]; +}; + +class dPc_c { +public: + dPc_c() : mpCtr(0) {} + virtual ~dPc_c() {} + + void release(); + bool check(int); + void set(dActor_c *, u8); + void set(int); + void chkTimer(); + + short getAngle() const; + mVec2_c getPos() { return m_14; } + + void move(float); + + dActor_c *mpOwner; + u8 mPad1[0x4]; + dPole_ctr_c *mpCtr; + dPole_ctr_c *mpCtr2; + mVec2_c m_14; + u8 mPad2[0xe]; + u8 m_2a; + u8 mPad3[0x2]; + u8 m_2d; + mVec3_c m_30; +}; diff --git a/include/game/bases/d_player_effect_manager.hpp b/include/game/bases/d_player_effect_manager.hpp new file mode 100644 index 00000000..21d94f43 --- /dev/null +++ b/include/game/bases/d_player_effect_manager.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include + +class dPyEffectMng_c { +public: + void fn_800d2de0(float, int, mVec3_c &, u8); ///< @unofficial + + static dPyEffectMng_c *mspInstance; +}; diff --git a/include/game/bases/d_player_model_base.hpp b/include/game/bases/d_player_model_base.hpp new file mode 100644 index 00000000..5c3f789c --- /dev/null +++ b/include/game/bases/d_player_model_base.hpp @@ -0,0 +1,97 @@ +#pragma once + +#include +#include +#include + +class dAcPy_c; + +class dPyMdlBase_c { +public: + virtual ~dPyMdlBase_c(); + virtual int getFaceJointIdx(); + virtual void createModel(); + virtual void initialize(); + virtual void play(); + virtual void _calc(); + virtual void calc2(); + virtual void draw(); + virtual void getBodyMdl(); + virtual void getAnmResFile(); + virtual void setPlayerMode(int); + virtual void setColorType(u8); + virtual void setDark(int); + virtual void setFunbariRate(float); + virtual void onStarAnm(); + virtual void offStarAnm(); + virtual void onStarEffect(); + virtual void offStarEffect(); + virtual void getJointMtx(mMtx_c *, int); + virtual void getHeadPropelJointMtx(mMtx_c *); + virtual void vf58(); ///< @unofficial + virtual void setAnm(int, float, float, float); + virtual void setPersonalAnm(int, nw4r::g3d::ResAnmChr *, int); + virtual void setBodyAnm(int, float, float, float); + virtual void releaseBodyAnm(float); + virtual void copyAnm(); + virtual void _setFootAnm(nw4r::g3d::ResAnmChr &, m3d::playMode_e, float, float, float); + virtual void _setBodyAnm(nw4r::g3d::ResAnmChr &, m3d::playMode_e, float, float, float); + virtual void setAnmBind(); + virtual void setPersonalRideAnm(int, nw4r::g3d::ResAnmChr *); + virtual void setTexAnmType(); + virtual void setFrame(float); + virtual void setBodyFrame(); + virtual void setRate(float); + virtual void setBodyRate(); + virtual void setPropelRollSpeed(s16) const; + virtual s16 getPropelRollSpeed(); + virtual void setPropelRollAngle(s16); + virtual s16 getPropelRollAngle() const; + virtual void setPropelScale(float); + virtual float *getLegLengthP(u8); + virtual void updateBonusCap(); + + bool isFootStepTiming(); + void getJointPos(mVec3_c *, int); + void fn_800d5e00(int); + void copyLinkAnm(float f); + + float getFrameMax() { return mAnm.mFrameMax; } + mMtx_c &getMtx() { return mMtx; } + + void setAng(mAng3_c ang) { + m_1fc = ang.x; + m_1fe = ang.y; + m_200 = ang.z; + } + + u32 get151CheckVal() { return 2; } + + u8 mPad1[0x1c]; + dAcPy_c *mpOwner; + dPyMdlBase_c *mpSpinLiftParentMdl; + m3d::anmChr_c mAnm; + u8 mPad3[0x6c]; + mVec3_c mHatPosMaybe; + u8 mPad4[0x30]; + mMtx_c mMtx; + u8 mPad5[0xc]; + mVec3_c mScale; + u8 mPad6[0x1]; + u8 m_151; + u8 m_152; + int mCurrAnmID; + u8 mPad7[8]; + u32 mFlags; + u8 mPad8[0x18]; + u32 m_17c; + u8 mPad9[0x7c]; + s16 m_1fc; + s16 m_1fe; + s16 m_200; + u32 m_204; + u32 m_208; + + static const float scWaterCrouchAnmSpeed; + static const float scFireShootFrame; +}; diff --git a/include/game/bases/d_player_model_manager.hpp b/include/game/bases/d_player_model_manager.hpp new file mode 100644 index 00000000..8762b95e --- /dev/null +++ b/include/game/bases/d_player_model_manager.hpp @@ -0,0 +1,338 @@ +#pragma once + +#include + +class dPyAnm_HIO_c { +public: + u8 mID; + float mRate; + float mBlendDuration; +}; + +class dPyAnmMain_HIO_c { +public: + dPyAnm_HIO_c mAnm[177]; +}; + +/// @unofficial +struct dPyModelData_s { + float a, b, c, d; +}; + +class dPyModel_HIO_c { +public: + float mData[5]; + + dPyModelData_s getModelData(u8 index) { + return modelData[index]; + } + + dPyModelData_s modelData[3]; +}; + +class dYoshiModel_HIO_c { +public: + float mData[4]; +}; + +class dPyMdlBase_HIO_c { +public: + u8 changeHioType(u8 hioType); + float getValue(dPyModelData_s model, u8 powerup); ///< @unofficial + + float getValue(int playerType, int idx, int powerup) { + dPyModelData_s modelData = mPyModel[changeHioType(playerType)].getModelData(idx); + return getValue(modelData, powerup); + } + + enum ScaleIndex_e {}; + + float get_08(ScaleIndex_e index) { + return m_08[index]; + } + + u8 mPad[0x8]; + float m_08[8]; + dPyAnmMain_HIO_c mPyAnm; + dPyModel_HIO_c mPyModel[3]; + dYoshiModel_HIO_c mYoshiModel[3]; +}; + +enum AnmID_e { + PLAYER_ANIM_WAIT, + PLAYER_ANIM_WALK, + PLAYER_ANIM_RUN, + PLAYER_ANIM_B_DASH, + PLAYER_ANIM_B_DASH2, + PLAYER_ANIM_JUMP, + PLAYER_ANIM_JUMP2, + PLAYER_ANIM_JUMPED, + PLAYER_ANIM_2JMP_C_1, + PLAYER_ANIM_2JMP_C_2, + PLAYER_ANIM_2JUMPED, + PLAYER_ANIM_ROLL_JUMP, + PLAYER_ANIM_2JUMP2, + PLAYER_ANIM_MAME_JUMP2, + PLAYER_ANIM_TURN, + PLAYER_ANIM_TURNED, + PLAYER_ANIM_HIPSR, + PLAYER_ANIM_HIPAT, + PLAYER_ANIM_HIPED, + PLAYER_ANIM_HIP_TO_STOOP, + PLAYER_ANIM_STOOP, + PLAYER_ANIM_STOOP_START, + PLAYER_ANIM_SLIP, + PLAYER_ANIM_SLIPED, + PLAYER_ANIM_SLIP_TO_STOOP, + PLAYER_ANIM_CARRY_WAIT, + PLAYER_ANIM_CARRY_WALK, + PLAYER_ANIM_CARRY_THROW, + PLAYER_ANIM_RCARRY_WAIT, + PLAYER_ANIM_WSLD, + PLAYER_ANIM_FIRE_AT, + PLAYER_ANIM_SWIM_FIRE_AT, + PLAYER_ANIM_SWIM_FIRE_AT2, + PLAYER_ANIM_STAR_ROLL, + PLAYER_ANIM_P_SWIM, + PLAYER_ANIM_SWIM, + PLAYER_ANIM_SWIM_WAIT, + PLAYER_ANIM_SWIM_THROW, + PLAYER_ANIM_SWIM_WALK, + PLAYER_ANIM_SWIM_STANDING, + PLAYER_ANIM_PADDLE_1, + PLAYER_ANIM_PADDLE_2, + PLAYER_ANIM_PADDLE_CARRY, + PLAYER_ANIM_TREE_START, + PLAYER_ANIM_TREE_WAIT, + PLAYER_ANIM_TREE_CLIMB, + PLAYER_ANIM_TREE_POSE, + PLAYER_ANIM_MONKEY_START, + PLAYER_ANIM_MONKEY_WAIT_R, + PLAYER_ANIM_MONKEY_WAIT_L, + PLAYER_ANIM_MONKEY_R_TO_L, + PLAYER_ANIM_MONKEY_L_TO_R, + PLAYER_ANIM_NET_WAIT, + PLAYER_ANIM_NET_WALK1, + PLAYER_ANIM_NET_WALK2, + PLAYER_ANIM_NET_ATTACK, + PLAYER_ANIM_PEA_PLANT, + PLAYER_ANIM_PEA_PLANT_ST, + PLAYER_ANIM_PEA_PLANT_WAIT, + PLAYER_ANIM_WALL_WAIT, + PLAYER_ANIM_WALL_WALK_L, + PLAYER_ANIM_WALL_WALK_R, + PLAYER_ANIM_HANG_START, + PLAYER_ANIM_HANG_UP, + PLAYER_ANIM_HANG_WAIT, + PLAYER_ANIM_HANG_WALK_L, + PLAYER_ANIM_HANG_WALK_R, + PLAYER_ANIM_W_JUMP1, + PLAYER_ANIM_W_JUMP2, + PLAYER_ANIM_2JUMPED_DUPLICATE, + PLAYER_ANIM_JUMP_HANG, + PLAYER_ANIM_SPIN_ST, + PLAYER_ANIM_SPIN_END, + PLAYER_ANIM_SPIN_LOW_ST, + PLAYER_ANIM_SPIN_LOW_ED, + PLAYER_ANIM_SPIN_JUMP2, + PLAYER_ANIM_SPIN_JUMP_END, + PLAYER_ANIM_DAM_F, + PLAYER_ANIM_DAM_B, + PLAYER_ANIM_DOW_F, + PLAYER_ANIM_DOW_B, + PLAYER_ANIM_FIREJMP, + PLAYER_ANIM_E_SHOCK, + PLAYER_ANIM_DEAD, + PLAYER_ANIM_DEAD_POSE, + PLAYER_ANIM_RTREE_START, + PLAYER_ANIM_RTREE_WAIT, + PLAYER_ANIM_RTREE_POSE, + PLAYER_ANIM_GOAL_JUMP, + PLAYER_ANIM_GOAL_JUMP_ED, + PLAYER_ANIM_GOAL_PUTON_CAP, + PLAYER_ANIM_PL_GOAL_PUTON_CAP, + PLAYER_ANIM_P_GOAL_PUTON_CAP, + PLAYER_ANIM_PL_RGOAL_PUTON_CAP, + PLAYER_ANIM_P_RGOAL_PUTON_CAP, + PLAYER_ANIM_GOAL_PUTON_CAPF, + PLAYER_ANIM_R_EAT, + PLAYER_ANIM_R_EAT_OUT, + PLAYER_ANIM_R_EAT_SUCCESS, + PLAYER_ANIM_R_EAT_FAIL, + PLAYER_ANIM_R_EAT_SUCCESSB, + PLAYER_ANIM_R_EAT_SUCCESSB_DUPLICATE, + PLAYER_ANIM_RS_EAT, + PLAYER_ANIM_RS_EAT_OUT, + PLAYER_ANIM_RS_EAT_SUCCESS, + PLAYER_ANIM_RS_EAT_FAIL, + PLAYER_ANIM_RS_EAT_SUCCESSB, + PLAYER_ANIM_RS_EAT_SUCCESS_DUPLICATE, + PLAYER_ANIM_CARRY_P_START, + PLAYER_ANIM_CARRY_P_WAIT, + PLAYER_ANIM_CARRY_P_WALK, + PLAYER_ANIM_CARRY_P_THROW, + PLAYER_ANIM_CARRY_P_WAIT_DUPLICATE, + PLAYER_ANIM_RIDE_ON, + PLAYER_ANIM_F_JUMP, + PLAYER_ANIM_SET, + PLAYER_ANIM_SET_TO_WAIT, + PLAYER_ANIM_STAR_ROLL_DUPLICATE, + PLAYER_ANIM_S_JUMP, + PLAYER_ANIM_S_JUMP2, + PLAYER_ANIM_S_JUMPED, + PLAYER_ANIM_GET_DOWN, + PLAYER_ANIM_ICE_TURN, + PLAYER_ANIM_ICE_TURNED, + PLAYER_ANIM_ICE_SLIP_F, + PLAYER_ANIM_ICE_SLIP_B, + PLAYER_ANIM_ROPE_SWING, + PLAYER_ANIM_SHOOT, + PLAYER_ANIM_SHOOT_SLIP, + PLAYER_ANIM_SHOOT_SLIP_END, + PLAYER_ANIM_LOW_WALK_START, + PLAYER_ANIM_LOW_WALK, + PLAYER_ANIM_SWIM_PIPE, + PLAYER_ANIM_DOOR_WALK, + PLAYER_ANIM_PL_SPIN_JUMP, + PLAYER_ANIM_WAIT_L, + PLAYER_ANIM_WAIT_R, + PLAYER_ANIM_FIRE_AT2, + PLAYER_ANIM_BLOW_UP, + PLAYER_ANIM_P_SLIP, + PLAYER_ANIM_P_SLIP_JUMP, + PLAYER_ANIM_P_SLIP_JUMP2, + PLAYER_ANIM_RF_JUMP, + PLAYER_ANIM_STAMP, + PLAYER_ANIM_WAIT_R_DUPLICATE, + PLAYER_ANIM_WAIT_L_DUPLICATE, + PLAYER_ANIM_WAIT_R3, + PLAYER_ANIM_WAIT_L3, + PLAYER_ANIM_BOSS_KEY_GET, + PLAYER_ANIM_BALLOON_WAIT, + PLAYER_ANIM_SLOPE_WAIT_L, + PLAYER_ANIM_SLOPE_WAIT_R, + PLAYER_ANIM_SLOPE_WAIT_L2, + PLAYER_ANIM_SLOPE_WAIT_R2, + PLAYER_ANIM_CARRY_P_WAIT_L, + PLAYER_ANIM_CARRY_P_WAIT_R, + PLAYER_ANIM_CARRY_WAIT_L, + PLAYER_ANIM_CARRY_WAIT_R, + PLAYER_ANIM_SPIN_JUMP3, + PLAYER_ANIM_RIDE_WAIT, + PLAYER_ANIM_P_PADDLE_1, + PLAYER_ANIM_P_PADDLE_2, + PLAYER_ANIM_POSE_L, + PLAYER_ANIM_POSE_R, + PLAYER_ANIM_GORL_WAIT, + PLAYER_ANIM_DM_NOTICE, + PLAYER_ANIM_DM_NOTI_WAIT, + PLAYER_ANIM_DM_SURPRISE, + PLAYER_ANIM_DM_SURP_WAIT, + PLAYER_ANIM_WAIT_SELECT, + PLAYER_ANIM_COURSE_IN, + PLAYER_ANIM_WAIT_DUPLICATE, + PLAYER_ANIM_WAIT_DUPLICATE2, + PLAYER_ANIM_DM_ESCORT, + PLAYER_ANIM_DM_GLAD, + PLAYER_ANIM_ENDING_WAIT, + PLAYER_ANIM_COIN_COMP +}; + +class dPyMdlMng_c { +public: + enum ModelType_e {}; + enum SceneType_e { + SCENE_TYPE_0 + }; + + dPyMdlMng_c(ModelType_e modelType); + virtual ~dPyMdlMng_c(); + void calc(mMtx_c &); + void calc(mVec3_c, mAng3_c, mVec3_c); + void calc2(); + void draw(); + void play(); + + void create(u8 playerNo, u8 powerup, SceneType_e sceneType); + + static dPyAnm_HIO_c &getHIO(u8 anmID) { + return m_hio.mPyAnm.mAnm[anmID]; + } + + void setAnm(int anmID, float rate, float blendDuration, float f) { + mpMdl->setAnm(anmID, rate, blendDuration, f); + } + + void setAnm(int anmID, float blendDuration, float f) { + float rate = getHIO(anmID).mRate; + setAnm(anmID, rate, blendDuration, f); + } + + void setAnm(int anmID, const dPyAnm_HIO_c &hio, float f = 0.0f) { + mpMdl->setAnm(anmID, hio.mRate, hio.mBlendDuration, f); + } + + void setAnm(int anmID, float f = 0.0f) { + setAnm(anmID, m_hio.mPyAnm.mAnm[(u8) anmID], f); + } + + void setAnmOnlyRate(int anmID, const dPyAnm_HIO_c &hio, float a, float b) { + mpMdl->setAnm(anmID, hio.mRate, a, b); + } + + void setAnmOnlyRate(int anmID, float a, float b) { + setAnmOnlyRate(anmID, getHIO(anmID), a, b); + } + + bool isAnm(int anmID) const { + return mpMdl->mCurrAnmID == anmID; + } + + int getAnm() const { + return mpMdl->mCurrAnmID; + } + + float getLastFrame() const { + return mpMdl->mAnm.mFrameMax - 1.0f; + } + + bool isAnmStop() const { + return mpMdl->mAnm.isStop(); + } + + mAng3_c getAng() const { + return mAng3_c( + mpMdl->m_1fc, + mpMdl->m_1fe, + mpMdl->m_200 + ); + } + void setAng(mAng3_c v) { mpMdl->setAng(v); } + + u32 getFlags() const { + return mpMdl->mFlags; + } + + u32 getFlags2() const { + return mpMdl->m_17c; + } + + mVec3_c &getHatPos() const { return mpMdl->mHatPosMaybe; } + + float getSomeScale() { + return m_hio.get_08((dPyMdlBase_HIO_c::ScaleIndex_e) mpMdl->m_152); + } + + float getSomeScale2() { + return m_hio.m_08[mpMdl->m_152]; + } + + dPyMdlBase_c *mpMdl; + u8 mPad[0x4]; + + static dPyMdlBase_HIO_c *getHIO() { + return &m_hio; + } + + static dPyMdlBase_HIO_c m_hio; +}; diff --git a/include/game/bases/d_player_orchestra.hpp b/include/game/bases/d_player_orchestra.hpp new file mode 100644 index 00000000..5aa15198 --- /dev/null +++ b/include/game/bases/d_player_orchestra.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include + +class dPlayerOrchestra_c { +public: + dPlayerOrchestra_c(); + + void init(int playerNo); + void update(); + + u8 mPad[0x20]; +}; diff --git a/include/game/bases/d_propel_parts.hpp b/include/game/bases/d_propel_parts.hpp new file mode 100644 index 00000000..53ed67b4 --- /dev/null +++ b/include/game/bases/d_propel_parts.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include + +class dPropelParts_c { +public: + enum Mode_e { + PROPEL_MODE_0, + PROPEL_MODE_1, + PROPEL_MODE_2, + PROPEL_MODE_3 + }; + + dPropelParts_c(); + void create(dActor_c *); + void update(const mMtx_c &); + void finalizePropelFly(s16); + + bool isMode(Mode_e); + + u8 mPad1[0x8]; + int mMode; + s16 mRollSpeed; + float mScale; + mEf::levelEffect_c mLevelEf; + u8 mPad3[0x4]; +}; diff --git a/include/game/bases/d_quake.hpp b/include/game/bases/d_quake.hpp index e8f04da9..c2dde916 100644 --- a/include/game/bases/d_quake.hpp +++ b/include/game/bases/d_quake.hpp @@ -23,6 +23,8 @@ class dQuake_c { FLAG_2 = BIT_FLAG(2) }; + void shockMotor(s8, TYPE_SHOCK_e, int, bool); + float mSpeed; float mResult; float mMultiplier; @@ -42,5 +44,7 @@ class dQuake_c { int mPOWLength; int mMPGPLength; + static dQuake_c* getInstance() { return m_instance; } + static dQuake_c *m_instance; }; diff --git a/include/game/bases/d_rc.hpp b/include/game/bases/d_rc.hpp index 218e14c3..9e4d78bb 100644 --- a/include/game/bases/d_rc.hpp +++ b/include/game/bases/d_rc.hpp @@ -62,6 +62,7 @@ class dRc_c { short mRotation; u8 mLineKind; u8 mRideType; - u8 pad2[2]; + u8 mFlags; + u8 m_31; u8 mLayer; }; diff --git a/include/game/bases/d_remocon_manager.hpp b/include/game/bases/d_remocon_manager.hpp index 343ddee0..ea72a247 100644 --- a/include/game/bases/d_remocon_manager.hpp +++ b/include/game/bases/d_remocon_manager.hpp @@ -1,9 +1,40 @@ -#pragma once +#include +#include +#include +#include class dRemoconMng_c { public: class dConnect_c { public: + class dExtension_c { + public: + virtual ~dExtension_c(); + + mPad::CH_e mControllerID; + u32 mExtensionType; + sFStateMgr_c mState; + }; + + virtual ~dConnect_c(); + + mPad::CH_e mControllerID; + dExtension_c mExtension; + u32 m_50; + bool mWillDisconnect; + bool mIsRumbleEnabled; + u32 m_58; + sFStateMgr_c mState; + static bool m_isBoot; }; + + dRemoconMng_c(mPad::CH_e); + virtual ~dRemoconMng_c(); + void execute(); + void reset(); + + dConnect_c *mRemocons[4]; + + static dRemoconMng_c *m_instance; }; diff --git a/include/game/bases/d_s_stage.hpp b/include/game/bases/d_s_stage.hpp index 6c881e48..2e6da91a 100644 --- a/include/game/bases/d_s_stage.hpp +++ b/include/game/bases/d_s_stage.hpp @@ -1,28 +1,47 @@ #pragma once #include +#include #include #include class dScStage_c : public dScene_c { public: + enum Exit_e { + EXIT_0, + EXIT_1, + EXIT_2, + EXIT_3 + }; + + /// @unofficial + enum GameMode_e { + GAME_MODE_NORMAL, + GAME_MODE_TITLE_SCREEN = 2, + GAME_MODE_REPLAY = 4 + }; + /// @brief The possible stage loop types. - enum LOOP_TYPE_e { + /// @unofficial + enum LoopType_e { LOOP_NONE, ///< No stage looping occurs. LOOP_EDGES, ///< The stage loops around on the zone edges. Only works for specific zone sizes. LOOP_SECTION, ///< The stage loops in specific sections. - LOOP_COUNT, + LOOP_COUNT }; char pad[0x1198]; u8 mCurrWorld; u8 mCurrCourse; u8 mCurrFile; - u8 mCurrArea; + u8 mCurrAreaNo; + u8 mCurrLayer; - u8 getCurrArea() const { return mCurrArea; } + u8 getCurrArea() const { return mCurrAreaNo; } static dScStage_c *getInstance() { return m_instance; } + static NOINLINE Exit_e getExitMode() { return m_exitMode; } + static float getLoopPosX(float x); static u32 m_exeFrame; static int m_loopType; @@ -38,6 +57,12 @@ class dScStage_c : public dScene_c { static void setTitleReplayRandomTable(); + static void setNextScene(u16, int, Exit_e, dFader_c::fader_type_e); + + static GameMode_e m_gameMode; + static int m_miniGame; + static Exit_e m_exitMode; + static bool m_isStaffCredit; static changePosFunc changePos; static dScStage_c *m_instance; }; diff --git a/include/game/bases/d_score_manager.hpp b/include/game/bases/d_score_manager.hpp index a8f4b05e..b29b9044 100644 --- a/include/game/bases/d_score_manager.hpp +++ b/include/game/bases/d_score_manager.hpp @@ -7,6 +7,7 @@ class dScoreMng_c { void ScoreSet(dActor_c *, ulong, int, float, float); void ScoreSet2(mVec3_c &, ulong, int); void UnKnownScoreSet(dActor_c *, ulong, float, float); + void fn_800e25a0(ulong, int, int); ///< @unofficial static dScoreMng_c *getInstance() { return m_instance; } diff --git a/include/game/bases/d_stage_timer.hpp b/include/game/bases/d_stage_timer.hpp new file mode 100644 index 00000000..78ebac72 --- /dev/null +++ b/include/game/bases/d_stage_timer.hpp @@ -0,0 +1,15 @@ +#pragma once +#include + +class dStageTimer_c { +public: + virtual ~dStageTimer_c() {} + + int mTimeValue; + + short convertToIGT() const { + return (mTimeValue + 4095) >> 12; + } + + static dStageTimer_c *m_instance; +}; diff --git a/include/game/bases/d_water_entry_manager.hpp b/include/game/bases/d_water_entry_manager.hpp new file mode 100644 index 00000000..26559a88 --- /dev/null +++ b/include/game/bases/d_water_entry_manager.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include + +class dWaterEntryMng_c { +public: + u8 mPad[0x8c0]; + float m_8c0; + + float get_8c0() const { return m_8c0; } + + static dWaterEntryMng_c *m_instance; +}; diff --git a/include/game/bases/d_yoshi_mdl.hpp b/include/game/bases/d_yoshi_mdl.hpp new file mode 100644 index 00000000..a2633e4b --- /dev/null +++ b/include/game/bases/d_yoshi_mdl.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include + +class dYoshiMdl_c : public dPyMdlBase_c { +public: + enum YoshiColor_e {}; + + YoshiColor_e getColor() { return mColor; } + + u8 mPad[0x40]; + YoshiColor_e mColor; +}; diff --git a/include/game/framework/f_base.hpp b/include/game/framework/f_base.hpp index e35614a8..98390bac 100644 --- a/include/game/framework/f_base.hpp +++ b/include/game/framework/f_base.hpp @@ -180,6 +180,8 @@ class fBase_c { virtual ~fBase_c(); ///< Destroys the base. public: + fBaseID_e getID() const { return mUniqueID; } + /// @brief Requests deletion of the base. /// @details Calling this function multiple times has no effect. void deleteRequest(); diff --git a/include/game/mLib/m_angle.hpp b/include/game/mLib/m_angle.hpp index fc5e5f85..8df2b81c 100644 --- a/include/game/mLib/m_angle.hpp +++ b/include/game/mLib/m_angle.hpp @@ -17,6 +17,12 @@ struct mAng { /// @brief Constructs a vector from a short value. mAng(s16 x) : mAngle(x) {} + /// @brief Assignment operator from a short value. + mAng *operator=(s16 ang) { + mAngle = ang; + return this; + } + operator s16() { return mAngle; } bool chase(short target, short step) { @@ -52,6 +58,9 @@ struct mAng { float cos() const { return nw4r::math::CosIdx(mAngle); } s16 mAngle; ///< The rotation. + + static float AngleToDegreeCoefficient; + static float DegreeToAngleCoefficient; }; /// @brief A three-dimensional short angle vector. @@ -87,6 +96,14 @@ class mAng3_c { return this; } + void set(const mAng3_c &v) { x = v.x; y = v.y; z = v.z; } + + void set(s16 fx, s16 fy, s16 fz) { + x = fx; + y = fy; + z = fz; + } + /// @brief Augmented addition operator. mAng3_c &operator+=(const mAng3_c &v) { x += v.x; y += v.y; z += v.z; return *this; } diff --git a/include/game/mLib/m_effect.hpp b/include/game/mLib/m_effect.hpp index 327a4cc5..bafd04ad 100644 --- a/include/game/mLib/m_effect.hpp +++ b/include/game/mLib/m_effect.hpp @@ -1,7 +1,50 @@ #pragma once +#include #include +#include -class mEf { +namespace mEf { + +class effect_c : public EGG::Effect { public: - static void createEffect(const char *, unsigned long, const mVec3_c *, const mAng3_c *, const mVec3_c *); + effect_c() {} + + virtual void reset(); + virtual void createEffect(const char *, int); + virtual void createEffect(const char *, ulong, const mVec3_c *, const mAng3_c *, const mVec3_c *); + virtual void createEffect(const char *, ulong, const mMtx_c *); + virtual void vfa8(); + virtual void vfac(); + virtual bool follow(const mVec3_c *, const mAng3_c *, const mVec3_c *); + virtual bool follow(const mMtx_c *); + + void copyExEffectParam(); }; + +class levelEffect_c : public effect_c { +public: + levelEffect_c() : m_114(0), m_118(0), m_11c(0), m_11d(0), m_120(0), m_124(0) {} + virtual ~levelEffect_c() { cleanup(); } + + virtual void fade(); + virtual void kill(); + virtual void update(); + virtual void createEffect(const char *, int); + virtual void createEffect(const char *, ulong, const mVec3_c *, const mAng3_c *, const mVec3_c *); + virtual void createEffect(const char *, ulong, const mMtx_c *); + virtual void vfa8(); + virtual void vfac(); + virtual bool follow(const mVec3_c *, const mAng3_c *, const mVec3_c *); + virtual bool follow(const mMtx_c *); + virtual bool isActive(); + + void cleanup(); + + u32 m_114, m_118; + u8 m_11c, m_11d; + u32 m_120, m_124; +}; + +void createEffect(const char *, unsigned long, const mVec3_c *, const mAng3_c *, const mVec3_c *); + +}; // namespace mEf diff --git a/include/game/mLib/m_fader_base.hpp b/include/game/mLib/m_fader_base.hpp index 14a180e2..a1367301 100644 --- a/include/game/mLib/m_fader_base.hpp +++ b/include/game/mLib/m_fader_base.hpp @@ -51,6 +51,10 @@ class mFaderBase_c { void setFrame(u16 duration); ///< Sets the duration of the fade. Duration must not be zero. void setColor(const mColor &color); ///< Sets the fader's color. Alpha is not modified. + /// @brief Checks if the fader is in a specific status. + /// @unofficial + bool isStatus(EStatus status) const { return getStatus() == status; } + protected: EStatus mStatus; ///< The fader's status. u8 mFlag; ///< The fader's flags. diff --git a/include/game/mLib/m_mtx.hpp b/include/game/mLib/m_mtx.hpp index cb701ca8..6c797b0b 100644 --- a/include/game/mLib/m_mtx.hpp +++ b/include/game/mLib/m_mtx.hpp @@ -20,6 +20,15 @@ class mMtx_c : public nw4r::math::MTX34 { /// @brief Const Mtx cast operator. operator const Mtx*() const { return &mtx; } + mMtx_c &operator=(const mMtx_c &other) { + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 4; j++) { + m[i][j] = other.m[i][j]; + } + } + return *this; + } + void XrotS(mAng angle); ///< Generates a rotation matrix for the X axis with the given angle. void XrotM(mAng angle); ///< Rotates the matrix on the X axis by the given angle. void YrotS(mAng angle); ///< Generates a rotation matrix for the Y axis with the given angle. @@ -43,6 +52,8 @@ class mMtx_c : public nw4r::math::MTX34 { static mMtx_c createTrans(const mVec3_c &v) { return createTrans(v.x, v.y, v.z); } static mMtx_c createTrans(float x, float y, float z) { mMtx_c mtx; PSMTXTrans(mtx, x, y, z); return mtx; } + static mMtx_c createScale(const mVec3_c &v) { mMtx_c mtx; PSMTXScale(mtx, v.x, v.y, v.z); return mtx; } + static mMtx_c createScale(float x, float y, float z) { mMtx_c mtx; PSMTXScale(mtx, x, y, z); return mtx; } mMtx_c &concat(const mMtx_c &other) { PSMTXConcat(*this, other, *this); return *this; } mMtx_c &trans(const mVec3_c &v) { PSMTXTrans(*this, v.x, v.y, v.z); return *this; } diff --git a/include/game/mLib/m_pad.hpp b/include/game/mLib/m_pad.hpp index 293df98a..dc09109a 100644 --- a/include/game/mLib/m_pad.hpp +++ b/include/game/mLib/m_pad.hpp @@ -2,7 +2,14 @@ #include -class mPad { -public: - static EGG::CoreController *g_currentCore; +namespace mPad { + enum CH_e { + MPAD_CH_0, + MPAD_CH_1, + MPAD_CH_2, + MPAD_CH_3 + }; + + extern EGG::CoreController *g_currentCore; + extern EGG::CoreController *g_core[4]; }; diff --git a/include/game/mLib/m_vec.hpp b/include/game/mLib/m_vec.hpp index b62a374e..aa9d96c9 100644 --- a/include/game/mLib/m_vec.hpp +++ b/include/game/mLib/m_vec.hpp @@ -7,10 +7,28 @@ /// A plain-old-data structure version of mVec2_c. /// @unofficial struct mVec2_POD_c { + void set(float fx, float fy) { + x = fx; + y = fy; + } + void set(const mVec2_POD_c &v) { + set(v.x, v.y); + } + void setX(float fx) { x = fx; } + void setY(float fy) { y = fy; } + float x; float y; }; +/// @unofficial +struct sPcRect { + int mLeft; + int mTop; + int mHeight; + int mWidth; +}; + /// @brief A two-dimensional floating point vector. /// @ingroup mlib class mVec2_c : public EGG::Vector2f { @@ -181,7 +199,7 @@ class mVec3_c : public EGG::Vector3f { mVec3_c operator*(f32 f) const { return mVec3_c(f * x, f * y, f * z); } /// @brief Scalar division operator. - mVec3_c operator/(f32 f) const { f32 r = 1.0f / f; return operator*(r); } + mVec3_c operator/(f32 f) const { f32 r = 1.0f / f; return mVec3_c(x * r, y * r, z * r); } /// @brief Equality operator. bool operator==(const mVec3_c &v) const { return x == v.x && y == v.y && z == v.z; } @@ -201,6 +219,14 @@ class mVec3_c : public EGG::Vector3f { return EGG::Mathf::sqrt(PSVECSquareDistance((const Vec*) this, (const Vec*) &other)); } + friend mVec3_c operator*(f32 f, const mVec3_c &v) { + return mVec3_c(v.x * f, v.y * f, v.z * f); + } + + bool isSmallerThan1() const { + return PSVECMag(*this) <= 1.0f; + } + /// @brief Normalizes the vector. /// @return The vector's magnitude. float normalize(); diff --git a/include/game/sLib/s_math.hpp b/include/game/sLib/s_math.hpp index 23c1fce2..87c9090c 100644 --- a/include/game/sLib/s_math.hpp +++ b/include/game/sLib/s_math.hpp @@ -2,9 +2,12 @@ namespace sLib { -bool chase(short *, short, short); -bool chase(float *, float, float); +bool chase(short *value, short target, short step); +bool chase(int *value, int target, int step); +bool chase(long *value, long target, long step); +bool chase(float *value, float target, float step); short addCalcAngle(short *, short, short, short, short); +void addCalc(float *, float, float, float, float); template T calcTimer(T *val) { diff --git a/include/game/snd/snd_audio_mgr.hpp b/include/game/snd/snd_audio_mgr.hpp index bbb7b9a8..248e23ce 100644 --- a/include/game/snd/snd_audio_mgr.hpp +++ b/include/game/snd/snd_audio_mgr.hpp @@ -1,8 +1,17 @@ #pragma once +#include +#include class SndAudioMgr { public: void startSystemSe(unsigned int soundID, unsigned long); + u32 get3DCtrlFlag(unsigned long); + void setSoundPosition(nw4r::snd::SoundHandle *p, const nw4r::math::VEC2 &pos); + + u8 mPad1[0x100]; + nw4r::snd::SoundArchive *mpSndArc; + u8 mPad2[0x4b8]; + nw4r::snd::SoundArchivePlayer &mArcPlayer; public: static SndAudioMgr *sInstance; diff --git a/include/game/snd/snd_scene_manager.hpp b/include/game/snd/snd_scene_manager.hpp new file mode 100644 index 00000000..c1da302f --- /dev/null +++ b/include/game/snd/snd_scene_manager.hpp @@ -0,0 +1,15 @@ +#pragma once +#include + +class SndSceneMgr { +public: + void moveMissFin(); + void fn_8019be60(int); ///< @unofficial + void fn_8019bd90(int); ///< @unofficial + + u8 mPad1[0x10]; + int m_10; + int m_14; + + static SndSceneMgr *sInstance; +}; diff --git a/include/lib/egg/core/eggController.h b/include/lib/egg/core/eggController.h index 2f2e15da..da100b5b 100644 --- a/include/lib/egg/core/eggController.h +++ b/include/lib/egg/core/eggController.h @@ -19,6 +19,8 @@ class CoreController { virtual bool upAll(ulong) const; virtual void beginFrame(PADStatus *); virtual void endFrame(); + + void startPatternRumble(const char *, int, bool); }; } // namespace EGG diff --git a/include/lib/egg/util/eggEffect.hpp b/include/lib/egg/util/eggEffect.hpp new file mode 100644 index 00000000..eba617dd --- /dev/null +++ b/include/lib/egg/util/eggEffect.hpp @@ -0,0 +1,57 @@ +#pragma once +#include + +namespace EGG { + +class Effect { +public: + enum ERecursive { + RECURSIVE_3 = 3 + }; + + Effect(); + virtual ~Effect(); + virtual void create(); + virtual void fade(); + virtual void followFade(); + virtual void kill(); + virtual void setDisableCalc(bool); + virtual void setDisableDraw(bool); + virtual void setDisableCalcDraw(bool); + virtual void setLife(unsigned short, EGG::Effect::ERecursive); + virtual void setEmitRatio(float, EGG::Effect::ERecursive); + virtual void setEmitInterval(unsigned short, EGG::Effect::ERecursive); + virtual void setEmitEmitDiv(unsigned short, EGG::Effect::ERecursive); + virtual void setInitVelocityRandom(s8, EGG::Effect::ERecursive); + virtual void setPowerYAxis(float, EGG::Effect::ERecursive); + virtual void setPowerRadiationDir(float, EGG::Effect::ERecursive); + virtual void setPowerSpecDir(float, EGG::Effect::ERecursive); + virtual void setPowerSpecDirAdd(float, EGG::Effect::ERecursive); + virtual void setSpecDir(const nw4r::math::VEC3&, EGG::Effect::ERecursive); + virtual void setSpecDirAdd(const nw4r::math::VEC3&, EGG::Effect::ERecursive); + virtual void setVelocity(const nw4r::math::VEC3&); + virtual void setColor(u8, u8, u8, u8, EGG::Effect::ERecursive); + virtual void setRegisterColor(const _GXColor &, const _GXColor &, u8, EGG::Effect::ERecursive); + virtual void setRegisterAlpha(u8, u8, u8, EGG::Effect::ERecursive); + virtual void setDefaultParticleSize(nw4r::math::VEC2&, EGG::Effect::ERecursive); + virtual void setParticleScale(nw4r::math::VEC2&, EGG::Effect::ERecursive); + virtual void setDefaultParticleRotate(const nw4r::math::VEC3&, EGG::Effect::ERecursive); + virtual void setParticleRotate(const nw4r::math::VEC3&, EGG::Effect::ERecursive); + virtual void setEmitterSize(const nw4r::math::VEC3&, bool, EGG::Effect::ERecursive); + virtual void setLocalScale(const nw4r::math::VEC3&, EGG::Effect::ERecursive); + virtual void setDynamicsScale(const nw4r::math::VEC3&, const nw4r::math::VEC2*); + virtual void setScale(float); + virtual void setScale(const nw4r::math::VEC3&); + virtual void setPos(const nw4r::math::VEC3&); + virtual void setMtx(const nw4r::math::MTX34&); + virtual void setPtclAnim(int, bool); + virtual void update(); + virtual void reset(); + + void getEffect() const; + void getRootEmitter() const; + + u8 mPad[0x110]; +}; + +} // namespace EGG diff --git a/include/lib/nw4r/snd/snd_SoundActor.h b/include/lib/nw4r/snd/snd_SoundActor.h index d7907ddb..1430123f 100644 --- a/include/lib/nw4r/snd/snd_SoundActor.h +++ b/include/lib/nw4r/snd/snd_SoundActor.h @@ -68,6 +68,7 @@ namespace nw4r { namespace snd void StopAllSound(int fadeFrames); void PauseAllSound(bool flag, int fadeFrames); int GetPlayingSoundCount(int playerId) const; + void SetPlayableSoundCount(int playerId, int count); // static members public: diff --git a/include/lib/nw4r/snd/snd_SoundHandle.h b/include/lib/nw4r/snd/snd_SoundHandle.h index c790f26f..4b63b44b 100644 --- a/include/lib/nw4r/snd/snd_SoundHandle.h +++ b/include/lib/nw4r/snd/snd_SoundHandle.h @@ -76,6 +76,11 @@ namespace nw4r { namespace snd return 0; } + void SetPlayerPriority(int priority) { + if (IsAttachedSound()) + mSound->SetPlayerPriority(priority); + } + ulong GetId() const { if (IsAttachedSound()) diff --git a/include/lib/nw4r/snd/snd_SoundPlayer.h b/include/lib/nw4r/snd/snd_SoundPlayer.h index 1b76dfa4..2d8d39e7 100644 --- a/include/lib/nw4r/snd/snd_SoundPlayer.h +++ b/include/lib/nw4r/snd/snd_SoundPlayer.h @@ -74,10 +74,10 @@ namespace nw4r { namespace snd template TForEachFunc ForEachSound(TForEachFunc pFunc, bool reverse) { if (reverse) { - detail::BasicSound::SoundPlayerPlayLinkList::ReverseIterator it = mSoundList.GetBeginReverseIter(); + detail::BasicSound::SoundPlayerPlayLinkList::RevIterator it = mSoundList.GetBeginReverseIter(); while (it != mSoundList.GetEndReverseIter()) { - detail::BasicSound::SoundPlayerPlayLinkList::ReverseIterator curr = it; + detail::BasicSound::SoundPlayerPlayLinkList::RevIterator curr = it; SoundHandle handle; handle.detail_AttachSoundAsTempHandle(&*curr); diff --git a/slices/wiimj2d.json b/slices/wiimj2d.json index fbf30b33..cd573498 100644 --- a/slices/wiimj2d.json +++ b/slices/wiimj2d.json @@ -58,7 +58,8 @@ "__dt__7mVec2_cFv", "__dt__7mVec3_cFv", "__dt__Q34nw4r3lyt19ArcResourceAccessorFv", - "GetRuntimeTypeInfo__Q34nw4r3lyt4PaneCFv" + "GetRuntimeTypeInfo__Q34nw4r3lyt4PaneCFv", + "dummy__10daPlBase_cFv" ], "slices": [ { @@ -150,6 +151,18 @@ ".sdata2": "0x2c8-0x2d0" } }, + { + "source": "dol/bases/d_a_player_base.cpp", + "memoryRanges": { + ".text": "0x3f950-0x54c20", + ".ctors": "0x7c-0x80", + ".bss": "0x2b90-0x35a0", + ".data": "0x9898-0xb268", + ".rodata": "0xc98-0xec0", + ".sbss": "0xc8-0xd0", + ".sdata2": "0x7c0-0x998" + } + }, { "source": "dol/bases/d_ac_py_key.cpp", "memoryRanges": { @@ -446,6 +459,19 @@ ".sdata": "0x1cd8-0x1ce0" } }, + { + "source": "dol/bases/d_a_player.cpp", + "memoryRanges": { + ".text": "0x11fed0-0x1440b0", + ".ctors": "0x1e8-0x1ec", + ".data": "0x267b8-0x282c0", + ".rodata": "0x7128-0x7b10", + ".bss": "0x245a0-0x25438", + ".sbss": "0x750-0x758", + ".sdata": "0x1ce0-0x1d08", + ".sdata2": "0x26d8-0x2968" + } + }, { "source": "dol/bases/d_pausewindow.cpp", "memoryRanges": { diff --git a/source/d_basesNP/bases/d_a_remo_door.cpp b/source/d_basesNP/bases/d_a_remo_door.cpp index 01159baa..4cd439ae 100644 --- a/source/d_basesNP/bases/d_a_remo_door.cpp +++ b/source/d_basesNP/bases/d_a_remo_door.cpp @@ -73,12 +73,12 @@ void daRemoDoor_c::executeState_Open() { short newAngle = mAngle.y; newAngle += 0x400; if (newAngle < 0) { - newAngle = -0x8000; + newAngle = 0x8000; } mAngle.y = newAngle; // [Oversight: the player number check never fails] - if (mAngle.y == mAng(-0x8000) && daPyMng_c::mCtrlPlrNo < 4 && + if (mAngle.y == mAng(0x8000) && daPyMng_c::mCtrlPlrNo < 4 && dGameKey_c::m_instance->getAccVerticalAngleX(daPyMng_c::mCtrlPlrNo) <= 0x1000) { mStateMgr.changeState(StateID_Close); } diff --git a/source/dol/bases/d_a_en_carry.cpp b/source/dol/bases/d_a_en_carry.cpp index 8cdaa3e7..be9b32ef 100644 --- a/source/dol/bases/d_a_en_carry.cpp +++ b/source/dol/bases/d_a_en_carry.cpp @@ -17,7 +17,7 @@ int daEnCarry_c::acmShellPlayerNo(dActor_c *actor) const { if (isState(StateID_Carry)) { return mPlayerNo; } - return *actor->getPlrNo(); + return actor->getPlrNo(); } void daEnCarry_c::shellDamageEffect(dCc_c *cc, dActor_c *actor) { diff --git a/source/dol/bases/d_a_player.cpp b/source/dol/bases/d_a_player.cpp new file mode 100644 index 00000000..b525fae7 --- /dev/null +++ b/source/dol/bases/d_a_player.cpp @@ -0,0 +1,12014 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const float dAcPy_c::msc_JUMP_SPEED = daPlBase_c::sc_JumpSpeed; + +inline float getSomeData(int idx) { + return dAcPy_c::data_802f5a0c[idx]; +} + +inline float getData(int idx) { + return dAcPy_c::data_802f5a48[idx]; +} + +bool dAcPy_c::setHipAttackOnEnemy(mVec3_c *hitPos) { + if (isState(StateID_HipAttack) && isStatus(STATUS_HIP_ATTACK_FALL)) { + onStatus(STATUS_PRESS_ATTACH); + mPressAttachPos = *hitPos; + return true; + } else if (isState(StateID_SpinHipAttack) && isStatus(STATUS_SPIN_HIP_ATTACK_FALL)) { + onStatus(STATUS_PRESS_ATTACH); + mPressAttachPos = *hitPos; + return true; + } + return false; +} + +void dAcPy_c::setHipAttackEffect() { + if (isNowBgCross(BGC_WATER_SHALLOW)) { + setSeaLandSmokeEffect(); + startSound(SE_PLY_HPDP_SPLASH, 0); + if (mPowerup == POWERUP_MINI_MUSHROOM) { + startSound(SE_PLY_HIP_ATTACK_M, 0); + } else { + startSound(SE_PLY_HIP_ATTACK, 0); + } + } else { + daPlBase_c::setHipAttackEffect(); + } +} + +bool dAcPy_c::setHipAttackAction() { + if ( + !isStatus(STATUS_A7) && + !isNowBgCross(BGC_FOOT) && !isNowBgCross(BGC_37) && + mKey.checkHipAttack() && + !isDemoType(DEMO_ENDING_DANCE) + ) { + if (!isStatus(STATUS_PROPEL)) { + if (!isCarry()) { + changeState(StateID_HipAttack, HIP_ATTACK_ARG_PLAYER); + return true; + } + } else { + changeState(StateID_SpinHipAttack, 0); + return true; + } + } + return false; +} + +void dAcPy_c::setHipAttack_AttackStart() { + daPlBase_c::setHipAttack_AttackStart(); + startSound(SE_PLY_ROLLING, 0); +} + +void dAcPy_c::initializeState_HipAttack() { + daPlBase_c::initializeState_HipAttack(); + mJumpCounter = 0; + offStatus(STATUS_CAN_WATER_WALK); + onStatus(STATUS_CAN_LAND); +} + +void dAcPy_c::finalizeState_HipAttack() { + daPlBase_c::finalizeState_HipAttack(); + offStatus(STATUS_CAN_LAND); +} + +void dAcPy_c::executeState_HipAttack() { + if (isNowBgCross(BGC_WATER_SHALLOW) && isOldBgCross(BGC_WATER_SHALLOW) == 0) { + setWaterInEffect(); + } + daPlBase_c::executeState_HipAttack(); +} + +void dAcPy_c::setSpinHipAttackEffect() { + dEf::createPlayerEffect(mPlayerNo, &mLevelEf1, "Wm_mr_spindown", 0, &mPos, nullptr, nullptr); + dEf::createPlayerEffect(mPlayerNo, &mLevelEf2, "Wm_mr_spindownline", 0, &mPos, nullptr, nullptr); +} + +void dAcPy_c::initializeState_SpinHipAttack() { + mSubstate = SPIN_HIP_ATTACK_ACTION_0; + mPyMdlMng.setAnm(PLAYER_ANIM_SPIN_JUMP2); + onStatus(STATUS_SPIN_HIP_ATTACK_FALL); + onStatus(STATUS_A8); + onStatus(STATUS_CAN_LAND); + onStatus(STATUS_SPIN); + mKey.onStatus(dAcPyKey_c::STATUS_FORCE_NO_JUMP); + int changeParam = (int) mStateArg; + mSpeedF = 0.0f; + mMaxSpeedF = 0.0f; + mAccelY = 0.0f; + if (changeParam == 0) { + mSubstateValue = 0; + mSpeed.y = 0.0f; + float v = data_802f5a0c[13]; + mMaxFallSpeed = v; + } else { + mSubstateValue = 1; + mSpeed.y = -6.0f; + mMaxFallSpeed = -6.0f; + } + m_2e8 = 0x1000; + mSubstateTimer = 10; + setScrollMode(2); +} + +void dAcPy_c::executeState_SpinHipAttack() { + offStatus(STATUS_SPIN_HIP_ATTACK_LANDING); + if (isStatus(STATUS_SPIN_HIP_ATTACK_FALL)) { + setCcAtSpinFall(); + } + if (isNowBgCross(BGC_WATER_SHALLOW) && isOldBgCross(BGC_WATER_SHALLOW) == 0) { + setWaterInEffect(); + } + if (mPowerup != POWERUP_PROPELLER_SHROOM && getCarryPropelActor() == nullptr) { + changeState(StateID_Fall, false); + return; + } + switch ((SpinHipAttackSubstate_e) mSubstate) { + case SPIN_HIP_ATTACK_ACTION_0: + holdSound(SE_PLY_PRPL_LETDOWN_FAST, 0); + if (isNowBgCross(BGC_WATER_SHALLOW)) { + mMaxFallSpeed = sc_WaterMaxFallSpeed; + } else { + sLib::chase(&mMaxFallSpeed, data_802f5a0c[13], 0.1f); + } + mAccelY = getGravityData()[0]; + onStatus(STATUS_AA); + if (isNowBgCross(BGC_WATER_SUBMERGED)) { + offStatus(STATUS_AA); + } + if (isNowBgCross(BGC_62)) { + mSpeed.y = 0.0f; + m_2e8 = 0x1000; + offNowBgCross(BGC_FOOT); + } + if (isNowBgCross(BGC_FOOT) && !isOldBgCross(BGC_62)) { + startQuakeShock(dQuake_c::TYPE_7); + startSound(SE_PLY_PRPL_LETDOWN_FAST_LAND, 0); + if (isNowBgCross(BGC_CLIFF)) { + changeState(daPlBase_c::StateID_Kani, KANI_ARG_JUMP_HANG); // [why daPlBase_c?] + return; + } + s16 curr = m_2e8; + if (checkCrouch()) { + m_2e8 = curr; + return; + } + mSubstate = SPIN_HIP_ATTACK_ACTION_1; + mAngle.y = getMukiAngle(mDirection); + mPyMdlMng.setAnm(PLAYER_ANIM_SPIN_JUMP_END); + mSubstateTimer = 20; + offStatus(STATUS_SPIN_HIP_ATTACK_FALL); + offStatus(STATUS_SPIN); + onStatus(STATUS_9F); + onStatus(STATUS_SPIN_HIP_ATTACK_LANDED); + onStatus(STATUS_SPIN_HIP_ATTACK_LANDING); + return; + } + if (!mKey.buttonDown() && mSubstateTimer == 0) { + if (mSubstateValue == 0) { + mMaxFallSpeed = data_802f5a0c[5]; + } + changeState(StateID_Propel, (void *) 1); + return; + } + if (isNowBgCross(BGC_WATER_TOUCH)) { + m_2e8.chase(0, 0x1000); + } else { + m_2e8.chase(0x2000, 0x400); + } + mAngle.y += m_2e8; + setSpinHipAttackEffect(); + setPropelSpinSmokeEffect(); + break; + case SPIN_HIP_ATTACK_ACTION_1: + m_2e8.chase(0, 0x200); + mAngle.y += m_2e8; + if (checkJumpTrigger()) { + return; + } + if (mSubstateTimer == 0 || mPyMdlMng.isAnmStop() || mSpeedF) { + changeState(StateID_Walk, BLEND_DEFAULT); + return; + } + break; + } + if (isStatus(STATUS_PRESS_ATTACH)) { + offStatus(STATUS_PRESS_ATTACH); + mPos.x = mPressAttachPos.x; + mPos.y = mPressAttachPos.y; + } +} + +void dAcPy_c::finalizeState_SpinHipAttack() { + m_2e8 = 0; + offStatus(STATUS_SPIN); + offStatus(STATUS_SPIN_HIP_ATTACK_FALL); + offStatus(STATUS_SPIN_HIP_ATTACK_LANDED); + offStatus(STATUS_SPIN_HIP_ATTACK_LANDING); + offStatus(STATUS_A8); + offStatus(STATUS_AA); + offStatus(STATUS_9F); + offStatus(STATUS_PRESS_ATTACH); + offStatus(STATUS_CAN_LAND); + mKey.offStatus(dAcPyKey_c::STATUS_FORCE_NO_JUMP); + setScrollMode(0); +} + +void dAcPy_c::initializeState_Fall() { + daPlBase_c::initializeState_Fall(); + onStatus(STATUS_9B); + onStatus(STATUS_9C); + onStatus(STATUS_9D); + onStatus(STATUS_9E); + onStatus(STATUS_9F); + onStatus(STATUS_92); + onStatus(STATUS_CAN_LAND); + onStatus(STATUS_A1); + if (!isNowBgCross(BGC_WATER_TOUCH)) { + setWaterWalkFlag(); + } + mSpeedMax.x = 0.0; + mJumpCounter = 0; + mSubstate = FALL_ACTION_1; + setAddLiftSpeedF(); + if (isStatus(STATUS_ON_WATER_MOVE)) { + mSpeed.y = 0.5f; + } + setJumpGravity(); + maxFallSpeedSet(); + moveSpeedSet(); + powerSet(); +} + +void dAcPy_c::finalizeState_Fall() { + daPlBase_c::finalizeState_Fall(); + mAngle.x = 0; + offStatus(STATUS_9B); + offStatus(STATUS_9C); + offStatus(STATUS_9D); + offStatus(STATUS_9E); + offStatus(STATUS_9F); + offStatus(STATUS_92); + offStatus(STATUS_CAN_LAND); + offStatus(STATUS_ON_WATER_MOVE); + offStatus(STATUS_A1); +} + +void dAcPy_c::executeState_Fall() { + daPlBase_c::executeState_Fall(); + setJumpGravity(); + maxFallSpeedSet(); + moveSpeedSet(); + powerSet(); + if (!setKaniActionInitHangHand()) { + jump_common(); + if (setDelayHelpJump()) { + return; + } + } +} + +void dAcPy_c::initializeState_Jump() { + daPlBase_c::initializeState_Jump(); + onStatus(STATUS_9B); + onStatus(STATUS_9C); + onStatus(STATUS_9D); + if (!m_1058) { + onStatus(STATUS_9F); + } + onStatus(STATUS_92); + onStatus(STATUS_CAN_LAND); + onStatus(STATUS_A1); + m_12f4 = mDirection; + mSpeedMax.x = 0.0f; + setStartJumpEffect(0); + _jumpSet(stateArg()); + if (mJumpCounter != 2) { + onStatus(STATUS_9E); + } +} + +void dAcPy_c::finalizeState_Jump() { + daPlBase_c::finalizeState_Jump(); + m_1058 = 0; + mJumpComboTimer = 8; + if (!isStatus(STATUS_61)) { + onStatus(STATUS_61); + calcJumpCount(); + } + offStatus(STATUS_STAR_JUMP); + offStatus(STATUS_96); + offStatus(STATUS_48); + offStatus(STATUS_BF); + offStatus(STATUS_A8); + offStatus(STATUS_9B); + offStatus(STATUS_9C); + offStatus(STATUS_9D); + offStatus(STATUS_9E); + offStatus(STATUS_9F); + offStatus(STATUS_92); + offStatus(STATUS_CAN_LAND); + offStatus(STATUS_A1); +} + +void dAcPy_c::executeState_Jump() { + daPlBase_c::executeState_Jump(); + if (m_1058 != 0) { + if (--m_1058 == 0) { + onStatus(STATUS_9F); + } + } + if (isStatus(STATUS_A8) && mSpeed.y < 2.0f) { + offStatus(STATUS_A8); + } + gravitySet(); + maxFallSpeedSet(); + moveSpeedSet(); + airPowerSet(); + if (!setKaniActionInitHangHand()) { + jump_common(); + } +} + +void dAcPy_c::calcJumpCount() { + if (!isStatus(STATUS_AB)) { + mJumpCounter++; + if (mJumpCounter > 2) { + mJumpCounter = 0; + } + } +} + +float dAcPy_c::getJumpSpeed() { + float baseSpeed; + float absSpeed = std::fabs(mSpeedF); + if (absSpeed < daPlayerData_c::smc_POWER_CHANGE_DATA.mJumpSpeedValues1[0]) { + baseSpeed = daPlayerData_c::smc_POWER_CHANGE_DATA.mJumpSpeedValues2[0]; + } else if (absSpeed < daPlayerData_c::smc_POWER_CHANGE_DATA.mJumpSpeedValues1[1]) { + baseSpeed = daPlayerData_c::smc_POWER_CHANGE_DATA.mJumpSpeedValues2[1]; + } else if (absSpeed < daPlayerData_c::smc_POWER_CHANGE_DATA.mJumpSpeedValues1[2]) { + baseSpeed = daPlayerData_c::smc_POWER_CHANGE_DATA.mJumpSpeedValues2[2]; + } else { + baseSpeed = daPlayerData_c::smc_POWER_CHANGE_DATA.mJumpSpeedValues2[3]; + } + if (std::fabs(mSpeedF) >= getSpeedData()->mHighSpeed) { + baseSpeed = daPlayerData_c::smc_POWER_CHANGE_DATA.mJumpSpeedValues2[3]; + } + float jumpSpeed; + if (isNowBgCross(BgCross1_e(BGC_IN_SINK_SAND | BGC_ON_SINK_SAND))) { + if (isNowBgCross(BGC_IN_SINK_SAND)) { + jumpSpeed = sc_JumpSpeedNuma2; + } else { + jumpSpeed = sc_JumpSpeedNuma1; + if (mPos.y < mSinkSandHeight - 4.0f) { + jumpSpeed += -0.15f; + } + } + } else { + jumpSpeed = sc_JumpSpeed + baseSpeed; + } + if (isMameAction()) { + jumpSpeed *= 0.8125f; + } + return jumpSpeed; +} + +void dAcPy_c::setJumpSpeed() { + float jumpSpeed = getJumpSpeed(); + if (mJumpCounter == 2) { + jumpSpeed *= 1.05f; + } + mSpeed.y = jumpSpeed; +} + +void dAcPy_c::fn_80127740(int jumpType, AnmBlend_e blendMode) { + mSubstate = JUMP_TAKE_OFF; + fn_80145fd0(jumpType); + if (isStatus(STATUS_YOSHI_DISMOUNT_JUMP)) { + mPyMdlMng.setAnm(PLAYER_ANIM_GET_DOWN, 0.0f, 0.0f); + } else if (isStatus(STATUS_SPIN)) { + mPyMdlMng.setAnm(PLAYER_ANIM_SPIN_ST); + } else if (isStatus(STATUS_KANI_JUMP)) { + mPyMdlMng.setAnm(PLAYER_ANIM_W_JUMP1, 0.0f, 0.0f); + } else if (isStatus(STATUS_STAR_JUMP) && !isCarry()) { + mPyMdlMng.setAnm(PLAYER_ANIM_STAR_ROLL_DUPLICATE); + } else if (isStatus(STATUS_SIT_JUMP)) { + mPyMdlMng.setAnm(PLAYER_ANIM_S_JUMP); + } else { + int anmNum; + switch (mJumpCounter) { + case 0: + anmNum = PLAYER_ANIM_JUMP; + break; + case 1: + startPlayerVoice(VOICE_JUMP_2ND, 0); + anmNum = PLAYER_ANIM_2JMP_C_1; + break; + default: + startPlayerVoice(VOICE_JUMP_3RD, 0); + anmNum = PLAYER_ANIM_ROLL_JUMP; + break; + } + if (!isCarry()) { + if (mJumpCounter == 1) { + mPyMdlMng.mpMdl->fn_800d5e00(1); + } else { + mPyMdlMng.mpMdl->fn_800d5e00(0); + } + } + if (blendMode == BLEND_NONE) { + mPyMdlMng.setAnm(anmNum, 0.0f, 0.0f); + } else { + mPyMdlMng.setAnm(anmNum); + } + } +} + +bool dAcPy_c::jump_common() { + if (checkCarryThrow()) { + return true; + } + if (setHipAttackAction()) { + return true; + } + if (isNowBgCross(BGC_WALL_TOUCH_L_2) | isNowBgCross(BGC_WALL_TOUCH_R_2)) { + mKey.offStatus(dAcPyKey_c::STATUS_DISABLE_LR); + } + if (mSpeed.y <= 0.0f) { + mKey.offStatus(dAcPyKey_c::STATUS_FORCE_JUMP); + } + typedef void (dAcPy_c::*JumpActionProc)(); + static JumpActionProc l_JumpActionProc[] = { + &dAcPy_c::jumpExeTakeOff, + &dAcPy_c::jumpExecAir + }; + (this->*l_JumpActionProc[mSubstate])(); + return false; +} + +void dAcPy_c::jumpExeTakeOff() { + if (isStatus(STATUS_STAR_JUMP)) { + mSubstate = JUMP_AIR; + } else if (isStatus(STATUS_YOSHI_DISMOUNT_JUMP)) { + if (mPyMdlMng.isAnmStop()) { + mPyMdlMng.setAnm(PLAYER_ANIM_JUMP2, 3.0f, 0.0f); + mSubstate = JUMP_AIR; + } + } else if (mSpeed.y < 0.0f) { + if (isStatus(STATUS_KANI_JUMP)) { + mPyMdlMng.setAnm(PLAYER_ANIM_W_JUMP2, 10.0f, 0.0f); + } else if (isStatus(STATUS_SIT_JUMP)) { + mPyMdlMng.setAnm(PLAYER_ANIM_S_JUMP2); + } else if (mJumpCounter != 2) { + /// @unofficial + static const int l_AnmIDs[] = { PLAYER_ANIM_JUMP2, PLAYER_ANIM_2JMP_C_2, PLAYER_ANIM_2JUMP2 }; + mPyMdlMng.setAnm(l_AnmIDs[mJumpCounter]); + } + mSubstate = JUMP_AIR; + } + jumpExecAir(); +} + +void dAcPy_c::jumpExecAir() { + if (isStatus(STATUS_STAR_JUMP) && !isStar()) { + offStatus(STATUS_STAR_JUMP); + mPyMdlMng.setAnm(PLAYER_ANIM_JUMP2, 10.0f, 0.0f); + } + if (mJumpCounter == 2) { + if (mSubstate == JUMP_AIR) { + turnAngle(); + if (mDirection != m_12f4 || isNowBgCross(BGC_HEAD)) { + float f = mPyMdlMng.getLastFrame(); + mPyMdlMng.setAnm(PLAYER_ANIM_ROLL_JUMP, 0.0f, f); + } + } + } else if (!isStatus(STATUS_KANI_JUMP)) { + turnAngle(); + } + setJumpGravity(); + maxFallSpeedSet(); + if (isStatus(STATUS_TWIRL) && mSpeed.y < 0.0f) { + mAccelY = 0.0f; + float f = std::fabs(mSpeed.y * 0.15f); + if (f < 0.1f) { + f = 0.1f; + } + if (f > 1.0f) { + f = 1.0f; + } + sLib::chase(&mSpeed.y, 0.0f, f); + } + if ( + isNowBgCross(BGC_FOOT) && + !checkSlip() && + !checkJumpTrigger() && + !checkCrouch() + ) { + mAngle.x = 0; + if (isStatus(STATUS_SIT_JUMP)) { + changeState(StateID_Crouch, CROUCH_ARG_FROM_SIT_JUMP); + return; + } + if ( + mPowerup != POWERUP_MINI_MUSHROOM && + !isCarry() && + isStatus(STATUS_JUMP) && + isNowBgCross(BGC_GROUNDED_MOVE_UP) + ) { + changeState(StateID_Land, true); + return; + } + if ((isStatus(STATUS_YOSHI_DISMOUNT_JUMP) || mJumpCounter == 2) && !mKey.buttonWalk(nullptr)) { + mSpeedF = 0.0f; + } + setLandJumpEffect(0); + if (mSpeedF) { + fn_801282d0(BLEND_NONE); + return; + } + if (isStatus(STATUS_KANI_JUMP)) { + mPyMdlMng.setAnm(PLAYER_ANIM_2JUMPED_DUPLICATE, 10.0f, 0.0f); + } else { + if (mJumpCounter == 0) { + mPyMdlMng.setAnm(PLAYER_ANIM_JUMPED); + } else { + mPyMdlMng.setAnm(PLAYER_ANIM_2JUMPED); + } + } + changeState(StateID_Land, false); + } +} + +void dAcPy_c::setJumpCommonBase() { + if (isStatus(STATUS_FOLLOW_MAME_KURIBO)) { + int v = getFollowMameKuribo() - 1; + if (v < 0) { + v = 0; + } + if (v > 4) { + v = 4; + } + /// @unofficial + static const float speedMultiplier[] = { 0.84f, 0.81f, 0.78f, 0.75f, 0.72f }; + mSpeed.y *= speedMultiplier[v]; + } + offNowBgCross(BGC_FOOT); + setAddLiftSpeedF(); + setJumpGravity(); + maxFallSpeedSet(); +} + +void dAcPy_c::_jumpSet(jmpInf_c *jumpInf) { + setWaterWalkFlag(); + mAngle.x = 0; + offStatus(STATUS_88); + if (isStar()) { + onStatus(STATUS_STAR_JUMP); + } else { + offStatus(STATUS_STAR_JUMP); + } + if (isOnSinkSand()) { + onStatus(STATUS_SINK_SAND_JUMP); + } + int jumpMode = 1; + if (jumpInf != nullptr) { + jumpMode = jumpInf->mJumpMode; + } + if (isStatus(STATUS_C0)) { + jumpMode = 0; + } + if ( + isOnSinkSand() || + mJumpComboTimer == 0 || + isCarry() || + std::fabs(mSpeedF) < 3.0f || + jumpMode == 0 + ) { + mJumpCounter = 0; + } + if (getCarryPlayer() != nullptr && isStatus(STATUS_47)) { + onStatus(STATUS_48); + } + if (jumpInf != nullptr) { + if (jumpInf->mSpeed) { + mSpeed.y = jumpInf->mSpeed; + } else { + setJumpSpeed(); + } + } else { + setJumpSpeed(); + } + AnmBlend_e blendMode = BLEND_DEFAULT; + if (jumpInf != nullptr) { + blendMode = jumpInf->mBlendMode; + } + + fn_80127740(jumpMode, blendMode); + mAngle.y = getMukiAngle(mDirection); + setJumpCommonBase(); +} + +void dAcPy_c::fn_801282d0(AnmBlend_e blendMode) { + if (mKey.buttonWalk(nullptr) && mSpeedF * mMaxSpeedF < 0.0f && checkTurn()) { + return; + } + changeState(StateID_Walk, blendMode); +} + +void dAcPy_c::initializeState_Land() { + if (mSubstate == LAND_ACTION_1) { + mSpeedF = 0.0f; + mPyMdlMng.setAnm(PLAYER_ANIM_2JUMPED, 2.0f, 0.0f, 0.0f); + } + onStatus(STATUS_9B); + onStatus(STATUS_9D); + onStatus(STATUS_9E); + onStatus(STATUS_9F); + onStatus(STATUS_92); + onStatus(STATUS_A0); + onStatus(STATUS_A2); + onStatus(STATUS_A3); +} + +void dAcPy_c::finalizeState_Land() { + offStatus(STATUS_9B); + offStatus(STATUS_9D); + offStatus(STATUS_9E); + offStatus(STATUS_9F); + offStatus(STATUS_92); + offStatus(STATUS_A0); + offStatus(STATUS_A2); + offStatus(STATUS_A3); +} + +void dAcPy_c::executeState_Land() { + gravitySet(); + maxFallSpeedSet(); + moveSpeedSet(); + airPowerSet(); + if (checkWalkNextAction()) { + return; + } + if (isNowBgCross(BgCross1_e(BGC_WALL_TOUCH_L_2 | BGC_WALL_TOUCH_R_2))) { + mKey.offStatus(dAcPyKey_c::STATUS_DISABLE_LR); + } + if (isIceSlipAnmPlay()) { + changeState(StateID_Walk, BLEND_DEFAULT); + return; + } + if (mSubstate == LAND_ACTION_0) { + if (!mSpeedF && !mPyMdlMng.isAnmStop()) { + return; + } + fn_801282d0(BLEND_DEFAULT); + } else { + mSpeedF = 0.0f; + if ((mKey.buttonWalk(nullptr) && mPyMdlMng.mpMdl->mAnm.getFrame() >= 10.0f) || mPyMdlMng.isAnmStop()) { + fn_801282d0(BLEND_DEFAULT); + } + } +} + +int dAcPy_c::checkWallSlideEnable(int dir) { + if ( + !isNowBgCross(BGC_WATER_SHALLOW) && + mWallSlideCooldown == 0 && + !isStatus(STATUS_VINE) && + !isStatus(STATUS_A8) && + !isNowBgCross(BGC_37) && + !isNowBgCross(BGC_FOOT) && + !mIsBgDamage && + mBc.getWallAttr(dir) != 7 && + !isNowBgCross(BGC_HEAD) && + !isCarry() + ) { + /// @unofficial + static const BgCross1_e flags[] = { + BGC_WALL_TOUCH_R, + BGC_WALL_TOUCH_L + }; + if (isNowBgCross(flags[mDirection]) && dir == mDirection) { + return 0; + } else { + return 1; + } + } + return 2; +} + +bool dAcPy_c::checkWallJump() { + if (isStatus(STATUS_WALL_SLIDE)) { + return false; + } + int dir; + if ( + mKey.buttonWalk(&dir) && + !isNowBgCross(BGC_37) && + !checkWallSlideEnable(dir) + ) { + if (!isStatus(STATUS_A9) && mSpeed.y < 0.0f) { + changeState(StateID_WallSlide, 0); + return true; + } + if (mKey.triggerJump()) { + changeState(StateID_WallJump, 0); + return true; + } + } + return false; +} + +void dAcPy_c::initializeState_WallSlide() { + mPyMdlMng.setAnm(PLAYER_ANIM_WSLD, 0.0f, 0.0f); + onStatus(STATUS_97); + onStatus(STATUS_WALL_SLIDE); + onStatus(STATUS_9F); + onStatus(STATUS_CAN_LAND); + mBc.mPlayerFlags |= 2; + mAccelY = getGravityData()[0]; + mAngle.y = getMukiAngle(mDirection); + mMaxSpeedF = 0.0f; + mSpeedF = 0.0f; + mAccelF = 0.0f; +} + +void dAcPy_c::finalizeState_WallSlide() { + offStatus(STATUS_WALL_SLIDE); + offStatus(STATUS_9F); + offStatus(STATUS_CAN_LAND); + mBc.mPlayerFlags &= ~2; + mAccelY = getGravityData()[0]; + mWallSlideCooldown = 4; +} + +void dAcPy_c::setWallSlideEffect() { + holdSound(SE_PLY_SLIP_TATE, 0); + if (getTallType(-1) > 2) { + return; + } + u8 idx = (mDirection ^ 1) + getTallType(-1) * 2; + if (idx >= 6) { + return; + } + mVec3_c jnt; + mPyMdlMng.mpMdl->getJointPos(&jnt, 14); + if (mDirection == 0) { + jnt.x = mPos.x + mWallBcData.mOffset / 4096.0f; + } else { + jnt.x = mPos.x - mWallBcData.mOffset / 4096.0f; + } + /// @unofficial + static const char *sc_wallSlidEffectID[] = { + "Wm_mr_wallslip_ss_r", + "Wm_mr_wallslip_ss_l", + "Wm_mr_wallslip_s_r", + "Wm_mr_wallslip_s_l", + "Wm_mr_wallslip_r", + "Wm_mr_wallslip_l" + }; + dEf::createPlayerEffect(mPlayerNo, &mSmokeEffect, sc_wallSlidEffectID[idx], 0, &jnt, nullptr, nullptr); +} + +void dAcPy_c::executeState_WallSlide() { + if (isNowBgCross(BGC_FOOT)) { + changeState(StateID_Walk, BLEND_NONE); + return; + } + if (mKey.triggerJump()) { + changeState(StateID_WallJump, 0); + return; + } + if (setHipAttackAction()) { + return; + } + int dir; + if (mKey.buttonWalk(&dir) && dir != mDirection) { + mSubstateValue += 1; + if (mSubstateValue >= 15) { + changeState(StateID_Fall, false); + } + } else { + mSubstateValue = 0; + } + if (checkWallSlideEnable(mDirection)) { + changeState(StateID_Fall, false); + return; + } + if (isMameAction()) { + mMaxFallSpeed = -0.75f; + } else { + mMaxFallSpeed = -2.0f; + } + setWallSlideEffect(); + mSpeedF = sc_DirSpeed[mDirection]; +} + +void dAcPy_c::initializeState_WallJump() { + onStatus(STATUS_97); + offStatus(STATUS_A7); + setWaterWalkFlag(); + mAccelY = 0.0f; + mSpeed.y = 0.0f; + mDirection ^= 1; + mAngle.y = getMukiAngle(mDirection); + mMaxSpeedF = 0.0f; + mSpeedF = 0.0f; + if (getTallType(-1) <= 2) { + u8 dir = mDirection; + u8 idx = dir + getTallType(-1) * 2; + if (idx < 6) { + float thing = mWallBcData.mOffset / 4096.0f; + mVec3_c pos(mPos.x - thing * sc_DirSpeed[dir], mPos.y, mPos.z); + mVec3_c pos2(pos.x - sc_DirSpeed[mDirection] * 8.0f, pos.y, pos.z); + if (!dBc_c::checkWall(&mPos, &pos2, nullptr, mLayer, mAmiLayer, nullptr)) { + pos.y += 8.0f; + float f; + if (dBc_c::checkTenjou(&pos2, &f, mLayer, mAmiLayer) && f < mPos.y + getModelHeight()) { + pos.y = f + 8.0f; + } + } + /// @unofficial + static const char *sc_wallKickEffectID[] = { + "Wm_mr_wallkick_ss_r", + "Wm_mr_wallkick_ss_l", + "Wm_mr_wallkick_s_r", + "Wm_mr_wallkick_s_l", + "Wm_mr_wallkick_r", + "Wm_mr_wallkick_l" + }; + dEf::createPlayerEffect(mPlayerNo, sc_wallKickEffectID[idx], 0, &pos, nullptr, nullptr); + } + } + mKey.offStatus(dAcPyKey_c::STATUS_FORCE_JUMP); + m_15b0 = 35; +} + +void dAcPy_c::finalizeState_WallJump() { + mAccelY = getGravityData()[0]; +} + +void dAcPy_c::executeState_WallJump() { + mSpeedF = sc_DirSpeed[mDirection] * 2.25f; + mMaxSpeedF = mSpeedF; + onStatus(STATUS_96); + float f = 3.5f; + if (isMameAction()) { + f *= 0.8125f; + } + jmpInf_c jumpInf(f, 0, BLEND_DEFAULT); + changeState(StateID_Jump, &jumpInf); + startPlayerVoice(VOICE_WALL_KICK, 0); + startSound(SE_PLY_KABE_KICK, false); + mWallSlideCooldown = 16; +} + +void dAcPy_c::setSpinHoldReq(float targetX) { + onStatus(STATUS_IS_SPIN_HOLD_REQ); + mSpinHoldReqTarget = targetX; +} + +bool dAcPy_c::setSpinSpeed(float speedF, float speedY) { + if (isState(StateID_SpinJump)) { + if (isStatus(STATUS_IS_SPIN_HOLD_REQ) || m_15ae != 0) { + return false; + } + mSpeed.y = speedY; + mSpeedF = speedF; + mKey.onStatus(dAcPyKey_c::STATUS_NO_INPUT); + m_15ae = 30; + mSpinTimer = 30; + m_1048 = 0x2000; + offNowBgCross(BGC_FOOT); + dQuake_c::getInstance()->shockMotor(getPlrNo(), dQuake_c::TYPE_7, 0, false); + return true; + } + return false; +} + +void dAcPy_c::setSpinJumpEffect(int i) { + if (!isStatus(STATUS_SPIN)) { + endSpinJumpEffect(); + } else if (fManager_c::searchBaseByID(mCarryActorID) != nullptr) { + dAcPy_c *carryPlayer = getCarryPlayer(); + if (carryPlayer != nullptr) { + carryPlayer->setSpinJumpEffectSub(i); + } + } else { + setSpinJumpEffectSub(i); + } +} + +void dAcPy_c::setSpinJumpEffectSub(int i) { + if (dScStage_c::m_isStaffCredit) { + return; + } + mVec3_c jnt1, jnt2; + mPyMdlMng.mpMdl->getJointPos(&jnt1, 11); + mPyMdlMng.mpMdl->getJointPos(&jnt2, 14); + mVec3_c pos(mPos.x, 4.0f + (jnt1.y + jnt2.y) / 2, mPos.z); + float s; + static const float scSpinJumpEffectScale[3] = { 0.6f, 0.8f, 1.0f }; + static const float scSpinJumpEffectScale_K[3] = { 0.6f, 0.7f, 0.8f }; + if (PLAYER_YELLOW_TOAD <= mPlayerType && mPlayerType <= PLAYER_BLUE_TOAD) { + s = scSpinJumpEffectScale_K[getTallType(-1)]; + } else { + s = scSpinJumpEffectScale[getTallType(-1)]; + } + mVec3_c scale(s, s, s); + if (i == 1) { + if (m_1288 == 0) { + static const char *sc_spinEffectID[] = { + "Wm_mr_normalspin", + "Wm_mr_normalspin_pm" + }; + int idx = 0; + if (mPowerup == POWERUP_PENGUIN_SUIT) { + idx = 1; + } + dEf::createPlayerEffect(mPlayerNo, &mFollowEf2, sc_spinEffectID[idx], 0, &pos, nullptr, &scale); + m_1288 = 1; + } + } else if (m_1288 != 0) { + if (!mFollowEf2.follow(&pos, nullptr, &scale)) { + m_1288 = 0; + } + } +} + +void dAcPy_c::endSpinJumpEffect() { + if (m_1288 != 0) { + m_1288 = 0; + mFollowEf2.kill(); + } +} + +void dAcPy_c::setMissSpinJumpEffect(int i) { + dAcPy_c *carryPlayer = getCarryPlayer(); + if (carryPlayer != nullptr) { + carryPlayer->setMissSpinJumpEffect(i); + return; + } + if (i == 0 && !m_128c) { + return; + } + mVec3_c jnt; + mPyMdlMng.mpMdl->getJointPos(&jnt, 1); + float s = mPyMdlMng.getSomeScale2(); + mVec3_c scale(s, s, s); + if (i == 1) { + dEf::createPlayerEffect(mPlayerNo, &mFollowEf3, "Wm_mr_halfspin", 0, &jnt, nullptr, &scale); + m_128c = 1; + } else if (m_128c != 0) { + if (!mFollowEf3.follow(&jnt, nullptr, &scale)) { + m_128c = 0; + } + } +} + +void dAcPy_c::initializeState_SpinJump() { + m_12f4 = mDirection; + onStatus(STATUS_9B); + onStatus(STATUS_9C); + onStatus(STATUS_9D); + onStatus(STATUS_92); + onStatus(STATUS_A9); + onStatus(STATUS_CAN_LAND); + onStatus(STATUS_A1); + onStatus(STATUS_SPIN); + mSpinFireBallCooldown = 0; + mSpinTimer = 30; + m_1048 = 0x2000; + setSpinJumpEffect(1); + u32 substate = (u32) mStateArg; + if (substate <= SPIN_JUMP_ACTION_1) { + startSound(SE_PLY_SPIN_ATTACK, true); + } + if (isStatus(STATUS_IS_SPIN_HOLD_REQ)) { + mPyMdlMng.setAnm(PLAYER_ANIM_SPIN_ST, 0.0f, 0.0f); + } else { + mKey.onStatus(dAcPyKey_c::STATUS_FORCE_JUMP); + jmpInf_c jumpInf(mSpeed.y, 0, BLEND_DEFAULT); + if (substate == SPIN_JUMP_ACTION_0) { + jumpInf.mSpeed = sc_JumpSpeed - 0.4f; + } + if ( + isNowBgCross(BgCross1_e(BGC_IN_SINK_SAND | BGC_ON_SINK_SAND)) && + (isNowBgCross(BGC_IN_SINK_SAND) || mPos.y < mSinkSandHeight - 4.0f) + ) { + jumpInf.mSpeed = sc_JumpSpeed - 0.7f; + } + _jumpSet(&jumpInf); + } + setStartJumpEffect(1); + dAcPy_c *carryPlayer = getCarryPlayer(); + if (carryPlayer != nullptr) { + carryPlayer->initRideSpinMove(); + } +} + +void dAcPy_c::executeState_SpinJump() { + mAngle.y += m_1048; + setCcAtSpin(); + if (mSpinFireBallCooldown != 0) { + mSpinFireBallCooldown--; + } + if (mSpinTimer != 0) { + mSpinTimer--; + if (mSpinFireBallCooldown == 0) { + if (mSpinTimer == 21) { + setSpinFireBall(); + } else if (mSpinTimer == 15) { + m_12f4 ^= 1; + setSpinFireBall(); + mSpinFireBallCooldown = 20; + } + } + } + if (isStatus(STATUS_IS_SPIN_HOLD_REQ)) { + mKey.onStatus(dAcPyKey_c::STATUS_5); + if (mKey.triggerShakeJump() && mSpinTimer < 10) { + mSpinTimer = 30; + m_1048 = 0x2000; + } + mSpeed.y = 0.0f; + mSpeedF = 0.0f; + mAccelY = 0.0f; + mAccelF = 0.0f; + sLib::chase(&mPos.x, mSpinHoldReqTarget, 1.0f); + if (!checkJumpTrigger()) { + if ( + mKey.buttonWalk(nullptr) && + (mKey.triggerRight() || mKey.triggerLeft()) + ) { + changeState(StateID_Walk, BLEND_DEFAULT); + } else { + if (mSpinTimer == 0) { + mPyMdlMng.setAnm(PLAYER_ANIM_SPIN_END); + changeState(StateID_Land, false); + } + } + } + } else { + setJumpGravity(); + maxFallSpeedSet(); + moveSpeedSet(); + airPowerSet(); + onStatus(STATUS_JUMP); + if (isNowBgCross(BGC_HEAD)) { + mSpinTimer = 0; + } + if (isNowBgCross(BGC_FOOT)) { + setLandJumpEffect(1); + mPyMdlMng.setAnm(PLAYER_ANIM_SPIN_END, 0.0f, 0.0f); + changeState(StateID_Land, false); + } + } +} + +void dAcPy_c::finalizeState_SpinJump() { + mSpinTimer = 0; + mSpinFireBallCooldown = 0; + offStatus(STATUS_9B); + offStatus(STATUS_9C); + offStatus(STATUS_9D); + offStatus(STATUS_9F); + offStatus(STATUS_SPIN); + offStatus(STATUS_92); + offStatus(STATUS_A9); + offStatus(STATUS_CAN_LAND); + offStatus(STATUS_JUMP); + offStatus(STATUS_A1); + mKey.offStatus(dAcPyKey_c::STATUS_FORCE_JUMP); + mKey.offStatus(dAcPyKey_c::STATUS_FORCE_NO_JUMP); + mKey.offStatus(dAcPyKey_c::STATUS_DISABLE_LR); + mKey.offStatus(dAcPyKey_c::STATUS_NO_INPUT); + mKey.offStatus(dAcPyKey_c::STATUS_5); + mAngle.y = getMukiAngle(mDirection); + dAcPy_c *carryPlayer = getCarryPlayer(); + if (carryPlayer != nullptr) { + carryPlayer->endRideSpinMove(); + } +} + +bool dAcPy_c::isMissSpinEnableAnm() { + if (mPyMdlMng.getAnm() == PLAYER_ANIM_STAR_ROLL_DUPLICATE) { + return false; + } + if (mPyMdlMng.getAnm() == PLAYER_ANIM_ROLL_JUMP && !mPyMdlMng.isAnmStop()) { + return false; + } + return true; +} + +s16 dAcPy_c::getMissSpinAngle() { + if (isMissSpinEnableAnm()) { + return m_105c; + } + return 0; +} + +void dAcPy_c::setMissSpin() { + m_105c = 0x1400; + startSound(SE_PLY_SPIN_ONCE, true); + if (isMissSpinEnableAnm()) { + setMissSpinJumpEffect(1); + } +} + +void dAcPy_c::resetMissSpin() { + m_105c = 0; +} + +void dAcPy_c::updateMissSpin() { + if (m_105c == 0) { + return; + } + s16 prevAngle = m_105c; + m_105c += 0x1400; + if (prevAngle < 0 && m_105c >= 0) { + m_105c = 0; + return; + } + onStatus(STATUS_TWIRL); +} + +void dAcPy_c::initializeState_RideOffJump() { + onStatus(STATUS_9B); + onStatus(STATUS_9C); + onStatus(STATUS_9D); + onStatus(STATUS_9E); + onStatus(STATUS_YOSHI_DISMOUNT_JUMP); + onStatus(STATUS_97); + onStatus(STATUS_JUMP); + onStatus(STATUS_A1); + m_12f4 = mDirection; + mSpeedMax.x = 0.0f; + mSubstateTimer = 30; + mKey.onStatus(dAcPyKey_c::STATUS_FORCE_NO_JUMP); + mAngle.y = getMukiAngle(mDirection); + mSpeedF = sc_DirSpeed[mDirection] * -1.0f; + jmpInf_c jumpInf(2.85f, 0, BLEND_DEFAULT); + _jumpSet(&jumpInf); + startSound(SE_PLY_BREAK_FREE_YOSHI, false); +} + +void dAcPy_c::finalizeState_RideOffJump() { + mAngle.x = 0; + mAngle.y = getMukiAngle(mDirection); + offStatus(STATUS_JUMP); + offStatus(STATUS_48); + offStatus(STATUS_9B); + offStatus(STATUS_9C); + offStatus(STATUS_9D); + offStatus(STATUS_9E); + offStatus(STATUS_9F); + offStatus(STATUS_88); + offStatus(STATUS_CAN_LAND); + offStatus(STATUS_YOSHI_DISMOUNT_JUMP); + offStatus(STATUS_97); + offStatus(STATUS_A1); + mKey.offStatus(dAcPyKey_c::STATUS_FORCE_JUMP); + mKey.offStatus(dAcPyKey_c::STATUS_FORCE_NO_JUMP); +} + +void dAcPy_c::executeState_RideOffJump() { + gravitySet(); + maxFallSpeedSet(); + moveSpeedSet(); + airPowerSet(); + if (mSubstateTimer == 0) { + onStatus(STATUS_9F); + onStatus(STATUS_CAN_LAND); + } + jump_common(); +} + +void dAcPy_c::initializeState_SitJump() { + onStatus(STATUS_9B); + onStatus(STATUS_9C); + onStatus(STATUS_9D); + onStatus(STATUS_9F); + onStatus(STATUS_9E); + onStatus(STATUS_CAN_LAND); + onStatus(STATUS_SIT_JUMP); + onStatus(STATUS_A0); + onStatus(STATUS_A1); + m_12f4 = mDirection; + mSpeedMax.x = 0.0f; + if (!stateArg()) { + _jumpSet(nullptr); + } else { + mPyMdlMng.setAnm(PLAYER_ANIM_S_JUMP2); + mAngle.y = getMukiAngle(mDirection); + } +} + +void dAcPy_c::finalizeState_SitJump() { + mAngle.x = 0; + mAngle.y = getMukiAngle(mDirection); + offStatus(STATUS_JUMP); + offStatus(STATUS_48); + offStatus(STATUS_9B); + offStatus(STATUS_9C); + offStatus(STATUS_9D); + offStatus(STATUS_9E); + offStatus(STATUS_9F); + offStatus(STATUS_88); + offStatus(STATUS_CAN_LAND); + offStatus(STATUS_SIT_JUMP); + offStatus(STATUS_A0); + offStatus(STATUS_A1); + offStatus(STATUS_AA); + mKey.offStatus(dAcPyKey_c::STATUS_FORCE_JUMP); + mKey.offStatus(dAcPyKey_c::STATUS_FORCE_NO_JUMP); +} + +void dAcPy_c::executeState_SitJump() { + gravitySet(); + maxFallSpeedSet(); + moveSpeedSet(); + airPowerSet(); + onStatus(STATUS_JUMP); + if (dScStage_c::m_instance->mCurrWorld == WORLD_5 && dScStage_c::m_instance->mCurrCourse == STAGE_GHOST_HOUSE) { + if (isNowBgCross(BGC_BLOCK_HIT) && isOldBgCross(BGC_SEMISOLID)) { + if (mLastPosDelta.x < 0.0f) { + mPos.x -= 4.0f; + } else { + mPos.x += 4.0f; + } + mSpeedF = 0.0f; + } + } + jump_common(); + if (mSpeed.y < 0.0f) { + offStatus(STATUS_AA); + if (!mKey.buttonCrouch() && !checkStandUpRoof()) { + jmpInf_c jumpInf(mSpeed.y, 0, BLEND_DEFAULT); + changeState(StateID_Jump, &jumpInf); + } + } +} + +void dAcPy_c::initializeState_KaniJump() { + onStatus(STATUS_9B); + onStatus(STATUS_9C); + onStatus(STATUS_9D); + onStatus(STATUS_9F); + onStatus(STATUS_9E); + onStatus(STATUS_CAN_LAND); + onStatus(STATUS_KANI_JUMP); + onStatus(STATUS_A2); + jmpInf_c jumpInf(3.0f, 1, BLEND_DEFAULT); + _jumpSet(&jumpInf); + mSpeedMax.x = 0.0f; + mAngle.y = 0; +} + +void dAcPy_c::finalizeState_KaniJump() { + mAngle.x = 0; + offStatus(STATUS_JUMP); + offStatus(STATUS_48); + offStatus(STATUS_9B); + offStatus(STATUS_9C); + offStatus(STATUS_9D); + offStatus(STATUS_9E); + offStatus(STATUS_9F); + offStatus(STATUS_88); + offStatus(STATUS_CAN_LAND); + offStatus(STATUS_KANI_JUMP); + offStatus(STATUS_A2); +} + +void dAcPy_c::executeState_KaniJump() { + gravitySet(); + maxFallSpeedSet(); + setKaniMoveSpeed(true); + onStatus(STATUS_JUMP); + jump_common(); + if (mPos.y < m_d8c - 4.0f) { + changeState(StateID_Fall, false); + } +} + +void dAcPy_c::initializeState_CannonJump() { + onStatus(STATUS_BD); + onStatus(STATUS_CANNON_JUMP); + onStatus(STATUS_88); + onStatus(STATUS_7F); + if (m_68 == 1) { + onStatus(STATUS_7A); + } + clearNowBgCross(); + dQuake_c::m_instance->shockMotor(mPlayerNo, dQuake_c::TYPE_5, 0, false); + startPlayerVoice(VOICE_CANNON_SHOT_S, 0); + mPyMdlMng.setAnm(PLAYER_ANIM_SHOOT); + mKey.onStatus(dAcPyKey_c::STATUS_DISABLE_LR); + mKey.onStatus(dAcPyKey_c::STATUS_FORCE_NO_JUMP); + mAngle.y = getMukiAngle(mDirection); + int ang = cM::atan2s(std::fabs(mSpeedF), mSpeed.y); + mAngle.x = 0x4000 - ang; + mSubstateValue = 0; + m_12b4 = (u32) mStateArg; + m_12a8 = mPos; +} + +void dAcPy_c::finalizeState_CannonJump() { + float data = getSpeedData()->mHighSpeed; + if (mSpeedF > data) { + mSpeedF = data; + } + if (mSpeedF < -data) { + mSpeedF = -data; + } + offStatus(STATUS_7F); + offStatus(STATUS_CANNON_JUMP); + offStatus(STATUS_BD); + offStatus(STATUS_88); + offStatus(STATUS_8E); + offStatus(STATUS_7A); + mKey.offStatus(dAcPyKey_c::STATUS_DISABLE_LR); + mKey.offStatus(dAcPyKey_c::STATUS_FORCE_NO_JUMP); + mAngle.x = 0; +} + +void dAcPy_c::executeState_CannonJump() { + if (isStatus(STATUS_8E)) { + onStatus(STATUS_8D); + } + switch ((CannonJumpSubstate_e) mSubstate) { + case CANNON_JUMP_ACTION_0: { + setCcAtCannon(); + if (m_12b4 != 0) { + m_12b4--; + mAccelF = 0.0f; + mAccelY = 0.0f; + } else { + mAccelY = -0.5f; + if (std::fabs(mSpeedF) >= 1.0f) { + mAccelF = 0.03f; + } else { + mAccelF = 0.0f; + } + } + mVec3_c tmp(m_12a8.x - mPos.x, m_12a8.y - mPos.y, 0.0f); + if (PSVECMag(tmp) >= 8.0f) { + if (!isStatus(STATUS_8E)) { + offStatus(STATUS_7F); + } + offZPosSetNone(); + } + int ang = cM::atan2s(std::fabs(mSpeedF), mSpeed.y); + mAngle.x = 0x4000 - ang; + if (isNowBgCross(BGC_HEAD) || isNowBgCross(BgCross1_e(BGC_WALL_TOUCH_L_2 | BGC_WALL_TOUCH_R_2))) { + mSpeed.y = 0.0f; + changeState(StateID_Fall, false); + } else { + if (mSpeed.y <= 0.0f && std::fabs(mSpeedF) < 0.1f) { + changeState(StateID_Fall, false); + } + if (isNowBgCross(BGC_FOOT)) { + mPyMdlMng.setAnm(PLAYER_ANIM_SHOOT_SLIP); + mSubstate = CANNON_JUMP_ACTION_1; + mAngle.x = 0; + offStatus(STATUS_BD); + } + } + break; + } + case CANNON_JUMP_ACTION_1: + if (mSpeedF) { + setCcAtCannon(); + } + gravitySet(); + maxFallSpeedSet(); + mMaxSpeedF = 0.0f; + powerSet(); + if (isNowBgCross(BGC_FOOT)) { + setCrouchSmokeEffect(); + if (!(std::fabs(mSpeedF) < 1.0f && checkJumpTrigger()) && std::fabs(mSpeedF) <= 0.1f) { + mPyMdlMng.setAnm(PLAYER_ANIM_SHOOT_SLIP_END); + mSubstate = CANNON_JUMP_ACTION_2; + mSpeedF = 0.0f; + } + } else { + mSubstate = CANNON_JUMP_ACTION_0; + mPyMdlMng.setAnm(PLAYER_ANIM_SHOOT); + } + break; + case CANNON_JUMP_ACTION_2: + if (isNowBgCross(BGC_FOOT)) { + if (checkJumpTrigger()) { + return; + } + } else { + changeState(StateID_Fall, false); + return; + } + if (mPyMdlMng.isAnmStop()) { + changeState(StateID_Walk, BLEND_DEFAULT); + } + break; + } +} + +void dAcPy_c::initializeState_BlockJump() { + onStatus(STATUS_7F); + onStatus(STATUS_7A); + mSubstate = (int) mStateArg; + if (mSubstate == BLOCK_JUMP_ACTION_0) { + jmpInf_c jumpInf(sc_JumpSpeed, 0, BLEND_DEFAULT); + _jumpSet(&jumpInf); + } else { + mSubstateTimer = 10; + } + mSpeedF = 0.5f; + mKey.onStatus(dAcPyKey_c::STATUS_FORCE_JUMP); + if (isItemKinopio()) { + startSound(SE_VOC_ITEM_KO_FOUND, false); + } +} + +void dAcPy_c::finalizeState_BlockJump() { + offStatus(STATUS_7F); + offStatus(STATUS_7A); + mKey.offStatus(dAcPyKey_c::STATUS_FORCE_JUMP); +} + +void dAcPy_c::executeState_BlockJump() { + gravitySet(); + maxFallSpeedSet(); + moveSpeedSet(); + airPowerSet(); + jump_common(); + if (mSubstate == BLOCK_JUMP_ACTION_0) { + if (mSpeed.y < 0.0f) { + changeState(StateID_Fall, false); + } + if (mSubstateTimer == 0) { + offStatus(STATUS_7F); + if (isNowBgCross(BGC_HEAD)) { + changeState(StateID_Fall, false); + } + } + } else if (mSubstateTimer == 0) { + changeState(StateID_Fall, false); + } +} + +void dAcPy_c::setSlipAction() { + mMoveSakaAngle = mBc.getSakaAngleBySpeed(mSpeedF); + if (mPowerup == POWERUP_PENGUIN_SUIT) { + if (isState(StateID_HipAttack)) { + mDirection = mBc.getSakaDir(); + } + changeState(StateID_PenguinSlide, 0); + } else { + changeState(daPlBase_c::StateID_Slip, 0); // [why daPlBase_c version?] + } +} + +void dAcPy_c::setSlipSE() { + if (!mSpeedF) { + return; + } + if (isNowBgCross(BGC_WATER_TOUCH) && mPowerup == POWERUP_MINI_MUSHROOM) { + holdSound(SE_PLY_SLIP_W, 0); + } else { + daPlBase_c::setSlipSE(); + } +} + +void dAcPy_c::setSlipEffect() { + daPlBase_c::setSlipSmokeEffect(); + setSlipSE(); +} + +void dAcPy_c::slipActionMove(int mode) { + if (isNowBgCross(BGC_FOOT) && std::fabs(mSpeedF) > 0.1f) { + setSlipEffect(); + } + daPlBase_c::slipActionMove(mode); +} + +void dAcPy_c::initializeState_Slip() { + daPlBase_c::initializeState_Slip(); + releaseCarryActor(); + onStatus(STATUS_9F); + setWaterWalkFlag(); +} + +void dAcPy_c::finalizeState_Slip() { + daPlBase_c::finalizeState_Slip(); + offStatus(STATUS_9F); +} + +void dAcPy_c::executeState_Slip() { + daPlBase_c::executeState_Slip(); +} + +void dAcPy_c::initializeState_RollSlip() { + m_d8c = mPos.y; + mSubstate = ROLL_SLIP_ACTION_0; + mPyMdlMng.setAnm(PLAYER_ANIM_STAR_ROLL_DUPLICATE); + mMaxSpeedF = getSlipMaxSpeedF(); + mMaxFallSpeed = -3.0f; + m_94 = 2.0f; + mSubstateTimer = 4; + mNoInteractTimer = 10; + setInvalidKeyTimer_LR(10, 1); + releaseCarryActor(); + onStatus(STATUS_32); + onStatus(STATUS_97); + onStatus(STATUS_CAN_LAND); + onStatus(STATUS_31); + onStatus(STATUS_88); + onStatus(STATUS_JUMP_DAI_COOLDOWN); + onStatus(STATUS_A1); + mKey.onStatus(dAcPyKey_c::STATUS_FORCE_JUMP); +} + +void dAcPy_c::finalizeState_RollSlip() { + offStatus(STATUS_32); + offStatus(STATUS_9F); + offStatus(STATUS_CAN_LAND); + offStatus(STATUS_31); + offStatus(STATUS_88); + offStatus(STATUS_JUMP_DAI_COOLDOWN); + offStatus(STATUS_A1); + mNoInteractTimer = 0; + mTimer_a8 = 0; + mKey.offStatus(dAcPyKey_c::STATUS_FORCE_JUMP); + if (std::fabs(mSpeedF) > 1.0f) { + mSpeedF = sc_DirSpeed[mDirection]; + } +} + +void dAcPy_c::executeState_RollSlip() { + if (mSubstateTimer == 0) { + offStatus(STATUS_JUMP_DAI_COOLDOWN); + } + gravitySet(); + moveSpeedSet(); + powerSet(); + turnAngle(); + if (mSubstateValue != 0 && mKey.triggerJump()) { + setJump(sc_JumpSpeed, mSpeedF * 0.8f, true, 0, 1); + return; + } + switch ((RollSlipSubstate_e) mSubstate) { + case ROLL_SLIP_ACTION_0: + holdSound(SE_PLY_MOVE_ROLLING, false); + switch (mSubstateValue) { + case 0: + mAccelF = 0.0f; + m_94 = 1.5f; + mPyMdlMng.mpMdl->setRate(m_94); + if (isNowBgCross(BGC_FOOT)) { + mSubstateValue = 1; + mSpeedF = sc_DirSpeed[mDirection]; + mSpeed.y = 2.0f; + mPyMdlMng.mpMdl->setFrame(0.0f); + } else if (isNowBgCross(BgCross1_e(BGC_WALL_TOUCH_L_2 | BGC_WALL_TOUCH_R_2))) { + mSubstateValue = 1; + mDirection = mDirection ^ 1; + mSpeedF = sc_DirSpeed[mDirection]; + mSpeed.y = 0.0f; + mPyMdlMng.mpMdl->setFrame(0.0f); + } + break; + case 1: + mPyMdlMng.mpMdl->setRate(0.5f); + if (isNowBgCross(BGC_FOOT)) { + if (isNowBgCross(BGC_FOOT)) { + if (!mKey.buttonCrouch()) { + setSlipAction_ToEnd(); + } else { + setSlipAction_ToStoop(); + } + } + } + break; + case 2: + if (!isNowBgCross(BGC_FOOT)) { + changeState(StateID_Fall, false); + return; + } + float s = std::fabs(mSpeedF) * 0.5f; + if (s > 1.0f) { + s = 1.0f; + } + if (s < 0.1f) { + s = 0.1f; + } + if (mSpeedF * sc_DirSpeed[mDirection] < 0.0f) { + s = -s; + } + mPyMdlMng.mpMdl->setRate(s); + if (std::fabs(mSpeedF) < 1.1f) { + if (!mKey.buttonCrouch()) { + setSlipAction_ToEnd(); + } else { + setSlipAction_ToStoop(); + } + } + } + // [Fallthrough...?] + case ROLL_SLIP_ACTION_1: + mMaxSpeedF = 0.0f; + if (mPyMdlMng.isAnmStop()) { + changeState(StateID_Crouch, CROUCH_ARG_FROM_OTHER); + } + break; + case ROLL_SLIP_ACTION_2: + mSpeedF = 0.0f; + mMaxSpeedF = 0.0f; + if (mPyMdlMng.isAnmStop()) { + changeActionSlipEnd(BLEND_DEFAULT); + } + break; + } +} + +void dAcPy_c::initializeState_PenguinSlide() { + mSubstate = PENGUIN_SLIDE_ACTION_0; + mMaxSpeedF = getSlipMaxSpeedF(); + if (isNowBgCross(BGC_FOOT) && !isSlipSaka()) { + float f = std::fabs(mSpeedF) / getSpeedData()->mHighSpeed + 0.2f; + if (f > 1.0f) { + f = 1.0f; + } + if (f < 0.5f) { + f = 0.5f; + } + m_54c = mSpeedF + f * sc_DirSpeed[mDirection]; + if (m_54c > 4.0f) { + m_54c = 4.0f; + } + if (m_54c < -4.0f) { + m_54c = -4.0f; + } + m_548 = 1; + } + if (mPos.y >= mWaterHeight - 4.0f) { + onStatus(STATUS_CAN_WATER_SLIDE); + } + mSubstateTimer = 8; + releaseCarryActor(); + onStatus(STATUS_30); + onStatus(STATUS_97); + onStatus(STATUS_9F); + onStatus(STATUS_A2); + onStatus(STATUS_PENGUIN_SLIDE); + onStatus(STATUS_88); + + mPyMdlMng.setAnm(PLAYER_ANIM_P_SLIP); + startPlayerVoice(VOICE_PNGN_SLIDE, 0); + m_540 = 30; + m_544 = getData(0); +} + +void dAcPy_c::finalizeState_PenguinSlide() { + offStatus(STATUS_30); + offStatus(STATUS_9F); + offStatus(STATUS_A2); + offStatus(STATUS_PENGUIN_SLIDE); + offStatus(STATUS_88); + offStatus(STATUS_INITIAL_SLIDE); + offStatus(STATUS_CAN_WATER_SLIDE); + m_1598 = 0.0f; + mAngle.x = 0; + m_b98 = 10; +} + +bool dAcPy_c::checkPenguinSlideJump() { + if (isNowBgCross(BGC_FOOT) && mKey.triggerJump()) { + int dir = -1; + if (mKey.buttonDown() || (mKey.buttonWalk(&dir) && dir == mDirection)) { + mPyMdlMng.setAnm(PLAYER_ANIM_P_SLIP_JUMP); + startSound(SE_PLY_PNGN_JUMP, false); + onStatus(STATUS_PENGUIN_SLIDE_JUMP); + offNowBgCross(BGC_FOOT); + float tmp = std::fabs(mSpeedF) - 1.5f; + mSpeed.y = data_802f5a48[2] + tmp * data_802f5a48[3]; + if (mSpeed.y > data_802f5a48[1]) { + mSpeed.y = data_802f5a48[1]; + } + if (mSpeed.y < data_802f5a48[2]) { + mSpeed.y = data_802f5a48[2]; + } + } else { + setJump(sc_JumpSpeed, mSpeedF * 0.8f, true, 0, 1); + } + return true; + } + return false; +} + +void dAcPy_c::executeState_PenguinSlide() { + gravitySet(); + maxFallSpeedSet(); + moveSpeedSet(); + powerSet(); + m_1598 = 0.0f; + if (!isStatus(STATUS_CAN_WATER_SLIDE) && mPos.y >= mWaterHeight - 1.0f) { + onStatus(STATUS_CAN_WATER_SLIDE); + } + if (isNowBgCross(BGC_ON_WATER_MOVE)) { + mSpeed.y = sc_MaxFallSpeed_Foot; + } + if (m_544 != 0) { + m_544--; + } + if (isNowBgCross(BGC_FOOT) && m_540 != 0) { + m_540--; + } + s16 newAng = 0; + if (isNowBgCross(BGC_FOOT)) { + newAng = mBc.getSakaAngle(mDirection); + } + sLib::addCalcAngle(&mAngle.x.mAngle, newAng, 4, 0x2000, 0x40); + if (isNowBgCross(BGC_FOOT)) { + switch ((PenguinSlideSubstate_e) mSubstate) { + case PENGUIN_SLIDE_ACTION_0: + if (checkPenguinSlideJump()) { + return; + } + break; + case PENGUIN_SLIDE_ACTION_1: + if (setCrouchJump()) { + return; + } + break; + case PENGUIN_SLIDE_ACTION_2: + if (checkJumpTrigger()) { + return; + } + break; + } + } + if (mPowerup != POWERUP_PENGUIN_SUIT) { + changeState(StateID_Walk, BLEND_NONE); + return; + } + if (mSpeedF * sc_DirSpeed[mDirection] < 0.0f) { + mDirection = mDirection ^ 1; + } + int ang = turnAngle(); + switch ((PenguinSlideSubstate_e) mSubstate) { + case PENGUIN_SLIDE_ACTION_0: + if (mPlayerType == PLAYER_LUIGI) { + m_1598 = -0.5f; + } else { + m_1598 = 1.0f; + } + if (!isStatus(STATUS_DEMO_NEXT_GOTO_BLOCK) && m_540 == 0) { + if (!isNowBgCross(BGC_FOOT)) { + offStatus(STATUS_INITIAL_SLIDE); + } + if (!isStatus(STATUS_INITIAL_SLIDE) && (isNowBgCross(BGC_FOOT) || mSpeed.y < 0.0f)) { + int dir = -1; + if (!(mKey.buttonDown() || (mKey.buttonWalk(&dir) && dir == mDirection))) { + onStatus(STATUS_52); + changeState(StateID_Walk, BLEND_NONE); + return; + } + } + } + if (isNowBgCross(BGC_FOOT)) { + setPenguinSlideEffect(); + if (mPyMdlMng.getAnm() != PLAYER_ANIM_P_SLIP) { + mPyMdlMng.setAnm(PLAYER_ANIM_P_SLIP); + } + if (isStatus(STATUS_PENGUIN_SLIDE_JUMP)) { + offStatus(STATUS_PENGUIN_SLIDE_JUMP); + setPenguinSlideLandEffect(); + } + } else if (isStatus(STATUS_PENGUIN_SLIDE_JUMP)) { + if (mSpeed.y < 0.0f && mPyMdlMng.getAnm() != PLAYER_ANIM_P_SLIP_JUMP2) { + mPyMdlMng.setAnm(PLAYER_ANIM_P_SLIP_JUMP2); + } + } + daPlBase_c::slipActionMove(ang); + if (isNowBgCross(BGC_FOOT)) { + if (mGroundType == GROUND_TYPE_WATER) { + holdSound(SE_PLY_PNGN_SLIP_SEA, std::fabs(mSpeedF), false); + } else { + holdSound(SE_PLY_PNGN_SLIP, false); + } + } + break; + case PENGUIN_SLIDE_ACTION_1: + mMaxSpeedF = 0.0f; + if (mPyMdlMng.isAnmStop()) { + changeState(StateID_Crouch, CROUCH_ARG_FROM_OTHER); + return; + } + break; + case PENGUIN_SLIDE_ACTION_2: + if (mPyMdlMng.isAnmStop()) { + changeActionSlipEnd(BLEND_DEFAULT); + return; + } + break; + } + if (isNowBgCross(BGC_FOOT)) { + if (isSlipSaka()) { + if (mMaxSpeedF * mSpeedF > 0.0f) { + mAccelF = 1.2f * mAccelF; + m_544 = data_802f5a48[0]; + } else { + m_548 = 0; + if (getPowerChangeType(true) != POWER_CHANGE_NORMAL) { + mAccelF = 0.01f; + } + } + } else { + if (getPowerChangeType(true) != POWER_CHANGE_NORMAL) { + mAccelF = 0.005f; + } + if (m_544 && mMaxSpeedF == 0.0f) { + mAccelF = 0.0f; + } + } + } else { + mAccelF = 0.0f; + mMaxSpeedF = std::fabs(mSpeedF); + } + if (m_548 == 1) { + if (isStatus(STATUS_FOLLOW_MAME_KURIBO) || std::fabs(mSpeedF) >= std::fabs(m_54c)) { + m_548 = 0; + } else { + mAccelF = 0.1f; + mMaxSpeedF = m_54c; + } + } +} + +void dAcPy_c::setPenguinSlideEffect() { + if (!isNowBgCross(BGC_FOOT)) { + return; + } + mAng3_c ang(0, 0, 0); + if (mDirection == 1) { + ang.y = 0x8000; + } + mVec3_c efPos; + if (mGroundType == GROUND_TYPE_WATER) { + efPos.set(mPos.x, mWaterHeight, mPos.z); + dEf::createPlayerEffect(mPlayerNo, &mLevelEf4, "Wm_mr_waterswim", 0, &efPos, nullptr, nullptr); + dEf::createPlayerEffect(mPlayerNo, &mLevelEf5, "Wm_en_cmnwater02", 0, &efPos, &ang, nullptr); + } else { + mpMdlMng->mpMdl->getJointPos(&efPos, 1); + static const char *sc_penguinSlidEffectID[] = { + "Wm_mr_penguinsmoke", + "Wm_mr_penguinsnow", + "Wm_mr_pdesertsmoke", + "Wm_mr_penguinice", + "Wm_mr_penguinsmoke", + "Wm_mr_waterswim", + "Wm_mr_penguinsmoke", + "Wm_mr_pdesertsmoke", + "Wm_mr_penguinsmoke", + "Wm_mr_pbeachsmoke", + "Wm_mr_penguinsmoke", + "Wm_mr_penguinsmoke", + "Wm_mr_penguinsmoke" + }; + dEf::createPlayerEffect(mPlayerNo, &mLevelEf4, sc_penguinSlidEffectID[mGroundType], 0, &efPos, nullptr, nullptr); + switch (mGroundType) { + case GROUND_TYPE_SNOW: + dEf::createPlayerEffect(mPlayerNo, &mLevelEf5, "Wm_mr_p_snowslip", 0, &efPos, &ang, nullptr); + break; + case GROUND_TYPE_ICE: + dEf::createPlayerEffect(mPlayerNo, &mLevelEf5, "Wm_mr_p_iceslip", 0, &efPos, &ang, nullptr); + break; + default: + break; + } + } +} + +void dAcPy_c::setPenguinSlideLandEffect() { + setLandSmokeEffect(0); + if (mGroundType == GROUND_TYPE_WATER) { + startSound(SE_PLY_SPLASH_SHALLOW, false); + } +} + +bool dAcPy_c::isWaitFrameCountMax() { + return mWaitFrameCount >= 80; +} + +bool dAcPy_c::checkWalkNextAction() { + if (checkCarryThrow()) { + return true; + } + if (checkSlip()) { + return true; + } + if (checkJumpTrigger()) { + return true; + } + if (!isNowBgCross(BGC_FOOT)) { + mSpeed.y = 0.0f; + if (setDelayHelpJump()) { + return true; + } + if (mAirWalkTimer == 0) { + changeState(StateID_Fall, false); + return true; + } + } + if (isState(StateID_Walk) && mKey.buttonWalk(nullptr) && mDirection != mPrevDirection) { + mKey.onStatus(dAcPyKey_c::STATUS_SHAKE_COOLDOWN); + if (checkTurn()) { + return true; + } + } + if (isState(daPlBase_c::StateID_Walk) || isState(StateID_Land)) { // [why daPlBase_c?] + if (checkCrouch()) { + return true; + } + } + return false; +} + +void dAcPy_c::setWalkActionAnm(AnmBlend_e blendMode) { + float speed = std::fabs(mSpeedF); + float f; + if (mPowerup == POWERUP_MINI_MUSHROOM) { + if (speed <= getSpeedData()->mLowSpeed) { + float tmp = speed * 2.0f * 1.45f; + f = (tmp < 2.0f) ? 2.0f : tmp; + } else { + float tmp = speed * 1.5f * 1.45f; + f = (tmp < 0.5f) ? 0.5f : tmp; + } + } else { + if (speed <= getSpeedData()->mLowSpeed) { + float tmp = speed * 2.0f; + f = (tmp < 2.0f) ? 2.0f : tmp; + } else { + float tmp = speed * 1.5f; + f = (tmp < 0.5f) ? 0.5f : tmp; + } + } + float g = 4.0f; + if (mPowerup == POWERUP_MINI_MUSHROOM) { + if (speed <= getSpeedData()->mLowSpeed) { + g = 8.7f; + } else { + g = 5.8f; + } + } + if ( + isNowBgCross(BGC_ON_BELT_L) && mSpeedF > 0.0f || + isNowBgCross(BGC_ON_BELT_R) && mSpeedF < 0.0f + ) { + float tmp = speed * 2.5f; + f = (tmp < 2.0f) ? 2.0f : ((tmp > g) ? g : tmp); + } + float h = f; + if (isSaka() && mBc.getSakaUpDown(mDirection) == 1 && mMaxSpeedF && mSpeedF * sc_DirSpeed[mDirection] >= 0.0f) { + h = f * 2.0f; + if (h > g) { + h = g; + } + } + if (mPowerup != POWERUP_PENGUIN_SUIT && isNowBgCross(BGC_ON_ICE) && speed < getSpeedData()->mMediumSpeed) { + float tmp = h * 8.0f; + h = (tmp > g) ? g : tmp; + } + if (isNowBgCross(BgCross1_e(BGC_ON_SINK_SAND | BGC_IN_SINK_SAND))) { + if (isNowBgCross(BGC_IN_SINK_SAND)) { + h *= 0.5f; + } else { + h *= 0.7f; + } + } + setNormalWalkAnm(blendMode, h); +} + +void dAcPy_c::setWaitActionAnm(AnmBlend_e blendMode) { + if (dScStage_c::m_isStaffCredit && isStatus(STATUS_ENDING_DANCE_AUTO)) { + mPyMdlMng.setAnm(PLAYER_ANIM_ENDING_WAIT); + return; + } + if (isStatus(STATUS_63)) { + mPyMdlMng.setAnm(PLAYER_ANIM_WAIT_DUPLICATE2); + return; + } + /// @unofficial + static const float scSakaCheckOffset[] = { 2.0f, 0.0f, -2.0f, 4.0f, 0.0f, -4.0f }; + s16 ang = mStillSakaAngle; + int count = 0; + float sum = 0.0f; + for (int i = 0; i < 3; i++) { + mVec3_c p(mPos.x + scSakaCheckOffset[3 + i], mPos.y + 5.0f, mPos.z); + s16 tmpAng; + float f; + if (dBc_c::checkGroundAngle(&p, &f, &tmpAng, mLayer, mAmiLayer, -1, nullptr, 0) && std::fabs(f - mPos.y) < 8.0f) { + count++; + sum += tmpAng; + } + } + if (count != 0) { + ang = sum / count; + } + static const int scSlopeWaitAnm[] = { PLAYER_ANIM_SLOPE_WAIT_L, PLAYER_ANIM_SLOPE_WAIT_R }; + static const int scLongWaitAnm[] = { PLAYER_ANIM_WAIT_L, PLAYER_ANIM_WAIT_R }; + if (ang != 0 || m_80 != 0) { + ang = -ang * sc_DirSpeed[mDirection]; + float f = ang * mAng::AngleToDegreeCoefficient + 70.0f; + if (f < 0.0f) { + f = 0.0f; + } + if (f > 140.0f) { + f = 140.0f; + } + if (blendMode == BLEND_DEFAULT) { + mPyMdlMng.setAnm(scSlopeWaitAnm[mDirection], f); + } else { + mPyMdlMng.setAnm(scSlopeWaitAnm[mDirection], 0.0f, f); + } + mPyMdlMng.mpMdl->m_17c |= 0x40; + m_80 = 1; + } else { + if (blendMode == BLEND_DEFAULT) { + mPyMdlMng.setAnm(scLongWaitAnm[mDirection]); + } else { + mPyMdlMng.setAnm(scLongWaitAnm[mDirection], 0.0f, 0.0f); + } + } +} + +bool dAcPy_c::isIceSlipAnmPlay() { + if (isNowBgCross(BGC_ON_ICE) && !mKey.buttonWalk(nullptr) && mPowerup != POWERUP_PENGUIN_SUIT) { + return true; + } + return false; +} + +void dAcPy_c::setNormalWalkAnm(AnmBlend_e blendMode, float speedRate) { + if (isIceSlipAnmPlay()) { + switch (mWalkAnmState) { + case 0: + if (isNowBgCross(BGC_LIFT) && std::fabs(mBc.mIceSpeed) > 1.0f || std::fabs(mSpeedF) > 0.82f) { + if (mSpeedF * sc_DirSpeed[mDirection] < 0.0f) { + mPyMdlMng.setAnm(PLAYER_ANIM_ICE_SLIP_B); + } else { + mPyMdlMng.setAnm(PLAYER_ANIM_ICE_SLIP_F); + } + mWalkAnmState = 1; + } else { + setWaitActionAnm(blendMode); + } + break; + case 1: + calcAccOnIceLift(); + if (mPyMdlMng.isAnmStop()) { + setWaitActionAnm(blendMode); + mWalkAnmState = 2; + } + break; + case 2: + calcAccOnIceLift(); + setWaitActionAnm(blendMode); + break; + } + holdSound(SE_PLY_ICE_SLIP, std::fabs(mSpeedF), false); + } else { + mWalkAnmState = 0; + onStatus(STATUS_62); + int anmID; + if (isCarry()) { + anmID = (mPyMdlMng.mpMdl->m_17c & 0x4) ? PLAYER_ANIM_CARRY_P_WALK : PLAYER_ANIM_CARRY_WALK; + blendMode = BLEND_NONE; + } else { + if ( + isNowBgCross(BGC_ON_BELT_L) && mSpeedF > 0.0f || + isNowBgCross(BGC_ON_BELT_R) && mSpeedF < 0.0f + ) { + anmID = PLAYER_ANIM_RUN; + } else { + float speed = std::fabs(mSpeedF); + if (speed <= getSpeedData()->mLowSpeed) { + anmID = PLAYER_ANIM_RUN; + } else if (speed < getSpeedData()->mHighSpeed) { + anmID = PLAYER_ANIM_B_DASH; + } else { + anmID = PLAYER_ANIM_B_DASH2; + } + } + } + if (!mPyMdlMng.isAnm(anmID)) { + float blendDuration = 0.0f; + if (blendMode == BLEND_DEFAULT) { + blendDuration = dPyMdlMng_c::getHIO(anmID).mBlendDuration; + } + mPyMdlMng.setAnm(anmID, speedRate, blendDuration, 0.0f); + } else { + mPyMdlMng.mpMdl->setRate(speedRate); + } + } +} + +void dAcPy_c::walkActionInit_Wait(AnmBlend_e blendMode) { + mSubstate = 0; + mSubstateTimer = 150; + mWaterWalkTimer = 8; + setWaitActionAnm(blendMode); +} + +void dAcPy_c::walkAction_Wait() { + if (!isWaitFrameCountMax()) { + mWaitFrameCount++; + } + if (mSpeedF) { + walkActionInit_Move(BLEND_DEFAULT); + return; + } + setWaitActionAnm(BLEND_NONE); + if (isStatus(STATUS_63)) { + mAngle.y.chase(0, 0x400); + } else { + turnAngle(); + } + if (mSubstateTimer == 0) { + m_15b2 = 8; + } + if (isStatus(STATUS_CAN_WATER_WALK)) { + if (!sLib::calcTimer(&mWaterWalkTimer)) { + offStatus(STATUS_CAN_WATER_WALK); + m_15b6 = 30; + } + } +} + +void dAcPy_c::walkActionInit_Move(AnmBlend_e blendMode) { + mSubstate = 1; + setWalkActionAnm(blendMode); +} + +void dAcPy_c::walkAction_Move() { + m_80 = 0; + mWaitFrameCount = 0; + turnAngle(); + setRunOnWaterEffect(); + daPlBase_c::walkAction_Move(); + if (m_88 == 0 && !isNowBgCross(BGC_WATER_TOUCH)) { + m_88 = 1; + } + if (m_88 == 1) { + setWaterWalkFlag(); + } +} + +void dAcPy_c::initializeState_Walk() { + AnmBlend_e blendMode = stateArg(); + calcSpeedOnIceLift(); + m_88 = 1; + if (isOldBgCross(BGC_WATER_SHALLOW)) { + m_88 = 0; + } + if (mSpeedF) { + walkActionInit_Move(blendMode); + } else { + walkActionInit_Wait(blendMode); + } + if (isItemKinopio()) { + setControlDemoKinopioWalk(); + } + onStatus(STATUS_9B); + onStatus(STATUS_9D); + onStatus(STATUS_9E); + onStatus(STATUS_9F); + onStatus(STATUS_92); + onStatus(STATUS_A0); + offStatus(STATUS_ON_WATER_MOVE); + onStatus(STATUS_A2); + onStatus(STATUS_A3); + m_80 = 0; +} + +void dAcPy_c::executeState_Walk() { + daPlBase_c::executeState_Walk(); + mAccelY = getGravityData()[0]; + maxFallSpeedSet(); + moveSpeedSet(); + grandPowerSet(); + if (isNowBgCross(BGC_FOOT)) { + if (isNowBgCross(BGC_ON_WATER_MOVE)) { + onStatus(STATUS_ON_WATER_MOVE); + } else { + offStatus(STATUS_ON_WATER_MOVE); + } + } + offStatus(STATUS_CAN_LAND); + if (isOnSinkSand()) { + onStatus(STATUS_CAN_LAND); + } + if (!checkWalkNextAction()) { + switch (mSubstate) { + case 0: + walkAction_Wait(); + break; + case 1: + walkAction_Move(); + break; + } + if (!(mPyMdlMng.getFlags() & 0x1000) && mPyMdlMng.getFlags2() & 0x40) { + mPyMdlMng.mpMdl->m_17c &= ~0x40; + mPyMdlMng.mpMdl->releaseBodyAnm(0.0f); + } + } +} + +void dAcPy_c::finalizeState_Walk() { + daPlBase_c::finalizeState_Walk(); + mWaitFrameCount = 0; + offStatus(STATUS_9B); + offStatus(STATUS_9D); + offStatus(STATUS_9E); + offStatus(STATUS_9F); + offStatus(STATUS_92); + offStatus(STATUS_A0); + offStatus(STATUS_A2); + offStatus(STATUS_CAN_LAND); + offStatus(STATUS_A3); + mWalkAnmState = 0; + if (mPyMdlMng.getFlags2() & 0x40) { + mPyMdlMng.mpMdl->m_17c &= ~0x40; + mPyMdlMng.mpMdl->releaseBodyAnm(0.0f); + } +} + +void dAcPy_c::setRunOnWaterEffect() { + if (isNowBgCross(BGC_ON_WATER_MOVE)) { + static const char *sc_waterRunEffectID[] = { + "Wm_mr_waterrun_l_ss", + "Wm_mr_waterrun_r_ss" + }; + dEf::createPlayerEffect(mPlayerNo, &mSmokeEffect, sc_waterRunEffectID[mDirection], 0, &mPos, nullptr, nullptr); + } +} + +void dAcPy_c::initializeState_Turn() { + onStatus(STATUS_9F); + onStatus(STATUS_A2); + mSubstate = 0; + if (getPowerChangeType(false) == POWER_CHANGE_ICE) { + mPyMdlMng.setAnm(PLAYER_ANIM_ICE_TURN, 0.0f, 0.0f); + } else { + mPyMdlMng.setAnm(PLAYER_ANIM_TURN, 0.0f, 0.0f); + } + mAngle.y = getMukiAngle((mSpeedF < 0.0f) ? DIR_LR_L : DIR_LR_R); + mDirection ^= 1; + mMaxSpeedF = 0.0f; + mAccelY = getGravityData()[0]; + maxFallSpeedSet(); + turnPowerSet(); + mKey.onStatus(dAcPyKey_c::STATUS_SHAKE_COOLDOWN); +} + +void dAcPy_c::finalizeState_Turn() { + offStatus(STATUS_9F); + offStatus(STATUS_A2); + fadeOutTurnEffect(); +} + +void dAcPy_c::turnPowerSet() { + u8 dir; + if (mSpeedF < 0.0f) { + dir = 1; + } else if (mSpeedF > 0.0f) { + dir = 0; + } else { + dir = mDirection; + } + sTurnPowerData data; + getTurnPower(data); + switch (mSubstate) { + case 0: + case 1: + if (isSaka()) { + if (mBc.getSakaUpDown(dir) == 1) { + mAccelF = data.mSakaUp; + } else { + mAccelF = data.mSakaDown; + } + } else { + mAccelF = data.mNormal; + } + if (isStatus(STATUS_89)) { + mAccelF = getAccelF() * scTurnPowerUpRate; + } + break; + case 2: + mAccelF = data.mAir; + break; + } +} + +void dAcPy_c::setTurnSmokeEffect() { + mVec3_c efPos; + mPyMdlMng.mpMdl->getJointPos(&efPos, 7); + setBrakeSmokeEffect(efPos); + daPlBase_c::setTurnSmokeEffect(); +} + +void dAcPy_c::executeState_Turn() { + turnPowerSet(); + if (!checkWalkNextAction()) { + switch (mSubstate) { + case 0: + setTurnSmokeEffect(); + if (mSpeedF == 0.0f) { + mSubstateTimer = 8; + mSubstate = 1; + } + if (!mKey.buttonWalk(nullptr)) { + if (mSpeedF) { + mDirection = mSpeedF < 0.0f ? DIR_LR_L : DIR_LR_R; + } + setTurnEnd(); + } + break; + case 1: + setTurnSmokeEffect(); + if (mDirection != mPrevDirection) { + setTurnEnd(); + } else if (mSubstateTimer == 0) { + fadeOutTurnEffect(); + mSubstate = 2; + if (getPowerChangeType(false) == POWER_CHANGE_ICE) { + mPyMdlMng.setAnm(PLAYER_ANIM_ICE_TURNED, 0.0f, 0.0f); + } else { + mPyMdlMng.setAnm(PLAYER_ANIM_TURNED, 0.0f, 0.0f); + } + } + break; + case 2: + float maxSpeed = 0.0f; + int dir; + if (mKey.buttonWalk(&dir)) { + if (mKey.buttonDush()) { + maxSpeed = sc_DirSpeed[dir] * getSpeedData()->mHighSpeed; + } else { + maxSpeed = sc_DirSpeed[dir] * getSpeedData()->mLowSpeed; + } + } + mMaxSpeedF = maxSpeed; + if (mDirection != mPrevDirection || mPyMdlMng.isAnmStop()) { + setTurnEnd(); + } + } + } +} + +bool dAcPy_c::checkCrouch() { + if ( + !isStatus(STATUS_51) && + !isStatus(STATUS_SIT_JUMP) && + !isOnSinkSand() && + !isStatus(STATUS_BE) + ) { + if (isCarry()) { + return false; + } + if (mKey.buttonCrouch()) { + if (mPowerup == POWERUP_PENGUIN_SUIT && isStatus(STATUS_CAN_PENGUIN_SLIDE)) { + changeState(StateID_PenguinSlide, 0); + return true; + } + changeState(StateID_Crouch, CROUCH_ARG_FROM_WALK); + return true; + } + } + return false; +} + +void dAcPy_c::setCrouchSmokeEffect() { + if (!mSpeedF) { + return; + } + if (!isNowBgCross(BGC_WATER_SHALLOW)) { + mVec3_c efPos; + mPyMdlMng.mpMdl->getJointPos(&efPos, 1); + setBrakeSmokeEffect(efPos); + } + setSlipSE(); +} + +void dAcPy_c::initializeState_Crouch() { + if (!isNowBgCross(BGC_WATER_SHALLOW)) { + mSubstate = CROUCH_GROUND; + onStatus(STATUS_9F); + } else { + mSubstate = CROUCH_WATER; + onStatus(STATUS_AA); + } + switch (stateArg()) { + case CROUCH_ARG_FROM_WALK: + if (!isNowBgCross(BGC_WATER_SHALLOW)) { + mPyMdlMng.setAnm(PLAYER_ANIM_STOOP_START); + } else { + mPyMdlMng.setAnm(PLAYER_ANIM_STOOP_START, dPyMdlBase_c::scWaterCrouchAnmSpeed, 3.0f, 0.0f); + } + break; + case CROUCH_ARG_FROM_OTHER: + mPyMdlMng.setAnm(PLAYER_ANIM_STOOP, 3.0f, 0.0f); + break; + case CROUCH_ARG_FROM_SIT_JUMP: + mPyMdlMng.setAnm(PLAYER_ANIM_S_JUMPED); + break; + } + mAngle.y = getMukiAngle(mDirection); + startSound(SE_PLY_QUAT, true); + onStatus(STATUS_A8); + onStatus(STATUS_51); + onStatus(STATUS_A2); + onStatus(STATUS_A3); +} + +void dAcPy_c::finalizeState_Crouch() { + offStatus(STATUS_A8); + offStatus(STATUS_9D); + offStatus(STATUS_9F); + offStatus(STATUS_AA); + offStatus(STATUS_51); + offStatus(STATUS_CAN_LAND); + offStatus(STATUS_A2); + offStatus(STATUS_A3); + m_2e8 = 0; +} + +void dAcPy_c::CrouchActionGround() { + if (isOnSinkSand() && setCancelCrouch()) { + return; + } + if (!setCrouchJump() && !checkCrouchSlip()) { + if (!isNowBgCross(BGC_FOOT)) { + mSpeed.y = 0.0f; + changeState(StateID_SitJump, true); + } else { + setCrouchSmokeEffect(); + if (mKey.buttonCrouch() || !setCancelCrouch()) { + offStatus(STATUS_CAN_WATER_WALK); + } + } + } +} + +void dAcPy_c::CrouchActionWater() { + if (mKey.triggerJump()) { + if (!isNowBgCross(BGC_WATER_SUBMERGED)) { + setCrouchJump(); + onStatus(STATUS_AA); + } else { + if (!checkStandUpRoofOnLift()) { + changeState(StateID_Swim, SWIM_ARG_INITIAL); + setWaterGroundJump(); + } + } + } else { + if (!isNowBgCross(BGC_FOOT)) { + changeState(StateID_Swim, SWIM_ARG_INITIAL); + } else { + if (!mKey.buttonCrouch() && setCancelCrouch()) { + changeState(StateID_Swim, SWIM_ARG_INITIAL); + } + } + } +} + +void dAcPy_c::executeState_Crouch() { + gravitySet(); + maxFallSpeedSet(); + if (isNowBgCross(BGC_FOOT)) { + mMaxSpeedF = 0.0f; + offStatus(STATUS_CAN_LAND); + } else { + simpleMoveSpeedSet(); + onStatus(STATUS_CAN_LAND); + } + powerSet(); + turnAngle(); + m_2e8.chase(0, 0x200); + mAngle.y += m_2e8; + typedef void (dAcPy_c::*ActionProc)(); + static ActionProc l_CrouchActionProc[] = { + &dAcPy_c::CrouchActionGround, + &dAcPy_c::CrouchActionWater + }; + (this->*l_CrouchActionProc[mSubstate])(); + int anmID = mPyMdlMng.getAnm(); + if (anmID == PLAYER_ANIM_STOOP_START || anmID == PLAYER_ANIM_S_JUMPED) { + if (mPyMdlMng.isAnmStop()) { + mPyMdlMng.setAnm(PLAYER_ANIM_STOOP); + } + } +} + +bool dAcPy_c::setCancelCrouch() { + mAngle.y = getMukiAngle(mDirection); + return daPlBase_c::setCancelCrouch(); +} + +dAcPy_c *dAcPy_c::getCarryPlayer() { + dActor_c *actor = (dActor_c *) fManager_c::searchBaseByID(mCarryActorID); + if (actor != nullptr && actor->mKind == STAGE_ACTOR_PLAYER) { + return (dAcPy_c *) actor; + } + return nullptr; +} + +dActor_c *dAcPy_c::getCarryPropelBlock() { + dActor_c *actor = (dActor_c *) fManager_c::searchBaseByID(mCarryActorID); + if (actor != nullptr && actor->mProfName == fProfile::AC_PROP_BLOCK) { + return actor; + } + return nullptr; +} + +dActor_c *dAcPy_c::getCarryPropelActor() { + dActor_c *actor = (dActor_c *) fManager_c::searchBaseByID(mCarryActorID); + if (actor != nullptr) { + if (actor->mKind == STAGE_ACTOR_PLAYER) { + dAcPy_c *player = (dAcPy_c *) actor; + if (player->mPowerup == POWERUP_PROPELLER_SHROOM) { + return actor; + } + } else if (actor->mProfName == fProfile::AC_PROP_BLOCK) { + return actor; + } + } + return nullptr; +} + +dActor_c *dAcPy_c::getCarryHardBlock() { + dActor_c *actor = (dActor_c *) fManager_c::searchBaseByID(mCarryActorID); + if (actor != nullptr && ( + actor->mProfName == fProfile::AC_LIGHT_BLOCK || + actor->mProfName == fProfile::AC_PROP_BLOCK + )) { + return actor; + } + return nullptr; +} + +bool dAcPy_c::isLiftUp() { + if (isCarry() && m_1308 == 0) { + return true; + } + return false; +} + +bool dAcPy_c::isCarryMamePlayer() { + dAcPy_c *player = getCarryPlayer(); + if (player != nullptr && player->mPowerup == POWERUP_MINI_MUSHROOM) { + return true; + } + return false; +} + +bool dAcPy_c::isLiftUpExceptMame() { + if (isLiftUp() && !isCarryMamePlayer()) { + return true; + } + return false; +} + +float dAcPy_c::getLiftUpOffset() { + return m_1304 * sGlobalData_c::mData.mPos[getTallType(-1)].y; +} + +mVec3_c dAcPy_c::getCarryPos() { + mVec3_c jnt1, jnt2; + mPyMdlMng.mpMdl->getJointPos(&jnt1, 11); + mPyMdlMng.mpMdl->getJointPos(&jnt2, 14); + if (isCarry()) { + mVec3_c res = (jnt1 + jnt2) / 2.0f; + res.x = dScStage_c::getLoopPosX(res.x); + if (mPyMdlMng.getFlags2() & 4) { + res.y = mPos.y + getLiftUpOffset(); + } + return res; + } else { + jnt2.x = dScStage_c::getLoopPosX(jnt2.x); + return jnt2; + } +} + +mVec3_c dAcPy_c::getLiftUpPos() { + mMtx_c mtx; + getModel()->getJointMtx(&mtx, 11); + mtx.concat(mMtx_c::createTrans(5.0f, 0.0f, 0.0f)); + mVec3_c tmp; + mtx.multVecZero(tmp); + + getModel()->getJointMtx(&mtx, 14); + mtx.concat(mMtx_c::createTrans(5.0f, 0.0f, 0.0f)); + mVec3_c tmp2; + mtx.multVecZero(tmp2); + + mVec3_c res = (tmp + tmp2) / 2.0f; + res.x = dScStage_c::getLoopPosX(res.x); + if (mPyMdlMng.getFlags2() & 4) { + res.y = mPos.y + getLiftUpOffset(); + if (res.y < mPos.y + 2.0f) { + res.y = mPos.y + 2.0f; + } + } + return res; +} + +void dAcPy_c::clearSpinLiftUpReserve() { + m_12fc = BASE_ID_NULL; + m_1300 = 256.0f; +} + +void dAcPy_c::checkSpinLiftUpReserve(dCc_c *cc) { + daPlBase_c *actor = (daPlBase_c *) cc->getOwner(); + if ( + actor == nullptr || + !actor->isSpinLiftUpEnable() || + !spinLiftUp(actor, false) + ) { + return; + } + float f = std::fabs(mPos.x - cc->getCenterPosX()); + if (m_1300 > f) { + m_12fc = actor->mUniqueID; + m_1300 = f; + } +} + +void dAcPy_c::setSpinLiftUpReserve() { + if ( + !isStatus(STATUS_7A) && + !isDemo() && + !isCarry() && + !isStatus(STATUS_OUT_OF_PLAY) && + !isStatus(STATUS_STUNNED) && + !isStatus(STATUS_QUAKE) + ) { + dActor_c *actor = (dActor_c *) fManager_c::searchBaseByID(m_12fc); + if (actor != nullptr && actor->isSpinLiftUpEnable()) { + mCarryActorID = actor->mUniqueID; + m_1308 = 0; + mPyMdlMng.mpMdl->m_17c |= 4; + if (actor->mKind == STAGE_ACTOR_PLAYER) { + dAcPy_c *player = (dAcPy_c *) actor; + mPyMdlMng.mpMdl->mpSpinLiftParentMdl = player->getModel(); + } + changeState(StateID_LiftUp, 0); + dQuake_c::m_instance->shockMotor(mPlayerNo, dQuake_c::TYPE_7, 0, false); + actor->setSpinLiftUpActor(this); + } + clearSpinLiftUpReserve(); + } +} + +void dAcPy_c::checkSpinLiftUpRoofHeight() { + mVec3_c pos(mPos.x, mPos.y + 4.0f, mPos.z); + float _unused = mWallBcData.mOffset; + float height; + float f = 0.0f; + if (dBc_c::checkTenjou(&pos, &height, mLayer, 1) && f > height) { + f = height; + } + m_12f8 = f; +} + +bool dAcPy_c::spinLiftUp(dActor_c *actor, bool b) { + if (actor == nullptr || isCarry() || !mKey.buttonCarry()) { + return false; + } + if (!b) { + return true; + } + if (isStatus(STATUS_92)) { + mCarryActorID = actor->mUniqueID; + m_1308 = 1; + mPyMdlMng.mpMdl->m_17c |= 2; + mPyMdlMng.mpMdl->setBodyAnm(PLAYER_ANIM_RCARRY_WAIT, 1.0f, 0.0f, 0.0f); + startPlayerVoice(VOICE_MOTIAGE, 0); + return true; + } + return false; +} + +bool dAcPy_c::cancelCarry(dActor_c *carriedActor) { + dActor_c *actor = (dActor_c *) fManager_c::searchBaseByID(mCarryActorID); + if (actor == carriedActor || carriedActor == nullptr) { + mPyMdlMng.mpMdl->m_17c &= ~0x6; + mPyMdlMng.mpMdl->releaseBodyAnm(0.0f); + mPyMdlMng.mpMdl->mpSpinLiftParentMdl = nullptr; + mCarryActorID = BASE_ID_NULL; + return true; + } + return false; +} + +void dAcPy_c::releaseCarryActor() { + if (!isCarry()) { + return; + } + dActor_c *actor = (dActor_c *) fManager_c::searchBaseByID(mCarryActorID); + if (actor != nullptr) { + if (actor->mKind == STAGE_ACTOR_PLAYER) { + dAcPy_c *player = (dAcPy_c *) actor; + player->setCarryOffFall(this); + } else { + actor->setCarryFall(this, 20); + actor->mCarryingFlags |= CARRY_RELEASE; + actor->mThrowDirection = mDirection; + } + } + cancelCarry(actor); +} + +void dAcPy_c::setCarryOffFall(const dAcPy_c *carrier) { + m_d8c = mPos.y; + mDirection = carrier->mDirection; + mSpeedF = sc_DirSpeed[mDirection]; + mPos.x += sc_DirSpeed[mDirection] * 5.0f; + + *(const dAcPy_c **) &carrier = nullptr; // [nice fake match] + + changeState(StateID_Fall, false); + onStatus(STATUS_JUMP_DAI_COOLDOWN); +} + +bool dAcPy_c::checkEnableThrow() { + if (!isCarry()) { + return false; + } + dActor_c *actor = (dActor_c *) fManager_c::searchBaseByID(mCarryActorID); + if (actor == nullptr) { + cancelCarry(nullptr); + return false; + } + return !mKey.buttonCarry(); +} + +bool dAcPy_c::checkCarryThrow() { + if (checkEnableThrow()) { + if (isState(StateID_Propel)) { + changeState(StateID_PropelThrow, 0); + return true; + } else { + changeState(StateID_Throw, 0); + return true; + } + } + return false; +} + +void dAcPy_c::initializeThrowCommonBase() { + startPlayerVoice(VOICE_NAGERU, 0); + if (isNowBgCross(BGC_WATER_SHALLOW)) { + mPyMdlMng.setAnm(PLAYER_ANIM_SWIM_THROW); + } else { + dActor_c *actor = (dActor_c *) fManager_c::searchBaseByID(mCarryActorID); + if (actor->mKind == STAGE_ACTOR_PLAYER) { + mPyMdlMng.setAnm(PLAYER_ANIM_CARRY_P_THROW, 0.0f, 0.0f); + } else { + mPyMdlMng.setAnm(PLAYER_ANIM_CARRY_THROW, 0.0f, 0.0f); + } + } + mAngle.y = getMukiAngle(mDirection); + onStatus(STATUS_THROW); +} + +void dAcPy_c::initializeThrowCommon() { + initializeThrowCommonBase(); + onStatus(STATUS_AA); + onStatus(STATUS_97); +} + +void dAcPy_c::finalizeThrowCommonBase() { + offStatus(STATUS_THROW); +} + +void dAcPy_c::finalizeThrowCommon() { + finalizeThrowCommonBase(); + if (mSubstate == 0) { + releaseCarryActor(); + } + offStatus(STATUS_AA); + offStatus(STATUS_97); + offStatus(STATUS_92); + offStatus(STATUS_CAN_LAND); +} + +void dAcPy_c::setThrowActor() { + if (!isCarry()) { + return; + } + dActor_c *actor = (dActor_c *) fManager_c::searchBaseByID(mCarryActorID); + if (actor != nullptr) { + if (actor->mKind == STAGE_ACTOR_PLAYER) { + dAcPy_c *player = (dAcPy_c *) actor; + player->changeState(StateID_RollSlip, 0); + + player->mSpeed.y = sGlobalData_c::mData.mThrowSpeed1; + float speed = getDirSpeed(); + speed *= sGlobalData_c::mData.mThrowSpeed2; + if (getDirSpeed() * mSpeedF >= 0.0f) { + speed += mSpeedF * 0.35f; + if (speed > sGlobalData_c::mData.mThrowSpeedMax) { + speed = sGlobalData_c::mData.mThrowSpeedMax; + } + } + player->mSpeedF = speed; + player->setNoHitPlayer(this, 10); + + mVec3_c pos = player->mPos; + + float spd = speed + sc_DirSpeed[mDirection] * 5.0f; + if (spd < -8.0f) { + spd = -8.0f; + } else if (spd > 8.0f) { + spd = 8.0f; + } + + mVec3_c p(mPos.x, pos.y, pos.z); + pos.x += spd; + + float thing = sc_DirSpeed[mDirection] * std::fabs(getWallBgPointData()->mOffset / 4096.0f); + mVec3_c playerPos(pos.x + thing, pos.y, pos.z); + float hitX; + if (dBc_c::checkWall(&p, &playerPos, &hitX, mLayer, 1, nullptr)) { + bool stop = false; + if (mPowerup == POWERUP_NONE) { + mVec3_c revPos(hitX, pos.y + 16.0f, pos.z); + float hitY; + if (dBc_c::checkGround(&revPos, &hitY, mLayer, 1, -1)) { + if (hitY <= mPos.y + 16.0f) { + pos.y = mPos.y + 16.0f; + stop = true; + } + } + } + if (!stop) { + player->mSpeedF = 0.0f; + pos.x = hitX - thing; + } + } + p.set(pos.x, pos.y + 1.0f, pos.z); + if (dBc_c::checkTenjou(&p, &hitX, mLayer, 1)) { + float offsX = std::fabs(getHeadBgPointData()->mOffset / 4096.0f); + // float tmp = hitX - offsX; + if (pos.y > hitX - offsX) { + pos.y = hitX - offsX; + player->mSpeed.y = 0.0f; + } + } + player->mPos = pos; + player->mLastPos = player->mPos; + calcDispSideLimit(); + } else { + actor->mCarryingFlags |= CARRY_RELEASE | CARRY_THROW; + actor->mThrowDirection = mDirection; + } + } + cancelCarry(actor); +} + +void dAcPy_c::executeThrowCommon() { + if (isNowBgCross(BGC_FOOT)) { + offStatus(STATUS_CAN_LAND); + } else { + onStatus(STATUS_CAN_LAND); + } + switch ((ThrowSubstate_e) mSubstate) { + case THROW_ACTION_0: + if (mPyMdlMng.mpMdl->mCurrAnmID == PLAYER_ANIM_SWIM_THROW) { + if (mPyMdlMng.mpMdl->mAnm.checkFrame(12.0f)) { + mSubstate = THROW_ACTION_2; + setThrowActor(); + } + } else { + if (isNowBgCross(BGC_FOOT) && mKey.triggerJump()) { + fn_80145fd0(1); + setJumpSpeed(); + setJumpCommonBase(); + } + if (mPyMdlMng.mpMdl->mAnm.checkFrame(5.0f)) { + mSubstate = THROW_ACTION_1; + setThrowActor(); + onStatus(STATUS_92); + } + } + break; + case THROW_ACTION_1: + if (isNowBgCross(BGC_FOOT) && checkJumpTrigger()) { + break; + } + if (mPyMdlMng.mpMdl->mAnm.getFrame() >= 20.0f) { + if (isNowBgCross(BGC_FOOT)) { + if (mSpeedF) { + changeState(StateID_Walk, BLEND_DEFAULT); + break; + } + } else { + changeState(StateID_Fall, false); + } + } + if (mPyMdlMng.isAnmStop()) { + changeState(StateID_Walk, BLEND_DEFAULT); + } + break; + case THROW_ACTION_2: + if (mPyMdlMng.isAnmStop()) { + changeState(StateID_Swim, SWIM_ARG_INITIAL); + } + break; + } +} + +void dAcPy_c::initializeState_Throw() { + initializeThrowCommon(); +} + +void dAcPy_c::finalizeState_Throw() { + finalizeThrowCommon(); +} + +void dAcPy_c::executeState_Throw() { + if (isNowBgCross(BGC_WATER_SHALLOW)) { + setWaterMoveSpeed(); + } else { + gravitySet(); + maxFallSpeedSet(); + simpleMoveSpeedSet(); + powerSet(); + } + executeThrowCommon(); +} + +void dAcPy_c::initializeState_PropelThrow() { + initializeThrowCommon(); +} + +void dAcPy_c::finalizeState_PropelThrow() { + finalizeThrowCommon(); +} + +void dAcPy_c::executeState_PropelThrow() { + if (!isNowBgCross(BGC_FOOT) && mKey.buttonJump()) { + mAccelY = getSomeData(7); + mMaxFallSpeed = getSomeData(5); + } else { + mAccelY = getGravityData()[0]; + mMaxFallSpeed = sc_MaxFallSpeed; + } + mAccelF = getSpeedData()->mPowerChangeNormal.mSlowAccel; + mMaxSpeedF = 0.0f; + executeThrowCommon(); +} + +bool dAcPy_c::isSpinLiftUpEnable() { + if ( + isStatus(STATUS_7A) || + isDemo() || + isCarry() || + mRideActorID != BASE_ID_NULL || + isStatus(STATUS_93) || + isStatus(STATUS_OUT_OF_PLAY) || + isStatus(STATUS_STUNNED) || + isStatus(STATUS_QUAKE) + ) { + return false; + } + return true; +} + +void dAcPy_c::setSpinLiftUpActor(dActor_c *carryingActor) { + if (mRideActorID != BASE_ID_NULL) { + return; + } + mRideActorID = carryingActor->mUniqueID; + if (!isState(StateID_CarryPlayer)) { + changeState(StateID_CarryPlayer, 0); + } + + dQuake_c::getInstance()->shockMotor(getPlrNo(), dQuake_c::TYPE_7, 0, false); +} + +void dAcPy_c::initializeState_LiftUp() { + offStatus(STATUS_8A); + onStatus(STATUS_97); + onStatus(STATUS_46); + m_1304 = 0.0f; + dAcPy_c *carryPlayer = getCarryPlayer(); + setVirusStar(carryPlayer); + if (carryPlayer != nullptr) { + startPlayerVoice(VOICE_MOTIAGE_PLAYER, 0); + } else { + startPlayerVoice(VOICE_MOTIAGE, 0); + } + startSound(SE_PLY_OTHER_ON, false); + mPyMdlMng.setAnm(PLAYER_ANIM_CARRY_P_START, 0.0f, 0.0f); + mSpeedF = 0.0f; + mSpeed.y = 0.3f; + m_1048 = 10000; + m_130c = 0; +} + +void dAcPy_c::finalizeState_LiftUp() { + offStatus(STATUS_97); + offStatus(STATUS_46); + m_1304 = 1.0f; + mAngle.y = getMukiAngle(mDirection); +} + +void dAcPy_c::executeState_LiftUp() { + m_130c++; + float f = m_130c / 30.0f; + if (f > 1.0f) { + f = 1.0f; + } + m_1304 = f; + sLib::chase(&m_1048, 0, 250); + if (m_1048 != 0) { + mAngle.y += m_1048; + } else { + turnAngle(); + } + setCcAtSpin(); + gravitySet(); + maxFallSpeedSet(); + if (m_130c <= 18) { + mMaxSpeedF = 0.0f; + powerSet(); + } else { + simpleMoveSpeedSet(); + powerSet(); + if (checkCarryThrow()) { + int dir; + if (mKey.buttonWalk(&dir)) { + mDirection = dir; + mAngle.y = getMukiAngle(mDirection); + } + return; + } else if (checkJumpTrigger()) { + sBcPointData d1 = mWallBcData; + sBcPointData d2 = mHeadBcData; + fn_80143060(d1, d2, true); + if (!fn_80143220(d1, d2)) { + return; + } + onStatus(STATUS_48); + return; + } + } + if (mPyMdlMng.isAnmStop()) { + changeState(StateID_Walk, BLEND_DEFAULT); + } +} + +void dAcPy_c::calcUzuSwimSpeed(float f1, float f2, float *fOut) { + if (!isStatus(STATUS_PENGUIN_SWIM)) { + return; + } + + *fOut *= data_802f5a48[15]; + if (*fOut * f1 >= 0.0f && std::fabs(f2) > data_802f5a48[17]) { + *fOut = 0.0f; + return; + } + + if (*fOut * f1 < 0.0f) { + if (f2 * f1 > 0.0f) { + if (std::fabs(f2) > 0.5f) { + return; + } + } else { + *fOut *= data_802f5a48[16]; + } + float lim = data_802f5a48[11] - 0.01f; + if (std::fabs(*fOut) > lim) { + if (*fOut < 0.0f) { + *fOut = -lim; + } else { + *fOut = lim; + } + } + } +} + +void dAcPy_c::setUzuSpeedY(float f) { + if (std::fabs(mSpeed.y) < 2.0f) { + if (f > 0.0f) { + if (isNowBgCross(BGC_FOOT)) { + setUzuSwimAction(); + } + if (isNowBgCross(BGC_HEAD)) { + return; + } + } + calcUzuSwimSpeed(mUzuSwimSpeed.y, mSpeed.y, &f); + if (f > 0.0f) { + m_b88 = 20; + } + if (f * mUzuSwimSpeed.y < 0.0f) { + onStatus(STATUS_SWIM_AGAINST_JET_V); + } + mSpeed.y += f; + } +} + +void dAcPy_c::setUzuSpeedF(float f) { + if (std::fabs(mSpeedF) < 2.0f) { + calcUzuSwimSpeed(mUzuSwimSpeed.x, mSpeedF, &f); + if (f * mUzuSwimSpeed.x < 0.0f) { + onStatus(STATUS_SWIM_AGAINST_JET_H); + } + mSpeedF += f; + } +} + +bool dAcPy_c::setUzuSwimAction() { + if (isNowBgCross(BGC_WATER_SHALLOW) && isState(StateID_Swim) && mSubstate == 1) { + setSwimAction_Swim(BLEND_DEFAULT); + return true; + } + return false; +} + +bool dAcPy_c::setSwimAction() { + if (isStatus(STATUS_45) || isStatus(STATUS_AA) || isStatus(STATUS_SWIM)) { + return false; + } + if (isNowBgCross(BGC_WATER_SHALLOW)) { + if (isOldBgCross(BGC_WATER_SHALLOW)) { + changeState(StateID_Swim, SWIM_ARG_INITIAL); + } else if (isStatus(STATUS_FIREBALL_PREPARE_SHOOT)) { + changeState(StateID_Swim, SWIM_ARG_FIREBALL); + } else { + changeState(StateID_Swim, SWIM_ARG_ENTERING); + } + return true; + } + return false; +} + +void dAcPy_c::setWaterInEffect() { + dScStage_c *stage = dScStage_c::m_instance; + bool bigSplash = false; + + if (isNowBgCross(BGC_WATER_BUBBLE)) { + startSound(SE_PLY_SPLASH_GEL, false); + mAng3_c efAng(0, 0, -mAirWaterHitAngle); + dEf::createPlayerEffect(mPlayerNo, "Wm_mr_wfloatsplash", 0, &mAirWaterHitPos, &efAng, nullptr); + return; + } + if ( + stage->mCurrWorld == WORLD_4 && + stage->mCurrCourse == STAGE_CASTLE && + stage->mCurrFile == 1 + ) { + bigSplash = true; + } + mVec3_c efPos(mPos.x, mWaterHeight, mPos.z); + if (bigSplash || mWaterDepth == 3) { + float f = 1.0f; + u32 i; + if (mPowerup == POWERUP_MINI_MUSHROOM) { + startSound(SE_PLY_SPLASH_MAME, false); + i = 3; + } else { + startSound(SE_PLY_SPLASH, false); + i = 2; + if (mPowerup == POWERUP_NONE) { + f = 0.8f; + } + } + dPyEffectMng_c::mspInstance->fn_800d2de0(f, i, efPos, mLayer); + dBg_c::m_bg_p->setWaterInWave(efPos.x, efPos.y, 1); + } else { + float f = 1.0f; + if (mPowerup == POWERUP_MINI_MUSHROOM) { + f = 0.6f; + } else if (mPowerup == POWERUP_NONE) { + f = 0.8f; + } + dPyEffectMng_c::mspInstance->fn_800d2de0(f, 4, efPos, mLayer); + if (mPowerup == POWERUP_MINI_MUSHROOM) { + startSound(SE_PLY_SPLASH_SHALLOW_MAME, false); + } else { + startSound(SE_PLY_SPLASH_SHALLOW, false); + } + dBg_c::m_bg_p->setWaterInWave(efPos.x, efPos.y, 0); + } +} + +void dAcPy_c::setWaterOutEffect() { + if (isOldBgCross(BGC_WATER_BUBBLE)) { + startSound(SE_PLY_SPLASH_GEL_OUT, false); + mAng3_c efAng(0, 0, -mAirWaterHitAngle); + dEf::createPlayerEffect(mPlayerNo, "Wm_mr_wfloatsplash", 0, &mAirWaterHitPos, &efAng, nullptr); + return; + } + mVec3_c efPos(mPos.x, mPrevWaterHeight, mPos.z); + + if (mWaterDepth == 3) { + float f = 1.0f; + u32 i; + if (mPowerup == POWERUP_MINI_MUSHROOM) { + i = 1; + } else { + i = 0; + if (mPowerup == POWERUP_NONE) { + f = 0.8f; + } + } + dPyEffectMng_c::mspInstance->fn_800d2de0(f, i, efPos, mLayer); + dBg_c::m_bg_p->setWaterInWave(efPos.x, efPos.y, 3); + startSound(SE_PLY_SPLASH_OUT, false); + } else { + float f = 1.0f; + if (mPowerup == POWERUP_MINI_MUSHROOM) { + f = 0.6f; + } else if (mPowerup == POWERUP_NONE) { + f = 0.8f; + } + dPyEffectMng_c::mspInstance->fn_800d2de0(f, 4, efPos, mLayer); + startSound(SE_PLY_SPLASH_SHALLOW_OUT, false); + dBg_c::m_bg_p->setWaterInWave(efPos.x, efPos.y, 2); + } +} + +void dAcPy_c::setPaddleSwimEffect() { + mVec3_c efPos; + mPyMdlMng.mpMdl->getJointPos(&efPos, 11); + dEf::createPlayerEffect(mPlayerNo, &mLevelEf9, "Wm_mr_swimpaddle", 0, &efPos, nullptr, nullptr); + mPyMdlMng.mpMdl->getJointPos(&efPos, 14); + dEf::createPlayerEffect(mPlayerNo, &mLevelEf10, "Wm_mr_swimpaddle", 0, &efPos, nullptr, nullptr); +} + +void dAcPy_c::resetPaddleSwimEffect() { + mLevelEf9.fade(); + mLevelEf10.fade(); +} + +void dAcPy_c::setWaterSurfaceSwimEffect() { + if (getWaterCheckPosY() < mWaterHeight - 4.0f) { + return; + } + mVec3_c efPos(mPos.x, mWaterHeight, mPos.z); + mAng3_c efAng(0, 0, 0); + if (mDirection == DIR_LR_L) { + efAng.y = 0x8000; + } + static const float sc_waterFaceEffectScale[] = { 0.65f, 0.8f, 1.0f }; + float s = sc_waterFaceEffectScale[getTallType(-1)]; + mVec3_c scale(s, s, s); + dEf::createPlayerEffect(mPlayerNo, &mLevelEf11, "Wm_mr_waterswim", 0, &efPos, nullptr, &scale); + dEf::createPlayerEffect(mPlayerNo, &mLevelEf12, "Wm_en_cmnwater02", 0, &efPos, &efAng, &scale); +} + +void dAcPy_c::setFlutterKickEffect() { + mVec3_c efPos; + mPyMdlMng.mpMdl->getJointPos(&efPos, 4); + dEf::createPlayerEffect(mPlayerNo, &mLevelEf9, "Wm_mr_flutterkick", 0, &efPos, nullptr, nullptr); + mPyMdlMng.mpMdl->getJointPos(&efPos, 7); + dEf::createPlayerEffect(mPlayerNo, &mLevelEf10, "Wm_mr_flutterkick", 0, &efPos, nullptr, nullptr); +} + +void dAcPy_c::initializeState_Swim() { + onStatus(STATUS_SWIM); + onStatus(STATUS_AA); + onStatus(STATUS_A8); + onStatus(STATUS_92); + offStatus(STATUS_CAN_WATER_WALK); + SwimArg_e param = stateArg(); + m_b84 = 0; + m_b88 = 0; + m_b80 = 0.0f; + if (param == SWIM_ARG_ENTERING || param == SWIM_ARG_FIREBALL || param == SWIM_ARG_CLIFF_HANG) { + m_b80 = 1; + m_15b6 = 30; + if (mSpeed.y < -1.5f) { + mSpeed.y = -1.5f; + } + if (m_b98 != 0 && mSpeed.y < -0.5f) { + mSpeed.y = -0.5f; + } + } + if (param == SWIM_ARG_FIREBALL) { + setInitSwimAction_FireBall(); + } else { + dAcPy_c *carryPlayer = getCarryPlayer(); + if (carryPlayer != nullptr) { + mVec3_c pos(mPos.x, mPos.y + 4.0f, mPos.z); + float height; + if (dBc_c::checkTenjou(&pos, &height, mLayer, mAmiLayer)) { + if (mPos.y + getModelHeight() + getBgPointData_Powerup(mPowerup, 1)->mHead.mOffset / 4096.0f > height) { + releaseCarryActor(); + } + } + } + AnmBlend_e blendMode = BLEND_DEFAULT; + if (param == SWIM_ARG_CLIFF_HANG) { + blendMode = BLEND_NONE; + } + if (mPowerup == POWERUP_PENGUIN_SUIT) { + if (!isCarry()) { + setSwimAction_Penguin(blendMode); + } else { + setSwimAction_Swim(blendMode); + } + } else if (isNowBgCross(BGC_FOOT)) { + setSwimAction_Walk(blendMode); + } else { + setSwimAction_Swim(blendMode); + } + } + if (isNowBgCross(BGC_WATER_SHALLOW) && isOldBgCross(BGC_WATER_SHALLOW) == 0) { + setWaterInEffect(); + } + if (isItemKinopio()) { + setControlDemoKinopioSwim(); + } +} + +bool dAcPy_c::setWaterSurfaceJump() { + if (mKey.triggerJump()) { + if (mSubstate == SWIM_ACTION_2) { + if (mKey.buttonUp()) { + m_b88 = 20; + } + } else { + m_b88 = 20; + } + } + if (!isNowBgCross(BGC_WATER_SHALLOW)) { + if (!isNowBgCross(BGC_WATER_TOUCH) && (!isCarry() || mPowerup != POWERUP_MINI_MUSHROOM)) { + if (mSubstate == SWIM_ACTION_3 && m_b89 == 0) { + createFireBall(0); + } + changeState(StateID_Fall, false); + return true; + } + if (m_b88 != 0) { + if (mSubstate == SWIM_ACTION_3 && m_b89 == 0) { + createFireBall(0); + } + float h = 3.5f; + if (isMameAction()) { + h = 2.625f; + } + jmpInf_c jmpInf(h, 1, BLEND_DEFAULT); + if (mSubstate == SWIM_ACTION_2) { + jmpInf.mBlendMode = BLEND_NONE; + } + changeState(StateID_Jump, &jmpInf); + mKey.onStatus(dAcPyKey_c::STATUS_FORCE_JUMP); + onStatus(STATUS_A8); + return true; + } + } + return false; +} + +void dAcPy_c::setSwimAction_Swim(AnmBlend_e blendMode) { + m_b89 = 0; + mSubstate = SWIM_ACTION_0; + m_b84 = 4; + m_b88 = 0; + if (blendMode == BLEND_DEFAULT) { + mPyMdlMng.setAnm(PLAYER_ANIM_SWIM_WAIT); + } else { + mPyMdlMng.setAnm(PLAYER_ANIM_SWIM_WAIT, 0.0f, 0.0f); + } + mAngle.x = 0; +} + +void dAcPy_c::SwimAction_Swim() { + if (mPowerup == POWERUP_PENGUIN_SUIT && !isCarry()) { + setSwimAction_Penguin(BLEND_DEFAULT); + return; + } + setWaterMoveSpeed(); + turnAngle(); + if (checkEnableThrow()) { + startPlayerVoice(VOICE_NAGERU, 0); + setThrowActor(); + return; + } + if (setWaterSurfaceJump()) { + return; + } + if (isNowBgCross(BGC_FOOT) && mPowerup != POWERUP_PENGUIN_SUIT) { + setSwimAction_Walk(BLEND_DEFAULT); + return; + } + setWaterSurfaceSwimEffect(); + if (isNowBgCross(BGC_WATER_SHALLOW)) { + if (mKey.triggerJump()) { + startSound(SE_PLY_SWIM, 0); + mSpeed.y += 1.0f; + if (mSpeed.y > 1.8f) { + mSpeed.y = 1.8f; + } + } + if (isNowBgCross(BGC_NON_BREAK_BLOCK_HIT)) { + mSpeed.y = -1.875f; + } + } + switch (m_b89) { + case 0: + if (mKey.triggerJump()) { + m_b89 = 1; + mPyMdlMng.setAnm(PLAYER_ANIM_PADDLE_1); + onStatus(STATUS_40); + } else if (mKey.buttonJump()) { + m_b89 = 3; + mPyMdlMng.setAnm(PLAYER_ANIM_SWIM); + } + break; + case 1: + setPaddleSwimEffect(); + if (mKey.triggerJump() && mPyMdlMng.mpMdl->mAnm.getFrame() > 9.0f) { + mPyMdlMng.mpMdl->setFrame(0.0f); + resetPaddleSwimEffect(); + onStatus(STATUS_40); + } + if (mPyMdlMng.isAnmStop()) { + if (mKey.buttonJump()) { + m_b89 = 3; + mPyMdlMng.setAnm(PLAYER_ANIM_SWIM); + } else { + m_b89 = 2; + mPyMdlMng.setAnm(PLAYER_ANIM_PADDLE_2); + } + } + break; + case 3: + mPyMdlMng.mpMdl->setRate(1.0f); + if (mPyMdlMng.mpMdl->mAnm.checkFrame(1.0f) || mPyMdlMng.mpMdl->mAnm.checkFrame(9.0f)) { + startSound(SE_PLY_SWIM_KICK, 0); + } + setFlutterKickEffect(); + if (!mKey.buttonJump()) { + m_b89 = 2; + mPyMdlMng.setAnm(PLAYER_ANIM_PADDLE_2); + } + break; + case 2: + if (mPyMdlMng.isAnmStop()) { + m_b89 = 0; + mPyMdlMng.setAnm(PLAYER_ANIM_SWIM_WAIT); + } + break; + case 4: + if (!isCarry()) { + m_b89 = 0; + mPyMdlMng.setAnm(PLAYER_ANIM_SWIM_WAIT); + } + break; + } +} + +void dAcPy_c::setSeaLandSmokeEffect() { + static const char *sc_hipAttackEffectID[] = { + "Wm_mr_sealandsmk_ss", + "Wm_mr_sealandsmk_s", + "Wm_mr_sealandsmk", + }; + dEf::createPlayerEffect_change(mPlayerNo, sc_hipAttackEffectID[getTallType(-1)], 0, &mPos, nullptr, nullptr); +} + +void dAcPy_c::setSwimActionWalkAnm() { + if (!mSpeedF) { + mPyMdlMng.setAnm(PLAYER_ANIM_SWIM_STANDING); + return; + } + float f = 1.0f; + if (mMaxSpeedF && mSpeedF * mMaxSpeedF < 0.0f) { + f = std::fabs(mSpeedF) - sc_WaterWalkSpeed + 1.0f; + if (f < 1.0f) { + f = 1.0f; + } else if (f > 2.0f) { + f = 2.0f; + } + } + mPyMdlMng.setAnm(PLAYER_ANIM_SWIM_WALK, f, 10.0f, 0.0f); +} + +void dAcPy_c::setSwimAction_Walk(AnmBlend_e blendMode) { + if (!isOldBgCross(BGC_FOOT)) { + setSeaLandSmokeEffect(); + } + m_b89 = 0; + mSubstate = SWIM_ACTION_1; + if (blendMode == BLEND_DEFAULT) { + setSwimActionWalkAnm(); + } else { + mPyMdlMng.setAnm(PLAYER_ANIM_SWIM_STANDING); + } +} + +void dAcPy_c::setWaterGroundJump() { + mSpeed.y = sc_WaterJumpSpeed; + setSwimAction_Swim(BLEND_DEFAULT); + startSound(SE_PLY_SWIM, 0); + m_b88 = 20; +} + +void dAcPy_c::SwimAction_Walk() { + if (mPowerup == POWERUP_PENGUIN_SUIT) { + setSwimAction_Penguin(BLEND_DEFAULT); + return; + } + setWaterMoveSpeed(); + turnAngle(); + if (mKey.triggerJump()) { + if (!setWaterSurfaceJump()) { + setWaterGroundJump(); + } + } else { + if (!isNowBgCross(BGC_FOOT)) { + setSwimAction_Swim(BLEND_DEFAULT); + } else { + if (!checkCrouch()) { + setSwimActionWalkAnm(); + } + } + } +} + +s16 dAcPy_c::getPenguinSwinAngleX() { + float f = std::fabs(mUzuSwimSpeed.x); + if (f < 0.1f) { + f = 0.1f; + } + float cos = mUzuSwimSpeed.y; + if (mKey.buttonUp()) { + if (cos < 0.0f) { + cos = 0.0f; + } + } + if (mKey.buttonDown()) { + if (cos < 0.0f) { + cos = 0.0f; + } + } + // [cos gets discarded here?] + return -(cM::atan2s(f, mUzuSwimSpeed.y) - 0x4000); +} + +void dAcPy_c::setSwimAction_Penguin(AnmBlend_e blendMode) { + mSubstate = SWIM_ACTION_2; + m_b88 = 0; + if (m_b80 != 0 || getOldState() == StateID_HipAttack) { + m_b80 = 0; + if (blendMode == BLEND_DEFAULT) { + mPyMdlMng.setAnm(PLAYER_ANIM_P_SWIM); + } else { + mPyMdlMng.setAnm(PLAYER_ANIM_P_SWIM, 0.0f, 0.0f); + } + mSubstateTimer = 15; + m_b89 = 0; + return; + } + if (mSpeedF > 0.1f || mSpeed.y > 0.1f) { + m_b8c = 1.0f; + } else { + m_b8c = 0.0f; + } + m_b89 = 1; + if (blendMode == BLEND_DEFAULT) { + mPyMdlMng.setAnm(PLAYER_ANIM_P_SWIM); + } else { + mPyMdlMng.setAnm(PLAYER_ANIM_P_SWIM, 0.0f, 0.0f); + } +} + +void dAcPy_c::setPenWaterMoveSpeed(int i) { + if (m_b98 != 0 && mKey.triggerDown()) { + m_b98 = 0; + } + bool noUpDown = false; + if (mKey.buttonUp() || m_b98 == 0 && mKey.buttonDown()) { + noUpDown = true; + } + bool b = 0; + if (mKey.buttonWalk(nullptr)) { + b = 1; + } + s16 ang = 0; + if (noUpDown) { + ang = 0x3e00; + if (b) { + ang = 0x2000; + } + if (mKey.buttonDown()) { + ang = -ang; + } + } + mAngle.y.chase(getMukiAngle(mDirection), 0x400); + mAngle.x.chase(getPenguinSwinAngleX(), 0x300); + float f3 = getData(9); + float f2 = 0.0f; + if (i != 0) { + if (noUpDown) { + f2 = getData(6); + if (isStatus(STATUS_SWIM_AGAINST_JET_V)) { + f3 = getData(18); + } else { + f3 = getData(12); + } + } + } else { + if (noUpDown) { + f2 = getData(5); + f3 = getData(11); + } else if (b) { + f3 = getData(14); + } + float d = getData(5); + if (std::fabs(mSpeed.y) >= d) { + f3 = getData(13); + } + } + float target = mAng(ang).sin() * f2; + mUzuSwimSpeed.y = target; + float offs = mPos.y + getModelHeight() / 2.0f; + if (mWaterHeight <= offs) { + target = -1.5f; + if (mSpeed.y > 0.0f) { + f3 = std::fabs(-24.0f / 256.0f); + } else { + f3 = std::fabs(-7.0f / 256.0f); + } + } else { + if (mSpeed.y < -getData(6)) { + f3 = std::fabs(-24.0f / 256.0f); + } + } + sLib::addCalc(&mSpeed.y, target, 0.5f, f3, 0.01f); + mMaxFallSpeed = sc_MaxFallSpeed; + mAccelY = 0.0f; + if (i != 0) { + f2 = getData(8); + if (isStatus(STATUS_SWIM_AGAINST_JET_H)) { + f3 = getData(18); + } else { + f3 = getData(12); + } + } else { + if (b) { + f2 = getData(7); + f3 = getData(11); + } else { + f2 = 0.3f; + if (std::fabs(mSpeedF) < 0.3f) { + f3 = 0.005f; + } else if (noUpDown) { + f3 = getData(14); + } else { + f3 = getData(10); + } + } + float d = getData(7); + if (std::fabs(mSpeedF) >= d) { + f3 = getData(13); + } + } + f3 = sc_DirSpeed[mDirection] * f3; + mUzuSwimSpeed.x = mAng(ang).cos() * f2 * sc_DirSpeed[mDirection]; + float f4 = 0.0f; + if (dWaterEntryMng_c::m_instance->m_8c0) { + f4 = 8.25f; + } + float f5 = mUzuSwimSpeed.x + f4 * 0.3f; + float f10 = f3 + f4 * 0.005f; + if (mUzuSwimSpeed.x * f4 < 0.0f) { + if (i != 0) { + f5 = mUzuSwimSpeed.x + f4 * 0.1f; + f10 = f3 + f4 * 0.0001f; + } else if (b) { + f5 = mUzuSwimSpeed.x + f4 * 0.13f; + if (std::fabs(mSpeedF) < 1.0f) { + f10 = f10; + } else { + f10 = f3 + f4 * 0.003f; + } + } + } + mMaxSpeedF = f5; + if (f3 < 0.0f) { + f3 = f3; + } + mAccelF = std::fabs(f10); + if (b || noUpDown || i != 0) { + m_b8c = 1.0f; + } else { + m_b8c = 0.3f; + } +} + +bool dAcPy_c::setPenguinPaddleSwim() { + if (mKey.triggerJump()) { + m_b89 = 2; + mPyMdlMng.setAnm(PLAYER_ANIM_P_PADDLE_1); + startSound(SE_PLY_PNGN_SWIM, false); + onStatus(STATUS_40); + return true; + } + return false; +} + +void dAcPy_c::SwimAction_Penguin() { + if (mPowerup != POWERUP_PENGUIN_SUIT || isCarry()) { + setSwimAction_Swim(BLEND_DEFAULT); + return; + } + if (setWaterSurfaceJump()) { + return; + } + setWaterSurfaceSwimEffect(); + int moveMode = 0; + switch (m_b89) { + case 0: + if (mSubstateTimer == 0) { + m_b8c = 1.0f; + m_b89 = 1; + mPyMdlMng.setAnm(PLAYER_ANIM_P_SWIM); + } + break; + case 1: { + if (mPyMdlMng.mpMdl->mAnm.checkFrame(1.0f) || mPyMdlMng.mpMdl->mAnm.checkFrame(9.0f)) { + startSound(SE_PLY_SWIM_KICK_PENGUIN, false); + } + float rate = mPyMdlMng.mpMdl->mAnm.getRate(); + if (m_b8c == 1.0f) { + setFlutterKickEffect(); + sLib::chase(&rate, m_b8c, 0.1f); + } else { + sLib::chase(&rate, m_b8c, 0.03f); + } + mPyMdlMng.mpMdl->setRate(rate); + if (setPenguinPaddleSwim()) { + return; + } + break; + } + case 2: + setPaddleSwimEffect(); + if (mPyMdlMng.mpMdl->mAnm.getFrame() < 9.0f) { + moveMode = 1; + } + if (mPyMdlMng.isAnmStop()) { + m_b89 = 3; + mPyMdlMng.setAnm(PLAYER_ANIM_P_PADDLE_2); + } + break; + case 3: + if (setPenguinPaddleSwim()) { + return; + } + if (mPyMdlMng.isAnmStop()) { + m_b8c = 1.0f; + m_b89 = 1; + mPyMdlMng.setAnm(PLAYER_ANIM_P_SWIM); + } + break; + } + onStatus(STATUS_PENGUIN_SWIM); + setPenWaterMoveSpeed(moveMode); +} + +void dAcPy_c::setInitSwimAction_FireBall() { + mSubstate = SWIM_ACTION_3; + m_b89 = 1; + createFireBall(0); + mPyMdlMng.setAnm(PLAYER_ANIM_SWIM_FIRE_AT, dPyMdlBase_c::scFireShootFrame); + mAngle.y = getMukiAngle(mDirection); + m_12f4 = mDirection; +} + +void dAcPy_c::setSwimAction_FireBall() { + mSubstate = SWIM_ACTION_3; + m_b89 = 0; + if (mAngle.x > 0x1800) { + mPyMdlMng.setAnm(PLAYER_ANIM_SWIM_FIRE_AT2); + } else { + mPyMdlMng.setAnm(PLAYER_ANIM_SWIM_FIRE_AT); + } + mPyMdlMng.mpMdl->setFrame(0.0f); + mAngle.y = getMukiAngle(mDirection); + m_12f4 = mDirection; +} + +void dAcPy_c::SwimAction_FireBall() { + if (setWaterSurfaceJump()) { + return; + } + if (mPowerup != POWERUP_PENGUIN_SUIT) { + setWaterMoveSpeed(); + } else { + onStatus(STATUS_PENGUIN_SWIM); + setPenWaterMoveSpeed(0); + } + switch (m_b89) { + case 0: + if (mPyMdlMng.mpMdl->mAnm.checkFrame(dPyMdlBase_c::scFireShootFrame)) { + createFireBall(0); + m_b89 = 1; + } + break; + case 1: + if (checkSetFireBall()) { + setSwimAction_FireBall(); + } else if (mPyMdlMng.isAnmStop()) { + if (mPowerup == POWERUP_PENGUIN_SUIT) { + setSwimAction_Penguin(BLEND_DEFAULT); + } else if (isNowBgCross(BGC_FOOT)) { + setSwimAction_Walk(BLEND_DEFAULT); + } else { + setSwimAction_Swim(BLEND_DEFAULT); + } + } + break; + } +} + +void dAcPy_c::setWaterMoveSpeed() { + float targetY = -1.5f; + float accelY = getGravityData()[0]; + if (isCarry()) { + float posY = mPos.y + getModelHeight() / 2.0f; + if (std::fabs(mWaterHeight - posY) < 0.2f && std::fabs(mSpeed.y) < 0.1f) { + targetY = 0.0f; + mSpeed.y = 0.0f; + accelY = targetY; + } else if (mWaterHeight > posY) { + targetY = 1.0f; + accelY = -0.04296875f; + } else { + targetY = -1.5f; + accelY = -0.04296875f; + if (mSpeed.y > 0.0f) { + sLib::chase(&mSpeed.y, 0.0f, 0.1f); + } + } + } else { + if (isNowBgCross(BGC_WATER_SHALLOW)) { + if (isStatus(STATUS_39)) { + targetY = 1.0f; + } else if (!mKey.buttonJump()) { + targetY = -1.5f; + } else { + targetY = -0.5f; + } + float speedY = mSpeed.y; + if (speedY < 0.0f) { + if (speedY < targetY) { + accelY = -0.09375f; + } else { + accelY = -0.02734375f; + } + } else { + accelY = -0.04296875f; + } + } + } + sLib::chase(&mSpeed.y, targetY, std::fabs(accelY)); + mMaxFallSpeed = sc_MaxFallSpeed; + mAccelY = 0.0f; + float maxSpeedF; + if (mPowerup == POWERUP_PENGUIN_SUIT) { + if (isNowBgCross(BGC_FOOT)) { + maxSpeedF = 0.84375f; + } else { + maxSpeedF = 1.6875f; + } + } else if (isNowBgCross(BGC_FOOT)) { + maxSpeedF = sc_WaterWalkSpeed; + } else { + maxSpeedF = sc_WaterSwimSpeed; + if (m_b84 != 0 && std::fabs(mSpeedF) > std::fabs(sc_WaterSwimSpeed)) { + sLib::chase(&mSpeedF, sc_WaterSwimSpeed, 0.5f); + } + } + float targetF = 0.0f; + if (mKey.buttonWalk(nullptr)) { + targetF = maxSpeedF * sc_DirSpeed[mDirection]; + } + targetF += dWaterEntryMng_c::m_instance->get_8c0() * 0.3f; + mMaxSpeedF = targetF; + float absSpeedF = std::fabs(mSpeedF); + float speedF = mSpeedF; + if (mPowerup == POWERUP_PENGUIN_SUIT) { + if (targetF) { + if (speedF * targetF < 0.0f) { + mAccelF = 0.0625f; + } else if (absSpeedF > std::fabs(targetF)) { + mAccelF = 0.0625f; + } else { + mAccelF = 0.0546875f; + } + } else if (isState(StateID_Crouch)) { + mAccelF = 0.0546875f; + } else { + mAccelF = 0.015625f; + } + } else { + if (targetF) { + if (speedF * targetF < 0.0f) { + mAccelF = 0.017f; + } else if (absSpeedF > std::fabs(targetF)) { + if (isNowBgCross(BGC_FOOT)) { + mAccelF = 0.05f; + } else { + mAccelF = 0.017f; + } + } else { + mAccelF = 0.025f; + } + } else if (absSpeedF > std::fabs(targetF)) { + if (isNowBgCross(BGC_FOOT)) { + mAccelF = 0.05f; + } else { + mAccelF = 0.017f; + } + } else if (isState(StateID_Crouch)) { + mAccelF = 0.027f; + } else { + mAccelF = 0.004f; + } + } + if (mKey.buttonWalk(nullptr)) { + mAccelF = std::fabs(sc_DirSpeed[mDirection] * mAccelF + dWaterEntryMng_c::m_instance->get_8c0() * 0.003f); + } +} + +void dAcPy_c::executeState_Swim() { + if (isStatus(STATUS_ENEMY_STAGE_CLEAR) && isNowBgCross(BGC_FOOT)) { + offNowBgCross(BGC_FOOT); + mSpeed.y = 1.0f; + } + if (m_b84 != 0) { + m_b84--; + } + if (m_b88 != 0) { + m_b88--; + } + if (isStatus(STATUS_39)) { + if (mSpeed.y >= -0.25f) { + offStatus(STATUS_39); + } + } + if (!isNowBgCross(BGC_WATER_SHALLOW) && isNowBgCross(BGC_FOOT)) { + changeState(StateID_Walk, BLEND_NONE); + } else { + if (mSubstate != SWIM_ACTION_3 && checkSetFireBall()) { + setSwimAction_FireBall(); + } + offStatus(STATUS_PENGUIN_SWIM); + typedef void (dAcPy_c::*SwimActionProc)(); + static SwimActionProc l_SwimActionProc[] = { + &dAcPy_c::SwimAction_Swim, + &dAcPy_c::SwimAction_Walk, + &dAcPy_c::SwimAction_Penguin, + &dAcPy_c::SwimAction_FireBall, + }; + (this->*l_SwimActionProc[mSubstate])(); + calcPenguinSwimGroundRev(); + } +} + +void dAcPy_c::calcPenguinSwimGroundRev() { + if (!isStatus(STATUS_PENGUIN_SWIM)) { + m_1594 = 0.0f; + m_1598 = 0.0f; + return; + } + float f1 = 0.0f; + float f2 = 0.0f; + mMtx_c rotMtx; + rotMtx.trans(mPos); + rotMtx.YrotM(mAngle.y); + rotMtx.concat(mMtx_c::createTrans(0.0f, 8.0f, 0.0f)); + rotMtx.XrotM(-mAngle.x); + rotMtx.concat(mMtx_c::createTrans(0.0f, 8.0f, 0.0f)); + rotMtx.ZrotM(mAngle.z); + rotMtx.concat(mMtx_c::createTrans(0.0f, 0.0f, 20.0f)); + mVec3_c resVec; + rotMtx.multVecZero(resVec); + const sBcPointData *bgPointData = getWallBgPointData(); + if (bgPointData != nullptr) { + float bgOffs[2]; + bgOffs[0] = bgPointData->mInfMargin / 4096.0f; + bgOffs[1] = bgPointData->mSupMargin / 4096.0f; + mVec3_c wallPos1(mPos.x, mPos.y + bgOffs[0], mPos.z); + mVec3_c wallPos2(resVec.x, mPos.y + bgOffs[0], resVec.z); + for (int i = 0; i < 2; i++) { + wallPos1.set(mPos.x, mPos.y + bgOffs[i], mPos.z); + wallPos2.set(resVec.x, mPos.y + bgOffs[i], resVec.z); + float wallX; + if (dBc_c::checkWall(&wallPos1, &wallPos2, &wallX, mLayer, 1, nullptr)) { + f1 = wallX - resVec.x; + if (mPos.x < resVec.x) { + resVec.x = wallX - 1.0f; + } else { + resVec.x = wallX + 1.0f; + } + } + } + } + mVec3_c groundPos(resVec.x, mPos.y + 4.0f, resVec.z); + float groundHeight; + if (dBc_c::checkGround(&groundPos, &groundHeight, mLayer, 1, -1) && groundHeight > resVec.y) { + f2 = groundHeight - resVec.y; + } + sLib::chase(&m_1594, f1, 1.0f); + sLib::chase(&m_1598, f2, 1.0f); +} + +void dAcPy_c::finalizeState_Swim() { + m_1594 = 0.0f; + m_1598 = 0.0f; + m_b88 = 0; + mAngle.z = 0; + mAngle.x = 0; + offStatus(STATUS_SWIM); + if (isStatus(STATUS_PENGUIN_SWIM)) { + float groundHeight; + mVec3_c checkPos(mPos.x, mPos.y - 5.0f, mPos.z); + if (dBc_c::checkGround(&mPos, &groundHeight, mLayer, 1, -1)) { + if (mPos.y <= groundHeight) { + mPos.y = groundHeight; + mLastPos.y = mPos.y; + } + } + offStatus(STATUS_PENGUIN_SWIM); + } + offStatus(STATUS_97); + offStatus(STATUS_AA); + offStatus(STATUS_A8); + offStatus(STATUS_92); + if (!isNowBgCross(BGC_WATER_SHALLOW)) { + setWaterOutEffect(); + } +} + +void dAcPy_c::setIvyHangEffect() { + mMtx_c jntMtx; + mPyMdlMng.mpMdl->getJointMtx(&jntMtx, 11); + mVec3_c v1; + jntMtx.multVecZero(v1); + mPyMdlMng.mpMdl->getJointMtx(&jntMtx, 14); + mVec3_c v2; + jntMtx.multVecZero(v2); + mVec3_c efPos = (v1 + v2) / 2.0f; + efPos.z = mPos.z; + dEf::createPlayerEffect(mPlayerNo, &mLevelEf6, "Wm_mr_ivy", 0, &efPos, nullptr, nullptr); +} + +bool dAcPy_c::setVineAction() { + if (isStatus(STATUS_9B)) { + if (isCarry()) { + return false; + } + if (mSpeed.y <= 0.0f && mKey.buttonUp() && isNowBgCross(BGC_VINE_TOUCH_U)) { + if (mBc.mFenceType == 1) { + changeState(StateID_Vine, (void *) 2); + } else { + changeState(StateID_Vine, (void *) 0); + } + return true; + } + } + return false; +} + +float dAcPy_c::getHangBcOffsetY() { + static const float scHangOffsetY[] = { + 16.0f, 27.0f, 27.0f, 12.0f, 27.0f, 27.0f, 27.0f + }; + static const float scKinopioHangOffsetY[] = { + 13.0f, 21.0f, 21.0f, 9.0f, 21.0f, 21.0f, 21.0f + }; + // [probably some inline?] + if (!(mPlayerType != PLAYER_MARIO && mPlayerType != PLAYER_LUIGI)) { + return scHangOffsetY[mPowerup]; + } else { + return scKinopioHangOffsetY[mPowerup]; + } +} + +bool dAcPy_c::setKaniHangToVineAction() { + if (mKey.buttonDown()) { + float y = mPos.y - 1.0f; + float x2 = mPos.x + (mVineBcData.mOffset / 4096.0f); + float x1 = mPos.x - (mVineBcData.mOffset / 4096.0f + 1.0f); + if ( + dBc_c::getUnitType(x1, y, mLayer) & 0x400 || + dBc_c::getUnitType(x2, y, mLayer) & 0x400 + ) { + mPos.y -= getHangBcOffsetY(); + m_60 = 10; + changeState(StateID_Vine, (void *) 3); + return true; + } + } + return false; +} + +bool dAcPy_c::setVineToKaniHangAction() { + if (mKey.buttonUp()) { + sBcPointData r = mVineBcData; + r.mInfMargin = getHangBcOffsetY() * 4096.0f; + if (!(mBc.checkCollision2(&r) & 3)) { + float y = mPos.y + getHangBcOffsetY(); + float x = mPos.x; + short groundY = (((short) y) & 0xfff0) - 16; + u32 unitKind = dBc_c::getUnitKind(x, groundY + 1.0f, mLayer); + if ((unitKind >> 16 & 0xff) == 8) { + mPos.y += getHangBcOffsetY(); + m_60 = 10; + changeState(StateID_Kani, KANI_ARG_HANG_UP_VINE); + return true; + } + } + } + return false; +} + +void dAcPy_c::initializeState_Vine() { + setScrollMode(2); + onStatus(STATUS_VINE); + mAccelY = 0.0f; + mSpeedF = 0.0f; + mAccelF = 0.0f; + mMaxSpeedF = 0.0f; + mSpeed.x = 0.0f; + mSpeed.y = 0.0f; + m_7c4 = 0; + if (mAmiLayer == 1) { + m_7c0 = 0x8000; + } else { + m_7c0 = 0; + } + int changeParam = (int) mStateArg; + mAngle.y = m_7c0; + mBc.mPlayerFlags |= 1; + switch (changeParam) { + case 0: + case 2: + startPlayerVoice(VOICE_ROPE_CATCH, 0); + switch (mBc.mFenceType) { + case 0: + startSound(SE_PLY_CATCH_IVY, 0); + if (!isNowBgCross(BGC_FOOT)) { + mPyMdlMng.setAnm(PLAYER_ANIM_PEA_PLANT_ST); + mSubstate = VINE_ACTION_IVY; + mSubstateValue = 0; + } else { + mPyMdlMng.setAnm(PLAYER_ANIM_PEA_PLANT_WAIT); + mSubstate = VINE_ACTION_IVY; + mSubstateValue = 1; + } + break; + case 1: + mPyMdlMng.setAnm(PLAYER_ANIM_NET_WAIT); + mSubstate = VINE_ACTION_NET; + break; + case 2: + startSound(SE_PLY_LAND_FENCE, 0); + mPyMdlMng.setAnm(PLAYER_ANIM_NET_WAIT); + mSubstate = VINE_ACTION_NET; + break; + } + break; + case 1: + mPyMdlMng.setAnm(PLAYER_ANIM_PEA_PLANT_WAIT); + mSubstate = VINE_ACTION_IVY; + mSubstateValue = 1; + break; + case 3: + mPyMdlMng.setAnm(PLAYER_ANIM_NET_WAIT, 0.0f, 0.0f); + mSubstate = VINE_ACTION_NET; + break; + } +} + +void dAcPy_c::calcVineSpeed() { + float speed; + switch (mBc.mFenceType) { + case 0: + case 2: + if (mKey.buttonDush()) { + speed = 1.5f; + } else { + speed = 1.0f; + } + break; + case 1: + if (mKey.buttonDush()) { + speed = sGlobalData_c::mData.mVineSpeedRelated[1]; + } else { + speed = sGlobalData_c::mData.mVineSpeedRelated[0]; + } + break; + } + mSpeed.y = 0.0f; + if (mKey.buttonUp()) { + if (isNowBgCross(BGC_VINE_TOUCH_U) && isNowBgCross(BGC_VINE_TOUCH_2)) { + mSpeed.y = speed; + } + } else if (mKey.buttonDown()) { + mSpeed.y = -speed; + } + mSpeedF = 0.0f; + float tmp = 0.0f; + switch (mBc.mFenceType) { + case 0: + if (mKey.buttonDush()) { + tmp = 0.7f; + } else { + tmp = 0.5f; + } + if (mKey.buttonUp() || mKey.buttonDown()) { + tmp = 0.0f; + } + break; + case 1: + if (mKey.buttonDush()) { + tmp = sGlobalData_c::mData.mVineSpeedRelated[3]; + } else { + tmp = sGlobalData_c::mData.mVineSpeedRelated[2]; + } + break; + case 2: + if (mKey.buttonDush()) { + tmp = 1.25f; + } else { + tmp = 0.875f; + } + break; + } + if (mKey.buttonLeft()) { + if (!isNowBgCross(BGC_WALL_TOUCH_L_2)) { + mSpeedF = -tmp; + } + } else if (mKey.buttonRight()) { + if (!isNowBgCross(BGC_WALL_TOUCH_R_2)) { + mSpeedF = tmp; + } + } +} + +bool dAcPy_c::checkVineEnd() { + if (!isNowBgCross(BGC_VINE_TOUCH_FULL) || isNowBgCross(BGC_FOOT) && !mKey.buttonUp()) { + mAngle.y = getMukiAngle(mDirection); + if (isNowBgCross(BGC_CLIFF)) { + changeState(StateID_Kani, KANI_ARG_WALK_FORCE); + return true; + } else { + changeState(StateID_Walk, BLEND_NONE); + return true; + } + } + return false; +} + +void dAcPy_c::setVineWalkSE() { + if (mPyMdlMng.mpMdl->mAnm.checkFrame(10.0f) || mPyMdlMng.mpMdl->mAnm.checkFrame(30.0f)) { + switch (mBc.mFenceType) { + case 0: + startSound(SE_PLY_MOVE_IVY, false); + break; + case 2: + startSound(SE_PLY_WALK_METAL, false); + break; + case 1: + startSound(SE_PLY_FOOTNOTE_ROCK_CLIMB, false); + break; + } + } +} + +void dAcPy_c::VineActionIvy() { + if (setRideOffPlayerJump(sc_JumpSpeed, 0.0f) || startJump(BLEND_NONE, 1)) { + return; + } + if (checkVineEnd()) { + return; + } + calcVineSpeed(); + if (mSubstateValue == 0) { + if (mPyMdlMng.isAnmStop()) { + mSubstateValue++; + } + } else { + if (mSpeed.x || mSpeed.y) { + float blend = 0.0f; + if (mKey.buttonDush()) { + blend = 1.875f; + } else { + blend = 1.5f; + } + if (mSpeed.y < 0.0f) { + blend = -blend; + } + mPyMdlMng.setAnm(PLAYER_ANIM_PEA_PLANT, blend, 0.0f, 0.0f); + if (mBc.mFenceType == 0 && m_7c4 == 0) { + setIvyHangEffect(); + setVineWalkSE(); + } + } else { + mPyMdlMng.setAnm(PLAYER_ANIM_PEA_PLANT_WAIT, 0.0f); + m_7c4 = 3; + } + } +} + +void dAcPy_c::VineActionNet() { + if (checkVineEnd()) { + return; + } + switch (mBc.mFenceType) { + default: + if (setRideOffPlayerJump(sc_JumpSpeed, 0.0f) || startJump(BLEND_NONE, 0)) { + switch (mPowerup) { + case POWERUP_NONE: + startSound(SE_PLY_JUMP_FENCE_S, false); + break; + case POWERUP_MINI_MUSHROOM: + startSound(SE_PLY_JUMP_FENCE_SS, false); + break; + default: + startSound(SE_PLY_JUMP_FENCE, false); + break; + } + mAngle.y = getMukiAngle(mDirection); + return; + } + if (mKey.triggerAttack()) { + mSubstate = VINE_ACTION_ATTACK; + mSubstateValue = 0; + mPyMdlMng.setAnm(PLAYER_ANIM_NET_ATTACK); + mSpeed.y = 0.0f; + mSpeedF = 0.0f; + onStatus(STATUS_4A); + return; + } + break; + case 1: + if (setVineToKaniHangAction()) { + return; + } + break; + } + calcVineSpeed(); + float f = 1.0f; + if (mBc.mpFenceCollision != nullptr) { + short s = abs(mBc.mpFenceCollision->m_c2); + if (s > 128) { + s = 128; + } + float tmp = s * 0.5f; + f = tmp / 128.0f + 1.0f; + } + if (!mKey.buttonUp()) { + m_7c4 = 0; + } + if (mSpeed.y) { + float rate; + if (mKey.buttonDush()) { + rate = 1.875f; + } else { + rate = 1.5f; + } + rate = rate * f; + if (mSpeed.y < 0.0f) { + rate = -rate; + } + mPyMdlMng.setAnm(PLAYER_ANIM_NET_WALK1, rate, 0.0f, 0.0f); + m_7c4 = 5; + setVineWalkSE(); + } else if (mSpeed.x) { + if (m_7c4 == 0) { + float rate; + if (mKey.buttonDush()) { + rate = 1.875f; + } else { + rate = 1.5f; + } + rate = rate * f; + mPyMdlMng.setAnm(PLAYER_ANIM_NET_WALK2, rate, 0.0f, 0.0f); + } + setVineWalkSE(); + } else if (f > 1.0f) { + if (mKey.buttonLeft() || mKey.buttonRight()) { + mPyMdlMng.setAnm(PLAYER_ANIM_NET_WALK2, 0.6f * f, 0.0f, 0.0f); + } else { + mPyMdlMng.setAnm(PLAYER_ANIM_NET_WALK1, 0.6f * f, 0.0f, 0.0f); + } + } else { + mPyMdlMng.setAnm(PLAYER_ANIM_NET_WAIT); + } +} + +void dAcPy_c::VineActionAttack() { + if (checkVineEnd()) { + return; + } + u16 frame = mPyMdlMng.mpMdl->mAnm.getFrame(); + if (mPyMdlMng.mpMdl->mAnm.checkFrame(3.0f)) { + onStatus(STATUS_49); + mMtx_c jntMtx; + mPyMdlMng.mpMdl->getJointMtx(&jntMtx, 14); + jntMtx.concat(mMtx_c::createTrans(3.0f, 0.0f, 0.0f)); + mVec3_c efPos; + jntMtx.multVecZero(efPos); + dEf::createPlayerEffect_change(mPlayerNo, "Wm_mr_wirehit", 0, &efPos, nullptr, nullptr); + startSound(SE_PLY_ATTACK_FENCE, false); + } + if (!isStatus(STATUS_85)) { + if (frame >= 12.0f && mKey.buttonCross() || mPyMdlMng.isAnmStop()) { + mSubstate = VINE_ACTION_NET; + return; + } + if (mKey.triggerAttack()) { + mSubstateValue = 1; + } + if (frame >= 23.0f && mSubstateValue != 0) { + mPyMdlMng.mpMdl->setFrame(0.0f); + mSubstateValue = 0; + } + } + if (frame < 24.0f) { + onStatus(STATUS_4A); + setCcAtNetPunch(); + } +} + +void dAcPy_c::VineActionRoll() { + onStatus(STATUS_7A); + switch (m_7bc) { + case 0: + if (mPyMdlMng.isAnmStop()) { + m_7bc = 1; + mPyMdlMng.setAnm(PLAYER_ANIM_NET_WAIT); + } + break; + case 2: + offStatus(STATUS_7A); + mPyMdlMng.setAnm(PLAYER_ANIM_NET_WAIT); + mSubstate = VINE_ACTION_NET; + break; + } +} + +void dAcPy_c::executeState_Vine() { + offStatus(STATUS_49); + offStatus(STATUS_4A); + if (m_7c4 != 0) { + m_7c4--; + } + typedef void (dAcPy_c::*VineActionProc_t)(); + static VineActionProc_t l_VineActionProc[] = { + &dAcPy_c::VineActionIvy, + &dAcPy_c::VineActionNet, + &dAcPy_c::VineActionAttack, + &dAcPy_c::VineActionRoll + }; + (this->*l_VineActionProc[mSubstate])(); +} + +bool dAcPy_c::checkNetPunch() { + if ( + isState(StateID_Vine) && + mSubstate == VINE_ACTION_ATTACK && + mPyMdlMng.mpMdl->mAnm.getFrame() >= 10.0f + ) { + mSubstate = VINE_ACTION_ROLL; + m_7bc = 0; + return true; + } + return false; +} + +bool dAcPy_c::setAmiRollAction(mVec3_c *pos) { + if (isState(StateID_Vine)) { + if (mSubstate != VINE_ACTION_ROLL) { + mSubstate = VINE_ACTION_ROLL; + m_7bc = 1; + mPyMdlMng.setAnm(PLAYER_ANIM_NET_WAIT); + } + mPos.z = 0.0f; + mAmiRollPos = *pos; + mAmiAng = mAngle.y; + mAmiXDiff = mPos.x - mAmiRollPos.x; + mAmiRelated = 0.7f; + return true; + } + return false; +} + +bool dAcPy_c::isAmiRollAction() { + if (isState(StateID_Vine) && mSubstate == VINE_ACTION_ROLL) { + return true; + } + return false; +} + +void dAcPy_c::setAmiRollPos(short ang, float f) { + float cos = mAng(ang).cos(); + float sin = mAng(ang).sin(); + mVec3_c v( + mAmiRollPos.x + cos * mAmiXDiff + sin * mAmiRelated, + mPos.y, + mAmiRollPos.z + cos * mAmiRelated - sin * mAmiXDiff + ); + setAmiRollPos(ang, f, v); +} + +void dAcPy_c::setAmiRollPos(short ang, float f, mVec3_c &v) { + if (isAmiRollAction()) { + mAngle.y = mAmiAng + ang; + mPos = v; + mAmiRelated2 = f; + } +} + +void dAcPy_c::endAmiRollAction(short ang) { + if (isAmiRollAction()) { + mAng newAng = m_7c0 + ang; + m_7c0 = newAng; + mAngle.y = newAng; + if (m_7c0 == 0x8000) { + mAmiLayer = 1; + } else { + mAmiLayer = 2; + } + mAmiRelated2 = 1.0f; + m_7bc = 2; + } +} + +void dAcPy_c::finalizeState_Vine() { + mAccelY = getGravityData()[0]; + offStatus(STATUS_VINE); + offStatus(STATUS_7A); + offStatus(STATUS_49); + offStatus(STATUS_4A); + mBc.mPlayerFlags &= ~1; +} + +void dAcPy_c::setCarryPlayerHang(float height) { + mPos.y = height - mHeadBcData.mOffset / 4096.0f; + onNowBgCross(BGC_HANG_ROPE); + changeState(StateID_Hang, 0); +} + +bool dAcPy_c::setHangAction() { + if (isNowBgCross(BGC_HANG_ROPE)) { + dAcPy_c *carryPlayer = getCarryPlayer(); + if (carryPlayer != nullptr && carryPlayer->isStatus(STATUS_9C) && !carryPlayer->isCarry()) { + float hangHeight = mPos.y + mHeadBcData.mOffset / 4096.0f; + releaseCarryActor(); + carryPlayer->setCarryPlayerHang(hangHeight); + return true; + } + if (isStatus(STATUS_9C) && !isCarry() && mSpeed.y >= 0.0f) { + changeState(StateID_Hang, 0); + return true; + } + } + return false; +} + +void dAcPy_c::initializeState_Hang() { + onStatus(STATUS_HANG); + mAccelY = 0.0f; + mSpeedF = 0.0f; + mMaxSpeedF = 0.0f; + mSpeed.x = 0.0f; + mSpeed.y = 0.0f; + m_1598 = 0.0f; + if (mPlayerType == PLAYER_YELLOW_TOAD || mPlayerType == PLAYER_BLUE_TOAD) { + static const float scHangOffsetY[POWERUP_COUNT] = { 4.5f, 10.0f, 10.0f, 1.0f, 10.0f, 9.0f, 10.0f }; + m_1598 = scHangOffsetY[mPowerup]; + } + mPyMdlMng.setAnm(PLAYER_ANIM_MONKEY_START); + setZPositionDirect(400.0f); + startPlayerVoice(VOICE_ROPE_CATCH, 0); +} + +void dAcPy_c::HangActionStart() { + mSpeedF = 0.0f; + m_8f0 = 0; + if (mPyMdlMng.isAnmStop()) { + setHangActionWait(); + } else if (mKey.buttonRight() || mKey.buttonLeft()) { + setHangActionMove(); + } +} + +void dAcPy_c::setHangActionWait() { + mSubstate = HANG_ACTION_WAIT; + static const int scHangWaitAnm[] = { PLAYER_ANIM_MONKEY_WAIT_R, PLAYER_ANIM_MONKEY_WAIT_L }; + mPyMdlMng.setAnm(scHangWaitAnm[m_8f0]); +} + +void dAcPy_c::HangActionWait() { + mSpeedF = 0.0f; + if (mKey.buttonRight() || mKey.buttonLeft()) { + setHangActionMove(); + } +} + +void dAcPy_c::setHangActionMove() { + mSubstate = HANG_ACTION_MOVE; + static const int scHangMoveAnm[] = { PLAYER_ANIM_MONKEY_R_TO_L, PLAYER_ANIM_MONKEY_L_TO_R }; + mPyMdlMng.setAnm(scHangMoveAnm[m_8f0]); + m_8f0 ^= 1; + startSound(SE_PLY_MONKEY_BARS, false); +} + +void dAcPy_c::HangActionMove() { + if (mKey.buttonDush()) { + mSpeedF = sc_DirSpeed[mDirection] * 1.125f; + mPyMdlMng.mpMdl->setRate(1.5f); + } else { + mSpeedF = sc_DirSpeed[mDirection] * 0.875f; + mPyMdlMng.mpMdl->setRate(1.0f); + } + if (mPyMdlMng.isAnmStop()) { + if (mKey.buttonRight() || mKey.buttonLeft()) { + setHangActionMove(); + } else { + setHangActionWait(); + } + } +} + +void dAcPy_c::executeState_Hang() { + if (!isNowBgCross(BGC_HANG_ROPE) || mKey.buttonDown()) { + changeState(StateID_Fall, false); + startPlayerVoice(VOICE_ROPE_RELEASE, 0); + } else { + turnBesideAngle(); + typedef void (dAcPy_c::*HangActionProc_t)(); + static HangActionProc_t l_HangActionProc[] = { + &dAcPy_c::HangActionStart, + &dAcPy_c::HangActionWait, + &dAcPy_c::HangActionMove, + }; + (this->*l_HangActionProc[mSubstate])(); + } +} + +void dAcPy_c::finalizeState_Hang() { + m_1598 = 0.0f; + setScrollMode(0); + offStatus(STATUS_HANG); + offZPosSetNone(); +} + +void dAcPy_c::setPoleTurnAngle() { + short target = getBesideMukiAngle(mDirection ^ 1); + mAngle.y.chase(target, 0x2000); +} + +bool dAcPy_c::setPoleAction() { + if (isStatus(STATUS_9D)) { + if (mPoleGrabCooldown != 0 || isCarry()) { + return false; + } + if (mSpeed.y <= 3.0f && mKey.buttonUp() && isNowBgCross(BGC_CAN_CLIMB)) { + changeState(StateID_Pole, 0); + return true; + } + } + return false; +} + +void dAcPy_c::initializeState_Pole() { + onStatus(STATUS_POLE); + onStatus(STATUS_97); + onStatus(STATUS_9F); + mAccelY = 0.0f; + mSpeedF = 0.0f; + mAccelF = 0.0f; + mMaxSpeedF = 0.0f; + mSpeed.x = 0.0f; + mSpeed.y = 0.0f; + mAngle.y = getBesideMukiAngle(mDirection); + m_8f4.x = (int) (mPos.x / 16.0f) * 16.0f + 8.0f; + setZPositionDirect(400.0f); + if (isNowBgCross(BGC_CAN_CLIMB)) { + m_8f4.y = mPos.y; + } + if (isNowBgCross(BGC_FOOT)) { + setPoleActionUp(); + mSpeed.y = 1.0f; + offNowBgCross(BGC_FOOT); + mDirection ^= 1; + offStatus(STATUS_97); + } else { + mPyMdlMng.setAnm(PLAYER_ANIM_TREE_START); + startSound(SE_PLY_POLE_CATCH, false); + startPlayerVoice(VOICE_ROPE_CATCH, 0); + mSubstate = 0; + } +} + +void dAcPy_c::PoleActionStart() { + if (mKey.triggerJump()) { + mSubstateValue = 1; + } + if (mPyMdlMng.mpMdl->mAnm.getFrame() >= 5.0f && mSubstateValue != 0) { + int dir; + if (mKey.buttonWalk(&dir)) { + mDirection = dir; + } + setPoleJump(); + + } else if (mPyMdlMng.isAnmStop()) { + setPoleActionWait(); + mDirection ^= 1; + offStatus(STATUS_97); + } +} + +void dAcPy_c::setPoleActionWait() { + mSubstate = 1; + mPyMdlMng.setAnm(PLAYER_ANIM_TREE_WAIT); +} + +void dAcPy_c::PoleActionWait() { + if (!isNowBgCross(BGC_CAN_CLIMB)) { + mDirection ^= 1; + changeState(StateID_Fall, false); + } else { + setPoleTurnAngle(); + mSpeed.y = 0.0f; + if (mKey.buttonDown()) { + setPoleActionDown(); + } else if (mKey.buttonUp()) { + setPoleActionUp(); + } + } +} + +void dAcPy_c::setPoleActionUp() { + mSubstate = 2; + mPyMdlMng.setAnm(PLAYER_ANIM_TREE_CLIMB); +} + +void dAcPy_c::PoleActionUp() { + setPoleTurnAngle(); + if (mPyMdlMng.mpMdl->mAnm.checkFrame(0.0f)) { + startSound(SE_PLY_POLE_CLIMB, false); + } + mSpeed.y = 0.0f; + if (!isNowBgCross(BGC_CAN_CLIMB)) { + mPos.y = m_8f4.y; + } + if (mKey.buttonDown()) { + setPoleActionDown(); + } else if (!mKey.buttonUp()) { + setPoleActionWait(); + } else if (mKey.buttonDush()) { + mPyMdlMng.mpMdl->setRate(1.875f); + mSpeed.y = 1.5f; + } else { + mPyMdlMng.mpMdl->setRate(1.5f); + mSpeed.y = 1.0f; + } +} + +void dAcPy_c::setPoleActionDown() { + mSubstate = 3; + mPyMdlMng.setAnm(PLAYER_ANIM_TREE_POSE); +} + +void dAcPy_c::PoleActionDown() { + if (!isNowBgCross(BGC_CAN_CLIMB)) { + mDirection ^= 1; + changeState(StateID_Fall, false); + return; + } + setPoleTurnAngle(); + mSpeed.y = 0.0f; + if (mKey.buttonUp()) { + setPoleActionUp(); + } else if (!mKey.buttonDown()) { + setPoleActionWait(); + } else { + if (mKey.buttonDush()) { + float rate = 1.6f; + mSpeed.y = rate * -2.0f; + mPyMdlMng.mpMdl->setRate(rate); + } else { + mSpeed.y = -2.0f; + mPyMdlMng.mpMdl->setRate(1.0f); + } + holdSound(SE_PLY_POLE_SLIDE, false); + } +} + +void dAcPy_c::setPoleJump() { + startPlayerVoice(VOICE_ROPE_RELEASE, 0); + mPoleGrabCooldown = 5; + changeState(StateID_Jump, nullptr); + u8 dir = mDirection; + float baseSpeed = getSpeedData()->mLowSpeed; + mSpeedF = baseSpeed * sc_DirSpeed[dir]; +} + +bool dAcPy_c::setPoleShakeJump() { + u8 dir = mDirection; + float baseSpeed = getSpeedData()->mLowSpeed; + if (setRideOffPlayerJump(sc_JumpSpeed, baseSpeed * sc_DirSpeed[dir])) { + startPlayerVoice(VOICE_ROPE_RELEASE, 0); + mPoleGrabCooldown = 5; + return true; + } + return false; +} + +void dAcPy_c::executeState_Pole() { + if (isNowBgCross(BGC_FOOT)) { + mDirection ^= 1; + changeState(StateID_Walk, BLEND_DEFAULT); + } else if (isNowBgCross(BgCross1_e(BGC_SIDE_LIMIT_L | BGC_SIDE_LIMIT_R))) { + mDirection ^= 1; + changeState(StateID_Fall, false); + } else { + if (!setPoleShakeJump()) { + if (mSubstate != 0 && mKey.triggerJump()) { + setPoleJump(); + return; + } + mPos.x = m_8f4.x; + if (isNowBgCross(BGC_CAN_CLIMB)) { + m_8f4.y = mPos.y; + } + typedef void (dAcPy_c::*PoleActionProc_t)(); + static PoleActionProc_t l_PoleActionProc[] = { + &dAcPy_c::PoleActionStart, + &dAcPy_c::PoleActionWait, + &dAcPy_c::PoleActionUp, + &dAcPy_c::PoleActionDown, + }; + (this->*l_PoleActionProc[mSubstate])(); + float yDelta = mCcRevTotalOffsY; + mPos.y += yDelta; + } + } +} + +void dAcPy_c::finalizeState_Pole() { + offStatus(STATUS_POLE); + offStatus(STATUS_97); + offStatus(STATUS_9F); + offZPosSetNone(); +} + +bool dAcPy_c::setKaniActionInitHangHand() { + if (isCarry()) { + return false; + } + if ( + !isNowBgCross(BGC_FOOT) && + mSpeed.y < 0.0f && + !isOldBgCross(BgCross2_e(BGC_CLIFF_ABOVE_1 | BGC_CLIFF_ABOVE_2)) && + isNowBgCross(BgCross2_e(BGC_CLIFF_ABOVE_1 | BGC_CLIFF_ABOVE_2)) + ) { + mPos.y = mKaniHeight; + changeState(StateID_Kani, KANI_ARG_HANG_HAND); + return true; + } + return false; +} + +bool dAcPy_c::setKaniHangAction() { + if (isNowBgCross(BGC_CLIFF) && mSpeed.y <= 0.0f) { + if (isStatus(STATUS_A1)) { + changeState(StateID_Kani, KANI_ARG_JUMP_HANG); + return true; + } + if (isStatus(STATUS_A2)) { + changeState(StateID_Kani, KANI_ARG_WALK); + return true; + } + } + return false; +} + +void dAcPy_c::setKaniWalkEffect() { + if (m_b70 != 1) { + mVec3_c efPos; + mPyMdlMng.mpMdl->getJointPos(&efPos, 4); + dEf::createPlayerEffect(mPlayerNo, &mLevelEf7, "Wm_mr_movecliff", 0, &efPos, nullptr, nullptr); + mPyMdlMng.mpMdl->getJointPos(&efPos, 7); + dEf::createPlayerEffect(mPlayerNo, &mLevelEf7, "Wm_mr_movecliff", 0, &efPos, nullptr, nullptr); + } +} + +void dAcPy_c::setKaniHangEffect() { + if (m_b70 != 1) { + mVec3_c efPos; + mPyMdlMng.mpMdl->getJointPos(&efPos, 11); + dEf::createPlayerEffect(mPlayerNo, &mLevelEf7, "Wm_mr_movecliff", 0, &efPos, nullptr, nullptr); + mPyMdlMng.mpMdl->getJointPos(&efPos, 14); + dEf::createPlayerEffect(mPlayerNo, &mLevelEf7, "Wm_mr_movecliff", 0, &efPos, nullptr, nullptr); + } +} + +void dAcPy_c::setKaniCliffCatchEffect() { + static const char *scCliffCatchEffectID[] = { + "Wm_mr_cliffcatch", + "Wm_en_landsmoke_s" + }; + static const float sc_cliffCatchScale[] = { 0.5f, 0.8f, 1.0f }; + u8 tallType = getTallType(-1); + float scale = sc_cliffCatchScale[tallType]; + mVec3_c efSize(scale, scale, scale); + mVec3_c efPos; + mPyMdlMng.mpMdl->getJointPos(&efPos, 11); + efPos.y = mPos.y; + dEf::createPlayerEffect(mPlayerNo, scCliffCatchEffectID[m_b70], 0, &efPos, nullptr, &efSize); + mPyMdlMng.mpMdl->getJointPos(&efPos, 14); + efPos.y = mPos.y; + dEf::createPlayerEffect(mPlayerNo, scCliffCatchEffectID[m_b70], 0, &efPos, nullptr, &efSize); +} + +void dAcPy_c::initializeState_Kani() { + onStatus(STATUS_A8); + mSpeed.y = 0.0f; + m_b70 = 0; + if (isNowBgCross(BGC_LIFT)) { + m_b70 = 1; + } + m_b74 = m_b70; + m_b78 = mPos.y; + m_b7c = 0; + + KaniArg_e arg = stateArg(); + if (arg == KANI_ARG_WALK && mKey.buttonDown()) { + arg = KANI_ARG_HANG; + } + switch (arg) { + case KANI_ARG_WALK: setKaniAction_Walk(); break; + case KANI_ARG_HANG: setKaniAction_Hang(); break; + case KANI_ARG_JUMP_HANG: setKaniAction_JumpHang(); break; + case KANI_ARG_WALK_FORCE: setKaniAction_Walk(); break; + case KANI_ARG_HANG_UP_VINE: setKaniAction_HangUpVine(); break; + case KANI_ARG_HANG_HAND: setKaniAction_HangHand(); break; + } +} + +void dAcPy_c::finalizeState_Kani() { + offStatus(STATUS_9B); + offStatus(STATUS_KANI_HANG_ANIMATION); + offStatus(STATUS_KANI_HANG); + offStatus(STATUS_KANI_WALK); + offStatus(STATUS_A8); + mAngle.y = getMukiAngle(mDirection); + offZPosSetNone(); +} + +void dAcPy_c::setKaniMoveSpeed(bool b) { + float scale = 0.0f; + int dir; + if (mKey.buttonWalk(&dir)) { + float f; + if (isStar()) { + if (mKey.buttonDush()) { + f = 1.3f; + } else { + f = 1.05f; + } + } else { + if (mKey.buttonDush()) { + f = sGlobalData_c::mData.mKaniSpeedRelated[1]; + } else { + f = sGlobalData_c::mData.mKaniSpeedRelated[0]; + } + } + scale = f * sc_DirSpeed[dir]; + } + if (b == true) { + scale *= 0.8f; + } else { + scale *= 1.2f; + } + mMaxSpeedF = scale; + normalPowerSet(); +} + +void dAcPy_c::setKaniHangStartEffect() {} + +void dAcPy_c::setKaniAction_Walk() { + mAngle.y = 0; + setKaniMoveSpeed(true); + if (!mMaxSpeedF) { + mSpeedF = 0.0f; + } else if (mMaxSpeedF < 0.0f) { + if (mSpeedF < mMaxSpeedF) { + mSpeedF = mMaxSpeedF; + } + } else if (mSpeedF > mMaxSpeedF) { + mSpeedF = mMaxSpeedF; + } + mSubstate = KANI_ACTION_WALK; +} + +void dAcPy_c::setKaniAction_Hang() { + releaseCarryActor(); + mAngle.y = 0x8000; + mSpeedF = 0.0f; + mPyMdlMng.setAnm(PLAYER_ANIM_HANG_START); + startPlayerVoice(VOICE_CLIFF_DOWN, 0); + mSubstate = KANI_ACTION_HANG_INIT; + onStatus(STATUS_KANI_HANG_ANIMATION); +} + +void dAcPy_c::setKaniAction_JumpHang() { + releaseCarryActor(); + mAngle.y = 0x8000; + mSpeedF = 0.0f; + mPyMdlMng.setAnm(PLAYER_ANIM_JUMP_HANG); + setKaniCliffCatchEffect(); + startPlayerVoice(VOICE_CLIFF_DIVE, 0); + mSubstate = KANI_ACTION_JUMP_HANG_INIT; +} + +void dAcPy_c::setKaniAction_HangFall() { + mPyMdlMng.setAnm(PLAYER_ANIM_HANG_WAIT); + mSubstate = KANI_ACTION_HANG_FALL; +} + +void dAcPy_c::setKaniAction_HangUp() { + releaseCarryActor(); + mSpeedF = 0.0f; + setKaniHangStartEffect(); + mPyMdlMng.setAnm(PLAYER_ANIM_HANG_UP); + startPlayerVoice(VOICE_CLIFF_UP, 0); + mSubstate = KANI_ACTION_HANG_UP; +} + +void dAcPy_c::setKaniAction_HangHand() { + if (isNowBgCross(BGC_CLIFF_ABOVE_2)) { + m_b70 = 1; + } + releaseCarryActor(); + mAngle.y = 0x8000; + mSpeedF = 0.0f; + mPyMdlMng.setAnm(PLAYER_ANIM_JUMP_HANG, 0.0f, 0.0f); + setKaniCliffCatchEffect(); + mSubstate = KANI_ACTION_JUMP_HANG_INIT; +} + +void dAcPy_c::setKaniAction_HangUpVine() { + releaseCarryActor(); + mSpeedF = 0.0f; + mPyMdlMng.setAnm(PLAYER_ANIM_HANG_WAIT, 0.5f, 0.0f, 0.0f); + mSubstate = KANI_ACTION_HANG_UP_VINE; +} + +void dAcPy_c::KaniAction_Walk() { + onStatus(STATUS_KANI_WALK); + onStatus(STATUS_9B); + if (!isNowBgCross(BGC_CLIFF)) { + changeState(StateID_Walk, BLEND_NONE); + return; + } + if (mKey.triggerDown()) { + setKaniAction_Hang(); + } else if (mKey.triggerJump()) { + changeState(StateID_KaniJump); + } else { + setKaniMoveSpeed(true); + if (!mSpeedF) { + if (mPyMdlMng.getAnm() != PLAYER_ANIM_WALL_WAIT) { + mPyMdlMng.setAnm(PLAYER_ANIM_WALL_WAIT); + } + } else { + setKaniWalkEffect(); + float absSpeed = std::fabs(mSpeedF) - 0.5f; + if (absSpeed < 0.0f) { + absSpeed = 0.0f; + } + if (absSpeed > 1.0f) { + absSpeed = 1.0f; + } + float rate = absSpeed * 2.0f + 1.0f; + static const int sc_WallWalkAnm[] = { PLAYER_ANIM_WALL_WALK_L, PLAYER_ANIM_WALL_WALK_R }; + if (!mPyMdlMng.isAnm(sc_WallWalkAnm[mDirection])) { + mPyMdlMng.setAnm(sc_WallWalkAnm[mDirection], rate, 10.0f, 0.0f); + } + mPyMdlMng.mpMdl->setRate(rate); + if (mPyMdlMng.mpMdl->mAnm.checkFrame(1.0f)) { + startSound(SE_PLY_SHUFFLE, false); + } + } + } +} + +void dAcPy_c::KaniAction_HangInit() { + onStatus(STATUS_KANI_HANG); + if (mPyMdlMng.isAnmStop()) { + setKaniHangStartEffect(); + mSubstate = KANI_ACTION_HANG; + mPyMdlMng.setAnm(PLAYER_ANIM_HANG_WAIT, 0.0f, 0.0f); + offStatus(STATUS_KANI_HANG_ANIMATION); + } +} + +void dAcPy_c::KaniAction_JumpHangInit() { + onStatus(STATUS_KANI_HANG); + mPyMdlMng.mpMdl->mAnm.checkFrame(3.0f); + if (mPyMdlMng.mpMdl->mAnm.getFrame() > 9.0f) { + mSubstate = KANI_ACTION_HANG; + } +} + +bool dAcPy_c::checkCliffHangFootGround() { + float height; + if (dBc_c::checkGround(&mPos, &height, mLayer, 1, -1)) { + float currHeight = mPos.y - getHangBcOffsetY(); + if (height > currHeight && (u8) (dBc_c::getUnitKind(mPos.x, height, mLayer) >> 16) != 8) { + mPos.y = currHeight; + m_60 = 10; + changeState(StateID_Walk, BLEND_NONE); + return true; + } + } + return false; +} + +bool dAcPy_c::checkCliffHangWater() { + float waterHeight; + float currHeight = mPos.y - getHangBcOffsetY(); + u8 waterType = dBc_c::checkWater(mPos.x, currHeight, mLayer, &waterHeight); + if (waterType == dBc_c::WATER_CHECK_WATER) { + if (getWaterCheckPosY() - getHangBcOffsetY() <= waterHeight) { + onNowBgCross(BGC_WATER_SHALLOW); + mPos.y = currHeight; + m_60 = 10; + changeState(StateID_Swim, SWIM_ARG_CLIFF_HANG); + return true; + } + } + return false; +} + +void dAcPy_c::KaniAction_Hang() { + onStatus(STATUS_KANI_HANG); + if (!checkCliffHangFootGround() && !checkCliffHangWater() && !setKaniHangToVineAction()) { + if (!isNowBgCross(BGC_FOOT)) { + setKaniAction_HangFall(); + } else if (m_b74 == 1 && m_b70 == 0 && m_b7c == 1) { + setKaniAction_JumpHang(); + } else { + setKaniMoveSpeed(false); + mSpeedF = mMaxSpeedF; + if (!mSpeedF) { + if (mPyMdlMng.isAnm(PLAYER_ANIM_JUMP_HANG)) { + if (mPyMdlMng.isAnmStop()) { + mPyMdlMng.setAnm(PLAYER_ANIM_HANG_WAIT); + } + } else if (!mPyMdlMng.isAnm(PLAYER_ANIM_HANG_WAIT)) { + mPyMdlMng.setAnm(PLAYER_ANIM_HANG_WAIT); + } + } else { + setKaniHangEffect(); + float rate = std::fabs(mSpeedF); + if (rate < 0.5f) { + rate = 0.5f; + } + if (rate > 1.5f) { + rate = 1.5f; + } + static const int sc_WallHangAnm[] = { PLAYER_ANIM_HANG_WALK_R, PLAYER_ANIM_HANG_WALK_L }; + if (!mPyMdlMng.isAnm(sc_WallHangAnm[mDirection])) { + mPyMdlMng.setAnm(sc_WallHangAnm[mDirection], rate, 10.0f, 0.0f); + } + mPyMdlMng.mpMdl->setRate(rate); + if (mPyMdlMng.mpMdl->mAnm.checkFrame(1.0f)) { + startSound(SE_PLY_HANG_MOVE, false); + } + } + int dir; + if ( + !isNowBgCross(BGC_HEAD) && + ( + mKey.buttonUp() || + mKey.buttonWalk(&dir) && checkBGCrossWall(dir) + ) + ) { + setKaniAction_HangUp(); + } + } + } +} + +void dAcPy_c::KaniAction_HangFall() { + onStatus(STATUS_KANI_HANG); + if (!checkCliffHangFootGround() && !checkCliffHangWater()) { + if (isNowBgCross(BGC_FOOT)) { + setKaniAction_JumpHang(); + } else { + setKaniMoveSpeed(false); + mSpeedF = mMaxSpeedF; + } + } +} + +void dAcPy_c::KaniAction_HangUp() { + onStatus(STATUS_KANI_HANG); + if (mPyMdlMng.isAnmStop()) { + mPyMdlMng.setAnm(PLAYER_ANIM_WALL_WAIT, 0.0f, 0.0f); + setKaniAction_Walk(); + } +} + +void dAcPy_c::KaniAction_HangUpVine() { + setKaniAction_HangUp(); +} + +void dAcPy_c::executeState_Kani() { + if (checkEnableThrow()) { + releaseCarryActor(); + return; + } + m_b74 = m_b70; + m_b70 = 0; + if (isNowBgCross(BGC_LIFT)) { + m_b70 = 1; + m_b7c = 0; + if (m_b78 > mPos.y) { + m_b7c = 1; + } + } + offStatus(STATUS_9B); + offStatus(STATUS_KANI_WALK); + offStatus(STATUS_KANI_HANG); + mMaxSpeedF = 0.0f; + mAccelF = 0.0f; + mAccelY = getGravityData()[0]; + maxFallSpeedSet(); + offZPosSetNone(); + if (mSubstate != KANI_ACTION_WALK) { + setZPosition(3200.0f); + } + typedef void (dAcPy_c::*KaniActionProc_t)(); + static KaniActionProc_t l_KaniActionProc[] = { + &dAcPy_c::KaniAction_Walk, + &dAcPy_c::KaniAction_HangInit, + &dAcPy_c::KaniAction_JumpHangInit, + &dAcPy_c::KaniAction_Hang, + &dAcPy_c::KaniAction_HangFall, + &dAcPy_c::KaniAction_HangUp, + &dAcPy_c::KaniAction_HangUpVine, + }; + (this->*l_KaniActionProc[mSubstate])(); + m_b78 = mPos.y; +} + +void dAcPy_c::setCatchRopeSE() { + switch (m_914) { + case 0: + case 2: + startSound(SE_PLY_CATCH_ROPE, false); + break; + default: + startSound(SE_PLY_CATCH_KUSARI, false); + break; + } + startPlayerVoice(VOICE_ROPE_CATCH, 0); +} + +void dAcPy_c::setClimbRopeSE() { + switch (m_914) { + case 0: + case 2: + startSound(SE_PLY_CLIMB_ROPE, false); + break; + default: + startSound(SE_PLY_CLIMB_KUSARI, false); + break; + } +} + +void dAcPy_c::setSlideRopeSE() { + switch (m_914) { + case 0: + case 2: + holdSound(SE_PLY_SLIDE_ROPE, false); + break; + default: + holdSound(SE_PLY_SLIDE_KUSARI, false); + break; + } +} + +void dAcPy_c::setRopeHasigoSE() { + if (mPyMdlMng.mpMdl->mAnm.checkFrame(10.0f) || mPyMdlMng.mpMdl->mAnm.checkFrame(30.0f)) { + startSound(SE_PLY_FOOTNOTE_HASHIGO_NAWA, false); + } +} + +void dAcPy_c::releasePoleCheck() { + mPc.release(); + mPc.m_2d = 0; +} + +bool dAcPy_c::setTarzanRopeAction() { + if (isCarry()) { + return false; + } + if (mTarzanRopeCooldown != 0) { + return false; + } + if (isStatus(STATUS_9C) && mPc.check(0)) { + if (mPc.mpCtr->m_20 == 3) { + if (mPos.y + mCenterOffs.y < mPc.mpCtr->m_28->y) { + changeState(StateID_TarzanRope, (void *) 1); + return true; + } + } else { + changeState(StateID_TarzanRope, (void *) 0); + return true; + } + releasePoleCheck(); + } + if (isStatus(STATUS_A3) && mKey.buttonDown() && mPc.check(0)) { + if (mPc.mpCtr->m_20 == 3) { + changeState(StateID_TarzanRope, (void *) 2); + return true; + } + releasePoleCheck(); + } + return false; +} + +void dAcPy_c::initializeState_TarzanRope() { + onStatus(STATUS_97); + onStatus(STATUS_7F); + onStatus(STATUS_36); + mAccelY = 0.0f; + mSpeedF = 0.0f; + mAccelF = 0.0f; + mMaxSpeedF = 0.0f; + mSpeed.x = 0.0f; + mSpeed.y = 0.0f; + m_918 = 0.0f; + setZPositionDirect(400.0f); + switch ((int) mStateArg) { + case 0: + mAngle.y = getBesideMukiAngle(mDirection); + mPyMdlMng.setAnm(PLAYER_ANIM_TREE_START); + if (mPc.mpCtr->m_20 == 2) { + m_914 = 1; + } else { + m_914 = 0; + } + mSubstate = 0; + setCatchRopeSE(); + break; + case 1: + mAngle.y = 0x8000; + m_914 = 2; + setTarzanRopeActionHasigoMove(); + setCatchRopeSE(); + break; + case 2: + offStatus(STATUS_36); + releasePoleCheck(); + mAngle.y = 0x8000; + mPyMdlMng.setAnm(PLAYER_ANIM_HANG_START); + startPlayerVoice(VOICE_CLIFF_DOWN, 0); + m_914 = 2; + mSubstate = 5; + } +} + +void dAcPy_c::finalizeState_TarzanRope() { + offStatus(STATUS_97); + offStatus(STATUS_7F); + offStatus(STATUS_36); + mPc.release(); + m_1594 = 0.0f; + m_1598 = 0.0f; + mAngle.x = 0; + mAngle.z = 0, + offZPosSetNone(); +} + +bool dAcPy_c::setTarzanRopeJump() { + if (!mKey.triggerShakeJump() && !mKey.triggerJump()) { + return false; + } + float jumpSpeed = sc_JumpSpeed; + float h = 0.0f; + if (!isNowBgCross(BGC_HEAD)) { + h = mPc.getPos().x; + if (mKey.buttonLeft()) { + h -= 1.5f; + } else if (mKey.buttonRight()) { + h += 1.5f; + } + if (h < 0.0f) { + jumpSpeed = -4.0f; + if (h < -4.0f) { + h = -4.0f; + } else if (h > -0.5f) { + h = -0.5f; + } + } else if (h > 0.0f) { + jumpSpeed = 4.0f; + if (h > 4.0f) { + h = 4.0f; + } else if (h < 0.5f) { + h = 0.5f; + } + } else { + h = sc_DirSpeed[mDirection] * getSpeedData()->mLowSpeed; + } + jumpSpeed = mPc.getPos().y; + } + if (setRideOffPlayerJump(jumpSpeed, h)) { + startPlayerVoice(VOICE_ROPE_RELEASE, 0); + if (h * sc_DirSpeed[mDirection] < 0.0f) { + mDirection ^= 1; + } + mNoGravityTimer = 10; + return true; + } else { + if (mKey.triggerJump()) { + startPlayerVoice(VOICE_ROPE_RELEASE, 0); + if (h * sc_DirSpeed[mDirection] < 0.0f) { + mDirection ^= 1; + } + mNoGravityTimer = 10; + mSpeedF = h; + jmpInf_c jump(jumpSpeed, 1, BLEND_DEFAULT); + changeState(StateID_Jump, &jump); + onStatus(STATUS_88); + return true; + } + } + return false; +} + +bool dAcPy_c::updateRopeAngle() { + m_906 = m_904; + m_904 = mPc.getAngle(); + m_902 = m_900; + if (mPc.mpCtr != nullptr) { + if (mPc.mpCtr->m_20 == 1 || mPc.mpCtr->m_20 == 2) { + m_900 = mPc.mpCtr->m_34[mPlayerNo]; + return true; + } + } + return false; +} + +void dAcPy_c::setRopeSwingAnm(float a, float b) { + mPyMdlMng.mpMdl->mCurrAnmID = PLAYER_ANIM_WALK; + mPyMdlMng.setAnm(PLAYER_ANIM_ROPE_SWING, a, 10.0f, b); +} + +bool dAcPy_c::checkStartSwingUp() { + int baseAngle = m_900; + int absAngle = abs(baseAngle); + if (absAngle > 128 && absAngle < abs(m_902)) { + if (sc_DirSpeed[mDirection] * baseAngle >= 0.0f) { + m_90c = ROPE_SWING_1; + setRopeSwingAnm(1.0f, 1.0f); + return true; + } + } + return false; +} + +bool dAcPy_c::checkStartSwingDown() { + int baseAngle = m_900; + int absAngle = abs(baseAngle); + if (absAngle > 128 && absAngle < abs(m_902)) { + if (sc_DirSpeed[mDirection] * baseAngle <= 0.0f) { + int dir; + bool ok = mKey.buttonWalk(&dir) && dir != mDirection; + if (ok) { + setRopeSwingAnm(1.0f, 64.0f); + m_90c = ROPE_SWING_7; + return true; + } + m_90c = ROPE_SWING_0; + } + } + return false; +} + +void dAcPy_c::updateRopeSwingAnm() { + if (updateRopeAngle()) { + switch (m_90c) { + case ROPE_SWING_0: + checkStartSwingUp(); + break; + case ROPE_SWING_1: + if (mPyMdlMng.mpMdl->mAnm.checkFrame(32.0f)) { + mPyMdlMng.mpMdl->setRate(0.0f); + m_90c = ROPE_SWING_2; + } + // fallthrough + case ROPE_SWING_2: + if (m_900 * m_902 <= 0) { + setRopeSwingAnm(1.0f, 32.0f); + m_90c = ROPE_SWING_3; + } + break; + case ROPE_SWING_3: + if (mPyMdlMng.mpMdl->mAnm.checkFrame(64.0f)) { + mPyMdlMng.mpMdl->setRate(0.0f); + m_90c = ROPE_SWING_4; + } + // fallthrough + case ROPE_SWING_4: + checkStartSwingDown(); + break; + case ROPE_SWING_7: + if (mPyMdlMng.mpMdl->mAnm.checkFrame(96.0f)) { + mPyMdlMng.mpMdl->setRate(0.0f); + m_90c = ROPE_SWING_8; + } + // fallthrough + case ROPE_SWING_8: + if (m_900 * m_902 <= 0) { + setRopeSwingAnm(1.0f, 96.0f); + m_90c = ROPE_SWING_10; + } + break; + case ROPE_SWING_10: + if (mPyMdlMng.isAnmStop()) { + m_90c = ROPE_SWING_0; + } + checkStartSwingUp(); + break; + case ROPE_SWING_5: + if (mPyMdlMng.mpMdl->mAnm.checkFrame(86.0f)) { + mPyMdlMng.mpMdl->setRate(0.0f); + m_90c = ROPE_SWING_6; + } + // fallthrough + case ROPE_SWING_6: + if (m_900 * m_902 <= 0) { + setRopeSwingAnm(-0.5f, 86.0f); + m_90c = ROPE_SWING_9; + } + break; + case ROPE_SWING_9: + if (mPyMdlMng.mpMdl->mAnm.checkFrame(64.0f)) { + m_90c = ROPE_SWING_0; + } + checkStartSwingUp(); + break; + } + } else { + m_90c = ROPE_SWING_0; + } + if (m_90c == ROPE_SWING_0) { + mPyMdlMng.setAnm(PLAYER_ANIM_TREE_WAIT, 10.0f, 0.0f); + } +} + +void dAcPy_c::TarzanRopeActionStart() { + if (mPyMdlMng.isAnmStop()) { + setTarzanRopeActionWait(); + } +} + +void dAcPy_c::setTarzanRopeActionWait() { + mSubstate = 1; + m_918 = 0; + updateRopeAngle(); + m_906 = m_904; + m_902 = m_900; + m_90c = ROPE_SWING_0; + m_908 = 0; +} + +void dAcPy_c::TarzanRopeActionWait() { + turnBesideAngle(); + updateRopeSwingAnm(); + if (!(mPc.m_2a & 4) && mKey.buttonDown()) { + setTarzanRopeActionDown(); + } else if (!(mPc.m_2a & 2) && mKey.buttonUp()) { + setTarzanRopeActionUp(); + } +} + +void dAcPy_c::setTarzanRopeActionUp() { + mSubstate = 2; + mPyMdlMng.setAnm(PLAYER_ANIM_TREE_CLIMB); +} + +void dAcPy_c::TarzanRopeActionUp() { + turnBesideAngle(); + if (m_914 == 0) { + setIvyHangEffect(); + } + if (mPyMdlMng.mpMdl->mAnm.checkFrame(1.0f)) { + setClimbRopeSE(); + } + if (mKey.buttonDush()) { + mPyMdlMng.mpMdl->setRate(1.875f); + m_918 = 1.5f; + } else { + mPyMdlMng.mpMdl->setRate(1.5f); + m_918 = 1.0f; + } + if (!(mPc.m_2a & 4) && mKey.buttonDown()) { + setTarzanRopeActionDown(); + } else if (!mKey.buttonUp()) { + setTarzanRopeActionWait(); + } +} + +void dAcPy_c::setTarzanRopeActionDown() { + mSubstate = 3; + mPyMdlMng.setAnm(PLAYER_ANIM_TREE_POSE); +} + +void dAcPy_c::TarzanRopeActionDown() { + turnBesideAngle(); + if (m_914 == 0) { + setIvyHangEffect(); + } + setSlideRopeSE(); + m_918 = -2.0f; + if (!(mPc.m_2a & 2) && mKey.buttonUp()) { + setTarzanRopeActionUp(); + } else if (!mKey.buttonDown()) { + setTarzanRopeActionWait(); + } +} + +void dAcPy_c::setTarzanRopeActionHasigoMove() { + mSubstate = 4; +} + +void dAcPy_c::TarzanRopeActionHasigoMove() { + if (mKey.buttonUp() && (mPc.m_2a & 2)) { + setTarzanRopeActionHasigoHangUp(); + return; + } + float f1 = mKey.buttonDush() ? 1.5f : 1.0f; + float f2 = mKey.buttonDush() ? 1.875f : 1.5f; + if (mKey.buttonUp() && !(mPc.m_2a & 2)) { + m_918 = f1; + mPyMdlMng.setAnm(PLAYER_ANIM_NET_WALK1, f2, 0.0f, 0.0f); + setRopeHasigoSE(); + } else if (mKey.buttonDown() && !(mPc.m_2a & 4)) { + m_918 = -f1; + mPyMdlMng.setAnm(PLAYER_ANIM_NET_WALK1, -f2, 0.0f, 0.0f); + setRopeHasigoSE(); + } else { + m_918 = 0.0f; + mPyMdlMng.setAnm(PLAYER_ANIM_NET_WAIT); + } +} + +void dAcPy_c::TarzanRopeActionHasigoHangDown() { + if (!mPyMdlMng.isAnmStop()) { + return; + } + mPyMdlMng.setAnm(PLAYER_ANIM_NET_WAIT, 0.0f, 0.0f); + mPos.y -= getHangBcOffsetY(); + m_60 = 10; + onStatus(STATUS_36); + setTarzanRopeActionHasigoMove(); + if (!mPc.check(1)) { + mTarzanRopeCooldown = 30; + mPyMdlMng.setAnm(PLAYER_ANIM_JUMP2, 0.0f, 0.0f); + changeState(StateID_Fall, true); + } +} + +void dAcPy_c::setTarzanRopeActionHasigoHangUp() { + mVec3_c pos = mPos; + pos.y += getHangBcOffsetY() + 8.0f; + float h; + if (dBc_c::checkGround(&pos, &h, mLayer, 1, -1)) { + if (mPos.y < h) { + mPos.y = h; + } + } + m_60 = 10; + mSubstate = 6; + m_91c = 0; + mPyMdlMng.setAnmOnlyRate(PLAYER_ANIM_HANG_WAIT, 0.0f, 0.0f); + startPlayerVoice(VOICE_CLIFF_UP, 0); + offStatus(STATUS_36); + releasePoleCheck(); +} + +void dAcPy_c::TarzanRopeActionHasigoHangUp() { + switch (m_91c) { + case 0: + mPyMdlMng.setAnm(PLAYER_ANIM_HANG_UP); + m_91c = 1; + break; + case 1: + if (mPyMdlMng.isAnmStop()) { + mPyMdlMng.setAnmOnlyRate(PLAYER_ANIM_WALL_WAIT, 0.0f, 0.0f); + mAngle.y = 0; + m_91c = 2; + } + break; + case 2: + changeState(StateID_Walk, BLEND_DEFAULT); + break; + } +} + +void dAcPy_c::executeState_TarzanRope() { + typedef void (dAcPy_c::*TarzanRopeActionProc_t)(); + static TarzanRopeActionProc_t l_TarzanRopeActionProc[] = { + &dAcPy_c::TarzanRopeActionStart, + &dAcPy_c::TarzanRopeActionWait, + &dAcPy_c::TarzanRopeActionUp, + &dAcPy_c::TarzanRopeActionDown, + &dAcPy_c::TarzanRopeActionHasigoMove, + &dAcPy_c::TarzanRopeActionHasigoHangDown, + &dAcPy_c::TarzanRopeActionHasigoHangUp + }; + if (!isStatus(STATUS_36)) { + (this->*l_TarzanRopeActionProc[mSubstate])(); + } else if (isNowBgCross(BgCross1_e(BGC_SIDE_LIMIT_L | BGC_SIDE_LIMIT_R)) || mPc.mpCtr == nullptr) { + changeState(StateID_Fall, false); + } else { + s16 ang = mPc.getAngle(); + if (m_914 == 0 || m_914 == 1) { + if (mDirection == DIR_LR_L) { + ang = -mPc.getAngle(); + } + mAngle.x = ang; + float f = -2.5f; + if (mPowerup == POWERUP_NONE) { + f = -1.5f; + } + m_1594 = f * mAng(ang).cos() * mAng(mAngle.y).sin(); + m_1598 = f * mAng(ang).sin(); + } else { + mAngle.z = -ang; + } + if (!setTarzanRopeJump()) { + (this->*l_TarzanRopeActionProc[mSubstate])(); + mPc.move(getCcRevOffsY() + m_918); + if (mPc.m_2a & 1) { + changeState(StateID_Fall, false); + } + } + } +} + +void dAcPy_c::startQuakeAction(QuakeMode_e mode) { + setQuakeActionLocal(0, mode); + mSubstateValue = 1; +} + +void dAcPy_c::setQuakeAction(int i, QuakeMode_e mode) { + setQuakeActionLocal(i, mode); + mSubstateValue = 0; +} + +void dAcPy_c::setQuakeActionLocal(int i, QuakeMode_e mode) { + if (!isDemo() && isNowBgCross(BGC_FOOT) && !isState(StateID_Quake)) { + changeState(StateID_Quake, (void *) mode); + mSubstateTimer = i; + } +} + +void dAcPy_c::endQuakeAction() { + if (isState(StateID_Quake)) { + changeState(StateID_Walk, BLEND_DEFAULT); + } +} + +void dAcPy_c::initializeState_Quake() { + mSpeedF = 0.0f; + mMaxSpeedF = 0.0f; + mAccelY = 0.0f; + mSpeed.y = 0.0f; + mAngle.y = 0.0f; + mPyMdlMng.setAnm(PLAYER_ANIM_E_SHOCK); + onStatus(STATUS_QUAKE); + mKey.onStatus(dAcPyKey_c::STATUS_NO_INPUT); + startPlayerVoice(VOICE_QUAKE, 0); + startQuakeShock(dQuake_c::TYPE_6); + m_1040 = 8; + mSubstate = (int) mStateArg; +} + +void dAcPy_c::finalizeState_Quake() { + mKey.offStatus(dAcPyKey_c::STATUS_NO_INPUT); + mAngle.y = getMukiAngle(mDirection); + offStatus(STATUS_QUAKE); +} + +void dAcPy_c::executeState_Quake() { + if (m_1040 != 0) { + m_1040--; + } + if (m_1040 == 0) { + m_1040 = 5; + startQuakeShock(dQuake_c::TYPE_8); + } + setQuakeNumbEffect(); + if (mSubstateValue == 0 && mSubstateTimer == 0) { + changeState(StateID_Walk, BLEND_DEFAULT); + } +} + +void dAcPy_c::setQuakeNumbEffect() { + mVec3_c center = getCenterPos(); + static const float sc_QuakeNumbScale[] = { 0.6f, 0.8f, 1.0f }; + u8 tallType = getTallType(-1); + float scale = sc_QuakeNumbScale[tallType]; + mVec3_c size(scale, scale, scale); + static const char *sc_QuakeEffectID[] = { + "Wm_mr_brosquake", + "Wm_mr_quakewait" + }; + dEf::createPlayerEffect(mPlayerNo, &mSmokeEffect, sc_QuakeEffectID[mSubstate], 0, ¢er, nullptr, &size); +} + +void dAcPy_c::initializeState_ElecShock() { + initElecShock(); + mSpeedF = 0.0f; + mMaxSpeedF = 0.0f; + mAccelY = 0.0f; + mSpeed.y = 0.0f; + mAngle.y = 0; + onStatus(STATUS_STUNNED); + mKey.onStatus(dAcPyKey_c::STATUS_NO_INPUT); +} + +void dAcPy_c::finalizeState_ElecShock() { + offStatus(STATUS_STUNNED); + mKey.offStatus(dAcPyKey_c::STATUS_NO_INPUT); +} + +void dAcPy_c::executeState_ElecShock() { + if (!executeElecShock()) { + changeState(StateID_Walk, BLEND_DEFAULT); + mPyMdlMng.setAnm(PLAYER_ANIM_E_SHOCK); + setDamage2(nullptr, DAMAGE_BG); + } +} + +void dAcPy_c::initElecShock() { + startPlayerVoice(VOICE_DAMAGE_ELEC, 0); + startSound(SE_PLY_TOUCH_BIRI, false); + mPyMdlMng.setAnm(PLAYER_ANIM_E_SHOCK); + mSubstateTimer = 60; +} + +bool dAcPy_c::executeElecShock() { + setElecEffect(); + return mSubstateTimer != 0; +} + +void dAcPy_c::setElecEffect() { + mVec3_c efPos; + mPyMdlMng.mpMdl->getJointPos(&efPos, 1); + float s = mPyMdlMng.getSomeScale(); + mVec3_c efScale(s, s, s); + int shockType = 0; + if (mPowerup == POWERUP_MINI_MUSHROOM || mPowerup == POWERUP_NONE) { + shockType = 1; + } + static const char *sc_elecEffectID[] = { + "Wm_mr_electricshock", + "Wm_mr_electricshock_s" + }; + dEf::createPlayerEffect(mPlayerNo, &mSmokeEffect, sc_elecEffectID[shockType], 0, &efPos, nullptr, &efScale); +} + +bool dAcPy_c::setFlyDamageAction(int action, dActor_c *actor) { + if (isState(StateID_FlyDamage)) { + return false; + } + bool changeParam = false; + if (actor != nullptr) { + if (action == 4) { + mPos.y += 12.0f; + mPos.x = mPos.x - 4.0f * sc_DirSpeed[mDirection]; + } else { + switch ((u32) actor->mKind) { + case STAGE_ACTOR_PLAYER: + case STAGE_ACTOR_ENEMY: + if (actor->mProfName == fProfile::EN_SLIP_PENGUIN2) { + bool dir = 0; + if (actor->mSpeed.x < 0.0f) { + dir = 1; + } + if (dir == mDirection && (actor->mLastPos.x - mLastPos.x) * sc_DirSpeed[mDirection] < 0.0f) { + changeParam = true; + } + } else if ((actor->mLastPos.x - mLastPos.x) * sc_DirSpeed[mDirection] < 0.0f) { + changeParam = true; + } + break; + default: + if (mDirection == actor->mDirection) { + changeParam = true; + } + } + } + } + int isAction6 = 0; + u32 finalChangeParam = 0; + if (action == 2) { + finalChangeParam = 2; + } else if (action == 3 || action == 4) { + finalChangeParam = 4; + } else if (action == 5) { + finalChangeParam = 0; + } else if (action == 6) { + finalChangeParam = 0; + isAction6 = 1; + } + finalChangeParam = (finalChangeParam + changeParam) & 0xFF; + if (isAction6 == 1) { + finalChangeParam |= 0x100; + } + changeState(StateID_FlyDamage, (void *) finalChangeParam); + return true; +} + +void dAcPy_c::initializeState_FlyDamage() { + static const u8 sc_DamageAnmID[] = { + PLAYER_ANIM_DAM_F, PLAYER_ANIM_DAM_B, + PLAYER_ANIM_DOW_F, PLAYER_ANIM_DOW_B, + PLAYER_ANIM_DOW_F, PLAYER_ANIM_DOW_B, + PLAYER_ANIM_DOW_F + }; + m_103c = ((int) mStateArg) & 0xFF; + u32 crash = ((int) mStateArg) & 0x100; + mPyMdlMng.setAnm(sc_DamageAnmID[m_103c], 0.0f, 0.0f); + if (crash == 0) { + startPlayerVoice(VOICE_HIP_ATTACKED, 0); + if (m_103c == 0 || m_103c == 1) { + startSound(SE_PLY_CRASH_S, false); + } else { + startSound(SE_PLY_CRASH_L, false); + } + } + if (m_103c == 0 || m_103c == 1) { + float speed1 = sc_DirSpeed[(m_103c ^ 1) & 1]; + float speed2 = getDirSpeed(); + speed2 *= sGlobalData_c::mData.f8; + mSpeedF = speed1 * speed2; + mSpeed.y = 0.0f; + mSubstate = 5; + } else { + mKey.onStatus(dAcPyKey_c::STATUS_DISABLE_LR); + float speed = sc_DirSpeed[mDirection] * sc_DirSpeed[(m_103c ^ 1) & 1]; + mSubstate = 0; + if (mPowerup == POWERUP_MINI_MUSHROOM) { + mPyMdlMng.setAnm(PLAYER_ANIM_STAR_ROLL_DUPLICATE); + mSubstateTimer = 30; + if (speed < 0.0f) { + mDirection = DIR_LR_L; + } else { + mDirection = DIR_LR_R; + } + } + switch (m_103c) { + case 2: + case 3: + mSpeedF = speed * sGlobalData_c::mData.f5; + mSpeed.y = sGlobalData_c::mData.f4; + break; + case 4: + case 5: + if (isNowBgCross(BGC_FOOT)) { + mSpeedF = speed * sGlobalData_c::mData.f7; + } else { + mSpeedF = speed; + } + mSpeed.y = sGlobalData_c::mData.f6; + break; + case 6: + mSpeedF = speed; + mSpeed.y = 2.0f; + break; + } + } + mMaxSpeedF = mSpeedF; + mAccelY = getGravityData()[0]; + mMaxFallSpeed = sc_MaxFallSpeed; + mAngle.y = getMukiAngle(mDirection); +} + +void dAcPy_c::finalizeState_FlyDamage() { + offStatus(STATUS_9B); + offStatus(STATUS_9C); + offStatus(STATUS_9D); + offStatus(STATUS_A1); + mKey.offStatus(dAcPyKey_c::STATUS_DISABLE_LR); + offStatus(STATUS_PENGUIN_RECOIL); +} + +void dAcPy_c::executeState_FlyDamage() { + int dir; + mAccelF = 0.08f; + if (mSubstate == 5 && mKey.buttonWalk(&dir) && mSpeedF * sc_DirSpeed[dir] < 0.0f) { + mAccelF = 0.15f; + } + + icePowerChange(0); + mMaxSpeedF = mSpeedF; + if (isNowBgCross(BGC_FOOT)) { + mMaxSpeedF = 0.0f; + } + static const u8 sc_damageStopFrame[] = { 0, 0, 9, 10, 9, 10, 9 }; + switch (mSubstate) { + case 0: + onStatus(STATUS_A1); + if (mPowerup != POWERUP_MINI_MUSHROOM) { + mSubstate = 2; + } else { + mSubstate = 1; + } + break; + case 1: + if (mSubstateTimer == 0 || mPowerup != POWERUP_MINI_MUSHROOM) { + changeState(StateID_Fall, false); + } + break; + case 2: + if (mPyMdlMng.mpMdl->mAnm.getFrame() >= sc_damageStopFrame[m_103c]) { + mPyMdlMng.mpMdl->setRate(0.0f); + mSubstate = 3; + mSubstateValue = 10; + } + break; + case 3: + if (isNowBgCross(BGC_FOOT)) { + if (mSubstateValue != 0) { + mSubstateValue--; + } + if (mSubstateValue == 0) { + onStatus(STATUS_9B); + onStatus(STATUS_9C); + onStatus(STATUS_9D); + if (checkJumpTrigger()) { + break; + } + } + if (std::fabs(mSpeedF) < 0.5f) { + mPyMdlMng.mpMdl->setRate(1.0f); + mSubstate = 4; + } + } + break; + case 4: + if (!isNowBgCross(BGC_FOOT)) { + changeState(StateID_Fall, false); + } else if (!checkJumpTrigger() && mPyMdlMng.isAnmStop()) { + changeState(StateID_Walk, BLEND_DEFAULT); + } + break; + case 5: + if (!isNowBgCross(BGC_FOOT)) { + if (mPyMdlMng.mpMdl->mAnm.getFrame() > 17.0f) { + mPyMdlMng.setAnm(PLAYER_ANIM_JUMP2, 10.0f, 0.0f); + changeState(StateID_Fall, false); + } + } else if (mPyMdlMng.mpMdl->mAnm.getFrame() > 17.0f) { + if (checkJumpTrigger()) { + break; + } + if (mKey.buttonWalk(nullptr)) { + changeState(StateID_Walk, BLEND_DEFAULT); + break; + } + } + if (mPyMdlMng.isAnmStop()) { + changeState(StateID_Walk, BLEND_DEFAULT); + } + break; + } +} + +void dAcPy_c::setBreakBalloonJump(u8 playerNo, short angle) { + offStatus(STATUS_DISABLE_STATE_CHANGE); + startPlayerVoice(VOICE_HUKKATSU, 0); + startSound(SE_PLY_BALLOON_BRAKE, false); + dQuake_c::m_instance->shockMotor(mPlayerNo, dQuake_c::TYPE_4, 0, false); + mJumpDaiFallTimer = 30; + mTimer_ce8 = 30; + mCcRevDisabledTimer = 30; + if (isNowBgCross(BGC_WATER_SHALLOW)) { + changeState(StateID_Swim, SWIM_ARG_INITIAL); + float cos = mAng(angle).cos(); + float sin = mAng(angle).sin(); + setSwimSpeed(cos * 2.0f, sin * 2.0f); + } else { + float sin = mAng(angle).sin() * 4.0f; + float cos = mAng(angle).cos() * sc_JumpSpeed; + if (cos < 0.0f) { + cos = 0.0f; + } + setJump(cos, sin, true, 1, 0); + } +} + +void dAcPy_c::setDrawBalloonInPlayer(mVec3_c &pos) { + if (!isStatus(STATUS_53)) { + return; + } + onStatus(STATUS_54); + static const float scBalloonOffsetY[] = { + 0.0f, -4.0f, -4.0f, 4.0f, -6.0f, -2.0f, -4.0f + }; + pos.y += scBalloonOffsetY[mPowerup]; + mPos = mLastPos = pos; +} + +bool dAcPy_c::isNotBalloonCourse() { + return daPyMng_c::mRest[daPyMng_c::mPlayerType[mPlayerNo]] <= 0; +} + +void dAcPy_c::initializeState_Balloon() { + clearJumpActionInfo(1); + releaseCarryActor(); + endStar(); + mActorProperties |= BIT_FLAG(6); + mPyMdlMng.setAnm(PLAYER_ANIM_BALLOON_WAIT); + onStatus(STATUS_7E); + onStatus(STATUS_7A); + onStatus(STATUS_AA); + onStatus(STATUS_INVISIBLE); + onStatus(STATUS_OUT_OF_PLAY); + onStatus(STATUS_PROPEL_NO_ROLL); + onStatus(STATUS_DISABLE_STATE_CHANGE); + mAccelY = 0.0f; + mMaxFallSpeed = sc_MaxFallSpeed; + mAccelF = 0.0f; + mSpeed.y = 0.0f; + mSpeedF = 0.0f; + mSubstate = (int) mStateArg; + switch (mSubstate) { + case 0: + mSubstateTimer = 150; + if (isNotBalloonCourse()) { + mSubstate = 4; + } + break; + case 3: + startSound(SE_PLY_BALLOON_SELF, false); + break; + } + m_12b8 = 0; + daPyMng_c::decNum(mPlayerNo); + if (daPyMng_c::mNum == 0) { + onStatus(STATUS_57); + mAllBalloonFadeTimer = 210; + daPyMng_c::mAllBalloon = true; + } + if (mPlayerType == PLAYER_MARIO && mPyMdlMng.mpMdl->m_151 == 0) { + ((dMarioMdl_c *) mPyMdlMng.mpMdl)->fn_800cab00(0); + } + if (mPowerup != POWERUP_NONE && mPowerup != POWERUP_MINI_MUSHROOM) { + mAmiRelated2 = 0.9f; + } + setScrollMode(1); + setZPosition(8000.0f); + mPlayerOrchestra.init(mPlayerNo); +} + +void dAcPy_c::finalizeState_Balloon() { + mActorProperties &= ~BIT_FLAG(6); + offStatus(STATUS_53); + offStatus(STATUS_54); + offStatus(STATUS_95); + offStatus(STATUS_7E); + offStatus(STATUS_7A); + offStatus(STATUS_AA); + offStatus(STATUS_INVISIBLE); + offStatus(STATUS_OUT_OF_PLAY); + offStatus(STATUS_PROPEL_NO_ROLL); + mCc.mCcData.mStatus &= ~CC_STATUS_NO_PASS_INFO; + daPyMng_c::addNum(mPlayerNo); + mAmiRelated2 = 1.0f; + setScrollMode(0); + mDamageInvulnTimer = 127; + offZPosSetNone(); + daPyMng_c::mPauseEnableInfo |= 1 << mPlayerNo; +} + +void dAcPy_c::executeState_Balloon() { + if (isStatus(STATUS_57) && mFader_c::mFader->isStatus(mFaderBase_c::HIDDEN)) { + SndSceneMgr::sInstance->moveMissFin(); + } + sLib::calcTimer(&m_12b8); + if (mAllBalloonFadeTimer != 0) { + mAllBalloonFadeTimer--; + if (mAllBalloonFadeTimer == 0) { + checkAllBalloonFade(); + } + } + mAngle.y = 0; + switch (mSubstate) { + case 2: + if (mFader_c::mFader->isStatus(mFaderBase_c::HIDDEN)) { + mSubstate = 0; + mSubstateTimer = dGameCom::rndInt(5) * 30; + } + break; + case 0: + if (mSubstateTimer != 0) { + break; + } + if (!isNotBalloonCourse()) { + onStatus(STATUS_53); + onStatus(STATUS_95); + m_12b8 = 600; + offStatus(STATUS_OUT_OF_PLAY); + mSubstate = 1; + dEnemyMng_c::m_instance->createRevivalBallon(mPos, 0, mPlayerNo); + } else { + mSubstate = 4; + } + break; + case 3: { + onStatus(STATUS_53); + onStatus(STATUS_95); + m_12b8 = 180; + offStatus(STATUS_OUT_OF_PLAY); + mSubstate = 1; + mVec3_c pos(mPos.x, mPos.y + 4.0f, mPos.z); + dEnemyMng_c::m_instance->createRevivalBallon(mPos, 2, mPlayerNo); + break; + } + case 1: + onStatus(STATUS_INVISIBLE); + if (isStatus(STATUS_54)) { + offStatus(STATUS_INVISIBLE); + offStatus(STATUS_54); + } + break; + case 4: + mPlayerOrchestra.update(); + daPyMng_c::mPauseEnableInfo &= ~(1 << mPlayerNo); + if (isNotBalloonCourse()) { + break; + } + startPlayerVoice(VOICE_CONTINUE_COURSE, 0); + mSubstate = 0; + mSubstateTimer = 60; + daPyMng_c::mPauseEnableInfo |= 1 << mPlayerNo; + } +} + +void dAcPy_c::setBalloonHelpVoice() { + if (isStatus(STATUS_53) && mSubstate == 1 && !isStatus(STATUS_DISPLAY_OUT_DEAD) && mBalloonHelpVoiceCooldown == 0) { + startPlayerVoice(VOICE_BALLOON_HELP_2, 0); + mBalloonHelpVoiceCooldown = 120; + } +} + +bool dAcPy_c::setBalloonInNextgoto() { + if (daPyMng_c::isEntryNum1() || isStatus(STATUS_53)) { + return false; + } + changeDemoState(StateID_DemoNone, true); + changeState(StateID_Balloon, (void *) 2); + return true; +} + +bool dAcPy_c::setBalloonInDamage() { + if (daPyMng_c::mNum == 0 || daPyMng_c::isEntryNum1() || isStatus(STATUS_53)) { + return false; + } + changeDemoState(StateID_DemoNone, false); + fn_801416c0(POWERUP_NONE); + if (!isState(StateID_Balloon)) { + changeState(StateID_Balloon, 0); + } + return true; +} + +bool dAcPy_c::setBalloonButtonA() { + if (!mKey.triggerA()) { + return false; + } + if (dNext_c::m_instance->m_18) { + return false; + } + if (dInfo_c::mGameFlag & dInfo_c::GAME_FLAG_IS_COIN_COURSE) { + return false; + } + if (daPyMng_c::isEntryNum1()) { + return false; + } + if ( + isDemoAll() || + isStatus(STATUS_CA) || + isStatus(STATUS_56) || + isStatus(STATUS_OUT_OF_PLAY) || + isStatus(STATUS_STUNNED) || + isStatus(STATUS_50) || + isStatus(STATUS_QUAKE) || + isStatus(STATUS_53) || + isNotBalloonCourse() || + isStatus(STATUS_ENEMY_STAGE_CLEAR) + ) { + return false; + } + if (dEnemyMng_c::m_instance->m_15c == 1 || dEnemyMng_c::m_instance->m_15c == 2) { + return false; + } + if (dScStage_c::m_miniGame) { + return false; + } + int level = dScStage_c::m_instance->mCurrCourse; + if (level == STAGE_TITLE || level == STAGE_PEACH_CASTLE || level == STAGE_STAFFROLL) { + return false; + } + if (getFollowMameKuribo()) { + startSound(SE_EMY_MAMEKURIBO_CLINGING_NOW, false); + return false; + } + changeDemoState(StateID_DemoNone, false); + if (!isState(StateID_Balloon)) { + changeState(StateID_Balloon, (void *) 3); + } + return true; +} + +bool dAcPy_c::checkAllBalloonFade() { + if (!isStatus(STATUS_ALL_DOWN_FADE)) { + onStatus(STATUS_ALL_DOWN_FADE); + dScStage_c::setNextScene(3, 0, dScStage_c::EXIT_1, dFader_c::FADER_BOWSER); + return true; + } + return false; +} + +bool dAcPy_c::setBalloonInDispOutByYoshi(int i) { + return setBalloonInDispOutBase(i, 1); +} + +bool dAcPy_c::setBalloonInDispOut(int i) { + return setBalloonInDispOutBase(i, 0); +} + +bool dAcPy_c::setBalloonInDispOutBase(int i, int j) { + if (!isDispOutCheckOn()) { + return false; + } + if (i == 2 || i == 0) { + if (isDemoAll() && !isStatus(STATUS_5A)) { + return false; + } + if (isStatus(STATUS_B8)) { + return false; + } + } else { + if (isItemKinopio() && !dBg_c::m_bg_p->mAutoscrolls[0].mActive) { + return false; + } + } + if (getCarryPlayer() != nullptr) { + getCarryPlayer()->setBalloonInDispOut(i); + } + if (j == 1) { + onStatus(STATUS_B8); + } + if (isStatus(STATUS_DISPLAY_OUT_DEAD)) { + setFallDownDemo(); + } else { + setPressBgDamage(11, 0); + } + if (i == 2 || i == 0) { + startPlayerVoice(VOICE_SCROLL_OUT, 0); + dQuake_c::m_instance->shockMotor(mPlayerNo, dQuake_c::TYPE_4, 0, false); + } + return true; +} + +void dAcPy_c::setShakeIce(float f) { + if (isStatus(STATUS_07)) { + m_1594 = f; + } +} + +mVec3_c dAcPy_c::getIceDrawPos() { + return mVec3_c( + mPos.x + m_1594, + mPos.y + m_1598 + m_159c, + mPos.z + ); +} + +void dAcPy_c::fn_801395a0() { + offStatus(STATUS_DISABLE_STATE_CHANGE); + setRideOffPlayerJump(sc_JumpSpeed, 0.0f); +} + +void dAcPy_c::initializeState_IceDamage() { + mSpeedF = 0.0f; + mMaxSpeedF = 0.0f; + mAccelY = 0.0f; + mSpeed.y = 0.0f; + mSubstateTimer = 300; + startPlayerVoice(VOICE_DAMAGE_FREEZE, 0); + onStatus(STATUS_7E); + onStatus(STATUS_7A); + onStatus(STATUS_STUNNED); + onStatus(STATUS_07); + onStatus(STATUS_NO_ANIM); + onStatus(STATUS_DISABLE_STATE_CHANGE); + dActor_c *ice = dActor_c::construct(fProfile::PLAYER_ICE, this, 0,& mPos, nullptr, 0); + mIceActorID = ice->mUniqueID; + dQuake_c::m_instance->shockMotor(mPlayerNo, dQuake_c::TYPE_4, 0, false); + mPyMdlMng.setAnm(PLAYER_ANIM_JUMP, 0.0f, 0.0f, 0.0f); + mPyMdlMng.mpMdl->setFrame(0.0f); +} + +void dAcPy_c::finalizeState_IceDamage() { + m_1594 = 0.0f; + offStatus(STATUS_7E); + offStatus(STATUS_7A); + offStatus(STATUS_STUNNED); + offStatus(STATUS_07); + offStatus(STATUS_NO_ANIM); + offStatus(STATUS_DISABLE_STATE_CHANGE); + mDamageInvulnTimer = 127; +} + +void dAcPy_c::executeState_IceDamage() { + daPlyIce_c *ice = (daPlyIce_c *) fManager_c::searchBaseByID(mIceActorID); + if (ice == nullptr) { + offStatus(STATUS_DISABLE_STATE_CHANGE); + changeState(StateID_Walk, BLEND_NONE); + } else if (isNowBgCross(BgCross1_e(BGC_SIDE_LIMIT_L | BGC_SIDE_LIMIT_R))) { + ice->setRevivalBreakIce(); + } +} + +bool dAcPy_c::setRideOffPlayerJump(float a, float b) { + if (mKey.triggerShakeJump()) { + mVec3_c pos(mPos.x, mPos.y + 1.0f, mPos.z); + float height; + if (dBc_c::checkTenjou(&pos, &height, mLayer, 1)) { + float tmp = getStandHeadBgPointY() + 1.0f; + if (mPos.y > height - tmp) { + mPos.y = height - tmp; + mLastPos = mPos; + a = 0.0f; + } + } + calcDispSideLimit(); + return fn_80146e40(a, b, false); + } + return false; +} + +bool dAcPy_c::setRideOffYoshiJump(daPlBase_c *yoshi) { + if (!((daYoshi_c *) yoshi)->checkRideOffAble()) { + return false; + } + + if (mKey.triggerShakeJump()) { + if (isDemo() || isStatus(STATUS_OUT_OF_PLAY)) { + return false; + } + if (!yoshi->isNowBgCross(BGC_FOOT)) { + m_1058 = 10; + setJump(sc_JumpSpeed + 0.1f, yoshi->mSpeedF, true, 1, 1); + startPlayerVoice(VOICE_YOSHI_JUMP, 0); + } else { + float speed = 0.0f; + if (std::fabs(yoshi->mSpeedF) < 1.5f) { + if (yoshi->mDirection == DIR_LR_L) { + speed = 1.0f; + } else { + speed = -1.0f; + } + } + mSpeedF = speed; + mSpeed.y = sc_JumpSpeed - 0.2f; + changeState(StateID_RideOffJump, 0); + mKey.onStatus(dAcPyKey_c::STATUS_FORCE_JUMP); + } + calcDispSideLimit(); + return true; + } + return false; +} + +daYoshi_c *dAcPy_c::getRideYoshi() { + if (isStatus(STATUS_RIDE_YOSHI)) { + return (daYoshi_c *) fManager_c::searchBaseByID(mRideActorID); + } + return nullptr; +} + +void dAcPy_c::setRideOnYoshi(daYoshi_c *yoshi) { + if (mRideActorID != 0) { + return; + } + mRideActorID = yoshi->mUniqueID; + onStatus(STATUS_RIDE_YOSHI); + changeState(StateID_RideYoshi, 0); +} + +void dAcPy_c::initializeState_RideYoshi() { + daPyMng_c::startYoshiBGM(); + mKey.onStatus(dAcPyKey_c::STATUS_DISABLE_LR); + onStatus(STATUS_7A); + onStatus(STATUS_7E); + onStatus(STATUS_93); + onStatus(STATUS_81); + mAccelY = 0.0f; + mSubstateTimer = 10; + m_60 = 10; +} + +void dAcPy_c::finalizeState_RideYoshi() { + mAngle.x = 0; + daYoshi_c *yoshi = (daYoshi_c *) fManager_c::searchBaseByID(mRideActorID); + if (yoshi != nullptr) { + if (mIsBeingDeleted == 1) { + yoshi->onStatus(STATUS_ABOUT_TO_BE_DELETED); + } + yoshi->setRideOffPlayer(); + mTreadCount = yoshi->mTreadCount; + } + mRideActorID = BASE_ID_NULL; + mKey.offStatus(dAcPyKey_c::STATUS_DISABLE_LR); + offStatus(STATUS_RIDE_YOSHI); + offStatus(STATUS_7A); + offStatus(STATUS_7E); + offStatus(STATUS_93); + offStatus(STATUS_81); + mNoInteractTimer = 10; + if (!isStatus(STATUS_C5)) { + daPyMng_c::stopYoshiBGM(); + } + calcDispSideLimit(); +} + +void dAcPy_c::executeState_RideYoshi() { + offStatus(STATUS_DISABLE_STATE_CHANGE); + daYoshi_c *yoshi = getRideYoshi(); + if (yoshi == nullptr) { + changeState(StateID_Jump, nullptr); + return; + } + turnAngle(); + if (yoshi->isStatus(STATUS_B3)) { + onStatus(STATUS_DISABLE_STATE_CHANGE); + return; + } + if (mSubstateTimer == 0 && setRideOffYoshiJump(yoshi)) { + return; + } +} + +void dAcPy_c::initializeState_Cloud() { + daPlBase_c::initializeState_Cloud(); + setScrollMode(6); +} + +void dAcPy_c::finalizeState_Cloud() { + daPlBase_c::finalizeState_Cloud(); + setScrollMode(0); + if (mSubstate == 7) { + releaseCarryActor(); + } else if (mSubstate == 4 && mIsBeingDeleted == 0) { + createFireBall(0); + } +} + +float dAcPy_c::getCloudOffsetY() { + return dPyMdlMng_c::m_hio.getValue(mPlayerType, 2, mPowerup); +} + +void dAcPy_c::setCloudStateMove() { + mPyMdlMng.setAnm(PLAYER_ANIM_WAIT); + mSubstate = 1; +} + +bool dAcPy_c::checkCloudStateCrouch() { + if (!mKey.buttonCrouch()) { + return false; + } + if (isCarry()) { + return false; + } + onStatus(STATUS_51); + mPyMdlMng.setAnm(PLAYER_ANIM_STOOP_START); + mSubstate = 2; + return true; +} + +void dAcPy_c::setCloudStateFireCreate() { + mPyMdlMng.setAnm(PLAYER_ANIM_FIRE_AT); + mPyMdlMng.mpMdl->setFrame(0.0f); + mAngle.y = getMukiAngle(mDirection); + m_12f4 = mDirection; + mSubstate = 4; +} + +void dAcPy_c::executeState_Cloud() { + if (updateCloudMove()) { + return; + } + switch (mSubstate) { + case 0: + case 5: + case 8: + if (mPyMdlMng.isAnmStop()) { + finalizeThrowCommonBase(); + setCloudStateMove(); + } + // fallthrough + case 1: + if (!setRideOffPlayerJump(sc_JumpSpeed - 0.2f, 0.0f)) { + if (checkSetFireBall()) { + setCloudStateFireCreate(); + } else if (checkEnableThrow()) { + initializeThrowCommonBase(); + mSubstate = 7; + } else if (checkCloudStateCrouch()) { + return; + } + } + break; + case 2: + if (mPyMdlMng.isAnmStop()) { + mPyMdlMng.setAnm(PLAYER_ANIM_STOOP); + } + if (!mKey.buttonCrouch()) { + mPyMdlMng.setAnm(PLAYER_ANIM_WAIT, 10.0f, 0.0f); + mSubstateTimer = 10; + offStatus(STATUS_51); + mSubstate = 3; + } + break; + case 3: + if (checkSetFireBall()) { + setCloudStateFireCreate(); + } + if (mSubstateTimer == 0) { + setCloudStateMove(); + } + break; + case 4: + if (mPyMdlMng.mpMdl->mAnm.checkFrame(4.0f)) { + createFireBall(0); + mSubstate = 5; + } + break; + case 7: + if (mPyMdlMng.mpMdl->mAnm.checkFrame(5.0f)) { + mSubstate = 8; + setThrowActor(); + } + break; + } +} + +bool dAcPy_c::checkCarryActor(dAcPy_c *player) { + if (mCarryActorID == player->mUniqueID && player->mRideActorID == mUniqueID) { + return true; + } + return false; +} + +bool dAcPy_c::setDropCarryPlayer() { + dAcPy_c *ridePlayer = getRidePlayer(); + if (ridePlayer == nullptr) { + return false; + } + if (ridePlayer->isNowBgCross(BGC_FOOT) && !ridePlayer->isStatus(STATUS_JUMP)) { + if (ridePlayer->isStatus(STATUS_46)) { + if (ridePlayer->isNowBgCross(BGC_HEAD)) { + setJump(0.0f, ridePlayer->mSpeedF / 2.0f, true, 0, 0); + onStatus(STATUS_JUMP_DAI_COOLDOWN); + return true; + } + mVec3_c pos(ridePlayer->mPos.x, ridePlayer->mPos.y + 4.0f, ridePlayer->mPos.z); + mVec3_c pos2(mPos.x, mPos.y + 4.0f, mPos.z); + if (!dBc_c::checkWall(&pos, &pos2, nullptr, mLayer, mAmiLayer, nullptr)) { + float height; + if (dBc_c::checkTenjou(&pos2, &height, mLayer, mAmiLayer)) { + const sBcPlayerPointData *p = getBgPointData_Powerup(mPowerup, 1); + if (mPos.y + p->mHead.mOffset / 4096.0f + 2.0f > height) { + setJump(0.0f, ridePlayer->mSpeedF / 2.0f, true, 0, 0); + onStatus(STATUS_JUMP_DAI_COOLDOWN); + return true; + } + } + } + } + if (!ridePlayer->isStatus(STATUS_46)) { + if (ridePlayer->isNowBgCross(BGC_12) && !ridePlayer->isNowBgCross(BGC_13)) { + float f; + if (ridePlayer->isNowBgCross(BGC_WALL_TOUCH_R_2)) { + f = -1.0f; + mPos.x -= 3.0f; + } else { + f = 1.0f; + mPos.x += 3.0f; + } + setJump(ridePlayer->mSpeed.y, f, true, 0, 0); + onStatus(STATUS_JUMP_DAI_COOLDOWN); + return true; + } + if (ridePlayer->isNowBgCross(BGC_SLOPE_AND_HEAD)) { + setJump(0.0f, 0.0f, true, 0, 0); + onStatus(STATUS_JUMP_DAI_COOLDOWN); + } + } + } + return false; +} + +void dAcPy_c::initializeState_CarryPlayer() { + onStatus(STATUS_45); + onStatus(STATUS_97); + onStatus(STATUS_7F); + onStatus(STATUS_93); + onStatus(STATUS_JUMP_DAI_COOLDOWN); + onStatus(STATUS_9C); + onStatus(STATUS_81); + mAccelY = 0.0f; + mSpeedF = 0.0f; + mPyMdlMng.setAnm(PLAYER_ANIM_WAIT); + mSubstateTimer = 55; + mSubstate = 0; + if (isItemKinopio()) { + if (daPyMng_c::mKinopioCarryCount < 2) { + daPyMng_c::mKinopioCarryCount++; + } + if (daPyMng_c::mKinopioCarryCount >= 2) { + dGameCom::hideFukidashiForSession(mPlayerNo, 8); + } + } +} + +void dAcPy_c::finalizeState_CarryPlayer() { + mAngle.x = 0; + dAcPy_c *ridePlayer = getRidePlayer(); + if (ridePlayer != nullptr) { + ridePlayer->cancelCarry(this); + } + offStatus(STATUS_45); + offStatus(STATUS_97); + offStatus(STATUS_7F); + offStatus(STATUS_THROW); + offStatus(STATUS_93); + offStatus(STATUS_JUMP_DAI_COOLDOWN); + offStatus(STATUS_51); + offStatus(STATUS_9C); + offStatus(STATUS_81); + offZPosSetNone(); + mNoInteractTimer = 20; + mPyMdlMng.mpMdl->m_17c &= ~BIT_FLAG(7); + mPyMdlMng.setAnm(PLAYER_ANIM_JUMP2, 0.0f, 0.0f); + mRideActorID = BASE_ID_NULL; + mKey.offStatus(dAcPyKey_c::STATUS_DISABLE_LR); + calcDispSideLimit(); +} + +void dAcPy_c::executeState_CarryPlayer() { + dAcPy_c *ridePlayer = getRidePlayer(); + if (ridePlayer == nullptr || fManager_c::searchBaseByID(ridePlayer->mCarryActorID) != this) { + changeState(StateID_Fall, false); + return; + } + setZPositionDirect(ridePlayer->mPos.z); + if (setDropCarryPlayer()) { + return; + } + if (isNowBgCross(BGC_VINE_TOUCH_FULL)) { + mAmiLayer = ridePlayer->mAmiLayer; + } + if (!ridePlayer->isStatus(STATUS_46)) { + if (setRideOffPlayerJump(sc_JumpSpeed - 0.2f, 0.0f)) { + return; + } + } + switch (mSubstate) { + case 4: + case 2: + if (mPyMdlMng.isAnmStop()) { + setCarryPlayerMode_Move(0.0f); + } + // fallthrough + case 0: + if (checkSetFireBall()) { + setCarryPlayerMode_Fire(); + } else if (ridePlayer->isStatus(STATUS_47)) { + setCarryPlayerMode_Crouch(); + } + break; + case 3: + if (!mPyMdlMng.mpMdl->mAnm.checkFrame(dPyMdlBase_c::scFireShootFrame)) { + break; + } + createFireBall(0); + mSubstate = 4; + break; + case 1: + if (mPyMdlMng.isAnmStop()) { + mPyMdlMng.setAnm(PLAYER_ANIM_STOOP); + } + if (ridePlayer->isStatus(STATUS_47)) { + break; + } + setCarryPlayerMode_Move(10.0f); + offStatus(STATUS_51); + break; + } +} + +void dAcPy_c::setCarryPlayerMode_Move(float f) { + mPyMdlMng.mpMdl->m_17c &= ~BIT_FLAG(7); + mPyMdlMng.setAnmOnlyRate(PLAYER_ANIM_WAIT, f, 0.0f); + mSubstate = 0; + dAcPy_c *ridePlayer = getRidePlayer(); + if (ridePlayer != nullptr) { + ridePlayer->mpMdlMng->mpMdl->copyLinkAnm(f); + } +} + +void dAcPy_c::setCarryPlayerMode_Fire() { + mPyMdlMng.mpMdl->m_17c |= BIT_FLAG(7); + mPyMdlMng.setAnmOnlyRate(PLAYER_ANIM_FIRE_AT2, 0.0f, 0.0f); + mPyMdlMng.mpMdl->setFrame(0.0f); + mAngle.y = getMukiAngle(mDirection); + m_12f4 = mDirection; + mSubstate = 3; +} + +void dAcPy_c::setCarryPlayerMode_Crouch() { + mPyMdlMng.mpMdl->m_17c |= BIT_FLAG(7); + mPyMdlMng.setAnm(PLAYER_ANIM_STOOP_START, 3.0f, 0.0f, 0.0f); + mSubstate = 1; + onStatus(STATUS_51); +} + +void dAcPy_c::initRideSpinMove() { + if (!isStatus(STATUS_51)) { + onStatus(STATUS_SPIN); + } +} + +void dAcPy_c::endRideSpinMove() { + offStatus(STATUS_SPIN); +} + +dAcPy_c *dAcPy_c::getRidePlayer() { + if (isStatus(STATUS_45)) { + return (dAcPy_c *) fManager_c::searchBaseByID(mRideActorID); + } + return nullptr; +} + +void dAcPy_c::setYoshiBackPos() { + daYoshi_c *yoshi = getRideYoshi(); + if (yoshi == nullptr) { + return; + } + + mMtx_c mtx; + mVec3_c pos; + yoshi->getModel()->getJointMtx(&mtx, 8); + mtx.concat(mMtx_c::createTrans(0.0f, -5.0f, 0.0f)); + mtx.multVecZero(pos); + + mPos.x = yoshi->mPos.x; + mPos.y = pos.y - 8.0f; + mDirection = yoshi->mDirection; +} + +void dAcPy_c::setPlayerHandPos() { + dAcPy_c *ridePlayer = getRidePlayer(); + if (ridePlayer == nullptr) { + return; + } + + mVec3_c liftPos = ridePlayer->getLiftUpPos(); + liftPos.z = mPos.z; + mPos = mLastPos = liftPos; + if (isStatus(STATUS_97)) { + mDirection = ridePlayer->mDirection; + int newAng = ridePlayer->mAngle.y.mAngle + ridePlayer->getMissSpinAngle(); + mAngle.y = newAng; + } +} + +void dAcPy_c::setEatTongue(dActor_c *eatingActor) { + changeState(StateID_PlayerEat, 0); +} + +void dAcPy_c::setEatTongueOff(dActor_c *eatingActor) { + changeState(StateID_Fall, false); +} + +void dAcPy_c::setEatMouth(dActor_c *eatingActor) { + daYoshi_c *yoshi = (daYoshi_c *) eatingActor; + if (isState(StateID_PlayerEat)) { + onStatus(STATUS_INVISIBLE); + onStatus(STATUS_C9); + yoshi->setVirusStar(this); + } +} + +bool dAcPy_c::setEatSpitOut(dActor_c *eatingActor) { + daYoshi_c *yoshi = (daYoshi_c *) eatingActor; + if (isState(StateID_PlayerEat)) { + setNoHitPlayer(yoshi, 10); + dQuake_c::m_instance->shockMotor(mPlayerNo, dQuake_c::TYPE_4, 0, false); + mDirection = yoshi->mDirection; + mAngle.y = getMukiAngle(mDirection); + if (m_1298 == 1) { + mSpeed.y = sGlobalData_c::mData.mSpitRelated[2]; + float f = getDirSpeed(); + f *= sGlobalData_c::mData.mSpitRelated[3]; + mSpeedF = 0.5f * yoshi->getSpeedF() + f; + setRideOffPlayerJump(mSpeed.y, mSpeedF); + } else { + mSpeed.y = sGlobalData_c::mData.mSpitRelated[0]; + float f = getDirSpeed(); + f *= sGlobalData_c::mData.mSpitRelated[1]; + mSpeedF = 0.5f * yoshi->getSpeedF() + f; + changeState(StateID_RollSlip, 0); + } + mMtx_c mtx; + yoshi->getMouthMtx(&mtx); + mtx.concat(mMtx_c::createTrans(10.0f, 0.0f, 0.0f)); + mPos.x = mtx.transX(); + mPos.y = mtx.transY(); + float f = yoshi->mPos.y + 4.0f; + if (mPos.y < f) { + mPos.y = f; + } + mVec3_c posCopy(yoshi->mPos.x, mPos.y, mPos.z); + float offs = sc_DirSpeed[mDirection] * std::fabs(getWallBgPointData()->mOffset / 4096.0f); + mVec3_c posCopy2(mPos.x + offs, mPos.y, mPos.z); + float height; + if (dBc_c::checkWall(&posCopy, &posCopy2, &height, mLayer, 1, nullptr)) { + mSpeedF = 0.0f; + mPos.x = height - offs; + } + float offs2 = getHeadBgPointData()->mOffset / 4096.0f; + posCopy.set(mPos.x, offs2 + yoshi->mPos.y, mPos.z); + if (dBc_c::checkTenjou(&posCopy, &height, mLayer, 1)) { + if (mPos.y > height - offs2) { + mPos.y = height - offs2; + mSpeed.y = 0.0f; + } + } + mLastPos = mPos; + calcDispSideLimit(); + } + return true; +} + +void dAcPy_c::setPlayerEatPos(dActor_c *eatingActor) { + daYoshi_c *yoshi = (daYoshi_c *) eatingActor; + mMtx_c mtx; + if (yoshi != nullptr && yoshi->getTongueTipMtx(&mtx)) { + mPos.x = mtx.transX(); + mPos.y = mtx.transY(); + m_129c.x = (mPos.x - yoshi->mPos.x) / mAng(yoshi->mAngle.y).sin(); + m_129c.y = mPos.y - yoshi->mPos.y; + } +} + +void dAcPy_c::eatMove(dActor_c *eatingActor) { + if (eatingActor != nullptr && isStatus(STATUS_C8)) { + if (isStatus(STATUS_C9)) { + mPos.x = eatingActor->mPos.x + m_129c.x * mAng(eatingActor->mAngle.y).sin(); + mPos.y = eatingActor->mPos.y + m_129c.y; + } else { + setPlayerEatPos(eatingActor); + } + } +} + +void dAcPy_c::initializeState_PlayerEat() { + releaseCarryActor(); + endPowerUpEffect(); + onStatus(STATUS_97); + onStatus(STATUS_AA); + onStatus(STATUS_7A); + onStatus(STATUS_7E); + onStatus(STATUS_81); + onStatus(STATUS_C8); + dActor_c *eatingActor = (dActor_c *) fManager_c::searchBaseByID(mEatenByID); + if (eatingActor == nullptr) { + setPlayerEatPos(eatingActor); + } + onStatus(STATUS_CA); + mPyMdlMng.setAnm(PLAYER_ANIM_STAR_ROLL_DUPLICATE); + mSpeedF = 0.0f; + mAccelY = 0.0f; + mSpeed.y = 0.0f; + m_1298 = 0; +} + +void dAcPy_c::finalizeState_PlayerEat() { + mEatState = EAT_STATE_NONE; + mEatenByID = BASE_ID_NULL; + offStatus(STATUS_97); + offStatus(STATUS_AA); + offStatus(STATUS_7A); + offStatus(STATUS_7E); + offStatus(STATUS_81); + offStatus(STATUS_INVISIBLE); + offStatus(STATUS_C8); + offStatus(STATUS_C9); + offStatus(STATUS_CA); + calcDispSideLimit(); +} + +void dAcPy_c::executeState_PlayerEat() { + daYoshi_c *yoshi = (daYoshi_c *) fManager_c::searchBaseByID(mEatenByID); + if (yoshi == nullptr) { + changeState(StateID_Jump, nullptr); + return; + } + if (mSubstateValue != 0) { + mSubstateValue--; + } + if (mKey.triggerShakeJump() && yoshi->fn_8014f030(this)) { + m_1298 = 1; + } +} + +void dAcPy_c::setPlayerEatReact() { + mEatBehaviour = EAT_TYPE_NONE; + if ( + isDemo() || + isChange() || + (mDamageInvulnTimer | mPowerupChangeInvulnTimer) != 0 || // [maybe an inline?] + mNoInteractTimer != 0 || + isStatus(STATUS_DISPLAY_OUT_DEAD) || + isStatus(STATUS_OUT_OF_PLAY) || + isStatus(STATUS_STUNNED) || + isStatus(STATUS_QUAKE) + ) { + return; + } + mEatBehaviour = EAT_TYPE_EAT; +} + +bool dAcPy_c::setRideJrCrown(const dActor_c *actor) { + if (mRideActorID == 0) { + mRideActorID = actor->mUniqueID; + changeState(StateID_JrCrown, 0); + return true; + } + return false; +} + +bool dAcPy_c::isRideJrCrownOwn(const dActor_c *actor) { + if (isStatus(STATUS_4F) && mRideActorID == actor->mUniqueID) { + return true; + } + return false; +} + +void dAcPy_c::setRideJrCrownMtx(const mMtx_c *mtx) { + if (isStatus(STATUS_4F)) { + mRideJrClownMtx = *mtx; + } +} + +void dAcPy_c::setJrCrownPos() { + if (isStatus(STATUS_4F)) { + mRideJrClownMtx.multVecZero(mPos); + } +} + +void dAcPy_c::setRideJrCrownAnm(int i) { + if (isStatus(STATUS_4F) && !isStatus(STATUS_50)) { + mPyMdlMng.setAnm(i); + } +} + +void dAcPy_c::initializeState_JrCrown() { + releaseCarryActor(); + onStatus(STATUS_4F); + onStatus(STATUS_7E); + onStatus(STATUS_93); + onStatus(STATUS_JUMP_DAI_COOLDOWN); + mAccelY = 0.0f; + mSpeedF = 0.0f; + mMaxSpeedF = 0.0f; + mPyMdlMng.setAnm(PLAYER_ANIM_RIDE_WAIT); + mRc.mFlags |= BIT_FLAG(2); +} + +void dAcPy_c::finalizeState_JrCrown() { + offStatus(STATUS_4F); + offStatus(STATUS_50); + offStatus(STATUS_7E); + offStatus(STATUS_93); + offStatus(STATUS_JUMP_DAI_COOLDOWN); + mRideActorID = BASE_ID_NULL; + mRc.mFlags &= ~BIT_FLAG(2); +} + +void dAcPy_c::executeState_JrCrown() { + switch (mSubstate) { + case 0: + offStatus(STATUS_50); + break; + case 1: + if (!executeElecShock()) { + setDamage2(nullptr, DAMAGE_BG); + mSubstate = 2; + } + break; + case 2: + mSubstate = 0; + mPyMdlMng.setAnm(PLAYER_ANIM_RIDE_WAIT); + break; + } +} + +void dAcPy_c::setJrCrownElecDamage() { + onStatus(STATUS_50); + initElecShock(); + mSubstate = 1; +} + +bool dAcPy_c::checkSetFireBall() { + if (mKey.triggerFire()) { + if (isCarry()) { + return false; + } + if (mPowerup == POWERUP_FIRE_FLOWER) { + if (daFireBall_Player_c::CheckFireBallLimit(mPlayerNo, 0)) { + return true; + } + } else if (mPowerup == POWERUP_PENGUIN_SUIT || mPowerup == POWERUP_ICE_FLOWER) { + if (daIceBall_c::CheckIceballLimit(mPlayerNo, 0)) { + return true; + } + } + } + return false; +} + +bool dAcPy_c::setFireBallAction() { + if (isStatus(STATUS_9E) && checkSetFireBall()) { + changeState(StateID_Fire, 0); + return true; + } + return false; +} + +bool dAcPy_c::checkFireJump() { + if (isNowBgCross(BGC_FOOT) && mKey.triggerJump()) { + if (isNowBgCross(BGC_WATER_SHALLOW)) { + mSpeed.y = sc_WaterJumpSpeed; + } else { + fn_80145fd0(1); + setJumpSpeed(); + } + setJumpCommonBase(); + return true; + } + return false; +} + +void dAcPy_c::createFireBall(int i) { + mMtx_c mtx; + mVec3_c pos; + mVec3_c loopPos; + mVec3_c pos2; + mPyMdlMng.mpMdl->getJointMtx(&mtx, 11); + mtx.concat(mMtx_c::createTrans(-1.0f, 4.0f, 4.0f)); + mtx.multVecZero(pos); + mPyMdlMng.mpMdl->getJointMtx(&mtx, 0); + mtx.multVecZero(pos2); + mVec3_c diff = pos - pos2; + float dist = diff.xzLen(); + float dirSpeed = sc_DirSpeed[m_12f4]; + loopPos.set( + dScStage_c::getLoopPosX(pos2.x + dirSpeed * dist), + pos.y, + mPos.z + ); + if (mPowerup == POWERUP_FIRE_FLOWER) { + startSound(SE_PLY_THROW_FIRE, false); + pos = loopPos; + u32 param = (i << 16) | (mAmiLayer << 12) | (mLayer << 8) | (m_12f4 << 4) | mPlayerNo; + dActor_c::construct(fProfile::PL_FIREBALL, param, &pos, nullptr, 0); + } else if (mPowerup == POWERUP_PENGUIN_SUIT || mPowerup == POWERUP_ICE_FLOWER) { + startSound(SE_PLY_THROW_ICEBALL, false); + pos = loopPos; + u32 param = (i << 16) | (mAmiLayer << 12) | (mLayer << 8) | (m_12f4 << 4) | mPlayerNo; + dActor_c::construct(fProfile::ICEBALL, param, &pos, nullptr, 0); + } +} + +void dAcPy_c::initializeState_Fire() { + mSubstate = 0; + mPyMdlMng.setAnm(PLAYER_ANIM_FIRE_AT); + mAngle.y = getMukiAngle(mDirection); + m_12f4 = mDirection; + onStatus(STATUS_A0); + onStatus(STATUS_FIREBALL_PREPARE_SHOOT); + onStatus(STATUS_9F); +} + +void dAcPy_c::finalizeState_Fire() { + offStatus(STATUS_9F); + offStatus(STATUS_A0); + offStatus(STATUS_CAN_LAND); + offStatus(STATUS_9B); + offStatus(STATUS_9C); + offStatus(STATUS_9D); + offStatus(STATUS_FIREBALL_PREPARE_SHOOT); + offStatus(STATUS_A1); +} + +void dAcPy_c::executeState_Fire() { + gravitySet(); + maxFallSpeedSet(); + simpleMoveSpeedSet(); + powerSet(); + if (isNowBgCross(BGC_FOOT)) { + offStatus(STATUS_CAN_LAND); + offStatus(STATUS_9B); + offStatus(STATUS_9C); + offStatus(STATUS_9D); + offStatus(STATUS_A1); + } else { + onStatus(STATUS_CAN_LAND); + onStatus(STATUS_9B); + onStatus(STATUS_9C); + onStatus(STATUS_9D); + onStatus(STATUS_A1); + } + switch (mSubstate) { + case 0: + checkFireJump(); + if (mPyMdlMng.mpMdl->mAnm.checkFrame(dPyMdlBase_c::scFireShootFrame)) { + createFireBall(0); + mSubstate = 1; + offStatus(STATUS_FIREBALL_PREPARE_SHOOT); + } + break; + case 1: + if (checkSetFireBall()) { + m_12f4 = getDirection(); + mAngle.y = getMukiAngle(mDirection); + mSubstate = 0; + mPyMdlMng.setAnm(PLAYER_ANIM_FIRE_AT); + mPyMdlMng.mpMdl->setFrame(0.0f); + } else if (isNowBgCross(BGC_FOOT)) { + if ( + !checkJumpTrigger() && + ( + mPyMdlMng.mpMdl->mAnm.getFrame() >= 10.0f && mSpeedF || + mPyMdlMng.isAnmStop() + ) + ) { + changeState(StateID_Walk, BLEND_DEFAULT); + } + } else { + if ( + mPyMdlMng.mpMdl->mAnm.getFrame() >= 10.0f || + (mPyMdlMng.isAnmStop() && mSpeed.y <= 0.0f) + ) { + changeState(StateID_Fall, false); + } + } + break; + } +} + +void dAcPy_c::setSpinFireBall() { + if (isCarry()) { + dAcPy_c *carryPlayer = getCarryPlayer(); + if (carryPlayer != nullptr) { + carryPlayer->m_12f4 = m_12f4; + carryPlayer->setSpinFireBall(); + } + } else if (mPowerup == POWERUP_FIRE_FLOWER) { + if (daFireBall_Player_c::CheckFireBallLimit(mPlayerNo, 1)) { + createFireBall(1); + } + } else if (mPowerup == POWERUP_PENGUIN_SUIT || mPowerup == POWERUP_ICE_FLOWER) { + if (daIceBall_c::CheckIceballLimit(mPlayerNo, 1)) { + createFireBall(1); + } + } +} + +bool dAcPy_c::setPropelAction() { + if (isStatus(STATUS_IS_SPIN_HOLD_REQ) || isOnSinkSand()) { + changeState(StateID_SpinJump, 0); + return false; + } + if (m_2f4 == 1) { + if (!getCarryPropelBlock() && dScStage_c::m_miniGame == 0) { + dGameCom::hideFukidashiForSession(mPlayerNo, 1); + } + if (isNowBgCross(BGC_FOOT)) { + changeState(StateID_Propel, (void *) 2); + } else { + changeState(StateID_Propel, (void *) 0); + } + return true; + } + return false; +} + +void dAcPy_c::resetPropelFlyTime() { + if (m_2f4 == 0) { + m_2f4 = 1; + } +} + +void dAcPy_c::clearPropelFlyUpTime() { + if (isStatus(STATUS_PROPEL_UP) && m_2ec > 10) { + m_2ec = 10; + } +} + +void dAcPy_c::calcPropelMoveSpeedF() { + int dir; + u8 wasWalk = mKey.buttonWalk(&dir); + if (wasWalk) { + mDirection = dir; + } + float f; + if (!isStatus(STATUS_PROPEL_UP)) { + mAccelF = data_802f5a0c[2]; + if (wasWalk && mSpeedF * sc_DirSpeed[mDirection] < 0.0f) { + mAccelF = data_802f5a0c[3]; + } + if (isStatus(STATUS_PROPEL_SLOW_FALL)) { + f = data_802f5a0c[8]; + } else { + f = data_802f5a0c[9]; + } + } else { + mAccelF = data_802f5a0c[1]; + f = data_802f5a0c[10]; + } + if (!wasWalk) { + float oldF = f; + f = std::fabs(mSpeedF); + mAccelF = 0.05f; + if (f > oldF) { + f = oldF; + } + } + if (mDirection == DIR_LR_L) { + f = -f; + } + mMaxSpeedF = f; +} + +void dAcPy_c::setPropelActionFlyInit() { + m_2f4 = 0; + m_2f0 = 25; + onStatus(STATUS_SPIN); + mPropelRollSpeed = 12000; + mIsPropelFall = 0; + startPlayerVoice(VOICE_PRPL_JUMP, 0); + startSound(SE_PLY_PRPL_JUMP, false); + mPyMdlMng.setAnm(PLAYER_ANIM_PL_SPIN_JUMP); + mAccelY = 0.0f; + mMaxFallSpeed = data_802f5a0c[5]; +} + +void dAcPy_c::setPropelActionBigFly() { + setPropelActionFlyInit(); + mSubstate = 0; + mSpeed.y = 0.5f; + m_2ec = 38; + setStartPropelJumpEffect(); + startPatternRumble("****--****--**----**----**----**----**----**----**"); +} + +void dAcPy_c::setPropelActionFly() { + setPropelActionFlyInit(); + mSubstate = 1; + m_2ec = 50; + startPatternRumble("***---***---*----**-----*----**-----*-----**-----*"); +} + +void dAcPy_c::PropelActionFly() { + setCcAtSpin(); + setPropelSpinSmokeEffect(); + if (mPropelRollSpeed < 3000) { + mPropelRollSpeed = 3000; + } + if (isNowBgCross(BGC_HEAD)) { + mSpeed.y = data_802f5a0c[4]; + } + if (isNowBgCross(BGC_FOOT)) { + m_2ec = 0; + } + if (mSubstate == 0) { + sLib::chase(&mSpeed.y, 3.0f, 0.7f); + } else { + sLib::chase(&mSpeed.y, data_802f5a0c[11], data_802f5a0c[12]); + } + if (m_2ec != 0) { + m_2ec--; + } + if (m_2ec == 0) { + setPropelActionFall(); + if (mSubstate == 0) { + mSubstateTimer = 30; + } else { + mSubstateTimer = 10; + } + } +} + +void dAcPy_c::setPropelActionFall() { + offStatus(STATUS_SPIN); + mPyMdlMng.setAnm(PLAYER_ANIM_PL_SPIN_JUMP, 30.0f, 0.0f); + setAddLiftSpeedF(); + mSubstate = 2; + mPropelRollSpeed = 3000; + mIsPropelFall = 1; + mAccelY = data_802f5a0c[7]; +} + +void dAcPy_c::PropelActionFall() { + if (mSpeed.y < 0.0f) { + offStatus(STATUS_PROPEL_UP); + } + if (isStatus(STATUS_PROPEL_SLOW_FALL)) { + mMaxFallSpeed = data_802f5a0c[6]; + } else { + mMaxFallSpeed = data_802f5a0c[5]; + } + offStatus(STATUS_A8); + onStatus(STATUS_A9); + onStatus(STATUS_92); + if (isNowBgCross(BGC_FOOT)) { + setLandSE(); + mPyMdlMng.setAnm(PLAYER_ANIM_JUMPED); + changeState(StateID_Land, false); + } else { + if (mPropelRollSpeed < 2000) { + offStatus(STATUS_PROPEL_SLOW_FALL); + } else { + onStatus(STATUS_PROPEL_SLOW_FALL); + } + calcPropelFallSpinEffect(); + if (mPropelRollSpeed < 1000) { + mPropelRollSpeed = 1000; + if (mPyMdlMng.getAnm() != PLAYER_ANIM_SPIN_JUMP3) { + mPyMdlMng.setAnm(PLAYER_ANIM_SPIN_JUMP3); + } + } + if ( + mPyMdlMng.mpMdl->mCurrAnmID == PLAYER_ANIM_SPIN_JUMP3 && + ( + mPyMdlMng.mpMdl->mAnm.checkFrame(8.0f) || + mPyMdlMng.mpMdl->mAnm.checkFrame(19.0f) + ) + ) { + startSound(SE_PLY_PRPL_FLY, false); + } + if (mKey.triggerShakeJump()) { + mPropelRollSpeed = 5000; + mIsPropelFall = 1; + mPyMdlMng.setAnm(PLAYER_ANIM_PL_SPIN_JUMP); + setPropelFallSpinEffect(); + } + } +} + +void dAcPy_c::initializeState_Propel() { + m_2ec = 0; + switch ((int) mStateArg) { + case 0: + setPropelActionFly(); + break; + case 1: + setPropelActionFall(); + break; + case 2: + setPropelActionBigFly(); + break; + } + if (isNowBgCross(BGC_FOOT)) { + offNowBgCross(BGC_FOOT); + } + onStatus(STATUS_PROPEL); + onStatus(STATUS_PROPEL_UP); + onStatus(STATUS_9B); + onStatus(STATUS_9C); + onStatus(STATUS_9D); + onStatus(STATUS_A0); + onStatus(STATUS_A8); + onStatus(STATUS_CAN_LAND); + mSubstateValue = 0; + if (getCarryPropelActor() != nullptr) { + mSubstateValue = 1; + } + setScrollMode(2); +} + +void dAcPy_c::finalizeState_Propel() { + endPropelFlyPartsMove(); + stopPropelFallSpinEffect(); + mPropelRollSpeed = 0; + mAngle.x = 0; + mAngle.y = getMukiAngle(mDirection); + offStatus(STATUS_PROPEL); + offStatus(STATUS_PROPEL_UP); + offStatus(STATUS_SPIN); + offStatus(STATUS_9B); + offStatus(STATUS_9C); + offStatus(STATUS_9D); + offStatus(STATUS_A0); + offStatus(STATUS_A8); + offStatus(STATUS_A9); + offStatus(STATUS_CAN_LAND); + offStatus(STATUS_PROPEL_SLOW_FALL); + offStatus(STATUS_92); + setScrollMode(0); +} + +void dAcPy_c::executeState_Propel() { + offStatus(STATUS_92); + if (mSubstateValue == 0) { + if (mPowerup != POWERUP_PROPELLER_SHROOM) { + changeState(StateID_Fall, false); + return; + } + } else if (getCarryPropelActor() == nullptr) { + changeState(StateID_Fall, false); + return; + } + if (mPropelRollSpeed != 0) { + mAngle.y += mPropelRollSpeed; + if (!mIsPropelFall) { + mPropelRollSpeed -= 200; + } else { + mPropelRollSpeed -= 80; + } + } + if (mPropelRollSpeed <= 0) { + mPropelRollSpeed = 0; + mAngle.y = getMukiAngle(mDirection); + offStatus(STATUS_SPIN); + } + typedef void (dAcPy_c::*PropelActionProc)(); + static PropelActionProc l_PropelActionProc[] = { + &dAcPy_c::PropelActionFly, + &dAcPy_c::PropelActionFly, + &dAcPy_c::PropelActionFall + }; + (this->*l_PropelActionProc[mSubstate])(); + calcPropelMoveSpeedF(); + sLib::addCalcAngle(&mAngle.x.mAngle, 0, 0x100, 0x2000, 0x200); + if (!checkCarryThrow() && setHipAttackAction()) { + return; + } +} + +void dAcPy_c::updatePropelParts() { + if (!isStatus(STATUS_45)) { + if (isStatus(STATUS_PROPEL)) { + updatePropelFlyPartsMove(); + } else if (isLiftUp()) { + mpPropelParts->mMode = 3; + } else if (isStatus(STATUS_70)) { + mpPropelParts->mMode = 5; + } else { + mpPropelParts->mMode = 4; + } + } + mMtx_c mtx; + mPyMdlMng.mpMdl->getHeadPropelJointMtx(&mtx); + mpPropelParts->update(mtx); + if (!mpPropelParts->isMode(dPropelParts_c::PROPEL_MODE_3) && !isStatus(STATUS_PROPEL_NO_ROLL)) { + mPyMdlMng.mpMdl->setPropelRollSpeed(mpPropelParts->mRollSpeed); + } else { + mPyMdlMng.mpMdl->setPropelRollSpeed(0); + mPyMdlMng.mpMdl->setPropelRollAngle(0); + } + mPyMdlMng.mpMdl->setPropelScale(mpPropelParts->mScale); +} + +void dAcPy_c::updatePropelFlyPartsMove() { + int v = 4; + if (isStatus(STATUS_PROPEL)) { + switch (mSubstate) { + case 0: + case 1: + v = 0; + break; + default: + v = 2; + if (mPropelRollSpeed < 3000) { + v = 1; + } + break; + } + } + dActor_c *propelActor = getCarryPropelActor(); + if (propelActor == nullptr) { + mpPropelParts->mMode = v; + } else { + mpPropelParts->mMode = 3; + propelActor->mpPropelParts->mMode = v; + } +} + +void dAcPy_c::endPropelFlyPartsMove() { + dActor_c *propelActor = getCarryPropelActor(); + if (propelActor != nullptr) { + propelActor->mpPropelParts->finalizePropelFly(mPropelRollSpeed); + } + mpPropelParts->finalizePropelFly(mPropelRollSpeed); +} + +void dAcPy_c::setPropelSpinSmokeEffect() { + mVec3_c efPos = mPos; + efPos.y += 10.0f; + if (dMaskMng::isCaveMask() && mLayer == 0 && mAmiLayer == 1) { + efPos.z = 2000.0f; + } + float height; + if (dBc_c::checkGround(&efPos, &height, mLayer, 1, -1) && mPos.y < height + 64.0f) { + efPos.y = height; + dEf::createPlayerEffect(mPlayerNo, &mLevelEf3, "Wm_mr_spinsmoke", 0, &efPos, nullptr, nullptr); + } +} + +void dAcPy_c::setStartPropelJumpEffect() { + if (isNowBgCross(BGC_FOOT)) { + mVec3_c efPos = mPos; + if (dMaskMng::isCaveMask() && mLayer == 0 && mAmiLayer == 1) { + efPos.z = 2000.0f; + } + dEf::createPlayerEffect(mPlayerNo, "Wm_mr_spindepart", 0, &efPos, nullptr, nullptr); + } +} + +void dAcPy_c::setPropelFallSpinEffect() { + startSound(SE_PLY_PRPL_LETDOWN_SPIN, false); + if (m_538 == 0) { + m_538 = 1; + } +} + +bool dAcPy_c::calcPropelFallSpinEffect() { + if (m_53c != 0) { + m_53c--; + } + switch (m_538) { + case 1: + case 2: + case 3: { + if (isStatus(STATUS_PROPEL_SLOW_FALL)) { + dAcPy_c *carryPlayer = getCarryPlayer(); + mVec3_c efPos; + if (carryPlayer != nullptr) { + carryPlayer->getModel()->getJointPos(&efPos, 1); + } else { + mPyMdlMng.mpMdl->getJointPos(&efPos, 1); + } + if (m_538 == 1) { + dEf::createPlayerEffect(mPlayerNo, &mFollowEf, "Wm_mr_spinjump_re", 0, &efPos, nullptr, nullptr); + if (carryPlayer != nullptr) { + m_538 = 3; + } else { + m_538 = 2; + } + return true; + } + if (m_538 == 3 && carryPlayer == nullptr) { + stopPropelFallSpinEffect(); + return false; + } + if (mFollowEf.follow(&efPos, nullptr, nullptr)) { + return true; + } + } + m_538 = 4; + m_53c = 20; + break; + } + case 4: + if (m_53c == 0) { + m_538 = 0; + } + break; + } + return false; +} + +void dAcPy_c::stopPropelFallSpinEffect() { + mFollowEf.kill(); + m_53c = 0; + m_538 = 0; +} + +void dAcPy_c::initDemo_DownPose() { + if (mPyMdlMng.mpMdl->mFlags & 4) { + mPos.y = getAnkleCenterPos().y; + } + mPyMdlMng.setAnm(PLAYER_ANIM_DEAD_POSE); + mSpeedF = 0.0f; + mAngle.set(0, 0, 0); + mPos.y += 2.0f; + setZPosition(5000.0f); + mMaxFallSpeed = 0.0f; + mSpeed.set(0.0f, 0.0f, 0.0f); + mAccelY = 0.0f; + calcModel(); +} + +void dAcPy_c::initDemo_DownFall() { + switch ((DemoDownArg_e) mDemoStateArg) { + case DEMO_DOWN_ARG_HIT: + startPlayerVoice(VOICE_DAMAGE_LAST_2, 0); + break; + case DEMO_DOWN_ARG_TIME_UP: + if (daPyMng_c::mTimeUpPlayerNum >= 2) { + startPlayerVoice(VOICE_TIMEUP_MULTI, 0); + } else { + startPlayerVoice(VOICE_TIMEUP, 0); + } + break; + case DEMO_DOWN_ARG_POISON: + case DEMO_DOWN_ARG_POISON_FOG: + startPlayerVoice(VOICE_DAMAGE_POISON, 0); + break; + } + mPyMdlMng.setAnm(PLAYER_ANIM_DEAD); + mSpeed.x = 0.0f; + mSpeed.y = 3.25f; + mSpeed.z = 0.0f; + mMaxFallSpeed = sc_MaxFallSpeed; + mAccelY = -0.125f; +} + +void dAcPy_c::exeDemo_DownFall() { + if (mSpeed.y > 2.5f) { + mAccelY = -0.06f; + } else if (mSpeed.y > 0.5f) { + mAccelY = -0.25f; + } else if (mSpeed.y > -0.5f) { + mAccelY = -0.047f; + } else { + mAccelY = -0.1f; + } + mPos.y += mSpeed.y; + calcFallSpeed(); +} + +void dAcPy_c::checkRest() { + if (isItemKinopio()) { + deleteRequest(); + return; + } + if (!m_7c) { + setBalloonInDamage(); + return; + } + if (isStatus(STATUS_ALL_DOWN_FADE)) { + return; + } + onStatus(STATUS_ALL_DOWN_FADE); + bool allDown = true; + for (int i = 0; i < PLAYER_COUNT; i++) { + if (daPyMng_c::mPlayerEntry[i] && daPyMng_c::mRest[daPyMng_c::mPlayerType[i]] != 0) { + allDown = false; + break; + } + } + if (!allDown) { + dScStage_c::setNextScene(3, 0, dScStage_c::EXIT_1, dFader_c::FADER_BOWSER); + } else { + dScStage_c::setNextScene(9, 0, dScStage_c::EXIT_1, dFader_c::FADER_BOWSER); + } +} + +void dAcPy_c::initPlayerDownCommon() { + m_7c = 0; + if (daPyMng_c::decNum(mPlayerNo) && daPyMng_c::mNum == 0) { + m_7c = 1; + } + changeState(StateID_None); + releaseCarryActor(); + resetMissSpin(); + endStar(); + setScrollMode(3); + onStatus(STATUS_OUT_OF_PLAY); + mDamageInvulnTimer = 0; + mStarTimer = 0; + mVisible = true; + if (!isItemKinopio()) { + daPyMng_c::decRest(mPlayerNo); + if (m_7c) { + SndSceneMgr::sInstance->fn_8019be60(1); + } + } + mDemoSubstateTimer = 30; +} + +void dAcPy_c::stopOtherDownDemo() { + if (isItemKinopio()) { + return; + } + if (!m_7c) { + stopOther(); + return; + } + daPyDemoMng_c::mspInstance->m_84 = mPlayerNo; + mExecStopReq |= 0b1111; + + dAcPy_c *player; + for (int i = 0; i < PLAYER_COUNT; i++) { + player = daPyMng_c::getPlayer(i); + if (player != nullptr && !player->isStatus(STATUS_53) && !player->isItemKinopio()) { + player->mExecStopMask &= ~BIT_FLAG(1); + } + daYoshi_c *yoshi = daPyMng_c::getYoshi(i); + if (yoshi != nullptr) { + yoshi->mExecStopMask &= ~BIT_FLAG(1); + } + } + mExecStopReq |= 0b1101; +} + +void dAcPy_c::playOtherDownDemo() { + if (!isItemKinopio() && daPyDemoMng_c::mspInstance->m_84 == -1 && !m_7c) { + playOther(); + } +} + +bool dAcPy_c::setTimeOverDemo() { + if ( + !isStatus(STATUS_53) && + !isStatus(STATUS_GOAL_POLE_NOT_GOAL_NO_MOVE) && + !isStatus(STATUS_OUT_OF_PLAY) && + !isStatus(STATUS_STUNNED) + ) { + changeDemoState(StateID_DemoDown, DEMO_DOWN_ARG_TIME_UP); + return true; + } + return false; +} + +void dAcPy_c::initializeState_DemoDown() { + initPlayerDownCommon(); + initDemo_DownPose(); + startSound(SE_PLY_DOWN, false); + switch ((DemoDownArg_e) mDemoStateArg) { + case DEMO_DOWN_ARG_HIT: + case DEMO_DOWN_ARG_POISON_FOG: + stopOtherDownDemo(); + break; + case DEMO_DOWN_ARG_POISON: { + mVec3_c efPos( + mPos.x, + mWaterHeight, + mPos.z + ); + dEf::createPlayerEffect(mPlayerNo, "Wm_mr_poisonwave", nullptr, &efPos, nullptr, nullptr); + startSound(SE_PLY_SPLASH_POISON, 0); + dBg_c::m_bg_p->setWaterInWave(mPos.x, mWaterHeight, 20); + stopOtherDownDemo(); + break; + } + case DEMO_DOWN_ARG_TIME_UP: + daPyMng_c::mTimeUpPlayerNum++; + stopOtherDownDemo(); + break; + } + dQuake_c::m_instance->shockMotor(mPlayerNo, dQuake_c::TYPE_4, 0, false); +} + +void dAcPy_c::finalizeState_DemoDown() { + mMaxFallSpeed = sc_MaxFallSpeed; +} + +void dAcPy_c::executeState_DemoDown() { + switch (mDemoSubstate) { + case 0: + if (mDemoSubstateTimer == 0) { + daPyMng_c::startMissBGM(mPlayerNo); + mDemoSubstate = 1; + initDemo_DownFall(); + if (dBg_c::m_bg_p->m_90009 == 3) { + mMaxFallSpeed = sc_MaxFallDownSpeed; + } + if ((int) mDemoStateArg != 1) { + playOtherDownDemo(); + mDemoSubstateTimer = 80; + } else { + mDemoSubstateTimer = 150; + } + } + break; + case 1: { + exeDemo_DownFall(); + if (!m_7c) { + dBgParameter_c *bgParam = dBgParameter_c::ms_Instance_p; + dBg_c *bg = dBg_c::m_bg_p; + float t = getVisTop(); + u8 val = bg->m_90009; + float f = bgParam->yStart() - bgParam->ySize() - 24.0f; + if (val == 3) { + f = bgParam->yStart() - bgParam->ySize() - 8.0f; + } + if (t < f) { + checkRest(); + mDemoSubstate = 2; + break; + } + if (val != 3) { + break; + } + if (getVisBottom() > bgParam->yStart() + 64.0f) { + checkRest(); + mDemoSubstate = 2; + } + } else if (mDemoSubstateTimer == 0) { + checkRest(); + mDemoSubstate = 2; + } + break; + } + case 2: + exeDemo_DownFall(); + } + checkSideViewLemit(); +} + +void dAcPy_c::setFallDownDemo() { + if (isDispOutCheckOn()) { + mAccelY = 0.0f; + mSpeedF = 0.0f; + mBgPushForce.set(0.0f, 0.0f, 0.0f); + mExtraPushForceX = 0.0f; + mSpeed.y = 0.0f; + changeDemoState(StateID_DemoFallDown, 0); + } +} + +void dAcPy_c::initializeState_DemoFallDown() { + initPlayerDownCommon(); + mPyMdlMng.setAnm(PLAYER_ANIM_JUMP2, 1.0f, 0.0f, 0.0f); + mAccelY = 0.0f; + mSpeedF = 0.0f; + mBgPushForce.set(0.0f, 0.0f, 0.0f); + mExtraPushForceX = 0.0f; + mSpeed.y = 0.0f; + mAngle.y = 0; + setZPosition(5000.0f); + float f = dBgParameter_c::ms_Instance_p->getLoopScrollDispPosX(mPos.x); + float f1 = f - 96.0f; + float f2 = f + dBgParameter_c::ms_Instance_p->xSize() + 96.0f; + if (f1 <= mPos.x && mPos.x < f2) { + startSound(SE_PLY_DOWN, false); + } + stopOtherDownDemo(); + onStatus(STATUS_INVISIBLE); + mVisible = false; +} + +void dAcPy_c::finalizeState_DemoFallDown() { + offStatus(STATUS_INVISIBLE); +} + +void dAcPy_c::executeState_DemoFallDown() { + switch (mDemoSubstate) { + case 0: + if (mDemoSubstateTimer == 0) { + mDemoSubstate = 1; + daPyMng_c::startMissBGM(mPlayerNo); + if (!m_7c) { + playOtherDownDemo(); + mDemoSubstateTimer = 50; + } else { + mDemoSubstateTimer = 80; + } + } + break; + case 1: + if (mDemoSubstateTimer == 0) { + checkRest(); + mDemoSubstate = 2; + } + } + checkSideViewLemit(); +} + +void dAcPy_c::initializeState_DemoFireDown() { + dScStage_c *stage = dScStage_c::m_instance; + initPlayerDownCommon(); + if (mBgDamageType == 7) { + mVec3_c efPos( + mPos.x, + mWaterHeight, + 6500.0f + ); + if (stage != nullptr) { + if ( + stage->mCurrWorld == WORLD_8 && stage->mCurrCourse == STAGE_3 || + stage->mCurrWorld == WORLD_8 && stage->mCurrCourse == STAGE_CASTLE && stage->mCurrFile == 3 + ) { + dEf::createPlayerEffect(mPlayerNo, "Wm_en_cmnmagmawave", 0, &efPos, nullptr, nullptr); + } else { + dEf::createPlayerEffect(mPlayerNo, "Wm_mr_magmawave", 0, &efPos, nullptr, nullptr); + } + } + dBg_c::m_bg_p->setWaterInWave(mPos.x, mWaterHeight, 13); + } + initDemo_DownPose(); + setZPosition(3000.0f); + startSound(SE_PLY_SPLASH_LAVA, false); + startSound(SE_PLY_DOWN, false); + dQuake_c::m_instance->shockMotor(mPlayerNo, dQuake_c::TYPE_4, 0, false); + stopOtherDownDemo(); +} + +void dAcPy_c::finalizeState_DemoFireDown() {} + +void dAcPy_c::executeState_DemoFireDown() { + switch (mDemoSubstate) { + case 0: + if (mDemoSubstateTimer == 0) { + daPyMng_c::startMissBGM(mPlayerNo); + mDemoSubstateTimer = 80; + startPlayerVoice(VOICE_DAMAGE_FIRE, 0); + startSound(SE_PLY_BURN_DOWN, false); + setZPosition(5000.0f); + mPyMdlMng.setAnm(PLAYER_ANIM_FIREJMP); + mSpeed.x = 0.0f; + mSpeed.y = 3.25f; + mSpeed.z = 0.0f; + mMaxFallSpeed = sc_MaxFallSpeed; + mAccelY = -0.125f; + mAngle.y = getMukiAngle(mDirection); + mDemoSubstate = 1; + playOtherDownDemo(); + } + break; + case 1: + exeDemo_DownFall(); + if (!m_7c) { + dBgParameter_c *bgParam = dBgParameter_c::ms_Instance_p; + float edgePos = getVisTop(); + float bgBottom = bgParam->yStart() - bgParam->ySize() - 24.0f; + if (edgePos < bgBottom) { + checkRest(); + mDemoSubstate = 2; + } + } else if (mDemoSubstateTimer == 0) { + checkRest(); + mDemoSubstate = 2; + } + break; + case 2: + exeDemo_DownFall(); + break; + } + if (mDemoSubstate != 0) { + mVec3_c efScale(1.0f, 1.0f, 1.0f); + if (mPowerup == POWERUP_MINI_MUSHROOM) { + efScale.set(0.6f, 0.6f, 0.6f); + } + dEf::createPlayerEffect(mPlayerNo, &mSmokeEffect, "Wm_mr_atitismoke", 0, &mPos, nullptr, &efScale); + } + checkSideViewLemit(); +} + +void dAcPy_c::setPlayerEatDie() { + m_15a8 = 0; + if ((int) mDemoStateArg == 12) { + m_15a8 = 1; + } else { + if (!isStar() && (mPowerup == POWERUP_NONE || mPowerup == POWERUP_MINI_MUSHROOM)) { + m_15a8 = 1; + } + } +} + +void dAcPy_c::initializeState_DemoEatDie() { + setPlayerEatDie(); + if (m_15a8 != 0) { + initPlayerDownCommon(); + } + mRelatedActorID = BASE_ID_NULL; + mSpeedF = 0.0f; + mMaxFallSpeed = 0.0f; + mSpeed.set(0.0f, 0.0f, 0.0f); + mAccelY = 0.0f; + mDemoSubstate = 0; +} + +void dAcPy_c::finalizeState_DemoEatDie() { + offStatus(STATUS_INVISIBLE); + offStatus(STATUS_OUT_OF_PLAY); +} + +void dAcPy_c::executeState_DemoEatDie() { + switch (mDemoSubstate) { + case 2: + if (mDemoSubstateTimer == 0) { + if (m_15a8 != 0) { + startSound(SE_PLY_DOWN, false); + } else if (!isStar()) { + if (mPowerup == POWERUP_MUSHROOM) { + fn_801416c0(POWERUP_NONE); + } else { + fn_801416c0(POWERUP_MUSHROOM); + } + startSound(SE_PLY_CHANGE_SMALL, false); + mDamageInvulnTimer = 127; + } + mDemoSubstate = 1; + } + break; + case 0: + case 1: + if (mRelatedActorID == 0 || fManager_c::searchBaseByID(mRelatedActorID) == nullptr) { + releaseEatDie(); + } + break; + case 3: + if (mDemoSubstateTimer == 0) { + checkRest(); + mDemoSubstate = 4; + } + break; + } +} + +void dAcPy_c::releaseEatDie() { + if (!isItemKinopio() && m_7c) { + SndSceneMgr::sInstance->fn_8019bd90(1); + } + changeNormalAction(); + checkDisplayOutDead(); +} + +bool dAcPy_c::setEatDieHide() { + if (isDemoState(StateID_DemoEatDie)) { + mPyMdlMng.mpMdl->offStarEffect(); + onStatus(STATUS_INVISIBLE); + mDemoSubstate = 1; + return true; + } + return false; +} + +bool dAcPy_c::setEatDieFadeOut() { + if (isDemoState(StateID_DemoEatDie)) { + daPyMng_c::startMissBGM(mPlayerNo); + mDemoSubstate = 3; + mDemoSubstateTimer = 80; + return true; + } + return false; +} + +bool dAcPy_c::setEatDieSpitOut() { + if (isDemoState(StateID_DemoEatDie)) { + releaseEatDie(); + return true; + } + return false; +} + +void dAcPy_c::setEatDieScreamVoice() { + if (isDemoState(StateID_DemoEatDie)) { + startPlayerVoice(VOICE_DAMAGE_EATEN, 0); + mDemoSubstate = 2; + mDemoSubstateTimer = 30; + } +} + +bool dAcPy_c::searchDoorActor() { + dActor_c *door = nullptr; + while ((door = (dActor_c *) fManager_c::searchBaseByGroupType(ACTOR, door)) != nullptr) { + if ( + door->mProfName == fProfile::EN_DOOR || + door->mProfName == fProfile::EN_OBAKEDOOR || + door->mProfName == fProfile::EN_TORIDEDOOR || + door->mProfName == fProfile::EN_CASTLEDOOR + ) { + if (std::fabs(door->mPos.x - mPos.x) < 16.0f && std::fabs(door->mPos.y - mPos.y) < 16.0f) { + mRelatedActorID = door->mUniqueID; + return true; + } + } + } + mRelatedActorID = BASE_ID_NULL; + return false; +} + +void dAcPy_c::initializeState_DemoInDoor() { + onStatus(STATUS_INVISIBLE); + m_74 = 255; + changeState(StateID_Walk, BLEND_DEFAULT); + mPyMdlMng.setAnm(PLAYER_ANIM_DOOR_WALK); + mAngle.y = 0; + if (mLayer == 0) { + setZPosition(2800.0f); + } else { + setZPosition(-2000.0f); + } + mDamageInvulnTimer = 35; + searchDoorActor(); + if (daPyDemoMng_c::mspInstance->checkDemoNo(mPlayerNo) != 0) { + mDemoSubstate = 0; + } else { + mDemoSubstate = 2; + } +} + +void dAcPy_c::finalizeState_DemoInDoor() { + mDamageInvulnTimer = 0; + mPowerupChangeInvulnTimer = 0; + m_74 = 0; + mRelatedActorID = BASE_ID_NULL; +} + +void dAcPy_c::setDemoInDoor_Walk() { + offStatus(STATUS_INVISIBLE); + mDemoSubstate = 4; + mDemoSubstateTimer = 10; +} + +void dAcPy_c::executeState_DemoInDoor() { + daEnDoor_c *door = nullptr; + if (mRelatedActorID != BASE_ID_NULL) { + door = (daEnDoor_c *) fManager_c::searchBaseByID(mRelatedActorID); + } + if (door == nullptr) { + if (!mFader_c::mFader->isStatus(mFaderBase_c::HIDDEN)) { + searchDoorActor(); + } else { + changeNormalAction(); + } + return; + } + switch (mDemoSubstate) { + case 0: + if (mFader_c::mFader->isStatus(mFaderBase_c::HIDDEN)) { + door->m_5d4 = 1; + if (door->m_5cc == 0) { + door->m_5cc = 2; + } + mDemoSubstate++; + } + break; + case 1: + if (door->m_5d0 != 0) { + setDemoInDoor_Walk(); + } + break; + case 2: + if (daPyDemoMng_c::mspInstance->checkDemoNo(mPlayerNo)) { + setDemoInDoor_Walk(); + } + break; + case 4: + sLib::chase(&m_74, 0, 15); + onStatus(STATUS_79); + if (mDemoSubstateTimer == 0) { + if (daPyDemoMng_c::mspInstance->getNextDemoNo() == -1) { + mDemoSubstate = 5; + if (mRelatedActorID != BASE_ID_NULL) { + daEnDoor_c *tmpDoor = (daEnDoor_c *) fManager_c::searchBaseByID(mRelatedActorID); + if (tmpDoor != nullptr && (tmpDoor->m_5cc == 1 || tmpDoor->m_5cc == 2)) { + tmpDoor->m_5cc = 3; + } + } + } else { + mDemoSubstate = 6; + } + } + break; + case 5: + sLib::chase(&m_74, 0, 15); + onStatus(STATUS_79); + if (door->isClosed()) { + mDemoSubstate = 6; + } + break; + case 6: + sLib::chase(&m_74, 0, 15); + onStatus(STATUS_79); + short ang = getMukiAngle(mDirection); + if (!addCalcAngleY(ang, 10)) { + daPyDemoMng_c::mspInstance->turnNextDemoNo(); + mAngle.y = ang; + changeNormalAction(); + } + } +} + +void dAcPy_c::initializeState_DemoInJump() { + offStatus(STATUS_INVISIBLE); + mDemoSubstateTimer = 30; + mPyMdlMng.setAnm(PLAYER_ANIM_JUMP, 0.0f, 0.0f); + u8 jumpDir = (int) mDemoStateArg; + mDirection = jumpDir; + mSpeedF = sc_DirSpeed[jumpDir] * 0.5f; + mMaxSpeedF = sc_DirSpeed[jumpDir] * 0.5f; + if (mPowerup == POWERUP_MINI_MUSHROOM) { + mSpeed.y = 4.2f; + } else { + mSpeed.y = 5.0f; + } + mMaxFallSpeed = sc_MaxFallSpeed; + setButtonJumpGravity(); + mAngle.y = getMukiAngle(mDirection); +} + +void dAcPy_c::finalizeState_DemoInJump() {} + +void dAcPy_c::executeState_DemoInJump() { + switch (mDemoSubstate) { + case 0: + if (mDemoSubstateTimer == 0 && daPyDemoMng_c::mspInstance->checkDemoNo(mPlayerNo)) { + mDemoSubstateTimer = 30; + mDemoSubstate++; + } + break; + case 1: + if (mDemoSubstateTimer == 0) { + daPyDemoMng_c::mspInstance->turnNextDemoNo(); + mDemoSubstateTimer = 95; + mDemoSubstate++; + int world = dScStage_c::m_instance->mCurrWorld; + if (world == WORLD_4 || world == WORLD_6 || world == WORLD_8) { + if (dScStage_c::m_instance->mCurrCourse == STAGE_DOOMSHIP) { + startPlayerVoice(VOICE_JR_A_BATTLE_APP, 0); + } + } + } + break; + case 2: + setButtonJumpGravity(); + calcSpeedXY(); + posMove(); + if (mSpeed.y < 0.0f) { + changeNormalAction(); + changeState(StateID_Fall, false); + } + break; + } +} + +void dAcPy_c::initializeState_DemoInVine() { + mPyMdlMng.setAnm(PLAYER_ANIM_PEA_PLANT, 0.0f, 0.0f); + offStatus(STATUS_INVISIBLE); + mDemoSubstateTimer = 30; + mDirection = DIR_LR_R; + mAngle.y = 0x8000; + dEnemyMng_c::m_instance->demo_ivy_create(&mPos); +} + +void dAcPy_c::finalizeState_DemoInVine() {} + +void dAcPy_c::executeState_DemoInVine() { + switch (mDemoSubstate) { + case 0: + if (mDemoSubstateTimer == 0 && daPyDemoMng_c::mspInstance->checkDemoNo(mPlayerNo) != 0) { + mDemoSubstateTimer = 30; + mDemoSubstate++; + } + break; + case 1: + if (mDemoSubstateTimer == 0) { + daPyDemoMng_c::mspInstance->turnNextDemoNo(); + mDemoSubstateTimer = 95; + mDemoSubstate++; + } + break; + case 2: + mPos.y += 1.0f; + setIvyHangEffect(); + setVineWalkSE(); + mBc.checkHead(0); + if (mDemoSubstateTimer == 0) { + changeNormalAction(); + changeState(StateID_Vine, (void *) 1); + } + break; + } +} + +bool dAcPy_c::isDoorDemoEnable() { + if (!isEnableDokanInStatus()) { + return false; + } + if (mKey.buttonDoor()) { + if (isDemoState(StateID_DemoNone) && isOldBgCross(BGC_FOOT) && ((int) mPos.y & 0xf) == 0) { + return true; + } + } + return false; +} + +bool dAcPy_c::setDoorDemo(dActor_c *door) { + if (isDoorDemoEnable()) { + mVec3_c doorEnterPos( + door->mPos.x, + (int) mPos.y, + mPos.z + ); + int nextGoto; + if (dNext_c::m_instance->searchNextNum(dScStage_c::m_instance->mCurrFile, doorEnterPos.x, doorEnterPos.y + 1.0f, &nextGoto)) { + mDokanEnterNextGotoID = nextGoto; + if (dNext_c::m_instance->fn_800cfed0(dScStage_c::m_instance->mCurrFile, mDokanEnterNextGotoID)) { + return false; + } + if (daPyDemoMng_c::mspInstance->m_5c != 0) { + return false; + } + dNext_c::m_instance->setChangeSceneNextDat(dScStage_c::m_instance->mCurrFile, mDokanEnterNextGotoID, dFader_c::FADER_CIRCLE_TARGET); + mRelatedActorID = door->mUniqueID; + mWarpPos = doorEnterPos; + mDoorSize = 0; + int profName = door->mProfName; + if ( + profName == fProfile::EN_TORIDEDOOR || + profName == fProfile::EN_CASTLEDOOR + // || profName == fProfile::EN_KOOPADOOR + ) { + mDoorSize = 1; + } + changeDemoState(StateID_DemoOutDoor, 0); + changeState(StateID_None); + return true; + } + } + return false; +} + +void dAcPy_c::initializeState_DemoOutDoor() { + dAcPy_c *carryPlayer = getCarryPlayer(); + if (carryPlayer != nullptr) { + releaseCarryActor(); + } + mDemoSubstate = DEMO_OUT_DOOR_OPEN_DOOR; + mSpeedF = 0.0f; + mMaxSpeedF = 0.0f; + mSpeed.set(0.0f, 0.0f, 0.0f); + float z = daPyDemoMng_c::mspInstance->get_88() * 64.0f; + daPyDemoMng_c::mspInstance->inc_88(); + if (mLayer == 0) { + setZPosition(2800.0f + z); + } else { + setZPosition(-2000.0f + z); + } + mPyMdlMng.setAnm(PLAYER_ANIM_WAIT); + mAngle.x = 0; + if (daPyMng_c::mNum == 1) { + stopOther(); + } + mVec3_c pos(mWarpPos.x, mWarpPos.y, 0.0f); + if (mRelatedActorID != 0) { + daEnDoor_c *door = (daEnDoor_c *) fManager_c::searchBaseByID(mRelatedActorID); + if (door != nullptr && door->m_5cc == 0) { + door->m_5cc = 1; + } + } +} + +void dAcPy_c::finalizeState_DemoOutDoor() { + mRelatedActorID = BASE_ID_NULL; +} + +void dAcPy_c::exeDemoOutDoor_OpenDoor() { + addCalcAngleY(0x8000, 2); + if (mRelatedActorID != 0) { + daEnDoor_c *door = (daEnDoor_c *) fManager_c::searchBaseByID(mRelatedActorID); + if (door != nullptr && door->m_5d0 != 0) { + static const float scDoorEnterWidth[] = { 8.0f, 10.0f }; + if (std::fabs(mPos.x - mWarpPos.x) > scDoorEnterWidth[mDoorSize]) { + initDemoOutDoor_MoveCenter(); + } else { + initDemoOutDoor_MoveInter(); + } + } + } +} + +void dAcPy_c::initDemoOutDoor_MoveCenter() { + mDemoSubstateTimer = 10; + float speed = std::fabs(mPos.x - mWarpPos.x) / mDemoSubstateTimer; + if (speed > 1.0f) { + speed = 1.0f; + } + mSpeedF = speed; + mDemoSubstate = DEMO_OUT_DOOR_MOVE_CENTER; + + float animSpeed = (speed * 2.0f < 2.0f) ? 2.0f : speed * 2.0f; + mPyMdlMng.setAnm(PLAYER_ANIM_RUN, animSpeed, 0.0f, 0.0f); +} + +void dAcPy_c::exeDemoOutDoor_MoveCenter() { + if (std::fabs(mPos.x - mWarpPos.x) < 1.0f) { + initDemoOutDoor_MoveInter(); + return; + } + if (mPos.x < mWarpPos.x) { + addCalcAngleY(getMukiAngle(DIR_LR_R), 2); + } else { + addCalcAngleY(getMukiAngle(DIR_LR_L), 2); + } + sLib::chase(&mPos.x, mWarpPos.x, mSpeedF); +} + +void dAcPy_c::initDemoOutDoor_MoveInter() { + mDemoSubstateTimer = 30; + mDemoSubstate = DEMO_OUT_DOOR_MOVE_INTER; + mPyMdlMng.setAnm(PLAYER_ANIM_DOOR_WALK); + endPowerUpEffect(); +} + +void dAcPy_c::exeDemoOutDoor_MoveInter() { + addCalcAngleY(0x8000, 2); + sLib::chase(&m_1598, 2.0f, 0.2f); + sLib::chase(&m_74, 255, 15); + if (mDoorSize == 0) { + sLib::chase(&mPos.x, mWarpPos.x, 0.4f); + } + if (mDemoSubstateTimer != 0) { + return; + } + bool hasNonEnteredPlayer = false; + int count = 0; + for (int i = 0; i < PLAYER_COUNT; i++) { + dAcPy_c *player = daPyMng_c::getCtrlPlayer(i); + if (player == nullptr || player == this) { + continue; + } + if (daPyMng_c::mActPlayerInfo & (1 << (u8) i)) { + if (!player->isStatus(STATUS_64)) { + hasNonEnteredPlayer = true; + } + } else { + if (player->isStatus(STATUS_53)) { + count++; + } + } + } + if (!hasNonEnteredPlayer && count == 0) { + if (mRelatedActorID != BASE_ID_NULL) { + daEnDoor_c *door = (daEnDoor_c *) fManager_c::searchBaseByID(mRelatedActorID); + if (door != nullptr) { + if ((door->m_5cc == 1 || door->m_5cc == 2)) { + door->m_5cc = 3; + } + mDemoSubstate = DEMO_OUT_DOOR_WAIT_CLOSE; + } + } + } else { + mDemoSubstate = DEMO_OUT_DOOR_WAIT_ENTER; + } + m_1598 = 0.0f; + onStatus(STATUS_INVISIBLE); + mDemoSubstateTimer = 20; +} + +void dAcPy_c::exeDemoOutDoor_WaitClose() { + addCalcAngleY(0x8000, 2); + if (mDemoSubstateTimer != 0) { + return; + } + if (mRelatedActorID != nullptr) { + daEnDoor_c *door = (daEnDoor_c *) fManager_c::searchBaseByID(mRelatedActorID); + if (door != nullptr && door->isClosed()) { + changeNextScene(1); + mDemoSubstate = DEMO_OUT_DOOR_FINISHED; + } + } +} + +void dAcPy_c::exeDemoOutDoor_WaitEnter() { + if (mDemoSubstateTimer == 0) { + changeNextScene(1); + mDemoSubstate = DEMO_OUT_DOOR_FINISHED; + } +} + +void dAcPy_c::executeState_DemoOutDoor() { + typedef void (dAcPy_c::*DemoOutDoorProc)(); + static DemoOutDoorProc sDemoOutDoorProc[] = { + &dAcPy_c::exeDemoOutDoor_OpenDoor, + &dAcPy_c::exeDemoOutDoor_MoveCenter, + &dAcPy_c::exeDemoOutDoor_MoveInter, + &dAcPy_c::exeDemoOutDoor_WaitClose, + &dAcPy_c::exeDemoOutDoor_WaitEnter, + }; + if (mDemoSubstate != DEMO_OUT_DOOR_FINISHED) { + (this->*sDemoOutDoorProc[mDemoSubstate])(); + } +} + +bool dAcPy_c::initDemoDokanCannon(mVec3_c &pos, int cannonMode) { + if (isEnableDokanInStatus()) { + m_68 = cannonMode; + mWarpPos = pos; + changeDemoState(StateID_DemoDokanCannon, 0); + changeState(StateID_None); + return true; + } + return false; +} + +void dAcPy_c::endDemoDokanCannon(mVec3_c &pos) { + mPos.x = pos.x; + mPos.y = pos.y; + changeDemoState(StateID_DemoNone, false); +} + +bool dAcPy_c::isDokanCannonIn() { + if (isDemoState(StateID_DemoDokanCannon) && isStatus(STATUS_INVISIBLE)) { + return true; + } + return false; +} + +void dAcPy_c::initializeState_DemoDokanCannon() { + onStatus(STATUS_5A); + mpMdlMng->setAnm(PLAYER_ANIM_WAIT, 0.0f, 5.0f, scDokanWaitAnmFixFrame); + initDemoOutDokan(); +} + +void dAcPy_c::finalizeState_DemoDokanCannon() { + offStatus(STATUS_5A); + offStatus(STATUS_INVISIBLE); +} + +void dAcPy_c::executeState_DemoDokanCannon() { + switch (mDemoSubstate) { + case 0: + sLib::chase(&mPos.x, mWarpPos.x, scDokanInSpeedX); + if (std::fabs(mPos.x - mWarpPos.x) <= scDokanInWidthX) { + if (m_68 != 2) { + setScrollMode(4); + } + mDemoSubstate++; + } + break; + case 1: + if (sLib::chase(&mPos.y, mWarpPos.y - 32.0f, scDokanInMoveSpeed)) { + onStatus(STATUS_INVISIBLE); + mDemoSubstate++; + } + break; + case 2: + checkDisplayOutDead(); + break; + } +} + +int dAcPy_c::setDemoGoal(mVec3_c &landPos, float goalCastleX, u8 goalType) { + daYoshi_c *yoshi = getRideYoshi(); + if (yoshi != nullptr) { + return yoshi->setDemoGoal(landPos, goalCastleX, goalType); + } else { + return daPlBase_c::setDemoGoal(landPos, goalCastleX, goalType); + } +} + +void dAcPy_c::setOffYoshiInGoal(daPlBase_c *yoshi) { + changeState(StateID_RideOffJump, 0); + changeDemoState(StateID_DemoGoal, true); + mGoalDemoIndex = yoshi->mGoalDemoIndex; + mGoalTouchOrder = yoshi->mGoalTouchOrder; + mWarpPos = yoshi->mWarpPos; +} + +bool dAcPy_c::setHideNotGoalPlayer() { + if (isStatus(STATUS_OUT_OF_PLAY) || isStatus(STATUS_53) || isItemKinopio()) { + return false; + } + return daPlBase_c::setHideNotGoalPlayer(); +} + +void dAcPy_c::initDemoGoalBase() { + mDirection = DIR_LR_R; + endPowerUpEffect(); + dActor_c *carryActor = (dActor_c *) fManager_c::searchBaseByID(mCarryActorID); + if (carryActor != nullptr) { + carryActor->mPos.x = mPos.x; + } + releaseCarryActor(); + daPlBase_c::initDemoGoalBase(); + if ((int) mDemoStateArg == 1) { + setDemoGoalMode(3, 6); + mPyMdlMng.setAnm(PLAYER_ANIM_GET_DOWN, 0.0f, 0.0f); + mSpeed.y = sc_JumpSpeed - 0.2f; + mSpeedF = 1.0f; + mDemoState = CONTROL_DEMO_KINOPIO_SWIM; + mDirection = DIR_LR_L; + mAngle.y = getMukiAngle(DIR_LR_L); + } +} + +void dAcPy_c::executeDemoGoal_Run() { + switch (mDemoState) { + case 0: + if (mGoalTouchOrder >= 3 && dGameCom::rnd() < 0.5f) { + mDemoSubstateTimer = 60; + mDemoState = 2; + } else { + mDemoSubstateTimer = mGoalTouchOrder * 5 + 10; + mDemoState = 1; + } + for (int i = 0; i < PLAYER_COUNT; i++) { + daYoshi_c *yoshi = daPyMng_c::getYoshi(i); + if (yoshi != nullptr && yoshi->isStatus(STATUS_GOAL_POLE_TOUCHED)) { + mDemoSubstateTimer += 14; + break; + } + } + case 1: + case 2: + if (mDemoSubstateTimer == 0) { + daPyDemoMng_c::mspInstance->mFlags |= 0x20; + if (mGoalTouchOrder == 0) { + daPyDemoMng_c::mspInstance->setDemoMode(daPyDemoMng_c::MODE_2, 0); + } + mDirection = DIR_LR_R; + mSpeed.set(0.0f, 0.0f, 0.0f); + mDemoSubstateTimer = 60; + mSpeedF = 1.9499999f; + float f = 2.6f; + if (mPowerup == POWERUP_MINI_MUSHROOM) { + f = 2.0f * f; + } else if (mDemoState == 2) { + mSpeedF = 2.25f; + f = 3.0f; + } + mPyMdlMng.setAnm(PLAYER_ANIM_RUN, f, 5.0f, 0.0f); + mDemoState = 3; + } + break; + case 3: + turnAngle(); + if (mPos.x > mWarpPos.x) { + float height; + if (dBc_c::checkGround(&mPos, &height, 0, 1, -1)) { + if (mPos.y < height + 1.0f) { + mPos.y = height + 1.0f; + } + } + mPos.z = -1800.0f; + } + if (sLib::chase(&mPos.x, mWarpPos.x + 32.0f, mSpeedF)) { + mPyMdlMng.setAnm(PLAYER_ANIM_WAIT); + mDemoState = 4; + onStatus(STATUS_6E); + } + break; + case 4: + mPos.z = -1800.0f; + break; + case 6: + setNormalJumpGravity(); + mSpeed.y += mAccelY; + if (mSpeed.y < sc_MaxFallSpeed) { + mSpeed.y = sc_MaxFallSpeed; + } + mPos.y += mSpeed.y; + mPos.x += mSpeedF; + if (isNowBgCross(BGC_FOOT)) { + mSpeedF = 0.0f; + mPyMdlMng.setAnm(PLAYER_ANIM_JUMPED); + setLandSE(); + mDemoState = 7; + } + break; + case 7: + if (mPyMdlMng.isAnmStop()) { + mPyMdlMng.setAnm(PLAYER_ANIM_WAIT); + mDemoState = 1; + mDemoSubstateTimer = mGoalTouchOrder * 5; + } + break; + } +} + +bool dAcPy_c::updateDemoKimePose(ClearType_e clearType) { + switch (mKimePoseMode) { + case KIME_POSE_NONE: + mPyMdlMng.setAnm(PLAYER_ANIM_WAIT); + if (mPowerup == POWERUP_PROPELLER_SHROOM) { + mKimePoseMode = KIME_POSE_PROPELLER; + mPyMdlMng.setAnm(PLAYER_ANIM_PL_GOAL_PUTON_CAP); + } else if (mPowerup == POWERUP_PENGUIN_SUIT) { + mKimePoseMode = KIME_POSE_PENGUIN; + mPyMdlMng.setAnm(PLAYER_ANIM_P_GOAL_PUTON_CAP); + } else { + if ( + mPyMdlMng.mpMdl->m_151 == mPyMdlMng.mpMdl->get151CheckVal() || + mPyMdlMng.mpMdl->m_151 == 3 || + mPyMdlMng.mpMdl->m_151 == 4 + ) { + mKimePoseMode = KIME_POSE_NO_HAT; + } else { + mKimePoseMode = KIME_POSE_WITH_HAT; + } + mPyMdlMng.setAnm(PLAYER_ANIM_GOAL_PUTON_CAP); + } + startKimePoseVoice(clearType); + // fallthrough + case KIME_POSE_WITH_HAT: { + dMarioMdl_c *mdl = (dMarioMdl_c *) mPyMdlMng.mpMdl; + if (mPyMdlMng.mpMdl->mAnm.checkFrame(41.0f)) { + mdl->fn_800cab00(1); + break; + } + if (mPyMdlMng.mpMdl->mAnm.checkFrame(107.0f)) { + mdl->fn_800cab00(0); + break; + } + if (mPyMdlMng.isAnmStop()) { + offStatus(STATUS_6C); + return true; + } + break; + } + case KIME_POSE_PROPELLER: + if (mPyMdlMng.mpMdl->mAnm.checkFrame(5.0f)) { + onStatus(STATUS_70); + break; + } + if (mPyMdlMng.mpMdl->mAnm.checkFrame(12.0f)) { + offStatus(STATUS_70); + break; + } + if (mPyMdlMng.isAnmStop()) { + offStatus(STATUS_6C); + return true; + } + break; + case KIME_POSE_PENGUIN: + case KIME_POSE_NO_HAT: + if (mPyMdlMng.isAnmStop()) { + offStatus(STATUS_6C); + return true; + } + break; + } + return false; +} + +void dAcPy_c::initializeDemoControl() { + releaseCarryActor(); + if (isStatus(STATUS_72)) { + clearPropelFlyUpTime(); + } +} + +bool dAcPy_c::setDemoCannonWarp(int delay, short angX, short angY) { + if (!isDemo()) { + changeDemoState(StateID_DemoCannonWarp, 0); + mAngle.x = angX + 0x2000; + mAngle.y = angY + 0x6000; + mDemoSubstateTimer = delay; + return true; + } + return false; +} + +void dAcPy_c::initializeState_DemoCannonWarp() { + mPyMdlMng.setAnm(PLAYER_ANIM_SHOOT); + mAccelY = 0.0f; + mMaxFallSpeed = sc_MaxFallSpeed; + m_78 = 60; +} + +void dAcPy_c::finalizeState_DemoCannonWarp() {} + +void dAcPy_c::executeState_DemoCannonWarp() { + switch (mDemoSubstate) { + case 0: + if (mDemoSubstateTimer == 0) { + mDemoSubstate = 1; + mAccelF = 0.0f; + mSpeed.y = mAng(mAngle.x).sin() * 4.0f; + mSpeedF = mAng(mAngle.x).cos() * 4.0f; + mSpeed.x = mSpeedF * mAng(mAngle.y).sin(); + mSpeed.z = mSpeedF * mAng(mAngle.y).cos(); + mAmiRelated2 = 1.0f; + dQuake_c::m_instance->shockMotor(mPlayerNo, dQuake_c::TYPE_5, 0, false); + startPlayerVoice(VOICE_CANNON_SHOT, 0); + } + break; + case 1: { + int ang = cM::atan2s(std::fabs(mSpeedF), mSpeed.y); + mAngle.x = 0x4000 - ang; + if (m_78 != 0) { + m_78--; + mAccelY = 0.0f; + } else { + if (mSpeed.y < 1.0f) { + mAccelY = -0.0625f; + } else { + mAccelY = -0.125f; + } + } + mSpeed.y += mAccelY; + if (mSpeed.y < sc_MaxFallSpeed) { + mSpeed.y = sc_MaxFallSpeed; + } + posMove(); + mVec3_c efPos; + mPyMdlMng.mpMdl->getJointPos(&efPos, 1); + static const float sc_slipEffectScale[] = { 0.5f, 0.8f, 1.0f }; + float s = mAmiRelated2 * sc_slipEffectScale[getTallType(-1)]; + mVec3_c efScale(s, s, s); + dEf::createPlayerEffect(mPlayerNo, &mSlipSmokeEffect, "Wm_mr_slipsmoke", 0, &efPos, nullptr, &efScale); + if (sLib::chase(&mAmiRelated2, 0.0f, 0.008f)) { + onStatus(STATUS_INVISIBLE); + mDemoSubstate = 2; + mDemoSubstateTimer = 30; + } + break; + } + case 2: + if (mDemoSubstateTimer == 0) { + mDemoSubstate = 3; + mDemoSubstateTimer = 90; + dEf::createPlayerEffect(mPlayerNo, "Wm_ob_warpcannonkira", 0, &mPos, nullptr, nullptr); + dAudio::g_pSndObjMap->startSound(SE_OBJ_WARP_CANNON_SHINE, mPos, 0); + } + break; + case 3: + if (mDemoSubstateTimer == 0) { + mDemoSubstate = 4; + dScStage_c::setNextScene(3, 0, dScStage_c::EXIT_0, dFader_c::FADER_CIRCLE_TARGET); + if (daPyDemoMng_c::mspInstance->mPlayerNo < 0) { + daPyDemoMng_c::mspInstance->mPlayerNo = mPlayerNo; + } + } + break; + } +} + +bool dAcPy_c::isEnableDokanInStatus() { + if (!daPlBase_c::isEnableDokanInStatus()) { + return false; + } + + if (isCarry() && getCarryPlayer() == nullptr) { + return false; + } + + if (getRidePlayer() != nullptr) { + return false; + } + + if (isChange()) { + return false; + } + + return !isStatus(STATUS_RIDE_YOSHI); +} + +bool dAcPy_c::setDokanIn(DokanDir_e dir) { + if (isStatus(STATUS_7E)) { + return false; + } + + dAcPy_c *carryPlayer = getCarryPlayer(); + if (carryPlayer != nullptr) { + int nextGotoNum; + switch (dir) { + case DOKAN_D: + if (mKey.buttonDown() && mBc.checkDokanDown(&mWarpPos, &nextGotoNum)) { + if (setDemoOutDokanAction(nextGotoNum, dir)) { + return true; + } + } + break; + case DOKAN_U: + if (carryPlayer->mKey.buttonUp() && mBc.checkDokanUp(&mWarpPos, &nextGotoNum)) { + carryPlayer->mWarpPos = mWarpPos; + if (carryPlayer->setDemoOutDokanAction(nextGotoNum, dir)) { + return true; + } + } + break; + default: + break; + } + return false; + } + + return daPlBase_c::setDokanIn(dir); +} + +void dAcPy_c::initDemoOutDokan() { + daPlBase_c::initDemoOutDokan(); + + if (getCarryPlayer() != nullptr) { + releaseCarryActor(); + } + + dAcPy_c *ridePlayer = getRidePlayer(); + if (ridePlayer != nullptr) { + ridePlayer->cancelCarry(this); + } +} + +void dAcPy_c::initialDoor() { + changeDemoState(StateID_DemoInDoor, 0); +} + +void dAcPy_c::initialJumpRight() { + changeDemoState(StateID_DemoInJump, 0); +} + +void dAcPy_c::initialJumpLeft() { + changeDemoState(StateID_DemoInJump, 1); +} + +void dAcPy_c::initialVine() { + changeDemoState(StateID_DemoInVine, 0); +} + +void dAcPy_c::initialSwim() { + changeState(StateID_Swim, SWIM_ARG_INITIAL); + changeDemoState(StateID_DemoNone, false); + onDemo(); + mSpeed.y = -1.0f; + bgCheck(0); +} + +void dAcPy_c::initialBlockJump() { + playOther(); + changeState(StateID_BlockJump, 0); + changeDemoState(StateID_DemoControl, CONTROL_DEMO_WAIT); +} + +void dAcPy_c::initialBlockJumpBelow() { + playOther(); + changeState(StateID_BlockJump, (void *) 1); // [This might have initially meant to be StateID_HipAttack]. + changeDemoState(StateID_DemoControl, CONTROL_DEMO_WAIT); +} + +void dAcPy_c::setCreateAction(int action) { + mExecStopReq |= BIT_FLAG(0) | BIT_FLAG(3); + if (daPyMng_c::isCreateBalloon(mPlayerNo) && setBalloonInNextgoto()) { + return; + } + if (daPyMng_c::mCreateItem[daPyMng_c::mPlayerType[mPlayerNo]] & 2) { + daYoshi_c *yoshi = daPyMng_c::createYoshi(mPos, daPyMng_c::getYoshiColor(mPlayerNo), this); + if (yoshi != nullptr) { + yoshi->mFruitCount = daPyMng_c::getYoshiFruit(mPlayerNo); + } + } else { + daPlBase_c::setCreateAction(action); + } +} + +void dAcPy_c::initChangeInit() { + if (!isStatus(STATUS_GOAL_POLE_TOUCHED)) { + playOther(); + } else { + playGoalOther(); + } + dAudio::pauseOffMove(mPlayerNo); +} + +bool dAcPy_c::executeChangeInit() { + if (mPowerup == mPowerupCopy2) { + return false; + } + setPowerup(mPowerupCopy2, 0); + stopOther(); + dAudio::pauseMove(mPlayerNo); + setChange(1); + if (mPowerup == POWERUP_MINI_MUSHROOM) { + float jumpSpeed = getJumpSpeed(); + if (mSpeed.y > jumpSpeed) { + mSpeed.y = jumpSpeed; + } + releaseCarryActor(); + } + return isPlayerGameStop(); +} + +int dAcPy_c::change_reverse_scale_set() { + int res = 6 - mChangeTimer / 6; + if (res < 0) { + res = 0; + } + /// @unofficial + static const float ratios[] = { + 0.4f, 0.2f, 0.6f, 0.4f, 0.8f, 0.6f, 1.0f + }; + /// @unofficial + struct Keyframe { + float startScaleY, endScaleY; + float startScaleX, endScaleX; + float unk; + }; + /// @unofficial + static const Keyframe data[] = { + { + 0.6f, 1.0f, + 0.6f, 1.0f, + 6.0f + }, + { + 0.36f, 1.0f, + 0.6f, 1.0f, + 20.0f + }, + { + 1.0f, 0.6f, + 1.0f, 0.6f, + -10.0f + }, + { + 0.6f, 1.0f, + 1.0f, 1.0f, + 10.0f + }, + { + 1.0f, 0.36f, + 1.0f, 0.6f, + -20.0f + }, + { + 1.0f, 0.6f, + 1.0f, 1.0f, + -10.0f + }, + { + 1.0f, 1.0f, + 1.0f, 1.0f, + 0.0f + }, + { + 0.0f, 0.0f, + 0.0f, 0.0f, + 0.0f + } + }; + if (mChangeTimer != 0) { + if (m_67 != 7) { + float ratioA = 1.0f - ratios[res]; + float ratioB = ratios[res]; + Keyframe curr = data[m_67]; + float x = curr.startScaleX * ratioA + curr.endScaleX * ratioB; + float y = curr.startScaleY * ratioA + curr.endScaleY * ratioB; + mScale.set(x, y, x); + m_159c = 0.0f; + if (isStatus(STATUS_HANG)) { + m_159c = curr.unk * ratioA; + } + } + } else { + mScale.set(1.0f, 1.0f, 1.0f); + m_159c = 0.0f; + } + return res; +} + +void dAcPy_c::initChangeNormal() { + mChangeTimer = 30; + int prevTallType = getTallType(mPowerupCopy); + int currTallType = getTallType(-1); + if (isStatus(STATUS_HANG)) { + static const float offsets[3] = { 21.0f, 11.0f, 0.0f }; + mPos.y += offsets[currTallType] - offsets[prevTallType]; + } + static const int tallTypeChange[3][3] = { + {7, 7, 1}, + {2, 7, 3}, + {4, 5, 6} + }; + m_67 = tallTypeChange[prevTallType][currTallType]; + switch (m_67) { + case 0: + case 1: + case 3: + if (mPowerup == POWERUP_PROPELLER_SHROOM) { + startSound(SE_PLY_CHANGE_PRPL, false); + } else if (mPowerup == POWERUP_PENGUIN_SUIT) { + startSound(SE_PLY_CHANGE_PNGN, false); + } else { + startSound(SE_PLY_CHANGE_BIG, false); + } + break; + case 2: + case 4: + startSound(SE_PLY_CHANGE_MAME, false); + break; + case 5: + case 6: + if (mPowerup == POWERUP_PROPELLER_SHROOM) { + startSound(SE_PLY_CHANGE_PRPL, false); + } else if (mPowerup == POWERUP_PENGUIN_SUIT) { + startSound(SE_PLY_CHANGE_PNGN, false); + } else if (mPowerup == POWERUP_FIRE_FLOWER || mPowerup == POWERUP_ICE_FLOWER) { + startSound(SE_PLY_CHANGE_BIG, false); + } else { + startSound(SE_PLY_CHANGE_SMALL, false); + } + break; + } +} + +bool dAcPy_c::executeChangeNormal() { + int frame = change_reverse_scale_set(); + PLAYER_POWERUP_e powerup = mPowerup; + if (mChangeTimer != 0) { + if ((frame & 1) != 0) { + powerup = mPowerupCopy; + } + if (powerup == POWERUP_NONE || powerup == POWERUP_MINI_MUSHROOM) { + powerup = mPowerup; + if ( + mPowerup == POWERUP_NONE && mPowerupCopy == POWERUP_MINI_MUSHROOM || + mPowerup == POWERUP_MINI_MUSHROOM && mPowerupCopy == POWERUP_NONE + ) { + powerup = POWERUP_NONE; + } else { + powerup = POWERUP_MUSHROOM; + } + } + } else { + setChange(0); + mPowerupChangeInvulnTimer = 8; + } + mPyMdlMng.mpMdl->setPlayerMode(powerup); + switch (powerup) { + case POWERUP_FIRE_FLOWER: + mPyMdlMng.mpMdl->setColorType(1); + break; + case POWERUP_ICE_FLOWER: + mPyMdlMng.mpMdl->setColorType(2); + break; + default: + mPyMdlMng.mpMdl->setColorType(0); + break; + } + return isPlayerGameStop(); +} + +void dAcPy_c::setChange(int mode) { + mChangeType = mode; + typedef void (dAcPy_c::*ChangeInitProc)(); + static ChangeInitProc l_changeInitProc[] = { + &dAcPy_c::initChangeInit, + &dAcPy_c::initChangeNormal + }; + (this->*l_changeInitProc[mChangeType])(); + updateChange(); + setCcData(); +} + +bool dAcPy_c::updateChange() { + typedef bool (dAcPy_c::*ChangeActionProc)(); + static ChangeActionProc l_changeActionProc[] = { + &dAcPy_c::executeChangeInit, + &dAcPy_c::executeChangeNormal + }; + if (mChangeType >= 2) { + setChange(0); + return false; + } + if (mChangeTimer != 0) { + mChangeTimer--; + } + if ((this->*l_changeActionProc[mChangeType])()) { + mVisible = true; + setBcData(0); + bgCheck(1); + mBgPressActive = 0; + return true; + } + return false; +} + +void dAcPy_c::fn_801416c0(PLAYER_POWERUP_e powerup) { + mPowerupCopy2 = powerup; + setPowerup(powerup, 0); +} + +void dAcPy_c::initializeState_DemoStartWait() { + daPlBase_c::initializeState_DemoStartWait(); +} + +void dAcPy_c::executeState_DemoStartWait() { + if (!isNowBgCross(BGC_WATER_SHALLOW)) { + bgCheck(0); + if (isNowBgCross(BGC_WATER_SHALLOW)) { + onOldBgCross(BGC_WATER_SHALLOW); + changeState(daPlBase_c::StateID_Swim, SWIM_ARG_INITIAL); // [why daPlBase_c?] + } + } + daPlBase_c::executeState_DemoStartWait(); +} + +void dAcPy_c::finalizeState_DemoStartWait() { + daPlBase_c::finalizeState_DemoStartWait(); +} + +void dAcPy_c::setFireBallDamage(u8 type) { + switch (type) { + case 1: + startPlayerVoice(VOICE_DAMAGE_FIRE, 0); + break; + case 2: + startPlayerVoice(VOICE_DAMAGE_FREEZE, 0); + break; + default: + startPlayerVoice(VOICE_HIP_ATTACKED, 0); + break; + } + dQuake_c::m_instance->shockMotor(mPlayerNo, dQuake_c::TYPE_7, 0, false); +} + +///< @unofficial +const int l_tall_type_offsets[] = { 0x8000, 0xF800, 0x1F800 }; + +const sCcDatNew l_cc_data_mame = { + { 0.0f, 4.0f }, + { 2.0f, 4.0f } +}; + +const sCcDatNew l_cc_data_normal = { + { 0.0f, 7.0f }, + { 4.0f, 7.0f } +}; + +const sCcDatNew l_cc_data_super = { + { 0.0f, 12.0f }, + { 6.0f, 12.0f } +}; + +const sCcDatNew l_cc_data_propel = { + { 0.0f, 12.0f }, + { 6.0f, 12.0f } +}; + +const sCcDatNew l_cc_data_normal_sit = { + { 0.0f, 3.5f }, + { 4.0f, 3.5f } +}; + +const sCcDatNew l_cc_data_super_sit = { + { 0.0f, 7.0f }, + { 6.0f, 7.0f } +}; + +const sCcDatNew l_cc_data_normal_swim = { + { 0.0f, 8.0f }, + { 4.0f, 6.0f } +}; + +const sCcDatNew l_cc_data_super_swim = { + { 0.0f, 15.0f }, + { 6.0f, 9.0f } +}; + +const sCcDatNew l_cc_data_normal_waterwalk = { + { 0.0f, 7.5f }, + { 4.0f, 7.5f } +}; + +const sCcDatNew l_cc_data_super_waterwalk = { + { 0.0f, 14.0f }, + { 6.0f, 14.0f } +}; + +const sCcDatNew l_cc_data_penguin_slid = { + { 6.0f, 8.0f }, + { 12.0f, 8.0f } +}; + +enum CcSizeDataIndex_e { + CC_SIZE_DATA_MAME, + CC_SIZE_DATA_NORMAL, + CC_SIZE_DATA_SUPER, + CC_SIZE_DATA_PROPEL, + CC_SIZE_DATA_NORMAL_SIT, + CC_SIZE_DATA_SUPER_SIT, + CC_SIZE_DATA_NORMAL_SWIM, + CC_SIZE_DATA_SUPER_SWIM, + CC_SIZE_DATA_NORMAL_WATERWALK, + CC_SIZE_DATA_SUPER_WATERWALK, + CC_SIZE_DATA_PENGUIN_SLID +}; + +const sCcDatNew *l_cc_size_data[] = { + &l_cc_data_mame, + &l_cc_data_normal, + &l_cc_data_super, + &l_cc_data_propel, + &l_cc_data_normal_sit, + &l_cc_data_super_sit, + &l_cc_data_normal_swim, + &l_cc_data_super_swim, + &l_cc_data_normal_waterwalk, + &l_cc_data_super_waterwalk, + &l_cc_data_penguin_slid +}; + +const CcSizeDataIndex_e l_mode_cc_size_data[] = { + CC_SIZE_DATA_NORMAL, CC_SIZE_DATA_SUPER, CC_SIZE_DATA_SUPER, CC_SIZE_DATA_MAME, CC_SIZE_DATA_PROPEL, CC_SIZE_DATA_SUPER, CC_SIZE_DATA_SUPER +}; + +const sCcDatNewF scCcData = { + { + { 0.0f, 8.0f }, + { 3.0f, 8.0f } + }, + CC_KIND_PLAYER, + CC_ATTACK_NONE, + (u8) ~BIT_FLAG(CC_KIND_YOSHI), + (u32) ~(BIT_FLAG(CC_ATTACK_NONE) | BIT_FLAG(CC_ATTACK_YOSHI_MOUTH) | BIT_FLAG(CC_ATTACK_SAND_PILLAR)), + CC_STATUS_NONE, + dAcPy_c::ccCallBack +}; + +const sCcDatNewF scAtCcData = { + { + { 0.0f, 8.0f }, + { 6.0f, 6.0f } + }, + CC_KIND_PLAYER_ATTACK, + CC_ATTACK_NONE, + (u8) ~(BIT_FLAG(CC_KIND_YOSHI) | BIT_FLAG(CC_KIND_ITEM) | BIT_FLAG(CC_KIND_TAMA)), + 0, + CC_STATUS_NONE, + dAcPy_c::atCcCallBack +}; + +bool dAcPy_c::ccCheckAttack(dCc_c *self, dCc_c *other) { + dAcPy_c *selfPlayer = (dAcPy_c *) self->getOwner(); + dActor_c *otherActor = (dActor_c *) other->getOwner(); + + if (other->mCcData.mKind == CC_KIND_PLAYER || other->mCcData.mKind == CC_KIND_PLAYER_ATTACK) { + if (selfPlayer->mNoInteractTimer != 0) { + return false; + } + if (otherActor->mKind == STAGE_ACTOR_PLAYER) { + dAcPy_c *otherPlayer = (dAcPy_c *) otherActor; + if (otherPlayer->mNoInteractTimer != 0) { + return false; + } + if (selfPlayer->checkRideActor(otherPlayer)) { + return false; + } + } + } + + if (other->mCcData.mAttack == CC_ATTACK_SPIN) { + if (otherActor->mKind == STAGE_ACTOR_PLAYER) { + dAcPy_c *otherPlayer = (dAcPy_c *) otherActor; + if (!otherPlayer->checkCarryActor(selfPlayer)) { + selfPlayer->checkCarryActor(otherPlayer); + } + return true; + } + return true; + } + + if (selfPlayer->isNoDamage()) { + return false; + } + + dAcPy_c *otherPlayer = (dAcPy_c *) otherActor; + + switch (other->mCcData.mAttack) { + case CC_ATTACK_HIP_ATTACK: + case CC_ATTACK_SPIN_FALL: { + DamageType_e damageType = DAMAGE_HIP_ATTACK; + if (selfPlayer->isClimbing()) { + damageType = DAMAGE_CLIMB; + } + if (selfPlayer->setDamage(otherActor, damageType)) { + if (other->mCcData.mAttack == CC_ATTACK_HIP_ATTACK) { + otherPlayer->setVsPlHipAttackEffect(); + } + + selfPlayer->setHipAttackDamagePlayer(otherPlayer); + } + return true; + } + case CC_ATTACK_WIRE_NET: + selfPlayer->setDamage(other->getOwner(), DAMAGE_CLIMB); + return true; + case CC_ATTACK_FIREBALL: + case CC_ATTACK_ICEBALL: + if (selfPlayer->getPlrNo() != otherActor->getPlrNo() && !selfPlayer->isStatus(STATUS_IS_SPIN_HOLD_REQ)) { + selfPlayer->setFireBallDamage(other->mCcData.mAttack); + } + return true; + case CC_ATTACK_YOSHI_BULLET: + case CC_ATTACK_YOSHI_FIRE: + case CC_ATTACK_ICE_2: + if (selfPlayer->getPlrNo() != otherActor->getPlrNo() && !selfPlayer->isStatus(STATUS_IS_SPIN_HOLD_REQ)) { + if (selfPlayer->isStatus(STATUS_51)) { + selfPlayer->mSpeedF = daPlBase_c::sc_DirSpeed[other->getOwner()->mDirection]; + selfPlayer->mNoInteractTimer = 0; + } else { + selfPlayer->mNoInteractTimer = 30; + if (!selfPlayer->setDamage(other->getOwner(), DAMAGE_6)) { + return false; + } + } + selfPlayer->setFireBallDamage(other->mCcData.mAttack); + } + return true; + default: + return false; + } +} + +bool dAcPy_c::ccCheckStamp(dCc_c *self, dCc_c *other) { + dAcPy_c *selfPlayer = (dAcPy_c *) self->getOwner(); + daPlBase_c *otherActor = (daPlBase_c *) other->getOwner(); + + if ( + selfPlayer->mSpeed.y <= 0.0f && + !selfPlayer->isStatus(STATUS_JUMP_DAI_COOLDOWN) && + !selfPlayer->isDemoType(DEMO_PLAYER) && + selfPlayer->isStatus(STATUS_CAN_LAND) + ) { + if (otherActor->mKind == STAGE_ACTOR_YOSHI) { + daYoshi_c *yoshi = (daYoshi_c *) otherActor; + if ( + self->getCenterPosY() > other->getUnderPos() && + (!selfPlayer->isNowBgCross(BGC_FOOT) || selfPlayer->isOnSinkSand()) && + yoshi->m_94 == 0 + ) { + return yoshi->fn_8014eb70(selfPlayer, 0); + } + } + if (selfPlayer->isEnableStampPlayerJump(self, other)) { + if (otherActor->isStatus(STATUS_JUMP) && otherActor->mSpeed.y > 0.0f) { + selfPlayer->setStampPlayerJump(true, self->mCollOffsetY[CC_KIND_PLAYER]); + otherActor->setStampReduction(); + return true; + } + if (selfPlayer->setPlayerJumpDai(otherActor)) { + return true; + } + } + } + return false; +} + +bool dAcPy_c::ccCheckSideHit(dCc_c *self, dCc_c *other) { + dAcPy_c *selfPlayer = (dAcPy_c *) self->getOwner(); + daPlBase_c *otherActor = (daPlBase_c *) other->getOwner(); + + if (otherActor->isDemo()) { + selfPlayer->setCcPlayerRev(self, other, 1.0f, CC_KIND_PLAYER); + return true; + } + + static const float sCcRevRate[3][3] = { + { 0.5f, 1.0f, 1.0f }, + { 0.0f, 0.5f, 0.5f }, + { 0.0f, 0.5f, 0.5f }, + }; + u8 selfTallType = selfPlayer->getTallType(-1); + u8 otherTallType = otherActor->getTallType(-1); + selfPlayer->setCcPlayerRev(self, other, sCcRevRate[selfTallType][otherTallType], CC_KIND_PLAYER); + + return true; +} + +void dAcPy_c::ccCallBack(dCc_c *self, dCc_c *other) { + dActor_c *otherActor; + dAcPy_c *selfPlayer; + + selfPlayer = (dAcPy_c *) self->getOwner(); + otherActor = (dActor_c *) other->getOwner(); + + if (other->mCcData.mKind == CC_KIND_PLAYER || other->mCcData.mKind == CC_KIND_YOSHI) { + daPlBase_c *otherPlayer = (daPlBase_c *) otherActor; + if (selfPlayer == otherPlayer->mpNoHitPlayer || otherPlayer == selfPlayer->mpNoHitPlayer) { + return; + } + } + + if (ccCheckAttack(self, other)) { + return; + } + + if (other->mCcData.mKind == CC_KIND_PLAYER && otherActor->mKind == STAGE_ACTOR_PLAYER) { + daPlBase_c *otherPlayer = (daPlBase_c *) otherActor; + if (selfPlayer->checkRideActor(otherPlayer)) { + return; + } + if (ccCheckStamp(self, other)) { + return; + } + if (ccCheckSideHit(self, other)) { + return; + } + } + + if (other->mCcData.mKind == CC_KIND_YOSHI) { + daYoshi_c *yoshi = (daYoshi_c *) otherActor; + if (selfPlayer->checkRideActor(yoshi)) { + return; + } + if (ccCheckStamp(self, other)) { + return; + } + if (yoshi->m_94 == 0) { + return; + } + + static const float sCcRevRate[] = { 1.0f, 0.8f, 0.6f }; + selfPlayer->setCcPlayerRev(self, other, sCcRevRate[selfPlayer->getTallType(-1)], CC_KIND_YOSHI); + } +} + +void dAcPy_c::setCcDataDirect() { + const sCcDatNew *ccData = l_cc_size_data[l_mode_cc_size_data[mPowerup]]; + m_0c.x = ccData->mOffset.x; + m_0c.y = ccData->mOffset.y + m_1598 + m_159c; + mCc.mCcData.mBase.mOffset.set(m_0c.x, m_0c.y); + mCc.mCcData.mBase.mSize.set(ccData->mSize.x, ccData->mSize.y); +} + +void dAcPy_c::setCcAtNetPunch() { + float s = mPyMdlMng.getSomeScale(); + mAttCc1.mCcData.mAttack = CC_ATTACK_WIRE_NET; + mAttCc1.mCcData.mBase.mOffset.set(s * 8.0f, s * 16.0f); + mAttCc1.mCcData.mBase.mSize.set(s * 12.0f, s * 12.0f); +} + +void dAcPy_c::setCcAtSpin() { + float y = (getModelHeight() + 4.0f) / 2.0f; + mAttCc1.mCcData.mBase.mOffset.set(mCc.mCcData.mBase.mOffset.x, y); + float x = mCc.mCcData.mBase.mSize.x; + mAttCc1.mCcData.mBase.mSize.set(x * 3.5f, y); + mAttCc1.mCcData.mVsKind |= BIT_FLAG(CC_KIND_PLAYER_ATTACK); + mAttCc1.mCcData.mAttack = CC_ATTACK_SPIN; + mAttCc1.mCcData.mVsDamage = BIT_FLAG(CC_ATTACK_SPIN); + mCc.mCcData.mVsDamage &= ~BIT_FLAG(CC_ATTACK_SPIN); +} + +void dAcPy_c::setCcAtSpinFall() { + mAttCc1.mCcData.mBase.mOffset.set(0.0f, 10.0f); + mAttCc1.mCcData.mBase.mSize.set(12.0f, 10.0f); + mAttCc1.mCcData.mAttack = CC_ATTACK_SPIN_FALL; + setCcAtBody(CC_ATTACK_SPIN_FALL); +} + +void dAcPy_c::getCcBounds(sRangeDataF *bounds) { + float f = 18.0f; + if (mPowerup == POWERUP_MINI_MUSHROOM) { + f = 8.0f; + } else if (mPowerup == POWERUP_NONE) { + f = 16.0f; + } + if (bounds == nullptr) { + return; + } + float h = (getModelHeight() + 4.0f) / 2.0f; + bounds->mOffset.x = 0.0f; + bounds->mSize.x = f; + bounds->mOffset.y = h; + bounds->mSize.y = h; +} + +void dAcPy_c::setCcAtSpinLiftUp() { + sRangeDataF bounds; + getCcBounds(&bounds); + mAttCc1.mCcData.mBase.mOffset.x = bounds.mOffset.x; + mAttCc1.mCcData.mBase.mOffset.y = bounds.mOffset.y; + mAttCc1.mCcData.mBase.mSize.x = bounds.mSize.x; + mAttCc1.mCcData.mBase.mSize.y = bounds.mSize.y; + mAttCc1.mCcData.mAttack = CC_ATTACK_SPIN_LIFT_UP; + checkSpinLiftUpRoofHeight(); +} + +void dAcPy_c::setCcData() { + int sizeIndex = l_mode_cc_size_data[mPowerup]; + if (mPyMdlMng.getFlags() & 1) { + switch (getPowerup()) { + case POWERUP_MINI_MUSHROOM: + break; + case POWERUP_NONE: + sizeIndex = CC_SIZE_DATA_NORMAL_SIT; + break; + default: + sizeIndex = CC_SIZE_DATA_SUPER_SIT; + break; + } + } else if (mPyMdlMng.getFlags() & 0x10) { + switch (getPowerup()) { + case POWERUP_MINI_MUSHROOM: + break; + case POWERUP_NONE: + sizeIndex = CC_SIZE_DATA_NORMAL_SWIM; + break; + default: + sizeIndex = CC_SIZE_DATA_SUPER_SWIM; + break; + } + } else if (isStatus(STATUS_PENGUIN_SLIDE)) { + sizeIndex = CC_SIZE_DATA_PENGUIN_SLID; + } else if (isStatus(STATUS_SWIM)) { + switch (getPowerup()) { + case POWERUP_MINI_MUSHROOM: + break; + case POWERUP_NONE: + sizeIndex = CC_SIZE_DATA_NORMAL_WATERWALK; + break; + default: + sizeIndex = CC_SIZE_DATA_SUPER_WATERWALK; + break; + } + } + + if (isStatus(STATUS_PENGUIN_SWIM)) { + onStatus(STATUS_78); + mMtx_c mtx; + mVec3_c pos; + mPyMdlMng.mpMdl->getJointMtx(&mtx, 1); + mtx.concat(mMtx_c::createTrans(2.0f, 0.0f, 0.0f)); + mtx.multVecZero(pos); + mCc.mCcData.mBase.mSize.set(6.0f, 6.0f); + mCc.mCcData.mBase.mOffset.set(pos.x - mPos.x, pos.y - mPos.y); + mPyMdlMng.mpMdl->getJointMtx(&mtx, mPyMdlMng.mpMdl->getFaceJointIdx()); + mtx.concat(mMtx_c::createTrans(0.0f, -4.0f, 0.0f)); + mtx.multVecZero(pos); + mCc1.mCcData.mBase.mSize.set(6.0f, 6.0f); + mCc1.mCcData.mBase.mOffset.set(pos.x - mPos.x, pos.y - mPos.y); + return; + } + + const sCcDatNew *ccData = l_cc_size_data[sizeIndex]; + float x = ccData->mOffset.x; + if (mDirection == DIR_LR_L) { + x = -x; + } + float sx = ccData->mSize.x; + float sy = ccData->mSize.y; + m_0c.set(x, ccData->mOffset.y + m_1598 + m_159c); + mCc.mCcData.mBase.mSize.set(sx, sy); + mCc.mCcData.mBase.mOffset.setX(m_0c.x); + if (mPyMdlMng.mpMdl->mFlags & 4) { + mMtx_c mtx; + mVec3_c pos; + mVec3_c anklePos = getAnkleCenterPos(); + float tmp = anklePos.y - 2.0f; + if (tmp > mPos.y) { + tmp = mPos.y; + } + mPyMdlMng.mpMdl->getJointMtx(&mtx, mPyMdlMng.mpMdl->getFaceJointIdx()); + mtx.concat(mMtx_c::createTrans(0.0f, -4.0f, 0.0f)); + mtx.multVecZero(pos); + float tmp1 = (pos.y + tmp) / 2.0f; + mCc.mCcData.mBase.mOffset.y = tmp1 - mPos.y; + float tmp2 = (pos.y - tmp) / 2.0f; + mCc.mCcData.mBase.mSize.y = std::fabs(tmp2); + } else { + mCc.mCcData.mBase.mOffset.y = m_0c.y; + } + dAcPy_c *ridePlayer = getRidePlayer(); + if (ridePlayer != nullptr && ridePlayer->mPowerup == POWERUP_NONE) { + if (sizeIndex == 2) { + mCc.mCcData.mBase.mOffset.y = 16.0f; + mCc.mCcData.mBase.mSize.y = 8.0f; + mCc.mCcData.mBase.mSize.x = 4.0f; + } else if (sizeIndex == 1) { + mCc.mCcData.mBase.mOffset.y = 9.0f; + mCc.mCcData.mBase.mSize.y = 5.0f; + mCc.mCcData.mBase.mSize.x = 4.0f; + } + } + if (isStatus(STATUS_8E) || isStatus(STATUS_4F)) { + mCc.mCcData.mVsKind &= ~(BIT_FLAG(CC_KIND_YOSHI) | BIT_FLAG(CC_KIND_PLAYER) | BIT_FLAG(CC_KIND_PLAYER_ATTACK)); + } else { + mCc.mCcData.mVsKind |= (BIT_FLAG(CC_KIND_YOSHI) | BIT_FLAG(CC_KIND_PLAYER) | BIT_FLAG(CC_KIND_PLAYER_ATTACK)); + } +} + +void dAcPy_c::atCcCallBack(dCc_c *self, dCc_c *other) { + dActor_c *otherActor; + dAcPy_c *selfPlayer; + + selfPlayer = (dAcPy_c *) self->getOwner(); + otherActor = (dActor_c *) other->getOwner(); + + if (self->mCcData.mAttack == CC_ATTACK_SPIN_LIFT_UP) { + selfPlayer->checkSpinLiftUpReserve(other); + return; + } + + if (selfPlayer->isNoDamage()) { + return; + } + + if (other->mCcData.mKind == CC_KIND_PLAYER) { + dAcPy_c *otherPlayer = (dAcPy_c *) otherActor; + if (selfPlayer->mNoInteractTimer != 0 || otherPlayer->mNoInteractTimer != 0) { + return; + } + } + + if (self->mCcData.mAttack != CC_ATTACK_PENGUIN_SLIDE) { + return; + } + + if (other->mCcData.mAttack != CC_ATTACK_PENGUIN_SLIDE) { + return; + } + + selfPlayer->setDamage(otherActor, DAMAGE_CLIMB); +} + +const sBcPlayerPointData scBgPointData_Mame[5] = { + { + { 0xC8001, -0x1800, 0x1000, 0x0 }, + { 0x5C0001, -0x1000, 0x0, 0x7A00 }, + { 0xC0001, 0x3000, 0x4000, 0x5000 }, + { 0xC0001, 0x4000, 0x1000, 0x0 } + }, + { + { 0xC8001, -0x1800, 0x1000, 0x0 }, + { 0x5C0001, -0x1000, 0x0, 0x7A00 }, + { 0xC0001, 0x2800, 0x3800, 0x5000 }, + { 0xC0001, 0x4000, 0x1000, 0x0 } + }, + { + { 0xC8001, -0x2000, 0x1000, 0x0 }, + { 0x5C0001, -0x1000, 0x0, 0x1000 }, + { 0xC0001, -0x4000, -0x4000, 0x3000 }, + { 0xC0001, 0x4000, 0x1000, 0x0 } + }, + { + { 0xC8001, -0x1800, 0x1000, 0x0 }, + { 0x5C0001, -0x1000, 0x0, 0x7800 }, + { 0xC0001, 0x3000, 0x4000, 0x5000 }, + { 0xC0001, 0x4000, 0x1000, 0x0 } + }, + { + { 0xC8001, -0x1800, 0x1000, 0x0 }, + { 0x5C0001, -0x1000, 0x0, 0x7800 }, + { 0xC0001, 0x2800, 0x3800, 0x5000 }, + { 0xC0001, 0x4000, 0x1000, 0x0 } + } +}; + +const sBcPlayerPointData scBgPointData_Normal[5] = { + { + { 0xC8001, -0x5000, 0x4000, 0x0 }, + { 0x5C0001, -0x2000, 0x1000, 0x10000 }, + { 0xC0001, 0x4000, 0xB000, 0x8000 }, + { 0xC0001, 0x8000, 0x1000, 0x2000 } + }, + { + { 0xC8001, -0x5000, 0x4000, 0x0 }, + { 0x5C0001, -0x2000, 0x1000, 0xC000 }, + { 0xC0001, 0x4000, 0x8800, 0x8000 }, + { 0xC0001, 0x8000, 0x1000, 0x2000 } + }, + { + { 0xC8001, -0x5000, 0x4000, 0x0 }, + { 0x5C0001, -0x2000, 0x1000, 0x1000 }, + { 0xC0001, -0x4000, -0xE000, 0x8000 }, + { 0xC0001, 0x8000, 0x1000, 0x2000 } + }, + { + { 0xC8001, -0x5000, 0x4000, 0x0 }, + { 0x5C0001, -0x2000, 0x1000, 0x10000 }, + { 0xC0001, 0x4000, 0xA000, 0x8000 }, + { 0xC0001, 0x8000, 0x1000, 0x2000 } + }, + { + { 0xC8001, -0x5000, 0x4000, 0x0 }, + { 0x5C0001, -0x2000, 0x1000, 0xC000 }, + { 0xC0001, 0x4000, 0xA000, 0x8000 }, + { 0xC0001, 0x8000, 0x1000, 0x2000 } + } +}; + +const sBcPlayerPointData scBgPointData_Super[5] = { + { + { 0xC8001, -0x5000, 0x4000, 0x0 }, + { 0x9C0001, -0x2000, 0x1000, 0x1B000 }, + { 0xC0001, 0x4000, 0x13000, 0x8000 }, + { 0xC0001, 0x10000, 0x1000, 0x2000 } + }, + { + { 0xC8001, -0x5000, 0x4000, 0x0 }, + { 0x9C0001, -0x2000, 0x1000, 0x10000 }, + { 0xC0001, 0x4000, 0xB000, 0x8000 }, + { 0xC0001, 0xC000, 0x1000, 0x2000 } + }, + { + { 0xC8001, -0x5000, 0x4000, 0x0 }, + { 0x9C0001, -0x2000, 0x1000, 0x1000 }, + { 0xC0001, -0x4000, -0x18000, 0x8000 }, + { 0xC0001, 0x10000, 0x1000, 0x2000 } + }, + { + { 0xC8001, -0x5000, 0x4000, 0x0 }, + { 0x9C0001, -0x2000, 0x1000, 0x1B000 }, + { 0xC0001, 0x4000, 0x13000, 0x8000 }, + { 0xC0001, 0x10000, 0x1000, 0x2000 } + }, + { + { 0xC8001, -0x5000, 0x4000, 0x0 }, + { 0x9C0001, -0x2000, 0x1000, 0x12000 }, + { 0xC0001, 0x4000, 0x10000, 0x8000 }, + { 0xC0001, 0x10000, 0x1000, 0x2000 } + } +}; + +const sBcPlayerPointData scBgPointData_PenguinSlide = { + { 0xC8101, -0xA000, 0x9000, 0x0 }, + { 0x9C0101, -0x7000, 0x6000, 0x12000 }, + { 0x129C0101, 0x4000, 0xD000, 0x10000 }, + { 0x0, 0x0, 0x0, 0x0 } +}; + +const sBcPlayerPointData scBgPointData_PenguinSwim = { + { 0xC8001, -0x5000, 0x4000, 0x4000 }, + { 0x9C0001, -0x2000, 0x1000, 0x1B000 }, + { 0xC0001, 0x8000, 0x17000, 0x8000 }, + { 0x0, 0x0, 0x0, 0x0 } +}; + +const sBcPlayerPointData *scBgPointData[POWERUP_COUNT] = { + scBgPointData_Normal, + scBgPointData_Super, + scBgPointData_Super, + scBgPointData_Mame, + scBgPointData_Super, + scBgPointData_Super, + scBgPointData_Super, +}; + +const sBcPlayerPointData *dAcPy_c::getBgPointData_Powerup(PLAYER_POWERUP_e powerup, int index) { + return &scBgPointData[powerup][index]; +} + +float dAcPy_c::getStandHeadBgPointY() { + return getBgPointData_Powerup(mPowerup, 0)->mHead.mOffset / 4096.0f; +} + +const sBcPlayerPointData *dAcPy_c::getBgPointData() { + if (isStatus(STATUS_PENGUIN_SLIDE) && !isStatus(STATUS_INITIAL_SLIDE)) { + return &scBgPointData_PenguinSlide; + } + if (isStatus(STATUS_PENGUIN_SWIM)) { + return &scBgPointData_PenguinSwim; + } + u32 flags = mPyMdlMng.mpMdl->mFlags; + int bgDataIndex = 0; + if (flags & BIT_FLAG(0)) { + if (mPowerup != POWERUP_MINI_MUSHROOM) { + bgDataIndex = 1; + } + } else if (flags & BIT_FLAG(2)) { + bgDataIndex = 2; + } else if (flags & BIT_FLAG(4)) { + bgDataIndex = 3; + } else if (mPyMdlMng.mpMdl->mCurrAnmID == PLAYER_ANIM_STAR_ROLL_DUPLICATE) { + bgDataIndex = 4; + } + return getBgPointData_Powerup(mPowerup, bgDataIndex); +} + +void dAcPy_c::setBcData(int setInstant) { + offStatus(STATUS_B8); + if (isItemKinopio()) { + onStatus(STATUS_B8); + } + const sBcPlayerPointData *data = getBgPointData(); + sBcPointData footData = data->mFoot; + sBcPointData headData = data->mHead; + sBcPointData wallData = data->mWall; + sBcPointData vineData = data->mVine; + if (!isMameAction() && !isStatus(STATUS_4E) && !isStatus(STATUS_ENEMY_STAGE_CLEAR)) { + footData.mFlags |= 0x200000; + } + if (isStatus(STATUS_BD)) { + footData.mFlags |= 0x10900100; + wallData.mFlags |= 0x10900100; + headData.mFlags |= 0x10900100; + m_15b8 = 5; + } else if (isStatus(STATUS_HANG)) { + footData.mFlags |= 0x80000000; + } else if (isStatus(STATUS_VINE)) { + footData.mFlags |= 0x2000; + wallData.mSupMargin = headData.mOffset - 0x2000; + } else if (isStatus(STATUS_SPIN_HIP_ATTACK_FALL)) { + footData.mFlags |= 0xd00000; + } else if (isState(StateID_HipAttack)) { + switch (mPyMdlMng.mpMdl->mCurrAnmID) { + case PLAYER_ANIM_HIPAT: + if (mSpeed.y < 0.0f) { + footData.mFlags |= 0x500000; + if (isStatus(STATUS_C4)) { + footData.mFlags |= 0x800000; + } + } + break; + case PLAYER_ANIM_HIPED: + if (isStatus(STATUS_C4)) { + footData.mFlags |= 0x900000; + } + break; + } + } else { + if (isStatus(STATUS_52)) { + headData.mFlags |= 0x4000000; + wallData = getBgPointData_Powerup(mPowerup, 1)->mWall; + float y = mPos.y + getStandHeadBgPointY() - 1.0f; + mVec3_c pos(mPos.x, mPos.y + 4.0f, mPos.z); + float height; + if (dBc_c::checkTenjou(&pos, &height, mLayer, mAmiLayer)) { + if (height < y && !dBc_c::checkBg(pos.x, height + 4.0f, mLayer, mAmiLayer, 0x10)) { + footData.mFlags |= 0x800000; + } + } + } + } + if (isChange()) { + headData.mFlags |= 0x4000000; + } + if (isStatus(STATUS_30)) { + footData.mFlags |= 0x10000; + } + if (isStatus(STATUS_A4)) { + footData.mFlags |= 8; + } + if (isStatus(STATUS_7F)) { + footData.mFlags |= 0x80000000; + wallData.mFlags |= 0x80000000; + headData.mFlags |= 0x80000000; + } + if (m_15b8 != 0) { + footData.mFlags |= 0x100; + wallData.mFlags |= 0x100; + headData.mFlags |= 0x100; + } + if (mPowerup == POWERUP_PENGUIN_SUIT) { + footData.mFlags |= 0x10; + } + if (isStatus(STATUS_EXTRA_PUSH_FORCE)) { + footData.mFlags |= 0x20; + } + if (isStar()) { + wallData.mFlags |= 0x2000000; + headData.mFlags |= 0x2000000; + } + if (isStatus(STATUS_82)) { + headData.mFlags |= 0x4000000; + } + reviseBcDataCarryHardBlock(wallData, headData); + reviseBcDataCarryPlayer(wallData, headData); + if (isStatus(STATUS_PENGUIN_SWIM)) { + float angY = mAngle.y.sin() * 19456.0f; + mAng x = mAngle.x; + if (x > 0x2000) { + x -= 0x2000; + angY -= x.sin() * mAngle.y.sin() * 81920.0f; + } + headData.mInfMargin += angY; + headData.mSupMargin += angY; + } + if (setInstant == 1) { + mFootBcData = footData; + mHeadBcData = headData; + mWallBcData = wallData; + mVineBcData = vineData; + } else { + sLib::chase(&mFootBcData.mInfMargin, footData.mInfMargin, 0x1000); + sLib::chase(&mFootBcData.mSupMargin, footData.mSupMargin, 0x1000); + sLib::chase(&mFootBcData.mOffset, footData.mOffset, 0x1000); + + sLib::chase(&mHeadBcData.mInfMargin, headData.mInfMargin, 0x1000); + sLib::chase(&mHeadBcData.mSupMargin, headData.mSupMargin, 0x1000); + + sLib::chase(&mWallBcData.mInfMargin, wallData.mInfMargin, 0x1000); + sLib::chase(&mWallBcData.mSupMargin, wallData.mSupMargin, 0x1000); + sLib::chase(&mWallBcData.mOffset, wallData.mOffset, 0x1000); + + sLib::chase(&mVineBcData.mInfMargin, vineData.mInfMargin, 0x1000); + sLib::chase(&mVineBcData.mSupMargin, vineData.mSupMargin, 0x1000); + sLib::chase(&mVineBcData.mOffset, vineData.mOffset, 0x1000); + + if (mHeadBcData.mOffset < headData.mOffset) { + mVec3_c pos(mPos.x, mPos.y + mHeadBcData.mOffset / 4096.0f + 1.0f, mPos.z); + float height; + if (dBc_c::checkTenjou(&pos, &height, mLayer, mAmiLayer)) { + if (height < mPos.y + headData.mOffset / 4096.0f) { + float tmp = height - mPos.y; + if (tmp < 0.0f) { + tmp = 0.0f; + } + headData.mOffset = (int) (tmp * 4096.0f); + } + } + } + sLib::chase(&mHeadBcData.mOffset, headData.mOffset, 0x1000); + mFootBcData.mFlags = footData.mFlags; + mHeadBcData.mFlags = headData.mFlags; + mWallBcData.mFlags = wallData.mFlags; + mVineBcData.mFlags = vineData.mFlags; + } + mBc.set(this, mFootBcData, mHeadBcData, mWallBcData); + mBc.mAmiLine = getCcLineKind(); + mRc.mLineKind = getCcLineKind(); + mBc.mLayer = mLayer; + mRc.mLayer = mLayer; + if (m_15b2 != 0) { + mRc.mFlags |= BIT_FLAG(1); + } else { + mRc.mFlags &= ~BIT_FLAG(1); + } +} + +void dAcPy_c::fn_80143060(sBcPointData &data1, sBcPointData &data2, bool mode) { + dAcPy_c *carryPlayer = getCarryPlayer(); + if (carryPlayer == nullptr) { + return; + } + + const sBcPlayerPointData *data; + if (mode) { + data = getBgPointData_Powerup(carryPlayer->mPowerup, 1); + } else { + data = getBgPointData_Powerup(carryPlayer->mPowerup, 0); + } + + if (data1.mOffset < data->mWall.mOffset) { + data1.mOffset = data->mWall.mOffset; + } + + int headOffset = data->mHead.mOffset + l_tall_type_offsets[getTallType(-1)]; + int wallLMargin = data->mWall.mSupMargin + l_tall_type_offsets[getTallType(-1)]; + + if (isStatus(STATUS_46)) { + int thing = (int) (carryPlayer->mPos.y * 4096.0f) - (int) (mPos.y * 4096.0f); + int tmp = data->mHead.mOffset + thing; + if (headOffset > tmp) { + headOffset = tmp; + } + if (headOffset < data2.mOffset) { + headOffset = data2.mOffset; + } + int tmp2 = data->mWall.mSupMargin + thing; + if (wallLMargin > tmp2) { + wallLMargin = tmp2; + } + if (wallLMargin < data1.mSupMargin) { + wallLMargin = data1.mSupMargin; + } + } + + data2.mFlags = data->mHead.mFlags; + data2.mInfMargin = data->mHead.mInfMargin; + data2.mSupMargin = data->mHead.mSupMargin; + data2.mOffset = headOffset; + data1.mSupMargin = wallLMargin; + if (!isMameAction()) { + data2.mFlags = 0x9c0001; + } +} + +bool dAcPy_c::fn_80143220(sBcPointData &data1, sBcPointData &data2) { + dAcPy_c *carryPlayer = getCarryPlayer(); + if (carryPlayer == nullptr) { + return false; + } + mVec3_c pos(mPos.x, mPos.y + data2.mOffset / 4096.0f - 3.0f, mPos.z); + PLAYER_POWERUP_e powerup = carryPlayer->mPowerup; + float tmp = getBgPointData_Powerup(powerup, 0)->mHead.mOffset - getBgPointData_Powerup(powerup, 1)->mHead.mOffset; + float val = mPos.y + data2.mOffset / 4096.0f + tmp / 4096.0f; + float someOffset = data1.mOffset / 4096.0f - 1.0f; + pos.x = mPos.x + someOffset; + float height; + if (dBc_c::checkTenjou(&pos, &height, mLayer, 1)) { + if (height > pos.y && height <= val) { + return true; + } + } + if (!isStatus(STATUS_47)) { + pos.x = mPos.x - (someOffset + 1.0f); + if (dBc_c::checkTenjou(&pos, &height, mLayer, 1)) { + if (height > pos.y && height <= val) { + return true; + } + } + } + return false; +} + +void dAcPy_c::reviseBcDataCarryPlayer(sBcPointData &data1, sBcPointData &data2) { + dAcPy_c *ridePlayer = getRidePlayer(); + if (ridePlayer != nullptr && !ridePlayer->isMameAction()) { + data2.mFlags = 0x9c0001; + } + mBc.mRidePlrNo = -1; + offStatus(STATUS_47); + dAcPy_c *carryPlayer = getCarryPlayer(); + if (carryPlayer != nullptr) { + mBc.mRidePlrNo = carryPlayer->getPlrNo(); + if (isStatus(STATUS_JUMP) && !isStatus(STATUS_48)) { + fn_80143060(data1, data2, false); + } else { + fn_80143060(data1, data2, true); + if (fn_80143220(data1, data2)) { + onStatus(STATUS_47); + } + } + } +} + +void dAcPy_c::reviseBcDataCarryHardBlock(sBcPointData &data1, sBcPointData &data2) { + if (getCarryHardBlock()) { + const sBcPlayerPointData *data = getBgPointData_Powerup(mPowerup, 0); + if (data1.mOffset < data->mWall.mOffset) { + data1.mOffset = data->mWall.mOffset; + } + data2.mInfMargin = data->mHead.mInfMargin; + data2.mSupMargin = data->mHead.mSupMargin; + data2.mOffset += 0xc000; + data2.mFlags = 0x9c0001; + data1.mSupMargin += 0xc000; + } +} + +void dAcPy_c::initCcData() { + initCollision((sCcDatNewF *) &scCcData, (sCcDatNewF *) &scAtCcData); +} + +void dAcPy_c::initBcData() { + mBc.init(); + setBcData(1); + clearNowBgCross(); + clearOldBgCross(); +} + +void dAcPy_c::maxFallSpeedSet() { + if (isMameAction()) { + mMaxFallSpeed = -2.5f; + } else { + mMaxFallSpeed = sc_MaxFallSpeed; + } +} + +void dAcPy_c::set1UpKinokoEffect() { + setFollowEffect(1); +} + +void dAcPy_c::setFlagGetEffect() { + startPlayerVoice(VOICE_TYUKAN, 0); + setFollowEffect(2); +} + +void dAcPy_c::setFollowEffect(int followType) { + mFollowType = followType; + if (mFollowType == 0) { + return; + } + int efSizeType = 0; + if (mPowerup == POWERUP_NONE) { + efSizeType = 1; + } else if (mPowerup == POWERUP_MINI_MUSHROOM) { + efSizeType = 2; + } + mVec3_c efPos; + mPyMdlMng.mpMdl->getJointPos(&efPos, 0); + float s = mPyMdlMng.getSomeScale(); + mVec3_c efScale(s, s, s); + if (mFollowType == 1) { + static const char *sc_oneUpEffectID[] = { + "Wm_mr_1upkira", + "Wm_mr_1upkira_s", + "Wm_mr_1upkira_ss" + }; + dEf::createPlayerEffect_change(mPlayerNo, &mFollowEf4, sc_oneUpEffectID[efSizeType], 0, &efPos, nullptr, &efScale); + } else if (mFollowType == 2) { + static const char *sc_flagGetEffectID[] = { + "Wm_mr_flaggetkira", + "Wm_mr_flaggetkira_s", + "Wm_mr_flaggetkira_ss" + }; + dEf::createPlayerEffect(mPlayerNo, &mFollowEf4, sc_flagGetEffectID[efSizeType], 0, &efPos, nullptr, &efScale); + } +} + +void dAcPy_c::updateFollowEffect() { + if (mFollowType == 0) { + return; + } + + mVec3_c efPos; + mPyMdlMng.mpMdl->getJointPos(&efPos, 0); + float s = mPyMdlMng.getSomeScale(); + mVec3_c efScale(s, s, s); + if (!mFollowEf4.follow(&efPos, nullptr, &efScale)) { + mFollowType = 0; + } +} + +void dAcPy_c::calcTimerProc() { + if (isStatus(STATUS_OUT_OF_PLAY)) { + return; + } + + daPlBase_c::calcTimerProc(); + calcInvalidKeyTimer(); + + sLib::calcTimer(&mStarTimer); + sLib::calcTimer(&mNoInteractTimer); + sLib::calcTimer(&mJumpComboTimer); + sLib::calcTimer(&mWallSlideCooldown); + sLib::calcTimer(&mPoleGrabCooldown); + sLib::calcTimer(&m_15b2); + sLib::calcTimer(&m_15ae); + sLib::calcTimer(&m_2f0); + sLib::calcTimer(&mSpinCooldown); + sLib::calcTimer(&m_15b6); + sLib::calcTimer(&m_60); + sLib::calcTimer(&m_15b8); + sLib::calcTimer(&mBalloonHelpVoiceCooldown); + sLib::calcTimer(&mPowerUpEffectTimer); + sLib::calcTimer(&m_b98); + sLib::calcTimer(&mTarzanRopeCooldown); + if (m_15b0 != 0 && !sLib::calcTimer(&m_15b0)) { + mKey.clearShakeJump(); + } +} + +void dAcPy_c::executeMain() { + mPc.chkTimer(); + setCenterOffset(); + updateItemGetEffect(); + managePropelFukidashi(); + if (updateChange()) { + return; + } + calcReductionScale(); + if (!isStatus(STATUS_NO_ANIM)) { + mPyMdlMng.play(); + } + setFootSound(); + updatePropelParts(); + updateMissSpin(); + updateFollowEffect(); + calcStarTimer(); + daYoshi_c *yoshi = getRideYoshi(); + if (yoshi != nullptr) { + if (yoshi->isDemo()) { + return; + } + } else { + if (executeDemoState()) { + setCcDataDirect(); + return; + } + } + calcTimerProc(); + selectAction(); + if (mSpeed.y < 0.75f) { + offStatus(STATUS_96); + } + mPrevDirection = mDirection; + int dir; + if (!isStatus(STATUS_96) && !isStatus(STATUS_97) && mKey.buttonWalk(&dir)) { + mDirection = dir; + } + executeState(); + if (mSquishNoMoveTimer == 0) { + calcPlayerSpeedXY(); + } + updateRideNat(); + setCcData(); + if (isStar()) { + setCcAtStar(); + } + setBcData(1); + bgCheck(1); + checkDispOver(); + onStatus(STATUS_77); + if (mKey.mActionTriggered) { + mKey.onStatus(dAcPyKey_c::STATUS_SHAKE_COOLDOWN); + } +} + +void dAcPy_c::checkBgCrossSub() { + if (mBc.checkCollision(&mVineBcData)) { + onNowBgCross(BGC_CAN_CLIMB); + } + u32 resFlags = mBc.checkCollision2(&mVineBcData); + if (resFlags & 0x0F) { + onNowBgCross(BGC_VINE_TOUCH_FULL); + if (resFlags & 0b1100) { + onNowBgCross(BGC_VINE_TOUCH_D); + } + if (resFlags & 0b0011) { + onNowBgCross(BGC_VINE_TOUCH_U); + } + } + if (resFlags & 0x30) { + onNowBgCross(BGC_VINE_TOUCH_2); + } + if (isAmiRollAction()) { + onNowBgCross(BGC_VINE_TOUCH_L); + onNowBgCross(BGC_VINE_TOUCH_R); + return; + } + sBcPointData vineData = mVineBcData; + int v = mWallBcData.mOffset * 0.7f; + if (vineData.mOffset < v) { + vineData.mOffset = v; + } + u32 resFlags2 = mBc.checkCollision2(&vineData); + if (resFlags2 & 1 || resFlags2 & 2) { + onNowBgCross(BGC_VINE_TOUCH); + } + if (resFlags2 & 4 || resFlags2 & 8) { + onNowBgCross(BGC_VINE_TOUCH); + } + if (resFlags2 & 1 || resFlags2 & 4) { + onNowBgCross(BGC_VINE_TOUCH_L); + } + if (resFlags2 & 2 || resFlags2 & 8) { + onNowBgCross(BGC_VINE_TOUCH_R); + } +} + +void dAcPy_c::postBgCross() { + if (!isMameAction()) { + offStatus(STATUS_CAN_WATER_WALK); + } + if (isNowBgCross(BGC_WATER_TOUCH) && !isNowBgCross(BGC_WATER_BUBBLE)) { + if (isNowBgCross(BGC_HEAD)) { + m_15b6 = 10; + offStatus(STATUS_CAN_WATER_WALK); + } else if (isStatus(STATUS_CAN_WATER_WALK) || isStatus(STATUS_CAN_WATER_SLIDE)) { + if (mSpeed.y < 0.0f && m_15b6 == 0) { + mPos.y = mWaterHeight; + onNowBgCross(BGC_ON_WATER_MOVE); + onNowBgCross(BGC_FOOT); + if (isStatus(STATUS_PENGUIN_SLIDE)) { + onNowBgCross(BGC_ON_ICE); + } + offNowBgCross(BGC_WATER_SHALLOW); + offNowBgCross(BGC_WATER_SUBMERGED); + mWaterDepth = 0; + mBc.mpCtrHead = nullptr; + mRc.clrLink(); + } + } + } + + if (isNowBgCross(BGC_ON_SINK_SAND)) { + if (isStatus(STATUS_PENGUIN_SLIDE) && mSpeed.y < 0.0f) { + mPos.y = mSinkSandHeight; + onNowBgCross(BGC_FOOT); + offNowBgCross(BGC_ON_SINK_SAND); + offNowBgCross(BGC_IN_SINK_SAND); + offNowBgCross(BGC_INSIDE_SINK_SAND); + } + } + + daPlBase_c::postBgCross(); + + if (!isNowBgCross(BGC_61)) { + if (!isStatus(STATUS_1A) && !isStatus(STATUS_1B)) { + if ( + isNowBgCross(BGC_WALL_TOUCH_L_2) && mSpeedF < 0.0f || + isNowBgCross(BGC_WALL_TOUCH_R_2) && mSpeedF > 0.0f + ) { + mSpeedF = 0.0f; + mMaxSpeedF = 0.0f; + mFinalAirPushForceX = 0; + m_1138 = 0; + } + if ( + isNowBgCross(BGC_FOOT) && + isNowBgCross(BGC_ON_ICE) && + (isNowBgCross(BGC_OBJBG_TOUCH_L) || isNowBgCross(BGC_OBJBG_TOUCH_R)) && + mBc.mpCtrWall != nullptr + ) { + float f = mBc.mpCtrWall->mpActor->mPos.x - mBc.mpCtrWall->mpActor->mLastPos.x; + if (f > 1.0f) { + f = 1.0f; + } + if (f < -1.0f) { + f = -1.0f; + } + if (isNowBgCross(BGC_OBJBG_TOUCH_L)) { + if (mSpeedF < f) { + mSpeedF = f; + } + } else { + if (mSpeedF > f) { + mSpeedF = f; + } + } + } + } + } + + if (isNowBgCross(BGC_FOOT)) { + if (isNowBgCross(BGC_ON_WATER_MOVE)) { + onStatus(STATUS_ON_WATER_MOVE); + } else { + offStatus(STATUS_ON_WATER_MOVE); + } + } + + if ( + isNowBgCross(BGC_FOOT) || + isNowBgCross(BGC_WATER_SHALLOW) || + (isStatus(STATUS_VINE) && mBc.mFenceType == 1) || + isStatus(STATUS_53) || + isStatus(STATUS_STUNNED) || + isStatus(STATUS_OUT_OF_PLAY) || + isStatus(STATUS_RIDE_YOSHI) + ) { + if (!isNowBgCross(BGC_62)) { + clearTreadCount(); + } + } + + if ( + isNowBgCross(BGC_FOOT) || + isNowBgCross(BGC_WATER_SHALLOW) || + isStatus(STATUS_RIDE_YOSHI) || + isStatus(STATUS_VINE) || + isStatus(STATUS_HANG) || + isStatus(STATUS_POLE) || + isStatus(STATUS_KANI_HANG) || + isStatus(STATUS_36) + ) { + setEnemyStageClearDemo(); + clearJumpActionInfo(1); + resetPropelFlyTime(); + mKey.offStatus(dAcPyKey_c::STATUS_FORCE_JUMP); + mKey.offStatus(dAcPyKey_c::STATUS_FORCE_NO_JUMP); + } +} + +void dAcPy_c::clearJumpActionInfo(int) { + offStatus(STATUS_A7); + offStatus(STATUS_SINK_SAND_JUMP); + offStatus(STATUS_JUMP_DAI_COOLDOWN); + + bool checkRes = false; + if (mBc.mpCtrHead != nullptr && mBc.mpCtrHead->mpActor != nullptr) { + if (mBc.mpCtrHead->mpActor->mProfName == fProfile::EN_GOALPOLE) { + checkRes = true; + } + if (mBc.mpCtrHead->mpActor->mActorProperties & 0x10 || mBc.mpCtrHead->mpActor->mActorProperties & 0x20) { + checkRes = true; + } + } + if (!checkRes) { + onStatus(STATUS_B7); + } + if (mScrollMode == 4 || mScrollMode == 2) { + setScrollMode(0); + } + resetMissSpin(); +} + +float dAcPy_c::getSandSinkRate() { + return sGlobalData_c::mData.mSandSinkRate; +} + +bool dAcPy_c::setPressBgDamage(int a, int b) { + dAcPy_c *carryPlayer = getCarryPlayer(); + if (carryPlayer != nullptr) { + if (b == 0) { + cancelCarry(getCarryPlayer()); + return false; + } + if (mPowerup == POWERUP_MINI_MUSHROOM || carryPlayer->mPowerup == POWERUP_MINI_MUSHROOM) { + carryPlayer->setPressBgDamage(a, b); + } else { + mVec3_c pos = carryPlayer->mPos; + float height; + if (dBc_c::checkTenjou(&pos, &height, mLayer, mAmiLayer)) { + const sBcPlayerPointData *data = getBgPointData_Powerup(mPowerup, 0); + pos.y = height - data->mHead.mOffset / 4096.0f - 2.0f; + carryPlayer->mPos = pos; + } + cancelCarry(carryPlayer); + return false; + } + } + return daPlBase_c::setPressBgDamage(a, b); +} + +const sPowerChangeData daPlayerData_c::smc_POWER_CHANGE_DATA = { + { + // no star + 0.0f, 0.08f, + 0.03f, 0.06f, + 0.029f, 0.021f, + 0.09f, + // star + 0.0f, 0.11f, + 0.04f, 0.078f, + 0.039f, 0.027f, + 0.12f + }, + { + // no star + 0.12f, 0.12f, 0.094f, 0.25f, + // star + 0.12f, 0.12f, 0.094f, 0.25f + }, + { + // no star + 0.028f, 0.028f, 0.032f, 0.25f, + // star + 0.038f, 0.038f, 0.042f, 0.25f + }, + { + // no star + 0.07f, 0.07f, 0.07f, 0.25f, + // star + 0.07f, 0.07f, 0.07f, 0.25f + }, + // gravity normal + -0.34f, + 2.5f, + 1.5f, + 0.3f, + -0.12f, + -3.0f, + -0.34f, + -0.34f, + -0.34f, + -0.25f, + -0.34f, + -0.34f, + -0.06f, + -0.25f, + -0.34f, + -0.08f, + -0.31f, + -0.34f, + // gravity mini + -0.09f, + 2.5f, + 1.5f, + 0.0f, + -2.0f, + -2.0f, + -0.09f, + -0.09f, + -0.09f, + -0.06f, + -0.09f, + -0.09f, + -0.04f, + -0.06f, + -0.09f, + -0.06f, + -0.09f, + -0.09f, + -0.34f, + 2.5f, + 1.5f, + 0.3f, + -0.12f, + -3.0f, + -0.34f, + -0.34f, + -0.34f, + -0.25f, + -0.34f, + -0.34f, + -0.06f, + -0.25f, + -0.34f, + -0.1f, + -0.1f, + -0.1f, + { 0.7f, 1.5f, 2.8f }, + { 0.0f, 0.18f, 0.24f, 0.3f } +}; + +const float dAcPy_c::data_802f5a0c[] = { + 0.0f, 0.08f, 0.07f, 0.11f, -1.5f, -1.25f, + -1.0f, -0.1f, 1.5f, 1.5f, 2.5f, 2.5f, + 1.0f, -6.0f, 3.214242E-39 // [-> not just floats?] +}; + +const float dAcPy_c::data_802f5a48[] = { + 25.0f, 3.627f, 3.0f, 0.6f, 2.3509887E-38, // [-> not just floats?] + 1.2f, 2.0f, 1.5f, 2.4f, 0.02f, 0.01f, + 0.05f, 0.2f, 0.03f, 0.03f, 0.8f, 0.7f, + 0.8f, 0.14f, 4.0f, 0.07f, 40.0f +}; + +STATE_VIRTUAL_DEFINE(dAcPy_c, Walk); +STATE_VIRTUAL_DEFINE(dAcPy_c, Jump); +STATE_VIRTUAL_DEFINE(dAcPy_c, Fall); +STATE_VIRTUAL_DEFINE(dAcPy_c, Land); +STATE_VIRTUAL_DEFINE(dAcPy_c, Crouch); +STATE_VIRTUAL_DEFINE(dAcPy_c, SitJump); +STATE_VIRTUAL_DEFINE(dAcPy_c, Slip); +STATE_VIRTUAL_DEFINE(dAcPy_c, Turn); +STATE_VIRTUAL_DEFINE(dAcPy_c, HipAttack); +STATE_VIRTUAL_DEFINE(dAcPy_c, Swim); +STATE_VIRTUAL_DEFINE(dAcPy_c, Kani); +STATE_VIRTUAL_DEFINE(dAcPy_c, Cloud); + +STATE_DEFINE(dAcPy_c, RideOffJump); +STATE_DEFINE(dAcPy_c, SpinHipAttack); +STATE_DEFINE(dAcPy_c, RollSlip); +STATE_DEFINE(dAcPy_c, Vine); +STATE_DEFINE(dAcPy_c, Hang); +STATE_DEFINE(dAcPy_c, Pole); +STATE_DEFINE(dAcPy_c, Fire); +STATE_DEFINE(dAcPy_c, LiftUp); +STATE_DEFINE(dAcPy_c, Throw); +STATE_DEFINE(dAcPy_c, PropelThrow); +STATE_DEFINE(dAcPy_c, WallJump); +STATE_DEFINE(dAcPy_c, WallSlide); +STATE_DEFINE(dAcPy_c, Propel); +STATE_DEFINE(dAcPy_c, CarryPlayer); +STATE_DEFINE(dAcPy_c, RideYoshi); +STATE_DEFINE(dAcPy_c, SpinJump); +STATE_DEFINE(dAcPy_c, PenguinSlide); +STATE_DEFINE(dAcPy_c, KaniJump); +STATE_DEFINE(dAcPy_c, Quake); +STATE_DEFINE(dAcPy_c, ElecShock); +STATE_DEFINE(dAcPy_c, FlyDamage); +STATE_DEFINE(dAcPy_c, IceDamage); +STATE_DEFINE(dAcPy_c, CannonJump); +STATE_DEFINE(dAcPy_c, TarzanRope); +STATE_DEFINE(dAcPy_c, PlayerEat); +STATE_DEFINE(dAcPy_c, Balloon); +STATE_DEFINE(dAcPy_c, BlockJump); +STATE_DEFINE(dAcPy_c, JrCrown); + +STATE_VIRTUAL_DEFINE(dAcPy_c, DemoDown); +STATE_DEFINE(dAcPy_c, DemoInDoor); +STATE_DEFINE(dAcPy_c, DemoInJump); +STATE_DEFINE(dAcPy_c, DemoInVine); +STATE_DEFINE(dAcPy_c, DemoOutDoor); +STATE_DEFINE(dAcPy_c, DemoFallDown); +STATE_DEFINE(dAcPy_c, DemoFireDown); +STATE_DEFINE(dAcPy_c, DemoEatDie); +STATE_DEFINE(dAcPy_c, DemoDokanCannon); +STATE_DEFINE(dAcPy_c, DemoCannonWarp); +// STATE_VIRTUAL_DEFINE(dAcPy_c, DemoStartWait); // [TODO: intentionally left out?] + +ACTOR_PROFILE(PLAYER, dAcPy_c, 0); + +template <> +const dAcPy_c::GlobalData_t sGlobalData_c::mData = { + 0.0f, 0.0f, + 1.5f, 4.5f, 0.5f, 4.0f, 1.4f, 1.0f, + { + mVec3_c(0.0f, 10.0f, 0.0f), + mVec3_c(0.0f, 16.0f, 0.0f), + mVec3_c(0.0f, 28.0f, 0.0f) + }, + -3.0f, 3.0f, 3.2f, + 0.5f, 3.2f, 3.0f, 1.2f, + 0.5f, 0.625f, 0.5f, 0.625f, + 0.8f, 1.0f, 1.3f, 2.0f +}; + +dAcPy_HIO_Speed_c dAcPy_c::m_speed_hio[2]; + +dAcPy_c::dAcPy_c() : mPyMdlMng(daPyMng_c::getCourseInPlayerModelType(ACTOR_PARAM(PlayerNo))) { + setKind(STAGE_ACTOR_PLAYER); + mExecStopMask = BIT_FLAG(STAGE_ACTOR_PLAYER); + mpMdlMng = &mPyMdlMng; + mPyMdlMng.mpMdl->mpOwner = this; + mPlayerNo = ACTOR_PARAM(PlayerNo); + mPlayerType = daPyMng_c::getPlayerType(mPlayerNo); + mPowerup = daPyMng_c::mPlayerMode[daPyMng_c::getPlayerType(mPlayerNo)]; + mIsRescueKinopio = 0; + if (daPyMng_c::mCreateItem[daPyMng_c::getPlayerType(mPlayerNo)] & 8) { + mIsRescueKinopio = 1; + dInfo_c::m_instance->m_6c = true; + mPlayerType = PLAYER_BLUE_TOAD; + mPowerup = daPyMng_c::mKinopioMode; + daPyMng_c::mPlayerEntry[mPlayerNo] = 0; + daPyMng_c::mCreateItem[daPyMng_c::getPlayerType(mPlayerNo)] &= ~CREATE_ITEM_RESCUE_TOAD; + } + daPyMng_c::setPlayer(mPlayerNo, this); + mPlayerLayer = mPlayerNo; +} + +dAcPy_c::~dAcPy_c() { + daPyMng_c::setPlayer(mPlayerNo, nullptr); +} + +int dAcPy_c::doDelete() { + if (fn_801477c0() && !isItemKinopio()) { + dGameCom::fn_800b37b0(mPlayerNo, 1); + } + setSceneChangeInfo(); + daPlBase_c::doDelete(); + return SUCCEEDED; +} + +void dAcPy_c::setSceneChangeInfo() { + if (isItemKinopio()) { + if (dScStage_c::getExitMode() == dScStage_c::EXIT_3) { + dAcPy_c *ctrlPlayer = daPyMng_c::getCtrlPlayer(mPlayerNo); + if ( + ctrlPlayer != nullptr && + !ctrlPlayer->isStatus(STATUS_GOAL_POLE_TOUCHED) && + !isStatus(STATUS_OUT_OF_PLAY) && + !isStatus(STATUS_ITEM_KINOPIO_DISPLAY_OUT) + ) { + daPyMng_c::fn_8005f570(mPowerup, mPlayerNo); + } + } + return; + } + + PLAYER_POWERUP_e powerup = mPowerup; + u32 createItem = CREATE_ITEM_NONE; + + switch (dScStage_c::getExitMode()) { + case dScStage_c::EXIT_3: { + if (!isStatus(STATUS_55) || isNotBalloonCourse()) { + if (isStatus(STATUS_53)) { + createItem = CREATE_ITEM_BUBBLE; + } else if (isStatus(STATUS_OUT_OF_PLAY)) { + powerup = POWERUP_NONE; + createItem = CREATE_ITEM_BUBBLE; + } + } + daYoshi_c *yoshi = getRideYoshi(); + if (yoshi != nullptr) { + createItem = CREATE_ITEM_YOSHI; + int fruitCount = yoshi->getFruitCount(); + u8 yoshiColor = yoshi->getModel()->getColor(); + daPyMng_c::setCarryOverYoshiInfo(mPlayerNo, yoshiColor, fruitCount); + onStatus(STATUS_C5); + } + break; + } + case dScStage_c::EXIT_2: + powerup = daPyMng_c::mPlayerMode[daPyMng_c::getPlayerType(mPlayerNo)]; + createItem = daPyMng_c::mCreateItem[daPyMng_c::getPlayerType(mPlayerNo)]; + break; + case dScStage_c::EXIT_1: + powerup = POWERUP_NONE; + break; + default: + break; + } + + daPyMng_c::mPlayerEntry[mPlayerNo] = 1; + daPyMng_c::mPlayerMode[daPyMng_c::getPlayerType(mPlayerNo)] = powerup; + daPyMng_c::mCreateItem[daPyMng_c::getPlayerType(mPlayerNo)] = createItem; + daPyMng_c::m_star_time[mPlayerNo] = mStarTimer; + daPyMng_c::m_star_count[mPlayerNo] = mStarCount; +} + +int dAcPy_c::create() { + mPyMdlMng.create(mPlayerNo, mPowerup, dPyMdlMng_c::SCENE_TYPE_0); + mPowerupCopy2 = mPowerup; + mPowerupCopy = mPowerup; + setPowerup(mPowerup, 1); + mDirection = ACTOR_PARAM(Direction); + mAngle.y = getMukiAngle(mDirection); + mSpeedMax.set(0.0f, 0.0f, 0.0f); + mMaxFallSpeed = sc_MaxFallSpeed; + mAccelY = getGravityData()[0]; + mScale.set(1.0f, 1.0f, 1.0f); + mAmiRelated2 = 1.0f; + setStatus(STATUS_CREATED); + mCarryActorID = BASE_ID_NULL; + mRideActorID = BASE_ID_NULL; + mRelatedActorID = BASE_ID_NULL; + if (isItemKinopio()) { + setScrollMode(1); + } else { + setScrollMode(0); + } + mPc.m_30 = mPos; + mPropelParts.create(this); + initCcData(); + initBcData(); + setCreateAction(ACTOR_PARAM(CreateAction)); + calcModel(); + mPc.set(this, 1); + if (dScStage_c::m_miniGame == 0 && dScStage_c::m_instance->mCurrCourse != STAGE_PEACH_CASTLE) { + if ((daPyMng_c::mCreateItem[daPyMng_c::mPlayerType[mPlayerNo]] & CREATE_ITEM_STAR_POWER)) { + setStar(STAR_SET_2, 660); + } else { + if (daPyMng_c::m_star_time[mPlayerNo] != 0) { + setStar(STAR_SET_2, daPyMng_c::m_star_time[mPlayerNo]); + } + mStarCount = daPyMng_c::m_star_count[mPlayerNo]; + } + } + if (!isItemKinopio() && dScStage_c::m_gameMode == dScStage_c::GAME_MODE_NORMAL) { + mSndObj.m_58 = dAudio::getRemotePlayer(mPlayerNo); + } + int x = 0; + switch (mPlayerType) { + case PLAYER_MARIO: x = 0; break; + case PLAYER_LUIGI: x = 1; break; + case PLAYER_YELLOW_TOAD: x = 2; break; + case PLAYER_BLUE_TOAD: x = 3; break; + default: break; + } + mSndObj.m_ac = x; + setSoundPlyMode(); + daPlBase_c::create(); + mKey.mRemoconID = mPlayerNo; + return SUCCEEDED; +} + +int dAcPy_c::preExecute() { + u32 oldExecStopMask = mExecStopMask; + daYoshi_c *yoshi = getRideYoshi(); + if (yoshi != nullptr) { + mExecStopMask = yoshi->mExecStopMask; + } + int res = daPlBase_c::preExecute(); + mExecStopMask = oldExecStopMask; + return res; +} + +void dAcPy_c::postExecute(MAIN_STATE_e status) { + if (status == SUCCESS) { + mVec3_c pos = mPos; + dAcPy_c *ridePlayer = getRidePlayer(); + if (ridePlayer != nullptr) { + pos.x = ridePlayer->mPos.x; + } + if (mScrollMode != 3) { + if (m_60 != 0) { + bool notDone = false; + if (!sLib::chase(&mPc.m_30.x, pos.x, 3.0f)) { + notDone = true; + } + if (!sLib::chase(&mPc.m_30.y, pos.y, 3.0f)) { + notDone = true; + } + if (!notDone) { + m_60 = 0; + } + } else { + sLib::addCalc(&mPc.m_30.x, pos.x, 0.25f, 6.0f, 0.1f); + sLib::addCalc(&mPc.m_30.y, pos.y, 0.25f, 6.0f, 0.1f); + } + if (isStatus(STATUS_5C)) { + setScrollMode(5); + } else { + if (mScrollMode == 5) { + setScrollMode(0); + } + } + } + } + daPlBase_c::postExecute(status); +} + +void dAcPy_c::selectAction() { + offStatus(STATUS_CAN_PENGUIN_SLIDE); + if (std::fabs(mSpeedF) >= 1.0f) { + mFastRunFrames++; + if (mFastRunFrames >= 0) { + onStatus(STATUS_CAN_PENGUIN_SLIDE); + } + } else { + mFastRunFrames = 0; + } + + if (isStatus(STATUS_07) && setSpinActionReq()) { + return; + } + if (isDemo() || isStatus(STATUS_53)) { + return; + } + if (setBalloonButtonA()) { + return; + } + if (isStatus(STATUS_QUAKE_BIG)) { + offStatus(STATUS_QUAKE_BIG); + setQuakeAction(60, QUAKE_MODE_0); + } else if (isStatus(STATUS_QUAKE_SMALL)) { + offStatus(STATUS_QUAKE_SMALL); + if (isNowBgCross(BGC_FOOT)) { + setWaitJump(4.0f); + } + } else if (isStatus(STATUS_RIDE_YOSHI) && !isState(StateID_RideYoshi)) { + changeState(StateID_RideYoshi, 0); + } else if (setVineAction()) { + return; + } else if (setHangAction()) { + return; + } else if (setPoleAction()) { + return; + } else if (setKaniHangAction()) { + return; + } else if (checkWallJump()) { + return; + } else if (setSpinActionReq()) { + return; + } else if (setSwimAction()) { + return; + } else if (setFireBallAction()) { + return; + } else if (setTarzanRopeAction()) { + return; + } +} + +void dAcPy_c::executeLastPlayer() { + if (!isStatus(STATUS_CAN_EXECUTE)) { + return; + } + clearHipAttackDamagePlayer(); + if (isStatus(STATUS_RIDE_YOSHI)) { + setYoshiBackPos(); + } + if (isStatus(STATUS_PLAYER_JUMP)) { + setPlayerJumoDaiPos(); + } + if (isStatus(STATUS_4F)) { + setJrCrownPos(); + } + calcModel(); + if (isStatus(STATUS_77)) { + setPlayerEatReact(); + entryCollision(); + offStatus(STATUS_77); + offStatus(STATUS_78); + } +} + +void dAcPy_c::executeLastAll() { + if (!isStatus(STATUS_CAN_EXECUTE)) { + return; + } + setSpinLiftUpReserve(); + setSpinAction(); + offStatus(STATUS_8A); + if (isStatus(STATUS_45)) { + setPlayerHandPos(); + mAng3_c ang = mAngle; + ang.y += getMissSpinAngle(); + mPyMdlMng.calc( + mPos, + ang, + getModelScale() + ); + } + if (!isChange()) { + calcHeadAttentionAngle(); + } + setSpinJumpEffect(0); + setMissSpinJumpEffect(0); + mPyMdlMng.calc2(); +} + +void dAcPy_c::calcModel() { + mPyMdlMng.mpMdl->setDark(m_74); + + if (isNowBgCross(BGC_36)) { + mPyMdlMng.mpMdl->m_17c |= 0x400; + } else { + mPyMdlMng.mpMdl->m_17c &= ~0x400; + } + + daYoshi_c *yoshi = getRideYoshi(); + + if (yoshi != nullptr) { + mMtx_c mtx; + yoshi->getModel()->getJointMtx(&mtx, 1); + + mtx.concat(mMtx_c::createTrans( + dPyMdlMng_c::m_hio.getValue(mPlayerType, 0, mPowerup), + dPyMdlMng_c::m_hio.getValue(mPlayerType, 1, mPowerup), + 0.0f + )); + + mtx.ZrotM(-0x58E3); + mtx.YrotM(0xC000); + + mtx.concat(mMtx_c::createTrans(0.0f, 0.0f, 15.0f)); + mtx.concat(mMtx_c::createScale(daPlBase_c::getReductionModelScale())); + mtx.concat(mMtx_c::createTrans(0.0f, 0.0f, -15.0f)); + mtx.concat(mMtx_c::createScale(getModelScaleBase())); + + mPyMdlMng.calc(mtx); + return; + } + + if (daPlBase_c::isStatus(STATUS_4F)) { + mPyMdlMng.calc(mRideJrClownMtx); + return; + } + + mVec3_c pos( + mPos.x + m_1594, + mPos.y + m_1598 + m_159c, + mPos.z + ); + + mAng3_c rot( + mAngle.x.mAngle, + mAngle.y.mAngle + getMissSpinAngle(), + mAngle.z.mAngle + ); + + mPyMdlMng.calc(pos, rot, getModelScale()); +} + +mVec3_c dAcPy_c::getModelScaleBase() { + float scale = mAmiRelated2; + mVec3_c res( + mScale.x * scale, + mScale.y * scale, + mScale.z * scale + ); + return res; +} + +mVec3_c dAcPy_c::getModelScale() { + return mVec3_c( + getModelScaleBase().x * getReductionModelScale().x, + getModelScaleBase().y * getReductionModelScale().y, + getModelScaleBase().z * getReductionModelScale().z + ); +} + +int dAcPy_c::draw() { + if (isStatus(STATUS_INVULNERABLILITY_BLINK)) { + offStatus(STATUS_INVULNERABLILITY_BLINK); + return SUCCEEDED; + } + + mPyMdlMng.draw(); + return SUCCEEDED; +} + +bool dAcPy_c::fn_80145c00(PLAYER_POWERUP_e powerup) { + if (isStatus(STATUS_OUT_OF_PLAY) || isStatus(STATUS_STUNNED)) { + return false; + } + + if (mPowerupCopy2 == powerup) { + return false; + } + + mPowerupCopy2 = powerup; + return mPowerup != powerup; +} + +void dAcPy_c::setStar(StarSet_e starSet, int timer) { + setStarBase(starSet, timer); + if (starSet == STAR_SET_0) { + setVirusStar(getRidePlayer()); + setVirusStar(getCarryPlayer()); + } +} + +void dAcPy_c::setStarBase(StarSet_e starSet, int timer) { + if (starSet == STAR_SET_0) { + startPlayerVoice(VOICE_GET_STAR, 0); + } + if (timer != 0) { + mStarTimer = timer; + if (timer >= 60) { + daPyMng_c::startStarBGM(); + } + mPyMdlMng.mpMdl->onStarAnm(); + } +} + +void dAcPy_c::endStar() { + if (mStarTimer != 0) { + mStarTimer = 0; + mPyMdlMng.mpMdl->offStarAnm(); + mPyMdlMng.mpMdl->offStarEffect(); + daPyMng_c::stopStarBGM(); + } +} + +void dAcPy_c::calcStarTimer() { + mPyMdlMng.mpMdl->offStarEffect(); + if (mStarTimer != 0) { + mPyMdlMng.mpMdl->mScale = mVec3_c(mAmiRelated2, mAmiRelated2, mAmiRelated2); + if (!isStatus(STATUS_INVISIBLE) && !isStatus(STATUS_5E) && mStarTimer > 25) { + mPyMdlMng.mpMdl->onStarEffect(); + } + if (mStarTimer < 10) { + mPyMdlMng.mpMdl->offStarAnm(); + } + if (mStarTimer == 120) { + mStarTimer--; + startSound(SE_SYS_STAR_FINISH, false); + startSound(SE_SYS_STAR_FINISH_RC, false); + } + if (mStarTimer < 60) { + daPyMng_c::stopStarBGM(); + } + } else { + clearStarCount(); + } +} + +void dAcPy_c::setVirusStar(daPlBase_c *otherPlayer) { + if (otherPlayer == nullptr) { + return; + } + + int selfTimer = mStarTimer; + int otherTimer = otherPlayer->mStarTimer; + + if (selfTimer == otherTimer) { + return; + } + + if (selfTimer > otherTimer) { + otherPlayer->setStar(STAR_SET_1, selfTimer); + } else { + setStar(STAR_SET_1, otherTimer); + } +} + +void dAcPy_c::setWaterWalkFlag() { + if (isMameAction() && !isNowBgCross(BGC_WATER_SHALLOW)) { + onStatus(STATUS_CAN_WATER_WALK); + } +} + +void dAcPy_c::fn_80145fd0(int jumpType) { + static const dAudio::SoundEffectID_t sc_JumpSoundNormal[] = { SE_PLY_JUMP, SE_PLY_2NDJUMP, SE_PLY_3RDJUMP }; + static const dAudio::SoundEffectID_t sc_JumpSoundSuper[] = { SE_PLY_JUMP_S, SE_PLY_2NDJUMP_S, SE_PLY_3RDJUMP_S }; + static const dAudio::SoundEffectID_t sc_JumpSoundMame[] = { SE_PLY_JUMP_SS, SE_PLY_2NDJUMP_SS, SE_PLY_3RDJUMP_SS }; + if (jumpType == 2 && !mKey.buttonJump()) { + jumpType = 0; + } + switch (jumpType) { + case 1: + switch (mPowerup) { + case POWERUP_NONE: + startSound(sc_JumpSoundSuper[mJumpCounter], true); + break; + case POWERUP_MINI_MUSHROOM: + startSound(sc_JumpSoundMame[mJumpCounter], true); + break; + default: + startSound(sc_JumpSoundNormal[mJumpCounter], true); + break; + } + break; + case 2: + switch (mPowerup) { + case POWERUP_NONE: + startSound(SE_PLY_JUMP_SS_HIGH, false); + break; + case POWERUP_MINI_MUSHROOM: + startSound(SE_PLY_JUMP_S_HIGH, false); + break; + default: + startSound(SE_PLY_JUMP_HIGH, false); + break; + } + } +} + +bool dAcPy_c::isNoDamage() { + if ( + (mDamageInvulnTimer | mPowerupChangeInvulnTimer) != 0 || + isDemo() || + isDemoType(DEMO_PLAYER) || + isStatus(STATUS_DISPLAY_OUT_NO_DAMAGE) || + isStatus(STATUS_84) + ) { + return true; + } + return false; +} + +bool dAcPy_c::setDamage(dActor_c *actor, daPlBase_c::DamageType_e damageType) { + if (mPowerup != mPowerupCopy2 || isChange()) { + return false; + } + + if (isNoDamage()) { + return false; + } + + if (setDamage2(actor, damageType)) { + dQuake_c::m_instance->shockMotor(mPlayerNo, dQuake_c::TYPE_4, 0, false); + return true; + } + + return false; +} + +bool dAcPy_c::setForcedDamage(dActor_c *actor, daPlBase_c::DamageType_e damageType) { + if (isDemo() || mPowerup != mPowerupCopy2 || isChange()) { + return false; + } + + if (setDamage2(actor, damageType)) { + dQuake_c::m_instance->shockMotor(mPlayerNo, dQuake_c::TYPE_4, 0, false); + return true; + } + + return false; +} + +bool dAcPy_c::setDamage2(dActor_c *actor, daPlBase_c::DamageType_e damageType) { + if (isStatus(STATUS_OUT_OF_PLAY) || isStatus(STATUS_STUNNED) || isStatus(STATUS_53)) { + return false; + } + releaseCarryActor(); + if (damageType == DAMAGE_DEFAULT && isStatus(STATUS_PENGUIN_SLIDE) && actor != nullptr && actor->mActorProperties & 0x200) { + if (setFlyDamageAction(3, actor)) { + onStatus(STATUS_PENGUIN_RECOIL); + return true; + } + return false; + } + switch (damageType) { + case DAMAGE_YOGAN: + changeDemoState(StateID_DemoFireDown, 0); + break; + case DAMAGE_ELEC_SHOCK: + if (isStatus(STATUS_4F)) { + setJrCrownElecDamage(); + } else { + changeState(StateID_ElecShock, 0); + } + break; + case DAMAGE_POISON: + changeDemoState(StateID_DemoDown, DEMO_DOWN_ARG_POISON); + break; + case DAMAGE_SQUISH: + changeDemoState(StateID_DemoDown, DEMO_DOWN_ARG_HIT); + break; + case DAMAGE_POISON_FOG: + changeDemoState(StateID_DemoDown, DEMO_DOWN_ARG_POISON_FOG); + break; + case DAMAGE_EAT_DIE: + case DAMAGE_D: + changeDemoState(StateID_DemoEatDie, damageType); + mRelatedActorID = actor->mUniqueID; + break; + case DAMAGE_HIP_ATTACK: + case DAMAGE_4: + case DAMAGE_CLIMB: + case DAMAGE_6: + return setFlyDamageAction(damageType, actor); + case DAMAGE_11: + setReductionScale(); + break; + case DAMAGE_10: + changeState(StateID_IceDamage, 0); + break; + default: + if (mPowerup == POWERUP_NONE || mPowerup == POWERUP_MINI_MUSHROOM) { + if (damageType == DAMAGE_8) { + changeDemoState(StateID_DemoFireDown, 0); + } else { + changeDemoState(StateID_DemoDown, DEMO_DOWN_ARG_HIT); + } + } else { + if (mPowerup == POWERUP_MUSHROOM) { + fn_80145c00(POWERUP_NONE); + } else { + fn_80145c00(POWERUP_MUSHROOM); + } + if (damageType == DAMAGE_2) { + mDamageInvulnTimer = 127; + return setFlyDamageAction(damageType, actor); + } + if (damageType == DAMAGE_FREEZE) { + changeState(StateID_IceDamage, 0); + } else { + mDamageInvulnTimer = 127; + } + } + break; + } + return true; +} + +u8 dAcPy_c::getTallType(s8 powerup) { + const u8 l_tall_type[] = { + 1, 2, 2, 0, 2, 2, 2 + }; + + if (powerup == -1) { + powerup = mPowerup; + } + return l_tall_type[powerup]; +} + +void dAcPy_c::setCenterOffset() { + float l_powerup_offsets[] = { + 16.0f, 31.0f, 31.0f, 6.0f, 34.0f, 31.0f, 31.0f + }; + + mModelHeight = l_powerup_offsets[mPowerup]; + + mVec3_c offset(0.0f, 0.0f, 0.0f); + if (mPyMdlMng.mpMdl->mFlags & 1) { + offset.y = mModelHeight / 4.0f; + } else if (mPyMdlMng.mpMdl->mFlags & 4) { + offset.y = -(mModelHeight / 2.0f); + } else { + offset.y = mModelHeight / 2.0f; + } + mCenterOffs = offset; + + float target = 16.0f; + if (mPowerup == POWERUP_MINI_MUSHROOM) { + target = 8.0f; + } + sLib::chase(&mViewLimitPadding, target, 0.1f); +} + +void dAcPy_c::setPlayerData() { + static const mVec2_POD_c l_player_cull_data[] = { + {0.0f, 20.0f}, + {15.0f, 22.0f} + }; + setVisibleArea(l_player_cull_data[0], l_player_cull_data[1]); +} + +void dAcPy_c::setSpeedData() { + static const int scSpeedHioData[] = { 1, 1, 1, 0, 1, 1, 1 }; + u8 index = scSpeedHioData[mPowerup]; + mSpeedDataNormal = &m_speed_hio[index].mDataNormal; + mSpeedDataStar = &m_speed_hio[index].mDataStar; +} + +void dAcPy_c::setModeGravity() { + int index = 0; + if (mPowerup == POWERUP_MINI_MUSHROOM) { + index = 1; + } + mGravityData = daPlayerData_c::smc_POWER_CHANGE_DATA.mGravityData[index]; +} + +const float *dAcPy_c::getGravityData() { + if (isMameAction()) { + return daPlayerData_c::smc_POWER_CHANGE_DATA.mGravityData[1]; + } else { + return daPlayerData_c::smc_POWER_CHANGE_DATA.mGravityData[0]; + } +} + +void dAcPy_c::setPowerup(PLAYER_POWERUP_e powerup, int) { + mPowerupCopy = mPowerup; + mPowerup = powerup; + mPyMdlMng.mpMdl->setPlayerMode(mPowerup); + setPlayerData(); + setCenterOffset(); + setSpeedData(); + mAccelF = getSpeedData()->mPowerChangeNormal.mSlowAccel; + setModeGravity(); + offStatus(STATUS_IS_PENGUIN); + switch (mPowerup) { + case POWERUP_PROPELLER_SHROOM: + if (!isItemKinopio()) { + if (fn_801477c0()) { + dGameCom::fn_800b37b0(mPlayerNo, 1); + } + m_1580 = 0; + } + resetPropelFlyTime(); + break; + case POWERUP_PENGUIN_SUIT: + onStatus(STATUS_IS_PENGUIN); + break; + default: + break; + } + mBc.mPlayerFlags &= ~BIT_FLAG(3); + if (mPowerup == POWERUP_MINI_MUSHROOM) { + mBc.mPlayerFlags |= BIT_FLAG(3); + } + setSoundPlyMode(); +} + +bool dAcPy_c::setJump(float jumpSpeed, float speedF, bool allowSteer, int keyMode, int jumpMode) { + if (mPowerup != POWERUP_MINI_MUSHROOM && isClimbing()) { + return false; + } + return _setJump(jumpSpeed, speedF, allowSteer, keyMode, jumpMode); +} + +bool dAcPy_c::_setJump(float jumpSpeed, float speedF, bool allowSteer, int keyMode, int jumpMode) { + if (isDemo() || isStatus(STATUS_OUT_OF_PLAY)) { + return false; + } + if (isStatus(STATUS_DISABLE_STATE_CHANGE) && isStatus(STATUS_53)) { + return false; + } + if (setSwimSpeed(jumpSpeed * 0.5f, speedF * 0.5f)) { + return true; + } + clearJumpActionInfo(0); + if (isStatus(STATUS_KANI_WALK)) { + changeState(StateID_KaniJump); + } else { + bool res = false; + mSpeedF = speedF; + if (jumpSpeed <= 0.0f) { + if (isStatus(STATUS_80)) { + if (isOldBgCross(BGC_FOOT)) { + res = true; + } + } else { + if (isNowBgCross(BGC_FOOT)) { + res = false; + } + } + } + if (!res) { + bool isSpinJump = false; + bool isSitJump = false; + if (isStatus(STATUS_SPIN) && isStatus(STATUS_JUMP)) { + isSpinJump = true; + } else if (isStatus(STATUS_SIT_JUMP)) { + isSitJump = true; + } + if (jumpSpeed == 0.0f) { + changeState(StateID_Fall, false); + } else { + jmpInf_c jump(jumpSpeed, jumpMode, BLEND_DEFAULT); + changeState(StateID_Jump, &jump); + } + onStatus(STATUS_AB); + onStatus(STATUS_88); + if (isSpinJump) { + int param = 2; + if (jumpMode == 1) { + param = 1; + } + changeState(StateID_SpinJump, (void *) param); + } else if (isSitJump) { + changeState(StateID_SitJump, true); + } + } + } + offStatus(STATUS_A7); + offNowBgCross(BGC_FOOT); + mWallSlideCooldown = 4; + if (!allowSteer) { + mKey.onStatus(dAcPyKey_c::STATUS_DISABLE_LR); + onStatus(STATUS_A7); + } + if (keyMode == 1) { + mKey.onStatus(dAcPyKey_c::STATUS_FORCE_JUMP); + } else if (keyMode == 2) { + mKey.onStatus(dAcPyKey_c::STATUS_FORCE_NO_JUMP); + } + + return true; +} + +bool dAcPy_c::fn_80146e40(float a, float b, bool c) { + if (isDemo() || isStatus(STATUS_OUT_OF_PLAY) || isNowBgCross(BGC_WATER_SHALLOW)) { + return false; + } + checkSinkSand(); + if (getSpinActionMode() == 0 || isOnSinkSand()) { + mSpeed.y = a; + mSpeedF = b; + changeState(StateID_SpinJump, (void *) 1); + setJumpCommonBase(); + mKey.onStatus(dAcPyKey_c::STATUS_FORCE_JUMP); + offNowBgCross(BGC_FOOT); + mWallSlideCooldown = 4; + offStatus(STATUS_A7); + } else { + mSpeedF = b; + changeState(StateID_Propel, (void *) 2); + } + return true; +} + +bool dAcPy_c::setCannonJump(float speedY, float speedF, int jumpType) { + mSpeedF = speedF; + mMaxSpeedF = speedF; + mSpeed.y = speedY; + if (mSpeedF > 0.0f) { + mDirection = DIR_LR_R; + } else { + mDirection = DIR_LR_L; + } + changeState(StateID_CannonJump, (void *) jumpType); + return true; +} + +bool dAcPy_c::setSwimSpeed(float speedY, float speedF) { + if (isNowBgCross(BGC_WATER_SHALLOW)) { + setUzuSwimAction(); + mSpeed.y = speedY; + mSpeedF = speedF; + m_b88 = 20; + return true; + } + return false; +} + +bool dAcPy_c::isEnablePropelJump() { + if (mSpinCooldown != 0 || isNowBgCross(BGC_WATER_SHALLOW) || !isStatus(STATUS_9F)) { + return false; + } + + if (isDemo() || isStatus(STATUS_AUTO_BOUNCE)) { + return false; + } + + return getSpinActionMode() == 1; +} + +int dAcPy_c::getSpinActionMode() { + s8 tmp = getPowerup(); + if (getCarryPropelActor() != nullptr) { + tmp = POWERUP_PROPELLER_SHROOM; + } else { + dAcPy_c *carryPlayer = getCarryPlayer(); + if (carryPlayer != nullptr) { + tmp = carryPlayer->getPowerup(); + } else { + if (tmp == POWERUP_PROPELLER_SHROOM && isLiftUp()) { + tmp = POWERUP_MUSHROOM; + } + } + } + return tmp == POWERUP_PROPELLER_SHROOM ? 1 : 0; +} + +bool dAcPy_c::setSpinActionReq() { + mKey.offStatus(dAcPyKey_c::STATUS_2); + if (mPowerup == POWERUP_PROPELLER_SHROOM) { + mKey.onStatus(dAcPyKey_c::STATUS_2); + } + + if ( + mSpinCooldown != 0 || + !mKey.triggerShakeJump() || + isNowBgCross(BGC_WATER_SHALLOW) || + !isStatus(STATUS_9F) + ) { + return false; + } + + if (isNowBgCross(BGC_FOOT)) { + setCcAtSpinLiftUp(); + clearSpinLiftUpReserve(); + } + onStatus(STATUS_8A); + return true; +} + +bool dAcPy_c::setSpinAction() { + if ( + isDemo() || + isStatus(STATUS_OUT_OF_PLAY) || + isStatus(STATUS_STUNNED) || + isStatus(STATUS_QUAKE) || + isStatus(STATUS_AUTO_BOUNCE) || + !isStatus(STATUS_8A) + ) { + return false; + } + + if (checkStandUpRoof()) { + return false; + } + + if (isNowBgCross(BGC_HEAD)) { + return false; + } + + mSpinCooldown = 30; + resetMissSpin(); + if (getSpinActionMode() == 0) { + if (isNowBgCross(BGC_FOOT)) { + changeState(StateID_SpinJump, 0); + return true; + } + } else { + if (setPropelAction()) { + return true; + } + } + + setMissSpin(); + return true; +} + +void dAcPy_c::setScrollMode(s8 mode) { + if (!isItemKinopio()) { + mScrollMode = mode; + } else { + mScrollMode = 1; + } +} + +void dAcPy_c::setInvalidKeyTimer(int p1, int p2) { + m_1318[0] = p1; + m_1310[0] = p2; + mKey.onStatus(dAcPyKey_c::STATUS_NO_INPUT); +} + +void dAcPy_c::setInvalidKeyTimer_LR(int p1, int p2) { + m_1318[1] = p1; + m_1310[1] = p2; + mKey.onStatus(dAcPyKey_c::STATUS_DISABLE_LR); +} + +void dAcPy_c::calcInvalidKeyTimer() { + for (int i = 0; i < 2; i++) { + if (m_1318[i] != 0) { + if (m_1310[i] == 2) { + if (mSpeed.y <= 0.0f || isNowBgCross(BGC_FOOT)) { + m_1318[i] = 0; + } + } else if (m_1310[i] == 1) { + if (isNowBgCross(BGC_FOOT)) { + m_1318[i] = 0; + } + } + sLib::calcTimer(&m_1318[i]); + if (m_1318[i] == 0) { + if (i == 0) { + mKey.offStatus(dAcPyKey_c::STATUS_NO_INPUT); + } else { + mKey.offStatus(dAcPyKey_c::STATUS_DISABLE_LR); + } + } + } + } +} + +void dAcPy_c::startQuakeShock(dQuake_c::TYPE_SHOCK_e type) { + daPlBase_c::startQuakeShock(type); + dAcPy_c *carryPlayer = getCarryPlayer(); + if (carryPlayer != nullptr) { + carryPlayer->startQuakeShock(type); + } +} + +void dAcPy_c::startPatternRumble(const char *pattern) { + daPlBase_c::startPatternRumble(pattern); + dAcPy_c *carryPlayer = getCarryPlayer(); + if (carryPlayer != nullptr) { + carryPlayer->startPatternRumble(pattern); + } +} + +void dAcPy_c::setItemGetEffect() { + mPowerUpEffectTimer = 90; + mPowerUpType = 0; +} + +void dAcPy_c::setChukanPowerUpEffect() { + mPowerUpEffectTimer = 90; + mPowerUpType = 1; +} + +void dAcPy_c::endPowerUpEffect() { + if (mPowerUpEffectTimer != 0) { + mItemGetEffect1.fade(); + if (mPowerUpType == 0) { + mItemGetEffect2.fade(); + } + } + mPowerUpEffectTimer = 0; +} + +void dAcPy_c::updateItemGetEffect() { + if (mPowerUpEffectTimer == 0) { + return; + } + mVec3_c efPos = getCenterPos(); + mVec3_c efScale(1.0f, 1.0f, 1.0f); + if (mPowerup == POWERUP_MINI_MUSHROOM) { + efScale.set(0.7f, 0.7f, 0.7f); + } + mItemGetEffect1.createEffect("Wm_mr_itemget01", 0, &efPos, nullptr, &efScale); + if (mPowerUpType == 0) { + int alpha = mPowerUpEffectTimer * 8; + if (alpha > 255) { + alpha = 255; + } + mItemGetEffect1.setColor(255, 255, 255, alpha, EGG::Effect::RECURSIVE_3); + mItemGetEffect1.copyExEffectParam(); + mItemGetEffect2.createEffect("Wm_mr_itemget02", 0, &efPos, nullptr, &efScale); + } +} + +bool dAcPy_c::fn_801477c0() { + if (dInfo_c::mGameFlag & 0x10) { + return false; + } + if ( + dScStage_c::m_instance->mCurrWorld == WORLD_1 & + dScStage_c::m_instance->mCurrCourse == STAGE_1 && + !dSaveMng_c::m_instance->getSaveGame(-1)->isCourseDataFlag(0, 0, 0x10) + ) { + return true; + } + return false; +} + +bool dAcPy_c::searchKinopioNearPlayer(float *dist) { + dAcPy_c *player; + float closest = 1600.0f; + for (int i = 0; i < PLAYER_COUNT; i++) { + if (!(daPyMng_c::mActPlayerInfo & (1 << (u8) i))) { + continue; + } + player = daPyMng_c::getPlayer(i); + if (player == nullptr) { + continue; + } + if (player == this || !player->isDrawingCarryFukidashi()) { + continue; + } + mVec2_c diff( + player->mPos.x - mPos.x, + player->mPos.y - mPos.y + ); + if (closest > diff.length()) { + closest = diff.length(); + } + } + if (closest >= 1600.0f) { + return false; + } + if (dist != nullptr) { + *dist = closest; + } + return true; +} + +void dAcPy_c::managePropelFukidashi() { + if (m_157c != 0) { + m_157c--; + } + if (m_1584 != 0) { + m_1584--; + } + if (isItemKinopio()) { + int check = false; + float dist; + if (isSpinLiftUpEnable() && searchKinopioNearPlayer(&dist)) { + if (m_1580 == 0) { + if (dist < 48.0f) { + check = true; + } + } else if (dist < 80.0f) { + check = true; + } + } + if (check == true) { + if (m_157c != 0) { + check = false; + } + } else { + m_157c = 3; + } + if (m_1580 == 0) { + if (check == true) { + m_1580 = 1; + dGameCom::showFukidashi(mPlayerNo, 8); + m_1584 = 240; + } + } else { + if (m_1584 == 0) { + dGameCom::hideFukidashiTemporarily(mPlayerNo, 8, 0); + } + if (!check) { + m_1580 = 0; + dGameCom::hideFukidashiTemporarily(mPlayerNo, 8, 0); + } + } + } else { + int check = false; + if (isDrawingFukidashi() && isEnablePropelJump() && getCarryPropelBlock() == nullptr) { + if (m_157c == 0) { + check = true; + } + } else { + m_157c = 3; + } + if (m_1580 == 0) { + if (check == true) { + m_1580 = 1; + m_1584 = 480; + } + } else if (m_1584 == 0 && !fn_801477c0()) { + dGameCom::hideFukidashiTemporarily(mPlayerNo, 1, 0); + } else if (!check) { + dGameCom::hideFukidashiTemporarily(mPlayerNo, 1, 0); + } else { + dGameCom::showFukidashi(mPlayerNo, 1); + } + } +} + +bool dAcPy_c::isDrawingFukidashi() { + if ( + isItemKinopio() || + !isStatus(STATUS_9F) || + isDemoAll() || + mSpinCooldown != 0 || + isNowBgCross(BGC_WATER_SHALLOW) || + isStatus(STATUS_GOAL_POLE_TOUCHED) || + isStatus(STATUS_OUT_OF_PLAY) || + dScStage_c::m_miniGame != 0 + ) { + return false; + } + int level = dScStage_c::m_instance->mCurrCourse; + return level != STAGE_TITLE && + level != STAGE_PEACH_CASTLE && + level != STAGE_STAFFROLL; +} + +bool dAcPy_c::isDrawingCarryFukidashi() { + if ( + !isDrawingFukidashi() || + !mBc.isFoot() || + fManager_c::searchBaseByID(mCarryActorID) != nullptr + ) { + return false; + } + return true; +} diff --git a/source/dol/bases/d_a_player_base.cpp b/source/dol/bases/d_a_player_base.cpp new file mode 100644 index 00000000..dfdd9d8a --- /dev/null +++ b/source/dol/bases/d_a_player_base.cpp @@ -0,0 +1,6686 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const float daPlBase_c::sc_DirSpeed[] = { 1.0f, -1.0f }; +const float daPlBase_c::sc_JumpSpeed = 3.628f; +const float daPlBase_c::sc_JumpSpeedNuma1 = 3.5f; +const float daPlBase_c::sc_JumpSpeedNuma2 = 2.3f; +const float daPlBase_c::sc_WaterWalkSpeed = 0.5625f; +const float daPlBase_c::sc_WaterSwimSpeed = 1.125f; +const float daPlBase_c::sc_WaterJumpSpeed = 1.25f; +const float daPlBase_c::sc_WaterMaxFallSpeed = -3.0f; +const float daPlBase_c::sc_MaxFallSpeed = -4.0f; +const float daPlBase_c::sc_MaxFallSpeed_Foot = -2.0f; +const float daPlBase_c::sc_MaxFallDownSpeed = -8.5f; +const float daPlBase_c::scTurnPowerUpRate = 3.0f; + +namespace { + const float l_sakaMaxSpeedRatio[][3] = { + { 1.0f, 1.0f, 1.0f }, + { 1.25f, 0.6875f, 1.0f }, + { 1.25f, 0.6875f, 1.0f }, + { 1.44f, 0.5f, 1.0f }, + { 1.62f, 0.3f, 1.0f }, + }; + const float l_sakaStopAccele[][3] = { + { 0.035f, 0.035f, 0.035f }, + { 0.0315f, 0.046f, 0.035f }, + { 0.028f, 0.06f, 0.035f }, + { 0.021f, 0.123f, 0.035f }, + { 0.014f, 0.175f, 0.035f }, + }; + const float l_sakaMoveAccele[][3] = { + { 0.1f, 0.03f, 0.03f }, + { 0.04f, 0.03f, 0.03f }, + { 0.05f, 0.045f, 0.03f }, + { 0.07f, 0.12f, 0.03f }, + { 0.17f, 0.17, 0.03f }, + }; + const float l_sakaSlipOffSpeed[][3] = { + { 0.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f }, + { 0.2f, -0.2f, 0.0f }, + { 0.4f, -0.4f, 0.0f }, + { 0.4f, -0.4f, 0.0f }, + }; +} + +daPlBase_c::daPlBase_c() : + mpMdlMng(nullptr), + mDemoStateMgr(*this, sStateID::null), + mStateMgr(*this, sStateID::null) +{ + mAreaNo = dScStage_c::m_instance->mCurrAreaNo; + mLayer = dScStage_c::m_instance->mCurrLayer; + mAmiLayer = 1; + mBc.mOwningPlrNo = mPlayerNo; + changeDemoState(StateID_DemoNone, false); + changeState(StateID_None); + mAttentionMode = 3; + mViewLimitPadding = 16.0f; + mEatBehaviour = EAT_TYPE_NONE; +} + +daPlBase_c::~daPlBase_c() { + releaseCcData(); + mpMdlMng = nullptr; +} + +int daPlBase_c::create() { + mKey.init(); + if (dScStage_c::m_gameMode == dScStage_c::GAME_MODE_TITLE_SCREEN) { + mKey.onStatus(dAcPyKey_c::STATUS_FORCE_RIGHT); + } + setZPosition(); + return SUCCEEDED; +} + +int daPlBase_c::preExecute() { + offStatus(STATUS_CAN_EXECUTE); + if (dActor_c::preExecute() == NOT_READY) { + return NOT_READY; + } + if (isStatus(STATUS_STOP_EXECUTE)) { + return NOT_READY; + } + onStatus(STATUS_CAN_EXECUTE); + if (isNowBgCross(BGC_LIFT)) { + mLastPos = mLiftRelatedPos; + } + mBgPressFlags = 0; + offStatus(STATUS_84); + offStatus(STATUS_B7); + offStatus(STATUS_40); + offStatus(STATUS_61); + if (isStatus(STATUS_83)) { + onStatus(STATUS_82); + offStatus(STATUS_83); + } + return SUCCEEDED; +} + +int daPlBase_c::execute() { + updateEndingDance(); + if (isStatus(STATUS_GOAL_POLE_NOT_GOAL_NO_MOVE)) { + mKey.onStatus(dAcPyKey_c::STATUS_NO_INPUT); + } + mKey.update(); + setZPosition(); + releaseCcData(); + executeMain(); + mKey.updateEnd(); + mSndObj.calculate(dAudio::cvtSndObjctPos(getCenterPos())); + return SUCCEEDED; +} + +void daPlBase_c::postExecute(fBase_c::MAIN_STATE_e status) { + if (status == SUCCESS) { + mLastPosDelta = mLastPos - mPos; + mLiftRelatedPos = mPos; + offStatus(STATUS_1A); + offStatus(STATUS_1B); + offStatus(STATUS_BE); + offStatus(STATUS_RIDE_NUT); + offStatus(STATUS_62); + offStatus(STATUS_5B); + offStatus(STATUS_5C); + offStatus(STATUS_89); + offStatus(STATUS_QUAKE_BIG); + offStatus(STATUS_QUAKE_SMALL); + offStatus(STATUS_SWIM_AGAINST_JET_H); + offStatus(STATUS_SWIM_AGAINST_JET_V); + offStatus(STATUS_82); + if (isStatus(STATUS_8D)) { + offStatus(STATUS_8D); + if (isStatus(STATUS_DISPLAY_OUT_DEAD)) { + onStatus(STATUS_STOP_EXECUTE); + } + } + offStatus(STATUS_WAS_TWIRL); + if (isStatus(STATUS_TWIRL)) { + offStatus(STATUS_TWIRL); + onStatus(STATUS_WAS_TWIRL); + } + offStatus(STATUS_A4); + clearFollowMameKuribo(); + clearCcPlayerRev(); + clearCcData(); + } + dActor_c::postExecute(status); +} + +int daPlBase_c::doDelete() { + mIsBeingDeleted = true; + onStatus(STATUS_ABOUT_TO_BE_DELETED); + mStateMgr.finalizeState(); + return SUCCEEDED; +} + +int daPlBase_c::preDraw() { + if (isStatus(STATUS_INVISIBLE)) { + mVisible = false; + } else { + mVisible = true; + } + if (dBaseActor_c::preDraw() == NOT_READY) { + return NOT_READY; + } + return SUCCEEDED; +} + +int daPlBase_c::draw() { + return SUCCEEDED; +} + +STATE_VIRTUAL_DEFINE(daPlBase_c, None); +STATE_VIRTUAL_DEFINE(daPlBase_c, Walk); +STATE_VIRTUAL_DEFINE(daPlBase_c, Jump); +STATE_VIRTUAL_DEFINE(daPlBase_c, SitJump); +STATE_VIRTUAL_DEFINE(daPlBase_c, Fall); +STATE_VIRTUAL_DEFINE(daPlBase_c, Land); +STATE_VIRTUAL_DEFINE(daPlBase_c, Crouch); +STATE_VIRTUAL_DEFINE(daPlBase_c, Slip); +STATE_VIRTUAL_DEFINE(daPlBase_c, Turn); +STATE_VIRTUAL_DEFINE(daPlBase_c, HipAttack); +STATE_VIRTUAL_DEFINE(daPlBase_c, Swim); +STATE_VIRTUAL_DEFINE(daPlBase_c, JumpDai); +STATE_VIRTUAL_DEFINE(daPlBase_c, PlayerJumpDai); +STATE_VIRTUAL_DEFINE(daPlBase_c, Funsui); +STATE_VIRTUAL_DEFINE(daPlBase_c, Kani); +STATE_VIRTUAL_DEFINE(daPlBase_c, Cloud); +STATE_VIRTUAL_DEFINE(daPlBase_c, AnimePlay); +STATE_VIRTUAL_DEFINE(daPlBase_c, WaitJump); + +void daPlBase_c::changeState(const sStateIDIf_c &stateID, void *arg) { + if (isStatus(STATUS_DISABLE_STATE_CHANGE)) { + return; + } + clearComboCount(); + mSubstate = 0; + mSubstateTimer = 0; + mSubstateValue = 0; + offStatus(STATUS_97); + offStatus(STATUS_98); + mStateArg = arg; + mStateMgr.changeState(stateID); +} + +void daPlBase_c::executeState() { + if (mSubstateTimer != 0) { + mSubstateTimer--; + } + mStateMgr.executeState(); +} + +short daPlBase_c::getMukiAngle(u8 direction) { + static const short scMukiAngle[] = { 0x3000, -0x3000 }; + return scMukiAngle[direction]; +} + +int daPlBase_c::turnAngle() { + return mAngle.y.chase(getMukiAngle(mDirection), 0x2000); +} + +int daPlBase_c::addCalcAngleY(short p1, short p2) { + return sLib::addCalcAngle(&mAngle.y.mAngle, p1, p2, 0x2000, 0x400); +} + +short daPlBase_c::getBesideMukiAngle(u8 direction) { + static const short scMukiAngle[] = { 0x4000, -0x4000 }; + return scMukiAngle[direction]; +} + +void daPlBase_c::turnBesideAngle() { + mAngle.y.chase(getBesideMukiAngle(mDirection), 0x2000); +} + +bool daPlBase_c::checkRideActor(daPlBase_c *other) { + if (mRideActorID == other->mUniqueID || other->mRideActorID == mUniqueID) { + return true; + } + return false; +} + +void daPlBase_c::initializeState_None() {} +void daPlBase_c::finalizeState_None() {} +void daPlBase_c::executeState_None() {} + +void daPlBase_c::setWaitActionAnm(AnmBlend_e blendMode) {} +void daPlBase_c::setWalkActionAnm(AnmBlend_e blendMode) {} + +void daPlBase_c::walkActionInit_Wait(AnmBlend_e blendMode) {} +void daPlBase_c::walkAction_Wait() {} + +void daPlBase_c::walkActionInit_Move(AnmBlend_e blendMode) {} +void daPlBase_c::walkAction_Move() { + AnmBlend_e blendMode = BLEND_DEFAULT; + if (!mSpeedF) { + if (isNowBgCross(BGC_11) || mTimer_f4 != 0 || mWindSpeed) { + if (mKey.buttonWalk(nullptr)) { + blendMode = BLEND_NONE; + } else { + walkActionInit_Wait(BLEND_DEFAULT); + return; + } + } else { + if (isNowBgCross(BGC_WALL)) { + if (mPowerup == POWERUP_MINI_MUSHROOM && mBc.getSakaUpDown(mDirection) == 1) { + blendMode = BLEND_NONE; + } else { + walkActionInit_Wait(BLEND_DEFAULT); + return; + } + } + if (isNowBgCross(BGC_SLOPE_AND_HEAD) || !mKey.buttonWalk(nullptr)) { + walkActionInit_Wait(BLEND_DEFAULT); + return; + } + } + } else if (isNowBgCross(BGC_LIFT)) { + mTimer_f4 = 3; + } + setWalkActionAnm(blendMode); + setRunFootEffect(); +} + +void daPlBase_c::initializeState_Walk() {} + +void daPlBase_c::finalizeState_Walk() { + offStatus(STATUS_52); +} + +void daPlBase_c::executeState_Walk() { + if (isStatus(STATUS_52)) { + offStatus(STATUS_52); + } +} + +void daPlBase_c::calcSpeedOnIceLift() { + /// @unofficial + static const float csSpeedMult[] = { 0.5f, 0.8f }; + /// @unofficial + static const float csSpeedMultNoMove[] = { 0.3f, 1.0f }; + if ( + mPowerup != POWERUP_PENGUIN_SUIT && + isNowBgCross(BGC_LIFT) && + isNowBgCross(BGC_ON_ICE) && + std::fabs(mBc.mIceSpeed) > 1.0f + ) { + u8 idx = 0; + if (mBc.mIceSpeed < 0.0f) { + idx = 1; + } + if (mKey.buttonWalk(nullptr)) { + mSpeedF *= csSpeedMult[idx]; + } else { + mSpeedF *= csSpeedMultNoMove[idx]; + } + + float newSpeedF = std::fabs(mSpeedF); + if (newSpeedF < 0.3f) { + newSpeedF = 0.3f; + } else if (newSpeedF > 1.5f) { + newSpeedF = 1.5f; + } + + if (mSpeedF < 0.0f) { + mSpeedF = -newSpeedF; + } else { + mSpeedF = newSpeedF; + } + } +} + +void daPlBase_c::calcAccOnIceLift() { + if ( + isNowBgCross(BGC_LIFT) && + isNowBgCross(BGC_ON_ICE) && + !mKey.buttonWalk(nullptr) && + std::fabs(mBc.mIceSpeed) > 1.0f + ) { + mAccelF = calcSomeAccel(mAccelF); + } +} + +void daPlBase_c::initializeState_Jump() { + onStatus(STATUS_A0); + onStatus(STATUS_A5); + offStatus(STATUS_88); + if (mJumpDaiFallTimer != 0) { + onStatus(STATUS_JUMP_DAI_COOLDOWN); + } +} +void daPlBase_c::finalizeState_Jump() { + mAngle.x = 0; + if (isStatus(STATUS_A5)) { + mSndObj.stopPlyJumpSound(); + } + offStatus(STATUS_JUMP); + offStatus(STATUS_88); + offStatus(STATUS_A5); + offStatus(STATUS_AB); + offStatus(STATUS_A0); + offStatus(STATUS_JUMP_DAI_COOLDOWN); + mJumpDaiFallTimer = 0; + mKey.offStatus(dAcPyKey_c::STATUS_FORCE_JUMP); + mKey.offStatus(dAcPyKey_c::STATUS_FORCE_NO_JUMP); + mKey.offStatus(dAcPyKey_c::STATUS_DISABLE_LR); +} +void daPlBase_c::executeState_Jump() { + if (mJumpDaiFallTimer == 0) { + offStatus(STATUS_JUMP_DAI_COOLDOWN); + } + if (isStatus(STATUS_A5)) { + if (!mKey.buttonJump() || isNowBgCross(BGC_HEAD)) { + mSndObj.stopPlyJumpSound(); + offStatus(STATUS_A5); + } + if (mSpeed.y <= 1.0f) { + offStatus(STATUS_A5); + } + } + onStatus(STATUS_JUMP); +} + +bool daPlBase_c::setCrouchJump() { + if (mKey.triggerJump()) { + changeState(StateID_SitJump, false); + return true; + } + return false; +} + +void daPlBase_c::initializeState_SitJump() {} +void daPlBase_c::finalizeState_SitJump() {} +void daPlBase_c::executeState_SitJump() {} + +void daPlBase_c::setFallAction() { + if (isNowBgCross(BGC_FOOT)) { + return; + } + changeState(StateID_Fall, false); +} + +void daPlBase_c::initializeState_Fall() { + onStatus(STATUS_A0); + if (mJumpDaiFallTimer != 0) { + onStatus(STATUS_JUMP_DAI_COOLDOWN); + } + if (!stateArg()) { + mpMdlMng->setAnm(PLAYER_ANIM_JUMP2, 10.0f, 0.0f); + } + if (isOldBgCross(BGC_LIFT)) { + if (m_1134 * mSpeedF > 0.0f) { + m_1138 = m_1134; + m_1134 = 0.0f; + m_113c = std::fabs(m_1138 / 10.0f); + } + } +} +void daPlBase_c::finalizeState_Fall() { + offStatus(STATUS_A0); + offStatus(STATUS_88); + offStatus(STATUS_JUMP_DAI_COOLDOWN); + mJumpDaiFallTimer = 0; +} +void daPlBase_c::executeState_Fall() { + if (mJumpDaiFallTimer == 0) { + offStatus(STATUS_JUMP_DAI_COOLDOWN); + } +} + +void daPlBase_c::initializeState_Land() {} +void daPlBase_c::finalizeState_Land() {} +void daPlBase_c::executeState_Land() {} + +bool daPlBase_c::checkCrouch() { + return false; +} + +bool daPlBase_c::setCancelCrouch() { + if (checkStandUpRoofOnLift()) { + return false; + } + if (mpMdlMng->getAnm() != PLAYER_ANIM_STOOP_START) { + mpMdlMng->setAnm(PLAYER_ANIM_STOOP_START); + mpMdlMng->mpMdl->setFrame(mpMdlMng->getLastFrame()); + } + if (!isNowBgCross(BGC_WATER_SHALLOW)) { + mpMdlMng->mpMdl->setRate(-1.0f); + } else { + mpMdlMng->mpMdl->setRate(-dPyMdlBase_c::scWaterCrouchAnmSpeed); + } + onStatus(STATUS_52); + changeState(StateID_Walk, BLEND_DEFAULT); + return true; +} + +bool daPlBase_c::checkStandUpRoofOnLift() { + if (isNowBgCross(BGC_FOOT) && !isNowBgCross(BGC_LIFT)) { + return false; + } + return checkStandUpRoof(); +} + +bool daPlBase_c::checkStandUpRoof() { + const sBcPointData *headBgP = getHeadBgPointData(); + if (headBgP == nullptr) { + return false; + } + float standHeadBgY = getStandHeadBgPointY(); + float tmpCalc = mPos.y + standHeadBgY - 1.0f; + mVec3_c p = mVec3_c( + mPos.x + headBgP->mInfMargin / 4096.0f, + mPos.y + 4.0f, + mPos.z + ); + float res; + if (dBc_c::checkTenjou(&p, &res, mLayer, mAmiLayer) && res < tmpCalc) { + return true; + } + p.x = mPos.x + headBgP->mSupMargin / 4096.0f; + if (dBc_c::checkTenjou(&p, &res, mLayer, mAmiLayer) && res < tmpCalc) { + return true; + } + return false; +} + +void daPlBase_c::initializeState_Crouch() {} +void daPlBase_c::finalizeState_Crouch() {} +void daPlBase_c::executeState_Crouch() {} + +void daPlBase_c::initializeState_Slip() { + mSubstate = SLIP_ACTION_NONE; + mpMdlMng->setAnm(PLAYER_ANIM_SLIP); + mMaxSpeedF = getSlipMaxSpeedF(); + mSubstateTimer = 8; + mAutoSlipTimer = 0; + onStatus(STATUS_30); + onStatus(STATUS_97); +} +void daPlBase_c::finalizeState_Slip() { + offStatus(STATUS_30); + offStatus(STATUS_97); + mAngle.x = 0; +} +void daPlBase_c::executeState_Slip() { + gravitySet(); + maxFallSpeedSet(); + moveSpeedSet(); + powerSet(); + sLib::calcTimer(&mAutoSlipTimer); + mAng ang = 0; + if (isNowBgCross(BGC_FOOT)) { + ang = mBc.getSakaAngle(mDirection) * 0.3f; + } + sLib::addCalcAngle(&mAngle.x.mAngle, ang.mAngle, 4, 0x2000, 0x100); + int angle = turnAngle(); + if (isNowBgCross(BGC_AUTOSLIP)) { + mAutoSlipTimer = 9; + } else if (checkJumpTrigger()) { + return; + } else if (angle && mAutoSlipTimer == 0 && checkSlipEndKey()) { + changeActionSlipEnd(BLEND_NONE); + return; + } + switch ((SlipSubstate_e) mSubstate) { + case SLIP_ACTION_NONE: + if (!isNowBgCross(BGC_FOOT) && (mKey.triggerJump() || mKey.triggerCross())) { + changeState(StateID_Fall, false); + } else { + slipActionMove(angle); + } + break; + case SLIP_ACTION_STOOP: + mMaxSpeedF = 0.0f; + if (mpMdlMng->mpMdl->mAnm.isStop()) { + changeState(StateID_Crouch, CROUCH_ARG_FROM_OTHER); + } + break; + case SLIP_ACTION_END: + if (mpMdlMng->mpMdl->mAnm.isStop()) { + changeActionSlipEnd(BLEND_DEFAULT); + } + default: + break; + } +} + +void daPlBase_c::setSlipAction_ToStoop() { + if (checkStandUpRoofOnLift()) { + return; + } + offStatus(STATUS_30); + if (isStatus(STATUS_PENGUIN_SLIDE)) { + offStatus(STATUS_PENGUIN_SLIDE); + } + mSubstate = SLIP_ACTION_STOOP; + mpMdlMng->setAnm(PLAYER_ANIM_SLIP_TO_STOOP); +} + +void daPlBase_c::setSlipAction_ToEnd() { + if (checkStandUpRoofOnLift()) { + return; + } + offStatus(STATUS_30); + if (isStatus(STATUS_PENGUIN_SLIDE)) { + offStatus(STATUS_PENGUIN_SLIDE); + } + mSubstate = SLIP_ACTION_END; + mSpeedF = 0.0f; + mMaxSpeedF = 0.0f; + mpMdlMng->setAnm(PLAYER_ANIM_SLIPED); +} + +void daPlBase_c::setSlipActionEnd() { + offStatus(STATUS_30); + if (!mKey.buttonCrouch()) { + setSlipAction_ToEnd(); + } +} + +void daPlBase_c::setSlipActionViewLimitEnd() { + offStatus(STATUS_30); + if (!mKey.buttonCrouch()) { + setSlipAction_ToEnd(); + } else if (dScStage_c::m_instance->mCurrWorld == WORLD_1 && dScStage_c::m_instance->mCurrCourse == STAGE_6 && dScStage_c::m_instance->mCurrFile == 1) { + if (isNowBgCross(BGC_LIFT)) { + setSlipAction_ToEnd(); + } + } +} + +void daPlBase_c::slipActionMove(int param) { + onStatus(STATUS_30); + if (mSpeedF) { + if (mPowerup != POWERUP_PENGUIN_SUIT) { + setCcAtSlip(); + } else { + setCcAtPenguinSlip(); + } + } + if (isOldBgCross(BGC_FOOT) && mPrevMoveSakaAngle > 0 && mStillSakaAngle * mPrevStillSakaAngle <= 0) { + offNowBgCross(BGC_FOOT); + float baseSpeed = mSpeedF; + float cos = mAng(mPrevMoveSakaAngle).cos(); + mMaxSpeedF = baseSpeed; + mSpeedF = baseSpeed * cos; + mSpeed.y = std::fabs(baseSpeed) * mAng(mPrevMoveSakaAngle).sin(); + } + if (isNowBgCross(BGC_FOOT)) { + if (mSpeedF <= 0.0f && isNowBgCross(BGC_SIDE_LIMIT_L)) { + setSlipActionViewLimitEnd(); + } else if (checkSakaReverse()) { + setSlipActionEnd(); + } else if (isNowBgCross(BGC_SLOPE)) { + mSlipEndTimer = 3; + mSubstateTimer = 8; + mMaxSpeedF = getSlipMaxSpeedF(); + if (!mBc.getSakaUpDown(mDirection)) { + if (param == 0) { + mAccelF = 0.5f * mAccelF; + } + if (std::fabs(mSpeedF) < 1.0f && + ((mCc.getXOffset(0) < 0.0f && mSpeedF >= 0.0f) || + (mCc.getXOffset(0) > 0.0f && mSpeedF <= 0.0f))) + { + setSlipActionEnd(); + } + if (!mSpeedF && checkBGCrossWall(mDirection)) { + setSlipActionEnd(); + } + } + } else { + mSubstateTimer = 0; + mMaxSpeedF = 0.0f; + if (mSlipEndTimer == 0 && std::fabs(mSpeedF) < 1.1f) { + if (!mKey.buttonCrouch()) { + setSlipAction_ToEnd(); + } else { + setSlipAction_ToStoop(); + } + } + } + } else { + if (mSubstateTimer != 0) { + mAccelY = 0.0f; + onStatus(STATUS_98); + } else { + offStatus(STATUS_98); + } + } +} + +void daPlBase_c::changeActionSlipEnd(AnmBlend_e param) { + if ( + (mKey.buttonLeft() && mDirection == 0 && mSpeedF > 0.0f) || + (mKey.buttonRight() &&mDirection == 1 && mSpeedF < 0.0f) + ) { + mAngle.y = getMukiAngle(mDirection); + mDirection ^= 1; + changeState(StateID_Turn); + return; + } + if ( + (mKey.buttonLeft() && mDirection == 0 && mSpeedF < 0.0f) || + (mKey.buttonRight() && mDirection == 1 && mSpeedF > 0.0f) + ) { + mAngle.y = getMukiAngle(mDirection); + mDirection ^= 1; + } + changeState(StateID_Walk, param); +} + +bool daPlBase_c::checkTurn() { + if (!isCarry() && !isStatus(STATUS_74) && std::fabs(mSpeedF) >= 2.5f) { + if (isNowBgCross(BGC_ON_ICE)) { + if ( + (mSpeedF < 0.0f && mKey.buttonRight() && mDirection == 0) || + (mSpeedF > 0.0f && mKey.buttonLeft() && mDirection == 1) + ) { + changeState(StateID_Turn); + return true; + } + } else { + changeState(StateID_Turn); + return true; + } + } + return false; +} + +void daPlBase_c::setTurnEnd() { + mAngle.y = getMukiAngle(mDirection); + changeState(StateID_Walk, BLEND_NONE); +} + +void daPlBase_c::initializeState_Turn() {} +void daPlBase_c::finalizeState_Turn() {} +void daPlBase_c::executeState_Turn() {} + +bool daPlBase_c::setHipAttackOnEnemy(mVec3_c *) { + return 0; +} + +void daPlBase_c::setVsPlHipAttackEffect() { + dEf::createPlayerEffect(mPlayerNo, "Wm_mr_misshit", 0, &mPos, nullptr, nullptr); +} + +void daPlBase_c::setHipAttackEffect() { + if (mRideActorID) { + return; + } + if (!isOnSinkSand()) { + setLandSmokeEffect(getTallType(-1)); + } + if (mGroundType == GROUND_TYPE_WATER) { + startSound(SE_PLY_HPDP_SPLASH, false); + } + if (mPowerup == POWERUP_MINI_MUSHROOM) { + startSound(SE_PLY_HIP_ATTACK_M, false); + return; + } + + if ( + !(GROUND_TYPE_DEFAULT <= mGroundType && mGroundType <= GROUND_TYPE_CLOUD) && + !(GROUND_TYPE_MANTA <= mGroundType && mGroundType <= GROUND_TYPE_CARPET) + ) { + switch (mGroundType) { + case GROUND_TYPE_FUNSUI: + case GROUND_TYPE_LEAF: + startSound(SE_PLY_HIP_ATTACK_SOFT, false); + default: + return; + case GROUND_TYPE_WOOD: + break; + } + } + startSound(SE_PLY_HIP_ATTACK, false); +} + +void daPlBase_c::setHipAttackDropEffect() { + static const float sc_dropEffectScale[] = { 0.7f, 0.8f, 1.0f }; + mVec3_c pos; + mpMdlMng->mpMdl->getJointPos(&pos, 1); + float scale = sc_dropEffectScale[getTallType(-1)]; + mVec3_c scaleVec(scale, scale, scale); + dEf::createPlayerEffect(mPlayerNo, &mHitAttackDropEffect, "Wm_mr_drop", 0, &pos, nullptr, &scaleVec); +} + +void daPlBase_c::setHipBlockBreak() { + if (mPowerup == POWERUP_MINI_MUSHROOM || mPowerup == POWERUP_NONE) { + offStatus(STATUS_C4); + } else { + onStatus(STATUS_C4); + } +} + +void daPlBase_c::setHipAttack_Ready() { + mSubstate = HIP_ACTION_READY; + mpMdlMng->setAnm(PLAYER_ANIM_HIPSR); + mSpeed.y = 1.0f; +} + +void daPlBase_c::setHipAttack_KinopioStart() { + setHipAttack_AttackStart(); + onStatus(STATUS_7F); + onStatus(STATUS_7A); + if (isItemKinopio()) { + startSound(SE_VOC_ITEM_KO_FOUND, false); + } +} + +void daPlBase_c::setHipAttack_AttackStart() { + mSubstate = HIP_ACTION_ATTACK_START; + mpMdlMng->setAnm(PLAYER_ANIM_HIPAT); + mSubstateTimer = 5; + mSpeed.y = 0.0f; +} + +void daPlBase_c::setHipAttack_AttackFall() { + mSubstate = HIP_ACTION_ATTACK_FALL; + mAccelF = 0.1f; + mMaxSpeedF = 0.0f; + mAccelY = *getGravityData(); + mMaxFallSpeed = -6.0f; + if (stateArg() == HIP_ATTACK_ARG_ITEM_KINOPIO) { + mSpeed.y = -2.0f; + } else { + mSpeed.y = -6.0f; + } + onStatus(STATUS_HIP_ATTACK_FALL); + setHipBlockBreak(); + mSubstateTimer = 5; +} + +void daPlBase_c::setHipAttack_StandNormal() { + mSubstateTimer = 20; + mSubstate = HIP_ACTION_STAND_NORMAL; + mpMdlMng->setAnm(PLAYER_ANIM_HIPED); + onStatus(STATUS_HIP_ATTACK_STAND_UP); + offStatus(STATUS_HIP_ATTACK_FALL); + onStatus(STATUS_9F); + mAccelY = *getGravityData(); + mMaxFallSpeed = -6.0f; + mSpeed.y = 0.0f; +} + +void daPlBase_c::setHipAttack_StandNormalEnd() { + mSubstate = HIP_ACTION_STAND_NORMAL_END; + mpMdlMng->setAnm(PLAYER_ANIM_SLIPED); + offStatus(STATUS_HIP_ATTACK_STAND_UP); +} + +void daPlBase_c::setHipAttack_ToStoop() { + mSubstate = HIP_ACTION_TO_STOOP; + mpMdlMng->setAnm(PLAYER_ANIM_HIP_TO_STOOP); + offStatus(STATUS_HIP_ATTACK_STAND_UP); +} + +void daPlBase_c::HipAction_Ready() { + if (mpMdlMng->mpMdl->mAnm.isStop()) { + setHipAttack_AttackStart(); + } +} + +void daPlBase_c::HipAction_AttackStart() { + if (mSubstateTimer == 0) { + setHipAttack_AttackFall(); + } +} + +void daPlBase_c::HipAction_AttackFall() { + setHipAttackDropEffect(); + if (mSubstateTimer == 0 || isNowBgCross(BGC_FOOT)) { + offStatus(STATUS_7F); + offStatus(STATUS_7A); + } + if (!isNowBgCross(BGC_FOOT)) { + if (isNowBgCross(BGC_WATER_SHALLOW)) { + mMaxFallSpeed = -3.0f; + } else { + mMaxFallSpeed = -6.0f; + } + mAccelY = *getGravityData(); + int dir; + if (mKey.buttonWalk(&dir)) { + mMaxSpeedF = sc_DirSpeed[dir] * 0.3f; + } + if (mKey.buttonDown() && mSpeed.y < 0.0f) { + setHipBlockBreak(); + } + if (!isStatus(STATUS_PRESS_ATTACH) && mKey.buttonUp()) { + changeState(StateID_Fall, false); + } + } else { + if (!mKey.buttonDown()) { + offStatus(STATUS_C4); + } + setHipAttackEffect(); + int quakeType = 0; + if (mPowerup == POWERUP_MINI_MUSHROOM) { + quakeType = 2; + } + daPyMng_c::setHipAttackQuake(quakeType, mPlayerNo); + onStatus(STATUS_HIP_ATTACK_LAND); + offStatus(STATUS_91); + if (isNowBgCross(BGC_CLIFF)) { + changeState(StateID_Kani, KANI_ARG_JUMP_HANG); + } else if (isSlipSaka()) { + if (!isNowBgCross(BGC_WATER_TOUCH)) { + if (mBc.getSakaType() >= 2) { + mSpeedF = getSlipMaxSpeedF(); + } else { + mSpeedF = getSlipMaxSpeedF() * 0.5f; + } + } + setSlipAction(); + } else { + mMaxSpeedF = 0.0f; + mSpeedF = 0.0f; + mSpeed.y = 0.0f; + mAccelY = 0.0f; + mSubstate = HIP_ACTION_GROUND; + } + } +} + +void daPlBase_c::HipAction_Ground() { + if (!mKey.buttonDown() && !isNowBgCross(BGC_FOOT)) { + changeState(StateID_Fall, false); + } else { + setHipAttack_StandNormal(); + } +} + +void daPlBase_c::HipAction_StandNormal() { + if (mpMdlMng->getAnm() != PLAYER_ANIM_HIPED) { + mpMdlMng->setAnm(PLAYER_ANIM_HIPED); + } + if (isNowBgCross(BGC_FOOT)) { + if (mpMdlMng->isAnmStop()) { + if (!mKey.buttonDown()) { + offStatus(STATUS_HIP_ATTACK); + setHipAttack_StandNormalEnd(); + } else { + setHipBlockBreak(); + if (m_344 == 0) { + if (isNowBgCross(BGC_54)) { + mSubstateTimer = 15; + } + if (dScStage_c::m_isStaffCredit && isNowBgCross(BGC_FOOT) && !isNowBgCross(BGC_LIFT)) { + m_344 = 1; + } + } + if (mSubstateTimer == 0) { + offStatus(STATUS_HIP_ATTACK); + setHipAttack_ToStoop(); + } + } + } else if (isSlipSaka()) { + mSpeedF = getSlipMaxSpeedF(); + setSlipAction(); + } else { + turnAngle(); + } + } else { + if (mKey.buttonCrouch()) { + setHipAttack_AttackFall(); + } + } +} + +void daPlBase_c::HipAction_StandNormalEnd() { + if (!checkCrouch()) { + if (mpMdlMng->mpMdl->mAnm.isStop()) { + changeState(StateID_Walk, BLEND_DEFAULT); + } else { + turnAngle(); + } + } +} + +void daPlBase_c::HipAction_ToStoop() { + if (mpMdlMng->mpMdl->mAnm.isStop()) { + changeState(StateID_Crouch, CROUCH_ARG_FROM_OTHER); + } else { + turnAngle(); + } +} + +void daPlBase_c::initializeState_HipAttack() { + mAngle.y = getMukiAngle(mDirection); + mSpeedF = 0.0f; + mMaxSpeedF = 0.0f; + mAccelY = 0.0f; + switch (stateArg()) { + case HIP_ATTACK_ARG_PLAYER: + setHipAttack_Ready(); + break; + case HIP_ATTACK_ARG_ITEM_KINOPIO: + setHipAttack_KinopioStart(); + break; + } + onStatus(STATUS_A8); + onStatus(STATUS_AA); + onStatus(STATUS_HIP_ATTACK); +} + +void daPlBase_c::finalizeState_HipAttack() { + mMaxFallSpeed = -4.0f; + offStatus(STATUS_HIP_ATTACK_FALL); + offStatus(STATUS_A8); + offStatus(STATUS_AA); + offStatus(STATUS_C4); + offStatus(STATUS_PRESS_ATTACH); + offStatus(STATUS_HIP_ATTACK_LAND); + offStatus(STATUS_HIP_ATTACK_STAND_UP); + offStatus(STATUS_9F); + offStatus(STATUS_HIP_ATTACK); + offStatus(STATUS_7F); + offStatus(STATUS_7A); + m_344 = 0; +} + +void daPlBase_c::executeState_HipAttack() { + static ProcFunc l_HipActionProc[] = { + &daPlBase_c::HipAction_Ready, + &daPlBase_c::HipAction_AttackStart, + &daPlBase_c::HipAction_AttackFall, + &daPlBase_c::HipAction_Ground, + &daPlBase_c::HipAction_StandNormal, + &daPlBase_c::HipAction_StandNormalEnd, + &daPlBase_c::HipAction_ToStoop + }; + + offStatus(STATUS_HIP_ATTACK_LAND); + if (isStatus(STATUS_HIP_ATTACK_FALL)) { + setCcAtHipAttack(); + } + if (isNowBgCross(BGC_WATER_SUBMERGED)) { + offStatus(STATUS_AA); + } + if (mSubstate < HIP_ACTION_STAND_NORMAL || !checkJumpTrigger()) { + (this->*l_HipActionProc[mSubstate])(); + if (isStatus(STATUS_PRESS_ATTACH)) { + offStatus(STATUS_PRESS_ATTACH); + mPos.x = mPressAttachPos.x; + mPos.y = mPressAttachPos.y; + } + } +} + +void daPlBase_c::initializeState_Swim() {} +void daPlBase_c::finalizeState_Swim() {} +void daPlBase_c::executeState_Swim() {} + +bool daPlBase_c::setJumpDaiRide() { + if (isStatus(STATUS_45) || isNowBgCross(BGC_HEAD)) { + return false; + } + changeState(StateID_JumpDai); + return true; +} + +void daPlBase_c::initializeState_JumpDai() { + onStatus(STATUS_SPRING_JUMP); + onStatus(STATUS_86); + onStatus(STATUS_BIG_JUMP); + mKey.onStatus(dAcPyKey_c::STATUS_NO_INPUT); + mSpeed.y = 0.0f; + mSpeedF = 0.0f; + if (mpMdlMng->getAnm() == PLAYER_ANIM_STOOP) { + mSubstate = JUMP_DAI_HIGH_JUMP; + } else { + mpMdlMng->setAnm(PLAYER_ANIM_JUMPED); + } +} + +void daPlBase_c::finalizeState_JumpDai() { + offStatus(STATUS_BIG_JUMP); + offStatus(STATUS_SPRING_JUMP); + mKey.offStatus(dAcPyKey_c::STATUS_NO_INPUT); +} + +void daPlBase_c::executeState_JumpDai() { + if (!isStatus(STATUS_86)) { + changeState(StateID_Fall, false); + } else { + turnAngle(); + switch ((JumpDaiSubstate_e) mSubstate) { + case JUMP_DAI_MOVE_DOWN: + if (mpMdlMng->mpMdl->mAnm.isStop()) { + setWaitActionAnm(BLEND_DEFAULT); + mSubstate = JUMP_DAI_HIGH_JUMP; + } + break; + case JUMP_DAI_HIGH_JUMP: + break; + } + } +} + +bool daPlBase_c::setPlayerJumpDai(daPlBase_c *other) { + if (mRideActorID == 0) { + float topPos = other->getHeadTopPosP()->y - 4.0f; + mVec3_c pos = mVec3_c( + mPos.x, + topPos, + mPos.z + ); + float f; + if (mBc.checkRoofPlayer(&pos, &f) && f < topPos + getModelHeight()) { + return false; + } + mRideActorID = other->mUniqueID; + changeState(StateID_PlayerJumpDai); + return true; + } + return false; +} + +void daPlBase_c::setPlayerJumoDaiPos() { + daPlBase_c *rideActor = (daPlBase_c *) fManager_c::searchBaseByID(mRideActorID); + if (rideActor == nullptr) { + return; + } + mPos.set( + mJumpDaiOffset.x + rideActor->mPos.x, + rideActor->getHeadTopPosP()->y - 4.0f, + mJumpDaiOffset.z + rideActor->mPos.z + ); +} + +void daPlBase_c::initializeState_PlayerJumpDai() { + onStatus(STATUS_PLAYER_JUMP); + onStatus(STATUS_BIG_JUMP); + daPlBase_c *rideActor = (daPlBase_c *) fManager_c::searchBaseByID(mRideActorID); + if (rideActor != nullptr) { + rideActor->initStampReduction(); + setNoHitPlayer(rideActor, 5); + mJumpDaiOffset = mPos - rideActor->mPos; + } + mJumpDaiSpeedF = mSpeedF; + mSpeedF = 0.0f; + mSpeed.y = 0.0f; + if (mpMdlMng->getAnm() != PLAYER_ANIM_STOOP) { + mpMdlMng->setAnm(PLAYER_ANIM_JUMPED); + } + if (mKey.triggerJumpBuf(5)) { + mSubstate = JUMP_DAI_HIGH_JUMP; + } else { + mSubstate = JUMP_DAI_MOVE_DOWN; + } + mSubstateValue = 0; +} + +void daPlBase_c::finalizeState_PlayerJumpDai() { + offStatus(STATUS_PLAYER_JUMP); + offStatus(STATUS_BIG_JUMP); + mRideActorID = (fBaseID_e) 0; +} + +void daPlBase_c::executeState_PlayerJumpDai() { + daPlBase_c *rideActor = (daPlBase_c *) fManager_c::searchBaseByID(mRideActorID); + if (rideActor == nullptr) { + changeState(StateID_Fall, false); + } else if (isNowBgCross(BGC_HEAD)) { + changeState(StateID_Fall, false); + mJumpDaiFallTimer = 30; + } else { + setNoHitPlayer(rideActor, 5); + turnAngle(); + if (mpMdlMng->mpMdl->mCurrAnmID == PLAYER_ANIM_JUMPED && mpMdlMng->mpMdl->mAnm.isStop()) { + setWaitActionAnm(BLEND_DEFAULT); + } + switch ((JumpDaiSubstate_e) mSubstate) { + case JUMP_DAI_MOVE_DOWN: + if (mSubstateValue < 5) { + if (mKey.triggerJump()) { + mSubstate = JUMP_DAI_HIGH_JUMP; + } + } else if (isMameAction()) { + setJump(daPlBase_c::sc_JumpSpeed - 0.35f, mJumpDaiSpeedF, true, 0, 0); + return; + } else if (mKey.buttonJump()) { + setJump(daPlBase_c::sc_JumpSpeed + 0.2f, mJumpDaiSpeedF, true, 0, 2); + return; + } else { + setJump(daPlBase_c::sc_JumpSpeed + 1.0f, mJumpDaiSpeedF, true, 2, 0); + return; + } + break; + case JUMP_DAI_HIGH_JUMP: + if (mSubstateValue > 5) { + float jumpSpeed = daPlBase_c::sc_JumpSpeed + 0.8f; + if (isMameAction()) { + jumpSpeed = daPlBase_c::sc_JumpSpeed + 0.2f; + } + setJump(jumpSpeed, 0.0f, true, 1, 2); + return; + } + break; + } + rideActor->calcJumpDaiReductionScale(mSubstateValue, 5); + mSubstateValue++; + } +} + +bool daPlBase_c::setFunsui() { + if (isDemo()) { + return false; + } + if (!isState(StateID_Funsui)) { + changeState(StateID_Funsui); + } + return true; +} + +bool daPlBase_c::updateFunsuiPos(float x, float y) { + if (isState(StateID_Funsui)) { + mPos.x = x; + mPos.y = y; + return true; + } + return false; +} + +bool daPlBase_c::releaseFunsui(float f) { + if (isState(StateID_Funsui)) { + mSpeed.y = f; + mSubstate = FUNSUI_ACTION_START; + mKey.onStatus(dAcPyKey_c::STATUS_FORCE_NO_JUMP); + offStatus(STATUS_7F); + } + return true; +} + +void daPlBase_c::releaseFunsuiAction() { + changeState(StateID_Fall, false); +} + +void daPlBase_c::initializeState_Funsui() { + onStatus(STATUS_7F); + mAccelY = 0.0f; + mSpeedF *= 0.7f; + mSpeed.y = 0.0f; + mSubstate = FUNSUI_ACTION_NONE; + mpMdlMng->setAnm(PLAYER_ANIM_BLOW_UP); + if (mPlayerNo >= 0) { + startPlayerVoice(VOICE_INTO_SANDPILLAR, 0); + dQuake_c::m_instance->shockMotor(mPlayerNo, dQuake_c::TYPE_7, 0, false); + mSubstateTimer = 8; + } +} + +void daPlBase_c::finalizeState_Funsui() { + offStatus(STATUS_7F); + mKey.offStatus(dAcPyKey_c::STATUS_FORCE_NO_JUMP); +} + +void daPlBase_c::executeState_Funsui() { + if (mPlayerNo >= 0) { + dEf::createPlayerEffect(mPlayerNo, &mSmokeEffect, "Wm_mr_sprisesmoke", 0, &mPos, nullptr, nullptr); + if (mSubstateTimer == 0) { + mSubstateTimer = 8; + dQuake_c::m_instance->shockMotor(mPlayerNo, dQuake_c::TYPE_8, 0, false); + } + } + turnAngle(); + if (mSubstate == FUNSUI_ACTION_START) { + gravitySet(); + maxFallSpeedSet(); + if (mSpeed.y <= 0.0f || isNowBgCross(BGC_HEAD)) { + releaseFunsuiAction(); + return; + } + } + int dir; + if (mKey.buttonWalk(&dir)) { + mMaxSpeedF = sc_DirSpeed[dir] * 0.35f; + } else { + mMaxSpeedF = 0.0f; + } + if (std::fabs(mSpeedF) > 0.35f) { + mAccelF = 0.1f; + } else { + mAccelF = 0.04f; + } +} + +void daPlBase_c::initializeState_Kani() {} +void daPlBase_c::finalizeState_Kani() {} +void daPlBase_c::executeState_Kani() {} + +bool daPlBase_c::setCloudOn(dActor_c *cloudActor) { + if (isNowBgCross(BGC_FOOT) || isStatus(STATUS_7E) || isStatus(STATUS_VINE)) { + return false; + } + if (cloudActor->mPos.y + getCloudOffsetY() >= mPos.y && mSpeed.y < 0.0f && mRideActorID == 0) { + mRideActorID = cloudActor->mUniqueID; + changeState(StateID_Cloud); + return true; + } + return false; +} + +void daPlBase_c::cancelCloudOn() { + mRideActorID = (fBaseID_e) 0; +} + +float daPlBase_c::getCloudOffsetY() { + return 0.0f; +} + +mVec3_c daPlBase_c::getCloudPos() { + return mVec3_c( + mPos.x, + mPos.y - getCloudOffsetY(), + mPos.z + ); +} + +void daPlBase_c::initializeState_Cloud() { + startSound(SE_PLY_RIDE_CLOUD, 0); + onStatus(STATUS_4E); + mAccelY = 0.0f; + mSpeed.y = 0.1f; + mSpeedF = 0.0f; + mMaxSpeedF = 0.0f; + mpMdlMng->setAnm(PLAYER_ANIM_JUMPED); + mRc.mFlags |= 4; +} + +void daPlBase_c::finalizeState_Cloud() { + mAngle.x = 0; + cancelCloudOn(); + offStatus(STATUS_4E); + offStatus(STATUS_51); + mRc.mFlags &= ~4; +} + +bool daPlBase_c::updateCloudMove() { + daPlBase_c *rideActor = (daPlBase_c *) fManager_c::searchBaseByID(mRideActorID); + if (rideActor == nullptr) { + changeState(StateID_Fall, false); + return true; + } + if (mKey.triggerJump()) { + changeState(StateID_Jump, nullptr); + return true; + } + onStatus(STATUS_82); + mPos = rideActor->mPos; + mPos.y += getCloudOffsetY(); + mSpeed.y = 0.0f; + if (!isStatus(STATUS_SPIN)) { + mAngle.set(rideActor->mAngle); + mDirection = rideActor->mDirection; + } + return false; +} + +void daPlBase_c::executeState_Cloud() {} + +void daPlBase_c::initializeState_AnimePlay() { + mDemoAnime = stateArg(); + if (mDemoAnime != DEMO_ANIME_NORMAL) { + onStatus(STATUS_DISABLE_STATE_CHANGE); + } +} + +void daPlBase_c::finalizeState_AnimePlay() { + offStatus(STATUS_DISABLE_STATE_CHANGE); + offStatus(STATUS_24); +} + +void daPlBase_c::executeState_AnimePlay() { + static const ProcFunc scDemoAnmFunc[] = { + &daPlBase_c::DemoAnmNormal, + &daPlBase_c::DemoAnmBossSetUp, + &daPlBase_c::DemoAnmBossGlad, + &daPlBase_c::DemoAnmBossAttention, + &daPlBase_c::DemoAnmBossKeyGet, + &daPlBase_c::DemoAnmBossGlad + }; + + mAccelY = *getGravityData(); + maxFallSpeedSet(); + moveSpeedSet(); + powerSet(); + if (isStatus(STATUS_DISABLE_STATE_CHANGE) || !checkWalkNextAction()) { + (this->*scDemoAnmFunc[mDemoAnime])(); + } +} + +void daPlBase_c::DemoAnmNormal() { + if (isStatus(STATUS_24)) { + addCalcAngleY(0, 10); + } else { + turnAngle(); + } + if (mpMdlMng->mpMdl->mAnm.isStop()) { + setControlDemoWait(); + } +} + +void daPlBase_c::DemoAnmBossSetUp() { + if (mSubstate == ANIME_PLAY_ACTION_0) { + mpMdlMng->setAnm(PLAYER_ANIM_WAIT_L3); + mSubstate++; + offStatus(STATUS_DISABLE_STATE_CHANGE); + } +} + +void daPlBase_c::DemoAnmBossGlad() { + addCalcAngleY(0, 10); + switch (mSubstate) { + case 0: + mSubstateTimer = 15; + mSubstate++; + // fallthrough + case 1: + if (mSubstateTimer == 0) { + initDemoKimePose(); + mSubstate++; + } + break; + case 2: { + ClearType_e clearType = CLEAR_TYPE_BOSS; + if (mDemoAnime == DEMO_ANIME_BOSS_GLAD_2) { + clearType = CLEAR_TYPE_FINAL_BOSS; + } + if (!updateDemoKimePose(clearType)) { + break; + } + mpMdlMng->setAnm(PLAYER_ANIM_WAIT, 5.0f, 0.0f); + mSubstate++; + offStatus(STATUS_DISABLE_STATE_CHANGE); + break; + } + default: + break; + } +} + +void daPlBase_c::DemoAnmBossAttention() { + daPlBase_c *boss = (daPlBase_c *) dAttention_c::mspInstance->search(mpMdlMng->mpMdl->mHatPosMaybe); + if (boss != nullptr) { + if (boss->getLookatPos().x > mPos.x) { + mDirection = DIR_LR_R; + } else { + mDirection = DIR_LR_L; + } + } + switch (mSubstate) { + default: + break; + case HIP_ACTION_READY: + if (mDirection == DIR_LR_R) { + mpMdlMng->setAnm(PLAYER_ANIM_WAIT_L_DUPLICATE); + } else { + mpMdlMng->setAnm(PLAYER_ANIM_WAIT_R_DUPLICATE); + } + mSubstate++; + break; + case HIP_ACTION_ATTACK_START: + if (mAngle.y.chase(getMukiAngle(mDirection), 0x800)) { + mSubstate++; + offStatus(STATUS_DISABLE_STATE_CHANGE); + } + break; + } +} + +void daPlBase_c::DemoAnmBossKeyGet() { + addCalcAngleY(0, 10); + switch (mSubstate) { + case 0: + mSubstateTimer = 15; + mSubstate++; + // [Fallthrough] + case 1: + if (mSubstateTimer == 0) { + mpMdlMng->setAnm(PLAYER_ANIM_BOSS_KEY_GET); + startKimePoseVoice(CLEAR_TYPE_BOSS); + mSubstate++; + offStatus(STATUS_DISABLE_STATE_CHANGE); + } + break; + default: + break; + } +} + +void daPlBase_c::initializeState_WaitJump() { + startQuakeShock(dQuake_c::TYPE_5); + onStatus(STATUS_WAIT_JUMP); + mKey.onStatus(dAcPyKey_c::STATUS_FORCE_NO_JUMP); + + mSpeedF = 0.0f; + mpMdlMng->setAnm(PLAYER_ANIM_WAIT); + mAngle.y = getMukiAngle(mDirection); +} + +void daPlBase_c::finalizeState_WaitJump() { + offStatus(STATUS_WAIT_JUMP); + mKey.offStatus(dAcPyKey_c::STATUS_FORCE_NO_JUMP); +} + +void daPlBase_c::executeState_WaitJump() { + gravitySet(); + maxFallSpeedSet(); + moveSpeedSet(); + airPowerSet(); + if (mSpeed.y <= 0.0f) { + changeState(StateID_Fall, false); + } +} + +bool daPlBase_c::checkSakaReverse() { + if (std::fabs(mSpeedF) < 0.5f && mBc.mPlayerFlags & 4) { + return true; + } + return false; +} + +bool daPlBase_c::isSaka() { + if (isNowBgCross(BGC_SLOPE) ? 1 : 0) { + return true; + } + return false; +} + +bool daPlBase_c::isSlipSaka() { + if (isSaka() && mBc.getFootAttr() != 10) { + return true; + } + return false; +} + +void daPlBase_c::setSlipAction() { + mMoveSakaAngle = mBc.getSakaAngle(mSpeedF); + changeState(StateID_Slip); +} + +bool daPlBase_c::checkSlip() { + if ( + (mSpeedF > 0.0f || !isNowBgCross(BGC_SIDE_LIMIT_L)) && + isNowBgCross(BGC_AUTOSLIP) + ) { + setSlipAction(); + return true; + } + return false; +} + +bool daPlBase_c::checkCrouchSlip() { + if (isNowBgCross(BGC_WATER_SHALLOW)) { + return false; + } + if ( + (mSpeedF > 0.0f || !isNowBgCross(BGC_SIDE_LIMIT_L)) && + (isNowBgCross(BGC_AUTOSLIP) || isSlipSaka()) + ) { + setSlipAction(); + return true; + } + return false; +} + +bool daPlBase_c::checkSlipEndKey() { + if (isNowBgCross(BGC_FOOT)) { + if (!mKey.buttonDown()) { + if (mBc.getSakaType() == 0) { + if (mKey.buttonCross()) { + return true; + } + } else if (mBc.getSakaType() != 4) { + if ( + mKey.buttonLeft() && mBc.getSakaDir() == 0 || + mKey.buttonRight() && mBc.getSakaDir() == 1 + ) { + return true; + } + } + } + if (mKey.buttonUp()) { + return true; + } + } + return false; +} + +float daPlBase_c::getSlipMaxSpeedF() { + if (isSaka()) { + return sc_DirSpeed[mBc.getSakaDir()] * 4.0f; + } + return 0.0f; +} + +float daPlBase_c::getSakaMaxSpeedRatio(u8 direction) { + return l_sakaMaxSpeedRatio[mBc.getSakaType()][mBc.getSakaUpDown(direction)]; +} + +float daPlBase_c::getSakaStopAccele(u8 direction) { + return l_sakaStopAccele[mBc.getSakaType()][mBc.getSakaUpDown(direction)]; +} + +float daPlBase_c::getSakaMoveAccele(u8 direction) { + return l_sakaMoveAccele[mBc.getSakaType()][mBc.getSakaUpDown(direction)]; +} + +float daPlBase_c::getIceSakaSlipOffSpeed() { + return l_sakaSlipOffSpeed[mBc.getSakaType()][mBc.getSakaDir()]; +} + +bool daPlBase_c::setSandMoveSpeed() { + if (isOnSinkSand()) { + int dir; + if (mKey.buttonWalk(&dir)) { + if (isStatus(STATUS_SPIN)) { + mMaxSpeedF = sc_DirSpeed[dir]; + } else { + mMaxSpeedF = sc_DirSpeed[dir] * 0.5f; + } + } else { + mMaxSpeedF = 0.0f; + } + if (mSpeedF * mMaxSpeedF >= 0.0f) { + if (std::fabs(mSpeedF) > std::fabs(mMaxSpeedF)) { + mSpeedF = mMaxSpeedF; + } + } else { + mSpeedF = 0.0f; + } + return true; + } + return false; +} + +void daPlBase_c::moveSpeedSet() { + if (!setSandMoveSpeed() && !isStatus(STATUS_96)) { + int dir; + if (mKey.buttonWalk(&dir)) { + if (!isNowBgCross(BGC_FOOT)) { + float absSpeed = std::fabs(mSpeedF); + float speed1 = sc_DirSpeed[dir] * getSpeedData()->mLowSpeed; + float speed2 = sc_DirSpeed[dir] * getSpeedData()->mHighSpeed; + float tmp = sc_DirSpeed[dir] * absSpeed; + if (absSpeed >= std::fabs(speed2) || mKey.buttonDush()) { + mMaxSpeedF = speed2; + } else if (absSpeed > std::fabs(speed1)) { + mMaxSpeedF = tmp; + } else { + mMaxSpeedF = speed1; + } + } else { + float speed; + if (mKey.buttonDush()) { + speed = sc_DirSpeed[dir] * getSpeedData()->mHighSpeed; + } else { + speed = sc_DirSpeed[dir] * getSpeedData()->mLowSpeed; + } + mMaxSpeedF = speed * getSakaMaxSpeedRatio(dir); + } + } else { + mMaxSpeedF = 0.0f; + if (checkSakaReverse()) { + mSpeedF = 0.0f; + } else if (getPowerChangeType(false) == POWER_CHANGE_ICE) { + mMaxSpeedF = getIceSakaSlipOffSpeed(); + } + } + if (!isNowBgCross(BGC_FOOT) && !isStatus(STATUS_88) && std::fabs(mSpeedF) > getSpeedData()->mHighSpeed) { + if (mSpeedF < 0.0f) { + mSpeedF = -getSpeedData()->mHighSpeed; + } else { + mSpeedF = getSpeedData()->mHighSpeed; + } + } + } +} + +void daPlBase_c::simpleMoveSpeedSet() { + if (!setSandMoveSpeed()) { + int dir; + if (mKey.buttonWalk(&dir)) { + if (mKey.buttonDush()) { + mMaxSpeedF = sc_DirSpeed[dir] * getSpeedData()->mHighSpeed; + } else { + mMaxSpeedF = sc_DirSpeed[dir] * getSpeedData()->mLowSpeed; + } + } else { + mMaxSpeedF = 0.0f; + } + } +} + +void daPlBase_c::grandPowerSet() { + if (isOnSinkSand()) { + mAccelF = getSpeedData()->mPowerChangeNormal.mVerySlowAccel; + } else if (isStatus(STATUS_30)) { + slipPowerSet(1); + } else { + slipPowerSet(0); + } +} + +void daPlBase_c::slipPowerSet(int mode) { + /// @unofficial + static const float sc_data[] = { 1.1f, 0.9f, 1.0f }; + if (isSaka()) { + int dir = 0; + if (mSpeedF < 0.0f) { + dir = 1; + } + mAccelF = getSakaMoveAccele(dir); + int dir2; + if (mKey.buttonWalk(&dir2)) { + mAccelF *= sc_data[mBc.getSakaUpDown(dir2)]; + } + if (mode == 0) { + if (!mKey.buttonWalk(&dir)) { + mAccelF = getSakaStopAccele(dir); + if (isStatus(STATUS_89)) { + mAccelF = calcSomeAccel(mAccelF); + } + } else if (mSpeedF * sc_DirSpeed[mDirection] < 0.0f) { + mAccelF = getSpeedData()->mPowerChangeNormal.mTurnAccel; + if (isStatus(STATUS_89)) { + mAccelF = calcSomeAccel(mAccelF); + } + return; + } + } + icePowerChange(mode); + } else { + if (mode == 1) { + if (isStatus(STATUS_31)) { + mAccelF = 0.05f; + } else { + mAccelF = 0.09f; + } + icePowerChange(1); + } else { + normalPowerSet(); + } + } +} + +void daPlBase_c::normalPowerSet() { + if (std::fabs(mSpeedF) > getSpeedData()->mHighSpeed) { + mAccelF = 0.75f; + return; + } + PowerChangeType_e powerChangeType = getPowerChangeType(false); + sPowerChangeSpeedData data; + getPowerChangeSpeedData(data); + if (!mKey.buttonWalk(nullptr)) { + if (mSpeedF * sc_DirSpeed[mDirection] < 0.0f) { + mAccelF = data.mTurnNoInputAccel; + } else if (std::fabs(mSpeedF) < getSpeedData()->mLowSpeed) { + mAccelF = data.mNoInputAccel; + } else { + mAccelF = data.mDefaultAccel; + } + if (powerChangeType == POWER_CHANGE_ICE && std::fabs(mSpeedF) < 0.5f) { + mAccelF = 0.004f; + } + if (isStatus(STATUS_89)) { + mAccelF = calcSomeAccel(mAccelF); + } + return; + } + if (mSpeedF * sc_DirSpeed[mDirection] < 0.0f) { + mAccelF = data.mTurnAccel; + if (isStatus(STATUS_89)) { + mAccelF = calcSomeAccel(mAccelF); + } + return; + } + + float absMaxSpeed = std::fabs(mMaxSpeedF); + float absSpeed = std::fabs(mSpeedF); + + if (absSpeed < 0.5f) { + mAccelF = data.mVerySlowAccel; + } else if (absSpeed < getSpeedData()->mLowSpeed) { + if (mKey.buttonDush()) { + mAccelF = data.mRunSlowAccel; + } else { + mAccelF = data.mSlowAccel; + } + } else if (absSpeed < getSpeedData()->mMediumSpeed) { + if (absMaxSpeed < getSpeedData()->mMediumSpeed) { + mAccelF = data.mDefaultAccel; + } else { + mAccelF = data.mMediumAccel; + } + } else { + if (absMaxSpeed < getSpeedData()->mMediumSpeed) { + mAccelF = data.mDefaultAccel; + } else { + mAccelF = data.mFastAccel; + } + } +} + +daPlBase_c::PowerChangeType_e daPlBase_c::getPowerChangeType(bool affectPenguin) { + if (!affectPenguin && isStatus(STATUS_IS_PENGUIN)) { + return POWER_CHANGE_NORMAL; + } + if (isNowBgCross(BGC_ON_ICE)) { + return POWER_CHANGE_ICE; + } + if (isNowBgCross(BGC_ON_ICE_LOW_SLIP)) { + return POWER_CHANGE_LOW_SLIP; + } + if (isNowBgCross(BGC_ON_SNOW) ? 1 : 0) { + return POWER_CHANGE_LOW_SLIP; + } + return POWER_CHANGE_NORMAL; +} + +void daPlBase_c::getPowerChangeSpeedData(sPowerChangeSpeedData &data) { + switch (getPowerChangeType(false)) { + case POWER_CHANGE_NORMAL: + data = getSpeedData()->mPowerChangeNormal; + break; + case POWER_CHANGE_ICE: + data = getSpeedData()->mPowerChangeIce; + break; + case POWER_CHANGE_LOW_SLIP: + data = getSpeedData()->mPowerChangeLowSlip; + break; + } +} + +void daPlBase_c::getTurnPower(sTurnPowerData &bb) { + const sPowerChangeData &data = daPlayerData_c::smc_POWER_CHANGE_DATA; + int idx = isStar() ? 1 : 0; + switch (getPowerChangeType(false)) { + case POWER_CHANGE_NORMAL: + bb = data.mTurnPowerNormal[idx]; + break; + case POWER_CHANGE_ICE: + bb = data.mTurnPowerIce[idx]; + break; + case POWER_CHANGE_LOW_SLIP: + bb = data.mTurnPowerLowSlip[idx]; + break; + } +} + +void daPlBase_c::icePowerChange(int mode) { + PowerChangeType_e powerChangeType = getPowerChangeType(false); + if (powerChangeType == POWER_CHANGE_ICE || (powerChangeType == POWER_CHANGE_LOW_SLIP && mode == 1)) { + if (mMaxSpeedF) { + if (mSpeedF * mMaxSpeedF < 0.0f) { + mAccelF = mAccelF * 0.375f; + } else if (mode == 0) { + if (isSaka()) { + mAccelF = mAccelF * 0.375f; + } else if (std::fabs(mSpeedF) < 0.5f) { + mAccelF = mAccelF * 0.25f; + } + } + } else if (!isSaka() && std::fabs(mSpeedF) < 0.5f) { + mAccelF = 0.004; + } else { + mAccelF = mAccelF * 0.375f; + } + } +} + +void daPlBase_c::airPowerSet() { + const sPowerChangeData *data = &daPlayerData_c::smc_POWER_CHANGE_DATA; + u8 idx = isStar() ? 1 : 0; + const sAirTurnPowerData &airPowerData = data->mAirPower[idx]; + int dir; + if (mKey.buttonWalk(&dir)) { + if (mSpeedF * sc_DirSpeed[dir] < 0.0f) { + mAccelF = airPowerData.mTurnAround; + return; + } else if (std::fabs(mSpeedF) < 0.5f) { + mAccelF = airPowerData.mStand; + return; + } + + float absSpeed = std::fabs(mSpeedF); + + if (absSpeed < getSpeedData()->mLowSpeed) { + if (mKey.buttonDush()) { + mAccelF = airPowerData.mSlowDash; + } else { + mAccelF = airPowerData.mSlowNoDash; + } + } else if (absSpeed < getSpeedData()->mMediumSpeed) { + mAccelF = airPowerData.mMedium; + } else { + mAccelF = airPowerData.mFast; + } + } else { + mAccelF = airPowerData.mNoButton; + } +} + +void daPlBase_c::powerSet() { + if (isNowBgCross(BGC_FOOT)) { + grandPowerSet(); + } else { + airPowerSet(); + } +} + +void daPlBase_c::maxFallSpeedSet() { + mMaxFallSpeed = -4.0f; +} + +void daPlBase_c::gravitySet() { + if (isStatus(STATUS_98)) { + return; + } + if (isNowBgCross(BGC_FOOT)) { + mAccelY = *getGravityData(); + } else { + setJumpGravity(); + } +} + +void daPlBase_c::setJumpGravity() { + if (mNoGravityTimer != 0) { + mAccelY = 0.0f; + } else if (mKey.buttonJump()) { + setButtonJumpGravity(); + } else { + setNormalJumpGravity(); + } +} + +void daPlBase_c::setButtonJumpGravity() { + mAccelY = *(getGravityData() + 17); + for (int i = 0; i < 5; i++) { + if (mSpeed.y > *(getGravityData() + i + 1)) { + mAccelY = *(getGravityData() + i + 12); + break; + } + } +} + +void daPlBase_c::setNormalJumpGravity() { + if (mSpeed.y <= 1.5f) { + mKey.offStatus(dAcPyKey_c::STATUS_FORCE_NO_JUMP); + } + mAccelY = *(getGravityData() + 11); + for (int i = 0; i < 5; i++) { + if (mSpeed.y > *(getGravityData() + i + 1)) { + mAccelY = *(getGravityData() + i + 6); + break; + } + } +} + +float fn_8004c700(float v) { + bool isNeg = false; + if (v < 0.0f) { + v = -v; + isNeg = true; + } + if (v < 0.1f) { + v = 0.0f; + } else { + v = (v - 0.1f) / 0.9f; + } + float tmp; + float lim2 = 0.1f; + if (v < lim2) { + v = 0.0f; + } else { + tmp = 1.0f; + v = (v - 0.1f) / (tmp - 0.1f); + } + if (isNeg == true) { + v = -v; + } + v *= 1.11111f; + return v; +} + +class daTagWind_c : public dActor_c { +public: + float m_00; +}; + +void daPlBase_c::calcWindSpeed() { + daTagWind_c *windActor = (daTagWind_c *) fManager_c::searchBaseByProfName(fProfile::TAG_WIND, nullptr); + if (windActor == nullptr) { + mWindSpeed = 0.0f; + return; + } + if (isStatus(STATUS_A0) && !isOnSinkSand()) { + float windSpeed = fn_8004c700(windActor->m_00); + float halfWindSpeed = windSpeed * 0.5f; + windSpeed = std::fabs(windSpeed) * 3.0f; + if ( + mWindSpeed > 0.0f && isNowBgCross(BGC_WALL_TOUCH_R_2) || + mWindSpeed < 0.0f && isNowBgCross(BGC_WALL_TOUCH_L_2) + ) { + mWindSpeed = 0.0f; + } + if (isNowBgCross(BGC_FOOT)) { + if (isStatus(STATUS_43)) { + offStatus(STATUS_43); + mSpeedF += mWindSpeed; + mWindSpeed = 0.0f; + } + float scale; + if (isStatus(STATUS_5B)) { + windSpeed = 0.45f * windSpeed; + } else { + windSpeed = 0.55f * windSpeed; + } + mWindGroundTimer = 3; + mWindSpeed += halfWindSpeed; + } else { + if (!isStatus(STATUS_43)) { + onStatus(STATUS_43); + } + if (mWindGroundTimer != 0) { + mWindGroundTimer--; + } else if (mSpeedF * mWindSpeed < 0.0f) { + mSpeedF += halfWindSpeed; + } else { + mWindSpeed += halfWindSpeed; + } + } + if (mWindSpeed > windSpeed) { + mWindSpeed = windSpeed; + } else if (mWindSpeed < -windSpeed) { + mWindSpeed = -windSpeed; + } + } else { + mWindSpeed = 0.0f; + return; + } +} + +void daPlBase_c::setLandSE() { + if (mPowerup == POWERUP_PENGUIN_SUIT) { + startFootSoundPlayer(SE_PLY_LAND_PNGN); + return; + } + static const dAudio::SoundEffectID_t scLandSeID[] = { + SE_PLY_LAND_ROCK, + SE_PLY_LAND_SNOW, + SE_PLY_LAND_SAND, + SE_PLY_LAND_ROCK, + SE_PLY_LAND_DIRT, + SE_PLY_LAND_WATER, + SE_PLY_LAND_CLOUD, + SE_PLY_LAND_BLOWSAND, + SE_PLY_LAND_MANTA, + SE_PLY_LAND_SAND, + SE_PLY_LAND_ROCK, + SE_PLY_LAND_LEAF, + SE_PLY_LAND_ROCK + }; + startFootSoundPlayer(scLandSeID[mGroundType]); +} + +void daPlBase_c::setSlipSE() { + if (mGroundType == GROUND_TYPE_WATER) { + holdSound(SE_PLY_PNGN_SLIP_SEA, std::fabs(mSpeedF), false); + return; + } + static const dAudio::SoundEffectID_t scSlipSeID[] = { + SE_PLY_SLIP, + SE_PLY_SLIP_SNOW, + SE_PLY_SLIP_SAND, + SE_PLY_SLIP_ICE, + SE_PLY_SLIP, + SE_PLY_SLIP, + SE_PLY_SLIP, + SE_PLY_SLIP_SAND, + SE_PLY_SLIP, + SE_PLY_SLIP_SAND, + SE_PLY_SLIP, + SE_PLY_SLIP, + SE_PLY_SLIP + }; + holdSound(scSlipSeID[mGroundType], false); +} + +void daPlBase_c::setLandSmokeEffect(int param1) { + static const char *sc_landSmokeEffectID[][3] = { + {"Wm_mr_landsmoke_ss", "Wm_mr_landsmoke_s", "Wm_mr_landsmoke" }, + {"Wm_mr_landsmoke_ss", "Wm_mr_landsmoke_s", "Wm_mr_landsmoke" }, + {"Wm_mr_sndlandsmk_ss", "Wm_mr_sndlandsmk_s", "Wm_mr_sndlandsmk" }, + {"Wm_mr_landsmoke_ss", "Wm_mr_landsmoke_s", "Wm_mr_landsmoke" }, + {"Wm_mr_landsmoke_ss", "Wm_mr_landsmoke_s", "Wm_mr_landsmoke" }, + {"Wm_mr_watersplash", "Wm_mr_watersplash", "Wm_mr_watersplash" }, + {"Wm_mr_landsmoke_ss", "Wm_mr_landsmoke_s", "Wm_mr_landsmoke" }, + {"Wm_mr_sndlandsmk_ss", "Wm_mr_sndlandsmk_s", "Wm_mr_sndlandsmk" }, + {"Wm_mr_landsmoke_ss", "Wm_mr_landsmoke_s", "Wm_mr_landsmoke" }, + {"Wm_mr_beachlandsmk_ss", "Wm_mr_beachlandsmk_s", "Wm_mr_beachlandsmk" }, + {"Wm_mr_landsmoke_ss", "Wm_mr_landsmoke_s", "Wm_mr_landsmoke" }, + {"Wm_mr_landsmoke_ss", "Wm_mr_landsmoke_s", "Wm_mr_landsmoke" }, + {"Wm_mr_landsmoke_ss", "Wm_mr_landsmoke_s", "Wm_mr_landsmoke" } + }; + if (mGroundType == GROUND_TYPE_FUNSUI) { + setSandFunsuiLandEffect(); + } else if (mGroundType == GROUND_TYPE_WATER) { + PLAYER_POWERUP_e powerup = mPowerup; + float sz = 1.0f; + if (powerup == POWERUP_MINI_MUSHROOM) { + sz = 0.6f; + } else if (powerup == POWERUP_NONE) { + sz = 0.8f; + } + mVec3_c size(sz, sz, sz); + dEf::createPlayerEffect(mPlayerNo, sc_landSmokeEffectID[mGroundType][param1], 0, &mPos, nullptr, &size); + } else { + dEf::createPlayerEffect_change(mPlayerNo, sc_landSmokeEffectID[mGroundType][param1], 0, &mPos, nullptr, nullptr); + } +} + +void daPlBase_c::setLandSmokeEffectLight() { + mVec3_c pos = mPos; + if (dMaskMng::isCaveMask() && mLayer == 0) { + if (mAmiLayer == 1) { + pos.z = 3700.0f; + } + } + float sz = dPyMdlMng_c::m_hio.m_08[mpMdlMng->mpMdl->m_152]; + mVec3_c size(sz, sz, sz); + if (isNowBgCross(BGC_ON_SAND)) { + if (mGroundType == GROUND_TYPE_FUNSUI) { + setSandFunsuiLandEffect(); + } else if (!isOnSinkSand()) { + dEf::createPlayerEffect(mPlayerNo, "Wm_mr_cmnsndlandsmk", 0, &pos, nullptr, &size); + } + } else { + dEf::createPlayerEffect(mPlayerNo, "Wm_mr_cmnlandsmoke", 0, &pos, nullptr, &size); + } +} + +bool daPlBase_c::setSandFunsuiLandEffect() { + if (mGroundType == GROUND_TYPE_FUNSUI) { + dEf::createPlayerEffect(mPlayerNo, "Wm_mr_spsmoke", 0, &mPos, nullptr, nullptr); + return true; + } + return false; +} + +void daPlBase_c::setStartJumpEffect(int param1) { + if (isNowBgCross(BGC_FOOT)) { + if (isOnSinkSand()) { + setSandJumpEffect(); + onStatus(STATUS_SINK_SAND_JUMP); + } else if (!setSandFunsuiLandEffect() && param1 == 1) { + setLandSmokeEffectLight(); + } + } +} + +void daPlBase_c::setLandJumpEffect(int param1) { + setLandSE(); + if (!setSandFunsuiLandEffect() && param1 == 1) { + setLandSmokeEffectLight(); + } +} + +void daPlBase_c::setSlipOnWaterEffect(mEf::levelEffect_c *effect) { + static const float sc_runFootScale[] = { 0.5f, 0.8f, 1.0f }; + float sz = sc_runFootScale[getTallType(-1)]; + mVec3_c size(sz, sz, sz); + mVec3_c pos( + mPos.x, + mPos.y + sz * 10.0f, + mPos.z + ); + dEf::createPlayerEffect(mPlayerNo, effect, "Wm_mr_foot_water", 0, &pos, nullptr, &size); +} + +void daPlBase_c::setSlipSmokeEffect() { + static const char *sc_slipSmokeEffectID[][2] = { + { "Wm_mr_slipsmoke_ss", "Wm_mr_slipsmoke" }, + { "Wm_mr_slipsmoke_ss", "Wm_mr_slipsmoke" }, + { "Wm_mr_sndslipsmk_ss", "Wm_mr_sndslipsmk" }, + { "Wm_mr_iceslipsmk_ss", "Wm_mr_iceslipsmk" }, + { "Wm_mr_slipsmoke_ss", "Wm_mr_slipsmoke" }, + { "Wm_mr_slipsmoke_ss", "Wm_mr_slipsmoke" }, + { "Wm_mr_slipsmoke_ss", "Wm_mr_slipsmoke" }, + { "Wm_mr_slipsmoke_ss", "Wm_mr_slipsmoke" }, + { "Wm_mr_slipsmoke_ss", "Wm_mr_slipsmoke" }, + { "Wm_mr_beachslipsmk_ss", "Wm_mr_beachslipsmk" }, + { "Wm_mr_slipsmoke_ss", "Wm_mr_slipsmoke" }, + { "Wm_mr_slipsmoke_ss", "Wm_mr_slipsmoke" }, + { "Wm_mr_slipsmoke_ss", "Wm_mr_slipsmoke" } + }; + + if (mGroundType == GROUND_TYPE_WATER) { + setSlipOnWaterEffect(&mSlipSmokeEffect); + return; + } + mVec3_c pos; + mpMdlMng->mpMdl->getJointPos(&pos, 1); + int idx = 0; + if (mPowerup != POWERUP_MINI_MUSHROOM) { + idx = 1; + } + dEf::createPlayerEffect_change(mPlayerNo, &mSlipSmokeEffect, sc_slipSmokeEffectID[mGroundType][idx], 0, &pos, nullptr, nullptr); +} + +void daPlBase_c::setBrakeSmokeEffect(mVec3_c &offset) { + static const char *sc_brakeSmokeEffectID[][2] = { + { "Wm_mr_brakesmoke_ss", "Wm_mr_brakesmoke" }, + { "Wm_mr_brakesmoke_ss", "Wm_mr_brakesmoke" }, + { "Wm_mr_sndbrakesmk_ss", "Wm_mr_sndbrakesmk" }, + { "Wm_mr_icebrakesmk_ss", "Wm_mr_icebrakesmk" }, + { "Wm_mr_brakesmoke_ss", "Wm_mr_brakesmoke" }, + { "Wm_mr_brakesmoke_ss", "Wm_mr_brakesmoke" }, + { "Wm_mr_brakesmoke_ss", "Wm_mr_brakesmoke" }, + { "Wm_mr_brakesmoke_ss", "Wm_mr_brakesmoke" }, + { "Wm_mr_brakesmoke_ss", "Wm_mr_brakesmoke" }, + { "Wm_mr_beachbrakesmk_ss", "Wm_mr_beachbrakesmk" }, + { "Wm_mr_brakesmoke_ss", "Wm_mr_brakesmoke" }, + { "Wm_mr_brakesmoke_ss", "Wm_mr_brakesmoke" }, + { "Wm_mr_brakesmoke_ss", "Wm_mr_brakesmoke" } + }; + + if (mGroundType == GROUND_TYPE_WATER) { + setSlipOnWaterEffect(&mBrakeSmokeEffect); + return; + } + int idx = 0; + if (mPowerup != POWERUP_MINI_MUSHROOM) { + idx = 1; + } + dEf::createPlayerEffect_change(mPlayerNo, &mBrakeSmokeEffect, sc_brakeSmokeEffectID[mGroundType][idx], 0, &offset, nullptr, nullptr); +} + +void daPlBase_c::setTurnSmokeEffect() { + if (mSpeedF) { + static const dAudio::SoundEffectID_t scTurnSeID[] = { + SE_PLY_BRAKE, + SE_PLY_BRAKE_SNOW, + SE_PLY_BRAKE_SAND, + SE_PLY_BRAKE_ICE, + SE_PLY_BRAKE, + SE_PLY_BRAKE_WATER, + SE_PLY_BRAKE, + SE_PLY_BRAKE_SAND, + SE_PLY_BRAKE, + SE_PLY_BRAKE_SAND, + SE_PLY_BRAKE, + SE_PLY_BRAKE, + SE_PLY_BRAKE + }; + holdSound(scTurnSeID[mGroundType], 0); + } + static const char *sc_turnSmokeEffectID[][2] = { + { "Wm_mr_turn_usual_r", "Wm_mr_turn_usual_l" }, + { "Wm_mr_turn_snow_r", "Wm_mr_turn_snow_l" }, + { "Wm_mr_turn_sand_r", "Wm_mr_turn_sand_l" }, + { "Wm_mr_turn_ice_r", "Wm_mr_turn_ice_l" }, + { "Wm_mr_turn_usual_r", "Wm_mr_turn_usual_l" }, + { "Wm_mr_turn_water_r", "Wm_mr_turn_water_l" }, + { "Wm_mr_turn_usual_r", "Wm_mr_turn_usual_l" }, + { "Wm_mr_turn_sand_r", "Wm_mr_turn_sand_l" }, + { "Wm_mr_turn_usual_r", "Wm_mr_turn_usual_l" }, + { "Wm_mr_turn_beach_r", "Wm_mr_turn_beach_l" }, + { "Wm_mr_turn_usual_r", "Wm_mr_turn_usual_l" }, + { "Wm_mr_turn_usual_r", "Wm_mr_turn_usual_l" }, + { "Wm_mr_turn_usual_r", "Wm_mr_turn_usual_l" } + }; + static const float sc_turnSmokeScale[] = { 0.5f, 0.8f, 1.0f }; + mVec3_c pos; + mpMdlMng->mpMdl->getJointPos(&pos, 1); + if (mGroundType == GROUND_TYPE_WATER) { + if (mPos.y < mWaterHeight - 4.0f) { + fadeOutTurnEffect(); + return; + } + pos.y = mWaterHeight; + } + float sz = sc_turnSmokeScale[getTallType(-1)]; + mVec3_c size(sz, sz, sz); + if (mTurnEffectFade == 1 && mTurnGroundType == mGroundType) { + mTurnSmokeEffect.follow(&pos, 0, 0); + } else { + dEf::createPlayerEffect(mPlayerNo, &mTurnSmokeEffect, sc_turnSmokeEffectID[mGroundType][mDirection], 0, &pos, nullptr, &size); + mTurnGroundType = mGroundType; + mTurnEffectFade = 1; + } +} + +void daPlBase_c::fadeOutTurnEffect() { + if (mTurnEffectFade != 1) { + return; + } + mTurnSmokeEffect.followFade(); + mTurnEffectFade = 0; +} + +void daPlBase_c::setRunFootEffect() { + static const char *sc_runFootEffectID[] = { + nullptr, + "Wm_mr_foot_snow", + "Wm_mr_foot_sand", + "Wm_mr_foot_ice", + nullptr, + "Wm_mr_foot_water", + nullptr, + "Wm_mr_foot_sand", + nullptr, + "Wm_mr_foot_beach", + nullptr, + nullptr, + nullptr + }; + if (!isOnSinkSand() && isStatus(STATUS_62)) { + if ( + GROUND_TYPE_SNOW <= mGroundType && mGroundType <= GROUND_TYPE_ICE || + mGroundType == GROUND_TYPE_WATER || + mGroundType == GROUND_TYPE_FUNSUI || + mGroundType == GROUND_TYPE_BEACH + ) { + mVec3_c pos; + mpMdlMng->mpMdl->getJointPos(&pos, 1); + static const float sc_runFootScale[] = { 0.5f, 0.8f, 1.0f }; + float sz = sc_runFootScale[getTallType(-1)]; + mVec3_c size(sz, sz, sz); + dEf::createPlayerEffect(mPlayerNo, &mRunEffect, sc_runFootEffectID[mGroundType], 0, &pos, nullptr, &size); + } + } +} + +void daPlBase_c::setSandEffect() { + if (isStatus(STATUS_4E) || isStatus(STATUS_RIDE_YOSHI)) { + return; + } + if (isOnSinkSand() && !isNowBgCross(BGC_INSIDE_SINK_SAND) || isStatus(STATUS_SINK_SAND_JUMP)) { + mVec3_c pos; + mpMdlMng->mpMdl->getJointPos(&pos, 8); + dEf::createPlayerEffect(mPlayerNo, &mQuicksandSplashEffect, "Wm_mr_sandsplash", 0, &pos, nullptr, nullptr); + } + if (isNowBgCross(BGC_IN_SINK_SAND)) { + mVec3_c pos = getCenterPos(); + dEf::createPlayerEffect(mPlayerNo, &mQuicksandSinkEffect, "Wm_mr_quicksand", 0, &pos, nullptr, nullptr); + } + if (isOnSinkSand() && !wasOnSinkSand()) { + if (mPos.y > mSinkSandHeight - 8.0f && mPrevSpeedY < 0.0f) { + int idx = 2; + if ((mPrevSpeedY < -4.0f || mAirTopHeight > mSinkSandHeight + 58.0f) && mPowerup != POWERUP_MINI_MUSHROOM) { + mSpeedF = 0.0f; + idx = (mPowerup == POWERUP_NONE) ? 1 : 0; + } + mVec3_c pos( + mPos.x, + mSinkSandHeight, + mPos.z + ); + static const char *scSandDiveEffectID[] = { + "Wm_mr_sanddive", + "Wm_mr_sanddive_m", + "Wm_mr_sanddive_s" + }; + dEf::createPlayerEffect(mPlayerNo, scSandDiveEffectID[idx], 0, &pos, nullptr, nullptr); + } + } +} + +bool daPlBase_c::setSandJumpEffect() { + if (isOnSinkSand() && mPos.y + getModelHeight() + 16.0f > mSinkSandHeight) { + mVec3_c pos = mPos; + pos.y = mSinkSandHeight; + dEf::createPlayerEffect(mPlayerNo, "Wm_mr_sanddive_s", 0, &pos, nullptr, nullptr); + return true; + } + return false; +} + +void daPlBase_c::setSoundPlyMode() { + static const int scPlayerSound[] = { + 0, 1, 2, 3, 4, 5, 1 + }; + mSndObj.m_b0 = scPlayerSound[mPowerup]; +} + +void daPlBase_c::setFootSound() { + if ( + (isDemo() || isNowBgCross(BGC_FOOT)) && + dScStage_c::m_gameMode != dScStage_c::GAME_MODE_TITLE_SCREEN && + mpMdlMng->mpMdl->isFootStepTiming() + ) { + if (mPowerup == POWERUP_PENGUIN_SUIT) { + startFootSoundPlayer(SE_PLY_FOOTNOTE_PNGN); + return; + } + static const dAudio::SoundEffectID_t scFootSeID[] = { + SE_PLY_FOOTNOTE_ROCK, + SE_PLY_FOOTNOTE_SNOW, + SE_PLY_FOOTNOTE_SAND, + SE_PLY_FOOTNOTE_ROCK, + SE_PLY_FOOTNOTE_DIRT, + SE_PLY_FOOTNOTE_WATER, + SE_PLY_FOOTNOTE_CLOUD, + SE_PLY_FOOTNOTE_BLOWSAND, + SE_PLY_FOOTNOTE_MANTA, + SE_PLY_FOOTNOTE_SAND, + SE_PLY_FOOTNOTE_CARPET, + SE_PLY_FOOTNOTE_LEAF, + SE_PLY_FOOTNOTE_WOOD + }; + startFootSoundPlayer(scFootSeID[mGroundType]); + } +} + +STATE_VIRTUAL_DEFINE(daPlBase_c, DemoNone); +STATE_VIRTUAL_DEFINE(daPlBase_c, DemoStartWait); +STATE_VIRTUAL_DEFINE(daPlBase_c, DemoWait); +STATE_VIRTUAL_DEFINE(daPlBase_c, DemoInDokanU); +STATE_VIRTUAL_DEFINE(daPlBase_c, DemoInDokanD); +STATE_VIRTUAL_DEFINE(daPlBase_c, DemoInDokanR); +STATE_VIRTUAL_DEFINE(daPlBase_c, DemoInDokanL); +STATE_VIRTUAL_DEFINE(daPlBase_c, DemoOutDokanU); +STATE_VIRTUAL_DEFINE(daPlBase_c, DemoOutDokanD); +STATE_VIRTUAL_DEFINE(daPlBase_c, DemoOutDokanR); +STATE_VIRTUAL_DEFINE(daPlBase_c, DemoOutDokanL); +STATE_VIRTUAL_DEFINE(daPlBase_c, DemoOutDokanRoll); +STATE_VIRTUAL_DEFINE(daPlBase_c, DemoInWaterTank); +STATE_VIRTUAL_DEFINE(daPlBase_c, DemoOutWaterTank); +STATE_VIRTUAL_DEFINE(daPlBase_c, DemoRailDokan); +STATE_VIRTUAL_DEFINE(daPlBase_c, DemoDown); +STATE_VIRTUAL_DEFINE(daPlBase_c, DemoNextGotoBlock); +STATE_VIRTUAL_DEFINE(daPlBase_c, DemoGoal); +STATE_VIRTUAL_DEFINE(daPlBase_c, DemoControl); + +void daPlBase_c::initialDokanUnder() { + changeDemoState(StateID_DemoInDokanD, DOKAN_TYPE_NORMAL); +} +void daPlBase_c::initialDokanUper() { + changeDemoState(StateID_DemoInDokanU, DOKAN_TYPE_NORMAL); +} +void daPlBase_c::initialDokanRight() { + changeDemoState(StateID_DemoInDokanR, DOKAN_TYPE_NORMAL); +} +void daPlBase_c::initialDokanLeft() { + changeDemoState(StateID_DemoInDokanL, DOKAN_TYPE_NORMAL); +} + +void daPlBase_c::initialDokanUnderM() { + changeDemoState(StateID_DemoInDokanD, DOKAN_TYPE_MINI); +} +void daPlBase_c::initialDokanUperM() { + changeDemoState(StateID_DemoInDokanU, DOKAN_TYPE_MINI); +} +void daPlBase_c::initialDokanRightM() { + changeDemoState(StateID_DemoInDokanR, DOKAN_TYPE_MINI); +} +void daPlBase_c::initialDokanLeftM() { + changeDemoState(StateID_DemoInDokanL, DOKAN_TYPE_MINI); +} + +void daPlBase_c::initialDokanDepth() { + changeDemoState(StateID_DemoInWaterTank, DOKAN_TYPE_NORMAL); +} + +void daPlBase_c::initialDoor() {} +void daPlBase_c::initialJumpRight() {} +void daPlBase_c::initialJumpLeft() {} +void daPlBase_c::initialVine() {} + +void daPlBase_c::initialFall() { + changeState(StateID_Fall, false); + changeDemoState(StateID_DemoNone, false); + mSpeed.y = -1.0f; + bgCheck(0); +} + +void daPlBase_c::initialHipAttack() { + changeState(StateID_HipAttack, HIP_ATTACK_ARG_PLAYER); + changeDemoState(StateID_DemoWait, DEMO_WAIT_ARG_TO_NONE); +} + +void daPlBase_c::initialSlip() { + onStatus(STATUS_INITIAL_SLIDE); + setSlipAction(); + changeDemoState(StateID_DemoWait, DEMO_WAIT_ARG_TO_CONTROL); +} + +void daPlBase_c::initialSwim() {} + +void daPlBase_c::initialTorideBoss() { + initialNormal(); + startControlDemo(); +} + +void daPlBase_c::initialBlockJump() {} +void daPlBase_c::initialBlockJumpBelow() {} + +void daPlBase_c::initialNormal() { + changeState(StateID_Walk, 0); + changeDemoState(StateID_DemoStartWait); + mSpeed.y = -1.0f; + bgCheck(0); +} + +void daPlBase_c::setCreateAction(int action) { + static ProcFunc l_createActionProc[] = { + &daPlBase_c::initialNormal, + &daPlBase_c::initialNormal, + &daPlBase_c::initialDoor, + &daPlBase_c::initialDokanUnder, + &daPlBase_c::initialDokanUper, + &daPlBase_c::initialDokanRight, + &daPlBase_c::initialDokanLeft, + &daPlBase_c::initialFall, + &daPlBase_c::initialHipAttack, + &daPlBase_c::initialSlip, + &daPlBase_c::initialSwim, + &daPlBase_c::initialNormal, + &daPlBase_c::initialNormal, + &daPlBase_c::initialNormal, + &daPlBase_c::initialDoor, + &daPlBase_c::initialDoor, + &daPlBase_c::initialDokanUnderM, + &daPlBase_c::initialDokanUperM, + &daPlBase_c::initialDokanRightM, + &daPlBase_c::initialDokanLeftM, + &daPlBase_c::initialJumpRight, + &daPlBase_c::initialVine, + &daPlBase_c::initialDokanDepth, + &daPlBase_c::initialTorideBoss, + &daPlBase_c::initialJumpLeft, + &daPlBase_c::initialBlockJump, + &daPlBase_c::initialBlockJumpBelow, + &daPlBase_c::initialNormal + }; + (this->*l_createActionProc[action])(); +} + +bool daPlBase_c::isDemoType(DemoType_e type) { + switch (type) { + case DEMO_1: + if (isDemoMode() && isStatus(STATUS_OUT_OF_PLAY)) { + return true; + } + break; + case DEMO_2: + if (isChange()) { + return true; + } + break; + case DEMO_3: + if (isStatus(STATUS_DEMO_NEXT_GOTO_BLOCK) || isDemoMode()) { + return true; + } + break; + case DEMO_PLAYER: + if (!isItemKinopio() && (isStatus(STATUS_72) || isStatus(STATUS_71)) && mDemoState >= CONTROL_DEMO_WAIT && mDemoState <= CONTROL_DEMO_4) { + return true; + } + break; + case DEMO_KINOPIO: + if (isItemKinopio() && (isStatus(STATUS_72) || isStatus(STATUS_71)) && mDemoState >= CONTROL_DEMO_WAIT && mDemoState <= CONTROL_DEMO_KINOPIO_SINK_SAND) { + return true; + } + break; + case DEMO_ENDING_DANCE: + if ((isStatus(STATUS_72) || isStatus(STATUS_71)) && mDemoState == CONTROL_DEMO_ENDING_DANCE) { + return true; + } + break; + default: + break; + } + return false; +} + +bool daPlBase_c::isDemo() { + if (isDemoType(DEMO_1) || isDemoType(DEMO_2) || isDemoType(DEMO_3)) { + return true; + } + return false; +} + +bool daPlBase_c::isControlDemoAll() { + if (isDemoType(DEMO_PLAYER) || isDemoType(DEMO_KINOPIO) || isDemoType(DEMO_ENDING_DANCE)) { + return true; + } + return false; +} + +bool daPlBase_c::isDemoAll() { + if (isDemo() || isControlDemoAll()) { + return true; + } + return false; +} + +bool daPlBase_c::isDemoMode() const { + return mIsDemoMode != false; +} + +void daPlBase_c::onDemo() { + if (mPlayerNo == -1) { + return; + } + daPlBase_c *pl = daPyMng_c::getPlayer(mPlayerNo); + if (pl != nullptr && !pl->isItemKinopio()) { + daPyMng_c::mPauseEnableInfo &= ~(1 << mPlayerNo); + daPyMng_c::mStopTimerInfo |= (1 << mPlayerNo); + } + mIsDemoMode = true; +} + +void daPlBase_c::offDemo() { + if (mPlayerNo == -1) { + return; + } + daPlBase_c *pl = daPyMng_c::getPlayer(mPlayerNo); + if (pl != nullptr && !pl->isItemKinopio()) { + daPyMng_c::mPauseEnableInfo |= (1 << mPlayerNo); + daPyMng_c::mStopTimerInfo &= ~(1 << mPlayerNo); + } + mIsDemoMode = false; +} + +void daPlBase_c::changeNextScene(int param1) { + onStatus(STATUS_64); + daPyMng_c::mPauseDisable = true; + daPyDemoMng_c::mspInstance->setCourseOutList(mPlayerNo); + if (mPlayerNo == daPyDemoMng_c::mspInstance->m_70) { + dNext_c::m_instance->m_19 = true; + daPyDemoMng_c::mspInstance->mPlayerNo = mPlayerNo; + } + if (param1 == 1) { + daPlBase_c *pl = daPyMng_c::getPlayer(mPlayerNo); + if (pl != nullptr) { + pl->onStatus(STATUS_STOP_EXECUTE); + } + daPlBase_c *yoshi = daPyMng_c::getYoshi(mPlayerNo); + if (yoshi != nullptr) { + yoshi->onStatus(STATUS_STOP_EXECUTE); + } + } +} + +bool daPlBase_c::isPlayerGameStop() { + return (dInfo_c::mGameFlag >> 1) & 1; +} + +void daPlBase_c::stopOther() { + if (!isPlayerGameStop()) { + return; + } + dActor_c::mExecStopReq |= 0xf; + if (mPlayerNo != -1) { + daPlBase_c *pl = daPyMng_c::getPlayer(mPlayerNo); + if (pl != nullptr) { + pl->mExecStopMask &= ~2; + } + daPlBase_c *yoshi = daPyMng_c::getYoshi(mPlayerNo); + if (yoshi != nullptr) { + yoshi->mExecStopMask &= ~2; + } + } else if (mKind == STAGE_ACTOR_YOSHI) { + mExecStopMask &= ~4; + } +} + +void daPlBase_c::playOther() { + dActor_c::mExecStopReq &= ~0xf; + if (mPlayerNo != -1) { + daPlBase_c *pl = daPyMng_c::getPlayer(mPlayerNo); + if (pl != nullptr) { + pl->mExecStopMask |= 2; + } + daPlBase_c *yoshi = daPyMng_c::getYoshi(mPlayerNo); + if (yoshi != nullptr) { + yoshi->mExecStopMask |= 2; + } + } else if (mKind == STAGE_ACTOR_YOSHI) { + mExecStopMask |= 4; + } +} + +void daPlBase_c::changeNormalAction() { + bgCheck(0); + offZPosSetNone(); + changeState(StateID_Walk, BLEND_DEFAULT); + changeDemoState(StateID_DemoNone, false); +} + +bool daPlBase_c::checkTimeOut() { + if (dStageTimer_c::m_instance->convertToIGT() == 0) { + if (setTimeOverDemo()) { + return true; + } + } + return false; +} + +void daPlBase_c::changeDemoState(const sStateIDIf_c &stateID, int arg) { + if (stateID == StateID_DemoNone && isItemKinopio()) { + changeDemoState(StateID_DemoControl, CONTROL_DEMO_KINOPIO_WALK); + } else { + onDemo(); + mDemoSubstate = 0; + mDemoStateArg = arg; + mDemoStateMgr.changeState(stateID); + } +} + +bool daPlBase_c::executeDemoState() { + offStatus(STATUS_79); + if (mDemoSubstateTimer != 0) { + mDemoSubstateTimer--; + } + mDemoStateMgr.executeState(); + if (isStatus(STATUS_71)) { + if (isDemoState(StateID_DemoNone)) { + changeDemoState(StateID_DemoControl, CONTROL_DEMO_WAIT); + } + } + if (!isDemoMode()) { + return false; + } + if (isStatus(STATUS_79)) { + onStatus(STATUS_77); + } + return true; +} + +void daPlBase_c::initializeState_DemoNone() { + mDemoSubstateTimer = 15; + daPyDemoMng_c::mspInstance->clearDemoNo(mPlayerNo); + offDemo(); + if (mDemoStateArg != 1) { + playOther(); + } + offStatus(STATUS_INVISIBLE); +} + +void daPlBase_c::finalizeState_DemoNone() {} + +void daPlBase_c::executeState_DemoNone() { + if (mFader_c::mFader->isStatus(mFaderBase_c::HIDDEN)) { + if (isDemoMode()) { + offDemo(); + } + if (mPlayerNo == daPyDemoMng_c::mspInstance->getPlrNo()) { + daPyDemoMng_c::mspInstance->setPlrNo(-1); + } + } + if (checkTimeOut()) { + return; + } + if (isNowBgCross(BGC_FOOT) || isStatus(STATUS_SWIM)) { + if (mKey.buttonRight()) { + mDokanCounterR++; + if (mDokanCounterR > sc_DokanEnterThreshold) { + mDokanCounterR = sc_DokanEnterThreshold; + } + } else { + mDokanCounterR = 0; + } + if (mKey.buttonLeft()) { + mDokanCounterL++; + if (mDokanCounterL > sc_DokanEnterThreshold) { + mDokanCounterL = sc_DokanEnterThreshold; + } + } else { + mDokanCounterL = 0; + } + } else { + mDokanCounterR = 0; + mDokanCounterL = 0; + } + if (mDemoSubstateTimer == 0 && isEnableDokanInStatus()) { + if (setDokanIn(DOKAN_D)) { + return; + } + if (setDokanIn(DOKAN_U)) { + return; + } + if (mDokanCounterR >= sc_DokanEnterThreshold && mDirection == DIR_LR_R) { + if (setDokanIn(DOKAN_R)) { + return; + } + } + if (mDokanCounterL >= sc_DokanEnterThreshold && mDirection == DIR_LR_L) { + if (setDokanIn(DOKAN_L)) { + return; + } + } + if (mKey.buttonDown()) { + onStatus(STATUS_A4); + } + } +} + +void daPlBase_c::initializeState_DemoStartWait() {} + +void daPlBase_c::executeState_DemoStartWait() { + if (dScStage_c::m_gameMode == dScStage_c::GAME_MODE_TITLE_SCREEN) { + changeDemoState(StateID_DemoNone, false); + } else { + if (mFader_c::mFader->isStatus(mFaderBase_c::HIDDEN)) { + bgCheck(0); + changeDemoState(StateID_DemoNone, false); + } + } +} + +void daPlBase_c::finalizeState_DemoStartWait() {} + +void daPlBase_c::initializeState_DemoWait() { + if (daPyDemoMng_c::mspInstance->checkDemoNo(mPlayerNo)) { + mDemoSubstate = DEMO_WAIT_TRANSITION; + mDemoSubstateTimer = 0; + } else { + mDemoSubstate = DEMO_WAIT_DELAY; + } +} + +void daPlBase_c::finalizeState_DemoWait() {} + +void daPlBase_c::executeState_DemoWait() { + if (mFader_c::mFader->isStatus(mFaderBase_c::HIDDEN)) { + switch ((DemoWaitSubstate_e) mDemoSubstate) { + case DEMO_WAIT_DELAY: + if (daPyDemoMng_c::mspInstance->checkDemoNo(mPlayerNo)) { + mDemoSubstate = DEMO_WAIT_TRANSITION; + mDemoSubstateTimer = sc_DemoWaitDuration; + } + break; + case DEMO_WAIT_TRANSITION: + if (mDemoSubstateTimer == 0) { + daPyDemoMng_c::mspInstance->turnNextDemoNo(); + switch ((DemoWaitArg_e) mDemoStateArg) { + case DEMO_WAIT_ARG_TO_NONE: + changeDemoState(StateID_DemoNone, false); + onDemo(); + bgCheck(0); + break; + case DEMO_WAIT_ARG_TO_CONTROL: + changeDemoState(StateID_DemoControl, CONTROL_DEMO_4); + break; + } + } + break; + } + } +} + +const float daPlBase_c::scDokanInSpeedX = 1.0f; +const float daPlBase_c::scDokanInWidthX = 0.0f; +const float daPlBase_c::scDokanInMoveSpeed = 0.75f; +const float daPlBase_c::scDokanWaitAnmFixFrame = 85.0f; + +namespace { + const float scDokanOutTurnSpeed[] = { 2048.0f }; +} + +float daPlBase_c::getWaterDokanCenterOffset(float param1) { + /// @unofficial + static const float l_maxOffsets[] = { 12.0f, 15.0f, 13.0f, 13.0f }; + float max = 16.0f; + if (mKind == 1) { + max = l_maxOffsets[mPlayerType]; + } + float pos = getCenterY() - mPos.y; + if (pos > max) { + pos = max; + } + return param1 + 16.0f - pos; +} + +void daPlBase_c::initDemoInDokan() { + onStatus(STATUS_5E); + mSpeedF = 0.0f; + mSpeed.y = 0.0f; + setZPosition(-1800.0f); + if (mDemoStateArg == DOKAN_TYPE_CONNECTED) { + mDamageInvulnTimer = 0; + } else { + mDamageInvulnTimer = 35; + if (daPyDemoMng_c::mspInstance->checkDemoNo(mPlayerNo)) { + stopOther(); + } + } + mDemoSubstate = 0; +} + +void daPlBase_c::endDemoInDokan() { + mDamageInvulnTimer = 0; + mPowerupChangeInvulnTimer = 0; + offStatus(STATUS_CAN_WATER_WALK); + offStatus(STATUS_PROPEL_NO_ROLL); + offStatus(STATUS_5E); +} + +void daPlBase_c::executeDemoInDokan(u8 dir) { + // 0: Play the pipe sound effect + // 1: Wait for a bit + // 2: Move the player out of the pipe + // 3: Finalize the transition + switch (mDemoSubstate) { + case 0: + if (!mFader_c::mFader->isStatus(mFaderBase_c::HIDDEN)) { + break; + } + if (!daPyDemoMng_c::mspInstance->checkDemoNo(mPlayerNo)) { + break; + } + offStatus(STATUS_INVISIBLE); + mDemoSubstate = 1; + mDemoSubstateTimer = 40; + if (mBc.checkWater(mWarpPos.x, mWarpPos.y, mLayer, nullptr)) { + onNowBgCross(BGC_WATER_SHALLOW); + } + if (isNowBgCross(BGC_WATER_SHALLOW)) { + if (isDemoState(StateID_DemoInDokanL) || isDemoState(StateID_DemoInDokanR)) { + mpMdlMng->setAnm(PLAYER_ANIM_SWIM_PIPE); + if (mDemoStateArg != DOKAN_TYPE_CONNECTED) { + mPos.y = getWaterDokanCenterOffset(mPos.y); + mWarpPos.y = mPos.y; + } + } + startSound(SE_PLY_WATER_DOKAN_IN_OUT, false); + } else { + startSound(SE_PLY_DOKAN_IN_OUT, false); + } + break; + case 1: + if (mDemoSubstateTimer == 0) { + daPyDemoMng_c::mspInstance->turnNextDemoNo(); + mDemoSubstate = 2; + } + case 2: + onStatus(STATUS_79); + if (isStatus(STATUS_PROPEL_NO_ROLL) && (dir == 2 || dir == 3) && std::fabs(mPos.x - mWarpPos.x) <= 20.0f) { + offStatus(STATUS_PROPEL_NO_ROLL); + } + if (isStatus(STATUS_5E) && std::fabs(mPos.x - mWarpPos.x) <= 20.0f) { + offStatus(STATUS_5E); + } + if (!demo_dokan_move_x(0.75f, 0.0f)) { + break; + } + if (!demo_dokan_move_y(0.75f, 0.0f)) { + break; + } + if (mDemoSubstate == 1) { + daPyDemoMng_c::mspInstance->turnNextDemoNo(); + } + mDemoSubstate = 3; + break; + case 3: + if (!mKey.buttonWalk(nullptr)) { + if (!mAngle.y.chase(getMukiAngle(mDirection), scDokanOutTurnSpeed[0])) { + break; + } + } + changeNormalAction(); + if (isNowBgCross(BGC_WATER_SHALLOW)) { + onOldBgCross(BGC_WATER_SHALLOW); + } + break; + } +} + +void daPlBase_c::initDemoInDokanUD(u8 dir) { + /// @unofficial + static const float tmps[] = { 34.0f, 36.0f, 38.0f, 38.0f }; + /// @unofficial + static const float tmps_big[] = { 40.0f, 42.0f, 44.0f, 44.0f }; + mpMdlMng->setAnm(PLAYER_ANIM_WAIT); + mWarpPos = mPos; + if (dir == 1) { + if (mDemoStateArg == DOKAN_TYPE_MINI) { + mWarpPos.y = mPos.y + 16.0f; + } else { + mWarpPos.y = mPos.y + 32.0f; + } + if (mKind == STAGE_ACTOR_YOSHI) { + mPos.y -= 16.0f; + } else { + mPos.y -= 8.0f; + } + } else { + onStatus(STATUS_PROPEL_NO_ROLL); + float tmp; + if (mKind == STAGE_ACTOR_YOSHI) { + tmp = 30.0f; + daPlBase_c *pl = ((daYoshi_c *) this)->getPlayerRideOn(); + if (pl != nullptr) { + int t = pl->mPlayerType; + switch (pl->mPowerup) { + case POWERUP_NONE: + tmp = tmps[t]; + break; + case POWERUP_MINI_MUSHROOM: + tmp = 30.0f; + break; + default: + tmp = tmps_big[t]; + break; + } + } + } else { + switch (mPowerup) { + case POWERUP_NONE: + tmp = 20.0f; + break; + case POWERUP_MINI_MUSHROOM: + tmp = 12.0f; + break; + case POWERUP_PROPELLER_SHROOM: + tmp = getModelHeight() + 8.0f; + break; + default: + tmp = getModelHeight(); + break; + } + } + mWarpPos.y = -tmp + mPos.y; + mPos.y += 2.0f; + } + if (mKind == STAGE_ACTOR_YOSHI) { + mAngle.y = 0; + } + initDemoInDokan(); +} + +void daPlBase_c::initDemoInDokanLR(u8 dir) { + static const float l_dokanOffset[] = { 32.0f, 32.0f, 20.0f }; + mpMdlMng->setAnm(PLAYER_ANIM_LOW_WALK); + onStatus(STATUS_PROPEL_NO_ROLL); + if (dir == DOKAN_R) { + mPos.x += 8.0f; + } else { + mPos.x -= 8.0f; + } + float tmp; + if (mKind == STAGE_ACTOR_YOSHI) { + tmp = 32.0f; + } else { + tmp = l_dokanOffset[mDemoStateArg]; + } + if (dir == 3) { + tmp = -tmp; + } + mWarpPos.set(mPos.x + tmp, mPos.y, mPos.z); + if (dir == DOKAN_R) { + mDirection = DIR_LR_L; + } else { + mDirection = DIR_LR_R; + } + mAngle.y = getMukiAngle(mDirection); + initDemoInDokan(); +} + +void daPlBase_c::initializeState_DemoInDokanU() { initDemoInDokanUD(DOKAN_U); } +void daPlBase_c::finalizeState_DemoInDokanU() { endDemoInDokan(); } +void daPlBase_c::executeState_DemoInDokanU() { executeDemoInDokan(DOKAN_U); } + +void daPlBase_c::initializeState_DemoInDokanD() { initDemoInDokanUD(DOKAN_D); } +void daPlBase_c::finalizeState_DemoInDokanD() { endDemoInDokan(); } +void daPlBase_c::executeState_DemoInDokanD() { executeDemoInDokan(DOKAN_D); } + +void daPlBase_c::initializeState_DemoInDokanL() { initDemoInDokanLR(DOKAN_L); } +void daPlBase_c::finalizeState_DemoInDokanL() { endDemoInDokan(); } +void daPlBase_c::executeState_DemoInDokanL() { executeDemoInDokan(DOKAN_L); } + +void daPlBase_c::initializeState_DemoInDokanR() { initDemoInDokanLR(DOKAN_R); } +void daPlBase_c::finalizeState_DemoInDokanR() { endDemoInDokan(); } +void daPlBase_c::executeState_DemoInDokanR() { executeDemoInDokan(DOKAN_R); } + +bool daPlBase_c::demo_dokan_move_x(float moveStep, float epsilon) { + sLib::chase(&mPos.x, mWarpPos.x, moveStep); + return std::fabs(mPos.x - mWarpPos.x) <= epsilon; +} + +bool daPlBase_c::demo_dokan_move_y(float moveStep, float offset) { + return sLib::chase(&mPos.y, mWarpPos.y + offset, moveStep); +} + +bool daPlBase_c::isEnableDokanInStatus() { + if (isDemo()) { + return false; + } + if ( + isStatus(STATUS_OUT_OF_PLAY) || + isStatus(STATUS_STUNNED) || + isStatus(STATUS_QUAKE) || + isStatus(STATUS_53) + ) { + return false; + } + return true; +} + +bool daPlBase_c::setDokanIn(DokanDir_e dir) { + if (isStatus(STATUS_7E)) { + return false; + } + int res = 0; + int entranceNextGotoID; + switch (dir) { + case DOKAN_D: + if (mKey.buttonDown()) { + res = mBc.checkDokanDown(&mWarpPos, &entranceNextGotoID); + } + break; + case DOKAN_U: + if (mKey.buttonUp()) { + res = mBc.checkDokanUp(&mWarpPos, &entranceNextGotoID); + } + break; + case DOKAN_L: + case DOKAN_R: { + float x = 0.0f; + float y = x; + if (isStatus(STATUS_SWIM)) { + x = 2.0f; + y = -2.0f; + } else { + if (isStatus(STATUS_17)) { + x = 8.0f; + y = 8.0f; + } + } + res = mBc.checkDokanLR(&mWarpPos, mDirection, &entranceNextGotoID, x, y); + break; + } + case DOKAN_ROLL: + break; + } + if (res == 1 && setDemoOutDokanAction(entranceNextGotoID, dir)) { + return true; + } + return false; +} + +bool daPlBase_c::setDemoOutDokanAction(int entranceNextGotoID, DokanDir_e dir) { + mDokanEnterNextGotoID = entranceNextGotoID; + dCdFile_c *cdFile = dCd_c::m_instance->getFileP(dScStage_c::m_instance->mCurrFile); + sNextGotoData *nextGoto = cdFile->getNextGotoP(mDokanEnterNextGotoID); + + mDokanMode = DEMO_DOKAN_NORMAL; + if (nextGoto->mFlags & NEXT_GOTO_RAIL) { + mDokanMode = DEMO_DOKAN_RAIL; + } else if (nextGoto->mFlags & NEXT_GOTO_WATER_TANK) { + mDokanMode = DEMO_DOKAN_WATER_TANK; + } + + static sStateIDIf_c *l_dokanInAction[] = { + &StateID_DemoOutDokanU, + &StateID_DemoOutDokanD, + &StateID_DemoOutDokanL, + &StateID_DemoOutDokanR, + &StateID_DemoOutDokanRoll, + }; + switch (mDokanMode) { + case DEMO_DOKAN_NONE: + break; + case DEMO_DOKAN_NORMAL: + if (dNext_c::m_instance->fn_800cfed0(dScStage_c::m_instance->mCurrFile, mDokanEnterNextGotoID)) { + return false; + } + if (daPyDemoMng_c::mspInstance->m_5c) { + return false; + } + dNext_c::m_instance->setChangeSceneNextDat(dScStage_c::m_instance->mCurrFile, mDokanEnterNextGotoID, dFader_c::FADER_CIRCLE_TARGET); + if (nextGoto->mType == 22) { + changeDemoState(StateID_DemoOutWaterTank, DOKAN_U); + } else { + changeDemoState(*l_dokanInAction[dir]); + } + return true; + case DEMO_DOKAN_RAIL: + dRail_c::getRailInfoP(nextGoto->mRailID); // [Unused return value] + changeDemoState(*l_dokanInAction[dir]); + return true; + case DEMO_DOKAN_WATER_TANK: + if (nextGoto->mType == 22) { + changeDemoState(StateID_DemoOutWaterTank, dir); + } else { + changeDemoState(*l_dokanInAction[dir]); + } + return true; + } + return false; +} + +void daPlBase_c::initDemoOutDokan() { + mSpeedF = 0.0f; + mMaxSpeedF = 0.0f; + mSpeed.set(0.0f, 0.0f, 0.0f); + mAngle.x = 0.0f; + setZPosition(-1800.0f); + if (isNowBgCross(BGC_WATER_SHALLOW)) { + startSound(SE_PLY_WATER_DOKAN_IN_OUT, false); + } else { + startSound(SE_PLY_DOKAN_IN_OUT, false); + } +} + +void daPlBase_c::endDemoOutDokan() { + offStatus(STATUS_PROPEL_NO_ROLL); + offStatus(STATUS_5E); +} + +void daPlBase_c::initDemoOutDokanUD(u8 dir) { + mDokanDir = dir; + changeState(StateID_Walk, nullptr); + mpMdlMng->setAnm(PLAYER_ANIM_WAIT, 0.0f, 5.0f, 85.0f); + if (mDokanMode == DEMO_DOKAN_RAIL) { + if (dir == DOKAN_U) { + mDokanOffsetY = 0.0f; + } else { + mDokanOffsetY = -34.0f; + } + } else if (dir == DOKAN_U) { + mDokanOffsetY = 2.0f; + } else if (mKind == STAGE_ACTOR_YOSHI) { + mDokanOffsetY = -16.0f; + } else { + mDokanOffsetY = -10.0f; + } + mDokanShiftXEpsilon = 0.0f; + if (mDokanMode == DEMO_DOKAN_NORMAL && daPyMng_c::mNum == 1) { + stopOther(); + } + initDemoOutDokan(); +} + +void daPlBase_c::executeDemoOutDokanUD() { + // 0: Move to the center of the pipe + // 1: Move into the pipe + // 2: Water tank only: move to Y target, then transition to in-tank state + // 3: Done + switch (mDemoSubstate) { + case 0: { + int cond = 0; + if (mKind == STAGE_ACTOR_YOSHI) { + if (mAngle.y.chase(0, scDokanOutTurnSpeed[0])) { + cond = 1; + } + } else { + if (mAngle.y.chase(getMukiAngle(mDirection), 0x2000)) { + cond = 1; + } + } + if (demo_dokan_move_x(1.0f, mDokanShiftXEpsilon) && cond == 1) { + mDemoSubstate = 1; + mDemoSubstateTimer = 10; + } + break; + } + case 1: + if (demo_dokan_move_y(0.75f, mDokanOffsetY)) { + onStatus(STATUS_5E); + switch (mDokanMode) { + case DEMO_DOKAN_RAIL: + changeDemoState(StateID_DemoRailDokan); + break; + case DEMO_DOKAN_WATER_TANK: + onStatus(STATUS_INVISIBLE); + mLayer = 0; + if (mDokanDir == DOKAN_U) { + mWarpPos.y = mPos.y + 80.0f; + } else { + mWarpPos.y = mPos.y - 80.0f; + } + mDemoSubstate = 2; + break; + default: + changeNextScene(1); + mDemoSubstate = 3; + break; + } + } + break; + case 2: + if (sLib::chase(&mPos.y, mWarpPos.y, 1.0f)) { + changeState(StateID_Walk, nullptr); + changeDemoState(StateID_DemoInWaterTank, DOKAN_TYPE_CONNECTED); + } + break; + } +} + +void daPlBase_c::initDemoOutDokanLR(u8 dir) { + mDokanDir = dir; + if (isStatus(STATUS_SWIM)) { + mpMdlMng->setAnm(PLAYER_ANIM_SWIM_PIPE); + } else { + mpMdlMng->setAnm(PLAYER_ANIM_LOW_WALK_START); + } + onStatus(STATUS_PROPEL_NO_ROLL); + if (mDokanMode == DEMO_DOKAN_NORMAL && daPyMng_c::mNum == 1) { + stopOther(); + } + if (isStatus(STATUS_SWIM) || mKind == STAGE_ACTOR_YOSHI) { + if (dir == DOKAN_R) { + mWarpPos.x += 8.0f; + } else { + mWarpPos.x -= 8.0f; + } + } + initDemoOutDokan(); +} + +void daPlBase_c::executeDemoOutDokanLR() { + // 0: Move into the pipe, possibly shifting in the Y direction if needed + // 1: Water tank only: move to X target + // 2: Water tank only: move down slightly + // 3: Water tank only: move to final X target, then transition to in-tank state + if (mpMdlMng->mpMdl->mAnm.isStop()) { + mpMdlMng->setAnm(PLAYER_ANIM_LOW_WALK); + } + switch (mDemoSubstate) { + case 0: { + bool yTargetReached = false; + if (!addCalcAngleY(getMukiAngle(mDirection), 10)) { + float offset = 0.0f; + if (isStatus(STATUS_SWIM)) { + offset = getWaterDokanCenterOffset(mWarpPos.y) - mWarpPos.y; + } + if (demo_dokan_move_y(0.75f, offset)) { + yTargetReached = true; + } + } + if (yTargetReached && demo_dokan_move_x(0.75f, 0.0f)) { + onStatus(STATUS_5E); + switch (mDokanMode) { + case DEMO_DOKAN_RAIL: + changeDemoState(StateID_DemoRailDokan); + break; + case DEMO_DOKAN_WATER_TANK: + onStatus(STATUS_INVISIBLE); + mLayer = LAYER_1; + mWarpPos.x = mPos.x + sc_DirSpeed[mDirection] * 48.0f; + mDemoSubstate = 1; + break; + default: + changeNextScene(1); + break; + } + } + break; + } + case 1: + if (sLib::chase(&mPos.x, mWarpPos.x, 1.0f)) { + mWarpPos.y -= 16.0f; + mDemoSubstate = 2; + } + break; + case 2: + if (sLib::chase(&mPos.y, mWarpPos.y, 1.0f)) { + mWarpPos.x = mPos.x + sc_DirSpeed[mDirection] * 32.0f; + mDemoSubstate = 3; + } + break; + case 3: + if (sLib::chase(&mPos.x, mWarpPos.x, 1.0f)) { + changeState(StateID_Walk, nullptr); + changeDemoState(StateID_DemoInWaterTank, DOKAN_TYPE_CONNECTED); + } + break; + } +} + +void daPlBase_c::initializeState_DemoOutDokanU() { initDemoOutDokanUD(DOKAN_U); } +void daPlBase_c::finalizeState_DemoOutDokanU() { endDemoOutDokan(); } +void daPlBase_c::executeState_DemoOutDokanU() { executeDemoOutDokanUD(); } + +void daPlBase_c::initializeState_DemoOutDokanD() { initDemoOutDokanUD(DOKAN_D); } +void daPlBase_c::finalizeState_DemoOutDokanD() { endDemoOutDokan(); } +void daPlBase_c::executeState_DemoOutDokanD() { executeDemoOutDokanUD(); } + +void daPlBase_c::initializeState_DemoOutDokanL() { initDemoOutDokanLR(DOKAN_L); } +void daPlBase_c::finalizeState_DemoOutDokanL() { endDemoOutDokan(); } +void daPlBase_c::executeState_DemoOutDokanL() { executeDemoOutDokanLR(); } + +void daPlBase_c::initializeState_DemoOutDokanR() { initDemoOutDokanLR(DOKAN_R); } +void daPlBase_c::finalizeState_DemoOutDokanR() { endDemoOutDokan(); } +void daPlBase_c::executeState_DemoOutDokanR() { executeDemoOutDokanLR(); } + +void daPlBase_c::initializeState_DemoOutDokanRoll() { + initDemoOutDokanUD(DOKAN_ROLL); + mDokanMode = DEMO_DOKAN_NORMAL; + mDokanMoveSpeed.x = 0.0f; + mDokanMoveSpeed.y = 0.0f; + mBc.setRideOnObjBg(mpDokanBgCtr, mPos); + mpDokanBgCtr->addDokanMoveDiff(&mWarpPos); +} + +void daPlBase_c::finalizeState_DemoOutDokanRoll() {} + +void daPlBase_c::executeState_DemoOutDokanRoll() { + mBc.setRideOnObjBg(mpDokanBgCtr, mPos); + mpDokanBgCtr->addDokanMoveDiff(&mWarpPos); + mVec3_c warpPos(mWarpPos.x, mWarpPos.y, mPos.z); + switch (mDemoSubstate) { + case 0: { + int cond = 0; + if (mKind == STAGE_ACTOR_YOSHI) { + if (mAngle.y.chase(0, scDokanOutTurnSpeed[0])) { + cond = 1; + } + } else { + if (mAngle.y.chase(getMukiAngle(mDirection), 0x2000)) { + cond = 1; + } + } + mVec3_c copy; + mVec3_c diff1 = warpPos - mPos; + copy.set(diff1.x, diff1.y, diff1.z); + copy.normalize(); + mPos += 1.0f * copy; + + if ((mPos - warpPos).isSmallerThan1()) { + if (cond == 1) { + mPos = warpPos; + mDemoSubstate = 1; + } + } + break; + } + case 1: { + mAng v = *mpDokanBgCtr->mRotation; + if (mDirection == DIR_LR_L) { + v = -v; + } + sLib::addCalcAngle(&mAngle.x.mAngle, v.mAngle, 4, 0x1000, 0x100); + float tmp = mDokanOffsetY + -32.0f; + sLib::chase(&mDokanMoveSpeed.y, tmp, 0.75f); + mMtx_c m1, m2; + m1.trans(warpPos); + m1.ZrotM(*mpDokanBgCtr->mRotation); + m2.trans(0.0f, mDokanMoveSpeed.y, 0.0f); + m1.concat(m2); + m1.multVecZero(mPos); + if (mDokanMoveSpeed.y <= tmp) { + changeNextScene(1); + mDemoSubstate = 3; + onStatus(STATUS_INVISIBLE); + } + break; + } + } +} + +void daPlBase_c::initializeState_DemoInWaterTank() { + onStatus(STATUS_INVISIBLE); + mDirection = mDemoStateArg; + mpMdlMng->setAnm(PLAYER_ANIM_LOW_WALK); + mAngle.y = 0; + if (mDemoStateArg == 1) { + mDamageInvulnTimer = 0; + mLayer = 0; + setZPosition(3000.0f); + } else { + mDamageInvulnTimer = 35; + if (daPyDemoMng_c::mspInstance->checkDemoNo(mPlayerNo)) { + stopOther(); + } + } + mDemoSubstate = 0; +} + +void daPlBase_c::finalizeState_DemoInWaterTank() {} + +void daPlBase_c::executeState_DemoInWaterTank() { + // 0: Animation in + // 1: Wait for animation end, then change to normal action + switch (mDemoSubstate) { + case 0: + if (!mFader_c::mFader->isStatus(mFaderBase_c::HIDDEN)) { + break; + } + if (!daPyDemoMng_c::mspInstance->checkDemoNo(mPlayerNo)) { + break; + } + offStatus(STATUS_INVISIBLE); + mDemoSubstate = 1; + mDemoSubstateTimer = 60; + clearNowBgCross(); + checkWater(); + if (isNowBgCross(BGC_WATER_SHALLOW)) { + mpMdlMng->setAnm(PLAYER_ANIM_SWIM_PIPE); + mPos.y = getWaterDokanCenterOffset(mPos.y); + startSound(SE_PLY_WATER_DOKAN_IN_OUT, false); + } else { + startSound(SE_PLY_DOKAN_IN_OUT, false); + } + break; + case 1: + if (mDemoSubstateTimer == 0) { + changeNormalAction(); + } + break; + } +} + +void daPlBase_c::initializeState_DemoOutWaterTank() { + mpMdlMng->setAnm(PLAYER_ANIM_WAIT); + mSpeedF = 0.0f; + mMaxSpeedF = 0.0f; + mSpeed.set(0.0f, 0.0f, 0.0f); + mAngle.x = 0.0f; + mAngle.y = 0x8000; +} + +void daPlBase_c::finalizeState_DemoOutWaterTank() {} + +void daPlBase_c::executeState_DemoOutWaterTank() { + // 0: Shift towards the center of the pipe + // 1: Wait for animation to finish + // 2: Move inside of the pipe horizontally + // 3: Move down the pipe vertically + // 4: Move to the final target position, then switch to the pipe exit state + switch (mDemoSubstate) { + case 0: + if (sLib::chase(&mPos.x, mWarpPos.x, 1.0f)) { + mpMdlMng->setAnm(PLAYER_ANIM_LOW_WALK_START); + startSound(SE_PLY_DOKAN_IN_OUT, false); + mDemoSubstateTimer = 60; + mDemoSubstate = 1; + } + break; + case 1: + if (mpMdlMng->mpMdl->mAnm.isStop()) { + mpMdlMng->setAnm(PLAYER_ANIM_LOW_WALK); + } + if (mDemoSubstateTimer == 0) { + onStatus(STATUS_INVISIBLE); + if (mDokanMode == DEMO_DOKAN_WATER_TANK) { + setZPosition(-1800.0f); + if (mDemoStateArg <= 1) { + mWarpPos.x = mPos.x + sc_DirSpeed[mDemoStateArg] * 32.0f; + mDemoSubstate = 2; + } else { + mWarpPos.y = mPos.y - sc_DirSpeed[mDemoStateArg & 1] * 80.0f; + mDemoSubstate = 4; + } + } else { + changeNextScene(1); + } + break; + } + break; + case 2: + if (sLib::chase(&mPos.x, mWarpPos.x, 1.0f)) { + mWarpPos.y = getWaterDokanCenterOffset(mWarpPos.y + 16.0f); + mDemoSubstate = 3; + } + break; + case 3: + if (sLib::chase(&mPos.y, mWarpPos.y, 1.0f)) { + mWarpPos.x = mPos.x + sc_DirSpeed[mDemoStateArg] * 48.0f; + mDemoSubstate = 4; + } + break; + case 4: + if ( + sLib::chase(&mPos.x, mWarpPos.x, 1.0f) && + sLib::chase(&mPos.y, mWarpPos.y, 1.0f) + ) { + mLayer = LAYER_2; + mAngle.y = 0; + switch (mDemoStateArg) { + case 0: + changeDemoState(StateID_DemoInDokanL, DOKAN_TYPE_CONNECTED); + break; + case 1: + changeDemoState(StateID_DemoInDokanR, DOKAN_TYPE_CONNECTED); + break; + case 2: + changeDemoState(StateID_DemoInDokanU, DOKAN_TYPE_CONNECTED); + break; + case 3: + changeDemoState(StateID_DemoInDokanD, DOKAN_TYPE_CONNECTED); + break; + } + setZPosition(-1800.0f); + } + break; + } +} + +void daPlBase_c::initializeState_DemoRailDokan() { + onStatus(STATUS_INVISIBLE); + sNextGotoData *nextGoto = dCd_c::m_instance-> + getFileP(dScStage_c::m_instance->mCurrFile)-> + getNextGotoP(mDokanEnterNextGotoID); + + sRailInfoData *rail = dRail_c::getRailInfoP(nextGoto->mRailID); + + // @bug This line should appear after setting mRailDokanRailIndex, not before. + sRailNodeData *node = &dCd_c::m_instance-> + getFileP(dScStage_c::m_instance->mCurrFile)-> + mpRailNodes[rail->mNodeIdx + mRailDokanRailIndex]; + + if (nextGoto->mFlags & NEXT_GOTO_RAIL_REVERSE) { + mRailDokanRailIndex = rail->mCount - 2; + } else { + mRailDokanRailIndex = 1; + } + + mVec2_c delta(node->mX - mPos.x, -node->mY - mPos.y); + + float size = delta.length(); + mRailDokanNextNodeTimer = size / 2.0f; + mDokanMoveSpeed.set(delta.x / size * 2.0f, delta.y / size * 2.0f); +} + +void daPlBase_c::finalizeState_DemoRailDokan() { + offStatus(STATUS_INVISIBLE); +} + +void daPlBase_c::setExitRailDokan() { + dCdFile_c *cdFile = dCd_c::m_instance->getFileP(dScStage_c::m_instance->mCurrFile); + + sNextGotoData *nextGoto = cdFile->getNextGotoP(mDokanEnterNextGotoID); + + // @bug This will the entered next-goto, not the one the player will exit from. + // To fix this, we'd need to do + // nextGoto = cdFile->getNextGotoP(nextGoto->mDestID); + // here. + + mLayer = nextGoto->mLayer; + + switch (nextGoto->mType) { + case 3: + changeDemoState(StateID_DemoInDokanU, DOKAN_TYPE_CONNECTED); + break; + case 4: + // @bug This should be StateID_DemoInDokanD. + changeDemoState(StateID_DemoInDokanU, DOKAN_TYPE_CONNECTED); + break; + case 5: + changeDemoState(StateID_DemoInDokanR, DOKAN_TYPE_CONNECTED); + break; + case 6: + changeDemoState(StateID_DemoInDokanL, DOKAN_TYPE_CONNECTED); + break; + } +} + +void daPlBase_c::executeState_DemoRailDokan() { + if (--mRailDokanNextNodeTimer < 0) { + sNextGotoData *ngt = dCd_c::m_instance-> + getFileP(dScStage_c::m_instance->mCurrFile)-> + getNextGotoP(mDokanEnterNextGotoID); + sRailInfoData *rail = dRail_c::getRailInfoP(ngt->mRailID); + + sRailNodeData *currNode = &dCd_c::m_instance-> + getFileP(dScStage_c::m_instance->mCurrFile)-> + mpRailNodes[rail->mNodeIdx + mRailDokanRailIndex]; + mPos.x = currNode->mX; + mPos.y = -currNode->mY; + + int done = 0; + if (ngt->mFlags & 1) { + mRailDokanRailIndex--; + if (mRailDokanRailIndex < 0) { + done = 1; + } + } else { + mRailDokanRailIndex++; + if (mRailDokanRailIndex >= rail->mCount) { + done = 1; + } + } + + if (done == 1) { + setExitRailDokan(); + return; + } + + sRailNodeData *nextNode = &dCd_c::m_instance-> + getFileP(dScStage_c::m_instance->mCurrFile)-> + mpRailNodes[rail->mNodeIdx + mRailDokanRailIndex]; + + mVec2_c distToNext(nextNode->mX - mPos.x, -nextNode->mY - mPos.y); + + float distLen = distToNext.length(); + mRailDokanNextNodeTimer = distLen / 2.0f; + mDokanMoveSpeed.set(distToNext.x / distLen * 2.0f, distToNext.y / distLen * 2.0f); + } else { + mPos.x += mDokanMoveSpeed.x; + mPos.y += mDokanMoveSpeed.y; + } +} + +void daPlBase_c::setObjDokanIn(dBg_ctr_c *bgCtr, mVec3_c &pos, int nextGotoID) { + mpDokanBgCtr = bgCtr; + mWarpPos.set(pos.x, pos.y, mPos.z); + mRollDokanAngle = *bgCtr->mRotation; + setDemoOutDokanAction(nextGotoID, DOKAN_ROLL); +} + +bool daPlBase_c::isDispOutCheckOn() { + if (isStatus(STATUS_OUT_OF_PLAY) || + isStatus(STATUS_STUNNED) || + isStatus(STATUS_53) || + isStatus(STATUS_GOAL_POLE_NOT_GOAL_NO_MOVE) || + isStatus(STATUS_DEMO_NEXT_GOTO_BLOCK) || + isStatus(STATUS_8D) + ) { + return false; + } + return true; +} + +void daPlBase_c::initializeState_DemoDown() {} +void daPlBase_c::finalizeState_DemoDown() {} +void daPlBase_c::executeState_DemoDown() {} + +int daPlBase_c::setDemoGoal(mVec3_c &landPos, float goalCastleX, u8 goalType) { + if (daPyDemoMng_c::mspInstance->mFlags & 4) { + return -1; + } + + mPos.x = landPos.x; + changeState(StateID_None); + changeDemoState(StateID_DemoGoal, false); + + mWarpPos.x = goalCastleX; + mWarpPos.y = landPos.y; + mWarpPos.z = landPos.x + 80.0f; + + mGoalDemoIndex = daPyDemoMng_c::mspInstance->setGoalDemoList(mPlayerNo); + if (mGoalDemoIndex == 0) { + // Only set once, when the first player reaches the goal + daPyDemoMng_c::mspInstance->setDemoMode(daPyDemoMng_c::MODE_1, 0); + daPyDemoMng_c::mspInstance->mGoalType = goalType; + daPyDemoMng_c::mspInstance->mPlayerNo = mPlayerNo; + + mVec3_c fireworkPos(goalCastleX - 112.0f, landPos.y, 5500.0f); + float height; + if (dBc_c::checkGround(&fireworkPos, &height, mLayer, 1, -1)) { + fireworkPos.y = height + 112.0f; + } + daPyDemoMng_c::mspInstance->mFireworkPos = fireworkPos; + } + + if (!daPyMng_c::isItemKinopio(mPlayerNo)) { + if (mGoalDemoIndex != 0 && mGoalDemoIndex + 1 == daPyMng_c::getNumInGame()) { + // All players have reached the goal + dMultiMng_c::mspInstance->setClapSE(); + } + } else { + daPyDemoMng_c::mspInstance->m_42 = 1; + dGameCom::hideFukidashiForSession(mPlayerNo, 8); + } + + int totalPlayers = daPyMng_c::getNumInGame() + daPyMng_c::getItemKinopioNum(); + if (totalPlayers == mGoalDemoIndex + 1) { + daPyDemoMng_c::mspInstance->stopBgmGoalDemo(); + } + + return -1; +} + +bool daPlBase_c::setHideNotGoalPlayer() { + if (!isStatus(STATUS_GOAL_POLE_TOUCHED)) { + mSpeedF = 0.0f; + mSpeed.y = 0.0f; + onStatus(STATUS_GOAL_POLE_NOT_GOAL_NO_MOVE); + setFallAction(); + return true; + } + return false; +} + +void daPlBase_c::stopGoalOther() { + if (!isPlayerGameStop()) { + return; + } + dActor_c::mExecStopReq |= 0xf; + for (int i = 0; i < PLAYER_COUNT; i++) { + daPlBase_c *ctrlPl = daPyMng_c::getCtrlPlayer(i); + if (ctrlPl == nullptr || !ctrlPl->isStatus(STATUS_GOAL_POLE_TOUCHED)) { + continue; + } + + daPlBase_c *pl = daPyMng_c::getPlayer(i); + if (pl != nullptr) { + pl->mExecStopMask &= ~2; + } + daPlBase_c *yoshi = daPyMng_c::getYoshi(i); + if (yoshi != nullptr) { + yoshi->mExecStopMask &= ~2; + } + } +} + +void daPlBase_c::playGoalOther() { + dActor_c::mExecStopReq &= ~0xf; + for (int i = 0; i < PLAYER_COUNT; i++) { + daPlBase_c *ctrlPl = daPyMng_c::getCtrlPlayer(i); + if (ctrlPl == nullptr || ctrlPl->isStatus(STATUS_GOAL_POLE_TOUCHED)) { + continue; + } + + daPlBase_c *pl = daPyMng_c::getPlayer(i); + if (pl != nullptr) { + pl->mExecStopMask |= 2; + } + daPlBase_c *yoshi = daPyMng_c::getYoshi(i); + if (yoshi != nullptr) { + yoshi->mExecStopMask |= 2; + } + } +} + +void daPlBase_c::initDemoGoalBase() { + onStatus(STATUS_GOAL_POLE_TOUCHED); + if (!mDemoStateArg) { + startPlayerVoice(VOICE_GOAL_POLE_CATCH, 0); + onStatus(STATUS_7E); + } + clearJumpActionInfo(0); + endStar(); + setDemoGoalMode(0, 0); + mpMdlMng->setAnm(PLAYER_ANIM_RTREE_START); + mAngle.x = 0; + setZPositionDirect(3000.0f); + mSpeed.x = 0.0f; + mSpeedF = 0.0f; + mSpeed.y = 0.0f; + mAccelY = 0.0f; + mMaxFallSpeed = -4.0f; +} + +void daPlBase_c::finalizeDemoGoalBase() { + offStatus(STATUS_GOAL_POLE_TOUCHED); + offStatus(STATUS_GOAL_POLE_WAIT_BELOW_PLAYER); + offStatus(STATUS_GOAL_POLE_FINISHED_SLIDE_DOWN); + offStatus(STATUS_GOAL_POLE_READY_FOR_JUMP_OFF); + offStatus(STATUS_GOAL_POLE_TURN); + offStatus(STATUS_6C); + offStatus(STATUS_6D); + offStatus(STATUS_6E); + offStatus(STATUS_7E); +} + +void daPlBase_c::initializeState_DemoGoal() { initDemoGoalBase(); } +void daPlBase_c::finalizeState_DemoGoal() { finalizeDemoGoalBase(); } + +float daPlBase_c::getDemoGoalLandPos() { + float pos = mWarpPos.z + daPyDemoMng_c::mspInstance->m_1c * 16.0f; + if (daPyDemoMng_c::mspInstance->m_1c > 1) { + pos -= mGoalTouchOrder * 32.0f; + } + return pos; +} + +void daPlBase_c::setDemoGoal_MultiJump() { + offStatus(STATUS_7E); + mVec3_c pos( + getDemoGoalLandPos(), + mPos.y, + mPos.z + ); + dBc_c::checkGround(&pos, &pos.y, mLayer, 1, -1); + mAngle.y = 0x4000; + mDemoState = GOAL_DEMO_POLE_JUMP; + mpMdlMng->setAnm(PLAYER_ANIM_GOAL_JUMP); + if (daPyDemoMng_c::mspInstance->m_1c > 1) { + initGoalJump(pos, daPlBase_c::sc_JumpSpeed + 1.5f); + } else { + initGoalJump(pos, daPlBase_c::sc_JumpSpeed + 1.3f); + } +} + +void daPlBase_c::executeDemoGoal_Pole() { + switch ((DemoGoalState_Pole_e) mDemoState) { + case GOAL_DEMO_POLE_SWING: + if (!addCalcAngleY(-0x4000, 10) && mpMdlMng->mpMdl->mAnm.isStop()) { + mDemoState = GOAL_DEMO_WAIT_BELOW_PLAYER; + mpMdlMng->setAnm(PLAYER_ANIM_RTREE_WAIT); + onStatus(STATUS_GOAL_POLE_WAIT_BELOW_PLAYER); + } + break; + case GOAL_DEMO_WAIT_BELOW_PLAYER: + if (isStatus(STATUS_67)) { + int polePlayer = daPyDemoMng_c::mspInstance->getPoleBelowPlayer(mPlayerNo); + if (polePlayer != -1) { + daPlBase_c *ctrlPl = daPyMng_c::getCtrlPlayer(polePlayer); + if (ctrlPl != nullptr) { + float l = 0.7f * ctrlPl->getModelHeight() + ctrlPl->mPos.y; + if (!(mPos.y > l || ctrlPl->isStatus(STATUS_GOAL_POLE_FINISHED_SLIDE_DOWN))) { + break; + } + } + } + mDemoState = GOAL_DEMO_POLE_SLIDE; + offStatus(STATUS_GOAL_POLE_WAIT_BELOW_PLAYER); + daPyDemoMng_c::mspInstance->mFlags |= 1; + mSpeed.y = -1.9f; + } + break; + case GOAL_DEMO_POLE_SLIDE: { + mPos.y += mSpeed.y; + if (mPos.y < mGoalPoleEndY) { + mPos.y = mGoalPoleEndY; + onStatus(STATUS_GOAL_POLE_FINISHED_SLIDE_DOWN); + mSpeed.y = 0.0f; + mDemoState = GOAL_DEMO_POLE_WAIT_JUMP; + mpMdlMng->setAnm(PLAYER_ANIM_RTREE_POSE); + } + break; + } + case GOAL_DEMO_POLE_WAIT_JUMP: + if (isStatus(STATUS_GOAL_POLE_READY_FOR_JUMP_OFF)) { + setDemoGoal_MultiJump(); + } + break; + case GOAL_DEMO_POLE_JUMP: + if (calcGoalJump()) { + mDemoState = GOAL_DEMO_POLE_LAND; + mpMdlMng->setAnm(PLAYER_ANIM_GOAL_JUMP_ED); + setLandSE(); + } + break; + case GOAL_DEMO_POLE_LAND: + if (mpMdlMng->mpMdl->mAnm.isStop()) { + mpMdlMng->setAnm(PLAYER_ANIM_STAMP); + mDemoState = GOAL_DEMO_POLE_WAIT_TURN; + mDemoSubstateTimer = sc_DemoPoleWaitTurn; + } + break; + case GOAL_DEMO_POLE_WAIT_TURN: + if (mDemoSubstateTimer == 0) { + onStatus(STATUS_GOAL_POLE_TURN); + mDemoState = GOAL_DEMO_POLE_TURN; + } + break; + case GOAL_DEMO_POLE_TURN: + if (daPyDemoMng_c::mspInstance->mFlags & 8 && !addCalcAngleY(0, 10)) { + mDemoSubstateTimer = sc_DemoPoleWaitEnd; + mDemoState = GOAL_DEMO_POLE_WAIT_END; + } + break; + case GOAL_DEMO_POLE_WAIT_END: + if (mDemoSubstateTimer == 0) { + setDemoGoalMode(GOAL_DEMO_ACTION_WAIT, 0); + } + break; + } +} + +void daPlBase_c::executeDemoGoal_Wait() { + if (isStatus(STATUS_6B)) { + offStatus(STATUS_6B); + onStatus(STATUS_6C); + setDemoGoalMode(GOAL_DEMO_ACTION_KIME_POSE, 0); + } + if (isStatus(STATUS_6D)) { + setDemoGoalMode(GOAL_DEMO_ACTION_RUN, 0); + } +} + +void daPlBase_c::executeDemoGoal_KimePose() { + if (mKimePoseMode != KIME_POSE_NONE && mpMdlMng->mpMdl->mAnm.checkFrame(107.0f)) { + daPlBase_c *pl = daPyMng_c::getPlayer(mPlayerNo); + if (pl != nullptr) { + if (pl->isItemKinopio()) { + if (mKimePoseMode == KIME_POSE_PENGUIN || mKimePoseMode == KIME_POSE_NO_HAT) { + if (pl->mPowerup == POWERUP_NONE) { + dScoreMng_c::m_instance->fn_800e25a0(8, mPlayerNo, 1); + } else { + dScoreMng_c::m_instance->fn_800e25a0(9, mPlayerNo, 1); + } + } + } else { + if (dInfo_c::mGameFlag & 0x10 && dInfo_c::mGameFlag & 0x40) { + if (mGoalDemoIndex == 0) { + SndAudioMgr::sInstance->startSystemSe(SE_OBJ_GOAL_GET_COIN_BONUS, 1); + } + static const int scGoalCoin[] = {20, 15, 10, 5 }; + dMultiMng_c::mspInstance->setBattleCoin(mPlayerNo, scGoalCoin[mGoalTouchOrder]); + } + } + } + } + if (updateDemoKimePose(CLEAR_TYPE_GOAL)) { + setDemoGoalMode(GOAL_DEMO_ACTION_WAIT, 0); + } +} + +void daPlBase_c::executeDemoGoal_Run() {} + +void daPlBase_c::setDemoGoalMode(int mode, int param) { + mDemoSubstate = mode; + mDemoState = param; +} + +void daPlBase_c::executeState_DemoGoal() { + switch ((DemoGoalSubstate_e) mDemoSubstate) { + case GOAL_DEMO_ACTION_POLE: + executeDemoGoal_Pole(); + break; + case GOAL_DEMO_ACTION_WAIT: + executeDemoGoal_Wait(); + break; + case GOAL_DEMO_ACTION_KIME_POSE: + executeDemoGoal_KimePose(); + break; + case GOAL_DEMO_ACTION_RUN: + executeDemoGoal_Run(); + break; + } + bgCheck(0); +} + +void daPlBase_c::initGoalJump(mVec3_c &pos, float ySpeed) { + mSpeed.y = ySpeed; + int count = 0; + float yPos = mPos.y; + while (true) { + mAccelY = -0.28f; + mSpeed.y += mAccelY; + if (mSpeed.y < -4.0f) { + mSpeed.y = -4.0f; + } + yPos += mSpeed.y; + if (mSpeed.y < 0.0f && yPos <= pos.y) { + break; + } + count++; + } + mGoalJumpTarget = pos; + mGoalJumpFrameCount = count; + mSpeed.y = ySpeed; +} + +bool daPlBase_c::calcGoalJump() { + if (mGoalJumpFrameCount != 0) { + sLib::chase(&mPos.x, mGoalJumpTarget.x, (mGoalJumpTarget.x - mPos.x) / mGoalJumpFrameCount); + mGoalJumpFrameCount--; + } + mAccelY = -0.28f; + mSpeed.y += mAccelY; + if (mSpeed.y < -4.0f) { + mSpeed.y = -4.0f; + } + mPos.y += mSpeed.y; + if (mSpeed.y < 0.0f && isNowBgCross(BGC_FOOT)) { + mPos = mGoalJumpTarget; + return true; + } + return false; +} + +void daPlBase_c::initDemoKimePose() { + onStatus(STATUS_6C); + mKimePoseMode = KIME_POSE_NONE; +} + +bool daPlBase_c::updateDemoKimePose(ClearType_e clearType) { + return false; +} + +void daPlBase_c::startKimePoseVoice(ClearType_e clearType) { + int playerCount; + if (clearType == CLEAR_TYPE_GOAL) { + playerCount = daPyDemoMng_c::mspInstance->m_1c; + } else { + playerCount = daPyDemoMng_c::mspInstance->getControlDemoPlayerNum(); + } + if (dInfo_c::m_startGameInfo.mScreenType == 1) { + if (playerCount >= 2) { + startPlayerVoice(VOICE_CLEAR_MULTI, 0); + } else { + startPlayerVoice(VOICE_CLEAR_HELPED, 0); + } + } else if (clearType == CLEAR_TYPE_FINAL_BOSS) { + startPlayerVoice(VOICE_CLEAR_LAST_BOSS, 0); + } else if (playerCount >= 2) { + startPlayerVoice(VOICE_CLEAR_MULTI, 0); + } else if (clearType == CLEAR_TYPE_GOAL) { + if (daPyDemoMng_c::mspInstance->mGoalType == 0) { + startPlayerVoice(VOICE_CLEAR_NORMAL, 0); + } else { + startPlayerVoice(VOICE_CLEAR_ANOTHER, 0); + } + } else { + startPlayerVoice(VOICE_CLEAR_BOSS, 0); + } +} + +bool daPlBase_c::startControlDemo() { + if (isDemoType(DEMO_PLAYER)) { + return true; + } else if (isDemoType(DEMO_ENDING_DANCE)) { + changeDemoState(StateID_DemoControl, CONTROL_DEMO_WAIT); + return true; + } else { + onStatus(STATUS_71); + return false; + } +} + +void daPlBase_c::endControlDemo(int p) { + if (isStatus(STATUS_72)) { + changeNormalAction(); + } +} + +void daPlBase_c::setControlDemoDir(u8 dir) { + if (isStatus(STATUS_72)) { + mDirection = dir; + if (!isState(StateID_Walk)) { + changeState(StateID_Walk, (void *) 1); + } + } +} + +void daPlBase_c::setControlDemoWait() { + if (isStatus(STATUS_72)) { + mDemoState = CONTROL_DEMO_WAIT; + changeState(StateID_Walk, (void *) 1); + } +} + +bool daPlBase_c::isControlDemoWait() { + if (isStatus(STATUS_72)) { + if (mDemoState == CONTROL_DEMO_WAIT) { + return true; + } + } + return false; +} + +void daPlBase_c::setControlDemoWalk(const float &f1, const float &f2) { + if (isStatus(STATUS_72)) { + mControlDemoTargetPos.x = f1; + mDemoState = CONTROL_DEMO_WALK; + mControlDemoSpeedF = std::fabs(f2); + if (mControlDemoSpeedF > getSpeedData()->mHighSpeed) { + mControlDemoSpeedF = getSpeedData()->mHighSpeed; + } + } +} + +bool daPlBase_c::isControlDemoWalk() { + if (isStatus(STATUS_72)) { + if (mDemoState == CONTROL_DEMO_WALK) { + return true; + } + } + return false; +} + +void daPlBase_c::setControlDemoAnm(int anmNo) { + if (isStatus(STATUS_72)) { + mDemoState = CONTROL_DEMO_REGULAR_ANIM; + changeState(StateID_AnimePlay, DEMO_ANIME_NORMAL); + mpMdlMng->setAnm(anmNo); + } +} +bool daPlBase_c::isControlDemoAnm(int anmNo) { + if (isStatus(STATUS_72) && mDemoState == CONTROL_DEMO_REGULAR_ANIM && anmNo == mpMdlMng->mpMdl->mCurrAnmID) { + return true; + } + return false; +} + +void daPlBase_c::setControlDemoCutscene(AnimePlayArg_e animID) { + if (isStatus(STATUS_72)) { + mDemoState = CONTROL_DEMO_CUTSCENE_ANIM; + changeState(StateID_AnimePlay, animID); + } +} + +void daPlBase_c::setControlDemoKinopioWalk() { + if (isDemoState(StateID_DemoNone) || (isDemoType(DEMO_KINOPIO) && mDemoState != CONTROL_DEMO_KINOPIO_WALK)) { + changeDemoState(StateID_DemoControl, CONTROL_DEMO_KINOPIO_WALK); + } +} + +void daPlBase_c::setControlDemoKinopioSwim() { + if (isDemoState(StateID_DemoNone) || (isDemoType(DEMO_KINOPIO) && mDemoState != CONTROL_DEMO_KINOPIO_SWIM)) { + changeDemoState(StateID_DemoControl, CONTROL_DEMO_KINOPIO_SWIM); + } +} + +void daPlBase_c::setControlDemoEndingDance() { + if (!isControlDemoAll()) { + changeDemoState(StateID_DemoControl, CONTROL_DEMO_ENDING_DANCE); + } +} + +bool daPlBase_c::isBossDemoLand() { + if (!isNowBgCross(BGC_FOOT)) { + return false; + } + if (isStatus(STATUS_BIG_JUMP) || isStatus(STATUS_4E) || isOnSinkSand() || mBossDemoLandTimer != 0) { + return false; + } + return true; +} + +bool daPlBase_c::isHitGroundKinopioWalk(int dir, float f, int i2) { + mVec3_c tmp( + mPos.x + f * sc_DirSpeed[dir], + mPos.y, + mPos.z + ); + float a = 4.0f; + if (a < 1.2f * f) { + a = 1.2f * f; + } + tmp.y = mPos.y + a; + float y; + if (mBc.checkGround(&tmp, &y, mLayer, mAmiLayer, -1) && std::fabs(y - mPos.y) < a) { + if (i2 == 1) { + tmp.y = mPos.y - 4.0f; + float y2; + if (dBc_c::checkWater(tmp.x, tmp.y, mLayer, &y2) && + mLastPosDelta.y >= 0.0f && + y <= y2 && + mPos.y <= y2 - 4.0f + ) { + return false; + } + } + return true; + } + return false; +} + +bool daPlBase_c::isHitWallKinopioWalk(int dir) { + static const BgCross1_e scViewHitFlag[] = { BGC_SIDE_LIMIT_R, BGC_SIDE_LIMIT_L }; + if (checkBGCrossWall(dir) || isNowBgCross(scViewHitFlag[dir])) { + return true; + } + return false; +} + +bool daPlBase_c::checkKinopioWaitBG(int dir) { + if (isHitWallKinopioWalk(dir)) { + return true; + } + return !isHitGroundKinopioWalk(dir, 10.0, 0); +} + +void daPlBase_c::initializeState_DemoControl() { + if (isStatus(STATUS_5F)) { + offStatus(STATUS_5F); + } + mKey.onStatus(dAcPyKey_c::STATUS_DEMO); + onStatus(STATUS_72); + offStatus(STATUS_71); + mIsDemoMode = false; + initializeDemoControl(); + mDemoState = mDemoStateArg; + switch (mDemoState) { + case CONTROL_DEMO_4: + mDemoSubstateTimer = 60; + onStatus(STATUS_7A); + break; + case CONTROL_DEMO_KINOPIO_WALK: + mControlDemoTargetPos.x = mPos.x; + mControlDemoSpeedF = 0.9f; + mItemKinopioDirection = mDirection; + mItemKinopioTurnTimer = 150; + if (!isHitGroundKinopioWalk(mDirection, 8.0f, 1)) { + mItemKinopioDirection ^= 1; + } + break; + case CONTROL_DEMO_KINOPIO_SWIM: + if (mSpeedF > 0.0f) { + mItemKinopioDirection = 0; + } else { + mItemKinopioDirection = 1; + } + break; + default: + break; + } +} + +void daPlBase_c::finalizeState_DemoControl() { + mKey.offStatus(dAcPyKey_c::STATUS_DEMO); + offStatus(STATUS_72); + offStatus(STATUS_74); + offStatus(STATUS_63); + offStatus(STATUS_73); + if (mDemoState == CONTROL_DEMO_4) { + offStatus(STATUS_7A); + } +} + +void daPlBase_c::executeState_DemoControl() { + offStatus(STATUS_74); + if (isStatus(STATUS_73)) { + if (isNowBgCross(BGC_FOOT)) { + offStatus(STATUS_73); + } else { + mSpeedF *= 0.98f; + } + } + + switch ((ControlDemoSubstate_e) mDemoState) { + case CONTROL_DEMO_WALK: { + onStatus(STATUS_74); + if (isNowBgCross(BGC_FOOT)) { + if (!isState(StateID_Walk) && !isState(StateID_Turn)) { + changeState(StateID_Walk, BLEND_DEFAULT); + } + } else { + if (!isState(StateID_Fall)) { + changeState(StateID_Fall, false); + } + } + if (std::fabs(mPos.x - mControlDemoTargetPos.x) < mControlDemoSpeedF) { + mDemoState = CONTROL_DEMO_WAIT; + mSpeedF = 0.0f; + mPos.x = mControlDemoTargetPos.x; + break; + } + if (mPos.x < mControlDemoTargetPos.x) { + mKey.onDemoTrigger(dAcPyKey_c::BUTTON_RIGHT); + mSpeedF = mControlDemoSpeedF; + break; + } + mKey.onDemoTrigger(dAcPyKey_c::BUTTON_LEFT); + mSpeedF = -mControlDemoSpeedF; + break; + } + case CONTROL_DEMO_4: { + if (mDemoSubstateTimer == 0) { + changeDemoState(StateID_DemoNone, false); + } + break; + } + case CONTROL_DEMO_KINOPIO_WALK: { + if ( + !isNowBgCross(BGC_FOOT) || + !mStateMgr.getStateID()->isEqual(StateID_Walk) && !mStateMgr.getStateID()->isEqual(StateID_Turn) + ) { + mDemoState = CONTROL_DEMO_WAIT; + break; + } + onStatus(STATUS_74); + if (isOnSinkSand() || (checkKinopioWaitBG(0) && checkKinopioWaitBG(1))) { + mDemoState = CONTROL_DEMO_KINOPIO_SINK_SAND; + mControlDemoSpeedF = 0.0f; + mSpeedF = 0.0f; + break; + } + int prevDirection = (int) (short) mItemKinopioDirection; + sLib::calcTimer(&mItemKinopioTurnTimer); + if (isHitWallKinopioWalk(mItemKinopioDirection) || mItemKinopioTurnTimer == 0) { + mItemKinopioDirection ^= 1; + mControlDemoTargetPos.x = mPos.x + sc_DirSpeed[mItemKinopioDirection] * 24.0f; + } else if (!isHitGroundKinopioWalk(mItemKinopioDirection, 4.0f, 1) && !isHitGroundKinopioWalk(mItemKinopioDirection, 8.0f, 1)) { + mItemKinopioDirection ^= 1; + mControlDemoTargetPos.x = mPos.x + sc_DirSpeed[mItemKinopioDirection] * 24.0f; + } + float tmp = mControlDemoTargetPos.x + sc_DirSpeed[mItemKinopioDirection] * 24.0f; + if (mPos.x < tmp) { + mKey.onDemoTrigger(dAcPyKey_c::BUTTON_RIGHT); + mSpeedF = mControlDemoSpeedF; + mItemKinopioDirection = 0; + } else { + mKey.onDemoTrigger(dAcPyKey_c::BUTTON_LEFT); + mItemKinopioDirection = 1; + mSpeedF = -mControlDemoSpeedF; + } + if (prevDirection != mItemKinopioDirection) { + mItemKinopioTurnTimer = 180; + } + break; + } + case CONTROL_DEMO_KINOPIO_SWIM: { + if (!mStateMgr.getStateID()->isEqual(StateID_Swim)) { + mDemoState = CONTROL_DEMO_WAIT; + break; + } + onStatus(STATUS_74); + if (isNowBgCross(BGC_FOOT) && isHitWallKinopioWalk(mItemKinopioDirection)) { + mItemKinopioDirection ^= 1; + } + if (mItemKinopioDirection == 0) { + mKey.onDemoTrigger(dAcPyKey_c::BUTTON_RIGHT); + sLib::chase(&mSpeedF, 0.5625f, 0.1f); + } else { + mKey.onDemoTrigger(dAcPyKey_c::BUTTON_LEFT); + sLib::chase(&mSpeedF, -0.5625f, 0.1f); + } + break; + } + case CONTROL_DEMO_KINOPIO_SINK_SAND: { + if ( + !isNowBgCross(BGC_FOOT) || + !mStateMgr.getStateID()->isEqual(StateID_Walk) && !mStateMgr.getStateID()->isEqual(StateID_Turn) + ) { + mDemoState = CONTROL_DEMO_WAIT; + break; + } + onStatus(STATUS_74); + onStatus(STATUS_63); + if (!checkKinopioWaitBG(0) || !checkKinopioWaitBG(1)) { + setControlDemoKinopioWalk(); + } + break; + } + default: + break; + } +} + +void daPlBase_c::setDemoOutNextGotoBlock(int nextGotoID, int delay, int fadeType) { + if (mDemoStateMgr.getStateID()->isEqual(StateID_DemoNextGotoBlock)) { + return; + } + changeDemoState(StateID_DemoNextGotoBlock, nextGotoID | ((fadeType & 0xFF) << 8)); + mDemoSubstateTimer = delay; + switch (fadeType) { + case 3: + startSound(SE_PLY_DOKAN_IN_OUT, false); + break; + case 1: + mIsDemoMode = false; + if (!isStatus(STATUS_PENGUIN_SLIDE)) { + changeState(StateID_Fall, false); + } + break; + default: + break; + } +} + +void daPlBase_c::initializeState_DemoNextGotoBlock() { + mKey.onStatus(dAcPyKey_c::STATUS_DEMO); + onStatus(STATUS_DEMO_NEXT_GOTO_BLOCK); + onStatus(STATUS_7A); + initializeDemoControl(); +} + +void daPlBase_c::finalizeState_DemoNextGotoBlock() { + mKey.offStatus(dAcPyKey_c::STATUS_DEMO); + offStatus(STATUS_DEMO_NEXT_GOTO_BLOCK); + offStatus(STATUS_7A); +} + +void daPlBase_c::executeState_DemoNextGotoBlock() { + switch (mDemoSubstate) { + case 0: + if (mDemoSubstateTimer == 0) { + dFader_c::fader_type_e f = dFader_c::FADER_DRIP_DOWN; + int param = (int) mDemoStateArg; + int nextGotoID = param & 0xff; + if (((param >> 8) & 0xff) == 3) { + f = dFader_c::FADER_CIRCLE_TARGET; + } + dNext_c::m_instance->setChangeSceneNextDat(dScStage_c::m_instance->mCurrFile, nextGotoID, f); + changeNextScene(0); + mDemoSubstate = 1; + } + break; + case 1: + break; + } +} + +void daPlBase_c::updateEndingDance() { + offStatus(STATUS_ENDING_DANCE_AUTO); + if (!dScStage_c::m_isStaffCredit || isDemoType(DEMO_PLAYER)) { + return; + } + int isActive = 0; + if (dGameKey_c::m_instance->checkButtonsDown(mPlayerNo) || dGameKey_c::m_instance->checkShaking(mPlayerNo)) { + isActive = 1; + } + if (!isDemoType(DEMO_ENDING_DANCE)) { + if (isActive == 1) { + mEndingDanceInactivityTimer = 0; + } else { + mEndingDanceInactivityTimer++; + if (mEndingDanceInactivityTimer >= 180) { + setControlDemoEndingDance(); + mEndingDanceInactivityTimer = 0; + } + } + } else if (isActive == 1) { + endControlDemo(0); + } else if (isStatus(STATUS_45)) { + for (int i = 0; i < ARRAY_SIZE(mEndingDanceKeyTimers); i++) { + mEndingDanceKeyTimers[i] = 0; + } + } else { + onStatus(STATUS_ENDING_DANCE_AUTO); + if (dAudio::isBgmAccentSign(2)) { + mDirection = 0; + } else if (dAudio::isBgmAccentSign(4)) { + mDirection = 1; + } else if (dAudio::isBgmAccentSign(8)) { + mKey.onDemoButton(dAcPyKey_c::BUTTON_DOWN); + mEndingDanceKeyTimers[2] = 6; + } else if (dAudio::isBgmAccentSign(16)) { + mKey.onDemoTrigger(dAcPyKey_c::BUTTON_TWO); + mKey.onDemoButton(dAcPyKey_c::BUTTON_TWO); + mEndingDanceKeyTimers[3] = 5; + } else if (dAudio::isBgmAccentSign(32)) { + mKey.onDemoTrigger(dAcPyKey_c::BUTTON_TWO); + mKey.onDemoButton(dAcPyKey_c::BUTTON_TWO); + mEndingDanceKeyTimers[4] = 30; + } else if (dAudio::isBgmAccentSign(64)) { + mKey.onDemoShake(); + } else if (dAudio::isBgmAccentSign(128)) { + if (dBgParameter_c::ms_Instance_p->m_48 > mPos.x) { + mDirection = 0; + } else { + mDirection = 1; + } + } + + for (int i = 0; i < 5; i++) { + if (mEndingDanceKeyTimers[i] != 0 && --mEndingDanceKeyTimers[i] == 0) { + switch (i) { + case 2: + mKey.offDemoButton(dAcPyKey_c::BUTTON_DOWN); + break; + case 3: + case 4: + mKey.offDemoButton(dAcPyKey_c::BUTTON_TWO); + break; + } + } + } + } +} + +bool daPlBase_c::setEnemyStageClearDemo() { + if (isStatus(STATUS_ENEMY_STAGE_CLEAR)) { + if ( + isNowBgCross(BGC_LIFT) && + mBc.mpCtrHead != nullptr && + mBc.mpCtrHead->mpActor != nullptr && + mBc.mpCtrHead->mpActor->mProfName == fProfile::EN_CHIKUWA_BLOCK + ) { + return false; + } + if (!isDemoType(DEMO_PLAYER)) { + changeDemoState(StateID_DemoControl, CONTROL_DEMO_WAIT); + } + mSpeed.y = 0.0f; + mSpeedF = 0.0f; + return true; + } + return false; +} + +int daPlBase_c::getCcLineKind() { + if (isNowBgCross(BgCross2_e(BGC_VINE_TOUCH_L | BGC_VINE_TOUCH_R))) { + return mAmiLayer; + } + return 3; +} + +void daPlBase_c::initCollision(sCcDatNewF *dat1, sCcDatNewF *dat2) { + mCc.set(this, dat1); + mCc1.set(this, dat1); + mAttCc1.set(this, dat2); + mAttCc2.set(this, dat2); + mAttCc3.set(this, dat2); +} + +void daPlBase_c::releaseCcData() { + u32 mVsKind = + BIT_FLAG(CC_KIND_PLAYER) | + BIT_FLAG(CC_KIND_PLAYER_ATTACK) | + BIT_FLAG(CC_KIND_YOSHI) | + BIT_FLAG(CC_KIND_ENEMY) | + BIT_FLAG(CC_KIND_BALLOON) | + BIT_FLAG(CC_KIND_ITEM) | + BIT_FLAG(CC_KIND_TAMA) | + BIT_FLAG(CC_KIND_KILLER) | + BIT_FLAG(CC_KIND_GOAL_POLE); + + u32 mVsKindAttack = + BIT_FLAG(CC_KIND_PLAYER) | + BIT_FLAG(CC_KIND_YOSHI) | + BIT_FLAG(CC_KIND_ENEMY) | + BIT_FLAG(CC_KIND_BALLOON) | + BIT_FLAG(CC_KIND_ITEM) | + BIT_FLAG(CC_KIND_KILLER); + + u32 vsDamage = + CC_FLAG_ATTACK_ALL & + ~BIT_FLAG(CC_ATTACK_NONE) & + ~BIT_FLAG(CC_ATTACK_YOSHI_MOUTH) & + ~BIT_FLAG(CC_ATTACK_SAND_PILLAR); + + mCc.release(); + mCc.mCcData.mVsKind = mVsKind; + mCc.mCcData.mAttack = 0; + mCc.mCcData.mVsDamage = vsDamage; + + mCc1.release(); + mCc1.mCcData.mVsKind = mVsKind; + mCc1.mCcData.mAttack = 0; + mCc1.mCcData.mVsDamage = vsDamage; + + mAttCc1.release(); + mAttCc1.mCcData.mVsKind = mVsKindAttack; + mAttCc1.mCcData.mAttack = 0; + mAttCc1.mCcData.mVsDamage = 0; + + mAttCc2.release(); + mAttCc2.mCcData.mVsKind = mVsKindAttack; + mAttCc2.mCcData.mAttack = 0; + mAttCc2.mCcData.mVsDamage = 0; + + mAttCc3.release(); + mAttCc3.mCcData.mVsKind = mVsKindAttack; + mAttCc3.mCcData.mAttack = 0; + mAttCc3.mCcData.mVsDamage = 0; +} + +void daPlBase_c::clearCcData() { + mCc.clear(); + mCc1.clear(); + mAttCc1.clear(); + mAttCc2.clear(); + mAttCc3.clear(); +} + +void daPlBase_c::setCcAtBody(int attackCategory) { + mAttCc2.mCcData.mBase.mOffset.set(mCc.mCcData.mBase.mOffset); + mAttCc2.mCcData.mBase.mSize.set(mCc.mCcData.mBase.mSize); + mAttCc2.mCcData.mAttack = attackCategory; + mAttCc2.mCcData.mVsKind = + BIT_FLAG(CC_KIND_PLAYER) | + BIT_FLAG(CC_KIND_PLAYER_ATTACK) | + BIT_FLAG(CC_KIND_YOSHI); + + mAttCc1.mCcData.mBase.mOffset.set(mCc.mCcData.mBase.mOffset); + mAttCc1.mCcData.mBase.mSize.set(mCc.mCcData.mBase.mSize); + mAttCc1.mCcData.mAttack = attackCategory; + mAttCc1.mCcData.mVsKind = mCc.mCcData.mVsKind & ~( + BIT_FLAG(CC_KIND_PLAYER) | + BIT_FLAG(CC_KIND_PLAYER_ATTACK) | + BIT_FLAG(CC_KIND_YOSHI) + ); +} + +void daPlBase_c::setCcAtSlip() { + setCcAtBody(CC_ATTACK_SLIP); +} + +void daPlBase_c::setCcAtPenguinSlip() { + if (isStatus(STATUS_PENGUIN_SLIDE)) { + setCcAtBody(CC_ATTACK_PENGUIN_SLIDE); + mAttCc2.mCcData.mVsDamage = BIT_FLAG(CC_ATTACK_PENGUIN_SLIDE); + mAttCc1.mCcData.mVsDamage = BIT_FLAG(CC_ATTACK_PENGUIN_SLIDE); + } +} + +void daPlBase_c::setCcAtHipAttack() { + setCcAtBody(CC_ATTACK_HIP_ATTACK); + mAttCc2.mCcData.mVsDamage = 0; + mAttCc1.mCcData.mVsDamage = 0; +} + +void daPlBase_c::setCcAtStar() { + mCc.mCcData.mAttack = CC_ATTACK_STAR; + if ((mAttCc2.mCcData.mVsKind & ( + BIT_FLAG(CC_KIND_PLAYER) | + BIT_FLAG(CC_KIND_PLAYER_ATTACK) | + BIT_FLAG(CC_KIND_YOSHI) + )) == 0) { + mCc1.mCcData.mAttack = CC_ATTACK_STAR; + } + if (mAttCc1.mCcData.mAttack != CC_ATTACK_NONE && + mAttCc1.mCcData.mAttack != CC_ATTACK_YOSHI_EAT + ) { + mAttCc3.mCcData.mBase.mOffset.set(mAttCc1.mCcData.mBase.mOffset); + mAttCc3.mCcData.mBase.mSize.set(mAttCc1.mCcData.mBase.mSize); + mAttCc3.mCcData.mAttack = CC_ATTACK_STAR; + } + onStatus(STATUS_84); +} + +void daPlBase_c::setCcAtCannon() { + setCcAtBody(CC_ATTACK_CANNON); +} + +void daPlBase_c::entryCollision() { + if (!isStatus(STATUS_OUT_OF_PLAY) && !isStatus(STATUS_STUNNED)) { + int lineKind = getCcLineKind(); + mCc.mAmiLine = lineKind; + if (mAttCc1.mCcData.mAttack == CC_ATTACK_WIRE_NET) { + lineKind ^= 3; + } + mAttCc1.mAmiLine = lineKind; + mAttCc3.mAmiLine = lineKind; + mCc.mLayer = mLayer; + mAttCc1.mLayer = mLayer; + mAttCc3.mLayer = mLayer; + if (isStatus(STATUS_74)) { + mCc.mCcData.mStatus |= CC_STATUS_NO_REVISION; + } else { + mCc.mCcData.mStatus &= ~CC_STATUS_NO_REVISION; + } + if (!isStatus(STATUS_7A)) { + mCc.entry(); + if (isStatus(STATUS_78)) { + mCc1.entry(); + } + } + if (mAttCc1.mCcData.mAttack != CC_ATTACK_NONE) { + mAttCc1.entry(); + } + if (mAttCc2.mCcData.mAttack != CC_ATTACK_NONE) { + mAttCc2.entry(); + } + if (mAttCc3.mCcData.mAttack != CC_ATTACK_NONE) { + mAttCc3.entry(); + } + } +} + +bool daPlBase_c::isActionRevisionY() { + if (isStatus(STATUS_POLE) || isStatus(STATUS_36)) { + return true; + } + return false; +} + +void daPlBase_c::setCcPlayerRev(dCc_c *cc1, dCc_c *cc2, float revRate, int ccKind) { + daPlBase_c *other = (daPlBase_c *) cc2->mpOwner; + float colliderSpeedF = other->mSpeedF; + float offsX = cc1->mCollOffsetX[ccKind]; + float offsY = cc1->mCollOffsetY[ccKind]; + if (isActionRevisionY()) { + if (other->isActionRevisionY()) { + if (mCcHasInitialRevY) { + mCcRevTotalOffsY = offsY + mCcRevTotalOffsY; + } else { + mCcHasInitialRevY = true; + mCcRevTotalOffsY = offsY * revRate; + } + } + } else if (!(std::fabs(offsY) < 1.0f || other->isActionRevisionY())) { + if (mCcRevSet) { + float prevOffsX = getCcRevOffsX() * getCcRevRate(); + float currOffsX = offsX * revRate; + if (std::fabs(prevOffsX) < std::fabs(currOffsX)) { + mCcRevSpeedF = colliderSpeedF; + } + mCcRevRate = 1.0f; + mCcRevTotalOffsX = prevOffsX + currOffsX; + } else { + mCcRevRate = revRate; + mCcRevSpeedF = colliderSpeedF; + mCcRevTotalOffsX = offsX; + mCcRevSet = true; + } + } +} + +void daPlBase_c::clearCcPlayerRev() { + mCcRevRate = 0.0f; + mCcRevSpeedF = 0.0f; + mCcRevTotalOffsX = 0.0f; + mCcRevTotalOffsY = 0.0f; + mCcRevSet = false; + mCcHasInitialRevY = false; +} + +bool daPlBase_c::calcCcPlayerRev(float *outShiftX) { + if (mCcRevSet) { + float rate = mCcRevRate; + if (isStatus(STATUS_IS_SPIN_HOLD_REQ) || mCcRevDisabledTimer != 0) { + rate = 0.0f; + } + if (isDemoType(DEMO_PLAYER) && isNowBgCross(BGC_FOOT)) { + rate = 0.0f; + } + float prevOffsX = mCcRevTotalOffsX; + mCcRevTotalOffsX = 0.0f; + if (prevOffsX) { + float shiftX = prevOffsX * rate; + float tmp2 = 3.0f; + if (shiftX > 3.0f) { + shiftX = 3.0f; + } else if (shiftX < -3.0f) { + shiftX = -3.0f; + } + if (mSpeedF * prevOffsX <= 0.0f) { + *outShiftX = shiftX; + if (isDemoType(DEMO_PLAYER) || isStatus(STATUS_5F)) { + return false; + } + float revSpeedF = mCcRevSpeedF; + float speedF = mSpeedF; + if ( + speedF * revSpeedF <= 0.0f && + std::fabs(mSpeedF) + std::fabs(mCcRevSpeedF) > 2.5f + ) { + mSpeedF = mCcRevSpeedF * 0.4f; + return true; + } + if ( + std::fabs(mSpeedF) > std::fabs(mCcRevSpeedF) && + std::fabs(mSpeedF) > 1.5f + ) { + mSpeedF = 0.0f; + return true; + } + } + } + } + return false; +} + +bool daPlBase_c::isEnableStampPlayerJump(dCc_c *cc1, dCc_c *cc2) { + daPlBase_c *other = (daPlBase_c *) cc2->mpOwner; + if (isNowBgCross(BGC_FOOT)) { + return false; + } + if (mSpeed.y >= 0.0f) { + return false; + } + if (isStatus(STATUS_HIP_ATTACK_FALL) || isStatus(STATUS_SPIN_HIP_ATTACK_FALL)) { + return false; + } + if (other->isLiftUp() || other->mSquishCooldownTimer != 0) { + return false; + } + if (isDemoType(DEMO_PLAYER) || other->isDemoType(DEMO_PLAYER)) { + return false; + } + float topPos = cc2->getTopPos() - 16.0f; + if (topPos < cc2->getCenterPosY()) { + topPos = cc2->getCenterPosY(); + } + if (cc1->getUnderPos() > topPos) { + return true; + } + return false; +} + +void daPlBase_c::setStampReduction() { + if (!isStatus(STATUS_SWIM)) { + if (mSpeed.y > 0.0f) { + mSpeed.y = 0.0f; + } + setReductionScale(); + } else { + mSpeed.y = -1.0f; + } +} + +void daPlBase_c::setStampPlayerJump(bool b, float yOffset) { + if (!isStatus(STATUS_SWIM)) { + float jumpSpeed = daPlBase_c::sc_JumpSpeed; + if (isMameAction()) { + jumpSpeed = daPlBase_c::sc_JumpSpeed - 0.35f; + } + if (b) { + dQuake_c::m_instance->shockMotor(mPlayerNo, dQuake_c::TYPE_7, 0, false); + if (mKey.buttonJump()) { + jumpSpeed = daPlBase_c::sc_JumpSpeed + 0.5f; + } + setJump(jumpSpeed, mSpeedF, true, 1, 0); + } else { + setJump(jumpSpeed, mSpeedF, true, 0, 0); + } + mPos.y += yOffset; + } else { + mSpeed.y = 1.0f; + } +} + +void daPlBase_c::setReductionScale() { + setReductionBoyon(); + initStampReduction(); +} + +void daPlBase_c::initStampReduction() { + if (!isStatus(STATUS_JUMP) || mSquishKeyframeIdx == 0) { + mSquishNoMoveTimer = 4; + } + mSquishCooldownTimer = 10; + startPlayerVoice(VOICE_STOMPED, 0); + dQuake_c::m_instance->shockMotor(mPlayerNo, dQuake_c::TYPE_7, 0, false); +} + +void daPlBase_c::calcJumpDaiReductionScale(int i1, int i2) { + if (i1 > i2) { + i1 = i2; + } + mSquishScale = i1 * 0.6f / i2; + mSquishState = SQUISH_INIT; +} + +void daPlBase_c::setReductionBoyon() { + mSquishState = SQUISH_ANIMATION; + mSquishKeyframeIdx = 4; +} + +void daPlBase_c::calcReductionScale() { + switch (mSquishState) { + case SQUISH_OFF: + break; + case SQUISH_INIT: + mSquishState = SQUISH_SET_REDUCTION; + break; + case SQUISH_SET_REDUCTION: + setReductionBoyon(); + break; + case SQUISH_ANIMATION: + if (mSquishKeyframeIdx) { + int idx = mSquishKeyframeIdx - 1; + static const float scStampScaleDt[] = { 0.0f, 0.2f, 0.0f, 0.4f }; + static const float scStampAcceleDt[] = { 0.02f, 0.025f, 0.04f, 0.06f }; + if (sLib::chase(&mSquishScale, scStampScaleDt[idx], scStampAcceleDt[idx])) { + mSquishKeyframeIdx--; + } + } + if (mSquishKeyframeIdx == 0) { + mSquishState = SQUISH_OFF; + } + break; + } +} + +mVec3_c daPlBase_c::getReductionModelScale() { + return mVec3_c( + 1.0f + mSquishScale, + 1.0f - mSquishScale, + 1.0f + mSquishScale + ); +} + +void daPlBase_c::setNoHitPlayer(const daPlBase_c *player, int duration) { + mpNoHitPlayer = player; + mNoHitTimer = duration; +} + +void daPlBase_c::updateNoHitPlayer() { + if (mNoHitTimer != 0) { + mNoHitTimer--; + } + if (mNoHitTimer == 0) { + mpNoHitPlayer = nullptr; + } +} + +daPlBase_c *daPlBase_c::getHipAttackDamagePlayer() { + return (daPlBase_c *) fManager_c::searchBaseByID(mHipAttackPlayerID); +} + +void daPlBase_c::setHipAttackDamagePlayer(daPlBase_c *player) { + onStatus(STATUS_HIP_ATTACK_DAMAGE_PLAYER); + mHipAttackPlayerID = player->mUniqueID; +} + +void daPlBase_c::clearHipAttackDamagePlayer() { + offStatus(STATUS_HIP_ATTACK_DAMAGE_PLAYER); + mHipAttackPlayerID = (fBaseID_e) 0; +} + +void daPlBase_c::setNoHitObjBg(dActor_c *obj, int duration) { + mBc.mpNoHitActor = obj; + mNoHitObjTimer = duration; +} + +void daPlBase_c::calcNoHitObjBgTimer() { + if (mNoHitObjTimer == 0) { + return; + } + if (--mNoHitObjTimer == 0) { + mBc.mpNoHitActor = nullptr; + } +} + +void daPlBase_c::setOldBGCross() { + mOldBgCross1 = mNowBgCross1; + mOldBgCross2 = mNowBgCross2; + for (int i = 9; i > 0; i--) { + mBgFootHistory[i] = mBgFootHistory[i - 1]; + } + mBgFootHistory[0] = isNowBgCross(BGC_FOOT) ? 1 : 0; +} + +void daPlBase_c::clearBgCheckInfo() { + setOldBGCross(); + clearNowBgCross(); + mPrevStandOnUnitType = mStandOnUnitType; + mStandOnUnitType = 0; + mBgPushForce.set(0.0f, 0.0f, 0.0f); + mExtraPushForceX = 0.0f; + mGroundType = GROUND_TYPE_DEFAULT; + mWaterDepth = 0; + m_d80[0] = 0.0f; + m_d80[1] = 0.0f; +} + +void daPlBase_c::bgCheck(int i) { + offStatus(STATUS_AUTO_BOUNCE); + offStatus(STATUS_86); + offStatus(STATUS_IS_SPIN_HOLD_REQ); + offStatus(STATUS_EXTRA_PUSH_FORCE); + if (isNowBgCross(BGC_FOOT)) { + m_d8c = mPos.y; + } + clearBgCheckInfo(); + sLib::calcTimer(&mAirWalkTimer); + if (i == 1) { + checkSideViewLemit(); + } + if (!isStatus(STATUS_7E)) { + checkBgCross(); + checkBgCrossSub(); + } + checkWater(); + if (!isStatus(STATUS_7E)) { + checkDamageBg(); + } + postBgCross(); +} + +void daPlBase_c::checkBgCross() { + if (mPowerup == POWERUP_MINI_MUSHROOM && (isOldBgCross(BGC_WALL_TOUCH_L_2) | isOldBgCross(BGC_WALL_TOUCH_R_2)) == 0) { + float dir = 1.0f; + if (mLastPos.x > mPos.x) { + dir = -1.0f; + } + const sBcPointData *wallData = getWallBgPointData(); + int wallSize = wallData->mInfMargin + wallData->mSupMargin; + float offset = ((float) wallSize / 4096.0f) / 2.0f; + mVec3_c p1( + mLastPos.x - dir * 3.0f, + mLastPos.y + offset, + mLastPos.z + ); + mVec3_c p2( + mPos.x + dir * 3.0f, + mPos.y + offset, + mPos.z + ); + float outX; + if (mBc.checkWallPlayer(&p1, &p2, &outX) && outX != p1.x) { + mPos.x = outX - dir * 3.0f; + } + } + + onStatus(STATUS_80); + u32 bgFlags = mBc.checkBgPlr(this); + offStatus(STATUS_80); + + if (isStatus(STATUS_7F)) { + return; + } + mPrevMoveSakaAngle = mMoveSakaAngle; + mPrevStillSakaAngle = mStillSakaAngle; + mStillSakaAngle = 0; + mMoveSakaAngle = 0; + mStandOnUnitType = mBc.mLastUnitType; + + if ((bgFlags & 0x3c000000) != 0) { + onNowBgCross(BGC_HEAD); + if (bgFlags & 0x4000000) { + onNowBgCross(BGC_PRESS_HEAD_HIT); + } + if (bgFlags & 0x40000000) { + onNowBgCross(BGC_63); + } + if (bgFlags & 0x80000000) { + onNowBgCross(BGC_NON_BREAK_BLOCK_HIT); + } + if (mBc.getHeadAttr() == 6) { + onNowBgCross(BGC_HANG_ROPE); + } + if (bgFlags & 0x20000000) { + onNowBgCross(BGC_BLOCK_HIT); + switch (mBc.m_c4) { + case 1: + onNowBgCross(BGC_58); + break; + case 2: + onNowBgCross(BGC_57); + break; + } + if (mBc.mpCtrFoot != nullptr && + mBc.mpCtrFoot->mpActor != nullptr && + !( + mBc.mpCtrFoot->mpActor->mProfName != fProfile::EN_HATENA_BLOCK_LINE && + mBc.mpCtrFoot->mpActor->mProfName != fProfile::EN_RENGA_BLOCK_LINE + ) + ) { + onNowBgCross(BGC_LINE_BLOCK_HIT); + } + } + } + + if (bgFlags & 0x1fe000) { + mMoveSakaAngle = mBc.getSakaAngleBySpeed(mSpeedF); + mStillSakaAngle = mBc.getSakaAngle(0); + if (bgFlags & 0x4000) { + onNowBgCross(BGC_SLOPE); + } + if (bgFlags & 0x400000) { + onNowBgCross(BGC_62); + } + if (bgFlags & 0x800000) { + onNowBgCross(BGC_54); + } + if (bgFlags & 0x1000000) { + onNowBgCross(BGC_36); + } + if (mMoveSakaAngle > 0 && isNowBgCross(BGC_HEAD)) { + onNowBgCross(BGC_SLOPE_AND_HEAD); + mSpeedF = 0.0f; + } + u16 footAttr = mBc.getFootAttr(); + switch (footAttr) { + case 3: + onNowBgCross(BGC_ON_SINK_SAND); + break; + case 7: + onNowBgCross(BGC_AUTOSLIP); + break; + case 4: + onNowBgCross(BGC_ON_BELT_R); + break; + case 5: + onNowBgCross(BGC_ON_BELT_L); + break; + } + if (mSpeed.y <= 0.0f) { + onNowBgCross(BGC_FOOT); + if (bgFlags & 0x200000) { + onNowBgCross(BGC_SEMISOLID); + } + if (bgFlags & 0x18000) { + onNowBgCross(BGC_LIFT); + } + if (mPos.y > mLastPos.y && !isNowBgCross(BGC_SLOPE)) { + onNowBgCross(BGC_GROUNDED_MOVE_UP); + } + switch (footAttr) { + case 2: + mGroundType = GROUND_TYPE_SNOW; + onNowBgCross(BGC_ON_SNOW); + break; + case 3: + case 12: + onNowBgCross(BGC_ON_SAND); + if (isNowBgCross(BGC_LIFT)) { + mGroundType = GROUND_TYPE_FUNSUI; + } else { + mGroundType = GROUND_TYPE_SAND; + } + break; + case 15: + onNowBgCross(BGC_ON_SAND); + mGroundType = GROUND_TYPE_BEACH; + break; + case 13: + mGroundType = GROUND_TYPE_DIRT; + break; + case 1: + mGroundType = GROUND_TYPE_ICE; + if (bgFlags & 0x2000000) { + onNowBgCross(BGC_ON_ICE_LOW_SLIP); + } else { + onNowBgCross(BGC_ON_ICE); + } + break; + case 8: + if (isStatus(STATUS_PENGUIN_SLIDE)) { + mVec3_c tmp( + mPos.x, + mPos.y + 4.0f, + mPos.z + ); + float groundHeight; + if (dBc_c::checkGround(&tmp, &groundHeight, mLayer, mAmiLayer, 8)) { + if (std::fabs(groundHeight - mPos.y) < 2.0f) { + onNowBgCross(BGC_CLIFF); + } + } + } else { + onNowBgCross(BGC_CLIFF); + } + break; + case 14: + mGroundType = GROUND_TYPE_CLOUD; + break; + case 11: + mGroundType = GROUND_TYPE_CARPET; + break; + } + if (isNowBgCross(BGC_LIFT)) { + if (bgFlags & 0x40000) { + mGroundType = GROUND_TYPE_MANTA; + } + if (bgFlags & 0x80000) { + mGroundType = GROUND_TYPE_LEAF; + } + if (bgFlags & 0x100000) { + mGroundType = GROUND_TYPE_WOOD; + } + } + } + } else { + if (isStatus(STATUS_RIDE_NUT_2)) { + mPos.y = mRideNutHeight; + mMoveSakaAngle = 0; + onNowBgCross(BGC_FOOT); + } + float s = getModelHeight() + mPos.y; + mVec3_c checkPos(mPos.x, s + 8.0f, mPos.z); + float groundHeight; + int groundType; + if (dBc_c::checkGround(&checkPos, &groundHeight, &groundType, mLayer, mAmiLayer, 8)) { + if (checkPos.y >= groundHeight && s <= groundHeight) { + if (groundType == 2) { + onNowBgCross(BGC_CLIFF_ABOVE_2); + } else { + onNowBgCross(BGC_CLIFF_ABOVE_1); + } + mKaniHeight = groundHeight; + } + } + } + + if (mSpeed.y < 0.0f && (isStatus(STATUS_BIG_JUMP) || isStatus(STATUS_4E))) { + onNowBgCross(BGC_LIFT); + onNowBgCross(BGC_FOOT); + onNowBgCross(BGC_37); + } + + if (bgFlags & 0x1fe000) { + onNowBgCross(BGC_37); + } else { + float groundY3; + if (dBc_c::checkGroundHalf(&mPos, &groundY3, mLayer, mAmiLayer) && (mPos.y - 16.0f < groundY3)) { + onNowBgCross(BGC_37); + } + } + + if (bgFlags & 0x100) { + onNowBgCross(BGC_61); + } + if ((bgFlags & 8) || isStatus(STATUS_1A)) { + onNowBgCross(BGC_WALL_TOUCH_L_2); + } + if ((bgFlags & 4) || isStatus(STATUS_1B)) { + onNowBgCross(BGC_WALL_TOUCH_R_2); + } + + if ((isNowBgCross(BGC_WALL_TOUCH_L_2) | isNowBgCross(BGC_WALL_TOUCH_R_2)) != 0) { + float sx = mSpeed.x; + mAdjacentSlopeAngle = mBc.mAdjacentSlopeAngle; + if (sx < 0.0f) { + if (isNowBgCross(BGC_WALL_TOUCH_L_2)) { + onNowBgCross(BGC_WALL); + } + } else if (sx > 0.0f) { + if (isNowBgCross(BGC_WALL_TOUCH_R_2)) { + onNowBgCross(BGC_WALL); + } + } else { + static const int flags[] = { 0x1, 0x2 }; + if (bgFlags & flags[mDirection]) { + onNowBgCross(BGC_WALL); + } + } + } + + if (bgFlags & 0xc0) { + dBg_ctr_c *ctrWall = mBc.mpCtrWall; + if (ctrWall) { + if (ctrWall->m_d0 & 0x800000) { + onNowBgCross(BGC_11); + } + if (ctrWall->m_c8 == 0 && *ctrWall->mRotation != 0) { + onNowBgCross(BGC_11); + } + } + if (bgFlags & 0x80) { + onNowBgCross(BGC_OBJBG_TOUCH_L); + if (isCarryObjBgCarried(1)) { + onNowBgCross(BGC_OBJBG_TOUCH_CARRIED_L); + } + } + if (bgFlags & 0x40) { + onNowBgCross(BGC_OBJBG_TOUCH_R); + if (isCarryObjBgCarried(0)) { + onNowBgCross(BGC_OBJBG_TOUCH_CARRIED_R); + } + } + } + + if (bgFlags & 0x2a) { + onNowBgCross(BGC_WALL_TOUCH_L); + } + if (bgFlags & 0x15) { + onNowBgCross(BGC_WALL_TOUCH_R); + } + if (bgFlags & 0x800) { + onNowBgCross(BGC_12); + } + if (bgFlags & 0x1000) { + onNowBgCross(BGC_13); + } + + if (isNowBgCross(BGC_ON_SINK_SAND)) { + checkSinkSand(); + } + + if (!isNowBgCross(BGC_FOOT)) { + if (mTopHeight < mPos.y) { + mTopHeight = mPos.y; + } + mAirTopHeight = mTopHeight; + } else { + mTopHeight = mPos.y; + } + + if (isNowBgCross(BGC_HEAD) && isNowBgCross(BGC_PRESS_HEAD_HIT) && !isNowBgCross(BGC_63)) { + setBgPressReq(nullptr, BG_PRESS_HEAD); + } + if (isNowBgCross(BGC_FOOT) && !isNowBgCross(BGC_LIFT)) { + setBgPressReq(nullptr, BG_PRESS_FOOT); + } + if (isNowBgCross(BGC_WALL_TOUCH_L_2) && !isNowBgCross(BGC_OBJBG_TOUCH_L)) { + setBgPressReq(nullptr, BG_PRESS_L); + } + if (isNowBgCross(BGC_WALL_TOUCH_R_2) && !isNowBgCross(BGC_OBJBG_TOUCH_R)) { + setBgPressReq(nullptr, BG_PRESS_R); + } +} + +bool daPlBase_c::isCarryObjBgCarried(u8 side) { + dBg_ctr_c *ctrWall = mBc.mpCtrWalls[side]; + if (ctrWall != nullptr) { + mVec2_c diff = ctrWall->m_a0 - ctrWall->m_ac; + set_m_d80(side, diff.x); + if (ctrWall->m_d0 & 0x800) { + dActor_c* carriedActor = ctrWall->mpActor; + if (carriedActor != nullptr && carriedActor->checkCarried(nullptr)) { + return true; + } + } + } + + return false; +} + +void daPlBase_c::postBgCross() { + if (isNowBgCross(BGC_HEAD)) { + if (mSpeed.y > 0.0f || isStatus(STATUS_4E)) { + if ( + !isOldBgCross(BGC_HEAD) && + !isNowBgCross(BGC_57) && + !isNowBgCross(BGC_63) && + !isNowBgCross(BGC_HANG_ROPE) + ) { + bool m = false; + if (mPowerup == POWERUP_MINI_MUSHROOM) { + m = true; + } + if (isNowBgCross(BGC_NON_BREAK_BLOCK_HIT)) { + startSound(SE_PLY_HIT_BLOCK_BOUND, m, false); + } else if (isNowBgCross(BGC_BLOCK_HIT)) { + if (isNowBgCross(BGC_58)) { + startSound(SE_PLY_HIT_BLOCK, m, false); + } else { + startSound(SE_PLY_HIT_GENERAL_OBJ, m, false); + } + } else { + startSound(SE_PLY_HIT_BLOCK, m, false); + } + } + } + if (mSpeed.y > 0.0f) { + mSpeed.y = 0.0f; + mNoGravityTimer = 0; + onStatus(STATUS_BF); + } + } + if (isNowBgCross(BGC_FOOT)) { + if (isNowBgCross(BGC_ON_BELT_L) | isNowBgCross(BGC_ON_BELT_R)) { + mBgPushForce = mBc.mPushForce; + } + if (isNowBgCross(BGC_WATER_SHALLOW) || isNowBgCross(BGC_HANG_ROPE)) { + mSpeed.y = 0.0f; + } else if (isNowBgCross(BGC_ON_SINK_SAND)) { + mSpeed.y = 0.0f; + mBgPushForce.set(0.0f, mBc.mPushForce.y * getSandSinkRate(), 0.0f); + } else if (isSaka() || isStatus(STATUS_30)) { + mSpeed.y = 0.0f; + } else { + mSpeed.y = -2.0f; + } + if (isStatus(STATUS_5F)) { + mSpeedF = 0.0f; + } + if (isNowBgCross(BGC_WATER_TOUCH) && !isNowBgCross(BGC_WATER_SHALLOW)) { + mGroundType = GROUND_TYPE_WATER; + } + if (!isNowBgCross(BGC_LIFT) && isNowBgCross(BGC_HEAD)) { + if (mBc.getSakaType() != 0 && mBc.getSakaUpDown(mDirection) == 1) { + if (mDirection == DIR_LR_R) { + onStatus(STATUS_1B); + } else { + onStatus(STATUS_1A); + } + mSpeedF = 0.0f; + mPos.x = mLastPos.x; + } + } + } + if (!isNowBgCross(BGC_FOOT) && !isNowBgCross(BGC_LIFT)) { + if (isOldBgCross(BGC_FOOT) && isOldBgCross(BGC_LIFT)) { + m_1134 = 0.0f; + if (std::fabs(mSpeedF) >= 0.01f && m_1eb.x * mSpeedF > 0.0f) { + m_1134 = m_1eb.x; + float add = m_1eb.x; + if (std::fabs(add) > 0.01f && std::fabs(add) < 1.0f) { + if (add > 1.0f) { + add = 1.0f; + } else { + add = -1.0f; + } + } + mPos.x += add; + } + } + } +} + +float daPlBase_c::getWaterCheckPosY() { + static const float scWaterOffsetY[] = { 4.0f, 8.0f, 16.0f }; + return mPos.y + scWaterOffsetY[getTallType(-1)]; +} + +void daPlBase_c::checkWater() { + mWaterType = dBc_c::WATER_CHECK_NONE; + mPrevWaterHeight = mWaterHeight; + mWaterHeight = dBg_c::m_bg_p->m_8fe00; + u8 waterCheck = dBc_c::checkWater(mPos.x, mPos.y, mLayer, &mWaterHeight); + if (waterCheck != dBc_c::WATER_CHECK_NONE && mPos.y <= mWaterHeight) { + onNowBgCross(BGC_WATER_TOUCH); + if (waterCheck == dBc_c::WATER_CHECK_WATER_BUBBLE) { + onNowBgCross(BGC_WATER_BUBBLE); + } + } + if (waterCheck == dBc_c::WATER_CHECK_NONE || waterCheck == dBc_c::WATER_CHECK_WATER_BUBBLE) { + waterCheck = dBc_c::checkWater(mPos.x, getWaterCheckPosY(), mLayer, &mWaterHeight); + if (waterCheck != dBc_c::WATER_CHECK_WATER_BUBBLE) { + return; + } + onNowBgCross(BGC_WATER_SHALLOW); + onNowBgCross(BGC_WATER_SUBMERGED); + } + switch (waterCheck) { + case dBc_c::WATER_CHECK_WATER_BUBBLE: { + onNowBgCross(BGC_WATER_BUBBLE); + mVec2_c pos; + dBc_c::getAirWaterHitPos(&pos); + mAirWaterHitPos.set(pos.x, pos.y, mPos.z); + short s; + dBc_c::getAirWaterHitAngle(&s); + mAirWaterHitAngle = s; + break; + } + case dBc_c::WATER_CHECK_WATER: { + if (getWaterCheckPosY() <= mWaterHeight) { + onNowBgCross(BGC_WATER_SHALLOW); + } + const sBcPointData *p = getHeadBgPointData(); + float f = p->mOffset; + if (mPos.y + f / 4096.0f <= mWaterHeight) { + onNowBgCross(BGC_WATER_SUBMERGED); + } + mWaterDepth = dBc_c::checkWaterDepth(mPos.x, mWaterHeight, mLayer, mAmiLayer, nullptr); + break; + } + case dBc_c::WATER_CHECK_YOGAN: + case dBc_c::WATER_CHECK_POISON: + if (!isStatus(STATUS_7E)) { + mWaterType = waterCheck; + } + break; + } +} + +void daPlBase_c::checkDamageBg() { + if (isStatus(STATUS_OUT_OF_PLAY) || + isStatus(STATUS_STUNNED) || + isStatus(STATUS_53) || + isStatus(STATUS_GOAL_POLE_NOT_GOAL_NO_MOVE) + ) { + return; + } + if (!isDemoAll() || isDemoType(DEMO_KINOPIO)) { + mIsBgDamage = mBc.m_e0; + mBgDamageType = mBc.m_e1; + switch (mWaterType) { + case dBc_c::WATER_CHECK_YOGAN: + mIsBgDamage = 1; + mBgDamageType = 7; + break; + case dBc_c::WATER_CHECK_POISON: + mIsBgDamage = 1; + mBgDamageType = 8; + break; + } + } +} + +bool daPlBase_c::setBgDamage() { + if (mIsBgDamage) { + mIsBgDamage = false; + DamageType_e damageType = DAMAGE_BG; + switch (mBgDamageType) { + case 7: + damageType = DAMAGE_YOGAN; + break; + case 8: + damageType = DAMAGE_POISON; + break; + case 9: + damageType = DAMAGE_SQUISH; + break; + } + if (damageType == DAMAGE_BG && isNoDamage()) { + return false; + } + return setDamage2(nullptr, damageType); + } + return false; +} + +bool daPlBase_c::checkSinkSand() { + mVec3_c pos = mPos; + pos.y += 128.0f; + if (dBc_c::checkGround(&pos, &mSinkSandHeight, mLayer, mAmiLayer, 3)) { + if (mSinkSandHeight > mPos.y) { + onNowBgCross(BGC_ON_SINK_SAND); + } + if (mSinkSandHeight > getCenterPos().y) { + onNowBgCross(BGC_IN_SINK_SAND); + } + if (mSinkSandHeight > mPos.y + getModelHeight()) { + onNowBgCross(BGC_INSIDE_SINK_SAND); + } + return true; + } + return false; +} + + +bool daPlBase_c::checkBGCrossWall(u8 direction) { + static const BgCross1_e flags[] = { BGC_WALL_TOUCH_R_2, BGC_WALL_TOUCH_L_2 }; + return isNowBgCross(flags[direction]); +} + +void daPlBase_c::checkSideViewLemit() { + if (!daPyDemoMng_c::mspInstance->m_94 && isDemoType(DEMO_PLAYER)) { + return; + } + if (isStatus(STATUS_53) || isStatus(STATUS_GOAL_POLE_NOT_GOAL_NO_MOVE) || isStatus(STATUS_8D)) { + return; + } + if (dScStage_c::m_loopType == 0) { + float tmpL = dBg_c::m_bg_p->getLeftLimit() + mViewLimitPadding; + if (mPos.x <= tmpL) { + calcSideLimitMultL(tmpL); + } + float tmpR = dBg_c::m_bg_p->getRightLimit() - mViewLimitPadding; + if (mPos.x >= tmpR) { + calcSideLimitMultR(tmpR); + } + } + checkDispSideLemit(); +} + +bool daPlBase_c::revSideLimitCommon(float limitX) { + if (mPos.x != limitX) { + u8 dir = 0; + if (mPos.x <= limitX) { + dir = 1; + } + if (!isStatus(STATUS_7E)) { + u16 ang = mBc.getSakaMoveAngle(dir); + if (ang != 0) { + mPos.y += (limitX - mPos.x) * (mAng(ang).sin() / mAng(ang).cos()); + } + } + mPos.x = limitX; + return true; + } + return false; +} + +bool daPlBase_c::calcSideLimitMultL(float limitX) { + onNowBgCross(BGC_SIDE_LIMIT_L); + revSideLimitCommon(limitX); + if (mSpeedF < 0.0f) { + if (mDirection == 1) { + mSpeedF = -0.01f; + } else { + mSpeedF = 0.0f; + } + return true; + } + return false; +} + +bool daPlBase_c::calcSideLimitMultR(float limitX) { + onNowBgCross(BGC_SIDE_LIMIT_R); + revSideLimitCommon(limitX); + if (mSpeedF > 0.0f) { + if (mDirection == 0) { + mSpeedF = 0.01f; + } else { + mSpeedF = 0.0f; + } + return true; + } + return false; +} + +bool daPlBase_c::checkDispSideLemit() { + if (isStatus(STATUS_B8) || isStatus(STATUS_81)) { + return false; + } + if (dScStage_c::m_loopType == 1) { + return false; + } + float dispX = dBgParameter_c::ms_Instance_p->getLoopScrollDispPosX(mPos.x); + float leftLimit = dispX + mViewLimitPadding; + float rightLimit = dispX + dBgParameter_c::ms_Instance_p->xSize() - mViewLimitPadding + 1.0f; + switch (mIsDispLimitL) { + case 0: + if (mPos.x < leftLimit) { + if (isOldBgCross(BGC_OBJBG_TOUCH_CARRIED_R) || !isOldBgCross(BGC_WALL_TOUCH_R_2)) { + calcSideLimitMultL(leftLimit); + return true; + } + mIsDispLimitL = 1; + mDispLimitAdjL = mPos.x - leftLimit; + } + break; + case 1: { + if (mPos.x > leftLimit) { + mIsDispLimitL = 0; + } + float diff = mPos.x - leftLimit; + if (mDispLimitAdjL < diff || isOldBgCross(BGC_WALL_TOUCH_R_2)) { + mDispLimitAdjL = diff; + } + if (mPos.x < leftLimit + mDispLimitAdjL) { + calcSideLimitMultL(leftLimit + mDispLimitAdjL); + return true; + } + break; + } + } + switch (mIsDispLimitR) { + case 0: + if (mPos.x > rightLimit) { + if (isOldBgCross(BGC_OBJBG_TOUCH_CARRIED_L) || !isOldBgCross(BGC_WALL_TOUCH_L_2)) { + calcSideLimitMultR(rightLimit); + return true; + } + mIsDispLimitR = 1; + mDispLimitAdjR = mLastPos.x - rightLimit; + } + break; + case 1: { + if (mPos.x < rightLimit) { + mIsDispLimitR = 0; + } + float diff = mPos.x - rightLimit; + if (mDispLimitAdjR > diff || isOldBgCross(BGC_WALL_TOUCH_L_2)) { + mDispLimitAdjR = diff; + } + if (mPos.x > rightLimit + mDispLimitAdjR) { + calcSideLimitMultR(rightLimit + mDispLimitAdjR); + return true; + } + } + } + return false; +} + +void daPlBase_c::calcDispSideLimit() { + if (dBg_c::m_bg_p->mAutoscrolls[0].mActive) { + return; + } + float dispX = dBgParameter_c::ms_Instance_p->getLoopScrollDispPosX(mPos.x); + float leftLimit = dispX + mViewLimitPadding; + float rightLimit = dispX + dBgParameter_c::ms_Instance_p->xSize() - mViewLimitPadding + 1.0f; + if (mPos.x < leftLimit) { + mIsDispLimitL = 1; + mDispLimitAdjL = mPos.x - leftLimit; + } + if (mPos.x > rightLimit) { + mIsDispLimitR = 1; + mDispLimitAdjR = mLastPos.x - rightLimit; + } +} + +void daPlBase_c::underOverCheck() { + float tmp = dBgParameter_c::ms_Instance_p->yStart() - dBgParameter_c::ms_Instance_p->ySize(); + float bgTop = tmp - 24.0f; + float selfTop = mPos.y + getVisOffsetY() + getVisSizeY(); + int cond = 0; + if (isItemKinopio()) { + cond = 1; + } + if (!dBg_c::m_bg_p->mAutoscrolls[0].mActive) { + if (dBg_c::m_bg_p->m_90009 == 1 || dBg_c::m_bg_p->m_90009 == 3 || daPyMng_c::mNum > 1) { + cond = true; + } + } + if (cond == 1) { + if (selfTop < bgTop && selfTop < dBg_c::m_bg_p->m_8fe00) { + setFallDownDemo(); + } + } else if (selfTop < bgTop) { + setFallDownDemo(); + } +} + +void daPlBase_c::checkDispOver() { + offStatus(STATUS_DISPLAY_OUT_DEAD); + offStatus(STATUS_DISPLAY_OUT_NO_DAMAGE); + offStatus(STATUS_ITEM_KINOPIO_DISPLAY_OUT); + if (isStatus(STATUS_OUT_OF_PLAY) || isStatus(STATUS_53)) { + return; + } + if (!isStatus(STATUS_7E)) { + float adj = dBgParameter_c::ms_Instance_p->yStart() + 96.0f; + if (dScStage_c::m_instance->mCurrWorld == WORLD_1 && + dScStage_c::m_instance->mCurrCourse == STAGE_CASTLE && + dScStage_c::m_instance->mCurrFile == 0 + ) { + adj = dBgParameter_c::ms_Instance_p->yStart() + 192.0f; + } + if (mPos.y > adj) { + mPos.y = adj; + } + underOverCheck(); + checkPressBg(); + mBgPressActive = 0; + setBgDamage(); + } + checkDisplayOutDead(); +} + +void daPlBase_c::checkDisplayOutDead() { + float offset = 20.0f; + if (daPyMng_c::mNum > 1 || dBg_c::m_bg_p->m_90009 == 1 || dBg_c::m_bg_p->m_90009 == 3) { + offset = 64.0f; + } + + float bgBottom = dBgParameter_c::ms_Instance_p->yStart() - dBgParameter_c::ms_Instance_p->ySize(); + float bgSide1 = bgBottom - 16.0f; + float bgSide2 = bgBottom - offset; + float edgePos = mPos.y + getVisOffsetY() + getVisSizeY(); + if (edgePos < bgSide1) { + onStatus(STATUS_DISPLAY_OUT_DEAD); + onStatus(STATUS_DISPLAY_OUT_NO_DAMAGE); + if (isItemKinopio()) { + onStatus(STATUS_ITEM_KINOPIO_DISPLAY_OUT); + } + } + if (edgePos < bgSide2) { + setBalloonInDispOut(3); + } + + float bgTop = dBgParameter_c::ms_Instance_p->yStart(); + bgSide1 = bgTop + 16.0f; + edgePos = mPos.y + getVisOffsetY() - getVisSizeY(); + if (edgePos > bgSide1) { + onStatus(STATUS_DISPLAY_OUT_DEAD); + } + + if (isItemKinopio() && edgePos > dBgParameter_c::ms_Instance_p->yStart() + 128.0f) { + onStatus(STATUS_ITEM_KINOPIO_DISPLAY_OUT); + } + if (isStatus(STATUS_81)) { + return; + } + + offset = 0.0f; + if (!isStatus(STATUS_B8)) { + if (dBg_c::m_bg_p->mAutoscrolls[0].mActive && dBg_c::m_bg_p->m_9008e != 4) { + offset = -(mWallBcData.mOffset / 4096.0f - 1.0f + getVisSizeX()); + } else if (daPyMng_c::mNum > 1) { + offset = 16.0f; + } + } + + float bgLeft = dBgParameter_c::ms_Instance_p->getLoopScrollDispPosX(mPos.x); + bgSide1 = bgLeft - 16.0f; + bgSide2 = bgLeft - offset; + edgePos = mPos.x + getVisOffsetX() + getVisSizeX(); + if (edgePos < bgSide1) { + onStatus(STATUS_DISPLAY_OUT_DEAD); + onStatus(STATUS_DISPLAY_OUT_NO_DAMAGE); + if (isItemKinopio()) { + onStatus(STATUS_ITEM_KINOPIO_DISPLAY_OUT); + } + } + if (edgePos < bgSide2) { + setBalloonInDispOut(2); + } + + bgSide1 = bgLeft + dBgParameter_c::ms_Instance_p->xSize() + 16.0f; + bgSide2 = bgLeft + dBgParameter_c::ms_Instance_p->xSize() + offset; + edgePos = mPos.x + getVisOffsetX() - getVisSizeX(); + if (edgePos > bgSide1) { + onStatus(STATUS_DISPLAY_OUT_DEAD); + onStatus(STATUS_DISPLAY_OUT_NO_DAMAGE); + if (isItemKinopio()) { + onStatus(STATUS_ITEM_KINOPIO_DISPLAY_OUT); + } + } + if (edgePos > bgSide2) { + setBalloonInDispOut(0); + } +} + +void daPlBase_c::setBgPressReq(dActor_c *actor, BgPress_e i) { + mBgPressActive |= (1 << i); + if (actor != nullptr) { + mBgPressIDs[i] = actor->mUniqueID; + } else { + mBgPressIDs[i] = BASE_ID_NULL; + } +} + +bool daPlBase_c::isBgPress(dActor_c *actor) { + u32 param = mBgPressFlags; + if (param == 0) { + return false; + } + for (int i = 1; i < BG_PRESS_COUNT; i++) { + if (param & (1 << i) && mBgPressIDs[i] == actor->getID()) { + return true; + } + } + return false; +} + +bool daPlBase_c::setPressBgDamage(int i1, int i2) { + if (i1 == DAMAGE_SQUISH) { + if (setDamage2(nullptr, DAMAGE_SQUISH)) { + mBc.clearBgcSaveAll(); + return true; + } + } else { + if (setDamage2(nullptr, DAMAGE_DEFAULT)) { + mBc.clearBgcSaveAll(); + dQuake_c::m_instance->shockMotor(mPlayerNo, dQuake_c::TYPE_4, 0, false); + return true; + } + } + return false; +} + +bool daPlBase_c::isEnablePressUD() { + dBg_ctr_c *ctrHead = mBc.mpCtrHead; + dBg_ctr_c *ctrFoot = mBc.mpCtrFoot; + if (ctrHead != nullptr && ctrFoot != nullptr) { + if (ctrHead == ctrFoot || ctrHead->m_e0 == ctrFoot->m_e0) { + return false; + } + } + return true; +} + +bool daPlBase_c::isEnablePressLR() { + dBg_ctr_c *ctrL = mBc.mpCtrWalls[1]; + dBg_ctr_c *ctrR = mBc.mpCtrWalls[0]; + if (ctrL != nullptr && ctrR != nullptr) { + if (ctrL == ctrR || ctrL->m_e0 == ctrR->m_e0) { + return false; + } + } + return true; +} + +bool daPlBase_c::checkPressBg() { + if ( + (isNowBgCross(BGC_SIDE_LIMIT_L) && isNowBgCross(BGC_WALL_TOUCH_R_2)) || + (isNowBgCross(BGC_SIDE_LIMIT_R) && isNowBgCross(BGC_WALL_TOUCH_L_2)) + ) { + return true; + } + if (dScStage_c::m_instance->mCurrWorld == WORLD_6 && + dScStage_c::m_instance->mCurrCourse == STAGE_CASTLE && + dScStage_c::m_instance->mCurrFile == 1 && + mPos.y >= -1420.0f + ) { + if (setPressBgDamage(DAMAGE_SQUISH, 1)) { + mBgPressFlags |= 0x8; + return true; + } + } + if (mBgPressActive & 0x20a && mBgPressActive & 0x414 && isEnablePressUD()) { + if (mBgPressActive & 0x18 && setPressBgDamage(DAMAGE_SQUISH, 1)) { + if (mBgPressActive & 0x8) { + mBgPressFlags |= 0x8; + } + if (mBgPressActive & 0x10) { + mBgPressFlags |= 0x10; + } + return true; + } + if (mBgPressActive & 6 && setPressBgDamage(DAMAGE_BG, 1)) { + if (mBgPressActive & 2) { + mBgPressFlags |= 0x2; + } + if (mBgPressActive & 4) { + mBgPressFlags |= 0x4; + } + return true; + } + } + if (isStatus(STATUS_PENGUIN_SLIDE)) { + return false; + } + if (mBgPressActive & 0x1140 && mBgPressActive & 0x8a0 && isEnablePressLR()) { + if (mBgPressActive & 0x60 && setPressBgDamage(DAMAGE_SQUISH, 0)) { + if (mBgPressActive & 0x20) { + mBgPressFlags |= 0x20; + } + if (mBgPressActive & 0x40) { + mBgPressFlags |= 0x40; + } + return true; + } + if (mBgPressActive & 0x180 && setPressBgDamage(DAMAGE_BG, 0)) { + if (mBgPressActive & 0x80) { + mBgPressFlags |= 0x80; + } + if (mBgPressActive & 0x100) { + mBgPressFlags |= 0x100; + } + return true; + } + } + return false; +} + +void daPlBase_c::setAutoBounce() { + onStatus(STATUS_AUTO_BOUNCE); +} + +bool daPlBase_c::isRideCheckEnable() { + if (mSpeed.y > 0.0f) { + return false; + } + if (isStatus(STATUS_4E)) { + dActor_c *rideActor = (dActor_c *) fManager_c::searchBaseByID(mRideActorID); + if (rideActor != nullptr && rideActor->mSpeed.y > 0.0f) { + return false; + } + } + return true; +} + +void daPlBase_c::setExtraPushForce(float f) { + onStatus(STATUS_EXTRA_PUSH_FORCE); + mExtraPushForceX = f; +} + +bool daPlBase_c::checkInsideCrossBg(float f) { + const sBcPointData *wallBg = getWallBgPointData(); + if (wallBg == nullptr) { + return false; + } + const sBcPointData *footBg = getFootBgPointData(); + if (footBg == nullptr) { + return false; + } + float offs2[] = { + footBg->mInfMargin / 4096.0f + f, + footBg->mSupMargin / 4096.0f - f + }; + float offs[] = { + wallBg->mInfMargin / 4096.0f, + wallBg->mSupMargin / 4096.0f + }; + for (int i = 0; i < 2; i++) { + mVec3_c modPos = mVec3_c( + mPos.x, + mPos.y + offs[i], + mPos.z + ); + mVec3_c copy; + copy.set( + modPos.x + offs2[0], + modPos.y, + modPos.z + ); + if (mBc.checkWallPlayer(&modPos, ©, nullptr)) { + return true; + } + copy.set( + modPos.x + offs2[1], + modPos.y, + modPos.z + ); + if (mBc.checkWallPlayer(&modPos, ©, nullptr)) { + return true; + } + } + return false; +} + +void daPlBase_c::setPowerup(PLAYER_POWERUP_e powerup, int) { + mPowerup = powerup; +} + +bool daPlBase_c::isMameAction() { + if (mPowerup == POWERUP_MINI_MUSHROOM && !isLiftUpExceptMame()) { + return true; + } + return false; +} + +void daPlBase_c::setStatus(int id) { + mStatusFlags[id / 32] = (1 << (id % 32)); +} + +void daPlBase_c::onStatus(int id) { + mStatusFlags[id / 32] |= (1 << (id % 32)); +} + +void daPlBase_c::offStatus(int id) { + mStatusFlags[id / 32] &= ~(1 << (id % 32)); +} + +bool daPlBase_c::isStatus(int id) { + return mStatusFlags[id / 32] & (1 << (id % 32)); +} + +u8 daPlBase_c::getTallType(s8) { + return 2; +} + +void daPlBase_c::calcTimerProc() { + if (sLib::calcTimer(&mDamageInvulnTimer) != 0) { + if (mDamageInvulnTimer < 60) { + if (mDamageInvulnTimer & 4) { + onStatus(STATUS_INVULNERABLILITY_BLINK); + } + } else if (mDamageInvulnTimer & 8) { + onStatus(STATUS_INVULNERABLILITY_BLINK); + } + } + + sLib::calcTimer(&mPowerupChangeInvulnTimer); + sLib::calcTimer(&mTimer_ce8); + sLib::calcTimer(&mNoGravityTimer); + sLib::calcTimer(&mTimer_a8); + sLib::calcTimer(&mSquishNoMoveTimer); + sLib::calcTimer(&mSquishCooldownTimer); + sLib::calcTimer(&mJumpDaiFallTimer); + sLib::calcTimer(&mCcRevDisabledTimer); + sLib::calcTimer(&mBossDemoLandTimer); + sLib::calcTimer(&mTimer_f4); + sLib::calcTimer(&mSlipEndTimer); + + updateNoHitPlayer(); + calcNoHitObjBgTimer(); +} + +dPyMdlBase_c * daPlBase_c::getModel() { + return mpMdlMng->mpMdl; +} + +void daPlBase_c::calcPlayerSpeedXY() { + static const float ratios[] = { 0.6f, 0.55f, 0.5f, 0.45f, 0.4f }; + float extraXAccel = 0.0f; + float ccRevShiftX = 0.0f; + bool x = calcCcPlayerRev(&ccRevShiftX); + + float c = 1.0f; + float b = mMaxSpeedF; + + if (isStatus(STATUS_FOLLOW_MAME_KURIBO)) { + int v = getFollowMameKuribo() - 1; + + if (v < 0) { + v = 0; + } + if (v > 4) { + v = 4; + } + + b = mMaxSpeedF * ratios[v]; + } + + if (x) { + if (b < -0.5f) { + b = -0.5f; + } + if (b > 0.5f) { + b = 0.5f; + } + if (std::fabs(mSpeedF) > std::fabs(b)) { + c = 1.0f; + } else { + c = 1.8f; + } + } + + sLib::chase(&mSpeedF, b, mAccelF * c); + calcWindSpeed(); + + float d = 5.0f; + if (isStatus(STATUS_88)) { + if (std::fabs(b) > 5.0f) { + d = std::fabs(b); + } + } + + float f = mSpeedF + mWindSpeed; + if (f < -d) { + f = -d; + } else if (f > d) { + f = d; + } + + mSpeed.x = f; + + if (f * ccRevShiftX >= 0.0f) { + mVec3_c wallvec1(mPos.x + f + ccRevShiftX, mPos.y + getModelHeight() / 2.0f, mPos.z); + mVec3_c wallvec2(wallvec1.x + f + ccRevShiftX, wallvec1.y, wallvec1.z); + + float g; + + if (dBc_c::checkWall(&wallvec1, &wallvec2, &g, mLayer, mAmiLayer, nullptr)) { + ccRevShiftX = 0.0f; + } + } + + extraXAccel += ccRevShiftX; + + if (mFinalAirPushForceX != 0.0f) { + if (!isNowBgCross(BGC_FOOT)) { + extraXAccel += mFinalAirPushForceX; + } else { + if (mFinalAirPushForceX * mSpeedF < 0.0f) { + mSpeedF += mFinalAirPushForceX; + } + mFinalAirPushForceX = 0.0f; + } + } + + if (m_1138 != 0.0f) { + if (!isNowBgCross(BGC_FOOT)) { + extraXAccel += m_1138; + sLib::chase(&m_1138, 0.0f, m_113c); + } else { + m_1138 = 0.0f; + } + } + + if (isNowBgCross(BGC_FOOT) && isStatus(STATUS_5F)) { + mSpeedF = 0.0f; + } + mPrevSpeedF = mSpeedF; + + float k = mMaxFallSpeed; + if (isNowBgCross(BGC_ON_SINK_SAND) | isNowBgCross(BGC_IN_SINK_SAND)) { + k = 0.0f; + } + + setSandEffect(); + + mPos += mVec3_c(mBgPushForce.x, mBgPushForce.y, mBgPushForce.z); + + mPrevSpeedY = mSpeed.y; + mSpeed.y += mAccelY; + + if (mSpeed.y < k) { + mSpeed.y = k; + } + + mVec3_c speed( + mSpeed.x + extraXAccel, + mSpeed.y, + mSpeed.z + ); + + posMoveAnglePlayer(speed); +} + +void daPlBase_c::posMoveAnglePenguin(mVec3_c a, unsigned short b) { + mVec3_c _40(0.0f, a.y, 0.0f); + + if (isNowBgCross(BGC_HEAD) && (_40.y > 0.0f)) { + mAng angle = mBc.getHeadSakaMoveAngle(mDirection); + + if (angle.mAngle > 0) { + _40.x = sc_DirSpeed[mDirection] * std::fabs(a.y * angle.sin()); + } + + _40.y = a.y * std::fabs(angle.cos()); + } + + if (isNowBgCross(BGC_FOOT) && (a.y < 0.0f)) { + mAng angle = mBc.getSakaMoveAngle(mDirection); + + if (angle.mAngle < 0) { + _40.x = sc_DirSpeed[mDirection] * std::fabs(a.y * angle.sin()); + } + + _40.y = a.y * std::fabs(angle.cos()); + } + + float x_mag = std::fabs(a.x); + + mVec3_c delta( + _40.x + x_mag * mAng(b).cos(), + _40.y + x_mag * mAng(b).sin(), + a.z + ); + + posMove(delta); +} + +void daPlBase_c::posMoveAnglePlayer(mVec3_c a) { + if ( + ((a.x > 0.0f && isNowBgCross(BGC_WALL_TOUCH_R_2)) || (a.x < 0.0f && isNowBgCross(BGC_WALL_TOUCH_L_2))) && + (std::fabs(a.x) > 2.5f) + ) { + if (a.x > 0.0f) { + a.x = 2.5f; + } else { + a.x = -2.5f; + } + } + + u8 dir = 0; + if (a.x < 0.0f) { + dir = 1; + } + + u16 x = mBc.getSakaMoveAngle(dir); + if (isNowBgCross(BGC_HEAD)) { + x = mBc.getHeadSakaMoveAngle(dir); + } + + if (isStatus(STATUS_PENGUIN_SWIM)) { + posMoveAnglePenguin(a, x); + return; + } + + u16 x2 = 0; + if (isStatus(STATUS_WALL_SLIDE)) { + x2 = mAdjacentSlopeAngle; + } + + float x_mag = std::fabs(a.x); + float y = a.y; + + mVec3_c delta( + x_mag * mAng(x).cos() - y * mAng(x2).sin(), + x_mag * mAng(x).sin() + y * std::fabs(mAng(x2).cos()), + a.z + ); + + posMove(delta); +} + +const sSpeedData *daPlBase_c::getSpeedData() { + if (isStar()) { + return mSpeedDataStar; + } else { + return mSpeedDataNormal; + } +} + +void daPlBase_c::setZPosition() { + if (isStatus(STATUS_99)) { + return; + } + + if ((mAmiLayer == 1) && (mLayer == 0)) { + mPos.z = 3000.0f - (float) (mPlayerLayer * 32); + } else { + mPos.z = -1800.0f - (float) (mPlayerLayer * 32); + } +} + +void daPlBase_c::setZPosition(float a) { + onStatus(STATUS_99); + mPos.z = a - (float) (mPlayerLayer * 32); +} + +void daPlBase_c::setZPositionDirect(float a) { + onStatus(STATUS_99); + mPos.z = a; +} + +void daPlBase_c::offZPosSetNone() { + offStatus(STATUS_99); +} + +float daPlBase_c::setJumpAddSpeedF(float a) { + if (isNowBgCross(BGC_FOOT)) { + return a; + } + + if (a >= 2.0f) { + a = 2.0f; + } + + if (a <= -2.0f) { + a = -2.0f; + } + + mFinalAirPushForceX = a; + return a; +} + +float daPlBase_c::setAddLiftSpeedF() { + float t = mExtraPushForceX; + + if (isStatus(STATUS_EXTRA_PUSH_FORCE)) { + t = mExtraPushForceX * 0.4f; + } + + return setJumpAddSpeedF(mBgPushForce.x + t); +} + +bool daPlBase_c::setDelayHelpJump() { + if (mKey.triggerJump() && std::fabs(mSpeedF) > 1.3f) { + bool x = false; + + if (mBgFootHistory[0]) { + x = true; + } else if (mBgFootHistory[1]) { + x = true; + } + + if (x && startJump(BLEND_DEFAULT, 1)) { + return true; + } + } + return false; +} + +bool daPlBase_c::startJump(AnmBlend_e blendMode, int jumpType) { + if (isNowBgCross(BGC_WATER_SHALLOW) || isStatus(STATUS_AUTO_BOUNCE)) { + return false; + } + + if (isNowBgCross(BGC_HEAD) && !isNowBgCross(BGC_LINE_BLOCK_HIT)) { + return false; + } + + if ((mpMdlMng->mpMdl->mFlags & 1) && checkStandUpRoofOnLift()) { + return setCrouchJump(); + } + + if (mKey.triggerJump()) { + daPlBase_c::jmpInf_c info(0.0f, jumpType, blendMode); + changeState(StateID_Jump, &info); + return true; + } + + return false; +} + +bool daPlBase_c::checkJumpTrigger() { + if (isNowBgCross(BGC_FOOT) && !isNowBgCross(BGC_CLIFF)) { + if (startJump(BLEND_DEFAULT, 1)) { + return true; + } + } + return false; +} + +bool daPlBase_c::isNoDamage() { + return false; +} + +bool daPlBase_c::setDamage(dActor_c *, daPlBase_c::DamageType_e) { + return false; +} + +bool daPlBase_c::setForcedDamage(dActor_c *, daPlBase_c::DamageType_e) { + return false; +} + +bool daPlBase_c::setDamage2(dActor_c *, daPlBase_c::DamageType_e) { + return false; +} + +bool daPlBase_c::setJump(float jumpSpeed, float speedF, bool allowSteer, int keyMode, int jumpMode) { + return false; +} + +bool daPlBase_c::_setJump(float jumpSpeed, float speedF, bool allowSteer, int keyMode, int jumpMode) { + return false; +} + +bool daPlBase_c::setWaitJump(float jumpSpeed) { + if (isDemo() || isStatus(STATUS_OUT_OF_PLAY)) { + return false; + } + + mSpeedF = 0.0f; + mSpeed.y = jumpSpeed; + changeState(StateID_WaitJump); + return true; +} + +bool daPlBase_c::setSwimSpeed(float a, float b) { + return false; +} + +void daPlBase_c::onFollowMameKuribo() { + onStatus(STATUS_FOLLOW_MAME_KURIBO); + mNewFollowMameKuribo++; +} + +void daPlBase_c::clearFollowMameKuribo() { + offStatus(STATUS_FOLLOW_MAME_KURIBO); + mFollowMameKuribo = mNewFollowMameKuribo; + mNewFollowMameKuribo = 0; +} + +u32 daPlBase_c::getFollowMameKuribo() { + return mFollowMameKuribo; +} + +bool daPlBase_c::isMaskDraw() { + if (isStatus(STATUS_53) || isStatus(STATUS_64)) { + return false; + } + return true; +} + +void daPlBase_c::setRideNat(float nutHeight) { + onStatus(STATUS_RIDE_NUT); + mRideNutHeight = nutHeight; +} + +void daPlBase_c::updateRideNat() { + if (isStatus(STATUS_RIDE_NUT) && mSpeed.y <= 0) { + if (!isStatus(STATUS_RIDE_NUT_2) && mPos.y <= mRideNutHeight) { + onStatus(STATUS_RIDE_NUT_2); + } + } else { + offStatus(STATUS_RIDE_NUT_2); + } +} + +bool daPlBase_c::suppressSound(int suppressionMode) { + if (suppressionMode == 1 && isStatus(STATUS_ENDING_DANCE_AUTO)) { + return true; + } + + if (isStatus(STATUS_ABOUT_TO_BE_DELETED)) { + return true; + } + + return false; +} + +void daPlBase_c::startSound(ulong soundID, bool b) { + if (!suppressSound(b)) { + mSndObj.startSound(soundID, 0); + } +} + +void daPlBase_c::startSound(ulong soundID, short s, bool b) { + if (!suppressSound(b)) { + mSndObj.startSound(soundID, s, 0); + } +} + +void daPlBase_c::holdSound(ulong soundID, bool b) { + if (!suppressSound(b)) { + mSndObj.holdSound(soundID, 0); + } +} + +void daPlBase_c::holdSound(ulong soundID, short s, bool b) { + if (!suppressSound(b)) { + mSndObj.holdSound(soundID, s, 0); + } +} + +void daPlBase_c::startPlayerVoice(int a, int b) { + if (!suppressSound(b)) { + mSndObj.fn_8019AAB0(a, 0); + } +} + +void daPlBase_c::holdPlayerVoice(int a, int b) { + if (!suppressSound(b)) { + mSndObj.fn_8019ABB0(a, 0); + } +} + +void daPlBase_c::startFootSoundPlayer(unsigned long a) { + if (!suppressSound(1)) { + mSndObj.startFootSound(a, std::fabs(mSpeedF), 0); + } +} + +void daPlBase_c::setItemCompleteVoice() { + startPlayerVoice(VOICE_ITEM_COMPLETE, 0); +} + +void daPlBase_c::setStar(daPlBase_c::StarSet_e, int) {} + +void daPlBase_c::clearTreadCount() { + mTreadCount = 0; +} + +s8 daPlBase_c::calcTreadCount(int max) { + if (mTreadCount < max) { + mTreadCount++; + } + + return mTreadCount; +} + +void daPlBase_c::clearStarCount() { + mStarCount = 0; +} + +s8 daPlBase_c::calcStarCount(int max) { + if (isStar() && mStarCount < max) { + mStarCount++; + } + + return mStarCount; +} + +void daPlBase_c::clearComboCount() { + mPlComboCount = 0; +} + +s8 daPlBase_c::calcComboCount(int max) { + if (mPlComboCount < max) { + mPlComboCount++; + } + return mPlComboCount; +} + +void daPlBase_c::startQuakeShock(dQuake_c::TYPE_SHOCK_e arg) { + dQuake_c::m_instance->shockMotor(mPlayerNo, arg, 0, false); +} + +void daPlBase_c::startPatternRumble(const char *pattern) { + if (dRemoconMng_c::m_instance->mRemocons[mPlayerNo]->mIsRumbleEnabled) { + mPad::g_core[dRemoconMng_c::m_instance->mRemocons[mPlayerNo]->mControllerID]->startPatternRumble(pattern, 0, false); + } +} + +mVec3_c daPlBase_c::getAnkleCenterPos() { + mVec3_c joint7Pos; + mVec3_c joint4Pos; + + mpMdlMng->mpMdl->getJointPos(&joint4Pos, 4); + mpMdlMng->mpMdl->getJointPos(&joint7Pos, 7); + + return (joint4Pos + joint7Pos) / 2.0f; +} + +void daPlBase_c::calcHeadAttentionAngle() { + if (isStatus(STATUS_NO_ANIM)) { + return; + } + + mAng3_c angle( + mAng(0), + mpMdlMng->getAng().y, + mpMdlMng->getAng().z + ); + + if (!isLiftUp() && !isStatus(STATUS_94) && !isStatus(STATUS_WAS_TWIRL)) { + if ((mpMdlMng->mpMdl->mFlags & 0x80) || (mpMdlMng->mpMdl->mFlags & 0x100)) { + mAng r31 = mAngle.y; + mAng r30 = 0; + bool cond = false; + daPlBase_c *pdVar10 = nullptr; + + if (mpMdlMng->mpMdl->mFlags & 0x100) { + if (isStatus(STATUS_95)) { + pdVar10 = (daPlBase_c *) dAttention_c::mspInstance->searchPlayer(this, mpMdlMng->getHatPos()); + } + } else { + pdVar10 = (daPlBase_c *) dAttention_c::mspInstance->search(mpMdlMng->getHatPos()); + } + + if (pdVar10 != nullptr) { + mVec3_c hatPos = mpMdlMng->getHatPos(); + mVec3_c _60 = mVec3_c( + pdVar10->getLookatPos().x - hatPos.x, + pdVar10->getLookatPos().y - hatPos.y, + 8.0f + ); + + int tmp = cM::atan2s(_60.y, _60.xzLen()); + short r27 = -tmp; + short r4 = 0x2000; + + if (pdVar10->mAttentionFlags & 2) { + r4 = 0xC00; + } + + if (r27 > r4) { + r27 = r4; + } + + int neg = -r4; + if (r27 < neg) { + r27 = neg; + } + + int temp = cM::atan2s(_60.x, _60.z); + short iVar2 = (temp - mAngle.y.mAngle); + + if (pdVar10->mAttentionMode == 3) { + mpMdlMng->mpMdl->m_204 = 2; + + int r29 = mpMdlMng->mpMdl->mFlags & 0x100; + s16 r30_tmp = 0x5000; + if (r29) { + r30_tmp = 0x2000; + } + + int r3 = abs(iVar2); + + if (r3 > r30_tmp) { + if (iVar2 > 0) { + temp = (mAng(r30_tmp) + mAngle.y).mAngle; + } else { + temp = (mAngle.y - mAng(r30_tmp)).mAngle; + } + } + + r31 = temp; + + if (r29) { + r30 = r27; + } else { + float tmpf = std::fabs(mAng(r3 / 2.0f).cos()); + r30 = r27 * tmpf; + } + cond = true; + } else if (abs(iVar2) < 0x4000) { + mpMdlMng->mpMdl->m_204 = 1; + r30 = r27; + cond = true; + } + } + + sLib::addCalcAngle(&angle.y.mAngle, r31.mAngle, 8, 0x400, 0x40); + if (pdVar10 != nullptr && (pdVar10->mAttentionFlags & 1)) { + sLib::addCalcAngle(&angle.z.mAngle, r30.mAngle, 8, 0x180, 0x40); + } else { + sLib::addCalcAngle(&angle.z.mAngle, r30.mAngle, 8, 0x400, 0x40); + } + + mpMdlMng->setAng(angle); + + if (!cond && angle.z == 0 && abs(angle.y.mAngle - mAngle.y.mAngle) < 0x100) { + mpMdlMng->mpMdl->m_204 = 0; + } + + return; + } + } + + angle.y = 0; + angle.z = 0; + mpMdlMng->setAng(angle); + mpMdlMng->mpMdl->m_204 = 0; +} diff --git a/source/dol/bases/d_ac_py_key.cpp b/source/dol/bases/d_ac_py_key.cpp index 3491110c..1cf49731 100644 --- a/source/dol/bases/d_ac_py_key.cpp +++ b/source/dol/bases/d_ac_py_key.cpp @@ -274,7 +274,7 @@ int dAcPyKey_c::buttonYoshiJump() const { return buttonTwo(); } -u8 dAcPyKey_c::triggerShakeJump() const { +int dAcPyKey_c::triggerShakeJump() const { return mTriggerShakeJump; } diff --git a/source/dol/bases/d_actor.cpp b/source/dol/bases/d_actor.cpp index 55b677d0..be5a5324 100644 --- a/source/dol/bases/d_actor.cpp +++ b/source/dol/bases/d_actor.cpp @@ -489,7 +489,7 @@ bool dActor_c::carryFukidashiCheck(int fukidashiAction, mVec2_c fukidashiTrigger bool canDrawFukidashi = player->isDrawingCarryFukidashi(); sRangeDataF playerBoundBox; - player->getCcBounds(playerBoundBox); + player->getCcBounds(&playerBoundBox); mVec3_c playerPos( dScStage_c::getLoopPosX(playerBoundBox.mOffset.x + player->mPos.x), playerBoundBox.mOffset.y + player->mPos.y, @@ -516,7 +516,7 @@ bool dActor_c::carryFukidashiCheck(int fukidashiAction, mVec2_c fukidashiTrigger bool canDrawFukidashi = player->isDrawingCarryFukidashi(); sRangeDataF playerBoundBox; - player->getCcBounds(playerBoundBox); + player->getCcBounds(&playerBoundBox); mVec3_c playerPos( dScStage_c::getLoopPosX(playerBoundBox.mOffset.x + player->mPos.x), playerBoundBox.mOffset.y + player->mPos.y, @@ -528,7 +528,7 @@ bool dActor_c::carryFukidashiCheck(int fukidashiAction, mVec2_c fukidashiTrigger bool overlap = dGameCom::checkRectangleOverlap(&minTriggerPos, &maxTriggerPos, &minPlayerPos, &maxPlayerPos, 0.0f); if (canDrawFukidashi && overlap) { - mCarryFukidashiPlayerNo = *player->getPlrNo(); + mCarryFukidashiPlayerNo = player->getPlrNo(); } } } @@ -631,7 +631,7 @@ bool dActor_c::setEatGlupDown(dActor_c *eatingActor) { mVec3_c smallScorePos = eatingActor->mPos; smallScorePos.y += 40.0f; - s8 plrNo = *eatingActor->getPlrNo(); + s8 plrNo = eatingActor->getPlrNo(); dGameCom::CreateSmallScore(smallScorePos, yoshiEatPopupTypes[mEatPoints], plrNo, false); if (plrNo != -1) { @@ -786,7 +786,7 @@ bool dActor_c::checkCarried(int *playerNum) { dAcPy_c *player = daPyMng_c::getPlayer(i); if (player != nullptr && fManager_c::searchBaseByID(player->mCarryActorID) == this) { if (playerNum != nullptr) { - *playerNum = *player->getPlrNo(); + *playerNum = player->getPlrNo(); } return true; } diff --git a/source/dol/bases/d_actorcreate_manager.cpp b/source/dol/bases/d_actorcreate_manager.cpp index c1c1393e..f6954f8d 100644 --- a/source/dol/bases/d_actorcreate_manager.cpp +++ b/source/dol/bases/d_actorcreate_manager.cpp @@ -351,7 +351,7 @@ void dActorCreateMng_c::MapActorScroolCreateCheck() { void dActorCreateMng_c::MapActorScrollCreate(sMapActorCreateBounds *createBounds, int isScreenScroll) { dScStage_c *stage = dScStage_c::m_instance; - u8 areaNo = stage->mCurrArea; + u8 areaNo = stage->mCurrAreaNo; dCdFile_c *file = dCd_c::m_instance->getFileP(stage->mCurrFile); int mapActorCount = file->mMapActorCountByArea[areaNo]; diff --git a/source/dol/bases/d_base_actor.cpp b/source/dol/bases/d_base_actor.cpp index 7dd05100..13f5797d 100644 --- a/source/dol/bases/d_base_actor.cpp +++ b/source/dol/bases/d_base_actor.cpp @@ -25,8 +25,8 @@ mAngle3D() } if (m_tmpCtAngleP != nullptr) { - mAngle = *m_tmpCtAngleP; - mAngle3D = *m_tmpCtAngleP; + mAngle.set(*m_tmpCtAngleP); + mAngle3D.set(*m_tmpCtAngleP); } // Initialize the rest diff --git a/source/dol/bases/d_cc.cpp b/source/dol/bases/d_cc.cpp index dea6d32f..1575c4f9 100644 --- a/source/dol/bases/d_cc.cpp +++ b/source/dol/bases/d_cc.cpp @@ -90,8 +90,8 @@ void dCc_c::release() { void dCc_c::set(dActor_c *actor, sCcDatNewF *collInfo) { mpOwner = actor; - mCcData.mOffset = collInfo->mOffset; - mCcData.mSize = collInfo->mSize; + mCcData.mBase.mOffset = collInfo->mBase.mOffset; + mCcData.mBase.mSize = collInfo->mBase.mSize; mCcData.mKind = collInfo->mKind; mCcData.mAttack = collInfo->mAttack; mCcData.mVsKind = collInfo->mVsKind; @@ -129,27 +129,27 @@ u16 dCc_c::isHitAtDmg(u16 mask) const { } float dCc_c::getTopPos() { - return mCcData.mOffset.y + mpOwner->mPos.y + mCcData.mSize.y; + return mCcData.mBase.mOffset.y + mpOwner->mPos.y + mCcData.mBase.mSize.y; } float dCc_c::getUnderPos() { - return mCcData.mOffset.y + mpOwner->mPos.y - mCcData.mSize.y; + return mCcData.mBase.mOffset.y + mpOwner->mPos.y - mCcData.mBase.mSize.y; } float dCc_c::getCenterPosY() { - return mCcData.mOffset.y + mpOwner->mPos.y; + return mCcData.mBase.mOffset.y + mpOwner->mPos.y; } float dCc_c::getRightPos() { - return mCcData.mOffset.x + mpOwner->mPos.x + mCcData.mSize.x; + return mCcData.mBase.mOffset.x + mpOwner->mPos.x + mCcData.mBase.mSize.x; } float dCc_c::getLeftPos() { - return mCcData.mOffset.x + mpOwner->mPos.x - mCcData.mSize.x; + return mCcData.mBase.mOffset.x + mpOwner->mPos.x - mCcData.mBase.mSize.x; } float dCc_c::getCenterPosX() { - return mCcData.mOffset.x + mpOwner->mPos.x; + return mCcData.mBase.mOffset.x + mpOwner->mPos.x; } bool dCc_c::isInside(dCc_c *other) { @@ -161,12 +161,12 @@ bool dCc_c::isInside(dCc_c *other) { return true; } float xDist = getCenterPosX() - other->getCenterPosX(); - if (std::fabs(xDist) > std::fabs(mCcData.mSize.x - other->mCcData.mSize.x)) { + if (std::fabs(xDist) > std::fabs(mCcData.mBase.mSize.x - other->mCcData.mBase.mSize.x)) { return false; } float yDist = getCenterPosY() - other->getCenterPosY(); - if (std::fabs(yDist) > std::fabs(mCcData.mSize.y - other->mCcData.mSize.y)) { + if (std::fabs(yDist) > std::fabs(mCcData.mBase.mSize.y - other->mCcData.mBase.mSize.y)) { return false; } return true; @@ -282,9 +282,9 @@ bool dCc_c::_hitCheckSquare(dCc_c *c1, dCc_c *c2, mVec2_c pos1, mVec2_c pos2) { // Compute the distance between the two colliders and the maximum distances for a collision float xDist = pos1.x - pos2.x; - float collSizeX = ci1.mSize.x + ci2.mSize.x; + float collSizeX = ci1.mBase.mSize.x + ci2.mBase.mSize.x; float yDist = pos1.y - pos2.y; - float collSizeY = ci1.mSize.y + ci2.mSize.y; + float collSizeY = ci1.mBase.mSize.y + ci2.mBase.mSize.y; if (std::fabs(xDist) < collSizeX && std::fabs(yDist) < collSizeY) { c1->mCollPos = pos1; @@ -356,19 +356,19 @@ bool dCc_c::_hitCheckCircle(dCc_c *c1, dCc_c *c2) { // [Not sure why we are looking at the height here... // It seems they maybe wanted the circles to also support ellipses? // Either way, the collision calculations treat it as a circle.] - float collSizeX = c1->mCcData.mSize.x + c2->mCcData.mSize.x; - float collSizeY = c1->mCcData.mSize.y + c2->mCcData.mSize.y; + float collSizeX = c1->mCcData.mBase.mSize.x + c2->mCcData.mBase.mSize.x; + float collSizeY = c1->mCcData.mBase.mSize.y + c2->mCcData.mBase.mSize.y; float collSizeRadius = (collSizeX + collSizeY) / 2; mVec2_c distVec = p2 - p1; if (distVec.length() <= collSizeRadius) { // Push the circles apart in the direction of the collision float dist = collSizeRadius - distVec.length(); - s16 ang = cM::atan2s(distVec.y, std::fabs(distVec.x)); + mAng ang = cM::atan2s(distVec.y, std::fabs(distVec.x)); // [This calculation is incorrect. It should be dist / 2 * ... // so that the shifting is distributed between the two colliders] - float offsetX = dist * nw4r::math::CosIdx(ang); - float offsetY = -dist * nw4r::math::SinIdx(ang); + float offsetX = dist * ang.cos(); + float offsetY = -dist * ang.sin(); c1->mCollOffsetX[c2->mCcData.mKind] = offsetX; c1->mCollOffsetY[c2->mCcData.mKind] = offsetY; @@ -409,17 +409,17 @@ bool dCc_c::_hitCheckBoxCircle(dCc_c *c1, dCc_c *c2) { mVec2_c circlePos = circleCc->getCenterVec(); mVec2_c boxPos = boxCc->getCenterVec(); - float circleRadius = circleCc->mCcData.mSize.x; + float circleRadius = circleCc->mCcData.mBase.mSize.x; dir_e boxSideX = (boxCc->getCenterPosX() < circleCc->getCenterPosX()) ? LEFT : RIGHT; dir_e boxSideY = (boxCc->getCenterPosY() < circleCc->getCenterPosY()) ? BELOW : ABOVE; float closerEdgeX[] = { - boxCc->getCenterPosX() + boxCc->mCcData.mSize.x, // Left edge, if box is on the left - boxCc->getCenterPosX() - boxCc->mCcData.mSize.x // Right edge, if box is on the right + boxCc->getCenterPosX() + boxCc->mCcData.mBase.mSize.x, // Left edge, if box is on the left + boxCc->getCenterPosX() - boxCc->mCcData.mBase.mSize.x // Right edge, if box is on the right }; float closerEdgeY[] = { - boxCc->getCenterPosY() + boxCc->mCcData.mSize.y, // Top edge, if box is below - boxCc->getCenterPosY() - boxCc->mCcData.mSize.y // Bottom edge, if box is above + boxCc->getCenterPosY() + boxCc->mCcData.mBase.mSize.y, // Top edge, if box is below + boxCc->getCenterPosY() - boxCc->mCcData.mBase.mSize.y // Bottom edge, if box is above }; if (closerEdgeY[ABOVE] < circlePos.y && circlePos.y < closerEdgeY[BELOW]) { @@ -523,7 +523,7 @@ bool dCc_c::_hitCheckDaikeiUD(dCc_c *ccTrp, dCc_c * ccBox) { // The left and right sides of the trapezoid are parallel, // so the width of this shape is the same everywhere. - float collSizeX = ccTrp->mCcData.mSize.x + ccBox->mCcData.mSize.x; + float collSizeX = ccTrp->mCcData.mBase.mSize.x + ccBox->mCcData.mBase.mSize.x; if (std::fabs(trpCenter.x - boxCenter.x) >= collSizeX) { return false; @@ -595,7 +595,7 @@ bool dCc_c::_hitCheckDaikeiLR(dCc_c *ccTrp, dCc_c *ccBox) { // The top and bottom sides of the trapezoid are parallel, // so the height of this shape is the same everywhere. - float heightSum = ccTrp->mCcData.mSize.y + ccBox->mCcData.mSize.y; + float heightSum = ccTrp->mCcData.mBase.mSize.y + ccBox->mCcData.mBase.mSize.y; if (std::fabs(p1.y - p2.y) >= heightSum) { return false; diff --git a/source/dol/bases/d_enemy.cpp b/source/dol/bases/d_enemy.cpp index 8e18ea9f..5040fe7f 100644 --- a/source/dol/bases/d_enemy.cpp +++ b/source/dol/bases/d_enemy.cpp @@ -240,18 +240,18 @@ void dEn_c::normal_collcheck(dCc_c *self, dCc_c *other) { actor1->mCcValue = self->mCanBounce; self->mInfo |= CC_NO_HIT; } else if (other->mCcData.mKind != CC_KIND_PLAYER_ATTACK) { - s8 *plrNo = actor2->getPlrNo(); - if (*plrNo >= 0 && *plrNo < PLAYER_COUNT) { - if (actor1->mNoHitPlayer.mTimer[*plrNo] == 0) { - actor1->mNoHitPlayer.mTimer[*plrNo] = smc_NO_HIT_PLAYER_TIMER_DEFAULT; + s8 &plrNo = actor2->getPlrNo(); + if (plrNo >= 0 && plrNo < PLAYER_COUNT) { + if (actor1->mNoHitPlayer.mTimer[plrNo] == 0) { + actor1->mNoHitPlayer.mTimer[plrNo] = smc_NO_HIT_PLAYER_TIMER_DEFAULT; actor1->Normal_VsPlHitCheck(self, other); } } } } } else if (kind == STAGE_ACTOR_YOSHI) { - s8 *plrNo = actor2->getPlrNo(); - if (*plrNo >= 0 && *plrNo < PLAYER_COUNT) { + s8 &plrNo = actor2->getPlrNo(); + if (plrNo >= 0 && plrNo < PLAYER_COUNT) { if (other->mCcData.mAttack == CC_ATTACK_YOSHI_EAT) { actor1->hitYoshiEat(self, other); } else { @@ -259,8 +259,8 @@ void dEn_c::normal_collcheck(dCc_c *self, dCc_c *other) { if (actor1->YoshiDamageCheck(self, other)) { actor1->mCcValue = self->mCanBounce; self->mInfo |= CC_NO_HIT; - } else if (actor1->mNoHitPlayer.mTimer[*plrNo] == 0) { - actor1->mNoHitPlayer.mTimer[*plrNo] = smc_NO_HIT_PLAYER_TIMER_DEFAULT; + } else if (actor1->mNoHitPlayer.mTimer[plrNo] == 0) { + actor1->mNoHitPlayer.mTimer[plrNo] = smc_NO_HIT_PLAYER_TIMER_DEFAULT; actor1->Normal_VsYoshiHitCheck(self, other); } } @@ -414,13 +414,13 @@ bool dEn_c::getPl_UDflag(const mVec3_c &pos) { } bool dEn_c::CeilCheck(float y, dCc_c *cc) { - return dBgParameter_c::getInstance()->check(y + cc->mCcData.mOffset.y, cc->mCcData.mSize.y); + return dBgParameter_c::getInstance()->check(y + cc->mCcData.mBase.mOffset.y, cc->mCcData.mBase.mSize.y); } bool dEn_c::carry_check(dActor_c *actor) { dAcPy_c *pl = (dAcPy_c *) actor; - if (pl->FUN_8012e540(this, true)) { - mPlayerNo = *actor->getPlrNo(); + if (pl->spinLiftUp(this, true)) { + mPlayerNo = actor->getPlrNo(); return true; } return false; @@ -513,8 +513,8 @@ void dEn_c::SpinFumiScoreSet(dActor_c *actor) { FumiScoreSet(actor); } -void dEn_c::PlayerFumiJump(dActor_c *actor, float param_2) { - ((daPlBase_c *) actor)->vf3fc(param_2, actor->mSpeedF, 1, 0, 2); +void dEn_c::PlayerFumiJump(dActor_c *actor, float jumpSpeed) { + ((daPlBase_c *) actor)->setJump(jumpSpeed, actor->mSpeedF, true, 0, 2); dEnemyMng_c::m_instance->m_138 = 1; } @@ -527,12 +527,12 @@ void dEn_c::setFumiComboScore(dActor_c *actor) { switch (mCombo.mType) { case dEnCombo_c::COMBO_REGULAR: { dScoreMng_c *instance = dScoreMng_c::getInstance(); - instance->ScoreSet(pos, treadCount, *actor->getPlrNo(), 1); + instance->ScoreSet(pos, treadCount, actor->getPlrNo(), 1); break; } case dEnCombo_c::COMBO_SHORT: { dScoreMng_c *instance = dScoreMng_c::getInstance(); - instance->ScoreSet2(pos, treadCount, *actor->getPlrNo()); + instance->ScoreSet2(pos, treadCount, actor->getPlrNo()); break; } default: @@ -560,7 +560,7 @@ void dEn_c::fumiSE(dActor_c *actor) { SE_EMY_FUMU_7 }; - int count = ((daPlBase_c *) actor)->getTreadCount(); + int count = ((daPlBase_c *) actor)->mTreadCount; if (count >= ARRAY_SIZE(cs_combo_se)) { count = ARRAY_SIZE(cs_combo_se) - 1; }; @@ -584,7 +584,7 @@ void dEn_c::spinfumiSE(dActor_c *actor) { SE_EMY_DOWN_SPIN_7 }; - int count = ((daPlBase_c *) actor)->getTreadCount(); + int count = ((daPlBase_c *) actor)->mTreadCount; if (count >= ARRAY_SIZE(cs_combo_se)) { count = ARRAY_SIZE(cs_combo_se) - 1; }; @@ -608,7 +608,7 @@ void dEn_c::yoshifumiSE(dActor_c *actor) { SE_EMY_YOSHI_FUMU_7 }; - int count = ((daPlBase_c *) actor)->getTreadCount(); + int count = ((daPlBase_c *) actor)->mTreadCount; if (count >= ARRAY_SIZE(cs_combo_se)) { count = ARRAY_SIZE(cs_combo_se) - 1; }; @@ -638,8 +638,8 @@ void dEn_c::fumiEffect(dActor_c *actor) { daPlBase_c *pl = (daPlBase_c *) actor; mVec3_c efPos; - efPos.x = pl->getAnkleCenterX(); - efPos.y = pl->getAnkleCenterY(); + efPos.x = pl->getAnkleCenterPos().x; + efPos.y = pl->getAnkleCenterPos().y; efPos.z = 5500.0f; mEf::createEffect("Wm_en_hit", 0, &efPos, nullptr, nullptr); } @@ -742,7 +742,7 @@ void dEn_c::WaterCheck(mVec3_c &pos, float h) { bool dEn_c::LineBoundaryCheck(dActor_c *actor) { daPlBase_c *pl = (daPlBase_c *) actor; if ((pl->mPos.z > 0.0f && mAmiLayer == 1) || (pl->mPos.z < 0.0f && mAmiLayer == 0)) { - if (pl->mFlags & 0x80000 || pl->mFlags & 0x100000) { + if (pl->isNowBgCross(daPlBase_c::BGC_VINE_TOUCH_L) || pl->isNowBgCross(daPlBase_c::BGC_VINE_TOUCH_R)) { return true; } } @@ -912,7 +912,7 @@ bool dEn_c::PlayerCarryCheck(dActor_c *actor) { mVec3_c dEn_c::calcCarryPos(const mVec3_c &pos) { dAcPy_c *player = daPyMng_c::getPlayer(mPlayerNo); - if (player->isStatus(4)) { + if (player->isStatus(daPlBase_c::STATUS_OUT_OF_PLAY)) { return mPos; } mMtx_c mtx = player->getCarryMtx(); @@ -936,9 +936,9 @@ void dEn_c::slipBound(dActor_c *actor) { daPlBase_c *pl = (daPlBase_c *) actor; u8 idx = !(pl->mPos.x >= mPos.x); - pl->vf3fc(3.0f, cs_jump_xspeed[idx], 1, 0, 0); + pl->setJump(3.0f, cs_jump_xspeed[idx], true, 0, 0); - int plrNo = *pl->getPlrNo(); + int plrNo = pl->getPlrNo(); mNoHitPlayer.mTimer[plrNo] = 3; } @@ -956,7 +956,7 @@ void dEn_c::setEatTongueOff(dActor_c *actor) { bool dEn_c::setEatSpitOut(dActor_c *actor) { calcSpitOutPos(actor); - int plrNo = *actor->getPlrNo(); + int plrNo = actor->getPlrNo(); mNoHitPlayer.mTimer[plrNo] = smc_NO_HIT_PLAYER_TIMER_SPIT_OUT; mDirection = actor->mDirection; reviveCc(); @@ -991,7 +991,7 @@ void dEn_c::iceballInvalid(dCc_c *self, dCc_c *other) { void dEn_c::setDamage(dActor_c *actor) { daPlBase_c *pl = (daPlBase_c *) actor; - pl->setDamage(this, daPlBase_c::DAMAGE_NONE); + pl->setDamage(this, daPlBase_c::DAMAGE_DEFAULT); } void dEn_c::boyonInit() { @@ -1004,7 +1004,7 @@ void dEn_c::boyonBegin() { void dEn_c::block_hit_init() { u8 dir = mDeathFallDirection; - s8 plrNo = *getPlrNo(); + s8 plrNo = getPlrNo(); mVec3_c efPos(mVec2_c(mPos.x, mPos.y), 5500.0f); diff --git a/source/dol/bases/d_enemy_carry.cpp b/source/dol/bases/d_enemy_carry.cpp index 7010f955..28832606 100644 --- a/source/dol/bases/d_enemy_carry.cpp +++ b/source/dol/bases/d_enemy_carry.cpp @@ -49,7 +49,7 @@ void dEnemyCarry_c::setDeathInfo_CarryBgIn(dActor_c *actor) { -1, -1, mDirection, - (u8) *actor->getPlrNo() + (u8) actor->getPlrNo() }; } @@ -92,7 +92,7 @@ void dEnemyCarry_c::executeState_Carry() { if (!(mBc.mFlags & 0x15 << mDirection)) { mPos.x += l_EnMuki[mDirection] * 6.0f; } - mPlayerNo = *player->getPlrNo(); + mPlayerNo = player->getPlrNo(); if (mCarryingFlags & CARRY_THROW) { setThrowSpeed(player); setThrowChangeState(); diff --git a/source/dol/bases/d_enemy_death.cpp b/source/dol/bases/d_enemy_death.cpp index 6667d3fa..fe677fcc 100644 --- a/source/dol/bases/d_enemy_death.cpp +++ b/source/dol/bases/d_enemy_death.cpp @@ -28,7 +28,7 @@ const s16 dEn_c::smc_DEADFALL_SPINSPEED = 0xc00; bool dEn_c::hitCallback_Star(dCc_c *self, dCc_c *other) { daPlBase_c *player = (daPlBase_c *) other->getOwner(); u8 dir = player->getTrgToSrcDir_Main(getCenterX(), player->getCenterX()); - u8 plrNo = *player->getPlrNo(); + u8 plrNo = player->getPlrNo(); mVec2_c collPos = self->mCollPos; hitdamageEffect(mVec3_c(collPos, 5500.0f)); @@ -59,7 +59,7 @@ bool dEn_c::hitCallback_Star(dCc_c *self, dCc_c *other) { bool dEn_c::hitCallback_Cannon(dCc_c *self, dCc_c *other) { daPlBase_c *player = (daPlBase_c *) other->getOwner(); u8 dir = player->getTrgToSrcDir_Main(getCenterX(), player->getCenterX()); - u8 plrNo = *player->getPlrNo(); + u8 plrNo = player->getPlrNo(); mVec2_c collPos = self->mCollPos; hitdamageEffect(mVec3_c(collPos, 5500.0f)); @@ -68,7 +68,7 @@ bool dEn_c::hitCallback_Cannon(dCc_c *self, dCc_c *other) { if (mCombo.mType == dEnCombo_c::COMBO_SHORT) { shortCombo = 1; } - player->slideComboSE(player->m_cee, shortCombo); + player->slideComboSE(player->mPlComboCount, shortCombo); int score = mCombo.getComboScore(dEnCombo_c::calcPlComboCnt(player)); @@ -90,7 +90,7 @@ bool dEn_c::hitCallback_Cannon(dCc_c *self, dCc_c *other) { bool dEn_c::hitCallback_Slip(dCc_c *self, dCc_c *other) { daPlBase_c *player = (daPlBase_c *) other->getOwner(); u8 dir = player->getTrgToSrcDir_Main(getCenterX(), player->getCenterX()); - u8 plrNo = *player->getPlrNo(); + u8 plrNo = player->getPlrNo(); mVec2_c collPos = self->mCollPos; hitdamageEffect(mVec3_c(collPos, 5500.0f)); @@ -125,7 +125,7 @@ bool dEn_c::hitCallback_Screw(dCc_c *self, dCc_c *other) { bool dEn_c::hitCallback_WireNet(dCc_c *self, dCc_c *other) { daPlBase_c *player = (daPlBase_c *) other->getOwner(); u8 dir = player->getTrgToSrcDir_Main(getCenterX(), player->getCenterX()); - u8 plrNo = *player->getPlrNo(); + u8 plrNo = player->getPlrNo(); dAudio::g_pSndObjEmy->startSound(SE_EMY_DOWN, mPos, 0); @@ -147,7 +147,7 @@ bool dEn_c::hitCallback_WireNet(dCc_c *self, dCc_c *other) { bool dEn_c::hitCallback_Large(dCc_c *self, dCc_c *other) { daPlBase_c *player = (daPlBase_c *) other->getOwner(); u8 dir = player->getTrgToSrcDir_Main(getCenterX(), player->getCenterX()); - u8 plrNo = *player->getPlrNo(); + u8 plrNo = player->getPlrNo(); float xSpeed = l_EnMuki[dir]; xSpeed += player->mSpeed.x - mSpeed.x; @@ -179,7 +179,7 @@ bool dEn_c::hitCallback_Rolling(dCc_c *self, dCc_c *other) { bool dEn_c::hitCallback_Spin(dCc_c *self, dCc_c *other) { daPlBase_c *player = (daPlBase_c *) other->getOwner(); u8 dir = player->getTrgToSrcDir_Main(getCenterX(), player->getCenterX()); - u8 plrNo = *player->getPlrNo(); + u8 plrNo = player->getPlrNo(); setDeathSound_Spin(); @@ -208,7 +208,7 @@ bool dEn_c::hitCallback_Spin(dCc_c *self, dCc_c *other) { bool dEn_c::hitCallback_HipAttk(dCc_c *self, dCc_c *other) { daPlBase_c *player = (daPlBase_c *) other->getOwner(); u8 dir = player->getTrgToSrcDir_Main(getCenterX(), player->getCenterX()); - u8 plrNo = *player->getPlrNo(); + u8 plrNo = player->getPlrNo(); setDeathSound_HipAttk(); @@ -237,7 +237,7 @@ bool dEn_c::hitCallback_HipAttk(dCc_c *self, dCc_c *other) { bool dEn_c::hitCallback_YoshiHipAttk(dCc_c *self, dCc_c *other) { daPlBase_c *player = (daPlBase_c *) other->getOwner(); u8 dir = player->getTrgToSrcDir_Main(getCenterX(), player->getCenterX()); - u8 plrNo = *player->getPlrNo(); + u8 plrNo = player->getPlrNo(); int comboScore = mCombo.getComboScore(dEnCombo_c::calcPlFumiCnt(player)); if (comboScore >= 0 && plrNo < PLAYER_COUNT) { @@ -254,7 +254,7 @@ bool dEn_c::hitCallback_YoshiHipAttk(dCc_c *self, dCc_c *other) { bool dEn_c::hitCallback_YoshiBullet(dCc_c *self, dCc_c *other) { daPlBase_c *player = (daPlBase_c *) other->getOwner(); u8 dir = player->getTrgToSrcDir_Main(getCenterX(), player->getCenterX()); - s8 plrNo = *player->getPlrNo(); + s8 plrNo = player->getPlrNo(); setDeathSound_Fire(); @@ -282,7 +282,7 @@ bool dEn_c::hitCallback_YoshiFire(dCc_c *self, dCc_c *other) { u8 dir = !(player->mSpeed.x >= 0.0f); mVec3_c centerPos = getCenterPos(); dActorMng_c::m_instance->createUpCoin(centerPos, dir, 1, 0); - s8 plrNo = *player->getPlrNo(); + s8 plrNo = player->getPlrNo(); mVec2_c collPos = self->mCollPos; hitdamageEffect(mVec3_c(collPos, 5500.0f)); @@ -316,7 +316,7 @@ bool dEn_c::hitCallback_YoshiFire(dCc_c *self, dCc_c *other) { bool dEn_c::hitCallback_Shell(dCc_c *self, dCc_c *other) { daPlBase_c *player = (daPlBase_c *) other->getOwner(); u8 dir = player->getTrgToSrcDir_Main(getCenterX(), player->getCenterX()); - s8 plrNo = *player->getPlrNo(); + s8 plrNo = player->getPlrNo(); mVec2_c collPos = self->mCollPos; hitdamageEffect(mVec3_c(collPos, 5500.0f)); @@ -355,7 +355,7 @@ bool dEn_c::hitCallback_Shell(dCc_c *self, dCc_c *other) { bool dEn_c::hitCallback_Fire(dCc_c *self, dCc_c *other) { daPlBase_c *player = (daPlBase_c *) other->getOwner(); u8 dir = !(player->mSpeed.x >= 0.0f); - s8 plrNo = *player->getPlrNo(); + s8 plrNo = player->getPlrNo(); setDeathSound_Fire(); @@ -393,7 +393,7 @@ bool dEn_c::hitCallback_Ice(dCc_c *self, dCc_c *other) { break; } } - mIceMng.mPlrNo = *player->getPlrNo(); + mIceMng.mPlrNo = player->getPlrNo(); mStateMgr.changeToSubState(StateID_Ice); } @@ -461,7 +461,7 @@ void dEn_c::setDeathInfo_Quake(int i) { void dEn_c::setDeathInfo_Smoke(dActor_c *actor) { u8 plrNo = mPlayerNo; if (actor != nullptr) { - plrNo = *actor->getPlrNo(); + plrNo = actor->getPlrNo(); } mDeathInfo = (sDeathInfoData) { @@ -479,7 +479,7 @@ void dEn_c::setDeathInfo_Smoke(dActor_c *actor) { void dEn_c::setDeathInfo_Fumi(dActor_c *killedBy, mVec2_c speed, const sStateIDIf_c &id, int) { bool dir = killedBy->getTrgToSrcDir_Main(getCenterX(), killedBy->getCenterX()); - u8 plrNo = *killedBy->getPlrNo(); + u8 plrNo = killedBy->getPlrNo(); mDeathInfo = (sDeathInfoData) { speed.x, @@ -496,7 +496,7 @@ void dEn_c::setDeathInfo_Fumi(dActor_c *killedBy, mVec2_c speed, const sStateIDI void dEn_c::setDeathInfo_YoshiFumi(dActor_c *killedBy) { bool dir = killedBy->getTrgToSrcDir_Main(getCenterX(), killedBy->getCenterX()); - u8 plrNo = *killedBy->getPlrNo(); + u8 plrNo = killedBy->getPlrNo(); mDeathInfo = (sDeathInfoData) { 0.0f, @@ -514,7 +514,7 @@ void dEn_c::setDeathInfo_YoshiFumi(dActor_c *killedBy) { void dEn_c::setDeathInfo_Other(dActor_c *killedBy) { s8 plrNo = -1; if (killedBy != nullptr) { - plrNo = *killedBy->getPlrNo(); + plrNo = killedBy->getPlrNo(); } mDeathInfo = (sDeathInfoData) { @@ -532,7 +532,7 @@ void dEn_c::setDeathInfo_Other(dActor_c *killedBy) { void dEn_c::setDeathInfo_SpinFumi(dActor_c *killedBy, int) { u8 dir = killedBy->getTrgToSrcDir_Main(getCenterX(), killedBy->getCenterX()); - u8 plrNo = *killedBy->getPlrNo(); + u8 plrNo = killedBy->getPlrNo(); mDeathInfo = (sDeathInfoData) { l_base_fall_speed_x[dir], @@ -808,7 +808,7 @@ void dEn_c::setDeathSound_Slip(dActor_c *killedBy) { SE_EMY_DOWN_COMBO_7 }; - int count = ((daPlBase_c *) killedBy)->m_cee; + int count = ((daPlBase_c *) killedBy)->mPlComboCount; if (count >= ARRAY_SIZE(cs_combo_se)) { count = ARRAY_SIZE(cs_combo_se) - 1; }; diff --git a/source/dol/bases/d_multi_manager.cpp b/source/dol/bases/d_multi_manager.cpp index 7f24ec28..b50e76ea 100644 --- a/source/dol/bases/d_multi_manager.cpp +++ b/source/dol/bases/d_multi_manager.cpp @@ -79,7 +79,7 @@ void dMultiMng_c::setBattleCoin(int plrNo, int value) { return; } mVec3_c popupPos = player->mPos; - popupPos.y += player->mSmallScoreOffset; + popupPos.y += player->getModelHeight(); dGameCom::CreateSmallScore(popupPos, popupType, plrNo, false); } } diff --git a/source/dol/bases/d_s_boot.cpp b/source/dol/bases/d_s_boot.cpp index e89acaa8..19c61eb2 100644 --- a/source/dol/bases/d_s_boot.cpp +++ b/source/dol/bases/d_s_boot.cpp @@ -465,7 +465,7 @@ void dScBoot_c::finalizeState_ResetWait() {} void dScBoot_c::initializeState_ResetFadeOut() { mIsResetting = true; dScene_c::m_isAutoFadeIn = false; - dFader_c::setFader(dFader_c::FADE); + dFader_c::setFader(dFader_c::FADER_FADE); mResetFadeOutStarted = dFader_c::startFadeOut(30); mResetFaderDone = false; } @@ -520,7 +520,7 @@ void dScBoot_c::finalizeState_ResetFadeOut() { void dScBoot_c::initializeState_ResetFadeIn() { dReset::Manage_c::GetInstance()->ActiveSaveWindow(true); - dFader_c::setFader(dFader_c::FADE); + dFader_c::setFader(dFader_c::FADER_FADE); dFader_c::startFadeIn(30); mpWiiStrapScreen->mLayout.mpAnimGroup->setAndUpdate(0.0f); } @@ -596,7 +596,7 @@ void dScBoot_c::finalizeState_WiiStrapDispEndWait() {} void dScBoot_c::initializeState_WiiStrapFadeOut() { dScene_c::m_isAutoFadeIn = false; - dFader_c::setFader(dFader_c::FADE); + dFader_c::setFader(dFader_c::FADER_FADE); dFader_c::startFadeOut(30); dHbm::Manage_c::GetInstance()->mFlags |= 0x40; dReset::Manage_c::GetInstance()->ActiveSaveWindow(true); @@ -616,7 +616,7 @@ void dScBoot_c::finalizeState_WiiStrapFadeOut() { } void dScBoot_c::initializeState_ControllerInformationFadeIn() { - dFader_c::setFader(dFader_c::FADE); + dFader_c::setFader(dFader_c::FADER_FADE); dFader_c::startFadeIn(30); mpControllerInformation->mVisible = true; } @@ -843,7 +843,7 @@ void dScBoot_c::finalizeState_WindowExitWait() {} void dScBoot_c::initializeState_GoToErrorFadeOut() { dScene_c::m_isAutoFadeIn = false; - dFader_c::setFader(dFader_c::FADE); + dFader_c::setFader(dFader_c::FADER_FADE); dFader_c::startFadeOut(30); dReset::Manage_c::GetInstance()->ActiveSaveWindow(true); } @@ -859,7 +859,7 @@ void dScBoot_c::executeState_GoToErrorFadeOut() { void dScBoot_c::finalizeState_GoToErrorFadeOut() {} void dScBoot_c::initializeState_GoToErrorFadeIn() { - dFader_c::setFader(dFader_c::FADE); + dFader_c::setFader(dFader_c::FADER_FADE); dFader_c::startFadeIn(30); } diff --git a/source/dol/bases/d_wipe_circle.cpp b/source/dol/bases/d_wipe_circle.cpp index 29386f23..574b2bfd 100644 --- a/source/dol/bases/d_wipe_circle.cpp +++ b/source/dol/bases/d_wipe_circle.cpp @@ -109,7 +109,7 @@ void dWipeCircle_c::CenterPosSet() { centerPos.x = mCenterPos.x; centerPos.y = mCenterPos.y; } else { - int targetPlayerNo = daPyDemoMng_c::mspInstance->mPlNo; + int targetPlayerNo = daPyDemoMng_c::mspInstance->mPlayerNo; if (dScStage_c::m_KoopaJrEscape) { targetPlayerNo = 0; } diff --git a/source/dol/bases/d_wipe_dokan.cpp b/source/dol/bases/d_wipe_dokan.cpp index c1a80ae3..a279acb2 100644 --- a/source/dol/bases/d_wipe_dokan.cpp +++ b/source/dol/bases/d_wipe_dokan.cpp @@ -119,7 +119,7 @@ void dWipeDokan_c::AnimeEndCheck() { } bool dWipeDokan_c::MuKiDecision() { - int actPlayer = daPyDemoMng_c::mspInstance->mPlNo; + int actPlayer = daPyDemoMng_c::mspInstance->mPlayerNo; if (actPlayer < 0) { return false; } diff --git a/syms.txt b/syms.txt index a411d089..3b9e1be0 100644 --- a/syms.txt +++ b/syms.txt @@ -259,9 +259,9 @@ CreateWarningManager__17dWarningManager_cFv=0x8010D2A0 AllWarningEnd__17dWarningManager_cFb=0x8010E5A0 __dt__Q23m2d8Simple_cFv=0x8010F5B0 getCarryPos__7dAcPy_cFv=0x8012DFC0 -FUN_8012e540__7dAcPy_cFP8dActor_cb=0x8012E540 +fn_8012e540__7dAcPy_cFP8dActor_cb=0x8012E540 cancelCarry__7dAcPy_cFP8dActor_c=0x8012E650 -getCcBounds__7dAcPy_cFR11sRangeDataF=0x801420B0 +getCcBounds__7dAcPy_cFP11sRangeDataF=0x801420B0 isDrawingCarryFukidashi__7dAcPy_cFv=0x80147CA0 getTongueTipMtx__9daYoshi_cFP6mMtx_c=0x801525C0 getMouthMtx__9daYoshi_cFP6mMtx_c=0x80152660 @@ -711,3 +711,303 @@ smc_SCORE_Y__11dScoreMng_c=0x8042CF6C c_CASTLE_ID__10dCsvData_c=0x8042D24C c_START_ID__10dCsvData_c=0x8042D264 c_PLAYNUM_DIGIT__14dGameDisplay_c=0x8042DE90 +StateID_Ice__5dEn_c=80358304 +StateID_EatIn__5dEn_c=80358384 +StateID_EatOut__5dEn_c=80358404 +changeState__5dEn_cFRC12sStateIDIf_c=800a7df0 +initializeState_Ice__5dEn_cFv=800a7e90 +finalizeState_Ice__5dEn_cFv=800a7f30 +executeState_Ice__5dEn_cFv=800a7f40 +createIceActor__5dEn_cFv=800a8060 +setIceAnm__5dEn_cFv=800a8150 +returnAnm_Ice__5dEn_cFv=800a8160 +killIce__5dEn_cFv=800a8170 +returnState_Ice__5dEn_cFv=800a8180 +initializeState_HitSpin__5dEn_cFv=800a8190 +finalizeState_HitSpin__5dEn_cFv=800a81a0 +executeState_HitSpin__5dEn_cFv=800a81b0 +initializeState_EatIn__5dEn_cFv=800a81c0 +finalizeState_EatIn__5dEn_cFv=800a81d0 +executeState_EatIn__5dEn_cFv=800a81e0 +initializeState_EatNow__5dEn_cFv=800a8260 +finalizeState_EatNow__5dEn_cFv=800a8270 +executeState_EatNow__5dEn_cFv=800a8280 +initializeState_EatOut__5dEn_cFv=800a8290 +finalizeState_EatOut__5dEn_cFv=800a82a0 +executeState_EatOut__5dEn_cFv=800a82b0 +search__12dAttention_cF7mVec3_c=80069270 +searchPlayer__12dAttention_cFPC8dActor_c7mVec3_c=800693e0 +m_hio__11dPyMdlMng_c=803710a0 +chase__4sLibFPsss=8015f480 +getJointPos__12dPyMdlBase_cFP7mVec3_ci=800d5880 +createPlayerEffect__3dEfFiPQ23mEf13levelEffect_cPCcUlPC7mVec3_cPC7mAng3_cPC7mVec3_c=8008fba0 +setHipAttackQuake__9daPyMng_cFiUc=80060c10 +getSakaType__5dBc_cFv=80070760 +getSakaDir__5dBc_cFv=800707e0 +getControlDemoPlayerNum__13daPyDemoMng_cCFv=8005cad0 +m_isStaffCredit__10dScStage_c=8042a4ff +m_gameMode__10dScStage_c=8042a4e4 +mPauseEnableInfo__9daPyMng_c=80429fb0 +mStopTimerInfo__9daPyMng_c=80429fb8 +getLeftLimit__5dBg_cFv=80078a70 +getRightLimit__5dBg_cFv=80078c10 +checkWallPlayer__5dBc_cFPC7mVec3_cPC7mVec3_cPf=80072440 +checkBgPlr__5dBc_cFP8dActor_c=80071210 +getHeadAttr__5dBc_cFv=80070730 +getSakaAngleBySpeed__5dBc_cFf=80070900 +checkGround__5dBc_cFPC7mVec3_cPfPiUcUcSc=800757e0 +checkGroundHalf__5dBc_cFPC7mVec3_cPfUcUc=80075800 +getAirWaterHitPos__5dBc_cFP7mVec2_c=80075750 +getAirWaterHitAngle__5dBc_cFPs=80075780 +isBgmAccentSign__6dAudioFUc=8006a200 +GetPlayingSoundCount__Q34nw4r3snd10SoundActorCFi=802756a0 +get3DCtrlFlag__11SndAudioMgrFUl=801967a0 +SetVolume__Q44nw4r3snd6detail10BasicSoundFfi=80267560 +sInstance__11SndSceneMgr=8042a788 +ReadSoundInfo__Q34nw4r3snd12SoundArchiveCFUlPQ44nw4r3snd12SoundArchive9SoundInfo=802758c0 +SetPlayerPriority__Q44nw4r3snd6detail10BasicSoundFi=802674d0 +SetPan__Q44nw4r3snd6detail10BasicSoundFf=80267600 +DetachSound__Q34nw4r3snd11SoundHandleFv=8027a340 +__dt__15NMSndObjectBaseFv=801974c0 +cleanup__Q23mEf13levelEffect_cFv=8016d5f0 +__ct__Q34nw4r2ef6EffectFv=80285950 +__ct__Q23EGG6EffectFv=802d7d90 +__dt__Q23EGG6EffectFv=802d7e10 +create__Q23EGG6EffectFv=802d7e70 +fade__Q23EGG6EffectFv=802d7f40 +followFade__Q23EGG6EffectFv=802d7fd0 +kill__Q23EGG6EffectFv=802d8040 +setDisableCalc__Q23EGG6EffectFb=802d80e0 +setDisableDraw__Q23EGG6EffectFb=802d8180 +setDisableCalcDraw__Q23EGG6EffectFb=802d8220 +setLife__Q23EGG6EffectFUsQ33EGG6Effect10ERecursive=802d82f0 +setEmitRatio__Q23EGG6EffectFfQ33EGG6Effect10ERecursive=802d8300 +setEmitInterval__Q23EGG6EffectFUsQ33EGG6Effect10ERecursive=802d8310 +setEmitEmitDiv__Q23EGG6EffectFUsQ33EGG6Effect10ERecursive=802d8320 +setInitVelocityRandom__Q23EGG6EffectFScQ33EGG6Effect10ERecursive=802d8330 +setPowerYAxis__Q23EGG6EffectFfQ33EGG6Effect10ERecursive=802d8340 +setPowerRadiationDir__Q23EGG6EffectFfQ33EGG6Effect10ERecursive=802d8350 +setPowerSpecDir__Q23EGG6EffectFfQ33EGG6Effect10ERecursive=802d8360 +setPowerSpecDirAdd__Q23EGG6EffectFfQ33EGG6Effect10ERecursive=802d8370 +setSpecDir__Q23EGG6EffectFRCQ34nw4r4math4VEC3Q33EGG6Effect10ERecursive=802d8380 +setSpecDirAdd__Q23EGG6EffectFRCQ34nw4r4math4VEC3Q33EGG6Effect10ERecursive=802d8390 +setVelocity__Q23EGG6EffectFRCQ34nw4r4math4VEC3=802d83a0 +setColor__Q23EGG6EffectFUcUcUcUcQ33EGG6Effect10ERecursive=802d8430 +setDefaultParticleSize__Q23EGG6EffectFRQ34nw4r4math4VEC2Q33EGG6Effect10ERecursive=802d84c0 +setParticleScale__Q23EGG6EffectFRQ34nw4r4math4VEC2Q33EGG6Effect10ERecursive=802d84d0 +setDefaultParticleRotate__Q23EGG6EffectFRCQ34nw4r4math4VEC3Q33EGG6Effect10ERecursive=802d84e0 +setParticleRotate__Q23EGG6EffectFRCQ34nw4r4math4VEC3Q33EGG6Effect10ERecursive=802d84f0 +setEmitterSize__Q23EGG6EffectFRCQ34nw4r4math4VEC3bQ33EGG6Effect10ERecursive=802d8500 +setLocalScale__Q23EGG6EffectFRCQ34nw4r4math4VEC3Q33EGG6Effect10ERecursive=802d8510 +setDynamicsScale__Q23EGG6EffectFRCQ34nw4r4math4VEC3PCQ34nw4r4math4VEC2=802d8520 +setScale__Q23EGG6EffectFf=802d8620 +setScale__Q23EGG6EffectFRCQ34nw4r4math4VEC3=802d8640 +setPos__Q23EGG6EffectFRCQ34nw4r4math4VEC3=802d8670 +setMtx__Q23EGG6EffectFRCQ34nw4r4math5MTX34=802d86a0 +setPtclAnim__Q23EGG6EffectFib=802d86c0 +update__Q23EGG6EffectFv=802d88b0 +getEffect__Q23EGG6EffectCFv=802d8a30 +getRootEmitter__Q23EGG6EffectCFv=802d8ab0 +reset__Q23EGG6EffectFv=802d8b30 +createEffect__Q23mEf8effect_cFPCci=8016caa0 +createEffect__Q23mEf8effect_cFPCcUlPC7mVec3_cPC7mAng3_cPC7mVec3_c=8016cbf0 +createEffect__Q23mEf8effect_cFPCcUlPC6mMtx_c=8016cca0 +follow__Q23mEf8effect_cFPC7mVec3_cPC7mAng3_cPC7mVec3_c=8016cfe0 +follow__Q23mEf8effect_cFPC6mMtx_c=8016d090 +getSakaUpDown__5dBc_cFUc=80070820 +shockMotor__8dQuake_cFScQ28dQuake_c12TYPE_SHOCK_eib=800d8ca0 +clearBgcSaveAll__5dBc_cFv=80075070 +mPauseDisable__9daPyMng_c=80429fb4 +setCourseOutList__13daPyDemoMng_cFSc=8005d050 +m_instance__7dNext_c=8042a2a0 +getYoshi__9daPyMng_cFi=8005fa60 +setGoalDemoList__13daPyDemoMng_cFi=8005b780 +setDemoMode__13daPyDemoMng_cFQ213daPyDemoMng_c6Mode_ei=8005b5c0 +getNumInGame__9daPyMng_cFv=8005fef0 +getItemKinopioNum__9daPyMng_cFv=80060010 +stopBgmGoalDemo__13daPyDemoMng_cFv=8005b810 +clearDemoNo__13daPyDemoMng_cFSc=8005d100 +m_instance__13dStageTimer_c=8042a350 +checkDemoNo__13daPyDemoMng_cFSc=8005d090 +turnNextDemoNo__13daPyDemoMng_cFv=8005d0d0 +getPlayerRideOn__9daYoshi_cCFv=8014eaf0 +chase__4sLibFPfff=8015f5b0 +setRideOnObjBg__5dBc_cFP9dBg_ctr_cRC7mVec3_c=800731e0 +addDokanMoveDiff__9dBg_ctr_cFP7mVec3_c=80080290 +getNextGotoP__9dCdFile_cFUc=8008e3d0 +getRailInfoP__7dRail_cFUc=800d91b0 +setChangeSceneNextDat__7dNext_cFUcUcQ28dFader_c12fader_type_e=800cfd90 +getPoleBelowPlayer__13daPyDemoMng_cFi=8005b840 +setBattleCoin__11dMultiMng_cFii=800ceb60 +stopPlyJumpSound__11SndObjctPlyFv=8019acf0 +scWaterCrouchAnmSpeed__12dPyMdlBase_c=8042cd50 +isStar__10daPlBase_cCFv=80022170 +getStarCount__10daPlBase_cCFv=8002d970 +isItemKinopio__10daPlBase_cFv=80020be0 +startFootSound__11SndObjctPlyFUlfUl=8019a810 +createPlayerEffect__3dEfFiPCcUlPC7mVec3_cPC7mAng3_cPC7mVec3_c=8008fb60 +checkDokanDown__5dBc_cFP7mVec3_cPi=800714d0 +checkDokanUp__5dBc_cFP7mVec3_cPi=800717a0 +checkDokanLR__5dBc_cFP7mVec3_cUcPiff=80071a60 +m_instance__13dRemoconMng_c=8042a308 +g_core__4mPad=80377f88 +__ct__15NMSndObjectBaseFQ215NMSndObjectBase8OBJ_TYPERQ34nw4r3snd18SoundArchivePlayer=80197440 +startPatternRumble__Q23EGG14CoreControllerFPCcib=802bcc70 +detail_SetupSound__Q34nw4r3snd10SoundActorFPQ34nw4r3snd11SoundHandleUlbPCQ44nw4r3snd14SoundStartable9StartInfo=80275710 +createPlayerEffect_change__3dEfFiPCcUlPC7mVec3_cPC7mAng3_cPC7mVec3_c=8008fc40 +detail_ConvertLabelStringToSoundId__Q34nw4r3snd10SoundActorFPCc=80275750 +SetupSound__Q34nw4r3snd10SoundActorFPQ34nw4r3snd11SoundHandleUlPCQ44nw4r3snd14SoundStartable9StartInfoPv=802756d0 +detail_SetupSoundWithAmbientInfo__Q34nw4r3snd10SoundActorFPQ34nw4r3snd11SoundHandleUlPCQ44nw4r3snd14SoundStartable9StartInfoPQ54nw4r3snd6detail10BasicSound11AmbientInfoPv=802756f0 +detail_StartSound__Q34nw4r3snd14SoundStartableFPQ34nw4r3snd11SoundHandleUlPCQ44nw4r3snd14SoundStartable9StartInfo=8027b2a0 +detail_PrepareSound__Q34nw4r3snd14SoundStartableFPQ34nw4r3snd11SoundHandleUlPCQ44nw4r3snd14SoundStartable9StartInfo=8027b3b0 +sendRemote__15NMSndObjectBaseFPQ34nw4r3snd11SoundHandleUlUl=80197540 +detail_HoldSound__Q34nw4r3snd14SoundStartableFPQ34nw4r3snd11SoundHandleUlPCQ44nw4r3snd14SoundStartable9StartInfo=8027b300 +GetSoundType__Q34nw4r3snd12SoundArchiveCFUl=802758b0 +__ct__Q34nw4r3snd14SeqSoundHandleFPQ34nw4r3snd11SoundHandle=80272d80 +WriteVariable__Q44nw4r3snd6detail8SeqSoundFis=80272b50 +DetachSound__Q34nw4r3snd14SeqSoundHandleFv=80272e80 +setSoundPosition__11SndAudioMgrFPQ34nw4r3snd11SoundHandleRCQ34nw4r4math4VEC2=801962d0 +SetPlayableSoundCount__Q34nw4r3snd10SoundActorFii=802756b0 +startSound__11SndObjctPlyFUlUl=8019a0f0 +holdSound__11SndObjctPlyFUlUl=8019a1e0 +startSound__11SndObjctPlyFUlsUl=8019a330 +holdSound__11SndObjctPlyFUlsUl=8019a450 +startSound__11SndObjctPlyFUlRCQ34nw4r4math4VEC2Ul=8019a5d0 +holdSound__11SndObjctPlyFUlRCQ34nw4r4math4VEC2Ul=8019a6c0 +getHeadSakaMoveAngle__5dBc_cFUc=80070980 +createPlayerEffect_change__3dEfFiPQ23mEf13levelEffect_cPCcUlPC7mVec3_cPC7mAng3_cPC7mVec3_c=8008fc80 +createPlayerEffect__3dEfFiPQ23dEf14followEffect_cPCcUlPC7mVec3_cPC7mAng3_cPC7mVec3_c=8008fbf0 +isFootStepTiming__12dPyMdlBase_cFv=800d6ba0 +isCaveMask__8dMaskMngFv=800cd3b0 +checkRoofPlayer__5dBc_cFPC7mVec3_cPf=800728c0 +__vt__Q23mEf13levelEffect_c=80329ca0 +__vt__Q23mEf8effect_c=80329d68 +setRegisterColor__Q23EGG6EffectFRC8_GXColorRC8_GXColorUcQ33EGG6Effect10ERecursive=802d8470 +setRegisterAlpha__Q23EGG6EffectFUcUcUcQ33EGG6Effect10ERecursive=802d84b0 +reset__Q23mEf8effect_cFv=8016ca60 +someCheck__8dGameComFP7mVec3_cP9mBoundBox=800b5640 +getAreaP__9dCdFile_cFUcP9mBoundBox=8008e410 +otherCullCheck__8dActor_cFRC7mVec3_cRC9mBoundBox9mBoundBoxUc=800b5730 +isInside__8dGameComFP7mVec3_cP7mVec3_cP7mVec3_cP7mVec3_cf=800b3100 +FUN_800b3720__8dGameComFiii=800b3720 +FUN_800b3750__8dGameComFiii=800b3750 +FUN_800b3600__8dGameComFii=800b3600 +vf68__8dActor_cFv=8001d210 +getLoopScrollDispPosX__14dBgParameter_cFf=80082240 +fn_8019ee20__9Snd2DCalcFRfRQ34nw4r4math4VEC2Ul=8019ee20 +vfa8__Q23mEf8effect_cFv=8016ce80 +vfac__Q23mEf8effect_cFv=8016cd30 +fn_800e25a0__11dScoreMng_cFUlii=800e25a0 +fn_800cfed0__7dNext_cFUcUc=800cfed0 +fn_8019AAB0__11SndObjctPlyFUli=8019AAB0 +fn_8019ABB0__11SndObjctPlyFUli=8019ABB0 +vf1C__15NMSndObjectBaseFUli=801976b0 +smc_POWER_CHANGE_DATA__14daPlayerData_c=802f5880 +getUnitType__5dBc_cFffUc=80070ba0 +m_instance__16dWaterEntryMng_c=8042a3e0 +addCalc__4sLibFPfffff=8015f280 +getAngle__5dPc_cCFv=800d2360 +check__5dPc_cFi=800d1600 +release__5dPc_cFv=800d22f0 +set__5dPc_cFP8dActor_cUc=800d15f0 +checkCollision__5dBc_cFP12sBcPointData=80072180 +checkCollision2__5dBc_cFP12sBcPointData=80071dc0 +create__11dPyMdlMng_cFUcUcQ211dPyMdlMng_c11SceneType_e=800d6ee0 +create__14dPropelParts_cFP8dActor_c=800d8370 +m_miniGame__10dScStage_c=8042a500 +mCreateItem__9daPyMng_c=80355180 +m_star_time__9daPyMng_c=80429f90 +m_star_count__9daPyMng_c=80429f98 +fn_800b37b0__8dGameComFii=800b37b0 +m_exitMode__10dScStage_c=8042931c +fn_8005f570__9daPyMng_cF16PLAYER_POWERUP_ei=8005f570 +setCarryOverYoshiInfo__9daPyMng_cFUcUci=8005fc20 +mPlayerEntry__9daPyMng_c=80355150 +setPlayer__9daPyMng_cFiP7dAcPy_c=8005f8c0 +__dt__11dPyMdlMng_cFv=800d6ef0 +fn_800d5e00__12dPyMdlBase_cFi=800d5e00 +mspInstance__14dPyEffectMng_c=8042a2d0 +fn_800d2de0__14dPyEffectMng_cFfiR7mVec3_cUc=800d2de0 +checkGroundAngle__5dBc_cFPC7mVec3_cPfPsUcUcScPii=80075820 +AngleToDegreeCoefficient__4mAng=8042dfb8 +fade__Q23mEf13levelEffect_cFv=8016d6b0 +kill__Q23mEf13levelEffect_cFv=8016d6c0 +update__Q23mEf13levelEffect_cFv=8016d580 +createEffect__Q23mEf13levelEffect_cFPCci=8016d2c0 +createEffect__Q23mEf13levelEffect_cFPCcUlPC6mMtx_c=8016d470 +follow__Q23mEf13levelEffect_cFPC6mMtx_c=8016d720 +follow__Q23mEf13levelEffect_cFPC7mVec3_cPC7mAng3_cPC7mVec3_c=8016d6d0 +isActive__Q23mEf13levelEffect_cFv=8016c920 +vfa8__Q23mEf13levelEffect_cFv=8016ce80 +vfac__Q23mEf13levelEffect_cFv=8016cd30 +getCourseInPlayerModelType__9daPyMng_cFUc=8005fbe0 +__ct__11dPyMdlMng_cFQ211dPyMdlMng_c11ModelType_e=800d6db0 +__ct__14dPropelParts_cFv=800d82d0 +__ct__18dPlayerOrchestra_cFv=800d7190 +mKinopioMode__9daPyMng_c=80429fa4 +getWallAttr__5dBc_cFi=80070740 +move__5dPc_cFf=800d2000 +CheckFireBallLimit__19daFireBall_Player_cFii=8011b060 +CheckIceballLimit__11daIceBall_cFii=80124700 +__ct__17dAcPy_HIO_Speed_cFv=8005d7e0 +__dt__17dAcPy_HIO_Speed_cFv=8005d830 +getValue__16dPyMdlBase_HIO_cF14dPyModelData_sUc=8005dc40 +createEffect__Q23mEf13levelEffect_cFPCcUlPC7mVec3_cPC7mAng3_cPC7mVec3_c=8016d3c0 +changeHioType__16dPyMdlBase_HIO_cFUc=8005dc20 +__vt__Q23dEf14dLevelEffect_c=803111d8 +setNextScene__10dScStage_cFUsiQ210dScStage_c6Exit_eQ28dFader_c12fader_type_e=80102370 +moveMissFin__11SndSceneMgrFv=8019c4b0 +createRevivalBallon__11dEnemyMng_cFR7mVec3_cii=800a74c0 +update__18dPlayerOrchestra_cFv=800d71d0 +setRevivalBreakIce__10daPlyIce_cFv=8014b030 +checkRideOffAble__9daYoshi_cFv=8014eb10 +setRideOffPlayer__9daYoshi_cFv=8014ecc0 +startYoshiBGM__9daPyMng_cFv=80060830 +stopYoshiBGM__9daPyMng_cFv=80060860 +addNum__9daPyMng_cFi=8005fdb0 +decNum__9daPyMng_cFi=8005fe30 +mAllBalloon__9daPyMng_c=80429fac +fn_800cab00__11dMarioMdl_cFi=800cab00 +init__18dPlayerOrchestra_cFi=800d71b0 +getEntryNum__9daPyMng_cFv=8005ffb0 +decRest__9daPyMng_cFi=80060600 +fn_8019be60__11SndSceneMgrFi=8019be60 +mTimeUpPlayerNum__9daPyMng_c=80429fa8 +startMissBGM__9daPyMng_cFi=800607d0 +finalizePropelFly__14dPropelParts_cFs=800d8600 +chase__4sLibFPiii=8015f4f0 +copyLinkAnm__12dPyMdlBase_cFf=800d6a30 +getNextDemoNo__13daPyDemoMng_cFv=8005d0c0 +mKinopioCarryCount__9daPyMng_c=80429fcc +fn_8014f030__9daYoshi_cFP7dAcPy_c=8014f030 +demo_ivy_create__11dEnemyMng_cFP7mVec3_c=800a7690 +searchNextNum__7dNext_cFUcffPi=800cff90 +update__14dPropelParts_cFRC6mMtx_c=800d8390 +isMode__14dPropelParts_cFQ214dPropelParts_c6Mode_e=800d85e0 +init__5dBc_cFv=8006cfe0 +isCreateBalloon__9daPyMng_cFi=80061110 +getYoshiColor__9daPyMng_cFUc=8005fc40 +getYoshiFruit__9daPyMng_cFUc=8005fc50 +createYoshi__9daPyMng_cFR7mVec3_ciP7dAcPy_c=8005e9a0 +calc__11dPyMdlMng_cFR6mMtx_c=800d6fa0 +calc__11dPyMdlMng_cF7mVec3_c7mAng3_c7mVec3_c=800d7030 +draw__11dPyMdlMng_cFv=800d7110 +pauseMove__6dAudioFi=8006a7d0 +pauseOffMove__6dAudioFi=8006a7f0 +fn_8014eb70__9daYoshi_cFP7dAcPy_ci=8014eb70 +chkTimer__5dPc_cFv=800d1730 +copyExEffectParam__Q23mEf8effect_cFv=8016d110 +play__11dPyMdlMng_cFv=800d6f80 +stopStarBGM__9daPyMng_cFv=80060750 +createPlayerEffect_change__3dEfFiPQ23dEf14followEffect_cPCcUlPC7mVec3_cPC7mAng3_cPC7mVec3_c=8008fcd0 +startStarBGM__9daPyMng_cFv=80060720 +calc2__11dPyMdlMng_cFv=800d70f0 +rnd__8dGameComFv=800b2f00 +scFireShootFrame__12dPyMdlBase_c=8042cd54 +getUnitKind__5dBc_cFffUc=80070bf0 +fn_8019bd90__11SndSceneMgrFi=8019bd90 +chase__4sLibFPlll=8015f550 +isItemKinopio__7dAcPy_cFv=80038fd0 +isChange__7dAcPy_cFv=8006c400 +getHeadTopPosP__7dAcPy_cFv=800e2640 +OSReport=8015f870 diff --git a/website/doxygen/overrides.js b/website/doxygen/overrides.js index 9c899e32..ce5947ee 100644 --- a/website/doxygen/overrides.js +++ b/website/doxygen/overrides.js @@ -222,7 +222,7 @@ const stateIDList = [...document.querySelectorAll('.memberdecls .memItemRight a' const descriptionElement = document.getElementsByClassName(`memdesc:${id}`); let description = ''; if (descriptionElement.length == 1) { - description = descriptionElement[0].querySelector('.mdescRight').innerText.trim(); + description = descriptionElement[0].querySelector('.mdescRight').innerHTML.trim(); } return { name, description, href, isInherited }; });