- Added One Handed Mode

- Fixed Freeze Time at night making Aiden complain about his immunity lmao
- Added Slow Motion, with speed and transition time modifiers
This commit is contained in:
EricPlayZ
2024-02-08 22:21:11 +02:00
parent 9bd867bc9f
commit 2d804f624c
24 changed files with 470 additions and 264 deletions

View File

@ -16,6 +16,7 @@
<ClCompile Include="source\dllmain.cpp" />
<ClCompile Include="source\game_classes.cpp" />
<ClCompile Include="source\hook.cpp" />
<ClCompile Include="source\ImGuiEx\Animation.cpp" />
<ClCompile Include="source\ImGuiEx\ImGuiEx.cpp" />
<ClCompile Include="source\ImGuiFileDialog\ImGuiFileDialog.cpp" />
<ClCompile Include="source\ImGuiHotkeys\Hotkey.cpp" />
@ -46,6 +47,7 @@
<ClInclude Include="source\core.h" />
<ClInclude Include="source\game_classes.h" />
<ClInclude Include="source\hook.h" />
<ClInclude Include="source\ImGuiEx\Animation.h" />
<ClInclude Include="source\ImGuiEx\ImGuiEx.h" />
<ClInclude Include="source\ImGuiFileDialog\dirent\dirent.h" />
<ClInclude Include="source\ImGuiFileDialog\ImGuiFileDialog.h" />

View File

@ -68,6 +68,9 @@
<ClCompile Include="source\menu\misc.cpp">
<Filter>menu</Filter>
</ClCompile>
<ClCompile Include="source\ImGuiEx\Animation.cpp">
<Filter>ImGuiEx</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="source\memory.h" />
@ -167,6 +170,9 @@
<ClInclude Include="source\menu\misc.h">
<Filter>menu</Filter>
</ClInclude>
<ClInclude Include="source\ImGuiEx\Animation.h">
<Filter>ImGuiEx</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="MinHook">

View File

@ -0,0 +1,37 @@
#define _USE_MATH_DEFINES
#include <cmath>
#include <imgui_internal.h>
#include <string_view>
#include <unordered_map>
namespace ImGui {
std::unordered_map<std::string_view, float> AnimValueStack{};
const float AnimEaseInSine(const float blendPoint) { return 1 - std::cos((blendPoint * static_cast<float>(M_PI)) / 2); }
const float AnimEaseOutSine(const float blendPoint) { return std::sin((blendPoint * static_cast<float>(M_PI)) / 2.0f); }
static const float SetAnimTime(const std::string_view& valueName, const float animSpeed, const bool resetBlendPoint = false, const float (*easingFunction)(float) = nullptr) {
const ImGuiContext& g = *GImGui;
float blendPoint = 0.0f;
if (!resetBlendPoint)
blendPoint = AnimValueStack[valueName];
if (blendPoint == 1.0f)
return blendPoint;
blendPoint += g.IO.DeltaTime / animSpeed;
blendPoint = ImMin(blendPoint, 1.0f);
AnimValueStack[valueName] = blendPoint;
if (easingFunction)
blendPoint = easingFunction(blendPoint);
return blendPoint;
}
const float AnimateLerp(const std::string_view& valueName, const float a, const float b, const float animSpeed, const bool resetBlendPoint, const float (*easingFunction)(float)) {
const float blendPoint = SetAnimTime(valueName, animSpeed, resetBlendPoint, easingFunction);
return ImLerp<float>(a, b, blendPoint);
}
}

View File

@ -0,0 +1,13 @@
#pragma once
#include <imgui_internal.h>
#include <string_view>
#include <unordered_map>
namespace ImGui {
extern std::unordered_map<std::string_view, float> AnimValueStack;
const float AnimEaseInSine(const float blendPoint);
const float AnimEaseOutSine(const float blendPoint);
extern const float AnimateLerp(const std::string_view& valueName, const float a, const float b, const float animSpeed, const bool resetBlendPoint = false, const float (*easingFunction)(float) = nullptr);
}

View File

