Files
ss/src/d/a/obj/d_a_obj_bomb.cpp
T
2026-09-29 13:54:30 -04:00

1258 lines
40 KiB
C++

#include "d/a/obj/d_a_obj_bomb.h"
#include "c/c_lib.h"
#include "c/c_math.h"
#include "common.h"
#include "d/a/d_a_base.h"
#include "d/a/d_a_player.h"
#include "d/a/e/d_a_en_base.h"
#include "d/a/obj/d_a_obj_base.h"
#include "d/col/bg/d_bg_pc.h"
#include "d/col/bg/d_bg_s.h"
#include "d/col/bg/d_bg_s_gnd_chk.h"
#include "d/col/c/c_cc_d.h"
#include "d/col/c/c_m3d.h"
#include "d/col/c/c_m3d_g_pla.h"
#include "d/col/cc/d_cc_s.h"
#include "d/d_light_env.h"
#include "d/d_linkage.h"
#include "d/d_rumble.h"
#include "d/d_sc_game.h"
#include "d/d_stage_mgr.h"
#include "d/d_vec.h"
#include "d/snd/d_snd_wzsound.h"
#include "d/t/d_t_stream.h"
#include "f/f_base.h"
#include "f/f_profile.h"
#include "f/f_profile_name.h"
#include "m/m3d/m3d.h"
#include "m/m_angle.h"
#include "m/m_color.h"
#include "m/m_mtx.h"
#include "m/m_vec.h"
#include "nw4r/g3d/res/g3d_resfile.h"
#include "nw4r/g3d/res/g3d_resmdl.h"
#include "nw4r/math/math_arithmetic.h"
#include "nw4r/math/math_types.h"
#include "rvl/GX/GXTypes.h"
#include "rvl/MTX/mtx.h"
#include "s/s_Math.h"
#include "s/s_State.hpp"
#include "toBeSorted/attention.h"
#include "toBeSorted/d_emitter.h"
#include "toBeSorted/event_manager.h"
#include "toBeSorted/minigame_mgr.h"
SPECIAL_ACTOR_PROFILE(BOMB, dAcBomb_c, fProfile::BOMB, 0x128, 0, 2);
static const Vec sSmokeOffset = {0, 60, 0};
struct dAcBomc_HIO_c {
static const f32 getBBoxX() {
return 36.0f;
}
static const f32 getBBoxY() {
return 66.0f;
}
static const f32 getBBoxZ() {
return 5.0f;
}
static const f32 getBombScale() {
return 30.0f;
}
static const s32 getSomething() {
return 40;
}
static const mVec3_c getBBoxMin() {
return mVec3_c(-bbox_x, 0.0f, -bbox_x);
}
static const mVec3_c getBBoxMax() {
return mVec3_c(bbox_x, bbox_y, bbox_x);
}
static const f32 bbox_x, bbox_y, bbox_z;
};
static dAcBomc_HIO_c sHIO = {};
const f32 dAcBomc_HIO_c::bbox_x = sHIO.getBBoxX();
const f32 dAcBomc_HIO_c::bbox_y = sHIO.getBBoxY();
const f32 dAcBomc_HIO_c::bbox_z = sHIO.getBBoxZ();
STATE_DEFINE(dAcBomb_c, Wait);
STATE_DEFINE(dAcBomb_c, FlowerWait);
STATE_DEFINE(dAcBomb_c, Explode);
STATE_DEFINE(dAcBomb_c, Carry);
STATE_DEFINE(dAcBomb_c, WindCarry);
dCcD_SrcSph sSphSrc = {
/* mObjInf */
{/* mObjAt */ {AT_TYPE_BOMB, 0x1803E, {0, 0, 0}, sHIO.getSomething(), 0, 0, 0, 0, 0},
/* mObjTg */
{~(AT_TYPE_BUGNET | AT_TYPE_GLITTERING_SPORES | AT_TYPE_0x8000 | AT_TYPE_0x10), 0x800111, {0, 0x0A, 0x40F}, 0, 0},
/* mObjCo */ {0xE9}},
/* mSphInf */
{sHIO.getBombScale()}
};
void dAcBomb_c::coHitCallback(cCcD_Obj *i_objInfB) {
if (!i_objInfB->ChkCo_0x8000()) {
return;
}
setFlag(dAcBomb_c::FLAG_BOMB_HIT);
setActorProperty(AC_PROP_0x4);
}
bool dAcBomb_coHitCallback(dAcObjBase_c *i_actorA, cCcD_Obj *i_objInfA, dAcObjBase_c *i_actorB, cCcD_Obj *i_objInfB) {
static_cast<dAcBomb_c *>(i_actorA)->coHitCallback(i_objInfB);
return true;
}
void dAcBomb_c::tgHitCallback(dAcObjBase_c *i_actorB, cCcD_Obj *i_objInfA, cCcD_Obj *i_objInfB) {
// Check if it is being blown
if ((i_objInfB->ChkAtType(AT_TYPE_WIND | AT_TYPE_BELLOWS) && i_objInfB->GetAtSrcModifier() == AT_MOD_WIND) &&
!(i_actorB &&
(i_actorB->mProfileName == fProfile::OBJ_WIND || i_actorB->mProfileName == fProfile::OBJ_TORNADO))) {
if (!getLinkage().checkState(dLinkage_c::STATE_ACTIVE) && !checkFlag(dAcBomb_c::FLAG_BOMB_HIT)) {
if (!(isState(StateID_FlowerWait) || isState(StateID_Explode))) {
cLib::addCalcPosXZ(&mHitForce, i_objInfA->GetTgAtHitDir() * 0.5f, 0.5f, 10.0f, 1.0f);
setFlag(dAcBomb_c::FLAG_0x8000);
}
}
} else if (!i_objInfB->ChkAtType(AT_TYPE_0x40 | AT_TYPE_WIND | AT_TYPE_WHIP | AT_TYPE_BEETLE) ||
i_objInfB->ChkAt_0x4000()) {
if (i_objInfB->ChkAtType(AT_TYPE_0x20000)) {
if (isState(StateID_FlowerWait)) {
changeState(StateID_Wait);
dAcPy_c::insertOwnedObject(this);
}
const dAcPy_c *pPlayer = dAcPy_c::GetLink2();
mVec3_c target;
setXYZCirclePoint(target, pPlayer->mRotation.y, 30.0f, 0.0f);
rollTo(target);
} else if (i_objInfB->ChkAtType(
AT_TYPE_SWORD | AT_TYPE_0x40 | AT_TYPE_SLINGSHOT | AT_TYPE_0x20000 | AT_TYPE_BEETLE
) &&
checkFlag(dAcBomb_c::FLAG_FLOWER | dAcBomb_c::FLAG_0x400000)) {
unsetFlag(dAcBomb_c::FLAG_FLOWER);
setFlag(dAcBomb_c::FLAG_0x400000);
unsetActorProperty(AC_PROP_0x1);
if (isState(StateID_FlowerWait)) {
dAcPy_c::insertOwnedObject(this);
}
if (!checkFlag(dAcBomb_c::FLAG_0x100) && i_objInfB->ChkAtType(AT_TYPE_SWORD)) {
setFlag(dAcBomb_c::FLAG_0x100);
}
} else {
setFlag(dAcBomb_c::FLAG_BOMB_HIT);
setActorProperty(AC_PROP_0x4);
if (i_objInfB->ChkAtType(AT_TYPE_BOMB)) {
setFlag(dAcBomb_c::FLAG_CHAIN_BOMB);
}
}
}
}
bool dAcBomb_tgHitCallback(dAcObjBase_c *i_actorA, cCcD_Obj *i_objInfA, dAcObjBase_c *i_actorB, cCcD_Obj *i_objInfB) {
static_cast<dAcBomb_c *>(i_actorA)->tgHitCallback(i_actorB, i_objInfA, i_objInfB);
return true;
}
bool dAcBomb_c::createHeap() {
mRes = nw4r::g3d::ResFile(getOarcResFile("Alink"));
nw4r::g3d::ResMdl mdl = mRes.GetResMdl("EquipBomb");
bool result = mMdl.create(mdl, &mAllocator, 0x120);
if (!result) {
return false;
}
mMainMatID = m3d::getMatID(mdl, "m_Main");
if (getBombType() == BOMBF_CRAWLSPACE) {
mMdl.setPriorityDraw(0x82, 0x7F);
}
return result;
}
int dAcBomb_c::create() {
CREATE_ALLOCATOR(dAcBomb_c);
mAcch.Set(this, 1, &mAcchCir);
mAcch.SetRoofCrrHeight(60.0f);
mAcch.SetGndChkOffset(60.0f);
mAcch.GetRoof().SetField_0x7C(1);
mAcch.SetWaterCheckOffset(10000.0f);
mAcch.SetWtrChkMode(2);
mAcch.ClrWaterNone();
mAcch.ClrRoofNone();
mAcch.OnLineCheck();
mAcchCir.SetWall(30.0f, 30.0f);
if (getBombType() == BOMBF_CRAWLSPACE) {
mStts.SetRank(4);
} else {
mStts.SetRank(5);
}
mSph.Set(sSphSrc);
mSph.SetStts(mStts);
mSph.SetTgCallback(dAcBomb_tgHitCallback);
mSph.setCenter(mPosition);
MTXIdentity(mMtx);
mBoundingBox.Set(sHIO.getBBoxMin(), sHIO.getBBoxMax());
mAcceleration = dAcPy_c::getBombAcceleration();
mMaxSpeed = dAcPy_c::getBombMaxSpeed();
mFuseTime = dAcPy_c::getBombExplodeTimer();
mLinkage.set(0xc9c2, 25.0f, 43.0f, 36.0f, nullptr);
mLinkage.setField_0x8C_0x90(dAcPy_c::getBombUnknown0_0(), dAcPy_c::getBombUnknown0_1());
mLinkage.setField_0x94_0x98(dAcPy_c::getBombUnknown1_0(), dAcPy_c::getBombUnknown1_1());
field_0xA50 = 1.0f;
mVec3_c pos = (mPosition);
mAcch.CrrPos(*dBgS::GetInstance());
setRoomId();
switch (getBombType()) {
case BOMB_0:
case BOMB_4:
case BOMB_EXPLODE_NO_DAMAGE: {
changeState(StateID_Explode);
} break;
case BOMB_PLAYER_CARRY: {
setFlag(dAcBomb_c::FLAG_0x200000);
setFlag(dAcBomb_c::FLAG_PLAYER_MAKE);
if (checkWaterIn()) {
setFlag(dAcBomb_c::FLAG_UNDERWATER);
mAcceleration = dAcPy_c::getBombAcceleration_1();
mMaxSpeed = dAcPy_c::getBombMaxSpeed_1();
}
changeState(StateID_Carry);
} break;
case BOMB_BOCO_CARRY: {
setFlag(dAcBomb_c::FLAG_BOKO_CARRY);
changeState(StateID_Carry);
} break;
case BOMBF:
case BOMBF_CRAWLSPACE:
case BOMB_5: {
mPosition = pos;
changeState(StateID_FlowerWait);
} break;
default: {
changeState(StateID_Wait);
} break;
}
f32 yOffset = mScale.y * 25.0f;
mWorldMtx.transS(mPosition);
mWorldMtx.ZXYrotM(mRotation);
mMtx_c m0, m1;
m0.transS(0, yOffset, 0);
mWorldMtx.concat(m0);
mWorldMtx.concat(mMtx);
m1.transS(0, -yOffset, 0);
mWorldMtx.concat(m1);
mMdl.setLocalMtx(mWorldMtx);
setBombColor();
mMdl.calc(false);
setSmokePos();
mExternalTranslation = mPosition;
return SUCCEEDED;
}
void dAcBomb_c::unkVirtFunc_0x5C() {
if (isState(StateID_Wait)) {
deleteRequest();
mEffect1.remove(true);
mEffect2.remove(true);
}
}
int dAcBomb_c::doDelete() {
mLinkage.forceRemove(this);
return SUCCEEDED;
}
// NONMATCHING
bool dAcBomb_c::checkExplode() {
if (mCarryTimer != 0) {
mCarryTimer--;
}
if (mFuseTime > 0) {
bool b = !checkFlag(
dAcBomb_c::FLAG_FLOWER | dAcBomb_c::FLAG_0x200000 | dAcBomb_c::FLAG_FALL_IN_WATER |
dAcBomb_c::FLAG_NEAR_TIMEDOOR
) &&
!isState(StateID_Explode);
if (b) {
mFuseTime--;
if (checkFlag(dAcBomb_c::FLAG_BOKO_CARRY | dAcBomb_c::FLAG_FUSE_PAUSED)) {
s16 explodeTimer = dAcPy_c::getBombExplodeTimer();
if (mFuseTime == (explodeTimer >> 1) || mFuseTime == (explodeTimer >> 2) ||
mFuseTime == (explodeTimer >> 3) || mFuseTime == (explodeTimer >> 4)) {
mFuseTime <<= 1;
}
}
}
}
if (checkFlag(dAcBomb_c::FLAG_FUSE_PAUSED | dAcBomb_c::FLAG_FALL_IN_WATER | dAcBomb_c::FLAG_NEAR_TIMEDOOR)) {
return false;
}
if (mFuseTime == 0 || checkFlag(dAcBomb_c::FLAG_BOMB_HIT) ||
(mSph.ChkCoHit() && mSph.GetCoActor()->isActorPlayer() &&
static_cast<dAcPy_c *>(mSph.GetCoActor())->isBurning()) ||
(checkFlag(dAcBomb_c::FLAG_BEETLE_CARRY) && mCarryTimer == 0) &&
( // Check Beetle or Chu grab
(mSph.ChkCoHit() && mSph.GetCoActor()->mProfileName != fProfile::BOOMERANG &&
mSph.GetCoActor()->mProfileName != fProfile::E_SM) ||
!mAcch.fn_80340ca0(mUnkInfo)
)) {
changeState(StateID_Explode);
return true;
}
if (mAcch.ChkGndHit()) {
const dBgS_GndChk &gnd = mAcch.GetGnd();
if (dBgS::GetInstance()->GetSpecialCode(gnd) == POLY_ATTR_LAVA ||
dBgS::GetInstance()->GetGroundCode(gnd) == 4 /* FIXME*/) {
mUnkInfo.SetPolyInfo(mAcch.GetGnd());
changeState(StateID_Explode);
return true;
}
}
if (mAcch.ChkWallHit(nullptr)) {
if (dBgS::GetInstance()->GetSpecialCode(mAcchCir) == POLY_ATTR_LAVA) {
mUnkInfo.SetPolyInfo(mAcchCir);
changeState(StateID_Explode);
return true;
}
}
return false;
}
void dAcBomb_c::setRoomId() {
if (mAcch.GetGroundH() != -1e9f) {
mRoomID = dBgS::GetInstance()->GetRoomId(mAcch.GetGnd());
} else if (mRoomID == -1) {
mRoomID = dAcPy_c::GetLink2()->getRoomId();
}
}
void dAcBomb_c::setSmokePos() {
mVec3_c in = sSmokeOffset;
mWorldMtx.multVec(in, mSmokePosNext);
mSmokePos = (mSmokePosNext - mSmokePosPrev) * 0.5f;
}
bool dAcBomb_c::checkWaterIn() {
return checkFlag(dAcBomb_c::FLAG_0x20000000) ||
(mAcch.ChkWaterHit() && (mPosition.y + mScale.x * sHIO.getBombScale() < mAcch.GetWtrGroundH()));
}
void dAcBomb_c::setTransformFromFlower(const mMtx_c &m) {
if (mLinkage.checkState(dLinkage_c::STATE_ACTIVE)) {
return;
}
mMtx = m;
mMtx_c &m0 = mMtx;
mVec3_c out;
m0.setTranslation(mVec3_c::Zero);
m0.multVecSR(mVec3_c::Ey, out);
f32 f = field_0xA50 * (25.0f * mScale.y);
m.getTranslation(mExternalTranslation);
mPosition = mExternalTranslation + out * f;
mPosition.y -= f;
}
void dAcBomb_c::setPickupTarget() {
if (checkFlag(dAcBomb_c::FLAG_FALL_IN_WATER)) {
return;
}
AttentionManager::GetInstance()->addPickUpTarget(*this, 120.0f);
}
void dAcBomb_c::lookAt() {
dAcPy_c::GetLink2()->lookTowardItem(mPositionCopy2, 4, 0x5555, 300, 400, -400);
}
void dAcBomb_c::bounceWall(mAng angle) {
mSpeed *= dAcPy_c::getBombBounceSpeed();
mRollSpeed *= dAcPy_c::getBombBounceSpeed();
mAngle.y = angle - mAng((mAngle.y + 0x8000) - angle);
mRollRotationY = angle - mAng((mRollRotationY + 0x8000) - angle);
}
void dAcBomb_c::getVelocity(mVec3_c &out) {
// out = Bomb Speed (Standard Parameters)
setXYZCirclePoint(out, mAngle.y, mSpeed, mVelocity.y);
if (mRollFrameTimer != 0) {
f32 f = cM::minMaxLimit(mRollFrameTimer * 0.02f, 0.0f, 1.0f);
mVec3_c v;
setXYZCirclePoint(v, mRollRotationY, mRollSpeed, 0.0f);
out = out * (1.0f - f) + v * f;
}
}
void dAcBomb_c::initializeState_Explode() {
setActorProperty(AC_PROP_0x4);
dAcPy_c *pPlayer = dAcPy_c::GetLink2();
dAcObjBase_c *pObj = pPlayer->getBeetleHeldActor();
if (pObj == this) {
mLinkage.forceRemove(this);
pPlayer->setBeetleReleasedObject(this);
}
mRotation.y = cM::rndF(65536);
mSmokePos = mVec3_c::Zero;
mVec3_c out;
if (getOldStateID() == StateID_FlowerWait || dBgS::GetInstance()->ChkPolySafe(mUnkInfo)) {
if (getOldStateID() == StateID_FlowerWait) {
mWorldMtx.multVecSR(mVec3_c::Ey, out);
} else {
cM3dGPla plane;
dBgS::GetInstance()->GetTriPla(mUnkInfo, &plane);
out = plane.GetN();
}
(void)out.atan2sX_Z();
(void)cM::atan2s(out.absXZ(), out.y);
mPosition.y += 25.0f;
mPosition -= out * 25.0f;
} else if (mAcch.ChkGndHit()) {
cM3dGPla plane;
dBgS::GetInstance()->GetTriPla(mAcch.GetGnd(), &plane);
(void)plane.GetN().atan2sX_Z();
(void)cM::atan2s(plane.GetN().absXZ(), plane.GetN().y);
}
dCamera_c *pCam = dScGame_c::getCamera();
mVec3_c v = pCam->getTarget() - pCam->getPosition();
if (v.getSquareMag() > 0.01f) {
v.normalize();
} else {
v = mVec3_c::Ez;
}
cM3dGPla plane;
plane.SetupNP(v, pCam->getPosition());
f32 d = cM3d_SignedLenPlaAndPos(&plane, mPosition);
mVec3_c temp(dAcPy_c::getBombParticleScale(), dAcPy_c::getBombParticleScale(), dAcPy_c::getBombParticleScale());
if (d < dAcPy_c::getBombDistanceUnknown0()) {
dEmitterBase_c *pEmitter = dJEffManager_c::spawnEffect(
PARTICLE_RESOURCE_ID_MAPPING_322_, mPosition, nullptr, &temp, nullptr, nullptr, 0, 0
);
if (pEmitter != nullptr) {
pEmitter->setRate(10.0f);
}
(void)dJEffManager_c::spawnEffect(
PARTICLE_RESOURCE_ID_MAPPING_323_, mPosition, nullptr, &temp, nullptr, nullptr, 0, 0
);
pEmitter = dJEffManager_c::spawnEffect(
PARTICLE_RESOURCE_ID_MAPPING_324_, mPosition, nullptr, &temp, nullptr, nullptr, 0, 0
);
if (pEmitter != nullptr) {
pEmitter->setRate(5.0f);
}
} else if (checkFlag(dAcBomb_c::FLAG_CHAIN_BOMB)) {
(void)dJEffManager_c::spawnEffect(
PARTICLE_RESOURCE_ID_MAPPING_321_, mPosition, nullptr, &temp, nullptr, nullptr, 0, 0
);
} else {
(void)dJEffManager_c::spawnEffect(
PARTICLE_RESOURCE_ID_MAPPING_322_, mPosition, nullptr, &temp, nullptr, nullptr, 0, 0
);
(void)dJEffManager_c::spawnEffect(
PARTICLE_RESOURCE_ID_MAPPING_323_, mPosition, nullptr, &temp, nullptr, nullptr, 0, 0
);
(void)dJEffManager_c::spawnEffect(
PARTICLE_RESOURCE_ID_MAPPING_324_, mPosition, nullptr, &temp, nullptr, nullptr, 0, 0
);
(void)dJEffManager_c::spawnEffect(
PARTICLE_RESOURCE_ID_MAPPING_325_, mPosition, nullptr, &temp, nullptr, nullptr, 0, 0
);
}
if (dStageMgr_c::GetInstance()->isInLastBoss() && mAcch.ChkGndHit()) {
(void)dJEffManager_c::spawnEffect(
PARTICLE_RESOURCE_ID_MAPPING_849_, mPosition, nullptr, nullptr, nullptr, nullptr, 0, 0
);
}
dLightEnv_c::GetPInstance()->SordFlush_set(&mPosition, 5);
mSpeed = 0.0f;
mVelocity = mVec3_c::Zero;
mAcceleration = 0.0f;
mSph.ClrTgSet();
mSph.ClrCoSet();
if (getBombType() == BOMB_EXPLODE_NO_DAMAGE) {
mSph.ClrAtSet();
} else {
mSph.OnAtSet();
}
if (getBombType() == BOMBF_CRAWLSPACE) {
mSph.SetR(200.0f);
} else {
mSph.SetR(dAcPy_c::getBombExplodeRadius());
}
mSph.SetC(mPosition);
mSph.SetAtType(AT_TYPE_BOMB);
mSph.SetAtVec(mVec3_c::Zero);
dCcS::GetInstance()->Set(&mSph);
dCcS::GetInstance()->SetMass(&mSph, 1);
startSound(SE_BM_EXPLODE);
mLinkage.forceRemove(this);
unsetObjectProperty(OBJ_PROP_0x1000);
mFuseTime = 0;
f32 dist = mPosition.squareDistance(pPlayer->mPosition);
if (dist < 160000.0f) {
dRumble_c::start(dRumble_c::sRumblePreset3, dRumble_c::FLAG_SLOT0 | dRumble_c::FLAG_ACTIVE);
} else if (dist < 640000.0f) {
dRumble_c::start(dRumble_c::sRumblePreset1, dRumble_c::FLAG_SLOT0 | dRumble_c::FLAG_ACTIVE);
}
dLightEnv_c::GetPInstance()->setBPM8_Type10_2(&mPosition);
dAcEnBase_c::fn_800307E0(&mPosition, 0);
}
void dAcBomb_c::executeState_Explode() {
if (--mFuseTime >= -3) {
dCcS::GetInstance()->Set(&mSph);
dCcS::GetInstance()->SetMass(&mSph, 1);
} else {
deleteRequest();
}
}
void dAcBomb_c::finalizeState_Explode() {}
void dAcBomb_c::initializeState_Carry() {
unsetFlag(dAcBomb_c::FLAG_BEETLE_CARRY | dAcBomb_c::FLAG_0x80000 | dAcBomb_c::FLAG_ROLL | dAcBomb_c::FLAG_0x10000);
mHitForce = mVec3_c::Zero;
if (mLinkage.checkConnection(dLinkage_c::CONNECTION_5)) {
setFlag(dAcBomb_c::FLAG_BEETLE_CARRY);
mCarryTimer = 5;
mLinkage.offFlag(0x20000000);
} else {
dAcBase_c *pObj = mLinkage.getControllingActor();
if (pObj != nullptr && pObj->isActorPlayer()) {
dAcPy_c::GetLink2()->getOwnedObjects().insert(this);
}
mSph.ClrCoSet();
}
dAcBase_c *pObj = mLinkage.getControllingActor();
if (pObj != nullptr && pObj->mProfileName == fProfile::E_SM) {
onSoundSourceFlag(1);
}
mSpeed = 0.0f;
mVelocity = mVec3_c::Zero;
mLinkage.bushTpFunc(mAcch);
setRoomId();
}
void dAcBomb_c::executeState_Carry() {
dAcPy_c *pPlayer = dAcPy_c::GetLink2();
if (checkExplode()) {
unsetFlag(dAcBomb_c::FLAG_BOKO_CARRY | dAcBomb_c::FLAG_FLOWER | dAcBomb_c::FLAG_0x200000);
} else {
if (!mLinkage.checkState(dLinkage_c::STATE_ACTIVE)) {
if (checkFlag(dAcBomb_c::FLAG_0x100000)) {
unsetFlag(dAcBomb_c::FLAG_0x100000);
mMtx.ZrotS(-mRotation.z);
mMtx.XrotM(-mRotation.x);
mMtx.YrotM(-mRotation.y);
mMtx.concat(mWorldMtx);
mMtx.m[0][3] = 0.0f;
mMtx.m[1][3] = 0.0f;
mMtx.m[2][3] = 0.0f;
}
if (mLinkage.checkState(dLinkage_c::STATE_3)) {
setFlag(dAcBomb_c::FLAG_0x80000 | dAcBomb_c::FLAG_ROLL);
mRollRotationY = pPlayer->mRotation.y;
mRollSpeed = mSpeed;
mRollFrameTimer = 60;
}
unsetFlag(dAcBomb_c::FLAG_BOKO_CARRY | dAcBomb_c::FLAG_FLOWER | dAcBomb_c::FLAG_0x200000);
changeState(StateID_Wait);
} else if (!mLinkage.checkConnection(dLinkage_c::CONNECTION_5)) {
unsetFlag(dAcBomb_c::FLAG_BEETLE_CARRY | dAcBomb_c::FLAG_FLOWER);
}
mLinkage.bushTpFunc(mAcch);
setRoomId();
if (isState(StateID_Carry)) {
mSpeed = 0.0f;
mVelocity = mVec3_c::Zero;
}
}
}
void dAcBomb_c::finalizeState_Carry() {
if (getNewStateID() != StateID_Explode) {
offSoundSourceFlag(1);
}
}
void dAcBomb_c::initializeState_Wait() {
mSph.OnCoSet();
mSph.SetCoCallback(dAcBomb_coHitCallback);
field_0xA42 = 5;
if (checkFlag(dAcBomb_c::FLAG_0x4000000)) {
unsetFlag(dAcBomb_c::FLAG_0x4000000);
setFlag(dAcBomb_c::FLAG_BEETLE_CARRY);
}
}
// NONMATCHING
void dAcBomb_c::executeState_Wait() {
if (checkExplode()) {
return;
}
if (mLinkage.checkState(dLinkage_c::STATE_ACTIVE)) {
changeState(StateID_Carry);
return;
}
if (mUnkRef.fn_80051780(mSph)) {
changeState(StateID_WindCarry);
return;
}
if (field_0xA42 != 0) {
field_0xA42--;
}
mVec3_c bombVelocity;
getVelocity(bombVelocity);
s16 bombAngleY = bombVelocity.atan2sX_Z();
f32 bombSpeed = bombVelocity.absXZ();
mAng gndAngle;
if (mAcch.ChkGndHit()) {
gndAngle = mAcch.GetGnd().GetAngle(bombAngleY);
mVelocity.y -= bombSpeed * nw4r::math::FAbs(gndAngle.sin());
bombVelocity *= gndAngle.cos();
if (mRollFrameTimer != 0) {
mRollFrameTimer--;
}
} else {
gndAngle = 0;
}
f32 prevAccel = mAcceleration;
mVelocity.y = nw4r::ut::Max(mVelocity.y + mAcceleration, mMaxSpeed);
bombVelocity.y = mVelocity.y;
mPosition += bombVelocity;
mPosition += mStts.GetCcMove();
if (checkFlag(dAcBomb_c::FLAG_0x10000) && checkFlag(dAcBomb_c::FLAG_UNDERWATER) && mAcch.ChkWaterHit()) {
if (mPosition.y + (mScale.x * sHIO.getBombScale()) + 1.0f >= mAcch.GetWtrGroundH()) {
mPosition.y = mAcch.GetWtrGroundH() - (mScale.x * sHIO.getBombScale()) - 1.0f;
mVelocity.y = 0.0f;
}
}
mAcceleration = prevAccel;
f32 prevVelocityY = mVelocity.y;
s16 a0 = 0;
s16 a1 = 0;
f32 f = 1.0f;
if (mAcch.ChkGndHit() && mHitForce.squareMagXZ() > 1.0f) {
cM3dGPla plane;
dBgS::GetInstance()->GetTriPla(mAcch.GetGnd(), &plane);
f = plane.GetAngle(mHitForce.atan2sX_Z()).cos();
f *= f;
}
mPosition += (mHitForce * f) + mStreamForce;
mAcch.CrrPos(*dBgS::GetInstance());
f32 sinkTarget = 0.0f;
f32 sinkRate = 4.0f;
mVec3_c force = mVec3_c::Zero;
f32 sinkValue = mYOffset;
if (mAcch.ChkGndHit() && !mLinkage.checkState(dLinkage_c::STATE_ACTIVE)) {
s32 attr = dBgS::GetInstance()->GetSpecialCode(mAcch.mGnd);
if (attr == POLY_ATTR_CURSED_WATER) {
sinkTarget = -60.0f;
if (sinkValue >= 0.0f) {
prevVelocityY *= 0.5f;
mSpeed *= 0.5f;
}
sinkRate = nw4r::math::FAbs(prevVelocityY);
mVelocity.y = prevVelocityY;
mAcceleration = dAcPy_c::getBombAcceleration_1();
mMaxSpeed = dAcPy_c::getBombMaxSpeed_1();
} else if (attr == POLY_ATTR_SAND_DEEP_INSTANT || attr == POLY_ATTR_SAND_DEEP_SLOW ||
attr == POLY_ATTR_SAND_MED) {
sinkTarget = -10.0f;
sinkRate = 1.0f;
}
if (attr == POLY_ATTR_SAND_DEEP_SLOW || attr == POLY_ATTR_SAND_MED) {
dTgStream_c::getForce(mPosition, force, dTgStream_c::sSandStreamList);
}
}
cLib::addCalcPosXZ(&mStreamForce, force, 0.5f, 10.0f, 3.0f);
sLib::chase(&sinkValue, sinkTarget, sinkRate);
mYOffset = sinkValue;
if (sinkValue <= -60.0f) {
setFlag(dAcBomb_c::FLAG_DELETE_BOMB);
}
setRoomId();
if (mAcch.ChkGndHit()) {
cM3dGPla plane;
dBgS::GetInstance()->GetTriPla(mAcch.GetGnd(), &plane);
mGndAngle = cM::atan2s(plane.GetN().absXZ(), plane.GetN().y);
a1 = plane.GetN().atan2sX_Z();
a0 = a1 - bombAngleY;
}
bool hit = false;
f32 outXZ = bombVelocity.absXZ();
if (mAcch.ChkWallHit(nullptr) && mAng::abs(mAcchCir.GetWallAngleY() - bombAngleY) > 0x4400 && outXZ > 1.0f) {
bounceWall(mAcchCir.GetWallAngleY());
hit = true;
startSoundWithFloatParam(SE_BM_BOUND, outXZ);
} else if (mAcch.ChkRoofHit() && mVelocity.y > 0.0f) {
startSoundWithFloatParam(SE_BM_BOUND, mVelocity.y);
mVelocity.y = 0.0f;
} else if (mAcch.ChkGroundLanding() && mSpeed > 5.0f && mGndAngle >= mAng::fromDeg(50.0f) &&
mAng::abs(a0) >= 0x4000) {
bounceWall(a1);
mVelocity.y = prevVelocityY;
mAcch.ClrGroundLanding();
mAcch.i_ClrGroundHit();
hit = true;
} else if (mSph.ChkCoHit() && field_0xA42 == 0 && mStts.GetCcMove().absXZ() >= 1.0f) {
bounceWall(mStts.GetCcMove().atan2sX_Z());
field_0xA42 = 5;
hit = true;
}
mAng hitGndAngle = gndAngle;
if (hit) {
getVelocity(bombVelocity);
s16 sVar15 = bombVelocity.atan2sX_Z();
if (mAcch.ChkGndHit()) {
hitGndAngle = mAcch.GetGnd().GetAngle(sVar15);
}
}
if (mAcch.ChkGroundLanding()) {
if (prevVelocityY < -5.0f) {
startSoundWithFloatParam(SE_BM_BOUND, prevVelocityY * -1.0f);
if (dBgS::GetInstance()->GetPolyAtt0(mAcch.GetGnd()) != POLY_ATT_0_LAVA) {
dJEffManager_c::spawnGroundEffect(mPosition, mPolyAttr0, mPolyAttr1, field_0x1B4, 1, 0.8f, field_0x1B0);
}
}
prevVelocityY *= -dAcPy_c::getBombBounceSpeed();
s32 attr = dBgS::GetInstance()->GetSpecialCode(mAcch.mGnd);
if (!checkFlag(dAcBomb_c::FLAG_ROLL) &&
(prevVelocityY < dAcPy_c::getBombStopSpeedY() ||
(attr == POLY_ATTR_SAND_DEEP_INSTANT ||
(attr == POLY_ATTR_CURSED_WATER || attr == POLY_ATTR_SAND_DEEP_SLOW || attr == POLY_ATTR_SAND_MED)))) {
sLib::chase(&mSpeed, 0.0f, 7.0f);
} else {
mSpeed *= 0.9f;
mRollSpeed *= 0.9f;
if (hitGndAngle < 0) {
mSpeed *= hitGndAngle.cos();
mRollSpeed *= hitGndAngle.cos();
}
if (checkFlag(dAcBomb_c::FLAG_0x80000)) {
unsetFlag(dAcBomb_c::FLAG_0x80000);
mVelocity.y = 0.0f;
} else if (prevVelocityY > dAcPy_c::getBombMaxSpeedY()) {
mVelocity.y = dAcPy_c::getBombMaxSpeedY();
} else {
mVelocity.y = prevVelocityY;
}
}
} else if (mAcch.ChkGndHit()) {
cM3dGPla plane;
dBgS::GetInstance()->GetTriPla(mAcch.mGnd, &plane);
int code = dBgS::GetInstance()->GetSpecialCode(mAcch.mGnd);
f32 step;
if (checkFlag(dAcBomb_c::FLAG_ROLL)) {
if (code == POLY_ATTR_SAND_DEEP_SLOW || code == POLY_ATTR_SAND_MED) {
step = 0.2f;
} else {
step = 0.1f;
}
} else {
step = 0.75f;
}
if (code != POLY_ATTR_CURSED_WATER) {
if (mGndAngle >= mAng::fromDeg(20.0f)) {
mVec3_c v1 = 2.0f * plane.GetN() * mAng(mGndAngle.mVal).sin();
v1.y = 0.0f;
mAng yRot = v1.atan2sX_Z();
f32 compare = mHitForce.squareMagXZ();
if (compare > 1.0f) {
s32 a = yRot - mAng::fromVec(mHitForce);
if (mAng::abs(a) >= 0x4000) {
mHitForce.rotY(-yRot);
mHitForce.z *= 0.99f;
sLib::chase(&mHitForce.z, 0.0f, 1.0f);
mHitForce.rotY(yRot);
}
}
if (mAng::abs(yRot - mAngle.y) >= 0x4000) {
sLib::chase(&mSpeed, 0.0f, step);
}
mSpeed *= 0.99f;
rollTo(v1);
mSpeed = nw4r::ut::Min(mSpeed, 30.0f);
if (mAng::abs(yRot - mRollRotationY) >= 0x4000) {
sLib::chase(&mRollSpeed, 0.0f, step);
}
mRollSpeed *= 0.99f;
rollToInternal(v1);
mRollSpeed = nw4r::ut::Min(mRollSpeed, 30.0f);
} else {
sLib::chase(&mRollSpeed, 0.0f, step);
if (sLib::chase(&mSpeed, 0.0f, step)) {
if (mHitForce.getSquareMag() < 1.0f && mStreamForce.getSquareMag() < 1.0f) {
setPickupTarget();
}
unsetFlag(dAcBomb_c::FLAG_ROLL);
mSph.ClrAtSet();
}
}
}
}
lookAt();
}
void dAcBomb_c::finalizeState_Wait() {
mSph.SetCoCallback(dAcBomb_coHitCallback);
mSph.OnCoSet();
}
void dAcBomb_c::initializeState_FlowerWait() {
setFlag(dAcBomb_c::FLAG_FLOWER);
mSph.ClrTgSet();
mScale.set(0.1f, 0.1f, 0.1f);
mStts.SetRank(0xD);
mAcch.OffLineCheck();
mMdl.setScale(mScale);
}
void dAcBomb_c::executeState_FlowerWait() {
dAcPy_c *pPlayer = dAcPy_c::GetLink2();
if (mScale.x < 1.0f || field_0xA50 < 1.0f) {
if (mScale.x < 0.15f && !MinigameManager::GetInstance()->checkInThrillDigger() &&
((getBombType() == BOMBF_CRAWLSPACE && pPlayer->checkActionFlagsCont(dAcPy_c::ActFLG1_INCRAWLSPACE)) ||
(getBombType() != BOMBF_CRAWLSPACE && !pPlayer->checkActionFlagsCont(dAcPy_c::ActFLG1_INCRAWLSPACE)))) {
startSound(SE_O_BOMB_FLOWER_SPROUT);
}
sLib::chase(&mScale.x, 1.0f, 0.1f);
mScale.z = mScale.y = mScale.x;
mVec3_c scale = mScale * field_0xA50;
mMdl.setScale(scale);
mMtx_c m = mMtx;
m.setTranslation(mExternalTranslation);
setTransformFromFlower(m);
mSph.ClrTgSet();
return;
}
AttentionManager::GetInstance()->addUnk3Target(*this, 1, 250.0f, -200.0f, 200.0f);
lookAt();
mSph.OnTgSet();
mVec3_c scale = mScale * field_0xA50;
mMdl.setScale(scale);
if (checkExplode()) {
return;
}
if (mLinkage.checkState(dLinkage_c::STATE_ACTIVE)) {
changeState(StateID_Carry);
return;
}
setPickupTarget();
}
void dAcBomb_c::finalizeState_FlowerWait() {
if (!(mLinkage.checkConnection(dLinkage_c::CONNECTION_5) && checkFlag(dAcBomb_c::FLAG_FLOWER))) {
unsetFlag(dAcBomb_c::FLAG_FLOWER);
}
if (getBombType() == BOMBF_CRAWLSPACE) {
mStts.SetRank(4);
} else {
mStts.SetRank(5);
}
unsetActorProperty(AC_PROP_0x1);
mAcch.OnLineCheck();
}
void dAcBomb_c::initializeState_WindCarry() {
unsetFlag(dAcBomb_c::FLAG_BEETLE_CARRY | dAcBomb_c::FLAG_0x80000 | dAcBomb_c::FLAG_ROLL | dAcBomb_c::FLAG_0x10000);
mHitForce = mVec3_c::Zero;
mSpeed = 0.0f;
mVelocity = mVec3_c::Zero;
mRollSpeed = 0.0f;
mLinkage.bushTpFunc(mAcch);
setRoomId();
}
void dAcBomb_c::executeState_WindCarry() {
if (checkExplode()) {
return;
}
if (mLinkage.checkState(dLinkage_c::STATE_ACTIVE)) {
changeState(StateID_Carry);
return;
}
if (mSph.ChkCoHit()) {
mPosition += mStts.GetCcMove();
mUnkRef.fn_800051630();
}
if (!mUnkRef.fn_80051780(mSph)) {
changeState(StateID_Wait);
return;
}
mLinkage.bushTpFunc(mAcch);
setRoomId();
mSpeed = 0.0f;
mVelocity = mVec3_c::Zero;
}
void dAcBomb_c::finalizeState_WindCarry() {}
void dAcBomb_c::setBombColor() {
mColor clr(0, 0, 0, 0xFF);
if (!checkFlag(dAcBomb_c::FLAG_FALL_IN_WATER)) {
bool b = !checkFlag(
dAcBomb_c::FLAG_FLOWER | dAcBomb_c::FLAG_0x200000 | dAcBomb_c::FLAG_FALL_IN_WATER |
dAcBomb_c::FLAG_NEAR_TIMEDOOR
) &&
!isState(StateID_Explode);
if (b) {
mEffect1.holdEffect(PARTICLE_RESOURCE_ID_MAPPING_974_, mWorldMtx, nullptr, nullptr);
if (!checkFlag(dAcBomb_c::FLAG_BOKO_CARRY)) {
mEffect2.holdEffect(PARTICLE_RESOURCE_ID_MAPPING_975_, mWorldMtx, nullptr, nullptr);
}
dAcObjBase_c *pObj;
if (
// Is controlled - and by player
// And Controlling Actor (player) as objprop 0x200 set
(mLinkage.checkState(dLinkage_c::STATE_ACTIVE) && static_cast<dAcObjBase_c *>(mLinkage.getControllingActor())->isPlayer())
&& ((pObj = static_cast<dAcObjBase_c *>(mLinkage.getControllingActor())) && pObj->checkObjectProperty(OBJ_PROP_0x200))
// OOOOR this bomb has it set.
|| checkObjectProperty(OBJ_PROP_0x200)
) {
mEffect1.stopDrawParticles();
mEffect2.stopDrawParticles();
} else {
holdSound(SE_BM_IGNITION_LV);
mEffect1.playDrawParticles();
mEffect2.playDrawParticles();
}
s32 interval;
s16 maxTime = dAcPy_c::getBombExplodeTimer();
if (mFuseTime > maxTime) {
interval = maxTime >> 1;
} else if (mFuseTime > (maxTime >> 1)) {
interval = maxTime >> 2;
} else if (mFuseTime > (maxTime >> 2)) {
interval = maxTime >> 3;
} else {
interval = maxTime >> 4;
}
s32 tmp1 = (mFuseTime / interval);
tmp1 = nw4r::ut::Max<s32>(mFuseTime - (tmp1 * interval) - 5, 0);
u8 colorVal = (1.0f / (interval - 5)) * tmp1 * 255.0f;
clr.r = colorVal;
clr.b = colorVal;
}
}
mMdl.setTevKColor(mMainMatID, GX_KCOLOR3, clr, false);
}
void dAcBomb_c::rollTo(const mVec3_c &dir) {
mVec3_c v;
setXYZCirclePoint(v, mAngle.y, mSpeed, mVelocity.y);
v += dir;
mAngle.y = v.atan2sX_Z();
mSpeed = v.absXZ();
mVelocity.y = v.y;
}
void dAcBomb_c::rollToInternal(const mVec3_c &dir) {
if (mRollFrameTimer == 0) {
return;
}
mVec3_c v;
setXYZCirclePoint(v, mRollRotationY, mRollSpeed, 0.0f);
v += dir;
v.y = 0.0f;
mRollRotationY = v.atan2sX_Z();
mRollSpeed = v.absXZ();
}
void dAcBomb_c::registerInEvent() {
if (!isState(StateID_Wait)) {
return;
}
if (!mAcch.ChkGndHit()) {
return;
}
const dAcObjBase_c *pObj = dBgS::GetInstance()->GetActorPointer(mAcch.GetGnd());
if (pObj != nullptr && pObj->mProfileName != fProfile::OBJ_CANNON) {
if (pObj->checkActorProperty(AC_PROP_0x4) || EventManager::FUN_800a0570(pObj)) {
setActorProperty(AC_PROP_0x4);
}
}
}
void dAcBomb_c::unkVirtFunc_0x6C() {
if (isState(StateID_Wait)) {
unsetActorProperty(AC_PROP_0x4);
}
}
// NONMATCHING (https://decomp.me/scratch/4ws7h )
int dAcBomb_c::actorExecute() {
unsetFlag(dAcBomb_c::FLAG_0x400000 | dAcBomb_c::FLAG_0x100);
mVec3_c v;
getVelocity(v);
f32 f = mHitForce.getSquareMag();
if (!checkFlag(dAcBomb_c::FLAG_0x8000)) {
if (f > 1.0f) {
v += mHitForce;
rollTo(mHitForce);
rollToInternal(mHitForce);
}
f = 0.0f;
mHitForce = mVec3_c::Zero;
} else {
unsetFlag(dAcBomb_c::FLAG_0x8000);
}
mGndAngle = 0;
mSmokePosPrev = mSmokePosNext;
executeState();
if (checkFlag(dAcBomb_c::FLAG_DELETE_BOMB)) {
deleteRequest();
return SUCCEEDED;
}
if (!isState(StateID_Explode)) {
if (checkFlag(dAcBomb_c::FLAG_FALL_IN_WATER)) {
if (sLib::chase(&mScale.x, 0.0f, 0.0875f)) {
deleteRequest();
return SUCCEEDED;
}
mScale.y = mScale.z = mScale.x;
mMdl.setScale(mScale);
} else if (mFuseTime < 4) {
f32 scale = nw4r::ut::Min((4 - mFuseTime) * (1.0f / 7.5f), 0.4f) + 1.0f;
mScale.set(scale, scale, scale);
mMdl.setScale(mScale);
}
if (checkWaterIn()) {
if (!checkFlag(dAcBomb_c::FLAG_FALL_IN_WATER | dAcBomb_c::FLAG_UNDERWATER)) {
if (!checkFlag(dAcBomb_c::FLAG_0x20000000)) {
// !!! FPR alloc here is weird I guess
f32 diff0 = (mOldPosition.y - mPosition.y);
f32 diff1 = (mAcch.GetWtrGroundH() - mPosition.y);
diff0 = nw4r::math::FAbs(diff0);
diff1 = nw4r::math::FAbs(diff1);
mVec3_c pos;
if (diff0 < 1.0f) {
pos.x = mPosition.x;
pos.y = mAcch.GetWtrGroundH();
pos.z = mPosition.z;
} else {
f32 f = diff1 / diff0;
if (f > 1.0f) {
f = 1.0f;
}
pos = f * mOldPosition + (1.0f - f) * mPosition;
}
dAcPy_c::fn_801E2FC0(pos, mAcch.mWtr, 0.8f);
}
startSound(SE_BM_FALL_WATER);
if (mLinkage.checkState(dLinkage_c::STATE_ACTIVE)) {
mLinkage.forceRemove(this);
}
setFlag(dAcBomb_c::FLAG_FALL_IN_WATER);
mSmokePos = mVec3_c::Zero;
mSpeed *= 0.5f;
mVelocity.y *= 0.5f;
mAcceleration = dAcPy_c::getBombAcceleration_1();
mMaxSpeed = dAcPy_c::getBombMaxSpeed_1();
}
if (checkFlag(dAcBomb_c::FLAG_DELETE_BOMB)) {
deleteRequest();
mSmokePos = mVec3_c::Zero;
return SUCCEEDED;
}
} else {
unsetFlag(dAcBomb_c::FLAG_UNDERWATER);
mAcceleration = dAcPy_c::getBombAcceleration();
mMaxSpeed = dAcPy_c::getBombMaxSpeed();
}
if (mSpeed > 1.0f || f > 1.0f) {
mVec3_c v;
setXYZCirclePoint(v, mAngle.y, mSpeed, 0.0f);
bool gndNotHit = true;
if (f > 1.0f) {
v += mHitForce;
} else if (mAcch.ChkGndHit()) {
gndNotHit = false;
}
mMtx_c m;
f32 f = v.absXZ();
s32 atan0 = v.atan2sX_Z();
mAng a1 = f / ((sHIO.getBombScale() * 2.0f * mScale.x) * M_PI) * 65536.0f;
mAng a0 = mAng(atan0) - mRotation.y;
m.YrotS(a0);
if (gndNotHit) {
a1.mVal >>= 1;
}
m.XrotM(a1);
m.YrotM(-a0);
MTXConcat(m, mMtx, mMtx);
}
f32 scale = mScale.y * 25.0f;
f32 f = 0.0f;
if (mGndAngle != 0 && mGndAngle < 0x4000) {
/// TODO: Fake? mGndAngle load again
f32 f_temp = ((1.0f / mAng(mGndAngle.mVal).cos()) - 1.0f);
f = scale * nw4r::ut::Min(f_temp * 0.75f, 0.5f);
}
mLinkage.fn_800511E0(this);
mUnkRef.modifyMtx();
mMtx_c m2, m0, m1;
m0.transS(0.0f, scale, 0.0f);
mWorldMtx.concat(m0);
mWorldMtx.concat(mMtx);
m1.transS(0.0f, -scale, 0.0f);
mWorldMtx.concat(m1);
m2.transS(0.0f, f, 0.0f);
MTXConcat(m2, mWorldMtx, mWorldMtx);
mMdl.setLocalMtx(mWorldMtx);
mVec3_c in(0.0f, mScale.y * sHIO.getBombScale(), 0.0f);
mWorldMtx.multVec(in, mPositionCopy2);
mPositionCopy3 = mPositionCopy2;
mSph.moveCenter(mPositionCopy2);
mSph.SetR(mScale.x * sHIO.getBombScale() * field_0xA50);
if (checkFlag(dAcBomb_c::FLAG_FALL_IN_WATER)) {
mSph.ClrTgSet();
mSph.ClrTgHit();
}
if (mSph.GetR() > 0.01f) {
dCcS::GetInstance()->Set(&mSph);
} else {
mSph.ClrCoHit();
mSph.ClrTgHit();
}
if (!checkFlag(dAcBomb_c::FLAG_FALL_IN_WATER)) {
setSmokePos();
}
mMdl.calc(false);
setBombColor();
}
return SUCCEEDED;
}
int dAcBomb_c::draw() {
if (isState(StateID_Explode) ||
(getBombType() == BOMBF_CRAWLSPACE && !dAcPy_c::GetLink()->checkActionFlagsCont(0x400000))) {
return SUCCEEDED;
}
drawModelType1(&mMdl);
mSphere_c sph(mVec3_c(0.0f, mScale.x * sHIO.getBombScale(), 0.0f), mScale.x * sHIO.getBombScale());
if (!isState(StateID_FlowerWait)) {
drawShadow(mShdw, nullptr, mWorldMtx, &sph, -1, -1, -1, -1, -1, mPosition.y - mAcch.GetGroundH());
}
return SUCCEEDED;
}