From d54d983a4a7433f97f92b9e162cea5972dac6165 Mon Sep 17 00:00:00 2001 From: Briggs Baltzell Date: Tue, 3 Mar 2026 22:44:51 -0600 Subject: [PATCH] d_a_boomerang matching (#936) * Added constructor implementation for `daBoomerang_c`. * Extend `daBoomerang_sightPacket_c` with `dDlst_base_c` base class. * Refactor `d_a_boomerang.h`: reorganize class definitions and update member layout in `daBoomerang_c`. * Extend `daBoomerang_c`: add new arrays, members, and static assertions for structure validation. * Extend `daBoomerang_c`: add `dBgS_BoomerangLinChk` member and update padding fields. * Extend `daBoomerang_c`: implement `create` method, add new members, and update function signatures. * Refactor `daBoomerang_c`: update `createHeap` function to return `BOOL` and adjust related calls. * Extend `daBoomerang_c`: implement `execute` method logic, update member variables, and adjust structure layout in `d_a_boomerang.h`. * Extend `daBoomerang_c`: add static blur vector definitions for `l_blur_top` and `l_blur_root`. * Add fields to `daBoomerang_blur_c`. * Refactor `daBoomerang_blur_c`: implement `initBlur` logic, add `pos` field, update structure layout in `d_a_boomerang.h`. * Refactor `daBoomerang_blur_c`: update `initBlur` and `copyBlur` logic, modify array structure to use 2D layout, and adjust declarations in `d_a_boomerang.h`. * Match `copyBlur` * Update `config.yml`: add symbol `l_matDL` for `daBoomerang_blur_c`. * Extend `daBoomerang_blur_c`: implement `draw` method, add vertex description, attribute format lists, and texture handling logic. * Add fields to `daBoomerang_sightPacket_c` * Update `play` method in `daBoomerang_sightPacket_c`: implement looping logic for modifying `field_0xF4` values. * Refactor `setSight` and `play` in `daBoomerang_sightPacket_c`: implement animation logic, replace `field_0xF4` with `arr_0xF4`, add `arr_0xF9`, and update structure in `d_a_boomerang.h`. * Refactor `daBoomerang_sightPacket_c`: add `setTex` and `setImage` methods; update image data logic in `d_a_boomerang.cpp` and `d_a_boomerang.h`. * Update `initFrame` and `resetSightOn` in `daBoomerang_sightPacket_c`: initialize `arr_0xF4` and reset `targetFlags`. * Replace hardcoded array size with `BOOM_TARGET_MAX` in `d_a_boomerang.cpp` and `d_a_boomerang.h` * Refactor `daBoomerang_sightPacket_c`: rename variables for clarity, update structure fields, and adjust logic in `setSight`, `play`, and related methods. * Implement `draw` method in `daBoomerang_sightPacket_c`: add vertex descriptor/attribute format lists, texture handling, and sight rendering logic. * Adjust vertex attribute formats in `d_a_boomerang.cpp`: update position to `GX_S8` and texture to `GX_U8`. * Reorder includes in `d_a_boomerang.cpp` to resolve dependencies for `l_sightMatDL` and `l_sightDL__d_a_boomerang` * Update `getFlyMax` in `daBoomerang_c`: add player status and stage name checks to determine maximum flight distance. * Refactor `procMove` and `execute` in `daBoomerang_c`: improve boomerang targeting logic, rename variables for clarity, update array structures, and adjust control flow. * Implement enhanced boomerang movement logic in `daBoomerang_c`: calculate angles, update position/rotation, handle water effects, and refine collision detection. Adjust structure fields in `d_a_boomerang.h`. * Refactor `daBoomerang_c` control flow: reorder player retrieval logic, adjust distance-based normalization, and refine boomerang return handling. * Change return type of `returnBoomerang` from `int` to `BOOL` in `d_a_player_main.h` and `d_a_player_boomerang.inc`. * Change `setItemWaterEffect` return type from `u32` to `BOOL` and refactor its parameters and logic for clarity and behavior adjustment. * Adjust `setItemWaterEffect` call in `d_a_boomerang.cpp` to use explicit `BOOL` comparison for clarity. * Refactor `daBoomerang_c` control flow and targeting logic: introduce `mTargetRayEnd`, enhance position/angle calculations, integrate player sight checks, and update camera handling. Adjust includes and structure definitions for consistency. * Match `rockLineCallback` * Rename `param_1` to `pHitActor` in `rockLineCallback` for clarity. * Match `setAimActor` in `d_a_boomerang.cpp`. * Refactor `daBoomerang_c`: update `setLockActor` to use `BOOL` type, modify related logic for clarity, and ensure consistent parameter usage across `d_a_boomerang.cpp`. * Match `resetLockActor` in `d_a_boomerang.cpp`: initialize target arrays and reset counters for consistency. * Refactor `daBoomerang_c`: Fix struct offsets, update instance size * Match `setRoomInfo` in `d_a_boomerang.cpp`: update position handling, ground checks, room ID assignment, and environment override logic. * Match `create` in `d_a_boomerang.cpp`: update matrix handling, target ID initialization, callback setup, and clean up unused code. * Match `setKeepMatrix` in `d_a_boomerang.cpp`: update transformation logic to align boomerang with Link's hand. * Refactor `d_a_player_main` boomerang logic: rename `m36F4` to `mBoomerangCatchPos`, implement `getBoomerangCatchPos` accessor * Match `setAimPos` in `d_a_boomerang.cpp`: implement target position logic based on current target index and player catch position. * Match `checkBgHit` in `d_a_boomerang.cpp`: implement background collision logic, position updates, sound effects, and behavior adjustments. * Continue matching `procWait` in `d_a_boomerang.cpp` * Refactor `d_a_boomerang.cpp`: rename `field_0xF3A` to `mModelRotY` for clarity, update all associated references, and adjust struct definition in the header file. * Continue matching `procWait` in `d_a_boomerang.cpp` * Match `procWait` in `d_a_boomerang.cpp` * Continue matching `procMove` in `d_a_boomerang.cpp` * Refactor `d_a_boomerang.cpp`: convert `u8` fields to `bool` for clarity and better type usage, update header and references accordingly. * Match `draw` in `d_a_boomerang.cpp`: implement drawing logic with model updates, light settings, shadow handling, and target sight management. Update struct definition to include `mGroundY`. * Refactor `procMove` in `d_a_boomerang.cpp`: simplify angle calculations, update `mInWater` to `u8`, and improve readability by reducing nested logic. * Fix `at_offset` initialization in `procMove` in `d_a_boomerang.cpp` * Match `procMove` in `d_a_boomerang.cpp` * Refine `draw` in `d_a_boomerang.cpp`: inline comments for quads setup, add light yellow trail color definition. * Refactor `d_a_boomerang.cpp` and header: rename `field_0x14` to `numTrailSegments` for improved clarity and update all related references. * Refactor `draw` in `d_a_boomerang.cpp`: reorganize quads initialization and alpha blending loops for improved structure and readability. * Refactor `draw` in `d_a_boomerang.cpp`: combine alpha variable declarations for improved local scope and clarity. * Refactor `draw` in `d_a_boomerang.cpp`: introduce `QUAD_VERT` macro to streamline quad vertex setup and improve code readability. * Refactor `draw` in `d_a_boomerang.cpp`: rename `alpha` variables to `uCoord` for improved clarity and consistency with their purpose. * Refactor `d_a_boomerang.cpp` and header: introduce `SEGMENTS_PER_STEP` constant for improved clarity and consistency, update related loops and data structures. * Refactor `d_a_boomerang.cpp` and header: rename trail arrays for improved clarity and consistency, update all related references. * Refactor `d_a_boomerang.cpp` and header: simplify trail vertex array indexing by flattening multidimensional arrays and updating all related code. * Refactor `d_a_boomerang.cpp`: mark `se_flg` array as `const` for improved immutability and clarity. * Refactor `d_a_boomerang.cpp`: relocate `l_at_cps_src` definition for improved organization and consistency. * Refactor `d_a_boomerang.cpp` and header: rename and clarify multiple variables (e.g., `field_0xF2C` to `mIsReturning`) for improved readability and consistency, update all related references and logic. * Refactor `d_a_boomerang.h`: add destructors to `daBoomerang_blur_c` and `daBoomerang_sightPacket_c` for proper ordering. * Refactor `daBoomerang_blur_c::draw` in `d_a_boomerang.cpp`: reorder variable initialization, streamline loops, and adjust `QUAD_VERT` macro usage for improved clarity and consistency. * Add inline geometry utility functions to `GFGeometry.h` * Refactor `d_a_boomerang.cpp`: simplify geometry rendering by updating `QUAD_VERT` macro implementation and replacing manual vertex management with `GFBegin`/`GFEnd`. * Refactor `d_a_boomerang.cpp`: simplify trail rendering by streamlining `uCoord` handling, reducing redundant variables, and improving clarity in loops. * Refactor `d_a_boomerang.cpp`: rename `QUAD_VERT` to `QUAD_VTX` for clarity and update all related references. * Add `l_matDL$4438` entry to config files for `daBoomerang_blur_c` rendering assets. * Add version check around `j3dSys.reinitGX()` in `d_a_boomerang.cpp` to limit execution to non-demo builds. * Refactor `d_a_boomerang.cpp`: replace direct `current.roomNo` usage with `roomNo` variable for improved clarity and consistency. * Add version-specific asserts in `d_a_boomerang.cpp` for demo and non-demo builds * Add version-specific asserts and adjust version check logic in `d_a_boomerang.cpp` for Japanese build * Align `GXVtxDescList` and `GXVtxAttrFmtList` declarations with `ALIGN_DECL(32)` in `d_a_boomerang.cpp` for consistent memory alignment. * Update `d_a_boomerang` to use `MatchingFor` in configuration * Remove outdated `FIXME` comment in `d_a_boomerang.cpp`. * Refactor `d_a_boomerang.cpp`: replace hardcoded rotation constants with `yRotPerStep` variable for clarity and maintainability. * Update `d_a_boomerang.cpp` configuration to use `Matching` instead of `MatchingFor`. * Refactor `d_a_boomerang.cpp`: rename `field_0xF2E` to `mJustHit` and `field_0xF2D` to `unused_0xF2D` for improved clarity. * Replace hardcoded value in `d_a_boomerang.cpp` with `daBoomerang_blur_c::SEGMENTS_PER_STEP` for improved readability and maintainability. * Refactor `d_a_boomerang.cpp`: replace `fpcM_GetParam` with `fopAcM_GetParam` for consistency with actor parameter retrieval methods. * Introduce `Mode` enum in `d_a_boomerang` and replace related hardcoded values for improved readability and maintainability. * Refactor `setAimActor` in `d_a_boomerang.cpp`: rename parameter for improved clarity. * Replace `fpcM_SetParam` with `fopAcM_SetParam` in `d_a_boomerang.cpp` for consistency with actor parameter setting methods. * Replace hardcoded `0` with `dEvtMode_NONE_e` in `d_a_boomerang.cpp` for improved readability and maintainability. * Replace `BOOM_TARGET_MAX` with `BOOMERANG_LOCK_MAX` in `d_a_boomerang` for consistency. * Refactor `d_a_boomerang.cpp` and `d_a_boomerang.h`: rename target-related variables and methods to lock-related for improved clarity and consistency. * Refactor `daBoomerang_Draw` and `daBoomerang_Execute` in `d_a_boomerang.cpp` to simplify and remove redundant casts. * Replace `Mode_0` and `Mode_1` with `Mode_Wait` and `Mode_Throw` in `d_a_boomerang` * Simplify boolean assignment in boomerang lock condition in `d_a_boomerang.cpp`. * Rename variable `b` to `isAiming` in `d_a_boomerang.cpp` for improved readability. * Refactor draw methods in `d_a_boomerang.cpp` to streamline list-setting logic. * Refactor particle effect in `d_a_boomerang.cpp` to use `dComIfGp_particle_setP1` for improved clarity and maintainability. * Replace `g_dComIfG_gameInfo` camera getter with `dComIfGp` equivalents in `d_a_boomerang.cpp` for consistency. * Simplify version-specific `JUT_ASSERT` calls in `d_a_boomerang.cpp` with `VERSION_SELECT` for improved maintainability. * Replace direct model matrix assignment with `fopAcM_SetMtx` in `d_a_boomerang.cpp` for consistency. * Update matching logic for `d_a_boomerang.cpp` to use `MatchingFor`. --- config/D44J01/config.yml | 5 + config/GZLE01/config.yml | 5 + config/GZLJ01/config.yml | 5 + config/GZLP01/config.yml | 5 + configure.py | 2 +- include/d/actor/d_a_boomerang.h | 107 ++- include/d/actor/d_a_player_main.h | 12 +- include/dolphin/gf/GFGeometry.h | 26 + src/d/actor/d_a_boomerang.cpp | 931 +++++++++++++++++++++++---- src/d/actor/d_a_player_boomerang.inc | 4 +- src/d/actor/d_a_player_main.cpp | 2 +- src/d/actor/d_a_player_particle.inc | 15 +- 12 files changed, 952 insertions(+), 167 deletions(-) diff --git a/config/D44J01/config.yml b/config/D44J01/config.yml index 7672c54d3..afb7cd053 100644 --- a/config/D44J01/config.yml +++ b/config/D44J01/config.yml @@ -3197,6 +3197,11 @@ extract: binary: assets/l_sightDL__d_a_boomerang.bin header: assets/l_sightDL__d_a_boomerang.h +- symbol: l_matDL$4433 + binary: assets/l_matDL__draw__18daBoomerang_blur_cFv.bin + header: assets/l_matDL__draw__18daBoomerang_blur_cFv.h + rename: l_matDL + - symbol: l_sightDL!.data:0x80383e00 binary: assets/l_sightDL__d_a_player_main.bin header: assets/l_sightDL__d_a_player_main.h diff --git a/config/GZLE01/config.yml b/config/GZLE01/config.yml index 24eb670cb..2361a311f 100644 --- a/config/GZLE01/config.yml +++ b/config/GZLE01/config.yml @@ -2775,6 +2775,11 @@ extract: binary: assets/l_sightDL__d_a_boomerang.bin header: assets/l_sightDL__d_a_boomerang.h +- symbol: l_matDL$4438 + binary: assets/l_matDL__draw__18daBoomerang_blur_cFv.bin + header: assets/l_matDL__draw__18daBoomerang_blur_cFv.h + rename: l_matDL + - symbol: l_sightDL!.data:0x8038fc80 binary: assets/l_sightDL__d_a_player_main.bin header: assets/l_sightDL__d_a_player_main.h diff --git a/config/GZLJ01/config.yml b/config/GZLJ01/config.yml index c731c8bc8..cfbb00d26 100644 --- a/config/GZLJ01/config.yml +++ b/config/GZLJ01/config.yml @@ -2359,6 +2359,11 @@ extract: binary: assets/l_sightDL__d_a_boomerang.bin header: assets/l_sightDL__d_a_boomerang.h +- symbol: l_matDL$4438 + binary: assets/l_matDL__draw__18daBoomerang_blur_cFv.bin + header: assets/l_matDL__draw__18daBoomerang_blur_cFv.h + rename: l_matDL + - symbol: l_sightDL!.data:0x80383320 binary: assets/l_sightDL__d_a_player_main.bin header: assets/l_sightDL__d_a_player_main.h diff --git a/config/GZLP01/config.yml b/config/GZLP01/config.yml index a223c1747..2761c626a 100644 --- a/config/GZLP01/config.yml +++ b/config/GZLP01/config.yml @@ -2371,6 +2371,11 @@ extract: binary: assets/l_sightDL__d_a_boomerang.bin header: assets/l_sightDL__d_a_boomerang.h +- symbol: l_matDL$4438 + binary: assets/l_matDL__draw__18daBoomerang_blur_cFv.bin + header: assets/l_matDL__draw__18daBoomerang_blur_cFv.h + rename: l_matDL + - symbol: l_sightDL!.data:0x80396960 binary: assets/l_sightDL__d_a_player_main.bin header: assets/l_sightDL__d_a_player_main.h diff --git a/configure.py b/configure.py index ed657ebc7..a57837acb 100755 --- a/configure.py +++ b/configure.py @@ -573,7 +573,7 @@ config.libs = [ Object(MatchingFor("GZLJ01", "GZLE01", "GZLP01"), "d/actor/d_a_bg.cpp"), Object(MatchingFor("GZLJ01", "GZLE01", "GZLP01"), "d/actor/d_a_bomb.cpp"), Object(MatchingFor("GZLJ01", "GZLE01", "GZLP01"), "d/actor/d_a_bomb2.cpp"), - Object(NonMatching, "d/actor/d_a_boomerang.cpp"), + Object(MatchingFor("GZLJ01", "GZLE01", "GZLP01"), "d/actor/d_a_boomerang.cpp"), Object(MatchingFor("GZLJ01", "GZLE01", "GZLP01"), "d/actor/d_a_dai_item.cpp"), Object(NonMatching, "d/actor/d_a_demo00.cpp"), Object(MatchingFor("GZLJ01", "GZLE01", "GZLP01"), "d/actor/d_a_disappear.cpp"), diff --git a/include/d/actor/d_a_boomerang.h b/include/d/actor/d_a_boomerang.h index b53aab5ee..2faa0aa1e 100644 --- a/include/d/actor/d_a_boomerang.h +++ b/include/d/actor/d_a_boomerang.h @@ -4,8 +4,60 @@ #include "f_op/f_op_actor.h" #include "d/d_cc_d.h" +#define BOOMERANG_LOCK_MAX 5 + +class daBoomerang_blur_c : public J3DPacket { +public: + virtual ~daBoomerang_blur_c() {} + void initBlur(MtxP, s16); + void copyBlur(MtxP, s16); + virtual void draw(); + + static const s32 SEGMENTS_PER_STEP = 5; + +public: + /* 0x010 */ void* imageData; + /* 0x014 */ s32 numTrailSegments; + /* 0x018 */ cXyz pos; + /* 0x024 */ cXyz trail0_vtxArr0[12 * SEGMENTS_PER_STEP]; + /* 0x2F4 */ cXyz trail0_vtxArr1[12 * SEGMENTS_PER_STEP]; + /* 0x5C4 */ cXyz trail1_vtxArr0[12 * SEGMENTS_PER_STEP]; + /* 0x894 */ cXyz trail1_vtxArr1[12 * SEGMENTS_PER_STEP]; +}; + +class daBoomerang_sightPacket_c : public dDlst_base_c { +public: + virtual ~daBoomerang_sightPacket_c() {} + virtual void draw(); + void setSight(cXyz*, int); + void play(int); + + void initFrame(int n) { mFrameArr[n] = 0; } + void resetSightOn() { mSightOnFlg = 0; } + void setImage(ResTIMG* i_img) { mImage = i_img; } + void setTex(void* data) { mTex = data; } + + static const s32 ANIM_LENGTH = 26; + static const s32 HALF_ANIM_LENGTH = ANIM_LENGTH / 2; + +private: + /* 0x004 */ Mtx mMtxArr[BOOMERANG_LOCK_MAX]; + /* 0x0F4 */ u8 mFrameArr[BOOMERANG_LOCK_MAX]; + /* 0x0F9 */ u8 mScaleArr[BOOMERANG_LOCK_MAX]; + /* 0x100 */ u32 mSightOnFlg; + /* 0x104 */ void* mTex; + /* 0x108 */ ResTIMG* mImage; +}; + class daBoomerang_c : public fopAc_ac_c { public: + typedef BOOL (daBoomerang_c::*daBoomerang_c_ProcFunc)(); + + enum Mode { + Mode_Wait = 0x0, + Mode_Throw = 0x1, + }; + void onCancelFlg() { mCancelFlg = true; } daBoomerang_c(); @@ -15,34 +67,49 @@ public: float getFlyMax(); void rockLineCallback(fopAc_ac_c*); void setAimActor(fopAc_ac_c*); - void setLockActor(fopAc_ac_c*, int); + BOOL setLockActor(fopAc_ac_c* i_actor, BOOL doSoundEffect); void resetLockActor(); void setRoomInfo(); void setKeepMatrix(); void setAimPos(); void checkBgHit(cXyz*, cXyz*); - void procWait(); - void procMove(); - void createHeap(); + BOOL procWait(); + BOOL procMove(); + BOOL createHeap(); public: - /* Place member variables here */ - /* 0x290 */ u8 m290[0xF34 - 0x290]; - /* 0xF34 */ bool mCancelFlg; + /* 0x0290 */ J3DModel* mpModel; + /* 0x0294 */ daBoomerang_sightPacket_c mSightPacket; + /* 0x03A0 */ daBoomerang_blur_c mBlur; + /* 0x0F04 */ fpc_ProcID mLockActorIDs[BOOMERANG_LOCK_MAX]; + /* 0x0F18 */ fopAc_ac_c* mLockActors[BOOMERANG_LOCK_MAX]; + /* 0x0F2C */ bool mIsReturning; + /* 0x0F2D */ bool unused_0xF2D; + /* 0x0F2E */ bool mJustHit; + /* 0x0F2F */ bool mCatchAndDelete; + /* 0x0F30 */ u8 unused_0xF30; + /* 0x0F31 */ u8 mLockCnt; + /* 0x0F32 */ u8 mCurLockIdx; + /* 0x0F33 */ bool mThirdPerson; + /* 0x0F34 */ bool mCancelFlg; + /* 0x0F35 */ u8 mInWater; + /* 0x0F36 */ bool mFreeFlyOut; + /* 0x0F38 */ s16 mModelRotZ; + /* 0x0F3A */ s16 mModelRotY; + /* 0x0F3C */ f32 mGroundY; + /* 0x0F40 */ cXyz mTargetPos; + /* 0x0F4C */ dCcD_Stts mStts; + /* 0x0F88 */ dCcD_Cps mCps; + /* 0x10C0 */ dBgS_BoomerangLinChk mLinChk; + /* 0x112C */ dBgS_ObjGndChk mGndChk; + /* 0x1180 */ daBoomerang_c_ProcFunc mProcFunc; }; -class daBoomerang_blur_c { -public: - void initBlur(MtxP, s16); - void copyBlur(MtxP, s16); - void draw(); -}; - -class daBoomerang_sightPacket_c { -public: - void draw(); - void setSight(cXyz*, int); - void play(int); -}; +STATIC_ASSERT(offsetof(daBoomerang_c, mSightPacket) == 0x294); +STATIC_ASSERT(offsetof(daBoomerang_c, mBlur) == 0x3A0); +STATIC_ASSERT(offsetof(daBoomerang_c, mCancelFlg) == 0xF34); +STATIC_ASSERT(offsetof(daBoomerang_c, mStts) == 0xF4C); +STATIC_ASSERT(offsetof(daBoomerang_c, mCps) == 0xF88); +STATIC_ASSERT(sizeof(daBoomerang_c) == 0x118C); #endif /* D_A_BOOMERANG_H */ diff --git a/include/d/actor/d_a_player_main.h b/include/d/actor/d_a_player_main.h index f7be09693..29ca6c4b6 100644 --- a/include/d/actor/d_a_player_main.h +++ b/include/d/actor/d_a_player_main.h @@ -58,6 +58,8 @@ public: } } + cXyz getPos() { return mPos; } + private: /* 0x04 */ bool mDrawFlag; /* 0x05 */ bool mLockFlag; @@ -1276,7 +1278,7 @@ public: void setDamageEmitter(); void endFlameDamageEmitter(); void endDamageEmitter(); - static u32 setItemWaterEffect(fopAc_ac_c*, int, int); + static BOOL setItemWaterEffect(fopAc_ac_c* i_actor, BOOL inWater, BOOL triggerOnExit); fopAc_ac_c* getDemoLookActor(); void setTinkleCeiverModel(); void setTalismanModel(); @@ -1608,7 +1610,7 @@ public: BOOL procRopeUpHang(); BOOL checkBoomerangAnime() const; void throwBoomerang(); - int returnBoomerang(); + BOOL returnBoomerang(); BOOL checkNextActionBoomerangReady(); void checkNextActionBoomerangFly(); BOOL checkNextBoomerangMode(); @@ -1846,8 +1848,8 @@ public: BOOL checkNoControll() const { return dComIfGp_getPlayer(0) != this; } void exchangeGrabActor(fopAc_ac_c* actor) { mActorKeepGrab.setData(actor); } void getDekuLeafWindPos() const {} - void getBoomerangCatchPos() const {} - void getLineTopPos() {} + cXyz getBoomerangCatchPos() const { return mBoomerangCatchPos; } + cXyz getLineTopPos() { return mSightPacket.getPos(); } cXyz getHookshotRootPos() const { return mHookshotRootPos; } void getIceParticleBtk() {} void getIceWaterParticleBtk() {} @@ -2294,7 +2296,7 @@ public: /* 0x36D0 */ cXyz m36D0; /* 0x36DC */ cXyz m36DC; /* 0x36E8 */ cXyz mHookshotRootPos; - /* 0x36F4 */ cXyz m36F4; + /* 0x36F4 */ cXyz mBoomerangCatchPos; /* 0x3700 */ cXyz m3700; /* 0x370C */ cXyz m370C; /* 0x3718 */ cXyz m3718; diff --git a/include/dolphin/gf/GFGeometry.h b/include/dolphin/gf/GFGeometry.h index 32d68cace..416942dca 100644 --- a/include/dolphin/gf/GFGeometry.h +++ b/include/dolphin/gf/GFGeometry.h @@ -8,4 +8,30 @@ void GFSetVtxAttrFmtv(GXVtxFmt, GXVtxAttrFmtList*); void GFSetArray(GXAttr, void*, u8); void GFSetCullMode(GXCullMode); +inline void GFBegin(GXPrimitive type, GXVtxFmt fmt, u16 vert_num) { + GXFIFO.u8 = fmt | type; + GXFIFO.u16 = vert_num; +} + +inline void GFEnd() {} + +inline void GFWrite_f32(f32 f) { + GX_WRITE_U32(*reinterpret_cast(&f)); +} + +inline void GFWrite_s16(s16 s) { + GXFIFO.s16 = s; +} + +inline void GFPosition3f32(f32 x, f32 y, f32 z) { + GFWrite_f32(x); + GFWrite_f32(y); + GFWrite_f32(z); +} + +inline void GFTexCoord2s16(s16 u, s16 v) { + GFWrite_s16(u); + GFWrite_s16(v); +} + #endif /* GFGEOMETRY_H */ diff --git a/src/d/actor/d_a_boomerang.cpp b/src/d/actor/d_a_boomerang.cpp index a012ab5be..dc6643561 100644 --- a/src/d/actor/d_a_boomerang.cpp +++ b/src/d/actor/d_a_boomerang.cpp @@ -5,13 +5,766 @@ #include "d/dolzel.h" // IWYU pragma: keep #include "d/actor/d_a_boomerang.h" +#include "d/d_camera.h" #include "d/d_procname.h" #include "d/d_priority.h" #include "d/d_cc_d.h" +#include "d/d_material.h" +#include "d/actor/d_a_player_main.h" +#include "d/res/res_link.h" +#include "dolphin/gf/GF.h" +#include "f_op/f_op_camera.h" +#include "f_op/f_op_camera_mng.h" +#include "m_Do/m_Do_lib.h" + +static cXyz l_blur_top(40.0f, 0.0f, 0.0f); +static cXyz l_blur_root(-40.0f, 0.0f, 0.0f); + +/* 800E0C08-800E0D44 .text initBlur__18daBoomerang_blur_cFPA4_fs */ +void daBoomerang_blur_c::initBlur(MtxP mtx, s16 yRot) { + cMtx_multVec(mtx, &l_blur_top, &trail0_vtxArr0[0]); + cMtx_multVec(mtx, &l_blur_root, &trail0_vtxArr1[0]); + trail0_vtxArr0[1] = trail0_vtxArr0[0]; + trail0_vtxArr1[1] = trail0_vtxArr1[0]; + + numTrailSegments = 0; + + pos.x = mtx[0][3]; + pos.y = mtx[1][3]; + pos.z = mtx[2][3]; + + mDoMtx_stack_c::copy(mtx); + mDoMtx_stack_c::YrotM(-(yRot * 2)); + mDoMtx_stack_c::multVec(&l_blur_top, &trail1_vtxArr0[0]); + mDoMtx_stack_c::multVec(&l_blur_root, &trail1_vtxArr1[0]); + trail1_vtxArr0[1] = trail1_vtxArr0[0]; + trail1_vtxArr1[1] = trail1_vtxArr1[0]; +} + +/* 800E0D44-800E101C .text copyBlur__18daBoomerang_blur_cFPA4_fs */ +void daBoomerang_blur_c::copyBlur(MtxP mtx, s16 yRot) { + for (int i = 54; i >= 0; i--) { + trail0_vtxArr0[SEGMENTS_PER_STEP + i] = trail0_vtxArr0[i]; + trail0_vtxArr1[SEGMENTS_PER_STEP + i] = trail0_vtxArr1[i]; + trail1_vtxArr0[SEGMENTS_PER_STEP + i] = trail1_vtxArr0[i]; + trail1_vtxArr1[SEGMENTS_PER_STEP + i] = trail1_vtxArr1[i]; + } + + float t = 0.0f; + + cXyz inPos; + inPos.x = mtx[0][3]; + inPos.y = mtx[1][3]; + inPos.z = mtx[2][3]; + + cXyz diff = pos - inPos; + + pos = inPos; + + mDoMtx_stack_c::push(); + + s16 yRotPerStep = 0x633; + + int i; + for (i = 0; i < SEGMENTS_PER_STEP; i++) { + mDoMtx_stack_c::multVec(&l_blur_top, &trail0_vtxArr0[i]); + mDoMtx_stack_c::multVec(&l_blur_root, &trail0_vtxArr1[i]); + VECAdd(&trail0_vtxArr0[i], &(diff * t), &trail0_vtxArr0[i]); + VECAdd(&trail0_vtxArr1[i], &(diff * t), &trail0_vtxArr1[i]); + t += 1.0f / SEGMENTS_PER_STEP; + mDoMtx_stack_c::YrotM(yRotPerStep); + } + + t = 0.0f; + + mDoMtx_stack_c::pop(); + + mDoMtx_stack_c::YrotM(-(yRot * 2)); + + for (i = 0; i < SEGMENTS_PER_STEP; i++) { + mDoMtx_stack_c::multVec(&l_blur_top, &trail1_vtxArr0[i]); + mDoMtx_stack_c::multVec(&l_blur_root, &trail1_vtxArr1[i]); + VECAdd(&trail1_vtxArr0[i], &(diff * t), &trail1_vtxArr0[i]); + VECAdd(&trail1_vtxArr1[i], &(diff * t), &trail1_vtxArr1[i]); + t += 1.0f / SEGMENTS_PER_STEP; + mDoMtx_stack_c::YrotM(-yRotPerStep); + } + + numTrailSegments += SEGMENTS_PER_STEP; + + if (numTrailSegments >= 59) { + numTrailSegments = 58; + } +} + +/* 800E101C-800E13A4 .text draw__18daBoomerang_blur_cFv */ +void daBoomerang_blur_c::draw() { +#include "assets/l_matDL__draw__18daBoomerang_blur_cFv.h" + + static GXVtxDescList l_vtxDescList[] ALIGN_DECL(32) = { + {GX_VA_POS, GX_DIRECT}, + {GX_VA_TEX0, GX_DIRECT}, + {GX_VA_NULL, GX_NONE}, + }; + + static GXVtxAttrFmtList l_vtxAttrFmtList[] ALIGN_DECL(32) = { + {GX_VA_POS, GX_POS_XYZ, GX_F32, 0x00}, + {GX_VA_TEX0, GX_TEX_ST, GX_S16, 0x08}, + {GX_VA_NULL, GX_POS_XYZ, GX_F32, 0x00}, + }; + + static GXTexObj texObj; + +#if VERSION > VERSION_JPN + j3dSys.reinitGX(); + GXSetNumIndStages(0); +#endif + + GXInitTexObj(&texObj, imageData, 16, 4, GX_TF_I4, GX_CLAMP, GX_CLAMP, FALSE); + GXInitTexObjLOD(&texObj, GX_LINEAR, GX_LINEAR, 0.0f, 0.0f, 0.0f, FALSE, FALSE, GX_ANISO_1); + GXLoadTexObj(&texObj, GX_TEXMAP0); + + GXCallDisplayList(l_matDL, 0x80); + + // Light yellow color for the trail. + static GXColor color0 = {0xFF, 0xFF, 0x7B, 0x96}; + GFSetTevColor(GX_TEVREG0, color0); + + const s32 uCoordStep = 0xFF / ((numTrailSegments >> 1) + 1); + s16 uCoord1 = uCoordStep; + s16 uCoord0 = 0; + + GFSetVtxDescv(l_vtxDescList); + GFSetVtxAttrFmtv(GX_VTXFMT0, l_vtxAttrFmtList); + + GFLoadPosMtxImm(j3dSys.getViewMtx(), GX_PNMTX0); + +#define QUAD_VTX(xyz, u, v) \ + GFPosition3f32((xyz).x, (xyz).y, (xyz).z); \ + GFTexCoord2s16((u), (v)) + + { + GFBegin(GX_QUADS, GX_VTXFMT0, numTrailSegments * 4 + 4); + + for (int i = numTrailSegments; i >= 0; i--) { + QUAD_VTX(trail0_vtxArr0[i], uCoord1, 0x00); + QUAD_VTX(trail0_vtxArr1[i], uCoord1, 0xFF); + QUAD_VTX(trail0_vtxArr1[i + 1], uCoord0, 0xFF); + QUAD_VTX(trail0_vtxArr0[i + 1], uCoord0, 0x00); + + uCoord0 = uCoord1; + uCoord1 += uCoordStep; + } + + GFEnd(); + } + + { + uCoord1 = uCoordStep; + uCoord0 = 0; + + GFBegin(GX_QUADS, GX_VTXFMT0, numTrailSegments * 4 + 4); + + for (int i = numTrailSegments; i >= 0; i--) { + QUAD_VTX(trail1_vtxArr0[i], uCoord1, 0x00); + QUAD_VTX(trail1_vtxArr1[i], uCoord1, 0xFF); + QUAD_VTX(trail1_vtxArr1[i + 1], uCoord0, 0xFF); + QUAD_VTX(trail1_vtxArr0[i + 1], uCoord0, 0x00); + + uCoord0 = uCoord1; + uCoord1 += uCoordStep; + } + + GFEnd(); + } + +#if VERSION > VERSION_JPN + J3DShape::resetVcdVatCache(); +#endif +} #include "assets/l_sightMatDL.h" #include "assets/l_sightDL__d_a_boomerang.h" +/* 800E13A4-800E14F0 .text draw__25daBoomerang_sightPacket_cFv */ +void daBoomerang_sightPacket_c::draw() { + static GXVtxDescList l_vtxDescList[] ALIGN_DECL(32) = { + {GX_VA_POS, GX_DIRECT}, + {GX_VA_TEX0, GX_DIRECT}, + {GX_VA_NULL, GX_NONE}, + }; + + static GXVtxAttrFmtList l_vtxAttrFmtList[] ALIGN_DECL(32) = { + {GX_VA_POS, GX_POS_XYZ, GX_S8, 0x00}, + {GX_VA_TEX0, GX_TEX_ST, GX_U8, 0x00}, + {GX_VA_NULL, GX_POS_XYZ, GX_F32, 0x00}, + }; + + GXTexObj texObj; + + const GXBool mipmap = mImage->mipmapCount > 1 ? TRUE : FALSE; + GXInitTexObj(&texObj, mTex, mImage->width, mImage->height, GXTexFmt(mImage->format), GXTexWrapMode(mImage->wrapS), GXTexWrapMode(mImage->wrapT), mipmap); + GXInitTexObjLOD(&texObj, GX_LINEAR, GX_LINEAR, 0.0f, 0.0f, 0.0f, FALSE, FALSE, GX_ANISO_1); + GXLoadTexObj(&texObj, GX_TEXMAP0); + + GXCallDisplayList(l_sightMatDL, 0x60); + GFSetVtxDescv(l_vtxDescList); + GFSetVtxAttrFmtv(GX_VTXFMT0, l_vtxAttrFmtList); + + GXColor color0 = {0xFF, 0xFF, 0x32, 0xFF}; + GXColor color1 = {0xFF, 0xFF, 0x32, 0xFF}; + + for (int i = 0; i < BOOMERANG_LOCK_MAX; i++) { + if (mSightOnFlg & (1 << i)) { + color0.a = mScaleArr[i]; + color1.a = mScaleArr[i]; + GFSetTevColor(GX_TEVREG0, color0); + GFSetTevColor(GX_TEVREG1, color1); + GFLoadPosMtxImm(mMtxArr[i], GX_PNMTX0); + GXCallDisplayList(l_sightDL, 0x20); + } + } +} + +/* 800E14F0-800E1718 .text setSight__25daBoomerang_sightPacket_cFP4cXyzi */ +void daBoomerang_sightPacket_c::setSight(cXyz* pPos, int n) { + if (pPos != NULL) { + s32 animFrame = mFrameArr[n]; + f32 pingPongAnim; + f32 imageRot; + if (animFrame < (u32)HALF_ANIM_LENGTH) { + pingPongAnim = 1.0f - animFrame / (f32)HALF_ANIM_LENGTH; + imageRot = -pingPongAnim; + } else { + pingPongAnim = (animFrame - HALF_ANIM_LENGTH) / (f32)HALF_ANIM_LENGTH; + imageRot = pingPongAnim; + } + mScaleArr[n] = pingPongAnim * 30.0f + 150.0f; + + f32 scale = (pingPongAnim * 35.0f + 65.0f) * 0.01f; + f32 scaleX = scale * mImage->width; + f32 scaleY = scale * mImage->height; + + cXyz proj; + mDoLib_project(pPos, &proj); + mDoMtx_stack_c::transS(proj); + mDoMtx_stack_c::scaleM(scaleX, scaleY, scale); + + mDoMtx_stack_c::ZrotM(cM_ssin(imageRot * 16384.0f) * 32768.0f); + MTXCopy(mDoMtx_stack_c::get(), mMtxArr[n]); + + mSightOnFlg |= 1 << n; + } else { + mSightOnFlg &= ~(1 << n); + } +} + +/* 800E1718-800E1754 .text play__25daBoomerang_sightPacket_cFi */ +void daBoomerang_sightPacket_c::play(int n) { + u8* p = &mFrameArr[0]; + for (int i = 0; i < n; i++) { + *p = *p + 1; + if (*p == ANIM_LENGTH) { + *p = 0; + } + p++; + } +} + +/* 800E1754-800E1998 .text draw__13daBoomerang_cFv */ +BOOL daBoomerang_c::draw() { + dComIfGd_setListP1(); + + if (!mThirdPerson && mLockCnt != 0) { + mSightPacket.resetSightOn(); + for (int i = mCurLockIdx; i < mLockCnt; i++) { + fopAc_ac_c* pActor = mLockActors[i]; + if (pActor) { + mSightPacket.setSight(&pActor->eyePos, i); + } else { + mSightPacket.setSight(NULL, i); + } + } + + dComIfGd_set2DXlu(&mSightPacket); + } + + if (mBlur.numTrailSegments > 0) { + dComIfGd_entryZSortXluList(&mBlur, current.pos); + } + + if (daPy_getPlayerActorClass()->checkPlayerNoDraw() && fopAcM_GetParam(this) == Mode_Wait) { + dComIfGd_setList(); + return TRUE; + } + + dKy_getEnvlight().settingTevStruct(TEV_TYPE_ACTOR, ¤t.pos, &tevStr); + dKy_getEnvlight().setLightTevColorType(mpModel, &tevStr); + + if (fopAcM_GetParam(this) == Mode_Wait && daPy_getPlayerLinkActorClass()->checkFreezeState()) { + dMat_control_c::iceUpdateDL(mpModel, -1, NULL); + } else { + mDoExt_modelUpdateDL(mpModel); + } + + dComIfGd_setList(); + + if (mGroundY != -G_CM3D_F_INF && fopAcM_GetParam(this) == Mode_Throw) { + cXyz* pFloorNrm = dComIfG_Bgsp()->GetTriPla(mGndChk)->GetNP(); + if (pFloorNrm) { + dComIfGd_setSimpleShadow(¤t.pos, mGroundY, 30.0f, pFloorNrm); + } + } + + return TRUE; +} + +/* 800E1998-800E19B8 .text daBoomerang_Draw__FP13daBoomerang_c */ +static BOOL daBoomerang_Draw(daBoomerang_c* i_this) { + return i_this->draw(); +} + +/* 800E19B8-800E1A14 .text getFlyMax__13daBoomerang_cFv */ +float daBoomerang_c::getFlyMax() { + if (dComIfGp_checkPlayerStatus0(0, 0x10000) != 0) { + return 5000.0f; + } + + if (strcmp(dComIfGp_getStartStageName(), "GanonK") != 0) { + return 2500.0f; + } + + return 5000.0f; +} + +/* 800E1A14-800E1AAC .text rockLineCallback__13daBoomerang_cFP10fopAc_ac_c */ +void daBoomerang_c::rockLineCallback(fopAc_ac_c* pHitActor) { + if (fopAcM_GetParam(this) == Mode_Wait) { + if (pHitActor) { + setLockActor(pHitActor, TRUE); + } + } else { + for (int i = 0; i < BOOMERANG_LOCK_MAX; i++) { + if (mLockActors[i] == pHitActor) { + mLockActorIDs[i] = -1; + mLockActors[i] = NULL; + if (i == mCurLockIdx) { + mJustHit = true; + mCurLockIdx++; + } + } + } + } +} + +/* 800E1AAC-800E1AD0 .text daBoomerang_rockLineCallback__FP10fopAc_ac_cP12dCcD_GObjInfP10fopAc_ac_cP12dCcD_GObjInf */ +void daBoomerang_rockLineCallback(fopAc_ac_c* i_actor, dCcD_GObjInf*, fopAc_ac_c* i_hit, dCcD_GObjInf*) { + ((daBoomerang_c*)i_actor)->rockLineCallback(i_hit); +} + +/* 800E1AD0-800E1B20 .text setAimActor__13daBoomerang_cFP10fopAc_ac_c */ +void daBoomerang_c::setAimActor(fopAc_ac_c* i_actor) { + resetLockActor(); + mThirdPerson = true; + setLockActor(i_actor, FALSE); +} + +/* 800E1B20-800E1C20 .text setLockActor__13daBoomerang_cFP10fopAc_ac_ci */ +BOOL daBoomerang_c::setLockActor(fopAc_ac_c* i_actor, BOOL doSoundEffect) { + if (mLockCnt >= BOOMERANG_LOCK_MAX) { + return FALSE; + } + + fpc_ProcID id = fopAcM_GetID(i_actor); + + for (int i = 0; i < mLockCnt; i++) { + if (mLockActorIDs[i] == id) { + return FALSE; + } + } + + mLockActorIDs[mLockCnt] = id; + mLockActors[mLockCnt] = i_actor; + mSightPacket.initFrame(mLockCnt); + + if (doSoundEffect) { + static const u32 se_flg[BOOMERANG_LOCK_MAX] = { + JA_SE_BOOM_LOCK_ON_1, + JA_SE_BOOM_LOCK_ON_2, + JA_SE_BOOM_LOCK_ON_3, + JA_SE_BOOM_LOCK_ON_4, + JA_SE_BOOM_LOCK_ON_5, + }; + + mDoAud_seStart(se_flg[mLockCnt]); + } + + mLockCnt++; + return TRUE; +} + +/* 800E1C20-800E1C58 .text resetLockActor__13daBoomerang_cFv */ +void daBoomerang_c::resetLockActor() { + for (int i = 0; i < BOOMERANG_LOCK_MAX; i++) { + mLockActorIDs[i] = fpcM_ERROR_PROCESS_ID_e; + mLockActors[i] = NULL; + } + + mLockCnt = 0; + mCurLockIdx = 0; +} + +/* 800E1C58-800E1CFC .text setRoomInfo__13daBoomerang_cFv */ +void daBoomerang_c::setRoomInfo() { + mGndChk.SetPos(¤t.pos); + + f32 groundY = dComIfG_Bgsp()->GroundCross(&mGndChk); + s32 roomNo; + if (groundY != -G_CM3D_F_INF) { + roomNo = dComIfG_Bgsp()->GetRoomId(mGndChk); + tevStr.mEnvrIdxOverride = dComIfG_Bgsp()->GetPolyColor(mGndChk); + } else { + roomNo = dComIfGp_roomControl_getStayNo(); + } + + tevStr.mRoomNo = roomNo; + mStts.SetRoomId(roomNo); + current.roomNo = roomNo; +} + +/* 800E1CFC-800E1DA8 .text setKeepMatrix__13daBoomerang_cFv */ +void daBoomerang_c::setKeepMatrix() { + // Transform the boomerang to Link's hand. + mDoMtx_stack_c::copy(daPy_getPlayerActorClass()->getLeftHandMatrix()); + mDoMtx_stack_c::transM(10.3f, 36.6f, 1.1f); + mDoMtx_stack_c::XYZrotM(-0x39f4, -0x357, -0x2af3); + MtxP mtx = mDoMtx_stack_c::get(); + mpModel->setBaseTRMtx(mtx); + current.pos.set(mtx[0][3], mtx[1][3], mtx[2][3]); +} + +/* 800E1DA8-800E1E6C .text setAimPos__13daBoomerang_cFv */ +void daBoomerang_c::setAimPos() { + if (mIsReturning) { + mTargetPos = daPy_getPlayerLinkActorClass()->getBoomerangCatchPos(); + } else { + for (int i = mCurLockIdx; i < mLockCnt; i++) { + if (mLockActors[i] != NULL) { + mTargetPos = mLockActors[i]->eyePos; + return; + } + mCurLockIdx++; + } + } +} + +/* 800E1E6C-800E1F94 .text checkBgHit__13daBoomerang_cFP4cXyzP4cXyz */ +void daBoomerang_c::checkBgHit(cXyz* pi_start, cXyz* pi_end) { + mLinChk.Set(pi_start, pi_end, this); + if (dComIfG_Bgsp()->LineCross(&mLinChk)) { + current.pos.set(mLinChk.GetCross()); + dComIfGp_particle_setP1(dPa_name::ID_COMMON_PURPLE_HIT, ¤t.pos); + mIsReturning = true; + current.angle.y += 0x8000; + shape_angle.y = current.angle.y; + resetLockActor(); + u32 mtrlSndId = dComIfG_Bgsp()->GetMtrlSndId(mLinChk); + s8 roomNo = current.roomNo; + s8 reverb = dComIfGp_getReverb(roomNo); + mDoAud_seStart(JA_SE_LK_W_WEP_HIT, &eyePos, mtrlSndId, reverb); + } +} + +/* 800E1F94-800E239C .text procWait__13daBoomerang_cFv */ +BOOL daBoomerang_c::procWait() { + daPy_lk_c* pPlayer = daPy_getPlayerLinkActorClass(); + speedF = 0.0f; + setKeepMatrix(); + + if (mBlur.numTrailSegments > 0) { + mBlur.numTrailSegments -= daBoomerang_blur_c::SEGMENTS_PER_STEP; + } + + if (fopAcM_GetParam(this) == Mode_Throw) { + speedF = 60.0f; + mCps.ResetAtHit(); + mCps.OffAtNoTgHitInfSet(); + mIsReturning = false; + unused_0xF2D = true; + mJustHit = false; + mCurLockIdx = 0; + + setAimPos(); + + if (mCurLockIdx == mLockCnt) { + resetLockActor(); + + s16 angleY = pPlayer->getBodyAngleY() + pPlayer->shape_angle.y; + s16 angleX = pPlayer->getBodyAngleX(); + + f32 flyMax = getFlyMax(); + + mTargetPos.set( + current.pos.x + flyMax * cM_ssin(angleY) * cM_scos(angleX), + current.pos.y - flyMax * cM_ssin(angleX), + current.pos.z + flyMax * cM_scos(angleY) * cM_scos(angleX) + ); + } + + mModelRotY = 0; + + cXyz diff = mTargetPos - current.pos; + + s16 angle = cM_atan2s(-diff.y, diff.absXZ()); + current.angle.x = angle; + if (mLockCnt == 0) { + current.angle.y = cM_atan2s(diff.x, diff.z) + 0x3000; + if (mThirdPerson) { + mFreeFlyOut = false; + } else { + mFreeFlyOut = true; + } + } else { + current.angle.y = cM_atan2s(diff.x, diff.z); + mFreeFlyOut = false; + } + + shape_angle.x = current.angle.x; + shape_angle.y = current.angle.y; + shape_angle.z = 0x2000; + mModelRotZ = 0x2000; + + mProcFunc = &daBoomerang_c::procMove; + + mCancelFlg = false; + + mBlur.initBlur(mpModel->getBaseTRMtx(), mModelRotY); + + cXyz bgHitPos(pPlayer->current.pos.x, pPlayer->current.pos.y + 60.0f, pPlayer->current.pos.z); + checkBgHit(&bgHitPos, ¤t.pos); + + procMove(); + } else { + if (dCam_getBody()->mCurMode != 0xB) { + resetLockActor(); + } else { + bool isAiming = (pPlayer->mCurProc == daPy_lk_c::daPyProc_BOOMERANG_SUBJECT_e || pPlayer->mCurProc == daPy_lk_c::daPyProc_SHIP_BOOMERANG_e) && + pPlayer->mSightPacket.getDrawFlg(); + + if (isAiming) { + camera_class* pCamera = dComIfGp_getCamera(dComIfGp_getPlayerCameraID(0)); + cXyz eyePos = *fopCamM_GetEye_p(pCamera); + cXyz topPos = pPlayer->getLineTopPos(); + mCps.OnAtNoTgHitInfSet(); + mCps.cM3dGCps::Set(eyePos, topPos, 3.0f); + + mCps.CalcAtVec(); + mCps.SetAtHitCallback(&daBoomerang_rockLineCallback); + + dComIfG_Ccsp()->Set(&mCps); + } + } + } + + return TRUE; +} + +/* 800E239C-800E2AF4 .text procMove__13daBoomerang_cFv */ +BOOL daBoomerang_c::procMove() { + static cXyz at_offset; // Never used. + + if (mCatchAndDelete) { + fopAcM_delete(this); + return TRUE; + } + + if (dComIfGp_event_getMode() == dEvtMode_NONE_e) { + daPy_lk_c* pPlayer = daPy_getPlayerLinkActorClass(); + s16 s = mModelRotY; + mModelRotY -= 0x1F00; + if (s >= 0 && mModelRotY < 0) { + s8 roomNo = current.roomNo; + mDoAud_seStart(JA_SE_LK_BOOM_FLY, &eyePos, 0, dComIfGp_getReverb(roomNo)); + } + setAimPos(); + + cXyz diff = mTargetPos - current.pos; + f32 dist = diff.abs(); + cXyz norm; + if (dist > 0.1f) { + norm = diff / dist; + } else { + norm = diff; + } + + s16 angle = cM_atan2s(norm.x, norm.z); + s16 currentAngle = angle - current.angle.y; + + if (mJustHit) { + mJustHit = false; + if (s16(angle - current.angle.y) > 0) { + current.angle.y = angle - 0x3000; + } else { + current.angle.y = angle + 0x3000; + } + currentAngle = angle - current.angle.y; + } + + if (mIsReturning) { + if (dist < speedF * 2.0f) { + if (pPlayer->returnBoomerang()) { + fopAcM_SetParam(this, Mode_Wait); + mThirdPerson = false; + mProcFunc = &daBoomerang_c::procWait; + mCps.SetAtHitCallback(NULL); + } else { + mCatchAndDelete = true; + } + } + } else { + if (dist < speedF || mCps.ChkAtHit() && mCps.GetAtHitAc() == mLockActors[mCurLockIdx]) { + // Boomerang hit its current target. + mJustHit = true; + mLockActors[mCurLockIdx] = NULL; + mLockActorIDs[mCurLockIdx] = fpcM_ERROR_PROCESS_ID_e; + mCurLockIdx++; + mFreeFlyOut = false; + } + } + + if (!mIsReturning && (mCancelFlg || (!mFreeFlyOut && mLockCnt <= mCurLockIdx) || mCps.ChkAtShieldHit())) { + // Boomerang should return. It either was canceled, hit its last target, or hit a shield. + mJustHit = true; + mIsReturning = true; + resetLockActor(); + mCancelFlg = false; + mFreeFlyOut = false; + } + + if (mJustHit) { + current.angle.y = angle; + } else { + s16 newAngle; + if (!mThirdPerson) { + f32 a = 20.0f - dist * 2.0f / speedF; + if (a < 0.0f) { + a = 0.0f; + } else if (a > 18.0f) { + a = 20.0f + 40.0f * (a - 18.0f); + } + newAngle = a * 256.0f + 1024.0f; + } else { + newAngle = 0x4000; + } + + if (currentAngle > newAngle) { + currentAngle = newAngle; + } else if (currentAngle < -newAngle) { + currentAngle = -newAngle; + } + current.angle.y += currentAngle; + } + + angle = cM_atan2s(-norm.y, norm.absXZ()); + current.angle.x = angle; + + current.pos.x += speedF * cM_scos(current.angle.x) * cM_ssin(current.angle.y); + current.pos.y -= speedF * cM_ssin(current.angle.x); + current.pos.z += speedF * cM_scos(current.angle.x) * cM_scos(current.angle.y); + + shape_angle.y = current.angle.y; + shape_angle.x = current.angle.x; + + if (!mIsReturning) { + checkBgHit(&old.pos, ¤t.pos); + } + + currentAngle = -(currentAngle * 2); + + if (currentAngle > 0x100) { + currentAngle = 0x2000; + } else if (currentAngle < -0x100) { + currentAngle = -0x2000; + } else { + currentAngle = mModelRotZ; + } + + mModelRotZ = currentAngle; + cLib_addCalcAngleS(&shape_angle.z, currentAngle, 0x10, 0x1000, 0x10); + } + + mDoMtx_stack_c::transS(current.pos); + mDoMtx_stack_c::ZXYrotM(shape_angle.x, shape_angle.y, shape_angle.z); + mDoMtx_stack_c::YrotM(mModelRotY); + mpModel->setBaseTRMtx(mDoMtx_stack_c::get()); + mCps.cM3dGCps::Set(old.pos, current.pos, 30.0f); + mCps.CalcAtVec(); + + if (dComIfGp_event_getMode() == dEvtMode_NONE_e) { + mBlur.copyBlur(mDoMtx_stack_c::get(), mModelRotY); + dComIfG_Ccsp()->Set(&mCps); + dComIfG_Ccsp()->SetMass(&mCps, 1); + } else { + mBlur.copyBlur(mDoMtx_stack_c::get(), 0); + mCps.ResetAtHit(); + } + + mInWater = daPy_lk_c::setItemWaterEffect(this, mInWater, TRUE); + + return TRUE; +} + +/* 800E2AF4-800E2BD0 .text execute__13daBoomerang_cFv */ +BOOL daBoomerang_c::execute() { + for (int i = 0; i < mLockCnt; i++) { + mLockActors[i] = fopAcM_SearchByID(mLockActorIDs[i]); + } + + if (mProcFunc) { + (this->*mProcFunc)(); + } + + attention_info.position = current.pos; + eyePos = current.pos; + + setRoomInfo(); + mSightPacket.play(mLockCnt); + + return TRUE; +} + +/* 800E2BD0-800E2BF0 .text daBoomerang_Execute__FP13daBoomerang_c */ +static BOOL daBoomerang_Execute(daBoomerang_c* i_this) { + return i_this->execute(); +} + +/* 800E2BF0-800E2BF8 .text daBoomerang_IsDelete__FP13daBoomerang_c */ +static BOOL daBoomerang_IsDelete(daBoomerang_c*) { + return TRUE; +} + +/* 800E2BF8-800E2C00 .text daBoomerang_Delete__FP13daBoomerang_c */ +static BOOL daBoomerang_Delete(daBoomerang_c*) { + return TRUE; +} + +/* 800E2C00-800E2CC8 .text createHeap__13daBoomerang_cFv */ +BOOL daBoomerang_c::createHeap() { + J3DModelData* modelData = (J3DModelData*)dComIfG_getObjectRes("Link", LINK_BDL_BOOMERANG); + + JUT_ASSERT(VERSION_SELECT(1543, 1539, 1546, 1546), modelData != NULL); + + mpModel = mDoExt_J3DModel__create(modelData, 0x80000, 0x37220202); + if (mpModel == NULL) + return FALSE; + return TRUE; +} + +/* 800E2CC8-800E2CE8 .text daBoomerang_createHeap__FP10fopAc_ac_c */ +static BOOL daBoomerang_createHeap(fopAc_ac_c* i_this) { + return static_cast(i_this)->createHeap(); +} + static dCcD_SrcCps l_at_cps_src = { // dCcD_SrcGObjInf { @@ -42,140 +795,54 @@ static dCcD_SrcCps l_at_cps_src = { }}, }; - -/* 800E0C08-800E0D44 .text initBlur__18daBoomerang_blur_cFPA4_fs */ -void daBoomerang_blur_c::initBlur(MtxP, s16) { - /* Nonmatching */ -} - -/* 800E0D44-800E101C .text copyBlur__18daBoomerang_blur_cFPA4_fs */ -void daBoomerang_blur_c::copyBlur(MtxP, s16) { - /* Nonmatching */ -} - -/* 800E101C-800E13A4 .text draw__18daBoomerang_blur_cFv */ -void daBoomerang_blur_c::draw() { - /* Nonmatching */ -} - -/* 800E13A4-800E14F0 .text draw__25daBoomerang_sightPacket_cFv */ -void daBoomerang_sightPacket_c::draw() { - /* Nonmatching */ -} - -/* 800E14F0-800E1718 .text setSight__25daBoomerang_sightPacket_cFP4cXyzi */ -void daBoomerang_sightPacket_c::setSight(cXyz*, int) { - /* Nonmatching */ -} - -/* 800E1718-800E1754 .text play__25daBoomerang_sightPacket_cFi */ -void daBoomerang_sightPacket_c::play(int) { - /* Nonmatching */ -} - -/* 800E1754-800E1998 .text draw__13daBoomerang_cFv */ -BOOL daBoomerang_c::draw() { - /* Nonmatching */ -} - -/* 800E1998-800E19B8 .text daBoomerang_Draw__FP13daBoomerang_c */ -static BOOL daBoomerang_Draw(daBoomerang_c* i_this) { - return ((daBoomerang_c*)i_this)->draw(); -} - -/* 800E19B8-800E1A14 .text getFlyMax__13daBoomerang_cFv */ -float daBoomerang_c::getFlyMax() { - /* Nonmatching */ -} - -/* 800E1A14-800E1AAC .text rockLineCallback__13daBoomerang_cFP10fopAc_ac_c */ -void daBoomerang_c::rockLineCallback(fopAc_ac_c*) { - /* Nonmatching */ -} - -/* 800E1AAC-800E1AD0 .text daBoomerang_rockLineCallback__FP10fopAc_ac_cP12dCcD_GObjInfP10fopAc_ac_cP12dCcD_GObjInf */ -void daBoomerang_rockLineCallback(fopAc_ac_c*, dCcD_GObjInf*, fopAc_ac_c*, dCcD_GObjInf*) { - /* Nonmatching */ -} - -/* 800E1AD0-800E1B20 .text setAimActor__13daBoomerang_cFP10fopAc_ac_c */ -void daBoomerang_c::setAimActor(fopAc_ac_c*) { - /* Nonmatching */ -} - -/* 800E1B20-800E1C20 .text setLockActor__13daBoomerang_cFP10fopAc_ac_ci */ -void daBoomerang_c::setLockActor(fopAc_ac_c*, int) { - /* Nonmatching */ -} - -/* 800E1C20-800E1C58 .text resetLockActor__13daBoomerang_cFv */ -void daBoomerang_c::resetLockActor() { - /* Nonmatching */ -} - -/* 800E1C58-800E1CFC .text setRoomInfo__13daBoomerang_cFv */ -void daBoomerang_c::setRoomInfo() { - /* Nonmatching */ -} - -/* 800E1CFC-800E1DA8 .text setKeepMatrix__13daBoomerang_cFv */ -void daBoomerang_c::setKeepMatrix() { - /* Nonmatching */ -} - -/* 800E1DA8-800E1E6C .text setAimPos__13daBoomerang_cFv */ -void daBoomerang_c::setAimPos() { - /* Nonmatching */ -} - -/* 800E1E6C-800E1F94 .text checkBgHit__13daBoomerang_cFP4cXyzP4cXyz */ -void daBoomerang_c::checkBgHit(cXyz*, cXyz*) { - /* Nonmatching */ -} - -/* 800E1F94-800E239C .text procWait__13daBoomerang_cFv */ -void daBoomerang_c::procWait() { - /* Nonmatching */ -} - -/* 800E239C-800E2AF4 .text procMove__13daBoomerang_cFv */ -void daBoomerang_c::procMove() { - /* Nonmatching */ -} - -/* 800E2AF4-800E2BD0 .text execute__13daBoomerang_cFv */ -BOOL daBoomerang_c::execute() { - /* Nonmatching */ -} - -/* 800E2BD0-800E2BF0 .text daBoomerang_Execute__FP13daBoomerang_c */ -static BOOL daBoomerang_Execute(daBoomerang_c* i_this) { - return ((daBoomerang_c*)i_this)->execute(); -} - -/* 800E2BF0-800E2BF8 .text daBoomerang_IsDelete__FP13daBoomerang_c */ -static BOOL daBoomerang_IsDelete(daBoomerang_c*) { - return TRUE; -} - -/* 800E2BF8-800E2C00 .text daBoomerang_Delete__FP13daBoomerang_c */ -static BOOL daBoomerang_Delete(daBoomerang_c*) { - return TRUE; -} - -/* 800E2C00-800E2CC8 .text createHeap__13daBoomerang_cFv */ -void daBoomerang_c::createHeap() { - /* Nonmatching */ -} - -/* 800E2CC8-800E2CE8 .text daBoomerang_createHeap__FP10fopAc_ac_c */ -static BOOL daBoomerang_createHeap(fopAc_ac_c*) { - /* Nonmatching */ -} - /* 800E2CE8-800E2EF0 .text create__13daBoomerang_cFv */ cPhs_State daBoomerang_c::create() { - /* Nonmatching */ + fopAcM_SetupActor(this, daBoomerang_c); + + if (!fopAcM_entrySolidHeap(this, daBoomerang_createHeap, 0xD40)) { + return cPhs_ERROR_e; + } + + setKeepMatrix(); + fopAcM_SetMtx(this, mpModel->getBaseTRMtx()); + mProcFunc = &daBoomerang_c::procWait; + mStts.Init(0x3C, 0xFF, this); + + mCps.Set(l_at_cps_src); + mCps.SetStts(&mStts); + mCps.SetAtHitCallback(&daBoomerang_rockLineCallback); + + mLinChk.ClrSttsRoofOff(); + + for (int i = 0; i < BOOMERANG_LOCK_MAX; i++) { + mLockActorIDs[i] = fpcM_ERROR_PROCESS_ID_e; + } + + { + ResTIMG* tmp_img = (ResTIMG*)dComIfG_getObjectRes("Link", LINK_BTI_BLUR); + + JUT_ASSERT(VERSION_SELECT(1626, 1622, 1629, 1629), tmp_img != NULL); + + mBlur.imageData = (u8*)tmp_img + tmp_img->imageOffset; + } + + { + ResTIMG* tmp_img = (ResTIMG*)dComIfG_getObjectRes("Link", LINK_BTI_ROCK_MARK); + + JUT_ASSERT(VERSION_SELECT(1634, 1630, 1637, 1637), tmp_img != NULL); + + mSightPacket.setTex((u8*)tmp_img + tmp_img->imageOffset); + mSightPacket.setImage(tmp_img); + } + + setRoomInfo(); + model = mpModel; + + return cPhs_COMPLEATE_e; +} + +/* 800E2EF0-800E329C .text __ct__13daBoomerang_cFv */ +daBoomerang_c::daBoomerang_c() { } /* 800E33F0-800E3410 .text daBoomerang_Create__FP10fopAc_ac_c */ diff --git a/src/d/actor/d_a_player_boomerang.inc b/src/d/actor/d_a_player_boomerang.inc index 6849cd812..7792e9ef9 100644 --- a/src/d/actor/d_a_player_boomerang.inc +++ b/src/d/actor/d_a_player_boomerang.inc @@ -24,7 +24,7 @@ BOOL daPy_lk_c::checkBoomerangAnime() const { void daPy_lk_c::throwBoomerang() { daBoomerang_c* boomerang = (daBoomerang_c*)mActorKeepEquip.getActor(); - fopAcM_SetParam(boomerang, 1); + fopAcM_SetParam(boomerang, daBoomerang_c::Mode_Throw); if (mpAttnActorLockOn != NULL) { boomerang->setAimActor(mpAttnActorLockOn); } @@ -47,7 +47,7 @@ void daPy_lk_c::throwBoomerang() { } /* 80149698-801497A4 .text returnBoomerang__9daPy_lk_cFv */ -int daPy_lk_c::returnBoomerang() { +BOOL daPy_lk_c::returnBoomerang() { dComIfGp_clearPlayerStatus0(0, daPyStts0_BOOMERANG_WAIT_e); if (mEquipItem == daPyItem_NONE_e && !checkNoControll() && !dComIfGp_event_runCheck() && mDemo.getDemoType() == 0 && diff --git a/src/d/actor/d_a_player_main.cpp b/src/d/actor/d_a_player_main.cpp index 129889c31..7b3185168 100644 --- a/src/d/actor/d_a_player_main.cpp +++ b/src/d/actor/d_a_player_main.cpp @@ -11650,7 +11650,7 @@ BOOL daPy_lk_c::execute() { checkRoofRestart(); mDoMtx_multVecZero(mpCLModel->getAnmMtx(0x08), &mLeftHandPos); mDoMtx_multVecZero(mpCLModel->getAnmMtx(0x0C), &mRightHandPos); - cMtx_multVec(mpCLModel->getAnmMtx(0x00), &boomerang_catch, &m36F4); + cMtx_multVec(mpCLModel->getAnmMtx(0x00), &boomerang_catch, &mBoomerangCatchPos); cMtx_multVec(mpCLModel->getAnmMtx(0x08), &hookshot_root, &mHookshotRootPos); mpKatsuraModel->setBaseTRMtx(mpCLModel->getAnmMtx(0x0F)); mpKatsuraModel->calc(); diff --git a/src/d/actor/d_a_player_particle.inc b/src/d/actor/d_a_player_particle.inc index 79cc71153..f72fa684b 100644 --- a/src/d/actor/d_a_player_particle.inc +++ b/src/d/actor/d_a_player_particle.inc @@ -1276,16 +1276,19 @@ void daPy_lk_c::endDamageEmitter() { } /* 8012CA44-8012CD60 .text setItemWaterEffect__9daPy_lk_cFP10fopAc_ac_cii */ -u32 daPy_lk_c::setItemWaterEffect(fopAc_ac_c* i_actor, int param_1, int param_2) { +BOOL daPy_lk_c::setItemWaterEffect(fopAc_ac_c* i_actor, BOOL inWater, BOOL triggerOnExit) { static cXyz eff_scale0(0.5f, 0.5f, 0.5f); static cXyz eff_scale2(0.13f, 0.13f, 0.13f); static JGeometry::TVec3 direction(0.0f, 1.0f, 0.0f); f32 waterY; - if (fopAcM_getWaterY(&i_actor->current.pos, &waterY) && ((param_1 != 0 && i_actor->current.pos.y > waterY) || (param_1 == 0 && waterY >= i_actor->current.pos.y))) { - param_1 ^= 1; - if (param_1 == 0 && param_2 == 0) { - return param_1; + if (fopAcM_getWaterY(&i_actor->current.pos, &waterY) && + ((inWater && i_actor->current.pos.y > waterY) || (!inWater && waterY >= i_actor->current.pos.y))) + { + // Item entered or exited the water. + inWater ^= 1; + if (!inWater && !triggerOnExit) { + return inWater; } f32 deltaY = std::fabsf(i_actor->old.pos.y - i_actor->current.pos.y); @@ -1321,5 +1324,5 @@ u32 daPy_lk_c::setItemWaterEffect(fopAc_ac_c* i_actor, int param_1, int param_2) } } - return param_1; + return inWater; }