1#include "Player/PlayerStateSlope.h"
2
3#include "Library/Controller/PadRumbleFunction.h"
4#include "Library/LiveActor/ActorMovementFunction.h"
5#include "Library/LiveActor/ActorPoseUtil.h"
6#include "Library/Math/MathUtil.h"
7#include "Library/Nerve/NerveSetupUtil.h"
8#include "Library/Nerve/NerveUtil.h"
9
10#include "Player/PlayerActionSlopeSlideControl.h"
11#include "Player/PlayerAnimator.h"
12#include "Player/PlayerConst.h"
13#include "Util/PlayerCollisionUtil.h"
14
15namespace {
16NERVE_IMPL(PlayerStateSlope, Slide)
17NERVES_MAKE_NOSTRUCT(PlayerStateSlope, Slide)
18} // namespace
19
20PlayerStateSlope::PlayerStateSlope(al::LiveActor* player, const PlayerConst* pConst,
21 const PlayerInput* input, const IUsePlayerCollision* collision,
22 PlayerAnimator* animator)
23 : al::ActorStateBase("坂すべり", player), mConst(pConst), mCollision(collision),
24 mAnimator(animator) {
25 mActionSlopeSlideControl = new PlayerActionSlopeSlideControl(player, pConst, input, collision);
26 initNerve(nerve: &Slide, stateCount: 0);
27}
28
29void PlayerStateSlope::appear() {
30 al::NerveStateBase::appear();
31 mActionSlopeSlideControl->setup();
32
33 mTimeInAir = 0;
34 mSlopeForceCounter = 0;
35 mIsForceSlide = false;
36 mIsRunningRumbleLoop = false;
37
38 if (rs::isOnGroundForceSlideCode(mActor, mCollision, mConst)) {
39 sead::Vector3f direction = mActionSlopeSlideControl->getDirSlide();
40 if (al::isNearZero(vec: direction))
41 al::setVelocityZero(mActor);
42 else {
43 sead::Vector3f* velocityPtr = al::getVelocityPtr(actor: mActor);
44 al::parallelizeVec(velocityPtr, direction, *velocityPtr);
45 }
46 mIsForceSlide = true;
47 }
48
49 const sead::Vector3f& direction = mActionSlopeSlideControl->getDirSlide();
50 const sead::Vector3f& velocity = al::getVelocity(actor: mActor);
51 f32 directedVel = direction.dot(t: velocity);
52 if (directedVel < 5.0f)
53 al::addVelocityToDirection(actor: mActor, dir: direction, force: 5.0f - directedVel);
54
55 sead::Vector3f* velocityPtr = al::getVelocityPtr(actor: mActor);
56 al::limitLength(out: velocityPtr, vec: *velocityPtr, limit: mConst->getSlopeSlideMaxSpeed());
57 al::setNerve(user: this, nerve: &Slide);
58}
59
60void PlayerStateSlope::kill() {
61 al::NerveStateBase::kill();
62
63 if (mIsRunningRumbleLoop) {
64 alPadRumbleFunction::stopPadRumbleLoop(actor: mActor, name: "【ループ】ジリジリ(中)",
65 position: al::getTransPtr(actor: mActor));
66 mIsRunningRumbleLoop = false;
67 }
68}
69
70bool PlayerStateSlope::isEnableCancelSandSink() const {
71 return mSlopeForceCounter > 15;
72}
73
74f32 PlayerStateSlope::calcSlideSpeed() const {
75 return mActionSlopeSlideControl->getHorizontalVelocity().dot(
76 t: mActionSlopeSlideControl->getDirSlide());
77}
78
79void PlayerStateSlope::exeSlide() {
80 if (al::isFirstStep(user: this)) {
81 mAnimator->startAnim(animName: "Slide");
82 mTimeInAir = 0;
83 mSlopeForceCounter = 0;
84 }
85
86 bool isCollidedGround = rs::isCollidedGround(mCollision);
87 al::LiveActor* actor = mActor;
88 if (isCollidedGround) {
89 if (!mIsRunningRumbleLoop) {
90 alPadRumbleFunction::startPadRumbleLoopNo3D(actor, name: "【ループ】ジリジリ(中)",
91 position: al::getTransPtr(actor));
92 mIsRunningRumbleLoop = true;
93 }
94 } else if (mIsRunningRumbleLoop) {
95 alPadRumbleFunction::stopPadRumbleLoop(actor, name: "【ループ】ジリジリ(中)",
96 position: al::getTransPtr(actor));
97 mIsRunningRumbleLoop = false;
98 }
99
100 bool isForceSlide = rs::isOnGroundForceSlideCode(mActor, mCollision, mConst);
101 if (!mIsForceSlide && isForceSlide) {
102 sead::Vector3f direction = mActionSlopeSlideControl->getDirSlide();
103 if (al::isNearZero(vec: direction))
104 al::setVelocityZero(mActor);
105 else {
106 sead::Vector3f* velocityPtr = al::getVelocityPtr(actor: mActor);
107 al::parallelizeVec(velocityPtr, direction, *velocityPtr);
108 }
109 mIsForceSlide = true;
110 }
111
112 mActionSlopeSlideControl->update(
113 accel: mConst->getSlopeSlideAccel(), brake: isForceSlide ? 0.0f : mConst->getSlopeSlideBrake(), against: 0.0f,
114 anglePowerMax: 0.0f, maxSpeed: mConst->getSlopeSlideMaxSpeed(),
115 sideAccel: isForceSlide ? mConst->getSlopeSlideForceSideAccel() : mConst->getSlopeSlideSideAccel(),
116 sideBrake: isForceSlide ? mConst->getSlopeSlideForceSideBrake() : mConst->getSlopeSlideSideBrake(),
117 sideMaxSpeed: isForceSlide ? mConst->getSlopeSlideForceSideMaxSpeed() :
118 mConst->getSlopeSlideSideMaxSpeed(),
119 turnDegree: mIsForceSlide ? mConst->getSlopeSlideForceTurnDegree() : mConst->getSlopeTurnDegree(),
120 gravity: mConst->getGravityMove(), isRolling: 0);
121
122 if (rs::isOnGroundSlopeSlideEnd(mActor, mCollision, mConst)) {
123 if (rs::isJustLand(mCollision) && mTimeInAir >= 30) {
124 kill();
125 return;
126 }
127
128 s32 forceFrame = mConst->getSlopeForceFrame();
129 mSlopeForceCounter = al::converge(mSlopeForceCounter, forceFrame, 1);
130 bool fastSlide = mActionSlopeSlideControl->getHorizontalVelocity().length() >
131 mConst->getSlopeSlideSpeedEnd();
132 if (!fastSlide && al::isGreaterEqualStep(user: this, step: mConst->getSlopeForceFrame())) {
133 kill();
134 return;
135 }
136 } else {
137 mSlopeForceCounter = 0;
138 if (rs::isCollidedGround(mCollision))
139 mTimeInAir = 0;
140 else
141 mTimeInAir = al::converge(mTimeInAir, 30, 1);
142 }
143}
144