From 3a933dcd24ecd317d309dd74284d3fb8e56f1516 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sat, 28 Sep 2024 13:43:23 -0600 Subject: [PATCH] CPlayer progress --- config/GM8E01_00/symbols.txt | 6 +- config/GM8E01_01/symbols.txt | 6 +- include/Kyoto/Basics/CCast.hpp | 11 + include/Kyoto/Math/CQuaternion.hpp | 2 +- include/MetroidPrime/CActor.hpp | 3 + include/MetroidPrime/CPhysicsActor.hpp | 5 +- .../MetroidPrime/Cameras/CCameraManager.hpp | 2 +- include/MetroidPrime/Player/CPlayer.hpp | 21 +- .../ScriptObjects/CScriptWater.hpp | 10 +- include/dolphin/os/OSFastCast.h | 1 + src/MetroidPrime/Cameras/CBallCamera.cpp | 2 +- src/MetroidPrime/Player/CPlayer.cpp | 335 +++++++++++++++++- 12 files changed, 389 insertions(+), 15 deletions(-) diff --git a/config/GM8E01_00/symbols.txt b/config/GM8E01_00/symbols.txt index ce87e4bd..667df2ea 100644 --- a/config/GM8E01_00/symbols.txt +++ b/config/GM8E01_00/symbols.txt @@ -377,11 +377,11 @@ UpdateCameraState__7CPlayerFR13CStateManager = .text:0x800173F4; // type:functio UpdateCinematicState__7CPlayerFR13CStateManager = .text:0x80017414; // type:function size:0x258 scope:global SetSpawnedMorphBallState__7CPlayerFQ27CPlayer21EPlayerMorphBallStateR13CStateManager = .text:0x8001766C; // type:function size:0x178 scope:global SetMorphBallState__7CPlayerFQ27CPlayer21EPlayerMorphBallStateR13CStateManager = .text:0x800177E4; // type:function size:0x27C scope:global -GetVisorRunoffEffect__FRC7CPlayerRC13CStateManager = .text:0x80017A60; // type:function size:0x54 scope:global +GetVisorRunoffEffect__7CPlayerCFRC13CStateManager = .text:0x80017A60; // type:function size:0x54 scope:global SetVisorSteam__7CPlayerFfffUib = .text:0x80017AB4; // type:function size:0x24 scope:global SetSteam__Q27CPlayer11CVisorSteamFfffUib = .text:0x80017AD8; // type:function size:0x34 scope:global Update__Q27CPlayer11CVisorSteamFf = .text:0x80017B0C; // type:function size:0x1A8 scope:global -__ct__Q27CPlayer11CVisorSteamFv = .text:0x80017CB4; // type:function size:0x3C scope:global +__ct__Q27CPlayer11CVisorSteamFfffUi = .text:0x80017CB4; // type:function size:0x3C scope:global UpdateFootstepSounds__7CPlayerFRC11CFinalInputR13CStateManagerf = .text:0x80017CF0; // type:function size:0x444 scope:global GetMaterialSoundUnderPlayer__7CPlayerFR13CStateManagerPCUsiUs = .text:0x80018134; // type:function size:0x270 scope:global SfxIdFromMaterial__7CPlayerFRC13CMaterialListPCUsiUs = .text:0x800183A4; // type:function size:0x94 scope:global @@ -389,7 +389,7 @@ UpdatePlayerSounds__7CPlayerFf = .text:0x80018438; // type:function size:0x68 sc UpdateCrosshairsState__7CPlayerFRC11CFinalInput = .text:0x800184A0; // type:function size:0x3C scope:global UpdateVisorTransition__7CPlayerFfR13CStateManager = .text:0x800184DC; // type:function size:0x54 scope:global UpdateVisorState__7CPlayerFRC11CFinalInputfR13CStateManager = .text:0x80018530; // type:function size:0x1B4 scope:global -ShouldSampleFailsafe__7CPlayerCFv = .text:0x800186E4; // type:function size:0x8C scope:global +ShouldSampleFailsafe__7CPlayerCFR13CStateManager = .text:0x800186E4; // type:function size:0x8C scope:global Update__7CPlayerFfR13CStateManager = .text:0x80018770; // type:function size:0x61C scope:global __ct__10CModelDataFRC10CModelData = .text:0x80018D8C; // type:function size:0x13C scope:global ForceGunOrientation__7CPlayerFRC12CTransform4fR13CStateManager = .text:0x80018EC8; // type:function size:0x8C scope:global diff --git a/config/GM8E01_01/symbols.txt b/config/GM8E01_01/symbols.txt index bd13514d..03a4c3a5 100644 --- a/config/GM8E01_01/symbols.txt +++ b/config/GM8E01_01/symbols.txt @@ -377,11 +377,11 @@ UpdateCameraState__7CPlayerFR13CStateManager = .text:0x80017470; // type:functio UpdateCinematicState__7CPlayerFR13CStateManager = .text:0x80017490; // type:function size:0x258 scope:global SetSpawnedMorphBallState__7CPlayerFQ27CPlayer21EPlayerMorphBallStateR13CStateManager = .text:0x800176E8; // type:function size:0x178 scope:global SetMorphBallState__7CPlayerFQ27CPlayer21EPlayerMorphBallStateR13CStateManager = .text:0x80017860; // type:function size:0x27C scope:global -GetVisorRunoffEffect__FRC7CPlayerRC13CStateManager = .text:0x80017ADC; // type:function size:0x54 scope:global +GetVisorRunoffEffect__7CPlayerCFRC13CStateManager = .text:0x80017ADC; // type:function size:0x54 scope:global SetVisorSteam__7CPlayerFfffUib = .text:0x80017B30; // type:function size:0x24 scope:global SetSteam__Q27CPlayer11CVisorSteamFfffUib = .text:0x80017B54; // type:function size:0x34 scope:global Update__Q27CPlayer11CVisorSteamFf = .text:0x80017B88; // type:function size:0x1A8 scope:global -__ct__Q27CPlayer11CVisorSteamFv = .text:0x80017D30; // type:function size:0x3C scope:global +__ct__Q27CPlayer11CVisorSteamFfffUi = .text:0x80017D30; // type:function size:0x3C scope:global UpdateFootstepSounds__7CPlayerFRC11CFinalInputR13CStateManagerf = .text:0x80017D6C; // type:function size:0x444 scope:global GetMaterialSoundUnderPlayer__7CPlayerFR13CStateManagerPCUsiUs = .text:0x800181B0; // type:function size:0x270 scope:global SfxIdFromMaterial__7CPlayerFRC13CMaterialListPCUsiUs = .text:0x80018420; // type:function size:0x94 scope:global @@ -389,7 +389,7 @@ UpdatePlayerSounds__7CPlayerFf = .text:0x800184B4; // type:function size:0x68 sc UpdateCrosshairsState__7CPlayerFRC11CFinalInput = .text:0x8001851C; // type:function size:0x3C scope:global UpdateVisorTransition__7CPlayerFfR13CStateManager = .text:0x80018558; // type:function size:0x54 scope:global UpdateVisorState__7CPlayerFRC11CFinalInputfR13CStateManager = .text:0x800185AC; // type:function size:0x1B4 scope:global -ShouldSampleFailsafe__7CPlayerCFv = .text:0x80018760; // type:function size:0x8C scope:global +ShouldSampleFailsafe__7CPlayerCFR13CStateManager = .text:0x80018760; // type:function size:0x8C scope:global Update__7CPlayerFfR13CStateManager = .text:0x800187EC; // type:function size:0x61C scope:global __ct__10CModelDataFRC10CModelData = .text:0x80018E08; // type:function size:0x13C scope:global ForceGunOrientation__7CPlayerFRC12CTransform4fR13CStateManager = .text:0x80018F44; // type:function size:0x8C scope:global diff --git a/include/Kyoto/Basics/CCast.hpp b/include/Kyoto/Basics/CCast.hpp index 211a57d7..adc54d7f 100644 --- a/include/Kyoto/Basics/CCast.hpp +++ b/include/Kyoto/Basics/CCast.hpp @@ -17,6 +17,16 @@ inline uchar ToUint8(register float in) { return *ptr; } +inline char ToInt8(register float in) { + char a; + register char* ptr = &a; + + asm { + psq_st in, 0(ptr), 1, OS_FASTCAST_S8 + } + return *ptr; +} + inline float ToReal32(register const uchar& in) { register float r; asm { @@ -47,6 +57,7 @@ inline ushort FtoUS(register float in) { #else inline uchar ToUint8(float in) { return static_cast< uchar >(in); } +inline char ToInt8(float in) { return static_cast< char >(in); } inline float ToReal32(uchar in) { return static_cast< float >(in); } inline short FtoS(float in) { return static_cast< short >(in); } inline ushort FtoUS(float in) { return static_cast< ushort >(in); } diff --git a/include/Kyoto/Math/CQuaternion.hpp b/include/Kyoto/Math/CQuaternion.hpp index 5aa924b7..68d60f14 100644 --- a/include/Kyoto/Math/CQuaternion.hpp +++ b/include/Kyoto/Math/CQuaternion.hpp @@ -13,7 +13,7 @@ class CNUQuaternion; class CQuaternion { public: CQuaternion(float w, float x, float y, float z) : w(w), imaginary(x, y, z) {} - // __ct__11CQuaternionFfRC9CVector3f + CQuaternion(float w, const CVector3f& imaginary) : w(w), imaginary(imaginary) {} // CQuaternion(const CQuaternion& other) // : w(other.w) diff --git a/include/MetroidPrime/CActor.hpp b/include/MetroidPrime/CActor.hpp index 546240b7..57d5a467 100644 --- a/include/MetroidPrime/CActor.hpp +++ b/include/MetroidPrime/CActor.hpp @@ -156,6 +156,8 @@ public: const CMaterialFilter& GetMaterialFilter() const; void SetMaterialFilter(const CMaterialFilter& filter); + TUniqueId InFluidId() const { return xc4_fluidId; } + bool GetTransformDirty() const { return xe4_27_notInSortedLists; } bool GetTransformDirtySpare() const { return xe4_28_transformDirty; } bool GetPreRenderHasMoved() const { return xe4_29_actorLightsDirty; } @@ -164,6 +166,7 @@ public: bool GetDrawShadow() const { return xe5_24_shadowEnabled; } bool GetShadowDirty() const { return xe5_25_shadowDirty; } bool GetMuted() const { return xe5_26_muted; } + bool IsInFluid() const { return xe6_24_fluidCounter != 0; } EThermalFlags GetThermalFlags() const { return static_cast< EThermalFlags >(xe6_27_thermalVisorFlags); } diff --git a/include/MetroidPrime/CPhysicsActor.hpp b/include/MetroidPrime/CPhysicsActor.hpp index bb306c10..2f26b910 100644 --- a/include/MetroidPrime/CPhysicsActor.hpp +++ b/include/MetroidPrime/CPhysicsActor.hpp @@ -111,12 +111,15 @@ public: void Stop(); CVector3f GetPrimitiveOffset() const; + uchar IsStandardCollider() const { return xf9_standardCollider; } // name and type? + void SetStandardCollider(uchar v) { xf9_standardCollider = v; } // name and type? const CVector3f& GetConstantForceWR() const { return xfc_constantForce; } void SetConstantForceWR(const CVector3f& force) { xfc_constantForce = force; } const CAxisAngle& GetAngularMomentumWR() const { return x108_angularMomentum; } void SetAngularMomentumWR(const CAxisAngle& angularMomentum) { x108_angularMomentum = angularMomentum; } + const CVector3f& GetVelocityWR() const { return x138_velocity; } const CVector3f& GetMomentumWR() const { return x150_momentum; } void SetMomentumWR(const CVector3f& momentum) { x150_momentum = momentum; } const CVector3f& GetForceWR() const { return x15c_force; } @@ -174,7 +177,7 @@ private: float xf4_inertiaTensorRecip; bool xf8_24_movable : 1; bool xf8_25_angularEnabled : 1; - bool xf9_standardCollider; + uchar xf9_standardCollider; CVector3f xfc_constantForce; CAxisAngle x108_angularMomentum; CMatrix3f x114_; diff --git a/include/MetroidPrime/Cameras/CCameraManager.hpp b/include/MetroidPrime/Cameras/CCameraManager.hpp index 8004d705..42b7b4d8 100644 --- a/include/MetroidPrime/Cameras/CCameraManager.hpp +++ b/include/MetroidPrime/Cameras/CCameraManager.hpp @@ -92,7 +92,7 @@ public: int GetFluidCounter() const { return x74_fluidCounter; } TUniqueId GetFluidId() const { return x78_fluidId; } - // GetInsideFluid__14CCameraManagerCFv + bool GetInsideFluid() const { return x74_fluidCounter == 0; } bool IsInsideFluid() const { return xa0_26_inWater; } // WasInsideFluid__14CCameraManagerCFv // SetWasInsideFluid__14CCameraManagerFb diff --git a/include/MetroidPrime/Player/CPlayer.hpp b/include/MetroidPrime/Player/CPlayer.hpp index e01df554..150f59e2 100644 --- a/include/MetroidPrime/Player/CPlayer.hpp +++ b/include/MetroidPrime/Player/CPlayer.hpp @@ -59,6 +59,7 @@ class CPlayer : public CPhysicsActor, public TOneStatic< CPlayer > { bool x28_affectsThermal; public: + CVisorSteam(); CVisorSteam(float targetAlpha, float alphaInDur, float alphaOutDur, CAssetId tex); // : x0_curTargetAlpha(targetAlpha) // , x4_curAlphaInDur(alphaInDur) @@ -237,7 +238,6 @@ public: void ForceGunOrientation(const CTransform4f& xf, CStateManager& mgr); void Update(float dt, CStateManager& mgr); void UpdateMorphBallTransition(float dt, CStateManager& mgr); - void ApplySubmergedPitchBend(CSfxHandle sfx); void UpdateAimTarget(CStateManager& mgr); void UpdateAimTargetTimer(float dt); void UpdateOrbitModeTimer(float dt); @@ -245,9 +245,21 @@ public: void UpdateGunAlpha(); void UpdateVisorTransition(float dt, CStateManager& mgr); void UpdatePlayerSounds(float dt); - bool ShouldSampleFailsafe(CStateManager& mgr); + bool ShouldSampleFailsafe(CStateManager& mgr) const; bool IsEnergyLow(CStateManager& mgr); bool StartSamusVoiceSfx(ushort sfx, short vol, int prio); + void UpdateVisorState(const CFinalInput& input, float dt, CStateManager& mgr); + void UpdateCrosshairsState(const CFinalInput& input); + ushort GetMaterialSoundUnderPlayer(CStateManager& mgr, const ushort* table, int length, + ushort defId); + void UpdateFootstepSounds(const CFinalInput& input, CStateManager& mgr, float dt); + float JumpInput(const CFinalInput& input, CStateManager& mgr); + float TurnInput(const CFinalInput& input) const; + float StrafeInput(const CFinalInput& input) const; + float ForwardInput(const CFinalInput& input, float turnInput) const; + float GetActualFirstPersonMaxVelocity(float dt) const; + const CScriptWater* GetVisorRunoffEffect(const CStateManager& mgr) const; + void SetMorphBallState(EPlayerMorphBallState state, CStateManager& mgr); CPlayerGun* PlayerGun() { return x490_gun.get(); } const CPlayerGun* GetPlayerGun() const { return x490_gun.get(); } @@ -276,6 +288,8 @@ public: NPlayer::EPlayerMovementState GetPlayerMovementState() const { return x258_movementState; } const CVector3f& GetAssistedTargetAim() const { return x480_assistedTargetAim; } + bool IsInsideFluid() const { return x9c4_31_inWaterMovement; } + void Teleport(const CTransform4f& xf, CStateManager& mgr, bool resetBallCam); void SetSpawnedMorphBallState(EPlayerMorphBallState state, CStateManager& mgr); const CVisorSteam& GetVisorSteam() const { return x7a0_visorSteam; } @@ -293,6 +307,9 @@ public: // void DeactivatePlayerHint(TUniqueId id, CStateManager& mgr); // void UpdatePlayerHints(CStateManager& mgr); + static int SfxIdFromMaterial(const CMaterialList& mat, const ushort* idList, int tableLen, + ushort defId); + private: NPlayer::EPlayerMovementState x258_movementState; rstl::vector< CToken > x25c_ballTransitionsRes; diff --git a/include/MetroidPrime/ScriptObjects/CScriptWater.hpp b/include/MetroidPrime/ScriptObjects/CScriptWater.hpp index e82c3a02..6a5466fa 100644 --- a/include/MetroidPrime/ScriptObjects/CScriptWater.hpp +++ b/include/MetroidPrime/ScriptObjects/CScriptWater.hpp @@ -61,7 +61,15 @@ public: // GetWRSurfacePlane__12CScriptWaterCFv float GetSurfaceZ() const { return GetTriggerBoundsWR().GetMaxPoint().GetZ(); } const CColor& GetUnderwaterFogColor() const { return x2a8_insideFogColor; } - // GetVisorRunoffEffect__12CScriptWaterCFv + const rstl::optional_object< TLockedToken< CGenDescription > >& GetVisorRunoffEffect() const { + return x23c_visorRunoffEffect; + } + ushort GetVisorRunoffSfx() const { return x260_visorRunoffSfx; } + const rstl::optional_object< TLockedToken< CGenDescription > >& + GetUnmorphVisorRunoffEffect() const { + return x250_unmorphVisorRunoffEffect; + } + ushort GetUnmorphVisorRunoffSfx() const { return x262_unmorphVisorRunoffSfx; } // GetFluidType__12CScriptWaterCFv // IsMorphing__12CScriptWaterCFv // SetMorphing__12CScriptWaterFb diff --git a/include/dolphin/os/OSFastCast.h b/include/dolphin/os/OSFastCast.h index b6ca50d1..c64b5f9a 100644 --- a/include/dolphin/os/OSFastCast.h +++ b/include/dolphin/os/OSFastCast.h @@ -13,6 +13,7 @@ extern "C" { #define OS_FASTCAST_U8 2 #define OS_FASTCAST_U16 3 +#define OS_FASTCAST_S8 4 #define OS_FASTCAST_S16 5 // clang-format off static inline void OSInitFastCast(void) { diff --git a/src/MetroidPrime/Cameras/CBallCamera.cpp b/src/MetroidPrime/Cameras/CBallCamera.cpp index be95d8f4..078770f8 100644 --- a/src/MetroidPrime/Cameras/CBallCamera.cpp +++ b/src/MetroidPrime/Cameras/CBallCamera.cpp @@ -342,7 +342,7 @@ void CBallCamera::UpdateColliders(const CTransform4f& xf, } colliderList[idx].SetRealPosition(worldPos); colliderList[idx].SetPosition(localPos); - CVector3f scaledWorldColliderPos = centerToCollider * mag / tolerance; + CVector3f scaledWorldColliderPos = centerToCollider * mag / tolerance; scaledWorldColliderPos *= x308_speedFactor; scaledWorldColliderPos += x31c_predictedLookPos; colliderList[idx].SetLookAtPosition(scaledWorldColliderPos); diff --git a/src/MetroidPrime/Player/CPlayer.cpp b/src/MetroidPrime/Player/CPlayer.cpp index 2571e5f9..119a1d7a 100644 --- a/src/MetroidPrime/Player/CPlayer.cpp +++ b/src/MetroidPrime/Player/CPlayer.cpp @@ -4,6 +4,7 @@ #include "MetroidPrime/CControlMapper.hpp" #include "MetroidPrime/CWorld.hpp" #include "MetroidPrime/Cameras/CCameraManager.hpp" +#include "MetroidPrime/Cameras/CCinematicCamera.hpp" #include "MetroidPrime/Cameras/CFirstPersonCamera.hpp" #include "MetroidPrime/Player/CGrappleArm.hpp" #include "MetroidPrime/Player/CMorphBall.hpp" @@ -11,13 +12,17 @@ #include "MetroidPrime/Player/CPlayerGun.hpp" #include "MetroidPrime/SFX/LavaWorld.h" #include "MetroidPrime/SFX/MiscSamus.h" +#include "MetroidPrime/ScriptObjects/CHUDBillboardEffect.hpp" +#include "MetroidPrime/ScriptObjects/CScriptWater.hpp" #include "MetroidPrime/Tweaks/CTweakPlayer.hpp" #include "MetroidPrime/Tweaks/CTweakPlayerGun.hpp" #include "MetroidPrime/Tweaks/CTweakPlayerRes.hpp" #include "Kyoto/Audio/CSfxManager.hpp" #include "Kyoto/Audio/CStreamAudioManager.hpp" +#include "Kyoto/CSimplePool.hpp" #include "Kyoto/Math/CRelAngle.hpp" +#include "Kyoto/Math/CloseEnough.hpp" #include "Collision/CCollisionInfo.hpp" #include "Collision/CRayCastResult.hpp" @@ -731,7 +736,7 @@ void CPlayer::Update(float dt, CStateManager& mgr) { CSfxManager::KillAll(CSfxManager::kSC_Game); CStreamAudioManager::StopAll(); if (x2f8_morphBallState == kMS_Unmorphed) { - ApplySubmergedPitchBend(CSfxManager::SfxStart(SFXsam_death)); + DoSfxEffects(CSfxManager::SfxStart(SFXsam_death)); } } @@ -742,7 +747,7 @@ void CPlayer::Update(float dt, CStateManager& mgr) { xa00_deathPowerBomb = x490_gun->DropPowerBomb(mgr); } if (x9f4_deathTime >= 4.f && prevDeathTime < 4.f) { - ApplySubmergedPitchBend(CSfxManager::SfxStart(SFXsam_death)); + DoSfxEffects(CSfxManager::SfxStart(SFXsam_death)); } } } @@ -803,3 +808,329 @@ void CPlayer::Update(float dt, CStateManager& mgr) { xa30_samusExhaustedVoiceTimer = 4.f; } } + +// TODO nonmatching +bool CPlayer::ShouldSampleFailsafe(CStateManager& mgr) const { + const CCinematicCamera* cineCam = + TCastToConstPtr< CCinematicCamera >(mgr.GetCameraManager()->GetCurrentCamera(mgr)); + if (!mgr.GetPlayerState()->IsAlive() || + (x2f4_cameraState == kCS_Spawned && cineCam && (cineCam->GetFlags() & 0x80) != 0)) { + return false; + } + return true; +} + +void CPlayer::UpdateVisorState(const CFinalInput& input, float dt, CStateManager& mgr) { + x7a0_visorSteam.Update(dt); + if (x7a0_visorSteam.AffectsThermal()) { + mgr.SetThermalColdScale2(mgr.GetThermalColdScale2() + x7a0_visorSteam.GetAlpha()); + } + + CPlayerState* playerState = mgr.PlayerState(); + const CScriptGrapplePoint* grapplePoint = + TCastToConstPtr< CScriptGrapplePoint >(mgr.GetObjectById(x310_orbitTargetId)); + if (GetOrbitState() != CPlayer::kOS_Grapple && !grapplePoint && + GetMorphballTransitionState() == kMS_Unmorphed && !playerState->GetIsVisorTransitioning() && + x3a8_scanState == kSS_NotScanning) { + + if (playerState->GetTransitioningVisor() == CPlayerState::kPV_Scan && + (ControlMapper::GetDigitalInput(ControlMapper::kC_FireOrBomb, input) || + ControlMapper::GetDigitalInput(ControlMapper::kC_MissileOrPowerBomb, input)) && + playerState->HasPowerUp(CPlayerState::kIT_CombatVisor)) { + playerState->StartTransitionToVisor(CPlayerState::kPV_Combat); + DrawGun(mgr); + } + + for (int i = 0; i < ARRAY_SIZE(skVisorToItemMapping); ++i) { + const TVisorToItemMapping& mapping = skVisorToItemMapping[i]; + + if (playerState->HasPowerUp(mapping.first) && + ControlMapper::GetPressInput(mapping.second, input)) { + x9c4_24_visorChangeRequested = true; + + CPlayerState::EPlayerVisor visor = static_cast< CPlayerState::EPlayerVisor >(i); + if (playerState->GetTransitioningVisor() != visor) { + playerState->StartTransitionToVisor(visor); + if (visor == CPlayerState::kPV_Scan) { + HolsterGun(mgr); + } else { + DrawGun(mgr); + } + } + } + } + } +} + +void CPlayer::UpdateVisorTransition(float dt, CStateManager& mgr) { + CPlayerState* playerState = mgr.PlayerState(); + if (playerState->GetIsVisorTransitioning()) { + playerState->UpdateVisorTransition(dt); + } +} + +void CPlayer::UpdateCrosshairsState(const CFinalInput& input) { + x9c4_25_showCrosshairs = ControlMapper::GetDigitalInput(ControlMapper::kC_ShowCrosshairs, input); +} + +void CPlayer::UpdatePlayerSounds(float dt) { + if (x784_damageSfxTimer > 0.f) { + x784_damageSfxTimer -= dt; + if (x784_damageSfxTimer <= 0.f) { + CSfxManager::SfxStop(x770_damageLoopSfx); + x770_damageLoopSfx.Clear(); + } + } +} + +int CPlayer::SfxIdFromMaterial(const CMaterialList& mat, const ushort* idList, int tableLen, + ushort defId) { + int id = defId; + for (short i = 0; i < tableLen; ++i) { + if (mat.HasMaterial(static_cast< EMaterialTypes >(i)) && idList[i] != 0xFFFF) { + id = idList[i]; + } + } + // Odd issue with return value, should be ushort + return ushort(id); +} + +ushort CPlayer::GetMaterialSoundUnderPlayer(CStateManager& mgr, const ushort* table, int length, + ushort defId) { + int ret = defId; + static const CVector3f skDown(0.f, 0.f, -1.f); + static const CMaterialFilter matFilter = CMaterialFilter::MakeInclude(CMaterialList(kMT_Solid)); + + TUniqueId collideId = kInvalidUniqueId; + TEntityList nearList; + CAABox aabb = GetBoundingBox(); + aabb.AccumulateBounds(GetTranslation() + skDown); + mgr.BuildNearList(nearList, aabb, matFilter, nullptr); + const CRayCastResult result = + mgr.RayWorldIntersection(collideId, GetTranslation(), skDown, 1.5f, matFilter, nearList); + if (result.IsValid()) { + ret = SfxIdFromMaterial(result.GetMaterial(), table, length, defId); + } + return ret; +} + +void CPlayer::UpdateFootstepSounds(const CFinalInput& input, CStateManager& mgr, float dt) { + if (x2f8_morphBallState == kMS_Unmorphed && x258_movementState == NPlayer::kMS_OnGround && + !x3dc_inFreeLook && !x3dd_lookButtonHeld) { + char sfxVol = 127; + x78c_footstepSfxTimer += dt; + float turn = TurnInput(input); + const float forward = fabsf(ForwardInput(input, turn)); + turn = fabsf(turn); + float sfxDelay = 0.f; + if (forward > 0.05f || x304_orbitState != kOS_NoOrbit) { + CVector3f velocity = GetVelocityWR(); + float mag = velocity.Magnitude(); + float vel = rstl::min_val(mag / GetActualFirstPersonMaxVelocity(dt), 1.f); + if (vel > 0.05f) { + sfxDelay = -0.475f * vel + 0.85f; + if (x790_footstepSfxSel == kFS_None) { + x790_footstepSfxSel = kFS_Left; + } + } else { + x78c_footstepSfxTimer = 0.f; + x790_footstepSfxSel = kFS_None; + } + + sfxVol = CCast::ToInt8((vel * 38.f + 89.f) * 1.f); + } else if (turn > 0.05f) { + if (x790_footstepSfxSel == kFS_Left) { + sfxDelay = -0.813f * turn + 1.f; + } else { + sfxDelay = -2.438f * turn + 3.f; + } + if (x790_footstepSfxSel == kFS_None) { + x790_footstepSfxSel = kFS_Left; + sfxDelay = x78c_footstepSfxTimer; + } + sfxVol = 96; + } else { + x78c_footstepSfxTimer = 0.f; + x790_footstepSfxSel = kFS_None; + } + + if (x790_footstepSfxSel != kFS_None && x78c_footstepSfxTimer > sfxDelay) { + static const float earHeight = GetEyeHeight() - 0.1f; + if (IsInFluid() && x828_distanceUnderWater > 0.f && x828_distanceUnderWater < earHeight) { + if (x82c_inLava) { + if (x790_footstepSfxSel == kFS_Left) { + DoSfxEffects(CSfxManager::SfxStart(SFXlav_wlklava_00, sfxVol, 64, true)); + } else { + DoSfxEffects(CSfxManager::SfxStart(SFXlav_wlklava_01, sfxVol, 64, true)); + } + } else { + if (x790_footstepSfxSel == kFS_Left) { + DoSfxEffects(CSfxManager::SfxStart(SFXsam_wlkwater_00, sfxVol, 64, true)); + } else { + DoSfxEffects(CSfxManager::SfxStart(SFXsam_wlkwater_01, sfxVol, 64, true)); + } + } + } else { + ushort sfx; + if (x790_footstepSfxSel == kFS_Left) { + sfx = GetMaterialSoundUnderPlayer(mgr, skLeftStepSounds, ARRAY_SIZE(skLeftStepSounds), + 0xffff); + } else { + sfx = GetMaterialSoundUnderPlayer(mgr, skRightStepSounds, ARRAY_SIZE(skRightStepSounds), + 0xffff); + } + DoSfxEffects(CSfxManager::SfxStart(sfx, sfxVol, 64, true)); + } + + x78c_footstepSfxTimer = 0.f; + if (x790_footstepSfxSel == kFS_Left) { + x790_footstepSfxSel = kFS_Right; + } else { + x790_footstepSfxSel = kFS_Left; + } + } + } +} + +CPlayer::CVisorSteam::CVisorSteam(float targetAlpha, float alphaInDur, float alphaOutDur, + CAssetId tex) +: x0_curTargetAlpha(targetAlpha) +, x4_curAlphaInDur(alphaInDur) +, x8_curAlphaOutDur(alphaOutDur) +, xc_tex(tex) +, x10_nextTargetAlpha(0.f) +, x14_nextAlphaInDur(0.f) +, x18_nextAlphaOutDur(0.f) +, x1c_txtr(kInvalidAssetId) +, x20_alpha(0.f) +, x24_delayTimer(0.f) +, x28_affectsThermal(false) {} + +void CPlayer::CVisorSteam::Update(float dt) { + if (x1c_txtr != kInvalidAssetId) { + x0_curTargetAlpha = x10_nextTargetAlpha; + x4_curAlphaInDur = x14_nextAlphaInDur; + x8_curAlphaOutDur = x18_nextAlphaOutDur; + xc_tex = x1c_txtr; + } else { + x0_curTargetAlpha = 0.f; + } + + x1c_txtr = kInvalidAssetId; + if (close_enough(x20_alpha, x0_curTargetAlpha) && close_enough(x20_alpha, 0.f)) { + return; + } + + if (x20_alpha > x0_curTargetAlpha) { + if (x24_delayTimer <= 0.f) { + x20_alpha -= dt / x8_curAlphaOutDur; + if (x20_alpha < x0_curTargetAlpha) { + x20_alpha = x0_curTargetAlpha; + } + } else { + x24_delayTimer -= dt; + if (x24_delayTimer < 0.f) { + x24_delayTimer = 0.f; + } + } + return; + } + + if (!gpSimplePool->GetObj(SObjectTag('TXTR', xc_tex)).IsLoaded()) { + return; + } + + x20_alpha += dt / x4_curAlphaInDur; + if (x20_alpha > x0_curTargetAlpha) { + x20_alpha = x0_curTargetAlpha; + } + + x24_delayTimer = 0.1f; +} + +void CPlayer::CVisorSteam::SetSteam(float targetAlpha, float alphaInDur, float alphaOutDur, + CAssetId txtr, bool affectsThermal) { + if (x1c_txtr == kInvalidAssetId || targetAlpha > x10_nextTargetAlpha) { + x10_nextTargetAlpha = targetAlpha; + x14_nextAlphaInDur = alphaInDur; + x18_nextAlphaOutDur = alphaOutDur; + x1c_txtr = txtr; + } + x28_affectsThermal = affectsThermal; +} + +void CPlayer::SetVisorSteam(float targetAlpha, float alphaInDur, float alphaOutDur, CAssetId txtr, + bool affectsThermal) { + x7a0_visorSteam.SetSteam(targetAlpha, alphaInDur, alphaOutDur, txtr, affectsThermal); +} + +const CScriptWater* CPlayer::GetVisorRunoffEffect(const CStateManager& mgr) const { + const CScriptWater* water = nullptr; + if (InFluidId() != kInvalidUniqueId) { + water = TCastToConstPtr< CScriptWater >(mgr.GetObjectById(InFluidId())); + } + return water; +} + +void CPlayer::SetMorphBallState(EPlayerMorphBallState state, CStateManager& mgr) { + if (x2f8_morphBallState == kMS_Morphed && state != kMS_Morphed) { + x9c5_26_ = IsInsideFluid(); + } + + x2f8_morphBallState = state; + SetStandardCollider(state == kMS_Morphed); + + switch (state) { + case kMS_Unmorphed: + if (x9c5_26_ && mgr.GetCameraManager()->GetInsideFluid()) { + if (const CScriptWater* water = GetVisorRunoffEffect(mgr)) { + if (water->GetUnmorphVisorRunoffEffect()) { + mgr.AddObject(rs_new CHUDBillboardEffect( + rstl::optional_object< TToken< CGenDescription > >( + *water->GetUnmorphVisorRunoffEffect()), + rstl::optional_object_null(), mgr.AllocateUniqueId(), true, + rstl::string_l("WaterSheets"), CHUDBillboardEffect::GetNearClipDistance(mgr), + CHUDBillboardEffect::GetScaleForPOV(mgr), CColor(1.f, 1.f, 1.f, 1.f), + CVector3f(1.f, 1.f, 1.f), CVector3f(0.f, 0.f, 0.f))); + } + DoSfxEffects(CSfxManager::SfxStart(water->GetUnmorphVisorRunoffSfx())); + } + } + break; + case kMS_Morphed: + case kMS_Morphing: + x768_morphball->LoadMorphBallModel(mgr); + break; + case kMS_Unmorphing: + break; + } +} + +// void CPlayer::SetSpawnedMorphBallState(EPlayerMorphBallState state, CStateManager& mgr) { +// x2fc_spawnedMorphBallState = state; +// SetCameraState(kCS_Spawned, mgr); +// if (x2fc_spawnedMorphBallState != x2f8_morphBallState) { +// CPhysicsActor::Stop(); +// SetOrbitRequest(kOR_Respawn, mgr); +// switch (x2fc_spawnedMorphBallState) { +// case kMS_Unmorphed: { +// CVector3f pos; +// if (CanLeaveMorphBallState(mgr, pos)) { +// SetTranslation(GetTranslation() + pos); +// LeaveMorphBallState(mgr); +// ForceGunOrientation(GetTransform(), mgr); +// DrawGun(mgr); +// } +// break; +// } +// case kMS_Morphed: +// EnterMorphBallState(mgr); +// ResetBallCAmera(mgr); +// mgr.GetCameraManager()->ResetCameraHint(mgr); +// mgr.GetCameraManager()->GetBallCamera()->Reset(CreateTransformFromMovementDirection(), mgr); +// break; +// default: +// break; +// } +// } +// }