diff --git a/config/GM8E01_00/splits.txt b/config/GM8E01_00/splits.txt index 74d97f9d..07e82c4f 100644 --- a/config/GM8E01_00/splits.txt +++ b/config/GM8E01_00/splits.txt @@ -162,14 +162,14 @@ MetroidPrime/Tweaks/CTweakGame.cpp: .data start:0x803D9CD0 end:0x803D9CE0 MetroidPrime/Weapons/CGameProjectile.cpp: - .text start:0x80037400 end:0x8003A7A4 + .text start:0x80037400 end:0x8003A820 .rodata start:0x803CCE20 end:0x803CCE38 .data start:0x803D9CE0 end:0x803D9D50 .sdata start:0x805A6DB8 end:0x805A6DE0 .sdata2 start:0x805AA120 end:0x805AA168 MetroidPrime/Player/CPlayerGun.cpp: - .text start:0x8003A7A4 end:0x80043DE0 + .text start:0x8003A820 end:0x80043DE0 .ctors start:0x803CB1E0 end:0x803CB1E4 .rodata start:0x803CCE38 end:0x803CCEE0 .data start:0x803D9D50 end:0x803D9E30 diff --git a/config/GM8E01_00/symbols.txt b/config/GM8E01_00/symbols.txt index 53e16766..86f6de1e 100644 --- a/config/GM8E01_00/symbols.txt +++ b/config/GM8E01_00/symbols.txt @@ -760,7 +760,7 @@ __cl__Q24rstl209pair_sorter_finder,Q24rstl17rmemory_allocator>,Q24rstl53vector<16CEffectComponent,Q24rstl17rmemory_allocator>>,Q24rstl189vector,Q24rstl17rmemory_allocator>,Q24rstl53vector<16CEffectComponent,Q24rstl17rmemory_allocator>>,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>,Q24rstl66basic_string,Q24rstl17rmemory_allocator>,Q24rstl265pair_sorter_finder,Q24rstl17rmemory_allocator>,Q24rstl53vector<16CEffectComponent,Q24rstl17rmemory_allocator>>,Q24rstl81less,Q24rstl17rmemory_allocator>>>>__4rstlFQ24rstl405const_pointer_iterator,Q24rstl17rmemory_allocator>,Q24rstl53vector<16CEffectComponent,Q24rstl17rmemory_allocator>>,Q24rstl189vector,Q24rstl17rmemory_allocator>,Q24rstl53vector<16CEffectComponent,Q24rstl17rmemory_allocator>>,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>Q24rstl405const_pointer_iterator,Q24rstl17rmemory_allocator>,Q24rstl53vector<16CEffectComponent,Q24rstl17rmemory_allocator>>,Q24rstl189vector,Q24rstl17rmemory_allocator>,Q24rstl53vector<16CEffectComponent,Q24rstl17rmemory_allocator>>,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>RCQ24rstl66basic_string,Q24rstl17rmemory_allocator>Q24rstl265pair_sorter_finder,Q24rstl17rmemory_allocator>,Q24rstl53vector<16CEffectComponent,Q24rstl17rmemory_allocator>>,Q24rstl81less,Q24rstl17rmemory_allocator>>> = .text:0x800310FC; // type:function size:0xCC fn_800311C8 = .text:0x800311C8; // type:function size:0x20 lower_bound,Q24rstl77vector,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>,Ui,Q24rstl79pair_sorter_finder,Q24rstl8less>>__4rstlFQ24rstl180const_pointer_iterator,Q24rstl77vector,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>Q24rstl180const_pointer_iterator,Q24rstl77vector,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>RCUiQ24rstl79pair_sorter_finder,Q24rstl8less> = .text:0x800311E8; // type:function size:0xC0 scope:global -fn_800312A8 = .text:0x800312A8; // type:function size:0x84 +free_node_and_sub_nodes__Q24rstl130red_black_tree<10CPrimitive,10CPrimitive,0,Q24rstl22identity<10CPrimitive>,Q24rstl18less<10CPrimitive>,Q24rstl17rmemory_allocator>FPQ34rstl130red_black_tree<10CPrimitive,10CPrimitive,0,Q24rstl22identity<10CPrimitive>,Q24rstl18less<10CPrimitive>,Q24rstl17rmemory_allocator>4node = .text:0x800312A8; // type:function size:0x84 __dt__13CAnimTreeNodeFv = .text:0x8003132C; // type:function size:0x80 scope:global fn_800313AC = .text:0x800313AC; // type:function size:0xB0 fn_8003145C = .text:0x8003145C; // type:function size:0x9C @@ -959,7 +959,7 @@ AcceptScriptMsg__10CPlayerGunF20EScriptObjectMessage9TUniqueIdR13CStateManager = CancelFiring__10CPlayerGunFR13CStateManager = .text:0x8003CA58; // type:function size:0xFC scope:global StopChargeSound__10CPlayerGunFR13CStateManager = .text:0x8003CB54; // type:function size:0x74 scope:global TakeDamage__10CPlayerGunFbbR13CStateManager = .text:0x8003CBC8; // type:function size:0x1E0 scope:global -DamageRumble__10CPlayerGunFRC9CVector3fRC13CStateManager = .text:0x8003CDA8; // type:function size:0x20 scope:global +DamageRumble__10CPlayerGunFRC9CVector3ffRC13CStateManager = .text:0x8003CDA8; // type:function size:0x20 scope:global Update__Q210CPlayerGun12CMotionStateFbfR12CTransform4fR13CStateManager = .text:0x8003CDC8; // type:function size:0x440 scope:global UpdateGunIdle__10CPlayerGunFbffR13CStateManager = .text:0x8003D208; // type:function size:0x730 scope:global ResetIdle__10CPlayerGunFR13CStateManager = .text:0x8003D938; // type:function size:0xC4 scope:global @@ -1011,7 +1011,7 @@ __dt__Q24rstl24single_ptr<10CAuxWeapon>Fv = .text:0x80042E04; // type:function s __dt__10CAuxWeaponFv = .text:0x80042E5C; // type:function size:0x11C scope:global __dt__Q24rstl34single_ptr<20CRainSplashGenerator>Fv = .text:0x80042F78; // type:function size:0x58 scope:global __dt__20CRainSplashGeneratorFv = .text:0x80042FD0; // type:function size:0x54 scope:global -fn_80043024 = .text:0x80043024; // type:function size:0xF0 +__dt__Q24rstl72vectorFv = .text:0x80043024; // type:function size:0xF0 __dt__Q24rstl80reserved_vector,2>,2>Fv = .text:0x80043114; // type:function size:0xB4 scope:global __ct__10CPlayerGunF9TUniqueId = .text:0x800431C8; // type:function size:0x984 scope:global __dl__24TOneStatic<10CPlayerGun>FPv = .text:0x80043B4C; // type:function size:0x2C scope:global @@ -2020,7 +2020,7 @@ AddToRenderer__5CBombCFRC14CFrustumPlanesRC13CStateManager = .text:0x80090454; / Touch__5CBombFR6CActorR13CStateManager = .text:0x800905D8; // type:function size:0xC scope:global Explode__5CBombFRC9CVector3fR13CStateManager = .text:0x800905E4; // type:function size:0x10C scope:global __dt__5CBombFv = .text:0x800906F0; // type:function size:0xB4 scope:global -__ct__5CBombFRC25TToken<15CGenDescription>RC25TToken<15CGenDescription>9TUniqueId7TAreaId9TUniqueIdfRC12CTransform4fRC11CDamageInfo = .text:0x800907A4; // type:function size:0x3B0 scope:global +__ct__5CBombF25TToken<15CGenDescription>25TToken<15CGenDescription>9TUniqueId7TAreaId9TUniqueIdfRC12CTransform4fRC11CDamageInfo = .text:0x800907A4; // type:function size:0x3B0 scope:global __ct__10CTweakBallFR12CInputStream = .text:0x80090B54; // type:function size:0x620 scope:global __dt__10CTweakBallFv = .text:0x80091174; // type:function size:0x5C scope:global __dl__24TOneStatic<10CTweakBall>FPv = .text:0x800911D0; // type:function size:0x2C scope:weak @@ -11334,7 +11334,7 @@ CreateMaze__15CSinglePathMazeFi = .text:0x80289F30; // type:function size:0x968 __ct__15CSinglePathMazeFiiii = .text:0x8028A898; // type:function size:0x80 scope:global __ct__9SMazeCellFv = .text:0x8028A918; // type:function size:0xB4 scope:weak get_current_suit__12NWeaponTypesFRC13CStateManager = .text:0x8028A9CC; // type:function size:0x58 scope:global -GetShotDamageInfo__10CGunWeaponCFRC10SShotParamR13CStateManager = .text:0x8028AA24; // type:function size:0xD4 scope:global +GetShotDamageInfo__10CGunWeaponCFRC11CDamageInfoR13CStateManager = .text:0x8028AA24; // type:function size:0xD4 scope:global play_sfx__12NWeaponTypesFUsbbs = .text:0x8028AAF8; // type:function size:0x90 scope:global do_sound_event__12NWeaponTypesFRQ24rstl21pairRibUifUiffUcUcRC9CVector3fRC9CVector3f7TAreaIdR13CStateManager = .text:0x8028AB88; // type:function size:0x334 scope:global primitive_set_to_token_vector__12NWeaponTypesFRC9CAnimDataRCQ24rstl72set<10CPrimitive,Q24rstl18less<10CPrimitive>,Q24rstl17rmemory_allocator>RQ24rstl42vector<6CToken,Q24rstl17rmemory_allocator>b = .text:0x8028AEBC; // type:function size:0x2B8 scope:global @@ -14522,7 +14522,7 @@ BoxFrustumPlanesCheck__14CFrustumPlanesCFRC6CAABox = .text:0x80345098; // type:f BoxInFrustumPlanes__14CFrustumPlanesCFRCQ24rstl24optional_object<6CAABox> = .text:0x80345188; // type:function size:0x48 scope:global BoxInFrustumPlanes__14CFrustumPlanesCFRC6CAABox = .text:0x803451D0; // type:function size:0x84 scope:global __ct__14CFrustumPlanesFRC12CTransform4ffffbf = .text:0x80345254; // type:function size:0x45C scope:global -fn_803456B0__FRC9CVector3fRC9CVector3fRC9CVector3f = .text:0x803456B0; // type:function size:0x9C +CreateNormal__FRC9CVector3fRC9CVector3fRC9CVector3f = .text:0x803456B0; // type:function size:0x9C GetCompressedBlend__13CCubeMaterialCFv = .text:0x8034574C; // type:function size:0x38 scope:global DisableShadowMaps__10CCubeModelFv = .text:0x80345784; // type:function size:0xC scope:global EnableShadowMaps__10CCubeModelFPC8CTextureRC12CTransform4fUcUc = .text:0x80345790; // type:function size:0x58 scope:global @@ -14661,9 +14661,9 @@ fn_8034CAD0 = .text:0x8034CAD0; // type:function size:0x84 fn_8034CB54 = .text:0x8034CB54; // type:function size:0x9C fn_8034CBF0 = .text:0x8034CBF0; // type:function size:0x54 fn_8034CC44 = .text:0x8034CC44; // type:function size:0x88 -insert_into__Q24rstl488red_black_tree,Q24rstl17rmemory_allocator>,Q24rstl117pair,Q24rstl17rmemory_allocator>,Q24rstl26ncrc_ptr<14CAudioGroupSet>>,0,Q24rstl138select1st,Q24rstl17rmemory_allocator>,Q24rstl26ncrc_ptr<14CAudioGroupSet>>>,Q24rstl81less,Q24rstl17rmemory_allocator>>,Q24rstl17rmemory_allocator = .text:0x8034CCCC; // type:function size:0x280 scope:global -insert_into__Q24rstl273red_black_tree,Q24rstl17rmemory_allocator>>,0,Q24rstl104select1st,Q24rstl17rmemory_allocator>>>,Q24rstl8less,Q24rstl17rmemory_allocator>FPQ34rstl273red_black_tree,Q24rstl17rmemory_allocator>>,0,Q24rstl104select1st,Q24 = .text:0x8034CF4C; // type:function size:0x238 scope:global -fn_8034D184 = .text:0x8034D184; // type:function size:0x280 +insert_into__Q24rstl488red_black_tree,Q24rstl17rmemory_allocator>,Q24rstl117pair,Q24rstl17rmemory_allocator>,Q24rstl26ncrc_ptr<14CAudioGroupSet>>,0,Q24rstl138select1st,Q24rstl17rmemory_allocator>,Q24rstl26ncrc_ptr<14CAudioGroupSet>>>,Q24rstl81less,Q24rstl17rmemory_allocator>>,Q24rstl17rmemory_allocator>FPQ34rstl488red_black_tree,Q24rstl17rmemory_allocator>,Q24rstl117pair,Q24rstl17rmemory_allocator>,Q24rstl26ncrc_ptr<14CAudioGroupSet>>,0,Q24rstl138select1st,Q24rstl17rmemory_allocator>,Q24rstl26ncrc_ptr<14CAudioGroupSet>>>,Q24rstl81less,Q24rstl17rmemory_allocator>>,Q24rstl17rmemory_allocator>4nodeRCQ24rstl117pair,Q24rstl17rmemory_allocator>,Q24rstl26ncrc_ptr<14CAudioGroupSet>> = .text:0x8034CCCC; // type:function size:0x280 scope:global +insert_into__Q24rstl273red_black_tree,Q24rstl17rmemory_allocator>>,0,Q24rstl104select1st,Q24rstl17rmemory_allocator>>>,Q24rstl8less,Q24rstl17rmemory_allocator>FPQ34rstl273red_black_tree,Q24rstl17rmemory_allocator>>,0,Q24rstl104select1st,Q24rstl17rmemory_allocator>>>,Q24rstl8less,Q24rstl17rmemory_allocator>4nodeRCQ24rstl84pair,Q24rstl17rmemory_allocator>> = .text:0x8034CF4C; // type:function size:0x238 scope:global +insert_into__Q24rstl498red_black_tree,Q24rstl17rmemory_allocator>,Q24rstl122pair,Q24rstl17rmemory_allocator>,Q24rstl31ncrc_ptr>,0,Q24rstl143select1st,Q24rstl17rmemory_allocator>,Q24rstl31ncrc_ptr>>,Q24rstl81less,Q24rstl17rmemory_allocator>>,Q24rstl17rmemory_allocator>FPQ34rstl498red_black_tree,Q24rstl17rmemory_allocator>,Q24rstl122pair,Q24rstl17rmemory_allocator>,Q24rstl31ncrc_ptr>,0,Q24rstl143select1st,Q24rstl17rmemory_allocator>,Q24rstl31ncrc_ptr>>,Q24rstl81less,Q24rstl17rmemory_allocator>>,Q24rstl17rmemory_allocator>4nodeRCQ24rstl122pair,Q24rstl17rmemory_allocator>,Q24rstl31ncrc_ptr> = .text:0x8034D184; // type:function size:0x280 ReleaseData__Q24rstl29rc_ptrFv = .text:0x8034D404; // type:function size:0x7C __sinit_DolphinCAudioSys_cpp = .text:0x8034D480; // type:function size:0x5C scope:local FreeCardWorkArea__14CMemoryCardSysFQ214CMemoryCardSys15EMemoryCardPort = .text:0x8034D4DC; // type:function size:0x6C scope:global @@ -15124,7 +15124,7 @@ HeaderReadComplete__17CDSPStreamManagerFlP11DVDFileInfo = .text:0x80363788; // t GetStreamState__17CDSPStreamManagerFi = .text:0x8036397C; // type:function size:0xD0 scope:global CanStop__17CDSPStreamManagerFi = .text:0x80363A4C; // type:function size:0xC8 scope:global IsStreamAvailable__17CDSPStreamManagerFi = .text:0x80363B14; // type:function size:0xC0 scope:global -UpdateVolume__17CDSPStreamManagerFii = .text:0x80363BD4; // type:function size:0x98 scope:global +UpdateVolume__17CDSPStreamManagerFic = .text:0x80363BD4; // type:function size:0x98 scope:global __ct__14SDSPStreamInfoFRC17CDSPStreamManager = .text:0x80363C6C; // type:function size:0x124 scope:global StopStreaming__17CDSPStreamManagerFi = .text:0x80363D90; // type:function size:0x138 scope:global FindClaimedStreamIdx__17CDSPStreamManagerFi = .text:0x80363EC8; // type:function size:0x9C scope:global @@ -16773,7 +16773,7 @@ mBeamComboArr = .rodata:0x803CCE64; // type:object size:0x10 scope:global mBeamCtrlCmd = .rodata:0x803CCE74; // type:object size:0x10 scope:global data:4byte lbl_803CCE84 = .rodata:0x803CCE84; // type:object size:0x14 lbl_803CCE98 = .rodata:0x803CCE98; // type:object size:0x18 data:4byte -lbl_803CCEB0 = .rodata:0x803CCEB0; // type:object size:0x30 +@stringBase0 = .rodata:0x803CCEB0; // type:object size:0x29 scope:local data:string_table @stringBase0 = .rodata:0x803CCEE0; // type:object size:0x38 scope:local data:string_table @stringBase0 = .rodata:0x803CCF18; // type:object size:0x7 scope:local data:string_table @stringBase0 = .rodata:0x803CCF20; // type:object size:0x7 scope:local data:string_table @@ -22794,10 +22794,10 @@ lbl_805AA150 = .sdata2:0x805AA150; // type:object size:0x4 align:4 data:float lbl_805AA154 = .sdata2:0x805AA154; // type:object size:0x4 align:4 data:float lbl_805AA158 = .sdata2:0x805AA158; // type:object size:0x4 align:4 data:float lbl_805AA160 = .sdata2:0x805AA160; // type:object size:0x8 align:8 data:double -lbl_805AA168 = .sdata2:0x805AA168; // type:object size:0x4 data:4byte +kGunLocator = .sdata2:0x805AA168; // type:object size:0x4 scope:local data:4byte lbl_805AA16C = .sdata2:0x805AA16C; // type:object size:0x4 align:4 data:float -lbl_805AA170 = .sdata2:0x805AA170; // type:object size:0x8 -lbl_805AA178 = .sdata2:0x805AA178; // type:object size:0x8 +mToMissileSound = .sdata2:0x805AA170; // type:object size:0x8 scope:local +mFromMissileSound = .sdata2:0x805AA178; // type:object size:0x8 scope:local lbl_805AA180 = .sdata2:0x805AA180; // type:object size:0x8 lbl_805AA188 = .sdata2:0x805AA188; // type:object size:0x4 align:4 data:float lbl_805AA18C = .sdata2:0x805AA18C; // type:object size:0x4 align:4 data:float diff --git a/config/GM8E01_01/symbols.txt b/config/GM8E01_01/symbols.txt index 2c2e5f84..2120197d 100644 --- a/config/GM8E01_01/symbols.txt +++ b/config/GM8E01_01/symbols.txt @@ -2020,7 +2020,7 @@ AddToRenderer__5CBombCFRC14CFrustumPlanesRC13CStateManager = .text:0x800904D0; / Touch__5CBombFR6CActorR13CStateManager = .text:0x80090654; // type:function size:0xC scope:global Explode__5CBombFRC9CVector3fR13CStateManager = .text:0x80090660; // type:function size:0x10C scope:global __dt__5CBombFv = .text:0x8009076C; // type:function size:0xB4 scope:global -__ct__5CBombFRC25TToken<15CGenDescription>RC25TToken<15CGenDescription>9TUniqueId7TAreaId9TUniqueIdfRC12CTransform4fRC11CDamageInfo = .text:0x80090820; // type:function size:0x3B0 scope:global +__ct__5CBombF25TToken<15CGenDescription>25TToken<15CGenDescription>9TUniqueId7TAreaId9TUniqueIdfRC12CTransform4fRC11CDamageInfo = .text:0x80090820; // type:function size:0x3B0 scope:global __ct__10CTweakBallFR12CInputStream = .text:0x80090BD0; // type:function size:0x620 scope:global __dt__10CTweakBallFv = .text:0x800911F0; // type:function size:0x5C scope:global __dl__24TOneStatic<10CTweakBall>FPv = .text:0x8009124C; // type:function size:0x2C scope:weak diff --git a/include/MetroidPrime/CDamageInfo.hpp b/include/MetroidPrime/CDamageInfo.hpp index 48bfaffd..3dcce6c1 100644 --- a/include/MetroidPrime/CDamageInfo.hpp +++ b/include/MetroidPrime/CDamageInfo.hpp @@ -6,7 +6,6 @@ #include "MetroidPrime/TGameTypes.hpp" #include "MetroidPrime/Weapons/WeaponTypes.hpp" -struct SShotParam; class CDamageVulnerability; class CDamageInfo { @@ -40,9 +39,6 @@ public: CDamageInfo(CInputStream& in); CDamageInfo(const CDamageInfo&, float); - CDamageInfo(const SShotParam& other); - - CDamageInfo& operator=(const SShotParam& other); const CWeaponMode& GetWeaponMode() const { return x0_weaponMode; } void SetWeaponMode(const CWeaponMode& mode) { x0_weaponMode = mode; } diff --git a/include/MetroidPrime/CModelData.hpp b/include/MetroidPrime/CModelData.hpp index c10e433c..5fba6dd2 100644 --- a/include/MetroidPrime/CModelData.hpp +++ b/include/MetroidPrime/CModelData.hpp @@ -101,6 +101,9 @@ public: bool IsLoaded(int shaderIdx) const; bool IsDefinitelyOpaque(EWhichModel which) const; + CTransform4f GetLocatorTransformDynamic(const rstl::string& name, const CCharAnimTime* time) const; + CTransform4f GetScaledLocatorTransformDynamic(const rstl::string& name, + const CCharAnimTime* time) const; CTransform4f GetLocatorTransform(const rstl::string& name) const; CTransform4f GetScaledLocatorTransform(const rstl::string& name) const; diff --git a/include/MetroidPrime/Enemies/CMetroidBeta.hpp b/include/MetroidPrime/Enemies/CMetroidBeta.hpp index 1b351224..08057035 100644 --- a/include/MetroidPrime/Enemies/CMetroidBeta.hpp +++ b/include/MetroidPrime/Enemies/CMetroidBeta.hpp @@ -6,6 +6,7 @@ class CMetroidBeta : public CPatterned { public: void RenderHitBallEffect() const; + void RenderHitGunEffect() const; }; #endif // _CMETROIDBETA diff --git a/include/MetroidPrime/Enemies/CPatterned.hpp b/include/MetroidPrime/Enemies/CPatterned.hpp index 5fbd4ca7..de9803ff 100644 --- a/include/MetroidPrime/Enemies/CPatterned.hpp +++ b/include/MetroidPrime/Enemies/CPatterned.hpp @@ -337,6 +337,10 @@ public: void UpdateDamageColor(float dt); void UpdateAlphaDelta(float dt, CStateManager& mgr); + // TODO: names? + bool IsMakingBigStrike() const { return x402_28_isMakingBigStrike; } + float GetDamageDuration() const { return x504_damageDur; } + protected: EPatrolState x2d8_patrolState; TUniqueId x2dc_destObj; diff --git a/include/MetroidPrime/Player/CGrappleArm.hpp b/include/MetroidPrime/Player/CGrappleArm.hpp index edc94d70..4b636a44 100644 --- a/include/MetroidPrime/Player/CGrappleArm.hpp +++ b/include/MetroidPrime/Player/CGrappleArm.hpp @@ -6,6 +6,7 @@ #include "Kyoto/Animation/CAnimCharacterSet.hpp" #include "Kyoto/Audio/CSfxHandle.hpp" #include "Kyoto/Math/CTransform4f.hpp" +#include "MetroidPrime/CEntityInfo.hpp" #include "MetroidPrime/CModelData.hpp" #include "MetroidPrime/Player/CPlayerState.hpp" @@ -23,6 +24,8 @@ class CSwooshDescription; class CElementGen; class CParticleSwoosh; class CRainSplashGenerator; +class CModelFlags; +class CActorLights; class CGrappleArm { public: @@ -44,15 +47,25 @@ public: ~CGrappleArm(); void PreRender(CStateManager& mgr, const CFrustumPlanes& frustum, const CVector3f& camPos); + void Update(float swingT, float dt, CStateManager& mgr); void EnterFidget(CStateManager& mgr, int a, int b, int c); + void EnterFreeLook(int gunId, int setId, CStateManager& mgr); void EnterComboFire(int a, CStateManager& mgr); void ReturnToDefault(CStateManager& mgr, float dt, bool setState); void EnterIdle(CStateManager& mgr); void EnterStruck(CStateManager&, float, bool, bool); void DisconnectGrappleBeam(); void RenderGrappleBeam(const CStateManager&, const CVector3f&) const; + void AsyncLoadSuit(CStateManager& mgr); + void TouchModel(const CStateManager&) const; + void Render(const CStateManager&, const CVector3f&, const CModelFlags&, const CActorLights*) const; + void AcceptScriptMsg(EScriptObjectMessage, TUniqueId, CStateManager&); void SetTransform(const CTransform4f& xf) { x220_xf = xf; } + CTransform4f GetTransform() const { return x220_xf; } + CTransform4f& AuxTransform() { return x2e0_auxXf; } + CGunController* GunController() { return x328_gunController.get(); } + const CGunController* GetGunController() const { return x328_gunController.get(); } EArmState GetAnimState() const { return x334_animState; } void SetAnimState(const EArmState state) { x334_animState = state; } diff --git a/include/MetroidPrime/Player/CPlayer.hpp b/include/MetroidPrime/Player/CPlayer.hpp index ecfcaa70..2167b63e 100644 --- a/include/MetroidPrime/Player/CPlayer.hpp +++ b/include/MetroidPrime/Player/CPlayer.hpp @@ -363,6 +363,9 @@ public: TUniqueId GetOrbitTargetId() const { return x310_orbitTargetId; } const CVector3f& GetOrbitPoint() const { return x314_orbitPoint; } TUniqueId GetOrbitNextTargetId() const { return x33c_orbitNextTargetId; } + TUniqueId GetAttachedActor() const { return x26c_attachedActor; } + bool GetControlsFrozen() const { return x760_controlsFrozen; } // name? + float GetDistanceUnderWater() const { return x828_distanceUnderWater; } TUniqueId GetScanningObjectId() const { return x3b4_scanningObject; } EGrappleState GetGrappleState() const { return x3b8_grappleState; } bool IsInFreeLook() const { return x3dc_inFreeLook; } @@ -370,6 +373,7 @@ public: bool GetFreeLookStickState() const { return x3de_lookAnalogHeld; } TUniqueId GetAimTargetId() const { return x3f4_aimTarget; } EPlayerCameraState GetCameraState() const { return x2f4_cameraState; } + TUniqueId GetRidingPlatformId() const { return x82e_ridingPlatform; } void SetCameraState(EPlayerCameraState state, CStateManager& mgr); EGunHolsterState GetGunHolsterState() const { return x498_gunHolsterState; } NPlayer::EPlayerMovementState GetPlayerMovementState() const { return x258_movementState; } @@ -378,6 +382,7 @@ public: const CVector3f& GetAssistedTargetAim() const { return x480_assistedTargetAim; } // CPlayer::GetFlipSpiderBallControlY() const weak // CPlayer::GetFlipSpiderBallControlX() const weak + float GetDeathTime() const { return x9f4_deathTime; } // name? bool IsInsideFluid() const { return x9c4_31_inWaterMovement; } @@ -393,6 +398,7 @@ public: float GetGravity() const; float GetAttachedActorStruggle() const; + const CPlayerEnergyDrain& GetPlayerEnergyDrain() const { return x274_energyDrain; } float GetGunAlpha() const { return x494_gunAlpha; } void SetAttachedActorStruggle(float struggle) { xa28_attachedActorStruggle = struggle; } diff --git a/include/MetroidPrime/Player/CPlayerGun.hpp b/include/MetroidPrime/Player/CPlayerGun.hpp index 1c032604..d180053d 100644 --- a/include/MetroidPrime/Player/CPlayerGun.hpp +++ b/include/MetroidPrime/Player/CPlayerGun.hpp @@ -173,14 +173,46 @@ public: void SetPhazonBeamFeedback(bool); void SetAssistAimTransform(const CTransform4f& xf) { x478_assistAimXf = xf; } + CTransform4f GetTransform() const { return x3e8_xf; } float GetChargeBeamFactor() const { return x834_24_charging ? x340_chargeBeamFactor : 0.f; } + EChargeState GetChargeState() const { return x330_chargeState; } + CPlayerState::EBeamId GetPrimaryWeaponId() const { return x310_currentBeam; } + CPlayerState::EBeamId GetPrimaryDestWeaponId() const { return x314_nextBeam; } + uint GetSecondaryItemId() const { return x318_comboAmmoIdx; } + int GetBombsPending() const { return x308_bombCount; } + uint GetFiring() const { return x2ec_lastFireButtonStates; } + float GetHoloTransitionFactor() const { return x678_morph.GetTransitionFactor(); } + TUniqueId GetPowerBombId() const { return x53a_powerBomb; } static float GetTractorBeamFactor() { return kTractorBeamFactor; } + static const CVector3f& GetGunScale() { return kScaleVector; } int GetStateFlags() const { return x2f8_stateFlags; } void SetStateFlags(int flags) { x2f8_stateFlags = flags; } + bool IsWeaponStateSet(int state) const { return (x2f8_stateFlags & state) == state; } + void EnableWeaponState(int state) { x2f8_stateFlags |= state; } + void DisableWeaponState(int state) { x2f8_stateFlags &= ~state; } + void ResetToBeam() { + if (!IsWeaponStateSet(0x8)) { + EnableWeaponState(0x1); + DisableWeaponState(0x16); + } + x318_comboAmmoIdx = 0; + x31c_missileMode = kMM_Inactive; + } + void ResetToMissile() { + DisableWeaponState(0x1); + EnableWeaponState(0x6); + x318_comboAmmoIdx = 1; + x31c_missileMode = kMM_Active; + } + bool CanCycleShoot() const { + return x32c_chargePhase == kCP_NotCharging && int(x318_comboAmmoIdx) != 1; + } bool IsCharging() const { return x834_24_charging; } void SetTransform(CTransform4f xf) { x3e8_xf = xf; } + CTransform4f GetGunMotionTransform() const { return x4a8_gunWorldXf; } + CGrappleArm& GrappleArm() { return *x740_grappleArm.get(); } CGrappleArm& GetGrappleArm() const { return *x740_grappleArm.get(); } bool IsFidgeting() const { return x833_24_notFidgeting; } @@ -285,10 +317,10 @@ private: uint x2f4_fireButtonStates; // 0x1: beam mode, 0x2: missile mode, 0x4: missile ready, 0x8: morphing, 0x10: combo fire int x2f8_stateFlags; - uint x2fc_fidgetAnimBits; + int x2fc_fidgetAnimBits; uint x300_remainingMissiles; uint x304_; - uint x308_bombCount; + int x308_bombCount; uint x30c_rapidFireShots; CPlayerState::EBeamId x310_currentBeam; CPlayerState::EBeamId x314_nextBeam; @@ -296,7 +328,7 @@ private: EMissileMode x31c_missileMode; CPlayerState::EBeamId x320_currentAuxBeam; EIdleState x324_idleState; - float x328_animSfxPitch; + int x328_animSfxPitch; EChargePhase x32c_chargePhase; EChargeState x330_chargeState; uint x334_; diff --git a/include/MetroidPrime/ScriptObjects/CScriptPlatform.hpp b/include/MetroidPrime/ScriptObjects/CScriptPlatform.hpp index 8228fc80..d7e508ce 100644 --- a/include/MetroidPrime/ScriptObjects/CScriptPlatform.hpp +++ b/include/MetroidPrime/ScriptObjects/CScriptPlatform.hpp @@ -74,6 +74,7 @@ public: bool IsRider(TUniqueId id) const; bool IsSlave(TUniqueId id) const; void BuildSlaveList(CStateManager& mgr); + void AddSlave(TUniqueId id, CStateManager& mgr); rstl::vector< SRiders >& GetStaticSlaves() { return x328_slavesStatic; } rstl::vector< SRiders >& GetDynamicSlaves() { return x338_slavesDynamic; } diff --git a/include/MetroidPrime/Tweaks/CTweakPlayerGun.hpp b/include/MetroidPrime/Tweaks/CTweakPlayerGun.hpp index 01848dfe..dd9da0b5 100644 --- a/include/MetroidPrime/Tweaks/CTweakPlayerGun.hpp +++ b/include/MetroidPrime/Tweaks/CTweakPlayerGun.hpp @@ -3,67 +3,24 @@ #include "types.h" +#include "MetroidPrime/CDamageInfo.hpp" #include "MetroidPrime/Tweaks/ITweakObject.hpp" #include "Kyoto/Math/CVector3f.hpp" +#include "Kyoto/TOneStatic.hpp" #include "rstl/reserved_vector.hpp" -struct SShotParam { - uint x0_weaponType; - bool x4_24_charged : 1; - bool x4_25_combo : 1; - bool x4_26_instaKill : 1; - float x8_damage; - float xc_radiusDamage; - float x10_radius; - float x14_knockback; - bool x18_24_noImmunity : 1; - - SShotParam() - : x0_weaponType(-1) - , x4_24_charged(false) - , x4_25_combo(false) - , x4_26_instaKill(false) - , x8_damage(0.f) - , xc_radiusDamage(0.f) - , x10_radius(0.f) - , x14_knockback(0.f) - , x18_24_noImmunity(false) {} - - SShotParam(float chargeFactor, const SShotParam& other) { - x14_knockback = chargeFactor * other.x14_knockback; - x0_weaponType = other.x0_weaponType; - x10_radius = chargeFactor * other.x10_radius; - x8_damage = chargeFactor * other.x8_damage; - x18_24_noImmunity = false; - *(reinterpret_cast(this) + 1) = *(reinterpret_cast(&other) + 1); - xc_radiusDamage = chargeFactor * other.xc_radiusDamage; - } - - explicit SShotParam(CInputStream& in); -}; - -struct SComboShotParam : SShotParam { - SComboShotParam() { x4_25_combo = true; } - explicit SComboShotParam(CInputStream& in) : SShotParam(in) { x4_25_combo = true; } -}; - -struct SChargedShotParam : SShotParam { - SChargedShotParam() { x4_24_charged = true; } - explicit SChargedShotParam(CInputStream& in) : SShotParam(in) { x4_24_charged = true; } -}; - struct SWeaponInfo { float x0_coolDown; - SShotParam x4_normal; - SChargedShotParam x20_charged; + CDamageInfo x4_normal; + CDamageInfo x20_charged; SWeaponInfo() : x0_coolDown(0.1f) {} explicit SWeaponInfo(CInputStream& in); }; -class CTweakPlayerGun : public ITweakObject, public TOneStatic { +class CTweakPlayerGun : public ITweakObject, public TOneStatic< CTweakPlayerGun > { public: CTweakPlayerGun(CInputStream& in); ~CTweakPlayerGun() override; @@ -91,6 +48,8 @@ public: const SWeaponInfo& GetBeamInfo(int beam) const; + const CDamageInfo& GetBombInfo() const { return x70_bomb; } + // private: float x4_upLookAngle; float x8_downLookAngle; @@ -113,12 +72,11 @@ public: CVector3f x4c_gunPosition; CVector3f x58_; CVector3f x64_grapplingArmPosition; - SShotParam x70_bomb; - SShotParam x8c_powerBomb; - SShotParam x1d4_missile; + CDamageInfo x70_bomb; + CDamageInfo x8c_powerBomb; + CDamageInfo x1d4_missile; SWeaponInfo xa8_beams[5]; - rstl::reserved_vector< SShotParam, 5 > - x1f0_combos; // Originally rstl::reserved_vector + rstl::reserved_vector< CDamageInfo, 5 > x1f0_combos; rstl::reserved_vector< float, 5 > x280_ricochetData; }; diff --git a/include/MetroidPrime/Weapons/CAuxWeapon.hpp b/include/MetroidPrime/Weapons/CAuxWeapon.hpp index 47b5cf61..79e33142 100644 --- a/include/MetroidPrime/Weapons/CAuxWeapon.hpp +++ b/include/MetroidPrime/Weapons/CAuxWeapon.hpp @@ -3,7 +3,10 @@ #include "types.h" +#include "MetroidPrime/CEntityInfo.hpp" +#include "MetroidPrime/Player/CPlayerState.hpp" #include "MetroidPrime/TGameTypes.hpp" +#include "MetroidPrime/Weapons/WeaponCommon.hpp" class CWeaponDescription; class CGenDescription; @@ -14,6 +17,19 @@ public: CAuxWeapon(TUniqueId playerId); bool IsComboFxActive(const CStateManager& mgr) const; + bool UpdateComboFx(float dt, const CVector3f& scale, const CVector3f& firePos, + const CTransform4f& targetXf, CStateManager& mgr); + TUniqueId HasTarget(const CStateManager& mgr) const; + void SetNewTarget(TUniqueId target, CStateManager& mgr); + void StopComboFx(CStateManager& mgr, bool deactivate); + void Load(int curBeam, CStateManager& mgr); + void Fire(float dt, bool underwater, CPlayerState::EBeamId currentBeam, + CPlayerState::EChargeStage chargeState, const CTransform4f& xf, CStateManager& mgr, + EWeaponType type, TUniqueId homingId); + void RenderMuzzleFx() const; + void AcceptScriptMsg(EScriptObjectMessage, TUniqueId, CStateManager&); + + bool IsLoaded() const { return x80_24_isLoaded; } private: TCachedToken< CWeaponDescription > x0_missile; diff --git a/include/MetroidPrime/Weapons/CBomb.hpp b/include/MetroidPrime/Weapons/CBomb.hpp index 68ae7198..53e51561 100644 --- a/include/MetroidPrime/Weapons/CBomb.hpp +++ b/include/MetroidPrime/Weapons/CBomb.hpp @@ -9,8 +9,8 @@ class CElementGen; class CGenDescription; class CBomb : public CWeapon { public: - CBomb(const TToken< CGenDescription >& particle1, const TToken< CGenDescription >& particle2, - TUniqueId uid, TAreaId aid, TUniqueId playerId, float f1, const CTransform4f& xf, + CBomb(TToken< CGenDescription > particle1, TToken< CGenDescription > particle2, TUniqueId uid, + TAreaId aid, TUniqueId playerId, float f1, const CTransform4f& xf, const CDamageInfo& dInfo); ~CBomb(); diff --git a/include/MetroidPrime/Weapons/CGunWeapon.hpp b/include/MetroidPrime/Weapons/CGunWeapon.hpp index cbf695aa..bfcbb4f0 100644 --- a/include/MetroidPrime/Weapons/CGunWeapon.hpp +++ b/include/MetroidPrime/Weapons/CGunWeapon.hpp @@ -30,7 +30,6 @@ class CTransform4f; class CModelFlags; class CActorLights; class SWeaponInfo; -class SShotParam; enum EFrozenFxType { kFFT_None, @@ -59,6 +58,7 @@ private: }; class CGunWeapon { + friend class CPlayerGun; public: CGunWeapon(CAssetId ancsId, EWeaponType type, TUniqueId playerId, EMaterialTypes playerMaterial, @@ -74,7 +74,7 @@ public: // Virtual Methods virtual void Reset(CStateManager& mgr); - virtual void PlayAnim(const NWeaponTypes::EGunAnimType type, const bool loop); + virtual void PlayAnim(const NWeaponTypes::EGunAnimType type, bool loop); virtual void PreRenderGunFx(const CStateManager& mgr, const CTransform4f& xf); virtual void PostRenderGunFx(const CStateManager& mgr, const CTransform4f& xf); virtual void UpdateGunFx(const bool shotSmoke, const float dt, const CStateManager& mgr, @@ -124,7 +124,7 @@ public: CDamageInfo GetDamageInfo(CStateManager& mgr, CPlayerState::EChargeStage chargeState, float chargeFactor); - CDamageInfo GetShotDamageInfo(const SShotParam& shotParam, CStateManager& mgr) const; + CDamageInfo GetShotDamageInfo(const CDamageInfo& shotParam, CStateManager& mgr) const; static const char* GetMuzzleLocator() { return skMuzzleLocator; } diff --git a/include/MetroidPrime/Weapons/CPhazonBeam.hpp b/include/MetroidPrime/Weapons/CPhazonBeam.hpp index 99068589..df1bd30a 100644 --- a/include/MetroidPrime/Weapons/CPhazonBeam.hpp +++ b/include/MetroidPrime/Weapons/CPhazonBeam.hpp @@ -8,6 +8,8 @@ #include class CPhazonBeam : public CGunWeapon { + friend class CPlayerGun; + public: CPhazonBeam(CAssetId characterId, EWeaponType type, TUniqueId playerId, EMaterialTypes playerMaterial, const CVector3f& scale); @@ -34,7 +36,7 @@ public: void Unload(CStateManager& mgr) override; bool IsLoaded() const override; void CreateBeam(CStateManager& mgr); - void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CStateManager& mgr); + void AcceptScriptMsg(EScriptObjectMessage, TUniqueId, CStateManager&); private: TToken< CModel > mVeins; diff --git a/include/MetroidPrime/Weapons/CWeapon.hpp b/include/MetroidPrime/Weapons/CWeapon.hpp index 21cb53db..f4f085cb 100644 --- a/include/MetroidPrime/Weapons/CWeapon.hpp +++ b/include/MetroidPrime/Weapons/CWeapon.hpp @@ -55,9 +55,12 @@ public: TUniqueId GetOwnerId() const { return xec_ownerId; } EWeaponType GetType() const { return xf0_weaponType; } CMaterialFilter GetFilter() const { return xf8_filter; } + + // TODO: names? CDamageInfo& OrigDamageInfo() { return x110_origDamageInfo; } CDamageInfo& CurrentDamageInfo() { return x12c_curDamageInfo; } const CDamageInfo& GetCurrentDamageInfo() const { return x12c_curDamageInfo; } + float GetDamageDuration() const { return x150_damageDuration; } float GetInterferenceDuration() const { return x154_interferenceDuration; } void SetOwnerId(TUniqueId id) { xec_ownerId = id; } diff --git a/include/MetroidPrime/Weapons/GunController/CGunMotion.hpp b/include/MetroidPrime/Weapons/GunController/CGunMotion.hpp index fe853c9a..5c50c2ae 100644 --- a/include/MetroidPrime/Weapons/GunController/CGunMotion.hpp +++ b/include/MetroidPrime/Weapons/GunController/CGunMotion.hpp @@ -48,6 +48,8 @@ public: CModelData& GetModelData() { return x0_modelData; } const CModelData& GetModelData() const { return x0_modelData; } + CGunController& GunController() { return x4c_gunController; } + const CGunController& GunController() const { return x4c_gunController; } bool IsAnimPlaying() const { return xb8_24_animPlaying; } private: diff --git a/include/MetroidPrime/Weapons/WeaponCommon.hpp b/include/MetroidPrime/Weapons/WeaponCommon.hpp index 0e5f134e..b601c2f1 100644 --- a/include/MetroidPrime/Weapons/WeaponCommon.hpp +++ b/include/MetroidPrime/Weapons/WeaponCommon.hpp @@ -11,6 +11,8 @@ class CSfxHandle; class CAnimData; class CStateManager; class CPrimitive; +class CVector3f; +struct TAreaId; namespace NWeaponTypes { @@ -29,6 +31,10 @@ enum EGunAnimType { }; CSfxHandle play_sfx(const ushort sfx, const bool underwater, const bool looped, const short pan); +void do_sound_event(rstl::pair< u16, CSfxHandle >& sfxHandle, int& pitch, bool doPitchBend, + uint soundId, float weight, uint flags, float falloff, float maxDist, + uchar minVol, uchar maxVol, const CVector3f& posToCam, const CVector3f& pos, + TAreaId aid, CStateManager& mgr); void primitive_set_to_token_vector(const CAnimData& animData, const rstl::set< CPrimitive >& primSet, diff --git a/include/MetroidPrime/Weapons/WeaponTypes.hpp b/include/MetroidPrime/Weapons/WeaponTypes.hpp index 734e6150..d539fa3b 100644 --- a/include/MetroidPrime/Weapons/WeaponTypes.hpp +++ b/include/MetroidPrime/Weapons/WeaponTypes.hpp @@ -23,8 +23,8 @@ enum EWeaponType { class CWeaponMode { public: - explicit CWeaponMode(const EWeaponType type = kWT_None, const bool charged = false, - const bool comboed = false, const bool instaKill = false) + CWeaponMode(const EWeaponType type = kWT_None, const bool charged = false, + const bool comboed = false, const bool instaKill = false) : x0_weaponType(type) , x4_24_charged(charged) , x4_25_comboed(comboed) diff --git a/src/MetroidPrime/CDamageInfo.cpp b/src/MetroidPrime/CDamageInfo.cpp index e7146cfb..956d2caa 100644 --- a/src/MetroidPrime/CDamageInfo.cpp +++ b/src/MetroidPrime/CDamageInfo.cpp @@ -13,24 +13,6 @@ CDamageInfo::CDamageInfo(CInputStream& in) x14_knockback = in.ReadFloat(); } -// CDamageInfo::CDamageInfo(const SShotParam& other) -// : x0_weaponMode(CWeaponMode(EWeaponType(other.x0_weaponType), other.x4_24_charged, -// other.x4_25_combo, other.x4_26_instaKill)) , x8_damage(other.x8_damage) , -// xc_radiusDamage(other.xc_radiusDamage) , x10_radius(other.x10_radius) , -// x14_knockback(other.x14_knockback) , x18_24_noImmunity(other.x18_24_noImmunity) {} - -// CDamageInfo& CDamageInfo::operator=(const SShotParam& other) { -// x0_weaponMode = -// CWeaponMode(EWeaponType(other.x0_weaponType), other.x4_24_charged, other.x4_25_combo, -// other.x4_26_instaKill); -// x8_damage = other.x8_damage; -// xc_radiusDamage = other.xc_radiusDamage; -// x10_radius = other.x10_radius; -// x14_knockback = other.x14_knockback; -// x18_24_noImmunity = other.x18_24_noImmunity; -// return *this; -// } - float CDamageInfo::GetDamage(const CDamageVulnerability& dVuln) const { EVulnerability vuln = dVuln.GetVulnerability(x0_weaponMode, false); if (vuln == kVN_Deflect) @@ -63,4 +45,4 @@ CDamageInfo::CDamageInfo(const CDamageInfo& other, float dt) CDamageInfo CDamageInfo::MakeScaledForTime(const float dt) const { return CDamageInfo(x0_weaponMode, x8_damage * (60.f * dt), x10_radius, x14_knockback, true); -} \ No newline at end of file +} diff --git a/src/MetroidPrime/Player/CGrappleArm.cpp b/src/MetroidPrime/Player/CGrappleArm.cpp index 44ccd4df..adae4f8b 100644 --- a/src/MetroidPrime/Player/CGrappleArm.cpp +++ b/src/MetroidPrime/Player/CGrappleArm.cpp @@ -141,3 +141,20 @@ void CGrappleArm::EnterStruck(CStateManager& mgr, float angle, bool bigStrike, b x328_gunController->EnterStruck(mgr, angle, bigStrike, notInFreeLook); } + +void CGrappleArm::TouchModel(const CStateManager& mgr) const { + if (!x3b2_24_active || x3b2_29_suitLoading) { + return; + } + + x0_grappleArmModel->Touch(mgr, 0); + if (x50_grappleArmSkeletonModel) { + x50_grappleArmSkeletonModel->Touch(mgr, 0); + } + + if (mgr.GetPlayerState()->HasPowerUp(CPlayerState::kIT_GrappleBeam)) { + xa0_grappleGearModel.Touch(mgr, 0); + xec_grapNoz1Model.Touch(mgr, 0); + x138_grapNoz2Model.Touch(mgr, 0); + } +} diff --git a/src/MetroidPrime/Player/CPlayerGun.cpp b/src/MetroidPrime/Player/CPlayerGun.cpp index c3feeca4..2b4c4cbf 100644 --- a/src/MetroidPrime/Player/CPlayerGun.cpp +++ b/src/MetroidPrime/Player/CPlayerGun.cpp @@ -1,18 +1,34 @@ #include "MetroidPrime/Player/CPlayerGun.hpp" +#include "Kyoto/Math/CTransform4f.hpp" +#include "Kyoto/Math/CVector3f.hpp" #include "MetroidPrime/CAnimData.hpp" #include "MetroidPrime/CAnimRes.hpp" +#include "MetroidPrime/CControlMapper.hpp" +#include "MetroidPrime/CFluidPlaneCPU.hpp" +#include "MetroidPrime/CGameLight.hpp" #include "MetroidPrime/CRainSplashGenerator.hpp" +#include "MetroidPrime/CRumbleManager.hpp" #include "MetroidPrime/CStateManager.hpp" #include "MetroidPrime/CWorld.hpp" #include "MetroidPrime/CWorldShadow.hpp" #include "MetroidPrime/Cameras/CCameraManager.hpp" +#include "MetroidPrime/Cameras/CGameCamera.hpp" +#include "MetroidPrime/Enemies/CMetroid.hpp" +#include "MetroidPrime/Enemies/CMetroidBeta.hpp" +#include "MetroidPrime/Enemies/CPatterned.hpp" +#include "MetroidPrime/HUD/CSamusHud.hpp" #include "MetroidPrime/Player/CGrappleArm.hpp" #include "MetroidPrime/Player/CPlayer.hpp" +#include "MetroidPrime/SFX/PhazonGun.h" #include "MetroidPrime/SFX/Weapons.h" +#include "MetroidPrime/TGameTypes.hpp" #include "MetroidPrime/Tweaks/CTweakGunRes.hpp" +#include "MetroidPrime/Tweaks/CTweakPlayer.hpp" #include "MetroidPrime/Tweaks/CTweakPlayerGun.hpp" #include "MetroidPrime/Weapons/CAuxWeapon.hpp" +#include "MetroidPrime/Weapons/CBomb.hpp" +#include "MetroidPrime/Weapons/CEnergyProjectile.hpp" #include "MetroidPrime/Weapons/CIceBeam.hpp" #include "MetroidPrime/Weapons/CPhazonBeam.hpp" #include "MetroidPrime/Weapons/CPlasmaBeam.hpp" @@ -22,7 +38,12 @@ #include "MetroidPrime/Weapons/GunController/CGunMotion.hpp" #include "MetroidPrime/Weapons/WeaponTypes.hpp" +#include "MetroidPrime/ScriptObjects/CScriptPlatform.hpp" +#include "MetroidPrime/ScriptObjects/CScriptWater.hpp" +#include "MetroidPrime/TCastTo.hpp" + #include "Kyoto/Audio/CSfxManager.hpp" +#include "Kyoto/Graphics/CGX.hpp" #include "Kyoto/Graphics/CModelFlags.hpp" #include "Kyoto/Math/CAbsAngle.hpp" #include "Kyoto/Math/CMath.hpp" @@ -30,6 +51,7 @@ #include "Kyoto/Particles/CElementGen.hpp" #include "Kyoto/Particles/CGenDescription.hpp" #include "Kyoto/SObjectTag.hpp" +#include "Kyoto/Text/CStringTable.hpp" #include "Collision/CMaterialFilter.hpp" #include "Collision/CMaterialList.hpp" @@ -37,8 +59,16 @@ #include "MetaRender/CCubeRenderer.hpp" #include "Weapons/IWeaponRenderer.hpp" + +#include "Kyoto/Animation/CPrimitive.hpp" +#include "rstl/set.hpp" + #include "math.h" +#pragma inline_max_size(250) + +static const char* const kGunLocator = "GBSE_SDK"; + static float kVerticalAngleTable[3] = {-30.f, 0.f, 30.f}; static float kHorizontalAngleTable[3] = {30.f, 30.f, 30.f}; static float kVerticalVarianceTable[3] = {30.f, 30.f, 30.f}; @@ -70,19 +100,19 @@ static const CPlayerState::EItemType mBeamComboArr[4] = { CPlayerState::kIT_Flamethrower, }; -// static ControlMapper::ECommands mBeamCtrlCmd[4] = { -// ControlMapper::kC_PowerBeam, -// ControlMapper::kC_IceBeam, -// ControlMapper::kC_WaveBeam, -// ControlMapper::kC_PlasmaBeam, -// }; +static const ControlMapper::ECommands mBeamCtrlCmd[4] = { + ControlMapper::kC_PowerBeam, + ControlMapper::kC_IceBeam, + ControlMapper::kC_WaveBeam, + ControlMapper::kC_PlasmaBeam, +}; -// constexpr std::array skFromMissileSound{ -// SFXwpn_from_missile_power, -// SFXwpn_from_missile_ice, -// SFXwpn_from_missile_wave, -// SFXwpn_from_missile_plasma, -// }; +static const ushort mFromMissileSound[4] = { + SFXsam_b_misswitch_00, + SFXsam_b_misswitch_10, + SFXsam_b_misswitch_20, + SFXsam_b_misswitch_30, +}; // constexpr std::array mFromBeamSound{ // SFXsfx0000, @@ -91,12 +121,12 @@ static const CPlayerState::EItemType mBeamComboArr[4] = { // SFXwpn_from_beam_plasma, // }; -// constexpr std::array skToMissileSound{ -// SFXwpn_to_missile_power, -// SFXwpn_to_missile_ice, -// SFXwpn_to_missile_wave, -// SFXwpn_to_missile_plasma, -// }; +static const ushort mToMissileSound[4] = { + SFXsam_b_misswitch_01, + SFXsam_b_misswitch_11, + SFXsam_b_misswitch_21, + SFXsam_b_misswitch_31, +}; // constexpr std::array mIntoBeamSound{ // SFXsfx0000, @@ -116,27 +146,32 @@ static const float kChargeSpeed = 1.f / CPlayerState::GetMissileComboChargeFacto static const float kChargeStart = 0.025f / CPlayerState::GetMissileComboChargeFactor(); static const float kChargeFxStart = 1.f / CPlayerState::GetMissileComboChargeFactor(); -// constexpr std::array skBeamChargeUpSound{ -// SFXwpn_chargeup_power, -// SFXwpn_chargeup_ice, -// SFXwpn_chargeup_wave, -// SFXwpn_chargeup_plasma, -// }; +static ushort sBeamChargeUpSound[4] = { + SFXsam_a_cbmcharge_lp_00, + SFXsam_a_icecharge_lp_00, + SFXsam_a_wavcharge_lp_00, + SFXsam_a_placharge_lp_00, +}; static const CPlayerState::EItemType skItemArr[2] = { CPlayerState::kIT_Invalid, CPlayerState::kIT_Missiles, }; +static const CPlayerState::EBeamId mCurrentBeamId[5] = { + CPlayerState::kBI_Power, CPlayerState::kBI_Ice, CPlayerState::kBI_Wave, + CPlayerState::kBI_Plasma, CPlayerState::kBI_Power, +}; + static const CModelFlags kThermalFlags[4] = { CModelFlags::Normal(), - CModelFlags::AlphaBlended(CColor(u8(255), u8(255), u8(255), u8(128))), + CModelFlags::AlphaBlended(CColor(u8(0), u8(0), u8(0), u8(128))), CModelFlags::Normal(), CModelFlags::Normal(), }; -static const CModelFlags kHandThermalFlag(CModelFlags::kT_Additive, CColor::White()); -static const CModelFlags kHandHoloFlag(CModelFlags::kT_One, kArmColor); +static const CModelFlags kHandThermalFlag = CModelFlags(CModelFlags::kT_Additive, CColor::White()); +static const CModelFlags kHandHoloFlag = CModelFlags(CModelFlags::kT_One, kArmColor); static ushort mItemEmptySound[2] = { CSfxManager::kInternalInvalidSfxId, @@ -157,8 +192,91 @@ static ushort mFromBeamSound[4] = { SFXsam_b_plaswitch_01, }; +static const float kDepthFar = 1.f; +static const float kDepthWorld = 1.f / 8.f; +static const float kDepthGun = 1.f / 32.f; + +static void DrawClipCube(const CAABox& aabb) { + const CColor color(1.f, 1.f, 1.f, 0.f); + gpRender->SetBlendMode_AlphaBlended(); + CGraphics::SetCullMode(kCM_None); + + gpRender->BeginTriangleStrip(4); + gpRender->PrimColor(color); + gpRender->PrimVertex( + CVector3f(aabb.GetMaxPoint().GetX(), aabb.GetMaxPoint().GetY(), aabb.GetMinPoint().GetZ())); + gpRender->PrimVertex( + CVector3f(aabb.GetMaxPoint().GetX(), aabb.GetMinPoint().GetY(), aabb.GetMinPoint().GetZ())); + gpRender->PrimVertex( + CVector3f(aabb.GetMaxPoint().GetX(), aabb.GetMaxPoint().GetY(), aabb.GetMaxPoint().GetZ())); + gpRender->PrimVertex( + CVector3f(aabb.GetMaxPoint().GetX(), aabb.GetMinPoint().GetY(), aabb.GetMaxPoint().GetZ())); + gpRender->EndPrimitive(); + + gpRender->BeginTriangleStrip(4); + gpRender->PrimColor(color); + gpRender->PrimVertex( + CVector3f(aabb.GetMinPoint().GetX(), aabb.GetMaxPoint().GetY(), aabb.GetMinPoint().GetZ())); + gpRender->PrimVertex( + CVector3f(aabb.GetMaxPoint().GetX(), aabb.GetMaxPoint().GetY(), aabb.GetMinPoint().GetZ())); + gpRender->PrimVertex( + CVector3f(aabb.GetMinPoint().GetX(), aabb.GetMaxPoint().GetY(), aabb.GetMaxPoint().GetZ())); + gpRender->PrimVertex( + CVector3f(aabb.GetMaxPoint().GetX(), aabb.GetMaxPoint().GetY(), aabb.GetMaxPoint().GetZ())); + gpRender->EndPrimitive(); + + gpRender->BeginTriangleStrip(4); + gpRender->PrimColor(color); + gpRender->PrimVertex( + CVector3f(aabb.GetMinPoint().GetX(), aabb.GetMaxPoint().GetY(), aabb.GetMinPoint().GetZ())); + gpRender->PrimVertex( + CVector3f(aabb.GetMinPoint().GetX(), aabb.GetMinPoint().GetY(), aabb.GetMinPoint().GetZ())); + gpRender->PrimVertex( + CVector3f(aabb.GetMaxPoint().GetX(), aabb.GetMaxPoint().GetY(), aabb.GetMinPoint().GetZ())); + gpRender->PrimVertex( + CVector3f(aabb.GetMaxPoint().GetX(), aabb.GetMinPoint().GetY(), aabb.GetMinPoint().GetZ())); + gpRender->EndPrimitive(); + + gpRender->BeginTriangleStrip(4); + gpRender->PrimColor(color); + gpRender->PrimVertex( + CVector3f(aabb.GetMinPoint().GetX(), aabb.GetMaxPoint().GetY(), aabb.GetMaxPoint().GetZ())); + gpRender->PrimVertex( + CVector3f(aabb.GetMaxPoint().GetX(), aabb.GetMaxPoint().GetY(), aabb.GetMaxPoint().GetZ())); + gpRender->PrimVertex( + CVector3f(aabb.GetMinPoint().GetX(), aabb.GetMinPoint().GetY(), aabb.GetMaxPoint().GetZ())); + gpRender->PrimVertex( + CVector3f(aabb.GetMaxPoint().GetX(), aabb.GetMinPoint().GetY(), aabb.GetMaxPoint().GetZ())); + gpRender->EndPrimitive(); + + gpRender->BeginTriangleStrip(4); + gpRender->PrimColor(color); + gpRender->PrimVertex( + CVector3f(aabb.GetMinPoint().GetX(), aabb.GetMinPoint().GetY(), aabb.GetMaxPoint().GetZ())); + gpRender->PrimVertex( + CVector3f(aabb.GetMinPoint().GetX(), aabb.GetMinPoint().GetY(), aabb.GetMinPoint().GetZ())); + gpRender->PrimVertex( + CVector3f(aabb.GetMinPoint().GetX(), aabb.GetMaxPoint().GetY(), aabb.GetMaxPoint().GetZ())); + gpRender->PrimVertex( + CVector3f(aabb.GetMinPoint().GetX(), aabb.GetMaxPoint().GetY(), aabb.GetMinPoint().GetZ())); + gpRender->EndPrimitive(); + + gpRender->BeginTriangleStrip(4); + gpRender->PrimColor(color); + gpRender->PrimVertex( + CVector3f(aabb.GetMaxPoint().GetX(), aabb.GetMinPoint().GetY(), aabb.GetMaxPoint().GetZ())); + gpRender->PrimVertex( + CVector3f(aabb.GetMaxPoint().GetX(), aabb.GetMaxPoint().GetY(), aabb.GetMaxPoint().GetZ())); + gpRender->PrimVertex( + CVector3f(aabb.GetMaxPoint().GetX(), aabb.GetMinPoint().GetY(), aabb.GetMinPoint().GetZ())); + gpRender->PrimVertex( + CVector3f(aabb.GetMaxPoint().GetX(), aabb.GetMaxPoint().GetY(), aabb.GetMinPoint().GetZ())); + gpRender->EndPrimitive(); +} + CPlayerGun::CPlayerGun(TUniqueId playerId) -: x0_lights(8, CVector3f::Zero(), 4, 4, false, false, false, 0.1) +: x0_lights(8, CVector3f::Zero(), 4, 4, CActorLights::kDefaultPositionUpdateThreshold, false, false, + false) , x2ec_lastFireButtonStates(0) , x2f0_pressedFireButtonStates(0) , x2f4_fireButtonStates(0) @@ -171,10 +289,10 @@ CPlayerGun::CPlayerGun(TUniqueId playerId) , x310_currentBeam(CPlayerState::kBI_Power) , x314_nextBeam(CPlayerState::kBI_Power) , x318_comboAmmoIdx(0) -, x31c_missileMode(kMM_Inactive) -, x320_currentAuxBeam(CPlayerState::kBI_Power) +, x31c_missileMode(EMissileMode(x318_comboAmmoIdx)) +, x320_currentAuxBeam(x310_currentBeam) , x324_idleState(kIS_Four) -, x328_animSfxPitch(0.f) +, x328_animSfxPitch(0x2000) , x32c_chargePhase(kCP_NotCharging) , x330_chargeState(kCS_Normal) , x334_(0) @@ -334,7 +452,8 @@ void CPlayerGun::PreRender(CStateManager& mgr, const CFrustumPlanes& frustum, break; } case CPlayerState::kPV_Combat: { - CAABox aabb = x72c_currentBeam->GetBounds(CTransform4f::Translate(camPos) * x4a8_gunWorldXf); + CTransform4f offsetXf = CTransform4f::Translate(camPos) * GetGunMotionTransform(); + CAABox aabb = x72c_currentBeam->GetBounds(offsetXf); if (mgr.GetNextAreaId() != kInvalidAreaId) { x0_lights.SetFindShadowLight(true); x0_lights.SetShadowDynamicRangeThreshold(0.25f); @@ -369,24 +488,602 @@ void CPlayerGun::PreRender(CStateManager& mgr, const CFrustumPlanes& frustum, } } -void CPlayerGun::TouchModel(const CStateManager&) const {} - -CVector3f CPlayerGun::ConvertToScreenSpace(const CVector3f& pos, const CGameCamera&) const { - return pos; +static void CopyScreenTex() { + GXSetTexCopySrc(0x140, 0xe0, 0x140, 0xe0); + GXSetTexCopyDst(0x140, 0xe0, GX_TF_RGBA8, false); + GXCopyTex(CGraphics::mpSpareBuffer, false); + GXPixModeSync(); } -void CPlayerGun::DrawArm(const CStateManager&, const CVector3f&, const CModelFlags&) const {} +static void DrawScreenTex(float z) { + const CTransform4f backupViewMtx(CGraphics::GetViewMatrix()); + const CGraphics::CProjectionState backupProjectionState(CGraphics::GetProjectionState()); + const int vpLeft = CGraphics::mViewport.mLeft; + const int vpTop = CGraphics::mViewport.mTop; + const int vpRight = vpLeft + CGraphics::mViewport.mWidth; + const int vpBottom = vpTop + CGraphics::mViewport.mHeight; + const float bottom = static_cast< float >(vpBottom); + const float top = static_cast< float >(vpTop); + const float right = static_cast< float >(vpRight); + CGraphics::SetOrtho(static_cast< float >(vpLeft), right, bottom, top, -1.f, 1.f); + CGraphics::SetViewPointMatrix(CTransform4f::Identity()); + gpRender->SetModelMatrix(CTransform4f::Identity()); + gpRender->SetBlendMode_AlphaBlended(); + CGraphics::SetDepthWriteMode(true, kE_GEqual, true); -void CPlayerGun::Render(const CStateManager&, const CVector3f&, const CModelFlags&) const {} + CGraphics::LoadDolphinSpareTexture(0x140, 0xe0, GX_TF_RGBA8, NULL, + CGraphics::kSpareBufferTexMapID); -void CPlayerGun::GetLctrWithShake(CTransform4f& xfOut, const CModelData&, const rstl::string&, bool, - bool) {} + const GXVtxDescList vtxDesc[3] = { + {GX_VA_POS, GX_DIRECT}, + {GX_VA_TEX0, GX_DIRECT}, + {GX_VA_NULL, GX_NONE}, + }; + CGX::SetVtxDescv(vtxDesc); + CGX::SetNumChans(0); + CGX::SetNumTexGens(1); + CGX::SetNumTevStages(1); + CGX::SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, CGraphics::kSpareBufferTexMapID, GX_COLOR_NULL); + CGX::SetChanCtrl(CGX::Channel0, false, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE, + GX_AF_NONE); + CGX::Begin(GX_TRIANGLESTRIP, GX_VTXFMT0, 4); + GXPosition3f32(320.f, z, 0.f); + GXTexCoord2f32(0.f, 1.f); + GXPosition3f32(640.f, z, 0.f); + GXTexCoord2f32(1.f, 1.f); + GXPosition3f32(320.f, z, 224.f); + GXTexCoord2f32(0.f, 0.f); + GXPosition3f32(640.f, z, 224.f); + GXTexCoord2f32(1.f, 0.f); + CGX::End(); -void CPlayerGun::PlayAnim(NWeaponTypes::EGunAnimType type, bool) {} + CGraphics::SetDepthWriteMode(true, kE_LEqual, true); + CGraphics::SetViewPointMatrix(backupViewMtx); + CGraphics::SetProjectionState(backupProjectionState); +} -void CPlayerGun::Update(float, float, float, CStateManager&) {} +void CPlayerGun::TouchModel(const CStateManager& mgr) const { + if (mgr.GetPlayer()->GetMorphballTransitionState() != CPlayer::kMS_Morphed) { + x73c_gunMotion->GetModelData().Touch(mgr, 0); -void CPlayerGun::ProcessInput(const CFinalInput&, CStateManager&) {} + switch (x33c_phazonBeamState) { + case kPBS_Entering: + if (x75c_phazonBeam.get()) { + x75c_phazonBeam->Touch(mgr); + } + break; + case kPBS_Exiting: + if (x738_nextBeam != nullptr) { + x738_nextBeam->Touch(mgr); + } + break; + default: + if (!x833_28_phazonBeamActive) { + x72c_currentBeam->Touch(mgr); + } else { + x75c_phazonBeam->Touch(mgr); + } + break; + } + + x72c_currentBeam->TouchHolo(mgr); + x740_grappleArm->TouchModel(mgr); + x6e0_rightHandModel.Touch(mgr, 0); + } + + if (x734_loadingBeam != nullptr) { + x734_loadingBeam->Touch(mgr); + x734_loadingBeam->TouchHolo(mgr); + } +} + +CVector3f CPlayerGun::ConvertToScreenSpace(const CVector3f& pos, const CGameCamera& cam) const { + CVector3f viewPos = cam.GetTransform().TransposeRotate( + CVector3f(pos.GetX() - cam.GetTransform().Get03(), pos.GetY() - cam.GetTransform().Get13(), + pos.GetZ() - cam.GetTransform().Get23())); + CVector3f screenPos(viewPos); + + if (screenPos.IsNonZero()) { + return CGraphics::GetPerspectiveProjectionMatrix().MultiplyOneOverW(screenPos); + } + + return CVector3f(-1.f, -1.f, 1.f); +} + +void CPlayerGun::DrawArm(const CStateManager& mgr, const CVector3f& pos, + const CModelFlags& flags) const { + if (!x740_grappleArm->GetActive()) { + return; + } + if (x740_grappleArm->GetAnimState() == CGrappleArm::kAS_Done) { + return; + } + + const float dot = CVector3f::Dot(x740_grappleArm->GetTransform().GetForward(), + mgr.GetPlayer()->GetTransform().GetForward()); + if (mgr.GetPlayer()->GetGrappleState() != CPlayer::kGS_None || dot > 0.1f) { + x740_grappleArm->Render( + mgr, pos, x740_grappleArm->IsArmMoving() ? flags : CModelFlags::Normal(), &x0_lights); + } +} + +void CPlayerGun::Render(const CStateManager& mgr, const CVector3f& pos, + const CModelFlags& flags) const { + const CGraphics::CProjectionState projState = CGraphics::GetProjectionState(); + const CPlayerState::EPlayerVisor visor = mgr.GetPlayerState()->GetCurrentVisor(); + const bool thermalVisor = visor == CPlayerState::kPV_Thermal; + const CModelFlags* beamFlags = &flags; + CModelFlags beamFlagCopy(flags); + if (thermalVisor) { + beamFlags = &kThermalFlags[x310_currentBeam]; + } else if (x835_26_phazonBeamMorphing) { + beamFlagCopy = CModelFlags(CModelFlags::kT_One, 0, CModelFlags::EFlags(3), + CColor(CColor::Lerp(0xffffffff, 0xff000000, x39c_phazonMorphT))); + beamFlags = &beamFlagCopy; + } + + const CGameCamera& cam = mgr.GetCameraManager()->GetCurrentCamera(mgr); + CGraphics::SetDepthRange(kDepthGun, kDepthWorld); + CTransform4f offsetWorldXf(CTransform4f::Translate(pos) * GetGunMotionTransform()); + CTransform4f elbowOffsetXf(offsetWorldXf * x508_elbowLocalXf); + if (x32c_chargePhase != kCP_NotCharging && !IsWeaponStateSet(0x10)) { + offsetWorldXf.AddTranslation(CVector3f(x34c_shakeX, 0.f, x350_shakeZ)); + } + + CTransform4f oldViewMtx(CGraphics::GetViewMatrix()); + CGraphics::SetViewPointMatrix(offsetWorldXf.GetInverse() * oldViewMtx); + gpRender->SetModelMatrix(CTransform4f::Identity()); + if (x32c_chargePhase >= kCP_FxGrown && x32c_chargePhase < kCP_ComboXfer) { + x800_auxMuzzleGenerators[x320_currentAuxBeam]->Render(); + } + + if (x832_25_chargeEffectVisible && + (x38c_muzzleEffectVisTimer > 0.f || x32c_chargePhase > kCP_AnimAndSfx)) { + x72c_currentBeam->DrawMuzzleFx(mgr); + } + + const CGunMorph::EGunState gunState = x678_morph.GetGunState(); + if (gunState == CGunMorph::kGS_InWipe || gunState == CGunMorph::kGS_OutWipe) { + x774_holoTransitionGen->Render(); + } + + CGraphics::SetViewPointMatrix(oldViewMtx); + if (IsWeaponStateSet(0x10)) { + x744_auxWeapon->RenderMuzzleFx(); + } + x72c_currentBeam->PreRenderGunFx(mgr, offsetWorldXf); + const bool drawSuitArm = !x740_grappleArm->IsGrappling() && + mgr.GetPlayer()->GetGunHolsterState() == CPlayer::kGH_Drawn; + x73c_gunMotion->Draw(mgr, offsetWorldXf); + + switch (gunState) { + case CGunMorph::kGS_OutWipeDone: + if (x0_lights.GetAreaLightIndexForShadowLight() != -1) { + x82c_shadow->EnableModelProjectedShadow(offsetWorldXf, x0_lights.GetShadowLightIndex(), + 2.15f); + } + if (visor == CPlayerState::kPV_XRay) { + CTransform4f handXf(elbowOffsetXf * CTransform4f::Translate(0.f, -0.2f, 0.02f)); + x6e0_rightHandModel.Render(mgr, handXf, &x0_lights, + thermalVisor ? kHandThermalFlag : kHandHoloFlag); + } + DrawArm(mgr, pos, flags); + x72c_currentBeam->Draw(drawSuitArm, mgr, offsetWorldXf, *beamFlags, &x0_lights); + x82c_shadow->DisableModelProjectedShadow(); + break; + case CGunMorph::kGS_InWipeDone: + case CGunMorph::kGS_InWipe: + case CGunMorph::kGS_OutWipe: + if (gunState != CGunMorph::kGS_InWipeDone) { + CTransform4f morphXf(elbowOffsetXf * + CTransform4f::Translate(0.f, x678_morph.GetYLerp(), 0.f)); + CopyScreenTex(); + { + CTransform4f handXf(elbowOffsetXf * CTransform4f::Translate(0.f, -0.2f, 0.02f)); + x6e0_rightHandModel.Render(mgr, handXf, &x0_lights, + thermalVisor ? kHandThermalFlag : kHandHoloFlag); + } + x72c_currentBeam->DrawHologram(mgr, offsetWorldXf, + CModelFlags(CModelFlags::kT_Opaque, 0, CModelFlags::EFlags(3), + CColor(1.f, 1.f, 1.f, 1.f))); + DrawScreenTex(ConvertToScreenSpace(morphXf.GetTranslation(), cam).GetZ()); + if (x0_lights.GetAreaLightIndexForShadowLight() != -1) { + x82c_shadow->EnableModelProjectedShadow(offsetWorldXf, x0_lights.GetShadowLightIndex(), + 2.15f); + } + gpRender->SetModelMatrix(morphXf); + DrawClipCube(x6c8_hologramClipCube); + x72c_currentBeam->Draw(drawSuitArm, mgr, offsetWorldXf, *beamFlags, &x0_lights); + x82c_shadow->DisableModelProjectedShadow(); + } else { + CTransform4f handXf(elbowOffsetXf * CTransform4f::Translate(0.f, -0.2f, 0.02f)); + x6e0_rightHandModel.Render(mgr, handXf, &x0_lights, + thermalVisor ? kHandThermalFlag : kHandHoloFlag); + x72c_currentBeam->DrawHologram(mgr, offsetWorldXf, + CModelFlags(CModelFlags::kT_Opaque, 0, CModelFlags::EFlags(3), + CColor(1.f, 1.f, 1.f, 1.f))); + if (x0_lights.GetAreaLightIndexForShadowLight() != -1) { + x82c_shadow->EnableModelProjectedShadow(offsetWorldXf, x0_lights.GetShadowLightIndex(), + 2.15f); + } + DrawArm(mgr, pos, flags); + x82c_shadow->DisableModelProjectedShadow(); + } + break; + } + + CTransform4f oldViewMtx2(CGraphics::GetViewMatrix()); + CGraphics::SetViewPointMatrix(offsetWorldXf.GetInverse() * oldViewMtx2); + gpRender->SetModelMatrix(CTransform4f::Identity()); + x72c_currentBeam->PostRenderGunFx(mgr, offsetWorldXf); + if (x832_26_comboFiring && x77c_comboXferGen.get()) { + x77c_comboXferGen->Render(); + } + CGraphics::SetViewPointMatrix(oldViewMtx2); + + RenderEnergyDrainEffects(mgr); + + CGraphics::SetDepthRange(kDepthWorld, kDepthFar); + CGraphics::SetProjectionState(projState); +} + +void CPlayerGun::GetLctrWithShake(CTransform4f& xfOut, const CModelData& modelData, + const rstl::string& locatorName, bool shake, bool dynamic) { + xfOut = dynamic ? modelData.GetScaledLocatorTransformDynamic(locatorName, NULL) + : modelData.GetScaledLocatorTransform(locatorName); + + if (x834_24_charging && shake) { + xfOut.AddTranslation(CVector3f(x34c_shakeX, 0.f, x350_shakeZ)); + } +} + +void CPlayerGun::PlayAnim(NWeaponTypes::EGunAnimType type, bool loop) { + if (x338_nextState != kNS_ChangeWeapon) + x72c_currentBeam->PlayAnim(type, loop); + + ushort sfx = CSfxManager::kInternalInvalidSfxId; + switch (type) { + case NWeaponTypes::kGAT_FromMissile: + DisableWeaponState(0x4); + sfx = mFromMissileSound[x310_currentBeam]; + break; + case NWeaponTypes::kGAT_MissileReload: + sfx = SFXsam_a_mislload_00; + break; + case NWeaponTypes::kGAT_FromBeam: + sfx = mFromBeamSound[x310_currentBeam]; + break; + case NWeaponTypes::kGAT_ToMissile: + DisableWeaponState(0x1); + sfx = mToMissileSound[x310_currentBeam]; + break; + default: + break; + } + + if (sfx != CSfxManager::kInternalInvalidSfxId) + NWeaponTypes::play_sfx(sfx, x834_27_underwater, false, 0x4a); +} + +static bool just_thawed(bool frozen, bool playerFrozen) { return frozen && !playerFrozen; } +static bool just_froze(bool frozen, bool playerFrozen) { return !frozen && playerFrozen; } + +void CPlayerGun::Update(float grappleSwingT, float cameraBobT, float dt, CStateManager& mgr) { + CPlayer& player = *mgr.Player(); + CPlayerState& playerState = *mgr.PlayerState(); + const bool isUnmorphed = player.GetMorphballTransitionState() == CPlayer::kMS_Unmorphed; + + bool justFroze = false; + if (isUnmorphed) { + justFroze = just_froze(x834_29_frozen, player.GetFrozenState()); + } + + bool justThawed = false; + if (isUnmorphed) { + justThawed = just_thawed(x834_29_frozen, player.GetFrozenState()); + } + + x834_29_frozen = isUnmorphed && player.GetFrozenState(); + float advDt = dt; + if (x834_29_frozen) { + advDt = 0.f; + } + + const bool inMorph = x678_morph.GetGunState() != CGunMorph::kGS_OutWipeDone; + if (mgr.GetPlayerState()->GetCurrentVisor() == CPlayerState::kPV_XRay || inMorph) { + x6e0_rightHandModel.AdvanceAnimation(advDt, mgr, kInvalidAreaId, true); + } + if (inMorph && x734_loadingBeam != NULL && x734_loadingBeam != x72c_currentBeam) { + x744_auxWeapon->Load(x314_nextBeam, mgr); + x734_loadingBeam->Update(advDt, mgr); + } + if (!x744_auxWeapon->IsLoaded()) { + x744_auxWeapon->Load(x310_currentBeam, mgr); + } + + if (justFroze) { + x72c_currentBeam->EnableSecondaryFx(CGunWeapon::kSFT_None); + x72c_currentBeam->EnableFrozenEffect(kFFT_Frozen); + } else if (justThawed) { + x72c_currentBeam->EnableFrozenEffect(kFFT_Thawed); + } + + if (justFroze || justThawed) { + x2f4_fireButtonStates = 0; + x2ec_lastFireButtonStates = 0; + CancelFiring(mgr); + } + + x72c_currentBeam->Update(advDt, mgr); + x73c_gunMotion->Update(advDt * x370_gunMotionSpeedMult, mgr); + x740_grappleArm->Update(grappleSwingT, advDt, mgr); + + if (x338_nextState != kNS_StatusQuo) { + if (x678_morph.GetGunState() == CGunMorph::kGS_InWipeDone) { + if (x338_nextState == kNS_ChangeWeapon) { + ChangeWeapon(playerState, mgr); + x338_nextState = kNS_StatusQuo; + } + } else if (!x72c_currentBeam->GetSolidModelData().GetAnimationData()->IsAnimTimeRemaining( + 0.001f, rstl::string_l("Whole Body")) || + x832_30_requestReturnToDefault) { + bool statusQuo = true; + switch (x338_nextState) { + case kNS_EnterMissile: + ResetToMissile(); + break; + case kNS_ExitMissile: + ResetToBeam(); + x390_cooldown = x72c_currentBeam->GetWeaponInfo().x0_coolDown; + break; + case kNS_MissileReload: + PlayAnim(NWeaponTypes::kGAT_MissileReload, false); + x338_nextState = kNS_MissileShotDone; + statusQuo = false; + break; + case kNS_MissileShotDone: + EnableWeaponState(0x4); + break; + case kNS_ChangeWeapon: + ChangeWeapon(playerState, mgr); + break; + case kNS_SetupBeam: + x390_cooldown = x72c_currentBeam->GetWeaponInfo().x0_coolDown; + DisableWeaponState(0x8); + ResetToBeam(); + break; + case kNS_EnterPhazonBeam: + if (x75c_phazonBeam->IsLoaded()) { + break; + } + x72c_currentBeam->x218_29_drawHologram = true; + x75c_phazonBeam->Load(mgr, false); + x33c_phazonBeamState = kPBS_Entering; + break; + case kNS_ExitPhazonBeam: + if (x738_nextBeam->IsLoaded()) { + break; + } + x72c_currentBeam->x218_29_drawHologram = true; + x738_nextBeam->Load(mgr, false); + x33c_phazonBeamState = kPBS_Exiting; + break; + default: + break; + } + + if (statusQuo) { + x338_nextState = kNS_StatusQuo; + } + } + } + + if (x37c_rapidFireShotsDecayTimer < 0.2f) { + x37c_rapidFireShotsDecayTimer += advDt; + } else { + x37c_rapidFireShotsDecayTimer = 0.f; + if (x30c_rapidFireShots > 0) { + x30c_rapidFireShots -= 1; + } + } + + if (x32c_chargePhase != kCP_NotCharging && !player.GetFrozenState()) { + x34c_shakeX = chargeShakeTbl[mgr.Random()->Next() % 3] * x340_chargeBeamFactor; + x350_shakeZ = chargeShakeTbl[mgr.Random()->Next() % 3] * x340_chargeBeamFactor; + } + + if (!x72c_currentBeam->IsLoaded()) { + return; + } + + GetLctrWithShake(x4d8_gunLocalXf, x73c_gunMotion->GetModelData(), rstl::string_l(kGunLocator), + true, true); + GetLctrWithShake(x418_beamLocalXf, x72c_currentBeam->GetSolidModelData(), + rstl::string_l(CGunWeapon::skMuzzleLocator), false, true); + GetLctrWithShake(x508_elbowLocalXf, x72c_currentBeam->GetSolidModelData(), + rstl::string_l("elbow"), false, false); + x4a8_gunWorldXf = x3e8_xf * x4d8_gunLocalXf * x550_camBob.GetCameraBobTransformation(); + + if (x740_grappleArm->GetActive() && !x740_grappleArm->IsGrappling()) { + UpdateLeftArmTransform(*x72c_currentBeam->SolidModelData(), mgr); + } + + x6a0_motionState.Update(x2f0_pressedFireButtonStates != 0 && x832_28_readyForShot && + x32c_chargePhase < kCP_AnimAndSfx && !player.IsInFreeLook(), + advDt, x4a8_gunWorldXf, mgr); + + x72c_currentBeam->SolidModelData()->AdvanceParticles(GetGunMotionTransform(), advDt, mgr); + x72c_currentBeam->UpdateGunFx(x380_shotSmokeTimer > 2.f && x378_shotSmokeStartTimer > 0.15f, dt, + mgr, x508_elbowLocalXf); + + CTransform4f beamWorldXf = GetGunMotionTransform() * x418_beamLocalXf; + + if (player.GetMorphballTransitionState() == CPlayer::kMS_Unmorphed && + !mgr.GetCameraManager()->IsInCinematicCamera()) { + TEntityList nearList; + const CAABox aabb = x72c_currentBeam->GetBounds().GetTransformedAABox(GetGunMotionTransform()); + mgr.BuildNearList(nearList, aabb, sAimFilter, &player); + TUniqueId bestId = kInvalidUniqueId; + const CVector3f dir = GetGunMotionTransform().GetForward().AsNormalized(); + const CVector3f pos = GetGunMotionTransform().GetTranslation() + dir * -0.5f; + const CRayCastResult result = + mgr.RayWorldIntersection(bestId, pos, dir, 3.5f, sAimFilter, nearList); + x833_29_pointBlankWorldSurface = result.IsValid(); + if (result.IsValid()) { + x448_elbowWorldXf = GetGunMotionTransform() * x508_elbowLocalXf; + x448_elbowWorldXf.AddTranslation(dir * -0.5f); + beamWorldXf.SetTranslation(result.GetPoint()); + } + } else { + x833_29_pointBlankWorldSurface = false; + } + + CTransform4f beamTargetXf = x833_29_pointBlankWorldSurface ? x448_elbowWorldXf : beamWorldXf; + + const CVector3f camTrans = mgr.GetCameraManager()->GetGlobalCameraTranslation(mgr); + beamWorldXf.AddTranslation(camTrans); + beamTargetXf.AddTranslation(camTrans); + + if (x832_25_chargeEffectVisible) { + const bool emitting = x833_30_canShowAuxMuzzleEffect ? x344_comboXferTimer < 1.f : false; + const CVector3f scale( + (emitting && x832_26_comboFiring) ? (1.f - x344_comboXferTimer) * 2.f : 2.f, + (emitting && x832_26_comboFiring) ? (1.f - x344_comboXferTimer) * 2.f : 2.f, + (emitting && x832_26_comboFiring) ? (1.f - x344_comboXferTimer) * 2.f : 2.f); + x72c_currentBeam->UpdateMuzzleFx(advDt, scale, x418_beamLocalXf.GetTranslation(), emitting); + CElementGen& gen = *x800_auxMuzzleGenerators[x320_currentAuxBeam]; + gen.SetGlobalOrientAndTrans(x418_beamLocalXf); + gen.SetGlobalScale(scale); + gen.SetParticleEmission(emitting); + gen.Update(advDt); + } + + if (x748_rainSplashGenerator.get()) { + x748_rainSplashGenerator->Update(advDt, mgr); + } + + UpdateGunLight(beamWorldXf, mgr); + ProcessGunMorph(advDt, mgr); + if (x835_26_phazonBeamMorphing) { + ProcessPhazonGunMorph(advDt, mgr); + } + + if (x832_26_comboFiring && x77c_comboXferGen.get()) { + x77c_comboXferGen->SetGlobalTranslation(x418_beamLocalXf.GetTranslation()); + x77c_comboXferGen->SetGlobalOrientation(x418_beamLocalXf.GetRotation()); + x77c_comboXferGen->Update(advDt); + x344_comboXferTimer += advDt * 4.f; + } + + if (x35c_bombTime > 0.f) { + x35c_bombTime -= advDt; + if (x35c_bombTime <= 0.f) { + x308_bombCount = 3; + } + } + + if (playerState.ItemEnabled(CPlayerState::kIT_ChargeBeam) && + x32c_chargePhase != kCP_NotCharging) { + UpdateChargeState(advDt, mgr); + } else { + x340_chargeBeamFactor -= advDt; + if (x340_chargeBeamFactor < 0.f) { + x340_chargeBeamFactor = 0.f; + } + } + + UpdateAuxWeapons(advDt, beamTargetXf, mgr); + DoUserAnimEvents(advDt, mgr); + + if (player.GetOrbitState() == CPlayer::kOS_OrbitObject && GetTargetId(mgr) != kInvalidUniqueId) { + if (!x832_29_lockedOn && !x832_26_comboFiring && !IsWeaponStateSet(0x10)) { + x832_29_lockedOn = true; + x6a0_motionState.SetState(CMotionState::kMS_LockOn); + ReturnArmAndGunToDefault(mgr, true); + } + } else { + CancelLockOn(); + } + + UpdateWeaponFire(advDt, playerState, mgr); + UpdateGunIdle(x364_gunStrikeCoolTimer > 0.f, cameraBobT, advDt, mgr); + + if ((x2ec_lastFireButtonStates & 0x1) == 0x1) { + x378_shotSmokeStartTimer = 0.f; + } else if (x378_shotSmokeStartTimer < 2.f) { + x378_shotSmokeStartTimer += advDt; + if (x378_shotSmokeStartTimer > 1.f) { + x30c_rapidFireShots = 0; + x380_shotSmokeTimer = 0.f; + } + } + + if (x38c_muzzleEffectVisTimer > 0.f) { + x38c_muzzleEffectVisTimer -= advDt; + } + + if (x30c_rapidFireShots > 5 && x380_shotSmokeTimer < 2.f) { + x380_shotSmokeTimer += advDt; + } + + if (x384_gunStrikeDelayTimer > 0.f) { + x384_gunStrikeDelayTimer -= advDt; + } + + if (x364_gunStrikeCoolTimer > 0.f) { + x2f4_fireButtonStates = 0; + x364_gunStrikeCoolTimer -= advDt; + } + + if (isUnmorphed && IsWeaponStateSet(0x4)) { + x3a0_missileExitTimer -= advDt; + if (x3a0_missileExitTimer < 0.f) { + x3a0_missileExitTimer = 0.f; + ExitMissile(); + } + } +} + +void CPlayerGun::ProcessInput(const CFinalInput& input, CStateManager& mgr) { + const CPlayer* player = mgr.GetPlayer(); + const CPlayerState* cPlayerState = mgr.GetPlayerState(); + CPlayerState* playerState = const_cast< CPlayerState* >(cPlayerState); + bool damageNotMorphed = false; + if (x834_30_inBigStrike && player->GetMorphballTransitionState() != CPlayer::kMS_Morphed) { + damageNotMorphed = true; + } + + if (x832_24_coolingCharge || damageNotMorphed || IsWeaponStateSet(0x8)) { + return; + } + + if (cPlayerState->HasPowerUp(CPlayerState::kIT_ChargeBeam)) { + if (!cPlayerState->ItemEnabled(CPlayerState::kIT_ChargeBeam)) { + playerState->EnableItem(CPlayerState::kIT_ChargeBeam); + } + } else if (cPlayerState->ItemEnabled(CPlayerState::kIT_ChargeBeam)) { + playerState->DisableItem(CPlayerState::kIT_ChargeBeam); + ResetCharge(mgr, false); + } + + switch (player->GetMorphballTransitionState()) { + case CPlayer::kMS_Morphing: + case CPlayer::kMS_Unmorphing: + x2f4_fireButtonStates = 0; + break; + case CPlayer::kMS_Unmorphed: + if (!IsWeaponStateSet(0x10)) { + HandleWeaponChange(input, mgr); + } + // fallthrough + case CPlayer::kMS_Morphed: + x2f4_fireButtonStates = + ControlMapper::GetDigitalInput(ControlMapper::kC_FireOrBomb, input) ? 1 : 0; + x2f4_fireButtonStates |= + ControlMapper::GetDigitalInput(ControlMapper::kC_MissileOrPowerBomb, input) ? 2 : 0; + break; + } +} void CPlayerGun::ProcessChargeState(int releasedStates, int pressedStates, CStateManager& mgr, float dt) { @@ -454,8 +1151,8 @@ void CPlayerGun::ProcessNormalState(int releasedStates, int pressedStates, CStat } bool CPlayerGun::ExitMissile() { - if ((x2f8_stateFlags & 0x1) != 0x1) { - if ((x2f8_stateFlags & 0x10) != 0x10 && x338_nextState != kNS_ExitMissile) { + if (!IsWeaponStateSet(0x1)) { + if (!IsWeaponStateSet(0x10) && x338_nextState != kNS_ExitMissile) { x338_nextState = kNS_ExitMissile; PlayAnim(NWeaponTypes::kGAT_FromMissile, false); } @@ -464,17 +1161,298 @@ bool CPlayerGun::ExitMissile() { return true; } -void CPlayerGun::UpdateNormalShotCycle(float, CStateManager&) {} +void CPlayerGun::UpdateNormalShotCycle(float dt, CStateManager& mgr) { + if (ExitMissile()) { + if (!mgr.GetCameraManager()->IsInCinematicCamera()) { + bool showChargeFx = false; + if (x833_28_phazonBeamActive) { + showChargeFx = true; + } else if (x310_currentBeam == CPlayerState::kBI_Plasma) { + showChargeFx = true; + } -void CPlayerGun::FireSecondary(float, CStateManager&) {} + bool chargeEffectVisible = false; + if (showChargeFx && x32c_chargePhase == kCP_NotCharging) { + chargeEffectVisible = true; + } + x832_25_chargeEffectVisible = chargeEffectVisible; + x30c_rapidFireShots += 1; -void CPlayerGun::DropBomb(CPlayerGun::EBWeapon, CStateManager&) {} + const uint targetHoming = + x72c_currentBeam->GetVelocityInfo().GetTargetHoming(int(x330_chargeState)); -void CPlayerGun::ActivateCombo(CStateManager&) {} + CTransform4f xf(x833_29_pointBlankWorldSurface ? x448_elbowWorldXf + : GetGunMotionTransform() * x418_beamLocalXf); + if (!x833_29_pointBlankWorldSurface && x364_gunStrikeCoolTimer <= 0.f) { + const CVector3f fwd = xf.GetForward(); + xf = x478_assistAimXf; + xf.SetTranslation(fwd); + } -void CPlayerGun::EnableChargeFx(CPlayerState::EChargeStage, CStateManager&) {} + xf.AddTranslation(mgr.GetCameraManager()->GetGlobalCameraTranslation(mgr)); + x38c_muzzleEffectVisTimer = 0.0625f; -void CPlayerGun::UpdateChargeState(float, CStateManager&) {} + TUniqueId homingTarget = targetHoming ? GetTargetId(mgr) : kInvalidUniqueId; + x72c_currentBeam->Fire(x834_27_underwater, dt, CPlayerState::EChargeStage(x330_chargeState), + xf, mgr, homingTarget, x340_chargeBeamFactor, x340_chargeBeamFactor); + + mgr.InformListeners(GetGunMotionTransform().GetTranslation(), kLNT_PlayerFire); + } + } +} + +void CPlayerGun::FireSecondary(float dt, CStateManager& mgr) { + if (mgr.GetCameraManager()->IsInCinematicCamera()) { + return; + } + + CPlayerState* playerState = mgr.PlayerState(); + if (x835_25_inPhazonBeam || int(x318_comboAmmoIdx) == 0 || + playerState->HasPowerUp(skItemArr[x318_comboAmmoIdx]) != true || !IsWeaponStateSet(0x4)) { + NWeaponTypes::play_sfx(SFXsam_b_malfxn_00, x834_27_underwater, false, 0x4a); + return; + } + + bool fired = false; + if (int(x318_comboAmmoIdx) == 1) { + x300_remainingMissiles = playerState->GetItemAmount(CPlayerState::kIT_Missiles); + if (mgr.GetWeaponIdCount(x538_playerId, kWT_Missile) < 3 && int(x300_remainingMissiles) != 0) { + playerState->DecrPickUp(CPlayerState::kIT_Missiles, + x832_26_comboFiring ? playerState->GetMissileCostForAltAttack() : 1); + fired = true; + } + + if (int(x300_remainingMissiles) > 5) { + x300_remainingMissiles = 5; + } else { + x300_remainingMissiles -= 1; + } + } + + if (fired) { + TUniqueId targetId = GetTargetId(mgr); + if (x832_26_comboFiring && targetId == kInvalidUniqueId && + x310_currentBeam == CPlayerState::kBI_Wave) { + targetId = mgr.GetPlayer()->GetAimTargetId(); + } + + CTransform4f beamXf = x4a8_gunWorldXf * x418_beamLocalXf; + const CTransform4f& shotXf = x833_29_pointBlankWorldSurface ? x448_elbowWorldXf : beamXf; + CTransform4f xf(shotXf); + if (!x833_29_pointBlankWorldSurface && x364_gunStrikeCoolTimer <= 0.f) { + const float z = xf.Get23(); + const float y = xf.Get13(); + const float x = xf.Get03(); + xf = x478_assistAimXf; + xf.SetTranslation(CVector3f(x, y, z)); + } + + xf.AddTranslation(mgr.GetCameraManager()->GetGlobalCameraTranslation(mgr)); + x744_auxWeapon->Fire(dt, x834_27_underwater, CPlayerState::EBeamId(x310_currentBeam), + CPlayerState::EChargeStage(x330_chargeState), xf, mgr, + x72c_currentBeam->GetType(), targetId); + + mgr.InformListeners(GetGunMotionTransform().GetTranslation(), kLNT_PlayerFire); + + x3a0_missileExitTimer = 7.f; + if (x832_26_comboFiring != true) { + PlayAnim(NWeaponTypes::kGAT_MissileShoot, false); + x338_nextState = int(x300_remainingMissiles) > 0 ? kNS_MissileReload : kNS_MissileShotDone; + DisableWeaponState(0x4); + } + } else { + ushort sfx = mItemEmptySound[x318_comboAmmoIdx]; + NWeaponTypes::play_sfx(sfx, x834_27_underwater, false, 0x4a); + } +} + +void CPlayerGun::DropBomb(CPlayerGun::EBWeapon weapon, CStateManager& mgr) { + const float ballHalfExtent = gpTweakPlayer->GetPlayerBallHalfExtent(); + + switch (weapon) { + case kBW_Bomb: { + if (x32c_chargePhase != kCP_NotCharging) { + x32c_chargePhase = kCP_ChargeDone; + break; + } + + if (x308_bombCount <= 0) { + break; + } + + CBomb* bomb = rs_new CBomb(x784_bombEffects[weapon][0], x784_bombEffects[weapon][1], + mgr.AllocateUniqueId(), mgr.GetPlayer()->GetCurrentAreaId(), + x538_playerId, x354_bombFuseTime, + CTransform4f::Translate(mgr.GetPlayer()->GetTranslation() + + CVector3f(0.f, 0.f, ballHalfExtent)), + gpTweakPlayerGun->GetBombInfo()); + mgr.AddObject(*bomb); + + if (x308_bombCount == 3) { + x35c_bombTime = x358_bombDropDelayTime; + } + + --x308_bombCount; + + if (CEntity* ent = mgr.ObjectById(mgr.GetPlayer()->GetRidingPlatformId())) { + if (CScriptPlatform* plat = TCastToPtr< CScriptPlatform >(ent)) { + plat->AddSlave(bomb->GetUniqueId(), mgr); + } + } + break; + } + case kBW_PowerBomb: + mgr.PlayerState()->DecrPickUp(CPlayerState::kIT_PowerBombs, 1); + x53a_powerBomb = DropPowerBomb(mgr); + break; + default: + break; + } +} + +void CPlayerGun::ActivateCombo(CStateManager& mgr) { + if (x832_26_comboFiring == true) { + return; + } + + CPlayerState& playerState = *mgr.PlayerState(); + const int altCost = playerState.GetMissileCostForAltAttack(); + if (playerState.GetItemAmount(skItemArr[x318_comboAmmoIdx]) >= altCost) { + bool canFire = true; + if (x310_currentBeam == CPlayerState::kBI_Plasma) { + canFire = !x834_27_underwater; + } + + if (canFire) { + x832_26_comboFiring = true; + + TCachedToken< CGenDescription >& cachedXferEffect = x72c_currentBeam->x160_xferEffect; + if (cachedXferEffect.TryCache()) { + x77c_comboXferGen = rs_new CElementGen(cachedXferEffect); + x77c_comboXferGen->SetGlobalScale(kScaleVector); + } + + x72c_currentBeam->x218_25_enableCharge = true; + StopChargeSound(mgr); + NWeaponTypes::play_sfx(SFXsam_a_combochg_00, x834_27_underwater, false, 0x4a); + x32c_chargePhase = kCP_ComboXfer; + } + } else { + NWeaponTypes::play_sfx(SFXsam_b_malfxn_00, x834_27_underwater, false, 0x4a); + } +} + +void CPlayerGun::EnableChargeFx(CPlayerState::EChargeStage, CStateManager& mgr) { + x72c_currentBeam->ActivateCharge(true, false); + SetGunLightActive(true, mgr); + x72c_currentBeam->EnableSecondaryFx(CGunWeapon::kSFT_Charge); + StopContinuousBeam(mgr, false); + + switch (x310_currentBeam) { + case CPlayerState::kBI_Power: + case CPlayerState::kBI_Plasma: + x832_25_chargeEffectVisible = true; + break; + default: + break; + } + + EnableWeaponState(0x7); + x318_comboAmmoIdx = 1; + x338_nextState = kNS_StatusQuo; + x833_30_canShowAuxMuzzleEffect = true; + + x800_auxMuzzleGenerators[x320_currentAuxBeam] = + rs_new CElementGen(x7c0_auxMuzzleEffects[x320_currentAuxBeam]); + x800_auxMuzzleGenerators[x320_currentAuxBeam]->SetParticleEmission(true); +} + +void CPlayerGun::UpdateChargeState(float dt, CStateManager& mgr) { + switch (x32c_chargePhase) { + case kCP_ChargeRequested: + x340_chargeBeamFactor = 0.f; + x330_chargeState = kCS_Normal; + x832_27_chargeAnimStarted = false; + x834_24_charging = true; + x32c_chargePhase = kCP_AnimAndSfx; + break; + case kCP_AnimAndSfx: + if (x832_27_chargeAnimStarted == false) { + if (x340_chargeBeamFactor > kChargeStart && x832_25_chargeEffectVisible) { + x832_25_chargeEffectVisible = false; + } + if (x340_chargeBeamFactor > kTractorBeamFactor) { + PlayAnim(NWeaponTypes::kGAT_ChargeUp, false); + if (!x2e0_chargeSfx) { + x2e0_chargeSfx = NWeaponTypes::play_sfx(sBeamChargeUpSound[x310_currentBeam], + x834_27_underwater, true, 0x4a); + } + if (x830_chargeRumbleHandle == -1) { + x830_chargeRumbleHandle = + mgr.GetRumbleManager()->Rumble(mgr, kRFX_PlayerGunCharge, 1.f, kRP_Three); + } + x832_27_chargeAnimStarted = true; + } + } else if (x340_chargeBeamFactor >= kChargeFxStart && !IsWeaponStateSet(0x8)) { + x832_25_chargeEffectVisible = true; + x832_27_chargeAnimStarted = false; + x32c_chargePhase = kCP_FxGrowing; + x330_chargeState = kCS_Charged; + EnableChargeFx(CPlayerState::kCS_Charged, mgr); + PlayAnim(NWeaponTypes::kGAT_ChargeLoop, true); + } + break; + case kCP_FxGrowing: + if (x340_chargeBeamFactor >= 1.f) { + x32c_chargePhase = kCP_FxGrown; + } + break; + case kCP_ComboXfer: + if (x344_comboXferTimer >= 1.f) { + x32c_chargePhase = kCP_ComboXferDone; + x832_25_chargeEffectVisible = false; + } + break; + case kCP_ComboXferDone: + x32c_chargePhase = kCP_ComboFire; + x348_chargeCooldownTimer = 0.f; + break; + case kCP_ComboFire: + x740_grappleArm->EnterComboFire(int(x310_currentBeam), mgr); + x73c_gunMotion->PlayPasAnim(SamusGun::kAS_ComboFire, mgr, 0.f, false); + x72c_currentBeam->PlayPasAnim(SamusGun::kAS_ComboFire, mgr, 0.f); + x833_31_inFreeLook = false; + x32c_chargePhase = kCP_ComboFireDone; + break; + case kCP_ChargeCooldown: + if (!IsWeaponStateSet(0x10)) { + x348_chargeCooldownTimer += dt; + if (x348_chargeCooldownTimer >= 0.3f && x72c_currentBeam->IsChargeAnimOver()) { + x32c_chargePhase = kCP_ChargeDone; + } + } else { + x832_24_coolingCharge = false; + } + break; + case kCP_ChargeDone: + ResetCharge(mgr, false); + Reset(mgr, false); + break; + default: + break; + } + + if (x2e0_chargeSfx) { + CSfxManager::PitchBend(x2e0_chargeSfx, x834_27_underwater ? 0 : 0x2000); + } + + if (x32c_chargePhase > kCP_NotCharging && x32c_chargePhase < kCP_FxGrown) { + x340_chargeBeamFactor += kChargeSpeed * dt; + if (x340_chargeBeamFactor > 1.f) { + x340_chargeBeamFactor = 1.f; + } + } +} void CPlayerGun::Reset(CStateManager& mgr, bool b1) { x72c_currentBeam->Reset(mgr); @@ -483,17 +1461,12 @@ void CPlayerGun::Reset(CStateManager& mgr, bool b1) { x833_26_ = false; x348_chargeCooldownTimer = 0.f; SetGunLightActive(false, mgr); - if ((x2f8_stateFlags & 0x10) != 0x10) { - if (!b1 && (x2f8_stateFlags & 0x2) != 0x2) { - if ((x2f8_stateFlags & 0x8) != 0x8) { - x2f8_stateFlags |= 0x1; - x2f8_stateFlags &= ~0x16; - } - x318_comboAmmoIdx = 0; - x31c_missileMode = kMM_Inactive; + if (!IsWeaponStateSet(0x10)) { + if (!b1 && !IsWeaponStateSet(0x2)) { + ResetToBeam(); } } else { - x2f8_stateFlags &= ~0x7; + DisableWeaponState(0x7); } } @@ -501,20 +1474,15 @@ void CPlayerGun::ResetCharge(CStateManager& mgr, bool resetBeam) { if (x32c_chargePhase != kCP_NotCharging) StopChargeSound(mgr); - if ((x2f8_stateFlags & 0x8) != 0x8 && (x2f8_stateFlags & 0x10) != 0x10) { + if (!IsWeaponStateSet(0x8) && !IsWeaponStateSet(0x10)) { bool doResetBeam = mgr.GetPlayer()->GetMorphballTransitionState() == CPlayer::kMS_Morphed || resetBeam; if (x832_27_chargeAnimStarted || doResetBeam) PlayAnim(NWeaponTypes::kGAT_BasePosition, false); if (doResetBeam) x72c_currentBeam->EnableSecondaryFx(CGunWeapon::kSFT_None); - if ((x2f8_stateFlags & 0x2) != 0x2 || x330_chargeState != kCS_Normal) { - if ((x2f8_stateFlags & 0x8) != 0x8) { - x2f8_stateFlags |= 0x1; - x2f8_stateFlags &= ~0x16; - } - x318_comboAmmoIdx = 0; - x31c_missileMode = kMM_Inactive; + if (!IsWeaponStateSet(0x2) || x330_chargeState != kCS_Normal) { + ResetToBeam(); } } @@ -528,6 +1496,7 @@ void CPlayerGun::ResetCharge(CStateManager& mgr, bool resetBeam) { } #define SFXwpn_morph_out_wipe 1774 +#define SFXwpn_morph_in_wipe_done 1775 void CPlayerGun::ResetBeamParams(CStateManager& mgr, const CPlayerState& playerState, bool playSelectionSfx) { @@ -547,17 +1516,153 @@ void CPlayerGun::ResetBeamParams(CStateManager& mgr, const CPlayerState& playerS x833_30_canShowAuxMuzzleEffect = true; } -void CPlayerGun::ChangeWeapon(const CPlayerState&, CStateManager&) {} +void CPlayerGun::ChangeWeapon(const CPlayerState& playerState, CStateManager& mgr) { + if (x730_outgoingBeam != nullptr && x730_outgoingBeam != x72c_currentBeam) + x730_outgoingBeam->Unload(mgr); -void CPlayerGun::StartPhazonBeamTransition(bool, CStateManager&, CPlayerState&) {} + x734_loadingBeam = x760_selectableBeams[x314_nextBeam]; + if (x734_loadingBeam != nullptr && x734_loadingBeam != x72c_currentBeam) { + x734_loadingBeam->Load(mgr, false); + x744_auxWeapon->Load(x314_nextBeam, mgr); + } -void CPlayerGun::HandleWeaponChange(const CFinalInput&, CStateManager&) {} + x72c_currentBeam->EnableFx(false); + x834_28_requestImmediateRecharge = x32c_chargePhase != kCP_NotCharging; + ResetBeamParams(mgr, playerState, true); + x678_morph.StartWipe(CGunMorph::kD_In); +} -void CPlayerGun::HandleBeamChange(const CFinalInput&, CStateManager&) {} +void CPlayerGun::StartPhazonBeamTransition(bool active, CStateManager& mgr, + CPlayerState& playerState) { + if (x833_28_phazonBeamActive == active) { + return; + } -void CPlayerGun::SetPhazonBeamMorph(bool) {} + x760_selectableBeams[x310_currentBeam]->Unload(mgr); + x760_selectableBeams[x310_currentBeam] = active ? x75c_phazonBeam.get() : x738_nextBeam; + ResetBeamParams(mgr, playerState, false); + x72c_currentBeam = x760_selectableBeams[x310_currentBeam]; + x833_28_phazonBeamActive = active; + SetPhazonBeamFeedback(active); + x72c_currentBeam->x1bc_rainSplashGenerator = x748_rainSplashGenerator.get(); + x72c_currentBeam->EnableFx(true); + x72c_currentBeam->x218_29_drawHologram = false; + PlayAnim(NWeaponTypes::kGAT_ToBeam, false); + if (x833_31_inFreeLook) { + EnterFreeLook(mgr); + } else if (x832_30_requestReturnToDefault) { + ReturnArmAndGunToDefault(mgr, false); + } + x832_30_requestReturnToDefault = false; +} -void CPlayerGun::HandlePhazonBeamChange(CStateManager&) {} +void CPlayerGun::HandleWeaponChange(const CFinalInput& input, CStateManager& mgr) { + x833_25_ = false; + if (ControlMapper::GetPressInput(ControlMapper::kC_Morph, input)) { + StopContinuousBeam(mgr, true); + } + if (!IsWeaponStateSet(0x8)) { + if (!x835_25_inPhazonBeam) { + HandleBeamChange(input, mgr); + } else { + HandlePhazonBeamChange(mgr); + } + } +} + +void CPlayerGun::HandleBeamChange(const CFinalInput& input, CStateManager& mgr) { + const CPlayerState& playerState = *mgr.GetPlayerState(); + float maxInput = 0.f; + int beam = -1; + + for (int i = 0; i < 4; ++i) { + if (playerState.HasPowerUp(mBeamArr[i])) { + const float inputVal = ControlMapper::GetAnalogInput(mBeamCtrlCmd[i], input); + if (inputVal > 0.05f && inputVal > maxInput) { + maxInput = inputVal; + beam = i; + } + } + } + + if (beam > -1) { + x833_25_ = true; + if (x310_currentBeam != beam && playerState.HasPowerUp(mBeamArr[beam])) { + x314_nextBeam = static_cast< CPlayerState::EBeamId >(beam); + + uint stateFlags = 0; + if (IsWeaponStateSet(0x10)) { + stateFlags = 0x10; + } + SetStateFlags(0); + EnableWeaponState(stateFlags | 0x8); + PlayAnim(NWeaponTypes::kGAT_FromBeam, false); + + if (x833_31_inFreeLook || x744_auxWeapon->IsComboFxActive(mgr) || x832_26_comboFiring) { + x832_30_requestReturnToDefault = true; + x740_grappleArm->EnterIdle(mgr); + } + + x72c_currentBeam->EnableSecondaryFx(CGunWeapon::kSFT_None); + x338_nextState = kNS_ChangeWeapon; + x2e4_invalidSfx.Clear(); + } else if (playerState.HasPowerUp(mBeamArr[beam])) { + if (ExitMissile()) { + if (!CSfxManager::IsPlaying(x2e4_invalidSfx)) { + x2e4_invalidSfx = + NWeaponTypes::play_sfx(SFXsam_a_mislemp_00, x834_27_underwater, false, 0x4a); + } + } else { + x2e4_invalidSfx.Clear(); + } + } + } +} + +void CPlayerGun::SetPhazonBeamMorph(bool intoPhazonBeam) { + x39c_phazonMorphT = intoPhazonBeam ? 0.f : 1.f; + const bool into = intoPhazonBeam; + const int morphing = true; + x835_27_intoPhazonBeam = into; + x835_26_phazonBeamMorphing = morphing; +} + +void CPlayerGun::HandlePhazonBeamChange(CStateManager& mgr) { + bool inMorph = false; + switch (x33c_phazonBeamState) { + case kPBS_Inactive: + SetPhazonBeamMorph(true); + x338_nextState = kNS_EnterPhazonBeam; + inMorph = true; + break; + case kPBS_Active: + if (!x835_24_canFirePhazon) { + SetPhazonBeamMorph(true); + x338_nextState = kNS_ExitPhazonBeam; + inMorph = true; + CPhazonBeam* beam = x75c_phazonBeam.get(); + if (beam) { + beam->mClipWipeActive = false; + beam->mVeinsAlphaActive = true; + } + } + break; + default: + break; + } + + if (inMorph) { + ResetBeamParams(mgr, *mgr.GetPlayerState(), true); + SetStateFlags(0); + EnableWeaponState(0x8); + PlayAnim(NWeaponTypes::kGAT_FromBeam, false); + if (x833_31_inFreeLook) { + x832_30_requestReturnToDefault = true; + x740_grappleArm->EnterIdle(mgr); + } + CancelCharge(mgr, false); + } +} void CPlayerGun::InitBeamData() { x760_selectableBeams[0] = x74c_powerBeam.get(); @@ -584,12 +1689,26 @@ void CPlayerGun::InitBombData() { } void CPlayerGun::InitMuzzleData() { - for (int i = 0; i < 5; ++i) { - SObjectTag tag('PART', (i < 0 || 4 < i) ? kInvalidAssetId : gpTweakGunRes->xa4_auxMuzzle[i]); - x7c0_auxMuzzleEffects.push_back(gpSimplePool->GetObj(tag)); - // TODO: not likely correct, maybe need improvements to auto_ptr - x800_auxMuzzleGenerators.push_back(rs_new CElementGen(x7c0_auxMuzzleEffects.back())); - x800_auxMuzzleGenerators.back()->SetParticleEmission(false); + CPlayerGun* gun = this; + TLockedToken< CGenDescription >* muzzleEffects = gun->x7c0_auxMuzzleEffects.data(); + rstl::auto_ptr< CElementGen >* muzzleGenerators = gun->x800_auxMuzzleGenerators.data(); + TLockedToken< CGenDescription >* muzzleEffect = muzzleEffects; + int i = 0; + int j = 0; + + for (; i < 5; ++i, j += 4) { + CAssetId muzzleId = kInvalidAssetId; + if (i >= 0 && i <= 4) { + muzzleId = gpTweakGunRes->xa4_auxMuzzle[i]; + } + + SObjectTag tag('PART', muzzleId); + gun->x7c0_auxMuzzleEffects.push_back(gpSimplePool->GetObj(tag)); + + CElementGen* gen = rs_new CElementGen(*muzzleEffect); + gen->SetParticleEmission(false); + gun->x800_auxMuzzleGenerators.push_back(gen); + ++muzzleEffect; } } @@ -607,9 +1726,10 @@ TUniqueId CPlayerGun::GetTargetId(CStateManager& mgr) { ret = mgr.GetPlayer()->GetOrbitNextTargetId(); if (ret != kInvalidUniqueId) { - const CActor* act = TCastToConstPtr< CActor >(mgr.GetObjectById(ret)); + CActor* act = TCastToPtr< CActor >(const_cast< CEntity* >(mgr.GetObjectById(ret))); if (act != nullptr) { - if (!act->GetMaterialList().HasMaterial(kMT_Target)) { + const uchar hasTarget = act->GetMaterialList().HasMaterial(kMT_Target) ? 1 : 0; + if (hasTarget != 1) { ret = kInvalidUniqueId; } } @@ -620,7 +1740,7 @@ TUniqueId CPlayerGun::GetTargetId(CStateManager& mgr) { CPlayerGun::CGunMorph::CGunMorph(float gunTransformTime, float holoHoldTime) : x0_yLerp(0.f) -, x4_gunTransformTime(CMath::Sign(gunTransformTime)) +, x4_gunTransformTime(CMath::FastFSel(-gunTransformTime, 1.f, gunTransformTime)) , x8_remTime(0.f) , xc_speed(0.1f) , x10_holoHoldTime(fabs(holoHoldTime)) @@ -670,10 +1790,10 @@ CPlayerGun::CGunMorph::EMorphEvent CPlayerGun::CGunMorph::Update(float inY, floa float omt = x8_remTime * xc_speed; float t = 1.f - omt; if (x1c_dir == kD_In) { - x0_yLerp = omt * outY + t * inY; + x0_yLerp = inY * t + outY * omt; x18_transitionFactor = omt; } else { - x0_yLerp = omt * inY + t * outY; + x0_yLerp = outY * t + inY * omt; x18_transitionFactor = t; } @@ -700,25 +1820,29 @@ CPlayerGun::CGunMorph::EMorphEvent CPlayerGun::CGunMorph::Update(float inY, floa void CPlayerGun::UpdateWeaponFire(float dt, CPlayerState& playerState, CStateManager& mgr) { uint oldFiring = x2ec_lastFireButtonStates; - x2ec_lastFireButtonStates = x2f4_fireButtonStates; - uint pressedStates = x2f4_fireButtonStates & (oldFiring ^ x2f4_fireButtonStates); + uint fireButtonStates = x2f4_fireButtonStates; + x2ec_lastFireButtonStates = fireButtonStates; + uint pressedStates = fireButtonStates & (oldFiring ^ fireButtonStates); x2f0_pressedFireButtonStates = pressedStates; - uint releasedStates = oldFiring & (oldFiring ^ x2f4_fireButtonStates); + uint releasedStates = oldFiring & (oldFiring ^ fireButtonStates); + CPlayer& player = *mgr.Player(); + int morphState = player.GetMorphballTransitionState(); + bool chargeRequested = x32c_chargePhase != kCP_NotCharging; + x832_28_readyForShot = false; - CPlayer& player = *mgr.Player(); if (!x832_24_coolingCharge && !x834_30_inBigStrike) { float coolDown = x72c_currentBeam->GetWeaponInfo().x0_coolDown; if ((pressedStates & 0x1) == 0) { if (x390_cooldown >= coolDown) { x390_cooldown = coolDown; - if (player.GetMorphballTransitionState() == CPlayer::kMS_Unmorphed && + if (morphState == CPlayer::kMS_Unmorphed && playerState.ItemEnabled(CPlayerState::kIT_ChargeBeam) && player.GetGunHolsterState() == CPlayer::kGH_Drawn && player.GetGrappleState() == CPlayer::kGS_None && - playerState.GetTransitioningVisor() != CPlayerState::kPV_Scan && - playerState.GetCurrentVisor() != CPlayerState::kPV_Scan && - (x2ec_lastFireButtonStates & 0x1) != 0 && x32c_chargePhase == kCP_NotCharging) { + mgr.GetPlayerState()->GetTransitioningVisor() != CPlayerState::kPV_Scan && + mgr.GetPlayerState()->GetCurrentVisor() != CPlayerState::kPV_Scan && + (x2ec_lastFireButtonStates & 0x1) != 0 && !chargeRequested) { x832_28_readyForShot = true; pressedStates |= 0x1; x390_cooldown = 0.f; @@ -734,7 +1858,7 @@ void CPlayerGun::UpdateWeaponFire(float dt, CPlayerState& playerState, CStateMan if (x834_28_requestImmediateRecharge) x834_28_requestImmediateRecharge = (x2ec_lastFireButtonStates & 0x1) != 0; - if (player.GetMorphballTransitionState() == CPlayer::kMS_Morphed) { + if (morphState == CPlayer::kMS_Morphed) { x835_28_bombReady = false; x835_29_powerBombReady = false; if (!x835_31_actorAttached) { @@ -742,39 +1866,47 @@ void CPlayerGun::UpdateWeaponFire(float dt, CPlayerState& playerState, CStateMan if (x53a_powerBomb != kInvalidUniqueId && !mgr.CanCreateProjectile(x538_playerId, kWT_PowerBomb, 1)) { const CPowerBomb* pb = static_cast< const CPowerBomb* >(mgr.GetObjectById(x53a_powerBomb)); - if (pb && !pb->IsEnding()) { + if (pb != NULL && pb->GetCurTime() <= CPowerBomb::kEndingTime) { x835_28_bombReady = false; } else { x53a_powerBomb = kInvalidUniqueId; } } - if (((pressedStates & 0x1) != 0 || x32c_chargePhase != kCP_NotCharging) && + if (((pressedStates & 0x1) != 0 || chargeRequested) && playerState.HasPowerUp(CPlayerState::kIT_MorphBallBombs)) { if (x835_28_bombReady) DropBomb(kBW_Bomb, mgr); - } else if (playerState.HasPowerUp(CPlayerState::kIT_PowerBombs) && - playerState.GetItemAmount(CPlayerState::kIT_PowerBombs) > 0) { - x835_29_powerBombReady = mgr.CanCreateProjectile(x538_playerId, kWT_PowerBomb, 1) && - mgr.CanCreateProjectile(x538_playerId, kWT_Bomb, 1); + } else { + bool hasPowerBombs = false; + bool canCreatePowerBomb = false; + bool powerBombReady = false; + if (playerState.HasPowerUp(CPlayerState::kIT_PowerBombs)) { + if (playerState.GetItemAmount(CPlayerState::kIT_PowerBombs) > 0) { + hasPowerBombs = true; + } + } + if (hasPowerBombs) { + canCreatePowerBomb = mgr.CanCreateProjectile(x538_playerId, kWT_PowerBomb, 1); + } + if (canCreatePowerBomb) { + powerBombReady = mgr.CanCreateProjectile(x538_playerId, kWT_Bomb, 1); + } + x835_29_powerBombReady = powerBombReady; if ((pressedStates & 0x2) != 0 && x835_29_powerBombReady) DropBomb(kBW_PowerBomb, mgr); } } - } else if ((x2f8_stateFlags & 0x8) != 0x8 && - player.GetMorphballTransitionState() == CPlayer::kMS_Unmorphed) { - if ((pressedStates & 0x2) != 0 && x318_comboAmmoIdx == 0 && (x2f8_stateFlags & 0x2) != 0x2 && + } else if (!IsWeaponStateSet(0x8) && morphState == CPlayer::kMS_Unmorphed) { + if ((pressedStates & 0x2) != 0 && x318_comboAmmoIdx == 0 && !IsWeaponStateSet(0x2) && x32c_chargePhase == kCP_NotCharging) { - uint missileCount = playerState.GetItemAmount(CPlayerState::kIT_Missiles); + int missileCount = playerState.GetItemAmount(CPlayerState::kIT_Missiles); if (x338_nextState != kNS_EnterMissile && x338_nextState != kNS_ExitMissile) { if (playerState.HasPowerUp(CPlayerState::kIT_Missiles) && missileCount > 0) { x300_remainingMissiles = missileCount; - if (x300_remainingMissiles > 5) + if (static_cast< int >(x300_remainingMissiles) > 5) x300_remainingMissiles = 5; if (!x835_25_inPhazonBeam) { - x2f8_stateFlags &= ~0x1; - x2f8_stateFlags |= 0x6; - x318_comboAmmoIdx = 1; - x31c_missileMode = kMM_Active; + ResetToMissile(); } FireSecondary(dt, mgr); } else { @@ -788,13 +1920,16 @@ void CPlayerGun::UpdateWeaponFire(float dt, CPlayerState& playerState, CStateMan } } else { if (x3a4_fidget.GetState() == CFidget::kS_NoFidget) { - if ((x2f8_stateFlags & 0x10) == 0x10 && x744_auxWeapon->IsComboFxActive(mgr)) { - if (x2ec_lastFireButtonStates == 0 || - (x310_currentBeam == CPlayerState::kBI_Wave && x833_29_pointBlankWorldSurface)) { - StopContinuousBeam(mgr, (x2f8_stateFlags & 0x8) == 0x8); + if (IsWeaponStateSet(0x10) && x744_auxWeapon->IsComboFxActive(mgr)) { + bool stopCombo = false; + if (x310_currentBeam == CPlayerState::kBI_Wave && x833_29_pointBlankWorldSurface) { + stopCombo = true; + } + if (x2ec_lastFireButtonStates == 0 || stopCombo) { + StopContinuousBeam(mgr, IsWeaponStateSet(0x8)); } } else { - if (mgr.GetPlayerState()->ItemEnabled(CPlayerState::kIT_ChargeBeam) && + if (playerState.ItemEnabled(CPlayerState::kIT_ChargeBeam) && x33c_phazonBeamState == kPBS_Inactive) ProcessChargeState(releasedStates, pressedStates, mgr, dt); else @@ -825,10 +1960,11 @@ void CPlayerGun::ResetIdle(CStateManager& mgr) { void CPlayerGun::UpdateGunIdle(bool inStrikeCooldown, float camBobT, float dt, CStateManager& mgr) { CPlayer& player = *mgr.Player(); + if (player.IsInFreeLook() && !x832_29_lockedOn && !x740_grappleArm->IsGrappling() && x3a4_fidget.GetState() != CFidget::kS_HolsterBeam && player.GetGunHolsterState() == CPlayer::kGH_Drawn && !x834_30_inBigStrike) { - if ((x2f8_stateFlags & 0x8) != 0x8) { + if (!IsWeaponStateSet(0x8)) { if (!x833_31_inFreeLook && !x834_26_animPlaying) { if (x388_enterFreeLookDelayTimer < 0.25f) x388_enterFreeLookDelayTimer += dt; @@ -844,7 +1980,7 @@ void CPlayerGun::UpdateGunIdle(bool inStrikeCooldown, float camBobT, float dt, C } } else { if (x833_31_inFreeLook) { - if ((x2f8_stateFlags & 0x10) != 0x10) { + if (!IsWeaponStateSet(0x10)) { x73c_gunMotion->ReturnToDefault(mgr, x834_30_inBigStrike); x740_grappleArm->ReturnToDefault(mgr, 0.f, false); } @@ -856,7 +1992,7 @@ void CPlayerGun::UpdateGunIdle(bool inStrikeCooldown, float camBobT, float dt, C !(player.GetSurfaceRestraint() != CPlayer::kSR_Water && mgr.GetPlayerState()->GetCurrentVisor() != CPlayerState::kPV_Scan && (x2f4_fireButtonStates & 0x3) == 0 && x32c_chargePhase == kCP_NotCharging && - !x832_29_lockedOn && (x2f8_stateFlags & 0x8) != 0x8 && x364_gunStrikeCoolTimer <= 0.f && + !x832_29_lockedOn && !IsWeaponStateSet(0x8) && x364_gunStrikeCoolTimer <= 0.f && player.GetPlayerMovementState() == NPlayer::kMS_OnGround && !player.IsInFreeLook() && !player.GetFreeLookStickState() && player.GetOrbitState() == CPlayer::kOS_NoOrbit && fabs(player.GetAngularVelocityOR().GetAngle()) <= 0.1f && camBobT <= 0.01f && @@ -866,7 +2002,10 @@ void CPlayerGun::UpdateGunIdle(bool inStrikeCooldown, float camBobT, float dt, C !x835_25_inPhazonBeam); if (x833_24_notFidgeting) { if (!x834_30_inBigStrike) { - bool doWander = camBobT > 0.01f && (x2f4_fireButtonStates & 0x3) == 0; + bool doWander = false; + if (camBobT > 0.01f && (x2f4_fireButtonStates & 0x3) == 0) { + doWander = true; + } if (doWander) { x370_gunMotionSpeedMult = 1.f; x374_ = 0.f; @@ -877,7 +2016,7 @@ void CPlayerGun::UpdateGunIdle(bool inStrikeCooldown, float camBobT, float dt, C x550_camBob.SetState(CPlayerCameraBob::kCBS_Walk, mgr); } x368_idleWanderDelayTimer -= dt; - x360_ -= dt; + x360_ += dt; } if (!doWander || x834_26_animPlaying) ResetIdle(mgr); @@ -916,19 +2055,24 @@ void CPlayerGun::UpdateGunIdle(bool inStrikeCooldown, float camBobT, float dt, C EnterFidget(mgr); break; case CFidget::kS_StillMinorFidget: - case CFidget::kS_StillMajorFidget: + case CFidget::kS_StillMajorFidget: { x550_camBob.SetState(CPlayerCameraBob::kCBS_Walk, mgr); x833_24_notFidgeting = false; - x834_26_animPlaying = - x834_25_gunMotionFidgeting - ? x73c_gunMotion->IsAnimPlaying() - : x72c_currentBeam->GetSolidModelData().GetAnimationData()->IsAnimTimeRemaining( - 0.001f, rstl::string_l("Whole Body")); + bool animPlaying; + if (x834_25_gunMotionFidgeting) { + animPlaying = x73c_gunMotion->IsAnimPlaying(); + } else { + animPlaying = + x72c_currentBeam->GetSolidModelData().GetAnimationData()->IsAnimTimeRemaining( + 0.001f, rstl::string_l("Whole Body")); + } + x834_26_animPlaying = animPlaying; if (!x834_26_animPlaying) { x3a4_fidget.ResetMinor(); ReturnToRestPose(); } break; + } default: break; } @@ -1014,14 +2158,17 @@ void CPlayerGun::CMotionState::Update(bool firing, float dt, CTransform4f& xf, C } } -void CPlayerGun::DamageRumble(const CVector3f&, float damage, const CStateManager&) {} +void CPlayerGun::DamageRumble(const CVector3f& location, float damage, const CStateManager&) { + x398_damageAmt = damage; + x3dc_damageLocation = location; +} void CPlayerGun::TakeDamage(bool bigStrike, bool notFromMetroid, CStateManager& mgr) { const CPlayer& player = *mgr.GetPlayer(); bool hasStrikeAngle = false; float angle = 0.f; - if (x398_damageAmt >= 10.f && !bigStrike && (x2f8_stateFlags & 0x10) != 0x10 && - !x832_26_comboFiring && x384_gunStrikeDelayTimer <= 0.f) { + if (x398_damageAmt >= 10.f && !bigStrike && !IsWeaponStateSet(0x10) && !x832_26_comboFiring && + x384_gunStrikeDelayTimer <= 0.f) { x384_gunStrikeDelayTimer = 20.f; x364_gunStrikeCoolTimer = 0.75f; if (x678_morph.GetGunState() == CGunMorph::kGS_OutWipeDone) { @@ -1044,60 +2191,749 @@ void CPlayerGun::TakeDamage(bool bigStrike, bool notFromMetroid, CStateManager& x3dc_damageLocation = CVector3f::Zero(); } -void CPlayerGun::StopChargeSound(CStateManager&) {} +void CPlayerGun::StopChargeSound(CStateManager& mgr) { + if (x2e0_chargeSfx) { + CSfxManager::SfxStop(x2e0_chargeSfx); + x2e0_chargeSfx.Clear(); + } + if (x830_chargeRumbleHandle != -1) { + mgr.GetRumbleManager()->StopRumble(x830_chargeRumbleHandle); + x830_chargeRumbleHandle = -1; + } +} -void CPlayerGun::CancelFiring(CStateManager&) {} +void CPlayerGun::CancelFiring(CStateManager& mgr) { + if (x32c_chargePhase == kCP_ComboFireDone) + ReturnArmAndGunToDefault(mgr, true); -void CPlayerGun::AcceptScriptMsg(EScriptObjectMessage, TUniqueId, CStateManager&) {} + if (IsWeaponStateSet(0x10)) { + StopContinuousBeam(mgr, true); + ResetToBeam(); + } -void CPlayerGun::StopContinuousBeam(CStateManager&, bool) {} + if (x32c_chargePhase != kCP_NotCharging) { + x72c_currentBeam->ActivateCharge(false, false); + SetGunLightActive(false, mgr); + ResetCharge(mgr, true); + } -void CPlayerGun::RenderEnergyDrainEffects(const CStateManager&) const {} + Reset(mgr, IsWeaponStateSet(0x2)); +} -void CPlayerGun::DoUserAnimEvents(float, CStateManager&) {} +void CPlayerGun::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CStateManager& mgr) { + CPlayer* player = mgr.Player(); + CPlayerState* playerState = mgr.PlayerState(); + const bool isUnmorphed = player->GetMorphballTransitionState() == CPlayer::kMS_Unmorphed; -void CPlayerGun::DoUserAnimEvent(float, CStateManager&, const CInt32POINode&, EUserEventType) {} + switch (msg) { + case kSM_Registered: { + CreateGunLight(mgr); + const CPlayerState::EBeamId beam = mCurrentBeamId[playerState->GetCurrentBeam()]; + x320_currentAuxBeam = beam; + x314_nextBeam = beam; + x310_currentBeam = beam; + x72c_currentBeam = x760_selectableBeams[x310_currentBeam]; + x738_nextBeam = x72c_currentBeam; + x72c_currentBeam->Load(mgr, true); + x72c_currentBeam->x1bc_rainSplashGenerator = x748_rainSplashGenerator.get(); + x744_auxWeapon->Load(x310_currentBeam, mgr); + x6e0_rightHandModel.AnimationData()->SetAnimation( + CAnimPlaybackParms(mHandAnimId[x310_currentBeam], -1, 1.f, true), false); + break; + } + case kSM_Deleted: + DeleteGunLight(mgr); + break; + case kSM_UpdateSplashInhabitant: + if (playerState->HasPowerUp(CPlayerState::kIT_PhazonSuit) && isUnmorphed) { + if (const CScriptWater* water = + TCastToPtr< CScriptWater >(const_cast< CEntity* >(mgr.GetObjectById(sender)))) { + if (water->GetFluidPlane().GetFluidType() == CFluidPlane::kFT_PhazonFluid) { + x835_24_canFirePhazon = true; + x835_25_inPhazonBeam = true; + } + } + } -void CPlayerGun::CancelCharge(CStateManager&, bool) {} + if (player->GetDistanceUnderWater() > player->GetEyeHeight()) { + x834_27_underwater = true; + if (x744_auxWeapon->IsComboFxActive(mgr) && x310_currentBeam != CPlayerState::kBI_Wave) { + StopContinuousBeam(mgr, false); + } + } else { + x834_27_underwater = false; + } + break; + case kSM_RemoveSplashInhabitant: + x834_27_underwater = false; + x835_24_canFirePhazon = false; + break; + case kSM_AddPhazonPoolInhabitant: + x835_30_inPhazonPool = true; + if (playerState->HasPowerUp(CPlayerState::kIT_PhazonSuit) && isUnmorphed) { + x835_24_canFirePhazon = true; + } + break; + case kSM_UpdatePhazonPoolInhabitant: + x835_30_inPhazonPool = true; + if (playerState->HasPowerUp(CPlayerState::kIT_PhazonSuit) && isUnmorphed) { + x835_24_canFirePhazon = true; + x835_25_inPhazonBeam = true; + if (x833_28_phazonBeamActive && + static_cast< CPhazonBeam* >(x72c_currentBeam)->IsFiring(mgr)) { + if (CEntity* ent = TCastToPtr< CEntity >(mgr.ObjectById(sender))) { + mgr.DeliverScriptMsg(ent, x538_playerId, kSM_Decrement); + } + } + } + break; + case kSM_RemovePhazonPoolInhabitant: + x835_30_inPhazonPool = false; + x835_24_canFirePhazon = false; + break; + case kSM_Damage: { + bool bigStrike = false; + bool metroidAttached = false; -void CPlayerGun::EnterFreeLook(CStateManager&) {} + if (const CEnergyProjectile* proj = + TCastToPtr< CEnergyProjectile >(const_cast< CEntity* >(mgr.GetObjectById(sender)))) { + if ((proj->GetAttribField() & CWeapon::kPA_BigStrike) == CWeapon::kPA_BigStrike) { + x394_damageTimer = proj->GetDamageDuration(); + bigStrike = true; + } + } else if (const CPatterned* ai = + TCastToPtr< CPatterned >(const_cast< CEntity* >(mgr.GetObjectById(sender)))) { + if (ai->IsMakingBigStrike()) { + x394_damageTimer = ai->GetDamageDuration(); + bigStrike = true; + const TUniqueId& attachedActor = player->GetAttachedActor(); + if (attachedActor != kInvalidUniqueId) { + const TPatternedCast< CMetroid > metroid( + const_cast< CEntity* >(mgr.GetObjectById(attachedActor))); + metroidAttached = CPatterned::CastTo< CMetroid >(metroid) != NULL; + } + } + } -void CPlayerGun::EnterFidget(CStateManager&) {} + if (!x834_30_inBigStrike) { + if (bigStrike) { + x834_31_gunMotionInFidgetBasePosition = false; + CancelFiring(mgr); + } + TakeDamage(bigStrike, !metroidAttached, mgr); + x834_30_inBigStrike = bigStrike; + } + break; + } + case kSM_OnFloor: + if (player->GetControlsFrozen() && !x834_30_inBigStrike) { + x2f4_fireButtonStates = 0; + x2ec_lastFireButtonStates = 0; + CancelFiring(mgr); + TakeDamage(true, false, mgr); + x394_damageTimer = 0.75f; + x834_30_inBigStrike = true; + } + break; + default: + break; + } -void CPlayerGun::UpdateLeftArmTransform(const CModelData&, const CStateManager&) {} + x740_grappleArm->AcceptScriptMsg(msg, sender, mgr); + x758_plasmaBeam->AcceptScriptMsg(msg, sender, mgr); + x75c_phazonBeam->AcceptScriptMsg(msg, sender, mgr); + x744_auxWeapon->AcceptScriptMsg(msg, sender, mgr); +} -void CPlayerGun::ReturnArmAndGunToDefault(CStateManager&, bool) {} +void CPlayerGun::StopContinuousBeam(CStateManager& mgr, bool stopSfx) { + if (IsWeaponStateSet(0x10)) { + ReturnArmAndGunToDefault(mgr, false); + x744_auxWeapon->StopComboFx(mgr, stopSfx); -void CPlayerGun::UpdateAuxWeapons(float, const CTransform4f&, CStateManager&) {} + bool doFx = true; + if (x310_currentBeam != CPlayerState::kBI_Ice) { + if (x310_currentBeam < CPlayerState::kBI_Ice) { + if (x310_currentBeam < CPlayerState::kBI_Power) { + return; + } + } else if (x310_currentBeam >= CPlayerState::kBI_Phazon) { + return; + } -void CPlayerGun::CancelLockOn() {} + if (x310_currentBeam == CPlayerState::kBI_Power && !x833_28_phazonBeamActive) { + doFx = false; + } + if (doFx) { + x72c_currentBeam->EnableSecondaryFx(stopSfx ? CGunWeapon::kSFT_None + : CGunWeapon::kSFT_CancelCharge); + } + } + } else if (x833_28_phazonBeamActive) { + CPhazonBeam* beam = static_cast< CPhazonBeam* >(x72c_currentBeam); + if (beam->IsFiring(mgr)) { + beam->StopBeam(mgr, stopSfx); + } + } else if (x310_currentBeam == CPlayerState::kBI_Plasma) { + CPlasmaBeam* beam = static_cast< CPlasmaBeam* >(x72c_currentBeam); + if (beam->IsFiring(mgr)) { + beam->StopBeam(mgr, static_cast< const bool >(stopSfx)); + } + } +} -void CPlayerGun::CreateGunLight(CStateManager&) {} +void CPlayerGun::RenderEnergyDrainEffects(const CStateManager& mgr) const { + const CEnergyDrainSource* it; + const CPlayer* const player = TCastToConstPtr< CPlayer >(mgr.GetObjectById(x538_playerId)); + if (player != nullptr) { + it = player->GetPlayerEnergyDrain().GetEnergyDrainSources().data(); + while (it != player->GetPlayerEnergyDrain().GetEnergyDrainSources().data() + + player->GetPlayerEnergyDrain().GetEnergyDrainSources().size()) { + CMetroidBeta* metroid = CPatterned::CastTo(TPatternedCast< CMetroidBeta >( + const_cast< CEntity* >(mgr.GetObjectById(it->GetEnergyDrainSourceId())))); + if (metroid != nullptr) { + metroid->RenderHitGunEffect(); + return; + } + ++it; + } + } +} -void CPlayerGun::DeleteGunLight(CStateManager&) {} +void CPlayerGun::DoUserAnimEvents(float dt, CStateManager& mgr) { + TAreaId aid = mgr.GetPlayer()->GetCurrentAreaId(); + const CAnimData& animData = *x72c_currentBeam->GetSolidModelData().GetAnimationData(); + const CGameCamera& camera = mgr.GetCameraManager()->GetCurrentCamera(mgr); + const CVector3f origin = x3e8_xf.GetTranslation(); + const CVector3f posToCam = camera.GetTranslation() - origin; -void CPlayerGun::UpdateGunLight(const CTransform4f&, CStateManager&) {} + int soundNodeCount = 0; + const CSoundPOINode* soundNode = animData.GetSoundPOIList(soundNodeCount); + if (soundNodeCount > 0) { + for (int i = 0; i < soundNodeCount; ++i, ++soundNode) { + const int charIdx = soundNode->GetCharacterIndex(); + if (soundNode->GetPoiType() != kPT_Sound) + continue; + if (charIdx != -1 && charIdx != animData.GetCharacterIndex()) + continue; + NWeaponTypes::do_sound_event(x670_animSfx, x328_animSfxPitch, false, soundNode->GetSoundId(), + soundNode->GetWeight(), soundNode->GetFlags(), + soundNode->GetFallOff(), soundNode->GetMaxDistance(), 0x14, 0x7f, + posToCam, origin, aid, mgr); + } + } -void CPlayerGun::SetGunLightActive(bool, CStateManager&) {} + int intNodeCount = 0; + const CInt32POINode* intNode = animData.GetInt32POIList(intNodeCount); + if (intNodeCount > 0) { + for (int i = 0; i < intNodeCount; ++i, ++intNode) { + const int charIdx = intNode->GetCharacterIndex(); + switch (intNode->GetPoiType()) { + case kPT_UserEvent: + DoUserAnimEvent(dt, mgr, *intNode, static_cast< EUserEventType >(intNode->GetValue())); + break; + case kPT_SoundInt32: + if (charIdx != -1 && charIdx != animData.GetCharacterIndex()) + break; + NWeaponTypes::do_sound_event(x670_animSfx, x328_animSfxPitch, false, intNode->GetValue(), + intNode->GetWeight(), intNode->GetFlags(), 0.1f, 150.f, 0x14, + 0x7f, posToCam, origin, aid, mgr); + break; + default: + break; + } + } + } +} -void CPlayerGun::LoadHandAnimTokens() {} +void CPlayerGun::DoUserAnimEvent(float dt, CStateManager& mgr, const CInt32POINode&, + EUserEventType type) { + switch (type) { + case kUE_Projectile: { + if (x32c_chargePhase != kCP_ComboFireDone) { + return; + } -void CPlayerGun::ProcessPhazonGunMorph(float, CStateManager&) {} + uchar fireSecondary = 0; + if (x310_currentBeam != CPlayerState::kBI_Wave && + x310_currentBeam != CPlayerState::kBI_Plasma) { + fireSecondary = 1; + } -void CPlayerGun::ProcessGunMorph(float, CStateManager&) {} + bool doFireSecondary = fireSecondary ? true : (x2ec_lastFireButtonStates & 0x1); + if (doFireSecondary) { + FireSecondary(dt, mgr); + } + if (!IsWeaponStateSet(0x10)) { + EnableWeaponState(0x10); + } + CancelCharge(mgr, true); + if (doFireSecondary) { + x72c_currentBeam->EnableSecondaryFx(CGunWeapon::kSFT_ToCombo); + } + break; + } + case kUE_Delete: + case kUE_DamageOn: + default: + break; + } +} -void CPlayerGun::AsyncLoadFidget(CStateManager&) {} +void CPlayerGun::CancelCharge(CStateManager& mgr, bool withEffect) { + if (withEffect) { + x32c_chargePhase = kCP_ChargeCooldown; + x72c_currentBeam->EnableSecondaryFx(CGunWeapon::kSFT_CancelCharge); + } else { + x72c_currentBeam->EnableSecondaryFx(CGunWeapon::kSFT_None); + } -void CPlayerGun::UnLoadFidget() {} + x834_24_charging = false; + x348_chargeCooldownTimer = 0.f; + x72c_currentBeam->ActivateCharge(false, false); + SetGunLightActive(false, mgr); +} -bool CPlayerGun::IsFidgetLoaded() { return false; } +void CPlayerGun::EnterFreeLook(CStateManager& mgr) { + if (!x832_30_requestReturnToDefault) + x73c_gunMotion->PlayPasAnim(SamusGun::kAS_FreeLook, mgr, 0.f, false); -void CPlayerGun::SetFidgetAnimBits(int, bool) {} + const int setId = x73c_gunMotion->GetFreeLookSetId(); + x740_grappleArm->EnterFreeLook(x835_25_inPhazonBeam ? 1 : x310_currentBeam, setId, mgr); +} -void CPlayerGun::AsyncLoadSuit(CStateManager&) {} +void CPlayerGun::EnterFidget(CStateManager& mgr) { + SamusGun::EFidgetType type = x3a4_fidget.GetType(); + int animSet = x3a4_fidget.GetAnimSet(); -void CPlayerGun::ReturnToRestPose() {} + if ((x2fc_fidgetAnimBits & 0x1) == 0x1) { + x73c_gunMotion->EnterFidget(mgr, type, animSet); + x834_25_gunMotionFidgeting = true; + } else { + x834_25_gunMotionFidgeting = false; + } -TUniqueId CPlayerGun::DropPowerBomb(CStateManager&) const {} + if ((x2fc_fidgetAnimBits & 0x2) == 0x2) { + x72c_currentBeam->EnterFidget(mgr, type, animSet); + } -void CPlayerGun::SetPhazonBeamFeedback(bool) {} + if ((x2fc_fidgetAnimBits & 0x4) == 0x4) { + x740_grappleArm->EnterFidget(mgr, type, type != SamusGun::kFT_Minor ? x310_currentBeam : 0, + animSet); + } + + UnLoadFidget(); + x3a4_fidget.DoneLoading(); +} + +void CPlayerGun::UpdateLeftArmTransform(const CModelData& modelData, const CStateManager&) { + CVector3f elbowOffset(-0.9f, -0.4f, 0.4f); + CTransform4f& auxXf = x740_grappleArm->AuxTransform(); + + if (x834_26_animPlaying) { + auxXf = CTransform4f::Identity(); + } else { + GetLctrWithShake(auxXf, modelData, rstl::string_l("elbow"), true, false); + } + + const CVector3f elbowPos = auxXf * elbowOffset; + auxXf.SetTranslation(elbowPos); + x740_grappleArm->SetTransform(x3e8_xf); +} + +void CPlayerGun::ReturnArmAndGunToDefault(CStateManager& mgr, bool returnToDefault) { + if (returnToDefault || !x833_31_inFreeLook) { + x73c_gunMotion->ReturnToDefault(mgr, false); + x740_grappleArm->ReturnToDefault(mgr, 0.f, false); + } + if (!x834_25_gunMotionFidgeting) + x72c_currentBeam->ReturnToDefault(mgr); + x834_25_gunMotionFidgeting = false; +} + +void CPlayerGun::UpdateAuxWeapons(float dt, const CTransform4f& targetXf, CStateManager& mgr) { + bool done = false; + { + CVector3f beamPos(x418_beamLocalXf.Get03(), x418_beamLocalXf.Get13(), x418_beamLocalXf.Get23()); + CVector3f firePoint(GetGunMotionTransform() * beamPos); + CVector3f camPos(mgr.GetCameraManager()->GetGlobalCameraTranslation(mgr)); + CVector3f firePos(firePoint.GetX() + camPos.GetX(), firePoint.GetY() + camPos.GetY(), + firePoint.GetZ() + camPos.GetZ()); + done = x744_auxWeapon->UpdateComboFx(dt, kScaleVector, firePos, targetXf, mgr); + } + if (IsWeaponStateSet(0x10)) { + if (x310_currentBeam == CPlayerState::kBI_Wave && + x744_auxWeapon->HasTarget(mgr) == kInvalidUniqueId) { + TUniqueId targetId = GetTargetId(mgr); + if (targetId == kInvalidUniqueId) { + targetId = mgr.GetPlayer()->GetAimTargetId(); + } + x744_auxWeapon->SetNewTarget(targetId, mgr); + } + if (done == true) { + return; + } + + bool comboDone = + x310_currentBeam == CPlayerState::kBI_Wave || x310_currentBeam == CPlayerState::kBI_Plasma; + if (comboDone != true) { + if (x72c_currentBeam->ComboFireOver()) { + comboDone = true; + } + } + + x72c_currentBeam->EnableSecondaryFx(CGunWeapon::kSFT_CancelCharge); + if (comboDone) { + x32c_chargePhase = kCP_ChargeDone; + ReturnArmAndGunToDefault(mgr, false); + ResetToBeam(); + } + } else { + if (x833_28_phazonBeamActive) { + CPhazonBeam* phazonBeam = static_cast< CPhazonBeam* >(x72c_currentBeam); + CVector3f phazonBeamPos = x418_beamLocalXf.GetTranslation(); + phazonBeam->UpdateBeam(dt, targetXf, phazonBeamPos, mgr); + } else if (x310_currentBeam == CPlayerState::kBI_Plasma) { + CPlasmaBeam* plasmaBeam = static_cast< CPlasmaBeam* >(x72c_currentBeam); + CVector3f plasmaBeamPos = x418_beamLocalXf.GetTranslation(); + plasmaBeam->UpdateBeam(dt, targetXf, plasmaBeamPos, mgr); + } + } +} + +void CPlayerGun::CancelLockOn() { + if (x832_29_lockedOn) { + x832_29_lockedOn = false; + x6a0_motionState.SetState(CMotionState::kMS_CancelLockOn); + if (x32c_chargePhase == kCP_NotCharging && int(x318_comboAmmoIdx) != 1) { + PlayAnim(NWeaponTypes::kGAT_BasePosition, false); + } + } +} + +void CPlayerGun::CreateGunLight(CStateManager& mgr) { + if (x53c_lightId != kInvalidUniqueId) { + return; + } + + x53c_lightId = mgr.AllocateUniqueId(); + CAssetId lightId = x53c_lightId; + mgr.AddObject(rs_new CGameLight( + x53c_lightId, kInvalidAreaId, false, rstl::string_l("GunLite"), x3e8_xf, x538_playerId, + CLight::BuildDirectional(CVector3f::Forward(), CColor::Black()), lightId & 0x3ff, 0, 0.f)); +} + +void CPlayerGun::DeleteGunLight(CStateManager& mgr) { + if (x53c_lightId == kInvalidUniqueId) { + return; + } + + mgr.DeleteObjectRequest(x53c_lightId); + x53c_lightId = kInvalidUniqueId; +} + +void CPlayerGun::UpdateGunLight(const CTransform4f& xf, CStateManager& mgr) { + if (x53c_lightId == kInvalidUniqueId) { + return; + } + if (x32c_chargePhase == kCP_NotCharging) { + return; + } + + if (CGameLight* light = TCastToPtr< CGameLight >(mgr.ObjectById(x53c_lightId))) { + if (light->GetActive()) { + CElementGen* chargeFx = x72c_currentBeam->GetChargeMuzzleFx(); + light->SetTransform(xf); + light->SetTranslation(xf.GetTranslation()); + if (chargeFx != NULL && chargeFx->SystemHasLight()) { + CLight genLight = chargeFx->GetLight(); + genLight.SetColor( + CColor::Lerp(0, genLight.GetColor().GetColor_u32(), x340_chargeBeamFactor)); + light->SetLight(genLight); + } + } + } +} + +void CPlayerGun::SetGunLightActive(bool active, CStateManager& mgr) { + if (x53c_lightId == kInvalidUniqueId) { + return; + } + + if (CGameLight* light = TCastToPtr< CGameLight >(mgr.ObjectById(x53c_lightId))) { + light->SetActive(active); + if (active) { + if (CElementGen* chargeFx = x72c_currentBeam->GetChargeMuzzleFx()) { + if (chargeFx->SystemHasLight()) { + CLight genLight = chargeFx->GetLight(); + genLight.SetColor(CColor::Black()); + light->SetLight(genLight); + } + } + } + } +} + +void CPlayerGun::LoadHandAnimTokens() { + CAnimData& animData = *x6e0_rightHandModel.AnimationData(); + rstl::set< CPrimitive > prims; + for (int i = 0; i < 3; ++i) { + CAnimPlaybackParms parms(i, -1, 1.f, true); + animData.GetAnimationPrimitives(parms, prims); + } + CAnimData::PrimitiveSetToTokenVector(prims, x540_handAnimTokens, true); +} + +void CPlayerGun::ProcessPhazonGunMorph(float dt, CStateManager& mgr) { + if (x835_26_phazonBeamMorphing) { + if (x835_27_intoPhazonBeam) { + x39c_phazonMorphT += 15.f * dt; + if (x39c_phazonMorphT > 1.f) { + x39c_phazonMorphT = 1.f; + } + } else { + x39c_phazonMorphT -= 2.f * dt; + if (x39c_phazonMorphT < 0.f) { + x835_26_phazonBeamMorphing = false; + x39c_phazonMorphT = 0.f; + } + } + } + + switch (x33c_phazonBeamState) { + case kPBS_Entering: + if (x75c_phazonBeam.get() != NULL) { + x75c_phazonBeam->Update(dt, mgr); + if (x75c_phazonBeam->IsLoaded()) { + StartPhazonBeamTransition(true, mgr, *mgr.PlayerState()); + SetPhazonBeamMorph(false); + x33c_phazonBeamState = kPBS_Active; + x338_nextState = kNS_SetupBeam; + } + } + break; + case kPBS_Exiting: + if (x738_nextBeam != NULL) { + x738_nextBeam->Update(dt, mgr); + if (x738_nextBeam->IsLoaded()) { + x835_25_inPhazonBeam = false; + StartPhazonBeamTransition(false, mgr, *mgr.PlayerState()); + SetPhazonBeamMorph(false); + x33c_phazonBeamState = kPBS_Inactive; + x338_nextState = kNS_SetupBeam; + } + } + break; + default: + break; + } +} + +void CPlayerGun::ProcessGunMorph(float dt, CStateManager& mgr) { + const CGunMorph::EGunState gunState = x678_morph.GetGunState(); + const bool isUnmorphed = mgr.GetPlayer()->GetMorphballTransitionState() == CPlayer::kMS_Unmorphed; + CPlayerState* playerState = mgr.PlayerState(); + + switch (gunState) { + case CGunMorph::kGS_InWipeDone: + if (x310_currentBeam != x314_nextBeam && x734_loadingBeam != NULL) { + if (!isUnmorphed) { + x734_loadingBeam->Touch(mgr); + } + if (x734_loadingBeam->IsLoaded() && x744_auxWeapon->IsLoaded()) { + x730_outgoingBeam = x734_loadingBeam != x72c_currentBeam ? x72c_currentBeam : NULL; + x734_loadingBeam = NULL; + x310_currentBeam = x314_nextBeam; + x320_currentAuxBeam = x314_nextBeam; + x833_30_canShowAuxMuzzleEffect = true; + x72c_currentBeam = x760_selectableBeams[x314_nextBeam]; + x738_nextBeam = x72c_currentBeam; + x678_morph.SetWeaponChanged(); + playerState->SetCurrentBeam(x314_nextBeam); + } + } + break; + case CGunMorph::kGS_InWipe: + case CGunMorph::kGS_OutWipe: + x774_holoTransitionGen->SetGlobalScale(kScaleVector); + x774_holoTransitionGen->SetGlobalTranslation(CVector3f(0.f, x678_morph.GetYLerp(), 0.f)); + x774_holoTransitionGen->Update(dt); + break; + default: + break; + } + + switch (x678_morph.Update(0.2f, 1.292392f, dt)) { + case CGunMorph::kME_InWipeDone: + CSfxManager::SfxStart(SFXwpn_morph_in_wipe_done, 0x7f, 0x40, true, CSfxManager::kMaxPriority, + false, CSfxManager::kAllAreas); + break; + case CGunMorph::kME_OutWipeDone: + if (x730_outgoingBeam != NULL) { + if (x730_outgoingBeam != x72c_currentBeam) { + x730_outgoingBeam->Unload(mgr); + x730_outgoingBeam = NULL; + } + } + if (isUnmorphed) { + const ushort* const intoBeamSounds = mIntoBeamSound; + const short pan = 0x4a; + NWeaponTypes::play_sfx(intoBeamSounds[x310_currentBeam], x834_27_underwater, false, pan); + } + x72c_currentBeam->x1bc_rainSplashGenerator = x748_rainSplashGenerator.get(); + x72c_currentBeam->EnableFx(true); + PlayAnim(NWeaponTypes::kGAT_ToBeam, false); + if (x833_31_inFreeLook) { + EnterFreeLook(mgr); + } else if (x832_30_requestReturnToDefault) { + ReturnArmAndGunToDefault(mgr, false); + } + if (x834_28_requestImmediateRecharge || (x2ec_lastFireButtonStates & 0x1) != 0) { + if (playerState->GetCurrentVisor() != CPlayerState::kPV_Scan) { + x32c_chargePhase = kCP_ChargeRequested; + } + x834_28_requestImmediateRecharge = false; + } + x832_30_requestReturnToDefault = false; + x338_nextState = kNS_SetupBeam; + break; + default: + break; + } +} + +void CPlayerGun::AsyncLoadFidget(CStateManager& mgr) { + SamusGun::EFidgetType type = x3a4_fidget.GetType(); + int animSet = x3a4_fidget.GetAnimSet(); + SamusGun::EFidgetType beamType = type; + bool beamOnly = x3a4_fidget.GetState() == CFidget::kS_HolsterBeam; + + SetFidgetAnimBits(animSet, beamOnly); + + if ((x2fc_fidgetAnimBits & 0x1) == 0x1) { + x73c_gunMotion->GunController().LoadFidgetAnimAsync(mgr, type, x310_currentBeam, animSet); + } + + if ((x2fc_fidgetAnimBits & 0x2) == 0x2) { + x72c_currentBeam->AsyncLoadFidget(mgr, beamOnly ? SamusGun::kFT_Minor : beamType, animSet); + x832_31_inRestPose = false; + } + + if ((x2fc_fidgetAnimBits & 0x4) == 0x4) { + if (CGunController* gc = x740_grappleArm->GunController()) { + gc->LoadFidgetAnimAsync(mgr, type, type != SamusGun::kFT_Minor ? x310_currentBeam : 0, + animSet); + } + } +} + +void CPlayerGun::UnLoadFidget() { + if ((x2fc_fidgetAnimBits & 0x1) == 0x1) + x73c_gunMotion->GunController().UnLoadFidget(); + if ((x2fc_fidgetAnimBits & 0x2) == 0x2) + x72c_currentBeam->UnLoadFidget(); + if ((x2fc_fidgetAnimBits & 0x4) == 0x4) + if (CGunController* gc = x740_grappleArm->GunController()) + gc->UnLoadFidget(); + x2fc_fidgetAnimBits = 0; +} + +bool CPlayerGun::IsFidgetLoaded() { + uint loadFlags = 0; + if ((x2fc_fidgetAnimBits & 0x1) == 0x1 && x73c_gunMotion->GunController().IsFidgetLoaded()) { + loadFlags |= 0x1; + } + if ((x2fc_fidgetAnimBits & 0x2) == 0x2 && x72c_currentBeam->IsFidgetLoaded()) { + loadFlags |= 0x2; + } + if ((x2fc_fidgetAnimBits & 0x4) == 0x4) { + if (CGunController* gc = x740_grappleArm->GunController()) { + if (gc->IsFidgetLoaded()) { + loadFlags |= 0x4; + } + } + } + return loadFlags == x2fc_fidgetAnimBits; +} + +void CPlayerGun::SetFidgetAnimBits(int animSet, bool beamOnly) { + x2fc_fidgetAnimBits = 0; + if (beamOnly) { + x2fc_fidgetAnimBits = 2; + return; + } + + switch (x3a4_fidget.GetType()) { + case SamusGun::kFT_Minor: + x2fc_fidgetAnimBits = 1; + if (animSet <= 0) { + return; + } + if (animSet >= 2) { + return; + } + x2fc_fidgetAnimBits |= 4; + return; + case SamusGun::kFT_Major: + if (animSet >= 6 || animSet < 4) { + x2fc_fidgetAnimBits = 2; + } else { + x2fc_fidgetAnimBits = 1; + } + x2fc_fidgetAnimBits |= 4; + return; + default: + return; + } +} + +void CPlayerGun::AsyncLoadSuit(CStateManager& mgr) { + x72c_currentBeam->AsyncLoadSuitArm(mgr); + x740_grappleArm->AsyncLoadSuit(mgr); +} + +void CPlayerGun::ReturnToRestPose() { + if (x832_31_inRestPose == true) { + return; + } + + if (IsWeaponStateSet(0x1)) { + PlayAnim(NWeaponTypes::kGAT_BasePosition, false); + } else if (IsWeaponStateSet(0x4)) { + PlayAnim(NWeaponTypes::kGAT_ToMissile, false); + } + + x832_31_inRestPose = true; +} + +TUniqueId CPlayerGun::DropPowerBomb(CStateManager& mgr) const { + const CDamageInfo dInfo = mgr.GetPlayer()->GetDeathTime() <= 0.f + ? gpTweakPlayerGun->x8c_powerBomb + : CDamageInfo(CWeaponMode::PowerBomb(), 0.f, 0.f, 0.f); + const float ballHalfExtent = gpTweakPlayer->GetPlayerBallHalfExtent(); + + TUniqueId uid = mgr.AllocateUniqueId(); + float zero = 0.f; + CPowerBomb* pBomb = + rs_new CPowerBomb(x784_bombEffects[1][0], uid, kInvalidAreaId, x538_playerId, + CTransform4f::Translate(mgr.GetPlayer()->GetTranslation() + + CVector3f(zero, zero, ballHalfExtent)), + dInfo); + mgr.AddObject(*pBomb); + return uid; +} + +void CPlayerGun::SetPhazonBeamFeedback(bool active) { + const bool fadeOut = !active; + CSamusHud::DisplayHudMemo(rstl::wstring_l(gpStringTable->GetString(21)), + CHUDMemoParms(5.f, true, fadeOut, false)); + + if (CSfxManager::IsPlaying(x2e8_phazonBeamSfx)) { + CSfxManager::SfxStop(x2e8_phazonBeamSfx); + } + + x2e8_phazonBeamSfx.Clear(); + if (active) { + x2e8_phazonBeamSfx = + NWeaponTypes::play_sfx(SFXsam_a_phazup_lp_00, x834_27_underwater, false, 0x4a); + } +} diff --git a/src/MetroidPrime/ScriptObjects/CScriptPlatform.cpp b/src/MetroidPrime/ScriptObjects/CScriptPlatform.cpp index 8d7611da..7a02b7ee 100644 --- a/src/MetroidPrime/ScriptObjects/CScriptPlatform.cpp +++ b/src/MetroidPrime/ScriptObjects/CScriptPlatform.cpp @@ -302,3 +302,19 @@ void CScriptPlatform::BuildSlaveList(CStateManager& mgr) { } } } + +void CScriptPlatform::AddSlave(TUniqueId id, CStateManager& mgr) { + rstl::vector< SRiders >::iterator it = x338_slavesDynamic.begin(); + rstl::vector< SRiders >::iterator end = x338_slavesDynamic.end(); + for (; it != end; ++it) { + if (it->x0_uid == id) { + return; + } + } + + if (CActor* act = TCastToPtr< CActor >(mgr.ObjectById(id))) { + act->AddMaterial(kMT_PlatformSlave, mgr); + CTransform4f xf = GetTransform().GetInverse() * act->GetTransform(); + x338_slavesDynamic.push_back(SRiders(id, 0.166667f, xf)); + } +} diff --git a/src/MetroidPrime/Weapons/CBomb.cpp b/src/MetroidPrime/Weapons/CBomb.cpp index 28458a6c..540462eb 100644 --- a/src/MetroidPrime/Weapons/CBomb.cpp +++ b/src/MetroidPrime/Weapons/CBomb.cpp @@ -16,7 +16,7 @@ #include #include -CBomb::CBomb(const TToken< CGenDescription >& particle1, const TToken< CGenDescription >& particle2, +CBomb::CBomb(TToken< CGenDescription > particle1, TToken< CGenDescription > particle2, TUniqueId uid, TAreaId aid, TUniqueId playerId, float f1, const CTransform4f& xf, const CDamageInfo& dInfo) : CWeapon(uid, aid, true, playerId, kWT_Bomb, rstl::string_l("Bomb"), xf, @@ -74,7 +74,7 @@ void CBomb::AddToRenderer(const CFrustumPlanes& frustum, const CStateManager& mg } } -void CBomb::Render(const CStateManager& mgr) const { } +void CBomb::Render(const CStateManager& mgr) const {} // Equivelant, https://decomp.me/scratch/cr4FM void CBomb::Think(float dt, CStateManager& mgr) { diff --git a/src/MetroidPrime/Weapons/CGunWeapon.cpp b/src/MetroidPrime/Weapons/CGunWeapon.cpp index 525728a3..f58cfd1c 100644 --- a/src/MetroidPrime/Weapons/CGunWeapon.cpp +++ b/src/MetroidPrime/Weapons/CGunWeapon.cpp @@ -3,6 +3,7 @@ #include "MetroidPrime/CAnimData.hpp" #include "MetroidPrime/CAnimPlaybackParms.hpp" #include "MetroidPrime/CAnimRes.hpp" +#include "MetroidPrime/CDamageInfo.hpp" #include "MetroidPrime/CRainSplashGenerator.hpp" #include "MetroidPrime/CStateManager.hpp" #include "MetroidPrime/Cameras/CCameraManager.hpp" @@ -447,7 +448,8 @@ CDamageInfo CGunWeapon::GetDamageInfo(CStateManager& mgr, CPlayerState::EChargeS if (chargeState == CPlayerState::kCS_Normal) { return GetShotDamageInfo(wInfo.x4_normal, mgr); } else { - SShotParam param(chargeFactor, wInfo.x20_charged); + CDamageInfo param = wInfo.x20_charged; + param.MultiplyDamageAndRadius(chargeFactor); return GetShotDamageInfo(param, mgr); } } diff --git a/src/MetroidPrime/Weapons/WeaponTypes.cpp b/src/MetroidPrime/Weapons/WeaponTypes.cpp index 4c3477f9..28658e75 100644 --- a/src/MetroidPrime/Weapons/WeaponTypes.cpp +++ b/src/MetroidPrime/Weapons/WeaponTypes.cpp @@ -167,18 +167,8 @@ CSfxHandle play_sfx(const ushort sfx, const bool underwater, const bool looped, } // namespace NWeaponTypes -CDamageInfo CGunWeapon::GetShotDamageInfo(const SShotParam& shotParam, CStateManager& mgr) const { - // CWeaponMode mode(shotParam.x0_weaponType, 0); - // float damage = shotParam.x8_damage; - // float radiusDamage = shotParam.xc_radiusDamage; - // float radius = shotParam.x10_radius; - // float knockback = shotParam.x14_knockback; - // bool noImmunity = shotParam.x18_24_noImmunity; - - CDamageInfo result(CWeaponMode(shotParam.x0_weaponType, 0), shotParam.x8_damage, - shotParam.xc_radiusDamage, shotParam.x10_radius, shotParam.x14_knockback, - shotParam.x18_24_noImmunity); - +CDamageInfo CGunWeapon::GetShotDamageInfo(const CDamageInfo& shotParam, CStateManager& mgr) const { + CDamageInfo result = shotParam; if (gpGameState->GetHardMode()) { result.MultiplyDamage(gpGameState->GetHardModeWeaponMultiplier()); }