SMG-Decomp
A decompilation of Super Mario Galaxy 1
Loading...
Searching...
No Matches
Poihana.cpp
1#include "Game/Enemy/Poihana.hpp"
2#include "Game/Util.hpp"
3#include "JSystem/JMath/JMath.hpp"
4
5namespace {
6 const Vec sNormalBinderPos = { 0.0f, 130.0f, 120.0f };
7 const Vec sTrampleBinderPos = { 0.0f, 150.0f, 0.0f };
8};
9
10Poihana::Poihana(const char *pName) : LiveActor(pName) {
11 mAnimScaleCtrl = nullptr;
12 mBindStarPointer = nullptr;
13 mCamInfo = nullptr;
14 mBindedActor = nullptr;
15 mLaunchIntensity = 0.0f;
16 mRespawnPos.setInline(0.0f);
17 _AC = 0.0f;
18 _B0 = 0.0f;
19 mHomePos.setInline(0.0f);
20 _C0 = 1.0f;
21 mBoundTimer = -1;
22 mBehavior = POIHANA_BEHAVIOR_NORMAL;
23 mCanDrown = false;
24 mWaterColumn = nullptr;
25 mIsActive = false;
26 _E5 = 0;
27}
28
29/*void Poihana::init(const JMapInfoIter &rIter) {
30 MR::initDefaultPos(this, rIter);
31 MR::initActorCamera(this, rIter, &mCamInfo);
32 initModelManagerWithAnm("Poihana", nullptr, false);
33
34 MR::connectToSceneEnemy(this);
35
36 // Initialize sensors
37 initHitSensor(2);
38 MR::addHitSensorPriorBinder(this, "binder", 8, 125.0f, sNormalBinderPos);
39 MR::addHitSensorAtJoint(this, "body", "Body", 30, 8, 70.0f, TVec3f(0.0f, 0.0f, 0.0f));
40
41 // Initialize binder
42 bool useSmallBinder = false;
43 MR::getJMapInfoArg7NoInit(rIter, &useSmallBinder);
44
45 if (useSmallBinder) {
46 initBinder(100.0f, 100.0f, 0);
47 }
48 else {
49 initBinder(150.0f, 150.0f, 0);
50 }
51
52 mIsActive = true;
53 MR::setGroupClipping(this, rIter, 0x20);
54 initEffectKeeper(1, nullptr, false);
55 initSound(4, false);
56
57 // Initialize 2P behavior
58 MR::initStarPointerTarget(this, 150.0f, TVec3f(0.0f, 100.0f, 0.0f));
59 mAnimScaleCtrl = new AnimScaleController(nullptr);
60 mBindStarPointer = new WalkerStateBindStarPointer(this, mAnimScaleCtrl);
61
62 MR::initShadowVolumeSphere(this, 80.0f);
63 MR::addToAttributeGroupSearchTurtle(this);
64
65 mRespawnPos.set(mPosition);
66 mHomePos.set(mRespawnPos);
67
68 // Calculate launch intensity, thanks to Shibbo for helping me on that one
69 s32 launchIntensity = 1000;
70 MR::getJMapInfoArg0NoInit(rIter, &launchIntensity);
71 float launchIntensityF = 2.0f * launchIntensity;
72
73 if (launchIntensityF > 0) {
74 f32 factor;
75 f32 reciprocal = __frsqrte(launchIntensityF);
76 factor = reciprocal * launchIntensityF;
77 launchIntensityF = -(factor * reciprocal - 3.0f) * factor * 0.5f;
78 }
79
80 mLaunchIntensity = -launchIntensityF;
81
82 // Setup color
83 //s32 color = 0;
84 //MR::getJMapInfoArg2NoInit(rIter, &color);
85 //MR::startBtpAndSetFrameAndStop(this, "ColorChange", color);
86
87 // Setup behaviors
88 //MR::getJMapInfoArg1NoInit(rIter, &mActiveRange);
89 MR::getJMapInfoArg3NoInit(rIter, &mBehavior);
90 MR::getJMapInfoArg4NoInit(rIter, &mCanDrown);
91
92 if (mCanDrown) {
93 mWaterColumn = MR::createModelObjMapObj("エフェクト水柱", "WaterColumn", (MtxPtr)getBaseMtx());
94 mWaterColumn->mScale.setAll(2.0f);
95 }
96
97 MR::tryCreateMirrorActor(this, nullptr);
98 //MR::useStageSwitchAwake(this, rIter);
99
100 if (mBehavior == POIHANA_BEHAVIOR_SLEEP) {
101 initNerve(&NrvPoihana::PoihanaNrvSleep::sInstance);
102 }
103 else {
104 initNerve(&NrvPoihana::PoihanaNrvWait::sInstance);
105 }
106
107 makeActorAppeared();
108}*/
109
110void Poihana::initAfterPlacement() {
111 TVec3f gravityNegated;
112 JGeometry::negateInternal((f32 *)&mGravity, (f32 *)&gravityNegated);
113 TPos3f baseMtx;
114 MR::makeMtxUpNoSupportPos(&baseMtx, gravityNegated, mPosition);
115 MR::setBaseTRMtx(this, baseMtx);
116 MR::calcFrontVec(&mFrontVec, this);
117 MR::trySetMoveLimitCollision(this);
118}
119
120void Poihana::control() {
121 if (!isNerve(&NrvPoihana::PoihanaNrvHide::sInstance)) {
122 mAnimScaleCtrl->updateNerve();
123 calcBound();
124 controlVelocity();
125 calcMyGravity();
126
127 if (!tryDrown() && !tryDPDSwoon() && tryHipDropShock()) {
128 return;
129 }
130 }
131}
132
134 TPos3f baseMtx;
135 MR::calcMtxFromGravityAndZAxis(&baseMtx, this, mGravity, mFrontVec);
136
137 if (isNerveTypeWalkOrWait()) {
138 MR::blendMtx((MtxPtr)getBaseMtx(), (MtxPtr)&baseMtx, 0.3f, (MtxPtr)&baseMtx);
139 }
140
141 MR::setBaseTRMtx(this, baseMtx);
142
143 TVec3f newScale;
144 newScale.multPS(mScale, mAnimScaleCtrl->_C);
145 MR::setBaseScale(this, newScale);
146}
147
148// This inline function might be used elsewhere too? It seems unusual for it to be used once
149inline void calcRepelVector(const TVec3f &agent, const TVec3f &object, TVec3f& dst) {
150 JMAVECScaleAdd(agent.toCVec(), object.toCVec(), dst.toVec(), -agent.dot(object));
151}
152
153void Poihana::attackSensor(HitSensor *pSender, HitSensor *pReceiver) {
154 bool ret = false;
155
156 if (MR::isSensorPlayer(pReceiver) || MR::isSensorEnemy(pReceiver) ||
157 MR::isSensorMapObj(pReceiver)) {
158 ret = true;
159 }
160
161 if (!ret) {
162 return;
163 }
164
165 if (MR::isSensorEnemy(pSender)) {
166 if (MR::isSensorPlayer(pReceiver)) {
167 contactMario(pSender, pReceiver);
168 }
169
170 if (MR::sendMsgPush(pReceiver, pSender)) {
171 if (MR::isSensorPlayer(pReceiver)) {
172 ret = false;
173 if (isNerve(&NrvPoihana::PoihanaNrvShock::sInstance) ||
174 isNerve(&NrvPoihana::PoihanaNrvSwoonLand::sInstance) ||
175 isNerve(&NrvPoihana::PoihanaNrvSwoon::sInstance) ||
176 isNerve(&NrvPoihana::PoihanaNrvRecover::sInstance)) {
177 ret = true;
178 }
179
180 if (ret) {
181 return;
182 }
183 }
184
185 TVec3f pushVelocity(mPosition - pReceiver->mActor->mPosition);
186 MR::normalizeOrZero(&pushVelocity);
187
188 if (mVelocity.dot(pushVelocity) < 0.0f) {
189 const TVec3f& velocity = mVelocity;
190 calcRepelVector(pushVelocity, velocity, mVelocity);
191 }
192 }
193 }
194}
195
196bool Poihana::receiveMsgPush(HitSensor *pSender, HitSensor *pReceiver) {
197 if (MR::isSensorEnemy(pSender) || MR::isSensorMapObj(pSender)) {
198 TVec3f pushOffset(mPosition - pSender->mActor->mPosition);
199 MR::normalizeOrZero(&pushOffset);
200 JMAVECScaleAdd(pushOffset.toCVec(), mVelocity.toCVec(), mVelocity.toVec(), 1.5f);
201
202 return true;
203 }
204
205 return false;
206}
207
208bool Poihana::receiveMsgPlayerAttack(u32 msg, HitSensor *pSender, HitSensor *pReceiver) {
209 if (MR::isMsgStarPieceAttack(msg)) {
210 return true;
211 }
212
213 if (MR::isMsgPlayerTrample(msg) || MR::isMsgPlayerHipDrop(msg)) {
214 bool flag = false;
215
216 if (isNerve(&NrvPoihana::PoihanaNrvDrown::sInstance) ||
217 isNerve(&NrvPoihana::PoihanaNrvHide::sInstance) ||
218 isNerve(&NrvPoihana::PoihanaNrvAppear::sInstance) ||
219 isNerve(&NrvPoihana::PoihanaNrvShock::sInstance)) {
220 flag = true;
221 }
222
223 if (flag) {
224 goto here;
225 }
226
227 flag = false;
228 if (isNerve(&NrvPoihana::PoihanaNrvSleepStart::sInstance) ||
229 isNerve(&NrvPoihana::PoihanaNrvSleep::sInstance) ||
230 isNerve(&NrvPoihana::PoihanaNrvGetUp::sInstance)) {
231 flag = true;
232 }
233
234 if (flag) {
235here:
236 startBound();
237 MR::startSound(this, "SE_EV_POIHANA_TRAMPLE", -1, -1);
238
239 if (MR::isMsgPlayerHipDrop(msg)) {
240 MR::sendMsgAwayJump(pSender, pReceiver);
241 }
242
243 return true;
244 }
245
246 MR::setSensorOffset(this, "binder", sTrampleBinderPos);
247 MR::setSensorRadius(this, "binder", 125.0f);
248 MR::validateHitSensor(this, "binder");
249 }
250
251 if (MR::isMsgPlayerHitAll(msg) && tryShock()) {
252 MR::stopSceneForDefaultHit(3);
253 return true;
254 }
255
256 return false;
257}
258
259bool Poihana::receiveMsgEnemyAttack(u32 msg, HitSensor *pSender, HitSensor *pReceiver) {
260 if (MR::isMsgExplosionAttack(msg) && tryShock()) {
261 return true;
262 }
263
264 return false;
265}
266
267/*bool Poihana::receiveOtherMsg(u32 msg, HitSensor *pSender, HitSensor *pReceiver) {
268 if (MR::isMsgAutoRushBegin(msg) && MR::isSensorPlayer(pSender)) {
269 if (isNerve(&NrvPoihana::PoihanaNrvShootUpCharge::sInstance)) {
270 return false;
271 }
272 else if (MR::isOnGroundPlayer()) {
273 if (isNerve(&NrvPoihana::PoihanaNrvShootUp::sInstance)) {
274 if (getNerveStep() < 30) {
275 if (!tryToStartBind(pSender)) {
276 return false;
277 }
278 }
279 }
280 else if (isNerve(&NrvPoihana::PoihanaNrvShootUpCharge::sInstance) ||
281 !MR::isNear(pSender, pReceiver, 100.0f)) {
282 return false;
283 }
284 else {
285 setNerve(&NrvPoihana::PoihanaNrvShootUpCharge::sInstance);
286 }
287 }
288 else if (tryToStartBind(pSender)) {
289 setNerve(&NrvPoihana::PoihanaNrvShootUp::sInstance);
290 return true;
291 }
292 }
293 else if (MR::isMsgUpdateBaseMtx(msg) && mBindedActor) {
294 updateBindActorMtx();
295 return true;
296 }
297
298 return false;
299}*/
300
301void Poihana::exeNonActive() {
302 if (MR::isFirstStep(this)) {
303 mVelocity.zero();
304 MR::offBind(this);
305 MR::offCalcShadow(this, nullptr);
306 MR::offCalcAnim(this);
307
308 mIsActive = false;
309
310 MR::invalidateHitSensors(this);
311 }
312
313 if (MR::isNearPlayerAnyTime(this, 3500.0f)) {
314 if (mBehavior == POIHANA_BEHAVIOR_SLEEP) {
315 setNerve(&NrvPoihana::PoihanaNrvSleep::sInstance);
316 }
317 else {
318 setNerve(&NrvPoihana::PoihanaNrvWait::sInstance);
319 }
320 }
321}
322
323void Poihana::endNonActive() {
324 MR::onBind(this);
325 MR::onCalcShadow(this, nullptr);
326 MR::onCalcAnim(this);
327
328 mIsActive = true;
329
330 MR::setSensorOffset(this, "binder", sNormalBinderPos);
331 MR::setSensorRadius(this, "binder", 125.0f);
332 MR::validateHitSensor(this, "binder");
333 MR::validateHitSensors(this);
334}
335
336void Poihana::exeWait() {
337 if (MR::isFirstStep(this)) {
338 MR::startBckNoInterpole(this, "Wait");
339 MR::setSensorOffset(this, "binder", sNormalBinderPos);
340 MR::setSensorRadius(this, "binder", 125.0f);
341 MR::validateHitSensor(this, "binder");
342 }
343
344 if (MR::isNearPlayer(this, 800.0f)) {
345 setNerve(&NrvPoihana::PoihanaNrvSearch::sInstance);
346 }
347 else if (MR::isGreaterStep(this, 180)) {
348 setNerve(&NrvPoihana::PoihanaNrvWalkAround::sInstance);
349 }
350 else {
351 tryNonActive();
352 }
353}
354
355void Poihana::exeWalkAround() {
356 if (MR::isFirstStep(this)) {
357 if (!MR::isBckPlaying(this, "Walk")) {
358 MR::startBck(this, "Walk", nullptr);
359 }
360
361 mRandDir = MR::getRandom((s32)-2, (s32)2);
362 }
363
364 MR::rotateVecDegree(&mFrontVec, mGravity, mRandDir);
365 JMAVECScaleAdd(mFrontVec.toCVec(), mVelocity.toCVec(), mVelocity.toVec(), 0.5f);
366
367 if (isNeedForBackHome()) {
368 setNerve(&NrvPoihana::PoihanaNrvGoBack::sInstance);
369 }
370
371 else if (MR::isNearPlayer(this, 800.0f)) {
372 setNerve(&NrvPoihana::PoihanaNrvSearch::sInstance);
373 }
374
375 else if (MR::isGreaterStep(this, 120)) {
376 if (mBehavior == POIHANA_BEHAVIOR_SLEEP) {
377 setNerve(&NrvPoihana::PoihanaNrvSleepStart::sInstance);
378 }
379 else {
380 setNerve(&NrvPoihana::PoihanaNrvWait::sInstance);
381 }
382 }
383}
384
385void Poihana::exeSleepStart() {
386 if (MR::isFirstStep(this)) {
387 MR::startBck(this, "SleepStart", nullptr);
388 MR::startSound(this, "SE_EV_POIHANA_SLEEP_START", -1, -1);
389 MR::invalidateHitSensor(this, "binder");
390 }
391
392 if (MR::isBckStopped(this)) {
393 setNerve(&NrvPoihana::PoihanaNrvSleep::sInstance);
394 }
395}
396
397void Poihana::exeSleep() {
398 if (MR::isFirstStep(this)) {
399 MR::startBck(this, "Sleep", nullptr);
400 MR::invalidateHitSensor(this, "binder");
401 }
402
403 if (isNeedForGetUp()) {
404 setNerve(&NrvPoihana::PoihanaNrvGetUp::sInstance);
405 }
406 else {
407 tryNonActive();
408 }
409}
410
411void Poihana::exeGetUp() {
412 if (MR::isFirstStep(this)) {
413 MR::startBck(this, "GetUp", nullptr);
414 MR::startSound(this, "SE_EV_POIHANA_WAKEUP", -1, -1);
415 MR::startSound(this, "SE_EM_POIHANA_WAKEUP", -1, -1);
416 }
417
418 if (MR::isBckStopped(this)) {
419 MR::setSensorOffset(this, "binder", sNormalBinderPos);
420 MR::setSensorRadius(this, "binder", 125.0f);
421 MR::validateHitSensor(this, "binder");
422 setNerve(&NrvPoihana::PoihanaNrvWait::sInstance);
423 }
424}
425
426void Poihana::exeSearch() {
427 if (MR::isFirstStep(this)) {
428 MR::startBck(this, "Search", nullptr);
429 MR::startSound(this, "SE_EV_POIHANA_FIND", -1, -1);
430 }
431
432 MR::turnDirectionToTargetUseGroundNormalDegree(this, &mFrontVec, *MR::getPlayerPos(), 4.0f);
433
434 if (MR::isBckStopped(this)) {
435 setNerve(&NrvPoihana::PoihanaNrvChasePlayer::sInstance);
436 }
437}
438
439void Poihana::exeChasePlayer() {
440 if (MR::isFirstStep(this)) {
441 MR::startBck(this, "Run", nullptr);
442 MR::setSensorOffset(this, "binder", sNormalBinderPos);
443 MR::setSensorRadius(this, "binder", 125.0f);
444 MR::validateHitSensor(this, "binder");
445 }
446
447 MR::turnDirectionToTargetUseGroundNormalDegree(this, &mFrontVec, *MR::getPlayerPos(), 4.0f);
448 JMAVECScaleAdd(mFrontVec.toCVec(), mVelocity.toCVec(), mVelocity.toVec(), 0.5f);
449
450 if (isNeedForBackHome()) {
451 setNerve(&NrvPoihana::PoihanaNrvGoBack::sInstance);
452 }
453}
454
455void Poihana::exeShootUpCharge() {
456 if (MR::isFirstStep(this)) {
457 MR::startBck(this, "ThrowStart", nullptr);
458 }
459
460 TVec3f& gravity = mGravity;
461 f32 dot = gravity.dot(mVelocity);
462 mVelocity.scale(dot, gravity);
463
464 if (MR::isBckStopped(this)) {
465 setNerve(&NrvPoihana::PoihanaNrvShootUp::sInstance);
466 }
467}
468
469/*void Poihana::exeShootUp() {
470 if (MR::isFirstStep(this)) {
471 MR::startBck(this, "Throw", nullptr);
472 MR::startSound(this, "SE_EV_POIHANA_SHOOT_UP", -1, -1);
473 MR::startActorCameraNoTarget(this, mCamInfo, -1);
474 }
475
476 f32 dot = mGravity.dot(mVelocity);
477 mVelocity.scale(dot, mGravity);
478
479 if (MR::isStep(this, 2)) {
480 endBind();
481 MR::invalidateHitSensor(this, "binder");
482 }
483
484 if (MR::isStep(this, 30)) {
485 MR::setSensorOffset(this, "binder", sNormalBinderPos);
486 MR::setSensorRadius(this, "binder", 125.0f);
487 MR::validateHitSensor(this, "binder");
488 }
489
490 if (MR::isBckStopped(this)) {
491 if (mBehavior == POIHANA_BEHAVIOR_NEW_HOME) {
492 mHomePos.set(mPosition);
493 setNerve(&NrvPoihana::PoihanaNrvWalkAround::sInstance);
494 }
495 else {
496 setNerve(&NrvPoihana::PoihanaNrvGoBack::sInstance);
497 }
498 }
499}*/
500
501void Poihana::endShootUp() {
502 endBind();
503
504 MR::setSensorOffset(this, "binder", sNormalBinderPos);
505 MR::setSensorRadius(this, "binder", 125.0f);
506 MR::validateHitSensor(this, "binder");
507
508 MR::endActorCamera(this, mCamInfo, true, -1);
509}
510
511void Poihana::exeGoBack() {
512 if (MR::isFirstStep(this) && !MR::isBckPlaying(this, "Walk")) {
513 MR::startBck(this, "Walk", nullptr);
514 }
515
516 MR::turnDirectionToTargetUseGroundNormalDegree(this, &mFrontVec, mHomePos, 2.0f);
517 JMAVECScaleAdd(mFrontVec.toCVec(), mVelocity.toCVec(), mVelocity.toVec(), 0.5f);
518
519 if (MR::isNearPlayer(this, 800.0f) && MR::isGreaterStep(this, 120)) {
520 setNerve(&NrvPoihana::PoihanaNrvSearch::sInstance);
521 }
522 else if (MR::isNear(this, mHomePos, 100.0f)) {
523 setNerve(&NrvPoihana::PoihanaNrvWait::sInstance);
524 }
525}
526
527void Poihana::exeShock() {
528 if (MR::isFirstStep(this)) {
529 MR::startBck(this, "PunchDamage", nullptr);
530 MR::startBlowHitSound(this);
531 MR::invalidateHitSensor(this, "binder");
532 }
533
534 if (MR::isOnGround(this) && MR::isGreaterStep(this, 12)) {
535 setNerve(&NrvPoihana::PoihanaNrvSwoon::sInstance);
536 }
537}
538
539void Poihana::exeSwoonLand() {
540 if (MR::isFirstStep(this)) {
541 MR::startBckNoInterpole(this, "SwoonLand");
542 MR::startSound(this, "SE_EV_POIHANA_SWOON", -1, -1);
543 }
544
545 if (MR::isBckStopped(this)) {
546 setNerve(&NrvPoihana::PoihanaNrvSwoon::sInstance);
547 }
548}
549
550void Poihana::exeSwoon() {
551 if (MR::isFirstStep(this)) {
552 MR::startBck(this, "Swoon", nullptr);
553 }
554
555 MR::startLevelSound(this, "SE_EM_LV_SWOON_S", -1, -1, -1);
556
557 if (MR::isStep(this, 110)) {
558 setNerve(&NrvPoihana::PoihanaNrvRecover::sInstance);
559 }
560}
561
562void Poihana::exeRecover() {
563 if (MR::isFirstStep(this)) {
564 MR::startBck(this, "Recover", nullptr);
565 MR::startSound(this, "SE_EM_POIHANA_RECOVER", -1, -1);
566 MR::startSound(this, "SE_EV_POIHANA_RECOVER", -1, -1);
567 mScale.setInline(1.0f);
568 }
569
570 if (MR::isBckStopped(this)) {
571 MR::setSensorOffset(this, "binder", sNormalBinderPos);
572 MR::setSensorRadius(this, "binder", 125.0f);
573 MR::validateHitSensor(this, "binder");
574 setNerve(&NrvPoihana::PoihanaNrvWait::sInstance);
575 }
576}
577
578// Needs to be reviewed
579void Poihana::exeShake() {
580 f32 _f31 = 0.2f - 0.01f * getNerveStep();
581 f32 scale = MR::sinDegree(getNerveStep() * 0.01745329251f) * _f31 + 36.0f;
582 mScale.setInline(scale);
583
584 if (MR::isStep(this, 20)) {
585 mScale.setInline(1.0f);
586 setNerve(&NrvPoihana::PoihanaNrvSearch::sInstance);
587 }
588}
589
590void Poihana::exeDrown() {
591 if (MR::isFirstStep(this)) {
592 MR::startBck(this, "Drown", nullptr);
593 MR::invalidateClipping(this);
594 MR::invalidateHitSensors(this);
595 MR::startSound(this, "SE_EM_FALL_INTO_WATER_S", -1, -1);
596
597 mWaterColumn->appear();
598 MR::tryStartAllAnim(mWaterColumn, "Splash");
599 }
600
601 if (MR::isBckStopped(this)) {
602 setNerve(&NrvPoihana::PoihanaNrvHide::sInstance);
603 }
604}
605
606void Poihana::exeHide() {
607 if (MR::isFirstStep(this)) {
608 MR::startSound(this, "SE_EM_EXPLODE_S_WATER", -1, -1);
609 MR::emitEffect(this, "DeathWater");
610 MR::hideModel(this);
611 }
612
613 if (MR::isStep(this, 150)) {
614 setNerve(&NrvPoihana::PoihanaNrvAppear::sInstance);
615 }
616}
617
618void Poihana::exeAppear() {
619 if (MR::isFirstStep(this)) {
620 MR::resetPosition(this, mRespawnPos);
621 MR::emitEffect(this, "Appear");
622 }
623
624 if (MR::isLessStep(this, 60)) {
625 MR::startLevelSound(this, "SE_EM_LV_POIHANA_REVIVE_EFFECT", -1, -1, -1);
626 }
627
628 if (MR::isStep(this, 60)) {
629 MR::showModel(this);
630 MR::startBck(this, "Appear", nullptr);
631 MR::startSound(this, "SE_EM_POIHANA_REVIVE_APPEAR", -1, -1);
632 }
633 else if (MR::isBckStopped(this) && MR::isGreaterStep(this, 60)) {
634 MR::validateClipping(this);
635 MR::validateHitSensors(this);
636 MR::setSensorOffset(this, "binder", sNormalBinderPos);
637 MR::setSensorRadius(this, "binder", 125.0f);
638 MR::validateHitSensor(this, "binder");
639 setNerve(&NrvPoihana::PoihanaNrvWait::sInstance);
640 }
641}
642
643void Poihana::exeDPDSwoon() {
644 if (MR::isFirstStep(this)) {
645 MR::invalidateHitSensor(this, "Binder");
646 }
647
648 MR::updateActorStateAndNextNerve(this, (ActorStateBaseInterface*)mBindStarPointer,
649 &NrvPoihana::PoihanaNrvWait::sInstance);
650}
651
652void Poihana::endDPDSwoon() {
653 mBindStarPointer->kill();
654
655 MR::setSensorOffset(this, "binder", sNormalBinderPos);
656 MR::setSensorRadius(this, "binder", 125.0f);
657 MR::validateHitSensor(this, "binder");
658}
659
660bool Poihana::tryToStartBind(HitSensor* pSender) {
661 if (mBindedActor != nullptr) {
662 return false;
663 }
664
665 LiveActor *bindedActor = pSender->mActor;
666 if (MR::isInWater(bindedActor, TVec3f(0.0f, 0.0f, 0.0f))) {
667 return false;
668 }
669
670 MR::tryRumblePadMiddle(this, 0);
671 mBindedActor = pSender->mActor;
672 MR::startBckPlayer("Rise", (const char *)nullptr);
673 MR::invalidateClipping(this);
674 return true;
675}
676
677void Poihana::updateBindActorMtx() {
678 TPos3f binderMtx;
679 MR::makeMtxTR(binderMtx.toMtxPtr(), mBindedActor);
680 MR::setBaseTRMtx(mBindedActor, binderMtx);
681}
682
683void Poihana::endBind() {
684 MR::validateClipping(this);
685
686 if (MR::isPlayerInRush()) {
687 TVec3f jumpVec;
688 jumpVec.scale(-mLaunchIntensity, mGravity);
689 MR::endBindAndPlayerJump(this, jumpVec, 0);
690 MR::startSound(this, "SE_PM_HELI_JUMP", -1, -1);
691 }
692
693 mBindedActor = nullptr;
694}
695
696void Poihana::startBound() {
697 mBoundTimer = 0;
698 mScale.setInline(1.0f);
699}
700
701/*
702* This function calculates Poihana's scale for 40 frames after being trampled. This is
703* used to simulate the "vibrating" visual effect. This is not 1:1 the same as in SMG1,
704* but it looks VERY similar and appears to be even more efficient compared to SMG1's
705* unusually complicated calculations.
706*/
707/*void Poihana::calcBound() {
708 if (mBoundTimer != -1) {
709 f32 scale = 1.0f;
710
711 if (mBoundTimer < 40) {
712 scale = 0.05f * sin(0.393f * mBoundTimer) + 1.0f;
713 mBoundTimer++;
714 }
715 else {
716 mBoundTimer = -1;
717 }
718
719 mScale.setAll(scale);
720 }
721}*/
722
723void Poihana::contactMario(HitSensor *pSender, HitSensor *pReceiver) {
724 bool isShooting;
725
726 if (!isNerveTypeWalkOrWait()) {
727 isShooting = false;
728 if (isNerve(&NrvPoihana::PoihanaNrvShootUpCharge::sInstance) ||
729 isNerve(&NrvPoihana::PoihanaNrvShootUp::sInstance)) {
730 isShooting = true;
731 }
732 } else {
733 goto doFlip;
734 }
735
736 if (isShooting) {
737doFlip:
738 if (!isBackAttack(pReceiver)) {
739 return;
740 }
741
742 if (MR::sendMsgEnemyAttackFlipWeak(pReceiver, pSender)) {
743 setNerve(&NrvPoihana::PoihanaNrvShake::sInstance);
744 }
745 } else if (isNerve(&NrvPoihana::PoihanaNrvSleep::sInstance)) {
746 setNerve(&NrvPoihana::PoihanaNrvGetUp::sInstance);
747 }
748}
749
750// Needs review
751/*void Poihana::controlVelocity() {
752 if (!mIsActive) {
753 return;
754 }
755
756 // Calculate front vector
757 TVec3f gravity;
758 if (MR::isBindedGround(this)) {
759 gravity.set(-*MR::getGroundNormal(this));
760 }
761 else {
762 gravity.set(mGravity);
763 }
764
765 TVec3f frontVec(mFrontVec);
766 MR::turnVecToPlane(&mFrontVec, frontVec, gravity);
767
768 // Calculate velocity
769 if (MR::isBindedGround(this)) {
770 f32 dot = mFrontVec.dot(mVelocity) * -1.0f;
771
772 TVec3f addVel;
773 JMAVECScaleAdd(mFrontVec.toCVec(), mVelocity.toCVec(), addVel.toVec(), dot);
774 addVel.scale(0.8f);
775
776 mVelocity.scale(mFrontVec.dot(mVelocity), mFrontVec);
777 mVelocity.add(addVel);
778
779 if (mVelocity.dot(gravity) > 0.0f) {
780 dot = gravity.dot(mVelocity) * -1.0f;
781 JMAVECScaleAdd(gravity.toCVec(), mVelocity.toCVec(), mVelocity.toVec(), dot);
782 }
783
784 mVelocity.scale(0.95f);
785 }
786
787 JMAVECScaleAdd(gravity.toCVec(), mVelocity.toCVec(), mVelocity.toVec(), 2.0f);
788
789 if (!isNerve(&NrvPoihana::PoihanaNrvShock::sInstance)) {
790 f32 magVel = isNerve(&NrvPoihana::PoihanaNrvChasePlayer::sInstance) ? 10.0f : 5.0f;
791
792 if (PSVECMag((Vec *)&mVelocity) > magVel) {
793 f32 squared = mVelocity.squared();
794
795 if (squared > 0.0000038146973f) {
796 mVelocity.scale(JGeometry::TUtil<f32>::inv_sqrt(squared));
797 }
798 }
799
800 if (MR::isNearZero(mVelocity, 0.001f)) {
801 mVelocity.zero();
802 }
803 }
804}*/
805
806void Poihana::calcMyGravity() {
807 if (!mIsActive) {
808 return;
809 }
810
811 TVec3f upVec, gravityPos;
812 MR::calcUpVec(&upVec, this);
813 JMAVECScaleAdd(upVec.toCVec(), mPosition.toCVec(), gravityPos.toVec(), 20.0f);
814 MR::calcGravity(this, gravityPos);
815}
816
817bool Poihana::tryNonActive() {
818 if (!MR::isStageStateScenarioOpeningCamera()) {
819 bool notNear = !MR::isNearPlayerAnyTime(this, 3500.0f);
820 if (notNear && MR::isBindedGround(this)) {
821 setNerve(&NrvPoihana::PoihanaNrvNonActive::sInstance);
822 return true;
823 }
824 }
825
826 return false;
827}
828
829bool Poihana::tryDrown() {
830 if (!mCanDrown) {
831 return false;
832 }
833
834 if (isNerve(&NrvPoihana::PoihanaNrvAppear::sInstance)) {
835 return false;
836 }
837
838 if (isNerve(&NrvPoihana::PoihanaNrvDrown::sInstance)) {
839 return false;
840 }
841
842 if (!MR::isInWater(this, TVec3f(0.0f, 0.0f, 0.0f))) {
843 return false;
844 }
845
846 setNerve(&NrvPoihana::PoihanaNrvDrown::sInstance);
847 return true;
848}
849
850bool Poihana::tryDPDSwoon() {
851 if (!isNerveTypeWalkOrWait()) {
852 return false;
853 }
854
855 if (!mBindStarPointer->tryStartPointBind()) {
856 return false;
857 }
858
859 setNerve(&NrvPoihana::PoihanaNrvDPDSwoon::sInstance);
860 return true;
861}
862
863bool Poihana::tryShock() {
864 bool ret = false;
865
866 if (isNerve(&NrvPoihana::PoihanaNrvDrown::sInstance) ||
867 isNerve(&NrvPoihana::PoihanaNrvHide::sInstance) ||
868 isNerve(&NrvPoihana::PoihanaNrvAppear::sInstance)) {
869 ret = true;
870 }
871
872 if (ret) {
873 return false;
874 }
875
876 if (isNerve(&NrvPoihana::PoihanaNrvShock::sInstance)) {
877 return false;
878 }
879
880 if (isNerve(&NrvPoihana::PoihanaNrvSwoonLand::sInstance)) {
881 return false;
882 }
883
884 mVelocity.scale(-30.0f, mGravity);
885 setNerve(&NrvPoihana::PoihanaNrvShock::sInstance);
886 return true;
887}
888
889bool Poihana::tryHipDropShock() {
890 bool isNotNear = !MR::isNearPlayerAnyTime(this, 500.0f);
891
892 if (isNotNear) {
893 return false;
894 }
895
896 if (MR::isPlayerHipDropLand()) {
897 return tryShock();
898 }
899
900 return false;
901}
902
903bool Poihana::isNerveTypeWalkOrWait() const {
904 return (isNerve(&NrvPoihana::PoihanaNrvWait::sInstance) ||
905 isNerve(&NrvPoihana::PoihanaNrvSearch::sInstance) ||
906 isNerve(&NrvPoihana::PoihanaNrvWalkAround::sInstance) ||
907 isNerve(&NrvPoihana::PoihanaNrvChasePlayer::sInstance) ||
908 isNerve(&NrvPoihana::PoihanaNrvGoBack::sInstance));
909}
910
911bool Poihana::isNeedForBackHome() const {
912 if (isNerve(&NrvPoihana::PoihanaNrvWalkAround::sInstance)) {
913 return !MR::isNear(this, mHomePos, 350.0f);
914 }
915
916 if (!isNerve(&NrvPoihana::PoihanaNrvChasePlayer::sInstance)) {
917 bool ret;
918 if (mBehavior == POIHANA_BEHAVIOR_NEW_HOME) {
919 ret = !MR::isNearPlayer(this, 1100.0f);
920 } else {
921 ret = false;
922 if (!MR::isNear(this, mHomePos, 2000.0f) || !MR::isNearPlayer(this, 1110.0f)) {
923 ret = true;
924 }
925 }
926
927 return ret;
928 }
929
930 return false;
931}
932
933bool Poihana::isNeedForGetUp() const {
934 bool ret = false;
935
936 if (MR::isNearPlayer(this, 500.0f)) {
937 bool flag = true;
938
939 f32 mag = PSVECMag((Vec *)MR::getPlayerVelocity());
940
941 if (!(mag >= 10.0f) && !MR::isPlayerSwingAction()) {
942 flag = false;
943 }
944
945 if (flag) {
946 ret = true;
947 }
948 }
949
950 return ret;
951}
952
953bool Poihana::isBackAttack(HitSensor *pMySensor) const {
954 TVec3f frontVec;
955 MR::calcFrontVec(&frontVec, this);
956 JGeometry::negateInternal((f32 *)&frontVec, (f32 *)&frontVec);
957
958 TVec3f sensorRelative(pMySensor->mPosition - mPosition);
959 return sensorRelative.dot(frontVec) > 0.0f;
960}
961
962namespace NrvPoihana {
963 INIT_NERVE(PoihanaNrvNonActive);
964 INIT_NERVE(PoihanaNrvWait);
965 INIT_NERVE(PoihanaNrvWalkAround);
966 INIT_NERVE(PoihanaNrvSleepStart);
967 INIT_NERVE(PoihanaNrvSleep);
968 INIT_NERVE(PoihanaNrvGetUp);
969 INIT_NERVE(PoihanaNrvSearch);
970 INIT_NERVE(PoihanaNrvChasePlayer);
971 INIT_NERVE(PoihanaNrvShootUpCharge);
972 INIT_NERVE(PoihanaNrvShootUp);
973 INIT_NERVE(PoihanaNrvGoBack);
974 INIT_NERVE(PoihanaNrvShock);
975 INIT_NERVE(PoihanaNrvSwoon);
976 INIT_NERVE(PoihanaNrvSwoonLand);
977 INIT_NERVE(PoihanaNrvRecover);
978 INIT_NERVE(PoihanaNrvShake);
979 INIT_NERVE(PoihanaNrvDrown);
980 INIT_NERVE(PoihanaNrvHide);
981 INIT_NERVE(PoihanaNrvAppear);
982 INIT_NERVE(PoihanaNrvDPDSwoon);
983
984 void PoihanaNrvNonActive::execute(Spine *pSpine) const {
985 Poihana *pActor = (Poihana*)pSpine->mExecutor;
986 pActor->exeNonActive();
987 }
988
989 void PoihanaNrvNonActive::executeOnEnd(Spine *pSpine) const {
990 Poihana *pActor = (Poihana*)pSpine->mExecutor;
991 pActor->endNonActive();
992 }
993
994 void PoihanaNrvWait::execute(Spine *pSpine) const {
995 Poihana *pActor = (Poihana*)pSpine->mExecutor;
996 pActor->exeWait();
997 }
998
999 void PoihanaNrvWalkAround::execute(Spine *pSpine) const {
1000 Poihana *pActor = (Poihana*)pSpine->mExecutor;
1001 pActor->exeWalkAround();
1002 }
1003
1004 void PoihanaNrvSleepStart::execute(Spine *pSpine) const {
1005 Poihana *pActor = (Poihana*)pSpine->mExecutor;
1006 pActor->exeSleepStart();
1007 }
1008
1009 void PoihanaNrvSleep::execute(Spine *pSpine) const {
1010 Poihana *pActor = (Poihana*)pSpine->mExecutor;
1011 pActor->exeSleep();
1012 }
1013
1014 void PoihanaNrvGetUp::execute(Spine *pSpine) const {
1015 Poihana *pActor = (Poihana*)pSpine->mExecutor;
1016 pActor->exeGetUp();
1017 }
1018
1019 void PoihanaNrvSearch::execute(Spine *pSpine) const {
1020 Poihana *pActor = (Poihana*)pSpine->mExecutor;
1021 pActor->exeSearch();
1022 }
1023
1024 void PoihanaNrvChasePlayer::execute(Spine *pSpine) const {
1025 Poihana *pActor = (Poihana*)pSpine->mExecutor;
1026 pActor->exeChasePlayer();
1027 }
1028
1029 void PoihanaNrvShootUpCharge::execute(Spine *pSpine) const {
1030 Poihana *pActor = (Poihana*)pSpine->mExecutor;
1031 pActor->exeShootUpCharge();
1032 }
1033
1034 void PoihanaNrvShootUp::execute(Spine *pSpine) const {
1035 Poihana *pActor = (Poihana*)pSpine->mExecutor;
1036 pActor->exeShootUp();
1037 }
1038
1039 void PoihanaNrvShootUp::executeOnEnd(Spine *pSpine) const {
1040 Poihana *pActor = (Poihana*)pSpine->mExecutor;
1041 pActor->endShootUp();
1042 }
1043
1044 void PoihanaNrvGoBack::execute(Spine *pSpine) const {
1045 Poihana *pActor = (Poihana*)pSpine->mExecutor;
1046 pActor->exeGoBack();
1047 }
1048
1049 void PoihanaNrvShock::execute(Spine *pSpine) const {
1050 Poihana *pActor = (Poihana*)pSpine->mExecutor;
1051 pActor->exeShock();
1052 }
1053
1054 void PoihanaNrvSwoon::execute(Spine *pSpine) const {
1055 Poihana *pActor = (Poihana*)pSpine->mExecutor;
1056 pActor->exeSwoon();
1057 }
1058
1059 void PoihanaNrvSwoonLand::execute(Spine *pSpine) const {
1060 Poihana *pActor = (Poihana*)pSpine->mExecutor;
1061 pActor->exeSwoonLand();
1062 }
1063
1064 void PoihanaNrvRecover::execute(Spine *pSpine) const {
1065 Poihana *pActor = (Poihana*)pSpine->mExecutor;
1066 pActor->exeRecover();
1067 }
1068
1069 void PoihanaNrvShake::execute(Spine *pSpine) const {
1070 Poihana *pActor = (Poihana*)pSpine->mExecutor;
1071 pActor->exeShake();
1072 }
1073
1074 void PoihanaNrvDrown::execute(Spine *pSpine) const {
1075 Poihana *pActor = (Poihana*)pSpine->mExecutor;
1076 pActor->exeDrown();
1077 }
1078
1079 void PoihanaNrvHide::execute(Spine *pSpine) const {
1080 Poihana *pActor = (Poihana*)pSpine->mExecutor;
1081 pActor->exeHide();
1082 }
1083
1084 void PoihanaNrvAppear::execute(Spine *pSpine) const {
1085 Poihana *pActor = (Poihana*)pSpine->mExecutor;
1086 pActor->exeAppear();
1087 }
1088
1089 void PoihanaNrvDPDSwoon::execute(Spine *pSpine) const {
1090 Poihana *pActor = (Poihana*)pSpine->mExecutor;
1091 pActor->exeDPDSwoon();
1092 }
1093
1094 void PoihanaNrvDPDSwoon::executeOnEnd(Spine *pSpine) const {
1095 Poihana *pActor = (Poihana*)pSpine->mExecutor;
1096 pActor->endDPDSwoon();
1097 }
1098}
The basis of a drawable actor that can contain states (see: Nerve)
Definition LiveActor.hpp:24
TVec3f mPosition
3D vector of the actor's position.
Definition LiveActor.hpp:95
TVec3f mScale
3D vector of the actor's scale.
Definition LiveActor.hpp:97
TVec3f mVelocity
3D vector of the actor's velocity.
Definition LiveActor.hpp:98
TVec3f mGravity
3D vector of the actor's gravity.
Definition LiveActor.hpp:99
virtual MtxPtr getBaseMtx() const
Gets the base matrix of the model used for the actor.
virtual void calcAndSetBaseMtx()
Calculates and sets the base matrix of the actor.
Definition Poihana.cpp:133
Definition Spine.hpp:9