Files
sms/src/Enemy/bosseel.cpp
T
Paolo Imbriani 01b2fce78d Enemy/Bosswanwan TU (#159)
* feat: TBW started, shakeCamera done

* feat: progress TBW, first started shakeCamera

* feat: TBossWanwaReceiveMessage, 92%

* fix: misc...
- fixed to SMSGetSound instead of other API
- used Particles.hpp enum and created a new one based off modders tables
- used msSqrtf instead of fabricated match

* feat: added calcRootMatrix()

* fix: improve calcRootMatrix to 100%

* feat: TBWLeash(Node) progress

* feat: TBWLeashNode::calcTemperature 100%

* feat: some progress and TBossWanwanManager::createModelData() 100%

* feat: progress emitEffects() 97%

* declaring stuff

* progress TBWPicket, TBWHit

* progress TBWPicket::moveRequest

* more progress

* fixing some issues, progressing a lil

* feat: sliteToCurPathNode

* control

* feat: TNerveBWJumpToBath

* a bunch of stuff

* fucking destructors

* bunch of stuff 2.0

* changeBck unused function

* inline shenanigans

* anotha nerve

* feat: other nerves

* why I decided to do this

* 90ing all functions??????

* adjust after rebasing

* adjust after rebasing

* fix particles.hpp

* fixing some stuff

* fix: use enums for sound, animations, etc; update particles and actor types for wanwan

* create enum flags for wanwan

* fix: reorder symbol by val script + some adjusting
2026-10-26 14:33:58 +03:00

2432 lines
75 KiB
C++

#include <Enemy/BossEel.hpp>
#include <Enemy/Conductor.hpp>
#include <Camera/Camera.hpp>
#include <Camera/CameraShake.hpp>
#include <GC2D/GCConsole2.hpp>
#include <Camera/CubeManagerBase.hpp>
#include <MarioUtil/MathUtil.hpp>
#include <MarioUtil/MtxUtil.hpp>
#include <MarioUtil/PacketUtil.hpp>
#include <MarioUtil/RandomUtil.hpp>
#include <MarioUtil/RumbleMgr.hpp>
#include <MarioUtil/ScreenUtil.hpp>
#include <MarioUtil/TexUtil.hpp>
#include <MarioUtil/LightUtil.hpp>
#include <Map/Map.hpp>
#include <Map/MapData.hpp>
#include <Map/MapCollisionEntry.hpp>
#include <MoveBG/Item.hpp>
#include <MoveBG/ItemManager.hpp>
#include <M3DUtil/MActor.hpp>
#include <M3DUtil/SDLModel.hpp>
#include <MSound/MSound.hpp>
#include <MSound/SoundEffects.hpp>
#include <Player/MarioAccess.hpp>
#include <Player/Mario.hpp>
#include <Strategic/SharedParts.hpp>
#include <Strategic/Spine.hpp>
#include <Strategic/Strategy.hpp>
#include <Strategic/ObjModel.hpp>
#include <System/Application.hpp>
#include <System/EmitterViewObj.hpp>
#include <System/MarDirector.hpp>
#include <System/Particles.hpp>
#include <JSystem/J3D/J3DGraphAnimator/J3DCluster.hpp>
#include <JSystem/J3D/J3DGraphAnimator/J3DModel.hpp>
#include <JSystem/J3D/J3DGraphBase/J3DMaterial.hpp>
#include <JSystem/J3D/J3DGraphLoader/J3DModelLoader.hpp>
#include <JSystem/JDrama/JDRNameRefGen.hpp>
#include <JSystem/JKernel/JKRFileLoader.hpp>
#include <JSystem/JUtility/JUTTexture.hpp>
// rogue includes needed for matching sinit & bss
#include <MSound/MSSetSound.hpp>
#include <MSound/MSoundBGM.hpp>
f32 TBossEel::mOpenRollSpeed = 0.3f;
bool TBossEel::mUseObjCollision = true;
f32 TBossEel::mForcePow = 10.0f;
bool TBossEel::mUseMapCollision;
bool TBossEel::mToothDamageAnm;
f32 TBossEel::mTestAngY;
static const char* bosseel_bastable[] = {
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
"/scene/bosseel/bas/meoto_in_loop.bas",
nullptr,
"/scene/bosseel/bas/meoto_mogu.bas",
nullptr,
nullptr,
nullptr,
"/scene/bosseel/bas/meoto_out_loop.bas",
"/scene/bosseel/bas/meoto_paku.bas",
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
};
static const char* bossEelTears_bastable[]
= { nullptr, nullptr, nullptr, nullptr };
TBEelTearsDrop::TBEelTearsDrop(TBEelTears* owner, int jointIndex,
SDLModelData* modelData, const char* name)
: THitActor(name)
, mSharedParts(nullptr)
, mOwner(owner)
{
mSharedParts
= new TSharedParts(mOwner, jointIndex, modelData, 0, "<TSharedParts>");
initHitActor(ACTOR_TYPE_BOSS_EEL_TEARS, 3, HIT_CATEGORY_PLAYER,
mOwner->getTearsParams()->mSLTearsDropAttackRadius.get(),
mOwner->getTearsParams()->mSLTearsDropAttackHeight.get(),
mOwner->getTearsParams()->mSLTearsDropDamageRadius.get(),
mOwner->getTearsParams()->mSLTearsDropDamageHeight.get());
static_cast<TIdxGroupObj*>(JDrama::TNameRefGen::search("敵グループ"))
->getChildren()
.push_back(this);
mActive = false;
TScreenTexture* screenTexture = static_cast<TScreenTexture*>(
JDrama::TNameRefGen::search("スクリーンテクスチャ"));
const ResTIMG* textureInfo = screenTexture->getTexture()->getTexInfo();
new J3DSkinDeform;
MActor* actor = mSharedParts->getMActor();
SMS_ChangeTextureAll(actor->getModel()->getModelData(), "M_dummy",
*textureInfo);
actor->setBckFromIndex(0);
actor->setLightType(LIGHT_TYPE_INDIRECT);
}
void TBEelTearsDrop::perform(u32 cue, JDrama::TGraphics* graphics)
{
THitActor::perform(cue, graphics);
if (cue & CUE_MOVE) {
mPosition.y += mRiseSpeed;
if (mPosition.y > SMS_GetMarioPos().y + 2000.0f)
mActive = false;
}
if (cue & CUE_CALC_ANIM) {
Mtx transform;
// TODO: inline?
MtxPtr ptr = transform;
MsMtxSetXYZRPH(ptr, mPosition.x, mPosition.y, mPosition.z, mRotation.x,
mRotation.y, mRotation.z);
mSharedParts->getMActor()->getModel()->setBaseTRMtx(ptr);
f32 scale = mOwner->getTearsParams()->mSLTearsDropScaleLow.get();
mScaling.set(scale, scale, scale);
mSharedParts->getMActor()->getModel()->setBaseScale(mScaling);
}
mSharedParts->getMActor()->perform(cue, graphics);
}
void TBEelTearsDrop::generate(JGeometry::TVec3<f32>& position)
{
offHitFilter(HIT_FILTER_NO_COLLISION);
mActive = true;
TMsRange<f32> riseRange(4.0f, 6.0f);
mRiseSpeed = riseRange.rand();
mPosition = position;
TMsRange<f32> unused(1.0f, 1.5f);
unused.rand();
f32 scale = mOwner->getTearsParams()->mTearsDropScaleRange.rand();
mScaling.set(scale, scale, scale);
}
TBEelTearsSaveLoadParams::TBEelTearsSaveLoadParams(const char* path)
: TSpineEnemyParams(path)
, PARAM_INIT(mSLTearsUpSpeed, 5.0f)
, PARAM_INIT(mSLTearsDamageUpSpeed, 1.0f)
, PARAM_INIT(mSLTearsLiveHeight, 2000.0f)
, PARAM_INIT(mSLTearsSplitNum, 2)
, PARAM_INIT(mSLTearsDamageRadius, 600)
, PARAM_INIT(mSLTearsDamageHeight, 400)
, PARAM_INIT(mSLTearsAttackRadius, 500)
, PARAM_INIT(mSLTearsAttackHeight, 300)
, PARAM_INIT(mSLTearsDropDamageRadius, 600)
, PARAM_INIT(mSLTearsDropDamageHeight, 400)
, PARAM_INIT(mSLTearsDropAttackRadius, 500)
, PARAM_INIT(mSLTearsDropAttackHeight, 300)
, PARAM_INIT(mSLHighPolyDistY, 3000.0f)
, PARAM_INIT(mSLHitAnmFrameRate, 1.0f)
, PARAM_INIT(mSLBodyScaleLow, 1.0f)
, PARAM_INIT(mSLBodyScaleHigh, 1.0f)
, PARAM_INIT(mSLTearsDropScaleLow, 1.0f)
, PARAM_INIT(mSLTearsDropScaleHigh, 1.0f)
, mBodyScaleRange(0.0f, 1.0f)
, mTearsDropScaleRange(0.0f, 1.0f)
{
TParams::load(mPrmPath);
mBodyScaleRange.mMin = mSLBodyScaleLow.get();
mBodyScaleRange.mMax = mSLBodyScaleHigh.get();
mTearsDropScaleRange.mMin = mSLTearsDropScaleLow.get();
mTearsDropScaleRange.mMax = mSLTearsDropScaleHigh.get();
}
TBEelTearsManager::TBEelTearsManager(const char* name)
: TEnemyManager(name)
{
}
void TBEelTearsManager::load(JSUMemoryInputStream& stream)
{
unk38 = new TBEelTearsSaveLoadParams("/enemy/bossEelTears.prm");
TEnemyManager::load(stream);
}
void TBEelTearsManager::loadAfter()
{
SMS_LoadParticle("/scene/bossEelTears/ms_meo_tear_bomb.jpa", 0xD5);
SMS_LoadParticle("/scene/bossEelTears/ms_meo_tear_awaget.jpa", 0xD6);
SMS_LoadParticle("/scene/bossEelTears/ms_meo_tear_awa.jpa", 0x19D);
}
void TBEelTearsManager::createModelData()
{
static TModelDataLoadEntry entry[] = {
{ "tears.bmd",
J3DMLF_MaterialPEFull | J3DMLF_MaterialUseIndirect
| J3DMLF_UseUniqueMaterials | (4 << J3DMLF_TevStageNumShift),
0 },
{ "tears_waterhit.bmd",
J3DMLF_MaterialPEFull | J3DMLF_MaterialUseIndirect
| J3DMLF_UseUniqueMaterials | (4 << J3DMLF_TevStageNumShift),
0 },
{ nullptr, 0, 0 },
};
createModelDataArray(entry);
}
void TBEelTearsManager::perform(u32 cue, JDrama::TGraphics* graphics)
{
if (cue & CUE_CALC_ANIM)
clipEnemies(graphics);
for (int i = 0; i < getActiveObjNum(); ++i)
getObj(i)->perform(cue, graphics);
for (int i = 0; i < 30; ++i) {
if (mTearsDrops[i]->mActive)
mTearsDrops[i]->perform(cue, graphics);
}
}
TSpineEnemy* TBEelTearsManager::createEnemyInstance()
{
return new TBEelTears("めおとウナギ涙");
}
void TBEelTearsManager::createEnemies(int count)
{
TEnemyManager::createEnemies(count);
void* resource = JKRGetResource("/scene/bossEelTears/tears_drop.bmd");
SDLModelData* modelData
= new SDLModelData(J3DModelLoaderDataBase::load(resource, 0x11240000));
TBEelTears* owner = static_cast<TBEelTears*>(getObj(0));
for (int i = 0; i < 30; ++i)
mTearsDrops[i] = new TBEelTearsDrop(owner, 0, modelData, "涙粒");
}
void TBEelTearsManager::splitTears(JGeometry::TVec3<f32>& position)
{
int tearsLeft = getSaveParam()->mSLTearsSplitNum.get();
position.y += 600.0f;
TMsRange<f32> positionRange(-250.0f, 250.0f);
for (int i = 0; i < 30; ++i) {
TBEelTearsDrop** dropPtr = &mTearsDrops[i];
if ((*dropPtr)->mActive)
continue;
JGeometry::TVec3<f32> dropPosition = position;
dropPosition.x += positionRange.rand();
dropPosition.y += positionRange.rand();
dropPosition.z += positionRange.rand();
--tearsLeft;
(*dropPtr)->generate(dropPosition);
if (tearsLeft < 0)
break;
}
}
TBEelTears::TBEelTears(const char* name)
: TSpineEnemy(name)
, mTearsParams(nullptr)
, mHighPoly(true)
, mStateTimer(0)
, mSpawnMtx(nullptr)
, mRecoverCollision(nullptr)
{
}
void TBEelTears::init(TLiveManager* manager)
{
TSpineEnemy::init(manager);
mActorType = ACTOR_TYPE_BOSS_EEL;
onHitFilter(HIT_CATEGORY_PLAYER);
setMActorAndKeeper();
mTearsParams = static_cast<TBEelTearsSaveLoadParams*>(getSaveParam());
mSpine->initWith(&TNerveBEelTearsGenerate::theNerve());
TScreenTexture* screenTexture = static_cast<TScreenTexture*>(
JDrama::TNameRefGen::search("スクリーンテクスチャ"));
const ResTIMG& screenTexInfo = *screenTexture->getTexture()->getTexInfo();
J3DSkinDeform* deform = new J3DSkinDeform;
MActor* tearsActor = mMActorKeeper->getMActor("tears.bmd");
tearsActor->getModel()->setSkinDeform(deform, J3D_DEFORM_ATTACH_FLAG_UNK_1);
tearsActor->resetDL();
SMS_ChangeTextureAll(tearsActor->getModel()->getModelData(), "M_dummy",
screenTexInfo);
tearsActor->setLightType(LIGHT_TYPE_INDIRECT);
MActor* waterHitActor = mMActorKeeper->getMActor("tears_waterhit.bmd");
SMS_ChangeTextureAll(waterHitActor->getModel()->getModelData(), "M_dummy",
screenTexInfo);
waterHitActor->setLightType(LIGHT_TYPE_INDIRECT);
onLiveFlag(LIVE_FLAG_DEAD);
mBodyScale = mTearsParams->mBodyScaleRange.rand();
TIdxGroupObj* enemyGroup
= static_cast<TIdxGroupObj*>(JDrama::TNameRefGen::search("敵グループ"));
mRecoverCollision = new TBossEelTearsRecoverCollision(
mMActor->getModel()->getAnmMtx(0), "回復コリジョン");
mRecoverCollision->initCollision();
enemyGroup->getChildren().push_back(mRecoverCollision);
mRecoverCollision->onHitFilter(HIT_FILTER_NO_COLLISION);
}
void TBEelTears::setMActorAndKeeper()
{
mMActorKeeper = new TMActorKeeper(mManager, 2);
mMActor = mMActorKeeper->createMActor("tears.bmd", 0);
mMActorKeeper->createMActor("tears_waterhit.bmd", 0);
}
void TBEelTears::moveObject()
{
f32 liveHeight = mTearsParams->mSLTearsLiveHeight.get();
mVelocity.x *= 0.9f;
mVelocity.z *= 0.9f;
mPosition.x += mVelocity.x;
mPosition.z += mVelocity.z;
if (!mRecoverCollision->mColliding && mSpawnMtx != nullptr
&& (mPosition.y > gpMarioPos->y + 3000.0f
|| mPosition.y > mSpawnMtx[1][3] + liveHeight)) {
kill();
return;
}
f32 scale = mScaling.x;
f32 attackRadius = mTearsParams->mSLTearsAttackRadius.get();
f32 attackHeight = mTearsParams->mSLTearsAttackHeight.get();
f32 damageRadius = mTearsParams->mSLTearsDamageRadius.get();
f32 damageHeight = mTearsParams->mSLTearsDamageHeight.get();
setHitParams(attackRadius * scale, attackHeight * scale,
damageRadius * scale, damageHeight * scale);
for (int i = 0; i < getColNum(); ++i) {
THitActor* actor = getCollision(i);
if (actor->isActorType(ACTOR_TYPE_MARIO)) {
if (mSpine->getCurrentNerve()
== &TNerveBEelTearsMoveUp::theNerve()) {
SMS_SendMessageToMario(this, HIT_MESSAGE_ATTACK);
mSpine->pushNerve(&TNerveBEelTearsSplit::theNerve());
}
} else {
JGeometry::TVec3<f32> velocity(0.0f, 0.0f, 0.0f);
JGeometry::TVec3<f32> push(mPosition.x - actor->mPosition.x,
mPosition.y - actor->mPosition.y,
mPosition.z - actor->mPosition.z);
if (push.x == 0.0f && push.y == 0.0f && push.z == 0.0f)
push.x += 1.0f;
MsVECNormalize(&push, &push);
push *= 5.0f;
velocity += push;
mPositionDelta = velocity;
}
}
TLiveActor::moveObject();
}
void TBEelTears::calcRootMatrix()
{
if (mSpawnMtx != nullptr) {
if (mPosition.y < mSpawnMtx[1][3])
mPosition.y = mSpawnMtx[1][3];
TSpineEnemy::calcRootMatrix();
if (mSpine->getCurrentNerve() == &TNerveBEelTearsGenerate::theNerve()) {
TPosition3f transform(mPosition.x, mPosition.y, mPosition.z);
transform.ref(0, 3)
= transform.at(0, 3)
+ (mSpawnMtx[0][3] - transform.at(0, 3)) * 0.1f;
transform.ref(2, 3)
= transform.at(2, 3)
+ (mSpawnMtx[2][3] - transform.at(2, 3)) * 0.1f;
mScaling.setAll(mTearsParams->mSLBodyScaleLow.get());
mMActor->getModel()->setBaseScale(mScaling);
mMActor->getModel()->setBaseTRMtx(transform);
}
} else {
TSpineEnemy::calcRootMatrix();
}
}
void TBEelTears::perform(u32 cue, JDrama::TGraphics* graphics)
{
mRecoverCollision->perform(cue, graphics);
if (checkLiveFlag(LIVE_FLAG_DEAD))
return;
if (cue & CUE_MOVE)
moveObject();
if (cue & CUE_CALC_ANIM) {
Mtx44 effectMtx;
SMS_GetLightPerspectiveForEffectMtx(effectMtx);
mMActor->getModel()
->getModelData()
->getMaterialNodePointer(0)
->getTexGenBlock()
->getTexMtx(1)
->setEffectMtx(effectMtx);
updateAnmSound();
}
if (cue & CUE_CALC_ANIM)
mMActor->frameUpdate();
if (checkLiveFlag(LIVE_FLAG_HIDDEN | LIVE_FLAG_CLIPPED_OUT))
return;
if (cue & CUE_CALC_ANIM) {
calcRootMatrix();
mMActor->calc();
}
if (cue & CUE_CALC_VIEW)
mMActor->viewCalc();
if (cue & CUE_ENTRY)
mMActor->entry();
THitActor::perform(cue, graphics);
}
BOOL TBEelTears::receiveMessage(THitActor*, u32 message)
{
if (message == HIT_MESSAGE_SPRAYED_BY_WATER) {
mStateTimer = 60;
if (mSpine->getCurrentNerve() == &TNerveBEelTearsMoveUp::theNerve()
|| mSpine->getCurrentNerve() == &TNerveOilBallStay::theNerve())
mSpine->pushNerve(&TNerveBEelTearsWaterHit::theNerve());
if (mSpine->getCurrentNerve() == &TNerveBEelTearsWaterHit::theNerve()) {
MActor* actor = mMActor;
actor->setFrameRate(SMSGetAnmFrameRate(), ANM_TYPE_BCK);
}
return true;
}
return false;
}
void TBEelTears::kill()
{
onHitFilter(HIT_FILTER_NO_COLLISION);
mRecoverCollision->onHitFilter(HIT_FILTER_NO_COLLISION);
onLiveFlag(LIVE_FLAG_DEAD);
}
void TBEelTears::reset()
{
mActorType = ACTOR_TYPE_BOSS_EEL;
TSpineEnemy::reset();
mSpine->initWith(&TNerveBEelTearsGenerate::theNerve());
onLiveFlag(LIVE_FLAG_UNK10);
offLiveFlag(LIVE_FLAG_DEAD);
offLiveFlag(LIVE_FLAG_CLIPPED_OUT);
offLiveFlag(LIVE_FLAG_UNK200);
offLiveFlag(LIVE_FLAG_HIDDEN);
mGroundPlane = gpMap->getIllegalCheckData();
offHitFilter(HIT_FILTER_NO_COLLISION);
}
void TBEelTears::setBubble()
{
setRecoverTears();
mRecoverCollision->mPosition = mPosition;
mSpine->initWith(&TNerveBEelTearsMarioRecover::theNerve());
onLiveFlag(LIVE_FLAG_HIDDEN);
mRecoverCollision->mColliding = true;
}
void TBEelTears::setRecoverTears()
{
mRecoverCollision->mColliding = false;
mRecoverCollision->offHitFilter(HIT_FILTER_NO_COLLISION);
mRecoverCollision->mRecovering = true;
mRecoverCollision->mPosition = mPosition;
}
void TBEelTears::deadEffect()
{
JPABaseEmitter* emitter = gpMarioParticleManager->emitAndBindToPosPtr(
BOSSEELTEARS_MS_MEO_TEAR_BOMB, &mPosition, 0, nullptr);
if (emitter)
emitter->setGlobalScale(mScaling);
setRecoverTears();
mRecoverCollision->mPosition = mPosition;
static_cast<TBEelTearsManager*>(mManager)->splitTears(mPosition);
SMSGetMSound()->startSoundActor(MSD_SE_BS_UNG_TEAR_CLASH, &mPosition, 0,
nullptr, 0, 4);
onLiveFlag(LIVE_FLAG_HIDDEN);
}
const char** TBEelTears::getBasNameTable() const
{
return bossEelTears_bastable;
}
DEFINE_NERVE(TNerveBEelTearsGenerate, TLiveActor)
{
TBEelTears* tears = static_cast<TBEelTears*>(spine->getBody());
if (spine->getTime() == 0) {
tears->mMActor = tears->mMActorKeeper->getMActor("tears.bmd");
tears->mMActor->setBckFromIndex(2);
}
if (tears->checkCurAnmEnd(0)) {
spine->pushAfterCurrent(&TNerveBEelTearsMoveUp::theNerve());
return true;
}
return false;
}
DEFINE_NERVE(TNerveBEelTearsMoveUp, TLiveActor)
{
TBEelTears* tears = static_cast<TBEelTears*>(spine->getBody());
if (spine->getTime() == 0) {
tears->mMActor = tears->mMActorKeeper->getMActor("tears.bmd");
tears->mMActor->setBckFromIndex(1);
}
tears->mPosition.y += tears->getTearsParams()->mSLTearsUpSpeed.get();
return false;
}
DEFINE_NERVE(TNerveBEelTearsWaterHit, TLiveActor)
{
TBEelTears* tears = static_cast<TBEelTears*>(spine->getBody());
if (spine->getTime() == 0) {
SMSGetMSound()->startSoundActor(MSD_SE_BS_UNG_TEAR_TREMBLE,
&tears->mPosition, 0, nullptr, 0, 4);
tears->mMActor = tears->mMActorKeeper->getMActor("tears_waterhit.bmd");
tears->mMActor->setBckFromIndex(3);
}
--tears->mStateTimer;
f32 frameRate = tears->getTearsParams()->mSLHitAnmFrameRate.get();
if (tears->mStateTimer < 0) {
MActor* actor = tears->getMActor();
actor->setFrameRate(-frameRate * SMSGetAnmFrameRate(), ANM_TYPE_BCK);
if (tears->getCurAnmFrameNo(ANM_TYPE_BCK) < 1.0f)
return true;
} else {
MActor* actor = tears->getMActor();
actor->setFrameRate(frameRate * SMSGetAnmFrameRate(), ANM_TYPE_BCK);
}
if (tears->checkCurAnmEnd(ANM_TYPE_BCK)) {
spine->pushAfterCurrent(&TNerveBEelTearsMarioRecover::theNerve());
tears->deadEffect();
return true;
}
if (tears->mHighPoly)
tears->mPosition.y
+= tears->getTearsParams()->mSLTearsDamageUpSpeed.get();
return false;
}
DEFINE_NERVE(TNerveBEelTearsMarioRecover, TLiveActor)
{
TBEelTears* tears = static_cast<TBEelTears*>(spine->getBody());
if (!tears->mRecoverCollision->mRecovering) {
JPABaseEmitter* emitter = gpMarioParticleManager->emitAndBindToPosPtr(
BOSSEELTEARS_MS_MEO_TEAR_AWAGET, &SMS_GetMarioPos(), 0, nullptr);
if (emitter)
emitter->setGlobalScale(tears->mScaling);
tears->kill();
return true;
}
JPABaseEmitter* emitter = gpMarioParticleManager->emitAndBindToPosPtr(
BOSSEELTEARS_MS_MEO_TEAR_AWA, &tears->mPosition, 1, tears);
if (emitter)
emitter->setGlobalScale(tears->mScaling);
if (spine->getTime() > 1000) {
tears->kill();
return true;
}
if (tears->mRecoverCollision->mColliding) {
tears->mPosition.y += tears->getTearsParams()->mSLTearsUpSpeed.get();
tears->mRecoverCollision->mPosition.y = tears->mPosition.y;
}
return false;
}
DEFINE_NERVE(TNerveBEelTearsSplit, TLiveActor)
{
TBEelTears* tears = static_cast<TBEelTears*>(spine->getBody());
if (spine->getTime() == 0) {
SMSGetMSound()->startSoundActor(MSD_SE_BS_UNG_TEAR_TREMBLE,
&tears->mPosition, 0, nullptr, 0, 4);
tears->mMActor = tears->mMActorKeeper->getMActor("tears_waterhit.bmd");
tears->mMActor->setBckFromIndex(3);
MActor* actor = tears->getMActor();
f32 frameRate = tears->getTearsParams()->mSLHitAnmFrameRate.get();
actor->setFrameRate(frameRate * SMSGetAnmFrameRate(), ANM_TYPE_BCK);
}
if (tears->checkCurAnmEnd(ANM_TYPE_BCK)) {
tears->deadEffect();
spine->pushAfterCurrent(&TNerveBEelTearsMarioRecover::theNerve());
return true;
}
return false;
}
void TOilBall::load(JSUMemoryInputStream& stream)
{
mHighPoly = false;
TSpineEnemy::load(stream);
mInitialPosition = mPosition;
reset();
}
void TOilBall::reset()
{
TBEelTears::reset();
mPosition = mInitialPosition;
mSpine->initWith(&TNerveOilBallStay::theNerve());
mMActor = mMActorKeeper->getMActor("tears.bmd");
mMActor->setBckFromIndex(2);
mHighPoly = false;
}
void TOilBall::moveObject()
{
TBEelTearsSaveLoadParams* params = mTearsParams;
f32 scale = mScaling.x;
f32 attackRadius = params->mSLTearsAttackRadius.get();
f32 attackHeight = params->mSLTearsAttackHeight.get();
f32 damageRadius = params->mSLTearsDamageRadius.get();
f32 damageHeight = params->mSLTearsDamageHeight.get();
setHitParams(attackRadius * scale, attackHeight * scale,
damageRadius * scale, damageHeight * scale);
for (int i = 0; i < getColNum(); ++i) {
THitActor* actor = getCollision(i);
if (actor->isActorType(ACTOR_TYPE_MARIO)) {
if (mSpine->getCurrentNerve() == &TNerveBEelTearsMoveUp::theNerve()
|| mSpine->getCurrentNerve()
== &TNerveOilBallStay::theNerve()) {
SMS_SendMessageToMario(this, HIT_MESSAGE_ATTACK);
mSpine->pushNerve(&TNerveBEelTearsSplit::theNerve());
}
} else {
JGeometry::TVec3<f32> velocity(0.0f, 0.0f, 0.0f);
JGeometry::TVec3<f32> push;
push.sub(mPosition, actor->mPosition);
if (push.x == 0.0f && push.y == 0.0f && push.z == 0.0f)
push.x += 1.0f;
MsVECNormalize(&push, &push);
push.scale(5.0f);
velocity.add(push);
mPositionDelta = velocity;
}
}
TLiveActor::moveObject();
}
void TOilBall::calcRootMatrix() { TSpineEnemy::calcRootMatrix(); }
DEFINE_NERVE(TNerveOilBallStay, TLiveActor)
{
TOilBall* oilBall = static_cast<TOilBall*>(spine->getBody());
if (oilBall->getMActor()->checkCurBckFromIndex(3)
|| (oilBall->checkCurAnmEnd(0)
&& !oilBall->getMActor()->checkCurBckFromIndex(1))) {
oilBall->mMActor = oilBall->mMActorKeeper->getMActor("tears.bmd");
oilBall->mMActor->setBckFromIndex(1);
}
return false;
}
TBossEelSaveParams::TBossEelSaveParams()
: TParams("/enemy/bosseel.prm")
, PARAM_INIT(mSLInitTransYOffset, 0.0f)
, PARAM_INIT(mSLAppearMoveDistY, 6000.0f)
, PARAM_INIT(mSLBodyScale, 0.75f)
, PARAM_INIT(mSLViewClipFar, 25000.0f)
, PARAM_INIT(mSLViewClipRadius, 12000.0f)
, PARAM_INIT(mSLBodyToHeadDistance, 6000.0f)
, PARAM_INIT(mSLBodyAttackRadius, 2400.0f)
, PARAM_INIT(mSLBodyAttackHeight, 6300.0f)
, PARAM_INIT(mSLBodyDamageRadius, 2200.0f)
, PARAM_INIT(mSLBodyDamageHeight, 6100.0f)
, PARAM_INIT(mSLHeadAttackRadius, 3600.0f)
, PARAM_INIT(mSLHeadAttackHeight, 5600.0f)
, PARAM_INIT(mSLHeadDamageRadius, 3400.0f)
, PARAM_INIT(mSLHeadDamageHeight, 5400.0f)
, PARAM_INIT(mSLToothAttackRadius, 500.0f)
, PARAM_INIT(mSLToothAttackHeight, 300.0f)
, PARAM_INIT(mSLToothDamageRadius, 600.0f)
, PARAM_INIT(mSLToothDamageHeight, 400.0f)
, PARAM_INIT(mSLSpinAccel, 0.01f)
, PARAM_INIT(mSLSpinMaxSpeed, 10.0f)
, PARAM_INIT(mSLToothUpSpeed, 5.0f)
, PARAM_INIT(mSLToothLiveHeight, 2000.0f)
, PARAM_INIT(mSLToothMaxHitPoint, 50)
, PARAM_INIT(mSLGenTearsTime, 100)
, PARAM_INIT(mSLVortexAttackRadius, 500.0f)
, PARAM_INIT(mSLVortexAttackHeight, 300.0f)
, PARAM_INIT(mSLVortexDamageRadius, 600.0f)
, PARAM_INIT(mSLVortexDamageHeight, 400.0f)
, PARAM_INIT(mSLVortexLiveTimer, 300)
, PARAM_INIT(mSLVortexScaleXZ, 1.0f)
, PARAM_INIT(mSLVortexScaleY, 1.0f)
, PARAM_INIT(mSLMouthOpenFrame, 500)
, PARAM_INIT(mSLMouthOpenInterval, 2000)
, PARAM_INIT(mSLCanEatFrame, 200)
, PARAM_INIT(mSLBreathInPower, 10.0f)
{
TParams::load(mPrmPath);
}
void TBossEelManager::loadAfter()
{
SMS_LoadParticle("/scene/bosseel/jpa/ms_meo_awa_tooth.jpa",
BOSSEEL_JPA_MS_MEO_AWA_TOOTH);
SMS_LoadParticle("/scene/bosseel/jpa/ms_meo_awa_mouth.jpa",
BOSSEEL_JPA_MS_MEO_AWA_MOUTH);
SMS_LoadParticle("/scene/bosseel/jpa/ms_meo_eyeblur.jpa",
BOSSEEL_JPA_MS_MEO_EYEBLUR);
SMS_LoadParticle("/scene/bosseel/jpa/ms_meo_spin_smoke.jpa",
BOSSEEL_JPA_MS_MEO_SPIN_SMOKE);
SMS_LoadParticle("/scene/bosseel/jpa/ms_meo_spin_smoke_l.jpa",
BOSSEEL_JPA_MS_MEO_SPIN_SMOKE_L);
SMS_LoadParticle("/scene/bosseel/jpa/ms_meo_spin_awa.jpa",
BOSSEEL_JPA_MS_MEO_SPIN_AWA);
SMS_LoadParticle("/scene/bosseel/jpa/ms_meo_spin_awa_l.jpa",
BOSSEEL_JPA_MS_MEO_SPIN_AWA_L);
SMS_LoadParticle("/scene/bosseel/jpa/ms_meo_awa_body.jpa",
BOSSEEL_JPA_MS_MEO_AWA_BODY);
SMS_LoadParticle("/scene/bosseel/jpa/ms_meo_awa_dead.jpa",
BOSSEEL_JPA_MS_MEO_AWA_DEAD);
SMS_LoadParticle("/scene/bosseel/jpa/ms_meo_suikomi.jpa",
BOSSEEL_JPA_MS_MEO_SUIKOMI);
SMS_LoadParticle("/scene/bosseel/jpa/ms_meo_tooth_wash.jpa",
BOSSEEL_JPA_MS_MEO_TOOTH_WASH);
SMS_LoadParticle("/scene/bosseel/jpa/ms_meo_tooth_kira.jpa",
BOSSEEL_JPA_MS_MEO_TOOTH_KIRA);
SMS_LoadParticle("/scene/bosseel/jpa/ms_meo_tooth_always.jpa",
BOSSEEL_JPA_MS_MEO_TOOTH_ALWAYS);
}
void TBossEelManager::createModelData()
{
static const TModelDataLoadEntry entry[] = {
{ "meoto_model.bmd",
J3DMLF_MaterialPEFull | (2 << J3DMLF_TevStageNumShift), 0 },
{ nullptr, 0, 0 },
};
createModelDataArray(entry);
}
void TBossEelManager::clipEnemies(JDrama::TGraphics* graphics)
{
clipActorsAux(graphics, mSaveParams.mSLViewClipFar.get(),
mSaveParams.mSLViewClipRadius.get());
}
TBossEelTooth::TBossEelTooth(u8 toothType, TBossEel* owner,
const char* jointName, SDLModelData* modelData,
const char* name)
: THitActor(name)
, mSharedParts(nullptr)
, mOwner(owner)
, mHitPoints(0)
, mToothType(toothType)
, mTrembleRotation(0.0f, 0.0f, 0.0f)
, mDamageCooldown(0)
, mCanShedTears(true)
{
s32 jointIndex = mOwner->getMActor()
->getModel()
->getModelData()
->getJointName()
->getIndex(jointName);
mSharedParts
= new TSharedParts(mOwner, jointIndex, modelData, 0, "<TSharedParts>");
MActor* actor = mSharedParts->getMActor();
mSharedParts->getMActor()->setLightType(LIGHT_TYPE_OBJECT);
mSharedParts->getMActor()->setBckFromIndex(22);
mSharedParts->getMActor()->setFrameRate(0.0f, ANM_TYPE_BCK);
for (u16 i = 0; i < actor->getModel()->getModelData()->getMaterialNum();
++i)
SMS_InitPacket_OneTevKColorAndFog(actor->getModel(), i, GX_KCOLOR0,
&mColor);
mColor.a = 0xFF;
mHitPoints = mOwner->getBossEelParams().mSLToothMaxHitPoint.get();
initHitActor(ACTOR_TYPE_BOSS_EEL_TOOTH, 5,
HIT_CATEGORY_PLAYER | HIT_CATEGORY_WATER,
mOwner->getBossEelParams().mSLToothAttackRadius.get(),
mOwner->getBossEelParams().mSLToothAttackHeight.get(),
mOwner->getBossEelParams().mSLToothDamageRadius.get(),
mOwner->getBossEelParams().mSLToothDamageHeight.get());
static_cast<TIdxGroupObj*>(
JDrama::TNameRefGen::search("オブジェクトグループ"))
->getChildren()
.push_back(this);
offHitFilter(HIT_FILTER_NO_COLLISION);
}
void TBossEelTooth::changeToothAlpha(u8 alpha) { mColor.a = alpha; }
BOOL TBossEelTooth::receiveMessage(THitActor* sender, u32 message)
{
BOOL result = false;
if (message == HIT_MESSAGE_SPRAYED_BY_WATER) {
if (mDamageCooldown == 0 && !mOwner->mToothBroken && mHitPoints > 1) {
mDamageCooldown = 2;
--mHitPoints;
MActor* actor = mSharedParts->getMActor();
actor->setFrameRate(SMSGetAnmFrameRate(), ANM_TYPE_BCK);
mOwner->mToothDamaged = true;
mColor.a = static_cast<u8>(
static_cast<f32>(mHitPoints * 0xFF)
/ static_cast<f32>(
mOwner->getBossEelParams().mSLToothMaxHitPoint.get()));
if (mToothType == 1 && mHitPoints % 20 == 1)
mOwner->forceShedTears(mCanShedTears);
if (mHitPoints == 1) {
mColor.a = 0;
MTXCopy(mSharedParts->getConnectedMtx(), mDetachedMtx);
if (mToothType == 1) {
SMSGetMSound()->startSoundActor(MSD_SE_BS_UNG_TEATH_COMEOFF,
&mPosition, 0, nullptr, 0,
4);
if (mCanShedTears)
SMSGetMSound()->startSoundActor(
MSD_SE_BS_UNG_VOICE_M_CRY, &mOwner->mPosition, 0,
nullptr, 0, 4);
else
SMSGetMSound()->startSoundActor(
MSD_SE_BS_UNG_VOICE_W_CRY, &mOwner->mPosition, 0,
nullptr, 0, 4);
mOwner->mToothBroken = true;
JPABaseEmitter* emitter = gpMarioParticleManager->emit(
BOSSEEL_JPA_MS_MEO_AWA_TOOTH, &mPosition, 0, nullptr);
if (emitter)
emitter->setGlobalScale(mOwner->mScaling);
} else {
SMSGetMSound()->startSoundActor(MSD_SE_BS_UNG_TEATH_FLASH,
&mPosition, 0, nullptr, 0,
4);
if (mCanShedTears)
SMSGetMSound()->startSoundActor(
MSD_SE_BS_UNG_VOICE_M_JOY, &mOwner->mPosition, 0,
nullptr, 0, 4);
else
SMSGetMSound()->startSoundActor(
MSD_SE_BS_UNG_VOICE_W_JOY, &mOwner->mPosition, 0,
nullptr, 0, 4);
}
}
}
result = true;
}
return result;
}
void TBossEelTooth::updateTremble() { }
void TBossEelTooth::perform(u32 cue, JDrama::TGraphics* graphics)
{
if (mOwner->checkLiveFlag(LIVE_FLAG_CLIPPED_OUT) || mHitPoints == 0)
return;
if (cue & CUE_MOVE) {
TBossEelSaveParams* params = mOwner->mSaveParams;
f32 scale = mOwner->mScaling.x;
f32 attackRadius = params->mSLToothAttackRadius.get();
f32 attackHeight = params->mSLToothAttackHeight.get();
f32 damageHeight = params->mSLToothDamageHeight.get();
f32 damageRadius = params->mSLToothDamageRadius.get();
attackRadius *= scale;
attackHeight *= scale;
damageRadius *= scale;
damageHeight *= scale;
setHitParams(attackRadius, attackHeight, damageRadius, damageHeight);
for (s32 i = 0; i < mColCount; ++i) {
THitActor* collision = mCollisions[i];
if (mOwner->isValidToothDamage()
&& collision->isActorType(ACTOR_TYPE_MARIO) && mHitPoints > 1) {
SMS_SendMessageToMario(this, HIT_MESSAGE_ATTACK);
}
}
if (mDamageCooldown > 0) {
--mDamageCooldown;
} else {
if (mSharedParts->getMActor()->checkCurBckFromIndex(22)
&& mSharedParts->getMActor()->curAnmEndsNext(ANM_TYPE_BCK,
nullptr))
mSharedParts->getMActor()->setFrameRate(0.0f, ANM_TYPE_BCK);
if (mHitPoints == 1) {
if (mToothType == 1) {
if (mSharedParts->getMActor()->checkCurBckFromIndex(22)) {
mSharedParts->getMActor()->setBckFromIndex(20);
JGeometry::TVec3<f32> tearsPosition(
mDetachedMtx.at(0, 3),
mTrembleRotation.y + mDetachedMtx.at(1, 3),
mDetachedMtx.at(2, 3));
mOwner->generateBubble(tearsPosition);
mSharedParts->getMActor()->setFrameRate(
SMSGetAnmFrameRate(), ANM_TYPE_BCK);
}
if (mSharedParts->getMActor()->checkCurBckFromIndex(20)
&& mSharedParts->getMActor()->curAnmEndsNext(
ANM_TYPE_BCK, nullptr))
mSharedParts->getMActor()->setBckFromIndex(21);
}
f32 speed = mOwner->getBossEelParams().mSLToothUpSpeed.get();
if (mToothType == 1) {
mTrembleRotation.y += speed;
if (mTrembleRotation.y > mOwner->getBossEelParams()
.mSLToothLiveHeight.get()
|| mPosition.y > SMS_GetMarioPos().y + 2000.0f) {
mHitPoints = 0;
onHitFilter(HIT_FILTER_NO_COLLISION);
}
}
}
}
}
if (cue & CUE_CALC_ANIM) {
Mtx toothMtx;
if (mHitPoints > 1 || mToothType == 0 || mToothType == 2)
MTXCopy(mSharedParts->getConnectedMtx(), toothMtx);
else
MTXCopy(mDetachedMtx, toothMtx);
if (mHitPoints > 1) {
JPABaseEmitter* emitter
= gpMarioParticleManager->emitAndBindToPosPtr(
BOSSEEL_JPA_MS_MEO_TOOTH_ALWAYS, &mPosition, 1, this);
if (emitter)
emitter->setGlobalScale(mOwner->mScaling);
}
if (mSharedParts->getMActor()->checkCurBckFromIndex(22)
&& mSharedParts->getMActor()->getFrameCtrl(ANM_TYPE_BCK)->getRate()
> 0.0f) {
JPABaseEmitter* emitter
= gpMarioParticleManager->emitAndBindToPosPtr(
BOSSEEL_JPA_MS_MEO_TOOTH_WASH, &mPosition, 1, this);
if (emitter)
emitter->setGlobalScale(mOwner->mScaling);
}
if ((mToothType == 0 || mToothType == 2) && mHitPoints == 1) {
JPABaseEmitter* emitter
= gpMarioParticleManager->emitAndBindToPosPtr(
BOSSEEL_JPA_MS_MEO_TOOTH_KIRA, &mPosition, 1, this);
if (emitter)
emitter->setGlobalScale(mOwner->mScaling);
}
TPosition3f transform(0, 0, mTrembleRotation.x);
MTXConcat(toothMtx, transform, toothMtx);
MsMtxSetRotRPH(transform, mTrembleRotation.z, mTrembleRotation.z, 0.0f);
MTXConcat(toothMtx, transform, toothMtx);
toothMtx[1][3] += mTrembleRotation.y;
mPosition.x = toothMtx[0][3];
mPosition.y = toothMtx[1][3];
mPosition.z = toothMtx[2][3];
mSharedParts->getMActor()->getModel()->setBaseTRMtx(toothMtx);
}
THitActor::perform(cue, graphics);
mSharedParts->getMActor()->perform(cue, graphics);
}
TBossEelVortex::TBossEelVortex(TBossEel* owner, const char* name)
: THitActor(name)
, mOwner(owner)
, mInactive(true)
{
initHitActor(ACTOR_TYPE_BOSS_EEL, 3, HIT_CATEGORY_PLAYER,
mOwner->getBossEelParams().mSLVortexAttackRadius.get(),
mOwner->getBossEelParams().mSLVortexAttackHeight.get(),
mOwner->getBossEelParams().mSLVortexDamageRadius.get(),
mOwner->getBossEelParams().mSLVortexDamageHeight.get());
static_cast<TIdxGroupObj*>(JDrama::TNameRefGen::search("敵グループ"))
->getChildren()
.push_back(this);
offHitFilter(HIT_FILTER_NO_COLLISION);
}
void TBossEelVortex::perform(u32 cue, JDrama::TGraphics* graphics)
{
if (mInactive)
return;
if (cue & CUE_MOVE) {
{
TBossEel* owner = mOwner;
TBossEelSaveParams* params = owner->mSaveParams;
f32 scale = owner->mScaling.x;
f32 attackRadius = params->mSLVortexAttackRadius.get();
f32 attackHeight = params->mSLVortexAttackHeight.get();
f32 damageHeight = params->mSLVortexDamageHeight.get();
f32 damageRadius = params->mSLVortexDamageRadius.get();
mAttackRadius = attackRadius * scale;
mAttackHeight = attackHeight * scale;
mDamageRadius = damageRadius * scale;
mDamageHeight = damageHeight * scale;
}
calcEntryRadius();
++mTimer;
if (mTimer > 30) {
if (mOwner->getMActor()->checkCurBckFromIndex(14)
|| mOwner->getMActor()->checkCurBckFromIndex(17)) {
for (s32 i = 0; i < mColCount; ++i) {
if (!mCollisions[i]->isActorType(ACTOR_TYPE_MARIO))
continue;
JGeometry::TVec3<f32> marioTarget;
marioTarget.set(mOwner->mPosition.x - SMS_GetMarioPos().x,
mOwner->mPosition.y - SMS_GetMarioPos().y,
mOwner->mPosition.z - SMS_GetMarioPos().z);
MsVECNormalize(&marioTarget, &marioTarget);
f32 power = mOwner->mSaveParams->mSLBreathInPower.get();
f32 wave = fabsf(JMASSin(
static_cast<s16>(182.04445f * (0.9f * mTimer))));
if (wave > 1.0f)
wave = 1.0f;
else if (wave < 0.1f)
wave = 0.1f;
power *= wave;
SMSRumbleMgr->start(8, &mPosition);
if (mOwner->getMActor()->checkCurBckFromIndex(17))
power *= 0.5f;
marioTarget.scale(power);
marioTarget.add(SMS_GetMarioPos());
SMS_MarioMoveRequest(marioTarget);
}
} else {
onHitFilter(HIT_FILTER_NO_COLLISION);
}
}
}
if (cue & CUE_CALC_ANIM) {
mPosition.x = mOwner->getMActor()->getModel()->getAnmMtx(
mOwner->mMapCollisionJointIndices[2])[0][3];
mPosition.y = mOwner->getMActor()->getModel()->getAnmMtx(
mOwner->mMapCollisionJointIndices[2])[1][3]
+ 1000.0f;
mPosition.z = mOwner->getMActor()->getModel()->getAnmMtx(
mOwner->mMapCollisionJointIndices[2])[2][3];
}
THitActor::perform(cue, graphics);
}
void TBossEelVortex::reset()
{
offHitFilter(HIT_FILTER_NO_COLLISION);
onHitFilter(HIT_CATEGORY_PLAYER);
mTimer = 0;
}
TBossEelEye::TBossEelEye(const TLiveActor* owner, int jointIndex,
SDLModelData* modelData, u32 modelFlags,
const char* name)
: TSharedParts(owner, jointIndex, modelData, modelFlags, name)
, mBlendModel(nullptr)
, mCopyConnectedMtx(-1)
, mBlinkTimer(0)
, mBlinkDelay(0)
, mBlurTimer(0)
, mBlurDuration(50)
{
mBlendModel = new SDLModel(modelData, modelFlags, 1);
mBlendModel->getModelData()->getMaterialName()->getIndex("_mat7");
getMActor()->initBckNormalMotionBlend();
mPreviousBckIndex = getMActor()->getCurAnmIdx(ANM_TYPE_BCK);
mAnimationMode = 0;
mBlendRatio = 1.0f;
getMActor()->setBckOldMotionBlendAnmPtr(getMActor()->getCurBckAnmPtr());
getMActor()->setBckFromIndex(0);
getMActor()->setBckMotionBlendRatio(mBlendRatio);
}
void TBossEelEye::perform(u32 cue, JDrama::TGraphics* graphics)
{
if (getOwner()->checkLiveFlag(LIVE_FLAG_DEAD | LIVE_FLAG_HIDDEN
| LIVE_FLAG_CLIPPED_OUT))
return;
if (cue & CUE_CALC_ANIM) {
mBlurPosition.set(getConnectedMtx()[0][3], getConnectedMtx()[1][3],
getConnectedMtx()[2][3]);
JPABaseEmitter* emitter = gpMarioParticleManager->emitAndBindToPosPtr(
BOSSEEL_JPA_MS_MEO_EYEBLUR, &mBlurPosition, 1, this);
if (emitter)
emitter->setGlobalScale(getOwner()->mScaling);
Mtx eyeMtx;
MTXCopy(getConnectedMtx(), eyeMtx);
MtxPtr mtx = eyeMtx;
getMActor()->getModel()->setBaseTRMtx(mtx);
if (mCopyConnectedMtx == 0)
MTXCopy(mtx, mBlendMtx);
mBlendRatio = MsClamp(mBlendRatio - 0.01f, 0.0f, 1.0f);
getMActor()->setBckMotionBlendRatio(mBlendRatio);
if (mAnimationMode == 1
&& getMActor()->curAnmEndsNext(ANM_TYPE_BCK, nullptr)) {
++mAnimationLoopCount;
if (mAnimationLoopCount > 3) {
mPreviousBckIndex = getMActor()->getCurAnmIdx(ANM_TYPE_BCK);
mAnimationMode = 0;
mBlendRatio = 1.0f;
getMActor()->setBckOldMotionBlendAnmPtr(
getMActor()->getCurBckAnmPtr());
getMActor()->setBckFromIndex(0);
getMActor()->setBckMotionBlendRatio(mBlendRatio);
TBossEelEye* paired = mPairedEye;
paired->mPreviousBckIndex
= paired->getMActor()->getCurAnmIdx(ANM_TYPE_BCK);
paired->mAnimationMode = 0;
paired->mBlendRatio = 1.0f;
paired->getMActor()->setBckOldMotionBlendAnmPtr(
paired->getMActor()->getCurBckAnmPtr());
paired->getMActor()->setBckFromIndex(0);
paired->getMActor()->setBckMotionBlendRatio(
paired->mBlendRatio);
}
}
}
getMActor()->perform(cue, graphics);
mCopyConnectedMtx = -1;
}
void TBossEelEye::setBckAnm(int index)
{
mPreviousBckIndex = getMActor()->getCurAnmIdx(ANM_TYPE_BCK);
mAnimationMode = 1;
mBlendRatio = 1.0f;
getMActor()->setBckOldMotionBlendAnmPtr(getMActor()->getCurBckAnmPtr());
getMActor()->setBckFromIndex(index);
getMActor()->setBckMotionBlendRatio(mBlendRatio);
}
TBossEelHeartCoin::TBossEelHeartCoin(const TLiveActor* owner, int jointIndex,
SDLModelData* modelData, u32 modelFlags,
const char* name)
: TSharedParts(owner, jointIndex, modelData, modelFlags, name)
, mActive(false)
, mOwner(nullptr)
{
mOwner = owner;
for (s32 i = 0; i < 20; ++i) {
mCoins[i] = gpItemManager->newAndRegisterCoinReal();
mCoins[i]->kill();
}
}
void TBossEelHeartCoin::perform(u32 cue, JDrama::TGraphics* graphics)
{
if (!mActive)
return;
u32 calcAnim = cue & CUE_CALC_ANIM;
if (calcAnim) {
s32 jointIndex = mOwner->mMActor->getModel()
->getModelData()
->getJointName()
->getIndex("ha7");
MtxPtr jointMtx = mOwner->mMActor->getModel()->getAnmMtx(jointIndex);
if (mOwner->mMActor->checkCurBckFromIndex(3)
&& mOwner->mMActor->getFrameCtrl(ANM_TYPE_BCK)->getFrame()
< 700.0f) {
mPosition.set(jointMtx[0][3], jointMtx[1][3], jointMtx[2][3]);
}
mPosition.y = jointMtx[1][3];
TPosition3f heartMtx(mPosition.x, mPosition.y, mPosition.z);
getMActor()->getModel()->setBaseTRMtx(heartMtx);
}
getMActor()->perform(cue, graphics);
if (calcAnim) {
for (s32 i = 0; i < 20; ++i) {
MtxPtr coinMtx = getMActor()->getModel()->getAnmMtx(i + 2);
mCoins[i]->mPosition.set(coinMtx[0][3], coinMtx[1][3],
coinMtx[2][3]);
}
}
}
#pragma dont_inline on
void TBossEelHeartCoin::generate(JGeometry::TVec3<f32>& position)
{
mPosition.set(position.x, position.y, position.z);
mActive = true;
for (s32 i = 0; i < 20; ++i) {
mCoins[i]->appear();
mCoins[i]->onMapObjFlag(0x10000000);
MtxPtr coinMtx = getMActor()->getModel()->getAnmMtx(0);
mCoins[i]->mPosition.set(coinMtx[0][3], coinMtx[1][3], coinMtx[2][3]);
}
}
#pragma dont_inline off
TBossEel::TBossEel(const char* name)
: TSpineEnemy(name)
, mHeadCollision(nullptr)
, mMouthCubeManager(nullptr)
, mBodyCollision(nullptr)
, mBckBlendRatio(1.0f)
, mTearEyeIndex(0)
, mTearCycleTimer(0)
, mSpinAngle(500.0f)
, mTearEyeToggle(true)
, mMouthOpenAmount(2350.0f)
, mMouthOpenSpeed(0.75f)
, mSaveParams(nullptr)
, mInDemo(false)
, mAppearOffset(0.0f)
, mToothDamaged(false)
, mToothBroken(false)
, mIsBiting(false)
, mBattleTimer(0)
, mBarrierCollision(nullptr)
, mAwaCollision(nullptr)
, mHeartCoin(nullptr)
, mMoguCameraActive(false)
, mCollisionEnabled(true)
{
mSpinTimer = new JGeometry::TVec2<s32>(0, 1);
}
void TBossEel::generateBubble(JGeometry::TVec3<f32>& position)
{
TBEelTears* tears
= static_cast<TBEelTears*>(gpConductor->makeOneEnemyAppear(
position, "めおとウナギ涙マネージャー", 0));
if (tears)
tears->setBubble();
}
TBossEelCollision::TBossEelCollision(MtxPtr collisionMtx, const char* name)
: THitActor(name)
, mCollisionMtx(collisionMtx)
, mBaseAttackRadius(0.0f)
, mBaseAttackHeight(0.0f)
, mBaseDamageRadius(0.0f)
, mBaseDamageHeight(0.0f)
, mOwner(nullptr)
{
}
void TBossEelCollision::perform(u32 cue, JDrama::TGraphics* graphics)
{
if (cue & CUE_MOVE) {
calcEntryRadius();
for (s32 i = 0; i < mColCount; ++i) {
if (mCollisions[i]->isActorType(ACTOR_TYPE_MARIO))
behaveToMario();
}
}
if (cue & CUE_CALC_ANIM) {
mPosition.x = mCollisionMtx[0][3];
mPosition.y = mCollisionMtx[1][3];
mPosition.z = mCollisionMtx[2][3];
}
THitActor::perform(cue, graphics);
}
void TBossEelCollision::initCollision()
{
initHitActor(ACTOR_TYPE_BOSS_EEL_COLLISION, 5, HIT_CATEGORY_PLAYER,
mBaseAttackRadius, mBaseAttackHeight, mBaseDamageRadius,
mBaseDamageHeight);
}
void TBossEelCollision::behaveToMario()
{
JGeometry::TVec3<f32> marioTarget(0.0f, TBossEel::mForcePow, 0.0f);
marioTarget += SMS_GetMarioPos();
SMS_MarioMoveRequest(marioTarget);
if (mOwner && mOwner->canEatMario())
mOwner->forceEat();
}
void TBossEelBodyCollision::initCollision()
{
mBaseAttackRadius = 2000.0f;
mBaseDamageRadius = 2000.0f;
mBaseAttackHeight = 5800.0f;
mBaseDamageHeight = 5000.0f;
TBossEelCollision::initCollision();
}
void TBossEelAwaCollision::initCollision()
{
mBaseDamageRadius = 2000.0f;
mBaseAttackRadius = 2000.0f;
mBaseDamageHeight = 2000.0f;
mBaseAttackHeight = 2000.0f;
initHitActor(ACTOR_TYPE_BOSS_EEL, 2, HIT_CATEGORY_PLAYER, mBaseAttackRadius,
mBaseAttackHeight, mBaseDamageRadius, mBaseDamageHeight);
}
void TBossEelAwaCollision::behaveToMario()
{
JGeometry::TVec3<f32> marioTarget(0.0f, 10.0f, 0.0f);
marioTarget.y = 15.0f;
*gpMarioSpeedY = 0.0f;
marioTarget += SMS_GetMarioPos();
SMS_MarioMoveRequest(marioTarget);
}
void TBossEelAwaCollision::perform(u32 cue, JDrama::TGraphics* graphics)
{
if (cue & CUE_MOVE) {
calcEntryRadius();
if (SMS_GetMarioPos().y < mPosition.y + 500.0f)
offHitFilter(HIT_FILTER_NO_COLLISION);
if (SMS_GetMarioPos().y > mPosition.y + mAttackHeight)
onHitFilter(HIT_FILTER_NO_COLLISION);
for (s32 i = 0; i < mColCount; ++i) {
if (mCollisions[i]->isActorType(ACTOR_TYPE_MARIO))
behaveToMario();
}
}
if (cue & CUE_CALC_ANIM) {
mPosition.x = mCollisionMtx[0][3];
mPosition.y = mCollisionMtx[1][3] + 11000.0f;
mPosition.z = mCollisionMtx[2][3];
}
THitActor::perform(cue, graphics);
}
void TBossEelBarrierCollision::initCollision()
{
mBaseDamageRadius = 0.0f;
mBaseAttackRadius = 0.0f;
mBaseDamageHeight = 0.0f;
mBaseAttackHeight = 0.0f;
TBossEelCollision::initCollision();
}
void TBossEelBarrierCollision::behaveToMario()
{
JGeometry::TVec3<f32> marioTarget(0.0f, TBossEel::mForcePow, 0.0f);
marioTarget += SMS_GetMarioPos();
SMS_MarioMoveRequest(marioTarget);
}
void TBossEelTearsRecoverCollision::initCollision()
{
mBaseDamageRadius = 400.0f;
mBaseAttackRadius = 400.0f;
mBaseDamageHeight = 400.0f;
mBaseAttackHeight = 400.0f;
initHitActor(ACTOR_TYPE_BOSS_EEL_TEARS, 3, HIT_CATEGORY_PLAYER,
mBaseAttackRadius, mBaseAttackHeight, mBaseDamageRadius,
mBaseDamageHeight);
}
void TBossEelTearsRecoverCollision::behaveToMario()
{
SMS_SendMessageToMario(this, HIT_MESSAGE_ATTACK);
mRecovering = false;
onHitFilter(HIT_FILTER_NO_COLLISION);
}
void TBossEelTearsRecoverCollision::perform(u32 cue,
JDrama::TGraphics* graphics)
{
if (cue & CUE_MOVE) {
calcEntryRadius();
for (s32 i = 0; i < mColCount; ++i) {
if (mCollisions[i]->isActorType(ACTOR_TYPE_MARIO))
behaveToMario();
}
}
THitActor::perform(cue, graphics);
}
void TBossEel::init(TLiveManager* manager)
{
mManager = manager;
manager->manageActor(this);
mMActorKeeper = new TMActorKeeper(manager);
mMActorKeeper->createMActorFromAllBmd(0);
mMActor = mMActorKeeper->getMActor(0);
mSaveParams = &static_cast<TBossEelManager*>(manager)->mSaveParams;
mInitialPosition.set(mPosition);
onLiveFlag(LIVE_FLAG_UNK8 | LIVE_FLAG_UNK10);
mGroundHeight = gpMap->checkGround(
mPosition.x, mPosition.y + getHeadHeight(), mPosition.z, &mGroundPlane);
mMActor->initBckNormalMotionBlend();
mSpine->initWith(&TNerveBossEelWaitAppear::theNerve());
initHitActor(ACTOR_TYPE_BOSS_EEL, 1, HIT_CATEGORY_PLAYER,
mSaveParams->mSLBodyAttackRadius.get(),
mSaveParams->mSLBodyAttackHeight.get(),
mSaveParams->mSLBodyDamageRadius.get(),
mSaveParams->mSLBodyDamageHeight.get());
offHitFilter(HIT_FILTER_NO_COLLISION);
J3DModel* model = mMActor->getModel();
if (!model->getSkinDeform())
model->setSkinDeform(new J3DSkinDeform, J3D_DEFORM_ATTACH_FLAG_UNK_1);
mMActor->resetDL();
mHeadCollision = new THitActor("めおとウナギの頭部");
mHeadCollision->initHitActor(ACTOR_TYPE_BOSS_EEL, 2, HIT_CATEGORY_PLAYER,
mSaveParams->mSLHeadAttackRadius.get(),
mSaveParams->mSLHeadAttackHeight.get(),
mSaveParams->mSLHeadDamageRadius.get(),
mSaveParams->mSLHeadDamageHeight.get());
TIdxGroupObj* enemyGroup
= static_cast<TIdxGroupObj*>(JDrama::TNameRefGen::search("敵グループ"));
enemyGroup->getChildren().push_back(mHeadCollision);
mHeadCollision->offHitFilter(HIT_FILTER_NO_COLLISION);
mBodyCollision = new TBossEelBodyCollision(
mMActor->getModel()->getBaseTRMtx(), "体コリジョン");
mBodyCollision->initCollision();
mBodyCollision->mOwner = this;
enemyGroup->getChildren().push_back(mBodyCollision);
mBodyCollision->offHitFilter(HIT_FILTER_NO_COLLISION);
mBarrierCollision = new TBossEelBarrierCollision(
mMActor->getModel()->getAnmMtx(7), "障害コリジョン");
mBarrierCollision->initCollision();
enemyGroup->getChildren().push_back(mBarrierCollision);
mBarrierCollision->offHitFilter(HIT_FILTER_NO_COLLISION);
JUTNameTab* jntNames = mMActor->getModel()->getModelData()->getJointName();
{
static const char* sEyePartsJointTable[]
= { "eye1", "eye2", "eye3", "eye4" };
void* eyeResource = JKRGetResource("/scene/bosseel/eye.bmd");
SDLModelData* eyeModelData
= new SDLModelData(J3DModelLoaderDataBase::load(
eyeResource, J3DMLF_MaterialPEFull | J3DMLF_UseUniqueMaterials
| (4 << J3DMLF_TevStageNumShift)));
for (s32 i = 0; i < 4; ++i) {
s32 jointIndex = jntNames->getIndex(sEyePartsJointTable[i]);
mEyes[i] = new TBossEelEye(this, jointIndex, eyeModelData, 3,
"めおとウナギ目");
}
mEyes[0]->mPairedEye = mEyes[1];
mEyes[1]->mPairedEye = mEyes[0];
mEyes[2]->mPairedEye = mEyes[3];
mEyes[3]->mPairedEye = mEyes[2];
mEyes[2]->getMActor()->getFrameCtrl(ANM_TYPE_BCK)->setFrame(100.0f);
mEyes[3]->getMActor()->getFrameCtrl(ANM_TYPE_BCK)->setFrame(100.0f);
}
{
SDLModelData* toothModelData[3];
void* resource1 = JKRGetResource("/scene/bosseel/tooth.bmd");
toothModelData[0] = new SDLModelData(J3DModelLoaderDataBase::load(
resource1,
J3DMLF_MaterialPEFull | (16 << J3DMLF_TevStageNumShift)));
void* resource2 = JKRGetResource("/scene/bosseel/bad_tooth.bmd");
toothModelData[1] = new SDLModelData(J3DModelLoaderDataBase::load(
resource2,
J3DMLF_MaterialPEFull | (16 << J3DMLF_TevStageNumShift)));
void* resource3 = JKRGetResource("/scene/bosseel/gold_tooth.bmd");
toothModelData[2] = new SDLModelData(J3DModelLoaderDataBase::load(
resource3,
J3DMLF_MaterialPEFull | (16 << J3DMLF_TevStageNumShift)));
static const char* sToothPartsJointTable[]
= { "ha1", "ha2", "ha3", "ha4", "ha5", "ha6", "ha7", "ha8" };
for (s32 i = 0; i < 8; ++i) {
u8 toothType = 0;
if (i == 1 || i == 4 || i == 7)
toothType = 1;
if (i == 6)
toothType = 2;
mTeeth[i] = new TBossEelTooth(
toothType, this, sToothPartsJointTable[i],
toothModelData[toothType], "めおとウナギの歯");
mTeeth[i]->mCanShedTears = false;
if (i == 0 || i == 1 || i == 2 || i == 7)
mTeeth[i]->mCanShedTears = true;
}
}
{
void* heartResource
= JKRGetResource("/scene/bosseel/meoto_heartcoin.bmd");
SDLModelData* heartModelData
= new SDLModelData(J3DModelLoaderDataBase::load(
heartResource, J3DMLF_MaterialPEFull | J3DMLF_UseUniqueMaterials
| (4 << J3DMLF_TevStageNumShift)));
mHeartCoin = new TBossEelHeartCoin(this, 0, heartModelData, 3,
"めおとウナギハートコイン");
}
{
static const char* sCollisionJointTable[]
= { "headcol1", "headcol2", "sebone5", "sebone5" };
static const char* sCollisionFileTable[]
= { "/bosseel/meoto_head", "/bosseel/meoto_head2",
"/bosseel/meoto_camera", "/bosseel/meoto_out_loop" };
for (s32 i = 0; i < 4; ++i) {
mMapCollisionJointIndices[i]
= jntNames->getIndex(sCollisionJointTable[i]);
mMapCollisions[i] = new TMapCollisionMove;
mMapCollisions[i]->init(sCollisionFileTable[i], 2, this);
mMapCollisions[i]->setUpTrans(mPosition);
}
}
mAwaCollision = new TBossEelAwaCollision(
mMActor->getModel()->getAnmMtx(mMapCollisionJointIndices[2]),
"泡コリジョン");
mAwaCollision->initCollision();
enemyGroup->getChildren().push_back(mAwaCollision);
mAwaCollision->onHitFilter(HIT_FILTER_NO_COLLISION);
mVortex = new TBossEelVortex(this, "めおとウナギ渦");
mMouthCubeManager = new TCubeManagerBase("コリジョンキューブ", 2);
TCubeGeneralInfo* mouthCube
= *mMouthCubeManager->unk14->getChildren().begin();
mouthCube->unkC.set(mPosition.x, mPosition.y + 9600.0f, mPosition.z);
mouthCube->unk24.set(7000.0f, 10000.0f, 7000.0f);
if (mInstanceIndex == 0) {
for (u8 i = 0; i < getModel()->getModelData()->getJointNum(); ++i)
; // assert?
}
initAnmSound();
mMActor->getModel()->calc();
}
MtxPtr TBossEel::getTakingMtx() { return mMActor->getModel()->getAnmMtx(7); }
void TBossEel::calcAndSetCollisionCubeBite_()
{
TCubeGeneralInfo* mouthCube
= mMouthCubeManager->unk14->getChildren().begin()[1];
mouthCube->unk18.set(mRotation);
mouthCube->unkC.set(mPosition.x, mPosition.y + 1900.0f, mPosition.z);
mouthCube->unk24.set(1100.0f, 1000.0f, 1100.0f);
mouthCube->unkC.set(mPosition.x, mPosition.y + 9600.0f * mScaling.y,
mPosition.z);
mouthCube->unk24.set(7000.0f * mScaling.x, 10000.0f * mScaling.y,
7000.0f * mScaling.z);
}
void TBossEel::updateTearsCnt()
{
static const s32 eyeTable[] = { 0, 2, 1, 3 };
++mTearCycleTimer;
s32 interval = mSaveParams->mSLGenTearsTime.get();
f32 height = fabsf(mPosition.y - SMS_GetMarioPos().y);
if (height > 30000.0f)
interval *= 4;
else if (height > 15000.0f)
interval *= 3;
else if (height > 6000.0f)
interval *= 2;
if (mTearCycleTimer == interval - 100) {
s32 eyeIndex = eyeTable[mTearEyeIndex];
mEyes[eyeIndex]->setBckAnm(1);
mEyes[eyeIndex]->mPairedEye->setBckAnm(1);
}
if (mTearCycleTimer > interval) {
mTearCycleTimer = 0;
s32 eyeIndex = eyeTable[mTearEyeIndex];
MtxPtr spawnMtx = mEyes[eyeIndex]->getConnectedMtx();
mEyes[eyeIndex]->setBckAnm(1);
mEyes[eyeIndex]->mAnimationLoopCount = 0;
shedTears(spawnMtx);
mTearEyeIndex += 1;
if (mTearEyeIndex >= 4)
mTearEyeIndex = 0;
}
}
void TBossEel::forceEat()
{
if (mSpine->getCurrentNerve() != &TNerveBossEelEat::theNerve())
mSpine->pushNerve(&TNerveBossEelEat::theNerve());
}
bool TBossEel::canEatMario()
{
if (mForceEat)
return true;
MtxPtr mouthMtx
= getMActor()->getModel()->getAnmMtx(mMapCollisionJointIndices[0]);
JGeometry::TVec3<f32> distance = SMS_GetMarioPos();
distance.x -= mouthMtx[0][3];
distance.y -= mouthMtx[1][3];
distance.z -= mouthMtx[2][3];
if (MsVECMag2(&distance) < mMouthOpenAmount * mMouthOpenSpeed)
return true;
return false;
}
BOOL TBossEel::isEyeBlurOn() { }
void TBossEel::shedTears(MtxPtr spawnMtx)
{
JGeometry::TVec3<f32> position(spawnMtx[0][3], spawnMtx[1][3],
spawnMtx[2][3]);
TBEelTears* tears
= static_cast<TBEelTears*>(gpConductor->makeOneEnemyAppear(
position, "めおとウナギ涙マネージャー", 0));
if (!tears)
return;
tears->mSpawnMtx = spawnMtx;
tears->reset();
JGeometry::TVec3<f32> direction(0.0f, 0.0f, 100.0f);
TMsRange<f32> angleRange(0.0f, 360.0f);
Mtx rotation;
MsMtxSetRotRPH(rotation, 0.0f, angleRange.rand(), 0.0f);
MTXMultVec(rotation, &direction, &direction);
tears->mPosition.x += direction.x;
tears->mPosition.z += direction.z;
MsVECNormalize(&direction, &direction);
direction.x *= 10.0f;
direction.z *= 10.0f;
tears->mVelocity = direction;
}
#pragma dont_inline on
void TBossEel::forceShedTears(bool rearEyes)
{
mTearEyeToggle = !mTearEyeToggle;
s32 eyeIndex;
if (!rearEyes) {
eyeIndex = 0;
if (mTearEyeToggle)
eyeIndex = 1;
} else {
eyeIndex = 2;
if (mTearEyeToggle)
eyeIndex = 3;
}
MtxPtr spawnMtx = mEyes[eyeIndex]->getConnectedMtx();
mEyes[eyeIndex]->setBckAnm(1);
mEyes[eyeIndex]->mAnimationLoopCount = 0;
shedTears(spawnMtx);
}
#pragma dont_inline off
void TBossEel::generateVortex()
{
mVortex->reset();
MtxPtr vortexMtx
= getMActor()->getModel()->getAnmMtx(mMapCollisionJointIndices[2]);
mVortex->mPosition.set(vortexMtx[0][3], vortexMtx[1][3], vortexMtx[2][3]);
mVortex->mInactive = false;
mVortex->mScaling.set(mSaveParams->mSLVortexScaleXZ.get(),
mSaveParams->mSLVortexScaleY.get(),
mSaveParams->mSLVortexScaleXZ.get());
offHitFilter(HIT_FILTER_NO_COLLISION);
}
void TBossEel::invalidateAllCollision()
{
mBodyCollision->onHitFilter(HIT_FILTER_NO_COLLISION);
mBarrierCollision->onHitFilter(HIT_FILTER_NO_COLLISION);
mVortex->onHitFilter(HIT_FILTER_NO_COLLISION);
mHeadCollision->onHitFilter(HIT_FILTER_NO_COLLISION);
mAwaCollision->offHitFilter(HIT_FILTER_NO_COLLISION);
}
void TBossEel::collideToMario()
{
JGeometry::TVec3<f32> marioTarget = SMS_GetMarioPos();
JGeometry::TVec3<f32> correction(0.0f, 0.0f, 0.0f);
for (s32 i = 0; i < 2; ++i) {
MtxPtr collisionMtx
= mMActor->getModel()->getAnmMtx(mMapCollisionJointIndices[i]);
JGeometry::TVec3<f32> center(collisionMtx[0][3], collisionMtx[1][3],
collisionMtx[2][3]);
JGeometry::TVec3<f32> axis;
axis.x = collisionMtx[0][1];
axis.y = collisionMtx[1][1];
axis.z = collisionMtx[2][1];
if (i == 0)
axis.negate();
axis.normalize();
JGeometry::TVec3<f32> distance = marioTarget;
distance.sub(center);
f32 length = distance.length();
if (length == 0.0f || length >= mMouthOpenAmount)
continue;
f32 penetration = mMouthOpenAmount - length;
f32 axialDistance = distance.dot(axis);
if (axialDistance >= 0.0f)
continue;
JGeometry::TVec3<f32> push;
if (-axialDistance < penetration) {
push = axis;
push.scale(-axialDistance);
} else {
push = distance;
push.normalize();
push.scale(penetration);
}
correction.add(push);
}
marioTarget.add(correction);
SMS_MarioMoveRequest(marioTarget);
}
void TBossEel::perform(u32 cue, JDrama::TGraphics* graphics)
{
if ((cue & CUE_CALC_ANIM)
&& mSpine->getCurrentNerve() == &TNerveBossEelDie::theNerve()) {
mDeathEffectPosition.set(0.0f, -14000.0f, 0.0f);
gpMarioParticleManager->emit(BOSSEEL_JPA_MS_MEO_AWA_DEAD,
&mDeathEffectPosition, 1, this);
}
if (mMActor->checkCurBckFromIndex(4))
mAwaCollision->perform(cue, graphics);
if (checkLiveFlag(LIVE_FLAG_UNK200))
return;
if (cue & CUE_MOVE) {
mScaling.x = mScaling.y = mScaling.z = mSaveParams->mSLBodyScale.get();
mPosition.y
= mAppearOffset
+ (mInitialPosition.y + mSaveParams->mSLInitTransYOffset.get());
TCubeGeneralInfo* mouthCube
= *mMouthCubeManager->unk14->getChildren().begin();
mouthCube->unkC.set(mPosition.x, mPosition.y + 9600.0f * mScaling.y,
mPosition.z);
mouthCube->unk24.set(7000.0f * mScaling.x, 10000.0f * mScaling.y,
7000.0f * mScaling.z);
moveObject();
mMActor->calcAnm();
calcRootMatrix();
collideToMario();
TPosition3f collisionMtx;
collisionMtx.set(
mMActor->getModel()->getAnmMtx(mMapCollisionJointIndices[2]));
mMapCollisions[2]->moveMtx(collisionMtx);
if (mUseMapCollision) {
for (s32 i = 0; i < 2; ++i) {
TPosition3f collisionMtx;
collisionMtx.set(mMActor->getModel()->getAnmMtx(
mMapCollisionJointIndices[i]));
mMapCollisions[i]->moveMtx(collisionMtx);
}
}
if (mUseObjCollision
&& mSpine->getCurrentNerve() != &TNerveBossEelDie::theNerve())
mBodyCollision->offHitFilter(HIT_FILTER_NO_COLLISION);
else
mBodyCollision->onHitFilter(HIT_FILTER_NO_COLLISION);
mHeadCollision->mPosition = mPosition;
f32 bodyToHeadDistance = mSaveParams->mSLBodyToHeadDistance.get();
bodyToHeadDistance *= mScaling.y;
mHeadCollision->mPosition.y += bodyToHeadDistance;
mHeadCollision->setHitParams(
mSaveParams->mSLHeadAttackRadius.get() * mScaling.x,
mSaveParams->mSLHeadAttackHeight.get() * mScaling.x,
mSaveParams->mSLHeadDamageRadius.get() * mScaling.x,
mSaveParams->mSLHeadDamageHeight.get() * mScaling.x);
setHitParams(mSaveParams->mSLBodyAttackRadius.get() * mScaling.x,
mSaveParams->mSLBodyAttackHeight.get() * mScaling.x,
mSaveParams->mSLBodyDamageRadius.get() * mScaling.x,
mSaveParams->mSLBodyDamageHeight.get() * mScaling.x);
calcAndSetCollisionCubeBite_();
if (mHitPoints != 0) {
mForceEat = false;
for (s32 i = 0; i < mHeadCollision->getColNum(); ++i) {
if (mHeadCollision->getCollision(i)->isActorType(
ACTOR_TYPE_MARIO))
mForceEat = true;
}
if (mSpine->getCurrentNerve() != &TNerveBossEelFirstSpin::theNerve()
&& mSpine->getCurrentNerve()
!= &TNerveBossEelSecondSpin::theNerve()
&& mSpine->getCurrentNerve()
!= &TNerveBossEelMouthOpenWait::theNerve()
&& (mMActor->checkCurBckFromIndex(10)
|| mMActor->checkCurBckFromIndex(16)
|| mMActor->checkCurBckFromIndex(18)
|| mMActor->checkCurBckFromIndex(19)))
updateTearsCnt();
mBckBlendRatio = MsClamp(mBckBlendRatio - 0.01f, 0.0f, 1.0f);
mMActor->setBckMotionBlendRatio(mBckBlendRatio);
}
deadCheck();
}
if (cue & CUE_CALC_ANIM) {
offLiveFlag(LIVE_FLAG_CLIPPED_OUT);
updateAnmSound();
if (mSpine->getCurrentNerve() == &TNerveBossEelSecondSpin::theNerve()
|| mSpine->getCurrentNerve()
== &TNerveBossEelFirstSpin::theNerve()) {
MtxPtr breathMtx = mMActor->getModel()->getAnmMtx(5);
mBreathParticlePosition.set(breathMtx[0][3], breathMtx[1][3],
breathMtx[2][3]);
JPABaseEmitter* emitter;
if (checkLiveFlag(LIVE_FLAG_UNK10000))
emitter = gpMarioParticleManager->emit(
BOSSEEL_JPA_MS_MEO_SPIN_SMOKE, &mBreathParticlePosition, 1,
this);
else
emitter = gpMarioParticleManager->emit(
BOSSEEL_JPA_MS_MEO_SPIN_SMOKE_L, &mBreathParticlePosition,
1, this);
if (emitter)
emitter->setGlobalScale(mScaling);
if (checkLiveFlag(LIVE_FLAG_UNK10000))
emitter = gpMarioParticleManager->emit(
BOSSEEL_JPA_MS_MEO_SPIN_AWA, &mBreathParticlePosition, 1,
this);
else
emitter = gpMarioParticleManager->emit(
BOSSEEL_JPA_MS_MEO_SPIN_AWA_L, &mBreathParticlePosition, 1,
this);
if (emitter)
emitter->setGlobalScale(mScaling);
}
if (mMActor->checkCurBckFromIndex(15)) {
J3DFrameCtrl* frameCtrl = mMActor->getFrameCtrl(ANM_TYPE_BCK);
MtxPtr breathMtx = mMActor->getModel()->getAnmMtx(5);
mBreathParticlePosition.set(breathMtx[0][3], breathMtx[1][3],
breathMtx[2][3]);
if (frameCtrl->checkPass(102.0f)) {
JPABaseEmitter* emitter
= gpMarioParticleManager->emitAndBindToPosPtr(
BOSSEEL_JPA_MS_MEO_AWA_MOUTH, &mBreathParticlePosition,
0, nullptr);
if (emitter)
emitter->setGlobalScale(mScaling);
}
if (frameCtrl->getFrame() < 40.0f) {
JPABaseEmitter* emitter = gpMarioParticleManager->emit(
BOSSEEL_JPA_MS_MEO_AWA_BODY, &mBreathParticlePosition, 1,
this);
if (emitter)
emitter->setGlobalScale(mScaling);
}
}
if (mMActor->checkCurBckFromIndex(14)) {
J3DFrameCtrl* frameCtrl = mMActor->getFrameCtrl(ANM_TYPE_BCK);
MtxPtr breathMtx = mMActor->getModel()->getAnmMtx(5);
mBreathParticlePosition.set(breathMtx[0][3], breathMtx[1][3],
breathMtx[2][3]);
SMSGetMSound()->startSoundActor(MSD_SE_BS_UNG_VACUUM, &mPosition, 0,
nullptr, 0, 4);
JPABaseEmitter* emitter
= gpMarioParticleManager->emitAndBindToPosPtr(
BOSSEEL_JPA_MS_MEO_SUIKOMI, &mBreathParticlePosition, 1,
this);
if (emitter) {
JGeometry::TVec3<f32> scale(3.0f, 3.0f, 3.0f);
emitter->setGlobalScale(scale);
}
}
}
if (cue & CUE_CALC_VIEW)
mMActor->viewCalc();
if (cue & CUE_ENTRY)
mMActor->entry();
for (s32 i = 0; i < 4; ++i)
mEyes[i]->testPerform(cue, graphics);
for (s32 i = 0; i < 8; ++i)
mTeeth[i]->testPerform(cue, graphics);
mHeartCoin->perform(cue, graphics);
mVortex->perform(cue, graphics);
mBodyCollision->perform(cue, graphics);
mBarrierCollision->perform(cue, graphics);
}
void TBossEel::setBckAnm(int index)
{
mPreviousBckIndex = getMActor()->getCurAnmIdx(ANM_TYPE_BCK);
mCurrentBckIndex = index;
mBckBlendRatio = 1.0f;
getMActor()->setBckOldMotionBlendAnmPtr(getMActor()->getCurBckAnmPtr());
getMActor()->setBckFromIndex(index);
getMActor()->setBckMotionBlendRatio(mBckBlendRatio);
getMActor()
->getFrameCtrl(ANM_TYPE_BCK)
->setRate(0.25f * SMSGetAnmFrameRate());
setAnmSound(getBas(index));
}
void TBossEel::deadCheck()
{
for (s32 i = 0; i < 8; ++i)
if (mTeeth[i]->mHitPoints > 1)
return;
if (mSpine->getCurrentNerve() != &TNerveBossEelDie::theNerve()) {
mSpine->setNext(&TNerveBossEelDie::theNerve());
mHeadCollision->onHitFilter(HIT_FILTER_NO_COLLISION);
}
}
bool TBossEel::isValidToothDamage()
{
if (mSpine->getCurrentNerve() == &TNerveBossEelEat::theNerve())
return false;
return true;
}
// TODO: size is wrong but it feels very right
void TBossEel::quickBack()
{
s32 i;
TBossEelTooth** teeth = mTeeth;
for (i = 0; i < 8; ++i, ++teeth) {
TBossEelTooth* tooth = *teeth;
if (tooth && tooth->mHitPoints > 1) {
tooth->mHitPoints
= tooth->mOwner->mSaveParams->mSLToothMaxHitPoint.get();
tooth->mColor.a = 0xFF;
}
}
}
bool TBossEel::isInBossEelMoguDemo()
{
if (mMActor->checkCurBckFromIndex(12) || mMActor->checkCurBckFromIndex(3))
return true;
return false;
}
static s32 hoseiDiveCameraCallback(uintptr_t actorAddress, u32 state)
{
if (state == 1) {
const TLiveActor* actor
= reinterpret_cast<const TLiveActor*>(actorAddress);
JGeometry::TVec3<f32> position = actor->mPosition;
position.y += 12300.0f;
gpCamera->warpPosAndAt(position, SMS_GetMarioPos());
}
return 0;
}
void TBossEel::startMoguCamera()
{
if (!mMoguCameraActive) {
SMSGetMarDirector()->getConsole()->startAppearBalloon(0xE0015, true);
SMSGetMarDirector()->fireStartDemoCamera(
"meoto_mogu_camera", &mPosition, -1, 0.0f, false,
&hoseiDiveCameraCallback, reinterpret_cast<uintptr_t>(this),
nullptr, JDrama::TFlagT<u16>(0));
mMoguCameraActive = true;
}
}
const char** TBossEel::getBasNameTable() const { return bosseel_bastable; }
DEFINE_NERVE(TNerveBossEelWaitAppear, TLiveActor)
{
TBossEel* eel = static_cast<TBossEel*>(spine->getBody());
if (spine->getTime() == 0)
eel->setBckAnm(10);
if (spine->getTime() == 2500)
SMSGetMarDirector()->getConsole()->startAppearBalloon(0xE0012, true);
JGeometry::TVec3<f32> marioPosition = SMS_GetMarioPos();
marioPosition.y += 75.0f;
if (eel->mMouthCubeManager->isInCube(marioPosition, (s32)0)) {
spine->pushAfterCurrent(&TNerveBossEelFirstSpin::theNerve());
return true;
}
return false;
}
void ExecSpinNerve_Sub(TBossEel* eel)
{
f32 spinSpeed = eel->getTurnSpeed();
CLBChaseGeneralConstantSpecifySpeed(&spinSpeed,
eel->mSaveParams->mSLSpinMaxSpeed.get(),
eel->mSaveParams->mSLSpinAccel.get());
eel->setTurnSpeed(spinSpeed);
gpCameraShake->keepShake(static_cast<EnumCamShakeMode>(0x18), 1.0f);
if (eel->checkLiveFlag(TBossEel::LIVE_FLAG_UNK10000)) {
eel->mRotation.y -= spinSpeed;
if (eel->mRotation.y <= 0.0f)
SMSGetMSound()->startSoundActorWithInfo(
MSD_SE_BS_UNG_ROLL, &eel->mPosition, nullptr, spinSpeed, 0, 0,
nullptr, 0, 4);
} else {
eel->mRotation.y += spinSpeed;
if (eel->mRotation.y >= 360.0f)
SMSGetMSound()->startSoundActorWithInfo(
MSD_SE_BS_UNG_ROLL, &eel->mPosition, nullptr, spinSpeed, 0, 0,
nullptr, 0, 4);
}
eel->mRotation.y = MsWrap(eel->mRotation.y, 0.0f, 360.0f);
}
DEFINE_NERVE(TNerveBossEelFirstSpin, TLiveActor)
{
TBossEel* eel = static_cast<TBossEel*>(spine->getBody());
if (spine->getTime() == 0) {
eel->setTurnSpeed(0.0f);
SMSGetMSound()->startSoundActorWithInfo(MSD_SE_BS_UNG_ROLL,
&eel->mPosition, nullptr, 2.0f,
0, 0, nullptr, 0, 4);
eel->setBckAnm(10);
if (MsRandF() < 0.5f)
eel->onLiveFlag(TBossEel::LIVE_FLAG_UNK10000);
else
eel->offLiveFlag(TBossEel::LIVE_FLAG_UNK10000);
}
ExecSpinNerve_Sub(eel);
if (spine->getTime() >= 360) {
spine->pushAfterCurrent(&TNerveBossEelAppear::theNerve());
return true;
}
return false;
}
DEFINE_NERVE(TNerveBossEelSecondSpin, TLiveActor)
{
TBossEel* eel = static_cast<TBossEel*>(spine->getBody());
if (spine->getTime() == 0) {
eel->setBckAnm(10);
JGeometry::TVec2<s32>* spinTimer = eel->mSpinTimer;
spinTimer->x = 0;
spinTimer->y = static_cast<s32>(MsRandF() * 960.0f) + 241;
eel->setTurnSpeed(0.0f);
SMSGetMSound()->startSoundActorWithInfo(MSD_SE_BS_UNG_ROLL,
&eel->mPosition, nullptr, 2.0f,
0, 0, nullptr, 0, 4);
if (MsRandF() < 0.5f)
eel->onLiveFlag(TBossEel::LIVE_FLAG_UNK10000);
else
eel->offLiveFlag(TBossEel::LIVE_FLAG_UNK10000);
}
ExecSpinNerve_Sub(eel);
bool atLimit = false;
JGeometry::TVec2<s32>* spinTimer = eel->mSpinTimer;
++spinTimer->x;
if (spinTimer->x >= spinTimer->y) {
spinTimer->x = spinTimer->y;
atLimit = true;
}
if (atLimit) {
spine->pushAfterCurrent(&TNerveBossEelAppear::theNerve());
return true;
}
return false;
}
DEFINE_NERVE_INSTANCE(TNerveBossEelAppear)
static f32 testHeight;
DEFINE_NERVE_EXECUTE(TNerveBossEelAppear, TLiveActor)
{
TBossEel* eel = static_cast<TBossEel*>(spine->getBody());
if (spine->getTime() == 0) {
SMSGetMSound()->startSoundActor(MSD_SE_BS_UNG_UP, &eel->mPosition, 0,
nullptr, 0, 4);
eel->mBarrierCollision->offHitFilter(HIT_FILTER_NO_COLLISION);
eel->setBckAnm(15);
eel->mInDemo = true;
gpCameraShake->startShake(static_cast<EnumCamShakeMode>(0x19), 1.0f);
f32 duration
= eel->getMActor()->getFrameCtrl(ANM_TYPE_BCK)->getEnd() * 2;
eel->mAppearAcceleration
= (eel->mSaveParams->mSLAppearMoveDistY.get() / duration)
/ duration;
testHeight = 0.0f;
}
s32 duration = eel->getMActor()->getFrameCtrl(ANM_TYPE_BCK)->getEnd() * 2;
if (spine->getTime() < duration) {
eel->mAppearOffset
+= eel->mSaveParams->mSLAppearMoveDistY.get() / duration;
f32 sp = eel->getTurnSpeed();
sp *= 0.98f;
eel->setTurnSpeed(sp);
if (eel->checkLiveFlag(TBossEel::LIVE_FLAG_UNK10000))
eel->mRotation.y -= sp;
else
eel->mRotation.y += sp;
eel->mRotation.y = MsWrap(eel->mRotation.y, 0.0f, 360.0f);
} else if (eel->checkCurAnmEnd(0)) {
spine->pushAfterCurrent(&TNerveBossEelOutWait::theNerve());
eel->mBarrierCollision->onHitFilter(HIT_FILTER_NO_COLLISION);
if (eel->mCollisionEnabled) {
eel->mCollisionEnabled = false;
SMSGetMarDirector()->getConsole()->startAppearBalloon(0xE0013,
true);
}
return true;
}
return false;
}
DEFINE_NERVE(TNerveBossEelOutWait, TLiveActor)
{
TBossEel* eel = static_cast<TBossEel*>(spine->getBody());
++eel->mBattleTimer;
if (spine->getTime() == 0) {
eel->mToothDamaged = false;
eel->setBckAnm(16);
}
if (eel->checkCurAnmEnd(0)) {
s32 r28 = eel->mSaveParams->mSLMouthOpenInterval.get();
if (eel->getMActor()->checkCurBckFromIndex(19)) {
spine->setNext(&TNerveBossEelQuickBack::theNerve());
} else {
if (eel->mBattleTimer >= 3600) {
spine->pushAfterCurrent(&TNerveBossEelSlowBack::theNerve());
eel->mBattleTimer = 0;
return true;
}
if (spine->getTime() > r28) {
spine->pushAfterCurrent(&TNerveBossEelOutWait::theNerve());
spine->pushAfterCurrent(
&TNerveBossEelMouthOpenWait::theNerve());
return true;
}
if (eel->mToothBroken) {
eel->setBckAnm(19);
} else if (eel->mToothDamaged) {
eel->mToothDamaged = false;
eel->setBckAnm(18);
} else {
eel->setBckAnm(16);
}
}
}
return false;
}
static BOOL ExecBackNerve_Sub(TSpineBase<TLiveActor>* spine, f32 speed)
{
TBossEel* eel = static_cast<TBossEel*>(spine->getBody());
if (spine->getTime() == 1) {
SMSGetMSound()->startSoundActor(MSD_SE_BS_UNG_DOWN, &eel->mPosition, 0,
nullptr, 0, 4);
if (eel->mToothBroken) {
eel->mToothBroken = false;
eel->setBckAnm(6);
gpCameraShake->startShake(static_cast<EnumCamShakeMode>(0x1A),
1.0f);
} else {
eel->setBckAnm(9);
}
}
eel->mAppearOffset
-= eel->mSaveParams->mSLAppearMoveDistY.get()
/ (eel->getMActor()->getFrameCtrl(ANM_TYPE_BCK)->getEnd() * 2);
if (eel->mAppearOffset < 0.0f) {
eel->mAppearOffset = 0.0f;
if (eel->checkCurAnmEnd(0)) {
eel->mInDemo = false;
spine->pushAfterCurrent(&TNerveBossEelSecondSpin::theNerve());
if (eel->getMActor()->checkCurBckFromIndex(6))
spine->pushAfterCurrent(
&TNerveBossEelSleepOnBottom::theNerve());
return true;
}
}
return false;
}
DEFINE_NERVE(TNerveBossEelSlowBack, TLiveActor)
{
return ExecBackNerve_Sub(spine, 10.0f);
}
DEFINE_NERVE(TNerveBossEelQuickBack, TLiveActor)
{
if (ExecBackNerve_Sub(spine, 40.0f)) {
TBossEel* eel = static_cast<TBossEel*>(spine->getBody());
eel->quickBack();
return true;
}
return false;
}
DEFINE_NERVE(TNerveBossEelEat, TLiveActor)
{
TBossEel* eel = static_cast<TBossEel*>(spine->getBody());
if (spine->getTime() == 0)
eel->setBckAnm(17);
if (eel->checkCurAnmEnd(0)) {
if (eel->getMActor()->checkCurBckFromIndex(17)) {
if (eel->canEatMario()) {
eel->setBckAnm(12);
if (SMS_SendMessageToMario(eel, HIT_MESSAGE_TAKE)) {
eel->mHeldObject
= reinterpret_cast<TTakeActor*>(SMS_GetMarioHitActor());
eel->startMoguCamera();
}
} else {
eel->setBckAnm(5);
MtxPtr breathMtx = eel->getMActor()->getModel()->getAnmMtx(5);
eel->mBreathParticlePosition.set(
breathMtx[0][3], breathMtx[1][3], breathMtx[2][3]);
JPABaseEmitter* emitter
= gpMarioParticleManager->emitAndBindToPosPtr(
BOSSEEL_JPA_MS_MEO_AWA_MOUTH,
&eel->mBreathParticlePosition, 0, nullptr);
if (emitter)
emitter->setGlobalScale(eel->mScaling);
}
} else {
if (eel->getMActor()->checkCurBckFromIndex(12)) {
if (SMS_SendMessageToMario(eel, HIT_MESSAGE_DETACH)) {
eel->mHeldObject = nullptr;
SMS_SendMessageToMario(eel, HIT_MESSAGE_ATTACK);
SMSGetMarDirector()->fireEndDemoCamera();
eel->mMoguCameraActive = false;
}
spine->reset();
spine->setDefaultNext();
spine->pushAfterCurrent(&TNerveBossEelQuickBack::theNerve());
}
return true;
}
}
if (eel->getMActor()->checkCurBckFromIndex(12)) {
if (eel->getMActor()->getFrameCtrl(ANM_TYPE_BCK)->getFrame() < 250.0f)
SMSRumbleMgr->start(8, &eel->mPosition);
else
SMSRumbleMgr->start(20, 10, static_cast<f32*>(nullptr));
gpMarioOriginal->mGamePad->onNeutralMarioKey();
if (SMS_SendMessageToMario(eel, HIT_MESSAGE_TAKE)) {
eel->mHeldObject
= reinterpret_cast<TTakeActor*>(SMS_GetMarioHitActor());
eel->startMoguCamera();
}
}
return false;
}
DEFINE_NERVE(TNerveBossEelDie, TLiveActor)
{
TBossEel* eel = static_cast<TBossEel*>(spine->getBody());
if (spine->getTime() == 0) {
SMSGetMSound()->startSoundActor(MSD_SE_BS_UNG_VOICE_LAST,
&eel->mPosition, 0, nullptr, 0, 4);
SMSGetMarDirector()->getConsole()->startAppearBalloon(0xE0014, true);
MSBgm::stopTrackBGMs(7, 10);
gpCameraShake->startShake(CAM_SHAKE_MODE_UNK1E, 1.0f);
eel->setBckAnm(3);
eel->invalidateAllCollision();
eel->mHeartCoin->generate(eel->mPosition);
if (SMS_SendMessageToMario(eel, HIT_MESSAGE_TAKE)) {
eel->mHeldObject
= reinterpret_cast<TTakeActor*>(SMS_GetMarioHitActor());
SMSGetMarDirector()->fireStartDemoCamera(
"meoto_end_camera", &eel->mPosition, -1, 0.0f, false, nullptr,
0, nullptr, JDrama::TFlagT<u16>(0));
}
}
if (eel->getMActor()->checkCurBckFromIndex(3)) {
if (eel->getMActor()->getFrameCtrl(ANM_TYPE_BCK)->checkPass(650.0f))
eel->mHeartCoin->getMActor()->setBckFromIndex(8);
if (eel->checkCurAnmEnd(0)) {
if (SMS_SendMessageToMario(eel, HIT_MESSAGE_DETACH)) {
eel->mHeldObject = nullptr;
SMS_SendMessageToMario(eel, HIT_MESSAGE_ATTACK);
SMSGetMarDirector()->fireEndDemoCamera();
}
JGeometry::TVec3<f32> marioPosition = SMS_GetMarioPos();
eel->generateBubble(marioPosition);
s32 jointIndex = eel->getMActor()
->getModel()
->getModelData()
->getJointName()
->getIndex("ha7");
MtxPtr shineMtx
= eel->getMActor()->getModel()->getAnmMtx(jointIndex);
gpItemManager->makeShineAppearWithDemo(
"シャイン(ボス用)", "めおとウナギシャインカメラ",
shineMtx[0][3], shineMtx[1][3], shineMtx[2][3]);
eel->mTeeth[6]->mHitPoints = 0;
eel->mTeeth[6]->onHitFilter(HIT_FILTER_NO_COLLISION);
eel->setBckAnm(4);
}
}
return false;
}
DEFINE_NERVE(TNerveBossEelMouthOpenWait, TLiveActor)
{
TBossEel* eel = static_cast<TBossEel*>(spine->getBody());
if (spine->getTime() == 0) {
if (eel->mToothBroken)
eel->mToothBroken = false;
eel->setBckAnm(13);
gpCameraShake->startShake(CAM_SHAKE_MODE_UNK1B, 1.0f);
} else if (eel->checkCurAnmEnd(0)) {
if (eel->getMActor()->checkCurBckFromIndex(13)) {
eel->setBckAnm(14);
gpCameraShake->startShake(CAM_SHAKE_MODE_UNK1C, 1.0f);
eel->generateVortex();
} else {
s32 openFrames = eel->mSaveParams->mSLMouthOpenFrame.get();
if (spine->getTime()
> openFrames - eel->mSaveParams->mSLCanEatFrame.get()) {
if (eel->canEatMario()) {
spine->pushAfterCurrent(&TNerveBossEelEat::theNerve());
return true;
}
}
if (spine->getTime() > openFrames) {
if (eel->getMActor()->checkCurBckFromIndex(2))
return true;
gpCameraShake->startShake(CAM_SHAKE_MODE_UNK1D, 1.0f);
eel->setBckAnm(2);
}
}
}
if (eel->getMActor()->checkCurBckFromIndex(14))
eel->mRotation.y += TBossEel::mOpenRollSpeed;
return false;
}
DEFINE_NERVE(TNerveBossEelSleepOnBottom, TLiveActor)
{
TBossEel* eel = static_cast<TBossEel*>(spine->getBody());
if (spine->getTime() == 0) {
eel->mBattleTimer = 0;
eel->setBckAnm(10);
}
if (spine->getTime() % 100 == 1)
eel->forceShedTears(spine->getTime() % 2);
if (spine->getTime() > 1000 && eel->checkCurAnmEnd(0))
return true;
return false;
}