diff --git a/config/GM8E01_00/splits.txt b/config/GM8E01_00/splits.txt index f2d7ed6e..861b7b16 100644 --- a/config/GM8E01_00/splits.txt +++ b/config/GM8E01_00/splits.txt @@ -2176,7 +2176,7 @@ MetroidPrime/Player/CMorphBallShadow.cpp: .sdata2 start:0x805ADCB8 end:0x805ADCD0 .sbss2 start:0x805AF470 end:0x805AF478 -MetroidPrime/Player/CPlayerInputFilter.cpp: +MetroidPrime/Player/CPlayerStuckTracker.cpp: .text start:0x80296E24 end:0x802979E4 .sdata2 start:0x805ADCD0 end:0x805ADCE8 diff --git a/config/GM8E01_00/symbols.txt b/config/GM8E01_00/symbols.txt index 5c4b4511..615d656d 100644 --- a/config/GM8E01_00/symbols.txt +++ b/config/GM8E01_00/symbols.txt @@ -289,7 +289,7 @@ __ct__11CObjectListF15EGameObjectList = .text:0x80010038; // type:function size: __ct__Q211CObjectList16SObjectListEntryFv = .text:0x8001012C; // type:function size:0x18 scope:weak __dt__7CPlayerFv = .text:0x80010144; // type:function size:0x730 scope:global fn_80010874 = .text:0x80010874; // type:function size:0x58 -__dt__Q27CPlayer12CInputFilterFv = .text:0x800108CC; // type:function size:0x1CC scope:global +__dt__Q27CPlayer19CPlayerStuckTrackerFv = .text:0x800108CC; // type:function size:0x1CC scope:global IsTransparent__7CPlayerCFv = .text:0x80010A98; // type:function size:0x18 scope:global IsEnergyLow__7CPlayerCFRC13CStateManager = .text:0x80010AB0; // type:function size:0x7C scope:global FinishNewScan__7CPlayerFR13CStateManager = .text:0x80010B2C; // type:function size:0x12C scope:global @@ -352,7 +352,7 @@ UpdateGunAlpha__7CPlayerFRC13CStateManager = .text:0x8001454C; // type:function ComputeFreeLook__7CPlayerFRC11CFinalInput = .text:0x80014618; // type:function size:0x208 scope:global UpdateFreeLook__7CPlayerFf = .text:0x80014820; // type:function size:0x184 scope:global DetachActorFromPlayer__7CPlayerFv = .text:0x800149A4; // type:function size:0x2C scope:global -AttachActorToPlayer__7CPlayerF9TUniqueId = .text:0x800149D0; // type:function size:0x70 scope:global +AttachActorToPlayer__7CPlayerF9TUniqueIdb = .text:0x800149D0; // type:function size:0x70 scope:global CalculateLeftStickEdgePosition__7CPlayerCFff = .text:0x80014A40; // type:function size:0x100 scope:global GetMaximumPlayerPositiveVerticalVelocity__7CPlayerCFRC13CStateManager = .text:0x80014B40; // type:function size:0x40 scope:global UpdateMorphBallState__7CPlayerFfRC11CFinalInputR13CStateManager = .text:0x80014B80; // type:function size:0x1DC scope:global @@ -6226,7 +6226,7 @@ ComputeBoostBallMovement__10CMorphBallFRC11CFinalInputRC13CStateManagerf = .text UpdateEffects__10CMorphBallFfR13CStateManager = .text:0x800F4868; // type:function size:0xC30 scope:global fn_800F5498 = .text:0x800F5498; // type:function size:0x30 fn_800F54C8 = .text:0x800F54C8; // type:function size:0xE4 -StopEffects__10CMorphBallFv = .text:0x800F55AC; // type:function size:0x90 scope:global +StopParticleWakes__10CMorphBallFv = .text:0x800F55AC; // type:function size:0x90 scope:global LeaveMorphBallState__10CMorphBallFR13CStateManager = .text:0x800F563C; // type:function size:0x4C scope:global EnterMorphBallState__10CMorphBallFR13CStateManager = .text:0x800F5688; // type:function size:0xB8 scope:global SetBallLightActive__10CMorphBallFR13CStateManagerb = .text:0x800F5740; // type:function size:0x78 scope:global @@ -8024,7 +8024,7 @@ BuildNearListBox__FbRC12CTransform4ffff = .text:0x8017F970; // type:function siz __sinit_CPlayerOrbit_cpp = .text:0x8017F9D8; // type:function size:0x1AC scope:local fn_8017FB84 = .text:0x8017FB84; // type:function size:0x788 GetActorRelativeVelocities__14CGameCollisionFPC13CPhysicsActorPC13CPhysicsActor = .text:0x8018030C; // type:function size:0xE0 scope:global -FindNonIntersectingVector__14CGameCollisionFR13CStateManagerRC19CAreaCollisionCacheRC13CPhysicsActorRC19CCollisionPrimitiveRCQ24rstl32reserved_vector<9TUniqueId,1024> = .text:0x801803EC; // type:function size:0x4A0 scope:global +FindNonIntersectingVector__14CGameCollisionFRC13CStateManagerR19CAreaCollisionCacheR13CPhysicsActorRC19CCollisionPrimitiveRCQ24rstl32reserved_vector<9TUniqueId,1024> = .text:0x801803EC; // type:function size:0x4A0 scope:global CollisionFailsafe__14CGameCollisionFRC13CStateManagerR19CAreaCollisionCacheR13CPhysicsActorRC19CCollisionPrimitiveRCQ24rstl32reserved_vector<9TUniqueId,1024>fUi = .text:0x8018088C; // type:function size:0x668 scope:global MoveAndCollide__14CGameCollisionFR13CStateManagerR13CPhysicsActorfRC16ICollisionFilterPCQ24rstl32reserved_vector<9TUniqueId,1024> = .text:0x80180EF4; // type:function size:0xCE8 scope:global MovePlayer__14CGameCollisionFR13CStateManagerR13CPhysicsActorfPCQ24rstl32reserved_vector<9TUniqueId,1024> = .text:0x80181BDC; // type:function size:0x15C scope:global @@ -11475,13 +11475,13 @@ fn_80296C3C = .text:0x80296C3C; // type:function size:0x7C fn_80296CB8 = .text:0x80296CB8; // type:function size:0x78 fn_80296D30 = .text:0x80296D30; // type:function size:0x7C fn_80296DAC = .text:0x80296DAC; // type:function size:0x78 -Reset__Q27CPlayer12CInputFilterFv = .text:0x80296E24; // type:function size:0x148 scope:global -Passes__Q27CPlayer12CInputFilterFv = .text:0x80296F6C; // type:function size:0x480 scope:global +ResetStats__Q27CPlayer19CPlayerStuckTrackerFv = .text:0x80296E24; // type:function size:0x148 scope:global +IsPlayerStuck__Q27CPlayer19CPlayerStuckTrackerFv = .text:0x80296F6C; // type:function size:0x480 scope:global _getElementBoundsCheck__FRCQ24rstl21reserved_vectori = .text:0x802973EC; // type:function size:0x3C scope:global _getElementBoundsCheck<9CVector2f,20>__FRCQ24rstl30reserved_vector<9CVector2f,20>i = .text:0x80297428; // type:function size:0x44 scope:global _getElementBoundsCheck<9CVector3f,20>__FRCQ24rstl30reserved_vector<9CVector3f,20>i = .text:0x8029746C; // type:function size:0x4C scope:global -AddSample__Q27CPlayer12CInputFilterFiRC9CVector3fRC9CVector3fRC9CVector2f = .text:0x802974B8; // type:function size:0x514 scope:global -__ct__Q27CPlayer12CInputFilterFv = .text:0x802979CC; // type:function size:0x18 scope:global +AddState__Q27CPlayer19CPlayerStuckTrackerFQ37CPlayer19CPlayerStuckTracker12EPlayerStateRC9CVector3fRC9CVector3fRC9CVector2f = .text:0x802974B8; // type:function size:0x514 scope:global +__ct__Q27CPlayer19CPlayerStuckTrackerFv = .text:0x802979CC; // type:function size:0x18 scope:global GetIsContinueDraw__10CSlideShowFv = .text:0x802979E4; // type:function size:0x8 scope:global fn_802979EC = .text:0x802979EC; // type:function size:0x130 fn_80297B1C = .text:0x80297B1C; // type:function size:0xF8 @@ -26575,7 +26575,7 @@ lbl_805AE768 = .sdata2:0x805AE768; // type:object size:0x8 data:float @771 = .sdata2:0x805AE784; // type:object size:0x4 scope:local data:float lbl_805AE788 = .sdata2:0x805AE788; // type:object size:0x4 data:float lbl_805AE78C = .sdata2:0x805AE78C; // type:object size:0x4 data:float -lbl_805AE790 = .sdata2:0x805AE790; // type:object size:0x8 data:float +lbl_805AE790 = .sdata2:0x805AE790; // type:object size:0x4 data:float @181 = .sdata2:0x805AE798; // type:object size:0x4 scope:local data:float @182 = .sdata2:0x805AE79C; // type:object size:0x4 scope:local data:float @183 = .sdata2:0x805AE7A0; // type:object size:0x4 scope:local data:float diff --git a/config/GM8E01_01/splits.nope b/config/GM8E01_01/splits.nope index b922fe97..5c0eed77 100644 --- a/config/GM8E01_01/splits.nope +++ b/config/GM8E01_01/splits.nope @@ -2147,7 +2147,7 @@ MetroidPrime/Player/CMorphBallShadow.cpp: .sdata2 start:0x805ADE98 end:0x805ADEB0 .sbss2 start:0x805AF650 end:0x805AF658 -MetroidPrime/Player/CPlayerInputFilter.cpp: +MetroidPrime/Player/CPlayerStuckTracker.cpp: .text start:0x80296ED0 end:0x80297A90 .sdata2 start:0x805ADEB0 end:0x805ADEC8 diff --git a/config/GM8E01_01/symbols.txt b/config/GM8E01_01/symbols.txt index 88b45a67..08351934 100644 --- a/config/GM8E01_01/symbols.txt +++ b/config/GM8E01_01/symbols.txt @@ -289,7 +289,7 @@ __ct__11CObjectListF15EGameObjectList = .text:0x800100B4; // type:function size: __ct__Q211CObjectList16SObjectListEntryFv = .text:0x800101A8; // type:function size:0x18 scope:weak __dt__7CPlayerFv = .text:0x800101C0; // type:function size:0x730 scope:global fn_80010874 = .text:0x800108F0; // type:function size:0x58 scope:global -__dt__Q27CPlayer12CInputFilterFv = .text:0x80010948; // type:function size:0x1CC scope:global +__dt__Q27CPlayer19CPlayerStuckTrackerFv = .text:0x80010948; // type:function size:0x1CC scope:global IsTransparent__7CPlayerCFv = .text:0x80010B14; // type:function size:0x18 scope:global IsEnergyLow__7CPlayerCFRC13CStateManager = .text:0x80010B2C; // type:function size:0x7C scope:global FinishNewScan__7CPlayerFR13CStateManager = .text:0x80010BA8; // type:function size:0x12C scope:global @@ -352,7 +352,7 @@ UpdateGunAlpha__7CPlayerFRC13CStateManager = .text:0x800145C8; // type:function ComputeFreeLook__7CPlayerFRC11CFinalInput = .text:0x80014694; // type:function size:0x208 scope:global UpdateFreeLook__7CPlayerFf = .text:0x8001489C; // type:function size:0x184 scope:global DetachActorFromPlayer__7CPlayerFv = .text:0x80014A20; // type:function size:0x2C scope:global -AttachActorToPlayer__7CPlayerF9TUniqueId = .text:0x80014A4C; // type:function size:0x70 scope:global +AttachActorToPlayer__7CPlayerF9TUniqueIdb = .text:0x80014A4C; // type:function size:0x70 scope:global CalculateLeftStickEdgePosition__7CPlayerCFff = .text:0x80014ABC; // type:function size:0x100 scope:global GetMaximumPlayerPositiveVerticalVelocity__7CPlayerCFRC13CStateManager = .text:0x80014BBC; // type:function size:0x40 scope:global UpdateMorphBallState__7CPlayerFfRC11CFinalInputR13CStateManager = .text:0x80014BFC; // type:function size:0x1DC scope:global @@ -6228,7 +6228,7 @@ ComputeBoostBallMovement__10CMorphBallFRC11CFinalInputRC13CStateManagerf = .text UpdateEffects__10CMorphBallFfR13CStateManager = .text:0x800F48E4; // type:function size:0xC30 scope:global fn_800F5498 = .text:0x800F5514; // type:function size:0x30 scope:global fn_800F54C8 = .text:0x800F5544; // type:function size:0xE4 scope:global -StopEffects__10CMorphBallFv = .text:0x800F5628; // type:function size:0x90 scope:global +StopParticleWakes__10CMorphBallFv = .text:0x800F5628; // type:function size:0x90 scope:global LeaveMorphBallState__10CMorphBallFR13CStateManager = .text:0x800F56B8; // type:function size:0x4C scope:global EnterMorphBallState__10CMorphBallFR13CStateManager = .text:0x800F5704; // type:function size:0xB8 scope:global SetBallLightActive__10CMorphBallFR13CStateManagerb = .text:0x800F57BC; // type:function size:0x78 scope:global @@ -8029,7 +8029,7 @@ BuildNearListBox__FbRC12CTransform4ffff = .text:0x8017F9EC; // type:function siz __sinit_CPlayerOrbit_cpp = .text:0x8017FA54; // type:function size:0x1AC scope:global fn_8017FB84 = .text:0x8017FC00; // type:function size:0x788 scope:global GetActorRelativeVelocities__14CGameCollisionFPC13CPhysicsActorPC13CPhysicsActor = .text:0x80180388; // type:function size:0xE0 scope:global -FindNonIntersectingVector__14CGameCollisionFR13CStateManagerRC19CAreaCollisionCacheRC13CPhysicsActorRC19CCollisionPrimitiveRCQ24rstl32reserved_vector<9TUniqueId,1024> = .text:0x80180468; // type:function size:0x4A0 scope:global +FindNonIntersectingVector__14CGameCollisionFRC13CStateManagerR19CAreaCollisionCacheR13CPhysicsActorRC19CCollisionPrimitiveRCQ24rstl32reserved_vector<9TUniqueId,1024> = .text:0x80180468; // type:function size:0x4A0 scope:global CollisionFailsafe__14CGameCollisionFRC13CStateManagerR19CAreaCollisionCacheR13CPhysicsActorRC19CCollisionPrimitiveRCQ24rstl32reserved_vector<9TUniqueId,1024>fUi = .text:0x80180908; // type:function size:0x668 scope:global MoveAndCollide__14CGameCollisionFR13CStateManagerR13CPhysicsActorfRC16ICollisionFilterPCQ24rstl32reserved_vector<9TUniqueId,1024> = .text:0x80180F70; // type:function size:0xCE8 scope:global MovePlayer__14CGameCollisionFR13CStateManagerR13CPhysicsActorfPCQ24rstl32reserved_vector<9TUniqueId,1024> = .text:0x80181C58; // type:function size:0x15C scope:global @@ -11488,13 +11488,13 @@ fn_80296C3C = .text:0x80296CE8; // type:function size:0x7C scope:global fn_80296CB8 = .text:0x80296D64; // type:function size:0x78 scope:global fn_80296D30 = .text:0x80296DDC; // type:function size:0x7C scope:global fn_80296DAC = .text:0x80296E58; // type:function size:0x78 scope:global -Reset__Q27CPlayer12CInputFilterFv = .text:0x80296ED0; // type:function size:0x148 scope:global -Passes__Q27CPlayer12CInputFilterFv = .text:0x80297018; // type:function size:0x480 scope:global +ResetStats__Q27CPlayer19CPlayerStuckTrackerFv = .text:0x80296ED0; // type:function size:0x148 scope:global +IsPlayerStuck__Q27CPlayer19CPlayerStuckTrackerFv = .text:0x80297018; // type:function size:0x480 scope:global _getElementBoundsCheck__FRCQ24rstl21reserved_vectori = .text:0x80297498; // type:function size:0x3C scope:global _getElementBoundsCheck<9CVector2f,20>__FRCQ24rstl30reserved_vector<9CVector2f,20>i = .text:0x802974D4; // type:function size:0x44 scope:global _getElementBoundsCheck<9CVector2f,20>__FRCQ24rstl30reserved_vector<9CVector2f,20>i = .text:0x80297518; // type:function size:0x4C scope:global -AddSample__Q27CPlayer12CInputFilterFiRC9CVector3fRC9CVector3fRC9CVector2f = .text:0x80297564; // type:function size:0x514 scope:global -__ct__Q27CPlayer12CInputFilterFv = .text:0x80297A78; // type:function size:0x18 scope:global +AddState__Q27CPlayer19CPlayerStuckTrackerFQ37CPlayer19CPlayerStuckTracker12EPlayerStateRC9CVector3fRC9CVector3fRC9CVector2f = .text:0x80297564; // type:function size:0x514 scope:global +__ct__Q27CPlayer19CPlayerStuckTrackerFv = .text:0x80297A78; // type:function size:0x18 scope:global GetIsContinueDraw__10CSlideShowFv = .text:0x80297A90; // type:function size:0x8 scope:global fn_802979EC = .text:0x80297A98; // type:function size:0x130 scope:global fn_80297B1C = .text:0x80297BC8; // type:function size:0xF8 scope:global diff --git a/configure.py b/configure.py index 794c9f7c..6c357353 100755 --- a/configure.py +++ b/configure.py @@ -713,7 +713,7 @@ config.libs = [ Object(NonMatching, "MetroidPrime/CNESEmulator.cpp"), Object(NonMatching, "MetroidPrime/Enemies/CPhazonHealingNodule.cpp"), Object(NonMatching, "MetroidPrime/Player/CMorphBallShadow.cpp"), - Object(NonMatching, "MetroidPrime/Player/CPlayerInputFilter.cpp"), + Object(NonMatching, "MetroidPrime/Player/CPlayerStuckTracker.cpp"), Object(NonMatching, "MetroidPrime/CSlideShow.cpp"), Object(Matching, "MetroidPrime/Tweaks/CTweakSlideShow.cpp"), Object(NonMatching, "MetroidPrime/CArtifactDoll.cpp"), diff --git a/include/Collision/CCollidableAABox.hpp b/include/Collision/CCollidableAABox.hpp index 4d516e53..7e6924a3 100644 --- a/include/Collision/CCollidableAABox.hpp +++ b/include/Collision/CCollidableAABox.hpp @@ -23,6 +23,8 @@ public: FourCC GetPrimType() const; CRayCastResult CastRayInternal(const CInternalRayCastStructure&) const; + const CAABox& GetBox() const { return x10_aabb; } + static void SetStaticTableIndex(uint idx); static CCollisionPrimitive::Type GetType(); diff --git a/include/Kyoto/Audio/CSfxManager.hpp b/include/Kyoto/Audio/CSfxManager.hpp index dbdea6fe..ff4310ab 100644 --- a/include/Kyoto/Audio/CSfxManager.hpp +++ b/include/Kyoto/Audio/CSfxManager.hpp @@ -210,7 +210,7 @@ public: static void SetDuration(CSfxHandle handle, float duration); static ushort GetReverbAmount(); - static CSfxHandle SfxStart(ushort id, const short vol = 127, const short pan = 64, + static CSfxHandle SfxStart(const ushort id, const short vol = 127, const short pan = 64, const bool useAcoustics = false, const short prio = kMedPriority, const bool looped = false, const int areaId = kAllAreas); static void SfxStop(CSfxHandle handle); diff --git a/include/Kyoto/Input/CFinalInput.hpp b/include/Kyoto/Input/CFinalInput.hpp index 285d71ac..43a24b25 100644 --- a/include/Kyoto/Input/CFinalInput.hpp +++ b/include/Kyoto/Input/CFinalInput.hpp @@ -91,6 +91,10 @@ public: float AStart() const { return x2d_b27_Start ? 1.f : 0.f; } + float ALeftX() const { return x8_anaLeftX; } + + float ALeftY() const { return xc_anaLeftY; } + bool DLAUp() const { return kInput_AnalogOnThreshhold < xc_anaLeftY ? true : false; } bool DLADown() const { return -kInput_AnalogOnThreshhold > xc_anaLeftY ? true : false; } diff --git a/include/Kyoto/Math/CRelAngle.hpp b/include/Kyoto/Math/CRelAngle.hpp index bdb86f16..d4538059 100644 --- a/include/Kyoto/Math/CRelAngle.hpp +++ b/include/Kyoto/Math/CRelAngle.hpp @@ -40,13 +40,22 @@ private: }; CHECK_SIZEOF(CRelAngle, 0x4) -// __mi__FRC9CRelAngleRC9CRelAngle -// __pl__FRC9CRelAngleRC9CRelAngle -// __dv__FRC9CRelAnglef -// static inline CRelAngle operator/(const CRelAngle& ang, float f) { -// return CRelAngle::FromRadians(ang.AsRadians() / f); -// } -static inline float sine(const CRelAngle& angle) { return sin(angle.AsRadians()); } -static inline float cosine(const CRelAngle& angle) { return cos(angle.AsRadians()); } +inline CRelAngle operator-(const CRelAngle& a, const CRelAngle& b) { + CRelAngle out(a); + out -= b; + return out; +} +inline CRelAngle operator+(const CRelAngle& a, const CRelAngle& b) { + CRelAngle out(a); + out += b; + return out; +} +inline CRelAngle operator/(const CRelAngle& a, float b) { + CRelAngle out(a); + out /= b; + return out; +} +inline float sine(const CRelAngle& angle) { return sin(angle.AsRadians()); } +inline float cosine(const CRelAngle& angle) { return cos(angle.AsRadians()); } #endif // _CRELANGLE diff --git a/include/MetroidPrime/CGameCollision.hpp b/include/MetroidPrime/CGameCollision.hpp index 1e017aa7..e541580f 100644 --- a/include/MetroidPrime/CGameCollision.hpp +++ b/include/MetroidPrime/CGameCollision.hpp @@ -32,9 +32,14 @@ public: TUniqueId&, CCollisionInfo&, double&); static CRayCastResult RayStaticIntersection(const CStateManager&, const CVector3f&, const CVector3f&, float, const CMaterialFilter&); - static CRayCastResult RayDynamicIntersection(const CStateManager& mgr, TUniqueId& idOut, const CVector3f& pos, - const CVector3f& dir, float mag, const CMaterialFilter& filter, + static CRayCastResult RayDynamicIntersection(const CStateManager& mgr, TUniqueId& idOut, + const CVector3f& pos, const CVector3f& dir, + float mag, const CMaterialFilter& filter, const TEntityList& nearList); + static rstl::optional_object< CVector3f > + FindNonIntersectingVector(const CStateManager& mgr, CAreaCollisionCache& cache, + CPhysicsActor& actor, const CCollisionPrimitive& prim, + const TEntityList& nearList); // name? static void Move(CStateManager& mgr, CPhysicsActor& actor, float dt, const TEntityList*); }; diff --git a/include/MetroidPrime/Player/CMorphBall.hpp b/include/MetroidPrime/Player/CMorphBall.hpp index a25e0b02..1c6bc80f 100644 --- a/include/MetroidPrime/Player/CMorphBall.hpp +++ b/include/MetroidPrime/Player/CMorphBall.hpp @@ -127,6 +127,7 @@ public: // ApplyGravity__10CMorphBallFR13CStateManager global void Land(); void ResetMorphBallIceBreak(); + void StopParticleWakes(); private: struct CSpiderBallElectricityManager { diff --git a/include/MetroidPrime/Player/CPlayer.hpp b/include/MetroidPrime/Player/CPlayer.hpp index 1c4367a5..177fa701 100644 --- a/include/MetroidPrime/Player/CPlayer.hpp +++ b/include/MetroidPrime/Player/CPlayer.hpp @@ -10,6 +10,7 @@ #include "MetroidPrime/Player/CPlayerState.hpp" #include "Kyoto/TReservedAverage.hpp" +#include "Kyoto/Math/CRelAngle.hpp" #include "rstl/auto_ptr.hpp" #include "rstl/vector.hpp" @@ -57,15 +58,21 @@ class CPlayer : public CPhysicsActor, public TOneStatic< CPlayer > { bool AffectsThermal() const { return x28_affectsThermal; } }; - class CInputFilter { + class CPlayerStuckTracker { public: - CInputFilter(); - void AddSample(int, const CVector3f&, const CVector3f&, const CVector2f&); - bool Passes(); - void Reset(); + enum EPlayerState { + kPS_Jump, + kPS_StartingJump, + kPS_Moving, + }; + + CPlayerStuckTracker(); + void AddState(EPlayerState, const CVector3f&, const CVector3f&, const CVector2f&); + bool IsPlayerStuck(); + void ResetStats(); private: - rstl::reserved_vector< int, 20 > x0_; + rstl::reserved_vector< EPlayerState, 20 > x0_; rstl::reserved_vector< CVector3f, 20 > x54_; rstl::reserved_vector< CVector3f, 20 > x148_; rstl::reserved_vector< CVector2f, 20 > x23c_; @@ -263,6 +270,7 @@ public: float GetActualFirstPersonMaxVelocity(float dt) const; const CScriptWater* GetVisorRunoffEffect(const CStateManager& mgr) const; void SetMorphBallState(EPlayerMorphBallState state, CStateManager& mgr); + bool CanEnterMorphBallState(CStateManager& mgr, float dt) const; bool CanLeaveMorphBallState(CStateManager& mgr, CVector3f& pos) const; void LeaveMorphBallState(CStateManager& mgr); void EnterMorphBallState(CStateManager& mgr); @@ -292,6 +300,20 @@ public: void ComputeMovement(const CFinalInput& input, CStateManager& mgr, float dt); void ProcessInput(const CFinalInput& input, CStateManager& mgr); void UpdateScanningState(const CFinalInput& input, CStateManager& mgr, float dt); + bool IsUnderBetaMetroidAttack(CStateManager& mgr) const; + void UpdateGrappleState(const CFinalInput& input, CStateManager& mgr); + void ApplyGrappleForces(const CFinalInput& input, CStateManager& mgr, float dt); + void ComputeFreeLook(const CFinalInput& input); + void UpdateOrbitInput(const CFinalInput& input, CStateManager& mgr); + void UpdateOrbitZone(CStateManager& mgr); + void UpdateMorphBallState(float dt, const CFinalInput& input, CStateManager& mgr); + void CalculateLeaveMorphBallDirection(const CFinalInput& input); + void TransitionToMorphBallState(float dt, CStateManager& mgr); + void TransitionFromMorphBallState(float dt, CStateManager& mgr); + float GetMaximumPlayerPositiveVerticalVelocity(const CStateManager& mgr) const; + CVector3f CalculateLeftStickEdgePosition(float strafeInput, float forwardInput) const; + bool AttachActorToPlayer(TUniqueId id, bool disableGun); + void DetachActorFromPlayer(); CPlayerGun* PlayerGun() { return x490_gun.get(); } const CPlayerGun* GetPlayerGun() const { return x490_gun.get(); } @@ -334,6 +356,9 @@ public: float GetAverageSpeed() const; float GetGravity() const; + float GetAttachedActorStruggle() const { return xa28_attachedActorStruggle; } + void SetAttachedActorStruggle(float struggle) { xa28_attachedActorStruggle = struggle; } + // PlayerHint // bool SetAreaPlayerHint(const CScriptPlayerHint& hint, CStateManager& mgr); void AddToPlayerHintRemoveList(TUniqueId id, CStateManager& mgr); @@ -427,7 +452,7 @@ private: float x494_gunAlpha; EGunHolsterState x498_gunHolsterState; float x49c_gunHolsterRemTime; - rstl::single_ptr< CInputFilter > x4a0_inputFilter; + rstl::single_ptr< CPlayerStuckTracker > x4a0_playerStuckTracker; TReservedAverage< float, 20 > x4a4_moveSpeedAvg; float x4f8_moveSpeed; float x4fc_flatMoveSpeed; diff --git a/include/MetroidPrime/Player/CPlayerGun.hpp b/include/MetroidPrime/Player/CPlayerGun.hpp index b10dd5ce..0bca5cd1 100644 --- a/include/MetroidPrime/Player/CPlayerGun.hpp +++ b/include/MetroidPrime/Player/CPlayerGun.hpp @@ -186,6 +186,8 @@ public: CGrappleArm& GetGrappleArm() const { return *x740_grappleArm.get(); } bool IsFidgeting() const { return x833_24_notFidgeting; } + void SetActorAttached(bool attached) { x835_31_actorAttached = attached; } // name? + private: class CGunMorph { public: diff --git a/include/rstl/reserved_vector.hpp b/include/rstl/reserved_vector.hpp index 33195040..6b6d56ed 100644 --- a/include/rstl/reserved_vector.hpp +++ b/include/rstl/reserved_vector.hpp @@ -43,8 +43,9 @@ public: return *this; } void clear() { + T* ptr = data(); for (int i = 0; i < x0_count; ++i) { - destroy(&data()[i]); + destroy(&ptr[i]); } x0_count = 0; } diff --git a/src/Kyoto/Math/CQuaternion.cpp b/src/Kyoto/Math/CQuaternion.cpp index 00556543..d2865a16 100644 --- a/src/Kyoto/Math/CQuaternion.cpp +++ b/src/Kyoto/Math/CQuaternion.cpp @@ -1,5 +1,14 @@ #include "Kyoto/Math/CQuaternion.hpp" +#include "Kyoto/Math/CRelAngle.hpp" +#include "Kyoto/Math/CUnitVector3f.hpp" + +CQuaternion CQuaternion::AxisAngle(const CUnitVector3f& axis, const CRelAngle& angle) { + float w = cosine(angle / 2.f); + CVector3f vec = axis * sine(angle / 2.f); + return CQuaternion(w, vec); +} + CQuaternion CQuaternion::operator*(const CQuaternion& rhs) const { float w = this->w * rhs.w - CVector3f::Dot(imaginary, rhs.imaginary); CVector3f imag = diff --git a/src/MetroidPrime/Player/CPlayer.cpp b/src/MetroidPrime/Player/CPlayer.cpp index ede8ea3b..9818905b 100644 --- a/src/MetroidPrime/Player/CPlayer.cpp +++ b/src/MetroidPrime/Player/CPlayer.cpp @@ -19,8 +19,10 @@ #include "MetroidPrime/SFX/IceCrack.h" #include "MetroidPrime/SFX/LavaWorld.h" #include "MetroidPrime/SFX/MiscSamus.h" +#include "MetroidPrime/SFX/Weapons.h" #include "MetroidPrime/ScriptObjects/CHUDBillboardEffect.hpp" #include "MetroidPrime/ScriptObjects/CScriptWater.hpp" +#include "MetroidPrime/Tweaks/CTweakBall.hpp" #include "MetroidPrime/Tweaks/CTweakPlayer.hpp" #include "MetroidPrime/Tweaks/CTweakPlayerGun.hpp" #include "MetroidPrime/Tweaks/CTweakPlayerRes.hpp" @@ -259,7 +261,7 @@ CPlayer::CPlayer(TUniqueId uid, const CTransform4f& xf, const CAABox& aabb, CAss , x494_gunAlpha(1.f) , x498_gunHolsterState(kGH_Drawn) , x49c_gunHolsterRemTime(gpTweakPlayerGun->x40_gunNotFiringTime) -, x4a0_inputFilter(rs_new CInputFilter()) +, x4a0_playerStuckTracker(rs_new CPlayerStuckTracker()) , x4a4_moveSpeedAvg() , x4f8_moveSpeed(0.f) , x4fc_flatMoveSpeed(0.f) @@ -1763,3 +1765,254 @@ void CPlayer::StartLandingControlFreeze() { x760_controlsFrozen = true; x764_controlsFrozenTimeout = 0.75f; } + +void CPlayer::ProcessInput(const CFinalInput& input, CStateManager& mgr) { + if (input.ControllerNumber() != 0) { + return; + } + + float dt = input.Time(); + if (x2f8_morphBallState != kMS_Morphed) { + UpdateScanningState(input, mgr, dt); + } + + if (mgr.GetGameState() != CStateManager::kGS_Running || !mgr.GetPlayerState()->IsAlive()) { + return; + } + + if (GetFrozenState()) { + UpdateFrozenState(input, mgr); + + if (GetFrozenState()) { + if (x258_movementState != NPlayer::kMS_OnGround && + x258_movementState != NPlayer::kMS_FallingMorphed) { + const CFinalInput dummyInput; + if (x2f8_morphBallState == kMS_Morphed) { + x768_morphball->ComputeBallMovement(dummyInput, mgr, dt); + x768_morphball->UpdateBallDynamics(mgr, dt); + } else { + ComputeMovement(dummyInput, mgr, dt); + } + } + return; + } + } + + if (x760_controlsFrozen) { + UpdateControlLostState(dt, mgr); + return; + } + + if (x2f8_morphBallState == kMS_Unmorphed && x4a0_playerStuckTracker->IsPlayerStuck()) { + const CCollidableAABox* prim = static_cast< const CCollidableAABox* >(GetCollisionPrimitive()); + const CAABox& bounds = prim->GetBox(); + const CCollidableAABox tmpBox(CAABox(bounds.GetMinPoint() - CVector3f(0.2f, 0.2f, 0.2f), + bounds.GetMaxPoint() + CVector3f(0.2f, 0.2f, 0.2f)), + GetCollisionPrimitive()->GetMaterial()); + CPhysicsActor::Stop(); + const CAABox testBounds = bounds.GetTransformedAABox(GetTransform()); + const CAABox expandedBounds = CAABox(testBounds.GetMinPoint() - CVector3f(3.f, 3.f, 3.f), + testBounds.GetMaxPoint() + CVector3f(3.f, 3.f, 3.f)); + CAreaCollisionCache cache(expandedBounds); + CGameCollision::BuildAreaCollisionCache(mgr, cache); + TEntityList nearList; + mgr.BuildColliderList(nearList, *this, expandedBounds); + const rstl::optional_object< CVector3f > nonIntVec = + CGameCollision::FindNonIntersectingVector(mgr, cache, *this, tmpBox, nearList); + if (nonIntVec) { + x4a0_playerStuckTracker->ResetStats(); + SetTranslation(GetTranslation() + *nonIntVec); + } + } + + UpdateGrappleState(input, mgr); + if (x2f8_morphBallState == kMS_Morphed) { + float leftDiv = gpTweakBall->GetLeftStickDivisor(); + const float rightDiv = gpTweakBall->GetRightStickDivisor(); + if (x26c_attachedActor != kInvalidUniqueId || IsUnderBetaMetroidAttack(mgr)) { + leftDiv = 2.f; + } + const CFinalInput scaledInput = input.ScaleAnalogueSticks(leftDiv, rightDiv); + x768_morphball->ComputeBallMovement(scaledInput, mgr, dt); + x768_morphball->UpdateBallDynamics(mgr, dt); + x4a0_playerStuckTracker->ResetStats(); + } else { + if (x304_orbitState == CPlayer::kOS_Grapple) { + ApplyGrappleForces(input, mgr, dt); + } else { + const CFinalInput scaledInput = + input.ScaleAnalogueSticks(IsUnderBetaMetroidAttack(mgr) ? 3.f : 1.f, 1.f); + ComputeMovement(scaledInput, mgr, dt); + } + + if (ShouldSampleFailsafe(mgr)) { + CPlayerStuckTracker::EPlayerState playerState = CPlayerStuckTracker::kPS_Moving; + if (x258_movementState == NPlayer::kMS_ApplyJump) { + playerState = CPlayerStuckTracker::kPS_StartingJump; + } else if (x258_movementState == NPlayer::kMS_Jump) { + playerState = CPlayerStuckTracker::kPS_Jump; + } + x4a0_playerStuckTracker->AddState(playerState, GetTranslation(), GetVelocityWR(), + CVector2f(input.ALeftX(), input.ALeftY())); + } + } + + ComputeFreeLook(input); + UpdateFreeLookState(input, dt, mgr); + UpdateOrbitInput(input, mgr); + UpdateOrbitZone(mgr); + UpdateGunState(input, mgr); + UpdateVisorState(input, dt, mgr); + + if (x2f8_morphBallState == kMS_Morphed || + (x2f8_morphBallState == kMS_Unmorphed && x498_gunHolsterState == kGH_Drawn)) { + x490_gun->ProcessInput(input, mgr); + if (x2f8_morphBallState == kMS_Morphed && x26c_attachedActor != kInvalidUniqueId) { + bool turnLeft = ControlMapper::GetPressInput(ControlMapper::kC_TurnLeft, input); + bool turnRight = ControlMapper::GetPressInput(ControlMapper::kC_TurnRight, input); + bool forward = ControlMapper::GetPressInput(ControlMapper::kC_Forward, input); + bool backward = ControlMapper::GetPressInput(ControlMapper::kC_Backward, input); + bool jump = ControlMapper::GetPressInput(ControlMapper::kC_JumpOrBoost, input); + if (turnLeft || turnRight || forward || backward || jump) { + float tmp = 600.0f * dt; + xa28_attachedActorStruggle += dt * tmp; + if (xa28_attachedActorStruggle > 1.f) { + xa28_attachedActorStruggle = 1.f; + } + } else { + float tmp = 7.5f * dt; + tmp = rstl::min_val(xa28_attachedActorStruggle * tmp + tmp, 1.f); + xa28_attachedActorStruggle -= dt * tmp; + if (xa28_attachedActorStruggle < 0.f) { + xa28_attachedActorStruggle = 0.f; + } + } + } + } + + UpdateCameraState(mgr); + UpdateMorphBallState(dt, input, mgr); + UpdateCameraTimers(dt, input); + UpdateFootstepSounds(input, mgr, dt); + x2a8_timeSinceJump += dt; + + if (CheckSubmerged()) { + SetSoundEventPitchBend(0); + } else { + SetSoundEventPitchBend(8192); + } + + CalculateLeaveMorphBallDirection(input); +} + +void CPlayer::UpdateMorphBallState(float dt, const CFinalInput& input, CStateManager& mgr) { + if (!ControlMapper::GetPressInput(ControlMapper::kC_Morph, input)) { + return; + } + + switch (x2f8_morphBallState) { + case kMS_Unmorphed: + if (mgr.GetPlayerState()->HasPowerUp(CPlayerState::kIT_MorphBall) == true && + CanEnterMorphBallState(mgr, 0.f)) { + x574_morphTime = 0.f; + x578_morphDuration = 1.f; + TransitionToMorphBallState(dt, mgr); + } else { + DoSfxEffects(CSfxManager::SfxStart(SFXwpn_invalid_action, 127, 64, true)); + } + break; + case kMS_Morphing: + break; + case kMS_Morphed: { + CVector3f posDelta = CVector3f::Zero(); + if (CanLeaveMorphBallState(mgr, posDelta)) { + SetTranslation(GetTranslation() + posDelta); + x574_morphTime = 0.f; + x578_morphDuration = 1.f; + TransitionFromMorphBallState(dt, mgr); + } else { + DoSfxEffects(CSfxManager::SfxStart(SFXwpn_invalid_action, 127, 64, true)); + } + break; + } + case kMS_Unmorphing: + break; + } +} + +float CPlayer::GetMaximumPlayerPositiveVerticalVelocity(const CStateManager& mgr) const { + return mgr.GetPlayerState()->GetItemAmount(CPlayerState::kIT_SpaceJumpBoots) ? 14.f : 11.666666f; +} + +CVector3f CPlayer::CalculateLeftStickEdgePosition(float strafeInput, float forwardInput) const { + float f31 = -1.f; + float f30 = -0.555f; + float f29 = 0.555f; + + if (strafeInput >= 0.f) { + f31 = -f31; + f30 = -f30; + } + + if (forwardInput < 0.f) { + f29 = -f29; + } + + float f1 = CMath::ArcTangentR(fabsf(forwardInput) / fabsf(strafeInput)); + float f4 = CMath::Limit(f1 / (M_PIF / 4.f), 1.f); + return CVector3f(f31, 0.f, 0.f) + + CVector3f(f4, f4, f4) * (CVector3f(f30, f29, 0.f) - CVector3f(f31, 0.f, 0.f)); +} + +bool CPlayer::AttachActorToPlayer(TUniqueId id, bool disableGun) { + if (x26c_attachedActor == kInvalidUniqueId) { + if (disableGun) { + x490_gun->SetActorAttached(true); + } + x26c_attachedActor = id; + x270_attachedActorTime = 0.f; + xa28_attachedActorStruggle = 0.f; + x768_morphball->StopParticleWakes(); + return true; + } + return false; +} + +void CPlayer::DetachActorFromPlayer() { + x26c_attachedActor = kInvalidUniqueId; + x270_attachedActorTime = 0.f; + xa28_attachedActorStruggle = 0.f; + x490_gun->SetActorAttached(false); +} + +void CPlayer::UpdateFreeLook(float dt) { + if (GetFrozenState()) { + return; + } + + float lookDeltaAngle = dt * gpTweakPlayer->GetFreeLookSpeed(); + if (!x3de_lookAnalogHeld) { + lookDeltaAngle = dt * gpTweakPlayer->GetFreeLookSnapSpeed(); + } + + float angleVelP = x3f0_vertFreeLookAngleVel - x3ec_freeLookPitchAngle; + float vertLookDamp = CMath::Clamp(0.f, fabsf(angleVelP / 1.0471976f), 1.f); + float dx = lookDeltaAngle * (2.f * vertLookDamp - sinf((M_PIF / 2.f) * vertLookDamp)); + if (0.f <= angleVelP) { + x3ec_freeLookPitchAngle += dx; + } else { + x3ec_freeLookPitchAngle -= dx; + } + + angleVelP = x3e8_horizFreeLookAngleVel - x3e4_freeLookYawAngle; + dx = lookDeltaAngle * CMath::Clamp(0.f, fabsf(angleVelP / gpTweakPlayer->GetHorizontalFreeLookAngleVel()), 1.f); + if (0.f <= angleVelP) { + x3e4_freeLookYawAngle += dx; + } else { + x3e4_freeLookYawAngle -= dx; + } + + if (gpTweakPlayer->GetFreeLookTurnsPlayer()) { + x3e4_freeLookYawAngle = 0.f; + } +} diff --git a/src/MetroidPrime/Player/CPlayerInputFilter.cpp b/src/MetroidPrime/Player/CPlayerStuckTracker.cpp similarity index 81% rename from src/MetroidPrime/Player/CPlayerInputFilter.cpp rename to src/MetroidPrime/Player/CPlayerStuckTracker.cpp index f753a51a..2d8c41b9 100644 --- a/src/MetroidPrime/Player/CPlayerInputFilter.cpp +++ b/src/MetroidPrime/Player/CPlayerStuckTracker.cpp @@ -1,13 +1,14 @@ -#include "Kyoto/Math/CVector3f.hpp" #include "MetroidPrime/Player/CPlayer.hpp" -#include "dolphin/hw_regs.h" + +#include "Kyoto/Math/CVector3f.hpp" + #include "rstl/optional_object.hpp" #include "rstl/reserved_vector.hpp" -CPlayer::CInputFilter::CInputFilter() {} +CPlayer::CPlayerStuckTracker::CPlayerStuckTracker() {} -void CPlayer::CInputFilter::AddSample(int a, const CVector3f& b, const CVector3f& c, - const CVector2f& d) { +void CPlayer::CPlayerStuckTracker::AddState(EPlayerState a, const CVector3f& b, const CVector3f& c, + const CVector2f& d) { x0_.push_back(a); x54_.push_back(b); x148_.push_back(c); @@ -46,7 +47,7 @@ rstl::optional_object< int > _getElementBoundsCheck(const rstl::reserved_vector< return v[idx]; } -bool CPlayer::CInputFilter::Passes() { +bool CPlayer::CPlayerStuckTracker::IsPlayerStuck() { if (x0_.size() != 14) { return false; } @@ -56,7 +57,8 @@ bool CPlayer::CInputFilter::Passes() { CAABox box1(min1, max1); CAABox box(*_getElementBoundsCheck(x148_, 0), *_getElementBoundsCheck(x148_, 0)); } -void CPlayer::CInputFilter::Reset() { + +void CPlayer::CPlayerStuckTracker::ResetStats() { x0_.clear(); x54_.clear(); x148_.clear();