From 77e7f3b33578c07d034d12ae8e5b28d3a8052263 Mon Sep 17 00:00:00 2001 From: elijah-thomas774 Date: Sun, 20 Sep 2026 11:54:25 -0400 Subject: [PATCH] Bomb First Pass --- include/d/a/d_a_player.h | 18 + include/d/a/obj/d_a_obj_bomb.h | 133 ++++- include/d/d_vec.h | 11 +- src/REL/d/a/d_a_bombf.cpp | 2 +- src/REL/d/a/e/d_a_e_sm.cpp | 4 +- src/REL/d/t/d_t_action.cpp | 2 +- src/d/a/obj/d_a_obj_bomb.cpp | 955 ++++++++++++++++++++++++++++++++- 7 files changed, 1092 insertions(+), 33 deletions(-) diff --git a/include/d/a/d_a_player.h b/include/d/a/d_a_player.h index a768c823..ec26b17b 100644 --- a/include/d/a/d_a_player.h +++ b/include/d/a/d_a_player.h @@ -54,6 +54,24 @@ protected: /* 0x4564 */ f32 field_0x4564; public: + // Bomb Function [0x80202CA0 - 0x80202DF0?] + static f32 getBombDistanceUnknown0(); + static s32 getBombExplodeTimer(); + static f32 getBombAcceleration(); + static f32 getBombMaxSpeed(); + static f32 getBombUnknown0_0(); + static f32 getBombUnknown0_1(); + static f32 getBombUnknown1_0(); + static f32 getBombUnknown1_1(); + static f32 getBombAcceleration_1(); + static f32 getBombMaxSpeed_1(); + static f32 getBombBounceSpeed(); // GetBombBoundRate + static f32 getBombExplodeScale(); // getBombEffScale + static f32 getBombExplodeRadius(); // getBombAt + static f32 getBombUnkFloat_0(); + static f32 getBombUnkFloat_1(); + static f32 getBombUnkFloat_2(); + // Beetle Functions [0x8021AA70 - 0x8021BE20] s16 getBeetleFlightTime(); mAng getBeetleAngle0(); diff --git a/include/d/a/obj/d_a_obj_bomb.h b/include/d/a/obj/d_a_obj_bomb.h index 9d0bfe99..c45711b6 100644 --- a/include/d/a/obj/d_a_obj_bomb.h +++ b/include/d/a/obj/d_a_obj_bomb.h @@ -9,25 +9,64 @@ #include "d/col/cc/d_cc_d.h" #include "d/d_shadow.h" #include "m/m3d/m_smdl.h" +#include "m/m_angle.h" #include "m/m_mtx.h" +#include "m/m_vec.h" #include "nw4r/g3d/res/g3d_resfile.h" #include "s/s_State.hpp" -#include "s/s_StateID.hpp" #include "toBeSorted/d_emitter.h" -// This may need its own file and could be independent of a bomb -class UnkBombColInfo : public cBgS_PolyInfo { -public: - UnkBombColInfo() : field_0x10(0), field_0x14(0), field_0x18(0) {} - u32 field_0x10; - u32 field_0x14; - u32 field_0x18; -}; - class dAcBomb_c : public dAcObjBase_c { public: - dAcBomb_c() : mStateMgr(*this), mSelfRef(this), mEffect1(this), mEffect2(this) {} - virtual ~dAcBomb_c(); + dAcBomb_c() : mStateMgr(*this), mUnkRef(this), mEffect1(this), mEffect2(this) {} + virtual ~dAcBomb_c() {} + + enum Type_e { + BOMB_0 = 0, // Explode + BOMB_1 = 1, // Flower + BOMB_2 = 2, // Flower + BOMB_3 = 3, // Carry + BOMB_4 = 4, // Explode + BOMB_5 = 5, // Flower + BOMB_6 = 6, // Explode + BOMB_7 = 7, // Carry + BOMB_MAX, + }; + + enum Flag_e { + FLAG_0x1 = (1 << 0), // Player Make + FLAG_0x2 = (1 << 1), + FLAG_0x4 = (1 << 2), // Bomb Hit ? + FLAG_0x8 = (1 << 3), + FLAG_0x10 = (1 << 4), + FLAG_0x20 = (1 << 5), // Underwater? + FLAG_0x40 = (1 << 6), + FLAG_0x80 = (1 << 7), + FLAG_0x100 = (1 << 8), + FLAG_0x200 = (1 << 9), + FLAG_0x400 = (1 << 10), + FLAG_0x800 = (1 << 11), + FLAG_0x1000 = (1 << 12), + FLAG_0x2000 = (1 << 13), + FLAG_0x4000 = (1 << 14), + FLAG_0x8000 = (1 << 15), + FLAG_0x10000 = (1 << 16), + FLAG_0x20000 = (1 << 17), + FLAG_0x40000 = (1 << 18), + FLAG_0x80000 = (1 << 19), + FLAG_0x100000 = (1 << 20), + FLAG_0x200000 = (1 << 21), + FLAG_0x400000 = (1 << 22), + FLAG_0x800000 = (1 << 23), + FLAG_0x1000000 = (1 << 24), + FLAG_0x2000000 = (1 << 25), + FLAG_0x4000000 = (1 << 26), + FLAG_0x8000000 = (1 << 27), + FLAG_0x10000000 = (1 << 28), + FLAG_0x20000000 = (1 << 29), + FLAG_0x40000000 = (1 << 30), + FLAG_0x80000000 = (1 << 31), + }; /* vt 0x08 */ virtual int create() override; /* vt 0x14 */ virtual int doDelete() override; @@ -44,36 +83,80 @@ public: STATE_FUNC_DECLARE(dAcBomb_c, Carry); STATE_FUNC_DECLARE(dAcBomb_c, WindCarry); - void setTransformFromFlower(const mMtx_c &); + STATE_MGR_DEFINE_UTIL_ISSTATE(dAcBomb_c); + STATE_MGR_DEFINE_UTIL_CHANGESTATE(dAcBomb_c); + STATE_MGR_DEFINE_UTIL_GETSTATEID(dAcBomb_c); + STATE_MGR_DEFINE_UTIL_GETOLDSTATEID(dAcBomb_c); + STATE_MGR_DEFINE_UTIL_GETNEWSTATEID(dAcBomb_c); - void Off_0xA3C(u32 mask) { + void coHitCallback(cCcD_Obj *i_objInfB); + void tgHitCallback(dAcObjBase_c *i_actorB, cCcD_Obj *i_objInfA, cCcD_Obj *i_objInfB); + + void setTarget(const mVec3_c &t); + + void setRoomId(); + void setSmokePos(); + bool checkWaterIn(); + void setTransformFromFlower(const mMtx_c &); + void setPickupTarget(); + bool checkExplode(); + void lookAt(); + void bounceWall(mAng angle); + void fn_8025A1F0(mVec3_c &out); + void setBombColor(); + void rollTo(const mVec3_c &dir); + void rollToInternal(const mVec3_c &dir); + + s16 get0xA44() const { + return mFuseTime; + } + + bool check0xA3C(u32 mask) const { + return (field_0xA3C & mask); + } + void unset0xA3C(u32 mask) { field_0xA3C &= ~mask; } - void On_0xA3C(u32 mask) { + void set0xA3C(u32 mask) { field_0xA3C |= mask; } + u32 getBombType() const { + return mParams; + } + +private: + bool createModel(); + public: - /* 0x330 */ nw4r::g3d::ResFile mBrres; + /* 0x330 */ nw4r::g3d::ResFile mRes; /* 0x334 */ m3d::smdl_c mMdl; /* 0x350 */ dShadowCircle_c mShdw; /* 0x358 */ dBgS_BombAcch mAcch; /* 0x708 */ dBgS_AcchCir mAcchCir; - /* 0x764 */ dCcD_Sph mCcDSph; + /* 0x764 */ dCcD_Sph mSph; /* 0x8B4 */ mMtx_c mMtx; /* 0x8E4 */ dBgS_BombLinChk mLinChk; - /* 0x97C */ UnkBombColInfo mUnkInfo; - /* 0x9B4 */ u8 _9B4[0x9B8 - 0x9B4]; - /* 0x9B8 */ dAcBomb_c *mSelfRef; - /* 0x9BC */ u8 _9BC[0x9D4 - 0x9BC]; + /* 0x97C */ cBgS_PolyInfo mUnkInfo; + /* 0x9A8 */ dAcObjRef_unk mUnkRef; /* 0x9D4 */ dEmitter_c mEffect1; /* 0xA08 */ dEmitter_c mEffect2; /* 0xA3C */ u32 field_0xA3C; - /* 0xA40 */ u32 field_0xA40; - /* 0xA44 */ s16 field_0xA44; - /* 0xA46 */ u8 _3[0xA50 - 0xA46]; + /* 0xA40 */ u8 field_0xA40; + /* 0xA41 */ u8 mMainMatID; + /* 0xA42 */ u8 field_0xA42; + /* 0xA44 */ s16 mFuseTime; + /* 0xA46 */ u16 field_0xA46; + /* 0xA48 */ u8 _3[0xA4A - 0xA48]; + /* 0xA4A */ mAng mBombRotationY; + /* 0xA4C */ f32 mBombSpeed; /* 0xA50 */ f32 field_0xA50; - /* 0xA54 */ u8 _4[0xA9C - 0xA54]; + /* 0xA54 */ mVec3_c field_0xA54; + /* 0xA60 */ mVec3_c field_0xA60; + /* 0xA6C */ mVec3_c field_0xA6C; + /* 0xA78 */ mVec3_c field_0xA78; + /* 0xA84 */ mVec3_c field_0xA84; + /* 0xA90 */ mVec3_c field_0xA90; /* 0xA9C */ STATE_MGR_DECLARE(dAcBomb_c); }; diff --git a/include/d/d_vec.h b/include/d/d_vec.h index 5c9dbfda..11e5c87c 100644 --- a/include/d/d_vec.h +++ b/include/d/d_vec.h @@ -6,7 +6,7 @@ /** * @brief Gets a point on a XZ circle. - * + * * @param center the circle center. Will also hold the result. * @param angle the Y angle. * @param radius the circle radius. @@ -15,10 +15,15 @@ inline static void getXZCirclePoint(mVec3_c ¢er, const mAng &angle, f32 radi center.x += radius * angle.sin(); center.z += radius * angle.cos(); } +inline static void setXYZCirclePoint(mVec3_c ¢er, const mAng &angle, f32 radius, f32 y) { + center.x = radius * angle.sin(); + center.y = y; + center.z = radius * angle.cos(); +} /** * @brief Converts a 2D vector to a 3D vector holding the original's vector coordinates in its XY components. - * + * * @param v The 2D vector * @return mVec3_c The 3D vector */ @@ -28,7 +33,7 @@ inline mVec3_c vec2ToVec3XY(const mVec2_c &v) { /** * @brief Computes left x right - * + * * @param result the result * @param left left operant * @param right right operand diff --git a/src/REL/d/a/d_a_bombf.cpp b/src/REL/d/a/d_a_bombf.cpp index d94a76d0..8ad94510 100644 --- a/src/REL/d/a/d_a_bombf.cpp +++ b/src/REL/d/a/d_a_bombf.cpp @@ -160,7 +160,7 @@ void dAcBombf_c::regrowBomb() { bomb->setActorProperty(AC_PROP_0x1); } if (field_0x3D4 == 0) { - bomb->field_0xA44 *= 1.5f; + bomb->mFuseTime *= 1.5f; } } } diff --git a/src/REL/d/a/e/d_a_e_sm.cpp b/src/REL/d/a/e/d_a_e_sm.cpp index af8edaca..b3f7f47e 100644 --- a/src/REL/d/a/e/d_a_e_sm.cpp +++ b/src/REL/d/a/e/d_a_e_sm.cpp @@ -1093,8 +1093,8 @@ bool dAcEsm_c::fn_187_4B50() { if (mBombRef.isLinked()) { dAcBomb_c *pBomb = mBombRef.get(); if (pBomb) { - pBomb->On_0xA3C(0x4); - pBomb->Off_0xA3C(0x800000); + pBomb->set0xA3C(0x4); + pBomb->unset0xA3C(0x800000); mBombRef.unlink(); } diff --git a/src/REL/d/t/d_t_action.cpp b/src/REL/d/t/d_t_action.cpp index a40bbacb..d2d269db 100644 --- a/src/REL/d/t/d_t_action.cpp +++ b/src/REL/d/t/d_t_action.cpp @@ -52,7 +52,7 @@ int dTgAction_c::actorExecute() { } if (pObj->mProfileName == fProfile::BOMB) { if (checkAreaBox(mActiveMtx, pObj->getPosition())) { - reinterpret_cast(pObj)->On_0xA3C(0x20000000); + reinterpret_cast(pObj)->set0xA3C(0x20000000); } } } diff --git a/src/d/a/obj/d_a_obj_bomb.cpp b/src/d/a/obj/d_a_obj_bomb.cpp index 5b9d6b6f..d70c13e9 100644 --- a/src/d/a/obj/d_a_obj_bomb.cpp +++ b/src/d/a/obj/d_a_obj_bomb.cpp @@ -1,20 +1,973 @@ #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_quat.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 + +// For real?? +template +inline T MyClamp(T value, T min, T max) { + return (value < min ? min : value > max ? max : value); +} SPECIAL_ACTOR_PROFILE(BOMB, dAcBomb_c, fProfile::BOMB, 0x128, 0, 2); +static const Vec vec_fn_80259E80 = {0, 60, 0}; + +dCcD_SrcSph sSphSrc = { + /* mObjInf */ + {/* mObjAt */ {AT_TYPE_BOMB, 0x1803E, {0, 0, 0}, 0, 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 */ + {0.0f} +}; + +struct dAcBomc_HIO_c { + static const f32 getBBoxX() { + return 36.f; + } + static const f32 getBBoxY() { + return 66.f; + } + static const f32 getBBoxZ() { + return 6.f; + } + static const f32 getBombScale() { + return 30.f; + } + static const mVec3_c getBBoxMin() { + return mVec3_c(-bbox_x, 0.f, -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 const f32 bbox_min_y; +}; +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); -bool dAcBomb_c::createHeap() {} +void dAcBomb_c::coHitCallback(cCcD_Obj *i_objInfB) { + if (!i_objInfB->ChkCo_0x8000()) { + return; + } + + set0xA3C(FLAG_0x4); + 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(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) && !check0xA3C(FLAG_0x4)) { + if (!(isState(StateID_FlowerWait) || isState(StateID_Explode))) { + cLib::addCalcPosXZ(&field_0xA84, i_objInfA->GetTgAtHitDir() * 0.5f, 0.5f, 10.f, 1.f); + set0xA3C(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.f, 0.f); + setTarget(target); + } else if (i_objInfB->ChkAtType( + AT_TYPE_SWORD | AT_TYPE_0x40 | AT_TYPE_SLINGSHOT | AT_TYPE_0x20000 | AT_TYPE_BEETLE + ) && + check0xA3C(FLAG_0x1000000 | FLAG_0x400000)) { + unset0xA3C(FLAG_0x1000000); + set0xA3C(FLAG_0x400000); + unsetActorProperty(AC_PROP_0x1); + if (isState(StateID_FlowerWait)) { + dAcPy_c::insertOwnedObject(this); + } + if (!check0xA3C(FLAG_0x100) && i_objInfB->ChkAtType(AT_TYPE_SWORD)) { + set0xA3C(FLAG_0x100); + } + } else { + set0xA3C(FLAG_0x4); + setActorProperty(AC_PROP_0x4); + if (i_objInfB->ChkAtType(AT_TYPE_BOMB)) { + set0xA3C(FLAG_0x2); + } + } + } +} + +bool dAcBomb_tgHitCallback(dAcObjBase_c *i_actorA, cCcD_Obj *i_objInfA, dAcObjBase_c *i_actorB, cCcD_Obj *i_objInfB) { + static_cast(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() == BOMB_2) { + mMdl.setPriorityDraw(0x82, 0x7F); + } + return result; +} int dAcBomb_c::create() { + CREATE_ALLOCATOR(dAcBomb_c); + + mAcch.Set(this, 1, &mAcchCir); + mAcch.SetRoofCrrHeight(60.f); + mAcch.SetGndChkOffset(60.f); + mAcch.GetRoof().SetField_0x7C(1); + mAcch.SetWaterCheckOffset(10000.f); + mAcch.SetWtrChkMode(2); + mAcch.ClrWaterNone(); + mAcch.ClrRoofNone(); + mAcch.OnLineCheck(); + + mAcchCir.SetWall(30.f, 30.f); + + if (getBombType() == BOMB_2) { + 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.f, 43.f, 36.f, 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.f; + mVec3_c pos = (mPosition); + mAcch.CrrPos(*dBgS::GetInstance()); + setRoomId(); + + switch (getBombType()) { + case BOMB_0: + case BOMB_4: + case BOMB_6: { + changeState(StateID_Explode); + } break; + case BOMB_3: { + set0xA3C(FLAG_0x200000); + set0xA3C(FLAG_0x1); + if (checkWaterIn()) { + set0xA3C(FLAG_0x20); + mAcceleration = dAcPy_c::getBombAcceleration_1(); + mMaxSpeed = dAcPy_c::getBombMaxSpeed_1(); + } + changeState(StateID_Carry); + } break; + case BOMB_7: { + set0xA3C(FLAG_0x8000000); + changeState(StateID_Carry); + } break; + case BOMB_1: + case BOMB_2: + case BOMB_5: { + mPosition = pos; + changeState(StateID_FlowerWait); + } break; + default: { + changeState(StateID_Wait); + } break; + } + + f32 yOffset = mScale.y * 25.f; + 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(); + field_0xA78 = 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 (field_0xA46 != 0) { + field_0xA46--; + } + + if (mFuseTime > 0) { + bool b = !check0xA3C(FLAG_0x1000000 | FLAG_0x200000 | FLAG_0x800 | FLAG_0x200) && !isState(StateID_Explode); + if (b) { + mFuseTime--; + if (check0xA3C(FLAG_0x8000000 | FLAG_0x800000)) { + s16 explodeTimer = dAcPy_c::getBombExplodeTimer(); + if (mFuseTime == (explodeTimer >> 1) || mFuseTime == (explodeTimer >> 2) || + mFuseTime == (explodeTimer >> 3) || mFuseTime == (explodeTimer >> 4)) { + mFuseTime <<= 1; + } + } + } + } + + if (check0xA3C(FLAG_0x800000 | FLAG_0x800 | FLAG_0x200)) { + return false; + } + + if (mFuseTime == 0 || check0xA3C(FLAG_0x4) || + (mSph.ChkCoHit() && mSph.GetCoActor()->isActorPlayer() && + static_cast(mSph.GetCoActor())->isBurning()) || + (check0xA3C(FLAG_0x2000000) && field_0xA46 == 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 = vec_fn_80259E80; + mWorldMtx.multVec(in, field_0xA54); + field_0xA6C = (field_0xA54 - field_0xA60) * 0.5f; +} + +bool dAcBomb_c::checkWaterIn() { + return check0xA3C(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.f * mScale.y); + m.getTranslation(field_0xA78); + + mPosition = field_0xA78 + out * f; + mPosition.y -= f; +} + +void dAcBomb_c::setPickupTarget() { + if (check0xA3C(FLAG_0x800)) { + return; + } + + AttentionManager::GetInstance()->addPickUpTarget(*this, 120.f); +} + +void dAcBomb_c::lookAt() { + dAcPy_c::GetLink2()->lookTowardItem(mPositionCopy2, 4, 0x5555, 300, 400, -400); +} + +void dAcBomb_c::bounceWall(mAng angle) { + mSpeed *= dAcPy_c::getBombBounceSpeed(); + mBombSpeed *= dAcPy_c::getBombBounceSpeed(); + + mAngle.y = angle - mAng((mAngle.y + 0x8000) - angle); + mBombRotationY = angle - mAng((mBombRotationY + 0x8000) - angle); +} + +void dAcBomb_c::fn_8025A1F0(mVec3_c &out) { + setXYZCirclePoint(out, mAngle.y, mSpeed, mVelocity.y); + + if (field_0xA40 != 0) { + f32 f = MyClamp(field_0xA40 * 0.02f, 0.f, 1.f); + + mVec3_c v; + setXYZCirclePoint(v, mBombRotationY, mBombSpeed, 0.f); + + out = out * (1.f - 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); + field_0xA6C = 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.f; + + mPosition -= out * 25.f; + + } 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::getBombExplodeScale(), dAcPy_c::getBombExplodeScale(), dAcPy_c::getBombExplodeScale()); + 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.f); + } + (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.f); + } + } else if (check0xA3C(FLAG_0x2)) { + (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.f; + mVelocity = mVec3_c::Zero; + mAcceleration = 0.f; + + mSph.ClrTgSet(); + mSph.ClrCoSet(); + if (getBombType() == BOMB_6) { + mSph.ClrAtSet(); + } else { + mSph.OnAtSet(); + } + + if (getBombType() == BOMB_2) { + mSph.SetR(200.f); + } else { + mSph.SetR(dAcPy_c::getBombExplodeScale()); + } + + 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); + mFuseTime = 0; + unsetObjectProperty(OBJ_PROP_0x1000); + + f32 dist = mPosition.squareDistance(pPlayer->mPosition); + if (dist < 160000.f) { + dRumble_c::start(dRumble_c::sRumblePreset3, dRumble_c::FLAG_SLOT0 | dRumble_c::FLAG_ACTIVE); + } else if (dist < 640000.f) { + 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() { + unset0xA3C(FLAG_0x2000000 | FLAG_0x80000 | FLAG_0x40000 | FLAG_0x10000); + field_0xA84 = mVec3_c::Zero; + if (mLinkage.checkConnection(dLinkage_c::CONNECTION_5)) { + set0xA3C(FLAG_0x2000000); + field_0xA46 = 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.f; + mVelocity = mVec3_c::Zero; + + mLinkage.bushTpFunc(mAcch); + setRoomId(); +} +void dAcBomb_c::executeState_Carry() { + dAcPy_c *pPlayer = dAcPy_c::GetLink2(); + + if (checkExplode()) { + unset0xA3C(FLAG_0x8000000 | FLAG_0x1000000 | FLAG_0x200000); + } else { + if (!mLinkage.checkState(dLinkage_c::STATE_ACTIVE)) { + if (check0xA3C(FLAG_0x100000)) { + unset0xA3C(FLAG_0x100000); + mMtx.ZrotS(-mRotation.z); + mMtx.XrotM(-mRotation.x); + mMtx.YrotM(-mRotation.y); + mMtx.concat(mWorldMtx); + mMtx.m[0][3] = 0.f; + mMtx.m[1][3] = 0.f; + mMtx.m[2][3] = 0.f; + } + if (mLinkage.checkState(dLinkage_c::STATE_3)) { + set0xA3C(FLAG_0x80000 | FLAG_0x40000); + mBombRotationY = pPlayer->mRotation.y; + mBombSpeed = mSpeed; + field_0xA40 = 60; + } + unset0xA3C(FLAG_0x8000000 | FLAG_0x1000000 | FLAG_0x200000); + changeState(StateID_Wait); + } else if (!mLinkage.checkConnection(dLinkage_c::CONNECTION_5)) { + unset0xA3C(FLAG_0x2000000 | FLAG_0x1000000); + } + mLinkage.bushTpFunc(mAcch); + setRoomId(); + if (isState(StateID_Carry)) { + mSpeed = 0.f; + 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 (check0xA3C(FLAG_0x4000000)) { + unset0xA3C(FLAG_0x4000000); + set0xA3C(FLAG_0x2000000); + } +} +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 out; + fn_8025A1F0(out); + + s16 s = out.atan2sX_Z(); + f32 d = out.absXZ(); + + s16 out_s; + + if (mAcch.ChkGndHit()) { + mAng a = mAcch.GetGnd().GetAngle(s); + mVelocity.y -= d * std::abs(a.sin()); + + f32 cos = a.cos(); + out.x *= cos; + out.z *= cos; + if (field_0xA40 != 0) { + field_0xA40--; + } + out_s = a; + + } else { + out_s = 0; + } + + f32 acc = mAcceleration; + f32 vely = mVelocity.y; + out.y += mVelocity.y + mAcceleration; + if (out.y < mMaxSpeed) { + out.y = mMaxSpeed; + } + mVelocity.y = out.y; + + mPosition += out + mStts.GetCcMove(); + + if (check0xA3C(FLAG_0x10000) && check0xA3C(FLAG_0x20) && mAcch.ChkWaterHit()) { + if (mAcch.GetWtrGroundH() <= mPosition.y + (mScale.x * 30.f) + 1.f) { + mVelocity.y = 0.f; + mPosition.y = mAcch.GetWtrGroundH() - (mScale.x * 30.f) - 1.f; + } + } + mAcceleration = acc; + f32 f = 1.f; + if (mAcch.ChkGndHit() && field_0xA84.squareMagXY() > 1.f) { + cM3dGPla plane; + dBgS::GetInstance()->GetTriPla(mAcch.GetGnd(), &plane); + + f = plane.GetAngle(field_0xA84.atan2sX_Z()).cos(); + f *= f; + } + + mPosition += (field_0xA84 * f) + field_0xA90; + mAcch.CrrPos(*dBgS::GetInstance()); + f32 f1 = 0.f; + f32 f2 = 4.f; + mVec3_c force = mVec3_c::Zero; + f32 offs = mYOffset; + if (mAcch.ChkGndHit() && !mLinkage.checkState(dLinkage_c::STATE_ACTIVE)) { + s32 attr = dBgS::GetInstance()->GetSpecialCode(mAcch.GetGnd()); + if (attr == POLY_ATTR_CURSED_WATER) { + f1 = -60.f; + if (mYOffset >= 0.f) { + vely *= 0.5f; + mSpeed *= 0.5f; + } + f2 = nw4r::math::FAbs(vely); + mVelocity.y = vely; + 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) { + f1 = -10.f; + f2 = 1.f; + } + if (attr == POLY_ATTR_SAND_DEEP_SLOW || attr == POLY_ATTR_SAND_MED) { + dTgStream_c::getForce(mPosition, force); + } + + cLib::addCalcPosXZ(&field_0xA90, force, 0.5f, 10.f, 3.f); + sLib::chase(&offs, f1, f2); + mYOffset = offs; + if (offs <= -60.f) { + set0xA3C(FLAG_0x1000); + } + setRoomId(); + + if (mAcch.ChkGndHit()) { + cM3dGPla plane; + dBgS::GetInstance()->GetTriPla(mAcch.GetGnd(), &plane); + } + // ... + + if (mAcch.ChkGroundLanding()) { + if (vely < -5.f) { + startSoundWithFloatParam(SE_BM_BOUND, -1.f); + if (dBgS::GetInstance()->GetPolyAtt0(mAcch.GetGnd()) != POLY_ATT_0_LAVA) { + dJEffManager_c::spawnGroundEffect( + mPosition, mPolyAttr0, mPolyAttr1, field_0x1B4, 1, 0.8f, field_0x1B0 + ); + } + } + + // ... + + f32 f3 = dAcPy_c::getBombUnkFloat_0(); + s32 attr = dBgS::GetInstance()->GetSpecialCode(mAcch.GetGnd()); + + if (check0xA3C(FLAG_0x40000) || + ((dAcPy_c::getBombUnkFloat_1() <= f3 && attr != POLY_ATTR_SAND_DEEP_INSTANT) && + attr != POLY_ATTR_CURSED_WATER && attr != POLY_ATTR_SAND_DEEP_SLOW && attr != POLY_ATTR_SAND_MED)) { + mSpeed *= 0.9f; + mBombSpeed *= 0.9f; + } + } + } + + lookAt(); +} +void dAcBomb_c::finalizeState_Wait() { + mSph.SetCoCallback(dAcBomb_coHitCallback); + mSph.OnCoSet(); +} + +void dAcBomb_c::initializeState_FlowerWait() { + set0xA3C(FLAG_0x1000000); + 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(); + + AttentionManager::GetInstance()->addUnk3Target(*this, 1, 250.f, -200.f, 200.f); + 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) && check0xA3C(FLAG_0x1000000))) { + unset0xA3C(FLAG_0x1000000); + } + + if (getBombType() == BOMB_2) { + mStts.SetRank(4); + } else { + mStts.SetRank(5); + } + + unsetActorProperty(AC_PROP_0x1); + mAcch.OnLineCheck(); +} + +void dAcBomb_c::initializeState_WindCarry() { + unset0xA3C(FLAG_0x2000000 | FLAG_0x80000 | FLAG_0x40000 | FLAG_0x10000); + field_0xA84 = mVec3_c::Zero; + mSpeed = 0.f; + mVelocity = mVec3_c::Zero; + mBombSpeed = 0.f; + 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.f; + mVelocity = mVec3_c::Zero; +} +void dAcBomb_c::finalizeState_WindCarry() {} + +void dAcBomb_c::setBombColor() { + mColor clr(0, 0, 0, 0xFF); + if (!check0xA3C(FLAG_0x800)) { + bool b = !check0xA3C(FLAG_0x1000000 | FLAG_0x200000 | FLAG_0x800 | FLAG_0x200) && !isState(StateID_Explode); + if (b) { + mEffect1.holdEffect(PARTICLE_RESOURCE_ID_MAPPING_974_, mWorldMtx, nullptr, nullptr); + if (!check0xA3C(FLAG_0x8000000)) { + 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(mLinkage.getControllingActor())->isPlayer()) + && ((pObj = static_cast(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(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 (field_0xA40 == 0) { + return; + } + mVec3_c v; + setXYZCirclePoint(v, mBombRotationY, mBombSpeed, 0.f); + v += dir; + + v.y = 0.f; + + mBombRotationY = v.atan2sX_Z(); + mBombSpeed = 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); + } +} + +int dAcBomb_c::actorExecute() {} + +int dAcBomb_c::draw() { + if (isState(StateID_Explode) || (getBombType() == BOMB_2 && !dAcPy_c::GetLink()->checkActionFlagsCont(0x400000))) { + return SUCCEEDED; + } + + drawModelType1(&mMdl); + + mQuat_c rot(0.f, mScale.x * sHIO.getBombScale(), 0.f, mScale.x * sHIO.getBombScale()); + + if (!isState(StateID_FlowerWait)) { + drawShadow(mShdw, nullptr, mWorldMtx, &rot, -1, -1, -1, -1, -1, mPosition.y - mAcch.GetGroundH()); + } return SUCCEEDED; }