1#include "MapObj/MapObjStatePlayerHold.h"
2
3#include <math/seadMatrix.h>
4
5#include "Library/Collision/Collider.h"
6#include "Library/LiveActor/ActorClippingFunction.h"
7#include "Library/LiveActor/ActorCollisionFunction.h"
8#include "Library/LiveActor/ActorFlagFunction.h"
9#include "Library/LiveActor/ActorModelFunction.h"
10#include "Library/LiveActor/ActorMovementFunction.h"
11#include "Library/LiveActor/ActorPoseUtil.h"
12#include "Library/LiveActor/ActorSensorUtil.h"
13#include "Library/LiveActor/LiveActor.h"
14#include "Library/Math/MathUtil.h"
15#include "Library/Matrix/MatrixUtil.h"
16#include "Library/Nerve/NerveSetupUtil.h"
17#include "Library/Nerve/NerveUtil.h"
18#include "Library/Shadow/ActorShadowUtil.h"
19
20#include "Util/DemoUtil.h"
21#include "Util/PlayerUtil.h"
22#include "Util/SensorMsgFunction.h"
23
24namespace {
25NERVE_IMPL(MapObjStatePlayerHold, Hold)
26
27NERVES_MAKE_STRUCT(MapObjStatePlayerHold, Hold)
28} // namespace
29
30MapObjStatePlayerHold::MapObjStatePlayerHold(al::LiveActor* actor,
31 const sead::Vector3f& localOffset,
32 const sead::Vector3f& localRotate)
33 : al::ActorStateBase("プレイヤーに持たれるステート", actor), mLocalOffset(localOffset),
34 mLocalRotate(localRotate) {
35 initNerve(nerve: &NrvMapObjStatePlayerHold.Hold, stateCount: 0);
36}
37
38void MapObjStatePlayerHold::initUseColliderPush(f32 pushForce) {
39 mIsUseColliderPush = true;
40 mColliderRadius = al::getColliderRadius(mActor);
41 mColliderPushForce = pushForce;
42}
43
44void MapObjStatePlayerHold::initShadowMaskDropLengthCtrl(const char* shadowMaskName) {
45 mShadowMaskName = shadowMaskName;
46 mShadowMaskDropLength = al::getShadowMaskDropLength(actor: mActor, maskName: shadowMaskName);
47}
48
49void MapObjStatePlayerHold::appear() {
50 al::NerveStateBase::appear();
51 mTotalPush = {0.0f, 0.0f, 0.0f};
52 al::invalidateClipping(actor: mActor);
53
54 if (mIsUseColliderPush) {
55 mColliderUpOffset = 0;
56 al::setColliderRadius(mActor,
57 sead::Mathf::clampMax(val: mColliderRadius * mColliderPushForce, max_: 40.0f));
58 al::getActorCollider(mActor)->onInvalidate();
59 al::onCollide(actor: mActor);
60 if (mIsCarryUp)
61 mColliderUpOffset = 1000;
62 } else {
63 al::offCollide(actor: mActor);
64 }
65
66 al::stopDitherAnimAutoCtrl(actor: mActor);
67 al::invalidateOcclusionQuery(actor: mActor);
68 mIsResetPositionNeeded = false;
69 al::setNerve(user: this, nerve: &NrvMapObjStatePlayerHold.Hold);
70}
71
72void MapObjStatePlayerHold::kill() {
73 mPlayerHitSensor = nullptr;
74 al::validateClipping(actor: mActor);
75
76 if (mIsUseColliderPush)
77 al::setColliderRadius(mActor, mColliderRadius);
78 else
79 al::onCollide(actor: mActor);
80
81 if (mShadowMaskName)
82 al::setShadowMaskDropLength(actor: mActor, dropLength: mShadowMaskDropLength, maskName: mShadowMaskName);
83
84 al::restartDitherAnimAutoCtrl(actor: mActor);
85 al::setModelAlphaMask(actor: mActor, 1.0f);
86 al::validateOcclusionQuery(actor: mActor);
87 mTotalPush = {0.0f, 0.0f, 0.0f};
88 al::NerveStateBase::kill();
89}
90
91void MapObjStatePlayerHold::attackSensor(al::HitSensor* self, al::HitSensor* other) {
92 al::sendMsgPlayerItemGet(receiver: other, sender: self);
93}
94
95bool MapObjStatePlayerHold::receiveMsgNoRelease(const al::SensorMsg* message, al::HitSensor* other,
96 al::HitSensor* self) {
97 if (al::isMsgPlayerDisregard(msg: message))
98 return al::isNerve(user: this, nerve: &NrvMapObjStatePlayerHold.Hold);
99
100 sead::Vector3f pushPos = {0.0f, 0.0f, 0.0f};
101 if (al::tryReceiveMsgPushAndCalcPushTrans(&pushPos, message, mActor, other, self, 15.0f)) {
102 al::sendMsgCollidePush(mPlayerHitSensor, self, pushPos);
103 return true;
104 }
105
106 if (al::isMsgPlayerCarryKeepDemo(msg: message)) {
107 rs::addDemoActor(mActor, false);
108 return true;
109 }
110
111 if (rs::isMsgPlayerCarryShineGetStart(message)) {
112 al::hideModelIfShow(actor: mActor);
113 rs::addDemoActor(mActor, false);
114 return true;
115 }
116
117 if (rs::isMsgPlayerCarryShineGetEnd(message)) {
118 al::showModelIfHide(actor: mActor);
119 return true;
120 }
121
122 if (rs::isMsgPlayerCarryCameraSubjectiveStart(message)) {
123 al::hideModelIfShow(actor: mActor);
124 return true;
125 }
126
127 if (rs::isMsgPlayerCarryCameraSubjectiveEnd(message)) {
128 al::showModelIfHide(actor: mActor);
129 return true;
130 }
131
132 if (al::isMsgPlayerCarryWarp(msg: message)) {
133 mIsResetPositionNeeded = true;
134 return true;
135 }
136 return false;
137}
138
139bool MapObjStatePlayerHold::receiveMsgRelease(const al::SensorMsg* message, al::HitSensor* other,
140 al::HitSensor* self) {
141 if (al::isMsgHoldReleaseAll(msg: message)) {
142 al::LiveActor* actor = mActor;
143 sead::Vector3f frontDir = {0.0f, 0.0f, 0.0f};
144 rs::calcPlayerFrontDir(&frontDir, actor);
145 al::makeQuatFrontUp(outQuat: al::getQuatPtr(actor), front: frontDir, up: sead::Vector3f::ey);
146
147 if (mIsUseColliderPush)
148 prepareThrowCollide();
149 kill();
150 return true;
151 }
152 return false;
153}
154
155void MapObjStatePlayerHold::prepareThrowCollide() {
156 al::LiveActor* actor = mActor;
157 sead::Vector3f direction = {0.0f, 0.0f, 0.0f};
158 al::Collider* collider = actor->getCollider();
159
160 collider->setRadius(sead::Mathf::clampMax(val: mColliderRadius * mColliderPushForce, max_: 40.0f));
161 collider->onInvalidate();
162 collider->setRadius(mColliderRadius);
163
164 al::setTrans(actor, trans: collider->collide(direction) + al::getTrans(actor));
165}
166
167bool MapObjStatePlayerHold::receiveMsgCancel(const al::SensorMsg* message, al::HitSensor* other,
168 al::HitSensor* self) {
169 if (al::isMsgHoldCancel(msg: message)) {
170 if (mIsUseColliderPush)
171 prepareThrowCollide();
172 kill();
173 return true;
174 }
175 return false;
176}
177
178bool MapObjStatePlayerHold::tryStartCarryFront(const al::SensorMsg* message,
179 al::HitSensor* sensor) {
180 if (al::isMsgPlayerCarryFront(msg: message)) {
181 mIsCarryUp = false;
182 mPlayerHitSensor = sensor;
183 return true;
184 }
185 return false;
186}
187
188bool MapObjStatePlayerHold::tryStartCarryFrontWallKeep(const al::SensorMsg* message,
189 al::HitSensor* sensor) {
190 if (al::isMsgPlayerCarryFrontWallKeep(msg: message)) {
191 mIsCarryUp = false;
192 mPlayerHitSensor = sensor;
193 return true;
194 }
195 return false;
196}
197
198bool MapObjStatePlayerHold::tryStartCarryUp(const al::SensorMsg* message, al::HitSensor* sensor) {
199 if (al::isMsgPlayerCarryUp(msg: message)) {
200 mIsCarryUp = true;
201 mPlayerHitSensor = sensor;
202 return true;
203 }
204 return false;
205}
206
207void MapObjStatePlayerHold::tryCancelHold(al::HitSensor* sensor) {
208 al::sendMsgHoldCancel(receiver: mPlayerHitSensor, sender: sensor);
209}
210
211void MapObjStatePlayerHold::updateCollider(al::HitSensor* sensor) {
212 al::LiveActor* actor = mActor;
213 al::Collider* collider = actor->getCollider();
214
215 if (al::isNoCollide(actor)) {
216 collider->onInvalidate();
217 return;
218 }
219
220 s32 nextOffset = sead::Mathi::clampMin(val: mColliderUpOffset - 3, min_: 0);
221 f32 maxColliderRadius = mColliderRadius * mColliderPushForce;
222 f32 colliderRadius = nextOffset * 10.0f + 40.0f;
223
224 collider->setRadius(sead::Mathf::min(a: colliderRadius, b: maxColliderRadius));
225 sead::Vector3f pushPos = collider->collide(sead::Vector3f::zero);
226
227 if (al::isOnGround(actor, 0)) {
228 if (rs::isPlayerOnGround(actor)) {
229 al::verticalizeVec(out: &pushPos, vertical: al::getGravity(actor), vec: pushPos);
230 } else {
231 sead::Vector3f groundPos = al::getCollidedGroundPos(actor);
232 sead::Vector3f normal = al::getActorTrans(mPlayerHitSensor) - groundPos;
233 al::verticalizeVec(out: &normal, vertical: al::getGravity(actor), vec: normal);
234 if (!al::tryNormalizeOrZero(out: &normal)) {
235 rs::calcPlayerFrontDir(&normal, actor);
236 normal.negate();
237 }
238 pushPos += mColliderRadius * normal * mColliderPushForce * 0.5f;
239 }
240 } else if (mIsCarryUp && al::isLessStep(user: this, step: 3) && al::isCollidedCeiling(actor)) {
241 sead::Vector3f ceilingPos = al::getCollidedCeilingPos(actor);
242 sead::Vector3f normal = al::getActorTrans(mPlayerHitSensor) - ceilingPos;
243 al::verticalizeVec(out: &normal, vertical: al::getGravity(actor), vec: normal);
244 if (!al::tryNormalizeOrZero(out: &normal)) {
245 rs::calcPlayerFrontDir(&normal, actor);
246 normal.negate();
247 }
248 pushPos += mColliderRadius * normal * mColliderPushForce;
249 }
250 mTotalPush = pushPos;
251 al::sendMsgCollidePush(mPlayerHitSensor, sensor, pushPos);
252 mColliderUpOffset = al::converge(mColliderUpOffset, 1000, 1);
253}
254
255void MapObjStatePlayerHold::exeHold() {
256 rs::syncPlayerModelAlpha(mActor);
257 sead::Matrix34f poseMtx = sead::Matrix34f::ident;
258 rs::calcPlayerHoldMtx(&poseMtx, mPlayerHitSensor);
259
260 sead::Vector3f position = {0.0f, 0.0f, 0.0f};
261 al::calcTransLocalOffsetByMtx(&position, poseMtx, mLocalOffset);
262
263 sead::Matrix34f rotationMatrix;
264 sead::Vector3f rotate(sead::Mathf::deg2rad(deg: mLocalRotate.x),
265 sead::Mathf::deg2rad(deg: mLocalRotate.y),
266 sead::Mathf::deg2rad(deg: mLocalRotate.z));
267 rotationMatrix.makeR(r: rotate);
268
269 poseMtx = poseMtx * rotationMatrix;
270 poseMtx.setBase(axis: 3, v: position);
271 al::updatePoseMtx(actor: mActor, mtx: &poseMtx);
272
273 if (mIsResetPositionNeeded) {
274 al::resetPosition(actor: mActor);
275 mIsResetPositionNeeded = false;
276 }
277
278 if (mShadowMaskName) {
279 al::setShadowMaskDropLength(
280 actor: mActor, dropLength: mShadowMaskDropLength + rs::getPlayerShadowDropLength(mActor), maskName: mShadowMaskName);
281 }
282}
283