diff --git a/src/Hook.cpp b/src/Hook.cpp index 6397176..f258ac0 100644 --- a/src/Hook.cpp +++ b/src/Hook.cpp @@ -19,6 +19,7 @@ #include "modules/ModLoader.h" #include "modules/Patches.h" #include "modules/Frontend.h" +#include "modules/camera/FreeCamera.h" #include "cdc/render/PCDeviceManager.h" @@ -127,6 +128,7 @@ void Hook::RegisterModules() RegisterModule(); RegisterModule(); RegisterModule(); + RegisterModule(); #ifndef TR8 RegisterModule(); diff --git a/src/game/Camera.cpp b/src/game/Camera.cpp new file mode 100644 index 0000000..9141a89 --- /dev/null +++ b/src/game/Camera.cpp @@ -0,0 +1,14 @@ +#include "Camera.h" +#include "util/Hooking.h" + +Camera* CAMERA_GetCamera() +{ + return (Camera*)GET_ADDRESS(0x000000, 0x850670, 0x000000); +} + +void CAMERA_CalcPosition(cdc::Vector3* position, cdc::Vector3* base, cdc::Euler* rotation, float distance) +{ + auto addr = GET_ADDRESS(0x48D8B0, 0x491320, 0x000000); + + Hooking::Call(addr, position, base, rotation, distance); +} \ No newline at end of file diff --git a/src/game/Camera.h b/src/game/Camera.h new file mode 100644 index 0000000..1fcc862 --- /dev/null +++ b/src/game/Camera.h @@ -0,0 +1,23 @@ +#pragma once + +#include "cdc/math/Vector.h" + +struct CameraCore +{ + cdc::Vector3 position; + char pad1[608]; + cdc::Euler rotation; + char pad2[128]; +}; + +struct Camera : CameraCore +{ + char pad3[12]; + + int flags; + int lock; + __int16 mode; +}; + +Camera* CAMERA_GetCamera(); +void CAMERA_CalcPosition(cdc::Vector3* position, cdc::Vector3* base, cdc::Euler* rotation, float distance); \ No newline at end of file diff --git a/src/input/Input.cpp b/src/input/Input.cpp index 1ad0c71..b67ab4a 100644 --- a/src/input/Input.cpp +++ b/src/input/Input.cpp @@ -5,4 +5,28 @@ void Input::DisableInput(bool disable) { *(bool*)GET_ADDRESS(0x1101689, 0x8551A9, 0xA02B79) = disable; +} + +void Input::DisablePlayerControl(bool disable) +{ + *(bool*)GET_ADDRESS(0xF15AB4, 0x666C34, 0x8AB4E6) = !disable; +} + +bool Input::IsInputActionPressed(int action) +{ + auto inputSystem = GetInputSystem(); + + return (inputSystem->m_pActionMapper->m_pActionResults[action].state & 4) == 4; +} + +InputSystem* Input::GetInputSystem() +{ + return *(InputSystem**)GET_ADDRESS(0x1101680, 0x8551A0, 0xA02B68); +} + +float InputSystem::GetAxisValue(int axisID) +{ + auto addr = GET_ADDRESS(0x4E3FC0, 0x4E38C0, 0x480E50); + + return Hooking::ThisCallReturn(addr, this, axisID); } \ No newline at end of file diff --git a/src/input/Input.h b/src/input/Input.h index 6a8514f..487f91c 100644 --- a/src/input/Input.h +++ b/src/input/Input.h @@ -1,7 +1,38 @@ #pragma once +class InputActionMapper +{ +public: + struct ActionResult + { + unsigned int state; + + char pad1[20]; + }; + + ActionResult* m_pActionResults; +}; + +class InputSystem +{ +public: + unsigned int m_numButtons; + unsigned int m_numAxis; + + char pad1[16]; + + InputActionMapper* m_pActionMapper; + +public: + float GetAxisValue(int axisID); +}; + class Input { public: static void DisableInput(bool disable); + static void DisablePlayerControl(bool disable); + static bool IsInputActionPressed(int action); + + static InputSystem* GetInputSystem(); }; \ No newline at end of file diff --git a/src/modules/camera/FreeCamera.cpp b/src/modules/camera/FreeCamera.cpp new file mode 100644 index 0000000..9f2146e --- /dev/null +++ b/src/modules/camera/FreeCamera.cpp @@ -0,0 +1,96 @@ +#include "FreeCamera.h" + +#include "input/Input.h" +#include "game/Game.h" +#include "render/Font.h" + +FreeCameraBase::FreeCameraBase() : m_vKeys() +{ +} + +void FreeCameraBase::ToggleMode() +{ + // Switch between disabled -> enabled -> no control + m_mode = m_mode == Disabled ? Enabled : m_mode == NoControl ? Disabled : NoControl; + + // Disable player control when the free camera is enabled + Input::DisablePlayerControl(m_mode == Enabled); +} + +void FreeCameraBase::OnInput(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (msg == WM_KEYUP && wParam == VK_F4) + { + ToggleMode(); + } + + // 1-3 virtual keys, kinda hack.. TODO global thing like this? + if (msg == WM_KEYDOWN && wParam >= 0x31 && wParam <= 0x33) + { + m_vKeys[wParam - 0x31] = true; + } + + if (msg == WM_KEYUP && wParam >= 0x31 && wParam <= 0x33) + { + m_vKeys[wParam - 0x31] = false; + } +} + +void FreeCameraBase::OnControl() +{ + auto input = Input::GetInputSystem(); + auto gameTracker = Game::GetGameTracker(); + + // Camera rotation based on mouse/controller axis + auto rotX = input->GetAxisValue(17) * gameTracker->timeMult; + auto rotZ = input->GetAxisValue(16) * gameTracker->timeMult; + + Rotate(rotX, rotZ); + + // Camera roll + if (m_vKeys[0] || m_vKeys[2]) + { + // TODO + auto roll = m_vKeys[0] ? 0.02454f : -0.02454f; + + Rotate(roll * gameTracker->timeMult); + } + + // Change the speed depending on if shift/alt is pressed + auto shift = Input::IsInputActionPressed(18); + auto control = Input::IsInputActionPressed(23); + + auto speed = shift ? 200.f : control ? 20.f : 80.f; + + // Camera forward/backward + if (Input::IsInputActionPressed(1) || Input::IsInputActionPressed(2)) + { + auto distance = Input::IsInputActionPressed(1) ? -speed : speed; + + MoveForward(distance * gameTracker->timeMult); + } + + // Camera left/right + if (Input::IsInputActionPressed(3) || Input::IsInputActionPressed(4)) + { + auto distance = Input::IsInputActionPressed(3) ? -speed : speed; + + MoveLeft(distance * gameTracker->timeMult); + } + + // Camera up/down + if (Input::IsInputActionPressed(16) || Input::IsInputActionPressed(17)) + { + auto distance = Input::IsInputActionPressed(16) ? -speed : speed; + + MoveUp(distance * gameTracker->timeMult); + } +} + +void FreeCameraBase::OnLoop() +{ + if (m_mode == Enabled) + { + OnControl(); + } +} \ No newline at end of file diff --git a/src/modules/camera/FreeCamera.h b/src/modules/camera/FreeCamera.h new file mode 100644 index 0000000..341f0aa --- /dev/null +++ b/src/modules/camera/FreeCamera.h @@ -0,0 +1,52 @@ +#pragma once + +#include "modules/Module.h" + +// Base class for both free camera implementations +class FreeCameraBase : public Module +{ +public: + enum ControlMode + { + Disabled, + Enabled, + NoControl + }; + +private: + bool m_vKeys[3]; + +protected: + ControlMode m_mode = Disabled; + + virtual void ToggleMode(); + virtual void OnControl(); + + // Game specific + virtual void Rotate(float x, float z) = 0; + virtual void Rotate(float y) = 0; + virtual void MoveForward(float distance) = 0; + virtual void MoveLeft(float distance) = 0; + virtual void MoveUp(float distance) = 0; + +public: + FreeCameraBase(); + + void OnInput(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + void OnLoop(); +}; + +// Free camera implementation for Legend and Anniversary +class LegendCamera : public FreeCameraBase +{ +protected: + void ToggleMode(); + + void Rotate(float x, float z); + void Rotate(float y); + void MoveForward(float distance); + void MoveLeft(float distance); + void MoveUp(float distance); +}; + +using FreeCamera = LegendCamera; \ No newline at end of file diff --git a/src/modules/camera/Legend.cpp b/src/modules/camera/Legend.cpp new file mode 100644 index 0000000..8285ded --- /dev/null +++ b/src/modules/camera/Legend.cpp @@ -0,0 +1,63 @@ +#define _USE_MATH_DEFINES +#include + +#include "FreeCamera.h" +#include "game/Camera.h" + +void LegendCamera::ToggleMode() +{ + FreeCameraBase::ToggleMode(); + + auto camera = CAMERA_GetCamera(); + + if (m_mode == Enabled) + { + camera->mode = 7; + } + + if (m_mode == Disabled) + { + // Switch back to gameplay camera + camera->mode = 2; + } +} + +void LegendCamera::Rotate(float x, float z) +{ + auto camera = CAMERA_GetCamera(); + + camera->rotation.x -= x; + camera->rotation.z -= z; +} + +void LegendCamera::Rotate(float y) +{ + auto camera = CAMERA_GetCamera(); + + camera->rotation.y += y; +} + +void LegendCamera::MoveForward(float distance) +{ + auto camera = CAMERA_GetCamera(); + + CAMERA_CalcPosition(&camera->position, &camera->position, &camera->rotation, distance); +} + +void LegendCamera::MoveLeft(float distance) +{ + auto camera = CAMERA_GetCamera(); + auto rotation = camera->rotation; + + rotation.x = 0.f; + rotation.z += static_cast(M_PI) / 2.f; + + CAMERA_CalcPosition(&camera->position, &camera->position, &rotation, distance); +} + +void LegendCamera::MoveUp(float distance) +{ + auto camera = CAMERA_GetCamera(); + + camera->position.z += distance; +} \ No newline at end of file