2023-12-13 00:40:16 -05:00
|
|
|
#include "Game/MapObj/MarblePlanet.hpp"
|
|
|
|
|
#include "Game/LiveActor/ModelObj.hpp"
|
|
|
|
|
#include "JSystem/JMath.hpp"
|
2022-02-22 12:00:13 -05:00
|
|
|
|
|
|
|
|
MarblePlanet::MarblePlanet(const char *pName) : LiveActor(pName) {
|
|
|
|
|
mCorePlanetModel = 0;
|
|
|
|
|
mPlanetElectrons = 0;
|
|
|
|
|
mWatermelonCollision = 0;
|
|
|
|
|
mNumElectrons = 3;
|
|
|
|
|
mRemainingElectrons = 3;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MarblePlanet::init(const JMapInfoIter &rIter) {
|
|
|
|
|
MR::initDefaultPos(this, rIter);
|
|
|
|
|
initModelManagerWithAnm("MarblePlanet", 0, false);
|
|
|
|
|
MR::connectToScenePlanet(this);
|
|
|
|
|
initHitSensor(1);
|
|
|
|
|
MR::addHitSensorEnemy(this, "core", 8, 50.0f, TVec3f(0.0f, 0.0f, 0.0f));
|
|
|
|
|
MR::initCollisionParts(this, "MarblePlanet", getSensor(0), 0);
|
|
|
|
|
mWatermelonCollision = MR::createCollisionPartsFromLiveActor(this, "WaterMelon", getSensor(0), (MR::CollisionScaleType)2);
|
|
|
|
|
initEffectKeeper(0, 0, false);
|
|
|
|
|
initSound(4, false);
|
|
|
|
|
MR::setClippingTypeSphereContainsModelBoundingBox(this, 100.0f);
|
|
|
|
|
MR::setClippingFar(this, -1.0f);
|
|
|
|
|
MR::needStageSwitchWriteDead(this, rIter);
|
|
|
|
|
MR::getJMapInfoArg0NoInit(rIter, &mNumElectrons);
|
|
|
|
|
mRemainingElectrons = mNumElectrons;
|
|
|
|
|
initCoreAndElectron();
|
|
|
|
|
MR::declarePowerStar(this);
|
|
|
|
|
initNerve(&NrvMarblePlanet::MarblePlanetNrvWait::sInstance);
|
|
|
|
|
makeActorAppeared();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MarblePlanet::exeScaleUpCore() {
|
|
|
|
|
if (MR::isFirstStep(this)) {
|
|
|
|
|
MR::tryRumblePadMiddle(this, 0);
|
|
|
|
|
MR::shakeCameraNormal();
|
|
|
|
|
mRemainingElectrons = mRemainingElectrons - 1;
|
|
|
|
|
switch (mRemainingElectrons) {
|
|
|
|
|
case 0:
|
|
|
|
|
MR::emitEffect(this, "Break");
|
|
|
|
|
MR::startSound(this, "SE_OJ_MARBLE_HIT_CORE_3", -1, -1);
|
|
|
|
|
MR::startSystemSE("SE_SY_MARBLE_HIT_CORE_3", -1, -1);
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
MR::emitEffect(this, "Smoke6f");
|
|
|
|
|
MR::startSound(this, "SE_OJ_MARBLE_HIT_CORE_2", -1, -1);
|
|
|
|
|
MR::startSystemSE("SE_SY_MARBLE_HIT_CORE_2", -1, -1);
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
default:
|
|
|
|
|
MR::emitEffect(this, "Smoke3f");
|
|
|
|
|
MR::startSound(this, "SE_OJ_MARBLE_HIT_CORE_1", -1, -1);
|
|
|
|
|
MR::startSystemSE("SE_SY_MARBLE_HIT_CORE_1", -1, -1);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mRemainingElectrons <= 0) {
|
|
|
|
|
setNerve(&NrvMarblePlanet::MarblePlanetNrvBreakCore::sInstance);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
s32 electronCount = mNumElectrons;
|
|
|
|
|
f32 frameMax = MR::getBckFrameMax(mCorePlanetModel);
|
|
|
|
|
f32 frame = ((electronCount - mRemainingElectrons) * frameMax) / electronCount;
|
|
|
|
|
MR::setBckFrameAndStop(mCorePlanetModel, frame);
|
|
|
|
|
MR::setBtkFrameAndStop(mCorePlanetModel, frame);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
f32 nerveRate = MR::calcNerveRate(this, 0x1E);
|
|
|
|
|
f32 scale = MR::getScaleWithReactionValueZeroToOne(nerveRate, 0.5f, -0.5f);
|
|
|
|
|
mCorePlanetModel->mScale.setAll(MR::getLinerValue(scale, 1.3f, 1.0f, 1.0f));
|
|
|
|
|
|
|
|
|
|
if (MR::isStep(this, 0x1E)) {
|
|
|
|
|
setNerve(&NrvMarblePlanet::MarblePlanetNrvWait::sInstance);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MarblePlanet::exeBreakCore() {
|
|
|
|
|
if (MR::isFirstStep(this)) {
|
|
|
|
|
MR::setBckFrameAndStop(mCorePlanetModel, MR::getBckFrameMax(mCorePlanetModel));
|
|
|
|
|
MR::setBtkFrameAndStop(mCorePlanetModel, MR::getBtkFrameMax(mCorePlanetModel));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (MR::isStep(this, 1)) {
|
|
|
|
|
MR::tryRumblePadStrong(this, 0);
|
|
|
|
|
MR::shakeCameraStrong();
|
|
|
|
|
MR::startAfterBossBGM();
|
|
|
|
|
MR::requestAppearPowerStar(this, mPosition);
|
|
|
|
|
MR::hideModel(this);
|
|
|
|
|
MR::invalidateCollisionParts(this);
|
|
|
|
|
MR::validateCollisionParts(mWatermelonCollision);
|
|
|
|
|
MR::onSwitchDead(this);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MarblePlanet::startClipped() {
|
|
|
|
|
mCorePlanetModel->startClipped();
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < mNumElectrons; i++) {
|
|
|
|
|
mPlanetElectrons[i]->startClipped();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LiveActor::startClipped();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MarblePlanet::endClipped() {
|
|
|
|
|
mCorePlanetModel->endClipped();
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < mNumElectrons; i++) {
|
|
|
|
|
mPlanetElectrons[i]->endClipped();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LiveActor::endClipped();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MarblePlanet::kill() {
|
|
|
|
|
MR::onSwitchDead(this);
|
|
|
|
|
mCorePlanetModel->kill();
|
|
|
|
|
LiveActor::kill();
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-31 01:01:30 -04:00
|
|
|
bool MarblePlanet::receiveMsgEnemyAttack(u32 msg, HitSensor *a1, HitSensor *a2) {
|
2022-02-22 12:00:13 -05:00
|
|
|
if (isNerve(&NrvMarblePlanet::MarblePlanetNrvScaleUpCore::sInstance)) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isNerve(&NrvMarblePlanet::MarblePlanetNrvBreakCore::sInstance)) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setNerve(&NrvMarblePlanet::MarblePlanetNrvScaleUpCore::sInstance);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MarblePlanet::initCoreAndElectron() {
|
|
|
|
|
mCorePlanetModel = MR::createModelObjMapObj("ビー玉惑星コア", "MarblePlanetCore", getBaseMtx());
|
|
|
|
|
MR::invalidateClipping(mCorePlanetModel);
|
|
|
|
|
MR::startBck(mCorePlanetModel, "MarblePlanetCore", 0);
|
|
|
|
|
MR::startBtk(mCorePlanetModel, "MarblePlanetCore");
|
|
|
|
|
MR::setBckFrameAndStop(mCorePlanetModel, 0.0f);
|
|
|
|
|
MR::setBtkFrameAndStop(mCorePlanetModel, 0.0f);
|
|
|
|
|
mPlanetElectrons = new MarblePlanetElectron*[mNumElectrons];
|
|
|
|
|
|
|
|
|
|
TVec3f front;
|
|
|
|
|
MR::calcFrontVec(&front, this);
|
|
|
|
|
|
|
|
|
|
TVec3f* pos;
|
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
|
|
if (mNumElectrons > 0) {
|
|
|
|
|
pos = &mPosition;
|
|
|
|
|
for (; i < mNumElectrons; i++) {
|
|
|
|
|
if (i != 0) {
|
|
|
|
|
TVec3f up;
|
|
|
|
|
MR::calcUpVec(&up, this);
|
|
|
|
|
MR::rotateVecDegree(&front, up, (360.0f / mNumElectrons));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TVec3f position;
|
|
|
|
|
JMAVECScaleAdd(front.toCVec(), pos->toCVec(), position.toVec(), 1000.0f);
|
|
|
|
|
TVec3f rotation;
|
|
|
|
|
rotation.setAll((360.0f * i) / mNumElectrons);
|
|
|
|
|
mPlanetElectrons[i] = new MarblePlanetElectron(this, position, rotation, "ビー玉惑星電子");
|
|
|
|
|
mPlanetElectrons[i]->initWithoutIter();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MarblePlanetElectron::MarblePlanetElectron(LiveActor *pPlanet, const TVec3f &rPosition, const TVec3f &rRotation, const char *pName) : LiveActor(pName) {
|
|
|
|
|
mParentPlanet = static_cast<MarblePlanet*>(pPlanet);
|
|
|
|
|
mElectronShadow = 0;
|
|
|
|
|
_94.x = 0.0f;
|
|
|
|
|
_94.y = 0.0f;
|
|
|
|
|
_94.z = 1.0f;
|
|
|
|
|
mPosition.set(rPosition);
|
|
|
|
|
mRotation.set(rRotation);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MarblePlanetElectron::init(const JMapInfoIter &rIter) {
|
|
|
|
|
initModelManagerWithAnm("MarblePlanetElectron", 0, false);
|
|
|
|
|
MR::connectToScenePlanet(this);
|
|
|
|
|
initHitSensor(1);
|
|
|
|
|
MR::addHitSensorEnemy(this, "body", 8, 500.0f, TVec3f(0.0f, 0.0f, 0.0f));
|
|
|
|
|
initBinder(200.0f, 0.0f, 0);
|
|
|
|
|
initEffectKeeper(1, 0, false);
|
|
|
|
|
MR::addEffectHitNormal(this, 0);
|
|
|
|
|
initSound(4, false);
|
|
|
|
|
MR::invalidateClipping(this);
|
|
|
|
|
mElectronShadow = new MarblePlanetElectronShadow(this, mParentPlanet->mPosition, "電子影");
|
|
|
|
|
mElectronShadow->initWithoutIter();
|
|
|
|
|
MR::calcGravity(this);
|
|
|
|
|
mGravity.negate();
|
|
|
|
|
|
|
|
|
|
TPos3f mtx;
|
|
|
|
|
MR::makeMtxUpNoSupportPos(&mtx, mGravity, mPosition);
|
|
|
|
|
MR::setBaseTRMtx(this, mtx);
|
|
|
|
|
MR::calcFrontVec(&_94, this);
|
|
|
|
|
MR::startBck(this, "MarblePlanetElectron", 0);
|
|
|
|
|
initNerve(&NrvMarblePlanetElectron::MarblePlanetElectronNrvMove::sInstance);
|
|
|
|
|
makeActorAppeared();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MarblePlanetElectron::exeMove() {
|
|
|
|
|
MR::turnDirectionToGround(this, &_94);
|
|
|
|
|
MR::attenuateVelocity(this, 0.99000001f);
|
|
|
|
|
f32 mag = PSVECMag(mVelocity.toCVec());
|
|
|
|
|
f32 scale = (mag >= 13.0f ? mag : 13.0f);
|
|
|
|
|
mVelocity.scale(scale, _94);
|
|
|
|
|
MR::startLevelSound(this, "SE_OJ_LV_MARBLE_ROTATE", -1, -1, -1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MarblePlanetElectron::exeAttack() {
|
|
|
|
|
if (MR::isFirstStep(this)) {
|
|
|
|
|
MR::startSound(this, "SE_OJ_MARBLE_FLIP", -1, -1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TVec3f velocity;
|
|
|
|
|
velocity.sub(mParentPlanet->mPosition, mPosition);
|
|
|
|
|
MR::normalize(&velocity);
|
|
|
|
|
mVelocity.scale(40.0f, velocity);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MarblePlanetElectron::control() {
|
|
|
|
|
MR::calcGravity(this);
|
|
|
|
|
mGravity.negate();
|
|
|
|
|
|
|
|
|
|
if (isNerve(&NrvMarblePlanetElectron::MarblePlanetElectronNrvMove::sInstance)) {
|
|
|
|
|
MR::restrictVelocity(this, 30.0f);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MarblePlanetElectron::attackSensor(HitSensor *a1, HitSensor *a2) {
|
|
|
|
|
if (MR::isSensorEnemy(a2)) {
|
|
|
|
|
if (MR::sendMsgEnemyAttack(a2, a1)) {
|
|
|
|
|
mElectronShadow->kill();
|
|
|
|
|
kill();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
bool isNear = !MR::isNear(this, a2->mActor->mPosition, 440.0f);
|
|
|
|
|
|
|
|
|
|
if (!isNear) {
|
|
|
|
|
if (MR::sendMsgPush(a2, a1)) {
|
|
|
|
|
MR::tryRumblePadVeryWeak(this, 0);
|
|
|
|
|
|
|
|
|
|
if (!MR::isEffectValid(this, "HitMarkNormal")) {
|
|
|
|
|
MR::emitEffectHitBetweenSensors(this, a1, a2, 0.0f, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MR::killVelocityToTarget(this, a2->mActor->mPosition);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-23 00:59:05 -04:00
|
|
|
bool MarblePlanetElectron::receiveMsgPlayerAttack(u32 msg, HitSensor *a2, HitSensor *a3) {
|
2022-02-22 12:00:13 -05:00
|
|
|
if (isNerve(&NrvMarblePlanetElectron::MarblePlanetElectronNrvAttack::sInstance)) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (MR::isMsgPlayerHipDrop(msg)) {
|
|
|
|
|
setNerve(&NrvMarblePlanetElectron::MarblePlanetElectronNrvAttack::sInstance);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-14 00:08:49 -04:00
|
|
|
bool MarblePlanetElectron::receiveMsgPush(HitSensor *a1, HitSensor *a2) {
|
2022-02-22 12:00:13 -05:00
|
|
|
if (!MR::isSensorEnemy(a1)) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
crashElectron(a1);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MarblePlanetElectron::crashElectron(HitSensor *pSensor) {
|
|
|
|
|
TVec3f stack_8;
|
|
|
|
|
stack_8.sub(pSensor->mActor->mPosition, mPosition);
|
|
|
|
|
MR::normalize(&stack_8);
|
|
|
|
|
JMAVECScaleAdd(stack_8.toCVec(), mVelocity.toCVec(), mVelocity.toVec(), -5.0f);
|
|
|
|
|
MR::normalize(mVelocity, &_94);
|
|
|
|
|
mVelocity.x *= 1.2f;
|
|
|
|
|
mVelocity.y *= 1.2f;
|
|
|
|
|
mVelocity.z *= 1.2f;
|
|
|
|
|
MR::startSound(this, "SE_OJ_MARBLE_HIT_EACH", -1, -1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MarblePlanetElectronShadow::MarblePlanetElectronShadow(LiveActor *pElectronPtr, const TVec3f &rVec, const char *pName) : LiveActor(pName) {
|
|
|
|
|
mParentElectron = static_cast<MarblePlanetElectron*>(pElectronPtr);
|
|
|
|
|
_90 = &rVec;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MarblePlanetElectronShadow::init(const JMapInfoIter &rIter) {
|
|
|
|
|
initModelManagerWithAnm("MarblePlanetElectronShadow", 0, false);
|
|
|
|
|
MR::connectToScenePlanet(this);
|
|
|
|
|
MR::invalidateClipping(this);
|
|
|
|
|
makeActorAppeared();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MarblePlanetElectronShadow::calcAndSetBaseMtx() {
|
|
|
|
|
mPosition.set(*_90);
|
|
|
|
|
TVec3f stack_8;
|
|
|
|
|
stack_8.sub(mParentElectron->mPosition, *_90);
|
|
|
|
|
MR::normalize(&stack_8);
|
|
|
|
|
TPos3f up_mtx;
|
|
|
|
|
MR::makeMtxUpNoSupportPos(&up_mtx, stack_8, *_90);
|
|
|
|
|
MR::setBaseTRMtx(this, up_mtx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MarblePlanet::~MarblePlanet() {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MarblePlanetElectron::~MarblePlanetElectron() {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MarblePlanetElectronShadow::~MarblePlanetElectronShadow() {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
namespace NrvMarblePlanet {
|
|
|
|
|
INIT_NERVE(MarblePlanetNrvWait);
|
|
|
|
|
INIT_NERVE(MarblePlanetNrvScaleUpCore);
|
|
|
|
|
INIT_NERVE(MarblePlanetNrvBreakCore);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
namespace NrvMarblePlanetElectron {
|
|
|
|
|
INIT_NERVE(MarblePlanetElectronNrvMove);
|
|
|
|
|
INIT_NERVE(MarblePlanetElectronNrvAttack);
|
|
|
|
|
|
|
|
|
|
void MarblePlanetElectronNrvAttack::execute(Spine *pSpine) const {
|
|
|
|
|
MarblePlanetElectron* electron = reinterpret_cast<MarblePlanetElectron*>(pSpine->mExecutor);
|
|
|
|
|
electron->exeAttack();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MarblePlanetElectronNrvMove::execute(Spine *pSpine) const {
|
|
|
|
|
MarblePlanetElectron* electron = reinterpret_cast<MarblePlanetElectron*>(pSpine->mExecutor);
|
|
|
|
|
electron->exeMove();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
namespace NrvMarblePlanet {
|
|
|
|
|
void MarblePlanetNrvBreakCore::execute(Spine *pSpine) const {
|
|
|
|
|
MarblePlanet* marble = reinterpret_cast<MarblePlanet*>(pSpine->mExecutor);
|
|
|
|
|
marble->exeBreakCore();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MarblePlanetNrvScaleUpCore::execute(Spine *pSpine) const {
|
|
|
|
|
MarblePlanet* marble = reinterpret_cast<MarblePlanet*>(pSpine->mExecutor);
|
|
|
|
|
marble->exeScaleUpCore();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MarblePlanetNrvWait::execute(Spine *pSpine) const {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
};
|