1#include "Player/PlayerStateHipDrop.h"
2
3#include "Library/LiveActor/ActorMovementFunction.h"
4#include "Library/LiveActor/ActorPoseUtil.h"
5#include "Library/LiveActor/ActorSensorUtil.h"
6#include "Library/Math/MathUtil.h"
7#include "Library/Nerve/NerveSetupUtil.h"
8#include "Library/Nerve/NerveUtil.h"
9
10#include "Player/PlayerAnimator.h"
11#include "Player/PlayerConst.h"
12#include "Player/PlayerInput.h"
13#include "Player/PlayerTrigger.h"
14#include "Util/ObjUtil.h"
15#include "Util/PlayerCollisionUtil.h"
16
17namespace {
18NERVE_IMPL(PlayerStateHipDrop, Land);
19NERVE_IMPL(PlayerStateHipDrop, Start);
20NERVE_IMPL(PlayerStateHipDrop, Fall);
21
22NERVES_MAKE_NOSTRUCT(PlayerStateHipDrop, Land, Start, Fall);
23} // namespace
24
25PlayerStateHipDrop::PlayerStateHipDrop(al::LiveActor* player, const PlayerConst* pConst,
26 const PlayerInput* input,
27 const IUsePlayerCollision* collider,
28 PlayerAnimator* animator, PlayerTrigger* trigger)
29 : al::ActorStateBase("ヒップドロップ", player), mConst(pConst), mInput(input),
30 mCollision(collider), mAnimator(animator), mTrigger(trigger) {
31 initNerve(nerve: &Start, stateCount: 0);
32}
33
34void PlayerStateHipDrop::appear() {
35 al::NerveStateBase::appear();
36 if (mAnimator->isSubAnimPlaying())
37 mAnimator->endSubAnim();
38 mIsLandGround = false;
39 mLandPos = {0.0f, 0.0f, 0.0f};
40 al::setNerve(user: this, nerve: &Start);
41}
42
43bool PlayerStateHipDrop::attackHipDropKnockDown(al::HitSensor* sender, al::HitSensor* receiver) {
44 if (isDead())
45 return false;
46 if (!al::isNerve(user: this, nerve: &Land) || !al::isFirstStep(user: this))
47 return false;
48 return al::sendMsgPlayerHipDropKnockDown(receiver, sender);
49}
50
51bool PlayerStateHipDrop::isEnableHeadSliding() const {
52 if (isDead())
53 return false;
54 return al::isNerve(user: this, nerve: &Start) || al::isNerve(user: this, nerve: &Fall);
55}
56
57bool PlayerStateHipDrop::isEnableHipDropAttack() const {
58 if (isDead())
59 return false;
60 return al::isNerve(user: this, nerve: &Fall) && mHipDropMsgIntervalCounter == 0;
61}
62
63bool PlayerStateHipDrop::isEnableLandCancel() const {
64 if (isDead())
65 return false;
66 if (!al::isNerve(user: this, nerve: &Land))
67 return false;
68 s32 nerveStep = al::getNerveStep(user: this);
69 return nerveStep >= mConst->getJumpHipDropPermitBeginFrame() &&
70 nerveStep <= mConst->getJumpHipDropPermitEndFrame();
71}
72
73bool PlayerStateHipDrop::isEnableMove() const {
74 if (isDead())
75 return false;
76 return al::isNerve(user: this, nerve: &Land) &&
77 al::isGreaterEqualStep(user: this, step: mConst->getHipDropLandCancelFrame());
78}
79
80bool PlayerStateHipDrop::isEnableInWater() const {
81 if (isDead())
82 return false;
83 if (al::isNerve(user: this, nerve: &Start))
84 return false;
85 if (al::isNerve(user: this, nerve: &Fall))
86 return al::isGreaterEqualStep(user: this, step: 1);
87 return true;
88}
89
90bool PlayerStateHipDrop::isEnableIK() const {
91 if (isDead())
92 return false;
93 return al::isNerve(user: this, nerve: &Land);
94}
95
96bool PlayerStateHipDrop::isLandTrigger() const {
97 if (mTrigger->isOn(PlayerTrigger::ECollisionTrigger_val1))
98 return true;
99 return al::isNerve(user: this, nerve: &Land) && al::isFirstStep(user: this);
100}
101
102void PlayerStateHipDrop::exeStart() {
103 if (al::isFirstStep(user: this)) {
104 mAnimator->startAnim(animName: "HipDropStart");
105 al::setVelocityZero(mActor);
106 sead::Vector3f negGravity = -al::getGravity(actor: mActor);
107 sead::Vector3f up = {0.0f, 0.0f, 0.0f};
108 al::calcUpDir(up: &up, actor: mActor);
109
110 if (up.dot(t: negGravity) <=
111 sead::Mathf::cos(t: sead::Mathf::deg2rad(deg: mConst->getCollisionResetLimit())))
112 mTrigger->set(PlayerTrigger::EActionTrigger_val3);
113
114 sead::Quatf quat;
115 al::calcQuat(quat: &quat, actor: mActor);
116 al::turnQuatYDirRadian(&quat, quat, negGravity, sead::Mathf::deg2rad(deg: 180.0f));
117 al::updatePoseQuat(actor: mActor, quat);
118 }
119
120 if (mAnimator->isAnimEnd())
121 al::setNerve(user: this, nerve: &Fall);
122}
123
124void PlayerStateHipDrop::exeFall() {
125 if (al::isFirstStep(user: this)) {
126 mAnimator->startAnim(animName: "HipDrop");
127 al::addVelocityToGravityLimit(actor: mActor, force: mConst->getHipDropSpeed(),
128 limit: mConst->getHipDropSpeedMax());
129 }
130
131 al::addVelocityToGravityLimit(actor: mActor, force: mConst->getHipDropGravity(),
132 limit: mConst->getHipDropSpeedMax());
133 if (mTrigger->isOn(PlayerTrigger::ECollisionTrigger_val1) && mInput->isHoldHipDrop()) {
134 mHipDropMsgIntervalCounter = mConst->getHipDropMsgInterval();
135 mAnimator->startAnim(animName: "HipDropReaction");
136 mIsLandGround = false;
137 if (rs::isCollidedGround(mCollision)) {
138 mIsLandGround = true;
139 mLandPos = rs::getCollidedGroundPos(mCollision);
140 }
141 }
142
143 if (mHipDropMsgIntervalCounter > 0) {
144 if (rs::convergeOnGroundCount(&mHipDropMsgIntervalCounter, mActor, mCollision, 0, 1))
145 return;
146 mHipDropMsgIntervalCounter = 0;
147 }
148
149 if (rs::isOnGroundRunAngle(mActor, mCollision, mConst))
150 al::setNerve(user: this, nerve: &Land);
151}
152
153void PlayerStateHipDrop::exeLand() {
154 if (al::isFirstStep(user: this)) {
155 mAnimator->startAnim(animName: "HipDropLand");
156
157 al::LiveActor* actor = mActor;
158 bool isLandingWeak = false;
159 if (mIsLandGround) {
160 const IUsePlayerCollision* collision = mCollision;
161 if (rs::isCollidedGround(collision)) {
162 const sead::Vector3f& gravity = al::getGravity(actor);
163 isLandingWeak =
164 (rs::getCollidedGroundPos(collision) - mLandPos).dot(t: gravity) <= 10.0f;
165 }
166 }
167 rs::startHitReactionHipDropLand(actor, isLandingWeak);
168 }
169
170 if (rs::isOnGroundRunAngle(mActor, mCollision, mConst)) {
171 rs::waitGround(mActor, mCollision, mConst->getGravityMove(), mConst->getFallSpeedMax(),
172 mConst->getSlerpQuatRateWait(), mConst->getWaitPoseDegreeMax());
173 } else {
174 kill();
175 }
176
177 if (mAnimator->isAnimEnd())
178 kill();
179}
180