1#include "Game/MapObj/CocoNut.hpp"
2#include "Game/LiveActor/Spine.hpp"
3#include "Game/NameObj/NameObjArchiveListCollector.hpp"
4#include "Game/Util.hpp"
5#include "JSystem/JMath.hpp"
7inline void negateInternalInline(
const TVec3f &src, TVec3f *dst) {
8 JGeometry::negateInternal((f32 *)&src, (f32 *)dst);
11CocoNut::CocoNut(
const char *pName) :
LiveActor(pName),
19 mSpawnPosition(gZeroVec),
22 mSphericalShadow(false),
23 mRespawnWhenOutOfView(false),
25 mContinueRolling(false)
36 initMapToolInfo(rIter);
38 MR::connectToSceneNoSilhouettedMapObjStrongLight(
this);
39 MR::initLightCtrl(
this);
41 initBinder(_D0, 0.0f, 0);
42 MR::onCalcGravity(
this);
46 if (!mSphericalShadow) {
47 MR::initShadowVolumeCylinder(
this, _D0);
50 MR::initShadowVolumeSphere(
this, _D0);
53 MR::setShadowDropLength(
this,
nullptr, 1500.0f);
56 if (MR::getJMapInfoClippingGroupID(rIter, &stack_8)) {
57 MR::setGroupClipping(
this, rIter, 32);
61 MR::setClippingFar200m(
this);
64 MR::tryRegisterDemoCast(
this, rIter);
66 if (!mSphericalShadow) {
67 initNerve(&NrvCocoNut::CocoNutNrvWaitOnBind::sInstance);
70 initNerve(&NrvCocoNut::CocoNutNrvWait::sInstance);
76void CocoNut::initAfterPlacement() {
80 MR::makeMtxTR(&stack_50.mMtx[0],
this);
82 _94.set(stack_50.mMtx[0][2], stack_50.mMtx[1][2], stack_50.mMtx[2][2]);
84 if (MR::isSameDirection(_94, gravity, 0.01f)) {
85 TVec3f gravityNegated;
86 negateInternalInline(gravity, &gravityNegated);
89 MR::makeMtxUpNoSupport(&stack_20, gravityNegated);
90 _94.set(stack_20.mMtx[0][2], stack_20.mMtx[1][2], stack_20.mMtx[2][2]);
94void CocoNut::startClipped() {
95 if (isNerve(&NrvCocoNut::CocoNutNrvReplaceReady::sInstance)) {
96 if (!MR::isDemoActive()) {
102 MR::onCalcGravity(
this);
104 MR::validateHitSensors(
this);
105 if (!mSphericalShadow) {
107 setNerve(&NrvCocoNut::CocoNutNrvWait::sInstance);
110 setNerve(&NrvCocoNut::CocoNutNrvWaitOnBind::sInstance);
114 else if (mRespawnWhenOutOfView) {
117 setNerve(&NrvCocoNut::CocoNutNrvReplaceReady::sInstance);
119 LiveActor::startClipped();
122void CocoNut::hit(
const TVec3f &a1, f32 a2) {
129 else if (a2 > 35.0f) {
137 if (!isNerve(&NrvCocoNut::CocoNutNrvMove::sInstance)) {
138 setNerve(&NrvCocoNut::CocoNutNrvMove::sInstance);
142bool CocoNut::isPossibleToHit(
const TVec3f &a1,
const TVec3f &a2,
const TVec3f &a3)
const {
148 stack_2C.sub(a2, a1);
149 if (MR::normalizeOrZero(&stack_2C)) {
152 if (MR::normalizeOrZero(a3, &stack_14)) {
155 if (isNerve(&NrvCocoNut::CocoNutNrvMove::sInstance)) {
156 if (MR::normalizeOrZero(
mVelocity, &stack_8)) {
159 stack_20.sub(stack_14, stack_8);
160 if (MR::normalizeOrZero(&stack_20)) {
165 stack_20.set(stack_14);
167 return stack_2C.dot(stack_20) < 0.0f;
170f32 CocoNut::calcMoveSpeed()
const {
171 return !isNerve(&NrvCocoNut::CocoNutNrvMove::sInstance) ? 0.0f : MR::max(_8C, PSVECMag(_150.toCVec()));
174void CocoNut::initSensor() {
176 MR::addHitSensor(
this,
"body", 0x17, 0x10, 65.0f *
mScale.x, TVec3f(0.0f, 0.0f, 0.0f));
177 MR::addHitSensor(
this,
"eye", 0x7f, 0x10, 1.1f *
mScale.x, TVec3f(0.0f, 0.0f, 0.0f));
180void CocoNut::initModel() {
181 initModelManagerWithAnm(getModelName(),
nullptr,
false);
184void CocoNut::initEffect() {
185 initEffectKeeper(0,
"CocoNut",
false);
186 MR::setEffectHostMtx(
this,
"RollingSmoke", _D8.toMtxPtr());
187 MR::setEffectHostMtx(
this,
"RollingSmokeAttrWater", _D8.toMtxPtr());
188 MR::setEffectHostMtx(
this,
"RollingSmokeAttrSand", _D8.toMtxPtr());
189 MR::setEffectHostMtx(
this,
"Land", _D8.toMtxPtr());
190 MR::setEffectHostMtx(
this,
"LandAttrWater", _D8.toMtxPtr());
191 MR::setEffectHostMtx(
this,
"WaterColumn", _D8.toMtxPtr());
192 MR::setEffectHostMtx(
this, getBreakEffectName(), _D8.toMtxPtr());
193 MR::setEffectHostMtx(
this,
"SpinHitMark", _108.toMtxPtr());
198void CocoNut::updateRotate(
float a1) {
205 negateInternalInline(
mGravity, &stack_20);
206 if (!MR::normalizeOrZero(
mVelocity, &stack_2C) && !MR::isSameDirection(stack_2C, stack_20, 0.01f)) {
208 PSVECCrossProduct(stack_2C.toCVec(), stack_20.toCVec(), stack_14.toVec());
210 f32 temp1 = PSVECMag(
mVelocity.toCVec()) * -180.0f;
211 f32 temp2 = a1 * temp1;
212 f32 f = PI_180 * (temp2 / (PI * getSize()));
214 stack_38.mMtx[0][3] = 0.0f;
215 stack_38.mMtx[1][3] = 0.0f;
216 stack_38.mMtx[2][3] = 0.0f;
218 stack_8.set(stack_14);
219 PSVECMag(stack_8.toCVec());
220 PSVECNormalize(stack_8.toCVec(), stack_8.toVec());
227 f32 fcos1 = 1.0f - fcos;
229 stack_38.mMtx[0][0] = (rx * rx * fcos1) + fcos;
230 stack_38.mMtx[0][1] = fcos1 * rx * ry - (fsin * rz);
231 stack_38.mMtx[0][2] = fcos1 * rx * rz + (fsin * ry);
232 stack_38.mMtx[1][0] = fcos1 * rx * ry + (fsin * rz);
233 stack_38.mMtx[1][1] = (ry * ry * fcos1) + fcos;
234 stack_38.mMtx[1][2] = fcos1 * ry * rz - (fsin * rx);
235 stack_38.mMtx[2][0] = fcos1 * rx * rz - (fsin * ry);
236 stack_38.mMtx[2][1] = fcos1 * ry * rz + (fsin * rx);
237 stack_38.mMtx[2][2] = (rz * rz * fcos1) + fcos;
239 _A0.concat(stack_38, _A0);
244void CocoNut::updateGravity() {
247 f32 f31 = _13C ? 0.4f : 1.0f;
251 f32 f2 = f0 >= 25.0f ? 25.0f : f0;
253 stack_8.scale((f32)(f64)f2);
259void CocoNut::processMove() {
266 f32 temp_f31 = calcMoveSpeed();
267 bool temp_r31 = MR::isBindedGroundWater(
this);
268 TVec3f *temp_r3_1 = MR::getGroundNormal(
this);
270 if (
mGravity.dot(*temp_r3_1) < 0.0f) {
272 s32 var_r5 = 100.0f * (temp_f31 / 35.0f);
278 MR::startSound(
this,
"SE_OJ_COCONUT_BOUND_WATER", var_r5, -1);
281 MR::startSound(
this,
"SE_OJ_COCONUT_BOUND", var_r5, -1);
285 if (_138 >= 10 && 3.0f < _90) {
286 MR::emitEffect(
this,
"Land");
292 MR::emitEffect(
this,
"RollingSmoke");
293 s32 var_r5_2 = 100.0f * (temp_f31 / 35.0f);
294 if (var_r5_2 > 100) {
297 if (var_r5_2 >= 10) {
299 MR::startLevelSound(
this,
"SE_OJ_LV_COCONUT_ROLL_WATER", var_r5_2, -1, -1);
302 MR::startLevelSound(
this,
"SE_OJ_LV_COCONUT_ROLL", var_r5_2, -1, -1);
306 _14C = MR::calcVelocityAreaMoveOnGround(&stack_2C,
this);
309 _150.scaleInline(0.75f);
321 MR::deleteEffect(
this,
"RollingSmoke");
326 if (getWallNormal(&stack_20) && _94.dot(stack_20) < 0.0f) {
328 PSVECMag(stack_14.toCVec());
329 PSVECNormalize(stack_14.toCVec(), stack_14.toVec());
331 stack_8.set(stack_20);
332 PSVECMag(stack_8.toCVec());
333 PSVECNormalize(stack_8.toCVec(), stack_8.toVec());
335 f32 ok2 = -2.0f * stack_14.dot(stack_8);
336 JMAVECScaleAdd(stack_8.toCVec(), _94.toCVec(), _94.toVec(), ok2);
338 PSVECMag(_94.toCVec());
339 PSVECNormalize(_94.toCVec(), _94.toVec());
344 MR::startSound(
this,
"SE_OJ_COCONUT_BOUND", 100.0f * (calcMoveSpeed() / 35.0f), -1);
350 bool ok = _14C && _138 < 10;
352 _150.scaleInline(0.925f);
359void CocoNut::setFrontVec(
const TVec3f &a1) {
362 if (!MR::normalizeOrZero(a1, &stack_14)) {
363 if (MR::isSameDirection(a1, stack_8, 0.01f)) {
367 MR::vecKillElement(stack_14, stack_8, &_94);
375 if (!isNerve(&NrvCocoNut::CocoNutNrvMove::sInstance)) {
378 f32 moveSpeed = nut->calcMoveSpeed();
379 if (calcMoveSpeed() < moveSpeed) {
382 TVec3f *otherSensorPos = &pOtherSensor->mPosition;
383 TVec3f *mySensorPos = &pMySensor->mPosition;
384 if (!nut->isPossibleToHit(*mySensorPos, *otherSensorPos,
mVelocity)) {
392 calcHitSpeedAndFrontVec(&stack_C, &stack_8, &stack_1C, &stack_10, *otherSensorPos, *mySensorPos);
393 hit(stack_1C, stack_C);
394 nut->hit(stack_10, stack_8);
406 TVec3f *otherSensorPos = &pOtherSensor->mPosition;
407 TVec3f *mySensorPos = &pMySensor->mPosition;
411 if (isNerve(&NrvCocoNut::CocoNutNrvMove::sInstance)) {
412 stack_34.sub(*otherSensorPos, *mySensorPos);
413 MR::normalize(&stack_34);
414 if (0.0f < stack_34.dot(_94)) {
417 calcHitSpeedAndFrontVec(&stack_C, &stack_8, &stack_28, &stack_1C, *otherSensorPos, *mySensorPos);
418 hit(stack_28, stack_C);
421 f32 mySensorRadius = pMySensor->mRadius;
422 f32 otherSensorRadius = pOtherSensor->mRadius;
423 if (((otherSensorRadius + mySensorRadius) - PSVECDistance(otherSensorPos->toCVec(), mySensorPos->toVec())) < 0.0f) {
426 stack_10.sub(*otherSensorPos, *mySensorPos);
427 if (MR::normalizeOrZero(&stack_10)) {
435void CocoNut::reviseFrontVec() {
441 for (
int i = 0; i < eye->mSensorCount; i++) {
442 sensor = eye->mSensors[i];
443 if ((sensor->isType(0x26) || sensor->isType(0x56)) && !MR::isDead(sensor->mActor)) {
444 found_actor = sensor->mActor;
448 if (found_actor ==
nullptr) {
457 stack_14.sub(found_actor->
mPosition, this->mPosition);
458 if (!MR::isSameDirection(stack_14, stack_20, 0.01f)) {
459 MR::vecKillElement(stack_14, stack_20, &stack_8);
460 MR::normalize(&stack_8);
461 f32 temp_f31 = stack_8.dot(_94);
462 if (MR::cosDegree(15.0f) < temp_f31) {
463 JMAVECLerp(_94.toCVec(), stack_8.toCVec(), _94.toVec(), 0.8f);
468void CocoNut::statusToWait() {
473 MR::validateClipping(
this);
474 if (!mSphericalShadow && !MR::isBindedGroundIce(
this)) {
477 MR::offCalcGravity(
this);
478 if (!isNerve(&NrvCocoNut::CocoNutNrvWait::sInstance)) {
479 setNerve(&NrvCocoNut::CocoNutNrvWait::sInstance);
483 setNerve(&NrvCocoNut::CocoNutNrvWaitOnBind::sInstance);
487void CocoNut::tryMoveEnd() {
489 bool var_r3 = _14C && _138 < 10;
490 if (!var_r3 && calcMoveSpeed() < 1.5f && (!mContinueRolling || !isContactWithOtherCocoNut())) {
495 if (sendMsgToBindedSensor()) {
496 setNerve(&NrvCocoNut::CocoNutNrvBreak::sInstance);
499 if (!tryDisappear()) {
500 _8C = MR::max(_8C, 1.5f);
504bool CocoNut::tryDisappear() {
507 if (MR::isInWater(
this, stack_14)) {
508 setNerve(&NrvCocoNut::CocoNutNrvInWater::sInstance);
511 if (MR::isInDeath(
this, TVec3f(0.0f, 0.0f, 0.0f))) {
512 setNerve(&NrvCocoNut::CocoNutNrvBreak::sInstance);
518bool CocoNut::isValidPushedFromPlayer(
const HitSensor *arg0,
const HitSensor *arg1)
const {
522 if (isNerve(&NrvCocoNut::CocoNutNrvMove::sInstance) && MR::isLessStep(
this, 15)) {
525 TVec3f *playerVelocity = MR::getPlayerVelocity();
526 f32 nutVelocitySquared =
mVelocity.squared();
527 if (playerVelocity->squared() < nutVelocitySquared) {
531 stack_14.sub(arg0->mPosition, arg1->mPosition);
532 if (MR::normalizeOrZero(&stack_14)) {
536 if (MR::normalizeOrZero(*playerVelocity, &stack_8)) {
539 if (stack_14.dot(stack_8) < MR::cosDegree(45.0f)) {
548void CocoNut::calcHitSpeedAndFrontVec(f32 *arg0, f32 *arg1, TVec3f *arg2, TVec3f *arg3,
const TVec3f &arg4,
const TVec3f &arg5)
const {
552 arg3->sub(arg5, arg4);
555 PSVECCrossProduct(arg3->toCVec(), stack_14.toCVec(), arg2->toVec());
557 if (MR::normalizeOrZero(
mVelocity, &stack_8)) {
560 f32 var_f30 = stack_8.dot(*arg2);
561 if (var_f30 < 0.0f) {
562 negateInternalInline(stack_14, &stack_14);
563 PSVECCrossProduct(arg3->toCVec(), stack_14.toCVec(), arg2->toVec());
565 var_f30 = stack_8.dot(*arg2);
568 f32 temp_f2 = 1.0f - (var_f30 * var_f30);
571 if (temp_f2 > 0.0f) {
572 f32 temp_f31 = __frsqrte(temp_f2);
573 f32 temp_f3 = temp_f31 * temp_f2;
574 var_f31 = -((temp_f3 * temp_f31) - 3.0f) * temp_f3 * 0.5f;
579 f32 temp_f1_2 = calcMoveSpeed();
580 *arg1 = temp_f1_2 * var_f31;
581 *arg0 = temp_f1_2 * var_f30;
585bool CocoNut::isOnGround()
const {
586 if (0.0f < _90 && MR::isOnGround(
this)) {
587 TVec3f *groundNormal = MR::getGroundNormal(
this);
588 if (groundNormal->dot(
mGravity) < MR::cosDegree(120.0f)) {
595bool CocoNut::getWallNormal(TVec3f *arg0)
const {
596 if (MR::isBindedWall(
this)) {
597 arg0->set(*MR::getWallNormal(
this));
600 if (0.0f < _90 && (MR::isOnGround(
this)) && !isOnGround()) {
601 arg0->set(*MR::getGroundNormal(
this));
607bool CocoNut::sendMsgToBindedSensor() {
608 if (MR::isBindedGround(
this)) {
609 return sendMsgEnemyAttackToBindedSensor(MR::getGroundSensor(
this));
611 if (MR::isBindedWall(
this)) {
612 return sendMsgEnemyAttackToBindedSensor(MR::getWallSensor(
this));
614 if (MR::isBindedRoof(
this)) {
615 return sendMsgEnemyAttackToBindedSensor(MR::getRoofSensor(
this));
620bool CocoNut::sendMsgEnemyAttackToBindedSensor(
HitSensor *arg0) {
622 return MR::sendMsgEnemyAttack(arg0,
getSensor(
"body"));
627bool CocoNut::isValidReceiveMsg(
const HitSensor *a1)
const {
629 isNerve(&NrvCocoNut::CocoNutNrvWait::sInstance) ||
630 isNerve(&NrvCocoNut::CocoNutNrvWaitOnBind::sInstance) ||
631 isNerve(&NrvCocoNut::CocoNutNrvMove::sInstance)
635const char *CocoNut::getModelName() {
636 bool watermelonMode = MR::isStarPieceCounterStop();
637 return watermelonMode ?
"Watermelon" :
"CocoNut";
640const char *CocoNut::getBreakEffectName() {
641 bool watermelonMode = MR::isStarPieceCounterStop();
642 return watermelonMode ?
"BreakWatermelon" :
"CocoNutBreak";
646 pArchiveList->addArchive(getModelName());
654 MR::setBaseTRMtx(
this, _A0);
656 if (isNerve(&NrvCocoNut::CocoNutNrvMove::sInstance) && MR::isOnGround(
this)) {
657 TVec3f *groundNormal = MR::getGroundNormal(
this);
660 TVec3f stack_8(*groundNormal);
661 stack_8.scale(temp_f31);
666 if (MR::isSameDirection(*groundNormal, _94, 0.01f)) {
667 MR::makeMtxUpNoSupportPos(&_D8, *groundNormal, stack_14);
670 MR::makeMtxUpFrontPos(&_D8, *groundNormal, _94, stack_14);
674 _D8.mMtx[0][0] *= temp_f9;
675 _D8.mMtx[0][1] *= temp_f9;
676 _D8.mMtx[0][2] *= temp_f9;
677 _D8.mMtx[1][0] *= temp_f9;
678 _D8.mMtx[1][1] *= temp_f9;
679 _D8.mMtx[1][2] *= temp_f9;
680 _D8.mMtx[2][0] *= temp_f9;
681 _D8.mMtx[2][1] *= temp_f9;
682 _D8.mMtx[2][2] *= temp_f9;
687 if (isValidReceiveMsg(arg0)) {
688 if (MR::isSensorPlayer(arg1) && !isValidPushedFromPlayer(arg0, arg1)) {
689 if (!MR::isPlayerHipDropFalling()) {
690 MR::sendMsgPush(arg1, arg0);
693 else if (arg1->isType(0x17)) {
694 if (MR::sendMsgPush(arg1, arg0)) {
695 MR::startSound(
this,
"SE_OJ_COCONUT_HIT", -1, -1);
699 if (_13C && isNerve(&NrvCocoNut::CocoNutNrvMove::sInstance) && MR::sendMsgToEnemyAttackBlow(arg1, arg0)) {
700 MR::startSound(
this,
"SE_OJ_COCONUT_HIT", -1, -1);
701 setNerve(&NrvCocoNut::CocoNutNrvBreak::sInstance);
704 MR::sendMsgPush(arg1, arg0);
711 if (!isValidReceiveMsg(pOtherSensor)) {
714 if (pMySensor->isType(0x17)) {
715 return tryHit(pOtherSensor, pMySensor);
717 return tryPushedFromActor(pOtherSensor, pMySensor);
720bool CocoNut::receiveMsgPlayerAttack(u32 a1,
HitSensor *pOtherSensor,
HitSensor *pMySensor) {
721 if (!isValidReceiveMsg(pMySensor)) {
724 if (!MR::isMsgPlayerHitAll(a1) && !MR::isMsgPlayerTrample(a1) && !MR::isMsgPlayerHipDrop(a1) && !MR::isMsgStarPieceReflect(a1)) {
729 if (MR::isMsgPlayerSpinAttack(a1)) {
732 MR::startSound(
this,
"SE_PM_SPIN_HIT", -1, -1);
733 MR::startSound(
this,
"SE_OJ_COCONUT_LAUNCH", -1, -1);
734 emitEffectSpinHit(pOtherSensor, pMySensor);
737 else if (MR::isMsgPlayerHipDrop(a1) || MR::isMsgInvincibleAttack(a1)) {
740 MR::startSound(
this,
"SE_OJ_COCONUT_FLIP_M", -1, -1);
741 if (MR::isMsgPlayerHipDrop(a1)) {
742 MR::sendMsgAwayJump(pOtherSensor, pMySensor);
748 MR::startSound(
this,
"SE_OJ_COCONUT_FLIP_S", -1, -1);
755 stack_2C.sub(pMySensor->mPosition, pOtherSensor->mPosition);
756 if (MR::isMsgStarPieceReflect(a1) && !MR::normalizeOrZero(stack_2C, &stack_20) && !MR::normalizeOrZero(pOtherSensor->mActor->
mVelocity, &stack_14)) {
757 if (stack_20.dot(stack_14) < MR::cosDegree(60.0f)) {
758 TVec3f stack_8(stack_14);
759 stack_8.scale(65.0f);
760 stack_2C.add(stack_8);
763 setFrontVec(stack_2C);
764 if (MR::isMsgPlayerSpinAttack(a1)) {
767 setNerve(&NrvCocoNut::CocoNutNrvMove::sInstance);
771bool CocoNut::receiveOtherMsg(u32 arg0,
HitSensor *pOtherSensor,
HitSensor *pMySensor) {
776 if (!isValidReceiveMsg(pMySensor)) {
779 if (MR::isMsgPlayerKick(arg0)) {
780 if (isValidPushedFromPlayer(pMySensor, pOtherSensor)) {
781 TVec3f *playerVelocity = MR::getPlayerVelocity();
782 setFrontVec(*playerVelocity);
783 temp_f1 = _94.dot(*playerVelocity);
785 temp_f0 = 1.1f * temp_f1;
787 _8C = MR::max(var_f2, temp_f0);
788 _90 = -(0.7f * temp_f1);
789 MR::startSound(
this,
"SE_OJ_COCONUT_FLIP_S", -1, -1);
790 setNerve(&NrvCocoNut::CocoNutNrvMove::sInstance);
795 if (MR::isMsgHitmarkEmit(arg0)) {
802void CocoNut::initMapToolInfo(
const JMapInfoIter &rIter) {
803 MR::initDefaultPos(
this, rIter);
804 MR::getJMapInfoArg0NoInit(rIter, &mSphericalShadow);
805 MR::getJMapInfoArg1NoInit(rIter, &mRespawnWhenOutOfView);
806 MR::getJMapInfoArg2NoInit(rIter, &mContinueRolling);
811void CocoNut::statusToHide() {
814 MR::offCalcGravity(
this);
816 MR::invalidateHitSensors(
this);
817 MR::clearHitSensors(
this);
818 MR::deleteEffectAll(
this);
821void CocoNut::emitEffectSpinHit(
const HitSensor *pOtherSensor,
const HitSensor *pMySensor) {
823 JMAVECLerp(pOtherSensor->mPosition.toCVec(), pMySensor->mPosition.toCVec(), point.toVec(), 0.7f);
824 _108.mMtx[0][0] = 1.0f;
825 _108.mMtx[1][0] = 0.0f;
826 _108.mMtx[2][0] = 0.0f;
827 _108.mMtx[0][1] = 0.0f;
828 _108.mMtx[1][1] = 1.0f;
829 _108.mMtx[2][1] = 0.0f;
830 _108.mMtx[0][2] = 0.0f;
831 _108.mMtx[1][3] = 0.0f;
832 _108.mMtx[2][3] = 1.0f;
833 _108.mMtx[0][3] = point.x;
834 _108.mMtx[1][3] = point.y;
835 _108.mMtx[2][3] = point.z;
836 MR::emitEffect(
this,
"SpinHitMark");
839bool CocoNut::isContactWithOtherCocoNut()
const {
841 for (
int i = 0; i < body->mSensorCount; i++) {
843 if (body->mSensors[i]->isType(0x17)) {
850void CocoNut::exeWait() {
851 if (MR::isFirstStep(
this)) {
852 MR::deleteEffect(
this,
"RollingSmoke");
855 if (tryDisappear()) {
860 if (!_D4 && MR::isOnGround(
this)) {
865void CocoNut::exeWaitOnBind() {
866 if (MR::isFirstStep(
this)) {
867 MR::deleteEffect(
this,
"RollingSmoke");
869 if (!tryDisappear()) {
871 if (MR::isOnGround(
this)) {
877void CocoNut::exeMove() {
878 if (MR::isFirstStep(
this)) {
883 MR::onCalcGravity(
this);
884 MR::calcGravity(
this);
886 MR::invalidateClipping(
this);
889 if (_13C && MR::isStep(
this, 1)) {
896void CocoNut::exeInWater() {
897 if (MR::isFirstStep(
this)) {
900 MR::offCalcGravity(
this);
902 MR::invalidateHitSensors(
this);
903 MR::clearHitSensors(
this);
904 MR::deleteEffectAll(
this);
905 TVec3f gravityNegated;
906 negateInternalInline(
mGravity, &gravityNegated);
907 MR::makeMtxUpNoSupportPos(&_D8, gravityNegated,
mPosition);
908 MR::emitEffect(
this,
"WaterColumn");
909 MR::startSound(
this,
"SE_OJ_FALL_IN_WATER_M", -1, -1);
910 MR::releaseSoundHandle(
this,
"SE_OJ_FALL_IN_WATER_M");
912 if (!MR::isEffectValid(
this,
"WaterColumn")) {
914 setNerve(&NrvCocoNut::CocoNutNrvReplaceReady::sInstance);
918void CocoNut::exeBreak() {
919 if (MR::isFirstStep(
this)) {
921 TVec3f gravityNegated;
922 negateInternalInline(
mGravity, &gravityNegated);
923 MR::makeMtxUpNoSupportPos(&_D8, gravityNegated,
mPosition);
924 MR::emitEffect(
this, getBreakEffectName());
926 if (!MR::isEffectValid(
this, getBreakEffectName())) {
928 setNerve(&NrvCocoNut::CocoNutNrvReplaceReady::sInstance);
932namespace NrvCocoNut {
933 INIT_NERVE(CocoNutNrvWait)
934 INIT_NERVE(CocoNutNrvWaitOnBind)
935 INIT_NERVE(CocoNutNrvMove)
936 INIT_NERVE(CocoNutNrvInWater)
937 INIT_NERVE(CocoNutNrvBreak)
938 INIT_NERVE(CocoNutNrvReplaceReady)
940 void CocoNutNrvReplaceReady::execute(
Spine *pSpine)
const {
942 if (MR::isFirstStep(nut)) {
943 MR::validateClipping(nut);
946 void CocoNutNrvBreak::execute(
Spine *pSpine)
const {
950 void CocoNutNrvInWater::execute(
Spine *pSpine)
const {
954 void CocoNutNrvMove::execute(
Spine *pSpine)
const {
958 void CocoNutNrvWaitOnBind::execute(
Spine *pSpine)
const {
960 nut->exeWaitOnBind();
962 void CocoNutNrvWait::execute(
Spine *pSpine)
const {
virtual void init(const JMapInfoIter &)
Intializes the NameObj and can set various settings and construct necessary classes.
virtual void calcAndSetBaseMtx()
Calculates and sets the base matrix of the actor.
The basis of a drawable actor that can contain states (see: Nerve)
TVec3f mPosition
3D vector of the actor's position.
TVec3f mScale
3D vector of the actor's scale.
TVec3f mVelocity
3D vector of the actor's velocity.
TVec3f mGravity
3D vector of the actor's gravity.
HitSensor * getSensor(const char *pSensorName) const
Gets a sensor.
Stores archive names of NameObjs.