diff --git a/DL2GameOverhaulScript/DL2GameOverhaulScript.vcxproj b/DL2GameOverhaulScript/DL2GameOverhaulScript.vcxproj index aa5d2f3..f84411a 100644 --- a/DL2GameOverhaulScript/DL2GameOverhaulScript.vcxproj +++ b/DL2GameOverhaulScript/DL2GameOverhaulScript.vcxproj @@ -91,6 +91,7 @@ + @@ -167,6 +168,7 @@ + diff --git a/DL2GameOverhaulScript/DL2GameOverhaulScript.vcxproj.filters b/DL2GameOverhaulScript/DL2GameOverhaulScript.vcxproj.filters index b093d85..054786c 100644 --- a/DL2GameOverhaulScript/DL2GameOverhaulScript.vcxproj.filters +++ b/DL2GameOverhaulScript/DL2GameOverhaulScript.vcxproj.filters @@ -188,6 +188,9 @@ ImGui\misc\freetype + + menu + @@ -402,6 +405,9 @@ ImGui\misc\freetype + + menu + diff --git a/DL2GameOverhaulScript/pch/pch.h b/DL2GameOverhaulScript/pch/pch.h index 8f5ecdb..80530a8 100644 --- a/DL2GameOverhaulScript/pch/pch.h +++ b/DL2GameOverhaulScript/pch/pch.h @@ -49,10 +49,10 @@ #include #include #include -#include +#include +#include #include #include -#include #include #include #include diff --git a/DL2GameOverhaulScript/source/ImGui/ImGuiFileDialog/ImGuiFileDialog.cpp b/DL2GameOverhaulScript/source/ImGui/ImGuiFileDialog/ImGuiFileDialog.cpp index aa483f7..7ab9523 100644 --- a/DL2GameOverhaulScript/source/ImGui/ImGuiFileDialog/ImGuiFileDialog.cpp +++ b/DL2GameOverhaulScript/source/ImGui/ImGuiFileDialog/ImGuiFileDialog.cpp @@ -70,7 +70,7 @@ SOFTWARE. #ifdef USE_STD_FILESYSTEM #include #else -#include "dirent/dirent.h" // directly open the dirent file attached to this lib +#include // directly open the dirent file attached to this lib #endif // USE_STD_FILESYSTEM #define PATH_SEP '\\' #ifndef PATH_MAX diff --git a/DL2GameOverhaulScript/source/ImGui/freetype/lib/freetype-mtd.lib b/DL2GameOverhaulScript/source/ImGui/freetype/lib/freetype-mtd.lib index 060b898..862ee74 100644 Binary files a/DL2GameOverhaulScript/source/ImGui/freetype/lib/freetype-mtd.lib and b/DL2GameOverhaulScript/source/ImGui/freetype/lib/freetype-mtd.lib differ diff --git a/DL2GameOverhaulScript/source/ImGui/imguiex.cpp b/DL2GameOverhaulScript/source/ImGui/imguiex.cpp index 081204a..c584ceb 100644 --- a/DL2GameOverhaulScript/source/ImGui/imguiex.cpp +++ b/DL2GameOverhaulScript/source/ImGui/imguiex.cpp @@ -4,6 +4,8 @@ namespace ImGui { static ImGuiStyle defImGuiStyle{}; + static size_t tabIndex = 1; + void StyleScaleAllSizes(ImGuiStyle* style, const float scale_factor, ImGuiStyle* defStyle) { if (!defStyle) defStyle = &defImGuiStyle; @@ -33,13 +35,17 @@ namespace ImGui { style->DisplaySafeAreaPadding = ImFloor(defStyle->DisplaySafeAreaPadding * scale_factor); style->MouseCursorScale = ImFloor(defStyle->MouseCursorScale * scale_factor); } - void SpanTabsAcrossWidth(const float width, const size_t tabs) { + void SpanNextTabAcrossWidth(const float width, const size_t tabs) { if (width <= 0.0f) return; const float oneTabWidthWithSpacing = width / tabs; - const float oneTabWidth = oneTabWidthWithSpacing - (GImGui->Style.ItemSpacing.x / 2.0f); + const float oneTabWidth = oneTabWidthWithSpacing - (tabIndex == tabs ? 0.0f : GImGui->Style.ItemSpacing.x / 2.0f); ImGui::SetNextItemWidth(oneTabWidth); + } + void EndTabBarEx() { + ImGui::EndTabBar(); + tabIndex = 1; } bool Checkbox(const char* label, Option* v) { ImGuiWindow* window = GetCurrentWindow(); diff --git a/DL2GameOverhaulScript/source/ImGui/imguiex.h b/DL2GameOverhaulScript/source/ImGui/imguiex.h index 3860506..897e1be 100644 --- a/DL2GameOverhaulScript/source/ImGui/imguiex.h +++ b/DL2GameOverhaulScript/source/ImGui/imguiex.h @@ -3,7 +3,8 @@ namespace ImGui { extern void StyleScaleAllSizes(ImGuiStyle* style, const float scale_factor, ImGuiStyle* defStyle = nullptr); - extern void SpanTabsAcrossWidth(const float width, const size_t tabs = 1); + extern void SpanNextTabAcrossWidth(const float width, const size_t tabs = 1); + extern void EndTabBarEx(); extern bool Checkbox(const char* label, Option* v); extern bool CheckboxHotkey(const char* label, KeyBindOption* v); extern void TextCentered(const char* text, const bool calculateWithScrollbar = true); diff --git a/DL2GameOverhaulScript/source/ImGui/impl/d3d11_impl.cpp b/DL2GameOverhaulScript/source/ImGui/impl/d3d11_impl.cpp index 988c968..12df38b 100644 --- a/DL2GameOverhaulScript/source/ImGui/impl/d3d11_impl.cpp +++ b/DL2GameOverhaulScript/source/ImGui/impl/d3d11_impl.cpp @@ -1,5 +1,6 @@ #include #include "..\menu\menu.h" +#include "..\menu\init.h" namespace impl { namespace d3d11 { @@ -29,7 +30,7 @@ namespace impl { ImGui_ImplWin32_Init(desc.OutputWindow); ImGui_ImplDX11_Init(d3d11Device, d3d11DeviceContext); - Menu::InitImGuiStyle(); + Menu::InitImGui(); init = true; } diff --git a/DL2GameOverhaulScript/source/ImGui/impl/d3d12_impl.cpp b/DL2GameOverhaulScript/source/ImGui/impl/d3d12_impl.cpp index 0b94c28..fa93e37 100644 --- a/DL2GameOverhaulScript/source/ImGui/impl/d3d12_impl.cpp +++ b/DL2GameOverhaulScript/source/ImGui/impl/d3d12_impl.cpp @@ -1,5 +1,6 @@ #include #include "..\menu\menu.h" +#include "..\menu\init.h" namespace impl { namespace d3d12 { @@ -98,7 +99,7 @@ namespace impl { ImGui_ImplDX12_Init(d3d12Device, buffersCounts, DXGI_FORMAT_R8G8B8A8_UNORM, d3d12DescriptorHeapImGuiRender, d3d12DescriptorHeapImGuiRender->GetCPUDescriptorHandleForHeapStart(), d3d12DescriptorHeapImGuiRender->GetGPUDescriptorHandleForHeapStart()); ImGui_ImplDX12_CreateDeviceObjects(); - Menu::InitImGuiStyle(); + Menu::InitImGui(); ImGui_ImplDX12_InvalidateDeviceObjects(); init = true; diff --git a/DL2GameOverhaulScript/source/game/GamePH/PlayerVariables.h b/DL2GameOverhaulScript/source/game/GamePH/PlayerVariables.h index 1a04cb1..b360e36 100644 --- a/DL2GameOverhaulScript/source/game/GamePH/PlayerVariables.h +++ b/DL2GameOverhaulScript/source/game/GamePH/PlayerVariables.h @@ -17,6 +17,16 @@ namespace GamePH { static void GetPlayerVars(); static void SortPlayerVars(); + template static T getDefaultValue() { + if constexpr (std::is_same::value) + return {}; + else if constexpr (std::is_same::value) + return false; + else if constexpr (std::is_same::value) + return -404.0f; + else + return T(); + } template static T GetPlayerVar(const std::string& playerVar) { static_assert(std::is_same::value || std::is_same::value || std::is_same::value, "Invalid type: value must be bool, float or string"); @@ -24,14 +34,8 @@ namespace GamePH { return pair.first == playerVar; }); - if (it == PlayerVariables::playerVars.end()) { - if (std::is_same::value) - return {}; - else if (std::is_same::value) - return -404.0f; - else - return false; - } + if (it == PlayerVariables::playerVars.end()) + return getDefaultValue(); return *reinterpret_cast(it->second.first); } diff --git a/DL2GameOverhaulScript/source/menu/debug.cpp b/DL2GameOverhaulScript/source/menu/debug.cpp index 786f01f..e2bc5ef 100644 --- a/DL2GameOverhaulScript/source/menu/debug.cpp +++ b/DL2GameOverhaulScript/source/menu/debug.cpp @@ -31,42 +31,77 @@ namespace Menu { namespace Debug { + static const std::vector> GamePHClassAddrMap = { + { "TimeWeather\\CSystem", reinterpret_cast(&GamePH::TimeWeather::CSystem::Get)}, + { "DayNightCycle", reinterpret_cast(&GamePH::DayNightCycle::Get) }, + { "FreeCamera", reinterpret_cast(&GamePH::FreeCamera::Get) }, + { "GameDI_PH", reinterpret_cast(&GamePH::GameDI_PH::Get) }, + { "GameDI_PH2", reinterpret_cast(&GamePH::GameDI_PH2::Get) }, + { "gen_TPPModel", reinterpret_cast(&GamePH::gen_TPPModel::Get) }, + { "LevelDI", reinterpret_cast(&GamePH::LevelDI::Get) }, + { "LocalClientDI", reinterpret_cast(&GamePH::LocalClientDI::Get) }, + { "LogicalPlayer", reinterpret_cast(&GamePH::LogicalPlayer::Get) }, + { "PlayerDI_PH", reinterpret_cast(&GamePH::PlayerDI_PH::Get) }, + { "PlayerHealthModule", reinterpret_cast(&GamePH::PlayerHealthModule::Get) }, + { "PlayerObjProperties", reinterpret_cast(&GamePH::PlayerObjProperties::Get) }, + { "PlayerState", reinterpret_cast(&GamePH::PlayerState::Get) }, + { "PlayerVariables", reinterpret_cast(&GamePH::PlayerVariables::Get) }, + { "SessionCooperativeDI", reinterpret_cast(&GamePH::SessionCooperativeDI::Get) }, + { "TPPCameraDI", reinterpret_cast(&GamePH::TPPCameraDI::Get) } + }; + static const std::vector> EngineClassAddrMap = { + { "CBulletPhysicsCharacter", reinterpret_cast(&Engine::CBulletPhysicsCharacter::Get) }, + { "CGSObject", reinterpret_cast(&Engine::CGSObject::Get) }, + { "CGSObject2", reinterpret_cast(&Engine::CGSObject2::Get) }, + { "CGame", reinterpret_cast(&Engine::CGame::Get) }, + { "CInput", reinterpret_cast(&Engine::CInput::Get) }, + { "CLevel", reinterpret_cast(&Engine::CLevel::Get) }, + { "CLevel2", reinterpret_cast(&Engine::CLevel2::Get) }, + { "CLobbySteam", reinterpret_cast(&Engine::CLobbySteam::Get) }, + { "CVideoSettings", reinterpret_cast(&Engine::CVideoSettings::Get) }, + { "CoPhysicsProperty", reinterpret_cast(&Engine::CoPhysicsProperty::Get) } + }; + + static void RenderClassAddrPair(const std::pair* pair) { + static float maxInputTextWidth = ImGui::CalcTextSize("0x0000000000000000").x; + static std::string labelID{}; + labelID = "##DebugAddrInputText" + std::string(pair->first); + + std::stringstream ss{}; + if (pair->second()) + ss << "0x" << std::uppercase << std::hex << reinterpret_cast(pair->second()); + else + ss << "NULL"; + + static std::string addrString{}; + addrString = ss.str(); + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ((ImGui::GetFrameHeight() - ImGui::GetTextLineHeight()) / 2.0f)); + ImGui::Text(pair->first.data()); + + ImGui::SameLine(); + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() - ((ImGui::GetFrameHeight() - ImGui::GetTextLineHeight()) / 2.0f)); + ImGui::SetNextItemWidth(maxInputTextWidth); + ImGui::PushStyleColor(ImGuiCol_Text, pair->second() ? IM_COL32(0, 255, 0, 255) : IM_COL32(255, 0, 0, 255)); + ImGui::InputText(labelID.c_str(), const_cast(addrString.c_str()), strlen(addrString.c_str()), ImGuiInputTextFlags_ReadOnly); + ImGui::PopStyleColor(); + } + Tab Tab::instance{}; void Tab::Update() {} void Tab::Render() { ImGui::SeparatorText("Class addresses##Debug"); if (ImGui::CollapsingHeader("GamePH", ImGuiTreeNodeFlags_None)) { ImGui::Indent(); - ImGui::Text("TimeWeather\\CSystem: 0x%p", GamePH::TimeWeather::CSystem::Get()); - ImGui::Text("DayNightCycle: 0x%p", GamePH::DayNightCycle::Get()); - ImGui::Text("FreeCamera: 0x%p", GamePH::FreeCamera::Get()); - ImGui::Text("GameDI_PH: 0x%p", GamePH::GameDI_PH::Get()); - ImGui::Text("GameDI_PH2: 0x%p", GamePH::GameDI_PH2::Get()); - ImGui::Text("gen_TPPModel: 0x%p", GamePH::gen_TPPModel::Get()); - ImGui::Text("LevelDI: 0x%p", GamePH::LevelDI::Get()); - ImGui::Text("LocalClientDI: 0x%p", GamePH::LocalClientDI::Get()); - ImGui::Text("LogicalPlayer: 0x%p", GamePH::LogicalPlayer::Get()); - ImGui::Text("PlayerDI_PH: 0x%p", GamePH::PlayerDI_PH::Get()); - ImGui::Text("PlayerHealthModule: 0x%p", GamePH::PlayerHealthModule::Get()); - ImGui::Text("PlayerObjProperties: 0x%p", GamePH::PlayerObjProperties::Get()); - ImGui::Text("PlayerState: 0x%p", GamePH::PlayerState::Get()); - ImGui::Text("PlayerVariables: 0x%p", GamePH::PlayerVariables::Get()); - ImGui::Text("SessionCooperativeDI: 0x%p", GamePH::SessionCooperativeDI::Get()); - ImGui::Text("TPPCameraDI: 0x%p", GamePH::TPPCameraDI::Get()); + for (auto& pair : GamePHClassAddrMap) + RenderClassAddrPair(&pair); ImGui::Unindent(); } if (ImGui::CollapsingHeader("Engine", ImGuiTreeNodeFlags_None)) { ImGui::Indent(); - ImGui::Text("CBulletPhysicsCharacter: 0x%p", Engine::CBulletPhysicsCharacter::Get()); - ImGui::Text("CGSObject: 0x%p", Engine::CGSObject::Get()); - ImGui::Text("CGSObject2: 0x%p", Engine::CGSObject2::Get()); - ImGui::Text("CGame: 0x%p", Engine::CGame::Get()); - ImGui::Text("CInput: 0x%p", Engine::CInput::Get()); - ImGui::Text("CLevel: 0x%p", Engine::CLevel::Get()); - ImGui::Text("CLevel2: 0x%p", Engine::CLevel2::Get()); - ImGui::Text("CLobbySteam: 0x%p", Engine::CLobbySteam::Get()); - ImGui::Text("CVideoSettings: 0x%p", Engine::CVideoSettings::Get()); - ImGui::Text("CoPhysicsProperty: 0x%p", Engine::CoPhysicsProperty::Get()); + for (auto& pair : EngineClassAddrMap) + RenderClassAddrPair(&pair); ImGui::Unindent(); } } diff --git a/DL2GameOverhaulScript/source/menu/init.cpp b/DL2GameOverhaulScript/source/menu/init.cpp new file mode 100644 index 0000000..5fb9c2d --- /dev/null +++ b/DL2GameOverhaulScript/source/menu/init.cpp @@ -0,0 +1,262 @@ +#include +#include "..\changelog.h" +#include "..\game\GamePH\Other.h" +#include "menu.h" + +namespace Menu { + static const std::string welcomeTitle = std::string(title + " - Welcome!"); + static const std::string changelogTitle = std::string(title + " - Update Changelog"); + + static constexpr ImGuiWindowFlags welcomeWindowFlags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove; + static constexpr ImVec2 minChangelogWndSize = ImVec2(400.0f, 0.0f); + static constexpr ImVec2 defMaxChangelogWndSize = ImVec2(400.0f, 700.0f); + static constexpr ImVec2 minWelcomeWndSize = ImVec2(800.0f, 0.0f); + static constexpr ImVec2 defMaxWelcomeWndSize = ImVec2(800.0f, 700.0f); + + static Utils::Time::Timer timePassedFromWelcomeScreen{}; + + static void CreateChangelogFile() { + const std::string localAppDataDir = Utils::Files::GetLocalAppDataDir(); + if (localAppDataDir.empty()) + return; + const std::string dirPath = std::string(localAppDataDir) + "\\EGameTools\\"; + std::filesystem::create_directories(dirPath); + + const std::string finalPath = dirPath + MOD_VERSION_STR + ".changelog"; + if (!std::filesystem::exists(finalPath)) { + std::ofstream outFile(finalPath.c_str(), std::ios::binary); + if (!outFile.is_open()) + return; + outFile.close(); + } + } + static bool DoesChangelogFileExist() { + const std::string localAppDataDir = Utils::Files::GetLocalAppDataDir(); + if (localAppDataDir.empty()) + return false; + return std::filesystem::exists(std::string(localAppDataDir) + "\\EGameTools\\" + MOD_VERSION_STR + ".changelog"); + } + + static void RenderWelcomeScreen() { + ImGui::SetNextWindowBgAlpha(1.0f); + ImGui::SetNextWindowSizeConstraints(minWelcomeWndSize, defMaxWelcomeWndSize); + if (ImGui::BeginPopupModal(welcomeTitle.c_str(), nullptr, welcomeWindowFlags)) { + ImGui::TextCenteredColored("PLEASE read the following text!", IM_COL32(230, 0, 0, 255)); + ImGui::Spacing(ImVec2(0.0f, 5.0f)); + + const std::string thankYou = "Thank you for downloading EGameTools (" + std::string(MOD_VERSION_STR) + ")!"; + ImGui::TextCentered(thankYou.c_str()); + ImGui::Spacing(ImVec2(0.0f, 5.0f)); + + const std::string gameCompat = "This version of the mod is compatible with game version " + std::string(GAME_VER_COMPAT_STR) + "."; + ImGui::TextCentered(gameCompat.c_str()); + const std::string gameVer = "The game version you are currently running is v" + GamePH::GetCurrentGameVersionStr() + "."; + ImGui::TextCentered(gameVer.c_str()); + const std::string gameTestedVer = "This mod has last been tested with version v" + GamePH::GameVerToStr(GAME_VER_COMPAT) + "."; + ImGui::TextCentered(gameTestedVer.c_str()); + if (GamePH::GetCurrentGameVersion() < 11400 || GamePH::GetCurrentGameVersion() > GAME_VER_COMPAT) { + const std::string gameNotCompat = "Please note that your game version has not been officially tested with this mod, therefore expect bugs, glitches or the mod to completely stop working. If so, please " + std::string(GamePH::GetCurrentGameVersion() > GAME_VER_COMPAT ? "wait for a new patch." : "upgrade your game version to one that the mod supports."); + ImGui::TextCenteredColored(gameNotCompat.c_str(), IM_COL32(200, 0, 0, 255)); + } + ImGui::Spacing(ImVec2(0.0f, 5.0f)); + ImGui::TextCentered("I will not bore you with what this mod is about, so let's get right to teaching you how to use it!"); + + ImGui::SeparatorTextColored("Menu Toggle", IM_COL32(200, 0, 0, 255)); + ImGui::NewLine(); + ImGui::TextCentered("The default key for opening/closing the menu is F5. You can use your mouse to navigate the menu."); + ImGui::TextCentered("To change it, you can open up the menu and change the hotkey by clicking the hotkey button for \"Menu Toggle Key\" and then pressing a key on your keyboard."); + + ImGui::SeparatorTextColored("FreeCam", IM_COL32(200, 0, 0, 255)); + ImGui::NewLine(); + ImGui::TextCentered("While using FreeCam, you can press Shift or Alt to boost your speed or slow you down respectively."); + ImGui::TextCentered("You can also use the scroll wheel to change FreeCam speed while FreeCam is enabled."); + + ImGui::SeparatorTextColored("Menu Sliders", IM_COL32(200, 0, 0, 255)); + ImGui::NewLine(); + ImGui::TextCentered("To manually change the value of a slider option, hold \"CTRL\" while clicking the slider."); + ImGui::TextCentered("This will let you input a value manually into the slider, which can also go beyond the option's slider limit, given I allow the option to do so."); + + ImGui::SeparatorTextColored("Custom File Loading", IM_COL32(200, 0, 0, 255)); + ImGui::NewLine(); + ImGui::TextCentered("The mod always creates a folder \"EGameTools\\UserModFiles\" inside the same folder as the game executable (exe) or in the same folder as the mod file."); + ImGui::TextCentered("This folder is used for custom file loading. This has only been tested with a few mods that change some .scr files, gpufx files, and other files included inside .pak game archives, or files like .rpack files."); + ImGui::TextCentered("Files in this folder must have the same names as the ones from the game files, otherwise the game won't know it should load those files. Files in subfolders of the \"EGameTools\\UserModFiles\" folder will automatically be detected, so you can sort all your mods in different folders!"); + ImGui::Spacing(ImVec2(0.0f, 5.0f)); + ImGui::TextCentered("The game will reload a lot of the files upon a load of your savegame, so if you want to edit those files and reload them without having to restart the game, just reload your savegame and the game should automatically reload most of those files!"); + ImGui::TextCentered("Just make sure that if you add new, additional files while you're in-game, please wait AT LEAST 5 seconds before reloading your savegame, otherwise additional files will not get detected."); + ImGui::TextCentered("Also, if there are multiple files of the same exact name, the game will pick the first instance of that file it finds in the folder."); + ImGui::Spacing(ImVec2(0.0f, 5.0f)); + ImGui::TextCentered("The gist of it is, you now don't have to use dataX.pak mods anymore! You can open the pak files, extract their files in the \"EGameTools\\UserModFiles\" folder and start the game!"); + ImGui::Spacing(ImVec2(0.0f, 5.0f)); + ImGui::TextCenteredColored("FOR MOD DEVELOPERS", IM_COL32(200, 0, 0, 255)); + ImGui::TextCentered("If you want to make mods for EGameTools to load, please try to use as few folders as you possibly can. For example, your mod should only have one folder, something like \"EGameTools\\UserModFiles\\2019 Weather Mod\"."); + ImGui::TextCentered("The reason is, my mod continuously checks for new files in the directory, and many folders can slow down the process, and therefore slow down game loading times. So just keep this in mind!"); + ImGui::Spacing(ImVec2(0.0f, 5.0f)); + ImGui::TextCentered("If you want to officially include one of your mods as part of EGameTools, please contact me on NexusMods or on Discord (@EricPlayZ)."); + + ImGui::SeparatorTextColored("Game Variables Reloading", IM_COL32(200, 0, 0, 255)); + ImGui::NewLine(); + ImGui::TextCentered("You can also reload Player Variables from a file specified by you, or reload Jump Parameters from \"EGameTools\\UserModFiles\"."); + + ImGui::SeparatorTextColored("Hotkeys", IM_COL32(200, 0, 0, 255)); + ImGui::NewLine(); + ImGui::TextCentered("Most mod menu options are toggleable by a hotkey that you can change by clicking the hotkey button for the respective option and then pressing a key on your keyboard."); + ImGui::TextCentered("To change those hotkeys through the config file, visit the \"Virtual-Key Codes\" page from Microsoft which contains a list of all virtual key codes. Simply write the name of the keycode you want to use for each hotkey and save the config file."); + + ImGui::SeparatorTextColored("Config", IM_COL32(200, 0, 0, 255)); + ImGui::NewLine(); + ImGui::TextCentered("A config file \"EGameTools.ini\" is stored in the same folder as the game executable (exe) or in the same folder as the mod file."); + ImGui::TextCentered("The config file stores the mod menu's options and hotkeys."); + + ImGui::Spacing(ImVec2(0.0f, 5.0f)); + + ImGui::TextCentered("Changes to the mod menu or to the config file are always automatically saved or refreshed respectively."); + ImGui::TextCentered("You DO NOT NEED to restart the game for the changes in the config to be applied!"); + ImGui::TextCentered("If you want to regenerate the config file, delete it and it will automatically be regenerated."); + + ImGui::Separator(); + ImGui::NewLine(); + ImGui::TextCentered("Finally, if you've got any issue, no matter how small, please make sure to report it! I will try my best to fix it. I want this mod to be polished and enjoyable to use!"); + ImGui::TextCentered("If you've got any suggestions for how I could improve the mod, in terms of UI, features, among other things, please let me know!"); + ImGui::Spacing(ImVec2(0.0f, 5.0f)); + + ImGui::BeginDisabled(!timePassedFromWelcomeScreen.DidTimePass()); + { + const std::string btnText = "Let me play!" + (!timePassedFromWelcomeScreen.DidTimePass() ? (" (" + std::to_string(10 - (timePassedFromWelcomeScreen.GetTimePassed() / 1000)) + ")") : ""); + if (ImGui::ButtonCentered(btnText.c_str(), ImVec2(0.0f, 30.0f))) { + ImGui::CloseCurrentPopup(); + firstTimeRunning.Set(false); + if (hasSeenChangelog.GetValue()) + menuToggle.SetChangesAreDisabled(false); + } + ImGui::EndDisabled(); + } + ImGui::EndPopup(); + } + } + static void RenderChangelog() { + ImGui::SetNextWindowBgAlpha(1.0f); + ImGui::SetNextWindowSizeConstraints(minChangelogWndSize, defMaxChangelogWndSize); + if (ImGui::BeginPopupModal(changelogTitle.c_str(), nullptr, welcomeWindowFlags)) { + const std::string subTitle = "This is what the " + std::string(MOD_VERSION_STR) + " update brings:"; + ImGui::TextCenteredColored(subTitle.c_str(), IM_COL32(230, 0, 0, 255), false); + ImGui::Spacing(ImVec2(0.0f, 5.0f)); + + std::istringstream iss(Changelog::changelogs[MOD_VERSION_STR]); + std::string line{}; + while (std::getline(iss, line)) { + if (line.empty()) { + ImGui::NewLine(); + continue; + } + ImGui::TextCentered(line.c_str(), false); + } + + if (ImGui::ButtonCentered("Close", ImVec2(0.0f, 30.0f))) { + ImGui::CloseCurrentPopup(); + menuToggle.SetChangesAreDisabled(false); + hasSeenChangelog.Set(true); + firstTimeRunning.Set(false); + CreateChangelogFile(); + } + ImGui::EndPopup(); + } + } + void FirstTimeRunning() { + static bool firstTimeRunningFunc = true; + if (firstTimeRunningFunc) + hasSeenChangelog.SetBothValues(hasSeenChangelog.GetValue() && DoesChangelogFileExist()); + + if (hasSeenChangelog.GetValue() && !firstTimeRunning.GetValue()) { + firstTimeRunningFunc = false; + return; + } + + if (firstTimeRunningFunc) { + firstTimeRunningFunc = false; + timePassedFromWelcomeScreen = Utils::Time::Timer(10000); + menuToggle.SetChangesAreDisabled(true); + + if (firstTimeRunning.GetValue()) + ImGui::OpenPopup(welcomeTitle.c_str()); + else if (!hasSeenChangelog.GetValue()) + ImGui::OpenPopup(changelogTitle.c_str()); + } + RenderWelcomeScreen(); + + static bool changelogPopupOpened = false; + if (!hasSeenChangelog.GetValue() && !firstTimeRunning.GetValue() && !changelogPopupOpened) { + changelogPopupOpened = true; + ImGui::OpenPopup(changelogTitle.c_str()); + } + RenderChangelog(); + } + + void InitImGui() { + ImGuiStyle* style = &ImGui::GetStyle(); + + style->WindowTitleAlign = ImVec2(0.5f, 0.5f); + style->WindowPadding = ImVec2(15, 15); + style->WindowRounding = 5.0f; + style->ChildRounding = 4.0f; + style->FramePadding = ImVec2(5, 5); + style->FrameRounding = 4.0f; + style->ItemSpacing = ImVec2(12, 8); + style->ItemInnerSpacing = ImVec2(8, 6); + style->IndentSpacing = 25.0f; + style->ScrollbarSize = 15.0f; + style->ScrollbarRounding = 9.0f; + style->GrabMinSize = 5.0f; + style->GrabRounding = 3.0f; + + style->Colors[ImGuiCol_Text] = ImVec4(0.80f, 0.80f, 0.83f, 1.00f); + style->Colors[ImGuiCol_TextDisabled] = ImVec4(0.24f, 0.23f, 0.29f, 1.00f); + style->Colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.05f, 0.07f, 1.00f); + style->Colors[ImGuiCol_ChildBg] = ImVec4(0.07f, 0.07f, 0.09f, 1.00f); + style->Colors[ImGuiCol_PopupBg] = ImVec4(0.07f, 0.07f, 0.09f, 1.00f); + style->Colors[ImGuiCol_Border] = ImVec4(0.80f, 0.80f, 0.83f, 0.88f); + style->Colors[ImGuiCol_BorderShadow] = ImVec4(0.92f, 0.91f, 0.88f, 0.00f); + style->Colors[ImGuiCol_FrameBg] = ImVec4(0.10f, 0.09f, 0.12f, 1.00f); + style->Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.24f, 0.23f, 0.29f, 1.00f); + style->Colors[ImGuiCol_FrameBgActive] = ImVec4(0.4705f, 0.0784f, 0.1176f, 1.00f); + style->Colors[ImGuiCol_TitleBg] = ImVec4(0.10f, 0.09f, 0.12f, 1.00f); + style->Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(1.00f, 0.98f, 0.95f, 0.75f); + style->Colors[ImGuiCol_TitleBgActive] = ImVec4(0.07f, 0.07f, 0.09f, 1.00f); + style->Colors[ImGuiCol_MenuBarBg] = ImVec4(0.13f, 0.12f, 0.15f, 1.00f); + style->Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.10f, 0.09f, 0.12f, 1.00f); + style->Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.5882f, 0.0784f, 0.1176f, 1.00f); + style->Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(1.0f, 0.0784f, 0.1176f, 1.00f); + style->Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.4705f, 0.0784f, 0.1176f, 1.00f); + style->Colors[ImGuiCol_CheckMark] = ImVec4(1.0f, 0.0784f, 0.1176f, 1.00f); + style->Colors[ImGuiCol_SliderGrab] = ImVec4(1.0f, 0.0784f, 0.1176f, 1.00f); + style->Colors[ImGuiCol_SliderGrabActive] = ImVec4(1.0f, 0.0784f, 0.1176f, 1.00f); + style->Colors[ImGuiCol_Button] = ImVec4(0.10f, 0.09f, 0.12f, 1.00f); + style->Colors[ImGuiCol_ButtonHovered] = ImVec4(1.0f, 0.0784f, 0.1176f, 1.00f); + style->Colors[ImGuiCol_ButtonActive] = ImVec4(0.4705f, 0.0784f, 0.1176f, 1.00f); + style->Colors[ImGuiCol_Header] = ImVec4(0.5882f, 0.0784f, 0.1176f, 1.00f); + style->Colors[ImGuiCol_HeaderHovered] = ImVec4(1.0f, 0.0784f, 0.1176f, 1.00f); + style->Colors[ImGuiCol_HeaderActive] = ImVec4(0.4705f, 0.0784f, 0.1176f, 1.00f); + style->Colors[ImGuiCol_Tab] = ImVec4(0.5882f, 0.0784f, 0.1176f, 1.00f); + style->Colors[ImGuiCol_TabHovered] = ImVec4(0.4705f, 0.0784f, 0.1176f, 1.00f); + style->Colors[ImGuiCol_TabActive] = ImVec4(1.0f, 0.0784f, 0.1176f, 1.00f); + style->Colors[ImGuiCol_ResizeGrip] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + style->Colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.56f, 0.56f, 0.58f, 1.00f); + style->Colors[ImGuiCol_ResizeGripActive] = ImVec4(0.06f, 0.05f, 0.07f, 1.00f); + style->Colors[ImGuiCol_PlotLines] = ImVec4(0.40f, 0.39f, 0.38f, 0.63f); + style->Colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.25f, 1.00f, 0.00f, 1.00f); + style->Colors[ImGuiCol_PlotHistogram] = ImVec4(0.40f, 0.39f, 0.38f, 0.63f); + style->Colors[ImGuiCol_PlotHistogramHovered] = ImVec4(0.25f, 1.00f, 0.00f, 1.00f); + style->Colors[ImGuiCol_TextSelectedBg] = ImVec4(0.5882f, 0.0784f, 0.1176f, 1.00f); + style->Colors[ImGuiCol_ModalWindowDimBg] = ImVec4(1.00f, 0.98f, 0.95f, 0.73f); + + defStyle = *style; + + ImGuiIO& io = ImGui::GetIO(); + ImFontConfig fontConfig{}; + fontConfig.FontDataOwnedByAtlas = false; + io.FontDefault = io.Fonts->AddFontFromMemoryTTF((void*)g_FontRudaBold, sizeof(g_FontRudaBold), 12.0f + 6.0f, &fontConfig); + io.Fonts->Build(); + + EGTLogoTexture = Utils::Texture::LoadImGuiTexture(g_EGTWhiteLogo, sizeof(g_EGTWhiteLogo)); + } +} \ No newline at end of file diff --git a/DL2GameOverhaulScript/source/menu/init.h b/DL2GameOverhaulScript/source/menu/init.h new file mode 100644 index 0000000..174551a --- /dev/null +++ b/DL2GameOverhaulScript/source/menu/init.h @@ -0,0 +1,6 @@ +#pragma once +namespace Menu { + extern void FirstTimeRunning(); + + extern void InitImGui(); +} \ No newline at end of file diff --git a/DL2GameOverhaulScript/source/menu/menu.cpp b/DL2GameOverhaulScript/source/menu/menu.cpp index 4e18573..e9d77d4 100644 --- a/DL2GameOverhaulScript/source/menu/menu.cpp +++ b/DL2GameOverhaulScript/source/menu/menu.cpp @@ -1,275 +1,23 @@ #include -#include "..\changelog.h" -#include "..\game\GamePH\Other.h" #include "menu.h" namespace Menu { - static const std::string title = "EGameTools (" + std::string(MOD_VERSION_STR) + ")"; - - static ImGuiStyle defStyle{}; - static constexpr ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoScrollbar; - - static constexpr ImVec2 minWndSize = ImVec2(425.0f, 700.0f); - static constexpr ImVec2 defMaxWndSize = ImVec2(900.0f, 700.0f); - static ImVec2 maxWndSize = defMaxWndSize; - - static constexpr ImGuiWindowFlags welcomeWindowFlags = (windowFlags | ImGuiWindowFlags_NoMove) & ~(ImGuiWindowFlags_NoScrollbar); - static constexpr ImVec2 minChangelogWndSize = ImVec2(400.0f, 0.0f); - static constexpr ImVec2 defMaxChangelogWndSize = ImVec2(400.0f, 700.0f); - static constexpr ImVec2 minWelcomeWndSize = ImVec2(800.0f, 0.0f); - static constexpr ImVec2 defMaxWelcomeWndSize = ImVec2(800.0f, 700.0f); - + const std::string title = "EGameTools (" + std::string(MOD_VERSION_STR) + ")"; + ImGuiStyle defStyle{}; ImTextureID EGTLogoTexture{}; + static constexpr ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoScrollbar; + static constexpr ImVec2 minWndSize = ImVec2(425.0f, 725.0f); + static constexpr ImVec2 defMaxWndSize = ImVec2(900.0f, 725.0f); + static ImVec2 maxWndSize = defMaxWndSize; + KeyBindOption menuToggle = KeyBindOption(VK_F5); float opacity = 99.0f; float scale = 1.0f; - static Utils::Time::Timer timePassedFromWelcomeScreen{}; Option firstTimeRunning{}; Option hasSeenChangelog{}; - void InitImGuiStyle() { - ImGuiStyle* style = &ImGui::GetStyle(); - - style->WindowTitleAlign = ImVec2(0.5f, 0.5f); - style->WindowPadding = ImVec2(15, 15); - style->WindowRounding = 5.0f; - style->ChildRounding = 4.0f; - style->FramePadding = ImVec2(5, 5); - style->FrameRounding = 4.0f; - style->ItemSpacing = ImVec2(12, 8); - style->ItemInnerSpacing = ImVec2(8, 6); - style->IndentSpacing = 25.0f; - style->ScrollbarSize = 15.0f; - style->ScrollbarRounding = 9.0f; - style->GrabMinSize = 5.0f; - style->GrabRounding = 3.0f; - - style->Colors[ImGuiCol_Text] = ImVec4(0.80f, 0.80f, 0.83f, 1.00f); - style->Colors[ImGuiCol_TextDisabled] = ImVec4(0.24f, 0.23f, 0.29f, 1.00f); - style->Colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.05f, 0.07f, 1.00f); - style->Colors[ImGuiCol_ChildBg] = ImVec4(0.07f, 0.07f, 0.09f, 1.00f); - style->Colors[ImGuiCol_PopupBg] = ImVec4(0.07f, 0.07f, 0.09f, 1.00f); - style->Colors[ImGuiCol_Border] = ImVec4(0.80f, 0.80f, 0.83f, 0.88f); - style->Colors[ImGuiCol_BorderShadow] = ImVec4(0.92f, 0.91f, 0.88f, 0.00f); - style->Colors[ImGuiCol_FrameBg] = ImVec4(0.10f, 0.09f, 0.12f, 1.00f); - style->Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.24f, 0.23f, 0.29f, 1.00f); - style->Colors[ImGuiCol_FrameBgActive] = ImVec4(0.4705f, 0.0784f, 0.1176f, 1.00f); - style->Colors[ImGuiCol_TitleBg] = ImVec4(0.10f, 0.09f, 0.12f, 1.00f); - style->Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(1.00f, 0.98f, 0.95f, 0.75f); - style->Colors[ImGuiCol_TitleBgActive] = ImVec4(0.07f, 0.07f, 0.09f, 1.00f); - style->Colors[ImGuiCol_MenuBarBg] = ImVec4(0.13f, 0.12f, 0.15f, 1.00f); - style->Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.10f, 0.09f, 0.12f, 1.00f); - style->Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.5882f, 0.0784f, 0.1176f, 1.00f); - style->Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(1.0f, 0.0784f, 0.1176f, 1.00f); - style->Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.4705f, 0.0784f, 0.1176f, 1.00f); - style->Colors[ImGuiCol_CheckMark] = ImVec4(1.0f, 0.0784f, 0.1176f, 1.00f); - style->Colors[ImGuiCol_SliderGrab] = ImVec4(1.0f, 0.0784f, 0.1176f, 1.00f); - style->Colors[ImGuiCol_SliderGrabActive] = ImVec4(1.0f, 0.0784f, 0.1176f, 1.00f); - style->Colors[ImGuiCol_Button] = ImVec4(0.10f, 0.09f, 0.12f, 1.00f); - style->Colors[ImGuiCol_ButtonHovered] = ImVec4(1.0f, 0.0784f, 0.1176f, 1.00f); - style->Colors[ImGuiCol_ButtonActive] = ImVec4(0.4705f, 0.0784f, 0.1176f, 1.00f); - style->Colors[ImGuiCol_Header] = ImVec4(0.5882f, 0.0784f, 0.1176f, 1.00f); - style->Colors[ImGuiCol_HeaderHovered] = ImVec4(1.0f, 0.0784f, 0.1176f, 1.00f); - style->Colors[ImGuiCol_HeaderActive] = ImVec4(0.4705f, 0.0784f, 0.1176f, 1.00f); - style->Colors[ImGuiCol_Tab] = ImVec4(0.5882f, 0.0784f, 0.1176f, 1.00f); - style->Colors[ImGuiCol_TabHovered] = ImVec4(0.4705f, 0.0784f, 0.1176f, 1.00f); - style->Colors[ImGuiCol_TabActive] = ImVec4(1.0f, 0.0784f, 0.1176f, 1.00f); - style->Colors[ImGuiCol_ResizeGrip] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); - style->Colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.56f, 0.56f, 0.58f, 1.00f); - style->Colors[ImGuiCol_ResizeGripActive] = ImVec4(0.06f, 0.05f, 0.07f, 1.00f); - style->Colors[ImGuiCol_PlotLines] = ImVec4(0.40f, 0.39f, 0.38f, 0.63f); - style->Colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.25f, 1.00f, 0.00f, 1.00f); - style->Colors[ImGuiCol_PlotHistogram] = ImVec4(0.40f, 0.39f, 0.38f, 0.63f); - style->Colors[ImGuiCol_PlotHistogramHovered] = ImVec4(0.25f, 1.00f, 0.00f, 1.00f); - style->Colors[ImGuiCol_TextSelectedBg] = ImVec4(0.5882f, 0.0784f, 0.1176f, 1.00f); - style->Colors[ImGuiCol_ModalWindowDimBg] = ImVec4(1.00f, 0.98f, 0.95f, 0.73f); - - defStyle = *style; - - ImGuiIO& io = ImGui::GetIO(); - ImFontConfig fontConfig{}; - fontConfig.FontDataOwnedByAtlas = false; - io.FontDefault = io.Fonts->AddFontFromMemoryTTF((void*)g_FontRudaBold, sizeof(g_FontRudaBold), 12.0f + 6.0f, &fontConfig); - io.Fonts->Build(); - - EGTLogoTexture = Utils::Texture::LoadImGuiTexture(g_EGTWhiteLogo, sizeof(g_EGTWhiteLogo)); - } - - static void CreateChangelogFile() { - const std::string localAppDataDir = Utils::Files::GetLocalAppDataDir(); - if (localAppDataDir.empty()) - return; - const std::string dirPath = std::string(localAppDataDir) + "\\EGameTools\\"; - std::filesystem::create_directories(dirPath); - - const std::string finalPath = dirPath + MOD_VERSION_STR + ".changelog"; - if (!std::filesystem::exists(finalPath)) { - std::ofstream outFile(finalPath.c_str(), std::ios::binary); - if (!outFile.is_open()) - return; - outFile.close(); - } - } - static bool DoesChangelogFileExist() { - const std::string localAppDataDir = Utils::Files::GetLocalAppDataDir(); - if (localAppDataDir.empty()) - return false; - return std::filesystem::exists(std::string(localAppDataDir) + "\\EGameTools\\" + MOD_VERSION_STR + ".changelog"); - } - void FirstTimeRunning() { - static bool firstTimeRunningFunc = true; - if (firstTimeRunningFunc) - hasSeenChangelog.SetBothValues(hasSeenChangelog.GetValue() && DoesChangelogFileExist()); - - if (hasSeenChangelog.GetValue() && !firstTimeRunning.GetValue()) { - firstTimeRunningFunc = false; - return; - } - - const std::string changelogTitle = std::string(title + " - Update Changelog"); - const std::string welcomeTitle = std::string(title + " - Welcome!"); - - if (firstTimeRunningFunc) { - firstTimeRunningFunc = false; - timePassedFromWelcomeScreen = Utils::Time::Timer(10000); - menuToggle.SetChangesAreDisabled(true); - - if (firstTimeRunning.GetValue()) - ImGui::OpenPopup(welcomeTitle.c_str()); - else if (!hasSeenChangelog.GetValue()) - ImGui::OpenPopup(changelogTitle.c_str()); - } - - ImGui::SetNextWindowBgAlpha(1.0f); - ImGui::SetNextWindowSizeConstraints(minWelcomeWndSize, defMaxWelcomeWndSize); - if (ImGui::BeginPopupModal(welcomeTitle.c_str(), nullptr, welcomeWindowFlags)) { - ImGui::TextCenteredColored("PLEASE read the following text!", IM_COL32(230, 0, 0, 255)); - ImGui::Spacing(ImVec2(0.0f, 5.0f)); - - const std::string thankYou = "Thank you for downloading EGameTools (" + std::string(MOD_VERSION_STR) + ")!"; - ImGui::TextCentered(thankYou.c_str()); - ImGui::Spacing(ImVec2(0.0f, 5.0f)); - - const std::string gameCompat = "This version of the mod is compatible with game version " + std::string(GAME_VER_COMPAT_STR) + "."; - ImGui::TextCentered(gameCompat.c_str()); - const std::string gameVer = "The game version you are currently running is v" + GamePH::GetCurrentGameVersionStr() + "."; - ImGui::TextCentered(gameVer.c_str()); - const std::string gameTestedVer = "This mod has last been tested with version v" + GamePH::GameVerToStr(GAME_VER_COMPAT) + "."; - ImGui::TextCentered(gameTestedVer.c_str()); - if (GamePH::GetCurrentGameVersion() < 11400 || GamePH::GetCurrentGameVersion() > GAME_VER_COMPAT) { - const std::string gameNotCompat = "Please note that your game version has not been officially tested with this mod, therefore expect bugs, glitches or the mod to completely stop working. If so, please " + std::string(GamePH::GetCurrentGameVersion() > GAME_VER_COMPAT ? "wait for a new patch." : "upgrade your game version to one that the mod supports."); - ImGui::TextCenteredColored(gameNotCompat.c_str(), IM_COL32(200, 0, 0, 255)); - } - ImGui::Spacing(ImVec2(0.0f, 5.0f)); - ImGui::TextCentered("I will not bore you with what this mod is about, so let's get right to teaching you how to use it!"); - - ImGui::SeparatorTextColored("Menu Toggle", IM_COL32(200, 0, 0, 255)); - ImGui::NewLine(); - ImGui::TextCentered("The default key for opening/closing the menu is F5. You can use your mouse to navigate the menu."); - ImGui::TextCentered("To change it, you can open up the menu and change the hotkey by clicking the hotkey button for \"Menu Toggle Key\" and then pressing a key on your keyboard."); - - ImGui::SeparatorTextColored("FreeCam", IM_COL32(200, 0, 0, 255)); - ImGui::NewLine(); - ImGui::TextCentered("While using FreeCam, you can press Shift or Alt to boost your speed or slow you down respectively."); - ImGui::TextCentered("You can also use the scroll wheel to change FreeCam speed while FreeCam is enabled."); - - ImGui::SeparatorTextColored("Menu Sliders", IM_COL32(200, 0, 0, 255)); - ImGui::NewLine(); - ImGui::TextCentered("To manually change the value of a slider option, hold \"CTRL\" while clicking the slider."); - ImGui::TextCentered("This will let you input a value manually into the slider, which can also go beyond the option's slider limit, given I allow the option to do so."); - - ImGui::SeparatorTextColored("Custom File Loading", IM_COL32(200, 0, 0, 255)); - ImGui::NewLine(); - ImGui::TextCentered("The mod always creates a folder \"EGameTools\\UserModFiles\" inside the same folder as the game executable (exe) or in the same folder as the mod file."); - ImGui::TextCentered("This folder is used for custom file loading. This has only been tested with a few mods that change some .scr files, gpufx files, and other files included inside .pak game archives, or files like .rpack files."); - ImGui::TextCentered("Files in this folder must have the same names as the ones from the game files, otherwise the game won't know it should load those files. Files in subfolders of the \"EGameTools\\UserModFiles\" folder will automatically be detected, so you can sort all your mods in different folders!"); - ImGui::Spacing(ImVec2(0.0f, 5.0f)); - ImGui::TextCentered("The game will reload a lot of the files upon a load of your savegame, so if you want to edit those files and reload them without having to restart the game, just reload your savegame and the game should automatically reload most of those files!"); - ImGui::TextCentered("Just make sure that if you add new, additional files while you're in-game, please wait AT LEAST 5 seconds before reloading your savegame, otherwise additional files will not get detected."); - ImGui::TextCentered("Also, if there are multiple files of the same exact name, the game will pick the first instance of that file it finds in the folder."); - ImGui::Spacing(ImVec2(0.0f, 5.0f)); - ImGui::TextCentered("The gist of it is, you now don't have to use dataX.pak mods anymore! You can open the pak files, extract their files in the \"EGameTools\\UserModFiles\" folder and start the game!"); - ImGui::Spacing(ImVec2(0.0f, 5.0f)); - ImGui::TextCenteredColored("FOR MOD DEVELOPERS", IM_COL32(200, 0, 0, 255)); - ImGui::TextCentered("If you want to make mods for EGameTools to load, please try to use as few folders as you possibly can. For example, your mod should only have one folder, something like \"EGameTools\\UserModFiles\\2019 Weather Mod\"."); - ImGui::TextCentered("The reason is, my mod continuously checks for new files in the directory, and many folders can slow down the process, and therefore slow down game loading times. So just keep this in mind!"); - ImGui::Spacing(ImVec2(0.0f, 5.0f)); - ImGui::TextCentered("If you want to officially include one of your mods as part of EGameTools, please contact me on NexusMods or on Discord (@EricPlayZ)."); - - ImGui::SeparatorTextColored("Game Variables Reloading", IM_COL32(200, 0, 0, 255)); - ImGui::NewLine(); - ImGui::TextCentered("You can also reload Player Variables from a file specified by you, or reload Jump Parameters from \"EGameTools\\UserModFiles\"."); - - ImGui::SeparatorTextColored("Hotkeys", IM_COL32(200, 0, 0, 255)); - ImGui::NewLine(); - ImGui::TextCentered("Most mod menu options are toggleable by a hotkey that you can change by clicking the hotkey button for the respective option and then pressing a key on your keyboard."); - ImGui::TextCentered("To change those hotkeys through the config file, visit the \"Virtual-Key Codes\" page from Microsoft which contains a list of all virtual key codes. Simply write the name of the keycode you want to use for each hotkey and save the config file."); - - ImGui::SeparatorTextColored("Config", IM_COL32(200, 0, 0, 255)); - ImGui::NewLine(); - ImGui::TextCentered("A config file \"EGameTools.ini\" is stored in the same folder as the game executable (exe) or in the same folder as the mod file."); - ImGui::TextCentered("The config file stores the mod menu's options and hotkeys."); - - ImGui::Spacing(ImVec2(0.0f, 5.0f)); - - ImGui::TextCentered("Changes to the mod menu or to the config file are always automatically saved or refreshed respectively."); - ImGui::TextCentered("You DO NOT NEED to restart the game for the changes in the config to be applied!"); - ImGui::TextCentered("If you want to regenerate the config file, delete it and it will automatically be regenerated."); - - ImGui::Separator(); - ImGui::NewLine(); - ImGui::TextCentered("Finally, if you've got any issue, no matter how small, please make sure to report it! I will try my best to fix it. I want this mod to be polished and enjoyable to use!"); - ImGui::TextCentered("If you've got any suggestions for how I could improve the mod, in terms of UI, features, among other things, please let me know!"); - ImGui::Spacing(ImVec2(0.0f, 5.0f)); - - ImGui::BeginDisabled(!timePassedFromWelcomeScreen.DidTimePass()); { - const std::string btnText = "Let me play!" + (!timePassedFromWelcomeScreen.DidTimePass() ? (" (" + std::to_string(10 - (timePassedFromWelcomeScreen.GetTimePassed() / 1000)) + ")") : ""); - if (ImGui::ButtonCentered(btnText.c_str(), ImVec2(0.0f, 30.0f))) { - ImGui::CloseCurrentPopup(); - firstTimeRunning.Set(false); - if (hasSeenChangelog.GetValue()) - menuToggle.SetChangesAreDisabled(false); - } - ImGui::EndDisabled(); - } - ImGui::EndPopup(); - } - - static bool changelogPopupOpened = false; - if (!hasSeenChangelog.GetValue() && !firstTimeRunning.GetValue() && !changelogPopupOpened) { - changelogPopupOpened = true; - ImGui::OpenPopup(changelogTitle.c_str()); - } - - ImGui::SetNextWindowBgAlpha(1.0f); - ImGui::SetNextWindowSizeConstraints(minChangelogWndSize, defMaxChangelogWndSize); - if (ImGui::BeginPopupModal(changelogTitle.c_str(), nullptr, welcomeWindowFlags)) { - const std::string subTitle = "This is what the " + std::string(MOD_VERSION_STR) + " update brings:"; - ImGui::TextCenteredColored(subTitle.c_str(), IM_COL32(230, 0, 0, 255), false); - ImGui::Spacing(ImVec2(0.0f, 5.0f)); - - std::istringstream iss(Changelog::changelogs[MOD_VERSION_STR]); - std::string line{}; - while (std::getline(iss, line)) { - if (line.empty()) { - ImGui::NewLine(); - continue; - } - ImGui::TextCentered(line.c_str(), false); - } - - if (ImGui::ButtonCentered("Close", ImVec2(0.0f, 30.0f))) { - ImGui::CloseCurrentPopup(); - menuToggle.SetChangesAreDisabled(false); - hasSeenChangelog.Set(true); - firstTimeRunning.Set(false); - CreateChangelogFile(); - } - ImGui::EndPopup(); - } - } void Render() { maxWndSize = defMaxWndSize * scale; ImGui::SetNextWindowBgAlpha(static_cast(opacity) / 100.0f); @@ -284,8 +32,8 @@ namespace Menu { if (ImGui::BeginTabBar("##MainTabBar")) { for (auto& tab : *MenuTab::GetInstances()) { static float childWidth = 0.0f; - ImGui::SpanTabsAcrossWidth(childWidth, MenuTab::GetInstances()->size()); + ImGui::SpanNextTabAcrossWidth(childWidth, MenuTab::GetInstances()->size()); if (ImGui::BeginTabItem(tab.second->tabName.data())) { ImGui::SetNextWindowBgAlpha(static_cast(opacity) / 100.0f); ImGui::SetNextWindowSizeConstraints(ImVec2(minWndSize.x - GImGui->Style.WindowPadding.x * 2.0f, remainingHeight), ImVec2(maxWndSize.x - GImGui->Style.WindowPadding.x * 2.0f, remainingHeight)); @@ -297,7 +45,7 @@ namespace Menu { ImGui::EndTabItem(); } } - ImGui::EndTabBar(); + ImGui::EndTabBarEx(); } ImGui::Hotkey("Menu Toggle Key", &menuToggle); diff --git a/DL2GameOverhaulScript/source/menu/menu.h b/DL2GameOverhaulScript/source/menu/menu.h index f43055a..d99d0c0 100644 --- a/DL2GameOverhaulScript/source/menu/menu.h +++ b/DL2GameOverhaulScript/source/menu/menu.h @@ -16,6 +16,10 @@ namespace Menu { int tabIndex{}; }; + extern const std::string title; + extern ImGuiStyle defStyle; + extern ImTextureID EGTLogoTexture; + extern KeyBindOption menuToggle; extern float opacity; extern float scale; @@ -23,8 +27,5 @@ namespace Menu { extern Option firstTimeRunning; extern Option hasSeenChangelog; - extern void InitImGuiStyle(); - - extern void FirstTimeRunning(); extern void Render(); } \ No newline at end of file diff --git a/DL2GameOverhaulScript/source/menu/player.cpp b/DL2GameOverhaulScript/source/menu/player.cpp index da38109..9ec211f 100644 --- a/DL2GameOverhaulScript/source/menu/player.cpp +++ b/DL2GameOverhaulScript/source/menu/player.cpp @@ -6299,38 +6299,53 @@ namespace Menu { if (lowerSearch.find(std::string(lowerFilter)) == std::string::npos) continue; + float* floatVarAddr = nullptr; + bool* boolVarAddr = nullptr; + if (val.second == "float") { - float* varAddr = reinterpret_cast(val.first); - float newValue = *varAddr; + floatVarAddr = reinterpret_cast(val.first); + float newValue = *floatVarAddr; if (ImGui::InputFloat(key.data(), &newValue)) { - *varAddr = newValue; - *(varAddr + 1) = newValue; - } - ImGui::SameLine(); - restoreBtnName = std::string("Restore##") + std::string(key); - if (ImGui::Button(restoreBtnName.c_str())) - RestoreVariableToDefault(key); - if (debugEnabled) { - ImGui::SameLine(); - ImGui::Text("0x%p", varAddr); + *floatVarAddr = newValue; + *(floatVarAddr + 1) = newValue; } } else if (val.second == "bool") { - bool* varAddr = reinterpret_cast(val.first); - bool newValue = *varAddr; + boolVarAddr = reinterpret_cast(val.first); + bool newValue = *boolVarAddr; if (ImGui::Checkbox(key.data(), &newValue)) { - *varAddr = newValue; - *(varAddr + 1) = newValue; + *boolVarAddr = newValue; + *(boolVarAddr + 1) = newValue; } + } + + ImGui::SameLine(); + restoreBtnName = std::string("Restore##") + std::string(key); + if (ImGui::Button(restoreBtnName.c_str())) + RestoreVariableToDefault(key); + if (debugEnabled) { + static float maxInputTextWidth = ImGui::CalcTextSize("0x0000000000000000").x; + static std::string labelID{}; + labelID = "##DebugAddrInputText" + std::string(key); + const DWORD64 finalAddr = floatVarAddr ? reinterpret_cast(floatVarAddr) : reinterpret_cast(boolVarAddr); + + std::stringstream ss{}; + if (finalAddr) + ss << "0x" << std::uppercase << std::hex << finalAddr; + else + ss << "NULL"; + + static std::string addrString{}; + addrString = ss.str(); + ImGui::SameLine(); - restoreBtnName = std::string("Restore##") + std::string(key); - if (ImGui::Button(restoreBtnName.c_str())) - RestoreVariableToDefault(key); - if (debugEnabled) { - ImGui::SameLine(); - ImGui::Text("0x%p", varAddr); - } + + ImGui::SetCursorPosY(ImGui::GetCursorPosY() - ((ImGui::GetFrameHeight() - ImGui::GetTextLineHeight()) / 2.0f)); + ImGui::SetNextItemWidth(maxInputTextWidth); + ImGui::PushStyleColor(ImGuiCol_Text, finalAddr ? IM_COL32(0, 255, 0, 255) : IM_COL32(255, 0, 0, 255)); + ImGui::InputText(labelID.c_str(), const_cast(addrString.c_str()), strlen(addrString.c_str()), ImGuiInputTextFlags_ReadOnly); + ImGui::PopStyleColor(); } } ImGui::Unindent();