@ -1,4 +1,5 @@
#define IMGUI_DEFINE_MATH_OPERATORS
#include <Hotkey.h>
#include <imgui_internal.h>
#include "..\core.h"
@ -80,6 +81,11 @@ namespace ImGui {
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (v->GetValue() ? ImGuiItemStatusFlags_Checked : 0));
return pressed;
}
bool CheckboxHotkey(const char* label, KeyBindOption* v) {
const bool checkbox = ImGui::Checkbox(label, v);
ImGui::Hotkey(std::string(label + std::string("##ToggleKey")), v);
return checkbox;
}
static const float CalculateIndentation(const float& window_width, const float& text_width, const float& min_indentation) {
const float indentation = (window_width - text_width) * 0.5f;
return indentation > min_indentation ? indentation : min_indentation;

View File

@ -1,9 +1,11 @@
#pragma once
#include "..\core.h"
#include "Animation.h"
namespace ImGui {
extern void StyleScaleAllSizes(ImGuiStyle* style, float scale_factor);
extern bool Checkbox(const char* label, Option* v);
extern bool CheckboxHotkey(const char* label, KeyBindOption* v);
extern void TextCentered(const char* text);
extern void TextCenteredColored(const char* text, const ImU32& col);
extern bool ButtonCentered(const char* label, const ImVec2& size = ImVec2(0.0f, 0.0f));

View File

@ -5,21 +5,40 @@
bool ImGui::isAnyHotkeyBtnPressed = false;
Utils::Timer ImGui::timeSinceHotkeyBtnPressed{ 250 };
void ImGui::Hotkey(std::string_view label, KeyBindOption& key, float samelineOffset, const ImVec2& size) {
const auto id = ImGui::GetID(label.data());
void ImGui::Hotkey(const std::string_view& label, KeyBindOption* key) {
ImGuiContext& g = *GImGui;
bool wasDisabled = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0;
if (wasDisabled)
ImGui::EndDisabled();
const ImGuiID id = ImGui::GetID(label.data());
ImGui::PushID(label.data());
if (!label.contains("##"))
ImGui::Text("%s", label.data());
ImGui::SameLine(samelineOffset);
ImGuiWindow* window = GetCurrentWindow();
if (!label.contains("##") && !window->SkipItems) {
const ImGuiStyle& style = (*GImGui).Style;
const ImVec2 label_size = CalcTextSize(label.data(), nullptr, true);
const ImVec2 pos = window->DC.CursorPos;
const ImRect total_bb(pos, pos + ImVec2((label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), label_size.y + style.FramePadding.y * 2.0f));
ItemSize(total_bb, style.FramePadding.y);
if (ItemAdd(total_bb, window->GetID(label.data()))) {
const ImVec2 label_pos = ImVec2(pos.x + style.ItemInnerSpacing.x, pos.y + style.FramePadding.y);
if (label_size.x > 0.0f)
RenderText(label_pos, label.data());
}
}
ImGui::SameLine(0.0f);
if (ImGui::GetActiveID() == id) {
ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetColorU32(ImGuiCol_ButtonActive));
ImGui::Button("...", size);
ImGui::Button("...", ImVec2(0.0f, 0.0f));
ImGui::PopStyleColor();
ImGui::GetCurrentContext()->ActiveIdAllowOverlap = true;
if ((!ImGui::IsItemHovered() && ImGui::GetIO().MouseClicked[0]) || key.SetToPressedKey()) {
if ((!ImGui::IsItemHovered() && ImGui::GetIO().MouseClicked[0]) || key->SetToPressedKey()) {
timeSinceHotkeyBtnPressed = Utils::Timer(250);
isAnyHotkeyBtnPressed = false;
ImGui::ClearActiveID();
@ -27,10 +46,13 @@ void ImGui::Hotkey(std::string_view label, KeyBindOption& key, float samelineOff
else
ImGui::SetActiveID(id, ImGui::GetCurrentWindow());
}
else if (ImGui::Button(key.ToString(), size)) {
else if (ImGui::Button(key->ToString(), ImVec2(0.0f, 0.0f))) {
isAnyHotkeyBtnPressed = true;
ImGui::SetActiveID(id, ImGui::GetCurrentWindow());
}
ImGui::PopID();
if (wasDisabled)
ImGui::BeginDisabled(wasDisabled);
}

View File

@ -7,5 +7,5 @@ namespace ImGui {
extern bool isAnyHotkeyBtnPressed;
extern Utils::Timer timeSinceHotkeyBtnPressed;
void Hotkey(std::string_view label, KeyBindOption& key, float samelineOffset = 0.0f, const ImVec2& size = { 0.0f, 0.0f });
void Hotkey(const std::string_view& label, KeyBindOption* key);
}

View File

@ -4028,16 +4028,22 @@ namespace Config {
{ "Menu:Keybinds", "MenuToggleKey", std::string("VK_F5"), &Menu::menuToggle, String},
{ "Menu:Keybinds", "GodModeToggleKey", std::string("VK_F6"), &Menu::Player::godMode, String},
{ "Menu:Keybinds", "FreezePlayerToggleKey", std::string("VK_F7"), &Menu::Player::freezePlayer, String},
{ "Menu:Keybinds", "DisableOutOfBoundsTimerToggleKey", std::string("VK_NONE"), &Menu::Player::disableOutOfBoundsTimer, String},
{ "Menu:Keybinds", "NightrunnerModeToggleKey", std::string("VK_F9"), &Menu::Player::nightrunnerMode, String},
{ "Menu:Keybinds", "OneHandedModeToggleKey", std::string("VK_NONE"), &Menu::Player::oneHandedMode, String},
{ "Menu:Keybinds", "FreeCamToggleKey", std::string("VK_F3"), &Menu::Camera::freeCam, String},
{ "Menu:Keybinds", "TeleportPlayerToCameraToggleKey", std::string("VK_F4"), &Menu::Camera::teleportPlayerToCamera, String},
{ "Menu:Keybinds", "ThirdPersonToggleKey", std::string("VK_F1"), &Menu::Camera::thirdPersonCamera, String},
{ "Menu:Keybinds", "UseTPPModelToggleKey", std::string("VK_F2"), &Menu::Camera::tpUseTPPModel, String},
{ "Menu:Keybinds", "DisablePhotoModeLimits", std::string("VK_NONE"), &Menu::Camera::disablePhotoModeLimits, String},
{ "Menu:Keybinds", "DisableSafezoneFOVReduction", std::string("VK_NONE"), &Menu::Camera::disableSafezoneFOVReduction, String},
{ "Menu:Keybinds", "DisableHUDToggleKey", std::string("VK_F8"), &Menu::Misc::disableHUD, String},
{ "Menu:Keybinds", "FreezeTimeToggleKey", std::string("VK_NONE"), &Menu::World::freezeTime, String},
{ "Menu:Keybinds", "SlowMotionToggleKey", std::string("VK_X"), &Menu::World::slowMotion, String},
{ "Player:Misc", "GodMode", false, &Menu::Player::godMode, OPTION },
{ "Player:Misc", "DisableOutOfBoundsTimer", true, &Menu::Player::disableOutOfBoundsTimer, OPTION },
{ "Player:Misc", "NightrunnerMode", false, &Menu::Player::nightrunnerMode, OPTION },
{ "Player:Misc", "OneHandedMode", false, &Menu::Player::oneHandedMode, OPTION },
{ "Player:PlayerVariables", "Enabled", false, &Menu::Player::playerVariables, OPTION },
{ "Player:PlayerVariables", "LastSaveSCRPath", std::string(), &Menu::Player::saveSCRPath, String },
{ "Player:PlayerVariables", "LastLoadSCRFilePath", std::string(), &Menu::Player::loadSCRFilePath, String },
@ -4049,7 +4055,9 @@ namespace Config {
{ "Camera:ThirdPerson", "HeightAbovePlayer", 1.35f, &Menu::Camera::tpHeightAbovePlayer, Float },
{ "Camera:ThirdPerson", "HorizontalDistanceFromPlayer", 0.0f, &Menu::Camera::tpHorizontalDistanceFromPlayer, Float },
{ "Camera:Misc", "DisablePhotoModeLimits", true, &Menu::Camera::disablePhotoModeLimits, OPTION },
{ "Camera:Misc", "DisableSafezoneFOVReduction", true, &Menu::Camera::disableSafezoneFOVReduction, OPTION }
{ "Camera:Misc", "DisableSafezoneFOVReduction", true, &Menu::Camera::disableSafezoneFOVReduction, OPTION },
{ "World:Time", "SlowMotionSpeed", 0.4f, &Menu::World::slowMotionSpeed, Float },
{ "World:Time", "SlowMotionTransitionTime", 1.0f, &Menu::World::slowMotionTransitionTime, Float }
});
std::vector<ConfigEntry> configVariables(configVariablesDefault.begin(), configVariablesDefault.end());
static const char* configFileName = "EGameTools.ini";

View File

@ -140,22 +140,15 @@ namespace Core {
PrintInfo("Initializing MinHook");
MH_Initialize();
PrintInfo("Hooking ReadVideoSettings");
const auto readVidSettingsHook = std::find_if(Hook::HookBase::GetInstances()->begin(), Hook::HookBase::GetInstances()->end(), [](const auto& item) { return item->name == "ReadVideoSettings"; });
if (readVidSettingsHook != Hook::HookBase::GetInstances()->end()) {
(*readVidSettingsHook)->HookLoop();
Hook::HookBase::GetInstances()->erase(readVidSettingsHook);
PrintSuccess("Hooked ReadVideoSettings!");
}
PrintInfo("Hooking DX11/DX12 renderer");
LoopHookRenderer();
PrintSuccess("Hooked DX11/DX12 renderer!");
std::thread([]() {
LoopHookRenderer();
PrintSuccess("Hooked DX11/DX12 renderer!");
}).detach();
for (auto& hook : *Hook::HookBase::GetInstances()) {
PrintInfo("Hooking %s", hook->name.data());
hook->HookLoop();
PrintSuccess("Hooked %s!", hook->name.data());
std::thread([hook]() { hook->HookLoop(); }).detach();
}
const HANDLE proc = GetCurrentProcess();

View File

@ -8,6 +8,7 @@
#include "menu\camera.h"
#include "menu\misc.h"
#include "menu\player.h"
#include "menu\world.h"
#include "print.h"
#include "sigscan\offsets.h"
#include "utils.h"
@ -29,6 +30,7 @@ namespace GamePH {
static void detourMoveCameraFromForwardUpPos(LPVOID pCBaseCamera, float* a3, float* a4, Vector3* pos);
static bool detourIsNotOutOfBounds(LPVOID pInstance, DWORD64 a2);
static void detourShowUIManager(LPVOID pLevelDI, bool enabled);
static DWORD64 detourPlaySoundEvent(LPVOID pCoAudioEventControl, DWORD64 name, DWORD64 a3);
static DWORD64 detourFsOpen(DWORD64 file, DWORD a2, DWORD a3);
#pragma region CreatePlayerHealthModule
@ -240,6 +242,20 @@ namespace GamePH {
}
#pragma endregion
#pragma region PlaySoundEvent
static Hook::MHook<LPVOID, DWORD64(*)(LPVOID, DWORD64, DWORD64)> PlaySoundEventHook{ "PlaySoundEvent", &Offsets::Get_PlaySoundEvent, &detourPlaySoundEvent };
static DWORD64 detourPlaySoundEvent(LPVOID pCoAudioEventControl, DWORD64 name, DWORD64 a3) {
const char* soundName = reinterpret_cast<const char*>(name);
if (Menu::World::freezeTime.GetValue() &&
(!strcmp(soundName, "set_gp_infection_start") || !strcmp(soundName, "set_gp_infection_immune"))) {
return 0;
}
return PlaySoundEventHook.pOriginal(pCoAudioEventControl, name, a3);
}
#pragma endregion
#pragma region fs::open
static LPVOID GetFsOpen() {
return Utils::GetProcAddr("filesystem_x64_rwdi.dll", "?open@fs@@YAPEAUSFsFile@@V?$string_const@D@ttl@@W4TYPE@EFSMode@@W45FFSOpenFlags@@@Z");
@ -254,19 +270,19 @@ namespace GamePH {
if (fileName.empty())
return FsOpenHook.pOriginal(file, a2, a3);
for (const auto& entry : std::filesystem::directory_iterator("EGameTools\\FilesToLoad")) {
if (fileName.contains(".rpack"))
return FsOpenHook.pOriginal(file, a2, a3);
if (fileName.contains("player_anims_pc"))
return FsOpenHook.pOriginal(file, a2, a3);
if (fileName.contains("sfx"))
return FsOpenHook.pOriginal(file, a2, a3);
if (entry.path().filename().string().contains(fileName)) {
std::string finalPath = std::string("EGameTools\\FilesToLoad\\") + fileName;
const char* filePath2 = finalPath.c_str();
for (const auto& entry : std::filesystem::recursive_directory_iterator("EGameTools\\FilesToLoad")) {
const std::filesystem::path pathToFile = entry.path();
if (!std::filesystem::is_regular_file(pathToFile))
continue;
return FsOpenHook.pOriginal(firstByte != 0x0 ? (reinterpret_cast<DWORD64>(filePath2) | (firstByte << 56)) : reinterpret_cast<DWORD64>(filePath2), a2, a3); // restores first byte of addr if first byte was not 0
}
const std::filesystem::path pathToFilename = pathToFile.filename();
if (!pathToFilename.string().contains(fileName))
continue;
std::string finalPath = pathToFile.string();
const char* filePath2 = finalPath.c_str();
return FsOpenHook.pOriginal(firstByte != 0x0 ? (reinterpret_cast<DWORD64>(filePath2) | (firstByte << 56)) : reinterpret_cast<DWORD64>(filePath2), a2, a3); // restores first byte of addr if first byte was not 0
}
return FsOpenHook.pOriginal(file, a2, a3);
}
@ -694,6 +710,28 @@ namespace GamePH {
return;
}
}
float LevelDI::TimerGetSpeedUp() {
__try {
float(*pTimerGetSpeedUp)(LPVOID iLevel) = (decltype(pTimerGetSpeedUp))Utils::GetProcAddr("engine_x64_rwdi.dll", "?TimerGetSpeedUp@ILevel@@QEBAMXZ");
if (!pTimerGetSpeedUp)
return -1.0f;
return pTimerGetSpeedUp(this);
} __except (EXCEPTION_EXECUTE_HANDLER) {
return -1.0f;
}
}
void LevelDI::TimerSetSpeedUp(float timeScale) {
__try {
void(*pTimerSetSpeedUp)(LPVOID iLevel, float timeScale) = (decltype(pTimerSetSpeedUp))Utils::GetProcAddr("engine_x64_rwdi.dll", "?TimerSetSpeedUp@ILevel@@QEAAXM@Z");
if (!pTimerSetSpeedUp)
return;
pTimerSetSpeedUp(this, timeScale);
} __except (EXCEPTION_EXECUTE_HANDLER) {
return;
}
}
TimeWeather::CSystem* LevelDI::GetTimeWeatherSystem() {
__try {
TimeWeather::CSystem*(*pGetTimeWeatherSystem)(LevelDI* iLevel) = (decltype(pGetTimeWeatherSystem))Utils::GetProcAddr("engine_x64_rwdi.dll", "?GetTimeWeatherSystem@ILevel@@QEBAPEAVCSystem@TimeWeather@@XZ");

View File

@ -5,6 +5,7 @@
#include <memory>
#include <string>
#include <vector>
#include "core.h"
#include "hook.h"
#include "utils.h"
@ -145,6 +146,9 @@ namespace GamePH {
static void ChangePlayerVar(const std::string& playerVar, const T value) {
static_assert(std::is_same<T, bool>::value || std::is_same<T, float>::value || std::is_same<T, std::string>::value, "Invalid type: value must be bool, float or string");
if (!gotPlayerVars)
return;
auto it = std::find_if(PlayerVariables::playerVars.begin(), PlayerVariables::playerVars.end(), [&playerVar](const auto& pair) {
return pair.first == playerVar;
});
@ -176,6 +180,24 @@ namespace GamePH {
*(varValue + 1) = value;
}
}
template <typename T>
static void ManagePlayerVarOption(const std::string& playerVar, const T valueIfTrue, const T valueIfFalse, Option* option, const bool& usePreviousVal = true) {
if (!gotPlayerVars)
return;
static T previousPlayerVarValue = GamePH::PlayerVariables::GetPlayerVar<T>(playerVar);
if (option->GetValue()) {
if (!option->GetPrevValue())
previousPlayerVarValue = GamePH::PlayerVariables::GetPlayerVar<T>(playerVar);
GamePH::PlayerVariables::ChangePlayerVar(playerVar, valueIfTrue);
option->SetPrevValue(true);
} else if (option->GetPrevValue()) {
option->SetPrevValue(false);
GamePH::PlayerVariables::ChangePlayerVar(playerVar, usePreviousVal ? previousPlayerVarValue : valueIfFalse);
}
}
static PlayerVariables* Get();
};
@ -268,6 +290,8 @@ namespace GamePH {
void SetViewCamera(LPVOID viewCam);
float GetTimePlayed();
void ShowUIManager(bool enabled);
float TimerGetSpeedUp();
void TimerSetSpeedUp(float timeScale);
TimeWeather::CSystem* GetTimeWeatherSystem();
static LevelDI* Get();

View File

@ -3,6 +3,7 @@
#include <functional>
#include <set>
#include "MinHook\include\MinHook.h"
#include "print.h"
namespace Hook {
struct DETOUR_INFO {
@ -68,6 +69,8 @@ namespace Hook {
Sleep(250);
}
PrintSuccess("Hooked %s!", name.data());
}
OrigType pOriginal = nullptr;
@ -95,6 +98,8 @@ namespace Hook {
Sleep(250);
}
PrintSuccess("Hooked %s!", name.data());
}
OrigType pOriginal = nullptr;

View File

@ -23,8 +23,8 @@ namespace Menu {
float tpHeightAbovePlayer = 1.35f;
float tpHorizontalDistanceFromPlayer = 0.0f;
Option disablePhotoModeLimits{};
Option disableSafezoneFOVReduction{};
KeyBindOption disablePhotoModeLimits{ VK_NONE };
KeyBindOption disableSafezoneFOVReduction{ VK_NONE };
static const int baseFOV = 57;
static const float baseSafezoneFOVReduction = -10.0f;
@ -104,13 +104,7 @@ namespace Menu {
if (!GamePH::PlayerVariables::gotPlayerVars)
return;
if (disableSafezoneFOVReduction.GetValue()) {
GamePH::PlayerVariables::ChangePlayerVar("CameraDefaultFOVReduction", 0.0f);
disableSafezoneFOVReduction.SetPrevValue(true);
} else if (disableSafezoneFOVReduction.GetPrevValue()) {
disableSafezoneFOVReduction.SetPrevValue(false);
GamePH::PlayerVariables::ChangePlayerVar("CameraDefaultFOVReduction", baseSafezoneFOVReduction);
}
GamePH::PlayerVariables::ManagePlayerVarOption("CameraDefaultFOVReduction", 0.0f, baseSafezoneFOVReduction, &disableSafezoneFOVReduction);
}
static void UpdateDisabledOptions() {
GamePH::LevelDI* iLevel = GamePH::LevelDI::Get();
@ -130,28 +124,24 @@ namespace Menu {
void Tab::Render() {
ImGui::SeparatorText("Free Camera");
ImGui::BeginDisabled(freeCam.GetChangesAreDisabled() || photoMode.GetValue()); {
ImGui::Checkbox("Enabled##FreeCam", &freeCam);
ImGui::CheckboxHotkey("Enabled##FreeCam", &freeCam);
ImGui::EndDisabled();
}
ImGui::Hotkey("##FreeCamToggleKey", freeCam);
ImGui::SliderFloat("Speed##FreeCam", &freeCamSpeed, 0.1f, 200.0f, "%.3f", ImGuiSliderFlags_AlwaysClamp);
ImGui::BeginDisabled(teleportPlayerToCamera.GetChangesAreDisabled()); {
ImGui::Checkbox("Teleport Player to Camera", &teleportPlayerToCamera);
ImGui::CheckboxHotkey("Teleport Player to Camera", &teleportPlayerToCamera);
ImGui::EndDisabled();
}
ImGui::Hotkey("##TeleportPlayerToCamToggleKey", teleportPlayerToCamera);
ImGui::SeparatorText("Third Person Camera");
ImGui::BeginDisabled(thirdPersonCamera.GetChangesAreDisabled()); {
ImGui::Checkbox("Enabled##ThirdPerson", &thirdPersonCamera);
ImGui::CheckboxHotkey("Enabled##ThirdPerson", &thirdPersonCamera);
ImGui::EndDisabled();
}
ImGui::Hotkey("##ThirdPersonToggleKey", thirdPersonCamera);
ImGui::BeginDisabled(tpUseTPPModel.GetChangesAreDisabled()); {
ImGui::Checkbox("Use Third Person Player (TPP) Model", &tpUseTPPModel);
ImGui::CheckboxHotkey("Use Third Person Player (TPP) Model", &tpUseTPPModel);
ImGui::EndDisabled();
}
ImGui::Hotkey("##TPPModelToggleKey", tpUseTPPModel);
ImGui::SliderFloat("Distance behind player", &tpDistanceBehindPlayer, 1.0f, 10.0f);
ImGui::SliderFloat("Height above player", &tpHeightAbovePlayer, 1.0f, 3.0f);
ImGui::SliderFloat("Horizontal distance from player", &tpHorizontalDistanceFromPlayer, -2.0f, 2.0f);
@ -165,8 +155,8 @@ namespace Menu {
FOV = static_cast<int>(pCVideoSettings->extraFOV) + baseFOV;
ImGui::EndDisabled();
}
ImGui::Checkbox("Disable Photo Mode Limits", &disablePhotoModeLimits);
ImGui::Checkbox("Disable Safezone FOV Reduction", &disableSafezoneFOVReduction);
ImGui::CheckboxHotkey("Disable Photo Mode Limits", &disablePhotoModeLimits);
ImGui::CheckboxHotkey("Disable Safezone FOV Reduction", &disableSafezoneFOVReduction);
}
}
}

View File

@ -18,8 +18,8 @@ namespace Menu {
extern float tpHeightAbovePlayer;
extern float tpHorizontalDistanceFromPlayer;
extern Option disablePhotoModeLimits;
extern Option disableSafezoneFOVReduction;
extern KeyBindOption disablePhotoModeLimits;
extern KeyBindOption disableSafezoneFOVReduction;
class Tab : MenuTab {
public:

View File

@ -135,7 +135,7 @@ namespace Menu {
ImGui::Separator();
ImGui::Hotkey("Menu Toggle Key", menuToggle);
ImGui::Hotkey("Menu Toggle Key", &menuToggle);
ImGui::SliderFloat("Menu Transparency", &transparency, 0.0f, 100.0f, "%.1f%%", ImGuiSliderFlags_AlwaysClamp);
if (ImGui::SliderFloat("Menu Scale", &scale, 1.0f, 2.5f, "%.1f%%", ImGuiSliderFlags_AlwaysClamp)) {
ImGui::StyleScaleAllSizes(style, scale);

View File

@ -35,8 +35,7 @@ namespace Menu {
void Tab::Render() {
ImGui::SeparatorText("Misc##Misc");
ImGui::BeginDisabled(disableHUD.GetChangesAreDisabled()); {
ImGui::Checkbox("Disable HUD", &disableHUD);
ImGui::Hotkey("##DisableHUDToggleKey", disableHUD);
ImGui::CheckboxHotkey("Disable HUD", &disableHUD);
ImGui::EndDisabled();
}
}

View File

@ -6003,9 +6003,10 @@ namespace Menu {
float playerMaxHealth = 80.0f;
KeyBindOption godMode{ VK_F6 };
KeyBindOption freezePlayer{ VK_F7 };
Option playerVariables{};
Option disableOutOfBoundsTimer{};
KeyBindOption disableOutOfBoundsTimer{ VK_NONE };
KeyBindOption nightrunnerMode{ VK_F9 };
KeyBindOption oneHandedMode{ VK_NONE };
Option playerVariables{};
std::string saveSCRPath{};
std::string loadSCRFilePath{};
@ -6047,47 +6048,138 @@ namespace Menu {
Utils::str_replace(str, value, newValue);
}
static void SaveVariablesToSCR() {
if (!std::filesystem::exists(saveSCRPath))
return;
std::string tempPlayerVarsSCR = playerVarsSCR;
static void PlayerPositionUpdate() {
Engine::CBulletPhysicsCharacter* playerCharacter = Engine::CBulletPhysicsCharacter::Get();
if (!playerCharacter)
return;
std::istringstream iss(tempPlayerVarsSCR);
std::string line{};
while (std::getline(iss, line)) {
if (freezePlayer.GetValue() || (Camera::freeCam.GetValue() && !Camera::teleportPlayerToCamera.GetValue())) {
playerCharacter->FreezeCharacter();
return;
}
Engine::CBulletPhysicsCharacter::posBeforeFreeze = playerCharacter->playerPos;
if (!Camera::freeCam.GetValue() || !Camera::teleportPlayerToCamera.GetValue())
return;
GamePH::FreeCamera* freeCam = GamePH::FreeCamera::Get();
if (!freeCam)
return;
Vector3 camPos{};
freeCam->GetPosition(&camPos);
if (camPos.isDefault())
return;
playerCharacter->MoveCharacter(camPos);
}
static void PlayerVarsUpdate() {
if (!playerVariables.GetValue())
return;
auto bgn = GamePH::PlayerVariables::playerVars.begin();
for (auto it = bgn; it != GamePH::PlayerVariables::playerVars.end(); ++it) {
if (!it->second.first)
continue;
try {
auto& valDef = GamePH::PlayerVariables::playerVarsDefault.at(it - bgn);
if (it->second.second == "float") {
float* varAddr = reinterpret_cast<float*>(it->second.first);
if (!Utils::are_same(*varAddr, *(varAddr + 1)) && !Utils::are_same(*(varAddr + 1), std::any_cast<float>(valDef.second.first)))
*varAddr = *(varAddr + 1);
} else if (it->second.second == "bool") {
bool* varAddr = reinterpret_cast<bool*>(it->second.first);
if (*varAddr != *(varAddr + 1) && *(varAddr + 1) != std::any_cast<bool>(valDef.second.first))
*varAddr = *(varAddr + 1);
}
} catch (std::out_of_range& e) {
UNREFERENCED_PARAMETER(e);
}
}
}
static void PlayerHealthUpdate() {
GamePH::PlayerHealthModule* playerHealthModule = GamePH::PlayerHealthModule::Get();
if (!playerHealthModule)
return;
playerMaxHealth = playerHealthModule->maxHealth;
if (menuToggle.GetValue())
return;
GamePH::LevelDI* iLevel = GamePH::LevelDI::Get();
if (!iLevel || !iLevel->IsLoaded())
return;
playerHealth = playerHealthModule->health;
}
static void UpdatePlayerVars() {
if (!GamePH::PlayerVariables::gotPlayerVars)
return;
GamePH::PlayerVariables::ManagePlayerVarOption("NightRunnerItemForced", nightrunnerMode.GetValue(), !nightrunnerMode.GetValue(), &nightrunnerMode);
GamePH::PlayerVariables::ManagePlayerVarOption("NightRunnerFurySmashEnabled", nightrunnerMode.GetValue(), !nightrunnerMode.GetValue(), &nightrunnerMode);
GamePH::PlayerVariables::ManagePlayerVarOption("NightRunnerFuryGroundPoundEnabled", nightrunnerMode.GetValue(), !nightrunnerMode.GetValue(), &nightrunnerMode);
GamePH::PlayerVariables::ManagePlayerVarOption("LeftHandDisabled", oneHandedMode.GetValue(), !oneHandedMode.GetValue(), &oneHandedMode);
}
static void UpdateDisabledOptions() {
freezePlayer.SetChangesAreDisabled(!Engine::CBulletPhysicsCharacter::Get());
}
Tab Tab::instance{};
void Tab::Update() {
PlayerPositionUpdate();
PlayerVarsUpdate();
PlayerHealthUpdate();
UpdateDisabledOptions();
UpdatePlayerVars();
}
static void SaveVariablesToSCR() {
if (!std::filesystem::exists(saveSCRPath))
return;
std::string tempPlayerVarsSCR = playerVarsSCR;
std::istringstream iss(tempPlayerVarsSCR);
std::string line{};
while (std::getline(iss, line)) {
const std::string origLine = line;
const std::string paramName = getParamName(line);
if (paramName.empty())
continue;
const std::string paramName = getParamName(line);
if (paramName.empty())
continue;
auto it = std::find_if(GamePH::PlayerVariables::playerVars.begin(), GamePH::PlayerVariables::playerVars.end(), [&paramName](const auto& pair) {
return pair.first == paramName;
});
if (it == GamePH::PlayerVariables::playerVars.end())
continue;
if (it == GamePH::PlayerVariables::playerVars.end())
continue;
if (it->second.second == "float") {
float value = *reinterpret_cast<float*>(it->second.first);
replaceParamValue(line, std::to_string(value));
} else {
bool value = *reinterpret_cast<bool*>(it->second.first);
replaceParamValue(line, value ? "true" : "false");
}
if (it->second.second == "float") {
float value = *reinterpret_cast<float*>(it->second.first);
replaceParamValue(line, std::to_string(value));
} else {
bool value = *reinterpret_cast<bool*>(it->second.first);
replaceParamValue(line, value ? "true" : "false");
}
Utils::str_replace(tempPlayerVarsSCR, origLine, line);
}
}
std::ofstream outFile(std::string(saveSCRPath) + "\\player_variables.scr", std::ios::binary);
std::ofstream outFile(std::string(saveSCRPath) + "\\player_variables.scr", std::ios::binary);
if (!outFile.is_open()) {
ImGui::OpenPopup("Failed saving player variables.");
return;
}
outFile << tempPlayerVarsSCR;
outFile.close();
outFile << tempPlayerVarsSCR;
outFile.close();
ImGui::OpenPopup("Saved player variables!");
}
}
static void LoadPlayerVariablesSCR() {
if (!std::filesystem::exists(loadSCRFilePath))
return;
@ -6169,150 +6261,12 @@ namespace Menu {
else
GamePH::PlayerVariables::ChangePlayerVar(varName, std::any_cast<bool>(itDef->second.first));
}
static void PlayerPositionUpdate() {
Engine::CBulletPhysicsCharacter* playerCharacter = Engine::CBulletPhysicsCharacter::Get();
if (!playerCharacter)
return;
if (freezePlayer.GetValue() || (Camera::freeCam.GetValue() && !Camera::teleportPlayerToCamera.GetValue())) {
playerCharacter->FreezeCharacter();
return;
}
Engine::CBulletPhysicsCharacter::posBeforeFreeze = playerCharacter->playerPos;
if (!Camera::freeCam.GetValue() || !Camera::teleportPlayerToCamera.GetValue())
return;
GamePH::FreeCamera* freeCam = GamePH::FreeCamera::Get();
if (!freeCam)
return;
Vector3 camPos{};
freeCam->GetPosition(&camPos);
if (camPos.isDefault())
return;
playerCharacter->MoveCharacter(camPos);
}
static void PlayerVarsUpdate() {
static void HandlePlayerVariablesList() {
if (!playerVariables.GetValue())
return;
auto bgn = GamePH::PlayerVariables::playerVars.begin();
for (auto it = bgn; it != GamePH::PlayerVariables::playerVars.end(); ++it) {
if (!it->second.first)
continue;
try {
auto& valDef = GamePH::PlayerVariables::playerVarsDefault.at(it - bgn);
if (it->second.second == "float") {
float* varAddr = reinterpret_cast<float*>(it->second.first);
if (!Utils::are_same(*varAddr, *(varAddr + 1)) && !Utils::are_same(*(varAddr + 1), std::any_cast<float>(valDef.second.first)))
*varAddr = *(varAddr + 1);
} else if (it->second.second == "bool") {
bool* varAddr = reinterpret_cast<bool*>(it->second.first);
if (*varAddr != *(varAddr + 1) && *(varAddr + 1) != std::any_cast<bool>(valDef.second.first))
*varAddr = *(varAddr + 1);
}
} catch (std::out_of_range& e) {
UNREFERENCED_PARAMETER(e);
}
}
}
static void PlayerHealthUpdate() {
GamePH::PlayerHealthModule* playerHealthModule = GamePH::PlayerHealthModule::Get();
if (!playerHealthModule)
return;
playerMaxHealth = playerHealthModule->maxHealth;
if (menuToggle.GetValue())
return;
GamePH::LevelDI* iLevel = GamePH::LevelDI::Get();
if (!iLevel || !iLevel->IsLoaded())
return;
playerHealth = playerHealthModule->health;
}
static void UpdatePlayerVars() {
if (!GamePH::PlayerVariables::gotPlayerVars)
return;
static bool previousNightRunnerItemForced{};
static bool previousNightRunnerFurySmashEnabled{};
static bool previousNightRunnerFuryGroundPoundEnabled{};
if (nightrunnerMode.GetValue()) {
if (!nightrunnerMode.GetPrevValue()) {
previousNightRunnerItemForced = GamePH::PlayerVariables::GetPlayerVar<bool>("NightRunnerItemForced");
previousNightRunnerFurySmashEnabled = GamePH::PlayerVariables::GetPlayerVar<bool>("NightRunnerFurySmashEnabled");
previousNightRunnerFuryGroundPoundEnabled = GamePH::PlayerVariables::GetPlayerVar<bool>("NightRunnerFuryGroundPoundEnabled");
}
GamePH::PlayerVariables::ChangePlayerVar("NightRunnerItemForced", true);
GamePH::PlayerVariables::ChangePlayerVar("NightRunnerFurySmashEnabled", true);
GamePH::PlayerVariables::ChangePlayerVar("NightRunnerFuryGroundPoundEnabled", true);
nightrunnerMode.SetPrevValue(true);
} else if (nightrunnerMode.GetPrevValue()) {
nightrunnerMode.SetPrevValue(false);
GamePH::PlayerVariables::ChangePlayerVar("NightRunnerItemForced", previousNightRunnerItemForced);
GamePH::PlayerVariables::ChangePlayerVar("NightRunnerFurySmashEnabled", previousNightRunnerFurySmashEnabled);
GamePH::PlayerVariables::ChangePlayerVar("NightRunnerFuryGroundPoundEnabled", previousNightRunnerFuryGroundPoundEnabled);
}
}
static void UpdateDisabledOptions() {
freezePlayer.SetChangesAreDisabled(!Engine::CBulletPhysicsCharacter::Get());
}
Tab Tab::instance{};
void Tab::Update() {
PlayerPositionUpdate();
PlayerVarsUpdate();
PlayerHealthUpdate();
UpdateDisabledOptions();
UpdatePlayerVars();
}
void Tab::Render() {
ImGui::SeparatorText("Misc");
GamePH::PlayerHealthModule* playerHealthModule = GamePH::PlayerHealthModule::Get();
ImGui::BeginDisabled(!playerHealthModule); {
if (ImGui::SliderFloat("Player Health", &playerHealth, 0.0f, playerMaxHealth, "%.2f") && playerHealthModule)
playerHealthModule->health = playerHealth;
else if (playerHealthModule)
playerHealth = playerHealthModule->health;
ImGui::EndDisabled();
}
ImGui::Checkbox("God Mode", &godMode);
ImGui::Hotkey("##GodModeToggleKey", godMode);
ImGui::SameLine();
ImGui::BeginDisabled(freezePlayer.GetChangesAreDisabled()); {
ImGui::Checkbox("Freeze Player", &freezePlayer);
ImGui::EndDisabled();
}
ImGui::Hotkey("##FreezePlayerToggleKey", freezePlayer);
ImGui::Checkbox("Disable Out of Bounds Timer", &disableOutOfBoundsTimer);
ImGui::Checkbox("Nightrunner Mode", &nightrunnerMode);
ImGui::Hotkey("##NightrunnerModeToggleKey", nightrunnerMode);
ImGui::SeparatorText("Player Jump Parameters");
if (ImGui::Button("Reload Jump Params")) {
if (Utils::FileExistsInDir("jump_parameters.scr", "EGameTools\\FilesToLoad")) {
GamePH::ReloadJumps();
ImGui::OpenPopup("Reloaded player jump parameters!");
} else
ImGui::OpenPopup("Failed reloading player jump parameters.");
}
ImGui::SeparatorText("Player Variables");
ImGui::Checkbox("Enabled##PlayerVars", &playerVariables);
if (!playerVariables.GetValue())
return;
ImGui::BeginDisabled(!GamePH::PlayerVariables::gotPlayerVars); {
ImGui::BeginDisabled(!GamePH::PlayerVariables::gotPlayerVars);
{
if (ImGui::CollapsingHeader("Player variables list", ImGuiTreeNodeFlags_None)) {
ImGui::Indent();
if (ImGui::Button("Save variables to file"))
@ -6331,8 +6285,7 @@ namespace Menu {
SaveVariablesAsDefault();
ImGui::Separator();
ImGui::InputTextWithHint("##VarsSearch", "Search variables", playerVarsSearchFilter, 64);
ImGui::InputTextWithHint("##VarsSearch", "Search variables", playerVarsSearchFilter, 64);
std::string restoreBtnName{};
for (auto const& [key, val] : GamePH::PlayerVariables::playerVars) {
@ -6348,7 +6301,6 @@ namespace Menu {
if (val.second == "float") {
float* varAddr = reinterpret_cast<float*>(val.first);
float newValue = *varAddr;
if (ImGui::InputFloat(key.data(), &newValue)) {
@ -6365,7 +6317,6 @@ namespace Menu {
}
} else if (val.second == "bool") {
bool* varAddr = reinterpret_cast<bool*>(val.first);
bool newValue = *varAddr;
if (ImGui::Checkbox(key.data(), &newValue)) {
@ -6386,7 +6337,8 @@ namespace Menu {
}
ImGui::EndDisabled();
}
}
void HandleDialogs() {
if (ImGuiFileDialog::Instance()->Display("ChooseSCRPath", ImGuiWindowFlags_NoCollapse, ImVec2(600.0f, 400.0f))) {
if (ImGuiFileDialog::Instance()->IsOk()) {
const std::string filePath = ImGuiFileDialog::Instance()->GetCurrentPath();
@ -6453,5 +6405,42 @@ namespace Menu {
ImGui::EndPopup();
}
}
void Tab::Render() {
ImGui::SeparatorText("Misc");
GamePH::PlayerHealthModule* playerHealthModule = GamePH::PlayerHealthModule::Get();
ImGui::BeginDisabled(!playerHealthModule); {
if (ImGui::SliderFloat("Player Health", &playerHealth, 0.0f, playerMaxHealth, "%.2f") && playerHealthModule)
playerHealthModule->health = playerHealth;
else if (playerHealthModule)
playerHealth = playerHealthModule->health;
ImGui::EndDisabled();
}
ImGui::CheckboxHotkey("God Mode", &godMode);
ImGui::SameLine();
ImGui::BeginDisabled(freezePlayer.GetChangesAreDisabled()); {
ImGui::CheckboxHotkey("Freeze Player", &freezePlayer);
ImGui::EndDisabled();
}
ImGui::CheckboxHotkey("Disable Out of Bounds Timer", &disableOutOfBoundsTimer);
ImGui::CheckboxHotkey("Nightrunner Mode", &nightrunnerMode);
ImGui::CheckboxHotkey("One-handed Mode", &oneHandedMode);
ImGui::SeparatorText("Player Jump Parameters");
if (ImGui::Button("Reload Jump Params")) {
if (Utils::FileExistsInDir("jump_parameters.scr", "EGameTools\\FilesToLoad")) {
GamePH::ReloadJumps();
ImGui::OpenPopup("Reloaded player jump parameters!");
} else
ImGui::OpenPopup("Failed reloading player jump parameters.");
}
ImGui::SeparatorText("Player Variables");
ImGui::Checkbox("Enabled##PlayerVars", &playerVariables);
HandlePlayerVariablesList();
HandleDialogs();
}
}
}

View File

@ -9,9 +9,10 @@ namespace Menu {
extern float playerMaxHealth;
extern KeyBindOption godMode;
extern KeyBindOption freezePlayer;
extern Option playerVariables;
extern Option disableOutOfBoundsTimer;
extern KeyBindOption disableOutOfBoundsTimer;
extern KeyBindOption nightrunnerMode;
extern KeyBindOption oneHandedMode;
extern Option playerVariables;
extern std::string saveSCRPath;
extern std::string loadSCRFilePath;

View File

@ -8,7 +8,13 @@ namespace Menu {
namespace World {
float time = 0.0f;
static float timeBeforeFreeze = 0.0f;
float gameSpeed = 1.0f;
static float gameSpeedBeforeSlowMo = gameSpeed;
KeyBindOption freezeTime{ VK_NONE };
KeyBindOption slowMotion{ 'X' };
float slowMotionSpeed = 0.4f;
static float slowMotionSpeedLerp = gameSpeed;
float slowMotionTransitionTime = 1.0f;
EWeather::TYPE weather = EWeather::TYPE::Default;
static const char* const weatherItems[7] = {
@ -21,6 +27,13 @@ namespace Menu {
"Stormy"
};
static void UpdateDisabledOptions() {
GamePH::DayNightCycle* dayNightCycle = GamePH::DayNightCycle::Get();
GamePH::LevelDI* iLevel = GamePH::LevelDI::Get();
freezeTime.SetChangesAreDisabled(!iLevel || !iLevel->IsLoaded() || !dayNightCycle);
slowMotion.SetChangesAreDisabled(!iLevel || !iLevel->IsLoaded() || !dayNightCycle);
}
Tab Tab::instance{};
void Tab::Update() {
GamePH::DayNightCycle* dayNightCycle = GamePH::DayNightCycle::Get();
@ -33,52 +46,87 @@ namespace Menu {
if (freezeTime.HasChangedTo(true)) {
timeBeforeFreeze = time;
freezeTime.SetPrevValue(true);
} else if (freezeTime.HasChangedTo(false)) {
dayNightCycle->SetDaytime(timeBeforeFreeze);
freezeTime.SetPrevValue(false);
}
if (slowMotion.HasChangedTo(false)) {
static bool slowMoHasChanged = true;
slowMotionSpeedLerp = ImGui::AnimateLerp("slowMotionSpeedLerp", slowMotionSpeed, gameSpeedBeforeSlowMo, slowMotionTransitionTime, slowMoHasChanged, &ImGui::AnimEaseOutSine);
iLevel->TimerSetSpeedUp(slowMotionSpeedLerp);
slowMoHasChanged = false;
if (Utils::are_same(gameSpeed, gameSpeedBeforeSlowMo)) {
slowMoHasChanged = true;
slowMotion.SetPrevValue(false);
}
} else if (slowMotion.GetValue()) {
if (slowMotion.HasChanged()) {
gameSpeedBeforeSlowMo = gameSpeed;
slowMotionSpeedLerp = gameSpeed;
}
slowMotionSpeedLerp = ImGui::AnimateLerp("slowMotionSpeedLerp", gameSpeedBeforeSlowMo, slowMotionSpeed, slowMotionTransitionTime, slowMotion.HasChanged(), &ImGui::AnimEaseOutSine);
iLevel->TimerSetSpeedUp(slowMotionSpeedLerp);
if (slowMotion.HasChanged())
slowMotion.SetPrevValue(slowMotion.GetValue());
}
if (!menuToggle.GetValue()) {
if (!freezeTime.GetValue()) {
if (freezeTime.HasChangedTo(false)) {
dayNightCycle->SetDaytime(time);
freezeTime.SetPrevValue(false);
}
time = dayNightCycle->time1 * 24;
} else if (!Utils::are_same(time, timeBeforeFreeze))
time = dayNightCycle->time1 * 24;
if (freezeTime.GetValue() && !Utils::are_same(time, timeBeforeFreeze, 0.009f))
dayNightCycle->SetDaytime(timeBeforeFreeze);
if (!slowMotion.GetValue() && !slowMotion.HasChanged())
iLevel->TimerSetSpeedUp(gameSpeed);
if (!Utils::are_same(iLevel->TimerGetSpeedUp(), 1.0f))
gameSpeed = iLevel->TimerGetSpeedUp();
}
}
void Tab::Render() {
GamePH::DayNightCycle* dayNightCycle = GamePH::DayNightCycle::Get();
GamePH::LevelDI* iLevel = GamePH::LevelDI::Get();
ImGui::SeparatorText("Misc##World");
ImGui::BeginDisabled(!iLevel || !iLevel->IsLoaded() || !dayNightCycle || dayNightCycle->time1 == 0.0f); {
static bool sliderBeingPressed = false;
if (ImGui::SliderFloat("Time", &time, 0.01f, 24.0f, "%.2f", ImGuiSliderFlags_AlwaysClamp) && dayNightCycle)
sliderBeingPressed = true;
else if (dayNightCycle) {
if (sliderBeingPressed) {
sliderBeingPressed = false;
ImGui::SeparatorText("Time##World");
ImGui::BeginDisabled(!iLevel || !iLevel->IsLoaded() || !dayNightCycle); {
static bool timeSliderBeingPressed = false;
if (ImGui::SliderFloat("Time", &time, 0.01f, 24.0f, "%.2f", ImGuiSliderFlags_AlwaysClamp))
timeSliderBeingPressed = true;
else if (iLevel && iLevel->IsLoaded() && dayNightCycle) {
if (timeSliderBeingPressed) {
timeSliderBeingPressed = false;
timeBeforeFreeze = time;
dayNightCycle->SetDaytime(time);
}
if (!freezeTime.GetValue()) {
if (freezeTime.HasChangedTo(false)) {
dayNightCycle->SetDaytime(timeBeforeFreeze);
freezeTime.SetPrevValue(false);
}
time = dayNightCycle->time1 * 24;
} else if (!Utils::are_same(time, timeBeforeFreeze))
time = dayNightCycle->time1 * 24;
if (freezeTime.GetValue() && !Utils::are_same(time, timeBeforeFreeze, 0.009f))
dayNightCycle->SetDaytime(timeBeforeFreeze);
}
ImGui::Checkbox("Freeze Time", &freezeTime);
ImGui::Hotkey("##FreezeTimeToggleKey", freezeTime);
ImGui::BeginDisabled(slowMotion.GetValue()); {
if (ImGui::SliderFloat("Game Speed", &gameSpeed, 0.0f, 2.0f, "%.2f"))
iLevel->TimerSetSpeedUp(gameSpeed);
else if (iLevel && iLevel->IsLoaded()) {
if (!slowMotion.GetValue() && !slowMotion.HasChanged())
iLevel->TimerSetSpeedUp(gameSpeed);
if (!Utils::are_same(iLevel->TimerGetSpeedUp(), 1.0f))
gameSpeed = iLevel->TimerGetSpeedUp();
}
ImGui::EndDisabled();
}
ImGui::CheckboxHotkey("Freeze Time", &freezeTime);
ImGui::SameLine();
ImGui::CheckboxHotkey("Slow Motion", &slowMotion);
ImGui::EndDisabled();
}
ImGui::SliderFloat("Slow Motion Speed", &slowMotionSpeed, 0.01f, 0.99f, "%.2f", ImGuiSliderFlags_AlwaysClamp);
ImGui::SliderFloat("Slow Motion Transition Time", &slowMotionTransitionTime, 0.00f, 5.00f, "%.2f", ImGuiSliderFlags_AlwaysClamp);
GamePH::TimeWeather::CSystem* timeWeatherSystem = GamePH::TimeWeather::CSystem::Get();
const bool weatherDisabledFlag = !iLevel || !iLevel->IsLoaded() || !timeWeatherSystem;
ImGui::SeparatorText("Weather");
ImGui::SeparatorText("Weather##World");
ImGui::BeginDisabled(weatherDisabledFlag); {
if (ImGui::Combo("Weather", reinterpret_cast<int*>(&weather), weatherItems, IM_ARRAYSIZE(weatherItems)) && timeWeatherSystem)
timeWeatherSystem->SetForcedWeather(static_cast<EWeather::TYPE>(weather - 1));

View File

@ -5,7 +5,11 @@
namespace Menu {
namespace World {
extern float time;
extern float gameSpeed;
extern KeyBindOption freezeTime;
extern KeyBindOption slowMotion;
extern float slowMotionSpeed;
extern float slowMotionTransitionTime;
extern EWeather::TYPE weather;

View File

@ -62,6 +62,7 @@ struct Offsets {
//AddOffset(CalculateOutOfBoundsTimer, "gamedll_ph_x64_rwdi.dll", "48 89 5C 24 ?? 48 89 74 24 ?? 57 48 81 EC ?? ?? ?? ?? 0F B6 99", PatternType::Address, LPVOID)
AddOffset(IsNotOutOfBounds, "gamedll_ph_x64_rwdi.dll", "48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 41 56 41 57 48 83 EC ?? 4C 8B F9 48 85 D2", PatternType::Address, LPVOID)
AddOffset(ReloadJumps, "gamedll_ph_x64_rwdi.dll", "48 83 EC ?? E8 ?? ?? ?? ?? 48 8D 15", PatternType::Address, LPVOID)
AddOffset(PlaySoundEvent, "gamedll_ph_x64_rwdi.dll", "4C 8B DC 49 89 5B ?? 49 89 73 ?? 57 48 81 EC ?? ?? ?? ?? 4C 8B 4C 24 ?? 48 8B F9 4D 8B D0 66 C7 84 24 ?? ?? ?? ?? ?? ?? 49 8B C1 66 C7 84 24", PatternType::Address, LPVOID)
//AddOffset(GetTimeWeatherSystem, "engine_x64_rwdi.dll", "E8 [?? ?? ?? ?? 33 D2 48 8B C8 E8 ?? ?? ?? ?? 49 8D 4F 38", PatternType::RelativePointer, LPVOID)
//AddOffset(SetForcedWeather, "engine_x64_rwdi.dll", "89 51 68 C3 CC CC CC CC CC CC CC CC CC CC CC CC", PatternType::Address, LPVOID)
//AddOffset(GetCurrentWeather, "engine_x64_rwdi.dll", "48 8B 41 78 48 85 C0 75 0F", PatternType::Address, LPVOID)

View File

@ -40,8 +40,12 @@ namespace Utils {
return timePassed;
}
bool are_same(float a, float b) {
return abs(a - b) < 0.0001f;
bool are_same(float a, float b, float precision) {
return abs(a - b) < precision;
}
float round_dec(float value, int decimal_places) {
const float multiplier = std::pow(10.0f, decimal_places);
return std::roundf(value * multiplier) / multiplier;
}
bool str_replace(std::string& str, const std::string& from, const std::string& to) {
@ -75,15 +79,27 @@ namespace Utils {
return path;
}
std::filesystem::path GetCurrentProcDirectoryFS() {
char buffer[MAX_PATH];
GetModuleFileNameA(nullptr, buffer, sizeof(buffer));
return std::filesystem::path(buffer).parent_path();
}
std::string GetCurrentProcDirectory() {
char buffer[MAX_PATH];
GetModuleFileNameA(nullptr, buffer, sizeof(buffer));
return std::filesystem::path(buffer).parent_path().string();
}
bool FileExistsInDir(const char* fileName, const char* dir) {
for (const auto& entry : std::filesystem::directory_iterator(dir)) {
if (entry.path().filename().string() == fileName)
return true;
for (const auto& entry : std::filesystem::recursive_directory_iterator(dir)) {
const std::filesystem::path pathToFile = entry.path();
if (!std::filesystem::is_regular_file(pathToFile))
continue;
const std::filesystem::path pathToFilename = pathToFile.filename();
if (!pathToFilename.string().contains(fileName))
continue;
return true;
}
return false;
}

View File

@ -25,7 +25,8 @@ namespace Utils {
bool timePassed;
};
extern bool are_same(float a, float b);
extern bool are_same(float a, float b, float precision = 0.0001f);
extern float round_dec(float value, int decimal_places = 2);
extern bool str_replace(std::string& str, const std::string& from, const std::string& to);
template <typename T>
@ -40,6 +41,7 @@ namespace Utils {
extern std::string_view GetDesktopDir();
extern std::string_view GetDocumentsDir();
extern std::filesystem::path GetCurrentProcDirectoryFS();
extern std::string GetCurrentProcDirectory();
extern bool FileExistsInDir(const char* fileName, const char* dir);
extern WindowsVersion GetWindowsVersion();