diff --git a/data/odyssey_functions.csv b/data/odyssey_functions.csv index ce6931ae6..9f1762eaf 100644 --- a/data/odyssey_functions.csv +++ b/data/odyssey_functions.csv @@ -26083,10 +26083,10 @@ Address,Quality,Size,Name 0x0000007100418c60,U,000060,_ZN28PlayerActionPivotTurnControl5resetEv 0x0000007100418c9c,U,001064,_ZN28PlayerActionPivotTurnControl6updateEv 0x00000071004190c4,U,000032,_ZN28PlayerActionPivotTurnControl17calcMoveDirectionEPN4sead7Vector3IfEERKS2_ -0x00000071004190e4,U,000068,_ZN29PlayerActionSlopeSlideControlC2EPN2al9LiveActorEPK11PlayerConstPK11PlayerInputPK19IUsePlayerCollision -0x0000007100419128,U,000184,_ZN29PlayerActionSlopeSlideControl5setupEv -0x00000071004191e0,U,000284,_ZN29PlayerActionSlopeSlideControl24setupCutSlideOppositeDirEv -0x00000071004192fc,U,002068,_ZN29PlayerActionSlopeSlideControl6updateEffffffffffb +0x00000071004190e4,O,000068,_ZN29PlayerActionSlopeSlideControlC2EPN2al9LiveActorEPK11PlayerConstPK11PlayerInputPK19IUsePlayerCollision +0x0000007100419128,O,000184,_ZN29PlayerActionSlopeSlideControl5setupEv +0x00000071004191e0,O,000284,_ZN29PlayerActionSlopeSlideControl24setupCutSlideOppositeDirEv +0x00000071004192fc,O,002068,_ZN29PlayerActionSlopeSlideControl6updateEffffffffffb 0x0000007100419b10,U,000124,_ZN23PlayerActionTurnControlC2EPN2al9LiveActorE 0x0000007100419b8c,U,000028,_ZN23PlayerActionTurnControl5setupEffffiii 0x0000007100419ba8,U,000024,_ZN23PlayerActionTurnControl5resetEv diff --git a/src/Player/PlayerActionSlopeSlideControl.cpp b/src/Player/PlayerActionSlopeSlideControl.cpp new file mode 100644 index 000000000..4e626ce88 --- /dev/null +++ b/src/Player/PlayerActionSlopeSlideControl.cpp @@ -0,0 +1,164 @@ +#include "Player/PlayerActionSlopeSlideControl.h" + +#include "Library/LiveActor/ActorMovementFunction.h" +#include "Library/LiveActor/ActorPoseKeeper.h" +#include "Library/LiveActor/ActorPoseUtil.h" +#include "Library/Math/MathUtil.h" + +#include "Player/PlayerConst.h" +#include "Player/PlayerInput.h" +#include "Util/ObjUtil.h" +#include "Util/PlayerCollisionUtil.h" + +PlayerActionSlopeSlideControl::PlayerActionSlopeSlideControl(al::LiveActor* player, + const PlayerConst* pConst, + const PlayerInput* input, + const IUsePlayerCollision* collider) + : mPlayer(player), mConst(pConst), mInput(input), mCollision(collider) {} + +void PlayerActionSlopeSlideControl::setup() { + mGroundNormal = -al::getGravity(mPlayer); + mDirSlide = {0.0f, 0.0f, 0.0f}; + + if (rs::isCollidedGround(mCollision)) { + al::calcDirSlide(&mDirSlide, al::getGravity(mPlayer), + rs::getCollidedGroundNormal(mCollision)); + if (!rs::isJustLand(mCollision)) + mGroundNormal = rs::getCollidedGroundNormal(mCollision); + } + + mHorizontalVelocity = {0.0f, 0.0f, 0.0f}; +} + +void PlayerActionSlopeSlideControl::setupCutSlideOppositeDir() { + setup(); + + sead::Vector3f groundNormal = {0.0f, 0.0f, 0.0f}; + rs::calcGroundNormalOrGravityDir(&groundNormal, mPlayer, mCollision); + + sead::Vector3f slideDir = {0.0f, 0.0f, 0.0f}; + sead::Vector3f* velocityPtr = al::getVelocityPtr(mPlayer); + al::alongVectorNormalH(velocityPtr, *velocityPtr, mGroundNormal, groundNormal); + if (rs::calcSlideDir(&slideDir, al::getGravity(mPlayer), groundNormal)) + al::limitVectorOppositeDir(velocityPtr, slideDir, *velocityPtr, velocityPtr->length()); + + *velocityPtr -= mConst->getGravityMove() * groundNormal; + mGroundNormal = groundNormal; +} + +f32 PlayerActionSlopeSlideControl::update(f32 accel, f32 brake, f32 against, f32 anglePowerMax, + f32 maxSpeed, f32 sideAccel, f32 sideBrake, + f32 sideMaxSpeed, f32 turnDegree, f32 gravity, + bool isRolling) { + sead::Vector3f prevGroundNormal = mGroundNormal; + sead::Vector3f up = -al::getGravity(mPlayer); + sead::Vector3f velocity = al::getVelocity(mPlayer); + bool isOnGroundSlopeSlideEnd = rs::isOnGroundSlopeSlideEnd(mPlayer, mCollision, mConst); + if (rs::isOnGround(mPlayer, mCollision)) { + mGroundNormal = rs::getCollidedGroundNormal(mCollision); + up = mGroundNormal; + al::calcDirSlide(&mDirSlide, al::getGravity(mPlayer), up); + al::alongVectorNormalH(&velocity, velocity, prevGroundNormal, up); + + sead::Vector3f velDirSlide = {0.0f, 0.0f, 0.0f}; + sead::Vector3f velSide = {0.0f, 0.0f, 0.0f}; + if (isOnGroundSlopeSlideEnd) { + al::separateVectorParallelVertical(&velSide, &velDirSlide, up, velocity); + velDirSlide *= brake; + velSide *= sideBrake; + if (isRolling) { + sead::Vector3f moveInput = {0.0f, 0.0f, 0.0f}; + mInput->calcMoveInput(&moveInput, up); + + sead::Vector3f normDirSlide = {0.0f, 0.0f, 0.0f}; + al::tryNormalizeOrZero(&normDirSlide, velDirSlide); + + sead::Vector3f side; + side.setCross(up, normDirSlide); + al::tryNormalizeOrZero(&side); + + f32 sideInput = side.dot(moveInput); + sead::Vector3f moveSideVec = side * sideInput * sideAccel; + al::addVectorLimit(&velDirSlide, moveSideVec, maxSpeed); + } + } else { + al::separateVectorParallelVertical(&velDirSlide, &velSide, mDirSlide, velocity); + sead::Vector3f moveInput = {0.0f, 0.0f, 0.0f}; + mInput->calcMoveInput(&moveInput, up); + f32 speedDirSlide = velDirSlide.dot(mDirSlide); + if (speedDirSlide < 0.0) + velDirSlide *= brake; + + f32 moveInputAgainst = sead::Mathf::clamp(-mDirSlide.dot(moveInput), 0.0f, 1.0f); + f32 minSpeedNorm = sead::Mathf::clamp(1.0f - (moveInputAgainst * against), 0.0, 1.0); + f32 speedNorm = sead::Mathf::clamp(speedDirSlide + 1.0f, minSpeedNorm, 1.0f); + + f32 anglePower = sead::Mathf::clamp( + 90.0f - al::calcAngleDegree(mDirSlide, al::getGravity(mPlayer)), 0.0f, 90.0f); + + f32 anglePowerNorm = 1.0f; + if (anglePowerMax > 0.0) + anglePowerNorm = sead::Mathf::clampMax(anglePower / anglePowerMax, 1.0f); + + al::addVectorLimit(&velDirSlide, mDirSlide * accel * anglePowerNorm * speedNorm, + maxSpeed); + velSide *= sideBrake; + sead::Vector3f inputDir = {0.0f, 0.0f, 0.0f}; + if (al::tryNormalizeOrZero(&inputDir, moveInput)) { + sead::Vector3f sideDir; + sideDir.setCross(up, mDirSlide); + al::addVectorLimit(&velSide, + sideDir * sideDir.dot(inputDir) * moveInput.length() * sideAccel, + sideMaxSpeed); + } + } + + sead::Vector3f vel; + vel.x = velDirSlide.x + velSide.x; + vel.y = velDirSlide.y + velSide.y; + vel.z = velDirSlide.z + velSide.z; + al::limitLength(&vel, vel, maxSpeed); + al::setVelocity(mPlayer, vel - (mConst->getGravityMove() * up)); + } else { + mGroundNormal = up; + f32 prevUpVel = prevGroundNormal.dot(al::getVelocity(mPlayer)); + al::alongVectorNormalH(al::getVelocityPtr(mPlayer), al::getVelocity(mPlayer), + prevGroundNormal, mGroundNormal); + sead::Vector3f* velPtr = al::getVelocityPtr(mPlayer); + velPtr->x = (prevUpVel * mGroundNormal.x) + velPtr->x; + velPtr->y = (prevUpVel * mGroundNormal.y) + velPtr->y; + velPtr->z = (prevUpVel * mGroundNormal.z) + velPtr->z; + al::addVectorLimit(al::getVelocityPtr(mPlayer), up * -gravity, mConst->getFallSpeedMax()); + } + + sead::Vector3f hVel = {0.0f, 0.0f, 0.0f}; + al::verticalizeVec(&hVel, up, al::getVelocity(mPlayer)); + sead::Vector3f hVelDir = {0.0f, 0.0f, 0.0f}; + + f32 rumbleStrength; + if (al::tryNormalizeOrZero(&hVelDir, hVel)) { + sead::Vector3f front = {0.0f, 0.0f, 0.0f}; + al::calcFrontDir(&front, mPlayer); + al::verticalizeVec(&front, up, front); + al::tryNormalizeOrZero(&front); + if (turnDegree > 0.0) { + f32 angleFrontVel = 2 * al::calcAngleDegree(front, hVelDir); + f32 turn = sead::Mathf::clamp(angleFrontVel / turnDegree, 0.0f, 1.0f); + sead::Vector3f upFrontVel; + upFrontVel.setCross(front, hVelDir); + rumbleStrength = -al::sign(up.dot(upFrontVel)) * turn; + } else { + rumbleStrength = 0.0; + } + + al::turnVecToVecCosOnPlane(&front, hVelDir, up, + sead::Mathf::cos(sead::Mathf::deg2rad(turnDegree))); + rs::slerpUpFront(mPlayer, up, front, mConst->getSlerpQuatRate(), + mConst->getHillPoseDegreeMax()); + } else { + rumbleStrength = 0.0; + } + + mHorizontalVelocity = hVel; + return rumbleStrength; +} diff --git a/src/Player/PlayerActionSlopeSlideControl.h b/src/Player/PlayerActionSlopeSlideControl.h index e7a6cf0f0..94d9552bd 100644 --- a/src/Player/PlayerActionSlopeSlideControl.h +++ b/src/Player/PlayerActionSlopeSlideControl.h @@ -1,6 +1,5 @@ #pragma once -#include #include namespace al { @@ -12,11 +11,12 @@ class IUsePlayerCollision; class PlayerActionSlopeSlideControl { public: - PlayerActionSlopeSlideControl(al::LiveActor*, const PlayerConst*, const PlayerInput*, - const IUsePlayerCollision*); + PlayerActionSlopeSlideControl(al::LiveActor* player, const PlayerConst* pConst, + const PlayerInput* input, const IUsePlayerCollision* collider); void setup(); void setupCutSlideOppositeDir(); - f32 update(f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, bool); + f32 update(f32 accel, f32 brake, f32 against, f32 anglePowerMax, f32 maxSpeed, f32 sideAccel, + f32 sideBrake, f32 sideMaxSpeed, f32 turnDegree, f32 gravity, bool isRolling); const sead::Vector3f& getDirSlide() const { return mDirSlide; } @@ -29,9 +29,9 @@ class PlayerActionSlopeSlideControl { const PlayerConst* mConst; const PlayerInput* mInput; const IUsePlayerCollision* mCollision; - sead::Vector3f mDirSlide = {0.0f, 0.0f, 0.0f}; - sead::Vector3f mGroundNormal = {0.0f, 0.0f, 0.0f}; - sead::Vector3f mHorizontalVelocity = {0.0f, 0.0f, 0.0f}; + sead::Vector3f mDirSlide = sead::Vector3f::zero; + sead::Vector3f mGroundNormal = sead::Vector3f::zero; + sead::Vector3f mHorizontalVelocity = sead::Vector3f::zero; }; static_assert(sizeof(PlayerActionSlopeSlideControl) == 0x48); diff --git a/src/Util/ObjUtil.h b/src/Util/ObjUtil.h index 9b4d1e9e9..7274fcb56 100644 --- a/src/Util/ObjUtil.h +++ b/src/Util/ObjUtil.h @@ -38,4 +38,7 @@ void startHitReactionHipDropLand(al::LiveActor*, bool); void waitGround(al::LiveActor*, const IUsePlayerCollision*, f32, f32, f32, f32); +void slerpUpFront(al::LiveActor*, const sead::Vector3f&, const sead::Vector3f&, f32, f32); + +bool calcSlideDir(sead::Vector3f*, const sead::Vector3f&, const sead::Vector3f&); } // namespace rs