From c7be0f3e5f299946a47d366434405eee206cef60 Mon Sep 17 00:00:00 2001 From: c4nvm <164799743+c4nvm@users.noreply.github.com> Date: Fri, 24 Jul 2026 02:14:22 -0400 Subject: [PATCH 1/4] almost --- data/file_list.yml | 78 ++-- src/Player/PlayerActionAirMoveControl.h | 21 +- src/Player/PlayerContinuousJump.h | 4 + src/Player/PlayerStateJump.cpp | 554 ++++++++++++++++++++++++ src/Player/PlayerStateJump.h | 119 +++++ 5 files changed, 736 insertions(+), 40 deletions(-) create mode 100644 src/Player/PlayerStateJump.cpp create mode 100644 src/Player/PlayerStateJump.h diff --git a/data/file_list.yml b/data/file_list.yml index 849ee8c91c..a2dc2be381 100644 --- a/data/file_list.yml +++ b/data/file_list.yml @@ -126879,7 +126879,7 @@ Player/PlayerStateJump.o: label: - _ZN15PlayerStateJumpC1EPN2al9LiveActorEPK11PlayerConstPK19IPlayerModelChangerPK13IUseDimensionPK11PlayerInputPK24PlayerJumpMessageRequestPK6IJudgePK21PlayerCounterForceRunPK24PlayerJointControlKeeperPK19IUsePlayerCollisionP13PlayerTriggerP20PlayerContinuousJumpP14PlayerAnimatorP23PlayerActionDiveInWaterP7HackCapPSI_b - _ZN15PlayerStateJumpC2EPN2al9LiveActorEPK11PlayerConstPK19IPlayerModelChangerPK13IUseDimensionPK11PlayerInputPK24PlayerJumpMessageRequestPK6IJudgePK21PlayerCounterForceRunPK24PlayerJointControlKeeperPK19IUsePlayerCollisionP13PlayerTriggerP20PlayerContinuousJumpP14PlayerAnimatorP23PlayerActionDiveInWaterP7HackCapPSI_b - status: NotDecompiled + status: Wip - offset: 0x470b9c size: 4416 label: _ZN15PlayerStateJump6appearEv @@ -126887,79 +126887,79 @@ Player/PlayerStateJump.o: - offset: 0x471cdc size: 92 label: _ZNK15PlayerStateJump27calcJumpPowerBorderSpeedMinEv - status: NotDecompiled + status: Matching - offset: 0x471d38 size: 92 label: _ZNK15PlayerStateJump27calcJumpPowerBorderSpeedMaxEv - status: NotDecompiled + status: Matching - offset: 0x471d94 size: 176 label: _ZNK15PlayerStateJump16calcJumpPowerMinEv - status: NotDecompiled + status: Matching - offset: 0x471e44 size: 172 label: _ZNK15PlayerStateJump16calcJumpPowerMaxEv - status: NotDecompiled + status: Wip - offset: 0x471ef0 size: 100 label: _ZNK15PlayerStateJump15calcJumpGravityEv - status: NotDecompiled + status: Wip - offset: 0x471f54 size: 320 label: _ZN15PlayerStateJump24tryCountUpContinuousJumpEP20PlayerContinuousJump - status: NotDecompiled + status: Wip - offset: 0x472094 size: 116 label: _ZNK15PlayerStateJump14isJumpCapCatchEv - status: NotDecompiled + status: Matching - offset: 0x472108 size: 92 label: _ZNK15PlayerStateJump16isJumpSpinFlowerEv - status: NotDecompiled + status: Matching - offset: 0x472164 size: 92 label: _ZNK15PlayerStateJump16isJumpSpinGroundEv - status: NotDecompiled + status: Matching - offset: 0x4721c0 size: 16 label: _ZNK15PlayerStateJump25isJumpSpinGroundClockwiseEv - status: NotDecompiled + status: Matching - offset: 0x4721d0 size: 32 label: _ZNK15PlayerStateJump10isJumpBackEv - status: NotDecompiled + status: Matching - offset: 0x4721f0 size: 92 label: _ZNK15PlayerStateJump10isHoveringEv - status: NotDecompiled + status: Matching - offset: 0x47224c size: 200 label: _ZNK15PlayerStateJump21isEndJumpDownFallLandEv - status: NotDecompiled + status: Matching - offset: 0x472314 size: 84 label: _ZNK15PlayerStateJump14isHoldDownFallEv - status: NotDecompiled + status: Matching - offset: 0x472368 size: 144 label: _ZNK15PlayerStateJump20isEnableHipDropStartEv - status: NotDecompiled + status: Matching - offset: 0x4723f8 size: 96 label: _ZNK15PlayerStateJump30isEnableTrampleByHipDropAttackEv - status: NotDecompiled + status: Matching - offset: 0x472458 size: 28 label: _ZNK15PlayerStateJump24isEnableReactionCapCatchEv - status: NotDecompiled + status: Matching - offset: 0x472474 size: 144 label: _ZNK15PlayerStateJump24isEnableCancelCarryThrowEv - status: NotDecompiled + status: Matching - offset: 0x472504 size: 156 label: _ZNK15PlayerStateJump13isFormSquat2DEv - status: NotDecompiled + status: Matching - offset: 0x4725a0 size: 1472 label: _ZN15PlayerStateJump7exeJumpEv @@ -126967,11 +126967,11 @@ Player/PlayerStateJump.o: - offset: 0x472b60 size: 88 label: _ZN15PlayerStateJump22trySubAnimJumpReactionEv - status: NotDecompiled + status: Matching - offset: 0x472bb8 size: 204 label: _ZNK15PlayerStateJump16calcJumpAnimNameEv - status: NotDecompiled + status: Matching - offset: 0x472c84 size: 916 label: _ZN15PlayerStateJump17exeJumpSpinFlowerEv @@ -126979,35 +126979,35 @@ Player/PlayerStateJump.o: - offset: 0x473018 size: 128 label: _ZN15PlayerStateJump25exeJumpSpinFlowerDownFallEv - status: NotDecompiled + status: Matching - offset: 0x473098 size: 600 label: _ZN15PlayerStateJump19updateNerveDownFallEPKcfffPKN2al5NerveE - status: NotDecompiled + status: Wip - offset: 0x4732f0 size: 668 label: _ZN15PlayerStateJump17exeJumpSpinGroundEv - status: NotDecompiled + status: Wip - offset: 0x47358c size: 164 label: _ZN15PlayerStateJump25exeJumpSpinGroundDownFallEv - status: NotDecompiled + status: Matching - offset: 0x473630 size: 764 label: _ZN15PlayerStateJump11exeJumpTurnEv - status: NotDecompiled + status: Wip - offset: 0x47392c size: 668 label: _ZN15PlayerStateJump11exeJumpBackEv - status: NotDecompiled + status: Wip - offset: 0x473bc8 size: 716 label: _ZN15PlayerStateJump17exeHoveringJump2DEv - status: NotDecompiled + status: Wip - offset: 0x473e94 size: 400 label: _ZN15PlayerStateJump13exeHovering2DEv - status: NotDecompiled + status: Wip - offset: 0x474024 size: 36 label: _ZN15PlayerStateJumpD0Ev @@ -127016,47 +127016,47 @@ Player/PlayerStateJump.o: - offset: 0x474048 size: 8 label: _ZNK12_GLOBAL__N_122PlayerStateJumpNrvJump7executeEPN2al11NerveKeeperE - status: NotDecompiled + status: Matching guess: true - offset: 0x474050 size: 8 label: _ZNK12_GLOBAL__N_132PlayerStateJumpNrvHoveringJump2D7executeEPN2al11NerveKeeperE - status: NotDecompiled + status: Matching guess: true - offset: 0x474058 size: 8 label: _ZNK12_GLOBAL__N_132PlayerStateJumpNrvJumpSpinFlower7executeEPN2al11NerveKeeperE - status: NotDecompiled + status: Matching guess: true - offset: 0x474060 size: 8 label: _ZNK12_GLOBAL__N_126PlayerStateJumpNrvJumpBack7executeEPN2al11NerveKeeperE - status: NotDecompiled + status: Matching guess: true - offset: 0x474068 size: 8 label: _ZNK12_GLOBAL__N_126PlayerStateJumpNrvJumpTurn7executeEPN2al11NerveKeeperE - status: NotDecompiled + status: Matching guess: true - offset: 0x474070 size: 8 label: _ZNK12_GLOBAL__N_132PlayerStateJumpNrvJumpSpinGround7executeEPN2al11NerveKeeperE - status: NotDecompiled + status: Matching guess: true - offset: 0x474078 size: 128 label: _ZNK12_GLOBAL__N_140PlayerStateJumpNrvJumpSpinFlowerDownFall7executeEPN2al11NerveKeeperE - status: NotDecompiled + status: Matching guess: true - offset: 0x4740f8 size: 164 label: _ZNK12_GLOBAL__N_140PlayerStateJumpNrvJumpSpinGroundDownFall7executeEPN2al11NerveKeeperE - status: NotDecompiled + status: Matching guess: true - offset: 0x47419c size: 8 label: _ZNK12_GLOBAL__N_128PlayerStateJumpNrvHovering2D7executeEPN2al11NerveKeeperE - status: NotDecompiled + status: Matching guess: true Player/PlayerStateJump2D3D.o: '.text': diff --git a/src/Player/PlayerActionAirMoveControl.h b/src/Player/PlayerActionAirMoveControl.h index bd3f795a96..fbfc6fe5b3 100644 --- a/src/Player/PlayerActionAirMoveControl.h +++ b/src/Player/PlayerActionAirMoveControl.h @@ -23,8 +23,27 @@ class PlayerActionAirMoveControl { bool isHoldJumpExtend() const; void calcMoveInput(sead::Vector3f*, const sead::Vector3f&) const; + void set_40(bool value) { _40 = value; } + + void set_42(bool value) { _42 = value; } + + void set_44(s32 value) { _44 = value; } + + void set_48(f32 value) { _48 = value; } + + f32 get_64() const { return _64; } + private: - void* filler[0x90 / 8]; + u8 _0[0x40]; + bool _40; + u8 _41; + bool _42; + u8 _43; + s32 _44; + f32 _48; + u8 _4c[0x64 - 0x4c]; + f32 _64; + u8 _68[0x90 - 0x68]; }; static_assert(sizeof(PlayerActionAirMoveControl) == 0x90); diff --git a/src/Player/PlayerContinuousJump.h b/src/Player/PlayerContinuousJump.h index 40ea47b2e0..9d2d92898d 100644 --- a/src/Player/PlayerContinuousJump.h +++ b/src/Player/PlayerContinuousJump.h @@ -11,6 +11,10 @@ class PlayerContinuousJump { void clear(); void countUp(const sead::Vector3f& jumpDir); + u32 getCount() const { return mCount; } + + const sead::Vector3f& getLastJumpDir() const { return mLastJumpDir; } + private: const PlayerConst* mConst; u32 mCount = 0; diff --git a/src/Player/PlayerStateJump.cpp b/src/Player/PlayerStateJump.cpp new file mode 100644 index 0000000000..f1434eb6d3 --- /dev/null +++ b/src/Player/PlayerStateJump.cpp @@ -0,0 +1,554 @@ +#include "Player/PlayerStateJump.h" + +#include "Library/Base/StringUtil.h" +#include "Library/LiveActor/ActorActionFunction.h" +#include "Library/LiveActor/ActorMovementFunction.h" +#include "Library/LiveActor/ActorPoseUtil.h" +#include "Library/Math/MathUtil.h" +#include "Library/Nerve/NerveSetupUtil.h" +#include "Library/Nerve/NerveUtil.h" + +#include "Player/IPlayerModelChanger.h" +#include "Player/PlayerActionAirMoveControl.h" +#include "Player/PlayerActionDiveInWater.h" +#include "Player/PlayerAnimator.h" +#include "Player/PlayerConst.h" +#include "Player/PlayerContinuousJump.h" +#include "Player/PlayerCounterForceRun.h" +#include "Player/PlayerInput.h" +#include "Player/PlayerTrigger.h" +#include "Util/ActorDimensionUtil.h" +#include "Util/JudgeUtil.h" +#include "Util/ObjUtil.h" +#include "Util/PlayerCollisionUtil.h" + +namespace { +NERVE_IMPL(PlayerStateJump, Jump); +NERVE_IMPL(PlayerStateJump, HoveringJump2D); +NERVE_IMPL(PlayerStateJump, JumpSpinFlower); +NERVE_IMPL(PlayerStateJump, JumpBack); +NERVE_IMPL(PlayerStateJump, JumpTurn); +NERVE_IMPL(PlayerStateJump, JumpSpinGround); +NERVE_IMPL(PlayerStateJump, JumpSpinFlowerDownFall); +NERVE_IMPL(PlayerStateJump, JumpSpinGroundDownFall); +NERVE_IMPL(PlayerStateJump, Hovering2D); + +NERVES_MAKE_STRUCT(PlayerStateJump, Jump, HoveringJump2D, JumpSpinFlower, JumpBack, JumpTurn, + JumpSpinGround, JumpSpinFlowerDownFall, JumpSpinGroundDownFall, Hovering2D); +} // namespace + +PlayerStateJump::PlayerStateJump(al::LiveActor* player, const PlayerConst* pConst, + const IPlayerModelChanger* modelChanger, + const IUseDimension* dimension, const PlayerInput* input, + const PlayerJumpMessageRequest* jumpMessageRequest, + const IJudge* judgeCapCatchJump, + const PlayerCounterForceRun* counterForceRun, + const PlayerJointControlKeeper* jointControlKeeper, + const IUsePlayerCollision* collider, PlayerTrigger* trigger, + PlayerContinuousJump* continuousJump, PlayerAnimator* animator, + PlayerActionDiveInWater* actionDiveInWater, HackCap* hackCap, + IJudge* judgeWallCatch, bool isEnableCapJumpSlowly) + : al::ActorStateBase("ジャンプ", player), mConst(pConst), mModelChanger(modelChanger), + mDimension(dimension), mJumpMessageRequest(jumpMessageRequest), + mJudgeCapCatchJump(judgeCapCatchJump), mCounterForceRun(counterForceRun), + mJointControlKeeper(jointControlKeeper), mCollider(collider), mAnimator(animator), + mContinuousJump(continuousJump), mTrigger(trigger), mDiveInWater(actionDiveInWater), + mHackCap(hackCap), mJudgeWallCatch(judgeWallCatch), + mIsEnableCapJumpSlowly(isEnableCapJumpSlowly), mInput(input) { + mAirMoveControl = new PlayerActionAirMoveControl(player, pConst, input, collider, false); + mAirMoveControl->set_40(true); + mAirMoveControl->set_42(true); + mAirMoveControl->set_44(0); + mAirMoveControl->set_48(pConst->getJumpBaseSpeedMax()); + initNerve(&NrvPlayerStateJump.Jump, 0); +} + +f32 PlayerStateJump::calcJumpPowerBorderSpeedMin() const { + const IUseDimension* dimension = mDimension; + bool is2D = mModelChanger->is2DModel() && rs::isIn2DArea(dimension); + return is2D ? mConst->getJumpPowerMinBorder2D() : mConst->getNormalMinSpeed(); +} + +f32 PlayerStateJump::calcJumpPowerBorderSpeedMax() const { + const IUseDimension* dimension = mDimension; + bool is2D = mModelChanger->is2DModel() && rs::isIn2DArea(dimension); + return is2D ? mConst->getJumpPowerMaxBorder2D() : mConst->getNormalMaxSpeed(); +} + +f32 PlayerStateJump::calcJumpPowerMin() const { + const IUseDimension* dimension = mDimension; + if (mModelChanger->is2DModel() && rs::isIn2DArea(dimension)) + return mConst->getJumpPowerMin2DArea(); + if (mCounterForceRun->isForceRun()) + return mConst->getJumpPowerForceRun(); + switch (mContinuousJumpCount) { + case 0: + return mConst->getJumpPowerMin(); + case 1: + return mConst->getContinuousJumpPowerMin(); + case 2: + return mConst->getContinuousJumpPowerMin(); + default: + return mConst->getJumpPowerMax(); + } +} + +f32 PlayerStateJump::calcJumpPowerMax() const { + const IUseDimension* dimension = mDimension; + if (mModelChanger->is2DModel() && rs::isIn2DArea(dimension)) + return mConst->getJumpPowerMax2DArea(); + if (mCounterForceRun->isForceRun()) + return mConst->getJumpPowerForceRun(); + switch (mContinuousJumpCount) { + case 1: + return mConst->getJumpPowerMax2nd(); + case 2: + return mConst->getJumpPowerMax3rd(); + default: + return mConst->getJumpPowerMax(); + } +} + +f32 PlayerStateJump::calcJumpGravity() const { + if (mCounterForceRun->isForceRun()) + return mConst->getJumpGravityForceRun(); + switch (mContinuousJumpCount) { + case 1: + return mConst->getJumpGravity2nd(); + case 2: + return mConst->getJumpGravity3rd(); + default: + return mConst->getJumpGravity(); + } +} + +void PlayerStateJump::tryCountUpContinuousJump(PlayerContinuousJump* continuousJump) { + if (!mIsContinuousJump || mModelChanger->is2DModel()) { + continuousJump->clear(); + return; + } + + sead::Vector3f jumpDir = {0.0f, 0.0f, 0.0f}; + al::verticalizeVec(&jumpDir, al::getGravity(mActor), al::getVelocity(mActor)); + al::tryNormalizeOrZero(&jumpDir); + + if (continuousJump->getCount() != 0) { + f32 jumpPower = mJumpPower; + f32 jumpPowerBorder = mConst->getJumpPowerMax() * 0.99f; + f32 dot = jumpDir.dot(continuousJump->getLastJumpDir()); + // 6.123032e-17f is cos(90°), 0.70710678f is cos(45°) + bool isInAngle = mIsEnableCapJumpSlowly ? dot >= 6.123032e-17f : dot >= 0.70710678f; + if (jumpPower < jumpPowerBorder || !isInAngle) { + continuousJump->clear(); + return; + } + } + + continuousJump->countUp(jumpDir); +} + +bool PlayerStateJump::isJumpCapCatch() const { + return !isDead() && al::isNerve(this, &NrvPlayerStateJump.Jump) && + mAnimator->isAnim("JumpCapCatch"); +} + +bool PlayerStateJump::isJumpSpinFlower() const { + return !isDead() && (al::isNerve(this, &NrvPlayerStateJump.JumpSpinFlower) || + al::isNerve(this, &NrvPlayerStateJump.JumpSpinFlowerDownFall)); +} + +bool PlayerStateJump::isJumpSpinGround() const { + return !isDead() && (al::isNerve(this, &NrvPlayerStateJump.JumpSpinGround) || + al::isNerve(this, &NrvPlayerStateJump.JumpSpinGroundDownFall)); +} + +bool PlayerStateJump::isJumpSpinGroundClockwise() const { + return al::isEqualString(mAnimName, "SpinJumpR"); +} + +bool PlayerStateJump::isJumpBack() const { + return !isDead() && al::isNerve(this, &NrvPlayerStateJump.JumpBack); +} + +bool PlayerStateJump::isHovering() const { + return !isDead() && (al::isNerve(this, &NrvPlayerStateJump.Hovering2D) || + al::isNerve(this, &NrvPlayerStateJump.HoveringJump2D)); +} + +bool PlayerStateJump::isEndJumpDownFallLand() const { + if (!al::isNerve(this, &NrvPlayerStateJump.JumpSpinFlowerDownFall) && + !al::isNerve(this, &NrvPlayerStateJump.JumpSpinGroundDownFall)) + return false; + if (!mIsDownFall) + return true; + if (!rs::isCollidedGround(mCollider)) + return false; + sead::Vector3f groundPos = rs::getCollidedGroundPos(mCollider); + const sead::Vector3f& gravity = al::getGravity(mActor); + return (groundPos - mDownFallStartPos).dot(gravity) > 10.0f; +} + +bool PlayerStateJump::isHoldDownFall() const { + if (!al::isNerve(this, &NrvPlayerStateJump.JumpSpinFlowerDownFall) && + !al::isNerve(this, &NrvPlayerStateJump.JumpSpinGroundDownFall)) + return false; + return mInput->isHoldHipDrop(); +} + +bool PlayerStateJump::isEnableHipDropStart() const { + if (isJumpSpinGround()) + return false; + if (isJumpSpinFlower()) + return false; + return true; +} + +bool PlayerStateJump::isEnableTrampleByHipDropAttack() const { + if (isDead()) + return false; + if (!al::isNerve(this, &NrvPlayerStateJump.JumpSpinFlowerDownFall) && + !al::isNerve(this, &NrvPlayerStateJump.JumpSpinGroundDownFall)) + return false; + return mHipDropAttackCount == 0; +} + +bool PlayerStateJump::isEnableReactionCapCatch() const { + return !isDead() && al::isNerve(this, &NrvPlayerStateJump.Jump); +} + +bool PlayerStateJump::isEnableCancelCarryThrow() const { + if (isJumpSpinFlower()) + return true; + if (isJumpSpinGround()) + return true; + return false; +} + +bool PlayerStateJump::isFormSquat2D() const { + if (isDead()) + return false; + if (!mModelChanger->is2DModel()) + return false; + if (mSubAnimName) + return al::isEqualString(mSubAnimName, "JumpSquat"); + return mAnimator->isAnim("JumpSquat"); +} + +bool PlayerStateJump::trySubAnimJumpReaction() { + if (!mAnimator->isSubAnimPlaying()) + return false; + + if (mIsJumpMessageRequest) { + mAnimator->endSubAnim(); + return false; + } + + al::startHitReaction(mActor, "アクションジャンプ"); + return true; +} + +const char* PlayerStateJump::calcJumpAnimName() const { + if (mModelChanger->is2DModel()) + return mSubAnimName ? mSubAnimName : "Jump"; + + if (mAnimName) + return mAnimName; + + switch (mContinuousJumpCount) { + case 0: + if (mAnimator->isSubAnimPlaying()) + return rs::isPlayerSideFaceToCameraZ(mActor) ? "JumpInterp" : "JumpReverseInterp"; + return rs::isPlayerSideFaceToCameraZ(mActor) ? "Jump" : "JumpReverse"; + case 1: + return "Jump2"; + case 2: + return "Jump3"; + default: + return "Jump"; + } +} + +void PlayerStateJump::exeJumpSpinFlowerDownFall() { + updateNerveDownFall("SpinJumpDownFall", mConst->getSpinFlowerJumpDownFallInitSpeed(), + mConst->getSpinFlowerJumpDownFallPower(), + mConst->getSpinFlowerJumpDownFallSpeedMax(), + &NrvPlayerStateJump.JumpSpinFlower); +} + +void PlayerStateJump::updateNerveDownFall(const char* animName, f32 initSpeed, f32 gravity, + f32 fallSpeedMax, const al::Nerve* nerve) { + al::LiveActor* actor = mActor; + + if (al::isFirstStep(this)) { + mAnimator->startAnim(animName); + al::setVelocityToGravity(actor, initSpeed); + _b6 = true; + } + + al::addVelocityToGravityLimit(actor, gravity, fallSpeedMax); + + if (al::isGreaterEqualStep(this, mConst->getDownFallFrameMin()) && !mInput->isHoldHipDrop()) { + if (rs::isOnGround(actor, mCollider)) + kill(); + else + al::setNerve(this, nerve); + return; + } + + if (mTrigger->isOn(PlayerTrigger::ECollisionTrigger_val1)) { + mHipDropAttackCount = mConst->getHipDropMsgInterval(); + mIsDownFall = false; + if (rs::isCollidedGround(mCollider)) { + mIsDownFall = true; + mDownFallStartPos = rs::getCollidedGroundPos(mCollider); + } + } + + if (mHipDropAttackCount > 0) { + if (rs::convergeOnGroundCount(&mHipDropAttackCount, actor, mCollider, 0, 1)) + return; + mHipDropAttackCount = 0; + } + + if (!rs::isOnGround(actor, mCollider)) + return; + + if (mInput->isHoldHipDrop() && mInput->isMoveDeepDown()) { + sead::Vector3f moveDir = {0.0f, 0.0f, 0.0f}; + mInput->calcMoveDirection(&moveDir, -al::getGravity(actor)); + sead::Vector3f groundNormal = rs::getCollidedGroundNormal(mCollider); + rs::slerpUpFront(actor, groundNormal, moveDir, mConst->getSlerpQuatRate(), + mConst->getHillPoseDegreeMax()); + } + + kill(); +} + +void PlayerStateJump::exeJumpSpinGroundDownFall() { + const char* animName = isJumpSpinGroundClockwise() ? "SpinJumpDownFallR" : "SpinJumpDownFallL"; + updateNerveDownFall(animName, mConst->getSpinJumpDownFallInitSpeed(), + mConst->getSpinJumpDownFallPower(), mConst->getSpinJumpDownFallSpeedMax(), + &NrvPlayerStateJump.JumpSpinGround); +} + +void PlayerStateJump::exeHovering2D() { + if (!mModelChanger->is2DModel()) { + kill(); + return; + } + + al::LiveActor* actor = mActor; + f32 maxSpeed; + if (mModelChanger->is2DModel()) + maxSpeed = mConst->getNormalMaxSpeed(); + else + maxSpeed = mConst->getNormalMaxSpeed2D(); + rs::scaleVelocityInertiaWallHit(actor, mCollider, 0.25f, 1.0f, maxSpeed); + + if (al::isFirstStep(this)) { + mAnimator->startAnim("Hovering"); + sead::Vector3f* velocity = al::getVelocityPtr(actor); + al::verticalizeVec(velocity, al::getGravity(actor), *velocity); + mAirMoveControl->setup(mMoveSpeedMax, mConst->getNormalMaxSpeed2D(), 0, 0.0f, 0.0f, 0, + 0.0f); + } + + mAirMoveControl->update(); + + if (rs::isOnGround(actor, mCollider) || !mInput->isHoldCapSeparateJump() || + al::isGreaterEqualStep(this, 60)) + kill(); +} + +void PlayerStateJump::exeJumpBack() { + al::LiveActor* actor = mActor; + + if (al::isFirstStep(this)) { + trySubAnimJumpReaction(); + mAnimator->startAnim("JumpBack"); + + sead::Vector3f frontDir = {0.0f, 0.0f, 0.0f}; + al::calcFrontDir(&frontDir, actor); + al::verticalizeVec(&frontDir, al::getGravity(actor), frontDir); + al::tryNormalizeOrZero(&frontDir); + + sead::Vector3f velocity = + -(frontDir * mConst->getSquatJumpBackPower() + al::getGravity(actor) * mJumpPower); + al::setVelocity(actor, velocity); + } + + if (mTrigger->isOnUpperPunchHit()) { + rs::reflectCeilingUpperPunch(actor, mCollider, mInput, mConst, mTrigger, false); + mIsContinuousJump = false; + } + + if (rs::isCollidedCeiling(mCollider)) { + rs::reflectCeiling(actor, 0.0f); + mIsContinuousJump = false; + } + + sead::Vector3f moveInput = {0.0f, 0.0f, 0.0f}; + mInput->calcMoveInput(&moveInput, -al::getGravity(actor)); + + rs::moveParallelJump(actor, moveInput, mConst->getSquatJumpMovePowerFront(), + mConst->getSquatJumpMovePowerFront(), mConst->getSquatJumpMovePowerSide(), + mConst->getSquatJumpMoveSpeedMax(), mJumpGravity, + mConst->getFallSpeedMax(), mConst->getSlerpQuatGrav()); + + if (rs::isOnGround(actor, mCollider)) + kill(); +} + +void PlayerStateJump::exeJumpSpinGround() { + al::LiveActor* actor = mActor; + + f32 maxSpeed; + if (mModelChanger->is2DModel()) + maxSpeed = mConst->getNormalMaxSpeed(); + else + maxSpeed = mConst->getNormalMaxSpeed2D(); + rs::scaleVelocityInertiaWallHit(actor, mCollider, 0.25f, 1.0f, maxSpeed); + + if (al::isFirstStep(this)) { + trySubAnimJumpReaction(); + + const char* format = _b6 ? "Restart%s" : "Start%s"; + mAnimator->startAnim(al::StringTmp<64>(format, mAnimName)); + + mAirMoveControl->setup(mMoveSpeedMax, mConst->getNormalMaxSpeed(), 0, mJumpPower, + mJumpGravity, 0, mConst->getJumpInertiaRate()); + + if (_b6) + al::setVelocityToGravity(actor, mConst->getFallSpeedMax()); + } + + if (mTrigger->isOnUpperPunchHit()) { + rs::reflectCeilingUpperPunch(actor, mCollider, mInput, mConst, mTrigger, false); + mIsContinuousJump = false; + } + + if (rs::isCollidedCeiling(mCollider)) { + rs::reflectCeiling(actor, 0.0f); + mIsContinuousJump = false; + } + + mAirMoveControl->update(); + + if (mInput->isTriggerHipDrop()) { + al::setNerve(this, &NrvPlayerStateJump.JumpSpinGroundDownFall); + return; + } + + if (rs::isOnGround(actor, mCollider)) { + sead::Vector3f horizontalVel = {0.0f, 0.0f, 0.0f}; + sead::Vector3f verticalVel = {0.0f, 0.0f, 0.0f}; + al::separateVelocityHV(&horizontalVel, &verticalVel, actor); + f32 speed = sead::Mathf::min(horizontalVel.length(), mAirMoveControl->get_64()); + al::limitLength(&horizontalVel, horizontalVel, speed); + al::setVelocity(actor, horizontalVel + verticalVel); + kill(); + } +} + +void PlayerStateJump::exeHoveringJump2D() { + if (!mModelChanger->is2DModel()) { + kill(); + return; + } + + al::LiveActor* actor = mActor; + + f32 maxSpeed; + if (mModelChanger->is2DModel()) + maxSpeed = mConst->getNormalMaxSpeed(); + else + maxSpeed = mConst->getNormalMaxSpeed2D(); + rs::scaleVelocityInertiaWallHit(actor, mCollider, 0.25f, 1.0f, maxSpeed); + + if (al::isFirstStep(this)) { + mAnimator->startAnim("Hovering"); + mAirMoveControl->setup(mMoveSpeedMax, mConst->getNormalMaxSpeed2D(), 0, 20.0f, 2.0f, 0, + 0.0f); + } + + if (mTrigger->isOnUpperPunchHit()) { + rs::reflectCeilingUpperPunch(actor, mCollider, mInput, mConst, mTrigger, true); + mAirMoveControl->setExtendFrame(0); + mIsContinuousJump = false; + } + + bool onGround = rs::isOnGround(actor, mCollider); + + if (rs::isCollidedCeiling(mCollider) && !al::isFirstStep(this)) { + rs::reflectCeiling(actor, 0.0f); + mAirMoveControl->setExtendFrame(0); + mIsContinuousJump = false; + } + + if (mModelChanger->is2DModel() && rs::isIn2DArea(mDimension)) { + sead::Vector3f lockDir = {0.0f, 0.0f, 0.0f}; + rs::calcLockDirection(&lockDir, mDimension); + mAirMoveControl->verticalizeStartMoveDir(lockDir); + } + + mAirMoveControl->update(); + + if (onGround) { + sead::Vector3f horizontalVel = {0.0f, 0.0f, 0.0f}; + sead::Vector3f verticalVel = {0.0f, 0.0f, 0.0f}; + al::separateVelocityHV(&horizontalVel, &verticalVel, actor); + f32 speed = sead::Mathf::min(horizontalVel.length(), mAirMoveControl->get_64()); + al::limitLength(&horizontalVel, horizontalVel, speed); + al::setVelocity(actor, horizontalVel + verticalVel); + kill(); + } else if (rs::updateJudgeAndResult(mJudgeWallCatch) || al::calcSpeedV(actor) < 0.0f) { + al::setNerve(this, &NrvPlayerStateJump.Hovering2D); + } +} + +void PlayerStateJump::exeJumpTurn() { + al::LiveActor* actor = mActor; + + if (al::isFirstStep(this)) { + trySubAnimJumpReaction(); + + sead::Vector3f upDir = {0.0f, 0.0f, 0.0f}; + al::calcUpDir(&upDir, actor); + sead::Quatf quat = sead::Quatf::unit; + al::makeQuatFrontUp(&quat, mTurnDir, upDir); + al::updatePoseQuat(actor, quat); + + sead::Vector3f dir = {0.0f, 0.0f, 0.0f}; + al::verticalizeVec(&dir, al::getGravity(actor), mTurnDir); + if (!al::tryNormalizeOrZero(&dir)) + dir = upDir; + + al::setVelocity(actor, dir * mConst->getTurnJumpVelH()); + al::addVelocityToGravity(actor, -mJumpPower); + mAnimator->startAnim("JumpTurn"); + } + + if (mTrigger->isOnUpperPunchHit()) { + rs::reflectCeilingUpperPunch(actor, mCollider, mInput, mConst, mTrigger, false); + mIsContinuousJump = false; + } + + if (rs::isCollidedCeiling(mCollider)) { + rs::reflectCeiling(actor, 0.0f); + mIsContinuousJump = false; + } + + mDiveInWater->tryChangeDiveInWaterAnim(); + + sead::Vector3f moveInput = {0.0f, 0.0f, 0.0f}; + mInput->calcMoveInput(&moveInput, -al::getGravity(actor)); + + rs::moveDivingJump(actor, moveInput, mConst->getTurnJumpAccel(), mConst->getTurnJumpBrake(), + mConst->getTurnJumpVelH(), 0.0f, mConst->getTurnJumpSideAccel(), mJumpGravity, + mConst->getFallSpeedMax(), 0.0f); + + rs::slerpUp(actor, -al::getGravity(actor), mConst->getSlerpQuatGrav(), 180.0f); + + if (rs::isOnGround(actor, mCollider)) + kill(); +} diff --git a/src/Player/PlayerStateJump.h b/src/Player/PlayerStateJump.h new file mode 100644 index 0000000000..168ee4abe8 --- /dev/null +++ b/src/Player/PlayerStateJump.h @@ -0,0 +1,119 @@ +#pragma once + +#include +#include + +#include "Library/Nerve/NerveStateBase.h" + +namespace al { +class Nerve; +} // namespace al + +class HackCap; +class IJudge; +class IPlayerModelChanger; +class IUseDimension; +class IUsePlayerCollision; +class PlayerActionAirMoveControl; +class PlayerActionDiveInWater; +class PlayerAnimator; +class PlayerConst; +class PlayerContinuousJump; +class PlayerCounterForceRun; +class PlayerInput; +class PlayerJointControlKeeper; +class PlayerTrigger; +struct PlayerJumpMessageRequest; + +class PlayerStateJump : public al::ActorStateBase { +public: + PlayerStateJump(al::LiveActor* player, const PlayerConst* pConst, + const IPlayerModelChanger* modelChanger, const IUseDimension* dimension, + const PlayerInput* input, const PlayerJumpMessageRequest* jumpMessageRequest, + const IJudge* judgeCapCatchJump, const PlayerCounterForceRun* counterForceRun, + const PlayerJointControlKeeper* jointControlKeeper, + const IUsePlayerCollision* collider, PlayerTrigger* trigger, + PlayerContinuousJump* continuousJump, PlayerAnimator* animator, + PlayerActionDiveInWater* actionDiveInWater, HackCap* hackCap, + IJudge* judgeWallCatch, bool isEnableCapJumpSlowly); + + void appear() override; + + f32 calcJumpPowerBorderSpeedMin() const; + f32 calcJumpPowerBorderSpeedMax() const; + f32 calcJumpPowerMin() const; + f32 calcJumpPowerMax() const; + f32 calcJumpGravity() const; + void tryCountUpContinuousJump(PlayerContinuousJump* continuousJump); + + bool isJumpCapCatch() const; + bool isJumpSpinFlower() const; + bool isJumpSpinGround() const; + bool isJumpSpinGroundClockwise() const; + bool isJumpBack() const; + bool isHovering() const; + bool isEndJumpDownFallLand() const; + bool isHoldDownFall() const; + bool isEnableHipDropStart() const; + bool isEnableTrampleByHipDropAttack() const; + bool isEnableReactionCapCatch() const; + bool isEnableCancelCarryThrow() const; + bool isFormSquat2D() const; + + void exeJump(); + bool trySubAnimJumpReaction(); + const char* calcJumpAnimName() const; + void exeJumpSpinFlower(); + void exeJumpSpinFlowerDownFall(); + void updateNerveDownFall(const char* animName, f32 animFrame, f32 gravity, f32 fallSpeedMax, + const al::Nerve* nerve); + void exeJumpSpinGround(); + void exeJumpSpinGroundDownFall(); + void exeJumpTurn(); + void exeJumpBack(); + void exeHoveringJump2D(); + void exeHovering2D(); + +private: + const PlayerConst* mConst; + const IPlayerModelChanger* mModelChanger; + const IUseDimension* mDimension; + const PlayerJumpMessageRequest* mJumpMessageRequest; + const IJudge* mJudgeCapCatchJump; + const PlayerCounterForceRun* mCounterForceRun; + const PlayerJointControlKeeper* mJointControlKeeper; + const IUsePlayerCollision* mCollider; + PlayerAnimator* mAnimator; + PlayerContinuousJump* mContinuousJump; + PlayerTrigger* mTrigger; + PlayerActionDiveInWater* mDiveInWater; + PlayerActionAirMoveControl* mAirMoveControl = nullptr; + HackCap* mHackCap; + IJudge* mJudgeWallCatch; + bool mIsEnableCapJumpSlowly; + s32 mExtendFrame = 0; + f32 mJumpPower = 0.0f; + f32 mMoveSpeedMax = 0.0f; + f32 mJumpGravity = 0.0f; + s32 _ac = 0; + s32 mContinuousJumpCount = 0; + bool mIsContinuousJump = false; + bool _b5 = false; + bool _b6 = false; + bool _b7 = false; + bool mIsJumpMessageRequest = false; + bool _b9 = false; + bool _ba = false; + s32 _bc = 0; + s32 _c0 = 0; + s32 _c4 = 0; + const char* mAnimName = nullptr; + const char* mSubAnimName = nullptr; + const PlayerInput* mInput; + sead::Vector3f mTurnDir = {0.0f, 0.0f, 0.0f}; + s32 mHipDropAttackCount = 0; + bool mIsDownFall = false; + sead::Vector3f mDownFallStartPos = {0.0f, 0.0f, 0.0f}; +}; + +static_assert(sizeof(PlayerStateJump) == 0x100); From 46881fb8e372eaf18c4818cd1674c4de8c82cd63 Mon Sep 17 00:00:00 2001 From: c4nvm <164799743+c4nvm@users.noreply.github.com> Date: Fri, 24 Jul 2026 12:54:09 -0400 Subject: [PATCH 2/4] so close --- data/file_list.yml | 10 +- src/Player/PlayerStateJump.cpp | 192 ++++++++++++++++++++++++++++++--- src/Player/PlayerStateJump.h | 4 +- 3 files changed, 183 insertions(+), 23 deletions(-) diff --git a/data/file_list.yml b/data/file_list.yml index a2dc2be381..38c416b638 100644 --- a/data/file_list.yml +++ b/data/file_list.yml @@ -126963,7 +126963,7 @@ Player/PlayerStateJump.o: - offset: 0x4725a0 size: 1472 label: _ZN15PlayerStateJump7exeJumpEv - status: NotDecompiled + status: Wip - offset: 0x472b60 size: 88 label: _ZN15PlayerStateJump22trySubAnimJumpReactionEv @@ -126975,7 +126975,7 @@ Player/PlayerStateJump.o: - offset: 0x472c84 size: 916 label: _ZN15PlayerStateJump17exeJumpSpinFlowerEv - status: NotDecompiled + status: Matching - offset: 0x473018 size: 128 label: _ZN15PlayerStateJump25exeJumpSpinFlowerDownFallEv @@ -126983,7 +126983,7 @@ Player/PlayerStateJump.o: - offset: 0x473098 size: 600 label: _ZN15PlayerStateJump19updateNerveDownFallEPKcfffPKN2al5NerveE - status: Wip + status: Matching - offset: 0x4732f0 size: 668 label: _ZN15PlayerStateJump17exeJumpSpinGroundEv @@ -126995,11 +126995,11 @@ Player/PlayerStateJump.o: - offset: 0x473630 size: 764 label: _ZN15PlayerStateJump11exeJumpTurnEv - status: Wip + status: Matching - offset: 0x47392c size: 668 label: _ZN15PlayerStateJump11exeJumpBackEv - status: Wip + status: Matching - offset: 0x473bc8 size: 716 label: _ZN15PlayerStateJump17exeHoveringJump2DEv diff --git a/src/Player/PlayerStateJump.cpp b/src/Player/PlayerStateJump.cpp index f1434eb6d3..b045364132 100644 --- a/src/Player/PlayerStateJump.cpp +++ b/src/Player/PlayerStateJump.cpp @@ -8,6 +8,7 @@ #include "Library/Nerve/NerveSetupUtil.h" #include "Library/Nerve/NerveUtil.h" +#include "Player/HackCap.h" #include "Player/IPlayerModelChanger.h" #include "Player/PlayerActionAirMoveControl.h" #include "Player/PlayerActionDiveInWater.h" @@ -234,6 +235,104 @@ bool PlayerStateJump::isFormSquat2D() const { return mAnimator->isAnim("JumpSquat"); } +void PlayerStateJump::exeJump() { + al::LiveActor* actor = mActor; + + f32 maxSpeed; + if (mModelChanger->is2DModel()) + maxSpeed = mConst->getNormalMaxSpeed(); + else + maxSpeed = mConst->getNormalMaxSpeed2D(); + rs::scaleVelocityInertiaWallHit(actor, mCollider, 0.25f, 1.0f, maxSpeed); + + if (al::isFirstStep(this)) { + trySubAnimJumpReaction(); + + if (_b9 && mAnimator->isUpperBodyAnimAttached()) + mAnimator->clearUpperBodyAnim(); + + const char* animName = calcJumpAnimName(); + + if (!_b5) + mAnimator->startAnim(animName); + + if (al::isEqualString(animName, "JumpCapCatch")) + mHackCap->startCatch("JumpCapCatch", false, sead::Vector3f::zero); + + if (_b7 && !mModelChanger->is2DModel()) { + sead::Vector3f upDir = {0.0f, 0.0f, 0.0f}; + al::calcUpDir(&upDir, actor); + if (mUpDir.dot(upDir) <= + sead::Mathf::cos(sead::Mathf::deg2rad(mConst->getCollisionResetLimit()))) + mTrigger->set(PlayerTrigger::EActionTrigger_val3); + rs::slerpUp(actor, mUpDir, 1.0f, 180.0f); + } + + mAirMoveControl->setup(mMoveSpeedMax, + mModelChanger->is2DModel() ? mConst->getNormalMaxSpeed2D() + : mConst->getNormalMaxSpeed(), + mExtendFrame, mJumpPower, mJumpGravity, 0, + mConst->getJumpInertiaRate()); + } + + if (mTrigger->isOnUpperPunchHit()) { + if (mModelChanger->is2DModel()) { + rs::reflectCeilingUpperPunch(mActor, mCollider, mInput, mConst, mTrigger, true); + } else { + mAnimator->startAnim("Jump"); + mAnimator->setAnimFrame(mAnimator->getAnimFrameMax()); + rs::reflectCeilingUpperPunch(mActor, mCollider, mInput, mConst, mTrigger, false); + } + mAirMoveControl->setExtendFrame(0); + mIsContinuousJump = false; + } + + bool onGround; + if (mCounterForceRun->isForceRun()) + onGround = rs::isOnGroundAndGravity(actor, mCollider); + else + onGround = rs::isOnGround(actor, mCollider); + + if (rs::isCollidedCeiling(mCollider) && !al::isFirstStep(this)) { + rs::reflectCeiling(mActor, 0.0f); + mAirMoveControl->setExtendFrame(0); + mIsContinuousJump = false; + } + + if (mModelChanger->is2DModel() && rs::isIn2DArea(mDimension)) { + sead::Vector3f lockDir = {0.0f, 0.0f, 0.0f}; + rs::calcLockDirection(&lockDir, mDimension); + mAirMoveControl->verticalizeStartMoveDir(lockDir); + } + + mDiveInWater->tryChangeDiveInWaterAnim(); + mAirMoveControl->update(); + + if (onGround) { + sead::Vector3f horizontalVel = {0.0f, 0.0f, 0.0f}; + sead::Vector3f verticalVel = {0.0f, 0.0f, 0.0f}; + al::separateVelocityHV(&horizontalVel, &verticalVel, mActor); + f32 speed = sead::Mathf::min(horizontalVel.length(), mAirMoveControl->get_64()); + al::limitLength(&horizontalVel, horizontalVel, speed); + al::setVelocity(mActor, horizontalVel + verticalVel); + kill(); + } else if (rs::updateJudgeAndResult(mJudgeWallCatch)) { + if (!isDead() && mModelChanger->is2DModel() && + (mSubAnimName ? al::isEqualString(mSubAnimName, "JumpSquat") + : mAnimator->isAnim("JumpSquat"))) { + mTrigger->set(PlayerTrigger::EActionTrigger_val3); + mSubAnimName = nullptr; + } + if (_ba) + al::setNerve(this, &NrvPlayerStateJump.Hovering2D); + else + al::setNerve(this, &NrvPlayerStateJump.HoveringJump2D); + } else { + if (_ba) + _ba = mInput->isHoldCapSeparateJump(); + } +} + bool PlayerStateJump::trySubAnimJumpReaction() { if (!mAnimator->isSubAnimPlaying()) return false; @@ -268,6 +367,69 @@ const char* PlayerStateJump::calcJumpAnimName() const { } } +void PlayerStateJump::exeJumpSpinFlower() { + al::LiveActor* actor = mActor; + + if (al::isFirstStep(this)) { + trySubAnimJumpReaction(); + + sead::Vector3f* velocity = al::getVelocityPtr(actor); + al::verticalizeVec(velocity, al::getGravity(actor), *velocity); + + if (_b6) { + mAnimator->startAnim("SpinJumpLoop"); + al::addVelocityToGravity(actor, mConst->getSpinFlowerJumpFallSpeedMax()); + } else { + mAnimator->startAnim("SpinJumpStart"); + al::addVelocityToGravity(actor, -mJumpPower); + } + } + + if (mAnimator->isAnim("SpinJumpStart") && mAnimator->isAnimEnd()) + mAnimator->startAnim("SpinJumpLoop"); + + if (mTrigger->isOnUpperPunchHit()) { + rs::reflectCeilingUpperPunch(mActor, mCollider, mInput, mConst, mTrigger, false); + mIsContinuousJump = false; + } + + if (rs::isCollidedCeiling(mCollider)) { + rs::reflectCeiling(mActor, 0.0f); + mIsContinuousJump = false; + } + + sead::Vector3f moveInput = {0.0f, 0.0f, 0.0f}; + mInput->calcMoveInput(&moveInput, -al::getGravity(actor)); + + f32 gravity = mConst->getJumpGravity(); + f32 fallSpeedMax = mConst->getSpinFlowerJumpFallSpeedMax(); + if (al::calcSpeedV(actor) < 0.0f || al::isNearZero(al::calcSpeedV(actor))) { + gravity = mConst->getSpinFlowerJumpGravity(); + if (_ac > 0) { + _ac--; + fallSpeedMax = mConst->getSpinFlowerJumpStaySpeedMax(); + } + } else { + _ac = mConst->getSpinFlowerJumpStayFrame(); + } + + rs::moveParallelJump(mActor, moveInput, mConst->getSpinFlowerJumpMovePower(), + mConst->getSpinFlowerJumpMovePower(), mConst->getSpinFlowerJumpMovePower(), + mConst->getSpinFlowerJumpVelMax(), gravity, fallSpeedMax, + mConst->getSlerpQuatGrav()); + + if (!mInput->isMove()) + al::scaleVelocityHV(actor, mConst->getSpinFlowerJumpNoInputBrake(), 1.0f); + + if (mInput->isTriggerHipDrop()) { + al::setNerve(this, &NrvPlayerStateJump.JumpSpinFlowerDownFall); + return; + } + + if (rs::isOnGround(actor, mCollider)) + kill(); +} + void PlayerStateJump::exeJumpSpinFlowerDownFall() { updateNerveDownFall("SpinJumpDownFall", mConst->getSpinFlowerJumpDownFallInitSpeed(), mConst->getSpinFlowerJumpDownFallPower(), @@ -285,7 +447,7 @@ void PlayerStateJump::updateNerveDownFall(const char* animName, f32 initSpeed, f _b6 = true; } - al::addVelocityToGravityLimit(actor, gravity, fallSpeedMax); + al::addVelocityToGravityLimit(mActor, gravity, fallSpeedMax); if (al::isGreaterEqualStep(this, mConst->getDownFallFrameMin()) && !mInput->isHoldHipDrop()) { if (rs::isOnGround(actor, mCollider)) @@ -305,7 +467,7 @@ void PlayerStateJump::updateNerveDownFall(const char* animName, f32 initSpeed, f } if (mHipDropAttackCount > 0) { - if (rs::convergeOnGroundCount(&mHipDropAttackCount, actor, mCollider, 0, 1)) + if (rs::convergeOnGroundCount(&mHipDropAttackCount, mActor, mCollider, 0, 1)) return; mHipDropAttackCount = 0; } @@ -378,19 +540,19 @@ void PlayerStateJump::exeJumpBack() { } if (mTrigger->isOnUpperPunchHit()) { - rs::reflectCeilingUpperPunch(actor, mCollider, mInput, mConst, mTrigger, false); + rs::reflectCeilingUpperPunch(mActor, mCollider, mInput, mConst, mTrigger, false); mIsContinuousJump = false; } if (rs::isCollidedCeiling(mCollider)) { - rs::reflectCeiling(actor, 0.0f); + rs::reflectCeiling(mActor, 0.0f); mIsContinuousJump = false; } sead::Vector3f moveInput = {0.0f, 0.0f, 0.0f}; mInput->calcMoveInput(&moveInput, -al::getGravity(actor)); - rs::moveParallelJump(actor, moveInput, mConst->getSquatJumpMovePowerFront(), + rs::moveParallelJump(mActor, moveInput, mConst->getSquatJumpMovePowerFront(), mConst->getSquatJumpMovePowerFront(), mConst->getSquatJumpMovePowerSide(), mConst->getSquatJumpMoveSpeedMax(), mJumpGravity, mConst->getFallSpeedMax(), mConst->getSlerpQuatGrav()); @@ -423,12 +585,12 @@ void PlayerStateJump::exeJumpSpinGround() { } if (mTrigger->isOnUpperPunchHit()) { - rs::reflectCeilingUpperPunch(actor, mCollider, mInput, mConst, mTrigger, false); + rs::reflectCeilingUpperPunch(mActor, mCollider, mInput, mConst, mTrigger, false); mIsContinuousJump = false; } if (rs::isCollidedCeiling(mCollider)) { - rs::reflectCeiling(actor, 0.0f); + rs::reflectCeiling(mActor, 0.0f); mIsContinuousJump = false; } @@ -442,10 +604,10 @@ void PlayerStateJump::exeJumpSpinGround() { if (rs::isOnGround(actor, mCollider)) { sead::Vector3f horizontalVel = {0.0f, 0.0f, 0.0f}; sead::Vector3f verticalVel = {0.0f, 0.0f, 0.0f}; - al::separateVelocityHV(&horizontalVel, &verticalVel, actor); + al::separateVelocityHV(&horizontalVel, &verticalVel, mActor); f32 speed = sead::Mathf::min(horizontalVel.length(), mAirMoveControl->get_64()); al::limitLength(&horizontalVel, horizontalVel, speed); - al::setVelocity(actor, horizontalVel + verticalVel); + al::setVelocity(mActor, horizontalVel + verticalVel); kill(); } } @@ -472,7 +634,7 @@ void PlayerStateJump::exeHoveringJump2D() { } if (mTrigger->isOnUpperPunchHit()) { - rs::reflectCeilingUpperPunch(actor, mCollider, mInput, mConst, mTrigger, true); + rs::reflectCeilingUpperPunch(mActor, mCollider, mInput, mConst, mTrigger, true); mAirMoveControl->setExtendFrame(0); mIsContinuousJump = false; } @@ -480,7 +642,7 @@ void PlayerStateJump::exeHoveringJump2D() { bool onGround = rs::isOnGround(actor, mCollider); if (rs::isCollidedCeiling(mCollider) && !al::isFirstStep(this)) { - rs::reflectCeiling(actor, 0.0f); + rs::reflectCeiling(mActor, 0.0f); mAirMoveControl->setExtendFrame(0); mIsContinuousJump = false; } @@ -496,10 +658,10 @@ void PlayerStateJump::exeHoveringJump2D() { if (onGround) { sead::Vector3f horizontalVel = {0.0f, 0.0f, 0.0f}; sead::Vector3f verticalVel = {0.0f, 0.0f, 0.0f}; - al::separateVelocityHV(&horizontalVel, &verticalVel, actor); + al::separateVelocityHV(&horizontalVel, &verticalVel, mActor); f32 speed = sead::Mathf::min(horizontalVel.length(), mAirMoveControl->get_64()); al::limitLength(&horizontalVel, horizontalVel, speed); - al::setVelocity(actor, horizontalVel + verticalVel); + al::setVelocity(mActor, horizontalVel + verticalVel); kill(); } else if (rs::updateJudgeAndResult(mJudgeWallCatch) || al::calcSpeedV(actor) < 0.0f) { al::setNerve(this, &NrvPlayerStateJump.Hovering2D); @@ -529,12 +691,12 @@ void PlayerStateJump::exeJumpTurn() { } if (mTrigger->isOnUpperPunchHit()) { - rs::reflectCeilingUpperPunch(actor, mCollider, mInput, mConst, mTrigger, false); + rs::reflectCeilingUpperPunch(mActor, mCollider, mInput, mConst, mTrigger, false); mIsContinuousJump = false; } if (rs::isCollidedCeiling(mCollider)) { - rs::reflectCeiling(actor, 0.0f); + rs::reflectCeiling(mActor, 0.0f); mIsContinuousJump = false; } diff --git a/src/Player/PlayerStateJump.h b/src/Player/PlayerStateJump.h index 168ee4abe8..deb9996057 100644 --- a/src/Player/PlayerStateJump.h +++ b/src/Player/PlayerStateJump.h @@ -104,9 +104,7 @@ class PlayerStateJump : public al::ActorStateBase { bool mIsJumpMessageRequest = false; bool _b9 = false; bool _ba = false; - s32 _bc = 0; - s32 _c0 = 0; - s32 _c4 = 0; + sead::Vector3f mUpDir = {0.0f, 0.0f, 0.0f}; const char* mAnimName = nullptr; const char* mSubAnimName = nullptr; const PlayerInput* mInput; From 8878029601fd2b7e2015b5c0cb0748915ed5790a Mon Sep 17 00:00:00 2001 From: c4nvm <164799743+c4nvm@users.noreply.github.com> Date: Fri, 24 Jul 2026 14:51:34 -0400 Subject: [PATCH 3/4] Player: Implement most of \`PlayerStateJump\ --- data/file_list.yml | 8 ++--- src/Player/PlayerStateJump.cpp | 62 +++++++++++++++------------------- 2 files changed, 32 insertions(+), 38 deletions(-) diff --git a/data/file_list.yml b/data/file_list.yml index 38c416b638..73da721cb6 100644 --- a/data/file_list.yml +++ b/data/file_list.yml @@ -126963,7 +126963,7 @@ Player/PlayerStateJump.o: - offset: 0x4725a0 size: 1472 label: _ZN15PlayerStateJump7exeJumpEv - status: Wip + status: Matching - offset: 0x472b60 size: 88 label: _ZN15PlayerStateJump22trySubAnimJumpReactionEv @@ -126987,7 +126987,7 @@ Player/PlayerStateJump.o: - offset: 0x4732f0 size: 668 label: _ZN15PlayerStateJump17exeJumpSpinGroundEv - status: Wip + status: Matching - offset: 0x47358c size: 164 label: _ZN15PlayerStateJump25exeJumpSpinGroundDownFallEv @@ -127003,11 +127003,11 @@ Player/PlayerStateJump.o: - offset: 0x473bc8 size: 716 label: _ZN15PlayerStateJump17exeHoveringJump2DEv - status: Wip + status: Matching - offset: 0x473e94 size: 400 label: _ZN15PlayerStateJump13exeHovering2DEv - status: Wip + status: Matching - offset: 0x474024 size: 36 label: _ZN15PlayerStateJumpD0Ev diff --git a/src/Player/PlayerStateJump.cpp b/src/Player/PlayerStateJump.cpp index b045364132..cbda6683d1 100644 --- a/src/Player/PlayerStateJump.cpp +++ b/src/Player/PlayerStateJump.cpp @@ -36,6 +36,14 @@ NERVE_IMPL(PlayerStateJump, Hovering2D); NERVES_MAKE_STRUCT(PlayerStateJump, Jump, HoveringJump2D, JumpSpinFlower, JumpBack, JumpTurn, JumpSpinGround, JumpSpinFlowerDownFall, JumpSpinGroundDownFall, Hovering2D); + +static bool isIn2DAreaModel(const IPlayerModelChanger* modelChanger, const IUseDimension* dimension) { + return modelChanger->is2DModel() && rs::isIn2DArea(dimension); +} + +static f32 getNormalMaxSpeed(const PlayerConst* pConst, const IPlayerModelChanger* modelChanger) { + return modelChanger->is2DModel() ? pConst->getNormalMaxSpeed() : pConst->getNormalMaxSpeed2D(); +} } // namespace PlayerStateJump::PlayerStateJump(al::LiveActor* player, const PlayerConst* pConst, @@ -238,12 +246,8 @@ bool PlayerStateJump::isFormSquat2D() const { void PlayerStateJump::exeJump() { al::LiveActor* actor = mActor; - f32 maxSpeed; - if (mModelChanger->is2DModel()) - maxSpeed = mConst->getNormalMaxSpeed(); - else - maxSpeed = mConst->getNormalMaxSpeed2D(); - rs::scaleVelocityInertiaWallHit(actor, mCollider, 0.25f, 1.0f, maxSpeed); + rs::scaleVelocityInertiaWallHit(actor, mCollider, 0.25f, 1.0f, + getNormalMaxSpeed(mConst, mModelChanger)); if (al::isFirstStep(this)) { trySubAnimJumpReaction(); @@ -299,7 +303,7 @@ void PlayerStateJump::exeJump() { mIsContinuousJump = false; } - if (mModelChanger->is2DModel() && rs::isIn2DArea(mDimension)) { + if (isIn2DAreaModel(mModelChanger, mDimension)) { sead::Vector3f lockDir = {0.0f, 0.0f, 0.0f}; rs::calcLockDirection(&lockDir, mDimension); mAirMoveControl->verticalizeStartMoveDir(lockDir); @@ -314,14 +318,14 @@ void PlayerStateJump::exeJump() { al::separateVelocityHV(&horizontalVel, &verticalVel, mActor); f32 speed = sead::Mathf::min(horizontalVel.length(), mAirMoveControl->get_64()); al::limitLength(&horizontalVel, horizontalVel, speed); - al::setVelocity(mActor, horizontalVel + verticalVel); + al::setVelocity(mActor, verticalVel + horizontalVel); kill(); } else if (rs::updateJudgeAndResult(mJudgeWallCatch)) { if (!isDead() && mModelChanger->is2DModel() && (mSubAnimName ? al::isEqualString(mSubAnimName, "JumpSquat") : mAnimator->isAnim("JumpSquat"))) { - mTrigger->set(PlayerTrigger::EActionTrigger_val3); mSubAnimName = nullptr; + mTrigger->set(PlayerTrigger::EActionTrigger_val3); } if (_ba) al::setNerve(this, &NrvPlayerStateJump.Hovering2D); @@ -500,12 +504,8 @@ void PlayerStateJump::exeHovering2D() { } al::LiveActor* actor = mActor; - f32 maxSpeed; - if (mModelChanger->is2DModel()) - maxSpeed = mConst->getNormalMaxSpeed(); - else - maxSpeed = mConst->getNormalMaxSpeed2D(); - rs::scaleVelocityInertiaWallHit(actor, mCollider, 0.25f, 1.0f, maxSpeed); + rs::scaleVelocityInertiaWallHit(actor, mCollider, 0.25f, 1.0f, + getNormalMaxSpeed(mConst, mModelChanger)); if (al::isFirstStep(this)) { mAnimator->startAnim("Hovering"); @@ -564,18 +564,16 @@ void PlayerStateJump::exeJumpBack() { void PlayerStateJump::exeJumpSpinGround() { al::LiveActor* actor = mActor; - f32 maxSpeed; - if (mModelChanger->is2DModel()) - maxSpeed = mConst->getNormalMaxSpeed(); - else - maxSpeed = mConst->getNormalMaxSpeed2D(); - rs::scaleVelocityInertiaWallHit(actor, mCollider, 0.25f, 1.0f, maxSpeed); + rs::scaleVelocityInertiaWallHit(mActor, mCollider, 0.25f, 1.0f, + getNormalMaxSpeed(mConst, mModelChanger)); if (al::isFirstStep(this)) { trySubAnimJumpReaction(); - const char* format = _b6 ? "Restart%s" : "Start%s"; - mAnimator->startAnim(al::StringTmp<64>(format, mAnimName)); + if (_b6) + mAnimator->startAnim(al::StringTmp<64>("Restart%s", mAnimName)); + else + mAnimator->startAnim(al::StringTmp<64>("Start%s", mAnimName)); mAirMoveControl->setup(mMoveSpeedMax, mConst->getNormalMaxSpeed(), 0, mJumpPower, mJumpGravity, 0, mConst->getJumpInertiaRate()); @@ -605,9 +603,9 @@ void PlayerStateJump::exeJumpSpinGround() { sead::Vector3f horizontalVel = {0.0f, 0.0f, 0.0f}; sead::Vector3f verticalVel = {0.0f, 0.0f, 0.0f}; al::separateVelocityHV(&horizontalVel, &verticalVel, mActor); - f32 speed = sead::Mathf::min(horizontalVel.length(), mAirMoveControl->get_64()); - al::limitLength(&horizontalVel, horizontalVel, speed); - al::setVelocity(mActor, horizontalVel + verticalVel); + al::limitLength(&horizontalVel, horizontalVel, + sead::Mathf::min(horizontalVel.length(), mAirMoveControl->get_64())); + al::setVelocity(mActor, verticalVel + horizontalVel); kill(); } } @@ -620,12 +618,8 @@ void PlayerStateJump::exeHoveringJump2D() { al::LiveActor* actor = mActor; - f32 maxSpeed; - if (mModelChanger->is2DModel()) - maxSpeed = mConst->getNormalMaxSpeed(); - else - maxSpeed = mConst->getNormalMaxSpeed2D(); - rs::scaleVelocityInertiaWallHit(actor, mCollider, 0.25f, 1.0f, maxSpeed); + rs::scaleVelocityInertiaWallHit(actor, mCollider, 0.25f, 1.0f, + getNormalMaxSpeed(mConst, mModelChanger)); if (al::isFirstStep(this)) { mAnimator->startAnim("Hovering"); @@ -647,7 +641,7 @@ void PlayerStateJump::exeHoveringJump2D() { mIsContinuousJump = false; } - if (mModelChanger->is2DModel() && rs::isIn2DArea(mDimension)) { + if (isIn2DAreaModel(mModelChanger, mDimension)) { sead::Vector3f lockDir = {0.0f, 0.0f, 0.0f}; rs::calcLockDirection(&lockDir, mDimension); mAirMoveControl->verticalizeStartMoveDir(lockDir); @@ -661,7 +655,7 @@ void PlayerStateJump::exeHoveringJump2D() { al::separateVelocityHV(&horizontalVel, &verticalVel, mActor); f32 speed = sead::Mathf::min(horizontalVel.length(), mAirMoveControl->get_64()); al::limitLength(&horizontalVel, horizontalVel, speed); - al::setVelocity(mActor, horizontalVel + verticalVel); + al::setVelocity(mActor, verticalVel + horizontalVel); kill(); } else if (rs::updateJudgeAndResult(mJudgeWallCatch) || al::calcSpeedV(actor) < 0.0f) { al::setNerve(this, &NrvPlayerStateJump.Hovering2D); From 123c8e2603eb9349bdd4266e59a966349b4c9ee9 Mon Sep 17 00:00:00 2001 From: c4nvm <164799743+c4nvm@users.noreply.github.com> Date: Sat, 25 Jul 2026 02:45:00 -0400 Subject: [PATCH 4/4] Finishes `PlayerStateJump` --- data/file_list.yml | 12 +- src/Player/PlayerActionAirMoveControl.h | 18 +- src/Player/PlayerActionVelocityControl.h | 2 + src/Player/PlayerStateJump.cpp | 367 ++++++++++++++++++++++- src/Player/PlayerTrigger.h | 2 + 5 files changed, 374 insertions(+), 27 deletions(-) diff --git a/data/file_list.yml b/data/file_list.yml index 73da721cb6..d01597c70a 100644 --- a/data/file_list.yml +++ b/data/file_list.yml @@ -126879,11 +126879,11 @@ Player/PlayerStateJump.o: label: - _ZN15PlayerStateJumpC1EPN2al9LiveActorEPK11PlayerConstPK19IPlayerModelChangerPK13IUseDimensionPK11PlayerInputPK24PlayerJumpMessageRequestPK6IJudgePK21PlayerCounterForceRunPK24PlayerJointControlKeeperPK19IUsePlayerCollisionP13PlayerTriggerP20PlayerContinuousJumpP14PlayerAnimatorP23PlayerActionDiveInWaterP7HackCapPSI_b - _ZN15PlayerStateJumpC2EPN2al9LiveActorEPK11PlayerConstPK19IPlayerModelChangerPK13IUseDimensionPK11PlayerInputPK24PlayerJumpMessageRequestPK6IJudgePK21PlayerCounterForceRunPK24PlayerJointControlKeeperPK19IUsePlayerCollisionP13PlayerTriggerP20PlayerContinuousJumpP14PlayerAnimatorP23PlayerActionDiveInWaterP7HackCapPSI_b - status: Wip + status: Matching - offset: 0x470b9c size: 4416 label: _ZN15PlayerStateJump6appearEv - status: NotDecompiled + status: Matching - offset: 0x471cdc size: 92 label: _ZNK15PlayerStateJump27calcJumpPowerBorderSpeedMinEv @@ -126899,15 +126899,15 @@ Player/PlayerStateJump.o: - offset: 0x471e44 size: 172 label: _ZNK15PlayerStateJump16calcJumpPowerMaxEv - status: Wip + status: Matching - offset: 0x471ef0 size: 100 label: _ZNK15PlayerStateJump15calcJumpGravityEv - status: Wip + status: Matching - offset: 0x471f54 size: 320 label: _ZN15PlayerStateJump24tryCountUpContinuousJumpEP20PlayerContinuousJump - status: Wip + status: Matching - offset: 0x472094 size: 116 label: _ZNK15PlayerStateJump14isJumpCapCatchEv @@ -127011,7 +127011,7 @@ Player/PlayerStateJump.o: - offset: 0x474024 size: 36 label: _ZN15PlayerStateJumpD0Ev - status: NotDecompiled + status: Matching lazy: true - offset: 0x474048 size: 8 diff --git a/src/Player/PlayerActionAirMoveControl.h b/src/Player/PlayerActionAirMoveControl.h index fbfc6fe5b3..2ede0d5f18 100644 --- a/src/Player/PlayerActionAirMoveControl.h +++ b/src/Player/PlayerActionAirMoveControl.h @@ -23,23 +23,27 @@ class PlayerActionAirMoveControl { bool isHoldJumpExtend() const; void calcMoveInput(sead::Vector3f*, const sead::Vector3f&) const; - void set_40(bool value) { _40 = value; } - - void set_42(bool value) { _42 = value; } + void set_33(bool value) { _33 = value; } - void set_44(s32 value) { _44 = value; } + void set_40(bool value) { _40 = value; } - void set_48(f32 value) { _48 = value; } + void setMaxJumpSpeed(f32 minSpeed, f32 maxSpeed) { + _42 = true; + _44 = minSpeed; + _48 = maxSpeed; + } f32 get_64() const { return _64; } private: - u8 _0[0x40]; + u8 _0[0x33]; + bool _33; + u8 _34[0x40 - 0x34]; bool _40; u8 _41; bool _42; u8 _43; - s32 _44; + f32 _44; f32 _48; u8 _4c[0x64 - 0x4c]; f32 _64; diff --git a/src/Player/PlayerActionVelocityControl.h b/src/Player/PlayerActionVelocityControl.h index b9e12bdb2b..5645d042b6 100644 --- a/src/Player/PlayerActionVelocityControl.h +++ b/src/Player/PlayerActionVelocityControl.h @@ -20,6 +20,8 @@ class PlayerActionVelocityControl { void calcOnGround(const sead::Vector3f& groundNormal); void apply(); + const sead::Vector3f& getVelocityFront() const { return mVelocityFront; } + private: al::LiveActor* mActor; sead::Vector3f mSide = sead::Vector3f::zero; diff --git a/src/Player/PlayerStateJump.cpp b/src/Player/PlayerStateJump.cpp index cbda6683d1..59483f4834 100644 --- a/src/Player/PlayerStateJump.cpp +++ b/src/Player/PlayerStateJump.cpp @@ -12,16 +12,21 @@ #include "Player/IPlayerModelChanger.h" #include "Player/PlayerActionAirMoveControl.h" #include "Player/PlayerActionDiveInWater.h" +#include "Player/PlayerActionFunction.h" +#include "Player/PlayerActionVelocityControl.h" #include "Player/PlayerAnimator.h" #include "Player/PlayerConst.h" #include "Player/PlayerContinuousJump.h" #include "Player/PlayerCounterForceRun.h" #include "Player/PlayerInput.h" +#include "Player/PlayerJointControlKeeper.h" +#include "Player/PlayerJumpMessageRequest.h" #include "Player/PlayerTrigger.h" #include "Util/ActorDimensionUtil.h" #include "Util/JudgeUtil.h" #include "Util/ObjUtil.h" #include "Util/PlayerCollisionUtil.h" +#include "Util/PlayerUtil.h" namespace { NERVE_IMPL(PlayerStateJump, Jump); @@ -37,10 +42,16 @@ NERVE_IMPL(PlayerStateJump, Hovering2D); NERVES_MAKE_STRUCT(PlayerStateJump, Jump, HoveringJump2D, JumpSpinFlower, JumpBack, JumpTurn, JumpSpinGround, JumpSpinFlowerDownFall, JumpSpinGroundDownFall, Hovering2D); -static bool isIn2DAreaModel(const IPlayerModelChanger* modelChanger, const IUseDimension* dimension) { +static bool isIn2DAreaModel(const IPlayerModelChanger* modelChanger, + const IUseDimension* dimension) { return modelChanger->is2DModel() && rs::isIn2DArea(dimension); } +static f32 calcVelocityFrontSpeed(al::LiveActor* actor, const IUsePlayerCollision* collider) { + PlayerActionVelocityControl velControl(actor, collider); + return velControl.getVelocityFront().length(); +} + static f32 getNormalMaxSpeed(const PlayerConst* pConst, const IPlayerModelChanger* modelChanger) { return modelChanger->is2DModel() ? pConst->getNormalMaxSpeed() : pConst->getNormalMaxSpeed2D(); } @@ -64,14 +75,333 @@ PlayerStateJump::PlayerStateJump(al::LiveActor* player, const PlayerConst* pCons mContinuousJump(continuousJump), mTrigger(trigger), mDiveInWater(actionDiveInWater), mHackCap(hackCap), mJudgeWallCatch(judgeWallCatch), mIsEnableCapJumpSlowly(isEnableCapJumpSlowly), mInput(input) { - mAirMoveControl = new PlayerActionAirMoveControl(player, pConst, input, collider, false); + mAirMoveControl = new PlayerActionAirMoveControl(player, mConst, mInput, mCollider, false); mAirMoveControl->set_40(true); - mAirMoveControl->set_42(true); - mAirMoveControl->set_44(0); - mAirMoveControl->set_48(pConst->getJumpBaseSpeedMax()); + mAirMoveControl->setMaxJumpSpeed(0.0f, mConst->getJumpBaseSpeedMax()); initNerve(&NrvPlayerStateJump.Jump, 0); } +void PlayerStateJump::appear() { + rs::startHitReactionLandJumpIfLanding(mActor, mCollider, mModelChanger->is2DModel()); + + f32 speedMax = mConst->getJumpBaseSpeedMax(); + f32 forceRunSpeed = 0.0f; + if (mCounterForceRun->isForceRun()) { + forceRunSpeed = mCounterForceRun->getSpeed(); + speedMax = sead::Mathf::max(speedMax, forceRunSpeed); + } + mAirMoveControl->setMaxJumpSpeed(forceRunSpeed, speedMax); + + al::ActorStateBase::appear(); + + al::LiveActor* actor = mActor; + if (rs::isJustLand(mCollider)) { + sead::Vector3f redirected = {0.0f, 0.0f, 0.0f}; + al::alongVectorNormalH(&redirected, al::getVelocity(actor), -al::getGravity(actor), + rs::getCollidedGroundNormal(mCollider)); + const sead::Vector3f& groundNormal = rs::getCollidedGroundNormal(mCollider); + al::setVelocity(actor, redirected - mConst->getGravity() * groundNormal); + } + + if ((u32)mJumpMessageRequest->jumpType == 0xf && !mJumpMessageRequest->isEnableStandUp) { + sead::Vector3f horizontal = {0.0f, 0.0f, 0.0f}; + sead::Vector3f vertical = {0.0f, 0.0f, 0.0f}; + al::separateVelocityHV(&horizontal, &vertical, actor); + f32 speed = + sead::Mathf::clampMin(horizontal.length(), mConst->getSquatJumpCeilSlideSpeed2D()); + sead::Vector3f dir = {0.0f, 0.0f, 0.0f}; + mInput->calcMoveInput(&dir, -al::getGravity(actor)); + if (!al::tryNormalizeOrZero(&dir)) + al::calcFrontDir(&dir, actor); + al::setVelocity(actor, dir * speed + vertical); + } + + rs::scaleVelocityInertiaWallHit(actor, mCollider, 0.25f, 1.0f, + getNormalMaxSpeed(mConst, mModelChanger)); + + u32 messageJumpBit = (u32)mJumpMessageRequest->jumpType - 1; + bool isInMessageJumpRange = messageJumpBit < 0x10; + bool isMessageJump = ((0x9001u >> (u16)messageJumpBit) & 1) && isInMessageJumpRange; + const PlayerConst* pConst = mConst; + PlayerContinuousJump* continuousJump = mContinuousJump; + const IUsePlayerCollision* collider = mCollider; + bool isMini = mModelChanger->isMini(); + bool isEnableCapJumpSlowly = mIsEnableCapJumpSlowly; + mContinuousJumpCount = 0; + bool isContinuousJump = false; + if (isMessageJump || isMini) { + continuousJump->clear(); + } else if (continuousJump->getCount() >= 2) { + PlayerActionVelocityControl velControl(actor, collider); + f32 frontSpeed = velControl.getVelocityFront().length(); + sead::Vector3f jumpDir = {0.0f, 0.0f, 0.0f}; + al::verticalizeVec(&jumpDir, al::getGravity(actor), velControl.getVelocityFront()); + al::tryNormalizeOrZero(&jumpDir); + f32 maxSpeed = isEnableCapJumpSlowly ? pConst->getNormalMaxSpeed() * 0.5f : + pConst->getNormalMaxSpeed(); + if (frontSpeed < maxSpeed * 0.99f) { + continuousJump->clear(); + } else { + sead::Vector3f dir = jumpDir; + sead::Vector3f lastJumpDir = continuousJump->getLastJumpDir(); + f32 dot = dir.dot(lastJumpDir); + // 6.123032e-17f is cos(90°), 0.70710678f is cos(45°) + bool isInAngle = isEnableCapJumpSlowly ? dot >= 6.123032e-17f : dot >= 0.70710678f; + if (!isInAngle) { + continuousJump->clear(); + } else { + mContinuousJumpCount = continuousJump->getCount(); + isContinuousJump = true; + } + } + } else { + mContinuousJumpCount = continuousJump->getCount(); + isContinuousJump = true; + } + mIsContinuousJump = isContinuousJump; + + mAirMoveControl->set_33(isIn2DAreaModel(mModelChanger, mDimension)); + mIsDownFall = false; + mDownFallStartPos = {0.0f, 0.0f, 0.0f}; + _b9 = false; + _ba = false; + _b5 = false; + _b6 = false; + _b7 = false; + mIsJumpMessageRequest = false; + mUpDir = {0.0f, 0.0f, 0.0f}; + mAnimName = nullptr; + mSubAnimName = nullptr; + mMoveSpeedMax = sead::Mathf::max(mConst->getJumpMoveSpeedMax(), speedMax); + + switch ((u32)mJumpMessageRequest->jumpType) { + case 12: + rs::noticePlayerJumpStart(mTrigger, actor); + mJumpPower = mConst->getSpinJumpPower(); + mMoveSpeedMax = mConst->getSpinJumpMoveSpeedMax(); + mJumpGravity = mConst->getSpinJumpGravity(); + mExtendFrame = 0; + mAnimName = mJumpMessageRequest->isSpinClockwise ? "SpinJumpR" : "SpinJumpL"; + mIsJumpMessageRequest = true; + al::setNerve(this, &NrvPlayerStateJump.JumpSpinGround); + return; + case 13: + mJumpPower = mJumpMessageRequest->jumpPower; + mIsJumpMessageRequest = true; + al::setNerve(this, &NrvPlayerStateJump.JumpSpinFlower); + return; + case 14: + rs::noticePlayerJumpStart(mTrigger, actor); + mJumpPower = mConst->getSquatJumpPower(); + mJumpGravity = mConst->getSquatJumpGravity(); + mIsJumpMessageRequest = true; + al::setNerve(this, &NrvPlayerStateJump.JumpBack); + return; + case 16: + rs::noticePlayerJumpStart(mTrigger, actor); + mJumpPower = mConst->getTurnJumpPower(); + mJumpGravity = mConst->getTurnJumpGravity(); + mTurnDir = mJumpMessageRequest->turnJumpAngle; + mIsJumpMessageRequest = true; + al::setNerve(this, &NrvPlayerStateJump.JumpTurn); + return; + case 18: + al::setNerve(this, &NrvPlayerStateJump.HoveringJump2D); + return; + default: + break; + } + + { + const sead::Vector3f& gravity = al::getGravity(actor); + bool isMove = mInput->isMove(); + f32 velDotGravity = al::getVelocity(actor).dot(gravity); + const PlayerJumpMessageRequest* msg = mJumpMessageRequest; + u32 jumpType = (u32)msg->jumpType; + switch (jumpType) { + case 1: + mJumpPower = msg->jumpPower; + mJumpGravity = mConst->getJumpGravity(); + mExtendFrame = mJumpMessageRequest->extendFrame; + mIsJumpMessageRequest = true; + mAnimName = "JumpObjectReaction"; + al::setVelocityZero(actor); + break; + case 2: + mJumpPower = msg->jumpPower; + mJumpGravity = mConst->getJumpGravity(); + mExtendFrame = 0; + _b5 = true; + mIsJumpMessageRequest = true; + break; + case 4: + case 11: { + bool is2DModel = mModelChanger->is2DModel(); + if (velDotGravity < 0.0f) { + if (isMove) + al::scaleVelocityExceptDirection(actor, al::getGravity(actor), + mConst->getTrampleRisingBrakeVelH()); + else + al::setVelocityZero(actor); + + if (jumpType == 0xb) { + mJumpPower = mConst->getTrampleHighJumpPower(); + mJumpGravity = mConst->getTrampleHighGravity(); + mExtendFrame = 0; + } else { + mExtendFrame = mConst->getExtendFrame(); + mJumpPower = PlayerActionFunction::calcJumpSpeed( + calcVelocityFrontSpeed(mActor, mCollider), calcJumpPowerBorderSpeedMin(), + calcJumpPowerBorderSpeedMax(), calcJumpPowerMin(), calcJumpPowerMax()); + mJumpGravity = calcJumpGravity(); + } + } else { + if (!isMove) + al::setVelocityZero(actor); + + if (jumpType == 0xb) { + mJumpPower = mConst->getTrampleHighJumpPower(); + mJumpGravity = mConst->getTrampleHighGravity(); + } else if (mInput->isHoldJump()) { + if (is2DModel) { + mJumpPower = mConst->getTrampleHighJumpPower2D(); + mJumpGravity = mConst->getTrampleHighGravity2D(); + } else { + mJumpPower = mConst->getTrampleHighJumpPower(); + mJumpGravity = mConst->getTrampleHighGravity(); + } + } else if (is2DModel) { + mJumpPower = mConst->getTrampleJumpPower2D(); + mJumpGravity = mConst->getTrampleGravity2D(); + } else { + mJumpPower = mConst->getTrampleJumpPower(); + mJumpGravity = mConst->getTrampleGravity(); + } + mExtendFrame = 0; + } + + if (is2DModel) { + if (mAnimator->isAnim("JumpSquat")) { + mSubAnimName = "JumpSquat"; + _b5 = true; + } else { + mSubAnimName = "JumpTrample"; + } + } + mIsJumpMessageRequest = true; + _ba = mInput->isHoldCapSeparateJump(); + break; + } + case 5: + mJumpPower = msg->jumpPower; + mJumpGravity = mConst->getTrampleHighGravity(); + mExtendFrame = 0; + mIsJumpMessageRequest = true; + al::setVelocityZero(actor); + mAnimName = "Jump"; + break; + case 6: + mJumpPower = mConst->getTrampleHipDropJumpPower(); + mJumpGravity = mConst->getTrampleHipDropGravity(); + mExtendFrame = 0; + mIsJumpMessageRequest = true; + break; + case 7: + if ((velDotGravity < 0.0f) & isMove) + al::scaleVelocityExceptDirection(actor, al::getGravity(actor), + mConst->getTrampleRisingBrakeVelH()); + else if (!isMove) + al::setVelocityZero(actor); + + if (mInput->isHoldJump()) { + mJumpPower = mConst->getObjLeapFrogJumpPowerHigh(); + mJumpGravity = mConst->getTrampleHighGravity(); + } else { + mJumpPower = mConst->getObjLeapFrogJumpPower(); + mJumpGravity = mConst->getTrampleGravity(); + } + mExtendFrame = 0; + mAnimName = "JumpNpcTrample"; + mIsJumpMessageRequest = true; + break; + case 8: + mJumpPower = mConst->getCapLeapFrogJumpPower(); + mJumpGravity = mConst->getCapLeapFrogJumpGravity(); + mExtendFrame = 0; + mAnimName = "JumpCapLeapFrog"; + _b5 = mModelChanger->is2DModel(); + mIsJumpMessageRequest = true; + if (!isMove) + al::setVelocityZero(actor); + al::setTrans(actor, mJumpMessageRequest->actorTrans); + break; + case 9: + mJumpPower = mConst->getCapLeapFrogJumpPowerAir(); + mJumpGravity = mConst->getCapLeapFrogJumpGravity(); + mExtendFrame = 0; + mAnimName = "JumpCapLeapFrog"; + _b5 = mModelChanger->is2DModel(); + mIsJumpMessageRequest = true; + if (!isMove) + al::setVelocityZero(actor); + al::setTrans(actor, mJumpMessageRequest->actorTrans); + break; + case 10: + mMoveSpeedMax = mConst->getCapHeadSpringSpeedMax(); + mJumpPower = mConst->getCapHeadSpringJumpPowerHigh(); + mJumpGravity = mConst->getCapHeadSpringJumpGravityHigh(); + mExtendFrame = 0; + _b5 = mModelChanger->is2DModel(); + mIsJumpMessageRequest = true; + if (!isMove) + al::setVelocityZero(actor); + al::setTrans(actor, mJumpMessageRequest->actorTrans); + break; + case 17: + rs::noticePlayerJumpStart(mTrigger, actor); + mJumpPower = mConst->getJumpHipDropPower(); + mJumpGravity = mConst->getJumpGravity(); + mExtendFrame = 0; + mAnimName = "JumpHipDrop"; + mIsJumpMessageRequest = true; + break; + default: { + bool isCapCatchJump = rs::isJudge(mJudgeCapCatchJump); + rs::noticePlayerJumpStart(mTrigger, actor); + if (isCapCatchJump) { + PlayerActionVelocityControl velControl(mActor, mCollider); + mJumpPower = mConst->getJumpPowerCapCatch(); + mJumpGravity = mConst->getJumpGravityCapCatch(); + mExtendFrame = mConst->getExtendFrame(); + mAnimName = "JumpCapCatch"; + mIsJumpMessageRequest = true; + _b9 = mAnimator->isUpperBodyAnimAttached() && !rs::isPlayerCarrySomething(mActor); + break; + } + + mJumpPower = PlayerActionFunction::calcJumpSpeed( + calcVelocityFrontSpeed(mActor, mCollider), calcJumpPowerBorderSpeedMin(), + calcJumpPowerBorderSpeedMax(), calcJumpPowerMin(), calcJumpPowerMax()); + mJumpGravity = calcJumpGravity(); + mExtendFrame = mConst->getExtendFrame(); + _b7 = mTrigger->isOn(PlayerTrigger::EActionTrigger_val21); + if (_b7) + mJointControlKeeper->calcGroundPoseUp(&mUpDir); + + if ((u32)mJumpMessageRequest->jumpType != 0xf) { + if ((u32)mJumpMessageRequest->jumpType == 3 && mContinuousJumpCount == 0) + mAnimName = "JumpDashFast"; + } else { + mSubAnimName = "JumpSquat"; + } + break; + } + } + } + + al::setNerve(this, &NrvPlayerStateJump.Jump); +} + f32 PlayerStateJump::calcJumpPowerBorderSpeedMin() const { const IUseDimension* dimension = mDimension; bool is2D = mModelChanger->is2DModel() && rs::isIn2DArea(dimension); @@ -109,6 +439,8 @@ f32 PlayerStateJump::calcJumpPowerMax() const { if (mCounterForceRun->isForceRun()) return mConst->getJumpPowerForceRun(); switch (mContinuousJumpCount) { + case 0: + return mConst->getJumpPowerMax(); case 1: return mConst->getJumpPowerMax2nd(); case 2: @@ -122,6 +454,8 @@ f32 PlayerStateJump::calcJumpGravity() const { if (mCounterForceRun->isForceRun()) return mConst->getJumpGravityForceRun(); switch (mContinuousJumpCount) { + case 0: + return mConst->getJumpGravity(); case 1: return mConst->getJumpGravity2nd(); case 2: @@ -144,13 +478,18 @@ void PlayerStateJump::tryCountUpContinuousJump(PlayerContinuousJump* continuousJ if (continuousJump->getCount() != 0) { f32 jumpPower = mJumpPower; f32 jumpPowerBorder = mConst->getJumpPowerMax() * 0.99f; - f32 dot = jumpDir.dot(continuousJump->getLastJumpDir()); + sead::Vector3f dir = jumpDir; + sead::Vector3f lastJumpDir = continuousJump->getLastJumpDir(); + f32 dot = dir.dot(lastJumpDir); // 6.123032e-17f is cos(90°), 0.70710678f is cos(45°) bool isInAngle = mIsEnableCapJumpSlowly ? dot >= 6.123032e-17f : dot >= 0.70710678f; - if (jumpPower < jumpPowerBorder || !isInAngle) { - continuousJump->clear(); + bool isEnoughPower = jumpPower >= jumpPowerBorder; + if (isEnoughPower & isInAngle) { + continuousJump->countUp(jumpDir); return; } + continuousJump->clear(); + return; } continuousJump->countUp(jumpDir); @@ -273,8 +612,8 @@ void PlayerStateJump::exeJump() { } mAirMoveControl->setup(mMoveSpeedMax, - mModelChanger->is2DModel() ? mConst->getNormalMaxSpeed2D() - : mConst->getNormalMaxSpeed(), + mModelChanger->is2DModel() ? mConst->getNormalMaxSpeed2D() : + mConst->getNormalMaxSpeed(), mExtendFrame, mJumpPower, mJumpGravity, 0, mConst->getJumpInertiaRate()); } @@ -322,8 +661,8 @@ void PlayerStateJump::exeJump() { kill(); } else if (rs::updateJudgeAndResult(mJudgeWallCatch)) { if (!isDead() && mModelChanger->is2DModel() && - (mSubAnimName ? al::isEqualString(mSubAnimName, "JumpSquat") - : mAnimator->isAnim("JumpSquat"))) { + (mSubAnimName ? al::isEqualString(mSubAnimName, "JumpSquat") : + mAnimator->isAnim("JumpSquat"))) { mSubAnimName = nullptr; mTrigger->set(PlayerTrigger::EActionTrigger_val3); } @@ -700,8 +1039,8 @@ void PlayerStateJump::exeJumpTurn() { mInput->calcMoveInput(&moveInput, -al::getGravity(actor)); rs::moveDivingJump(actor, moveInput, mConst->getTurnJumpAccel(), mConst->getTurnJumpBrake(), - mConst->getTurnJumpVelH(), 0.0f, mConst->getTurnJumpSideAccel(), mJumpGravity, - mConst->getFallSpeedMax(), 0.0f); + mConst->getTurnJumpVelH(), 0.0f, mConst->getTurnJumpSideAccel(), + mJumpGravity, mConst->getFallSpeedMax(), 0.0f); rs::slerpUp(actor, -al::getGravity(actor), mConst->getSlerpQuatGrav(), 180.0f); diff --git a/src/Player/PlayerTrigger.h b/src/Player/PlayerTrigger.h index d2a27026c5..dd9fe247f8 100644 --- a/src/Player/PlayerTrigger.h +++ b/src/Player/PlayerTrigger.h @@ -30,6 +30,8 @@ class PlayerTrigger { EActionTrigger_val11 = 11, // used in PlayerStateSquat::appear EActionTrigger_val12 = 12, + // used in PlayerStateJump::appear + EActionTrigger_val21 = 21, // used in PlayerJudgeWallCatch::update, PlayerJudgeWallKeep::update EActionTrigger_val30 = 30, // used in PlayerCounterQuickTurnJump::isEnableTurnJump