diff --git a/src/prime/CFirstPersonCamera.hpp b/src/prime/CFirstPersonCamera.hpp index 982451f..18d052b 100644 --- a/src/prime/CFirstPersonCamera.hpp +++ b/src/prime/CFirstPersonCamera.hpp @@ -22,6 +22,14 @@ class CFirstPersonCameraMP1 : public CGameCameraMP1 { class CCameraManagerMP1 { public: + inline bool IsInCinematicCamera() + { + // camera count + if(*GetField(this, 0x8) != 0) { + return true; + } + return *GetField(this, 0x18) != 0; + } static float GetDefaultFirstPersonVerticalFOV(); }; diff --git a/src/prime/CGameState.hpp b/src/prime/CGameState.hpp index 7c464c7..c42e288 100644 --- a/src/prime/CGameState.hpp +++ b/src/prime/CGameState.hpp @@ -1,6 +1,8 @@ #pragma once #include "CObjectId.hpp" +#include "prime/CFirstPersonCamera.hpp" +#include "prime/CWorldMP1.hpp" #include "program/GetField.hpp" #include "types.h" @@ -89,6 +91,12 @@ class CStateManager { inline CStateManagerGameLogicMP1* GameLogic() { return GetField(this, 0x4e0150); } + inline CCameraManagerMP1* GetCameraManager() { + auto* ptr = reinterpret_cast(reinterpret_cast(this) + 0x4e0150); + if (ptr != nullptr) + return *reinterpret_cast(reinterpret_cast(*ptr) + 0x30); + return nullptr; + } }; class CStateManagerUpdateAccess; @@ -110,4 +118,7 @@ class CStateManagerGameLogicMP1 { static CPlayerStateMP1* PlayerState(); CPlayerMP1* PlayerActor(); void SetGameState(EGameState state); + + inline CWorldMP1* GetWorld() { return *GetField(this, 0x20); } + inline CCameraManagerMP1* GetCameraManager() { return *GetField(this, 0x30); } }; \ No newline at end of file diff --git a/src/prime/CPlayerStateMP1.hpp b/src/prime/CPlayerStateMP1.hpp index 1b9407e..648f759 100644 --- a/src/prime/CPlayerStateMP1.hpp +++ b/src/prime/CPlayerStateMP1.hpp @@ -1,5 +1,7 @@ #pragma once +class CStateManager; + class CPowerUp { public: int amount; @@ -60,8 +62,10 @@ class CPlayerStateMP1 { void SetPowerUp(EItemType type, int amount); int GetPowerUp(EItemType type); int GetItemCapacity(EItemType type) const; + void Kill(CStateManager&); inline CPowerUp* GetPowerups() { return reinterpret_cast(reinterpret_cast(this) + 0x44); } + inline bool IsPlayerAlive() { return (*reinterpret_cast(this) & 1) == 1; } static int GetItemMax(EItemType type); // _ZN15CPlayerStateMP110GetItemMaxE9EItemType diff --git a/src/prime/CWorldMP1.hpp b/src/prime/CWorldMP1.hpp new file mode 100644 index 0000000..81d2a66 --- /dev/null +++ b/src/prime/CWorldMP1.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "program/GetField.hpp" +#include "types.h" + +class CWorldMP1 { +public: + inline int32_t GetLoadPhase() { return *GetField(this, 8); } +}; \ No newline at end of file diff --git a/src/program/PlayerMenu.cpp b/src/program/PlayerMenu.cpp index 81c23ee..03c2c71 100644 --- a/src/program/PlayerMenu.cpp +++ b/src/program/PlayerMenu.cpp @@ -36,6 +36,11 @@ namespace GUI { // u32 savedWorldAssetID{0}; // u32 savedAreaAssetID{0}; + bool isInCutscene = true; + bool alive = false; + bool kill = false; + int32_t loadPhase = -1; + void drawPlayerMenu() { // CStateManager *stateManager = mostRecentStateManager; // if (stateManager == nullptr) return; @@ -124,6 +129,9 @@ namespace GUI { // player->setFluidCounter((u32) fluidCounter); // } // ImGui::DragFloat("Water depth", player->getDepthUnderWater(), 1.f, -FLT_MAX, FLT_MAX, "%.3f", flags); + if (!isInCutscene && loadPhase == 4 && ImGui::Button("Death")) { + kill = alive; + } ImGui::TreePop(); } diff --git a/src/program/PlayerMenu.hpp b/src/program/PlayerMenu.hpp index 77b1a1b..3d64c95 100644 --- a/src/program/PlayerMenu.hpp +++ b/src/program/PlayerMenu.hpp @@ -1,6 +1,7 @@ #pragma once #include "prime/Math.hpp" +#include "types.h" namespace GUI { extern bool hasDesiredPositionData; @@ -17,6 +18,11 @@ namespace GUI { extern double desiredTime; + extern bool isInCutscene; + extern bool alive; + extern bool kill; + extern int32_t loadPhase; + void drawPlayerMenu(); void savePos(); void loadPos(); diff --git a/src/program/patches.cpp b/src/program/patches.cpp index 81e6536..330b4f5 100644 --- a/src/program/patches.cpp +++ b/src/program/patches.cpp @@ -58,9 +58,9 @@ HOOK_DEFINE_INLINE(CheckFloatVar) { HOOK_DEFINE_TRAMPOLINE(CPlayerMP1_ProcessInput) { static void Callback(CPlayerMP1 *thiz, const CFinalInput &input, CStateManager &stateManager) { mostRecentStateManager = &stateManager; + auto *gameState = stateManager.GameState(); GUI::igt = gameState->GetPlayTime(); - GUI::moveState = thiz->GetMoveState(); GUI::bombJumpState = thiz->GetMorphBall()->GetBombJumpState(); GUI::isInHalfPipeMode = thiz->GetMorphBall()->GetIsInHalfPipeMode(); @@ -161,6 +161,11 @@ HOOK_DEFINE_TRAMPOLINE(CPlayerMP1_ProcessInput) { int etanks = CStateManagerGameLogicMP1::PlayerState()->GetItemCapacity(CPlayerStateMP1::EItemType::EnergyTanks); thiz->HealthInfo(stateManager).heatlh = (float)etanks * 100.0f + 99.0f; } + + if (GUI::kill) { + CStateManagerGameLogicMP1::PlayerState()->Kill(stateManager); + GUI::kill = false; + } } }; @@ -209,6 +214,17 @@ HOOK_DEFINE_TRAMPOLINE(NTonemap_build_tonemap_eval_params){ HOOK_DEFINE_TRAMPOLINE(CStateManagerGameLogicMP1_GameMainLoop){ static void Callback(CStateManagerGameLogicMP1 *self, CStateManager &mgr, CStateManagerUpdateAccess &mgrUpdAcc, float dt) { + auto *playerState = CStateManagerGameLogicMP1::PlayerState(); + auto *cameraManager = self->GetCameraManager(); + auto *world = self->GetWorld(); + + // Consider not alive when loading game + GUI::alive = false; + // Consider in cutscene when loading game + GUI::isInCutscene = true; + // set by default to undefined + GUI::loadPhase = -1; + if(PATCH_CONFIG.enable_stop_time) { if ((InputHelper::isHoldLeftStick() && InputHelper::isPressL()) || (InputHelper::isPressLeftStick() && InputHelper::isHoldL())) { const auto new_state = GUI::is_time_stopped ? CStateManagerGameLogicMP1::EGameState::Running @@ -219,6 +235,12 @@ HOOK_DEFINE_TRAMPOLINE(CStateManagerGameLogicMP1_GameMainLoop){ self->PlayerActor()->BreakOrbit((CPlayerMP1::EOrbitBrokenType)1, mgr); } } + } else { + if(playerState != nullptr && cameraManager != nullptr && world != nullptr) { + GUI::alive = playerState->IsPlayerAlive(); + GUI::isInCutscene = !GUI::alive ? true : cameraManager->IsInCinematicCamera(); + GUI::loadPhase = !GUI::alive ? -1 : world->GetLoadPhase(); + } } Orig(self, mgr, mgrUpdAcc, dt);