From ebfd1aaa0e2d002621d2dc6fe2a3d5230fad628c Mon Sep 17 00:00:00 2001 From: Cole Barker Date: Sun, 10 May 2026 22:00:38 -0400 Subject: [PATCH] d_t_beetle --- config/SOUE01/rels/d_t_beetleNP/symbols.txt | 21 ++-- include/d/t/d_t_beetle.h | 37 ++++++ src/REL/d/t/d_t_beetle.cpp | 126 ++++++++++++++++++++ 3 files changed, 173 insertions(+), 11 deletions(-) diff --git a/config/SOUE01/rels/d_t_beetleNP/symbols.txt b/config/SOUE01/rels/d_t_beetleNP/symbols.txt index 11eec349..91f91a8c 100644 --- a/config/SOUE01/rels/d_t_beetleNP/symbols.txt +++ b/config/SOUE01/rels/d_t_beetleNP/symbols.txt @@ -2,21 +2,20 @@ _prolog = .text:0x00000000; // type:function size:0x2C scope:global _epilog = .text:0x00000030; // type:function size:0x2C scope:global _unresolved = .text:0x00000060; // type:function size:0x4 scope:global dTgBeetle_c_classInit__Fv = .text:0x00000070; // type:function size:0x4C -fn_302_C0 = .text:0x000000C0; // type:function size:0x14C -fn_302_210 = .text:0x00000210; // type:function size:0x8 -fn_302_220 = .text:0x00000220; // type:function size:0x17C -fn_302_3A0 = .text:0x000003A0; // type:function size:0x8 -fn_302_3B0 = .text:0x000003B0; // type:function size:0x168 -fn_302_520 = .text:0x00000520; // type:function size:0xFC -fn_302_620 = .text:0x00000620; // type:function size:0x54 -fn_302_674 = .text:0x00000674; // type:function size:0x4 +create__11dTgBeetle_cFv = .text:0x000000C0; // type:function size:0x14C +doDelete__11dTgBeetle_cFv = .text:0x00000210; // type:function size:0x8 +actorExecute__11dTgBeetle_cFv = .text:0x00000220; // type:function size:0x17C +draw__11dTgBeetle_cFv = .text:0x000003A0; // type:function size:0x8 +isWithinCylinder__11dTgBeetle_cCFRC7mVec3_c = .text:0x000003B0; // type:function size:0x168 +isWithinSphere__11dTgBeetle_cCFRC7mVec3_c = .text:0x00000520; // type:function size:0xFC +updateBeetle__11dTgBeetle_cFR14dAcBoomerang_c = .text:0x00000620; // type:function size:0x58 __dt__11dTgBeetle_cFv = .text:0x00000680; // type:function size:0x5C _ctors = .ctors:0x00000000; // type:label scope:global _dtors = .dtors:0x00000000; // type:label scope:global lbl_302_rodata_0 = .rodata:0x00000000; // type:object size:0x4 data:float -dTgBeetle__scaleMultiplier = .rodata:0x00000004; // type:object size:0x4 align:4 data:float -lbl_302_rodata_4.y = .rodata:0x00000008; // type:object size:0x4 align:4 data:float -lbl_302_rodata_4.z = .rodata:0x0000000C; // type:object size:0xC align:4 data:float +dTgBeetle__scaleMultiplier = .rodata:0x00000004; // type:object size:0xC align:4 data:float +lbl_302_rodata_4.y = .rodata:0x00000010; // type:object size:0x4 align:4 data:float +lbl_302_rodata_4.z = .rodata:0x00000014; // type:object size:0x4 align:4 data:float g_profile_BEETLE_TAG = .data:0x00000000; // type:object size:0x10 lbl_302_data_10 = .data:0x00000010; // type:object size:0x5 data:string dTgBeetle__vtable = .data:0x00000018; // type:object size:0x74 diff --git a/include/d/t/d_t_beetle.h b/include/d/t/d_t_beetle.h index fab00d6d..56fb505e 100644 --- a/include/d/t/d_t_beetle.h +++ b/include/d/t/d_t_beetle.h @@ -1,14 +1,51 @@ #ifndef D_T_BEETLE_H #define D_T_BEETLE_H +#include "d/a/obj/d_a_obj_boomerang.h" #include "d/t/d_tg.h" +#include "m/m_mtx.h" + +// This is a tag actor for controlling where the beetle can fly +// BtlTgC is leaves (beetle plays leaf animation as it passes through) class dTgBeetle_c : public dTg_c { public: dTgBeetle_c() {} virtual ~dTgBeetle_c() {} + virtual int create() override; + virtual int doDelete() override; + virtual int actorExecute() override; + u32 isWithinSphere(const mVec3_c ¶m) const; + u32 isWithinCylinder(const mVec3_c ¶m) const; + void updateBeetle(dAcBoomerang_c &boomerang); + virtual int draw() override; + + enum Variant_e { + BtlTg, + BtlTgA, // is this even used? + BtlTgB, // is this even used? + BtlTgC, // spherical leaf object + }; + + enum ZoneType_e { + LeafZone = 1, + BorderZone = 2, + UnknownZone = 3, + }; + + enum ZoneShape_e { + RectangularPrismShape, + CylinderShape, + SphereShape, + }; private: + /* 0xFC */ mMtx_c mMatrix1; + /* 0x12C*/ u8 mZoneType; // defines what this object does + /* 0x12D*/ u8 mZoneShape; // the shape created inside the object that it checks + /* 0x12E*/ u8 mUnknown; // unused + /* 0x12F*/ u8 mBeetleFlag; + /* 0x130*/ u8 mPastOnly; // object only exists in past state }; #endif diff --git a/src/REL/d/t/d_t_beetle.cpp b/src/REL/d/t/d_t_beetle.cpp index 390c6e6f..858fcab1 100644 --- a/src/REL/d/t/d_t_beetle.cpp +++ b/src/REL/d/t/d_t_beetle.cpp @@ -1,3 +1,129 @@ #include "d/t/d_t_beetle.h" +#include "d/a/d_a_player.h" +#include "d/a/obj/d_a_obj_base.h" +#include "d/a/obj/d_a_obj_boomerang.h" +#include "d/d_sc_game.h" +#include "d/flag/sceneflag_manager.h" +#include "toBeSorted/area_math.h" +#include "toBeSorted/time_area_mgr.h" + SPECIAL_ACTOR_PROFILE(BEETLE_TAG, dTgBeetle_c, fProfile::BEETLE_TAG, 0x297, 0, 0); + +int dTgBeetle_c::create() { + if (dScGame_c::currentSpawnInfo.stageName == "F103") { // flooded faron woods + if (mActorSubtype) { + mScale *= 0.01f; + } + // Haven't verfied but I think CO_TEST is an invisible sphere created around leaves + // underwater to prevent you from swimming through trees + dAcObjBase_c::create(fProfile::CO_TEST, mRoomID, 0, &mPosition, &mRotation, &mScale, 0xFFFFFFFF); + + return FAILED; + } else { + if (!mActorSubtype) { // BtlTg + mZoneType = getFromParams(0, 0xF); + mZoneShape = getFromParams(4, 0x3); + mUnknown = getFromParams(6, 0xFF); + mBeetleFlag = getFromParams(0xE, 0xFF); + mPastOnly = getFromParams(0x16, 0x3); + } else { + mZoneType = LeafZone; + if (mActorSubtype == BtlTgA) { // BtlTgA + mZoneShape = RectangularPrismShape; + } else if (mActorSubtype == BtlTgB) { // BtlTgB + mZoneShape = CylinderShape; + } else if (mActorSubtype == BtlTgC) { // BtlTgC + mZoneShape = SphereShape; + } + } + matrixCreateFromPosRotYScale(mMatrix1, mPosition, mRotation.y, mScale, nullptr, 0); + return SUCCEEDED; + } +} + +int dTgBeetle_c::doDelete() { + return SUCCEEDED; +} + +int dTgBeetle_c::actorExecute() { + if (mPastOnly == 1 && !mActorSubtype) { + if (dTimeAreaMgr_c::GetInstance()->checkPositionIsInPastState(mRoomID, mPosition, nullptr, 1.0f) == 0) { + return SUCCEEDED; + } + } + + if (!SceneflagManager::sInstance->checkBoolFlag(mRoomID, mBeetleFlag) || mActorSubtype) { + dAcBoomerang_c *beetlePtr = + (dAcBoomerang_c *)dAcPy_c::GetLink() + ->vt_0x1C0(); // boomerang pointer cast required because function currently returns void* + + if (mZoneShape == RectangularPrismShape) { // rectangular prism + if (beetlePtr && checkAreaBox(mMatrix1, beetlePtr->mPosition)) { + updateBeetle(*beetlePtr); + } + } else if (mZoneShape == CylinderShape) { // cylinder + if (beetlePtr && isWithinCylinder((beetlePtr->mPosition))) { + updateBeetle(*beetlePtr); + } + } else if (mZoneShape == SphereShape) { // sphere + if (beetlePtr && isWithinSphere((beetlePtr->mPosition))) { + updateBeetle(*beetlePtr); + } + } + } + return SUCCEEDED; +} + +u32 dTgBeetle_c::isWithinSphere( + const mVec3_c &position +) const { // fn_302_520 is position within a sphere the size of the zone + + mVec3_c diff = position - (mPosition + mScale.y * mVec3_c::Ey * 1.0f); + + diff.x /= mScale.x; + diff.y /= mScale.y; + diff.z /= mScale.z; + + return diff.mag() <= 1.0f; // is beetle within a certain distance from center +} + +u32 dTgBeetle_c::isWithinCylinder( + const mVec3_c &position +) const { // is position within a really thin cylinder inside the zone + + mVec3_c diff = (position - (mPosition + mVec3_c::Ey * mScale.y * 0.5f)); + + bool returnValue = 0; + bool returnCheck = 0; + + diff.x /= mScale.x; + diff.y /= mScale.y; + diff.z /= mScale.z; + + if (diff.absXZ() <= 0.01f && diff.y <= 0.5f) { + returnCheck = 1; + } + + if (returnCheck && diff.y >= -0.5f) { + returnValue = 1; + } + + return returnValue; +} + +void dTgBeetle_c::updateBeetle(dAcBoomerang_c &boomerang) { // fn_302_620 update beetle based on zone type + if (mZoneType == LeafZone) { // leaf zone + return boomerang.setField_0x8CC(0x20); + } else if (mZoneType == BorderZone) { // border zone, reduce flight time + return boomerang.setRemainingFlightTime(0x3C); + } else if (mZoneType == UnknownZone) { //??? + return boomerang.setField_0x8CC(0x80); + } else { // instant flashing red + return boomerang.setRemainingFlightTime(-1); + } +} + +int dTgBeetle_c::draw() { + return 1; +}