diff --git a/include/game/bases/d_a_en_bomhei.hpp b/include/game/bases/d_a_en_bomhei.hpp new file mode 100644 index 00000000..a26ad367 --- /dev/null +++ b/include/game/bases/d_a_en_bomhei.hpp @@ -0,0 +1,124 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +/// @brief A bob-omb enemy. +/// @statetable +/// @paramtable +/// @ingroup bases +class daEnBomhei_c : public daEnCarry_c { +public: + /// @brief The different modes for spawning a bob-omb. + enum SpawnMode_e { + SPAWN_MODE_NORMAL, ///< Start walking immediately. + SPAWN_MODE_WAKIDASHI, ///< Walk out of a pipe. + SPAWN_MODE_ICE_LUMP, ///< Stuck in a large ice block. + SPAWN_MODE_CANNON_HOP ///< Shoot out of a cannon. + }; + + daEnBomhei_c() : mExplodeWaitTimer(-1), mExplodeTimer(-1), mFireCoinCount(smc_FireCountCount) {} + virtual ~daEnBomhei_c() {} + + virtual int create(); + virtual int execute(); + virtual int preDraw(); + virtual int draw(); + virtual int doDelete(); + virtual void deleteReady(); + virtual void finalUpdate(); + virtual bool ActorDrawCullCheck(); + virtual void setSpinLiftUpActor(dActor_c *carryingActor); + virtual void Normal_VsEnHitCheck(dCc_c *self, dCc_c *other); + virtual void Normal_VsPlHitCheck(dCc_c *self, dCc_c *other); + virtual void Normal_VsYoshiHitCheck(dCc_c *self, dCc_c *other); + virtual void block_hit_init(); + virtual bool hitCallback_Shell(dCc_c *self, dCc_c *other); + virtual bool hitCallback_Fire(dCc_c *self, dCc_c *other); + virtual bool hitCallback_Ice(dCc_c *self, dCc_c *other); + virtual void returnState_Ice(); + virtual bool hitCallback_HipAttk(dCc_c *self, dCc_c *other); + virtual bool hitCallback_YoshiHipAttk(dCc_c *self, dCc_c *other); + virtual bool hitCallback_Spin(dCc_c *self, dCc_c *other) { return hitCallback_HipAttk(self, other); } + virtual bool createIceActor(); + virtual bool EtcDamageCheck(dCc_c *self, dCc_c *other); + + virtual void boyonBegin() {} + virtual bool isSpinLiftUpEnable() { return isState(StateID_Sleep); } + + STATE_FUNC_DECLARE(daEnBomhei_c, Walk); ///< Walking on the ground. + STATE_FUNC_DECLARE(daEnBomhei_c, Sleep); ///< Sleeping, waiting to explode. + STATE_VIRTUAL_FUNC_DECLARE(daEnBomhei_c, Carry); ///< Being carried by a player. + STATE_FUNC_DECLARE(daEnBomhei_c, Slide); ///< Sliding along the ground after a ground pound. + STATE_FUNC_DECLARE(daEnBomhei_c, Kick); ///< Being kicked by the player. + STATE_FUNC_DECLARE(daEnBomhei_c, KickBom); + STATE_FUNC_DECLARE(daEnBomhei_c, Wakidashi); ///< Moving out of a pipe. + STATE_FUNC_DECLARE(daEnBomhei_c, Explode); ///< Exploding after the timer runs out. + STATE_FUNC_DECLARE(daEnBomhei_c, Turn); ///< Turning around + STATE_FUNC_DECLARE(daEnBomhei_c, CannonHop_Upper); ///< Being shot upwards out of a cannon. + STATE_FUNC_DECLARE(daEnBomhei_c, CannonHop_Under); ///< Being shot downwards out of a cannon. + STATE_FUNC_DECLARE(daEnBomhei_c, AfterIce); + STATE_FUNC_DECLARE(daEnBomhei_c, InIceLump); ///< Stuck in a large ice block. + STATE_VIRTUAL_FUNC_DECLARE(daEnBomhei_c, EatOut); + + virtual void vf28c(); + virtual void modelUpdate(); + virtual void postMdlSetup(); + virtual void initialStateSet(); + virtual void vf29c() {} + + void mdlSetup(); + + void bcSet1(); + void bcSet2(); + void setDeathInfo_Carry(dActor_c *killedBy); + void checkBombBreak(); + void explodeBgUnit(); + mVec2_c getExplodeTilePos(); + void calcIgnitionPos(); + void updateCarryCc(); + + void breakEffect() { mEf::createEffect("Wm_en_bombheibreak", 0, &mIgnitionPos, nullptr, nullptr); } + void explosionEffect() { mEf::createEffect("Wm_en_explosion", 0, &mIgnitionPos, nullptr, nullptr); } + + dHeapAllocator_c mAllocator; + nw4r::g3d::ResFile mFile; + m3d::mdl_c mModel; + m3d::anmChr_c mAnm; + m3d::anmMatClr_c mAnmMat; + int mExplodeWaitTimer; ///< Timer counting down until the bob-omb explodes. + int mExplodeTimer; ///< Timer counting up while exploding. + int mWakidashiTimer; ///< Timer counting down until the bob-omb will beging walking normally. + int mCannonHopDir; + int mCannonHopTimer; + u8 mPad[4]; + mVec3_c mLiftPos; + float mCcOffsetX; + float mCcOffsetY; + float mCcWidth; + float mCcHeight; + int mFireCoinCount; ///< How many more coins can be spawned by hitting the bob-omb with a fireball. + int mCarryingPlayer; + int mUnkTimer; + mVec3_c mIgnitionPos; + mEf::levelEffect_c mEffect; + + ACTOR_PARAM_CONFIG(WakidashiSpawnDir, 0, 2); ///< The direction to move out of the pipe. + ACTOR_PARAM_CONFIG(CannonHopSpawnDir, 4, 2); ///< The direction to shoot out of the cannon. + ACTOR_PARAM_CONFIG(CannonHopType, 6, 1); ///< The trajectory to shoot out of the cannon. 0 is a flat arc, 1 is a high arc. + ACTOR_PARAM_CONFIG(ZLayer, 24, 4); ///< The Z layer to place the bob-omb on. + ACTOR_PARAM_CONFIG(SpawnMode, 28, 2); ///< See SpawnMode_e. + + static const float smc_WalkSpeed; + static const float smc_SlideSpeedX; + static const float smc_KickSpeedX; + static const float smc_KickSpeedY; + static const int smc_ExplodeWaitFrames; + static const int smc_SoundEffectIDs[]; + + static const int smc_FireCountCount = 3; +}; diff --git a/include/game/bases/d_a_fireball_base.hpp b/include/game/bases/d_a_fireball_base.hpp new file mode 100644 index 00000000..518835a1 --- /dev/null +++ b/include/game/bases/d_a_fireball_base.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include +#include + +class daFireBall_Base_c : public dActorState_c { +public: + void kill(); +}; diff --git a/include/game/bases/d_audio.hpp b/include/game/bases/d_audio.hpp index 60507d70..7135601c 100644 --- a/include/game/bases/d_audio.hpp +++ b/include/game/bases/d_audio.hpp @@ -231,6 +231,39 @@ class NMSndObject : public NMSndObjectBase { nw4r::math::VEC2 mPos; }; +template +class NMSndObjectCmn : public NMSndObjectBase { +public: + class SoundHandlePrm : public nw4r::snd::SoundHandle { + public: + SoundHandlePrm() : m_04(1.0f) {} + + float m_04; + }; + + NMSndObjectCmn() : + NMSndObjectBase(NMSndObjectBase::OBJ_TYPE_0, SndAudioMgr::sInstance->mArcPlayer), + m_64(1.0f), m_68(0), m_6c(1.0f), m_70(0.0f) + { + SetPlayableSoundCount(0, T); + mTotalCount = T + 2; + m_58 = 1; + } + + virtual SoundHandlePrm *startSound(unsigned long p1, const nw4r::math::VEC2 &p2, unsigned long p3); + virtual SoundHandlePrm *startSound(unsigned long p1, const nw4r::math::VEC2 &p2, short p3, unsigned long p4); + virtual SoundHandlePrm *holdSound(unsigned long p1, const nw4r::math::VEC2 &p2, unsigned long p3); + virtual SoundHandlePrm *holdSound(unsigned long p1, int p2, const nw4r::math::VEC2 &p3, unsigned long p4); + virtual SoundHandlePrm *holdSound(unsigned long p1, int p2, const nw4r::math::VEC2 &p3, short p4, unsigned long p5); + + float m_64; + int m_68; + float m_6c; + float m_70; + SoundHandlePrm mParams[T + 2]; + nw4r::math::VEC2 mPos; +}; + class SndObjctPly : public NMSndObject<4> { public: void calculate(const nw4r::math::VEC2 &pos) { @@ -260,24 +293,22 @@ class SndObjctEmy : public NMSndObject<4> { virtual SoundHandlePrm *holdSound(ulong p1, const nw4r::math::VEC2 &p2, ulong p3); }; -class SndObjctCmnEmy : public NMSndObject<4> { +class SndObjctCmnEmy : public NMSndObjectCmn<12> { public: - virtual SoundHandlePrm *startSound(ulong p1, ulong p2); - virtual SoundHandlePrm *holdSound(ulong p1, ulong p2); - virtual SoundHandlePrm *startSound(ulong p1, short p2, ulong p3); - virtual SoundHandlePrm *holdSound(ulong p1, short p2, ulong p3); - virtual SoundHandlePrm *startSound(ulong p1, const nw4r::math::VEC2 &p2, ulong p3); - virtual SoundHandlePrm *holdSound(ulong p1, const nw4r::math::VEC2 &p2, ulong p3); + virtual SoundHandlePrm *startSound(unsigned long p1, const nw4r::math::VEC2 &p2, unsigned long p3); + virtual SoundHandlePrm *startSound(unsigned long p1, const nw4r::math::VEC2 &p2, short p3, unsigned long p4); + virtual SoundHandlePrm *holdSound(unsigned long p1, const nw4r::math::VEC2 &p2, unsigned long p3); + virtual SoundHandlePrm *holdSound(unsigned long p1, int p2, const nw4r::math::VEC2 &p3, unsigned long p4); + virtual SoundHandlePrm *holdSound(unsigned long p1, int p2, const nw4r::math::VEC2 &p3, short p4, unsigned long p5); }; -class SndObjctCmnMap : public NMSndObject<4> { +class SndObjctCmnMap : public NMSndObjectCmn<12> { public: - virtual SoundHandlePrm *startSound(ulong p1, ulong p2); - virtual SoundHandlePrm *holdSound(ulong p1, ulong p2); - virtual SoundHandlePrm *startSound(ulong p1, short p2, ulong p3); - virtual SoundHandlePrm *holdSound(ulong p1, short p2, ulong p3); - virtual SoundHandlePrm *startSound(ulong p1, const nw4r::math::VEC2 &p2, ulong p3); - virtual SoundHandlePrm *holdSound(ulong p1, const nw4r::math::VEC2 &p2, ulong p3); + virtual SoundHandlePrm *startSound(unsigned long p1, const nw4r::math::VEC2 &p2, unsigned long p3); + virtual SoundHandlePrm *startSound(unsigned long p1, const nw4r::math::VEC2 &p2, short p3, unsigned long p4); + virtual SoundHandlePrm *holdSound(unsigned long p1, const nw4r::math::VEC2 &p2, unsigned long p3); + virtual SoundHandlePrm *holdSound(unsigned long p1, int p2, const nw4r::math::VEC2 &p3, unsigned long p4); + virtual SoundHandlePrm *holdSound(unsigned long p1, int p2, const nw4r::math::VEC2 &p3, short p4, unsigned long p5); }; namespace dAudio { @@ -340,6 +371,12 @@ namespace dAudio { SoundHandlePrm *startSound(unsigned long soundID, const mVec3_c &pos, int remPlayer) { return SndObjctCmnEmy::startSound(soundID, dAudio::cvtSndObjctPos(pos), remPlayer); } + SoundHandlePrm *holdSound(unsigned long soundID, int i, const nw4r::math::VEC2 &pos, int remPlayer) { + return SndObjctCmnEmy::holdSound(soundID, i, pos, remPlayer); + } + SoundHandlePrm *holdSound(unsigned long soundID, int i, const mVec3_c &pos, int remPlayer) { + return SndObjctCmnEmy::holdSound(soundID, i, dAudio::cvtSndObjctPos(pos), remPlayer); + } }; class SndObjctEmy_c : public SndObjctEmy { @@ -390,20 +427,34 @@ namespace dAudio { obj->startSound(id, dAudio::cvtSndObjctPos(pos), playerNo); } - void playEmySound(const mVec2_c &pos, int playerNo) const { - playObjSound(dAudio::g_pSndObjEmy, pos, playerNo); + template + void holdObjSound(T *obj, int i, const mVec2_c &pos, int playerNo) const { + obj->holdSound(id, i, dAudio::cvtSndObjctPos(pos), playerNo); } - void playEmySound(const mVec3_c &pos, int playerNo) const { + template + void holdObjSound(T *obj, int i, const mVec3_c &pos, int playerNo) const { + obj->holdSound(id, i, dAudio::cvtSndObjctPos(pos), playerNo); + } + + template + void playEmySound(const T &pos, int playerNo) const { playObjSound(dAudio::g_pSndObjEmy, pos, playerNo); } - void playMapSound(const mVec2_c &pos, int playerNo) const { + template + void playMapSound(const T &pos, int playerNo) const { playObjSound(dAudio::g_pSndObjMap, pos, playerNo); } - void playMapSound(const mVec3_c &pos, int playerNo) const { - playObjSound(dAudio::g_pSndObjMap, pos, playerNo); + template + void holdEmySound(int i, const T &pos, int playerNo) const { + holdObjSound(dAudio::g_pSndObjEmy, i, pos, playerNo); + } + + template + void holdMapSound(int i, const T &pos, int playerNo) const { + holdObjSound(dAudio::g_pSndObjMap, i, pos, playerNo); } private: diff --git a/include/game/bases/d_bc.hpp b/include/game/bases/d_bc.hpp index 95c655ea..50bcc5c1 100644 --- a/include/game/bases/d_bc.hpp +++ b/include/game/bases/d_bc.hpp @@ -157,6 +157,7 @@ class dBc_c { u16 getHeadAttr(); short getHeadSakaMoveAngle(u8 direction); void clearBgcSaveAll(); + void checkBombBreak(mVec2_c, mVec2_c); bool getSakaUpDown(u8 direction); short getSakaAngleBySpeed(float); diff --git a/include/game/bases/d_bg.hpp b/include/game/bases/d_bg.hpp index 526d4dff..2f36c7fa 100644 --- a/include/game/bases/d_bg.hpp +++ b/include/game/bases/d_bg.hpp @@ -17,6 +17,16 @@ class dBg_c { }; public: + float getLiquidHeight() const { return mLiquidHeight; } + + float getDispScale() { return mDispScale; } + float getPrevDispScale() { return mPrevDispScale; } + + void setWaterInWave(float x, float y, u8 type); + float getLeftLimit(); + float getRightLimit(); + void BgUnitChange(u16, u16, int, u16); + u8 mPad1[0x8fe70]; float m_8fe00; u8 mPad2[0x2c]; @@ -34,14 +44,5 @@ class dBg_c { u8 mPad7[0x1a]; u8 m_9008e; - float getLiquidHeight() const { return mLiquidHeight; } - - void setWaterInWave(float x, float y, u8 type); - float getLeftLimit(); - float getRightLimit(); - - float getDispScale() { return mDispScale; } - float getPrevDispScale() { return mPrevDispScale; } - static dBg_c *m_bg_p; }; diff --git a/include/game/bases/d_cc.hpp b/include/game/bases/d_cc.hpp index 002e9ef7..82dc4f76 100644 --- a/include/game/bases/d_cc.hpp +++ b/include/game/bases/d_cc.hpp @@ -23,6 +23,7 @@ enum CC_STATUS_FLAG_e { */ CC_STATUS_NO_PASS_INFO = BIT_FLAG(2), CC_STATUS_8 = BIT_FLAG(8), + CC_STATUS_9 = BIT_FLAG(9), }; ///< @unofficial @@ -44,8 +45,8 @@ enum CC_KIND_e { CC_KIND_ITEM, CC_KIND_TAMA, CC_KIND_KILLER, - CC_KIND_GOAL_POLE, - CC_KIND_COUNT = CC_KIND_GOAL_POLE // Goal pole is special and doesn't count + CC_KIND_COUNT, + CC_KIND_GOAL_POLE = CC_KIND_COUNT ///< [Unsure why this goes above the count] }; ///< @unofficial diff --git a/include/game/bases/d_en_boyo_manager.hpp b/include/game/bases/d_en_boyo_manager.hpp index 83ab1695..20f48aa6 100644 --- a/include/game/bases/d_en_boyo_manager.hpp +++ b/include/game/bases/d_en_boyo_manager.hpp @@ -21,7 +21,6 @@ class dEnBoyoMng_c { float mFactorDelta; int mCounter; dActor_c *mpOwner; - u8 mDirection; static float smc_DELTA_SCALE; static int smc_BOYON_TIME; diff --git a/include/game/bases/d_enemy.hpp b/include/game/bases/d_enemy.hpp index fdb30668..bc63b10c 100644 --- a/include/game/bases/d_enemy.hpp +++ b/include/game/bases/d_enemy.hpp @@ -282,6 +282,7 @@ class dEn_c : public dActorMultiState_c { bool mFootAttr1; u8 mPad3[5]; dEnBoyoMng_c mBoyoMng; + u8 mIceDirection; dIceMng_c mIceMng; ///< The ice manager for this enemy. float mAirAccelY; ///< The Y acceleration before entering a liquid. float mAirSpeedMaxY; ///< The maximum Y speed before entering a liquid. diff --git a/include/game/bases/d_enemy_manager.hpp b/include/game/bases/d_enemy_manager.hpp index 2573dfa3..9da5587a 100644 --- a/include/game/bases/d_enemy_manager.hpp +++ b/include/game/bases/d_enemy_manager.hpp @@ -12,9 +12,11 @@ class dEnemyMng_c { u8 mPad1[0x138]; int m_138; - u8 mPad2[0x18]; - int m_154; + u8 mPad2[0x10]; + int mBomheiCount; u8 mPad3[0x4]; + int m_154; + u8 mPad4[0x4]; int m_15c; static dEnemyMng_c *m_instance; diff --git a/include/game/bases/d_ice_manager.hpp b/include/game/bases/d_ice_manager.hpp index d0f2cc7c..cd4bf2a7 100644 --- a/include/game/bases/d_ice_manager.hpp +++ b/include/game/bases/d_ice_manager.hpp @@ -20,7 +20,7 @@ class dIceEfScale_c { class dIceInfo { public: - ~dIceInfo(); + ~dIceInfo() {} int mMode; mVec3_c mPos; diff --git a/include/game/mLib/m_3d/anm_mat_clr.hpp b/include/game/mLib/m_3d/anm_mat_clr.hpp index d5aec51e..6bbdbb57 100644 --- a/include/game/mLib/m_3d/anm_mat_clr.hpp +++ b/include/game/mLib/m_3d/anm_mat_clr.hpp @@ -6,6 +6,8 @@ namespace m3d { class anmMatClr_c : public banm_c { public: + anmMatClr_c() : children(nullptr) {} + virtual ~anmMatClr_c(); virtual void remove(); virtual void play(); diff --git a/include/game/mLib/m_angle.hpp b/include/game/mLib/m_angle.hpp index 339cdc6e..9504b1cf 100644 --- a/include/game/mLib/m_angle.hpp +++ b/include/game/mLib/m_angle.hpp @@ -29,6 +29,10 @@ struct mAng { return sLib::chase(&mAngle, target, step); } + BOOL chaseAngle(short target, short step) { + return sLib::chaseAngle(&mAngle, target, step); + } + int abs() const { return ::abs(mAngle); } diff --git a/include/game/mLib/m_effect.hpp b/include/game/mLib/m_effect.hpp index 608fd824..9b5dfcc6 100644 --- a/include/game/mLib/m_effect.hpp +++ b/include/game/mLib/m_effect.hpp @@ -1,6 +1,6 @@ #pragma once #include -#include +#include #include #include diff --git a/include/lib/egg/util/eggEffect.hpp b/include/lib/egg/util/eggEffect.h similarity index 100% rename from include/lib/egg/util/eggEffect.hpp rename to include/lib/egg/util/eggEffect.h diff --git a/include/lib/egg/util/eggEffectManager.hpp b/include/lib/egg/util/eggEffectManager.h similarity index 100% rename from include/lib/egg/util/eggEffectManager.hpp rename to include/lib/egg/util/eggEffectManager.h diff --git a/slices/d_enemiesNP.json b/slices/d_enemiesNP.json index eb3c3c8f..2e69129f 100644 --- a/slices/d_enemiesNP.json +++ b/slices/d_enemiesNP.json @@ -48,6 +48,16 @@ ".bss": "0x0-0x8" } }, + { + "source": "d_enemiesNP/bases/d_a_en_bomhei.cpp", + "memoryRanges": { + ".text": "0x25fa0-0x2b0e0", + ".ctors": "0x60-0x64", + ".data": "0x80c0-0x8838", + ".rodata": "0x10b8-0x1330", + ".bss": "0x1618-0x1998" + } + }, { "source": "d_enemiesNP/bases/d_a_en_noko.cpp", "memoryRanges": { diff --git a/source/d_enemiesNP/bases/d_a_en_bomhei.cpp b/source/d_enemiesNP/bases/d_a_en_bomhei.cpp new file mode 100644 index 00000000..bc0e523e --- /dev/null +++ b/source/d_enemiesNP/bases/d_a_en_bomhei.cpp @@ -0,0 +1,1306 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +ACTOR_PROFILE(EN_BOMHEI, daEnBomhei_c, 0x12); + +STATE_DEFINE(daEnBomhei_c, Walk); +STATE_DEFINE(daEnBomhei_c, Sleep); +STATE_VIRTUAL_DEFINE(daEnBomhei_c, Carry); +STATE_DEFINE(daEnBomhei_c, Slide); +STATE_DEFINE(daEnBomhei_c, Kick); +STATE_DEFINE(daEnBomhei_c, KickBom); +STATE_DEFINE(daEnBomhei_c, Wakidashi); +STATE_DEFINE(daEnBomhei_c, Explode); +STATE_DEFINE(daEnBomhei_c, Turn); +STATE_DEFINE(daEnBomhei_c, CannonHop_Upper); +STATE_DEFINE(daEnBomhei_c, CannonHop_Under); +STATE_DEFINE(daEnBomhei_c, AfterIce); +STATE_DEFINE(daEnBomhei_c, InIceLump); +STATE_VIRTUAL_DEFINE(daEnBomhei_c, EatOut); + +const float daEnBomhei_c::smc_WalkSpeed = 0.5f; +const float daEnBomhei_c::smc_SlideSpeedX = 4.0f; +const float daEnBomhei_c::smc_KickSpeedX = 2.5f; +const float daEnBomhei_c::smc_KickSpeedY = 2.0f; +const int daEnBomhei_c::smc_ExplodeWaitFrames = 240; + +const sBcSensorPoint l_bomhei_head = { SENSOR_IS_POINT, 0x0, 0x10000 }; +const sBcSensorLine l_bomhei_foot = { SENSOR_IS_LINE, -0x3000, 0x3000, 0 }; +const sBcSensorPoint l_bomhei_wall = { SENSOR_IS_POINT, 0x6000, 0x6000 }; +const sBcSensorPoint l_bomhei_4 = { 0x40000, 0, 0x10000 }; +const sBcSensorPoint l_bomhei_5 = { 0x40000, 0, 0 }; +const sBcSensorPoint l_bomhei_6 = { 0x40000, 0x6000, 0x6000 }; +const sBcSensorLine l_bomhei_7 = { 0x82000001, -0x6000, 0x6000, 0x10000 }; +const u32 l_unused1[] = { 0, 0 }; +const sBcSensorLine l_bomhei_8 = { 0x82000001, -0x6000, 0x6000, 0 }; +const u32 l_unused2[] = { 0, 0 }; +const sBcSensorLine l_bomhei_9 = { 0x82000001, 0xE000, 0x3000, 0x8000 }; +const u32 l_unused3[] = { 0, 0 }; + +int unused() { + return l_unused1[0] + l_unused2[0] + l_unused3[0]; +} + +const sCcDatNewF l_bomhei_cc = { + 0.0f, 8.0f, + 8.0f, 8.0f, + CC_KIND_ENEMY, + CC_ATTACK_NONE, + BIT_FLAG(CC_KIND_PLAYER) | BIT_FLAG(CC_KIND_PLAYER_ATTACK) | BIT_FLAG(CC_KIND_YOSHI) | + BIT_FLAG(CC_KIND_ENEMY) | BIT_FLAG(CC_KIND_ITEM) | BIT_FLAG(CC_KIND_TAMA), + (u32) ~BIT_FLAG(CC_ATTACK_NONE) & ~BIT_FLAG(CC_ATTACK_YOSHI_MOUTH) & ~BIT_FLAG(CC_ATTACK_SAND_PILLAR), + CC_STATUS_NONE, + dEn_c::normal_collcheck, +}; + +const short l_turn_angleY_add[] = { 0x400, -0x400 }; + +int daEnBomhei_c::create() { + mdlSetup(); + mScale.set(1.0f, 1.0f, 1.0f); + mSpeedMax.set(0.0f, -4.0f, 0.0f); + mVisibleAreaOffset.set(0.0f, 8.0f); + mVisibleAreaSize.set(16.0f, 16.0f); + mCenterOffs.set(0.0f, 8.0f, 0.0f); + + mBc.set(this, l_bomhei_foot, l_bomhei_head, l_bomhei_wall); + mBc.m_4c = mPos.x; + mCc.set(this, (sCcDatNewF *) &l_bomhei_cc); + mCc.entry(); + + mEatBehavior = EAT_TYPE_DRINK; + mFlags = EN_IS_HARD; + + if (ACTOR_PARAM(SpawnMode) != SPAWN_MODE_ICE_LUMP) { + dEnemyMng_c::m_instance->mBomheiCount++; + } + initialStateSet(); + + return SUCCEEDED; +} + +void daEnBomhei_c::initialStateSet() { + if (ACTOR_PARAM(SpawnMode) == SPAWN_MODE_WAKIDASHI) { + changeState(StateID_Wakidashi); + } else if (ACTOR_PARAM(SpawnMode) == SPAWN_MODE_ICE_LUMP) { + changeState(StateID_InIceLump); + } else if (ACTOR_PARAM(SpawnMode) == SPAWN_MODE_CANNON_HOP) { + int spawnDir = ACTOR_PARAM(CannonHopSpawnDir); + mCannonHopDir = spawnDir; + mDirection = spawnDir & 1; + mAngle.y = l_base_angleY[mDirection]; + if (spawnDir == 0 || spawnDir == 1) { + // up-right or up-left + changeState(StateID_CannonHop_Upper); + } else { + // down-right or down-left + changeState(StateID_CannonHop_Under); + } + } else { + mDirection = getPl_LRflag(mPos); + mAngle.y = l_base_angleY[mDirection]; + changeState(StateID_Walk); + } +} + +void daEnBomhei_c::mdlSetup() { + mAllocator.createFrmHeap(-1, mHeap::g_gameHeaps[0], nullptr, 0x20); + + mFile = dResMng_c::m_instance->getRes("bombhei", "g3d/bombhei.brres"); + nw4r::g3d::ResMdl resMdl = mFile.GetResMdl("bombhei"); + mModel.create(resMdl, &mAllocator, 0x128, 1, nullptr); + + setSoftLight_Enemy(mModel); + nw4r::g3d::ResAnmChr anmChr = mFile.GetResAnmChr("walk"); + mAnm.create(resMdl, anmChr, &mAllocator, nullptr); + + nw4r::g3d::ResAnmClr anmClr = mFile.GetResAnmClr("bombhei"); + mAnmMat.create(resMdl, anmClr, &mAllocator, nullptr, 1); + + mModel.setAnm(mAnmMat); + mAnmMat.setPlayMode(m3d::FORWARD_ONCE, 0); + mAnmMat.setFrame(0.0f, 0); + + postMdlSetup(); + mAllocator.adjustFrmHeap(); +} + +void daEnBomhei_c::postMdlSetup() {} + +int daEnBomhei_c::execute() { + mStateMgr.executeState(); + if (!isState(StateID_InIceLump)) { + if (!isState(StateID_Ice)) { + if (mExplodeWaitTimer > 0) { + mAnmMat.play(); + dAudio::SoundEffectID_t(SE_EMY_BH_HIBANA).holdEmySound(mUniqueID, mPos, 0); + } + if (mUnkTimer > 0) { + mUnkTimer--; + } + if (HasamareBgCheck() || EnLavaCheck(mPos)) { + changeState(StateID_Explode); + } + } + ActorScrOutCheck(0); + } + return SUCCEEDED; +} + +int daEnBomhei_c::preDraw() { + if (dEn_c::preDraw() == NOT_READY) { + return NOT_READY; + } + + if (isState(StateID_Explode)) { + return NOT_READY; + } + + return SUCCEEDED; +} + +int daEnBomhei_c::draw() { + mModel.entry(); + return SUCCEEDED; +} + +void daEnBomhei_c::modelUpdate() { + mVec3_c pos = mPos; + mAng3_c angle = mAngle; + if (isState(StateID_Carry)) { + pos = calcCarryPos(mLiftPos); + mPos.x = pos.x; + mPos.y = pos.y; + } + + changePosAngle(&pos, &angle, 1); + mMatrix.trans(pos.x, pos.y, pos.z); + mMatrix.YrotM(angle.y); + + mMatrix.concat(mMtx_c::createTrans(0.0f, 8.0f, 0.0f)); + mMatrix.XrotM(angle.x); + mMatrix.concat(mMtx_c::createTrans(0.0f, -8.0f, 0.0f)); + + mMatrix.concat(mMtx_c::createTrans(0.0f, 16.0f, 0.0f)); + mMatrix.ZrotM(angle.z); + mMatrix.concat(mMtx_c::createTrans(0.0f, -16.0f, 0.0f)); + + mModel.setLocalMtx(&mMatrix); + mModel.setScale(mScale); + mModel.calc(false); + + calcIgnitionPos(); +} + +void daEnBomhei_c::deleteReady() {} + +int daEnBomhei_c::doDelete() { + for (int i = 0; i < PLAYER_COUNT; i++) { + dAcPy_c *player = daPyMng_c::getPlayer(i); + if (player != nullptr && fManager_c::searchBaseByID(player->mCarryActorID) == this) { + player->cancelCarry(this); + } + } + + if (ACTOR_PARAM(SpawnMode) != SPAWN_MODE_ICE_LUMP) { + dEnemyMng_c::m_instance->mBomheiCount--; + if (dEnemyMng_c::m_instance->mBomheiCount < 0) { + dEnemyMng_c::m_instance->mBomheiCount = 0; + } + } + + return SUCCEEDED; +} + +void daEnBomhei_c::finalUpdate() { + modelUpdate(); +} + +bool daEnBomhei_c::ActorDrawCullCheck() { + if (isState(StateID_Carry)) { + return false; + } + return dActor_c::ActorDrawCullCheck(); +} + +void daEnBomhei_c::calcIgnitionPos() { + nw4r::g3d::ResNode resNode = mModel.getResMdl().GetResNode("skl_root"); + mMtx_c mtx; + mModel.getNodeWorldMtx(resNode.GetID(), &mtx); + mtx.multVecZero(mIgnitionPos); +} + +void daEnBomhei_c::updateCarryCc() { + bool dir = mAngle.y < 0 ? 1 : 0; + + static const float sc_carryOffsetX[] = { -8.0f, 8.0f }; + + mVec3_c centerPos( + getCenterPos().x + sc_carryOffsetX[dir], + getCenterPos().y, + getCenterPos().z + ); + + mVec3_c v2( + centerPos.x + l_EnMuki[dir] * 16.0f, + centerPos.y, + centerPos.z + ); + + mCc.mCcData.mBase.mOffset.set(mCcOffsetX, mCcOffsetY); + mCc.mCcData.mBase.mSize.set(mCcWidth, mCcHeight); + float f = 0.0f; + if (dBc_c::checkWall(¢erPos, &v2, &f, mLayer, 1, nullptr)) { + float f1 = (centerPos.x + f) * 0.5f; + float f2 = (centerPos.x - f) * 0.5f; + mCc.mCcData.mBase.mOffset.set(f1 - mPos.x, 8.0f); + mCc.mCcData.mBase.mSize.set(std::fabs(f2), 8.0f); + } +} + +void daEnBomhei_c::setSpinLiftUpActor(dActor_c *carryingActor) { + int plrNo = carryingActor->getPlrNo(); + mPlayerNo = plrNo; + mCarryingPlayer = plrNo; + mLiftPos.set(0.0f, 0.0f, 0.0f); + changeState(StateID_Carry); +} + +void daEnBomhei_c::Normal_VsPlHitCheck(dCc_c *self, dCc_c *other) { + dAcPy_c *player = (dAcPy_c *) other->mpOwner; + if (fManager_c::searchBaseByID(player->mCarryActorID) == this) { + return; + } + + u8 newDir = self->mCollOffsetX[CC_KIND_PLAYER] >= 0.0f ? 0 : 1; + u8 plrNo = player->getPlrNo(); + if (isState(StateID_Sleep)) { + if (carry_check(player)) { + mCarryingPlayer = plrNo; + mLiftPos.set(0.0f, -5.0f, 6.0f); + changeState(StateID_Carry); + } else { + mDirection = newDir; + mNoHitPlayer.mTimer[plrNo] = 32; + dAudio::SoundEffectID_t(SE_EMY_KAME_KERU).playEmySound(getCenterPos(), dAudio::getRemotePlayer(plrNo)); + mPlayerNo = plrNo; + mBc.mOwningPlrNo = plrNo; + changeState(StateID_Kick); + } + } else if (isState(StateID_Slide) || isState(StateID_Kick)) { + mDirection = newDir; + mNoHitPlayer.mTimer[plrNo] = 32; + dAudio::SoundEffectID_t(SE_EMY_KAME_KERU).playEmySound(getCenterPos(), dAudio::getRemotePlayer(plrNo)); + mPlayerNo = plrNo; + mBc.mOwningPlrNo = plrNo; + changeState(StateID_Kick); + } else { + int checkRes = Enfumi_check(self, other, 0); + if (checkRes == 0) { + if (!isState(StateID_Wakidashi) && !isState(StateID_Carry)) { + dEn_c::Normal_VsPlHitCheck(self, other); + } + } else if (checkRes == 1) { + mPlayerNo = plrNo; + mBc.mOwningPlrNo = plrNo; + if (isState(StateID_Carry)) { + changeState(StateID_Kick); + } else { + vf28c(); + } + } else if (checkRes == 3) { + mDirection = newDir; + mPlayerNo = plrNo; + mBc.mOwningPlrNo = plrNo; + if (mExplodeWaitTimer < 0) { + mExplodeWaitTimer = smc_ExplodeWaitFrames; + mAnmMat.setFrame(0.0f, 0); + } + vf29c(); + changeState(StateID_Slide); + } + } +} + +void daEnBomhei_c::Normal_VsYoshiHitCheck(dCc_c *self, dCc_c *other) { + daYoshi_c *yoshi = (daYoshi_c *) other->mpOwner; + u8 newDir = self->mCollOffsetX[CC_KIND_YOSHI] >= 0.0f ? 0 : 1; + u8 plrNo = yoshi->getPlrNo(); + + if (Enfumi_check(self, other, 0) == 0) { + if (isState(StateID_Sleep) || isState(StateID_Slide) || isState(StateID_Kick)) { + if (plrNo < PLAYER_COUNT) { + mDirection = newDir; + mPlayerNo = plrNo; + mNoHitPlayer.mTimer[plrNo] = 32; + mBc.mOwningPlrNo = plrNo; + dAudio::SoundEffectID_t(SE_EMY_KAME_KERU).playEmySound(getCenterPos(), dAudio::getRemotePlayer(plrNo)); + changeState(StateID_Kick); + } + } else { + dEn_c::Normal_VsYoshiHitCheck(self, other); + } + } else if (!isState(StateID_Explode)) { + setDeathInfo_YoshiFumi(yoshi); + } +} + +void daEnBomhei_c::Normal_VsEnHitCheck(dCc_c *self, dCc_c *other) { + u16 flag = other->mCcData.mStatus; + dActor_c *enemy = other->getOwner(); + + if (flag & CC_STATUS_9) { + self->mInfo |= CC_NO_HIT; + if (!isState(StateID_Explode)) { + changeState(StateID_Explode); + } + } else if (self->mCcData.mAttack == CC_ATTACK_SHELL && (flag & CC_STATUS_8) && hitCallback_Shell(self, other)) { + other->mInfo |= CC_NO_HIT; + self->mInfo |= CC_NO_HIT; + } else if ( + isState(StateID_Carry) && (other->mCcData.mVsDamage & BIT_FLAG(CC_ATTACK_SHELL)) && + enemy->mProfName != fProfile::EN_HATENA_BALLOON && hitCallback_Shell(self, other) + ) { + other->mInfo |= CC_NO_HIT; + } else if (isState(StateID_Walk)) { + float offsetX = self->mCollOffsetX[CC_KIND_ENEMY]; + + if ((mDirection == DIR_LR_L && offsetX > 0.0f) || (mDirection == DIR_LR_R && offsetX < 0.0f)) { + changeState(StateID_Turn); + } + } else { + dEn_c::Normal_VsEnHitCheck(self, other); + } +} + +void daEnBomhei_c::vf28c() { + if (isState(StateID_Wakidashi)) { + float f = l_EnMuki[mDirection ^ 1]; + mBc.checkWall(&f); + } + + mSpeed.set(0.0f, 0.0f, 0.0f); + vf29c(); + + if (mExplodeWaitTimer < 0) { + mExplodeWaitTimer = smc_ExplodeWaitFrames; + mAnmMat.setFrame(0.0f, 0); + changeState(StateID_Sleep); + } +} + +void daEnBomhei_c::block_hit_init() { + mVec3_c efPos(mVec2_c(mPos.x, mPos.y), 5500.0f); + + hitdamageEffect(efPos); + dAudio::SoundEffectID_t(SE_EMY_DOWN).playEmySound(mPos, 0); + + mDirection = mDeathFallDirection; + mSpeed.set(l_base_fall_speed_x[mDirection], 3.0f, 0.0f); + vf29c(); + + if (mExplodeWaitTimer < 0) { + mExplodeWaitTimer = smc_ExplodeWaitFrames; + mAnmMat.setFrame(0.0f, 0); + changeState(StateID_Sleep); + } +} + +bool daEnBomhei_c::hitCallback_Shell(dCc_c *self, dCc_c *other) { + dActor_c *shell = other->getOwner(); + u8 dir = getTrgToSrcDir_Main( + getCenterX(), + shell->getCenterX() + ); + int plrNo = acmShellPlayerNo(shell); + shellDamageEffect(self, shell); + int comboScore = -1; + + if ((u32) plrNo < PLAYER_COUNT) { + int shortCombo = 0; + if (mCombo.mType == 2) { + shortCombo = 1; + } + shell->slideComboSE(shell->mComboMultiplier, shortCombo); + shell->mComboMultiplier++; + if (shell->mComboMultiplier >= 8) { + shell->mComboMultiplier = 8; + } + comboScore = mCombo.getComboScore(shell->mComboMultiplier); + } else { + dAudio::SoundEffectID_t(SE_EMY_DOWN).playEmySound(mPos, 0); + } + + mDeathInfo = (sDeathInfoData) { + l_base_fall_speed_x[dir], + smc_DEADFALL_YSPEED, + smc_DEADFALL_YSPEED_MAX, + smc_DEADFALL_GRAVITY, + &StateID_DieFall, + comboScore, + -1, + dir, + (u8) plrNo + }; + + return true; +} + +bool daEnBomhei_c::hitCallback_Fire(dCc_c *self, dCc_c *other) { + dActor_c *fire = other->getOwner(); + u8 dir = !(fire->mSpeed.x >= 0.0f); + mDirection = dir; + mAngle.y = l_base_angleY[dir]; + mSpeed.x = l_EnMuki[dir] * smc_WalkSpeed; + mSpeed.y = 1.5f; + mSpeedMax.x = 0.0f; + dAudio::SoundEffectID_t(SE_EMY_DOWN).playEmySound(mPos, 0); + + if (--mFireCoinCount >= 0) { + dActorMng_c::m_instance->createUpCoin(getCenterPos(), dir, 1, 0); + } + vf29c(); + + if (mExplodeWaitTimer < 0) { + mExplodeWaitTimer = smc_ExplodeWaitFrames; + mAnmMat.setFrame(0.0f, 0); + changeState(StateID_Sleep); + } + + return true; +} + +bool daEnBomhei_c::hitCallback_Ice(dCc_c *self, dCc_c *other) { + if (mIceMng.mActive) { + return true; + } + + dActor_c *player = (dActor_c *) other->getOwner(); + if (player->mSpeed.x >= 0.0f) { + mIceDirection = DIR_LR_R; + } else { + mIceDirection = DIR_LR_L; + } + + mAnmMat.setFrame(0.0f, 0); + + for (int i = 0; i < PLAYER_COUNT; i++) { + dAcPy_c *pl = daPyMng_c::getPlayer(i); + if (pl != nullptr && fManager_c::searchBaseByID(pl->mCarryActorID) == this) { + pl->cancelCarry(this); + } + } + mIceMng.mPlrNo = player->getPlrNo(); + changeState(StateID_Ice); + + mExplodeWaitTimer = -1; + mPlayerNo = -1; + + return true; +} + +void daEnBomhei_c::returnState_Ice() { + mPlayerNo = -1; + changeState(StateID_AfterIce); +} + +bool daEnBomhei_c::hitCallback_HipAttk(dCc_c *self, dCc_c *other) { + dActor_c *otherActor = other->getOwner(); + u8 plrNo = otherActor->getPlrNo(); + + if (plrNo >= PLAYER_COUNT) { + return true; + } + if (mNoHitPlayer.mTimer[plrNo] != 0) { + return true; + } + + if (mPos.x >= otherActor->mPos.x) { + mDirection = DIR_LR_R; + } else { + mDirection = DIR_LR_L; + } + + mPlayerNo = plrNo; + dAudio::SoundEffectID_t(SE_EMY_DOWN).playEmySound(mPos, 0); + hipatkEffect(otherActor->mPos); + mNoHitPlayer.mTimer[mPlayerNo] = 16; + if (mExplodeWaitTimer < 0) { + mExplodeWaitTimer = smc_ExplodeWaitFrames; + mAnmMat.setFrame(0.0f, 0); + } + vf29c(); + changeState(StateID_Slide); + + return true; +} + +bool daEnBomhei_c::hitCallback_YoshiHipAttk(dCc_c *self, dCc_c *other) { + if (!isState(StateID_Explode)) { + dAudio::SoundEffectID_t(SE_EMY_YOSHI_HPDP).playEmySound(mPos, 0); + setDeathInfo_YoshiFumi(other->getOwner()); + return true; + } + + return false; +} + +bool daEnBomhei_c::createIceActor() { + mVec3_c pos, size; + if (isState(StateID_Walk) || isState(StateID_Turn)) { + pos.set(mPos.x, mPos.y - 2.0f, mPos.z); + size.set(1.25f, 1.25f, 1.25f); + } else { + pos.set(mPos.x, mPos.y - 2.0f, 2.0f + mPos.z); + size.set(1.25f, 1.25f, 1.5f); + } + + dIceInfo iceInfo[] = { + { + 0, + pos, + size + } + }; + return mIceMng.createIce(iceInfo, ARRAY_SIZE(iceInfo)); +} + +bool daEnBomhei_c::EtcDamageCheck(dCc_c *self, dCc_c *other) { + if (dEn_c::EtcDamageCheck(self, other)) { + return true; + } + + dActor_c *otherActor = other->getOwner(); + daEnBomhei_c *selfActor = (daEnBomhei_c *) self->getOwner(); + if (other->mCcData.mStatus & CC_STATUS_9) { + self->mInfo |= CC_NO_HIT; + if (!selfActor->isState(StateID_Explode)) { + selfActor->changeState(StateID_Explode); + } + return true; + } else if (otherActor->mProfName == fProfile::PAKKUN_FIREBALL || otherActor->mProfName == fProfile::BROS_FIREBALL) { + if (selfActor->mExplodeWaitTimer < 0) { + selfActor->mExplodeWaitTimer = smc_ExplodeWaitFrames; + selfActor->mAnmMat.setFrame(0.0f, 0); + selfActor->changeState(StateID_Sleep); + } + daFireBall_Base_c *fireball = (daFireBall_Base_c *) otherActor; + fireball->kill(); + return true; + } + + return false; +} + +void daEnBomhei_c::bcSet1() { + mBc.set(this, l_bomhei_5, l_bomhei_4, l_bomhei_6); + mBc.mOwningPlrNo = mPlayerNo; +} + +void daEnBomhei_c::bcSet2() { + mBc.set(this, l_bomhei_foot, l_bomhei_head, l_bomhei_wall); +} + +void daEnBomhei_c::setDeathInfo_Carry(dActor_c *killedBy) { + mDeathInfo = (sDeathInfoData) { + 0.0f, + 3.0f, + -4.0f, + -0.1875f, + &StateID_DieFall, + -1, + -1, + mDirection, + (u8) killedBy->getPlrNo() + }; +} + +void daEnBomhei_c::checkBombBreak() { + mVec2_c v1, v2; + + static const float offsets[2][2] = { + { 40.0f, -24.0f }, + { 24.0f, -40.0f } + }; + + v1.x = mPos.x + offsets[mDirection][1]; + v1.y = mPos.y + 15.0f; + v2.x = mPos.x + offsets[mDirection][0]; + v2.y = mPos.y + 1.0f; + mBc.checkBombBreak(v1, v2); + + v1.x = mPos.x - 8.0f; + v1.y = mPos.y + 31.0f; + v2.x = mPos.x + 8.0f; + v2.y = mPos.y - 15.0f; + mBc.checkBombBreak(v1, v2); +} + +void daEnBomhei_c::explodeBgUnit() { + mVec2_c pos = getExplodeTilePos(); + for (int i = 0; i < 2; i++) { + int unitType = dBc_c::getUnitType(pos.x, pos.y, mLayer); + if (unitType & 0x1c) { + short x, y; + y = -pos.y; + x = pos.x; + dBg_c::m_bg_p->BgUnitChange(x, y, 0, 0); + } + pos.x += l_EnMuki[mDirection] * 16.0f; + } +} + +mVec2_c daEnBomhei_c::getExplodeTilePos() { + if (mExplodeTimer >= 9) { + return mVec2_c(0.0f, 0.0f); + } + + static const float xOffsets[] = { + -16.0f, 0.0f, 16.0f, + -16.0f, 0.0f, 16.0f, + -16.0f, 0.0f, 16.0f + }; + static const float yOffsets[] = { + 16.0f, 16.0f, 16.0f, + 0.0f, 0.0f, 0.0f, + -16.0f, -16.0f, -16.0f + }; + + int tileX = mPos.x / 16; + int tileY = mPos.y / 16; + float x = tileX * 16.0f; + float y = tileY * 16.0f; + x += xOffsets[mExplodeTimer]; + y += yOffsets[mExplodeTimer]; + return mVec2_c(x, y); +} + +void explosionCallback(dCc_c *self, dCc_c *other) { + dActor_c *selfActor = self->getOwner(); + dActor_c *otherActor = other->getOwner(); + if (otherActor->mKind == dActor_c::STAGE_ACTOR_PLAYER || otherActor->mKind == dActor_c::STAGE_ACTOR_YOSHI) { + daPlBase_c *player = (daPlBase_c *) otherActor; + player->setDamage(selfActor, daPlBase_c::DAMAGE_DEFAULT); + } +} + +void daEnBomhei_c::initializeState_Walk() { + if ( + *mStateMgr.getOldStateID() != StateID_AfterIce && + *mStateMgr.getOldStateID() != StateID_CannonHop_Upper && + *mStateMgr.getOldStateID() != StateID_CannonHop_Under + ) { + nw4r::g3d::ResAnmChr anm = mFile.GetResAnmChr("walk"); + mAnm.setAnm(mModel, anm, m3d::FORWARD_LOOP); + mModel.setAnm(mAnm, 2.0f); + mAnm.setRate(1.0f); + } + + static const float dirSpeed[] = { smc_WalkSpeed, -smc_WalkSpeed }; + + mFlags &= ~0x10000; + mSpeed.x = dirSpeed[mDirection]; + mPos.z = 1500.0f + ACTOR_PARAM(ZLayer) * 16.0f; + mPlayerNo = -1; + mBc.mOwningPlrNo = -1; +} + +void daEnBomhei_c::finalizeState_Walk() {} + +void daEnBomhei_c::executeState_Walk() { + mModel.play(); + calcSpeedY(); + posMove(); + + EnBgCheckFoot(); + if (mBc.isFoot()) { + mSpeed.y = 0.0f; + } + + mBc.checkHead(mBc.mFlags); + + EnBgCheckWall(); + + WaterCheck(mPos, 1.0f); + if (mBc.mFlags & 0x15 << mDirection) { + changeState(StateID_Turn); + } +} + +void daEnBomhei_c::initializeState_Turn() { + mSpeed.x = 0.0f; + mDirection ^= 1; +} + +void daEnBomhei_c::finalizeState_Turn() {} + +void daEnBomhei_c::executeState_Turn() { + mModel.play(); + calcSpeedY(); + posMove(); + + EnBgCheckFoot(); + if (mBc.isFoot()) { + mAnm.setRate(1.0f); + mSpeed.y = 0.0f; + } + + mBc.checkHead(mBc.mFlags); + + EnBgCheckWall(); + + WaterCheck(mPos, 1.0f); + + mAngle.y += l_turn_angleY_add[mDirection]; + int angleY = l_base_angleY[mDirection]; + + int abs1 = abs(angleY); + int abs2 = abs(mAngle.y); + if (abs2 >= abs1) { + mAngle.y = angleY; + changeState(StateID_Walk); + } +} + +void daEnBomhei_c::initializeState_Sleep() { + nw4r::g3d::ResAnmChr anm = mFile.GetResAnmChr("stop"); + mAnm.setAnm(mModel, anm, m3d::FORWARD_LOOP); + mModel.setAnm(mAnm, 2.0f); + mAnm.setRate(1.0f); + mFlags &= ~0x10000; + mAngle.y = l_base_angleY[mDirection]; +} + +void daEnBomhei_c::finalizeState_Sleep() {} + +void daEnBomhei_c::executeState_Sleep() { + mModel.play(); + calcSpeedY(); + posMove(); + + EnBgCheckFoot(); + if (mBc.isFoot()) { + Bound(0.1875f, 0.5f, 0.5f); + } + + mBc.checkHead(0); + + EnBgCheckWall(); + if (mBc.mFlags & 0x3c000000) { + if (mSpeed.y > 0.0f) { + mSpeed.y = -0.85f * mSpeed.y; + } + } + if (mBc.mFlags & 0x3f) { + mSpeed.x = 0.0f; + } + + mEffect.createEffect("Wm_en_bombignition", 0, &mIgnitionPos, nullptr, nullptr); + mExplodeWaitTimer--; + if (mExplodeWaitTimer <= 0) { + changeState(StateID_Explode); + } +} + +void daEnBomhei_c::initializeState_Carry() { + nw4r::g3d::ResAnmChr anm = mFile.GetResAnmChr("carry"); + mAnm.setAnm(mModel, anm, m3d::FORWARD_LOOP); + mModel.setAnm(mAnm, 2.0f); + mAnm.setRate(1.0f); + + mPlayerNo = mCarryingPlayer; + dAcPy_c *player = daPyMng_c::getPlayer(mCarryingPlayer); + if (player->mAmiLayer == 1) { + mAmiLayer = 0; + } else { + mAmiLayer = 1; + } + + float x = mCc.mCcData.mBase.mOffset.x; + float y = mCc.mCcData.mBase.mOffset.y; + float width = mCc.mCcData.mBase.mSize.x; + float height = mCc.mCcData.mBase.mSize.y; + mCcOffsetX = x; + mCcOffsetY = y; + mCcWidth = width; + mCcHeight = height; + mCc.mAmiLine = l_Ami_Line[mAmiLayer]; + mBc.mAmiLine = l_Ami_Line[mAmiLayer]; + mCc.mCcData.mVsKind |= BIT_FLAG(CC_KIND_KILLER) | BIT_FLAG(CC_KIND_BALLOON); + mCc.mCcData.mAttack = CC_ATTACK_SHELL; + mRc.setRide(nullptr); + mActorProperties &= ~0x2; +} + +void daEnBomhei_c::finalizeState_Carry() { + dAcPy_c *player = daPyMng_c::getPlayer(mCarryingPlayer); + player->cancelCarry(this); + mCc.mCcData.mVsKind &= ~BIT_FLAG(CC_KIND_KILLER); + mCc.mCcData.mAttack = CC_ATTACK_NONE; + mCc.mCcData.mBase.mOffset.set(mCcOffsetX, mCcOffsetY); + mCc.mCcData.mBase.mSize.set(mCcWidth, mCcHeight); + mRc.setRide(nullptr); + mBc.mFlags = 0; + mCarryingFlags &= ~(CARRY_RELEASE | CARRY_THROW); + mActorProperties |= 0x2; + mAngle.y = l_base_angleY[mDirection]; +} + +void daEnBomhei_c::executeState_Carry() { + dAcPy_c *player = daPyMng_c::getPlayer(mCarryingPlayer); + mModel.play(); + mEffect.createEffect("Wm_en_bombignition", 0, &mIgnitionPos, nullptr, nullptr); + + mExplodeWaitTimer--; + if (mExplodeWaitTimer <= 0) { + mDirection = player->mDirection; + if (checkWallAndBg()) { + setDeathInfo_Carry(player); + } else { + changeState(StateID_Explode); + } + } else if (mCarryingFlags & CARRY_RELEASE) { + mDirection = mThrowDirection; + mAngle.y = l_base_angleY[mDirection]; + if (checkWallAndBg()) { + setDeathInfo_Carry(player); + return; + } + if ((mBc.mFlags & 0x15 << mDirection) == 0) { + mPos.x += l_EnMuki[mDirection] * 6.0f; + } + if (mCarryingFlags & CARRY_THROW) { + changeState(StateID_Slide); + } else { + changeState(StateID_Sleep); + } + } else { + mAngle.y = player->mAngle.y; + WaterCheck(mPos, 1.0f); + } + updateCarryCc(); +} + +void daEnBomhei_c::initializeState_Slide() { + nw4r::g3d::ResAnmChr anm = mFile.GetResAnmChr("stop"); + mAnm.setAnm(mModel, anm, m3d::FORWARD_LOOP); + mModel.setAnm(mAnm, 2.0f); + mAnm.setRate(1.0f); + + static const float dirSpeed[] = { smc_SlideSpeedX, -smc_SlideSpeedX }; + clrComboCnt(); + mAccelF = 0.0625f; + mSpeed.x = dirSpeed[mDirection]; + mSpeedMax.x = 0.0f; + mAngle.y = l_base_angleY[mDirection]; + mNoHitPlayer.mTimer[mPlayerNo] = 10; + mCc.mCcData.mAttack = CC_ATTACK_SHELL; + bcSet1(); +} + +void daEnBomhei_c::finalizeState_Slide() { + clrComboCnt(); + mAccelF = 0.0f; + mSpeedMax.x = 0.0f; + bcSet2(); + mCc.mCcData.mAttack = CC_ATTACK_NONE; +} + +void daEnBomhei_c::executeState_Slide() { + mModel.play(); + calcSpeedX(); + calcSpeedY(); + posMove(); + + u32 bcFlags = EnBgCheckFoot(); + if (mBc.isFoot()) { + Bound(0.1875f, 1.0f, 0.5f); + if (std::fabs(mSpeed.x) > 0.2f) { + mVec3_c efPos(mPos.x, mPos.y, 5500.0f); + mEf::createEffect("Wm_en_landsmoke_s", 0, &efPos, nullptr, nullptr); + } + } + + mBc.checkHead(bcFlags); + + EnBgCheckWall(); + if (mBc.mFlags & 0x15 << mDirection) { + mDirection ^= 1; + mAngle.y = l_base_angleY[mDirection]; + mSpeed.x = -mSpeed.x * smc_WalkSpeed; + } + + mEffect.createEffect("Wm_en_bombignition", 0, &mIgnitionPos, nullptr, nullptr); + + WaterCheck(mPos, 1.0f); + + mExplodeWaitTimer--; + if (mExplodeWaitTimer <= 0) { + changeState(StateID_Explode); + } else if (mSpeed.x == 0.0f) { + changeState(StateID_Sleep); + } +} + +void daEnBomhei_c::initializeState_Kick() { + static const float dirSpeed[] = { smc_KickSpeedX, -smc_KickSpeedX }; + + mSpeed.set(dirSpeed[mDirection], smc_KickSpeedY, 0.0f); + mAngle.y = l_base_angleY[mDirection]; + clrComboCnt(); + mAccelY = -0.1875f; + mCc.mCcData.mAttack = CC_ATTACK_SHELL; +} + +void daEnBomhei_c::finalizeState_Kick() { + clrComboCnt(); + mCc.mCcData.mAttack = CC_ATTACK_NONE; +} + +void daEnBomhei_c::executeState_Kick() { + calcSpeedY(); + posMove(); + + u32 bcFlags = EnBgCheckFoot(); + if (mBc.isFoot()) { + Bound(0.1875f, 0.5f, 0.5f); + } + + mBc.checkHead(bcFlags); + + EnBgCheckWall(); + if (bcFlags != 0) { + if (std::fabs(mSpeed.x) > 0.2f) { + mVec3_c efPos(mPos.x, mPos.y, 5500.0f); + mEf::createEffect("Wm_en_landsmoke_s", 0, &efPos, nullptr, nullptr); + } + } + if (mBc.mFlags & 0x3c000000) { + if (mSpeed.y > 0.0f) { + mSpeed.y = -0.85f * mSpeed.y; + } + } + if (mBc.mFlags & 0x15 << mDirection) { + mDirection = mDirection ^ 1; + mAngle.y = l_base_angleY[mDirection]; + mSpeed.x = -mSpeed.x; + } + + mEffect.createEffect("Wm_en_bombignition", 0, &mIgnitionPos, nullptr, nullptr); + + WaterCheck(mPos, 1.0f); + + mExplodeWaitTimer--; + if (mExplodeWaitTimer <= 0) { + changeState(StateID_Explode); + } else if (mSpeed.x == 0.0f) { + changeState(StateID_Sleep); + } +} + +void daEnBomhei_c::initializeState_KickBom() { + static const float dirSpeed[] = { smc_KickSpeedX, -smc_KickSpeedX }; + + mSpeed.set(dirSpeed[mDirection], 2.0f, 0.0f); + mAngle.y = l_base_angleY[mDirection]; + clrComboCnt(); + mAccelY = -0.1875f; + mCc.mCcData.mAttack = CC_ATTACK_SHELL; + m_23b = 1; +} + +void daEnBomhei_c::finalizeState_KickBom() { + clrComboCnt(); + mCc.mCcData.mAttack = CC_ATTACK_NONE; +} + +void daEnBomhei_c::executeState_KickBom() { + calcSpeedY(); + posMove(); + + u32 bcFlags = EnBgCheckFoot(); + mBc.checkHead(bcFlags); + EnBgCheckWall(); + if (mBc.mFlags & 0x15 << mDirection) { + mDirection = mDirection ^ 1; + mAngle.y = l_base_angleY[mDirection]; + mSpeed.x = -mSpeed.x; + } + + WaterCheck(mPos, 1.0f); + + switch (m_23b) { + case 1: + if (bcFlags != 0) { + mSpeed.y = 1.0f; + m_23b = 2; + } + break; + case 2: + if (bcFlags != 0) { + changeState(StateID_Explode); + } + break; + } +} + +void daEnBomhei_c::initializeState_Wakidashi() { + nw4r::g3d::ResAnmChr anm = mFile.GetResAnmChr("walk"); + mAnm.setAnm(mModel, anm, m3d::FORWARD_LOOP); + mModel.setAnm(mAnm, 2.0f); + mAnm.setRate(2.0f); + + u8 wakidashiDir = ACTOR_PARAM(WakidashiSpawnDir); + if (wakidashiDir & 2) { + mDirection = (wakidashiDir & 1) ^ 1; + } else { + mDirection = getPl_LRflag(mPos); + } + + static const float speedX[] = { 0.0f, 0.0f, -smc_WalkSpeed, smc_WalkSpeed }; + static const float speedY[] = { smc_WalkSpeed, -smc_WalkSpeed, 0.0f, 0.0f }; + + mAngle.y = l_base_angleY[mDirection]; + mSpeed.set(speedX[wakidashiDir], speedY[wakidashiDir], 0.0f); + mFlags |= 0x10000; + mWakidashiTimer = 32; + mCc.mCcData.mVsKind &= ~BIT_FLAG(CC_KIND_ENEMY); + mCc.mCcData.mVsDamage &= ~BIT_FLAG(CC_ATTACK_FIREBALL); +} + +void daEnBomhei_c::finalizeState_Wakidashi() { + mCc.mCcData.mVsKind |= BIT_FLAG(CC_KIND_ENEMY); + mPos.z = 1500.0f; + mCc.mCcData.mVsDamage |= BIT_FLAG(CC_ATTACK_FIREBALL); +} + +void daEnBomhei_c::executeState_Wakidashi() { + mModel.play(); + dBaseActor_c::posMove(); + mWakidashiTimer--; + if (mWakidashiTimer == 0) { + changeState(StateID_Walk); + } +} + +void daEnBomhei_c::initializeState_CannonHop_Upper() { + nw4r::g3d::ResAnmChr anm = mFile.GetResAnmChr("walk"); + mAnm.setAnm(mModel, anm, m3d::FORWARD_LOOP); + mModel.setAnm(mAnm, 0.0f); + mAnm.setRate(2.0f); + + static const float speedX[2][2] = { + {1.5f, -1.5f}, + {1.3f, -1.3f} + }; + static const float speedY[] = { 2.25f, 4.5f }; + + mAccelY = -0.1875f; + mSpeed.set( + speedX[ACTOR_PARAM(CannonHopType)][mDirection], + speedY[ACTOR_PARAM(CannonHopType)], + 0.0f + ); + mBc.set(this, l_bomhei_8, l_bomhei_7, l_bomhei_9); + mCannonHopTimer = 8; + m_23b = 1; +} + +void daEnBomhei_c::finalizeState_CannonHop_Upper() { + mBc.set(this, l_bomhei_foot, l_bomhei_head, l_bomhei_wall); +} + +void daEnBomhei_c::executeState_CannonHop_Upper() { + mModel.play(); + calcSpeedY(); + posMove(); + + switch (m_23b) { + case 1: + mBc.checkWall(nullptr); + mBc.checkHead(0); + mCannonHopTimer--; + if (mCannonHopTimer <= 0) { + mBc.set(this, l_bomhei_foot, l_bomhei_head, l_bomhei_wall); + m_23b = 2; + } + break; + case 2: + if (mBc.checkFootEnm()) { + mAnm.setRate(1.0f); + changeState(StateID_Walk); + } else if (mBc.checkWall(nullptr)) { + mSpeed.x = -mSpeed.x; + changeState(StateID_Turn); + } + break; + } +} + +void daEnBomhei_c::initializeState_CannonHop_Under() { + nw4r::g3d::ResAnmChr anm = mFile.GetResAnmChr("walk"); + mAnm.setAnm(mModel, anm, m3d::FORWARD_LOOP); + mModel.setAnm(mAnm, 0.0f); + mAnm.setRate(1.0f); + mAnm.setRate(2.0f); + + static const float speedX[] = { 1.25f, -1.25f }; + + mAccelY = -0.1875f; + mSpeed.set(speedX[mDirection], -0.75f, 0.0f); + mCannonHopTimer = 8; + mBc.set(this, l_bomhei_8, l_bomhei_7, l_bomhei_9); + m_23b = 1; +} + +void daEnBomhei_c::finalizeState_CannonHop_Under() { + mBc.set(this, l_bomhei_foot, l_bomhei_head, l_bomhei_wall); +} + +void daEnBomhei_c::executeState_CannonHop_Under() { + mModel.play(); + calcSpeedY(); + posMove(); + + switch (m_23b) { + case 1: + mBc.checkWall(nullptr); + mBc.checkHead(0); + mCannonHopTimer--; + if (mCannonHopTimer <= 0) { + mBc.set(this, l_bomhei_foot, l_bomhei_head, l_bomhei_wall); + m_23b = 2; + } + break; + case 2: + if (mBc.checkFootEnm()) { + mAnm.setRate(1.0f); + changeState(StateID_Walk); + } else if (mBc.checkWall(nullptr)) { + mSpeed.x = -mSpeed.x; + changeState(StateID_Turn); + } + break; + } +} + +void daEnBomhei_c::initializeState_AfterIce() { + mAnmMat.setFrame(0.0f, 0); + m_23b = 1; +} + +void daEnBomhei_c::finalizeState_AfterIce() {} + +void daEnBomhei_c::executeState_AfterIce() { + calcSpeedY(); + posMove(); + if (mBc.checkWall(nullptr)) { + mSpeed.x = -mSpeed.x; + } + + switch (m_23b) { + case 1: + if (mBc.checkFootEnm()) { + nw4r::g3d::ResAnmChr anm = mFile.GetResAnmChr("walk"); + mAnm.setAnm(mModel, anm, m3d::FORWARD_LOOP); + mModel.setAnm(mAnm, 5.0f); + mAnm.setRate(1.0f); + mSpeed.set(0.0f, 0.0f, 0.0f); + mDirection = getPl_LRflag(mPos); + m_23b = 2; + } + break; + case 2: + mModel.play(); + if (mBc.checkFootEnm()) { + mSpeed.y = 0.0f; + } + if (mAngle.y.chaseAngle(l_base_angleY[mDirection], 0x400)) { + changeState(StateID_Walk); + } + break; + } +} + +void daEnBomhei_c::initializeState_EatOut() { + dEn_c::initializeState_EatOut(); + nw4r::g3d::ResAnmChr anm = mFile.GetResAnmChr("stop"); + mAnm.setAnm(mModel, anm, m3d::FORWARD_LOOP); + mModel.setAnm(mAnm, 0.0f); + mAnm.setRate(1.0f); +} + +void daEnBomhei_c::finalizeState_EatOut() { + dEn_c::finalizeState_EatOut(); +} + +void daEnBomhei_c::executeState_EatOut() { + mEffect.createEffect("Wm_en_bombignition", 0, &mIgnitionPos, nullptr, nullptr); + mExplodeWaitTimer--; + if (mExplodeWaitTimer <= 0) { + changeState(StateID_Explode); + } else { + dEn_c::executeState_EatOut(); + } +} + +void daEnBomhei_c::initializeState_Explode() { + explosionEffect(); + breakEffect(); + dAudio::SoundEffectID_t(SE_EMY_BH_BOMB).playEmySound(mPos, 0); + mCc.mCcData.mBase.mOffset.x = 0.0f; + mCc.mCcData.mBase.mOffset.y = 0.0f; + mCc.mCcData.mBase.mSize.x = 18.0f; + mCc.mCcData.mBase.mSize.y = 18.0f; + mCc.mCcData.mAttack = CC_ATTACK_SHELL; + mCc.mCcData.mVsKind |= BIT_FLAG(CC_KIND_PLAYER) | BIT_FLAG(CC_KIND_PLAYER_ATTACK) | BIT_FLAG(CC_KIND_YOSHI) | + BIT_FLAG(CC_KIND_ENEMY) | BIT_FLAG(CC_KIND_TAMA) | BIT_FLAG(CC_KIND_KILLER); + mCc.mCcData.mVsDamage = 0; + mCc.mCcData.mStatus |= CC_STATUS_NO_REVISION; + mCc.mCcData.mCallback = explosionCallback; + + mExplodeWaitTimer = 0; + mAngle.y = l_base_angleY[mDirection]; + mPos.y += 8.0f; + checkBombBreak(); +} + +void daEnBomhei_c::finalizeState_Explode() {} + +void daEnBomhei_c::executeState_Explode() { + mExplodeTimer++; + if (mExplodeTimer < 9) { + explodeBgUnit(); + } else if (mExplodeTimer == 16) { + deleteActor(true); + } +} + +void daEnBomhei_c::initializeState_InIceLump() { + mAngle.x = dGameCom::rndInt(9) * 0x1000 - 0x4000; + mAngle.y = dGameCom::rndInt(9) * 0x1000 - 0x4000; + mAngle.z = dGameCom::rndInt(9) * 0x1000 - 0x4000; + mCc.release(); +} + +void daEnBomhei_c::finalizeState_InIceLump() {} + +void daEnBomhei_c::executeState_InIceLump() {} + +const int daEnBomhei_c::smc_SoundEffectIDs[] = { + SE_EMY_YOSHI_HPDP, + SE_EMY_DOWN, + SE_EMY_KAME_KERU, + SE_EMY_BH_HIBANA, + SE_EMY_BH_BOMB +}; diff --git a/source/dol/bases/d_a_en_shell.cpp b/source/dol/bases/d_a_en_shell.cpp index b3619f47..8d0a00a8 100644 --- a/source/dol/bases/d_a_en_shell.cpp +++ b/source/dol/bases/d_a_en_shell.cpp @@ -757,9 +757,9 @@ bool daEnShell_c::hitCallback_Ice(dCc_c *self, dCc_c *other) { } if (other->mpOwner->mSpeed.x >= 0.0f) { - mBoyoMng.mDirection = DIR_LR_R; + mIceDirection = DIR_LR_R; } else { - mBoyoMng.mDirection = DIR_LR_L; + mIceDirection = DIR_LR_L; } for (int i = 0; i < PLAYER_COUNT; i++) { dAcPy_c *player = daPyMng_c::getPlayer(i); diff --git a/source/dol/bases/d_enemy_death.cpp b/source/dol/bases/d_enemy_death.cpp index 75491736..8eea1c62 100644 --- a/source/dol/bases/d_enemy_death.cpp +++ b/source/dol/bases/d_enemy_death.cpp @@ -381,9 +381,9 @@ bool dEn_c::hitCallback_Ice(dCc_c *self, dCc_c *other) { daPlBase_c *player = (daPlBase_c *) other->getOwner(); if (player->mSpeed.x >= 0.0f) { - mBoyoMng.mDirection = 0; + mIceDirection = 0; } else { - mBoyoMng.mDirection = 1; + mIceDirection = 1; } for (int i = 0; i < PLAYER_COUNT; i++) { diff --git a/source/dol/bases/d_last_actor.cpp b/source/dol/bases/d_last_actor.cpp index aef85198..647a2ce9 100644 --- a/source/dol/bases/d_last_actor.cpp +++ b/source/dol/bases/d_last_actor.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include BASE_PROFILE(LASTACTOR, dLastActor_c); diff --git a/syms.txt b/syms.txt index 62c168ef..a7d64331 100644 --- a/syms.txt +++ b/syms.txt @@ -32,6 +32,7 @@ getType__Q23m3d8anmChr_cCFv=0x8002A210 getStarCount__10daPlBase_cCFv=0x8002D970 refreshState__99sStateStateMgr_c<18dActorMultiState_c,12sFStateMgr_c,20sStateMethodUsr_FI_c,20sStateMethodUsr_FI_c>Fv=0x80034700 getStateID__82sStateMgr_c<13dActorState_c,20sStateMethodUsr_FI_c,12sFStateFct_c,13sStateIDChk_c>CFv=0x80040BC0 +kill__17daFireBall_Base_cFv=0x80040EC0 __dt__18dCircleLightMask_cFv=0x800414A0 setDemoMode__13daPyDemoMng_cFQ213daPyDemoMng_c6Mode_ei=0x8005B5C0 setGoalDemoList__13daPyDemoMng_cFi=0x8005B780 @@ -150,6 +151,8 @@ checkTenjou__5dBc_cFPC7mVec3_cPfUcUc=0x80075CA0 checkWall__5dBc_cFPC7mVec3_cPC7mVec3_cPfUcUcPP8dActor_c=0x80075FD0 checkWaterDepth__5dBc_cFffUcUcPf=0x80076530 checkWireNet__5dBc_cFffUc=0x800767F0 +checkBombBreak__5dBc_cF7mVec2_c7mVec2_c=0x800768D0 +BgUnitChange__5dBg_cFUsUsiUs=0x80077860 setWaterInWave__5dBg_cFffUc=0x80078410 getLeftLimit__5dBg_cFv=0x80078A70 getRightLimit__5dBg_cFv=0x80078C10 @@ -435,6 +438,16 @@ fade__Q23mEf13levelEffect_cFv=0x8016D6B0 kill__Q23mEf13levelEffect_cFv=0x8016D6C0 follow__Q23mEf13levelEffect_cFPC7mVec3_cPC7mAng3_cPC7mVec3_c=0x8016D6D0 follow__Q23mEf13levelEffect_cFPC6mMtx_c=0x8016D720 +setCurrentHeap__5mHeapFPQ23EGG4Heap=0x8016E630 +createExpHeap__5mHeapFUlPQ23EGG4HeapPCcUlQ25mHeap13AllocOptBit_t=0x8016E640 +createFrmHeap__5mHeapFUlPQ23EGG4HeapPCcUlQ25mHeap13AllocOptBit_t=0x8016E770 +destroyFrmHeap__5mHeapFPQ23EGG7FrmHeap=0x8016E880 +adjustFrmHeap__5mHeapFPQ23EGG7FrmHeap=0x8016E8A0 +frmHeapCost__5mHeapFUlUl=0x8016E910 +saveCurrentHeap__4mHeapFv=0x8016EAB0 +saveCurrentHeap__5mHeapFv=0x8016EAB0 +restoreCurrentHeap__5mHeapFv=0x8016EAC0 +createFrmHeapToCurrent__5mHeapFUlPQ23EGG4HeapPCcUlQ25mHeap13AllocOptBit_t=0x8016EAF0 create__4mPadFv=0x8016F330 beginPad__4mPadFv=0x8016F360 endPad__4mPadFv=0x8016F550 @@ -448,6 +461,7 @@ __dt__15NMSndObjectBaseFv=0x801974C0 sendRemote__15NMSndObjectBaseFPQ34nw4r3snd11SoundHandleUlUl=0x80197540 vf1C__15NMSndObjectBaseFUli=0x801976B0 startSound__14SndObjctCmnEmyFUlRCQ34nw4r4math4VEC2Ul=0x80198040 +holdSound__14SndObjctCmnEmyFUliRCQ34nw4r4math4VEC2Ul=0x801987A0 startSound__14SndObjctCmnMapFUlRCQ34nw4r4math4VEC2Ul=0x80198D70 startSound__11SndObjctPlyFUlUl=0x8019A0F0 holdSound__11SndObjctPlyFUlUl=0x8019A1E0 @@ -561,6 +575,7 @@ SinFIdx__Q24nw4r4mathFf=0x80237D10 CosFIdx__Q24nw4r4mathFf=0x80237D80 GetResMdl__Q34nw4r3g3d7ResFileCFPCc=0x80239F70 GetResAnmChr__Q34nw4r3g3d7ResFileCFPCc=0x8023A1F0 +GetResAnmClr__Q34nw4r3g3d7ResFileCFPCc=0x8023A2D0 GetResAnmTexPat__Q34nw4r3g3d7ResFileCFPCc=0x8023A340 GetResAnmTexSrt__Q34nw4r3g3d7ResFileCFPCc=0x8023A3B0 Bind__Q34nw4r3g3d7ResFileFQ34nw4r3g3d7ResFile=0x8023A490