From 5db0dd62556a70013017653eefea6c4e9328516e Mon Sep 17 00:00:00 2001 From: Henrique Gemignani Passos Lima Date: Sat, 4 Jul 2026 15:46:33 +0300 Subject: [PATCH] First CPlayerGun::UpdateChargeState --- config/G2ME01/splits.txt | 3 +- config/G2ME01/symbols.txt | 10 ++-- include/MetroidPrime/CRumbleManager.hpp | 27 +++++++++++ include/MetroidPrime/CStateManager.hpp | 1 + include/MetroidPrime/Player/CPlayerGun.hpp | 50 +++++++++++++++++--- include/MetroidPrime/Player/CPlayerState.hpp | 1 + src/MetroidPrime/Player/CPlayerGun.cpp | 40 ++++++++++++++++ 7 files changed, 120 insertions(+), 12 deletions(-) create mode 100644 include/MetroidPrime/CRumbleManager.hpp diff --git a/config/G2ME01/splits.txt b/config/G2ME01/splits.txt index e2a7965..d55ede3 100644 --- a/config/G2ME01/splits.txt +++ b/config/G2ME01/splits.txt @@ -85,7 +85,8 @@ MetroidPrime/CDamageInfo.cpp: .text start:0x80189FD4 end:0x8018A188 MetroidPrime/Player/CPlayerGun.cpp: - .text start:0x801C6DF8 end:0x801C8CE8 + .text start:0x801C6DF8 end:0x801D2F0C + .ctors start:0x803A5578 end:0x803A557C .sdata2 start:0x8041D11C end:0x8041D124 MetroidPrime/Weapons/CPowerBeam.cpp: diff --git a/config/G2ME01/symbols.txt b/config/G2ME01/symbols.txt index 5a6c3d5..515c777 100644 --- a/config/G2ME01/symbols.txt +++ b/config/G2ME01/symbols.txt @@ -6020,9 +6020,9 @@ fn_8016CB64 = .text:0x8016CB64; // type:function size:0x214 align:4 fn_8016CD78 = .text:0x8016CD78; // type:function size:0x49C fn_8016D214 = .text:0x8016D214; // type:function size:0xA44 align:4 fn_8016DC58 = .text:0x8016DC58; // type:function size:0x24 align:4 -fn_8016DC7C = .text:0x8016DC7C; // type:function size:0x30 +StopRumble__14CRumbleManagerFs = .text:0x8016DC7C; // type:function size:0x30 fn_8016DCAC = .text:0x8016DCAC; // type:function size:0x10C align:4 -fn_8016DDB8 = .text:0x8016DDB8; // type:function size:0xE4 +Rumble__14CRumbleManagerFR13CStateManager11ERumbleFxIdf15ERumblePriority = .text:0x8016DDB8; // type:function size:0xE4 fn_8016DE9C = .text:0x8016DE9C; // type:function size:0x60 fn_8016DEFC = .text:0x8016DEFC; // type:function size:0x40 fn_8016DF3C = .text:0x8016DF3C; // type:function size:0x104 align:4 @@ -7471,7 +7471,7 @@ fn_801CC1A0 = .text:0x801CC1A0; // type:function size:0x4F8 align:4 fn_801CC698 = .text:0x801CC698; // type:function size:0x618 align:4 fn_801CCCB0 = .text:0x801CCCB0; // type:function size:0x16C fn_801CCE1C = .text:0x801CCE1C; // type:function size:0xD8 -fn_801CCEF4 = .text:0x801CCEF4; // type:function size:0x1B8 align:4 +UpdateChargeState__10CPlayerGunFfR13CStateManager = .text:0x801CCEF4; // type:function size:0x1B8 align:4 fn_801CD0AC = .text:0x801CD0AC; // type:function size:0x38C fn_801CD438 = .text:0x801CD438; // type:function size:0x124 fn_801CD55C = .text:0x801CD55C; // type:function size:0x4BC @@ -7525,7 +7525,7 @@ fn_801D20C8 = .text:0x801D20C8; // type:function size:0x50 fn_801D2118 = .text:0x801D2118; // type:function size:0x84 fn_801D219C = .text:0x801D219C; // type:function size:0x94 __ct__10CPlayerGunF9TUniqueIdi = .text:0x801D2230; // type:function size:0x714 -fn_801D2944 = .text:0x801D2944; // type:function size:0x5C8 align:4 +__sinit_CPlayerGun_cpp = .text:0x801D2944; // type:function size:0x5C8 align:4 fn_801D2F0C = .text:0x801D2F0C; // type:function size:0x1FC align:4 fn_801D3108 = .text:0x801D3108; // type:function size:0x38 align:4 fn_801D3140 = .text:0x801D3140; // type:function size:0x1F4 align:4 @@ -7699,7 +7699,7 @@ fn_801DD53C = .text:0x801DD53C; // type:function size:0x190 align:4 fn_801DD6CC = .text:0x801DD6CC; // type:function size:0x30 fn_801DD6FC = .text:0x801DD6FC; // type:function size:0x18 align:4 fn_801DD714 = .text:0x801DD714; // type:function size:0x10 align:4 -fn_801DD724 = .text:0x801DD724; // type:function size:0x34 +GetPlayerFromAll__10CPlayerGunCFR13CStateManager = .text:0x801DD724; // type:function size:0x34 GetPlayer__10CPlayerGunCFR13CStateManager = .text:0x801DD758; // type:function size:0x34 fn_801DD78C = .text:0x801DD78C; // type:function size:0x320 fn_801DDAAC = .text:0x801DDAAC; // type:function size:0x310 align:4 diff --git a/include/MetroidPrime/CRumbleManager.hpp b/include/MetroidPrime/CRumbleManager.hpp new file mode 100644 index 0000000..e94c3aa --- /dev/null +++ b/include/MetroidPrime/CRumbleManager.hpp @@ -0,0 +1,27 @@ +#ifndef _CRUMBLEMANAGER +#define _CRUMBLEMANAGER + +#include "types.h" + +#include "Kyoto/Input/CRumbleGenerator.hpp" + +class CStateManager; +class CVector3f; + +class CRumbleManager { +public: + CRumbleManager(); + ~CRumbleManager(); + + short Rumble(CStateManager&, const CVector3f&, ERumbleFxId, float, ERumblePriority); + short Rumble(CStateManager&, ERumbleFxId, float, ERumblePriority); + + void StopRumble(short id); + void HardStopAll() { x0_rumbleGenerator.HardStopAll(); } + void Update(float dt); + +private: + CRumbleGenerator x0_rumbleGenerator; +}; + +#endif // _CRUMBLEMANAGER diff --git a/include/MetroidPrime/CStateManager.hpp b/include/MetroidPrime/CStateManager.hpp index 6749f00..0b0fbf2 100644 --- a/include/MetroidPrime/CStateManager.hpp +++ b/include/MetroidPrime/CStateManager.hpp @@ -146,6 +146,7 @@ public: const CPlayerState* GetPlayerState() const { return m_playerState; } const CPlayerState* GetPlayerState(int playerIndex) const { return m_playerStates[playerIndex]; } CPlayerState* PlayerState(int playerIndex) { return m_playerStates[playerIndex]; } + CRumbleManager* RumbleManager(int playerIndex) { return m_rumbleManagers[playerIndex]; } int fn_800366e4(CActor *); int fn_801EDD8C(TUniqueId) const; diff --git a/include/MetroidPrime/Player/CPlayerGun.hpp b/include/MetroidPrime/Player/CPlayerGun.hpp index 6498a72..aa76915 100644 --- a/include/MetroidPrime/Player/CPlayerGun.hpp +++ b/include/MetroidPrime/Player/CPlayerGun.hpp @@ -1,17 +1,24 @@ #ifndef _CPLAYERGUN #define _CPLAYERGUN -#include "MetroidPrime//TGameTypes.hpp" +#include "MetroidPrime/CEntity.hpp" +#include "Kyoto/Math/CTransform4f.hpp" +#include "Kyoto/Audio/CSfxHandle.hpp" + +#include "MetroidPrime/CActorLights.hpp" + +class CWorldTransManager; class CStateManager; class CPlayer; +class CWorldShadow; enum EChargeState { kCS_Normal, kCS_Charged, }; -class CPlayerGun { +class CPlayerGun : public CEntity { public: enum EChargePhase { kCP_NotCharging, @@ -21,11 +28,20 @@ public: kCP_AnimAndSfx, kCP_Phase_5, }; + enum ESeekerChargeState { + kSCS_NotCharging, + kSCS_State_1, + kSCS_State_2, + kSCS_State_3, + kSCS_FullyCharged, + // Ghidra has State 9 too + }; CPlayerGun(TUniqueId, int); ~CPlayerGun(); CPlayer* GetPlayer(CStateManager& mgr) const; + CPlayer* GetPlayerFromAll(CStateManager& mgr) const; void PlayAnim(CStateManager&, int animType, int loop); @@ -34,17 +50,39 @@ public: void StopChargeSound(CStateManager&, bool); void EnableChargeFx(CStateManager&, bool); + void UpdateChargeState(float dt, CStateManager& mgr); void Charging(CStateManager&, int); private: - char m_pad0[0x3a4]; // 0x000 + CTransform4f m_0x24; + CTransform4f m_0x54; + float m_0x84; + float m_0x88; + float m_0x8c; + CWorldTransManager *m_worldTransManager; + CActorLights m_lights; + TUniqueId m_playerUniqueId; + TUniqueId m_lightId; + CWorldShadow* m_worldShadow; + float m_cooldown; + float m_0x384; + float m_gunHolsterRemTime; + char m_pad0[24]; EChargeState m_chargeState; // 0x3a4 char m_pad1[0x2EC]; // 0x3a8 EChargePhase m_chargePhase; // 0x694 - char m_pad2[0xD8]; // 0x698 - int m_0x770; - char m_pad3[0x9C]; // 0x774 + ESeekerChargeState m_seekerChargeState; // 0x698 + float m_timerRelatedToSeekers; // 0x69c + char m_pad2[0xD0]; // 0x6A0 + int m_0x770; // 0x770 + char m_pad4[0x2b]; // 0x774 + unsigned char m_0x70f; // 0x70f + CSfxHandle m_chargeSfx; // 0x7a0 + CSfxHandle m_sfxForShoot; // 0x7a4 + short m_chargeRumbleHandle; // 0x7a8 + float m_maybeChargeAnim; // 0x7ac + char m_pad3[0x60]; // 0x7B0 uint m_0x810_b0 : 1; uint m_0x810_b1 : 1; uint m_0x810_b2 : 1; diff --git a/include/MetroidPrime/Player/CPlayerState.hpp b/include/MetroidPrime/Player/CPlayerState.hpp index 212d698..9f05c76 100644 --- a/include/MetroidPrime/Player/CPlayerState.hpp +++ b/include/MetroidPrime/Player/CPlayerState.hpp @@ -297,6 +297,7 @@ public: void fn_80084B6C(); void fn_80084928(const UnknownPlayerStateStruct&); float GetChargeBeamFactor() const { return chargeBeamFactor; } + float GetChargeAnimStart() const { return chargeAnimStart; } void IncrementChargeBeamFactor(float); void DecrementAmmoAndDisplayAlertIfOut(const CStateManager&, EItemType, int quantity); diff --git a/src/MetroidPrime/Player/CPlayerGun.cpp b/src/MetroidPrime/Player/CPlayerGun.cpp index ebdd40d..c64a276 100644 --- a/src/MetroidPrime/Player/CPlayerGun.cpp +++ b/src/MetroidPrime/Player/CPlayerGun.cpp @@ -1,8 +1,48 @@ #include "MetroidPrime/Player/CPlayer.hpp" #include "MetroidPrime/Player/CPlayerGun.hpp" #include "MetroidPrime/Player/CPlayerState.hpp" +#include "MetroidPrime/CStateManager.hpp" +#include "MetroidPrime/CRumbleManager.hpp" +#include "Kyoto/Audio/CSfxManager.hpp" static const float kFactorMultiplierForBeamCombo = 1.0f / CPlayerState::GetMissileComboChargeFactor(); +static const float kChargeFactor = 1.0f / CPlayerState::GetMissileComboChargeFactor(); + +void CPlayerGun::UpdateChargeState(float dt, CStateManager& mgr) { + + CPlayerState* playerState = GetPlayerFromAll(mgr)->GetPlayerState(); + + if (m_chargePhase == kCP_AnimAndSfx) { + m_maybeChargeAnim += dt; + if (5.0f <= m_maybeChargeAnim) { + m_maybeChargeAnim = 0.0f; + CRumbleManager* rumbleMgr = mgr.RumbleManager(mgr.MaskUIdNumPlayers(m_playerUniqueId)); + if (m_chargeRumbleHandle == -1) { + rumbleMgr->StopRumble(-1); + m_chargeRumbleHandle = -1; + } + m_chargeRumbleHandle = rumbleMgr->Rumble(mgr, kRFX_PlayerGunCharge, 1.f, kRP_Three); + } + } else { + m_maybeChargeAnim = 0.0f; + } + + if (m_chargePhase == kCP_NotCharging) { + if (0.0f < playerState->GetChargeBeamFactor()) { + playerState->IncrementChargeBeamFactor(-dt); + } + } else { + if (m_chargePhase == kCP_Phase_1 && playerState->GetChargeAnimStart() < playerState->GetChargeBeamFactor()) { + m_chargePhase = kCP_Phase_2; + } + if (m_chargeSfx && m_seekerChargeState != kSCS_FullyCharged) { + CSfxManager::PitchBend(m_chargeSfx, m_0x70f * 0x40 ? 0 : 0x2000); // FIXME: still wrong + } + if (0 < m_chargePhase && m_chargePhase < 4) { + playerState->IncrementChargeBeamFactor(dt * kChargeFactor); + } + } +} void CPlayerGun::Charging(CStateManager& mgr, int param) { switch (param) {