diff --git a/src/Hook.cpp b/src/Hook.cpp index b1ec4e5..d1bf630 100644 --- a/src/Hook.cpp +++ b/src/Hook.cpp @@ -6,6 +6,7 @@ #include "instance/Instances.h" #include "game/Game.h" #include "render/Font.h" +#include "game/GameLoop.h" // Modules #include "modules/MainMenu.h" @@ -76,6 +77,8 @@ void Hook::PostInitialize() #ifndef TR8 Font::OnFlush(std::bind(&Hook::OnFrame, this)); #endif + + GameLoop::OnLoop(std::bind(&Hook::OnLoop, this)); } void Hook::OnMessage(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) @@ -96,6 +99,14 @@ void Hook::OnFrame() } } +void Hook::OnLoop() +{ + for (auto& [hash, mod] : m_modules) + { + mod->OnLoop(); + } +} + void Hook::OnDevice() { // Assign the DeviceManager instance diff --git a/src/Hook.h b/src/Hook.h index a88d6bf..85360df 100644 --- a/src/Hook.h +++ b/src/Hook.h @@ -21,6 +21,7 @@ class Hook void OnMessage(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); void OnFrame(); + void OnLoop(); public: Hook(); diff --git a/src/game/Game.cpp b/src/game/Game.cpp index fe09907..edb47cc 100644 --- a/src/game/Game.cpp +++ b/src/game/Game.cpp @@ -22,4 +22,18 @@ void GAMELOOP_RequestLevelChangeByName(char* name, GameTracker* gameTracker, int auto addr = GET_ADDRESS(0x451970, 0xC61CFA, 0x5DF8C0); Hooking::Call(addr, name, gameTracker, doneType); +} + +void PLAYER_DebugSwitchPlayerCharacter() +{ + auto addr = GET_ADDRESS(0x5A40B0, 0x5A39A0, 0x79DB50); + + Hooking::Call(addr); +} + +int OBTABLE_GetObjectID(char* name) +{ + auto addr = GET_ADDRESS(0x462590, 0x465DE0, 0x5BF770); + + return Hooking::CallReturn(addr, name); } \ No newline at end of file diff --git a/src/game/Game.h b/src/game/Game.h index 07e2d79..4a82b47 100644 --- a/src/game/Game.h +++ b/src/game/Game.h @@ -77,6 +77,11 @@ struct GameTracker float timeDilation; int debugTimeMult; + + char pad2[752]; + + int currentPlayerObjectID; + int altPlayerObjectID; }; #else struct GameTracker @@ -143,8 +148,8 @@ struct GameTracker int field_134; int field_138; int field_13C; - int field_140; - int field_144; + int currentPlayerObjectID; + int altPlayerObjectID; float timeDilation; }; @@ -158,4 +163,7 @@ class Game static STracker* GetStreamTracker(); }; -void GAMELOOP_RequestLevelChangeByName(char* name, GameTracker* gameTracker, int doneType); \ No newline at end of file +void GAMELOOP_RequestLevelChangeByName(char* name, GameTracker* gameTracker, int doneType); + +void PLAYER_DebugSwitchPlayerCharacter(); +int OBTABLE_GetObjectID(char* name); \ No newline at end of file diff --git a/src/game/GameLoop.cpp b/src/game/GameLoop.cpp new file mode 100644 index 0000000..8c870a9 --- /dev/null +++ b/src/game/GameLoop.cpp @@ -0,0 +1,25 @@ +#include + +#include "GameLoop.h" +#include "Game.h" +#include "util/Hooking.h" + +static std::function s_callback; +static void(*s_GAMELOOP_Process)(GameTracker*); + +static void GAMELOOP_Process(GameTracker* gameTracker) +{ + s_callback(); + s_GAMELOOP_Process(gameTracker); +} + +void GameLoop::OnLoop(std::function callback) +{ + if (!s_callback) + { + MH_CreateHook((void*)GET_ADDRESS(0x452140, 0x454AC0, 0x5DFBE0), GAMELOOP_Process, (void**)&s_GAMELOOP_Process); + MH_EnableHook(MH_ALL_HOOKS); + } + + s_callback = callback; +} \ No newline at end of file diff --git a/src/game/GameLoop.h b/src/game/GameLoop.h new file mode 100644 index 0000000..8302866 --- /dev/null +++ b/src/game/GameLoop.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +class GameLoop +{ +public: + static void OnLoop(std::function callback); +}; \ No newline at end of file diff --git a/src/modules/MainMenu.cpp b/src/modules/MainMenu.cpp index fe71d64..ea57dd3 100644 --- a/src/modules/MainMenu.cpp +++ b/src/modules/MainMenu.cpp @@ -28,6 +28,25 @@ void MainMenu::OnDraw() BirthObject(object); } + // Player + if (ImGui::CollapsingHeader("Player")) + { + static char outfit[64] = ""; + ImGui::InputText("Outfit", outfit, sizeof(outfit)); + + if (ImGui::Button("Change")) + { + SwitchPlayerCharacter(outfit); + } + + ImGui::SameLine(); + + if (ImGui::Button("Next")) + { + SwitchPlayerCharacter(); + } + } + // Time if (ImGui::CollapsingHeader("Time")) { @@ -57,8 +76,22 @@ void MainMenu::BirthObject(char* name) INSTANCE_BirthObjectNoParent(game->StreamUnitID, &player->position, &player->rotation, nullptr, tracker->object, 0, 1); } +void MainMenu::SwitchPlayerCharacter(char* name) +{ + auto game = Game::GetGameTracker(); + + if (name) + { + auto object = OBTABLE_GetObjectID(name); + game->altPlayerObjectID = object; + } + + m_switchPlayerNextFrame = true; +} + void MainMenu::OnFrame() { + // Shows the watermark in th main menu auto mainState = *(int*)GET_ADDRESS(0x10E5868, 0x838838, 0x000000); if (mainState == MS_DISPLAY_MAIN_MENU) @@ -70,6 +103,15 @@ void MainMenu::OnFrame() } } +void MainMenu::OnLoop() +{ + if (m_switchPlayerNextFrame) + { + m_switchPlayerNextFrame = false; + PLAYER_DebugSwitchPlayerCharacter(); + } +} + void MainMenu::OnInput(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { auto gameTracker = Game::GetGameTracker(); diff --git a/src/modules/MainMenu.h b/src/modules/MainMenu.h index 8bf0811..db8cf24 100644 --- a/src/modules/MainMenu.h +++ b/src/modules/MainMenu.h @@ -5,10 +5,14 @@ class MainMenu : public Module { private: + bool m_switchPlayerNextFrame = false; + void BirthObject(char* name); + void SwitchPlayerCharacter(char* name = nullptr); public: void OnDraw(); void OnFrame(); + void OnLoop(); void OnInput(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); }; \ No newline at end of file diff --git a/src/modules/Module.h b/src/modules/Module.h index b34c737..39e7295 100644 --- a/src/modules/Module.h +++ b/src/modules/Module.h @@ -14,6 +14,9 @@ class Module // Called just before a frame ends, Font::Flush to be specific virtual void OnFrame() { }; + // Called every frame before the game loop + virtual void OnLoop() { }; + // Called when a message is processed by the window procedure virtual void OnInput(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { }; }; \ No newline at end of file