mirror of
https://github.com/doldecomp/sms.git
synced 2026-11-07 09:06:00 -10:00
404 lines
11 KiB
C++
404 lines
11 KiB
C++
#include <Enemy/Conductor.hpp>
|
|
#include <Enemy/Enemy.hpp>
|
|
#include <Enemy/EnemyManager.hpp>
|
|
#include <Enemy/Graph.hpp>
|
|
#include <Enemy/Rocket.hpp>
|
|
#include <Enemy/SmallEnemy.hpp>
|
|
#include <Enemy/Walker.hpp>
|
|
#include <JSystem/JDrama/JDRActor.hpp>
|
|
#include <JSystem/JDrama/JDRNameRef.hpp>
|
|
#include <JSystem/JGeometry/JGRotation3.hpp>
|
|
#include <JSystem/JStage/JSGActor.hpp>
|
|
#include <JSystem/JStage/JSGObject.hpp>
|
|
#include <JSystem/JSupport/JSUList.hpp>
|
|
#include <M3DUtil/MActor.hpp>
|
|
#include <MSound/MSSetSound.hpp>
|
|
#include <MSound/MSound.hpp>
|
|
#include <MSound/MSoundBGM.hpp>
|
|
#include <MSound/MSoundSE.hpp>
|
|
#include <MSound/SoundEffects.hpp>
|
|
#include <Map/Map.hpp>
|
|
#include <Map/MapCollisionData.hpp>
|
|
#include <MarioUtil/RumbleMgr.hpp>
|
|
#include <Player/MarioAccess.hpp>
|
|
#include <Player/ModelWaterManager.hpp>
|
|
#include <Player/WaterGun.hpp>
|
|
#include <Strategic/LiveActor.hpp>
|
|
#include <Strategic/LiveManager.hpp>
|
|
#include <Strategic/Nerve.hpp>
|
|
#include <Strategic/ObjManager.hpp>
|
|
#include <Strategic/ObjModel.hpp>
|
|
#include <Strategic/TakeActor.hpp>
|
|
#include <System/BaseParam.hpp>
|
|
#include <System/EmitterViewObj.hpp>
|
|
#include <System/MarDirector.hpp>
|
|
#include <System/MarioGamePad.hpp>
|
|
#include <System/ParamInst.hpp>
|
|
#include <System/Params.hpp>
|
|
#include <System/Particles.hpp>
|
|
|
|
TRocketSaveLoadParams::TRocketSaveLoadParams(const char* param_1)
|
|
: TSmallEnemyParams(param_1)
|
|
, PARAM_INIT(mSLReleaseSpeed, 10.0f)
|
|
, PARAM_INIT(mSLFlyGravity, 0.0f)
|
|
, PARAM_INIT(mSLFlyLimitTime, 300)
|
|
{
|
|
TParams::load(mPrmPath);
|
|
}
|
|
|
|
static const char* rocket_bastable[] = {
|
|
nullptr,
|
|
nullptr,
|
|
nullptr,
|
|
nullptr,
|
|
};
|
|
|
|
f32 TRocket::mTestAng_x = 0.0f;
|
|
f32 TRocket::mTestAng_y = 90.0f;
|
|
f32 TRocket::mTestAng_z = 0.0f;
|
|
f32 TRocket::mNozzleOffsetZ = 25.0f;
|
|
f32 TRocket::mColOffsetY = 20.0f;
|
|
|
|
TRocketManager::TRocketManager(const char* param_1)
|
|
: TSmallEnemyManager(param_1)
|
|
, unk60(1)
|
|
, unk64(0)
|
|
, unk68(nullptr)
|
|
{
|
|
}
|
|
|
|
void TRocketManager::load(JSUMemoryInputStream& param_1)
|
|
{
|
|
TSmallEnemyManager::load(param_1);
|
|
unk38 = new TRocketSaveLoadParams("/enemy/rocket.prm");
|
|
unk68 = new TWaterEmitInfo("/enemy/rocketexpwater.prm");
|
|
}
|
|
|
|
void TRocketManager::loadAfter() { JDrama::TNameRef::loadAfter(); }
|
|
|
|
TSpineEnemy* TRocketManager::createEnemyInstance() { return new TRocket; }
|
|
|
|
void TRocketManager::initSetEnemies()
|
|
{
|
|
for (int i = 0; i < mObjNum; ++i) {
|
|
TGraphWeb* graph = gpConductor->getGraphByName("main");
|
|
TRocket* rocket = (TRocket*)getObj(i);
|
|
if (rocket->checkLiveFlag(LIVE_FLAG_DEAD) && !graph->isDummy()) {
|
|
JGeometry::TVec3<f32> position;
|
|
graph->getGraphNode(TMsRange<s32>(0, graph->getNodeNum()).rand())
|
|
.getPoint(&position);
|
|
rocket->mPosition = position;
|
|
rocket->mPosition.y += 5.0f;
|
|
rocket->onLiveFlag(LIVE_FLAG_AIRBORNE);
|
|
rocket->reset();
|
|
}
|
|
}
|
|
}
|
|
|
|
void TRocketManager::createModelData()
|
|
{
|
|
static TModelDataLoadEntry entry[] = {
|
|
{ "rocket.bmd", J3DMLF_MaterialPEFull | (4 << J3DMLF_TevStageNumShift),
|
|
0 },
|
|
{ nullptr, 0, 0 },
|
|
};
|
|
createModelDataArray(entry);
|
|
}
|
|
|
|
void TRocketManager::perform(u32 cue, JDrama::TGraphics* param_2)
|
|
{
|
|
if (cue & CUE_MOVE) {
|
|
for (int i = 0; i < getActiveObjNum(); ++i) {
|
|
TRocket* rocket = (TRocket*)getObj(i);
|
|
if (rocket->checkLiveFlag(LIVE_FLAG_DEAD))
|
|
rocket->reset();
|
|
}
|
|
}
|
|
TSmallEnemyManager::perform(cue, param_2);
|
|
}
|
|
|
|
TRocket::TRocket(const char* param_1)
|
|
: TSmallEnemy(param_1)
|
|
, unk1A0(0)
|
|
, unk1A1(0)
|
|
{
|
|
}
|
|
|
|
void TRocket::load(JSUMemoryInputStream& param_1)
|
|
{
|
|
TSmallEnemy::load(param_1);
|
|
unk194 = mPosition;
|
|
unk1A1 = 1;
|
|
reset();
|
|
}
|
|
|
|
void TRocket::init(TLiveManager* param_1)
|
|
{
|
|
TSmallEnemy::init(param_1);
|
|
mActorType = ACTOR_TYPE_ROCKET;
|
|
unk150 = 0x11;
|
|
unk1A4 = (TRocketSaveLoadParams*)getSaveParam();
|
|
mSpine->initWith(&TNerveRocketWait::theNerve());
|
|
onHitFilter(HIT_CATEGORY_BOSS);
|
|
}
|
|
|
|
void TRocket::calcRootMatrix()
|
|
{
|
|
if (unk1A0) {
|
|
getModel()->setBaseScale(mScaling);
|
|
TPosition3f matrix;
|
|
if (mSpine->getCurrentNerve() == &TNerveRocketFly::theNerve()) {
|
|
matrix.translation(mPosition.x, mPosition.y, mPosition.z);
|
|
} else {
|
|
MTXCopy(SMS_GetMarioWaterGun()->getEmitMtx(0), matrix);
|
|
JGeometry::TVec3<f32> axes[3];
|
|
axes[0].x = matrix.at(0, 0);
|
|
axes[0].y = matrix.at(1, 0);
|
|
axes[0].z = matrix.at(2, 0);
|
|
f32 xLength = axes[0].length();
|
|
axes[1].x = matrix.at(0, 1);
|
|
axes[1].y = matrix.at(1, 1);
|
|
axes[1].z = matrix.at(2, 1);
|
|
f32 yLength = axes[1].length();
|
|
axes[2].x = matrix.at(0, 2);
|
|
axes[2].y = matrix.at(1, 2);
|
|
axes[2].z = matrix.at(2, 2);
|
|
f32 zLength = axes[2].length();
|
|
if (zLength != 0.0f) {
|
|
matrix.ref(0, 0) /= xLength;
|
|
matrix.ref(1, 0) /= xLength;
|
|
matrix.ref(2, 0) /= xLength;
|
|
}
|
|
if (xLength != 0.0f) {
|
|
matrix.ref(0, 1) /= yLength;
|
|
matrix.ref(1, 1) /= yLength;
|
|
matrix.ref(2, 1) /= yLength;
|
|
}
|
|
if (yLength != 0.0f) {
|
|
matrix.ref(0, 2) /= zLength;
|
|
matrix.ref(1, 2) /= zLength;
|
|
matrix.ref(2, 2) /= zLength;
|
|
}
|
|
TPosition3f offset;
|
|
offset.translation(mNozzleOffsetZ, 0.0f, 0.0f);
|
|
MTXConcat(matrix, offset, matrix);
|
|
mPosition.x = matrix.at(0, 3);
|
|
mPosition.y = matrix.at(1, 3) - mColOffsetY;
|
|
mPosition.z = matrix.at(2, 3);
|
|
}
|
|
Mtx rotation;
|
|
MsMtxSetRotRPH(rotation, mTestAng_x, mTestAng_y, mTestAng_z);
|
|
MTXConcat(matrix, rotation, matrix);
|
|
getModel()->setBaseTRMtx(matrix);
|
|
} else {
|
|
TSpineEnemy::calcRootMatrix();
|
|
}
|
|
if (isBckAnm(1))
|
|
SMSGetMSound()->startSoundActor(MSD_SE_PO_PETBOTTLE_FLY, &mPosition, 0,
|
|
nullptr, 0, 4);
|
|
}
|
|
|
|
void TRocket::setMActorAndKeeper()
|
|
{
|
|
mMActorKeeper = new TMActorKeeper(mManager, 1);
|
|
mMActor = mMActorKeeper->createMActor("rocket.bmd", 3);
|
|
}
|
|
|
|
void TRocket::reset()
|
|
{
|
|
unk1A0 = 0;
|
|
TSmallEnemy::reset();
|
|
if (unk1A1)
|
|
mPosition = unk194;
|
|
onLiveFlag(LIVE_FLAG_NO_BIND);
|
|
offLiveFlag(LIVE_FLAG_RECYCLABLE);
|
|
onLiveFlag(LIVE_FLAG_NO_SHADOW);
|
|
mSpine->initWith(&TNerveRocketWait::theNerve());
|
|
}
|
|
|
|
void TRocket::attackToMario()
|
|
{
|
|
if (mSpine->getCurrentNerve() == &TNerveRocketWait::theNerve()
|
|
&& ((TRocketManager*)mManager)->unk60)
|
|
mSpine->pushNerve(&TNerveRocketPossessedNozzle::theNerve());
|
|
}
|
|
|
|
void TRocket::behaveToWater(THitActor* param_1) { attackToMario(); }
|
|
|
|
void TRocket::bind()
|
|
{
|
|
if (checkLiveFlag(LIVE_FLAG_NO_BIND))
|
|
return;
|
|
if (mSpine->getCurrentNerve() == &TNerveRocketPossessedNozzle::theNerve()
|
|
|| mSpine->getCurrentNerve() == &TNerveRocketFly::theNerve()) {
|
|
TBGWallCheckRecord record(mPosition.x, mPosition.y, mPosition.z,
|
|
getWallRadius(), 1, 0);
|
|
if (gpMap->isTouchedWallsAndMoveXZ(&record)) {
|
|
const TLiveActor* actor = record.mResultWalls[0]->getActor();
|
|
if (actor)
|
|
((TLiveActor*)actor)->receiveMessage(this, HIT_MESSAGE_ATTACK);
|
|
kill();
|
|
return;
|
|
}
|
|
if (mSpine->getCurrentNerve() == &TNerveRocketFly::theNerve()) {
|
|
TLiveActor::bind();
|
|
if (!isAirborne()) {
|
|
const TLiveActor* actor = getGroundPlane()->getActor();
|
|
if (actor)
|
|
((TLiveActor*)actor)
|
|
->receiveMessage(this, HIT_MESSAGE_ATTACK);
|
|
kill();
|
|
}
|
|
}
|
|
} else {
|
|
TLiveActor::bind();
|
|
}
|
|
}
|
|
|
|
void TRocket::setDeadAnm()
|
|
{
|
|
TRocketManager* manager = (TRocketManager*)mManager;
|
|
manager->unk68->mPos.value = mPosition;
|
|
gpModelWaterManager->emitRequest(*manager->unk68);
|
|
if (unk1A0)
|
|
releaseNozzle();
|
|
onLiveFlag(TSmallEnemy::LIVE_FLAG_NO_ITEM_DROPS);
|
|
gpMarioParticleManager->emitAndBindToMtxPtr(
|
|
PARTICLE_MS_PETBTL_BOMB_A, mMActor->getModel()->getBaseTRMtx(), 0,
|
|
nullptr);
|
|
gpMarioParticleManager->emitAndBindToMtxPtr(
|
|
PARTICLE_MS_PETBTL_BOMB_B, mMActor->getModel()->getBaseTRMtx(), 0,
|
|
nullptr);
|
|
}
|
|
|
|
f32 TRocket::getGravityY() const
|
|
{
|
|
f32 gravity = mGravity;
|
|
if (mSpine->getCurrentNerve() == &TNerveRocketFly::theNerve())
|
|
gravity = unk1A4->mSLFlyGravity.get();
|
|
return gravity;
|
|
}
|
|
|
|
bool TRocket::isCollidMove(THitActor* param_1)
|
|
{
|
|
if (mSpine->getCurrentNerve() == &TNerveRocketFly::theNerve()
|
|
&& param_1->receiveMessage(this, HIT_MESSAGE_TRAMPLE))
|
|
kill();
|
|
return false;
|
|
}
|
|
|
|
void TRocket::possessedNozzle()
|
|
{
|
|
((TRocketManager*)mManager)->unk60 = 0;
|
|
offLiveFlag(LIVE_FLAG_NO_BIND);
|
|
unk1A0 = 1;
|
|
}
|
|
|
|
void TRocket::releaseNozzle()
|
|
{
|
|
((TRocketManager*)mManager)->unk60 = 1;
|
|
unk1A0 = 0;
|
|
}
|
|
|
|
bool TRocket::checkTrigger()
|
|
{
|
|
SMS_SendMessageToMario(this, HIT_MESSAGE_ATTACH);
|
|
if ((u8)SMSGetMarDirector()->getGamePad()->mCompSPos[3] > 20
|
|
&& getHitPoints() > 1)
|
|
--mHitPoints;
|
|
if (!isBckAnm(2)) {
|
|
SMSGetMSound()->startSoundSystemSE(MSD_SE_SY_PO_WATER_FULL, 0, nullptr,
|
|
0);
|
|
setBckAnm(2);
|
|
}
|
|
if (SMSGetMarDirector()->getGamePad()->mEnabledFrameMeaning
|
|
& TMarioGamePad::MEANING_R) {
|
|
unk190 = 2.0f;
|
|
expandCollision();
|
|
SMSGetMSound()->startSoundActor(MSD_SE_PO_PETBOTTLE_FLY, &mPosition, 0,
|
|
nullptr, 0, 4);
|
|
SMSRumbleMgr->start(0x15, 5, (f32*)nullptr);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void TRocket::flyBehavior()
|
|
{
|
|
gpMarioParticleManager->emitAndBindToPosPtr(PARTICLE_MS_PETBTL_SMOKE,
|
|
&mPosition, 1, this);
|
|
if (mSpine->getTime() > unk1A4->mSLFlyLimitTime.get())
|
|
kill();
|
|
if (!checkLiveFlag(LIVE_FLAG_CLIPPED_OUT))
|
|
getModel();
|
|
}
|
|
|
|
bool TRocket::isAttack()
|
|
{
|
|
if (mSpine->getCurrentNerve() == &TNerveRocketFly::theNerve())
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
const char** TRocket::getBasNameTable() const { return rocket_bastable; }
|
|
|
|
DEFINE_NERVE(TNerveRocketPossessedNozzle, TLiveActor)
|
|
{
|
|
TRocket* self = (TRocket*)spine->getBody();
|
|
if (spine->getTime() == 0) {
|
|
SMSRumbleMgr->start(0x15, 10, (f32*)nullptr);
|
|
SMSGetMSound()->startSoundActor(MSD_SE_MA_GET_ITEM, &self->mPosition, 0,
|
|
nullptr, 0, 4);
|
|
SMSGetMSound()->startSoundActor(MSD_SE_PO_GET_PETBOTTLE,
|
|
&self->mPosition, 0, nullptr, 0, 4);
|
|
self->possessedNozzle();
|
|
self->setBckAnm(0);
|
|
}
|
|
if (self->checkTrigger()) {
|
|
spine->pushAfterCurrent(&TNerveRocketFly::theNerve());
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
DEFINE_NERVE(TNerveRocketFly, TLiveActor)
|
|
{
|
|
TRocket* self = (TRocket*)spine->getBody();
|
|
|
|
if (spine->getTime() == 0) {
|
|
self->setBckAnm(1);
|
|
|
|
MtxPtr emitMtx = SMS_GetMarioWaterGun()->getEmitMtx(0);
|
|
f32 speed = self->unk1A4->mSLReleaseSpeed.get();
|
|
JGeometry::TVec3<f32> velocity;
|
|
velocity.x = speed * emitMtx[0][0];
|
|
velocity.y = speed * emitMtx[1][0];
|
|
velocity.z = speed * emitMtx[2][0];
|
|
self->mVelocity = velocity;
|
|
self->onLiveFlag(LIVE_FLAG_AIRBORNE);
|
|
self->releaseNozzle();
|
|
|
|
f32 angle = MsGetRotFromZaxisY(velocity);
|
|
self->mRotation.set(0.0f, MsAngleWrap(angle), 0.0f);
|
|
self->offHitFilter(HIT_FILTER_NO_COLLISION);
|
|
}
|
|
|
|
if (!self->isBckAnm(1))
|
|
self->setBckAnm(1);
|
|
|
|
self->mRotation.x = MsGetRotFromZaxis(self->getVelocity()).x;
|
|
self->flyBehavior();
|
|
|
|
return false;
|
|
}
|
|
|
|
DEFINE_NERVE(TNerveRocketWait, TLiveActor)
|
|
{
|
|
TRocket* self = (TRocket*)spine->getBody();
|
|
if (spine->getTime() == 0) {
|
|
self->onLiveFlag(LIVE_FLAG_NO_BIND);
|
|
self->setBckAnm(3);
|
|
}
|
|
return false;
|
|
}
|