#include "d/t/d_t_insect.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_insect_butterfly.h" #include "d/a/d_a_item.h" #include "d/a/d_a_itembase.h" #include "d/a/obj/d_a_obj_base.h" #include "d/a/obj/d_a_obj_soil.h" #include "d/a/obj/d_a_obj_warp.h" #include "d/col/bg/d_bg_s.h" #include "d/col/bg/d_bg_s_gnd_chk.h" #include "d/col/bg/d_bg_s_lin_chk.h" #include "d/flag/itemflag_manager.h" #include "d/flag/sceneflag_manager.h" #include "d/flag/storyflag_manager.h" #include "f/f_base.h" #include "f/f_manager.h" #include "f/f_profile.h" #include "f/f_profile_name.h" #include "m/m_angle.h" #include "m/m_vec.h" #include "nw4r/math/math_geometry.h" #include "nw4r/math/math_types.h" #include "rvl/MTX/mtx.h" SPECIAL_ACTOR_PROFILE(TAG_INSECT, dTgInsect_c, fProfile::TAG_INSECT, 0x167, 0, 0); STATE_DEFINE(dTgInsect_c, Wait); STATE_DEFINE(dTgInsect_c, WaitCreate); STATE_DEFINE(dTgInsect_c, WaitForceEscape); STATE_DEFINE(dTgInsect_c, End); static const s32 unused[] = { 0x001E0100, 0, 0, 0, 0, 0, 0, 0, }; const f32 dTgInsect_c::SCALE_X = 100; const f32 dTgInsect_c::SCALE_Y = 100; static const f32 unused2[] = {150, 0.5f}; const s32 *useUnused() { return unused + (s32)unused2; } int dTgInsect_c::actorCreate() { if (getSubtype() == SUBTYPE_INVALID0) { return FAILED; } if (getSubtype() == SUBTYPE_INVALID1) { return FAILED; } if (getSubtype() == SUBTYPE_INVALID2) { return FAILED; } mInsectCount = getInsectCount(); if (mInsectCount > 0xF) { mInsectCount = 0xF; } else { if (mInsectCount == 0xF) { mInsectCount = 1; } } mScale *= 0.01f; mRevealed = 0; mRevealedSpawnPos = mPosition; if (isTrialGateType() || isGossipStoneType() || isGoddessWallType() || isSpawnSubtype(SPAWN_BUG_MINIGAME)) { field_0x24e = 1; } return SUCCEEDED; } inline bool checkProfile(u16 prof, u32 target) { return prof == target; } int dTgInsect_c::actorPostCreate() { Subtype subtype = getSubtype(); // ??? doesn't match without the double comparison if (subtype == SUBTYPE_WOODLAND_RHINO_BEETLE || subtype == SUBTYPE_WOODLAND_RHINO_BEETLE || subtype == SUBTYPE_SAND_CICADA || subtype == SUBTYPE_VOLCANIC_LADYBUG || subtype == SUBTYPE_SKY_STAG_BEETLE) { if (!checkValidSpawnLocation(mPosition, 1)) { return FAILED; } } dAcBase_c *obj = nullptr; do { obj = searchNextActor(obj); if (obj == nullptr) { break; } u16 prof = obj->mProfileName; if (( checkProfile(prof, fProfile::OBJ_TUBO) || checkProfile(prof, fProfile::OBJ_CARRY_STONE) || checkProfile(prof, fProfile::OBJ_OCT_GRASS_LEAF) || checkProfile(prof, fProfile::OBJ_FRUIT) || checkProfile(prof, fProfile::OBJ_BARREL) || checkProfile(prof, fProfile::OBJ_VSD) || checkProfile(prof, fProfile::OBJ_SOIL) ) && getSquareDistanceTo(obj->mPosition) < 25) { if (subtype == SUBTYPE_FARON_GRASSHOPPER || subtype == SUBTYPE_SKYLOFT_MANTIS || subtype == SUBTYPE_LANAYRU_ANT || subtype == SUBTYPE_EDLIN_ROLLER) { if (prof == fProfile::OBJ_SOIL && static_cast(obj)->isStateHole()) { return FAILED; } setActorRef(obj); } break; } } while (true); if (mActorNode.isLinked()) { mStateMgr.changeState(StateID_WaitCreate); } else { if (isSpawnSubtype(SPAWN_BUG_MINIGAME)) { for (s32 i = 0; i < (s32)ARRAY_LENGTH(field_0x1f8); i++) { field_0x1f8[i] = 0; } mStateMgr.changeState(StateID_Wait); } else if (isTrialGateType()) { dAcOWarp_c *warp = static_cast(fManager_c::searchBaseByProfName(fProfile::OBJ_WARP)); if (warp == nullptr) { return FAILED; } if (!warp->checkThisHasSongItem() || warp->isTrialComplete()) { return FAILED; } if ((warp->mPosition - mPosition).squareMagXZ() < 1000000.f) { mWarpRef.link(warp); } else { return FAILED; } mStateMgr.changeState(StateID_WaitForceEscape); } else if (isGossipStoneType()) { if (!ItemflagManager::sInstance->getFlagDirect(ITEM_BALLAD_OF_THE_GODDESS)) { return FAILED; } if (!StoryflagManager::sInstance->getFlag(STORYFLAG_IMPRISONED_1_DEFEATED)) { return FAILED; } if (SceneflagManager::sInstance->checkBoolFlag(mRoomID, mParams >> 0xC & 0xFF)) { return FAILED; } } else if (isGoddessWallType()) { if (!ItemflagManager::sInstance->getFlagDirect(ITEM_BALLAD_OF_THE_GODDESS)) { return FAILED; } if (!StoryflagManager::sInstance->getFlag(STORYFLAG_FARON_TRIAL_COMPLETE)) { return FAILED; } mStateMgr.changeState(StateID_WaitForceEscape); } else { mStateMgr.changeState(StateID_End); } spawnAll(); } return SUCCEEDED; } int dTgInsect_c::doDelete() { return SUCCEEDED; } int dTgInsect_c::actorExecute() { mStateMgr.executeState(); return SUCCEEDED; } int dTgInsect_c::draw() { return SUCCEEDED; } void dTgInsect_c::initializeState_Wait() {} #pragma opt_strength_reduction off void dTgInsect_c::executeState_Wait() { if (isSpawnSubtype(SPAWN_BUG_MINIGAME)) { s32 i = 0; for (; i < mInsectCount; i++) { if (!mLinks[i].isLinked()) { if (mInsectRespawnTimers[i] > 0) { mInsectRespawnTimers[i]--; } else if (mInsectRespawnTimers[i] == 0) { nw4r::math::MTX34 mtx; MTXTrans(mtx, mPosition.x, mPosition.y, mPosition.z); nw4r::math::MTX34 scale; MTXScale(scale, mScale.x, mScale.y, mScale.x); MTXConcat(mtx, scale, mtx); nw4r::math::AABB aabb(-100, 0, -100, 100, 100, 100); aabb.Set(&aabb, &mtx); if (fn_801BB750(&aabb, 10000)) { spawnInsect(i); } } else { mInsectRespawnTimers[i] = 900; } } } } } #pragma opt_strength_reduction on void dTgInsect_c::finalizeState_Wait() {} void dTgInsect_c::initializeState_WaitCreate() { if (!isSpawnSubtype(SPAWN_BUG_MINIGAME)) { field_0x24f = 1; for (s32 i = 0; i < mInsectCount; i++) { mShouldSpawn[i] = shouldSpawn(); } } } void dTgInsect_c::executeState_WaitCreate() { if (mActorNode.isLinked()) { if (mActorNode.get()->mProfileName == fProfile::OBJ_VSD || mActorNode.get()->mProfileName == fProfile::OBJ_SOIL) { if (mRevealed == 0) { return; } } else { if (mPosition.squareDistanceToXZ(mActorNode.get()->mPosition) < 25) { return; } } } mActorNode.unlink(); for (s32 i = 0; i < mInsectCount; i++) { if (!isSpawnSubtype(SPAWN_BUG_MINIGAME)) { if (mShouldSpawn[i] != 0) { mShouldSpawn[i] = 0; } else { continue; } } dAcBase_c *insect = nullptr; mVec3_c tmp1 = mPosition; if (mRevealed) { tmp1 = mRevealedSpawnPos; } mAng3_c rot(0, cM::rndFX(65536), 0); switch (getSubtype()) { case SUBTYPE_LANAYRU_ANT: insect = dAcObjBase_c::createInsectActor(this, fProfile::INSECT_ANT, 1, &tmp1, &rot, nullptr, 0, 0x3f); break; case SUBTYPE_FARON_GRASSHOPPER: insect = dAcObjBase_c::createInsectActor( this, fProfile::INSECT_GRASSHOPPER, 1, &tmp1, &rot, nullptr, 0, 0x3f ); break; case SUBTYPE_SKYLOFT_MANTIS: insect = dAcObjBase_c::createInsectActor( this, fProfile::INSECT_GRASSHOPPER, 0x10000001, &tmp1, &rot, nullptr, 0, 0x3f ); break; case SUBTYPE_EDLIN_ROLLER: insect = dAcObjBase_c::createInsectActor(this, fProfile::INSECT_SCARAB, 1, &tmp1, &rot, nullptr, 0, 0x3f); break; } if (insect != nullptr) { mLinks[i].link(insect); mInsectRespawnTimers[i] = -1; } } if (isSpawnSubtype(SPAWN_BUG_MINIGAME)) { mStateMgr.changeState(StateID_Wait); } else { mStateMgr.changeState(StateID_End); } } void dTgInsect_c::finalizeState_WaitCreate() {} void dTgInsect_c::initializeState_WaitForceEscape() { for (s32 i = 0; i < mInsectCount; i++) { dAcOInsect_c* tmp = static_cast(mLinks[i].get()); if (tmp) { tmp->setActorProperty(AC_PROP_0x4); } } } void dTgInsect_c::executeState_WaitForceEscape() { if (isTrialGateType()) { if (mWarpRef.isLinked()) { dAcOWarp_c *warp = static_cast(mWarpRef.get()); if (warp->fn_0x90()) { for (s32 i = 0; i < mInsectCount; i++) { if (mLinks[i].isLinked()) { static_cast(mLinks[i].get())->setKillSignal(); mStateMgr.changeState(StateID_End); } } } } } else if (isGoddessWallType() && mKillSignal) { for (s32 i = 0; i < mInsectCount; i++) { if (mLinks[i].isLinked()) { static_cast(mLinks[i].get())->setKillSignal(); mStateMgr.changeState(StateID_End); } } } } void dTgInsect_c::finalizeState_WaitForceEscape() {} void dTgInsect_c::initializeState_End() {} void dTgInsect_c::executeState_End() {} void dTgInsect_c::finalizeState_End() {} static const f32 FLOAT_ARRAY[] = { 0.1f, -0.4f, 0.3f, 0.7f, -0.7f, }; void dTgInsect_c::spawnAll() { for (s32 i = 0; i < mInsectCount; i++) { if (shouldSpawn()) { spawnInsect(i); } } } void dTgInsect_c::spawnInsect(s32 index) { f32 scaleX; f32 scaleY; f32 scaleXExt; f32 scaleYExt; f32 scaledScaleY; f32 scaledScaleX; f32 mult; f32 scaledTemp; scaleY = mScale.y; scaleYExt = SCALE_Y; scaledScaleY = scaleY * scaleYExt; mult = 0.85f; scaleXExt = SCALE_X; scaleX = mScale.x; scaledTemp = scaleXExt * scaleX; scaledScaleX = mult * scaledTemp; s16 angle1; mVec3_c pos; mVec3_c tmp; mAng3_c rot(0, 0, 0); bool spawnFound = false; s32 tries = 5; do { f32 scale = cM::rndF(scaledScaleX); angle1 = cM::rndFX(65536.0f); rot.y = cM::rndFX(65536.0f); mVec3_c v2 = mVec3_c::Ez * scale; cLib::offsetPos(pos, mPosition, angle1, v2); switch (getSubtype()) { case SUBTYPE_VOLCANIC_LADYBUG: case SUBTYPE_WOODLAND_RHINO_BEETLE: case SUBTYPE_SAND_CICADA: case SUBTYPE_SKY_STAG_BEETLE: pos = mPosition; if (getSubtype() == SUBTYPE_SAND_CICADA) { tmp = mVec3_c::Ez; tmp.rotY(mAng(mRotation.y + 0x4000)); f32 arrayResult = FLOAT_ARRAY[index % (s32)ARRAY_LENGTH(FLOAT_ARRAY)]; f32 scaledX = SCALE_X * mScale.x; tmp.multScalar(arrayResult * scaledX); pos = mPosition + tmp; f32 scaledScale = SCALE_Y * mScale.y; pos.y = mPosition.y + scaledScale * 0.3f; pos.y += cM::rndF(scaledScale * 0.5f); if (!checkValidSpawnLocation(pos, 0)) { return; } } else { pos.y += cM::rndF(scaledScaleY); } spawnFound = true; break; case SUBTYPE_FARON_GRASSHOPPER: case SUBTYPE_LANAYRU_ANT: case SUBTYPE_SKYLOFT_MANTIS: case SUBTYPE_EDLIN_ROLLER: pos.y = 100 + mPosition.y; if (dBgS_ObjGndChk::CheckPos(pos)) { spawnFound = true; } break; case SUBTYPE_GERUDO_DRAGONFLY: case SUBTYPE_BUTTERFLY: case SUBTYPE_STARRY_FIREFLY: spawnFound = true; break; } } while (!spawnFound && --tries); dAcBase_c *ref = nullptr; switch (getSubtype()) { case SUBTYPE_VOLCANIC_LADYBUG: ref = dAcObjBase_c::createInsectActor(this, fProfile::INSECT_LADYBUG, 0, &pos, &rot, NULL, 0, 0x3f); break; case SUBTYPE_GERUDO_DRAGONFLY: ref = dAcObjBase_c::createInsectActor(this, fProfile::INSECT_DRAGONFLY, 0, &pos, &rot, NULL, 0, 0x3f); break; case SUBTYPE_WOODLAND_RHINO_BEETLE: ref = dAcObjBase_c::createInsectActor(this, fProfile::INSECT_BEETLE, 0, &pos, &rot, NULL, 0, 0x3f); break; case SUBTYPE_FARON_GRASSHOPPER: ref = dAcObjBase_c::createInsectActor(this, fProfile::INSECT_GRASSHOPPER, 0, &pos, &rot, NULL, 0, 0x3f); break; case SUBTYPE_SAND_CICADA: ref = dAcObjBase_c::createInsectActor(this, fProfile::INSECT_CICADA, 0, &pos, &rot, NULL, 0, 0x3f); break; case SUBTYPE_LANAYRU_ANT: ref = dAcObjBase_c::createInsectActor(this, fProfile::INSECT_ANT, 0, &pos, &rot, NULL, 0, 0x3f); break; case SUBTYPE_SKY_STAG_BEETLE: ref = dAcObjBase_c::createInsectActor(this, fProfile::INSECT_BEETLE, 0x10000000, &pos, &rot, NULL, 0, 0x3f); break; case SUBTYPE_BUTTERFLY: ref = dAcObjBase_c::createInsectActor( this, fProfile::INSECT_BUTTERFLY, (s16)mViewClipIdx, &pos, &rot, NULL, 0, 0x3f ); break; case SUBTYPE_SKYLOFT_MANTIS: ref = dAcObjBase_c::createInsectActor( this, fProfile::INSECT_GRASSHOPPER, 0x10000000, &pos, &rot, NULL, 0, 0x3f ); break; case SUBTYPE_EDLIN_ROLLER: ref = dAcObjBase_c::createInsectActor(this, fProfile::INSECT_SCARAB, 0, &pos, &rot, NULL, 0, 0x3f); break; case SUBTYPE_STARRY_FIREFLY: ref = dAcObjBase_c::createInsectActor(this, fProfile::INSECT_FIREFLY, 0, &pos, &rot, NULL, 0, 0x3f); break; } if (ref != nullptr) { mLinks[index].link(ref); mInsectRespawnTimers[index] = -1; } return; } bool dTgInsect_c::shouldSpawn() { if (isSpawnSubtype(SPAWN_BUG_MINIGAME)) { return true; } else if (isSpawnSubtype(SPAWN_SKYLOFT_BUGKID_TREE)) { return !SceneflagManager::sInstance->checkBoolFlag(mRoomID, 0x3a); } else { if (isTrialGateType()) { return true; } else if (isGossipStoneType() || isGoddessWallType()) { return true; } else if ((isSubtype(SUBTYPE_STARRY_FIREFLY)) && !dAcItem_c::checkFlag(ITEM_STARRY_FIREFLY)) { return true; } else { if (cM::rndF(1.0f) >= 0.5f) { return false; } else { return true; } } } } bool dTgInsect_c::checkValidSpawnLocation(const mVec3_c &pos, bool updateRotation) { mVec3_c tmp = mVec3_c::Ez * (SCALE_X * mScale.x); tmp.rotY(mRotation.y); tmp += pos; dBgS_LinChk linChk; linChk.mBackFlag = true; linChk.mFrontFlag = false; linChk.Set(&pos, &tmp, nullptr); if (!dBgS::GetInstance()->LineCross(&linChk)) { mAng yRot = mRotation.y + 0x7FFF; if (updateRotation) { mRotation.y = yRot; } tmp = mVec3_c::Ez * (SCALE_X * mScale.x); tmp.rotY(yRot); tmp += pos; linChk.Set(&pos, &tmp, nullptr); if (!dBgS::GetInstance()->LineCross(&linChk)) { return false; } } return true; } void moreUnused() { static const s32 a = 0x3a; }