1#include "Player/HackerStateWingFly.h"
2
3#include "Library/Layout/LayoutActionFunction.h"
4#include "Library/LiveActor/ActorActionFunction.h"
5#include "Library/LiveActor/ActorCollisionFunction.h"
6#include "Library/LiveActor/ActorMovementFunction.h"
7#include "Library/LiveActor/ActorPoseUtil.h"
8#include "Library/LiveActor/ActorSensorUtil.h"
9#include "Library/Math/MathUtil.h"
10#include "Library/Nerve/NerveSetupUtil.h"
11#include "Library/Nerve/NerveUtil.h"
12
13#include "Util/Hack.h"
14#include "Util/ObjUtil.h"
15#include "Util/PlayerCollisionUtil.h"
16#include "Util/SensorMsgFunction.h"
17
18namespace {
19NERVE_HOST_TYPE_IMPL(HackerStateWingFly, FlyRiseToHighest);
20NERVE_HOST_TYPE_IMPL(HackerStateWingFly, FlyRiseToTop);
21NERVE_HOST_TYPE_IMPL(HackerStateWingFly, FlyTop);
22NERVE_HOST_TYPE_IMPL(HackerStateWingFly, Fall);
23NERVE_HOST_TYPE_IMPL(HackerStateWingFly, FallFly);
24NERVE_HOST_TYPE_IMPL(HackerStateWingFly, Trample);
25NERVE_HOST_TYPE_IMPL(HackerStateWingFly, UpperPunch);
26
27NERVES_MAKE_STRUCT(HostType, FlyRiseToHighest, Fall, Trample, UpperPunch, FlyRiseToTop, FlyTop,
28 FallFly);
29} // namespace
30
31inline bool isTriggerHacker(IUsePlayerHack** hacker) {
32 return rs::isTriggerHackAnyButton(*hacker) || rs::isTriggerHackSwing(*hacker);
33}
34
35HackerStateWingFly::HackerStateWingFly(al::LiveActor* actor, IUsePlayerHack** hacker,
36 IUsePlayerCollision* collision)
37 : al::ActorStateBase("はばたき飛行", actor), mHacker(hacker), mCollision(collision) {
38 mFlyLimit.y = sead::Mathf::minNumber() / 2.0f;
39 initNerve(nerve: &NrvHostType.FlyRiseToHighest, stateCount: 0);
40}
41
42void HackerStateWingFly::appear() {
43 al::NerveStateBase::appear();
44 mFallTimeDelay = 0;
45
46 if (mIsJudgeFall) {
47 mIsJudgeFall = false;
48 al::setNerve(user: this, nerve: &NrvHostType.Fall);
49 return;
50 }
51
52 goFlyRise();
53}
54
55void HackerStateWingFly::goFlyRise() {
56 al::Nerve* nerve;
57
58 if (al::getTrans(actor: mActor).y < mFlyLimit.y)
59 nerve = &NrvHostType.FlyRiseToHighest;
60 else
61 nerve = &NrvHostType.FlyRiseToTop;
62
63 al::setNerve(user: this, nerve);
64}
65
66void HackerStateWingFly::attackSensor(al::HitSensor* self, al::HitSensor* other) {
67 if (mParam.actionTrample != nullptr &&
68 rs::trySendMsgPlayerReflectOrTrample(mActor, self, other)) {
69 al::setNerve(user: this, nerve: &NrvHostType.Trample);
70 return;
71 }
72
73 if (canUpperPunch(self, other) &&
74 (al::sendMsgPlayerUpperPunch(receiver: other, sender: self) || rs::sendMsgHackUpperPunch(source: other, target: self) ||
75 rs::sendMsgHackObjUpperPunch(source: other, target: self))) {
76 al::setVelocityZeroV(mActor);
77 al::setNerve(user: this, nerve: &NrvHostType.UpperPunch);
78 }
79}
80
81bool HackerStateWingFly::canUpperPunch(al::HitSensor* self, al::HitSensor* other) const {
82 if (mParam.actionUpperPunch == nullptr)
83 return false;
84 if (al::isNerve(user: this, nerve: &NrvHostType.Fall))
85 return false;
86 if (al::isNerve(user: this, nerve: &NrvHostType.FallFly))
87 return false;
88 if (!al::isSensorName(self, "Head"))
89 return false;
90
91 sead::Vector3f sensors;
92 sead::Vector3f gravity = -al::getGravity(actor: mActor);
93 al::calcVecBetweenSensors(&sensors, self, other);
94 if (sensors.dot(t: gravity) < 0.0f)
95 return false;
96
97 al::parallelizeVec(&sensors, gravity, sensors);
98 if (!(al::getSensorRadius(other) < sensors.length()))
99 return false;
100
101 if (al::isNerve(user: this, nerve: &NrvHostType.UpperPunch) && isOnGround())
102 return false;
103
104 return true;
105}
106
107void HackerStateWingFly::updateFlyLimit() {
108 if (mFlyLimit.y < al::getTrans(actor: mActor).y)
109 mFlyLimit.set(al::getTrans(actor: mActor));
110}
111
112bool HackerStateWingFly::judgeStart() {
113 if (!isTriggerHacker(hacker: mHacker))
114 return false;
115
116 al::LiveActor* actor = mActor;
117 if (rs::isTriggerHackSwing(*mHacker)) {
118 al::setActionFrameRate(actor, rate: mParam.swingFramerate);
119 mAccel = mParam.swingAccel;
120 mVelocityY = mParam.swingVelocityY;
121 return true;
122 }
123
124 al::setActionFrameRate(actor, rate: mParam.defaultFramerate);
125 mAccel = mParam.defaultAccel;
126 mVelocityY = mParam.defaultVelocityY;
127 return true;
128}
129
130void HackerStateWingFly::updateMove() {
131 al::LiveActor* actor = mActor;
132 sead::Vector3f dir = sead::Vector3f(0.0f, 0.0f, 0.0f);
133
134 rs::addHackActorAccelStick(actor, *mHacker, &dir, mAccel, sead::Vector3f::ey);
135 al::turnToDirection(actor, dir, deg: mParam.turnAngle);
136
137 if (mCollision != nullptr) {
138 rs::reboundVelocityFromCollision(actor, mCollision, 0.0f, 0.0f, 1.0f);
139 return;
140 }
141
142 if (al::isCollidedCeiling(actor)) {
143 const sead::Vector3f& ceilingNormal = al::getCollidedCeilingNormal(actor);
144 f32 speedTowardsCeiling = ceilingNormal.dot(t: al::getVelocity(actor));
145 if (speedTowardsCeiling < 0.0f)
146 *al::getVelocityPtr(actor) -= ceilingNormal * speedTowardsCeiling * 1.1f;
147 }
148
149 if (al::isCollidedWall(actor)) {
150 const sead::Vector3f& wallNormal = al::getCollidedWallNormal(actor);
151 f32 speedTowardsWall = wallNormal.dot(t: al::getVelocity(actor));
152 if (speedTowardsWall < 0.0f)
153 *al::getVelocityPtr(actor) -= wallNormal * speedTowardsWall * 1.1f;
154 }
155}
156
157bool HackerStateWingFly::isOnGround() const {
158 al::LiveActor* actor = mActor;
159 if (mCollision != nullptr)
160 return rs::isOnGround(actor, mCollision);
161
162 return al::isOnGround(actor, 0);
163}
164
165bool HackerStateWingFly::tryUpperPunchToCollision() {
166 al::LiveActor* actor = mActor;
167 bool isCollidedCeiling =
168 mCollision == nullptr ? al::isCollidedCeiling(actor) : rs::isCollidedCeiling(mCollision);
169
170 if (!isCollidedCeiling)
171 return false;
172
173 al::HitSensor* other = mCollision == nullptr ? al::tryGetCollidedCeilingSensor(actor) :
174 rs::tryGetCollidedCeilingSensor(mCollision);
175 al::HitSensor* self = al::getHitSensor(actor, "Head");
176
177 if (!al::sendMsgPlayerUpperPunch(receiver: other, sender: self))
178 return false;
179
180 al::setVelocityZeroV(actor);
181 al::setNerve(user: this, nerve: &NrvHostType.UpperPunch);
182 return true;
183}
184
185void HackerStateWingFly::updateFlyAction() {
186 al::LiveActor* actor = mActor;
187 if (al::isFirstStep(user: this)) {
188 if (!al::isActionPlaying(actor, actionName: "FallFly") ||
189 (al::isActionPlaying(actor, actionName: "FallFly") && al::isActionEnd(actor)))
190 al::tryStartActionIfNotPlaying(actor, actionName: mParam.actionFly);
191
192 mFallTimeDelay = 0;
193 }
194
195 if (al::isActionPlaying(actor, actionName: "FallFly") && al::isActionEnd(actor))
196 al::tryStartActionIfNotPlaying(actor, actionName: mParam.actionFly);
197
198 if (!isTriggerHacker(hacker: mHacker))
199 return;
200
201 if (rs::isTriggerHackSwing(*mHacker)) {
202 al::setActionFrameRate(actor, rate: mParam.swingFramerate);
203 mAccel = mParam.swingAccel;
204 mVelocityY = mParam.swingVelocityY;
205 } else {
206 al::setActionFrameRate(actor, rate: mParam.defaultFramerate);
207 mAccel = mParam.defaultAccel;
208 mVelocityY = mParam.defaultVelocityY;
209 }
210 mFallTimeDelay = 0;
211}
212
213void HackerStateWingFly::exeFlyRiseToHighest() {
214 al::LiveActor* actor = mActor;
215 updateFlyAction();
216 if (tryUpperPunchToCollision())
217 return;
218
219 if (al::getTrans(actor).y > mFlyLimit.y + mParam.yOvershootMax) {
220 al::setNerve(user: this, nerve: &NrvHostType.FlyTop);
221 return;
222 }
223
224 if (al::getTrans(actor).y >= mFlyLimit.y) {
225 al::setNerve(user: this, nerve: &NrvHostType.FlyRiseToTop);
226 return;
227 }
228
229 al::setVelocityY(actor, y: mVelocityY);
230 al::addVelocityToGravity(actor, force: 4.0f);
231 al::scaleVelocityHV(actor, factorH: 0.95f, factorV: 0.7f);
232 if (mFallTimeDelay >= 21) {
233 al::setNerve(user: this, nerve: &NrvHostType.Fall);
234 return;
235 }
236
237 mFallTimeDelay++;
238 updateMove();
239}
240
241void HackerStateWingFly::exeFlyRiseToTop() {
242 al::LiveActor* actor = mActor;
243 updateFlyAction();
244 if (tryUpperPunchToCollision())
245 return;
246
247 f32 endVelY;
248 if (al::getTrans(actor).y < mFlyLimit.y) {
249 endVelY = mVelocityY;
250 } else {
251 f32 flyLerpTime = al::calcNerveSquareOutRate(user: this, max: 30);
252 f32 posY = mFlyLimit.y + al::lerpValue(a: 0.0f, b: mParam.yOvershootMax, t: flyLerpTime);
253 endVelY = posY - getTrans(actor).y;
254 }
255
256 if (0.0f < endVelY) {
257 f32 startVelY = al::getVelocity(actor).y;
258 endVelY = al::lerpValue(a: startVelY, b: endVelY, t: mParam.flyStartLerpTime);
259 al::setVelocityY(actor, y: endVelY);
260 }
261
262 al::scaleVelocityHV(actor, factorH: 0.95f, factorV: 0.7f);
263 if (al::getTrans(actor).y >= mFlyLimit.y + mParam.yOvershootMax) {
264 al::setNerve(user: this, nerve: &NrvHostType.FlyTop);
265 return;
266 }
267
268 if (mFallTimeDelay >= 21) {
269 al::setNerve(user: this, nerve: &NrvHostType.Fall);
270 return;
271 }
272
273 mFallTimeDelay++;
274 updateMove();
275}
276
277void HackerStateWingFly::exeFlyTop() {
278 al::LiveActor* actor = mActor;
279 updateFlyAction();
280
281 sead::Vector3f trans = al::getTrans(actor);
282 f32 maxFlyY = mFlyLimit.y + mParam.yOvershootMax;
283 if (trans.y > maxFlyY) {
284 al::getTransPtr(actor)->y = al::lerpValue(a: al::getTrans(actor).y, b: maxFlyY, t: 0.01f);
285 al::setVelocityZeroY(actor);
286 }
287
288 if (tryUpperPunchToCollision())
289 return;
290
291 al::scaleVelocityHV(actor: mActor, factorH: 0.95f, factorV: 0.7f);
292 if (mFallTimeDelay >= 21) {
293 al::setNerve(user: this, nerve: &NrvHostType.Fall);
294 return;
295 }
296
297 mFallTimeDelay++;
298 updateMove();
299}
300
301void HackerStateWingFly::exeFall() {
302 if (al::isFirstStep(user: this)) {
303 if (!al::isActionPlaying(actor: mActor, actionName: mParam.actionFly)) {
304 al::startAction(actor: mActor, actionName: mParam.actionFall);
305 al::setActionFrameRate(actor: mActor, rate: 1.0f);
306 mAccel = mParam.defaultAccel;
307 mVelocityY = mParam.defaultVelocityY;
308 }
309 mFallFrame = 0;
310 }
311
312 if (al::isActionPlaying(actor: mActor, actionName: mParam.actionFly) && al::getActionFrame(actor: mActor) < mFallFrame) {
313 al::startAction(actor: mActor, actionName: mParam.actionFall);
314 al::setActionFrameRate(actor: mActor, rate: 1.0f);
315 mAccel = mParam.defaultAccel;
316 mVelocityY = mParam.defaultVelocityY;
317 } else {
318 mFallFrame = al::getActionFrame(actor: mActor);
319 }
320
321 al::addVelocityToGravity(actor: mActor, force: mParam.gravity);
322 al::scaleVelocityHV(actor: mActor, factorH: 0.95f, factorV: 0.94f);
323 if (isTriggerHacker(hacker: mHacker)) {
324 al::setVelocityZeroV(mActor);
325 al::LiveActor* actor = mActor;
326 if (rs::isTriggerHackSwing(*mHacker)) {
327 al::setActionFrameRate(actor, rate: mParam.swingFramerate);
328 mAccel = mParam.swingAccel;
329 mVelocityY = mParam.swingVelocityY;
330 } else {
331 al::setActionFrameRate(actor, rate: mParam.defaultFramerate);
332 mAccel = mParam.defaultAccel;
333 mVelocityY = mParam.defaultVelocityY;
334 }
335 al::setNerve(user: this, nerve: &NrvHostType.FallFly);
336 return;
337 }
338
339 if (isOnGround()) {
340 kill();
341 return;
342 }
343 updateMove();
344}
345
346void HackerStateWingFly::exeFallFly() {
347 if (al::isFirstStep(user: this))
348 al::startAction(actor: mActor, actionName: "FallFly");
349
350 bool isLessStep = al::isLessStep(user: this, step: 20);
351 al::LiveActor* actor = mActor;
352 if (!isLessStep) {
353 al::addVelocityToGravity(actor, force: mParam.gravity);
354 actor = mActor;
355 }
356
357 al::scaleVelocityHV(actor, factorH: 0.95f, factorV: 0.94f);
358 if (isTriggerHacker(hacker: mHacker)) {
359 al::Nerve* nerve;
360 if (al::getTrans(actor: mActor).y < mFlyLimit.y)
361 nerve = &NrvHostType.FlyRiseToHighest;
362 else
363 nerve = &NrvHostType.FlyRiseToTop;
364
365 al::setNerve(user: this, nerve);
366 return;
367 }
368
369 updateMove();
370 if (isOnGround()) {
371 kill();
372 return;
373 }
374
375 if (al::isActionEnd(actor: mActor))
376 al::setNerve(user: this, nerve: &NrvHostType.Fall);
377}
378
379void HackerStateWingFly::exeTrample() {
380 al::LiveActor* actor = mActor;
381 if (al::isFirstStep(user: this)) {
382 al::startAction(actor, actionName: mParam.actionTrample);
383 al::setVelocityZeroV(actor);
384 al::addVelocityJump(actor, force: 20.0f);
385 }
386
387 if (al::isActionEnd(actor)) {
388 al::setNerve(user: this, nerve: &NrvHostType.Fall);
389 return;
390 }
391
392 if (isTriggerHacker(hacker: mHacker)) {
393 if (rs::isTriggerHackSwing(*mHacker)) {
394 al::setActionFrameRate(actor, rate: mParam.swingFramerate);
395 mAccel = mParam.swingAccel;
396 mVelocityY = mParam.swingVelocityY;
397 } else {
398 al::setActionFrameRate(actor, rate: mParam.defaultFramerate);
399 mAccel = mParam.defaultAccel;
400 mVelocityY = mParam.defaultVelocityY;
401 }
402
403 al::Nerve* nerve;
404 if (al::getTrans(actor: mActor).y < mFlyLimit.y)
405 nerve = &NrvHostType.FlyRiseToHighest;
406 else
407 nerve = &NrvHostType.FlyRiseToTop;
408
409 al::setNerve(user: this, nerve);
410 return;
411 }
412
413 if (isOnGround()) {
414 kill();
415 return;
416 }
417 al::addVelocityToGravity(actor, force: mParam.gravity);
418 al::scaleVelocityHV(actor, factorH: 0.95f, factorV: 0.94f);
419 updateMove();
420}
421
422void HackerStateWingFly::exeUpperPunch() {
423 al::LiveActor* actor = mActor;
424 if (al::isFirstStep(user: this))
425 al::startAction(actor, actionName: mParam.actionUpperPunch);
426
427 if (al::isActionEnd(actor)) {
428 al::setNerve(user: this, nerve: &NrvHostType.Fall);
429 return;
430 }
431
432 if (al::isGreaterStep(user: this, step: 1) && isTriggerHacker(hacker: mHacker)) {
433 if (rs::isTriggerHackSwing(*mHacker)) {
434 al::setActionFrameRate(actor, rate: mParam.swingFramerate);
435 mAccel = mParam.swingAccel;
436 mVelocityY = mParam.swingVelocityY;
437 } else {
438 al::setActionFrameRate(actor, rate: mParam.defaultFramerate);
439 mAccel = mParam.defaultAccel;
440 mVelocityY = mParam.defaultVelocityY;
441 }
442
443 al::Nerve* nerve;
444 if (al::getTrans(actor: mActor).y < mFlyLimit.y)
445 nerve = &NrvHostType.FlyRiseToHighest;
446 else
447 nerve = &NrvHostType.FlyRiseToTop;
448
449 al::setNerve(user: this, nerve);
450 return;
451 }
452
453 al::addVelocityToGravity(actor, force: mParam.gravity);
454 al::scaleVelocityHV(actor, factorH: 0.95f, factorV: 0.94f);
455 updateMove();
456}
457