From 65333e2f81cbd52816b7e13cbbd6d22ba734a4f2 Mon Sep 17 00:00:00 2001 From: Oleksandr Nemesh Date: Fri, 31 May 2024 18:56:51 +0300 Subject: [PATCH 01/20] prepare for 64 bit only linker errors for libcurl and cocos2d are to fix (need to get the new libs) --- CMakeLists.txt | 17 ++++++++++++++++- mod.json | 4 ++-- src/standalone/debug/crashhandler.hpp | 11 +++++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5cf338c..e0eb0a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,9 +68,24 @@ target_link_libraries( INTERFACE external_libs opengl32 - ${CMAKE_SOURCE_DIR}/libs/glew/lib/Release/Win32/glew32.lib ) +if (CMAKE_SIZEOF_VOID_P EQUAL 8) + # Windows 64 + target_link_libraries( + ${PROJECT_NAME} + INTERFACE + ${CMAKE_SOURCE_DIR}/libs/glew/lib/Release/x64/glew32.lib + ) +else() + # Windows 32 + target_link_libraries( + ${PROJECT_NAME} + INTERFACE + ${CMAKE_SOURCE_DIR}/libs/glew/lib/Release/Win32/glew32.lib + ) +endif() + if (PROJECT_IS_TOP_LEVEL) target_compile_definitions(${PROJECT_NAME} INTERFACE OPENHACK_EXPORT) endif() diff --git a/mod.json b/mod.json index 706be86..460253b 100644 --- a/mod.json +++ b/mod.json @@ -1,9 +1,9 @@ { - "geode": "2.0.0-beta.26", + "geode": "2.0.0-beta.27", "gd": { "win": "2.204" }, - "version": "v2.3.2", + "version": "v2.4.0", "id": "prevter.openhack", "name": "OpenHack", "developer": "Prevter", diff --git a/src/standalone/debug/crashhandler.hpp b/src/standalone/debug/crashhandler.hpp index 3e2f98f..fecfa14 100644 --- a/src/standalone/debug/crashhandler.hpp +++ b/src/standalone/debug/crashhandler.hpp @@ -4,6 +4,16 @@ #include "logger.hpp" #ifdef PLATFORM_WINDOWS +#if _WIN64 + +namespace crashhandler +{ + void init() + { + } +} + +#else #include #include @@ -333,6 +343,7 @@ namespace crashhandler { } } +#endif #else namespace crashhandler From 34c225b128a5f401d7ef27b625f54c0073130dba Mon Sep 17 00:00:00 2001 From: Oleksandr Nemesh Date: Fri, 31 May 2024 18:58:09 +0300 Subject: [PATCH 02/20] click between frames warning --- CHANGELOG.md | 3 +++ src/shared/hacks/zephyrus/replays.cpp | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5455e9..458dd8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## v2.4.0 +* Added a notice for "Click Between Frames" users + ## v2.3.2 * Resolved issue with "Respawn Delay" diff --git a/src/shared/hacks/zephyrus/replays.cpp b/src/shared/hacks/zephyrus/replays.cpp index 4cc4871..d50edf1 100644 --- a/src/shared/hacks/zephyrus/replays.cpp +++ b/src/shared/hacks/zephyrus/replays.cpp @@ -92,6 +92,20 @@ namespace openhack::hacks { // Create window menu::addWindow("Replays (beta)", [&]() { +#ifdef OPENHACK_GEODE + // Show a warning if user has "syzzi.click_between_frames" enabled + static geode::Mod* cbfMod = geode::Loader::get()->getLoadedMod("syzzi.click_between_frames"); + static bool hasCBF = cbfMod != nullptr && cbfMod->isEnabled(); + + if (hasCBF) { + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.5f, 0.5f, 1.0f)); + ImGui::TextWrapped("Warning: \"Click Between Frames\" is enabled"); + gui::tooltip("The replay system may not work correctly with this mod enabled.\n" + "Please disable it to use the replay system."); + ImGui::PopStyleColor(); + } +#endif + gui::width(120); if (gui::combo("State", "zephyrus.state", "Disabled\0Playing\0Recording\0\0")) { s_replayEngine.setState(static_cast(config::get("zephyrus.state"))); From 77997fc190ef6d8f74e90ddd039476ef5459897b Mon Sep 17 00:00:00 2001 From: Oleksandr Nemesh Date: Fri, 31 May 2024 21:06:35 +0300 Subject: [PATCH 03/20] improve best run --- src/geode/hooks/PlayLayer.cpp | 1 + src/shared/hacks/startpos-switcher/startpos-switcher.cpp | 2 ++ src/standalone/hooks/PlayLayer.cpp | 1 + 3 files changed, 4 insertions(+) diff --git a/src/geode/hooks/PlayLayer.cpp b/src/geode/hooks/PlayLayer.cpp index ae48eb4..ccd4b2e 100644 --- a/src/geode/hooks/PlayLayer.cpp +++ b/src/geode/hooks/PlayLayer.cpp @@ -71,6 +71,7 @@ namespace openhack::hooks { void fullReset() { PlayLayer::fullReset(); hacks::Hitboxes::fullReset(); + config::setGlobal("bestRun", 0); } void playEndAnimationToPos(cocos2d::CCPoint pos) { diff --git a/src/shared/hacks/startpos-switcher/startpos-switcher.cpp b/src/shared/hacks/startpos-switcher/startpos-switcher.cpp index 052dfcf..4c77daa 100644 --- a/src/shared/hacks/startpos-switcher/startpos-switcher.cpp +++ b/src/shared/hacks/startpos-switcher/startpos-switcher.cpp @@ -167,6 +167,8 @@ namespace openhack::hacks { // Update label updateLabel(); + + config::setGlobal("bestRun", 0); } } \ No newline at end of file diff --git a/src/standalone/hooks/PlayLayer.cpp b/src/standalone/hooks/PlayLayer.cpp index 36c23c8..a873447 100644 --- a/src/standalone/hooks/PlayLayer.cpp +++ b/src/standalone/hooks/PlayLayer.cpp @@ -70,6 +70,7 @@ namespace openhack::hooks::PlayLayer { void fullReset(gd::PlayLayer *self) { hook::PlayLayer::fullReset(self); hacks::Hitboxes::fullReset(); + config::setGlobal("bestRun", 0); } void playEndAnimationToPos(gd::PlayLayer *self, cocos2d::CCPoint pos) { From 1ec13b4d29db286153b1490b1920ea5c820d3030 Mon Sep 17 00:00:00 2001 From: Oleksandr Nemesh Date: Fri, 31 May 2024 21:06:50 +0300 Subject: [PATCH 04/20] add more labels --- src/shared/hacks/labels/labels.cpp | 89 +++++++++++++++++++++--------- 1 file changed, 64 insertions(+), 25 deletions(-) diff --git a/src/shared/hacks/labels/labels.cpp b/src/shared/hacks/labels/labels.cpp index 70d541c..99bf8d3 100644 --- a/src/shared/hacks/labels/labels.cpp +++ b/src/shared/hacks/labels/labels.cpp @@ -181,6 +181,10 @@ namespace openhack::hacks { .caption = "Frame", .text = "Frame: {frame}", }, + { + .caption = "Total Attempts", + .text = "Attempts: {total_attempts}", + }, { .caption = "Custom Message", .text = "", @@ -201,6 +205,7 @@ namespace openhack::hacks { "Attempt Time", "Session Time", "Frame", + "Total Attempts", "Custom Message" }; @@ -487,6 +492,7 @@ namespace openhack::hacks { // {attempts} - attempts in the level // {star_emoji} - places ⭐ or 🌙 depending on whether the level is platformer or not // {clock} - current time + // {clock12} - current time in 12-hour format // {fps} - current FPS // {cps} - clicks per second // {clicks} - total clicks in the level @@ -499,45 +505,48 @@ namespace openhack::hacks { // {time} - attempt time in seconds // {formatted_time} - attempt time in MM:SS.mmm format // {session_time} - session time in MM:SS.mmm format + // {total_attempts} - total attempts in the level + // {openhack_ver} - OpenHack version + // {mod_count} - number of loaded mods in Geode std::unordered_map> tokens = { - {"{username}", []() { + {"{username}", []() { auto *gameManager = gd::GameManager::sharedState(); return gameManager->m_playerName(); }}, - {"{id}", [playLayer, editorLayer]() { + {"{id}", [playLayer, editorLayer]() { gd::GJBaseGameLayer *layer = playLayer ? (gd::GJBaseGameLayer *) playLayer : (gd::GJBaseGameLayer *) editorLayer; if (!layer) return std::string(""); return std::to_string(layer->m_level()->m_levelID().value()); }}, - {"{name}", [playLayer, editorLayer]() { + {"{name}", [playLayer, editorLayer]() { gd::GJBaseGameLayer *layer = playLayer ? (gd::GJBaseGameLayer *) playLayer : (gd::GJBaseGameLayer *) editorLayer; if (!layer) return std::string("Unknown"); return layer->m_level()->m_levelName(); }}, - {"{author}", [playLayer, editorLayer]() { + {"{author}", [playLayer, editorLayer]() { gd::GJBaseGameLayer *layer = playLayer ? (gd::GJBaseGameLayer *) playLayer : (gd::GJBaseGameLayer *) editorLayer; if (!layer) return std::string("Unknown"); if (isRobTopLevel(layer->m_level())) return std::string("RobTop"); return layer->m_level()->m_creatorName(); }}, - {"{difficulty}", [playLayer]() { + {"{difficulty}", [playLayer]() { if (!playLayer) return std::string(""); return getDifficultyAsset(playLayer->m_level()); }}, - {"{progress}", [playLayer]() { + {"{progress}", [playLayer]() { if (!playLayer) return std::string(""); auto progress = playLayer->getCurrentPercentInt(); if (progress < 0) progress = 0; return std::to_string(progress); }}, - {"{best}", [playLayer]() { + {"{best}", [playLayer]() { if (!playLayer) return std::string(""); if (playLayer->m_level()->isPlatformer()) { int millis = playLayer->m_level()->m_bestTime(); - if (millis == 0) return std::string("No Best Time"); + if (millis == 0) return std::string("N/A"); double seconds = millis / 1000.0; if (seconds < 60.0) return fmt::format("{:.3f}", seconds); @@ -547,7 +556,7 @@ namespace openhack::hacks { } return std::to_string(playLayer->m_level()->m_normalPercent().value()); }}, - {"{objects}", [playLayer, editorLayer]() { + {"{objects}", [playLayer, editorLayer]() { if (playLayer) { return std::to_string(playLayer->m_level()->m_objectCount().value()); } else if (editorLayer) { @@ -555,68 +564,77 @@ namespace openhack::hacks { } return std::string(""); }}, - {"{stars}", [playLayer]() { + {"{stars}", [playLayer]() { if (playLayer) { return std::to_string(playLayer->m_level()->m_stars().value()); } return std::string(""); }}, - {"{attempts}", [playLayer]() { + {"{attempts}", [playLayer]() { if (!playLayer) return std::string(""); return std::to_string(playLayer->m_attempts()); }}, - {"{rating}", [playLayer]() { + {"{rating}", [playLayer]() { if (!playLayer) return std::string(""); return std::to_string(playLayer->m_level()->m_ratingsSum()); }}, - {"{star_emoji}", [playLayer]() { + {"{star_emoji}", [playLayer]() { if (!playLayer) return std::string(""); return std::string(playLayer->m_level()->isPlatformer() ? "🌙" : "⭐"); }}, - {"{clock}", []() { + {"{clock}", []() { std::time_t now = std::time(nullptr); std::tm tm{}; localtime_s(&tm, &now); return fmt::format("{:02d}:{:02d}:{:02d}", tm.tm_hour, tm.tm_min, tm.tm_sec); }}, - {"{fps}", []() { + {"{clock12}", []() { + std::time_t now = std::time(nullptr); + std::tm tm{}; + localtime_s(&tm, &now); + int hour = tm.tm_hour; + if (hour > 12) hour -= 12; + return fmt::format("{:02d}:{:02d}:{:02d} {}", hour, tm.tm_min, tm.tm_sec, + tm.tm_hour > 12 ? "PM" : "AM"); + }}, + {"{fps}", []() { return std::to_string(static_cast(ImGui::GetIO().Framerate)); }}, - {"{cps}", [playLayer]() { + {"{cps}", [playLayer]() { if (!playLayer) return std::string(""); return std::to_string(config::getGlobal("cps", 0)); }}, - {"{clicks}", [playLayer]() { + {"{clicks}", [playLayer]() { if (!playLayer) return std::string(""); return std::to_string(config::getGlobal("totalClicks", 0)); }}, - {"{noclip_acc}", [playLayer]() { + {"{noclip_acc}", [playLayer]() { if (!playLayer) return std::string(""); auto noclipAcc = config::getGlobal("noclipAcc", 0); return fmt::format("{:.2f}", noclipAcc); }}, - {"{noclip_death}", [playLayer]() { + {"{noclip_death}", [playLayer]() { if (!playLayer) return std::string(""); auto noclipDeath = config::getGlobal("noclipDeath", 0); return std::to_string(noclipDeath); }}, - {"{from}", [playLayer]() { + {"{from}", [playLayer]() { if (!playLayer) return std::string(""); auto from = config::getGlobal("fromPercent", 0); return std::to_string(from < 0 ? 0 : from); }}, - {"{best_run}", [playLayer]() { + {"{best_run}", [playLayer]() { if (!playLayer) return std::string(""); return std::to_string(config::getGlobal("bestRun", 0)); }}, - {"{random_seed}", []() { + {"{random_seed}", []() { return std::to_string(RandomSeed::getCurrentSeed()); }}, - {"{frame}", [playLayer]() { + {"{frame}", [playLayer]() { if (!playLayer) return std::string("0"); return std::to_string(static_cast(playLayer->m_dTime() * 240.0f)); }}, - {"{time}", [playLayer]() { + {"{time}", [playLayer]() { if (!playLayer) return std::string(""); auto time = playLayer->m_dTime(); return fmt::format("{:.3f}", time); @@ -629,12 +647,33 @@ namespace openhack::hacks { int millis = (int) (time * 1000) % 1000; return fmt::format("{}:{:02d}.{:03d}", minutes, seconds, millis); }}, - {"{session_time}", []() { + {"{session_time}", []() { auto time = std::time(nullptr) - config::getGlobal("discord_rpc.levelTime", std::time(nullptr)); int minutes = (int) time / 60; int seconds = (int) time % 60; return fmt::format("{}:{:02d}", minutes, seconds); }}, + {"{total_attempts}", [playLayer]() { + if (!playLayer) return std::string(""); + return std::to_string(playLayer->m_level()->m_attempts().value()); + }}, + {"{openhack_ver}", []() { + static std::string version = fmt::format( + "{}.{}.{}", + OPENHACK_VERSION_MAJOR, + OPENHACK_VERSION_MINOR, + OPENHACK_VERSION_PATCH); + return version; + }}, +#ifdef OPENHACK_GEODE + {"{mod_count}", []() { + static auto allMods = geode::Loader::get()->getAllMods(); + static auto modCount = std::count_if(allMods.begin(), allMods.end(), [](const auto &mod) { + return mod->shouldLoad(); + }); + return std::to_string(modCount); + }}, +#endif }; std::string result = text; From 4af2f3f0e7997b66a5ed42dcaad26789eded5be1 Mon Sep 17 00:00:00 2001 From: Oleksandr Nemesh Date: Fri, 31 May 2024 21:07:16 +0300 Subject: [PATCH 05/20] Update gd.hpp --- libs/gd.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/gd.hpp b/libs/gd.hpp index 0b0f3ff..7c4ab8e 160000 --- a/libs/gd.hpp +++ b/libs/gd.hpp @@ -1 +1 @@ -Subproject commit 0b0f3ff302f2e1524098b2aacf9d96f5369356d0 +Subproject commit 7c4ab8e6199b373b33c4f55d2fc72ed532e7c958 From e1fbda2d03a2b5dacef1c466a9b149a712dc614d Mon Sep 17 00:00:00 2001 From: Oleksandr Nemesh Date: Fri, 31 May 2024 21:07:28 +0300 Subject: [PATCH 06/20] Update CHANGELOG.md --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 458dd8c..a67e2ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,9 @@ ## v2.4.0 +* Improved "Best Run" calculation +* Added "Total Attempts" label ({total_attempts}) +* Added "Mod version" label ({openhack_ver}) +* Added 12-hour clock label ({clock12}) +* [Geode] Added "Mod count" label ({mod_count}) * Added a notice for "Click Between Frames" users ## v2.3.2 From 07fb60e5371d30d59223c62ce1283784a63d336b Mon Sep 17 00:00:00 2001 From: Oleksandr Nemesh Date: Fri, 31 May 2024 21:12:29 +0300 Subject: [PATCH 07/20] ui tweaks --- CHANGELOG.md | 8 +++++++- src/shared/config.cpp | 1 + src/shared/menu/menu.cpp | 30 +++++++++++++++++++++--------- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a67e2ba..a8c1889 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,16 @@ ## v2.4.0 +**New**: +* Ported to 2.206 * Improved "Best Run" calculation +* Tweaked some UI elements +* Added a "Lock First Column" option for the menu +* Added a notice for "Click Between Frames" users + +**Labels**: * Added "Total Attempts" label ({total_attempts}) * Added "Mod version" label ({openhack_ver}) * Added 12-hour clock label ({clock12}) * [Geode] Added "Mod count" label ({mod_count}) -* Added a notice for "Click Between Frames" users ## v2.3.2 * Resolved issue with "Respawn Delay" diff --git a/src/shared/config.cpp b/src/shared/config.cpp index cf44a1f..0109a01 100644 --- a/src/shared/config.cpp +++ b/src/shared/config.cpp @@ -26,6 +26,7 @@ namespace openhack::config { setIfEmpty("menu.rainbow.value", 65.0f); setIfEmpty("menu.checkForUpdates", true); setIfEmpty("menu.animateOpacity", false); + setIfEmpty("menu.lockFirstColumn", true); setIfEmpty("keybinds.ingame", false); } diff --git a/src/shared/menu/menu.cpp b/src/shared/menu/menu.cpp index 9cab8dc..15a7726 100644 --- a/src/shared/menu/menu.cpp +++ b/src/shared/menu/menu.cpp @@ -142,10 +142,12 @@ namespace openhack::menu { gui::checkbox("Check for updates", "menu.checkForUpdates"); #endif - if (gui::button("Open GitHub page")) + if (gui::button("GitHub", ImVec2(0.5, 0))) createOpenURLPopup(OPENHACK_HOME_URL); - if (gui::button("Join Discord server")) + ImGui::SameLine(0, 2); + + if (gui::button("Discord")) createOpenURLPopup("https://discord.gg/QSd4jUyc45"); auto searchValue = config::getGlobal("searchValue", ""); @@ -230,6 +232,7 @@ namespace openhack::menu { // blur::setState(config::get("menu.blur")); // } + gui::callback([]() { gui::tooltip("Makes the title bar change colors."); }); @@ -248,7 +251,11 @@ namespace openhack::menu { stackWindows(); gui::tooltip("Reorganizes the windows to take as little space as possible"); + gui::checkbox("Lock First Column", "menu.lockFirstColumn"); + gui::tooltip("Makes OpenHack specific windows stay in the first column"); + gui::checkbox("Lock Windows", "menu.stackWindows"); + gui::tooltip("Realign all windows automatically"); }); @@ -485,10 +492,14 @@ namespace openhack::menu { } std::map getStackedPositions() { - const std::string builtInWindows[] = {"OpenHack", "Interface", "Keybinds"}; - const size_t builtInCount = sizeof(builtInWindows) / sizeof(builtInWindows[0]); - auto snap = config::get("menu.windowSnap"); + auto firstColumnLock = config::get("menu.lockFirstColumn"); + static std::array s_builtInWindows = {"OpenHack", "Interface", "Keybinds"}; + std::array builtInWindows = s_builtInWindows; + if (!firstColumnLock) { + builtInWindows = {}; + } + auto snap = config::get("menu.windowSnap"); ImVec2 screenSize = ImGui::GetIO().DisplaySize; const auto scale = config::getGlobal("UIScale"); @@ -513,11 +524,11 @@ namespace openhack::menu { return positions; // Rest are stacked to take as little space as possible - std::vector heights(columns - 1, snap); + auto columnCount = firstColumnLock ? columns - 1 : columns; + std::vector heights(columnCount, snap); for (auto &window: windows) { // Skip built-in windows - if (std::find(builtInWindows, builtInWindows + builtInCount, window.getTitle()) != - builtInWindows + builtInCount) + if (std::find(builtInWindows.begin(), builtInWindows.end(), window.getTitle()) != builtInWindows.end()) continue; // Find the column with the smallest height @@ -525,7 +536,8 @@ namespace openhack::menu { auto index = std::distance(heights.begin(), min); // Set the position - positions[&window] = ImVec2((float) (index + 1) * (windowWidth + snap) + snap, *min); + auto windowColumn = firstColumnLock ? index + 1 : index; + positions[&window] = ImVec2((float) windowColumn * (windowWidth + snap) + snap, *min); *min += window.getSize().y + snap; // Update the height From 946e80f32e29b7bd8215e555fd06763f2138d7e3 Mon Sep 17 00:00:00 2001 From: Oleksandr Nemesh Date: Fri, 31 May 2024 21:19:49 +0300 Subject: [PATCH 08/20] fix 64 bit crashhandler --- src/standalone/debug/crashhandler.hpp | 62 +++++++++++++++++++-------- 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/src/standalone/debug/crashhandler.hpp b/src/standalone/debug/crashhandler.hpp index fecfa14..13ef4ba 100644 --- a/src/standalone/debug/crashhandler.hpp +++ b/src/standalone/debug/crashhandler.hpp @@ -4,16 +4,6 @@ #include "logger.hpp" #ifdef PLATFORM_WINDOWS -#if _WIN64 - -namespace crashhandler -{ - void init() - { - } -} - -#else #include #include @@ -139,6 +129,35 @@ namespace crashhandler { } std::wstring getRegisters(PCONTEXT ctx) { +#if _WIN64 +return fmt::format( + L"RAX: {:016x}\n" + L"RBX: {:016x}\n" + L"RCX: {:016x}\n" + L"RDX: {:016x}\n" + L"RBP: {:016x}\n" + L"RSP: {:016x}\n" + L"RDI: {:016x}\n" + L"RSI: {:016x}\n" + L"R8: {:016x}\n" + L"R9: {:016x}\n" + L"R10: {:016x}\n" + L"R11: {:016x}\n" + L"R12: {:016x}\n" + L"R13: {:016x}\n" + L"R14: {:016x}\n" + L"R15: {:016x}\n" + L"RIP: {:016x}\n", + ctx->Rax, ctx->Rbx, + ctx->Rcx, ctx->Rdx, + ctx->Rbp, ctx->Rsp, + ctx->Rdi, ctx->Rsi, + ctx->R8, ctx->R9, + ctx->R10, ctx->R11, + ctx->R12, ctx->R13, + ctx->R14, ctx->R15, + ctx->Rip); +#else return fmt::format( L"EAX: {:08x}\n" L"EBX: {:08x}\n" @@ -149,15 +168,12 @@ namespace crashhandler { L"EDI: {:08x}\n" L"ESI: {:08x}\n" L"EIP: {:08x}\n", - ctx->Eax, - ctx->Ebx, - ctx->Ecx, - ctx->Edx, - ctx->Ebp, - ctx->Esp, - ctx->Edi, - ctx->Esi, + ctx->Eax, ctx->Ebx, + ctx->Ecx, ctx->Edx, + ctx->Ebp, ctx->Esp, + ctx->Edi, ctx->Esi, ctx->Eip); +#endif } std::wstring getStackTrace(PCONTEXT ctx) { @@ -167,12 +183,21 @@ namespace crashhandler { memset(&stackFrame, 0, sizeof(STACKFRAME64)); DWORD machineType = IMAGE_FILE_MACHINE_I386; +#if _WIN64 + stackFrame.AddrPC.Offset = ctx->Rip; + stackFrame.AddrPC.Mode = AddrModeFlat; + stackFrame.AddrFrame.Offset = ctx->Rbp; + stackFrame.AddrFrame.Mode = AddrModeFlat; + stackFrame.AddrStack.Offset = ctx->Rsp; + stackFrame.AddrStack.Mode = AddrModeFlat; +#else stackFrame.AddrPC.Offset = ctx->Eip; stackFrame.AddrPC.Mode = AddrModeFlat; stackFrame.AddrFrame.Offset = ctx->Ebp; stackFrame.AddrFrame.Mode = AddrModeFlat; stackFrame.AddrStack.Offset = ctx->Esp; stackFrame.AddrStack.Mode = AddrModeFlat; +#endif HANDLE process = GetCurrentProcess(); HANDLE thread = GetCurrentThread(); @@ -343,7 +368,6 @@ namespace crashhandler { } } -#endif #else namespace crashhandler From dd892238bf4f820e3944d3d9dcec9b267a38fd22 Mon Sep 17 00:00:00 2001 From: Oleksandr Nemesh Date: Fri, 31 May 2024 23:38:56 +0300 Subject: [PATCH 09/20] x64 libcurl --- libs/curl/CMakeLists.txt | 7 ++++++- libs/curl/lib/x64/libcurl.lib | Bin 0 -> 13408 bytes libs/curl/{ => lib/x86}/libcurl.lib | Bin 3 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 libs/curl/lib/x64/libcurl.lib rename libs/curl/{ => lib/x86}/libcurl.lib (100%) diff --git a/libs/curl/CMakeLists.txt b/libs/curl/CMakeLists.txt index e946898..90fc7ee 100644 --- a/libs/curl/CMakeLists.txt +++ b/libs/curl/CMakeLists.txt @@ -1,4 +1,9 @@ add_library(libcurl INTERFACE) target_include_directories(libcurl INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include) -target_link_libraries(libcurl INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/libcurl.lib) \ No newline at end of file + +if (CMAKE_SIZEOF_VOID_P EQUAL 8) + target_link_libraries(libcurl INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/lib/x64/libcurl.lib) +else() + target_link_libraries(libcurl INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/lib/x86/libcurl.lib) +endif() \ No newline at end of file diff --git a/libs/curl/lib/x64/libcurl.lib b/libs/curl/lib/x64/libcurl.lib new file mode 100644 index 0000000000000000000000000000000000000000..b4dc919072f385c16ba3c37437ca8accd03745e3 GIT binary patch literal 13408 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 Date: Fri, 31 May 2024 23:58:50 +0300 Subject: [PATCH 10/20] Update gd.hpp --- libs/gd.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/gd.hpp b/libs/gd.hpp index 7c4ab8e..5408084 160000 --- a/libs/gd.hpp +++ b/libs/gd.hpp @@ -1 +1 @@ -Subproject commit 7c4ab8e6199b373b33c4f55d2fc72ed532e7c958 +Subproject commit 5408084dbdc04f2be30b90b88e879e9b6ac7dd71 From 9458fa76e7a8aac88c22f89b5fc4433efc3bcbbe Mon Sep 17 00:00:00 2001 From: Oleksandr Nemesh Date: Sun, 2 Jun 2024 01:03:45 +0300 Subject: [PATCH 11/20] remove 4gb patch --- src/shared/hacks/shortcuts/shortcuts.cpp | 49 ------------ src/shared/menu/menu.cpp | 6 -- src/shared/platform/win32/4gb_patch.hpp | 94 ------------------------ src/shared/platform/win32/win32.hpp | 1 - 4 files changed, 150 deletions(-) delete mode 100644 src/shared/platform/win32/4gb_patch.hpp diff --git a/src/shared/hacks/shortcuts/shortcuts.cpp b/src/shared/hacks/shortcuts/shortcuts.cpp index d581a0d..06fcd1e 100644 --- a/src/shared/hacks/shortcuts/shortcuts.cpp +++ b/src/shared/hacks/shortcuts/shortcuts.cpp @@ -9,48 +9,6 @@ namespace openhack::hacks { -#ifdef PLATFORM_WINDOWS - - void Shortcuts::patchGame() { - gui::Modal::create("4GB Patch", [](gui::Modal *popup) { - ImGui::TextWrapped("This patch allows the game to use 4GB, instead of only 2GB."); - ImGui::TextWrapped("It is highly recommended to install this patch, as " - "it resolves some \"Out of memory\"/\"Bad Allocation\" crashes."); - - if (gui::button("Apply Patch", {0.5, 0.f})) { - bool success = win32::four_gb::patch(); - L_INFO("Patched the game to use 4GB of memory: {}", success); - if (success) { - popup->close(); - gui::Modal::create("4GB Patch", [](gui::Modal *popup) { - ImGui::TextWrapped("Patched the game to use 4GB of memory. Please restart the game."); - if (gui::button("Restart")) { - ON_STANDALONE(std::exit(0);) // TODO: Implement proper restart for standalone - ON_GEODE(geode::utils::game::restart();) - } - }); - } else { - popup->close(); - gui::Modal::create("4GB Patch", "Failed to patch the game. Could not write to the file."); - } - } - - ImGui::SameLine(0, 2); - - if (gui::button("Cancel")) { - popup->close(); - } - }); - } - -#else - - void Shortcuts::patchGame() { - L_WARN("4GB patch is not supported on this platform."); - } - -#endif - void uncompleteLevelConfirmed() { if (gd::PlayLayer *playLayer = gd::PlayLayer::get()) { auto *level = playLayer->m_level(); @@ -167,13 +125,6 @@ namespace openhack::hacks { }); #ifdef PLATFORM_WINDOWS - if (!win32::four_gb::isPatched()) { - if (gui::button("Apply 4GB patch")) { - patchGame(); - } - gui::tooltip("Highly recommended to install.\n" - "Allows the game to use more memory, which resolves some crashes."); - } if (gui::button("Inject DLL")) { win32::promptDllInjection(); } diff --git a/src/shared/menu/menu.cpp b/src/shared/menu/menu.cpp index 15a7726..6585ee2 100644 --- a/src/shared/menu/menu.cpp +++ b/src/shared/menu/menu.cpp @@ -127,12 +127,6 @@ namespace openhack::menu { if (isInitialized) return; -#ifdef PLATFORM_WINDOWS - if (!win32::four_gb::isPatched()) { - L_WARN("The game is not patched to use 4GB of memory"); - } -#endif - addWindow("OpenHack", []() { gui::text("Version: " OPENHACK_VERSION); gui::text("Build: " __DATE__ " " __TIME__); diff --git a/src/shared/platform/win32/4gb_patch.hpp b/src/shared/platform/win32/4gb_patch.hpp deleted file mode 100644 index adb4675..0000000 --- a/src/shared/platform/win32/4gb_patch.hpp +++ /dev/null @@ -1,94 +0,0 @@ -#pragma once - -#include -#include - -#define WIN32_LEAN_AND_MEAN - -#include - -namespace openhack::win32::four_gb { - /// @brief Whether `isPatched` has been called. - inline static bool HAS_CHECKED = false; - /// @brief Whether the game is already patched to use 4GB of memory. - inline static bool IS_PATCHED = false; - - /// @brief Gets the path of the running executable. - /// @return The path of the running executable. - inline std::string getExecutablePath() { - char buffer[MAX_PATH]; - GetModuleFileNameA(nullptr, buffer, MAX_PATH); - return buffer; - } - - /// @brief Check whether the game is already patched to use 4GB of memory. - /// @return Whether the game is already patched to use 4GB of memory. - inline bool isPatched() { - // Check if we already know the result - if (HAS_CHECKED) return IS_PATCHED; - - auto exePath = getExecutablePath(); - - // Try reading the game executable - std::ifstream file(exePath, std::ios::binary); - if (!file.is_open()) return false; - - // Read the file into memory - file.seekg(0, std::ios::end); - auto size = file.tellg(); - file.seekg(0, std::ios::beg); - auto buffer = new char[size]; - file.read(buffer, size); - file.close(); - - // Check if the "largeAddressAware" flag is set - auto peHeader = reinterpret_cast(buffer + - reinterpret_cast(buffer)->e_lfanew); - IS_PATCHED = (peHeader->FileHeader.Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE) != 0; - - // Clean up - delete[] buffer; - - // Return the result of the check - HAS_CHECKED = true; - return IS_PATCHED; - } - - /// @brief Patch the game to use 4GB of memory. - /// @return Whether the patch was successful. - inline bool patch() { - // Try reading the game executable - auto exePath = getExecutablePath(); - std::ifstream file(exePath, std::ios::binary); - if (!file.is_open()) return false; - - // Read the file into memory - file.seekg(0, std::ios::end); - auto size = file.tellg(); - file.seekg(0, std::ios::beg); - auto buffer = new char[size]; - file.read(buffer, size); - file.close(); - - // Set the "largeAddressAware" flag - auto peHeader = reinterpret_cast(buffer + - reinterpret_cast(buffer)->e_lfanew); - peHeader->FileHeader.Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE; - - // Move the original file to a backup - auto backupPath = exePath + ".bak"; - if (std::rename(exePath.c_str(), backupPath.c_str()) != 0) { - delete[] buffer; - return false; - } - - // Write the modified file - std::ofstream newFile(exePath, std::ios::binary); - newFile.write(buffer, size); - newFile.close(); - - // Clean up - delete[] buffer; - return true; - } -} \ No newline at end of file diff --git a/src/shared/platform/win32/win32.hpp b/src/shared/platform/win32/win32.hpp index de1b968..216a44c 100644 --- a/src/shared/platform/win32/win32.hpp +++ b/src/shared/platform/win32/win32.hpp @@ -11,7 +11,6 @@ #include #include -#include "4gb_patch.hpp" #include "dll_inject.hpp" #include From 14cf0f97f41bde80d8519b144bacdffbbb4a219c Mon Sep 17 00:00:00 2001 From: Oleksandr Nemesh Date: Sun, 2 Jun 2024 01:04:06 +0300 Subject: [PATCH 12/20] 2.206 changes --- CMakeLists.txt | 4 ++-- mod.json | 2 +- src/shared/platform/win32/win32.hpp | 1 + src/standalone/xinput/injector.hpp | 2 +- src/standalone/xinput/xinput.def | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e0eb0a3..4619915 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.15) project( OpenHack - VERSION 2.3.2 + VERSION 2.4.0 HOMEPAGE_URL "https://github.com/Prevter/OpenHack" LANGUAGES C CXX ) @@ -189,7 +189,7 @@ target_compile_definitions( set_target_properties( ${PROJECT_NAME}-Standalone PROPERTIES - OUTPUT_NAME "xinput9_1_0" + OUTPUT_NAME "xinput1_4" ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/bin" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/bin" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/bin" diff --git a/mod.json b/mod.json index 460253b..8cf06be 100644 --- a/mod.json +++ b/mod.json @@ -1,7 +1,7 @@ { "geode": "2.0.0-beta.27", "gd": { - "win": "2.204" + "win": "2.206" }, "version": "v2.4.0", "id": "prevter.openhack", diff --git a/src/shared/platform/win32/win32.hpp b/src/shared/platform/win32/win32.hpp index 216a44c..003f8ee 100644 --- a/src/shared/platform/win32/win32.hpp +++ b/src/shared/platform/win32/win32.hpp @@ -130,6 +130,7 @@ namespace openhack::utils { {1704601266, "2.202"}, {1704948277, "2.203"}, {1705041028, "2.204"}, + {1717243515, "2.206"} }; uint32_t timestamp = ntHeaders->FileHeader.TimeDateStamp; diff --git a/src/standalone/xinput/injector.hpp b/src/standalone/xinput/injector.hpp index ac36839..e4b775b 100644 --- a/src/standalone/xinput/injector.hpp +++ b/src/standalone/xinput/injector.hpp @@ -12,7 +12,7 @@ namespace xinput { void initialize() { char syspath[MAX_PATH]; GetSystemDirectoryA(syspath, MAX_PATH); - strcat_s(syspath, "\\xinput9_1_0.dll"); + strcat_s(syspath, "\\xinput1_4.dll"); hMod = LoadLibraryA(syspath); if (hMod > (HMODULE) 31) { oXInputEnable = (tXInputEnable) GetProcAddress(hMod, "XInputEnable"); diff --git a/src/standalone/xinput/xinput.def b/src/standalone/xinput/xinput.def index 6dac1ca..3fdcf34 100644 --- a/src/standalone/xinput/xinput.def +++ b/src/standalone/xinput/xinput.def @@ -1,4 +1,4 @@ -LIBRARY "XINPUT9_1_0" +LIBRARY "XINPUT1_4" EXPORTS XInputEnable From 7423783d931b9bd506d32725db4caa24742322bf Mon Sep 17 00:00:00 2001 From: Oleksandr Nemesh Date: Sun, 2 Jun 2024 01:04:41 +0300 Subject: [PATCH 13/20] update libs --- libs/curl/lib/x64/libcurl.lib | Bin 13408 -> 20662 bytes libs/glew/lib/Release/x64/glew32.lib | Bin 757468 -> 991246 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/libs/curl/lib/x64/libcurl.lib b/libs/curl/lib/x64/libcurl.lib index b4dc919072f385c16ba3c37437ca8accd03745e3..ea36565c9718c399e11d4646cf085a8c1e0628dc 100644 GIT binary patch literal 20662 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 z z*GtfjiB`Np%u(iodh3_BV}nut%xz~?YFXxdJRSEp76aZOYyB><@nGB_i58S3U44z~ ztq8q`TrWW}5-qki%3M%yq;DpB4d8q|8+`s<79rvcdjZjc{F&Rcs*c(nT9Z096_w;@ zI(}J%K3_A%NVF(lgNg5DnH76$eCjc1B}9v?jV7d*XLv@M)5m2=#L(iP7tlRY>LNaW z+{&Z;u^cf6y&zp%4eV9-V}o)2h80*QyTDJbqR=7(9JkGS0&0^7%)zv%9^k?AqI#-1 z9@9F&Sym^a1HTo13!!Y!5raTBUSU~AZb5-qaE_r`Ilym`iQZ!=vk zA5>Kvkq3Rn$GiPEed3;H|c5intAcxx@ZQb4(tn z9NR>KQ8|Ju`)|(1^~hpiX;6>-F0=7qT#rNx`eO=>G8&qj-22%IE2s+{bw&Hzswv_& zfVbOgX+#c2f;Q&}xJ~Zt7Rjir1j4cVlp`?Q0TFjNEDYx)?$t(F8RF$en;bX9L`qWY zYkjN{=TW@ms4S&#@^G@2NYGOGFbymfq4O?%MaGt@)UnFsKd^+q46f@8J|@9D@r&_G z`;xaRFN1RamIof=d^UN&9PRqmc81sWt8maqB*I$X(cE)DZDP+G9&g({3---+&xVK9 zn%LVL9@W}C3wCC9d_)m9iY9jU#>e+|EcU!{{-V=(J3ed{`5EPpk6Hyh7CS#VxI@H? z>W?oSM!aAbb4N#UM(vEn&QIRD4(zem^TzEn+SlEUH))&L+Z*SP7F}}oJ#V}%w@a%o zhN*98fFZ{Ly44pedTj%bH9}v=iJt~5OsX;+vk4u z_!rG8<#eGD|Hg@Ti%Zs10{UI!bfFRdmZhI7syvN@8tda5XmhmkcFTOQq67|>YiSwm~|i(Iri-mu>2762@N z`XwGZ$zo@1SZ^n8WGWSt!at9SgvHLMe!-9a&?svo@?ZI^B%(#ubC>EgegSyt84wvDErV zbD&Y)n%MD%^+u=pu#a3ZIBzK$8|Dq`?JTG_+8P_?jm0i+!+N8$Y1l`um>_Q~?$&;v z((8okC)aWT#PaJyb(kq$u`4r=qL8Dv1SGfiR9N`fqLf+Rg72A15p&b!-L!eRcucX6 z>`dQ^vJH_~#?}^M-Lh)k;l7o zm5lzCP!;7+7So+MLzF6*WCW@^0b+eu9%o_+Dr>w5(_;rfc0gd}(eXC~b8DA15#z*R4 zAWIni@mtG-Df7gz(#$F&96h&Wuk4f|AU(F!Pwm#U@;zX`Gl5W8C>$F#QE__Q#FET6 z0{R%J)4O&)H*b-g-jVeCWsXA@ot)m0^xFfGoZgZ2y8)4$-jVdRkD*N z5`kq?4$Fd!U9Rsoe^TEvJE6a;bc1yMcChfGCth9LJlBod$&3X(s0e3xJdsHQcVww_ zn@=N$Sg1YHLu$94(hV|pr{1M7_<=L`Rc07b>9n}7!av`*S~;lpEmB7g;nLAZdb)L9 z?GPz(>4^6L1b*Pm5|)lxq7kZm+u>d#x=1Srmg%xzasglp^hjT_=nnA>3y~6+j<{7R z@PpFXVPB%Q)6Uro?Sr<1$B^Bqbed3=sM)!1*4wVVNC`_v-l!J%xO7hMQ0dU;Fdn9g z!1x`PPWr5Fr{{$~gVG@i^e7m2+TH1{-CfjjBJKbEpmbPf7*Xl?ai`sd2Hm8|toD&Z zxO9SXr=1e+MNkJ9CN^>{wj*ni{nMQ+ih-_M7w;T_}?`W=+m^`?=DZz zsdXO(68c_Hgyr?CEk%N-muYXmQ9w|kClX3Nb&B)l?s2vFk%N4GSbSd9&(!Qn+7k@q zM$65g6sCT$-7cqXFN{RD0>h)=iMcFFcWp*>vfb6KdHHp-p&;?g@6)PmYl=b(WFvNI z?AZawmK~uWHjh7Y=IE)0^TmGA^ZpV^q+Qy}+fUE$?S-C!9)_zBlMd`(`bxBs=GYj?ek3M)D6=DfFxXiJgw1mkKoj!fDF2 zT)Y;8NhxV3bL{KdxNRm>dc=|~GH1QATx&f4FFg6O0^ITdpYzx!Z3yKZ1@}?TsK_m+O#HixYaj>XwqL1R+m!*z+lS9`@Mf zF3m0S?_cV0VrZfA03vC#0A5e|Ssu?+0>Qgj1HCzuP~w zJy%l(4KX}jtX;Zi?Ots+59k-RvXLBU>79>xImIB;QwWovVi})@s8A!!epe;MLdUD^ z%P-6Q zVwIb2+clOSUNac&$;J2mwBFH-Z%6yk^x>s5f~8{(Iy+Va%26I|e%sNfq-qQ0D?_Af zySb|6q?ht7(>!{8ztN2*!CRuiFCHEi`8!hk^xC9Htf*!>-y)2r@+%Q^@BJ}7yn$># z&c6Yvw5km&$DU+V@6J$37Y}rp0+mjnK7X~lO~c!}t2ex|K(4DqZL9ut+dgTM1CDOI zje}aP{D94$JiLj-B@+USZSf&o^%yTAz>FSVJ`Me0z^tAbfA|K!)|2MJm$X{2eOj!v z0xvO4+T^E~st(gmSNe@f*Q`7s+OHLADmERk(jd@h4a{k&f^oSkbFMNCGBdzPi1@Yd ziN4U-N+h`d9UT%#MfaLsp%h;jK3Q9*FsT=~i&~ml-=D&3K z7x${I8_vUw&id2On))Yu(u9OVzG$kRUxb4HPlsvyqgt+}da*=8%g?`mFE@vEd44eW z*UU8n$V+8UYrfRaL|f`?D~3A2s%zJvg_d6%>(%1>jr|$v`51t#zNCoTxR{G)cf8E9 z>wqmLF`1~61CFS7$-y<=Tr`!f)2*eTi}Z2|07B1u`X*oOhU@NQh}YGA3N&nl7dJswa^$@ zmh*Nr6&BN^Gy++H;ekn6V(DbVd9(O2ZLQu?W<-Tjp&=cwq^%z9sZI3wo6j<572gsQ zK5b!Me5YqEmk;!DzgYd^5=y+nluXmQi|uwp1)jchGtwk!EPog`WJ^#ut*-vn5$W;Z ztRer0NT*kVAJd8F>8^;y-vyORH+k6X`V@i8`ZGdUDt`;rF5$oZ7y5tC{{GqDpZxtl z{N>;Ly-xqT`sc}C{>`(~e@K7)5C7r6{EvS5<^TGRfBof`fA;GyfB8>-{pEl9=fD2) zAN;4k{<5Wi|1bSp{b#@a^8e7kumAb4zx?0y@8iGt^_TyH{=NAxe*NYDq%U^%_ z-|640|MJ&g{x|yfZ~xV=zx=QC@9e+&^_TyJ{{5?e{p&CPGyVH#|265Rf4}}W{~vpI z7u8kuHF|vQ_xA-Np&}v?5fPCh85t2GDiM;AArT=WA`&7YqM4bQnVFfHnVFfHnVFfH znVFfHnVFfHnVFfHnHiap5gF0>p7ESB#{aoEH|O#kFFxZpfW6n6YtFfr#Qs6Hn1*wh za;YuaQJ=`in0%QnS}`ff7A>f`+!m)%lWdFQsJ+4#CsE#mSWwy17AH`WVv7SP>}89+ z7@SHh$i31QyOH197Tb|_l`S?QHO&^Q5qq^QmLsN*Efzq(hPly##&lbpLFKiKjhqZy zY(?^QtP9DRwpfYyzP4D5@GM)*h2M{LLS)-wBAQXtpZHNSfcTIz&=%W}mctl`y`K5u z=GtO9S~2wo;=sf_a)X9JtQAH1tO=PnvKAx_CclWh$rkfr7m#15H?sybp<)R0qv96E zKt-V~4x@M|@nCQfHAUX7lU<1-)yi z8)C=UViBTi$vvXR@-bwcEoPz(lkOx=)Ya27C>=)~QP99E^2f7gM zkdKiQ==10$oJIBH1Uux4a0AYLRsX^T}zTS(8N_fy1=q(!z^kA$bmJHi$- zHpDaRO&mk<65_<*XUPe2mog^Oo?{H8E@N!OJWqTum(v$$Lfs403Pmf32fbh9T12d5 zPeHuInSoZ+ui{#iyi6UDv)UG$(c=~FLF^jtf&Hp2W}pod*D}Uy)DKOlSV#Sk`#Sd` zc|EyARzKvQU;eA^yLD+WgK|2~h;QU4T4)!bxJ|s8D-bu_z{)j$B>MqU$ zqg$o_;HB6SbFhnP>JY^f5R*Cj*u@Dd`q98@F@2o`#a)C+A-FH zxbMjYB92o>s6TK9q8T+OID3%$BXOb6Nn5N%(odWl$UQ}lkoz;Q$Zg^k`M;18WS{0f z^!SzaAm$8v9Ff0q4kNsok0F1jhEUJ)iZ;~$!M_WrYM~EM@F!y;y_LOz;?I$1 zg#OLFu-m9VPNV7{_8$t`i3{2P5)V>@BUT|+al|5os*aciQ**==w4q*i#0iubj@W}- z(-B*dVmV?h5^YB;LyY5y6^L>jF$b#Wh-uJ$K871GCeET(I-(g3A&xkW@=!+{!jKM* zIDq^xN9@Lsj*i%i^l(S4M&bpISc8}dM=U^OCr2znLT5)TMpzd|%!Y_$E}TU}SLQ%j z6l0^Rn#@WT8tw$A@f3Vf}~hStViNSj#!E0I9?HXu_NZgjCaIjw4vb= z=0I(NBhFy*rF=cn5fjmj^2?YT`AN)$-j_RK9paK5u@LSR*0t~sO;&8eHf79 zh>b|>MO=tU8AaTfVPPCxR5)NIy(9{m{uaRaCY!Ur-x+EANAu2FnF zYe9CdBQ_)H2JS&b9`nK;#66Jtj+lxTOuCWSQ9GE}QE?M-ptOKoqV#4*97XvMUQv7t zpGSV7BX%KsD7i*@5q*k;Tj>#m71JYdZ)2^HC43C?c4~k&Of032s2@h}qoj=ZkvrTG z+mTbwI?!VTJ%QK?)`R$w>?4F#GB)&4tOI9IQRRq($REuZNUf%qk$eZejrbbkL--i# zi^y8y!Z}opb;My5*Re+A-pLrqs;3r68%HgW)WBXu)OhlWcGNYp29!@=k0E~|c|pcq zG&K7m<1LT#@UICb@Uf{yiP6< zy`J+6?iTYa)PXloH>Ypi=KqNiScn7Z z&SR8)$y_Ks$SaD!A}-_|q8HHPYwC#T!;FEbZ}=F|N5}(0zoj=2ew5yT{vC6m1$D=W z2SdK6-pD;p%t-se5gQP9f-zzLNFC6M>XV!a$p48opwB6K1o1ypXGAnHAHsg2&S*#d zX?hUFzp|f^bB1}4`Wvw#qM6vxhU(vm3B_mWBMkV1SP1+G|$m5;Bj zhq$i902$@-^AE=F=8EZPL1nZn_93e~*CH;)6-y9$p(|!WjpbUjqwym0g4#G&oI>%% zuGoXDcvoyd(j~-?hy+*6hkL2Z&p?<5wTZ4cfr86e2U3z;u?!KHGY{HPpUgEVxq_IG z(}Nlzt|u`eB83{E4Yj>oaT2Ae#DL5zxfV&i$q(YLVtmA=v1YWR?rK*Y$B;g**pAd| zT(KMx>BN8*R9@?f{m9NBA4s^4aS)YB4iVOu7+_|RceJCnA9+VXHhD)zfAWFU0j^k$ zgn`@(nL}@(2}Rd)EmCud7tuGkVisCZpXZ7*C>g{x$jE1HNW78!!X502NjQVbo9HDJ z6u4pwl5ZwgaEDMY97FysuGos+h4dyOhq4B=qN<44QG6>oM_w_#j^x{z3lSyc5BlxI zj#ku_QYRD+BR*u6F+MVeb1yQ=`50Lv=xd}@utvm=Bo7FyWUbIg(H}U6hAP&B>d}mi z@@o1XC3m>u5Q=JCaR7y5s1JtJ5-$qI@`{2wVnODe(Bk3;UMeHPUiO{=UF$3pNH<`Xe**)YPMN^0edH1qbBuyo6h`5jW zAf{0VG@<-{)`EiRuGodF2gnyvXSiYw;veK*M9$=1*bk9&G^2JFwM4V`MgCmQ7i2ufwTPR?dLSRC-_eG;`Q!klPjJ>DYXR#(%9HdiViz(# z!k!`rXh-8BVnN~4CX zLi}d#f&UI`LmL{m(BCM2*A;t_yOr}0+3!(TWNst>NPM5Zg}vPs6LAt{A8-$Hc5n@P ze@KlGx0Adh>?76zeHVR$R@8sYnS#l?Ss!M9!dmvwXNdfi_#pRkmZ1%epRpEH?PE@q zeolTdU_W~rnO{&pWE>zr$oi7nBkdsj4k=&JYluHYObGj$UPBuu9j2F2^9_3&B}eE9 z6nx9tk#&?Yk@g++hCIeSIDwMy*=NW<&iv@}1A7LsCs-5OQ2ir4jNFst2MIq>J9Iup zPeA{fT;dc8o0t<>zYsT)Pct53f92nJgr4CZ*uRlGoJB)3_oDE3_7&34at~tu;9BS{ zjE^&@{gZ1^)k+>w_7~?A^3O3Z`ut7p5YtATq5ngza0L17^bZpLr9RMwC+cw&`HCmD zAWrr8e#PVa6;Dh<8ya*^oJN)5iDM`>J+UA8mM3;1-S)&<#5tZ=1nF`wT2SM04~l(H z>_cwgiLFSJ+=GM=Pb@`fs3&H@?7+PcVIJSBctY>!iOFcilyF{Ae*y8JI>Hl8sOiMV zDDUivgDB`iT*!;`#171akp53WIWPfu({?-Wn0M079WgPlrFa2n-Tdg1^IdV69Qvaj;Q zcJxm3#45yH?eWaU6R~}W7w$Elm;sUQ@yv#}QFbk3ATNV^k#?OYRwFi(JizTsZP1GP zEapXdKXQ)zZ0d^M{XMY)od>X1w4!>TCyt{$hh9VR_1uHPTCJ|XiqFgL^biizk|G?4Yf7o7`0WPymy^r-`$TVIt_yS8`^8&peVNW4rjwd!E`B6TP)Vb^pL_fwjkn_kR+R^Yh{fDCY_*np%!kCq>}7;K!?kdiFc0i!*|$)a(t|jQ zy64CVs+Y09Q2RW+gR1591_r-CUXiwfGXSYCvIfMgq(>3+5_2JH75PT!%ghONHFKa9 zlU^ZSG_IjnQ1L2z3;Amq8$DiQZ3tV(z0hChT*W!mu4j*+aT?{HkY5z+Ax30=O6|~l zFY7|gXXF#^KJth&sQH{4p=v)hL)jOeIE=yr^bB&p>cjOyM$H+7M@2L%%QFfepG2jQ*iNq7+72!XU zPnaj!w>XEopNJV{r`WH^|Cuug*-i8SGJfH#LE357kECCT9kFMa7ooq=!)QZ8GkHMe z@0=qjKFgRW_=CJ7y@h`}5&tLgAgq;jq7C(bk$+U5^TY|1{LS7$pEmY9qWG<`7}?WnhWaSTIjU+h4- z`TZCPNFQq7rW8t zQsP8ZqAzCPEXpq9Ye-M>#ahH&?u)q)$-bz@0pwi4*AU%<7-9FMJ~)T^6y`utFUCPe zsxQ_d`AX(OWN%`Jd6h33a14Xfe6bO+SNmcP+ECNS7fqn@(=g=UV1QVumjk zA^bXWi#9Z7at~_yk`q*BF+R%r`Qk82v&j)k`ZFd54DiKz#15oRFmrq{38zqcy)X77 zFPC|dasz#U&Uxem_8?zOMJp=ueX$o=H_|&u8B7fkc@yh_C?GF5h02@h6%-Hg#V+)@ zh2BJTA?rc-Q0_rHYKw>$dACw`Bp3T)DZ*|e-#CZ55?`D~&F!oaLrUp+WDR3&h$|!C z@Q2f{IEBJ;Uu;L85nO}B3f6{*k-nG(y^^)T9z}iOR`CjZH1nbrjn%$rLCqc18maqa6)1eQ^TC57Fz$nnga5@G!MR=xlP17F0dL+$fmC z+(>(rxe+~=xnVxW+-O4iJbDi~k5hN_m`{Ds`3dHRSisykjj|_wp85D9dm-ya!c)u* ze-U}a8I(WGT9CV#wIJ;o_9POQ_+l9%pQZodFQvX{L&J0A6&1^f8zs-PXHc=+7spZl z0(C^$3i=L3FY=0lm7HV9eTmr7V->L@>SfMyM69OApuR$UIERUA=nXWyO1!9D%PSgR zBNj|s$15hiP94#>p8i1n8(fF_4SXJx-sCz=*+`Dw;y#$0m=E%8)`*DB#DVa4*k|y! z@Oi|(OHR;dE9X9<-eaFb-^RE&gUa{GH8Qtz4I)3Fw{RAfJ6JyoKBT_rvy<}|u^-Xb zaCZ?Gno;>NxkS!x&OIc5LT^FtVJ;lQkWU#0X?vLqQJ)bH_z!1Mha(vBIoBX{KfQ#w zFPIDZ0oIPQsQQw*kbjWKD#S6rZNAFyL2TY(vT!`U3c-{PE7F6G8WW7$UDxVv4#Aj?oVPx zbu0T96@M`YO3zV46#vb+gTglU4GR8YZsfL;Z>0arK1ZSm#45bF?c20Y&hgtP)N18r!q1JQ(XClCja=LTXc(!4;dMWW9<=o~N)bQy?7 zoI*)RAogKEXdpHtxkDgUASx^n^Wk?4_&y~NEvN|(_&y~NMHd8OFLEOSu?=aR0GA$4@ zpCEMb`#m4>B{z4|-e|h@}Y6B>!kZRbP4ng<0eUefqIR z#AF9z4%$)MpEaR$0KI^mfy9p9Iph%O*OMRQ=dxCm+`#-O&kMvM6b@o+Wara&7<^+O zj-X~R^~9u`s8s>$LOT}ROwSBq4h+79F;QN~m?#^{$H*@tkI1@}ydl0g5X%vE8*4)g zYD%a*s&A*B7+gvZBXt-#MtE5ursEu{hchm6%b6FcBgg~dDgvGUc)Jr*3oasxsw>sqn2dOi1XL2o49ty-NM9m7s zJm?QobDTldY`K@{6gxpULjxLEWue+tRN@IdXe>E@Je2h`4aOYdKI}wJ8EC%%s}31dIgEE zu=ioF;q1d%)VxaFk-3&UA?7vW#yM22qkoX~I`<=eJ$;GJZ!ibKHUzxymAs?uO~ygq zMskIex9Bx=-o$v&-=;5d97UVS6*Au;X2fja8i;qPBTk}tD|2J;dx6-Fv~8SgNP3^# zA$B`wKgDZKjc~@?4+mQe#Cll235PL1&TiAT4e5K&msF0?m@;LYJ}uZ zsWrm)5*zf-7z53y*+-wC@N@bSS^MdGBz-}@qw@iJ4EmSEh9;CAWIZVOiuxh@5IIHK z*UXC^hsiCHzTw(C#Vma zQ1l~tM30l~1GqntYn(vgDRO|cpNRnxP3(0vqx2W{I5JOjE+Xz%@(%S3|Ni3$a(`p} zh-+qEh~LQ(4kPa@{ea{@_;(R@3ug|Fqwr7WMOrKS8Igan573H=bIgnMzxf&>+SmhV zM)^PF5ZUeYEMotqMrcR1km4}%6v^`)DSD_6bf}IwxNe1#bWrT6cce0 zMV1u1(8rcyCBhvkrsE9CT`Be<+mm7g;(aORLl2~wgeH_rDGnk(MDm^#$$L_ySdaJ) zQY?fFlVTcLP}5P0qZks-oJhYw@;+H9;v%>fekZO)3#vPFEeg6wu^oLPxfZcqxfXtu z6jRZH+HO)DL4LFpTanydiY1UST!R+WTqwmc6vs-j8)+9Y9%AC8SOEQE)`XKNj+bH& z@-87xlq8S`x|}>9HCc+~2)}}S;v6b_NS^mdk=c{E z5t$;zOsKuMA1$a$CHJVgl2}mLn>?WODk%=3G>umjUQLY1>cf1PN<=}TUbmL$mF7#|E8gLTD{mB(F2T)VQ4`jV?bLcIc zLHYH}gWOyxHX->2`VV1wQp~_PR1YEs49+Ki=zSw|B5E*mLfpihIDw)9=0xVrQmjSX z5b6W_7IK6$C@Un77%)_djYukDPK4dcoM=IHG5Z4fw=pMrmryfA-_D#cOW6ZBjj~~^ z0l8)L4^oE{AEL|YcbFsS4V*%0g%o>{HIhAn#7c4kIf`CGGb*d75%NYe9#X2MSb>N; zq?m;^)Yj0CC>%qNA-z_Lb%-BJe?!(W9$HX;C-p#SJ+;H&anu@_4b%mRLXNyr3DCi-{k3&v3RPWeNKhanCY7!k4mt(T2L`*k34GM*kx7d1`}%DV91Nq2AL~~8*wjD8`!JZ4>*SWmx&VztJw#zUt#??i>fu$4TE20{YYCY z#cIU7M%`eqqi#5Ziq}~S^43!~q`pDj5Ve8*0R2t&1Da5_ks2W9E#^j#O`K)u{I(Rc zAvO~qno#-lEFTlO=KqwpyE7=6BD4n!ZL7Er$@S2%%^a~LQarznlTXnD`UVtLr>uhDt{w36g3k+vVZ4HK%cYJ z74d&iD}=SMx6p>VKZzB^t=xm`zsL)c&(YUN{G0qDtc@B#{f9cC3AOFahvI*!35JLe zu?Ja7h**bMHAE~xxE3Pjz|}*PE|BO@e4Y(VeO5U~a^9YVxBm|-D&AHy#NcMK7YXhL~- z2tRuX;b$+zjI4+du^B0yLc}U0b`B9s5Y>e-AR`$AXHnZVL>xhWREXGwgl-{XKH5

f(Ir%=&Bgo%zKTwEX`L?_W%bPti&8O6l!@V@T#OJEVx*`PqePV$&G)Q#h#E0Q)QYj9PTa|Rl*Wk$FJc8;u*0-JS&!p=lFTv^J2MpL97rjik0Feu}ZuwR*P4}8u6-F zD_#@p#Ou7L`wg){yeT${x5Os#w%9D*;d$k|Vyk#hY!mN`?cxKmLwqQ9ijTxD@v+z~ zKA}%P6??^JVxRb2>=$2%1L8|@P<$m0iLd#d{2OsZe9L>Uz7xm9_u{ztL7Wgjij(3e zaZ3Cwn#3>SwD?t=5x7;a4x+sxKS0zg6rbH{QZ84Ll`E7UN>3$4>7}G9S1P@gtCTe5YNd~Ijgqcht7ItGDVa)N zB}?h2WGnrZ0m?unN4Z|fRc=u7ltD_qa-%X>xk)KdZdQgUwjHo>CSmPb-U+XOtz%v&vHCIc1shys}(*L0O@^sH{|8QdTK1E31`Plr_q$ z%39?$Wu5Z6vR-*Z*`U0sY*gM-HYsl_o0WHzEy}yfR^>fqoASQ0UHL%Sp?s+9R6bI6 zDIY7ll~0sC%BRX+eXn zK{=uPsGL-OQcfv9D^1ET%4y|S<&5&1(yaWhoK^l%T9iMPR^>0{obtEQru?I{EB`7& zRa8~gR9!VxQ?*oEbyQdNR9_8LsfMVbY6mq;?Wl&U7pM_xC$+QMMU7Ous!?h;HCpYi z#;6ynvFb%?oO-buuU?`isF$jV>Sbz@dbygcUZM6-d#WjFFEv%YQtho?rKYJ@t9{gK z)O7V)HAB5l%~boUS!zEuTkWq7PzS0x>h)@_dV`v$4pQ^g8`Z(;O=^L9vpPh*MJ-f^ zszvIpYO#8oTB6>rma4I3Qw^+9!}`j9$HeOR5XKBCT1 zA64h7kE!$2$JP1j6Y2u>Np+$6l)6ZLT3xI@qb^aORhO#Isms*o)#d67>I(Hmb*1`} zx=MXnU9G;Nu2ElA*Q&3n>(tlP_39hy2K7yKqxzP*Nqt-0tiGdeQQuX!s_&`W)c4ix z>Ido$^+R>1`jNUz{aD?texmMCKUMdtpQ-!Q&(;0v7wQ4^OZA}om3m11T0N|OqaIPe zRgbFQsmIjs)#K_9>IwBn^`!cfdP@CSZBl^&hoe{Z|#5qN$pu>6)RLnx)yAqq&-=`C6b!Ekp~|I%r{9M=e~tK#R~iX`Qt$ zTBO!hi_*Gj(OP#cM!Qgp)h^QFw2QTP?Gi0PyHrcmF4K~<%e7?f3ay9MQ%li$X{p+k zT5s(tEls;x>!V$xrEAw}8QOJPrq)->()wxHT7PYTHc-pauGez48?-!ake09As14R` z(h9VjwISLqTA?;nE7ES&inZIc676=aR2!z1X~VU0ZG={#jnpc&QCgKYTC3LX&}y_X zTCFx#tJCh(>a}rNgEn4k)Fx;XwY#)Q+TGe@?H+B4cCR*7yHA^@-LFm89?)iJ4{9^D zhqPJR!`f`^5p9n4s5V!7Oq-`YuFcn;&=zP)Lwl4Q+$=rnXUgOWUNqt!>uc z(Y9#sYFoAUv~Ak^+IH;&ZHM-uwp05^+ogT1?bbfg_Gq7Kd$rHBecI>Re(ekGfcB+! zQ2RXy0l_wePfJ+V|RV?Fa3I_M>)E`$;>c{j4==$-V=dKW!X@2W@X-SlX^yB?!osK@FT>2dnSdc1y#o}gcYxNBMIz3bGt7qx`^lZJqK0qI+=jhk# zx%v%yo<2y=*KgDZ>o@5I`pxv!li`WU@dAFJ2tck1=}IK4q1uQ%!w^ojai`Xv2seX@R!K1IJ*pQ_)d zPt)($r|S>sGxP`bnfgQeEd619w*H7dM}JhGt3RgC(;wI8>rdzl^e6R&`cwKM{b_x% z{*1mve^y_rKc_F#pVyb`FX$`u7xk6;OZqDPWqq~&ioQmFRbQ*Wrmxdq*VpTB=o|Dm z^^N*l`X>EteY5_KzD0jm->Sc-Z`0q`x9cD1JM<6ro%%=mF8yPDxBiK~NB>mctAD2N z(?8eu>tE;x^e^>;`d9iP{cHWO{*8V_|5iV$f2SYQzt@lJKjkSXT3@P zML(_os-Mw+)0_3*^|SgPdW-(2-m3qlpVR-=+w_0*cKu&n7>c19nxPwpVH%cU8;;=` zp5YsTA&n3t)aYP@86Ayq;{qeX=wx&@x)_m0S0l>kW<(p^jTqxXBi6Xch%+uW;*Cp; z1mjX8(YVY=GA=igjVp{EMo%Nf=w+lDR~o&ItBf?`YNL;Fjgf9#Yh)PL8JR|3Bg^P# zWE=gB0meWh$GG0eHEuBSj6p`eaicNVxXCCmZZ?J(w-|-SP@~AW)hIS@GfIrxjZ$Nn zQDzJ`%8e05g)!2oG)5U!#%QD3xWlM1#u&B6SfkFk)2KJb84bpGqtTdPOf>E?CK-1d zlZ|_fDaO6VRO3ElnsL7|-FU#5VLWKeG#)Z$84nw?jYo_*#-qku<1u5N@whSHc*0m< zJZUU6o-!60PaBJkXN)Drv&K^6Ib)geys_MP!B}CuXsk3|GFBNc8>@|1j5Wrq##-Yw zW1aE3vEF#Y*kHVAY&707HW_aln~isjEylaXR^vTmoAJJ}-T1)RVSH%pG(IwR86O+F zjZcg{#;3+!<1=HQ@wu_z_`*0~d}$mszA_FOUmJ&wZ;T_xx5iQ9JL8z~y>Z<5!8l?3 zXq+^DGENyk8%@S9#%beM zOx-k0)3i+6bWGRuOy3MlX@;1gW(PCO>}ZCY7nl)dC$qEJ#f&t&no(vqGurHK#+VnH zvF1f)oO!VsZ(d?1n3tM~=4ED*dAXTvUSakydzvX`FEiD=((G+sWu}=|n|;h{%yjcw zGsC>j%ryI&S!O>o+w5-+FbA4B=JjT-d4ri}4l?u28_mJyO=f|4vpK}P#Vj<3nnmWV zX0dsjSz_L9mYT!NGIO|DZjLZ3%#miLIm)auN1N5=9cGO=#;i5Rnsw%#X1zJiY%s^0 zjphV%qIs7&$-LW~Y~Eu|G4C~}n)jL0%=^vh<^$#o^Fec_`H(rweAt|AK4Q)>A2sKi zkD2q#$IbcX6XpW*Npqq3l)1=!+FWctV=ghDHJ6&tnaj-Q&E@6`<_hygbEWx`xypRm zTy4H$t}$OV*P5@H>&(~9_2wJq2J=mGqxqJ($$Z<~Y`$Y|G2b<}n(vw0%=gXh<_G2u z^Fwo|`H{KH{Mg)Weq!!1KQ;H7pPBp2&&~bj7v=%;OY@-lm3heg+B|H2V;(WTHIJI# zna9lU&Ew_|<_Ysh^Q8HcdCL6RY%+f_Pn*A*XUyNsX7hLRtoeu8V*Y8intz$+%)iYx z^B=R_{MQtgVyTv9>6T%cmSx$NW4V@R`Bq>_E5r)5I#^*=M=RXAz>2UsS)HveR;1O{ zin6*{(N=dW#=6jowJx&atc$I9>k=!$y3|UvF0+!X%dKSV3af|J(@L>=S*g~QR&VPn zE6uvv>SJAFrCZlp8P;`Hrq$QVvie!sR)1@NHPFhjuD5cn8>~EQkd<%UXbrY*vI?x5 zts&MeR-rZ2Dza|1imltM66aB5BgEii2v?f>+t-GvA*4@@*>mF;0b+0wmy3d+s-EU2|9qijrFRv)_ToaXT5H%x8ATeSZ`Vzt+%XA*4x%*>m6&0^{%zm zde7Qsy>D%|KCpIJA6h%DkE~tR$JTD^6Kjw4skPVo%-UytZtb_eunt&XS_iGKtV7n< z)?w=#>xlKOb=3OKI%a)u9k+h4PFO!$C#|2XQ`XN`ll6;r+WOTxWBq0|TfbXptv{?5 z>rboI`pY_J{cW{b|5)wTzm~8STeUS?w+-90E!(yo+qFI0w*y<+A$F+U!49)K+Tr#E zc7)x@?re9lBkitsl-GrjDhJBr#Y4^3W?0$B(-QONy543aa>+M|o20PCl zWaryA+Jo(z`14vf+e7SI>_U5}U1Z;C7u&blCHC!hsXfdtvxnQ|_6WPe9%)zFqwFes zv|VlAVb|DW>{@%QU1#5E*W2Ul27A2SXiu;w+IQKL?7QvB_C59#`(AsheV;wezTcj1 zKVZ+WAGBxM581Qqhwa(+BlaBoQG2fam_5&a+@5bgVK1*^BI_?Zx&p_7eM9 zd#U}Lz07{zUT(i&udrXVSK2SxtL&HU)%Gj)8vYQ{TKhG7o&CDK-hRX0V83Z^wBNEf z*>BsM`C~;}?04<0_Ivg=`+a-6{eiv1{?OiOe`N2nKel(UIIy&Lb1x|$1$?5ELaUz|rPL$KliFUd>G0ufftaFhQ=UnW>JC`^K&ZSPG zbD5LmT<#=0S2#VKo=%F>%Sm;vbb32iIcd(-P9NtQC*8T$$#AZ7GM&ComebG4cKSO5 zoPkb`bG?)6+~DLngPeTlMrW{dlT+Z_>kaSENGPLXq~Q|#R4lsLCLrOq&?%o*;K zJ0qM5XQWfacZ5hPMve7Q}2v(8l3S?qcg#o=-lN@a_)8}JNGzK zoO_+A&V9}_=YD6p^MEtMdC-~ZJmk!B9(HCsk2rIjN1eIOW6nJ1ac92sgtNeT(pl&{ z%69(mCjS-^!gIDa~=&R@aO9M zuI1XU`o9?JjnoahJHyx=Y>X+-2_b?sE49cZK_+yV8BhUFE*)uI870 z*SN2`Yu(q}b?)o#diM=?gZrkt(S6I^MJ>~xFHo3pJr`=!OGwyG0v-`Vy*8Rh6asPB%-M`#(?%!^k`;Xi1 z@{63F;;EkI>7L=4p5@t|DxYd7Zs3UZmI6i}Jd8 z(O!2i#=Fpq^)B+_yo*HPHrF++U8QyhXrq|cY^7?t%UVm?ZH_*%RuJ>}i8@xPkkeBb>=neL6@(R40y&>K$ zUZFSCEAnpjioM&s67P1e)EnlNdBeSOZ-iIjjr1zLQC^id+N<{N@M^pb-GZgE!u5^d@){y}P_g-re40?;dZ8cds|qyU&~E-S18J9`I&(4|+4bhrC(d!`^J~ z5pRz7s5jSp%$w&u?#=g}@D_MadJDa$yhYyA-eT_=Z;AJ;x72&iTjo9QE%#pVR(LOZ zE4`PzRo=_qYVQ?qjrXdz)_cuc=e_Q&_ulX}cyD?ey|=tg-rL@0?;UT8_pZ0qd(YeE zz3*-JKJa#UA9_2zkGx&p$KG!56K{|Askhhr%-iRE?(O%!@D6xidI!C)yhGmC-eK<> z?}+!UchvjNJLY}w9ru3lPIy0hC%vD%Q{K;BllO~v+WXZzGJ`Sbk8{rUbA{sR9=f1&>rZz@%758k?Z4u$@n7}V`mg!x{MY^U{u}-V|4o0R|CYbWf7{>e zzr$O}-}Sfp@A=#O_x z|DgYsf5`vZKkR?wAMwBSkNV&F$Nca8Id2iFD}!F54q&^O2m`UTlR|6o8cFvtn6 z4|0PWg1lf*kRRL_3=VDz3WA%1A;B#{VK6i(3T_RGgWH0V;P#+27#5TT!-Mi*L{Jfo z3@U?BK~*q1s1EK3YJxFAZ7?>d3+@c+gK0YFW45mA8Zdk2zCS?20Md~f?dJK!S3LbU{COAus8TD z*cW^r><_*O4g_BY2ZOJIL&4X<;ozI#NbqfNH25w!7JMHZ4}J(v1V08RgP(#^!OuZc z@Jnzy_%%2a{1!9^zXxZ7KZ2Iv&!9ExVY9kd1i1nt4Ufsl$+c|(^j4QWbC+R~A( z^rSBXDP@QZl^uASRYw^vFOU(klk6?>FM)wxqLyckT1%W@+G-SzARVESL7P`s$45ylk4Q`a=m;*Zjf)vjq)wINxm&N z%Xj1!`L5h5-;>+q`*OSdfM4+bQ0|l;$zAeexm$iB_sCD>Uiq2aCqI|_|J;R{57aC;ygh@*mkQ|CJ&{2~k6|5Iw{QF+;2nJH!cbL%a|_BnXiqAt9k59YVrF zI);RYTo4iw(kY~KNSBbvkgg$7A>BfvL%N5=gj^UB8}k4A`ZY0Z*ucF0Lx=Us9#AxF z%=nsy(c^}XsjC_J-#*_^KEASYWc`2t+{lRyiFUH!;$<3^9I9X6n7NYDR$ zQQtw?!^&&;zpM`%GrD%n@QK4JhmYX@_Wqw={@=HbtYG?n!y5i;#Q(z;eTV!XuBaV1 zvc7S6!|2A5!zxDBHB|lQ{S_n2$B!B|c6>wK_=f-fc`h6_qK2go8#l6Ucs>6^^Z)ks z`r#9X{nw(${nsk~^Q)Eh!^bf2|4hk$rfk^oipJr!Bly2#|F4|>&lLRUwf~jbVRd82 zjc)iKqnhNp8dk2s3nQp6v@p+%2s~;`2h37xoJp9FuNc23)2sZ zY`NaQ`rXuA>j3WeGmQga*sX^7Glpnb4Nv%DxsjSD%)SN+TfGqcJ6GK>otUW8lE=07gKJx zdBFJ0ZkOvh`2P3VZ@+1@)RqQsbNfF|;;A7ThxyYAGkvx=+zwCk?F=GDlU9atHs5ca zmJ6(p19jqTvo$@Jh;HYr)yA|tA%>sZ)pD`i&z=W-aQ)|u=I9gp&@7-tyL_5I3^PoP zyV;0tqCd?XOl0GJSTB~V8Cc^Z?z&SP!Sj4|82V)NF?#A+S=WXSq#TE^Pg30*^cmJF z_6jU^Yz}s@q#a=PFyB9-%WjwR(YGa&r2n7k>i4_(dZbB%1u)#*&KKWLXRGCU7-tZ9 zzJ9>qO_LjLspC`MtmZGa?=5Y37;`f~mgspo{GhII$7bKm1H%k(N|p!sx|niM@=MqOLjPwzIpX^t3CsS#2=q{4OP&L>6$WHgM~Vs3J}skYtGLGo;M&49%(ly)4WE1L&yQIi^o#05u18O~ zXi_ne?69-#VfQf1p$=GixY|^O#q1t#XJ;oT4v1-Y`+}ur!Q*yV99Hukwo0R6umI!B zdSS`)96LG3=J2$nv0iW09?Zou5g$SO*_#j7um6F6Vos#p@JPhy{#fQ(g5Irr*&_~N z%Q)>Syi8~A3}fjHLBKrWw`si&wBgg%-}!C(!wqDW?**#V%O`Wyt`sf=eZ?oENTXr z9QK3PIum=sJkN1#V$seXcAEnf<>lXX{W2L;K03?itJ#ju@*T#2r&iTIgsi8bGZx#K z^qXxzz^vC8=wY>LcTaE$^?Zhto}Y%L=|;XT$SpwEBH&=K(86W9X#_(i>Myo^93Qj! zVgZf7a8*}|9^73ur~ye!yid!O#+KZdg+3l`+ZFS$nvL7#?%5P77rv@7QB4IryWgs7phej$B5?IyDq4iD zN#WXAORIaie$e!J4%gd`nV4lJ2S)%89Co5~U|Zb|Vn+C?UN8Yp!Q~w-Ui2jXUzKlQ z>AIJ;5l}s>Y4o+^3UAL_E{kPEH#ppZ)g_oPWN+a^%J5=ne5uZbtdZt*1_zs#yJ+i* z9LjVD-8WaO0n>+#5`5$=mHvhrx6AE7*DK!gpwccEqtmIG2%2T?x^`J?HyD`Ca0_nS z?x3S-vA3Jm%LA?toBR6_tAnjL7C-Kje!kdX-nrvDuO^-mFiH)9(7Vm^<~t^5x_xWz zQw9XIcelAcp!z&l_!yYo4v+KarMemxLR?PG6qn)zoz1so0g%h`a@^onf}K-KqG&Nl zxc1929nvPdM&6}Ooe4(+?bf4UV7p*Di7lj!A+$WSWWQu7K_6t(Tb^W5Ju>|!j48w? zBC_HNg)_I*qPMWL;BvHSdO*r8{E?7qqqH^tO=UhlIgPq{ibcG{p4&#i^Hzl`30`%;5yRRk$)fB}7 za&%~5D)zf$sUzW>rAE~-te@djFp7IFOehEdmC(#ngWhe%5knD;5EZ}M>`x=y{c=SH z>-icd3GSuaW!U;e<&3~e_~yEmWfSXeRP)nvw}TB#{4)E^Y`9ZKC&gOmaLL^b+d(-* zG)e2qA}uM)u*Uq|ZhoMdFevPQY$9poq<1DZ#UtUBtz99>6~ZRxi1W^9y;&yArR=vv{XbUz11;$h2gr#PU?{-}_Xgl{B zbg}2y>EF_kiif%OqgCTrBzW6s1(FJ`TaoXrNl|O}8@aH^+MM0OrKC$6WWTK3pMO7t zb`g~pG})-!wwu_q`!pzcOy=O0oH)wC9kATLZ0YR0pS^k||H0JXBRc_M`qxus2S;;G z|3D)#L>P?9^%BFfT6S-@37vEefA_tlt$(go!)4Y2wO!geLa+NY9eX}X^6uLgGU7WY4?*8PI3>AKJCdC#7De9M9T|Rq z>@X3YHh0x2V+q~Sl#$vkL$H7U`E|CR!%0*&N`lU@@8$_Xze77eBh>!Pzp>r00ILK;X1!F?z z1Ys74)@Y&<1krjLDm*f*7wq$9bwD78c0@7m>E(Ml6&cWVS~S>d8Pr`QUJq)p_7zIu zr!CA+cV=nXq7sG#l6PO;zM8?r`VTVX&)tVZttt|r1TfR8kEkp0EkP_8X zYpAKSWsA^Y@nNjyw?pv+5f=eJ&3E7Hg-YP;+CX&49pW2?(JY+6v%zIJLML=l2zp%1 zVW?Lps1a~E{tusT`&I+w;(>?5!;4Pn5m5IK6H&uK3VzD@QHY9V*vL!rKwpGaATw#u zt=6hZ$}VT`=~OKr3D#f3;LU?52bv8XqoQDVD0@d>Pkw|ErQ8Xaj|wr<@f;o(sPz*h zkQa6?3^G=d6Q$$2@XWO9f^fxkku)Erix{+3AOh5xmWNys*-YD7*SK_XRx|~rs^Z!p z>PJ|oIVwz7!V@m(_u@4uhb)y5G`WY{Lby)A6*xERROpk^VT;6ZHB<=?eY8c1LdFq> zJcBhuiFtDx193Bm*}WNJi-S5|%_dxQIWEYt1%IDXJsDHI5v-}0P7()3=&C4X5los} z*p{_^j8Z0A*?Kdc9vJ3 zSshgZnL(v)7S{3Z>YO#R+sy_?eX;M7cq!0CHh&kIr0_wBnWm{m0$ubu#Vjc z=Axj>_S%*#DD0OM_|zQvJ=YKmW?VpqxxrXFqm=AAhZw!1kRXaBzNM2DyE6VLh6AC1 zEq_5#Luo|Kq{glldXBi{^KQSG`5kmO$4HqtV%;3*{y2~6;t8LUQ*zV1AL(9d%kU0A zll!W{uyacLoJcM&5&ec<53d`B#zdwt^l;#g5ij*XY*Ms{e>r)#ti!KuoguL`u@9)(oi9vM+g zBGV&MsUoAxlkK!jl7fRdq+&;Y9@`6v48aT!G`FhhON+CCI)F%rsH8NL148$+ht&pt zGaQIm7;OKjabk*{EO>G-!e?xQrlzUP9-J<)d9zek{>%hcBs!EEsR2*!N{`yrwd$Sl z%+&Z*%zzk-l@n1uxX0;>zA2fUD(N;hH@aQ+zrpN`n5yb$VqsE2x>g&8xD!Deg|R|I z%_$UXV1}eUpF*Zw&*{0XN!&Nautx&tk&65}2G2Lvh-GNa)J3%c2b<*rsx%z6^eVvi zT^41Eo~(xdXE4fPR7|^kdZOs)3_C|e->e8;G9-r~_I3J>!jc8xg$@FA_Y<5$) z*4~rFB|l7ilosr|n2NRhWK>hmE04k`Y3G$kYv+{4^_^1zRclhoGN&We$MqT>a_aJF zNIr(0TdJ8A#gSl_jd~W_7e8W%aN5^(3_o+eFfAsX^7TQF##q0E#^4bKwvyXGL&%M4 zd|SGBy4FYewAh*B|;g*#@G%qkRtNfjd1)ofIsC_e^*Ovv$XL zA@Mp@L9{1ZL0K1?ZVG!>l-uO`-PcHL?P=rU@lBv=&iR>(W_DQ9HGoWCtVn27@3hkJ zM$0rv#9Mv)_ATNWxVoqbsdRhrB*c#)Fn+M&H~T)kV3eM49X0xQ@+6fxXioc|uU^f_ zwCpY<@BeRB8O4n>`|$Sd&F9>V57+N5-<|(k%w9OqcGx!bL!OL>C7$jBR`vbkij?GR zFvMknp2b*$I7mdND+8Bn2Bu!?v<(l4JgvNS=;F;K9-uWAL;~~Gl1@drz}o9N5y)Kw zPB?7l%W@VFhN70C&*-p60%svQ4tF9k^J4`=OBs-h%MaZEe8OoB9LsfWZ2?4~?#jXC zJ@+C}W^0jk6B0(w7%4!IcgwthO*~ z@^r-E$gYtW7oR>{%f-r`!wlz0#uY^}Qe%sppT4~N2o)c@!6Qrs$xLFgn7TDKUuMVh zZ+3uKIzJ3-Q11c??sN|nJrOs}WtmwMSj1Z>aG zjUWIb%As6Xp-Pve_R(Zi(YI9WmjX>Ip}zDJG%?08!FN_IQ0^?f0$A^UyenD`vFOsR zevxiOd@I(%X_>PB{PHaa9qxt)6`FPV?&fv%p<}bE5qyL)Tgg2=sVT3L7|kc5yiLgs z6}Wk@nCvWN|6&q6ZHG-eNo7&Jxo4`_W7yKZYoAOq_jH)4um}dr!>iQ4ncb(a=p6Py zHj_04lCvGwdH$&sW}$niqj{3CJz0mf)1C@4iVTwrjDJ~DghAXly-zd*nknzc6vb?w z9De$W!G7krR5g@PU7 zysicUfcbS9f`a29}^&SeCABLqfwOp1JDoy?RAW9G8)O6#4 zE%_Sc#8DkW!|t#cTzZgugb4A@vvFPTw=8SRE0eXcD4hbZ0mIgZw+%4Bs{M$mn}=%| znjVnR1chbWNbdc_C~`Lp|8#f)b?6=CtUGy>Ut9nu_SJ0 zmP*qqMF{W2^+ure!OqwzH@Bj|!ojsd zz1u;BNFze2BVff^Qka_YS};1jp$odq`R8lQswoeweubA%GFF;t8%P6Exo$eAHo-e79vCG7UCA((9I!^? z29@}$>AkzRo&cGYi26KI_0-bvdCf`#oR}a1=L{V14;RBCkbJARQ8^ZhJrs8@B^j6CfenFBJUKg#M@HZW z=u1#dp+2EokPyX`@kl+2c&;EF0c8R%=CV<1(+@SHxM`)s^2*{Y8mcn3khZHlEvV+L zA2=t}(|r6s%Qo$3vrYG8ta8rM^sLpdbY9pOdAbiQfnO{Ewmvo{5yf|z*xzqo{SFh8 z&g;?8;PM}FNPZ+1>d z7WXg;rA@u;J+zZ;}+>1m6v4iZO^mq})@+=cwTBm6^tf z71nFVnV~jpXb+v@ph>jzZGvQW*wX89+qfo0-g7l1Dqbo8U27*vq|PqP6Xs<=8R zgX$@}%?#OYL~#lTB4s#NU2wGB(e5>xNu9}L<_5e4p*KNW(|QbK%b4~Ok(!nW^e9=3p00el&ldBoj#D5p!e>DZ!pN74 zjMl66`Q1%@ppbjP09mWn7NZ!8{A%N>G>d4QZ7oL<=}LrzQwH_X6uz$G^_e%aR$&3< z2=cN660WW*6}g@kiLPAHrBo6n1kI9p8v|9siqAuiKN_dt!7TxazAXNYYf`%e}d{IZec90h*GAUk_5)Z)+)6E#Lea>WrEQ|((jR} zOAPU=O|e>l!kL^K1ZR~)R81|!4yI_BPw!+$E$LSb$;0hG>{~tJmlRRz0(GBJn4Ejc zEEVaobiEY~QCF4GKCq41ir%MAN|D)XeM}3HV713-XLBep4zGF<A`I|BR^l_l^&@vaU?n5*K28$ z5m*CjMH;F*V!|VT^#N}{=|usVYs&H~*`sG^51mvhjp5h!Ws|_HGPn(nB zLus1HhUNV|(*<<0YNpJyFOtulAhm*hM*(1F8m7N@@YG-B~$ArVT@X}rZuit%m z{Smn#U(J4Fg$6fi`)Z>Sbn-(A!LZgZ{}POoLP+#YmNj8WJ*Y{fEfOy+EdaVK-niV| z(Iuv0KApoewi|Fc4fL~{)0w{g-F&!!zDEA#Te^>FW2B(?C4;#oF#K-V&yjdJ4Mnb- zQRH3l!61xq_HI*%Y>dPWGzP9tw-z4No?dClx-&&YN$6FC$xNqyuRcO=(W6n733hgF zs!PxuKV@$2+#Q*q4MjC*F%y@Q*5Fh)pn)TCGi(n^oNqY9RN@;DCrJB{OyRgM4Hrbs zFJ}+frZIQn%vM_=7h^Q#%$z{WQ_C(1JB4L$w6U&I0izcx2v>u7@V2XB)MXre#IW%r z`1}#kVA(!t8b#Az1rkdsp7%*3Me54~?mv!iedB`$JSW5z zL}xF@7ud4-)>Sey`yfUUGm&-smCwq*H=FXhiHj{4i?FYkc&D<#5J4v*E!s#V4l$*s zIxMbCxUI1tBx-bBe>PN0gHh6$#2MQkh z2g`{dMNMJe#r0pu2a1VkU8c=z#D9Fw;%3qx>PTSz0EZZP?Hx|z$y%U-ssmKJ)?XI8 zMR~5nB^XjwbTc@ND+xD14vm#w&dRx~NE6(=s1V4Och&6X&!H1obv#~4VCD5d1vhq~YZ zhW(6lvGL|wnhAv67{9)|zPb4P2^s9mHd{eupH-lU?lkkSbVVJlpknpQpp)5ez91fq zc+hD}g@pSpRU_=_tdZ-i<#pEbI-51T&LUn-8_#A<8_#CH7f~;Yr`LuS{B`kZhPT3` zS6JI1Ax8D~SiM7GRDSOZbtYHB@E?d3O8fW4<<;lwFSGM^H*c>muD*P}#?%{runGLr zpC3QY8ax>N)%!YDMo`Eq`$nq`LQwhpO;8*+i)D5#Cma&yC67-DbgmfUgezGSL#`;W z3exjz5Ed~h!y)dn3Zo)QPp zO{TzkaT79abPZ0FGoW!kOB84+n*yk$lXbzga*U@kz-J|}U0LWT?%*7DQ>qjtL5%(- zLat&dq)j=!9in`DP~dEhrw594deIs5dcl6Qf6|l3OM3D67bWPyltT*yPjO0D;{5mE z8+L6aq$zMC&Zzge4*No1uuvtNK;@rcI7JMXuZaA^*8Yj!tTOT4-3?~IAGm5?V}HUa zTM=Yiy}=!k4il!u=j|4kSMNSt!CtteFs_mG+=7LA|2~-kK5t*W{&EpxPP&*=k3n!d z8LJH+z~~LB2!txXY~H4+b^>|;+=e8QI`YsGw0q{tt8XrTP)Hy?2fxR+@3?{#+#hnz>L43uL8#C zOU@>z>*r6Jq^j!hGgPKm;{FEDvexLX{GRBVb1zLIOCQB$tK^K&vq5UD&1U51{L#pN z(KjP4<13hbF6BFs(7d!ngy91GN>O7N+5q@-crCPa3yZ=<>rhqL1z9)QH$>Bo;WwnV zI@&Ke*6DrvRH3f0K^`k?yFwt2 zJ$IVYv_^w&^e9`q$6nZ}g`VwDv~0-x&@3rokfUEze}HXYp~1Ed8e_ZghAmP%#XLcD_s|&PEWSoha1RRYpNy(?<E7gF7>!8bK&GOvUP*QqZTovt@i9jTu_pwJaysn&ZW;PQxs%TDEC zrM=2}m3Zdwp}NLhLYUkgy15$eTB1?MnYw1`!ltPP;riC#CZvg)-BjZHl9>B`WSEn@ z>|sl_be4N{$d&#xP@@OJS*HrKDnXBQ`;bG z%62ao*I3i39&3BoV_oN8k@=Et3#+v1njVKb!Rnvx%?xv`02qyrs54j>pzoBu=0|Z! zV<|N>7(HVvGHFh%8P(hSTmB@v+$PV5`#CgqU+Z7<<^CooiajiUKdXiTDa`~DmL)TY zD$PK>m4O_KEJuAN+6*z(Zm%d3pw7u<0_Z83U}Z*6-2MLc`VV_gkQ z`S@%BXZN32Bkb~S349%Au8y;&j>D}8e&Pi`tC)ssMm4Q1g--9ALZ-joQ_Iv=O&x%x z!zrbV*^f7vicw}ihf!uf#$4h>Yf@>{2va?TDf?mpL_})TiSFu@Kg7lJC;u*MoB?N! z0KYAPSMFKVr1I0@h5TuH_9V=+wo`Ettkf?lF1Co1VXh?&9Rnhwq88m7p_yLcaFNn7 zTC{Di$3;aoOrB3)tdVU-tp$O8KI|iK6|5;yQF>(ww}PuGAasaZdc9pyZ84ni4?`ii zHw0M$xfysGk6Iqe)fMU}lEzE!m8DlXwO2CE6eA;w6Bhwr$OkFaj$7VhUM8alZ}6|q z^+4z6nug@$ILYZGNj^2E>&jHq)n%%<#(bc?%GO-!6LK&NcNG=&NyeV^3!a=$73B9Z zveJBwr$-8!X<&stJ=Z&oVw}4nZfM1JM9u_pb1U{p@wm~sc(>h^AZ~iacUn(wsEOH| z^bn?qXOpJr&LpZOixT&fmb7wlDE%@8G&|3B@O`s)6}1P@lI%T%>NsJjD9CTyZt_L2*0%w=cYg zG41uW7LH5}w)JU@=_ifQ+sgLE9Cr4Ma!4;-E}7S5uW-g6D{oir_NBdVssXz~ejn4q ze1>@`GThe=cor-ul2H?-)Hbvw-*+zJn_*C1r+CN_8JY1^(6xu@JW!QX&7TPUV z32Z^=u9us;gJiXtK=D3N@f;pj+`$}O$f^*-t*hiM!<440v|vUl`$#dxF+z-+5^yl8 z4rXNNu$Q`Ql#7A+=mmq!t~)CQIq{eLuAsJ1JLoL6bH@pPtIMj)Zu9h()`vFqifCyf+eS2QI*S(bfW)cf?Fq@o%lUVwk2sCEHwcdE zyh0TIem}r#i}VFb`IMMXgRQ#-oeeZtsq*vT_V92Cou5qFu>9Ui=3g4F2vyxxA-3GE z4Az*60!$TMBgIG_SBUkEc%PsNf|x3#E2Ah;oZsIHBlPExSEgDu=Xk&f1O@&`WRH%q z5~QqKG4C68c0p_6QHw$qgzH>Nyr*|HW`ox7vbQ8)vi!(&uSUXx&Hj=+HCseoIW11j zCGMAQ^qCax>_md(GaLIWT<*R%2sP@Fq%QJ{UbvXBCG0n@KWJ-jU^SYlsU+MUr6#*Q z8kpY!4YC>Q#K?J}gweh$d<+t#V+*@tWNucFOh~gl z$j8$R811{33IMI0NJV-7^&)q-;8e^9OZY(u_Gl@o5v@2H>pM#0njJ@w(mA>iuCi5BoWJ?^0$ohsj4?1t*hk>1saB1*IAyHh4SI?}567W{W*VBh1x<0UVciw2HeO+nukWcF+J37xj!dFP z8)-?9zDFshM*b~5u_QaAdfR1IB= zv>lT1!Hlb@G@Jq3JXxAq*A%uR)}ZyAnyN?B^;(j|CDLwx6u~Q%W_?Tq;j2shvM@&o zkD$$b!4>H73p|-)9=#ZApnOuM?hhwgOJHW3M(c%X;I&g#M|LP|gAI{ICC$mSrqP;I zeGSgB+qv-5G9{*X6rv-{rlph^(W!cbqSU5HzkX+fS*ZZuM`6I1`3{Mzv|60vMCvhT zNztE)qPC@>Aj{Q>a#4i@EgNJSf4`bPI2ZrB1a9J69m0CS(_~GB^uFjYWuD3{T&X(E ze&0|ieL-+NHA}D^hEqzG6l|2JG_oD68W|41Q^h-|M!_|BG ztzcym-CshbyGS5u&Qxyh1rT_BSt1S0gHq}V=J%<}ph1~R8?5eInMnTnhU#=Edo4i8 z*2Ln$Io7fW&-2ygd|R)g?|u%*U6LQf)#5+*ABMf?UOAjaH&UU;2CkIy7MUy(2g{$aHg#_h1W$m+Eg9mi_tX2mI6Duce2j- z`B^?YyR<}k%PXM=W9a@fv(?!|J|et&jm@h1LDiGJc*ctdyI4 zYF5t6>7tYMF1z*intI=>O}mPWkcc9!-VTH5HLKgAWv?+|JMw%8no>}KXayHkR&f&r zgJ$J&QOgQ$qCVfgC%j9~A2d!MGR`{(Jp=h~WY@C-X6H*ateC0XqLmq49pLXNw{3dI z7BbKT>Uh&EIL$6{N<*u>Uus<`A}WWpK5i9Z!Dj_G#L?$Bb^qMTgBl-@PximCRoD15 zi=1U0G@jM%glSui)>4iZuX?v?h&Vj*L*w!OxoWFZRC*)J11zkrHY0z@hFFzX^@>$G z)Z4ZsL!2|7%qaGMxo^5RvP2gyg7F=HDsxs9RYEO6MwP8SXUF*O(|2QD#uCCqSz*!$S0YV2j zAtVWocV}0O@?|Ta?waI*PO}$8381h03R>JK6;`JsV0znD-D$x60;WTq!y3#ZZ#98m z@FlI49i}wh9njkpl!T4hpkD7$g}R@pG8(F{G_HVYl`f-{jZ!2{QPW4zvJpCzQ%#c} z4de>gBQ_NaeR?4w%-V8!mx$^zI9)V7l6$>J23lm}!8f6Y^k%a}2*VB{FX@bj)j{>j zPUJ8rz{QAfV-K{1$|P;DNZLRFLcc`R3YAKG_6Zz_l`wBs$UGL+sqx+FCJK&iA)k1P z`i>mNVqt(rQp~^>vve4KPCeX7F|$4FF*b1O4|iz_s_tM5Y1X8AaMMq3HXA%(T_@w8 z($OJZ!Yya{K1wjrEpx6DJb9czPNA$6mMguatnZd;t@1Rj<(l9T%Y@P^EVThsR>gFe zN)p)cqQ{x$)g`Da%g?qP-cBkS6W>#ng7uCPmAWSKRKF$F9SDg$&6?ztj z=wnsz1um+>)vPRdssZYlBNJh@@)eq;nGKmnp4$~76{EvlC5#+V%n63e_|2R!qGxk| z;F2^{>xm%J%Pv;Fudio?U?paH8;Y&j?nTs zl;d5nY6Qa43V)P^or-N0+D5|Si)pLIjN8C)km&f=kDO;$4rY(2SH-rF85oMRiUO#p z*yex`s&F$El-WxQ$n=Ww?1@uDnHs1P9bu&n2f$JO3jVl^_JaV<`nR3?FmOAgx*8|F zBqs8T7f!Z!9+swptJ5*W7)Is#aR zI&%%!R+tL3Cu}a0F-mNwK>R&Sx7pkG4R31=ow5!Q~>TB>v;7wzEUDd^SYu`wb2S(~TFn7vZC~zn_^Ms6dtaSz-28 ziCrzRunKhohkIVaMRfvZIy;e)mJF2X7^%0>pQ!|WUY71&^SxZy?cQxEtXl7IrURZO zZZ};OyqpQk8+8Yl8e_4%Qx-QE<}vN7@Bs4@w0tjdMKncFq2Ul#%7&qQu`zBP2w;$Y z!!sr&yOk2^Uk5}svtDwzRh&vFEm5bA(tQ_42{6E+ zFoi`&j)ITMi}S(^E449$^^79ROY%%rmd4@`Qm8c+<4vO?l4b+dM2!_9K=x{Aj1H=7 z!nH+}E^|bmVs6LCCo3rZ?35+XxzOolHbK-@nrz~{FBfipPBO=s(ofDlsav3ZLN}c? zp1RI@IBP!I$cNXc_pZ< z+51yaHg~ZBI#Z@bIa{WnKF)84RaMUv(6m+HrN2;%ZkNNNA{DZQ&9}t|rT058i%HRL zPc`EJdT~b{d4Skp#+$v~x-`Zz6b$ErG)K0;5kl2K&*zA6BO9`>;N!4ZQa;u zS`y-Oge0w`5*k2)SI=FlO1)sUczH`D&ucp@n51RE(YkDK`1Ix7$GQ~MLVd#-H-diP zvQZz=l`^^tnMK8sfDsiIzmg;7<@UA?FJ}Ty0e|6DC*l0H2HX51Czz!#Gb_QweJWwJ z9k99mrxODTU75dkb|VQW+*Xq)sLzeru)v`$(>FWyj-GJ#Op9x_G;!T>0Oc#mozb>a zRhGn>z!Qn;0<*f4Pdc-Y%ckt{yAZt6Nvt1-WF zR7`Q~%I`H`Zdx-IF>^P$Qc)v$M>DMxq(ks4Ow4Yb0!Yd}g-bxKBtV)90{k>{^x6b> z-=__G5KQvd7h7N0)SS}>mu9zfM^fd(qa=CHl-T^uf`YIe!e7>EHf#wNz!$9+OZxVq z#OW)JTuPp(#89J$3pdjq_mPj3Do1a1R49E1M0zG~{&r6T*={?mp)b0~d2FM+L6%>0vN>A|(Wy;p&XgP~S~dgEhP94Iq{D1jm`^2^cbQN_nEG0~0XN z$Vh^U_oGUUG}y`FK?jt=&cfowo{~ClaoS@0!*2+pSzri)$$%}x&j-9^`wkNcGKATk ztK6{iCxcQjn3_sHvN2KE4($*b;XDl#KOLvlh+-T|Emob0j6?#y9AGAgg40lRG42*##7p7X?#Wtr9sS0?tvx{O0>7VnQC)u%*B32Y>C>IBV|5+@zd5{qV(>z#Vjn zAoLCjpUb=4U?AbzgnOH$OMK&sz$vh4y1@o+{Lrr}A(I$EsQo zExwCox3BMEQ=TbYKiBVUc1$CRL)`MpArP&;o0mI`v)m@;p2`oURKZk6kI==v`QG5n zMD-XukgBeadXefa^p(+Ydj*-TJXzVuo+C&@?u8f8DqutXbF*K~J_`W1S62 zv$SR*jnR9Vg?Ht%77$&iH?Q19(iSnzY`!n&ByaFemyXOk}NBCqGY~ zq6yb4N{J8a5!48>4#n~q3l)TRfs`1#y~NqPzf)o>IDc4Ot~e6}WZL%V@)E0MT~HI; zElpSftRt#Y`T(a(0l_L2nKc|)_AxtfI$&d{O$dSXQ&1FWb9G5Y1o4jYOG|EH%?)lF zym)!$@3GLumeW??Bhr+Q;U-NZo-W%BU4qD?S{F`t z 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 F_#cG@k*5Fv literal 757468 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

ELiajr9{p$UVkjwYR~Zr&SI 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 yt$2XdE+cR-qf7T`pBxx_i5d2(`a;prfPMhf&yz zYlXJ>wKvE(!053E3mpOg}l&~qbgIJ>r{fxWF zEQK36Jr~zgDfSJ*b6kVPLVK~df40c0z1TX?St!#NLoq58DztS$*AyznUU-JGpX(ta zcRReGRbZV|VJ#Iob&z)}7$)7_g_icgmY%j^dwvNvHU)S)yF}g=tBB~%ww^*|c1t@y zPDH-W-hr4_nBCIVQRwI@xAY?{Fj%3Z*x!cqTZ$(pNoB6#g;)B z@M2f78=jp-T1F=)>tlE>rqow#LuBuP-Ys+%dtjL1$wXv~%5C)RO_-qYzDM8uLU9mk z6GiHUH%7^uK`7*j3~g=c z>MA4s6qAeddb>((rT)SoeWt5Gz7YCQtJvVUM5!Czb1lFGY%jpGk$vQk$lQ;?@Sqxb z^Sc1mzzYaco(XJ_yuDfvOrGo^!@|}ggeSD2Qq1YYSf(=cG=1m~Dukcfu}?T&!3v%5 z&NOs%YpJDzw>JUC{~sZW)t|hr2Ongyy%io2YAkfYL&%i^GzcC)gh?=zLI~%0=;AK# zYMGBMAz4sAdD*k83+55Bif5sNrQ%#Ncm?=&i}N@UCy$vnrD+W7K=O12%%8S7g<_>~ zSPPGY&5AAIl98EA0O>`xwF@59$ZT~Z1&nmxW6)9$JYP)~=Rym4Qor6mVtTkn8sf)$B=^Bx=OH8)5SuRC_(fV+Try@GFB*y za#tC?KB~pgDF(t}dm!Uh?wy~^u|gLNY!^T76c+DSY-V7UcEHkwN<(Wd^pZ#9QO+G* z1C`l{w9uQvFwpwbQ(ZodDU|Ilh2DX_&SDEFVwkj4oVZeq-q+b$7%_Y}N`gt>IvC>`BA5c#R1csn%)q48#i(SZDUuD5EYj%E z%x`OL>q7>0+Ni?V=HXNshyAU!1nVfT?i(;0rN`(+Y0~ z!xn?C0fY>@4^@-m5#vUJAm{<5W1y!^wx1IaTSAE9BCbV1Zv#~Y(JLvX2p>V7x>p5B zMTC{G7ka#>zpvaSHlQuN$YHA+sUW|blYIxKd@{4yx*%^bFoc&F@smefA)ybpfRX}T zTXPj!z&Gd2NU7w^7!S2%An0L~oh!xK8Bsb7pkGSynN~U(*f9wRdIcj!7J!*K z08z8KFs)CNAcc^9KV+qXw`Rq%$v0Iydm|r5^~;iOpmbuu${VXtn0^mU!BD(XNMWFP zl-kMS10w?e=Z|xMA;yY$kpygK51DCV>ryC8>!Ez$06Y&`4|X5H@I&atwn-HLggd3t zRV?X72?#Tej!d{qmuk-FB=Y6}NLLbzN>^7ACNDMa(Jj0r=hIP3<7k~hr>{* zt%9D?C=|{fN$1Nx-`+9|cJ8ENh)QoC=;mV6ddpq&JK+FZ?&zq%S4?fF7^>1Ap8?y- zF!xclDp>*O>;vO*QQEM+@?d!md?v9yO02KG*$w)quiQESVkNVaZl8tL;_Q~el3?(t z!od`Se0Yo%p%q$siLH#8j7pU{ZO2k&eWWz(Gh!JE8p=$`E zgC&sKAu$GNGb8zQMY;bUmPqKc#F(B;YkAFV+SfH%5}p_oYYfAorp+3gRiSjoFJL5mjVnuv*(R$xjSJ!s<9 zlU1b)tT6+yL=}b!CjFRY1~p>%2E>9e1b(F+@J_T#8lK@v7~n zNaji_%z%<$zolH}^$);m+)C}cvSw7-FhhZC#-p$T*x0DsHszfqDh3CZs6h!TIm4rS z3j!*%_V)AUw^XGmb|7Ca5*$$Y&QPs2MxZv+RGr11L2!#Ahromp0f1m|AV9vD45+VM zslbrR$D6QfFZVaf5gny2;v{S7fgKnuFTJIl-iooPYbn)0iBTYtoOz4n5_Olzd);gb z7W&JDV!L1>PF2RxVAAO;_7(-VZyG2I0!UB79^#}a&xH;FV_g5-vRq20X`u%6RHZRW z@ByYE#NkUFT=Kg5kaJPeoA6Z)+n~@ge4r#RAMalwEwhU3=3VECP(J_BB5OJaSrtKkPwkBFk%yvASeV7 zQ6T!irZ>%ko*;*4c0}g;gwPX~sU3~~AbA+kk@;kc27z9+aiVh+0Hieg9OL7GC<4USlzKY&Ee6W=_DF*sfLc3RGL2DW z98a*M^TqQ4a3RF{tw>m;)uhIDUPFl45%n>5psUjXQxH;2Vg;ZqI+y_z&jb2};ts_W zh^=Kq!dCkGzzD!i;xUt^=6=(Jp7S}6oi&{}AW>&Hp^ffD6?Q@zJANXw^kUj%7C_>2 z`iN6$ZXZm#?s7Zts?NgEtv-Q>&T2y0afca&{uXerbK3@?wZOiVor2`o9DgMx3ws&; z6_!`(MT@sbge~=AQdgjiSlkm_!t^MF#xv4->iI%BQ1Zpes_ZIvLbzF(GaA*HVES^6 z3U&cd82F$+O3!h}5_%iN7D}Sw7+K~|tx@HUz$#|2+%*8fhoXa@BD&|#;j|L^a~)@` zfT?*1#7<_OU(!utbO&S9-3un;_RP|NvFQfO4+M6#7sgH>J*)sOn@x!MK3SEp68Z79 ztnwbxL87gb5tGf6g>GS0;9go*x)!N}lq5sP7DJK9Jh)vgtwqk0PWUoncT3+K-Vng3 z)V&L_lkE_DSF9kPywtl(%hL$f9M>!ZRoYs>;h559kVcd$dri~$^UA#9@sS#4O^Sdqkv=f$8B;psG!FVaj+Cl@%_cO_QA;@DAL zk?_xu3mwRG$|B$p$eS@Kn^L8X1Qqm^T7?4)rPqA1R3AmUnYnUv+_hCcaFHeH5g8xM zqgyQ>JIsh$F9}QIpv1gJBbLA(CmqYwhm7En<(C#9wxFEDT2&B=%NV<>AE@lxtMN|` zGAR*}i9&{mRg<^la87M7nU_Hk<6NCY>^QuVZI@^Wa0-Q-iBeQ7oR*PkSU@$PO>9&; z@>Ti`Fi>^Nk#VU4VBa7i#}b7s-?dJ~&N$DJ>N0f98^O5LajsKP9|^7{H>6sLP6PWD z{DCvcF&y|O+ej2{JXeqp3s&hI|2yR}*w^1y!1t5B7MKHlatkUc4`)!&iir6I{PXA` zDgF*C#6}}_94NSCPb@GC4nn7{f6c*uezrx89Vjy79k=RUHvaJY#88VHsQiOu- z8oZON_Iga$$aK1NXloT0 zFvmAy@+VD8W`f)=oPY8Tz`GM<&jq4FfiLIwIjJ~ZTlDY4quN60L)Nn?n=TBfp8 zF+H5CD&0n6L>B@CcmRyH7$CrdMAv^BQP1^{U}dJvq+PMuXwGUlb z61F5V680JS*uX+fub;{h>8OICq43y)bR&qC#a|6i(=mT+nhsZNVOeaIYHLaJB~b)v zR+1=!30S2V8F(=vP9h2u4rDjE{eqni zU-O0yD-bsqdKezJZE{p#?)k#_(W9HEWE(tw+So~B$Lz?A*PtNu!J;T$6;Dv$S0ran z>~J(;DmhXm?t>)s4sqZCkm>K$DUp>3=ryB+XtM`$GO2N!ZPTbpkYGXLPas5UHX(vB zLk(uYA~1Hsh42X2{z}|VO6cUi7HFj6g$Y7TM9dB7BEZay>;ls!H^@zs#@D$JNf7B1 z94tCLn7xePQWhh`sFfWDf=?{DSa=7ar%w1{;rRF=E1PstTGQ(#76*}&6v`bGh)4;R z=pEIIXdQ5Y8%z;!$Ps;8=|Zs*0qPSUIoLFL{4{pt$Fw0zr8geB$c+cmEnF)mPaiuG zj*hUt%?1NoY=Fct@DbJSO0qdv+KW1YF*NaQQ2#~T*)-r)aAP#l+S8L{^rVp^F@D4V z9rqwcCKi2q!3F(jXf5faEOe{K_{7r2noxCMD*Sj-j>(8tAke+S-|5(H!ZhX*DpY;t zc$S_Vpu~VdO2BB4>cRI!?)j6y3HNykjCvun4JALr%{)*BF_Ehs8TSPF2!xwLgvI~k zdP@y1n#2e#t_rqSYL5}cO*%ULMbZ=7>~>CDCG4c=uKyRh0{3j-+ic`MnC+&|O0FXG z6+49h=}BXoN7f>;U@7J!_X!}gEOw9!+1%ZD3Zgm(yStq25=PA=0*S4e+!{@RV5|h6 zS}ZdLkj;6d(tel<@&1FQD53Sm%7GBRM~N(5Ks-X(3MS8hj-@dp!Uw~)haC3>DGT2K zckx@~Pn>|UpGgb~BTOiOI4Ig+esLc?p~KxclFK0j6RV-S6S=L0r0lCSX~-rKA}6k-&NncTmAiBdoKu zj3hBbLW@%%kPid=Xh^&8s30ibUMyDC4c?qd$@$3{su1M9YLy1|cyiO0zgJSFv-lOz z3`yQV-seD2(vX~lD2b3s$g(eyG9Dc0n$yyQU4w_>vXn4{l;m>DO`wnlrc{4nh&o#1 z!ILKv09N=a3o0|o0D@loAcaW!LNsca5Fuy>&jm$@iE3M2Z|T~LO|dF8{_@2JCcI*R zu;tWhixFH@N?M*60Wp&3_fi!mUS;4)(|m9#!pWIC*`#@Zo>Qc#>nLfX+>B!oB; z900sdl}i6?h_&zJa$l0_h$@n38p6CFRJj~AqPUf$N^VGW9d;d3NGupjkW3jdD@6=o z<1bbt3nhhO%!q=9IT31ZIy?$sf!48+I}V~jPHcc>QA;EX7jCHpNUZMF5|Idf-Ccwe z6l4txtQAyOKhwNe~TDds_Hh zrGQ{A3ZT+#h!7dXIU4{%EnirqYL*833fK$;>1k;?eR4=}G@%()afqDQ3A!;HWI$Dh zj)hd0NO>M2&K0JjlW$3}%?Q>lno)RARJ-GyH=DCU?6WKk|ELiRpM;1sfJK|c6?XIv+X#%n zV!lNI3C1!xx7Zg?QuT`c%_{66NpMMuM>?R?SP5xgaGgJvF%Cni^Pwl;*scVtV_!c_ z4ToscF*dOsb(G8fkdg-ZLK5I?`l%oWt6KlS)=vV>DzhP8fxo94qhPs%MF=z##IY1Z zQeiHbPaHuJC%f3$@aYxHG@)3|Qkw|?iIoF!^M_s{S+a}Wt#C75s41rQ6`|3HSsMgS zdKrlZNm0=(3Te7Di9!mLHW`Z15fY#n@{j{84D^y5RaiIBTn}jp26-n!if`&tpQu?T zJqBtHu`*zRhbdMmg+wYA$%0ydtf)*Smcrx*s6?bHf-LN0ZHBu)Qg-a?sY4bQ{iH5d zyiqJKTpu3-M68CpFi!qj0(FY1kOIfS_TH8O&}ZSp;%}wFSY)VTRT=jhJ?e}6SvGX~ zkuXg~&W5>!i7X^g5V?C!Bx3yH6}evH;#BO+$}E#DULl4Rxa`uk+G2!M@`Nrsw8lcm zFmdFwbn(NXnpUB$rB{rMBSPj}MHk3O8u*yh>=(`*lBNc4mzT6S>^Q+fW&kbN3ml|JcZPZPjRj;xWmMoDq>*O#)F;p2&QWL zkj0l~K-fOO0QsppDF)0RtURZg5F(g&u)_}{!I^s=$p$J8bG_cIf3PMs)S8ZIYAFPg z?T}EZy2uV7qKJLq76W%oJKJ%pNj4E+XX_?dehX4Vd`KbPC!DlX^d!?V@?o={kBvO+ ztRRYzfbgJnS`pLzQ<@5E7q0o!5+E>mA3?*w^2$*JWcYy_5XAnGBsazyzz(n6j>XE; zV=c0J#AjMA@{X1n=p(r#+3P9HCogtKR;y;&JcN6Wgj)v4IuYZ>VySt@1Y^Kx@<8eg z3JIi6)01VHT=XaYcDXEgTyKU~PTsCGj;g_E#;r6eH+(4#6qEg@sq%5HYMd;9F&&^( z7#=_6A@2?`4w2NF(fMTSXbh6sS5tiA%sg?b9Zox$G6^zU5Y?2#{cwT;3Dk7tp)OJg zHhq*dV;buNq-kjqFGiY{?!>xLUQ@?IdKYrrlbBMu&zR7XeiEtMkDfA#CDVv^Z7dZU z1;w6o;rcx#f{m(&9M4fNIz_a@DnspANbn5>R5xp3&k@L6zfpSHAJPFPB{*erCo2jg zflctrRC1?BG(1vNyd-CMl1I6SRT}r5=NA(nF{Ak8yUCH4ht#GVxX)=~_UwFRd};0p zrqBpG7e&z9bKp~*FEejU8#{jFM0k~ASYZRIo`Qu5dzYdH%YB)G!HPX%wv3oU)9bOg z)NFfVI#J~4b47@upFtqw304x$LU0GVy`3DjdHUor5TVdl1mlcUJ8y0*i1v-<@lBw! zlSrgiVqXy57Ysn}qavqON^LLpx4<)7sCr8Q#H)&jI#M#{rOP&rB8WeN@CPJ9P3aOc zs$91CZZ2Cfkm5|W%NGDXF`}R4%RxZBFg|ioV#7TR6E647hUo3YuYok5 ze5S$`D#n3+pYd4+9_$!^(>q#I?Or)_5aeS)?!3he$!ngF7a#2LeV8bz!1}!U&|6=u zhWYSKfxa&LtY^_Uc9NDJsUB{+pus_uGdsBx7kp|GpiD?GkL+`V`Ug3^mvU!uw^(o$ zBg0ZhEiFiebQz?Nmy)18I;SKknogQqXkF_N4B zqDmp&fX_i4Be0VgCDBiqz66S@YO|<;j8EjwN`m19T#9HWcLsoW@{l2^fWL@^+q4bz z!`g#F#78_BOL)GeGzhjz;Su13ENv)+I3z|Z%&tevC)y5dyd*UyB3Xi{DaF`jnG7@h zu4@JoN0UjDdS}5Tk_e4A%)lU&yMnDzNegi0J9XoLCMF>>Bc~fG1H|Kw7yzg!%;_&a z=o=IJK$JL@6=uUoqlm3exT1ytWGmVHw!Sv*GC3_xf3F=Ik(N>fmogEG!l{U4)L|Nu zP%Ne*`F2=QstaMIn36>7F(S32LsX5E-72TT9VXKo4J2(BJZ&Sqebl_eWGFn8Ta5%6 zXZyfZ4WQEaH^dcBN>Yn7^P$l-m7i4rq4#9S^Kb+FvH?V}xYMlbbW`Fw2gukaGGpwt z=B6o=;ax~>ld2K8T`EP8mubw_UMs^Ld};*FyO0ou7dF6ILEdYe&?qYbk6+44NSfGK zkhEijtd0?~Iz|*Eb&QbLA?d3T1xa6xC~U+vu&Ekngay~lY?@qv97RO8#5@#)TuEg? z5^hOTK$2SsRNZXllsXsUe=~dLOnCEoW}$J+xLN4QJt30|IW&TXw+Ax7$Vp>pNG}{W z%59}=@KTI`^!l;yox3f{@(mOX1+Vj8jDcyxK|`K)mlKMS^h&>;biPObV=p z)*;nX!zWE@M6NNV?R7PNX-i}#F+vT}-7*K<%maNShZ9|jkg70iON|5X3`|j|CeJzB za5B3qfYcrPSL3}I1JvRV^B?Z2Rb1;=@(tv?+!YsrJlss%Wlh0l1yEL2_$z-gg7G6M z1n4H2J=~>;nW+ci2#|OioimgZ56;1|^LjRbu~seI#sD=rPHx7f#H*p|%{wAfoq0zf z_2wPL)FQ*VfhSaa-cgEt-tpuloLkl>6|$D$%MoFfCWFS2GT^WdYib+=ms~na{cwDV z!(_N?#5G)J3tVsG+DXcTB{uVTS*-*+RC79ejZB53LqQ%+t-WrABC^lOGYEv|jG4ub z^{MD9gjU<-s>C+(I(s(avPx?&l4;gjgwF}CxIqtdt%iE(c<`!xl>xbc(bCaDQmfTY z-&HDIt_UPv>P7CU1r0!;A*FA$RQbd~&}`sDCh^yviC&SSs%HzyngC6v!<7wot%|~w zxcEqrJ)hJtB;Z{L!{W&BCIwuRr}pXd+_Fn44djfvQfBrBOja+S;^X=7pX zSD7#ri7cMVLfLR)GYv9F*qbFbCvjVbW{5yE!{+%JIbadIuE z4K3K--V8Hu0vN5P!I*&Fk}b-7Kh0nzscqD>To-&xlctUxKNb8CB@((_A?KxRVRBn| zTx@ik(mQPA^rk%e@H+HHoDSC(iBk^Y43t_%874FcG`&1Jp6X-h-R042CF1)99>1I) z_opxneaQ${rooN(c2F7k(tX9aY!!hpnLz^|NA~r#%&)@4P9)^9T}9%25P1M?3Vj1p z=o{h?84ZiiC>nUtJkUA@PIhpwJljtRstI1}E#`qH(d_b~bo9~XSOk9BQ5u`>nOa9d zGJ_uI_T&!zG@6Nc2oSE9aXx$-DJq$TOd7tkC}c_-y&h5S*?yqdHy^8NDwuUAm0__h z_kj*B%1h|9FwHe0(kV^y^T^3?HjvS{j-}#KX8eSxQJRRaCFR2>)1OkC$)N@fzie%UB zS_>&n&Y6;>j4L_Kt>Cqi&ycJ`(xKr2m~1?z37hKBwGy0+C0Sr4%L8MU#H9+;0xC*q z66OgRLaKz)bm_(RbTUk7BE~ySuNlmesW*{iUYnX+p~T8hg0nqI^PdkQ=MTwVNQBHS z94k85M-!8f2^LeP#!rL`ea3c-)@)2+(&{u3Yjc{84M;P!R`&^&#=nc*OlA#eR@0y_ z>3ARwg5Dcn?8)t@oDPmjJHXZ>NR^@ug}o@fu%?Su^l=*l(!i81Ba~0kMoyi|Z*wq# zQUGi~Qe;5^A@h&XC2Mw?C^nu^CA$z|o!W$&>4Rdd8mtEdXgo9`mZVDUno5Fmi+#cj zC6OJYz(x+Q`a+7SY-gruJXb;*On zLAcS#(2!FGgmgGvibh2!jK$dgs-Cu*Gx6X%R5A-fXgGL2^48%qOkYvIszDWLRbF6FR55xO&7 zY;63@V=f3fMM7sMdZbt4V?5vJ(Gc@Tx&(r5Cqmc`HDscxKUHw_;5c1k0+s=jgHM&NNyED_#DRM{l!%tIc;UQ#V zq$njRWdI}5Ml}iR1!c%+13AR335*sRQ-nCgc76tsCR0i+;HD}!`&}5tY7wLoI%;{{ z%K^mk1bI>z={SfOIjhtR#|DnFN@I|L;xX8W@fdVirxN!JISF^g>xg6&L5-xx3ULM| z6tulSgf5epOo(FP5?L~7ii}u;<-m8hrCBGv=^-d*`bo`f6ihmYA zl$gSOCq!Rw>|kBg*a1;6*`Cgl2XXpr{yV0nW)EUNkLZ|8&mMK^6k&MXBhb1>Na`MF zWepvUH*`deE~za6NP4Qups_>30O|d4q(6kskaQs|12nBP;<%uTZjCNDE;zd2xS;e& zki92XeTDf&>L+w=Z>jz)FCff3Qf6x70K$p<%B^n{JOTy7uNW9V#L@=F2VA0TK$drL zX2HmbK{AAltjXWg7$)>4Ed}-CYr@wBi0cO9UuD4`KR~B!B{{Zg02vF=?>dWBSO)@2l+)%S z{q!oLv?N1#juy*Oh%S194f$&@MXj%NP{}iUKIAUYQ~vKu{o4(t;5EM zlPXC~lK~DNDzI?~z+~?pO6>`DC;}wdJQ)(DV_4P$M*5ItTJNeQbu{ZxbHbyW?O z+gl`rq3#zH>z@>tH-FQ(I&+uQn~0b7yN24__$IRFcrE{po`tdL46{0GBbL;<5oX5nft60o3InEWW)YDl93E zH#-Bs8&_k1jW;kL3pwX)i9^j-3zMZQYtgAa%Or;Nu7~|QxpZHtejYR=8R#1eHCH2D2JSIx6us1Wpu2` z9mjXzaf6w{NeBogBME^krEbgC_@_fWu##vf2dfu5JJQxLLY~MB5w{KRvkZh&GgvL) zcPZi{)(n=-aed|P(d3&Jomx!%_*26gEd+XCAZDUtF{#c>Fx6(Ez4 zVHOQ6Mtm~}Ta}pe6sZ7Pw9*ADqPV2uoE43g9!GAtBU@dX%B`_6DYo>okCS&&R56K% zJNwy)Wd6$+5yGsdJzFQ5p0UYYml=d=U9dYrNE+Ug1W*xY4e4Zjd1HJt0n)JUqJ2rW zO$ntIJuRs`XG38U#7iqOr?`MYY=~lrWOgM~v{Beb!z79+Vq8U*EUY7>uj8`#bdm31 zjB|!Q1Qz&|L-#>eLDk(RSqIq1f(!-m;!7q6*}+fxS}V~Z_F+<6){{2|(!sUOmaScchR#-!Lk{K_jR1qB zblHZ%Q#_DWiTRc3l$QAF#t1;crV~TP&>W7jt68|R6oc|>fjeA~kGBFUj)s!Ps4J2$~j9J#S7I&Vk=Xnce0vF~NBmsq_zNw=T z(%xQ@T84N#;1VF;f;4SBJjT`A47qoa7Nl`7;@PJ!$uVXOm` z8LL>Q#pH}hvJbmf7->PQ^H$;r${a)viEYUBSuh;JD87A2=OglULkltpqVKYJirRR11n$zg~*2aw?1?u!)wOKW6x|*R0 z#p+0x`+tfzB>0d($b5vO{_N=x9aBkWK^_L7QGF#Ix|~TZ!jPGr28oMFhFTjCVGtxZ ztb;O83=nI~NV^4XS&&0OpcV9S*MX{2u0FpibV!Vc(gt=br+&>0SFK+tFk=oiw{um( z>)7cLcR{X)l48(naqjTR1vvs8uSIK@T-~^qHA@Y@JhRLm>zADX_2ugBh=14HYXwxeM zDOR}vi5i`$tEM2!<*8x#y^FER>d^6TxMaKr9fO70Pwt@Q-RmEV0QgT1g=8(2z$OX5 z#Eo_U$e646`}{!9xy>I_iGgOm7@Y`IO5r-5{U|Ea30xclRzmD>_Io^g`C8EX`%uU9 z5+rQx6podI!mrmnO96n0Bw)l*W78WqT!0wqtCW0UlE9u>ENMFWtbl_pU6WdRd85tP zc}2($nk3@j8P4k;U+ia^cM@hQc1;RYkx)}dK^Y{r9KuCZNU+jOUrUuROKgl1a(Z`> zRmOT(MuqK$`g^N>n$n=8F0wJjmjmPovL&HaHB~Z=#yCI)%pOBe6;lR_aG|xmSi+#> z-7j*UF86>}i=TSbs4v(JtG|ld&^QE2J9E}i5l2Zt6!$4wfRTL~f^g1Y99pL9njG>7#AYP-`)gh}a1(8;j z!ifDVRy8;TMuPgA=smT%N<(2Y1bIqz;KmN`jn2^XyP-}Gl=2&& z)9z#jN}FBkqKi7KM59C&|pLq@Ycc#j0$;p-beZS176V|L80 zpyV?3PVj01)`-M)UNe;LGl#et!`sfwBJ_qNQj*_TH zW6-LaB`QfNcomgBZlQ=tW1B~cz1qsIwDZ?RiEkmN<mSP*LVzTzeWG)<1EH6f8 ziWn{!5(A7W&+VzultWFE#@CTa4E4k~(m-FvGH1NvW)2^df)7Q4oUx5ra-o}|h+^0* zhN)js&eVxTso#E*XR|&ZEE}gNGu32Bra>Rh_lb*M8KMfpwva-HxoK%jA7@O#EmCI)r^ z0*mS*Kj(yW5i*Pa#Y1>&bRi-uMH0I>j+)ARWl$jgSv0?;Xq*eXM&UmjprkiFVW2X^ zdWDgpVw+W;z*in~1rjyS?`|!3VG|?%Xi-uh=c^Iw6byU3p$)1|ow|kcX_|Ow=L#cz zkuEQ&j@9Dv2Zi)Cob4c>IQvW;iJ*X@DN=qxL@ZV|zUj-@%XlPfrd);$LSz#s+Zfpo z?>j-x-T{&pj;&VQ%`dQNvb-EfObj06m%93-K_{|~54 z5RENN67G3qj@$Qa;hv`O!ikS1mW1nrY^e`V<Z}rZy$4L^VAm4wSrUd-3bN+Zh}8osXDiHbNP&jR3|4b~5+ap~-x&%TTBX!N1;Q>Y?K$oxx?EG0)3D#YE=4rWX_XdYK^sN`kQU`$COjR{}?DDoCh zMvgNzP=y^fCmP~__HZh_0R@SD%OkKUpH2-yoFMgCRZ;b%qCOQY%@u7Zcl%eAo&%t@ zRWYfN%;A(m4Urx835b=7R!rJNX56mbHN>tG0x*5=XkzNMDyAy&WZrlpGC+ozL}AMV zstJqo0EATMY%mOf>@QUU(xaJ35avV{41J{Xbo8}oumc3i$4H+^7k$t`rKdscy9DCfqHN=G_7`5o!&goHFp;te8l zNF73i2q$K;jZ!)JuPQ^t#EA>bbe^PqLYJ^0DMG0`MRZcc5~dKy8HF~Y3PHb9B1sC7 z$0RY-=L%B;4TV*%NC_*%?9W=C*ejU&Nm@~z;Nr>!4b8>lLy%hp(S}mBRAmuOzFG0B zz+9nIsC-dVK*4IyRXh~KJro(w-eV_E!4&&R*aVk<6^9@T@dViXy9A>q6rTX8*vjzi zd+qhic=@jqkTzFo)fS6-B8C|fD{(ADR_N@dDulG5DXO?sQDW8Xk!sb1sr&*YftCgl zXirBOHdbUfn&3R&S?t?r1hUpvX~Hq3M!~Equ&&2Uv4dJn%vt+mgj^z^AOjc|Bj+vv zAYIF(lAOy(=|0#jiAABMpBcfhJui#H4wD=L>AXR9Qz|~P;%$jBbW_Vk#LdPqbl>2D z7~o4II}Su4(G(QPxfv~<#z_UqaLW;fnt+o-IO0+V!7>nh$flL1iil{p%>BU&f>0a34>Djlx@rX{?AB93DEvNgM7SZs&Y zna224ARi{uCYr;XnQ&5-BA?QvQcrh_aF}PmO5s(O;u6eCrU3Psh>I`B1YLQPL*v+< zK~zOa(R0g#fmTc-L1t)dbOm}Yf1u~`r)xLX2{Hd{q-1VYS!iyp)d6T4A`GTcj*wM$ zx$;#}a$d|Gj7%HS8wpXI&%{m|M-kL2L9BZyPFNRk6w-VQDA`ofP>ID4f#laIG3}-J z#0VLilzuuSt(kJJS7->8RmTWbhWT2mXmKIPfy%^)y?u1As&dA^0?Hl7UA85JB0f|Ij;5yZF|fYfVx1^0MrM<025nUi(R}bo+2SV#HiIChuXz{;4mP75ULH^ zkBE|T>hHrP%{(NDX$cvJ`+QW9ARc#W2&dbixG<;bSQU&;U;98*CPsxoX$fsi3q;5h ze->Wx#9~jUkhTx{jK-SPXauAgMStf_T+cfUMEvsao-w+qiD9b?5XaqoRx< z&>?orHo-X$HNvHWAz~=8Yay0Y5lDCr2^g;dTxc6M(_~QS|)?S$6?|p4O1BfRWG-gpuZ9-wu$fGagwOI5IMuIRq|PtqNo@ z$Z)_H0v=MQmiR1zTQkzU&=DZ4;v~&@q<7aq6fklSsQFAvou65Sq+8H8qysZ%n(>fJFLnGwTJRetKYJ`9*Vc4 zdXp>zlh3sbOgiOYS;S`@)j;-KTyTQ0(v7KZQkAuC1$;;oWh;i7ENT7)5 zJQ9uuVx+YoBI3dqF@jD)A@Dds5=_pvS5)gvN7bWyPy%3Y8zYxeVWo&MP`(5?y7~UB zvv+Z1WTTG}Q#v{zbOsrPm|oj0k#8)AdJM=KgUvEJRP0WWY+1~wn^!dIY=symXXajQV6~)r0sLSvPxYeA`S9(B-fyjK?5p(Plcbt2n1(T zy_vxduNbHr!-^3hTn(MKJwQO+8H9k&l^zzZg;he`RZ@lt6?!?Z@IVD8m%HY7!oJmC z>g`3tjC(k%5mpDBF;ESim`^AHD->%n;-b(~rQ{S7KlY>;-t93@^oW#{l<0R=van~@ zC^?d%$El>GY%Qcc_R3Ahhnw4j#rD{6 zLsK9&7yC&DzUIs%rqi^yOb-4eR)-J5Y3hMotEG0JG8ZL@?BL300dSzs!K4BjC0wZI zJq62Q#zXU~25O3}r1oU1k&}T9{ot~QN-EWi_`O$H-*H9QkNle76obLL4O&l6Kd09; zRbX0>tGs012sD<1xjjB03e%zz)3Yvxrs~h~0H-v$t6B=eJx;cBYTS@Abn7)$;vGViB_`DSj!>8&ZB^Y#?C4w@1-if?HnYV`m?&<1Ocq{|YO16t zSO=uY;s~aQ$hsa=sYN9gOsrwz_^CUL=3WG!JY!a-0|a20ZeQUXnKo4t0F`aOGcpacZVIT9yAE}@yF_Ws#Cw1=G6h3lpOPk!gW zShCHL6ru61S0R^Rixu{01UE${mRs7J$d*~^pFgI^ZWMws6^^{Z$Pp;>`EUZl@A%q8 zO3*plTdu^9)n?N=V*sHsB9m-_JA_Gx$fRu!HMa`My&&3>d-7IX8uE9v{A+xZTIR%B zAcX!)_O2Qx2awu&Q=IsQ5>_~p8+Z_MJmrg zlj`g8On?HzUPMWSZwJ>>s|0?lPD^){hu78I>%#dvg2=@aXq^-&`a+zWz>A+;rC2gp&>)NGf!Uq z8%0{sKU+}o2#uVe+eP~;_(<5njC2P0<+GA=L}7K|=)&40UgBpy8KI5vsj!bUtAl1H zJ_BSmO$;DNnf?wLldPtRFcCCOf+-Q@o2i@GZpzZI#-)nFaw|S)%dt-|yv0NUgS$?U z(WV0CFi4KdD>GT)63$7Hp`j_`yf!CnDG(a~qywb=l>hc*wGU!gHe5=eN}iR>!PS#X zIBN*JlHS03ERj1wNe7t+CS#U6%(6nVf#&f!LybbEgUzF*-736Sn%h1BEo&H6Z(||o zM~mo#ZjuH8jV?^HM0AhZ6x8>1< zh~s1uU|yv(OD@qCJAf!Sz!FgjOHRxd+2C4esLrKQJmbXJkuxidYgqX2s-qrBFij8b{+l z<`lUZB5&bY2U-0wxjqAu!=9wrt&fDpBmG;(wo+1-u@_w_YfKP1jU6FnsbkA@64L6@Zz5 z+&%d}-o64ps$=^LY&OZ3&F-?B4GDd9ccp!GcX{{nElLBR*WvHyxbV93bLZWi+N*wNJBps3K64&cFRL{^E(;}4YfSuJio*YD_hBn5? z(mWq!iYMB&)o)u~>kIn><)Y4?O|$yb_K<=Z55fOKFUe16liJP!>#!l7DWObd`vKNG ziXf?GDLlWiVB$oC)Xo_8K9pNw+Ii$kPBLP7t>^(`RS-1;$)80D%=(?b8=F6pt`BBW zSMk=G{+YjVTEEj*O|Fpgdf+P5%Jwj3IV>S~IOdj#QDyj2Dd-GWT(0~W)ITMKJdv|y zvXCp(rRtA^%8x;pqC$?VOQnxZ!j%Kkn!k6YV%1tjiCAU82Qi%F=OeR1_i$8E1??+% z9T_vZs1TpZ*{?h;cI{k(?*EX3BreUftxTH6uD&=LGPCCz0Is|mOP-JHaktz+UK9%mG_-Qvt?&S}L*nFFD zLWm};N)GE`9w^jjiL#{0vQw!84FDNa%b17aN*4T< z!As^e4#93E0nw=*G{~`3r+Sij|G|=$@>Fj6#iK2Sw4lsm-ef!NL!fw~KC~6fQ)_EL zStxck$`U`aAl?FIl>JEiltM_xIQUjDJwblL7eZ$-aZI)&n3>R!9|~2&sW(xqgWc{?%U5UV+@lTgoTrNn9tYtC`C_~x9~ORVR#VsbqP0^lnuR!ykb&@QT0 z&QvlbBg5y(ypk=PSj%A`LN(Dh!J<8}mP2EXd7VDFJ(oJbi?Rp8!bC2}o3VvK_(Om9VQ|5vAStl8ZEa20sdIV&c9|FjMR+CdD>&K-wl;l7tsrd#3lTNWv)p(AIjC17MCP#;0 zdMQYOY^Ph}hEg>J{kco^%<0fJ4kOI}485+nm z4Gkb;){2^pp-P6C06JBXLq;+dj8FNg5Y0=4QWY8JW*}qHf>dle0~rfupu*P~7ce)| z`eB6(WX!54$v8K|;)w>S;wUoBfsz};b4DgIW>wT9XaE_rR@7t+Rn%k*6;x!5#p(tG zGg*EnMMGGjR7J*l8OT_)brqY=)NK_v&da!fSVOsfSRn%$vnm-H$uRfIwIklOg-KG9 zF}xOMB4buXJ%R?1F>6Il#!w~0OsL5izRy4pW*C~xLr&KdBgXS{o35vvpLDeh#A2)1 zP+;|xnqHgW#-cdHtU5}$CsjwiKvuOn^}&{^)euN!8-C{?RLpoEDAzw%~t z4H>8UB(~aV*cic`z5y$VPWPGDo7HN_YUb88WMZLKgFqWNu?>N22w+3u8Z@za4VqY1 zt05Dc*Pv|zwHh$7td<%Sxt@|sF(yveFm=6B~$e9kUn6Vc+bfVrOi2(J9?eA}AUq6@%e% zAZD6CN*e#P*(ZBVmxDK?D+qI)E+A}-u#kn+W)Fl?@L4Pln?>AI*nSu9WVRx48j1rI zff&4d2fBuQVL3KJaRB0m#slp6rYKPpsAEA_6fcNd;jSn7+M8=8RBk+NN0skI8p9iO*q0Iie3kro;MRpZi&165~Y$-P(%%iiBzd z%;c5wU`et=l{^WOGbFOH^kt40EU>0<$<)ysd~S1|<(8ZXkS-D1Y#!RHG2N zPPEfBKSFsyT(5MAC3gvZPnU!B1@EzyF5>k`=I>x>h0aklo>l13WGp2_iYbH4rnzz& zfU6>&pHeHL0)?uO5eFK{1jOt7L=@pdBNkJWoF1m24P%aa0&&pNn8lBk*s^Ly_*^uz6pKX-olq`NJKuFl zAu4{X?7FND6+Y)Z9>u~8>n%i95WkkRc0z@Ol2#LC8PFkSr;660I8y`4iI-K;V)sQp z#4jA7iWVDCPJTkt8%Uq4#~;rye$rKk$B~uIjfesG-X9kRIBzyt0K0fx=gPok1-13 zVk*OVPQEZrLaF?DjYEozZUM7IIw#QTwi0jBNrg)o>|ViGTyPeG?=f8q%b!W0G9xyK zvCO_D%55?ySYH+i!(u7d2_sgsOI@PbQj6@1F3}vPf?T?QNb7E5SP5x`$Xr&LsYYrS zg7EnmGEj`_iM8OjVsOP{p%>`55MnJl3B0YADgJbcfi9|jB3=`z7MD()|GgXJO7(>t z(?JNurWTktE;g(5=*=if1ZS=H=$&d`ERP2KK}hb?FJR6gPsT!_B;iNFI69qux&k(n z&@-VzZKfLNfT3)HIaCNW(EPh32rihFx3urVM=@lX0<5%%;>b0I<V`+--UWEFl9%FFB)L9g>=Nso zlU-y>e3d3kGQ9z$9aRFZm2iwW9Ns0SJ{`$1H@^eF(@G%JZXg6vr(ry1RzQ)S>^0Eg zg(!DA_~29WU?{VH;^RDpOTr3%DbbE<$j($Ofai2ShH zo-sh&wybGe4cRLgYM6ml#rsRTK)ksmODx^0v)01X43Gc8x?CR8ck|WoqL$9;oOMRy2{}}lU>Yp`a}*InfxS=R;KjwclyN@|=byhdfO7l)ND&3#IUX_5%J^lqwPJV(kSEpMYha$QIb9#jBaa zCtw9de}d*wbP2jM24V!;GO^5J>H?M;fmwx!w*WQ3si{uH#owgPz?l!-KqqN9b9fCb zGy_f%lJmdyv!sqRf0yzKT0c8fuOqlDfYwpft#Ey|+m1Lwxkge2F31tkDONX^zbmDG zCf3FJAQOCUzO6<^c*lMb^TIlimrt!zR|vI&UhBacylfJOBwv9TT}q}BmEtfb_OcA0 z65URJP3#4(P}w$otZH1M_EgI<&D&qhGzqlm`IW16^)D3qoDd;2;pcTL;TOzAe z0Wn6aOi)L_yr&9OAK9qQp*J#-TMf$*xYD2;89O#?11A>8f`RusIeJ(c35w;IVM4JD z$9XQGA=QXjaf2G_7WKvAgcw{00S4J7q=#b_(u1)IiM2?TP$Nqf5_Fm>qo&>}q}c^( z^XS$G-%7tQw1|W=zd~Y)Q+X1e(>;{zL3UNv8 zU=7WAfw32?lw4t3sg1~-4*J751CqM{M`W&i=<;c=JWS9eHTQA9rK0b_V`k!akr?u zOg*3_!%&%;HcUFjcTa52tVbNpVns;xTn{Q%{*_gNP1cge?$n&qaEW+J3=DJZ@fU)m z3w1d+(A2Lyb4>osv;5Sr;`J(3;LwWXf0X=yXX&Y5W#2GckuVju5@#6jmvj2eX)MBl znSyZy5fmWF5Af;B3B!CABNv1{->SZI8jx&4knRb+JjBs&eUd{Gi|7rMtV|M%oR26~ zo$L*fgDCj{Ni39ed+Gzp^~6@hp)Pg5@vKi;SNcfK1K5~X} z_`a zCq~JN9LJ*|7WmL<8^Q@muARTPXjzTCuS@<3XPRWPK&SjVv<)kZ{hC(I1fWNWe6wY;A zc3PH;Rr4ZyDGT2#7nS)X)6IhdI~GaQ1jFEcLW}s$+>qvXXt&3#_9ffd?qM*>By2fs zzsqx+`b50^vaeViJf|jYg)%dQc1?Q}^J~#^gSBp{%yRPOXP@rTa=20|TZo1tzVejY zEN_F;Jsz+;p?GRe{cPFF2o{p*&%h+EGQi)eq0qGcvsxC%+#|nh+wL8LVbKVR{SG;# zx+P*2;N~fX*kt8}VA(5BkokMu`iv?p@OQ87-D|u#1UZY8N35B8=8!*G54;FwU|a6&W47yX})}AY&7+7 z6qMgqY(rrx*UU9U29_ob-g_itw;DW5tB)*(h(!sC^|jZw2&RFxO>%8uWorjCw06eX zuy@39bT}oMvXDi&A%$U$0$Gue`}w&Y$=~JUrLj% z)haLi^B+nAx=^fYnAfOqA4-w4`BG)8itfty3BFzWR54G8Z2Bll7Aij_m)4wJDTg!H zBS|PSd5ZO^Vx)3Q7h>LWm`XZ= z5EVVB6O+xZ7)Xq7R^44mPr!Ywq9fTrnfuh4j&hWAl%t}f9KoBFM^ukAu38vD8Ev70-3%NAjBhhpM6@QAfaksP3+kjwFk9u4O5kJy+^XN4ZKm z%2m-(u7ZxBOtrzGSg|m9odt(y`&h70)pTBGLBqm-EbFlOa>bbPI;#hj*IDrM=37pb zsk<$Dd5d3X7`3Qa5J|5Peq{_ z=u^#Z5@jl8q}-QKsNB_1u54R1$*`lr z%T>_C11R^okmNxqQ+8W4P!YaWk6Cme<3G+YX82e!W-L{9T(INdpyfdPLa_oEg7m9# zRqG6P4VgYxL1!9sp5h2EghC~@V9UVGh@81xC|2~E2>8x_tl)r!a9*f8tzztuT0GO3 zRf|PfBJdqo5-4SrAbhSIIH{~>T3^QK6dG%Lxr!57uN#i%LZQ?1hwW_Xq)=Z$nQHBz z*qLguQ2nuNd19a4PT5edI<-4x^cftaV$Idi%U~KAjXBCuV&mhEE?**#)&BVJpHGp?XF7ftxz(QyC z)Kw+fV4>nuAPq;BE4#^aeS(>F{uB=!=h9@XS1I;82VlCzJGWw%tGK2$?~1jH18Y|n zD=)+GY^9Pco~^tk#??ycIOva6T~jN1MlYL!WB9s=1%=xBt@K+!5P_j}5$M-~rk%?NenGt;@QY_188 zqR~jqGz1jbFIOa*SBJu@#m$$Ktf;)mKv`J{edgw7AI?inh*Xp{&q1 zf0r#5%->-z3yN#=ci5)n@A6B9Ssx@F`U5!L9SVr1z>qM~7nWF14M0+&L9T`sS#JGI>_Ib(!G#e>}*Af4hlk=?IU@4 zQymPdI>^7Wr5lu<*lb0L4hkwo+eeBH#uXhDR5YmuWm^zik#h${wT=J5g9=s$a-8#!^U76ast*+l4f30!RmB2;?56loF)<*wIeb_QR`?L4HWZK?fqG)V zX)!xYU#Qu)Z3x_lz()cCg+yZYwnN@5jmIMp=QsD=1;@xt8v)ZxvlwgXp; zFw3_C@gMw{8d0tSbd(>ALjof+ZAS?Pg15^KWEloklCnYI$U2NHUmYl8lVT6p%X-qjDiQ(TB8+8hY6+yi zN;RaJXdj8zvp#^&SiY~uCw8Sh+`DT6Z7V9k#i*t}zr90wat+I^Zp(c&+mY(A7a%UF zfH^c)-LzXaGcw9!V^xxPRy#JfXKN=jL72m26Jdf%gk{#~YApqgW0gvioL|~L1S>_8 zLVhU({_kztM%aZ**8luc%V|okM$^j?(IhB|7Om2FhghWAnIR-=iR+BNqw7{c=A9%`x~@ZaI>Z7FCyF(GGtxRsDIp#t z$r_CKfoy#B(o}O*&~r&$gD6e1@Qz)(7v@V05qvY-Ct@*-B7({+m>*KB@!i5H3$ zB*KFV`N7IyjW5KeKc&Es&seBgPzR|8Ffe``R2Xo`QgC7&3Xu_8_c-{pQnSORMdti~ zk0s%X2sLFLebv=IcBYd}rb^WVOs=i3IvNT%5J*k3l9ERFS`K8wSE4#z6!&8{x)h~D z%`&D3lVNchdeKvb)b!g019m*}*Mby)O@6SdHK;XShIed@w?Rr)!;_#8BV*V4LKGTi zQ2_r~$iGOtLlb8QL`z7Qg@O)ADNqdF+*Te|2MNEM zuQo#kcyqO;t0clYEA|3p+yH{%F1E}nVD(eEc2hM%0W3$c|kYpKeKLt zzdV!t59`kxvKqC!3IkF2F33q1odkaw2mfDa{csTcc|%syK~}xy*3Vf-!(aBo{}(2I zfIn}@YBK0R`1AOzBiOIDL0z16Vxz<0$BC>UE9=;-Q?o`_pHLL^$0G4aMNN}SiZ5-_ zsj&0SRyp?vVqrh<|5;fFv%fWhe;>mBmYzB2fj?3mg|3dSKHz|T`|Mvp)hz7Wfmz8B z-;kBXdRvwJg^kU`vFhYu9r!3KRi|0{7ySJk{Fn6)ww{&M()us_ri~06IBPBQY_oPymap5rgXRK) zxx)0UDfU*g^5X(&jNg}sIghIBs;t7 z$gC{fpXHBzG<(qe^Vt{=ffel7si3EUDa?%OM5qQ-9(WJSN>jZ)pKO-mqiM`PZ_C<; zJNE$KAa=|eQ-|jYuX#&(j9ITOo!Auc4ixb~jSE504P;s|h(iPyYokMHNw&QM>9IGA zcAMwO_?2UZ%)1Qm4@%?171{uGQn=ix4nmx+Is;-sf!O5=nONPm)B29O5|9t(k&^=s zl*3}TH&C4o^I!+p-m}dK^es=_KL^ndaYS!h;t@JQWi9W{*>)+QA1b1U<9NHRfpq6a zc_3O-(ZU#P;UfXI9t!Kdl3VLY`(Qq;C# zx5;~C0t(H?HUQhG2-NtwZLZscW=S#5)`Ld=?sG4O9vtV`1IRF!-Q3lzQ@9&$oUw)c=efeAILxc>Oj?5+=6D{LrO^uoKqF9Yz%vitL*3Cfb%K81bJZ9;K~LbZnUG?X zBcFj+-5{imbwy{*2-)GJt_!za1jr}y$YD^Q7?puAoFMp0W}j?b+M;&Wq)!iBgFEXa z9yQ|khZ0Oo>5~Y=>Wu)t#=F8Mq?JXRj+%yZeKL;?N(Oi-tVaH6RGXRS-5@t>E}vnS ze(}T73jp~P0XY~B194R|BLz2@6lD!;KWjCP_EZ5g7O8|o#3&1fA*F_KYhKf)UL()= zW%qhSK8;5jY!$uZfTm}TtC&GycRjg={&NhCsYgKlsu!|lqq;ho+03Z0|A(= z#0`I3ci3>@Lc9x{DfEGzkcJO3(Fgr-AxPj8h!Kf$tW0-jQ#3v+ zzt3i*@v}($G9OsvxZ2T_lvF&t*HDy_8k3lTx@aiq57rp9%w@wsA(5r+vJ<@aeSkW% zJ05k(UOcnUCi@YrhWAJVqxc$30}X#Iw|7Bz_9?!)`q0kPk*}UZ_5dD5!v0{$fEfWL zryFc)^m%{%Iu}RZM2QX0Zi#>gJ)lP4y~(8`aP;SrJwQD%@;dWE>SpxKTFAWpio0(g zbRl4$Ctw4$#RJ~#c7oG=y>9y6Y(PCgI+sLW&ek}5pkyNeQx2F ztDpxL@IA1u+(soBt^=bfgGBdk>79}l58g9#Fmn0}X>_X>d9Fs?g5a_f z{~+=uJhH`Q%`2G!1}*`2S|4KeH%&flF`jXks*r2o#0`WXQyu6UFe-GtfY4CnT&^t!wt8Cgw^J)vggK10z;fzS)-yYPI|LYSH(R`GGw$(LBCczcLDP_);YklwzWF?cM_`L!aprCl}8 zF*kGGjL@f_d+r-6&IZ)$MAQnn6T4br>NdD{%d`9NHh8^+hHnK%6fIx5iPffNN`rmi ztA{K>4fYK(Y9d~hq$}ViJj2w-CRX+AYd4HU`KYagO}|ySSzqdnu5p*q>rp;xC*qqb zMkAVtRR++9!49lFa%!!|c6(w3u6276nXR%l>+VnqUj0P;kQGe;HD5%HRhAifIXQMf z?OjW}h4mV~ZufbBS0Lem;8#`;w=Fk_&50d5W#WZWPgyQf5v*s1U$p6OMv#)Sd2> zy4P$xZ`f$WFLc6Zk0LcjyN<1J0UwA!1`Q+Soh%vA3q;Y!A?%-5}VeYZR#%ditpPAC}$N(s42}=6+C#_ zr&@col)N!z;_?|NZ*&%MEo~9Ix_a;$M4gIfe=u_jo{C+R*wS=skDHS8zP#nGWhm)& zb-<2VSJ(im#Zgt|ii?a>}baxUZ(Izfl zvH~UATLonEUW$*GuJ7W6Zuhyy+cu!p>}@=%AKoiPGZ0Va_x9?GndEW1h!+6S(mVSE z;?1mn{%L!WitnJ133Ae2Q$pJLWYo!<&}Q>a5i=MC<`@Py^^iLXCRTLNXD6-0JDDM1 z+O-^#dP93{DL%1t=$v&p!*_|u9`QuV3Ze6pbu-Zl!6##)@ioZrNs->X7<#gg2z~vp zT}MyG-CHL2BT*CZ!d8-!bV9FQIvFJ$KaE<8>15&dZB#;jXfV|c_Tw(%x)e_JAnVpP zBd`bMVh_M_4&%W2LIya!!wUtR6in>o9>aBeKqIdf@?l}Z?8E>MR$vsXz6a9OCE4df{Ge<*f<-hs5gboZ0zles!c`2 zNqGH1>-XWBhA2c2PC{yzcDQK-dqb`kF=Ii?Yr>QBkkED9+2g|HctZ&b$jq=8-Z;u(aW9n|y ztQYeC1z@6jtkip9lw0Z%TGRm%^yG;#-bvH5=cG`||i;1yhL*3Lw#gEe6Wmh)gkZBiO%QmTzh$qet8jaq^;{h){o zZ{{9adl9nl?eCN@kEDlWUP zgy-|Ci@)54FPP7WxNzcvTFZK&my8m%X_JBmjqM{&w}2m zoRU@>k$P7fHe}%_bJ_w$UCban|3`V-b^-UsIxTEJ}N{&50Y~&etl};f?UW zJT5w!hC%_5;7p5ce2owC#)rD2rtW5AKDvG<-pyVY(1Xzc`kgVIA{a3T{c#U$)(MT~ z0k4(r!M*f`h!6IyNlqzWjdVv&amhpf8nX+};x`3kOo!tj0%)%{^&)U?=?7zRN4-Vi z#-o^uz)srQn3M(6ucy5}8&9LRMa)orCHS61Dk|au(D`5x9Cz5n3ip5WD`ti8j))zv zv0MWD5s)ecg8v}46n%wvJ~pcm*HiG#d zEN^np=ezp&ZtHMIz0c!%95tZ@vC@NYUoizk#C^ac$0B73SnH(N!=5LMvOtxuHt5c? zl9C2u6H8a2H1HwS2k@iiM0)MLMZMZTaNpfy@zwq#Cq%;+#rOeCk8A|v5pcwDt5K%< z@$dF`cVa(2cI*e7BoNEZd_VW59~9j`@M1F-JL40+A6D#)q(a@@I#AN*Ql1HZ;d}) z=;Bg-%LmRlZ65k9f1$wjG(HI-FRi}ggOJ2-8p@+Kb+p>8mFMTDT z?~mvxRK&o7*AH8XHs@bA0G}f}eQGD>eqZFLq4+NO4T$~)T;5=O4??_B`xlDzhaksvd{;%f~ zlQ$z@`JO~KPmbCMFQDqqG$pBJM`vxrJ^cfTE5^NX!_}x!zjbrzP8{`*3Us&jX4Hw* zzESN;Jh6TvaR~;dO<~meTzSOJ(@`${nM8#!ul^v0ey~rnHZG+HoW3RUH|ha@A#pv7 zEJVD&MISkI6`orI9I%-^a#BK-ubcYgC(i71_5?;EmHkThAyEc)jWuxPwokn7-lERz zeghBNfMfrS#7#a;nS0C>(p>TtV*Uq=*tQ7uu)iz&AcV8ho^{Hm^OZH*W}{8#A0%?p zy1Kz|PBQ zioR-g((?p=@Qa_0NBn^q@PlCp+gQ$#z9;zC`6Am8e^3T|9K74x0p$t$#7%=oqbKNK z8J{=q&>k&yo-AD#T8!t(5DLxkRhMBT1XpWJS<1h#_~Icb6Al$n&A4SA*bWo6YPbA) z^$;BCFcNcr>80QJa^W=8OAl9}atdNy{!Q_Z;kO*V4*ACj6{-iiJ4#kKtL>s`C@YK< zvB9Vy9VN=;c|n|&hrTlGZ#*kU3Ak2NI&*=A4XZoXc?4ZOnYC=fnSeW5z;*4nO=!!; zJ=$h6-fPD2SgELEAcI+VS^JjN9VMl+*nRmo{~{fa6_L$g|7GBW7v#e*>7r6}96$CI z7Jq%511gLCeOCgj7*$HjPFPgli$k0cR4RyT>Ui|LUBnOOTgOcSZ$D2V(?I#MMS7>`X4$dd3*s z+cOl%kiaSqOx?c0^yiv*F@JaOdPZS0ow3U!HMy>EDSO^qj-R##?RjU>xD~+=hNkv~ z;f({lQlmkadz-MsXfnHUJ?b)MD|_HUoM1u+`}_wNEJ1mDjsv#aToTmHV%2&7EJAsE zE{$o%=ykQul;)zOS>7zvT+E|UtAm)m&r01=6EOmi>DW~tD9z;92V2cR&E$MlAHXv= z7KlQ&c{{xJ?j~f!cVGG6KIAJ49MI_$RNBbI>Gj|jp=Ee_Eu@jdAe=@cePNqHsD_%p z5&OWkc?%^ip3I0WKA(mw~HGDaVpna&? z$dpv{%tHgFpj5P+Mz++@T#zb#T;koZ%eAMmcj6UJxKc-K<>$CeB@c?Qa3s~mdJH`uSAJF7P84n-6#p<`|p2;`5~{(gv<$ly7WZJ1h?HA z9gH%;x=hHaXg-{;oFMfv0`n{bOO)>)Yil=Iwf-ACN^2 zuXkv9?TXSVZOYIN;q55>Zs2i~E~}QImwRmr^;Ub_O{cEIGjb!3ZMvnHcS@rS5);`6 ztxI>*4X?#FYgm4*O$uBOMojFr1N(JiF_kyd$floi^Sm-XWWDy736AEQ^BTM5Y*8Vj zg}qBnEXBdYk%M-k?Zs9Snp`eL*yY@V9O#4fKcNGjtoFnfk1oU2-YxVXnel^#!LturAC=G*T|dp( zigNxQ9?fXA{1XisS( zCHT~)sFuV%uE$M{rdu z1-v&wIxivYw01uzUOu_e=}T~TA8hMKNnt7MFmx?3T|8XwHR81Xb1U>3T!lQa;Kl8*4+1VcsQ>4VFI!x5L!FIOevjQ03mdo{+bhh za$kQubRNnphjaZfGq0KgvAY$gPVXZxTs#v`?<06j@3J5e9OtR#hqKs#M+%tXTGO?) zIx3i*>(4I1Q=i*Yz5uldNAaksXf^I773!|B^Sg?vc-J_ZN5z4fqP}G@Xg@-9xjL0; z;_pD;z32^pjDQ<}2Zahw)vAp~P;Oh_sXLHzkLA&#VLIiU{(2HGN2_1EU^!~xj^i*Mt3@vv`0>H$XIL}^H(^D z#+HI0YLAz=uRp%~Ll(>XWE#_YwTguO++pYia+gQH9gOHLA)jgu2C*eU;_1-*ZyI*_S4g-`9)n7R~!AY z68pLAtd?8x+&_ayb-dQ-(iZhbbajUz%kb`aW*W1gv;?F7dy$K%8L^MrF7R(_0*Ghv zi0v!)lU3Z#Pp%k*GDc$_ub^WmGiH-)u%bJ!l+Wymzl`38KC@>#p<>=$jL~BBje*=z z9Vz!dPtHfT&zXjD&N)tfAOcP6j-85HRb142I!3K(BICy0T3k{zeAPd1??4(pm&fbX zy@yfbgXB)!^S$;?rR+&>>$G_R+LNBgBlj%t3nejpa3$#}(F1Ypl;BH=tdv%{*FWZJOS1uB8Sr!F9 zMxwVv>h255=H%*^c8x%rlZz?DKp#l+!fb;Bro*c%bb{{|um5Q}N)eY(=$>VbptOY- zJ{#SH$d@`ICoc$Y#!P8!Ivv@Oc}`qLA%`NBLBA2FGnz(r#cK`g%c=NiPLY0lj z^f3vE<a~ z=I5|3d#)&nSkr$$x@se?>D40Ue$0|_%RQwmYd}*9(cp!@td$-qn zwUbbn+(O2-@~;$>w9hsmTy9H@8%VJb?OjD_sXG7CeH&6-OR*o}{hbBmz zUs-@l5~WQ+#Jpa-$A+puq}lvg>TbEq-64k8~YZaOx{jF^fu!Ng}hD(hQZX-gUv~4q7{lpC0^9TKE`((Dz_^Xf zd%cjrPv)R>Icnlw|7eTdEb8@51S<3WG?HU?wV#N4Smn+AmZ2PbGl2~E&2XG$I!PKU zyFsTc&<{V~6fozB%QP{>=BR*crFl8xOD+gw4f@-r*gs zVbt9kgbp+fk=Wp94)F|IcmApS&_T`Gup4-Zb5G=FO>K&!ZYQhHe|re7e0OJL*V$7j z+2^*a=M6*Irw5Ol%AR6bk_m=Px^qo&%RgqnwGg>wPX}c8mNwKp_q@3EcAV!@C2F3# z9Y)+8&VBKMo#?CHOTdLZCdq6u9!1-uGOHKgF`H#pzg0#zrze@L?L1-?#1xOfD^az5Np(j^?VQT3r%c72a|e&dL`lm%#LRZV z83X7dQyPWKdR(~{&%-+@WPCTV4^^K#5pv{(UmrdVwdw|i2);i7$e7DrxAjqpQ|aqR zubzarg}W$JLXn|8x5NoNrT;-okw5rEOb_#>P&cC=^UAm2Sj%`^CTLLVKQG35+nf0; z4}qV@G|ek3D!}F1eWVs@tpDxUhGo1i7jOgB5y;miAFy7GHP~v?9$eRe0@JAQ{w{R+ zty9+^m#9$Tf?tHYSUl8A*b(P-V=+G~1>|7dj~VDOjB&fbCZ9CXA5#>`YncIK!{S=5M6fA_qJcvrZaK#oEdaf?y88ZmXI z5B#PzJ7Iehxb8EwP}+>5wFhrQZAQouky&_x(Lh-cWb}GBGu?u?2QCS}xxN|TS3BZk zbPSd@9fEWa2ZZ*i)Pj&~>Tjvr)f{>e*6D>itrj6qPDyNGv5z7|FVN}SJAVMm8)tR! zv`OfV6Lmu8V#}p26S7FJzaoU>cfl!#&PU6(KF+-{?;Qdq{z=sMi ztn4Wr_7RV7Vmj;ui7gpjYf~E~y_~k~!ci!x)smReAfyv=$Lk5HG?;S&^S|#aVzNYM z<(}|5>Qp`AmqzSVtrKu@kj_D@b*YNd4wT(<-9FR~)KkbQRj#WOhKP&v)QKb3qQ`JQ zB`Tb9V2cNqoZuYprU#UMqT|#6i*$C6&;w6%MG-f=Q(rlVWz_qRh-=T=WFM^dUZUQ= zf`z%uk$2pyLiHk2Cvj@je>G_%N{si3*xqJ~BF^rK@7A-k`+fmA7OW1|1ZxApso`B0 z)XVS}moYU6E2H9JuFFCHi ze+}wO9ujbCV>N!my;hZ&<3=wo+=6rbFpn7X!9f^v3WDUx96#Ln?u|Idj|j*CA3S8E zQ!=E-a&0qB(DXBBT(li+BOVoTnK&Lte`r_SgSz2%f@QC|`a*L+kv=u4$Nf`_LLLg%x9DZSl zb?I_m2@1;gwPE(GPYKBW03?U>z`BN#GQPOK-7u6go)$0zFvxNrD5G3k-Ba(Ut-|>e zn*i!FA}VO!sv;df znavmC{oxf7*Opz%Jc>cuvL8>{BPVF^&>2zYf!#k-575)j6{n%b|4h^K=HmEYbwJ1L zl<;^D+!bs>G53?Jn=9Qa~@c`!8L>20|5%Dc(vz)qQUq2mM%vce6yiFaHpFkr2hp?ULK4x)LUc^ ztm_rb0=N0K$4=?PdX=wXIn>{lkspHEtW(59TL-giEv40giJH- z;J=okJ;l2cYAk()h2+{yL1t&N`eP=vC6E1ZIkT&LPe3;_5qa_QK*?0|u5CLDWvcg8 zsP3ql;4ig1C(lGZ$p->z4ZQRCJ@b;GPVub%XZ?$(_=h4g3)uo{A?97@^V|wA|Ld7^ zkduEz<3bQ}BOY{_LyX$JQx~k*gmU`FG%mX3yQ5^{Hhad%F|+YD`-y-FURPkZ3PD?3 zAyP8>Yt_x?pp^V6kI20kd1G}(X|!8CzK+Ec{!D=`KU3+Rj8v?prz?({jIowJ7m=lD z)yGII9VueLvKBo#8<{|RHz+0h2D|3_on zV>^MG(+@9ykSiH9H}Ef4^U#u@wlA)KdPF8h0Lt_&;RE5BXf?prY`{ZvL0$;QBE$zUv%V z6n@X2pIw6E|0y$mJlEy;spvkHrxz?k8;GA9hHu1S8`z0J`wSpB#NbDt+l_M5FAjZ3 z?58|nITIHx!n?o#HLiRJ>GNdbwzuM;hX>(p?^hZfa|Lhc#-*yx=Z}~ z;I3_Wml#3!0pGE+o4Xo0h5Ave7V{BxB#kPY;cL$~m9ul_o9Ax8vw9Sb8V$ri=}_jy z+dZXG>ecEgmhE{ojc(<7;}x^o9F2GzyW!j|D^Qa)hQ{4*`PTaPTt5f3J7XPiIn|l= z`cgWq>6@ROj5@4wG@@&p1xhLzeo4nI$Sub^V;aS-&IyWJUh(}{ma%+-3bi8#t3AV% z2CHA!L32?W`dfi(-o5QCLz{{TN%vo0KbGlYq60F#G{Y-{+jk90BA9aIPkT@znB<6z zTK_;@G!l0CnoL>zZhmmqIJEek?0_yBH|fqbMbppZ9X}jtdWr+4{CMUC>fSM5u$?s3 z0o8pDJ?h2o{ND!c#uvM3G%8EfV@s1$T+qV}Wm8;h!zp7&AlI5s_h7$d@q6^#yLaL3 zZH9p9k)Hsuf7{>jD|?rmDIh8XV`%d%ikc4{anE9;=2<*)B8*-F7~xC`gr!Z*#2cZ% z$62`#ayROHRevUJyWPqtVR_atZvC$|N(R8i?Hy)@dEiJVV z*$d<@btlZh^JpH8>`~S@iZ6G(x6MxE%kxQO4_ zH(W6s>1rX5%dF^(-hp~J{;I*Bv(DA(5|ZorKjaQU+(i;Dp7klgmAe$`QWeE9>aKrv z8*+@rJZ@cfwt*45J$U1wtcMD|-nbKWc}vo$9d1fm4VqcJjE?Qwck5!GX8rXg-eHRm zJYqNAftRL{I~Erd73B9aXxT*Z|us9!>kaH;QtUSM{_N=vFNG$uYbWMWAOgFf+Cl=#KwAHXC)8t9eA`^@${8`oy~TKc}e4xBWntpJNS=ZF+n_!b5lh2)eZ1 zAbgRVTsx4(by>@!g0&yo=9K$t+{Gv+US8+_GyZ(l9)_g9UMlnKs4ZUXV*(e zu#>Lsz6bg9zdX8KqBBAe@P#{$^!F`s?*DXV;a)uV*V~YbI)XklTpkLC0L#nl=XYWgB>0yE!);#9`UtUmKnBxIgZjPHWKPej|@=^P~3KJ6 zFOqSSJjkv|@vmN&e7F+%*Jd6S()%Pmsq6=_Hpe9PR=;`IuR(cs3y)|DvPf#+k>UoE zis>*vE4CP8I&9@Jll$3j)e%L1Iam0^zM69F5o__KYg+^HIrBz+8YfQ2GxOdYiP7h_ z(>=hfVS#X!53*>%x`X30{2T0O-A1UU-a-7&-?bQJz#Vi?tXDrj+?Kgz(4GZK1M=ph z$8AFm$W9w}=Z?jutBM!z*Tl>hm91yqSGxpEeBO$MeEtBOB0kPYT6dRGGXC8weprNO z$Zk7oNkJ#D&j)2h6~suef{55jU3-qHx2Eb)VjaFU?Gcf|A0i!Z-4q#u{aEf5SAC!| zQlI$CucL9l?G^g~CrTxYZE3L^CV2}XF12TYn*W78dyL2V-$(Qy73H#hQQNkz#!kuJ zqrQ4=3G&yh15^2u3p?Y=W5g@s0N18A;%+tL&72*0w>m(?M31yk2*N11mq#gm(4)(L z9f4Yz10~!*j5!|xKQq{SmwlRbM@(sRFW+AF3jba3VK zK4GtI2a7#Oo@#M_FdpYG(%QJh`TcG8RYOoVJ|vBM^Nq!33|=FZP03eY%MKG)^G;|x z`@hn0H0G2zv_a^k>z)4oChjD+{`=q(yoDXc_XFLAK}I$zLWy`4Uh+jJV%-&>vbEfQ z|L4;&Tg%}*Hp>a%X1=MMavLV)?8cmONAOtThyg|+JaOsID?wea`(EFR)O93}m*OMV z_Ckp*=q@e^WnZ}OlR<0HzVIj>J;uD=lc8XIem~xY$^uos+8{p#x~ogYaroxCe%tXi z`)H~Uu08K5Eo9)#)~itqc?^$eO*On*FjrDHltsx26DxOZLpkAC9yQ6m>@qpCw5}?5 zrxT?5@btMi497kk*T6o6-1dR+vMTFy_}*5~hei$TLma$IK|IgpL`LnsM@bI%bSPhp zlEd+~o|Kd($vzgS1Xor!R6x<*IqUBoiL`e@8ndXNTiep4qyi3s%$^8?=rGKwleE{B(m;1FxMw}`)RRTb z7z-I}-MOv6DV$PCo1YQ)pNRv{8H_7@ihvF&pdjA1MP05?sT=>Y4rdI;8~>>Ss*`x; zioysT-fw@-TZ8idX##!?oLUfYmPN>6mk&Fz_G(iaoo!!S$}%OKE+E4r8a`%$mevlb zy}|?sySeP4fAEdr3<0s;U*;zh18R@6B_RopAG%|GTR=TCjoP^fa4VKaRFXr@a75n4 zi=^&+^Pc~7Hm>?1%XYA6YG)Iu7zx)8WX@fCw8u*6k9u8NyaM${=kTbZU>GAYvLPqI?E}`v zrgXIDe|h>cr1T~{Hq+6fOjrRvyYBqJC>y+0&(E2TTKRMBs2~8;1~IsV0R|74rGwkn z+M}iJxIhV&86R-Unagm-FXWMu z&oAsn!sKD_lj}IoEr|Qqh~SLbEujY&HMj>b>j`(UZ77a*@Gal`jU4S_x*uNXv51wv z?cB3w<2%$PJSu&p*oj?#zY#ix4>~-s2&w(jhM>c=dk|HKkX&kGFK@zA>@uPkrYDS1 z0XdENi?86u}!>=Y$EomIAUxKyp5>Ol94l&(PQ(DrT5!a4I&2&=%UnP=h;}W~5f8{5$ za2I8ZxZ)FteVMg)5q0y4jh-|FXFMkpGMt*=q|Avcx+AB~uH3qSip#f z`EVb)J!nb1MsykU@H&jqme=4O7+?VA3j?+*`fEYljjs5tcr|Kwnq}+@1jB_WadAk7 z>HbZO(kniG$(mKDS8Oiy1QPVhDf{#(k=O&#t(&Ie9%vyWngP?92nRu?UF`uX_GIjs zu7jHZa!VQ6y$v=YH7)%v%rs}MIK1*eAob$rE*1&J*`B{W!Ls+Y7BE@LTo#xER9F#r z)=3l{4f|vFETp401g?}aSDTKgTUYbX=a0f$*EIwpM1F&tAB0G9MMKm*^SJ2H`FPK~ zmOwT0dxC*P$X6ZZ!yD?4n2-c#ym8@Nln$=ru^p1u>herV_xtQ!pRz1e*UN}x3RP`P zVwBe$F>WS~@&*~x1Nol1Nte9Qk3}zRDLcM)qFLIR=af%upb-=_XFw%A$ZlKl| zN}#Q?t5b*4_@4CHihoe!+n&d(vm#TPiIG@@Le~~P#At6i;q$>LRp-;_HoH3erq!h= zYR{gw__cAkXA3ywiZWCcU@`+3xX)jO1|Zy&YwuYqes%RHT^3;c>JB`%dyNor-u!Xa z^}F$|-SP$VGAdHya!EV2cPeFVJnx0TEY$LJR^l3wsK^}k(Ft47@;9f< zL))}2G`e*qE(0rAhzSq(5_eXRR1~N8Z@6Y2*G^qPKfUGsf0f1-S_LKA{V>e5fNW}*@GPDlU&*e5faL{9TS!!@4mwc z->8T-cSX;X&LMPBqbaC!xKlzkHxM_?`t(b1s(8(!8BGAu;1H{Pp$ZSQD#XiE?B(Wz zalhQf;hBD#M1pPoF%oNe2i+Ax3^jhj&@ls&Wq3GSEn0P2KTg!t1(! zuSH{V_XGr7uuwL)k1Is#U9I)icW%aWzJf3IVNKD;JwyLvQg*P;SCr1&-M_gvZoP@1P#`&~B@Uv2v+Fp*oc2w)Iw*Uq|h$4pUL zv&E&%UNy$!t5e`=uQhc;3U|14IZ7dM0vUb#!CE%#ZoCw~Y%}-tb;vJkcvN^0M+t;* zL)ITFaYN}lu6R4%7ZN-wOM4rSV&XwJ>q^~F`d_+Y86wsSh-SiDF>JjqB~drO?>et$ z*{b{Ui14%x>MWxc0?BfQsQU9tNLIm@m$Fl>fu+h)@mo$Nq{zt}TXT2RzmwKtY!I}%-AA~De0T%v~j5zQ3cO` zI~=`}ALnt+B&lF=Pz`aDnA!Gz*xwx!cd_`nPbjdZ%aZ=6iBs|7Rax8c_5aCC$h?A5 zADht2hClpr1?pv=Qej84n?ou&*S6D?{C@a`L+9d6@o5DO(o(fN#@aY=#RCt!c4M!lxdK@wlqfs%W0)-PT8Uf+nr3Wi@s$?~K zcrczS&r$ub(tkQ%mvv`?dhMAT?7kH>s?U=>u-v!dwI^1?+|XRU3Q+b&=ZybBJ~pxM9((_QVYu&JmasuR0heZYPjzkUO4(Sg>e*s1j`Ma0{v-{go!LzwLSL z48(qo!{$>-ny%a~-@ynyVA(TmW}}ApzXEn0JlY$9>as|j6Wp}NOWifstcs38sp)kJ zGZui&Bn2kZ$0f!(a?MR!aI9~LxR@c-1B#~fP^%hUH3#)jZ<3f`1r!VNDR8t$O6ky7 ze!G4H?xVM8RELz3+WUymtv0W}XcV3lZ=upyI)m4FPp-UAz3Z4ah}5ppomM=y-=oE_gR){ZSJV%HLoAvlXTD4@qnXgJ^wZ zLgT#oxQ|)1;Ezb;a5Pe59|- z{)rkFDGgOWab6(S9y!6~u3kA{A-*7eO7=j0bl1itZlGIwKgpsoe5Sy3r&FWOuOUCi zSyr#l6{xv(!qQ%0N_W|`N8wDAeZSyQl_@@S=a{->Z~4zrD{vownE}_`JX6}N13t}~ zgxajHIOIe)Xg*h&{$BW>L3jl>O-fwNI`y(M;d@gS{F>`SZF$s}Ft6AVm$AQzofMn> z@dn&U-#BA(ldZkV#La5pj_wauZadKsrXFd0tu2-8&D(v+pdO&$1(ZPxZjkA~}<{?y6HBa1TE8 z!X~7&AE+MeC(nyv1sFnU% zg-WjdQ{{Oc8~p)N5z+S z!|#jYZPwk{K=A3cD-UK-hkp|=1AU{BSdDyn_F_#h%e{XG&hGCDOm|dFy=HBG`TIF& zukr_t8h4*Pj`C<9)a2)JO#t=JG-{WEZUzQpa~E3QF2%8<79HWik}0E1pToJSV<5ejMIYhdcHm>I*?| zH<0MP@P{Wf%cWUcHlQ8R2(bqc6hvYx+Pk|MAzOcWW9xZm1L8;?k=gR(a7Ur;ZlchB zKfYiQqKzWZa=D{H8;v*v&s#KM8%mI)2{bQOkn$>g;m)FYsLdOrz=Uj6W#C-L2innI zO-iS>bWHXd)TxaX&~1S#;AU7J0KZCCyN8l;{u)xh7`64|2y9}z=#Q5;6*s?m({?-+ z$McwhP=F|Zjf9|x0nV;-r9=S4*bXPSkh9Q2kn=w<;?cko^o-s!{YEw6Oh4C)f_7Kq^i4@C`rD9`sBSkzi5!9FiF4pc}U>!n0@= zkBZJnD#svgY)XnLIznVkhN)843n1mMR_2ZjN zMElXXJf=q(2q!c$uRG-7`cVHqBREaYTZycCHvO0r$^*0ll)U zr4g$v^R=`C>d!E-e;&B><^^~YTfie)KC#G_+*+AXG~D~M`n5>I3rW;kA4EumJFq)z z59-Eybf=}O@W#7Hz%`9kO%G_(WYs>=+MJQldS83dj-@!_#WZpRV#!1J6L%wSLG0RX zT-$4~v*DsXoe|?dvG=yYIR2$VKY+TxFgqn%*{59_m%2497&w0wa_VIQ zE`)R{_r=hOlMDx|jZNh03(Mn&we`0^0{(YmNcowd6z-ABM_Qlm7F>wO7xbeqvsDu8OMonr7@#2ZOsa)Yx zXYtF%!z@z7dIx+@^f|=I^jO}a<)}^CpvLt;nx*J$(AD{WBb{xe(V1~r3=B@eD$>=A zQ`}_fVdt}mnVV>A4>NvKx~%1!HqSy`)@B+V&9q#Nn4+=SvnGwl(|-$%X?Y#GJ26@i zQpbXY!{)UC+^tTy5th=!E(YaTv1r`Q0YUH4o~I1QdEZ9&1?{?BVNxgNXPc+a!INV< zkI7|sm(@zzCnlkL?~-%ZO4Q=*Ad$U^ZA9s)?|gQ_4CE?1N!*(HXu!yBYW%4_p- zO5gI>%`LYy0rXuq^dfjQO{QPAFR<<`QxfL5-raYh1h$*U14BdR@MwqgWPH~jxp+N} zZx4?LFLpAZ_V@_NXG*{8RwCYB8(xoMGpw7qVYKmx`}h0TKQR;KoqY~??kJ`ufw;Y5 z%&6-DG3%gI2IVgH5t?H)XSY150EdvUUc5R`5?@iz^7%Le2c-McwPPWu+~a=Gd%KNg zOr1xwPT9Q%`Qm{*qQ#@!V^Vza^EUHXE|!DRn76d=Qe^b%-Xl4)Mx_t)JlVI9HiZ!y zEu;O2DX7spSU|S&OhN1jSBS(JxZ}NlM&j9fh=2%&?_u=bA`%Dd^9my3+vRV~VA(bg z6>!Vp!tG7|EXuO3@vfe`@LlvU0Tr``vBxVx39Y@Rgalu(y?7Je8xB`sy5k&_-}UY7 z%O;|Q+YtgP1Qkd<8C5`RRWNDb9z=CVOi9l@s=6}2ydwo{aD=U>hKovNC{hL)2*r>u z+H^%_T-h@HnkATVv0)?IJ9X2KNPCKr09Ll^Wir9fLJ{s7M zPwm}B*{VJEWP4`6e3FERN$D{?rEAI}?oUrm`}$wp(+|v4JXOR33wXcbD=$ZfDLbh4dQ!6A^AG<058jDS zv!iy-hva*)0Qea@7y{~!H;=HZDY)dgf6f5p)6>Y^at*iMpOj_A_ji`fLd%LXY)Bmo zyBRFoU>Q0eiXlmL$45!>p^Z0Cp?njT_fFnIiz$_2c_=2IN zFmER!?U52Ic~aK4r6^@K7Emi7UkDn`x{duo>Ck3fch?M*Tjmvs-7d@VlYsgU%>YqbLX#l%+{cZfN4|Ixx*yZbihf6u{<~DQkcYbTbquEo5Rxi z53EEEc%Fb6Ww9^`Q0*0^ETG1|^~H3wfI449WiMD>tt-WQuiyIE-^hC}5RgH3N8<{I z<<*{P;uc)~<+IHD=|TcI3T)qtxu*0f*L42hKGdgNB;ZPv81t1g__m6dFh`5bUZF6diUl(w|#mJ%4(!#TY#8t|D<6Uv`B_?V9%2 zc4ToXt`;ysg%UI>;q?IS7zrtnobH-Z$P4lgV*I!%g&gw?nK*5mU3bD%w5Z6YkRdNE zXbAV?xX(Un-+bg#IU+jCzHaJb&HUr`#nzp1Dk5f8!C6fIn@b}5;nL#@k=VCyFPOse zQ0CEy?97dZI2D2RPNH7oF8tyCq4*NlOu+T~LXiF<=8INAV8~>MA&jKr}?|Aw_$IDLJRI@PtVy=d_kk!?lr6 z0u?Del!^6lx^DMBy^g0P42%7U&pQ!@xb*)PF1dpNO7r>13#aD`}TSX5p!E( z)-u~U=bJ7?m|;27LFH<0LF+)1eHv9XJrtj6rIZAH{tmvS7znOe91fJG;2Cty`T zG-60`0Tyj8-&lz^^}Zinx&`lC?L|z`&M?<%SL;Z<1AP187c75wK7k0fsgQQrfH!+4 zSGdBaB#P~icbS8GrhveP*A|yimnp<`fi-Ipu>*k^si=taZa%uZltMgZ)Z(3p*pWbt z`rwg|J5sd~2^u=?!@ss74c$l}#zBPPSfBQJMrluX-*FMM%PS-hz2F2?{Db=*`FJhb zp57#4CY>HxqB67+h=XsFyD?K<=|!hSR-;$?%})3jRyhIE1Ee0Rtf~hhlX6#=rYKv0-yU7S;)xZD*eNA~5x{p#`*iE#QndVSe&;zz%iSbg zSl^J_^`*36W9qxHjFKfHqFr;qIoarrlcK6Q=l5BSRMlNTWm@w-3DDTo)JufXxAS3~HlNTE8<_ez+R7emw=$>S&;nn_N%O1{ZJGgJ`7$ znmY@s7R2r5>BUE`&jYkx0vZ?$;d0te9Rm!TOoK#M`-Zsj+k5Yzb^(~37&qb2S;7tH8232FFt0o!t%Ze9kVc-+1CQ#K!7g6C>89WlFbt?n~z|9pjxUR0uUt!wpz_g$X~v^Fx2L2*8FC+4ai=p#@v_ z>CY@0++8#>SYvU6)t+bS9JurGCug7qfKSAXgzCePeFp3hD=OS+Rf+q-^99|Rr*@fu z3P%9OM2&L+LiEQ;$Wf>6Ibu4>QGNjtg49D|fG{L~i-vq*cXAZv)6jKM^Z88xw_L*Y zz~-N@K-$`R*?e5jfPlwtU1dRETsmHL_Y4)i>9WcHF2U$c6(TCQhDSKZ9BnjWjL~IZ z?Zh!wl4ynxqLM?BFgM(nvhDhC*ScY7+f^l^hJxHxLwAIf96GA#vmt1|78J3-z0Ayh z?N8KzvcSz4sdYSW)tX7Tj(1DAt}|W|+N~#F?6(;0fO?B)iL&xwEvOGcHQ{Q61m}5d z`itvO(hkX(@`lvrJe17)<%XX|q0Cz?AVRW9D+!C0bI3kaZDi_I|H4~ZFu%dDhz#cZ zEKf#xxdE=4u5hUgx&4|}EWr%95eM9~k)V5P25R?ot$lw6?w+UvKAhbkIrzB4RCm`> z`k2z=Ze~#e`#9iMv&S>T7Y@cFHL*xE$SI6;MhYnbXXXzt0_c;lRR!b6a1+roNOZ?W=>*RGW7r-fdqqae^?q!_Z+&+yqV=cHJRjTc`+BcHv{xxK zcl(>5k`LZ)vjEXvqtHCxZ=Fx7Sc7Q)mC^FNU$?{Cb(xN6uTyBAuiL>tzA+xr-k{Jt zU$^sqxq1eoy-A^YzHUR`zH1z!y+xsU&L>wE-n$&p-lotz=aX5X{!bKMJ?(l(tnzXwEk7hfhzVt^(NXvgJ z8`cCcKNK+g`l6CrNPA|9)vSGQ!QZ%=A2Gb19Xl2DgwUlONo4bV+-p#2fJ)Z5~{M8mUigsBMe#jY>!{0H*8_e-J`~L|po76Zh`Y`T~|& z{8Kw_aXU*-4?$2W-J(*q``>>ydotSYe{DE*HGH8&g_uXOnVZizT%KW%oW8EBfja|2^(?5{}XVleZ9eqHW35clN#9JKF-8Oo7PCZR>dEK z@of55M8-EjFJ6d<(FQ(#i$&D@PQWA*rs$86IGYAMHJ_bL--~$6HqCvO2}(cv!nNH- zqki@W1tu`hh|iUliL%uie0J}Jcq;xVAX|x@2sZ~^uF-;+34rZU)A7|#XpS`vO&&=O5^?>StK93{r7@u_f=^y0d ze+WHbi5O)<)5fG;q0jBvWH`P;|0!Yy<6tIP@AL?zk4>B*ALLy;6;I5+1nm7UBb@il zo^dE63>1*}w~UZ`-zt{9ZjgYx|7C>leP_-^+8Qh(??)No%RtRuj4d!kz}#OlLf4;O zVKHroig;eh2!y0P;-n9!BG(wEzy$k7mhVgw6|{E|^$K>)&Ho*bxAx&e58|jMATD*f z+?uj+H+04 z{_T!^v;klLMhWPZzUpds@8wi%j>zEuY{C6AT0{$kF$tFa(AORvMM>*EUd#5+7y-}B z_vJw*L}LHE^Wd5(sEHXXU^41u?AUNUR?2d;c~&2mcVV0}ZXym2koHN|-8q#1-{g+# zx1m+?cpGl#9!7qt>ERjS%*^yxm3WuG^!3K`QI?zFgy`-Cfv|a)aYdt*IL5zuM1RDS z4A#_YepT9YBA(|HdBpMniZEpX5Y+<)Qk1LJB)CzT(Pa*vs*`wJ#^?#-TmAJUFb{g{ zSLXjdna5;?4Yp^SeH9cbo>>ywlefwlaCK>m(h{zC?)^o` ztL9Lc5Nkflhnx3goGtrYGatt}*M`{z68&H(L{DT>;`CYk(6|M-hvqR%oVm7smX!A9 zKz*RRC;^n*GZ@az0eyyjiuK1!oVAY)7(Wls+W9u@8c5^OHO8Va3Xs~XO1vmFe(HMW zDZD^H?8Z{HTDb1UNxbQ-ez9&0>L(Y9s1S15sFYKiIP zM zzx(Sx&+N?3&d$!xN}VAfAJ}osqHPp89p#8UZSKKJQv6}DNB>uWx8@M@}yIId<=5Bo^Id5$OzdHETAcC!8^CyHoJ zWlIqj9^4^ZX{PL;u2Y`K4xyTo0da2t=H~q`PS2$(>ns&nxf>Ny*fgkXV&it*L)C+8 z3H8tKT>S+;KCS1asA0l(3w&(jdHpxg89XWIrlDZxgZyCZ*r~8lnXdpM0DR?Iz16~j}jdvc(sBGbJ6axZ`u#+ z#Q2<=TPWupE+??)2&1};K~I%gMY*i=YHm+EU3hEfcH0KuVat0b5GO^osmJttK}A=f z!A?81Q0BxH9%s}cA+7nEtN=yci&|pWsDa8l!?_3H@dXlwK0M|yMS_=#cocZHSMm^n z?2Y2cq^Ka}qDz;aa=ss(9d2!$yO+)mbM@>{YOICPqEe%I+vnU@88mM%Ysq1(GOk1{ zX~O-3(}{Sci0Jj&q6ZWzRvRXXTM~#MJoz7;qX;68Bl@CVDNhV&`DKT1qU_SuJG4Nh zP%A<4yfF?c6SFxZ=*>L06c^P0{qMUf>&S+#`Qd6^qNoj_JVeyP8&A>9x$c)NIdi~h z$BkQ*Nuzy3%f1~o`BW_FEl`eY`s^38X!Xh0a=S)HD=kmy*qMxs}R9wP{&G{i*bj(?q?gr!ql9yL1okEJa1})7q1doTT{a zmX^whYM7`EBR_aFZOaYvN_X8$FUHb8vRTVm?Ybz%t!kk7n1X1u_ta;PQZ!l$5oNs~ z;B5>p#iHN40Z)4U2ASuPkIc!U4AMP-7fM~zwGU`oGNxgvlh)Cg-m7IsQnk0Nj3^d- zqV%zR@;>)zdEJ#fpoc1cLhSaKDCIa;Z9JmZiahRr@1|cPk9)r#uC&ZxovE@VIiJ>< z(tg-l=O-#Ps&o6GdZ&|=M|wa@_Qk+HPtOS~Oa&e{^4;Dm$oD@>TK4*fCl~=a+gS zgI3Y9CQL4ICOo=mWqCZY$68uh9@cPuVZM}%!0&$j^JD*!Pbvpkva+FlQ`yId<_9Re z@_-k}wb~J$AHdH~`|Uy+`S}V4JZ?$~>km~NKJ)6QTPfH2hyhbOA%&#`USM3W#60o> zj{;&>)}38iPB15fK5u@K=Hz3BR7pvJ=XtW+raX#-DgtIiiJWgaU#Ps9qcydR;tOjVE`!jF?@6Bc-Ah;4z-~d=m2*wKPnYgaikt!Zrj} z))`L?X0P?sHY9RGE3QxA|KG|ywu$_I9Yd-|J+$IXFk32rcX>O_mZvn#&h!RHxJ`L> z(XQNLm6a7`mz)0)$a-c!t>K0#_bHX$H%=q86}sJV_4yo%n(AuFR7Gyp$q=yN(F^;W zr&aG64b?I^!Jc?Vo9Sr*3bCG+=&R%4f_&j|1$&C0g6}#`dx~cfPd0J^b9B(D8Z7Hr zAMwJKC(Ed_zubHQdK}kt;wjQ&0}a)eJ=eQ=;c*3W=H@(eo$U2FL!#{bL>*F>)xN>9 zs|^jQoTC@^MyNWy%Z_^vQFZ$B8fqkK5vnCHM@^Q`V%=mKA)3b3is}*NJ5j9Qeo(FHUg9>^a1~eA!Jbf({^#(R`}PDV+$KDiN&`8Q z6_pdkU%y3d-A(aVQ^f0`979O?0u*O=Jw3XBPQRNO5sik|66+n>aS-bS^CF^4Sue_p zRjt0Cy-CnqOEXI<3rmT1Q5D}Fu!VL}EzG&vX(LQV_SA4^ZVuT~OAT37+#qF7D3_em zCtxq_Q(GAk+l7Z~4}FB^4T$Kgl`gxRBKp=wRL;>0Gr^kHX?WcWw5Gje#FRhf2Wxk! z`90HV?QR387UWq$L|>*tUN%MaFB=jy6II-9!Pq|b=DEu>wyyvtJdhBkqFsO6A*)kq z*Z-=PsydK}^ePvj<9*|-ovxx5)g0_&UM#=lJl$e!>xW+$;%h%Zcmz;I{L`~HU7>l@ zPW=VSd7HAEak01WN?^^KJT-q6`KZ7mCcSGOXmh(Ac6X?+30{QYu(LTnF- z+F=#dD>@aaHTSD+bSe_0<+Z1t)N0{GS?IQ6#s5CvMLU>az~YoAZZTlTv}y4RtBDt) zzmxRWXkfQFKJn>itiKH;q>Bj+j`Of|RZf0kY2QP?x=x8;Z%Y zYZ~xC3p`(3qfE+cm>6kKRPrfaxg9CWq^zwud>fs8cQWV7Y8OcSN|^%Iqp7nw*&;0? z*|Sf z0I|dUusKt+guS@N#QntX=7-IxT9}PauNOy6I2fR?BQRS^$LOBhl~dpCrKmB|fG4Y4 z#H@dy<0WEtH(<)@6fwud9bp|Qdl)dKbqS*5-j1Ky%RfD}%n;?ig++b}N&45e`wr9S z_R>==Sr^c5^4~{WouS=iZ(}B>RN)mL?07uwbJtK#pYP`S%XIwSyx6H;k!rJ_4-0JrnkCq-f(!6Q;DE0NjZY$M+JquL+kkD{&tTxUKs1 zIYQiiCR|Rn!d$ffSn|r-`)L2sU(c1(DcBGEI{c>{v>$j2u%vYfc&G9fWf0E>c+xsV zyr8`E#ESwvS=}M8Tdw_5wx&gEd3Un14()bT*j`Z9uvA3A8rqS^sF)6~Qfp#O6#(#g zt$S`+Lq5-LMAVgvTjBGTztm?f`Mg*oDrZ2#Ot7|GdGpvRT1DfGn6ml=qr2tYy;(H6 z12oJoiaKKqlqxJKpw?}jw~eTdA}YJ?)h;H6ZW*&GDXp+pP~WWj=2@Z+_YM+uy@B(R!JnBNrBRICO^z;{FfB*Uf|O*+SW87sriYjlqKxY*Ee< zxMOjwXQh17Ya&ODRPG)rL#;L=aVbG|Y2nbmsdSR?Hs(qCK9uRGpZFK+PxW1RwOpegRcW=0G@68Y+!Ph{ zdnh`2dgpsrXf;c|Lu_wzI>{^85@I?l4}WPLyzr=^tkur98|6^e>YXCy0DJTx)k+rW zwRw{?hf<=lqRi17%P-_n_9n#-SJsjcyVapTPZN8vAGT}+iYf&9S9&F#cEdxoY(9L@ z54yOvK@`y=u=6=OlY6%~bZ+QHwT@Qy&mF(+p_To;BEC~8SM%nNbvV>2++!A*H_4T8w%T;<1a(mMJnA|~-jQ5jLqU{<$fSyVGP z91t}vZN%jR7P{~0Nz7tC)6#2o}});dic8Ioh`J#{X$D)t1))mqB5dAVD%O+#0X7@1odx zoR%C;t@7zkpR;iDuUmA4bOWAz-WSEG$G`hJk0QD6)Kq1w&ssaG zMHIFpIHtpYUm2j#W+0lR{h&<7z9#bzP$uJh4KLhjOR#H#aAEy{9mb2LT&yZ|CSY+P zxbRpa*{am`9wyml>3NzETv#@c!x-_jH-mB*vx`_%$lEm5=XjdNM)r{F)eGi>J?hzW zG#};|F_Sr{_^1NvpH)t8s-{rqa?}B`dql9WITNyM4QcQPo|UYHiE0o<_LrOgzMnkl zJT0qPY!_DQZkZ<0+O>M!kju1o{pgQfA{u?`*2`B&qw_g>Noe%xxk)QXqYHSJq()KH zwZ7_s!!$pB;#f&hzDe1HpOnJ$168LjNh+60d-0zQsk{F`|}8SMo};TCiyDHzTTiS8}j=9XxgAILZ3EmKtXB z3@WVNqpO*ZV_H)f_bldjepyHQqRoPByy~uw-RJ`GW9rtyomI4Dh6* zI-tQXmcLa%tJR-cUU<_a%}`pRw|$*Qt)|uLFFi|>>JrskGa%R5LoXa6x&G!@%}PM7 ze_w00k>vVE&ytc0ohRN~&?t*eYL;^>cy&-%YsicCnB0JQ(SIS43J^jA<=!7awbD=J zI#$pQ;D3;stZUjUYBOl=WjU&^r@6jD%T&@>-KiW&Zg&c@4X>{FDUUK|D>09AFQO76 z&)FxW$yTz|Ra&A>JW&=J&4s1D%%ss=4OpCL;&uuuzxy-_XI-sR0q;&JZ>(lQ3Ug7# z)#X?IJVu%AHRfF9rn=gIghv=iyt8jxR=c;>j9db_{DzOc#w1>6&XtuItj7P=fBXd5 z)OtYXaKgGp-uAU8KF%d?yFtZ^k5c*txkD3_SH!g2W^p3$2`^s!ZX@}GjXGji_HdaN zDQra`E3j?SOWCyR*rX#C%^FE6u-$(?I?wKhY&M~Cn^^Jj1=5y#zcuT_yv3NymHP{i zF_89pqkC9al&vOIS!q!g=FfJ04^S3nn~tlLlEvAJ6wJY`kU3ym`TbN`yj{({U9%Wz zkE4oakJhj((eS-1d*38`-l66uI-IPK8kS57OA9@keh`67<7w-ApHXx<7hTX*%#*iQgVNNZnHQn$T~b z^6Ca(T=(D$?k;G5lD^=-Vtj#40hWA0(9+I(=?nH1;|p|35dH#`1I}wOrm7;WaZ!-ovI;S$Wavexqtr*~=rDretksV1-3bxN?a}e8iM1n`J|F zSH0hKX3C`0^+|tZS*bwbG^H$tn`4NQz4SQoRO>I zCwT1cWThQovOU7)QSSH_rFOIqSJ>wP{=bh-IZpClE)HKdn+DGIJ|2I#fKHvSsQJk* zXA*To3~@LW@wM9_abF8w>m2_=sY_IonrB9p)HXVQ%i0#p-W$Ja%$1$tK-!)4+-W53 zH8ZNLv|zu#cgNq`C~J5faf^&vE=~sb6W&PnX3#0l4Rfxf#Ar9<82t)+1vcNDtU0(6 zp2Z+y3p#poFGXwxez=^-!gC3Ao$#)FgS{ql)08b&fq>5Hj=VdJy)%5voXd$UJlbGB z^;ue$&8NHWyZuJ1QuBP#~C8}MXLeNnci@AYy=Xb1lQ$GkINt%)(f zsZM^*j_b6Oeb66SQnN_v>lNL5Na`}?Y}r@?Nc~P^467A?$RAl!YIJ+;r?<=Ort|i) z8aCUqD>IjG&>%d6K=fL3Z>{|ly*_M6dQFnkqpA2H_Y(lDZFMNsYawoDd$Qf>(Oq7)Vx0T0Y_Xo? zt&O-v-a=|mi?SA_+#jx>+*BQNuIwxVmKFPAkF_N6Q)Xn@9RbM3eLCgsl_c@g=G+pH zcunA?gCucXGqR+YL^`g~+nGudKV#07lo*jGRrxTD$n{j@WV>70<0{YVdIy9ic)YfR zXgk-mN_akj2(HcHXID^l^|P2P>7P+uz@k0l&eQ(7zLuywIp!LqRKr>)Em(W&{I9_| zT6-H9u_fh2>(P=wB5u)o^qiKdl>UafVv?Nf`6w+`RIg}P(D&{I$0;&zXhLPlA}v~Y zZ9oy^4?B`rzUcWPw(^{u*WS+UwhfN7dxKNt-uFZ|T@GaZ%KFte;+Vc(VVWkX;xdBR zad*p8r%0IRIBJlR!;C=8z_U&n4_wCWobkeWuldSciFB5w9+@>n7$t4 zU84rtqrDzUpNQto{-ivXTW!j5!|m?aZb^3c;1aoi_Q{gJkJ9ayW<1sR7Pnkn0d}!@ zZ9B6Ue_zBr-|))T3IXoT=q;?LQFF|_{U*1RHKBRhIy3tMjc*H%OB!|9H8}Bk3icrP zec9?b?Lk^{JoPK!l2i~oO={BWe1Jl2#Ze1i$JPKv=O}s|J8(~z+$R-YYo4dPSZ$Yk zdl5vWA2j&m9K~lZK^in!VO=6m^jui^>*R^rKyJ8ihL(UQx|Eb~m3;lnW?ZSWVRXu~ z>3@Hv2Po86c&gI%+b+4bpcr)Yh-Nn^27Q(1DSfX(+^+ccw5!uSfFNwWV73g~S}lVl zZOf4h`?*QY79{CsDNnHe{Ox!i|3bDD8Li)2@2P*8*6%=$?Cajb;v>tMD*~T5Ma=d^ z%p}@Y6uvDHlPo)9z)8pd294N9%plB+m1Ux{vxDXAIdpawtYW&|ip7T8oOZ9*9%l2p z9Vy&WD(;uSEsaHg&D~Dq5K}UjbP^^v1LM50?3$da3c14_GM$#u;;jx;gy$%Tch4^$ zypeoh$0CwFDk&~Zxd5i@Wau@7C|mR(87k80{Ih*7)5wOJQf1$yMPx@_$a*5bW=@U> zREsREQ&c^X7#f;K5lbgbwxCNNT3a{Ps(+K#*3M>BZt@7*6^JD=U$mX2SRxE^eQ(gn z>KA$9>=hN6hw1{kO2WnN)@)L(kTv%X0_VG)FWbWydHFRrdmN^j@`j##`;AA9>558= zPUKGZ=*PVLnqzsf7#cuBClrKaLv~9^4_^ZI5w8 zD-XL#`$6P?pIkETEcxI5Jej?ISaO-k3rpIw)AYAEE~`CJ&M_PbakBmi%-XEwmrn&K z(%Jyk!-WmPb_`C2#@C*jPbWiB9M7Ws4v=u+)uG$TlA?KHw9?kXqueVgOcKg@D3q04 z>-sH?R<{_AOvh1Ns>PDI`eC^l=V`9md7hHn4s#_qXvT0V73YFA?(gS6yFqJQEZ~-0 zPQ7kK5{n(;cxnmd)Z6vhc$oac0L-%{w++_v?W5*r(CMNBb3L3>5Z5S(lRlp~a~svp z4m4m|KUapg+q#?P${>ztNd_N8_K&^zFMGY%iFxubCWBG^qSbmmZ|TVZMP4_@wd5oSXf@+XKD(Fc;d!@T&fqt~;$8@xCjK*J!45iq^72&q z^CvK-gI^5YO=FtG(=0d{L3xZO_3E-$uakM6?28~E>Kfao?s|&4-T^FKL7lknz^Zl6 zfGg)|)k@)rw@+WV$tcW3dxocuuDC^!-e8_-=?M&~KKkgcldM0-5Wi%}l@qLFZNL7S zoy5G$v8_7&L3{7#3R+*Gz4v=2ObhG^>_-nadh0O7xI<0IoWm8jE#Qk>A(b;|g?ZnE zE1i`C^3Hu~>QR#S1IYE|IArG%Iww9F_t4q^h5Mn3t2}TS=t@e6;hnt|E86jDKVBf- zM~Ej|p$JyA>rb^{z5GAc@*->ralY(sEY~8Z%=h{UFFC_j+{x5!yiv2UO00gr!99UDc{x zHkIDH`V8MA;#sCISXv{ff*7JjLrIh;x~6q1w>tt=do zQnL_sH~rN0Jl~1 zFPRftc+}BZOl#K=b}Q=}6S^!HjrT8=x}Tx(9&f;9L#+$Dg~uE0jh9Y7lTYLcrerF_ zw_4Lj`ZT{mnx5#FESm>Kl~99vN8O}KsBd|?rh$#<2&45jJEG`4iF5!r2f$5-Vltyz#?3EFc$jZXW&2RtOC zs5d~>dY48zc2gF8CS(>~+mjkuw7%?K00?x!mtqqNSz3!_I(&+zS z_6?F;6h}>3l(3I{^*l4Kc0m&NAmCJN)W!GqP!{G#4cDqVH?#&``ea)ct%36aQBx`; zE+4R|P0!uj5TMW&AQ~4YiP{g!O;mgE$U5Tv1bN-%UdICR#jcHF^8Ji>C19ty?r-zR zP8TAcMY}t+(luW`cLl9Yx$lbpY5c!iaUo^~-Y^e~Go7wB`$gpnr# z6z(F()dEHB6-7=%Q{paAl=z>9-5tffFhaSjk#I}A?yLsine85-UeFH{yw6EEjSTC3MH7kqzJ(Aym_OmyuZof+Nbd~ux$dZ9=+?~@gjj|)F z&B@wjUf3#8WyaBt>)8#%R1I0VP&uHx@^riB_A($zMj5b1Gp1al4A>e>mL#I8o7knN z^JxuOt0A%@eAB>2*#Cevpv<1pd&sud`C)5=8&NVkXZotvkTZ17wBC>`x1&T6^Q(U? zJx&qx24f};s>E#?M9f=O^}0o`Qfw>^U2-;~$g1xP8@EtowaJ(-O9ejU$c!=vY4^8T zLoKYIlblUxhcM04hING7qUG_mbLx;;T)SW298XEKWB9{To|ixkamFD9QG0`buYR(AN_L%V3D+F||;lJY*2wy9J1so@jVIgQD17#i3hb0Vu=cOs~0(=J;;SSM(gjx|Bo>aN-(NLF&NYsnv&zLRz>d(GJvNslTJmtC26jdI`r6@5WWoIS*8 ziwjZi(A&6&??ttZZp&UtzjrmApY78T!(EO9$)Ze@|2g|i!#v9W>^EX|c6hv@ zfpRrKpsF;i${f}gETf3)%di!Ssw>VA_GKs{>^^y6CPjn?jHucmRG5k8@S#!7cGDa_ zSj0>yR&kjy9mOgS&wcy=Wt|Qg)A`~uVJ_NTZCrNjEUlJ@Ij(7OnJ^j6+sCSXeu3s~ zCP&7{55jW@)L1Rwwl8%4lse)V2R%w@bNXUt^#(=Q z`-1yM@Ahc9ha#A>rc~|F3Uk4X{4;IjCGxxH{BSj`mV|8;jq~prpPZ&~KCdP#ReN!C zLJ6C>h{}u3C&$;!+C}G+7u3|Q>edj0wSz1!EARj}Ud_y%?Y?KN`Ic2*6qu5=ZdFublxe83>C1G=G~85keW$GDK|%)>m9;t8AADA}$FW8V_kNCBsMbJ7g3UcR(v{?nwoA*6yu;M@Q~o3GP#W{) zWdS7G#oPYp`E1RG8|LM=d-uF z?sNxt=q8i6%pfLP^3Ss?DJ%Gpo`3rduM)AW%1I^?+cnwlb}K8OLza*BYf;ytvT46o zUd?ygqP=v@%9WsO6=fqDl-n5mUD6fGZB)2JWt~(bxmG>mRt(O=|5)Gba)82mM9dx731_6jxN_h)k36BMZEL;P62QXrJ*oB5H?JTtX0w7R1JFq-dfN$1Cij zAYb1NnBPpT%lbS$!7&T#R3dwHk;@dJ2xeucDeR5j%0*12lji^>98I*x6kg+@J}xp* zFgo)(`^%KIbRts44_9YQ!rDb|uRXi9GJBD^svo+n|3i|0U-r?RBzZN&Ry~f)YVXv; zE-pD(b2=V7bCA}Y>cydR;tP975Leg>0(MYbQA5iQccj>z^fCsMT6R8z+XM~X__%<4 zLrW`u5Q5mI#woXW*ivjPex=+jm||v2uVpTXvkm z%22t(jB~Uy)G8vo;@Z1h%B68DY9fGUD-B(mO`5H(BNpy9rREUY{d~9m+zyIS>lhIw z=MD1Hvo2R=XBbZzF)gUVK+)P;$NHvIwDz=)t100V_D!gdP=1+~hpCTHT|G;3L{T2b zbu^frdp)D4$#o6`(aT47MX#gir5<2$q6v>A(pp1@Gmo_Ptd1wyO$+Rv#`k&bIBBiE zp2dkK>e-Oi-s?Ctld@+G^fb%07Semr71G*sfW?U>t~IbWemwab)&;GhjyFKoQv<#A z=rSjr^!B`-#mJ*gXdnvH3#;Y z6R%ZYTS?(HR`WEi-Gs*wtaJ-jZrS^ULTRF*Xv|(%8kEC5+Wn1nl*4UW#3?*FZtrrs z+{!a;%1fX&CpQH|B}8#~CFiY!^d@pMbFzHA27L5885NIG%=98)D_IzNLye@DoQY^{ zU%KRemVaulBX@Sh4e%<9MjNHi0$Y565HE-$e7SOfCKGRM-1 z+{TPtB3jCC22GeQ~4`QY|JeY?GC%~ z>T%L;mBDl#6zh?>Mrq z(T=jKmfOeW(mj?ctXH%LyLGbRMT%g;wY;dL*jT$eNNLjOJDZW+6@Xplr8W;E|4!A3bR7orWo4c$vzmNa zPxK9U&~i6BP}X6Ds3(JehGZ)WXLF7TEWa*Ix ztH_F}-Pn%bX+oA=JyDdr>Ve)jDN2qv;YyD*h*a+xI=FzMyNDsP=&o(3*cKGuQYwzOA0&5 zgsoad+0SH${hh8oBjl_QMC%<#KC_vk^<;nF0zN=g59pRcy)WNqw-nw{@$GhB9kwqC z)=sh~54vr=HD&Bdx^11Jq9%E~N%5KjDpC2+eceX=mt3OCn87-d?5c(23Tx9WhvXW< z)1<0Zklq^n^)`FG{M|dG4)z3gB_Yh_9%M-+4zSj0TYtVm^JbChE5XnmmPN%}k#*VLSQ zb3Mg1A8Kfto)sS1nT~GH94~im8`Teg#Bt;8zQmKpY{c~lPFjCEAIk1le{4jQT+L9% zq1UOt=je2Im=Tk6Hp24*tYVWIY`j4l{Y1?S3lHuP?zYD`qLsrM4}U}?Jif?o8$UXG zCwbIQ)m*w+;gQbe04Wo8q@|LS!__oR*As`GyV@--CGd1(rg_ejr~6FJ4Yzp*a4=y_ z0*l?&YD_j+&j<~xsK*LFu)<7G?Qv=D^K9M!T*Gv`;@r0Qa7UtDX)$4!oSUGM^TESU z9t}_=9SNu&&Z!Ga33eCWm+P|{<1Y|T(#xXy>C#X1zD8E_rJ6@wWE3M+hmOLsfe8Bh zUNx?gXB`Dt@||SRioCJ^J~o$Siz)R^6%)(c`oSZ`yI%5op(sBao-oI}gBkEW~Dz{t-k1kp_PL_IN1Fak5)KuSz zh+8u`glR~Z>6yQ?-W=a(X!dwp;sBR&(VZJs;rR%B&89ClZy{?PuOSYOk8(MAoVbL* zmv-NF{91s*o1o?uo^J3!VfnyH{Mx`->u4pOsNwOwf#fuaa*(O#7UfZf=v#BHq&G*g z>zT(sJWn2WlA5f#VJIgn$}cBm_t;7K<;g}w>759QUf}5{FdHuVIGdO=449k=36CqPEUEYE_G6So{9ezbGcd&$`o>pU zUf>O9?5def-f*UlUFd@KsuhSMKFRrIrl3C_lPGr#;i{7BPR@%LbGL^GcWN*7@ zuOr#s&g+VIM7MV(QIm9EI>@29I3>zQ-uSiqKg=a>JO}Z;Zby`Q8VQdz@{4<$)=wqB zIM;|Mxnn`A-AnC$%AnQm2R&2i45Yl1?Nv5rwA+@F7U{RyrkvBH-+5-_9tnODG5C_!1x|x1o>_36V*mMidZEnf0T-1Qtwo#aWw8$Y3k->z zc?sJz@|k~K?wvzE^Cv@UpwksSh*z*U8$`(cKACZfZ2M<(wpO{qWE5AWmbYD}xN4yx znHSg!4KJ(K>Jmj8zZgZwXY{J~1=P;IDeg{0oda=9ewA`O$; zq5DpflsYfTQzSHl+Ejhu1W^|oP#yAAu<|eYt!)~u{7W=cuh$kmz#iihmrrGh+c41U z`c-3ZkzRj8+`{Np%142yZr_0>1r*i&&M}qM_I4Gc8YwO($h=OhmVSZe>L12T&M^vG zFwko4#9rq~t4r0?K$pvDwc;hVjrd4Wcd#58Y+-Xa&Yf3f5d0<@Ut$cnDjq7U6lhq`Ua9`O>){8$C5;a8| z;t~Shm1XTu(ul6n@Tl=ccY2aaZ8qXOFrqJ4zK`|aUW<9MSptxsxEk>k>kY6D6Ys1s zu^Ja7I!93FzvUqdc2VcQ^?u2m*uo=?=shdEkV^Coe(6eLQ%cY1hEaaKFWLLi8~xC= z+YKv5JuT%K)@gE+Uvf!|`m;$luhXb+_Dh!?b#%tGIV5Zs`Kv9M&LM?I8>|ENcMr3^ z)mybhRsUPn1e1&`P~Ys7_a0qIeY3au=R0I086IpGrVcNBxq4}dTq=>N5@YcA6G??im1rFER$P<&x8hccpzUivPN_Mp2se!MLq zrlWF^(atq+vO?x(7yYt=WZum&6P06Jk3EJ}=PEgO_BO1nk3p4li?^@ZLOa7W%)gDc z+^2Us@eaE+y2qT$1%ARK4)!iN?W(2H-X-0TOwHoifXhh@vK*!Q3{Ryj@LvCHPT9he z1NxGK%kqf+pDF!zi+;86qI8s{%#5kAmUc7ywDg2zms3gmyAnbiPUU<>hKlyctuL?7 zqO9zGQz|#u!rlbsqBp+t@piJa3BX1iWOt+4c1Rn*h>km2 zzqXD#c!1WgOf@}7DMgM8Qx+3t`Rwe9Q=6JF6J!>nr_H@e>&FojW=T}et{mO<1aXg= zab>IaK#X*1^PH>X#g1vYUYoOW64W%rSfYpAXyWmj#Gz7?i|u7lqP zby`PVUQg($T=G_!2G-?K=U%=AQXTh}Hopw2O$wIYwdM z1oF7egZiDIJnkjL(@qvk8ycOWd68#GjdswdJ(aH04*Hfk znHO4k4kM{^I^M<3xb7-_`&C=z3D(>1zu%Txr)Vprj(zuq6(n^jbF#G5sFz-uryZ-Q zm)_kR`}R%VcB}-7Cib1cQ8Ihc0^|>Fu77oFOXVx>5%~&9&xXEZP|e?R={xQf`3}hw zY*aP-M)ak1luxM*STf+{!gON3m$H5PP@lVGYgU@v^(xQc*D&*U&fnU!@#VIY{FslJIDv^M|%Q8eOLIhw_l9@?UCE z#mQjLv1FT*b%3hikIacJs#PTQ#LbI$lhluxvt|7zkow?&Z(G|Ccub?V{$92T+x39~p%(`Q^ z+OVzQKhm<&I^tI<2H%k^$452IOW#|POWBbpH2j2EmvXuy?T>-a8r5>vS@KzxwLGsq z&hBpBOgi5L@;@<6yX26BRUlC^hX+>s(Zdh#qjRgOm?wWL82E|Mu#77-Z>nLYtakv} zf=<=@UZ-q9bwIQ#SBdO3r`PLDn>7Ge+Iqmqo`0t6b{g3yF;8}6LDnh${qM6V>r@jE zsR~_@QtJlAJukRDGUlF8b|*N%fGW#Gb(pngeSL*00&DS1xAIavU0t+!eLW}m0|jx3 zfd#vl)hHkfu5C=Gnt!#!7v}=~K67uwb)?@qCR{lxieVh>$Fg_kp3+j2ZOZ$F3EslX zGko$#TwXBFWs)ZDqj7#3l0)clLz;^u&TLTm0!3|gAvaXH{;VuH(qzC{>1 z88w+@P*XID6^S+xEsTa?+GI=e?Y?d+a4q+6t4AbE{8 z%X3Kb`i5+)bd0jrCu_x?p}lkiHJx>IvngG<>`LudY%-tP6V^A_!(VlKR}%L*L#{)b zi|XB~9_+r7Dn%OVxVJml$x4f;^?JW@nyAn7)NViG|%NlZF)1=^pWcgEhL@_C~KFs?sz&MmkQXW4T@$ZNpD$fQHz>IPSGHIU_V$N2U zeQw}|y)}ww->f$LEXA`OOzHA746!pt99Tu{j;3sRxzS0+`JSJyrMzLNj_rHyNp3|( z_a*GXafc}H{F)(AyIm2sYhYWwS{!0~@J?zbwPz}PCh?AGOJ~xMeoGJUbc6KU*)LtQ zMHIJdkmdjS;a5*kMMIc>HaD$=#~t{y>R(P=N&c*hKRRezBFqO7Zk_cx=P3)()rb#T zmk4vg&it+s(JbE-?uW|_xv<93-O`yCJ8q{uW;X*iXeT1fMHOsAJN$5y>h>bcxtz$N zqul~nS;VES1+5iwq>ii<&=tFsO!P}yg6KQ@^x2G;l`rWo{3YD52x|nrY}hUAkrVW? zVGpyfx#RkD#azPQfFi2Hziwx55%nzAH^}XW&=?FVcsqy2pjR>Z(s}^ip!Agg&aoGR zb>9%~dmMpkw2LB3eRw6T3G_bL^!tB4O7DZcUd*r12U?;t1l`dY`{spJbVsL8@xDU0 zk+R|&TAqEBy`23<@xDP9^of20@|JZTnR|-7<(o#|;JXCJnWHEfvrG z<6MNWK9MCoxat({E|ld)PW{sMXllCorBc_ZHd$YQ@&vp zyMxTxl2W7k(ckAe){u^!fb4ba%t}~Vv`1V2Ph-{@HeSPwj&>%|eQu#p86Cj3G-Olx-FD1pZopn(?m@)qDqf3 zvZuTyTX&E>y{)IlQ%@`DlW8z>$6Q>vo2pgadZx=QPXu|Tzh}OCkg|9lo)~2F3}{DP zy5+KX=(UCqc0GB5r1bL4&h~^j?*J`Oe4c{L!qLGM(rIl?;)!8)rNkmS!j=$c*J6cd z3&_Inp1E{4VFz~l{~@_o~ZP$vBdWQ=JiIk4ifWS%;X1Fc($O(CHkX& ztdj9P4O6KwD}2QzR4LcjwZ0H118=mp-s`!Ps zSC0KOi|Fs0(@A_;I+#V5uNANi+Xv?K!VP9vkUDe|mL9AUmgv1{ z>AELr##K$kwWA}dYI1DMryvmcYtWwO(GDlG_1CJ1H~&}0IqV!hBG)(kB;_DKOb4c>WseB z5Z$imb}=#3AlHI^WkAlw@9klIl#JH-!@7}r`T*f;Iq;jm8Hw=EfGCu;xoI5KEW@YPd$lx7PJ!@_RTjdDKeZ0=!Rko zTRS4(b^p7^i2SV?nHO1{3}V9r>sM`{*l-deI}+{6`HRvv)q*(=_COU!q-~^3!ekS+ zc8Xh}<>+}g*3ei_0o2>q6m)Io#K#(}mG-PxQmIaJstFl2eiN1&#DeR${&1Wkv1!F% z%S(@H2uA+6bOoK{PA~2kNXAI$UfrudtvyPa^zTf*LH7Me#GTiz-Erd1FyZpkTU6`l zyzk*2A0DO|_Pq&LZibaXtnx1)T9?Qu1-mmr@%JU`0qGOA^!h-ulwvku((VVO)FBawk zolYKdiM=^6-;~RWd)1pa;dzQ8o#ok!PSfhUzzzEc<707S4{-f40`Jfj3Y^?>L9vnAz z7p<*J45`vu1=PMD$Fcs%zZp<1@K0d%xvSy(TWB@--HfVJuBc6+)nI4fnj^Ft{9#7s z23nMh{Nly0Z)_vKxYUrVnLffZ7RkD1^Oy@H>oQ}e^cbUfc+-}a>^AeCCS2_V5*}f& z&%HkSo@*3^|7A>-)GO)}lQetv7U~o8w~ne^=!7K%5k>kBWAZ6V{0FdfiWIgW)Tt}` zY^^-%bg&!|wJNlP_suhnS)c!Z0gqFjFt0gS(=z^iXEo&t{-@>@qv%>xn%I@b^C?OL9xx`MpZDmCBNE6jZ-52)PtPzT4t;|^v~ z+OdVlDHpfe4_A830eepQ)mw?3>W3{o-XLQAX0~T5MXYN~*-D9{dcZB2WrL>aAthX&<;r%TH9gc`475$-m}^ z#(MwBM|RU#Z#H2{%L?rJbkkB-X*ae-!yRB#o`eMl38L1FGB_>&oxomi+NvjpyY0~q zs?H8!4IkAGM3jtbTYGf+;5x-U+w|l}*6&CSw8WCWy87@ovZU=sL@p&KDkXZsDLePR z0(!w|hn^`rSHWEQdH!hj?(0sTrsQxVY+m1Mv*9+U-RqUC;%x!e{&UGs?Q5dQy32s> z3j=PS((nbDqN9!G?I`PhzA`i5tyC)s}*`rw3U$vKN&U8}bsBtJl5?bEY# z7mtKT7G!A-E`8|)Woh=SdCKGnOo~su6QN7rphIg-&+|>#4d4tjvh*!F1HUZ$RxBFzI{uT|CY>E!i}aJ)NnL~<94)~`9$o;*YA*HIIubleFl z90olzgLT|KX2RuED!huJljq>(rE(}ce%z2Ny>kU|%4=h@c2SPvgc+3^W?|0@xba&; zvWc5z#^r`tm4m6RBiYvYEfwK)}~sO z6%_BD0Zi7a&~hnfcPhVzq&#axl%20&Hy(HD;Zu}lItQ41Yecocq9cs*$jkTl-a%QH z^Tl9uq6=FU%Avn_H8zuEzu=dz4T-IgJ$mx2Y?A$AG1$_w13x`=-IV?0r!N7%RjWVh znpdy>+lMKSoa=`xEi=d?FW5MQ)$d+5WlOKdV3vLKSLPYAv@8C|oYEA5rjt>bsD@;q04dVHCn1TblI5&;@#TQ53!S>yNkn@ zv@*0_{u3X~-f_Oil&@5u_Ln^U1ncG3=YP(pbJu&#*|KC1odhl&%Ie|oGbd|A7M)+n z+V<4xxs$BzejV4ToGipdvQsMG$&IdTMU;=SYQM}XI7nHw(rSKT9yrkHiXNo9dLc?h zHMhaPzkG@G`~adR#m3s*k&YpDZgL6FZnSS6d+qUj+BZK4$cm^A)>i8Y^A0|t!jCq`66&_V^f>D0TgjCweSJ4tZj<^Kn$%DaO zyS{ORxTIhesaoMY>+@IDh|9OD5T>Gi<24GwEQYz4L`x@V|yCY8mt~KvyB58LGO+8N1)&x|m zUeH9`4ZmK!O56azy?s=~O<`fHMiKtyO1oJf<60b-HqW=CPpxwl^&IFv#eJKf$fay= zZ4K2Ptu#^VnrL_1yh;U}bpK?q+I_aEdj{oa>S(!cuRVoL;li7B%CpjP{uxD~Q4=46oLF?rgM%wGSsz+0n?!TU3xzerG%)_kq*c_hp*|q8r((?( zNnu}xy8oYFJU^4Zpg}RdK(|y1e*xOdFRJnAW{Pc}Gx~xOs9!lbqTVH1IU1TUrB@EH zK0mu=D|@l;c|)%3jvB2T!2{3lqm`qP8I==P)Vh&obE?i;O`3hdh}&6mKM!Wq8@+O_ zk!Bm4Fga0$tr(5*TfctG&SIMwa%s0M85Mx@st&6&v+2C5sUg>j{UKVLQ%L?B9|-`IJX*Wz3WuWmM_+VqBMe%C@#Prk23?4zF<{ zo5uGgBdRtPY03EB-*oOC8s9d?%n}&i#_!*EmB#mFV`>SE?}wu+XVUn-Vno%3c9x9q zk!P2%bD&p^nI$m38^U(6_mA5eQzge2`KBXRAK6I0shx)Eh_Soc+Y+gmQR(z-x5dYB z3!v~gBld*R&;3X2Kyx@T>uu_A?8Tb184qMMLiB@OWL+B3hOR&iiIudG927g{~T6 zm@QG)uvb_%d>zs_@x<*G%+1I8O}R{SvyX;YSV|_l;|6~G z(=joL)?FMyusfI))P!Ze>;^ne zmEtmjb+X;?N+)QYj4fh1T~Rh?J7?kmTZoNL)T1JMbdky)qk4t@3(B*OOmW8Cn3CXr zF>M{|5;VY=8(R|GH%kA_YMmU$Tt`W8pE$WPo%B1+P zI)@PV&H0(EG~cJp#;31UqEMCZx=D+m4-lf zZU^1DNgCTRTs^#^nnd@KK3Vwa0jf1|`(-C<;lk?xI?em*)1);dxyK*fp@mx^dD}D7 zuaV?lzie5_(Jp+!$G6z3o1~&Ay4>C{d%Vj%I3$KMZA(TwBDeNl8tr7r?Bz&k+QfIi zk%J45Hi&Ar)j5~3y=MX9LD@ZtOSouMkj zVJfO(K2EzWnH|Q^5pjE$%N-MG_j;5dC(`n<{(fkgT@+b;qWywI7hMVsw|NJYz}xNj z4PUpD#`;qgGuh^J#3)GLyEF72uv%2%u?D%AU&k#xMAcEl4XMigJsvD>&tPAD_nCog z-}Mao_(i2hRi1rnFI`D9>kB}(Bo_}XZT*5iD`|)SC1xrD z>yCGYEe*xZsq4G2xOr3&*VE3UgcUx|$#2huna#i|(J%C1YE?znuT)H*_mI&f>OQ%o zPR=3fJ~>)PlFq^bxw>{cl}mQ>wT`B|(5RFSC3v-=ld!FV$YMgugw+&Tj8QR_)i&Oi z5JQW+7AUMeRHftUlb=VC#aIh{Bpf(w*#@b&8~$ zsN#j#6Qb?XJr7YPEoE2hJj$ef%hR+2DJ~fp$%b*~4$??YQnM_I3edjgq2o{NqJ7I` z%;QW`*j7L$twHvSJBT<16FGAcC8AY-=8G=Y6@RLV$W}gICgrvx<=nS08E7-MR2;jR zH_egIhE?aWp)qobWk z^l$}xiBvnZqH`2Qj`cIvU8Trzj*3ZJT{#kpa=uO-y@%%HTs6t%NbrVI)uB@l6}DM) zo;q{K2YYB2@PnSJ*p6!u+t+J_73QLOIqaua7ieD2Q*+&{)=|!GK&~&W!iCcm5B#WS zNzM$k16VrowLIDZ%-7Q-#}UoLKIO{h(mY(Cr-c_jOD{E^%|K>)cJ{XPDhl%_6_ZUr zDH4k0&V`iONt*kaCrNi5LlJ-VI{U9s#J^BSldBm;ten`)oy7WuXK{<5s1HN0P7Gdh zf!#OwRmD<2k*8LhFb~*=Bl3YmWRr^wc$|pB{shf~$gFuch`HE+$pwzWOyt7?S5#+b z=u1@0!Y-rgAr)pJ9WJXgCp|!s?>9B;_W2h#prSfN>z?=BJ$q^0`(4drZU5Aw36nr9 z8n~^=30evMP?Nk$dRNw4f;g#W?r(=EPFkvFB_-0atvx0pxI??nQqlopbl#|Kl@;PL zHBm`+NpV0nZ&cO;dui4AljG>NyyDgfR@CR3)Y?XV`7aes$y3r1grqH^8iVo;E?lBh z@4xjlYxig%+m(7{H|wnXk3Y7owSt+^`rS&$C?Z_0X1i?(9(oSxcEee8OQSFmL;w#jYITcN(M)um@|IeP-@%kE8U z50Y-zYRIhEjr!zrNKxIQ`+3jxewW=9UZ)|lGeY0i-zsTA4N~I$XVwHL(ylLJ+oJ4F zm_8Df741K2-#e7;KQNTd393El zdg1q#RC};P#q)TB+_rZL&lNq9v>))acRHj`G!g&PQvF%&!_FeU%N7$#$EObO;2=AN zTdXypa=VgWx`b^OX!rMNV=vLX-=*REUNX>_lCa&P%D#2q{JEYYp4}Q+p)JYAb)Z_x zTXEbrs^Ce}@K|YdqRV6Vi5a6dV$m^0D{{j1o-1fY-eXGTj9GkqfxHilXnla>O*bRQ zS}pJBb>mKuyn9Wl((-}``mcsj`^ldEQ<0+wv8H<-ZjlroU!>W9^5w3Pr2AC7xG<$9 zfl_ea-sW`DD;&D5yf7K%m_DmkZ#zY``|prT{>;oaaP=u-W@wn*l9cAZtn))sl-$aO zMtJ+{quJa!P{gziDy+8a;!3dU91F~y((@n9qPcSrkTF)+SD=0Nm*aD&()*BxsyYK! z2`xK=(EG;)FCRQi?;js724Cx-g{23PS#a&<$7tV_X+*z0@SNzvY>-_URk;r9(R#!m zTPwEkY(}Ggy6hh}Xw;8t*s6VuO6yv@6_S7X;V`y~I%Y(_J?dJtxa1(-$j|%k096tn z*RTuocfO38N_I}|;$HyfdD^Mhu2IByqF7&`9RlIe2U(ady~pN|?z4>fx5u9oUziT| zC;?-S9jBWeC;ij4q6?2bI<2?f`|Bqo+mK65{MK5gv*@c6{{628smE81Q6cEmUz)^}%rV zM$lO`v%M=psSI$kt0b}&|6p9(FS)#y#`T<0UV=M8w$;|d~<%auOb zLAmY=227m+3C~7!$NA*(7FXzQ^+hu(C$6Z!LsnGwhU9mm-Tue%0ASx^Ljc*y~z>Tm4(84m|PGfJVQ}MU-itEYlwTxgv*6P z;#}a3$~FFBJ*}g6J$U_qwxwqxS>uoh)_J6kcR;HprcRHT!|QX5T^*p19|UAxRAEa7`-wIE3-%MQ4B+ts3iH5Roe42UH?XV(2Rtbi=HoEe)pBui%Nfco>Y ziCo@{%$t-j8O<3_g?{S-6mkVX=0z3NFX9ERv)>}#BY?*XXa#T1_E}qq_bA8f>h=zB zaZX5>2X+&kyM4TwGDVMZyl_{dEDiYD5ua_$q!Y4=JT1vHfWwJf3-CbAqC(k=oR4$7 z2p1irOWO+|23ESp_P&)MQQBg_$-(;fUc5lJke}d)km6jECG26Z5*c!@-S5r|_eDBOt zD;I~;?(RN7dH*8DBfF14^ncEETS@fle(9Y$MyL~z;(7-D;lAK+)5$;7D5A4lk%2b1 z+hKRh@j#^A=DD@(74|1FFK}>#Jx;k%C&vX|BIf6|>~3#O%;k(()X$@u(9cKzvX9O- z1302D`FJNC=-{716lJ4c*AquCT~Gd^mWu5e5J)!c9l)0niQ5r~bX!mT^?HCptgRu^ z70?(v4-}RV=rcO>WtL;DQ^a#5_%6WE%vCO)s!d3k2z*ofr+?Z`zUe7LqO5m7H#4L5 zetLwcPa9HY^C_reGA--fJybDSS4~x36p$HHl<}Lfxo0+I{GQ=B+;kMSP*mai)SIo( zQ>9zIB9^i%vZT@toHAGF>pDr*B+qJSclIYGRC$)tH1sI#66%{$rR@~R`|yk}50ShL z%*d8ko}~tjWtC^onNp?Y1rgaZnaB5#hi#}KJE(BfSAM3RD#G@QPO`p!Fp#~*`MeR4 zn>3<64^?CRHzxT8*;6AUrjlTFxRp1orKClx=kn;@`Luez;E&8TQxKK91*p*Y_OAVV zS}N?u{@8(zgczq%{ny@=B-`x>^(DJm@5eRNm#j%~zeAgf6}CE5sr38lMXXw-slRVv zW1uzzQB9z}gRK%?JxbL=&5A{ro#)67e@frRy57F%?+avSABb^wyQXiXInZ3s4tCn( zl@f90YNXE|QN>5YxS<(z($Kh%9Y8!PLK04gPYPVY(^ChV$n|k=f`|By2`jRo#8Xph*tb6&#SyTzv#y?xu z%L9FfEU0z0wL*W{Kix_{4`PW||H?i6qVgrL6#q+PJv|tY?X#UH$^KvU{}s}{9<6p$ zZ~l=-&y%;-kUqN^F=cCJfz{65 zSbZH?ZG-_+(`eTcDaU=gauZ1zX+-4IX@%9c?KbWhS#5VCrsY;U@W*Faf6pF`*q|KfNRJq+M%Ex`R;nf1tW-lWmC#DtJtbX*3?WE1#Moi1K>8dD)uah?W8xc7%tzO~$h-tYt`*!~AKhowPLn0@pCEEO@L4&oVO(&){wLU(u zFA7{mb2HwE$cbr%HurtHK8xmNf)UelZ9ee(VHUf)42hhWmS}V1BW=!-HWLk~*2f1Y z{%FGT2X7k@IWeu!X5CdaPLMX;Moi1K*>u8$6*MC>;DCr|r{ z5z}&Q{II1&uXk%IOoydEqGQ3pCDv*`x&I zy!5{xSZ&8Q#!SoQoR&Y1y?r&_fZ4PJ5Vp#1gU97Qrzq$X36H#FCJ4T+N3zkc=}Cu|#Y& z>B1D28J-1+(lUa2D|`PR_LGO5ts}C|(~W~TM<*Ox0%rEXZ#EEf4rVqf31*FlcOD?- zT+D1L%S0lWPVZ}$3Q z>?PM9jmgs90d*Bk?{%1U6`gOwm7YI9UT4in*2Q3fF<07CAbB?={JV`hQT}AYm6aFS zbj#B7Pm)dltmCTR^5mR`uuY?mf~)#nyhWYa7V5~#Q%~4gS;9>p@?Z{ee=+3h9F`^A zx5xjPPuyP(xjLsM&IR7NZ}o|+T49lv8*TG=3tNFm-u3|T%chn=N9lg!V!(7dydlc_ zLiVVn*jT$;k`3-#4EO$egnZ=^z-GuhFNvuy8jAW#bfb3S?rB@;hRtt!GCkVHy<;Xt z2mAB~2E9MzLZ=L{LB!MVg=#K@c%OAc2GudJiO_cL)&r|DFkwy|drhWuCeF z)-Gw|5n+#I4<9+>xy4!OFKGh4WORkuIrQ$v zBF`^rZ+5X4rAr#MSek?=^MM^cGVdxNJN)I7uS^Gb{VoNS-$i%*7W<;7c#3aC4AdWV zdMm}i65o7Id}%sZ%l+_Z$O^ji`nM-NI@aQJ+8yj(wMOo(6anZydE3duw^7bp>dEeD zF%PEKfFWE~?xrB;MJ5DZ3enjAh}ltgr^Ti9U+TqrnQ;n`{RY&}=Cv!M*qM}Np5M^R zWN}4n&lBsDy?nF-i^sO#Sx6TDS5I}Cl9H`vEz@_?T3BeJYmJJc)hrI!BQkexBzF33 zw%daOp)QvxHZhX5+)|Vq-LtC|cW^h&WtSs%8b))oB@Cn4GBco(#sVT~+=#PUF@pZ`?F( zsnTY$D)T`OiC&U-n(C(2Uig|jb7*Oe11mqi#m06wGa)%8hIeOaCa`k-Gi@`-%2{5R zoT&0v200`An~*J(GuG(29`&Iz8&u`@Ke02PMyR!Vwp)Eh7oj~L?UB_t>V;T&Tbq?s z6=mN6TW!Y`jm>8czITu$&k@pZui)r5>!c+IaXn~5*Mk(->+XQ<539erd&B{feZ7$1 zO=})#fYm`{e|uM40ab$=ys&L?W=F|fP$iS29z!1n9xtYz0~_y%uB!W{AmaX>n_SdH z`+{8I7kJEwxJ_|c4{Qo@PNf0Ui>V9AraS)%#fk;#qP^q%4${SDA7Albp{mUe6??;= z^{&4jE6ZM?+#>vnTTk7%JEMH&2eI(luYa(fI9q*@mDlLe+C-Us|6Zg>+~$k!vG^tH zfr#F=Uc?omZ}&y_SOSx#gDA|u-^w!J4qtRG1xT~OeEipb=4&(`-|36p&J=4_zJMN5u%v1e z^)5ZtdNHGssLa2IuaX}2>c8UF^VqZ=X1!g2gedPQHwE2q=3N`GCP@2&eRuQ)$~z6f z7kZs^v5tRvck%_wdrC+L-;HaPK|0ufM_-_-1M~&+7o;AeFF0@qUl1O`Z#2n9BiZ>O_@)XJ5c8K|UryXYyI`Q(5=Rf;;+#6kZMT-vDO2b-EtANGoQAclZswB8;%b zM(Y4(i-ULY4bG5w{u2z*!>6;&S4aRm+Y(eqD73df>YbWwzv`%->%RSJz)BaIlQ-yNy-0KNV?N2M za-)&C+son1>c@T3+0b0FqN`MuHv_d{wL|ajYNhGmgv?ij#-*BUvF13%`3d@-X2Z?v z>3dGfd{1k8s+pETIWtMeCa52$ZO=bN9g|PVe2?OHptpm5uKn`n0PQ%XHUEEVU> zXnlQTz_BB=zJ8{ZXTG&GX2d%dK-1+vnaR2iopmP~`JOG!r2UgW9V1uSV6sOk^j z{Ng&jy>Q8c#cl6O`%Vamk%y*5q}SAF#XL=StwUBWlyC08wCiYqM!L+A+SxU)ap{-G zWO>MDsV{%Ii)?m<<3(}T4WwDXW{rog$tIg!1uWh1duf}YGwCxdU2f1h-)lS#9=w;8 z4@F(iu4T4U)LqBK2#eFD+HDoA^H0h8`zmFa8{Fq%zC z!7-uT!_~4Hh{6l=DzWpvWh(#oCU0ko3hRH&R1PX_Q!rBPh*_FRa+bx+I1VZAxj@dG zW8GMbB2&bu+w=?^)7DQji+tR!Hn%8A}!D%14ALK;)voT_a2}W~*8T z0;@OHRTs7gXtc^4Ez0Ha07_>cP_stvnakclx|iprI1ae(9*dri8@UJ$L0i0XM15Fd_6XB~MT zC?%SlPHo?mwRl&~XkeA5--aUA-R40zqAND>_MS<+u56X{O*H>M*=%|~*|COzs5>TN zNVPG~xq3g1P7jHQeppqRdiU~k0UGmRcV=R1yVdT{t~RR8a?q^mV(KpTmgFNGFDc1n zi*qXSz^>Q09vxTFi_DL5Ji9}g21bbmna^d?yyG#BrY+93F(5yp8>PgrfH`0v@TyuM{92#lANeL znPN^eL`uLd?z=aaxU~gb_H2o&c0sPYI3bkvj()dY#8WzY=|G}4sI+#$%=MqoKVV&z>j;Rd>ttxn z<;%p?>qyGFm}xOy%1Vo3uG2i{X#r7HO0;vf^3U(j(uw6~bj)a%*%oWDvW(j$KHh0o zT&+W^EW!nRd4p1IyP)fF>nXPo7--xjc z_|V2}yI9BJ7xlyvlPd3Lq46y6p_^$9X_J(YrPrB;45p=3FZpL%F>1<<=Z#pNubX0+HeR0`NH%arszUa#5 zmyq4F2Mo(2dWcUtC%Pea4|=wL7HPh*Pr5(s{@$SMT|{rZg<)GFArf%`x5WQA!zATgS zY#R|#O|KwIuH2ixk)ouno)~QzYK|&7Afdb)0#+((UtE$)r%l>?@C=HNPMFIfr6mPBy_LVq-W#A1 zBQVi$Z?)M*ts?JT#2lxGN^2P1 z_}uYI)H&*K*42$_Nz!_uq?*I*DYiIm`7F$yrdk0Z@|j_Ct`fPMS27ng(lVpF3};5Z z!1hd{J;~k7PM68yVp}KfX-S%kByN}VKn6+N-8)y&%4qgbJuQ!&dFde}>!H&A46<;! zgr^Qs7VhcJv^zA{8fw0Ei`c1ZUDVCsRfl;m-RSQHxFx5V*`63Rz0nP?(lUe5^}A=c zu+g=*8{3|s^>Yie*i4QgN*;w~zW+-(&R!wtgLzzWBr73WRhrfFdv;U0uLqHJkGnks zc51yo)qDzdFEck=wvW0+^z%vAu0iSX@(~QiqZNi9$v{L;# zPuCh|-&TA`9G9%6tq$fI-L~}IOMO}1@J>$U(DFJ5Qis2td4i;V(wgc6y498*#qaoZ!+r2kbvh4X@FdW%kAfmt2itFHMZSOze2CY`Wa4=xZRKZXUI$ zh}P*7e6S73=0NMOniE;ar$nC4w;WK-EkN?KRTdPJRUOLACdSPhQ4Mb1&PB$XM0(!%<4cJcXARlxCax7R^=n_Be z64lHOpL7GVEEv->3j$>;R#=VMxr#f8U^ixN`RA{Z zhTj%573(u(*Z05wfZa`hM@;1wuVn3t)}C#5pE^ow&+iJU&X73HutsnncqDxzao_X8 z<(D+1xnOLXpFO*X#-?GOTFM z0P*Yo_1N20BY0vDn}yE91?rw?menyjk#pvMt5;IYjuaAg+qQ=2^`2^9Jq;+5$qp?*FKv~W85b~Vv`Uq@ypv3=y&YhudN~dj`G6Qmu#}qqRfBK z!1vgTPM>Z>_BlT92KYb}?a-vGx6-e5mdfFb6^eYin@%>Wd!#AEkwUw%f(PE}Y$V$r! zGDZ64B}XVzeC>^^=)-6~H@fiRKHAS6(mKD+z=jaRZ>WNA%<-1z8~ z1y{+J$BMbCz6{n+-YoY4>rC;jn5qj~X-R=kb)0&65BbzMFHBBUY0IJ=-ECPdvS^$g zFW?3lULRKf;H|TiDZUdDb;>nF%BYp&w~&_eO^}5vez9yH z>2{)!s;FBKqf2`{lR+^$NzCL#m5vusAAU8Wh*kVQh^U6wheyY~aDXCovXJO8*vR`X z&~ISshLfbKJHFG8yE@mhTI8uO>AVkRf5v|WLu{h~i*H$2Vx~vPO3Mm-c=5c?SCbD<_r_K9VN@T6CWq~$`f!FfE+4egevGn3kEKy8 zTg>!I){88yX^4MfKsrqOwP+a>@{JLkzDE`>YywiZaD2AyKDXL!=y=;aEvh zt`;#3uMeY&6IRoBlPM%BTN7mAiu-k(N(s-kW|jLsM|X*rEIYs5@WROxsD^%;Axcb%d7Fk49U7;NNy7wEUnFPXbYzd2sGYMB>heAA`5Y{zJw7b-v0 zNZS?U!L^O;EDx^t#?^}}uVqjlb_;5?lj3!Qkjpu-JQc+2;AH{nlnXZssm90a&q4F{ zlRxE(nVhK7b_J4_KWxt;NjHh8ey9((1fEz=Rm)~E(<5Z1Wd%N5>EWyEDN}6m##QuT zR3Dz-HGVhMhg-dI`Jk2dW0WldF9aVWO>gr`){88yX^SkI$+##mw!d6;R;8TgMs$D0a+UbSKi7Ibd5VuKz!}rlGkX-_92d&k#)tqAS2qZ)3 zPp%$tl<2#C(!(R$E8UicH^X0hu#is0@9{}j^K5i)`sj#5Yv=~bUY~3}pk=)c(H#r7 zohAA{-*is#(sbZ+<73*hn@4%R>3YS>`y9BF-~69r+bE0f7tpnr)f|?zpg3KK8$yog z_3c(7AMj4rx9689gKGNxg61d5)AN0ixfCO9ZE)}9V3TDl=-x|#cXnE^s>T8P-;c8P z5WCP9TUF;^6ba91kxMal&^Ox;T5tV*r*xA1kPo_ceLyX*0}!DK;Hb;59^71%sW|C;~=*@++$@f<(A{V$g27V zp4Q>AV;y(`1mZXvCo_CfbY zZh60dowdY1)5q{1qU0LUVy!>Q;RxzFTPFB@8 z$Ss54%Q#E9rN|dqRo@`K=lxrQjbazPv;C4=oXs+Jke6Td#a7ih$St2&i`+|Ie#tl6 z4_f~*fAk5Gyx0d_c?<;>-#X#xHN?K`i|q%ke?Rk`9i;UuzS)XeN4Hx$w`|1D@n03t zY5uRDipkCl&|RaEjqXaPHIHjvsNCgN>DdsH_VZ>xZ=_YF>pZul9b5$UJ5-bwcvtzl zy>C)~-W%@JRQo`!qhbkHsSZb7{yHVz$fI?vnQ{iY(9Z26+PWj< zqZ7o*)J5a=Q=C+UOwMhjiA?}8z0a&7%KLZei6u|6-tJP7VhN3Gqb4n=aGJONlbvk5 z`!>6q$*EZ~TI++Xy@APzD{WJ-roM7#AND$HrBb5V6c@(YHL^aZ<~UU<@Y|km6>TQJ zy$4Vgb1l$n-{cQ2(0PE$fY!~NV6ofW4JoZvkP9|#{CgMWf_rtuo|ZVXJ&GRjaYpy( ztinXE2)8U}UrDbBSJ5$TB|LYSbd;d%8ur%^_WI?0h{j#Kmewff^SJ2M2Dt&6bX5^g z)kA>=hl~z8K^DB>$+E|`l`;eqZ3VWW{382S+d2dA5!GGAlsJfaGkwV@PHdvdzsSF zJ~<`Q{??Hvr@dEJ<}TbWw+CwX$@~w&akp^ z(*)%AdesN)Xryr;^2UwSDlm(ajWOZRXj@~A|L`61)vE~f74hwD+4L2U z-04?DMJd)YO+k#Uo^dg&h4vMX-sxAwrJA&S6Q^2fGzETfe(K}LUednhu{->h)^_bB zUM(>60V(YvU_EKc%$`NT+LzS4!!O~2L^>xl1>Z1bRK_;?hR5&l8@O#y`ELLHh^Jnh#n$bgaN{OhO|fR`@6=j*dF0k> zE?m(ht#vf}U%TzkLp1w;Qp8S);jpqkkJdU8+gDpoqiukgn#y6NrA2x0#&=PBDGxp+ ziYPKkoeA8 z=Pi@fIGr>D_3h$kU)}kN_BBsSe~qecngR=TeBzy(WT9t#eN9S?z)@r^)D)~YoN4^o ziKg0DJbUL~!7D>PYJfIw_NsD>v{6s|9X?#d2yF!4{Awd<C0 zn@Lt*&4AB7TrT%eEA6}fcPHOvu=h3tu^hR!UV5nZJq`X}zK2(kd{l!O{^fyJ)-=<; z=*2tvBBQb#n2!z!u70t(_8kpnzC&3f=p0~;oL^7Vu2UoNml&i6^mOkLg zW$95(cIv6DT&l@}#C&xwn2Bv2R=ATY&|o1~b+r&lTlUSat4P`qF;!Vww8r&CMmM&P z-q?*hC`Ef$OM6>OTOPH!q8#i=B&U9QBOUQ*&2r4ferEzSnVYz=on}`Di_^uJDr+C8 zw`$_^t*_C3NmBt&bta2qct*Q~8x+IM^vpV zVoNgVo*Oj8o)zoe*b$)7UP3fZxw6tBd;S#Hklkf$;m*_ED=XP8aYnX{4s~}Sc^N@= z=)Y#^QOXW4yEE<9RC611vMaHt$*RSUnjM>hs%F-a`_e-+YD=E#wo<4yU{2EBc8u3n z#Y6e!GFfe-`z^CSC}8J|UUC11lq7R^hsoxoX2|W#=C~MB>_8=*qa5|W7jGP<9l%$8 zk@bp~ws#1qlX~>-eDE=i-KvyrcbT-6eoq}0W z!RFXJdU3U_2hBNSC zUP|CO6~lX-CeP`_F&(#0RA^5^x*JlOidM9%Pnmm|R1b`nxnSZ}suntnx!N;6?rN6xCp1zg)ek>IXOX*jrE+SPw=c+lACDNp?m0wxC3A|F zCZo}8VMxat6hmEwWL=X9c_vt~D4!C1h0Y{&6El@;i{u>AcimBvGg`=0%!okF*#2X7 zlbqefOeHx(Ko;ITGUec-8nZ_!GuC9)mtC^4(inK`jh3ws(1_jBjbm{-?GE@-zn->( z{HBkPtjGk?W>;^qF+gMX<(aq2A(dQ&&tm})iEmCRz18FHBBUX$_-w z^RQg&DO#@|Cg8TClent4u|eeI<<7oIIvy_IMg{8|R!Z9y)S<(_JH_6(9N~qjGpw|R z(Yc@H=9ryi*^wfu-NIiTmgb^W!O>^#*-Wc~?|bKRP9>{nbRuT-tQuSCM9c@?$r0Kq zpzyFrm6{FFCw1F(mFOS3(XHlKSCrWiA8EH)wCiTKZfiTaYd+GlgSER;WB%SvCmBBC z=-N?PSBk^Tj>|@yUFti2AVUXzyO6EoeT>=4Ow@1Sqm!{&)NkMu%)EVcgojJ(8q5dg zpKHuIUyX8OCz+BH?GE$pJx=PJk*et9XjQLsxjpP={-P$4Sha2BAjP}t zU^J}QzHbiIIG>4`s*-~Jlk_vc7SjI7=WbM2JGz$ZaR^B|Z-oFUgPOdWSxe)6;lWc| znLxQ>O1GDeQ?B?@$GY{-{eSmxZBCa-Yo4KamIUOA$nZDM(>niG?(}e5s>xx|fSf6% zb&FnQuQGW|Hm$CWb|*&IwSBkN_7XAuK`r01<1V6p?M`(&*A}13C1QD5!MUK|(dp~x zT+o<8J}%^7o)XyZ6qv^~WUtGgyHEgOiz#p$P4Pz;WTG}RMw=&WPj^ zh439uEV&0CX0^u-)O<8f>r3SBq|z~g*e|x8!}^+iuVZVZZrXvz@FeZFahS>Bu$UeC zRBH(PrT4yIXFMke*-_f|zjgvkl?}#}B=f$LbSHlzVwW7k?BbxN3n|*c^d$WUNP8KW z?X+kcx{_u)lic}^WV1~x3)`jGVpXdn)P1Vo_G;`*#}B1UOM=a0jW*w^krZPW%_esZ z>5xgY$;l#SNh7n~?v5?3Ul7F)*{d9)DE^V-_8iCx6}>^Fy%~+9>z55=JuQCnAl}xm zDiu_`={NtlLMz}?N~y`_Sc}Q3ory0gSCljh=FGdCwNKI5{j-p$nj_Jvy6>hfzfP6z zFK$$a#Z_9?$7>Oz=0#w=G|b%MB+b;P3aP0)R^FFDc1q1|%=+Q|D&ksrtaQu(Y3;T9 z>?3KX38@B13u3iq{DD;ztJ6!lE|bI6-D1_op{}jF=oSRz^$Si6UH`o5^#F}H!=30d zw>Blylw2RCvYJJ6;-}9B9iut%OgEl3U$R)WnW0rXWSkhzYHh90h#DKsOGAImWiKMm z60!A2dHsSMv2@Y{7br*k=E0<)%}mo`m#%P=rlPT?PTnkb(s;Hvs_Lu_NZTYL_#8<) zhv!oFBtxV{cD?WUid$$;<#(RiCD|Az$V&spxY$cZe~6i?`UR_4oBz#V`wVkEsqFHV z>Rb`616V4Z$ftFHc|0@P<**Obh8^Q#7I;)()d}axqvnh0icyO?lgvKx&{674vVf;{ zPc+-ul_VeONoUWfBO6iy$WRWH0pK{{^Hn7>hG{n$o6S|c^!b+L5;L5 z)_Zu-9ejtH7SKH5RGaHZXm0YCJKdqRP1MqMl382Hj5nUypxvR5oXzdEfUN&u=0x`u8@m zyD6b$1)=0pGOto;TcXkb$8TR`qkp;^)s{ea_e(YpIn~NDL7o0yo0I8Or!OyMmfSt2 zIw!bIJKgk4o(N_n)xuoaG$UD2N;Es2W~_FdHQ54Z%g1kzf7CRyl1tJR?-eZ zecuShNKu1%d#OUsbR(u|EzeD{i6y-l6r~ISW6ILkV{bmLF|*v6C3(O-@yKfw48u z=A9$%1|ip?&IQrYr%iMgdC*38E<0@zsCuFuRCQO2YHgrB@mxStJfr=81{IYIN& zO&+{kt=ELD5@r1t^@&P4QFOhbM&In4uH3;0^+tR?zsol22DnAU_t|((Rtsphn3S4d zK(ocIcm5U1+CbJQDD%{2vc@*ycL-ZVN=G>AZ+&3Hm=m;@w*3zHyaHtHfaGs+Ht;gZ zzXR}nwAC|2{%Rjo%^~@B-T_}#esrGj#*#DpDZ}mpd_l7~dAUJ`O@8}}8#JHX?S-o> zFW@@125g|rzQ>d6hs=IFH6n*H`(8j(&FrYon%rRKHIiG6pE-$dG-jQ#Q`DGG2rBvw2^@DHk@4I^k`Sw9TQ}u1M_SAUT z@$IzsbjX8e$eDSN3C%MXvrbosJ%~|(il^m4jr;u%i}sK{k3gE@Ie8%6z!~RRo51^3z+NBI%Ann(@+A7`E#i<@w{DJk^^Hz;;)*{dk3>I{|6NOV?mr?~NqgNl#vg z@wPiwd&4S{?i8dcN(c65>dol1k9J5-d-CA&t8DH>IeS*qraP(HIwN8laC-ucQFlFi zEr-Uavm$P)$FjQg7=^kpZoIZ~D|KN!=gw_wOI7O^7y_*M=G(t>mFYath*Q_>#eB6S&J2y*V1@+1F*QodTH$s55)Dc|8tO2C4?A1`xrD&Qp!=E2h!1x{g?K z%`H%^3IZ9n{NzUtkbDn7nsP(}`MRxnimiG)2#EUY-_m&w$X8`t%t4Z`2BfLVhq_ER z?bUGyon3qg5{;_#P@Oe#Y}c*iIS&J}V*Ly>`|5y!B(g$lPEe?ZKcrnEdGp)=j%6U~5OT0^4w^HiEfvN!oR)NFK+`AXO&X zq3%@e;dQh_T}#AtGcYHz{P+U&y!8GLuaV5PF+bQJGJjC^kL4uu6C$ROGJ`QS>XCOZ z(U|%q;74mWkeupgI6>{15t6%$YR>>2H6?~kO4a=t5c`h~T}#BL5K-Bi(dt6;cSDa; z1y~0W^~qS?dx3<9>rTH;64u2$E?}f{1jzrDdVaE<^8eGAs9FI68LQsA@D$1T3?{1P zUT_AnbW!N%B6v)a?u>(xtR&L#UmJK~a-zy>7p%LDSvYlTfX021=eDya@YhLX zy$7A(>o&jR8alz&(36*HW_K-a9};%*7qVsfXkTn=<~z$N7d7Jfc-WNJG01-tPFnU5 zGY~R822N=vx?y?gM#F7%!!k&~bSsGrTC;8fB=6E`t$N`6=j6`1<8cX(F)leLZimK7mm}A}6M_HzO;5`)c?RvT|1;)t^>=@sT;J z$jaUBgwBaCt8`^#ioD zPa{b$CUibUlD;Np`a#lrqUN&d@^ukaKS&uO>A-z8_mHG-h?$C#qWc3m-(_s0v*>T~ z)SedeU^Tx5tL#H6-n~3PqxDBLMd{Ek)R0wwWfISXc&a;mAPa3D`r2~Z6N)M2IZUww zwbeI=B~5XK5uGIY`I$b~=p;$3JJ05f*B%UNXEw*hXl!kt&tZw-nw!aH161E!Te z)i-fsc1ahWFq2c)&P6&}P&bZRGs>N!ZX9M`bmd(t)Wd!H*n2Xle|)@{-cx(vKo@q*s6c z*7J0SWPqNiwL>%O4&KT}6zXI(tV?_bb+Q_Go7KZ+p;!*oJ=!cCKS-{PgNxbS7^^2s zX^jZURc21&Rgx>ogQd8h3Tohut~yF% zOEO?_qRD#*m^ByIJ$;g_HpqjgxLykCg1oy19uCl04o_B-5KcJRNJF};e(=RZq)R8_ zDP|FrxBl2~-b#7Pg?Oo)fYR1OmCw9`)?(6V3MA@9l-4MSyJcTJdXr8Ir+V@@@nmTz z?g}2Mx|Xu?U{9Liao6jy8JEac(g2GSP1wBLjq0UGfwNL2Jou%_Jdr=!GT~;)Qc#u zQ!wi|_39t%$V1-+M6Lvs=Ak*`eaG`}(wy-^9tIo;=PuWof8V`D{hClN5KKd(sS#yQ|fc26wMe!WHjd{78()QGKHh!><+1UeES(~akZak=$xN>AJXpq8 zVVlRkeu1j6?>$*u%9NH2RADowe8%SF6Fg~3T11t@JJttQQ>;w{EKW3O??>Lay5(nw zs0y3p!85)JTej!1bpaad2TzvAU?6KZq{}Yv9nB|QPDVV{JPE3>ysIlV(`ff2;_*X) zwDnN#iaIso9BK3?NYslctx-^gJ!5^Xkm7ENCy#SZSsJQTEI+i^Puc5dPnzLz*QKDz zdh(TD0E-h%+Hy#?;CsHp?%jeDOx{pe8|_h$3F5aX+`rM2=_QmoJM zWa$)Xgj|8mIv0^#zk9HZufj$hy}>$0|KZ8vQl_+IpbC3oY0o0k;#^Ofk`__r;0T?X zOR+W&usG4Ay&rkw@${H;WVQJoJmagd=~X%w1!$}Vo-B{SK-O+Zml@H~he?-zBA#lV z1Xb8`gPLd1XtxmY_@O}BdMI}-onKf$8eIg5dJ&~H3aYS|LmFPED(o*$9_O60G*qc% z{B~_0#oc00n&ELbIi@2UNoWvR0YST`- zjkS{Jg<0*f1H&w~IPIXJ+F4!Tr`g-14wIi|cu-k?6ID4u?b2i0sl9XpdKFLXV6w$o z%_$a-1R$+lK%M;Vcj-i3EvAM?ws%*rG!@u1V)R$+z41&jRW&Zb9o)(<%*&+iDp_JG zpMc~e25?{b{TzEQYmFB!r(}69u&r}*T0Yr!trxCd&C<37kuz&!@J@=HY@S+j4m>DM zmy(PizBcXjdLrfsi1BJf;J>|sL$^{+S|=o`RwAgMa_`U^te^6F0W~dHQMcf(e5>aI z^XXRg1|d^XyTEV9cNxbr;YKe^MZX1-_UjSE`ZVT>s3FE{H!NtuVbbm2JJr@v{d=|2ah+73jMa_b&F!a8v`IHs535ov53JsV4 zlubUgT|iA!&A1>|E{wdqmzX<*OhxU2tk9=+^;I;Q?exM_^jjcl{bqA+kfggrR6k^e zH+vmqoh)_>nZ|4Phj9hVNxOTzFcq~6Vzla zcw@r5MU)ltghYR2g}eJKEFiz#FQED(E1bSjc@r@Y2$_o71zF+yiBU($Z}Yt{75x@u zgc*orlu(DmG{ng*X-G?mR;K!0-d8~TgU8&6Nv7nIo3ZYT3eq&RGBx$% zK5Iyy#}SQ7veNnl_8Z&i?!Cl2fq1I-tHIc{CGPzdGjVdY~5_|gaKhGmm4opa+_?WVZ)$tjU0=fKWA zd#mUd?W0_+9lVbAQO=hVo#rTqJwfXoslq~?D(@Zj!U^)*BETxqESC-p(W$NfbL&W_ z7XUTdrM)VqyAE%J&!(iET|;tSbSFk9nzXlrZfRCEK2cWh{IvZFW%Wz9sXg07h4yG? zu~}3{Nsxms@2!8FWGvRx+M8X`DUNtktl7d1mD09EGXA`%#!iy)vYr}lv$#}c1kt$D z@o*t|&J~X4yd|O@DeXC+n#|nu&1I@!uj+}BrsP{l)t(uEIrPZynbf=Cnx5IsoM3Tk z4SKtzxRO);Gpd@zsCUDfwEnDj!*xvWX^Au2p}M90sTt^#)V*f**-%aP8@}niEUv^T zODv5#(Jn^{`=M8d^cSH~HnCpa92#YB>c8lg3PNLJ%}zxhK-4umV%Up|W$yd$1x=Pa zdf2qG&>+tPmD;W;u6*j5T$ZOgZuuTGymXv_n!8oS9UG|TE>}u6SuHfegP~8}t{}?3 z*-`d9MRs`+ksJDCr9@qef3CV_5A`3bAYw*YlFe3a-sV2g%S#LDr>&2@f1c{6if&}B z)wlL;CrxT@jrICsQJxFp`OO_4U8HVcck$dP_#nGH6P)Rp_0fstbf)KSo*9$M4fC=# zMK7S`cR6+r#uhTpVQA4 zWl;Tje<@F!hT0unlFbhGR0;n;iZm6?mg+<$ucp~jH8-k5>$()gwRw__bX4mOZWDEi zYTfD{Eal1?tk`ZI_wxpl>;aAz><7u7Jp5uNN%o)z%O8^2CVx~+lGWg7A%2i7;DJ7D ze)5n9OI0%T=0xm*>>E@+J!k7Rmgmm>lkjmX;Y*t37L-JWAxp#N-GA$RIXfpEc|X^-Zpc$YkN3W=cXOYjBD+ z2kIz5sqPV8EU-P&%|GJbr#)2#e*4eDyR zYyR9knim5PZ|oh7-S zL}cylvDS9GBhDDPfyGZ>{xpv)9)RfK+5_Ba5G_5vqmJ40`i?$DU8A2uY}PGWTX+_W zFZ~Uue`@Ww?#`wDsddmdl)PUA6(DVSu;R7g$2O;kT^F%$KmKO%c*;VS-5AUn`@A;n zB+VJ0Mr?y#&_L(+K3d;?JI&0W5pwm*JhHMj1!Ku*`%@c3H0HC28EuZW+v2oVt>W}1 z`wb|&)!#UGFGYDh^bKC!T$YX^E#PpU0*bWf5WQqP(^W9suqGX8=o==)w>wPV@Vu{Y zxHY&be*;)O7;|n>R*?1$FZlX~lG1|v1S2ew{8j<8M15ahaI3E3KEV)6gdHrqmn`u= zpWgsepCR9{*Os$^zM+AyZ@5+E`9lvy=K`+MH@xWc8w}C|@W{Qh2VWqMZ0PG7;3r6X zB*>0&=hkIYc5Ed6f?M+%9GJ4-fMz(??%KMXW;lUfzCry>T{Odasn;8YRQCn>A}j4% zqRJy6%alQ*f3TQrh|SR{kp{h{EDzAwAv~M4iq|)rmbEW>H=_TXSoZ#CV*!s_j+f3b zjX`zw>#UdAjff@!rdpkWZrOcPZ{u#-=V&S*>aJkO%LwKUuYdI0ZmOo5iHMwHjj(02 zIZv_IPMV9Ddd14i33Al?6&xAluPeUpm6s9t>!kI^Zqoku z%L1let{4}GzbuP(sa_Q^^@=sb zmc4!tWZmvsVW#3*D9W%OPI`C+Nf|02s;-ElQRMgjwGIYo%rMMU8ZnWKYo=DaL^8G( z@Hpo&#FF>c`yV^c)JDM6JCC%#f~XwtxL!z6*;YU_J}Tcnn|*ike_c_w2^&QsMNGY7sV*JiI2cgIXWR6WmJK6;v@ z>>(ifqw1M7<*%Co8nY*68ea8SW({POT`vKTa~?x1Il*3Vh~^@_1x&s3Nc$^@%9Piu z6;o995fF`!$|rxhpUs{7iin(IrKJQ>S;10``D;HBQ?FQgTY^!fFzoDp^4HfOQ{PP4 z2pJ#w;r$yFldlVSoLc2&1fxiu#~(aT{`!W1saLDCl)ztSEgn@s{`#hXXuQ834T@(s zqWg=8oMNS=1paEzePILH(j;Q)6)SH`;IE5Yw^$vZF=H^(@T#Zrl(JVy##jN5Q>(m; zz+Zbb$jBgnjT12SYL&Jm@YfeUe)uZ+t64xa-e3P(_c`mD5-%chij|fU`0KO@){SJ# z1QAoOSVL^tY}s8!WXnX%^h4FNApEYYB&9__^heb*FX`SJ0UC1vW*T1g%=`8dt9k|s zc%1VXV#z@dnYNK7tpcXrd8GXnL}kmXU!0++OcD@{kIDws|Jg}%5u1p}DOOra5S0O~ z8XO~kwTqZ~#TsJEn;&1@Pqs{k%#hA8I@L-`3C>6deQ{|Oosk|SByy@XM9z~_B3Y&G z5Kt|K%h_;z_7RfPDJ1$s&ed7z`D9O*fa)|{&X>%Wwv(JGLZUz9{B&6NbdobwKuw8J zIe&=m32#dq!|s+277~@^1UaF?gGFqXkS3(+3@RTh;AHQMhu7Vp+kQjDOionkyZ|Jv zzTo@al>LT^sQM5!MAF?A2W%xt-x4$ZAn9)}{aZ|uzAd8agVYd7?_NE26G{4xn5il$ z7`IbazI1`c?RPO%Ke))t33mE37M@;ClMtzrnG*Wtyzu`F!iO0w3NVioXs9$yY3?eM8&)Zd}m8?nPT#t_eDfb zvC>k4toK8eMl8R7AY$qjD{o8SuQgmta|1LvKg3MKR}SuKYhOwJ`jLRgsa0M^;IH$4 zzj==8gO3GFy;`L$3Hpl?>jrZ4@Reok&NJoi?oMNS=1paE?{N*;X<)!J16i-^W>RsPRG~XHI$Dg8WlEe&Sa0q3?uLy>g`` z1-gCt;3~GG@V$VkPqWfQpxZ%fudS!`kqJVgvTlK#dyc$vgM4VBfU2Kj8X@NsJuYk@ zIVTB;s&b;+0sRvi?4#QOKR~Luv5OHBH;i9=og|(N+2E49eAEDc+Ptmf0iym0sfOHm z2IKb0dspA2`yW4fqlR{FAJJB2-K`0@`O{=*j}6ahjTsxzp(Zoy7K zVb+O*v}!y@%;ZEhB0hWU49=qX{2fz+jE~Rh)pxKS?SF`fs!{^K{jl?nRTQ6dMNFMJ zrS%H@*5!JWy^c0dNaVzn_aPu>^`<9|lAQAeRO92b#>dM}QG6~C5|!ly@i}JiDz?h` zr;w^MsJw1LeAWy*Q%v!>P|V~+mG&brexAFYx|ZT|5vB$kAD;^!Ph@AL{t^*Yr38Na zPS(;(4&65;-yDeF(@|@Wx`cQvSDqYJ7Y?aJp+c$+=WW zRF)IO=aT1a?4HGk}IAA8AR zrHH9>TWKP&X6ChQR>x-uiJX}7)&z3?nf3b>^4e7bs_`pU5w;;W$ZJ;%iOO<89L#E38w^5ytC1!G>O8XJ8=x<-mVr!6VL{wdXN)v(Su6%mI z6|(4BA(0bPUc11eO*>_?+bY>Ys__<0d-CVYWYHWklM_{1zd+JAYKQHj-H>%6sy;~N zwF`Xro{Ni)k)-RzOjSvNC#~-C)fV!k4Vdb=940R-So@ot@bv-eHn-6mRlgu6&jmVm z*yGuWzg*0{)u-G&Ey;Ql>SlE4LclTVX0*vGl{2oqyr6Q3m^^C}RSugWIYQsqN1g~) z0RMjP5q2wSi-^dHDXU-9*(WDp7`t(?Rm9Y#C21mvnqF%rU!$nmCM0rV%Ig+T@0ows zE~0K1Pz`vI4aCgE6(iSDUfLn1a>qoZH4HLDqZZ|}DMRcOP{Gsh@;V06J{KE%hNRu) zg{x0YveKfxpUm9qxwHqf+Y6O{hFzA6x_;L9-E^F^yvG|?FRr|nL0gUuA~j!3Rn1EvKl~D(&MJrk0oC(aOleO7+0eElH=W|N&5bLv)=`|E@IvK;mA5R2)8Tt^cTk+3#M}_w)eLzeh|?ZtMy{b1!c!t5=fKi71#x=1 z&q}t=a$3YRJWk)LJ9aaTr)PvjPE2{-f;es7F)WX$X9ZOM#Od=5i}EO9&WWj<>q^@c z#A&So8SL%5^8%`W;xy~$f}0elMP8_!u!dMR@LB@9LwW&o{j}QR>h$vwlJ=rEs%n*w zZ2Q8*o#auMFxOA3Ew4OaJ4dT6#a^k(aSQTOhsrnE`@xqXIVw{)$G+&R+i0|KT$?3p_wh%p}&F#TcAOId~N zO@tZ(rm{Ujm6F?S(*{~`cu2t1&g!U++F*W|(yGjAnjb#QQT5LYxfe&$<2JbAHT>}C z(*YXw5uR!_+u~GfB2Xv%e*fMLR@7o#pwzUi&V-iV5E4udoy+dx-O=shIj7X zHo_e$KZ^$ITxC99xQbQ{p6000E{EBa6d1>)GkGS+p-l^O4^a+%M!-zvpwc!4a&8#< z6YKo&EN1dUg&}f2@$jGnBxgMV(;sry${)qL>pX{<{P1LmoRcD2viZRC0;WIYjQDD1 z0r~9>=3Av}lV zd=WGK5}$Rh|F((Zv!Q_L4>_kiQ@onwY=oJ9iO=$}za1kv0|iWf$XV}5d)Dhc2s8Z> zpAB2avXf}R0;WIY{HMxYY+MO}%wWI7=ljneV)5Bn!1RZlJ>sjbCBJQgnSP1Stf#lG zC%6iGtd*a=DNzUd1ra$C7F?Pusvgb>f>6iFCdnj`Y$=O1{ z^oN{{%6`T2(94h+;+Obz4exq|Aa>W-qfPA<=c~AdBi8ADp##WL+TZu-F!I<5h`Z2KxER7JJEa+hJlVhm@bOfYXaN z-@C}($!-ssT-#H5BGBuc{QGy)YE1`Bd6)FkW(c_r&6QU9HM;J0g}b&S5C-sZW*^aY*ndoUsN2ReL*2w z?1_mb$DMn-FQCg(LqN=Iul?<%ni{p2o;t)9t3qlV7;x*ae`W0q;Z5!Rx(}PbkW=ua zM(XWB3XO`2&^67Jw;+hjz)AD3k=OLm@p=xtZ9~NvK{6Ii{ogT?v2Q7}qz*K>5}m3% zkkz{ke38A0+>hs#>@BJ8Sp(wp6+hojaq$`^c4-@};x}lw?&Yt}tft+%*EwPgf9+M; zYY=T?^Yj%&dxN9J`GxjS#a{VDdy}KZ`-Rr1!epk&{v6HX7utnw7x$2CCXVJ*rZomV zav%M!*RdxwS`0_i&ZnqG0idm`^ZPlX#qu-{Rm$dQB-^mJ2Nn@6j;DF3QkI4yph^0< zD`YowDa~Swvk%rrdDYw3psIMfaK-KbjTVn+s+L1D%Ge&cbRRAO@gmzshq|XP>5PJ` z*LU2DN6C7Lh^Q+LWv$m3$oFW)E;~s+3#4%hm6s2U2~x9@?;a zx9w!XA&AGTQ(i*gq1BfKZ=)PK6cG*g(1hq;i%Gt>AdOR~ynMhz>n$3(lScWsA(2<9 ztPPQejxC7XOCI`;CsDP#2=LIhpLW<6pwZq%G)|$i(jgB`sB-8mS@1o?dn&x~$n#?4|jSA(2<9tPPQec4(KqhCK8WKs3G%-Mjpag8>?C6rynom6Z;8 zXvCy9u9F2nMLb@e@)iUhx~tOb$H_xKLqx+pH1*z%XGp%!A&pb0ynMhz->UsB%b{OD zBCk?e8zK+gYw4Xw9{MF98efMl>``Y$fJXZY(Kv<5N{2l3n?~uU$%3O1k5{L>1%Zby z+p;W+JoIZsG~7d1cl?`0;222b6e=$t@X+hI+lr|U{RR?wl^S8gjQSt%AsdeMB!Gz1}7a6lEMY7f334rMIi;Pp+bvsPHIuQ}oWdx@mKCgT91f71E#1Xrh zV_hbj77b2rb6(zGL0+x;?VxLvSAQs_IxH@8q{%su!%4>@*t=eEaqJn|yPnKwgXv#} zTCMh2lSVWr*&Ra^_mZ1{^9T3cKXGRxjrpS+)9JLwS~O^Qk}1I)mJ%OtcC<}3+g#4@ zU|mBTS((vE%DqRMU8j?jKb7*s%n24-J8Hty-C>FyXt5=za>0(tlJ{!wp&md}+_>6? zR~w5n*=icn+HSQwx|?FG{E-iNuL7qpE*8(pq7$n>>)FwRP03*pZzt|dFI+A;%X7g9 zRM+}6dqr@T8`qvZgqb!vC8mwZWm2?oV?Z?>k6``6esiO0cbr}3(D-^9E5rMW=%p;0Z^dCNa|?tl8eC9&eW&%ov}{c;P)=5u+n z@na&$Cf`3BbCjZb9#3~GLbx(O+SgFlzW=2Uk5J7upXWy1N}PH{8^T;PaCH$e7YLZj z*$d2|m%r4Aof-VIl-Z_tYpa&74H*vsvCpQQy);Ky=uV8V#}4cgGe9faxr33iv4d>+ z&+b$ENUw|Bi6ykq*jTfZL(1C{)R9#q|GY}`%fEEYWU~#aRh|e&ga-$WSw}OW#qLDP zM^3G0Wr?(Y7!kTx{%!?jhb8XRXtS%E*=bL4#G0cMO%8JhlPymDTsEkf$Bs9#cToR! zr}waFb0dSi31pnGbQr1W#z59nV~*^h*}*?3>z}#a;$hymPOsxrOsL|s+8f$-EQ-O`O|MGML$6B-sU4HreLRy7R=eg=N6|ifa zsYedHsL__Y)0{4ceTc6CR@%Z~B_q^QaXZyBD?I4p0aliay!mq6s$BBsl^$F?z#74< z^>w=)#LN&exdB$13D!|Qn7D!UHecn&v^Z%6fz85b+~dj@X)5rkx0W4eece`jP}`eX zc2s48@#pb6huJ(Rvy|D^=1oxfQ4dt7)qY!=M`L>yPsM`DGl5Oh-hJ~T-OX9!&Wtm1 zWeQa>uMFG8D$=#?)Rd(5$tfizg=!Up)@q)cP&S>`YO+0;&UOxal3{aAl!cpr(PkB8 z;T%u4exQ@KDY}I^XXLcAbO&^uo@RDvQ))Q8D7$|hAZes-Fnd%Kr>5ci$Kr2 zSO+HdV0W=Ll#<&y%*L!Oqm`OYZ-0G*DyWU6yj#&4ZAwbEn!C{&vwlfg-o{|88)93$ zlE%7RPcExf+fX^hfu;2eD#qXXn_0!UNx*Fzm!K>!${53cXvwu2nE3OJ5>dvlz6%%#4n5tOQGyx-h(BjDah8lH;j@rhOU~!qOELq;}7{G50 z$y*!bt7qRBaEM-R*{S2VO>>!TPHpwgsdX*THitNM8$v#H_SNe|-sP3dsa%?jV)^g% zg;%N0*{vh9nxltP+m2I?WuWINZG*PZ{nb4>CJSPIX;ofEFao|+V`652#@p+`v&GxF zv>~0BLG9S`j{x?P%04~Ml$2y*dwi-oMKkJNRq{^Jj5<%iG%#|2hPOWyy_{-{{d#)I zoIp7E%IX?bl6}YbUQU(d0Z0}OztVn%dKE+;Y`T}E&KI-65G*S-%FnM&d~XZo=K?XA zb24cvuyWt;8x;j;)IuFK(iuyIRhLLz+g)iMSkZm1Udb)+gF4==dA$0#2Z)Wk^w>db z$cHeIOTe-+q8-({m%p%%c2p1RiEdk(Yy-yQsNn7s|n#u8sAo^LsG& ztMU4|i!}E;T}ljhmaI>etlSu}5(n0b&J-^>Pb0t?z{N{cvKa%N>IwhzP4)un*-~mp ztqBOZZ+nM5MRlhDSoG_=7Hp^S{ah(A!miDFj6OGoYKwUt3vLkmygNH~py#rUqF*%y ze)VaGgquMcyQq{MX&UIcKhpZvTvY#boUEz~ zpMRCO7rk-0BxwXU@sTo@iF>J(+cm}P7;;O}TXO47Ez3na7RP>@w2gKTia9QugSED& z*j#E%RJjJ;H#dVS*UN}W8B05Hs*Og9H6-$?8m~{;O^ zAA6tm1|}*-E~;+k~&*=ja94L?DR=AO2m&u3EQQO<*I*vt&XZ>{<_*^IZmn5ybo zU`6uOTZ=bQwO+x4Dmch2?_0pWAGWBnoa|fCgKD&Qp{arsyD=9WX_k#8H2N;6G?TreTFIU2G?$!ZHe&Pz>z|Q>`mdwa-g|URmv-95%K;Q= z&qA^LM{dV$q~pq^H>|Xd!Ps~0(4SYxqwaO1YH!`$N*CSj%&S#%G>G1cmls^1 z{e&v+T$g|L6VSLczBpqCjZ63G`0f3=4*cxtcdpYqa8&`*xOHIUU#APh*>2VSI{JUL z23yJEwohdJ3(nJO-o16ERMX{!Ts=WG-2-~2U;#;%*aT#(W8ZvPKpE>nJu$*G#Ox4? zDz9I#=3M{V`fCC-a*a|lwaC@3dl;Zw!0Qy4bdq=vdGMlRRBeggS{(bsBP;1e!iO~; zS*mSXvi1^ulD55Uvbr}3l(i!25t!QcGj?nHk^3vKf8E~fYU^;=wcwzAO%)oFY{mNT zcavm~y3zjIN>yTk9k+GY<`z7ru^uaBc?u=%k0D@PX5%Xltf--pYThD+Yj Date: Sun, 2 Jun 2024 01:06:16 +0300 Subject: [PATCH 14/20] x64 workflow --- .github/workflows/build.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3e4d150..420b87c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -79,9 +79,9 @@ jobs: shell: bash run: | mkdir -p $HOME/.sccache - export CFLAGS="--target=i686-windows-msvc" - export CXXFLAGS="--target=i686-windows-msvc" - export LDFLAGS="--target=i686-windows-msvc" + export CFLAGS="--target=x86_64-windows-msvc" + export CXXFLAGS="--target=x86_64-windows-msvc" + export LDFLAGS="--target=x86_64-windows-msvc" cmake -B build -DBUILD_GEODE=OFF -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -G Ninja -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang cmake --build build --config ${{env.BUILD_TYPE}} @@ -108,7 +108,7 @@ jobs: run: | mkdir -p ${{ github.workspace }}/bin/standalone cp -r ${{ github.workspace }}/bin/openhack ${{ github.workspace }}/bin/standalone/openhack - cp ${{ github.workspace }}/bin/xinput9_1_0.dll ${{ github.workspace }}/bin/standalone/xinput9_1_0.dll + cp ${{ github.workspace }}/bin/xinput1_4.dll ${{ github.workspace }}/bin/standalone/xinput1_4.dll - name: Package standalone run: | @@ -136,4 +136,4 @@ jobs: ${{ github.workspace }}/bin/OpenHack-Nightly.zip ${{ github.workspace }}/bin/prevter.openhack.geode ${{ github.workspace }}/bin/prevter.openhack.pdb - ${{ github.workspace }}/bin/xinput9_1_0.pdb + ${{ github.workspace }}/bin/xinput1_4.pdb From 6e57c30c55ced6b444ce209b4db89f047bf8c40c Mon Sep 17 00:00:00 2001 From: Oleksandr Nemesh Date: Sun, 2 Jun 2024 01:06:48 +0300 Subject: [PATCH 15/20] update libs --- libs/cocos-headers | 2 +- libs/gd.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/cocos-headers b/libs/cocos-headers index 217d6e5..c8f48d5 160000 --- a/libs/cocos-headers +++ b/libs/cocos-headers @@ -1 +1 @@ -Subproject commit 217d6e5e27b8ba5a13ccd377a1b9946d5296833f +Subproject commit c8f48d525e542571ef6e84baaad67016d362d5a1 diff --git a/libs/gd.hpp b/libs/gd.hpp index 5408084..605550b 160000 --- a/libs/gd.hpp +++ b/libs/gd.hpp @@ -1 +1 @@ -Subproject commit 5408084dbdc04f2be30b90b88e879e9b6ac7dd71 +Subproject commit 605550b913b90fe2abd2ee2cc6e07ab940a41115 From d7fd1b32fea730db02677fb1c79dc9c096d46a58 Mon Sep 17 00:00:00 2001 From: Oleksandr Nemesh Date: Sun, 2 Jun 2024 01:24:48 +0300 Subject: [PATCH 16/20] 2.206 --- libs/gd.hpp | 2 +- src/standalone/main.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/gd.hpp b/libs/gd.hpp index 605550b..a2ae0a3 160000 --- a/libs/gd.hpp +++ b/libs/gd.hpp @@ -1 +1 @@ -Subproject commit 605550b913b90fe2abd2ee2cc6e07ab940a41115 +Subproject commit a2ae0a3c7d6aac5dd99350043f3d1657539525dd diff --git a/src/standalone/main.cpp b/src/standalone/main.cpp index 1679739..5c7eda1 100644 --- a/src/standalone/main.cpp +++ b/src/standalone/main.cpp @@ -24,9 +24,9 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv crashhandler::init(); // TODO: Add support for other versions - if (openhack::utils::getGameVersion() != "2.204") { + if (openhack::utils::getGameVersion() != "2.206") { L_ERROR("Unsupported game version"); - return FALSE; + return TRUE; } // Initialize OpenHack From 17ddc7a5a7975029d4d9496a97bc8a73dc2e5f56 Mon Sep 17 00:00:00 2001 From: Oleksandr Nemesh Date: Fri, 26 Jul 2024 12:34:09 +0300 Subject: [PATCH 17/20] "small fix" --- .github/workflows/build.yml | 100 ++-- .gitmodules | 3 - CMakeLists.txt | 5 + libs/CMakeLists.txt | 8 +- libs/gd.hpp | 1 - mod.json | 3 +- src/geode/hooks/CCDrawNode.cpp | 4 +- src/geode/hooks/ChannelControl.cpp | 12 +- src/geode/hooks/HardStreak.cpp | 2 +- src/geode/hooks/MainGameLayer.cpp | 24 +- src/geode/hooks/PauseLayer.cpp | 2 +- src/geode/hooks/PlayLayer.cpp | 10 +- src/geode/hooks/PlayerObject.cpp | 8 +- src/geode/utils.cpp | 4 +- src/shared/config.cpp | 22 +- src/shared/config.hpp | 22 +- src/shared/gui/themes/gruvbox/gruvbox.cpp | 2 +- .../accurate-percentage.cpp | 28 +- src/shared/hacks/auto-deafen/auto-deafen.cpp | 10 +- src/shared/hacks/auto-kill/auto-kill.cpp | 20 +- .../auto-pickup-coins/auto-pickup-coins.cpp | 10 +- .../auto-pickup-coins/auto-pickup-coins.hpp | 4 +- src/shared/hacks/auto-save/auto-save.cpp | 8 +- src/shared/hacks/click-tp/click-tp.cpp | 16 +- .../custom-wave-trail/custom-wave-trail.cpp | 6 +- .../custom-wave-trail/custom-wave-trail.hpp | 2 +- src/shared/hacks/discord-rpc/discord-rpc.cpp | 8 +- src/shared/hacks/discord-rpc/discord-rpc.hpp | 6 +- src/shared/hacks/display/display.cpp | 40 +- src/shared/hacks/display/display.hpp | 2 +- src/shared/hacks/hacks.cpp | 1 - src/shared/hacks/hacks.hpp | 2 +- src/shared/hacks/hide-pause/hide-pause.cpp | 8 +- src/shared/hacks/hide-pause/hide-pause.hpp | 2 +- .../hacks/hide-triggers/hide-triggers.cpp | 10 +- src/shared/hacks/hitboxes/hitboxes.cpp | 85 ++-- src/shared/hacks/hitboxes/hitboxes.hpp | 2 +- .../instant-complete/instant-complete.cpp | 6 +- src/shared/hacks/labels/label.cpp | 29 +- src/shared/hacks/labels/label.hpp | 6 +- src/shared/hacks/labels/labels.cpp | 116 ++--- src/shared/hacks/labels/labels.hpp | 6 +- .../hacks/menu-gameplay/menu-gameplay.cpp | 8 +- .../hacks/menu-gameplay/menu-gameplay.hpp | 2 +- .../hacks/noclip-limit/noclip-limit.cpp | 8 +- .../hacks/noclip-limit/noclip-limit.hpp | 2 +- src/shared/hacks/rgb-icons/rgb-icons.cpp | 22 +- src/shared/hacks/shortcuts/shortcuts.cpp | 40 +- .../hacks/smart-startpos/smart-startpos.cpp | 56 +- .../hacks/smart-startpos/smart-startpos.hpp | 2 +- src/shared/hacks/speedhack/speedhack.cpp | 2 +- .../startpos-switcher/startpos-switcher.cpp | 32 +- .../startpos-switcher/startpos-switcher.hpp | 6 +- src/shared/hacks/zephyrus/replays.cpp | 70 ++- src/shared/hacks/zephyrus/replays.hpp | 4 +- src/shared/menu/keybinds.cpp | 33 +- src/shared/menu/keybinds.hpp | 2 +- src/shared/menu/menu.cpp | 11 +- src/shared/openhack.hpp | 2 +- src/shared/platform/win32/sigscan.hpp | 479 ++++++++++++++++++ src/shared/platform/win32/win32.cpp | 430 ++++++++++++++++ src/shared/platform/win32/win32.hpp | 417 +-------------- src/shared/utils.hpp | 201 ++++---- src/standalone/main.cpp | 14 +- 64 files changed, 1520 insertions(+), 988 deletions(-) delete mode 160000 libs/gd.hpp create mode 100644 src/shared/platform/win32/sigscan.hpp create mode 100644 src/shared/platform/win32/win32.cpp diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 420b87c..441ec03 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -52,50 +52,50 @@ jobs: name: OpenHack-Geode path: ${{ steps.build.outputs.build-output }} - standalone: - name: Vanilla OpenHack - runs-on: windows-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Install Ninja - shell: bash - run: | - curl -L https://github.com/ninja-build/ninja/releases/latest/download/ninja-win.zip -o ninja.zip - 7z x ninja.zip -o"$GITHUB_WORKSPACE/ninja" - echo "$GITHUB_WORKSPACE/ninja" >> $GITHUB_PATH - - - name: Update LLVM - shell: bash - run: | - curl -L https://github.com/llvm/llvm-project/releases/download/llvmorg-17.0.6/LLVM-17.0.6-win64.exe -o llvm-inst.exe - 7z x llvm-inst.exe -ollvm bin/clang.exe bin/clang++.exe bin/lld-link.exe bin/llvm-rc.exe bin/*.dll lib/clang/*/include/* - echo "$GITHUB_WORKSPACE/llvm/bin" >> $GITHUB_PATH - - - name: Configure CMake and build - id: build - shell: bash - run: | - mkdir -p $HOME/.sccache - export CFLAGS="--target=x86_64-windows-msvc" - export CXXFLAGS="--target=x86_64-windows-msvc" - export LDFLAGS="--target=x86_64-windows-msvc" - cmake -B build -DBUILD_GEODE=OFF -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -G Ninja -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang - cmake --build build --config ${{env.BUILD_TYPE}} - - - name: Save artifacts - uses: actions/upload-artifact@v4 - with: - name: OpenHack-Standalone - path: ${{github.workspace}}/bin +# standalone: +# name: Vanilla OpenHack +# runs-on: windows-latest +# steps: +# - uses: actions/checkout@v4 +# with: +# submodules: recursive +# +# - name: Install Ninja +# shell: bash +# run: | +# curl -L https://github.com/ninja-build/ninja/releases/latest/download/ninja-win.zip -o ninja.zip +# 7z x ninja.zip -o"$GITHUB_WORKSPACE/ninja" +# echo "$GITHUB_WORKSPACE/ninja" >> $GITHUB_PATH +# +# - name: Update LLVM +# shell: bash +# run: | +# curl -L https://github.com/llvm/llvm-project/releases/download/llvmorg-17.0.6/LLVM-17.0.6-win64.exe -o llvm-inst.exe +# 7z x llvm-inst.exe -ollvm bin/clang.exe bin/clang++.exe bin/lld-link.exe bin/llvm-rc.exe bin/*.dll lib/clang/*/include/* +# echo "$GITHUB_WORKSPACE/llvm/bin" >> $GITHUB_PATH +# +# - name: Configure CMake and build +# id: build +# shell: bash +# run: | +# mkdir -p $HOME/.sccache +# export CFLAGS="--target=x86_64-windows-msvc" +# export CXXFLAGS="--target=x86_64-windows-msvc" +# export LDFLAGS="--target=x86_64-windows-msvc" +# cmake -B build -DBUILD_GEODE=OFF -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -G Ninja -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang +# cmake --build build --config ${{env.BUILD_TYPE}} +# +# - name: Save artifacts +# uses: actions/upload-artifact@v4 +# with: +# name: OpenHack-Standalone +# path: ${{github.workspace}}/bin package: name: Create Nightly Release runs-on: ubuntu-latest if: github.ref == 'refs/heads/lemonade' - needs: ['standalone', 'package-geode'] + needs: ['package-geode'] steps: - name: Download artifacts @@ -104,15 +104,15 @@ jobs: path: ${{ github.workspace }}/bin merge-multiple: true - - name: Prepare standalone zip - run: | - mkdir -p ${{ github.workspace }}/bin/standalone - cp -r ${{ github.workspace }}/bin/openhack ${{ github.workspace }}/bin/standalone/openhack - cp ${{ github.workspace }}/bin/xinput1_4.dll ${{ github.workspace }}/bin/standalone/xinput1_4.dll - - - name: Package standalone - run: | - 7z a -tzip ${{ github.workspace }}/bin/OpenHack-Nightly.zip ${{ github.workspace }}/bin/standalone/* +# - name: Prepare standalone zip +# run: | +# mkdir -p ${{ github.workspace }}/bin/standalone +# cp -r ${{ github.workspace }}/bin/openhack ${{ github.workspace }}/bin/standalone/openhack +# cp ${{ github.workspace }}/bin/xinput1_4.dll ${{ github.workspace }}/bin/standalone/xinput1_4.dll +# +# - name: Package standalone +# run: | +# 7z a -tzip ${{ github.workspace }}/bin/OpenHack-Nightly.zip ${{ github.workspace }}/bin/standalone/* - name: Get latest release tag id: get_latest_release @@ -133,7 +133,7 @@ jobs: Changes since the last release: https://github.com/Prevter/OpenHack/compare/${{ steps.get_latest_release.outputs.tag }}...nightly files: | - ${{ github.workspace }}/bin/OpenHack-Nightly.zip +# ${{ github.workspace }}/bin/OpenHack-Nightly.zip ${{ github.workspace }}/bin/prevter.openhack.geode ${{ github.workspace }}/bin/prevter.openhack.pdb - ${{ github.workspace }}/bin/xinput1_4.pdb +# ${{ github.workspace }}/bin/xinput1_4.pdb diff --git a/.gitmodules b/.gitmodules index 307f957..4474a22 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,6 @@ [submodule "libs/imgui"] path = libs/imgui url = https://github.com/prevter/imgui -[submodule "libs/gd.hpp"] - path = libs/gd.hpp - url = https://github.com/prevter/gd.hpp [submodule "libs/minhook"] path = libs/minhook url = https://github.com/TsudaKageyu/minhook diff --git a/CMakeLists.txt b/CMakeLists.txt index 4619915..959002a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -139,6 +139,11 @@ endif() # ======================================== # | Standalone build # ======================================== +if (BUILD_STANDALONE) + message(ERROR "Standalone build is deprecated, please use Geode instead") + return() +end() + if (NOT BUILD_STANDALONE) message(STATUS "Standalone build disabled") return() diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt index cdf1230..fd196f7 100644 --- a/libs/CMakeLists.txt +++ b/libs/CMakeLists.txt @@ -28,18 +28,22 @@ target_link_libraries( ) # Other libraries -add_subdirectory(gd.hpp) add_subdirectory(json) add_subdirectory(glfw) add_subdirectory(discord-rpc) add_subdirectory(zephyrus) +# Fix debug build +if (CMAKE_BUILD_TYPE STREQUAL "Debug" AND WIN32) + target_compile_definitions(discord-rpc PRIVATE _HAS_ITERATOR_DEBUGGING=0) + target_compile_definitions(Zephyrus PRIVATE _HAS_ITERATOR_DEBUGGING=0) +endif() + # Link all external libraries target_link_libraries( external_libs INTERFACE imgui glfw - gd.hpp nlohmann_json::nlohmann_json discord-rpc Zephyrus diff --git a/libs/gd.hpp b/libs/gd.hpp deleted file mode 160000 index a2ae0a3..0000000 --- a/libs/gd.hpp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a2ae0a3c7d6aac5dd99350043f3d1657539525dd diff --git a/mod.json b/mod.json index 8cf06be..3fc07cf 100644 --- a/mod.json +++ b/mod.json @@ -1,5 +1,5 @@ { - "geode": "2.0.0-beta.27", + "geode": "3.2.0", "gd": { "win": "2.206" }, @@ -28,7 +28,6 @@ "resources/licenses/*" ] }, - "early-load": true, "api": { "include": [ "api/*.hpp" diff --git a/src/geode/hooks/CCDrawNode.cpp b/src/geode/hooks/CCDrawNode.cpp index eea34a8..0ab2fe3 100644 --- a/src/geode/hooks/CCDrawNode.cpp +++ b/src/geode/hooks/CCDrawNode.cpp @@ -10,7 +10,7 @@ namespace openhack::hooks { // Fix border width being negative (robtop made a mirror portal bug) borderWidth = abs(borderWidth); - hacks::Hitboxes::modifyDraw((gd::cocos2d::CCDrawNode *) this, (gui::Color &) fillColor, borderWidth, (gui::Color &) borderColor); + hacks::Hitboxes::modifyDraw(this, (gui::Color &) fillColor, borderWidth, (gui::Color &) borderColor); return cocos2d::CCDrawNode::drawPolygon(vertex, count, fillColor, borderWidth, borderColor); } @@ -19,7 +19,7 @@ namespace openhack::hooks { // Fix border width being negative (robtop made a mirror portal bug) borderWidth = abs(borderWidth); - hacks::Hitboxes::modifyDraw((gd::cocos2d::CCDrawNode *) this, (gui::Color &) color, borderWidth, (gui::Color &) borderColor); + hacks::Hitboxes::modifyDraw(this, (gui::Color &) color, borderWidth, (gui::Color &) borderColor); return cocos2d::CCDrawNode::drawCircle(position, radius, color, borderWidth, borderColor, segments); } }; diff --git a/src/geode/hooks/ChannelControl.cpp b/src/geode/hooks/ChannelControl.cpp index 097f309..7379f6c 100644 --- a/src/geode/hooks/ChannelControl.cpp +++ b/src/geode/hooks/ChannelControl.cpp @@ -1,8 +1,6 @@ #include "../pch.hpp" #include -#include -#include #include "../../shared/hacks/speedhack/speedhack.hpp" namespace openhack::hooks::ChannelControl { @@ -13,9 +11,9 @@ namespace openhack::hooks::ChannelControl { } $execute { - (void) geode::Mod::get()->hook( - (void *) gd::findSignature("FMOD::ChannelControl::setVolume"), - &openhack::hooks::ChannelControl::setVolume, - "FMOD::ChannelControl::setVolume", - tulip::hook::TulipConvention::Stdcall); +// (void) geode::Mod::get()->hook( +// (void *) gd::findSignature("FMOD::ChannelControl::setVolume"), +// &openhack::hooks::ChannelControl::setVolume, +// "FMOD::ChannelControl::setVolume", +// tulip::hook::TulipConvention::Stdcall); } \ No newline at end of file diff --git a/src/geode/hooks/HardStreak.cpp b/src/geode/hooks/HardStreak.cpp index c01793b..226b840 100644 --- a/src/geode/hooks/HardStreak.cpp +++ b/src/geode/hooks/HardStreak.cpp @@ -7,7 +7,7 @@ namespace openhack::hooks { struct HardStreakHook : geode::Modify { void updateStroke(float dt) { - hacks::CustomWaveTrail::updateStroke(reinterpret_cast(this)); + hacks::CustomWaveTrail::updateStroke(this); HardStreak::updateStroke(dt); } }; diff --git a/src/geode/hooks/MainGameLayer.cpp b/src/geode/hooks/MainGameLayer.cpp index 6763689..8fd4f3b 100644 --- a/src/geode/hooks/MainGameLayer.cpp +++ b/src/geode/hooks/MainGameLayer.cpp @@ -4,25 +4,17 @@ #include namespace openhack::hooks::MenuGameLayerHook { - bool tryJump(MenuGameLayer *self, float dt) { - if (config::get("hack.menu_gameplay", false)) - return false; - return reinterpret_cast(self)->tryJump(dt); - } - - struct MenuGameLayerHook2 : geode::Modify { + struct MenuGameLayerHook : geode::Modify { void update(float dt) { - hacks::MenuGameplay::menuUpdate(reinterpret_cast(m_playerObject)); + hacks::MenuGameplay::menuUpdate(m_playerObject); MenuGameLayer::update(dt); } - }; -} -$execute { - (void) geode::Mod::get()->hook( - (void *) gd::findOffset("MenuGameLayer::tryJump"), - &openhack::hooks::MenuGameLayerHook::tryJump, - "MenuGameLayer::tryJump", - tulip::hook::TulipConvention::Thiscall); + void tryJump(float dt) { + if (config::get("hack.menu_gameplay", false)) + return; + return MenuGameLayer::tryJump(dt); + } + }; } diff --git a/src/geode/hooks/PauseLayer.cpp b/src/geode/hooks/PauseLayer.cpp index 0ee4bf7..6c23ce9 100644 --- a/src/geode/hooks/PauseLayer.cpp +++ b/src/geode/hooks/PauseLayer.cpp @@ -7,7 +7,7 @@ namespace openhack::hooks { struct PauseLayerHook : geode::Modify { void customSetup() { - hacks::HidePause::pauseInit(reinterpret_cast(this)); + hacks::HidePause::pauseInit(this); PauseLayer::customSetup(); } }; diff --git a/src/geode/hooks/PlayLayer.cpp b/src/geode/hooks/PlayLayer.cpp index ccd4b2e..0aa9b9c 100644 --- a/src/geode/hooks/PlayLayer.cpp +++ b/src/geode/hooks/PlayLayer.cpp @@ -18,7 +18,7 @@ namespace openhack::hooks { struct PlayLayerHook : geode::Modify { bool init(GJGameLevel *level, bool useReplay, bool dontCreateObjects) { - hacks::Display::playLayerInit(reinterpret_cast(level)); + hacks::Display::playLayerInit(level); hacks::AutoPickupCoins::initLevel(); hacks::StartPosSwitcher::initLevel(); hacks::Labels::playLayerInit(); @@ -49,13 +49,13 @@ namespace openhack::hooks { void addObject(GameObject *object) { PlayLayer::addObject(object); - hacks::AutoPickupCoins::addObject(reinterpret_cast(object)); - hacks::StartPosSwitcher::addObject(reinterpret_cast(object)); - hacks::SmartStartPos::addObject(reinterpret_cast(object)); + hacks::AutoPickupCoins::addObject(object); + hacks::StartPosSwitcher::addObject(object); + hacks::SmartStartPos::addObject(object); } void destroyPlayer(PlayerObject* player, GameObject* object) { - hacks::NoclipLimit::destroyPlayer(reinterpret_cast(object)); + hacks::NoclipLimit::destroyPlayer(object); PlayLayer::destroyPlayer(player, object); hacks::NoclipLimit::postDestroyPlayer(); hacks::Hitboxes::destroyPlayer(); diff --git a/src/geode/hooks/PlayerObject.cpp b/src/geode/hooks/PlayerObject.cpp index 1b1f5b1..efb71b3 100644 --- a/src/geode/hooks/PlayerObject.cpp +++ b/src/geode/hooks/PlayerObject.cpp @@ -7,14 +7,14 @@ namespace openhack::hooks { struct PlayerObjectHook : geode::Modify { void pushButton(PlayerButton btn) { - hacks::Zephyrus::PlayerObjectPushButton(reinterpret_cast(this), static_cast(btn)); - hacks::Labels::pushButton(reinterpret_cast(this)); + hacks::Zephyrus::PlayerObjectPushButton(this, static_cast(btn)); + hacks::Labels::pushButton(this); PlayerObject::pushButton(btn); } void releaseButton(PlayerButton btn) { - hacks::Zephyrus::PlayerObjectReleaseButton(reinterpret_cast(this), static_cast(btn)); - hacks::Labels::releaseButton(reinterpret_cast(this)); + hacks::Zephyrus::PlayerObjectReleaseButton(this, static_cast(btn)); + hacks::Labels::releaseButton(this); PlayerObject::releaseButton(btn); } }; diff --git a/src/geode/utils.cpp b/src/geode/utils.cpp index cc34b4a..faa1876 100644 --- a/src/geode/utils.cpp +++ b/src/geode/utils.cpp @@ -4,11 +4,11 @@ namespace openhack::utils { std::filesystem::path getModSaveDirectory() noexcept { - return static_cast(geode::Mod::get()->getSaveDir()); + return geode::Mod::get()->getSaveDir(); } std::filesystem::path getModAssetsDirectory() noexcept { - return static_cast(geode::Mod::get()->getResourcesDir()); + return geode::Mod::get()->getResourcesDir(); } std::filesystem::path getModFontsDirectory() noexcept { diff --git a/src/shared/config.cpp b/src/shared/config.cpp index 0109a01..8330689 100644 --- a/src/shared/config.cpp +++ b/src/shared/config.cpp @@ -3,9 +3,19 @@ #include -#include "hacks/labels/labels.hpp" +// #include "hacks/labels/labels.hpp" namespace openhack::config { + nlohmann::json& getStorage() { + static nlohmann::json storage; + return storage; + } + + nlohmann::json& getGlobals() { + static nlohmann::json globals; + return globals; + } + void setDefaults() { setIfEmpty("menu.animationTime", 0.35); setIfEmpty("menu.easingType", gui::animation::Easing::Cubic); @@ -40,11 +50,11 @@ namespace openhack::config { return; } - storage = nlohmann::json::parse(file, nullptr, false); - if (storage.is_discarded()) { + getStorage() = nlohmann::json::parse(file, nullptr, false); + if (getStorage().is_discarded()) { file.close(); L_WARN("Failed to parse config file, creating a new one"); - storage = nlohmann::json(); + getStorage() = nlohmann::json(); save(); } else { file.close(); @@ -52,11 +62,11 @@ namespace openhack::config { } void save() { - hacks::Labels::save(); + // hacks::Labels::save(); auto path = utils::getModSaveDirectory() / "config.json"; std::ofstream file(path); - file << storage.dump(4); + file << getStorage().dump(4); file.close(); } } diff --git a/src/shared/config.hpp b/src/shared/config.hpp index f65b29c..9c490e0 100644 --- a/src/shared/config.hpp +++ b/src/shared/config.hpp @@ -8,14 +8,14 @@ /// @brief Namespace for all save data and configuration. namespace openhack::config { - inline nlohmann::json storage; // Object that holds options which are saved to disk - inline nlohmann::json globals; // Object that holds temporary values + nlohmann::json& getStorage(); + nlohmann::json& getGlobals(); /// @brief Check if a key exists in the configuration. /// @param key Key to check. /// @return True if the key exists in the configuration. inline bool has(const std::string &key) { - return storage.contains(key); + return getStorage().contains(key); } /// @brief Get a value by key from the configuration. @@ -28,7 +28,7 @@ namespace openhack::config { if (!has(key)) return defaultValue; - return storage.at(key).get(); + return getStorage().at(key).get(); } /// @brief Get a value by key from the configuration. @@ -41,7 +41,7 @@ namespace openhack::config { if (!has(key)) throw std::runtime_error("Key " + key + " does not exist"); - return storage.at(key).get(); + return getStorage().at(key).get(); } /// @brief Set a value by key in the configuration. @@ -50,7 +50,7 @@ namespace openhack::config { /// @param value Value to set. template inline void set(const std::string &key, const T &value) { - storage[key] = value; + getStorage()[key] = value; } /// @brief Check if the value is of the specified type. @@ -63,7 +63,7 @@ namespace openhack::config { return false; try { - storage.at(key).get(); + getStorage().at(key).get(); return true; } catch (const nlohmann::json::exception &e) { return false; @@ -84,7 +84,7 @@ namespace openhack::config { /// @param key Key to check. /// @return True if the key exists in the global variables. inline bool hasGlobal(const std::string &key) { - return globals.contains(key); + return getGlobals().contains(key); } /// @brief Get a value by key from the global variables. @@ -97,7 +97,7 @@ namespace openhack::config { if (!hasGlobal(key)) return defaultValue; - return globals.at(key).get(); + return getGlobals().at(key).get(); } /// @brief Get a value by key from the global variables. @@ -110,7 +110,7 @@ namespace openhack::config { if (!hasGlobal(key)) throw std::runtime_error("Key " + key + " does not exist"); - return globals.at(key).get(); + return getGlobals().at(key).get(); } /// @brief Set a value by key in the global variables. @@ -119,7 +119,7 @@ namespace openhack::config { /// @param value Value to set. template inline void setGlobal(const std::string &key, const T &value) { - globals[key] = value; + getGlobals()[key] = value; } /// @brief Set the default values for the configuration. diff --git a/src/shared/gui/themes/gruvbox/gruvbox.cpp b/src/shared/gui/themes/gruvbox/gruvbox.cpp index 5e2a0df..d3a0778 100644 --- a/src/shared/gui/themes/gruvbox/gruvbox.cpp +++ b/src/shared/gui/themes/gruvbox/gruvbox.cpp @@ -78,7 +78,7 @@ namespace openhack::gui { bool GruvboxCheckbox(const char *label, bool value, float width = -1.0f) { auto *drawList = ImGui::GetWindowDrawList(); auto pos = ImGui::GetCursorScreenPos(); - auto scale = config::getGlobal("UIScale"); + auto scale = config::getGlobal("UIScale", 1.f); auto padding = scale * 3; auto size = ImGui::GetFrameHeight() - padding * 2; auto frameColor = ImGui::GetColorU32(ImGuiCol_FrameBg); diff --git a/src/shared/hacks/accurate-percentage/accurate-percentage.cpp b/src/shared/hacks/accurate-percentage/accurate-percentage.cpp index 8b13d53..e44df18 100644 --- a/src/shared/hacks/accurate-percentage/accurate-percentage.cpp +++ b/src/shared/hacks/accurate-percentage/accurate-percentage.cpp @@ -4,23 +4,23 @@ namespace openhack::hacks { float AccuratePercentage::getPercentage(bool oldEvaluation) { - auto *playLayer = gd::PlayLayer::get(); + auto *playLayer = PlayLayer::get(); if (!playLayer) return 0.f; if (oldEvaluation) { - float playerX = playLayer->m_player1()->getPositionX(); - float endX = playLayer->m_endPortal()->getPositionX(); + float playerX = playLayer->m_player1->getPositionX(); + float endX = playLayer->m_endPortal->getPositionX(); return playerX / endX * 100.f; } - auto *level = playLayer->m_level(); - auto timestamp = level->m_timestamp(); + auto *level = playLayer->m_level; + auto timestamp = level->m_timestamp; float percent; if (timestamp > 0) { - percent = static_cast(playLayer->m_gameState().m_stepSpeed()) / timestamp * 100.f; + /// percent = static_cast(playLayer->m_gameState.m_stepSpeed) / timestamp * 100.f; } else { - percent = playLayer->m_player1()->m_position().x / playLayer->m_levelLength() * 100.f; + percent = playLayer->m_player1->m_position.x / playLayer->m_levelLength * 100.f; } if (percent >= 100.f) return 100.f; @@ -67,30 +67,30 @@ namespace openhack::hacks { void AccuratePercentage::postUpdate() { if (!config::get("hack.accurate_percentage.enabled", false)) return; - auto* playLayer = gd::PlayLayer::get(); + auto* playLayer = PlayLayer::get(); if (!playLayer) return; - auto* label = playLayer->m_percentageLabel(); + auto* label = playLayer->m_percentageLabel; if (!label) return; - bool isPlatformer = playLayer->m_level()->isPlatformer(); + bool isPlatformer = playLayer->m_level->isPlatformer(); if (isPlatformer) { bool showMinutes = config::get("hack.accurate_percentage.show_minutes"); if (showMinutes) { - auto time = playLayer->m_dTime(); + auto time = playLayer->m_gameState.m_levelTime; int minutes = (int) time / 60; int seconds = (int) time % 60; int millis = (int) (time * 1000) % 1000; if (minutes > 0) - label->setString(fmt::format("{}:{:02d}.{:03d}", minutes, seconds, millis)); + label->setString(fmt::format("{}:{:02d}.{:03d}", minutes, seconds, millis).c_str()); else - label->setString(fmt::format("{}.{:03d}", seconds, millis)); + label->setString(fmt::format("{}.{:03d}", seconds, millis).c_str()); } } else if (config::get("hack.accurate_percentage.normal_mode")) { bool oldEvaluation = config::get("hack.accurate_percentage.old_eval"); float percent = getPercentage(oldEvaluation); int decimalPlaces = floor(config::get("hack.accurate_percentage.decimal_places", 6.f)); - label->setString(fmt::format("{:.{}f}%", percent, decimalPlaces)); + label->setString(fmt::format("{:.{}f}%", percent, decimalPlaces).c_str()); } } diff --git a/src/shared/hacks/auto-deafen/auto-deafen.cpp b/src/shared/hacks/auto-deafen/auto-deafen.cpp index d2bee4c..1565e5d 100644 --- a/src/shared/hacks/auto-deafen/auto-deafen.cpp +++ b/src/shared/hacks/auto-deafen/auto-deafen.cpp @@ -56,7 +56,7 @@ namespace openhack::hacks { if (!config::get("hack.auto_deafen.enabled", false)) return; // Get PlayLayer - auto *playLayer = gd::PlayLayer::get(); + auto *playLayer = PlayLayer::get(); if (playLayer == nullptr) return setState(false); // Get the current percentage @@ -69,12 +69,12 @@ namespace openhack::hacks { bool testMode = config::get("hack.auto_deafen.test_mode", false); // Ignore practice and test mode if disabled - if (!practice && playLayer->m_isPracticeMode()) return setState(false); - if (!testMode && playLayer->m_isTestMode()) return setState(false); + if (!practice && playLayer->m_isPracticeMode) return setState(false); + if (!testMode && playLayer->m_isTestMode) return setState(false); // Check if paused, level ended or died - auto* player = playLayer->m_player1(); - if (playLayer->m_isPaused() || playLayer->m_hasCompletedLevel() || player->m_isDead()) + auto* player = playLayer->m_player1; + if (playLayer->m_isPaused || playLayer->m_hasCompletedLevel || player->m_isDead) return setState(false); setState(percentage >= startPercentage && percentage <= endPercentage); diff --git a/src/shared/hacks/auto-kill/auto-kill.cpp b/src/shared/hacks/auto-kill/auto-kill.cpp index 2424c26..c9ce8e6 100644 --- a/src/shared/hacks/auto-kill/auto-kill.cpp +++ b/src/shared/hacks/auto-kill/auto-kill.cpp @@ -3,14 +3,14 @@ namespace openhack::hacks { - inline float getCurrentPercent(gd::PlayLayer *playLayer) { + inline float getCurrentPercent(PlayLayer *playLayer) { float percent; - auto *level = playLayer->m_level(); - auto timestamp = level->m_timestamp(); + auto *level = playLayer->m_level; + auto timestamp = level->m_timestamp; if (timestamp > 0) { - percent = static_cast(playLayer->m_gameState().m_stepSpeed()) / timestamp * 100.f; + percent = static_cast(playLayer->m_gameState.m_currentProgress) / timestamp * 100.f; } else { - percent = playLayer->m_player1()->m_position().x / playLayer->m_levelLength() * 100.f; + percent = playLayer->m_player1->m_position.x / playLayer->m_levelLength * 100.f; } if (percent >= 100.f) return 100.f; @@ -57,13 +57,13 @@ namespace openhack::hacks { } void AutoKill::killPlayer() { - auto *playLayer = gd::PlayLayer::get(); + auto *playLayer = PlayLayer::get(); if (playLayer == nullptr) return; // Toggle noclip off to make sure the player dies hacks::getHack("level.noclip")->applyPatch(false); - auto *player = playLayer->m_player1(); - if (player != nullptr && !player->m_isDead()) { + auto *player = playLayer->m_player1; + if (player != nullptr && !player->m_isDead) { playLayer->destroyPlayer(player, player); } hacks::getHack("level.noclip")->applyPatch(); @@ -73,11 +73,11 @@ namespace openhack::hacks { if (!config::get("hack.auto_kill.enabled", false)) return; // Get PlayLayer - auto *playLayer = gd::PlayLayer::get(); + auto *playLayer = PlayLayer::get(); if (playLayer == nullptr) return; float percentage = getCurrentPercent(playLayer); - double time = playLayer->m_dTime(); + double time = playLayer->m_gameState.m_levelTime; bool checkPercentage = config::get("hack.auto_kill.use_percentage"); bool checkTime = config::get("hack.auto_kill.use_time"); diff --git a/src/shared/hacks/auto-pickup-coins/auto-pickup-coins.cpp b/src/shared/hacks/auto-pickup-coins/auto-pickup-coins.cpp index acabf16..2cf2444 100644 --- a/src/shared/hacks/auto-pickup-coins/auto-pickup-coins.cpp +++ b/src/shared/hacks/auto-pickup-coins/auto-pickup-coins.cpp @@ -3,7 +3,7 @@ namespace openhack::hacks { - std::vector AutoPickupCoins::m_coins; + std::vector AutoPickupCoins::m_coins; void AutoPickupCoins::onInit() { // Set the default value @@ -33,8 +33,8 @@ namespace openhack::hacks { m_coins.clear(); } - void AutoPickupCoins::addObject(gd::GameObject *object) { - uint32_t id = object->m_objectID(); + void AutoPickupCoins::addObject(GameObject *object) { + uint32_t id = object->m_objectID; if (id == 142 || id == 1329) { m_coins.push_back(object); } @@ -44,14 +44,14 @@ namespace openhack::hacks { if (!config::get("hack.auto_pickup_coins.enabled", false)) return; // Get PlayLayer - auto *playLayer = gd::PlayLayer::get(); + auto *playLayer = PlayLayer::get(); // Pickup all coins from m_coins for (auto *coin : m_coins) { if (coin == nullptr) continue; // Pickup the coin - playLayer->pickupItem(coin); + playLayer->pickupItem(static_cast(coin)); playLayer->destroyObject(coin); } } diff --git a/src/shared/hacks/auto-pickup-coins/auto-pickup-coins.hpp b/src/shared/hacks/auto-pickup-coins/auto-pickup-coins.hpp index 2620f9f..e970ffd 100644 --- a/src/shared/hacks/auto-pickup-coins/auto-pickup-coins.hpp +++ b/src/shared/hacks/auto-pickup-coins/auto-pickup-coins.hpp @@ -19,12 +19,12 @@ namespace openhack::hacks { /// @brief PlayLayer::init hook static void initLevel(); /// @brief PlayLayer::addObject hook - static void addObject(gd::GameObject *object); + static void addObject(GameObject *object); /// @brief PlayLayer::resetLevel hook static void resetLevel(); private: - static std::vector m_coins; + static std::vector m_coins; }; } \ No newline at end of file diff --git a/src/shared/hacks/auto-save/auto-save.cpp b/src/shared/hacks/auto-save/auto-save.cpp index 5b8b135..3f20900 100644 --- a/src/shared/hacks/auto-save/auto-save.cpp +++ b/src/shared/hacks/auto-save/auto-save.cpp @@ -34,7 +34,7 @@ namespace openhack::hacks { void AutoSave::triggerSave() { bool prompt = config::get("hack.auto_save.prompt_on_save"); if (!prompt) { - gd::AppDelegate::get()->trySaveGame(true); + AppDelegate::get()->trySaveGame(true); return; } @@ -43,7 +43,7 @@ namespace openhack::hacks { "Do you want to save the game?", "Yes", "No", [](bool confirmed) { if (confirmed) { - gd::AppDelegate::get()->trySaveGame(true); + AppDelegate::get()->trySaveGame(true); } }); } @@ -51,8 +51,8 @@ namespace openhack::hacks { void AutoSave::onLevelQuit() { if (!config::get("hack.auto_save.enabled")) return; - auto *playLayer = gd::PlayLayer::get(); - if (!playLayer || playLayer->m_level()->m_levelID().value() == 0) + auto *playLayer = PlayLayer::get(); + if (!playLayer || playLayer->m_level->m_levelID.value() == 0) return; triggerSave(); diff --git a/src/shared/hacks/click-tp/click-tp.cpp b/src/shared/hacks/click-tp/click-tp.cpp index 3c5d32d..4412e16 100644 --- a/src/shared/hacks/click-tp/click-tp.cpp +++ b/src/shared/hacks/click-tp/click-tp.cpp @@ -23,10 +23,10 @@ namespace openhack::hacks { }); } - ImVec2 screenToGame(ImVec2 screenPos, gd::PlayLayer *playLayer) { - auto cameraPos = playLayer->m_gameState().m_cameraPosition(); - auto cameraScale = playLayer->m_gameState().m_cameraScale(); - auto cameraAngle = playLayer->m_gameState().m_cameraAngle(); + ImVec2 screenToGame(ImVec2 screenPos, PlayLayer *playLayer) { + auto cameraPos = playLayer->m_gameState.m_cameraPosition; + auto cameraScale = playLayer->m_gameState.m_cameraZoom; + auto cameraAngle = playLayer->m_gameState.m_cameraAngle; // Rotate the position around the camera angle // TODO: Fix rotation @@ -46,14 +46,14 @@ namespace openhack::hacks { if (!config::get("hack.click_tp.enabled", false)) return; // Always show the cursor - gd::cocos2d::CCEGLView::sharedOpenGLView()->showCursor(true); + cocos2d::CCEGLView::sharedOpenGLView()->showCursor(true); // Check if the right mouse button is pressed if (!utils::isKeyPressed("RMB")) return; // Check if the player is in the play layer - if (auto *playLayer = gd::PlayLayer::get()) { - auto *player = playLayer->m_player1(); + if (auto *playLayer = PlayLayer::get()) { + auto *player = playLayer->m_player1; if (!player) return; ImVec2 mousePos = ImGui::GetMousePos(); @@ -63,7 +63,7 @@ namespace openhack::hacks { auto teleportPos = screenToGame({framePos.x, framePos.y}, playLayer); // Teleport the player - player->m_position({teleportPos.x, teleportPos.y}); + player->m_position = cocos2d::CCPoint {teleportPos.x, teleportPos.y}; } } diff --git a/src/shared/hacks/custom-wave-trail/custom-wave-trail.cpp b/src/shared/hacks/custom-wave-trail/custom-wave-trail.cpp index 6a82ce0..0133d18 100644 --- a/src/shared/hacks/custom-wave-trail/custom-wave-trail.cpp +++ b/src/shared/hacks/custom-wave-trail/custom-wave-trail.cpp @@ -61,7 +61,7 @@ namespace openhack::hacks { }, ImVec2(0, 0)); } - void CustomWaveTrail::updateStroke(gd::HardStreak *streak) { + void CustomWaveTrail::updateStroke(HardStreak *streak) { if (!config::get("hack.custom_wave_trail.enabled", false)) return; gui::Color target; @@ -80,7 +80,7 @@ namespace openhack::hacks { } if (changeColor) { - reinterpret_cast(streak)->setColor({ + streak->setColor({ static_cast(target.r * 255), static_cast(target.g * 255), static_cast(target.b * 255) @@ -88,7 +88,7 @@ namespace openhack::hacks { } auto scale = config::get("hack.custom_wave_trail.scale"); - streak->m_pulseSize() = scale; + streak->m_pulseSize = scale; } } \ No newline at end of file diff --git a/src/shared/hacks/custom-wave-trail/custom-wave-trail.hpp b/src/shared/hacks/custom-wave-trail/custom-wave-trail.hpp index 0132fa1..2677f4d 100644 --- a/src/shared/hacks/custom-wave-trail/custom-wave-trail.hpp +++ b/src/shared/hacks/custom-wave-trail/custom-wave-trail.hpp @@ -16,7 +16,7 @@ namespace openhack::hacks { public: /// @brief PlayLayer::postUpdate hook - static void updateStroke(gd::HardStreak* streak); + static void updateStroke(HardStreak* streak); }; } \ No newline at end of file diff --git a/src/shared/hacks/discord-rpc/discord-rpc.cpp b/src/shared/hacks/discord-rpc/discord-rpc.cpp index ac27163..6b40fb2 100644 --- a/src/shared/hacks/discord-rpc/discord-rpc.cpp +++ b/src/shared/hacks/discord-rpc/discord-rpc.cpp @@ -194,15 +194,15 @@ namespace openhack::hacks { } } - std::string DiscordRPC::replaceTokens(const char *id, gd::PlayLayer *playLayer, gd::LevelEditorLayer *editorLayer) { + std::string DiscordRPC::replaceTokens(const char *id, PlayLayer *playLayer, LevelEditorLayer *editorLayer) { auto str = config::get(id); return Labels::replaceTokens(str, playLayer, editorLayer); } /// @brief Get the current state of the game and return corresponding strings DiscordRPCState DiscordRPC::getState() { - if (auto playLayer = gd::PlayLayer::get()) { - if (playLayer->m_level()->m_levelLength() == gd::GJLevelLength::Platformer) { + if (auto playLayer = PlayLayer::get()) { + if (playLayer->m_level->isPlatformer()) { // Playing a platformer level return { replaceTokens("hack.discord_rpc.platformer.state", playLayer), @@ -221,7 +221,7 @@ namespace openhack::hacks { playLayer, nullptr, }; - } else if (auto editorLayer = gd::LevelEditorLayer::get()) { + } else if (auto editorLayer = LevelEditorLayer::get()) { // Editing a level return { replaceTokens("hack.discord_rpc.editor.state", nullptr, editorLayer), diff --git a/src/shared/hacks/discord-rpc/discord-rpc.hpp b/src/shared/hacks/discord-rpc/discord-rpc.hpp index 34ed5a0..8ec4c3f 100644 --- a/src/shared/hacks/discord-rpc/discord-rpc.hpp +++ b/src/shared/hacks/discord-rpc/discord-rpc.hpp @@ -9,8 +9,8 @@ namespace openhack::hacks { std::string details; std::string imageKey; std::string imageText; - gd::PlayLayer *playLayer; - gd::LevelEditorLayer *editorLayer; + PlayLayer *playLayer; + LevelEditorLayer *editorLayer; }; /// @brief Discord Rich Presence integration @@ -34,7 +34,7 @@ namespace openhack::hacks { /// @brief Gets the string from config and replaces all tokens with their values /// @param id The string to replace tokens in /// @return The string with tokens replaced - static std::string replaceTokens(const char *id, gd::PlayLayer *playLayer = nullptr, gd::LevelEditorLayer *editorLayer = nullptr); + static std::string replaceTokens(const char *id, PlayLayer *playLayer = nullptr, LevelEditorLayer *editorLayer = nullptr); }; } \ No newline at end of file diff --git a/src/shared/hacks/display/display.cpp b/src/shared/hacks/display/display.cpp index 8dc6eb7..142eb75 100644 --- a/src/shared/hacks/display/display.cpp +++ b/src/shared/hacks/display/display.cpp @@ -124,8 +124,8 @@ namespace openhack::hacks { void Display::onLateInit() { // Set default values - auto *manager = gd::GameManager::sharedState(); - config::set("hack.display.fps", manager->m_customFPSTarget()); + auto *manager = GameManager::sharedState(); + config::set("hack.display.fps", manager->m_customFPSTarget); config::set("hack.display.unlock_fps", manager->getGameVariable("0116")); config::setIfEmpty("hack.display.pfps", 240.0f); config::setIfEmpty("hack.display.physics_bypass", false); @@ -140,8 +140,8 @@ namespace openhack::hacks { } void Display::refreshRate() { - auto *application = gd::cocos2d::CCApplication::sharedApplication(); - auto *manager = gd::GameManager::sharedState(); + auto *application = cocos2d::CCApplication::sharedApplication(); + auto *manager = GameManager::sharedState(); // Get settings bool vsync = config::get("hack.display.vsync"); @@ -169,7 +169,7 @@ namespace openhack::hacks { // Set FPS if (unlockFps) { auto fps = config::get("hack.display.fps"); - manager->m_customFPSTarget(fps); + manager->m_customFPSTarget = fps; } manager->updateCustomFPS(); @@ -185,17 +185,19 @@ namespace openhack::hacks { bool bypass = config::get("hack.display.physics_bypass"); float pfps = bypass ? config::get("hack.display.pfps") : 240.0f; - utils::writeMemory(config::getGlobal("physicsTickAddr"), 1.f / pfps); - - auto *playLayer = gd::PlayLayer::get(); - if (playLayer && playLayer->m_level()->m_timestamp() > 0) { - auto startTimestamp = config::getGlobal("startTimestamp"); - float timeMultiplier = pfps / 240.0f; - float stepsMultiplier = (startTimestamp * timeMultiplier) / playLayer->m_level()->m_timestamp(); - float originalValue = playLayer->m_gameState().m_stepSpeed(); - playLayer->m_level()->m_timestamp(startTimestamp * timeMultiplier); - playLayer->m_gameState().m_stepSpeed(originalValue * stepsMultiplier); - } + auto addr = config::getGlobal("physicsTickAddr", 0); + if (!addr) return; + utils::writeMemory(addr, 1.f / pfps); + +// auto *playLayer = PlayLayer::get(); +// if (playLayer && playLayer->m_level->m_timestamp > 0) { +// auto startTimestamp = config::getGlobal("startTimestamp"); +// float timeMultiplier = pfps / 240.0f; +// float stepsMultiplier = (startTimestamp * timeMultiplier) / playLayer->m_level->m_timestamp(); +// float originalValue = playLayer->m_gameState.m_currentProgress; +// playLayer->m_level->m_timestamp = (startTimestamp * timeMultiplier); +// playLayer->m_gameState.m_currentProgress = (originalValue * stepsMultiplier); +// } } bool Display::isCheating() { @@ -203,8 +205,8 @@ namespace openhack::hacks { config::get("hack.display.pfps") != 240.0f); } - void Display::playLayerInit(gd::GJGameLevel *level) { - config::setGlobal("startTimestamp", level->m_timestamp()); + void Display::playLayerInit(GJGameLevel *level) { + config::setGlobal("startTimestamp", level->m_timestamp); } void Display::playLayerReset() { @@ -214,7 +216,7 @@ namespace openhack::hacks { static double s_extraDeltaTime = 0; void Display::schedulerUpdate(float dt, const std::function& original) { - if (!config::get("hack.display.tps_bypass") || !gd::PlayLayer::get()) { + if (!config::get("hack.display.tps_bypass") || !PlayLayer::get()) { original(dt); return; } diff --git a/src/shared/hacks/display/display.hpp b/src/shared/hacks/display/display.hpp index 093ec15..23a9c92 100644 --- a/src/shared/hacks/display/display.hpp +++ b/src/shared/hacks/display/display.hpp @@ -23,7 +23,7 @@ namespace openhack::hacks { public: /// @brief PlayLayer::init hook - static void playLayerInit(gd::GJGameLevel *level); + static void playLayerInit(GJGameLevel *level); /// @brief PlayLayer::resetLevel hook static void playLayerReset(); diff --git a/src/shared/hacks/hacks.cpp b/src/shared/hacks/hacks.cpp index 106a4ac..92aa568 100644 --- a/src/shared/hacks/hacks.cpp +++ b/src/shared/hacks/hacks.cpp @@ -1,6 +1,5 @@ #include "hacks.hpp" #include "../openhack.hpp" -#include #include "hack-list.hpp" namespace openhack::hacks { diff --git a/src/shared/hacks/hacks.hpp b/src/shared/hacks/hacks.hpp index f06a598..29bcda1 100644 --- a/src/shared/hacks/hacks.hpp +++ b/src/shared/hacks/hacks.hpp @@ -4,7 +4,7 @@ #include #include -#include +#include "../platform/win32/sigscan.hpp" #include "../gui/gui.hpp" #include "../gui/window.hpp" diff --git a/src/shared/hacks/hide-pause/hide-pause.cpp b/src/shared/hacks/hide-pause/hide-pause.cpp index 303dec0..db03132 100644 --- a/src/shared/hacks/hide-pause/hide-pause.cpp +++ b/src/shared/hacks/hide-pause/hide-pause.cpp @@ -3,14 +3,14 @@ namespace openhack::hacks { - gd::PauseLayer* g_pauseLayer = nullptr; + PauseLayer* g_pauseLayer = nullptr; void updatePauseVisibility() { if (!g_pauseLayer) return; - __try { + if (PlayLayer::get()->m_isPaused) { bool enabled = config::get("hack.hide_pause.enabled", false); g_pauseLayer->setVisible(!enabled); - } __except (EXCEPTION_EXECUTE_HANDLER) { + } else { g_pauseLayer = nullptr; } } @@ -39,7 +39,7 @@ namespace openhack::hacks { }); } - void HidePause::pauseInit(gd::PauseLayer *self) { + void HidePause::pauseInit(PauseLayer *self) { g_pauseLayer = self; updatePauseVisibility(); } diff --git a/src/shared/hacks/hide-pause/hide-pause.hpp b/src/shared/hacks/hide-pause/hide-pause.hpp index 21a7319..8f7e1ac 100644 --- a/src/shared/hacks/hide-pause/hide-pause.hpp +++ b/src/shared/hacks/hide-pause/hide-pause.hpp @@ -16,7 +16,7 @@ namespace openhack::hacks { public: /// @brief PauseLayer::updateVisibility hook - static void pauseInit(gd::PauseLayer *self); + static void pauseInit(PauseLayer *self); }; diff --git a/src/shared/hacks/hide-triggers/hide-triggers.cpp b/src/shared/hacks/hide-triggers/hide-triggers.cpp index 3bc766b..3edaa32 100644 --- a/src/shared/hacks/hide-triggers/hide-triggers.cpp +++ b/src/shared/hacks/hide-triggers/hide-triggers.cpp @@ -9,7 +9,7 @@ namespace openhack::hacks { - static std::vector triggers; + static std::vector triggers; void HideTriggers::onInit() { // Set the default value @@ -34,15 +34,15 @@ namespace openhack::hacks { void HideTriggers::onPlaytest() { if (!config::get("hack.hide_triggers.enabled")) return; - auto *editorLayer = gd::LevelEditorLayer::get(); + auto *editorLayer = LevelEditorLayer::get(); if (!editorLayer) return; triggers.clear(); - auto objects = reinterpret_cast(editorLayer->m_objects()); + auto objects = editorLayer->m_objects; for (int i = 0; i < objects->count(); i++) { auto obj = objects->objectAtIndex(i); - auto* gameObject = reinterpret_cast(obj); - if (gameObject->m_objectType() == gd::GameObjectType::Modifier) { + auto* gameObject = reinterpret_cast(obj); + if (gameObject->m_objectType == GameObjectType::Modifier) { triggers.push_back(gameObject); } } diff --git a/src/shared/hacks/hitboxes/hitboxes.cpp b/src/shared/hacks/hitboxes/hitboxes.cpp index bf0ae17..50ed94a 100644 --- a/src/shared/hacks/hitboxes/hitboxes.cpp +++ b/src/shared/hacks/hitboxes/hitboxes.cpp @@ -6,8 +6,8 @@ namespace openhack::hacks { struct PlayerHitbox { - gd::cocos2d::CCRect hitbox; - gd::cocos2d::CCRect tinyHitbox; + cocos2d::CCRect hitbox; + cocos2d::CCRect tinyHitbox; }; static ToggleComponent *s_hitboxesToggle = nullptr; @@ -45,18 +45,18 @@ namespace openhack::hacks { /// @brief Check whether hitboxes made by RobTop should be drawn. (e.g. in practice mode) inline bool robtopHitboxCheck() { - auto *playLayer = gd::PlayLayer::get(); + auto *playLayer = PlayLayer::get(); if (!playLayer) return false; - return playLayer->m_isPracticeMode() && gd::GameManager::sharedState()->getGameVariable("0166"); + return playLayer->m_isPracticeMode && GameManager::get()->getGameVariable("0166"); } /// @brief Clears the hitboxes if the feature is disabled. inline void toggleOffIfNeeded() { if (isEnabled()) return; - auto *playLayer = gd::PlayLayer::get(); + auto *playLayer = PlayLayer::get(); if (!playLayer) return; - auto *debugDrawNode = playLayer->m_debugDrawNode(); + auto *debugDrawNode = playLayer->m_debugDrawNode; if (!debugDrawNode) return; // Toggle the visibility of the debug draw node @@ -189,26 +189,23 @@ namespace openhack::hacks { return config::get("hack.hitboxes.enabled", false); } - gd::cocos2d::CCRect getPlayerHitbox(gd::PlayerObject *player) { - auto *rect = player->getObjectRect(); - return {rect->origin.x, rect->origin.y, rect->size.width, rect->size.height}; - } - - inline void drawRect(gd::cocos2d::CCDrawNode *node, const gd::cocos2d::CCRect &rect, const gui::Color &color, + inline void drawRect(cocos2d::CCDrawNode *node, const cocos2d::CCRect &rect, const gui::Color &color, float borderWidth, const gui::Color &borderColor) { - std::vector vertices = { - gd::cocos2d::CCPoint(rect.getMinX(), rect.getMinY()), - gd::cocos2d::CCPoint(rect.getMinX(), rect.getMaxY()), - gd::cocos2d::CCPoint(rect.getMaxX(), rect.getMaxY()), - gd::cocos2d::CCPoint(rect.getMaxX(), rect.getMinY()) + std::vector vertices = { + cocos2d::CCPoint(rect.getMinX(), rect.getMinY()), + cocos2d::CCPoint(rect.getMinX(), rect.getMaxY()), + cocos2d::CCPoint(rect.getMaxX(), rect.getMaxY()), + cocos2d::CCPoint(rect.getMaxX(), rect.getMinY()) }; s_skipDrawHook = true; - node->drawPolygon(vertices.data(), vertices.size(), - (const gd::cocos2d::_ccColor4F &) color, borderWidth, - (const gd::cocos2d::_ccColor4F &) borderColor); + node->drawPolygon( + vertices.data(), vertices.size(), + (const cocos2d::_ccColor4F &) color, borderWidth, + (const cocos2d::_ccColor4F &) borderColor + ); } - inline gd::cocos2d::CCRect scaleHitbox(const gd::cocos2d::CCRect &rect, float scale) { + inline cocos2d::CCRect scaleHitbox(const cocos2d::CCRect &rect, float scale) { auto width = rect.size.width * scale; auto height = rect.size.height * scale; auto x = rect.origin.x + (rect.size.width - width) / 2; @@ -231,15 +228,15 @@ namespace openhack::hacks { return HitboxType::Danger; } - void Hitboxes::modifyDraw(gd::cocos2d::CCDrawNode *node, gui::Color &color, float &borderWidth, + void Hitboxes::modifyDraw(cocos2d::CCDrawNode *node, gui::Color &color, float &borderWidth, gui::Color &borderColor) { if (s_skipDrawHook) { s_skipDrawHook = false; return; } - if (!gd::PlayLayer::get()) return; - if (node != gd::PlayLayer::get()->m_debugDrawNode()) return; + if (!PlayLayer::get()) return; + if (node != PlayLayer::get()->m_debugDrawNode) return; if (!shouldDrawHitboxes()) return; bool accuratePlayer = false; @@ -278,8 +275,8 @@ namespace openhack::hacks { void Hitboxes::postUpdate() { if (!isEnabled()) return; - auto *playLayer = gd::PlayLayer::get(); - auto *debugDrawNode = playLayer->m_debugDrawNode(); + auto *playLayer = PlayLayer::get(); + auto *debugDrawNode = playLayer->m_debugDrawNode; bool enabled = shouldDrawHitboxes(); debugDrawNode->setVisible(enabled || robtopHitboxCheck()); @@ -301,19 +298,19 @@ namespace openhack::hacks { gui::Color innerFillColor(innerColor.r, innerColor.g, innerColor.b, fill ? fillAlpha : 0.f); float borderWidth = 0.25f * scale; - auto *player1 = playLayer->m_player1(); + auto *player1 = playLayer->m_player1; if (player1) { - auto hitbox = getPlayerHitbox(player1); + auto hitbox = player1->getObjectRect(); drawRect(debugDrawNode, hitbox, fillColor, borderWidth, borderColor); - auto tinyHitbox = scaleHitbox(hitbox, player1->m_vehicleSize() >= 1.f ? 0.25f : 0.4f); + auto tinyHitbox = scaleHitbox(hitbox, player1->m_vehicleSize >= 1.f ? 0.25f : 0.4f); drawRect(debugDrawNode, tinyHitbox, innerFillColor, borderWidth, innerColor); } - auto *player2 = playLayer->m_player2(); + auto *player2 = playLayer->m_player2; if (player2) { - auto hitbox = getPlayerHitbox(player2); + auto hitbox = player2->getObjectRect(); drawRect(debugDrawNode, hitbox, fillColor, borderWidth, borderColor); - auto tinyHitbox = scaleHitbox(hitbox, player2->m_vehicleSize() >= 1.f ? 0.25f : 0.4f); + auto tinyHitbox = scaleHitbox(hitbox, player2->m_vehicleSize >= 1.f ? 0.25f : 0.4f); drawRect(debugDrawNode, tinyHitbox, innerFillColor, borderWidth, innerColor); } } @@ -354,9 +351,9 @@ namespace openhack::hacks { } void Hitboxes::destroyPlayer() { - auto *playLayer = gd::PlayLayer::get(); - auto *player = playLayer->m_player1(); - if (player && !player->m_isDead()) return; + auto *playLayer = PlayLayer::get(); + auto *player = playLayer->m_player1; + if (player && !player->m_isDead) return; s_isDead = true; } @@ -364,20 +361,20 @@ namespace openhack::hacks { if (!config::get("hack.hitboxes.trail", false)) return; // Add player trail to the queue - auto *playLayer = gd::PlayLayer::get(); + auto *playLayer = PlayLayer::get(); if (!playLayer) return; - auto *player1 = playLayer->m_player1(); - auto *player2 = playLayer->m_player2(); + auto *player1 = playLayer->m_player1; + auto *player2 = playLayer->m_player2; - if (player1 && !player1->m_isDead()) { - auto hitbox = getPlayerHitbox(player1); - s_playerTrail1.emplace_back(hitbox, scaleHitbox(hitbox, player1->m_vehicleSize() >= 1.f ? 0.25f : 0.4f)); + if (player1 && !player1->m_isDead) { + auto hitbox = player1->getObjectRect(); + s_playerTrail1.emplace_back(hitbox, scaleHitbox(hitbox, player1->m_vehicleSize >= 1.f ? 0.25f : 0.4f)); } - if (player2 && !player2->m_isDead()) { - auto hitbox = getPlayerHitbox(player2); - s_playerTrail2.emplace_back(hitbox, scaleHitbox(hitbox, player2->m_vehicleSize() >= 1.f ? 0.25f : 0.4f)); + if (player2 && !player2->m_isDead) { + auto hitbox = player2->getObjectRect(); + s_playerTrail2.emplace_back(hitbox, scaleHitbox(hitbox, player2->m_vehicleSize >= 1.f ? 0.25f : 0.4f)); } // Remove old player trail diff --git a/src/shared/hacks/hitboxes/hitboxes.hpp b/src/shared/hacks/hitboxes/hitboxes.hpp index adedd88..75897be 100644 --- a/src/shared/hacks/hitboxes/hitboxes.hpp +++ b/src/shared/hacks/hitboxes/hitboxes.hpp @@ -16,7 +16,7 @@ namespace openhack::hacks { public: /// @brief CCDrawNode::drawPolygon and CCDrawNode::drawCircle hook - static void modifyDraw(gd::cocos2d::CCDrawNode* node, gui::Color &color, float &borderWidth, gui::Color &borderColor); + static void modifyDraw(cocos2d::CCDrawNode* node, gui::Color &color, float &borderWidth, gui::Color &borderColor); /// @brief PlayLayer::postUpdate hook static void postUpdate(); diff --git a/src/shared/hacks/instant-complete/instant-complete.cpp b/src/shared/hacks/instant-complete/instant-complete.cpp index da872d6..0a75258 100644 --- a/src/shared/hacks/instant-complete/instant-complete.cpp +++ b/src/shared/hacks/instant-complete/instant-complete.cpp @@ -31,10 +31,10 @@ namespace openhack::hacks { if (!config::get("hack.instant_complete.enabled", false)) return; // Get the current PlayLayer - auto *playLayer = gd::PlayLayer::get(); + auto *playLayer = PlayLayer::get(); if (!playLayer) return; - auto *level = playLayer->m_level(); - if (level->m_levelLength() == gd::GJLevelLength::Platformer) { + auto *level = playLayer->m_level; + if (level->isPlatformer()) { playLayer->playPlatformerEndAnimationToPos({2, 2}, false); } else { playLayer->playEndAnimationToPos({2, 2}); diff --git a/src/shared/hacks/labels/label.cpp b/src/shared/hacks/labels/label.cpp index d8ba6ec..4546dd5 100644 --- a/src/shared/hacks/labels/label.cpp +++ b/src/shared/hacks/labels/label.cpp @@ -61,18 +61,18 @@ namespace openhack::hacks { m_heightMultiply = multiplier; } - void Label::addToLayer(gd::cocos2d::CCLayer *layer) { - m_label = gd::cocos2d::CCLabelBMFont::create(m_text.c_str(), m_font.c_str()); + void Label::addToLayer(cocos2d::CCLayer *layer) { + m_label = cocos2d::CCLabelBMFont::create(m_text.c_str(), m_font.c_str()); m_label->setZOrder(1000); layer->addChild(m_label); update(); #ifdef OPENHACK_GEODE - reinterpret_cast(m_label)->setID(m_id); + m_label->setID(m_id); #endif } - void Label::remove(gd::cocos2d::CCLayer *layer) { + void Label::remove(cocos2d::CCLayer *layer) { layer->removeChild(m_label); delete m_label; m_label = nullptr; @@ -80,26 +80,25 @@ namespace openhack::hacks { void Label::update() { if (m_label == nullptr) return; - auto *label = reinterpret_cast(m_label); - label->setFntFile(m_font.c_str()); - label->setCString(m_text.c_str()); - label->setVisible(m_visible); - label->setScale(m_scale); + m_label->setFntFile(m_font.c_str()); + m_label->setCString(m_text.c_str()); + m_label->setVisible(m_visible); + m_label->setScale(m_scale); if (m_heightMultiply != 1.0f && m_anchor.y == 1.0f) { // Calculate the offset to keep the label in the same position - auto offset = label->getContentSize().height - getHeight(); - label->setPosition({m_position.x, m_position.y + offset * m_scale}); + auto offset = m_label->getContentSize().height - getHeight(); + m_label->setPosition({m_position.x, m_position.y + offset * m_scale}); } else { - label->setPosition({m_position.x, m_position.y}); + m_label->setPosition({m_position.x, m_position.y}); } - label->setAnchorPoint({m_anchor.x, m_anchor.y}); + m_label->setAnchorPoint({m_anchor.x, m_anchor.y}); auto opacity = static_cast(m_color.a * 255); cocos2d::_ccColor3B col = {static_cast(m_color.r * 255), static_cast(m_color.g * 255), static_cast(m_color.b * 255)}; - label->setColor(col); - label->setOpacity(opacity); + m_label->setColor(col); + m_label->setOpacity(opacity); } } \ No newline at end of file diff --git a/src/shared/hacks/labels/label.hpp b/src/shared/hacks/labels/label.hpp index 5de3ecb..258470b 100644 --- a/src/shared/hacks/labels/label.hpp +++ b/src/shared/hacks/labels/label.hpp @@ -41,10 +41,10 @@ namespace openhack::hacks { void multiplyHeight(float multiplier); /// @brief Add the label to a layer. - void addToLayer(gd::cocos2d::CCLayer *layer); + void addToLayer(cocos2d::CCLayer *layer); /// @brief Remove the label from a layer. - void remove(gd::cocos2d::CCLayer *layer); + void remove(cocos2d::CCLayer *layer); public: /// @brief Get the label's text. @@ -72,7 +72,7 @@ namespace openhack::hacks { const gui::Color &getColor() const { return m_color; } private: - gd::cocos2d::CCLabelBMFont *m_label = nullptr; + cocos2d::CCLabelBMFont *m_label = nullptr; bool m_visible = true; ImVec2 m_position = {0, 0}; diff --git a/src/shared/hacks/labels/labels.cpp b/src/shared/hacks/labels/labels.cpp index 99bf8d3..6b453e8 100644 --- a/src/shared/hacks/labels/labels.cpp +++ b/src/shared/hacks/labels/labels.cpp @@ -16,10 +16,10 @@ namespace openhack::hacks { } void LabelsContainer::recalculatePositions() { - if (gd::PlayLayer::get() == nullptr) return; + if (PlayLayer::get() == nullptr) return; - auto *playLayer = gd::PlayLayer::get(); - auto winSize = gd::cocos2d::CCDirector::sharedDirector()->getWinSize(); + auto *playLayer = PlayLayer::get(); + auto winSize = cocos2d::CCDirector::sharedDirector()->getWinSize(); auto padding = config::get("hack.labels.padding"); ImVec2 anchor = {0, 0}; ImVec2 offset = {0, 0}; @@ -66,7 +66,7 @@ namespace openhack::hacks { } void LabelsContainer::recreateLabels() { - auto *playLayer = gd::PlayLayer::get(); + auto *playLayer = PlayLayer::get(); if (playLayer == nullptr) return; for (auto &label: m_labels) { @@ -83,7 +83,7 @@ namespace openhack::hacks { } void LabelsContainer::deleteFromScene() { - auto *playLayer = gd::PlayLayer::get(); + auto *playLayer = PlayLayer::get(); if (playLayer == nullptr) return; for (auto &label: m_labels) { @@ -94,7 +94,7 @@ namespace openhack::hacks { } void LabelsContainer::update() { - if (gd::PlayLayer::get() == nullptr) return; + if (PlayLayer::get() == nullptr) return; recalculatePositions(); @@ -367,7 +367,7 @@ namespace openhack::hacks { } void Labels::update() { - if (gd::PlayLayer::get() == nullptr) return; + if (PlayLayer::get() == nullptr) return; for (auto &container: CONTAINERS) { container.update(); @@ -422,7 +422,7 @@ namespace openhack::hacks { newLabel->setVisible(cfg->visible); CONTAINERS[static_cast(labelConfig.position)].addLabel(newLabel, [cfg](Label *label) { label->setFont(cfg->font, false); - label->setText(replaceTokens(cfg->text, gd::PlayLayer::get(), nullptr), false); + label->setText(replaceTokens(cfg->text, PlayLayer::get(), nullptr), false); label->setTextColor(cfg->color, false); label->setScale(cfg->scale, false); label->setVisible(cfg->visible); @@ -434,19 +434,19 @@ namespace openhack::hacks { } } - inline bool isRobTopLevel(gd::GJGameLevel *level) { - int id = level->m_levelID().value(); + inline bool isRobTopLevel(GJGameLevel *level) { + int id = level->m_levelID.value(); return (id > 0 && id < 100) || (id >= 3001 && id <= 6000); } - inline std::string getDifficultyAsset(gd::GJGameLevel *level) { - if (level->m_autoLevel()) return "auto"; + inline std::string getDifficultyAsset(GJGameLevel *level) { + if (level->m_autoLevel) return "auto"; - if (level->m_ratingsSum() != 0) - level->m_difficulty(static_cast(level->m_ratingsSum() / 10)); + if (level->m_ratingsSum != 0) + level->m_difficulty = static_cast(level->m_ratingsSum / 10); - if (level->isDemon()) { - switch (level->m_demonDifficulty()) { + if (level->m_demon.value() > 0) { + switch (level->m_demonDifficulty) { case 3: return "easy_demon"; case 4: @@ -460,18 +460,18 @@ namespace openhack::hacks { } } - switch (level->m_difficulty()) { - case gd::GJDifficulty::Easy: + switch (level->m_difficulty) { + case GJDifficulty::Easy: return "easy"; - case gd::GJDifficulty::Normal: + case GJDifficulty::Normal: return "normal"; - case gd::GJDifficulty::Hard: + case GJDifficulty::Hard: return "hard"; - case gd::GJDifficulty::Harder: + case GJDifficulty::Harder: return "harder"; - case gd::GJDifficulty::Insane: + case GJDifficulty::Insane: return "insane"; - case gd::GJDifficulty::Demon: + case GJDifficulty::Demon: return "hard_demon"; default: return "na"; @@ -479,7 +479,7 @@ namespace openhack::hacks { } std::string - Labels::replaceTokens(const std::string &text, gd::PlayLayer *playLayer, gd::LevelEditorLayer *editorLayer) { + Labels::replaceTokens(const std::string &text, PlayLayer *playLayer, LevelEditorLayer *editorLayer) { // {username} - username of the player // {id} - level id // {name} - level name @@ -510,31 +510,31 @@ namespace openhack::hacks { // {mod_count} - number of loaded mods in Geode std::unordered_map> tokens = { {"{username}", []() { - auto *gameManager = gd::GameManager::sharedState(); - return gameManager->m_playerName(); + auto *gameManager = GameManager::sharedState(); + return gameManager->m_playerName; }}, {"{id}", [playLayer, editorLayer]() { - gd::GJBaseGameLayer *layer = playLayer ? (gd::GJBaseGameLayer *) playLayer - : (gd::GJBaseGameLayer *) editorLayer; + GJBaseGameLayer *layer = playLayer ? (GJBaseGameLayer *) playLayer + : (GJBaseGameLayer *) editorLayer; if (!layer) return std::string(""); - return std::to_string(layer->m_level()->m_levelID().value()); + return std::to_string(layer->m_level->m_levelID.value()); }}, {"{name}", [playLayer, editorLayer]() { - gd::GJBaseGameLayer *layer = playLayer ? (gd::GJBaseGameLayer *) playLayer - : (gd::GJBaseGameLayer *) editorLayer; + GJBaseGameLayer *layer = playLayer ? (GJBaseGameLayer *) playLayer + : (GJBaseGameLayer *) editorLayer; if (!layer) return std::string("Unknown"); - return layer->m_level()->m_levelName(); + return layer->m_level->m_levelName; }}, {"{author}", [playLayer, editorLayer]() { - gd::GJBaseGameLayer *layer = playLayer ? (gd::GJBaseGameLayer *) playLayer - : (gd::GJBaseGameLayer *) editorLayer; + GJBaseGameLayer *layer = playLayer ? (GJBaseGameLayer *) playLayer + : (GJBaseGameLayer *) editorLayer; if (!layer) return std::string("Unknown"); - if (isRobTopLevel(layer->m_level())) return std::string("RobTop"); - return layer->m_level()->m_creatorName(); + if (isRobTopLevel(layer->m_level)) return std::string("RobTop"); + return layer->m_level->m_creatorName; }}, {"{difficulty}", [playLayer]() { if (!playLayer) return std::string(""); - return getDifficultyAsset(playLayer->m_level()); + return getDifficultyAsset(playLayer->m_level); }}, {"{progress}", [playLayer]() { if (!playLayer) return std::string(""); @@ -544,8 +544,8 @@ namespace openhack::hacks { }}, {"{best}", [playLayer]() { if (!playLayer) return std::string(""); - if (playLayer->m_level()->isPlatformer()) { - int millis = playLayer->m_level()->m_bestTime(); + if (playLayer->m_level->isPlatformer()) { + int millis = playLayer->m_level->m_bestTime; if (millis == 0) return std::string("N/A"); double seconds = millis / 1000.0; if (seconds < 60.0) @@ -554,33 +554,33 @@ namespace openhack::hacks { seconds -= minutes * 60; return fmt::format("{:02d}:{:06.3f}", minutes, seconds); } - return std::to_string(playLayer->m_level()->m_normalPercent().value()); + return std::to_string(playLayer->m_level->m_normalPercent.value()); }}, {"{objects}", [playLayer, editorLayer]() { if (playLayer) { - return std::to_string(playLayer->m_level()->m_objectCount().value()); + return std::to_string(playLayer->m_level->m_objectCount.value()); } else if (editorLayer) { - return std::to_string(editorLayer->m_objects()->count()); + return std::to_string(editorLayer->m_objects->count()); } return std::string(""); }}, {"{stars}", [playLayer]() { if (playLayer) { - return std::to_string(playLayer->m_level()->m_stars().value()); + return std::to_string(playLayer->m_level->m_stars.value()); } return std::string(""); }}, {"{attempts}", [playLayer]() { if (!playLayer) return std::string(""); - return std::to_string(playLayer->m_attempts()); + return std::to_string(playLayer->m_attempts); }}, {"{rating}", [playLayer]() { if (!playLayer) return std::string(""); - return std::to_string(playLayer->m_level()->m_ratingsSum()); + return std::to_string(playLayer->m_level->m_ratingsSum); }}, {"{star_emoji}", [playLayer]() { if (!playLayer) return std::string(""); - return std::string(playLayer->m_level()->isPlatformer() ? "🌙" : "⭐"); + return std::string(playLayer->m_level->isPlatformer() ? "🌙" : "⭐"); }}, {"{clock}", []() { std::time_t now = std::time(nullptr); @@ -632,16 +632,16 @@ namespace openhack::hacks { }}, {"{frame}", [playLayer]() { if (!playLayer) return std::string("0"); - return std::to_string(static_cast(playLayer->m_dTime() * 240.0f)); + return std::to_string(static_cast(playLayer->m_gameState.m_levelTime * 240.0f)); }}, {"{time}", [playLayer]() { if (!playLayer) return std::string(""); - auto time = playLayer->m_dTime(); + auto time = playLayer->m_gameState.m_levelTime; return fmt::format("{:.3f}", time); }}, {"{formatted_time}", [playLayer]() { if (!playLayer) return std::string(""); - auto time = playLayer->m_dTime(); + auto time = playLayer->m_gameState.m_levelTime; int minutes = (int) time / 60; int seconds = (int) time % 60; int millis = (int) (time * 1000) % 1000; @@ -655,7 +655,7 @@ namespace openhack::hacks { }}, {"{total_attempts}", [playLayer]() { if (!playLayer) return std::string(""); - return std::to_string(playLayer->m_level()->m_attempts().value()); + return std::to_string(playLayer->m_level->m_attempts.value()); }}, {"{openhack_ver}", []() { static std::string version = fmt::format( @@ -729,7 +729,7 @@ namespace openhack::hacks { void Labels::beforeResetLevel() { // Calculate "Best%" - auto *playLayer = gd::PlayLayer::get(); + auto *playLayer = PlayLayer::get(); auto progress = playLayer->getCurrentPercentInt(); auto currentBest = config::getGlobal("bestRun", 0); if (progress > currentBest) { @@ -742,10 +742,10 @@ namespace openhack::hacks { s_clickFrames.clear(); } - void Labels::pushButton(gd::PlayerObject *player) { - auto *playLayer = gd::PlayLayer::get(); + void Labels::pushButton(PlayerObject *player) { + auto *playLayer = PlayLayer::get(); if (!playLayer) return; - if (playLayer->m_player1() != player) return; + if (playLayer->m_player1 != player) return; config::setGlobal("isHolding", true); auto totalClicks = config::getGlobal("totalClicks", 0); @@ -758,16 +758,16 @@ namespace openhack::hacks { } } - void Labels::releaseButton(gd::PlayerObject *player) { - auto *playLayer = gd::PlayLayer::get(); + void Labels::releaseButton(PlayerObject *player) { + auto *playLayer = PlayLayer::get(); if (!playLayer) return; - if (playLayer->m_player1() != player) return; + if (playLayer->m_player1 != player) return; config::setGlobal("isHolding", false); } void Labels::gameUpdate() { - auto *playLayer = gd::PlayLayer::get(); + auto *playLayer = PlayLayer::get(); if (!playLayer) return; auto frame = config::getGlobal("frame", 0); diff --git a/src/shared/hacks/labels/labels.hpp b/src/shared/hacks/labels/labels.hpp index 3927d63..8d73675 100644 --- a/src/shared/hacks/labels/labels.hpp +++ b/src/shared/hacks/labels/labels.hpp @@ -134,7 +134,7 @@ namespace openhack::hacks { /// @brief Replaces all {} tokens in a string with their respective values static std::string - replaceTokens(const std::string &text, gd::PlayLayer *playLayer, gd::LevelEditorLayer *editorLayer); + replaceTokens(const std::string &text, PlayLayer *playLayer, LevelEditorLayer *editorLayer); /// @brief Save the labels to the config static void save(); @@ -153,10 +153,10 @@ namespace openhack::hacks { static void beforeResetLevel(); /// @brief PlayerObject::pushButton hook - static void pushButton(gd::PlayerObject *player); + static void pushButton(PlayerObject *player); /// @brief PlayerObject::releaseButton hook - static void releaseButton(gd::PlayerObject *player); + static void releaseButton(PlayerObject *player); /// @brief GJBaseGameLayer::update hook static void gameUpdate(); diff --git a/src/shared/hacks/menu-gameplay/menu-gameplay.cpp b/src/shared/hacks/menu-gameplay/menu-gameplay.cpp index 2411a0b..11738de 100644 --- a/src/shared/hacks/menu-gameplay/menu-gameplay.cpp +++ b/src/shared/hacks/menu-gameplay/menu-gameplay.cpp @@ -21,16 +21,16 @@ namespace openhack::hacks { }); } - void MenuGameplay::menuUpdate(gd::PlayerObject *player) { + void MenuGameplay::menuUpdate(PlayerObject *player) { if (!config::get("hack.menu_gameplay", false)) return; - if (!player || player->m_isSpider()) return; + if (!player || player->m_isSpider) return; const char *keys[] = {"LMB", "Up", "W"}; for (const char *key: keys) { if (utils::isKeyPressed(key)) - player->pushButton(gd::PlayerButton::Jump); + player->pushButton(PlayerButton::Jump); else if (utils::isKeyReleased(key)) - player->releaseButton(gd::PlayerButton::Jump); + player->releaseButton(PlayerButton::Jump); } } diff --git a/src/shared/hacks/menu-gameplay/menu-gameplay.hpp b/src/shared/hacks/menu-gameplay/menu-gameplay.hpp index 6567b52..9e3060d 100644 --- a/src/shared/hacks/menu-gameplay/menu-gameplay.hpp +++ b/src/shared/hacks/menu-gameplay/menu-gameplay.hpp @@ -16,7 +16,7 @@ namespace openhack::hacks { public: /// @brief MenuGameLayer::update hook - static void menuUpdate(gd::PlayerObject *player); + static void menuUpdate(PlayerObject *player); }; } \ No newline at end of file diff --git a/src/shared/hacks/noclip-limit/noclip-limit.cpp b/src/shared/hacks/noclip-limit/noclip-limit.cpp index d193ad5..f2db23a 100644 --- a/src/shared/hacks/noclip-limit/noclip-limit.cpp +++ b/src/shared/hacks/noclip-limit/noclip-limit.cpp @@ -6,7 +6,7 @@ namespace openhack::hacks { bool isDead = false; bool lastFrameDead = false; bool isAntiCheatDeath = false; - gd::GameObject* antiCheatObject = nullptr; + GameObject* antiCheatObject = nullptr; uint32_t deathCount = 0; void NoclipLimit::onInit() { @@ -68,7 +68,7 @@ namespace openhack::hacks { return result; } - void NoclipLimit::destroyPlayer(gd::GameObject* object) { + void NoclipLimit::destroyPlayer(GameObject* object) { isAntiCheatDeath = false; auto frames = config::getGlobal("frame", 0); @@ -111,8 +111,8 @@ namespace openhack::hacks { } void NoclipLimit::processCommands() { - auto* playlayer = gd::PlayLayer::get(); - if (!playlayer || playlayer->m_hasCompletedLevel() || playlayer->m_player1()->m_isDead()) return; + auto* playlayer = PlayLayer::get(); + if (!playlayer || playlayer->m_hasCompletedLevel || playlayer->m_player1->m_isDead) return; if (isDead) { deathCount++; diff --git a/src/shared/hacks/noclip-limit/noclip-limit.hpp b/src/shared/hacks/noclip-limit/noclip-limit.hpp index 79f0d9f..7a07d9a 100644 --- a/src/shared/hacks/noclip-limit/noclip-limit.hpp +++ b/src/shared/hacks/noclip-limit/noclip-limit.hpp @@ -16,7 +16,7 @@ namespace openhack::hacks { public: /// @brief PlayLayer::destroyPlayer hook - static void destroyPlayer(gd::GameObject* object); + static void destroyPlayer(GameObject* object); /// @brief PlayLayer::destroyPlayer hook (after the original function) static void postDestroyPlayer(); diff --git a/src/shared/hacks/rgb-icons/rgb-icons.cpp b/src/shared/hacks/rgb-icons/rgb-icons.cpp index ec2600a..6c53ff0 100644 --- a/src/shared/hacks/rgb-icons/rgb-icons.cpp +++ b/src/shared/hacks/rgb-icons/rgb-icons.cpp @@ -64,11 +64,11 @@ namespace openhack::hacks { void RGBIcons::postUpdate() { if (!config::get("hack.rgb_icons.enabled", false)) return; - auto *gameLayer = gd::GJBaseGameLayer::get(); + auto *gameLayer = GJBaseGameLayer::get(); if (!gameLayer) return; - auto *player1 = gameLayer->m_player1(); - auto *player2 = gameLayer->m_player2(); + auto *player1 = gameLayer->m_player1; + auto *player2 = gameLayer->m_player2; auto speed = config::get("hack.rgb_icons.speed") / 10.0f; auto saturation = config::get("hack.rgb_icons.saturation") / 100.f; @@ -80,13 +80,13 @@ namespace openhack::hacks { if (player1) { if (applyPrimary) { auto color1 = getRainbowColor(speed, saturation, value, 0.0f); - reinterpret_cast(player1)->setColor({static_cast(color1.r * 255), - static_cast(color1.g * 255), - static_cast(color1.b * 255)}); + player1->setColor({static_cast(color1.r * 255), + static_cast(color1.g * 255), + static_cast(color1.b * 255)}); } if (applySecondary) { auto color2 = getRainbowColor(speed, saturation, value, secondOffset); - reinterpret_cast(player1->m_iconSpriteSecondary())->setColor( + player1->m_iconSpriteSecondary->setColor( {static_cast(color2.r * 255), static_cast(color2.g * 255), static_cast(color2.b * 255)}); @@ -97,13 +97,13 @@ namespace openhack::hacks { auto offset = config::get("hack.rgb_icons.playerOffset"); if (applyPrimary) { auto color1 = getRainbowColor(speed, saturation, value, offset); - reinterpret_cast(player2)->setColor({static_cast(color1.r * 255), - static_cast(color1.g * 255), - static_cast(color1.b * 255)}); + player2->setColor({static_cast(color1.r * 255), + static_cast(color1.g * 255), + static_cast(color1.b * 255)}); } if (applySecondary) { auto color2 = getRainbowColor(speed, saturation, value, secondOffset + offset); - reinterpret_cast(player2->m_iconSpriteSecondary())->setColor( + player2->m_iconSpriteSecondary->setColor( {static_cast(color2.r * 255), static_cast(color2.g * 255), static_cast(color2.b * 255)}); diff --git a/src/shared/hacks/shortcuts/shortcuts.cpp b/src/shared/hacks/shortcuts/shortcuts.cpp index 06fcd1e..6c31600 100644 --- a/src/shared/hacks/shortcuts/shortcuts.cpp +++ b/src/shared/hacks/shortcuts/shortcuts.cpp @@ -10,40 +10,40 @@ namespace openhack::hacks { void uncompleteLevelConfirmed() { - if (gd::PlayLayer *playLayer = gd::PlayLayer::get()) { - auto *level = playLayer->m_level(); - auto *statsManager = gd::GameStatsManager::sharedState(); + if (PlayLayer *playLayer = PlayLayer::get()) { + auto *level = playLayer->m_level; + auto *statsManager = GameStatsManager::sharedState(); statsManager->uncompleteLevel(level); // Clear progress - level->m_practicePercent() = 0; - level->m_normalPercent() = 0; - level->m_newNormalPercent2() = 0; - level->m_orbCompletion() = 0; - level->m_54() = 0; - level->m_k111() = 0; - level->m_bestPoints() = 0; - level->m_bestTime() = 0; + level->m_practicePercent = 0; + level->m_normalPercent = 0; + level->m_newNormalPercent2 = 0; + level->m_orbCompletion = 0; + level->m_54 = 0; + level->m_k111 = 0; + level->m_bestPoints = 0; + level->m_bestTime = 0; // Remove coins - auto *coinDict = reinterpret_cast(statsManager->m_verifiedUserCoins()); + auto *coinDict = statsManager->m_verifiedUserCoins; if (!coinDict) { L_WARN("coinDict is null"); return; } - auto coins = level->m_coins(); + auto coins = level->m_coins; for (auto i = 0; i < coins; i++) { auto *key = level->getCoinKey(i + 1); coinDict->removeObjectForKey(key); } // Save the level - gd::GameLevelManager::sharedState()->saveLevel(level); + GameLevelManager::sharedState()->saveLevel(level); } } void Shortcuts::uncompleteLevel() { - if (!gd::PlayLayer::get()) { + if (!PlayLayer::get()) { gui::Modal::create("Uncomplete level", "You need to be in a level to use this."); return; } @@ -60,24 +60,24 @@ namespace openhack::hacks { } void Shortcuts::openOptions() { - auto *options = gd::OptionsLayer::create(); - auto *scene = gd::cocos2d::CCDirector::sharedDirector()->getRunningScene(); + auto *options = OptionsLayer::create(); + auto *scene = cocos2d::CCDirector::sharedDirector()->getRunningScene(); scene->addChild(options); options->setZOrder(1000); options->showLayer(false); } void Shortcuts::restartLevel() { - auto *playLayer = gd::PlayLayer::get(); + auto *playLayer = PlayLayer::get(); if (playLayer) { playLayer->resetLevel(); } } void Shortcuts::togglePractice() { - auto *playLayer = gd::PlayLayer::get(); + auto *playLayer = PlayLayer::get(); if (playLayer) { - bool isPractice = playLayer->m_isPracticeMode(); + bool isPractice = playLayer->m_isPracticeMode; playLayer->togglePracticeMode(!isPractice); } } diff --git a/src/shared/hacks/smart-startpos/smart-startpos.cpp b/src/shared/hacks/smart-startpos/smart-startpos.cpp index 154e38b..9ca1db8 100644 --- a/src/shared/hacks/smart-startpos/smart-startpos.cpp +++ b/src/shared/hacks/smart-startpos/smart-startpos.cpp @@ -3,8 +3,8 @@ namespace openhack::hacks { - static std::vector s_startPosObjects; - static std::vector s_gravityPortals, s_dualPortals, s_gamemodePortals, s_miniPortals, s_speedChanges, s_mirrorPortals; + static std::vector s_startPosObjects; + static std::vector s_gravityPortals, s_dualPortals, s_gamemodePortals, s_miniPortals, s_speedChanges, s_mirrorPortals; void SmartStartPos::onInit() { // Set default values @@ -38,8 +38,8 @@ namespace openhack::hacks { s_mirrorPortals.clear(); } - void SmartStartPos::addObject(gd::GameObject* object) { - auto objID = object->m_objectID(); + void SmartStartPos::addObject(GameObject* object) { + auto objID = object->m_objectID; switch (objID) { case 10: // Blue Gravity Portal case 11: // Yellow Gravity Portal @@ -76,7 +76,7 @@ namespace openhack::hacks { s_speedChanges.push_back(object); break; case 31: // StartPos - s_startPosObjects.push_back(reinterpret_cast(object)); + s_startPosObjects.push_back(static_cast(object)); break; default: return; @@ -87,8 +87,8 @@ namespace openhack::hacks { } /// @brief Get all objects that are before the given x position - std::vector findBefore(std::vector& vec, float x) { - std::vector result; + std::vector findBefore(std::vector& vec, float x) { + std::vector result; for (auto* obj : vec) { if (obj->getPositionX() < x) { result.push_back(obj); @@ -97,8 +97,8 @@ namespace openhack::hacks { return result; } - gd::GameObject* findLastBefore(std::vector& vec, float x) { - gd::GameObject* result = nullptr; + GameObject* findLastBefore(std::vector& vec, float x) { + GameObject* result = nullptr; for (auto* obj : vec) { if (obj->getPositionX() < x) { result = obj; @@ -113,13 +113,13 @@ namespace openhack::hacks { for (auto* startPos : s_startPosObjects) { auto x = startPos->getPositionX(); - auto* startPosSettings = startPos->m_levelSettings(); - bool upsideDown = startPosSettings->m_isFlipped(); - bool dual = startPosSettings->m_startDual(); - bool mini = startPosSettings->m_startMini(); - bool mirror = startPosSettings->m_mirrorMode(); - int speed = startPosSettings->m_startSpeed(); - int gamemode = startPosSettings->m_startMode(); + auto* startPosSettings = startPos->m_startSettings; + bool upsideDown = startPosSettings->m_isFlipped; + bool dual = startPosSettings->m_startDual; + bool mini = startPosSettings->m_startMini; + bool mirror = startPosSettings->m_mirrorMode; + int speed = static_cast(startPosSettings->m_startSpeed); + int gamemode = startPosSettings->m_startMode; // Get all objects that are before the current StartPos auto gravityPortals = findBefore(s_gravityPortals, x + 10); @@ -131,7 +131,7 @@ namespace openhack::hacks { // Iterate over all objects and set the settings accordingly for (auto* gravityPortal : gravityPortals) { - switch (gravityPortal->m_objectID()) { + switch (gravityPortal->m_objectID) { case 10: // Blue Gravity Portal upsideDown = false; break; @@ -145,7 +145,7 @@ namespace openhack::hacks { } if (dualPortal) { - switch (dualPortal->m_objectID()) { + switch (dualPortal->m_objectID) { case 286: // Orange Dual Portal dual = true; break; @@ -156,7 +156,7 @@ namespace openhack::hacks { } if (dualPortal) { - switch (gamemodePortal->m_objectID()) { + switch (gamemodePortal->m_objectID) { case 12: // Cube Portal gamemode = 0; break; @@ -185,7 +185,7 @@ namespace openhack::hacks { } if (miniPortal) { - switch (miniPortal->m_objectID()) { + switch (miniPortal->m_objectID) { case 99: // Normal Size Portal mini = false; break; @@ -196,7 +196,7 @@ namespace openhack::hacks { } if (speedChange) { - switch (speedChange->m_objectID()) { + switch (speedChange->m_objectID) { case 200: // -1x Speed Change speed = 1; break; @@ -216,7 +216,7 @@ namespace openhack::hacks { } if (mirrorPortal) { - switch (mirrorPortal->m_objectID()) { + switch (mirrorPortal->m_objectID) { case 45: // Orange Mirror Portal mirror = true; break; @@ -226,12 +226,12 @@ namespace openhack::hacks { } } - startPosSettings->m_startMode() = gamemode; - startPosSettings->m_startSpeed() = speed; - startPosSettings->m_startMini() = mini; - startPosSettings->m_startDual() = dual; - startPosSettings->m_mirrorMode() = mirror; - startPosSettings->m_isFlipped() = upsideDown; + startPosSettings->m_startMode = gamemode; + startPosSettings->m_startSpeed = static_cast(speed); + startPosSettings->m_startMini = mini; + startPosSettings->m_startDual = dual; + startPosSettings->m_mirrorMode = mirror; + startPosSettings->m_isFlipped = upsideDown; } } diff --git a/src/shared/hacks/smart-startpos/smart-startpos.hpp b/src/shared/hacks/smart-startpos/smart-startpos.hpp index 11faa53..6c6f7ba 100644 --- a/src/shared/hacks/smart-startpos/smart-startpos.hpp +++ b/src/shared/hacks/smart-startpos/smart-startpos.hpp @@ -21,7 +21,7 @@ namespace openhack::hacks { static void initLevel(); /// @brief PlayLayer::addObject hook - static void addObject(gd::GameObject* object); + static void addObject(GameObject* object); }; } \ No newline at end of file diff --git a/src/shared/hacks/speedhack/speedhack.cpp b/src/shared/hacks/speedhack/speedhack.cpp index bcb1519..6554178 100644 --- a/src/shared/hacks/speedhack/speedhack.cpp +++ b/src/shared/hacks/speedhack/speedhack.cpp @@ -32,7 +32,7 @@ namespace openhack::hacks { void SpeedHack::update() { FMOD::Channel *channel; - FMOD::System *system = gd::FMODAudioEngine::sharedEngine()->m_system(); + FMOD::System *system = FMODAudioEngine::sharedEngine()->m_system; for (auto i = 0; i < 2; i++) { system->getChannel(126 + i, &channel); if (channel) diff --git a/src/shared/hacks/startpos-switcher/startpos-switcher.cpp b/src/shared/hacks/startpos-switcher/startpos-switcher.cpp index 4c77daa..171a0e0 100644 --- a/src/shared/hacks/startpos-switcher/startpos-switcher.cpp +++ b/src/shared/hacks/startpos-switcher/startpos-switcher.cpp @@ -4,13 +4,13 @@ namespace openhack::hacks { - std::vector StartPosSwitcher::m_startposes; + std::vector StartPosSwitcher::m_startposes; int32_t StartPosSwitcher::m_currentIndex; Label *m_label; void StartPosSwitcher::updateLabel() { // Check if PlayLayer is available - auto *playLayer = gd::PlayLayer::get(); + auto *playLayer = PlayLayer::get(); if (playLayer == nullptr) return; // Check if label is available @@ -23,7 +23,7 @@ namespace openhack::hacks { m_label->setVisible(show); m_label->setTextColor(config::get("hack.startpos_switch.label.color")); m_label->setScale(config::get("hack.startpos_switch.label.scale")); - auto winSize = gd::cocos2d::CCDirector::sharedDirector()->getWinSize(); + auto winSize = cocos2d::CCDirector::sharedDirector()->getWinSize(); m_label->setPosition({winSize.width / 2.f, 2.0f}); m_label->setAnchor({0.5f, 0.0f}); auto text = fmt::format("{}/{}", m_currentIndex + 1, m_startposes.size()); @@ -78,7 +78,7 @@ namespace openhack::hacks { void StartPosSwitcher::update() { // Get PlayLayer - auto *playLayer = gd::PlayLayer::get(); + auto *playLayer = PlayLayer::get(); if (playLayer == nullptr) { if (m_label != nullptr) { delete m_label; @@ -104,25 +104,25 @@ namespace openhack::hacks { void StartPosSwitcher::lateInitLevel() { // Sort startposes by x position - std::sort(m_startposes.begin(), m_startposes.end(), [](gd::GameObject *a, gd::GameObject *b) { - return a->m_startPosition().x < b->m_startPosition().x; + std::sort(m_startposes.begin(), m_startposes.end(), [](GameObject *a, GameObject *b) { + return a->m_startPosition.x < b->m_startPosition.x; }); - auto *playLayer = gd::PlayLayer::get(); + auto *playLayer = PlayLayer::get(); size_t count = m_startposes.size(); - m_currentIndex = playLayer->m_isTestMode() ? count - 1 : -1; + m_currentIndex = playLayer->m_isTestMode ? count - 1 : -1; // Setup label m_label = new Label("", "bigFont.fnt"); m_label->setId("openhack-startpos-label"); - m_label->addToLayer(gd::PlayLayer::get()); + m_label->addToLayer(PlayLayer::get()); updateLabel(); } - void StartPosSwitcher::addObject(gd::GameObject *object) { - uint32_t id = object->m_objectID(); + void StartPosSwitcher::addObject(GameObject *object) { + uint32_t id = object->m_objectID; if (id == 31) { - m_startposes.push_back(reinterpret_cast(object)); + m_startposes.push_back(static_cast(object)); } } @@ -130,7 +130,7 @@ namespace openhack::hacks { if (!config::get("hack.startpos_switch.enabled", false)) return; // Get PlayLayer - auto *playLayer = gd::PlayLayer::get(); + auto *playLayer = PlayLayer::get(); if (playLayer == nullptr) return; updateLabel(); @@ -139,7 +139,7 @@ namespace openhack::hacks { playLayer->resetCamera(); } - void StartPosSwitcher::pickStartPos(gd::PlayLayer *playLayer, int32_t index) { + void StartPosSwitcher::pickStartPos(PlayLayer *playLayer, int32_t index) { if (m_startposes.empty()) return; size_t count = m_startposes.size(); @@ -151,7 +151,7 @@ namespace openhack::hacks { } m_currentIndex = index; - playLayer->m_startPosCheckpoint(nullptr); + playLayer->m_currentCheckpoint = nullptr; if (index >= 0) { playLayer->setStartPosObject(m_startposes[index]); @@ -159,7 +159,7 @@ namespace openhack::hacks { playLayer->setStartPosObject(nullptr); } - if (playLayer->m_isPracticeMode()) + if (playLayer->m_isPracticeMode) playLayer->resetLevelFromStart(); playLayer->resetLevel(); diff --git a/src/shared/hacks/startpos-switcher/startpos-switcher.hpp b/src/shared/hacks/startpos-switcher/startpos-switcher.hpp index e7de023..54a5a9f 100644 --- a/src/shared/hacks/startpos-switcher/startpos-switcher.hpp +++ b/src/shared/hacks/startpos-switcher/startpos-switcher.hpp @@ -23,16 +23,16 @@ namespace openhack::hacks { static void lateInitLevel(); /// @brief PlayLayer::addObject hook - static void addObject(gd::GameObject *object); + static void addObject(GameObject *object); /// @brief PlayLayer::resetLevel hook static void resetLevel(); private: - static void pickStartPos(gd::PlayLayer *playLayer, int32_t index); + static void pickStartPos(PlayLayer *playLayer, int32_t index); static void updateLabel(); - static std::vector m_startposes; + static std::vector m_startposes; static int32_t m_currentIndex; }; diff --git a/src/shared/hacks/zephyrus/replays.cpp b/src/shared/hacks/zephyrus/replays.cpp index d50edf1..43bda7d 100644 --- a/src/shared/hacks/zephyrus/replays.cpp +++ b/src/shared/hacks/zephyrus/replays.cpp @@ -22,65 +22,63 @@ namespace openhack::hacks { // Initialize Zephyrus s_replayEngine = zephyrus::Zephyrus(); s_replayEngine.setGetFrameMethod([]() -> uint32_t { - auto *playLayer = gd::PlayLayer::get(); + auto *playLayer = PlayLayer::get(); if (playLayer == nullptr) return 0; - auto frame = static_cast(playLayer->m_dTime() * 240.0f); + auto frame = static_cast(playLayer->m_gameState.m_levelTime * 240.0f); return frame; }); s_replayEngine.setHandleButtonMethod([](int player, int button, bool pressed) { - auto *playLayer = gd::PlayLayer::get(); + auto *playLayer = PlayLayer::get(); if (playLayer == nullptr) return; playLayer->handleButton( - pressed, - static_cast(button), + pressed, button, player == 0 ? - playLayer->m_player1() : playLayer->m_player2()); + playLayer->m_player1 : playLayer->m_player2); }); s_replayEngine.setFixPlayerMethod([](int player, const zephyrus::Macro::FrameFix::PlayerData &data) { - auto *playLayer = gd::PlayLayer::get(); + auto *playLayer = PlayLayer::get(); if (playLayer == nullptr) return; auto *playerObj = player == 0 ? - playLayer->m_player1() : playLayer->m_player2(); + playLayer->m_player1 : playLayer->m_player2; if (playerObj == nullptr || s_levelFinished) return; // set position - auto*playerSpr = reinterpret_cast(playerObj); - playerObj->m_position().x = data.x; - playerObj->m_position().y = data.y; - playerObj->m_yAccel(data.ySpeed); - playerSpr->setPosition({data.x, data.y}); + playerObj->m_position.x = data.x; + playerObj->m_position.y = data.y; + playerObj->m_yVelocity = data.ySpeed; + playerObj->setPosition({data.x, data.y}); if (config::get("zephyrus.rotationFix", true)) { - playerSpr->setRotation(data.rotation); + playerObj->setRotation(data.rotation); } }); s_replayEngine.setRequestMacroFixMethod([]() -> zephyrus::Macro::FrameFix { - auto *playLayer = gd::PlayLayer::get(); + auto *playLayer = PlayLayer::get(); if (playLayer == nullptr) return zephyrus::Macro::FrameFix(0, {0, 0, 0, 0}); - auto *player1 = playLayer->m_player1(); - auto *player2 = playLayer->m_player2(); + auto *player1 = playLayer->m_player1; + auto *player2 = playLayer->m_player2; if (player1 == nullptr) return zephyrus::Macro::FrameFix(0, {0, 0, 0, 0}); zephyrus::Macro::FrameFix::PlayerData player1Data = { - player1->m_position().x, - player1->m_position().y, - player1->m_yAccel(), - reinterpret_cast(player1)->getRotation() + player1->m_position.x, + player1->m_position.y, + player1->m_yVelocity, + player1->getRotation() }; if (player2 == nullptr) return {0, player1Data}; zephyrus::Macro::FrameFix::PlayerData player2Data = { - player2->m_position().x, - player2->m_position().y, - player2->m_yAccel(), - reinterpret_cast(player2)->getRotation() + player2->m_position.x, + player2->m_position.y, + player2->m_yVelocity, + player2->getRotation() }; return {0, player1Data, player2Data}; @@ -97,11 +95,11 @@ namespace openhack::hacks { static geode::Mod* cbfMod = geode::Loader::get()->getLoadedMod("syzzi.click_between_frames"); static bool hasCBF = cbfMod != nullptr && cbfMod->isEnabled(); - if (hasCBF) { + if (hasCBF && !cbfMod->getSettingValue("soft-toggle")) { ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.5f, 0.5f, 1.0f)); ImGui::TextWrapped("Warning: \"Click Between Frames\" is enabled"); gui::tooltip("The replay system may not work correctly with this mod enabled.\n" - "Please disable it to use the replay system."); + "Please disable it to use the replay system."); ImGui::PopStyleColor(); } #endif @@ -165,7 +163,7 @@ namespace openhack::hacks { } } - ImGui::Text("Macro actions: %d", s_replayEngine.getMacro().getFrames().size()); + ImGui::Text("Macro actions: %zu", s_replayEngine.getMacro().getFrames().size()); ImGui::Text("Frame: %d", s_replayEngine.getFrame()); }); } @@ -177,30 +175,30 @@ namespace openhack::hacks { && !s_replayEngine.getMacro().getFrames().empty(); } - void Zephyrus::PlayerObjectPushButton(gd::PlayerObject *player, int buttonIndex) { - auto *playLayer = gd::PlayLayer::get(); + void Zephyrus::PlayerObjectPushButton(PlayerObject *player, int buttonIndex) { + auto *playLayer = PlayLayer::get(); if (playLayer == nullptr) return; s_replayEngine.PlayerObjectPushButton( - player == playLayer->m_player2() ? 1 : 0, + player == playLayer->m_player2 ? 1 : 0, buttonIndex); } - void Zephyrus::PlayerObjectReleaseButton(gd::PlayerObject *player, int buttonIndex) { - auto *playLayer = gd::PlayLayer::get(); + void Zephyrus::PlayerObjectReleaseButton(PlayerObject *player, int buttonIndex) { + auto *playLayer = PlayLayer::get(); if (playLayer == nullptr) return; s_replayEngine.PlayerObjectReleaseButton( - player == playLayer->m_player2() ? 1 : 0, + player == playLayer->m_player2 ? 1 : 0, buttonIndex); } void Zephyrus::GJBaseGameLayerProcessCommands() { - auto *playLayer = gd::PlayLayer::get(); + auto *playLayer = PlayLayer::get(); if (playLayer == nullptr) return; s_replayEngine.GJBaseGameLayerProcessCommands(); } void Zephyrus::PlayLayerResetLevel() { - auto *playLayer = gd::PlayLayer::get(); + auto *playLayer = PlayLayer::get(); if (playLayer == nullptr) return; s_levelFinished = false; s_replayEngine.PlayLayerResetLevel(); diff --git a/src/shared/hacks/zephyrus/replays.hpp b/src/shared/hacks/zephyrus/replays.hpp index 4d94c79..a5d6710 100644 --- a/src/shared/hacks/zephyrus/replays.hpp +++ b/src/shared/hacks/zephyrus/replays.hpp @@ -17,9 +17,9 @@ namespace openhack::hacks { public: /// @brief PlayerObject::pushButton hook - static void PlayerObjectPushButton(gd::PlayerObject* player, int buttonIndex); + static void PlayerObjectPushButton(PlayerObject* player, int buttonIndex); /// @brief PlayerObject::releaseButton hook - static void PlayerObjectReleaseButton(gd::PlayerObject* player, int buttonIndex); + static void PlayerObjectReleaseButton(PlayerObject* player, int buttonIndex); /// @brief GJBaseGameLayer::processCommands hook static void GJBaseGameLayerProcessCommands(); /// @brief PlayLayer::resetLevel hook diff --git a/src/shared/menu/keybinds.cpp b/src/shared/menu/keybinds.cpp index d325069..9c78623 100644 --- a/src/shared/menu/keybinds.cpp +++ b/src/shared/menu/keybinds.cpp @@ -3,23 +3,26 @@ #include "menu.hpp" namespace openhack::menu::keybinds { - static std::vector keybinds; + std::vector& getKeybinds() { + static std::vector keybinds; + return keybinds; + } void addKeybind(const Keybind &keybind) { - keybinds.push_back(keybind); + getKeybinds().push_back(keybind); } void removeKeybind(const std::string &id) { - for (auto it = keybinds.begin(); it != keybinds.end(); ++it) { + for (auto it = getKeybinds().begin(); it != getKeybinds().end(); ++it) { if (it->id == id) { - keybinds.erase(it); + getKeybinds().erase(it); return; } } } Keybind getKeybind(const std::string &id) { - for (auto &keybind: keybinds) { + for (auto &keybind: getKeybinds()) { if (keybind.id == id) { return keybind; } @@ -28,17 +31,13 @@ namespace openhack::menu::keybinds { } bool hasKeybind(const std::string &id) { - return std::any_of(keybinds.begin(), keybinds.end(), [&](const Keybind &keybind) { + return std::any_of(getKeybinds().begin(), getKeybinds().end(), [&](const Keybind &keybind) { return keybind.id == id; }); } - std::vector getKeybinds() { - return keybinds; - } - void setKeybindCallback(const std::string &id, const std::function &callback) { - for (auto &keybind: keybinds) { + for (auto &keybind: getKeybinds()) { if (keybind.id == id) { keybind.callback = callback; return; @@ -47,7 +46,7 @@ namespace openhack::menu::keybinds { } void load() { - keybinds = config::get("keybinds", std::vector()); + getKeybinds() = config::get("keybinds", std::vector()); // Create the keybinds window menu::addWindow("Keybinds", [&]() { @@ -61,10 +60,10 @@ namespace openhack::menu::keybinds { gui::checkbox("In-game only", "keybinds.ingame"); gui::tooltip("Only allow keybinds to be triggered when you're inside a level.\nUseful, to avoid triggering keybinds while searching for levels."); - if (keybinds.empty()) + if (getKeybinds().empty()) gui::text("Right click any hack and\npress \"Add keybind\" to set it."); - for (auto &keybind: keybinds) { + for (auto &keybind: getKeybinds()) { uint32_t originalKeycode = keybind.keycode; if (gui::keybind(keybind.name.c_str(), &keybind.keycode, true)) { removeKeybind(keybind.id); @@ -79,10 +78,10 @@ namespace openhack::menu::keybinds { } void update() { - if (config::get("keybinds.ingame") && !gd::PlayLayer::get()) + if (config::get("keybinds.ingame") && !PlayLayer::get()) return; - for (auto &keybind: keybinds) { + for (auto &keybind: getKeybinds()) { if (utils::isKeyPressed(keybind.keycode) && keybind.callback) { keybind.callback(); save(); @@ -91,7 +90,7 @@ namespace openhack::menu::keybinds { } void save() { - config::set("keybinds", keybinds); + config::set("keybinds", getKeybinds()); config::save(); } diff --git a/src/shared/menu/keybinds.hpp b/src/shared/menu/keybinds.hpp index bb27eb5..a80ea41 100644 --- a/src/shared/menu/keybinds.hpp +++ b/src/shared/menu/keybinds.hpp @@ -41,7 +41,7 @@ namespace openhack::menu::keybinds { /// @brief Gets all keybinds. /// @return All keybinds. - std::vector getKeybinds(); + std::vector& getKeybinds(); /// @brief Sets the callback for a keybind if it exists. /// @param id The ID of the keybind. diff --git a/src/shared/menu/menu.cpp b/src/shared/menu/menu.cpp index 6585ee2..88bc1a1 100644 --- a/src/shared/menu/menu.cpp +++ b/src/shared/menu/menu.cpp @@ -51,15 +51,15 @@ namespace openhack::menu { inline void updateCursorState() { bool canShowInLevel = true; - if (auto *playLayer = gd::PlayLayer::get()) { - canShowInLevel = playLayer->m_hasCompletedLevel() || - playLayer->m_isPaused() || - gd::GameManager::sharedState()->getGameVariable("0024"); + if (auto *playLayer = PlayLayer::get()) { + canShowInLevel = playLayer->m_hasCompletedLevel || + playLayer->m_isPaused || + GameManager::get()->getGameVariable("0024"); // "Click Teleport" enables cursor, so we need to check if it's enabled if (config::get("hack.click_tp.enabled", false)) return; } - gd::cocos2d::CCEGLView::sharedOpenGLView()->showCursor(isOpened || canShowInLevel); + cocos2d::CCEGLView::sharedOpenGLView()->showCursor(isOpened || canShowInLevel); } void toggle() { @@ -286,7 +286,6 @@ namespace openhack::menu { }); isInitialized = true; - } uint8_t firstRunState = 0; diff --git a/src/shared/openhack.hpp b/src/shared/openhack.hpp index 93a1dca..d9158be 100644 --- a/src/shared/openhack.hpp +++ b/src/shared/openhack.hpp @@ -21,7 +21,7 @@ #ifdef OPENHACK_GEODE #include "../geode/pch.hpp" -#include +// #include #define ON_GEODE(...) __VA_ARGS__ #define ON_STANDALONE(...) diff --git a/src/shared/platform/win32/sigscan.hpp b/src/shared/platform/win32/sigscan.hpp new file mode 100644 index 0000000..869d0ed --- /dev/null +++ b/src/shared/platform/win32/sigscan.hpp @@ -0,0 +1,479 @@ +#pragma once + +#include +#include +#include + +#define WIN32_LEAN_AND_MEAN + +#include +#include + +/// @brief Contains tools for signature scanning. +namespace gd::sigscan { + /* + * Pattern syntax: + * ? - any byte + * ^ - set address cursor + * * - multi pattern (finds all matches) + * 1F - byte value (any hex value) + * + * Example: + * "*6A106A0CE8????84C0^750B8BCE" + * 1. '*' tells to find all occurrences of the pattern + * 2. Then match this pattern: + * 6A 10 6A 0C E8 XX XX XX XX 84 C0 75 0B 8B CE + * ^ + * 3. Store address of the byte marked with '^' in the result + * + * This will return two addresses which we can use to patch the game. + * + */ + + /* + * Mask syntax: + * ? - any byte + * %([+/-]XX) - add or subtract XX from original byte value + * $([+/-]XX) - get byte value from original_address + XX as offset + * &([+/-]XX[+/-]YY) - combines % and $ (XX is offset, YY is value to add/subtract) + * *XX - repeat next mask token XX times + * @N(PATTERN) - look for a pattern and store a relative offset in N bytes (used for relative jumps) + * 1F - byte value (any hex value) + * + * Example 1: + * "909090909090C6?%(-3A)2D??01E9" + * 1. First 7 bytes ("909090909090C6") are simply replaced + * 2. Next byte ("?") is left as is + * 3. "%(-3A)" tells to subtract 0x3A from original byte value + * 4. "2D ? ? 01 E9" does the same as step 1-2 + * + * Example 2: + * "E9&(01+01)*03$0190" + * 1. "E9" is replaced + * 2. "&(01+01)" takes the value of the byte with offset 0x01 (next byte), + * adds 0x01 to it and stores it here + * 3. "*03" tells to repeat the next mask token 3 times: + * - "$01" gets the value of the next byte + * 4. "90" is replaced + * + * Example 3: + * "E9@4(8BCBFF15????^8B4C24?64890D00000000595F5E)" + * 1. "E9" is replaced (jmp) + * 2. "@4" tells to look for a pattern and store a relative offset in 4 bytes + * 3. "(8BCBFF15????^8B4C24?64890D00000000595F5E)" is the pattern to look for (see pattern syntax) + * If the offset for this pattern is 0x746, the final mask would be: + * "E942070000" (jmp 0x747) + * The changes from 0x746 to 0x742 and to 0x747 are explained by how relative jumps work in x86: + * - 0x746 to 0x742 is calculated by subtracting 4 bytes because the jump address is 4 bytes long + * - "E9 42070000" is actually "jmp 0x747" because the jump takes 5 bytes and jumps from it's end (0x742 + 5 = 0x747) + * + */ + + /// @brief A pattern token + struct PatternToken { + bool any_byte; // true if the byte is a wildcard + uint8_t byte; // value of the byte + bool set_address_cursor; // true if the address cursor should be set to this byte + bool multi_pattern; // true if the pattern should be matched multiple times + int8_t jump_if_fail; // valid inside [] brackets, tells how many tokens to skip in the pattern if the match fails + + PatternToken() : any_byte(false), byte(0), set_address_cursor(false), multi_pattern(false), jump_if_fail(0) {} + }; + + /// @brief A mask token + struct MaskToken { + bool any_byte; // true if the byte is a wildcard + + bool is_pattern; // true if the value should be an address to the pattern + bool is_relative; // true if the byte value should be changed by a relative offset + bool is_address; // true if the value of the byte should be taken from original_address + offset + + // NOTE: if is_relative and is_address are both true, + // the value of the byte will be taken from original_address + offset + value + + uint8_t value; // value to change the byte to + int8_t offset; // offset to add to the value + + std::string pattern; // pattern to calculate the offset from + + MaskToken() : any_byte(false), is_pattern(false), is_relative(false), is_address(false), value(0), offset(0) {} + }; + + /// @brief Result of a pattern match + struct Opcode { + uintptr_t address; + std::string library; + std::vector original; + std::vector patched; + + Opcode(uintptr_t address, std::string library, std::vector original, + std::vector patched) + : address(address), + library(std::move(library)), + original(std::move(original)), + patched(std::move(patched)) {} + }; + + inline PatternToken parseToken(std::string pattern, uint32_t ¤tIndex) { + PatternToken token; + token.any_byte = false; + token.byte = 0; + token.set_address_cursor = false; + token.multi_pattern = false; + token.jump_if_fail = -1; + + if (pattern[currentIndex] == '?') { + token.any_byte = true; + currentIndex++; + } else if (pattern[currentIndex] == '^') { + token.set_address_cursor = true; + currentIndex++; + } else if (pattern[currentIndex] == '*') { + token.multi_pattern = true; + currentIndex++; + } else { + token.byte = std::stoi(pattern.substr(currentIndex, 2), nullptr, 16); + currentIndex += 2; + } + + return token; + } + + inline bool eatToken(const char symbol, const std::string &pattern, uint32_t ¤tIndex) { + if (pattern[currentIndex] == symbol) { + currentIndex++; + return true; + } + return false; + } + + inline int8_t readSignedByte(const std::string &pattern, uint32_t ¤tIndex) { + bool is_negative = false; + switch (pattern[currentIndex]) { + case '+': + currentIndex++; + break; + case '-': + is_negative = true; + currentIndex++; + break; + default: + break; + } + + int8_t byte = std::stoi(pattern.substr(currentIndex, 2), nullptr, 16); + if (is_negative) + byte = -byte; + currentIndex += 2; + + return byte; + } + + /// @brief Parses a pattern string to get a list of tokens + /// @param pattern Pattern string + /// @return List of pattern tokens + inline std::vector parsePattern(const std::string &pattern) { + uint32_t current_index = 0; + std::vector tokens; + + while (current_index < pattern.length()) { + if (pattern[current_index] == ' ') { + current_index++; + continue; + } else if (eatToken('[', pattern, current_index)) { + std::vector sub_tokens; + while (!eatToken(']', pattern, current_index)) { + PatternToken token = parseToken(pattern, current_index); + sub_tokens.push_back(token); + } + + int32_t len = sub_tokens.size(); + for (uint32_t i = 0; i < sub_tokens.size(); i++) { + sub_tokens[i].jump_if_fail = len - i - 1; + } + + tokens.insert(tokens.end(), sub_tokens.begin(), sub_tokens.end()); + continue; + } + + PatternToken token = parseToken(pattern, current_index); + tokens.push_back(token); + } + + return tokens; + } + + /// @brief Parses a mask string to get a list of tokens + /// @param mask Mask string + /// @return List of mask tokens + inline std::vector parseMask(const std::string &mask) { + uint32_t current_index = 0; + std::vector bytes; + + uint32_t repeat_count = 1; + + while (current_index < mask.length()) { + MaskToken byte; + byte.any_byte = false; + byte.is_relative = false; + byte.is_address = false; + byte.value = 0; + byte.offset = 0; + + if (mask[current_index] == ' ') // ignore spaces + { + current_index++; + } else if (mask[current_index] == '?') // wildcard byte + { + byte.any_byte = true; + current_index++; + } else if (mask[current_index] == '%') // add/sub byte + { + byte.is_relative = true; + eatToken('(', mask, ++current_index); + byte.value = readSignedByte(mask, current_index); + eatToken(')', mask, current_index); + } else if (mask[current_index] == '$') // address byte + { + byte.is_address = true; + eatToken('(', mask, ++current_index); + byte.offset = readSignedByte(mask, current_index); + eatToken(')', mask, current_index); + } else if (mask[current_index] == '&') // address + add/sub byte + { + byte.is_address = true; + byte.is_relative = true; + eatToken('(', mask, ++current_index); + byte.offset = readSignedByte(mask, current_index); + byte.value = readSignedByte(mask, current_index); + eatToken(')', mask, current_index); + } else if (mask[current_index] == '*') // repeat next byte n times + { + eatToken('(', mask, ++current_index); + repeat_count = std::stoi(mask.substr(current_index, 2), nullptr, 16); + current_index += 2; + eatToken(')', mask, current_index); + continue; + } else if (mask[current_index] == '@') // calculate offset by pattern + { + byte.is_pattern = true; + // read how many bytes should be stored + uint8_t bytes_to_store = std::stoi(mask.substr(++current_index, 1), nullptr, 10); + eatToken('(', mask, ++current_index); + + // read the pattern + std::string pattern; + while (!eatToken(')', mask, current_index)) { + pattern += mask[current_index]; + current_index++; + } + + byte.value = bytes_to_store; + byte.pattern = pattern; + } else { + byte.value = std::stoi(mask.substr(current_index, 2), nullptr, 16); + current_index += 2; + } + + for (uint32_t i = 0; i < repeat_count; i++) + bytes.push_back(byte); + + repeat_count = 1; + } + + return bytes; + } + + /// @brief Finds a pattern in a library + /// @param pattern A list of pattern tokens + /// @param library Library name + /// @return All found addresses + inline std::vector findPattern(std::vector pattern, const std::string &library = "") { + // get module handle + HMODULE module; + if (library.empty()) + module = GetModuleHandle(nullptr); + else + module = GetModuleHandle(library.c_str()); + + if (module == nullptr) + return {}; + + bool search_all = false; + + // check if first token is a wildcard + if (pattern[0].multi_pattern) { + search_all = true; + pattern.erase(pattern.begin()); + } + + // get module info + MODULEINFO module_info; + if (!GetModuleInformation(GetCurrentProcess(), module, &module_info, sizeof(MODULEINFO))) + return {}; + + std::vector addresses; + + // iterate over module memory + for (uint32_t i = 0; i < module_info.SizeOfImage; i++) { + bool found = true; + void *address = (void *) ((uintptr_t) module + i); + void *addr = address; + bool set_address_cursor = false; + uint32_t subtracted_bytes = 0; + uint32_t max_jump_length = -1; + + // iterate over pattern tokens + for (uint32_t j = 0; j < pattern.size(); j++) { + // check if we need to set the address cursor + if (pattern[j].set_address_cursor) { + // set address to current address + addr = (void *) ((uintptr_t) address + j); + set_address_cursor = true; + continue; + } + + // if cursor has been set, we need to offset j by 1 + uintptr_t addr = (uintptr_t) address + (set_address_cursor ? j - 1 : j) - subtracted_bytes; + + // check if we have enough memory left + if (addr >= (uintptr_t) module + module_info.SizeOfImage) { + found = false; + break; + } + + if (pattern[j].jump_if_fail != -1 && max_jump_length == -1) { + max_jump_length = pattern[j].jump_if_fail; + } else if (pattern[j].jump_if_fail == -1) { + max_jump_length = -1; + } + + // check if we have a match + if (!pattern[j].any_byte && *(uint8_t *) (addr) != pattern[j].byte) { + // check if has "jump_if_fail" set + if (pattern[j].jump_if_fail != -1) { + // jump to the next token + j += pattern[j].jump_if_fail; + + // we also need to make sure we return to the original address before the [] brackets + subtracted_bytes += max_jump_length + 1; + continue; + } + + found = false; + break; + } + } + + // return address offset for base address + if (found) { + if (search_all) + addresses.push_back((uintptr_t) addr); + else + return {(uintptr_t) addr}; + } + } + + return addresses; + } + + /// @brief Finds a pattern in a library + /// @param pattern Pattern string + /// @param library Library name + /// @return All found addresses + inline std::vector findPatterns(const std::string &pattern, const std::string &library = "") { + return findPattern(parsePattern(pattern), library); + } + + /// @brief Finds a pattern in a library + /// @param pattern Pattern string + /// @param library Library name + /// @return The first found address + inline uintptr_t findPattern(const std::string &pattern, const std::string &library = "") { + auto result = findPatterns(pattern, library); + if (result.empty()) { + return 0; + } + return result[0]; + } + + /// @brief Finds a pattern in a library + /// @param pattern Pattern string + /// @param mask Mask string + /// @param library Library name + /// @return All opcodes found + inline std::vector + match(const std::string &pattern, const std::string &mask = "", const std::string &library = "") { + std::vector results; + + auto patternTokens = parsePattern(pattern); + auto maskTokens = parseMask(mask); + + // find pattern + auto addresses = findPattern(patternTokens, library); + if (addresses.empty()) + return results; + + for (auto &address: addresses) { + // address is the base address, so we need to offset it + uintptr_t module_addr; + if (library.empty()) + module_addr = (uintptr_t) GetModuleHandle(nullptr); + else + module_addr = (uintptr_t) GetModuleHandle(library.c_str()); + + Opcode opcode((uintptr_t) address - module_addr, library, {}, {}); + uintptr_t global_offset = 0; + + + // read bytes + for (uint32_t i = 0; i < maskTokens.size(); i++) { + uintptr_t curr_address = (uintptr_t) address + i + global_offset; + uint8_t byte = *(uint8_t *) curr_address; + opcode.original.push_back(byte); + + if (maskTokens[i].any_byte) { + // add wildcard byte + opcode.patched.push_back(byte); + } else if (maskTokens[i].is_relative && maskTokens[i].is_address) { + // take byte from relative address and add value + uint8_t value = *(uint8_t *) (curr_address + maskTokens[i].offset); + opcode.patched.push_back(value + maskTokens[i].value); + } else if (maskTokens[i].is_relative) { + // add value to current byte + opcode.patched.push_back(byte + maskTokens[i].value); + } else if (maskTokens[i].is_address) { + // take byte from relative address + uint8_t value = *(uint8_t *) (curr_address + maskTokens[i].offset); + opcode.patched.push_back(value); + } else if (maskTokens[i].is_pattern) { + // find pattern and calculate offset + uintptr_t addr = findPattern(maskTokens[i].pattern, library); + + uintptr_t offset = (uintptr_t) addr - (uintptr_t) curr_address; + offset -= maskTokens[i].value; + + // format offset to bytes + for (uint32_t j = 0; j < maskTokens[i].value; j++) { + curr_address = (uintptr_t) address + i + global_offset + j; + uint8_t byte = *(uint8_t *) curr_address; + + if (j > 0) // first byte was added already + opcode.original.push_back(byte); + + opcode.patched.push_back((offset >> (j * 8)) & 0xFF); + } + + global_offset += maskTokens[i].value; + } else { + // set byte to a specific value + opcode.patched.push_back(maskTokens[i].value); + } + } + + results.push_back(opcode); + } + + return results; + } +} \ No newline at end of file diff --git a/src/shared/platform/win32/win32.cpp b/src/shared/platform/win32/win32.cpp new file mode 100644 index 0000000..1ee7e3e --- /dev/null +++ b/src/shared/platform/win32/win32.cpp @@ -0,0 +1,430 @@ +#include "win32.hpp" + +namespace openhack::utils { + std::string getCurrentDirectory() { + char buffer[MAX_PATH]; + GetModuleFileNameA(nullptr, buffer, MAX_PATH); + std::string::size_type pos = std::string(buffer).find_last_of("\\/"); + return std::string(buffer).substr(0, pos); + } + + std::string getSaveDirectory() { + char buffer[MAX_PATH]; + SHGetFolderPathA(nullptr, CSIDL_LOCAL_APPDATA, nullptr, 0, buffer); + std::string path = std::string(buffer) + "\\GeometryDash"; + return path; + } + + void openDirectory(const char *path) { + ShellExecuteA(nullptr, "open", path, nullptr, nullptr, SW_SHOWNORMAL); + } + + void openURL(const char *url) { + ShellExecuteA(nullptr, "open", url, nullptr, nullptr, SW_SHOW); + } + + uintptr_t getModuleHandle(const char *module) { + return reinterpret_cast(GetModuleHandleA(module)); + } + + bool patchMemory(uintptr_t address, const std::vector &bytes) { + DWORD oldProtect; + if (VirtualProtect((LPVOID) address, bytes.size(), PAGE_EXECUTE_READWRITE, &oldProtect)) { + memcpy((void *) address, bytes.data(), bytes.size()); + VirtualProtect((LPVOID) address, bytes.size(), oldProtect, &oldProtect); + return true; + } + return false; + } + + std::vector readMemory(uintptr_t address, size_t size) { + std::vector buffer(size); + memcpy(buffer.data(), (void *) address, size); + return buffer; + } + + /// @brief Automatically checks the game version and returns it. + /// @return The game version. + std::string getGameVersion() { + static std::string gameVersion; + if (!gameVersion.empty()) + return gameVersion; + + HMODULE module = GetModuleHandleA(nullptr); + auto dosHeader = (PIMAGE_DOS_HEADER) module; + + if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) { + gameVersion = "Unknown"; + return gameVersion; + } + + auto ntHeaders = (PIMAGE_NT_HEADERS) ((uint8_t *) module + dosHeader->e_lfanew); + if (ntHeaders->Signature != IMAGE_NT_SIGNATURE) { + gameVersion = "Unknown"; + return gameVersion; + } + + std::map versionsMap = { + {1419173053, "1.900"}, + {1419880840, "1.910"}, + {1421745341, "1.920"}, + {1440638199, "2.000"}, + {1440643927, "2.001"}, + {1443053232, "2.010"}, + {1443077847, "2.011"}, + {1443077847, "2.020"}, + {1484612867, "2.100"}, + {1484626658, "2.101"}, + {1484737207, "2.102"}, + {1510526914, "2.110"}, + {1510538091, "2.111"}, + {1510619253, "2.112"}, + {1511220108, "2.113"}, + {1702921605, "2.200"}, + {1704582672, "2.201"}, + {1704601266, "2.202"}, + {1704948277, "2.203"}, + {1705041028, "2.204"}, + {1717243515, "2.206"} + }; + + uint32_t timestamp = ntHeaders->FileHeader.TimeDateStamp; + auto version = versionsMap.find(timestamp); + if (version != versionsMap.end()) { + gameVersion = version->second; + return gameVersion; + } + + // check if larger than latest version + if (timestamp > versionsMap.rbegin()->first) { + // split by dot + std::vector version; + std::string version_str = versionsMap.rbegin()->second; + std::string delimiter = "."; + size_t pos; + std::string token; + while ((pos = version_str.find(delimiter)) != std::string::npos) { + token = version_str.substr(0, pos); + version.push_back(token); + version_str.erase(0, pos + delimiter.length()); + } + version.push_back(version_str); + + // increment last number + int32_t last = atoi(version[1].c_str()); + last++; + version[1] = std::to_string(last); + + // join by dot + gameVersion = version[0] + "." + version[1]; + return gameVersion; + } + + gameVersion = "Unknown"; + return gameVersion; + } + + const std::map& getKeyNames() { + static std::map KEY_NAMES = { + {0, "..."}, // unset key + {VK_LBUTTON, "LMB"}, + {VK_RBUTTON, "RMB"}, + {VK_MBUTTON, "MMB"}, + {VK_XBUTTON1, "X1"}, + {VK_XBUTTON2, "X2"}, + {VK_BACK, "Backspace"}, + {VK_TAB, "Tab"}, + {VK_CLEAR, "Clear"}, + {VK_RETURN, "Enter"}, + {VK_SHIFT, "Shift"}, + {VK_CONTROL, "Ctrl"}, + {VK_MENU, "Alt"}, + {VK_PAUSE, "Pause"}, + {VK_CAPITAL, "Caps Lock"}, + {VK_ESCAPE, "Esc"}, + {VK_SPACE, "Space"}, + {VK_PRIOR, "Page Up"}, + {VK_NEXT, "Page Down"}, + {VK_END, "End"}, + {VK_HOME, "Home"}, + {VK_LEFT, "Left"}, + {VK_UP, "Up"}, + {VK_RIGHT, "Right"}, + {VK_DOWN, "Down"}, + {VK_SELECT, "Select"}, + {VK_PRINT, "Print"}, + {VK_EXECUTE, "Execute"}, + {VK_SNAPSHOT, "Print Screen"}, + {VK_INSERT, "Insert"}, + {VK_DELETE, "Delete"}, + {VK_HELP, "Help"}, + {VK_LWIN, "Left Windows"}, + {VK_RWIN, "Right Windows"}, + {VK_APPS, "Applications"}, + {VK_SLEEP, "Sleep"}, + {VK_NUMPAD0, "Numpad 0"}, + {VK_NUMPAD1, "Numpad 1"}, + {VK_NUMPAD2, "Numpad 2"}, + {VK_NUMPAD3, "Numpad 3"}, + {VK_NUMPAD4, "Numpad 4"}, + {VK_NUMPAD5, "Numpad 5"}, + {VK_NUMPAD6, "Numpad 6"}, + {VK_NUMPAD7, "Numpad 7"}, + {VK_NUMPAD8, "Numpad 8"}, + {VK_NUMPAD9, "Numpad 9"}, + {VK_MULTIPLY, "Numpad *"}, + {VK_ADD, "Numpad +"}, + {VK_SEPARATOR, "Numpad Separator"}, + {VK_SUBTRACT, "Numpad -"}, + {VK_DECIMAL, "Numpad ."}, + {VK_DIVIDE, "Numpad /"}, + {VK_F1, "F1"}, + {VK_F2, "F2"}, + {VK_F3, "F3"}, + {VK_F4, "F4"}, + {VK_F5, "F5"}, + {VK_F6, "F6"}, + {VK_F7, "F7"}, + {VK_F8, "F8"}, + {VK_F9, "F9"}, + {VK_F10, "F10"}, + {VK_F11, "F11"}, + {VK_F12, "F12"}, + {VK_F13, "F13"}, + {VK_F14, "F14"}, + {VK_F15, "F15"}, + {VK_F16, "F16"}, + {VK_F17, "F17"}, + {VK_F18, "F18"}, + {VK_F19, "F19"}, + {VK_F20, "F20"}, + {VK_F21, "F21"}, + {VK_F22, "F22"}, + {VK_F23, "F23"}, + {VK_F24, "F24"}, + {VK_NUMLOCK, "Num Lock"}, + {VK_SCROLL, "Scroll Lock"}, + {VK_LSHIFT, "Left Shift"}, + {VK_RSHIFT, "Right Shift"}, + {VK_LCONTROL, "Left Ctrl"}, + {VK_RCONTROL, "Right Ctrl"}, + {VK_LMENU, "Left Alt"}, + {VK_RMENU, "Right Alt"}, + {VK_BROWSER_BACK, "Browser Back"}, + {VK_BROWSER_FORWARD, "Browser Forward"}, + {VK_BROWSER_REFRESH, "Browser Refresh"}, + {VK_BROWSER_STOP, "Browser Stop"}, + {VK_BROWSER_SEARCH, "Browser Search"}, + {VK_BROWSER_FAVORITES, "Browser Favorites"}, + {VK_BROWSER_HOME, "Browser Home"}, + {VK_VOLUME_MUTE, "Volume Mute"}, + {VK_VOLUME_DOWN, "Volume Down"}, + {VK_VOLUME_UP, "Volume Up"}, + {VK_MEDIA_NEXT_TRACK, "Next Track"}, + {VK_MEDIA_PREV_TRACK, "Previous Track"}, + {VK_MEDIA_STOP, "Stop"}, + {VK_MEDIA_PLAY_PAUSE, "Play/Pause"}, + {VK_LAUNCH_MAIL, "Launch Mail"}, + {VK_LAUNCH_MEDIA_SELECT, "Select Media"}, + {VK_LAUNCH_APP1, "Launch App 1"}, + {VK_LAUNCH_APP2, "Launch App 2"}, + {VK_OEM_1, ";"}, + {VK_OEM_PLUS, "+"}, + {VK_OEM_COMMA, ","}, + {VK_OEM_MINUS, "-"}, + {VK_OEM_PERIOD, "."}, + {VK_OEM_2, "/"}, + {VK_OEM_3, "`"}, + {VK_OEM_4, "["}, + {VK_OEM_5, "\\"}, + {VK_OEM_6, "]"}, + {VK_OEM_7, "'"}, + {VK_OEM_8, "OEM 8"}, + {VK_OEM_102, "OEM 102"}, + {VK_PROCESSKEY, "IME Process"}, + {VK_PACKET, "Packet"}, + {VK_ATTN, "Attn"}, + {VK_CRSEL, "CrSel"}, + {VK_EXSEL, "ExSel"}, + {VK_EREOF, "Erase EOF"}, + {VK_PLAY, "Play"}, + {VK_ZOOM, "Zoom"}, + {VK_NONAME, "NoName"}, + {VK_PA1, "PA1"}, + {VK_OEM_CLEAR, "Clear"}, + }; + return KEY_NAMES; + } + + std::string getKeyName(uint32_t keycode) { + // find key in map + for (auto &key: getKeyNames()) { + if (key.first == keycode) { + return key.second; + } + } + + // check if key is a letter + if (keycode >= 0x41 && keycode <= 0x5A) { + return std::string(1, (char) keycode); + } + + // check if key is a number + if (keycode >= 0x30 && keycode <= 0x39) { + return std::string(1, (char) keycode); + } + + return "Unknown"; + } + + uint32_t getKeyCode(std::string key) { + // find key in map + for (auto &key_: getKeyNames()) { + // compare lowercase strings + std::string key_lower = key; + std::transform(key_lower.begin(), key_lower.end(), key_lower.begin(), ::tolower); + std::string key_lower_ = key_.second; + std::transform(key_lower_.begin(), key_lower_.end(), key_lower_.begin(), ::tolower); + if (key_lower == key_lower_) { + return key_.first; + } + } + + // check if key is a letter + if (key.length() == 1) { + return (uint32_t) key[0]; + } + + return 0; + } + + HWND WINDOW_HANDLE = nullptr; + + HWND getWindowHandle() { + if (WINDOW_HANDLE != nullptr) + return WINDOW_HANDLE; + + auto *director = cocos2d::CCDirector::sharedDirector(); + auto *window = director->getOpenGLView()->getWindow(); + WINDOW_HANDLE = WindowFromDC(*reinterpret_cast(reinterpret_cast(window) + 0x278)); + return WINDOW_HANDLE; + } + + void resetWindowHandle() { + WINDOW_HANDLE = nullptr; + } + + std::map& getKeyStates() { + static std::map keyStates; + return keyStates; + } + + std::map& getKeyStatesPrevious() { + static std::map keyStatesPrevious; + return keyStatesPrevious; + } + + bool isKeyDown(uint32_t keycode) { + return GetAsyncKeyState(keycode) & 0x8000; + } + + bool isKeyDown(std::string key) { + return isKeyDown(getKeyCode(std::move(key))); + } + + bool isKeyPressed(uint32_t keycode) { + // if window is not focused + if (GetForegroundWindow() != getWindowHandle()) + return false; + + // if state changed + if (getKeyStates()[keycode] ^ getKeyStatesPrevious()[keycode]) { + // return current state + return getKeyStates()[keycode]; + } + + return false; + } + + bool isKeyPressed(std::string key) { + return isKeyPressed(getKeyCode(std::move(key))); + } + + bool isKeyReleased(uint32_t keycode) { + // if window is not focused + if (GetForegroundWindow() != getWindowHandle()) + return false; + + // if state changed + if (getKeyStates()[keycode] ^ getKeyStatesPrevious()[keycode]) { + // return current state + return !getKeyStates()[keycode]; + } + + return false; + } + + bool isKeyReleased(std::string key) { + return isKeyReleased(getKeyCode(std::move(key))); + } + + void resetKeyStates() { + // set previous states + for (auto& [key, value]: getKeyStates()) { + getKeyStatesPrevious()[key] = value; + } + + // reset all keys + for (int i = 0; i < 256; i++) { + getKeyStates()[i] = GetAsyncKeyState(i) & 0x8000; + } + } + + void pressKey(uint32_t keycode) { + keybd_event(keycode, 0, 0, 0); + keybd_event(keycode, 0, KEYEVENTF_KEYUP, 0); + } + + void pressKey(std::string key) { + pressKey(getKeyCode(std::move(key))); + } + + std::filesystem::path filePickerDialog(const char *filter, const char *title) { + OPENFILENAME ofn; + char szFile[260] = {0}; + ZeroMemory(&ofn, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = nullptr; + ofn.lpstrFile = szFile; + ofn.nMaxFile = sizeof(szFile); + ofn.lpstrFilter = filter; + ofn.nFilterIndex = 1; + ofn.lpstrFileTitle = nullptr; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = nullptr; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; + ofn.lpstrTitle = title; + GetOpenFileName(&ofn); + return ofn.lpstrFile; + } + + /// @brief Open a file dialog to save a file. + std::filesystem::path fileSaveDialog(const char *filter, const char *title) { + OPENFILENAME ofn; + char szFile[260] = {0}; + ZeroMemory(&ofn, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = nullptr; + ofn.lpstrFile = szFile; + ofn.nMaxFile = sizeof(szFile); + ofn.lpstrFilter = filter; + ofn.nFilterIndex = 1; + ofn.lpstrFileTitle = nullptr; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = nullptr; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; + ofn.lpstrTitle = title; + GetSaveFileName(&ofn); + return ofn.lpstrFile; + } +} \ No newline at end of file diff --git a/src/shared/platform/win32/win32.hpp b/src/shared/platform/win32/win32.hpp index 003f8ee..f42b0e6 100644 --- a/src/shared/platform/win32/win32.hpp +++ b/src/shared/platform/win32/win32.hpp @@ -13,59 +13,33 @@ #include "dll_inject.hpp" -#include - namespace openhack::utils { /// @brief Gets the current directory of the running executable. /// @return The current directory. - inline std::string getCurrentDirectory() { - char buffer[MAX_PATH]; - GetModuleFileNameA(nullptr, buffer, MAX_PATH); - std::string::size_type pos = std::string(buffer).find_last_of("\\/"); - return std::string(buffer).substr(0, pos); - } + std::string getCurrentDirectory(); /// @brief Gets the save directory of Geometry Dash. /// @return The save directory. - inline std::string getSaveDirectory() { - char buffer[MAX_PATH]; - SHGetFolderPathA(nullptr, CSIDL_LOCAL_APPDATA, nullptr, 0, buffer); - std::string path = std::string(buffer) + "\\GeometryDash"; - return path; - } + std::string getSaveDirectory(); /// @brief Opens a directory in the file explorer. /// @param path The path of the directory. - inline void openDirectory(const char *path) { - ShellExecuteA(nullptr, "open", path, nullptr, nullptr, SW_SHOWNORMAL); - } + void openDirectory(const char *path); /// @brief Opens a URL in the default web browser. /// @param url The URL to open. - inline void openURL(const char *url) { - ShellExecuteA(nullptr, "open", url, nullptr, nullptr, SW_SHOW); - } + void openURL(const char *url); /// @brief Gets the handle of the module with the given name. /// @param module The name of the module. /// @return The handle of the module. - inline uintptr_t getModuleHandle(const char *module = nullptr) { - return reinterpret_cast(GetModuleHandleA(module)); - } + uintptr_t getModuleHandle(const char *module = nullptr); /// @brief Write bytes to the game's memory. /// @param address The address to write to. /// @param bytes The bytes to write. /// @return True if the bytes were successfully written. - inline bool patchMemory(uintptr_t address, const std::vector &bytes) { - DWORD oldProtect; - if (VirtualProtect((LPVOID) address, bytes.size(), PAGE_EXECUTE_READWRITE, &oldProtect)) { - memcpy((void *) address, bytes.data(), bytes.size()); - VirtualProtect((LPVOID) address, bytes.size(), oldProtect, &oldProtect); - return true; - } - return false; - } + bool patchMemory(uintptr_t address, const std::vector &bytes); /// @brief Write a value to the game's memory. /// @tparam T The type of the value. @@ -81,413 +55,68 @@ namespace openhack::utils { /// @param address The address to read from. /// @param size The amount of bytes to read. /// @return The bytes read from the memory. - inline std::vector readMemory(uintptr_t address, size_t size) { - std::vector buffer(size); - memcpy(buffer.data(), (void *) address, size); - return buffer; - } - - inline std::string gameVersion; + std::vector readMemory(uintptr_t address, size_t size); /// @brief Automatically checks the game version and returns it. /// @return The game version. - inline std::string getGameVersion() { - if (!gameVersion.empty()) - return gameVersion; - - HMODULE module = GetModuleHandleA(nullptr); - auto dosHeader = (PIMAGE_DOS_HEADER) module; - - if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) { - gameVersion = "Unknown"; - return gameVersion; - } - - auto ntHeaders = (PIMAGE_NT_HEADERS) ((uint8_t *) module + dosHeader->e_lfanew); - if (ntHeaders->Signature != IMAGE_NT_SIGNATURE) { - gameVersion = "Unknown"; - return gameVersion; - } - - std::map versionsMap = { - {1419173053, "1.900"}, - {1419880840, "1.910"}, - {1421745341, "1.920"}, - {1440638199, "2.000"}, - {1440643927, "2.001"}, - {1443053232, "2.010"}, - {1443077847, "2.011"}, - {1443077847, "2.020"}, - {1484612867, "2.100"}, - {1484626658, "2.101"}, - {1484737207, "2.102"}, - {1510526914, "2.110"}, - {1510538091, "2.111"}, - {1510619253, "2.112"}, - {1511220108, "2.113"}, - {1702921605, "2.200"}, - {1704582672, "2.201"}, - {1704601266, "2.202"}, - {1704948277, "2.203"}, - {1705041028, "2.204"}, - {1717243515, "2.206"} - }; - - uint32_t timestamp = ntHeaders->FileHeader.TimeDateStamp; - auto version = versionsMap.find(timestamp); - if (version != versionsMap.end()) { - gameVersion = version->second; - return gameVersion; - } - - // check if larger than latest version - if (timestamp > versionsMap.rbegin()->first) { - // split by dot - std::vector version; - std::string version_str = versionsMap.rbegin()->second; - std::string delimiter = "."; - size_t pos; - std::string token; - while ((pos = version_str.find(delimiter)) != std::string::npos) { - token = version_str.substr(0, pos); - version.push_back(token); - version_str.erase(0, pos + delimiter.length()); - } - version.push_back(version_str); - - // increment last number - int32_t last = atoi(version[1].c_str()); - last++; - version[1] = std::to_string(last); - - // join by dot - gameVersion = version[0] + "." + version[1]; - return gameVersion; - } - - gameVersion = "Unknown"; - return gameVersion; - } - - inline std::map KEY_NAMES = { - {0, "..."}, // unset key - {VK_LBUTTON, "LMB"}, - {VK_RBUTTON, "RMB"}, - {VK_MBUTTON, "MMB"}, - {VK_XBUTTON1, "X1"}, - {VK_XBUTTON2, "X2"}, - {VK_BACK, "Backspace"}, - {VK_TAB, "Tab"}, - {VK_CLEAR, "Clear"}, - {VK_RETURN, "Enter"}, - {VK_SHIFT, "Shift"}, - {VK_CONTROL, "Ctrl"}, - {VK_MENU, "Alt"}, - {VK_PAUSE, "Pause"}, - {VK_CAPITAL, "Caps Lock"}, - {VK_ESCAPE, "Esc"}, - {VK_SPACE, "Space"}, - {VK_PRIOR, "Page Up"}, - {VK_NEXT, "Page Down"}, - {VK_END, "End"}, - {VK_HOME, "Home"}, - {VK_LEFT, "Left"}, - {VK_UP, "Up"}, - {VK_RIGHT, "Right"}, - {VK_DOWN, "Down"}, - {VK_SELECT, "Select"}, - {VK_PRINT, "Print"}, - {VK_EXECUTE, "Execute"}, - {VK_SNAPSHOT, "Print Screen"}, - {VK_INSERT, "Insert"}, - {VK_DELETE, "Delete"}, - {VK_HELP, "Help"}, - {VK_LWIN, "Left Windows"}, - {VK_RWIN, "Right Windows"}, - {VK_APPS, "Applications"}, - {VK_SLEEP, "Sleep"}, - {VK_NUMPAD0, "Numpad 0"}, - {VK_NUMPAD1, "Numpad 1"}, - {VK_NUMPAD2, "Numpad 2"}, - {VK_NUMPAD3, "Numpad 3"}, - {VK_NUMPAD4, "Numpad 4"}, - {VK_NUMPAD5, "Numpad 5"}, - {VK_NUMPAD6, "Numpad 6"}, - {VK_NUMPAD7, "Numpad 7"}, - {VK_NUMPAD8, "Numpad 8"}, - {VK_NUMPAD9, "Numpad 9"}, - {VK_MULTIPLY, "Numpad *"}, - {VK_ADD, "Numpad +"}, - {VK_SEPARATOR, "Numpad Separator"}, - {VK_SUBTRACT, "Numpad -"}, - {VK_DECIMAL, "Numpad ."}, - {VK_DIVIDE, "Numpad /"}, - {VK_F1, "F1"}, - {VK_F2, "F2"}, - {VK_F3, "F3"}, - {VK_F4, "F4"}, - {VK_F5, "F5"}, - {VK_F6, "F6"}, - {VK_F7, "F7"}, - {VK_F8, "F8"}, - {VK_F9, "F9"}, - {VK_F10, "F10"}, - {VK_F11, "F11"}, - {VK_F12, "F12"}, - {VK_F13, "F13"}, - {VK_F14, "F14"}, - {VK_F15, "F15"}, - {VK_F16, "F16"}, - {VK_F17, "F17"}, - {VK_F18, "F18"}, - {VK_F19, "F19"}, - {VK_F20, "F20"}, - {VK_F21, "F21"}, - {VK_F22, "F22"}, - {VK_F23, "F23"}, - {VK_F24, "F24"}, - {VK_NUMLOCK, "Num Lock"}, - {VK_SCROLL, "Scroll Lock"}, - {VK_LSHIFT, "Left Shift"}, - {VK_RSHIFT, "Right Shift"}, - {VK_LCONTROL, "Left Ctrl"}, - {VK_RCONTROL, "Right Ctrl"}, - {VK_LMENU, "Left Alt"}, - {VK_RMENU, "Right Alt"}, - {VK_BROWSER_BACK, "Browser Back"}, - {VK_BROWSER_FORWARD, "Browser Forward"}, - {VK_BROWSER_REFRESH, "Browser Refresh"}, - {VK_BROWSER_STOP, "Browser Stop"}, - {VK_BROWSER_SEARCH, "Browser Search"}, - {VK_BROWSER_FAVORITES, "Browser Favorites"}, - {VK_BROWSER_HOME, "Browser Home"}, - {VK_VOLUME_MUTE, "Volume Mute"}, - {VK_VOLUME_DOWN, "Volume Down"}, - {VK_VOLUME_UP, "Volume Up"}, - {VK_MEDIA_NEXT_TRACK, "Next Track"}, - {VK_MEDIA_PREV_TRACK, "Previous Track"}, - {VK_MEDIA_STOP, "Stop"}, - {VK_MEDIA_PLAY_PAUSE, "Play/Pause"}, - {VK_LAUNCH_MAIL, "Launch Mail"}, - {VK_LAUNCH_MEDIA_SELECT, "Select Media"}, - {VK_LAUNCH_APP1, "Launch App 1"}, - {VK_LAUNCH_APP2, "Launch App 2"}, - {VK_OEM_1, ";"}, - {VK_OEM_PLUS, "+"}, - {VK_OEM_COMMA, ","}, - {VK_OEM_MINUS, "-"}, - {VK_OEM_PERIOD, "."}, - {VK_OEM_2, "/"}, - {VK_OEM_3, "`"}, - {VK_OEM_4, "["}, - {VK_OEM_5, "\\"}, - {VK_OEM_6, "]"}, - {VK_OEM_7, "'"}, - {VK_OEM_8, "OEM 8"}, - {VK_OEM_102, "OEM 102"}, - {VK_PROCESSKEY, "IME Process"}, - {VK_PACKET, "Packet"}, - {VK_ATTN, "Attn"}, - {VK_CRSEL, "CrSel"}, - {VK_EXSEL, "ExSel"}, - {VK_EREOF, "Erase EOF"}, - {VK_PLAY, "Play"}, - {VK_ZOOM, "Zoom"}, - {VK_NONAME, "NoName"}, - {VK_PA1, "PA1"}, - {VK_OEM_CLEAR, "Clear"}, - }; + std::string getGameVersion(); /// @brief Convert a key code to a key name. /// @param keycode The key code. /// @return The key name. - inline std::string getKeyName(uint32_t keycode) { - // find key in map - for (auto &key: KEY_NAMES) { - if (key.first == keycode) { - return key.second; - } - } - - // check if key is a letter - if (keycode >= 0x41 && keycode <= 0x5A) { - return std::string(1, (char) keycode); - } - - // check if key is a number - if (keycode >= 0x30 && keycode <= 0x39) { - return std::string(1, (char) keycode); - } - - return "Unknown"; - } + std::string getKeyName(uint32_t keycode); /// @brief Convert a key name to a key code. /// @param key The key name. /// @return The key code. - inline uint32_t getKeyCode(std::string key) { - // find key in map - for (auto &key_: KEY_NAMES) { - // compare lowercase strings - std::string key_lower = key; - std::transform(key_lower.begin(), key_lower.end(), key_lower.begin(), ::tolower); - std::string key_lower_ = key_.second; - std::transform(key_lower_.begin(), key_lower_.end(), key_lower_.begin(), ::tolower); - if (key_lower == key_lower_) { - return key_.first; - } - } - - // check if key is a letter - if (key.length() == 1) { - return (uint32_t) key[0]; - } - - return 0; - } - - inline HWND WINDOW_HANDLE = nullptr; + uint32_t getKeyCode(std::string key); /// @brief Gets the window handle of the game. - inline HWND getWindowHandle() { - if (WINDOW_HANDLE != nullptr) - return WINDOW_HANDLE; - - auto *director = gd::cocos2d::CCDirector::sharedDirector(); - auto *window = director->getOpenGLView()->getWindow(); - WINDOW_HANDLE = WindowFromDC(*reinterpret_cast(reinterpret_cast(window) + 0x244)); - return WINDOW_HANDLE; - } + HWND getWindowHandle(); /// @brief Resets the window handle. - inline void resetWindowHandle() { - WINDOW_HANDLE = nullptr; - } - - inline std::map KEY_STATES; - inline std::map KEY_STATES_PREVIOUS; + void resetWindowHandle(); /// @brief Check whether a key is down. - inline bool isKeyDown(uint32_t keycode) { - return GetAsyncKeyState(keycode) & 0x8000; - } + bool isKeyDown(uint32_t keycode); /// @brief Check whether a key is down. - inline bool isKeyDown(std::string key) { - return isKeyDown(getKeyCode(std::move(key))); - } + bool isKeyDown(std::string key); /// @brief Check whether a key was pressed during the current frame. /// @param keycode The key code. /// @return True if the key was pressed. - inline bool isKeyPressed(uint32_t keycode) { - // if window is not focused - if (GetForegroundWindow() != getWindowHandle()) - return false; - - // if state changed - if (KEY_STATES[keycode] ^ KEY_STATES_PREVIOUS[keycode]) { - // return current state - return KEY_STATES[keycode]; - } - - return false; - } + bool isKeyPressed(uint32_t keycode); /// @brief Check whether a key was pressed during the current frame. /// @param key Key name. /// @return True if the key was pressed. - inline bool isKeyPressed(std::string key) { - return isKeyPressed(getKeyCode(std::move(key))); - } + bool isKeyPressed(std::string key); /// @brief Check whether a key was released during the current frame. /// @param keycode The key code. /// @return True if the key was released. - inline bool isKeyReleased(uint32_t keycode) { - // if window is not focused - if (GetForegroundWindow() != getWindowHandle()) - return false; - - // if state changed - if (KEY_STATES[keycode] ^ KEY_STATES_PREVIOUS[keycode]) { - // return current state - return !KEY_STATES[keycode]; - } - - return false; - } + bool isKeyReleased(uint32_t keycode); /// @brief Check whether a key was released during the current frame. /// @param key Key name. /// @return True if the key was released. - inline bool isKeyReleased(std::string key) { - return isKeyReleased(getKeyCode(std::move(key))); - } + bool isKeyReleased(std::string key); /// @brief Needs to be called every frame to update the key states. - inline void resetKeyStates() { - // set previous states - for (auto &key: KEY_STATES) { - KEY_STATES_PREVIOUS[key.first] = key.second; - } - - // reset all keys - for (int i = 0; i < 256; i++) { - KEY_STATES[i] = GetAsyncKeyState(i) & 0x8000; - } - } + void resetKeyStates(); /// @brief Simulates a key press. /// @param keycode The key code. - inline void pressKey(uint32_t keycode) { - keybd_event(keycode, 0, 0, 0); - keybd_event(keycode, 0, KEYEVENTF_KEYUP, 0); - } + void pressKey(uint32_t keycode); /// @brief Simulates a key press. /// @param key The key name. - inline void pressKey(std::string key) { - pressKey(getKeyCode(std::move(key))); - } + void pressKey(std::string key); /// @brief Open a file dialog to select a file. - inline std::filesystem::path filePickerDialog(const char *filter, const char *title) { - OPENFILENAME ofn; - char szFile[260] = {0}; - ZeroMemory(&ofn, sizeof(ofn)); - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = nullptr; - ofn.lpstrFile = szFile; - ofn.nMaxFile = sizeof(szFile); - ofn.lpstrFilter = filter; - ofn.nFilterIndex = 1; - ofn.lpstrFileTitle = nullptr; - ofn.nMaxFileTitle = 0; - ofn.lpstrInitialDir = nullptr; - ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; - ofn.lpstrTitle = title; - GetOpenFileName(&ofn); - return ofn.lpstrFile; - } + std::filesystem::path filePickerDialog(const char *filter, const char *title); /// @brief Open a file dialog to save a file. - inline std::filesystem::path fileSaveDialog(const char *filter, const char *title) { - OPENFILENAME ofn; - char szFile[260] = {0}; - ZeroMemory(&ofn, sizeof(ofn)); - ofn.lStructSize = sizeof(ofn); - ofn.hwndOwner = nullptr; - ofn.lpstrFile = szFile; - ofn.nMaxFile = sizeof(szFile); - ofn.lpstrFilter = filter; - ofn.nFilterIndex = 1; - ofn.lpstrFileTitle = nullptr; - ofn.nMaxFileTitle = 0; - ofn.lpstrInitialDir = nullptr; - ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; - ofn.lpstrTitle = title; - GetSaveFileName(&ofn); - return ofn.lpstrFile; - } + std::filesystem::path fileSaveDialog(const char *filter, const char *title); } \ No newline at end of file diff --git a/src/shared/utils.hpp b/src/shared/utils.hpp index 398e6ef..d7e3e7a 100644 --- a/src/shared/utils.hpp +++ b/src/shared/utils.hpp @@ -2,6 +2,7 @@ #include #include +#include #include "platform/platform.hpp" #ifndef M_PI @@ -9,15 +10,11 @@ #endif #ifdef __clang__ - #include - #else #include - #endif - #include #if 0 @@ -112,7 +109,7 @@ namespace openhack::utils { /// @param pos The screen position. /// @return The frame position. inline ImVec2 screenToFrame(const ImVec2& pos) { - auto *director = gd::cocos2d::CCDirector::sharedDirector(); + auto *director = cocos2d::CCDirector::sharedDirector(); const auto frameSize = director->getOpenGLView()->getFrameSize(); const auto winSize = director->getWinSize(); @@ -125,103 +122,103 @@ namespace openhack::utils { /// @brief Compare the version of the game with the given version. /// @param version The version to compare with, in the format "[>=|<=|>|<|=]x.yyy,x.yyy-x.yyy,..." /// @return True if the version is compatible with the given version. - inline bool compareVersion(const std::string &version) { - // Split the versions - std::vector parts; - std::string versionCopy = version; - std::string delimiter = ","; - size_t pos = 0; - std::string token; - while ((pos = versionCopy.find(delimiter)) != std::string::npos) { - token = versionCopy.substr(0, pos); - parts.push_back(token); - versionCopy.erase(0, pos + delimiter.length()); - } - parts.push_back(versionCopy); - - // Get current version - auto currentVersion = utils::getGameVersion(); - - // Check if any of the versions are compatible - bool match = false; - for (auto &part: parts) { - // Check if it's a range - if (part.find('-') != std::string::npos) { - std::vector range; - std::string rangeCopy = part; - std::string rangeDelimiter = "-"; - size_t rangePos = 0; - std::string rangeToken; - while ((rangePos = rangeCopy.find(rangeDelimiter)) != std::string::npos) { - rangeToken = rangeCopy.substr(0, rangePos); - range.push_back(rangeToken); - rangeCopy.erase(0, rangePos + rangeDelimiter.length()); - } - range.push_back(rangeCopy); - - if (range.size() != 2) - continue; - - if (strcmp(currentVersion.c_str(), range.at(0).c_str()) >= 0 && - strcmp(currentVersion.c_str(), range.at(0).c_str()) <= 0) { - match = true; - break; - } - } else { - // Get operator - auto op = part.at(0); - std::string ver = part.substr(1); - std::string operation; - switch (op) { - case '=': - operation = "=="; - break; - case '!': - operation = "!="; - break; - case '>': - // Check if it's >= - if (part.at(1) == '=') { - operation = ">="; - ver = ver.substr(1); - } else { - operation = ">"; - } - break; - case '<': - // Check if it's <= - if (part.at(1) == '=') { - operation = "<="; - ver = ver.substr(1); - } else { - operation = "<"; - } - break; - default: - operation = "=="; - break; - } - - int32_t result = strcmp(currentVersion.c_str(), ver.c_str()); - if (operation == "==" && result == 0) - match = true; - else if (operation == "!=" && result != 0) - match = true; - else if (operation == "<" && result < 0) - match = true; - else if (operation == "<=" && result <= 0) - match = true; - else if (operation == ">" && result > 0) - match = true; - else if (operation == ">=" && result >= 0) - match = true; - - if (match) - break; - } - } - - return match; + inline bool compareVersion(std::string version) { + return false; +// // Split the versions +// std::vector parts; +// std::string delimiter = ","; +// size_t pos = 0; +// std::string token; +// while ((pos = version.find(delimiter)) != std::string::npos) { +// token = version.substr(0, pos); +// parts.push_back(token); +// version.erase(0, pos + delimiter.length()); +// } +// parts.push_back(version); +// +// // Get current version +// auto currentVersion = utils::getGameVersion(); +// +// // Check if any of the versions are compatible +// bool match = false; +// for (auto &part: parts) { +// // Check if it's a range +// if (part.find('-') != std::string::npos) { +// std::vector range; +// std::string rangeCopy = part; +// std::string rangeDelimiter = "-"; +// size_t rangePos = 0; +// std::string rangeToken; +// while ((rangePos = rangeCopy.find(rangeDelimiter)) != std::string::npos) { +// rangeToken = rangeCopy.substr(0, rangePos); +// range.push_back(rangeToken); +// rangeCopy.erase(0, rangePos + rangeDelimiter.length()); +// } +// range.push_back(rangeCopy); +// +// if (range.size() != 2) +// continue; +// +// if (strcmp(currentVersion.c_str(), range.at(0).c_str()) >= 0 && +// strcmp(currentVersion.c_str(), range.at(0).c_str()) <= 0) { +// match = true; +// break; +// } +// } else { +// // Get operator +// auto op = part.at(0); +// std::string ver = part.substr(1); +// std::string operation; +// switch (op) { +// case '=': +// operation = "=="; +// break; +// case '!': +// operation = "!="; +// break; +// case '>': +// // Check if it's >= +// if (part.at(1) == '=') { +// operation = ">="; +// ver = ver.substr(1); +// } else { +// operation = ">"; +// } +// break; +// case '<': +// // Check if it's <= +// if (part.at(1) == '=') { +// operation = "<="; +// ver = ver.substr(1); +// } else { +// operation = "<"; +// } +// break; +// default: +// operation = "=="; +// break; +// } +// +// int32_t result = strcmp(currentVersion.c_str(), ver.c_str()); +// if (operation == "==" && result == 0) +// match = true; +// else if (operation == "!=" && result != 0) +// match = true; +// else if (operation == "<" && result < 0) +// match = true; +// else if (operation == "<=" && result <= 0) +// match = true; +// else if (operation == ">" && result > 0) +// match = true; +// else if (operation == ">=" && result >= 0) +// match = true; +// +// if (match) +// break; +// } +// } +// +// return match; } /// @brief Convert a string of hex characters to a vector of bytes. diff --git a/src/standalone/main.cpp b/src/standalone/main.cpp index 5c7eda1..d4ced5f 100644 --- a/src/standalone/main.cpp +++ b/src/standalone/main.cpp @@ -1,6 +1,6 @@ #include "pch.hpp" -#include "hooks/hooks.hpp" +// #include "hooks/hooks.hpp" #include "debug/crashhandler.hpp" #include "imgui/imgui_hook.hpp" #include "utils.hpp" @@ -19,8 +19,8 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv xinput::initialize(); // Debugging - bool altPressed = openhack::utils::isKeyDown("Alt"); - logger::initialize(altPressed, true, "openhack.log"); + // bool altPressed = openhack::utils::isKeyDown("Alt"); + logger::initialize(true, true, "openhack.log"); crashhandler::init(); // TODO: Add support for other versions @@ -30,7 +30,7 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv } // Initialize OpenHack - openhack::initialize(); + // openhack::initialize(); // Setup ImGui ImGuiHook::setInitCallback([]() { @@ -58,7 +58,7 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv ImGuiHook::setDrawCallback(openhack::menu::draw); // Install hooks - openhack::hooks::installHooks(); + // openhack::hooks::installHooks(); // Load DLL files from the "dll" directory auto dllDir = openhack::utils::getModAssetsDirectory() / "dll"; @@ -79,8 +79,8 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv break; } case DLL_PROCESS_DETACH: - ImGuiHook::destroy(); - openhack::deinitialize(); + // ImGuiHook::destroy(); + // openhack::deinitialize(); break; default: From d584ca6a801c0ee9e081841b307a553d45a85f0f Mon Sep 17 00:00:00 2001 From: Oleksandr Nemesh Date: Mon, 26 Aug 2024 01:26:27 +0300 Subject: [PATCH 18/20] tiny clean-ups --- CMakeLists.txt | 4 +- mod.json | 8 +- src/geode/main.cpp | 5 - src/geode/pch.hpp | 10 +- src/shared/config.cpp | 4 +- src/shared/config.hpp | 25 ++-- src/shared/gui/animation/easing.cpp | 38 +++-- src/shared/gui/animation/easing.hpp | 7 +- src/shared/gui/color.cpp | 144 +++++++++++++++++++ src/shared/gui/color.hpp | 110 +++++++-------- src/shared/gui/gui.cpp | 2 +- src/shared/gui/gui.hpp | 2 +- src/shared/gui/window.hpp | 3 + src/shared/hacks/hacks.hpp | 4 +- src/shared/menu/keybinds.cpp | 14 +- src/shared/menu/keybinds.hpp | 10 +- src/shared/menu/menu.cpp | 11 +- src/shared/menu/menu.hpp | 2 +- src/shared/openhack.cpp | 4 - src/shared/openhack.hpp | 3 - src/shared/platform/win32/sigscan.hpp | 35 +++-- src/shared/platform/win32/win32.cpp | 24 ++-- src/shared/platform/win32/win32.hpp | 10 +- src/shared/utils.hpp | 191 +++++++++++++------------- 24 files changed, 393 insertions(+), 277 deletions(-) create mode 100644 src/shared/gui/color.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 959002a..7e1249c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,7 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") endif() # Create build options -option(BUILD_STANDALONE "Build the standalone version" ON) +option(BUILD_STANDALONE "Build the standalone version" OFF) option(BUILD_GEODE "Build the Geode version" ON) # Get the latest abbreviated commit hash of the working branch @@ -142,7 +142,7 @@ endif() if (BUILD_STANDALONE) message(ERROR "Standalone build is deprecated, please use Geode instead") return() -end() +endif() if (NOT BUILD_STANDALONE) message(STATUS "Standalone build disabled") diff --git a/mod.json b/mod.json index 3fc07cf..e3e9bad 100644 --- a/mod.json +++ b/mod.json @@ -1,5 +1,5 @@ { - "geode": "3.2.0", + "geode": "3.4.0", "gd": { "win": "2.206" }, @@ -8,11 +8,7 @@ "name": "OpenHack", "developer": "Prevter", "description": "A collection of hacks for Geometry Dash", - "tags": [ - "Universal", - "Gameplay", - "Cheats" - ], + "tags": ["universal", "gameplay", "cheats", "bugfix"], "repository": "https://github.com/Prevter/GDOpenHack", "issues": { "info": "Join the Discord server for support", diff --git a/src/geode/main.cpp b/src/geode/main.cpp index 2bafc2e..e24df30 100644 --- a/src/geode/main.cpp +++ b/src/geode/main.cpp @@ -11,9 +11,4 @@ geode::listenForSettingChanges("legacy-render", [](bool value) { ImGuiCocos::get().setForceLegacy(value); }); -} - -$on_mod(Unloaded) { - ImGuiCocos::get().destroy(); - openhack::deinitialize(); } \ No newline at end of file diff --git a/src/geode/pch.hpp b/src/geode/pch.hpp index e0e2f55..317a55f 100644 --- a/src/geode/pch.hpp +++ b/src/geode/pch.hpp @@ -5,8 +5,8 @@ #include -#define L_TRACE(...) geode::prelude::log::debug(__VA_ARGS__) -#define L_INFO(...) geode::prelude::log::info(__VA_ARGS__) -#define L_WARN(...) geode::prelude::log::warn(__VA_ARGS__) -#define L_ERROR(...) geode::prelude::log::error(__VA_ARGS__) -#define L_CRITICAL(...) geode::prelude::log::error(__VA_ARGS__) \ No newline at end of file +#define L_TRACE(...) geode::log::debug(__VA_ARGS__) +#define L_INFO(...) geode::log::info(__VA_ARGS__) +#define L_WARN(...) geode::log::warn(__VA_ARGS__) +#define L_ERROR(...) geode::log::error(__VA_ARGS__) +#define L_CRITICAL(...) geode::log::error(__VA_ARGS__) \ No newline at end of file diff --git a/src/shared/config.cpp b/src/shared/config.cpp index 8330689..a5db9b8 100644 --- a/src/shared/config.cpp +++ b/src/shared/config.cpp @@ -3,7 +3,7 @@ #include -// #include "hacks/labels/labels.hpp" +#include "hacks/labels/labels.hpp" namespace openhack::config { nlohmann::json& getStorage() { @@ -62,7 +62,7 @@ namespace openhack::config { } void save() { - // hacks::Labels::save(); + hacks::Labels::save(); auto path = utils::getModSaveDirectory() / "config.json"; std::ofstream file(path); diff --git a/src/shared/config.hpp b/src/shared/config.hpp index 9c490e0..98a83f3 100644 --- a/src/shared/config.hpp +++ b/src/shared/config.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -14,7 +15,7 @@ namespace openhack::config { /// @brief Check if a key exists in the configuration. /// @param key Key to check. /// @return True if the key exists in the configuration. - inline bool has(const std::string &key) { + inline bool has(std::string_view key) { return getStorage().contains(key); } @@ -24,7 +25,7 @@ namespace openhack::config { /// @param defaultValue Default value to return if the key does not exist. /// @return Value from the configuration or the default value if the key does not exist. template - inline T get(const std::string &key, const T &defaultValue) { + inline T get(std::string_view key, const T &defaultValue) { if (!has(key)) return defaultValue; @@ -37,9 +38,9 @@ namespace openhack::config { /// @param key Key to get the value from. /// @return Value from the configuration. template - inline T get(const std::string &key) { + inline T get(std::string_view key) { if (!has(key)) - throw std::runtime_error("Key " + key + " does not exist"); + throw std::runtime_error(fmt::format("Key '{}' does not exist", key)); return getStorage().at(key).get(); } @@ -49,7 +50,7 @@ namespace openhack::config { /// @param key Key to set the value to. /// @param value Value to set. template - inline void set(const std::string &key, const T &value) { + inline void set(std::string_view key, const T &value) { getStorage()[key] = value; } @@ -58,7 +59,7 @@ namespace openhack::config { /// @param key Key to check. /// @return True if the value is of the specified type. template - inline bool is(const std::string &key) { + inline bool is(std::string_view key) { if (!has(key)) return false; @@ -75,7 +76,7 @@ namespace openhack::config { /// @param key Key to set the value to. /// @param value Value to set. template - inline void setIfEmpty(const std::string &key, const T &value) { + inline void setIfEmpty(std::string_view key, const T &value) { if (!has(key)) set(key, value); } @@ -83,7 +84,7 @@ namespace openhack::config { /// @brief Check if a key exists in the global variables. /// @param key Key to check. /// @return True if the key exists in the global variables. - inline bool hasGlobal(const std::string &key) { + inline bool hasGlobal(std::string_view key) { return getGlobals().contains(key); } @@ -93,7 +94,7 @@ namespace openhack::config { /// @param defaultValue Default value to return if the key does not exist. /// @return Value from the global variables or the default value if the key does not exist. template - inline T getGlobal(const std::string &key, const T &defaultValue) { + inline T getGlobal(std::string_view key, const T &defaultValue) { if (!hasGlobal(key)) return defaultValue; @@ -106,9 +107,9 @@ namespace openhack::config { /// @param key Key to get the value from. /// @return Value from the global variables. template - inline T getGlobal(const std::string &key) { + inline T getGlobal(std::string_view key) { if (!hasGlobal(key)) - throw std::runtime_error("Key " + key + " does not exist"); + throw std::runtime_error(fmt::format("Key '{}' does not exist", key)); return getGlobals().at(key).get(); } @@ -118,7 +119,7 @@ namespace openhack::config { /// @param key Key to set the value to. /// @param value Value to set. template - inline void setGlobal(const std::string &key, const T &value) { + inline void setGlobal(std::string_view key, const T &value) { getGlobals()[key] = value; } diff --git a/src/shared/gui/animation/easing.cpp b/src/shared/gui/animation/easing.cpp index 6054d80..6b35f5a 100644 --- a/src/shared/gui/animation/easing.cpp +++ b/src/shared/gui/animation/easing.cpp @@ -1,14 +1,7 @@ #include "easing.hpp" -#if defined(__clang__) || defined(__GNUC__) #include -#else -#include -#endif - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif +#include namespace openhack::gui::animation { EasingFunction getEasingFunction(Easing easing, EasingMode mode) { @@ -30,15 +23,15 @@ namespace openhack::gui::animation { /* == Sine == */ double easeInSine(double t) { - return 1.0 - cos(t * M_PI / 2.0); + return 1.0 - cos(t * std::numbers::pi / 2.0); } double easeOutSine(double t) { - return sin(t * M_PI / 2.0); + return sin(t * std::numbers::pi / 2.0); } double easeInOutSine(double t) { - return -(cos(M_PI * t) - 1.0) / 2.0; + return -(cos(std::numbers::pi * t) - 1.0) / 2.0; } /* == Quadratic == */ @@ -157,7 +150,7 @@ namespace openhack::gui::animation { if (t == 0.0 || t == 1.0) return t; - const double c4 = (2 * M_PI) / 3; + const double c4 = (2 * std::numbers::pi) / 3; return -pow(2.0, 10.0 * t - 10.0) * sin((t * 10.0 - 10.75) * c4); } @@ -165,7 +158,7 @@ namespace openhack::gui::animation { if (t == 0.0 || t == 1.0) return t; - const double c4 = (2 * M_PI) / 3; + const double c4 = (2 * std::numbers::pi) / 3; return pow(2.0, -10.0 * t) * sin((t * 10.0 - 0.75) * c4) + 1.0; } @@ -174,9 +167,9 @@ namespace openhack::gui::animation { return t; if (t < 0.5) - return -(pow(2.0, 20.0 * t - 10.0) * sin((20.0 * t - 11.125) * (2 * M_PI) / 4.5)) / 2.0; + return -(pow(2.0, 20.0 * t - 10.0) * sin((20.0 * t - 11.125) * (2 * std::numbers::pi) / 4.5)) / 2.0; - return (pow(2.0, -20.0 * t + 10.0) * sin((20.0 * t - 11.125) * (2 * M_PI) / 4.5)) / 2.0 + 1.0; + return (pow(2.0, -20.0 * t + 10.0) * sin((20.0 * t - 11.125) * (2 * std::numbers::pi) / 4.5)) / 2.0 + 1.0; } /* == Bounce == */ @@ -191,11 +184,16 @@ namespace openhack::gui::animation { if (t < 1.0 / d1) return n1 * t * t; - if (t < 2.0 / d1) - return n1 * (t -= 1.5 / d1) * t + 0.75; - if (t < 2.5 / d1) - return n1 * (t -= 2.25 / d1) * t + 0.9375; - return n1 * (t -= 2.625 / d1) * t + 0.984375; + if (t < 2.0 / d1) { + auto t2 = t - 1.5 / d1; + return n1 * t2 * t2 + 0.75; + } + if (t < 2.5 / d1) { + auto t2 = t - 2.25 / d1; + return n1 * t2 * t2 + 0.9375; + } + auto t2 = t - 2.625 / d1; + return n1 * t2 * t2 + 0.984375; } double easeInOutBounce(double t) { diff --git a/src/shared/gui/animation/easing.hpp b/src/shared/gui/animation/easing.hpp index c2d6154..c666296 100644 --- a/src/shared/gui/animation/easing.hpp +++ b/src/shared/gui/animation/easing.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include namespace openhack::gui::animation { /// @brief Function pointer for an easing function. @@ -24,7 +25,7 @@ namespace openhack::gui::animation { }; /// @brief Easing names. - const char *const EASING_NAMES[] = { + const std::array EASING_NAMES = { "Linear", "Sine", "Quadratic", @@ -38,7 +39,7 @@ namespace openhack::gui::animation { "Bounce", }; - const size_t EASING_COUNT = sizeof(EASING_NAMES) / sizeof(EASING_NAMES[0]); + const size_t EASING_COUNT = EASING_NAMES.size(); /// @brief Easing modes. enum class EasingMode { @@ -48,7 +49,7 @@ namespace openhack::gui::animation { }; /// @brief Easing mode names. - const char *const EASING_MODE_NAMES[] = { + const std::array EASING_MODE_NAMES = { "EaseIn", "EaseOut", "EaseInOut", diff --git a/src/shared/gui/color.cpp b/src/shared/gui/color.cpp new file mode 100644 index 0000000..cb05a2d --- /dev/null +++ b/src/shared/gui/color.cpp @@ -0,0 +1,144 @@ +#include "color.hpp" + +namespace openhack::gui { + + const Color Color::WHITE = {1, 1, 1}; + const Color Color::BLACK = {0, 0, 0}; + const Color Color::RED = {1, 0, 0}; + const Color Color::GREEN = {0, 1, 0}; + const Color Color::BLUE = {0, 0, 1}; + const Color Color::YELLOW = {1, 1, 0}; + const Color Color::CYAN = {0, 1, 1}; + const Color Color::MAGENTA = {1, 0, 1}; + + Color::operator ImU32() const { + return ImGui::ColorConvertFloat4ToU32(ImVec4(r, g, b, a)); + } + + Color &Color::operator=(const Color &other) { + if (this == &other) return *this; + r = other.r; + g = other.g; + b = other.b; + a = other.a; + return *this; + } + + Color &Color::operator=(Color &&other) noexcept { + if (this == &other) return *this; + r = other.r; + g = other.g; + b = other.b; + a = other.a; + other.r = other.g = other.b = 0; + other.a = 1.0f; + return *this; + } + + Color::operator ImVec4() const { + return {r, g, b, a}; + } + + Color &Color::operator=(const ImVec4 &col2) { + r = col2.x; + g = col2.y; + b = col2.z; + a = col2.w; + return *this; + } + + Color::operator cocos2d::ccColor4F() const { + return {r, g, b, a}; + } + + Color Color::fromHSV(float h, float s, float v, float a) { + float c = v * s; + float x = c * (1 - std::abs(fmod(h / 60.0f, 2) - 1)); + float m = v - c; + + float r, g, b; + if (h < 60) { + r = c; + g = x; + b = 0; + } else if (h < 120) { + r = x; + g = c; + b = 0; + } else if (h < 180) { + r = 0; + g = c; + b = x; + } else if (h < 240) { + r = 0; + g = x; + b = c; + } else if (h < 300) { + r = x; + g = 0; + b = c; + } else { + r = c; + g = 0; + b = x; + } + + return {r + m, g + m, b + m, a}; + } + + Color Color::fromInt(int color, Color::IntType type) { + float v1, v2, v3, v4; + v1 = (float) ((color >> 24) & 0xFF) / 255.0f; + v2 = (float) ((color >> 16) & 0xFF) / 255.0f; + v3 = (float) ((color >> 8) & 0xFF) / 255.0f; + v4 = (float) (color & 0xFF) / 255.0f; + + switch (type) { + default: + return {v1, v2, v3, v4}; + case IntType::ARGB: + return {v2, v3, v4, v1}; + case IntType::ABGR: + return {v4, v3, v2, v1}; + case IntType::BGRA: + return {v3, v2, v1, v4}; + } + } + + int Color::toInt(Color::IntType type) const { + int rv, gv, bv, av; + rv = static_cast(this->r * 255); + gv = static_cast(this->g * 255); + bv = static_cast(this->b * 255); + av = static_cast(this->a * 255); + switch (type) { + default: + return (rv << 24) | (gv << 16) | (bv << 8) | av; + case IntType::ARGB: + return (av << 24) | (rv << 16) | (gv << 8) | bv; + case IntType::ABGR: + return (av << 24) | (bv << 16) | (gv << 8) | rv; + case IntType::BGRA: + return (bv << 24) | (gv << 16) | (rv << 8) | av; + } + } + + Color Color::fromString(const std::string &color, Color::IntType type) { + uint32_t c = std::strtoul(color.c_str(), nullptr, 16); + return fromInt(c, type); + } + + std::string Color::toString(Color::IntType type) const { + uint32_t c = toInt(type); + return fmt::format("{:08X}", c); + } + + cocos2d::ccColor3B Color::toCCColor3B() const { + return { + static_cast(r * 255), + static_cast(g * 255), + static_cast(b * 255) + }; + } + +} \ No newline at end of file diff --git a/src/shared/gui/color.hpp b/src/shared/gui/color.hpp index 388040a..fb825d7 100644 --- a/src/shared/gui/color.hpp +++ b/src/shared/gui/color.hpp @@ -13,25 +13,44 @@ namespace openhack::gui { struct Color { + static const Color WHITE; + static const Color BLACK; + static const Color RED; + static const Color GREEN; + static const Color BLUE; + static const Color YELLOW; + static const Color CYAN; + static const Color MAGENTA; + float r, g, b, a; Color() : r(0), g(0), b(0), a(1.0f) {} - Color(float r, float g, float b, float a = 1.0f) : r(r), g(g), b(b), a(a) {} + Color(const Color& other) = default; + explicit Color(const cocos2d::ccColor4F& other) : r(other.r), g(other.g), b(other.b), a(other.a) {} - /// @brief Converts the color to ImVec4 - operator ImVec4() const { - return {r, g, b, a}; + Color(Color&& other) noexcept : r(other.r), g(other.g), b(other.b), a(other.a) { + other.r = other.g = other.b = 0; + other.a = 1.0f; } + Color& operator=(const Color& other); + + Color& operator=(Color&& other) noexcept; + + /// @brief Converts the color to ImVec4 + operator ImVec4() const; + /// @brief Converts the color to ImU32 - operator ImU32() const { - return ImGui::ColorConvertFloat4ToU32(ImVec4(r, g, b, a)); - } + operator ImU32() const; + + Color& operator=(const ImVec4& col2); + + operator cocos2d::ccColor4F() const; /// @brief Returns a pointer to the color data /// @return Pointer to the color data - float *data() { + inline float* data() { return &r; } @@ -41,80 +60,45 @@ namespace openhack::gui { /// @param v Value /// @param a Alpha /// @return New color - static Color fromHSV(float h, float s, float v, float a = 1.0f) { - float c = v * s; - float x = c * (1 - std::abs(fmod(h / 60.0f, 2) - 1)); - float m = v - c; - - float r, g, b; - if (h < 60) { - r = c; - g = x; - b = 0; - } else if (h < 120) { - r = x; - g = c; - b = 0; - } else if (h < 180) { - r = 0; - g = c; - b = x; - } else if (h < 240) { - r = 0; - g = x; - b = c; - } else if (h < 300) { - r = x; - g = 0; - b = c; - } else { - r = c; - g = 0; - b = x; - } - - return {r + m, g + m, b + m, a}; - } + static Color fromHSV(float h, float s, float v, float a = 1.0f); /// @brief Creates a new color from HSV values /// @param hsv HSV values /// @return New color - static Color fromHSV(const ImVec4 &hsv) { + inline static Color fromHSV(const ImVec4& hsv) { return fromHSV(hsv.x, hsv.y, hsv.z, hsv.w); } + enum class IntType { + RGBA, ARGB, + ABGR, BGRA + }; + /// @brief Gets the color from an integer /// @param color Integer color + /// @param type Integer type to convert from /// @return New color - static Color fromInt(int color) { - return { - (float) ((color >> 16) & 0xFF) / 255.0f, - (float) ((color >> 8) & 0xFF) / 255.0f, - (float) (color & 0xFF) / 255.0f, - (float) ((color >> 24) & 0xFF) / 255.0f}; - } + static Color fromInt(int color, IntType type = IntType::RGBA); /// @brief Converts the color to an integer + /// @param type Integer type to convert to /// @return Integer color - [[nodiscard]] int toInt() const { - return ((int) (r * 255) << 16) | ((int) (g * 255) << 8) | (int) (b * 255) | ((int) (a * 255) << 24); - } + [[nodiscard]] int toInt(IntType type = IntType::RGBA) const; /// @brief Creates a new color from a string - /// @param color String color in format "RRGGBBAA" + /// @param color String color in proper format + /// @param type Integer type to convert from /// @return New color - static Color fromString(const char *color) { - uint32_t c; - sscanf_s(color, "%X", &c); - return fromInt(c); - } + static Color fromString(const std::string& color, IntType type = IntType::RGBA); /// @brief Converts the color to a string + /// @param type Integer type to convert to /// @return String color in format "RRGGBBAA" - [[nodiscard]] std::string toString() const { - uint32_t c = toInt(); - return fmt::format("{:08X}", c); - } + [[nodiscard]] std::string toString(IntType type = IntType::RGBA) const; + + /// @brief Converts the color to a CCColor3B + /// @return CCColor3B color + [[nodiscard]] cocos2d::ccColor3B toCCColor3B() const; }; } diff --git a/src/shared/gui/gui.cpp b/src/shared/gui/gui.cpp index e70a6f8..3feb6dd 100644 --- a/src/shared/gui/gui.cpp +++ b/src/shared/gui/gui.cpp @@ -229,7 +229,7 @@ namespace openhack::gui { return result; } - bool toggleSetting(const char *label, const char *settingKey, std::function popupDraw, ImVec2 size, float minWidth) { + bool toggleSetting(const char *label, const char *settingKey, const std::function& popupDraw, ImVec2 size, float minWidth) { bool value = config::get(settingKey, false); bool result = gui::toggleSetting(label, &value, popupDraw, size, minWidth); if (result) diff --git a/src/shared/gui/gui.hpp b/src/shared/gui/gui.hpp index 0fa2461..a7c46c4 100644 --- a/src/shared/gui/gui.hpp +++ b/src/shared/gui/gui.hpp @@ -128,7 +128,7 @@ namespace openhack::gui { /// @param minWidth The minimum width of the popup. /// @return True if the checkbox was clicked. /// @note Uses the configuration to store the value. - bool toggleSetting(const char *label, const char *settingKey, std::function popupDraw, + bool toggleSetting(const char *label, const char *settingKey, const std::function& popupDraw, ImVec2 size = ImVec2(0, 0), float minWidth = 0.0f); /// @brief Allows to set a callback, which will be called for some GUI elements, which have more than one ImGui call. diff --git a/src/shared/gui/window.hpp b/src/shared/gui/window.hpp index 475f92e..68926c2 100644 --- a/src/shared/gui/window.hpp +++ b/src/shared/gui/window.hpp @@ -20,6 +20,9 @@ namespace openhack::gui { /// @param onDraw Callback which will be called when the window is drawn Window(const std::string &title, std::function onDraw); + Window(std::string_view title, std::function onDraw) + : Window(std::string(title), onDraw) {} + /// @brief Draw the window void draw(); diff --git a/src/shared/hacks/hacks.hpp b/src/shared/hacks/hacks.hpp index 29bcda1..d1c5519 100644 --- a/src/shared/hacks/hacks.hpp +++ b/src/shared/hacks/hacks.hpp @@ -138,7 +138,7 @@ namespace openhack::hacks { /// @param id The ID of the component /// @return The component casted to type T or nullptr if not found template - inline T *getComponent(const std::string &id) { + inline T *getComponent(std::string_view id) { for (auto &component : getComponents()) { if (component->getId() == id) return dynamic_cast(component); @@ -149,7 +149,7 @@ namespace openhack::hacks { /// @brief Get a hack by its ID /// @param id The ID of the hack /// @return The hack or nullptr if not found - inline ToggleComponent *getHack(const std::string &id) { + inline ToggleComponent *getHack(std::string_view id) { for (auto &hack : getHacks()) { if (hack->getId() == id) return hack; diff --git a/src/shared/menu/keybinds.cpp b/src/shared/menu/keybinds.cpp index 9c78623..9d18daf 100644 --- a/src/shared/menu/keybinds.cpp +++ b/src/shared/menu/keybinds.cpp @@ -12,7 +12,7 @@ namespace openhack::menu::keybinds { getKeybinds().push_back(keybind); } - void removeKeybind(const std::string &id) { + void removeKeybind(std::string_view id) { for (auto it = getKeybinds().begin(); it != getKeybinds().end(); ++it) { if (it->id == id) { getKeybinds().erase(it); @@ -21,7 +21,7 @@ namespace openhack::menu::keybinds { } } - Keybind getKeybind(const std::string &id) { + Keybind getKeybind(std::string_view id) { for (auto &keybind: getKeybinds()) { if (keybind.id == id) { return keybind; @@ -30,13 +30,13 @@ namespace openhack::menu::keybinds { return {"", "", 0}; } - bool hasKeybind(const std::string &id) { + bool hasKeybind(std::string_view id) { return std::any_of(getKeybinds().begin(), getKeybinds().end(), [&](const Keybind &keybind) { return keybind.id == id; }); } - void setKeybindCallback(const std::string &id, const std::function &callback) { + void setKeybindCallback(std::string_view id, const std::function &callback) { for (auto &keybind: getKeybinds()) { if (keybind.id == id) { keybind.callback = callback; @@ -94,8 +94,8 @@ namespace openhack::menu::keybinds { config::save(); } - void addMenuKeybind(const std::string &id, const std::string &label, const std::function &callback) { - auto popupName = "##popup_" + id; + void addMenuKeybind(std::string_view id, std::string_view label, const std::function &callback) { + auto popupName = fmt::format("##popup_{}", id); if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { ImGui::OpenPopup(popupName.c_str()); } @@ -108,7 +108,7 @@ namespace openhack::menu::keybinds { } } else { if (ImGui::MenuItem("Add keybind")) { - addKeybind({label, id, 0, callback}); + addKeybind({std::string(label), std::string(id), 0, callback}); save(); } } diff --git a/src/shared/menu/keybinds.hpp b/src/shared/menu/keybinds.hpp index a80ea41..390527c 100644 --- a/src/shared/menu/keybinds.hpp +++ b/src/shared/menu/keybinds.hpp @@ -27,17 +27,17 @@ namespace openhack::menu::keybinds { /// @brief Removes a keybind by its ID. /// @param id The ID of the keybind to remove. - void removeKeybind(const std::string &id); + void removeKeybind(std::string_view id); /// @brief Gets a keybind by its ID. /// @param id The ID of the keybind to get. /// @return The keybind with the specified ID. - Keybind getKeybind(const std::string &id); + Keybind getKeybind(std::string_view id); /// @brief Checks if a keybind with the specified ID exists. /// @param id The ID of the keybind to check. /// @return True if a keybind with the specified ID exists. - bool hasKeybind(const std::string &id); + bool hasKeybind(std::string_view id); /// @brief Gets all keybinds. /// @return All keybinds. @@ -46,7 +46,7 @@ namespace openhack::menu::keybinds { /// @brief Sets the callback for a keybind if it exists. /// @param id The ID of the keybind. /// @param callback The callback to set. - void setKeybindCallback(const std::string &id, const std::function &callback); + void setKeybindCallback(std::string_view id, const std::function &callback); /// @brief Loads the keybinds from the configuration file and creates the window. /// @warning It doesn't create keybinding callbacks, they need to be added by each hack separately. @@ -65,5 +65,5 @@ namespace openhack::menu::keybinds { /// @param id The ID of the keybinding. /// @param label The label of the keybinding. /// @param callback The callback to call when the keybinding is pressed. - void addMenuKeybind(const std::string& id, const std::string& label, const std::function& callback); + void addMenuKeybind(std::string_view id, std::string_view label, const std::function& callback); } \ No newline at end of file diff --git a/src/shared/menu/menu.cpp b/src/shared/menu/menu.cpp index 88bc1a1..7a1239b 100644 --- a/src/shared/menu/menu.cpp +++ b/src/shared/menu/menu.cpp @@ -214,9 +214,12 @@ namespace openhack::menu { gui::inputFloat("Animation Time", "menu.animationTime", 0.0f, 10.0f, "%.3f"); gui::width(); gui::width(110); - gui::combo("Easing Type", "menu.easingType", gui::animation::EASING_NAMES, - gui::animation::EASING_COUNT); - gui::combo("Easing Mode", "menu.easingMode", gui::animation::EASING_MODE_NAMES, 3); + gui::combo("Easing Type", "menu.easingType", + gui::animation::EASING_NAMES.data(), + gui::animation::EASING_NAMES.size()); + gui::combo("Easing Mode", "menu.easingMode", + gui::animation::EASING_MODE_NAMES.data(), + gui::animation::EASING_MODE_NAMES.size()); gui::width(); gui::checkbox("Animate Opacity", "menu.animateOpacity"); }); @@ -480,7 +483,7 @@ namespace openhack::menu { } } - void addWindow(const std::string &title, const std::function &onDraw) { + void addWindow(std::string_view title, const std::function &onDraw) { windows.emplace_back(title, onDraw); } diff --git a/src/shared/menu/menu.hpp b/src/shared/menu/menu.hpp index 63a16b3..e896421 100644 --- a/src/shared/menu/menu.hpp +++ b/src/shared/menu/menu.hpp @@ -22,7 +22,7 @@ namespace openhack::menu { /// @brief Adds specified window to the draw stack /// @param window Window to add - void addWindow(const std::string &title, const std::function &onDraw); + void addWindow(std::string_view title, const std::function &onDraw); /// @brief Generates a new position for each window, so they don't overlap and are stacked nicely. /// @return Map of window pointers and their new positions diff --git a/src/shared/openhack.cpp b/src/shared/openhack.cpp index 4a7e975..06a8670 100644 --- a/src/shared/openhack.cpp +++ b/src/shared/openhack.cpp @@ -21,8 +21,4 @@ namespace openhack { hacks::initialize(); L_INFO("Initialized hacks"); } - - void deinitialize() { - config::save(); - } } \ No newline at end of file diff --git a/src/shared/openhack.hpp b/src/shared/openhack.hpp index d9158be..e3afc57 100644 --- a/src/shared/openhack.hpp +++ b/src/shared/openhack.hpp @@ -41,8 +41,5 @@ namespace openhack { /// This function should be called from the entry point of the mod. void initialize(); - /// @brief Unloads everything. - void deinitialize(); - extern bool debugMode; } \ No newline at end of file diff --git a/src/shared/platform/win32/sigscan.hpp b/src/shared/platform/win32/sigscan.hpp index 869d0ed..a615643 100644 --- a/src/shared/platform/win32/sigscan.hpp +++ b/src/shared/platform/win32/sigscan.hpp @@ -114,7 +114,7 @@ namespace gd::sigscan { patched(std::move(patched)) {} }; - inline PatternToken parseToken(std::string pattern, uint32_t ¤tIndex) { + inline PatternToken parseToken(std::string_view pattern, uint32_t ¤tIndex) { PatternToken token; token.any_byte = false; token.byte = 0; @@ -132,14 +132,14 @@ namespace gd::sigscan { token.multi_pattern = true; currentIndex++; } else { - token.byte = std::stoi(pattern.substr(currentIndex, 2), nullptr, 16); + token.byte = std::stoi(std::string(pattern.substr(currentIndex, 2)), nullptr, 16); currentIndex += 2; } return token; } - inline bool eatToken(const char symbol, const std::string &pattern, uint32_t ¤tIndex) { + inline bool eatToken(const char symbol, std::string_view pattern, uint32_t ¤tIndex) { if (pattern[currentIndex] == symbol) { currentIndex++; return true; @@ -147,7 +147,7 @@ namespace gd::sigscan { return false; } - inline int8_t readSignedByte(const std::string &pattern, uint32_t ¤tIndex) { + inline int8_t readSignedByte(std::string_view pattern, uint32_t ¤tIndex) { bool is_negative = false; switch (pattern[currentIndex]) { case '+': @@ -161,7 +161,7 @@ namespace gd::sigscan { break; } - int8_t byte = std::stoi(pattern.substr(currentIndex, 2), nullptr, 16); + int8_t byte = std::stoi(std::string(pattern.substr(currentIndex, 2)), nullptr, 16); if (is_negative) byte = -byte; currentIndex += 2; @@ -172,7 +172,7 @@ namespace gd::sigscan { /// @brief Parses a pattern string to get a list of tokens /// @param pattern Pattern string /// @return List of pattern tokens - inline std::vector parsePattern(const std::string &pattern) { + inline std::vector parsePattern(std::string_view pattern) { uint32_t current_index = 0; std::vector tokens; @@ -206,7 +206,7 @@ namespace gd::sigscan { /// @brief Parses a mask string to get a list of tokens /// @param mask Mask string /// @return List of mask tokens - inline std::vector parseMask(const std::string &mask) { + inline std::vector parseMask(std::string_view mask) { uint32_t current_index = 0; std::vector bytes; @@ -250,7 +250,7 @@ namespace gd::sigscan { } else if (mask[current_index] == '*') // repeat next byte n times { eatToken('(', mask, ++current_index); - repeat_count = std::stoi(mask.substr(current_index, 2), nullptr, 16); + repeat_count = std::stoi(std::string(mask.substr(current_index, 2)), nullptr, 16); current_index += 2; eatToken(')', mask, current_index); continue; @@ -258,7 +258,7 @@ namespace gd::sigscan { { byte.is_pattern = true; // read how many bytes should be stored - uint8_t bytes_to_store = std::stoi(mask.substr(++current_index, 1), nullptr, 10); + uint8_t bytes_to_store = std::stoi(std::string(mask.substr(++current_index, 1)), nullptr, 10); eatToken('(', mask, ++current_index); // read the pattern @@ -271,7 +271,7 @@ namespace gd::sigscan { byte.value = bytes_to_store; byte.pattern = pattern; } else { - byte.value = std::stoi(mask.substr(current_index, 2), nullptr, 16); + byte.value = std::stoi(std::string(mask.substr(current_index, 2)), nullptr, 16); current_index += 2; } @@ -288,13 +288,13 @@ namespace gd::sigscan { /// @param pattern A list of pattern tokens /// @param library Library name /// @return All found addresses - inline std::vector findPattern(std::vector pattern, const std::string &library = "") { + inline std::vector findPattern(std::vector pattern, std::string_view library = "") { // get module handle HMODULE module; if (library.empty()) module = GetModuleHandle(nullptr); else - module = GetModuleHandle(library.c_str()); + module = GetModuleHandle(library.data()); if (module == nullptr) return {}; @@ -381,7 +381,7 @@ namespace gd::sigscan { /// @param pattern Pattern string /// @param library Library name /// @return All found addresses - inline std::vector findPatterns(const std::string &pattern, const std::string &library = "") { + inline std::vector findPatterns(std::string_view pattern, std::string_view library = "") { return findPattern(parsePattern(pattern), library); } @@ -389,7 +389,7 @@ namespace gd::sigscan { /// @param pattern Pattern string /// @param library Library name /// @return The first found address - inline uintptr_t findPattern(const std::string &pattern, const std::string &library = "") { + inline uintptr_t findPattern(std::string_view pattern, std::string_view library = "") { auto result = findPatterns(pattern, library); if (result.empty()) { return 0; @@ -402,8 +402,7 @@ namespace gd::sigscan { /// @param mask Mask string /// @param library Library name /// @return All opcodes found - inline std::vector - match(const std::string &pattern, const std::string &mask = "", const std::string &library = "") { + inline std::vector match(std::string_view pattern, std::string_view mask = "", std::string_view library = "") { std::vector results; auto patternTokens = parsePattern(pattern); @@ -420,9 +419,9 @@ namespace gd::sigscan { if (library.empty()) module_addr = (uintptr_t) GetModuleHandle(nullptr); else - module_addr = (uintptr_t) GetModuleHandle(library.c_str()); + module_addr = (uintptr_t) GetModuleHandle(library.data()); - Opcode opcode((uintptr_t) address - module_addr, library, {}, {}); + Opcode opcode((uintptr_t) address - module_addr, std::string(library), {}, {}); uintptr_t global_offset = 0; diff --git a/src/shared/platform/win32/win32.cpp b/src/shared/platform/win32/win32.cpp index 1ee7e3e..d457e72 100644 --- a/src/shared/platform/win32/win32.cpp +++ b/src/shared/platform/win32/win32.cpp @@ -277,12 +277,12 @@ namespace openhack::utils { return "Unknown"; } - uint32_t getKeyCode(std::string key) { + uint32_t getKeyCode(std::string_view key) { // find key in map + std::string key_lower = std::string(key); + std::transform(key_lower.begin(), key_lower.end(), key_lower.begin(), ::tolower); + for (auto &key_: getKeyNames()) { - // compare lowercase strings - std::string key_lower = key; - std::transform(key_lower.begin(), key_lower.end(), key_lower.begin(), ::tolower); std::string key_lower_ = key_.second; std::transform(key_lower_.begin(), key_lower_.end(), key_lower_.begin(), ::tolower); if (key_lower == key_lower_) { @@ -328,8 +328,8 @@ namespace openhack::utils { return GetAsyncKeyState(keycode) & 0x8000; } - bool isKeyDown(std::string key) { - return isKeyDown(getKeyCode(std::move(key))); + bool isKeyDown(std::string_view key) { + return isKeyDown(getKeyCode(key)); } bool isKeyPressed(uint32_t keycode) { @@ -346,8 +346,8 @@ namespace openhack::utils { return false; } - bool isKeyPressed(std::string key) { - return isKeyPressed(getKeyCode(std::move(key))); + bool isKeyPressed(std::string_view key) { + return isKeyPressed(getKeyCode(key)); } bool isKeyReleased(uint32_t keycode) { @@ -364,8 +364,8 @@ namespace openhack::utils { return false; } - bool isKeyReleased(std::string key) { - return isKeyReleased(getKeyCode(std::move(key))); + bool isKeyReleased(std::string_view key) { + return isKeyReleased(getKeyCode(key)); } void resetKeyStates() { @@ -385,8 +385,8 @@ namespace openhack::utils { keybd_event(keycode, 0, KEYEVENTF_KEYUP, 0); } - void pressKey(std::string key) { - pressKey(getKeyCode(std::move(key))); + void pressKey(std::string_view key) { + pressKey(getKeyCode(key)); } std::filesystem::path filePickerDialog(const char *filter, const char *title) { diff --git a/src/shared/platform/win32/win32.hpp b/src/shared/platform/win32/win32.hpp index f42b0e6..f53c573 100644 --- a/src/shared/platform/win32/win32.hpp +++ b/src/shared/platform/win32/win32.hpp @@ -69,7 +69,7 @@ namespace openhack::utils { /// @brief Convert a key name to a key code. /// @param key The key name. /// @return The key code. - uint32_t getKeyCode(std::string key); + uint32_t getKeyCode(std::string_view key); /// @brief Gets the window handle of the game. HWND getWindowHandle(); @@ -81,7 +81,7 @@ namespace openhack::utils { bool isKeyDown(uint32_t keycode); /// @brief Check whether a key is down. - bool isKeyDown(std::string key); + bool isKeyDown(std::string_view key); /// @brief Check whether a key was pressed during the current frame. /// @param keycode The key code. @@ -91,7 +91,7 @@ namespace openhack::utils { /// @brief Check whether a key was pressed during the current frame. /// @param key Key name. /// @return True if the key was pressed. - bool isKeyPressed(std::string key); + bool isKeyPressed(std::string_view key); /// @brief Check whether a key was released during the current frame. /// @param keycode The key code. @@ -101,7 +101,7 @@ namespace openhack::utils { /// @brief Check whether a key was released during the current frame. /// @param key Key name. /// @return True if the key was released. - bool isKeyReleased(std::string key); + bool isKeyReleased(std::string_view key); /// @brief Needs to be called every frame to update the key states. void resetKeyStates(); @@ -112,7 +112,7 @@ namespace openhack::utils { /// @brief Simulates a key press. /// @param key The key name. - void pressKey(std::string key); + void pressKey(std::string_view key); /// @brief Open a file dialog to select a file. std::filesystem::path filePickerDialog(const char *filter, const char *title); diff --git a/src/shared/utils.hpp b/src/shared/utils.hpp index d7e3e7a..fa42544 100644 --- a/src/shared/utils.hpp +++ b/src/shared/utils.hpp @@ -123,102 +123,101 @@ namespace openhack::utils { /// @param version The version to compare with, in the format "[>=|<=|>|<|=]x.yyy,x.yyy-x.yyy,..." /// @return True if the version is compatible with the given version. inline bool compareVersion(std::string version) { - return false; -// // Split the versions -// std::vector parts; -// std::string delimiter = ","; -// size_t pos = 0; -// std::string token; -// while ((pos = version.find(delimiter)) != std::string::npos) { -// token = version.substr(0, pos); -// parts.push_back(token); -// version.erase(0, pos + delimiter.length()); -// } -// parts.push_back(version); -// -// // Get current version -// auto currentVersion = utils::getGameVersion(); -// -// // Check if any of the versions are compatible -// bool match = false; -// for (auto &part: parts) { -// // Check if it's a range -// if (part.find('-') != std::string::npos) { -// std::vector range; -// std::string rangeCopy = part; -// std::string rangeDelimiter = "-"; -// size_t rangePos = 0; -// std::string rangeToken; -// while ((rangePos = rangeCopy.find(rangeDelimiter)) != std::string::npos) { -// rangeToken = rangeCopy.substr(0, rangePos); -// range.push_back(rangeToken); -// rangeCopy.erase(0, rangePos + rangeDelimiter.length()); -// } -// range.push_back(rangeCopy); -// -// if (range.size() != 2) -// continue; -// -// if (strcmp(currentVersion.c_str(), range.at(0).c_str()) >= 0 && -// strcmp(currentVersion.c_str(), range.at(0).c_str()) <= 0) { -// match = true; -// break; -// } -// } else { -// // Get operator -// auto op = part.at(0); -// std::string ver = part.substr(1); -// std::string operation; -// switch (op) { -// case '=': -// operation = "=="; -// break; -// case '!': -// operation = "!="; -// break; -// case '>': -// // Check if it's >= -// if (part.at(1) == '=') { -// operation = ">="; -// ver = ver.substr(1); -// } else { -// operation = ">"; -// } -// break; -// case '<': -// // Check if it's <= -// if (part.at(1) == '=') { -// operation = "<="; -// ver = ver.substr(1); -// } else { -// operation = "<"; -// } -// break; -// default: -// operation = "=="; -// break; -// } -// -// int32_t result = strcmp(currentVersion.c_str(), ver.c_str()); -// if (operation == "==" && result == 0) -// match = true; -// else if (operation == "!=" && result != 0) -// match = true; -// else if (operation == "<" && result < 0) -// match = true; -// else if (operation == "<=" && result <= 0) -// match = true; -// else if (operation == ">" && result > 0) -// match = true; -// else if (operation == ">=" && result >= 0) -// match = true; -// -// if (match) -// break; -// } -// } -// -// return match; + // Split the versions + std::vector parts; + std::string delimiter = ","; + size_t pos = 0; + std::string token; + while ((pos = version.find(delimiter)) != std::string::npos) { + token = version.substr(0, pos); + parts.push_back(token); + version.erase(0, pos + delimiter.length()); + } + parts.push_back(version); + + // Get current version + auto currentVersion = utils::getGameVersion(); + + // Check if any of the versions are compatible + bool match = false; + for (auto &part: parts) { + // Check if it's a range + if (part.find('-') != std::string::npos) { + std::vector range; + std::string rangeCopy = part; + std::string rangeDelimiter = "-"; + size_t rangePos = 0; + std::string rangeToken; + while ((rangePos = rangeCopy.find(rangeDelimiter)) != std::string::npos) { + rangeToken = rangeCopy.substr(0, rangePos); + range.push_back(rangeToken); + rangeCopy.erase(0, rangePos + rangeDelimiter.length()); + } + range.push_back(rangeCopy); + + if (range.size() != 2) + continue; + + if (strcmp(currentVersion.c_str(), range.at(0).c_str()) >= 0 && + strcmp(currentVersion.c_str(), range.at(0).c_str()) <= 0) { + match = true; + break; + } + } else { + // Get operator + auto op = part.at(0); + std::string ver = part.substr(1); + std::string operation; + switch (op) { + case '=': + operation = "=="; + break; + case '!': + operation = "!="; + break; + case '>': + // Check if it's >= + if (part.at(1) == '=') { + operation = ">="; + ver = ver.substr(1); + } else { + operation = ">"; + } + break; + case '<': + // Check if it's <= + if (part.at(1) == '=') { + operation = "<="; + ver = ver.substr(1); + } else { + operation = "<"; + } + break; + default: + operation = "=="; + break; + } + + int32_t result = strcmp(currentVersion.c_str(), ver.c_str()); + if (operation == "==" && result == 0) + match = true; + else if (operation == "!=" && result != 0) + match = true; + else if (operation == "<" && result < 0) + match = true; + else if (operation == "<=" && result <= 0) + match = true; + else if (operation == ">" && result > 0) + match = true; + else if (operation == ">=" && result >= 0) + match = true; + + if (match) + break; + } + } + + return match; } /// @brief Convert a string of hex characters to a vector of bytes. From 23cb604b948c227a51edf3c15951651263e290d1 Mon Sep 17 00:00:00 2001 From: Oleksandr Nemesh Date: Wed, 28 Aug 2024 12:35:45 +0300 Subject: [PATCH 19/20] random edits --- CHANGELOG.md | 11 +- resources/hacks/level.json | 13 +- src/geode/hooks/PlayLayer.cpp | 14 +- src/shared/hacks/hack-list.hpp | 2 + .../hacks/hide-triggers/hide-triggers.cpp | 9 +- src/shared/hacks/labels/labels.hpp | 3 +- .../hacks/noclip-limit/noclip-limit.cpp | 25 +- .../hacks/noclip-limit/noclip-limit.hpp | 2 +- src/shared/hacks/noclip/noclip.cpp | 60 +++++ src/shared/hacks/noclip/noclip.hpp | 23 ++ src/shared/hacks/shortcuts/shortcuts.hpp | 2 +- .../hacks/smart-startpos/smart-startpos.cpp | 236 +++++++----------- .../hacks/smart-startpos/smart-startpos.hpp | 5 +- src/shared/hacks/speedhack/speedhack.cpp | 26 +- .../startpos-switcher/startpos-switcher.cpp | 2 +- src/shared/platform/win32/win32.cpp | 4 + 16 files changed, 241 insertions(+), 196 deletions(-) create mode 100644 src/shared/hacks/noclip/noclip.cpp create mode 100644 src/shared/hacks/noclip/noclip.hpp diff --git a/CHANGELOG.md b/CHANGELOG.md index a8c1889..e2f7141 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,16 +1,23 @@ ## v2.4.0 **New**: -* Ported to 2.206 +* Ported to 2.206 (Geode only) * Improved "Best Run" calculation * Tweaked some UI elements * Added a "Lock First Column" option for the menu * Added a notice for "Click Between Frames" users +* Performance improvements +* Noclip now has separate settings for each player + +**Fixes**: +* Fixed "Auto Hide Triggers" hiding speed portals and checkpoints +* Fixed "Speedhack Audio" compatibility with some mods +* Fixed "Smart StartPos" having issues with some levels **Labels**: * Added "Total Attempts" label ({total_attempts}) * Added "Mod version" label ({openhack_ver}) * Added 12-hour clock label ({clock12}) -* [Geode] Added "Mod count" label ({mod_count}) +* Added "Mod count" label ({mod_count}) ## v2.3.2 * Resolved issue with "Respawn Delay" diff --git a/resources/hacks/level.json b/resources/hacks/level.json index 605a66c..7ec6020 100644 --- a/resources/hacks/level.json +++ b/resources/hacks/level.json @@ -2,17 +2,8 @@ "title": "Level", "items": [ { - "type": "toggle", - "title": "Noclip", - "description": "Disables dying.", - "id": "level.noclip", - "opcodes": [ - { - "pattern": "6A148BCBFF15", - "mask": "E9@4(8BCBFF15????^8B4C24?64890D00000000595F5E)" - } - ], - "cheat": true + "type": "embedded", + "hack": "noclip" }, { "type": "embedded", diff --git a/src/geode/hooks/PlayLayer.cpp b/src/geode/hooks/PlayLayer.cpp index 0aa9b9c..127ddf7 100644 --- a/src/geode/hooks/PlayLayer.cpp +++ b/src/geode/hooks/PlayLayer.cpp @@ -4,6 +4,7 @@ #include "../../shared/hacks/auto-pickup-coins/auto-pickup-coins.hpp" #include "../../shared/hacks/startpos-switcher/startpos-switcher.hpp" #include "../../shared/hacks/labels/labels.hpp" +#include "../../shared/hacks/noclip/noclip.hpp" #include "../../shared/hacks/noclip-limit/noclip-limit.hpp" #include "../../shared/hacks/zephyrus/replays.hpp" #include "../../shared/hacks/random-seed/random-seed.hpp" @@ -17,6 +18,10 @@ namespace openhack::hooks { struct PlayLayerHook : geode::Modify { + static void onModify(auto& self) { + (void) self.setHookPriority("PlayLayer::destroyPlayer", 0x500000); + } + bool init(GJGameLevel *level, bool useReplay, bool dontCreateObjects) { hacks::Display::playLayerInit(level); hacks::AutoPickupCoins::initLevel(); @@ -54,14 +59,15 @@ namespace openhack::hooks { hacks::SmartStartPos::addObject(object); } - void destroyPlayer(PlayerObject* player, GameObject* object) { - hacks::NoclipLimit::destroyPlayer(object); - PlayLayer::destroyPlayer(player, object); + void destroyPlayer(PlayerObject* player, GameObject* object) override { + hacks::NoclipLimit::destroyPlayer(player, object); + if (!hacks::Noclip::destroyPlayer(player, object)) + PlayLayer::destroyPlayer(player, object); hacks::NoclipLimit::postDestroyPlayer(); hacks::Hitboxes::destroyPlayer(); } - void postUpdate(float dt) { + void postUpdate(float dt) override { PlayLayer::postUpdate(dt); hacks::Hitboxes::postUpdate(); hacks::AccuratePercentage::postUpdate(); diff --git a/src/shared/hacks/hack-list.hpp b/src/shared/hacks/hack-list.hpp index a84a0e1..a6ffa75 100644 --- a/src/shared/hacks/hack-list.hpp +++ b/src/shared/hacks/hack-list.hpp @@ -11,6 +11,7 @@ #include "click-tp/click-tp.hpp" #include "labels/labels.hpp" #include "noclip-limit/noclip-limit.hpp" +#include "noclip/noclip.hpp" #include "rgb-icons/rgb-icons.hpp" #include "zephyrus/replays.hpp" #include "frame-stepper/frame-stepper.hpp" @@ -44,6 +45,7 @@ namespace openhack::hacks { new DiscordRPC(), new ClickTeleport(), new Labels(), + new Noclip(), new NoclipLimit(), new RGBIcons(), new Zephyrus(), diff --git a/src/shared/hacks/hide-triggers/hide-triggers.cpp b/src/shared/hacks/hide-triggers/hide-triggers.cpp index 3edaa32..50df059 100644 --- a/src/shared/hacks/hide-triggers/hide-triggers.cpp +++ b/src/shared/hacks/hide-triggers/hide-triggers.cpp @@ -31,6 +31,11 @@ namespace openhack::hacks { }); } + static bool isSpeedPortal(GameObject* obj) { + auto id = obj->m_objectID; + return id == 200 || id == 201 || id == 202 || id == 203 || id == 1334; + } + void HideTriggers::onPlaytest() { if (!config::get("hack.hide_triggers.enabled")) return; @@ -42,7 +47,9 @@ namespace openhack::hacks { for (int i = 0; i < objects->count(); i++) { auto obj = objects->objectAtIndex(i); auto* gameObject = reinterpret_cast(obj); - if (gameObject->m_objectType == GameObjectType::Modifier) { + if (gameObject->m_objectType == GameObjectType::Modifier && + !isSpeedPortal(gameObject) && + gameObject->m_objectID != 2063) { triggers.push_back(gameObject); } } diff --git a/src/shared/hacks/labels/labels.hpp b/src/shared/hacks/labels/labels.hpp index 8d73675..831dc5b 100644 --- a/src/shared/hacks/labels/labels.hpp +++ b/src/shared/hacks/labels/labels.hpp @@ -133,8 +133,7 @@ namespace openhack::hacks { bool isCheating() override { return false; } /// @brief Replaces all {} tokens in a string with their respective values - static std::string - replaceTokens(const std::string &text, PlayLayer *playLayer, LevelEditorLayer *editorLayer); + static std::string replaceTokens(const std::string &text, PlayLayer *playLayer, LevelEditorLayer *editorLayer); /// @brief Save the labels to the config static void save(); diff --git a/src/shared/hacks/noclip-limit/noclip-limit.cpp b/src/shared/hacks/noclip-limit/noclip-limit.cpp index f2db23a..7edf2fe 100644 --- a/src/shared/hacks/noclip-limit/noclip-limit.cpp +++ b/src/shared/hacks/noclip-limit/noclip-limit.cpp @@ -5,9 +5,9 @@ namespace openhack::hacks { bool isDead = false; bool lastFrameDead = false; - bool isAntiCheatDeath = false; - GameObject* antiCheatObject = nullptr; uint32_t deathCount = 0; + bool isAntiCheatDeath = false; + bool hadNoclip = false; void NoclipLimit::onInit() { // Set the default value @@ -68,17 +68,12 @@ namespace openhack::hacks { return result; } - void NoclipLimit::destroyPlayer(GameObject* object) { - isAntiCheatDeath = false; - - auto frames = config::getGlobal("frame", 0); - if (!antiCheatObject && frames < 5) { - isAntiCheatDeath = true; - antiCheatObject = object; - return; - } + void NoclipLimit::destroyPlayer(PlayerObject* player, GameObject* object) { + PlayLayer* pl = PlayLayer::get(); + if (!pl) return; + if (player != pl->m_player1 || player != pl->m_player2) return; - if (antiCheatObject == object) { + if (pl->m_anticheatSpike == object) { isAntiCheatDeath = true; return; } @@ -86,7 +81,8 @@ namespace openhack::hacks { if (!config::get("hack.noclip_limit.enabled", false)) return; if (shouldDie()) { - hacks::getHack("level.noclip")->applyPatch(false); // disable noclip + hadNoclip = config::get("hack.noclip", false); + config::set("hack.noclip", false); } } @@ -97,7 +93,7 @@ namespace openhack::hacks { if (!config::get("hack.noclip_limit.enabled", false)) return; if (shouldDie()) { - hacks::getHack("level.noclip")->applyPatch(); // restore original setting + config::set("hack.noclip", hadNoclip); } } @@ -105,7 +101,6 @@ namespace openhack::hacks { isDead = false; lastFrameDead = false; deathCount = 0; - antiCheatObject = nullptr; config::setGlobal("noclipAcc", 100.0f); config::setGlobal("noclipDeath", 0); } diff --git a/src/shared/hacks/noclip-limit/noclip-limit.hpp b/src/shared/hacks/noclip-limit/noclip-limit.hpp index 7a07d9a..27ee3c4 100644 --- a/src/shared/hacks/noclip-limit/noclip-limit.hpp +++ b/src/shared/hacks/noclip-limit/noclip-limit.hpp @@ -16,7 +16,7 @@ namespace openhack::hacks { public: /// @brief PlayLayer::destroyPlayer hook - static void destroyPlayer(GameObject* object); + static void destroyPlayer(PlayerObject* player, GameObject* object); /// @brief PlayLayer::destroyPlayer hook (after the original function) static void postDestroyPlayer(); diff --git a/src/shared/hacks/noclip/noclip.cpp b/src/shared/hacks/noclip/noclip.cpp new file mode 100644 index 0000000..409210d --- /dev/null +++ b/src/shared/hacks/noclip/noclip.cpp @@ -0,0 +1,60 @@ +#include "noclip.hpp" +#include "../../menu/menu.hpp" + +namespace openhack::hacks { + + void Noclip::onInit() { + // Set the default value + config::setIfEmpty("level.noclip", false); + config::setIfEmpty("hack.noclip.p1", true); + config::setIfEmpty("hack.noclip.p2", true); + + // Initialize keybind + menu::keybinds::setKeybindCallback("level.noclip", []() { + bool enabled = !config::get("level.noclip"); + config::set("level.noclip", enabled); + }); + } + + void Noclip::onDraw() { + gui::callback([](){ + gui::tooltip("Automatically kills the player when you reach the death limit or accuracy limit"); + menu::keybinds::addMenuKeybind("level.noclip", "Noclip", [](){ + bool enabled = !config::get("level.noclip"); + config::set("level.noclip", enabled); + }); + }); + gui::toggleSetting("Noclip", "level.noclip", []() { + gui::width(150); + gui::checkbox("Player 1", "hack.noclip.p1"); + gui::tooltip("Whether to enable noclip for player 1"); + gui::checkbox("Player 2", "hack.noclip.p2"); + gui::tooltip("Whether to enable noclip for player 2"); + gui::width(); + }, ImVec2(0, 0), 150); + } + + bool Noclip::isCheating() { + return config::get("level.noclip") && (config::get("hack.noclip.p1") || config::get("hack.noclip.p2")); + } + + bool Noclip::destroyPlayer(PlayerObject* player, GameObject* object) { + PlayLayer* pl = PlayLayer::get(); + if (!pl) return false; + + if (object == pl->m_anticheatSpike) + return false; + + if (!config::get("level.noclip")) + return false; + + if (config::get("hack.noclip.p1") && player == pl->m_player1) + return true; + + if (config::get("hack.noclip.p2") && player == pl->m_player2) + return true; + + return false; + } + +} \ No newline at end of file diff --git a/src/shared/hacks/noclip/noclip.hpp b/src/shared/hacks/noclip/noclip.hpp new file mode 100644 index 0000000..04bbf97 --- /dev/null +++ b/src/shared/hacks/noclip/noclip.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include "../hacks.hpp" + +namespace openhack::hacks { + + /// @brief Kills the player if they die too much in noclip mode + class Noclip : public EmbeddedHack { + public: + Noclip() : EmbeddedHack("Noclip", "noclip") {} + + void onInit() override; + void onDraw() override; + void update() override {} + bool isCheating() override; + + public: + /// @brief PlayLayer::destroyPlayer hook + /// @return `true` if the original function should be called + static bool destroyPlayer(PlayerObject* player, GameObject* object); + }; + +} \ No newline at end of file diff --git a/src/shared/hacks/shortcuts/shortcuts.hpp b/src/shared/hacks/shortcuts/shortcuts.hpp index 2b6ebf3..671bfce 100644 --- a/src/shared/hacks/shortcuts/shortcuts.hpp +++ b/src/shared/hacks/shortcuts/shortcuts.hpp @@ -15,7 +15,7 @@ namespace openhack::hacks { bool isCheating() override { return false; } private: - static void patchGame(); + // static void patchGame(); static void uncompleteLevel(); static void openOptions(); static void restartLevel(); diff --git a/src/shared/hacks/smart-startpos/smart-startpos.cpp b/src/shared/hacks/smart-startpos/smart-startpos.cpp index 9ca1db8..8b58b44 100644 --- a/src/shared/hacks/smart-startpos/smart-startpos.cpp +++ b/src/shared/hacks/smart-startpos/smart-startpos.cpp @@ -4,7 +4,7 @@ namespace openhack::hacks { static std::vector s_startPosObjects; - static std::vector s_gravityPortals, s_dualPortals, s_gamemodePortals, s_miniPortals, s_speedChanges, s_mirrorPortals; + static std::vector s_dualPortals, s_gamemodePortals, s_miniPortals, s_speedChanges, s_mirrorPortals; void SmartStartPos::onInit() { // Set default values @@ -30,7 +30,6 @@ namespace openhack::hacks { void SmartStartPos::initLevel() { // Clear all vectors s_startPosObjects.clear(); - s_gravityPortals.clear(); s_dualPortals.clear(); s_gamemodePortals.clear(); s_miniPortals.clear(); @@ -38,14 +37,26 @@ namespace openhack::hacks { s_mirrorPortals.clear(); } + GameObject* getClosestObject(std::vector& vec, StartPosObject* startPos) { + GameObject* closest = nullptr; + + std::sort(vec.begin(), vec.end(), [] (GameObject* a, GameObject* b) { + return a->getPositionX() < b->getPositionX(); + }); + + for (auto obj : vec) { + if (obj->getPositionX() - 10 > startPos->getPositionX()) + break; + else if (obj->getPositionX() - 10 < startPos->getPositionX()) + closest = obj; + } + + return closest; + } + void SmartStartPos::addObject(GameObject* object) { auto objID = object->m_objectID; switch (objID) { - case 10: // Blue Gravity Portal - case 11: // Yellow Gravity Portal - case 2926: // Green Gravity Portal - s_gravityPortals.push_back(object); - break; case 12: // Cube Portal case 13: // Ship Portal case 47: // Ball Portal @@ -81,159 +92,84 @@ namespace openhack::hacks { default: return; } - - // Recalculate start positions when a new object is added - updateSmartStartPos(); } - /// @brief Get all objects that are before the given x position - std::vector findBefore(std::vector& vec, float x) { - std::vector result; - for (auto* obj : vec) { - if (obj->getPositionX() < x) { - result.push_back(obj); + void SmartStartPos::updateSmartStartPos(StartPosObject* startPos) { + LevelSettingsObject* startPosSettings = startPos->m_startSettings; + LevelSettingsObject* levelSettings = PlayLayer::get()->m_levelSettings; + + startPosSettings->m_startDual = levelSettings->m_startDual; + startPosSettings->m_startMode = levelSettings->m_startMode; + startPosSettings->m_startMini = levelSettings->m_startMini; + startPosSettings->m_startSpeed = levelSettings->m_startSpeed; + + GameObject* obj = getClosestObject(s_dualPortals, startPos); + if (obj) + startPosSettings->m_startDual = obj->m_objectID == 286; + + obj = getClosestObject(s_gamemodePortals, startPos); + + if (obj) { + switch(obj->m_objectID) { + case 12: + startPosSettings->m_startMode = 0; + break; + case 13: + startPosSettings->m_startMode = 1; + break; + case 47: + startPosSettings->m_startMode = 2; + break; + case 111: + startPosSettings->m_startMode = 3; + break; + case 660: + startPosSettings->m_startMode = 4; + break; + case 745: + startPosSettings->m_startMode = 5; + break; + case 1331: + startPosSettings->m_startMode = 6; + break; + case 1933: + startPosSettings->m_startMode = 7; + break; } } - return result; - } - GameObject* findLastBefore(std::vector& vec, float x) { - GameObject* result = nullptr; - for (auto* obj : vec) { - if (obj->getPositionX() < x) { - result = obj; + obj = getClosestObject(s_miniPortals, startPos); + + if (obj) + startPosSettings->m_startMini = obj->m_objectID == 101; + + obj = getClosestObject(s_speedChanges, startPos); + if (obj) { + switch(obj->m_objectID) { + case 200: + startPosSettings->m_startSpeed = Speed::Slow; + break; + case 201: + startPosSettings->m_startSpeed = Speed::Normal; + break; + case 202: + startPosSettings->m_startSpeed = Speed::Fast; + break; + case 203: + startPosSettings->m_startSpeed = Speed::Faster; + break; + case 1334: + startPosSettings->m_startSpeed = Speed::Fastest; + break; } } - return result; } - void SmartStartPos::updateSmartStartPos() { - if (!config::get("hack.smart_startpos.enabled")) return; - if (s_startPosObjects.empty()) return; - - for (auto* startPos : s_startPosObjects) { - auto x = startPos->getPositionX(); - auto* startPosSettings = startPos->m_startSettings; - bool upsideDown = startPosSettings->m_isFlipped; - bool dual = startPosSettings->m_startDual; - bool mini = startPosSettings->m_startMini; - bool mirror = startPosSettings->m_mirrorMode; - int speed = static_cast(startPosSettings->m_startSpeed); - int gamemode = startPosSettings->m_startMode; - - // Get all objects that are before the current StartPos - auto gravityPortals = findBefore(s_gravityPortals, x + 10); - auto dualPortal = findLastBefore(s_dualPortals, x + 10); - auto gamemodePortal = findLastBefore(s_gamemodePortals, x + 10); - auto miniPortal = findLastBefore(s_miniPortals, x + 10); - auto speedChange = findLastBefore(s_speedChanges, x + 50); - auto mirrorPortal = findLastBefore(s_mirrorPortals, x + 10); - - // Iterate over all objects and set the settings accordingly - for (auto* gravityPortal : gravityPortals) { - switch (gravityPortal->m_objectID) { - case 10: // Blue Gravity Portal - upsideDown = false; - break; - case 11: // Yellow Gravity Portal - upsideDown = true; - break; - case 2926: // Green Gravity Portal - upsideDown = !upsideDown; - break; - } - } - - if (dualPortal) { - switch (dualPortal->m_objectID) { - case 286: // Orange Dual Portal - dual = true; - break; - case 287: // Blue Dual Portal - dual = false; - break; - } - } - - if (dualPortal) { - switch (gamemodePortal->m_objectID) { - case 12: // Cube Portal - gamemode = 0; - break; - case 13: // Ship Portal - gamemode = 1; - break; - case 47: // Ball Portal - gamemode = 2; - break; - case 111: // UFO Portal - gamemode = 3; - break; - case 660: // Wave Portal - gamemode = 4; - break; - case 745: // Robot Portal - gamemode = 5; - break; - case 1331: // Spider Portal - gamemode = 6; - break; - case 1933: // SwingCopter Portal - gamemode = 7; - break; - } - } - - if (miniPortal) { - switch (miniPortal->m_objectID) { - case 99: // Normal Size Portal - mini = false; - break; - case 101: // Mini Portal - mini = true; - break; - } - } - - if (speedChange) { - switch (speedChange->m_objectID) { - case 200: // -1x Speed Change - speed = 1; - break; - case 201: // 1x Speed Change - speed = 0; - break; - case 202: // 2x Speed Change - speed = 2; - break; - case 203: // 3x Speed Change - speed = 3; - break; - case 1334: // 4x Speed Change - speed = 4; - break; - } - } - - if (mirrorPortal) { - switch (mirrorPortal->m_objectID) { - case 45: // Orange Mirror Portal - mirror = true; - break; - case 46: // Blue Mirror Portal - mirror = false; - break; - } - } - - startPosSettings->m_startMode = gamemode; - startPosSettings->m_startSpeed = static_cast(speed); - startPosSettings->m_startMini = mini; - startPosSettings->m_startDual = dual; - startPosSettings->m_mirrorMode = mirror; - startPosSettings->m_isFlipped = upsideDown; + void SmartStartPos::resetLevel() { + if (config::get("hack.smart_startpos.enabled", false)) { + for (StartPosObject* obj : s_startPosObjects) + updateSmartStartPos(obj); } - } } \ No newline at end of file diff --git a/src/shared/hacks/smart-startpos/smart-startpos.hpp b/src/shared/hacks/smart-startpos/smart-startpos.hpp index 6c6f7ba..5e68b1a 100644 --- a/src/shared/hacks/smart-startpos/smart-startpos.hpp +++ b/src/shared/hacks/smart-startpos/smart-startpos.hpp @@ -14,7 +14,7 @@ namespace openhack::hacks { void update() override {} bool isCheating() override { return false; } - static void updateSmartStartPos(); + static void updateSmartStartPos(StartPosObject* startPos); public: /// @brief PlayLayer::init hook @@ -22,6 +22,9 @@ namespace openhack::hacks { /// @brief PlayLayer::addObject hook static void addObject(GameObject* object); + + /// @brief PlayLayer::resetLevel hook + static void resetLevel(); }; } \ No newline at end of file diff --git a/src/shared/hacks/speedhack/speedhack.cpp b/src/shared/hacks/speedhack/speedhack.cpp index 6554178..02ef073 100644 --- a/src/shared/hacks/speedhack/speedhack.cpp +++ b/src/shared/hacks/speedhack/speedhack.cpp @@ -3,6 +3,16 @@ namespace openhack::hacks { + void updateChannels() { + FMOD::Channel *channel; + FMOD::System *system = FMODAudioEngine::sharedEngine()->m_system; + for (auto i = 0; i < 2; i++) { + system->getChannel(126 + i, &channel); + if (channel) + SpeedHack::setVolume(channel); + } + } + void SpeedHack::onInit() { // Set default values // We're disabling speedhack by default, so the game actually loads @@ -30,14 +40,16 @@ namespace openhack::hacks { }); } + static bool s_lastSpeedhackState = false; + void SpeedHack::update() { - FMOD::Channel *channel; - FMOD::System *system = FMODAudioEngine::sharedEngine()->m_system; - for (auto i = 0; i < 2; i++) { - system->getChannel(126 + i, &channel); - if (channel) - setVolume(channel); - } + bool speedhack = config::get("hack.speedhack.enabled", false); + bool toggledSpeedhack = s_lastSpeedhackState != speedhack; + s_lastSpeedhackState = speedhack; + + bool sync = config::get("hack.speedhack.music", false); + if ((speedhack || toggledSpeedhack) && sync) + updateChannels(); } bool SpeedHack::isCheating() { diff --git a/src/shared/hacks/startpos-switcher/startpos-switcher.cpp b/src/shared/hacks/startpos-switcher/startpos-switcher.cpp index 171a0e0..2a07a1b 100644 --- a/src/shared/hacks/startpos-switcher/startpos-switcher.cpp +++ b/src/shared/hacks/startpos-switcher/startpos-switcher.cpp @@ -114,7 +114,7 @@ namespace openhack::hacks { // Setup label m_label = new Label("", "bigFont.fnt"); - m_label->setId("openhack-startpos-label"); + m_label->setId("startpos-label"_spr); m_label->addToLayer(PlayLayer::get()); updateLabel(); } diff --git a/src/shared/platform/win32/win32.cpp b/src/shared/platform/win32/win32.cpp index d457e72..3286161 100644 --- a/src/shared/platform/win32/win32.cpp +++ b/src/shared/platform/win32/win32.cpp @@ -50,6 +50,9 @@ namespace openhack::utils { if (!gameVersion.empty()) return gameVersion; +#ifdef OPENHACK_GEODE + gameVersion = geode::Loader::get()->getGameVersion(); +#else HMODULE module = GetModuleHandleA(nullptr); auto dosHeader = (PIMAGE_DOS_HEADER) module; @@ -121,6 +124,7 @@ namespace openhack::utils { } gameVersion = "Unknown"; +#endif return gameVersion; } From e9579af45eeb488b66df7bd0143f2ce5fd7bf628 Mon Sep 17 00:00:00 2001 From: Oleksandr Nemesh Date: Mon, 7 Oct 2024 23:37:06 +0300 Subject: [PATCH 20/20] Update README.md --- README.md | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 46ee976..c1b1895 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,13 @@ + +

+

Deprecation Notice!

+

This repository is no longer maintained. Please consider using + Eclipse Menu instead, + which is a more up-to-date and feature-rich mod for Geometry Dash.

+

Latest Geometry Dash version supported by OpenHack is 2.204.

+
+ +
@@ -28,10 +32,6 @@

-
- Supports both Geode and Vanilla Geometry Dash! -
- ## Table of Contents - [About](#about) - [Features](#features) @@ -64,7 +64,7 @@ Please visit the [issues](https://github.com/prevter/gdopenhack/issues) page for - And more! ## Installation -> **Note:** OpenHack is only compatible with Windows and Linux (using Wine). Other operating systems are not supported for now. +> **Note:** OpenHack is only compatible with Windows (also Linux and macOS, if you're using Proton/Wine to run Geometry Dash). Other operating systems are not supported for now. There are two ways to install OpenHack: using Geode, or manually installing the mod. Each method has its own advantages and disadvantages, so choose the one that best suits your needs. @@ -128,15 +128,11 @@ Please read [CONTRIBUTING.md](CONTRIBUTING.md) for more information. ## License Distributed under the MIT License. See [LICENSE](LICENSE) for more information. -## Contact -Join the [Discord server](https://discord.gg/HaHn7RSJ4Q) to get in touch with the developers and other users. - -If you want to contact me directly, you can do so via -- Discord: `@prevter` -- Email: `support@prevter.me` - -## Support -If you like the project, consider supporting it by [buying me a coffee](https://www.buymeacoffee.com/prevter) or by contributing to the project. Any support is greatly appreciated and helps me keep motivated to work on the project and add new features! +[//]: # (## Contact) +[//]: # (Join the [Discord server](https://discord.gg/HaHn7RSJ4Q) to get in touch with the developers and other users.) +[//]: # (If you want to contact me directly, you can do so via) +[//]: # (- Discord: `@prevter`) +[//]: # (- Email: `support@prevter.me`) ## Acknowledgements [MegaHack](https://absolllute.com/store/view_mega_hack_pro) by Absolute for design inspiration and ideas.