From a6690c2052552a7339664f7ec7965da1ac747ee3 Mon Sep 17 00:00:00 2001 From: madeline Date: Sun, 12 Apr 2026 23:22:25 -0700 Subject: [PATCH 001/390] speedrun timer --- CMakeLists.txt | 4 + files.cmake | 3 + include/dusk/livesplit.h | 16 ++ include/dusk/settings.h | 5 + src/d/d_bright_check.cpp | 4 + src/dusk/imgui/ImGuiConsole.cpp | 27 +++- src/dusk/imgui/ImGuiConsole.hpp | 4 + src/dusk/imgui/ImGuiMenuEnhancements.cpp | 18 +++ src/dusk/imgui/ImGuiMenuSpeedrunTimer.cpp | 96 ++++++++++++ src/dusk/imgui/ImGuiMenuSpeedrunTimer.hpp | 13 ++ src/dusk/livesplit.cpp | 183 ++++++++++++++++++++++ src/dusk/settings.cpp | 10 +- src/f_ap/f_ap_game.cpp | 4 + 13 files changed, 385 insertions(+), 2 deletions(-) create mode 100644 include/dusk/livesplit.h create mode 100644 src/dusk/imgui/ImGuiMenuSpeedrunTimer.cpp create mode 100644 src/dusk/imgui/ImGuiMenuSpeedrunTimer.hpp create mode 100644 src/dusk/livesplit.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 775606ca8e..f1b4e4e26c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -216,6 +216,10 @@ set(GAME_INCLUDE_DIRS set(GAME_LIBS aurora::core aurora::gx aurora::gd aurora::si aurora::vi aurora::pad aurora::mtx aurora::os aurora::dvd aurora::card freeverb cxxopts::cxxopts absl::flat_hash_map nlohmann_json::nlohmann_json TracyClient) +if (WIN32) + list(APPEND GAME_LIBS Ws2_32) +endif () + if (DUSK_MOVIE_SUPPORT) if (TARGET libjpeg-turbo::turbojpeg-static) list(APPEND GAME_LIBS libjpeg-turbo::turbojpeg-static) diff --git a/files.cmake b/files.cmake index 7507fb6742..cfc6fcbdea 100644 --- a/files.cmake +++ b/files.cmake @@ -1361,6 +1361,8 @@ set(DUSK_FILES src/dusk/imgui/ImGuiMenuTools.hpp src/dusk/imgui/ImGuiMenuEnhancements.cpp src/dusk/imgui/ImGuiMenuEnhancements.hpp + src/dusk/imgui/ImGuiMenuSpeedrunTimer.cpp + src/dusk/imgui/ImGuiMenuSpeedrunTimer.hpp src/dusk/imgui/ImGuiPreLaunchWindow.cpp src/dusk/imgui/ImGuiPreLaunchWindow.hpp src/dusk/imgui/ImGuiFirstRunPreset.hpp @@ -1373,6 +1375,7 @@ set(DUSK_FILES src/dusk/imgui/ImGuiStubLog.cpp src/dusk/imgui/ImGuiMapLoader.cpp src/dusk/imgui/ImGuiSaveEditor.cpp + src/dusk/livesplit.cpp src/dusk/offset_ptr.cpp src/dusk/OSContext.cpp src/dusk/OSThread.cpp diff --git a/include/dusk/livesplit.h b/include/dusk/livesplit.h new file mode 100644 index 0000000000..b283a29af4 --- /dev/null +++ b/include/dusk/livesplit.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +namespace dusk::speedrun { +void onGameFrame(); +uint64_t getFrameCount(); +void start(); +void reset(); +void connectLiveSplit(const char* host = "127.0.0.1", int port = 16834); +void disconnectLiveSplit(); +bool consumeConnectedEvent(); +bool consumeDisconnectedEvent(); +void updateLiveSplit(); +void shutdown(); +} diff --git a/include/dusk/settings.h b/include/dusk/settings.h index 2ab587d3ce..1a5772e310 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -79,6 +79,11 @@ struct UserSettings { // Controls ConfigVar enableTurboKeybind; + + // Tools + ConfigVar speedrunTimer; + ConfigVar speedrunTimerOverlay; + ConfigVar liveSplitEnabled; } game; struct { diff --git a/src/d/d_bright_check.cpp b/src/d/d_bright_check.cpp index ac28e46838..ae4849cbe9 100644 --- a/src/d/d_bright_check.cpp +++ b/src/d/d_bright_check.cpp @@ -9,6 +9,7 @@ #include "JSystem/J2DGraph/J2DScreen.h" #include "JSystem/J2DGraph/J2DTextBox.h" #include "d/d_msg_string.h" +#include "dusk/livesplit.h" #include "m_Do/m_Do_controller_pad.h" dBrightCheck_c::dBrightCheck_c(JKRArchive* i_archive) { @@ -138,6 +139,9 @@ void dBrightCheck_c::modeWait() {} void dBrightCheck_c::modeMove() { if (mDoCPd_c::getTrigA(PAD_1) || mDoCPd_c::getTrigStart(PAD_1)) { mDoAud_seStart(Z2SE_ENTER_GAME, NULL, 0, 0); +#ifdef TARGET_PC + dusk::speedrun::start(); +#endif mCompleteCheck = true; mMode = MODE_WAIT_e; } diff --git a/src/dusk/imgui/ImGuiConsole.cpp b/src/dusk/imgui/ImGuiConsole.cpp index 1bff5da458..dc27f17c39 100644 --- a/src/dusk/imgui/ImGuiConsole.cpp +++ b/src/dusk/imgui/ImGuiConsole.cpp @@ -16,6 +16,7 @@ #include "m_Do/m_Do_controller_pad.h" #include "m_Do/m_Do_main.h" #include "dusk/config.hpp" +#include "dusk/livesplit.h" #include "dusk/main.h" #include "dusk/settings.h" #include "dusk/audio/DuskAudioSystem.h" @@ -38,6 +39,10 @@ namespace dusk { ImGui::TextUnformatted(text.data(), text.data() + text.size()); } + void DuskToast(std::string_view message, float duration) { + g_imguiConsole.AddToast(message, duration); + } + void ImGuiTextCenter(std::string_view text) { ImGui::NewLine(); float fontSize = ImGui::CalcTextSize(text.data(), text.data() + text.size()).x; @@ -235,6 +240,8 @@ namespace dusk { m_menuEnhancements.draw(); m_menuTools.draw(); + m_menuSpeedrunTimer.draw(); + ImGui::SetCursorPosX(ImGui::GetWindowWidth() - 80.0f * ImGuiScale()); ImGuiIO& io = ImGui::GetIO(); ImGuiStringViewText(fmt::format(FMT_STRING("FPS: {:.2f}\n"), io.Framerate)); @@ -252,12 +259,26 @@ namespace dusk { } if (dusk::IsGameLaunched && !m_isLaunchInitialized) { - m_toasts.emplace_back("Press F1 to toggle menu"s, 5.f); + DuskToast("Press F1 to toggle menu"s); m_isLaunchInitialized = true; + if (getSettings().game.liveSplitEnabled) { + dusk::speedrun::connectLiveSplit(); + } } + m_menuSpeedrunTimer.drawOverlay(); + m_menuGame.windowControllerConfig(); m_menuGame.windowInputViewer(); + + if (getSettings().game.liveSplitEnabled) { + dusk::speedrun::updateLiveSplit(); + if (dusk::speedrun::consumeConnectedEvent()) + AddToast("LiveSplit connected"); + else if (dusk::speedrun::consumeDisconnectedEvent()) + AddToast("LiveSplit disconnected"); + } + if (dusk::IsGameLaunched) { m_menuTools.ShowDebugOverlay(); m_menuTools.ShowCameraOverlay(); @@ -383,6 +404,10 @@ namespace dusk { return false; } + void ImGuiConsole::AddToast(std::string_view message, float duration) { + m_toasts.emplace_back(std::string(message), duration); + } + void ImGuiConsole::ShowToasts() { if (m_toasts.empty()) { return; diff --git a/src/dusk/imgui/ImGuiConsole.hpp b/src/dusk/imgui/ImGuiConsole.hpp index 0296dc24cc..bec998eb63 100644 --- a/src/dusk/imgui/ImGuiConsole.hpp +++ b/src/dusk/imgui/ImGuiConsole.hpp @@ -9,6 +9,7 @@ #include "ImGuiFirstRunPreset.hpp" #include "ImGuiMenuEnhancements.hpp" #include "ImGuiMenuGame.hpp" +#include "ImGuiMenuSpeedrunTimer.hpp" #include "ImGuiMenuTools.hpp" #include "ImGuiPreLaunchWindow.hpp" #include "imgui.h" @@ -22,6 +23,7 @@ public: void PostDraw(); static bool CheckMenuViewToggle(ImGuiKey key, bool& active); + void AddToast(std::string_view message, float duration = 3.f); private: struct Toast { @@ -39,6 +41,7 @@ private: ImGuiFirstRunPreset m_firstRunPreset; ImGuiMenuGame m_menuGame; ImGuiMenuEnhancements m_menuEnhancements; + ImGuiMenuSpeedrunTimer m_menuSpeedrunTimer; ImGuiPreLaunchWindow m_preLaunchWindow; // Keep always last @@ -57,6 +60,7 @@ std::string BytesToString(size_t bytes); void SetOverlayWindowLocation(int corner); bool ShowCornerContextMenu(int& corner, int avoidCorner); void ImGuiStringViewText(std::string_view text); +void DuskToast(std::string_view message, float duration = 3.f); void ImGuiBeginGroupPanel(const char* name, const ImVec2& size); void ImGuiEndGroupPanel(); void ImGuiTextCenter(std::string_view text); diff --git a/src/dusk/imgui/ImGuiMenuEnhancements.cpp b/src/dusk/imgui/ImGuiMenuEnhancements.cpp index 50e44f5c60..dfe8f5282b 100644 --- a/src/dusk/imgui/ImGuiMenuEnhancements.cpp +++ b/src/dusk/imgui/ImGuiMenuEnhancements.cpp @@ -2,6 +2,8 @@ #include "ImGuiMenuEnhancements.hpp" #include "ImGuiConfig.hpp" +#include "ImGuiConsole.hpp" +#include "dusk/livesplit.h" #include "dusk/settings.h" namespace dusk { @@ -181,6 +183,22 @@ namespace dusk { "This will not work with the \"Unlock Framerate\" enhancement."); } + bool prevSpeedrunTimer = getSettings().game.speedrunTimer; + config::ImGuiCheckbox("Speedrun Timer", getSettings().game.speedrunTimer); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Shows a speedrun timer in the menu bar."); + } + if ((bool)getSettings().game.speedrunTimer != prevSpeedrunTimer) { + if (!getSettings().game.speedrunTimer) { + getSettings().game.speedrunTimerOverlay.setValue(false); + if (getSettings().game.liveSplitEnabled) { + getSettings().game.liveSplitEnabled.setValue(false); + dusk::speedrun::disconnectLiveSplit(); + DuskToast("LiveSplit disconnected", 3.f); + } + } + } + ImGui::EndMenu(); } diff --git a/src/dusk/imgui/ImGuiMenuSpeedrunTimer.cpp b/src/dusk/imgui/ImGuiMenuSpeedrunTimer.cpp new file mode 100644 index 0000000000..6edbb7e084 --- /dev/null +++ b/src/dusk/imgui/ImGuiMenuSpeedrunTimer.cpp @@ -0,0 +1,96 @@ +#include "fmt/format.h" +#include "imgui.h" + +#include "ImGuiMenuSpeedrunTimer.hpp" +#include "ImGuiConfig.hpp" +#include "ImGuiConsole.hpp" +#include "dusk/livesplit.h" +#include "dusk/settings.h" + +namespace dusk { + static auto formatTime(uint64_t frames) { + const uint64_t totalSec = frames / 30; + + return fmt::format( + FMT_STRING("{:d}:{:02d}:{:02d}.{:02d}"), + totalSec / 3600, + (totalSec / 60) % 60, + totalSec % 60, + (int)(((f32)(frames % 30) / 30.0f) * 100.0f) + ); + } + + void ImGuiMenuSpeedrunTimer::draw() { + if (!getSettings().game.speedrunTimer) return; + + const uint64_t frames = dusk::speedrun::getFrameCount(); + + if (ImGui::BeginMenu("Timer##speedrun_timer")) { + ImGui::TextUnformatted(formatTime(frames).c_str()); + + ImGui::Separator(); + + if (ImGui::MenuItem("Reset")) { + dusk::speedrun::reset(); + } + + config::ImGuiCheckbox("Show Overlay", getSettings().game.speedrunTimerOverlay); + + bool prevLiveSplit = getSettings().game.liveSplitEnabled; + config::ImGuiCheckbox("LiveSplit Connection", getSettings().game.liveSplitEnabled); + + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Connect to LiveSplit server on localhost:16834."); + } + + if ((bool)getSettings().game.liveSplitEnabled != prevLiveSplit) { + if (getSettings().game.liveSplitEnabled) { + dusk::speedrun::connectLiveSplit(); + } else { + dusk::speedrun::disconnectLiveSplit(); + DuskToast("LiveSplit disconnected", 3.f); + } + } + + ImGui::EndMenu(); + } + + } + + void ImGuiMenuSpeedrunTimer::drawOverlay() { + if (!getSettings().game.speedrunTimer || !getSettings().game.speedrunTimerOverlay) { + return; + } + + const uint64_t frames = dusk::speedrun::getFrameCount(); + const ImGuiViewport* viewport = ImGui::GetMainViewport(); + + const float padding = 10.f; + + ImGui::SetNextWindowPos( + ImVec2( + viewport->WorkPos.x + viewport->WorkSize.x - padding, + viewport->WorkPos.y + viewport->WorkSize.y - padding + ), + ImGuiCond_Always, ImVec2(1.f, 1.f) + ); + + ImGui::SetNextWindowBgAlpha(0.65f); + + const float fixedWidth = ImGui::CalcTextSize("9:59:59.99").x; + + ImGui::SetNextWindowContentSize(ImVec2(fixedWidth, 0.f)); + + if ( + ImGui::Begin("##speedrun_overlay", nullptr, + ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoInputs | + ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | + ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | + ImGuiWindowFlags_NoNav + ) + ) { + ImGui::TextUnformatted(formatTime(frames).c_str()); + } + ImGui::End(); + } +} diff --git a/src/dusk/imgui/ImGuiMenuSpeedrunTimer.hpp b/src/dusk/imgui/ImGuiMenuSpeedrunTimer.hpp new file mode 100644 index 0000000000..8cb524469f --- /dev/null +++ b/src/dusk/imgui/ImGuiMenuSpeedrunTimer.hpp @@ -0,0 +1,13 @@ +#ifndef DUSK_IMGUI_MENUSPEEDRUNTIMER_HPP +#define DUSK_IMGUI_MENUSPEEDRUNTIMER_HPP + +namespace dusk { + class ImGuiMenuSpeedrunTimer { + public: + void draw(); + void drawOverlay(); + private: + }; +} + +#endif // DUSK_IMGUI_MENUSPEEDRUNTIMER_HPP diff --git a/src/dusk/livesplit.cpp b/src/dusk/livesplit.cpp new file mode 100644 index 0000000000..cec765f223 --- /dev/null +++ b/src/dusk/livesplit.cpp @@ -0,0 +1,183 @@ +#if _WIN32 + #include + #include + using socket_t = SOCKET; + static void closeSocket(socket_t s) { closesocket(s); } +#else + #include + #include + #include + #include + #include + #include + using socket_t = int; + static void closeSocket(socket_t s) { close(s); } + #ifndef INVALID_SOCKET + #define INVALID_SOCKET -1 + #endif +#endif + +#include +#include "dusk/livesplit.h" +#include "f_op/f_op_overlap_mng.h" + +namespace dusk::speedrun { + +static bool running = false; +static uint64_t frameCount = 0; +static socket_t sock = INVALID_SOCKET; +static bool wasLoading = false; +static bool connected = false; +static bool connectPending = false; +static bool disconnectPending = false; + +static void sendCmd(const char* cmd) { + if (sock == INVALID_SOCKET) { + return; + } + + char msg[64]; + int len = snprintf(msg, sizeof(msg), "%s\r\n", cmd); + + if (send(sock, msg, len, 0) >= 0) { + if (!connected) { + connected = connectPending = true; + } + + return; + } + +#if _WIN32 + int err = WSAGetLastError(); + if (err == WSAEWOULDBLOCK || err == WSAENOTCONN) { + return; + } +#else + if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOTCONN) { + return; + } +#endif + + if (connected) disconnectPending = true; + closeSocket(sock); + sock = INVALID_SOCKET; + connected = connectPending = false; +} + +uint64_t getFrameCount() { + return frameCount; +} + +void onGameFrame() { + if (!running) { + return; + } + + bool loading = fopOvlpM_IsDoingReq() != 0; + + if (loading != wasLoading) { + sendCmd(loading ? "pausegametime" : "unpausegametime"); + wasLoading = loading; + } + + if (!loading) { + ++frameCount; + } +} + +void start() { + if (running) { + return; + } + + running = true; + frameCount = 0; + wasLoading = false; + sendCmd("initgametime"); + sendCmd("reset"); + sendCmd("starttimer"); +} + +void reset() { + running = false; + frameCount = 0; + wasLoading = false; + sendCmd("reset"); +} + +void connectLiveSplit(const char* host, int port) { +#if _WIN32 + WSADATA wd{}; WSAStartup(MAKEWORD(2, 2), &wd); +#endif + + if (sock != INVALID_SOCKET) { + closeSocket(sock); sock = INVALID_SOCKET; + } + + sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + if (sock == INVALID_SOCKET) { + return; + } + +#if _WIN32 + u_long nb = 1; + ioctlsocket(sock, FIONBIO, &nb); +#else + fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NONBLOCK); +#endif + + sockaddr_in addr{}; addr.sin_family = AF_INET; + addr.sin_port = htons((uint16_t)port); + inet_pton(AF_INET, host, &addr.sin_addr); + connect(sock, (sockaddr*)&addr, sizeof(addr)); + sendCmd("initgametime"); +} + +void disconnectLiveSplit() { + if (sock != INVALID_SOCKET) { + closeSocket(sock); + sock = INVALID_SOCKET; + connected = false; + } +} + +bool consumeConnectedEvent() { bool v = connectPending; connectPending = false; return v; } +bool consumeDisconnectedEvent() { bool v = disconnectPending; disconnectPending = false; return v; } + +void updateLiveSplit() { + if (sock == INVALID_SOCKET) { + return; + } + + if (!connected) { + sendCmd("initgametime"); + return; + } + + if (!running) { + return; + } + + const uint64_t totalMs = frameCount * 1000 / 30; + const uint64_t totalSec = totalMs / 1000; + char cmd[32]; + + snprintf(cmd, sizeof(cmd), "setgametime %u:%02u:%02u.%03u", + (uint32_t)(totalSec / 3600), + (uint32_t)((totalSec / 60) % 60), + (uint32_t)(totalSec % 60), + (uint32_t)(totalMs % 1000) + ); + + sendCmd(cmd); +} + +void shutdown() { + disconnectLiveSplit(); +#if _WIN32 + WSACleanup(); +#endif +} + +} diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index 0e39e55854..064bd8a86d 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -66,7 +66,12 @@ UserSettings g_userSettings = { .restoreWiiGlitches {"game.restoreWiiGlitches", false}, // Controls - .enableTurboKeybind {"game.enableTurboKeybind", false} + .enableTurboKeybind {"game.enableTurboKeybind", false}, + + // Tools + .speedrunTimer {"game.speedrunTimer", false}, + .speedrunTimerOverlay {"game.speedrunTimerOverlay", false}, + .liveSplitEnabled {"game.liveSplitEnabled", false} }, .backend = { @@ -123,6 +128,9 @@ void registerSettings() { Register(g_userSettings.game.noLowHpSound); Register(g_userSettings.game.midnasLamentNonStop); Register(g_userSettings.game.enableTurboKeybind); + Register(g_userSettings.game.speedrunTimer); + Register(g_userSettings.game.speedrunTimerOverlay); + Register(g_userSettings.game.liveSplitEnabled); Register(g_userSettings.game.fastSpinner); Register(g_userSettings.game.enableFrameInterpolation); Register(g_userSettings.game.enableGyroAim); diff --git a/src/f_ap/f_ap_game.cpp b/src/f_ap/f_ap_game.cpp index f54ca1edad..48cf4fa16d 100644 --- a/src/f_ap/f_ap_game.cpp +++ b/src/f_ap/f_ap_game.cpp @@ -15,6 +15,7 @@ #include "d/d_model.h" #include "d/d_tresure.h" #include "dusk/frame_interpolation.h" +#include "dusk/livesplit.h" #include "dusk/logging.h" #include "f_op/f_op_camera_mng.h" #include "f_op/f_op_draw_tag.h" @@ -771,6 +772,9 @@ void fapGm_Execute() { fpcM_ManagementFunc(NULL, fapGm_After); #endif cCt_Counter(0); +#ifdef TARGET_PC + dusk::speedrun::onGameFrame(); +#endif } fapGm_HIO_c g_HIO; From 95470b830fa346a64540148bddafc45360602c77 Mon Sep 17 00:00:00 2001 From: TakaRikka Date: Thu, 16 Apr 2026 05:55:46 -0700 Subject: [PATCH 002/390] wip map mirror --- include/d/d_menu_fmap2D.h | 6 ++++++ include/d/d_menu_map_common.h | 10 ++++++++++ src/d/d_menu_fmap2D.cpp | 18 ++++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/include/d/d_menu_fmap2D.h b/include/d/d_menu_fmap2D.h index 9b237f2771..d6d869c645 100644 --- a/include/d/d_menu_fmap2D.h +++ b/include/d/d_menu_fmap2D.h @@ -165,6 +165,12 @@ public: void mapBlink() {} + #if PLATFORM_WII || TARGET_PC + f32 getMirrorPosX(f32 param_0, f32 param_1) { + return (field_0x11dc * 2.0f - (param_0 + param_1)) - param_1; + } + #endif + // Unknown name struct RegionTexData { /* 0x00 */ float mMinX; diff --git a/include/d/d_menu_map_common.h b/include/d/d_menu_map_common.h index 989aee7d8b..de50d775ca 100644 --- a/include/d/d_menu_map_common.h +++ b/include/d/d_menu_map_common.h @@ -66,6 +66,16 @@ public: _c90 = param_2; } +#if PLATFORM_WII || TARGET_PC + f32 getMirrorCenterPosX(f32 param_0, f32 param_1) { + if (_c90) { + return (mCenterPosX * 2.0f - (param_0 + param_1)) - param_1; + } + + return param_0; + } +#endif + struct Stage_c { // Incomplete class diff --git a/src/d/d_menu_fmap2D.cpp b/src/d/d_menu_fmap2D.cpp index 558ad05d6d..e6078e06c2 100644 --- a/src/d/d_menu_fmap2D.cpp +++ b/src/d/d_menu_fmap2D.cpp @@ -1393,6 +1393,15 @@ void dMenu_Fmap2DBack_c::regionTextureDraw() { if (uVar10 != uVar9) { bool b = 0; f32 v = mTransX + (dVar14 + (mRegionMinMapX[uVar10] + field_0xf0c[uVar10])); + + #if TARGET_PC + if (dusk::getSettings().game.enableMirrorMode) { + b = true; + v = getMirrorPosX(mTransX + (dVar14 + (mRegionMinMapX[uVar10] + field_0xf0c[uVar10])), + mRegionMapSizeX[uVar10] * mZoom * 0.5f); + } + #endif + mpAreaTex[uVar10]->draw( v, mTransZ + (dVar13 + (mRegionMinMapY[uVar10] + field_0xf2c[uVar10])), mRegionMapSizeX[uVar10] * mZoom, mRegionMapSizeY[uVar10] * mZoom, b, false, @@ -1400,6 +1409,15 @@ void dMenu_Fmap2DBack_c::regionTextureDraw() { } else { bool b = 0; f32 v = mTransX + (dVar14 + (mRegionMinMapX[uVar9] + field_0xf0c[uVar9])); + + #if TARGET_PC + if (dusk::getSettings().game.enableMirrorMode) { + b = true; + v = getMirrorPosX(mTransX + (dVar14 + (mRegionMinMapX[uVar9] + field_0xf0c[uVar9])), + mRegionMapSizeX[uVar9] * mZoom * 0.5f); + } + #endif + mpAreaTex[uVar9]->draw( v, mTransZ + (dVar13 + (mRegionMinMapY[uVar9] + field_0xf2c[uVar9])), mRegionMapSizeX[uVar9] * mZoom, mRegionMapSizeY[uVar9] * mZoom, b, false, From a4be0841e5a60a4ee690abc172ba678538a27cbe Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Thu, 16 Apr 2026 19:30:37 -0400 Subject: [PATCH 003/390] autosave WIP --- include/f_ap/f_ap_game.h | 10 ++++ src/d/d_s_play.cpp | 3 + src/d/d_save.cpp | 7 +++ src/dusk/imgui/ImGuiConsole.cpp | 6 +- src/dusk/imgui/ImGuiConsole.hpp | 2 + src/f_ap/f_ap_game.cpp | 100 ++++++++++++++++++++++++++++++++ 6 files changed, 127 insertions(+), 1 deletion(-) diff --git a/include/f_ap/f_ap_game.h b/include/f_ap/f_ap_game.h index fca2e70705..5d09d9bc28 100644 --- a/include/f_ap/f_ap_game.h +++ b/include/f_ap/f_ap_game.h @@ -14,6 +14,16 @@ void fapGm_After(); void fapGm_Create(); void fapGm_Execute(); +#if TARGET_PC +void noAutoSave(); +void triggerAutoSave(); +void updateAutoSave(); +void enterAutoSave(); +void autoSaving(); +void waitingForWrite(); +void endAutoSave(); +#endif + class fapGm_HIO_c : public JORReflexible { public: fapGm_HIO_c(); diff --git a/src/d/d_s_play.cpp b/src/d/d_s_play.cpp index 3f3cd073b9..ec8ea8f70a 100644 --- a/src/d/d_s_play.cpp +++ b/src/d/d_s_play.cpp @@ -1499,6 +1499,9 @@ static int phase_4(dScnPly_c* i_this) { } if (preLoadNo < 0) { + #if TARGET_PC + triggerAutoSave(); + #endif return cPhs_COMPLEATE_e; } diff --git a/src/d/d_save.cpp b/src/d/d_save.cpp index 3289a49c64..71f65b61e6 100644 --- a/src/d/d_save.cpp +++ b/src/d/d_save.cpp @@ -25,7 +25,10 @@ #include "lingcod/lingcod.h" #endif +#if TARGET_PC #include "dusk/settings.h" +#include +#endif static u8 dSv_item_rename(u8 i_itemNo) { switch (i_itemNo) { @@ -343,6 +346,10 @@ void dSv_player_item_c::setItem(int i_slotNo, u8 i_itemNo) { dComIfGp_setSelectItem(i); } } + + #if TARGET_PC + triggerAutoSave(); + #endif } u8 dSv_player_item_c::getItem(int i_slotNo, bool i_checkCombo) const { diff --git a/src/dusk/imgui/ImGuiConsole.cpp b/src/dusk/imgui/ImGuiConsole.cpp index eccf9b3c20..d030ca9119 100644 --- a/src/dusk/imgui/ImGuiConsole.cpp +++ b/src/dusk/imgui/ImGuiConsole.cpp @@ -267,7 +267,7 @@ namespace dusk { } if (dusk::IsGameLaunched && !m_isLaunchInitialized) { - m_toasts.emplace_back("Press F1 to toggle menu"s, 2.5f); + ShowToast("Press F1 to toggle menu", 2.5f); m_isLaunchInitialized = true; } @@ -401,6 +401,10 @@ namespace dusk { return false; } + void ImGuiConsole::ShowToast(std::string text, float time) { + m_toasts.emplace_back(text, time); + } + void ImGuiConsole::ShowToasts() { if (m_toasts.empty()) { return; diff --git a/src/dusk/imgui/ImGuiConsole.hpp b/src/dusk/imgui/ImGuiConsole.hpp index 0296dc24cc..9cef53d0e4 100644 --- a/src/dusk/imgui/ImGuiConsole.hpp +++ b/src/dusk/imgui/ImGuiConsole.hpp @@ -21,6 +21,8 @@ public: void PreDraw(); void PostDraw(); + void ShowToast(std::string, float); + static bool CheckMenuViewToggle(ImGuiKey key, bool& active); private: diff --git a/src/f_ap/f_ap_game.cpp b/src/f_ap/f_ap_game.cpp index 93a9148957..2ee6dd5e40 100644 --- a/src/f_ap/f_ap_game.cpp +++ b/src/f_ap/f_ap_game.cpp @@ -22,7 +22,15 @@ #include "f_op/f_op_scene_mng.h" #include "m_Do/m_Do_graphic.h" #include "m_Do/m_Do_main.h" + +#if TARGET_PC #include "tracy/Tracy.hpp" +#include +#include +#include +#include +#endif +#include fapGm_HIO_c::fapGm_HIO_c() { mUsingHostIO = true; @@ -732,6 +740,95 @@ static void fapGm_AfterRecord() { dusk::frame_interp::end_record(); fapGm_After(); } + +u8 mSaveBuffer[QUEST_LOG_SIZE * 3]; +u8 mAutoSaveProc = 0; +int autoSaveWriteState = 0; + +typedef void (*AutoSaveFuncs)(); +static AutoSaveFuncs AutoSaveFuncsProc[] = { + noAutoSave, + enterAutoSave, + autoSaving, + waitingForWrite, + endAutoSave, +}; + +void noAutoSave() {} + +void triggerAutoSave() { + if (mAutoSaveProc == 0 && strcmp(dComIfGp_getStartStageName(), "F_SP102") != 0 && dComIfGp_getStartStageLayer() != 0) + { + mAutoSaveProc = 1; + } +} + +void updateAutoSave() { + (AutoSaveFuncsProc[mAutoSaveProc])(); +} + +void writeAutoSave() { + int stageNo = dStage_stagInfo_GetSaveTbl(dComIfGp_getStageStagInfo()); + + dComIfGs_putSave(stageNo); + dComIfGs_setMemoryToCard(mSaveBuffer, dComIfGs_getDataNum()); + mDoMemCdRWm_SetCheckSumGameData(mSaveBuffer, dComIfGs_getDataNum()); + + u8* save = mSaveBuffer; + for (int i = 0; i < 3; i++) { + mDoMemCdRWm_TestCheckSumGameData(save); + save += QUEST_LOG_SIZE; + } + + g_mDoMemCd_control.save(mSaveBuffer, sizeof(mSaveBuffer), 0); +} + +void autoSaving() { + int cardState = g_mDoMemCd_control.LoadSync(mSaveBuffer, sizeof(mSaveBuffer), 0); + if (cardState != 0) { + if (cardState == 2) { + mAutoSaveProc = 1; + } else if (cardState == 1) { + writeAutoSave(); + mAutoSaveProc = 3; + } + } +} + +void enterAutoSave() { + u32 cardStatus = g_mDoMemCd_control.getStatus(0); + + if (cardStatus != 14) { + switch (cardStatus) { + case 2: + g_mDoMemCd_control.load(); + mAutoSaveProc = 2; + break; + case 3: + case 4: + case 5: + break; + default: + mAutoSaveProc = 0; + break; + } + } +} + +void waitingForWrite() { + autoSaveWriteState = g_mDoMemCd_control.SaveSync(); + + if (autoSaveWriteState == 2) { + mAutoSaveProc = 0; + } else if (autoSaveWriteState == 1) { + mAutoSaveProc = 4; + } +} + +void endAutoSave() { + dusk::g_imguiConsole.ShowToast("Saving...", 3.0f); + mAutoSaveProc = 0; +} #endif void fapGm_Execute() { @@ -747,6 +844,8 @@ void fapGm_Execute() { #endif #if TARGET_PC + updateAutoSave(); + if (mDoCPd_c::getHoldR(PAD_1) && mDoCPd_c::getTrigX(PAD_1)) { if (const auto link = g_dComIfG_gameInfo.play.getPlayer(0)) { dynamic_cast(link)->handleWolfHowl(); @@ -775,6 +874,7 @@ void fapGm_Execute() { #else fpcM_ManagementFunc(NULL, fapGm_After); #endif + cCt_Counter(0); } From 39d951d0cb7523c6a7c7d920d24797e74803a374 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Thu, 16 Apr 2026 19:50:20 -0400 Subject: [PATCH 004/390] scene saving now works --- src/d/d_menu_save.cpp | 3 --- src/d/d_stage.cpp | 4 ++++ src/f_ap/f_ap_game.cpp | 2 -- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/d/d_menu_save.cpp b/src/d/d_menu_save.cpp index 618677866b..cbff78c659 100644 --- a/src/d/d_menu_save.cpp +++ b/src/d/d_menu_save.cpp @@ -1326,9 +1326,6 @@ void dMenu_save_c::memCardDataLoadWait() { } void dMenu_save_c::dataWrite() { - int stageNo = dStage_stagInfo_GetSaveTbl(dComIfGp_getStageStagInfo()); - - dComIfGs_putSave(stageNo); dComIfGs_setMemoryToCard(mSaveBuffer, mSelectedFile); mDoMemCdRWm_SetCheckSumGameData(mSaveBuffer, mSelectedFile); diff --git a/src/d/d_stage.cpp b/src/d/d_stage.cpp index f3cdfed17b..c84616873a 100644 --- a/src/d/d_stage.cpp +++ b/src/d/d_stage.cpp @@ -326,6 +326,10 @@ int dStage_roomControl_c::loadRoom(int roomCount, u8* rooms, bool param_2) { if (!r26) { return FALSE; } + + #if TARGET_PC + triggerAutoSave(); + #endif for (int i = 0; i < roomCount; i++) { int roomNo = dStage_roomRead_dt_c_GetLoadRoomIndex(rooms[i]); diff --git a/src/f_ap/f_ap_game.cpp b/src/f_ap/f_ap_game.cpp index 2ee6dd5e40..9aa1763b8a 100644 --- a/src/f_ap/f_ap_game.cpp +++ b/src/f_ap/f_ap_game.cpp @@ -28,9 +28,7 @@ #include #include #include -#include #endif -#include fapGm_HIO_c::fapGm_HIO_c() { mUsingHostIO = true; From 842210e5395adf9371b83b5d0f4eba0601a56072 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Thu, 16 Apr 2026 19:56:04 -0400 Subject: [PATCH 005/390] remove scene autosave cause that's buggy atm --- src/d/d_s_play.cpp | 3 --- src/d/d_stage.cpp | 4 ---- 2 files changed, 7 deletions(-) diff --git a/src/d/d_s_play.cpp b/src/d/d_s_play.cpp index ec8ea8f70a..3f3cd073b9 100644 --- a/src/d/d_s_play.cpp +++ b/src/d/d_s_play.cpp @@ -1499,9 +1499,6 @@ static int phase_4(dScnPly_c* i_this) { } if (preLoadNo < 0) { - #if TARGET_PC - triggerAutoSave(); - #endif return cPhs_COMPLEATE_e; } diff --git a/src/d/d_stage.cpp b/src/d/d_stage.cpp index c84616873a..f3cdfed17b 100644 --- a/src/d/d_stage.cpp +++ b/src/d/d_stage.cpp @@ -326,10 +326,6 @@ int dStage_roomControl_c::loadRoom(int roomCount, u8* rooms, bool param_2) { if (!r26) { return FALSE; } - - #if TARGET_PC - triggerAutoSave(); - #endif for (int i = 0; i < roomCount; i++) { int roomNo = dStage_roomRead_dt_c_GetLoadRoomIndex(rooms[i]); From d9a0ef760fc7865814134059705f964425a36dd1 Mon Sep 17 00:00:00 2001 From: TakaRikka Date: Thu, 16 Apr 2026 19:46:02 -0700 Subject: [PATCH 006/390] fix icon positions --- src/d/d_menu_map_common.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/d/d_menu_map_common.cpp b/src/d/d_menu_map_common.cpp index e7d0fef7ad..0017975c4e 100644 --- a/src/d/d_menu_map_common.cpp +++ b/src/d/d_menu_map_common.cpp @@ -343,6 +343,11 @@ void dMenuMapCommon_c::drawIcon(f32 i_posX, f32 i_posY, f32 param_3, f32 param_4 } f32 pos_x = icon_pos_x + i_posX; + #if TARGET_PC + if (dusk::getSettings().game.enableMirrorMode) { + pos_x = getMirrorCenterPosX(pos_x, 0.0f); + } + #endif mpDrawCursor->setPos(pos_x, icon_pos_y + i_posY); mpDrawCursor->setScale(mIconInfo[info_idx].scale * g_fmapHIO.mMapIconHIO.mPortalCursorScale); mpDrawCursor->draw(); @@ -364,6 +369,12 @@ void dMenuMapCommon_c::drawIcon(f32 i_posX, f32 i_posY, f32 param_3, f32 param_4 } f32 pos_x = (icon_pos_x + i_posX); + #if TARGET_PC + if (dusk::getSettings().game.enableMirrorMode) { + pos_x = getMirrorCenterPosX(pos_x, 0.0f); + } + #endif + mpPortalIcon->setPos(pos_x, icon_pos_y + i_posY); mpPortalIcon->setScale(mIconInfo[info_idx].scale * g_fmapHIO.mMapIconHIO.mPortalIconScale); mpPortalIcon->draw(); @@ -399,6 +410,12 @@ void dMenuMapCommon_c::drawIcon(f32 i_posX, f32 i_posY, f32 param_3, f32 param_4 } f32 pos_x = i_posX + (icon_pos_x - (icon_size_x / 2)); + #if TARGET_PC + if (dusk::getSettings().game.enableMirrorMode) { + pos_x = getMirrorCenterPosX(i_posX + (icon_pos_x - (icon_size_x / 2)), icon_size_x / 2); + } + #endif + mPictures[mIconInfo[info_idx].icon_no]->draw(pos_x, (i_posY + (icon_pos_y - icon_size_y / 2)), icon_size_x, icon_size_y, false, false, false); From 8c5673d9b8dcb87448902183006f791d3cc0f93b Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Fri, 17 Apr 2026 13:12:20 -0400 Subject: [PATCH 007/390] autosave when loading scene --- src/d/d_s_play.cpp | 16 ++++++++++++++++ src/f_ap/f_ap_game.cpp | 3 --- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/d/d_s_play.cpp b/src/d/d_s_play.cpp index 3f3cd073b9..9af875b2f5 100644 --- a/src/d/d_s_play.cpp +++ b/src/d/d_s_play.cpp @@ -700,6 +700,10 @@ static u8 lbl_8074CAE4; static u32 l_sceneChangeStartTick; #endif +#if TARGET_PC +static BOOL shouldAutoSave; +#endif + static int dScnPly_Execute(dScnPly_c* i_this) { #if DEBUG fapGm_HIO_c::startCpuTimer(); @@ -742,6 +746,13 @@ static int dScnPly_Execute(dScnPly_c* i_this) { } } + #if TARGET_PC + if (!fopOvlpM_IsPeek() && !dComIfG_resetToOpening(i_this) && !dComIfGp_isEnableNextStage() && shouldAutoSave == FALSE) { + triggerAutoSave(); + shouldAutoSave = TRUE; + } + #endif + dKy_itudemo_se(); #if DEBUG @@ -1598,6 +1609,11 @@ static int dScnPly_Create(scene_class* i_this) { dScnPly_c* a_this = (dScnPly_c*)i_this; int phase_state = dComLbG_PhaseHandler(&a_this->field_0x1c4, l_method, a_this); + + #if TARGET_PC + shouldAutoSave = FALSE; + #endif + return phase_state; } diff --git a/src/f_ap/f_ap_game.cpp b/src/f_ap/f_ap_game.cpp index 9aa1763b8a..3dc192b665 100644 --- a/src/f_ap/f_ap_game.cpp +++ b/src/f_ap/f_ap_game.cpp @@ -766,9 +766,6 @@ void updateAutoSave() { } void writeAutoSave() { - int stageNo = dStage_stagInfo_GetSaveTbl(dComIfGp_getStageStagInfo()); - - dComIfGs_putSave(stageNo); dComIfGs_setMemoryToCard(mSaveBuffer, dComIfGs_getDataNum()); mDoMemCdRWm_SetCheckSumGameData(mSaveBuffer, dComIfGs_getDataNum()); From 8afb1141abd220791159c69aa94fe8af82c3304a Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Fri, 17 Apr 2026 13:41:56 -0400 Subject: [PATCH 008/390] Autosave when changing rooms --- src/d/d_save.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/d/d_save.cpp b/src/d/d_save.cpp index 71f65b61e6..c872cb0f17 100644 --- a/src/d/d_save.cpp +++ b/src/d/d_save.cpp @@ -1482,6 +1482,9 @@ void dSv_restart_c::setRoom(const cXyz& i_position, s16 i_angleY, s8 i_roomNo) { mRoomNo = i_roomNo; mRoomPos = i_position; mRoomAngleY = i_angleY; + #if TARGET_PC + triggerAutoSave(); + #endif } void dSv_turnRestart_c::set(const cXyz& i_position, s16 i_angleY, s8 param_3, u32 i_param) { From c157564da6dd3b45b2738cf721fad9c7c31212ab Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Mon, 20 Apr 2026 13:02:25 -0400 Subject: [PATCH 009/390] dungeon doors now autosave --- src/d/actor/d_a_door_shutter.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/d/actor/d_a_door_shutter.cpp b/src/d/actor/d_a_door_shutter.cpp index a481762132..d416d0b2bc 100644 --- a/src/d/actor/d_a_door_shutter.cpp +++ b/src/d/actor/d_a_door_shutter.cpp @@ -17,6 +17,10 @@ #include #include +#if TARGET_PC +#include +#endif + char* daDoor20_c::getStopBmdName() { switch (door_param2_c::getKind(this)) { case 3: @@ -196,6 +200,7 @@ void daDoor20_c::setEventPrm() { } else { roomNo = FRoomNo; } + if (dComIfGp_roomControl_checkStatusFlag(roomNo, 1)) { if (door_param2_c::getKind(this) == 9) { if (daPy_py_c::checkNowWolf()) { @@ -564,6 +569,11 @@ int daDoor20_c::openEnd(int param_1) { openEnd_1(); break; } + + #if TARGET_PC + triggerAutoSave(); + #endif + return 1; } From 871d18e294168d55f78f46b4cc0e95164dc482af Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Mon, 20 Apr 2026 13:15:37 -0400 Subject: [PATCH 010/390] added experimental setting for autosave --- include/dusk/settings.h | 1 + src/dusk/imgui/ImGuiFirstRunPreset.cpp | 1 + src/dusk/imgui/ImGuiMenuEnhancements.cpp | 12 ++++++++++++ src/dusk/settings.cpp | 22 ++++++++++++---------- src/f_ap/f_ap_game.cpp | 2 +- 5 files changed, 27 insertions(+), 11 deletions(-) diff --git a/include/dusk/settings.h b/include/dusk/settings.h index 03749967c9..31058a7cdd 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -63,6 +63,7 @@ struct UserSettings { ConfigVar instantSaves; ConfigVar instantText; ConfigVar sunsSong; + ConfigVar autoSave; // Preferences ConfigVar enableMirrorMode; diff --git a/src/dusk/imgui/ImGuiFirstRunPreset.cpp b/src/dusk/imgui/ImGuiFirstRunPreset.cpp index fb2d181562..d3f5441d94 100644 --- a/src/dusk/imgui/ImGuiFirstRunPreset.cpp +++ b/src/dusk/imgui/ImGuiFirstRunPreset.cpp @@ -41,6 +41,7 @@ static void ApplyPresetDusk() { s.game.enableFrameInterpolation.setValue(true); s.game.sunsSong.setValue(true); s.game.bloomMode.setValue(BloomMode::Dusk); + s.game.autoSave.setValue(true); } // ========================================================================= diff --git a/src/dusk/imgui/ImGuiMenuEnhancements.cpp b/src/dusk/imgui/ImGuiMenuEnhancements.cpp index 7d179aa578..e469a830df 100644 --- a/src/dusk/imgui/ImGuiMenuEnhancements.cpp +++ b/src/dusk/imgui/ImGuiMenuEnhancements.cpp @@ -65,6 +65,18 @@ namespace dusk { ImGui::SetTooltip("Skip the delay when writing to the Memory Card."); } + config::ImGuiCheckbox("Autosave", getSettings().game.autoSave); + const bool autoSaveHovered = ImGui::IsItemHovered(); + ImGui::SameLine(); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.72f, 0.2f, 1.0f)); + ImGui::TextUnformatted("[EXPERIMENTAL]"); + ImGui::PopStyleColor(); + if (autoSaveHovered || ImGui::IsItemHovered()) { + ImGui::SetTooltip( + "Automatically saves the game when going to new areas,\n" + "getting an item, or opening a dungeon door."); + } + config::ImGuiCheckbox("Hold B for Instant Text", getSettings().game.instantText); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Make text scroll immediately by holding B."); diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index 2bcdbe2185..9e6ae0f5d5 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -29,7 +29,7 @@ UserSettings g_userSettings = { .disableRupeeCutscenes {"game.disableRupeeCutscenes", false}, .noSwordRecoil {"game.noSwordRecoil", false}, .damageMultiplier {"game.damageMultiplier", 1}, - .noHeartDrops{"game.noHeartDrops", false}, + .noHeartDrops {"game.noHeartDrops", false}, .instantDeath {"game.instantDeath", false}, .fastClimbing {"game.fastClimbing", false}, .noMissClimbing {"game.noMissClimbing", false}, @@ -37,6 +37,7 @@ UserSettings g_userSettings = { .instantSaves {"game.instantSaves", false}, .instantText {"game.instantText", false}, .sunsSong {"game.sunsSong", false}, + .autoSave {"game.autoSave", false}, // Preferences .enableMirrorMode {"game.enableMirrorMode", false}, @@ -48,7 +49,7 @@ UserSettings g_userSettings = { .bloomMode {"game.bloomMode", BloomMode::Classic}, .bloomMultiplier {"game.bloomMultiplier", 1.0f}, .disableWaterRefraction {"game.disableWaterRefraction", false}, - .enableFrameInterpolation = {"game.enableFrameInterpolation", false}, + .enableFrameInterpolation {"game.enableFrameInterpolation", false}, .internalResolutionScale {"game.internalResolutionScale", 0}, .shadowResolutionMultiplier {"game.shadowResolutionMultiplier", 1}, @@ -69,14 +70,14 @@ UserSettings g_userSettings = { // Cheats .infiniteHearts {"game.infiniteHearts", false}, - .infiniteArrows{"game.infiniteArrows", false}, - .infiniteBombs{"game.infiniteBombs", false}, - .infiniteOil{"game.infiniteOil", false}, - .infiniteOxygen{"game.infiniteOxygen", false}, - .infiniteRupees{"game.infiniteRupees", false}, - .moonJump{"game.moonJump", false}, - .superClawshot{"game.superClawshot", false}, - .alwaysGreatspin{"game.alwaysGreatspin", false}, + .infiniteArrows {"game.infiniteArrows", false}, + .infiniteBombs {"game.infiniteBombs", false}, + .infiniteOil {"game.infiniteOil", false}, + .infiniteOxygen {"game.infiniteOxygen", false}, + .infiniteRupees {"game.infiniteRupees", false}, + .moonJump {"game.moonJump", false}, + .superClawshot {"game.superClawshot", false}, + .alwaysGreatspin {"game.alwaysGreatspin", false}, .enableFastIronBoots {"game.enableFastIronBoots", false}, .canTransformAnywhere {"game.canTransformAnywhere", false}, .fastSpinner {"game.fastSpinner", false}, @@ -134,6 +135,7 @@ void registerSettings() { Register(g_userSettings.game.instantSaves); Register(g_userSettings.game.instantText); Register(g_userSettings.game.sunsSong); + Register(g_userSettings.game.autoSave); Register(g_userSettings.game.enableMirrorMode); Register(g_userSettings.game.invertCameraXAxis); Register(g_userSettings.game.disableMainHUD); diff --git a/src/f_ap/f_ap_game.cpp b/src/f_ap/f_ap_game.cpp index d66c6fbbe1..4a4c37fd7b 100644 --- a/src/f_ap/f_ap_game.cpp +++ b/src/f_ap/f_ap_game.cpp @@ -755,7 +755,7 @@ static AutoSaveFuncs AutoSaveFuncsProc[] = { void noAutoSave() {} void triggerAutoSave() { - if (mAutoSaveProc == 0 && strcmp(dComIfGp_getStartStageName(), "F_SP102") != 0 && dComIfGp_getStartStageLayer() != 0) + if (dusk::getSettings().game.autoSave && mAutoSaveProc == 0 && strcmp(dComIfGp_getStartStageName(), "F_SP102") != 0 && dComIfGp_getStartStageLayer() != 0) { mAutoSaveProc = 1; } From 746910c59f466ae1a0614d2ee8879af886986ca8 Mon Sep 17 00:00:00 2001 From: Irastris Date: Fri, 24 Apr 2026 05:13:31 -0400 Subject: [PATCH 011/390] Register interp callback for d_a_obj_item Fixes rupee color changes --- src/d/actor/d_a_obj_item.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/d/actor/d_a_obj_item.cpp b/src/d/actor/d_a_obj_item.cpp index 6c7e82ab3e..e45de1933d 100644 --- a/src/d/actor/d_a_obj_item.cpp +++ b/src/d/actor/d_a_obj_item.cpp @@ -16,6 +16,10 @@ #include "f_op/f_op_camera_mng.h" #include "m_Do/m_Do_mtx.h" +#if TARGET_PC +#include "dusk/frame_interpolation.h" +#endif + static f32 Reflect(cXyz* i_vec, cBgS_PolyInfo const& i_polyinfo, f32 i_scale) { cM3dGPla plane; @@ -31,6 +35,27 @@ static f32 Reflect(cXyz* i_vec, cBgS_PolyInfo const& i_polyinfo, f32 i_scale) { return 0.0f; } +#if TARGET_PC +static void d_a_obj_item_interp_callback(bool isSimFrame, void* pUserWork) { + daItem_c* item = static_cast(pUserWork); + if (item == NULL || item->mpModel == NULL || !item->chkDraw()) { + return; + } + item->setTevStr(); + if (item->mpBrkAnm != NULL) { + s8 tevFrm = item->getTevFrm(); + if (tevFrm != -1) { + item->mpBrkAnm->entry(item->mpModel->getModelData(), tevFrm); + } else { + item->mpBrkAnm->entry(item->mpModel->getModelData()); + } + } + if (item->chkFlag(4)) { + fopAcM_setEffectMtx(item, item->mpModel->getModelData()); + } +} +#endif + const daItemBase_data& daItemBase_c::getData() { return m_data; } @@ -353,6 +378,10 @@ int daItem_c::_daItem_draw() { return 1; } +#if TARGET_PC + dusk::frame_interp::add_interpolation_callback(&d_a_obj_item_interp_callback, this); +#endif + if (chkDraw()) { return DrawBase(); } From 109f0a50e524bd165749077bcd5694eebe9efae6 Mon Sep 17 00:00:00 2001 From: madeline Date: Fri, 24 Apr 2026 03:37:35 -0700 Subject: [PATCH 012/390] fix sun song again --- src/Z2AudioLib/Z2WolfHowlMgr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Z2AudioLib/Z2WolfHowlMgr.cpp b/src/Z2AudioLib/Z2WolfHowlMgr.cpp index 4866af7a5d..f12d453fbe 100644 --- a/src/Z2AudioLib/Z2WolfHowlMgr.cpp +++ b/src/Z2AudioLib/Z2WolfHowlMgr.cpp @@ -369,7 +369,7 @@ void Z2WolfHowlMgr::setCorrectData(s8 curveID, Z2WolfHowlData* data) { #if TARGET_PC case Z2WOLFHOWL_TIMESONG: cPitchUp = 1.3348f; - cPitchCenter = 1.0f; + cPitchCenter = 0.8909f; cPitchDown = 0.7937f; break; #endif From 5fab665f21baabfc96025918cab29bc08806b0eb Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Fri, 24 Apr 2026 15:25:14 +0200 Subject: [PATCH 013/390] Don't allocate giant unused stacks for movie player How to save 800 KiB of commit charge easy --- src/d/actor/d_a_movie_player.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/d/actor/d_a_movie_player.cpp b/src/d/actor/d_a_movie_player.cpp index 079584f714..1f8bdeecd7 100644 --- a/src/d/actor/d_a_movie_player.cpp +++ b/src/d/actor/d_a_movie_player.cpp @@ -2855,7 +2855,7 @@ void* daMP_Reader(void*) { #endif } -static u8 daMP_ReadThreadStack[0x2000]; +static u8 daMP_ReadThreadStack[DUSK_IF_ELSE(8, 0x2000)]; #if TARGET_PC static BOOL VideoThreadCancelled; @@ -2880,7 +2880,7 @@ static BOOL daMP_CreateReadThread(s32 param_0) { static OSThread daMP_VideoDecodeThread; -static u8 daMP_VideoDecodeThreadStack[0x64000]; +static u8 daMP_VideoDecodeThreadStack[DUSK_IF_ELSE(8, 0x64000)]; static OSMessageQueue daMP_FreeTextureSetQueue; @@ -3132,7 +3132,7 @@ static BOOL AudioThreadCancelled; static OSThread daMP_AudioDecodeThread; -static u8 daMP_AudioDecodeThreadStack[0x64000]; +static u8 daMP_AudioDecodeThreadStack[DUSK_IF_ELSE(8, 0x64000)]; static OSMessageQueue daMP_FreeAudioBufferQueue; From 35ea13c53a4ef4263ec712df599708649773e540 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Fri, 24 Apr 2026 12:25:15 -0600 Subject: [PATCH 014/390] Update aurora --- extern/aurora | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/aurora b/extern/aurora index be1395c134..9ff83bcb97 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit be1395c1343a5587cceea25754daa5cacce34f76 +Subproject commit 9ff83bcb9718391a25c3c5ffa1faf470effb1c86 From 1fea4f02ed556b798eb7fcbfced02b7c3a2ec423 Mon Sep 17 00:00:00 2001 From: Irastris Date: Fri, 24 Apr 2026 14:26:52 -0400 Subject: [PATCH 015/390] Fix camera bouncing with interp enabled --- src/dusk/frame_interpolation.cpp | 38 ++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/src/dusk/frame_interpolation.cpp b/src/dusk/frame_interpolation.cpp index f3f8a842e1..941c9ed318 100644 --- a/src/dusk/frame_interpolation.cpp +++ b/src/dusk/frame_interpolation.cpp @@ -292,12 +292,20 @@ void interp_view(::view_class* view) { return; const f32 step = get_interpolation_step(); + const bool is_cam_curr_authoritative = g_is_sim_frame && step <= 0.0f; + cXyz eye; cXyz center; cXyz up; - lerp_xyz(&eye, s_cam_prev.eye, s_cam_curr.eye, step); - lerp_xyz(¢er, s_cam_prev.center, s_cam_curr.center, step); - lerp_xyz(&up, s_cam_prev.up, s_cam_curr.up, step); + if (is_cam_curr_authoritative) { + eye = s_cam_curr.eye; + center = s_cam_curr.center; + up = s_cam_curr.up; + } else { + lerp_xyz(&eye, s_cam_prev.eye, s_cam_curr.eye, step); + lerp_xyz(¢er, s_cam_prev.center, s_cam_curr.center, step); + lerp_xyz(&up, s_cam_prev.up, s_cam_curr.up, step); + } if (!up.normalizeRS()) { up = s_cam_curr.up; up.normalizeRS(); @@ -306,19 +314,25 @@ void interp_view(::view_class* view) { view->lookat.eye = eye; view->lookat.center = center; view->lookat.up = up; - view->bank = lerp_bank(s_cam_prev.bank, s_cam_curr.bank, step); - view->fovy = s_cam_prev.fovy + (s_cam_curr.fovy - s_cam_prev.fovy) * step; - view->aspect = s_cam_prev.aspect + (s_cam_curr.aspect - s_cam_prev.aspect) * step; - view->near_ = s_cam_prev.near_ + (s_cam_curr.near_ - s_cam_prev.near_) * step; - view->far_ = s_cam_prev.far_ + (s_cam_curr.far_ - s_cam_prev.far_) * step; + if (is_cam_curr_authoritative) { + view->bank = s_cam_curr.bank; + view->fovy = s_cam_curr.fovy; + view->aspect = s_cam_curr.aspect; + view->near_ = s_cam_curr.near_; + view->far_ = s_cam_curr.far_; + } else { + view->bank = lerp_bank(s_cam_prev.bank, s_cam_curr.bank, step); + view->fovy = s_cam_prev.fovy + (s_cam_curr.fovy - s_cam_prev.fovy) * step; + view->aspect = s_cam_prev.aspect + (s_cam_curr.aspect - s_cam_prev.aspect) * step; + view->near_ = s_cam_prev.near_ + (s_cam_curr.near_ - s_cam_prev.near_) * step; + view->far_ = s_cam_prev.far_ + (s_cam_curr.far_ - s_cam_prev.far_) * step; + } // FRAME INTERP TODO: It might be better if I rewired the game to not clear this flag until the // next sim frame, but I don't care enough to right now #if WIDESCREEN_SUPPORT - if (mDoGph_gInf_c::isWide() && !mDoGph_gInf_c::isWideZoom() && step >= 0.5f ? - s_cam_curr.wideZoom : - s_cam_prev.wideZoom) - { + const f32 wide_step = is_cam_curr_authoritative ? 1.0f : step; + if (mDoGph_gInf_c::isWide() && !mDoGph_gInf_c::isWideZoom() && wide_step >= 0.5f ? s_cam_curr.wideZoom : s_cam_prev.wideZoom) { mDoGph_gInf_c::onWideZoom(); } #endif From f0e8379fa52cf9ccd608a21582408f0e4bc55a5a Mon Sep 17 00:00:00 2001 From: Luke Street Date: Fri, 24 Apr 2026 13:19:09 -0600 Subject: [PATCH 016/390] Fix UaF in d_a_mirror Resolves #505 --- src/d/actor/d_a_mirror.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/d/actor/d_a_mirror.cpp b/src/d/actor/d_a_mirror.cpp index fb4142c0bb..746f32a9f6 100644 --- a/src/d/actor/d_a_mirror.cpp +++ b/src/d/actor/d_a_mirror.cpp @@ -599,6 +599,13 @@ int daMirror_c::execute() { return 1; } +#if TARGET_PC + if (mPacket.mbReset) { + mPacket.mModelCount = 0; + mPacket.mbReset = false; + } +#endif + daPy_py_c* player = daPy_getLinkPlayerActorClass(); JUT_ASSERT(0, player != NULL); From b2c09d56d6551d74f6b6654098f24b1afd03d1a7 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Fri, 24 Apr 2026 13:34:51 -0600 Subject: [PATCH 017/390] Remove unnecessary logic from dMirror_packet_c::entryModel --- src/d/actor/d_a_mirror.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/d/actor/d_a_mirror.cpp b/src/d/actor/d_a_mirror.cpp index 746f32a9f6..86ef4314f3 100644 --- a/src/d/actor/d_a_mirror.cpp +++ b/src/d/actor/d_a_mirror.cpp @@ -84,13 +84,6 @@ void dMirror_packet_c::calcMinMax() { } int dMirror_packet_c::entryModel(J3DModel* i_model) { -#if TARGET_PC - if (mbReset) { - mModelCount = 0; - mbReset = false; - } -#endif - if (mModelCount >= 0x40) { return 0; } From 171dbdd0a14b46b5baebfd3f6ad929547a0cce92 Mon Sep 17 00:00:00 2001 From: roeming Date: Fri, 24 Apr 2026 16:50:31 -0400 Subject: [PATCH 018/390] Implement custom sorting when sorting event flags by flag on/off --- src/dusk/imgui/ImGuiSaveEditor.cpp | 96 +++++++++++++++++++++++------- 1 file changed, 76 insertions(+), 20 deletions(-) diff --git a/src/dusk/imgui/ImGuiSaveEditor.cpp b/src/dusk/imgui/ImGuiSaveEditor.cpp index eced44c7f7..cc89d37275 100644 --- a/src/dusk/imgui/ImGuiSaveEditor.cpp +++ b/src/dusk/imgui/ImGuiSaveEditor.cpp @@ -1347,6 +1347,51 @@ namespace dusk { } } + template + concept FlagIter = requires(T t) { + ++t; + --t; + t + 1; + t < t; + { t->flagID } -> std::convertible_to; + }; + + template + concept FlagTester = requires(T t, u16 flagID) { + { t(flagID) } -> std::convertible_to; + }; + + static void sortByFlags(FlagIter auto begin, FlagIter auto end, FlagTester auto&& flagTester) { + if (begin == end) return; + + FlagIter auto fullEnd = end; + + // We want to find the location of where we can swap our `On` flags to. + // We're gonna put the `Off` bits first, and the `On` bits last. 0 < 1 + // We can achieve this by skipping all the `On` bits at the end. + + // backtrack until we find a bit that is off + while (begin < --end && flagTester(end->flagID)) { + // move the end pointer back while we find on bits + } + + // end should now be pointing to a bit that is off + while (begin < end) { + // if there's a flag that's on + if (flagTester(begin->flagID)) { + // move it to the end + std::rotate(begin, begin + 1, fullEnd); + // move back the end of where we're checking + --end; + // begin will now point to the next piece of data + // because we've rotated the data >= begin to the left + } else { + // not on, check next flag + ++begin; + } + } + } + void ImGuiSaveEditor::drawFlagsTab() { if (ImGui::TreeNode("Current Region Flags")) { dSv_memBit_c& membit = g_dComIfG_gameInfo.info.mMemory.mBit; @@ -1446,30 +1491,41 @@ namespace dusk { sort != nullptr && sort->SpecsCount > 0 && (sort->SpecsDirty || sort->Specs[0].ColumnIndex == COLUMN_FLAG)) { - auto column = sort->Specs->ColumnIndex; - const auto cmp = [&](const duskImguiEventFlagEntry& l, - const duskImguiEventFlagEntry& r) -> bool { - switch (column) { - case COLUMN_FLAG: - return (bool)event.isEventBit(l.flagID) < - (bool)event.isEventBit(r.flagID); - case COLUMN_NAME: - return l.flagName < r.flagName; - case COLUMN_LOC: - return l.location < r.location; - case COLUMN_DESC: - return l.description < r.description; - } - return false; - }; - + const auto column = sort->Specs[0].ColumnIndex; const auto direction = sort->Specs[0].SortDirection; - if (direction == ImGuiSortDirection_Ascending) { - std::sort(std::begin(duskImguiEventFlags), std::end(duskImguiEventFlags), cmp); + // if we're sorting by flags, do special sort, regular sort is bad for sorting bools + // it can swap values that are the same, and that causes constant reordering + if (column == COLUMN_FLAG) { + const auto testEventFunc = [&event](u16 flag) -> bool { return event.isEventBit(flag); }; + + if (direction == ImGuiSortDirection_Ascending) { + sortByFlags(std::begin(duskImguiEventFlags), + std::end(duskImguiEventFlags), testEventFunc); + } else { + sortByFlags(std::rbegin(duskImguiEventFlags), + std::rend(duskImguiEventFlags), testEventFunc); + } } else { - std::sort(std::rbegin(duskImguiEventFlags), std::rend(duskImguiEventFlags), cmp); + const auto cmp = [column](const duskImguiEventFlagEntry& l, + const duskImguiEventFlagEntry& r) -> bool { + switch (column) { + case COLUMN_NAME: return l.flagName < r.flagName; + case COLUMN_LOC: return l.location < r.location; + case COLUMN_DESC: return l.description < r.description; + default: return false; + } + }; + + if (direction == ImGuiSortDirection_Ascending) { + std::sort(std::begin(duskImguiEventFlags), + std::end(duskImguiEventFlags), cmp); + } else { + std::sort(std::rbegin(duskImguiEventFlags), + std::rend(duskImguiEventFlags), cmp); + } } + sort->SpecsDirty = false; } From d5aabe9f9ed2a13d275413cca114bf4b99c929b1 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Fri, 24 Apr 2026 18:06:02 -0400 Subject: [PATCH 019/390] Even faster tears to match TPHD --- src/d/actor/d_a_obj_drop.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/d/actor/d_a_obj_drop.cpp b/src/d/actor/d_a_obj_drop.cpp index 275a3d6e12..2b373c1e64 100644 --- a/src/d/actor/d_a_obj_drop.cpp +++ b/src/d/actor/d_a_obj_drop.cpp @@ -265,7 +265,7 @@ int daObjDrop_c::modeParentWait() { mModeAction = 1; #if TARGET_PC - mModeTimer = dusk::getSettings().game.fastTears && dComIfGp_event_getMode() == 0 ? 20 : 40; + mModeTimer = dusk::getSettings().game.fastTears && dComIfGp_event_getMode() == 0 ? 0 : 40; if (dusk::getSettings().game.fastTears && dComIfGp_event_getMode() == 0) { current.pos.y += 100.0f; } else { @@ -285,7 +285,7 @@ int daObjDrop_c::modeParentWait() { case 2: createBodyEffect(); #if TARGET_PC - mModeTimer = dusk::getSettings().game.fastTears && dComIfGp_event_getMode() == 0 ? 5 : 45; + mModeTimer = dusk::getSettings().game.fastTears && dComIfGp_event_getMode() == 0 ? 0 : 45; #else mModeTimer = 45; #endif From 274bf61b3ea216ec4f3e0db0610d8858e9d9420e Mon Sep 17 00:00:00 2001 From: Irastris Date: Fri, 24 Apr 2026 22:56:47 -0400 Subject: [PATCH 020/390] Fix Link's hands detaching when interp is enabled --- src/d/actor/d_a_alink.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/d/actor/d_a_alink.cpp b/src/d/actor/d_a_alink.cpp index e6943baf96..4fea05cd53 100644 --- a/src/d/actor/d_a_alink.cpp +++ b/src/d/actor/d_a_alink.cpp @@ -18936,11 +18936,20 @@ void daAlink_c::setDrawHand() { mpLinkHandModel->setBaseTRMtx(mpLinkModel->getBaseTRMtx()); mpLinkHandModel->calc(); +#if TARGET_PC + // FRAME INTERP NOTE: Always set these, otherwise the hands occasionally zip to origin. + // Doing it regardless of interpolation being active seems harmless. + mpLinkHandModel->setAnmMtx(1, mpLinkModel->getAnmMtx(9)); + mpLinkHandModel->setAnmMtx(2, mpLinkModel->getAnmMtx(0xE)); +#endif + if (var_r30 == 0xFE || var_r30 == 0xFB) { field_0x06d0 = field_0x06d8; } else { field_0x06d0 = mpLinkHandModel->getModelData()->getMaterialNodePointer(var_r30)->getShape(); +#if !TARGET_PC mpLinkHandModel->setAnmMtx(1, mpLinkModel->getAnmMtx(9)); +#endif } if (var_r30 == 0xFB) { @@ -18959,7 +18968,9 @@ void daAlink_c::setDrawHand() { field_0x06d4 = field_0x06dc; } else { field_0x06d4 = mpLinkHandModel->getModelData()->getMaterialNodePointer(var_r29)->getShape(); +#if !TARGET_PC mpLinkHandModel->setAnmMtx(2, mpLinkModel->getAnmMtx(0xE)); +#endif } if (var_r29 == 0xFB) { From c61e32cd4fd52af7495fc9366fae7c2f86c81384 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Fri, 24 Apr 2026 22:10:56 -0600 Subject: [PATCH 021/390] Update aurora for GXPeekZ Resolves #281 Resolves #468 --- extern/aurora | 2 +- src/dusk/stubs.cpp | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/extern/aurora b/extern/aurora index 9ff83bcb97..8d9618dc4b 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 9ff83bcb9718391a25c3c5ffa1faf470effb1c86 +Subproject commit 8d9618dc4bd82e476754c5b841b85fba6ee6ddab diff --git a/src/dusk/stubs.cpp b/src/dusk/stubs.cpp index 07e420445c..c6832d2cac 100644 --- a/src/dusk/stubs.cpp +++ b/src/dusk/stubs.cpp @@ -1020,10 +1020,6 @@ void GXInitTexCacheRegion(GXTexRegion* region, GXBool is_32b_mipmap, u32 tmem_ev // XXX, this should be some struct? // GXRenderModeObj GXNtsc480IntDf; //GXRenderModeObj GXNtsc480Int; -void GXPeekZ(u16 x, u16 y, u32* z) { - STUB_LOG(); - *z = 0; -} void GXReadXfRasMetric(u32* xf_wait_in, u32* xf_wait_out, u32* ras_busy, u32* clocks) { STUB_LOG(); *xf_wait_in = 0; From c8e89a0f998b88bf464aeabfc3913c4af6675a46 Mon Sep 17 00:00:00 2001 From: Irastris Date: Sat, 25 Apr 2026 00:31:37 -0400 Subject: [PATCH 022/390] Fix grass cutting when interp is enabled --- src/d/d_particle.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/d/d_particle.cpp b/src/d/d_particle.cpp index 248424e9a2..9b89afc7b1 100644 --- a/src/d/d_particle.cpp +++ b/src/d/d_particle.cpp @@ -1972,7 +1972,12 @@ void dPa_light8PcallBack::draw(JPABaseEmitter* param_1, JPABaseParticle* param_2 JGeometry::TVec3 local_154; JGeometry::TVec3 local_160; JGeometry::TVec3 local_16c; - dPa_setWindPower(param_2); +#if TARGET_PC + if (dusk::frame_interp::is_sim_frame()) +#endif + { + dPa_setWindPower(param_2); + } MTXIdentity(local_60); MTXIdentity(auStack_90); param_2->getBaseAxis(&local_10c); From 4e264d6a22d98835d62b3c29cb48376e9a88adaa Mon Sep 17 00:00:00 2001 From: Luke Street Date: Fri, 24 Apr 2026 22:53:41 -0600 Subject: [PATCH 023/390] Fix Zbuffer texture binding Resolves #511 --- src/d/d_resorce.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/d/d_resorce.cpp b/src/d/d_resorce.cpp index 73f031beae..bb982c4afb 100644 --- a/src/d/d_resorce.cpp +++ b/src/d/d_resorce.cpp @@ -102,11 +102,7 @@ static void setIndirectTex(J3DModelData* i_modelData) { texture->setResTIMG(i, *mDoGph_gInf_c::getFrameBufferTimg()); } if (memcmp(textureName, "Zbuffer", 8) == 0) { -#if !TARGET_PC texture->setResTIMG(i, *mDoGph_gInf_c::getZbufferTimg()); -#else - DuskLog.warn("Zbuffer texture binding not yet supported"); -#endif } } } From d7dced7ddfb0205aa3003843183eae9e8a71779a Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Sat, 25 Apr 2026 08:25:50 -0400 Subject: [PATCH 024/390] don't autosave if playing a cutscene --- src/d/d_s_play.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/d/d_s_play.cpp b/src/d/d_s_play.cpp index b549bd073d..1bc02029ec 100644 --- a/src/d/d_s_play.cpp +++ b/src/d/d_s_play.cpp @@ -748,7 +748,9 @@ static int dScnPly_Execute(dScnPly_c* i_this) { } #if TARGET_PC - if (!fopOvlpM_IsPeek() && !dComIfG_resetToOpening(i_this) && !dComIfGp_isEnableNextStage() && shouldAutoSave == FALSE) { + if (!dComIfGp_event_runCheck() && !fopOvlpM_IsPeek() && !dComIfG_resetToOpening(i_this) && + !dComIfGp_isEnableNextStage() && shouldAutoSave == FALSE) + { triggerAutoSave(); shouldAutoSave = TRUE; } From 0bf663141a00f0e1403e50b918acd8eae3f3cba2 Mon Sep 17 00:00:00 2001 From: roeming Date: Sat, 25 Apr 2026 14:39:47 -0400 Subject: [PATCH 025/390] change filter to avoid allocations --- src/dusk/imgui/ImGuiSaveEditor.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/dusk/imgui/ImGuiSaveEditor.cpp b/src/dusk/imgui/ImGuiSaveEditor.cpp index cc89d37275..37e3d96bb7 100644 --- a/src/dusk/imgui/ImGuiSaveEditor.cpp +++ b/src/dusk/imgui/ImGuiSaveEditor.cpp @@ -1530,7 +1530,9 @@ namespace dusk { } for (const auto& e : duskImguiEventFlags) { - if (!filter.PassFilter((e.location + "\n" + e.description + "\n" + e.flagName).c_str())) + if (!filter.PassFilter(e.location.c_str()) && + !filter.PassFilter(e.description.c_str()) && + !filter.PassFilter(e.flagName.c_str())) { continue; } From e755148f1673b23d41016fa58def537b2e3a9ddf Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Sat, 25 Apr 2026 16:59:04 -0400 Subject: [PATCH 026/390] Fix some UBs (#544) Co-authored-by: MelonSpeedruns --- src/d/actor/d_a_alink.cpp | 5 +++++ src/d/actor/d_flower.inc | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/src/d/actor/d_a_alink.cpp b/src/d/actor/d_a_alink.cpp index 4fea05cd53..28c979bab4 100644 --- a/src/d/actor/d_a_alink.cpp +++ b/src/d/actor/d_a_alink.cpp @@ -5877,6 +5877,11 @@ void daAlink_c::setItemMatrix(int param_0) { modelCalc(mSheathModel); int var_r26; + + #if AVOID_UB + var_r26 = 0; + #endif + if (!checkNoResetFlg3(FLG3_UNK_4000000)) { if (mEquipItem == 0x103 || param_0 != 0) { mSwordModel->setBaseTRMtx(mpLinkModel->getAnmMtx(mLeftItemJntNo)); diff --git a/src/d/actor/d_flower.inc b/src/d/actor/d_flower.inc index 58daa354a1..1850e1e1ad 100644 --- a/src/d/actor/d_flower.inc +++ b/src/d/actor/d_flower.inc @@ -789,6 +789,10 @@ void dFlower_packet_c::draw() { GXColor sp28; + #if AVOID_UB + sp28 = {1, 1, 1, 1}; + #endif + //u8 sp26, sp25, sp24; GXColor sp24; sp24.r = -0.4f * temp_r29->AmbCol.r * var_f29; From 60e8836968685bc7fc05460967ca87e07db0b390 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Sat, 25 Apr 2026 16:59:30 -0400 Subject: [PATCH 027/390] Tears Collect during cutscenes (#539) TPHD has tears collectable just as fast during cutscenes, this changes our implementation to reflect that. Co-authored-by: MelonSpeedruns --- src/d/actor/d_a_e_ym.cpp | 6 +++--- src/d/actor/d_a_obj_drop.cpp | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/d/actor/d_a_e_ym.cpp b/src/d/actor/d_a_e_ym.cpp index 758bec6269..3f6bef6788 100644 --- a/src/d/actor/d_a_e_ym.cpp +++ b/src/d/actor/d_a_e_ym.cpp @@ -1069,7 +1069,7 @@ void daE_YM_c::executeDown() { if (mAcch.ChkGroundHit()) { if (mFlyType != 1) { #if TARGET_PC - bckSet(6, 0, 0.0f, dusk::getSettings().game.fastTears && dComIfGp_event_getMode() == 0 ? 2.0f : 1.0f); + bckSet(6, 0, 0.0f, dusk::getSettings().game.fastTears ? 2.0f : 1.0f); #else bckSet(6, 0, 0.0f, 1.0f); #endif @@ -1093,7 +1093,7 @@ void daE_YM_c::executeDown() { mSound.startCreatureSound(Z2SE_CM_BODYFALL_WATER_M, 0, -1); mSound.startCreatureSound(Z2SE_EN_YM_MOGAKU, 0, -1); #if TARGET_PC - bckSet(6, 0, 0.0f, dusk::getSettings().game.fastTears && dComIfGp_event_getMode() == 0 ? 2.0f : 1.0f); + bckSet(6, 0, 0.0f, dusk::getSettings().game.fastTears ? 2.0f : 1.0f); #else bckSet(6, 0, 0.0f, 1.0f); #endif @@ -1115,7 +1115,7 @@ void daE_YM_c::executeDown() { || dComIfG_Bgsp().GetGroundCode(gnd_chk) == 5) { #if TARGET_PC - bckSet(6, 0, 0.0f, dusk::getSettings().game.fastTears && dComIfGp_event_getMode() == 0 ? 2.0f : 1.0f); + bckSet(6, 0, 0.0f, dusk::getSettings().game.fastTears ? 2.0f : 1.0f); #else bckSet(6, 0, 0.0f, 1.0f); #endif diff --git a/src/d/actor/d_a_obj_drop.cpp b/src/d/actor/d_a_obj_drop.cpp index 2b373c1e64..18d27840f7 100644 --- a/src/d/actor/d_a_obj_drop.cpp +++ b/src/d/actor/d_a_obj_drop.cpp @@ -265,8 +265,8 @@ int daObjDrop_c::modeParentWait() { mModeAction = 1; #if TARGET_PC - mModeTimer = dusk::getSettings().game.fastTears && dComIfGp_event_getMode() == 0 ? 0 : 40; - if (dusk::getSettings().game.fastTears && dComIfGp_event_getMode() == 0) { + mModeTimer = dusk::getSettings().game.fastTears ? 0 : 40; + if (dusk::getSettings().game.fastTears) { current.pos.y += 100.0f; } else { current.pos.y += 300.0f; @@ -285,7 +285,7 @@ int daObjDrop_c::modeParentWait() { case 2: createBodyEffect(); #if TARGET_PC - mModeTimer = dusk::getSettings().game.fastTears && dComIfGp_event_getMode() == 0 ? 0 : 45; + mModeTimer = dusk::getSettings().game.fastTears ? 0 : 45; #else mModeTimer = 45; #endif @@ -331,7 +331,7 @@ int daObjDrop_c::modeWait() { case 2: case 50: #if TARGET_PC - if (dusk::getSettings().game.fastTears && dComIfGp_event_getMode() == 0) { + if (dusk::getSettings().game.fastTears) { f32 player_dist = current.pos.abs(daPy_getPlayerActorClass()->current.pos); f32 home_dist = current.pos.abs(home.pos); From 5ec5f8864a06586339a4ad36ed8b3b8d2e745f1f Mon Sep 17 00:00:00 2001 From: Irastris Date: Sat, 25 Apr 2026 16:59:40 -0400 Subject: [PATCH 028/390] Register interp callback for d_a_e_sm2 Fixes chu color changes --- src/d/actor/d_a_e_sm2.cpp | 57 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/d/actor/d_a_e_sm2.cpp b/src/d/actor/d_a_e_sm2.cpp index fdbc338670..81633aa009 100644 --- a/src/d/actor/d_a_e_sm2.cpp +++ b/src/d/actor/d_a_e_sm2.cpp @@ -14,6 +14,10 @@ #include "f_op/f_op_camera_mng.h" #include +#if TARGET_PC +#include "dusk/frame_interpolation.h" +#endif + class daE_SM2_HIO_c : public fOpAcm_HIO_entry_c { public: daE_SM2_HIO_c(); @@ -76,6 +80,55 @@ static int nodeCallBack(J3DJoint* i_joint, int param_1) { return 1; } +#if TARGET_PC +static void daE_SM2_interp_callback(bool isSimFrame, void* pUserWork) { + e_sm2_class* i_this = static_cast(pUserWork); + if (i_this == NULL) { + return; + } + + fopAc_ac_c* actor = (fopAc_ac_c*)&i_this->enemy; + g_env_light.settingTevStruct(0, &actor->current.pos, &actor->tevStr); + + if (!i_this->isPiece) { + if (i_this->modelMorf == NULL) { + return; + } + J3DModel* model = i_this->modelMorf->getModel(); + if (model == NULL) { + return; + } + g_env_light.setLightTevColorType_MAJI(model, &actor->tevStr); + + J3DMaterial* material = model->getModelData()->getMaterialNodePointer(0); + material->getTevKColor(1)->r = i_this->color_R; + material->getTevKColor(1)->g = i_this->color_G; + material->getTevKColor(1)->b = i_this->color_B; + material->getTevKColor(1)->a = 217.0f * i_this->color_alpha; + + if (i_this->pbtk != NULL) { + i_this->pbtk->entry(model->getModelData()); + } + } else { + if (i_this->pieceModelMorf == NULL) { + return; + } + J3DModel* model = i_this->pieceModelMorf->getModel(); + if (model == NULL) { + return; + } + + J3DMaterial* material = model->getModelData()->getMaterialNodePointer(0); + material->getTevKColor(1)->r = i_this->color_R; + material->getTevKColor(1)->g = i_this->color_G; + material->getTevKColor(1)->b = i_this->color_B; + material->getTevKColor(1)->a = 217.0f * i_this->color_alpha; + + g_env_light.setLightTevColorType_MAJI(model, &actor->tevStr); + } +} +#endif + static int daE_SM2_Draw(e_sm2_class* i_this) { fopAc_ac_c* actor = (fopAc_ac_c*)&i_this->enemy; g_env_light.settingTevStruct(0, &actor->current.pos, &actor->tevStr); @@ -122,6 +175,10 @@ static int daE_SM2_Draw(e_sm2_class* i_this) { i_this->pieceInvisModel.entryDL(NULL); } +#if TARGET_PC + dusk::frame_interp::add_interpolation_callback(&daE_SM2_interp_callback, i_this); +#endif + return 1; } From 41420bc71cdd27d805a6c1f8906063fb0ed75608 Mon Sep 17 00:00:00 2001 From: Irastris Date: Sat, 25 Apr 2026 17:07:49 -0400 Subject: [PATCH 029/390] Chu Fix 2: Electric Boogaloo --- src/d/actor/d_a_e_sm2.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/d/actor/d_a_e_sm2.cpp b/src/d/actor/d_a_e_sm2.cpp index 81633aa009..f55c4411cb 100644 --- a/src/d/actor/d_a_e_sm2.cpp +++ b/src/d/actor/d_a_e_sm2.cpp @@ -131,6 +131,11 @@ static void daE_SM2_interp_callback(bool isSimFrame, void* pUserWork) { static int daE_SM2_Draw(e_sm2_class* i_this) { fopAc_ac_c* actor = (fopAc_ac_c*)&i_this->enemy; + +#if TARGET_PC + dusk::frame_interp::add_interpolation_callback(&daE_SM2_interp_callback, i_this); +#endif + g_env_light.settingTevStruct(0, &actor->current.pos, &actor->tevStr); J3DModel* model; @@ -175,10 +180,6 @@ static int daE_SM2_Draw(e_sm2_class* i_this) { i_this->pieceInvisModel.entryDL(NULL); } -#if TARGET_PC - dusk::frame_interp::add_interpolation_callback(&daE_SM2_interp_callback, i_this); -#endif - return 1; } From 977ad16806128059036d964849dc1f76d81ac6e3 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Sat, 25 Apr 2026 23:46:12 +0200 Subject: [PATCH 030/390] GCN PAL support (#533) * Basic PAL ISO & language support Probably still needs much more work * Add language selector to pre-launch * Store DVDDiskID in a global Can use this later for things * More version system API improvements * d_name mostly region switching fully JPN doesn't work yet cuz it'll be a nightmare, probably. * More version switching support * Mark GCN PAL as supported ROM * Fix remaining REL assets to have PAL offsets * d_a_mg_fish PAL * d_a_mg_fshop PAL * isRegionUsa helper * d_menu_fishing PAL * d_msg_class PAL * m_Do_MemCardRWmng PAL * Update CARDInit call & remove DUSK_TP_VERSION * Fix Ganon cape Missed this one. * Remove tp_version from Sentry --------- Co-authored-by: Luke Street --- CMakeLists.txt | 10 +- cmake-variants.yaml | 10 - files.cmake | 1 + include/d/d_name.h | 2 +- include/d/d_s_logo.h | 4 +- include/dusk/dvd_asset.hpp | 15 +- include/dusk/settings.h | 16 + include/dusk/version.hpp | 67 ++++ include/global.h | 4 + src/d/actor/d_a_mant.cpp | 13 +- src/d/actor/d_a_mg_fish.cpp | 27 +- src/d/actor/d_a_mg_fshop.cpp | 22 +- src/d/actor/d_a_mg_rod.cpp | 30 +- src/d/actor/d_a_player.cpp | 13 +- src/d/actor/d_a_title.cpp | 30 +- src/d/actor/d_flower.inc | 28 +- src/d/actor/d_grass.inc | 19 +- src/d/d_file_sel_info.cpp | 15 +- src/d/d_menu_fishing.cpp | 8 +- src/d/d_msg_class.cpp | 14 +- src/d/d_msg_object.cpp | 29 +- src/d/d_msg_unit.cpp | 4 +- src/d/d_name.cpp | 399 ++++++++++++++++++------ src/d/d_s_logo.cpp | 182 ++++++++++- src/d/d_save.cpp | 8 +- src/dusk/config.cpp | 1 + src/dusk/crash_reporting.cpp | 1 - src/dusk/dvd_asset.cpp | 28 +- src/dusk/imgui/ImGuiPreLaunchWindow.cpp | 18 ++ src/dusk/iso_validate.cpp | 1 + src/dusk/settings.cpp | 3 + src/dusk/version.cpp | 82 +++++ src/m_Do/m_Do_MemCard.cpp | 7 +- src/m_Do/m_Do_MemCardRWmng.cpp | 36 ++- src/m_Do/m_Do_main.cpp | 21 ++ 35 files changed, 957 insertions(+), 211 deletions(-) create mode 100644 include/dusk/version.hpp create mode 100644 src/dusk/version.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 19fd5d673f..b326931e79 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -280,22 +280,16 @@ set(DUSK_COMPANY_NAME "Twilit Realm") set(DUSK_FILE_DESCRIPTION "Dusk") set(DUSK_PRODUCT_NAME "Dusk") set(DUSK_COPYRIGHT "Copyright (C) Twilit Realm contributors") -set(DUSK_GAME_NAME "GZ2E") -set(DUSK_GAME_VERSION "01") -set(DUSK_TP_VERSION ${DUSK_GAME_NAME}${DUSK_GAME_VERSION}) - -message(STATUS "dusk: Game Version: ${DUSK_TP_VERSION}") source_group("dolzel" FILES ${DOLZEL_FILES} ${Z2AUDIOLIB_FILES} ${REL_FILES}) source_group("dusk" FILES ${DUSK_FILES}) -set(GAME_COMPILE_DEFS TARGET_PC WIDESCREEN_SUPPORT=1 AVOID_UB=1 VERSION=0 - DUSK_TP_VERSION="${DUSK_TP_VERSION}" DUSK_GAME_NAME="${DUSK_GAME_NAME}" DUSK_GAME_VERSION="${DUSK_GAME_VERSION}") +set(GAME_COMPILE_DEFS TARGET_PC WIDESCREEN_SUPPORT=1 AVOID_UB=1 VERSION=0) set(GAME_INCLUDE_DIRS include src - assets/${DUSK_TP_VERSION} + assets/GZ2E01 # TODO: make this dynamic if needed? libs/JSystem/include libs extern/aurora/include/dolphin diff --git a/cmake-variants.yaml b/cmake-variants.yaml index 62d2642311..37edcede95 100644 --- a/cmake-variants.yaml +++ b/cmake-variants.yaml @@ -13,13 +13,3 @@ buildType: short: RelWithDebInfo long: Optimized, with debug symbols buildType: RelWithDebInfo - -tp_version: - default: GZ2E01 - description: TP Version - choices: - GZ2E01: - short: GZ2E01 - long: GZ2E01 - settings: - DUSK_TP_VERSION: GZ2E01 diff --git a/files.cmake b/files.cmake index af101b6c47..d45dd7dc7c 100644 --- a/files.cmake +++ b/files.cmake @@ -1466,4 +1466,5 @@ set(DUSK_FILES src/dusk/OSThread.cpp src/dusk/OSMutex.cpp src/dusk/discord_presence.cpp + src/dusk/version.cpp ) diff --git a/include/d/d_name.h b/include/d/d_name.h index e685871738..3ac6592457 100644 --- a/include/d/d_name.h +++ b/include/d/d_name.h @@ -89,7 +89,7 @@ public: void MojiSelectAnm3(); int mojiChange(u8); void selectMojiSet(); - #if REGION_JPN + #if TARGET_PC || REGION_JPN int checkDakuon(int, u8); int setDakuon(int, u8); #endif diff --git a/include/d/d_s_logo.h b/include/d/d_s_logo.h index 56d10eef82..ab714a17ae 100644 --- a/include/d/d_s_logo.h +++ b/include/d/d_s_logo.h @@ -79,7 +79,7 @@ public: bool isProgressiveMode(); void setRenderMode(); - #if VERSION == VERSION_GCN_PAL || PLATFORM_WII || PLATFORM_SHIELD + #if TARGET_PC || VERSION == VERSION_GCN_PAL || PLATFORM_WII || PLATFORM_SHIELD u8 getPalLanguage(); #endif @@ -149,7 +149,7 @@ public: /* 0x200 */ dDlst_2D_c* mNvLogo; /* 0x204 */ dDlst_2D_c* mMocImg; #endif -#if VERSION == VERSION_GCN_PAL +#if TARGET_PC || VERSION == VERSION_GCN_PAL /* 0x1FC */ mDoDvdThd_mountArchive_c* mpPalLogoResCommand; #endif /* 0x1FC */ request_of_phase_process_class* m_preLoad_dylPhase; diff --git a/include/dusk/dvd_asset.hpp b/include/dusk/dvd_asset.hpp index 014c683d44..8594d4631c 100644 --- a/include/dusk/dvd_asset.hpp +++ b/include/dusk/dvd_asset.hpp @@ -1,22 +1,31 @@ #pragma once #include "dolphin/types.h" +#include "version.hpp" namespace dusk { +struct OffsetVersion { + version::GameVersion mGameVersion; + u32 mOffset; + + constexpr OffsetVersion(const version::GameVersion gameVersion, const u32 offset) + : mGameVersion(gameVersion), mOffset(offset) {} +}; + /** * Load bytes from the main DOL by GameCube virtual address */ -bool LoadDolAsset(void* dst, u32 virtualAddress, s32 size); +bool LoadDolAsset(void* dst, std::initializer_list virtualAddress, s32 size); /** * Load bytes from a REL file in the ISO filesystem, dst must be 32-byte aligned */ -bool LoadRelAsset(void* dst, const char* dvdPath, s32 offset, s32 size); +bool LoadRelAsset(void* dst, const char* dvdPath, std::initializer_list offset, s32 size); /** * Load bytes from a REL inside RELS.arc */ -bool LoadArchivedRelAsset(void* dst, u32 memType, const char* relFileName, s32 offset, s32 size); +bool LoadArchivedRelAsset(void* dst, u32 memType, const char* relFileName, std::initializer_list offset, s32 size); } // namespace dusk diff --git a/include/dusk/settings.h b/include/dusk/settings.h index 039e51af7d..9721b93614 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -13,12 +13,26 @@ enum class BloomMode : int { Dusk = 2, }; +enum class GameLanguage : u8 { + English = OS_LANGUAGE_ENGLISH, + German = OS_LANGUAGE_GERMAN, + French = OS_LANGUAGE_FRENCH, + Spanish = OS_LANGUAGE_SPANISH, + Italian = OS_LANGUAGE_ITALIAN, +}; + namespace config { template <> struct ConfigEnumRange { static constexpr auto min = BloomMode::Off; static constexpr auto max = BloomMode::Dusk; }; + +template <> +struct ConfigEnumRange { + static constexpr auto min = GameLanguage::English; + static constexpr auto max = GameLanguage::Italian; +}; } // Persistent user settings @@ -46,6 +60,8 @@ struct UserSettings { // Game settings struct { + ConfigVar language; + // QoL ConfigVar enableQuickTransform; ConfigVar hideTvSettingsScreen; diff --git a/include/dusk/version.hpp b/include/dusk/version.hpp new file mode 100644 index 0000000000..fe393b049b --- /dev/null +++ b/include/dusk/version.hpp @@ -0,0 +1,67 @@ +#ifndef DUSK_VERSION_HPP +#define DUSK_VERSION_HPP + +/** + * Functionality for switching game behavior based on the loaded game version (e.g. PAL/JPN, GC/Wii) + */ +namespace dusk::version { + enum class GameVersion : u8 { + GcnUsa = VERSION_GCN_USA, + GcnPal = VERSION_GCN_PAL, + GcnJpn = VERSION_GCN_JPN, + WiiUsaRev0 = VERSION_WII_USA_R0, + WiiUsa = VERSION_WII_USA_R2, + WiiPal = VERSION_WII_PAL, + WiiJpn = VERSION_WII_JPN, + WiiKor = VERSION_WII_KOR, + }; + + bool isGcn(); + bool isWii(); + bool isPalOrAtLeastWiiR2(); + + bool isRegionPal(); + bool isRegionJpn(); + bool isRegionUsa(); + + GameVersion getGameVersion(); + + const DVDDiskID& getDiskID(); + + void init(); + + template + struct VersionOption { + GameVersion mVersion; + T mValue; + + constexpr VersionOption(GameVersion version, T value) : mVersion(version), mValue(value) {} + }; + + template + const T& versionSelect(const std::initializer_list> options) { + const auto version = getGameVersion(); + for (const auto& opt : options) { + if (opt.mVersion == version) { + return opt.mValue; + } + } + + // Unable to find value. + abort(); + } + + template + const T& versionSelect(const std::initializer_list> options, const T& defaultValue) { + const auto version = getGameVersion(); + for (const auto& opt : options) { + if (opt.mVersion == version) { + return opt.mValue; + } + } + + return defaultValue; + } +} // namespace dusk::version + +#endif // DUSK_VERSION_HPP diff --git a/include/global.h b/include/global.h index 9301d12e11..556c5f6207 100644 --- a/include/global.h +++ b/include/global.h @@ -230,12 +230,16 @@ using std::isnan; // Some basic macros that are more convenient than putting down #if blocks for one-line changes. #if TARGET_PC #define IF_DUSK(statement) statement +#define IF_DUSK_BLOCK(cond) if (cond) { +#define IF_DUSK_BLOCK_END } #define IF_DUSK_ARG(expr) , expr #define IF_NOT_DUSK(statement) #define DUSK_IF_ELSE(dusk, orig) dusk #else #define IF_DUSK(statement) #define IF_DUSK_ARG(expr) +#define IF_DUSK_BLOCK(cond) +#define IF_DUSK_BLOCK_END #define IF_NOT_DUSK(statement) statement #define DUSK_IF_ELSE(dusk, orig) orig #endif diff --git a/src/d/actor/d_a_mant.cpp b/src/d/actor/d_a_mant.cpp index 282502419f..6a559c0e1c 100644 --- a/src/d/actor/d_a_mant.cpp +++ b/src/d/actor/d_a_mant.cpp @@ -13,9 +13,12 @@ #if TARGET_PC #include "dusk/dvd_asset.hpp" #include "dusk/frame_interpolation.h" -static u8* l_Egnd_mantTEX_get() { alignas(32) static u8 buf[0x4000]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", 0x1C00, 0x4000), true); return buf; } -static u8* l_Egnd_mantTEX_U_get() { alignas(32) static u8 buf[0x4000]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", 0x5C00, 0x4000), true); return buf; } -static u8* l_Egnd_mantPAL_get() { alignas(32) static u8 buf[0x60]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", 0x9C00, 0x60), true); return buf; } + +using GameVersion = dusk::version::GameVersion; + +static u8* l_Egnd_mantTEX_get() { alignas(32) static u8 buf[0x4000]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", {{GameVersion::GcnUsa, 0x1C00}, {GameVersion::GcnPal, 0x1C00}}, 0x4000), true); return buf; } +static u8* l_Egnd_mantTEX_U_get() { alignas(32) static u8 buf[0x4000]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", {{GameVersion::GcnUsa, 0x5C00}, {GameVersion::GcnPal, 0x5C00}}, 0x4000), true); return buf; } +static u8* l_Egnd_mantPAL_get() { alignas(32) static u8 buf[0x60]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", {{GameVersion::GcnUsa, 0x9C00}, {GameVersion::GcnPal, 0x9C00}}, 0x60), true); return buf; } #define l_Egnd_mantTEX (l_Egnd_mantTEX_get()) #define l_Egnd_mantTEX_U (l_Egnd_mantTEX_U_get()) #define l_Egnd_mantPAL (l_Egnd_mantPAL_get()) @@ -251,7 +254,9 @@ static u32 l_texCoord[338] = { }; #if TARGET_PC -static u8* l_Egnd_mantDL_get() { alignas(32) static u8 buf[0x3EC]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", 0xA9A0, 0x3EC), true); return buf; } +using GameVersion = dusk::version::GameVersion; + +static u8* l_Egnd_mantDL_get() { alignas(32) static u8 buf[0x3EC]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", {{GameVersion::GcnUsa, 0xA9A0}, {GameVersion::GcnPal, 0xA9A0}}, 0x3EC), true); return buf; } #define l_Egnd_mantDL (l_Egnd_mantDL_get()) #else #include "assets/l_Egnd_mantDL.h" diff --git a/src/d/actor/d_a_mg_fish.cpp b/src/d/actor/d_a_mg_fish.cpp index 90781345ad..6791bcb61c 100644 --- a/src/d/actor/d_a_mg_fish.cpp +++ b/src/d/actor/d_a_mg_fish.cpp @@ -22,6 +22,7 @@ #include "d/d_s_play.h" #include "d/d_vibration.h" #include "f_op/f_op_kankyo_mng.h" +#include "dusk/version.hpp" #include #define ANM_MG_FISH_MOUTH_CLOSE 4 @@ -3230,7 +3231,17 @@ static int daMg_Fish_Execute(mg_fish_class* i_this) { daPy_py_c* player = daPy_getPlayerActorClass(); -#if VERSION == VERSION_GCN_JPN +#if TARGET_PC + if (dusk::version::isRegionJpn()) { + lit_1008 = 0; + } else if (dusk::version::isRegionPal()) { + if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_ENGLISH) { + lit_1008 = 2; + } else { + lit_1008 = 0; + } + } +#elif VERSION == VERSION_GCN_JPN lit_1008 = 0; #elif VERSION == VERSION_GCN_PAL if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_ENGLISH) { @@ -3843,7 +3854,19 @@ static int daMg_Fish_Create(fopAc_ac_c* i_this) { a_this->mResName = "O_gD_bott"; } -#if VERSION == VERSION_GCN_JPN +#if TARGET_PC + if (dusk::version::isRegionJpn()) { + lit_1008 = 0; + } else if (dusk::version::isRegionPal()) { + if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_ENGLISH) { + lit_1008 = 2; + } else { + lit_1008 = 0; + } + } else { + lit_1008 = 1; + } +#elif VERSION == VERSION_GCN_JPN lit_1008 = 0; #elif VERSION == VERSION_GCN_PAL if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_ENGLISH) { diff --git a/src/d/actor/d_a_mg_fshop.cpp b/src/d/actor/d_a_mg_fshop.cpp index 99f39e410e..f0905efd5d 100644 --- a/src/d/actor/d_a_mg_fshop.cpp +++ b/src/d/actor/d_a_mg_fshop.cpp @@ -5,14 +5,15 @@ #include "d/dolzel_rel.h" // IWYU pragma: keep +#include "Z2AudioLib/Z2Instances.h" +#include "d/actor/d_a_mg_fish.h" #include "d/actor/d_a_mg_fshop.h" #include "d/actor/d_a_npc_henna.h" -#include "d/actor/d_a_mg_fish.h" #include "d/actor/d_a_player.h" -#include "f_op/f_op_camera_mng.h" -#include "d/d_timer.h" #include "d/d_s_play.h" -#include "Z2AudioLib/Z2Instances.h" +#include "d/d_timer.h" +#include "dusk/version.hpp" +#include "f_op/f_op_camera_mng.h" #if TARGET_PC #include "dusk/gyro.h" @@ -1742,7 +1743,18 @@ static int daFshop_Create(fopAc_ac_c* actor) { fopAcM_createChild(fpcNm_FSHOP_e, fopAcM_GetID(actor), 0xFFFFFF23, &actor->current.pos, fopAcM_GetRoomNo(actor), NULL, NULL, -1, NULL); u8 sp10; -#if VERSION == VERSION_GCN_PAL || VERSION == VERSION_WII_PAL +#if TARGET_PC + if (dusk::version::isRegionPal()) { + if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_ENGLISH) { + sp10 = 2; + } else { + sp10 = 0; + } + } else { + sp10 = 1; + } + +#elif VERSION == VERSION_GCN_PAL || VERSION == VERSION_WII_PAL if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_ENGLISH) { sp10 = 2; } else { diff --git a/src/d/actor/d_a_mg_rod.cpp b/src/d/actor/d_a_mg_rod.cpp index 96ad7aa148..956a9e3cff 100644 --- a/src/d/actor/d_a_mg_rod.cpp +++ b/src/d/actor/d_a_mg_rod.cpp @@ -25,6 +25,8 @@ #include #include +#include "dusk/version.hpp" + class dmg_rod_HIO_c : public JORReflexible { public: dmg_rod_HIO_c(); @@ -5734,10 +5736,22 @@ static void play_camera_u(dmg_rod_class* i_this) { static int dmg_rod_Execute(dmg_rod_class* i_this) { fopAc_ac_c* actor = &i_this->actor; + #if TARGET_PC + if (dusk::version::isPalOrAtLeastWiiR2()) { + if (dComIfGs_getPalLanguage() == 0) { + data_804BBBD4 = 2; + } else { + data_804BBBD4 = 0; + } + } else if (dusk::version::isRegionJpn()) { + data_804BBBD4 = 0; + } else { + data_804BBBD4 = 1; + } //TODO: It seems possible that dComIfGs_getPalLanguage returns a constant value for non-PAL // versions (causing the first block to be elided), and it's also possible that the value // being compared against is an enum value with per-version definitions. - #if VERSION == VERSION_SHIELD_DEBUG + #elif VERSION == VERSION_SHIELD_DEBUG if (dComIfGs_getPalLanguage() == 1) { data_804BBBD4 = 2; } else { @@ -6303,7 +6317,19 @@ static int dmg_rod_Create(fopAc_ac_c* i_this) { heap_size = 0xC9A0; } - #if VERSION == VERSION_SHIELD_DEBUG + #if TARGET_PC + if (dusk::version::isPalOrAtLeastWiiR2()) { + if (dComIfGs_getPalLanguage() == 0) { + data_804BBBD4 = 2; + } else { + data_804BBBD4 = 0; + } + } else if (dusk::version::isRegionJpn()) { + data_804BBBD4 = 0; + } else { + data_804BBBD4 = 1; + } + #elif VERSION == VERSION_SHIELD_DEBUG if (dComIfGs_getPalLanguage() == 1) { data_804BBBD4 = 2; } else { diff --git a/src/d/actor/d_a_player.cpp b/src/d/actor/d_a_player.cpp index 8ceb0ef237..6148d23e3a 100644 --- a/src/d/actor/d_a_player.cpp +++ b/src/d/actor/d_a_player.cpp @@ -369,18 +369,17 @@ JKRHeap* daPy_anmHeap_c::setAnimeHeap() { #if !PLATFORM_WII #if TARGET_PC #include "dusk/dvd_asset.hpp" +using GameVersion = dusk::version::GameVersion; static const u8* l_sightDL_get() { static u8 buf[0x89]; static bool _ = ( dusk::LoadDolAsset( buf, - #if VERSION == VERSION_GCN_PAL - 0x803BBDA0, - #elif VERSION == VERSION_GCN_JPN - 0x803B4220, - #elif VERSION == VERSION_GCN_USA - 0x803BA0C0, - #endif +{ + {GameVersion::GcnUsa, 0x803BA0C0}, + {GameVersion::GcnPal, 0x803BBDA0}, + {GameVersion::GcnJpn, 0x803B4220} + }, 0x89 ), true diff --git a/src/d/actor/d_a_title.cpp b/src/d/actor/d_a_title.cpp index 6df52abc5b..a75a96cb2e 100644 --- a/src/d/actor/d_a_title.cpp +++ b/src/d/actor/d_a_title.cpp @@ -1,21 +1,22 @@ #include "d/dolzel_rel.h" // IWYU pragma: keep +#include "JSystem/J2DGraph/J2DScreen.h" +#include "JSystem/J2DGraph/J2DTextBox.h" +#include "JSystem/JKernel/JKRExpHeap.h" +#include "JSystem/JKernel/JKRMemArchive.h" #include "d/actor/d_a_title.h" +#include "d/d_com_inf_game.h" +#include "d/d_demo.h" +#include "d/d_menu_collect.h" +#include "d/d_pane_class_alpha.h" #include "d/d_s_logo.h" #include "d/d_s_play.h" -#include "d/d_demo.h" -#include "d/d_pane_class_alpha.h" -#include "d/d_menu_collect.h" +#include "dusk/version.hpp" +#include "f_op/f_op_msg_mng.h" +#include "f_op/f_op_overlap_mng.h" +#include "f_op/f_op_scene_mng.h" #include "m_Do/m_Do_Reset.h" #include "m_Do/m_Do_controller_pad.h" -#include "d/d_com_inf_game.h" -#include "JSystem/JKernel/JKRExpHeap.h" -#include "f_op/f_op_overlap_mng.h" -#include "f_op/f_op_msg_mng.h" -#include "f_op/f_op_scene_mng.h" -#include "JSystem/J2DGraph/J2DScreen.h" -#include "JSystem/JKernel/JKRMemArchive.h" -#include "JSystem/J2DGraph/J2DTextBox.h" #include "m_Do/m_Do_graphic.h" #ifdef TARGET_PC @@ -49,7 +50,10 @@ static u8 const lit_3772[12] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -#if VERSION == VERSION_GCN_PAL +#if TARGET_PC +using namespace dusk::version; +#define l_arcName versionSelect({{GameVersion::GcnPal, "TitlePal"}}, "Title") +#elif VERSION == VERSION_GCN_PAL static char const l_arcName[] = "TitlePal"; #else static char const l_arcName[] = "Title"; @@ -59,7 +63,7 @@ daTit_HIO_c::daTit_HIO_c() { mPSScaleX = 1.0f; mPSScaleY = 1.0f; - #if VERSION == VERSION_GCN_PAL + #if TARGET_PC || VERSION == VERSION_GCN_PAL switch (OSGetLanguage()) { case OS_LANGUAGE_ENGLISH: case OS_LANGUAGE_GERMAN: diff --git a/src/d/actor/d_flower.inc b/src/d/actor/d_flower.inc index 1850e1e1ad..5f54ea4bda 100644 --- a/src/d/actor/d_flower.inc +++ b/src/d/actor/d_flower.inc @@ -17,7 +17,8 @@ const u16 l_J_Ohana00_64TEX__height = 63; #if TARGET_PC #include "dusk/dvd_asset.hpp" -static u8* l_J_Ohana00_64TEX_get() { static u8 buf[0x800]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x9060, 0x800), true); return buf; } +using GameVersion = dusk::version::GameVersion; +static u8* l_J_Ohana00_64TEX_get() { static u8 buf[0x800]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x9060}, {GameVersion::GcnPal, 0x9060}}, 0x800), true); return buf; } #define l_J_Ohana00_64TEX (l_J_Ohana00_64TEX_get()) #else #include "assets/l_J_Ohana00_64TEX.h" @@ -113,10 +114,12 @@ static u8 l_flowerTexCoord[] = { 0x3E, 0xA7, 0x72, 0xD6, 0xBD, 0x2F, 0x46, 0xAA}; #if TARGET_PC -static u8* l_J_hana00DL_get() { static u8 buf[0x150]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x9D20, 0x150), true); return buf; } -static u8* l_J_hana00_cDL_get() { static u8 buf[0xDE]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x9E80, 0xDE), true); return buf; } -static u8* l_matDL_get() { static u8 buf[0x99]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x9F60, 0x99), true); return buf; } -static u8* l_matLight4DL_get() { static u8 buf[0x99]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xA000, 0x99), true); return buf; } +using GameVersion = dusk::version::GameVersion; + +static u8* l_J_hana00DL_get() { static u8 buf[0x150]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x9D20}, {GameVersion::GcnPal, 0x9D20}}, 0x150), true); return buf; } +static u8* l_J_hana00_cDL_get() { static u8 buf[0xDE]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x9E80}, {GameVersion::GcnPal, 0x9E80}}, 0xDE), true); return buf; } +static u8* l_matDL_get() { static u8 buf[0x99]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x9F60}, {GameVersion::GcnPal, 0x9F60}}, 0x99), true); return buf; } +static u8* l_matLight4DL_get() { static u8 buf[0x99]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0xA000}, {GameVersion::GcnPal, 0xA000}}, 0x99), true); return buf; } #define l_J_hana00DL (l_J_hana00DL_get()) #define l_J_hana00_cDL (l_J_hana00_cDL_get()) #define l_matDL (l_matDL_get()) @@ -142,7 +145,8 @@ const u16 l_J_Ohana01_64128_0419TEX__height = 127; #endif #if TARGET_PC -static u8* l_J_Ohana01_64128_0419TEX_get() { static u8 buf[0x1000]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xA0A0, 0x1000), true); return buf; } +using GameVersion = dusk::version::GameVersion; +static u8* l_J_Ohana01_64128_0419TEX_get() { static u8 buf[0x1000]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0xA0A0}, {GameVersion::GcnPal, 0xA0A0}}, 0x1000), true); return buf; } #define l_J_Ohana01_64128_0419TEX (l_J_Ohana01_64128_0419TEX_get()) #else #include "assets/l_J_Ohana01_64128_0419TEX.h" @@ -274,11 +278,13 @@ static u8 l_flowerTexCoord2[] = { 0x40, 0x1B, 0x7D, 0x52, 0x3F, 0x80, 0x3F, 0x79, 0x40, 0x1B, 0x7D, 0x52, 0x3F, 0x51, 0x10, 0x6F}; #if TARGET_PC -static u8* l_J_hana01DL_get() { static u8 buf[0x138]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xB7C0, 0x138), true); return buf; } -static u8* l_J_hana01_c_00DL_get() { static u8 buf[0xDE]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xB900, 0xDE), true); return buf; } -static u8* l_J_hana01_c_01DL_get() { static u8 buf[0x128]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xB9E0, 0x128), true); return buf; } -static u8* l_mat2DL_get() { static u8 buf[0x99]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xBB20, 0x99), true); return buf; } -static u8* l_mat2Light4DL_get() { static u8 buf[0x99]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xBBC0, 0x99), true); return buf; } +using GameVersion = dusk::version::GameVersion; + +static u8* l_J_hana01DL_get() { static u8 buf[0x138]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0xB7C0}, {GameVersion::GcnPal, 0xB7C0}}, 0x138), true); return buf; } +static u8* l_J_hana01_c_00DL_get() { static u8 buf[0xDE]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0xB900}, {GameVersion::GcnPal, 0xB900}}, 0xDE), true); return buf; } +static u8* l_J_hana01_c_01DL_get() { static u8 buf[0x128]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0xB9E0}, {GameVersion::GcnPal, 0xB9E0}}, 0x128), true); return buf; } +static u8* l_mat2DL_get() { static u8 buf[0x99]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0xBB20}, {GameVersion::GcnPal, 0xBB20}}, 0x99), true); return buf; } +static u8* l_mat2Light4DL_get() { static u8 buf[0x99]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0xBBC0}, {GameVersion::GcnPal, 0xBBC0}}, 0x99), true); return buf; } #define l_J_hana01DL (l_J_hana01DL_get()) #define l_J_hana01_c_00DL (l_J_hana01_c_00DL_get()) #define l_J_hana01_c_01DL (l_J_hana01_c_01DL_get()) diff --git a/src/d/actor/d_grass.inc b/src/d/actor/d_grass.inc index ab2724060f..9bc8815753 100644 --- a/src/d/actor/d_grass.inc +++ b/src/d/actor/d_grass.inc @@ -20,8 +20,9 @@ const u16 l_M_kusa05_RGBATEX__height = 31; #if TARGET_PC #include "dusk/dvd_asset.hpp" -static u8* l_M_kusa05_RGBATEX_get() { static u8 buf[0x800]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x7680, 0x800), true); return buf; } -static u8* l_M_Hijiki00TEX_get() { static u8 buf[0x800]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x7E80, 0x800), true); return buf; } +using GameVersion = dusk::version::GameVersion; +static u8* l_M_kusa05_RGBATEX_get() { static u8 buf[0x800]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x7680}, {GameVersion::GcnPal, 0x7680}}, 0x800), true); return buf; } +static u8* l_M_Hijiki00TEX_get() { static u8 buf[0x800]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x7E80}, {GameVersion::GcnPal, 0x7E80}}, 0x800), true); return buf; } #define l_M_kusa05_RGBATEX (l_M_kusa05_RGBATEX_get()) #define l_M_Hijiki00TEX (l_M_Hijiki00TEX_get()) #else @@ -113,12 +114,14 @@ static u8 l_texCoord[160] = { }; #if TARGET_PC -static u8* l_M_Kusa_9qDL_get() { static u8 buf[0xCB]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x8B00, 0xCB), true); return buf; } -static u8* l_M_Kusa_9q_cDL_get() { static u8 buf[0xCB]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x8BE0, 0xCB), true); return buf; } -static u8* l_M_TenGusaDL_get() { static u8 buf[0xD4]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x8CC0, 0xD4), true); return buf; } -static u8* l_Tengusa_matDL_get() { static u8 buf[0xA8]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x8DA0, 0xA8), true); return buf; } -static u8* l_kusa9q_matDL_get() { static u8 buf[0xA8]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x8E60, 0xA8), true); return buf; } -static u8* l_kusa9q_l4_matDL_get() { static u8 buf[0xA8]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x8F20, 0xA8), true); return buf; } +using GameVersion = dusk::version::GameVersion; + +static u8* l_M_Kusa_9qDL_get() { static u8 buf[0xCB]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x8B00}, {GameVersion::GcnPal, 0x8B00}}, 0xCB), true); return buf; } +static u8* l_M_Kusa_9q_cDL_get() { static u8 buf[0xCB]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x8BE0}, {GameVersion::GcnPal, 0x8BE0}}, 0xCB), true); return buf; } +static u8* l_M_TenGusaDL_get() { static u8 buf[0xD4]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x8CC0}, {GameVersion::GcnPal, 0x8CC0}}, 0xD4), true); return buf; } +static u8* l_Tengusa_matDL_get() { static u8 buf[0xA8]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x8DA0}, {GameVersion::GcnPal, 0x8DA0}}, 0xA8), true); return buf; } +static u8* l_kusa9q_matDL_get() { static u8 buf[0xA8]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x8E60}, {GameVersion::GcnPal, 0x8E60}}, 0xA8), true); return buf; } +static u8* l_kusa9q_l4_matDL_get() { static u8 buf[0xA8]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x8F20}, {GameVersion::GcnPal, 0x8F20}}, 0xA8), true); return buf; } #define l_M_Kusa_9qDL (l_M_Kusa_9qDL_get()) #define l_M_Kusa_9q_cDL (l_M_Kusa_9q_cDL_get()) #define l_M_TenGusaDL (l_M_TenGusaDL_get()) diff --git a/src/d/d_file_sel_info.cpp b/src/d/d_file_sel_info.cpp index f305f59a9e..0c987e6d63 100644 --- a/src/d/d_file_sel_info.cpp +++ b/src/d/d_file_sel_info.cpp @@ -14,6 +14,8 @@ #include #include +#include "dusk/version.hpp" + dFile_info_c::dFile_info_c(JKRArchive* i_archive, u8 param_1) { mArchive = i_archive; field_0x22 = param_1; @@ -169,7 +171,18 @@ void dFile_info_c::setSaveDate(dSv_save_c* i_savedata) { OSCalendarTime time; OSTicksToCalendarTime(i_savedata->getPlayer().getPlayerStatusB().getDateIpl(), &time); - #if (VERSION == VERSION_GCN_JPN) || (VERSION == VERSION_WII_JPN) + #if TARGET_PC + if (dusk::version::isRegionJpn()) { + sprintf(mSaveDate, "%d.%02d.%02d %02d:%02d", time.year, time.mon + 1, time.mday, + time.hour, time.min); + } else if (dusk::version::isRegionPal() && dComIfGs_getPalLanguage() != dSv_player_config_c::LANGUAGE_ENGLISH) { + sprintf(mSaveDate, "%02d/%02d/%d %02d:%02d", time.mday, time.mon + 1, time.year, time.hour, + time.min); + } else { + sprintf(mSaveDate, "%02d/%02d/%d %02d:%02d", time.mon + 1, time.mday, time.year, time.hour, + time.min); + } + #elif (VERSION == VERSION_GCN_JPN) || (VERSION == VERSION_WII_JPN) sprintf(mSaveDate, "%d.%02d.%02d %02d:%02d", time.year, time.mon + 1, time.mday, time.hour, time.min); #elif VERSION == VERSION_GCN_PAL diff --git a/src/d/d_menu_fishing.cpp b/src/d/d_menu_fishing.cpp index 615323767b..b76002d540 100644 --- a/src/d/d_menu_fishing.cpp +++ b/src/d/d_menu_fishing.cpp @@ -16,6 +16,8 @@ #include "m_Do/m_Do_graphic.h" #include +#include "dusk/version.hpp" + typedef void (dMenu_Fishing_c::*initFunc)(); initFunc map_init_process[] = { &dMenu_Fishing_c::wait_init, @@ -135,9 +137,9 @@ bool dMenu_Fishing_c::isSync() { } void dMenu_Fishing_c::init() { - #if VERSION == VERSION_GCN_PAL + #if TARGET_PC || VERSION == VERSION_GCN_PAL BOOL isEnglish = FALSE; - if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_ENGLISH) { + if (dusk::version::isRegionUsa() || (dusk::version::isRegionPal() && dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_ENGLISH)) { isEnglish = TRUE; } #endif @@ -145,7 +147,7 @@ void dMenu_Fishing_c::init() { for (int i = 0; i < MAX_FINDABLE_FISHES; i++) { if (dComIfGs_getFishNum(i) != 0) { // Fish has been caught once, display it along with it's params - #if VERSION == VERSION_GCN_PAL + #if TARGET_PC || VERSION == VERSION_GCN_PAL if (isEnglish) { setFishParam(i, dComIfGs_getFishNum(i), dComIfGs_getFishSize(i) / 2.54f); } else { diff --git a/src/d/d_msg_class.cpp b/src/d/d_msg_class.cpp index 7af18f0732..4040eb0d7f 100644 --- a/src/d/d_msg_class.cpp +++ b/src/d/d_msg_class.cpp @@ -307,7 +307,7 @@ static u8 getOutFontNumberType(int param_0) { } } -#if VERSION == VERSION_GCN_PAL +#if TARGET_PC || VERSION == VERSION_GCN_PAL static void setPlayerName(char* i_player_name, u8 param_2) { if (param_2 != 0) { strcpy(i_player_name, dComIfGs_getPlayerName()); @@ -1485,7 +1485,7 @@ bool jmessage_tMeasureProcessor::do_tag(u32 i_tag, void const* i_data, u32 i_siz char buffer[40]; switch (i_tag & 0xFF00FFFF) { case MSGTAG_PLAYER_GENITIV: - #if VERSION == VERSION_GCN_PAL + #if TARGET_PC || VERSION == VERSION_GCN_PAL if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_GERMAN) { setPlayerName(buffer, 1); } else { @@ -1495,7 +1495,7 @@ bool jmessage_tMeasureProcessor::do_tag(u32 i_tag, void const* i_data, u32 i_siz push_word(buffer); return true; case MSGTAG_HORSE_GENITIV: - #if VERSION == VERSION_GCN_PAL + #if TARGET_PC || VERSION == VERSION_GCN_PAL if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_GERMAN) { setHorseName(buffer, 1); } else { @@ -4270,7 +4270,7 @@ bool jmessage_string_tMeasureProcessor::do_tag(u32 i_tag, void const* i_data, u3 char buffer[40]; switch (i_tag & 0xFF00FFFF) { case MSGTAG_PLAYER_GENITIV: - #if VERSION == VERSION_GCN_PAL + #if TARGET_PC || VERSION == VERSION_GCN_PAL if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_GERMAN) { setPlayerName(buffer, 1); } else { @@ -4281,7 +4281,7 @@ bool jmessage_string_tMeasureProcessor::do_tag(u32 i_tag, void const* i_data, u3 stack_pushCurrent(buffer); break; case MSGTAG_HORSE_GENITIV: - #if VERSION == VERSION_GCN_PAL + #if TARGET_PC || VERSION == VERSION_GCN_PAL if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_GERMAN) { setHorseName(buffer, 1); } else { @@ -4878,7 +4878,7 @@ bool jmessage_string_tRenderingProcessor::do_tag(u32 i_tag, void const* i_data, char buffer[40]; switch (i_tag & 0xFF00FFFF) { case MSGTAG_PLAYER_GENITIV: - #if VERSION == VERSION_GCN_PAL + #if TARGET_PC || VERSION == VERSION_GCN_PAL if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_GERMAN) { setPlayerName(buffer, 1); } else { @@ -4889,7 +4889,7 @@ bool jmessage_string_tRenderingProcessor::do_tag(u32 i_tag, void const* i_data, push_word(buffer); break; case MSGTAG_HORSE_GENITIV: - #if VERSION == VERSION_GCN_PAL + #if TARGET_PC || VERSION == VERSION_GCN_PAL if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_GERMAN) { setHorseName(buffer, 1); } else { diff --git a/src/d/d_msg_object.cpp b/src/d/d_msg_object.cpp index 9b7b64ebda..ae0e3d8427 100644 --- a/src/d/d_msg_object.cpp +++ b/src/d/d_msg_object.cpp @@ -24,9 +24,11 @@ #include "f_op/f_op_msg_mng.h" #include #include + +#include "JSystem/JKernel/JKRExpHeap.h" +#include "dusk/version.hpp" #include "m_Do/m_Do_controller_pad.h" #include "m_Do/m_Do_lib.h" -#include "JSystem/JKernel/JKRExpHeap.h" #if TARGET_PC #include "dusk/settings.h" @@ -1643,7 +1645,30 @@ void dMsgObject_c::readMessageGroupLocal(mDoDvdThd_mountXArchive_c** p_arcMount) #else #if TARGET_PC // Original game UB - snprintf(arcName, sizeof(arcName), "/res/Msgus/bmgres%d.arc", msgGroup); + + if (dusk::version::isRegionPal()) { + switch (dComIfGs_getPalLanguage()) { + case dSv_player_config_c::LANGUAGE_GERMAN: + snprintf(arcName, sizeof(arcName), "/res/Msgde/bmgres%d.arc", msgGroup); + break; + case dSv_player_config_c::LANGUAGE_FRENCH: + snprintf(arcName, sizeof(arcName), "/res/Msgfr/bmgres%d.arc", msgGroup); + break; + case dSv_player_config_c::LANGUAGE_SPANISH: + snprintf(arcName, sizeof(arcName), "/res/Msgsp/bmgres%d.arc", msgGroup); + break; + case dSv_player_config_c::LANGUAGE_ITALIAN: + snprintf(arcName, sizeof(arcName), "/res/Msgit/bmgres%d.arc", msgGroup); + break; + default: + snprintf(arcName, sizeof(arcName), "/res/Msguk/bmgres%d.arc", msgGroup); + } + } else if (dusk::version::isRegionJpn()) { + snprintf(arcName, sizeof(arcName), "/res/Msgjp/bmgres%d.arc", msgGroup); + } else { + snprintf(arcName, sizeof(arcName), "/res/Msgus/bmgres%d.arc", msgGroup); + } + #else sprintf(arcName, "/res/Msgus/bmgres%d.arc", msgGroup); #endif diff --git a/src/d/d_msg_unit.cpp b/src/d/d_msg_unit.cpp index f773abd373..7bbe8b3d70 100644 --- a/src/d/d_msg_unit.cpp +++ b/src/d/d_msg_unit.cpp @@ -334,11 +334,11 @@ void dMsgUnit_c::setTag(int i_type, int i_value, char* o_buffer, bool param_4) { vals[1] = ((dMsgUnit_inf1_section_t*)pInfoBlock)->entries[i_type].endFrame; #endif -#if REGION_PAL +#if TARGET_PC || REGION_PAL if (i_value == 1 || (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_FRENCH && i_value == 0)) { -#elif !REGION_USA +#elif !REGION_USA // Dusk TODO: What? This checks for Spanish when *not* PAL or USA? if (i_value == 1 || (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_SPANISH && i_value == 0)) { diff --git a/src/d/d_name.cpp b/src/d/d_name.cpp index e4232eff34..1f3ccbb1d7 100644 --- a/src/d/d_name.cpp +++ b/src/d/d_name.cpp @@ -8,9 +8,15 @@ #include "m_Do/m_Do_controller_pad.h" #include #include + #include "JSystem/J2DGraph/J2DAnmLoader.h" +#include "dusk/version.hpp" #include "f_op/f_op_msg_mng.h" +static bool isPalOrJpn() { + return dusk::version::isRegionPal() || dusk::version::isRegionJpn(); +} + static const char* l_mojiHira[65] = { "あ", "い", "う", "え", "お", "か", "き", "く", "け", "こ", "さ", "し", "す", "せ", "そ", "た", "ち", "つ", "て", "と", "な", "に", "ぬ", "ね", "の", "は", @@ -66,15 +72,31 @@ static const char* l_mojiEisu[65] = { "X", "k", "x", ",", "L", "Y", "l", "y", ".", "M", "Z", "m", "z", " ", }; -#if REGION_PAL -static char* l_mojiEisuPal_1[65] = { +#if TARGET_PC +// The game normally mutates this string list to fill in the real character codes. +// That can't work on a modern platform, so instead I've filled them out ahead of time. +static const char* l_mojiEisuPal_1[65] = { + "A", "N", "\xC0", "\xCF", "1", "B", "O", "\xC1", "\xD0", "2", "C", "P", "\xC2", "\xD1", "3", "D", "Q", + "\xC3", "\xD2", "4", "E", "R", "\xC4", "\xD3", "5", "F", "S", "\xC5", "\xD4", "6", "G", "T", "\xC6", "\xD5", + "7", "H", "U", "\xC7", "\xD6", "8", "I", "V", "\xC8", "\xD7", "9", "J", "W", "\xC9", "\xD8", "0", "K", + "X", "\xCA", "\xD9", ",", "L", "Y", "\xCB", "\xDA", ".", "M", "Z", "\xCC", "\xDB", " ", +}; + +static const char* l_mojiEisuPal_2[65] = { + "a", "n", "\xE0", "\xEF", "1", "b", "o", "\xE1", "\xF0", "2", "c", "p", "\xE2", "\xF1", "3", "d", "q", + "\xE3", "\xF2", "4", "e", "r", "\xE4", "\xF3", "5", "f", "s", "\xE5", "\xF4", "6", "g", "t", "\xE6", + "\xF5", "7", "h", "u", "\xE7", "\xF6", "8", "i", "v", "\xE8", "\xF7", "9", "j", "w", "\xE9", "\xF8", "0", + "k", "x", "\xEA", "\xF9", ",", "l", "y", "\xEB", "\xFA", ".", "m", "z", "\xEC", "\xFB", " ", +}; +#elif REGION_PAL +static const char* l_mojiEisuPal_1[65] = { "A", "N", "AA", "BB", "1", "B", "O", "CC", "DD", "2", "C", "P", "EE", "FF", "3", "D", "Q", "GG", "HH", "4", "E", "R", "II", "JJ", "5", "F", "S", "KK", "LL", "6", "G", "T", "MM", "NN", "7", "H", "U", "OO", "PP", "8", "I", "V", "QQ", "RR", "9", "J", "W", "SS", "TT", "0", "K", "X", "UU", "VV", ",", "L", "Y", "WW", "XX", ".", "M", "Z", "YY", "ZZ", " ", }; -static char* l_mojiEisuPal_2[65] = { +static const char* l_mojiEisuPal_2[65] = { "a", "n", "aa", "bb", "1", "b", "o", "cc", "dd", "2", "c", "p", "ee", "ff", "3", "d", "q", "gg", "hh", "4", "e", "r", "ii", "jj", "5", "f", "s", "kk", "ll", "6", "g", "t", "mm", "nn", "7", "h", "u", "oo", "pp", "8", "i", "v", "qq", "rr", "9", "j", "w", "ss", "tt", "0", @@ -82,6 +104,16 @@ static char* l_mojiEisuPal_2[65] = { }; #endif +#if TARGET_PC +// ' ' (full-width space) +#define SPACE_MAYBE_FULL (dusk::version::isRegionJpn() ? '\x81\x40' : ' ') +#elif REGION_JPN +// ' ' (full-width space) +#define SPACE_MAYBE_FULL '\x81\x40' +#else +#define SPACE_MAYBE_FULL ' ' +#endif + static dNm_HIO_c g_nmHIO; typedef void (dName_c::*selProcFunc)(void); @@ -163,13 +195,18 @@ void dName_c::init() { field_0x2ac = mSelProc; field_0x2ad = mSelProc; field_0x2ae = field_0x2ac; - #if REGION_PAL || REGION_JPN + #if TARGET_PC + mMojiSet = isPalOrJpn() ? MOJI_HIRA : MOJI_EIGO; + #elif REGION_PAL || REGION_JPN mMojiSet = MOJI_HIRA; #else mMojiSet = MOJI_EIGO; #endif mPrevMojiSet = 255; - #if REGION_PAL || REGION_JPN + #if TARGET_PC + mSelMenu = isPalOrJpn() ? MENU_HIRA : MENU_END; + mPrevSelMenu = isPalOrJpn() ? MENU_HIRA : MENU_END; + #elif REGION_PAL || REGION_JPN mSelMenu = MENU_HIRA; mPrevSelMenu = MENU_HIRA; #else @@ -187,7 +224,8 @@ void dName_c::initial() { mNextNameStr[0] = 0; } - #if REGION_PAL || REGION_JPN + #if TARGET_PC || REGION_PAL || REGION_JPN + IF_DUSK_BLOCK(isPalOrJpn()) if (mSelProc == PROC_MOJI_SELECT) { mMenuIcon[mMojiSet]->scale(g_nmHIO.mMenuScale, g_nmHIO.mMenuScale); mMenuText[mMojiSet]->setWhite(JUtility::TColor(0xC8, 0xC8, 0xC8, 0xFF)); @@ -196,6 +234,7 @@ void dName_c::initial() { mMenuText[mPrevMojiSet]->setWhite(JUtility::TColor(0x96, 0x96, 0x96, 0xFF)); } } + IF_DUSK_BLOCK_END #endif } @@ -230,8 +269,8 @@ void dName_c::_move() { stick->checkTrigger(); (this->*SelProc[mSelProc])(); - #if REGION_PAL || REGION_JPN - if (mDoCPd_c::getTrigY(PAD_1)) { + #if TARGET_PC || REGION_PAL || REGION_JPN + if (IF_DUSK(isPalOrJpn() &&) mDoCPd_c::getTrigY(PAD_1)) { mDoAud_seStart(Z2SE_SY_DUMMY, 0, 0, 0); mPrevMojiSet = mMojiSet; mMojiSet++; @@ -245,8 +284,8 @@ void dName_c::_move() { mojiListChange(); } else { #endif - #if REGION_JPN - if (mDoCPd_c::getTrigX(PAD_1)) { + #if TARGET_PC || REGION_JPN + if (IF_DUSK(dusk::version::isRegionJpn() &&) mDoCPd_c::getTrigX(PAD_1)) { if (mCurPos != 0) { if (mojiChange(mCurPos - 1) == 1) { mDoAud_seStart(Z2SE_SY_DUMMY, 0, 0, 0); @@ -283,12 +322,14 @@ void dName_c::_move() { backSpace(); } } else if (mDoCPd_c::getTrigStart(PAD_1)) { +#define EIGO_OR_END DUSK_IF_ELSE((dusk::version::isRegionPal() ? MENU_EIGO : MENU_END), MENU_END) + #if REGION_PAL if ((mSelProc != PROC_MENU_SELECT || mSelMenu != MENU_EIGO) && (mSelProc == PROC_MENU_SELECT || mSelProc == PROC_MOJI_SELECT)) { #else - if ((mSelProc != PROC_MENU_SELECT || mSelMenu != MENU_END) && + if ((mSelProc != PROC_MENU_SELECT || mSelMenu != EIGO_OR_END) && (mSelProc == PROC_MENU_SELECT || mSelProc == PROC_MOJI_SELECT)) { #endif @@ -297,7 +338,7 @@ void dName_c::_move() { #if REGION_PAL mSelMenu = MENU_EIGO; #else - mSelMenu = MENU_END; + mSelMenu = EIGO_OR_END; #endif switch (mSelProc) { @@ -314,10 +355,10 @@ void dName_c::_move() { } } } - #if REGION_JPN + #if TARGET_PC || REGION_JPN } #endif - #if REGION_PAL || REGION_JPN + #if TARGET_PC || REGION_PAL || REGION_JPN } #endif @@ -327,10 +368,9 @@ void dName_c::_move() { int dName_c::nameCheck() { for (int i = 8, len = 7; i > 0; i--) { #if REGION_JPN - // ' ' (full-width space) if (mChrInfo[len].mCharacter != ' ' && mChrInfo[len].mCharacter != '\x81\x40') { #else - if (mChrInfo[len].mCharacter != ' ') { + if (mChrInfo[len].mCharacter != ' ' IF_DUSK(&& (!dusk::version::isRegionJpn() || mChrInfo[len].mCharacter != '\x81\x40'))) { #endif return len + 1; } @@ -344,8 +384,8 @@ void dName_c::playNameSet(int nameLength) { char* str = mInputStr; for (int i = 0; i < nameLength; i++) { - #if REGION_JPN - if (mChrInfo[i].mMojiSet == 2) { + #if TARGET_PC || REGION_JPN + if (!dusk::version::isRegionJpn() || mChrInfo[i].mMojiSet == 2) { *str = mChrInfo[i].mCharacter; str += 1; } else { @@ -727,7 +767,34 @@ int dName_c::getMoji() { int result = -1; const char* moji; - #if REGION_PAL + #if TARGET_PC + if (dusk::version::isRegionPal()) { + switch (mMojiSet) { + case MOJI_HIRA: + moji = l_mojiEisuPal_1[mCharRow + mCharColumn * 5]; + break; + case MOJI_KATA: + moji = l_mojiEisuPal_2[mCharRow + mCharColumn * 5]; + break; + default: + abort(); + } + } else { + switch (mMojiSet) { + case MOJI_HIRA: + moji = l_mojiHira[mCharRow + mCharColumn * 5]; + break; + case MOJI_KATA: + moji = l_mojikata[mCharRow + mCharColumn * 5]; + break; + case MOJI_EIGO: + moji = l_mojiEisu[mCharRow + mCharColumn * 5]; + break; + default: + abort(); + } + } + #elif REGION_PAL switch (mMojiSet) { case MOJI_HIRA: moji = l_mojiEisuPal_1[mCharRow + mCharColumn * 5]; @@ -750,7 +817,17 @@ int dName_c::getMoji() { } #endif - #if REGION_JPN + #if TARGET_PC + if (dusk::version::isRegionJpn()) { + if (*(u8*)moji >> 4 == 0x8 || *(u8*)moji >> 4 == 0x9) { + result = *(u16*)moji; + } else { + result = *moji; + } + } else { + result = *moji; + } + #elif REGION_JPN if (*(u8*)moji >> 4 == 0x8 || *(u8*)moji >> 4 == 0x9) { result = *(u16*)moji; } else { @@ -763,6 +840,14 @@ int dName_c::getMoji() { return result; } +#if TARGET_PC +#define CHAR_TRUNC(val) (dusk::version::isRegionPal() ? val & 0xFF : val) +#elif REGION_PAL +#define CHAR_TRUNC(val) (val & 0xFF) +#else +#define CHAR_TRUNC(val) val +#endif + void dName_c::setMoji(int moji) { if (mCurPos == 8 || nameCheck() == 8) { mDoAud_seStart(Z2SE_SYS_ERROR, NULL, 0, 0); @@ -771,24 +856,14 @@ void dName_c::setMoji(int moji) { s32 notEmpty = false; for (int i = mCurPos; i < 8; i++) { - #if REGION_JPN - // ' ' (full-width space) - if (mChrInfo[i].mCharacter != '\x81\x40') { - #else - if (mChrInfo[i].mCharacter != ' ') { - #endif + if (mChrInfo[i].mCharacter != SPACE_MAYBE_FULL) { notEmpty = true; break; } } if (notEmpty) { - #if REGION_JPN - // ' ' (full-width space) - if (mChrInfo[7].mCharacter == '\x81\x40') { - #else - if (mChrInfo[7].mCharacter == ' ') { - #endif + if (mChrInfo[7].mCharacter == SPACE_MAYBE_FULL) { for (int i = 6; i >= mCurPos; i--) { mChrInfo[i + 1] = mChrInfo[i]; } @@ -797,11 +872,7 @@ void dName_c::setMoji(int moji) { mChrInfo[mCurPos].mRow = mCharRow; mChrInfo[mCurPos].mMojiSet = mMojiSet; mChrInfo[mCurPos].field_0x3 = 1; - #if REGION_PAL - mChrInfo[mCurPos].mCharacter = moji & 0xFF; - #else - mChrInfo[mCurPos].mCharacter = moji; - #endif + mChrInfo[mCurPos].mCharacter = CHAR_TRUNC(moji); if (mCurPos != 8) { mLastCurPos = mCurPos; @@ -814,11 +885,7 @@ void dName_c::setMoji(int moji) { mChrInfo[mCurPos].mRow = mCharRow; mChrInfo[mCurPos].mMojiSet = mMojiSet; mChrInfo[mCurPos].field_0x3 = 1; - #if REGION_PAL - mChrInfo[mCurPos].mCharacter = moji & 0xFF; - #else - mChrInfo[mCurPos].mCharacter = moji; - #endif + mChrInfo[mCurPos].mCharacter = CHAR_TRUNC(moji); if (mCurPos != 8) { mLastCurPos = mCurPos; @@ -844,13 +911,8 @@ void dName_c::setNameText() { "CR\x1b" "CC[000000]\x1bGM[0]%c\x1bHM\x1b" "CC[ffffff]\x1bGM[0]%c", - #if REGION_PAL - (u8)mChrInfo[i].mCharacter & 0xFF, - (u8)mChrInfo[i].mCharacter & 0xFF - #else - (u8)mChrInfo[i].mCharacter, - (u8)mChrInfo[i].mCharacter - #endif + CHAR_TRUNC((u8)mChrInfo[i].mCharacter), + CHAR_TRUNC((u8)mChrInfo[i].mCharacter) ); #if REGION_JPN } else { @@ -889,7 +951,29 @@ void dName_c::nameCursorMove() { void dName_c::selectCursorMove() { int idx; - #if REGION_PAL + #if TARGET_PC + if (dusk::version::isRegionPal()) { + if (mCharColumn < 3) { + idx = 0; + } else if (mCharColumn < 6) { + idx = 1; + } else if (mCharColumn >= 6) { + idx = 2; + } + } else if (dusk::version::isRegionJpn()) { + if (mCharColumn < 3) { + idx = 0; + } else if (mCharColumn < 6) { + idx = 1; + } else if (mCharColumn < 8) { + idx = 2; + } else if (mCharColumn >= 8) { + idx = 3; + } + } else { + idx = 3; + } + #elif REGION_PAL if (mCharColumn < 3) { idx = 0; } else if (mCharColumn < 6) { @@ -930,7 +1014,36 @@ void dName_c::selectCursorMove() { void dName_c::menuCursorPosSet() { mPrevSelMenu = mSelMenu; - #if REGION_PAL + #if TARGET_PC + if (dusk::version::isRegionPal()) { + if (mCharColumn < 3) { + mSelMenu = MENU_HIRA; + } else if (mCharColumn < 6) { + mSelMenu = MENU_KATA; + } else if (mCharColumn >= 6) { + mSelMenu = MENU_EIGO; + } + } else if (dusk::version::isRegionJpn()) { + if (mCharColumn < 3) { + mSelMenu = MENU_HIRA; + return; + } + if (mCharColumn < 6) { + mSelMenu = MENU_KATA; + return; + } + if (mCharColumn < 8) { + mSelMenu = MENU_EIGO; + return; + } + if (mCharColumn >= 8) { + mSelMenu = MENU_END; + return; + } + } else { + mSelMenu = MENU_END; + } + #elif REGION_PAL if (mCharColumn < 3) { mSelMenu = MENU_HIRA; } else if (mCharColumn < 6) { @@ -961,28 +1074,28 @@ void dName_c::menuCursorPosSet() { } void dName_c::MenuSelect() { - #if REGION_PAL || REGION_JPN - if (stick->checkRightTrigger()) { + #if TARGET_PC || REGION_PAL || REGION_JPN + if (isPalOrJpn() && stick->checkRightTrigger()) { mDoAud_seStart(Z2SE_SY_CURSOR_OPTION, NULL, 0, 0); mPrevSelMenu = mSelMenu; mSelMenu++; #if REGION_PAL if (mSelMenu > MENU_EIGO) { #else - if (mSelMenu > MENU_END) { + if (mSelMenu > EIGO_OR_END) { #endif mSelMenu = MENU_HIRA; } MenuSelectAnmInit(); mSelProc = PROC_MENU_SEL_ANM; - } else if (stick->checkLeftTrigger()) { + } else if (isPalOrJpn() && stick->checkLeftTrigger()) { mDoAud_seStart(Z2SE_SY_CURSOR_OPTION, NULL, 0, 0); mPrevSelMenu = mSelMenu; if (mSelMenu == MENU_HIRA) { #if REGION_JPN mSelMenu = MENU_END; #else - mSelMenu = MENU_EIGO; + mSelMenu = dusk::version::isRegionJpn() ? MENU_END : MENU_EIGO; #endif } else { mSelMenu--; @@ -1009,7 +1122,7 @@ void dName_c::MenuSelect() { #if REGION_PAL if (mSelMenu == MENU_EIGO) { #else - if (mSelMenu == MENU_END) { + if (mSelMenu == EIGO_OR_END) { #endif if (nameCheck() != 0) { mDoAud_seStart(Z2SE_SY_NAME_OK, NULL, 0, 0); @@ -1024,7 +1137,7 @@ void dName_c::MenuSelect() { #if REGION_PAL if (mSelMenu == MENU_EIGO) { #else - if (mSelMenu == MENU_END) { + if (mSelMenu == EIGO_OR_END) { #endif if (nameCheck() != 0) { mDoAud_seStart(Z2SE_SY_NAME_OK, NULL, 0, 0); @@ -1067,9 +1180,11 @@ void dName_c::MenuSelectAnm2() { if (canMove == true) { if (prevMenu_i != mojiSet_i) { mMenuText[prevMenu_i]->setWhite(JUtility::TColor(0x96, 0x96, 0x96, 0xFF)); - #if REGION_PAL || REGION_JPN + #if TARGET_PC || REGION_PAL || REGION_JPN + IF_DUSK_BLOCK(isPalOrJpn()) mMenuIcon[mojiSet_i]->scale(g_nmHIO.mMenuScale, g_nmHIO.mMenuScale); mMenuText[mojiSet_i]->setWhite(JUtility::TColor(0xC8, 0xC8, 0xC8, 0xFF)); + IF_DUSK_BLOCK_END #endif } selectCursorMove(); @@ -1081,6 +1196,11 @@ void dName_c::MenuSelectAnm2() { void dName_c::MenuSelectAnm3() {} void dName_c::menuAbtnSelect() { +#if TARGET_PC + if (dusk::version::isRegionPal() && mSelMenu == MENU_EIGO) { + goto pal_eigo; + } +#endif switch (mSelMenu) { case MENU_HIRA: case MENU_KATA: @@ -1098,6 +1218,7 @@ void dName_c::menuAbtnSelect() { #else case MENU_END: #endif + IF_DUSK(pal_eigo:) int nameNum = nameCheck(); if (nameNum != 0) { playNameSet(nameNum); @@ -1116,44 +1237,33 @@ void dName_c::backSpace() { if (mCurPos != 0) { mDoAud_seStart(Z2SE_SY_NAME_DELETE, NULL, 0, 0); - #if REGION_JPN - // ' ' (full-width space) - if (mCurPos == 8 && mChrInfo[7].mCharacter != '\x81\x40') { - #else - if (mCurPos == 8 && mChrInfo[7].mCharacter != ' ') { - #endif + if (mCurPos == 8 && mChrInfo[7].mCharacter != SPACE_MAYBE_FULL) { mChrInfo[7].mColumn = 7; mChrInfo[7].mRow = 1; - #if REGION_PAL || REGION_JPN + #if TARGET_PC + mChrInfo[7].mMojiSet = isPalOrJpn() ? MOJI_HIRA : MOJI_EIGO; + #elif REGION_PAL || REGION_JPN mChrInfo[7].mMojiSet = MOJI_HIRA; #else mChrInfo[7].mMojiSet = MOJI_EIGO; #endif mChrInfo[7].field_0x3 = 1; - #if REGION_JPN - // ' ' (full-width space) - mChrInfo[7].mCharacter = '\x81\x40'; - #else - mChrInfo[7].mCharacter = ' '; - #endif + mChrInfo[7].mCharacter = SPACE_MAYBE_FULL; } else { for (int i = mCurPos - 1; i < 7; i++) { mChrInfo[i] = mChrInfo[i + 1]; } mChrInfo[7].mColumn = 7; mChrInfo[7].mRow = 1; - #if REGION_PAL || REGION_JPN +#if TARGET_PC + mChrInfo[7].mMojiSet = isPalOrJpn() ? MOJI_HIRA : MOJI_EIGO; +#elif REGION_PAL || REGION_JPN mChrInfo[7].mMojiSet = MOJI_HIRA; #else mChrInfo[7].mMojiSet = MOJI_EIGO; #endif mChrInfo[7].field_0x3 = 1; - #if REGION_JPN - // ' ' (full-width space) - mChrInfo[7].mCharacter = '\x81\x40'; - #else - mChrInfo[7].mCharacter = ' '; - #endif + mChrInfo[7].mCharacter = SPACE_MAYBE_FULL; } setNameText(); @@ -1164,7 +1274,31 @@ void dName_c::backSpace() { } void dName_c::mojiListChange() { - #if REGION_PAL + #if TARGET_PC + const char** mojiSet; + if (dusk::version::isRegionPal()) { + switch (mMojiSet) { + case MOJI_HIRA: + mojiSet = l_mojiEisuPal_1; + break; + case MOJI_KATA: + mojiSet = l_mojiEisuPal_2; + break; + } + } else { + switch (mMojiSet) { + case MOJI_HIRA: + mojiSet = l_mojiHira; + break; + case MOJI_KATA: + mojiSet = l_mojikata; + break; + case MOJI_EIGO: + mojiSet = l_mojiEisu; + break; + } + } + #elif REGION_PAL char** mojiSet; switch (mMojiSet) { @@ -1212,7 +1346,8 @@ void dName_c::mojiListChange() { strcpy(mMojiText[i], buf); } - #if REGION_PAL || REGION_JPN + #if TARGET_PC || REGION_PAL || REGION_JPN + IF_DUSK_BLOCK(isPalOrJpn()) if (mSelProc == PROC_MOJI_SELECT) { mMenuIcon[mMojiSet]->scale(g_nmHIO.mMenuScale, g_nmHIO.mMenuScale); mMenuText[mMojiSet]->setWhite(JUtility::TColor(0xC8, 0xC8, 0xC8, 0xFF)); @@ -1221,6 +1356,7 @@ void dName_c::mojiListChange() { mMenuText[mPrevMojiSet]->setWhite(JUtility::TColor(0x96, 0x96, 0x96, 0xFF)); } } + IF_DUSK_BLOCK_END #endif } @@ -1241,9 +1377,11 @@ void dName_c::menuCursorMove2() { if (menu_i != mojiSet_i) { mMenuIcon[menu_i]->scale(g_nmHIO.mMenuScale, g_nmHIO.mMenuScale); mMenuText[menu_i]->setWhite(JUtility::TColor(0xC8, 0xC8, 0xC8, 0xFF)); - #if REGION_PAL || REGION_JPN + #if TARGET_PC || REGION_PAL || REGION_JPN + IF_DUSK_BLOCK(isPalOrJpn()) mMenuIcon[mojiSet_i]->scale(1.0f, 1.0f); mMenuText[mojiSet_i]->setWhite(JUtility::TColor(0x96, 0x96, 0x96, 0xFF)); + IF_DUSK_BLOCK_END #endif } @@ -1265,7 +1403,9 @@ void dName_c::selectCursorPosSet(int row) { mCharColumn = 3; break; case MENU_EIGO: - #if REGION_PAL + #if TARGET_PC + mCharColumn = dusk::version::isRegionPal() ? 8 : 6; + #elif REGION_PAL mCharColumn = 8; #else mCharColumn = 6; @@ -1481,9 +1621,11 @@ void dName_c::screenSet() { #endif } - #if !(REGION_PAL || REGION_JPN) + #if TARGET_PC || !(REGION_PAL || REGION_JPN) + IF_DUSK_BLOCK(!isPalOrJpn()) mMenuIcon[0]->hide(); mMenuIcon[1]->hide(); + IF_DUSK_BLOCK_END #endif mMojiPane = nameIn.NameInScr->search(MULTI_CHAR('moji_n')); @@ -1501,25 +1643,28 @@ void dName_c::screenSet() { ((J2DTextBox*)nameTagPane[i])->setFont(nameIn.font); ((J2DTextBox*)nameTagPane[i])->setString(72, ""); ((J2DTextBox*)nameTagPane[i])->setWhite(JUtility::TColor(0xC8, 0xC8, 0xC8, 0xFF)); - #if REGION_PAL + #if TARGET_PC || REGION_PAL + IF_DUSK_BLOCK(dusk::version::isRegionPal()) ((J2DTextBox*)nameTagPane[i])->resize(24.0f, 23.0f); + IF_DUSK_BLOCK_END #endif mNameText[i] = ((J2DTextBox*)nameTagPane[i])->getStringPtr(); } - #if REGION_PAL + #if REGION_PAL // DUSK version note: this code mutates strings. We just edit the table. + IF_DUSK_BLOCK(dusk::version::isRegionPal()) int idx = 2; - static u8 palMoji00[13] = { + static const u8 palMoji00[13] = { 0xC0, 0xC1, 0xC2, 0xC4, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, }; - static u8 palMoji01[13] = { + static const u8 palMoji01[13] = { 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD6, 0x8C, 0xD9, 0xDA, 0xDB, 0xDC, 0x2D, }; - static u8 palMoji10[13] = { + static const u8 palMoji10[13] = { 0xE0, 0xE1, 0xE2, 0xE4, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, }; - static u8 palMoji11[13] = { + static const u8 palMoji11[13] = { 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF6, 0x9C, 0xF9, 0xFA, 0xFB, 0xFC, 0xDF, }; @@ -1536,6 +1681,7 @@ void dName_c::screenSet() { l_mojiEisuPal_2[idx + 1][0] = palMoji11[i]; l_mojiEisuPal_2[idx + 1][1] = 0; } + IF_DUSK_BLOCK_END #endif mCharColumn = 0; @@ -1574,18 +1720,15 @@ void dName_c::displayInit() { mNameCursor[i]->hide(); mChrInfo[i].mColumn = 7; mChrInfo[i].mRow = 1; - #if REGION_PAL || REGION_JPN + #if TARGET_PC + mChrInfo[i].mMojiSet = isPalOrJpn() ? MOJI_HIRA : MOJI_EIGO; + #elif REGION_PAL || REGION_JPN mChrInfo[i].mMojiSet = MOJI_HIRA; #else mChrInfo[i].mMojiSet = MOJI_EIGO; #endif mChrInfo[i].field_0x3 = 1; - #if REGION_JPN - // ' ' (full-width space) - mChrInfo[i].mCharacter = '\x81\x40'; - #else - mChrInfo[i].mCharacter = ' '; - #endif + mChrInfo[i].mCharacter = SPACE_MAYBE_FULL; } mIsInputEnd = false; @@ -1596,7 +1739,63 @@ void dName_c::NameStrSet() { int i = 0; while (*moji != 0) { - #if REGION_PAL + #if TARGET_PC + if (dusk::version::isRegionPal()) { + mChrInfo[i].mCharacter = static_cast(*moji); + + for (int j = 0; j < 65; j++) { + if (mChrInfo[i].mCharacter == *(u8*)l_mojiEisuPal_1[j] || + mChrInfo[i].mCharacter == *(u16*)l_mojiEisuPal_2[j]) + { + mChrInfo[i].mColumn = j / 5; + mChrInfo[i].mRow = j % 5; + mChrInfo[i].mMojiSet = MOJI_HIRA; + break; + } + } + moji++; + i++; + } else { + if (*(u8*)moji >> 4 == 8 || *(u8*)moji >> 4 == 9) { + mChrInfo[i].mCharacter = *(u16*)moji; + + for (int j = 0; j < 65; j++) { + if (mChrInfo[i].mCharacter == *(u16*)l_mojiHira[j] || + mChrInfo[i].mCharacter == *(u16*)l_mojiHira2[j] || + mChrInfo[i].mCharacter == *(u16*)l_mojiHira3[j]) + { + mChrInfo[i].mColumn = j / 5; + mChrInfo[i].mRow = j % 5; + mChrInfo[i].mMojiSet = MOJI_HIRA; + break; + } else if (mChrInfo[i].mCharacter == *(u16*)l_mojikata[j] || + mChrInfo[i].mCharacter == *(u16*)l_mojikata2[j] || + mChrInfo[i].mCharacter == *(u16*)l_mojikata3[j]) + { + mChrInfo[i].mColumn = j / 5; + mChrInfo[i].mRow = j % 5; + mChrInfo[i].mMojiSet = MOJI_KATA; + break; + } + } + moji += 2; + i++; + } else { + mChrInfo[i].mCharacter = *moji; + + for (int j = 0; j < 65; j++) { + if (mChrInfo[i].mCharacter == *(u8*)l_mojiEisu[j]) { + mChrInfo[i].mColumn = j / 5; + mChrInfo[i].mRow = j % 5; + mChrInfo[i].mMojiSet = MOJI_EIGO; + break; + } + } + moji++; + i++; + } + } + #elif REGION_PAL mChrInfo[i].mCharacter = static_cast(*moji); for (int j = 0; j < 65; j++) { @@ -1669,7 +1868,9 @@ s32 dName_c::getMenuPosIdx(u8 selPos) { result = 1; break; case 2: - #if REGION_PAL + #if TARGET_PC + result = dusk::version::isRegionPal() ? 3 : 2; + #elif REGION_PAL result = 3; #else result = 2; diff --git a/src/d/d_s_logo.cpp b/src/d/d_s_logo.cpp index f04df0fa39..cc5d0114a4 100644 --- a/src/d/d_s_logo.cpp +++ b/src/d/d_s_logo.cpp @@ -24,6 +24,7 @@ #include "JSystem/JUtility/JUTConsole.h" #include "dusk/logging.h" +#include "dusk/version.hpp" #if !PLATFORM_GCN #include @@ -44,7 +45,12 @@ struct homeBtnData { }; #endif -#if VERSION == VERSION_SHIELD +#if TARGET_PC +using namespace dusk::version; + +#define LOGO_ARC versionSelect({{GameVersion::GcnJpn, "Logo"}, {GameVersion::GcnPal, "LogoPal"}}, "LogoUs") +#define MSG_PATH versionSelect({{GameVersion::GcnJpn, "/res/Msgjp/bmgres.arc"}}, "/res/Msgus/bmgres.arc") +#elif VERSION == VERSION_SHIELD #define LOGO_ARC "LogoUs" #define MSG_PATH "/res/Msgcn/bmgres.arc" #elif VERSION == VERSION_GCN_JPN @@ -789,7 +795,13 @@ dScnLogo_c::~dScnLogo_c() { JKR_DELETE(mProgressiveNo); JKR_DELETE(mProgressiveSel); - #if VERSION == VERSION_GCN_PAL + #if TARGET_PC + if (getGameVersion() == GameVersion::GcnPal) { + mpPalLogoResCommand->getArchive()->removeResourceAll(); + mpPalLogoResCommand->getArchive()->unmount(); + mpPalLogoResCommand->destroy(); + } + #elif VERSION == VERSION_GCN_PAL mpPalLogoResCommand->getArchive()->removeResourceAll(); mpPalLogoResCommand->getArchive()->unmount(); mpPalLogoResCommand->destroy(); @@ -951,7 +963,8 @@ static int phase_0(dScnLogo_c* i_this) { JUT_ASSERT(1528, i_this->mLogo01Heap != NULL); JKRHEAP_NAME(i_this->mLogo01Heap, "Logo01"); - #if VERSION == VERSION_GCN_PAL + #if TARGET_PC || VERSION == VERSION_GCN_PAL + IF_DUSK_BLOCK(getGameVersion() == GameVersion::GcnPal) switch (i_this->getPalLanguage()) { case 1: i_this->mpPalLogoResCommand = mDoDvdThd_mountArchive_c::create("/res/Layout/LogoPalGm.arc", 0, NULL); @@ -970,6 +983,7 @@ static int phase_0(dScnLogo_c* i_this) { i_this->mpPalLogoResCommand = mDoDvdThd_mountArchive_c::create("/res/Layout/LogoPalUk.arc", 0, NULL); break; } + IF_DUSK_BLOCK_END #endif #if PLATFORM_WII || PLATFORM_SHIELD @@ -990,7 +1004,8 @@ static int phase_1(dScnLogo_c* i_this) { } #endif - #if VERSION == VERSION_GCN_PAL + #if TARGET_PC || VERSION == VERSION_GCN_PAL + IF_DUSK_BLOCK(getGameVersion() == GameVersion::GcnPal) if (!mDoDvdThd::SyncWidthSound) { return cPhs_INIT_e; } @@ -998,6 +1013,7 @@ static int phase_1(dScnLogo_c* i_this) { if (!i_this->mpPalLogoResCommand->sync()) { return cPhs_INIT_e; } + IF_DUSK_BLOCK_END #endif int rt; @@ -1237,7 +1253,113 @@ void dScnLogo_c::logoInitGC() { ResTIMG* dolbyImg = (ResTIMG*)dComIfG_getObjectRes(LOGO_ARC, 3); mDolbyLogo = JKR_NEW dDlst_2D_c(dolbyImg, 189, 150, 232, 112, 255); -#if VERSION == VERSION_GCN_PAL +#if TARGET_PC + if (getGameVersion() == GameVersion::GcnPal) { + u8 language = getPalLanguage(); + if (language >= 5) { + language = 0; + } + + static const char* choice[] = { + "50_60_choice_eng.bti", + "50_60_choice_ger.bti", + "50_60_choice_fra.bti", + "50_60_choice_spa.bti", + "50_60_choice_ita.bti", + }; + + static const char* yes[] = { + "60_set_eng.bti", + "60_set_ger.bti", + "60_set_fra.bti", + "60_set_spa.bti", + "60_set_ita.bti", + }; + + static const char* no[] = { + "50_set_eng.bti", + "50_set_ger.bti", + "50_set_fra.bti", + "50_set_spa.bti", + "50_set_ita.bti", + }; + + static const char* prog[] = { + "progressive_pro.bti", + "progressive_pro_gm.bti", + "progressive_pro_fr.bti", + "progressive_pro_sp.bti", + "progressive_pro_it.bti", + }; + + static const char* intr[] = { + "progressive_inter.bti", + "progressive_inter_gm.bti", + "progressive_inter_fr.bti", + "progressive_inter_sp.bti", + "progressive_inter_it.bti", + }; + + static const char* warning[] = { + "warning.bti", + "warning_gm.bti", + "warning_fr.bti", + "warning_sp.bti", + "warning_it.bti", + }; + + static const char* warningPs[] = { + "warning_pstart.bti", + "warning_pstart_gm.bti", + "warning_pstart_fr.bti", + "warning_pstart_sp.bti", + "warning_pstart_it.bti", + }; + + ResTIMG* warningImg = (ResTIMG*)mpPalLogoResCommand->getArchive()->getResource('DAT ', warning[language]); + mWarning = JKR_NEW dDlst_2D_c(warningImg, 0, 0, FB_WIDTH, FB_HEIGHT, 255); + + ResTIMG* warnStartImg = (ResTIMG*)mpPalLogoResCommand->getArchive()->getResource('DAT ', warningPs[language]); + mWarningStart = JKR_NEW dDlst_2D_c(warnStartImg, 0, 359, FB_WIDTH, 48, 255); + + ResTIMG* progChoiceImg = (ResTIMG*)mpPalLogoResCommand->getArchive()->getResource('DAT ', choice[language]); + mProgressiveChoice = JKR_NEW dDlst_2D_c(progChoiceImg, 113, 143, 416, 210, 255); + + ResTIMG* progYesImg = (ResTIMG*)mpPalLogoResCommand->getArchive()->getResource('DAT ', yes[language]); + mProgressiveYes = JKR_NEW dDlst_2D_c(progYesImg, 121, 352, 200, 72, 255); + mProgressiveYes->getPicture()->setWhite(JUtility::TColor(160, 160, 160, 255)); + + ResTIMG* progNoImg = (ResTIMG*)mpPalLogoResCommand->getArchive()->getResource('DAT ', no[language]); + mProgressiveNo = JKR_NEW dDlst_2D_c(progNoImg, 320, 352, 200, 72, 255); + mProgressiveNo->getPicture()->setWhite(JUtility::TColor(160, 160, 160, 255)); + + mProgressivePro = (ResTIMG*)mpPalLogoResCommand->getArchive()->getResource('DAT ', prog[language]); + mProgressiveInter = (ResTIMG*)mpPalLogoResCommand->getArchive()->getResource('DAT ', intr[language]); + mProgressiveSel = JKR_NEW dDlst_2D_c(mProgressivePro, 153, 309, 336, 88, 255); + } else { + ResTIMG* warningImg = (ResTIMG*)dComIfG_getObjectRes(LOGO_ARC, 10); + mWarning = JKR_NEW dDlst_2D_c(warningImg, 0, 0, FB_WIDTH, FB_HEIGHT, 255); + + ResTIMG* warnStartImg = (ResTIMG*)dComIfG_getObjectRes(LOGO_ARC, 11); + mWarningStart = JKR_NEW dDlst_2D_c(warnStartImg, 0, 359, FB_WIDTH, 48, 255); + + ResTIMG* progChoiceImg = (ResTIMG*)dComIfG_getObjectRes(LOGO_ARC, 5); + mProgressiveChoice = JKR_NEW dDlst_2D_c(progChoiceImg, 113, 281, 416, 72, 255); + + ResTIMG* progYesImg = (ResTIMG*)dComIfG_getObjectRes(LOGO_ARC, 9); + mProgressiveYes = JKR_NEW dDlst_2D_c(progYesImg, 211, 372, 80, 32, 255); + mProgressiveYes->getPicture()->setWhite(JUtility::TColor(160, 160, 160, 255)); + + ResTIMG* progNoImg = (ResTIMG*)dComIfG_getObjectRes(LOGO_ARC, 7); + mProgressiveNo = JKR_NEW dDlst_2D_c(progNoImg, 350, 372, 80, 32, 255); + mProgressiveNo->getPicture()->setWhite(JUtility::TColor(160, 160, 160, 255)); + + mProgressivePro = (ResTIMG*)dComIfG_getObjectRes(LOGO_ARC, 8); + mProgressiveInter = (ResTIMG*)dComIfG_getObjectRes(LOGO_ARC, 6); + mProgressiveSel = JKR_NEW dDlst_2D_c(mProgressivePro, 153, 309, 336, 88, 255); + } + +#elif VERSION == VERSION_GCN_PAL u8 language = getPalLanguage(); if (language >= 5) { language = 0; @@ -1395,7 +1517,30 @@ void dScnLogo_c::dvdDataLoad() { mpButtonCommand = aramMount(BUTTON_RES_PATH, mDoExt_getJ2dHeap()); mpCardIconCommand = aramMount(ICON_RES_PATH, mDoExt_getJ2dHeap()); - #if VERSION == VERSION_GCN_PAL + #if TARGET_PC + if (getGameVersion() == GameVersion::GcnPal) { + switch (getPalLanguage()) { + case 1: + mpBmgResCommand = onMemMount("/res/Msgde/bmgres.arc"); + break; + case 2: + mpBmgResCommand = onMemMount("/res/Msgfr/bmgres.arc"); + break; + case 3: + mpBmgResCommand = onMemMount("/res/Msgsp/bmgres.arc"); + break; + case 4: + mpBmgResCommand = onMemMount("/res/Msgit/bmgres.arc"); + break; + case 0: + default: + mpBmgResCommand = onMemMount("/res/Msguk/bmgres.arc"); + break; + } + } else { + mpBmgResCommand = onMemMount(MSG_PATH); + } + #elif VERSION == VERSION_GCN_PAL switch (getPalLanguage()) { case 1: mpBmgResCommand = onMemMount("/res/Msgde/bmgres.arc"); @@ -1435,7 +1580,10 @@ void dScnLogo_c::dvdDataLoad() { mpMsgResCommand[1] = aramMount(MSG_RES1_PATH, mDoExt_getJ2dHeap()); mpMsgResCommand[2] = aramMount(MSG_RES2_PATH, mDoExt_getJ2dHeap()); mpMsgResCommand[3] = aramMount(MSG_RES3_PATH, mDoExt_getJ2dHeap()); -#if VERSION == VERSION_GCN_JPN +#if TARGET_PC + const auto res4Path = versionSelect({{GameVersion::GcnJpn, "/res/Layout/msgres04.arc"}}, "/res/Layout/msgres04F.arc"); + mpMsgResCommand[4] = aramMount( res4Path, mDoExt_getJ2dHeap()); +#elif VERSION == VERSION_GCN_JPN mpMsgResCommand[4] = aramMount("/res/Layout/msgres04.arc", mDoExt_getJ2dHeap()); #else mpMsgResCommand[4] = aramMount("/res/Layout/msgres04F.arc", mDoExt_getJ2dHeap()); @@ -1445,7 +1593,23 @@ void dScnLogo_c::dvdDataLoad() { mpMain2DCommand = onMemMount(MAIN2D_PATH); -#if VERSION == VERSION_GCN_JPN +#if TARGET_PC + const auto fontResPath = versionSelect( + { + {GameVersion::GcnJpn, "/res/Fontjp/fontres.arc"}, + {GameVersion::GcnPal, "/res/Fonteu/fontres.arc"}, + }, "/res/Fontus/fontres.arc"); + const auto fontRubyPath = versionSelect( + { + {GameVersion::GcnJpn, "/res/Fontjp/rubyres.arc"}, + {GameVersion::GcnPal, "/res/Fonteu/rubyres.arc"}, + }, "/res/Fontus/rubyres.arc"); + + // Note: GCN_JPN mounts this archive as tail instead of head. + // I'm guessing this is fine since we have more RAM. + mpFontResCommand = onMemMount(fontResPath); + mpRubyResCommand = onMemMount(fontRubyPath); +#elif VERSION == VERSION_GCN_JPN mpFontResCommand = mDoDvdThd_mountXArchive_c::create("/res/Fontjp/fontres.arc", 1, JKRArchive::MOUNT_MEM, NULL); mpRubyResCommand = onMemMount("/res/Fontjp/rubyres.arc"); #elif VERSION == VERSION_GCN_PAL @@ -1545,7 +1709,7 @@ static int dScnLogo_IsDelete(dScnLogo_c* i_this) { return 1; } -#if VERSION == VERSION_GCN_PAL || PLATFORM_WII || PLATFORM_SHIELD +#if TARGET_PC || VERSION == VERSION_GCN_PAL || PLATFORM_WII || PLATFORM_SHIELD u8 dScnLogo_c::getPalLanguage() { u8 language; diff --git a/src/d/d_save.cpp b/src/d/d_save.cpp index 3289a49c64..be95d1f190 100644 --- a/src/d/d_save.cpp +++ b/src/d/d_save.cpp @@ -16,6 +16,8 @@ #include #include +#include "dusk/version.hpp" + #if PLATFORM_WII || PLATFORM_SHIELD #include #include @@ -1027,7 +1029,7 @@ void dSv_player_config_c::init() { mAttentionType = 0; mVibration = 1; -#if DEBUG +#if DEBUG // DUSK VERSION SUPPORT: This field isn't used, so we can ignore it. mLanguage = SCGetLanguage(); #elif REGION_PAL || VERSION >= VERSION_WII_USA_R2 mLanguage = OSGetLanguage(); @@ -1072,7 +1074,8 @@ void dSv_player_config_c::setVibration(u8 i_status) { } u8 dSv_player_config_c::getPalLanguage() const { -#if VERSION == VERSION_GCN_PAL +#if TARGET_PC || VERSION == VERSION_GCN_PAL + IF_DUSK_BLOCK(dusk::version::getGameVersion() == dusk::version::GameVersion::GcnPal) switch (OSGetLanguage()) { case 0: return LANGUAGE_ENGLISH; @@ -1085,6 +1088,7 @@ u8 dSv_player_config_c::getPalLanguage() const { case 4: return LANGUAGE_ITALIAN; } + IF_DUSK_BLOCK_END #elif VERSION >= VERSION_WII_USA_R0 switch (SCGetLanguage()) { case 1: diff --git a/src/dusk/config.cpp b/src/dusk/config.cpp index 176967359d..856cdce4a3 100644 --- a/src/dusk/config.cpp +++ b/src/dusk/config.cpp @@ -154,6 +154,7 @@ namespace dusk::config { template class ConfigImpl; template class ConfigImpl; template class ConfigImpl; + template class ConfigImpl; } void dusk::config::Register(ConfigVarBase& configVar) { diff --git a/src/dusk/crash_reporting.cpp b/src/dusk/crash_reporting.cpp index 0499f0d6a1..657e5ef5d2 100644 --- a/src/dusk/crash_reporting.cpp +++ b/src/dusk/crash_reporting.cpp @@ -167,7 +167,6 @@ void InitializeCrashReporting() { sentry_set_tag("git_branch", DUSK_WC_BRANCH); sentry_set_tag("build_type", DUSK_BUILD_TYPE); - sentry_set_tag("tp_version", DUSK_TP_VERSION); g_sentryInitialized = true; DuskLog.info("Initialized Sentry crash reporting"); diff --git a/src/dusk/dvd_asset.cpp b/src/dusk/dvd_asset.cpp index b9e0729be9..75c82107cc 100644 --- a/src/dusk/dvd_asset.cpp +++ b/src/dusk/dvd_asset.cpp @@ -80,8 +80,19 @@ static s32 DolVaToFileOffset(u32 va) { return -1; } -bool LoadDolAsset(void* dst, u32 virtualAddress, s32 size) { - s32 fileOffset = DolVaToFileOffset(virtualAddress); +static u32 GetOffsetForVersion(std::initializer_list version) { + const auto gameVersion = dusk::version::getGameVersion(); + for (auto elem : version) { + if (elem.mGameVersion == gameVersion) { + return elem.mOffset; + } + } + + DuskLog.fatal("Unable to find offset for this game version!"); +} + +bool LoadDolAsset(void* dst, std::initializer_list virtualAddress, s32 size) { + s32 fileOffset = DolVaToFileOffset(GetOffsetForVersion(virtualAddress)); if (fileOffset < 0) { return false; } @@ -95,13 +106,16 @@ bool LoadDolAsset(void* dst, u32 virtualAddress, s32 size) { return true; } -bool LoadRelAsset(void* dst, const char* dvdPath, s32 offset, s32 size) { - void* p = JKRDvdRipper::loadToMainRAM(dvdPath, (u8*)dst, EXPAND_SWITCH_UNKNOWN1, (u32)size, nullptr, JKRDvdRipper::ALLOC_DIRECTION_FORWARD, (u32)offset, nullptr, nullptr); - if (!p) DuskLog.fatal("dvd_asset: failed to load {} (offset={:#x} size={:#x})", dvdPath, offset, size); +bool LoadRelAsset(void* dst, const char* dvdPath, std::initializer_list offset, s32 size) { + auto resOffset = GetOffsetForVersion(offset); + void* p = JKRDvdRipper::loadToMainRAM(dvdPath, (u8*)dst, EXPAND_SWITCH_UNKNOWN1, (u32)size, nullptr, JKRDvdRipper::ALLOC_DIRECTION_FORWARD, resOffset, nullptr, nullptr); + if (!p) DuskLog.fatal("dvd_asset: failed to load {} (offset={:#x} size={:#x})", dvdPath, resOffset, size); return p != nullptr; } -bool LoadArchivedRelAsset(void* dst, u32 memType, const char* relFileName, s32 offset, s32 size) { +bool LoadArchivedRelAsset(void* dst, u32 memType, const char* relFileName, std::initializer_list offset, s32 size) { + auto resOffset = GetOffsetForVersion(offset); + // On TARGET_PC, cDyl_InitCallback skips DynamicModuleControl::initialize() due to static linking // Mount RELS.arc on first use so sArchive is available static bool s_mountAttempted = false; @@ -118,7 +132,7 @@ bool LoadArchivedRelAsset(void* dst, u32 memType, const char* relFileName, s32 o DuskLog.fatal("dvd_asset: {} not found in RELS archive", relFileName); return false; } - std::memcpy(dst, rel + offset, size); + std::memcpy(dst, rel + resOffset, size); return true; } diff --git a/src/dusk/imgui/ImGuiPreLaunchWindow.cpp b/src/dusk/imgui/ImGuiPreLaunchWindow.cpp index 2727e78718..6347e9bc01 100644 --- a/src/dusk/imgui/ImGuiPreLaunchWindow.cpp +++ b/src/dusk/imgui/ImGuiPreLaunchWindow.cpp @@ -22,6 +22,10 @@ typedef void (ImGuiPreLaunchWindow::*drawFunc)(); drawFunc drawTable[2] = {&ImGuiPreLaunchWindow::drawMainMenu, &ImGuiPreLaunchWindow::drawOptions}; +static constexpr std::array skLanguageNames = { + "English", "German", "French", "Spanish", "Italian" +}; + static constexpr std::array skGameDiscFileFilters{{ {"Game Disc Images", "iso;gcm;ciso;gcz;nfs;rvz;wbfs;wia;tgc"}, {"All Files", "*"}, @@ -195,6 +199,20 @@ void ImGuiPreLaunchWindow::drawOptions() { false); } + // TODO: Only show if PAL disc selected? + // Language selection + auto selectedLanguage = getSettings().game.language.getValue(); + if (ImGui::BeginCombo("Language", skLanguageNames[static_cast(selectedLanguage)])) { + for (u8 i = 0; i < skLanguageNames.size(); ++i) { + if (ImGui::Selectable(skLanguageNames[i])) { + getSettings().game.language.setValue(static_cast(i)); + config::Save(); + } + } + + ImGui::EndCombo(); + } + AuroraBackend configuredBackend = BACKEND_AUTO; const std::string& configuredBackendId = getSettings().backend.graphicsBackend; if (!try_parse_backend(configuredBackendId, configuredBackend)) { diff --git a/src/dusk/iso_validate.cpp b/src/dusk/iso_validate.cpp index 755b4eede0..0b4a19ae9c 100644 --- a/src/dusk/iso_validate.cpp +++ b/src/dusk/iso_validate.cpp @@ -19,6 +19,7 @@ constexpr const char* TP_GAME_IDS[] = { constexpr const char* SUPPORTED_TP_GAME_IDS[] = { "GZ2E01", // GCN USA + "GZ2P01", // GCN PAL }; template diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index 3e6ee733fe..c7d19beb31 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -20,6 +20,8 @@ UserSettings g_userSettings = { }, .game = { + .language { "game.language", GameLanguage::English }, + // Quality of Life .enableQuickTransform {"game.enableQuickTransform", false}, .hideTvSettingsScreen {"game.hideTvSettingsScreen", false}, @@ -123,6 +125,7 @@ void registerSettings() { Register(g_userSettings.audio.enableReverb); // Game + Register(g_userSettings.game.language); Register(g_userSettings.game.enableQuickTransform); Register(g_userSettings.game.hideTvSettingsScreen); Register(g_userSettings.game.skipWarningScreen); diff --git a/src/dusk/version.cpp b/src/dusk/version.cpp new file mode 100644 index 0000000000..e925dabaf8 --- /dev/null +++ b/src/dusk/version.cpp @@ -0,0 +1,82 @@ +#include "dusk/version.hpp" + +#include "dusk/logging.h" + +namespace dusk::version { + +using namespace std::string_view_literals; + +static bool versionInitialized; +static GameVersion gameVersion; +static DVDDiskID diskId; + +void init() { + versionInitialized = true; + + if (!DVDLowReadDiskID(&diskId, nullptr)) { + DuskLog.fatal("DVDLowReadDiskID failed to return instantly."); + } + + std::string_view company(diskId.company, sizeof(diskId.company)); + std::string_view game(diskId.gameName, sizeof(diskId.gameName)); + + if (company != "01"sv) { + DuskLog.fatal("Wrong company ID in disc: {}", company); + } + + if (game == "GZ2E"sv) { + gameVersion = GameVersion::GcnUsa; + } else if (game == "GZ2P") { + gameVersion = GameVersion::GcnPal; + } else { + // TODO: Handle remaining valid versions. + DuskLog.fatal("Unknown/unsupported game version in disc: {}", game); + } + + DuskLog.info("Loaded game disc is {}{}", game, company); +} + +bool isGcn() { + return getGameVersion() == GameVersion::GcnUsa + || getGameVersion() == GameVersion::GcnPal + || getGameVersion() == GameVersion::GcnJpn; +} + +bool isWii() { + return getGameVersion() == GameVersion::WiiUsaRev0 + || getGameVersion() == GameVersion::WiiUsa + || getGameVersion() == GameVersion::WiiPal + || getGameVersion() == GameVersion::WiiJpn + || getGameVersion() == GameVersion::WiiKor; +} + +bool isPalOrAtLeastWiiR2() { + return getGameVersion() == GameVersion::GcnPal || getGameVersion() >= GameVersion::WiiUsa; +} + +bool isRegionJpn() { + return getGameVersion() == GameVersion::WiiJpn || getGameVersion() == GameVersion::GcnJpn; +} + +bool isRegionPal() { + return getGameVersion() == GameVersion::WiiPal || getGameVersion() == GameVersion::GcnPal; +} + +bool isRegionUsa() { + return getGameVersion() == GameVersion::WiiUsa || getGameVersion() == GameVersion::WiiUsaRev0 + || getGameVersion() == GameVersion::GcnUsa; +} + +GameVersion getGameVersion() { + if (!versionInitialized) { + abort(); + } + + return gameVersion; +} + +const DVDDiskID& getDiskID() { + return diskId; +} + +} // namespace dusk::version \ No newline at end of file diff --git a/src/m_Do/m_Do_MemCard.cpp b/src/m_Do/m_Do_MemCard.cpp index 5cb612f128..dbf962b173 100644 --- a/src/m_Do/m_Do_MemCard.cpp +++ b/src/m_Do/m_Do_MemCard.cpp @@ -12,6 +12,7 @@ #include "os_report.h" #include "dusk/os.h" #include "dusk/main.h" +#include "dusk/version.hpp" #if PLATFORM_WII || PLATFORM_SHIELD #include @@ -79,7 +80,11 @@ void mDoMemCd_Ctrl_c::ThdInit() { #if !PLATFORM_SHIELD CARDSetLoadType((CARDFileType)dusk::getSettings().backend.cardFileType.getValue()); - CARDInit(DUSK_GAME_NAME, DUSK_GAME_VERSION); + char version[5] = {}; + char maker[3] = {}; + std::memcpy(version, dusk::version::getDiskID().gameName, 4); + std::memcpy(maker, dusk::version::getDiskID().company, 2); + CARDInit(version, maker); #endif mCopyToPos = 0; diff --git a/src/m_Do/m_Do_MemCardRWmng.cpp b/src/m_Do/m_Do_MemCardRWmng.cpp index 518bdd27e9..d7739d6158 100644 --- a/src/m_Do/m_Do_MemCardRWmng.cpp +++ b/src/m_Do/m_Do_MemCardRWmng.cpp @@ -11,6 +11,8 @@ #include #include +#include "dusk/version.hpp" + #if VERSION == VERSION_GCN_JPN #define HEADER_TITLE "ゼルダの伝説 トワイライトプリンセス" #define HEADER_COMMENT "%d月%d日のセーブデータです" @@ -313,12 +315,44 @@ s32 mDoMemCdRWm_StoreBannerNAND(NANDFileInfo* file) { #endif static void mDoMemCdRWm_BuildHeader(mDoMemCdRWm_HeaderData* header) { +#if !TARGET_PC snprintf(header->mTitle, sizeof(header->mTitle), HEADER_TITLE); +#endif OSCalendarTime time; OSTicksToCalendarTime(OSGetTime(), &time); -#if VERSION == VERSION_GCN_PAL +#if TARGET_PC + if (dusk::version::isRegionPal()) { + snprintf(header->mTitle, sizeof(header->mTitle), HEADER_TITLE); + + switch (dComIfGs_getPalLanguage()) { + case dSv_player_config_c::LANGUAGE_ENGLISH: + snprintf(header->mComment, sizeof(header->mComment), "%d/%d Save Data", time.mon + 1, time.mday); + break; + case dSv_player_config_c::LANGUAGE_GERMAN: + snprintf(header->mComment, sizeof(header->mComment), "%d/%d Spielstand", time.mday, time.mon + 1); + break; + case dSv_player_config_c::LANGUAGE_FRENCH: + snprintf(header->mComment, sizeof(header->mComment), "Donn%ces de jeu %d/%d", 0xE9, time.mday, time.mon + 1); + break; + case dSv_player_config_c::LANGUAGE_SPANISH: + snprintf(header->mComment, sizeof(header->mComment), "Datos guardados el %d/%d", time.mday, time.mon + 1); + break; + case dSv_player_config_c::LANGUAGE_ITALIAN: + snprintf(header->mComment, sizeof(header->mComment), "Dati salvati: %d/%d", time.mday, time.mon + 1); + break; + } + } else if (dusk::version::isRegionUsa()) { + snprintf(header->mTitle, sizeof(header->mTitle), HEADER_TITLE); + + snprintf(header->mComment, sizeof(header->mComment), HEADER_COMMENT, time.mon + 1, time.mday); + } else { + // TODO JPN SHIFT-JIS + // snprintf(header->mTitle, sizeof(header->mTitle), "ゼルダの伝説 トワイライトプリンセス"); + // snprintf(header->mComment, sizeof(header->mComment), "%d月%d日のセーブデータです", time.mon + 1, time.mday); + } +#elif VERSION == VERSION_GCN_PAL switch (dComIfGs_getPalLanguage()) { case dSv_player_config_c::LANGUAGE_ENGLISH: snprintf(header->mComment, sizeof(header->mComment), "%d/%d Save Data", time.mon + 1, time.mday); diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index 579cbd8c8b..d25debb38e 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -71,6 +71,7 @@ #include "dusk/config.hpp" #include "dusk/imgui/ImGuiConsole.hpp" #include "dusk/settings.h" +#include "dusk/version.hpp" #include "dusk/discord_presence.hpp" #include "tracy/Tracy.hpp" #include "f_pc/f_pc_draw.h" @@ -465,6 +466,23 @@ static constexpr PADDefaultMapping defaultPadMapping = { static bool mainCalled = false; +static u8 selectedLanguage; + +u8 OSGetLanguage() { + return selectedLanguage; +} + +static void LanguageInit() { + // Keep language at 0 (English) if not on a PAL disk. + // Doubt this matters, but avoid funky shit. + if (!dusk::version::isRegionPal()) { + return; + } + + // Cache this to avoid funky shenanigans. + selectedLanguage = static_cast(dusk::getSettings().game.language.getValue()); +} + // ========================================================================= // PC ENTRY POINT // ========================================================================= @@ -597,6 +615,9 @@ int game_main(int argc, char* argv[]) { } } + dusk::version::init(); + LanguageInit(); + OSInit(); mDoMain::sPowerOnTime = OSGetTime(); From 0e5ea0d3b1552cd00beffa05b41b889cc9a8c539 Mon Sep 17 00:00:00 2001 From: Howard Luck Date: Sat, 25 Apr 2026 15:48:45 -0600 Subject: [PATCH 031/390] fix d_meter_button flashing (#549) --- include/d/d_meter_button.h | 5 +++++ src/d/d_meter_button.cpp | 16 +++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/include/d/d_meter_button.h b/include/d/d_meter_button.h index 3028abeab5..0f05d32440 100644 --- a/include/d/d_meter_button.h +++ b/include/d/d_meter_button.h @@ -343,6 +343,11 @@ public: /* 0x624 */ f32 mMidonaPosX; /* 0x628 */ f32 mMidonaPosY; /* 0x62C */ f32 mMidonaScale; + +#ifdef TARGET_PC + bool mWasListen[2]; + bool mWasRepeat[2]; +#endif }; #endif /* D_METER_D_METER_BUTTON_H */ diff --git a/src/d/d_meter_button.cpp b/src/d/d_meter_button.cpp index d36a124d17..e55b42bc1a 100644 --- a/src/d/d_meter_button.cpp +++ b/src/d/d_meter_button.cpp @@ -368,8 +368,22 @@ void dMeterButton_c::draw() { } if (var_r3) { +#ifdef TARGET_PC + if (dusk::frame_interp::get_ui_tick_pending()) { + mWasListen[i] = var_r22; + mWasRepeat[i] = var_r23; + } else { + var_r22 = mWasListen[i]; + var_r23 = mWasRepeat[i]; + } +#endif if (var_r22) { - if (field_0x2e8[i] == 18.0f) { +#ifdef TARGET_PC + if (field_0x2e8[i] == 18.0f && dusk::frame_interp::get_ui_tick_pending()) +#else + if (field_0x2e8[i] == 18.0f) +#endif + { mDoAud_seStart(Z2SE_SY_HINT_BUTTON_BLINK, NULL, 0, 0); } From 1b792eb964d6c77ea73c485f2da256455edf5456 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sat, 25 Apr 2026 16:18:16 -0600 Subject: [PATCH 032/390] Update aurora --- extern/aurora | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/aurora b/extern/aurora index 8d9618dc4b..135e976867 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 8d9618dc4bd82e476754c5b841b85fba6ee6ddab +Subproject commit 135e976867490380356878c8bb8d1956932489c5 From ca9330b412da1e6d84ff0ae9d017206e89e1c237 Mon Sep 17 00:00:00 2001 From: Irastris Date: Sat, 25 Apr 2026 20:40:29 -0400 Subject: [PATCH 033/390] Register interp callback for d_a_obj_lv8OptiLift Fixes disappearing platforms --- src/d/actor/d_a_obj_lv8OptiLift.cpp | 41 +++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/d/actor/d_a_obj_lv8OptiLift.cpp b/src/d/actor/d_a_obj_lv8OptiLift.cpp index a8610989a7..6b6c806d64 100644 --- a/src/d/actor/d_a_obj_lv8OptiLift.cpp +++ b/src/d/actor/d_a_obj_lv8OptiLift.cpp @@ -11,6 +11,10 @@ #include "d/d_com_inf_game.h" #include "d/d_path.h" +#if TARGET_PC +#include "dusk/frame_interpolation.h" +#endif + daOptiLift_HIO_c::daOptiLift_HIO_c() { mStopDisappearTime = 30; mStartMoveTime = 30; @@ -412,7 +416,44 @@ void daOptiLift_c::setNextPoint() { mCurrentPoint = next_point; } +#if TARGET_PC +static void daOptiLift_interp_callback(bool isSimFrame, void* pUserWork) { + daOptiLift_c* lift = static_cast(pUserWork); + if (lift == NULL || lift->mpModel == NULL) { + return; + } + + g_env_light.settingTevStruct(0x10, &lift->current.pos, &lift->tevStr); + g_env_light.setLightTevColorType_MAJI(lift->mpModel, &lift->tevStr); + + J3DModelData* modelData = lift->mpModel->getModelData(); + J3DMaterial* materialp = modelData->getMaterialNodePointer(0); + + if (materialp->getTexGenBlock()->getTexMtx(1) != NULL) { + J3DTexMtxInfo* mtx_info = &materialp->getTexGenBlock()->getTexMtx(1)->getTexMtxInfo(); + if (mtx_info != NULL) { + Mtx m; + C_MTXLightOrtho(m, 100.0f, -100.0f, -100.0f, 100.0f, 1.0f, 1.0f, 0.0f, 0.0f); + mDoMtx_stack_c::XrotS(0x4000); + mDoMtx_stack_c::transM(-lift->current.pos.x, -lift->current.pos.y, -lift->current.pos.z); + cMtx_concat(m, mDoMtx_stack_c::get(), mtx_info->mEffectMtx); + } + } + + lift->mBtk.entry(modelData); + + J3DGXColor* color = materialp->getTevKColor(1); + color->r = l_HIO.mColorR; + color->g = l_HIO.mColorG; + color->b = l_HIO.mColorB; +} +#endif + int daOptiLift_c::Draw() { +#if TARGET_PC + dusk::frame_interp::add_interpolation_callback(&daOptiLift_interp_callback, this); +#endif + g_env_light.settingTevStruct(0x10, ¤t.pos, &tevStr); g_env_light.setLightTevColorType_MAJI(mpModel, &tevStr); From 6fc862814419dd36e3e06e388d3575f97b8ccb03 Mon Sep 17 00:00:00 2001 From: Howard Luck Date: Sat, 25 Apr 2026 18:44:38 -0600 Subject: [PATCH 034/390] fix gdorf horseback reins + demo cuts (#551) --- include/d/actor/d_a_b_gnd.h | 9 ++++++ src/d/actor/d_a_b_gnd.cpp | 60 +++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/include/d/actor/d_a_b_gnd.h b/include/d/actor/d_a_b_gnd.h index b9c8781ec6..0827102eec 100644 --- a/include/d/actor/d_a_b_gnd.h +++ b/include/d/actor/d_a_b_gnd.h @@ -188,6 +188,15 @@ public: /* 0x273C */ f32 mKankyoBlend; /* 0x2740 */ u8 field_0x2740; /* 0x2744 */ dMsgFlow_c mMsgFlow; +#if TARGET_PC + cXyz mReinsInterpPrev[2][16]; + cXyz mReinsInterpCurr[2][16]; + cXyz mReinsTexInterpPrev[2]; + cXyz mReinsTexInterpCurr[2]; + bool mReinsInterpPrevValid; + bool mReinsInterpCurrValid; + s8 mDemoCamSyncTicks; +#endif }; STATIC_ASSERT(sizeof(b_gnd_class) == 0x2790); diff --git a/src/d/actor/d_a_b_gnd.cpp b/src/d/actor/d_a_b_gnd.cpp index 2272c35376..cd6bce78c4 100644 --- a/src/d/actor/d_a_b_gnd.cpp +++ b/src/d/actor/d_a_b_gnd.cpp @@ -17,6 +17,9 @@ #include "Z2AudioLib/Z2Instances.h" +#include "dusk/frame_interpolation.h" +#include "dusk/settings.h" + class daB_GND_HIO_c : public JORReflexible { public: daB_GND_HIO_c(); @@ -279,6 +282,30 @@ static int h_nodeCallBack(J3DJoint* i_joint, int param_2) { return 1; } +#if TARGET_PC +static void b_gnd_rein_interp_callback(bool isSimFrame, void* pUserWork) { + b_gnd_class* i_this = (b_gnd_class*)pUserWork; + if (!i_this->mReinsInterpPrevValid || !i_this->mReinsInterpCurrValid) { + return; + } + const f32 alpha = dusk::frame_interp::get_interpolation_step(); + for (int r = 0; r < 2; r++) { + cXyz* dst = i_this->mHorseReins[r].getPos(0); + for (int i = 0; i < 16; i++) { + const cXyz& p0 = i_this->mReinsInterpPrev[r][i]; + const cXyz& p1 = i_this->mReinsInterpCurr[r][i]; + dst[i] = p0 + (p1 - p0) * alpha; + } + } + cXyz* dst = i_this->field_0x21e8.getPos(0); + for (int i = 0; i < 2; i++) { + const cXyz& p0 = i_this->mReinsTexInterpPrev[i]; + const cXyz& p1 = i_this->mReinsTexInterpCurr[i]; + dst[i] = p0 + (p1 - p0) * alpha; + } +} +#endif + static int daB_GND_Draw(b_gnd_class* i_this) { fopAc_ac_c* a_this = (fopAc_ac_c*)i_this; @@ -366,6 +393,21 @@ static int daB_GND_Draw(b_gnd_class* i_this) { i_this->field_0x21e8.update(2, l_color, &a_this->tevStr); dComIfGd_set3DlineMat(&i_this->field_0x21e8); +#if TARGET_PC + if (dusk::getSettings().game.enableFrameInterpolation) { + if (i_this->mReinsInterpCurrValid) { + memcpy(i_this->mReinsInterpPrev, i_this->mReinsInterpCurr, sizeof(i_this->mReinsInterpCurr)); + memcpy(i_this->mReinsTexInterpPrev, i_this->mReinsTexInterpCurr, sizeof(i_this->mReinsTexInterpCurr)); + i_this->mReinsInterpPrevValid = true; + } + for (int r = 0; r < 2; r++) { + memcpy(i_this->mReinsInterpCurr[r], i_this->mHorseReins[r].getPos(0), 16 * sizeof(cXyz)); + } + memcpy(i_this->mReinsTexInterpCurr, i_this->field_0x21e8.getPos(0), 2 * sizeof(cXyz)); + i_this->mReinsInterpCurrValid = true; + dusk::frame_interp::add_interpolation_callback(&b_gnd_rein_interp_callback, i_this); + } +#endif } return 1; @@ -1189,10 +1231,16 @@ static void b_gnd_h_end(b_gnd_class* i_this) { if (i_this->mDemoCamMode < 32) { i_this->mDemoCamMode = 32; +#if TARGET_PC + i_this->mDemoCamSyncTicks = 2; +#endif } else { i_this->mDemoCamMode = 34; i_this->mDemoCamTimer = 0; i_this->mMoveMode = 2; +#if TARGET_PC + i_this->mDemoCamSyncTicks = 2; +#endif } } break; @@ -2887,6 +2935,9 @@ static void demo_camera(b_gnd_class* i_this) { cXyz spF0; s8 sp8 = false; +#if TARGET_PC + const s16 entry_demo_cam_mode = i_this->mDemoCamMode; +#endif switch (i_this->mDemoCamMode) { case 0: break; @@ -3725,6 +3776,15 @@ static void demo_camera(b_gnd_class* i_this) { i_this->mDemoCamTimer = 10000; } } +#if TARGET_PC + if (entry_demo_cam_mode != i_this->mDemoCamMode) { + i_this->mDemoCamSyncTicks = 2; + } + if (i_this->mDemoCamSyncTicks > 0) { + dusk::frame_interp::request_presentation_sync(); + i_this->mDemoCamSyncTicks--; + } +#endif } static void anm_se_set(b_gnd_class* i_this) { From 574b6197a23619ed8f59b6e7bb949d69f4a7a016 Mon Sep 17 00:00:00 2001 From: madeline Date: Sat, 25 Apr 2026 18:23:12 -0700 Subject: [PATCH 035/390] achievements --- files.cmake | 3 + include/dusk/achievements.h | 65 ++++ include/dusk/settings.h | 1 + src/dusk/achievements.cpp | 467 +++++++++++++++++++++++++ src/dusk/imgui/ImGuiAchievements.cpp | 228 ++++++++++++ src/dusk/imgui/ImGuiAchievements.hpp | 23 ++ src/dusk/imgui/ImGuiConsole.cpp | 11 + src/dusk/imgui/ImGuiFirstRunPreset.cpp | 1 + src/dusk/imgui/ImGuiMenuGame.cpp | 1 + src/dusk/imgui/ImGuiMenuTools.cpp | 10 + src/dusk/imgui/ImGuiMenuTools.hpp | 6 + src/dusk/settings.cpp | 2 + 12 files changed, 818 insertions(+) create mode 100644 include/dusk/achievements.h create mode 100644 src/dusk/achievements.cpp create mode 100644 src/dusk/imgui/ImGuiAchievements.cpp create mode 100644 src/dusk/imgui/ImGuiAchievements.hpp diff --git a/files.cmake b/files.cmake index af101b6c47..01b3863505 100644 --- a/files.cmake +++ b/files.cmake @@ -1460,6 +1460,9 @@ set(DUSK_FILES src/dusk/imgui/ImGuiSaveEditor.cpp src/dusk/imgui/ImGuiStateShare.hpp src/dusk/imgui/ImGuiStateShare.cpp + src/dusk/imgui/ImGuiAchievements.hpp + src/dusk/imgui/ImGuiAchievements.cpp + src/dusk/achievements.cpp src/dusk/iso_validate.cpp src/dusk/offset_ptr.cpp src/dusk/OSContext.cpp diff --git a/include/dusk/achievements.h b/include/dusk/achievements.h new file mode 100644 index 0000000000..cd4294b6f1 --- /dev/null +++ b/include/dusk/achievements.h @@ -0,0 +1,65 @@ +#pragma once + +#include +#include +#include +#include +#include +#include "nlohmann/json.hpp" + +namespace dusk { + +enum class AchievementCategory : uint8_t { + Story, + Collection, + Challenge, + Minigame, + Glitched +}; + +struct Achievement { + const char* key; + const char* name; + const char* description; + AchievementCategory category; + bool isCounter; + int32_t goal; + int32_t progress; + bool unlocked; +}; + +// Responsible for updating a.progress. +// Use extra for any per-achievement state that must survive across frames or sessions, extra is saved +using AchievementCheckFn = std::function; + +class AchievementSystem { +public: + static AchievementSystem& get(); + + void load(); + void save(); + void tick(); + void clearAll(); + + std::vector getAchievements() const; + bool hasPendingUnlock() const { return !m_pendingUnlocks.empty(); } + std::string consumePendingUnlock(); + +private: + struct Entry { + Achievement achievement; + AchievementCheckFn check; + nlohmann::json extra; + }; + + AchievementSystem(); + static std::vector makeEntries(); + void processEntry(Entry& e); + + std::vector m_entries; + bool m_loaded = false; + bool m_dirty = false; + std::queue m_pendingUnlocks; +}; + +} // namespace dusk diff --git a/include/dusk/settings.h b/include/dusk/settings.h index 039e51af7d..8d67805ff3 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -70,6 +70,7 @@ struct UserSettings { ConfigVar disableMainHUD; ConfigVar pauseOnFocusLost; ConfigVar enableLinkDollRotation; + ConfigVar enableAchievementNotifications; // Graphics diff --git a/src/dusk/achievements.cpp b/src/dusk/achievements.cpp new file mode 100644 index 0000000000..071332a7c2 --- /dev/null +++ b/src/dusk/achievements.cpp @@ -0,0 +1,467 @@ +#include "dusk/achievements.h" +#include "dusk/io.hpp" +#include "dusk/main.h" +#include "d/d_com_inf_game.h" +#include "d/d_meter2_info.h" +#include "d/actor/d_a_alink.h" +#include "d/actor/d_a_npc4.h" +#include "d/actor/d_a_player.h" +#include "d/d_demo.h" +#include "f_pc/f_pc_name.h" + +#include +#include + +namespace dusk { + +using json = nlohmann::json; + +static void checkGoatHerding(Achievement& a, int32_t threshMs) { + if (dMeter2Info_getMaxCount() != 20 || dMeter2Info_getNowCount() != 20) { + return; + } + const int32_t elapsed = dMeter2Info_getTimeMs(); + if (elapsed > 0 && elapsed <= threshMs) { + a.progress = 1; + } +} + +static constexpr auto ACHIEVEMENTS_FILENAME = "achievements.json"; + +std::vector AchievementSystem::makeEntries() { + return { + { + { + "hero_of_twilight", + "Hero of Twilight", + "Deliver the finishing blow to Ganondorf.", + AchievementCategory::Story, + false, 0, 0, false + }, + [](Achievement& a, json&) { + const auto* link = static_cast(daPy_getPlayerActorClass()); + if (link != nullptr && link->mProcID == daAlink_c::PROC_GANON_FINISH) { + a.progress = 1; + } + }, + {} + }, + { + { + "rollgoal_8", + "Rollgoal Novice", + "Complete the first 8 rollgoal stages.", + AchievementCategory::Minigame, + true, 8, 0, false + }, + [](Achievement& a, json&) { + a.progress = std::min((int)dComIfGs_getEventReg(0xf63f), 8); + }, + {} + }, + { + { + "rollgoal_all", + "Lost Your Marbles", + "Complete all rollgoal stages.", + AchievementCategory::Minigame, + true, 64, 0, false + }, + [](Achievement& a, json&) { + if (dComIfGs_isEventBit(dSv_event_flag_c::KORO2_ALLCLEAR)) { + a.progress = 64; + } else { + a.progress = dComIfGs_getEventReg(0xf63f); + } + }, + {} + }, + { + { + "goat_30s", + "Ranch Hand", + "Herd all 20 goats into the pen in under 30 seconds.", + AchievementCategory::Minigame, + false, 0, 0, false + }, + [](Achievement& a, json&) { + checkGoatHerding(a, 30000); + }, + {} + }, + { + { + "goat_20s", + "Bane of Howard", + "Herd all 20 goats into the pen in under 20 seconds.", + AchievementCategory::Minigame, + false, 0, 0, false + }, + [](Achievement& a, json&) { + checkGoatHerding(a, 20000); + }, + {} + }, + { + { + "goat_18s", + "King of the Ranch", + "Herd all 20 goats into the pen in under 18 seconds.", + AchievementCategory::Minigame, + false, 0, 0, false + }, + [](Achievement& a, json&) { + checkGoatHerding(a, 18000); + }, + {} + }, + { + { + "cave_of_ordeals", + "Conqueror of Ordeals", + "Clear all 50 floors of the Cave of Ordeals.", + AchievementCategory::Challenge, + false, 0, 0, false + }, + [](Achievement& a, json&) { + if (daNpcF_chkEvtBit(0x1F9)) { + a.progress = 1; + } + }, + {} + }, + { + { + "cave_of_ordeals_heartless", + "Indomitable", + "Clear all 50 floors of the Cave of Ordeals with only 3 heart containers.", + AchievementCategory::Challenge, + false, 0, 0, false + }, + [](Achievement& a, json&) { + if (daNpcF_chkEvtBit(0x1F9) && dComIfGs_getMaxLife() <= 15) { + a.progress = 1; + } + }, + {} + }, + { + { + "speedrun_12h", + "Been There Done That", + "Defeat Ganondorf with a total save file play time under 12 hours.", + AchievementCategory::Challenge, + false, 0, 0, false + }, + [](Achievement& a, json&) { + const auto* link = static_cast(daPy_getPlayerActorClass()); + if (link == nullptr || link->mProcID != daAlink_c::PROC_GANON_FINISH) { + return; + } + const int64_t ticks = (static_cast(OSGetTime()) - dComIfGs_getSaveStartTime()) + dComIfGs_getSaveTotalTime(); + if (ticks / OS_TIMER_CLOCK < 12 * 3600) { + a.progress = 1; + } + }, + {} + }, + { + { + "speedrun_8h", + "Swift Blade", + "Defeat Ganondorf with a total save file play time under 6 hours.", + AchievementCategory::Challenge, + false, 0, 0, false + }, + [](Achievement& a, json&) { + const auto* link = static_cast(daPy_getPlayerActorClass()); + if (link == nullptr || link->mProcID != daAlink_c::PROC_GANON_FINISH) { + return; + } + const int64_t ticks = (static_cast(OSGetTime()) - dComIfGs_getSaveStartTime()) + dComIfGs_getSaveTotalTime(); + if (ticks / OS_TIMER_CLOCK < 8 * 3600) { + a.progress = 1; + } + }, + {} + }, + { + { + "princess_of_bugs", + "The Princess of Bugs", + "Deliver all 24 golden bugs to Agitha.", + AchievementCategory::Collection, + true, 24, 0, false + }, + [](Achievement& a, json&) { + a.progress = dComIfGs_checkGetInsectNum(); + }, + {} + }, + { + { + "all_poes", + "Poe Collector", + "Collect all 60 Poe Souls.", + AchievementCategory::Collection, + true, 60, 0, false + }, + [](Achievement& a, json&) { + a.progress = dComIfGs_getPohSpiritNum(); + }, + {} + }, + { + { + "hylian_loach", + "Legendary Catch", + "Catch a Hylian Loach.", + AchievementCategory::Collection, + false, 0, 0, false + }, + [](Achievement& a, json&) { + if (dComIfGs_getFishNum(1) > 0) { + a.progress = 1; + } + }, + {} + }, + { + { + "all_fish", + "Gone Fishin'", + "Catch all 6 species of fish.", + AchievementCategory::Collection, + true, 6, 0, false + }, + [](Achievement& a, json&) { + int nUniqueFish = 0; + for (int i = 0; i < 6; ++i) { + if (dComIfGs_getFishNum(i) != 0) { + nUniqueFish++; + } + } + a.progress = nUniqueFish; + }, + {} + }, + { + { + "a_big_heart", + "A Big Heart", + "Reach maximum health with all 20 heart containers.", + AchievementCategory::Collection, + true, 20, 0, false + }, + [](Achievement& a, json&) { + a.progress = dComIfGs_getMaxLife() / 5; + }, + {} + }, + { + { + "back_in_time", + "Back in Time", + "Perform the Back in Time glitch to play on the title screen.", + AchievementCategory::Glitched, + false, 0, 0, false + }, + [](Achievement& a, json&) { + static int titleNoDemoFrames = 0; + if (fopAcM_SearchByName(fpcNm_TITLE_e) == nullptr) { + titleNoDemoFrames = 0; + return; + } + const auto* link = static_cast(daPy_getPlayerActorClass()); + if (link != nullptr && dDemo_c::getMode() == 0) { + if (++titleNoDemoFrames >= 60) { + a.progress = 1; + } + } else { + titleNoDemoFrames = 0; + } + }, + {} + }, + { + { + "early_master_sword", + "Early Master Sword", + "Obtain the Master Sword before completing Midna's Desperate Hour.", + AchievementCategory::Glitched, + false, 0, 0, false + }, + [](Achievement& a, json&) { + if (dComIfGs_isCollectSword(COLLECT_MASTER_SWORD) && !dComIfGs_isEventBit(0x1E08)) { + a.progress = 1; + } + }, + {} + }, + { + { + "earliest_master_sword", + "Earliest Master Sword", + "Obtain the Master Sword before meeting Midna.", + AchievementCategory::Glitched, + false, 0, 0, false + }, + [](Achievement& a, json&) { + if (dComIfGs_isCollectSword(COLLECT_MASTER_SWORD) && !dComIfGs_isTransformLV(0)) { + a.progress = 1; + } + }, + {} + }, + { + { + "ultimate_delivery", + "The Ultimate Delivery", + "Have all 16 postman letters at the same time.", + AchievementCategory::Glitched, + true, 16, 0, false + }, + [](Achievement& a, json&) { + a.progress = dMeter2Info_getRecieveLetterNum(); + }, + {} + }, + { + { + "speedrun_4h", + "Hero of Time", + "Defeat Ganondorf with a total save file play time under 4 hours.", + AchievementCategory::Glitched, + false, 0, 0, false + }, + [](Achievement& a, json&) { + const auto* link = static_cast(daPy_getPlayerActorClass()); + if (link == nullptr || link->mProcID != daAlink_c::PROC_GANON_FINISH) { + return; + } + const int64_t ticks = (static_cast(OSGetTime()) - dComIfGs_getSaveStartTime()) + dComIfGs_getSaveTotalTime(); + if (ticks / OS_TIMER_CLOCK < 4 * 3600) { + a.progress = 1; + } + }, + {} + } + }; +} + +AchievementSystem::AchievementSystem() : m_entries(makeEntries()) {} + +AchievementSystem& AchievementSystem::get() { + static AchievementSystem instance; + return instance; +} + +std::string AchievementSystem::consumePendingUnlock() { + std::string msg = std::move(m_pendingUnlocks.front()); + m_pendingUnlocks.pop(); + return msg; +} + +std::vector AchievementSystem::getAchievements() const { + std::vector result; + result.reserve(m_entries.size()); + for (const auto& e : m_entries) { + result.push_back(e.achievement); + } + return result; +} + +void AchievementSystem::load() { + m_loaded = true; + const auto filePath = dusk::ConfigPath / ACHIEVEMENTS_FILENAME; + if (!std::filesystem::exists(filePath)) { + return; + } + try { + auto data = io::FileStream::ReadAllBytes(filePath.string().c_str()); + auto j = json::parse(data); + if (!j.is_object()) { + return; + } + for (auto& e : m_entries) { + if (!j.contains(e.achievement.key)) { + continue; + } + const auto& entry = j[e.achievement.key]; + if (entry.contains("progress")) { + e.achievement.progress = entry["progress"].get(); + } + if (entry.contains("unlocked")) { + e.achievement.unlocked = entry["unlocked"].get(); + } + if (entry.contains("extra")) { + e.extra = entry["extra"]; + } + } + } catch (const std::exception&) {} +} + +void AchievementSystem::save() { + json j = json::object(); + for (const auto& e : m_entries) { + json entry = { + {"progress", e.achievement.progress}, + {"unlocked", e.achievement.unlocked}, + }; + if (!e.extra.is_null()) { + entry["extra"] = e.extra; + } + j[e.achievement.key] = std::move(entry); + } + try { + io::FileStream::WriteAllText( + (dusk::ConfigPath / ACHIEVEMENTS_FILENAME).string().c_str(), + j.dump(2) + ); + } catch (const std::exception&) {} +} + +void AchievementSystem::clearAll() { + m_entries = makeEntries(); + save(); +} + +void AchievementSystem::processEntry(Entry& e) { + if (e.achievement.unlocked) { + return; + } + const int32_t prevProgress = e.achievement.progress; + e.check(e.achievement, e.extra); + + const bool progressChanged = e.achievement.progress != prevProgress; + const bool nowUnlocked = e.achievement.isCounter ? + e.achievement.progress >= e.achievement.goal : + e.achievement.progress > 0; + + if (nowUnlocked) { + e.achievement.progress = e.achievement.isCounter ? e.achievement.goal : 1; + e.achievement.unlocked = true; + m_pendingUnlocks.push(e.achievement.name); + m_dirty = true; + } else if (progressChanged) { + m_dirty = true; + } +} + +void AchievementSystem::tick() { + if (!m_loaded) { + load(); + } + if (!dusk::IsGameLaunched) { + return; + } + for (auto& e : m_entries) { + processEntry(e); + } + if (m_dirty) { + save(); + m_dirty = false; + } +} + +} // namespace dusk diff --git a/src/dusk/imgui/ImGuiAchievements.cpp b/src/dusk/imgui/ImGuiAchievements.cpp new file mode 100644 index 0000000000..4b844b8386 --- /dev/null +++ b/src/dusk/imgui/ImGuiAchievements.cpp @@ -0,0 +1,228 @@ +#include "ImGuiAchievements.hpp" +#include "ImGuiConfig.hpp" +#include "dusk/achievements.h" +#include "dusk/settings.h" +#include "fmt/format.h" +#include "imgui.h" + +namespace dusk { + +void ImGuiAchievements::notify(std::string name) { + if (m_notifyTimer <= 0.f) { + m_notifyName = std::move(name); + m_notifyTimer = NOTIFY_DURATION; + } else { + m_notifyQueue.push(std::move(name)); + } +} + +void ImGuiAchievements::showNotification() { + if (!getSettings().game.enableAchievementNotifications.getValue()) { + return; + } + if (m_notifyTimer <= 0.f) { + if (m_notifyQueue.empty()) { + return; + } + m_notifyName = std::move(m_notifyQueue.front()); + m_notifyQueue.pop(); + m_notifyTimer = NOTIFY_DURATION; + } + + m_notifyTimer -= ImGui::GetIO().DeltaTime; + + const float alpha = std::min({ + m_notifyTimer / NOTIFY_FADE_TIME, + (NOTIFY_DURATION - m_notifyTimer) / NOTIFY_FADE_TIME, + 1.0f + }); + + const ImGuiViewport* viewport = ImGui::GetMainViewport(); + const float padding = 12.0f; + ImGui::SetNextWindowPos( + ImVec2(viewport->WorkPos.x + viewport->WorkSize.x - padding, viewport->WorkPos.y + padding), + ImGuiCond_Always, ImVec2(1.0f, 0.0f) + ); + + ImGui::SetNextWindowBgAlpha(alpha * 0.92f); + ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.08f, 0.06f, 0.01f, alpha * 0.92f)); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(1.0f, 0.8f, 0.1f, alpha)); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, alpha)); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 2.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(14.0f, 10.0f)); + + constexpr ImGuiWindowFlags flags = + ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | + ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | + ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs; + + if (ImGui::Begin("##achievement_notify", nullptr, flags)) { + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.82f, 0.1f, alpha)); + ImGui::TextUnformatted("Achievement Unlocked!"); + ImGui::PopStyleColor(); + ImGui::Spacing(); + ImGui::TextUnformatted(m_notifyName.c_str()); + } + ImGui::End(); + + ImGui::PopStyleVar(2); + ImGui::PopStyleColor(3); +} + +void ImGuiAchievements::draw(bool& open) { + showNotification(); + + if (!open) { + return; + } + + ImGui::SetNextWindowSizeConstraints(ImVec2(640, 200), ImVec2(800, 900)); + ImGui::SetNextWindowSize(ImVec2(640, 480), ImGuiCond_FirstUseEver); + + if (!ImGui::Begin( + "Achievements", &open, + ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav) + ) + { + ImGui::End(); + return; + } + + const auto achievements = AchievementSystem::get().getAchievements(); + + int unlocked = 0; + for (const auto& a : achievements) { + if (a.unlocked) { + ++unlocked; + } + } + + ImGui::Text("%d / %d achievements unlocked", unlocked, (int)achievements.size()); + ImGui::SameLine(); + config::ImGuiCheckbox("Notifications", getSettings().game.enableAchievementNotifications); + ImGui::Separator(); + + static const struct { + AchievementCategory cat; + const char* label; + ImVec4 color; + } ACHIEVEMENT_CATEGORIES[] = { + {AchievementCategory::Story, "Story", ImVec4(1.0f, 0.82f, 0.1f, 1.0f)}, + {AchievementCategory::Collection, "Collection", ImVec4(0.3f, 0.85f, 0.4f, 1.0f)}, + {AchievementCategory::Challenge, "Challenge", ImVec4(1.0f, 0.65f, 0.15f, 1.0f)}, + {AchievementCategory::Minigame, "Minigame", ImVec4(0.5f, 0.85f, 1.0f, 1.0f)}, + {AchievementCategory::Glitched, "Glitched", ImVec4(0.75f, 0.4f, 1.0f, 1.0f)}, + }; + + const float footerHeight = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); + + if (ImGui::BeginTabBar("##achievement_tabs", ImGuiTabBarFlags_FittingPolicyScroll)) { + for (const auto& catInfo : ACHIEVEMENT_CATEGORIES) { + int catTotal = 0, catUnlocked = 0; + for (const auto& a : achievements) { + if (a.category == catInfo.cat) { + ++catTotal; + if (a.unlocked) { + ++catUnlocked; + } + } + } + if (catTotal == 0) { + continue; + } + + const std::string tabLabel = fmt::format("{} ({}/{})", catInfo.label, catUnlocked, catTotal); + + ImGui::PushStyleColor(ImGuiCol_Text, catInfo.color); + const bool tabOpen = ImGui::BeginTabItem(tabLabel.c_str()); + ImGui::PopStyleColor(); + + if (tabOpen) { + ImGui::BeginChild( + "##cat_list", + ImVec2(0, -footerHeight), + ImGuiChildFlags_None, + ImGuiWindowFlags_NoBackground + ); + + ImGui::Spacing(); + + for (const auto& a : achievements) { + if (a.category != catInfo.cat) { + continue; + } + ImGui::PushID(a.key); + + ImGui::PushStyleColor( + ImGuiCol_Text, + a.unlocked ? + ImVec4(1.0f, 0.65f, 0.15f, 1.0f) : + ImGui::GetStyleColorVec4(ImGuiCol_Text) + ); + + ImGui::TextUnformatted(a.name); + ImGui::PopStyleColor(); + + const char* statusLabel = a.unlocked ? "[Unlocked]" : "[Locked]"; + ImGui::SameLine( + ImGui::GetContentRegionMax().x - + ImGui::CalcTextSize(statusLabel).x + ); + + if (a.unlocked) { + ImGui::TextColored(ImVec4(0.2f, 0.8f, 0.2f, 1.0f), "%s", statusLabel); + } else { + ImGui::TextColored(ImVec4(0.8f, 0.2f, 0.2f, 1.0f), "%s", statusLabel); + } + + ImGui::TextDisabled("%s", a.description); + + if (a.isCounter) { + const float fraction = a.goal > 0 ? (float)(a.progress) / (float)(a.goal) : 1.0f; + const std::string overlay = fmt::format("{} / {}", a.progress, a.goal); + ImGui::PushStyleColor( + ImGuiCol_PlotHistogram, + a.unlocked ? + ImVec4(0.4f, 0.7f, 0.1f, 1.0f) : + ImVec4(0.2f, 0.45f, 0.8f, 1.0f) + ); + ImGui::ProgressBar(fraction, ImVec2(-1.0f, 0.0f), overlay.c_str()); + ImGui::PopStyleColor(); + } + + ImGui::Spacing(); + ImGui::PopID(); + } + + ImGui::EndChild(); + ImGui::EndTabItem(); + } + } + ImGui::EndTabBar(); + } + + ImGui::Separator(); + ImGui::Spacing(); + + if (ImGui::Button("Clear All Achievements")) { + ImGui::OpenPopup("##confirm_clear"); + } + + if (ImGui::BeginPopup("##confirm_clear")) { + ImGui::Text("Reset all achievement progress?"); + ImGui::Spacing(); + if (ImGui::Button("Yes, reset all")) { + AchievementSystem::get().clearAll(); + ImGui::CloseCurrentPopup(); + } + ImGui::SameLine(); + if (ImGui::Button("Cancel")) { + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } + + ImGui::End(); +} + +} // namespace dusk diff --git a/src/dusk/imgui/ImGuiAchievements.hpp b/src/dusk/imgui/ImGuiAchievements.hpp new file mode 100644 index 0000000000..5ee77373fc --- /dev/null +++ b/src/dusk/imgui/ImGuiAchievements.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +namespace dusk { + +class ImGuiAchievements { +public: + void draw(bool& open); + void notify(std::string name); + +private: + void showNotification(); + + std::string m_notifyName; + float m_notifyTimer = 0.f; + std::queue m_notifyQueue; + static constexpr float NOTIFY_DURATION = 4.0f; + static constexpr float NOTIFY_FADE_TIME = 0.5f; +}; + +} // namespace dusk diff --git a/src/dusk/imgui/ImGuiConsole.cpp b/src/dusk/imgui/ImGuiConsole.cpp index 085b34dc2d..c8a9fa86aa 100644 --- a/src/dusk/imgui/ImGuiConsole.cpp +++ b/src/dusk/imgui/ImGuiConsole.cpp @@ -14,6 +14,7 @@ #include "SDL3/SDL_events.h" #include "SDL3/SDL_mouse.h" #include "aurora/lib/window.hpp" +#include "dusk/achievements.h" #include "dusk/audio/DuskAudioSystem.h" #include "dusk/config.hpp" #include "dusk/dusk.h" @@ -295,6 +296,15 @@ namespace dusk { UpdateSettings(); + AchievementSystem::get().tick(); + while (AchievementSystem::get().hasPendingUnlock()) { + if (getSettings().game.enableAchievementNotifications) { + m_menuTools.notifyAchievement(AchievementSystem::get().consumePendingUnlock()); + } else { + AchievementSystem::get().consumePendingUnlock(); + } + } + if ((ImGui::IsKeyDown(ImGuiKey_LeftCtrl) || ImGui::IsKeyDown(ImGuiKey_RightCtrl)) && ImGui::IsKeyPressed(ImGuiKey_R)) { @@ -374,6 +384,7 @@ namespace dusk { m_menuTools.ShowSaveEditor(); } m_menuTools.ShowStateShare(); + m_menuTools.ShowAchievements(); DuskDebugPad(); // temporary, remove later // Hide mouse cursor if the F1 menu is not open and the cursor is idle for 3 seconds. diff --git a/src/dusk/imgui/ImGuiFirstRunPreset.cpp b/src/dusk/imgui/ImGuiFirstRunPreset.cpp index fb2d181562..8009305870 100644 --- a/src/dusk/imgui/ImGuiFirstRunPreset.cpp +++ b/src/dusk/imgui/ImGuiFirstRunPreset.cpp @@ -35,6 +35,7 @@ static void ApplyPresetDusk() { ApplyPresetHD(); auto& s = getSettings(); + s.game.enableAchievementNotifications.setValue(true); s.game.enableQuickTransform.setValue(true); s.game.instantSaves.setValue(true); s.game.midnasLamentNonStop.setValue(true); diff --git a/src/dusk/imgui/ImGuiMenuGame.cpp b/src/dusk/imgui/ImGuiMenuGame.cpp index 7e54f2ffa3..8cb50e143d 100644 --- a/src/dusk/imgui/ImGuiMenuGame.cpp +++ b/src/dusk/imgui/ImGuiMenuGame.cpp @@ -444,6 +444,7 @@ namespace dusk { void ImGuiMenuGame::drawInterfaceMenu() { if (ImGui::BeginMenu("Interface")) { + config::ImGuiCheckbox("Achievement Notifications", getSettings().game.enableAchievementNotifications); config::ImGuiCheckbox("Skip Pre-Launch UI", getSettings().backend.skipPreLaunchUI); config::ImGuiCheckbox("Show Pipeline Compilation", getSettings().backend.showPipelineCompilation); #if DUSK_ENABLE_SENTRY_NATIVE diff --git a/src/dusk/imgui/ImGuiMenuTools.cpp b/src/dusk/imgui/ImGuiMenuTools.cpp index 00a03e635b..a82067a438 100644 --- a/src/dusk/imgui/ImGuiMenuTools.cpp +++ b/src/dusk/imgui/ImGuiMenuTools.cpp @@ -58,6 +58,8 @@ namespace dusk { ImGui::EndDisabled(); } + ImGui::MenuItem("Achievements", nullptr, &m_showAchievements); + #if DUSK_CAN_OPEN_DATA_FOLDER ImGui::Separator(); if (ImGui::MenuItem("Open Data Folder")) { @@ -252,4 +254,12 @@ namespace dusk { ImGui::End(); ImGui::PopFont(); } + + void ImGuiMenuTools::ShowAchievements() { + m_achievementsWindow.draw(m_showAchievements); + } + + void ImGuiMenuTools::notifyAchievement(std::string name) { + m_achievementsWindow.notify(std::move(name)); + } } diff --git a/src/dusk/imgui/ImGuiMenuTools.hpp b/src/dusk/imgui/ImGuiMenuTools.hpp index e48aab2742..de94ad2d8f 100644 --- a/src/dusk/imgui/ImGuiMenuTools.hpp +++ b/src/dusk/imgui/ImGuiMenuTools.hpp @@ -5,6 +5,7 @@ #include #include "imgui.h" +#include "ImGuiAchievements.hpp" #include "ImGuiSaveEditor.hpp" #include "ImGuiStateShare.hpp" @@ -26,6 +27,8 @@ namespace dusk { void ShowAudioDebug(); void ShowSaveEditor(); void ShowStateShare(); + void ShowAchievements(); + void notifyAchievement(std::string name); private: bool m_showDebugOverlay = false; @@ -65,6 +68,9 @@ namespace dusk { bool m_showStateShare = false; ImGuiStateShare m_stateShare; + + bool m_showAchievements = false; + ImGuiAchievements m_achievementsWindow; }; } diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index 3e6ee733fe..b6dc559610 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -44,6 +44,7 @@ UserSettings g_userSettings = { .disableMainHUD {"game.disableMainHUD", false}, .pauseOnFocusLost {"game.pauseOnFocusLost", false}, .enableLinkDollRotation = {"game.enableLinkDollRotation", false }, + .enableAchievementNotifications {"game.enableAchievementNotifications", false}, // Graphics .bloomMode {"game.bloomMode", BloomMode::Classic}, @@ -153,6 +154,7 @@ void registerSettings() { Register(g_userSettings.game.freeMagicArmor); Register(g_userSettings.game.restoreWiiGlitches); Register(g_userSettings.game.enableLinkDollRotation); + Register(g_userSettings.game.enableAchievementNotifications); Register(g_userSettings.game.noMissClimbing); Register(g_userSettings.game.noLowHpSound); Register(g_userSettings.game.midnasLamentNonStop); From 9ddfcc38c9f875f9ddf5fc2d6c8d0a3cd0981864 Mon Sep 17 00:00:00 2001 From: Howard Luck Date: Sat, 25 Apr 2026 20:37:36 -0600 Subject: [PATCH 036/390] fix interp on ooks rope (#553) --- include/d/actor/d_a_e_mb.h | 6 ++++++ src/d/actor/d_a_e_mb.cpp | 29 +++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/include/d/actor/d_a_e_mb.h b/include/d/actor/d_a_e_mb.h index f36c744879..527cf30eac 100644 --- a/include/d/actor/d_a_e_mb.h +++ b/include/d/actor/d_a_e_mb.h @@ -44,6 +44,12 @@ public: /* 0x88C */ u8 field_0x88C[0x8C8 - 0x88C]; /* 0x8C8 */ s8 field_0x8c8; /* 0x8C9 */ u8 mInitHIO; +#if TARGET_PC + cXyz mRopeInterpPrev[16]; + cXyz mRopeInterpCurr[16]; + bool mRopeInterpPrevValid; + bool mRopeInterpCurrValid; +#endif }; STATIC_ASSERT(sizeof(e_mb_class) == 0x8cc); diff --git a/src/d/actor/d_a_e_mb.cpp b/src/d/actor/d_a_e_mb.cpp index 939b253475..aa77a99612 100644 --- a/src/d/actor/d_a_e_mb.cpp +++ b/src/d/actor/d_a_e_mb.cpp @@ -12,6 +12,8 @@ #include "d/d_bomb.h" #include "c/c_damagereaction.h" #include "Z2AudioLib/Z2Instances.h" +#include "dusk/frame_interpolation.h" +#include "dusk/settings.h" #define ACTION_STANDBY 0 #define ACTION_WALK1 1 @@ -63,6 +65,22 @@ static void anm_init(e_mb_class* i_this, int i_anmID, f32 i_morf, u8 i_attr, f32 i_this->mAnm = i_anmID; } +#if TARGET_PC +static void e_mb_rope_interp_callback(bool isSimFrame, void* pUserWork) { + e_mb_class* i_this = (e_mb_class*)pUserWork; + if (!i_this->mRopeInterpPrevValid || !i_this->mRopeInterpCurrValid) { + return; + } + const f32 alpha = dusk::frame_interp::get_interpolation_step(); + cXyz* dst = i_this->mRopeMat.getPos(0); + for (int i = 0; i < 16; i++) { + const cXyz& p0 = i_this->mRopeInterpPrev[i]; + const cXyz& p1 = i_this->mRopeInterpCurr[i]; + dst[i] = p0 + (p1 - p0) * alpha; + } +} +#endif + static int daE_MB_Draw(e_mb_class* i_this) { fopAc_ac_c* a_this = (fopAc_ac_c*)i_this; @@ -86,6 +104,17 @@ static int daE_MB_Draw(e_mb_class* i_this) { static GXColor l_color = {0x14, 0x0F, 0x00, 0xFF}; i_this->mRopeMat.update(16, l_color, &a_this->tevStr); dComIfGd_set3DlineMat(&i_this->mRopeMat); +#if TARGET_PC + if (dusk::getSettings().game.enableFrameInterpolation) { + if (i_this->mRopeInterpCurrValid) { + memcpy(i_this->mRopeInterpPrev, i_this->mRopeInterpCurr, sizeof(i_this->mRopeInterpCurr)); + i_this->mRopeInterpPrevValid = true; + } + memcpy(i_this->mRopeInterpCurr, i_this->mRopeMat.getPos(0), 16 * sizeof(cXyz)); + i_this->mRopeInterpCurrValid = true; + dusk::frame_interp::add_interpolation_callback(&e_mb_rope_interp_callback, i_this); + } +#endif return 1; } From f7b5350d60eb96b92446e2d20a0a331e678c2ac0 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sat, 25 Apr 2026 20:42:02 -0600 Subject: [PATCH 037/390] Update README.md --- README.md | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index c2fe53576d..b6d6cec863 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ - ### **[Discord](https://discord.gg/QACynxeyna)** # Setup -**⚠️Dusk does NOT provide any copyrighted assets. You must provide your own copy of the game.** +**⚠️ Dusk does NOT provide any copyrighted assets. You must provide your own copy of the game.** ### 1. Verify your ROM dump First make sure your dump of the game is clean and supported by Dusk. You can do this by checking the sha1 hash of your dump against this list of supported versions. @@ -22,29 +22,10 @@ First make sure your dump of the game is clean and supported by Dusk. You can do - Select Options, then set the ISO Path to your supported game dump - Press Start Game to play! -![DuskOptions](assets/dusk_options.png) +![Dusk options](assets/dusk_options.png) # Building If you'd like to build Dusk from source, please read the [build instructions](docs/building.md). # Credits -- Taka -- encounter -- Antidote -- caseif -- CraftyBoss -- crowell -- dooplecks -- gymnast86 -- Irastris -- kipcode66 -- Lars -- LunarSoap -- Maddie -- MelonSpeedruns -- Pheenoh -- PJB -- Roeming -- YunataSavior - -Special thanks to the TP Decomp team, the GC/Wii Decomp community, the Aurora developers, and the TP speedrunning community. +Special thanks to the [TP decompilation](https://github.com/zeldaret/tp) team, the GC/Wii decompilation community, the [Aurora](https://github.com/encounter/aurora) developers, the [TP speedrunning community](https://zsrtp.link), and all [contributors](https://github.com/TwilitRealm/dusk/graphs/contributors). From ba58d2486e5dbae1c98ee363cbac0ea1f1511923 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Sat, 25 Apr 2026 23:35:43 -0400 Subject: [PATCH 038/390] Free Camera (#542) * freecam wip * added manual mode * fix freecam collision * made freecam into its own function * Added settings & Radius modification when camer is higher up --------- Co-authored-by: MelonSpeedruns --- include/d/d_cam_param.h | 6 +++ include/d/d_camera.h | 5 ++ include/dusk/settings.h | 5 +- src/d/d_camera.cpp | 66 ++++++++++++++++++++++++++ src/dusk/imgui/ImGuiFirstRunPreset.cpp | 1 + src/dusk/imgui/ImGuiMenuGame.cpp | 10 +++- src/dusk/settings.cpp | 8 +++- 7 files changed, 98 insertions(+), 3 deletions(-) diff --git a/include/d/d_cam_param.h b/include/d/d_cam_param.h index d6ff7b46d7..867c66e38d 100644 --- a/include/d/d_cam_param.h +++ b/include/d/d_cam_param.h @@ -143,6 +143,12 @@ public: /* 0x20 */ JORFile mFile; #endif +#if TARGET_PC + /* 0x24 */ u8 mManualMode; + /* 0x25 */ f32 freeXAngle; + /* 0x29 */ f32 freeYAngle; +#endif + u32 Id(s32 i_style) { return mCamStyleData[i_style].field_0x0; } int Algorythmn(s32 i_style) { return mCamStyleData[i_style].field_0x4; } int Algorythmn() { return mCurrentStyle->field_0x4; } diff --git a/include/d/d_camera.h b/include/d/d_camera.h index 85e930c395..105c9cae9f 100644 --- a/include/d/d_camera.h +++ b/include/d/d_camera.h @@ -273,6 +273,8 @@ public: /* 0xA4 */ f32 field_0xa4; /* 0xA8 */ int field_0xa8; /* 0xAC */ f32 field_0xac; + f32 xAngle; + f32 yAngle; }; struct LockOnData { @@ -1024,6 +1026,9 @@ public: bool colosseumCamera(s32); bool test1Camera(s32); bool test2Camera(s32); + #if TARGET_PC + bool freeCamera(); + #endif bool towerCamera(s32); bool hookshotCamera(s32); bool railCamera(s32); diff --git a/include/dusk/settings.h b/include/dusk/settings.h index 8a54197317..a7815569d0 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -82,7 +82,6 @@ struct UserSettings { // Preferences ConfigVar enableMirrorMode; - ConfigVar invertCameraXAxis; ConfigVar disableMainHUD; ConfigVar pauseOnFocusLost; ConfigVar enableLinkDollRotation; @@ -112,6 +111,10 @@ struct UserSettings { ConfigVar gyroDeadband; ConfigVar gyroInvertPitch; ConfigVar gyroInvertYaw; + ConfigVar freeCamera; + ConfigVar invertCameraXAxis; + ConfigVar invertCameraYAxis; + ConfigVar freeCameraSensitivity; // Cheats ConfigVar infiniteHearts; diff --git a/src/d/d_camera.cpp b/src/d/d_camera.cpp index f805a6a08b..917b30709a 100644 --- a/src/d/d_camera.cpp +++ b/src/d/d_camera.cpp @@ -800,6 +800,10 @@ void dCamera_c::updatePad() { } mLockLActive = 1; + + #if TARGET_PC + mCamParam.mManualMode = 0; + #endif } else { mLockLJustActivated = 0; mLockLActive = 0; @@ -833,6 +837,12 @@ void dCamera_c::updatePad() { mHoldB = mDoCPd_c::getHoldB(mPadID) ? true : false; mTrigB = mDoCPd_c::getTrigB(mPadID) ? true : false; + #if TARGET_PC + if (mCamParam.mManualMode) { + return; + } + #endif + bool sp6B = true; bool sp6C = true; int temp1; @@ -1167,6 +1177,13 @@ bool dCamera_c::Run() { } } else { sp0F = (this->*engine_tbl[mCamParam.Algorythmn(mCamStyle)])(mCamStyle); + + #if TARGET_PC + if (mCamParam.Algorythmn(mCamStyle) != 1) { + mCamParam.mManualMode = 0; + } + #endif + field_0x170++; field_0x160++; mCurCamStyleTimer++; @@ -3078,6 +3095,11 @@ bool dCamera_c::bumpCheck(u32 i_flags) { } else { field_0x968 *= mMonitor.field_0xc / 5.0f; } + + #if TARGET_PC + if (!dusk::getSettings().game.freeCamera || !mCamParam.mManualMode) { + #endif + f32 tmp = field_0x96c * (mIsWolf == 1 ? 30.0f : 30.0f); center += vec3.norm() * (tmp * globe.V().Sin()); cSGlobe globe2(vec2 - center); @@ -3091,6 +3113,10 @@ bool dCamera_c::bumpCheck(u32 i_flags) { vec = lin_chk1.GetCross(); } + #if TARGET_PC + } + #endif + #if DEBUG if (mCamSetup.CheckFlag(0x8000)) { dDbVw_Report(20, 235, " U"); @@ -4604,6 +4630,11 @@ bool dCamera_c::chaseCamera(s32 param_0) { sp110 = mViewCache.mDirection.R(); mViewCache.mDirection.R(mViewCache.mDirection.R() + (fVar55 - mViewCache.mDirection.R()) * chase->field_0x74); + + #if TARGET_PC + freeCamera(); + #endif + chase->field_0x64 = mViewCache.mCenter + mViewCache.mDirection.Xyz(); mViewCache.mEye = chase->field_0x64; @@ -7444,6 +7475,41 @@ bool dCamera_c::test2Camera(s32 param_0) { return false; } +#if TARGET_PC +bool dCamera_c::freeCamera() { + if (!dusk::getSettings().game.freeCamera) { + mCamParam.mManualMode = 0; + return false; + } + + cXyz camMovement = {mPadInfo.mCStick.mLastPosX, mPadInfo.mCStick.mLastPosY, 0.0f}; + f32 magnitude = sqrt(mPadInfo.mCStick.mLastPosX * mPadInfo.mCStick.mLastPosX + mPadInfo.mCStick.mLastPosY * mPadInfo.mCStick.mLastPosY); + + if (mPadInfo.mCStick.mLastPosX != 0 || mPadInfo.mCStick.mLastPosY != 0) { + if (!mCamParam.mManualMode) { + mCamParam.mManualMode = 1; + mCamParam.freeXAngle = mViewCache.mDirection.mAzimuth.Degree(); + mCamParam.freeYAngle = mViewCache.mDirection.mInclination.Degree(); + } + + camMovement = camMovement.normalize(); + camMovement.x *= (dusk::getSettings().game.invertCameraXAxis ? 1.0f : -1.0f) * dusk::getSettings().game.freeCameraSensitivity * 4.0f; + camMovement.y *= (dusk::getSettings().game.invertCameraYAxis ? 1.0f : -1.0f) * dusk::getSettings().game.freeCameraSensitivity * 4.0f; + mCamParam.freeXAngle += camMovement.x * magnitude * dusk::getSettings().game.freeCameraSensitivity; + mCamParam.freeYAngle += camMovement.y * magnitude * dusk::getSettings().game.freeCameraSensitivity; + } + + if (mCamParam.mManualMode) { + mCamParam.freeYAngle = std::clamp(mCamParam.freeYAngle, -35.0f, 60.0f); + mViewCache.mDirection.mAzimuth = cSAngle(mCamParam.freeXAngle); + mViewCache.mDirection.mInclination = cSAngle(mCamParam.freeYAngle); + mViewCache.mDirection.mRadius = std::clamp(mCamParam.freeYAngle * 15.0f, 300.0f, 10000.0f); + } + + return mCamParam.mManualMode; +} +#endif + bool dCamera_c::towerCamera(s32 param_0) { cSAngle stack_444 = cSAngle(mCamSetup.ChargeLatitude()); f32 sp224 = mCamSetup.ChargeBRatio(); diff --git a/src/dusk/imgui/ImGuiFirstRunPreset.cpp b/src/dusk/imgui/ImGuiFirstRunPreset.cpp index 8009305870..2a9bcc5c6e 100644 --- a/src/dusk/imgui/ImGuiFirstRunPreset.cpp +++ b/src/dusk/imgui/ImGuiFirstRunPreset.cpp @@ -29,6 +29,7 @@ static void ApplyPresetHD() { s.game.fastTears.setValue(true); s.game.biggerWallets.setValue(true); s.game.invertCameraXAxis.setValue(true); + s.game.freeCamera.setValue(true); } static void ApplyPresetDusk() { diff --git a/src/dusk/imgui/ImGuiMenuGame.cpp b/src/dusk/imgui/ImGuiMenuGame.cpp index 8cb50e143d..0a687233aa 100644 --- a/src/dusk/imgui/ImGuiMenuGame.cpp +++ b/src/dusk/imgui/ImGuiMenuGame.cpp @@ -383,7 +383,15 @@ namespace dusk { ImGui::SeparatorText("Camera"); - config::ImGuiCheckbox("Invert Camera X Axis", getSettings().game.invertCameraXAxis); + config::ImGuiCheckbox("Free Camera", getSettings().game.freeCamera); + + if (getSettings().game.freeCamera) { + config::ImGuiCheckbox("Invert Camera X Axis", getSettings().game.invertCameraXAxis); + config::ImGuiCheckbox("Invert Camera Y Axis", getSettings().game.invertCameraYAxis); + config::ImGuiSliderFloat("Free Camera Sensitivity", getSettings().game.freeCameraSensitivity, 0.5f, 2.0f, "%.1f"); + } else { + config::ImGuiCheckbox("Invert Camera X Axis", getSettings().game.invertCameraXAxis); + } ImGui::SeparatorText("Gyro"); diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index e10e6d9ee9..eb1d513ba9 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -42,7 +42,6 @@ UserSettings g_userSettings = { // Preferences .enableMirrorMode {"game.enableMirrorMode", false}, - .invertCameraXAxis {"game.invertCameraXAxis", false}, .disableMainHUD {"game.disableMainHUD", false}, .pauseOnFocusLost {"game.pauseOnFocusLost", false}, .enableLinkDollRotation = {"game.enableLinkDollRotation", false }, @@ -71,6 +70,10 @@ UserSettings g_userSettings = { .gyroDeadband {"game.gyroDeadband", 0.04f}, .gyroInvertPitch {"game.gyroInvertPitch", false}, .gyroInvertYaw {"game.gyroInvertYaw", false}, + .freeCamera {"game.freeCamera", false}, + .invertCameraXAxis {"game.invertCameraXAxis", false}, + .invertCameraYAxis {"game.invertCameraYAxis", false}, + .freeCameraSensitivity {"game.freeCameraSensitivity", 1.0f}, // Cheats .infiniteHearts {"game.infiniteHearts", false}, @@ -144,6 +147,8 @@ void registerSettings() { Register(g_userSettings.game.sunsSong); Register(g_userSettings.game.enableMirrorMode); Register(g_userSettings.game.invertCameraXAxis); + Register(g_userSettings.game.invertCameraYAxis); + Register(g_userSettings.game.freeCameraSensitivity); Register(g_userSettings.game.disableMainHUD); Register(g_userSettings.game.pauseOnFocusLost); Register(g_userSettings.game.bloomMode); @@ -183,6 +188,7 @@ void registerSettings() { Register(g_userSettings.game.gyroSmoothing); Register(g_userSettings.game.gyroInvertPitch); Register(g_userSettings.game.gyroInvertYaw); + Register(g_userSettings.game.freeCamera); Register(g_userSettings.backend.isoPath); Register(g_userSettings.backend.graphicsBackend); From 34ec362876dc99795c6fdd22b93547ea1365398d Mon Sep 17 00:00:00 2001 From: Pheenoh Date: Sat, 25 Apr 2026 21:37:11 -0600 Subject: [PATCH 039/390] fix zant fog spin and culling --- src/d/d_kankyo_rain.cpp | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/src/d/d_kankyo_rain.cpp b/src/d/d_kankyo_rain.cpp index 64cf2247e0..822612768c 100644 --- a/src/d/d_kankyo_rain.cpp +++ b/src/d/d_kankyo_rain.cpp @@ -5986,7 +5986,12 @@ static void dKyr_evil_draw2(Mtx drawMtx, u8** tex) { TGXTexObj texobj; dKyr_set_btitex(&texobj, (ResTIMG*)tex[1]); - rot += 0.7f; +#if TARGET_PC + if (dusk::frame_interp::get_ui_tick_pending()) +#endif + { + rot += 0.7f; + } MTXRotRad(rotMtx, 'Z', DEG_TO_RAD(rot)); MTXConcat(camMtx, rotMtx, camMtx); @@ -6037,7 +6042,14 @@ static void dKyr_evil_draw2(Mtx drawMtx, u8** tex) { sp34.y = 80.0f; sp34.z = 80.0f; mDoLib_project(&sp7C, &proj); - if (!(proj.x > -sp34.x) || !(proj.x < (FB_WIDTH + sp34.x)) || +#if TARGET_PC + f32 cullMinX = mDoGph_gInf_c::getSafeMinXF() - sp34.x; + f32 cullMaxX = mDoGph_gInf_c::getSafeMinXF() + mDoGph_gInf_c::getSafeWidthF() + sp34.x; +#else + f32 cullMinX = -sp34.x; + f32 cullMaxX = FB_WIDTH + sp34.x; +#endif + if (!(proj.x > cullMinX) || !(proj.x < cullMaxX) || !(proj.y > -sp34.y) || !(proj.y < (458.0f + sp34.z))) { continue; @@ -6208,7 +6220,12 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) { TGXTexObj texobj; dKyr_set_btitex(&texobj, (ResTIMG*)tex[0]); - rot += 1.0f; +#if TARGET_PC + if (dusk::frame_interp::get_ui_tick_pending()) +#endif + { + rot += 1.0f; + } MTXRotRad(rotMtx, 'Z', DEG_TO_RAD(rot)); MTXConcat(camMtx, rotMtx, camMtx); @@ -6262,7 +6279,14 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) { sp44.z = 80.0f; mDoLib_project(&spA4, &proj); - if (!(proj.x > -sp44.x) || !(proj.x < (FB_WIDTH + sp44.x)) || +#if TARGET_PC + f32 cullMinX = mDoGph_gInf_c::getSafeMinXF() - sp44.x; + f32 cullMaxX = mDoGph_gInf_c::getSafeMinXF() + mDoGph_gInf_c::getSafeWidthF() + sp44.x; +#else + f32 cullMinX = -sp44.x; + f32 cullMaxX = FB_WIDTH + sp44.x; +#endif + if (!(proj.x > cullMinX) || !(proj.x < cullMaxX) || !(proj.y > -sp44.y) || !(proj.y < (458.0f + sp44.z))) { continue; From 8e121a7e5187fb1f30b13b2d520c4303e2cd81db Mon Sep 17 00:00:00 2001 From: TakaRikka Date: Sat, 25 Apr 2026 21:12:51 -0700 Subject: [PATCH 040/390] update timer impl --- files.cmake | 1 + include/dusk/settings.h | 3 +- src/d/actor/d_a_alink_demo.inc | 10 ++ src/d/d_bright_check.cpp | 8 ++ src/d/d_s_name.cpp | 20 +++- src/dusk/imgui/ImGuiConsole.cpp | 9 +- src/dusk/imgui/ImGuiConsole.hpp | 7 +- src/dusk/imgui/ImGuiMenuGame.cpp | 121 +++++++++++++++++++++- src/dusk/imgui/ImGuiMenuGame.hpp | 22 ++++ src/dusk/imgui/ImGuiMenuSpeedrunTimer.cpp | 96 ----------------- src/dusk/imgui/ImGuiMenuTools.cpp | 9 ++ src/dusk/settings.cpp | 6 +- src/f_op/f_op_scene_req.cpp | 21 +++- 13 files changed, 215 insertions(+), 118 deletions(-) delete mode 100644 src/dusk/imgui/ImGuiMenuSpeedrunTimer.cpp diff --git a/files.cmake b/files.cmake index af101b6c47..91b0c0fab7 100644 --- a/files.cmake +++ b/files.cmake @@ -1461,6 +1461,7 @@ set(DUSK_FILES src/dusk/imgui/ImGuiStateShare.hpp src/dusk/imgui/ImGuiStateShare.cpp src/dusk/iso_validate.cpp + src/dusk/livesplit.cpp src/dusk/offset_ptr.cpp src/dusk/OSContext.cpp src/dusk/OSThread.cpp diff --git a/include/dusk/settings.h b/include/dusk/settings.h index 522e172e7c..7fb8c85a51 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -119,8 +119,7 @@ struct UserSettings { ConfigVar enableTurboKeybind; // Tools - ConfigVar speedrunTimer; - ConfigVar speedrunTimerOverlay; + ConfigVar speedrunMode; ConfigVar liveSplitEnabled; } game; diff --git a/src/d/actor/d_a_alink_demo.inc b/src/d/actor/d_a_alink_demo.inc index aa77b24129..b46af5cacb 100644 --- a/src/d/actor/d_a_alink_demo.inc +++ b/src/d/actor/d_a_alink_demo.inc @@ -23,6 +23,7 @@ #include "d/actor/d_a_npc_tkc.h" #include +#include "dusk/imgui/ImGuiConsole.hpp" #include "dusk/settings.h" BOOL daAlink_c::checkEventRun() const { @@ -4005,6 +4006,15 @@ int daAlink_c::procGanonFinishInit() { field_0x37c8 = current.pos; onEndResetFlg1(ERFLG1_SHIELD_BACKBONE); + +#if TARGET_PC + if (dusk::getSettings().game.speedrunMode) { + if (dusk::g_imguiConsole.isSpeedrunStart()) { + dusk::g_imguiConsole.stopSpeedrun(); + } + } +#endif + return 1; } diff --git a/src/d/d_bright_check.cpp b/src/d/d_bright_check.cpp index 2c683eb819..88d0b7a2d8 100644 --- a/src/d/d_bright_check.cpp +++ b/src/d/d_bright_check.cpp @@ -10,6 +10,7 @@ #include "JSystem/J2DGraph/J2DTextBox.h" #include "d/d_msg_string.h" #include "dusk/livesplit.h" +#include "dusk/imgui/ImGuiConsole.hpp" #include "m_Do/m_Do_controller_pad.h" dBrightCheck_c::dBrightCheck_c(JKRArchive* i_archive) { @@ -141,6 +142,13 @@ void dBrightCheck_c::modeMove() { mDoAud_seStart(Z2SE_ENTER_GAME, NULL, 0, 0); #ifdef TARGET_PC dusk::speedrun::start(); + + if (dusk::getSettings().game.speedrunMode && !dusk::getSettings().game.hideTvSettingsScreen) { + // start a new run if a run isn't already in progress + if (!dusk::g_imguiConsole.isSpeedrunStart()) { + dusk::g_imguiConsole.startSpeedrun(); + } + } #endif mCompleteCheck = true; mMode = MODE_WAIT_e; diff --git a/src/d/d_s_name.cpp b/src/d/d_s_name.cpp index 735ce4d0ca..9a20ca6caa 100644 --- a/src/d/d_s_name.cpp +++ b/src/d/d_s_name.cpp @@ -5,19 +5,20 @@ #include "d/dolzel.h" // IWYU pragma: keep -#include "d/d_s_name.h" #include "JSystem/JKernel/JKRExpHeap.h" #include "d/d_com_inf_game.h" #include "d/d_meter2_info.h" +#include "d/d_s_name.h" +#include "dusk/imgui/ImGuiConsole.hpp" +#include "dusk/memory.h" +#include "dusk/settings.h" +#include "f_op/f_op_overlap_mng.h" #include "f_op/f_op_scene_mng.h" #include "m_Do/m_Do_Reset.h" #include "m_Do/m_Do_graphic.h" #include "m_Do/m_Do_machine.h" -#include "m_Do/m_Do_mtx.h" #include "m_Do/m_Do_main.h" -#include "f_op/f_op_overlap_mng.h" -#include "dusk/memory.h" -#include "dusk/settings.h" +#include "m_Do/m_Do_mtx.h" #if TARGET_PC #define SHOW_TV_SETTINGS_SCREEN (this->mShowTvSettingsScreen) @@ -412,6 +413,15 @@ void dScnName_c::changeGameScene() { dKy_clear_game_init(); dComIfGs_resetDan(); dComIfGs_setRestartRoomParam(0); + +#if TARGET_PC + if (dusk::getSettings().game.speedrunMode && dusk::getSettings().game.hideTvSettingsScreen) { + // start a new run on file load if a run isn't already in progress + if (!dusk::g_imguiConsole.isSpeedrunStart()) { + dusk::g_imguiConsole.startSpeedrun(); + } + } +#endif } } diff --git a/src/dusk/imgui/ImGuiConsole.cpp b/src/dusk/imgui/ImGuiConsole.cpp index c64314a806..955cef3920 100644 --- a/src/dusk/imgui/ImGuiConsole.cpp +++ b/src/dusk/imgui/ImGuiConsole.cpp @@ -334,7 +334,6 @@ namespace dusk { if (showMenu && ImGui::BeginMainMenuBar()) { m_menuGame.draw(); m_menuTools.draw(); - m_menuSpeedrunTimer.draw(); const auto fpsLabel = fmt::format(FMT_STRING("FPS: {:.2f}\n"), ImGui::GetIO().Framerate); @@ -366,12 +365,11 @@ namespace dusk { } } - m_menuSpeedrunTimer.drawOverlay(); - UpdateDragScroll(); m_menuGame.windowControllerConfig(); m_menuGame.windowInputViewer(); + m_menuGame.drawSpeedrunTimerOverlay(); if (getSettings().game.liveSplitEnabled) { dusk::speedrun::updateLiveSplit(); @@ -381,7 +379,7 @@ namespace dusk { AddToast("LiveSplit disconnected"); } - if (dusk::IsGameLaunched) { + if (dusk::IsGameLaunched && !dusk::getSettings().game.speedrunMode) { m_menuTools.ShowDebugOverlay(); m_menuTools.ShowCameraOverlay(); m_menuTools.ShowProcessManager(); @@ -392,8 +390,9 @@ namespace dusk { m_menuTools.ShowPlayerInfo(); m_menuTools.ShowAudioDebug(); m_menuTools.ShowSaveEditor(); + m_menuTools.ShowStateShare(); } - m_menuTools.ShowStateShare(); + DuskDebugPad(); // temporary, remove later // Hide mouse cursor if the F1 menu is not open and the cursor is idle for 3 seconds. diff --git a/src/dusk/imgui/ImGuiConsole.hpp b/src/dusk/imgui/ImGuiConsole.hpp index 85e65d21a1..5e9f2aa523 100644 --- a/src/dusk/imgui/ImGuiConsole.hpp +++ b/src/dusk/imgui/ImGuiConsole.hpp @@ -10,7 +10,6 @@ #include "ImGuiFirstRunPreset.hpp" #include "ImGuiMenuGame.hpp" -#include "ImGuiMenuSpeedrunTimer.hpp" #include "ImGuiMenuTools.hpp" #include "ImGuiPreLaunchWindow.hpp" #include "imgui.h" @@ -30,6 +29,11 @@ public: static bool CheckMenuViewToggle(ImGuiKey key, bool& active); void AddToast(std::string_view message, float duration = 3.f); + bool isSpeedrunStart() const { return m_menuGame.isRunStarted(); } + void startSpeedrun() { m_menuGame.startRun(); } + void stopSpeedrun() { m_menuGame.stopRun(); } + void incSpeedrunTotalLoadTime(OSTime time) { m_menuGame.incTotalLoadTime(time); } + private: struct Toast { std::string message; @@ -53,7 +57,6 @@ private: ImGuiFirstRunPreset m_firstRunPreset; ImGuiMenuGame m_menuGame; - ImGuiMenuSpeedrunTimer m_menuSpeedrunTimer; ImGuiPreLaunchWindow m_preLaunchWindow; // Keep always last diff --git a/src/dusk/imgui/ImGuiMenuGame.cpp b/src/dusk/imgui/ImGuiMenuGame.cpp index 7e54f2ffa3..fbea49bcf9 100644 --- a/src/dusk/imgui/ImGuiMenuGame.cpp +++ b/src/dusk/imgui/ImGuiMenuGame.cpp @@ -12,12 +12,15 @@ #include "dusk/main.h" #include "dusk/hotkeys.h" #include "dusk/settings.h" +#include "dusk/livesplit.h" #include "m_Do/m_Do_controller_pad.h" #include "m_Do/m_Do_graphic.h" #include #include +#include "m_Do/m_Do_main.h" + namespace { constexpr int kInternalResolutionScaleMax = 12; } // namespace @@ -199,6 +202,7 @@ namespace dusk { ImGui::SeparatorText("Difficulty"); + ImGui::BeginDisabled(getSettings().game.speedrunMode); config::ImGuiSliderInt("Damage Multiplier", getSettings().game.damageMultiplier, 1, 8, "x%d"); config::ImGuiCheckbox("Instant Death", getSettings().game.instantDeath); @@ -211,6 +215,7 @@ namespace dusk { ImGui::SetTooltip("Hearts will never drop from enemies,\n" "pots and various other places."); } + ImGui::EndDisabled(); ImGui::SeparatorText("Quality of Life"); @@ -280,12 +285,39 @@ namespace dusk { ImGui::SetTooltip("Transform instantly by pressing R and Y simultaneously."); } + ImGui::SeparatorText("Speedrunning"); + if (config::ImGuiCheckbox("Speedrun Mode", getSettings().game.speedrunMode)) { + resetForSpeedrunMode(); + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Enables Speedrunning options, while restricting certain gameplay modifiers."); + } + + ImGui::BeginDisabled(!getSettings().game.speedrunMode); + bool prevLiveSplit = getSettings().game.liveSplitEnabled; + config::ImGuiCheckbox("LiveSplit Connection", getSettings().game.liveSplitEnabled); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Connect to LiveSplit server on localhost:16834."); + } + ImGui::EndDisabled(); + + if ((bool)getSettings().game.liveSplitEnabled != prevLiveSplit) { + if (getSettings().game.liveSplitEnabled) { + dusk::speedrun::connectLiveSplit(); + } else { + dusk::speedrun::disconnectLiveSplit(); + DuskToast("LiveSplit disconnected", 3.f); + } + } + ImGui::EndMenu(); } } void ImGuiMenuGame::drawCheatsMenu() { if (ImGui::BeginMenu("Cheats")) { + ImGui::BeginDisabled(getSettings().game.speedrunMode); + ImGui::SeparatorText("Resources"); config::ImGuiCheckbox("Infinite Hearts", getSettings().game.infiniteHearts); config::ImGuiCheckbox("Infinite Arrows", getSettings().game.infiniteArrows); @@ -293,8 +325,8 @@ namespace dusk { config::ImGuiCheckbox("Infinite Oil", getSettings().game.infiniteOil); config::ImGuiCheckbox("Infinite Oxygen", getSettings().game.infiniteOxygen); config::ImGuiCheckbox("Infinite Rupees", getSettings().game.infiniteRupees); - config::ImGuiCheckbox("Items Don't Despawn", getSettings().game.enableIndefiniteItemDrops); - ImGui::SetItemTooltip("Items Don't Despawn Unless You Load A Different Room In Which Case They Do But Even Under Some Circumstances They Don't, It Is Quite Rare Though"); + config::ImGuiCheckbox("No Item Timer", getSettings().game.enableIndefiniteItemDrops); + ImGui::SetItemTooltip("Item drops such as Rupees, Hearts, etc. will never disappear after they drop."); ImGui::SeparatorText("Abilities"); config::ImGuiCheckbox("Moon Jump (R+A)", getSettings().game.moonJump); @@ -317,6 +349,8 @@ namespace dusk { ImGui::SetTooltip("Makes the magic armor work without rupees."); } + ImGui::EndDisabled(); + ImGui::EndMenu(); } } @@ -431,10 +465,12 @@ namespace dusk { ImGui::SeparatorText("Tools"); + ImGui::BeginDisabled(getSettings().game.speedrunMode); config::ImGuiCheckbox("Turbo Key", getSettings().game.enableTurboKeybind); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Hold TAB to increase game speed by up to 4x."); } + ImGui::EndDisabled(); ImGui::Checkbox("Show Input Viewer", &m_showInputViewer); @@ -971,4 +1007,85 @@ namespace dusk { ImGui::End(); } + + static std::string GetFormattedTime(OSTime ticks) { + OSCalendarTime time; + OSTicksToCalendarTime(ticks, &time); + + return fmt::format("{0:02}:{1:02}:{2:02}.{3:03}", time.hour, time.min, time.sec, time.msec); + } + + void ImGuiMenuGame::resetForSpeedrunMode() { + // reset settings that should be off for speedrun mode + mDoMain::developmentMode = -1; + + getSettings().game.damageMultiplier.setValue(1); + getSettings().game.instantDeath.setValue(false); + getSettings().game.noHeartDrops.setValue(false); + + getSettings().game.infiniteHearts.setValue(false); + getSettings().game.infiniteArrows.setValue(false); + getSettings().game.infiniteBombs.setValue(false); + getSettings().game.infiniteOil.setValue(false); + getSettings().game.infiniteOxygen.setValue(false); + getSettings().game.infiniteRupees.setValue(false); + getSettings().game.enableIndefiniteItemDrops.setValue(false); + + getSettings().game.moonJump.setValue(false); + getSettings().game.superClawshot.setValue(false); + getSettings().game.alwaysGreatspin.setValue(false); + getSettings().game.enableFastIronBoots.setValue(false); + getSettings().game.canTransformAnywhere.setValue(false); + getSettings().game.fastSpinner.setValue(false); + getSettings().game.freeMagicArmor.setValue(false); + + getSettings().game.enableTurboKeybind.setValue(false); + } + + void ImGuiMenuGame::drawSpeedrunTimerOverlay() { + if (!getSettings().game.speedrunMode) { + return; + } + + // L+R+A+Start to reset timer + if (mDoCPd_c::getHoldL(PAD_1) && mDoCPd_c::getHoldR(PAD_1) && mDoCPd_c::getHoldA(PAD_1) && mDoCPd_c::getTrigStart(PAD_1)) { + m_speedrunInfo.m_endTimestamp = 0; + m_speedrunInfo.m_startTimestamp = 0; + m_speedrunInfo.m_totalLoadTime = 0; + m_speedrunInfo.m_isRunStarted = false; + } + + // L+R+A+Z to manually stop timer + if (mDoCPd_c::getHoldL(PAD_1) && mDoCPd_c::getHoldR(PAD_1) && mDoCPd_c::getHoldA(PAD_1) && mDoCPd_c::getTrigZ(PAD_1)) { + if (m_speedrunInfo.m_isRunStarted) { + m_speedrunInfo.m_endTimestamp = OSGetTime() - m_speedrunInfo.m_startTimestamp; + m_speedrunInfo.m_isRunStarted = false; + } + } + + ImGui::SetNextWindowBgAlpha(0.65f); + ImGuiWindowFlags flags = + ImGuiWindowFlags_NoResize + | ImGuiWindowFlags_NoDocking + | ImGuiWindowFlags_NoTitleBar + | ImGuiWindowFlags_NoScrollbar; + + if (ImGui::Begin("##SpeedrunTimerWindow", nullptr, flags)) { + OSTime elapsedTime = 0; + if (m_speedrunInfo.m_isRunStarted) { + elapsedTime = OSGetTime() - m_speedrunInfo.m_startTimestamp; + } else if (m_speedrunInfo.m_endTimestamp != 0) { + elapsedTime = m_speedrunInfo.m_endTimestamp; + } + + ImGui::Text("RTA"); + ImGui::SameLine(60.0f); + ImGuiStringViewText(GetFormattedTime(elapsedTime)); + + ImGui::Text("IGT"); + ImGui::SameLine(60.0f); + ImGuiStringViewText(GetFormattedTime(elapsedTime - m_speedrunInfo.m_totalLoadTime)); + } + ImGui::End(); + } } diff --git a/src/dusk/imgui/ImGuiMenuGame.hpp b/src/dusk/imgui/ImGuiMenuGame.hpp index e21374c8f4..795cf5f446 100644 --- a/src/dusk/imgui/ImGuiMenuGame.hpp +++ b/src/dusk/imgui/ImGuiMenuGame.hpp @@ -15,9 +15,23 @@ namespace dusk { void windowInputViewer(); void windowControllerConfig(); + void drawSpeedrunTimerOverlay(); static void ToggleFullscreen(); + static void resetForSpeedrunMode(); + bool isRunStarted() const { return m_speedrunInfo.m_isRunStarted; } + void startRun() { + resetForSpeedrunMode(); + m_speedrunInfo.m_isRunStarted = true; + m_speedrunInfo.m_startTimestamp = OSGetTime(); + } + void stopRun() { + m_speedrunInfo.m_isRunStarted = false; + m_speedrunInfo.m_endTimestamp = OSGetTime() - m_speedrunInfo.m_startTimestamp; + } + void incTotalLoadTime(OSTime time) { m_speedrunInfo.m_totalLoadTime += time; } + private: void drawAudioMenu(); void drawInputMenu(); @@ -40,6 +54,14 @@ namespace dusk { bool m_showInputViewerGyro = false; int m_inputOverlayCorner = 3; std::string m_controllerName; + + struct { + bool m_showTimerWindow = false; + bool m_isRunStarted = false; + OSTime m_startTimestamp = 0; + OSTime m_endTimestamp = 0; + OSTime m_totalLoadTime = 0; + } m_speedrunInfo; }; } diff --git a/src/dusk/imgui/ImGuiMenuSpeedrunTimer.cpp b/src/dusk/imgui/ImGuiMenuSpeedrunTimer.cpp deleted file mode 100644 index 6edbb7e084..0000000000 --- a/src/dusk/imgui/ImGuiMenuSpeedrunTimer.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include "fmt/format.h" -#include "imgui.h" - -#include "ImGuiMenuSpeedrunTimer.hpp" -#include "ImGuiConfig.hpp" -#include "ImGuiConsole.hpp" -#include "dusk/livesplit.h" -#include "dusk/settings.h" - -namespace dusk { - static auto formatTime(uint64_t frames) { - const uint64_t totalSec = frames / 30; - - return fmt::format( - FMT_STRING("{:d}:{:02d}:{:02d}.{:02d}"), - totalSec / 3600, - (totalSec / 60) % 60, - totalSec % 60, - (int)(((f32)(frames % 30) / 30.0f) * 100.0f) - ); - } - - void ImGuiMenuSpeedrunTimer::draw() { - if (!getSettings().game.speedrunTimer) return; - - const uint64_t frames = dusk::speedrun::getFrameCount(); - - if (ImGui::BeginMenu("Timer##speedrun_timer")) { - ImGui::TextUnformatted(formatTime(frames).c_str()); - - ImGui::Separator(); - - if (ImGui::MenuItem("Reset")) { - dusk::speedrun::reset(); - } - - config::ImGuiCheckbox("Show Overlay", getSettings().game.speedrunTimerOverlay); - - bool prevLiveSplit = getSettings().game.liveSplitEnabled; - config::ImGuiCheckbox("LiveSplit Connection", getSettings().game.liveSplitEnabled); - - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Connect to LiveSplit server on localhost:16834."); - } - - if ((bool)getSettings().game.liveSplitEnabled != prevLiveSplit) { - if (getSettings().game.liveSplitEnabled) { - dusk::speedrun::connectLiveSplit(); - } else { - dusk::speedrun::disconnectLiveSplit(); - DuskToast("LiveSplit disconnected", 3.f); - } - } - - ImGui::EndMenu(); - } - - } - - void ImGuiMenuSpeedrunTimer::drawOverlay() { - if (!getSettings().game.speedrunTimer || !getSettings().game.speedrunTimerOverlay) { - return; - } - - const uint64_t frames = dusk::speedrun::getFrameCount(); - const ImGuiViewport* viewport = ImGui::GetMainViewport(); - - const float padding = 10.f; - - ImGui::SetNextWindowPos( - ImVec2( - viewport->WorkPos.x + viewport->WorkSize.x - padding, - viewport->WorkPos.y + viewport->WorkSize.y - padding - ), - ImGuiCond_Always, ImVec2(1.f, 1.f) - ); - - ImGui::SetNextWindowBgAlpha(0.65f); - - const float fixedWidth = ImGui::CalcTextSize("9:59:59.99").x; - - ImGui::SetNextWindowContentSize(ImVec2(fixedWidth, 0.f)); - - if ( - ImGui::Begin("##speedrun_overlay", nullptr, - ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoInputs | - ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | - ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | - ImGuiWindowFlags_NoNav - ) - ) { - ImGui::TextUnformatted(formatTime(frames).c_str()); - } - ImGui::End(); - } -} diff --git a/src/dusk/imgui/ImGuiMenuTools.cpp b/src/dusk/imgui/ImGuiMenuTools.cpp index 00a03e635b..5dd5a62d84 100644 --- a/src/dusk/imgui/ImGuiMenuTools.cpp +++ b/src/dusk/imgui/ImGuiMenuTools.cpp @@ -50,10 +50,14 @@ namespace dusk { ImGui::BeginDisabled(); } + ImGui::BeginDisabled(getSettings().game.speedrunMode); + ImGui::MenuItem("Save Editor", hotkeys::SHOW_SAVE_EDITOR, &m_showSaveEditor); ImGui::MenuItem("Map Loader", hotkeys::SHOW_MAP_LOADER, &m_showMapLoader); ImGui::MenuItem("State Share", hotkeys::SHOW_STATE_SHARE, &m_showStateShare); + ImGui::EndDisabled(); + if (!dusk::IsGameLaunched) { ImGui::EndDisabled(); } @@ -69,6 +73,8 @@ namespace dusk { } if (ImGui::BeginMenu("Debug")) { + ImGui::BeginDisabled(getSettings().game.speedrunMode); + bool developmentMode = mDoMain::developmentMode == 1; if (ImGui::Checkbox("Development Mode", &developmentMode)) { mDoMain::developmentMode = developmentMode ? 1 : -1; @@ -117,6 +123,9 @@ namespace dusk { } ImGui::MenuItem("OSReport Force", nullptr, &OSReportReallyForceEnable); + + ImGui::EndDisabled(); + ImGui::EndMenu(); } } diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index bddc30cb84..843dd4b133 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -92,8 +92,7 @@ UserSettings g_userSettings = { .enableTurboKeybind {"game.enableTurboKeybind", false}, // Tools - .speedrunTimer {"game.speedrunTimer", false}, - .speedrunTimerOverlay {"game.speedrunTimerOverlay", false}, + .speedrunMode {"game.speedrunMode", false}, .liveSplitEnabled {"game.liveSplitEnabled", false} }, @@ -162,8 +161,7 @@ void registerSettings() { Register(g_userSettings.game.noLowHpSound); Register(g_userSettings.game.midnasLamentNonStop); Register(g_userSettings.game.enableTurboKeybind); - Register(g_userSettings.game.speedrunTimer); - Register(g_userSettings.game.speedrunTimerOverlay); + Register(g_userSettings.game.speedrunMode); Register(g_userSettings.game.liveSplitEnabled); Register(g_userSettings.game.fastSpinner); Register(g_userSettings.game.infiniteHearts); diff --git a/src/f_op/f_op_scene_req.cpp b/src/f_op/f_op_scene_req.cpp index 79b87eee4c..e4ce889266 100644 --- a/src/f_op/f_op_scene_req.cpp +++ b/src/f_op/f_op_scene_req.cpp @@ -4,13 +4,14 @@ */ #include "f_op/f_op_scene_req.h" +#include +#include "dusk/imgui/ImGuiConsole.hpp" +#include "dusk/logging.h" #include "f_op/f_op_overlap_mng.h" #include "f_op/f_op_scene.h" #include "f_op/f_op_scene_pause.h" #include "f_pc/f_pc_executor.h" #include "f_pc/f_pc_manager.h" -#include -#include "dusk/logging.h" static cPhs_Step fopScnRq_phase_ClearOverlap(scene_request_class* i_sceneReq) { return fopOvlpM_ClearOfReq() == 1 ? cPhs_NEXT_e : cPhs_INIT_e; @@ -39,6 +40,10 @@ static cPhs_Step fopScnRq_phase_IsDoneOverlap(scene_request_class* i_sceneReq) { static BOOL l_fopScnRq_IsUsingOfOverlap; +#if TARGET_PC +static OSTime l_fopScnRq_StartTime = 0; +#endif + static cPhs_Step fopScnRq_phase_Done(scene_request_class* i_sceneReq) { if (i_sceneReq->create_request.parameters != 1) { @@ -48,6 +53,14 @@ static cPhs_Step fopScnRq_phase_Done(scene_request_class* i_sceneReq) { } l_fopScnRq_IsUsingOfOverlap = FALSE; + #if TARGET_PC + if (dusk::getSettings().game.speedrunMode) { + if (dusk::g_imguiConsole.isSpeedrunStart()) { + dusk::g_imguiConsole.incSpeedrunTotalLoadTime(OSGetTime() - l_fopScnRq_StartTime); + } + } + #endif + return cPhs_NEXT_e; } @@ -88,6 +101,10 @@ static scene_request_class* fopScnRq_FadeRequest(s16 i_procname, u16 i_peektime) req = fopOvlpM_Request(i_procname, i_peektime); if (req != NULL) { l_fopScnRq_IsUsingOfOverlap = TRUE; + + #if TARGET_PC + l_fopScnRq_StartTime = OSGetTime(); + #endif } } From 6cf94b4491c62684e47add925d8c4f70d39dbf90 Mon Sep 17 00:00:00 2001 From: TakaRikka Date: Sat, 25 Apr 2026 21:18:51 -0700 Subject: [PATCH 041/390] remove unneeded file --- src/dusk/imgui/ImGuiMenuSpeedrunTimer.hpp | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 src/dusk/imgui/ImGuiMenuSpeedrunTimer.hpp diff --git a/src/dusk/imgui/ImGuiMenuSpeedrunTimer.hpp b/src/dusk/imgui/ImGuiMenuSpeedrunTimer.hpp deleted file mode 100644 index 8cb524469f..0000000000 --- a/src/dusk/imgui/ImGuiMenuSpeedrunTimer.hpp +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef DUSK_IMGUI_MENUSPEEDRUNTIMER_HPP -#define DUSK_IMGUI_MENUSPEEDRUNTIMER_HPP - -namespace dusk { - class ImGuiMenuSpeedrunTimer { - public: - void draw(); - void drawOverlay(); - private: - }; -} - -#endif // DUSK_IMGUI_MENUSPEEDRUNTIMER_HPP From 02924549be425dd9818aa1df3f8148669d97a934 Mon Sep 17 00:00:00 2001 From: Pheenoh Date: Sat, 25 Apr 2026 21:55:40 -0600 Subject: [PATCH 042/390] fix idle howl blinking --- src/d/d_msg_scrn_howl.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/d/d_msg_scrn_howl.cpp b/src/d/d_msg_scrn_howl.cpp index 1d39cba1a1..c701ea0b2b 100644 --- a/src/d/d_msg_scrn_howl.cpp +++ b/src/d/d_msg_scrn_howl.cpp @@ -20,6 +20,7 @@ #include "Z2AudioLib/Z2WolfHowlMgr.h" #if TARGET_PC +#include "dusk/frame_interpolation.h" #include "dusk/settings.h" #endif @@ -580,9 +581,14 @@ void dMsgScrnHowl_c::drawWave() { f17 = local_60; f18 = local_64; } else { - field_0x2134++; - if (field_0x2134 > 30) { - field_0x2134 = 0; +#if TARGET_PC + if (dusk::frame_interp::get_ui_tick_pending()) +#endif + { + field_0x2134++; + if (field_0x2134 > 30) { + field_0x2134 = 0; + } } if (field_0x2134 < 15) { local_dc = field_0x2134 / 15.0f; From c1231885fe515f13791ae32f33e48471f9991a31 Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Sat, 25 Apr 2026 22:17:17 -0700 Subject: [PATCH 043/390] Add rumble intensity sliders to input configurator (#558) --- src/dusk/imgui/ImGuiMenuGame.cpp | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/dusk/imgui/ImGuiMenuGame.cpp b/src/dusk/imgui/ImGuiMenuGame.cpp index 0a687233aa..42dfc8af65 100644 --- a/src/dusk/imgui/ImGuiMenuGame.cpp +++ b/src/dusk/imgui/ImGuiMenuGame.cpp @@ -965,7 +965,7 @@ namespace dusk { ImGui::SameLine(); // Options panel - ImGuiBeginGroupPanel("Options", ImVec2(150 * scale, 20 * scale)); + ImGuiBeginGroupPanel("Options", ImVec2(150 * scale, -1)); if (deadZones != nullptr) { if (ImGui::Checkbox("Enable Dead Zones", &deadZones->useDeadzones)) { @@ -975,7 +975,24 @@ namespace dusk { PADSerializeMappings(); } } - + + if (PADSupportsRumbleIntensity(m_controllerConfig.m_selectedPort)) { + ImGuiBeginGroupPanel("Rumble Intensity", ImVec2(150 * scale, -1)); + u16 low; + u16 high; + (void)PADGetRumbleIntensity(m_controllerConfig.m_selectedPort, &low, &high); + float fLow = static_cast(low / 32767) * 100.f; + bool changed = ImGui::SliderFloat("Low", &fLow, 0.f, 100.f, "%.0f%%"); + float fHigh = static_cast(high / 32767) * 100.f; + changed |= ImGui::SliderFloat("High", &fHigh, 0.f, 100.f, "%.0f%%"); + if (changed) { + PADSetRumbleIntensity(m_controllerConfig.m_selectedPort, + static_cast((fLow / 100.f) * 32767), + static_cast((fHigh / 100.f) * 32767)); + PADSerializeMappings(); + } + ImGuiEndGroupPanel(); + } ImGuiEndGroupPanel(); ImGui::End(); From 8784958c40d8205df876d2ef5dd2b3b837d328f5 Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Sat, 25 Apr 2026 22:51:39 -0700 Subject: [PATCH 044/390] Quick PAD rumble fixes, add button to test rumble configuration --- extern/aurora | 2 +- src/dusk/imgui/ImGuiMenuGame.cpp | 12 ++++++++---- src/dusk/imgui/ImGuiMenuGame.hpp | 1 + 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/extern/aurora b/extern/aurora index 135e976867..8af9057689 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 135e976867490380356878c8bb8d1956932489c5 +Subproject commit 8af9057689b9b85a55bbbd6218bc95304558fabd diff --git a/src/dusk/imgui/ImGuiMenuGame.cpp b/src/dusk/imgui/ImGuiMenuGame.cpp index 42dfc8af65..dcfcc55657 100644 --- a/src/dusk/imgui/ImGuiMenuGame.cpp +++ b/src/dusk/imgui/ImGuiMenuGame.cpp @@ -981,16 +981,20 @@ namespace dusk { u16 low; u16 high; (void)PADGetRumbleIntensity(m_controllerConfig.m_selectedPort, &low, &high); - float fLow = static_cast(low / 32767) * 100.f; + float fLow = (static_cast(low) / 32767.f) * 100.f; bool changed = ImGui::SliderFloat("Low", &fLow, 0.f, 100.f, "%.0f%%"); - float fHigh = static_cast(high / 32767) * 100.f; + float fHigh = (static_cast(high) / 32767.f) * 100.f; changed |= ImGui::SliderFloat("High", &fHigh, 0.f, 100.f, "%.0f%%"); if (changed) { PADSetRumbleIntensity(m_controllerConfig.m_selectedPort, - static_cast((fLow / 100.f) * 32767), - static_cast((fHigh / 100.f) * 32767)); + static_cast((fLow / 100) * 32767), + static_cast((fHigh / 100) * 32767)); PADSerializeMappings(); } + if (ImGui::Button(fmt::format("{0}...##rumbleTest", m_controllerConfig.m_isRumbling ? "Stop": "Test").c_str(), {-1, 0})) { + PADControlMotor(m_controllerConfig.m_selectedPort, !m_controllerConfig.m_isRumbling ? PAD_MOTOR_RUMBLE : PAD_MOTOR_STOP_HARD); + m_controllerConfig.m_isRumbling ^= 1; + } ImGuiEndGroupPanel(); } ImGuiEndGroupPanel(); diff --git a/src/dusk/imgui/ImGuiMenuGame.hpp b/src/dusk/imgui/ImGuiMenuGame.hpp index e21374c8f4..fb3f3f10ca 100644 --- a/src/dusk/imgui/ImGuiMenuGame.hpp +++ b/src/dusk/imgui/ImGuiMenuGame.hpp @@ -32,6 +32,7 @@ namespace dusk { PADButtonMapping* m_pendingButtonMapping = nullptr; PADAxisMapping* m_pendingAxisMapping = nullptr; int m_pendingPort = -1; + bool m_isRumbling = false; } m_controllerConfig; bool m_showControllerConfig = false; From 3498ded9d9c2ae29b032915cdd8122577683b89f Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Sun, 26 Apr 2026 10:18:47 -0400 Subject: [PATCH 045/390] ImGui Button name change + Fix Freecam Invert X Axis option --- src/d/d_camera.cpp | 7 +++---- src/dusk/imgui/ImGuiPreLaunchWindow.cpp | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/d/d_camera.cpp b/src/d/d_camera.cpp index 917b30709a..8efef81b8e 100644 --- a/src/d/d_camera.cpp +++ b/src/d/d_camera.cpp @@ -7493,10 +7493,9 @@ bool dCamera_c::freeCamera() { } camMovement = camMovement.normalize(); - camMovement.x *= (dusk::getSettings().game.invertCameraXAxis ? 1.0f : -1.0f) * dusk::getSettings().game.freeCameraSensitivity * 4.0f; - camMovement.y *= (dusk::getSettings().game.invertCameraYAxis ? 1.0f : -1.0f) * dusk::getSettings().game.freeCameraSensitivity * 4.0f; - mCamParam.freeXAngle += camMovement.x * magnitude * dusk::getSettings().game.freeCameraSensitivity; - mCamParam.freeYAngle += camMovement.y * magnitude * dusk::getSettings().game.freeCameraSensitivity; + camMovement.y *= dusk::getSettings().game.invertCameraYAxis ? 1.0f : -1.0f; + mCamParam.freeXAngle += camMovement.x * magnitude * dusk::getSettings().game.freeCameraSensitivity * 4.0f; + mCamParam.freeYAngle += camMovement.y * magnitude * dusk::getSettings().game.freeCameraSensitivity * 4.0f; } if (mCamParam.mManualMode) { diff --git a/src/dusk/imgui/ImGuiPreLaunchWindow.cpp b/src/dusk/imgui/ImGuiPreLaunchWindow.cpp index 6347e9bc01..4bfcce9047 100644 --- a/src/dusk/imgui/ImGuiPreLaunchWindow.cpp +++ b/src/dusk/imgui/ImGuiPreLaunchWindow.cpp @@ -193,7 +193,7 @@ void ImGuiPreLaunchWindow::drawOptions() { ImGui::InputText("Game ISO Path", &m_selectedIsoPath, ImGuiInputTextFlags_ReadOnly); ImGui::SameLine(); - if (ImGui::Button("Set")) { + if (ImGui::Button(m_selectedIsoPath == "" ? "Set" : "Change")) { ShowFileSelect(&fileDialogCallback, this, aurora::window::get_sdl_window(), skGameDiscFileFilters.data(), int(skGameDiscFileFilters.size()), nullptr, false); From 3859f397294e6e906fdf372ed64edcbcf38a623f Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Sun, 26 Apr 2026 10:25:10 -0400 Subject: [PATCH 046/390] Fix camera radius to be smoother --- src/d/d_camera.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d/d_camera.cpp b/src/d/d_camera.cpp index 8efef81b8e..c59cf1c525 100644 --- a/src/d/d_camera.cpp +++ b/src/d/d_camera.cpp @@ -7502,7 +7502,7 @@ bool dCamera_c::freeCamera() { mCamParam.freeYAngle = std::clamp(mCamParam.freeYAngle, -35.0f, 60.0f); mViewCache.mDirection.mAzimuth = cSAngle(mCamParam.freeXAngle); mViewCache.mDirection.mInclination = cSAngle(mCamParam.freeYAngle); - mViewCache.mDirection.mRadius = std::clamp(mCamParam.freeYAngle * 15.0f, 300.0f, 10000.0f); + mViewCache.mDirection.mRadius = std::clamp((mCamParam.freeYAngle + 35.0f) * 10.0f, 300.0f, 10000.0f); } return mCamParam.mManualMode; From 5c84978c3cfd6a1d15228198d6537a00a8961f99 Mon Sep 17 00:00:00 2001 From: "Jasper St. Pierre" Date: Sun, 26 Apr 2026 10:44:52 -0700 Subject: [PATCH 047/390] evil perf fix closes #552 --- src/d/d_kankyo_rain.cpp | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/src/d/d_kankyo_rain.cpp b/src/d/d_kankyo_rain.cpp index 822612768c..09e230c9fd 100644 --- a/src/d/d_kankyo_rain.cpp +++ b/src/d/d_kankyo_rain.cpp @@ -5962,6 +5962,8 @@ static void dKyr_evil_draw2(Mtx drawMtx, u8** tex) { fopAc_ac_c* player = dComIfGp_getPlayer(0); if (evil_packet != NULL) { + IF_DUSK(GXPushDebugGroup("dKyr_evil_draw2")); + j3dSys.reinitGX(); if (dComIfGd_getView() != NULL) { MTXInverse(dComIfGd_getView()->viewMtxNoTrans, camMtx); @@ -6162,6 +6164,8 @@ static void dKyr_evil_draw2(Mtx drawMtx, u8** tex) { } } + IF_DUSK(GXPopDebugGroup()); + GXSetClipMode(GX_CLIP_ENABLE); J3DShape::resetVcdVatCache(); } @@ -6199,6 +6203,8 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) { f32 sp60 = fabsf(cM_ssin(g_Counter.mCounter0 * 215)); if (evil_packet != NULL) { + IF_DUSK(GXPushDebugGroup("dKyr_evil_draw")); + j3dSys.reinitGX(); if (dComIfGd_getView() != NULL) { MTXInverse(dComIfGd_getView()->viewMtxNoTrans, camMtx); @@ -6231,8 +6237,8 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) { GXLoadPosMtxImm(drawMtx, GX_PNMTX0); GXSetCurrentMtx(GX_PNMTX0); - GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_CLR_RGBA, GX_F32, 0); - GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_CLR_RGBA, GX_RGBA4, 8); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_RGBA4, 8); GXClearVtxDesc(); GXSetVtxDesc(GX_VA_POS, GX_DIRECT); GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT); @@ -6255,6 +6261,19 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) { GXSetClipMode(GX_CLIP_DISABLE); GXSetNumIndStages(0); +#if TARGET_PC + // move color_reg0 to vtx for perf + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); + GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT); + GXSetNumChans(1); + GXSetChanCtrl(GX_COLOR0A0, GX_FALSE, GX_SRC_REG, GX_SRC_VTX, 0, GX_DF_NONE, GX_AF_NONE); + GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0); + GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_C1, GX_CC_RASC, GX_CC_TEXC, GX_CC_ZERO); + GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); + GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_TEXA, GX_CA_RASA, GX_CA_ZERO); + GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); +#endif + dComIfG_Ccsp()->PrepareMass(); for (int i = 0; i < g_env_light.field_0x1054; i++) { @@ -6373,7 +6392,7 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) { color_reg0.b = (115.0f * sp28) + (15.0f * fabsf(sp2C - sp64)); } - GXSetTevColor(GX_TEVREG0, color_reg0); + IF_NOT_DUSK(GXSetTevColor(GX_TEVREG0, color_reg0)); GXSetTevColor(GX_TEVREG1, color_reg1); spC8 = spA4; @@ -6412,12 +6431,16 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) { GXBegin(GX_QUADS, GX_VTXFMT0, 4); GXPosition3f32(pos[0].x, pos[0].y, pos[0].z); + IF_DUSK(GXColor4u8(color_reg0.r, color_reg0.g, color_reg0.b, color_reg0.a)); GXTexCoord2s16(0, 0); GXPosition3f32(pos[1].x, pos[1].y, pos[1].z); + IF_DUSK(GXColor4u8(color_reg0.r, color_reg0.g, color_reg0.b, color_reg0.a)); GXTexCoord2s16(0xFF, 0); GXPosition3f32(pos[2].x, pos[2].y, pos[2].z); + IF_DUSK(GXColor4u8(color_reg0.r, color_reg0.g, color_reg0.b, color_reg0.a)); GXTexCoord2s16(0xFF, 0xFF); GXPosition3f32(pos[3].x, pos[3].y, pos[3].z); + IF_DUSK(GXColor4u8(color_reg0.r, color_reg0.g, color_reg0.b, color_reg0.a)); GXTexCoord2s16(0, 0xFF); GXEnd(); } @@ -6425,6 +6448,8 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) { } } + IF_DUSK(GXPopDebugGroup()); + J3DShape::resetVcdVatCache(); GXSetClipMode(GX_CLIP_ENABLE); From 50e2d9d1a713afa52cb5fcd533e31a21527c7e8e Mon Sep 17 00:00:00 2001 From: "Jasper St. Pierre" Date: Sun, 26 Apr 2026 11:18:23 -0700 Subject: [PATCH 048/390] grass draw fix closes #534 --- src/d/actor/d_flower.inc | 14 ++------------ src/d/actor/d_grass.inc | 14 ++++++-------- 2 files changed, 8 insertions(+), 20 deletions(-) diff --git a/src/d/actor/d_flower.inc b/src/d/actor/d_flower.inc index 5f54ea4bda..4024d5ad6a 100644 --- a/src/d/actor/d_flower.inc +++ b/src/d/actor/d_flower.inc @@ -7,13 +7,8 @@ #include "dusk/frame_interpolation.h" -#if TARGET_PC -const u16 l_J_Ohana00_64TEX__width = 64; -const u16 l_J_Ohana00_64TEX__height = 64; -#else const u16 l_J_Ohana00_64TEX__width = 63; const u16 l_J_Ohana00_64TEX__height = 63; -#endif #if TARGET_PC #include "dusk/dvd_asset.hpp" @@ -136,13 +131,8 @@ l_matDL__d_a_grass(l_J_Ohana00_64TEX) l_matLight4DL(l_J_Ohana00_64TEX) #endif -#if TARGET_PC -const u16 l_J_Ohana01_64128_0419TEX__width = 64; -const u16 l_J_Ohana01_64128_0419TEX__height = 128; -#else const u16 l_J_Ohana01_64128_0419TEX__width = 63; const u16 l_J_Ohana01_64128_0419TEX__height = 127; -#endif #if TARGET_PC using GameVersion = dusk::version::GameVersion; @@ -592,11 +582,11 @@ dFlower_packet_c::dFlower_packet_c() { #if TARGET_PC GXInitTexObj(&mTexObj_l_J_Ohana00_64TEX, l_J_Ohana00_64TEX, - l_J_Ohana00_64TEX__width, l_J_Ohana00_64TEX__height, GX_TF_CMPR, GX_MIRROR, GX_MIRROR, GX_FALSE + l_J_Ohana00_64TEX__width + 1, l_J_Ohana00_64TEX__height + 1, GX_TF_CMPR, GX_MIRROR, GX_MIRROR, GX_FALSE ); GXInitTexObj(&mTexObj_l_J_Ohana01_64128_0419TEX, l_J_Ohana01_64128_0419TEX, - l_J_Ohana01_64128_0419TEX__width, l_J_Ohana01_64128_0419TEX__height, GX_TF_CMPR, GX_MIRROR, GX_MIRROR, GX_FALSE + l_J_Ohana01_64128_0419TEX__width + 1, l_J_Ohana01_64128_0419TEX__height + 1, GX_TF_CMPR, GX_MIRROR, GX_MIRROR, GX_FALSE ); #endif diff --git a/src/d/actor/d_grass.inc b/src/d/actor/d_grass.inc index 9bc8815753..3d67a57007 100644 --- a/src/d/actor/d_grass.inc +++ b/src/d/actor/d_grass.inc @@ -494,11 +494,11 @@ dGrass_packet_c::dGrass_packet_c() { #if TARGET_PC GXInitTexObj(&mTexObj_l_M_kusa05_RGBATEX, l_M_kusa05_RGBATEX, - l_M_kusa05_RGBATEX__width, l_M_kusa05_RGBATEX__height, GX_TF_RGB5A3, GX_REPEAT, GX_CLAMP, GX_FALSE + l_M_kusa05_RGBATEX__width + 1, l_M_kusa05_RGBATEX__height + 1, GX_TF_RGB5A3, GX_REPEAT, GX_CLAMP, GX_FALSE ); GXInitTexObj(&mTexObj_l_M_Hijiki00TEX, l_M_Hijiki00TEX, - l_M_Hijiki00TEX__width, l_M_Hijiki00TEX__height, GX_TF_RGB5A3, GX_REPEAT, GX_CLAMP, GX_FALSE + l_M_Hijiki00TEX__width + 1, l_M_Hijiki00TEX__height + 1, GX_TF_RGB5A3, GX_REPEAT, GX_CLAMP, GX_FALSE ); #endif @@ -646,18 +646,14 @@ void dGrass_packet_c::draw() { } if (var_r29->field_0x05 <= 3 || var_r29->field_0x05 >= 10) { -#if TARGET_PC - GXLoadTexObj(&mTexObj_l_M_kusa05_RGBATEX, GX_TEXMAP0); -#endif + IF_DUSK(GXLoadTexObj(&mTexObj_l_M_kusa05_RGBATEX, GX_TEXMAP0)); if (sp48 <= 3) { GXCallDisplayList(mp_kusa9q_14_DL, m_kusa9q_DL_14_size); } else { GXCallDisplayList(mp_kusa9q_DL, m_kusa9q_DL_size); } } else { -#if TARGET_PC - GXLoadTexObj(&mTexObj_l_M_Hijiki00TEX, GX_TEXMAP0); -#endif + IF_DUSK(GXLoadTexObj(&mTexObj_l_M_Hijiki00TEX, GX_TEXMAP0)); GXCallDisplayList(l_Tengusa_matDL, 0xA0); } @@ -683,12 +679,14 @@ void dGrass_packet_c::draw() { while (var_r29 != NULL) { if (var_r29->field_0x05 <= 3 || var_r29->field_0x05 >= 10) { + IF_DUSK(GXLoadTexObj(&mTexObj_l_M_kusa05_RGBATEX, GX_TEXMAP0)); if (sp48 <= 2) { GXCallDisplayList(mp_kusa9q_14_DL, m_kusa9q_DL_14_size); } else { GXCallDisplayList(mp_kusa9q_DL, m_kusa9q_DL_size); } } else { + IF_DUSK(GXLoadTexObj(&mTexObj_l_M_Hijiki00TEX, GX_TEXMAP0)); GXCallDisplayList(l_Tengusa_matDL, 0xA0); } From e75ea18ef01c2be02dc620d691c3eb13ce9105eb Mon Sep 17 00:00:00 2001 From: "Jasper St. Pierre" Date: Sun, 26 Apr 2026 11:52:20 -0700 Subject: [PATCH 049/390] map deco perf --- include/dusk/settings.h | 1 + src/d/d_map.cpp | 11 ++++------- src/d/d_map_path.cpp | 34 ++++++++++++++++++++++++-------- src/dusk/imgui/ImGuiMenuGame.cpp | 2 ++ src/dusk/settings.cpp | 2 ++ 5 files changed, 35 insertions(+), 15 deletions(-) diff --git a/include/dusk/settings.h b/include/dusk/settings.h index a7815569d0..875b839d44 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -96,6 +96,7 @@ struct UserSettings { ConfigVar internalResolutionScale; ConfigVar shadowResolutionMultiplier; ConfigVar enableDepthOfField; + ConfigVar enableMapBackground; // Audio ConfigVar noLowHpSound; diff --git a/src/d/d_map.cpp b/src/d/d_map.cpp index 7dc5187a88..a5163091fd 100644 --- a/src/d/d_map.cpp +++ b/src/d/d_map.cpp @@ -539,17 +539,14 @@ void renderingAmap_c::rendering(dDrawPath_c::poly_class const* i_poly) { } } -/* Enabling the following definition will modify the following function to - * make the map look worse for extra speed in the emulator, especially in large - * areas such as hyrule field. - */ -#define HYRULE_FIELD_SPEEDHACK bool renderingAmap_c::isDrawOutSideTrim() { bool rt = false; - #ifdef HYRULE_FIELD_SPEEDHACK - return 0; + #if TARGET_PC + if (!dusk::getSettings().game.enableMapBackground) { + return 0; + } #endif if (getDispType() == 0 || getDispType() == 4 || getDispType() == 3 || getDispType() == 2 || diff --git a/src/d/d_map_path.cpp b/src/d/d_map_path.cpp index 8288a2ef9f..f94cdc9475 100644 --- a/src/d/d_map_path.cpp +++ b/src/d/d_map_path.cpp @@ -497,12 +497,6 @@ void dRenderingFDAmap_c::postRenderingMap() { dMpath_n::dTexObjAggregate_c dMpath_n::m_texObjAgg; -/* Enabling the following definition will modify the following function to - * make the map look worse for extra speed in the emulator, especially in large - * areas such as hyrule field. - */ -#define HYRULE_FIELD_SPEEDHACK - void dRenderingFDAmap_c::renderingDecoration(dDrawPath_c::line_class const* p_line) { s32 width = getDecorationLineWidth(p_line->field_0x1); if (width <= 0) { @@ -527,8 +521,32 @@ void dRenderingFDAmap_c::renderingDecoration(dDrawPath_c::line_class const* p_li lineColor.r = lineColor.r - 4; GXSetTevColor(GX_TEVREG1, lineColor); +#if TARGET_PC + GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_C0); + GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); + GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_KONST); + GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); + GXBegin(GX_LINESTRIP, GX_VTXFMT0, 2 * (data_num - 1)); + for (int i = 0; i < data_num - 1; i++) { + GXPosition1x16(data_p[i]); + GXTexCoord2f32(0, 0); + GXPosition1x16(data_p[i + 1]); + GXTexCoord2f32(0, 0); + } + GXEnd(); + + GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_KONST, GX_CC_TEXC, GX_CC_C1); + GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); + GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_TEXA); + GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); + GXBegin(GX_POINTS, GX_VTXFMT0, data_num); + for (int i = 0; i < data_num; i++) { + GXPosition1x16(data_p[i]); + GXTexCoord2f32(0, 0); + } + GXEnd(); +#else for (int i = 0; i < data_num; i++) { -#ifndef HYRULE_FIELD_SPEEDHACK if (i < data_num - 1) { GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_C0); GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, @@ -547,7 +565,6 @@ void dRenderingFDAmap_c::renderingDecoration(dDrawPath_c::line_class const* p_li GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_TEXA); GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); -#endif GXBegin(GX_POINTS, GX_VTXFMT0, 1); GXPosition1x16(data_p[0]); @@ -555,6 +572,7 @@ void dRenderingFDAmap_c::renderingDecoration(dDrawPath_c::line_class const* p_li GXEnd(); data_p++; } +#endif setTevSettingNonTextureDirectColor(); GXClearVtxDesc(); diff --git a/src/dusk/imgui/ImGuiMenuGame.cpp b/src/dusk/imgui/ImGuiMenuGame.cpp index dcfcc55657..10b6e65bf2 100644 --- a/src/dusk/imgui/ImGuiMenuGame.cpp +++ b/src/dusk/imgui/ImGuiMenuGame.cpp @@ -167,6 +167,8 @@ namespace dusk { config::ImGuiCheckbox("Enable Depth of Field", getSettings().game.enableDepthOfField); + config::ImGuiCheckbox("Enable Mini-Map Shadows", getSettings().game.enableMapBackground); + ImGui::EndMenu(); } } diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index eb1d513ba9..84e56eda4f 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -55,6 +55,7 @@ UserSettings g_userSettings = { .internalResolutionScale {"game.internalResolutionScale", 0}, .shadowResolutionMultiplier {"game.shadowResolutionMultiplier", 1}, .enableDepthOfField {"game.enableDepthOfField", true}, + .enableMapBackground {"game.enableMapBackground", true}, // Audio .noLowHpSound {"game.noLowHpSound", false}, @@ -157,6 +158,7 @@ void registerSettings() { Register(g_userSettings.game.internalResolutionScale); Register(g_userSettings.game.shadowResolutionMultiplier); Register(g_userSettings.game.enableDepthOfField); + Register(g_userSettings.game.enableMapBackground); Register(g_userSettings.game.enableFastIronBoots); Register(g_userSettings.game.canTransformAnywhere); Register(g_userSettings.game.freeMagicArmor); From f856f871bb937c1aea63369e40e6df7b073a0f0a Mon Sep 17 00:00:00 2001 From: Pheenoh Date: Sun, 26 Apr 2026 13:55:32 -0600 Subject: [PATCH 050/390] Only show languages if PAL disc --- src/dusk/imgui/ImGuiPreLaunchWindow.cpp | 22 ++++++++++-------- src/dusk/imgui/ImGuiPreLaunchWindow.hpp | 1 + src/dusk/iso_validate.cpp | 31 +++++++++++++++++++++++++ src/dusk/iso_validate.hpp | 1 + 4 files changed, 45 insertions(+), 10 deletions(-) diff --git a/src/dusk/imgui/ImGuiPreLaunchWindow.cpp b/src/dusk/imgui/ImGuiPreLaunchWindow.cpp index 6347e9bc01..eef8c08e0d 100644 --- a/src/dusk/imgui/ImGuiPreLaunchWindow.cpp +++ b/src/dusk/imgui/ImGuiPreLaunchWindow.cpp @@ -75,6 +75,7 @@ void fileDialogCallback(void* userdata, const char* path, const char* error) { } self->m_selectedIsoPath = path; + self->m_isPal = iso::isPal(path); getSettings().backend.isoPath.setValue(self->m_selectedIsoPath); config::Save(); } @@ -92,6 +93,7 @@ bool ImGuiPreLaunchWindow::isSelectedPathValid() const { void ImGuiPreLaunchWindow::draw() { if (m_IsFirstDraw) { m_selectedIsoPath = getSettings().backend.isoPath; + m_isPal = !m_selectedIsoPath.empty() && iso::isPal(m_selectedIsoPath.c_str()); m_initialGraphicsBackend = getSettings().backend.graphicsBackend; m_IsFirstDraw = false; } @@ -199,18 +201,18 @@ void ImGuiPreLaunchWindow::drawOptions() { false); } - // TODO: Only show if PAL disc selected? - // Language selection - auto selectedLanguage = getSettings().game.language.getValue(); - if (ImGui::BeginCombo("Language", skLanguageNames[static_cast(selectedLanguage)])) { - for (u8 i = 0; i < skLanguageNames.size(); ++i) { - if (ImGui::Selectable(skLanguageNames[i])) { - getSettings().game.language.setValue(static_cast(i)); - config::Save(); + if (m_isPal) { + auto selectedLanguage = getSettings().game.language.getValue(); + if (ImGui::BeginCombo("Language", skLanguageNames[static_cast(selectedLanguage)])) { + for (u8 i = 0; i < skLanguageNames.size(); ++i) { + if (ImGui::Selectable(skLanguageNames[i])) { + getSettings().game.language.setValue(static_cast(i)); + config::Save(); + } } - } - ImGui::EndCombo(); + ImGui::EndCombo(); + } } AuroraBackend configuredBackend = BACKEND_AUTO; diff --git a/src/dusk/imgui/ImGuiPreLaunchWindow.hpp b/src/dusk/imgui/ImGuiPreLaunchWindow.hpp index 5d16a6ba0b..6cb078a228 100644 --- a/src/dusk/imgui/ImGuiPreLaunchWindow.hpp +++ b/src/dusk/imgui/ImGuiPreLaunchWindow.hpp @@ -18,5 +18,6 @@ public: std::string m_selectedIsoPath; std::string m_errorString; + bool m_isPal = false; }; } // namespace dusk diff --git a/src/dusk/iso_validate.cpp b/src/dusk/iso_validate.cpp index 0b4a19ae9c..e83b3fd34e 100644 --- a/src/dusk/iso_validate.cpp +++ b/src/dusk/iso_validate.cpp @@ -17,6 +17,11 @@ constexpr const char* TP_GAME_IDS[] = { "RZDK01", // Wii KOR }; +constexpr const char* PAL_GAME_IDS[] = { + "GZ2P01", // GCN PAL + "RZDP01", // Wii PAL +}; + constexpr const char* SUPPORTED_TP_GAME_IDS[] = { "GZ2E01", // GCN USA "GZ2P01", // GCN PAL @@ -124,4 +129,30 @@ ValidationError validate(const char* path) { return ValidationError::Success; } +bool isPal(const char* path) { + NodHandleWrapper disc; + + const auto sdlStream = SDL_IOFromFile(path, "rb"); + if (sdlStream == nullptr) { + return false; + } + + const NodDiscStream nod_stream{ + .user_data = sdlStream, + .read_at = StreamReadAt, + .stream_len = StreamLength, + .close = StreamClose, + }; + + if (nod_disc_open_stream(&nod_stream, nullptr, &disc.handle) != NOD_RESULT_OK || disc.handle == nullptr) { + return false; + } + + NodDiscHeader header{}; + if (nod_disc_header(disc.handle, &header) != NOD_RESULT_OK) { + return false; + } + + return matches(header.game_id, PAL_GAME_IDS); +} } // namespace dusk::iso \ No newline at end of file diff --git a/src/dusk/iso_validate.hpp b/src/dusk/iso_validate.hpp index da1ef1f2a6..d961f052cd 100644 --- a/src/dusk/iso_validate.hpp +++ b/src/dusk/iso_validate.hpp @@ -13,6 +13,7 @@ namespace dusk::iso { }; ValidationError validate(const char* path); + bool isPal(const char* path); } #endif // DUSK_ISO_VALIDATE_HPP From 90c0bdded0816de41f35e718af70619f58131b8c Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sun, 26 Apr 2026 14:02:28 -0600 Subject: [PATCH 051/390] Use GXDestroyCopyTex on map destroy Resolves #469 --- extern/aurora | 2 +- src/d/d_map.cpp | 6 ++++++ src/d/d_menu_dmap_map.cpp | 6 ++++++ src/d/d_menu_fmap_map.cpp | 6 ++++++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/extern/aurora b/extern/aurora index 8af9057689..a6a3d3a65a 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 8af9057689b9b85a55bbbd6218bc95304558fabd +Subproject commit a6a3d3a65ae0de6de8b60629cf47fd0f446c21cb diff --git a/src/d/d_map.cpp b/src/d/d_map.cpp index a5163091fd..d4e5a98888 100644 --- a/src/d/d_map.cpp +++ b/src/d/d_map.cpp @@ -13,6 +13,9 @@ #include "SSystem/SComponent/c_math.h" #include "d/actor/d_a_player.h" #include "d/d_com_inf_game.h" +#if TARGET_PC +#include +#endif #include #if DEBUG @@ -1215,6 +1218,9 @@ void dMap_c::changeTextureSize(int param_1, int param_2, int param_3) { void dMap_c::_remove() { if (mImage_p != NULL) { +#if TARGET_PC + GXDestroyCopyTex(mImage_p); +#endif JKR_DELETE_ARRAY(mImage_p); mImage_p = NULL; } diff --git a/src/d/d_menu_dmap_map.cpp b/src/d/d_menu_dmap_map.cpp index 8971b2630d..9100a7d63a 100644 --- a/src/d/d_menu_dmap_map.cpp +++ b/src/d/d_menu_dmap_map.cpp @@ -11,6 +11,9 @@ #include "d/d_menu_dmap_map.h" #include "f_op/f_op_msg_mng.h" #include "m_Do/m_Do_graphic.h" +#if TARGET_PC +#include +#endif struct dMdm_HIO_prm_res_dst_s { static void* m_res; @@ -291,6 +294,9 @@ void dMenu_DmapMap_c::_create(u16 param_0, u16 param_1, u16 param_2, u16 param_3 void dMenu_DmapMap_c::_delete() { for (int i = 0; i < 2; i++) { if (mMapImage_p[i] != NULL) { +#if TARGET_PC + GXDestroyCopyTex(mMapImage_p[i]); +#endif JKR_DELETE_ARRAY(mMapImage_p[i]); } diff --git a/src/d/d_menu_fmap_map.cpp b/src/d/d_menu_fmap_map.cpp index 3d1a9e2523..c500aff0be 100644 --- a/src/d/d_menu_fmap_map.cpp +++ b/src/d/d_menu_fmap_map.cpp @@ -8,6 +8,9 @@ #include "d/d_debug_viewer.h" #include "d/d_menu_fmap_map.h" #include "m_Do/m_Do_graphic.h" +#if TARGET_PC +#include +#endif #include static u8 twoValueLineInterpolation(u8 i_value1, u8 i_value2, f32 i_param) { @@ -494,6 +497,9 @@ void dMenu_FmapMap_c::_delete() { mResTIMG = NULL; } if (mMapImage_p != NULL) { +#if TARGET_PC + GXDestroyCopyTex(mMapImage_p); +#endif JKR_DELETE_ARRAY(mMapImage_p); mMapImage_p = NULL; } From 0f9d563a3e68f42e67f6a4bf60c27db4df9482fd Mon Sep 17 00:00:00 2001 From: Pheenoh Date: Sun, 26 Apr 2026 15:30:51 -0600 Subject: [PATCH 052/390] cLib_offsetPos param aliasing fix --- src/SSystem/SComponent/c_lib.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/SSystem/SComponent/c_lib.cpp b/src/SSystem/SComponent/c_lib.cpp index 6441d6ceb8..d73dfb8627 100644 --- a/src/SSystem/SComponent/c_lib.cpp +++ b/src/SSystem/SComponent/c_lib.cpp @@ -468,9 +468,20 @@ s16 cLib_targetAngleX(cXyz const* lhs, cXyz const* rhs) { void cLib_offsetPos(cXyz* pdest, cXyz const* psrc, s16 angle, cXyz const* vec) { f32 cos = cM_scos(angle); f32 sin = cM_ssin(angle); + // MWCC loads vec members into registers before writing to pdest; other compilers may not, + // which corrupts results when pdest and vec alias the same memory. +#if !__MWERKS__ + f32 vx = vec->x; + f32 vy = vec->y; + f32 vz = vec->z; + pdest->x = psrc->x + (vx * cos + vz * sin); + pdest->y = psrc->y + vy; + pdest->z = psrc->z + (vz * cos - vx * sin); +#else pdest->x = psrc->x + (vec->x * cos + vec->z * sin); pdest->y = psrc->y + vec->y; pdest->z = psrc->z + (vec->z * cos - vec->x * sin); +#endif } /** From a05d1a9ee61ba350ce26dbcc29f68b382ae171d4 Mon Sep 17 00:00:00 2001 From: Pheenoh Date: Sun, 26 Apr 2026 17:05:46 -0600 Subject: [PATCH 053/390] d_a_balloon score and interp fixes --- src/d/actor/d_a_balloon_2D.cpp | 17 ++++++++++++++--- src/d/actor/d_a_obj_balloon.cpp | 7 +++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/d/actor/d_a_balloon_2D.cpp b/src/d/actor/d_a_balloon_2D.cpp index 6b5b5a2bd2..8627505371 100644 --- a/src/d/actor/d_a_balloon_2D.cpp +++ b/src/d/actor/d_a_balloon_2D.cpp @@ -6,6 +6,7 @@ #include "d/dolzel_rel.h" // IWYU pragma: keep #include "d/actor/d_a_balloon_2D.h" +#include "dusk/frame_interpolation.h" #include "JSystem/J2DGraph/J2DGrafContext.h" #include "JSystem/J2DGraph/J2DScreen.h" #include "JSystem/J2DGraph/J2DTextBox.h" @@ -438,7 +439,12 @@ void daBalloon2D_c::setComboAlpha() { void daBalloon2D_c::drawAddScore() { for (s32 i = 19; i >= 0; i--) { if (field_0x5f8[i].field_0xe != 0) { - field_0x5f8[i].field_0xe--; +#ifdef TARGET_PC + if (dusk::frame_interp::get_ui_tick_pending()) +#endif + { + field_0x5f8[i].field_0xe--; + } s32 score3; s32 score2; s32 score = field_0x5f8[i].field_0xc; @@ -446,8 +452,13 @@ void daBalloon2D_c::drawAddScore() { u8 local_88 = 0xff; f32 dVar11 = 30.0f; f32 dVar9 = 30.0f; - field_0x5f8[i].field_0x0.x += cM_ssin(temp0) * 0.3f; - field_0x5f8[i].field_0x0.y -= 1.0f; +#ifdef TARGET_PC + if (dusk::frame_interp::get_ui_tick_pending()) +#endif + { + field_0x5f8[i].field_0x0.x += cM_ssin(temp0) * 0.3f; + field_0x5f8[i].field_0x0.y -= 1.0f; + } if (field_0x5f8[i].field_0xe < 10) { f32 fVar5 = field_0x5f8[i].field_0xe / 10.0f; local_88 = fVar5 * 255.0f; diff --git a/src/d/actor/d_a_obj_balloon.cpp b/src/d/actor/d_a_obj_balloon.cpp index 41430f97f0..4425483bef 100644 --- a/src/d/actor/d_a_obj_balloon.cpp +++ b/src/d/actor/d_a_obj_balloon.cpp @@ -205,6 +205,13 @@ int daObj_Balloon_c::_delete() { Z2GetAudioMgr()->seStop(Z2SE_OBJ_WATERMILL_ROUND, 0); if (mHIOInit) { hio_set = false; +#ifdef TARGET_PC + // !@bug d_a_obj_balloon.rel unload used to zero these file-statics; with static linking they dangle across scenes. + m_combo_type = 0xFFFFFFFF; + m_combo_count = 0; + m_combo_next_score = 0; + m_balloon_score = 0; +#endif } return 1; } From 206c02b527993d5dfa4e2e9c1471821dedc47805 Mon Sep 17 00:00:00 2001 From: TakaRikka Date: Sun, 26 Apr 2026 16:51:10 -0700 Subject: [PATCH 054/390] fix igt timer --- src/d/actor/d_a_alink_demo.inc | 4 +-- src/d/d_bright_check.cpp | 5 +-- src/d/d_s_name.cpp | 5 +-- src/dusk/imgui/ImGuiConsole.hpp | 5 --- src/dusk/imgui/ImGuiMenuGame.cpp | 13 +++++--- src/dusk/imgui/ImGuiMenuGame.hpp | 52 +++++++++++++++++++++----------- src/f_op/f_op_overlap_req.cpp | 20 ++++++++++++ src/f_op/f_op_scene_req.cpp | 16 ---------- 8 files changed, 70 insertions(+), 50 deletions(-) diff --git a/src/d/actor/d_a_alink_demo.inc b/src/d/actor/d_a_alink_demo.inc index b46af5cacb..5ac30a3cb9 100644 --- a/src/d/actor/d_a_alink_demo.inc +++ b/src/d/actor/d_a_alink_demo.inc @@ -4009,8 +4009,8 @@ int daAlink_c::procGanonFinishInit() { #if TARGET_PC if (dusk::getSettings().game.speedrunMode) { - if (dusk::g_imguiConsole.isSpeedrunStart()) { - dusk::g_imguiConsole.stopSpeedrun(); + if (dusk::m_speedrunInfo.m_isRunStarted) { + dusk::m_speedrunInfo.stopRun(); } } #endif diff --git a/src/d/d_bright_check.cpp b/src/d/d_bright_check.cpp index 88d0b7a2d8..3ee98be5c7 100644 --- a/src/d/d_bright_check.cpp +++ b/src/d/d_bright_check.cpp @@ -145,8 +145,9 @@ void dBrightCheck_c::modeMove() { if (dusk::getSettings().game.speedrunMode && !dusk::getSettings().game.hideTvSettingsScreen) { // start a new run if a run isn't already in progress - if (!dusk::g_imguiConsole.isSpeedrunStart()) { - dusk::g_imguiConsole.startSpeedrun(); + if (!dusk::m_speedrunInfo.m_isRunStarted) { + dusk::ImGuiMenuGame::resetForSpeedrunMode(); + dusk::m_speedrunInfo.startRun(); } } #endif diff --git a/src/d/d_s_name.cpp b/src/d/d_s_name.cpp index 9a20ca6caa..6baa07da30 100644 --- a/src/d/d_s_name.cpp +++ b/src/d/d_s_name.cpp @@ -417,8 +417,9 @@ void dScnName_c::changeGameScene() { #if TARGET_PC if (dusk::getSettings().game.speedrunMode && dusk::getSettings().game.hideTvSettingsScreen) { // start a new run on file load if a run isn't already in progress - if (!dusk::g_imguiConsole.isSpeedrunStart()) { - dusk::g_imguiConsole.startSpeedrun(); + if (!dusk::m_speedrunInfo.m_isRunStarted) { + dusk::ImGuiMenuGame::resetForSpeedrunMode(); + dusk::m_speedrunInfo.startRun(); } } #endif diff --git a/src/dusk/imgui/ImGuiConsole.hpp b/src/dusk/imgui/ImGuiConsole.hpp index 5e9f2aa523..a6c8b48fc7 100644 --- a/src/dusk/imgui/ImGuiConsole.hpp +++ b/src/dusk/imgui/ImGuiConsole.hpp @@ -29,11 +29,6 @@ public: static bool CheckMenuViewToggle(ImGuiKey key, bool& active); void AddToast(std::string_view message, float duration = 3.f); - bool isSpeedrunStart() const { return m_menuGame.isRunStarted(); } - void startSpeedrun() { m_menuGame.startRun(); } - void stopSpeedrun() { m_menuGame.stopRun(); } - void incSpeedrunTotalLoadTime(OSTime time) { m_menuGame.incTotalLoadTime(time); } - private: struct Toast { std::string message; diff --git a/src/dusk/imgui/ImGuiMenuGame.cpp b/src/dusk/imgui/ImGuiMenuGame.cpp index 83b80869b4..7f114aa015 100644 --- a/src/dusk/imgui/ImGuiMenuGame.cpp +++ b/src/dusk/imgui/ImGuiMenuGame.cpp @@ -1051,6 +1051,8 @@ namespace dusk { getSettings().game.enableTurboKeybind.setValue(false); } + SpeedrunInfo m_speedrunInfo; + void ImGuiMenuGame::drawSpeedrunTimerOverlay() { if (!getSettings().game.speedrunMode) { return; @@ -1058,10 +1060,7 @@ namespace dusk { // L+R+A+Start to reset timer if (mDoCPd_c::getHoldL(PAD_1) && mDoCPd_c::getHoldR(PAD_1) && mDoCPd_c::getHoldA(PAD_1) && mDoCPd_c::getTrigStart(PAD_1)) { - m_speedrunInfo.m_endTimestamp = 0; - m_speedrunInfo.m_startTimestamp = 0; - m_speedrunInfo.m_totalLoadTime = 0; - m_speedrunInfo.m_isRunStarted = false; + m_speedrunInfo.reset(); } // L+R+A+Z to manually stop timer @@ -1091,9 +1090,13 @@ namespace dusk { ImGui::SameLine(60.0f); ImGuiStringViewText(GetFormattedTime(elapsedTime)); + if (!m_speedrunInfo.m_isPauseIGT) { + m_speedrunInfo.m_igtTimer = elapsedTime - m_speedrunInfo.m_totalLoadTime; + } + ImGui::Text("IGT"); ImGui::SameLine(60.0f); - ImGuiStringViewText(GetFormattedTime(elapsedTime - m_speedrunInfo.m_totalLoadTime)); + ImGuiStringViewText(GetFormattedTime(m_speedrunInfo.m_igtTimer)); } ImGui::End(); } diff --git a/src/dusk/imgui/ImGuiMenuGame.hpp b/src/dusk/imgui/ImGuiMenuGame.hpp index 795cf5f446..4fbfec8f76 100644 --- a/src/dusk/imgui/ImGuiMenuGame.hpp +++ b/src/dusk/imgui/ImGuiMenuGame.hpp @@ -8,6 +8,39 @@ #include "imgui.h" namespace dusk { + struct SpeedrunInfo { + void startRun() { + m_isRunStarted = true; + m_startTimestamp = OSGetTime(); + } + + void stopRun() { + m_isRunStarted = false; + m_endTimestamp = OSGetTime() - m_startTimestamp; + } + + void reset() { + m_isRunStarted = false; + m_startTimestamp = 0; + m_endTimestamp = 0; + m_isPauseIGT = false; + m_loadStartTimestamp = 0; + m_totalLoadTime = 0; + m_igtTimer = 0; + } + + bool m_isRunStarted = false; + OSTime m_startTimestamp = 0; + OSTime m_endTimestamp = 0; + + bool m_isPauseIGT = false; + OSTime m_loadStartTimestamp = 0; + OSTime m_totalLoadTime = 0; + OSTime m_igtTimer = 0; + }; + + extern SpeedrunInfo m_speedrunInfo; + class ImGuiMenuGame { public: ImGuiMenuGame(); @@ -20,17 +53,6 @@ namespace dusk { static void ToggleFullscreen(); static void resetForSpeedrunMode(); - bool isRunStarted() const { return m_speedrunInfo.m_isRunStarted; } - void startRun() { - resetForSpeedrunMode(); - m_speedrunInfo.m_isRunStarted = true; - m_speedrunInfo.m_startTimestamp = OSGetTime(); - } - void stopRun() { - m_speedrunInfo.m_isRunStarted = false; - m_speedrunInfo.m_endTimestamp = OSGetTime() - m_speedrunInfo.m_startTimestamp; - } - void incTotalLoadTime(OSTime time) { m_speedrunInfo.m_totalLoadTime += time; } private: void drawAudioMenu(); @@ -55,13 +77,7 @@ namespace dusk { int m_inputOverlayCorner = 3; std::string m_controllerName; - struct { - bool m_showTimerWindow = false; - bool m_isRunStarted = false; - OSTime m_startTimestamp = 0; - OSTime m_endTimestamp = 0; - OSTime m_totalLoadTime = 0; - } m_speedrunInfo; + bool m_showTimerWindow = false; }; } diff --git a/src/f_op/f_op_overlap_req.cpp b/src/f_op/f_op_overlap_req.cpp index 28d0a743cc..4d410fb2c2 100644 --- a/src/f_op/f_op_overlap_req.cpp +++ b/src/f_op/f_op_overlap_req.cpp @@ -7,6 +7,8 @@ #include "f_op/f_op_overlap_req.h" #include "f_pc/f_pc_manager.h" +#include "dusk/imgui/ImGuiMenuGame.hpp" + void fopOvlpReq_SetPeektime(overlap_request_class*, u16); static int fopOvlpReq_phase_Done(overlap_request_class* i_overlapReq) { @@ -16,6 +18,16 @@ static int fopOvlpReq_phase_Done(overlap_request_class* i_overlapReq) { i_overlapReq->peektime = 0; i_overlapReq->field_0x8 = 0; i_overlapReq->field_0xc = 0; + + #if TARGET_PC + if (dusk::getSettings().game.speedrunMode) { + if (dusk::m_speedrunInfo.m_isRunStarted) { + dusk::m_speedrunInfo.m_isPauseIGT = false; + dusk::m_speedrunInfo.m_totalLoadTime += OSGetTime() - dusk::m_speedrunInfo.m_loadStartTimestamp; + dusk::m_speedrunInfo.m_loadStartTimestamp = OSGetTime(); + } + } + #endif return cPhs_NEXT_e; } @@ -81,6 +93,14 @@ static int fopOvlpReq_phase_Create(overlap_request_class* i_overlapReq) { fpcLy_SetCurrentLayer(i_overlapReq->layer); i_overlapReq->request_id = fpcM_Create(i_overlapReq->procname, NULL, NULL); + +#if TARGET_PC + if (dusk::m_speedrunInfo.m_isRunStarted) { + dusk::m_speedrunInfo.m_isPauseIGT = true; + dusk::m_speedrunInfo.m_loadStartTimestamp = OSGetTime(); + } +#endif + return cPhs_NEXT_e; } diff --git a/src/f_op/f_op_scene_req.cpp b/src/f_op/f_op_scene_req.cpp index e4ce889266..abcb6ce848 100644 --- a/src/f_op/f_op_scene_req.cpp +++ b/src/f_op/f_op_scene_req.cpp @@ -40,10 +40,6 @@ static cPhs_Step fopScnRq_phase_IsDoneOverlap(scene_request_class* i_sceneReq) { static BOOL l_fopScnRq_IsUsingOfOverlap; -#if TARGET_PC -static OSTime l_fopScnRq_StartTime = 0; -#endif - static cPhs_Step fopScnRq_phase_Done(scene_request_class* i_sceneReq) { if (i_sceneReq->create_request.parameters != 1) { @@ -53,14 +49,6 @@ static cPhs_Step fopScnRq_phase_Done(scene_request_class* i_sceneReq) { } l_fopScnRq_IsUsingOfOverlap = FALSE; - #if TARGET_PC - if (dusk::getSettings().game.speedrunMode) { - if (dusk::g_imguiConsole.isSpeedrunStart()) { - dusk::g_imguiConsole.incSpeedrunTotalLoadTime(OSGetTime() - l_fopScnRq_StartTime); - } - } - #endif - return cPhs_NEXT_e; } @@ -101,10 +89,6 @@ static scene_request_class* fopScnRq_FadeRequest(s16 i_procname, u16 i_peektime) req = fopOvlpM_Request(i_procname, i_peektime); if (req != NULL) { l_fopScnRq_IsUsingOfOverlap = TRUE; - - #if TARGET_PC - l_fopScnRq_StartTime = OSGetTime(); - #endif } } From 23a91a37be19b596e9bbd03e513309b84a62c67a Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sun, 26 Apr 2026 21:01:32 -0600 Subject: [PATCH 055/390] Kinda crappy initial controller support --- extern/aurora | 2 +- src/dusk/imgui/ImGuiConsole.cpp | 33 +++++++++- src/dusk/imgui/ImGuiConsole.hpp | 1 + src/dusk/imgui/ImGuiMenuGame.cpp | 100 ++++++++++++++++++++++++++----- src/dusk/imgui/ImGuiMenuGame.hpp | 3 + 5 files changed, 120 insertions(+), 19 deletions(-) diff --git a/extern/aurora b/extern/aurora index a6a3d3a65a..7784b6fc95 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit a6a3d3a65ae0de6de8b60629cf47fd0f446c21cb +Subproject commit 7784b6fc95568551499c87bd093b78d86e194eba diff --git a/src/dusk/imgui/ImGuiConsole.cpp b/src/dusk/imgui/ImGuiConsole.cpp index 6bca83482e..a94c7d1f5b 100644 --- a/src/dusk/imgui/ImGuiConsole.cpp +++ b/src/dusk/imgui/ImGuiConsole.cpp @@ -56,6 +56,21 @@ ImGuiWindow* FindDragScrollWindow(ImGuiWindow* window) { } return nullptr; } + +void FocusLastMenuBarItem() { + ImGuiContext& g = *ImGui::GetCurrentContext(); + ImGuiWindow* window = ImGui::GetCurrentWindow(); + const ImGuiID itemId = g.LastItemData.ID; + if (window == nullptr || itemId == 0) { + return; + } + + ImGui::FocusWindow(window); + ImGui::SetNavID(itemId, ImGuiNavLayer_Menu, g.CurrentFocusScopeId, + ImGui::WindowRectAbsToRel(window, g.LastItemData.NavRect)); + ImGui::SetNavCursorVisibleAfterMove(); + g.NavHighlightItemUnderNav = true; +} } // namespace namespace dusk { @@ -329,7 +344,17 @@ namespace dusk { } m_isHidden = !getSettings().backend.duskMenuOpen; - bool showMenu = !dusk::IsGameLaunched || !CheckMenuViewToggle(ImGuiKey_F1, m_isHidden); + if (dusk::IsGameLaunched) { + if (ImGui::IsKeyPressed(ImGuiKey_F1)) { + m_isHidden = !m_isHidden; + } + if (ImGui::IsKeyPressed(ImGuiKey_GamepadBack)) { + m_isHidden = !m_isHidden; + m_focusMenuBar = !m_isHidden; + } + } + + bool showMenu = !dusk::IsGameLaunched || !m_isHidden; if (dusk::IsGameLaunched) { const bool menuOpen = !m_isHidden; if (getSettings().backend.duskMenuOpen != menuOpen) { @@ -343,6 +368,10 @@ namespace dusk { ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f)); if (showMenu && ImGui::BeginMainMenuBar()) { m_menuGame.draw(); + if (m_focusMenuBar) { + FocusLastMenuBarItem(); + m_focusMenuBar = false; + } m_menuTools.draw(); const auto fpsLabel = @@ -367,7 +396,7 @@ namespace dusk { if (dusk::IsGameLaunched && !m_isLaunchInitialized) { m_toasts.emplace_back(ImGui::GetIO().MouseSource == ImGuiMouseSource_TouchScreen ? "Tap to toggle menu"s : - "Press F1 to toggle menu"s, + "Press F1 or Minus/Back to toggle menu"s, 2.5f); m_isLaunchInitialized = true; if (getSettings().game.liveSplitEnabled) { diff --git a/src/dusk/imgui/ImGuiConsole.hpp b/src/dusk/imgui/ImGuiConsole.hpp index a6c8b48fc7..fc7b4c51bc 100644 --- a/src/dusk/imgui/ImGuiConsole.hpp +++ b/src/dusk/imgui/ImGuiConsole.hpp @@ -41,6 +41,7 @@ private: float mouseHideTimer = 0.0f; bool m_isHidden = true; + bool m_focusMenuBar = false; bool m_isLaunchInitialized = false; bool m_touchTapActive = false; bool m_touchTapMoved = false; diff --git a/src/dusk/imgui/ImGuiMenuGame.cpp b/src/dusk/imgui/ImGuiMenuGame.cpp index d0da643b0c..251fabd227 100644 --- a/src/dusk/imgui/ImGuiMenuGame.cpp +++ b/src/dusk/imgui/ImGuiMenuGame.cpp @@ -23,6 +23,15 @@ namespace { constexpr int kInternalResolutionScaleMax = 12; + +bool is_controller_neutral(int port) { + if (port < 0) { + return true; + } + + return PADGetNativeButtonPressed(port) == -1 && + PADGetNativeAxisPulled(port).nativeAxis == -1; +} } // namespace namespace aurora::gx { @@ -196,7 +205,7 @@ namespace dusk { ImGui::SetTooltip("Restores patched glitches from Wii USA 1.0,\n" "the first released version."); } - + config::ImGuiCheckbox("Enable Rotating Link Doll", getSettings().game.enableLinkDollRotation); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Enables rotating Link in the collection menu with the C-Stick"); @@ -642,39 +651,90 @@ namespace dusk { void ImGuiMenuGame::windowControllerConfig() { if (!m_showControllerConfig) { + if (m_controllerConfig.m_isReading || + m_controllerConfig.m_suppressRemapActivationUntilRelease) + { + m_controllerConfig.m_isReading = false; + m_controllerConfig.m_pendingButtonMapping = nullptr; + m_controllerConfig.m_pendingAxisMapping = nullptr; + m_controllerConfig.m_pendingPort = -1; + m_controllerConfig.m_waitForInputRelease = false; + m_controllerConfig.m_suppressRemapActivationUntilRelease = false; + m_controllerConfig.m_suppressRemapActivationPort = -1; + PADBlockInput(false); + } return; } + bool suppressRemapActivationThisFrame = m_controllerConfig.m_suppressRemapActivationUntilRelease; + if (m_controllerConfig.m_suppressRemapActivationUntilRelease && + is_controller_neutral(m_controllerConfig.m_suppressRemapActivationPort)) + { + m_controllerConfig.m_suppressRemapActivationUntilRelease = false; + m_controllerConfig.m_suppressRemapActivationPort = -1; + PADBlockInput(false); + } + + if ((m_controllerConfig.m_pendingButtonMapping != nullptr || + m_controllerConfig.m_pendingAxisMapping != nullptr) && + m_controllerConfig.m_waitForInputRelease) + { + m_controllerConfig.m_waitForInputRelease = + !is_controller_neutral(m_controllerConfig.m_pendingPort); + } + // if pending for a button mapping, check to set new input - if (m_controllerConfig.m_pendingButtonMapping != nullptr) { + if (m_controllerConfig.m_pendingButtonMapping != nullptr && + !m_controllerConfig.m_waitForInputRelease) + { s32 nativeButton = PADGetNativeButtonPressed(m_controllerConfig.m_pendingPort); if (nativeButton != -1) { + const int suppressPort = m_controllerConfig.m_pendingPort; m_controllerConfig.m_pendingButtonMapping->nativeButton = nativeButton; m_controllerConfig.m_pendingButtonMapping = nullptr; m_controllerConfig.m_pendingPort = -1; - PADBlockInput(false); + m_controllerConfig.m_isReading = false; + m_controllerConfig.m_waitForInputRelease = false; + m_controllerConfig.m_suppressRemapActivationUntilRelease = true; + m_controllerConfig.m_suppressRemapActivationPort = suppressPort; + suppressRemapActivationThisFrame = true; + PADBlockInput(true); PADSerializeMappings(); } } // if pending for an axis mapping, check to set new input - if (m_controllerConfig.m_pendingAxisMapping != nullptr) { + if (m_controllerConfig.m_pendingAxisMapping != nullptr && + !m_controllerConfig.m_waitForInputRelease) + { auto nativeAxis = PADGetNativeAxisPulled(m_controllerConfig.m_pendingPort); if (nativeAxis.nativeAxis != -1) { + const int suppressPort = m_controllerConfig.m_pendingPort; m_controllerConfig.m_pendingAxisMapping->nativeAxis = nativeAxis; m_controllerConfig.m_pendingAxisMapping->nativeButton = -1; m_controllerConfig.m_pendingAxisMapping = nullptr; m_controllerConfig.m_pendingPort = -1; - PADBlockInput(false); + m_controllerConfig.m_isReading = false; + m_controllerConfig.m_waitForInputRelease = false; + m_controllerConfig.m_suppressRemapActivationUntilRelease = true; + m_controllerConfig.m_suppressRemapActivationPort = suppressPort; + suppressRemapActivationThisFrame = true; + PADBlockInput(true); PADSerializeMappings(); } else { auto nativeButton = PADGetNativeButtonPressed(m_controllerConfig.m_pendingPort); if (nativeButton != -1) { + const int suppressPort = m_controllerConfig.m_pendingPort; m_controllerConfig.m_pendingAxisMapping->nativeAxis = {-1, AXIS_SIGN_POSITIVE}; m_controllerConfig.m_pendingAxisMapping->nativeButton = nativeButton; m_controllerConfig.m_pendingAxisMapping = nullptr; m_controllerConfig.m_pendingPort = -1; - PADBlockInput(false); + m_controllerConfig.m_isReading = false; + m_controllerConfig.m_waitForInputRelease = false; + m_controllerConfig.m_suppressRemapActivationUntilRelease = true; + m_controllerConfig.m_suppressRemapActivationPort = suppressPort; + suppressRemapActivationThisFrame = true; + PADBlockInput(true); PADSerializeMappings(); } } @@ -710,6 +770,10 @@ namespace dusk { m_controllerConfig.m_pendingButtonMapping = nullptr; m_controllerConfig.m_pendingAxisMapping = nullptr; m_controllerConfig.m_pendingPort = -1; + m_controllerConfig.m_waitForInputRelease = false; + m_controllerConfig.m_isReading = false; + m_controllerConfig.m_suppressRemapActivationUntilRelease = false; + m_controllerConfig.m_suppressRemapActivationPort = -1; PADBlockInput(false); } @@ -786,7 +850,7 @@ namespace dusk { std::string dispName; if (m_controllerConfig.m_isReading && m_controllerConfig.m_pendingButtonMapping == &btnMappingList[i]) { - dispName = fmt::format("Press a Key...##{}", btnName); + dispName = fmt::format("{}##{}", m_controllerConfig.m_waitForInputRelease ? "Release..." : "Press a Key...", btnName); } else { const char* nativeName = GetNameForGamepadButton(gamepad, btnMappingList[i].nativeButton); if (nativeName == nullptr) { @@ -797,10 +861,11 @@ namespace dusk { bool pressed = ImGui::Button(dispName.c_str(), btnSize); - if (pressed) { + if (pressed && !m_controllerConfig.m_isReading && !suppressRemapActivationThisFrame) { m_controllerConfig.m_isReading = true; m_controllerConfig.m_pendingPort = m_controllerConfig.m_selectedPort; m_controllerConfig.m_pendingButtonMapping = &btnMappingList[i]; + m_controllerConfig.m_waitForInputRelease = true; PADBlockInput(true); } } @@ -830,17 +895,18 @@ namespace dusk { std::string dispName; if (m_controllerConfig.m_isReading && m_controllerConfig.m_pendingAxisMapping == &axisMappingList[trigger]) { - dispName = fmt::format("Press a Key...##{}", axisName); + dispName = fmt::format("{}##{}", m_controllerConfig.m_waitForInputRelease ? "Release..." : "Press a Key...", axisName); } else { dispName = fmt::format("{0}##-{1}", PADGetNativeAxisName(axisMappingList[trigger].nativeAxis), trigger); } bool pressed = ImGui::Button(dispName.c_str(), btnSize); - if (pressed) { + if (pressed && !m_controllerConfig.m_isReading && !suppressRemapActivationThisFrame) { m_controllerConfig.m_isReading = true; m_controllerConfig.m_pendingPort = m_controllerConfig.m_selectedPort; m_controllerConfig.m_pendingAxisMapping = &axisMappingList[trigger]; + m_controllerConfig.m_waitForInputRelease = true; PADBlockInput(true); } } @@ -897,7 +963,7 @@ namespace dusk { std::string dispName; if (m_controllerConfig.m_isReading && m_controllerConfig.m_pendingAxisMapping == &axisMappingList[axis]) { - dispName = fmt::format("Press a Key...##{}", label); + dispName = fmt::format("{}##{}", m_controllerConfig.m_waitForInputRelease ? "Release..." : "Press a Key...", label); } else { if (axisMappingList[axis].nativeAxis.nativeAxis != -1) { const char* signStr; @@ -916,10 +982,11 @@ namespace dusk { } bool pressed = ImGui::Button(dispName.c_str(), btnSize); - if (pressed) { + if (pressed && !m_controllerConfig.m_isReading && !suppressRemapActivationThisFrame) { m_controllerConfig.m_isReading = true; m_controllerConfig.m_pendingPort = m_controllerConfig.m_selectedPort; m_controllerConfig.m_pendingAxisMapping = &axisMappingList[axis]; + m_controllerConfig.m_waitForInputRelease = true; PADBlockInput(true); } } @@ -960,7 +1027,7 @@ namespace dusk { std::string dispName; if (m_controllerConfig.m_isReading && m_controllerConfig.m_pendingAxisMapping == &axisMappingList[axis]) { - dispName = fmt::format("Press a Key...##sub{}", label); + dispName = fmt::format("{}##sub{}", m_controllerConfig.m_waitForInputRelease ? "Release..." : "Press a Key...", label); } else { if (axisMappingList[axis].nativeAxis.nativeAxis != -1) { const char* signStr; @@ -979,10 +1046,11 @@ namespace dusk { } bool pressed = ImGui::Button(fmt::format("{0}##sub{1}", dispName, label).c_str(), btnSize); - if (pressed) { + if (pressed && !m_controllerConfig.m_isReading && !suppressRemapActivationThisFrame) { m_controllerConfig.m_isReading = true; m_controllerConfig.m_pendingPort = m_controllerConfig.m_selectedPort; m_controllerConfig.m_pendingAxisMapping = &axisMappingList[axis]; + m_controllerConfig.m_waitForInputRelease = true; PADBlockInput(true); } } @@ -1013,7 +1081,7 @@ namespace dusk { PADSerializeMappings(); } } - + if (PADSupportsRumbleIntensity(m_controllerConfig.m_selectedPort)) { ImGuiBeginGroupPanel("Rumble Intensity", ImVec2(150 * scale, -1)); u16 low; @@ -1032,7 +1100,7 @@ namespace dusk { if (ImGui::Button(fmt::format("{0}...##rumbleTest", m_controllerConfig.m_isRumbling ? "Stop": "Test").c_str(), {-1, 0})) { PADControlMotor(m_controllerConfig.m_selectedPort, !m_controllerConfig.m_isRumbling ? PAD_MOTOR_RUMBLE : PAD_MOTOR_STOP_HARD); m_controllerConfig.m_isRumbling ^= 1; - } + } ImGuiEndGroupPanel(); } ImGuiEndGroupPanel(); diff --git a/src/dusk/imgui/ImGuiMenuGame.hpp b/src/dusk/imgui/ImGuiMenuGame.hpp index e54541a010..c902c92359 100644 --- a/src/dusk/imgui/ImGuiMenuGame.hpp +++ b/src/dusk/imgui/ImGuiMenuGame.hpp @@ -68,6 +68,9 @@ namespace dusk { PADButtonMapping* m_pendingButtonMapping = nullptr; PADAxisMapping* m_pendingAxisMapping = nullptr; int m_pendingPort = -1; + bool m_waitForInputRelease = false; + bool m_suppressRemapActivationUntilRelease = false; + int m_suppressRemapActivationPort = -1; bool m_isRumbling = false; } m_controllerConfig; From 3e1e8f1244e3f1eeaedd4a0b9d2bf485742f21e1 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sun, 26 Apr 2026 21:53:39 -0600 Subject: [PATCH 056/390] Enable RmlUi --- CMakeLists.txt | 1 + extern/aurora | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 46f0b1a411..3e9c30fdad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -100,6 +100,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL Linux) endif () set(AURORA_ENABLE_DVD ON CACHE BOOL "Enable DVD API support" FORCE) set(AURORA_ENABLE_CARD ON CACHE BOOL "Enable CARD API support" FORCE) +set(AURORA_ENABLE_RMLUI ON CACHE BOOL "Enable RmlUi UI support" FORCE) add_subdirectory(extern/aurora EXCLUDE_FROM_ALL) add_subdirectory(libs/freeverb) diff --git a/extern/aurora b/extern/aurora index 7784b6fc95..b8407c6283 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 7784b6fc95568551499c87bd093b78d86e194eba +Subproject commit b8407c6283d757af7c6d55da96fe2ccfe1380510 From 5f33489465bc3d2da0de6daa7b7eabe6878d674f Mon Sep 17 00:00:00 2001 From: Irastris Date: Mon, 27 Apr 2026 01:04:45 -0400 Subject: [PATCH 057/390] Register interp callback for d_a_obj_lv8Lift --- include/d/actor/d_a_obj_lv8Lift.h | 3 +++ src/d/actor/d_a_obj_lv8Lift.cpp | 41 +++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/include/d/actor/d_a_obj_lv8Lift.h b/include/d/actor/d_a_obj_lv8Lift.h index c5a8ae9f27..c327f4cf3c 100644 --- a/include/d/actor/d_a_obj_lv8Lift.h +++ b/include/d/actor/d_a_obj_lv8Lift.h @@ -58,6 +58,9 @@ public: void setNextPoint(); int Draw(); int Delete(); +#if TARGET_PC + friend void daL8Lift_interp_callback(bool isSimFrame, void* pUserWork); +#endif u8 getPthID() { return fopAcM_GetParamBit(this, 0, 8); } u8 getMoveSpeed() { return fopAcM_GetParamBit(this, 8, 4); } diff --git a/src/d/actor/d_a_obj_lv8Lift.cpp b/src/d/actor/d_a_obj_lv8Lift.cpp index 4f475a626c..8fa9422325 100644 --- a/src/d/actor/d_a_obj_lv8Lift.cpp +++ b/src/d/actor/d_a_obj_lv8Lift.cpp @@ -10,6 +10,10 @@ #include "d/d_path.h" #include "d/d_bg_w.h" +#if TARGET_PC +#include "dusk/frame_interpolation.h" +#endif + daL8Lift_HIO_c::daL8Lift_HIO_c() { mStopDisappearTime = 30; mStartMoveTime = 60; @@ -380,7 +384,44 @@ void daL8Lift_c::setNextPoint() { mCurrentPoint = next_point; } +#if TARGET_PC +void daL8Lift_interp_callback(bool isSimFrame, void* pUserWork) { + daL8Lift_c* lift = static_cast(pUserWork); + if (lift == NULL || lift->mpModel == NULL) { + return; + } + + g_env_light.settingTevStruct(0x10, &lift->current.pos, &lift->tevStr); + g_env_light.setLightTevColorType_MAJI(lift->mpModel, &lift->tevStr); + + J3DModelData* modelData = lift->mpModel->getModelData(); + J3DMaterial* materialp = modelData->getMaterialNodePointer(0); + + if (materialp->getTexGenBlock()->getTexMtx(1) != NULL) { + J3DTexMtxInfo* mtx_info = &materialp->getTexGenBlock()->getTexMtx(1)->getTexMtxInfo(); + if (mtx_info != NULL) { + Mtx m; + C_MTXLightOrtho(m, 100.0f, -100.0f, -100.0f, 100.0f, 1.0f, 1.0f, 0.0f, 0.0f); + mDoMtx_stack_c::XrotS(0x4000); + mDoMtx_stack_c::transM(-lift->current.pos.x, -lift->current.pos.y, -lift->current.pos.z); + cMtx_concat(m, mDoMtx_stack_c::get(), mtx_info->mEffectMtx); + } + } + + lift->mBtk.entry(modelData); + + J3DGXColor* color = materialp->getTevKColor(1); + color->r = l_HIO.mColorR; + color->g = l_HIO.mColorG; + color->b = l_HIO.mColorB; +} +#endif + int daL8Lift_c::Draw() { +#if TARGET_PC + dusk::frame_interp::add_interpolation_callback(&daL8Lift_interp_callback, this); +#endif + g_env_light.settingTevStruct(16, ¤t.pos, &tevStr); g_env_light.setLightTevColorType_MAJI(mpModel, &tevStr); J3DModelData* modelData = mpModel->getModelData(); From 25e9064d09ab5f5343184c80b0125f07dfcd00a3 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Mon, 27 Apr 2026 00:18:31 -0600 Subject: [PATCH 058/390] Revamped prelaunch experiment w/ RmlUi --- README.md | 2 +- extern/aurora | 2 +- files.cmake | 20 + res/logo-mascot.png | Bin 0 -> 467557 bytes res/logo-mascot.webp | Bin 192532 -> 0 bytes src/dusk/imgui/ImGuiConsole.cpp | 3 +- src/dusk/iso_validate.cpp | 4 + src/dusk/ui/button.cpp | 160 ++++++ src/dusk/ui/button.hpp | 47 ++ src/dusk/ui/disc_state.cpp | 133 +++++ src/dusk/ui/disc_state.hpp | 41 ++ src/dusk/ui/element.cpp | 81 +++ src/dusk/ui/element.hpp | 18 + src/dusk/ui/focus_border.cpp | 36 ++ src/dusk/ui/focus_border.hpp | 10 + src/dusk/ui/game_option.cpp | 187 +++++++ src/dusk/ui/game_option.hpp | 43 ++ src/dusk/ui/label.cpp | 45 ++ src/dusk/ui/label.hpp | 19 + src/dusk/ui/prelaunch_layout.cpp | 113 ++++ src/dusk/ui/prelaunch_layout.hpp | 22 + src/dusk/ui/prelaunch_screen.cpp | 924 +++++++++++++++++++++++++++++++ src/dusk/ui/prelaunch_screen.hpp | 13 + src/dusk/ui/theme.cpp | 19 + src/dusk/ui/theme.hpp | 35 ++ src/dusk/ui/ui.cpp | 244 ++++++++ src/dusk/ui/ui.hpp | 29 + src/m_Do/m_Do_main.cpp | 13 + 28 files changed, 2260 insertions(+), 3 deletions(-) create mode 100644 res/logo-mascot.png delete mode 100644 res/logo-mascot.webp create mode 100644 src/dusk/ui/button.cpp create mode 100644 src/dusk/ui/button.hpp create mode 100644 src/dusk/ui/disc_state.cpp create mode 100644 src/dusk/ui/disc_state.hpp create mode 100644 src/dusk/ui/element.cpp create mode 100644 src/dusk/ui/element.hpp create mode 100644 src/dusk/ui/focus_border.cpp create mode 100644 src/dusk/ui/focus_border.hpp create mode 100644 src/dusk/ui/game_option.cpp create mode 100644 src/dusk/ui/game_option.hpp create mode 100644 src/dusk/ui/label.cpp create mode 100644 src/dusk/ui/label.hpp create mode 100644 src/dusk/ui/prelaunch_layout.cpp create mode 100644 src/dusk/ui/prelaunch_layout.hpp create mode 100644 src/dusk/ui/prelaunch_screen.cpp create mode 100644 src/dusk/ui/prelaunch_screen.hpp create mode 100644 src/dusk/ui/theme.cpp create mode 100644 src/dusk/ui/theme.hpp create mode 100644 src/dusk/ui/ui.cpp create mode 100644 src/dusk/ui/ui.hpp diff --git a/README.md b/README.md index b6d6cec863..631b2104c9 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![DuskLogo](res/logo-mascot.webp) +![DuskLogo](res/logo-mascot.png) - ### **[Official Website](https://twilitrealm.dev)** - ### **[Discord](https://discord.gg/QACynxeyna)** diff --git a/extern/aurora b/extern/aurora index b8407c6283..fa03533986 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit b8407c6283d757af7c6d55da96fe2ccfe1380510 +Subproject commit fa0353398661b5794322fb84ac67bb1bc7a5c468 diff --git a/files.cmake b/files.cmake index f91756a9d5..7799564f90 100644 --- a/files.cmake +++ b/files.cmake @@ -1462,6 +1462,26 @@ set(DUSK_FILES src/dusk/imgui/ImGuiStateShare.cpp src/dusk/imgui/ImGuiAchievements.hpp src/dusk/imgui/ImGuiAchievements.cpp + src/dusk/ui/button.hpp + src/dusk/ui/button.cpp + src/dusk/ui/disc_state.hpp + src/dusk/ui/disc_state.cpp + src/dusk/ui/element.hpp + src/dusk/ui/element.cpp + src/dusk/ui/focus_border.hpp + src/dusk/ui/focus_border.cpp + src/dusk/ui/game_option.hpp + src/dusk/ui/game_option.cpp + src/dusk/ui/label.hpp + src/dusk/ui/label.cpp + src/dusk/ui/prelaunch_layout.hpp + src/dusk/ui/prelaunch_layout.cpp + src/dusk/ui/prelaunch_screen.hpp + src/dusk/ui/prelaunch_screen.cpp + src/dusk/ui/theme.hpp + src/dusk/ui/theme.cpp + src/dusk/ui/ui.hpp + src/dusk/ui/ui.cpp src/dusk/achievements.cpp src/dusk/iso_validate.cpp src/dusk/livesplit.cpp diff --git a/res/logo-mascot.png b/res/logo-mascot.png new file mode 100644 index 0000000000000000000000000000000000000000..9f9a5d1ace69028fbf4d835b705a1c24e761ced3 GIT binary patch literal 467557 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ʕ_FjcLR6`mWd9L&#N_C**N0g?;6Z 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 z za5YV9&^A27TZLUR+i+TFVhfVa{CY-*iw$MLiD($s^J9;n1P z3u-AHV2MG*Wx7X7#Fii>))xMpaIKyD4lW6hOYmb+$`2v2C=X_akesTqg%B5cp7Y$r z=h+$Up|w)0%gbtgZOtu=_>&Z>;x+D>wJSSrPxLz^K61Z8!XW3K?BaVWf!WLc6-7}L%<`OBF{3a!d6|2cch|Rx)+9P3OM4vI zIKcCIT$1f`~87tdW?N@(@nSn{tuRlfL*r+VKk4KkZ#&WCrF!bG{dtWeX*fZDZDF&8_k z>Z1TsPjJhAd;T*7bq}=-C5XjAd1?Ajgzj6yB`+F8Z_uRqSh)xiS(8E+smS1BZCXRR zYB+v6;jXnb`P)ClCyuP7tIUI%2LYU2@)wQow^Q2GzT3IBx=w}f)kI7?Ma5UfieU`G zG{zoQM=ncVdskQ z)r)X^RpmEwUe3#XTzL^tco3M`#etjDuxQRZ48^r^{I>bA%?hgx*k}VhD{!+gGX1sB zm_Pp7mGp}*-q7Pq&k9>R1~V&RCNTAUHU?q>;MQEsiFu~)%S6FIyNG7{m)Bp@ay#?T z;&B+vP{V*$EoaBFUbCH=^loXdT@1x(_ESq6Ol7EhyD39A>(rEi;`#&#yo5#B5n9SY zbJU-Q2vp-U-oKEKvEN#=72NEldhqxE-rxMG^^Ldqgh5+ywt^IftorA*@&SuGj45PW;)$NDaFR>DK^$lyW}GPc;G^TYH&FbVQ1$>cK5Cv z)HV~P(n}&XsO|^3PaGD|4Br*|r=O}g;3C0@0a5gpo@MEd&x0Og#~W19?XA0&_;*W| zFEBj)Nyu`HJ&q^^WeKK)BTI1SI&yX$P7Yx`MGZB_Ry9BOeM|hW|HcMC{9vDK0k~-d zF5NPG^|={#Qetz1Ed^VO2m5d?)lra46|Epze-8(0dQi`T(HgUqU^Q4DXVb;nlyDm_ z4+rou1|Vy&v$mx4Ev*&rx^GB7QLGJh1zI>@)6+>rBJ;pz2#-Kz$r-FuZ3TQv3&>jE zPZ7X3MVi3Iimq1OM3}SG3_yQb2*uQr@0H{uOOd7IX;Oijc_GePb7Csjek<^Wi!=7h z_9R%qb)d^cSpnziupR~&4p!M%zr(eKSii-TVe4_e}^HLcXcL&O1{5)B`h%g8wR z+XI>4!AxD>zXmg9ZVN-~#j7uJ<@!~Wf?k?&?yfVet*nqHi31pwatsJd$WpHS{_xwy z%rq5{?U{%NRcka&`3~RO*(L@;vm_x)9m1z-MAU<-{(iW6xNq*fm8BJowJ5Dro)=Ph z3r%AR^4w*4FHGV1qc~txX^l=&dRd>l&ppKZzxSi8t{iRc-1>)_7fE7aEtK#(2wE{< z8TQ5Bq2_-6yI60r>0P^%ROh=h#&oNqb3AirR7|F&F2zo8iI38{zOh9@6YL5z712|| z%w=1S$Mptu4+bkd^i5N)*gC0&0$u zrj>Rp7|_d-?Buc4W9iay=Z2m?1?6=x`F_sO_Pts2u)nzo)Yb=a34A<>eplxT#aI~K zaB}$Cir#&0TU}=HoU+Iuq)Vr2)3IJj|Fm5j&xvi%Itb*9VXYWGi2==4i_XH>pt4Vy z001BWNkl>R`&Jz;q9l4Ud%?mn)!p4`=6eEMa3 zi^a);Vji(*k>=p}^i5D+4_EX>6K->Yog1!6+COPUdL8$0H_{0wPQJytSt?asEEc2$ zTMDK$*wT7X(*Xr|FiQxo=o*#i%AHgxDDnv}UcG>^C0eC&WaBQD2J8L><~fys2VrV! z(9!rB+dG#QHd2=LZx+S)1@=!?U6b)apk^DPPN~BU&y}9exU_c-g(ex?z~rkaJz}u& zDAs7CNTKv@)BQeG8e$R9dt}RxqVyOfaX?$1!>oWo4~{G&XE)&7I&xwFD=CA%=6!ef z_^%&X;}?E#nbYfn)4b>Y0Xo(7vFJJ*fKsW!N^7J2 z79?^Lx206s%R`Uu12v=K63<95*z;M_y&HZhl)0_8VrD6)mSS9zk4ka_c`qd|p~!{2 z5NEA9wV1J~vdm8k%hz8TvomX5(wk9dx^F8(oEv&;Y*nQc8yhDW4p$uLC#C{5>+cS< z44buObv%HVVGCB7!Gc;T2Zp*pslIa~55NEn*RJRh(CER+Bijx7t0H)!p7gck@x1!7?@FzGfWM^Re|G%W-qx>l$JKwH9W<{CpQrki6siSD>a zDUt2n*bD!0wK=J5>;?jkS{R>5b%(hdQ2&^r^dY=kZ2vDA)cHQnp`(t! z3Y3Or4Luk9zl*xQ8~xihX1hRu=7L5A2>j%SA3V1*?5(J!w8J`~?kFO8>FFx1ncC!)O*c2CbO!M-eJY_Djc)_d*62_mh;Pbn^alr8| zAfh=}wpnksS#7qutj`KN{?*@=-`*W&Pwh;V*&Yj9BX697n(vFapF(NMa}u4VeB;f> zXQc7H?e`nIIAMBzL92N@%)CVBEE*qy&ci$r%gW6Xlrw`s{c{Td9t<}2tSsS=H2Wa{&J$rI}?WZ33$cI+e&#i!fxdxk`c05m}`!$HR zeh>0M*q>6%k6~X}WRE4T1u~3Sw~n-V)pGGWmQP&}jt?+1^w)mF*#SR zKJMJzyPL~c%L|}_nsbH1T7*8`DYK^cI^8dQ~N))pYi6!)DUx@0cya-XOt0zv&&xu;vH+|5JGOIui% zsl1Gm3lZ1Pl`5PfRB>gs4vBMICil`?XcoEOrj~qa$tQ;CsAM`aOlL6bXXI+$1-&f6 zj7y~S1f}3R*GnFIsWZ0b72sk-hs|;dxUY>40fxg>jvhJbEURtl!OD4A&RJ>3KxgSg zJ(NC!y4#$UrN34=P*W+3*7f(w5>w&8OdYH@@tgmSJGUrvzWtqVbN%`?1Q_&s+X`6x+KySnCoRrAg|n%e_^k zcVzcgKdRzu?sk!errh`#_WOv4BuT<_Hm#mk8iO$9t&fEOU1{6=t0!=b7~iJ7ITt-XhF1(>y$9Lxm^L9U6vQs zwz)eSPjcgcO;S)^Ds9?Iw5@$M$+K+@G}JYSQeLnLiw}bovQ#sjg}{(+>as{_gYLdq zWVKm+&y5}b6AAG2HPnM_v z%QoH8+d$33T5Zy??^P*#Gr^+V+#a$AHcL}&j`uYczo2}_ajfDJEjr9y7kEzasR<>= z0o}1;7}SfZu5u7Xf%V5UcAWHLhlk0~Xw4L9)XP1iIyxcf1(ObK)G88)& zb>rdC8~&S7>@DG@49vh3=wnPj!ZavR*HbU!^BO7-y z9IRCqT}mnc-M^}LFBSheoo%zbch!S4okjQ3^n!?qqc(H_nq9=XsKo4TlNOe#fZSMi zW+QYuK?-O6qLXd1{za6UfC$PVjV=!4aEPEQt3#)B_}N!LOo>b;4zzP<8)OM`d>P(y z1kSCXHZo2fN%)1ow9J3;@m0R(&UBw^dR_`!W8n)==gf9X%%pU&QcD+WQ-U?4GgU-s zg-#VJRW77J=o$}h8j;G1(I|~os~2Q^E{SfKzMj0ci(vDy3LnTA?gUr4)!2 zDT)G6grvN|Ro;}wB@z;GRwqgmlC0^Z$I*?`y!~xI%rFKwg?a#0?(ysg7ZkOa5yLC7 zMN~K^Sg!>(8m~h80a04mD}+G`Cdo!OcO*FY9;Bq$8=IrONiMlHdtUQ&S>dahGOm9- z<;QmnT)P?FE3Ame@SH#2mX1fDpg%~+(%3BJFHGrD&<>-p?Ni)D$p853#pTDJ!(EN;WLW3iMR`Ud8K=$IBf+n58^h57h^O(herJo-ADZYlRorC_`cWqcfc7|=r9C3*~Nt)asp6!EN6XvZ({dD5CLI1UY zjrNsAGDw@;(q^R@gPU1jOY581Nb)(MF`J)Tv(;V!2 z-eskJJACg=RbER9Z4TY8;~fIFO06viBGT%%THQpYtZ&>w$RZ4Q;K^C%)v+~At#bz` zK>7G_%2{Cs&=LiEqZ{13bxEvPvb3kpoO*y>)~~HJl|U3bv9jP32WAw-h?}>bTG&8I zl3vZr=_UuSDlQ_z&Zc3${RL;&(r7=$Q(KoEVMvK7mZK-gd<`ZAYkl_Fkg+x|` z4rufVnq~z|rw+&q;AWb@FhfqQz`bk8UCZ<~GCuOQ0sqw_YrOyN9=)WlaA{y`V)?yq zPTAfy-fGiXGl~ZmLo+Dtz)Tk-mFj!&a~Gd{C$^ppnak@~m{eeCz-uwMXNBk4`kV?_ z6~~NFieYd5IpN+_M)hbDZ$;|d&aDfZP>4&I!!QgwpuT z<}+b7vCPJX>7HS->$d60ft}9n+*xTFLv5WpHBeYW_dUO5`TR4pD*R5PJPSPCL6;fu zLEr)Qs{#P5EU$6&$SG{)rfsSht-eRDudeaXefP7mzEN3Fs>)i{y#s{!nT{t|vCcxXEGhhE zjKM|=A~i+huZL+qW17z@-nF{41o1P7{e2w&3K`WUSZ*qpK&mJTk~9?oHJXmddObqC z*os+*V8mjq#Yk+msZlCHtAs2Ya^Jo0;lv&HM9if6S5N%mg<@qgfPir@ZJ~CHi7htc zsd!2q!^Q&)qM*!$?WvF@$i&KQmP_m)yhu5aE7x~-Cpo#;8CV6n@2%9Mvx1@<>K-~M zst2&&ov4V8hu`6ylgP?CQ49tP^5ebvOP4}-7*KO=p9qux_uETf$(EI!?S2JD7Sc7a z=^SueftdjmFQ_wE26`iUN^FtYw2q9$;-CZs_0UG=1`ssdH`F6oMZ`dBxTbA(4<(GB zARPr8%zf7hsWzl5uzoUSwqwr!z=PTOG$FRyyxka^@$b02CZHz3+R8FXZwVP0C_IA_ z>9&sUqOj(9y5s!#&0?i7(8wB&4#Jq$xR_*NU!Z{)WDmb%(AqyQ&7h~<)Rnwut@;)vC!&;_~YB-2A-{!@&*%avsKdv-)nW%>M5`Djs|4dh(U4SM~VvC1GdRz-$U8 zf(*J^G@b(mLJp$D@w(=_y*W!Tw+=ezBI*es7u0e{SC6&zZrQQF`J6T>H|#GO`+T)4 zIIIm^3&#MJKraRT+D-RurS0L17G=7uHJfheX)jF%fB%>M)=zC5zwZdTuaIrH@h@Q4 zCk)!JLhgqPgG?U-*l}B1>N%ujUKVIBwnv_7VujsJ%cbuae&caLDP(;)dE$33*pM)2 zk)>uVGq>tI3%2+T-c;pvf!=vVD~BRlr{_Rgfe-+tG-uB~gfWFT+N;4$YoRPHMOjjo z1~E30b82@@?LQOkK`;eYO15^cvOC&T3eC|YcQP2PIjcZ-19u+}rZ~W&1}DT8+_?G7 zK_ntdsT~oyPB#HAQhRQ@JJIPldWv!k-Gt4;WCq3}{T_BW zbfNSLi&ROOsDL;-nIW^hvT78iAknB^3Tp$@>18;(Omb?-hu=2jKl`awe)8=DHkJZF z1f!XAN58REQf?QRsln#9jz4Lm2GEWn>r|m)VACgi3gBjyh1`FS69HLa-jXtakQKNY z#lwu;(JLMto)z5DEmaK9>RKZX5N>S2O4E2Zbn!7b>w1QI%N)2^gPIZj8z@T1b74BM zOvip38MloM(}^X|ot5TvW+{y@&S87(Vr*{jSZ?mY%);|q!e_rTV^X$~V1Y{*blh+E z01pADfro*QG@IC@YIgRrBh~#T@5~StaRis9 z)~S@cPjD@FzpZyUw?3|>+pmJvCc@3l7kT>GZ!n!sK`Z)$0dIToA?`kVjx0+nH*^Oo zJIO}y7N@qvT3flDmt{d=a!gscMHlaKA1o!IPE_Q^jU~^g?2Shiq4%D9FX{IKV2^BgIC?6v;#0oYQjYo8@G)kqct)ArkJ@4_^+kJ`6 zo|~L2s8lg`gZ+tJLU!t=auf>^o~Iy=)^~DP?kQ`Po<(OLsKi{mRqRcR!A!)1nz{!n zowsp=8q5elSsWm|YYuLeTk8&sb6N_pYoqH%c~6X+}k&|H?!B)ZFcWM;(i4-t_!ZdTq`)ji!k z-R%kBzISh~k+GaO=bPViPTS{wE6R?TnV*C1vd`2zbdSEOZ5n=$Q{9_dRU7P)j$DUl zUCiUN-KPd+bJUV-w~WU{)7WtYJ=4$q52YpX0WMyR4+>=c=9$SphVlB6_FdapaEvns zm$Z*D*K+Nkk19>#+4H`aw_$T(UVP#F+S>BUvRV9$0fFKnRL9gYvzyGlC_^K#pSDNY z*iPe^Y2|TqH~g1)J>i+nPg|{i6kT;zo!ZvSHVJeVxY-0aCtTAj>xTc} zH{4ebRDNSnsp@3l7z`?Ecid*5waq0VI`4TAmzZ9SGvP@WY;v7W-F+fY1RFEzw+0A z>iTn6pU(0XpD?KZZ8!`GgRE`W1KOa%R2OK1#wn4bz>_kfr%ziSd((@mFFbtHa`P?6 z&Oo@dt`BdV>aX8;X!n=|HQNBrHpb>za`D4A4_nHQ!r$%ffSUDxt+N?t%NZu8`b04% z$CwV?&P)I`g&6YAykd=P38oU3@S^*W=`P%@LTymWz? z-aO8ZC5$-F!V=d^a^k3}l74@mqI`rPIngXy=dV{)5yi}tf|#*Q+uHUlPJ;qtpa>S6h$pEID(IHTOb6*?$lMH^4t=Cy9Srse@RTKL&_^-@ z#(0?-z)et|J);!#G})}-%QJ?xdBf8Gd%{2Y_JHG|2X_t!!tcCN@R!%R%&uC55KbTq z*9$G7RAg;xL_0()l$J*Xb$A>EADTb{Fcev9g6|1mUqUR;F~c%ux306AhiiEl%*Vs5 z8JkwHl|yM&vwLmjvy$7w)$ZqGfYZkiZDvtN;^2^pdMXt$kj@eAOw=3)%3z_y{=GLKi!yXl|b*!0Dma0^24>GzG+}%@XZE6rdDH-r(Jn4Rg z@jLzb@I8&3I8n6DIJbV8<)!s7r+jBBLK`R*^FY=8?Ae17CV|AG1DNOP7^~EoxyRat zKPG~gYRuM55(J@C4RD_H4|wC|cR4uT0@b6_>GJ%u&+^F^USMXXN1kPV%!RnSAa(mV z=d+$$=jBgjE2^rXEDJ`(h^n-~4Lt(5IslOpdm3vicJ}w{-x|&G!UD$li58iqT8}}@ z=Epy`Z-cqnc^_9(p`3_Rwu+5ZzsHEr;pH1hY(AxMN`W#cr7L-z&F+ViW$AvCAM{&N*_(( zxc}_{oEEUB{p$2jZ!Eq1b6+_6Qt2|4+X}KSxZsVL_H;A=B5PA8SC6VLjQc3XmtFEd zx}J9N*+&(Vp$Foso3iubD2u9g93OE^H}gfMb&f3;>l01Ts7R+{4nPSecXWE1Ph2#- z_Mp6ebv0kRwQYC99V2Yp_DM%_3df!`DBJq?T`giQx;jD4&cfUp9BDX~aoo|jd-wQ6 z=~Feo+vK=7=PhHGv!<~V`#ooJ?6d)}jsE>;P5BQ_(e=9DQqn$AOn;FPf5-1R<8>%4 z>9OhWuuW%P@6wz-ncjoaHqzto30o`qu7C08Ui|n>XV4{Ez*9~)!44*`lEx%X$91}P z!}#S!$Om%Xr;t?n~#jirxJq>8iG;nuc{uV{4`^ z=o7IuuU%YT`lVm~3qL!*{LDN!u$!>^n{ayD3zev$#**p{aeG8kB2bx*@EE2h_2_c6 z&$?Jje6Ec`*xPj6`hnxuUlHayxT8{k=l}S|BMF02P_s=>ZtBx*^6w*4-Y;NNHU2mE zHK+KaT`tm5TCGjF1^~`ku3r5FCIKfE)NaDgT3qQ92T1@nJ>yM<8~M0#_4)XW!bitj z93E|>6wJ;paBlrNS}AOx%|!-Q?M52engO72u3&fnY&UeJRNuMMBNk_)>TT^BOA2H* zm6Yc94xUx_@#b~51_wOs?*f-8`xoe}-1F9UZhT`Fwzd};R>(;K-OMu}I~_z6oDQI{ zs7yfn_@ii$L4nE(nC%5@B!DeO;S+U)K3h>_J;Ntv4S#pZP+Itn?+!REgrX9@`tp!3 zJlEs-wGz=9E#c9E15J%%X@xf64E}Ao3-JTP6AQ`uEb+HA)(8a-MEL{6DGz9B@#}$R z%;IzbppY6~^NRuz)D(2(K{5$OwXGbsus%sp<;LtyI|fT*&&M?}t#|yc0=Q=#Xarj+ z?jHz)70P+}?I{jHN#m9_$Mp<8TfJ1wa_n&i9dX66TWx=BdMpqucFZ zt)nc<;0j$=GxC&Ze4iRhLTkIUoUmqTVt9RSk=Xb#rjcp`X~X5Cw=AyBkGGQOx7 zzc6+I+;bsTq(*D;fS{6b;w9~IcX1Wl`wzJB#-DO{w1aby=RK}nyT-ryg)g$Sv`C(1 zn9L^}^Q6T9Xa>fqbI!-mbe5{JR8_^O7%>`+D2mbp+HTyjb<(2vK;b$^$H!Dvg+kHk zbeNr;L2FN_a3R)j9hwsr!fU87v-~y*{n#J%>2-P>aYRv;bh6ybuz0TW^Qnf7MSKA9 zAWBsHs0^huW@ndq_SrA7yK~FmPc$KGn;)3XWi>vVNw%jTVCvEt!J||iR(OynoFgR^ zr^4Q;usWygUM0iiZf&wPU3(lL!%`Q+QdbMrajvp3@G1pL#!6sQDyQZ~%I0h{C1Wj8 zh0={r_wD_W(>2o4G$iBqsP3HwYDOoXdYco5zxF%DAOG~H`QpjZYr2%#&OgQ@kUG<;-G%v)3{GM z=cm<2CfD;Hmv_0;FNQ-Ww9T_888=P#O)4vz``SPb=U+4{s6!yV%cW^+OHfBPRKoBS z4o7gssOq#YO~xiuemC#Z_Wy%0CDRr^OU_P{GBDlFZW{|)1ohj0Qoix|r}J;9r}e+n z(QYBXR#D+c@e9UB)_QdJM_6oAR&_`umQXuQ=Y=a##mXE$e%Kw8_`{BZ;XCpCn<> z<3P=6a`8huH{UB@^DH%S+5kQ4qqWIrtScAKy6N29vOggLTS<3$7e7Z;1pv~y+T9qD z5D(8MoQdC2f)dN|$sR|?JEE0lY4Mzz?JWidokJwLjz$nOCbDtC_0-WH>{C_IzMfhH z%uSvQO>Y_->9#nz(@EZREsLtxt9TdTiLyI9;-u(P4(4!WkD79*70h>Ge=w<)ofgP! z$7ehjh0Al8Rd93)g##mq5tPy14QDV!Wtn$DuY>vdb|(+MEdf}T4aLP?#;^QUL*6~$ zE8pp}d*b-|?SenMGvb-2d&o?V4!{+e_5pW;V2)%lZ4|DKnW} zgL4XP1+fZeWt`zJCJ?GTa2Z|HW2Z!;B_;&YMxn&{IGoPM&$J_pEgY_-W^2algyxwX zED~@c@!;zHeVjKVNjbhOupRm|O8>j{vH6$&=V}(#dl*j@?=Jj&CE0tuA#RP=n5%6>UsT zmUp>y@p)EOFClV7y=tednKs2QO#50&rSUdX1uH5GO=e{HUlvf7!k~cOvaSXNF(Z2V znabD%+^}RcbeVM+pG?~H9#w4OCjw2;kgGNLaOKpnOSi}84~CjZVDo6ku9F}A(p09> z{z*a2lpovXj$ZukOT*i@ADV~PE>xG7=0~dAT>#Ys%1QU%C@Rt{l<8g4c$)EdQ@q46 z2xAwo)R&}4uGeN}I>w-wG>(~EbjI6aQAypa#=i6z04tb|V`;@JZM2w1!Ptcb0^S`@>41 zfJ}i=lqbV_-H+u%YosS7j>e`$X+GPuVHNwf;?cft+J_oYrFH5b{Ilx+`CtC)?BWGm zets~LPR|VK&Mg6!+JH*?KGrCF>d;s!-P*eL)3WaaS{^evr_ID4Mz}ZU#^Xv;Zve7D zO}~yWPhs3wZI95lCaUq5_fa=h$^U6GsyTkoVrx!-no6nsKlyh*cl~oe`GwE)X0CLx z6;yA+@gKry6RL7@BpSxd%jk&}YnOU}pgE1P+4L_%>MecELE>e)w z0yo?0qJZ!3-s0znhpdiz*s6=p3X~IA=t94Qe&N?N2R^9X2wBodT)i^m-O`WysKOzc zLODTYphp#$5n_yIaso9+NhxpLt8DzB0#{y`<8S`Qn#D!KKmOVYyT_KVzgh6v7b-U9 zEV}MDheFpb>Cu%}84qrXR@mUnT*vyv17-nZm}m!J4AcpJ%v6F)89RyqY`T!O+yk9T z;R$O*P*bqRdDo~4bYOtF%Hc*9sqmqTtec1xN_++d`zMZ_BhL`Mx9526zT?i0X9DgW zS3EedC=sl+l$F28INqz&&l0~!H~MMiaTsO1jxmP3W9W1;ioz$siNNW!5<$^C_wL(H z97iX693Jn|$+~pAGtAB`GCQ-t?Cc_0)+Nibq|ScKXs5zl^KSV%;**--Rt_jZE1h6$ zg2E*rl0b~7siet6G2mdo^QKw@o|zaWzgDS zOh%q}xc<~n(Bpe?l+@R%2X#}u&G2tEV+B)AUQ?A%0Z^EDiz*hXA(RMtri+tf>5uoe zD%R;5B!HX_>~JuW5%b@xoC)6F(Cg9`U)0NRB-%~9m))qX7 zR^ag_OS(<-Xrhv~bHWrgxiG&ZteiJ|{hP(|m!CDyy>?%1 z_DAwK)@JiF4ctsy<^3yykM&obdbzOz>@ju|Pm?Oe=y5TI>63yd&GwCuK$;w-$-JiJ zoVM#HbD!L=NfRynS=<4cr{n@qbijGTP^E8;lkKz_AKhhp9K}JxdbRW>=-# zY1#h>z@NxM2MSO}13UOfUol_#@Bf;)Ftb%%>s@fF zo0rhZ!Ihw8{6a8|Q415JFLHsH?BNeu`@TEnOmOfCk8kd4)0(E8o6eUn7#{P0)=XdePjf+k zJB-Z_ZFxUj(I2;Tw=Kfya8Q8KDwE0;OJ`kZabcZquUi8XQGXE!w)C!_(FI*3CXkWf zlIpXf8*Ru!q8SlkFgWD!ctgTKXaK zeBJ|pI`c0mba3wyYQS?GR?`ox7-wrD+-ALPoCzJ}!dP*Piaz)6-{#HRuQD3->2`gT z{PP=^`TUDN&6O+H=yr3m+>m7&Z9Mx^u=NX%2=IEQctu%O6h%Q%cy?=1lvGtjB14Q{ zWyVb77#9}DXjJg#owpc`3Q*9=GFF$C=!Q8IdnLx?M8dP{=q{cnJM;DH5Bl`FJ&sS0 z0U^)4&qU4CRoW*I0(|y)a6!uv2n}gKYu_g(Bg;CRzxV>Gza0n2nBm=ALSubW7F$$J z(xB(*(ybVS7f>r3A}~CGHjRW-_i)Kw z+90_1K_QNdagcA$`Sv%!xlqd!;0Vv&>@tpr7~48Ng~e-J9mX$J(l&%gM{60*DH+Gr zY90gaBRwr?c!VGi;$wY;&HW!?iPm}e8Qb`*K7vOz>{MFO^1J1h^(+c_hH z*(o#m5@0;FEPaXF43k127kOLiqaoqO?w(;>x9GNM@4(~}PaFHqbJFwDo=kgP(Y{`_ zjgGcD#6C;=ugiFCa*eg={ZmdKC&QZh$rHPvXGVAbr@#Bxf9m>k*PhNgt3F}S@cVH3 zO&A?`10t1IsoXM*ZI!4)M(>UAqO#WSVhF9&Zis6_^9iFKV0#RHI1?PBw%KpYWd$>R429x?it3>TUyKf{0g1C z=Rw4%$2iY!bJk(Y3R_j4U0Ji@w5Q4^i8W%f5D{T8JZAsk0orKh=a$vn%%TS_ovmF= zJ^RTe9}jjC5)W0?fbz`5LFg>YcSfWBH1np}Hf?G|Y_oJyHz#;=`v7>I2Cxb6;B=Rp zhnrm8f1XuqQ5Mv&L{$#e&Cp9TVEZt%-fP!6~fOMRXg{VNI z(7|0Vf@v{By3&deBrs`0zv51$7Eel=oJX8^d_(+q7Z|6=I3^~^J^iAfyqmi6Y)$1P z0GmEuVa&o_S>ey_I36AdN2iw8?p1u}P0QhlA7{q{&;F~b>Jb*^g*N4ja zcJ|<(t{JzpGjn8lMo|`=Ti>AD>vDW@!nuv}R8`5|-aZ@a>xd}w+%Uhez~SK`RcYz> zPubhsrL0PZg8@Dvk~dsMgtGLMo88?Z2Zvj1ZokFK(gw>*Ys}0pVYHva%7wNJqi+mm z`l(a9rq{r>|7efPdG=dh_)}cHe2s3mOQ+*O zO=T2XyTA~ysI2%*=eELDzR$|aGscUe^vun&qOvv&J5|TQRLaNoGzN4StNr1CTX*lX ze{_T>pCD;zeu0hEmCy%%`b!wBDkwEt>)?j&nVUYaE1``YMk|W4Pyl(}QB_q2siJ}$ zRUWhyhoBKGNOVW3!U*woH`*tY(#Ej3v_^OSX^<^{&sfK%;@4E#Qspfg{;2{cj90Db z1{$Yen8Kr>Q21qicyQ`YlRLG2n&zq;9uEiofi9&Qg!al9Q?HrKL|rwm0OQz-X?FK0 zo!gANnAJVCyFa3|&6d&}4e|3NpymX?d4JCxzIHpm@o&5!pDL@uWUd3I3u^SJc^4JZ zCeWO&vMCsu!g{F@7q1aBqn|Kl2F9%CLwp*wcz)Wo=^SWday9{glm#%&2#VXokTqS$ z?4sfGmkqBytgc;K%hqn(w_BY3^0UnyT_;zc1`EBnR!?m}h7L^)yJ4vLEPf8|0PA=L zZ44=p_Hz-=Y0D*0&vr8uljTO{KDK^uREiAmo%yaZUj<|&(e*n zrE{Vwx8n9V2d7z{ZF4D>6ue3A8T0~eG~G;bG?08IH!-T6qWxLZD}5NtH2IsB*kb8w zrkGqs+U)K}UTT%rssHt#+u#2C|CM=Wx$l1Bv@fQUA7eU;{&H3(*=XU86GVc^y0-x= z&1d=Gf-H5-qtd3v+haLvbWK||RbzkKI+XT&izz$xKB@ka?u)2E+IMk(b3KIjA};V* zrP(sm#%dc|vk7k2NrRrbu(4sQDFqs=ys`eWKQkwO*` zsc4^6jbmW~Bz|PXC$mj55Gx$*I&R%?{MswRYzL=v{ik2~cAYTjNwS|eUC>kOYTEq! z$dn&N@}Ox0wN1zZD5Z1`&VWRIMQgFvva)<(B2JMwJg8Y&s>&s<=z+CacWcawj%Pdx zSX;5VeUr*o1f6GUK{XdcSd~dIRjb{6;@Le=!AJzUsKRp;k1lBl4?Wgj1qNX4LYz?ML=0E z0b^G5I`NCbyR8%20dOJVlyZtu1mOg}{bt1v-m=`;wrn3*?rc}=AKRMk=b6D0Vms0b zV7^mOa~#W2#SIX^L1S`!vLKv+R!()cS5vM1oY;A3_wY|;e)&mX?4>&qH z3<->E0DgqB@L9x*(SY5(hs-Z5vpB!P^3s|I)ifbq**JL^Y7A<|ct0s?GqQJ;1`*5Q z;XZHNyut477U0P8j6Bb|aN#na{?r$^eDN}!Zbqk@k>?pE^V!tFQrQY;EoEsb%fe?q zFUPFSm^7#?gPaKJrg!CzNsK@n@v&GH42vN*@80L`<`$K$P)ae=>2USZ1$wtg_qMnfuF382cdl-Zd%RmU^+7xI5pcmX6KyE|cp3{ppF zjWz~tG}>k;rCD5D1HJ3(C*g`ljbq@YfwWQ;JqJ-`|tZo=~ zZtDD(KFyb3xv%ft+pUubrEJZVwb|6i9FLCXw+pEJa78iwc5wz*c;;*cYyoR{uruvL z7>5u@jkGyPwrhQ-eux*uvLZGzoTTi#GMANp{HpfqW_Ugq><~nrF0T$c&^-bGm5Gbv(TB~Q@_(sTC?U_ z^+71jQ8{e|Y2zKYftyk8mo3}X!+m@7TYsW||CfKpobM`ozB_AKC>&(LD}t7@Do=ic zTIZeysGQZNAC&fPDUGT%d!xAq=*hz$8BJ|6D7|hvZ>IHr+T$t0b5X%+fBTotU3u<;%9a%N7!H05j=lxO(b>-z zLCduL9b*P(8oNE(C9wukhNW_jy)oqKl^$IkB6TXyF4NfawgcrzyE4_j*BGWo4SV|O|oj5augrKM%&=jL%vSYKP?{P_!XI$e~~bn*_{ z+nb!69<#f)0-QQ*@Ar?n|KKjS-+HqK39~$Brq|=Cr=I4;&wP>d z=PuIg_Q-SN<7#G+Rq3d#2Q7=TqAE(ts-z4dFs$|aopnC+KybSky!*aVo}p>9!WduQ zQBkn7f5_dodK%`r5S^i|R`X zFr*4sT#?dukWE!Q8Z|MSwD$X?^oHYU>62)c=+oUpHwag3Tj*1HTPxc;d#5LZVXu&) zk4K(!>Y%!@9^5W)oK2O`X#AyyTMFN~z#0y7Gcut+f+YpRQnk7HztK96Wo=eY zD1YsDMnCw^{-Qe6nOmQqAE-_?kGFhJ#&6Nvbpk48XLpW|4F@t7hw zpRz;K>p#vsZELAEGoYzC1#nFvWDAbf%Z8u4nsHc^FJ4_Yzk6@j9nc=8rp+b232LV0 zamMv~P~_2h6l)UOdlmmATfj1~#MpR)Nv2+Wy4VUZ2?r#%9UCFEKWz%eH1{{JnMfa( zu=(C+R?J7Y)bl1Za;=YreJOYy=S=*b&i6I|Vp>V%ND7*VHQqTGIzoK^_q4Rl)pYw* zn+s6SUR_`7=%GP(K~8;4TN~a+Mmbk7mdr42vuJ*&M!hf@j~K@DDTep}FI!WI6VL61 z{f5c8<@{ltS`mw>J*=r=rX}rxw#&y7_qVMd>3z~_B|5-kub19GzJ!2!EqssHqvjlo+uG)A+Y8re zUMEcqBv(r1f8`fG`}B)n`rM1%-jyzH1mz9b|9u!dgsPbAM@jCGW7;L))YF)o3ePL~KJW|;u=K&{9zWRJ;`;FnosoB&)`taVrh`NI1myEw zKPeAKP&yb{(xf_eL<&L5#*2uY=Yx5K*8s7zZ7L z>1CKw$V=hEdd7eFGmHGw-#uXGu;NlrV=Gs$q9S-8GZp?4`#X#e6cHGj?4fZ?$P^Te zc#dZUN@#qQtY1=ZQNZ@0aR0z@a4NjDRq@K*idXOXv1qF?&>rJZ`g^=P@+AfF1TaR^ z$-6jl%r7i(ZsR;Ny;&4&%p{v7XOZL!XAa&kidw9lJ2 zU+2N*eYUqY+1cG?cYmLoH*fOHv(ND9Pkoy8^>t=uy2Q-naU3Y+<7{?&9h54ul?Quu zH^*p$F^0v(B`#mO!pZ3ghlhvUe{he7oA-I};4Y(LNL5wDI5%Z6qAW-B`zOrIY_hzx z&cebn^K(nJyL{Rfer$#C2jVEoisO?*?%lt`;RWH`$p8Q#07*naRN;O-_C#QQZjR@l z{{%07`tvLk^i@_!zC??_o?#zN5z3 z;f><7KjhB+ZMna_%di-sLMJXR&U5|pMV`8Jfle0U(+VhbkUKFfh99#!#6492AykHE zu$O_wUNRgFQ3%H5q9X!~p=Q16Fd@N*PDr)a+I>DA<73?_G{*G&Hq!xPJ%a3H3@k(m z)O6F(Oag<^fRbdJPWHv$N+=59cqAB*ekFsGfs{;N++#_%x%=BEM}uNzXl3~A z*Ua}WZ^)mkiU(O|?z5ohz@9RG)5+vY7uD(}kP&Ox9Is7{CS#m1D7rUCB{*Hp(@_`4 zL#$8w^k=o$lMayNI$DEK!u+zZcG2+lZxqX4e9AoYr?;wm{gFhTK^ki_)gz)ydVGpD z*5;3(B#qH#NJd8WeAu>&@0$pA+Lm)t%xb2K4BZ1c z1a|`3O?pst7|*3R=OSwnkTm_WEdcr1B14$7AFL znR@iA+ZJC!_szx=Dd6owr0}}J)6yS?^phZzx9htE6=Z>XBBo6_I?uv zNy4C1^NBB~)7f#Bj-VN@9jR>-c^=LeHOs^0h?DpT=^g{Hsk-cfvW%|B3h|@Z9K{zEzVV3y!bJU$pT}@8{pB9 zuPP62O2}mH6P4(i(G^{vRrF&Q$Ns@4MKPjla<#H_5u;21Cjvkq5zwq^mvmtqYcnPm z>JPTgY#2f9X|3m-W2>bN(uqs5y{UGk$F)uB6x@u)OB9Vi0Dc~rn`l!Je)sOT`PBCF z%$#2(o8QA!7IRWzQRJB-HwrV~L9E~oM?TKvNr@

t+Gm46;xul*v#tGpOnmDLoi$ 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/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%0A7U_~#y2U5P@GXAL~Tu> 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 z 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

EEI}% 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%0AAl12JH?5&Z5AStF0elg! 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 HMP&XDnGBt* literal 0 HcmV?d00001 diff --git a/res/logo-mascot.webp b/res/logo-mascot.webp deleted file mode 100644 index c22f3bc90fb0801143a7477d61805efc488e43b5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 192532 zcmV)dK&QV_Nk&Et@B#o=MM6+kP&iBg@B#oYHHCZ-8H$nQhLNOb03^WZg8v3<_wN2J zi0Jai-qzHtxf(Rr80ucd3APgcx!^s*gs0KAPhL=D@AOb*7F#r%qHe4bi5dw$+T1qQn z0}&`8puuP%L_|VFz#t-oy8r}qiU1<=0*DBJAWC&Ni3sRJ$u#jwqi==&R1d^RcI!5H z4+I`Sg8dgP+4)ou5fflffCOM>_YIW$A}Ub!P;FNr)N&{ZZv&bSVr=g@4W8R3uQxBZIz)LRoA} z7A|2-S0xj3mYOuENqZAeAR`4Vnbb82Larh}5zuX#5M(QeTRQ}0uoS?_fsZZ(0$8!& zs+mzNi;yre)rCRd!=xELRm-B=SvZI!*{Pb045T0hsYpP=Nr0cj3k=#el4O-X$c3?c zH;;qZwpC?+cPa3J=tTKZP6V9iZvwo?|L<(OZ8wi{mUaUaUU;CI@HRnBm`#~YnN68Z zP!nbo4pcY+jB#D}{oMEcp7cK8qnxw)ki$?3s|9JJ4OKOfa^$HAIdRb(V9vn_*=RX6 z;UEX}I;Ve?BR^PWrYdKfx@wiP6`^AfGJDW;q#2os8Skps2`VCYz;H~m)d$1ff~yN& z+=&T012jhEx8G+2h%w!w!l9p47M<}z~|ro(_nvn`M!Ns{FFuFmH`C@2L%5E{xr5QK&@5CkD1=)R?f)JT#f$@Xr| zt05$WfsjxNNoY7@d`+>oSYez{b|^cP6Ur7? zvRL|jCcxACf6KN@c5`)kSt&(^73Sm#XNWK0c`56q)JyP7sF$!`!g>ic%c48l1;@-S_=GH8A@VracX=Bvb0Z5eC!LYGs8v>3D@XV?%H4R%`dTO)FRqnb~1Z zHkzr@(iJL0&GsnLIVzc-K}oH$4{3FH%FK`Q%u-=m+BB$%v1O{k3NynMdbDT3R)uC} zm#%PHrQ8#13qXKJbXGAN^%*mOkJ+jiHaI)1hGwmIQ(av6BF5}2iNtH{g zoe`R5p*0J2)X`HoBZPKMFJ7+R`0Pc1DJ2I9ZCWFmw72rW0MXEwdbNA=o?eyfz^QT^W30Ojwpe1ApT*|+c zFXgUcGA@5I7-|Ca#{d6bv!t9|dw~f6F`-W=6T*hjA)w`D)$jNJpYz<=yQ&c{A8%bq zppoAyOl@N>1aQ2y)<-jihovvt*O~-w0BF%@<>Ix8_ZYXZzG$Lg?DofR-MHU zH7TGXP>sD+?Too1kFA5Wh=2s-L)8~e23qW;VOW^e<2X#8jjO8HVMc!Itd#b0eYludv#ZC*1sEULLQ|^A%=pXaA+C|JsENc^4`$14f@}~TK^B=v<7gcGBcn_ z<)u9W#hL)ZT_umG6{CuF22gPr%AgMA=uWs3nm3X=n!%F$UIT!k5}Me1hg2?alj5WbQN^@PE=L<4$fR_r zLd>k=lOkplvaytR)shP>(Kyj1SiozCI=wEVCyb;JEdG)egwUl-$J zY~k6dADOf0LzK+j9C=-6)(?R z%8e;mBIU+EKw#`jL4g#6((cGB#s_fg%JoXF&|3mWUMk?qbS!u`L_a`57f88kka8){ zgAk5f7bZ89_Zn}X0ZL0R<+D8;Zmzg0g}lf?Ze#;fOV;d!(wG1eQtd{G4te6roZU%z zMIO0F=E|fjXDz4pBA6ONA;q5x3sX( z&9ZEul9%TR7s}%}d}D22vTfV88@X2PZ8a|-4?^EFttF))unIh!?P~N$hSP}vWAO36ym5rV;-4Uv`k*|+JL+Xpb#k&iN1%t zp}d;_@KmrDn*5%(J`do9qd9wM~*FDSO@0$T5bZarR=5%eib3N(4k` z5fGt78BtmU_I+{wl^q{CPmfL37iOMp+j1mHvaLm1wyB@+Au)miB?go@OR$(F=|I-9 z0ooL6iZvk{fTRHlw3s+4G0vp$kWgn;JA4R|Y}=}n6?eCXyW7KQ(PkJKT82i`-6F^Y zczQUF*)2zIo^z|3Dz#h2bDo2SP)^f)J)<?^LE%ToioK(gCWSJuBy&8rS_gmvg#SsD%pq!O8s6jU{<(zX4*J+fC z;~Wbhj(zByXn@Z4MXeka&peLnURgW6&S7vACpPq0Lr-mXE$o|ZXTdDE05k4XYp(bn3c2PskOFE zlB8{0$CakgRsCzj99~ciLPKx}4Z$H41cML|E(i|c9M;e}6e?M}tSr4(+n%?Pv~AmY zn&pN*ejo&d&>=7sh0>vPC<>uNz|Z-KRaNc5s$v6{Yuk1kN!maFBp4E_mSX7_9@Mag z-xQkCrofbMLK~o7Yu%k{@VeHotO@WN|Nr~nmZj`{kmi_U-u$B=1VY#$pc#4E`2E&C zr?~|1aL316Rrq+#c%(3Oy(vtp+B+#s0E~_7DpF7xU=o3Rqeh1CvbwH^78W@Wfjnjh zfYw^NhbXqy0iZgHmp@fIfp>KP*F-C;Zw`~gO<~-z#~fU2+>QWgk2+OrLcl&XF`Qai zVD1FAkJegiu>WqaGXb34|66rQmh)s(bSW$y*k%v+1(+^jUrJs|UP@fbzJwThxQ1qLmBQ}mJUe#` z)_UI^Rhc>ej*Mw$@4f+3>M?W4Lo0n|*)=?;wlU2xOS7G3tkbZKX&hrUQy!J`IL&ss z49iq1XI(-2F@>6A5ONxp6lG?{VJVKbIm{F~5QZ6*%Wz>%*gDYuLPHXQdo*gK?y41m4Fg% z<~ezvqNQLl5JbDx_PmXB$Or?@{_=7!zfxR^OGznHic9%QAOge7QD};iZQHKZX7afo z9{HgGC`-pV+ut=6uR{ae#MhM5lv8xJvhL7$MiZb{`u}H=EajJP=bkNenV5YkeJNbp zxrDs{L|+DGqcMjQEBf@Qe$#m0%3!>b{v1KMl%*cqiK`BNuevoB4z`3t^lpvRTdE$F_9O5 zW`*~Q`?{|1yK;C=ZrkWZ8L;piy2&XBps}Sb$ z{&{;-ZX`*PB&k_BdSdRF+4GsCEGbKBldvQt39)x|R+PEhNRkvOFHU3TXOuo-{I}{n z_zB<}{r~&hmXx*k>6t-uLb#z2dWSF}9J5Wt=(%@aP~9u5>lUpC*epSXDG*!BuPyc z_j66af2(8yPtX-?BS~`7ufZe#Xb5FPz?8-W_=yJW*>+2F*4jPtt|1AkAPK@BD)e4j z9o)~i`uo=IogeZV!{9?93qmCd9XEw$A;&ESXC>Rmm=>teAQLW z;7?@3DDyF|E$T9^MBt8&~xYhS653Y*hBRRa8AVSB|Q7^3g$f+J88gF&vQ4lbk=c^ zCuC+=RnXRDp51fzi>sG#P^bzg5ANALCAiQT@X(eL#U?zZr(8$VOFi4gT7PIUFh4abYU(aSCF0uIu$+AT|rOi!j}eYDLb~%yrg7}0(m-~ zL-LrYCp4i@NQFI8qh_9thb`PcO|z0w>7|}{N~U)YJzQE+z*3TAd1)z7kRY)JNs(;J zwvuae2K3-x4HA%mggYXBv;R7>BT2F(#Vf8bo6pf-Iz)KG-LXu^1nemIl5(@#6E1wJ z5;y&A8>O$6Pc@-zX?@yMMSp3j@~H-tYFdZ314X)^L7|mTwVzOFv`$0o&=N(uXhpI# zN=ubbwVqTcE!EJ_I@1?TX%tfzTKQDpNmHrNG@6FCBhwbGq)MZ-PWe>RNfG_fv>p@Y zcDb~o6(|~oRvyX;6)K%nOQ@(&cWT0}(=Dx_6-uMD_5qv}DbY=(qfSxneu2^oiY6Yy zO@#`iqODYwx;vxV8TFS|Xay3I2W?U*f!M5S%7jigc3{E;F*4eAX@z+3HkAs5>P)p# zD*<6gqmy-OV(cl3P9hF(TxhG%@9Hm#1uQ8`_iM{ zpaaQ+F)68Rw9{cWO9&x)#Li_zBKJ)nok%L%fn(|8sV20TE{7bQ9OS-!v>Ok`22sJ(U514asbl>U!h~GSQ#+ai z*>)#sG?6?2lZqk&)6O-B1Xip}gozARSj}N>&b%|9(D&p(CQ`Yt8!E(uu&JmZ6{h~e zSRJe;B7B;wmG0xVIiFDG=5ywWtUo8VIknNINgi-XrG%8&TsGIhYW3UuG*=VO?DWcn zyC&RPt>(<<<{n25a&&S`w?E=R*HkLnz{Iq<;NohvI=1U|!j090>5-8)ArIny}HxmvGY3Kd&2vx zmDPkgpF0+v?0$1C`5}gSc`rq5PW`3(>XmaIP9$f9E$ltGB^~bV2wIzPFD^2_fo$hX zT~oAqfz_6JSuavVimAUC3$L7dcm{|2XHc!j;u(KA(3^-zcSxOAewNWQUBavy`3HQ!mv;1!iyamEDJD zRiEhjFP}v5a<{buPqg#Ii%F$3xwyTO;7o)`gv0&E_J51FW_so%(`_&@+6+-BFqpD+<@3iY_pP((V0qI79b{roX@!^} zFi78kBy0dn0J(A*d3rki%*<#VvVyY}vd97B&)JFhW>h17PodnPk|DY_NatekGtxHTlNIcu+cR zMgc!X1xN{4>@y6&#Kc90qj1qw{OCc0gnB9_wU`$Za}sfCQQ?W41@zf z5D;``x^WF`hPYr;fob{-1F&ttwgHKC#+1ik#E4>~D3nft z@~K!$X$7?>GOyG7;MqKFb)GVK^q_L@hfY#AI!#HZ&*tQL}jdChQ1ae=g*o^-4BCe^f7z3jbMvRK06h)!* zCCN)>fhHZuVYTY}4)*?iw>KURLvCkb17II}_mjD}yx3_jLaT^;0wqEr6qjgRLz)G# zCy)kI0HY7EZ5wPGY;0118RWiFDWXh8n(0MdS3pf=Vr0a~$Ve#)C6RdfJh9E-qTcVo zt&PdR2Zk4KpBkJ@u{1rsA!{4~CJU3$@fMdGy{iry6kE~g=F(;Yt@;r}3548|r5b5? zG=U1JV)P-mZRE04N*ni-O2uZh)Bd(DwKsNk6;PL;F3EaEMn*Rg&3o=-kW^k|s6tmf$x61e5$Jo2^#;4w(Kk2~0JWkb#>QPz0 z0x&5V2thf6*|-K40s#S83)BA^RN4{riu4ZC5~|TQ2NP=1F*27rsHr zlB@9Mef6Z719UEQqMjsysAd=lxfQ6H%Z?i}5Wp}1Y?-YxFD1Gm+UdaJt=O9C8lVQq z$dJhxjYcD*QBg!hNJw55(=Z~knCkGXaQzLu^HG6il#{oAnTVb$k&5C; z7Bn39Qf_;`5fRWUz#Pg#06_y#X5=Z$o}P^aB%q98pl*XbU0^DeLZpaxIwor@qkSu( zrn&~Gff_P0GI^TOXk;WhLE>fe$dY|$Gn_o-jj!LQ_3&iE#?-WqBPo-8PU~~L-QM*6 z&)?*aAE_?h>LuHR4yZ4Y1VX~l&<%ixfccbj(g6U5VPJ!e4cN?1?je;TsL+{qw{=^3 ztFcE7Py;o{WMnd#%qTM&jXgpnfh2i(jOeW9J&$=}a_Td9fep4y0foud&*h)~!zcXZ zkaJSeeEr(cu+TAUbHEbvV}paoa68J8#-mIB+cN=y0oW+oFirQJA`t!Qn5?nrT|@g; zN)6ONCX>lzGMP+f9F6+3k%+|0wdvGtsvR;`JwEA=WC;#Ny zbtQ9);wnvwPZ~7P6ajM|>SY&lj7y=XfA*Yn0uoR;Y5>?W`Gk2-LW%ygy#{UF)-6Cw zy^Qw8X@%Z3<(m5FGMOxs8Al`2Y=jO8$xAY+PN*9+?crX}-XS0OoDa0Iw9%dCIjx`V zKl$*)&%a4^r+{!y+X(R2! zHBI0d#ZAYto#Z&#&))q56OPC_0a|97#x(##{x%iBESP!O+&+?!fe>Y2WTXXXoYGU; z_bTkC$?`k9?sRTFz95F{%%-sZ3|K5V++D1m&v+?4|A!P*kGu6{S(as)Ebo{|hlrO{ z(^Q%>SE!I&S+(sP{&QBTE04XLcZR8@i)70T87Q}|nJ+_i$XZMEZF4XC@95jucgL-8 zFZAT02GHy3Mh#}XbTamdz!J`O$0AlnIJg&PKrhHCK9$Zp>Gn=#dsd@9OTEI~ZNu;G zjw87DA-MgRJ+zF!{clvabM(WPvRHEWrPs}OKIYYv^24_q&1XP1q2X@iEX%Uoql0OK z2+2z)DMHCcc2tKF%B|hgyQTSd-uO>^#b2=(z(CTJvxpb8it9RSero;RhX%_^Mdzh_yE18GLT(t>1pno-XNKt-@=je`%iElE{M$S z8(Yc%=tquw5f%DpJQ;Ay=xJYSAGpqO9Dwqrz|2UCTAmA-f1CHBJtyu;{h&;D=Jqqi zvqyZ}W8zH**oR?h|7eE$r7wNsOTO{tZ%q3Y`@lXu_lKMrvX3qDSz98X^;3WHk@f$_ z!(U?OZk;U4a_%j3CZr+KBrk=eh<;R1IjMq5xrwDOJzurN$yPMq4!l1Qt#ji?T*nE; zF)ge67(_m9)W#c;N5|-IT!#oiw##pg$=kp94LDTo(v+;?re858GM388G4vY z2X^~8`SSabcM;EvebA;4*#7vg7C!Fm!;rT^d+hJSKJ2r1c;9_{hxYciQr>;*nf1v> z%deK(uVF&tZj(tW%eu|dpQJ-X;^og!p@LLOoWD}qkX%z~sVsUV_imLw{15R9ANYaq z{{l%OhHyYRyHJJa@C+EL1w`XwO5G{;lg8LSpw|I9Pd)C%RMImi6^B5r2Jjf;_RE3OJordfMg|B3@_Cp#bi3M4Q(KkVVXgOQ&!XM6`Ygt~vi6P7{;D)M2(kpg&A=T; z+yzru-9dhDtmjj<8#dYv!+2xHuIGyZ4tU8C1j1=dmEMOqbm)-1`*HW(cmEE)DQ^EZ z+T^~a)<(PRjBbeJC5}`|AU0>`oQHl1u1aYb6X_clYhvO*w?=bt*3V9lUKweE`FREz zi_ger?^TAOMYhl=w~$;Rk;~eP7p4{zJ(dHGN= zd(A+vgK`g)%u_-kRE|^>QB6B6caP?Ow+|xzpU;@yZ(ASphBX}AFlPZ8WlRv37&qsfBi99>(qtEIT3?sse}$xMLbk6QLpq17<9A4>>&K@NjSMW*v7w`B0yH zw0hg<{M)fM?ln#F(nTuzu{}AOb=qL!uwBSiR4As+A-l2qwRQZOZfog-J^%Ti#Kk=G zmz`jqspPV3+q-XKdrt9=g(v!CGTT}7R#`%wYzQ%44CM29Hv-{sc;d2efW6UTmr~kQ z#(}}Xn{t;T^(Iw8KHxZ32poq}ZR&Pc+LFo<6-sbmYQO(xeiuL9k9dymihWQvnarC; zz#T*}6cGn-HF0LmSdzl*>{haq9d9fac4il~yJU`Ie(>1nF85fyNW5&BN~MX-X?u;+Si|0Ou{n)u`m^NYH%$0AI^JaE6<0pdVdOI( z>B47eXY1Wtg~26(*@BEYgO2rV1T;BW8 z%DKiDfUpD?@NIR&0Wt53%<3-QuFH;?m6R1@jVakR9{0f_kdh;SxC4gv;St!T4~W6h zVz`sp(yY@x5;LO z#7N}MgyzP@w@f^J;c0946wQ_IfHN5Lym2x=lq@BO-%#%7$JNPfp~&t#irFlyUYR3x zsCuw`Brh=8#6&OplSM8Ky{Y&faCLQX@Y0*g!hpZG-2b__=nPx~nMLa@AirJhPvuCZ zQZ^5p|BLsdJ&XMK#jrnfK6&od4i^?A6tg2hT*Mv4#N9-9%&xB(uL6$)dO%#p){?Zw|{$Is@YeXzYNpZ^?L14-s1bTQ9^3t!^?XS5p2*UjF&l@FHv zyOlRwNG6ifR1q>*TG+YRDz7$SvQuQT!`{1v13ZLCBrnVo3eSI}b2*=UreFGz28oJ$ zhbn`E$D7^sVlUP(L?9C7N(ppXRtC8h3|W9aqMt&FRBEGtY>gjq>3U^x>emjjIJ89` zCX+eF0$edb91znWQM&7i@y6~7ZIY55x+csnW1rMp0r8U1Tl*zTQ+J=uEDVNWu~=d@ z8(1uc!2%B9&6mIPPyAzku{)8!LT8~MC43?N8nqQFwmNsDj>iNcMV-ph^zl7Zb^X&0t z$a@KqeEwz>nqpz^-q++Cisx+b+`=l{WrH`l!;Zh&O)fVi%8IkBVDr~W>H;`i(~A&% zhDjJ;WL;p7k0%`)IOZ`Ap*n}|U>R2q|KZJ#b=R*Q9NM(&c$vTV8-Ad#Y94~58cv+b+9wA4Ex4O7` zX~&zcTzluUzLszP{L1I8fB#qBeX>}ZVm|Uek)@qWTORxpyZ7>~v-_Gs;~LnW-}ik) z@;}wHl;oVIKsda7P7^F=df7+6)^SpL|BY)9vt!k3cbVPfar=U9zWHjd#9y0#U>vN0 zUNQi|febC+4xMn=S!y1$3QGU5ef_;gech+NerUK+43Cp@G(`gk96_;Q8-)iGu?D^3 z7#oB2I8-GbC$3~?#07B#!CeFpLTNHo%m|Ja!_wf0p@RW;npw^k3;w2G{<8k>^#6Y* zONJ*8bRBA`6Q5vnFQFTO@9x;#xTfV#Hy_ten`f>~>B+TaZ-*Ih7cNgf^kucwLl1!G)o~x@x(R&_RmXNAd3nmOP#%P7sQ)t7|P7QH?Ukhgux!?iPK;MM024YB^17u<4G z-P&nd>$Fett(_P7?hQqOo?)fVh*(o8Iy<6-rrgiBGxzyFJo?L})0p+af=Axb4I?V4_vp7P#2C7TBy`=1{^kFY-xSkwua0z27v(% zbOX`O^vCk0-{AZFS3)SJO+89?=Vm(a&{ukYO{$aeWa{y77-CINFR*bhqXZjJ2n38k zR&JVT=Pp?>&T1Qe4KSWRxbCkp5O=ctCeW1~xR*1BSIL1Z8(2mkl+nzT1&@>HNX^&=SrP8TXpy{oh_wU!~esX^-_il~m)-!FLm(SzF|9rpseUou#)q+f zEZ#-(pjzNGW6di&9GDZp7>&_J>5g8qVZEcnVA z9okeyHzDVwer~L7tA3ainx69{BKw`;TG&vZrE^`o7om zu6{=cJWOQ#o9;I|0WcwiCNyYAX-#Dsx3nG?J5sF2V$&ww*f=G_1;a3^&CDAG8{6(& zt#jP6f?1auYJ%!5f*nYx;LK%SeQ4OZZuY$ES;cJu5=5w|G!3oMnom(WMWCeD(9k+s zPtltavX{Dv+)yjqO8qdZWUWL9k%CY2Z!qEMTdpj4*tB7A7#Nl@IVcrM3aMxt&6Kr= zF@a2E9+IL=$1~1deEgeCF`2vxK7%j!w(M@p=C9#!|FH)iJbBQjQ-TG3ITK>tZAd@! z{9PZze-^2qpqgGd=`a7ntwUKLKHkmrk8TDgi$yTeg#Qpe#ERq;i}YzSM*|DERpsPT zrv<-SPs*!mxQGJ+=Ol1Ya{^#OqY3GZ#kb+zF2ZqbjCjWg;Yv)2Q8xk=X08r~T4o0g zfs2Bw-8DJk94<4`4h{>55Mqv*J|UsRn#y>s>%1P}N$YX|18Tz;om3;&Mak ziqcf5KuW5ip=~c&ASH>EWRpm3nWCji+g61-Q(g%5Lpf9uT~-%gchN4}0v7sA!5n}! zaOf8)NQIh|CRr2P9`!R1C3On{%M$1F)oK+fJpG=2=I;2$-e2;W&wA#`1AC7hJb1W) zPKiSLnZEsdJOjQD8uz(MrZ=c84Q7#DcBB0CDs5Q0XTcxSroPN~PE zv&mp$H5|y{U3G08rl=vRWc)k-pinm?)Rm+NB@h*8DOGQsYV1%*NlLOwNLuM>rPCDj5VEu2%kh+e5i1 zL1u;-#%Mb@$4T0DX<#OafUB5o%aH_b=XT)ot0%KB<1V2mMATX<9S!aL%T~qhuWZ%X zvQ=?gD_eCzp+ZGJ6`K_mYGMZqg+iv36N%D#O6!zn+a*-aQ1POyY}HwETIH%LFB(FG zh|cP7aB;%Pmtg7*Y0?|?%Ca@=ec0Y;R9EBfecaK;8a9tkX@i;-sQM!l)8r0HA|<7* z4#I>szv1G_gwvkn`Ym4NGVi+Q3XGayA|C@hH;{hVZ*!YhC&>lTo1g*e0s&f$MJUR# zFEc_#P{8oF2*EF32EG#=3s8&XtgSN5lBKtTR}hz!;R)tP~d8 zzI9jGPhqEpu39v4Hxsx=%0fll14~mSi3kSGDR98R&IreC4Izrz5o%@@ARybQxvK*2 zLV5mF#1wiv$#TA>nn1k(0@b9>lxhNXV*=HrE+$1vAQgKnDk{{SC@6{|r6N-{sX@^w zXnLEHswh$?1nPwms3vuWRFhrms$ysLa;vDS8iF8jXq(U2@XDJzXG#@wVIlpKZm99( zy&vK=zxs-QYzn-?zOO&RSPb1tr=n)1nr`g`ImpvYTaqMG>P825AJ1>NxbitqlYR>Z zVnbgT0^MX3OxdJYYeBP9gcyh-0#3$p06fSV z6j|A=EkJszQ>qYyq(V|jD#<(W8lKDHT^#V-Tz}9o^or$>K{Ej{K}^NdbFUNAnXV}; zu4t!$8}AbVqpX%F2?S+T(p*skH#%mVBXO_WB|&DQU?PGb09SwQxnhJGNs5BLuxe3*@m8L>nK&aSG#onq;MQkJM7DZ7MB{OBG zTbj~L+b9}Ew?gHFip|`(Y}!gwX{wW6rK#+?m6e_(HzYG>O&wN$gNu((v*8)999^iC z7Wx-p)X6lxM#j5_^!u-zczpDKahrw$yn1|GFs!3FQk|$-sZb?DCbF>2=oBQGWKw44 z$d2bX<`-A1ww>-@c{q;XD;dyPfIl3aem2k}Ox_m|3rQ3X00e#GWUKPw6Zd*w_P?>Oq=WbdR;v2ArBF9x$^jC#gej`K z7QwT*(~5Z$0|R!|Lv6sZ$Zp%C4mZbDEEg%qiKONA0rv3Kqe(qa42C`u_xHL6KT z(NHv6K~togf)v!Q=mvG;+G;4IniNt^D8zPdLUr0gkehKZzxG7f?&0%4(dgz%rT2wj!{B*P98EnDg7R5eu_ zaTmV?DhVgE#t-LJ$?&dwa*;6i>_?^)%l^u(*W69f@_Bz52JIw;BW(Gl~ z7`;`E^2#}8XLlS*be&^4fQLBCS9Otv05sq`Jrm;WCN7a8Le*`J2Dy|}sMt;sx4TGn z+6onFBUDOkh9Yibk?OP+Ds?ZRQqiVj=hP2`WZ2oz1_D(|QA%bi8bzaMMWZymMJp*( zD!ckA;?^grPFrazC_;&yaT`leQu;|Gxd~~55eTc*#i>5gckm@uzJ&$1;NCbnKoG@p zqM8FI{rTy4VU>)3&C}O)2j(G4P$5utLl!xv$uUJhA>|>H%!BGoX7QPD!+f<`;qmRX z@WJfeo8Dl$m4rbdmTzSV1)pV;+Rrq7t z{}99EHT9#8?7D}?2@KJE5=!ev8yD(9C9X66GBSUkwJB`eQj%adUq@bio zbyB3HLMl|;)`~(3N-A{^DN;d{=ubNXfsl;tWNkno2%Rb_6$(wEDb2Qvz10aRM8%6R zRTNTCNNH0dAPW_&D{T7Sz^)HRUx_xwX-wSp-u3Sixt+i4JxoW&wRA4f}(t2BjM_ zNr@PS*Z5IiMPT=(W?zJwo$W-J`d;kZ|Fm}9EqxRb&% z1;Bt(kHgf28C+VbWL5+z4rYRxxI+{wKkZ!v0>Tal0)il#Qc5+&E?25o>5vlp z=M5_gDkW8^P|~STK`L%=rBYHAi6B>%Qff2T5v+cDraXM`tFK$e8a6|vlET!j9jq>{Fkj8*^En|4v4n0xCNjx1bL}_C@s`fPA+E_YzmN2AuHH`QH;7eard?0W}!1TPGJ<42t*xfQx@O% z{{B&apX{d?@ia0QZygetm_?dG0uG&2xu6yy>%4lpES+udb?ac5VTNLfDq^aDqDuK* z?(=D$AzmmXVyg5dq*6p1+p}|{r=v${3sRjF(NBr)>|FQZ)Y2BI)LBxbL`n*?Gwod? z5eSIwWeCKaAgEHMU#6>lV@F9fdt-ZcZgoM~S-O?dO$nsp)Ol@3qf#kE5Le!`$$I!S z^*{KDzMV-Fx3$9)?Y`qzN@Tjp^f*BO81#5Hdj6U+xvIr0*PcASOZN8Z(O|66OjV?U zK!r%GF6yqVR@|7oJIG5cVG&d>A+^;RYiF!u9U=IT^SL=I^VMAI(=fgy&2tf!!D5Vm;HDT=OFQ{}< zDd|icn8%H3OM5h>TdDLaq@tofx32i;m>jyb5xKI>hhT2XGa1}G4nMbRuY7;&OgA7l z#vE=ML*AatxeLb&4z5o=fmVlzy;FJ3g|gxjl&^Z5-%n;{RoZjm`4?S{~2;GQ? z>O4-Rh>F;p4(1IzOo#1Kp;G#(RMafdp9j+|JSK;|rJ_isPD-W3_SBtrE`}ut0-+mI zWe5Zz2r(z9HFmh5?2YbpFx~c|>@HNQ6KzVg6Nhd%H(Yd%XeN6b~ z@zwl>4{3=-=ogekN;}GSN7b0frnFmWwb3-gm{;Ls|BStCz}nkl|YV&z=!}b!!cAb z98t%e7r)pYEB8X(za$x^&jqAXv6bfDZ-qDn{(y26}oo?%4 zyLLq6nldw`EY|BkJd@!;KetKQd>|fn8ODxy_massNAPUqs`$c?yD^R{d?F%yISc!wtw=h1Yg3BZDl_93`7q_YSW?2A3Lp$J#wGjicPDH zcGxhChbghb-Z*>Nu&?=*2qgGF#6iI9e?RY-ZTmv3&j6GoS4F%3t>H_ILS2SSqfZ z>mswEtpdy{CbJ346vtc~=NONjS;jHD({YY{$P9I}Z2<>W2LW6abiH`>yRX-$+>F<+ zE?wGQJs(mjqD)jUIWU{$rXNtj5tWLPl8SDc>BQ9;7q=KY4x5D%1*sh=QbF`*(_Nk2 z(c##%$BDc31|epI5TX&gH0oBA6jITj4os}U>WmwL&{p(NLfKn^H0|74qx$74uru)ZC}$WToduUP640$0b5Ye0U(-Xr2YWIR2xhJLga zW+%wFsC%Y|Gh21?@@GD4>r4sSgpXIocxKTqg3`@I+GHt`qtP~7ZCY&(V;C1JA-b>^ zaomg&pNfOEAP5M8z>Hyv^kwFOsRw44!12f4PY&-s{2Nf8K4j>#Gq^(TL`wA5JH3y zCv??yR4Gv@spw9Q$r`M&7@eCN2pr7;rCW$L+S$P}EMr~GSjL`1Hw{AMDiWC~GbtN? z@bKmOKi>0h(=jLJ0-&3v8k~?_G1-ynam%V)eE`_7eBa?8kUc$GhQ+~wsHwkXf{VJ3 zJ@71>&*NnO%ielV4^JLUKEQ;-88WH5v>&6qO_4pPPAgT+5k4%VWTgl zged&&d)Xi&C@*nl*Dlt=Fbv|Dm^d(6Eug`rd6t%l%CUM8=qUOeYz;{yHd6`&(9W`1 zjfj>Ks6Z0@RQ$%cQ_1MHI}5!QU-L=z$@ZIn@h|rW{%#kWZ;iup8!b7fRc(_lgCF1S zbvrO)0&{leFquy#^GPYGY+Fe?qoy-6P`Hw)Drp7?3YZ~)iMyi({5H9dhknivNN%H= zsyb7f3RHsVuVERMcHN9&VJr;YBPdi<3aMyQf!W($7(3QwjAk(`jEzHEx+P^hl@ckU z!nC;ttJ!}n{lM8Cai-U}Yk#$QFtO+49#`&p=DWRGxFRvR#nwcK5CZZxB9+~GUS*<{ zThCUXv}ZMH3!+klY3CZ+b%O#yXb)|rI-8+_Y40*z@fz0H;pj*@;#xBuNT^N_7t9^5y5<);d2YpfjptMyEvehc_lEdHPx%oLBnDp>~ryQ5bz*E0X=iD&iU;0yNBx$qT+X`gZ zf!XY5HeYA*7Xqd%PIh5u{;CN(Oy(2l2o?2tJ3HgC1Zk>fnc^v(v`qP2s9&g#sIJ?zy*Z%6E5Ao7H$+zJ?dk*#9dCQfH{J~f0a-|adhrdK@i4Y+~ z2*fsW%B|UkPjkzaH=Z~7YK^<4qx6I5ujY0Kf?(Jzl|ls-gy_y@4eh#`VfUe}21Q(N zCNi^7RS?-WPaI(FInU$g*N? zP=4F%cE?>*pFV${t=*sZd@_I4WQWOo0#~Q)ut;F+DiI`LLW+aCB^YG~;&hFL^r?y1 zyzuHy73zGVAKeLSSYu&ztg9OqhBcP4acGMail|hmM0Yl{Fj%nw@U|qqmFcyZ* zgNnV8tLSG|6+}SJ%%|v1Zan8qlHXOzmS@QzU!e-rn9`TKssXKotFms2^{FZi`b=37S;A`NPY{Pp1B>-$1j~;^;Zr zuAJlEia8(nxc~o$Rj64kN%@^mpWpg!n7?Ym&I5jA_fyQnIuA?MIpF}ASfZd9ifIHW zLaeb~pPsJQcw&M3_Fi~(XS%tUO6;84HP%>I9qZbMyEYclzs})MtAD2v2+LP z;>KdE0n5N)I;g11mY`D6hS*%q>3__-TF2C z&h?JPU>W*{y@e7Y*O0BYD$JbE_3qo?j>5ywdCp`o8QsUjm6JdHC$hq`+_%^Ay&z7A z(V%=^?_a`Rc6^-skVv-Y5&$z|-J$sOh&6h%lwjI>QTMTz{1$J@-7DY4Ykm6MfB2H` z@o?*C{s?zGhMz9p@35jy&&M;JZs_h%`Y*0n-I&iY8mo~}Z)+;GlK?f%c!x?zFX=j3 z%m%qxASRcCrvbH-uu4WhM>Us|)xqb<%6{`t%37cYcK$T_aX;!uY(fuv_Za}1`-#{O};u~Uf9fC^oDQq}+sk}O-uItBseZ8qmi&F;3!^|#86BWYFK)jGz?fvZg!>`rPL{@REp?MOx-oGELP|07sfKy zuz55Gq->W^X_$@KtO09SE`L~tHP)~O9B|kyQmK?S6>Taon>BiC&oA~)wLK4c{rbz2 zdwY9(_D=Tn?{O%3?>FEc_wL9&1>R!_Go!<9aib zQi2G<-KIQw(Ik<4&U4)B$}6sT;&ph!uVuyO4$`F|(B!G>E^3;;1^KuTkP9~1=K4+sBFV5jBUb!*E09${u!2wVQwR(KOAH^peEe+c$1jjn=oC2)Q||lfy-Hoz zH7nG>W4|Z3@^!)KH=f`9+SfijAn}+V)tf`7fMt(r4IrCDaqW}9(fah%tMNw5GFiE! zaC+apPIjay?HQ0Fx>J8@*I1T?bqg5Qu>0U(azOREfob;|tGWKMhP_8eks_T6M0eU; z9i#V)y{qllfBpLPPj`EO*B;%ow|BC)?*#YVpW1fgo_lyjg*WirtEIh4^0rR#&wo@C zflNqexb?h-z5DL)k%`ma`x_-j-LiXXr=81f4TP9;=pXtOCAw30+PTJZg<~<6p?}ys zP^jh_Q_4(9^@0##+P!DtPr<_v-z)hoys5>M=_r7uSJJfq&{c#0becLVF_lWiwD)4- zv6uW7uf2=)D_{FAFqwyI&$;)3zx88Z`SFR{6!^AI_vd3lU=g!|)kW!_YFk~L-|(3j zF)}uGPRn)@u&rr^p#(JGBqtG~$gDCk1FWcGLop742GdE7mF@@hL3J%ZHawHvM^~e)Yq{ndo?WO4suo>%mH? zrlzLyHvx+!f0byT+7kW?#3eyYnAcd4}sHuXfzZfi=?_$rZ?e*&~|5fq&^{4js*mH6} zj(GPa!}@43W3ZT_d(XWOyN4hDsIk@`dvz_mK;ZN|9pTn*A z@~<9TeiJ%Jhf*TVi*#6XA~q|SUWi8(bv>jkl(~=3=Y4N@5l_D#J_C4;D_5?VcEikQ zbi>}g0MUZrC#=t)th16+vAwX8e96HZXZJ_^9yoUoPw*LU`{>~}f9RFpmz!I7$>z%1 z__V?5d&?8EfJZB8fBsCc2=hbcqG_Lfadl(P2%`oYH^R;ouu}~*%`j{gDC^5{OgtL{ z@ob>HAdX{`jJwE{QFPTdSf_qv_OaPniPBXBy=CW&1VlvLxQ*6*ABM;M6uZmr>KHRx zAHMe0&;Hn#o_5pRsq1;otj}5Z?p55Y;5Px+pELjEf8=l2^uw<|tF;gCTS^n>v~iA{ zD8^EP0|DBHOby6wP>r+X!mxI9)W@F%@z`nMV8ztsD@_jq+ry^ni;??38Y9sl^h%`qvY zv_Z`ZOxv`(Il9!4!(RihgERl`5iZh30zq⪼PdiUJ>3+OS^>Alaf{G)(} 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Μ8R{Dy$lRjHx!!8giiG}J))w?#Jh*0 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 diff --git a/src/dusk/imgui/ImGuiConsole.cpp b/src/dusk/imgui/ImGuiConsole.cpp index a94c7d1f5b..c29ebbac0c 100644 --- a/src/dusk/imgui/ImGuiConsole.cpp +++ b/src/dusk/imgui/ImGuiConsole.cpp @@ -22,6 +22,7 @@ #include "dusk/livesplit.h" #include "dusk/main.h" #include "dusk/settings.h" +#include "dusk/ui/prelaunch_screen.hpp" #include "m_Do/m_Do_controller_pad.h" #include "m_Do/m_Do_main.h" #include "tracy/Tracy.hpp" @@ -339,7 +340,7 @@ namespace dusk { ImGuiMenuGame::ToggleFullscreen(); } - if (!dusk::IsGameLaunched) { + if (!dusk::IsGameLaunched && !dusk::ui::prelaunch::is_active()) { m_preLaunchWindow.draw(); } diff --git a/src/dusk/iso_validate.cpp b/src/dusk/iso_validate.cpp index e83b3fd34e..a4e64c5b70 100644 --- a/src/dusk/iso_validate.cpp +++ b/src/dusk/iso_validate.cpp @@ -101,6 +101,10 @@ ValidationError validate(const char* path) { NodHandleWrapper disc; const auto sdlStream = SDL_IOFromFile(path, "rb"); + if (sdlStream == nullptr) { + return ValidationError::IOError; + } + const NodDiscStream nod_stream { .user_data = sdlStream, .read_at = StreamReadAt, diff --git a/src/dusk/ui/button.cpp b/src/dusk/ui/button.cpp new file mode 100644 index 0000000000..69049dc1bf --- /dev/null +++ b/src/dusk/ui/button.cpp @@ -0,0 +1,160 @@ +#include "button.hpp" + +#include "element.hpp" +#include "focus_border.hpp" +#include "label.hpp" +#include "theme.hpp" + +#include + +#include + +namespace dusk::ui { +namespace { + +theme::Color variant_color(ButtonVariant variant) { + switch (variant) { + case ButtonVariant::Primary: + return theme::Primary; + case ButtonVariant::Secondary: + return theme::Secondary; + case ButtonVariant::Quiet: + default: + return theme::Elevated; + } +} + +} // namespace + +Button::Button(Rml::Element* parent, std::string_view id, std::string_view text, + ButtonVariant variant, std::function pressedCallback) + : m_variant(variant), m_pressedCallback(std::move(pressedCallback)) { + using namespace theme; + + m_element = append(parent, "button", id); + set_props(m_element, { + {"display", "flex"}, + {"position", "relative"}, + {"flex-direction", "row"}, + {"align-items", "center"}, + {"justify-content", "center"}, + {"box-sizing", "border-box"}, + {"width", "100%"}, + {"height", "68dp"}, + {"min-height", "68dp"}, + {"max-height", "68dp"}, + {"padding-left", "22dp"}, + {"padding-right", "22dp"}, + {"border-width", dp(BorderWidth)}, + {"border-radius", dp(BorderRadiusMedium)}, + {"cursor", "pointer"}, + {"tab-index", "auto"}, + {"nav-up", "auto"}, + {"nav-down", "auto"}, + {"nav-left", "auto"}, + {"nav-right", "auto"}, + {"opacity", "1"}, + {"font-family", "Inter"}, + {"color", rgba(Text)}, + }); + + add_focus_border(m_element, BorderRadiusMedium); + m_label = append_text(m_element, "span", text); + apply_label_style(m_label, LabelStyle::Medium); + set_props(m_label, { + {"pointer-events", "none"}, + {"text-align", "center"}, + }); + + m_element->AddEventListener(Rml::EventId::Click, this); + m_element->AddEventListener(Rml::EventId::Focus, this); + m_element->AddEventListener(Rml::EventId::Blur, this); + m_element->AddEventListener(Rml::EventId::Mouseover, this); + m_element->AddEventListener(Rml::EventId::Mouseout, this); + apply_style(); +} + +Button::~Button() { + if (m_element == nullptr) { + return; + } + + m_element->RemoveEventListener(Rml::EventId::Click, this); + m_element->RemoveEventListener(Rml::EventId::Focus, this); + m_element->RemoveEventListener(Rml::EventId::Blur, this); + m_element->RemoveEventListener(Rml::EventId::Mouseover, this); + m_element->RemoveEventListener(Rml::EventId::Mouseout, this); + m_element = nullptr; +} + +void Button::ProcessEvent(Rml::Event& event) { + switch (event.GetId()) { + case Rml::EventId::Click: + if (m_pressedCallback) { + m_pressedCallback(); + } + break; + case Rml::EventId::Focus: + m_focused = true; + apply_style(); + break; + case Rml::EventId::Blur: + m_focused = false; + apply_style(); + break; + case Rml::EventId::Mouseover: + m_focused = true; + apply_style(); + break; + case Rml::EventId::Mouseout: + m_focused = false; + apply_style(); + break; + default: + break; + } +} + +Rml::Element* Button::element() const { + return m_element; +} + +std::string Button::id() const { + return m_element == nullptr ? std::string{} : m_element->GetId(); +} + +void Button::set_text(std::string_view text) { + ui::set_text(m_label, text); +} + +void Button::apply_style() { + using namespace theme; + + if (m_element == nullptr) { + return; + } + + const bool active = m_hovered || m_focused; + const bool isBasic = m_variant == ButtonVariant::Quiet; + const Color color = variant_color(m_variant); + + int borderOpacity = isBasic ? 0 : 190; + int backgroundOpacity = isBasic ? 0 : 28; + int backgroundHoverOpacity = 116; + int borderHoverOpacity = isBasic ? backgroundHoverOpacity : 255; + + if (m_variant == ButtonVariant::Quiet) { + backgroundHoverOpacity = 68; + borderHoverOpacity = 150; + } + + m_element->SetProperty("border-color", + rgba(color, active ? borderHoverOpacity : borderOpacity)); + m_element->SetProperty("background-color", + rgba(color, active ? backgroundHoverOpacity : backgroundOpacity)); + m_element->SetProperty("color", rgba(active ? TextActive : Text)); + m_label->SetProperty("color", rgba(active ? TextActive : Text)); + set_focus_border_visible(m_element, m_focused); +} + +} // namespace dusk::ui diff --git a/src/dusk/ui/button.hpp b/src/dusk/ui/button.hpp new file mode 100644 index 0000000000..c60e2a0c8d --- /dev/null +++ b/src/dusk/ui/button.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include + +#include +#include +#include + +namespace Rml { +class Element; +} + +namespace dusk::ui { + +enum class ButtonVariant { + Primary, + Secondary, + Quiet, +}; + +class Button : public Rml::EventListener { +public: + Button(Rml::Element* parent, std::string_view id, std::string_view text, ButtonVariant variant, + std::function pressedCallback); + ~Button() override; + + Button(const Button&) = delete; + Button& operator=(const Button&) = delete; + + void ProcessEvent(Rml::Event& event) override; + + Rml::Element* element() const; + std::string id() const; + void set_text(std::string_view text); + +private: + Rml::Element* m_element = nullptr; + Rml::Element* m_label = nullptr; + ButtonVariant m_variant = ButtonVariant::Secondary; + std::function m_pressedCallback; + bool m_hovered = false; + bool m_focused = false; + + void apply_style(); +}; + +} // namespace dusk::ui diff --git a/src/dusk/ui/disc_state.cpp b/src/dusk/ui/disc_state.cpp new file mode 100644 index 0000000000..c550b4c97c --- /dev/null +++ b/src/dusk/ui/disc_state.cpp @@ -0,0 +1,133 @@ +#include "disc_state.hpp" + +#include "element.hpp" +#include "focus_border.hpp" +#include "label.hpp" +#include "theme.hpp" + +#include + +#include + +namespace dusk::ui { + +DiscState::DiscState(Rml::Element* parent, std::string_view id, std::string_view text, bool error, + std::function pressedCallback) + : m_pressedCallback(std::move(pressedCallback)), m_error(error) { + using namespace theme; + + m_element = append(parent, "button", id); + set_props(m_element, { + {"display", "flex"}, + {"position", "relative"}, + {"flex-direction", "column"}, + {"align-items", "stretch"}, + {"gap", "6dp"}, + {"width", "100%"}, + {"box-sizing", "border-box"}, + {"padding", "14dp 16dp"}, + {"border-width", dp(BorderWidth)}, + {"border-radius", dp(BorderRadiusSmall)}, + {"cursor", "pointer"}, + {"tab-index", "auto"}, + {"nav-up", "auto"}, + {"nav-down", "auto"}, + {"nav-left", "auto"}, + {"nav-right", "auto"}, + {"font-family", "Inter"}, + }); + + add_focus_border(m_element, BorderRadiusSmall); + + m_label = add_label(m_element, error ? "Disc Error" : "Selected Disc", LabelStyle::Annotation); + set_props(m_label, { + {"pointer-events", "none"}, + }); + + m_value = add_label(m_element, text, LabelStyle::Body); + set_props(m_value, { + {"overflow", "hidden"}, + {"text-overflow", "ellipsis"}, + {"white-space", "nowrap"}, + {"pointer-events", "none"}, + }); + + m_element->AddEventListener(Rml::EventId::Click, this); + m_element->AddEventListener(Rml::EventId::Focus, this); + m_element->AddEventListener(Rml::EventId::Blur, this); + m_element->AddEventListener(Rml::EventId::Mouseover, this); + m_element->AddEventListener(Rml::EventId::Mouseout, this); + apply_style(); +} + +DiscState::~DiscState() { + if (m_element == nullptr) { + return; + } + + m_element->RemoveEventListener(Rml::EventId::Click, this); + m_element->RemoveEventListener(Rml::EventId::Focus, this); + m_element->RemoveEventListener(Rml::EventId::Blur, this); + m_element->RemoveEventListener(Rml::EventId::Mouseover, this); + m_element->RemoveEventListener(Rml::EventId::Mouseout, this); + m_element = nullptr; +} + +void DiscState::ProcessEvent(Rml::Event& event) { + switch (event.GetId()) { + case Rml::EventId::Click: + if (m_pressedCallback) { + m_pressedCallback(); + } + break; + case Rml::EventId::Focus: + m_focused = true; + apply_style(); + break; + case Rml::EventId::Blur: + m_focused = false; + apply_style(); + break; + case Rml::EventId::Mouseover: + m_hovered = true; + apply_style(); + break; + case Rml::EventId::Mouseout: + m_hovered = false; + apply_style(); + break; + default: + break; + } +} + +Rml::Element* DiscState::element() const { + return m_element; +} + +std::string DiscState::id() const { + return m_element == nullptr ? std::string{} : m_element->GetId(); +} + +void DiscState::apply_style() { + using namespace theme; + + if (m_element == nullptr) { + return; + } + + const bool active = m_hovered || m_focused; + const Color accent = m_error ? Danger : Primary; + + m_element->SetProperty("background-color", rgba(accent, active ? 52 : (m_error ? 32 : 20))); + m_element->SetProperty("border-color", rgba(accent, active ? 220 : (m_error ? 190 : 120))); + m_element->SetProperty("color", rgba(active ? TextActive : Text)); + + m_label->SetProperty("color", rgba(m_error ? Danger : (active ? TextActive : TextDim), + m_error ? 220 : (active ? TextActive.a : TextDim.a))); + m_value->SetProperty("color", rgba(m_error ? Danger : (active ? TextActive : Text), + m_error ? 255 : (active ? TextActive.a : Text.a))); + set_focus_border_visible(m_element, m_focused); +} + +} // namespace dusk::ui diff --git a/src/dusk/ui/disc_state.hpp b/src/dusk/ui/disc_state.hpp new file mode 100644 index 0000000000..bc069482ae --- /dev/null +++ b/src/dusk/ui/disc_state.hpp @@ -0,0 +1,41 @@ +#pragma once + +#include + +#include +#include +#include + +namespace Rml { +class Element; +} + +namespace dusk::ui { + +class DiscState : public Rml::EventListener { +public: + DiscState(Rml::Element* parent, std::string_view id, std::string_view text, bool error, + std::function pressedCallback); + ~DiscState() override; + + DiscState(const DiscState&) = delete; + DiscState& operator=(const DiscState&) = delete; + + void ProcessEvent(Rml::Event& event) override; + + Rml::Element* element() const; + std::string id() const; + +private: + Rml::Element* m_element = nullptr; + Rml::Element* m_label = nullptr; + Rml::Element* m_value = nullptr; + std::function m_pressedCallback; + bool m_error = false; + bool m_hovered = false; + bool m_focused = false; + + void apply_style(); +}; + +} // namespace dusk::ui diff --git a/src/dusk/ui/element.cpp b/src/dusk/ui/element.cpp new file mode 100644 index 0000000000..c74ad74755 --- /dev/null +++ b/src/dusk/ui/element.cpp @@ -0,0 +1,81 @@ +#include "element.hpp" + +#include + +#include + +namespace dusk::ui { + +std::string escape(std::string_view text) { + std::string result; + result.reserve(text.size()); + for (char c : text) { + switch (c) { + case '&': + result += "&"; + break; + case '<': + result += "<"; + break; + case '>': + result += ">"; + break; + case '"': + result += """; + break; + case '\'': + result += "'"; + break; + default: + result += c; + break; + } + } + return result; +} + +Rml::Element* append(Rml::Element* parent, std::string_view tag, std::string_view id) { + if (parent == nullptr) { + return nullptr; + } + + Rml::ElementDocument* document = parent->GetOwnerDocument(); + if (document == nullptr) { + document = dynamic_cast(parent); + } + if (document == nullptr) { + return nullptr; + } + + Rml::ElementPtr child = document->CreateElement(std::string(tag)); + Rml::Element* rawChild = child.get(); + if (!id.empty()) { + rawChild->SetId(std::string(id)); + } + return parent->AppendChild(std::move(child)); +} + +Rml::Element* append_text(Rml::Element* parent, std::string_view tag, std::string_view text, + std::string_view id) { + Rml::Element* element = append(parent, tag, id); + set_text(element, text); + return element; +} + +void set_text(Rml::Element* element, std::string_view text) { + if (element != nullptr) { + element->SetInnerRML(escape(text)); + } +} + +void set_props(Rml::Element* element, + std::initializer_list > properties) { + if (element == nullptr) { + return; + } + for (const auto& [name, value] : properties) { + element->SetProperty(std::string(name), std::string(value)); + } +} + +} // namespace dusk::ui diff --git a/src/dusk/ui/element.hpp b/src/dusk/ui/element.hpp new file mode 100644 index 0000000000..9d28471bce --- /dev/null +++ b/src/dusk/ui/element.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include + +#include +#include + +namespace dusk::ui { + +std::string escape(std::string_view text); +Rml::Element* append(Rml::Element* parent, std::string_view tag, std::string_view id = {}); +Rml::Element* append_text(Rml::Element* parent, std::string_view tag, std::string_view text, + std::string_view id = {}); +void set_text(Rml::Element* element, std::string_view text); +void set_props(Rml::Element* element, + std::initializer_list > properties); + +} // namespace dusk::ui diff --git a/src/dusk/ui/focus_border.cpp b/src/dusk/ui/focus_border.cpp new file mode 100644 index 0000000000..8fc474f956 --- /dev/null +++ b/src/dusk/ui/focus_border.cpp @@ -0,0 +1,36 @@ +#include "focus_border.hpp" + +#include "element.hpp" +#include "theme.hpp" + +namespace dusk::ui { + +Rml::Element* add_focus_border(Rml::Element* parent, float radius) { + using namespace theme; + + auto* border = append(parent, "div"); + set_props(border, { + {"position", "absolute"}, + {"pointer-events", "none"}, + {"left", dp(-(BorderWidth * 3.0f))}, + {"top", dp(-(BorderWidth * 3.0f))}, + {"right", dp(-(BorderWidth * 3.0f))}, + {"bottom", dp(-(BorderWidth * 3.0f))}, + {"border-width", dp(BorderWidth * 2.0f)}, + {"border-radius", dp(radius + BorderWidth * 4.0f)}, + {"border-color", rgba(PrimaryLight, 0)}, + }); + return border; +} + +void set_focus_border_visible(Rml::Element* parent, bool visible) { + if (parent == nullptr || parent->GetNumChildren() == 0) { + return; + } + + parent->GetChild(0)->SetProperty("border-color", visible ? + theme::rgba(theme::PrimaryLight, 255) : + theme::rgba(theme::PrimaryLight, 0)); +} + +} // namespace dusk::ui diff --git a/src/dusk/ui/focus_border.hpp b/src/dusk/ui/focus_border.hpp new file mode 100644 index 0000000000..79bc315bbd --- /dev/null +++ b/src/dusk/ui/focus_border.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include + +namespace dusk::ui { + +Rml::Element* add_focus_border(Rml::Element* parent, float radius); +void set_focus_border_visible(Rml::Element* parent, bool visible); + +} // namespace dusk::ui diff --git a/src/dusk/ui/game_option.cpp b/src/dusk/ui/game_option.cpp new file mode 100644 index 0000000000..2ada2374d9 --- /dev/null +++ b/src/dusk/ui/game_option.cpp @@ -0,0 +1,187 @@ +#include "game_option.hpp" + +#include "element.hpp" +#include "focus_border.hpp" +#include "label.hpp" +#include "theme.hpp" + +#include + +#include + +namespace dusk::ui { + +GameOption::GameOption(Rml::Element* parent, std::string_view id, std::string_view title, + std::string_view value, std::string_view detail, + std::function pressedCallback) + : m_pressedCallback(std::move(pressedCallback)) { + using namespace theme; + + m_element = append(parent, "button", id); + set_props(m_element, { + {"display", "flex"}, + {"position", "relative"}, + {"flex-direction", "row"}, + {"align-items", "center"}, + {"justify-content", "space-between"}, + {"box-sizing", "border-box"}, + {"gap", "16dp"}, + {"width", "100%"}, + {"height", "auto"}, + {"padding", "16dp"}, + {"border-width", dp(BorderWidth)}, + {"border-radius", dp(BorderRadiusSmall)}, + {"background-color", rgba(Transparent)}, + {"border-color", rgba(ElevatedBorder, 0)}, + {"color", rgba(TextDim)}, + {"cursor", "pointer"}, + {"tab-index", "auto"}, + {"nav-up", "auto"}, + {"nav-down", "auto"}, + {"nav-left", "auto"}, + {"nav-right", "auto"}, + {"opacity", "1"}, + {"font-family", "Inter"}, + }); + + add_focus_border(m_element, BorderRadiusSmall); + + auto* left = append(m_element, "div"); + set_props(left, { + {"display", "flex"}, + {"flex-direction", "column"}, + {"gap", "4dp"}, + {"min-width", "0"}, + {"width", "0"}, + {"flex-grow", "1"}, + {"flex-shrink", "1"}, + {"pointer-events", "none"}, + }); + + m_title = add_label(left, title, LabelStyle::Large); + set_props(m_title, { + {"color", rgba(TextDim)}, + {"font-size", "28dp"}, + {"letter-spacing", "1dp"}, + }); + + if (!value.empty() || !detail.empty()) { + auto* right = append(m_element, "div"); + set_props(right, { + {"display", "flex"}, + {"flex-direction", "column"}, + {"align-items", "flex-end"}, + {"justify-content", "center"}, + {"gap", "4dp"}, + {"min-width", "170dp"}, + {"max-width", "48%"}, + {"flex-shrink", "0"}, + {"pointer-events", "none"}, + }); + + if (!value.empty()) { + m_value = add_label(right, value, LabelStyle::Body); + set_props(m_value, { + {"color", rgba(TextDim)}, + {"text-align", "right"}, + {"overflow", "hidden"}, + {"text-overflow", "ellipsis"}, + {"white-space", "nowrap"}, + }); + } + + if (!detail.empty()) { + m_detail = add_label(right, detail, LabelStyle::Annotation); + set_props(m_detail, { + {"color", rgba(TextDim)}, + {"text-align", "right"}, + }); + } + } + + m_element->AddEventListener(Rml::EventId::Click, this); + m_element->AddEventListener(Rml::EventId::Focus, this); + m_element->AddEventListener(Rml::EventId::Blur, this); + m_element->AddEventListener(Rml::EventId::Mouseover, this); + m_element->AddEventListener(Rml::EventId::Mouseout, this); + apply_style(); +} + +GameOption::~GameOption() { + if (m_element == nullptr) { + return; + } + + m_element->RemoveEventListener(Rml::EventId::Click, this); + m_element->RemoveEventListener(Rml::EventId::Focus, this); + m_element->RemoveEventListener(Rml::EventId::Blur, this); + m_element->RemoveEventListener(Rml::EventId::Mouseover, this); + m_element->RemoveEventListener(Rml::EventId::Mouseout, this); + m_element = nullptr; +} + +void GameOption::ProcessEvent(Rml::Event& event) { + switch (event.GetId()) { + case Rml::EventId::Click: + if (m_pressedCallback) { + m_pressedCallback(); + } + break; + case Rml::EventId::Focus: + m_focused = true; + apply_style(); + break; + case Rml::EventId::Blur: + m_focused = false; + apply_style(); + break; + case Rml::EventId::Mouseover: + m_hovered = true; + apply_style(); + break; + case Rml::EventId::Mouseout: + m_hovered = false; + apply_style(); + break; + default: + break; + } +} + +Rml::Element* GameOption::element() const { + return m_element; +} + +std::string GameOption::id() const { + return m_element == nullptr ? std::string{} : m_element->GetId(); +} + +void GameOption::set_value(std::string_view value) { + set_text(m_value, value); +} + +void GameOption::apply_style() { + if (m_element == nullptr) { + return; + } + + const bool active = m_hovered || m_focused; + m_element->SetProperty("background-color", active ? theme::rgba(theme::Primary, 52) : + theme::rgba(theme::Primary, 0)); + m_element->SetProperty("border-color", active ? theme::rgba(theme::Primary, 220) : + theme::rgba(theme::ElevatedBorder, 42)); + m_element->SetProperty("color", + active ? theme::rgba(theme::TextActive) : theme::rgba(theme::TextDim)); + m_title->SetProperty("color", + active ? theme::rgba(theme::TextActive) : theme::rgba(theme::TextDim)); + if (m_value != nullptr) { + m_value->SetProperty("color", + active ? theme::rgba(theme::TextActive) : theme::rgba(theme::TextDim)); + } + if (m_detail != nullptr) { + m_detail->SetProperty("color", theme::rgba(theme::TextDim)); + } + set_focus_border_visible(m_element, m_focused); +} + +} // namespace dusk::ui diff --git a/src/dusk/ui/game_option.hpp b/src/dusk/ui/game_option.hpp new file mode 100644 index 0000000000..a8ae5c20b8 --- /dev/null +++ b/src/dusk/ui/game_option.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include + +#include +#include +#include + +namespace Rml { +class Element; +} + +namespace dusk::ui { + +class GameOption : public Rml::EventListener { +public: + GameOption(Rml::Element* parent, std::string_view id, std::string_view title, + std::string_view value, std::string_view detail, + std::function pressedCallback); + ~GameOption() override; + + GameOption(const GameOption&) = delete; + GameOption& operator=(const GameOption&) = delete; + + void ProcessEvent(Rml::Event& event) override; + + Rml::Element* element() const; + std::string id() const; + void set_value(std::string_view value); + +private: + Rml::Element* m_element = nullptr; + Rml::Element* m_title = nullptr; + Rml::Element* m_value = nullptr; + Rml::Element* m_detail = nullptr; + std::function m_pressedCallback; + bool m_hovered = false; + bool m_focused = false; + + void apply_style(); +}; + +} // namespace dusk::ui diff --git a/src/dusk/ui/label.cpp b/src/dusk/ui/label.cpp new file mode 100644 index 0000000000..ca8ce3d4af --- /dev/null +++ b/src/dusk/ui/label.cpp @@ -0,0 +1,45 @@ +#include "label.hpp" + +#include "element.hpp" +#include "theme.hpp" + +namespace dusk::ui { + +void apply_label_style(Rml::Element* element, LabelStyle style) { + using namespace theme; + + switch (style) { + case LabelStyle::Annotation: + set_props(element, {{"font-size", "18dp"}, + {"letter-spacing", "2dp"}, + {"font-weight", "400"}, + {"color", rgba(TextDim)}}); + break; + case LabelStyle::Body: + set_props(element, {{"font-size", "20dp"}, + {"letter-spacing", "0"}, + {"font-weight", "400"}, + {"color", rgba(Text)}}); + break; + case LabelStyle::Medium: + set_props(element, {{"font-size", "28dp"}, + {"letter-spacing", "3dp"}, + {"font-weight", "700"}, + {"color", rgba(Text)}}); + break; + case LabelStyle::Large: + set_props(element, {{"font-size", "36dp"}, + {"letter-spacing", "4dp"}, + {"font-weight", "700"}, + {"color", rgba(Text)}}); + break; + } +} + +Rml::Element* add_label(Rml::Element* parent, std::string_view text, LabelStyle style) { + Rml::Element* label = append_text(parent, "div", text); + apply_label_style(label, style); + return label; +} + +} // namespace dusk::ui diff --git a/src/dusk/ui/label.hpp b/src/dusk/ui/label.hpp new file mode 100644 index 0000000000..fb23ad408f --- /dev/null +++ b/src/dusk/ui/label.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include + +#include + +namespace dusk::ui { + +enum class LabelStyle { + Annotation, + Body, + Medium, + Large, +}; + +Rml::Element* add_label(Rml::Element* parent, std::string_view text, LabelStyle style); +void apply_label_style(Rml::Element* element, LabelStyle style); + +} // namespace dusk::ui diff --git a/src/dusk/ui/prelaunch_layout.cpp b/src/dusk/ui/prelaunch_layout.cpp new file mode 100644 index 0000000000..c5c6ff9dc7 --- /dev/null +++ b/src/dusk/ui/prelaunch_layout.cpp @@ -0,0 +1,113 @@ +#include "prelaunch_layout.hpp" + +#include "element.hpp" +#include "label.hpp" +#include "theme.hpp" + +namespace dusk::ui::prelaunch::layout { + +void style_document(Rml::ElementDocument* document) { + using namespace theme; + + set_props(document, { + {"width", "100%"}, + {"height", "100%"}, + {"margin", "0"}, + {"padding", "0"}, + {"font-family", "Inter"}, + {"background-color", rgba(Background1)}, + {"color", rgba(Text)}, + }); +} + +Rml::Element* add_screen(Rml::ElementDocument* document, ScreenLayout layout) { + using namespace theme; + + auto* screen = append(document, "div", "prelaunch-screen"); + set_props(screen, + { + {"display", "flex"}, + {"position", "absolute"}, + {"left", "0"}, + {"top", "0"}, + {"right", "0"}, + {"bottom", "0"}, + {"flex-direction", layout == ScreenLayout::CompactSplit ? "row" : "column"}, + {"align-items", "center"}, + {"justify-content", "center"}, + {"gap", layout == ScreenLayout::CompactSplit ? "28dp" : "24dp"}, + {"box-sizing", "border-box"}, + {"padding", layout == ScreenLayout::CompactSplit ? "24dp" : "48dp 28dp"}, + {"background-color", rgba(Background1)}, + }); + return screen; +} + +Rml::Element* add_brand(Rml::Element* parent, std::string_view logoPath, bool compact) { + auto* brand = append(parent, "div"); + set_props(brand, { + {"display", "flex"}, + {"flex-direction", "column"}, + {"align-items", "center"}, + {"justify-content", "center"}, + {"gap", compact ? "8dp" : "12dp"}, + {"width", compact ? "260dp" : "100%"}, + {"max-width", compact ? "32%" : "720dp"}, + {"flex-shrink", compact ? "0" : "1"}, + }); + + auto* subtitle = add_label(brand, "Twilit Realm presents", LabelStyle::Annotation); + set_props(subtitle, { + {"text-align", "center"}, + {"font-size", compact ? "14dp" : "18dp"}, + }); + + if (!logoPath.empty()) { + auto* logo = append(brand, "img"); + logo->SetAttribute("src", std::string(logoPath)); + set_props(logo, { + {"width", compact ? "220dp" : "360dp"}, + {"max-width", compact ? "100%" : "70%"}, + {"height", "auto"}, + }); + } else { + auto* title = add_label(brand, "Dusk", LabelStyle::Large); + set_props(title, { + {"font-size", compact ? "42dp" : "54dp"}, + {"letter-spacing", compact ? "3dp" : "4dp"}, + }); + } + return brand; +} + +Rml::Element* add_heading(Rml::Element* parent, std::string_view title) { + auto* heading = add_label(parent, title, LabelStyle::Large); + set_props(heading, { + {"width", "100%"}, + {"max-width", "840dp"}, + {"text-align", "left"}, + }); + return heading; +} + +Rml::Element* add_panel(Rml::Element* parent, bool wide, bool compact) { + using namespace theme; + + auto* panel = append(parent, "div"); + set_props(panel, { + {"display", "flex"}, + {"flex-direction", "column"}, + {"gap", "12dp"}, + {"width", wide ? "840dp" : "520dp"}, + {"max-width", compact ? "62%" : "100%"}, + {"box-sizing", "border-box"}, + {"padding", compact ? "16dp" : "20dp"}, + {"border-width", dp(BorderWidth)}, + {"border-radius", dp(BorderRadiusMedium)}, + {"border-color", rgba(ElevatedBorder, ElevatedBorder.a)}, + {"background-color", rgba(ElevatedSoft, ElevatedSoft.a)}, + }); + return panel; +} + +} // namespace dusk::ui::prelaunch::layout diff --git a/src/dusk/ui/prelaunch_layout.hpp b/src/dusk/ui/prelaunch_layout.hpp new file mode 100644 index 0000000000..c43136a787 --- /dev/null +++ b/src/dusk/ui/prelaunch_layout.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include +#include + +#include + +namespace dusk::ui::prelaunch::layout { + +enum class ScreenLayout { + Standard, + CompactSplit, +}; + +void style_document(Rml::ElementDocument* document); +Rml::Element* add_screen(Rml::ElementDocument* document, + ScreenLayout layout = ScreenLayout::Standard); +Rml::Element* add_brand(Rml::Element* parent, std::string_view logoPath, bool compact = false); +Rml::Element* add_heading(Rml::Element* parent, std::string_view title); +Rml::Element* add_panel(Rml::Element* parent, bool wide, bool compact = false); + +} // namespace dusk::ui::prelaunch::layout diff --git a/src/dusk/ui/prelaunch_screen.cpp b/src/dusk/ui/prelaunch_screen.cpp new file mode 100644 index 0000000000..3bc2a85865 --- /dev/null +++ b/src/dusk/ui/prelaunch_screen.cpp @@ -0,0 +1,924 @@ +#include "prelaunch_screen.hpp" + +#include "button.hpp" +#include "disc_state.hpp" +#include "game_option.hpp" +#include "prelaunch_layout.hpp" +#include "ui.hpp" + +#include "../file_select.hpp" +#include "../iso_validate.hpp" +#include "dusk/config.hpp" +#include "dusk/main.h" +#include "dusk/settings.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "aurora/lib/window.hpp" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace dusk::ui::prelaunch { +namespace { + +enum class View { + Main, + Options, + LanguageSelect, + GraphicsBackendSelect, + SaveFileTypeSelect, +}; + +struct BackendChoice { + AuroraBackend backend = BACKEND_AUTO; + std::string id; + std::string name; +}; + +constexpr std::array kLanguageNames = { + "English", "German", "French", "Spanish", "Italian", +}; + +constexpr std::array kGameDiscFileFilters{{ + {"Game Disc Images", "iso;gcm;ciso;gcz;nfs;rvz;wbfs;wia;tgc"}, + {"All Files", "*"}, +}}; + +std::string iso_validation_error_message(iso::ValidationError code) { + switch (code) { + case iso::ValidationError::IOError: + return "Unable to read selected disc image"; + case iso::ValidationError::InvalidImage: + return "Unable to interpret selected file as a disc image"; + case iso::ValidationError::WrongGame: + return "Selected disc is for a different game"; + case iso::ValidationError::WrongVersion: + return "Selected disc is for an unsupported version. Only NTSC & PAL GameCube are " + "supported at this time"; + case iso::ValidationError::ExecutableMismatch: + return "Selected disc image contains modified executable files."; + case iso::ValidationError::Success: + return {}; + case iso::ValidationError::Unknown: + default: + return "Unknown disc image validation error"; + } +} + +std::string_view backend_name(AuroraBackend backend) { + switch (backend) { + default: + return "Auto"; + case BACKEND_D3D12: + return "D3D12"; + case BACKEND_D3D11: + return "D3D11"; + case BACKEND_METAL: + return "Metal"; + case BACKEND_VULKAN: + return "Vulkan"; + case BACKEND_OPENGL: + return "OpenGL"; + case BACKEND_OPENGLES: + return "OpenGL ES"; + case BACKEND_WEBGPU: + return "WebGPU"; + case BACKEND_NULL: + return "Null"; + } +} + +std::string_view backend_id(AuroraBackend backend) { + switch (backend) { + default: + return "auto"; + case BACKEND_D3D12: + return "d3d12"; + case BACKEND_D3D11: + return "d3d11"; + case BACKEND_METAL: + return "metal"; + case BACKEND_VULKAN: + return "vulkan"; + case BACKEND_OPENGL: + return "opengl"; + case BACKEND_OPENGLES: + return "opengles"; + case BACKEND_WEBGPU: + return "webgpu"; + case BACKEND_NULL: + return "null"; + } +} + +bool try_parse_backend(std::string_view backend, AuroraBackend& outBackend) { + if (backend == "auto") { + outBackend = BACKEND_AUTO; + return true; + } + if (backend == "d3d11") { + outBackend = BACKEND_D3D11; + return true; + } + if (backend == "d3d12") { + outBackend = BACKEND_D3D12; + return true; + } + if (backend == "metal") { + outBackend = BACKEND_METAL; + return true; + } + if (backend == "vulkan") { + outBackend = BACKEND_VULKAN; + return true; + } + if (backend == "opengl") { + outBackend = BACKEND_OPENGL; + return true; + } + if (backend == "opengles") { + outBackend = BACKEND_OPENGLES; + return true; + } + if (backend == "webgpu") { + outBackend = BACKEND_WEBGPU; + return true; + } + if (backend == "null") { + outBackend = BACKEND_NULL; + return true; + } + return false; +} + +std::string_view card_type_name(CARDFileType type) { + switch (type) { + case CARD_GCIFOLDER: + return "GCI Folder"; + case CARD_RAWIMAGE: + return "Card Image"; + default: + return ""; + } +} + +std::filesystem::path resource_path(const char* filename) { + const char* basePath = SDL_GetBasePath(); + if (basePath == nullptr) { + return std::filesystem::path("res") / filename; + } + return std::filesystem::path(basePath) / "res" / filename; +} + +std::string display_path(std::string_view path) { + const char* home = SDL_GetUserFolder(SDL_FOLDER_HOME); + if (home == nullptr || home[0] == '\0') { + home = std::getenv("HOME"); + } + if (home == nullptr || home[0] == '\0') { + return std::string(path); + } + + std::string homePath(home); + while (homePath.size() > 1 && homePath.back() == '/') { + homePath.pop_back(); + } + + if (path == homePath) { + return "~"; + } + + if (path.size() > homePath.size() && path.substr(0, homePath.size()) == homePath && + path[homePath.size()] == '/') + { + return "~" + std::string(path.substr(homePath.size())); + } + + return std::string(path); +} + +std::vector backend_choices() { + std::vector choices; + choices.push_back({BACKEND_AUTO, std::string(backend_id(BACKEND_AUTO)), + std::string(backend_name(BACKEND_AUTO))}); + + size_t backendCount = 0; + const AuroraBackend* availableBackends = aurora_get_available_backends(&backendCount); + for (size_t i = 0; i < backendCount; ++i) { + const AuroraBackend backend = availableBackends[i]; + choices.push_back( + {backend, std::string(backend_id(backend)), std::string(backend_name(backend))}); + } + + return choices; +} + +class Screen : public Rml::EventListener { +public: + bool initialize() { + if (m_initialized) { + return true; + } + if (!ui::initialize()) { + return false; + } + + m_selectedIsoPath = getSettings().backend.isoPath.getValue(); + validate_selected_iso(false); + m_initialGraphicsBackend = getSettings().backend.graphicsBackend.getValue(); + m_initialized = true; + + if (is_selected_path_valid() && getSettings().backend.skipPreLaunchUI.getValue()) { + IsGameLaunched = true; + return true; + } + + set_active(true); + rebuild(); + if (m_document == nullptr) { + shutdown(); + return false; + } + return true; + } + + void shutdown() { + close_document(); + set_active(false); + m_initialized = false; + m_focusIds.clear(); + } + + bool is_active() const { return m_initialized && ui::is_active(); } + + void handle_event(const SDL_Event& event) { ui::handle_event(event); } + + void update() { + if (m_requestedBack) { + m_requestedBack = false; + back(); + if (!is_active()) { + return; + } + } + + if (!m_requestedActivation.empty()) { + const std::string requestedActivation = m_requestedActivation; + m_requestedActivation.clear(); + activate(requestedActivation); + if (!is_active()) { + return; + } + } + + if (m_requestedCycleDirection != 0) { + const std::string requestedCycleId = m_requestedCycleId; + const int requestedCycleDirection = m_requestedCycleDirection; + m_requestedCycleId.clear(); + m_requestedCycleDirection = 0; + cycle_option(requestedCycleId, requestedCycleDirection); + if (!is_active()) { + return; + } + } + + if (is_selected_path_valid() && getSettings().backend.skipPreLaunchUI.getValue()) { + IsGameLaunched = true; + shutdown(); + return; + } + + ui::update(); + rebuild_if_layout_changed(); + } + + void ProcessEvent(Rml::Event& event) override { + if (event.GetId() == Rml::EventId::Keydown) { + const auto key = static_cast( + event.GetParameter("key_identifier", Rml::Input::KI_UNKNOWN)); + if (handle_key(key)) { + event.StopImmediatePropagation(); + } + } + } + +private: + bool m_initialized = false; + View m_view = View::Main; + Rml::ElementDocument* m_document = nullptr; + std::vector m_focusIds; + std::vector > m_buttons; + std::unique_ptr m_discState; + std::vector > m_options; + std::string m_pendingFocusId; + std::string m_requestedActivation; + std::string m_requestedCycleId; + int m_requestedCycleDirection = 0; + bool m_requestedBack = false; + std::string m_selectedIsoPath; + std::string m_errorString; + std::string m_initialGraphicsBackend; + bool m_compactLayout = false; + bool m_selectedIsoValid = false; + bool m_isPal = false; + + bool selected_path_exists() const { +#if TARGET_ANDROID + return !m_selectedIsoPath.empty(); +#else + return !m_selectedIsoPath.empty() && SDL_GetPathInfo(m_selectedIsoPath.c_str(), nullptr); +#endif + } + + bool is_selected_path_valid() const { return m_selectedIsoValid; } + + void validate_selected_iso(bool save_valid_path) { + m_errorString.clear(); + m_selectedIsoValid = false; + m_isPal = false; + + if (m_selectedIsoPath.empty()) { + return; + } + + if (!selected_path_exists()) { + m_errorString = "Selected disc image does not exist"; + return; + } + + const iso::ValidationError validationResult = iso::validate(m_selectedIsoPath.c_str()); + if (validationResult != iso::ValidationError::Success) { + m_errorString = iso_validation_error_message(validationResult); + return; + } + + m_selectedIsoValid = true; + m_isPal = iso::isPal(m_selectedIsoPath.c_str()); + if (save_valid_path) { + getSettings().backend.isoPath.setValue(m_selectedIsoPath); + Save(); + } + } + + void close_document() { + if (m_document == nullptr) { + return; + } + + m_document->RemoveEventListener(Rml::EventId::Keydown, this); + m_buttons.clear(); + m_discState.reset(); + m_options.clear(); + m_focusIds.clear(); + m_document->Close(); + m_document = nullptr; + } + + std::string logo_path() const { + const auto logo_path = resource_path("logo-mascot.png"); + if (std::filesystem::exists(logo_path)) { + return logo_path.string(); + } + + return {}; + } + + std::string disc_state_text() const { + if (!m_errorString.empty()) { + return m_errorString; + } + + if (is_selected_path_valid()) { + return display_path(m_selectedIsoPath); + } + + return "No disc image selected"; + } + + bool should_use_compact_layout() const { + Rml::Context* context = aurora::rmlui::get_context(); + if (context == nullptr) { + return false; + } + + const Rml::Vector2i dimensions = context->GetDimensions(); + float dp_ratio = context->GetDensityIndependentPixelRatio(); + if (dp_ratio <= 0.0f) { + dp_ratio = 1.0f; + } + + const float width = static_cast(dimensions.x) / dp_ratio; + const float height = static_cast(dimensions.y) / dp_ratio; + return height < 680.0f && width >= 720.0f; + } + + void rebuild_if_layout_changed() { + const bool compactLayout = should_use_compact_layout(); + if (compactLayout == m_compactLayout) { + return; + } + + if (Rml::Context* context = aurora::rmlui::get_context()) { + if (Rml::Element* focused = context->GetFocusElement()) { + m_pendingFocusId = focused->GetId(); + } + } + rebuild(); + } + + void queue_activation(std::string id) { m_requestedActivation = std::move(id); } + + void queue_back() { m_requestedBack = true; } + + void queue_cycle(std::string id, int direction) { + m_requestedCycleId = std::move(id); + m_requestedCycleDirection = direction; + } + + void add_button_control(Rml::Element* parent, std::string_view id, std::string_view text, + ButtonVariant variant) { + const std::string idString(id); + m_focusIds.push_back(idString); + m_buttons.push_back(std::make_unique + + + + + +
Equipment
+ + + + + + + +
+ + + + + + + + + +
+)RML"; + +const Rml::String kLocationContent = R"RML( +
+
Save Location
+ + + +
Horse Location
+ +
+
+)RML"; + +} // namespace + +EditorWindow::EditorWindow() + : Window({.tabs = { + {"Player Status", + [](Rml::Element* content) { + // TODO: actually bind values and events. wonder if we should have + // a SettingsPane element or something for sharing? + Rml::Factory::InstanceElementText(content, kPlayerStatusContent); + }}, + {"Location", + [](Rml::Element* content) { + Rml::Factory::InstanceElementText(content, kLocationContent); + }}, + {"Inventory"}, + }}) {} + +} // namespace dusk::ui \ No newline at end of file diff --git a/src/dusk/ui/editor.hpp b/src/dusk/ui/editor.hpp new file mode 100644 index 0000000000..cec381e277 --- /dev/null +++ b/src/dusk/ui/editor.hpp @@ -0,0 +1,11 @@ +#pragma once +#include "window.hpp" + +namespace dusk::ui { + +class EditorWindow : public Window { +public: + EditorWindow(); +}; + +} // namespace dusk::ui diff --git a/src/dusk/ui/element.cpp b/src/dusk/ui/element.cpp deleted file mode 100644 index 87a113486c..0000000000 --- a/src/dusk/ui/element.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include "element.hpp" - -#include - -#include - -namespace dusk::ui { - -std::string escape(std::string_view text) { - std::string result; - result.reserve(text.size()); - for (char c : text) { - switch (c) { - case '&': - result += "&"; - break; - case '<': - result += "<"; - break; - case '>': - result += ">"; - break; - case '"': - result += """; - break; - case '\'': - result += "'"; - break; - default: - result += c; - break; - } - } - return result; -} - -Rml::Element* append(Rml::Element* parent, std::string_view tag, std::string_view id, - std::initializer_list > properties) { - if (parent == nullptr) { - return nullptr; - } - - Rml::ElementDocument* document = parent->GetOwnerDocument(); - if (document == nullptr) { - document = dynamic_cast(parent); - } - if (document == nullptr) { - return nullptr; - } - - Rml::ElementPtr child = document->CreateElement(std::string(tag)); - Rml::Element* rawChild = child.get(); - if (!id.empty()) { - rawChild->SetId(std::string(id)); - } - Rml::Element* appended = parent->AppendChild(std::move(child)); - set_props(appended, properties); - return appended; -} - -Rml::Element* append_text( - Rml::Element* parent, std::string_view tag, std::string_view text, std::string_view id) { - Rml::Element* element = append(parent, tag, id); - set_text(element, text); - return element; -} - -void set_text(Rml::Element* element, std::string_view text) { - if (element != nullptr) { - element->SetInnerRML(escape(text)); - } -} - -void set_props(Rml::Element* element, - std::initializer_list > properties) { - if (element == nullptr) { - return; - } - for (const auto& [name, value] : properties) { - element->SetProperty(std::string(name), std::string(value)); - } -} - -void set_props(Rml::Element* element, - std::initializer_list > properties) { - if (element == nullptr) { - return; - } - for (const auto& [name, value] : properties) { - element->SetProperty(name, value); - } -} - -} // namespace dusk::ui diff --git a/src/dusk/ui/element.hpp b/src/dusk/ui/element.hpp deleted file mode 100644 index a5f7586b32..0000000000 --- a/src/dusk/ui/element.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include - -#include -#include - -namespace dusk::ui { - -std::string escape(std::string_view text); -Rml::Element* append(Rml::Element* parent, std::string_view tag, std::string_view id = {}, - std::initializer_list > properties = {}); -Rml::Element* append_text( - Rml::Element* parent, std::string_view tag, std::string_view text, std::string_view id = {}); -void set_text(Rml::Element* element, std::string_view text); -void set_props(Rml::Element* element, - std::initializer_list > properties); -void set_props(Rml::Element* element, - std::initializer_list > properties); - -} // namespace dusk::ui diff --git a/src/dusk/ui/focus_border.cpp b/src/dusk/ui/focus_border.cpp deleted file mode 100644 index 32f872f5d1..0000000000 --- a/src/dusk/ui/focus_border.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "focus_border.hpp" - -#include "element.hpp" -#include "theme.hpp" - -#include - -namespace dusk::ui { - -Rml::Element* add_focus_border(Rml::Element* parent, float radius) { - using namespace theme; - - const auto borderColor = rml_color(PrimaryLight, 0); - return append(parent, "div", {}, - { - {Rml::PropertyId::Position, Rml::Style::Position::Absolute}, - {Rml::PropertyId::PointerEvents, Rml::Style::PointerEvents::None}, - {Rml::PropertyId::Left, rml_dp(-(BorderWidth * 3.0f))}, - {Rml::PropertyId::Top, rml_dp(-(BorderWidth * 3.0f))}, - {Rml::PropertyId::Right, rml_dp(-(BorderWidth * 3.0f))}, - {Rml::PropertyId::Bottom, rml_dp(-(BorderWidth * 3.0f))}, - {Rml::PropertyId::BorderTopWidth, rml_dp(BorderWidth * 2.0f)}, - {Rml::PropertyId::BorderRightWidth, rml_dp(BorderWidth * 2.0f)}, - {Rml::PropertyId::BorderBottomWidth, rml_dp(BorderWidth * 2.0f)}, - {Rml::PropertyId::BorderLeftWidth, rml_dp(BorderWidth * 2.0f)}, - {Rml::PropertyId::BorderTopLeftRadius, rml_dp(radius + BorderWidth * 4.0f)}, - {Rml::PropertyId::BorderTopRightRadius, rml_dp(radius + BorderWidth * 4.0f)}, - {Rml::PropertyId::BorderBottomRightRadius, rml_dp(radius + BorderWidth * 4.0f)}, - {Rml::PropertyId::BorderBottomLeftRadius, rml_dp(radius + BorderWidth * 4.0f)}, - {Rml::PropertyId::BorderTopColor, borderColor}, - {Rml::PropertyId::BorderRightColor, borderColor}, - {Rml::PropertyId::BorderBottomColor, borderColor}, - {Rml::PropertyId::BorderLeftColor, borderColor}, - }); -} - -void set_focus_border_visible(Rml::Element* parent, bool visible) { - if (parent == nullptr || parent->GetNumChildren() == 0) { - return; - } - - const auto borderColor = rml_color(theme::PrimaryLight, visible ? 255 : 0); - set_props(parent->GetChild(0), { - {Rml::PropertyId::BorderTopColor, borderColor}, - {Rml::PropertyId::BorderRightColor, borderColor}, - {Rml::PropertyId::BorderBottomColor, borderColor}, - {Rml::PropertyId::BorderLeftColor, borderColor}, - }); -} - -} // namespace dusk::ui diff --git a/src/dusk/ui/focus_border.hpp b/src/dusk/ui/focus_border.hpp deleted file mode 100644 index 79bc315bbd..0000000000 --- a/src/dusk/ui/focus_border.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include - -namespace dusk::ui { - -Rml::Element* add_focus_border(Rml::Element* parent, float radius); -void set_focus_border_visible(Rml::Element* parent, bool visible); - -} // namespace dusk::ui diff --git a/src/dusk/ui/game_menu.cpp b/src/dusk/ui/game_menu.cpp deleted file mode 100644 index a05e20acb5..0000000000 --- a/src/dusk/ui/game_menu.cpp +++ /dev/null @@ -1,808 +0,0 @@ -#include "game_menu.hpp" - -#include "element.hpp" -#include "game_option.hpp" -#include "label.hpp" -#include "theme.hpp" -#include "ui.hpp" -#include "window.hpp" - -#include "dusk/config.hpp" -#include "dusk/imgui/ImGuiEngine.hpp" -#include "dusk/main.h" -#include "dusk/settings.h" -#include "m_Do/m_Do_graphic.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace aurora::gx { -extern bool enableLodBias; -} - -namespace dusk::ui::game_menu { -namespace { - -enum class Tab : int { - Audio = 0, - Cheats, - Gameplay, - Graphics, - Input, - Interface, - Count, -}; - -struct TabDef { - const char* id; - const char* label; -}; - -constexpr std::array(Tab::Count)> kTabs{{ - {"audio", "Audio"}, - {"cheats", "Cheats"}, - {"gameplay", "Gameplay"}, - {"graphics", "Graphics"}, - {"input", "Input"}, - {"interface", "Interface"}, -}}; - -constexpr int kInternalResolutionScaleMax = 12; -constexpr int kShadowResolutionMax = 8; - -constexpr std::array kBloomMultiplierStops{0.0f, 0.25f, 0.50f, 0.75f, 1.00f}; -constexpr std::array kBloomModeNames{"Off", "Classic", "Dusk"}; - -// TODO: Needs more spacing for newlines -static const char* get_description_for_item(std::string_view id) { - if (id == "internal-resolution") { - return "Auto renders at the native window resolution.\nHigher values scale the internal " - "framebuffer."; - } - if (id == "shadow-resolution") { - return "Improves the shadow resolution, making them higher quality."; - } - if (id == "frame-interp") { - return "Uses inter-frame interpolation to enable higher frame rates.\nVisual artifacts, " - "animation glitches, or instability may occur."; - } - - return "No description found."; -} - -struct Row { - std::string id; - std::function activate; - std::function cycle; -}; - -class Screen : public Rml::EventListener { -public: - bool initialize() { - if (m_initialized) { - return true; - } - if (!ui::initialize()) { - return false; - } - m_initialized = true; - return true; - } - - void shutdown() { - close_document(); - if (ui::is_active()) { - ui::set_active(false); - } - m_initialized = false; - m_focusIds.clear(); - m_rows.clear(); - } - - bool is_open() const { return m_open; } - - void set_open(bool open) { - if (open == m_open) { - return; - } - if (open && !initialize()) { - return; - } - m_open = open; - if (open) { - ui::set_active(true); - rebuild(); - } else { - close_document(); - ui::set_active(false); - } - } - - void toggle() { set_open(!m_open); } - - void handle_event(const SDL_Event& event) { - if (!m_open) { - return; - } - ui::handle_event(event); - } - - void update() { - if (!m_open) { - return; - } - - if (m_requestClose) { - m_requestClose = false; - set_open(false); - return; - } - - if (!m_pendingTabId.empty()) { - const std::string tabId = std::move(m_pendingTabId); - m_pendingTabId.clear(); - apply_tab_selection(tabId); - if (!m_open) { - return; - } - } - - if (!m_requestedActivation.empty()) { - const std::string id = std::move(m_requestedActivation); - m_requestedActivation.clear(); - invoke_activate(id); - if (!m_open) { - return; - } - } - - if (m_requestedCycleDirection != 0) { - const std::string id = std::move(m_requestedCycleId); - const int direction = m_requestedCycleDirection; - m_requestedCycleId.clear(); - m_requestedCycleDirection = 0; - invoke_cycle(id, direction); - if (!m_open) { - return; - } - } - - if (m_needsRebuild) { - m_needsRebuild = false; - rebuild(); - } - - ui::update(); - sync_description_pane(); - } - - void ProcessEvent(Rml::Event& event) override { - if (event.GetId() != Rml::EventId::Keydown) { - return; - } - const auto key = static_cast( - event.GetParameter("key_identifier", Rml::Input::KI_UNKNOWN)); - if (handle_key(key)) { - event.StopImmediatePropagation(); - } - } - -private: - bool m_initialized = false; - bool m_open = false; - Tab m_tab = Tab::Graphics; - Rml::ElementDocument* m_document = nullptr; - std::unique_ptr m_window; - std::vector > m_options; - std::vector m_rows; - std::vector m_focusIds; - std::string m_pendingFocusId; - std::string m_requestedActivation; - std::string m_requestedCycleId; - int m_requestedCycleDirection = 0; - bool m_requestClose = false; - bool m_needsRebuild = false; - std::string m_pendingTabId; - Rml::Element* m_descriptionElement = nullptr; - Rml::Element* m_lastDescriptionSyncFocus = nullptr; - - Row* find_row(std::string_view id) { - for (auto& row : m_rows) { - if (row.id == id) { - return &row; - } - } - return nullptr; - } - - void invoke_activate(const std::string& id) { - if (Row* row = find_row(id); row && row->activate) { - row->activate(); - } - } - - void invoke_cycle(const std::string& id, int direction) { - if (Row* row = find_row(id); row && row->cycle) { - row->cycle(direction); - } - } - - void close_document() { - if (m_document == nullptr) { - return; - } - m_document->RemoveEventListener(Rml::EventId::Keydown, this); - m_options.clear(); - m_rows.clear(); - m_focusIds.clear(); - m_descriptionElement = nullptr; - m_lastDescriptionSyncFocus = nullptr; - m_window.reset(); - m_document->Close(); - m_document = nullptr; - } - - void style_document(Rml::ElementDocument* document) { - using namespace theme; - set_props(document, { - {Rml::PropertyId::Width, rml_percent(100.0f)}, - {Rml::PropertyId::Height, rml_percent(100.0f)}, - {Rml::PropertyId::MarginTop, rml_px(0.0f)}, - {Rml::PropertyId::MarginRight, rml_px(0.0f)}, - {Rml::PropertyId::MarginBottom, rml_px(0.0f)}, - {Rml::PropertyId::MarginLeft, rml_px(0.0f)}, - {Rml::PropertyId::PaddingTop, rml_px(0.0f)}, - {Rml::PropertyId::PaddingRight, rml_px(0.0f)}, - {Rml::PropertyId::PaddingBottom, rml_px(0.0f)}, - {Rml::PropertyId::PaddingLeft, rml_px(0.0f)}, - {Rml::PropertyId::FontFamily, rml_string("Inter")}, - {Rml::PropertyId::Color, rml_color(Text)}, - }); - } - - Rml::Element* add_screen() { - using namespace theme; - return append(m_document, "div", "game-menu-screen", - { - {Rml::PropertyId::Display, Rml::Style::Display::Flex}, - {Rml::PropertyId::Position, Rml::Style::Position::Absolute}, - {Rml::PropertyId::Left, rml_px(0.0f)}, - {Rml::PropertyId::Top, rml_px(0.0f)}, - {Rml::PropertyId::Right, rml_px(0.0f)}, - {Rml::PropertyId::Bottom, rml_px(0.0f)}, - {Rml::PropertyId::FlexDirection, Rml::Style::FlexDirection::Column}, - {Rml::PropertyId::AlignItems, Rml::Style::AlignItems::Center}, - {Rml::PropertyId::JustifyContent, Rml::Style::JustifyContent::Center}, - {Rml::PropertyId::BoxSizing, Rml::Style::BoxSizing::BorderBox}, - {Rml::PropertyId::PaddingTop, rml_dp(32.0f)}, - {Rml::PropertyId::PaddingRight, rml_dp(32.0f)}, - {Rml::PropertyId::PaddingBottom, rml_dp(32.0f)}, - {Rml::PropertyId::PaddingLeft, rml_dp(32.0f)}, - }); - } - - Rml::Element* add_section_header(Rml::Element* parent, std::string_view title) { - auto* row = append(parent, "div", {}, - { - {Rml::PropertyId::Display, Rml::Style::Display::Flex}, - {Rml::PropertyId::FlexDirection, Rml::Style::FlexDirection::Row}, - {Rml::PropertyId::AlignItems, Rml::Style::AlignItems::Center}, - {Rml::PropertyId::Width, rml_percent(100.0f)}, - {Rml::PropertyId::PaddingTop, rml_dp(8.0f)}, - {Rml::PropertyId::PaddingBottom, rml_dp(4.0f)}, - }); - auto* label = add_label(row, title, LabelStyle::Annotation); - set_props(label, { - {Rml::PropertyId::FontSize, rml_dp(14.0f)}, - {Rml::PropertyId::LetterSpacing, rml_dp(3.0f)}, - {Rml::PropertyId::Color, rml_color(theme::WindowAccentSoft)}, - {Rml::PropertyId::FlexShrink, rml_number(0.0f)}, - }); - return row; - } - - Rml::Element* add_scroll_body(Rml::Element* parent) { - return append(parent, "div", {}, - { - {Rml::PropertyId::Display, Rml::Style::Display::Flex}, - {Rml::PropertyId::FlexDirection, Rml::Style::FlexDirection::Column}, - {Rml::PropertyId::Width, rml_percent(100.0f)}, - {Rml::PropertyId::FlexGrow, rml_number(1.0f)}, - {Rml::PropertyId::MinHeight, rml_px(0.0f)}, - {Rml::PropertyId::RowGap, rml_dp(8.0f)}, - {Rml::PropertyId::ColumnGap, rml_dp(8.0f)}, - {Rml::PropertyId::OverflowY, Rml::Style::Overflow::Auto}, - }); - } - - std::function queue_activate(std::string id) { - return [this, id = std::move(id)] { m_requestedActivation = id; }; - } - - void register_row(Row row, std::unique_ptr option) { - m_focusIds.push_back(row.id); - m_rows.push_back(std::move(row)); - m_options.push_back(std::move(option)); - } - - void add_toggle(Rml::Element* parent, std::string id, std::string_view title, - config::ConfigVar& var, std::function sideEffect = {}, - std::string_view detail = {}) { - auto mutate = [this, &var, sideEffect = std::move(sideEffect)] { - const bool next = !var.getValue(); - var.setValue(next); - Save(); - if (sideEffect) { - sideEffect(next); - } - m_needsRebuild = true; - }; - const std::string_view valueText = var.getValue() ? "On" : "Off"; - auto option = - std::make_unique(parent, id, title, valueText, detail, queue_activate(id)); - register_row(Row{id, mutate, [mutate](int) { mutate(); }}, std::move(option)); - } - - void add_action(Rml::Element* parent, std::string id, std::string_view title, - std::function action, std::string_view valueText = ">", - std::string_view detail = {}) { - auto mutate = [this, action = std::move(action)] { - action(); - m_needsRebuild = true; - }; - auto option = - std::make_unique(parent, id, title, valueText, detail, queue_activate(id)); - register_row(Row{id, mutate, {}}, std::move(option)); - } - - template - void add_cycle_row(Rml::Element* parent, std::string id, std::string_view title, - std::string_view valueText, std::string_view detail, std::function cycle) { - auto mutate = [this, cycle] { - cycle(1); - m_needsRebuild = true; - }; - auto cycleWithRebuild = [this, cycle](int direction) { - cycle(direction); - m_needsRebuild = true; - }; - auto option = - std::make_unique(parent, id, title, valueText, detail, queue_activate(id)); - register_row(Row{id, mutate, cycleWithRebuild}, std::move(option)); - } - - void add_int_cycle(Rml::Element* parent, std::string id, std::string_view title, - config::ConfigVar& var, int minValue, int maxValue, - std::function formatter, std::function sideEffect = {}) { - const int current = std::clamp(var.getValue(), minValue, maxValue); - const std::string valueText = formatter(current); - auto cycle = [&var, minValue, maxValue, sideEffect = std::move(sideEffect)](int dir) { - int next = std::clamp(var.getValue(), minValue, maxValue) + dir; - if (next < minValue) { - next = maxValue; - } else if (next > maxValue) { - next = minValue; - } - var.setValue(next); - Save(); - if (sideEffect) { - sideEffect(next); - } - }; - add_cycle_row(parent, std::move(id), title, valueText, {}, std::move(cycle)); - } - - void add_bloom_mode_row(Rml::Element* parent) { - auto& var = getSettings().game.bloomMode; - const int current = std::clamp( - static_cast(var.getValue()), 0, static_cast(kBloomModeNames.size() - 1)); - const std::string_view valueText = kBloomModeNames[static_cast(current)]; - auto cycle = [&var](int dir) { - const int count = kBloomModeNames.size(); - int next = static_cast(var.getValue()) + dir; - next = (next % count + count) % count; - var.setValue(static_cast(next)); - Save(); - }; - add_cycle_row(parent, "bloom-mode", "Bloom", valueText, {}, std::move(cycle)); - } - - void add_bloom_brightness_row(Rml::Element* parent) { - auto& var = getSettings().game.bloomMultiplier; - const std::string valueText = fmt::format("{:.2f}", var.getValue()); - auto cycle = [&var](int dir) { - const float currentValue = var.getValue(); - int closest = 0; - float bestDelta = std::abs(currentValue - kBloomMultiplierStops[0]); - for (int i = 1; i < static_cast(kBloomMultiplierStops.size()); ++i) { - const float delta = std::abs(currentValue - kBloomMultiplierStops[i]); - if (delta < bestDelta) { - bestDelta = delta; - closest = i; - } - } - const int count = kBloomMultiplierStops.size(); - const int next = (closest + dir + count) % count; - var.setValue(kBloomMultiplierStops[next]); - Save(); - }; - const std::string_view detail = - getSettings().game.bloomMode.getValue() == BloomMode::Off ? "Bloom is disabled" : ""; - add_cycle_row( - parent, "bloom-brightness", "Bloom Brightness", valueText, detail, std::move(cycle)); - } - - void build_description_pane() { - m_descriptionElement = nullptr; - m_lastDescriptionSyncFocus = nullptr; - Rml::Element* right = m_window->right_pane(); - if (right == nullptr) { - return; - } - m_descriptionElement = append_text(right, "p", " ", "option-description"); - set_props(m_descriptionElement, - { - {Rml::PropertyId::Color, rml_color(theme::TextActive)}, - {Rml::PropertyId::FontSize, rml_dp(20.0f)}, - {Rml::PropertyId::LineHeight, Rml::Property(1.45f, Rml::Unit::EM)}, - {Rml::PropertyId::TextAlign, Rml::Style::TextAlign::Left}, - {Rml::PropertyId::AlignSelf, Rml::Style::AlignSelf::Stretch}, - {Rml::PropertyId::Width, rml_percent(100.0f)}, - {Rml::PropertyId::BoxSizing, Rml::Style::BoxSizing::BorderBox}, - {Rml::PropertyId::WhiteSpace, Rml::Style::WhiteSpace::Preline}, - }); - } - - void sync_description_pane() { - if (m_descriptionElement == nullptr) { - return; - } - if (m_tab != Tab::Graphics) { - return; - } - Rml::Context* context = aurora::rmlui::get_context(); - if (context == nullptr) { - return; - } - Rml::Element* const focused = context->GetFocusElement(); - if (focused == m_lastDescriptionSyncFocus) { - return; - } - m_lastDescriptionSyncFocus = focused; - if (focused == nullptr) { - set_text(m_descriptionElement, get_description_for_item({})); - } else { - set_text(m_descriptionElement, get_description_for_item(focused->GetId())); - } - } - - void build_graphics_tab(Rml::Element* body) { - auto* scroll = add_scroll_body(body); - - add_section_header(scroll, "Display"); - - // TODO: Replace this with a Display Mode toggle. - add_toggle(scroll, "fullscreen", "Toggle Fullscreen", getSettings().video.enableFullscreen, - [](bool enabled) { VISetWindowFullscreen(enabled); }); - - u32 internalWidth = 0; - u32 internalHeight = 0; - AuroraGetRenderSize(&internalWidth, &internalHeight); - const std::string detail = fmt::format("Current: {}x{}", internalWidth, internalHeight); - - const int currentScale = std::clamp( - getSettings().game.internalResolutionScale.getValue(), 0, kInternalResolutionScaleMax); - const std::string scaleValue = - currentScale == 0 ? std::string("Auto") : fmt::format("{}x", currentScale); - - auto scaleCycle = [](int dir) { - int next = std::clamp(getSettings().game.internalResolutionScale.getValue(), 0, - kInternalResolutionScaleMax) + - dir; - if (next < 0) { - next = kInternalResolutionScaleMax; - } else if (next > kInternalResolutionScaleMax) { - next = 0; - } - getSettings().game.internalResolutionScale.setValue(next); - VISetFrameBufferScale(static_cast(next)); - Save(); - }; - - add_cycle_row(scroll, "internal-resolution", "Internal Resolution", scaleValue, detail, - std::move(scaleCycle)); - - add_int_cycle(scroll, "shadow-resolution", "Shadow Resolution", - getSettings().game.shadowResolutionMultiplier, 1, kShadowResolutionMax, - [](int v) { return fmt::format("x{}", v); }); - - add_toggle(scroll, "lock-aspect", "Force 4:3 Aspect Ratio", - getSettings().video.lockAspectRatio, [](bool enabled) { - AuroraSetViewportPolicy(enabled ? AURORA_VIEWPORT_FIT : AURORA_VIEWPORT_STRETCH); - }); - - add_toggle(scroll, "vsync", "VSync", getSettings().video.enableVsync, - [](bool enabled) { aurora_enable_vsync(enabled); }); - - add_toggle(scroll, "frame-interp", "Unlock Framerate", - getSettings().game.enableFrameInterpolation, {}, "Experimental"); - - add_section_header(scroll, "Post-Processing"); - - add_bloom_mode_row(scroll); - if (getSettings().game.bloomMode.getValue() != BloomMode::Off) { - add_bloom_brightness_row(scroll); - } - - add_toggle( - scroll, "depth-of-field", "Depth of Field", getSettings().game.enableDepthOfField); - - add_section_header(scroll, "Developer Options"); - - const std::string lodValue = aurora::gx::enableLodBias ? "On" : "Off"; - auto lodMutate = [this] { - aurora::gx::enableLodBias = !aurora::gx::enableLodBias; - m_needsRebuild = true; - }; - auto lodOption = std::make_unique(scroll, "lod-bias", "LOD Bias", lodValue, - std::string_view{}, queue_activate("lod-bias")); - register_row( - Row{"lod-bias", lodMutate, [lodMutate](int) { lodMutate(); }}, std::move(lodOption)); - - add_toggle( - scroll, "minimap-shadows", "Mini-Map Shadows", getSettings().game.enableMapBackground); - } - - void build_placeholder_tab(Rml::Element* body, std::string_view tabLabel) { - auto* wrap = append(body, "div", {}, - { - {Rml::PropertyId::Display, Rml::Style::Display::Flex}, - {Rml::PropertyId::FlexDirection, Rml::Style::FlexDirection::Column}, - {Rml::PropertyId::AlignItems, Rml::Style::AlignItems::Center}, - {Rml::PropertyId::JustifyContent, Rml::Style::JustifyContent::Center}, - {Rml::PropertyId::Width, rml_percent(100.0f)}, - {Rml::PropertyId::FlexGrow, rml_number(1.0f)}, - {Rml::PropertyId::RowGap, rml_dp(12.0f)}, - {Rml::PropertyId::ColumnGap, rml_dp(12.0f)}, - }); - auto* heading = add_label(wrap, tabLabel, LabelStyle::Large); - set_props(heading, {{Rml::PropertyId::TextAlign, Rml::Style::TextAlign::Center}}); - auto* sub = add_label(wrap, "Not yet ported.", LabelStyle::Body); - set_props(sub, { - {Rml::PropertyId::TextAlign, Rml::Style::TextAlign::Center}, - {Rml::PropertyId::Color, rml_color(theme::TextDim)}, - }); - } - - void build_body() { - m_window->set_right_pane_visible(m_tab == Tab::Graphics); - Rml::Element* body = m_window->body(); - switch (m_tab) { - case Tab::Graphics: - build_graphics_tab(body); - build_description_pane(); - break; - default: - build_placeholder_tab(body, kTabs[static_cast(m_tab)].label); - break; - } - } - - void rebuild() { - if (!m_open) { - return; - } - - Rml::Context* context = aurora::rmlui::get_context(); - if (context == nullptr) { - return; - } - - const std::string preferredFocus = - m_pendingFocusId.empty() ? current_focus_id() : m_pendingFocusId; - m_pendingFocusId.clear(); - - close_document(); - - m_document = context->CreateDocument(); - if (m_document == nullptr) { - return; - } - - style_document(m_document); - Rml::Element* screen = add_screen(); - - m_window = std::make_unique(screen, "game-menu", [this] { request_close(); }); - - for (const TabDef& tab : kTabs) { - const std::string tabId = tab.id; - m_window->add_tab(tabId, tab.label, [this, tabId] { m_pendingTabId = tabId; }); - } - m_window->set_selected_tab(kTabs[static_cast(m_tab)].id); - - build_body(); - - m_document->AddEventListener(Rml::EventId::Keydown, this); - m_document->Show(); - - focus_id(preferredFocus.empty() ? first_focus_id() : preferredFocus); - sync_description_pane(); - } - - void request_close() { m_requestClose = true; } - - void switch_tab(int direction) { - const int count = kTabs.size(); - const int next = (static_cast(m_tab) + direction + count) % count; - m_pendingTabId = kTabs[static_cast(next)].id; - } - - void apply_tab_selection(std::string_view tabId) { - for (size_t i = 0; i < kTabs.size(); ++i) { - if (tabId == kTabs[i].id) { - if (m_tab == static_cast(i)) { - return; - } - m_tab = static_cast(i); - m_pendingFocusId.clear(); - rebuild(); - return; - } - } - } - - std::string current_focus_id() const { - if (Rml::Context* context = aurora::rmlui::get_context()) { - if (Rml::Element* focused = context->GetFocusElement()) { - return focused->GetId(); - } - } - return {}; - } - - std::string first_focus_id() const { - return m_focusIds.empty() ? std::string{} : m_focusIds.front(); - } - - int focus_index() const { - const std::string id = current_focus_id(); - if (id.empty()) { - return -1; - } - for (int i = 0; i < static_cast(m_focusIds.size()); ++i) { - if (m_focusIds[i] == id) { - return i; - } - } - return -1; - } - - void focus_id(std::string_view id) { - if (m_document == nullptr) { - return; - } - if (!id.empty()) { - if (Rml::Element* element = m_document->GetElementById(std::string(id))) { - element->Focus(true); - return; - } - } - const std::string fallback = first_focus_id(); - if (!fallback.empty()) { - if (Rml::Element* element = m_document->GetElementById(fallback)) { - element->Focus(true); - } - } - } - - void move_focus(int direction) { - if (m_focusIds.empty()) { - return; - } - const int index = focus_index(); - if (index < 0) { - focus_id(m_focusIds.front()); - return; - } - const int next = index + direction; - if (next < 0 || next >= static_cast(m_focusIds.size())) { - return; - } - focus_id(m_focusIds[static_cast(next)]); - } - - void queue_activate_focused() { - const std::string id = current_focus_id(); - if (!id.empty()) { - m_requestedActivation = id; - } - } - - void queue_cycle_focused(int direction) { - const std::string id = current_focus_id(); - if (!id.empty()) { - m_requestedCycleId = id; - m_requestedCycleDirection = direction; - } - } - - bool handle_key(Rml::Input::KeyIdentifier key) { - switch (key) { - case Rml::Input::KI_UP: - move_focus(-1); - return true; - case Rml::Input::KI_DOWN: - move_focus(1); - return true; - case Rml::Input::KI_LEFT: - queue_cycle_focused(-1); - return true; - case Rml::Input::KI_RIGHT: - queue_cycle_focused(1); - return true; - case Rml::Input::KI_F16: - switch_tab(-1); - return true; - case Rml::Input::KI_F17: - switch_tab(1); - return true; - case Rml::Input::KI_RETURN: - queue_activate_focused(); - return true; - case Rml::Input::KI_ESCAPE: - case Rml::Input::KI_F15: - request_close(); - return true; - default: - return false; - } - } -}; - -Screen s_screen; - -} // namespace - -bool initialize() { - return s_screen.initialize(); -} - -void shutdown() { - s_screen.shutdown(); -} - -bool is_active() { - return s_screen.is_open(); -} - -void toggle() { - s_screen.toggle(); -} - -void set_active(bool active) { - s_screen.set_open(active); -} - -void handle_event(const SDL_Event& event) { - s_screen.handle_event(event); -} - -void update() { - s_screen.update(); -} - -} // namespace dusk::ui::game_menu diff --git a/src/dusk/ui/game_menu.hpp b/src/dusk/ui/game_menu.hpp deleted file mode 100644 index bff59a0f50..0000000000 --- a/src/dusk/ui/game_menu.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include - -namespace dusk::ui::game_menu { - -bool initialize(); -void shutdown(); - -bool is_active(); -void toggle(); -void set_active(bool active); - -void handle_event(const SDL_Event& event); -void update(); - -} // namespace dusk::ui::game_menu diff --git a/src/dusk/ui/game_option.cpp b/src/dusk/ui/game_option.cpp deleted file mode 100644 index 66540c967c..0000000000 --- a/src/dusk/ui/game_option.cpp +++ /dev/null @@ -1,201 +0,0 @@ -#include "game_option.hpp" - -#include "control_surface.hpp" -#include "element.hpp" -#include "focus_border.hpp" -#include "label.hpp" -#include "theme.hpp" - -#include - -#include - -namespace dusk::ui { - -GameOption::GameOption(Rml::Element* parent, std::string_view id, std::string_view title, - std::string_view value, std::string_view detail, std::function pressedCallback) - : m_pressedCallback(std::move(pressedCallback)) { - using namespace theme; - - m_element = append(parent, "button", id, - { - {Rml::PropertyId::Display, Rml::Style::Display::Flex}, - {Rml::PropertyId::Position, Rml::Style::Position::Relative}, - {Rml::PropertyId::FlexDirection, Rml::Style::FlexDirection::Row}, - {Rml::PropertyId::AlignItems, Rml::Style::AlignItems::Center}, - {Rml::PropertyId::JustifyContent, Rml::Style::JustifyContent::SpaceBetween}, - {Rml::PropertyId::BoxSizing, Rml::Style::BoxSizing::BorderBox}, - {Rml::PropertyId::RowGap, rml_dp(16.0f)}, - {Rml::PropertyId::ColumnGap, rml_dp(16.0f)}, - {Rml::PropertyId::Width, rml_percent(100.0f)}, - {Rml::PropertyId::PaddingTop, rml_dp(16.0f)}, - {Rml::PropertyId::PaddingRight, rml_dp(16.0f)}, - {Rml::PropertyId::PaddingBottom, rml_dp(16.0f)}, - {Rml::PropertyId::PaddingLeft, rml_dp(16.0f)}, - {Rml::PropertyId::BorderTopWidth, rml_dp(BorderWidth)}, - {Rml::PropertyId::BorderRightWidth, rml_dp(BorderWidth)}, - {Rml::PropertyId::BorderBottomWidth, rml_dp(BorderWidth)}, - {Rml::PropertyId::BorderLeftWidth, rml_dp(BorderWidth)}, - {Rml::PropertyId::BorderTopLeftRadius, rml_dp(BorderRadiusSmall)}, - {Rml::PropertyId::BorderTopRightRadius, rml_dp(BorderRadiusSmall)}, - {Rml::PropertyId::BorderBottomRightRadius, rml_dp(BorderRadiusSmall)}, - {Rml::PropertyId::BorderBottomLeftRadius, rml_dp(BorderRadiusSmall)}, - {Rml::PropertyId::BackgroundColor, rml_color(Transparent)}, - {Rml::PropertyId::BorderTopColor, rml_color(ElevatedBorder, 0)}, - {Rml::PropertyId::BorderRightColor, rml_color(ElevatedBorder, 0)}, - {Rml::PropertyId::BorderBottomColor, rml_color(ElevatedBorder, 0)}, - {Rml::PropertyId::BorderLeftColor, rml_color(ElevatedBorder, 0)}, - {Rml::PropertyId::Color, rml_color(TextDim)}, - {Rml::PropertyId::Cursor, rml_string("pointer")}, - {Rml::PropertyId::TabIndex, Rml::Style::TabIndex::Auto}, - {Rml::PropertyId::NavUp, Rml::Style::Nav::Auto}, - {Rml::PropertyId::NavDown, Rml::Style::Nav::Auto}, - {Rml::PropertyId::NavLeft, Rml::Style::Nav::Auto}, - {Rml::PropertyId::NavRight, Rml::Style::Nav::Auto}, - {Rml::PropertyId::Opacity, rml_number(1.0f)}, - {Rml::PropertyId::FontFamily, rml_string("Inter")}, - }); - - add_focus_border(m_element, BorderRadiusSmall); - - auto* left = append(m_element, "div", {}, - { - {Rml::PropertyId::Display, Rml::Style::Display::Flex}, - {Rml::PropertyId::FlexDirection, Rml::Style::FlexDirection::Column}, - {Rml::PropertyId::RowGap, rml_dp(4.0f)}, - {Rml::PropertyId::ColumnGap, rml_dp(4.0f)}, - {Rml::PropertyId::MinWidth, rml_px(0.0f)}, - {Rml::PropertyId::Width, rml_px(0.0f)}, - {Rml::PropertyId::FlexGrow, rml_number(1.0f)}, - {Rml::PropertyId::FlexShrink, rml_number(1.0f)}, - {Rml::PropertyId::PointerEvents, Rml::Style::PointerEvents::None}, - }); - - m_title = add_label(left, title, LabelStyle::Large); - set_props(m_title, { - {Rml::PropertyId::Color, rml_color(TextDim)}, - {Rml::PropertyId::FontSize, rml_dp(28.0f)}, - {Rml::PropertyId::LetterSpacing, rml_dp(1.0f)}, - }); - - if (!value.empty() || !detail.empty()) { - auto* right = append(m_element, "div", {}, - { - {Rml::PropertyId::Display, Rml::Style::Display::Flex}, - {Rml::PropertyId::FlexDirection, Rml::Style::FlexDirection::Column}, - {Rml::PropertyId::AlignItems, Rml::Style::AlignItems::FlexEnd}, - {Rml::PropertyId::JustifyContent, Rml::Style::JustifyContent::Center}, - {Rml::PropertyId::RowGap, rml_dp(4.0f)}, - {Rml::PropertyId::ColumnGap, rml_dp(4.0f)}, - {Rml::PropertyId::MinWidth, rml_dp(170.0f)}, - {Rml::PropertyId::MaxWidth, rml_percent(48.0f)}, - {Rml::PropertyId::FlexShrink, rml_number(0.0f)}, - {Rml::PropertyId::PointerEvents, Rml::Style::PointerEvents::None}, - }); - - if (!value.empty()) { - m_value = add_label(right, value, LabelStyle::Body); - set_props( - m_value, { - {Rml::PropertyId::Color, rml_color(TextDim)}, - {Rml::PropertyId::TextAlign, Rml::Style::TextAlign::Right}, - {Rml::PropertyId::OverflowX, Rml::Style::Overflow::Hidden}, - {Rml::PropertyId::OverflowY, Rml::Style::Overflow::Hidden}, - {Rml::PropertyId::TextOverflow, Rml::Style::TextOverflow::Ellipsis}, - {Rml::PropertyId::WhiteSpace, Rml::Style::WhiteSpace::Nowrap}, - }); - } - - if (!detail.empty()) { - m_detail = add_label(right, detail, LabelStyle::Annotation); - set_props(m_detail, { - {Rml::PropertyId::Color, rml_color(TextDim)}, - {Rml::PropertyId::TextAlign, Rml::Style::TextAlign::Right}, - }); - } - } - - m_element->AddEventListener(Rml::EventId::Click, this); - m_element->AddEventListener(Rml::EventId::Focus, this); - m_element->AddEventListener(Rml::EventId::Blur, this); - m_element->AddEventListener(Rml::EventId::Mouseover, this); - m_element->AddEventListener(Rml::EventId::Mouseout, this); - apply_style(); -} - -GameOption::~GameOption() { - if (m_element == nullptr) { - return; - } - - m_element->RemoveEventListener(Rml::EventId::Click, this); - m_element->RemoveEventListener(Rml::EventId::Focus, this); - m_element->RemoveEventListener(Rml::EventId::Blur, this); - m_element->RemoveEventListener(Rml::EventId::Mouseover, this); - m_element->RemoveEventListener(Rml::EventId::Mouseout, this); - m_element = nullptr; -} - -void GameOption::ProcessEvent(Rml::Event& event) { - switch (event.GetId()) { - case Rml::EventId::Click: - if (m_pressedCallback) { - m_pressedCallback(); - } - break; - case Rml::EventId::Focus: - m_focused = true; - apply_style(); - break; - case Rml::EventId::Blur: - m_focused = false; - apply_style(); - break; - case Rml::EventId::Mouseover: - m_hovered = true; - apply_style(); - break; - case Rml::EventId::Mouseout: - m_hovered = false; - apply_style(); - break; - default: - break; - } -} - -Rml::Element* GameOption::element() const { - return m_element; -} - -std::string GameOption::id() const { - return m_element == nullptr ? std::string{} : m_element->GetId(); -} - -void GameOption::set_value(std::string_view value) { - set_text(m_value, value); -} - -void GameOption::apply_style() { - if (m_element == nullptr) { - return; - } - - const bool active = m_hovered || m_focused; - apply_control_surface_style( - m_element, control_surface_style(ControlSurfaceTone::Quiet), active); - m_element->SetProperty( - Rml::PropertyId::Color, rml_color(active ? theme::TextActive : theme::TextDim)); - m_title->SetProperty( - Rml::PropertyId::Color, rml_color(active ? theme::TextActive : theme::TextDim)); - if (m_value != nullptr) { - m_value->SetProperty( - Rml::PropertyId::Color, rml_color(active ? theme::TextActive : theme::TextDim)); - } - if (m_detail != nullptr) { - m_detail->SetProperty(Rml::PropertyId::Color, rml_color(theme::TextDim)); - } - set_focus_border_visible(m_element, m_focused); -} - -} // namespace dusk::ui diff --git a/src/dusk/ui/game_option.hpp b/src/dusk/ui/game_option.hpp deleted file mode 100644 index c66e3ddd2a..0000000000 --- a/src/dusk/ui/game_option.hpp +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include - -#include -#include -#include - -namespace Rml { -class Element; -} - -namespace dusk::ui { - -class GameOption : public Rml::EventListener { -public: - GameOption(Rml::Element* parent, std::string_view id, std::string_view title, - std::string_view value, std::string_view detail, std::function pressedCallback); - ~GameOption() override; - - GameOption(const GameOption&) = delete; - GameOption& operator=(const GameOption&) = delete; - - void ProcessEvent(Rml::Event& event) override; - - Rml::Element* element() const; - std::string id() const; - void set_value(std::string_view value); - -private: - Rml::Element* m_element = nullptr; - Rml::Element* m_title = nullptr; - Rml::Element* m_value = nullptr; - Rml::Element* m_detail = nullptr; - std::function m_pressedCallback; - bool m_hovered = false; - bool m_focused = false; - - void apply_style(); -}; - -} // namespace dusk::ui diff --git a/src/dusk/ui/label.cpp b/src/dusk/ui/label.cpp deleted file mode 100644 index 1077a9fcba..0000000000 --- a/src/dusk/ui/label.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "label.hpp" - -#include "element.hpp" -#include "theme.hpp" - -namespace dusk::ui { - -void apply_label_style(Rml::Element* element, LabelStyle style) { - using namespace theme; - - switch (style) { - case LabelStyle::Annotation: - set_props(element, { - {Rml::PropertyId::FontSize, rml_dp(18.0f)}, - {Rml::PropertyId::LetterSpacing, rml_dp(2.0f)}, - {Rml::PropertyId::FontWeight, Rml::Style::FontWeight::Normal}, - {Rml::PropertyId::Color, rml_color(TextDim)}, - }); - break; - case LabelStyle::Body: - set_props(element, { - {Rml::PropertyId::FontSize, rml_dp(20.0f)}, - {Rml::PropertyId::LetterSpacing, rml_px(0.0f)}, - {Rml::PropertyId::FontWeight, Rml::Style::FontWeight::Normal}, - {Rml::PropertyId::Color, rml_color(Text)}, - }); - break; - case LabelStyle::Medium: - set_props(element, { - {Rml::PropertyId::FontSize, rml_dp(28.0f)}, - {Rml::PropertyId::LetterSpacing, rml_dp(3.0f)}, - {Rml::PropertyId::FontWeight, Rml::Style::FontWeight::Bold}, - {Rml::PropertyId::Color, rml_color(Text)}, - }); - break; - case LabelStyle::Large: - set_props(element, { - {Rml::PropertyId::FontSize, rml_dp(36.0f)}, - {Rml::PropertyId::LetterSpacing, rml_dp(4.0f)}, - {Rml::PropertyId::FontWeight, Rml::Style::FontWeight::Bold}, - {Rml::PropertyId::Color, rml_color(Text)}, - }); - break; - } -} - -Rml::Element* add_label(Rml::Element* parent, std::string_view text, LabelStyle style) { - Rml::Element* label = append_text(parent, "div", text); - apply_label_style(label, style); - return label; -} - -} // namespace dusk::ui diff --git a/src/dusk/ui/label.hpp b/src/dusk/ui/label.hpp deleted file mode 100644 index fb23ad408f..0000000000 --- a/src/dusk/ui/label.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include - -#include - -namespace dusk::ui { - -enum class LabelStyle { - Annotation, - Body, - Medium, - Large, -}; - -Rml::Element* add_label(Rml::Element* parent, std::string_view text, LabelStyle style); -void apply_label_style(Rml::Element* element, LabelStyle style); - -} // namespace dusk::ui diff --git a/src/dusk/ui/prelaunch_layout.cpp b/src/dusk/ui/prelaunch_layout.cpp deleted file mode 100644 index a1916cc89e..0000000000 --- a/src/dusk/ui/prelaunch_layout.cpp +++ /dev/null @@ -1,138 +0,0 @@ -#include "prelaunch_layout.hpp" - -#include "element.hpp" -#include "label.hpp" -#include "theme.hpp" - -#include - -namespace dusk::ui::prelaunch::layout { - -void style_document(Rml::ElementDocument* document) { - using namespace theme; - - set_props(document, { - {Rml::PropertyId::Width, rml_percent(100.0f)}, - {Rml::PropertyId::Height, rml_percent(100.0f)}, - {Rml::PropertyId::MarginTop, rml_px(0.0f)}, - {Rml::PropertyId::MarginRight, rml_px(0.0f)}, - {Rml::PropertyId::MarginBottom, rml_px(0.0f)}, - {Rml::PropertyId::MarginLeft, rml_px(0.0f)}, - {Rml::PropertyId::PaddingTop, rml_px(0.0f)}, - {Rml::PropertyId::PaddingRight, rml_px(0.0f)}, - {Rml::PropertyId::PaddingBottom, rml_px(0.0f)}, - {Rml::PropertyId::PaddingLeft, rml_px(0.0f)}, - {Rml::PropertyId::FontFamily, rml_string("Inter")}, - {Rml::PropertyId::BackgroundColor, rml_color(Background1)}, - {Rml::PropertyId::Color, rml_color(Text)}, - }); -} - -Rml::Element* add_screen(Rml::ElementDocument* document, ScreenLayout layout) { - using namespace theme; - - const bool compact = layout == ScreenLayout::CompactSplit; - return append(document, "div", "prelaunch-screen", - { - {Rml::PropertyId::Display, Rml::Style::Display::Flex}, - {Rml::PropertyId::Position, Rml::Style::Position::Absolute}, - {Rml::PropertyId::Left, rml_px(0.0f)}, - {Rml::PropertyId::Top, rml_px(0.0f)}, - {Rml::PropertyId::Right, rml_px(0.0f)}, - {Rml::PropertyId::Bottom, rml_px(0.0f)}, - {Rml::PropertyId::FlexDirection, - compact ? Rml::Style::FlexDirection::Row : Rml::Style::FlexDirection::Column}, - {Rml::PropertyId::AlignItems, Rml::Style::AlignItems::Center}, - {Rml::PropertyId::JustifyContent, Rml::Style::JustifyContent::Center}, - {Rml::PropertyId::RowGap, rml_dp(compact ? 28.0f : 24.0f)}, - {Rml::PropertyId::ColumnGap, rml_dp(compact ? 28.0f : 24.0f)}, - {Rml::PropertyId::BoxSizing, Rml::Style::BoxSizing::BorderBox}, - {Rml::PropertyId::PaddingTop, rml_dp(compact ? 24.0f : 48.0f)}, - {Rml::PropertyId::PaddingRight, rml_dp(compact ? 24.0f : 28.0f)}, - {Rml::PropertyId::PaddingBottom, rml_dp(compact ? 24.0f : 48.0f)}, - {Rml::PropertyId::PaddingLeft, rml_dp(compact ? 24.0f : 28.0f)}, - {Rml::PropertyId::BackgroundColor, rml_color(Background1)}, - }); -} - -Rml::Element* add_brand(Rml::Element* parent, std::string_view logoPath, bool compact) { - auto* brand = append(parent, "div", {}, - { - {Rml::PropertyId::Display, Rml::Style::Display::Flex}, - {Rml::PropertyId::FlexDirection, Rml::Style::FlexDirection::Column}, - {Rml::PropertyId::AlignItems, Rml::Style::AlignItems::Center}, - {Rml::PropertyId::JustifyContent, Rml::Style::JustifyContent::Center}, - {Rml::PropertyId::RowGap, rml_dp(compact ? 8.0f : 12.0f)}, - {Rml::PropertyId::ColumnGap, rml_dp(compact ? 8.0f : 12.0f)}, - {Rml::PropertyId::Width, compact ? rml_dp(260.0f) : rml_percent(100.0f)}, - {Rml::PropertyId::MaxWidth, compact ? rml_percent(32.0f) : rml_dp(720.0f)}, - {Rml::PropertyId::FlexShrink, rml_number(compact ? 0.0f : 1.0f)}, - }); - - auto* subtitle = add_label(brand, "Twilit Realm presents", LabelStyle::Annotation); - set_props(subtitle, { - {Rml::PropertyId::TextAlign, Rml::Style::TextAlign::Center}, - {Rml::PropertyId::FontSize, rml_dp(compact ? 14.0f : 18.0f)}, - }); - - if (!logoPath.empty()) { - auto* logo = append(brand, "img"); - logo->SetAttribute("src", std::string(logoPath)); - set_props(logo, { - {Rml::PropertyId::Width, rml_dp(compact ? 220.0f : 360.0f)}, - {Rml::PropertyId::MaxWidth, rml_percent(compact ? 100.0f : 70.0f)}, - {Rml::PropertyId::Height, Rml::Style::Height::Auto}, - }); - } else { - auto* title = add_label(brand, "Dusk", LabelStyle::Large); - set_props(title, { - {Rml::PropertyId::FontSize, rml_dp(compact ? 42.0f : 54.0f)}, - {Rml::PropertyId::LetterSpacing, rml_dp(compact ? 3.0f : 4.0f)}, - }); - } - return brand; -} - -Rml::Element* add_heading(Rml::Element* parent, std::string_view title) { - auto* heading = add_label(parent, title, LabelStyle::Large); - set_props(heading, { - {Rml::PropertyId::Width, rml_percent(100.0f)}, - {Rml::PropertyId::MaxWidth, rml_dp(840.0f)}, - {Rml::PropertyId::TextAlign, Rml::Style::TextAlign::Left}, - }); - return heading; -} - -Rml::Element* add_panel(Rml::Element* parent, bool wide, bool compact) { - using namespace theme; - - return append(parent, "div", {}, - { - {Rml::PropertyId::Display, Rml::Style::Display::Flex}, - {Rml::PropertyId::FlexDirection, Rml::Style::FlexDirection::Column}, - {Rml::PropertyId::RowGap, rml_dp(12.0f)}, - {Rml::PropertyId::ColumnGap, rml_dp(12.0f)}, - {Rml::PropertyId::Width, rml_dp(wide ? 840.0f : 520.0f)}, - {Rml::PropertyId::MaxWidth, rml_percent(compact ? 62.0f : 100.0f)}, - {Rml::PropertyId::BoxSizing, Rml::Style::BoxSizing::BorderBox}, - {Rml::PropertyId::PaddingTop, rml_dp(compact ? 16.0f : 20.0f)}, - {Rml::PropertyId::PaddingRight, rml_dp(compact ? 16.0f : 20.0f)}, - {Rml::PropertyId::PaddingBottom, rml_dp(compact ? 16.0f : 20.0f)}, - {Rml::PropertyId::PaddingLeft, rml_dp(compact ? 16.0f : 20.0f)}, - {Rml::PropertyId::BorderTopWidth, rml_dp(BorderWidth)}, - {Rml::PropertyId::BorderRightWidth, rml_dp(BorderWidth)}, - {Rml::PropertyId::BorderBottomWidth, rml_dp(BorderWidth)}, - {Rml::PropertyId::BorderLeftWidth, rml_dp(BorderWidth)}, - {Rml::PropertyId::BorderTopLeftRadius, rml_dp(BorderRadiusMedium)}, - {Rml::PropertyId::BorderTopRightRadius, rml_dp(BorderRadiusMedium)}, - {Rml::PropertyId::BorderBottomRightRadius, rml_dp(BorderRadiusMedium)}, - {Rml::PropertyId::BorderBottomLeftRadius, rml_dp(BorderRadiusMedium)}, - {Rml::PropertyId::BorderTopColor, rml_color(ElevatedBorder)}, - {Rml::PropertyId::BorderRightColor, rml_color(ElevatedBorder)}, - {Rml::PropertyId::BorderBottomColor, rml_color(ElevatedBorder)}, - {Rml::PropertyId::BorderLeftColor, rml_color(ElevatedBorder)}, - {Rml::PropertyId::BackgroundColor, rml_color(ElevatedSoft)}, - }); -} - -} // namespace dusk::ui::prelaunch::layout diff --git a/src/dusk/ui/prelaunch_layout.hpp b/src/dusk/ui/prelaunch_layout.hpp deleted file mode 100644 index 11efea9b4f..0000000000 --- a/src/dusk/ui/prelaunch_layout.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include -#include - -#include - -namespace dusk::ui::prelaunch::layout { - -enum class ScreenLayout { - Standard, - CompactSplit, -}; - -void style_document(Rml::ElementDocument* document); -Rml::Element* add_screen( - Rml::ElementDocument* document, ScreenLayout layout = ScreenLayout::Standard); -Rml::Element* add_brand(Rml::Element* parent, std::string_view logoPath, bool compact = false); -Rml::Element* add_heading(Rml::Element* parent, std::string_view title); -Rml::Element* add_panel(Rml::Element* parent, bool wide, bool compact = false); - -} // namespace dusk::ui::prelaunch::layout diff --git a/src/dusk/ui/prelaunch_screen.cpp b/src/dusk/ui/prelaunch_screen.cpp deleted file mode 100644 index 45525c6af7..0000000000 --- a/src/dusk/ui/prelaunch_screen.cpp +++ /dev/null @@ -1,933 +0,0 @@ -#include "prelaunch_screen.hpp" - -#include "button.hpp" -#include "disc_state.hpp" -#include "game_option.hpp" -#include "prelaunch_layout.hpp" -#include "ui.hpp" - -#include "../file_select.hpp" -#include "../iso_validate.hpp" -#include "dusk/config.hpp" -#include "dusk/main.h" -#include "dusk/settings.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "aurora/lib/window.hpp" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace dusk::ui::prelaunch { -namespace { - -enum class View { - Main, - Options, - LanguageSelect, - GraphicsBackendSelect, - SaveFileTypeSelect, -}; - -struct BackendChoice { - AuroraBackend backend = BACKEND_AUTO; - std::string id; - std::string name; -}; - -constexpr std::array kLanguageNames = { - "English", - "German", - "French", - "Spanish", - "Italian", -}; - -constexpr std::array kGameDiscFileFilters{{ - {"Game Disc Images", "iso;gcm;ciso;gcz;nfs;rvz;wbfs;wia;tgc"}, - {"All Files", "*"}, -}}; - -std::string iso_validation_error_message(iso::ValidationError code) { - switch (code) { - case iso::ValidationError::IOError: - return "Unable to read selected disc image"; - case iso::ValidationError::InvalidImage: - return "Unable to interpret selected file as a disc image"; - case iso::ValidationError::WrongGame: - return "Disc is for a different game"; - case iso::ValidationError::WrongVersion: - return "Disc is for an unsupported version. Only NTSC & PAL GameCube are " - "supported at this time"; - case iso::ValidationError::ExecutableMismatch: - return "Disc contains modified executable files"; - case iso::ValidationError::Success: - return {}; - case iso::ValidationError::Unknown: - default: - return "Unknown disc validation error"; - } -} - -std::string_view backend_name(AuroraBackend backend) { - switch (backend) { - default: - return "Auto"; - case BACKEND_D3D12: - return "D3D12"; - case BACKEND_D3D11: - return "D3D11"; - case BACKEND_METAL: - return "Metal"; - case BACKEND_VULKAN: - return "Vulkan"; - case BACKEND_OPENGL: - return "OpenGL"; - case BACKEND_OPENGLES: - return "OpenGL ES"; - case BACKEND_WEBGPU: - return "WebGPU"; - case BACKEND_NULL: - return "Null"; - } -} - -std::string_view backend_id(AuroraBackend backend) { - switch (backend) { - default: - return "auto"; - case BACKEND_D3D12: - return "d3d12"; - case BACKEND_D3D11: - return "d3d11"; - case BACKEND_METAL: - return "metal"; - case BACKEND_VULKAN: - return "vulkan"; - case BACKEND_OPENGL: - return "opengl"; - case BACKEND_OPENGLES: - return "opengles"; - case BACKEND_WEBGPU: - return "webgpu"; - case BACKEND_NULL: - return "null"; - } -} - -bool try_parse_backend(std::string_view backend, AuroraBackend& outBackend) { - if (backend == "auto") { - outBackend = BACKEND_AUTO; - return true; - } - if (backend == "d3d11") { - outBackend = BACKEND_D3D11; - return true; - } - if (backend == "d3d12") { - outBackend = BACKEND_D3D12; - return true; - } - if (backend == "metal") { - outBackend = BACKEND_METAL; - return true; - } - if (backend == "vulkan") { - outBackend = BACKEND_VULKAN; - return true; - } - if (backend == "opengl") { - outBackend = BACKEND_OPENGL; - return true; - } - if (backend == "opengles") { - outBackend = BACKEND_OPENGLES; - return true; - } - if (backend == "webgpu") { - outBackend = BACKEND_WEBGPU; - return true; - } - if (backend == "null") { - outBackend = BACKEND_NULL; - return true; - } - return false; -} - -std::string_view card_type_name(CARDFileType type) { - switch (type) { - case CARD_GCIFOLDER: - return "GCI Folder"; - case CARD_RAWIMAGE: - return "Card Image"; - default: - return ""; - } -} - -std::filesystem::path resource_path(const char* filename) { - const char* basePath = SDL_GetBasePath(); - if (basePath == nullptr) { - return std::filesystem::path("res") / filename; - } - return std::filesystem::path(basePath) / "res" / filename; -} - -std::string display_path(std::string_view path) { - const char* home = SDL_GetUserFolder(SDL_FOLDER_HOME); - if (home == nullptr || home[0] == '\0') { - home = std::getenv("HOME"); - } - if (home == nullptr || home[0] == '\0') { - return std::string(path); - } - - std::string homePath(home); - while (homePath.size() > 1 && homePath.back() == '/') { - homePath.pop_back(); - } - - if (path == homePath) { - return "~"; - } - - if (path.size() > homePath.size() && path.substr(0, homePath.size()) == homePath && - path[homePath.size()] == '/') - { - return "~" + std::string(path.substr(homePath.size())); - } - - return std::string(path); -} - -std::vector backend_choices() { - std::vector choices; - choices.push_back({BACKEND_AUTO, std::string(backend_id(BACKEND_AUTO)), - std::string(backend_name(BACKEND_AUTO))}); - - size_t backendCount = 0; - const AuroraBackend* availableBackends = aurora_get_available_backends(&backendCount); - for (size_t i = 0; i < backendCount; ++i) { - const AuroraBackend backend = availableBackends[i]; - choices.push_back( - {backend, std::string(backend_id(backend)), std::string(backend_name(backend))}); - } - - return choices; -} - -class Screen : public Rml::EventListener { -public: - bool initialize() { - if (m_initialized) { - return true; - } - if (!ui::initialize()) { - return false; - } - - m_selectedIsoPath = getSettings().backend.isoPath.getValue(); - validate_selected_iso(false); - m_initialGraphicsBackend = getSettings().backend.graphicsBackend.getValue(); - m_initialized = true; - - if (is_selected_path_valid() && getSettings().backend.skipPreLaunchUI.getValue()) { - IsGameLaunched = true; - return true; - } - - set_active(true); - rebuild(); - if (m_document == nullptr) { - shutdown(); - return false; - } - return true; - } - - void shutdown() { - close_document(); - set_active(false); - m_initialized = false; - m_focusIds.clear(); - } - - bool is_active() const { return m_initialized && ui::is_active(); } - - void handle_event(const SDL_Event& event) { ui::handle_event(event); } - - void update() { - if (m_requestedBack) { - m_requestedBack = false; - back(); - if (!is_active()) { - return; - } - } - - if (!m_requestedActivation.empty()) { - const std::string requestedActivation = m_requestedActivation; - m_requestedActivation.clear(); - activate(requestedActivation); - if (!is_active()) { - return; - } - } - - if (m_requestedCycleDirection != 0) { - const std::string requestedCycleId = m_requestedCycleId; - const int requestedCycleDirection = m_requestedCycleDirection; - m_requestedCycleId.clear(); - m_requestedCycleDirection = 0; - cycle_option(requestedCycleId, requestedCycleDirection); - if (!is_active()) { - return; - } - } - - if (is_selected_path_valid() && getSettings().backend.skipPreLaunchUI.getValue()) { - IsGameLaunched = true; - shutdown(); - return; - } - - ui::update(); - rebuild_if_layout_changed(); - } - - void ProcessEvent(Rml::Event& event) override { - if (event.GetId() == Rml::EventId::Keydown) { - const auto key = static_cast( - event.GetParameter("key_identifier", Rml::Input::KI_UNKNOWN)); - if (handle_key(key)) { - event.StopImmediatePropagation(); - } - } - } - -private: - bool m_initialized = false; - View m_view = View::Main; - Rml::ElementDocument* m_document = nullptr; - std::vector m_focusIds; - std::vector > m_buttons; - std::unique_ptr m_discState; - std::vector > m_options; - std::string m_pendingFocusId; - std::string m_requestedActivation; - std::string m_requestedCycleId; - int m_requestedCycleDirection = 0; - bool m_requestedBack = false; - std::string m_selectedIsoPath; - std::string m_errorString; - std::string m_initialGraphicsBackend; - bool m_compactLayout = false; - bool m_selectedIsoValid = false; - bool m_isPal = false; - - bool selected_path_exists() const { -#if TARGET_ANDROID - return !m_selectedIsoPath.empty(); -#else - return !m_selectedIsoPath.empty() && SDL_GetPathInfo(m_selectedIsoPath.c_str(), nullptr); -#endif - } - - bool is_selected_path_valid() const { return m_selectedIsoValid; } - - void validate_selected_iso(bool save_valid_path) { - m_errorString.clear(); - m_selectedIsoValid = false; - m_isPal = false; - - if (m_selectedIsoPath.empty()) { - return; - } - - if (!selected_path_exists()) { - m_errorString = "Selected disc image does not exist"; - return; - } - - const iso::ValidationError validationResult = iso::validate(m_selectedIsoPath.c_str()); - if (validationResult != iso::ValidationError::Success) { - m_errorString = iso_validation_error_message(validationResult); - return; - } - - m_selectedIsoValid = true; - m_isPal = iso::isPal(m_selectedIsoPath.c_str()); - if (save_valid_path) { - getSettings().backend.isoPath.setValue(m_selectedIsoPath); - Save(); - } - } - - void close_document() { - if (m_document == nullptr) { - return; - } - - m_document->RemoveEventListener(Rml::EventId::Keydown, this); - m_buttons.clear(); - m_discState.reset(); - m_options.clear(); - m_focusIds.clear(); - m_document->Close(); - m_document = nullptr; - } - - std::string logo_path() const { - const auto logo_path = resource_path("logo-mascot.png"); - if (std::filesystem::exists(logo_path)) { - return logo_path.string(); - } - - return {}; - } - - std::string selected_disc_text() const { - if (!m_selectedIsoPath.empty()) { - return display_path(m_selectedIsoPath); - } - - return "Select a disc..."; - } - - std::string disc_status_text() const { - if (!m_errorString.empty()) { - return m_errorString; - } - if (is_selected_path_valid()) { - return fmt::format("Disc region: {}", m_isPal ? "PAL" : "NTSC"); - } - return {}; - } - - bool should_use_compact_layout() const { - Rml::Context* context = aurora::rmlui::get_context(); - if (context == nullptr) { - return false; - } - - const Rml::Vector2i dimensions = context->GetDimensions(); - float dp_ratio = context->GetDensityIndependentPixelRatio(); - if (dp_ratio <= 0.0f) { - dp_ratio = 1.0f; - } - - const float width = static_cast(dimensions.x) / dp_ratio; - const float height = static_cast(dimensions.y) / dp_ratio; - return height < 680.0f && width >= 720.0f; - } - - void rebuild_if_layout_changed() { - const bool compactLayout = should_use_compact_layout(); - if (compactLayout == m_compactLayout) { - return; - } - - if (Rml::Context* context = aurora::rmlui::get_context()) { - if (Rml::Element* focused = context->GetFocusElement()) { - m_pendingFocusId = focused->GetId(); - } - } - rebuild(); - } - - void queue_activation(std::string id) { m_requestedActivation = std::move(id); } - - void queue_back() { m_requestedBack = true; } - - void queue_cycle(std::string id, int direction) { - m_requestedCycleId = std::move(id); - m_requestedCycleDirection = direction; - } - - void add_button_control( - Rml::Element* parent, std::string_view id, std::string_view text, ButtonVariant variant) { - const std::string idString(id); - m_focusIds.push_back(idString); - m_buttons.push_back(std::make_unique + +
+ + + +)RML"; + +bool setup_window_model(Rml::Context* context, WindowModel& model, Rml::DataModelHandle& handle) { + Rml::DataModelConstructor constructor = context->CreateDataModel("window"); + if (!constructor) { + return false; } - const bool active = m_hovered || m_focused; - - int textOpacity; - if (m_selected) { - textOpacity = 255; - } else if (active) { - textOpacity = 200; + if (auto tab_handle = constructor.RegisterStruct()) { + tab_handle.RegisterMember("label", &WindowTab::label); } else { - textOpacity = 110; - } - const Color textColor = m_selected ? TextActive : Text; - m_label->SetProperty(Rml::PropertyId::Color, rml_color(textColor, textOpacity)); - - if (m_indicator != nullptr) { - const int indicatorOpacity = m_selected ? 255 : (active ? 96 : 0); - m_indicator->SetProperty( - Rml::PropertyId::BackgroundColor, rml_color(WindowAccent, indicatorOpacity)); + return false; } - set_focus_border_visible(m_element, m_focused); + if (!constructor.RegisterArray >()) { + return false; + } + + constructor.Bind("active_tab", &model.activeTab); + constructor.Bind("tabs", &model.tabs); + constructor.BindEventCallback("set_active_tab", &WindowModel::set_active_tab, &model); + + handle = constructor.GetModelHandle(); + return true; } -Window::Window(Rml::Element* parent, std::string_view id, std::function closeCallback) - : m_closeCallback(std::move(closeCallback)) { - using namespace theme; +} // namespace - m_element = append(parent, "div", id, - { - {Rml::PropertyId::Display, Rml::Style::Display::Flex}, - {Rml::PropertyId::FlexDirection, Rml::Style::FlexDirection::Column}, - {Rml::PropertyId::BoxSizing, Rml::Style::BoxSizing::BorderBox}, - {Rml::PropertyId::Width, rml_percent(100.0f)}, - {Rml::PropertyId::MaxWidth, rml_dp(1088.0f)}, - {Rml::PropertyId::BorderTopWidth, rml_dp(BorderWidth)}, - {Rml::PropertyId::BorderRightWidth, rml_dp(BorderWidth)}, - {Rml::PropertyId::BorderBottomWidth, rml_dp(BorderWidth)}, - {Rml::PropertyId::BorderLeftWidth, rml_dp(BorderWidth)}, - {Rml::PropertyId::BorderTopLeftRadius, rml_dp(BorderRadiusMedium)}, - {Rml::PropertyId::BorderTopRightRadius, rml_dp(BorderRadiusMedium)}, - {Rml::PropertyId::BorderBottomRightRadius, rml_dp(BorderRadiusMedium)}, - {Rml::PropertyId::BorderBottomLeftRadius, rml_dp(BorderRadiusMedium)}, - {Rml::PropertyId::BorderTopColor, rml_color(ElevatedBorder)}, - {Rml::PropertyId::BorderRightColor, rml_color(ElevatedBorder)}, - {Rml::PropertyId::BorderBottomColor, rml_color(ElevatedBorder)}, - {Rml::PropertyId::BorderLeftColor, rml_color(ElevatedBorder)}, - {Rml::PropertyId::BackgroundColor, rml_color(WindowSurface)}, - {Rml::PropertyId::OverflowX, Rml::Style::Overflow::Hidden}, - {Rml::PropertyId::OverflowY, Rml::Style::Overflow::Hidden}, - }); - set_props(m_element, { - {"backdrop-filter", "blur(5dp)"}, - {"box-shadow", "0 0 25dp 5dp"}, - }); +void WindowModel::set_active_tab( + Rml::DataModelHandle model, Rml::Event& event, const Rml::VariantList& arguments) { + if (arguments.empty()) { + return; + } - m_tabBar = append(m_element, "div", {}, - { - {Rml::PropertyId::Display, Rml::Style::Display::Flex}, - {Rml::PropertyId::Position, Rml::Style::Position::Relative}, - {Rml::PropertyId::FlexDirection, Rml::Style::FlexDirection::Row}, - {Rml::PropertyId::AlignItems, Rml::Style::AlignItems::Center}, - {Rml::PropertyId::BoxSizing, Rml::Style::BoxSizing::BorderBox}, - {Rml::PropertyId::Width, rml_percent(100.0f)}, - {Rml::PropertyId::Height, rml_dp(WindowTabBarHeight)}, - {Rml::PropertyId::MinHeight, rml_dp(WindowTabBarHeight)}, - {Rml::PropertyId::PaddingLeft, rml_dp(12.0f)}, - {Rml::PropertyId::PaddingRight, rml_dp(12.0f)}, - {Rml::PropertyId::RowGap, rml_dp(4.0f)}, - {Rml::PropertyId::ColumnGap, rml_dp(4.0f)}, - {Rml::PropertyId::BackgroundColor, rml_color(WindowTitleOverlay)}, - {Rml::PropertyId::BorderBottomWidth, rml_dp(BorderWidth * 1.5f)}, - {Rml::PropertyId::BorderBottomColor, rml_color(WindowDivider)}, - }); + const int tabIndex = arguments[0].Get(); + if (tabIndex < 0 || tabIndex >= static_cast(tabs.size()) || tabIndex == activeTab) { + return; + } - m_tabStrip = append(m_tabBar, "div", {}, - { - {Rml::PropertyId::Display, Rml::Style::Display::Flex}, - {Rml::PropertyId::FlexDirection, Rml::Style::FlexDirection::Row}, - {Rml::PropertyId::AlignItems, Rml::Style::AlignItems::Stretch}, - {Rml::PropertyId::JustifyContent, Rml::Style::JustifyContent::FlexStart}, - {Rml::PropertyId::FlexGrow, rml_number(1.0f)}, - {Rml::PropertyId::FlexShrink, rml_number(1.0f)}, - {Rml::PropertyId::MinWidth, rml_px(0.0f)}, - {Rml::PropertyId::Height, rml_percent(100.0f)}, - {Rml::PropertyId::RowGap, rml_dp(4.0f)}, - {Rml::PropertyId::ColumnGap, rml_dp(4.0f)}, - }); + activeTab = tabIndex; + model.DirtyVariable("active_tab"); - const std::string closeId = id.empty() ? std::string{} : std::string(id) + "-close"; - m_closeButton = append(m_tabBar, "button", closeId, - { - {Rml::PropertyId::Display, Rml::Style::Display::Flex}, - {Rml::PropertyId::Position, Rml::Style::Position::Relative}, - {Rml::PropertyId::AlignItems, Rml::Style::AlignItems::Center}, - {Rml::PropertyId::JustifyContent, Rml::Style::JustifyContent::Center}, - {Rml::PropertyId::BoxSizing, Rml::Style::BoxSizing::BorderBox}, - {Rml::PropertyId::Width, rml_dp(36.0f)}, - {Rml::PropertyId::Height, rml_dp(36.0f)}, - {Rml::PropertyId::FlexShrink, rml_number(0.0f)}, - {Rml::PropertyId::BorderTopWidth, rml_px(0.0f)}, - {Rml::PropertyId::BorderRightWidth, rml_px(0.0f)}, - {Rml::PropertyId::BorderBottomWidth, rml_px(0.0f)}, - {Rml::PropertyId::BorderLeftWidth, rml_px(0.0f)}, - {Rml::PropertyId::BorderTopLeftRadius, rml_dp(BorderRadiusSmall)}, - {Rml::PropertyId::BorderTopRightRadius, rml_dp(BorderRadiusSmall)}, - {Rml::PropertyId::BorderBottomRightRadius, rml_dp(BorderRadiusSmall)}, - {Rml::PropertyId::BorderBottomLeftRadius, rml_dp(BorderRadiusSmall)}, - {Rml::PropertyId::BackgroundColor, rml_color(Transparent)}, - {Rml::PropertyId::Cursor, rml_string("pointer")}, - {Rml::PropertyId::TabIndex, Rml::Style::TabIndex::Auto}, - {Rml::PropertyId::FontFamily, rml_string("Inter")}, - }); - add_focus_border(m_closeButton, BorderRadiusSmall); + // Replace window content with new tab content + auto* currentElem = event.GetCurrentElement(); + if (currentElem == nullptr) { + return; + } + auto* doc = currentElem->GetOwnerDocument(); + if (doc == nullptr) { + return; + } + auto* content = doc->GetElementById("content"); + if (content == nullptr) { + return; + } + while (content->GetNumChildren() > 0) { + content->RemoveChild(content->GetFirstChild()); + } + if (tabs[tabIndex].setContent) { + tabs[tabIndex].setContent(content); + } +} - auto* closeGlyph = append(m_closeButton, "span", {}, - { - {Rml::PropertyId::FontSize, rml_dp(22.0f)}, - {Rml::PropertyId::FontWeight, Rml::Style::FontWeight::Normal}, - {Rml::PropertyId::Color, rml_color(WindowGlyph)}, - {Rml::PropertyId::PointerEvents, Rml::Style::PointerEvents::None}, - }); - set_text(closeGlyph, "\xc3\x97"); - - m_closeButton->AddEventListener(Rml::EventId::Click, this); - m_closeButton->AddEventListener(Rml::EventId::Focus, this); - m_closeButton->AddEventListener(Rml::EventId::Blur, this); - m_closeButton->AddEventListener(Rml::EventId::Mouseover, this); - m_closeButton->AddEventListener(Rml::EventId::Mouseout, this); - - m_contentRow = append(m_element, "div", {}, - { - {Rml::PropertyId::Display, Rml::Style::Display::Flex}, - {Rml::PropertyId::FlexDirection, Rml::Style::FlexDirection::Row}, - {Rml::PropertyId::AlignItems, Rml::Style::AlignItems::Stretch}, - {Rml::PropertyId::BoxSizing, Rml::Style::BoxSizing::BorderBox}, - {Rml::PropertyId::Width, rml_percent(100.0f)}, - {Rml::PropertyId::FlexGrow, rml_number(1.0f)}, - {Rml::PropertyId::FlexShrink, rml_number(1.0f)}, - {Rml::PropertyId::MinHeight, rml_px(0.0f)}, - {Rml::PropertyId::MinWidth, rml_px(0.0f)}, - {Rml::PropertyId::RowGap, rml_dp(20.0f)}, - {Rml::PropertyId::ColumnGap, rml_dp(20.0f)}, - }); - - m_leftPane = append(m_contentRow, "div", {}, - { - {Rml::PropertyId::Display, Rml::Style::Display::Flex}, - {Rml::PropertyId::FlexDirection, Rml::Style::FlexDirection::Column}, - {Rml::PropertyId::BoxSizing, Rml::Style::BoxSizing::BorderBox}, - {Rml::PropertyId::MinWidth, rml_px(0.0f)}, - {Rml::PropertyId::MinHeight, rml_px(0.0f)}, - {Rml::PropertyId::PaddingTop, rml_dp(24.0f)}, - {Rml::PropertyId::PaddingRight, rml_dp(24.0f)}, - {Rml::PropertyId::PaddingBottom, rml_dp(24.0f)}, - {Rml::PropertyId::PaddingLeft, rml_dp(24.0f)}, - {Rml::PropertyId::RowGap, rml_dp(12.0f)}, - {Rml::PropertyId::ColumnGap, rml_dp(12.0f)}, - }); - - m_rightPane = append(m_contentRow, "div", {}, - { - {Rml::PropertyId::Display, Rml::Style::Display::None}, - {Rml::PropertyId::FlexDirection, Rml::Style::FlexDirection::Column}, - {Rml::PropertyId::BoxSizing, Rml::Style::BoxSizing::BorderBox}, - {Rml::PropertyId::MinWidth, rml_px(0.0f)}, - {Rml::PropertyId::MinHeight, rml_px(0.0f)}, - {Rml::PropertyId::PaddingTop, rml_dp(24.0f)}, - {Rml::PropertyId::PaddingBottom, rml_dp(24.0f)}, - {Rml::PropertyId::PaddingRight, rml_dp(24.0f)}, - {Rml::PropertyId::PaddingLeft, rml_dp(8.0f)}, - {Rml::PropertyId::AlignItems, Rml::Style::AlignItems::FlexStart}, - {Rml::PropertyId::OverflowY, Rml::Style::Overflow::Auto}, - }); - - m_rightPane = append(m_contentRow, "div", {}, - { - {Rml::PropertyId::Display, Rml::Style::Display::None}, - {Rml::PropertyId::FlexDirection, Rml::Style::FlexDirection::Column}, - {Rml::PropertyId::BoxSizing, Rml::Style::BoxSizing::BorderBox}, - {Rml::PropertyId::MinWidth, rml_px(0.0f)}, - {Rml::PropertyId::MinHeight, rml_px(0.0f)}, - {Rml::PropertyId::PaddingTop, rml_dp(24.0f)}, - {Rml::PropertyId::PaddingBottom, rml_dp(24.0f)}, - {Rml::PropertyId::PaddingRight, rml_dp(24.0f)}, - {Rml::PropertyId::PaddingLeft, rml_dp(8.0f)}, - {Rml::PropertyId::AlignItems, Rml::Style::AlignItems::FlexStart}, - {Rml::PropertyId::OverflowY, Rml::Style::Overflow::Auto}, - }); - - apply_pane_layout(); - apply_close_style(); +Window::Window(WindowModel model) : mModel(std::move(model)) { + auto* context = aurora::rmlui::get_context(); + if (context == nullptr) { + return; + } + setup_window_model(context, mModel, mModelHandle); + mDocument = context->LoadDocumentFromMemory(kWindowDocumentRml); + if (mDocument == nullptr) { + return; + } + mModel.tabs[0].setContent(mDocument->GetElementById("content")); } Window::~Window() { - m_tabs.clear(); - if (m_closeButton != nullptr) { - m_closeButton->RemoveEventListener(Rml::EventId::Click, this); - m_closeButton->RemoveEventListener(Rml::EventId::Focus, this); - m_closeButton->RemoveEventListener(Rml::EventId::Blur, this); - m_closeButton->RemoveEventListener(Rml::EventId::Mouseover, this); - m_closeButton->RemoveEventListener(Rml::EventId::Mouseout, this); - m_closeButton = nullptr; - } - m_element = nullptr; -} - -void Window::ProcessEvent(Rml::Event& event) { - if (event.GetTargetElement() != m_closeButton) { - return; - } - - switch (event.GetId()) { - case Rml::EventId::Click: - if (m_closeCallback) { - m_closeCallback(); - } - break; - case Rml::EventId::Focus: - m_closeFocused = true; - apply_close_style(); - break; - case Rml::EventId::Blur: - m_closeFocused = false; - apply_close_style(); - break; - case Rml::EventId::Mouseover: - m_closeHovered = true; - apply_close_style(); - break; - case Rml::EventId::Mouseout: - m_closeHovered = false; - apply_close_style(); - break; - default: - break; + auto* context = aurora::rmlui::get_context(); + if (context != nullptr && mDocument != nullptr) { + context->UnloadDocument(mDocument); + mDocument = nullptr; } } -WindowTab* Window::add_tab( - std::string_view id, std::string_view label, std::function selectedCallback) { - if (m_tabStrip == nullptr) { - return nullptr; - } - - const std::string idString(id); - auto wrapped = [this, idString, cb = std::move(selectedCallback)]() { - set_selected_tab(idString); - if (cb) { - cb(); - } - }; - auto tab = std::make_unique(m_tabStrip, idString, label, std::move(wrapped)); - WindowTab* raw = tab.get(); - m_tabs.push_back(std::move(tab)); - return raw; -} - -void Window::set_selected_tab(std::string_view id) { - for (auto& tab : m_tabs) { - tab->set_selected(tab->id() == id); +void Window::show() { + if (mDocument != nullptr) { + mDocument->Show(); } } -std::string Window::selected_tab_id() const { - for (const auto& tab : m_tabs) { - if (tab->is_selected()) { - return tab->id(); - } - } - return {}; -} - -void Window::set_right_pane_visible(bool visible) { - if (m_rightPaneVisible == visible) { - return; - } - m_rightPaneVisible = visible; - apply_pane_layout(); -} - -void Window::apply_pane_layout() { - using namespace theme; - - if (m_leftPane == nullptr || m_rightPane == nullptr) { - return; - } - - if (m_rightPaneVisible) { - set_props(m_leftPane, { - {Rml::PropertyId::Display, Rml::Style::Display::Flex}, - {Rml::PropertyId::FlexGrow, rml_number(1.0f)}, - {Rml::PropertyId::FlexShrink, rml_number(1.0f)}, - {Rml::PropertyId::FlexBasis, rml_px(0.0f)}, - {Rml::PropertyId::MinWidth, rml_px(0.0f)}, - }); - set_props(m_rightPane, { - {Rml::PropertyId::Display, Rml::Style::Display::Flex}, - {Rml::PropertyId::FlexGrow, rml_number(0.0f)}, - {Rml::PropertyId::FlexShrink, rml_number(0.0f)}, - {Rml::PropertyId::FlexBasis, rml_percent(40.0f)}, - {Rml::PropertyId::MinWidth, rml_px(0.0f)}, - }); - } else { - set_props( - m_leftPane, { - {Rml::PropertyId::Display, Rml::Style::Display::Flex}, - {Rml::PropertyId::FlexGrow, rml_number(1.0f)}, - {Rml::PropertyId::FlexShrink, rml_number(1.0f)}, - {Rml::PropertyId::FlexBasis, Rml::Style::LengthPercentageAuto::Auto}, - {Rml::PropertyId::Width, rml_percent(100.0f)}, - }); - set_props(m_rightPane, { - {Rml::PropertyId::Display, Rml::Style::Display::None}, - }); +void Window::hide() { + if (mDocument != nullptr) { + mDocument->Hide(); } } -void Window::apply_close_style() { - using namespace theme; - - if (m_closeButton == nullptr) { - return; - } - - const bool active = m_closeHovered || m_closeFocused; - m_closeButton->SetProperty(Rml::PropertyId::BackgroundColor, - active ? rml_color(WindowAccent, 56) : rml_color(Transparent)); - set_focus_border_visible(m_closeButton, m_closeFocused); -} } // namespace dusk::ui diff --git a/src/dusk/ui/window.hpp b/src/dusk/ui/window.hpp index 66a30ad2b9..2faa4fb140 100644 --- a/src/dusk/ui/window.hpp +++ b/src/dusk/ui/window.hpp @@ -1,84 +1,35 @@ #pragma once -#include - -#include -#include -#include -#include -#include - -namespace Rml { -class Element; -} +#include +#include namespace dusk::ui { -class WindowTab : public Rml::EventListener { -public: - WindowTab(Rml::Element* parent, std::string_view id, std::string_view label, - std::function selectedCallback); - ~WindowTab() override; - WindowTab(const WindowTab&) = delete; - WindowTab& operator=(const WindowTab&) = delete; - - void ProcessEvent(Rml::Event& event) override; - - Rml::Element* element() const { return m_element; } - std::string id() const; - - void set_selected(bool selected); - bool is_selected() const { return m_selected; } - -private: - Rml::Element* m_element = nullptr; - Rml::Element* m_label = nullptr; - Rml::Element* m_indicator = nullptr; - std::function m_selectedCallback; - bool m_hovered = false; - bool m_focused = false; - bool m_selected = false; - - void apply_style(); +struct WindowTab { + Rml::String label; + std::function setContent; }; -class Window : public Rml::EventListener { +struct WindowModel { + int activeTab = 0; + std::vector tabs; + + void set_active_tab( + Rml::DataModelHandle model, Rml::Event& event, const Rml::VariantList& arguments); +}; + +class Window { public: - Window(Rml::Element* parent, std::string_view id, std::function closeCallback = {}); - ~Window() override; + Window(WindowModel model); + ~Window(); - Window(const Window&) = delete; - Window& operator=(const Window&) = delete; - - void ProcessEvent(Rml::Event& event) override; - - Rml::Element* element() const { return m_element; } - Rml::Element* body() const { return m_leftPane; } - Rml::Element* right_pane() const { return m_rightPane; } - void set_right_pane_visible(bool visible); - - Rml::Element* tab_strip() const { return m_tabStrip; } - - WindowTab* add_tab( - std::string_view id, std::string_view label, std::function selectedCallback); - void set_selected_tab(std::string_view id); - std::string selected_tab_id() const; + void show(); + void hide(); private: - Rml::Element* m_element = nullptr; - Rml::Element* m_tabBar = nullptr; - Rml::Element* m_tabStrip = nullptr; - Rml::Element* m_closeButton = nullptr; - Rml::Element* m_contentRow = nullptr; - Rml::Element* m_leftPane = nullptr; - Rml::Element* m_rightPane = nullptr; - bool m_rightPaneVisible = false; - std::function m_closeCallback; - std::vector > m_tabs; - bool m_closeHovered = false; - bool m_closeFocused = false; - - void apply_close_style(); - void apply_pane_layout(); + WindowModel mModel; + Rml::DataModelHandle mModelHandle; + Rml::ElementDocument* mDocument; }; -} // namespace dusk::ui + +} // namespace dusk::ui \ No newline at end of file diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index 80a0cd9e51..6f58b95e89 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -56,8 +56,8 @@ #include "dusk/logging.h" #include "dusk/main.h" #include "dusk/imgui/ImGuiConsole.hpp" -#include "dusk/ui/game_menu.hpp" -#include "dusk/ui/prelaunch_screen.hpp" +#include "dusk/ui/ui.hpp" +#include "dusk/ui/editor.hpp" #include "version.h" #include @@ -77,6 +77,7 @@ #include "tracy/Tracy.hpp" #include "f_pc/f_pc_draw.h" #include "tracy/Tracy.hpp" +#include // --- GLOBALS --- s8 mDoMain::developmentMode = -1; @@ -135,23 +136,18 @@ AuroraStats dusk::lastFrameAuroraStats; float dusk::frameUsagePct = 0.0f; bool launchUILoop() { - const bool useRmlPrelaunch = dusk::ui::prelaunch::initialize(); - while (dusk::IsRunning && !dusk::IsGameLaunched) { const AuroraEvent* event = aurora_update(); while (event != nullptr && event->type != AURORA_NONE) { switch (event->type) { case AURORA_SDL_EVENT: - if (useRmlPrelaunch) { - dusk::ui::prelaunch::handle_event(event->sdl); - } - // dusk::g_imguiConsole.HandleSDLEvent(event->sdl); + dusk::ui::handle_event(event->sdl); + dusk::g_imguiConsole.HandleSDLEvent(event->sdl); break; case AURORA_DISPLAY_SCALE_CHANGED: - // dusk::ImGuiEngine_Initialize(event->windowSize.scale); + dusk::ImGuiEngine_Initialize(event->windowSize.scale); break; case AURORA_EXIT: - dusk::ui::prelaunch::shutdown(); return false; } @@ -163,15 +159,13 @@ bool launchUILoop() { continue; } - if (useRmlPrelaunch) { - dusk::ui::prelaunch::update(); - } + dusk::g_imguiConsole.PreDraw(); + + dusk::g_imguiConsole.PostDraw(); aurora_end_frame(); } - dusk::ui::prelaunch::shutdown(); - return dusk::IsRunning; } @@ -214,7 +208,6 @@ void main01(void) { OSReport("Entering Main Loop (main01)...\n"); dusk::game_clock::ensure_initialized(); - dusk::ui::game_menu::initialize(); do { // 1. Update Window Events @@ -224,7 +217,8 @@ void main01(void) { case AURORA_NONE: goto eventsDone; case AURORA_SDL_EVENT: - dusk::ui::game_menu::handle_event(event->sdl); + dusk::ui::handle_event(event->sdl); + dusk::g_imguiConsole.HandleSDLEvent(event->sdl); if (event->sdl.type == SDL_EVENT_WINDOW_FOCUS_LOST && dusk::getSettings().game.pauseOnFocusLost) { dusk::IsFocusPaused = true; @@ -236,6 +230,9 @@ void main01(void) { dusk::game_clock::reset_frame_timer(); } break; + case AURORA_DISPLAY_SCALE_CHANGED: + dusk::ImGuiEngine_Initialize(event->windowSize.scale); + break; case AURORA_EXIT: goto exit; } @@ -260,7 +257,7 @@ void main01(void) { mDoGph_gInf_c::updateRenderSize(); - dusk::ui::game_menu::update(); + dusk::ui::update(); const auto pacing = dusk::game_clock::advance_main_loop(); if (pacing.is_interpolating) { @@ -313,7 +310,7 @@ void main01(void) { } while (dusk::IsRunning); exit:; - dusk::ui::game_menu::shutdown(); + dusk::ui::shutdown(); } static bool IsBackendAvailable(AuroraBackend backend) { @@ -359,6 +356,11 @@ static AuroraBackend ResolveDesiredBackend(const cxxopts::ParseResult& parsedArg return desiredBackend; } +static void aurora_imgui_init_callback(const AuroraWindowSize* size) { + dusk::ImGuiEngine_Initialize(size->scale); + dusk::ImGuiEngine_AddTextures(); +} + static void ApplyCVarOverrides(const cxxopts::OptionValue& option) { if (option.count() == 0) { return; @@ -559,6 +561,7 @@ int game_main(int argc, char* argv[]) { config.mem1Size = 256 * 1024 * 1024; config.mem2Size = 24 * 1024 * 1024; config.allowJoystickBackgroundEvents = true; + config.imGuiInitCallback = &aurora_imgui_init_callback; config.allowTextureReplacements = true; config.allowTextureDumps = false; auroraInfo = aurora_initialize(argc, argv, &config); @@ -581,6 +584,11 @@ int game_main(int argc, char* argv[]) { dusk::audio::SetMasterVolume(dusk::getSettings().audio.masterVolume / 100.0f); dusk::audio::SetEnableReverb(dusk::getSettings().audio.enableReverb); + dusk::ui::initialize(); + + // TODO: just for testing + dusk::ui::EditorWindow editorWindow; + editorWindow.show(); std::string dvd_path; bool dvd_opened = false; @@ -659,6 +667,7 @@ int game_main(int argc, char* argv[]) { #ifdef DUSK_DISCORD_RPC dusk::discord::Shutdown(); #endif + dusk::ui::shutdown(); aurora_shutdown(); return 0; From b48d9aa0520a790ebddb794fca742123f2f8d06d Mon Sep 17 00:00:00 2001 From: Irastris Date: Tue, 28 Apr 2026 19:09:47 -0400 Subject: [PATCH 092/390] Split window document and styles out to files for readability --- res/rcss/window.rcss | 142 +++++++++++++++++++++++++++++++++++ res/rml/window.rml | 19 +++++ src/dusk/ui/window.cpp | 167 +---------------------------------------- 3 files changed, 162 insertions(+), 166 deletions(-) create mode 100644 res/rcss/window.rcss create mode 100644 res/rml/window.rml diff --git a/res/rcss/window.rcss b/res/rcss/window.rcss new file mode 100644 index 0000000000..1596be869e --- /dev/null +++ b/res/rcss/window.rcss @@ -0,0 +1,142 @@ +*, *:before, *:after { + box-sizing: border-box; +} + +body { + width: 100%; + height: 100%; + padding: 64dp; + font-family: "Fira Sans"; + font-weight: normal; + font-style: normal; + font-size: 15dp; + color: #E0DBC8; +} + +.window { + max-width: 1088dp; + max-height: 768dp; + margin: auto; + border-radius: 14dp; + overflow: hidden; + border: 2dp #92875B; + backdrop-filter: blur(5dp); + box-shadow: 0 0 25dp 5dp; + background-color: rgba(21, 22, 16, 90%); +} + +.window .tab-bar { + display: flex; + height: 64dp; + background-color: rgba(217, 217, 217, 10%); + font-family: "Fira Sans Condensed"; + font-weight: bold; + font-size: 18dp; + text-transform: uppercase; + border-bottom: 2dp #92875B; +} + +.window .tab-bar .tab { + padding: 0 24dp; + line-height: 64dp; + opacity: 0.25; + tab-index: auto; + nav: horizontal; + focus: auto; +} + +.window .tab-bar .tab.active { + opacity: 1; + border-bottom: 4dp #C2A42D; + font-effect: glow(0dp 4dp 0dp 4dp black); + decorator: linear-gradient(to bottom, rgba(194, 164, 45, 0%) 0%, rgba(194, 164, 45, 15%) 100%); +} + +.window .tab-bar .tab:focus-visible { + opacity: 1; + font-effect: glow(0dp 4dp 0dp 4dp black); + decorator: linear-gradient(to bottom, rgba(194, 164, 45, 0%) 0%, rgba(194, 164, 45, 15%) 100%); +} + +.window .content { + display: flex; + height: 100%; +} + +.window .content .pane { + display: flex; + flex-flow: column; + flex: 1 1 0; + height: 100%; + padding: 24dp; + gap: 8dp; + overflow: auto; +} + +.window .content .pane:not(:last-of-type) { + border-right: 1dp #92875B; +} + +.section-heading { + font-weight: bold; + text-transform: uppercase; + font-size: 22dp; + opacity: 0.25; +} + +.button { + text-align: center; + background-color: rgba(17, 16, 10, 20%); + opacity: 0.9; + padding: 8dp 16dp; + border-radius: 14dp; + box-shadow: rgba(146, 135, 91, 25%) 0 0 0 1dp; + font-size: 20dp; + transition: background-color 0.1s linear-in-out, opacity 0.1s linear-in-out; +} + +.button.active, .button:hover { + background-color: rgba(204, 184, 119, 20%); + box-shadow: #C2A42D 0 0 0 2dp; +} + +.button.selected, .button:active { + opacity: 1; + background-color: rgba(204, 184, 119, 40%); + box-shadow: #C2A42D 0 0 0 2dp; +} + +.select-button { + display: flex; + align-items: center; + gap: 8dp; + background-color: rgba(17, 16, 10, 20%); + opacity: 0.9; + padding: 8dp 16dp; + border-radius: 14dp; + box-shadow: rgba(146, 135, 91, 25%) 0 0 0 1dp; + transition: background-color 0.1s linear-in-out, opacity 0.1s linear-in-out; +} + +.select-button.active, .select-button:hover { + background-color: rgba(204, 184, 119, 20%); + box-shadow: #C2A42D 0 0 0 2dp; +} + +.select-button.selected, .select-button:active { + opacity: 1; + background-color: rgba(204, 184, 119, 40%); + box-shadow: #C2A42D 0 0 0 2dp; +} + +.select-button .key { + font-family: "Fira Sans Condensed"; + font-weight: bold; + font-size: 18dp; + text-transform: uppercase; +} + +.select-button .value { + margin-left: auto; + font-size: 20dp; +} diff --git a/res/rml/window.rml b/res/rml/window.rml new file mode 100644 index 0000000000..93a4397ae1 --- /dev/null +++ b/res/rml/window.rml @@ -0,0 +1,19 @@ + + + Window + + + +
+
+ +
+
+
+ +
diff --git a/src/dusk/ui/window.cpp b/src/dusk/ui/window.cpp index 749d737385..e7ac3eb3c6 100644 --- a/src/dusk/ui/window.cpp +++ b/src/dusk/ui/window.cpp @@ -7,171 +7,6 @@ namespace dusk::ui { namespace { -const Rml::String kWindowDocumentRml = R"RML( - - - Window - - - -
-
- -
-
-
- -
-)RML"; - bool setup_window_model(Rml::Context* context, WindowModel& model, Rml::DataModelHandle& handle) { Rml::DataModelConstructor constructor = context->CreateDataModel("window"); if (!constructor) { @@ -239,7 +74,7 @@ Window::Window(WindowModel model) : mModel(std::move(model)) { return; } setup_window_model(context, mModel, mModelHandle); - mDocument = context->LoadDocumentFromMemory(kWindowDocumentRml); + mDocument = context->LoadDocument("res/rml/window.rml"); if (mDocument == nullptr) { return; } From f75faf6b06c60bb642df15d94db86b4dd23d7c1c Mon Sep 17 00:00:00 2001 From: gymnast86 Date: Tue, 28 Apr 2026 18:03:06 -0700 Subject: [PATCH 093/390] fix instant text clearing shop messages too early --- include/d/d_msg_object.h | 3 +++ src/d/d_msg_class.cpp | 9 +-------- src/d/d_msg_object.cpp | 38 +++++++++++++++++++++++++++++++++++++- 3 files changed, 41 insertions(+), 9 deletions(-) diff --git a/include/d/d_msg_object.h b/include/d/d_msg_object.h index b55ea73904..d2ac4ecb2a 100644 --- a/include/d/d_msg_object.h +++ b/include/d/d_msg_object.h @@ -67,6 +67,9 @@ public: bool isStaffMessage(); bool isSaveMessage(); bool isTalkMessage(); +#if TARGET_PC + bool isShopItemMessage(); +#endif const char* getSmellName(); const char* getPortalName(); const char* getBombName(); diff --git a/src/d/d_msg_class.cpp b/src/d/d_msg_class.cpp index 4040eb0d7f..fab6906ee0 100644 --- a/src/d/d_msg_class.cpp +++ b/src/d/d_msg_class.cpp @@ -1987,13 +1987,6 @@ bool jmessage_tSequenceProcessor::do_isReady() { } #endif -#if TARGET_PC - if (dusk::getSettings().game.instantText && mDoCPd_c::getHoldB(0)) { - field_0xb2 = 1; - pReference->setSendTimer(0); - } -#endif - if (dComIfGp_checkMesgBgm()) { bool isItemMusicPlaying = true; if (mDoAud_checkPlayingSubBgmFlag() != Z2BGM_ITEM_GET && @@ -2066,7 +2059,7 @@ bool jmessage_tSequenceProcessor::do_isReady() { case 0: case 5: case 6: - if (mDoCPd_c::getTrigA(PAD_1) || field_0xb2 != 0) { + if (mDoCPd_c::getTrigA(PAD_1) || field_0xb2 != 0 IF_DUSK(|| (dusk::getSettings().game.instantText && mDoCPd_c::getHoldB(0)))) { field_0xa4 = 0; pReference->onBatchFlag(); pReference->setCharCnt(D_MSG_CLASS_CHAR_CNT_MAX); diff --git a/src/d/d_msg_object.cpp b/src/d/d_msg_object.cpp index ae0e3d8427..22e722d790 100644 --- a/src/d/d_msg_object.cpp +++ b/src/d/d_msg_object.cpp @@ -32,6 +32,8 @@ #if TARGET_PC #include "dusk/settings.h" +#include +#include #endif static void dMsgObject_addFundRaising(s16 param_0); @@ -1594,7 +1596,7 @@ u8 dMsgObject_c::isSend() { return 2; } } else { - if (IF_DUSK((dusk::getSettings().game.instantText && mDoCPd_c::getHoldB(0)) ||) + if (IF_DUSK((dusk::getSettings().game.instantText && mDoCPd_c::getHoldB(0) && !isShopItemMessage()) ||) mDoCPd_c::getTrigA(0) != 0 || mDoCPd_c::getTrigB(0) != 0) { return 2; } @@ -1866,6 +1868,40 @@ bool dMsgObject_c::isTalkMessage() { return true; } +#if TARGET_PC +bool dMsgObject_c::isShopItemMessage() { + + // Probably a better way to do this than just listing every message id, but this works for now + // Note: Keep contents sorted so we can use binary search + const auto shopMsgIds = std::to_array>({ + {}, + // zel_01.bmg - Seras Shop + {7001, 7003, 7004, 7005, 7006, 7007, 7008, 7009, 7010, 7013, 7014, 7022, 7023, 7028, 7029, + 7044, 7045, 7053}, + // zel_02.bmg - Kakariko Shops + {5251, 5253, 5254, 5256, 5258, 5259, 5653, 5654, 5656, 5660, 5661, 5664, 5665, 5697, 5698, + 5699, 5803, 5804, 5806, 5810, 5811, 5812, 5814, 5821, 5823, 5824, 5987, 5988, 5989, 5990, + 5991, 5992, 5993, 5994, 5995, 5996, 5997, 5998, 5999}, + // zel_03.bmg - Death Mountain Shop + {5303, 5304, 5306, 5310, 5311, 5314, 5315, 5322, 5323, 5324, 5496, 5497, 5498, 5499}, + // zel_04.bmg - Castle Town Shops + {5407, 5408, 5409, 5410, 5411, 5412, 5413, 5414, 5415, 5416, 5417, 5418, 5419, 5420, 5431, + 5432, 5433, 5434, 5435, 5436, 5437, 5438, 5439, 5440, 5441, 5444, 5449, 5450, 5451, 5452, + 5462}, + // zel_05.bmg - Oocca Shop + {9428, 9429, 9430, 9431, 9432, 9437, 9443, 9448, 9449, 9451, 9459} + }); + + u16 id = mMessageID; + s16 group = dMsgObject_getGroupID(); + if (group < shopMsgIds.size()) { + return std::ranges::binary_search(shopMsgIds[group], id); + } + return false; + +} +#endif + const char* dMsgObject_c::getSmellName() { JMSMesgInfo_c* info_header_p = (JMSMesgInfo_c*)((char*)mpMsgRes + 0x20); char* data_ptr = (char*)info_header_p + info_header_p->header.size; From b26896cad53142d4dde73d6df6fc4869b4ab28da Mon Sep 17 00:00:00 2001 From: gymnast86 Date: Tue, 28 Apr 2026 18:05:40 -0700 Subject: [PATCH 094/390] includes --- src/d/d_msg_object.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/d/d_msg_object.cpp b/src/d/d_msg_object.cpp index 22e722d790..00dfc6626e 100644 --- a/src/d/d_msg_object.cpp +++ b/src/d/d_msg_object.cpp @@ -34,6 +34,7 @@ #include "dusk/settings.h" #include #include +#include #endif static void dMsgObject_addFundRaising(s16 param_0); From 1e372a856d21672b927aac53584c64ec6a22c8de Mon Sep 17 00:00:00 2001 From: Irastris Date: Tue, 28 Apr 2026 22:54:47 -0400 Subject: [PATCH 095/390] Attempted to start making the save editor functional --- res/rcss/window.rcss | 17 +++ src/dusk/ui/editor.cpp | 248 ++++++++++++++++++++++++++++------------- src/dusk/ui/window.cpp | 116 ++++++++++++++++--- src/dusk/ui/window.hpp | 16 ++- 4 files changed, 304 insertions(+), 93 deletions(-) diff --git a/res/rcss/window.rcss b/res/rcss/window.rcss index 1596be869e..3858ae5166 100644 --- a/res/rcss/window.rcss +++ b/res/rcss/window.rcss @@ -77,6 +77,23 @@ body { border-right: 1dp #92875B; } +.window .content .pane.detail-pane { + gap: 16dp; +} + +.window .content .detail-value { + padding: 12dp 16dp; + border-radius: 12dp; + background-color: rgba(17, 16, 10, 20%); + box-shadow: rgba(146, 135, 91, 25%) 0 0 0 1dp; + font-size: 20dp; +} + +.window .content .detail-controls { + display: flex; + gap: 12dp; +} + .section-heading { font-weight: bold; text-transform: uppercase; diff --git a/src/dusk/ui/editor.cpp b/src/dusk/ui/editor.cpp index 4b7a05dd2d..bd818438ca 100644 --- a/src/dusk/ui/editor.cpp +++ b/src/dusk/ui/editor.cpp @@ -2,72 +2,11 @@ #include +#include "fmt/format.h" + namespace dusk::ui { namespace { -const Rml::String kPlayerStatusContent = R"RML( -
-
Player
- - - - - - -
Equipment
- - - - - -
- -
- - - - - - - - - -
-)RML"; - const Rml::String kLocationContent = R"RML(
Save Location
@@ -92,21 +31,178 @@ const Rml::String kLocationContent = R"RML(
)RML"; +bool has_save_data() { + return dComIfGs_getSaveData() != nullptr; +} + +dSv_player_status_a_c* get_player_status() { + if (!has_save_data()) { + return nullptr; + } + return &dComIfGs_getSaveData()->getPlayer().getPlayerStatusA(); +} + +Rml::String get_player_name() { + if (!has_save_data()) { + return nullptr; + } + return dComIfGs_getPlayerName(); +} + +Rml::String get_horse_name() { + if (!has_save_data()) { + return nullptr; + } + return dComIfGs_getHorseName(); +} + +Rml::String value_for_player_selection(const Rml::String& selection) { + dSv_player_status_a_c* status = get_player_status(); + if (selection == "get_horse_name") { + return get_horse_name(); + } + if (status == nullptr) { + return "?"; + } + if (selection == "max_health") { + return fmt::format("{}", static_cast(status->mMaxLife)); + } + if (selection == "health") { + return fmt::format("{}", static_cast(status->mLife)); + } + if (selection == "max_oil") { + return fmt::format("{}", static_cast(status->mMaxOil)); + } + if (selection == "oil") { + return fmt::format("{}", static_cast(status->mOil)); + } + return "Unknown"; +} + +Rml::String make_select_row(std::string_view key, std::string_view label, const Rml::String& value, const Rml::String& activeSelection) { + const char* selectedClass = key == activeSelection ? " selected" : ""; + return fmt::format( + "", + selectedClass, + key, + label, + value + ); +} + +Rml::String make_numeric_detail(std::string_view label, std::string_view decAction, std::string_view incAction) { + return fmt::format( + "
" + "
{0}
" + "
" + "" + "" + "
" + "
", + label, + decAction, + incAction + ); +} + +template +void adjust_u16(TValue& value, int delta, u16 minValue, u16 maxValue) { + const int nextValue = std::clamp(static_cast(value) + delta, static_cast(minValue), static_cast(maxValue)); + value = static_cast(nextValue); +} + +void render_player_status_tab(Rml::Element* content, const Rml::String& activeSelection) { + Rml::String leftPane = R"RML(
Player
)RML"; + leftPane += make_select_row("player_name", "Player Name", get_player_name(), activeSelection); + leftPane += make_select_row("horse_name", "Horse Name", get_horse_name(), activeSelection); + leftPane += make_select_row("max_health", "Max Health", value_for_player_selection("max_health"), activeSelection); + leftPane += make_select_row("health", "Health", value_for_player_selection("health"), activeSelection); + leftPane += make_select_row("max_oil", "Max Oil", value_for_player_selection("max_oil"), activeSelection); + leftPane += make_select_row("oil", "Oil", value_for_player_selection("oil"), activeSelection); + leftPane += "
"; + + Rml::String rightPane; + if (activeSelection == "max_health") { + rightPane = make_numeric_detail("Max Health", "max_health.dec", "max_health.inc"); + } else if (activeSelection == "health") { + rightPane = make_numeric_detail("Health", "health.dec", "health.inc"); + } else if (activeSelection == "max_oil") { + rightPane = make_numeric_detail("Max Oil", "max_oil.dec", "max_oil.inc"); + } else if (activeSelection == "oil") { + rightPane = make_numeric_detail("Oil", "oil.dec", "oil.inc"); + } + + Rml::Factory::InstanceElementText(content, leftPane + rightPane); +} + +bool handle_editor_action(const Rml::VariantList& arguments) { + if (arguments.empty() || !has_save_data()) { + return true; + } + + const Rml::String action = arguments[0].Get(); + dSv_player_status_a_c* status = get_player_status(); + if (status == nullptr) { + return true; + } + + if (action == "max_health.inc") { + adjust_u16(status->mMaxLife, 1, 0, 0xFFFF); + return true; + } else if (action == "max_health.dec") { + adjust_u16(status->mMaxLife, -1, 0, 0xFFFF); + if (status->mLife > status->mMaxLife) { + status->mLife = status->mMaxLife; + } + return true; + } + + if (action == "health.inc") { + adjust_u16(status->mLife, 1, 0, status->mMaxLife); + return true; + } else if (action == "health.dec") { + adjust_u16(status->mLife, -1, 0, status->mMaxLife); + return true; + } + + if (action == "max_oil.inc") { + adjust_u16(status->mMaxOil, 1, 0, 0xFFFF); + return true; + } else if (action == "max_oil.dec") { + adjust_u16(status->mMaxOil, -1, 0, 0xFFFF); + if (status->mOil > status->mMaxOil) { + status->mOil = status->mMaxOil; + } + return true; + } + + if (action == "oil.inc") { + adjust_u16(status->mOil, 1, 0, status->mMaxOil); + return true; + } else if (action == "oil.dec") { + adjust_u16(status->mOil, -1, 0, status->mMaxOil); + return true; + } + + return false; +} + } // namespace EditorWindow::EditorWindow() : Window({.tabs = { - {"Player Status", - [](Rml::Element* content) { - // TODO: actually bind values and events. wonder if we should have - // a SettingsPane element or something for sharing? - Rml::Factory::InstanceElementText(content, kPlayerStatusContent); - }}, - {"Location", - [](Rml::Element* content) { - Rml::Factory::InstanceElementText(content, kLocationContent); - }}, - {"Inventory"}, - }}) {} + {"Player Status", + "player_name", + [](Rml::Element* content, const Rml::String& activeSelection) { render_player_status_tab(content, activeSelection); + }}, + {"Location", + "", + [](Rml::Element* content, const Rml::String&) { Rml::Factory::InstanceElementText(content, kLocationContent); + }}, + {"Inventory"}, + }, + .actionHandler = handle_editor_action +}){} -} // namespace dusk::ui \ No newline at end of file +} // namespace dusk::ui diff --git a/src/dusk/ui/window.cpp b/src/dusk/ui/window.cpp index e7ac3eb3c6..82d207f369 100644 --- a/src/dusk/ui/window.cpp +++ b/src/dusk/ui/window.cpp @@ -25,12 +25,76 @@ bool setup_window_model(Rml::Context* context, WindowModel& model, Rml::DataMode constructor.Bind("active_tab", &model.activeTab); constructor.Bind("tabs", &model.tabs); + constructor.Bind("active_selection", &model.activeSelection); constructor.BindEventCallback("set_active_tab", &WindowModel::set_active_tab, &model); + constructor.BindEventCallback("set_active_selection", &WindowModel::set_active_selection, &model); + constructor.BindEventCallback("window_action", &WindowModel::handle_action, &model); handle = constructor.GetModelHandle(); return true; } +Rml::ElementDocument* get_document_from_event(Rml::Event& event) { + auto* currentElem = event.GetCurrentElement(); + if (currentElem == nullptr) { + return nullptr; + } + return currentElem->GetOwnerDocument(); +} + +Rml::Element* get_content_element(Rml::ElementDocument* document) { + if (document == nullptr) { + return nullptr; + } + return document->GetElementById("content"); +} + +void clear_children(Rml::Element* element) { + if (element == nullptr) { + return; + } + while (element->GetNumChildren() > 0) { + element->RemoveChild(element->GetFirstChild()); + } +} + +void ensure_tab_selection_state(WindowModel& model) { + if (model.tabSelections.size() < model.tabs.size()) { + model.tabSelections.resize(model.tabs.size()); + } + if (model.activeTab < 0 || model.activeTab >= static_cast(model.tabs.size())) { + model.activeTab = 0; + } + if (model.tabs.empty()) { + model.activeSelection.clear(); + return; + } + + Rml::String& tabSelection = model.tabSelections[model.activeTab]; + if (tabSelection.empty()) { + tabSelection = model.tabs[model.activeTab].defaultSelection; + } + model.activeSelection = tabSelection; +} + +void render_active_tab_content(WindowModel& model, Rml::ElementDocument* document) { + auto* content = get_content_element(document); + if (content == nullptr) { + return; + } + + clear_children(content); + if (model.tabs.empty()) { + return; + } + + ensure_tab_selection_state(model); + const WindowTab& tab = model.tabs[model.activeTab]; + if (tab.setContent) { + tab.setContent(content, model.activeSelection); + } +} + } // namespace void WindowModel::set_active_tab( @@ -45,27 +109,43 @@ void WindowModel::set_active_tab( } activeTab = tabIndex; + ensure_tab_selection_state(*this); model.DirtyVariable("active_tab"); + model.DirtyVariable("active_selection"); + render_active_tab_content(*this, get_document_from_event(event)); +} - // Replace window content with new tab content - auto* currentElem = event.GetCurrentElement(); - if (currentElem == nullptr) { +void WindowModel::set_active_selection( + Rml::DataModelHandle model, Rml::Event& event, const Rml::VariantList& arguments) { + if (arguments.empty() || tabs.empty()) { return; } - auto* doc = currentElem->GetOwnerDocument(); - if (doc == nullptr) { + + const Rml::String selection = arguments[0].Get(); + ensure_tab_selection_state(*this); + if (activeSelection == selection) { return; } - auto* content = doc->GetElementById("content"); - if (content == nullptr) { + + activeSelection = selection; + tabSelections[activeTab] = selection; + model.DirtyVariable("active_selection"); + render_active_tab_content(*this, get_document_from_event(event)); +} + +void WindowModel::handle_action( + Rml::DataModelHandle model, Rml::Event& event, const Rml::VariantList& arguments) { + bool shouldRerender = true; + if (actionHandler) { + shouldRerender = actionHandler(arguments); + } + if (!shouldRerender) { return; } - while (content->GetNumChildren() > 0) { - content->RemoveChild(content->GetFirstChild()); - } - if (tabs[tabIndex].setContent) { - tabs[tabIndex].setContent(content); - } + + model.DirtyVariable("active_tab"); + model.DirtyVariable("active_selection"); + render_active_tab_content(*this, get_document_from_event(event)); } Window::Window(WindowModel model) : mModel(std::move(model)) { @@ -73,12 +153,20 @@ Window::Window(WindowModel model) : mModel(std::move(model)) { if (context == nullptr) { return; } + setup_window_model(context, mModel, mModelHandle); + mDocument = context->LoadDocument("res/rml/window.rml"); if (mDocument == nullptr) { return; } - mModel.tabs[0].setContent(mDocument->GetElementById("content")); + + ensure_tab_selection_state(mModel); + render_active_tab(); +} + +void Window::render_active_tab() noexcept { + render_active_tab_content(mModel, mDocument); } Window::~Window() { diff --git a/src/dusk/ui/window.hpp b/src/dusk/ui/window.hpp index 2faa4fb140..e4eb2c5ef6 100644 --- a/src/dusk/ui/window.hpp +++ b/src/dusk/ui/window.hpp @@ -7,15 +7,23 @@ namespace dusk::ui { struct WindowTab { Rml::String label; - std::function setContent; + Rml::String defaultSelection; + std::function setContent; }; struct WindowModel { int activeTab = 0; + Rml::String activeSelection; std::vector tabs; + std::vector tabSelections; + std::function actionHandler; void set_active_tab( Rml::DataModelHandle model, Rml::Event& event, const Rml::VariantList& arguments); + void set_active_selection( + Rml::DataModelHandle model, Rml::Event& event, const Rml::VariantList& arguments); + void handle_action( + Rml::DataModelHandle model, Rml::Event& event, const Rml::VariantList& arguments); }; class Window { @@ -27,9 +35,11 @@ public: void hide(); private: + void render_active_tab() noexcept; + WindowModel mModel; Rml::DataModelHandle mModelHandle; - Rml::ElementDocument* mDocument; + Rml::ElementDocument* mDocument = nullptr; }; -} // namespace dusk::ui \ No newline at end of file +} // namespace dusk::ui From e15f5bcee9a48932c66d4a4499a4a2ee23e26d3f Mon Sep 17 00:00:00 2001 From: doop <56421834+dooplecks@users.noreply.github.com> Date: Wed, 29 Apr 2026 03:40:49 +0000 Subject: [PATCH 096/390] Improve map outline rendering --- src/d/d_map_path.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/d/d_map_path.cpp b/src/d/d_map_path.cpp index f94cdc9475..911dd09cdd 100644 --- a/src/d/d_map_path.cpp +++ b/src/d/d_map_path.cpp @@ -16,6 +16,7 @@ #ifdef TARGET_PC constexpr u16 kMapResolutionMultiplier = 4; +constexpr u16 kMapCircleSize = 16 * kMapResolutionMultiplier; #endif void dMpath_n::dTexObjAggregate_c::create() { @@ -32,6 +33,47 @@ void dMpath_n::dTexObjAggregate_c::create() { JUT_ASSERT(74, image->magFilter == GX_NEAR); mDoLib_setResTimgObj(image, mp_texObj[lp1], 0, NULL); } + +#if TARGET_PC + auto hqCircle = JKR_NEW TGXTexObj(); + + static bool hqCircleDrawn = false; + static u8 hqCircleData[kMapCircleSize * kMapCircleSize]; + + if (!hqCircleDrawn) { + const auto center = kMapCircleSize / 2.0f; + const auto radiusSq = center * center; + const auto blocksAcross = kMapCircleSize >> 3; + + for (u16 y = 0; y < kMapCircleSize; y++) { + for (u16 x = 0; x < kMapCircleSize; x++) { + // swizzle raster order to I8 blocks + auto blockX = x >> 3; + auto blockY = y >> 2; + auto blockIdx = (blockY * blocksAcross) + blockX; + + auto localX = x & 7; + auto localY = y & 3; + auto localIdx = (localY << 3) + localX; + + auto finalOffset = (blockIdx << 5) + localIdx; + + auto dx = (x + 0.5f) - center; + auto dy = (y + 0.5f) - center; + + // the original texture is in I4 format and uses 1 to indicate if inside the circle + // so we scale to I8 range: 255 / 15 = 17 + hqCircleData[finalOffset] = (dx * dx + dy * dy < radiusSq) ? 17 : 0; + } + } + hqCircleDrawn = true; + } + + GXInitTexObj(hqCircle, hqCircleData, kMapCircleSize, kMapCircleSize, GX_TF_I8, GX_CLAMP, + GX_CLAMP, GX_FALSE); + GXInitTexObjLOD(hqCircle, GX_NEAR, GX_NEAR, 0.0f, 0.0f, 0.0f, GX_FALSE, GX_FALSE, GX_ANISO_1); + mp_texObj[6] = hqCircle; +#endif } void dMpath_n::dTexObjAggregate_c::remove() { From afe54f22abe94ad52c56622579f45ae503081907 Mon Sep 17 00:00:00 2001 From: doop <56421834+dooplecks@users.noreply.github.com> Date: Wed, 29 Apr 2026 04:16:24 +0000 Subject: [PATCH 097/390] Write circle pixels linearly --- src/d/d_map_path.cpp | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/d/d_map_path.cpp b/src/d/d_map_path.cpp index 911dd09cdd..eca620ef98 100644 --- a/src/d/d_map_path.cpp +++ b/src/d/d_map_path.cpp @@ -44,33 +44,34 @@ void dMpath_n::dTexObjAggregate_c::create() { const auto center = kMapCircleSize / 2.0f; const auto radiusSq = center * center; const auto blocksAcross = kMapCircleSize >> 3; + const auto totalPixels = sizeof(hqCircleData); - for (u16 y = 0; y < kMapCircleSize; y++) { - for (u16 x = 0; x < kMapCircleSize; x++) { - // swizzle raster order to I8 blocks - auto blockX = x >> 3; - auto blockY = y >> 2; - auto blockIdx = (blockY * blocksAcross) + blockX; + for (size_t i = 0; i < totalPixels; i++) { + // 8x4 block swizzling for I8 + const auto blockIdx = i >> 5; + const auto localIdx = i & 31; - auto localX = x & 7; - auto localY = y & 3; - auto localIdx = (localY << 3) + localX; + const auto blockY = blockIdx / blocksAcross; + const auto blockX = blockIdx % blocksAcross; - auto finalOffset = (blockIdx << 5) + localIdx; + const auto localY = localIdx >> 3; + const auto localX = localIdx & 7; - auto dx = (x + 0.5f) - center; - auto dy = (y + 0.5f) - center; + const auto x = (blockX << 3) + localX; + const auto y = (blockY << 2) + localY; - // the original texture is in I4 format and uses 1 to indicate if inside the circle - // so we scale to I8 range: 255 / 15 = 17 - hqCircleData[finalOffset] = (dx * dx + dy * dy < radiusSq) ? 17 : 0; - } + const auto dx = (x + 0.5f) - center; + const auto dy = (y + 0.5f) - center; + + // the original texture is in I4 format and uses 1 to indicate if inside the circle + // so we scale to I8 range: 255 / 15 = 17 + hqCircleData[i] = (dx * dx + dy * dy < radiusSq) ? 17 : 0; } hqCircleDrawn = true; } GXInitTexObj(hqCircle, hqCircleData, kMapCircleSize, kMapCircleSize, GX_TF_I8, GX_CLAMP, - GX_CLAMP, GX_FALSE); + GX_CLAMP, GX_FALSE); GXInitTexObjLOD(hqCircle, GX_NEAR, GX_NEAR, 0.0f, 0.0f, 0.0f, GX_FALSE, GX_FALSE, GX_ANISO_1); mp_texObj[6] = hqCircle; #endif From 3cb7fbd030276e6dde5017188861f4a6b6a34066 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Wed, 29 Apr 2026 00:38:26 -0600 Subject: [PATCH 098/390] Create new component system & initial settings window --- files.cmake | 12 ++ res/{rcss => rml}/window.rcss | 2 +- res/rml/window.rml | 13 +-- src/dusk/ui/button.cpp | 49 +++++++++ src/dusk/ui/button.hpp | 30 +++++ src/dusk/ui/component.cpp | 45 ++++++++ src/dusk/ui/component.hpp | 49 +++++++++ src/dusk/ui/editor.cpp | 143 +++++++++++++++--------- src/dusk/ui/event.cpp | 31 ++++++ src/dusk/ui/event.hpp | 27 +++++ src/dusk/ui/pane.cpp | 36 ++++++ src/dusk/ui/pane.hpp | 22 ++++ src/dusk/ui/select_button.cpp | 62 +++++++++++ src/dusk/ui/select_button.hpp | 38 +++++++ src/dusk/ui/settings.cpp | 131 ++++++++++++++++++++++ src/dusk/ui/settings.hpp | 11 ++ src/dusk/ui/ui.cpp | 56 +++++++++- src/dusk/ui/ui.hpp | 5 + src/dusk/ui/window.cpp | 202 +++++++++------------------------- src/dusk/ui/window.hpp | 57 +++++----- src/m_Do/m_Do_main.cpp | 8 +- 21 files changed, 777 insertions(+), 252 deletions(-) rename res/{rcss => rml}/window.rcss (99%) create mode 100644 src/dusk/ui/button.cpp create mode 100644 src/dusk/ui/button.hpp create mode 100644 src/dusk/ui/component.cpp create mode 100644 src/dusk/ui/component.hpp create mode 100644 src/dusk/ui/event.cpp create mode 100644 src/dusk/ui/event.hpp create mode 100644 src/dusk/ui/pane.cpp create mode 100644 src/dusk/ui/pane.hpp create mode 100644 src/dusk/ui/select_button.cpp create mode 100644 src/dusk/ui/select_button.hpp create mode 100644 src/dusk/ui/settings.cpp create mode 100644 src/dusk/ui/settings.hpp diff --git a/files.cmake b/files.cmake index 13fd5c9629..8aa6097119 100644 --- a/files.cmake +++ b/files.cmake @@ -1462,8 +1462,20 @@ set(DUSK_FILES src/dusk/imgui/ImGuiStateShare.cpp src/dusk/imgui/ImGuiAchievements.hpp src/dusk/imgui/ImGuiAchievements.cpp + src/dusk/ui/button.cpp + src/dusk/ui/button.hpp + src/dusk/ui/component.cpp + src/dusk/ui/component.hpp src/dusk/ui/editor.cpp src/dusk/ui/editor.hpp + src/dusk/ui/event.cpp + src/dusk/ui/event.hpp + src/dusk/ui/pane.cpp + src/dusk/ui/pane.hpp + src/dusk/ui/select_button.cpp + src/dusk/ui/select_button.hpp + src/dusk/ui/settings.cpp + src/dusk/ui/settings.hpp src/dusk/ui/ui.hpp src/dusk/ui/ui.cpp src/dusk/ui/window.hpp diff --git a/res/rcss/window.rcss b/res/rml/window.rcss similarity index 99% rename from res/rcss/window.rcss rename to res/rml/window.rcss index 3858ae5166..2b572772e5 100644 --- a/res/rcss/window.rcss +++ b/res/rml/window.rcss @@ -45,7 +45,7 @@ body { focus: auto; } -.window .tab-bar .tab.active { +.window .tab-bar .tab.selected { opacity: 1; border-bottom: 4dp #C2A42D; font-effect: glow(0dp 4dp 0dp 4dp black); diff --git a/res/rml/window.rml b/res/rml/window.rml index 93a4397ae1..a77728d00d 100644 --- a/res/rml/window.rml +++ b/res/rml/window.rml @@ -3,16 +3,9 @@ Window - -
-
- -
+ +
+
diff --git a/src/dusk/ui/button.cpp b/src/dusk/ui/button.cpp new file mode 100644 index 0000000000..d5c731e0f8 --- /dev/null +++ b/src/dusk/ui/button.cpp @@ -0,0 +1,49 @@ +#include "button.hpp" + +#include "ui.hpp" + +#include + +namespace dusk::ui { +namespace { + +Rml::Element* createRoot(Rml::Element* parent, const Rml::String& className) { + auto* doc = parent->GetOwnerDocument(); + auto elem = doc->CreateElement("button"); + elem->SetClass(className, true); + return parent->AppendChild(std::move(elem)); +} + +} // namespace + +Button::Button(Rml::Element* parent, ButtonProps props, const Rml::String& className) + : Component(createRoot(parent, className)) { + update_props(std::move(props)); + listen(mRoot, Rml::EventId::Click, [this](Rml::Event& event) { + if (mProps.onPressed) { + mProps.onPressed(event); + } + }); +} + +void Button::set_text(const Rml::String& text) { + if (mProps.text != text) { + mRoot->SetInnerRML(escape(text)); + mProps.text = text; + } +} + +void Button::set_selected(bool selected) { + if (mProps.selected != selected) { + mRoot->SetClass("selected", selected); + mProps.selected = selected; + } +} + +void Button::update_props(Props props) { + set_text(props.text); + set_selected(props.selected); + mProps = std::move(props); +} + +} // namespace dusk::ui \ No newline at end of file diff --git a/src/dusk/ui/button.hpp b/src/dusk/ui/button.hpp new file mode 100644 index 0000000000..deaadde12b --- /dev/null +++ b/src/dusk/ui/button.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include "component.hpp" + +namespace dusk::ui { + +struct ButtonProps { + Rml::String text; + std::function onPressed; + bool selected = false; +}; + +class Button : public Component { +public: + using Props = ButtonProps; + + Button(Rml::Element* parent, ButtonProps props, const Rml::String& className = "button"); + + void set_text(const Rml::String& text); + void set_selected(bool selected); + + const Rml::String& get_text() const { return mProps.text; } + +private: + void update_props(Props props); + + ButtonProps mProps; +}; + +} // namespace dusk::ui \ No newline at end of file diff --git a/src/dusk/ui/component.cpp b/src/dusk/ui/component.cpp new file mode 100644 index 0000000000..b4f6a287a9 --- /dev/null +++ b/src/dusk/ui/component.cpp @@ -0,0 +1,45 @@ +#include "component.hpp" + +#include "aurora/lib/dolphin/gd/gd.hpp" + +namespace dusk::ui { +static aurora::Module Log{"dusk::ui::component"}; + +Component::Component(Rml::Element* root) : mRoot(root) {} + +Component::~Component() = default; + +void Component::update() { + for (const auto& child : mChildren) { + child->update(); + } +} + +Rml::Element* Component::append(Rml::Element* parent, const Rml::String& tag) { + if (parent == nullptr) { + return nullptr; + } + auto* doc = parent->GetOwnerDocument(); + if (doc == nullptr) { + return nullptr; + } + return parent->AppendChild(doc->CreateElement(tag)); +} + +void Component::listen(Rml::Element* element, Rml::EventId event, + ScopedEventListener::Callback callback, bool capture) { + if (element == nullptr) { + element = mRoot; + } + mListeners.emplace_back( + std::make_unique(element, event, std::move(callback), capture)); +} + +void Component::clear_children() { + mChildren.clear(); + while (mRoot->GetNumChildren() > 0) { + mRoot->RemoveChild(mRoot->GetFirstChild()); + } +} + +} // namespace dusk::ui \ No newline at end of file diff --git a/src/dusk/ui/component.hpp b/src/dusk/ui/component.hpp new file mode 100644 index 0000000000..9291a25da8 --- /dev/null +++ b/src/dusk/ui/component.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include "event.hpp" + +#include + +#include +#include + +namespace Rml { +class Element; +} + +namespace dusk::ui { + +class Component { +public: + Component() = default; + explicit Component(Rml::Element* root); + virtual ~Component(); + + Component(const Component&) = delete; + Component& operator=(const Component&) = delete; + + virtual void update(); + + void listen(Rml::Element* element, Rml::EventId event, ScopedEventListener::Callback callback, + bool capture = false); + + Rml::Element* root() const { return mRoot; } + +protected: + static Rml::Element* append(Rml::Element* parent, const Rml::String& tag); + void clear_children(); + + template + requires std::is_base_of_v T& add_child(Args&&... args) { + auto child = std::make_unique(std::forward(args)...); + T& ref = *child; + mChildren.emplace_back(std::move(child)); + return ref; + } + + Rml::Element* mRoot = nullptr; + std::vector > mChildren; + std::vector > mListeners; +}; + +} // namespace dusk::ui diff --git a/src/dusk/ui/editor.cpp b/src/dusk/ui/editor.cpp index bd818438ca..56ef554c3c 100644 --- a/src/dusk/ui/editor.cpp +++ b/src/dusk/ui/editor.cpp @@ -4,32 +4,14 @@ #include "fmt/format.h" +#include "aurora/lib/dolphin/gd/gd.hpp" +#include "button.hpp" +#include "pane.hpp" +#include "select_button.hpp" + namespace dusk::ui { namespace { - -const Rml::String kLocationContent = R"RML( -
-
Save Location
- - - -
Horse Location
- -
-
-)RML"; +aurora::Module Log{"dusk::ui::editor"}; bool has_save_data() { return dComIfGs_getSaveData() != nullptr; @@ -44,14 +26,14 @@ dSv_player_status_a_c* get_player_status() { Rml::String get_player_name() { if (!has_save_data()) { - return nullptr; + return "Link"; } return dComIfGs_getPlayerName(); } Rml::String get_horse_name() { if (!has_save_data()) { - return nullptr; + return "Epona"; } return dComIfGs_getHorseName(); } @@ -79,19 +61,17 @@ Rml::String value_for_player_selection(const Rml::String& selection) { return "Unknown"; } -Rml::String make_select_row(std::string_view key, std::string_view label, const Rml::String& value, const Rml::String& activeSelection) { +Rml::String make_select_row(std::string_view key, std::string_view label, const Rml::String& value, + const Rml::String& activeSelection) { const char* selectedClass = key == activeSelection ? " selected" : ""; return fmt::format( "", - selectedClass, - key, - label, - value - ); + selectedClass, key, label, value); } -Rml::String make_numeric_detail(std::string_view label, std::string_view decAction, std::string_view incAction) { +Rml::String make_numeric_detail( + std::string_view label, std::string_view decAction, std::string_view incAction) { return fmt::format( "
" "
{0}
" @@ -100,15 +80,13 @@ Rml::String make_numeric_detail(std::string_view label, std::string_view decActi "" "
" "
", - label, - decAction, - incAction - ); + label, decAction, incAction); } template void adjust_u16(TValue& value, int delta, u16 minValue, u16 maxValue) { - const int nextValue = std::clamp(static_cast(value) + delta, static_cast(minValue), static_cast(maxValue)); + const int nextValue = std::clamp( + static_cast(value) + delta, static_cast(minValue), static_cast(maxValue)); value = static_cast(nextValue); } @@ -116,9 +94,12 @@ void render_player_status_tab(Rml::Element* content, const Rml::String& activeSe Rml::String leftPane = R"RML(
Player
)RML"; leftPane += make_select_row("player_name", "Player Name", get_player_name(), activeSelection); leftPane += make_select_row("horse_name", "Horse Name", get_horse_name(), activeSelection); - leftPane += make_select_row("max_health", "Max Health", value_for_player_selection("max_health"), activeSelection); - leftPane += make_select_row("health", "Health", value_for_player_selection("health"), activeSelection); - leftPane += make_select_row("max_oil", "Max Oil", value_for_player_selection("max_oil"), activeSelection); + leftPane += make_select_row( + "max_health", "Max Health", value_for_player_selection("max_health"), activeSelection); + leftPane += + make_select_row("health", "Health", value_for_player_selection("health"), activeSelection); + leftPane += make_select_row( + "max_oil", "Max Oil", value_for_player_selection("max_oil"), activeSelection); leftPane += make_select_row("oil", "Oil", value_for_player_selection("oil"), activeSelection); leftPane += "
"; @@ -190,19 +171,71 @@ bool handle_editor_action(const Rml::VariantList& arguments) { } // namespace -EditorWindow::EditorWindow() - : Window({.tabs = { - {"Player Status", - "player_name", - [](Rml::Element* content, const Rml::String& activeSelection) { render_player_status_tab(content, activeSelection); - }}, - {"Location", - "", - [](Rml::Element* content, const Rml::String&) { Rml::Factory::InstanceElementText(content, kLocationContent); - }}, - {"Inventory"}, - }, - .actionHandler = handle_editor_action -}){} +EditorWindow::EditorWindow() { + add_tab("Player Status", [this](Rml::Element* content) { + auto& leftPane = add_child(content); + leftPane.add_section("Player"); + leftPane.add_select_button({ + .key = "Player Name", + .getValue = get_player_name, + }); + leftPane.add_select_button({ + .key = "Horse Name", + .getValue = get_horse_name, + }); + leftPane.add_select_button({ + .key = "Max Health", + .getValue = [] { return value_for_player_selection("max_health"); }, + }); + leftPane.add_select_button({ + .key = "Max Oil", + .getValue = [] { return value_for_player_selection("max_oil"); }, + }); + leftPane.add_select_button({ + .key = "Oil", + .getValue = [] { return value_for_player_selection("oil"); }, + }); + leftPane.add_section("Equipment"); + leftPane.add_select_button({ + .key = "Equip X", + .value = "TODO", + .selected = true, + }); + leftPane.add_select_button({ + .key = "Equip Y", + .value = "TODO", + .selected = false, + }); + + auto& rightPane = add_child(content); + rightPane.add_button({ + .text = "Hello, world!", + }); + }); + + add_tab("Location", [this](Rml::Element* content) { + // TODO + }); + + add_tab("Inventory", [this](Rml::Element* content) { + // TODO + }); + + add_tab("Collection", [this](Rml::Element* content) { + // TODO + }); + + add_tab("Flags", [this](Rml::Element* content) { + // TODO + }); + + add_tab("Minigame", [this](Rml::Element* content) { + // TODO + }); + + add_tab("Config", [this](Rml::Element* content) { + // TODO + }); +} } // namespace dusk::ui diff --git a/src/dusk/ui/event.cpp b/src/dusk/ui/event.cpp new file mode 100644 index 0000000000..0135cd56b7 --- /dev/null +++ b/src/dusk/ui/event.cpp @@ -0,0 +1,31 @@ +#include "event.hpp" + +#include + +namespace dusk::ui { + +ScopedEventListener::ScopedEventListener( + Rml::Element* element, Rml::EventId event, Callback callback, bool capture) + : mElement(element), mEvent(event), mCapture(capture), mCallback(std::move(callback)) { + mElement->AddEventListener(mEvent, this, mCapture); +} + +ScopedEventListener::~ScopedEventListener() { + if (mElement != nullptr) { + mElement->RemoveEventListener(mEvent, this, mCapture); + } +} + +void ScopedEventListener::ProcessEvent(Rml::Event& event) { + if (mCallback) { + mCallback(event); + } +} + +void ScopedEventListener::OnDetach(Rml::Element* element) { + if (element == mElement) { + mElement = nullptr; + } +} + +} // namespace dusk::ui diff --git a/src/dusk/ui/event.hpp b/src/dusk/ui/event.hpp new file mode 100644 index 0000000000..27a318de3f --- /dev/null +++ b/src/dusk/ui/event.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include + +#include + +namespace dusk::ui { + +class ScopedEventListener final : public Rml::EventListener { +public: + using Callback = std::function; + + ScopedEventListener( + Rml::Element* element, Rml::EventId event, Callback callback, bool capture = false); + ~ScopedEventListener() override; + + void ProcessEvent(Rml::Event& event) override; + void OnDetach(Rml::Element* element) override; + +private: + Rml::Element* mElement = nullptr; + Rml::EventId mEvent = Rml::EventId::Invalid; + bool mCapture = false; + Callback mCallback; +}; + +} // namespace dusk::ui diff --git a/src/dusk/ui/pane.cpp b/src/dusk/ui/pane.cpp new file mode 100644 index 0000000000..d36d25ee30 --- /dev/null +++ b/src/dusk/ui/pane.cpp @@ -0,0 +1,36 @@ +#include "pane.hpp" + +#include "ui.hpp" + +namespace dusk::ui { +namespace { + +Rml::Element* createRoot(Rml::Element* parent) { + auto* doc = parent->GetOwnerDocument(); + auto elem = doc->CreateElement("div"); + elem->SetClass("pane", true); + return parent->AppendChild(std::move(elem)); +} + +} // namespace + +Pane::Pane(Rml::Element* parent) : Component(createRoot(parent)) {} + +Rml::Element* Pane::add_section(const Rml::String& text) { + auto* elem = append(mRoot, "div"); + elem->SetClass("section-heading", true); + elem->SetInnerRML(escape(text)); + return elem; +} + +Rml::Element* Pane::add_text(const Rml::String& text) { + auto* elem = append(mRoot, "div"); + elem->SetInnerRML(escape(text)); + return elem; +} + +void Pane::clear() { + clear_children(); +} + +} // namespace dusk::ui \ No newline at end of file diff --git a/src/dusk/ui/pane.hpp b/src/dusk/ui/pane.hpp new file mode 100644 index 0000000000..ac252bf54c --- /dev/null +++ b/src/dusk/ui/pane.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "button.hpp" +#include "component.hpp" +#include "select_button.hpp" + +namespace dusk::ui { + +class Pane : public Component { +public: + explicit Pane(Rml::Element* parent); + + Rml::Element* add_section(const Rml::String& text); + Button& add_button(Button::Props props) { return add_child", - selectedClass, key, label, value); -} - -Rml::String make_numeric_detail( - std::string_view label, std::string_view decAction, std::string_view incAction) { - return fmt::format( - "
" - "
{0}
" - "
" - "" - "" - "
" - "
", - label, decAction, incAction); -} - -template -void adjust_u16(TValue& value, int delta, u16 minValue, u16 maxValue) { - const int nextValue = std::clamp( - static_cast(value) + delta, static_cast(minValue), static_cast(maxValue)); - value = static_cast(nextValue); -} - -void render_player_status_tab(Rml::Element* content, const Rml::String& activeSelection) { - Rml::String leftPane = R"RML(
Player
)RML"; - leftPane += make_select_row("player_name", "Player Name", get_player_name(), activeSelection); - leftPane += make_select_row("horse_name", "Horse Name", get_horse_name(), activeSelection); - leftPane += make_select_row( - "max_health", "Max Health", value_for_player_selection("max_health"), activeSelection); - leftPane += - make_select_row("health", "Health", value_for_player_selection("health"), activeSelection); - leftPane += make_select_row( - "max_oil", "Max Oil", value_for_player_selection("max_oil"), activeSelection); - leftPane += make_select_row("oil", "Oil", value_for_player_selection("oil"), activeSelection); - leftPane += "
"; - - Rml::String rightPane; - if (activeSelection == "max_health") { - rightPane = make_numeric_detail("Max Health", "max_health.dec", "max_health.inc"); - } else if (activeSelection == "health") { - rightPane = make_numeric_detail("Health", "health.dec", "health.inc"); - } else if (activeSelection == "max_oil") { - rightPane = make_numeric_detail("Max Oil", "max_oil.dec", "max_oil.inc"); - } else if (activeSelection == "oil") { - rightPane = make_numeric_detail("Oil", "oil.dec", "oil.inc"); - } - - Rml::Factory::InstanceElementText(content, leftPane + rightPane); -} - -bool handle_editor_action(const Rml::VariantList& arguments) { - if (arguments.empty() || !has_save_data()) { - return true; - } - - const Rml::String action = arguments[0].Get(); - dSv_player_status_a_c* status = get_player_status(); - if (status == nullptr) { - return true; - } - - if (action == "max_health.inc") { - adjust_u16(status->mMaxLife, 1, 0, 0xFFFF); - return true; - } else if (action == "max_health.dec") { - adjust_u16(status->mMaxLife, -1, 0, 0xFFFF); - if (status->mLife > status->mMaxLife) { - status->mLife = status->mMaxLife; - } - return true; - } - - if (action == "health.inc") { - adjust_u16(status->mLife, 1, 0, status->mMaxLife); - return true; - } else if (action == "health.dec") { - adjust_u16(status->mLife, -1, 0, status->mMaxLife); - return true; - } - - if (action == "max_oil.inc") { - adjust_u16(status->mMaxOil, 1, 0, 0xFFFF); - return true; - } else if (action == "max_oil.dec") { - adjust_u16(status->mMaxOil, -1, 0, 0xFFFF); - if (status->mOil > status->mMaxOil) { - status->mOil = status->mMaxOil; - } - return true; - } - - if (action == "oil.inc") { - adjust_u16(status->mOil, 1, 0, status->mMaxOil); - return true; - } else if (action == "oil.dec") { - adjust_u16(status->mOil, -1, 0, status->mMaxOil); - return true; - } - - return false; -} - } // namespace EditorWindow::EditorWindow() { From 4fc09799b6276dfcb1a4d6c38623877bef182eff Mon Sep 17 00:00:00 2001 From: Luke Street Date: Thu, 30 Apr 2026 01:45:21 -0600 Subject: [PATCH 116/390] UI: Fix section heading font --- res/rml/window.rcss | 1 + 1 file changed, 1 insertion(+) diff --git a/res/rml/window.rcss b/res/rml/window.rcss index 6f4cf5b777..7a14f55096 100644 --- a/res/rml/window.rcss +++ b/res/rml/window.rcss @@ -165,6 +165,7 @@ scrollbarhorizontal sliderbar { } .section-heading { + font-family: "Fira Sans Condensed"; font-weight: bold; text-transform: uppercase; font-size: 22dp; From 3185f578fb1cfadcf23e8e36306c4e3a7c277826 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Thu, 30 Apr 2026 01:45:54 -0600 Subject: [PATCH 117/390] Update aurora --- extern/aurora | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/aurora b/extern/aurora index a2c431d084..bcbb2c8c4e 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit a2c431d0840404aef49a808a2f95a97bf45aad38 +Subproject commit bcbb2c8c4edf922810f96244fdd619a0e47230be From 3f560b060cfab40bc16b4a84b5d7bf41cd1abcd3 Mon Sep 17 00:00:00 2001 From: madeline Date: Thu, 30 Apr 2026 01:48:03 -0700 Subject: [PATCH 118/390] 40 achievements --- include/d/d_com_inf_game.h | 6 + include/d/d_save.h | 3 + src/d/actor/d_a_alink_damage.inc | 3 + src/d/actor/d_a_arrow.cpp | 10 +- src/d/actor/d_a_b_gnd.cpp | 6 + src/d/actor/d_a_e_th.cpp | 9 + src/d/d_cc_uty.cpp | 8 + src/dusk/achievements.cpp | 733 +++++++++++++++++++++++++------ 8 files changed, 643 insertions(+), 135 deletions(-) diff --git a/include/d/d_com_inf_game.h b/include/d/d_com_inf_game.h index 964cc34c0f..d81fc5bc1e 100644 --- a/include/d/d_com_inf_game.h +++ b/include/d/d_com_inf_game.h @@ -1845,6 +1845,12 @@ inline void dComIfGs_addDeathCount() { g_dComIfG_gameInfo.info.getPlayer().getPlayerInfo().addDeathCount(); } +#if TARGET_PC +inline u16 dComIfGs_getDeathCount() { + return g_dComIfG_gameInfo.info.getPlayer().getPlayerInfo().getDeathCount(); +} +#endif + inline char* dComIfGs_getPlayerName() { return g_dComIfG_gameInfo.info.getPlayer().getPlayerInfo().getPlayerName(); } diff --git a/include/d/d_save.h b/include/d/d_save.h index 0e9a4b37cd..e2719e0a98 100644 --- a/include/d/d_save.h +++ b/include/d/d_save.h @@ -486,6 +486,9 @@ public: mDeathCount++; } } +#if TARGET_PC + u16 getDeathCount() const { return mDeathCount; } +#endif char* getPlayerName() const { return const_cast(mPlayerName); } void setPlayerName(const char* i_name) { #if AVOID_UB diff --git a/src/d/actor/d_a_alink_damage.inc b/src/d/actor/d_a_alink_damage.inc index e095fc0393..bccdbf7381 100644 --- a/src/d/actor/d_a_alink_damage.inc +++ b/src/d/actor/d_a_alink_damage.inc @@ -205,6 +205,9 @@ int daAlink_c::setDamagePoint(int i_dmgAmount, BOOL i_checkZoraMag, BOOL i_setDm dComIfGp_setItemLifeCount(-i_dmgAmount, 0); } +#if TARGET_PC + dusk::AchievementSystem::get().signal("player_damaged"); +#endif onResetFlg1(RFLG1_DAMAGE_IMPACT); mSwordUpTimer = 0; diff --git a/src/d/actor/d_a_arrow.cpp b/src/d/actor/d_a_arrow.cpp index 769c3273e9..c18d19e149 100644 --- a/src/d/actor/d_a_arrow.cpp +++ b/src/d/actor/d_a_arrow.cpp @@ -17,6 +17,9 @@ #include "d/actor/d_a_e_pz.h" #include "d/actor/d_a_horse.h" #include "d/actor/d_a_hozelda.h" +#if TARGET_PC +#include "dusk/achievements.h" +#endif int daArrow_c::createHeap() { J3DModelData* model_data; @@ -92,7 +95,12 @@ void daArrow_c::atHitCallBack(dCcD_GObjInf* i_atObjInf, fopAc_ac_c* i_tgActor, d if (dist_to_hitpos < field_0x998) { field_0x998 = dist_to_hitpos; mHitAcID = fopAcM_GetID(i_tgActor); - +#if TARGET_PC + if (fopAcM_GetGroup(i_tgActor) == fopAc_ENEMY_e && + current.pos.abs(mStartPos) > 10000.0f) { + dusk::AchievementSystem::get().signal("arrow_hit_100m"); + } +#endif if (mArrowType == 1) { field_0x9a8 = *hit_pos_p; } else if (i_tgObjInf->ChkTgShield()) { diff --git a/src/d/actor/d_a_b_gnd.cpp b/src/d/actor/d_a_b_gnd.cpp index cd6bce78c4..f5b03be1b1 100644 --- a/src/d/actor/d_a_b_gnd.cpp +++ b/src/d/actor/d_a_b_gnd.cpp @@ -19,6 +19,9 @@ #include "dusk/frame_interpolation.h" #include "dusk/settings.h" +#if TARGET_PC +#include "dusk/achievements.h" +#endif class daB_GND_HIO_c : public JORReflexible { public: @@ -1289,6 +1292,9 @@ static void b_gnd_g_wait(b_gnd_class* i_this) { if (i_this->mMoveMode < 5 && i_this->mPlayerDistXZ < 600.0f) { i_this->mMoveMode = 5; i_this->field_0xc44[0] = 10; +#if TARGET_PC + dusk::AchievementSystem::get().signal("ganondorf_fishing_rod"); +#endif } } else if (i_this->mMoveMode == 5) { i_this->mMoveMode = 6; diff --git a/src/d/actor/d_a_e_th.cpp b/src/d/actor/d_a_e_th.cpp index 43ad8ec19b..056e9f565e 100644 --- a/src/d/actor/d_a_e_th.cpp +++ b/src/d/actor/d_a_e_th.cpp @@ -12,6 +12,9 @@ #include "c/c_damagereaction.h" #include "f_op/f_op_actor_enemy.h" #include "f_op/f_op_camera_mng.h" +#if TARGET_PC +#include "dusk/achievements.h" +#endif class daE_TH_HIO_c : public JORReflexible { public: @@ -542,6 +545,7 @@ static void damage_check(e_th_class* i_this) { if (i_this->field_0x6a4 == 0 && i_this->mAction != ACTION_SPIN) { daPy_py_c* player = (daPy_py_c*)dComIfGp_getPlayer(0); OS_REPORT("E_th HP1 %d\n", i_this->health); + s16 prevHealth = i_this->health; cc_at_check(i_this, &i_this->mAtInfo); OS_REPORT("E_th HP2 %d\n", i_this->health); @@ -554,6 +558,11 @@ static void damage_check(e_th_class* i_this) { dComIfGs_onOneZoneSwitch(3, -1); if (i_this->health <= 0) { +#if TARGET_PC + if (prevHealth == i_this->field_0x560) { + dusk::AchievementSystem::get().signal("dark_hammer_one_hit"); + } +#endif i_this->mAction = ACTION_END; i_this->mMode = 0; i_this->field_0x68a |= 4; diff --git a/src/d/d_cc_uty.cpp b/src/d/d_cc_uty.cpp index 7d71e490ac..ec9a177683 100644 --- a/src/d/d_cc_uty.cpp +++ b/src/d/d_cc_uty.cpp @@ -13,6 +13,9 @@ #include "d/d_s_play.h" #include "d/d_com_inf_game.h" #include "f_op/f_op_actor_mng.h" +#if TARGET_PC +#include "dusk/achievements.h" +#endif static int plCutLRC[58] = { 0, // @@ -434,6 +437,11 @@ fopAc_ac_c* cc_at_check(fopAc_ac_c* i_enemy, dCcU_AtInfo* i_AtInfo) { if (i_AtInfo->mAttackPower != 0 && i_enemy->health <= 0) { i_AtInfo->mHitStatus = 2; i_enemy->health = 0; +#if TARGET_PC + if (fopAcM_GetGroup(i_enemy) == fopAc_ENEMY_e) { + dusk::AchievementSystem::get().signal("enemy_killed"); + } +#endif } int uvar8; diff --git a/src/dusk/achievements.cpp b/src/dusk/achievements.cpp index 26a302678e..637dd13980 100644 --- a/src/dusk/achievements.cpp +++ b/src/dusk/achievements.cpp @@ -2,11 +2,16 @@ #include "dusk/io.hpp" #include "dusk/main.h" #include "d/d_com_inf_game.h" +#include "d/d_item_data.h" +#include "d/d_map_path_fmap.h" +#include "d/d_stage.h" +#include "d/d_menu_fmap.h" +#include "JSystem/JKernel/JKRArchive.h" #include "d/d_meter2_info.h" #include "d/actor/d_a_alink.h" +#include "d/actor/d_a_ni.h" #include "d/actor/d_a_npc4.h" #include "d/actor/d_a_player.h" -#include "d/d_demo.h" #include "f_pc/f_pc_name.h" #include "f_op/f_op_actor_mng.h" @@ -17,6 +22,14 @@ namespace dusk { using json = nlohmann::json; +static void* s_cucco_play_search(void* i_actor, void*) { + if (!fopAcM_IsActor(i_actor) || fopAcM_GetName((fopAc_ac_c*)i_actor) != fpcNm_NI_e) { + return nullptr; + } + auto* ni = static_cast(i_actor); + return ni->mAction == ACTION_PLAY_e ? i_actor : nullptr; +} + static void checkGoatHerding(Achievement& a, int32_t threshMs) { if (dMeter2Info_getMaxCount() != 20 || dMeter2Info_getNowCount() != 20) { return; @@ -31,6 +44,7 @@ static constexpr auto ACHIEVEMENTS_FILENAME = "achievements.json"; std::vector AchievementSystem::makeEntries() { return { + // Story { { "hero_of_twilight", @@ -47,6 +61,433 @@ std::vector AchievementSystem::makeEntries() { }, {} }, + { + { + "completionist", + "Completionist", + "100% the game.", + AchievementCategory::Story, + false, 0, 0, false + }, + [](Achievement& a, json&) { + const auto* link = static_cast(daPy_getPlayerActorClass()); + if (link == nullptr || link->mProcID != daAlink_c::PROC_GANON_FINISH) { + return; + } + if (dComIfGs_getMaxLife() < 100) { + return; + } + for (int i = 0; i < 4; ++i) { + if (!dComIfGs_isCollectMirror(i)) { + return; + } + } + for (int i = 0; i < 3; ++i) { + if (!dComIfGs_isCollectCrystal(i)) { + return; + } + } + static const u16 skillBits[] = { + dSv_event_flag_c::F_0338, dSv_event_flag_c::F_0339, + dSv_event_flag_c::F_0340, dSv_event_flag_c::F_0341, + dSv_event_flag_c::F_0342, dSv_event_flag_c::F_0343, + dSv_event_flag_c::F_0344 + }; + for (u16 bit : skillBits) { + if (!dComIfGs_isEventBit(bit)) { + return; + } + } + if (dComIfGs_checkGetInsectNum() < 24) { + return; + } + if (dComIfGs_getPohSpiritNum() < 60) { + return; + } + if (dComIfGs_getWalletSize() < 2) { + return; + } + if (dComIfGs_getArrowMax() < 100) { + return; + } + if (!dComIfGs_isCollectSword(COLLECT_MASTER_SWORD)) { + return; + } + if (!dComIfGs_isCollectShield(COLLECT_HYLIAN_SHIELD)) { + return; + } + if (!dComIfGs_isCollectClothes(KOKIRI_CLOTHES_FLAG)) { + return; + } + if (!dComIfGs_isItemFirstBit(dItemNo_WEAR_ZORA_e)) { + return; + } + if (!dComIfGs_isItemFirstBit(dItemNo_ARMOR_e)) { + return; + } + static const struct { int stage; int sw; } warpPortals[] = { + { dStage_SaveTbl_ORDON, 52 }, // Ordon Spring + { dStage_SaveTbl_FARON, 71 }, // South Faron Woods + { dStage_SaveTbl_FARON, 2 }, // North Faron Woods + { dStage_SaveTbl_GROVE, 100 }, // Sacred Grove + { dStage_SaveTbl_FIELD, 21 }, // Gorge + { dStage_SaveTbl_ELDIN, 31 }, // Kakariko Village + { dStage_SaveTbl_ELDIN, 21 }, // Death Mountain + { dStage_SaveTbl_FIELD, 99 }, // Bridge of Eldin + { dStage_SaveTbl_FIELD, 3 }, // Castle Town + { dStage_SaveTbl_LANAYRU, 10 }, // Lake Hylia + { dStage_SaveTbl_LANAYRU, 2 }, // Zora's Domain + { dStage_SaveTbl_LANAYRU, 21 }, // Upper Zora's River + { dStage_SaveTbl_SNOWPEAK, 21 }, // Snowpeak + { dStage_SaveTbl_DESERT, 21 }, // Gerudo Mesa + { dStage_SaveTbl_DESERT, 40 }, // Mirror Chamber + }; + for (const auto& p : warpPortals) { + if (!g_dComIfG_gameInfo.info.getSavedata().getSave(p.stage).getBit().isSwitch(p.sw)) { + return; + } + } + if (dComIfGs_getCollectSmell() == dItemNo_NONE_e) { + return; + } + + if (dMeter2Info_getRecieveLetterNum() == 0) { + return; + } + + bool hasJournal = false; + for (int fi = 0; fi < 6; ++fi) { + if (dComIfGs_getFishNum(fi) != 0) { + hasJournal = true; + break; + } + } + if (!hasJournal) { + return; + } + + int bottleCount = 0; + for (int i = 0; i < dSv_player_item_c::BOTTLE_MAX; ++i) { + if (dComIfGs_getItem(SLOT_11 + i, false) != dItemNo_NONE_e) { + bottleCount++; + } + } + if (bottleCount < 4) { + return; + } + + int bombBagCount = 0; + for (int i = 0; i < dSv_player_item_c::BOMB_BAG_MAX; ++i) { + if (dComIfGs_getItem(SLOT_15 + i, false) != dItemNo_NONE_e) { + bombBagCount++; + } + } + if (bombBagCount < 3) { + return; + } + + bool hasJewelRod = false; + for (int slot = 0; slot < 24 && !hasJewelRod; ++slot) { + const u8 item = dComIfGs_getItem(slot, false); + if (item == dItemNo_JEWEL_ROD_e || item == dItemNo_JEWEL_BEE_ROD_e || item == dItemNo_JEWEL_WORM_ROD_e) { + hasJewelRod = true; + } + } + if (!hasJewelRod) { + return; + } + + static const u8 requiredWheelItems[] = { + dItemNo_BOOMERANG_e, + dItemNo_BOW_e, + dItemNo_W_HOOKSHOT_e, + dItemNo_SPINNER_e, + dItemNo_IRONBALL_e, + dItemNo_COPY_ROD_e, + dItemNo_HVY_BOOTS_e, + dItemNo_KANTERA_e, + dItemNo_PACHINKO_e, + dItemNo_HAWK_EYE_e, + dItemNo_ANCIENT_DOCUMENT_e, + dItemNo_HORSE_FLUTE_e, + }; + for (u8 required : requiredWheelItems) { + bool found = false; + for (int slot = 0; slot < 24; ++slot) { + if (dComIfGs_getItem(slot, false) == required) { + found = true; + break; + } + } + if (!found) { + return; + } + } + a.progress = 1; + }, + {} + }, + // Collection + { + { + "princess_of_bugs", + "The Princess of Bugs", + "Deliver all 24 golden bugs to Agitha.", + AchievementCategory::Collection, + true, 24, 0, false + }, + [](Achievement& a, json&) { + a.progress = dComIfGs_checkGetInsectNum(); + }, + {} + }, + { + { + "all_poes", + "Poe Collector", + "Collect all 60 Poe Souls.", + AchievementCategory::Collection, + true, 60, 0, false + }, + [](Achievement& a, json&) { + a.progress = dComIfGs_getPohSpiritNum(); + }, + {} + }, + { + { + "hylian_loach", + "Legendary Catch", + "Catch a Hylian Loach.", + AchievementCategory::Collection, + false, 0, 0, false + }, + [](Achievement& a, json&) { + if (dComIfGs_getFishNum(1) > 0) { + a.progress = 1; + } + }, + {} + }, + { + { + "all_fish", + "Gone Fishin'", + "Catch all 6 species of fish.", + AchievementCategory::Collection, + true, 6, 0, false + }, + [](Achievement& a, json&) { + int nUniqueFish = 0; + for (int i = 0; i < 6; ++i) { + if (dComIfGs_getFishNum(i) != 0) { + nUniqueFish++; + } + } + a.progress = nUniqueFish; + }, + {} + }, + { + { + "a_big_heart", + "A Big Heart", + "Reach maximum health with all 20 heart containers.", + AchievementCategory::Collection, + true, 20, 0, false + }, + [](Achievement& a, json&) { + a.progress = dComIfGs_getMaxLife() / 5; + }, + {} + }, + { + { + "all_bottles", + "Glassware Guardian", + "Obtain all 4 bottles.", + AchievementCategory::Collection, + true, 4, 0, false + }, + [](Achievement& a, json&) { + if (daPy_getPlayerActorClass() == nullptr) { + return; + } + int count = 0; + for (int i = 0; i < dSv_player_item_c::BOTTLE_MAX; ++i) { + if (dComIfGs_getItem(SLOT_11 + i, false) != dItemNo_NONE_e) { + count++; + } + } + a.progress = count; + }, + {} + }, + { + { + "all_hidden_skills", + "Master of Secrets", + "Learn all 7 Hidden Skills.", + AchievementCategory::Collection, + true, 7, 0, false + }, + [](Achievement& a, json&) { + static const u16 skillBits[] = { + dSv_event_flag_c::F_0338, dSv_event_flag_c::F_0339, + dSv_event_flag_c::F_0340, dSv_event_flag_c::F_0341, + dSv_event_flag_c::F_0342, dSv_event_flag_c::F_0343, + dSv_event_flag_c::F_0344 + }; + int count = 0; + for (u16 bit : skillBits) { + if (dComIfGs_isEventBit(bit)) { + count++; + } + } + a.progress = count; + }, + {} + }, + // Challenge + { + { + "cave_of_ordeals", + "Conqueror of Ordeals", + "Clear all 50 floors of the Cave of Ordeals.", + AchievementCategory::Challenge, + false, 0, 0, false + }, + [](Achievement& a, json&) { + if (daNpcF_chkEvtBit(0x1F9)) { + a.progress = 1; + } + }, + {} + }, + { + { + "cave_of_ordeals_heartless", + "Indomitable", + "Clear all 50 floors of the Cave of Ordeals with only 3 heart containers.", + AchievementCategory::Challenge, + false, 0, 0, false + }, + [](Achievement& a, json&) { + if (daNpcF_chkEvtBit(0x1F9) && dComIfGs_getMaxLife() <= 15) { + a.progress = 1; + } + }, + {} + }, + { + { + "speedrun_12h", + "Been There Done That", + "Defeat Ganondorf with a total save file play time under 12 hours.", + AchievementCategory::Challenge, + false, 0, 0, false + }, + [](Achievement& a, json&) { + const auto* link = static_cast(daPy_getPlayerActorClass()); + if (link == nullptr || link->mProcID != daAlink_c::PROC_GANON_FINISH) { + return; + } + const int64_t ticks = (static_cast(OSGetTime()) - dComIfGs_getSaveStartTime()) + dComIfGs_getSaveTotalTime(); + if (ticks / OS_TIMER_CLOCK < 12 * 3600) { + a.progress = 1; + } + }, + {} + }, + { + { + "speedrun_8h", + "Swift Blade", + "Defeat Ganondorf with a total save file play time under 6 hours.", + AchievementCategory::Challenge, + false, 0, 0, false + }, + [](Achievement& a, json&) { + const auto* link = static_cast(daPy_getPlayerActorClass()); + if (link == nullptr || link->mProcID != daAlink_c::PROC_GANON_FINISH) { + return; + } + const int64_t ticks = (static_cast(OSGetTime()) - dComIfGs_getSaveStartTime()) + dComIfGs_getSaveTotalTime(); + if (ticks / OS_TIMER_CLOCK < 8 * 3600) { + a.progress = 1; + } + }, + {} + }, + { + { + "dark_hammer_one_hit", + "Mortal Edge", + "Defeat Dark Hammer in a single hit.", + AchievementCategory::Challenge, + false, 0, 0, false + }, + [](Achievement& a, json&) { + if (AchievementSystem::get().hasSignal("dark_hammer_one_hit")) { + a.progress = 1; + } + }, + {} + }, + { + { + "no_deaths_clear", + "Deathless", + "Defeat Ganondorf with 0 deaths on your save file.", + AchievementCategory::Challenge, + false, 0, 0, false + }, + [](Achievement& a, json&) { + const auto* link = static_cast(daPy_getPlayerActorClass()); + if (link == nullptr || link->mProcID != daAlink_c::PROC_GANON_FINISH) { + return; + } + if (dComIfGs_getDeathCount() == 0) { + a.progress = 1; + } + }, + {} + }, + { + { + "untouchable", + "Untouchable", + "Kill 25 enemies in a row without taking damage.", + AchievementCategory::Challenge, + true, 25, 0, false + }, + [](Achievement& a, json&) { + auto& sys = AchievementSystem::get(); + if (sys.hasSignal("player_damaged")) { + a.progress = 0; + } + if (sys.hasSignal("enemy_killed")) { + a.progress++; + } + }, + {} + }, + { + { + "bow_100m_hit", + "Long Shot", + "Hit an enemy from over 100 meters away with the bow.", + AchievementCategory::Challenge, + false, 0, 0, false + }, + [](Achievement& a, json&) { + if (AchievementSystem::get().hasSignal("arrow_hit_100m")) { + a.progress = 1; + } + }, + {} + }, + // Minigame { { "plumm_max", @@ -133,14 +574,16 @@ std::vector AchievementSystem::makeEntries() { }, { { - "cave_of_ordeals", - "Conqueror of Ordeals", - "Clear all 50 floors of the Cave of Ordeals.", - AchievementCategory::Challenge, + "snowboard_70s", + "Downhill Dash", + "Finish the snowboarding minigame in under 70 seconds.", + AchievementCategory::Minigame, false, 0, 0, false }, [](Achievement& a, json&) { - if (daNpcF_chkEvtBit(0x1F9)) { + const int32_t bestMs = dComIfGs_getRaceGameTime(); + if (dComIfGs_isEventBit(dSv_event_flag_c::F_0481) && + bestMs > 0 && bestMs <= 70000) { a.progress = 1; } }, @@ -148,132 +591,28 @@ std::vector AchievementSystem::makeEntries() { }, { { - "cave_of_ordeals_heartless", - "Indomitable", - "Clear all 50 floors of the Cave of Ordeals with only 3 heart containers.", - AchievementCategory::Challenge, - false, 0, 0, false - }, - [](Achievement& a, json&) { - if (daNpcF_chkEvtBit(0x1F9) && dComIfGs_getMaxLife() <= 15) { - a.progress = 1; - } - }, - {} - }, - { - { - "speedrun_12h", - "Been There Done That", - "Defeat Ganondorf with a total save file play time under 12 hours.", - AchievementCategory::Challenge, + "canoe_perfect", + "River Raider", + "Achieve a perfect score in the canoe minigame.", + AchievementCategory::Minigame, false, 0, 0, false }, [](Achievement& a, json&) { const auto* link = static_cast(daPy_getPlayerActorClass()); - if (link == nullptr || link->mProcID != daAlink_c::PROC_GANON_FINISH) { + if (link == nullptr) { return; } - const int64_t ticks = (static_cast(OSGetTime()) - dComIfGs_getSaveStartTime()) + dComIfGs_getSaveTotalTime(); - if (ticks / OS_TIMER_CLOCK < 12 * 3600) { + static bool wasInCanoe = false; + bool inCanoe = link->mProcID >= daAlink_c::PROC_CANOE_RIDE && + link->mProcID <= daAlink_c::PROC_CANOE_KANDELAAR_POUR; + if (wasInCanoe && !inCanoe && dMeter2Info_getNowCount() >= 30) { a.progress = 1; } + wasInCanoe = inCanoe; }, {} }, - { - { - "speedrun_8h", - "Swift Blade", - "Defeat Ganondorf with a total save file play time under 6 hours.", - AchievementCategory::Challenge, - false, 0, 0, false - }, - [](Achievement& a, json&) { - const auto* link = static_cast(daPy_getPlayerActorClass()); - if (link == nullptr || link->mProcID != daAlink_c::PROC_GANON_FINISH) { - return; - } - const int64_t ticks = (static_cast(OSGetTime()) - dComIfGs_getSaveStartTime()) + dComIfGs_getSaveTotalTime(); - if (ticks / OS_TIMER_CLOCK < 8 * 3600) { - a.progress = 1; - } - }, - {} - }, - { - { - "princess_of_bugs", - "The Princess of Bugs", - "Deliver all 24 golden bugs to Agitha.", - AchievementCategory::Collection, - true, 24, 0, false - }, - [](Achievement& a, json&) { - a.progress = dComIfGs_checkGetInsectNum(); - }, - {} - }, - { - { - "all_poes", - "Poe Collector", - "Collect all 60 Poe Souls.", - AchievementCategory::Collection, - true, 60, 0, false - }, - [](Achievement& a, json&) { - a.progress = dComIfGs_getPohSpiritNum(); - }, - {} - }, - { - { - "hylian_loach", - "Legendary Catch", - "Catch a Hylian Loach.", - AchievementCategory::Collection, - false, 0, 0, false - }, - [](Achievement& a, json&) { - if (dComIfGs_getFishNum(1) > 0) { - a.progress = 1; - } - }, - {} - }, - { - { - "all_fish", - "Gone Fishin'", - "Catch all 6 species of fish.", - AchievementCategory::Collection, - true, 6, 0, false - }, - [](Achievement& a, json&) { - int nUniqueFish = 0; - for (int i = 0; i < 6; ++i) { - if (dComIfGs_getFishNum(i) != 0) { - nUniqueFish++; - } - } - a.progress = nUniqueFish; - }, - {} - }, - { - { - "a_big_heart", - "A Big Heart", - "Reach maximum health with all 20 heart containers.", - AchievementCategory::Collection, - true, 20, 0, false - }, - [](Achievement& a, json&) { - a.progress = dComIfGs_getMaxLife() / 5; - }, - {} - }, + // Misc { { "friendly_fire", @@ -326,6 +665,87 @@ std::vector AchievementSystem::makeEntries() { }, {} }, + { + { + "email_me", + "Email Me", + "Read a letter during the Dark Beast Ganon fight.", + AchievementCategory::Misc, + false, 0, 0, false + }, + [](Achievement& a, json&) { + void* dbgExists = fopAcM_SearchByName(fpcNm_B_MGN_e); + if (dbgExists && AchievementSystem::get().hasSignal("open_letter")) { + a.progress = 1; + } + }, + {} + }, + { + { + "heavy_hitter", + "Heavy Hitter", + "Wear the Iron Boots during the end credits.", + AchievementCategory::Misc, + false, 0, 0, false + }, + [](Achievement& a, json&) { + const auto* link = static_cast(daPy_getPlayerActorClass()); + if (link == nullptr || link->mProcID != daAlink_c::PROC_GANON_FINISH) { + return; + } + if (daPy_getPlayerActorClass()->checkEquipHeavyBoots()) { + a.progress = 1; + } + }, + {} + }, + { + { + "fishing_rod_ganondorf", + "Here Fishy Fishy", + "Confuse Ganondorf with the fishing rod.", + AchievementCategory::Misc, + false, 0, 0, false + }, + [](Achievement& a, json&) { + if (AchievementSystem::get().hasSignal("ganondorf_fishing_rod")) { + a.progress = 1; + } + }, + {} + }, + { + { + "steal_from_trill", + "Petty Theft", + "Steal from Trill.", + AchievementCategory::Misc, + false, 0, 0, false + }, + [](Achievement& a, json&) { + if (dComIfGs_isEventBit(dSv_event_flag_c::F_0758)) { + a.progress = 1; + } + }, + {} + }, + { + { + "cucco_control", + "Cucco Whisperer", + "Take control of a cucco.", + AchievementCategory::Misc, + false, 0, 0, false + }, + [](Achievement& a, json&) { + if (fopAcM_Search(s_cucco_play_search, nullptr) != nullptr) { + a.progress = 1; + } + }, + {} + }, + // Glitched { { "back_in_time", @@ -411,34 +831,79 @@ std::vector AchievementSystem::makeEntries() { }, { { - "email_me", - "Email Me", - "Read a letter during the Dark Beast Ganon fight.", - AchievementCategory::Misc, + "no_fish_suit", + "No Fish Suit No Problem", + "Defeat Morpheel without equipping Zora Armor.", + AchievementCategory::Glitched, false, 0, 0, false }, [](Achievement& a, json&) { - void* dbgExists = fopAcM_SearchByName(fpcNm_B_MGN_e); - if (dbgExists && AchievementSystem::get().hasSignal("open_letter")) { + static bool prevMorpheelAlive = false; + static bool inArena = false; + static bool zoraWorn = false; + const bool morpheelAlive = fopAcM_SearchByName(fpcNm_B_OH_e) != nullptr; + const bool lakebedCleared = dComIfGs_isEventBit(dSv_event_flag_c::M_045); + + if (morpheelAlive && !lakebedCleared) { + inArena = true; + if (daPy_py_c::checkZoraWearFlg()) { + zoraWorn = true; + } + } + + if (prevMorpheelAlive && !morpheelAlive && inArena && !zoraWorn) { a.progress = 1; } + + prevMorpheelAlive = morpheelAlive; + }, + {} + }, + { + { + "null_item", + "Null Item", + "Obtain the mysterious black rupee in the item wheel.", + AchievementCategory::Glitched, + false, 0, 0, false + }, + [](Achievement& a, json&) { + if (daPy_getPlayerActorClass() == nullptr) { + return; + } + for (int i = 0; i < 24; ++i) { + if (dComIfGs_getItem(i, false) == 0x00) { + a.progress = 1; + break; + } + } }, {} }, { { - "heavy-hitter", - "Heavy Hitter", - "Wear the Iron Boots during the end credits.", - AchievementCategory::Misc, + "stallord_skip", + "Stallord Skip", + "Leave Stallord's arena through the exit without defeating Stallord.", + AchievementCategory::Glitched, false, 0, 0, false }, [](Achievement& a, json&) { - const auto* link = static_cast(daPy_getPlayerActorClass()); - if (link == nullptr || link->mProcID != daAlink_c::PROC_GANON_FINISH) { + static bool seenStallord = false; + if (strcmp(dComIfGp_getStartStageName(), "D_MN10A") != 0) { + seenStallord = false; return; } - if (daPy_getPlayerActorClass()->checkEquipHeavyBoots()) { + if (dComIfGs_isEventBit(dSv_event_flag_c::F_0265)) { + seenStallord = false; + return; + } + if (fopAcM_SearchByName(fpcNm_B_DS_e) != nullptr) { + seenStallord = true; + } + if (seenStallord && + dComIfGp_isEnableNextStage() && + strcmp(dComIfGp_getNextStageName(), "F_SP125") == 0) { a.progress = 1; } }, From 44f3828f682f1246c78d98ee5d925313017c80bb Mon Sep 17 00:00:00 2001 From: madeline Date: Thu, 30 Apr 2026 02:48:30 -0700 Subject: [PATCH 119/390] fix morpheel logic --- src/dusk/achievements.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/dusk/achievements.cpp b/src/dusk/achievements.cpp index 637dd13980..ec1eeaad55 100644 --- a/src/dusk/achievements.cpp +++ b/src/dusk/achievements.cpp @@ -11,6 +11,7 @@ #include "d/actor/d_a_alink.h" #include "d/actor/d_a_ni.h" #include "d/actor/d_a_npc4.h" +#include "d/actor/d_a_b_ob.h" #include "d/actor/d_a_player.h" #include "f_pc/f_pc_name.h" #include "f_op/f_op_actor_mng.h" @@ -841,9 +842,15 @@ std::vector AchievementSystem::makeEntries() { static bool prevMorpheelAlive = false; static bool inArena = false; static bool zoraWorn = false; - const bool morpheelAlive = fopAcM_SearchByName(fpcNm_B_OH_e) != nullptr; + const auto* morpheel = static_cast(fopAcM_SearchByName(fpcNm_B_OB_e)); + const bool morpheelAlive = morpheel != nullptr && morpheel->mAnmID != 0x14; + const bool morpheelDead = morpheel != nullptr && morpheel->mAnmID == 0x14; const bool lakebedCleared = dComIfGs_isEventBit(dSv_event_flag_c::M_045); + if (inArena && morpheel == nullptr) { + zoraWorn = false; + } + if (morpheelAlive && !lakebedCleared) { inArena = true; if (daPy_py_c::checkZoraWearFlg()) { @@ -851,7 +858,7 @@ std::vector AchievementSystem::makeEntries() { } } - if (prevMorpheelAlive && !morpheelAlive && inArena && !zoraWorn) { + if (prevMorpheelAlive && morpheelDead && inArena && !zoraWorn) { a.progress = 1; } From 5899b2157a83f0eecf6d8a26bea3c610864e6b99 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Thu, 30 Apr 2026 09:29:42 -0400 Subject: [PATCH 120/390] fix bow aiming in first person --- src/d/d_camera.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/d/d_camera.cpp b/src/d/d_camera.cpp index 471c93bb19..497d349e46 100644 --- a/src/d/d_camera.cpp +++ b/src/d/d_camera.cpp @@ -7091,10 +7091,12 @@ bool dCamera_c::subjectCamera(s32 param_0) { cXyz sp1E0(val0, val2, val1); #if TARGET_PC - f32 aspect = mDoGph_gInf_c::getAspect(); - f32 baseAspect = FB_WIDTH / FB_HEIGHT; - if (aspect > baseAspect) { - sp1E0.z += (aspect - baseAspect) * 4; + if (sp13) { + f32 aspect = mDoGph_gInf_c::getAspect(); + f32 baseAspect = FB_WIDTH / FB_HEIGHT; + if (aspect > baseAspect) { + sp1E0.z += (aspect - baseAspect) * 4; + } } #endif From 1ac6df8de7956a790b7782e74a1503568f922904 Mon Sep 17 00:00:00 2001 From: "Jasper St. Pierre" Date: Thu, 30 Apr 2026 07:52:44 -0700 Subject: [PATCH 121/390] mirror clip fix closes #581 --- src/d/actor/d_a_obj_mirror_chain.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/d/actor/d_a_obj_mirror_chain.cpp b/src/d/actor/d_a_obj_mirror_chain.cpp index 92c062f7c8..da4a09e1c5 100644 --- a/src/d/actor/d_a_obj_mirror_chain.cpp +++ b/src/d/actor/d_a_obj_mirror_chain.cpp @@ -59,7 +59,8 @@ void dScissorBegin_packet_c::draw() { } if (sp50 >= 4) { - GXSetScissor(FB_WIDTH + 1, FB_HEIGHT + 1, 0, 0); + IF_DUSK(GXSetColorUpdate(GX_FALSE)); + IF_NOT_DUSK(GXSetScissor(FB_WIDTH + 1, FB_HEIGHT + 1, 0, 0)); return; } @@ -170,7 +171,8 @@ void dScissorBegin_packet_c::draw() { } if (spBC.z < 0.0f || var_f31 > sp6C || sp7C < sp70 || var_f30 > sp64 || sp78 < sp68) { - GXSetScissor(FB_WIDTH + 1, FB_HEIGHT + 1, 0, 0); + IF_DUSK(GXSetColorUpdate(GX_FALSE)); + IF_NOT_DUSK(GXSetScissor(FB_WIDTH + 1, FB_HEIGHT + 1, 0, 0)); } else { var_f31 = cLib_minLimit(var_f31, sp70); sp7C = cLib_maxLimit(sp7C, sp6C); @@ -187,6 +189,7 @@ void dScissorEnd_packet_c::draw() { #endif GXSetScissor(l_scissor[0], l_scissor[1], l_scissor[2], l_scissor[3]); + IF_DUSK(GXSetColorUpdate(GX_TRUE)); } static int createSolidHeap(fopAc_ac_c* i_this) { From b0e9033736529acf445665d99634f8f4ac4597d8 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Thu, 30 Apr 2026 10:55:53 -0400 Subject: [PATCH 122/390] Widescreen Field Map --- include/d/d_menu_fmap2D.h | 8 ++++++++ src/d/d_menu_fmap2D.cpp | 30 +++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/include/d/d_menu_fmap2D.h b/include/d/d_menu_fmap2D.h index 9b237f2771..d0152f0229 100644 --- a/include/d/d_menu_fmap2D.h +++ b/include/d/d_menu_fmap2D.h @@ -81,6 +81,10 @@ public: void calcDrawPriority(); void setArrowPosAxis(f32, f32); + #if TARGET_PC + void fMapBackWide(); + #endif + virtual void draw(); virtual ~dMenu_Fmap2DBack_c(); @@ -330,6 +334,10 @@ public: void setHIO(bool); bool isWarpAccept(); + #if TARGET_PC + void fMapTopWide(); + #endif + virtual void draw(); virtual ~dMenu_Fmap2DTop_c(); diff --git a/src/d/d_menu_fmap2D.cpp b/src/d/d_menu_fmap2D.cpp index 8692156daf..f01ef2a10d 100644 --- a/src/d/d_menu_fmap2D.cpp +++ b/src/d/d_menu_fmap2D.cpp @@ -20,6 +20,15 @@ #include "dusk/frame_interpolation.h" #include +#if TARGET_PC +void dMenu_Fmap2DBack_c::fMapBackWide() { + mpBaseScreen->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f); + mpBaseScreen->translate(mDoGph_gInf_c::getSafeMinXF(), 0.0f); + mpBackScreen->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f); + mpBackScreen->translate(mDoGph_gInf_c::getSafeMinXF(), 0.0f); +} +#endif + dMenu_Fmap2DBack_c::dMenu_Fmap2DBack_c() { dMeter2Info_setMapDrugFlag(0); @@ -267,6 +276,10 @@ dMenu_Fmap2DBack_c::~dMenu_Fmap2DBack_c() { } void dMenu_Fmap2DBack_c::draw() { + #if TARGET_PC + fMapBackWide(); + #endif + calcBlink(); J2DGrafContext* grafPort = dComIfGp_getCurrentGrafPort(); @@ -1199,7 +1212,7 @@ f32 dMenu_Fmap2DBack_c::getMapScissorAreaSizeX() { } f32 dMenu_Fmap2DBack_c::getMapScissorAreaSizeRealX() { -#if PLATFORM_GCN && !TARGET_PC +#if PLATFORM_GCN return getMapScissorAreaSizeX(); #else return getMapScissorAreaSizeX() * mDoGph_gInf_c::getScale(); @@ -2179,6 +2192,17 @@ void dMenu_Fmap2DBack_c::setArrowPosAxis(f32 i_posX, f32 i_posZ) { control_ypos = 0.0f; } +#if TARGET_PC +void dMenu_Fmap2DTop_c::fMapTopWide() { + mpTitleScreen->search(MULTI_CHAR('spot0_n'))->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f); + mpTitleScreen->search(MULTI_CHAR('spot2_n'))->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f); + mpTitleScreen->search(MULTI_CHAR('name_n'))->translate(mDoGph_gInf_c::ScaleHUDXLeft(-243.0f), -169.0f); + mpTitleScreen->search(MULTI_CHAR('sub_n_n'))->translate(mDoGph_gInf_c::ScaleHUDXLeft(-80.0f), -154.0f); + mpTitleScreen->search(MULTI_CHAR('btn_i_n'))->translate(mDoGph_gInf_c::ScaleHUDXLeft(-241.0f), 177.0f); + mpTitleScreen->search(MULTI_CHAR('cont_n'))->translate(mDoGph_gInf_c::ScaleHUDXRight(515.0f), 83.0f); +} +#endif + dMenu_Fmap2DTop_c::dMenu_Fmap2DTop_c(JKRExpHeap* i_heap, STControl* i_stick) { mpHeap = i_heap; mTransX = 0.0f; @@ -2572,6 +2596,10 @@ void dMenu_Fmap2DTop_c::setAllAlphaRate(f32 i_rate, bool i_init) { } void dMenu_Fmap2DTop_c::draw() { + #if TARGET_PC + fMapTopWide(); + #endif + u32 scissor_left, scissor_top, scissor_width, scissor_height; J2DOrthoGraph* ctx = static_cast(dComIfGp_getCurrentGrafPort()); ctx->setup2D(); From b0809ea78c7817286c59b2e910677c27c11a4de7 Mon Sep 17 00:00:00 2001 From: roeming Date: Thu, 30 Apr 2026 11:02:18 -0400 Subject: [PATCH 123/390] Add area flags --- src/dusk/imgui/ImGuiEventFlags.hpp | 2557 ++++++++++++++++++++++++++++ 1 file changed, 2557 insertions(+) diff --git a/src/dusk/imgui/ImGuiEventFlags.hpp b/src/dusk/imgui/ImGuiEventFlags.hpp index 694336da03..e759d46b8d 100644 --- a/src/dusk/imgui/ImGuiEventFlags.hpp +++ b/src/dusk/imgui/ImGuiEventFlags.hpp @@ -3,6 +3,9 @@ #include #include +#include +#include +#include struct duskImguiEventFlagEntry { uint8_t byteIndex; @@ -839,4 +842,2558 @@ inline const MultiBitEventFlag duskImguiSwappedU16Events[] = { { 0xfd, "Rupees owed to Trill" }, }; +struct EventAreaFlags +{ + uint8_t byteIndex; + uint8_t bitIndex; + uint16_t flagID; + std::string description; +}; + +inline EventAreaFlags eventAreaFlagsAG[] = +{ + { 0x00, 0x80, 0x0080, "Ooccoo Map Flag" }, + { 0x00, 0x40, 0x0040, "fourth small chest epic spinner room" }, + { 0x00, 0x20, 0x0020, "third small chest epic spinner room" }, + { 0x00, 0x10, 0x0010, "first small chest epic spinner room" }, + { 0x00, 0x08, 0x0008, "second small chest epic spinner room" }, + { 0x00, 0x04, 0x0004, "PoH first big chest epic spinner room" }, + { 0x00, 0x02, 0x0002, "small chest first west room" }, + { 0x00, 0x01, 0x0001, "small key big chest elevator room B1" }, + { 0x01, 0x80, 0x0180, "small key big chest first room" }, + { 0x01, 0x20, 0x0120, "small key small chest fouth east room" }, + { 0x01, 0x10, 0x0110, "big key chest" }, + { 0x01, 0x08, 0x0108, "PoH right big chest main room" }, + { 0x01, 0x04, 0x0104, "map left big chest main room" }, + { 0x01, 0x02, 0x0102, "west small chest in second west room" }, + { 0x01, 0x01, 0x0101, "north east small chest in second west room" }, + { 0x02, 0x08, 0x0208, "Spinner big chest" }, + { 0x03, 0x40, 0x0340, "small key small chest first east room B1" }, + { 0x03, 0x20, 0x0320, "small key big chest second east room 2F" }, + { 0x03, 0x10, 0x0310, "compass big chest second east room 2F" }, + { 0x03, 0x08, 0x0308, "big chest first west room" }, + { 0x08, 0x80, 0x0880, "killed second poe (triggers flame getting lit cs)" }, + { 0x08, 0x40, 0x0840, "killed first poe" }, + { 0x08, 0x08, 0x0808, "open gate to spinner in mini-boss room cs" }, + { 0x08, 0x04, 0x0804, "unlock exit in mini-boss room (despawns mini-boss)" }, + { 0x08, 0x01, 0x0801, "unlocked boss door" }, + { 0x09, 0x10, 0x0910, "started pulling chain in second east room 1F (stays set)" }, + { 0x09, 0x04, 0x0904, "stairs to lower east room appeared in main room" }, + { 0x09, 0x02, 0x0902, "risen tracks on pillar before boss" }, + { 0x09, 0x01, 0x0901, "unlocked door in second west room" }, + { 0x0A, 0x10, 0x0A10, "killed second poe (duplicate)" }, + { 0x0A, 0x02, 0x0A02, "Tiny bugs spawn in first room small key area (duplicate)" }, + { 0x0A, 0x01, 0x0A01, "Tiny bugs spawn in first room small key area" }, + { 0x0B, 0x80, 0x0B80, "stairs to lower west room appeared in main room cs" }, + { 0x0B, 0x20, 0x0B20, "turn walls in third room 2B cs" }, + { 0x0B, 0x10, 0x0B10, "turn walls in third room 2B" }, + { 0x0B, 0x08, 0x0B08, "open gates in first room" }, + { 0x0B, 0x04, 0x0B04, "open gates in first room cs" }, + { 0x0B, 0x01, 0x0B01, "Stallord Phase 2" }, + { 0x0C, 0x80, 0x0C80, "killed third poe (triggers flame getting lit cs)" }, + { 0x0C, 0x40, 0x0C40, "Main Hall Dig Spot" }, + { 0x0C, 0x01, 0x0C01, "turned walls in first east room (stays set)" }, + { 0x0D, 0x02, 0x0D02, "turned slab in first east room B1 (stays set)" }, + { 0x0E, 0x10, 0x0E10, "Intro Cutscene" }, + { 0x0F, 0x80, 0x0F80, "unlocked door in second east room 2F" }, + { 0x0F, 0x40, 0x0F40, "open poe door once all poe flames are present (removes poe bodies)" }, + { 0x0F, 0x20, 0x0F20, "poe flame top left present" }, + { 0x0F, 0x10, 0x0F10, "poe flame bottom right present" }, + { 0x0F, 0x08, 0x0F08, "poe flame top right present" }, + { 0x0F, 0x04, 0x0F04, "poe flame bottom left present" }, + { 0x0F, 0x02, 0x0F02, "killed fourth poe (triggers flame getting lit cs)" }, + { 0x0F, 0x01, 0x0F01, "flame from third poe leaving lantern cs" }, + { 0x10, 0x40, 0x1040, "killed third poe (duplicate)" }, + { 0x10, 0x20, 0x1020, "flame from second poe leaving lantern cs" }, + { 0x10, 0x10, 0x1010, "open walls in third east room" }, + { 0x10, 0x08, 0x1008, "unlocked door in elevator room 2B" }, + { 0x10, 0x04, 0x1004, "unlocked door in first room" }, + { 0x10, 0x02, 0x1002, "killed stalfos in second west room" }, + { 0x11, 0x80, 0x1180, "killed gibdo in first east room B1" }, + { 0x11, 0x20, 0x1120, "reach boss door (unset once you enter)" }, + { 0x11, 0x04, 0x1104, "killed third poe (duplicate)" }, + { 0x11, 0x02, 0x1102, "unlock door in second room" }, + { 0x11, 0x01, 0x1101, "lit right torch in second room" }, + { 0x12, 0x80, 0x1280, "lit left torch in second room" }, + { 0x12, 0x40, 0x1240, "close spinner slot for walls in third room 2B" }, + { 0x12, 0x20, 0x1220, "unlocked door in first east room 1F" }, + { 0x12, 0x08, 0x1208, "risen tracks on pillar before boss cs" }, + { 0x12, 0x04, 0x1204, "pushed block in first west room" }, + { 0x12, 0x01, 0x1201, "taken down the cube in the second east room 1F" }, + { 0x13, 0x80, 0x1380, "placed cube at the right spot in the second east room 1F" }, + { 0x13, 0x40, 0x1340, "unlock door in fouth east room" }, + { 0x13, 0x20, 0x1320, "close poe door (unsets after lighting torches)" }, + { 0x13, 0x08, 0x1308, "main room poes taking flames cs" }, + { 0x14, 0x10, 0x1410, "explored first room" }, + { 0x14, 0x08, 0x1408, "open exit door in boss room" }, + { 0x15, 0x80, 0x1580, "Midna Text after defeating boss" }, + { 0x15, 0x08, 0x1508, "killed first stalfos in room before mini-boss" }, + { 0x15, 0x04, 0x1504, "killed second stalfos in room before mini-boss" }, + { 0x15, 0x02, 0x1502, "killed third stalfos in room before mini-boss" }, + { 0x15, 0x01, 0x1501, "extend platform to exit in boss room" }, + { 0x16, 0x80, 0x1680, "open gate to spinner in mini-boss room cs" }, + { 0x16, 0x40, 0x1640, "open gate to spinner in mini-boss room" }, + { 0x16, 0x10, 0x1610, "open wall in third west room cs (unset once you leave)" }, + { 0x16, 0x08, 0x1608, "pulled chain in main room" }, + { 0x16, 0x04, 0x1604, "pulled the chain in first room (triggers cs)" }, + { 0x16, 0x02, 0x1602, "open wall in third west room" }, + { 0x17, 0x40, 0x1740, "killed gibdos in third east room" }, + { 0x17, 0x20, 0x1720, "Ooccoo Rescued" }, + { 0x17, 0x10, 0x1710, "opened gates in room before mini-boss" }, + { 0x17, 0x08, 0x1708, "killed fourth poe (duplicate)" }, + { 0x17, 0x02, 0x1702, "dig spot in third east room" }, + { 0x17, 0x01, 0x1701, "Spinner big chest (set after)" }, +}; + +inline EventAreaFlags eventAreaFlagsCastleTown[] = +{ + { 0x03, 0x02, 0x0302, "small chest on doctor's balcony" }, + { 0x06, 0x10, 0x0610, "tear of light next to Telma's bar" }, + { 0x08, 0x80, 0x0880, "killed poe in Jovani's house (set if you dig into the house)" }, + { 0x08, 0x04, 0x0804, "explored 3nd room Jovani-Sewers " }, + { 0x08, 0x02, 0x0802, "explored 2nd room Jovani-Sewers " }, + { 0x08, 0x01, 0x0801, "?" }, + { 0x09, 0x80, 0x0980, "?" }, + { 0x09, 0x40, 0x0940, "?" }, + { 0x09, 0x20, 0x0920, "?" }, + { 0x09, 0x02, 0x0902, "intro cs twlight" }, + { 0x09, 0x01, 0x0901, "midna text after listening to Telma and Ilia spirits during twilight" }, + { 0x0A, 0x80, 0x0A80, "midna breaking castle barrier cs" }, + { 0x0A, 0x20, 0x0A20, "warp you to Lanayru spring (trigger twilight end)" }, + { 0x0A, 0x10, 0x0A10, "fan girl text next to star tent" }, + { 0x0A, 0x04, 0x0A04, "star tent intro cs" }, + { 0x0A, 0x02, 0x0A02, "invisible wall behind doctor gone" }, + { 0x0A, 0x01, 0x0A01, "?" }, + { 0x0B, 0x80, 0x0B80, "water is back in town (twilight)" }, + { 0x0B, 0x40, 0x0B40, "explored east alley that leads south" }, + { 0x0B, 0x20, 0x0B20, "star tent has double clawshot mini-game" }, + { 0x0B, 0x10, 0x0B10, "explored area with star tent" }, + { 0x0B, 0x08, 0x0B08, "explored alley with entrance to Jovani's house" }, + { 0x0B, 0x04, 0x0B04, "explored alley with entrance to agitha's house" }, + { 0x0B, 0x02, 0x0B02, "explored area with entrance to Telma's bar" }, + { 0x0B, 0x01, 0x0B01, "STAR 1 Completed" }, + { 0x0D, 0x04, 0x0D04, "map marker hero's shade" }, + { 0x0E, 0x10, 0x0E10, "malo mart posters on shop" }, + { 0x0E, 0x08, 0x0E08, "magic armor bought malo mart" }, + { 0x0E, 0x04, 0x0E04, "?" }, + { 0x0E, 0x02, 0x0E02, "enter Telma's bar from top intro cs" }, + { 0x0E, 0x01, 0x0E01, "first right door to castle pushed once (default)" }, + { 0x0F, 0x80, 0x0F80, "first left door to castle pushed once (default)" }, + { 0x0F, 0x40, 0x0F40, "first right door to castle pushed twice" }, + { 0x0F, 0x20, 0x0F20, "first right door to castle half closed" }, + { 0x0F, 0x10, 0x0F10, "first left door to castle closed" }, + { 0x0F, 0x08, 0x0F08, "first left door to castle pushed twice" }, + { 0x0F, 0x04, 0x0F04, "Jovani's house intro cs" }, + { 0x0F, 0x02, 0x0F02, "Jovani text after killing poe" }, + { 0x0F, 0x01, 0x0F01, "open path to sewers (Jovani's house)" }, + { 0x10, 0x80, 0x1080, "?" }, + { 0x16, 0x80, 0x1680, "killed light bug next to Telma's bar" }, + { 0x17, 0x08, 0x1708, "Gengle free (Jovani's house)" }, + { 0x17, 0x04, 0x1704, "Midna opens map to look for the last light bug" }, +}; + +inline EventAreaFlags eventAreaFlagsCitS[] = +{ + { 0x00, 0x08, 0x0008, "south east underwater big chest outside shop" }, + { 0x00, 0x04, 0x0004, "big chest east wing second room 2F" }, + { 0x00, 0x02, 0x0002, "big chest west wing main room 2F" }, + { 0x00, 0x01, 0x0001, "small chest main room 4F outside" }, + { 0x01, 0x80, 0x0180, "small chest west wing north room 2F" }, + { 0x01, 0x40, 0x0140, "center small chest west wing main room 1F" }, + { 0x01, 0x20, 0x0120, "small chest west wing main room B1" }, + { 0x01, 0x10, 0x0110, "north east small chest west wing main room 1F" }, + { 0x01, 0x08, 0x0108, "small chest east wing second room 1F" }, + { 0x01, 0x04, 0x0104, "small chest east wing second room 2F" }, + { 0x01, 0x02, 0x0102, "big chest ouside north wing" }, + { 0x02, 0x80, 0x0280, "small chest west wing main room 3F" }, + { 0x02, 0x40, 0x0240, "small chest main room 3F inside" }, + { 0x02, 0x20, 0x0220, "big key chest" }, + { 0x02, 0x10, 0x0210, "big chest main room 4F outside" }, + { 0x02, 0x08, 0x0208, "small chest west wing main room 2F" }, + { 0x02, 0x02, 0x0202, "PoH big chest west wing main room 3F" }, + { 0x03, 0x80, 0x0380, "small chest west wing north room 3F" }, + { 0x03, 0x40, 0x0340, "PoH big chest west wing north room 2F" }, + { 0x03, 0x20, 0x0320, "small key big chest west wing main room 1F" }, + { 0x03, 0x10, 0x0310, "compass big chest east wing first room B1" }, + { 0x03, 0x08, 0x0308, "south west underwater big chest outside shop" }, + { 0x03, 0x04, 0x0304, "map big chest east wing fourth room 1F" }, + { 0x03, 0x01, 0x0301, "double clawshot big chest east wing fifth room B3" }, + { 0x08, 0x80, 0x0880, "turn on wind in east wing second room 2F" }, + { 0x08, 0x40, 0x0840, "open gate in east wing second room 2F" }, + { 0x08, 0x20, 0x0820, "explored west wing main room 1F (unset if you enter main room)" }, + { 0x08, 0x10, 0x0810, "explored east wing first room 1F (unset if you enter main room)" }, + { 0x08, 0x04, 0x0804, "killed big baba west wing north room 1F" }, + { 0x08, 0x02, 0x0802, "double clawshot big chest east wing fifth room B3 (set after)" }, + { 0x08, 0x01, 0x0801, "west bridge broken" }, + { 0x09, 0x80, 0x0980, "east wing fifth room B3 intro cs" }, + { 0x09, 0x40, 0x0940, "open gate in east wing third room 2F" }, + { 0x09, 0x20, 0x0920, "spawn baba serpants under east bridge" }, + { 0x09, 0x08, 0x0908, "extended east bridge (spinner slot needs to be closed)" }, + { 0x09, 0x04, 0x0904, "extended west bridge (spinner slot needs to be closed)" }, + { 0x09, 0x02, 0x0902, "small key big chest west wing main room 1F (set after)" }, + { 0x0A, 0x80, 0x0A80, "explored main room 1F" }, + { 0x0A, 0x20, 0x0A20, "turn on wind in east wing third room 2F" }, + { 0x0A, 0x10, 0x0A10, "open door in east wing third room 1F" }, + { 0x0A, 0x04, 0x0A04, "fan on ceiling of main room active" }, + { 0x0A, 0x02, 0x0A02, "open gate in east wing fourth room 1F" }, + { 0x0B, 0x80, 0x0B80, "unlock boss door" }, + { 0x0B, 0x40, 0x0B40, "unlock east bridge door 1F" }, + { 0x0B, 0x08, 0x0B08, "east bridge extended (close east spinner slot)" }, + { 0x0B, 0x04, 0x0B04, "west bridge extended (close west spinner slot)" }, + { 0x0B, 0x02, 0x0B02, "open gate outside shop" }, + { 0x0C, 0x08, 0x0C08, "north wing main room intro cs" }, + { 0x0C, 0x04, 0x0C04, "east wing fourth room 2F intro cs" }, + { 0x0C, 0x02, 0x0C02, "went beyond first gate outside shop intro cs" }, + { 0x0C, 0x01, 0x0C01, "Intro CS" }, + { 0x0D, 0x80, 0x0D80, "killed left dynalfos in east wing third room 1F" }, + { 0x0D, 0x40, 0x0D40, "killed right dynalfos in east wing third room 1F" }, + { 0x0D, 0x20, 0x0D20, "?" }, + { 0x0D, 0x10, 0x0D10, "west bridge destroyed cs (triggered when you have a key)" }, + { 0x0D, 0x08, 0x0D08, "killed helmasaurus in main room 1F" }, + { 0x0D, 0x04, 0x0D04, "west bridge extented cs" }, + { 0x0D, 0x02, 0x0D02, "east bridge extented cs" }, + { 0x0E, 0x01, 0x0E01, "small key big chest west wing main room 1F (set after)" }, + { 0x0F, 0x80, 0x0F80, "exited dungeon with midna warp" }, + { 0x0F, 0x40, 0x0F40, "exited dungeon with midna warp" }, + { 0x0F, 0x20, 0x0F20, "save promt after boss" }, + { 0x0F, 0x10, 0x0F10, "open gate in west wing main room B2" }, + { 0x0F, 0x08, 0x0F08, "killed left aeralfos in north wing main room 1F" }, + { 0x0F, 0x04, 0x0F04, "killed right aeralfos in north wing main room 1F" }, + { 0x0F, 0x02, 0x0F02, "open gate in east wing fifth room B3" }, + { 0x0F, 0x01, 0x0F01, "stop fan in east wing fifth room B3" }, + { 0x10, 0x80, 0x1080, "killed third baba serpant under east bridge" }, + { 0x10, 0x10, 0x1010, "killed third tile worm in east wing second room 1F" }, + { 0x10, 0x08, 0x1008, "killed second tile worm in east wing second room 1F" }, + { 0x10, 0x04, 0x1004, "killed first tile worm in east wing second room 1F" }, + { 0x11, 0x20, 0x1120, "killed poe in main room 4F outside" }, + { 0x11, 0x10, 0x1110, "killed poe in west wing main room 2F" }, + { 0x12, 0x20, 0x1220, "small key big chest west wing main room 1F (set after)" }, + { 0x12, 0x02, 0x1202, "latched on to first pillar in east wing first room B2" }, + { 0x13, 0x40, 0x1340, "open door in east wing fifth room B3" }, + { 0x13, 0x10, 0x1310, "?" }, + { 0x15, 0x10, 0x1510, "activate north path fan " }, + { 0x17, 0x40, 0x1740, "killed east dynalfos in main room 3F outside" }, + { 0x17, 0x20, 0x1720, "killed north dynalfos in main room 3F outside" }, + { 0x17, 0x10, 0x1710, "killed dynalfos in west wing north room 3F" }, + { 0x17, 0x08, 0x1708, "killed first baba serpent in path to east spinner slot" }, + { 0x17, 0x04, 0x1704, "killed second baba serpent in path to east spinner slot" }, + { 0x17, 0x02, 0x1702, "killed first baba serpant under east bridge" }, + { 0x17, 0x01, 0x1701, "killed second baba serpant under east bridge" }, +}; + +inline EventAreaFlags eventAreaFlagsCoO[] = +{ + { 0x03, 0x01, 0x0301, "big chest Lanayru Ice Puzzle" }, + { 0x04, 0x80, 0x0480, "big chest right right right path Eldin Long Cave" }, + { 0x04, 0x40, 0x0440, "big chest right right left right path Eldin Long Cave" }, + { 0x04, 0x20, 0x0420, "small chest left right path Eldin Long Cave" }, + //{ 0x08, 0x80, 0x0880, "position of block 1 puzzle 2 Lanayru Ice Puzzle" }, + //{ 0x08, 0x40, 0x0840, "position of block 1 puzzle 2 Lanayru Ice Puzzle" }, + //{ 0x08, 0x20, 0x0820, "position of block 1 puzzle 2 Lanayru Ice Puzzle" }, + //{ 0x08, 0x10, 0x0810, "position of block 1 puzzle 2 Lanayru Ice Puzzle" }, + //{ 0x08, 0x08, 0x0808, "position of block 2 puzzle 2 Lanayru Ice Puzzle" }, + //{ 0x08, 0x04, 0x0804, "position of block 2 puzzle 2 Lanayru Ice Puzzle" }, + //{ 0x08, 0x02, 0x0802, "position of block 2 puzzle 2 Lanayru Ice Puzzle" }, + //{ 0x08, 0x01, 0x0801, "position of block 2 puzzle 2 Lanayru Ice Puzzle" }, + //{ 0x09, 0x80, 0x0980, "position of block 3 puzzle 2 Lanayru Ice Puzzle" }, + //{ 0x09, 0x40, 0x0940, "position of block 3 puzzle 2 Lanayru Ice Puzzle" }, + //{ 0x09, 0x20, 0x0920, "position of block 3 puzzle 2 Lanayru Ice Puzzle" }, + //{ 0x09, 0x10, 0x0910, "position of block 3 puzzle 2 Lanayru Ice Puzzle" }, + //{ 0x09, 0x04, 0x0904, "position of block 1 puzzle 1 Lanayru Ice Puzzle" }, + //{ 0x09, 0x02, 0x0902, "position of block 1 puzzle 1 Lanayru Ice Puzzle" }, + //{ 0x09, 0x01, 0x0901, "position of block 1 puzzle 1 Lanayru Ice Puzzle" }, + //{ 0x0A, 0x80, 0x0A80, "position of block 1 puzzle 1 Lanayru Ice Puzzle" }, + //{ 0x0A, 0x20, 0x0A20, "position of block 2 puzzle 1 Lanayru Ice Puzzle" }, + //{ 0x0A, 0x10, 0x0A10, "position of block 2 puzzle 1 Lanayru Ice Puzzle" }, + //{ 0x0A, 0x08, 0x0A08, "position of block 2 puzzle 1 Lanayru Ice Puzzle" }, + //{ 0x0A, 0x04, 0x0A04, "position of block 2 puzzle 1 Lanayru Ice Puzzle" }, + //{ 0x0B, 0x08, 0x0B08, "position of block 3 puzzle 1 Lanayru Ice Puzzle" }, + //{ 0x0B, 0x04, 0x0B04, "position of block 3 puzzle 1 Lanayru Ice Puzzle" }, + //{ 0x0B, 0x02, 0x0B02, "position of block 3 puzzle 1 Lanayru Ice Puzzle" }, + //{ 0x0B, 0x01, 0x0B01, "position of block 3 puzzle 1 Lanayru Ice Puzzle" }, + { 0x0D, 0x10, 0x0D10, "broke right ice blocking first doorway in Lanayru Ice Puzzle" }, + { 0x0D, 0x08, 0x0D08, "broke left ice blocking first doorway in Lanayru Ice Puzzle" }, + { 0x0D, 0x04, 0x0D04, "open fourth gate in Lanayru Ice Puzzle" }, + { 0x0D, 0x02, 0x0D02, "open third gate in Lanayru Ice Puzzle" }, + { 0x0D, 0x01, 0x0D01, "open second gate in Lanayru Ice Puzzle" }, + { 0x0E, 0x80, 0x0E80, "open first gate in Lanayru Ice Puzzle" }, + //{ 0x0E, 0x40, 0x0E40, "position of block 1 puzzle 3 Lanayru Ice Puzzle" }, + //{ 0x0E, 0x20, 0x0E20, "position of block 1 puzzle 3 Lanayru Ice Puzzle" }, + //{ 0x0E, 0x10, 0x0E10, "position of block 1 puzzle 3 Lanayru Ice Puzzle" }, + //{ 0x0E, 0x08, 0x0E08, "position of block 1 puzzle 3 Lanayru Ice Puzzle" }, + //{ 0x0E, 0x04, 0x0E04, "position of block 1 puzzle 3 Lanayru Ice Puzzle" }, + //{ 0x0E, 0x02, 0x0E02, "position of block 2 puzzle 3 Lanayru Ice Puzzle" }, + //{ 0x0E, 0x01, 0x0E01, "position of block 2 puzzle 3 Lanayru Ice Puzzle" }, + //{ 0x0F, 0x80, 0x0F80, "position of block 2 puzzle 3 Lanayru Ice Puzzle" }, + //{ 0x0F, 0x40, 0x0F40, "position of block 2 puzzle 3 Lanayru Ice Puzzle" }, + //{ 0x0F, 0x20, 0x0F20, "position of block 2 puzzle 3 Lanayru Ice Puzzle" }, + //{ 0x0F, 0x10, 0x0F10, "position of block 3 puzzle 3 Lanayru Ice Puzzle" }, + //{ 0x0F, 0x08, 0x0F08, "position of block 3 puzzle 3 Lanayru Ice Puzzle" }, + //{ 0x0F, 0x04, 0x0F04, "position of block 3 puzzle 3 Lanayru Ice Puzzle" }, + //{ 0x0F, 0x02, 0x0F02, "position of block 3 puzzle 3 Lanayru Ice Puzzle" }, + //{ 0x0F, 0x01, 0x0F01, "position of block 3 puzzle 3 Lanayru Ice Puzzle" }, + { 0x10, 0x80, 0x1080, "spawn big chest right right left right path Eldin Long Cave" }, + { 0x10, 0x40, 0x1040, "lit torch 3 (right right right path) Eldin Long Cave" }, + { 0x13, 0x80, 0x1380, "killed poe on floor 44 in Cave of Ordeals" }, + { 0x13, 0x40, 0x1340, "killed poe on floor 33 in Cave of Ordeals" }, + { 0x13, 0x20, 0x1320, "killed poe on floor 17 in Cave of Ordeals" }, + { 0x13, 0x08, 0x1308, "Cave of Ordeals intro cs" }, + { 0x13, 0x04, 0x1304, "obtained fairy's tears (if unset, you can get it even if you already have some) (also spawns that extra darknut on floor 49)" }, + { 0x13, 0x02, 0x1302, "open floor 1 door in Cave of Ordeals cs" }, + { 0x13, 0x01, 0x1301, "broke ice on floor 21 in Cave of Ordeals" }, + { 0x14, 0x40, 0x1440, "explored section 2 right right left right path Eldin Long Cave" }, + { 0x14, 0x20, 0x1420, "explored section 1 right right left right path Eldin Long Cave" }, + { 0x14, 0x10, 0x1410, "explored section 2 right right left left path Eldin Long Cave" }, + { 0x14, 0x08, 0x1408, "explored section 1 right right left left path Eldin Long Cave" }, + { 0x14, 0x04, 0x1404, "explored section 3 right right left path Eldin Long Cave" }, + { 0x14, 0x02, 0x1402, "explored section 2 right right left path Eldin Long Cave" }, + { 0x14, 0x01, 0x1401, "explored section 1 right right left path Eldin Long Cave" }, + { 0x15, 0x80, 0x1580, "explored section 2 right right right path Eldin Long Cave" }, + { 0x15, 0x40, 0x1540, "explored section 1 right right right path Eldin Long Cave" }, + { 0x15, 0x20, 0x1520, "explored section 3 right right path Eldin Long Cave" }, + { 0x15, 0x10, 0x1510, "explored section 2 right right path Eldin Long Cave" }, + { 0x15, 0x08, 0x1508, "explored section 1 right right path Eldin Long Cave" }, + { 0x15, 0x04, 0x1504, "explored section 1 right left path Eldin Long Cave" }, + { 0x15, 0x02, 0x1502, "explored section 6 right path Eldin Long Cave" }, + { 0x15, 0x01, 0x1501, "explored section 5 right path Eldin Long Cave" }, + { 0x16, 0x80, 0x1680, "explored section 4 right path Eldin Long Cave" }, + { 0x16, 0x40, 0x1640, "explored section 3 right path Eldin Long Cave" }, + { 0x16, 0x20, 0x1620, "explored section 2 right path Eldin Long Cave" }, + { 0x16, 0x10, 0x1610, "explored section 1 right path Eldin Long Cave" }, + { 0x16, 0x08, 0x1608, "explored section 2 left right path Eldin Long Cave" }, + { 0x16, 0x04, 0x1604, "explored section 1 right right path Eldin Long Cave" }, + { 0x16, 0x02, 0x1602, "explored section 2 left left path Eldin Long Cave" }, + { 0x16, 0x01, 0x1601, "explored section 1 right right path Eldin Long Cave" }, + { 0x17, 0x80, 0x1780, "explored section 2 left path Eldin Long Cave" }, + { 0x17, 0x40, 0x1740, "explored section 1 right path Eldin Long Cave" }, + { 0x17, 0x20, 0x1720, "explored section 2 Eldin Long Cave" }, + { 0x17, 0x10, 0x1710, "explored section 1 Eldin Long Cave" }, + { 0x17, 0x08, 0x1708, "lit torch 2 (right path) Eldin Long Cave" }, + { 0x17, 0x04, 0x1704, "lit left torch right right left right path Eldin Long Cave" }, + { 0x17, 0x02, 0x1702, "lit right torch right right left right path Eldin Long Cave" }, + { 0x17, 0x01, 0x1701, "killed poe right right left left path Eldin Long Cave" }, +}; + +inline EventAreaFlags eventAreaFlagsEldin[] = +{ + { 0x00, 0x01, 0x0001, "Big chest from torches graveyard" }, + { 0x01, 0x80, 0x0180, "Small chest in the inn" }, + { 0x01, 0x40, 0x0140, "PoH big chest death mountain archer alcove" }, + { 0x01, 0x20, 0x0120, "PoH big chest underwater behind spring" }, + { 0x01, 0x10, 0x0110, "Big chest next to watch tower" }, + { 0x01, 0x04, 0x0104, "?" }, + { 0x01, 0x02, 0x0102, "Big chest watch house" }, + { 0x01, 0x01, 0x0101, "tear of light death mountain hot spring water" }, + { 0x02, 0x80, 0x0280, "tear of light next to howling stone death mountain " }, + { 0x02, 0x40, 0x0240, "tear of light death mountain base" }, + { 0x02, 0x10, 0x0210, "tear of light sancuary basement" }, + { 0x02, 0x08, 0x0208, "tear of light Barnes storage house" }, + { 0x02, 0x04, 0x0204, "tear of light watch tower" }, + { 0x02, 0x02, 0x0202, "tear of light at Malo mart" }, + { 0x02, 0x01, 0x0201, "tear of light inn fire room" }, + { 0x03, 0x80, 0x0380, "tear of light Barnes shop" }, + { 0x03, 0x40, 0x0340, "tear of light graveyard" }, + { 0x03, 0x20, 0x0320, "tear of light Barnes storage house" }, + { 0x03, 0x10, 0x0310, "tear of light Barnes storage house" }, + { 0x03, 0x08, 0x0308, "tear of light sancuary basement" }, + { 0x03, 0x04, 0x0304, "tear of light sancuary basement" }, + { 0x03, 0x02, 0x0302, "tear of light ant house" }, + { 0x03, 0x01, 0x0301, "tear of light inn back room" }, + { 0x08, 0x80, 0x0880, "Kakariko Village Portal" }, + { 0x08, 0x40, 0x0840, "kakariko shadow beasts barrier appears (unset after fight)" }, + { 0x08, 0x20, 0x0820, "DM big rock fell" }, + { 0x08, 0x10, 0x0810, "done midna jumps 4 death mountain (hot spring water)" }, + { 0x08, 0x08, 0x0808, "done midna jumps 3 death mountain (1st floor)" }, + { 0x08, 0x04, 0x0804, "killed death mountain shadow beasts cs (unset later?)" }, + { 0x08, 0x01, 0x0801, "done midna jumps 1 death mountain (entrance)" }, + { 0x09, 0x80, 0x0980, "Malo mart has banners inside" }, + { 0x09, 0x40, 0x0940, "DM proper human intro CS (Map marker GM)" }, + { 0x09, 0x20, 0x0920, "Death Mountain Portal" }, + { 0x09, 0x10, 0x0910, "death mountain dark beasts barrier appears" }, + { 0x09, 0x08, 0x0908, "?" }, + { 0x09, 0x04, 0x0904, "?" }, + { 0x09, 0x02, 0x0902, "killed HV bublins (unset when cats spawn)" }, + { 0x09, 0x01, 0x0901, "killed light bug death mountain hot spring water" }, + { 0x0A, 0x80, 0x0A80, "killed light bug next to howling stone death mountain " }, + { 0x0A, 0x40, 0x0A40, "killed light bug death mountain base" }, + { 0x0A, 0x20, 0x0A20, "trigger twilight end cs (vessel of light filled) (Hot Spring Water Present on map)" }, + { 0x0A, 0x10, 0x0A10, "killed light bug sancuary basement" }, + { 0x0A, 0x04, 0x0A04, "killed light bug watch tower" }, + { 0x0A, 0x02, 0x0A02, "killed light bug malo mart" }, + { 0x0A, 0x01, 0x0A01, "killed light bug inn fire room" }, + { 0x0B, 0x80, 0x0B80, "killed light bug Barnes shop" }, + { 0x0B, 0x40, 0x0B40, "killed light bug graveyard" }, + { 0x0B, 0x08, 0x0B08, "killed light bug sancuary basement" }, + { 0x0B, 0x04, 0x0B04, "killed light bug sancuary basement" }, + { 0x0B, 0x02, 0x0B02, "killed light bug ant house" }, + { 0x0B, 0x01, 0x0B01, "killed light bug inn bedroom" }, + { 0x0C, 0x80, 0x0C80, "saw light bug enter Barnes storage house twilight cs" }, + { 0x0C, 0x40, 0x0C40, "malo mart sells hawkeye (moves potion to the right) (set when starting bow mini-game)" }, + { 0x0C, 0x20, 0x0C20, "malo mart sells arrows" }, + { 0x0C, 0x10, 0x0C10, "broke sanctuary roof patch during twilight (duplicate)" }, + { 0x0C, 0x08, 0x0C08, "box moved ant house (spawns light bug)" }, + { 0x0C, 0x04, 0x0C04, "Unknown crashes if rocks are pushed" }, + { 0x0C, 0x02, 0x0C02, "malo mart hylian shield bought" }, + { 0x0C, 0x01, 0x0C01, "ant house explored" }, + { 0x0D, 0x80, 0x0D80, "entered sanctuary from roof during twilight" }, + { 0x0D, 0x40, 0x0D40, "enter Barnes shop through the window in twilight cs" }, + { 0x0D, 0x20, 0x0D20, "light bug comes out of box in ant house cs" }, + { 0x0D, 0x10, 0x0D10, "spawn PoH cat mini game hidden village" }, + { 0x0D, 0x08, 0x0D08, "malo mart hawkeye sold out (needs to be set for arrows to show up)" }, + { 0x0D, 0x04, 0x0D04, "lit all torches in sanctuary twilight (opens basment)" }, + { 0x0D, 0x02, 0x0D02, "light bug in inn fireplace jumps out cs" }, + { 0x0D, 0x01, 0x0D01, "lit inn fireplace" }, + { 0x0E, 0x80, 0x0E80, "knocked down dresser in Barnes shop twilight cs" }, + { 0x0E, 0x40, 0x0E40, "?" }, + { 0x0E, 0x20, 0x0E20, "? (malo mart explored)" }, + { 0x0E, 0x10, 0x0E10, "lit west torch in sanctuary twilight" }, + { 0x0E, 0x08, 0x0E08, "lit north east torch in sanctuary twilight" }, + { 0x0E, 0x04, 0x0E04, "lit east torch in sanctuary twilight" }, + { 0x0E, 0x02, 0x0E02, "lit north west torch in sanctuary twilight" }, + { 0x0F, 0x80, 0x0F80, "broke ant house roof patch (duplicate)" }, + { 0x0F, 0x40, 0x0F40, "moved death mountain rock to exit" }, + { 0x0F, 0x20, 0x0F20, "Eldin spirit talks to Link after getting kakariko Portal cs" }, + { 0x0F, 0x10, 0x0F10, "broke ant house roof patch" }, + { 0x0F, 0x08, 0x0F08, "broke window of Barnes shop twilight" }, + { 0x0F, 0x04, 0x0F04, "broke sanctuary roof patch during twilight" }, + { 0x0F, 0x02, 0x0F02, "Renado talks to Link after trying to go up death mountain trail" }, + { 0x0F, 0x01, 0x0F01, "killed kakariko shadow beasts cs" }, + { 0x10, 0x80, 0x1080, "Killed poe watch tower" }, + { 0x10, 0x40, 0x1040, "Killed poe Barnes storage house" }, + { 0x10, 0x20, 0x1020, "blown up rock underwater to lake hylia from graveward" }, + { 0x10, 0x10, 0x1010, "Graveyard intro cs" }, + { 0x10, 0x08, 0x1008, "explored zora tombstone area" }, + { 0x10, 0x04, 0x1004, "broke floor patch in graveyard during twilight" }, + { 0x10, 0x02, 0x1002, "Killed poe death mountain" }, + { 0x10, 0x01, 0x1001, "Killed poe graveyard center" }, + { 0x11, 0x80, 0x1180, "Killed poe graveyard tombstone" }, + { 0x11, 0x40, 0x1140, "gorons in kakariko hot spring water gone" }, + { 0x11, 0x20, 0x1120, "Map Marker Sanctuary" }, + { 0x11, 0x08, 0x1108, "Midna text after DM big rock fell" }, + { 0x11, 0x04, 0x1104, "done midna jumps 2 death mountain (base floor)" }, + { 0x11, 0x02, 0x1102, "death mountain proper intro cs twilight" }, + { 0x11, 0x01, 0x1101, "moved death mountain rock to hot spring water" }, + { 0x12, 0x80, 0x1280, "sanctuary basement canon room explored" }, + { 0x12, 0x40, 0x1240, "done Midna jumps in sanctuary basement" }, + { 0x12, 0x20, 0x1220, "Midna text before Midna jumps in sanctuary basement" }, + { 0x12, 0x10, 0x1210, "sanctuary twilight cs" }, + { 0x12, 0x08, 0x1208, "killed right shadow bulblin inside inn twilight" }, + { 0x12, 0x04, 0x1204, "killed left shadow bulblin inside inn twilight" }, + { 0x12, 0x02, 0x1202, "killed top shadow bulblin inside inn twilight" }, + { 0x12, 0x01, 0x1201, "enter central room of inn during twilight cs" }, + { 0x13, 0x80, 0x1380, "sanctuary basement hallway to canon explored" }, + { 0x13, 0x40, 0x1340, "Malo mart shield on counter (requires reload)" }, + { 0x13, 0x20, 0x1320, "Kakariko intro cs" }, + { 0x13, 0x10, 0x1310, "blown up rocks on kakariko cliff PoH" }, + { 0x13, 0x08, 0x1308, "Blown up rock to secret passage to back of spring (updates map)" }, + { 0x13, 0x04, 0x1304, "Barnes storage house not blown up (unset once you enter) (twilight)" }, + { 0x13, 0x02, 0x1302, "Barnes storage house blew up cs (also changes map)" }, + { 0x13, 0x01, 0x1301, "Killed poe hidden village" }, + { 0x14, 0x80, 0x1480, "Midna text after sanctuary twilight cs" }, + { 0x14, 0x20, 0x1420, "light bug comes out of dresser in Barnes shop twilight" }, + { 0x14, 0x10, 0x1410, "GM save prompt" }, + { 0x14, 0x08, 0x1408, "Barnes sells Bombs" }, + { 0x14, 0x04, 0x1404, "midna text after shad leaves canon room" }, + { 0x14, 0x02, 0x1402, "Hero's shade map marker" }, + { 0x14, 0x01, 0x1401, "done midna jumps to top of sanctuary (also unlocks it)" }, + { 0x15, 0x80, 0x1580, "blown up rock underwater behind spring" }, + { 0x15, 0x40, 0x1540, "malo mart sells red potion on right slot" }, + { 0x15, 0x20, 0x1520, "beat bow mini-game" }, + { 0x15, 0x10, 0x1510, "malo mart sells red potion on left slot (default)" }, + { 0x15, 0x08, 0x1508, "explored bedroom in the inn" }, + { 0x15, 0x04, 0x1504, "explored central room in the inn" }, + { 0x15, 0x02, 0x1502, "blown up right rock underwater zora tombstone area" }, + { 0x15, 0x01, 0x1501, "midna text after charging dominion rod" }, + { 0x16, 0x80, 0x1680, "Goron lets you enter elevator in sumo hall" }, + { 0x16, 0x40, 0x1640, "Midna text after blowing up Barnes storage house" }, + { 0x16, 0x20, 0x1620, "hit third target in bow mini-game" }, + { 0x16, 0x10, 0x1610, "saved Colin cs (malo mart now open)" }, + { 0x16, 0x04, 0x1604, "Midna text after meeting the kids after twilight" }, + { 0x16, 0x02, 0x1602, "Started Rutela escort" }, + { 0x16, 0x01, 0x1601, "hit second target in bow mini-game" }, + { 0x17, 0x80, 0x1780, "hit first target in bow mini-game" }, + { 0x17, 0x40, 0x1740, "rock to zora tombstone gone + Barnes sells water bombs" }, + { 0x17, 0x20, 0x1720, "Followed Rutela to graveyard" }, + { 0x17, 0x10, 0x1710, "death mountain path intro cs twilight" }, + { 0x17, 0x08, 0x1708, "owl statue possessed cs (sanctuary basement)" }, + { 0x17, 0x04, 0x1704, "done midna jumps ant house (also unlocks it)" }, + { 0x17, 0x02, 0x1702, "Impaz in her house (hidden village)" }, + { 0x17, 0x01, 0x1701, "can't transform in hidden village (if bit 2 is set you can)" }, + { 0x1A, 0x40, 0x1A40, "picked up rupees from right rock underwater zora tombstone area" }, + { 0x1A, 0x20, 0x1A20, "picked up rupees from rock underwater behind spring" }, + { 0x1A, 0x10, 0x1A10, "Free standing PoH kakariko cliff" }, + { 0x1A, 0x08, 0x1A08, "Free standing PoH cat mini game hidden village" }, + { 0x1A, 0x04, 0x1A04, "picked up silver rupee from bell above sanctuary" }, + { 0x1A, 0x02, 0x1A02, "picked up yellow rupee in box secret passage to spring" }, + { 0x1A, 0x01, 0x1A01, "picked up blue rupee in box secret passage to spring" }, + { 0x1B, 0x80, 0x1B80, "picked up yellow rupee in box next to kakariko hot spring water" }, + { 0x1B, 0x40, 0x1B40, "picked up yellow rupee behind dresser inn bedroom" }, + { 0x1B, 0x20, 0x1B20, "picked up red rupee in box on platform above ant house" }, + { 0x1B, 0x10, 0x1B10, "picked up blue rupee behind dresser inn 2nd floor" }, + { 0x1B, 0x08, 0x1B08, "picked up yellow rupee 1 on leadge of top of death montain" }, + { 0x1B, 0x04, 0x1B04, "picked up yellow rupee 2 on leadge of top of death montain" }, + { 0x1B, 0x02, 0x1B02, "picked up yellow rupee 3 on leadge of top of death montain" }, + { 0x1B, 0x01, 0x1B01, "picked up rupee in death montain in rock below pipe (need BaC and rang)" }, +}; + +inline EventAreaFlags eventAreaFlagsFaron[] = +{ + { 0x00, 0x80, 0x0080, "small chest in lantern cave" }, + { 0x00, 0x40, 0x0040, "HP Chest Coro-Mist shortcut" }, + { 0x00, 0x20, 0x0020, "big chest mist area" }, + { 0x00, 0x10, 0x0010, "small chest mist area trunk" }, + { 0x00, 0x08, 0x0008, "small chest mist area next to key cave" }, + { 0x00, 0x04, 0x0004, "PoH chest key cave" }, + { 0x00, 0x01, 0x0001, "Small key cave key chest" }, + { 0x01, 0x80, 0x0180, "Dig Tear #1" }, + { 0x01, 0x20, 0x0120, "Final Tear #1" }, + { 0x01, 0x10, 0x0110, "Final Tear #2" }, + { 0x01, 0x04, 0x0104, "Wall Tear #1 (Mist Area)" }, + { 0x01, 0x02, 0x0102, "Wall Tear #2 (Mist Area)" }, + { 0x02, 0x40, 0x0240, "Tree Tear #1" }, + { 0x02, 0x20, 0x0220, "Tree Tear #2" }, + { 0x02, 0x10, 0x0210, "Tree Tear #3" }, + { 0x02, 0x08, 0x0208, "Gate Tear #1" }, + { 0x02, 0x02, 0x0202, "Coro Tear #1 (inside)" }, + { 0x02, 0x01, 0x0201, "Dig Tear #2" }, + { 0x03, 0x40, 0x0340, "Tear #2" }, + { 0x03, 0x20, 0x0320, "Gate Tear #2" }, + { 0x03, 0x10, 0x0310, "Coro Tear #2 (inside)" }, + { 0x03, 0x02, 0x0302, "Tear #1" }, + { 0x03, 0x01, 0x0301, "Coro Tear (outisde)" }, + { 0x04, 0x80, 0x0480, "Yellow Rupee Chest (N-Faron)" }, + { 0x08, 0x80, 0x0880, "explored east section of mist area after midna jump 1 twilight (gets unset)" }, + { 0x08, 0x40, 0x0840, "explored section with south entrance of mist area (gets unset)" }, + { 0x08, 0x10, 0x0810, "went up east section of mist area after midna jump 1 twilight" }, + { 0x08, 0x08, 0x0808, "S Faron warp twilight fences fall cs" }, + { 0x08, 0x04, 0x0804, "Sky character under owl statue" }, + { 0x08, 0x02, 0x0802, "midna jump 1 mist area (duplicate)" }, + { 0x08, 0x01, 0x0801, "unlock midna jump 1 mist area" }, + { 0x09, 0x80, 0x0980, "Coro spirits talk after killing light bugs in his house" }, + { 0x09, 0x40, 0x0940, "midna jump to Coro's house" }, + { 0x09, 0x20, 0x0920, "Map marker owl statue" }, + { 0x09, 0x10, 0x0910, "opened mist area gate to N faron" }, + { 0x09, 0x08, 0x0908, "lit torch 2 in lantern cave" }, + { 0x09, 0x04, 0x0904, "Talked to Midna next to the deku babas before Coro" }, + { 0x09, 0x02, 0x0902, "Rescued Monkey from Puppets" }, + { 0x09, 0x01, 0x0901, "dug behind Coro gate in twilight" }, + { 0x0A, 0x80, 0x0A80, "took Midna back s warp fight" }, + { 0x0A, 0x40, 0x0A40, "S warp shadow beast revive cs" }, + { 0x0A, 0x20, 0x0A20, "trigger twilight end cs (vessel of light filled)" }, + { 0x0A, 0x10, 0x0A10, "unlocked Coro gate" }, + { 0x0A, 0x08, 0x0A08, "Explored path to sacred grove" }, + { 0x0A, 0x04, 0x0A04, "burned cobweb in front of forest temple" }, + { 0x0A, 0x02, 0x0A02, "see spirit in front of FT twilight cs" }, + { 0x0A, 0x01, 0x0A01, "enter twilight cs" }, + { 0x0B, 0x40, 0x0B40, "talked to the light spirit in twilight" }, + { 0x0B, 0x20, 0x0B20, "saw light bugs dig underground mist area exit twilight" }, + { 0x0B, 0x10, 0x0B10, "Blown up rock next to Coro" }, + { 0x0B, 0x08, 0x0B08, "n warp fight fences appear cs" }, + { 0x0B, 0x04, 0x0B04, "North Faron Portal" }, + { 0x0B, 0x02, 0x0B02, "FT save prompt" }, + { 0x0C, 0x80, 0x0C80, "got lantern back after monkey follow" }, + { 0x0C, 0x40, 0x0C40, "saw light bugs move inside Coro's house cs" }, + { 0x0C, 0x20, 0x0C20, "in monkey follow (gets unset afterwards)" }, + { 0x0C, 0x10, 0x0C10, "Trill lets you shop" }, + { 0x0C, 0x04, 0x0C04, "killed left bokoblin before Trill after twilight" }, + { 0x0C, 0x02, 0x0C02, "killed right bokoblin before Trill after twilight" }, + { 0x0C, 0x01, 0x0C01, "explored section 6 in lantern cave" }, + { 0x0D, 0x80, 0x0D80, "explored section 5 in lantern cave" }, + { 0x0D, 0x40, 0x0D40, "explored section 4 in lantern cave" }, + { 0x0D, 0x20, 0x0D20, "explored section 3 in lantern cave" }, + { 0x0D, 0x10, 0x0D10, "explored section 2 in lantern cave" }, + { 0x0D, 0x08, 0x0D08, "explored section 1 in lantern cave" }, + { 0x0D, 0x04, 0x0D04, "got Coro key from Coro" }, + { 0x0D, 0x02, 0x0D02, "?" }, + { 0x0D, 0x01, 0x0D01, "killed right bokoblin next to Talo's cage" }, + { 0x0E, 0x80, 0x0E80, "killed left bokoblin next to Talo's cage" }, + { 0x0E, 0x40, 0x0E40, "broke Talo's cage" }, + { 0x0E, 0x20, 0x0E20, "killed both bokoblins next to Talo's cage" }, + { 0x0E, 0x08, 0x0E08, "enter Faron intro cs" }, + { 0x0E, 0x04, 0x0E04, "lit Coro's soup" }, + { 0x0E, 0x02, 0x0E02, "saved Talo cs" }, + { 0x0E, 0x01, 0x0E01, "see light spirit from far away in twilight cs" }, + { 0x0F, 0x80, 0x0F80, "enter mist area twilight cs" }, + { 0x0F, 0x40, 0x0F40, "found Talo's stick (child chase)" }, + { 0x0F, 0x20, 0x0F20, "explored top of east slope mist area twilight" }, + { 0x0F, 0x10, 0x0F10, "talked to Coro spirit before killing bugs" }, + { 0x0F, 0x08, 0x0F08, "entered mist area as human" }, + { 0x0F, 0x04, 0x0F04, "Talked to midna before talking to Coro spirit" }, + { 0x0F, 0x02, 0x0F02, "explored section with north exit of mist area (gets unset)" }, + { 0x0F, 0x01, 0x0F01, "saw light bugs on trunk mist area (gets unset)" }, + { 0x10, 0x80, 0x1080, "Map marker Rusl" }, + { 0x10, 0x40, 0x1040, "lit torch 1 in lantern cave" }, + { 0x10, 0x20, 0x1020, "Killed poe mist area" }, + { 0x10, 0x10, 0x1010, "spawn PoH chest key cave" }, + { 0x10, 0x08, 0x1008, "lit right torch in key cave" }, + { 0x10, 0x04, 0x1004, "lit left torch in key cave" }, + { 0x10, 0x02, 0x1002, "explored section 15 in lantern cave" }, + { 0x10, 0x01, 0x1001, "add mist area mist to mini-map" }, + { 0x11, 0x80, 0x1180, "explored section 14 in lantern cave" }, + { 0x11, 0x40, 0x1140, "explored section 13 in lantern cave" }, + { 0x11, 0x20, 0x1120, "explored section 12 in lantern cave" }, + { 0x11, 0x10, 0x1110, "explored section 11 in lantern cave" }, + { 0x11, 0x08, 0x1108, "explored section 10 in lantern cave" }, + { 0x11, 0x04, 0x1104, "explored section 9 in lantern cave" }, + { 0x11, 0x02, 0x1102, "explored section 3 of branching path in lantern cave" }, + { 0x11, 0x01, 0x1101, "explored section 8 in lantern cave" }, + { 0x12, 0x80, 0x1280, "explored section 7 in lantern cave" }, + { 0x12, 0x20, 0x1220, "Midna text before jumping to Lost Woods" }, + { 0x12, 0x10, 0x1210, "killed light bug outside Coro's house (duplicate)" }, + { 0x12, 0x08, 0x1208, "saw light bug run behind Coro gate" }, + { 0x12, 0x04, 0x1204, "Midna text warp to N faron for bridge" }, + { 0x12, 0x02, 0x1202, "saw first 2 light bugs run away from you" }, + { 0x12, 0x01, 0x1201, "S warp shadow beasts are spawned" }, + { 0x13, 0x80, 0x1380, "South Faron Portal" }, + { 0x13, 0x40, 0x1340, "explored section 2 of branching path in lantern cave" }, + { 0x13, 0x20, 0x1320, "killed right bokoblin in front of FT after twilight" }, + { 0x13, 0x10, 0x1310, "killed left bokoblin in front of FT after twilight" }, + { 0x13, 0x08, 0x1308, "explored section 1 of branching path in lantern cave" }, + { 0x13, 0x01, 0x1301, "S warp shadow beasts killed" }, + { 0x14, 0x80, 0x1480, "lit torch 4 in lantern cave" }, + { 0x14, 0x40, 0x1440, "killed light bug mist area north exit" }, + { 0x14, 0x20, 0x1420, "did midna jump 2 mist area" }, + { 0x14, 0x10, 0x1410, "killed light bug mist area north exit" }, + { 0x14, 0x08, 0x1408, "explored section 4 of branching path in lantern cave" }, + { 0x14, 0x04, 0x1404, "killed light bug in front of Forest Temple" }, + { 0x14, 0x02, 0x1402, "killed light bug in front of Forest Temple" }, + { 0x14, 0x01, 0x1401, "killed both light bugs in front of FT cs (map marker FT)" }, + { 0x15, 0x80, 0x1580, "killed light bug mist area south entrance" }, + { 0x15, 0x40, 0x1540, "killed light bug mist area south entrance" }, + { 0x15, 0x20, 0x1520, "did midna jump 5 mist area" }, + { 0x15, 0x10, 0x1510, "did midna jump 3 mist area" }, + { 0x15, 0x08, 0x1508, "killed light bug mist area trunk" }, + { 0x15, 0x04, 0x1504, "killed light bug mist area trunk" }, + { 0x15, 0x02, 0x1502, "killed light bug mist area trunk" }, + { 0x15, 0x01, 0x1501, "killed light bug between latern cave and gate" }, + { 0x16, 0x80, 0x1680, "map marker Talo (only during child save)" }, + { 0x16, 0x40, 0x1640, "killed light bug outside Coro's house" }, + { 0x16, 0x20, 0x1620, "Map marker key cave (only during child save)" }, + { 0x16, 0x10, 0x1610, "remove map marker key cave" }, + { 0x16, 0x08, 0x1608, "did midna jump 4 mist area" }, + { 0x16, 0x04, 0x1604, "killed light bug hallway to Coro (closer to spring)" }, + { 0x16, 0x02, 0x1602, "killed light bug between latern cave and gate" }, + { 0x16, 0x01, 0x1601, "killed both light bugs in Coro's house cs" }, + { 0x17, 0x80, 0x1780, "killed light bug inside Coro's house" }, + { 0x17, 0x40, 0x1740, "killed light bug inside Coro's house" }, + { 0x17, 0x20, 0x1720, "killed light bug hallway to Coro (closer to Coro)" }, + { 0x17, 0x10, 0x1710, "did midna jump 6 mist area" }, + { 0x17, 0x08, 0x1708, "explored east section of mist area after midna jump 1 twilight (gets unset)" }, + { 0x17, 0x04, 0x1704, "lit torch 3 in lantern cave" }, + { 0x17, 0x02, 0x1702, "burned cobweb 2 in lantern cave" }, + { 0x17, 0x01, 0x1701, "burned cobweb 1 in lantern cave" }, + { 0x1B, 0x01, 0x1B01, "picked up rupees from rock next to Coro" }, +}; + +inline EventAreaFlags eventAreaFlagsFishingPond[] = +{ + { 0x1B, 0x01, 0x1B01, "free standing PoH" }, +}; + +inline EventAreaFlags eventAreaFlagsFT[] = +{ + { 0x00, 0x80, 0x0080, "PoH big chest behind Deku Like" }, + { 0x00, 0x04, 0x0004, "big chest underwater Tiny Cave" }, + { 0x00, 0x02, 0x0002, "small key big chest on pillar tile worm room" }, + { 0x00, 0x01, 0x0001, "Small Chest tile worm room" }, + { 0x01, 0x10, 0x0110, "big chest compass main room" }, + { 0x01, 0x08, 0x0108, "PoH big chest behind stairs tile worm room" }, + { 0x01, 0x02, 0x0102, "saved monkey in front of big pit" }, + { 0x02, 0x80, 0x0280, "saved monkey in boomerang bombling room" }, + { 0x02, 0x20, 0x0220, "saved monkey in tile worm room" }, + { 0x02, 0x10, 0x0210, "saved monkey in big baba room" }, + { 0x02, 0x08, 0x0208, "saved 2nd monkey" }, + { 0x02, 0x04, 0x0204, "first Monkey saved" }, + { 0x02, 0x02, 0x0202, "Small Chest 2nd Monkey room" }, + { 0x03, 0x80, 0x0380, "small chest first room" }, + { 0x03, 0x40, 0x0340, "Big Baba key acquired" }, + { 0x03, 0x10, 0x0310, "small key big chest in single wind bridge room" }, + { 0x03, 0x04, 0x0304, "small key big chest in boomerang bombling room" }, + { 0x03, 0x02, 0x0302, "Big Chest in broken stairs room" }, + { 0x06, 0x01, 0x0601, "Ooccoo map marker" }, + { 0x07, 0x80, 0x0780, "big chest with map main room" }, + { 0x07, 0x40, 0x0740, "Big Key Chest" }, + { 0x07, 0x20, 0x0720, "small chest behind bombable wall main room" }, + { 0x07, 0x04, 0x0704, "Outside Monkey saved" }, + { 0x07, 0x02, 0x0702, "saved monkey in spider cave room" }, + { 0x08, 0x40, 0x0840, "Midna Boomerang text seen" }, + { 0x08, 0x20, 0x0820, "midna text after bridge before Ook broken" }, + { 0x08, 0x08, 0x0808, "Big Baba killed cutscene (still spawned)" }, + { 0x08, 0x02, 0x0802, "hit totem of 2nd monkey once cs" }, + { 0x08, 0x01, 0x0801, "Midna first monkey text end" }, + { 0x09, 0x80, 0x0980, "Boss Door opened" }, + { 0x09, 0x40, 0x0940, "bridge before Ook broken" }, + { 0x09, 0x20, 0x0920, "burned cob web big key room" }, + { 0x09, 0x10, 0x0910, "bridge 2nd monkey room broken" }, + { 0x09, 0x02, 0x0902, "Compass Chest knocked down" }, + { 0x0A, 0x80, 0x0A80, "Monkey freed in spider room" }, + { 0x0A, 0x08, 0x0A08, "unlocked door to 2nd monkey room" }, + { 0x0A, 0x04, 0x0A04, "broke cage of 2nd monkey cs" }, + { 0x0A, 0x02, 0x0A02, "bokoblins see you in single wind bridge room cs" }, + { 0x0A, 0x01, 0x0A01, "turned wind bridge in single wind bridge room cs" }, + { 0x0B, 0x80, 0x0B80, "Unlock Windbridge East Door" }, + { 0x0B, 0x10, 0x0B10, "Girl Monkey helps Link" }, + { 0x0C, 0x40, 0x0C40, "opened cage of monkey in big baba room" }, + { 0x0C, 0x20, 0x0C20, "killed higher bokoblin in room before boss" }, + { 0x0C, 0x10, 0x0C10, "killed lower bokoblin in room before boss" }, + { 0x0C, 0x02, 0x0C02, "blown up rock to Ooccoo" }, + { 0x0D, 0x80, 0x0D80, "blown up rock blocking tile worm room" }, + { 0x0D, 0x40, 0x0D40, "blown up main room bombable wall" }, + //{ 0x0D, 0x20, 0x0D20, "small key big chest tile worm room position" }, + //{ 0x0D, 0x10, 0x0D10, "small key big chest tile worm room position" }, + //{ 0x0D, 0x08, 0x0D08, "small key big chest tile worm room position" }, + //{ 0x0D, 0x04, 0x0D04, "small key big chest tile worm room position" }, + { 0x0D, 0x02, 0x0D02, "Staircase rises main room" }, + { 0x0E, 0x20, 0x0E20, "tile worm room intro cs" }, + { 0x0E, 0x08, 0x0E08, "opened cage of monkey in tile worm room" }, + { 0x0E, 0x04, 0x0E04, "gate to big key opened" }, + { 0x0E, 0x02, 0x0E02, "2nd Monkey room intro cs" }, + { 0x0F, 0x80, 0x0F80, "lit bottom right torch main room" }, + { 0x0F, 0x40, 0x0F40, "lit bottom left torch main room" }, + { 0x0F, 0x20, 0x0F20, "lit upper right torch main room" }, + { 0x0F, 0x10, 0x0F10, "lit upper left torch main room" }, + { 0x0F, 0x08, 0x0F08, "big baba room intro cs" }, + { 0x0F, 0x04, 0x0F04, "enter room before boss Midna text" }, + { 0x0F, 0x02, 0x0F02, "Midna text after saveing a monkey after Ook" }, + { 0x0F, 0x01, 0x0F01, "Small Bridge breaks scene seen" }, + { 0x10, 0x10, 0x1010, "enter southwest door outside intro cs" }, + { 0x10, 0x04, 0x1004, "Midna text after compass" }, + { 0x10, 0x02, 0x1002, "boomerang obtained" }, + { 0x10, 0x01, 0x1001, "burned west cob web main room" }, + { 0x11, 0x08, 0x1108, "5th monkey added to room before boss" }, + { 0x11, 0x04, 0x1104, "4 Monkeys in main room cutscene" }, + { 0x11, 0x02, 0x1102, "turned wind bridge in single wind bridge room" }, + { 0x11, 0x01, 0x1101, "Monkeys regroup in Main Room" }, + { 0x12, 0x80, 0x1280, "4 Monkeys gather in Main Room" }, + { 0x12, 0x40, 0x1240, "blown up 1st rock in boomeang bombling room" }, + { 0x12, 0x10, 0x1210, "Ooccoo Freed" }, + { 0x12, 0x01, 0x1201, "2nd Monkey Bokoblins Killed" }, + { 0x13, 0x80, 0x1380, "Midna first Monkey text prompt (makes vines climbable)" }, + { 0x13, 0x40, 0x1340, "killed big baba cs" }, + { 0x13, 0x08, 0x1308, "?" }, + { 0x13, 0x04, 0x1304, "?" }, + { 0x13, 0x02, 0x1302, "Diababa killed" }, + { 0x13, 0x01, 0x1301, "Diababa Phase 2 (unset post kill)" }, + { 0x14, 0x20, 0x1420, "broke bridge over water that leads to big key" }, + { 0x14, 0x04, 0x1404, "monkeys form a rope in room before boss cs" }, + { 0x14, 0x02, 0x1402, "monkeys start to form a rope in room before boss" }, + { 0x15, 0x80, 0x1580, "All Monkeys form rope" }, + { 0x15, 0x40, 0x1540, "Ook exit door opened" }, + { 0x15, 0x20, 0x1520, "opened gate to monkey in broken stairs room" }, + { 0x15, 0x08, 0x1508, "blown up 2nd rock in boomerang bombling room" }, + { 0x15, 0x02, 0x1502, "saved 5th monkey cs" }, + { 0x15, 0x01, 0x1501, "killed bokoblin next to first monkey" }, + { 0x16, 0x20, 0x1620, "see locked monkey post Ook" }, + { 0x16, 0x10, 0x1610, "Ook defeated" }, + { 0x16, 0x08, 0x1608, "monkeys form a rope in room before boss cs" }, + { 0x16, 0x04, 0x1604, "Staircase rising cutscene for 4th Monkey" }, + { 0x16, 0x02, 0x1602, "Intro Cutscene" }, + { 0x16, 0x01, 0x1601, "2nd Monkey Pillar scene" }, + { 0x17, 0x80, 0x1780, "enter room before boss intro cs" }, + { 0x17, 0x40, 0x1740, "turned mill for the first time in Ook room cs" }, + { 0x17, 0x20, 0x1720, "big chest compass main room (set after)" }, + { 0x17, 0x01, 0x1701, "hit totem of 2nd monkey once" }, + { 0x1B, 0x10, 0x1B10, "picked up red rupee from deku like in spider room" }, +}; + +inline EventAreaFlags eventAreaFlagsGerudoDesert[] = +{ + { 0x02, 0x80, 0x0280, "big chest next to Arbiter's Grounds" }, + { 0x02, 0x20, 0x0220, "small chest next to camp entrance" }, + { 0x02, 0x08, 0x0208, "small chest on pillar weat of entrance to desert" }, + { 0x02, 0x04, 0x0204, "small chest under tower of left bulblin outside camp" }, + { 0x02, 0x02, 0x0202, "small chest under tower of right bulblin outside camp" }, + { 0x02, 0x01, 0x0201, "small chest next to fire outside camp" }, + { 0x03, 0x80, 0x0380, "small chest island north of cave of ordeals" }, + { 0x03, 0x40, 0x0340, "small chest east canyon" }, + { 0x03, 0x20, 0x0320, "small chest next to pillar in the middle of the messa" }, + { 0x03, 0x08, 0x0308, "small chest behind 2 breakable walls (the west one)" }, + { 0x03, 0x04, 0x0304, "small chest behind 2 breakable walls (the east one)" }, + { 0x03, 0x02, 0x0302, "big chest owl statue" }, + { 0x03, 0x01, 0x0301, "big chest in south secret path" }, + { 0x04, 0x80, 0x0480, "both small chests and key in camp (each one sets it)" }, + { 0x08, 0x80, 0x0880, "?" }, + { 0x08, 0x40, 0x0840, "?" }, + { 0x08, 0x20, 0x0820, "explored island north of cave of ordeals" }, + { 0x08, 0x10, 0x0810, "explored part 9 of bulblin camp (KB battle area)" }, + { 0x08, 0x08, 0x0808, "explored part 8 of bulblin camp" }, + { 0x08, 0x04, 0x0804, "explored part 7 of bulblin camp" }, + { 0x08, 0x02, 0x0802, "explored part 6 of bulblin camp" }, + { 0x08, 0x01, 0x0801, "explored part 5 of bulblin camp" }, + { 0x09, 0x80, 0x0980, "Desert Intro CS (PoT)" }, + { 0x09, 0x20, 0x0920, "Gerudo Messa Portal" }, + { 0x09, 0x08, 0x0908, "explored part 2 of bulblin camp" }, + { 0x09, 0x04, 0x0904, "explored part 4 of bulblin camp" }, + { 0x09, 0x02, 0x0902, "explored part 3 of bulblin camp" }, + { 0x09, 0x01, 0x0901, "?" }, + { 0x0A, 0x40, 0x0A40, "explored south secret path to big chest" }, + { 0x0A, 0x10, 0x0A10, "Mirror chamber intro cs" }, + { 0x0A, 0x04, 0x0A04, "save prompt after beating Arbiter's Grounds" }, + { 0x0A, 0x02, 0x0A02, "killed archer bulblin on bore outside camp" }, + { 0x0A, 0x01, 0x0A01, "killed rider bulblin on bore outside camp" }, + { 0x0B, 0x80, 0x0B80, "killed lone bulblin on bore outside camp" }, + { 0x0B, 0x40, 0x0B40, "killed bulblin on left tower outside camp" }, + { 0x0B, 0x20, 0x0B20, "killed bulblin on right tower outside camp" }, + { 0x0B, 0x10, 0x0B10, "watched outside AG cutscene after bublin camp" }, + { 0x0B, 0x04, 0x0B04, "destroyed fire outside camp" }, + { 0x0B, 0x02, 0x0B02, "destroyed bore meat in camp" }, + { 0x0D, 0x08, 0x0D08, "killed poe next to entrance to camp" }, + { 0x0D, 0x04, 0x0D04, "Hero's Shade map marker" }, + { 0x0D, 0x02, 0x0D02, "spawn big chest next to Arbiter's Grounds" }, + { 0x0D, 0x01, 0x0D01, "lit right torch for big chest next to Arbiter's Grounds entrance" }, + { 0x0E, 0x80, 0x0E80, "lit left torch for big chest next to Arbiter's Grounds entrance" }, + { 0x0E, 0x20, 0x0E20, "explored area with Arbiter's Gounds entrance" }, + { 0x0E, 0x02, 0x0E02, "mirror light stairs appear" }, + { 0x0E, 0x01, 0x0E01, "Mirror Chamber Portal" }, + { 0x0F, 0x04, 0x0F04, "sky character under owl statue" }, + { 0x0F, 0x02, 0x0F02, "map marker owl statue" }, + { 0x0F, 0x01, 0x0F01, "Mirror Raised Cutscene Flag (Places Boar at desert entrance)" }, + { 0x10, 0x40, 0x1040, "broke left wall that prevents access to east small chest (set once pieces despawn)" }, + { 0x10, 0x20, 0x1020, "killed poe next to cave of ordeals" }, + { 0x10, 0x10, 0x1010, "killed poe south of desert entrance" }, + { 0x10, 0x08, 0x1008, "killed poe on elevated platform with grotto (messa)" }, + { 0x10, 0x04, 0x1004, "killed poe next to Arbiter's Grounds entrance" }, + { 0x10, 0x02, 0x1002, "destroyed tower of right bulbin outside camp" }, + { 0x10, 0x01, 0x1001, "destroyed tower of left bulbin outside camp" }, + { 0x11, 0x20, 0x1120, "broke first right wall to camp (set once pieces despawn)" }, + { 0x11, 0x10, 0x1110, "broke first middle wall to camp (set once pieces despawn)" }, + { 0x11, 0x08, 0x1108, "broke first left wall to camp (set once pieces despawn)" }, + { 0x11, 0x04, 0x1104, "broke second right wall to camp (set once pieces despawn)" }, + { 0x11, 0x02, 0x1102, "broke second left wall to camp (set once pieces despawn)" }, + { 0x12, 0x10, 0x1210, "explored elavated section with poe over grotto" }, + { 0x13, 0x40, 0x1340, "Desert Intro CS" }, + { 0x14, 0x80, 0x1480, "started climbing stairs to mirror chamber" }, + { 0x14, 0x40, 0x1440, "exit Arbiters Grounds to go to mirror chamber" }, + { 0x14, 0x02, 0x1402, "map marker palace of twilight (explored mirror chamber)" }, + { 0x14, 0x01, 0x1401, "killed poe in bulblin camp" }, + { 0x17, 0x08, 0x1708, "broke right wall that prevents access to east small chest (set once pieces despawn)" }, + { 0x17, 0x04, 0x1704, "broke left wall that prevents access to west small chest (set once pieces despawn)" }, + { 0x17, 0x02, 0x1702, "broke right wall that prevents access to west small chest (set once pieces despawn)" }, + { 0x18, 0x80, 0x1880, "free standing PoH bore meat bulblin camp" }, +}; + +inline EventAreaFlags eventAreaFlagsGM[] = +{ + { 0x00, 0x40, 0x0040, "big chest main room top floor" }, + { 0x00, 0x10, 0x0010, "small chest next to switch in toadpoli room" }, + { 0x00, 0x08, 0x0008, "small chest first room" }, + { 0x00, 0x04, 0x0004, "big chest elder 3 room" }, + { 0x00, 0x02, 0x0002, "small chest elder 2 room" }, + { 0x00, 0x01, 0x0001, "small chest elder 1 room" }, + { 0x01, 0x40, 0x0140, "Ooccoo Map Flag" }, + { 0x01, 0x20, 0x0120, "big chest underwater outside room" }, + { 0x01, 0x10, 0x0110, "PoH big chest room 3" }, + { 0x01, 0x02, 0x0102, "map big chest elder 1 room" }, + { 0x01, 0x01, 0x0101, "small key underwater big chest toadpoli room" }, + { 0x02, 0x80, 0x0280, "small key small chest outside room" }, + { 0x02, 0x40, 0x0240, "big chest outside room clawshot" }, + { 0x02, 0x20, 0x0220, "small chest room leading to elder 2" }, + { 0x02, 0x10, 0x0210, "compass big chest" }, + { 0x02, 0x08, 0x0208, "small key big chest main room bottom floor" }, + { 0x02, 0x02, 0x0202, "PoH big chest toadpoli room (the one after the gate)" }, + { 0x03, 0x40, 0x0340, "big chest bow" }, + { 0x08, 0x10, 0x0810, "cut rope of door outside room cs" }, + { 0x08, 0x08, 0x0808, "pressed second button main room floor 2 cs" }, + { 0x08, 0x04, 0x0804, "pressed third button in first room cs" }, + { 0x08, 0x02, 0x0802, "pressed second button in first room cs" }, + { 0x08, 0x01, 0x0801, "cut rope of door in toadpoli room cs" }, + { 0x09, 0x80, 0x0980, "unlocked boss door" }, + { 0x09, 0x20, 0x0920, "pressed first button main room floor 2 cs" }, + { 0x09, 0x10, 0x0910, "killed beamos outside room" }, + { 0x0A, 0x40, 0x0A40, "unlock mini-boss doors" }, + { 0x0A, 0x08, 0x0A08, "pressed button outside room" }, + { 0x0A, 0x04, 0x0A04, "cut rope of door in room before boss" }, + { 0x0A, 0x02, 0x0A02, "cut rope of door in toadpoli room" }, + { 0x0A, 0x01, 0x0A01, "cut rope of door in bow room" }, + { 0x0B, 0x20, 0x0B20, "cut rope of door at top floor of main room" }, + { 0x0B, 0x10, 0x0B10, "pressed first button main room floor 2" }, + { 0x0B, 0x08, 0x0B08, "reach west locked door in main room bottom floor" }, + { 0x0B, 0x04, 0x0B04, "lowered platform to open gate in first room (read only)" }, + { 0x0C, 0x80, 0x0C80, "unlocked north door in toadpoli room" }, + { 0x0C, 0x40, 0x0C40, "pressed second button main room floor 2" }, + { 0x0C, 0x20, 0x0C20, "unlock west locked door in main room bottom floor" }, + { 0x0C, 0x08, 0x0C08, "killed right beamos in toadpoli room" }, + { 0x0C, 0x04, 0x0C04, "killed left beamos in toadpoli room" }, + { 0x0D, 0x80, 0x0D80, "pressed button outside room cs" }, + { 0x0D, 0x40, 0x0D40, "pressed button at top floor of main room" }, + { 0x0D, 0x08, 0x0D08, "unlocked east door outside room" }, + { 0x0D, 0x01, 0x0D01, "broke underwater wood barrier outside room" }, + { 0x0E, 0x80, 0x0E80, "replace tektites with toadpolis in toadpoli room (set after obtaining bow)" }, + { 0x0E, 0x20, 0x0E20, "main room intro cs" }, + { 0x0E, 0x10, 0x0E10, "main room intro cs" }, + { 0x0E, 0x08, 0x0E08, "broke second wood barrier in outside room" }, + { 0x0E, 0x04, 0x0E04, "broke first wood barrier in outside room" }, + { 0x0E, 0x02, 0x0E02, "Oocco Freed" }, + { 0x0E, 0x01, 0x0E01, "elder 2 lets you climb ladder in his room" }, + { 0x0F, 0x80, 0x0F80, "elder 1 lets you climb ladder in his room" }, + { 0x0F, 0x40, 0x0F40, "pulled beamos outside room" }, + { 0x0F, 0x20, 0x0F20, "outside room intro cs" }, + { 0x0F, 0x10, 0x0F10, "outside room getting shot at after mini-boss cs" }, + { 0x0F, 0x08, 0x0F08, "outside room getting shot at after mini-boss cs" }, + { 0x0F, 0x04, 0x0F04, "outside room intro cs" }, + { 0x10, 0x80, 0x1080, "room after bow intro cs" }, + { 0x10, 0x40, 0x1040, "pulled beamos outside room cs" }, + { 0x10, 0x20, 0x1020, "activate first force field in toadpoli room" }, + { 0x10, 0x10, 0x1010, "pressed first button in toadpoli room cs" }, + { 0x10, 0x08, 0x1008, "open gate in toadpoli room cs" }, + { 0x10, 0x04, 0x1004, "pressed second button in toadpoli room cs" }, + { 0x10, 0x02, 0x1002, "activate second force field in toadpoli room" }, + { 0x10, 0x01, 0x1001, "room before elder 1 intro cs" }, + { 0x11, 0x80, 0x1180, "room before elder 1 intro cs" }, + { 0x11, 0x20, 0x1120, "intro cs" }, + { 0x11, 0x10, 0x1110, "pressed first button in first room cs" }, + { 0x11, 0x08, 0x1108, "open gate in first room cs" }, + { 0x11, 0x04, 0x1104, "pressed button in room after bow" }, + { 0x11, 0x02, 0x1102, "hit switch in room after bow" }, + { 0x11, 0x01, 0x1101, "press button room 3" }, + { 0x12, 0x80, 0x1280, "killed south-east beamos bow room" }, + { 0x12, 0x40, 0x1240, "killed south-west beamos bow room" }, + { 0x12, 0x20, 0x1220, "killed west beamos bow room" }, + { 0x12, 0x10, 0x1210, "killed north-east beamos bow room" }, + { 0x12, 0x08, 0x1208, "killed north-west beamos bow room" }, + { 0x12, 0x04, 0x1204, "killed east beamos bow room" }, + { 0x12, 0x02, 0x1202, "killed south beamos bow room" }, + { 0x12, 0x01, 0x1201, "pulled south-east beamos bow room" }, + { 0x13, 0x80, 0x1380, "pulled south-west beamos bow room" }, + { 0x13, 0x40, 0x1340, "pulled west beamos bow room" }, + { 0x13, 0x08, 0x1308, "pulled east beamos bow room" }, + { 0x13, 0x04, 0x1304, "pulled south beamos bow room" }, + { 0x13, 0x02, 0x1302, "pressed first button in toadpoli room" }, + { 0x13, 0x01, 0x1301, "pressed second button in toadpoli room" }, + { 0x15, 0x01, 0x1501, "reached area past pullable wall in room 3 (first in path to elder 1)" }, + { 0x16, 0x10, 0x1610, "reached bottom of water in room before elder 1" }, + { 0x16, 0x08, 0x1608, "reached area past pullable wall in room 3 (first in path to elder 1)" }, + { 0x16, 0x04, 0x1604, "knocked down fence in room after bow" }, + { 0x16, 0x02, 0x1602, "pullable wall in room 3 closed itself" }, + { 0x17, 0x80, 0x1780, "outside room killed leader bulblin archer" }, + { 0x17, 0x20, 0x1720, "cut rope of door outside room" }, + { 0x17, 0x10, 0x1710, "pressed unerwater button in room before elder" }, + { 0x17, 0x08, 0x1708, "main room floor 2 intro cs" }, + { 0x17, 0x04, 0x1704, "main room floor 2 intro cs" }, + { 0x17, 0x02, 0x1702, "hit switch in room after bow cs" }, + { 0x17, 0x01, 0x1701, "room after bow intro cs" }, +}; + +inline EventAreaFlags eventAreaFlagsGrotto[] = +{ + { 0x01, 0x20, 0x0120, "big chest grotto 5-4" }, + { 0x01, 0x08, 0x0108, "big chest grotto 4-3" }, + { 0x01, 0x04, 0x0104, "left small chest grotto 2-0" }, + { 0x01, 0x02, 0x0102, "right small chest grotto 2-0" }, + { 0x01, 0x01, 0x0101, "small chest grotto 5-3" }, + { 0x02, 0x80, 0x0280, "big chest grotto 4-2" }, + { 0x02, 0x40, 0x0240, "big chest grotto 3-0" }, + { 0x02, 0x20, 0x0220, "south small chest grotto 2-1" }, + { 0x02, 0x10, 0x0210, "east small chest grotto 2-1" }, + { 0x02, 0x08, 0x0208, "north small chest grotto 2-1" }, + { 0x02, 0x04, 0x0204, "small chest grotto 1-1" }, + { 0x02, 0x01, 0x0201, "big chest grotto 4-1" }, + { 0x03, 0x80, 0x0380, "big chest grotto 1-2" }, + { 0x03, 0x40, 0x0340, "big chest grotto 1-1" }, + { 0x03, 0x20, 0x0320, "big chest grotto 5-2" }, + { 0x03, 0x10, 0x0310, "big chest grotto 4-0" }, + { 0x03, 0x08, 0x0308, "big chest grotto 2-2" }, + { 0x03, 0x04, 0x0304, "big chest grotto 2-0" }, + { 0x03, 0x02, 0x0302, "big chest grotto 5-0" }, + { 0x03, 0x01, 0x0301, "big chest grotto 1-0" }, + { 0x08, 0x80, 0x0880, "lit right torch grotto 1-1" }, + { 0x08, 0x40, 0x0840, "lit left torch grotto 1-1" }, + { 0x08, 0x20, 0x0820, "killed red chu-chu grotto 3-3" }, + { 0x08, 0x10, 0x0810, "killed chu-chu grotto 3-2" }, + { 0x08, 0x08, 0x0808, "killed blue chu-chu grotto 3-1" }, + { 0x08, 0x04, 0x0804, "killed chu-chu grotto 2-0" }, + { 0x08, 0x02, 0x0802, "killed chu-chu grotto 1-2" }, + { 0x08, 0x01, 0x0801, "killed right freezard grotto 4-2" }, + { 0x09, 0x80, 0x0980, "broke ice wall 1 grotto 4-2" }, + { 0x09, 0x40, 0x0940, "killed chu-chu grotto 1-1" }, + { 0x09, 0x20, 0x0920, "killed all enemies grotto 5-4 (spawm chest)" }, + { 0x09, 0x10, 0x0910, "killed left freezard grotto 4-2" }, + { 0x09, 0x08, 0x0908, "killed blue chu-chu grotto 3-3" }, + { 0x09, 0x04, 0x0904, "broke ice wall 2 grotto 4-2" }, + { 0x09, 0x02, 0x0902, "broke ice wall 4 grotto 4-2" }, + { 0x09, 0x01, 0x0901, "killed poe in the back entrance grotto 3-0" }, + { 0x0A, 0x80, 0x0A80, "killed poe next to entrance grotto 3-0" }, + { 0x0A, 0x40, 0x0A40, "broke ice wall 3 grotto 4-2" }, + { 0x0A, 0x20, 0x0A20, "broke ice wall 6 grotto 4-2" }, + { 0x0A, 0x10, 0x0A10, "broke ice wall 5 grotto 4-2" }, + { 0x0A, 0x08, 0x0A08, "killed middle poe grotto 1-3" }, + { 0x0A, 0x04, 0x0A04, "killed right poe grotto 1-3" }, + { 0x0A, 0x02, 0x0A02, "spawn big chest grotto 1-1" }, + { 0x0A, 0x01, 0x0A01, "killed all enemies grotto 4-1 (spawm chest)" }, + { 0x0B, 0x80, 0x0B80, "killed middle freezard grotto 4-2" }, + { 0x0B, 0x40, 0x0B40, "blown up rocks in grotto 3-2" }, + { 0x0B, 0x20, 0x0B20, "killed all enemies grotto 5-2 (spawm chest)" }, + { 0x0B, 0x10, 0x0B10, "killed all enemies grotto 4-0 (spawm chest)" }, + { 0x0B, 0x08, 0x0B08, "killed all enemies grotto 2-2 (spawm chest)" }, + { 0x0B, 0x04, 0x0B04, "killed all enemies grotto 2-0 (spawm chest)" }, + { 0x0B, 0x02, 0x0B02, "killed all enemies grotto 5-0 (spawm chest)" }, + { 0x0B, 0x01, 0x0B01, "killed all enemies grotto 1-0 (spawm chest)" }, + { 0x0E, 0x10, 0x0E10, "spawn big chest grotto 4-3" }, + { 0x0E, 0x08, 0x0E08, "lit torch 3 grotto 4-3" }, + { 0x0E, 0x04, 0x0E04, "lit torch 2 grotto 4-3" }, + { 0x0E, 0x02, 0x0E02, "lit torch 1 grotto 4-3" }, + { 0x0E, 0x01, 0x0E01, "spawn big chest grotto 3-0" }, + { 0x0F, 0x80, 0x0F80, "lit right torch grotto 3-0" }, + { 0x0F, 0x40, 0x0F40, "lit middle torch grotto 3-0" }, + { 0x0F, 0x20, 0x0F20, "lit left torch grotto 3-0" }, + { 0x0F, 0x10, 0x0F10, "spawn big chest grotto 1-2" }, + { 0x0F, 0x08, 0x0F08, "lit middle torch grotto 1-2" }, + { 0x0F, 0x04, 0x0F04, "lit right torch grotto 1-2" }, + { 0x0F, 0x02, 0x0F02, "lit left torch grotto 1-2" }, + { 0x1A, 0x02, 0x1A02, "picked up yellow rupee from pot grotto 1-2" }, + { 0x1A, 0x01, 0x1A01, "picked up blue rupee from pot grotto 1-2" }, + { 0x1B, 0x80, 0x1B80, "picked up blue rupee from pot grotto 1-2" }, + { 0x1B, 0x40, 0x1B40, "picked up blue rupee from pot grotto 1-2" }, + { 0x1B, 0x20, 0x1B20, "picked up blue rupee from pot grotto 1-2" }, + { 0x1B, 0x10, 0x1B10, "picked up blue rupee from pot grotto 1-2" }, + { 0x1B, 0x08, 0x1B08, "picked up blue rupee from pot grotto 1-2" }, + { 0x1B, 0x04, 0x1B04, "picked up yellow rupee from pot grotto 1-2" }, + { 0x1B, 0x02, 0x1B02, "picked up red rupee from pot grotto 1-2" }, + { 0x1B, 0x01, 0x1B01, "picked up red rupee from pot grotto 1-2" }, +}; + +inline EventAreaFlags eventAreaFlagsHC[] = +{ + { 0x00, 0x40, 0x0040, "big chest behind first gate in graveyard" }, + { 0x00, 0x20, 0x0020, "second small chest treasure room" }, + { 0x00, 0x10, 0x0010, "eighth small chest treasure room" }, + { 0x00, 0x08, 0x0008, "seventh small chest treasure room" }, + { 0x00, 0x04, 0x0004, "sixth small chest treasure room" }, + { 0x00, 0x02, 0x0002, "big chest north room 2F" }, + { 0x01, 0x80, 0x0180, "fourth small chest treasure room" }, + { 0x01, 0x40, 0x0140, "fifth small chest treasure room" }, + { 0x01, 0x20, 0x0120, "third small chest treasure room" }, + { 0x01, 0x08, 0x0108, "fifth big chest treasure room" }, + { 0x01, 0x04, 0x0104, "fourth big chest treasure room" }, + { 0x01, 0x02, 0x0102, "third big chest treasure room" }, + { 0x01, 0x01, 0x0101, "second big chest treasure room" }, + { 0x02, 0x80, 0x0280, "first big chest treasure room" }, + { 0x02, 0x20, 0x0220, "north west big chest center room 2F" }, + { 0x02, 0x08, 0x0208, "small chest east garden" }, + { 0x02, 0x02, 0x0202, "north small chest west garden" }, + { 0x02, 0x01, 0x0201, "compass north east big chest center room 2F" }, + { 0x03, 0x80, 0x0380, "small key big chest behind third gate in graveyard" }, + { 0x03, 0x20, 0x0320, "center small chest west garden" }, + { 0x03, 0x10, 0x0310, "map big chest east garden" }, + { 0x03, 0x08, 0x0308, "king bulblin small key" }, + { 0x03, 0x04, 0x0304, "south west big chest center room 2F" }, + { 0x03, 0x02, 0x0302, "small key big chest outside 2F" }, + { 0x03, 0x01, 0x0301, "big key chest" }, + { 0x07, 0x08, 0x0708, "first small chest treasure room" }, + { 0x07, 0x04, 0x0704, "east small chest behind first gate in graveyard" }, + { 0x07, 0x02, 0x0702, "west small chest behind first gate in graveyard" }, + { 0x08, 0x10, 0x0810, "killed darknut in north room 2F (spawn big chest)" }, + { 0x08, 0x08, 0x0808, "reach end of specter maze 3F" }, + { 0x08, 0x04, 0x0804, "darknut 4F intro cs part 2" }, + { 0x08, 0x02, 0x0802, "darknut 4F intro cs part 1" }, + { 0x08, 0x01, 0x0801, "cut painting in north east room 2F cs" }, + { 0x09, 0x80, 0x0980, "cut painting in north east room 2F cs" }, + { 0x09, 0x40, 0x0940, "killed all enemies in center room 1F cs 1/2" }, + { 0x09, 0x20, 0x0920, "spawn north east big chest center room 2F" }, + { 0x09, 0x10, 0x0910, "killed lizalfos garding big key chest" }, + { 0x09, 0x08, 0x0908, "open third gate in graveyard cs" }, + { 0x09, 0x04, 0x0904, "blown up rock in graveyard" }, + { 0x09, 0x02, 0x0902, "lit torch behind first gate in graveyard (stops rain)" }, + { 0x09, 0x01, 0x0901, "graveyard intro cs" }, + { 0x0A, 0x80, 0x0A80, "open second gate in graveyard cs" }, + { 0x0A, 0x40, 0x0A40, "open first gate in graveyard cs" }, + { 0x0A, 0x20, 0x0A20, "open third gate in graveyard" }, + { 0x0A, 0x10, 0x0A10, "open first gate in graveyard" }, + { 0x0A, 0x04, 0x0A04, "open second gate in graveyard" }, + { 0x0B, 0x01, 0x0B01, "defeated dark beast Ganon" }, + { 0x0C, 0x40, 0x0C40, "cut first left painting in north west room 2F" }, + { 0x0C, 0x20, 0x0C20, "cut second left painting in north west room 2F" }, + { 0x0C, 0x10, 0x0C10, "cut third left painting in north west room 2F" }, + { 0x0C, 0x02, 0x0C02, "killed all enemies in center room 1F" }, + { 0x0D, 0x80, 0x0D80, "despawn yellow magic walls in center room 1F" }, + { 0x0D, 0x40, 0x0D40, "spawn yellow magic walls in center room 1F" }, + { 0x0D, 0x20, 0x0D20, "outside 4F intro cs" }, + { 0x0D, 0x10, 0x0D10, "outside 4F intro cs" }, + { 0x0D, 0x08, 0x0D08, "killed all east bokoblins in south garden" }, + { 0x0D, 0x04, 0x0D04, "killed all west bokoblins in south garden" }, + { 0x0D, 0x01, 0x0D01, "east room 2F intro cs" }, + { 0x0E, 0x80, 0x0E80, "east room 2F intro cs" }, + { 0x0E, 0x10, 0x0E10, "killed right lezalfos in north west room 2F" }, + { 0x0E, 0x08, 0x0E08, "killed left lezalfos in north west room 2F" }, + { 0x0E, 0x01, 0x0E01, "midna text at the end of east garden (talk about wall)" }, + { 0x0F, 0x80, 0x0F80, "explored graveyard" }, + { 0x10, 0x80, 0x1080, "killed both lizalfos in 4F (removes yellow magic barrior)" }, + { 0x10, 0x40, 0x1040, "killed both lizalfos in 3F (removes yellow magic barrior)" }, + { 0x10, 0x20, 0x1020, "south garden intro cs" }, + { 0x10, 0x02, 0x1002, "Midna text prompt after king bulblin" }, + { 0x10, 0x01, 0x1001, "killed all bokoblins in west garden" }, + { 0x11, 0x80, 0x1180, "prevent all torches form extinguishing north east room 2F" }, + { 0x11, 0x40, 0x1140, "unlock door in north east room 2F cs" }, + { 0x11, 0x10, 0x1110, "open second gate in west garden" }, + { 0x11, 0x08, 0x1108, "east garden intro cs" }, + { 0x11, 0x04, 0x1104, "east garden intro cs" }, + { 0x11, 0x02, 0x1102, "open gate in east garden" }, + { 0x11, 0x01, 0x1101, "open gate in east garden cs" }, + { 0x12, 0x80, 0x1280, "unlock door in north east room 2F" }, + { 0x12, 0x40, 0x1240, "lit all torches correctly in north east room 2F" }, + { 0x12, 0x20, 0x1220, "lit all torches correctly in north east room 2F cs" }, + { 0x12, 0x10, 0x1210, "unlock door outside 3F" }, + { 0x12, 0x08, 0x1208, "open gate to big key chest" }, + { 0x12, 0x04, 0x1204, "killed arealfos outside 2F" }, + { 0x12, 0x01, 0x1201, "killed all enemies in center room 1F cs 1/2" }, + { 0x13, 0x40, 0x1340, "Double Darknut room intro cs" }, + { 0x13, 0x08, 0x1308, "spawn north west big chest center room 2F" }, + { 0x13, 0x04, 0x1304, "west room 2F intro cs" }, + { 0x13, 0x02, 0x1302, "cut right painting in north west room 2F" }, + { 0x14, 0x40, 0x1440, "unlock boss door" }, + { 0x14, 0x10, 0x1410, "unlock door in south garden" }, + { 0x14, 0x08, 0x1408, "midna text seen after small key in graveyard" }, + { 0x14, 0x04, 0x1404, "midna text promt after small key in graveyard" }, + { 0x14, 0x02, 0x1402, "Midna text seen after king bulblin" }, + { 0x14, 0x01, 0x1401, "north west room 2F intro cs" }, + { 0x15, 0x40, 0x1540, "cut painting in north east room 2F" }, + { 0x15, 0x08, 0x1508, "second gate in west garden stops moving" }, + { 0x15, 0x04, 0x1504, "open second gate in west garden cs" }, + { 0x15, 0x01, 0x1501, "killed dynalfos in east room 2F (unlocks doors)" }, + { 0x16, 0x80, 0x1680, "unlock treasure room door 4F" }, + { 0x16, 0x04, 0x1604, "killed darknuts in west room 2F (unlocks doors)" }, + { 0x16, 0x02, 0x1602, "reach big chest in north room 2F" }, + { 0x16, 0x01, 0x1601, "lit south east torch north room 2F for the first time cs" }, + { 0x17, 0x80, 0x1780, "lit north east torch north room 2F for the first time cs" }, + { 0x17, 0x10, 0x1710, "unlock door in north west room 2F" }, + { 0x17, 0x01, 0x1701, "killed darknut 4F (removes yellow magic barrier)" }, +}; + +inline EventAreaFlags eventAreaFlagsHyruleField[] = +{ + { 0x02, 0x80, 0x0280, "Big chest owl statue hylia bridge" }, + { 0x02, 0x40, 0x0240, "Big chest spinner south of castle town" }, + { 0x02, 0x20, 0x0220, "Big chest double clawshot south of castle town" }, + { 0x02, 0x10, 0x0210, "Big chest tight rope south of castle town" }, + { 0x02, 0x08, 0x0208, "Big chest owl statue next to castle town" }, + { 0x02, 0x04, 0x0204, "Big chest on hylia bridge" }, + { 0x02, 0x02, 0x0202, "Big chest next to poe past hylia bridge" }, + { 0x02, 0x01, 0x0201, "Big chest spinner tracks (Lanayru)" }, + { 0x03, 0x80, 0x0380, "Big chest underwater Lanayru field" }, + { 0x03, 0x40, 0x0340, "Big chest under bridge faron field" }, + { 0x03, 0x20, 0x0320, "PoH big chest double clawshot Eldin gorge" }, + { 0x03, 0x10, 0x0310, "Big chest Eldin gorge owl statue" }, + { 0x03, 0x08, 0x0308, "PoH big chest owl statue Eldin bridge" }, + { 0x03, 0x04, 0x0304, "PoH big chest leage Eldin field after kakariko" }, + { 0x03, 0x02, 0x0302, "Map marker Telma carrage past hylia bridge" }, + { 0x03, 0x01, 0x0301, "Map marker Telma carrage west of castle town" }, + { 0x08, 0x80, 0x0880, "Lanayru field intro cs twilight" }, + { 0x08, 0x20, 0x0820, "blown up rock blocking Eldin long cave" }, + { 0x08, 0x10, 0x0810, "Hidden village path open" }, + { 0x08, 0x08, 0x0808, "East Castle Town Bridge Flag" }, + { 0x08, 0x04, 0x0804, "blown up rocks blocking path to zora's domain" }, + { 0x08, 0x01, 0x0801, "Midna pulls up the map to show you can warp" }, + { 0x09, 0x80, 0x0980, "midna text Eldin gorge bridge gone" }, + { 0x09, 0x40, 0x0940, "exit flight by foul after lanayru twilight cleared" }, + { 0x09, 0x20, 0x0920, "Kakariko Gorge Portal" }, + { 0x09, 0x10, 0x0910, "spawn barriers Eldin gorge dark beasts (unset once killed)" }, + { 0x09, 0x08, 0x0908, "bridge of Eldin placed (cs)" }, + { 0x09, 0x04, 0x0904, "Eldin bridge getting stolen cs trigger" }, + { 0x09, 0x02, 0x0902, "blown up rocks past Eldin bridge that lead to Lanayru" }, + { 0x09, 0x01, 0x0901, "see gorge gate cs" }, + { 0x0A, 0x80, 0x0A80, "blown up rocks to spinner tracks (Lanayru field side)" }, + { 0x0A, 0x40, 0x0A40, "blown up rocks to spinner tracks (hylia bridge side)" }, + { 0x0A, 0x20, 0x0A20, "entered Lanayru twilight cs" }, + { 0x0A, 0x10, 0x0A10, "entered Eldin twilight cs" }, + { 0x0A, 0x08, 0x0A08, "killed left shadow bulblin behind gorge gate twilight" }, + { 0x0A, 0x04, 0x0A04, "killed right shadow bulblin behind gorge gate twilight" }, + { 0x0A, 0x02, 0x0A02, "jumped over gorge fence after obtaining Epona" }, + { 0x0B, 0x80, 0x0B80, "Lanayru Main Feild has water on map" }, + { 0x0B, 0x40, 0x0B40, "seeing Lanayru twilight from up close cs" }, + { 0x0B, 0x20, 0x0B20, "seeing Eldin twilight from up close cs" }, + { 0x0B, 0x10, 0x0B10, "spawn dark beasts castle town portal (stays set)" }, + { 0x0B, 0x08, 0x0B08, "Castle Town Portal" }, + { 0x0B, 0x04, 0x0B04, "?" }, + { 0x0B, 0x01, 0x0B01, "blown up rocks from Eldin gorge to Eldin field" }, + { 0x0C, 0x80, 0x0C80, "blown up second rock to poe past hylia bridge" }, + { 0x0C, 0x20, 0x0C20, "Epona is accessible to Link (without calling her) (after lanayru twilight)" }, + { 0x0C, 0x08, 0x0C08, "killed poe past hylia bridge" }, + { 0x0C, 0x04, 0x0C04, "killed poe Eldin gorge" }, + { 0x0C, 0x02, 0x0C02, "killed poe faron field" }, + { 0x0D, 0x80, 0x0D80, "Midna text after warping gorge bridge back" }, + { 0x0D, 0x40, 0x0D40, "?" }, + { 0x0D, 0x10, 0x0D10, "spinner path next to hidden village explored" }, + { 0x0D, 0x08, 0x0D08, "killed poe Lanayru field" }, + { 0x0D, 0x02, 0x0D02, "enter field west of castle town from the east" }, + { 0x0D, 0x01, 0x0D01, "killed poe south of castle town" }, + { 0x0E, 0x80, 0x0E80, "bridge of Hylia intro cs twilight" }, + { 0x0E, 0x40, 0x0E40, "blown up rock blocking ice cave Lanayru field" }, + { 0x0E, 0x20, 0x0E20, "faron field intro cs" }, + { 0x0E, 0x10, 0x0E10, "blown up rock on leadge Eldin field after kakariko" }, + { 0x0E, 0x08, 0x0E08, "blown up first rock to poe past hylia bridge" }, + { 0x0E, 0x04, 0x0E04, "Hero's shade map marker (south castle town)" }, + { 0x0E, 0x02, 0x0E02, "Hero's shade map marker (west castle town)" }, + { 0x0E, 0x01, 0x0E01, "enter bridge east of castle town" }, + { 0x0F, 0x80, 0x0F80, "enter field south of castle town" }, + { 0x0F, 0x40, 0x0F40, "enter field west of castle town from the north" }, + { 0x0F, 0x20, 0x0F20, "?" }, + { 0x0F, 0x10, 0x0F10, "open path from faron field to south of castle town" }, + { 0x0F, 0x08, 0x0F08, "Midna text after Lanayru field twilight cs" }, + { 0x0F, 0x04, 0x0F04, "blown up rocks Eldin field after kakariko" }, + { 0x0F, 0x02, 0x0F02, "Eldin gorge bridge placed cs" }, + { 0x0F, 0x01, 0x0F01, "see Ilia's bag from far away" }, + { 0x10, 0x01, 0x1001, "Zora rivver boat path on map (Eldin)" }, + { 0x11, 0x80, 0x1180, "Sky letter next to castle town" }, + { 0x11, 0x40, 0x1140, "Map marker owl stature next to castle town" }, + { 0x11, 0x20, 0x1120, "Sky letter hylia bridge" }, + { 0x11, 0x10, 0x1110, "Map marker owl stature Hylia bridge" }, + { 0x11, 0x08, 0x1108, "Sky letter Eldin bridge" }, + { 0x11, 0x04, 0x1104, "Map marker owl stature Eldin bridge" }, + { 0x11, 0x02, 0x1102, "Sky letter Eldin gorge" }, + { 0x11, 0x01, 0x1101, "Map marker owl stature Eldin gorge" }, + { 0x12, 0x10, 0x1210, "blown up northern rock in field west of castle town" }, + { 0x12, 0x08, 0x1208, "blown up most northern rock in field west of castle town" }, + { 0x12, 0x04, 0x1204, "blown up rock south of castle town" }, + { 0x12, 0x02, 0x1202, "killed poe next to owl statue next to castle town" }, + { 0x13, 0x80, 0x1380, "killed poe east of castle town" }, + { 0x13, 0x10, 0x1310, "?" }, + { 0x13, 0x08, 0x1308, "?" }, + { 0x13, 0x04, 0x1304, "Epona isn't accessible to Link (without calling her) (after lanayru twilight)" }, + { 0x13, 0x02, 0x1302, "?" }, + { 0x13, 0x01, 0x1301, "Map marker hidden village" }, + { 0x14, 0x80, 0x1480, "blown up southern rock underwater Lanayru field" }, + { 0x14, 0x40, 0x1440, "blown up northern rock underwater Lanayru field" }, + { 0x14, 0x20, 0x1420, "blown up eastern rock Lanayru field " }, + { 0x14, 0x10, 0x1410, "blown up rock next to hylia bridge owl statue" }, + { 0x14, 0x08, 0x1408, "blown up rock closest to faron after hylia bridge" }, + { 0x14, 0x04, 0x1404, "blown up rock next to free standing PoH Elding gorge" }, + { 0x14, 0x01, 0x1401, "blown up rock next to Eldin gorge owl statue" }, + { 0x15, 0x80, 0x1580, "blown up rock past Eldin bridge" }, + { 0x16, 0x20, 0x1620, "Midna text after getting Ilia's scent" }, + { 0x16, 0x10, 0x1610, "Midna text after entering Lanayru twilight" }, + { 0x16, 0x08, 0x1608, "Midna text when seeing Lanayru twilight from far away" }, + { 0x16, 0x04, 0x1604, "Midna text after getting Youth's scent" }, + { 0x16, 0x02, 0x1602, "Midna text after entering Eldin twilight" }, + { 0x16, 0x01, 0x1601, "Midna text when seeing Eldin twilight from far away" }, + { 0x17, 0x80, 0x1780, "got Ilia's scent cs" }, + { 0x17, 0x40, 0x1740, "got youth's scent cs" }, + { 0x17, 0x20, 0x1720, "Epona can't cross Eldin bridge (set when stolen, unset when fixed)" }, + { 0x17, 0x10, 0x1710, "see broken wooden sword from far away cs" }, + { 0x17, 0x08, 0x1708, "Bridge of Eldin Portal" }, + { 0x1A, 0x80, 0x1A80, "picked up rupees from rock past Eldin bridge" }, + { 0x1A, 0x40, 0x1A40, "picked up rupees from rock next to free standing PoH Elding gorge" }, + { 0x1A, 0x20, 0x1A20, "picked up rupees from rock next to Eldin gorge owl statue" }, + { 0x1A, 0x10, 0x1A10, "picked up rupees from rock closest to faron after hylia bridge" }, + { 0x1A, 0x08, 0x1A08, "picked up rupees from rock next to hylia bridge owl statue" }, + { 0x1A, 0x04, 0x1A04, "picked up rupees from rocks to spinner tracks (hylia bridge side)" }, + { 0x1A, 0x02, 0x1A02, "picked up rupees from rocks to spinner tracks (Lanayru field side)" }, + { 0x1A, 0x01, 0x1A01, "picked up rupees from eastern rock Lanayru field " }, + { 0x1B, 0x80, 0x1B80, "picked up rupees from northern rock underwater Lanayru field" }, + { 0x1B, 0x40, 0x1B40, "picked up rupees from southern rock underwater Lanayru field" }, + { 0x1B, 0x20, 0x1B20, "picked up rupees from northern rock in field west of castle town" }, + { 0x1B, 0x10, 0x1B10, "picked up rupees from most northern rock in field west of castle town" }, + { 0x1B, 0x08, 0x1B08, "picked up rupees from rock south of castle town" }, + { 0x1B, 0x04, 0x1B04, "free standing PoH Elding gorge" }, + { 0x1B, 0x02, 0x1B02, "free standing PoH faron field" }, + { 0x1B, 0x01, 0x1B01, "free standing PoH goron Eldin field" }, +}; + +inline EventAreaFlags eventAreaFlagsLanayru[] = +{ + { 0x00, 0x40, 0x0040, "small chest next to mother and child iles zora's domain" }, + { 0x00, 0x20, 0x0020, "big chest fountain back room" }, + { 0x00, 0x10, 0x0010, "left small chest fountain back room" }, + { 0x00, 0x08, 0x0008, "right small chest fountain back room" }, + { 0x00, 0x04, 0x0004, "small chest midna jumps zora's domain" }, + { 0x01, 0x10, 0x0110, "west big chest zora's domain throne room" }, + { 0x01, 0x08, 0x0108, "east big chest zora's domain throne room" }, + { 0x02, 0x10, 0x0210, "small chest large underwater pillar in fountain" }, + { 0x02, 0x04, 0x0204, "small chest small underwater pillar in fountain" }, + { 0x02, 0x01, 0x0201, "small chest floor 3 flight by foul" }, + { 0x03, 0x80, 0x0380, "small chest floor 2 flight by foul" }, + { 0x03, 0x40, 0x0340, "big chest right pillar in front of fountain Lake Hylia" }, + { 0x03, 0x20, 0x0320, "big chest underwater next to Lake Hylia warp" }, + { 0x03, 0x10, 0x0310, "east big chest fountain" }, + { 0x03, 0x08, 0x0308, "west big chest fountain" }, + { 0x03, 0x04, 0x0304, "big chest floor 4 flight by foul" }, + { 0x03, 0x02, 0x0302, "small chest left pillar in front of fountain Lae Hylia" }, + { 0x03, 0x01, 0x0301, "big chest floor 5 flight by foul" }, + { 0x04, 0x40, 0x0440, "tear of light throne room zora's domain" }, + { 0x04, 0x20, 0x0420, "first tear of light flying" }, + { 0x04, 0x10, 0x0410, "tear of light midna jumps zora's domain" }, + { 0x04, 0x08, 0x0408, "tear of light on top of water zora's domain" }, + { 0x04, 0x04, 0x0404, "third tear of light flying" }, + { 0x04, 0x02, 0x0402, "fourth tear of light flying" }, + { 0x05, 0x80, 0x0580, "tear of light next to Iza's shop" }, + { 0x05, 0x40, 0x0540, "second tear of light flying" }, + { 0x05, 0x20, 0x0520, "final tear of light" }, + { 0x05, 0x04, 0x0504, "tear of light behind of Fyer's canon" }, + { 0x05, 0x02, 0x0502, "tear of light island east of Lake Hylia" }, + { 0x05, 0x01, 0x0501, "tear of light southmost island Lake Hylia" }, + { 0x06, 0x80, 0x0680, "tear of light next to fountain Lake Hylia" }, + { 0x06, 0x40, 0x0640, "tear of light on top of water zora's domain" }, + { 0x06, 0x20, 0x0620, "tear of light next to mother and child iles zora's domain" }, + { 0x08, 0x80, 0x0880, "see frozen zora spirits in domain twilight" }, + { 0x08, 0x40, 0x0840, "Lake hylia intro cs twilight" }, + { 0x08, 0x20, 0x0820, "blown up underwater rock in center of fountain" }, + { 0x08, 0x10, 0x0810, "the two zoras in upper zora river went down stream (twilight)" }, + { 0x08, 0x08, 0x0808, "saw light bug come out next to Iza spirit cs" }, + { 0x08, 0x02, 0x0802, "blown up rock to Lake hylia long cave" }, + { 0x08, 0x01, 0x0801, "spawned UZR portal fight barriers" }, + { 0x09, 0x80, 0x0980, "opened Upper Zora's River Portal cs" }, + { 0x09, 0x40, 0x0940, "talked to Iza before UZR portal" }, + { 0x09, 0x20, 0x0920, "Upper Zora's River Portal" }, + { 0x09, 0x10, 0x0910, "spawn big chest fountain back room" }, + { 0x09, 0x08, 0x0908, "lit left torch fountain back room" }, + { 0x09, 0x04, 0x0904, "lit right torch fountain back room" }, + { 0x09, 0x02, 0x0902, "seeing Twilight Bloat with sense cs" }, + { 0x09, 0x01, 0x0901, "Twilight Bloat comes out of water cs" }, + { 0x0A, 0x80, 0x0A80, "seeing Twilit Bloat move from far away cs" }, + { 0x0A, 0x40, 0x0A40, "Save Prompt after Lakebed (if disabled, triggers MDH after Lakebed)" }, + { 0x0A, 0x20, 0x0A20, "twilight end cs trigger (also map marker Lakebed Temple)" }, + { 0x0A, 0x10, 0x0A10, "obtained vessel of light (unset after twilight)" }, + { 0x0A, 0x08, 0x0A08, "spawn dark beasts Lake Hylia (unset once killed)" }, + { 0x0A, 0x04, 0x0A04, "Lake Hylia Portal" }, + { 0x0A, 0x02, 0x0A02, "Zora's river intro cs during twilight (flying with bird)" }, + { 0x0A, 0x01, 0x0A01, "midna text promt saying you can call down Kargarok to fly" }, + { 0x0B, 0x80, 0x0B80, "Rutella cs in domain twilight" }, + { 0x0B, 0x40, 0x0B40, "Zora river boat path on map" }, + { 0x0B, 0x20, 0x0B20, "entered Twilight Bloat arena (unset once killed)" }, + { 0x0B, 0x10, 0x0B10, "explored entrance to snowpeak" }, + { 0x0B, 0x08, 0x0B08, "got PoH flight by foul" }, + { 0x0B, 0x04, 0x0B04, "Zora's Domain Portal" }, + { 0x0B, 0x02, 0x0B02, "spawn barriers Zora's domain dark beasts fight" }, + { 0x0B, 0x01, 0x0B01, "Zora's domain intro cs twilight (frozen)" }, + { 0x0C, 0x08, 0x0C08, "blown up south underwater rock zora's domain " }, + { 0x0C, 0x04, 0x0C04, "blown up north underwater rock zora's domain" }, + { 0x0C, 0x02, 0x0C02, "blown up underwater rock in back of fountain" }, + { 0x0C, 0x01, 0x0C01, "Midna text after landing in Lake hylia twilight" }, + { 0x0D, 0x80, 0x0D80, "Iza text after Upper Zora's River Portal" }, + { 0x0D, 0x40, 0x0D40, "can now exit from the sides of zora's domain inside (set during domain outside cs after melting it)" }, + { 0x0D, 0x20, 0x0D20, "Midna text after domain outside cs after melting it" }, + { 0x0D, 0x10, 0x0D10, "domain outside cs after melting it" }, + { 0x0D, 0x08, 0x0D08, "map marker Auru" }, + { 0x0D, 0x04, 0x0D04, "Upper zora's river intro cs during twilight" }, + { 0x0D, 0x02, 0x0D02, "Midna text after leaving lake hylia after Lanayru twilight" }, + { 0x0D, 0x01, 0x0D01, "Zora's domain waterfall is going fast (during twilight only) (unset when you come back to Lake hylia)" }, + { 0x0E, 0x80, 0x0E80, "blown up rock blocking lakebed entrance cs" }, + { 0x0E, 0x40, 0x0E40, "opened stream next to lakebed entance" }, + { 0x0E, 0x20, 0x0E20, "Midna text after arriving at upper zora's river twilight" }, + { 0x0E, 0x10, 0x0E10, "melted zora's domain (Lake Hylia water on map (top part))" }, + { 0x0E, 0x08, 0x0E08, "twilight end cs watched" }, + { 0x0E, 0x04, 0x0E04, "map marker Snowpeak" }, + { 0x0E, 0x01, 0x0E01, "Midna text after coming back to lake after filling it (twilight)" }, + { 0x0F, 0x80, 0x0F80, "blown up rock blocking lakebed entrance" }, + { 0x0F, 0x40, 0x0F40, "went down the fast water in zora's domain (void out) (unset after twilight)" }, + { 0x0F, 0x20, 0x0F20, "Lake hylia filled twilight intro cs (domain water level normal)" }, + { 0x0F, 0x10, 0x0F10, "blown up first rock to throne room zora's domain" }, + { 0x0F, 0x08, 0x0F08, "Midna text prompt to tell you to look under the ice in zora's domain twilight" }, + { 0x0F, 0x04, 0x0F04, "Midna text before midna jumps fozen zora's domain twilight" }, + { 0x0F, 0x02, 0x0F02, "Midna text before midna jumps melted zora's domain twilight" }, + { 0x0F, 0x01, 0x0F01, "Midna text after melting domain (water everywhere on map)" }, + { 0x10, 0x80, 0x1080, "blown up underwater rock zora river town path" }, + { 0x10, 0x40, 0x1040, "spawn west big chest zora's domain throne room" }, + { 0x10, 0x20, 0x1020, "spawn east big chest zora's domain throne room" }, + { 0x10, 0x10, 0x1010, "lit east torch zora's domain throne room" }, + { 0x10, 0x08, 0x1008, "extingushed north torch zora's domain throne room" }, + { 0x10, 0x04, 0x1004, "lit west torch zora's domain throne room" }, + { 0x10, 0x02, 0x1002, "blown up west underwater rock Lakebed area" }, + { 0x10, 0x01, 0x1001, "blown up south underwater rock Lakebed area" }, + { 0x11, 0x80, 0x1180, "saw the two zora spirits from far away in upper zora river cs (twilight)" }, + { 0x11, 0x40, 0x1140, "saw light bug moving after exiting lanayru spring" }, + { 0x11, 0x20, 0x1120, "went down zora's river with bird during twilight" }, + { 0x11, 0x10, 0x1110, "blown up underwater rock zora river lake path" }, + { 0x11, 0x08, 0x1108, "midna text after seeing the frozen zoras in domain twilight" }, + { 0x11, 0x02, 0x1102, "paid Fyer to launch you to the flight by foul platform (unset once you enter the canon)" }, + { 0x11, 0x01, 0x1101, "blown up north underwater rock throne room zora's domain" }, + { 0x12, 0x80, 0x1280, "Lanayru spring map marker" }, + { 0x12, 0x40, 0x1240, "Midna Text after frozen zora's domain twilight intro cs" }, + { 0x12, 0x20, 0x1220, "killed poe underneath flight by foul" }, + { 0x12, 0x10, 0x1210, "killed poe next to watch tower to desert" }, + { 0x12, 0x08, 0x1208, "killed poe east of lake Hylia" }, + { 0x12, 0x04, 0x1204, "killed poe next to mother and chile iles Zora's Domain" }, + { 0x12, 0x02, 0x1202, "killed poe midna jumps Zora's Domain" }, + { 0x12, 0x01, 0x1201, "killed poe in Upper Zora's River" }, + { 0x13, 0x80, 0x1380, "killed poe on flight by foul prizes" }, + { 0x13, 0x40, 0x1340, "killed poe next to fountain Lake Hylia" }, + { 0x13, 0x20, 0x1320, "blew up rock in Iza's house" }, + { 0x13, 0x10, 0x1310, "Iza text after blowing the rocks inside her house" }, + { 0x13, 0x01, 0x1301, "blew up rock in Iza's house cs" }, + { 0x14, 0x40, 0x1440, "killed light bug throne room zora's domain" }, + { 0x14, 0x20, 0x1420, "killed first light bug flying" }, + { 0x14, 0x10, 0x1410, "killed light bug midna jumps zora's domain" }, + { 0x14, 0x08, 0x1408, "killed light bug on top of water zora's domain" }, + { 0x14, 0x04, 0x1404, "killed third light bug flying" }, + { 0x14, 0x02, 0x1402, "killed fourth light bug flying" }, + { 0x14, 0x01, 0x1401, "killed light bug behind of Fyer's canon" }, + { 0x15, 0x80, 0x1580, "killed light bug next to Iza's shop" }, + { 0x15, 0x40, 0x1540, "killed second light bug flying" }, + { 0x15, 0x20, 0x1520, "killed final light bug (Twilight Bloat)" }, + { 0x15, 0x10, 0x1510, "killed light bug island east of Lake Hylia" }, + { 0x15, 0x02, 0x1502, "killed light bug next to mother and child iles zora's domain" }, + { 0x15, 0x01, 0x1501, "?" }, + { 0x16, 0x80, 0x1680, "Watched CS of Ooccoo running to Sky Cannon" }, + { 0x16, 0x40, 0x1640, "killed light bug on top of water zora's domain" }, + { 0x16, 0x20, 0x1620, "killed light bug southmost island Lake Hylia" }, + { 0x16, 0x10, 0x1610, "killed light bug next to fountain Lake Hylia" }, + { 0x16, 0x02, 0x1602, "talked to light spirit during twilight" }, + { 0x16, 0x01, 0x1601, "went up zora's river after melting domain in twilight" }, + { 0x17, 0x80, 0x1780, "blown up rock zora river on land" }, + { 0x17, 0x40, 0x1740, "went up zora's river after melting domain in twilight (also set when failing to do so)" }, + { 0x17, 0x20, 0x1720, "blown up second rock to throne room zora's domain" }, + { 0x17, 0x10, 0x1710, "?" }, + { 0x17, 0x02, 0x1702, "Midna text after Zora's domain portal" }, + { 0x17, 0x01, 0x1701, "blown up underwater rock zora river middle" }, + { 0x18, 0x08, 0x1808, "picked up rupees from south underwater rock Lakebed area" }, + { 0x18, 0x04, 0x1804, "picked up rupees from west underwater rock Lakebed area" }, + { 0x18, 0x02, 0x1802, "picked up green rupees domain midna jumps twilight" }, + { 0x18, 0x01, 0x1801, "picked up fourth green rupee domain midna jumps twilight" }, + { 0x19, 0x80, 0x1980, "picked up third blue rupee midna jumps zora's domain" }, + { 0x19, 0x40, 0x1940, "picked up second blue rupee midna jumps zora's domain" }, + { 0x19, 0x20, 0x1920, "picked up first blue rupee midna jumps zora's domain" }, + { 0x19, 0x10, 0x1910, "picked up rupees from rock zora river on land" }, + { 0x19, 0x08, 0x1908, "picked up rupees from underwater rock zora river lake path" }, + { 0x19, 0x04, 0x1904, "picked up rupees from underwater rock zora river town path" }, + { 0x19, 0x02, 0x1902, "picked up rupees from underwater rock zora river middle" }, + { 0x19, 0x01, 0x1901, "picked up rupees from underwater rock back fountain" }, + { 0x1A, 0x80, 0x1A80, "picked up rupees from underwater rock center fountain" }, + { 0x1A, 0x40, 0x1A40, "picked up rupees from south underwater rock zora's domain " }, + { 0x1A, 0x20, 0x1A20, "picked up rupees from north underwater rock zora's domain" }, + { 0x1A, 0x10, 0x1A10, "picked up rupees from first rock to throne room zora's domain" }, + { 0x1A, 0x08, 0x1A08, "picked up rupees from second rock to throne room zora's domain" }, + { 0x1A, 0x04, 0x1A04, "picked up east blue rupees behind underwater bridge throne room zora's domain" }, + { 0x1A, 0x02, 0x1A02, "picked up west blue rupees behind underwater bridge throne room zora's domain" }, + { 0x1A, 0x01, 0x1A01, "picked up south yellow rupee unerwater throne room zora's domain" }, + { 0x1B, 0x80, 0x1B80, "picked up north yellow rupee unerwater throne room zora's domain" }, + { 0x1B, 0x40, 0x1B40, "picked up east yellow rupee unerwater throne room zora's domain" }, + { 0x1B, 0x20, 0x1B20, "picked up yellow rupee above north underwater rock throne room zora's domain" }, + { 0x1B, 0x10, 0x1B10, "picked up first yellow rupee midna jumps zora's domain" }, + { 0x1B, 0x08, 0x1B08, "picked up second yellow rupee midna jumps zora's domain" }, + { 0x1B, 0x02, 0x1B02, "picked up yellow rupee from broken pillar lakebed area" }, + { 0x1B, 0x01, 0x1B01, "picked up yellow rupee from broken pillar lakebed area" }, +}; + +inline EventAreaFlags eventAreaFlagsLBT[] = +{ + { 0x00, 0x40, 0x0040, "small chest first west room 1F" }, + { 0x00, 0x20, 0x0020, "south small chest first room" }, + { 0x00, 0x10, 0x0010, "west small chest first room" }, + { 0x00, 0x08, 0x0008, "small chest second east room 4F" }, + { 0x00, 0x02, 0x0002, "underwater big chest in first west room 2F" }, + { 0x00, 0x01, 0x0001, "small chest first east room 2F" }, + { 0x01, 0x40, 0x0140, "Ooccoo Map Flag" }, + { 0x01, 0x20, 0x0120, "small chest second west room 4F" }, + { 0x01, 0x10, 0x0110, "compass big chest second west room 4F" }, + { 0x01, 0x08, 0x0108, "center small chest first west room 2F" }, + { 0x01, 0x04, 0x0104, "small chest in room before big key" }, + { 0x01, 0x02, 0x0102, "map big chest main room 1F" }, + { 0x01, 0x01, 0x0101, "big chest under boss door main room B1" }, + { 0x02, 0x80, 0x0280, "south underwater big chest in room before mini-boss" }, + { 0x02, 0x40, 0x0240, "north underwater big chest in room before mini-boss" }, + { 0x02, 0x20, 0x0220, "north west big chest first west room 2F" }, + { 0x02, 0x10, 0x0210, "big key chest" }, + { 0x02, 0x08, 0x0208, "big chest second east room 4F" }, + { 0x02, 0x04, 0x0204, "small key big chest first east room 2F" }, + { 0x02, 0x01, 0x0201, "PoH big chest behind gate in first east room 1F" }, + { 0x03, 0x80, 0x0380, "south small chest in first west room 2F" }, + { 0x03, 0x40, 0x0340, "small key big chest first east room 1F" }, + { 0x03, 0x20, 0x0320, "PoH big chest main room 2F" }, + { 0x03, 0x08, 0x0308, "small chest second room" }, + { 0x03, 0x04, 0x0304, "small key big chest room before mini-boss" }, + { 0x03, 0x02, 0x0302, "small chest main room 1F" }, + { 0x03, 0x01, 0x0301, "clawshot big chest mini-boss room" }, + { 0x08, 0x80, 0x0880, "raised water in first east room 1F" }, + { 0x08, 0x40, 0x0840, "water flowing into first east room 1F cs" }, + { 0x08, 0x20, 0x0820, "?" }, + { 0x08, 0x02, 0x0802, "Midna Stalactite text second room" }, + { 0x09, 0x80, 0x0980, "water flowing into first east room 1F" }, + { 0x09, 0x20, 0x0920, "west water flowing into stairs in main room" }, + { 0x09, 0x10, 0x0910, "east water flowing into stairs in main room" }, + { 0x09, 0x08, 0x0908, "water flowing into east wing 1F" }, + { 0x09, 0x04, 0x0904, "water flowing into west wing 1F" }, + { 0x09, 0x02, 0x0902, "water in main room raised twice" }, + { 0x09, 0x01, 0x0901, "water in main room raised once" }, + { 0x0A, 0x80, 0x0A80, "west water not flowing into stairs in main room" }, + { 0x0A, 0x40, 0x0A40, "east water not flowing into stairs in main room" }, + { 0x0A, 0x20, 0x0A20, "west water is flowing into main room" }, + { 0x0A, 0x10, 0x0A10, "staircase top is west main room" }, + { 0x0A, 0x08, 0x0A08, "staircase top is east main room" }, + { 0x0A, 0x04, 0x0A04, "east water is flowing into main room" }, + { 0x0A, 0x02, 0x0A02, "let water flow out of room west wing 2F" }, + { 0x0A, 0x01, 0x0A01, "let water flow out of room east wing 2F" }, + { 0x0B, 0x10, 0x0B10, "spawn clawshot big chest" }, + { 0x0B, 0x08, 0x0B08, "set staircase top is east main room" }, + { 0x0B, 0x04, 0x0B04, "set staircase top is north main room" }, + { 0x0B, 0x02, 0x0B02, "set staircase top is west main room" }, + { 0x0B, 0x01, 0x0B01, "set staircase top is south main room (default)" }, + { 0x0D, 0x40, 0x0D40, "PoH big chest behind gate in first east room 1F (set after)" }, + { 0x0D, 0x20, 0x0D20, "horizontal wheel is turning in first east room" }, + { 0x0D, 0x10, 0x0D10, "unlock east door main room 2F" }, + { 0x0D, 0x08, 0x0D08, "vertical wheel is turning in first east room 2F" }, + { 0x0D, 0x04, 0x0D04, "small key big chest first east room 1F (set after)" }, + { 0x0D, 0x02, 0x0D02, "east wing water switch 4F" }, + { 0x0D, 0x01, 0x0D01, "west wing water switch 4F" }, + { 0x0E, 0x04, 0x0E04, "opened north gate first east room 2F" }, + { 0x0E, 0x01, 0x0E01, "opened gate in first room" }, + { 0x0F, 0x80, 0x0F80, "blown up second rock in room before big key" }, + { 0x0F, 0x40, 0x0F40, "blown up first rock in room before big key" }, + { 0x0F, 0x10, 0x0F10, "unlocked door in second east room 2F" }, + { 0x0F, 0x08, 0x0F08, "unlocked door in room before mini-boss" }, + { 0x0F, 0x02, 0x0F02, "horizontal wheel is turning in first east room cs" }, + { 0x0F, 0x01, 0x0F01, "horizontal wheels turning in first west room" }, + { 0x10, 0x80, 0x1080, "killed lizalfos in south hallway to main room 2F" }, + { 0x10, 0x40, 0x1040, "killed lizalfos behind gate in first east room 1F " }, + { 0x10, 0x04, 0x1004, "blown up rock in room before mini-boss" }, + { 0x11, 0x80, 0x1180, "Ooccoo Freed" }, + { 0x11, 0x20, 0x1120, "unlocked boss door" }, + { 0x11, 0x10, 0x1110, "a stalactite fell in second room (other than the first one)" }, + { 0x11, 0x04, 0x1104, "stalactite fell in first west room 2F" }, + { 0x11, 0x02, 0x1102, "stalactite falls by itself in second room" }, + { 0x11, 0x01, 0x1101, "left stalactite fell in first east room 2F" }, + { 0x12, 0x80, 0x1280, "right stalactite fell in first east room 2F" }, + { 0x12, 0x40, 0x1240, "blown up rock in first east room 2F" }, + { 0x12, 0x20, 0x1220, "south stalactite fell in first east room 1F" }, + { 0x12, 0x10, 0x1210, "north stalactite fell in first east room 1F" }, + { 0x12, 0x08, 0x1208, "south-east stalactite fell second room" }, + { 0x12, 0x04, 0x1204, "north east stalactite fell in second room" }, + { 0x12, 0x02, 0x1202, "south Stalactite fell second room" }, + { 0x12, 0x01, 0x1201, "north west stalactite fell in second room" }, + { 0x13, 0x80, 0x1380, "south west stalactile fell in second room" }, + { 0x13, 0x20, 0x1320, "killed first shell blade in room before big key" }, + { 0x13, 0x10, 0x1310, "killed second shell blade in room before big key" }, + { 0x13, 0x04, 0x1304, "opened north gate in first west room 2F" }, + { 0x13, 0x02, 0x1302, "opened south gate in first west room 2F" }, + { 0x13, 0x01, 0x1301, "opened gates in mini-boss room" }, + { 0x14, 0x10, 0x1410, "explore main room" }, + { 0x14, 0x04, 0x1404, "main room intro cs" }, + { 0x14, 0x02, 0x1402, "south Hallway to Main room intro cs" }, + { 0x14, 0x01, 0x1401, "first room intro cs" }, + { 0x15, 0x20, 0x1520, "move staircase main room cs" }, + { 0x15, 0x08, 0x1508, "west water flowing into staircase main room cs" }, + { 0x15, 0x04, 0x1504, "east water flowing into staircase main room cs" }, + { 0x15, 0x02, 0x1502, "water in main room raised rwice cs" }, + { 0x15, 0x01, 0x1501, "west water is flowing into main room cs" }, + { 0x16, 0x80, 0x1680, "water in main room raised once cs" }, + { 0x16, 0x40, 0x1640, "east water is flowing into main room cs" }, + { 0x16, 0x20, 0x1620, "big key chest (set after)" }, + { 0x16, 0x10, 0x1610, "compass big chest second west room 4F (set after)" }, + { 0x16, 0x08, 0x1608, "bubble worm cs second east room 2F" }, + { 0x16, 0x01, 0x1601, "enter/exit mini-boss room from 1F door (spawns enemies in room before)" }, + { 0x17, 0x04, 0x1704, "killed right lizalfos in first west room 2F" }, + { 0x17, 0x02, 0x1702, "killed left lizalfos in first west room 2F" }, + { 0x17, 0x01, 0x1701, "killed lizalfos in first east room 2F" }, +}; + +inline EventAreaFlags eventAreaFlagsLHLC[] = +{ + { 0x02, 0x40, 0x0240, "big chest room 5 lake hylia long cave" }, + { 0x02, 0x20, 0x0220, "east big chest room 10 Lake Hylia Long Cave" }, + { 0x02, 0x10, 0x0210, "north small chest room 9 Lake Hylia Long Cave" }, + { 0x02, 0x08, 0x0208, "east small chest room 8 Lake Hylia Long Cave" }, + { 0x02, 0x04, 0x0204, "north small chest room 6 Lake hylia Long Cave" }, + { 0x02, 0x02, 0x0202, "south small chest room 7 Lake Hylia Long Cave" }, + { 0x02, 0x01, 0x0201, "north small chest room 5 Lake hylia Long Cave" }, + { 0x03, 0x80, 0x0380, "north small chest room 4 Lake Hylia Long Cave" }, + { 0x03, 0x40, 0x0340, "west small chest room 2 Lake hylia Long Cave" }, + { 0x03, 0x20, 0x0320, "west big chest room 7 Lake Hylia Long Cave" }, + { 0x03, 0x10, 0x0310, "north big chest room 8 Lake Hylia Long Cave" }, + { 0x03, 0x08, 0x0308, "big chest room 11 lake hylia long cave" }, + { 0x03, 0x04, 0x0304, "north small chest room 1 Lake hylia Long Cave" }, + { 0x03, 0x02, 0x0302, "west small chest room 1 Lake hylia Long Cave" }, + { 0x03, 0x01, 0x0301, "east small chest room 3 Lake Hylia Long Cave" }, + { 0x04, 0x80, 0x0480, "small chest Goron Stock Cave" }, + { 0x04, 0x40, 0x0440, "big chest in front of exit Goron Stock Cave" }, + { 0x04, 0x20, 0x0420, "big chest spawned form torches Goron Stock Cave" }, + { 0x08, 0x80, 0x0880, "explored section 18 Lake hylia Long Cave" }, + { 0x08, 0x40, 0x0840, "explored section 15 Lake hylia Long Cave" }, + { 0x08, 0x20, 0x0820, "explored section 12 Lake hylia Long Cave" }, + { 0x08, 0x10, 0x0810, "explored section 11 Lake hylia Long Cave" }, + { 0x08, 0x08, 0x0808, "explored section 9 Lake hylia Long Cave" }, + { 0x08, 0x04, 0x0804, "explored section 6 Lake hylia Long Cave" }, + { 0x08, 0x02, 0x0802, "explored section 4 Lake hylia Long Cave" }, + { 0x08, 0x01, 0x0801, "explored section 27 (room 11) Lake hylia Long Cave" }, + { 0x09, 0x80, 0x0980, "explored section 24 (room 10) Lake hylia Long Cave" }, + { 0x09, 0x40, 0x0940, "explored section 23 (room 9) Lake hylia Long Cave" }, + { 0x09, 0x20, 0x0920, "explored section 22 Lake hylia Long Cave" }, + { 0x09, 0x10, 0x0910, "explored east area room 8 Lake hylia Long Cave" }, + { 0x09, 0x08, 0x0908, "explored north area room 8 Lake hylia Long Cave" }, + { 0x09, 0x04, 0x0904, "explored section 21 (room 8) Lake hylia Long Cave" }, + { 0x09, 0x02, 0x0902, "explored section 17 Lake hylia Long Cave" }, + { 0x09, 0x01, 0x0901, "explored south area room 7 Lake hylia Long Cave" }, + { 0x0A, 0x80, 0x0A80, "explored west area room 7 Lake hylia Long Cave" }, + { 0x0A, 0x40, 0x0A40, "explored section 16 (room 7) Lake hylia Long Cave" }, + { 0x0A, 0x20, 0x0A20, "explored section 14 Lake hylia Long Cave" }, + { 0x0A, 0x10, 0x0A10, "explored north area room 6 Lake hylia Long Cave" }, + { 0x0A, 0x08, 0x0A08, "explored section 13 (room 6) Lake hylia Long Cave" }, + { 0x0A, 0x04, 0x0A04, "explored section 10 (room 5) Lake hylia Long Cave" }, + { 0x0A, 0x02, 0x0A02, "explored section 8 Lake hylia Long Cave" }, + { 0x0A, 0x01, 0x0A01, "explored north area room 4 Lake hylia Long Cave" }, + { 0x0B, 0x80, 0x0B80, "explored section 7 (room 4) Lake hylia Long Cave" }, + { 0x0B, 0x40, 0x0B40, "explored section 5 (room 3) Lake hylia Long Cave" }, + { 0x0B, 0x20, 0x0B20, "explored section 3 (room 2) Lake hylia Long Cave" }, + { 0x0B, 0x10, 0x0B10, "explored section 2 Lake hylia Long Cave" }, + { 0x0B, 0x08, 0x0B08, "explored north area room 1 Lake hylia Long Cave" }, + { 0x0B, 0x04, 0x0B04, "explored west area room 1 Lake hylia Long Cave" }, + { 0x0B, 0x02, 0x0B02, "explored section 1 (room 1) Lake hylia Long Cave" }, + { 0x0C, 0x80, 0x0C80, "blown up north rock room 7 Lake hylia long cave" }, + { 0x0C, 0x10, 0x0C10, "blown up north rock room 3 Lake hylia long cave" }, + { 0x0C, 0x04, 0x0C04, "blown up north rock room 4 Lake hylia long cave" }, + { 0x0C, 0x01, 0x0C01, "blown up south rock room 8 Lake hylia long cave" }, + { 0x0D, 0x40, 0x0D40, "blown up east rock room 6 Lake Hylia Long Cave" }, + { 0x0D, 0x20, 0x0D20, "blown up west rock room 6 Lake Hylia Long Cave" }, + { 0x0D, 0x04, 0x0D04, "blown up north rock room 5 Lake Hylia Long Cave" }, + { 0x0D, 0x02, 0x0D02, "blown up north rock room 9 Lake Hylia Long Cave" }, + { 0x0D, 0x01, 0x0D01, "blown up east rock room 3 Lake hylia long cave" }, + { 0x0E, 0x80, 0x0E80, "lit right torch room 5 lake hylia long cave" }, + { 0x0E, 0x40, 0x0E40, "lit left torch room 5 lake hylia long cave" }, + { 0x0E, 0x20, 0x0E20, "spawn big chest room 11 lake hylia long cave" }, + { 0x0E, 0x10, 0x0E10, "lit right torch room 11 Lake Hylia Long Cave" }, + { 0x0E, 0x08, 0x0E08, "lit left torch room 11 Lake Hylia Long Cave" }, + { 0x0E, 0x04, 0x0E04, "explored south area room 11 Lake hylia Long Cave" }, + { 0x0E, 0x02, 0x0E02, "explored east area room 10 Lake hylia Long Cave" }, + { 0x0E, 0x01, 0x0E01, "explored north area room 9 Lake hylia Long Cave" }, + { 0x0F, 0x80, 0x0F80, "explored east area room 6 Lake hylia Long Cave" }, + { 0x0F, 0x40, 0x0F40, "explored north area room 5 Lake hylia Long Cave" }, + { 0x0F, 0x20, 0x0F20, "explored east area room 3 Lake hylia Long Cave" }, + { 0x0F, 0x10, 0x0F10, "explored west area room 2 Lake hylia Long Cave" }, + { 0x0F, 0x08, 0x0F08, "explored section 25 Lake hylia Long Cave" }, + { 0x0F, 0x04, 0x0F04, "explored section 26 Lake hylia Long Cave" }, + { 0x0F, 0x02, 0x0F02, "explored section 20 Lake hylia Long Cave" }, + { 0x0F, 0x01, 0x0F01, "explored section 19 Lake hylia Long Cave" }, + { 0x10, 0x80, 0x1080, "killed poe in room 11 Lake Hylia Long Cave" }, + { 0x10, 0x40, 0x1040, "killed poe in room 3 Lake Hylia Long Cave" }, + { 0x10, 0x20, 0x1020, "killed poe in room 8 Lake Hylia Long Cave" }, + { 0x10, 0x04, 0x1004, "lit torch 9 (room 7) Lake hylia Long Cave" }, + { 0x10, 0x01, 0x1001, "lit torch 5 (room 4) Lake hylia Long Cave" }, + { 0x11, 0x40, 0x1140, "lit torch 3 (room 2) Lake hylia Long Cave" }, + { 0x11, 0x20, 0x1120, "lit torch 2 (room 1) Lake hylia Long Cave" }, + { 0x11, 0x08, 0x1108, "lit torch 12 (room 10) Lake hylia Long Cave" }, + { 0x11, 0x04, 0x1104, "lit torch 10 (room 8) Lake hylia Long Cave" }, + { 0x11, 0x02, 0x1102, "spawn big chest room 5 lake hylia long cave" }, + { 0x11, 0x01, 0x1101, "lit torch 4 (room 3) Lake hylia Long Cave" }, + { 0x12, 0x80, 0x1280, "blown up east rock room 9 Lake hylia long cave" }, + { 0x12, 0x40, 0x1240, "blown up west rock room 2 Lake hylia Long Cave" }, + { 0x12, 0x20, 0x1220, "blown up east rock room 2 Lake hylia Long Cave" }, + { 0x12, 0x10, 0x1210, "blown up north rock room 6 Lake hylia Long Cave" }, + { 0x12, 0x08, 0x1208, "blown up west rock room 5 Lake hylia Long Cave" }, + { 0x12, 0x04, 0x1204, "blown up east rock room 8 Lake Hylia Long Cave" }, + { 0x12, 0x02, 0x1202, "blown up east rock room 10 Lake Hylia Long Cave" }, + { 0x12, 0x01, 0x1201, "blown up north rock room 8 Lake hylia Long Cave" }, + { 0x13, 0x80, 0x1380, "blown up west rock room 7 Lake hylia Long Cave" }, + { 0x13, 0x40, 0x1340, "blown up south rock room 7 Lake hylia Long Cave" }, + { 0x13, 0x20, 0x1320, "blown up south rock room 10 Lake hylia Long Cave" }, + { 0x13, 0x10, 0x1310, "blown up west rock room 4 Lake hylia Long Cave" }, + { 0x13, 0x08, 0x1308, "blown up west rock room 1 Lake hylia Long Cave" }, + { 0x13, 0x04, 0x1304, "blown up north rock room 1 Lake hylia Long Cave" }, + { 0x13, 0x02, 0x1302, "blown up east rock room 1 Lake hylia Long Cave" }, + { 0x14, 0x80, 0x1480, "spawn big chest bottom floor Goron Stock Cave" }, + { 0x14, 0x40, 0x1440, "lit right torch bottom floor Goron Stock Cave" }, + { 0x14, 0x20, 0x1420, "lit left torch bottom floor Goron Stock Cave" }, +}; + +inline EventAreaFlags eventAreaFlagsOrdon[] = +{ + { 0x03, 0x10, 0x0310, "wooden sword big chest" }, + { 0x03, 0x04, 0x0304, "iron boots big chest" }, + { 0x03, 0x02, 0x0302, "Big chest link's basement" }, + { 0x08, 0x80, 0x0880, "despawn Bo and Jaggle after scaring them away (wolf night)" }, + { 0x08, 0x40, 0x0840, "scare away Bo and Jaggle after hearing them (wolf night)" }, + { 0x08, 0x20, 0x0820, "started sword training" }, + { 0x08, 0x10, 0x0810, "obtained wooden sword" }, + { 0x08, 0x08, 0x0808, "midna text after getting ordon shield (spawns sword)" }, + { 0x08, 0x04, 0x0804, "got ordon shield (will despawn it if set)" }, + { 0x08, 0x02, 0x0802, "midna text after getting ordon sword" }, + { 0x08, 0x01, 0x0801, "got ordon sword" }, + { 0x09, 0x80, 0x0980, "exit shield house as wolf cs" }, + { 0x09, 0x40, 0x0940, "Goats 2" }, + { 0x09, 0x20, 0x0920, "day 3 intro cs (spawn in ranch)" }, + { 0x09, 0x08, 0x0908, "knocked down bee's nest day 2 cs" }, + { 0x09, 0x04, 0x0904, "? (wolf in village night)" }, + { 0x09, 0x02, 0x0902, "Ranch first time CS" }, + { 0x0A, 0x80, 0x0A80, "Rusl moving during wolf night" }, + { 0x0A, 0x40, 0x0A40, "killed spider on top of Link's house" }, + { 0x0A, 0x20, 0x0A20, "spawn 2 spiders around Link,s house (day 2) (set after buying slingshot)" }, + { 0x0A, 0x10, 0x0A10, "Ilia spring CS watched" }, + { 0x0A, 0x08, 0x0A08, "Ilia spring CS started" }, + { 0x0A, 0x04, 0x0A04, "Ordon Village first time CS" }, + { 0x0A, 0x02, 0x0A02, "Ilia spring CS Trigger" }, + { 0x0A, 0x01, 0x0A01, "killed spider on ladder to link's house" }, + { 0x0B, 0x80, 0x0B80, "Epona being in spring" }, + { 0x0B, 0x20, 0x0B20, "finished slingshot training" }, + { 0x0B, 0x10, 0x0B10, "Entered spring Area first time" }, + { 0x0B, 0x08, 0x0B08, "Intro CS watched" }, + { 0x0B, 0x02, 0x0B02, "finished sword training" }, + { 0x0C, 0x80, 0x0C80, "killed bulblin ordon woods" }, + { 0x0C, 0x40, 0x0C40, "killed second bulblin Link's house" }, + { 0x0C, 0x20, 0x0C20, "killed first bulblin Link's house" }, + { 0x0C, 0x10, 0x0C10, "spawn wooden sword big chest" }, + { 0x0C, 0x08, 0x0C08, "Day 2 intro CS" }, + { 0x0C, 0x04, 0x0C04, "talked to owl as wolf for the first time" }, + { 0x0C, 0x02, 0x0C02, "Goats 1" }, + { 0x0C, 0x01, 0x0C01, "set after getting ordon shield" }, + { 0x0D, 0x80, 0x0D80, "approach faron twilight to enter it with midna cs" }, + { 0x0D, 0x20, 0x0D20, "spawn shadow beast" }, + { 0x0D, 0x10, 0x0D10, "Ordon Spring Portal" }, + { 0x0D, 0x08, 0x0D08, "hear Bo and Jaggle talk about shield from far away (wolf night)" }, + { 0x0D, 0x02, 0x0D02, "entered shield house as wolf cs" }, + { 0x0D, 0x01, 0x0D01, "ordon shield fell down cs" }, + { 0x0E, 0x80, 0x0E80, "midna text leaving spring" }, + { 0x0E, 0x20, 0x0E20, "started midna jump to ordon shield inside house" }, + { 0x0E, 0x08, 0x0E08, "Hanch started attacking (unlocks midna jump to top of shop)" }, + { 0x0E, 0x04, 0x0E04, "midna cs after hearing Bo and Jaggle talk about shield" }, + { 0x0E, 0x02, 0x0E02, "day 3 Fado intro text" }, + { 0x0F, 0x80, 0x0F80, "Allows Link to stop goat in Village" }, + { 0x0F, 0x20, 0x0F20, "started midna jumps to top of shop" }, + { 0x0F, 0x08, 0x0F08, "midna text before doing jumps to top of shop" }, + { 0x0F, 0x04, 0x0F04, "Rusl talking to his wife cs (wolf night)" }, + { 0x0F, 0x02, 0x0F02, "unlock midna jumps to shield house" }, + { 0x0F, 0x01, 0x0F01, "scared Hanch" }, + { 0x12, 0x02, 0x1202, "torch next to Hanch is lit (wolf night)" }, + { 0x12, 0x01, 0x1201, "? (wolf in village night)" }, + { 0x13, 0x80, 0x1380, "iron boots big chest (duplicate)" }, + { 0x13, 0x40, 0x1340, "spawn iron boots chest in Bo's house" }, + { 0x13, 0x20, 0x1320, "brigthen up area under Hanch after getting spoted" }, + { 0x13, 0x10, 0x1310, "set after midna text after getting ordon shield" }, + { 0x13, 0x08, 0x1308, "Hanch spoted you cs (wolf night)" }, + { 0x13, 0x04, 0x1304, "randomly set during wolf night (often during Hanch part)" }, + { 0x13, 0x02, 0x1302, "Hero's shade map marker" }, + { 0x13, 0x01, 0x1301, "Ordon day 1 (save promt)" }, + { 0x14, 0x80, 0x1480, "set after midna text after getting ordon sword" }, + { 0x14, 0x01, 0x1401, "Jump to eagle grass next to Jaggle day 2 (removes Jaggle text)" }, + { 0x15, 0x10, 0x1510, "did midna jumps to top of shop" }, + { 0x16, 0x01, 0x1601, "King Bulblin cs" }, + { 0x17, 0x80, 0x1780, "enter village as wolf intro cs" }, + { 0x17, 0x20, 0x1720, "explored area with link's house (wolf)" }, + { 0x19, 0x80, 0x1980, "picked up yellow rupee on top of Hanch's house" }, + { 0x19, 0x40, 0x1940, "picked up green rupee in grass in front of Bo's house" }, + { 0x19, 0x20, 0x1920, "picked up green rupees in pond next to Rusl's house (day 2)" }, + { 0x19, 0x10, 0x1910, "picked up purple rupee behind Jaggle's house" }, + { 0x19, 0x01, 0x1901, "picked up green rupee in the back of the grass to the right of Link's house" }, + { 0x1A, 0x80, 0x1A80, "picked up green rupee in grass right of gate to village " }, + { 0x1A, 0x40, 0x1A40, "picked up green rupee next to rock in the grass to the right of Link's house" }, + { 0x1A, 0x20, 0x1A20, "picked up green rupee in grass to the right of Link's house" }, + { 0x1A, 0x10, 0x1A10, "picked up first green rupee in crawl space" }, + { 0x1A, 0x08, 0x1A08, "picked up yellow rupee on top of Bo's house" }, + { 0x1A, 0x02, 0x1A02, "picked up blue rupee on top of Hanch's house" }, + { 0x1A, 0x01, 0x1A01, "Picked up Orange Rupee by Rusl's house" }, + { 0x1B, 0x80, 0x1B80, "picked up green rupees on top of Hanch's house (day 2)" }, + { 0x1B, 0x40, 0x1B40, "picked up green rupees on top of Bo's house (day 2)" }, + { 0x1B, 0x08, 0x1B08, "Picked up Ordon Sword" }, + { 0x1B, 0x04, 0x1B04, "picked up green rupee under bridge (day 2)" }, + { 0x1B, 0x02, 0x1B02, "picked up yellow rupees on top of Rusl's house" }, + { 0x1B, 0x01, 0x1B01, "picked up yellow rupee on cliff next to Bo's house" }, +}; + +inline EventAreaFlags eventAreaFlagsPoT[] = +{ + { 0x00, 0x40, 0x0040, "PoH hidden big chest west room 1" }, + { 0x00, 0x20, 0x0020, "north west small chest east room 2" }, + { 0x00, 0x10, 0x0010, "north east small chest east room 2" }, + { 0x00, 0x08, 0x0008, "west small chest east room 1" }, + { 0x00, 0x04, 0x0004, "small key big chest north room 3" }, + { 0x00, 0x02, 0x0002, "south higher big chest west room 2" }, + { 0x00, 0x01, 0x0001, "small key big chest north room 2" }, + { 0x01, 0x80, 0x0180, "big key chest" }, + { 0x01, 0x40, 0x0140, "small key big chest north room 1" }, + { 0x02, 0x08, 0x0208, "placed west sol" }, + { 0x02, 0x04, 0x0204, "placed east sol" }, + { 0x03, 0x80, 0x0380, "small key east big chest east room 2" }, + { 0x03, 0x40, 0x0340, "small key north east big chest east room 1" }, + { 0x03, 0x20, 0x0320, "small key north big chest west room 2" }, + { 0x03, 0x10, 0x0310, "small key big chest west room 1" }, + { 0x03, 0x08, 0x0308, "compass lower south big chest west room 2" }, + { 0x03, 0x01, 0x0301, "PoH east big chest east room 1" }, + { 0x07, 0x10, 0x0710, "north west small chest east room 1" }, + { 0x07, 0x02, 0x0702, "map west big chest east room 2" }, + { 0x08, 0x10, 0x0810, "spawn south fence in east room 3" }, + { 0x08, 0x08, 0x0808, "spawn north fence in east room 3" }, + { 0x08, 0x04, 0x0804, "spawn south fence in west room 3" }, + { 0x08, 0x02, 0x0802, "spawn north fence in west room 3" }, + { 0x09, 0x80, 0x0980, "spawn in main room from midna warp" }, + { 0x09, 0x40, 0x0940, "save prompt after boss" }, + { 0x09, 0x20, 0x0920, "killed east phantom Zant (unlocks door)" }, + { 0x09, 0x10, 0x0910, "killed west phantom Zant (unlocks door)" }, + { 0x09, 0x04, 0x0904, "Phantom Zant 1 CS" }, + { 0x09, 0x02, 0x0902, "?" }, + { 0x09, 0x01, 0x0901, "?" }, + { 0x0A, 0x40, 0x0A40, "killed all Zant heads in east room 2 (spawn big chest)" }, + { 0x0A, 0x20, 0x0A20, "killed Zant head in east room 1 (spawn chest)" }, + { 0x0A, 0x10, 0x0A10, "killed Zant head in west room 2 (spawn 2 big chests)" }, + { 0x0A, 0x08, 0x0A08, "killed Zant head in west room 1 (spawn chest)" }, + { 0x0A, 0x02, 0x0A02, "unlock boss door" }, + { 0x0A, 0x01, 0x0A01, "unlock door in north room 3" }, + { 0x0B, 0x80, 0x0B80, "unlock door in east room 2" }, + { 0x0B, 0x40, 0x0B40, "unlock door in west room 2" }, + { 0x0B, 0x02, 0x0B02, "intro cs" }, + { 0x0B, 0x01, 0x0B01, "?" }, + { 0x0C, 0x80, 0x0C80, "get light master sword cs" }, + { 0x0C, 0x40, 0x0C40, "? (main room)" }, + { 0x0C, 0x20, 0x0C20, "? (main room)" }, + { 0x0C, 0x10, 0x0C10, "Watched CS of platform to east wing being activated" }, + { 0x0C, 0x08, 0x0C08, "Platform to east wing is active" }, + { 0x0C, 0x04, 0x0C04, "Midna text when west sol is placed" }, + { 0x0C, 0x02, 0x0C02, "Midna text when west hand steals sol" }, + { 0x0D, 0x80, 0x0D80, "killed south west Zant head in east room 2" }, + { 0x0D, 0x40, 0x0D40, "killed south east Zant head in east room 2" }, + { 0x0D, 0x20, 0x0D20, "killed center Zant head in east room 2" }, + { 0x0D, 0x10, 0x0D10, "killed first Zant head in east room 2" }, + { 0x0D, 0x08, 0x0D08, "unlock door in north room 2" }, + { 0x0D, 0x04, 0x0D04, "killed dark beasts in north room 3" }, + { 0x0D, 0x02, 0x0D02, "crossed black fog waterfall main room" }, + { 0x0D, 0x01, 0x0D01, "midna text black fog west room 1" }, + { 0x0E, 0x80, 0x0E80, "Midna text finding west sol" }, + { 0x0E, 0x40, 0x0E40, "midna text black fog waterfall main room" }, + { 0x0E, 0x20, 0x0E20, "midna text when seeing a civilian seen" }, + { 0x0E, 0x10, 0x0E10, "midna text after warping back to main room after boss" }, + { 0x0E, 0x02, 0x0E02, "killed second Zant head in north room 3 (spawn big chest)" }, + { 0x0E, 0x01, 0x0E01, "killed first Zant head in north room 3 (spawn head 2)" }, + { 0x0F, 0x80, 0x0F80, "midna text promt when seeing a civilian" }, + { 0x0F, 0x40, 0x0F40, "midna text after light master sword" }, + { 0x0F, 0x20, 0x0F20, "unlock door in north room 1" }, + { 0x0F, 0x10, 0x0F10, "unlock door in east room 1" }, + { 0x0F, 0x08, 0x0F08, "unlock door in west room 1" }, + { 0x10, 0x80, 0x1080, "killed south Zant head in north room 1 (wave 1)" }, + { 0x10, 0x40, 0x1040, "killed center Zant head in north room 1 (wave 1)" }, + { 0x10, 0x20, 0x1020, "killed north west Zant head in north room 1 (wave 1)" }, + { 0x10, 0x10, 0x1010, "killed north east Zant head in north room 1 (wave 1)" }, + { 0x10, 0x08, 0x1008, "?" }, + { 0x10, 0x04, 0x1004, "?" }, + { 0x10, 0x01, 0x1001, "? (main room)" }, + { 0x11, 0x80, 0x1180, "Heal Twili citizen outside west wing" }, + { 0x11, 0x40, 0x1140, "? (main room)" }, + { 0x11, 0x20, 0x1120, "Heal Twili near PoT entrance" }, + { 0x11, 0x10, 0x1110, "Heal Twili citizen outside east wing" }, + { 0x11, 0x08, 0x1108, "Heal Twili citizen next to west sol" }, + { 0x11, 0x04, 0x1104, "Heal Twili citizen next to east sol" }, + { 0x11, 0x02, 0x1102, "Heal Twili citizen north of Light Sword" }, + { 0x11, 0x01, 0x1101, "Heal Twili citizen near fog waterfall" }, + { 0x12, 0x08, 0x1208, "Opened Big Key Chest (causes fence to fall in room before Zant)" }, + { 0x12, 0x04, 0x1204, "Midna text after re-entering west wing after sol stolen" }, + { 0x12, 0x02, 0x1202, "remove fog in north room 4" }, + { 0x13, 0x40, 0x1340, "remove fog and spawn stairs in north room 1" }, + { 0x13, 0x20, 0x1320, "placed east sol in north room 1" }, + { 0x13, 0x10, 0x1310, "placed west sol in north room 1" }, + { 0x13, 0x02, 0x1302, "midna intro text" }, + { 0x15, 0x40, 0x1540, "killed all wave 4 Zant heads in north room 2 (spawn big chest)" }, + { 0x15, 0x20, 0x1520, "killed east Zant head north room 2 (wave 4)" }, + { 0x15, 0x10, 0x1510, "killed west Zant head north room 2 (wave 4)" }, + { 0x15, 0x08, 0x1508, "killed Zant head wave 3 in north room 2 (spawn wave 4)" }, + { 0x15, 0x04, 0x1504, "killed all wave 2 Zant heads in north room 2 (spawn wave 3)" }, + { 0x15, 0x02, 0x1502, "killed west Zant head north room 2 (wave 2)" }, + { 0x15, 0x01, 0x1501, "killed east Zant head north room 2 (wave 2)" }, + { 0x16, 0x80, 0x1680, "killed middle Zant head north room 2 (wave 2)" }, + { 0x16, 0x40, 0x1640, "killed first Zant head north room 2 (spawn wave 2)" }, + { 0x16, 0x10, 0x1610, "Watched east wing second room stairs CS" }, + { 0x16, 0x01, 0x1601, "?" }, + { 0x17, 0x80, 0x1780, "?" }, + { 0x17, 0x40, 0x1740, "killed dark beasts in east room 2" }, + { 0x17, 0x20, 0x1720, "spawn fog in east room 3" }, + { 0x17, 0x10, 0x1710, "spawn fog in west room 3" }, + { 0x17, 0x08, 0x1708, "killed all wave 2 Zant heads in north room 1 (spawn big chest)" }, + { 0x17, 0x04, 0x1704, "killed north west Zant head north room 1 (wave 2)" }, + { 0x17, 0x02, 0x1702, "killed north east Zant head north room 1 (wave 2)" }, + { 0x17, 0x01, 0x1701, "killed all wave 1 Zant heads in north room 1 (spawn wave 2)" }, + { 0x1B, 0x01, 0x1B01, "heart container" }, +}; + +inline EventAreaFlags eventAreaFlagsSacredGrove[] = +{ + { 0x03, 0x08, 0x0308, "Big chest lost woods 2 torches" }, + { 0x03, 0x04, 0x0304, "Big chest spinner in skull kid wolf battle area" }, + { 0x03, 0x02, 0x0302, "PoH big chest temple of time (past)" }, + { 0x08, 0x80, 0x0880, "lit left torch chest lost woods" }, + { 0x08, 0x40, 0x0840, "killed poe temple of time (past)" }, + { 0x08, 0x20, 0x0820, "midna text after pushing block human" }, + { 0x08, 0x10, 0x0810, "cs after pushing block human" }, + { 0x08, 0x08, 0x0808, "intro cs lost woods" }, + { 0x08, 0x02, 0x0802, "?" }, + { 0x08, 0x01, 0x0801, "?" }, + { 0x09, 0x80, 0x0980, "explored section after window before dungeon (includes map marker for dungeon)" }, + { 0x09, 0x40, 0x0940, "stairs to temple of time area near (dungeon)" }, + { 0x09, 0x20, 0x0920, "strike MS into pedestal in past" }, + { 0x09, 0x10, 0x0910, "window and stairs to dungeon work properly" }, + { 0x09, 0x02, 0x0902, "killed poe lost woods water" }, + { 0x09, 0x01, 0x0901, "killed poe in skull kid wolf battle area" }, + { 0x0A, 0x80, 0x0A80, "killed poe in master sword area (present)" }, + { 0x0A, 0x10, 0x0A10, "skull kid wolf battle area explored" }, + { 0x0B, 0x80, 0x0B80, "temple of time (present) main room explored" }, + { 0x0B, 0x40, 0x0B40, "temple of time (past) main room explored" }, + { 0x0B, 0x20, 0x0B20, "blown up rock in skull kid wolf battle area" }, + { 0x0B, 0x10, 0x0B10, "block pushed human" }, + { 0x0B, 0x04, 0x0B04, "Master Sword Puzzle Complete" }, + { 0x0B, 0x02, 0x0B02, "Master sword area explored" }, + { 0x0B, 0x01, 0x0B01, "Temple of time (present) human entrence explored" }, + { 0x0F, 0x02, 0x0F02, "spawn big chest lost woods 2 torches" }, + { 0x0F, 0x01, 0x0F01, "lit right torch chest lost woods" }, + { 0x16, 0x20, 0x1620, "Master Sword Pulled (does not despawn)" }, + { 0x16, 0x10, 0x1610, "Blocks entrance to Woods (auto-set upon re-entering Grove before Skull Kid 2" }, + { 0x16, 0x08, 0x1608, "Lost woods skull kid human chase (unset once done)" }, + { 0x16, 0x02, 0x1602, "skull kid human defeated" }, + { 0x16, 0x01, 0x1601, "lost woods turns to day after skull kid fight human" }, + { 0x17, 0x80, 0x1780, "Skull Kid Appears (set automatically)" }, + { 0x17, 0x40, 0x1740, "Transition to day after Skull Kid" }, + { 0x17, 0x20, 0x1720, "dark beasts spawned" }, + { 0x17, 0x10, 0x1710, "Sacred Grove Portal (removes statue blocking door of time (to past)" }, + { 0x17, 0x08, 0x1708, "Randomizer: remove statue to past" }, +}; + +inline EventAreaFlags eventAreaFlagsSewer[] = +{ + { 0x00, 0x80, 0x0080, "0" }, + { 0x00, 0x40, 0x0040, "1" }, + { 0x00, 0x20, 0x0020, "2" }, + { 0x00, 0x10, 0x0010, "3" }, + { 0x00, 0x08, 0x0008, "4" }, + { 0x00, 0x04, 0x0004, "5" }, + { 0x00, 0x02, 0x0002, "6" }, + { 0x00, 0x01, 0x0001, "7" }, + { 0x01, 0x80, 0x0180, "8" }, + { 0x01, 0x40, 0x0140, "9" }, + { 0x01, 0x20, 0x0120, "10" }, + { 0x01, 0x10, 0x0110, "11" }, + { 0x01, 0x08, 0x0108, "12" }, + { 0x01, 0x04, 0x0104, "13" }, + { 0x01, 0x02, 0x0102, "14" }, + { 0x01, 0x01, 0x0101, "15" }, + { 0x02, 0x80, 0x0280, "16" }, + { 0x02, 0x40, 0x0240, "17" }, + { 0x02, 0x20, 0x0220, "18" }, + { 0x02, 0x10, 0x0210, "19" }, + { 0x02, 0x08, 0x0208, "20" }, + { 0x08, 0x80, 0x0880, "twilight final cs" }, + { 0x08, 0x40, 0x0840, "Zelda cs twilight" }, + { 0x08, 0x20, 0x0820, "midna text after first gate sewers (how to fight)" }, + { 0x08, 0x10, 0x0810, "midna text after exiting to rooftops (twilight)" }, + { 0x08, 0x08, 0x0808, "wake up in jail cs" }, + { 0x08, 0x04, 0x0804, "midna promt to use sense to see gard (entrance to sewers)" }, + { 0x08, 0x02, 0x0802, "pushed box outside (MDH)" }, + { 0x08, 0x01, 0x0801, "pulled lever of first water gate in sewers" }, + { 0x09, 0x80, 0x0980, "dug up blue rupee after crawl space (sewers) (twilight)" }, + { 0x09, 0x40, 0x0940, "second water gate in sewers cs (unset afterwards)" }, + { 0x09, 0x20, 0x0920, "first water gate in sewers cs (unset afterwards)" }, + { 0x09, 0x10, 0x0910, "midna cs after diging out of jail" }, + { 0x09, 0x08, 0x0908, "midna intro cs" }, + { 0x09, 0x04, 0x0904, "waited long enough in jail" }, + { 0x09, 0x02, 0x0902, "broke fragile floor first jump of stairway (unlocks first midna jump)" }, + { 0x09, 0x01, 0x0901, "started midna jumps 3 stairway" }, + { 0x0A, 0x80, 0x0A80, "started midna jumps 2 stairway" }, + { 0x0A, 0x40, 0x0A40, "zelda tower intro cs" }, + { 0x0A, 0x20, 0x0A20, "midna went to the other side of the fence in sewers" }, + { 0x0A, 0x10, 0x0A10, "started midna jumps on rooftops" }, + { 0x0A, 0x08, 0x0A08, "started midna jumps 4 stairway (top to door)" }, + { 0x0A, 0x04, 0x0A04, "broke box inside Link's cell" }, + { 0x0A, 0x02, 0x0A02, "did midna jumps 1 stairway (broke small platform)" }, + { 0x0A, 0x01, 0x0A01, "outside top door intro cs" }, + { 0x0B, 0x80, 0x0B80, "broke fire in Zelda's room" }, + { 0x0B, 0x40, 0x0B40, "midna rejoinded link after crawl space" }, + { 0x0B, 0x20, 0x0B20, "went to the other side of the fence in sewers cs" }, + { 0x0B, 0x10, 0x0B10, "top of stairway intro cs" }, + { 0x0B, 0x08, 0x0B08, "stairway intro cs" }, + { 0x0B, 0x04, 0x0B04, "read midna promt to open door" }, + { 0x0B, 0x02, 0x0B02, "opened door in cell next to Link's" }, + { 0x0B, 0x01, 0x0B01, "dug out of Link's cell" }, + { 0x0D, 0x80, 0x0D80, "killed first bulblin outside (MDH)" }, + { 0x0D, 0x20, 0x0D20, "killed second bulblin outside (MDH)" }, + { 0x0D, 0x04, 0x0D04, "killed bulblin at top of stairway (on the patform) (MDH)" }, + { 0x0E, 0x80, 0x0E80, "killed fourth bulblin in stairway (MDH)" }, + { 0x0E, 0x20, 0x0E20, "killed third bulblin in stairway (MDH)" }, + { 0x0E, 0x04, 0x0E04, "killed second bulblin in stairway (MDH)" }, + { 0x0E, 0x02, 0x0E02, "killed first bulblin in stairway (MDH)" }, + { 0x0F, 0x20, 0x0F20, "talked to midna after using sense on first rooftop gard" }, + { 0x0F, 0x10, 0x0F10, "midna text when approching first rooftop gard" }, + { 0x0F, 0x08, 0x0F08, "listened to first gard in sewers" }, + { 0x0F, 0x04, 0x0F04, "saw first rooftop gard with sense" }, + { 0x0F, 0x02, 0x0F02, "saw first gard in sewers" }, + { 0x0F, 0x01, 0x0F01, "midna cs after diging out of jail" }, + { 0x1B, 0x08, 0x1B08, "picked up green rupee in box in secret passge next to fence (sewers) (twilight)" }, + { 0x1B, 0x04, 0x1B04, "picked up blue rupee in box in left secret way (sewers) (twilight)" }, + { 0x1B, 0x02, 0x1B02, "picked up purple rupee in boxes (first windy bridge) (MDH)" }, + { 0x1B, 0x01, 0x1B01, "picked up yellow rupee in Zelda's fire" }, +}; + +inline EventAreaFlags eventAreaFlagsSnowpeak[] = +{ + { 0x03, 0x01, 0x0301, "Big chest transition cave" }, + { 0x08, 0x40, 0x0840, "montain top explored" }, + { 0x08, 0x20, 0x0820, "Map marker Ashei" }, + { 0x08, 0x04, 0x0804, "montain top cs (pan towards tree)" }, + { 0x08, 0x02, 0x0802, "Post SPR Save Prompt" }, + { 0x09, 0x80, 0x0980, "?" }, + { 0x09, 0x40, 0x0940, "?" }, + { 0x09, 0x20, 0x0920, "Snowpeak top portal" }, + { 0x0B, 0x08, 0x0B08, "explored second section up montain" }, + { 0x0B, 0x04, 0x0B04, "explored first section up montain" }, + { 0x0B, 0x02, 0x0B02, "Midna text in front of SPR" }, + { 0x0B, 0x01, 0x0B01, "intro cs" }, + { 0x0D, 0x10, 0x0D10, "spawn big chest transition cave" }, + { 0x0D, 0x08, 0x0D08, "lit left torch transition cave" }, + { 0x0D, 0x04, 0x0D04, "lit right torch transition cave" }, + { 0x0F, 0x08, 0x0F08, "snow fell down next to howling stone" }, + { 0x14, 0x80, 0x1480, "killed poe transition cave" }, + { 0x14, 0x40, 0x1440, "killed poe next to snowpeak ruins" }, + { 0x14, 0x20, 0x1420, "killed first poe up the montain" }, + { 0x14, 0x10, 0x1410, "killed second poe next to lone tree on cliff" }, + { 0x14, 0x08, 0x1408, "killed third poe near 2 trees before howling stone" }, +}; + +inline EventAreaFlags eventAreaFlagsSPR[] = +{ + { 0x00, 0x02, 0x0002, "PoH big chest under broken ceiling" }, + { 0x01, 0x80, 0x0180, "left small chest behind armor in first room" }, + { 0x01, 0x40, 0x0140, "right small chest behind armor in first room" }, + { 0x01, 0x20, 0x0120, "PoH big chest in first room 2F" }, + { 0x01, 0x10, 0x0110, "west small chest behind ice in north west room" }, + { 0x01, 0x08, 0x0108, "east small chest behind ice in north west room" }, + { 0x01, 0x04, 0x0104, "small key small chest pumpkin room" }, + { 0x01, 0x01, 0x0101, "Ooccoo" }, + { 0x02, 0x80, 0x0280, "south east small chest in courtyard" }, + { 0x02, 0x40, 0x0240, "small key buried east small chest in courtyard" }, + { 0x02, 0x20, 0x0220, "small key buried west small chest in courtyard" }, + { 0x02, 0x08, 0x0208, "big key chest" }, + { 0x02, 0x04, 0x0204, "pumpkin big chest" }, + { 0x03, 0x80, 0x0380, "small key big chest in compass room 2F" }, + { 0x03, 0x40, 0x0340, "cheese big chest" }, + { 0x03, 0x08, 0x0308, "south small chest behind ice in courtyard" }, + { 0x03, 0x04, 0x0304, "compass big chest" }, + { 0x03, 0x02, 0x0302, "small chest compass room 1F" }, + //{ 0x08, 0x80, 0x0880, "position of second block in ice puzzle room" }, + //{ 0x08, 0x40, 0x0840, "position of second block in ice puzzle room" }, + //{ 0x08, 0x20, 0x0820, "position of second block in ice puzzle room" }, + //{ 0x08, 0x10, 0x0810, "position of second block in ice puzzle room" }, + //{ 0x08, 0x08, 0x0808, "position of second block in ice puzzle room" }, + //{ 0x08, 0x04, 0x0804, "position of third block in ice puzzle room (frozen one)" }, + //{ 0x08, 0x02, 0x0802, "position of third block in ice puzzle room (frozen one)" }, + //{ 0x08, 0x01, 0x0801, "position of third block in ice puzzle room (frozen one)" }, + //{ 0x09, 0x80, 0x0980, "position of third block in ice puzzle room (frozen one)" }, + //{ 0x09, 0x40, 0x0940, "position of third block in ice puzzle room (frozen one)" }, + { 0x09, 0x20, 0x0920, "killed poe in armor in first room" }, + { 0x09, 0x08, 0x0908, "unlock west living room door" }, + { 0x09, 0x04, 0x0904, "unlock north living room door" }, + { 0x09, 0x02, 0x0902, "lowered ball transport (west hallway-freezard)" }, + { 0x09, 0x01, 0x0901, "lowered ball transport (courtyard 2F)" }, + { 0x0A, 0x80, 0x0A80, "dug first time west buried small chest in courtyard" }, + { 0x0A, 0x40, 0x0A40, "lowered ball transport (west hallway-courtyard)" }, + { 0x0A, 0x20, 0x0A20, "dug second time west buried small chest in courtyard" }, + { 0x0A, 0x10, 0x0A10, "talked to Yeta for the first time (gives map)" }, + { 0x0A, 0x04, 0x0A04, "destroyed ice in courtyard 2F" }, + { 0x0A, 0x02, 0x0A02, "Yeta enters bedroom cs (in courtyard)" }, + { 0x0A, 0x01, 0x0A01, "unlock bedroom door" }, + { 0x0B, 0x80, 0x0B80, "enter courtyard" }, + { 0x0B, 0x20, 0x0B20, "compass big chest (set after)" }, + { 0x0B, 0x10, 0x0B10, "broke ice in pumpkin room 2F" }, + { 0x0B, 0x08, 0x0B08, "dug up east small chest in courtyard" }, + { 0x0B, 0x04, 0x0B04, "open west door 2F in ice puzzle room" }, + { 0x0B, 0x02, 0x0B02, "open west door 1F in ice puzzle room" }, + { 0x0C, 0x80, 0x0C80, "destroyed first left armor in first room" }, + { 0x0C, 0x40, 0x0C40, "destroyed second left armor in first room" }, + { 0x0C, 0x20, 0x0C20, "destroyed third left armor in first room" }, + //{ 0x0C, 0x08, 0x0C08, "canon in north west room orientation" }, + //{ 0x0C, 0x04, 0x0C04, "canon in north west room orientation" }, + { 0x0C, 0x02, 0x0C02, "killed freezard in courtyard 1F" }, + { 0x0C, 0x01, 0x0C01, "explored compass room" }, + { 0x0D, 0x80, 0x0D80, "killed first freezard in cage" }, + { 0x0D, 0x40, 0x0D40, "killed freezard in courtyard 2F" }, + { 0x0D, 0x20, 0x0D20, "killed west freezard in room above livng room (2F)" }, + { 0x0D, 0x10, 0x0D10, "killed north freezard in room above livng room (2F)" }, + { 0x0D, 0x08, 0x0D08, "broke ice in first room 2F" }, + { 0x0D, 0x04, 0x0D04, "destroyed ice on block in ice puzzle room" }, + { 0x0D, 0x01, 0x0D01, "unlock door in south east room 2F" }, + { 0x0E, 0x80, 0x0E80, "unlocked door to first room in freezard cage room" }, + { 0x0E, 0x20, 0x0E20, "unlock doors in room before pumpkin" }, + { 0x0E, 0x10, 0x0E10, "unlock door in east outside hallway" }, + { 0x0E, 0x08, 0x0E08, "unlock west door in courtyard" }, + { 0x0E, 0x04, 0x0E04, "explored courtyard 1F" }, + { 0x0E, 0x02, 0x0E02, "explored room above ice puzzle (2F)" }, + { 0x0E, 0x01, 0x0E01, "explored room above pumpkin (2F)" }, + { 0x0F, 0x80, 0x0F80, "puched left block in room above living room (2F)" }, + { 0x0F, 0x40, 0x0F40, "puched right block in room above living room (2F)" }, + { 0x0F, 0x20, 0x0F20, "2nd floor block pushed down in ice puzzle room" }, + //{ 0x0F, 0x10, 0x0F10, "position of first block in ice puzzle room" }, + //{ 0x0F, 0x08, 0x0F08, "position of first block in ice puzzle room" }, + //{ 0x0F, 0x04, 0x0F04, "position of first block in ice puzzle room" }, + //{ 0x0F, 0x02, 0x0F02, "position of first block in ice puzzle room" }, + //{ 0x0F, 0x01, 0x0F01, "position of first block in ice puzzle room" }, + { 0x10, 0x80, 0x1080, "Picked up B&C" }, + { 0x10, 0x40, 0x1040, "?" }, + { 0x10, 0x20, 0x1020, "Yeta lets you open door to kitchen" }, + { 0x10, 0x10, 0x1010, "north west room 1F intro cs" }, + { 0x10, 0x08, 0x1008, "Midna big key text prompt" }, + { 0x10, 0x02, 0x1002, "pumpkin room ambush cs trigger" }, + //{ 0x10, 0x01, 0x1001, "courtyard 2F canon orientation" }, + //{ 0x11, 0x80, 0x1180, "courtyard 2F canon orientation" }, + //{ 0x11, 0x40, 0x1140, "courtyard 1F canon orientation" }, + //{ 0x11, 0x20, 0x1120, "courtyard 1F canon orientation" }, + { 0x11, 0x02, 0x1102, "unlock mini-boss doors" }, + { 0x11, 0x01, 0x1101, "pushed block in west outside hallway" }, + { 0x12, 0x40, 0x1240, "unlock doors in pumpkin room" }, + { 0x12, 0x20, 0x1220, "explored path to bedroom 2F & 3F" }, + { 0x12, 0x10, 0x1210, "killed second freezard in cage" }, + { 0x12, 0x08, 0x1208, "explored west outside hallway 2F (canon)" }, + { 0x12, 0x04, 0x1204, "unlock door to big key in big key room" }, + //{ 0x12, 0x02, 0x1202, "freezard cage canon orientation" }, + //{ 0x12, 0x01, 0x1201, "freezard cage canon orientation" }, + { 0x13, 0x40, 0x1340, "killed chilfos in pumpkin room (unlock south door)" }, + { 0x13, 0x20, 0x1320, "?" }, + { 0x13, 0x10, 0x1310, "killed chilfos in big key room" }, + { 0x13, 0x08, 0x1308, "broke center ice in Ice puzzle room" }, + { 0x13, 0x04, 0x1304, "broke first right armor in first room" }, + { 0x13, 0x02, 0x1302, "broke second right armor in first room (spawns poe)" }, + { 0x13, 0x01, 0x1301, "broke third right armor in first room" }, + { 0x14, 0x80, 0x1480, "killed poe in south east room 2F" }, + { 0x14, 0x40, 0x1440, "Midna big key text seen" }, + { 0x14, 0x10, 0x1410, "explored east outside hallway 2F " }, + { 0x14, 0x08, 0x1408, "explored west outside hallway 1F (canonballs)" }, + { 0x14, 0x04, 0x1404, "explored room above living room (2F)" }, + { 0x14, 0x02, 0x1402, "explored freezard in cages room 2F" }, + { 0x14, 0x01, 0x1401, "Intro Cutscene" }, + { 0x15, 0x80, 0x1580, "unlock west door in pumpkin room" }, + { 0x15, 0x40, 0x1540, "destroyed first right armor in cheese room" }, + { 0x15, 0x20, 0x1520, "freezard in cage cs" }, + { 0x15, 0x08, 0x1508, "courtyard intro cs" }, + { 0x15, 0x04, 0x1504, "killed poe in center of first room" }, + { 0x15, 0x02, 0x1502, "pumpkin room intro cs" }, + { 0x15, 0x01, 0x1501, "?" }, + { 0x16, 0x80, 0x1680, "?" }, + { 0x16, 0x40, 0x1640, "Yeta points to kitchen cs" }, + { 0x16, 0x20, 0x1620, "Midna Cheese text prompt" }, + { 0x16, 0x10, 0x1610, "Midna Cheese text seen" }, + { 0x16, 0x08, 0x1608, "Midna pumpkin text seen" }, + { 0x16, 0x04, 0x1604, "Darkhammer (unsets after defeat)" }, + { 0x16, 0x02, 0x1602, "Midna pumpkin text prompt" }, + { 0x16, 0x01, 0x1601, "unlock exit door in big key room" }, + { 0x17, 0x80, 0x1780, "map marker bedroom key" }, + { 0x17, 0x40, 0x1740, "map marker ordon cheese" }, + { 0x17, 0x20, 0x1720, "map marker ordon pumpkin" }, + { 0x17, 0x10, 0x1710, "Blizzeta Cutscene" }, + { 0x17, 0x08, 0x1708, "broke first ice south door in north west room 1F" }, + { 0x17, 0x04, 0x1704, "broke second ice south door in north west room 1F" }, + { 0x17, 0x02, 0x1702, "broke third ice south door in north west room 1F" }, + { 0x17, 0x01, 0x1701, "broke ice wall in compass room 2F" }, +}; + +inline EventAreaFlags eventAreaFlagsToT[] = +{ + { 0x00, 0x80, 0x0080, "map marker statue in room 2" }, + { 0x00, 0x40, 0x0040, "map marker statue will spawn in room 2" }, + { 0x00, 0x20, 0x0020, "map marker statue in room 3" }, + { 0x00, 0x10, 0x0010, "map marker statue will spawn in room 3" }, + { 0x00, 0x08, 0x0008, "map marker statue in room 4" }, + { 0x00, 0x04, 0x0004, "map marker statue will spawn in room 4" }, + { 0x00, 0x02, 0x0002, "map marker statue in room 5" }, + { 0x00, 0x01, 0x0001, "map marker statue will spawn in room 5" }, + { 0x01, 0x80, 0x0180, "map marker statue in room 6" }, + { 0x01, 0x40, 0x0140, "map marker statue will spawn in room 6" }, + { 0x01, 0x20, 0x0120, "map marker statue in room 7" }, + { 0x01, 0x10, 0x0110, "map marker statue will spawn in room 7" }, + { 0x02, 0x10, 0x0210, "PoH big chest room 4" }, + { 0x02, 0x02, 0x0202, "small key big chest room 6 7F" }, + { 0x02, 0x01, 0x0201, "big key chest" }, + { 0x03, 0x40, 0x0340, "compass big chest room 4" }, + { 0x03, 0x20, 0x0320, "PoH big chest south room 5F" }, + { 0x03, 0x10, 0x0310, "small key big chest south room 5F" }, + { 0x03, 0x04, 0x0304, "small chest room 2 2F" }, + { 0x03, 0x02, 0x0302, "map big chest room 2 3F" }, + { 0x03, 0x01, 0x0301, "dominion rod big chest" }, + { 0x04, 0x80, 0x0480, "Ooccoo" }, + { 0x05, 0x01, 0x0501, "small chest big key room" }, + { 0x06, 0x80, 0x0680, "small chest room 5 7F" }, + { 0x06, 0x40, 0x0640, "south small chest south room 5F" }, + { 0x06, 0x20, 0x0620, "small chest room 2 3F" }, + { 0x06, 0x10, 0x0610, "big chest room 5 6F" }, + { 0x06, 0x08, 0x0608, "big chest room 6 8F" }, + { 0x06, 0x02, 0x0602, "small key big chest room 1" }, + { 0x07, 0x02, 0x0702, "map marker statue in room 1" }, + { 0x07, 0x01, 0x0701, "map marker statue will spawn in room 1" }, + { 0x08, 0x80, 0x0880, "Midna text asking to look at missing statue room 1" }, + { 0x08, 0x40, 0x0840, "Midna text after looking at missing statue room 1" }, + { 0x08, 0x20, 0x0820, "unlock door in room 6 8F" }, + { 0x08, 0x10, 0x0810, "unlock door in room 3 5F (spawn baby and young gohmas in south room 5F)" }, + { 0x08, 0x08, 0x0808, "unlock door in room 1" }, + { 0x08, 0x04, 0x0804, "dominion rod big chest (set after)" }, + { 0x08, 0x02, 0x0802, "killed poe in room 3 3F" }, + { 0x08, 0x01, 0x0801, "killed poe in room 5 7F" }, + { 0x09, 0x20, 0x0920, "intro cs" }, + { 0x09, 0x10, 0x0910, "scale intro cs room 5 6F" }, + { 0x09, 0x08, 0x0908, "change balance of scale for the first time cs" }, + { 0x09, 0x04, 0x0904, "change balance of scale for the first time" }, + { 0x0A, 0x80, 0x0A80, "entered room 7" }, + { 0x0A, 0x40, 0x0A40, "spawn west big chest in south room 5F" }, + { 0x0A, 0x08, 0x0A08, "statue getting possessed for the first time cs" }, + { 0x0B, 0x40, 0x0B40, "deactivate statue slot in room 1 (opens door and deactivates statue)" }, + { 0x0B, 0x20, 0x0B20, "deactivate bell in room 2 (required to spawn in room 1)" }, + { 0x0B, 0x10, 0x0B10, "deactivate bell in room 3 (required to spawn in room 2)" }, + { 0x0B, 0x08, 0x0B08, "deactivate bell in room 4 (required to spawn in room 3)" }, + { 0x0B, 0x04, 0x0B04, "deactivate bell in room 5 (required to spawn in room 4)" }, + { 0x0B, 0x02, 0x0B02, "deactivate bell in room 6 (required to spawn in room 5)" }, + { 0x0B, 0x01, 0x0B01, "deactivate bell in room 7 (required to spawn in room 6)" }, + { 0x0C, 0x80, 0x0C80, "unlock door in south room 5F" }, + { 0x0C, 0x40, 0x0C40, "killed armos in room 2 3F (spawn big chest)" }, + { 0x0C, 0x20, 0x0C20, "killed armos in big key room (unlocks door)" }, + { 0x0C, 0x10, 0x0C10, "lit both torches in room 1 (unset if you leave) (spawn big chest)" }, + { 0x0C, 0x04, 0x0C04, "broke gate in room 2 3F" }, + { 0x0C, 0x02, 0x0C02, "broke fouth gate in room 2 2F" }, + { 0x0C, 0x01, 0x0C01, "broke first gate in room 2 2F" }, + { 0x0D, 0x80, 0x0D80, "broke third gate in room 2 2F" }, + { 0x0D, 0x40, 0x0D40, "broke second gate in room 2 2F" }, + { 0x0D, 0x20, 0x0D20, "broke second sliding door in room 4 4F" }, + { 0x0D, 0x10, 0x0D10, "broke third sliding door in room 4 5F" }, + { 0x0D, 0x08, 0x0D08, "broke second sliding door in room 4 5F" }, + { 0x0D, 0x04, 0x0D04, "broke first sliding door in room 4 5F" }, + { 0x0D, 0x02, 0x0D02, "broke first sliding door in room 4 4F" }, + { 0x0D, 0x01, 0x0D01, "broke first beamos in room before boss" }, + { 0x0E, 0x80, 0x0E80, "broke left beamos in room before boss" }, + { 0x0E, 0x40, 0x0E40, "broke right beamos in room before boss" }, + { 0x0E, 0x20, 0x0E20, "broke beamos in room 6 7F" }, + { 0x0E, 0x10, 0x0E10, "broke first beamos in room 4 4F" }, + { 0x0E, 0x08, 0x0E08, "broke second beamos in room 4 4F" }, + { 0x0E, 0x04, 0x0E04, "broke beamos in room 3 3F" }, + { 0x0E, 0x01, 0x0E01, "broke gate to bell in room 3 3F" }, + { 0x0F, 0x80, 0x0F80, "broke gate to poe in room 3 3F" }, + { 0x0F, 0x40, 0x0F40, "broke gate in room 6 8F" }, + { 0x0F, 0x20, 0x0F20, "open door to poe in room 3 3F" }, + { 0x0F, 0x10, 0x0F10, "spawn baby gohmas in beamos room 3 3F" }, + { 0x0F, 0x08, 0x0F08, "broke gate in room 6 8F cs" }, + { 0x0F, 0x01, 0x0F01, "unlock boss door" }, + { 0x10, 0x80, 0x1080, "open big door in room 1 cs part 2" }, + { 0x10, 0x40, 0x1040, "open big door in room 1 cs part 1" }, + { 0x10, 0x10, 0x1010, "killed a baby gohma in room 6 8F" }, + { 0x10, 0x08, 0x1008, "killed a baby gohma in room 6 8F" }, + { 0x10, 0x04, 0x1004, "killed a baby gohma in room 6 8F" }, + { 0x10, 0x02, 0x1002, "killed a baby gohma in room 6 8F" }, + { 0x10, 0x01, 0x1001, "killed a baby gohma in room 6 8F" }, + { 0x11, 0x80, 0x1180, "killed a baby gohma in room 6 8F" }, + { 0x11, 0x40, 0x1140, "killed a baby gohma in room 6 8F" }, + { 0x11, 0x20, 0x1120, "killed a baby gohma in room 6 8F" }, + { 0x11, 0x10, 0x1110, "killed a baby gohma in room 6 8F" }, + { 0x11, 0x08, 0x1108, "killed a baby gohma in room 6 8F" }, + { 0x11, 0x04, 0x1104, "killed a baby gohma in room 6 8F" }, + { 0x11, 0x02, 0x1102, "killed a baby gohma in room 6 8F" }, + { 0x12, 0x80, 0x1280, "pressed button in room 1 (or 6 8F) for the first time cs" }, + { 0x12, 0x40, 0x1240, "pressed button in room 6 7F for the first time cs" }, + { 0x12, 0x20, 0x1220, "killed both armos in room 6 8F (opens gate)" }, + { 0x12, 0x08, 0x1208, "pressed buttons in room 3 5F for the first time cs" }, + { 0x12, 0x04, 0x1204, "pressed buttons in room 2 3F for the first time cs" }, + { 0x12, 0x02, 0x1202, "pressed button in room 2 2F for the first time cs" }, + { 0x13, 0x40, 0x1340, "open gate to dominion rod in room 7" }, + { 0x13, 0x20, 0x1320, "statue spawning out of bell in room 1 cs trigger" }, + { 0x13, 0x10, 0x1310, "statue spawning out of bell in room 1 cs" }, + { 0x13, 0x08, 0x1308, "killed all baby gohmas in room 6 8F (spawn big chest)" }, + { 0x13, 0x04, 0x1304, "killed all enemies in room 5 6F (spawn big chest)" }, + { 0x13, 0x02, 0x1302, "killed west armos in south room 5F" }, + { 0x13, 0x01, 0x1301, "killed east armos in south room 5F" }, + { 0x14, 0x40, 0x1440, "unlock door in room 7" }, + { 0x14, 0x20, 0x1420, "statue getting in bell in room 7 cs first part" }, + { 0x14, 0x10, 0x1410, "statue getting in bell in room 7 cs second part" }, + { 0x14, 0x08, 0x1408, "statue getting in bell in room 7 cs trigger" }, + { 0x14, 0x04, 0x1404, "open gate to dominion rod in room 7 cs" }, + { 0x14, 0x02, 0x1402, "statue spawn out of bell in room 6" }, + { 0x14, 0x01, 0x1401, "statue spawning out of bell in room 6 cs trigger" }, + { 0x15, 0x80, 0x1580, "statue spawning out of bell in room 6 cs part 1" }, + { 0x15, 0x40, 0x1540, "statue getting in bell in room 6 cs trigger" }, + { 0x15, 0x20, 0x1520, "statue getting in bell in room 6 cs" }, + { 0x15, 0x10, 0x1510, "statue spawning out of bell in room 5 cs trigger" }, + { 0x15, 0x08, 0x1508, "statue spawning out of bell in room 5 cs" }, + { 0x15, 0x04, 0x1504, "statue getting in bell in room 5 cs trigger" }, + { 0x15, 0x02, 0x1502, "statue getting in bell in room 5 cs" }, + { 0x15, 0x01, 0x1501, "statue spawning out of bell in room 4 cs trigger" }, + { 0x16, 0x80, 0x1680, "statue spawning out of bell in room 4 cs" }, + { 0x16, 0x40, 0x1640, "statue getting in bell in room 4 cs trigger" }, + { 0x16, 0x20, 0x1620, "statue getting in bell in room 4 cs" }, + { 0x16, 0x10, 0x1610, "statue spawning out of bell in room 3 cs trigger" }, + { 0x16, 0x08, 0x1608, "statue spawning out of bell in room 3 cs" }, + { 0x16, 0x04, 0x1604, "statue getting in bell in room 3 cs trigger" }, + { 0x16, 0x02, 0x1602, "statue getting in bell in room 3 cs" }, + { 0x16, 0x01, 0x1601, "statue spawning out of bell in room 2 cs trigger" }, + { 0x17, 0x80, 0x1780, "statue spawning out of bell in room 2 cs" }, + { 0x17, 0x40, 0x1740, "statue getting in bell in room 2 cs trigger" }, + { 0x17, 0x20, 0x1720, "statue getting in bell in room 2 cs" }, + { 0x17, 0x10, 0x1710, "deactivate spawning bell in room 7" }, + { 0x17, 0x08, 0x1708, "big door in room 1 opens" }, + { 0x17, 0x04, 0x1704, "open big door in room 1 cs part 2 trigger" }, + { 0x17, 0x02, 0x1702, "open big door in room 1 cs part 1 trigger" }, + { 0x17, 0x01, 0x1701, "statue placed in slot in room 1" }, +}; + +struct MultiByteAreaFlag +{ + // flags treated as bool, shift left after checking bool + const char* name; + std::vector flags; + std::map enumValues; +}; + +inline MultiByteAreaFlag ForestTempleWormRoomPosition = +{ + "Worm Room position", + { 0x0D20, 0x0D10, 0x0D08, 0x0D04 }, + { + {0x0, "on totem", }, + {0x8, "north", }, + {0x7, "north north east", }, + {0x6, "north east", }, + {0x5, "east north east", }, + {0x4, "east", }, + {0x3, "east south east", }, + {0x2, "south south east", }, + {0x1, "south", }, + {0xF, "south south west", }, + {0xE, "south west", }, + {0xD, "west south west", }, + {0xC, "west", }, + {0xA, "west north west", }, + {0xB, "north west", }, + {0x9, "north north west", }, + }, +}; + +inline MultiByteAreaFlag SPR_Courtyard1FCannon = { + "Courtyard First Floor Cannon", + {0x1140, 0x1120}, + { + {1, "north"}, + {0, "south"}, + {2, "east"}, + {3, "west"} + }, +}; + +inline MultiByteAreaFlag SPR_Courtyard2FCannon = +{ + "Courtyard Second Floor Cannon", + {0x1001, 0x1180}, + { + {3, "north east"}, + {0, "south east"}, + {2, "south west"}, + {1, "north west"}, + }, +}; + +inline MultiByteAreaFlag SPR_FreezardCageRoomCannon = { + "Freezard Cage Room Cannon", + {0x1202, 0x1201}, + { + {0, "north"}, + {2, "east"}, + {1, "south"}, + {3, "west"}, + }, +}; + +inline MultiByteAreaFlag SPR_NorthWestRoomCannon = { + "North West Room Cannon", + {0x0C08, 0x0C04}, + { + {3, "north"}, + {0, "east"}, + {2, "south"}, + {1, "west"}, + }, +}; + +inline const std::map _IceBlockPuzzleLocations = +{ + {0x0C, "(-2, 2)"}, + {0x0B, "(-1, 2)"}, + {0x0A, "( 0, 2)"}, + {0x09, "( 1, 2)"}, + {0x08, "( 2, 2)"}, + + {0x0D, "(-2, 1)"}, + {0x14, "(-1, 1)"}, + {0x15, "( 0, 1)"}, + {0x16, "( 1, 1)"}, + {0x07, "( 2, 1)"}, + + {0x0E, "(-2, 0)"}, + {0x17, "(-1, 0)"}, + {0x1A, "( 0, 0)"}, + {0x17, "( 1, 0)"}, + {0x06, "( 2, 0)"}, + + {0x0F, "(-2, -1)"}, + {0x12, "(-1, -1)"}, + {0x19, "( 0, -1)"}, + {0x18, "( 1, -1)"}, + {0x05, "( 2, -1)"}, + + {0x10, "(-2, -2)"}, + {0x11, "(-1, -2)"}, + {0x02, "( 0, -2)"}, + {0x03, "( 1, -2)"}, + {0x04, "( 2, -2)"}, + + {0x01, "( 0, -3)"}, +}; + +inline MultiByteAreaFlag SPR_IcePuzzleBlock1 = { + "Ice Block 1 Location", + {0x0F10, 0x0F08, 0x0F04, 0x0F02, 0x0F01}, + _IceBlockPuzzleLocations +}; + +inline MultiByteAreaFlag SPR_IcePuzzleBlock2 = { + "Ice Block 2 Location", + {0x0880, 0x0840, 0x0820, 0x0810, 0x0808}, + _IceBlockPuzzleLocations +}; + +inline MultiByteAreaFlag SPR_IcePuzzleBlock3 = { + "Ice Block 2 Location", + {0x0804, 0x0802, 0x0801, 0x0980, 0x0940}, + _IceBlockPuzzleLocations +}; + +inline const std::map _CoOBlockPuzzle1Locations = { + {0xB, "(-1, 2)"}, + {0xC, "( 0, 2)"}, + {0x1, "( 1, 2)"}, + + {0xA, "(-1, 1)"}, + {0xD, "( 0, 1)"}, + {0x2, "( 1, 1)"}, + + {0x9, "(-1, 0)"}, + {0xE, "( 0, 0)"}, + {0x3, "( 1, 0)"}, + + {0x8, "(-1, -1)"}, + {0xF, "( 0, -1)"}, + {0x4, "( 1, -1)"}, + + {0x7, "(-1, -2)"}, + {0x6, "( 0, -2)"}, + {0x5, "( 1, -2)"}, +}; + +inline MultiByteAreaFlag CoOPuzzle1Block1 = { + "Puzzle 1 Block 1 Location", + {0x0904, 0x0902, 0x0901, 0x0880}, + _CoOBlockPuzzle1Locations +}; + +inline MultiByteAreaFlag CoOPuzzle1Block2 = { + "Puzzle 1 Block 2 Location", + {0x0A20, 0x0A10, 0x0A08, 0x0A04}, + _CoOBlockPuzzle1Locations +}; + +inline MultiByteAreaFlag CoOPuzzle1Block3 = { + "Puzzle 1 Block 3 Location", + {0x0B08, 0x0B04, 0x0B02, 0x0B01}, + _CoOBlockPuzzle1Locations +}; + +inline const std::map _CoOBlockPuzzle2Locations = { + {0x1, "(-1, 2)"}, + {0x2, "( 0, 2)"}, + {0x3, "( 1, 2)"}, + + {0xC, "(-1, 1)"}, + {0xD, "( 0, 1)"}, + {0x4, "( 1, 1)"}, + {0x5, "( 2, 1)"}, + + {0xB, "(-1, 0)"}, + {0xE, "( 0, 0)"}, + {0xF, "( 1, 0)"}, + {0x6, "( 2, 0)"}, + + {0xA, "(-1, -1)"}, + {0x9, "( 0, -1)"}, + {0x8, "( 1, -1)"}, + {0x7, "( 2, -1)"}, +}; + +inline MultiByteAreaFlag CoOPuzzle2Block1 = { + "Puzzle 2 Block 1 Location", + {0x0880, 0x0840, 0x0820, 0x0810}, + _CoOBlockPuzzle2Locations +}; + +inline MultiByteAreaFlag CoOPuzzle2Block2 = { + "Puzzle 2 Block 2 Location", + {0x0808, 0x0804, 0x0802, 0x0801}, + _CoOBlockPuzzle2Locations +}; + +inline MultiByteAreaFlag CoOPuzzle2Block3 = { + "Puzzle 2 Block 3 Location", + {0x0980, 0x0940, 0x0920, 0x0910}, + _CoOBlockPuzzle2Locations +}; + +inline const std::map _CoOBlockPuzzle3Locations = { + {0x01, "(-2, 2)"}, + {0x02, "(-1, 2)"}, + {0x03, "( 0, 2)"}, + {0x04, "( 1, 2)"}, + {0x05, "( 2, 2)"}, + + {0x10, "(-2, 1)"}, + {0x11, "(-1, 1)"}, + {0x12, "( 0, 1)"}, + {0x13, "( 1, 1)"}, + {0x06, "( 2, 1)"}, + + {0x0F, "(-2, 0)"}, + {0x18, "(-1, 0)"}, + {0x19, "( 0, 0)"}, + {0x14, "( 1, 0)"}, + {0x07, "( 2, 0)"}, + + {0x0E, "(-2, -1)"}, + {0x17, "(-1, -1)"}, + {0x16, "( 0, -1)"}, + {0x15, "( 1, -1)"}, + {0x08, "( 2, -1)"}, + + {0x0D, "(-2, -2)"}, + {0x0C, "(-1, -2)"}, + {0x0B, "( 0, -2)"}, + {0x0A, "( 1, -2)"}, + {0x09, "( 2, -2)"}, +}; + +inline MultiByteAreaFlag CoOPuzzle3Block1 = { + "Puzzle 3 Block 1 Location", + {0x0E40, 0x0E20, 0x0E10, 0x0E08, 0x0E04}, + _CoOBlockPuzzle3Locations +}; + +inline MultiByteAreaFlag CoOPuzzle3Block2 = { + "Puzzle 3 Block 2 Location", + {0x0E02, 0x0E01, 0x0F80, 0x0F40, 0x0F20}, + _CoOBlockPuzzle3Locations +}; + +inline MultiByteAreaFlag CoOPuzzle3Block3 = { + "Puzzle 3 Block 3 Location", + {0x0F10, 0x0F08, 0x0F04, 0x0F02, 0x0F01}, + _CoOBlockPuzzle3Locations +}; + +struct AreaFlagIter { + template + AreaFlagIter(T t) : span(t) {} + std::span span; +}; + +inline std::map areaFlagLookup = +{ + { 0x00, eventAreaFlagsOrdon }, + { 0x01, eventAreaFlagsSewer }, + { 0x02, eventAreaFlagsFaron }, + { 0x03, eventAreaFlagsEldin }, + { 0x04, eventAreaFlagsLanayru }, + { 0x06, eventAreaFlagsHyruleField }, + { 0x07, eventAreaFlagsSacredGrove }, + { 0x08, eventAreaFlagsSnowpeak }, + { 0x09, eventAreaFlagsCastleTown }, + { 0x0A, eventAreaFlagsGerudoDesert }, + { 0x0B, eventAreaFlagsFishingPond }, + { 0x10, eventAreaFlagsFT }, + { 0x11, eventAreaFlagsGM }, + { 0x12, eventAreaFlagsLBT }, + { 0x13, eventAreaFlagsAG }, + { 0x14, eventAreaFlagsSPR }, + { 0x15, eventAreaFlagsToT }, + { 0x16, eventAreaFlagsCitS }, + { 0x17, eventAreaFlagsPoT }, + { 0x18, eventAreaFlagsHC }, + { 0x19, eventAreaFlagsCoO }, + { 0x1A, eventAreaFlagsLHLC }, + { 0x1B, eventAreaFlagsGrotto }, +}; + #endif // !DUSK_IMGUI_EVENTFLAGS_HPP \ No newline at end of file From 93f8a5fa8f5ce5f344979fd93591af2dbfd6e126 Mon Sep 17 00:00:00 2001 From: roeming Date: Thu, 30 Apr 2026 11:11:08 -0400 Subject: [PATCH 124/390] Move area multi flag bits to combined flags, at most 2 --- src/dusk/imgui/ImGuiEventFlags.hpp | 86 +++++++++++++++--------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/src/dusk/imgui/ImGuiEventFlags.hpp b/src/dusk/imgui/ImGuiEventFlags.hpp index e759d46b8d..45a051cb00 100644 --- a/src/dusk/imgui/ImGuiEventFlags.hpp +++ b/src/dusk/imgui/ImGuiEventFlags.hpp @@ -3108,14 +3108,14 @@ struct MultiByteAreaFlag { // flags treated as bool, shift left after checking bool const char* name; - std::vector flags; + uint16_t flags[2]; std::map enumValues; }; inline MultiByteAreaFlag ForestTempleWormRoomPosition = { "Worm Room position", - { 0x0D20, 0x0D10, 0x0D08, 0x0D04 }, + { 0x0D3C }, { {0x0, "on totem", }, {0x8, "north", }, @@ -3138,7 +3138,7 @@ inline MultiByteAreaFlag ForestTempleWormRoomPosition = inline MultiByteAreaFlag SPR_Courtyard1FCannon = { "Courtyard First Floor Cannon", - {0x1140, 0x1120}, + { 0x1160 }, { {1, "north"}, {0, "south"}, @@ -3150,7 +3150,7 @@ inline MultiByteAreaFlag SPR_Courtyard1FCannon = { inline MultiByteAreaFlag SPR_Courtyard2FCannon = { "Courtyard Second Floor Cannon", - {0x1001, 0x1180}, + { 0x1001, 0x1180 }, { {3, "north east"}, {0, "south east"}, @@ -3161,7 +3161,7 @@ inline MultiByteAreaFlag SPR_Courtyard2FCannon = inline MultiByteAreaFlag SPR_FreezardCageRoomCannon = { "Freezard Cage Room Cannon", - {0x1202, 0x1201}, + { 0x1203 }, { {0, "north"}, {2, "east"}, @@ -3172,7 +3172,7 @@ inline MultiByteAreaFlag SPR_FreezardCageRoomCannon = { inline MultiByteAreaFlag SPR_NorthWestRoomCannon = { "North West Room Cannon", - {0x0C08, 0x0C04}, + { 0x0C0C }, { {3, "north"}, {0, "east"}, @@ -3218,19 +3218,19 @@ inline const std::map _IceBlockPuzzleLocations = inline MultiByteAreaFlag SPR_IcePuzzleBlock1 = { "Ice Block 1 Location", - {0x0F10, 0x0F08, 0x0F04, 0x0F02, 0x0F01}, + { 0x0F1F }, _IceBlockPuzzleLocations }; inline MultiByteAreaFlag SPR_IcePuzzleBlock2 = { "Ice Block 2 Location", - {0x0880, 0x0840, 0x0820, 0x0810, 0x0808}, + { 0x08F8 }, _IceBlockPuzzleLocations }; inline MultiByteAreaFlag SPR_IcePuzzleBlock3 = { "Ice Block 2 Location", - {0x0804, 0x0802, 0x0801, 0x0980, 0x0940}, + { 0x0807, 0x09C0 }, _IceBlockPuzzleLocations }; @@ -3258,19 +3258,19 @@ inline const std::map _CoOBlockPuzzle1Locations = { inline MultiByteAreaFlag CoOPuzzle1Block1 = { "Puzzle 1 Block 1 Location", - {0x0904, 0x0902, 0x0901, 0x0880}, + { 0x0907, 0x0A80 }, _CoOBlockPuzzle1Locations }; inline MultiByteAreaFlag CoOPuzzle1Block2 = { "Puzzle 1 Block 2 Location", - {0x0A20, 0x0A10, 0x0A08, 0x0A04}, + { 0x0A3C }, _CoOBlockPuzzle1Locations }; inline MultiByteAreaFlag CoOPuzzle1Block3 = { "Puzzle 1 Block 3 Location", - {0x0B08, 0x0B04, 0x0B02, 0x0B01}, + { 0x0B0F }, _CoOBlockPuzzle1Locations }; @@ -3297,69 +3297,69 @@ inline const std::map _CoOBlockPuzzle2Locations = { inline MultiByteAreaFlag CoOPuzzle2Block1 = { "Puzzle 2 Block 1 Location", - {0x0880, 0x0840, 0x0820, 0x0810}, + { 0x08F0 }, _CoOBlockPuzzle2Locations }; inline MultiByteAreaFlag CoOPuzzle2Block2 = { "Puzzle 2 Block 2 Location", - {0x0808, 0x0804, 0x0802, 0x0801}, + { 0x080F }, _CoOBlockPuzzle2Locations }; inline MultiByteAreaFlag CoOPuzzle2Block3 = { "Puzzle 2 Block 3 Location", - {0x0980, 0x0940, 0x0920, 0x0910}, + { 0x09F0 }, _CoOBlockPuzzle2Locations }; inline const std::map _CoOBlockPuzzle3Locations = { - {0x01, "(-2, 2)"}, - {0x02, "(-1, 2)"}, - {0x03, "( 0, 2)"}, - {0x04, "( 1, 2)"}, - {0x05, "( 2, 2)"}, + { 0x01, "(-2, 2)" }, + { 0x02, "(-1, 2)" }, + { 0x03, "( 0, 2)" }, + { 0x04, "( 1, 2)" }, + { 0x05, "( 2, 2)" }, - {0x10, "(-2, 1)"}, - {0x11, "(-1, 1)"}, - {0x12, "( 0, 1)"}, - {0x13, "( 1, 1)"}, - {0x06, "( 2, 1)"}, + { 0x10, "(-2, 1)" }, + { 0x11, "(-1, 1)" }, + { 0x12, "( 0, 1)" }, + { 0x13, "( 1, 1)" }, + { 0x06, "( 2, 1)" }, - {0x0F, "(-2, 0)"}, - {0x18, "(-1, 0)"}, - {0x19, "( 0, 0)"}, - {0x14, "( 1, 0)"}, - {0x07, "( 2, 0)"}, + { 0x0F, "(-2, 0)" }, + { 0x18, "(-1, 0)" }, + { 0x19, "( 0, 0)" }, + { 0x14, "( 1, 0)" }, + { 0x07, "( 2, 0)" }, - {0x0E, "(-2, -1)"}, - {0x17, "(-1, -1)"}, - {0x16, "( 0, -1)"}, - {0x15, "( 1, -1)"}, - {0x08, "( 2, -1)"}, + { 0x0E, "(-2, -1)" }, + { 0x17, "(-1, -1)" }, + { 0x16, "( 0, -1)" }, + { 0x15, "( 1, -1)" }, + { 0x08, "( 2, -1)" }, - {0x0D, "(-2, -2)"}, - {0x0C, "(-1, -2)"}, - {0x0B, "( 0, -2)"}, - {0x0A, "( 1, -2)"}, - {0x09, "( 2, -2)"}, + { 0x0D, "(-2, -2)" }, + { 0x0C, "(-1, -2)" }, + { 0x0B, "( 0, -2)" }, + { 0x0A, "( 1, -2)" }, + { 0x09, "( 2, -2)" }, }; inline MultiByteAreaFlag CoOPuzzle3Block1 = { "Puzzle 3 Block 1 Location", - {0x0E40, 0x0E20, 0x0E10, 0x0E08, 0x0E04}, + { 0x0E7C }, _CoOBlockPuzzle3Locations }; inline MultiByteAreaFlag CoOPuzzle3Block2 = { "Puzzle 3 Block 2 Location", - {0x0E02, 0x0E01, 0x0F80, 0x0F40, 0x0F20}, + { 0x0E03, 0x0FE0 }, _CoOBlockPuzzle3Locations }; inline MultiByteAreaFlag CoOPuzzle3Block3 = { "Puzzle 3 Block 3 Location", - {0x0F10, 0x0F08, 0x0F04, 0x0F02, 0x0F01}, + { 0x0F1F }, _CoOBlockPuzzle3Locations }; From cad5a8d1bc1b84d0e8491e08d17fd4e46d44799b Mon Sep 17 00:00:00 2001 From: roeming Date: Thu, 30 Apr 2026 11:43:57 -0400 Subject: [PATCH 125/390] Add multibyte flags to Area iterators --- src/dusk/imgui/ImGuiEventFlags.hpp | 455 ++++++++++++++--------------- 1 file changed, 224 insertions(+), 231 deletions(-) diff --git a/src/dusk/imgui/ImGuiEventFlags.hpp b/src/dusk/imgui/ImGuiEventFlags.hpp index 45a051cb00..627e02c8c7 100644 --- a/src/dusk/imgui/ImGuiEventFlags.hpp +++ b/src/dusk/imgui/ImGuiEventFlags.hpp @@ -3108,209 +3108,171 @@ struct MultiByteAreaFlag { // flags treated as bool, shift left after checking bool const char* name; - uint16_t flags[2]; + std::array flags; std::map enumValues; }; +constexpr uint16_t AREA_FLAG_NONE = 0; -inline MultiByteAreaFlag ForestTempleWormRoomPosition = -{ - "Worm Room position", - { 0x0D3C }, - { - {0x0, "on totem", }, - {0x8, "north", }, - {0x7, "north north east", }, - {0x6, "north east", }, - {0x5, "east north east", }, - {0x4, "east", }, - {0x3, "east south east", }, - {0x2, "south south east", }, - {0x1, "south", }, - {0xF, "south south west", }, - {0xE, "south west", }, - {0xD, "west south west", }, - {0xC, "west", }, - {0xA, "west north west", }, - {0xB, "north west", }, - {0x9, "north north west", }, - }, +inline MultiByteAreaFlag ForestTempleMultiByteFlags[] = +{ + { + "Worm Room position", + { 0x0D3C, AREA_FLAG_NONE }, + { + { 0x0, "On Totem", }, + { 0x8, "North", }, + { 0x7, "North North East", }, + { 0x6, "North East", }, + { 0x5, "East North East", }, + { 0x4, "East", }, + { 0x3, "East South East", }, + { 0x2, "South South East", }, + { 0x1, "South", }, + { 0xF, "South South West", }, + { 0xE, "South West", }, + { 0xD, "West South West", }, + { 0xC, "West", }, + { 0xA, "West North West", }, + { 0xB, "North West", }, + { 0x9, "North North West", }, + }, + } }; -inline MultiByteAreaFlag SPR_Courtyard1FCannon = { - "Courtyard First Floor Cannon", - { 0x1160 }, - { - {1, "north"}, - {0, "south"}, - {2, "east"}, - {3, "west"} +inline const std::map _SPRIceBlockPuzzleLocations = +{ + { 0x0C, "(-2, 2)" }, + { 0x0B, "(-1, 2)" }, + { 0x0A, "( 0, 2)" }, + { 0x09, "( 1, 2)" }, + { 0x08, "( 2, 2)" }, + + { 0x0D, "(-2, 1)" }, + { 0x14, "(-1, 1)" }, + { 0x15, "( 0, 1)" }, + { 0x16, "( 1, 1)" }, + { 0x07, "( 2, 1)" }, + + { 0x0E, "(-2, 0)" }, + { 0x17, "(-1, 0)" }, + { 0x1A, "( 0, 0)" }, + { 0x17, "( 1, 0)" }, + { 0x06, "( 2, 0)" }, + + { 0x0F, "(-2, -1)" }, + { 0x12, "(-1, -1)" }, + { 0x19, "( 0, -1)" }, + { 0x18, "( 1, -1)" }, + { 0x05, "( 2, -1)" }, + + { 0x10, "(-2, -2)" }, + { 0x11, "(-1, -2)" }, + { 0x02, "( 0, -2)" }, + { 0x03, "( 1, -2)" }, + { 0x04, "( 2, -2)" }, + + { 0x01, "( 0, -3)" }, +}; + +inline MultiByteAreaFlag SPRMultiByteFlags[] = { + { + "Courtyard First Floor Cannon", + { 0x1160, AREA_FLAG_NONE }, + { + { 1, "North" }, + { 0, "South" }, + { 2, "East" }, + { 3, "West" } + }, }, -}; - -inline MultiByteAreaFlag SPR_Courtyard2FCannon = -{ - "Courtyard Second Floor Cannon", - { 0x1001, 0x1180 }, - { - {3, "north east"}, - {0, "south east"}, - {2, "south west"}, - {1, "north west"}, + { + "Courtyard Second Floor Cannon", + { 0x1001, 0x1180 }, + { + { 3, "North East" }, + { 0, "South East" }, + { 2, "South West" }, + { 1, "North West" }, + }, }, -}; - -inline MultiByteAreaFlag SPR_FreezardCageRoomCannon = { - "Freezard Cage Room Cannon", - { 0x1203 }, - { - {0, "north"}, - {2, "east"}, - {1, "south"}, - {3, "west"}, - }, -}; - -inline MultiByteAreaFlag SPR_NorthWestRoomCannon = { - "North West Room Cannon", - { 0x0C0C }, - { - {3, "north"}, - {0, "east"}, - {2, "south"}, - {1, "west"}, - }, -}; - -inline const std::map _IceBlockPuzzleLocations = -{ - {0x0C, "(-2, 2)"}, - {0x0B, "(-1, 2)"}, - {0x0A, "( 0, 2)"}, - {0x09, "( 1, 2)"}, - {0x08, "( 2, 2)"}, - - {0x0D, "(-2, 1)"}, - {0x14, "(-1, 1)"}, - {0x15, "( 0, 1)"}, - {0x16, "( 1, 1)"}, - {0x07, "( 2, 1)"}, - - {0x0E, "(-2, 0)"}, - {0x17, "(-1, 0)"}, - {0x1A, "( 0, 0)"}, - {0x17, "( 1, 0)"}, - {0x06, "( 2, 0)"}, - - {0x0F, "(-2, -1)"}, - {0x12, "(-1, -1)"}, - {0x19, "( 0, -1)"}, - {0x18, "( 1, -1)"}, - {0x05, "( 2, -1)"}, - - {0x10, "(-2, -2)"}, - {0x11, "(-1, -2)"}, - {0x02, "( 0, -2)"}, - {0x03, "( 1, -2)"}, - {0x04, "( 2, -2)"}, - - {0x01, "( 0, -3)"}, -}; - -inline MultiByteAreaFlag SPR_IcePuzzleBlock1 = { - "Ice Block 1 Location", - { 0x0F1F }, - _IceBlockPuzzleLocations -}; - -inline MultiByteAreaFlag SPR_IcePuzzleBlock2 = { - "Ice Block 2 Location", - { 0x08F8 }, - _IceBlockPuzzleLocations -}; - -inline MultiByteAreaFlag SPR_IcePuzzleBlock3 = { - "Ice Block 2 Location", - { 0x0807, 0x09C0 }, - _IceBlockPuzzleLocations + { + "Freezard Cage Room Cannon", + { 0x1203, AREA_FLAG_NONE }, + { + { 0, "North" }, + { 2, "East" }, + { 1, "South" }, + { 3, "West" }, + }, + }, + { + "North West Room Cannon", + { 0x0C0C, AREA_FLAG_NONE }, + { + { 3, "North" }, + { 0, "East" }, + { 2, "South" }, + { 1, "West" }, + }, + }, + { + "Ice Block 1 Location", + { 0x0F1F, AREA_FLAG_NONE }, + _SPRIceBlockPuzzleLocations + }, + { + "Ice Block 2 Location", + { 0x08F8, AREA_FLAG_NONE }, + _SPRIceBlockPuzzleLocations + }, + { + "Ice Block 2 Location", + { 0x0807, 0x09C0 }, + _SPRIceBlockPuzzleLocations + } }; inline const std::map _CoOBlockPuzzle1Locations = { - {0xB, "(-1, 2)"}, - {0xC, "( 0, 2)"}, - {0x1, "( 1, 2)"}, - - {0xA, "(-1, 1)"}, - {0xD, "( 0, 1)"}, - {0x2, "( 1, 1)"}, - - {0x9, "(-1, 0)"}, - {0xE, "( 0, 0)"}, - {0x3, "( 1, 0)"}, - - {0x8, "(-1, -1)"}, - {0xF, "( 0, -1)"}, - {0x4, "( 1, -1)"}, - - {0x7, "(-1, -2)"}, - {0x6, "( 0, -2)"}, - {0x5, "( 1, -2)"}, -}; - -inline MultiByteAreaFlag CoOPuzzle1Block1 = { - "Puzzle 1 Block 1 Location", - { 0x0907, 0x0A80 }, - _CoOBlockPuzzle1Locations -}; - -inline MultiByteAreaFlag CoOPuzzle1Block2 = { - "Puzzle 1 Block 2 Location", - { 0x0A3C }, - _CoOBlockPuzzle1Locations -}; - -inline MultiByteAreaFlag CoOPuzzle1Block3 = { - "Puzzle 1 Block 3 Location", - { 0x0B0F }, - _CoOBlockPuzzle1Locations + { 0x0B, "(-1, 2)" }, + { 0x0C, "( 0, 2)" }, + { 0x01, "( 1, 2)" }, + + { 0x0A, "(-1, 1)" }, + { 0x0D, "( 0, 1)" }, + { 0x02, "( 1, 1)" }, + + { 0x09, "(-1, 0)" }, + { 0x0E, "( 0, 0)" }, + { 0x03, "( 1, 0)" }, + + { 0x08, "(-1, -1)" }, + { 0x0F, "( 0, -1)" }, + { 0x04, "( 1, -1)" }, + + { 0x07, "(-1, -2)" }, + { 0x06, "( 0, -2)" }, + { 0x05, "( 1, -2)" }, }; inline const std::map _CoOBlockPuzzle2Locations = { - {0x1, "(-1, 2)"}, - {0x2, "( 0, 2)"}, - {0x3, "( 1, 2)"}, - - {0xC, "(-1, 1)"}, - {0xD, "( 0, 1)"}, - {0x4, "( 1, 1)"}, - {0x5, "( 2, 1)"}, - - {0xB, "(-1, 0)"}, - {0xE, "( 0, 0)"}, - {0xF, "( 1, 0)"}, - {0x6, "( 2, 0)"}, - - {0xA, "(-1, -1)"}, - {0x9, "( 0, -1)"}, - {0x8, "( 1, -1)"}, - {0x7, "( 2, -1)"}, -}; - -inline MultiByteAreaFlag CoOPuzzle2Block1 = { - "Puzzle 2 Block 1 Location", - { 0x08F0 }, - _CoOBlockPuzzle2Locations -}; - -inline MultiByteAreaFlag CoOPuzzle2Block2 = { - "Puzzle 2 Block 2 Location", - { 0x080F }, - _CoOBlockPuzzle2Locations -}; - -inline MultiByteAreaFlag CoOPuzzle2Block3 = { - "Puzzle 2 Block 3 Location", - { 0x09F0 }, - _CoOBlockPuzzle2Locations + { 0x01, "(-1, 2)" }, + { 0x02, "( 0, 2)" }, + { 0x03, "( 1, 2)" }, + + { 0x0C, "(-1, 1)" }, + { 0x0D, "( 0, 1)" }, + { 0x04, "( 1, 1)" }, + { 0x05, "( 2, 1)" }, + + { 0x0B, "(-1, 0)" }, + { 0x0E, "( 0, 0)" }, + { 0x0F, "( 1, 0)" }, + { 0x06, "( 2, 0)" }, + + { 0x0A, "(-1, -1)" }, + { 0x09, "( 0, -1)" }, + { 0x08, "( 1, -1)" }, + { 0x07, "( 2, -1)" }, }; inline const std::map _CoOBlockPuzzle3Locations = { @@ -3345,55 +3307,86 @@ inline const std::map _CoOBlockPuzzle3Locations = { { 0x09, "( 2, -2)" }, }; -inline MultiByteAreaFlag CoOPuzzle3Block1 = { - "Puzzle 3 Block 1 Location", - { 0x0E7C }, - _CoOBlockPuzzle3Locations -}; - -inline MultiByteAreaFlag CoOPuzzle3Block2 = { - "Puzzle 3 Block 2 Location", - { 0x0E03, 0x0FE0 }, - _CoOBlockPuzzle3Locations -}; - -inline MultiByteAreaFlag CoOPuzzle3Block3 = { - "Puzzle 3 Block 3 Location", - { 0x0F1F }, - _CoOBlockPuzzle3Locations +inline MultiByteAreaFlag CoOMultiByteFlags[] = { + { + "Puzzle 1 Block 1 Location", + { 0x0907, 0x0A80 }, + _CoOBlockPuzzle1Locations + }, + { + "Puzzle 1 Block 2 Location", + { 0x0A3C, AREA_FLAG_NONE }, + _CoOBlockPuzzle1Locations + }, + { + "Puzzle 1 Block 3 Location", + { 0x0B0F, AREA_FLAG_NONE }, + _CoOBlockPuzzle1Locations + }, + { + "Puzzle 2 Block 1 Location", + { 0x08F0, AREA_FLAG_NONE }, + _CoOBlockPuzzle2Locations + }, + { + "Puzzle 2 Block 2 Location", + { 0x080F, AREA_FLAG_NONE }, + _CoOBlockPuzzle2Locations + }, + { + "Puzzle 2 Block 3 Location", + { 0x09F0, AREA_FLAG_NONE }, + _CoOBlockPuzzle2Locations + }, + { + "Puzzle 3 Block 1 Location", + { 0x0E7C, AREA_FLAG_NONE }, + _CoOBlockPuzzle3Locations + }, + { + "Puzzle 3 Block 2 Location", + { 0x0E03, 0x0FE0 }, + _CoOBlockPuzzle3Locations + }, + { + "Puzzle 3 Block 3 Location", + { 0x0F1F, AREA_FLAG_NONE }, + _CoOBlockPuzzle3Locations + } }; struct AreaFlagIter { - template - AreaFlagIter(T t) : span(t) {} std::span span; + std::span span; }; inline std::map areaFlagLookup = { - { 0x00, eventAreaFlagsOrdon }, - { 0x01, eventAreaFlagsSewer }, - { 0x02, eventAreaFlagsFaron }, - { 0x03, eventAreaFlagsEldin }, - { 0x04, eventAreaFlagsLanayru }, - { 0x06, eventAreaFlagsHyruleField }, - { 0x07, eventAreaFlagsSacredGrove }, - { 0x08, eventAreaFlagsSnowpeak }, - { 0x09, eventAreaFlagsCastleTown }, - { 0x0A, eventAreaFlagsGerudoDesert }, - { 0x0B, eventAreaFlagsFishingPond }, - { 0x10, eventAreaFlagsFT }, - { 0x11, eventAreaFlagsGM }, - { 0x12, eventAreaFlagsLBT }, - { 0x13, eventAreaFlagsAG }, - { 0x14, eventAreaFlagsSPR }, - { 0x15, eventAreaFlagsToT }, - { 0x16, eventAreaFlagsCitS }, - { 0x17, eventAreaFlagsPoT }, - { 0x18, eventAreaFlagsHC }, - { 0x19, eventAreaFlagsCoO }, - { 0x1A, eventAreaFlagsLHLC }, - { 0x1B, eventAreaFlagsGrotto }, + { 0x00, AreaFlagIter{ eventAreaFlagsOrdon, {} } }, + { 0x01, AreaFlagIter{ eventAreaFlagsSewer, {} } }, + { 0x02, AreaFlagIter{ eventAreaFlagsFaron, {} } }, + { 0x03, AreaFlagIter{ eventAreaFlagsEldin, {} } }, + { 0x04, AreaFlagIter{ eventAreaFlagsLanayru, {} } }, + // 5 unused + { 0x06, AreaFlagIter{ eventAreaFlagsHyruleField, {} } }, + { 0x07, AreaFlagIter{ eventAreaFlagsSacredGrove, {} } }, + { 0x08, AreaFlagIter{ eventAreaFlagsSnowpeak, {} } }, + { 0x09, AreaFlagIter{ eventAreaFlagsCastleTown, {} } }, + { 0x0A, AreaFlagIter{ eventAreaFlagsGerudoDesert, {} } }, + { 0x0B, AreaFlagIter{ eventAreaFlagsFishingPond, {} } }, + // C-F unused + { 0x10, AreaFlagIter{ eventAreaFlagsFT, ForestTempleMultiByteFlags } }, + { 0x11, AreaFlagIter{ eventAreaFlagsGM, {} } }, + { 0x12, AreaFlagIter{ eventAreaFlagsLBT, {} } }, + { 0x13, AreaFlagIter{ eventAreaFlagsAG, {} } }, + { 0x14, AreaFlagIter{ eventAreaFlagsSPR, SPRMultiByteFlags } }, + { 0x15, AreaFlagIter{ eventAreaFlagsToT, {} } }, + { 0x16, AreaFlagIter{ eventAreaFlagsCitS, {} } }, + { 0x17, AreaFlagIter{ eventAreaFlagsPoT, {} } }, + { 0x18, AreaFlagIter{ eventAreaFlagsHC, {} } }, + { 0x19, AreaFlagIter{ eventAreaFlagsCoO, CoOMultiByteFlags } }, + { 0x1A, AreaFlagIter{ eventAreaFlagsLHLC, {} } }, + { 0x1B, AreaFlagIter{ eventAreaFlagsGrotto, {} } }, }; #endif // !DUSK_IMGUI_EVENTFLAGS_HPP \ No newline at end of file From b70a714f883f0f6aa50743c30017fd6b75d837fa Mon Sep 17 00:00:00 2001 From: roeming Date: Thu, 30 Apr 2026 11:45:16 -0400 Subject: [PATCH 126/390] Remove missed randomizer flag --- src/dusk/imgui/ImGuiEventFlags.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/dusk/imgui/ImGuiEventFlags.hpp b/src/dusk/imgui/ImGuiEventFlags.hpp index 627e02c8c7..c91e1562dc 100644 --- a/src/dusk/imgui/ImGuiEventFlags.hpp +++ b/src/dusk/imgui/ImGuiEventFlags.hpp @@ -2724,7 +2724,6 @@ inline EventAreaFlags eventAreaFlagsSacredGrove[] = { 0x17, 0x40, 0x1740, "Transition to day after Skull Kid" }, { 0x17, 0x20, 0x1720, "dark beasts spawned" }, { 0x17, 0x10, 0x1710, "Sacred Grove Portal (removes statue blocking door of time (to past)" }, - { 0x17, 0x08, 0x1708, "Randomizer: remove statue to past" }, }; inline EventAreaFlags eventAreaFlagsSewer[] = From b5871d72d94b6ab2fe6aee77b91559a76793baa1 Mon Sep 17 00:00:00 2001 From: roeming Date: Thu, 30 Apr 2026 11:47:22 -0400 Subject: [PATCH 127/390] fix build --- src/dusk/imgui/ImGuiEventFlags.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dusk/imgui/ImGuiEventFlags.hpp b/src/dusk/imgui/ImGuiEventFlags.hpp index c91e1562dc..b644e8b86b 100644 --- a/src/dusk/imgui/ImGuiEventFlags.hpp +++ b/src/dusk/imgui/ImGuiEventFlags.hpp @@ -3355,8 +3355,8 @@ inline MultiByteAreaFlag CoOMultiByteFlags[] = { }; struct AreaFlagIter { - std::span span; - std::span span; + std::span bitFlags; + std::span multibyteFlags; }; inline std::map areaFlagLookup = From 9b6b344ecf4e80389918ee7bae981b178bede215 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Thu, 30 Apr 2026 12:09:18 -0600 Subject: [PATCH 128/390] Revert "mirror clip fix" This reverts commit 1ac6df8de7956a790b7782e74a1503568f922904. --- src/d/actor/d_a_obj_mirror_chain.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/d/actor/d_a_obj_mirror_chain.cpp b/src/d/actor/d_a_obj_mirror_chain.cpp index da4a09e1c5..92c062f7c8 100644 --- a/src/d/actor/d_a_obj_mirror_chain.cpp +++ b/src/d/actor/d_a_obj_mirror_chain.cpp @@ -59,8 +59,7 @@ void dScissorBegin_packet_c::draw() { } if (sp50 >= 4) { - IF_DUSK(GXSetColorUpdate(GX_FALSE)); - IF_NOT_DUSK(GXSetScissor(FB_WIDTH + 1, FB_HEIGHT + 1, 0, 0)); + GXSetScissor(FB_WIDTH + 1, FB_HEIGHT + 1, 0, 0); return; } @@ -171,8 +170,7 @@ void dScissorBegin_packet_c::draw() { } if (spBC.z < 0.0f || var_f31 > sp6C || sp7C < sp70 || var_f30 > sp64 || sp78 < sp68) { - IF_DUSK(GXSetColorUpdate(GX_FALSE)); - IF_NOT_DUSK(GXSetScissor(FB_WIDTH + 1, FB_HEIGHT + 1, 0, 0)); + GXSetScissor(FB_WIDTH + 1, FB_HEIGHT + 1, 0, 0); } else { var_f31 = cLib_minLimit(var_f31, sp70); sp7C = cLib_maxLimit(sp7C, sp6C); @@ -189,7 +187,6 @@ void dScissorEnd_packet_c::draw() { #endif GXSetScissor(l_scissor[0], l_scissor[1], l_scissor[2], l_scissor[3]); - IF_DUSK(GXSetColorUpdate(GX_TRUE)); } static int createSolidHeap(fopAc_ac_c* i_this) { From e3ce1f01c91b0b23e40258eecdf8be546fc8afd7 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Thu, 30 Apr 2026 14:38:24 -0400 Subject: [PATCH 129/390] Widescreen Dungeon Map --- include/d/d_menu_dmap.h | 4 ++++ src/d/d_menu_dmap.cpp | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/include/d/d_menu_dmap.h b/include/d/d_menu_dmap.h index e50c533654..81baea1446 100644 --- a/include/d/d_menu_dmap.h +++ b/include/d/d_menu_dmap.h @@ -91,6 +91,10 @@ public: void calcCursor(); void drawCursor(); + #if TARGET_PC + void dMapBgWide(); + #endif + void setDPDFloorSelCurPos(s8 i_pos) { field_0xdd6 = i_pos; } f32 getMapWidth() { return mMapWidth; } diff --git a/src/d/d_menu_dmap.cpp b/src/d/d_menu_dmap.cpp index bb557efdac..8ef7fadd4b 100644 --- a/src/d/d_menu_dmap.cpp +++ b/src/d/d_menu_dmap.cpp @@ -856,7 +856,46 @@ void dMenu_DmapBg_c::decGoldFrameAlphaRate() { setGoldFrameAlphaRate(rate); } +void dMenu_DmapBg_c::dMapBgWide() { + // Scale Base HUD + mBaseScreen->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f); + mBaseScreen->translate(mDoGph_gInf_c::getSafeMinXF(), 0.0f); + + // Boss Key, Compass & Map icons + mBaseScreen->search(MULTI_CHAR('key_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mBaseScreen->search(MULTI_CHAR('con_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mBaseScreen->search(MULTI_CHAR('map_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // Text Header + mBaseScreen->search(MULTI_CHAR('t_t00'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mBaseScreen->search(MULTI_CHAR('f_t_00'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // C Button + mBaseScreen->search(MULTI_CHAR('c_btn2'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // Scale Buttons HUD + mButtonScreen->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f); + mButtonScreen->translate(mDoGph_gInf_c::getSafeMinXF(), 0.0f); + + // Buttons + mButtonScreen->search(MULTI_CHAR('cont_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // C Button + mButtonScreen->search(MULTI_CHAR('c_btn'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mButtonScreen->search(MULTI_CHAR('c_text_s'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mButtonScreen->search(MULTI_CHAR('c_text'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mButtonScreen->search(MULTI_CHAR('f_text_s'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mButtonScreen->search(MULTI_CHAR('f_text'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // Decorations + mButtonScreen->search(MULTI_CHAR('kazari_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); +} + void dMenu_DmapBg_c::draw() { + #if TARGET_PC + dMapBgWide(); + #endif + u32 scissor_left; u32 scissor_top; u32 scissor_width; From d6820c9233fcbeaabd8cac6f9ea38482747d5af2 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Thu, 30 Apr 2026 14:53:15 -0400 Subject: [PATCH 130/390] fix toast call --- src/dusk/imgui/ImGuiConsole.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dusk/imgui/ImGuiConsole.cpp b/src/dusk/imgui/ImGuiConsole.cpp index cbd3998116..12b4cf87d9 100644 --- a/src/dusk/imgui/ImGuiConsole.cpp +++ b/src/dusk/imgui/ImGuiConsole.cpp @@ -366,9 +366,9 @@ namespace dusk { if (dusk::IsGameLaunched && !m_isLaunchInitialized) { AddToast(ImGui::GetIO().MouseSource == ImGuiMouseSource_TouchScreen ? - "Tap to toggle menu" : - "Press F1 to toggle menu", - 2.5f); + "Tap to toggle menu"s : + "Press F1 to toggle menu"s, + 2.5f); m_isLaunchInitialized = true; if (getSettings().game.liveSplitEnabled) { dusk::speedrun::connectLiveSplit(); From a1960eaa33d56a27a2c56d5062cbd95ab398e4ce Mon Sep 17 00:00:00 2001 From: Irastris Date: Thu, 30 Apr 2026 15:30:08 -0400 Subject: [PATCH 131/390] Initial attempt at the popup menu --- files.cmake | 5 + res/rml/popup.rcss | 73 ++++++++++++++ res/rml/popup.rml | 11 +++ src/dusk/ui/nav_types.hpp | 17 ++++ src/dusk/ui/popup.cpp | 191 +++++++++++++++++++++++++++++++++++++ src/dusk/ui/popup.hpp | 47 +++++++++ src/dusk/ui/tab_button.cpp | 24 +++++ src/dusk/ui/tab_button.hpp | 14 +++ src/dusk/ui/ui.cpp | 11 +++ src/dusk/ui/ui.hpp | 17 +--- src/dusk/ui/window.cpp | 29 ++++-- src/dusk/ui/window.hpp | 4 +- src/m_Do/m_Do_main.cpp | 8 +- 13 files changed, 425 insertions(+), 26 deletions(-) create mode 100644 res/rml/popup.rcss create mode 100644 res/rml/popup.rml create mode 100644 src/dusk/ui/nav_types.hpp create mode 100644 src/dusk/ui/popup.cpp create mode 100644 src/dusk/ui/popup.hpp create mode 100644 src/dusk/ui/tab_button.cpp create mode 100644 src/dusk/ui/tab_button.hpp diff --git a/files.cmake b/files.cmake index eca3250d01..f0fa42489a 100644 --- a/files.cmake +++ b/files.cmake @@ -1470,16 +1470,21 @@ set(DUSK_FILES src/dusk/ui/editor.hpp src/dusk/ui/event.cpp src/dusk/ui/event.hpp + src/dusk/ui/nav_types.hpp src/dusk/ui/number_button.cpp src/dusk/ui/number_button.hpp src/dusk/ui/pane.cpp src/dusk/ui/pane.hpp + src/dusk/ui/popup.cpp + src/dusk/ui/popup.hpp src/dusk/ui/select_button.cpp src/dusk/ui/select_button.hpp src/dusk/ui/settings.cpp src/dusk/ui/settings.hpp src/dusk/ui/string_button.cpp src/dusk/ui/string_button.hpp + src/dusk/ui/tab_button.cpp + src/dusk/ui/tab_button.hpp src/dusk/ui/ui.hpp src/dusk/ui/ui.cpp src/dusk/ui/window.hpp diff --git a/res/rml/popup.rcss b/res/rml/popup.rcss new file mode 100644 index 0000000000..52c3e42d5d --- /dev/null +++ b/res/rml/popup.rcss @@ -0,0 +1,73 @@ +*, *:before, *:after { + box-sizing: border-box; +} + +body { + overflow: visible; + width: 100%; + height: 100%; + margin: 0; + padding: 0; + font-family: "Fira Sans Condensed"; + font-weight: bold; + font-size: 18dp; + color: #E0DBC8; +} + +button { + cursor: pointer; + focus: auto; +} + +.popup { + width: 100%; + display: flex; + align-items: stretch; + width: 100%; + height: 64dp; + background-color: rgba(21, 22, 16, 80%); + border-bottom: 2dp #92875B; + backdrop-filter: blur(5dp); + transform: translateY(0); + transition: transform 0.5s cubic-in-out, opacity 0.5s cubic-in-out; +} + +.popup.popup-hidden { + transform: translateY(-100%); +} + +.popup .tab-bar { + display: flex; + flex: 1 1 0; + min-width: 0; + overflow: auto hidden; + text-transform: uppercase; +} + +.popup .tab-bar .tab { + flex: 0 0 auto; + padding: 0 24dp; + line-height: 64dp; + opacity: 0.35; + white-space: nowrap; + color: #E0DBC8; + decorator: vertical-gradient(#c2a42d00 #c2a42d00); + transition: decorator 0.1s linear-in-out, opacity 0.1s linear-in-out; +} + +.popup .tab-bar .tab.selected { + opacity: 1; + border-bottom: 4dp #C2A42D; + font-effect: glow(0dp 4dp 0dp 4dp black); +} + +.popup .tab-bar .tab:focus-visible, +.popup .tab-bar .tab:hover { + opacity: 1; + font-effect: glow(0dp 4dp 0dp 4dp black); + decorator: vertical-gradient(#c2a42d00 #c2a42d26); +} + +.popup .tab-bar .tab:active { + decorator: vertical-gradient(#c2a42d10 #c2a42d40); +} diff --git a/res/rml/popup.rml b/res/rml/popup.rml new file mode 100644 index 0000000000..967c5d9fb3 --- /dev/null +++ b/res/rml/popup.rml @@ -0,0 +1,11 @@ + + + Popup + + + + + + diff --git a/src/dusk/ui/nav_types.hpp b/src/dusk/ui/nav_types.hpp new file mode 100644 index 0000000000..7e485b9e8f --- /dev/null +++ b/src/dusk/ui/nav_types.hpp @@ -0,0 +1,17 @@ +#pragma once + +namespace dusk::ui { + +enum class NavCommand { + None, + Up, + Down, + Left, + Right, + Next, // R1 + Previous, // L1 + Confirm, // A + Cancel, // B +}; + +} // namespace dusk::ui diff --git a/src/dusk/ui/popup.cpp b/src/dusk/ui/popup.cpp new file mode 100644 index 0000000000..103ef79485 --- /dev/null +++ b/src/dusk/ui/popup.cpp @@ -0,0 +1,191 @@ +#include "popup.hpp" + +#include + +#include "aurora/rmlui.hpp" +#include "tab_button.hpp" +#include "ui.hpp" +#include "window.hpp" + +#include +#include +#include +#include + +namespace dusk::ui { + +Popup::Popup(Window& settingsWindow, Window& editorWindow) + : mSettingsWindow(settingsWindow), mEditorWindow(editorWindow) { + auto* context = aurora::rmlui::get_context(); + if (context == nullptr) { + return; + } + + mDocument = context->LoadDocument("res/rml/popup.rml"); + if (mDocument == nullptr) { + return; + } + + auto* tabBar = mDocument->GetElementById("tab-bar"); + if (tabBar == nullptr) { + return; + } + + const std::array tabLabels = { + "Settings", + "Warp", + "Editor", + "Reset", + "Exit", + }; + + // TODO: Make warp, reset, and exit buttons work + mTabActions = { + [this] { + hide(); + mSettingsWindow.show(); + mSettingsWindow.focus_for_input(); + set_selected_tab(0); + }, + [this] { + set_selected_tab(1); + }, + [this] { + hide(); + mEditorWindow.show(); + mEditorWindow.focus_for_input(); + set_selected_tab(2); + }, + [this] { + set_selected_tab(3); + }, + [this] { + set_selected_tab(4); + }, + }; + + mTabs.reserve(tabLabels.size()); + for (int i = 0; i < static_cast(tabLabels.size()); ++i) { + mTabs.push_back(create_tab_button(tabBar, tabLabels[i], i == mSelectedTabIndex, + [this, i](Rml::Event&) { + if (i >= 0 && i < static_cast(mTabActions.size())) { + mTabActions[i](); + } + })); + } + + mKeyListener = std::make_unique( + mDocument, Rml::EventId::Keydown, [this](Rml::Event& event) { + const auto cmd = map_nav_event(event); + if (cmd == NavCommand::None) { + return; + } + if (cmd == NavCommand::Left || cmd == NavCommand::Previous) { + focus_tab(std::max(0, mSelectedTabIndex - 1)); + event.StopPropagation(); + return; + } + if (cmd == NavCommand::Right || cmd == NavCommand::Next) { + focus_tab(std::min(static_cast(mTabs.size()) - 1, mSelectedTabIndex + 1)); + event.StopPropagation(); + return; + } + if (cmd == NavCommand::Confirm && mSelectedTabIndex >= 0 && + mSelectedTabIndex < static_cast(mTabActions.size())) + { + mTabActions[mSelectedTabIndex](); + event.StopPropagation(); + return; + } + if (cmd == NavCommand::Cancel) { + hide(); + event.StopPropagation(); + } + }); +} + +Popup::~Popup() { + auto* context = aurora::rmlui::get_context(); + if (context != nullptr && mDocument != nullptr) { + context->UnloadDocument(mDocument); + } +} + +void Popup::show() { + if (mDocument == nullptr) { + return; + } + + mHideDeadline.reset(); + mDocument->Show(); + mVisible = true; +} + +void Popup::hide() { + if (mDocument == nullptr) { + mVisible = false; + return; + } + + if (auto* popup = mDocument->GetElementById("popup")) { + popup->SetClass("popup-hidden", true); + mHideDeadline = std::chrono::steady_clock::now() + std::chrono::milliseconds(500); // Must match the transition duration in popup.rcss + } else { + mDocument->Hide(); + } + mVisible = false; +} + +void Popup::toggle() { + if (is_visible()) { + hide(); + } else { + show(); + } +} + +bool Popup::is_visible() const { + return mVisible; +} + +void Popup::update() noexcept { + if (mDocument == nullptr) { + return; + } + if (mHideDeadline.has_value() && std::chrono::steady_clock::now() >= *mHideDeadline) { + mDocument->Hide(); + mHideDeadline.reset(); + } + if (mTabs.empty()) { + return; + } + std::vector tabs; + tabs.reserve(mTabs.size()); + for (const auto& tab : mTabs) { + tabs.push_back(tab.get()); + } + dusk::ui::set_selected_tab(tabs, mSelectedTabIndex); +} + +void Popup::set_selected_tab(int index) { + if (index < 0 || index >= static_cast(mTabs.size())) { + return; + } + mSelectedTabIndex = index; + std::vector tabs; + tabs.reserve(mTabs.size()); + for (const auto& tab : mTabs) { + tabs.push_back(tab.get()); + } + dusk::ui::set_selected_tab(tabs, mSelectedTabIndex); +} + +bool Popup::focus_tab(int index) { + if (index < 0 || index >= static_cast(mTabs.size())) { + return false; + } + set_selected_tab(index); + return mTabs[index]->focus(); +} + +} // namespace dusk::ui diff --git a/src/dusk/ui/popup.hpp b/src/dusk/ui/popup.hpp new file mode 100644 index 0000000000..002fffd0ca --- /dev/null +++ b/src/dusk/ui/popup.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include + +#include "button.hpp" +#include "event.hpp" + +#include +#include +#include +#include + +namespace dusk::ui { + +class Window; + +class Popup { +public: + Popup(Window& settingsWindow, Window& editorWindow); + ~Popup(); + + Popup(const Popup&) = delete; + Popup& operator=(const Popup&) = delete; + + void show(); + void hide(); + void toggle(); + bool is_visible() const; + void update() noexcept; + +private: + void set_selected_tab(int index); + bool focus_tab(int index); + + Window& mSettingsWindow; + Window& mEditorWindow; + Rml::ElementDocument* mDocument = nullptr; + std::vector > mTabs; + std::vector > mTabActions; + std::unique_ptr
+ + +)RML"; + +} + +Popup::Popup() : Document(kDocumentSource), mRoot(mDocument->GetElementById("popup")) { mTabBar = std::make_unique(mRoot, TabBar::Props{.autoSelect = false}); mTabBar->add_tab("Settings", [] { push_document(std::make_unique()); }); mTabBar->add_tab("Warp", [] { @@ -48,7 +62,7 @@ void Popup::show() { } Document::show(); - mRoot->SetClass("popup-hidden", false); + mRoot->SetAttribute("open", ""); mTabBar->set_active_tab(-1); mVisible = true; } @@ -62,7 +76,7 @@ void Popup::hide() { return; } - mRoot->SetClass("popup-hidden", true); + mRoot->RemoveAttribute("open"); mVisible = false; } diff --git a/src/dusk/ui/select_button.cpp b/src/dusk/ui/select_button.cpp index 707f605e82..13cfaba37f 100644 --- a/src/dusk/ui/select_button.cpp +++ b/src/dusk/ui/select_button.cpp @@ -9,18 +9,15 @@ namespace { Rml::Element* createRoot(Rml::Element* parent) { auto* doc = parent->GetOwnerDocument(); - auto elem = doc->CreateElement("button"); - elem->SetClass("select-button", true); + auto elem = doc->CreateElement("select-button"); return parent->AppendChild(std::move(elem)); } } // namespace SelectButton::SelectButton(Rml::Element* parent, Props props) : Component(createRoot(parent)) { - mKeyElem = append(mRoot, "div"); - mKeyElem->SetClass("key", true); - mValueElem = append(mRoot, "div"); - mValueElem->SetClass("value", true); + mKeyElem = append(mRoot, "key"); + mValueElem = append(mRoot, "value"); update_props(std::move(props)); listen(mRoot, Rml::EventId::Click, [this](Rml::Event& event) { if (mProps.disabled) { diff --git a/src/dusk/ui/tab_bar.cpp b/src/dusk/ui/tab_bar.cpp index 85bfecc803..5ae696a973 100644 --- a/src/dusk/ui/tab_bar.cpp +++ b/src/dusk/ui/tab_bar.cpp @@ -5,8 +5,7 @@ namespace { Rml::Element* createRoot(Rml::Element* parent) { auto* doc = parent->GetOwnerDocument(); - auto elem = doc->CreateElement("div"); - elem->SetClass("tab-bar", true); + auto elem = doc->CreateElement("tab-bar"); return parent->AppendChild(std::move(elem)); } diff --git a/src/dusk/ui/ui.cpp b/src/dusk/ui/ui.cpp index bbd69558a2..f531a8674b 100644 --- a/src/dusk/ui/ui.cpp +++ b/src/dusk/ui/ui.cpp @@ -87,8 +87,8 @@ Document* top_document() noexcept { } void update() noexcept { - for (size_t i = 0; i < sDocuments.size(); ++i) { - sDocuments[i].doc->update(); + for (const auto& doc : sDocuments) { + doc.doc->update(); } sDocuments.erase( std::remove_if(sDocuments.begin(), sDocuments.end(), diff --git a/src/dusk/ui/window.cpp b/src/dusk/ui/window.cpp index 3ad4cd559b..45459517b2 100644 --- a/src/dusk/ui/window.cpp +++ b/src/dusk/ui/window.cpp @@ -23,17 +23,27 @@ float base_body_padding(Rml::Context* context) noexcept { return 64.0f * dpRatio; } +const Rml::String kDocumentSource = R"RML( + + + + + + + + +)RML"; + } // namespace -Window::Window() : Document("res/rml/window.rml"), mRoot(mDocument->GetElementById("window")) { +Window::Window() : Document(kDocumentSource), mRoot(mDocument->GetElementById("window")) { mTabBar = std::make_unique(mRoot, TabBar::Props{ .selectedTabIndex = 0, .autoSelect = true, }); - auto elem = mDocument->CreateElement("div"); + auto elem = mDocument->CreateElement("content"); elem->SetAttribute("id", "content"); - elem->SetClass("content", true); mContentRoot = mRoot->AppendChild(std::move(elem)); listen(Rml::EventId::Keydown, [this](Rml::Event& event) { @@ -49,6 +59,39 @@ Window::Window() : Document("res/rml/window.rml"), mRoot(mDocument->GetElementBy } } }); + + // Hide document after transition completion + listen(mRoot, Rml::EventId::Transitionend, [this](Rml::Event& event) { + if (event.GetTargetElement() == mRoot && + *mRoot->GetProperty(Rml::PropertyId::Visibility) == Rml::Style::Visibility::Visible && + !mVisible) + { + Document::hide(); + } + }); +} + +void Window::show() { + if (mVisible) { + return; + } + + Document::show(); + mRoot->SetAttribute("open", ""); + mVisible = true; +} + +void Window::hide() { + if (mDocument == nullptr) { + mVisible = false; + return; + } + if (!mVisible) { + return; + } + + mRoot->RemoveAttribute("open"); + mVisible = false; } void Window::update() { @@ -114,7 +157,7 @@ bool Window::focus() { bool Window::handle_nav_command(Rml::Event& event, NavCommand cmd) { auto* target = event.GetTargetElement(); - if (cmd != NavCommand::Next && cmd != NavCommand::Previous && target->Closest(".content")) { + if (cmd != NavCommand::Next && cmd != NavCommand::Previous && target->Closest("content")) { if (handle_content_nav(event, cmd)) { return true; } diff --git a/src/dusk/ui/window.hpp b/src/dusk/ui/window.hpp index 4576740182..ffc69f2022 100644 --- a/src/dusk/ui/window.hpp +++ b/src/dusk/ui/window.hpp @@ -23,6 +23,8 @@ public: Window(const Window&) = delete; Window& operator=(const Window&) = delete; + void show() override; + void hide() override; void update() override; bool focus() override; bool set_active_tab(int index); @@ -47,6 +49,7 @@ protected: std::unique_ptr mTabBar; std::vector > mContentComponents; Insets mBodyPadding; + bool mVisible = false; }; } // namespace dusk::ui From 2cc9db77dd7470cce7836691f22d2f62c5e92cb4 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Thu, 30 Apr 2026 21:10:48 -0600 Subject: [PATCH 152/390] Fix overlay --- res/rml/overlay.rml | 22 ---------------------- src/dusk/ui/overlay.cpp | 26 +++++++++++++++++++++++++- 2 files changed, 25 insertions(+), 23 deletions(-) delete mode 100644 res/rml/overlay.rml diff --git a/res/rml/overlay.rml b/res/rml/overlay.rml deleted file mode 100644 index b9456289fc..0000000000 --- a/res/rml/overlay.rml +++ /dev/null @@ -1,22 +0,0 @@ - - - Overlay - - - -
-
-
-
- -
-
-
- -
-
- -
diff --git a/src/dusk/ui/overlay.cpp b/src/dusk/ui/overlay.cpp index 14a1e43ab4..301f12e06b 100644 --- a/src/dusk/ui/overlay.cpp +++ b/src/dusk/ui/overlay.cpp @@ -12,6 +12,30 @@ namespace dusk::ui { namespace { +const Rml::String kDocumentSource = R"RML( + + + + + +
+
+
+
+ +
+
+
+ +
+
+ +
+)RML"; + int get_value(GraphicsOption option) { switch (option) { case GraphicsOption::InternalResolution: @@ -132,7 +156,7 @@ Rml::String format_graphics_setting_value(GraphicsOption option, int value) { } Overlay::Overlay(OverlayProps props) - : Document("res/rml/overlay.rml"), + : Document(kDocumentSource), mOption(props.option), mValueMin(props.valueMin), mValueMax(props.valueMax) { From 9dc5fed6869e014da2d7ea3047c4a4152dea245c Mon Sep 17 00:00:00 2001 From: Luke Street Date: Thu, 30 Apr 2026 21:12:25 -0600 Subject: [PATCH 153/390] Fix overlay CSS --- res/rml/overlay.rcss | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/res/rml/overlay.rcss b/res/rml/overlay.rcss index de26e7188d..a493616ac9 100644 --- a/res/rml/overlay.rcss +++ b/res/rml/overlay.rcss @@ -101,7 +101,7 @@ button { justify-content: flex-end; } -.footer-button { +footer-button { display: block; width: 100%; max-width: 220dp; @@ -117,11 +117,11 @@ button { opacity: 1; } -.footer-button.return { +footer-button.return { text-align: left; } -.footer-button.reset { +footer-button.reset { text-align: right; } From 9629c000bdd49987613ce5a1652d7a142149b5db Mon Sep 17 00:00:00 2001 From: doop <56421834+dooplecks@users.noreply.github.com> Date: Fri, 1 May 2026 03:25:07 +0000 Subject: [PATCH 154/390] Interpolate shadow camera Fixes #454. --- src/d/d_drawlist.cpp | 54 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/src/d/d_drawlist.cpp b/src/d/d_drawlist.cpp index 373791f994..1f16b2f655 100644 --- a/src/d/d_drawlist.cpp +++ b/src/d/d_drawlist.cpp @@ -22,6 +22,10 @@ #include "dusk/frame_interpolation.h" #include "dusk/gx_helper.h" #include "dusk/logging.h" + +static const void* getInterpKey(const void* base, int idx) { + return reinterpret_cast(reinterpret_cast(base) ^ idx); +} #endif class dDlst_2Dm_c { @@ -1062,7 +1066,15 @@ void dDlst_shadowReal_c::reset() { } void dDlst_shadowReal_c::imageDraw(Mtx param_0) { - GXSetProjection(mRenderProjMtx, GX_ORTHOGRAPHIC); +#ifdef TARGET_PC + Mtx render_proj_mtx; + if (dusk::frame_interp::lookup_replacement(getInterpKey(mpModels[0], 2), render_proj_mtx)) { + GXSetProjection(render_proj_mtx, GX_ORTHOGRAPHIC); + } else +#endif + { + GXSetProjection(mRenderProjMtx, GX_ORTHOGRAPHIC); + } JUT_ASSERT(1916, mModelNum); J3DModelData* model_data; J3DModel** models = mpModels; @@ -1075,7 +1087,15 @@ void dDlst_shadowReal_c::imageDraw(Mtx param_0) { for (u16 j = 0; j < model_data->getShapeNum(); j++) { if (!model_data->getShapeNodePointer(j)->checkFlag(1)) { shape_pkt = (*models)->getShapePacket(j); - shape_pkt->setBaseMtxPtr(&mViewMtx); +#ifdef TARGET_PC + Mtx view_mtx; + if (dusk::frame_interp::lookup_replacement(getInterpKey(mpModels[0], 1), view_mtx)) { + shape_pkt->setBaseMtxPtr(&view_mtx); + } else +#endif + { + shape_pkt->setBaseMtxPtr(&mViewMtx); + } shape_pkt->drawFast(); shape_pkt->setBaseMtxPtr((Mtx*)param_0); } @@ -1096,7 +1116,18 @@ void dDlst_shadowReal_c::draw() { GXSetVtxDesc(GX_VA_POS, GX_DIRECT); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0); GXSetCurrentMtx(GX_PNMTX0); - GXLoadTexMtxImm(mReceiverProjMtx, GX_TEXMTX0, GX_MTX3x4); +#ifdef TARGET_PC + Mtx view_mtx, recv_proj_mtx; + const auto have_view_mtx = dusk::frame_interp::lookup_replacement(getInterpKey(mpModels[0], 1), view_mtx); + const auto have_recv_proj_mtx = dusk::frame_interp::lookup_replacement(getInterpKey(mpModels[0], 3), recv_proj_mtx); + if (have_view_mtx && have_recv_proj_mtx) { + cMtx_concat(recv_proj_mtx, view_mtx, recv_proj_mtx); + GXLoadTexMtxImm(recv_proj_mtx, GX_TEXMTX0, GX_MTX3x4); + } else +#endif + { + GXLoadTexMtxImm(mReceiverProjMtx, GX_TEXMTX0, GX_MTX3x4); + } mShadowRealPoly.draw(); } @@ -1253,6 +1284,13 @@ u8 dDlst_shadowReal_c::setShadowRealMtx(cXyz* param_0, cXyz* param_1, f32 param_ cMtx_lookAt(mViewMtx, &local_64, param_1, 0); C_MTXOrtho(mRenderProjMtx, param_2, -param_2, -param_2, param_2, 1.0f, 10000.0f); C_MTXLightOrtho(mReceiverProjMtx, param_2, -param_2, -param_2, param_2, 0.5f, -0.5f, 0.5f, 0.5f); + +#ifdef TARGET_PC + const auto keybase = mpModels[0]; + dusk::frame_interp::record_final_mtx(mViewMtx, getInterpKey(keybase, 1)); + dusk::frame_interp::record_final_mtx(mRenderProjMtx, getInterpKey(keybase, 2)); + dusk::frame_interp::record_final_mtx(mReceiverProjMtx, getInterpKey(keybase, 3)); +#endif cMtx_concat(mReceiverProjMtx, mViewMtx, mReceiverProjMtx); return r29; } @@ -1277,6 +1315,10 @@ u32 dDlst_shadowReal_c::set(u32 i_key, J3DModel* i_model, cXyz* param_2, f32 par } } +#ifdef TARGET_PC + // provide a stable key for interpolation + mpModels[0] = i_model; +#endif field_0x1 = setShadowRealMtx(&sp60, param_2, param_3, param_4, param_7, param_5); if (!field_0x1) { @@ -1370,12 +1412,6 @@ void dDlst_shadowSimple_c::draw() { GXCallDisplayList(l_shadowVolumeDL, 0x40); } -#if TARGET_PC -static const void* getInterpKey(const void* base, int idx) { - return reinterpret_cast(reinterpret_cast(base) ^ idx); -} -#endif - void dDlst_shadowSimple_c::set(cXyz* param_0, f32 param_1, f32 param_2, cXyz* param_3, s16 param_4, f32 param_5, TGXTexObj* param_6) { if (param_5 < 0.0f) { From 32b4c0567a99f7f87fa3abe30777c51b4e9f780f Mon Sep 17 00:00:00 2001 From: Luke Street Date: Thu, 30 Apr 2026 22:17:48 -0600 Subject: [PATCH 155/390] Animate overlay open/close --- extern/aurora | 2 +- res/rml/overlay.rcss | 8 +++++++- src/dusk/ui/overlay.cpp | 35 ++++++++++++++++++++++++----------- src/dusk/ui/overlay.hpp | 4 +++- 4 files changed, 35 insertions(+), 14 deletions(-) diff --git a/extern/aurora b/extern/aurora index 285c11a13c..d950468064 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 285c11a13c9200be196a3c407e31a642824658a9 +Subproject commit d9504680642bae0f862b8928f1ee42be3c9b274a diff --git a/res/rml/overlay.rcss b/res/rml/overlay.rcss index a493616ac9..60788b0e75 100644 --- a/res/rml/overlay.rcss +++ b/res/rml/overlay.rcss @@ -24,8 +24,14 @@ body { flex-direction: column; justify-content: flex-end; align-items: stretch; - decorator: linear-gradient(0deg, #151610F2 0%, #151610CC 60%, #00000000 100%); + decorator: vertical-gradient(#00000000 #151610F2); padding: 48dp 0 40dp 0; + filter: opacity(0); + transition: filter 0.2s linear-in-out; +} + +.overlay-root[open] { + filter: opacity(1); } button { diff --git a/src/dusk/ui/overlay.cpp b/src/dusk/ui/overlay.cpp index 301f12e06b..ef1a98ad91 100644 --- a/src/dusk/ui/overlay.cpp +++ b/src/dusk/ui/overlay.cpp @@ -18,7 +18,7 @@ const Rml::String kDocumentSource = R"RML( -
+
@@ -193,7 +193,7 @@ Overlay::Overlay(OverlayProps props) add_component
- +
@@ -183,14 +180,12 @@ Overlay::Overlay(OverlayProps props) }); } - if (auto* returnParent = mDocument->GetElementById("return")) { - auto& returnButton = - add_component
+ )RML"; diff --git a/src/dusk/ui/select_button.cpp b/src/dusk/ui/select_button.cpp index 95cffd873d..73742a60c2 100644 --- a/src/dusk/ui/select_button.cpp +++ b/src/dusk/ui/select_button.cpp @@ -2,6 +2,7 @@ #include "ui.hpp" +#include #include namespace dusk::ui { @@ -23,9 +24,29 @@ SelectButton::SelectButton(Rml::Element* parent, Props props) on_nav_command([this](Rml::Event&, NavCommand cmd) { return handle_nav_command(cmd); }); } +bool SelectButton::modified() const { + return mProps.modified; +} + +void SelectButton::set_modified(bool value) { + if (mProps.modified != value) { + mValueElem->SetClass("modified", value); + if (value) { + mValueElem->SetInnerRML(fmt::format("• {}", escape(mProps.value))); + } else { + mValueElem->SetInnerRML(escape(mProps.value)); + } + mProps.modified = value; + } +} + void SelectButton::set_value_label(const Rml::String& value) { if (mProps.value != value) { - mValueElem->SetInnerRML(escape(value)); + if (mProps.modified) { + mValueElem->SetInnerRML(fmt::format("• {}", escape(value))); + } else { + mValueElem->SetInnerRML(escape(value)); + } mProps.value = value; } } @@ -35,6 +56,7 @@ void SelectButton::update_props(Props props) { mKeyElem->SetInnerRML(escape(props.key)); } set_value_label(props.value); + set_modified(props.modified); mProps = std::move(props); } @@ -49,9 +71,17 @@ bool SelectButton::handle_nav_command(NavCommand cmd) { void BaseControlledSelectButton::update() { set_disabled(disabled()); set_value_label(format_value()); + set_modified(modified()); SelectButton::update(); } +bool ControlledSelectButton::modified() const { + if (mIsModified) { + return mIsModified(); + } + return BaseControlledSelectButton::modified(); +} + bool ControlledSelectButton::disabled() const { if (mIsDisabled) { return mIsDisabled(); diff --git a/src/dusk/ui/select_button.hpp b/src/dusk/ui/select_button.hpp index 4a9612076d..4640f7235f 100644 --- a/src/dusk/ui/select_button.hpp +++ b/src/dusk/ui/select_button.hpp @@ -10,10 +10,13 @@ public: struct Props { Rml::String key; Rml::String value; + bool modified = false; }; SelectButton(Rml::Element* parent, Props props); + virtual bool modified() const; + void set_modified(bool value); void set_value_label(const Rml::String& value); protected: @@ -23,7 +26,6 @@ protected: Props mProps; Rml::Element* mKeyElem = nullptr; Rml::Element* mValueElem = nullptr; - std::function mOnHover; }; class BaseControlledSelectButton : public SelectButton { @@ -43,12 +45,15 @@ public: Rml::String key; std::function getValue; std::function isDisabled; + std::function isModified; }; ControlledSelectButton(Rml::Element* parent, Props props) : BaseControlledSelectButton(parent, {std::move(props.key)}), - mGetValue(std::move(props.getValue)), mIsDisabled(std::move(props.isDisabled)) {} + mGetValue(std::move(props.getValue)), mIsDisabled(std::move(props.isDisabled)), + mIsModified(std::move(props.isModified)) {} + bool modified() const override; bool disabled() const override; protected: @@ -56,6 +61,7 @@ protected: std::function mGetValue; std::function mIsDisabled; + std::function mIsModified; }; } // namespace dusk::ui diff --git a/src/dusk/ui/settings.cpp b/src/dusk/ui/settings.cpp index 2cdb2d50d9..1f32071d37 100644 --- a/src/dusk/ui/settings.cpp +++ b/src/dusk/ui/settings.cpp @@ -81,8 +81,7 @@ struct ConfigBoolProps { SelectButton& config_bool_select( Pane& leftPane, Pane& rightPane, ConfigVar& var, ConfigBoolProps props) { return leftPane - .add_child(BoolButton::Props{ - .key = std::move(props.key), + .add_child(BoolButton::Props{.key = std::move(props.key), .getValue = [&var] { return var.getValue(); }, .setValue = [&var, callback = std::move(props.onChange)](bool value) { @@ -96,7 +95,7 @@ SelectButton& config_bool_select( } }, .isDisabled = std::move(props.isDisabled), - }) + .isModified = [&var] { return var.getValue() != var.getDefaultValue(); }}) .on_focus([&rightPane, helpText = std::move(props.helpText)](Rml::Event&) { rightPane.clear(); rightPane.add_rml(helpText); @@ -116,6 +115,7 @@ SelectButton& config_percent_select(Pane& leftPane, Pane& rightPane, ConfigVar(getSettings().game.bloomMode.getValue())); }, + .isModified = + [] { + return getSettings().game.bloomMode.getValue() != + getSettings().game.bloomMode.getDefaultValue(); + }, }) .on_nav_command([](Rml::Event&, NavCommand cmd) { if (cmd == NavCommand::Confirm || cmd == NavCommand::Left || @@ -559,6 +584,11 @@ SettingsWindow::SettingsWindow() { }, .isDisabled = [] { return getSettings().game.bloomMode.getValue() == BloomMode::Off; }, + .isModified = + [] { + return getSettings().game.bloomMultiplier.getValue() != + getSettings().game.bloomMultiplier.getDefaultValue(); + }, }) .on_nav_command([](Rml::Event&, NavCommand cmd) { if (cmd == NavCommand::Confirm || cmd == NavCommand::Left || @@ -619,7 +649,6 @@ SettingsWindow::SettingsWindow() { "- Account Username" }); #endif - leftPane.add_section("Advanced"); config_bool_select(leftPane, rightPane, getSettings().backend.skipPreLaunchUI, { .key = "Skip Pre-Launch UI", diff --git a/src/dusk/ui/ui.cpp b/src/dusk/ui/ui.cpp index a0764ecf08..10a62436b5 100644 --- a/src/dusk/ui/ui.cpp +++ b/src/dusk/ui/ui.cpp @@ -33,6 +33,7 @@ bool initialize() noexcept { } load_font("FiraSans-Regular.ttf", true); + load_font("FiraSans-Bold.ttf"); load_font("FiraSansCondensed-Regular.ttf"); load_font("FiraSansCondensed-Bold.ttf"); load_font("AlegreyaSC-Regular.ttf"); From 924dbc77154674741b8b25a92a2fbd4fcfb18f6c Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sun, 3 May 2026 17:16:15 -0600 Subject: [PATCH 217/390] UI: Implement controller config Resolves #622 --- extern/aurora | 2 +- files.cmake | 2 + src/dusk/ui/controller_config.cpp | 617 ++++++++++++++++++++++++++++++ src/dusk/ui/controller_config.hpp | 45 +++ src/dusk/ui/event.cpp | 13 +- src/dusk/ui/event.hpp | 3 + src/dusk/ui/input.cpp | 39 +- src/dusk/ui/select_button.cpp | 12 + src/dusk/ui/select_button.hpp | 6 + src/dusk/ui/settings.cpp | 15 +- 10 files changed, 737 insertions(+), 17 deletions(-) create mode 100644 src/dusk/ui/controller_config.cpp create mode 100644 src/dusk/ui/controller_config.hpp diff --git a/extern/aurora b/extern/aurora index 1def8fa1ef..935756010c 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 1def8fa1efee3bb7ac0835b9733861427e00097b +Subproject commit 935756010cbe02c04ce78bc5ccb7185c271040d6 diff --git a/files.cmake b/files.cmake index 64cb21d225..d238203776 100644 --- a/files.cmake +++ b/files.cmake @@ -1469,6 +1469,8 @@ set(DUSK_FILES src/dusk/ui/button.hpp src/dusk/ui/component.cpp src/dusk/ui/component.hpp + src/dusk/ui/controller_config.cpp + src/dusk/ui/controller_config.hpp src/dusk/ui/document.cpp src/dusk/ui/document.hpp src/dusk/ui/editor.cpp diff --git a/src/dusk/ui/controller_config.cpp b/src/dusk/ui/controller_config.cpp new file mode 100644 index 0000000000..af39782c02 --- /dev/null +++ b/src/dusk/ui/controller_config.cpp @@ -0,0 +1,617 @@ +#include "controller_config.hpp" + +#include "bool_button.hpp" +#include "button.hpp" +#include "pane.hpp" +#include "select_button.hpp" + +#include +#include + +#include +#include +#include +#include + +namespace dusk::ui { +namespace { + +Rml::String current_controller_name(int port) { + const char* name = PADGetName(port); + return name == nullptr ? "None" : name; +} + +Rml::String controller_index_name(u32 index) { + const char* name = PADGetNameForControllerIndex(index); + if (name == nullptr) { + return fmt::format("Controller {}", index + 1); + } + return name; +} + +SDL_Gamepad* gamepad_for_port(int port) { + const s32 index = PADGetIndexForPort(port); + if (index < 0) { + return nullptr; + } + return PADGetSDLGamepadForIndex(static_cast(index)); +} + +struct SpecificButtonName { + SDL_GamepadType type; + const char* name; +}; + +struct ButtonNames { + SDL_GamepadButton button; + std::vector names; +}; + +// clang-format off +const std::vector kGamepadButtonNames = { + { SDL_GAMEPAD_BUTTON_LEFT_STICK, { + {SDL_GAMEPAD_TYPE_PS3, "L3"}, + {SDL_GAMEPAD_TYPE_PS4, "L3"}, + {SDL_GAMEPAD_TYPE_PS5, "L3"}, + {SDL_GAMEPAD_TYPE_XBOX360, "Left Stick"}, + {SDL_GAMEPAD_TYPE_XBOXONE, "Left Stick"}, + {SDL_GAMEPAD_TYPE_GAMECUBE, "Control Stick"}, + }}, + { SDL_GAMEPAD_BUTTON_RIGHT_STICK, { + {SDL_GAMEPAD_TYPE_PS3, "R3"}, + {SDL_GAMEPAD_TYPE_PS4, "R3"}, + {SDL_GAMEPAD_TYPE_PS5, "R3"}, + {SDL_GAMEPAD_TYPE_XBOX360, "Right Stick"}, + {SDL_GAMEPAD_TYPE_XBOXONE, "Right Stick"}, + {SDL_GAMEPAD_TYPE_GAMECUBE, "C Stick"}, + }}, + { SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, { + {SDL_GAMEPAD_TYPE_PS3, "L1"}, + {SDL_GAMEPAD_TYPE_PS4, "L1"}, + {SDL_GAMEPAD_TYPE_PS5, "L1"}, + {SDL_GAMEPAD_TYPE_XBOX360, "LB"}, + {SDL_GAMEPAD_TYPE_XBOXONE, "LB"}, + }}, + { SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, { + {SDL_GAMEPAD_TYPE_PS3, "R1"}, + {SDL_GAMEPAD_TYPE_PS4, "R1"}, + {SDL_GAMEPAD_TYPE_PS5, "R1"}, + {SDL_GAMEPAD_TYPE_XBOX360, "RB"}, + {SDL_GAMEPAD_TYPE_XBOXONE, "RB"}, + {SDL_GAMEPAD_TYPE_GAMECUBE, "Z"}, + }}, + { SDL_GAMEPAD_BUTTON_BACK, { + {SDL_GAMEPAD_TYPE_PS3, "Select"}, + {SDL_GAMEPAD_TYPE_PS4, "Share"}, + {SDL_GAMEPAD_TYPE_PS5, "Create"}, + {SDL_GAMEPAD_TYPE_XBOX360, "Back"}, + {SDL_GAMEPAD_TYPE_XBOXONE, "View"}, + }}, + { SDL_GAMEPAD_BUTTON_START, { + {SDL_GAMEPAD_TYPE_PS3, "Start"}, + {SDL_GAMEPAD_TYPE_PS4, "Options"}, + {SDL_GAMEPAD_TYPE_PS5, "Options"}, + {SDL_GAMEPAD_TYPE_XBOX360, "Start"}, + {SDL_GAMEPAD_TYPE_XBOXONE, "Menu"}, + {SDL_GAMEPAD_TYPE_GAMECUBE, "Start/Pause"}, + }}, +}; +// clang-format on + +Rml::String native_button_name(SDL_Gamepad* gamepad, u32 buttonUntyped) { + if (buttonUntyped == PAD_NATIVE_BUTTON_INVALID) { + return "Not bound"; + } + + auto button = static_cast(buttonUntyped); + if (gamepad != nullptr) { + switch (SDL_GetGamepadButtonLabel(gamepad, button)) { + case SDL_GAMEPAD_BUTTON_LABEL_A: + return "A"; + case SDL_GAMEPAD_BUTTON_LABEL_B: + return "B"; + case SDL_GAMEPAD_BUTTON_LABEL_X: + return "X"; + case SDL_GAMEPAD_BUTTON_LABEL_Y: + return "Y"; + case SDL_GAMEPAD_BUTTON_LABEL_CROSS: + return "Cross"; + case SDL_GAMEPAD_BUTTON_LABEL_CIRCLE: + return "Circle"; + case SDL_GAMEPAD_BUTTON_LABEL_TRIANGLE: + return "Triangle"; + case SDL_GAMEPAD_BUTTON_LABEL_SQUARE: + return "Square"; + default: + break; + } + } + + const SDL_GamepadType type = + gamepad != nullptr ? SDL_GetGamepadType(gamepad) : SDL_GAMEPAD_TYPE_UNKNOWN; + for (const auto& buttonNames : kGamepadButtonNames) { + if (buttonNames.button != button) { + continue; + } + + for (const auto& name : buttonNames.names) { + if (name.type == type) { + return name.name; + } + } + } + + switch (button) { + case SDL_GAMEPAD_BUTTON_DPAD_LEFT: + return "D-pad left"; + case SDL_GAMEPAD_BUTTON_DPAD_RIGHT: + return "D-pad right"; + case SDL_GAMEPAD_BUTTON_DPAD_UP: + return "D-pad up"; + case SDL_GAMEPAD_BUTTON_DPAD_DOWN: + return "D-pad down"; + default: + break; + } + + if (const char* name = PADGetNativeButtonName(buttonUntyped)) { + return name; + } + return "Unknown"; +} + +Rml::String native_axis_name(const PADAxisMapping& mapping, SDL_Gamepad* gamepad) { + if (mapping.nativeAxis.nativeAxis != -1) { + Rml::String value = PADGetNativeAxisName(mapping.nativeAxis); + if (mapping.padAxis != PAD_AXIS_TRIGGER_L && mapping.padAxis != PAD_AXIS_TRIGGER_R) { + value += mapping.nativeAxis.sign == AXIS_SIGN_POSITIVE ? "+" : "-"; + } + return value; + } + + if (mapping.nativeButton != -1) { + return native_button_name(gamepad, static_cast(mapping.nativeButton)); + } + + return "Not bound"; +} + +bool is_dpad_button(PADButton button) { + return button == PAD_BUTTON_UP || button == PAD_BUTTON_DOWN || button == PAD_BUTTON_LEFT || + button == PAD_BUTTON_RIGHT; +} + +bool is_action_button(PADButton button) { + return button == PAD_BUTTON_A || button == PAD_BUTTON_B || button == PAD_BUTTON_X || + button == PAD_BUTTON_Y || button == PAD_BUTTON_START || button == PAD_TRIGGER_Z; +} + +bool input_neutral(int port) { + if (port < 0) { + return true; + } + return PADGetNativeButtonPressed(port) == -1 && PADGetNativeAxisPulled(port).nativeAxis == -1; +} + +} // namespace + +ControllerConfigWindow::ControllerConfigWindow() { + listen( + Rml::EventId::Keydown, + [this](Rml::Event& event) { + if (capture_active() || mSuppressNavigationUntilNeutral) { + event.StopPropagation(); + } + }, + true); + if (auto* context = mDocument != nullptr ? mDocument->GetContext() : nullptr) { + if (auto* root = context->GetRootElement()) { + mListeners.emplace_back(std::make_unique( + root, "controllerchange", [this](Rml::Event&) { refresh_controller_page(); })); + } + } + + for (int port = PAD_CHAN0; port < PAD_CHANMAX; ++port) { + add_tab(fmt::format("Port {}", port + 1), [this, port](Rml::Element* content) { + if (mPendingPort != -1 && mPendingPort != port) { + cancel_pending_binding(); + } + build_port_tab(content, port); + }); + } +} + +void ControllerConfigWindow::hide(bool close) { + cancel_pending_binding(); + Window::hide(close); +} + +void ControllerConfigWindow::update() { + poll_pending_binding(); + Window::update(); +} + +void ControllerConfigWindow::build_port_tab(Rml::Element* content, int port) { + auto& leftPane = add_child(content, Pane::Type::Controlled); + auto& rightPane = add_child(content, Pane::Type::Uncontrolled); + mRightPane = &rightPane; + mActivePort = port; + + auto showPage = [this, &rightPane, port](Page page) { + mPage = page; + render_page(rightPane, port, page); + }; + auto addPageButton = [&leftPane, showPage](Page page, Rml::String key, auto getValue) { + leftPane + .add_select_button({ + .key = std::move(key), + .getValue = std::move(getValue), + }) + .on_focus([showPage, page](Rml::Event&) { showPage(page); }) + .on_pressed([showPage, page] { showPage(page); }); + }; + + addPageButton(Page::Controller, "Controller", [port] { return current_controller_name(port); }); + addPageButton(Page::Buttons, "Buttons", [] { return Rml::String(">"); }); + addPageButton(Page::Triggers, "Triggers", [] { return Rml::String(">"); }); + addPageButton(Page::Sticks, "Sticks", [] { return Rml::String(">"); }); + + leftPane.add_section("Options"); + leftPane + .add_child(BoolButton::Props{ + .key = "Enable Dead Zones", + .getValue = + [port] { + PADDeadZones* deadZones = PADGetDeadZones(port); + return deadZones != nullptr && deadZones->useDeadzones; + }, + .setValue = + [port](bool value) { + if (PADDeadZones* deadZones = PADGetDeadZones(port)) { + deadZones->useDeadzones = value; + PADSerializeMappings(); + } + }, + .isDisabled = [port] { return PADGetDeadZones(port) == nullptr; }, + }) + .on_focus([&rightPane](Rml::Event&) { + rightPane.clear(); + rightPane.add_text("Apply configured dead zones to the sticks and analog triggers."); + }); + leftPane + .add_child(BoolButton::Props{ + .key = "Emulate Triggers", + .getValue = + [port] { + PADDeadZones* deadZones = PADGetDeadZones(port); + return deadZones != nullptr && deadZones->emulateTriggers; + }, + .setValue = + [port](bool value) { + if (PADDeadZones* deadZones = PADGetDeadZones(port)) { + deadZones->emulateTriggers = value; + PADSerializeMappings(); + } + }, + .isDisabled = [port] { return PADGetDeadZones(port) == nullptr; }, + }) + .on_focus([&rightPane](Rml::Event&) { + rightPane.clear(); + rightPane.add_text("Treat analog trigger movement as digital L and R button input."); + }); + + render_page(rightPane, port, mPage); +} + +void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) { + pane.clear(); + + switch (page) { + case Page::Controller: { + const u32 controllerCount = PADCount(); + if (controllerCount == 0) { + pane.add_text("No controllers detected"); + break; + } + + pane.add_button({ + .text = "None", + .isSelected = [port] { return PADGetIndexForPort(port) < 0; }, + }) + .on_pressed([this, port] { + cancel_pending_binding(); + PADClearPort(port); + PADSerializeMappings(); + }); + + for (u32 i = 0; i < controllerCount; ++i) { + pane.add_button( + { + .text = controller_index_name(i), + .isSelected = + [port, i] { return PADGetIndexForPort(port) == static_cast(i); }, + }) + .on_pressed([this, port, i] { + cancel_pending_binding(); + PADSetPortForIndex(i, port); + PADSerializeMappings(); + }); + } + break; + } + case Page::Buttons: { + u32 buttonCount = 0; + PADButtonMapping* mappings = PADGetButtonMappings(port, &buttonCount); + if (mappings == nullptr) { + pane.add_text("No controller selected"); + break; + } + + SDL_Gamepad* gamepad = gamepad_for_port(port); + pane.add_section("Buttons"); + for (u32 i = 0; i < buttonCount; ++i) { + PADButtonMapping& mapping = mappings[i]; + if (!is_action_button(mapping.padButton)) { + continue; + } + + pane.add_select_button({ + .key = PADGetButtonName(mapping.padButton), + .getValue = + [this, &mapping, gamepad] { + if (mPendingButtonMapping == &mapping) { + return pending_button_label(); + } + return native_button_name( + gamepad, mapping.nativeButton); + }, + }) + .on_pressed([this, port, &mapping] { + cancel_pending_binding(); + mPendingPort = port; + mPendingBindingArmed = false; + mPendingButtonMapping = &mapping; + }); + } + + pane.add_section("D-Pad"); + for (u32 i = 0; i < buttonCount; ++i) { + PADButtonMapping& mapping = mappings[i]; + if (!is_dpad_button(mapping.padButton)) { + continue; + } + + pane.add_select_button({ + .key = PADGetButtonName(mapping.padButton), + .getValue = + [this, &mapping, gamepad] { + if (mPendingButtonMapping == &mapping) { + return pending_button_label(); + } + return native_button_name( + gamepad, mapping.nativeButton); + }, + }) + .on_pressed([this, port, &mapping] { + cancel_pending_binding(); + mPendingPort = port; + mPendingBindingArmed = false; + mPendingButtonMapping = &mapping; + }); + } + break; + } + case Page::Triggers: { + u32 axisCount = 0; + PADAxisMapping* axes = PADGetAxisMappings(port, &axisCount); + u32 buttonCount = 0; + PADButtonMapping* buttons = PADGetButtonMappings(port, &buttonCount); + if (axes == nullptr && buttons == nullptr) { + pane.add_text("No controller selected"); + break; + } + + SDL_Gamepad* gamepad = gamepad_for_port(port); + pane.add_section("Analog"); + constexpr std::array kTriggerAxes = {PAD_AXIS_TRIGGER_L, PAD_AXIS_TRIGGER_R}; + if (axes != nullptr) { + for (PADAxis axis : kTriggerAxes) { + if (axis >= axisCount) { + continue; + } + PADAxisMapping& mapping = axes[axis]; + pane.add_select_button({ + .key = PADGetAxisName(mapping.padAxis), + .getValue = + [this, &mapping, gamepad] { + if (mPendingAxisMapping == &mapping) { + return pending_axis_label(); + } + return native_axis_name(mapping, gamepad); + }, + }) + .on_pressed([this, port, &mapping] { + cancel_pending_binding(); + mPendingPort = port; + mPendingBindingArmed = false; + mPendingAxisMapping = &mapping; + }); + } + } + + pane.add_section("Digital"); + if (buttons != nullptr) { + for (u32 i = 0; i < buttonCount; ++i) { + PADButtonMapping& mapping = buttons[i]; + if (mapping.padButton != PAD_TRIGGER_L && mapping.padButton != PAD_TRIGGER_R) { + continue; + } + pane.add_select_button({ + .key = PADGetButtonName(mapping.padButton), + .getValue = + [this, &mapping, gamepad] { + if (mPendingButtonMapping == &mapping) { + return pending_button_label(); + } + return native_button_name( + gamepad, mapping.nativeButton); + }, + }) + .on_pressed([this, port, &mapping] { + cancel_pending_binding(); + mPendingPort = port; + mPendingBindingArmed = false; + mPendingButtonMapping = &mapping; + }); + } + } + break; + } + case Page::Sticks: { + u32 axisCount = 0; + PADAxisMapping* axes = PADGetAxisMappings(port, &axisCount); + if (axes == nullptr) { + pane.add_text("No controller selected"); + break; + } + + SDL_Gamepad* gamepad = gamepad_for_port(port); + auto addAxis = [&](PADAxis axis) { + if (axis >= axisCount) { + return; + } + PADAxisMapping& mapping = axes[axis]; + pane.add_select_button({ + .key = PADGetAxisDirectionLabel(mapping.padAxis), + .getValue = + [this, &mapping, gamepad] { + if (mPendingAxisMapping == &mapping) { + return pending_axis_label(); + } + return native_axis_name(mapping, gamepad); + }, + }) + .on_pressed([this, port, &mapping] { + cancel_pending_binding(); + mPendingPort = port; + mPendingBindingArmed = false; + mPendingAxisMapping = &mapping; + }); + }; + + pane.add_section("Control Stick"); + addAxis(PAD_AXIS_LEFT_Y_POS); + addAxis(PAD_AXIS_LEFT_Y_NEG); + addAxis(PAD_AXIS_LEFT_X_NEG); + addAxis(PAD_AXIS_LEFT_X_POS); + + pane.add_section("C Stick"); + addAxis(PAD_AXIS_RIGHT_Y_POS); + addAxis(PAD_AXIS_RIGHT_Y_NEG); + addAxis(PAD_AXIS_RIGHT_X_NEG); + addAxis(PAD_AXIS_RIGHT_X_POS); + break; + } + } +} + +void ControllerConfigWindow::refresh_controller_page() { + if (!visible() || mPage != Page::Controller || mRightPane == nullptr) { + return; + } + render_page(*mRightPane, mActivePort, Page::Controller); +} + +void ControllerConfigWindow::poll_pending_binding() { + if (mSuppressNavigationUntilNeutral && input_neutral(mSuppressNavigationPort)) { + mSuppressNavigationUntilNeutral = false; + mSuppressNavigationPort = -1; + } + + if (!capture_active()) { + return; + } + + if (!mPendingBindingArmed) { + if (pending_input_neutral()) { + mPendingBindingArmed = true; + } + return; + } + + if (mPendingButtonMapping != nullptr) { + const s32 nativeButton = PADGetNativeButtonPressed(mPendingPort); + if (nativeButton != -1) { + const int completedPort = mPendingPort; + mPendingButtonMapping->nativeButton = static_cast(nativeButton); + mPendingButtonMapping = nullptr; + mPendingPort = -1; + mPendingBindingArmed = false; + mSuppressNavigationUntilNeutral = true; + mSuppressNavigationPort = completedPort; + PADSerializeMappings(); + } + return; + } + + if (mPendingAxisMapping != nullptr) { + const PADSignedNativeAxis nativeAxis = PADGetNativeAxisPulled(mPendingPort); + if (nativeAxis.nativeAxis != -1) { + const int completedPort = mPendingPort; + mPendingAxisMapping->nativeAxis = nativeAxis; + mPendingAxisMapping->nativeButton = -1; + mPendingAxisMapping = nullptr; + mPendingPort = -1; + mPendingBindingArmed = false; + mSuppressNavigationUntilNeutral = true; + mSuppressNavigationPort = completedPort; + PADSerializeMappings(); + return; + } + + const s32 nativeButton = PADGetNativeButtonPressed(mPendingPort); + if (nativeButton != -1) { + const int completedPort = mPendingPort; + mPendingAxisMapping->nativeAxis = {-1, AXIS_SIGN_POSITIVE}; + mPendingAxisMapping->nativeButton = nativeButton; + mPendingAxisMapping = nullptr; + mPendingPort = -1; + mPendingBindingArmed = false; + mSuppressNavigationUntilNeutral = true; + mSuppressNavigationPort = completedPort; + PADSerializeMappings(); + } + } +} + +bool ControllerConfigWindow::capture_active() const { + return mPendingButtonMapping != nullptr || mPendingAxisMapping != nullptr; +} + +bool ControllerConfigWindow::pending_input_neutral() const { + return input_neutral(mPendingPort); +} + +Rml::String ControllerConfigWindow::pending_button_label() const { + return mPendingBindingArmed ? "Press a button..." : "Waiting..."; +} + +Rml::String ControllerConfigWindow::pending_axis_label() const { + return mPendingBindingArmed ? "Move axis or press a button..." : "Waiting..."; +} + +void ControllerConfigWindow::cancel_pending_binding() { + if (mPendingButtonMapping == nullptr && mPendingAxisMapping == nullptr && + !mSuppressNavigationUntilNeutral) + { + return; + } + mPendingButtonMapping = nullptr; + mPendingAxisMapping = nullptr; + mPendingPort = -1; + mPendingBindingArmed = false; + mSuppressNavigationUntilNeutral = false; + mSuppressNavigationPort = -1; +} + +} // namespace dusk::ui diff --git a/src/dusk/ui/controller_config.hpp b/src/dusk/ui/controller_config.hpp new file mode 100644 index 0000000000..67379dbf87 --- /dev/null +++ b/src/dusk/ui/controller_config.hpp @@ -0,0 +1,45 @@ +#pragma once + +#include "window.hpp" + +#include + +namespace dusk::ui { + +class ControllerConfigWindow : public Window { +public: + ControllerConfigWindow(); + + void update() override; + void hide(bool close) override; + +private: + enum class Page { + Controller, + Buttons, + Triggers, + Sticks, + }; + + void build_port_tab(Rml::Element* content, int port); + void render_page(class Pane& pane, int port, Page page); + void refresh_controller_page(); + void poll_pending_binding(); + bool capture_active() const; + bool pending_input_neutral() const; + Rml::String pending_button_label() const; + Rml::String pending_axis_label() const; + void cancel_pending_binding(); + + Page mPage = Page::Controller; + Pane* mRightPane = nullptr; + int mActivePort = 0; + int mPendingPort = -1; + bool mPendingBindingArmed = false; + bool mSuppressNavigationUntilNeutral = false; + int mSuppressNavigationPort = -1; + PADButtonMapping* mPendingButtonMapping = nullptr; + PADAxisMapping* mPendingAxisMapping = nullptr; +}; + +} // namespace dusk::ui diff --git a/src/dusk/ui/event.cpp b/src/dusk/ui/event.cpp index 0ab2211645..38eeb8e9b7 100644 --- a/src/dusk/ui/event.cpp +++ b/src/dusk/ui/event.cpp @@ -10,9 +10,20 @@ ScopedEventListener::ScopedEventListener( mElement->AddEventListener(mEvent, this, mCapture); } +ScopedEventListener::ScopedEventListener( + Rml::Element* element, Rml::String event, Callback callback, bool capture) + : mElement(element), mEventName(std::move(event)), mCapture(capture), + mCallback(std::move(callback)) { + mElement->AddEventListener(mEventName, this, mCapture); +} + ScopedEventListener::~ScopedEventListener() { if (mElement != nullptr) { - mElement->RemoveEventListener(mEvent, this, mCapture); + if (!mEventName.empty()) { + mElement->RemoveEventListener(mEventName, this, mCapture); + } else { + mElement->RemoveEventListener(mEvent, this, mCapture); + } mElement = nullptr; } } diff --git a/src/dusk/ui/event.hpp b/src/dusk/ui/event.hpp index 4521fa1ea9..d4075150f2 100644 --- a/src/dusk/ui/event.hpp +++ b/src/dusk/ui/event.hpp @@ -12,6 +12,8 @@ public: ScopedEventListener( Rml::Element* element, Rml::EventId event, Callback callback, bool capture = false); + ScopedEventListener( + Rml::Element* element, Rml::String event, Callback callback, bool capture = false); ~ScopedEventListener() override; ScopedEventListener(const ScopedEventListener&) = delete; @@ -25,6 +27,7 @@ public: private: Rml::Element* mElement = nullptr; Rml::EventId mEvent = Rml::EventId::Invalid; + Rml::String mEventName; bool mCapture = false; Callback mCallback; }; diff --git a/src/dusk/ui/input.cpp b/src/dusk/ui/input.cpp index 891887f4bb..4c430540e9 100644 --- a/src/dusk/ui/input.cpp +++ b/src/dusk/ui/input.cpp @@ -64,6 +64,40 @@ bool should_block_pad_for_menu_chord() noexcept { return false; } +const char* controller_change_type(Uint32 eventType) noexcept { + switch (eventType) { + case SDL_EVENT_GAMEPAD_ADDED: + return "added"; + case SDL_EVENT_GAMEPAD_REMOVED: + return "removed"; + case SDL_EVENT_GAMEPAD_REMAPPED: + return "remapped"; + default: + return nullptr; + } +} + +void dispatch_controller_change_event(const SDL_Event& event) noexcept { + const char* type = controller_change_type(event.type); + if (type == nullptr) { + return; + } + + auto* context = aurora::rmlui::get_context(); + if (context == nullptr) { + return; + } + auto* root = context->GetRootElement(); + if (root == nullptr) { + return; + } + + Rml::Dictionary parameters; + parameters["type"] = Rml::String(type); + parameters["which"] = static_cast(event.gdevice.which); + root->DispatchEvent("controllerchange", parameters); +} + PADButton pad_button_from_axis(PADAxis axis) noexcept { switch (axis) { case PAD_AXIS_TRIGGER_R: @@ -502,8 +536,11 @@ void handle_event(const SDL_Event& event) noexcept { if (event.type == SDL_EVENT_GAMEPAD_REMOVED || event.type == SDL_EVENT_WINDOW_FOCUS_LOST) { reset_input_state(); sync_input_block(); - return; + if (event.type != SDL_EVENT_GAMEPAD_REMOVED) { + return; + } } + dispatch_controller_change_event(event); if (event.type != SDL_EVENT_GAMEPAD_BUTTON_DOWN && event.type != SDL_EVENT_GAMEPAD_BUTTON_UP && event.type != SDL_EVENT_GAMEPAD_AXIS_MOTION) { diff --git a/src/dusk/ui/select_button.cpp b/src/dusk/ui/select_button.cpp index 73742a60c2..bb19329125 100644 --- a/src/dusk/ui/select_button.cpp +++ b/src/dusk/ui/select_button.cpp @@ -51,6 +51,18 @@ void SelectButton::set_value_label(const Rml::String& value) { } } +SelectButton& SelectButton::on_pressed(SelectButtonCallback callback) { + if (!callback) { + return *this; + } + listen(Rml::EventId::Submit, [this, callback = std::move(callback)](Rml::Event& event) { + if (!disabled() && event.GetTargetElement() == mRoot) { + callback(); + } + }); + return *this; +} + void SelectButton::update_props(Props props) { if (mProps.key != props.key) { mKeyElem->SetInnerRML(escape(props.key)); diff --git a/src/dusk/ui/select_button.hpp b/src/dusk/ui/select_button.hpp index 4640f7235f..f050943673 100644 --- a/src/dusk/ui/select_button.hpp +++ b/src/dusk/ui/select_button.hpp @@ -3,8 +3,13 @@ #include "component.hpp" #include "ui.hpp" +#include +#include + namespace dusk::ui { +using SelectButtonCallback = std::function; + class SelectButton : public FluentComponent { public: struct Props { @@ -18,6 +23,7 @@ public: virtual bool modified() const; void set_modified(bool value); void set_value_label(const Rml::String& value); + SelectButton& on_pressed(SelectButtonCallback callback); protected: void update_props(Props props); diff --git a/src/dusk/ui/settings.cpp b/src/dusk/ui/settings.cpp index 1f32071d37..eb33f92b95 100644 --- a/src/dusk/ui/settings.cpp +++ b/src/dusk/ui/settings.cpp @@ -1,9 +1,8 @@ #include "settings.hpp" -#include - #include "aurora/gfx.h" #include "bool_button.hpp" +#include "controller_config.hpp" #include "dusk/audio/DuskAudioSystem.h" #include "dusk/audio/DuskDsp.hpp" #include "dusk/config.hpp" @@ -127,18 +126,6 @@ SelectButton& config_percent_select(Pane& leftPane, Pane& rightPane, ConfigVar(content, Pane::Type::Controlled); - pane.add_section("Coming soon"); - }); - } - } -}; - } // namespace SettingsWindow::SettingsWindow() { From 23cc18ba0e439e2bea799eb6ce29226cec26ab03 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sun, 3 May 2026 17:24:39 -0600 Subject: [PATCH 218/390] UI: Press ESC to unbind a button Resolves #562 --- src/dusk/ui/controller_config.cpp | 61 ++++++++++++++++++++++--------- src/dusk/ui/controller_config.hpp | 2 + 2 files changed, 45 insertions(+), 18 deletions(-) diff --git a/src/dusk/ui/controller_config.cpp b/src/dusk/ui/controller_config.cpp index af39782c02..393f2e2e4f 100644 --- a/src/dusk/ui/controller_config.cpp +++ b/src/dusk/ui/controller_config.cpp @@ -6,6 +6,7 @@ #include "select_button.hpp" #include +#include #include #include @@ -193,6 +194,14 @@ bool input_neutral(int port) { return PADGetNativeButtonPressed(port) == -1 && PADGetNativeAxisPulled(port).nativeAxis == -1; } +// A Keydown event with KI_ESCAPE may have been dispatched from the controller bindings, +// so instead poll the keyboard input directly for Escape-to-unbind +bool keyboard_escape_pressed() { + int keyCount = 0; + const bool* keys = SDL_GetKeyboardState(&keyCount); + return keys != nullptr && SDL_SCANCODE_ESCAPE < keyCount && keys[SDL_SCANCODE_ESCAPE]; +} + } // namespace ControllerConfigWindow::ControllerConfigWindow() { @@ -532,6 +541,11 @@ void ControllerConfigWindow::poll_pending_binding() { return; } + if (keyboard_escape_pressed()) { + unmap_pending_binding(); + return; + } + if (!mPendingBindingArmed) { if (pending_input_neutral()) { mPendingBindingArmed = true; @@ -544,12 +558,7 @@ void ControllerConfigWindow::poll_pending_binding() { if (nativeButton != -1) { const int completedPort = mPendingPort; mPendingButtonMapping->nativeButton = static_cast(nativeButton); - mPendingButtonMapping = nullptr; - mPendingPort = -1; - mPendingBindingArmed = false; - mSuppressNavigationUntilNeutral = true; - mSuppressNavigationPort = completedPort; - PADSerializeMappings(); + finish_pending_binding(completedPort); } return; } @@ -560,12 +569,7 @@ void ControllerConfigWindow::poll_pending_binding() { const int completedPort = mPendingPort; mPendingAxisMapping->nativeAxis = nativeAxis; mPendingAxisMapping->nativeButton = -1; - mPendingAxisMapping = nullptr; - mPendingPort = -1; - mPendingBindingArmed = false; - mSuppressNavigationUntilNeutral = true; - mSuppressNavigationPort = completedPort; - PADSerializeMappings(); + finish_pending_binding(completedPort); return; } @@ -574,16 +578,37 @@ void ControllerConfigWindow::poll_pending_binding() { const int completedPort = mPendingPort; mPendingAxisMapping->nativeAxis = {-1, AXIS_SIGN_POSITIVE}; mPendingAxisMapping->nativeButton = nativeButton; - mPendingAxisMapping = nullptr; - mPendingPort = -1; - mPendingBindingArmed = false; - mSuppressNavigationUntilNeutral = true; - mSuppressNavigationPort = completedPort; - PADSerializeMappings(); + finish_pending_binding(completedPort); } } } +void ControllerConfigWindow::finish_pending_binding(int completedPort) { + mPendingButtonMapping = nullptr; + mPendingAxisMapping = nullptr; + mPendingPort = -1; + mPendingBindingArmed = false; + mSuppressNavigationUntilNeutral = true; + mSuppressNavigationPort = completedPort; + PADSerializeMappings(); +} + +void ControllerConfigWindow::unmap_pending_binding() { + if (mPendingButtonMapping == nullptr && mPendingAxisMapping == nullptr) { + return; + } + + const int completedPort = mPendingPort; + if (mPendingButtonMapping != nullptr) { + mPendingButtonMapping->nativeButton = PAD_NATIVE_BUTTON_INVALID; + } + if (mPendingAxisMapping != nullptr) { + mPendingAxisMapping->nativeAxis = {-1, AXIS_SIGN_POSITIVE}; + mPendingAxisMapping->nativeButton = -1; + } + finish_pending_binding(completedPort); +} + bool ControllerConfigWindow::capture_active() const { return mPendingButtonMapping != nullptr || mPendingAxisMapping != nullptr; } diff --git a/src/dusk/ui/controller_config.hpp b/src/dusk/ui/controller_config.hpp index 67379dbf87..4bcf41ae8d 100644 --- a/src/dusk/ui/controller_config.hpp +++ b/src/dusk/ui/controller_config.hpp @@ -25,6 +25,8 @@ private: void render_page(class Pane& pane, int port, Page page); void refresh_controller_page(); void poll_pending_binding(); + void finish_pending_binding(int completedPort); + void unmap_pending_binding(); bool capture_active() const; bool pending_input_neutral() const; Rml::String pending_button_label() const; From ef02037990d258228b28efcc656ab10768fdb995 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sun, 3 May 2026 17:25:57 -0600 Subject: [PATCH 219/390] Remove ESC to exit fullscreen --- src/dusk/imgui/ImGuiConsole.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/dusk/imgui/ImGuiConsole.cpp b/src/dusk/imgui/ImGuiConsole.cpp index 321cb2e579..89a783650e 100644 --- a/src/dusk/imgui/ImGuiConsole.cpp +++ b/src/dusk/imgui/ImGuiConsole.cpp @@ -320,10 +320,6 @@ namespace dusk { ImGuiMenuGame::ToggleFullscreen(); } - if (ImGui::IsKeyPressed(ImGuiKey_Escape) && getSettings().video.enableFullscreen) { - ImGuiMenuGame::ToggleFullscreen(); - } - // if (!dusk::IsGameLaunched) { // m_preLaunchWindow.draw(); // } From 7fbfe5ad88c7aee43b465d615e846391a1d0a75d Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sun, 3 May 2026 18:29:08 -0600 Subject: [PATCH 220/390] UI: Add close button to tab bar --- extern/aurora | 2 +- res/MaterialSymbolsRounded-Regular.ttf | Bin 0 -> 1196044 bytes res/rml/tabbing.rcss | 50 ++++++++++++++++++ src/dusk/ui/popup.cpp | 18 +++++-- src/dusk/ui/tab_bar.cpp | 70 ++++++++++++++++++++++++- src/dusk/ui/tab_bar.hpp | 2 + src/dusk/ui/ui.cpp | 1 + src/dusk/ui/window.cpp | 1 + 8 files changed, 136 insertions(+), 8 deletions(-) create mode 100644 res/MaterialSymbolsRounded-Regular.ttf diff --git a/extern/aurora b/extern/aurora index 935756010c..a923cc0db4 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 935756010cbe02c04ce78bc5ccb7185c271040d6 +Subproject commit a923cc0db4a8ee44b7780d7943e7d0a3a6a35167 diff --git a/res/MaterialSymbolsRounded-Regular.ttf b/res/MaterialSymbolsRounded-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..782fc0a406530feb570bc3f5386024dfae64786f GIT binary patch literal 1196044 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%0AbcEe=^@a%=cwwshsNT+8+zs;Evs-YfnMw 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�d*=Mzv>#BZ{Ek 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�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
& headers, bool names) { + jclass stringClass = env->FindClass("java/lang/String"); + if (stringClass == nullptr || clear_pending_exception(env)) { + return nullptr; + } + + jobjectArray array = + env->NewObjectArray(static_cast(headers.size()), stringClass, nullptr); + env->DeleteLocalRef(stringClass); + if (array == nullptr || clear_pending_exception(env)) { + return nullptr; + } + + for (jsize i = 0; i < static_cast(headers.size()); ++i) { + const std::string& value = names ? headers[static_cast(i)].name : + headers[static_cast(i)].value; + jstring javaValue = to_jstring(env, value); + if (javaValue == nullptr || clear_pending_exception(env)) { + env->DeleteLocalRef(array); + return nullptr; + } + env->SetObjectArrayElement(array, i, javaValue); + env->DeleteLocalRef(javaValue); + if (clear_pending_exception(env)) { + env->DeleteLocalRef(array); + return nullptr; + } + } + + return array; +} + +std::vector
read_headers(JNIEnv* env, jobjectArray names, jobjectArray values) { + std::vector
headers; + if (names == nullptr || values == nullptr) { + return headers; + } + + const jsize count = std::min(env->GetArrayLength(names), env->GetArrayLength(values)); + headers.reserve(static_cast(count)); + for (jsize i = 0; i < count; ++i) { + auto* name = static_cast(env->GetObjectArrayElement(names, i)); + auto* value = static_cast(env->GetObjectArrayElement(values, i)); + if (clear_pending_exception(env)) { + if (name != nullptr) { + env->DeleteLocalRef(name); + } + if (value != nullptr) { + env->DeleteLocalRef(value); + } + headers.clear(); + return headers; + } + + if (name != nullptr) { + headers.push_back({ + .name = to_string(env, name), + .value = to_string(env, value), + }); + } + + if (name != nullptr) { + env->DeleteLocalRef(name); + } + if (value != nullptr) { + env->DeleteLocalRef(value); + } + } + + return headers; +} + +std::string read_body(JNIEnv* env, jbyteArray body) { + if (body == nullptr) { + return {}; + } + + const jsize bodySize = env->GetArrayLength(body); + std::string result(static_cast(bodySize), '\0'); + if (bodySize > 0) { + env->GetByteArrayRegion(body, 0, bodySize, reinterpret_cast(result.data())); + if (clear_pending_exception(env)) { + return {}; + } + } + return result; +} + +Result result_from_response(JNIEnv* env, jobject response) { + if (response == nullptr) { + return { + .error = Error::Network, + .message = "Android HTTP request did not return a response", + }; + } + + jclass responseClass = env->GetObjectClass(response); + if (responseClass == nullptr || clear_pending_exception(env)) { + return { + .error = Error::Network, + .message = "Failed to inspect Android HTTP response", + }; + } + + jfieldID errorField = env->GetFieldID(responseClass, "error", "I"); + jfieldID messageField = env->GetFieldID(responseClass, "message", "Ljava/lang/String;"); + jfieldID statusField = env->GetFieldID(responseClass, "statusCode", "I"); + jfieldID headerNamesField = + env->GetFieldID(responseClass, "headerNames", "[Ljava/lang/String;"); + jfieldID headerValuesField = + env->GetFieldID(responseClass, "headerValues", "[Ljava/lang/String;"); + jfieldID bodyField = env->GetFieldID(responseClass, "body", "[B"); + env->DeleteLocalRef(responseClass); + if (errorField == nullptr || messageField == nullptr || statusField == nullptr || + headerNamesField == nullptr || headerValuesField == nullptr || bodyField == nullptr || + clear_pending_exception(env)) + { + return { + .error = Error::Network, + .message = "Android HTTP response shape was not recognized", + }; + } + + const int javaError = env->GetIntField(response, errorField); + auto* message = static_cast(env->GetObjectField(response, messageField)); + auto* headerNames = static_cast(env->GetObjectField(response, headerNamesField)); + auto* headerValues = + static_cast(env->GetObjectField(response, headerValuesField)); + auto* body = static_cast(env->GetObjectField(response, bodyField)); + if (clear_pending_exception(env)) { + return { + .error = Error::Network, + .message = "Failed to read Android HTTP response", + }; + } + + Response httpResponse{ + .statusCode = static_cast(env->GetIntField(response, statusField)), + .headers = read_headers(env, headerNames, headerValues), + .body = read_body(env, body), + }; + + std::string messageString = to_string(env, message); + + if (message != nullptr) { + env->DeleteLocalRef(message); + } + if (headerNames != nullptr) { + env->DeleteLocalRef(headerNames); + } + if (headerValues != nullptr) { + env->DeleteLocalRef(headerValues); + } + if (body != nullptr) { + env->DeleteLocalRef(body); + } + + return { + .error = map_java_error(javaError), + .message = std::move(messageString), + .response = std::move(httpResponse), + }; +} + +} // namespace + +bool available() noexcept { + return true; +} + +Backend backend() noexcept { + return Backend::Android; +} + +const char* backend_name() noexcept { + return "Android"; +} + +Result get(const Request& request) { + if (request.url.empty()) { + return { + .error = Error::InvalidUrl, + .message = "URL is empty", + }; + } + if (!request.url.starts_with("https://")) { + return { + .error = Error::UnsupportedScheme, + .message = "Only https:// URLs are supported", + }; + } + + auto* env = static_cast(SDL_GetAndroidJNIEnv()); + if (env == nullptr) { + return { + .error = Error::Network, + .message = "Failed to access Android JNI environment", + }; + } + + jobject activity = static_cast(SDL_GetAndroidActivity()); + if (activity == nullptr || clear_pending_exception(env)) { + if (activity != nullptr) { + env->DeleteLocalRef(activity); + } + return { + .error = Error::Network, + .message = "Failed to access Android activity", + }; + } + + jclass clientClass = + load_dusk_class(env, activity, "com.twilitrealm.dusk.DuskHttpClient"); + env->DeleteLocalRef(activity); + if (clientClass == nullptr) { + return { + .error = Error::Network, + .message = "Failed to load Android HTTP helper", + }; + } + + jmethodID getMethod = env->GetStaticMethodID(clientClass, "get", + "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;IJ)" + "Lcom/twilitrealm/dusk/DuskHttpClient$Response;"); + if (getMethod == nullptr || clear_pending_exception(env)) { + env->DeleteLocalRef(clientClass); + return { + .error = Error::Network, + .message = "Failed to find Android HTTP helper method", + }; + } + + jstring url = to_jstring(env, request.url); + jobjectArray headerNames = make_string_array(env, request.headers, true); + jobjectArray headerValues = make_string_array(env, request.headers, false); + if (url == nullptr || headerNames == nullptr || headerValues == nullptr || + clear_pending_exception(env)) + { + if (url != nullptr) { + env->DeleteLocalRef(url); + } + if (headerNames != nullptr) { + env->DeleteLocalRef(headerNames); + } + if (headerValues != nullptr) { + env->DeleteLocalRef(headerValues); + } + env->DeleteLocalRef(clientClass); + return { + .error = Error::Network, + .message = "Failed to prepare Android HTTP request", + }; + } + + jobject response = env->CallStaticObjectMethod(clientClass, getMethod, url, headerNames, + headerValues, timeout_ms(request.timeout), max_body_bytes(request.maxBodyBytes)); + env->DeleteLocalRef(url); + env->DeleteLocalRef(headerNames); + env->DeleteLocalRef(headerValues); + env->DeleteLocalRef(clientClass); + if (clear_pending_exception(env)) { + return { + .error = Error::Network, + .message = "Android HTTP request failed with a Java exception", + }; + } + + Result result = result_from_response(env, response); + if (response != nullptr) { + env->DeleteLocalRef(response); + } + return result; +} + +} // namespace dusk::http diff --git a/src/dusk/http/http.hpp b/src/dusk/http/http.hpp index d62b031fbc..54bef6eec1 100644 --- a/src/dusk/http/http.hpp +++ b/src/dusk/http/http.hpp @@ -13,6 +13,7 @@ enum class Backend { WinHttp, UrlSession, LibCurl, + Android, }; enum class Error { diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index aa31540898..0b9ee8e695 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -82,6 +82,7 @@ UserSettings g_userSettings = { .freeCameraSensitivity {"game.freeCameraSensitivity", 1.0f}, .debugFlyCam {"game.debugFlyCam", false}, .debugFlyCamLockEvents {"game.debugFlyCamLockEvents", true}, + .allowBackgroundInput {"game.allowBackgroundInput", true}, // Cheats .infiniteHearts {"game.infiniteHearts", false}, @@ -215,6 +216,7 @@ void registerSettings() { Register(g_userSettings.game.freeCamera); Register(g_userSettings.game.debugFlyCam); Register(g_userSettings.game.debugFlyCamLockEvents); + Register(g_userSettings.game.allowBackgroundInput); Register(g_userSettings.backend.isoPath); Register(g_userSettings.backend.isoVerification); diff --git a/src/dusk/ui/prelaunch.cpp b/src/dusk/ui/prelaunch.cpp index 87f00c3809..5c41958409 100644 --- a/src/dusk/ui/prelaunch.cpp +++ b/src/dusk/ui/prelaunch.cpp @@ -445,8 +445,7 @@ private: } if (mFileName != nullptr) { - std::string fileName = - std::filesystem::path(sDiscVerificationTask->path).filename().string(); + std::string fileName = display_name_for_path(sDiscVerificationTask->path); if (fileName.empty()) { fileName = sDiscVerificationTask->path; } diff --git a/src/dusk/ui/settings.cpp b/src/dusk/ui/settings.cpp index e41dbbe46a..9645779b46 100644 --- a/src/dusk/ui/settings.cpp +++ b/src/dusk/ui/settings.cpp @@ -6,6 +6,7 @@ #include "dusk/audio/DuskAudioSystem.h" #include "dusk/audio/DuskDsp.hpp" #include "dusk/config.hpp" +#include "dusk/file_select.hpp" #include "dusk/imgui/ImGuiEngine.hpp" #include "dusk/livesplit.h" #include "graphics_tuner.hpp" @@ -317,7 +318,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) { if (path.empty()) { display = "(none)"; } else { - display = std::filesystem::path(path).filename().string(); + display = display_name_for_path(path); if (display.empty()) { display = path; } @@ -612,6 +613,12 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) { pane.clear(); pane.add_text("Open controller binding configuration."); }); + config_bool_select(leftPane, rightPane, getSettings().game.allowBackgroundInput, + { + .key = "Allow Background Input", + .helpText = "Allow controller input even when the game window is not focused.", + .onChange = [](bool value) { aurora_set_background_input(value); }, + }); leftPane.add_section("Camera"); addOption("Free Camera", getSettings().game.freeCamera, @@ -923,6 +930,12 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) { .helpText = "Checks GitHub releases for a new Dusk version on startup.

" "No personal information is transmitted or collected.", }); + config_bool_select(leftPane, rightPane, getSettings().game.pauseOnFocusLost, + { + .key = "Pause On Focus Lost", + .helpText = "Pause the game when window focus is lost.", + .onChange = [](bool value) { aurora_set_pause_on_focus_lost(value); }, + }); config_bool_select(leftPane, rightPane, getSettings().backend.enableAdvancedSettings, { .key = "Enable Advanced Settings", diff --git a/src/dusk/ui/ui.cpp b/src/dusk/ui/ui.cpp index a646527ee5..5b1ba7bb4a 100644 --- a/src/dusk/ui/ui.cpp +++ b/src/dusk/ui/ui.cpp @@ -255,11 +255,7 @@ void update() noexcept { } std::filesystem::path resource_path(const std::filesystem::path& filename) noexcept { - const char* basePath = SDL_GetBasePath(); - if (basePath == nullptr) { - return std::filesystem::path("res") / filename; - } - return std::filesystem::path(basePath) / "res" / filename; + return std::filesystem::path("res") / filename; } std::string escape(std::string_view str) noexcept { diff --git a/src/dusk/ui/window.cpp b/src/dusk/ui/window.cpp index 55ce96c69f..41080ff287 100644 --- a/src/dusk/ui/window.cpp +++ b/src/dusk/ui/window.cpp @@ -16,10 +16,7 @@ namespace dusk::ui { namespace { float base_body_padding(Rml::Context* context) noexcept { - if (context == nullptr) { - return 64.0f; - } - const float dpRatio = std::max(context->GetDensityIndependentPixelRatio(), 0.001f); + const float dpRatio = context->GetDensityIndependentPixelRatio(); const float heightDp = static_cast(context->GetDimensions().y) / dpRatio; if (heightDp <= 640.0f) { return 16.0f * dpRatio; diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index 8719998bd5..56ac05b16c 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -105,7 +105,6 @@ const int audioHeapSize = 0x14D800; bool dusk::IsRunning = true; bool dusk::IsShuttingDown = false; bool dusk::IsGameLaunched = false; -bool dusk::IsFocusPaused = false; bool dusk::RestartRequested = false; std::filesystem::path dusk::ConfigPath; #endif @@ -228,19 +227,16 @@ void main01(void) { switch (event->type) { case AURORA_NONE: goto eventsDone; + case AURORA_PAUSED: + dusk::audio::SetPaused(true); + break; + case AURORA_UNPAUSED: + dusk::audio::SetPaused(false); + dusk::game_clock::reset_frame_timer(); + break; case AURORA_SDL_EVENT: dusk::ui::handle_event(event->sdl); dusk::g_imguiConsole.HandleSDLEvent(event->sdl); - if (event->sdl.type == SDL_EVENT_WINDOW_FOCUS_LOST && - dusk::getSettings().game.pauseOnFocusLost) { - dusk::IsFocusPaused = true; - dusk::audio::SetPaused(true); - } else if (event->sdl.type == SDL_EVENT_WINDOW_FOCUS_GAINED && - dusk::IsFocusPaused) { - dusk::IsFocusPaused = false; - dusk::audio::SetPaused(false); - dusk::game_clock::reset_frame_timer(); - } break; case AURORA_DISPLAY_SCALE_CHANGED: dusk::ImGuiEngine_Initialize(event->windowSize.scale); @@ -254,19 +250,14 @@ void main01(void) { eventsDone:; - if (dusk::IsFocusPaused) { - std::this_thread::sleep_for(std::chrono::milliseconds(16)); + if (!aurora_begin_frame()) { + DuskLog.debug("aurora_begin_frame returned false, skipping draw this frame"); continue; } VIWaitForRetrace(); dusk::lastFrameAuroraStats = *aurora_get_stats(); - if (!aurora_begin_frame()) { - DuskLog.debug("aurora_begin_frame returned false, skipping draw this frame"); - continue; - } - mDoGph_gInf_c::updateRenderSize(); dusk::ui::update(); @@ -571,7 +562,8 @@ int game_main(int argc, char* argv[]) { config.logLevel = startupLogLevel; config.mem1Size = 256 * 1024 * 1024; config.mem2Size = 24 * 1024 * 1024; - config.allowJoystickBackgroundEvents = true; + config.allowJoystickBackgroundEvents = dusk::getSettings().game.allowBackgroundInput; + config.pauseOnFocusLost = dusk::getSettings().game.pauseOnFocusLost; config.imGuiInitCallback = &aurora_imgui_init_callback; config.allowTextureReplacements = true; config.allowTextureDumps = false; @@ -618,13 +610,19 @@ int game_main(int argc, char* argv[]) { // Invalidate a bad saved isoPath so that Dusk can't get blocked from starting up. // This is only a metadata check; full hash verification is handled by the prelaunch UI. + bool forcePreLaunchUI = false; + bool saveConfigBeforePrelaunch = false; + const std::string p = dusk::getSettings().backend.isoPath; dusk::iso::DiscInfo discInfo{}; if (!p.empty() && dusk::iso::inspect(p.c_str(), discInfo) != dusk::iso::ValidationError::Success) { + DuskLog.warn("Saved DVD image path failed validation, clearing configured path: {}", p); dusk::getSettings().backend.isoPath.setValue(""); dusk::getSettings().backend.isoVerification.setValue(dusk::DiscVerificationState::Unknown); + forcePreLaunchUI = true; + saveConfigBeforePrelaunch = true; } std::string dvd_path; @@ -636,6 +634,7 @@ int game_main(int argc, char* argv[]) { dvd_opened = aurora_dvd_open(dvd_path.c_str()); if (!dvd_opened) { DuskLog.warn("Failed to open DVD image from command line: {}, opening prelaunch UI", dvd_path); + forcePreLaunchUI = true; } else { dusk::getSettings().backend.isoPath.setValue(dvd_path); dusk::getSettings().backend.isoVerification.setValue( @@ -645,10 +644,23 @@ int game_main(int argc, char* argv[]) { } } else { DuskLog.warn("DVD image from command line failed validation: {}, opening prelaunch UI", dvd_path); + forcePreLaunchUI = true; } } if (!dvd_opened) { + if (dusk::getSettings().backend.isoPath.getValue().empty()) { + forcePreLaunchUI = true; + } + if (forcePreLaunchUI && dusk::getSettings().backend.skipPreLaunchUI.getValue()) { + DuskLog.warn("Prelaunch UI was disabled with no usable DVD image, enabling prelaunch UI"); + dusk::getSettings().backend.skipPreLaunchUI.setValue(false); + saveConfigBeforePrelaunch = true; + } + if (saveConfigBeforePrelaunch) { + dusk::config::Save(); + } + if (!dusk::getSettings().backend.skipPreLaunchUI) { dusk::ui::push_document(std::make_unique(), true); From 84ffd67622b77f583f236d4fc4f1cc4c12cf3c5e Mon Sep 17 00:00:00 2001 From: Irastris Date: Fri, 8 May 2026 19:01:19 -0400 Subject: [PATCH 332/390] Refactor notification settings, allow disabling controller toasts (#721) * Refactor notification settings, allow disabling controller toasts * "Toasts" to "Notifications" --- include/dusk/settings.h | 4 +-- src/dusk/achievements.cpp | 2 +- src/dusk/settings.cpp | 6 ++-- src/dusk/ui/preset.cpp | 6 ++-- src/dusk/ui/settings.cpp | 67 ++++++++++++++++++++++++++++++++++++--- src/dusk/ui/ui.cpp | 64 +++++++++++++++++++------------------ 6 files changed, 108 insertions(+), 41 deletions(-) diff --git a/include/dusk/settings.h b/include/dusk/settings.h index cb4945801a..d9d85fa36b 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -102,8 +102,8 @@ struct UserSettings { ConfigVar minimalHUD; ConfigVar pauseOnFocusLost; ConfigVar enableLinkDollRotation; - ConfigVar enableAchievementNotifications; - + ConfigVar enableAchievementToasts; + ConfigVar enableControllerToasts; // Graphics ConfigVar bloomMode; diff --git a/src/dusk/achievements.cpp b/src/dusk/achievements.cpp index eefcda978f..cac6f776b6 100644 --- a/src/dusk/achievements.cpp +++ b/src/dusk/achievements.cpp @@ -1113,7 +1113,7 @@ void AchievementSystem::processEntry(Entry& e) { if (nowUnlocked) { e.achievement.progress = e.achievement.isCounter ? e.achievement.goal : 1; e.achievement.unlocked = true; - if (getSettings().game.enableAchievementNotifications) { + if (getSettings().game.enableAchievementToasts) { ui::push_toast({ .type = "achievement", .title = "Achievement Unlocked!", diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index 0b9ee8e695..c8e7178d67 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -50,7 +50,8 @@ UserSettings g_userSettings = { .minimalHUD {"game.minimalHUD", false}, .pauseOnFocusLost {"game.pauseOnFocusLost", false}, .enableLinkDollRotation {"game.enableLinkDollRotation", false}, - .enableAchievementNotifications {"game.enableAchievementNotifications", true}, + .enableAchievementToasts {"game.enableAchievementToasts", true}, + .enableControllerToasts {"game.enableControllerToasts", true}, // Graphics .bloomMode {"game.bloomMode", BloomMode::Dusk}, @@ -184,7 +185,8 @@ void registerSettings() { Register(g_userSettings.game.freeMagicArmor); Register(g_userSettings.game.restoreWiiGlitches); Register(g_userSettings.game.enableLinkDollRotation); - Register(g_userSettings.game.enableAchievementNotifications); + Register(g_userSettings.game.enableAchievementToasts); + Register(g_userSettings.game.enableControllerToasts); Register(g_userSettings.game.noMissClimbing); Register(g_userSettings.game.noLowHpSound); Register(g_userSettings.game.midnasLamentNonStop); diff --git a/src/dusk/ui/preset.cpp b/src/dusk/ui/preset.cpp index 6b6bdc2248..1d559972f5 100644 --- a/src/dusk/ui/preset.cpp +++ b/src/dusk/ui/preset.cpp @@ -14,7 +14,8 @@ void applyPresetClassic() { auto& s = getSettings(); s.video.lockAspectRatio.setValue(true); s.game.bloomMode.setValue(BloomMode::Classic); - s.game.enableAchievementNotifications.setValue(false); + s.game.enableAchievementToasts.setValue(false); + s.game.enableControllerToasts.setValue(false); s.game.internalResolutionScale.setValue(1); s.game.shadowResolutionMultiplier.setValue(1); s.game.hideTvSettingsScreen.setValue(false); @@ -33,7 +34,8 @@ void applyPresetDusk() { s.game.biggerWallets.setValue(true); s.game.invertCameraXAxis.setValue(true); s.game.no2ndFishForCat.setValue(true); - s.game.enableAchievementNotifications.setValue(true); + s.game.enableAchievementToasts.setValue(true); + s.game.enableControllerToasts.setValue(true); s.game.enableQuickTransform.setValue(true); s.game.instantSaves.setValue(true); s.game.midnasLamentNonStop.setValue(true); diff --git a/src/dusk/ui/settings.cpp b/src/dusk/ui/settings.cpp index 9645779b46..cbfde1ba3a 100644 --- a/src/dusk/ui/settings.cpp +++ b/src/dusk/ui/settings.cpp @@ -896,10 +896,69 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) { auto& rightPane = add_child(content, Pane::Type::Uncontrolled); leftPane.add_section("Dusk"); - config_bool_select(leftPane, rightPane, getSettings().game.enableAchievementNotifications, - { - .key = "Achievement Notifications", - .helpText = "Display a toast when an achievement is unlocked.", + leftPane.register_control( + leftPane.add_select_button({ + .key = "Notifications", + .getValue = [] { + const bool ach = getSettings().game.enableAchievementToasts.getValue(); + const bool ctl = getSettings().game.enableControllerToasts.getValue(); + if (!ach && !ctl) { + return Rml::String{"Off"}; + } + if (ach && ctl) { + return Rml::String{"All"}; + } + return Rml::String{"Some"}; + }, + .isModified = [] { + const auto& ach = getSettings().game.enableAchievementToasts; + const auto& ctl = getSettings().game.enableControllerToasts; + return ach.getValue() != ach.getDefaultValue() || ctl.getValue() != ctl.getDefaultValue(); + }, + }), + rightPane, [](Pane& pane) { + pane.clear(); + pane.add_button("Select All").on_pressed([] { + mDoAud_seStartMenu(kSoundItemChange); + getSettings().game.enableAchievementToasts.setValue(true); + getSettings().game.enableControllerToasts.setValue(true); + config::Save(); + }); + pane.add_button("Select None").on_pressed([] { + mDoAud_seStartMenu(kSoundItemChange); + getSettings().game.enableAchievementToasts.setValue(false); + getSettings().game.enableControllerToasts.setValue(false); + config::Save(); + }); + + pane.add_section("Types"); + pane.add_button( + { + .text = "Achievements", + .isSelected = + [] { + return getSettings().game.enableAchievementToasts.getValue(); + }, + }) + .on_pressed([] { + mDoAud_seStartMenu(kSoundItemChange); + auto& v = getSettings().game.enableAchievementToasts; + v.setValue(!v.getValue()); + config::Save(); + }); + pane.add_button( + { + .text = "Controller", + .isSelected = + [] { return getSettings().game.enableControllerToasts.getValue(); }, + }) + .on_pressed([] { + mDoAud_seStartMenu(kSoundItemChange); + auto& v = getSettings().game.enableControllerToasts; + v.setValue(!v.getValue()); + config::Save(); + }); + pane.add_rml("
Choose which notifications can be displayed."); }); #if DUSK_ENABLE_SENTRY_NATIVE config_bool_select(leftPane, rightPane, getSettings().backend.enableCrashReporting, diff --git a/src/dusk/ui/ui.cpp b/src/dusk/ui/ui.cpp index 5b1ba7bb4a..0ee59e7938 100644 --- a/src/dusk/ui/ui.cpp +++ b/src/dusk/ui/ui.cpp @@ -125,43 +125,47 @@ void handle_event(const SDL_Event& event) noexcept { if (event.type == SDL_EVENT_GAMEPAD_ADDED) { auto* gamepad = SDL_GetGamepadFromID(event.gdevice.which); if (SDL_GamepadConnected(gamepad)) { - const char* name = SDL_GetGamepadName(gamepad); - Rml::String content = fmt::format("{}", name ? name : "[Unknown]"); - Rml::String title = "Controller connected"; - if (const char* icon = connection_state_icon(SDL_GetGamepadConnectionState(gamepad))) { - title = fmt::format( - "{} &#x{};", title, - icon); - } - int batteryLevel = -1; - const auto powerState = SDL_GetGamepadPowerInfo(gamepad, &batteryLevel); - if (powerState != SDL_POWERSTATE_UNKNOWN) { - content = fmt::format( - "{}&#x{};", - content, battery_icon(powerState, batteryLevel)); - if (batteryLevel > -1) { - content = fmt::format("{} {}%", content, batteryLevel); + if (getSettings().game.enableControllerToasts) { + const char* name = SDL_GetGamepadName(gamepad); + Rml::String content = fmt::format("{}", name ? name : "[Unknown]"); + Rml::String title = "Controller connected"; + if (const char* icon = connection_state_icon(SDL_GetGamepadConnectionState(gamepad))) { + title = fmt::format( + "{} &#x{};", title, + icon); } - content += ""; + int batteryLevel = -1; + const auto powerState = SDL_GetGamepadPowerInfo(gamepad, &batteryLevel); + if (powerState != SDL_POWERSTATE_UNKNOWN) { + content = fmt::format( + "{}&#x{};", + content, battery_icon(powerState, batteryLevel)); + if (batteryLevel > -1) { + content = fmt::format("{} {}%", content, batteryLevel); + } + content += ""; + } + push_toast({ + .type = "controller", + .title = title, + .content = content, + .duration = std::chrono::seconds(4), + }); } - push_toast({ - .type = "controller", - .title = title, - .content = content, - .duration = std::chrono::seconds(4), - }); sConnectedGamepads.insert(event.gdevice.which); } } else if (event.type == SDL_EVENT_GAMEPAD_REMOVED && sConnectedGamepads.contains(event.gdevice.which)) { - const char* name = SDL_GetGamepadNameForID(event.gdevice.which); - push_toast({ - .type = "controller", - .title = "Controller disconnected", - .content = name ? name : "[Unknown]", - .duration = std::chrono::seconds(4), - }); + if (getSettings().game.enableControllerToasts) { + const char* name = SDL_GetGamepadNameForID(event.gdevice.which); + push_toast({ + .type = "controller", + .title = "Controller disconnected", + .content = name ? name : "[Unknown]", + .duration = std::chrono::seconds(4), + }); + } sConnectedGamepads.erase(event.gdevice.which); } input::handle_event(event); From 4d67033ff8f70519f576f13809db0ec3baeee6f6 Mon Sep 17 00:00:00 2001 From: Tom Lube Date: Fri, 8 May 2026 18:45:05 -0400 Subject: [PATCH 333/390] Remove reset via CTRL + R --- src/dusk/imgui/ImGuiConsole.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/dusk/imgui/ImGuiConsole.cpp b/src/dusk/imgui/ImGuiConsole.cpp index e933e314e4..4793b717cc 100644 --- a/src/dusk/imgui/ImGuiConsole.cpp +++ b/src/dusk/imgui/ImGuiConsole.cpp @@ -253,13 +253,6 @@ namespace dusk { UpdateSettings(); - if (!fpcM_SearchByName(fpcNm_LOGO_SCENE_e) && - (ImGui::IsKeyDown(ImGuiKey_LeftCtrl) || ImGui::IsKeyDown(ImGuiKey_RightCtrl)) && - ImGui::IsKeyPressed(ImGuiKey_R)) - { - JUTGamePad::C3ButtonReset::sResetSwitchPushing = true; - } - if (ImGui::IsKeyPressed(ImGuiKey_F11)) { getSettings().video.enableFullscreen.setValue(!getSettings().video.enableFullscreen); VISetWindowFullscreen(getSettings().video.enableFullscreen); From 699d069b0ac05b7f1e4d5f53cb6feb87deb251e4 Mon Sep 17 00:00:00 2001 From: SuperDude88 <82904174+SuperDude88@users.noreply.github.com> Date: Fri, 8 May 2026 19:10:37 -0400 Subject: [PATCH 334/390] Fix Letter Menu Page Numbers (#722) This bug comes from `getBounds()` returning a reference to a static variable -- the compiler can load the float right away or later (after the second call), so the value it is referencing may have changed. If it waits to load the first operand, the subtraction results in 0. Further discussion at https://discord.com/channels/1446645861529550869/1446648842387722411/1502415404386091118. Resolves #719 --- src/d/d_menu_letter.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/d/d_menu_letter.cpp b/src/d/d_menu_letter.cpp index 589b2553c0..4bfda4b9cd 100644 --- a/src/d/d_menu_letter.cpp +++ b/src/d/d_menu_letter.cpp @@ -965,7 +965,8 @@ void dMenu_Letter_c::screenSetBase() { } if (field_0x374 > 1) { J2DPane* pJVar6 = mpBaseScreen->search('pi_n'); - f32 dVar18 = field_0x1f0[1]->getBounds().i.x - field_0x1f0[0]->getBounds().i.x; + f32 x1 = field_0x1f0[1]->getBounds().i.x; + f32 dVar18 = x1 - field_0x1f0[0]->getBounds().i.x; f32 dVar17 = dVar18 * (field_0x374 - 1); f32 dVar16 = (pJVar6->getWidth() / 2) - (dVar17 / 2); for (int i = 0; i < 9; i++) { From abec043249d47143aa6980dfec14cac4baa88c72 Mon Sep 17 00:00:00 2001 From: Irastris Date: Fri, 8 May 2026 19:11:13 -0400 Subject: [PATCH 335/390] Add mouse as a gyro input source (#720) * Add mouse as a gyro input source * Revisions * Grammar --- include/dusk/gyro.h | 1 + include/dusk/settings.h | 12 +++++ src/d/actor/d_a_mg_fshop.cpp | 8 +-- src/dusk/config.cpp | 1 + src/dusk/gyro.cpp | 101 ++++++++++++++++++++++++++++------- src/dusk/settings.cpp | 2 + src/dusk/ui/settings.cpp | 56 +++++++++++++++++-- 7 files changed, 155 insertions(+), 26 deletions(-) diff --git a/include/dusk/gyro.h b/include/dusk/gyro.h index 279aeae16e..a206100739 100644 --- a/include/dusk/gyro.h +++ b/include/dusk/gyro.h @@ -12,6 +12,7 @@ void rollgoalTableOffset(s16& out_ax, s16& out_az); extern bool s_sensor_keep_alive; bool get_sensor_keep_alive(); void set_sensor_keep_alive(bool value); +bool rollgoal_gyro_enabled(); } // namespace dusk::gyro #endif diff --git a/include/dusk/settings.h b/include/dusk/settings.h index d9d85fa36b..f74a4bf61f 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -27,6 +27,11 @@ enum class DiscVerificationState : u8 { HashMismatch, }; +enum class GyroMode : u8 { + Sensor = 0, + Mouse = 1, +}; + namespace config { template <> struct ConfigEnumRange { @@ -45,6 +50,12 @@ struct ConfigEnumRange { static constexpr auto min = DiscVerificationState::Unknown; static constexpr auto max = DiscVerificationState::HashMismatch; }; + +template <> +struct ConfigEnumRange { + static constexpr auto min = GyroMode::Sensor; + static constexpr auto max = GyroMode::Mouse; +}; } // Persistent user settings @@ -120,6 +131,7 @@ struct UserSettings { ConfigVar midnasLamentNonStop; // Input + ConfigVar gyroMode; ConfigVar enableGyroAim; ConfigVar enableGyroRollgoal; ConfigVar gyroSensitivityX; diff --git a/src/d/actor/d_a_mg_fshop.cpp b/src/d/actor/d_a_mg_fshop.cpp index f0905efd5d..0d5b6dd2c9 100644 --- a/src/d/actor/d_a_mg_fshop.cpp +++ b/src/d/actor/d_a_mg_fshop.cpp @@ -729,10 +729,12 @@ static void koro2_game(fshop_class* i_this) { cLib_addCalcAngleS2(&i_this->field_0x4020.z, 0, 2, 0x200); case 2: #if TARGET_PC - if (dusk::getSettings().game.enableGyroRollgoal) { + if (dusk::gyro::rollgoal_gyro_enabled()) { if (!dusk::gyro::get_sensor_keep_alive()) { dusk::gyro::set_sensor_keep_alive(true); } + } else if (dusk::gyro::get_sensor_keep_alive()) { + dusk::gyro::set_sensor_keep_alive(false); } #endif @@ -753,7 +755,7 @@ static void koro2_game(fshop_class* i_this) { old_stick_x = mDoCPd_c::getSubStickX(PAD_1); cLib_addCalcAngleS2(&i_this->field_0x4060, i_this->field_0x4062, 4, 0x1000); #if TARGET_PC - if (dusk::getSettings().game.enableGyroRollgoal) { + if (dusk::gyro::rollgoal_gyro_enabled()) { dusk::gyro::rollgoalTick(true, i_this->field_0x4060); } #endif @@ -791,7 +793,7 @@ static void koro2_game(fshop_class* i_this) { s16 gyro_ax = 0; s16 gyro_az = 0; #if TARGET_PC - if (dusk::getSettings().game.enableGyroRollgoal) { + if (dusk::gyro::rollgoal_gyro_enabled()) { dusk::gyro::rollgoalTableOffset(gyro_ax, gyro_az); } #endif diff --git a/src/dusk/config.cpp b/src/dusk/config.cpp index f4af7a2961..940797c9ce 100644 --- a/src/dusk/config.cpp +++ b/src/dusk/config.cpp @@ -156,6 +156,7 @@ namespace dusk::config { template class ConfigImpl; template class ConfigImpl; template class ConfigImpl; + template class ConfigImpl; } void dusk::config::Register(ConfigVarBase& configVar) { diff --git a/src/dusk/gyro.cpp b/src/dusk/gyro.cpp index abe22909c1..4011cbb721 100644 --- a/src/dusk/gyro.cpp +++ b/src/dusk/gyro.cpp @@ -1,5 +1,9 @@ #include "dusk/gyro.h" +#include "dusk/ui/ui.hpp" #include "d/actor/d_a_alink.h" + +#include +#include #include namespace dusk::gyro { @@ -12,11 +16,14 @@ constexpr float kGravityEmaAlpha = 0.1f; constexpr float kMinGravityProjection = 0.2f; // Let roll contribute more strongly as the pad approaches an upright posture. constexpr float kRollAimBoostMax = 2.0f; +constexpr float kMousePixelToRad = 0.0025f; bool s_sensor_enabled = false; bool s_accel_enabled = false; bool s_was_aiming = false; bool s_have_gravity_baseline = false; +bool s_mouse_enabled = false; +bool s_mouse_relative = false; float s_smooth_gx = 0.0f; float s_smooth_gy = 0.0f; float s_smooth_gz = 0.0f; @@ -36,6 +43,7 @@ void reset_filter_state() { s_baseline_gravity_y = s_baseline_gravity_z = 0.0f; s_was_aiming = false; s_have_gravity_baseline = false; + s_mouse_enabled = false; s_yaw_rad = s_pitch_rad = s_roll_rad = 0.0f; s_rollgoal_ax = s_rollgoal_az = 0; } @@ -46,14 +54,29 @@ float apply_deadband(float v, float deadband_rad_s) { } return v; } + +void disable_pad_sensors() { + if (s_sensor_enabled) { + PADSetSensorEnabled(PAD_CHAN0, PAD_SENSOR_GYRO, FALSE); + s_sensor_enabled = false; + } + if (s_accel_enabled) { + PADSetSensorEnabled(PAD_CHAN0, PAD_SENSOR_ACCEL, FALSE); + s_accel_enabled = false; + } +} } // namespace bool s_sensor_keep_alive = false; bool get_sensor_keep_alive() { return s_sensor_keep_alive; } void set_sensor_keep_alive(bool value) { s_sensor_keep_alive = value; } +bool rollgoal_gyro_enabled() { + return getSettings().game.enableGyroRollgoal && getSettings().game.gyroMode.getValue() != GyroMode::Mouse; +} + bool queryGyroAimContext() { - if (!static_cast(dusk::getSettings().game.enableGyroAim)) { + if (!static_cast(getSettings().game.enableGyroAim)) { return false; } @@ -71,15 +94,28 @@ void read(float dt) { const bool aim_just_ended = !aim_active && s_was_aiming; s_was_aiming = aim_active; + const bool mouse_mode = getSettings().game.gyroMode.getValue() == GyroMode::Mouse; + const bool mouse_gyro_active = !ui::any_document_visible() && mouse_mode && (aim_active || s_sensor_keep_alive); + SDL_Window* window = aurora::window::get_sdl_window(); + if (window != nullptr && mouse_gyro_active != s_mouse_relative && + SDL_SetWindowRelativeMouseMode(window, mouse_gyro_active)) + { + s_mouse_relative = mouse_gyro_active; + } + + if (mouse_gyro_active && !s_mouse_enabled && window != nullptr) { + const AuroraWindowSize sz = aurora::window::get_window_size(); + const float cx = static_cast(sz.width) * 0.5f; + const float cy = static_cast(sz.height) * 0.5f; + SDL_WarpMouseInWindow(window, cx, cy); + float discard_x = 0.0f; + float discard_y = 0.0f; + SDL_GetRelativeMouseState(&discard_x, &discard_y); + } + s_mouse_enabled = mouse_gyro_active; + if (!s_sensor_keep_alive && !aim_active) { - if (s_sensor_enabled) { - PADSetSensorEnabled(PAD_CHAN0, PAD_SENSOR_GYRO, FALSE); - s_sensor_enabled = false; - } - if (s_accel_enabled) { - PADSetSensorEnabled(PAD_CHAN0, PAD_SENSOR_ACCEL, FALSE); - s_accel_enabled = false; - } + disable_pad_sensors(); reset_filter_state(); return; } @@ -90,6 +126,31 @@ void read(float dt) { s_have_gravity_baseline = false; } + if (mouse_mode && !mouse_gyro_active) { + s_pitch_rad = 0.0f; + s_yaw_rad = 0.0f; + s_roll_rad = 0.0f; + return; + } + + if (mouse_mode) { + disable_pad_sensors(); + + float mx_rel = 0.0f; + float my_rel = 0.0f; + SDL_GetRelativeMouseState(&mx_rel, &my_rel); + // Convert pixels to radians + s_pitch_rad = my_rel * kMousePixelToRad * getSettings().game.gyroSensitivityX; + s_yaw_rad = -mx_rel * kMousePixelToRad * getSettings().game.gyroSensitivityY; + s_roll_rad = 0.0f; + + s_pitch_rad = getSettings().game.gyroInvertPitch ? -s_pitch_rad : s_pitch_rad; + s_yaw_rad = getSettings().game.gyroInvertYaw ? -s_yaw_rad : s_yaw_rad; + s_yaw_rad = getSettings().game.enableMirrorMode ? -s_yaw_rad : s_yaw_rad; + + return; + } + if (!s_sensor_enabled) { if (!PADHasSensor(PAD_CHAN0, PAD_SENSOR_GYRO)) { return; @@ -112,8 +173,8 @@ void read(float dt) { return; } - const float smooth_alpha = kGyroEmaAlphaMax + dusk::getSettings().game.gyroSmoothing * (kGyroEmaAlphaMin - kGyroEmaAlphaMax); - const float deadband = dusk::getSettings().game.gyroDeadband; + const float smooth_alpha = kGyroEmaAlphaMax + getSettings().game.gyroSmoothing * (kGyroEmaAlphaMin - kGyroEmaAlphaMax); + const float deadband = getSettings().game.gyroDeadband; s_smooth_gx += smooth_alpha * (gyro[0] - s_smooth_gx); s_smooth_gy += smooth_alpha * (gyro[1] - s_smooth_gy); @@ -123,8 +184,8 @@ void read(float dt) { const float yaw_rate = apply_deadband(s_smooth_gy, deadband); const float roll_rate = apply_deadband(s_smooth_gz, deadband); - s_pitch_rad = -pitch_rate * dt * dusk::getSettings().game.gyroSensitivityX; - s_roll_rad = roll_rate * dt * dusk::getSettings().game.gyroSensitivityX; // GYRO NOTE: Exposing Z sensitivity seems unusual, so I'm just using X + s_pitch_rad = -pitch_rate * dt * getSettings().game.gyroSensitivityX; + s_roll_rad = roll_rate * dt * getSettings().game.gyroSensitivityX; // GYRO NOTE: Exposing Z sensitivity seems unusual, so I'm just using X float horizontal_rate = yaw_rate; if (aim_active && s_accel_enabled) { @@ -162,11 +223,11 @@ void read(float dt) { } } - s_yaw_rad = horizontal_rate * dt * dusk::getSettings().game.gyroSensitivityY; + s_yaw_rad = horizontal_rate * dt * getSettings().game.gyroSensitivityY; - s_pitch_rad = dusk::getSettings().game.gyroInvertPitch ? -s_pitch_rad : s_pitch_rad; - s_yaw_rad = dusk::getSettings().game.gyroInvertYaw ? -s_yaw_rad : s_yaw_rad; - s_yaw_rad = dusk::getSettings().game.enableMirrorMode ? -s_yaw_rad : s_yaw_rad; + s_pitch_rad = getSettings().game.gyroInvertPitch ? -s_pitch_rad : s_pitch_rad; + s_yaw_rad = getSettings().game.gyroInvertYaw ? -s_yaw_rad : s_yaw_rad; + s_yaw_rad = getSettings().game.enableMirrorMode ? -s_yaw_rad : s_yaw_rad; } void getAimDeltas(float& out_yaw, float& out_pitch) { @@ -180,9 +241,9 @@ void rollgoalTick(bool play_active, s16 camera_yaw) { return; } - float pitch_rad = -s_pitch_rad * dusk::getSettings().game.gyroSensitivityRollgoal; - float roll_rad = s_roll_rad * dusk::getSettings().game.gyroSensitivityRollgoal; - roll_rad = dusk::getSettings().game.enableMirrorMode ? -roll_rad : roll_rad; + float pitch_rad = -s_pitch_rad * getSettings().game.gyroSensitivityRollgoal; + float roll_rad = s_roll_rad * getSettings().game.gyroSensitivityRollgoal; + roll_rad = getSettings().game.enableMirrorMode ? -roll_rad : roll_rad; s_rollgoal_az += cM_rad2s(roll_rad); cXyz in(roll_rad, 0.0f, pitch_rad); diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index c8e7178d67..f0d10d4226 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -68,6 +68,7 @@ UserSettings g_userSettings = { .midnasLamentNonStop {"game.midnasLamentNonStop", false}, // Input + .gyroMode {"game.gyroMode", GyroMode::Sensor}, .enableGyroAim {"game.enableGyroAim", false}, .enableGyroRollgoal {"game.enableGyroRollgoal", false}, .gyroSensitivityX {"game.gyroSensitivityX", 1.0f}, @@ -206,6 +207,7 @@ void registerSettings() { Register(g_userSettings.game.superClawshot); Register(g_userSettings.game.alwaysGreatspin); Register(g_userSettings.game.enableFrameInterpolation); + Register(g_userSettings.game.gyroMode); Register(g_userSettings.game.enableGyroAim); Register(g_userSettings.game.enableGyroRollgoal); Register(g_userSettings.game.gyroSensitivityX); diff --git a/src/dusk/ui/settings.cpp b/src/dusk/ui/settings.cpp index cbfde1ba3a..fd7365a39d 100644 --- a/src/dusk/ui/settings.cpp +++ b/src/dusk/ui/settings.cpp @@ -13,6 +13,7 @@ #include "m_Do/m_Do_main.h" #include "menu_bar.hpp" #include "number_button.hpp" +#include "menu_bar.hpp" #include "pane.hpp" #include "prelaunch.hpp" #include "ui.hpp" @@ -42,6 +43,11 @@ constexpr std::array kFpsOverlayCornerNames = { "Bottom Right", }; +constexpr std::array kGyroInputModeLabels = { + "Sensor", + "Mouse", +}; + bool try_parse_backend(std::string_view backend, AuroraBackend& outBackend) { if (backend == "auto") { outBackend = BACKEND_AUTO; @@ -200,7 +206,9 @@ int float_setting_percent(ConfigVar& var) { } bool gyro_enabled() { - return getSettings().game.enableGyroAim || getSettings().game.enableGyroRollgoal; + return getSettings().game.enableGyroAim || + (getSettings().game.enableGyroRollgoal && + getSettings().game.gyroMode.getValue() != GyroMode::Mouse); } struct ConfigBoolProps { @@ -634,12 +642,50 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) { [] { return !getSettings().game.freeCamera; }); leftPane.add_section("Gyro"); + leftPane.register_control( + leftPane.add_select_button({ + .key = "Gyro Input Method", + .getValue = + [] { + const auto mode = getSettings().game.gyroMode.getValue(); + const auto idx = static_cast(mode); + return Rml::String{kGyroInputModeLabels[idx]}; + }, + .isModified = + [] { + return getSettings().game.gyroMode.getValue() != + getSettings().game.gyroMode.getDefaultValue(); + }, + }), + rightPane, [](Pane& pane) { + for (size_t i = 0; i < kGyroInputModeLabels.size(); i++) { + pane + .add_button({ + .text = Rml::String{kGyroInputModeLabels[i]}, + .isSelected = + [i] { + return getSettings().game.gyroMode.getValue() == static_cast(i); + }, + }) + .on_pressed([i] { + mDoAud_seStartMenu(kSoundItemChange); + const GyroMode mode = static_cast(i); + getSettings().game.gyroMode.setValue(mode); + config::Save(); + }); + } + pane.add_rml( + "
Sensor reads motion directly from a supported controller's gyro via SDL.
" + "
Mouse treats mouse input as gyro, intended for use with the Steam Deck.
" + "
Mouse input cannot currently be used with Gyro Rollgoal."); + }); addOption("Gyro Aim", getSettings().game.enableGyroAim, "Enables gyro controls while in look mode, aiming a hawk, and aiming " "supported items.

Supported items include the Slingshot, Gale Boomerang, " "Hero's Bow, Clawshot(s), Ball and Chain, and Dominion Rod."); addOption("Gyro Rollgoal", getSettings().game.enableGyroRollgoal, - "Enables gyro controls for Rollgoal in Hena's Cabin."); + "Enables gyro controls for Rollgoal in Hena's Cabin.", + [] { return getSettings().game.gyroMode.getValue() == GyroMode::Mouse; }); config_percent_select(leftPane, rightPane, getSettings().game.gyroSensitivityY, "Gyro Pitch Sensitivity", "Controls vertical gyro aiming sensitivity.", 25, 400, 5, [] { return !gyro_enabled(); }); @@ -648,7 +694,11 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) { [] { return !gyro_enabled(); }); config_percent_select(leftPane, rightPane, getSettings().game.gyroSensitivityRollgoal, "Rollgoal Sensitivity", "Controls how strongly gyro input tilts the Rollgoal table.", - 25, 400, 5, [] { return !getSettings().game.enableGyroRollgoal; }); + 25, 400, 5, + [] { + return !getSettings().game.enableGyroRollgoal || + getSettings().game.gyroMode.getValue() == GyroMode::Mouse; + }); config_percent_select(leftPane, rightPane, getSettings().game.gyroDeadband, "Gyro Deadband", "Ignores small gyro movement to reduce drift and jitter.", 0, 50, 1, [] { return !gyro_enabled(); }); From a2c2988666c6edfc341bd44e888bbb11d0554a59 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Fri, 8 May 2026 17:12:50 -0600 Subject: [PATCH 336/390] Disable Sentry in CI builds --- CMakePresets.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakePresets.json b/CMakePresets.json index 92799249a9..3b2f0cae67 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -30,7 +30,7 @@ "CMAKE_CXX_COMPILER_LAUNCHER": "sccache", "DUSK_ENABLE_SENTRY_NATIVE": { "type": "BOOL", - "value": true + "value": false }, "DUSK_SENTRY_DSN": "$env{SENTRY_DSN}", "DUSK_SENTRY_ENVIRONMENT": "production" From a4fcc10f5f30934bc3c79b01981ae13cb63da4ff Mon Sep 17 00:00:00 2001 From: Luke Street Date: Fri, 8 May 2026 17:25:09 -0600 Subject: [PATCH 337/390] Make version logic tolerate prerelease semver --- CMakeLists.txt | 12 +-- src/dusk/update_check.cpp | 167 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 168 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 02eaeb183e..60aeb4e3fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,13 +48,15 @@ else () message(STATUS "Unable to find git, commit information will not be available") endif () -if (DUSK_WC_DESCRIBE MATCHES "^v([0-9]+)\\.([0-9]+)\\.([0-9]+)(-([0-9]+).*)?$") +if (DUSK_WC_DESCRIBE MATCHES "^v([0-9]+)\\.([0-9]+)\\.([0-9]+)([-+].*)?$") set(DUSK_SHORT_VERSION_STRING "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}") - if (CMAKE_MATCH_5) - set(DUSK_VERSION_STRING "${DUSK_SHORT_VERSION_STRING}.${CMAKE_MATCH_5}") - else () - set(DUSK_VERSION_STRING "${DUSK_SHORT_VERSION_STRING}.0") + set(DUSK_VERSION_TWEAK "0") + if (DUSK_WC_DESCRIBE MATCHES "^v[0-9]+\\.[0-9]+\\.[0-9]+-([0-9]+)(-dirty)?$") + set(DUSK_VERSION_TWEAK "${CMAKE_MATCH_1}") + elseif (DUSK_WC_DESCRIBE MATCHES "^v[0-9]+\\.[0-9]+\\.[0-9]+-[0-9A-Za-z.-]+-([0-9]+)(-dirty)?$") + set(DUSK_VERSION_TWEAK "${CMAKE_MATCH_1}") endif () + set(DUSK_VERSION_STRING "${DUSK_SHORT_VERSION_STRING}.${DUSK_VERSION_TWEAK}") else () set(DUSK_WC_DESCRIBE "UNKNOWN-VERSION") set(DUSK_VERSION_STRING "0.0.0.0") diff --git a/src/dusk/update_check.cpp b/src/dusk/update_check.cpp index 11c11795af..c1e332c432 100644 --- a/src/dusk/update_check.cpp +++ b/src/dusk/update_check.cpp @@ -5,9 +5,12 @@ #include "nlohmann/json.hpp" #include "version.h" +#include #include #include +#include #include +#include namespace dusk::update_check { namespace { @@ -20,8 +23,7 @@ struct Version { int major = 0; int minor = 0; int patch = 0; - - friend auto operator<=>(const Version&, const Version&) = default; + std::vector prerelease; }; std::string json_string(const json& value, const char* key) { @@ -57,6 +59,134 @@ bool consume(std::string_view& value, char expected) { return true; } +bool is_digit(char value) { + return value >= '0' && value <= '9'; +} + +bool is_identifier_char(char value) { + return is_digit(value) || (value >= 'A' && value <= 'Z') || (value >= 'a' && value <= 'z') || value == '-'; +} + +bool is_numeric_identifier(std::string_view value) { + if (value.empty()) { + return false; + } + for (const char c : value) { + if (!is_digit(c)) { + return false; + } + } + return true; +} + +bool is_identifier_list(std::string_view value) { + if (value.empty()) { + return false; + } + + bool expectingIdentifier = true; + for (const char c : value) { + if (c == '.') { + if (expectingIdentifier) { + return false; + } + expectingIdentifier = true; + continue; + } + if (!is_identifier_char(c)) { + return false; + } + expectingIdentifier = false; + } + + return !expectingIdentifier; +} + +std::string_view trim_git_describe_suffix(std::string_view value) { + if (value.ends_with("-dirty")) { + value.remove_suffix(6); + } + if (is_numeric_identifier(value)) { + return {}; + } + + const size_t suffixStart = value.rfind('-'); + if (suffixStart != std::string_view::npos && value.substr(0, suffixStart).find('.') != std::string_view::npos + && is_numeric_identifier(value.substr(suffixStart + 1))) { + value.remove_suffix(value.size() - suffixStart); + } + return value; +} + +void split_identifiers(std::string_view value, std::vector& identifiers) { + while (!value.empty()) { + const size_t separator = value.find('.'); + if (separator == std::string_view::npos) { + identifiers.push_back(value); + return; + } + identifiers.push_back(value.substr(0, separator)); + value.remove_prefix(separator + 1); + } +} + +std::string_view trim_leading_zeroes(std::string_view value) { + while (value.size() > 1 && value.front() == '0') { + value.remove_prefix(1); + } + return value; +} + +int compare_identifier(std::string_view lhs, std::string_view rhs) { + const bool lhsNumeric = is_numeric_identifier(lhs); + const bool rhsNumeric = is_numeric_identifier(rhs); + if (lhsNumeric && rhsNumeric) { + lhs = trim_leading_zeroes(lhs); + rhs = trim_leading_zeroes(rhs); + if (lhs.size() != rhs.size()) { + return lhs.size() < rhs.size() ? -1 : 1; + } + } else if (lhsNumeric != rhsNumeric) { + return lhsNumeric ? -1 : 1; + } + + const int result = lhs.compare(rhs); + if (result < 0) { + return -1; + } + if (result > 0) { + return 1; + } + return 0; +} + +int compare_version(const Version& lhs, const Version& rhs) { + if (lhs.major != rhs.major) { + return lhs.major < rhs.major ? -1 : 1; + } + if (lhs.minor != rhs.minor) { + return lhs.minor < rhs.minor ? -1 : 1; + } + if (lhs.patch != rhs.patch) { + return lhs.patch < rhs.patch ? -1 : 1; + } + if (lhs.prerelease.empty() != rhs.prerelease.empty()) { + return lhs.prerelease.empty() ? 1 : -1; + } + + const size_t commonSize = std::min(lhs.prerelease.size(), rhs.prerelease.size()); + for (size_t i = 0; i < commonSize; ++i) { + const int result = compare_identifier(lhs.prerelease[i], rhs.prerelease[i]); + if (result != 0) { + return result; + } + } + if (lhs.prerelease.size() != rhs.prerelease.size()) { + return lhs.prerelease.size() < rhs.prerelease.size() ? -1 : 1; + } + return 0; +} + std::optional parse_version(std::string_view value) { if (!value.empty() && value.front() == 'v') { value.remove_prefix(1); @@ -75,13 +205,38 @@ std::optional parse_version(std::string_view value) { if (!patch) { return std::nullopt; } - if (!value.empty() && value.front() != '-' && value.front() != '+') { - return std::nullopt; - } version.major = *major; version.minor = *minor; version.patch = *patch; + + if (value.empty()) { + return version; + } + if (value.front() == '+') { + value.remove_prefix(1); + if (!is_identifier_list(value)) { + return std::nullopt; + } + return version; + } + if (!consume(value, '-')) { + return std::nullopt; + } + + const size_t buildStart = value.find('+'); + std::string_view prerelease = value.substr(0, buildStart); + if (!is_identifier_list(prerelease)) { + return std::nullopt; + } + if (buildStart != std::string_view::npos && !is_identifier_list(value.substr(buildStart + 1))) { + return std::nullopt; + } + + prerelease = trim_git_describe_suffix(prerelease); + if (!prerelease.empty()) { + split_identifiers(prerelease, version.prerelease); + } return version; } @@ -185,7 +340,7 @@ Result check_latest_github_release(std::string_view owner, std::string_view repo }; } - const bool updateAvailable = *latestVersion > *currentVersion; + const bool updateAvailable = compare_version(*latestVersion, *currentVersion) > 0; return { .status = updateAvailable ? Status::UpdateAvailable : Status::UpToDate, .message = updateAvailable ? "Update available" : "Dusk is up to date", From 65e8577253cce7a51dc9120e70012da2fe8def6a Mon Sep 17 00:00:00 2001 From: Howard Luck Date: Fri, 8 May 2026 17:26:33 -0600 Subject: [PATCH 338/390] frame interp: fix b&c chain links (#724) --- include/d/actor/d_a_alink.h | 12 ++++++++++++ src/d/actor/d_a_alink.cpp | 26 ++++++++++++++++++++++++++ src/d/actor/d_a_alink_hook.inc | 27 +++++++++++++++++++++++++++ 3 files changed, 65 insertions(+) diff --git a/include/d/actor/d_a_alink.h b/include/d/actor/d_a_alink.h index 9980ab776f..107afc1ed3 100644 --- a/include/d/actor/d_a_alink.h +++ b/include/d/actor/d_a_alink.h @@ -4552,6 +4552,18 @@ public: void handleWolfHowl(); void handleQuickTransform(); bool checkGyroAimContext(); + + void onIronBallChainInterpCallback(); + + static const int IRON_BALL_CHAIN_COUNT = 102; + cXyz mIBChainInterpPrevPos[IRON_BALL_CHAIN_COUNT]; + cXyz mIBChainInterpCurrPos[IRON_BALL_CHAIN_COUNT]; + csXyz mIBChainInterpPrevAngle[IRON_BALL_CHAIN_COUNT]; + csXyz mIBChainInterpCurrAngle[IRON_BALL_CHAIN_COUNT]; + cXyz mIBChainInterpPrevHandRoot; + cXyz mIBChainInterpCurrHandRoot; + bool mIBChainInterpPrevValid; + bool mIBChainInterpCurrValid; #endif }; // Size: 0x385C diff --git a/src/d/actor/d_a_alink.cpp b/src/d/actor/d_a_alink.cpp index e14f598487..0204278ddc 100644 --- a/src/d/actor/d_a_alink.cpp +++ b/src/d/actor/d_a_alink.cpp @@ -51,6 +51,7 @@ #include "d/actor/d_a_ni.h" #include "d/d_s_play.h" +#include "dusk/frame_interpolation.h" #include "dusk/settings.h" #include "res/Object/Alink.h" #include @@ -14787,6 +14788,10 @@ void daAlink_c::deleteEquipItem(BOOL i_isPlaySound, BOOL i_isDeleteKantera) { mIronBallChainPos = NULL; mIronBallChainAngle = NULL; field_0x3848 = NULL; +#if TARGET_PC + mIBChainInterpPrevValid = false; + mIBChainInterpCurrValid = false; +#endif field_0x0774 = NULL; field_0x0778 = NULL; mpHookshotLinChk = NULL; @@ -19717,6 +19722,27 @@ int daAlink_c::draw() { ) { dComIfGd_getOpaListDark()->entryImm(mpHookChain, 0); + +#if TARGET_PC + if (dusk::getSettings().game.enableFrameInterpolation && + mEquipItem == dItemNo_IRONBALL_e && + mIronBallChainPos != NULL && mIronBallChainAngle != NULL) + { + if (mIBChainInterpCurrValid) { + memcpy(mIBChainInterpPrevPos, mIBChainInterpCurrPos, IRON_BALL_CHAIN_COUNT * sizeof(cXyz)); + memcpy(mIBChainInterpPrevAngle, mIBChainInterpCurrAngle, IRON_BALL_CHAIN_COUNT * sizeof(csXyz)); + mIBChainInterpPrevHandRoot = mIBChainInterpCurrHandRoot; + mIBChainInterpPrevValid = true; + } + + memcpy(mIBChainInterpCurrPos, mIronBallChainPos, IRON_BALL_CHAIN_COUNT * sizeof(cXyz)); + memcpy(mIBChainInterpCurrAngle, mIronBallChainAngle, IRON_BALL_CHAIN_COUNT * sizeof(csXyz)); + mIBChainInterpCurrHandRoot = mHookshotTopPos; + mIBChainInterpCurrValid = true; + + dusk::frame_interp::add_interpolation_callback(&ironBallChainInterpCallback, this); + } +#endif } } diff --git a/src/d/actor/d_a_alink_hook.inc b/src/d/actor/d_a_alink_hook.inc index c960d37a7b..36fba0c6d8 100644 --- a/src/d/actor/d_a_alink_hook.inc +++ b/src/d/actor/d_a_alink_hook.inc @@ -8,6 +8,8 @@ #include "d/actor/d_a_obj_swhang.h" #include "d/actor/d_a_obj_chandelier.h" #include "JSystem/J3DGraphBase/J3DMaterial.h" +#include "dusk/frame_interpolation.h" +#include "dusk/settings.h" enum { HS_MODE_NONE_e, @@ -235,6 +237,31 @@ void daAlink_c::hsChainShape_c::draw() { } } +#if TARGET_PC +static void ironBallChainInterpCallback(bool isSimFrame, void* pUserWork) { + static_cast(pUserWork)->onIronBallChainInterpCallback(); +} + +void daAlink_c::onIronBallChainInterpCallback() { + if (!mIBChainInterpPrevValid || !mIBChainInterpCurrValid) { + return; + } + if (mIronBallChainPos == NULL || mIronBallChainAngle == NULL) { + return; + } + + const f32 alpha = dusk::frame_interp::get_interpolation_step(); + + for (int i = 0; i < IRON_BALL_CHAIN_COUNT; i++) { + mIronBallChainPos[i] = mIBChainInterpPrevPos[i] + (mIBChainInterpCurrPos[i] - mIBChainInterpPrevPos[i]) * alpha; + mIronBallChainAngle[i].x = mIBChainInterpPrevAngle[i].x + (s16)((s16)(mIBChainInterpCurrAngle[i].x - mIBChainInterpPrevAngle[i].x) * alpha); + mIronBallChainAngle[i].y = mIBChainInterpPrevAngle[i].y + (s16)((s16)(mIBChainInterpCurrAngle[i].y - mIBChainInterpPrevAngle[i].y) * alpha); + mIronBallChainAngle[i].z = mIBChainInterpPrevAngle[i].z + (s16)((s16)(mIBChainInterpCurrAngle[i].z - mIBChainInterpPrevAngle[i].z) * alpha); + } + mHookshotTopPos = mIBChainInterpPrevHandRoot + (mIBChainInterpCurrHandRoot - mIBChainInterpPrevHandRoot) * alpha; +} +#endif + void daAlink_c::hookshotAtHitCallBack(dCcD_GObjInf* i_atObjInf, fopAc_ac_c* i_tgActor, dCcD_GObjInf* i_tgObjInf) { if (i_tgActor != NULL && fopAcM_IsActor(i_tgActor) && !i_tgObjInf->ChkTgHookshotThrough()) { From 34e10d384420e19b6fb43038f9021ca264c2151e Mon Sep 17 00:00:00 2001 From: Luke Street Date: Fri, 8 May 2026 17:55:39 -0600 Subject: [PATCH 339/390] Show "3-finger tap" for menu notif on mobile --- src/dusk/ui/overlay.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/dusk/ui/overlay.cpp b/src/dusk/ui/overlay.cpp index 0ce0b904ac..45482230a9 100644 --- a/src/dusk/ui/overlay.cpp +++ b/src/dusk/ui/overlay.cpp @@ -10,6 +10,10 @@ #include #include +#if defined(__APPLE__) +#include +#endif + namespace dusk::ui { namespace { aurora::Module Log{"dusk::ui::overlay"}; @@ -33,7 +37,7 @@ constexpr std::array, 3> kAutoSaveLayers{{ constexpr auto kMenuNotificationDuration = std::chrono::milliseconds(2500); -constexpr std::array kFpsCorners = { "tl", "tr", "bl", "br" }; +constexpr std::array kFpsCorners = {"tl", "tr", "bl", "br"}; Rml::Element* create_toast(Rml::Element* parent, const Toast& toast) { if (toast.type == "autosave") { @@ -130,13 +134,19 @@ Rml::String back_button_name() { return "Back"; } +#if defined(TARGET_ANDROID) || (defined(__APPLE__) && TARGET_OS_IOS && !TARGET_OS_MACCATALYST) +constexpr auto kMenuNotificationPrefix = "3-finger tap or"; +#else +constexpr auto kMenuNotificationPrefix = "Press F1 or"; +#endif + Rml::Element* create_menu_notification(Rml::Element* parent) { auto* elem = append(parent, "toast"); elem->SetClass("menu-notification", true); auto* message = append(elem, "message"); auto* row = append(message, "row"); - append(row, "span")->SetInnerRML("Press F1 or"); + append(row, "span")->SetInnerRML(kMenuNotificationPrefix); auto* icon = append(row, "icon"); icon->SetClass("controller", true); append(row, "span")->SetInnerRML(escape(back_button_name())); @@ -242,7 +252,8 @@ void Overlay::update() { const Uint64 now = SDL_GetPerformanceCounter(); // Limit updates to twice per second - const bool refreshLabel = perfFreq == 0 || mFpsLastUpdate == 0 || + const bool refreshLabel = + perfFreq == 0 || mFpsLastUpdate == 0 || static_cast(now - mFpsLastUpdate) >= 0.5 * static_cast(perfFreq); if (refreshLabel) { mFpsLastUpdate = now; From 78179eb93f8188596bccb0751af7d753b844dfcb Mon Sep 17 00:00:00 2001 From: roeming Date: Fri, 8 May 2026 20:56:38 -0400 Subject: [PATCH 340/390] comment out flags tab in editor (#727) Co-authored-by: roeming --- src/dusk/ui/editor.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dusk/ui/editor.cpp b/src/dusk/ui/editor.cpp index 09216a3b8a..469bb920e3 100644 --- a/src/dusk/ui/editor.cpp +++ b/src/dusk/ui/editor.cpp @@ -1881,9 +1881,9 @@ EditorWindow::EditorWindow() { } }); - add_tab("Flags", [this](Rml::Element* content) { - // TODO - }); + //add_tab("Flags", [this](Rml::Element* content) { + // // TODO + //}); add_tab("Minigame", [this](Rml::Element* content) { auto& leftPane = add_child(content, Pane::Type::Controlled); From d2a1dda52348f4f8adf0ea47b91c384c571b10df Mon Sep 17 00:00:00 2001 From: Irastris Date: Fri, 8 May 2026 21:00:12 -0400 Subject: [PATCH 341/390] Add interp callbacks to the stalks of four Baba variants --- include/d/actor/d_a_e_db.h | 6 ++++++ include/d/actor/d_a_e_hb.h | 6 ++++++ include/d/actor/d_a_e_yd.h | 6 ++++++ include/d/actor/d_a_e_yh.h | 6 ++++++ src/d/actor/d_a_e_db.cpp | 31 +++++++++++++++++++++++++++++++ src/d/actor/d_a_e_hb.cpp | 31 +++++++++++++++++++++++++++++++ src/d/actor/d_a_e_yd.cpp | 31 +++++++++++++++++++++++++++++++ src/d/actor/d_a_e_yh.cpp | 31 +++++++++++++++++++++++++++++++ 8 files changed, 148 insertions(+) diff --git a/include/d/actor/d_a_e_db.h b/include/d/actor/d_a_e_db.h index a95722a6d1..4f10715443 100644 --- a/include/d/actor/d_a_e_db.h +++ b/include/d/actor/d_a_e_db.h @@ -80,6 +80,12 @@ public: /* 0x125C */ u32 field_0x125c; /* 0x1260 */ u8 field_0x1260[0x126C - 0x1260]; /* 0x126C */ u8 HIOInit; +#if TARGET_PC + cXyz mStalkLineInterpPrev[12]; + cXyz mStalkLineInterpCurr[12]; + bool mStalkLineInterpPrevValid; + bool mStalkLineInterpCurrValid; +#endif }; STATIC_ASSERT(sizeof(e_db_class) == 0x1270); diff --git a/include/d/actor/d_a_e_hb.h b/include/d/actor/d_a_e_hb.h index a7e0241007..3069bcd325 100644 --- a/include/d/actor/d_a_e_hb.h +++ b/include/d/actor/d_a_e_hb.h @@ -73,6 +73,12 @@ public: /* 0x124C */ f32 field_0x124c; /* 0x1250 */ u8 field_0x1250[0x1264 - 0x1250]; /* 0x1264 */ u8 HIOInit; +#if TARGET_PC + cXyz mStalkLineInterpPrev[12]; + cXyz mStalkLineInterpCurr[12]; + bool mStalkLineInterpPrevValid; + bool mStalkLineInterpCurrValid; +#endif }; STATIC_ASSERT(sizeof(e_hb_class) == 0x1268); diff --git a/include/d/actor/d_a_e_yd.h b/include/d/actor/d_a_e_yd.h index 188e435ba5..44d6036600 100644 --- a/include/d/actor/d_a_e_yd.h +++ b/include/d/actor/d_a_e_yd.h @@ -74,6 +74,12 @@ public: /* 0x1250 */ f32 field_0x1250; /* 0x1254 */ u8 field_0x1254[0x1268 - 0x1254]; /* 0x1268 */ u8 field_0x1268; +#if TARGET_PC + cXyz mLineMatInterpPrev[12]; + cXyz mLineMatInterpCurr[12]; + bool mLineMatInterpPrevValid; + bool mLineMatInterpCurrValid; +#endif }; STATIC_ASSERT(sizeof(e_yd_class) == 0x126c); diff --git a/include/d/actor/d_a_e_yh.h b/include/d/actor/d_a_e_yh.h index 519e5e2779..63e8ac1882 100644 --- a/include/d/actor/d_a_e_yh.h +++ b/include/d/actor/d_a_e_yh.h @@ -77,6 +77,12 @@ public: /* 0x1260 */ u32 field_0x1260; /* 0x1260 */ u8 field_0x1264[0x1270 - 0x1264]; /* 0x1270 */ bool mIsHIOOwner; +#if TARGET_PC + cXyz mLineInterpPrev[12]; + cXyz mLineInterpCurr[12]; + bool mLineInterpPrevValid; + bool mLineInterpCurrValid; +#endif }; STATIC_ASSERT(sizeof(e_yh_class) == 0x1274); diff --git a/src/d/actor/d_a_e_db.cpp b/src/d/actor/d_a_e_db.cpp index cbd21176b9..4d60fbd6f6 100644 --- a/src/d/actor/d_a_e_db.cpp +++ b/src/d/actor/d_a_e_db.cpp @@ -10,6 +10,10 @@ #include "f_op/f_op_kankyo_mng.h" #include "f_op/f_op_actor_enemy.h" +#if TARGET_PC +#include "dusk/frame_interpolation.h" +#endif + class daE_DB_HIO_c : public JORReflexible { public: daE_DB_HIO_c(); @@ -66,6 +70,22 @@ static BOOL leaf_anm_init(e_db_class* i_this, int i_anm, f32 i_morf, u8 i_mode, return FALSE; } +#if TARGET_PC +static void daE_DB_interp_callback(bool isSimFrame, void* pUserWork) { + e_db_class* i_this = (e_db_class*)pUserWork; + if (!i_this->mStalkLineInterpPrevValid || !i_this->mStalkLineInterpCurrValid) { + return; + } + const f32 alpha = dusk::frame_interp::get_interpolation_step(); + cXyz* dst = i_this->stalkLine.getPos(0); + for (int i = 0; i < 12; i++) { + const cXyz& p0 = i_this->mStalkLineInterpPrev[i]; + const cXyz& p1 = i_this->mStalkLineInterpCurr[i]; + dst[i] = p0 + (p1 - p0) * alpha; + } +} +#endif + static int daE_DB_Draw(e_db_class* i_this) { fopAc_ac_c* actor = &i_this->enemy; @@ -95,6 +115,17 @@ static int daE_DB_Draw(e_db_class* i_this) { static GXColor l_color = {0x14, 0x0F, 0x00, 0xFF}; i_this->stalkLine.update(12, l_color, &actor->tevStr); dComIfGd_set3DlineMat(&i_this->stalkLine); +#if TARGET_PC + if (dusk::getSettings().game.enableFrameInterpolation) { + if (i_this->mStalkLineInterpCurrValid) { + memcpy(i_this->mStalkLineInterpPrev, i_this->mStalkLineInterpCurr, sizeof(i_this->mStalkLineInterpCurr)); + i_this->mStalkLineInterpPrevValid = true; + } + memcpy(i_this->mStalkLineInterpCurr, i_this->stalkLine.getPos(0), 12 * sizeof(cXyz)); + i_this->mStalkLineInterpCurrValid = true; + dusk::frame_interp::add_interpolation_callback(&daE_DB_interp_callback, i_this); + } +#endif for (int i = 1; i < 11; i++) { if (i_this->thornModel[i] != NULL) { diff --git a/src/d/actor/d_a_e_hb.cpp b/src/d/actor/d_a_e_hb.cpp index d3177ba0f6..8ed9058c6f 100644 --- a/src/d/actor/d_a_e_hb.cpp +++ b/src/d/actor/d_a_e_hb.cpp @@ -9,6 +9,10 @@ #include "d/actor/d_a_e_hb_leaf.h" #include "f_op/f_op_actor_enemy.h" +#if TARGET_PC +#include "dusk/frame_interpolation.h" +#endif + enum daE_HB_ACTION { ACTION_STAY, ACTION_APPEAR, @@ -64,6 +68,22 @@ static BOOL leaf_anm_init(e_hb_class* i_this, int i_anm, f32 i_morf, u8 i_mode, return FALSE; } +#if TARGET_PC +static void daE_HB_interp_callback(bool isSimFrame, void* pUserWork) { + e_hb_class* i_this = (e_hb_class*)pUserWork; + if (!i_this->mStalkLineInterpPrevValid || !i_this->mStalkLineInterpCurrValid) { + return; + } + const f32 alpha = dusk::frame_interp::get_interpolation_step(); + cXyz* dst = i_this->stalkLine.getPos(0); + for (int i = 0; i < 12; i++) { + const cXyz& p0 = i_this->mStalkLineInterpPrev[i]; + const cXyz& p1 = i_this->mStalkLineInterpCurr[i]; + dst[i] = p0 + (p1 - p0) * alpha; + } +} +#endif + static int daE_HB_Draw(e_hb_class* i_this) { fopAc_ac_c* actor = &i_this->enemy; @@ -82,6 +102,17 @@ static int daE_HB_Draw(e_hb_class* i_this) { static GXColor l_color = {0x14, 0x0F, 0x00, 0xFF}; i_this->stalkLine.update(12, l_color, &actor->tevStr); dComIfGd_set3DlineMat(&i_this->stalkLine); +#if TARGET_PC + if (dusk::getSettings().game.enableFrameInterpolation) { + if (i_this->mStalkLineInterpCurrValid) { + memcpy(i_this->mStalkLineInterpPrev, i_this->mStalkLineInterpCurr, sizeof(i_this->mStalkLineInterpCurr)); + i_this->mStalkLineInterpPrevValid = true; + } + memcpy(i_this->mStalkLineInterpCurr, i_this->stalkLine.getPos(0), 12 * sizeof(cXyz)); + i_this->mStalkLineInterpCurrValid = true; + dusk::frame_interp::add_interpolation_callback(&daE_HB_interp_callback, i_this); + } +#endif for (int i = 1; i < 11; i++) { if (i_this->thornModel[i] != NULL) { diff --git a/src/d/actor/d_a_e_yd.cpp b/src/d/actor/d_a_e_yd.cpp index bdcd044eed..18809e05ea 100644 --- a/src/d/actor/d_a_e_yd.cpp +++ b/src/d/actor/d_a_e_yd.cpp @@ -12,6 +12,10 @@ #include "d/d_cc_uty.h" #include "f_op/f_op_actor_enemy.h" +#if TARGET_PC +#include "dusk/frame_interpolation.h" +#endif + class daE_YD_HIO_c { public: daE_YD_HIO_c(); @@ -73,6 +77,22 @@ static s32 leaf_anm_init(e_yd_class* i_this, int param_1, f32 param_2, u8 param_ return false; } +#if TARGET_PC +static void daE_YD_interp_callback(bool isSimFrame, void* pUserWork) { + e_yd_class* i_this = (e_yd_class*)pUserWork; + if (!i_this->mLineMatInterpPrevValid || !i_this->mLineMatInterpCurrValid) { + return; + } + const f32 alpha = dusk::frame_interp::get_interpolation_step(); + cXyz* dst = i_this->mLineMat.getPos(0); + for (int i = 0; i < 12; i++) { + const cXyz& p0 = i_this->mLineMatInterpPrev[i]; + const cXyz& p1 = i_this->mLineMatInterpCurr[i]; + dst[i] = p0 + (p1 - p0) * alpha; + } +} +#endif + static s32 daE_YD_Draw(e_yd_class* i_this) { static GXColor l_color = { 0x14, 0x0F, 0x00, 0xFF }; @@ -86,6 +106,17 @@ static s32 daE_YD_Draw(e_yd_class* i_this) { i_this->mpMorf->entryDL(); i_this->mLineMat.update(12, l_color, &i_this->actor.tevStr); dComIfGd_set3DlineMat(&i_this->mLineMat); +#if TARGET_PC + if (dusk::getSettings().game.enableFrameInterpolation) { + if (i_this->mLineMatInterpCurrValid) { + memcpy(i_this->mLineMatInterpPrev, i_this->mLineMatInterpCurr, sizeof(i_this->mLineMatInterpCurr)); + i_this->mLineMatInterpPrevValid = true; + } + memcpy(i_this->mLineMatInterpCurr, i_this->mLineMat.getPos(0), 12 * sizeof(cXyz)); + i_this->mLineMatInterpCurrValid = true; + dusk::frame_interp::add_interpolation_callback(&daE_YD_interp_callback, i_this); + } +#endif for (s32 i = 1; i < 11; i++) { if (i_this->field_0x77c[i] != 0) { g_env_light.setLightTevColorType_MAJI(i_this->field_0x77c[i], &i_this->actor.tevStr); diff --git a/src/d/actor/d_a_e_yh.cpp b/src/d/actor/d_a_e_yh.cpp index bbbd3e5129..cf9955a7db 100644 --- a/src/d/actor/d_a_e_yh.cpp +++ b/src/d/actor/d_a_e_yh.cpp @@ -12,6 +12,10 @@ #include "f_op/f_op_actor_enemy.h" #include "f_op/f_op_kankyo_mng.h" +#if TARGET_PC +#include "dusk/frame_interpolation.h" +#endif + class daE_YH_HIO_c : public JORReflexible { public: daE_YH_HIO_c(); @@ -85,6 +89,22 @@ static BOOL leaf_anm_init(e_yh_class* i_this, int param_2, f32 param_3, u8 param return FALSE; } +#if TARGET_PC +static void daE_YH_interp_callback(bool isSimFrame, void* pUserWork) { + e_yh_class* i_this = (e_yh_class*)pUserWork; + if (!i_this->mLineInterpPrevValid || !i_this->mLineInterpCurrValid) { + return; + } + const f32 alpha = dusk::frame_interp::get_interpolation_step(); + cXyz* dst = i_this->mLine.getPos(0); + for (int i = 0; i < 12; i++) { + const cXyz& p0 = i_this->mLineInterpPrev[i]; + const cXyz& p1 = i_this->mLineInterpCurr[i]; + dst[i] = p0 + (p1 - p0) * alpha; + } +} +#endif + static int daE_YH_Draw(e_yh_class* i_this) { fopAc_ac_c* a_this = (fopAc_ac_c*)i_this; @@ -114,6 +134,17 @@ static int daE_YH_Draw(e_yh_class* i_this) { i_this->mLine.update(12, l_color, &a_this->tevStr); dComIfGd_set3DlineMat(&i_this->mLine); +#if TARGET_PC + if (dusk::getSettings().game.enableFrameInterpolation) { + if (i_this->mLineInterpCurrValid) { + memcpy(i_this->mLineInterpPrev, i_this->mLineInterpCurr, sizeof(i_this->mLineInterpCurr)); + i_this->mLineInterpPrevValid = true; + } + memcpy(i_this->mLineInterpCurr, i_this->mLine.getPos(0), 12 * sizeof(cXyz)); + i_this->mLineInterpCurrValid = true; + dusk::frame_interp::add_interpolation_callback(&daE_YH_interp_callback, i_this); + } +#endif for (int i = 1; i < 11; i++) { if (i_this->mModels[i] != NULL) { From 71c892368dfe146f6ffdcf13cd6e5194b77c7615 Mon Sep 17 00:00:00 2001 From: doop <56421834+dooplecks@users.noreply.github.com> Date: Fri, 8 May 2026 21:31:46 -0400 Subject: [PATCH 342/390] Use float vertex positions for trim (#729) Fixes #726 and looks much smoother. --- src/m_Do/m_Do_graphic.cpp | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/m_Do/m_Do_graphic.cpp b/src/m_Do/m_Do_graphic.cpp index 61eaf3bc2d..424f69cf4b 100644 --- a/src/m_Do/m_Do_graphic.cpp +++ b/src/m_Do/m_Do_graphic.cpp @@ -1194,8 +1194,13 @@ static void trimming(view_class* param_0, view_port_class* param_1) { if ((y_orig_pos == 0) && (param_1->scissor.y_orig != param_1->y_orig || (param_1->scissor.height != param_1->height))) { + #if TARGET_PC + f32 sc_top = param_1->scissor.y_orig; + f32 sc_bottom = param_1->scissor.y_orig + param_1->scissor.height; + #else s32 sc_top = (int)param_1->scissor.y_orig; s32 sc_bottom = param_1->scissor.y_orig + param_1->scissor.height; + #endif GXSetNumChans(1); GXSetChanCtrl(GX_ALPHA0, GX_FALSE, GX_SRC_REG, GX_SRC_REG, 0, GX_DF_NONE, GX_AF_NONE); GXSetNumTexGens(0); @@ -1224,20 +1229,20 @@ static void trimming(view_class* param_0, view_port_class* param_1) { GXLoadPosMtxImm(cMtx_getIdentity(), 0); GXClearVtxDesc(); GXSetVtxDesc(GX_VA_POS, GX_DIRECT); - GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_CLR_RGBA, GX_RGBA4, 0); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_CLR_RGBA, DUSK_IF_ELSE(GX_F32, GX_RGBA4), 0); GXSetProjection(ortho, GX_ORTHOGRAPHIC); GXSetCurrentMtx(0); GXBegin(GX_QUADS, GX_VTXFMT0, 8); #if TARGET_PC - GXPosition3s16(0, 0, -5); - GXPosition3s16(param_1->width, 0, -5); - GXPosition3s16(param_1->width, sc_top, -5); - GXPosition3s16(0, sc_top, -5); - GXPosition3s16(0, sc_bottom, -5); - GXPosition3s16(param_1->width, sc_bottom, -5); - GXPosition3s16(param_1->width, param_1->height, -5); - GXPosition3s16(0, param_1->height, -5); + GXPosition3f32(0, 0, -5); + GXPosition3f32(param_1->width, 0, -5); + GXPosition3f32(param_1->width, sc_top, -5); + GXPosition3f32(0, sc_top, -5); + GXPosition3f32(0, sc_bottom, -5); + GXPosition3f32(param_1->width, sc_bottom, -5); + GXPosition3f32(param_1->width, param_1->height, -5); + GXPosition3f32(0, param_1->height, -5); #else GXPosition3s16(0, 0, -5); GXPosition3s16(FB_WIDTH, 0, -5); From 4d4a80891feb7e249fdc28ba126a4c13edbb95f3 Mon Sep 17 00:00:00 2001 From: Pheenoh Date: Fri, 8 May 2026 20:21:37 -0600 Subject: [PATCH 343/390] frame interp: fix obj_fchain --- include/d/actor/d_a_obj_fchain.h | 12 ++++++++++ src/d/actor/d_a_obj_fchain.cpp | 39 ++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/include/d/actor/d_a_obj_fchain.h b/include/d/actor/d_a_obj_fchain.h index 1bd7b9a810..7c4ae74faf 100644 --- a/include/d/actor/d_a_obj_fchain.h +++ b/include/d/actor/d_a_obj_fchain.h @@ -31,6 +31,10 @@ public: csXyz* getAngle() { return field_0x8a4; } J3DModelData* getModelData() { return mModelData; } +#if TARGET_PC + void onInterpCallback(); +#endif + private: /* 0x568 */ request_of_phase_process_class mPhase; /* 0x570 */ J3DModelData* mModelData; @@ -42,6 +46,14 @@ private: /* 0x694 */ cXyz field_0x694[22]; /* 0x79C */ cXyz field_0x79c[22]; /* 0x8A4 */ csXyz field_0x8a4[22]; + +#if TARGET_PC + static const int CHAIN_COUNT = 22; + cXyz mChainInterpPrev[CHAIN_COUNT]; + cXyz mChainInterpCurr[CHAIN_COUNT]; + bool mChainInterpPrevValid; + bool mChainInterpCurrValid; +#endif }; STATIC_ASSERT(sizeof(daObjFchain_c) == 0x928); diff --git a/src/d/actor/d_a_obj_fchain.cpp b/src/d/actor/d_a_obj_fchain.cpp index e681fec4e7..024b4ecf8b 100644 --- a/src/d/actor/d_a_obj_fchain.cpp +++ b/src/d/actor/d_a_obj_fchain.cpp @@ -10,6 +10,8 @@ #include "JSystem/J3DGraphBase/J3DDrawBuffer.h" #include "SSystem/SComponent/c_math.h" #include "d/d_com_inf_game.h" +#include "dusk/frame_interpolation.h" +#include "dusk/settings.h" #include static char const l_arcName[] = "Fchain"; @@ -65,6 +67,10 @@ int daObjFchain_c::create() { local_48++; } rv = cPhs_COMPLEATE_e; +#if TARGET_PC + mChainInterpPrevValid = false; + mChainInterpCurrValid = false; +#endif break; } return rv; @@ -289,6 +295,26 @@ void daObjFchain_shape_c::draw() { } } +#if TARGET_PC +static void fchain_interp_callback(bool isSimFrame, void* pUserWork) { + static_cast(pUserWork)->onInterpCallback(); +} + +void daObjFchain_c::onInterpCallback() { + if (!mChainInterpPrevValid || !mChainInterpCurrValid) { + return; + } + + const f32 alpha = dusk::frame_interp::get_interpolation_step(); + + for (int i = 0; i < CHAIN_COUNT; i++) { + const cXyz& p0 = mChainInterpPrev[i]; + const cXyz& p1 = mChainInterpCurr[i]; + field_0x694[i] = p0 + (p1 - p0) * alpha; + } +} +#endif + int daObjFchain_c::draw() { if (field_0x584 != 0) { g_env_light.settingTevStruct(0, ¤t.pos, &tevStr); @@ -297,6 +323,19 @@ int daObjFchain_c::draw() { return 1; } dComIfGd_getOpaListDark()->entryImm(&mShape, 0); + +#if TARGET_PC + if (dusk::getSettings().game.enableFrameInterpolation) { + if (mChainInterpCurrValid) { + memcpy(mChainInterpPrev, mChainInterpCurr, sizeof(mChainInterpCurr)); + mChainInterpPrevValid = true; + } + + memcpy(mChainInterpCurr, field_0x694, sizeof(mChainInterpCurr)); + mChainInterpCurrValid = true; + dusk::frame_interp::add_interpolation_callback(&fchain_interp_callback, this); + } +#endif } return 1; } From 06c77a68184d64d93504ad54bdf6655e4700a90b Mon Sep 17 00:00:00 2001 From: Pheenoh Date: Fri, 8 May 2026 21:15:52 -0600 Subject: [PATCH 344/390] frame interp: e_s1 & e_yg --- include/d/actor/d_a_e_s1.h | 9 ++++++++ include/d/actor/d_a_e_yg.h | 9 ++++++++ src/d/actor/d_a_e_s1.cpp | 42 +++++++++++++++++++++++++++++++++++ src/d/actor/d_a_e_yg.cpp | 45 +++++++++++++++++++++++++++++++++++++- 4 files changed, 104 insertions(+), 1 deletion(-) diff --git a/include/d/actor/d_a_e_s1.h b/include/d/actor/d_a_e_s1.h index a631ba47ac..5cbae84696 100644 --- a/include/d/actor/d_a_e_s1.h +++ b/include/d/actor/d_a_e_s1.h @@ -81,6 +81,15 @@ public: /* 0x306D */ u8 field_0x306D[0x307C - 0x306D]; /* 0x307C */ u32 mBodyEffEmtrID; /* 0x3080 */ u8 mInitHIO; + +#if TARGET_PC + static const int HAIR_STRAND_COUNT = 22; + static const int HAIR_SEGMENT_COUNT = 16; + cXyz mHairInterpPrev[HAIR_STRAND_COUNT * HAIR_SEGMENT_COUNT]; + cXyz mHairInterpCurr[HAIR_STRAND_COUNT * HAIR_SEGMENT_COUNT]; + bool mHairInterpPrevValid; + bool mHairInterpCurrValid; +#endif }; STATIC_ASSERT(sizeof(e_s1_class) == 0x3084); diff --git a/include/d/actor/d_a_e_yg.h b/include/d/actor/d_a_e_yg.h index 69a85430a8..6be19933cb 100644 --- a/include/d/actor/d_a_e_yg.h +++ b/include/d/actor/d_a_e_yg.h @@ -63,6 +63,15 @@ public: /* 0x0BB4 */ yg_ke_s mYgKes[13]; /* 0x1880 */ mDoExt_3DlineMat0_c mLineMat; /* 0x189C */ u8 mIsFirstSpawn; + +#if TARGET_PC + static const int TENTACLE_STRAND_COUNT = 13; + static const int TENTACLE_SEGMENT_COUNT = 10; + cXyz mTentacleInterpPrev[TENTACLE_STRAND_COUNT * TENTACLE_SEGMENT_COUNT]; + cXyz mTentacleInterpCurr[TENTACLE_STRAND_COUNT * TENTACLE_SEGMENT_COUNT]; + bool mTentacleInterpPrevValid; + bool mTentacleInterpCurrValid; +#endif }; STATIC_ASSERT(sizeof(e_yg_class) == 0x18a0); diff --git a/src/d/actor/d_a_e_s1.cpp b/src/d/actor/d_a_e_s1.cpp index 48cd7d6800..a5a05fce20 100644 --- a/src/d/actor/d_a_e_s1.cpp +++ b/src/d/actor/d_a_e_s1.cpp @@ -14,6 +14,8 @@ #include "d/d_s_play.h" #include "f_op/f_op_actor_enemy.h" #include "f_op/f_op_camera_mng.h" +#include "dusk/frame_interpolation.h" +#include "dusk/settings.h" #include class daE_S1_HIO_c { @@ -99,6 +101,25 @@ static void anm_init(e_s1_class* i_this, int i_resNo, f32 i_morf, u8 i_attr, f32 i_this->mAnm = i_resNo; } +#if TARGET_PC +static void daE_S1_interp_callback(bool isSimFrame, void* pUserWork) { + e_s1_class* i_this = (e_s1_class*)pUserWork; + if (!i_this->mHairInterpPrevValid || !i_this->mHairInterpCurrValid) { + return; + } + const f32 alpha = dusk::frame_interp::get_interpolation_step(); + for (int s = 0; s < e_s1_class::HAIR_STRAND_COUNT; s++) { + cXyz* dst = i_this->mLineMat.getPos(s); + for (int i = 0; i < e_s1_class::HAIR_SEGMENT_COUNT; i++) { + int idx = s * e_s1_class::HAIR_SEGMENT_COUNT + i; + const cXyz& p0 = i_this->mHairInterpPrev[idx]; + const cXyz& p1 = i_this->mHairInterpCurr[idx]; + dst[i] = p0 + (p1 - p0) * alpha; + } + } +} +#endif + static int daE_S1_Draw(e_s1_class* i_this) { if (i_this->field_0x306c != 0) { return 1; @@ -132,6 +153,22 @@ static int daE_S1_Draw(e_s1_class* i_this) { i_this->mLineMat.update(16, line_color, &i_this->tevStr); dComIfGd_set3DlineMatDark(&i_this->mLineMat); +#if TARGET_PC + if (dusk::getSettings().game.enableFrameInterpolation) { + if (i_this->mHairInterpCurrValid) { + memcpy(i_this->mHairInterpPrev, i_this->mHairInterpCurr, sizeof(i_this->mHairInterpCurr)); + i_this->mHairInterpPrevValid = true; + } + for (int s = 0; s < e_s1_class::HAIR_STRAND_COUNT; s++) { + cXyz* src = i_this->mLineMat.getPos(s); + memcpy(&i_this->mHairInterpCurr[s * e_s1_class::HAIR_SEGMENT_COUNT], src, + e_s1_class::HAIR_SEGMENT_COUNT * sizeof(cXyz)); + } + i_this->mHairInterpCurrValid = true; + dusk::frame_interp::add_interpolation_callback(&daE_S1_interp_callback, i_this); + } +#endif + dComIfGd_setList(); return 1; } @@ -2149,6 +2186,11 @@ static int daE_S1_Create(fopAc_ac_c* i_this) { return cPhs_ERROR_e; } +#if TARGET_PC + a_this->mHairInterpPrevValid = false; + a_this->mHairInterpCurrValid = false; +#endif + OS_REPORT("//////////////E_S1 SET 2 !!\n"); if (path_no != 0xFF) { diff --git a/src/d/actor/d_a_e_yg.cpp b/src/d/actor/d_a_e_yg.cpp index 9ab6c80e6d..44a8aee249 100644 --- a/src/d/actor/d_a_e_yg.cpp +++ b/src/d/actor/d_a_e_yg.cpp @@ -10,6 +10,8 @@ #include "f_op/f_op_kankyo_mng.h" #include "d/actor/d_a_obj_carry.h" #include "Z2AudioLib/Z2Instances.h" +#include "dusk/frame_interpolation.h" +#include "dusk/settings.h" #include "f_op/f_op_actor_enemy.h" enum E_yg_RES_File_ID { @@ -134,7 +136,26 @@ static BOOL pl_check(e_yg_class* i_this, f32 i_dist) { return FALSE; } -static int daE_YG_Draw(e_yg_class* i_this) { +#if TARGET_PC +static void daE_YG_interp_callback(bool isSimFrame, void* pUserWork) { + e_yg_class* i_this = (e_yg_class*)pUserWork; + if (!i_this->mTentacleInterpPrevValid || !i_this->mTentacleInterpCurrValid) { + return; + } + const f32 alpha = dusk::frame_interp::get_interpolation_step(); + for (int s = 0; s < e_yg_class::TENTACLE_STRAND_COUNT; s++) { + cXyz* dst = i_this->mLineMat.getPos(s); + for (int i = 0; i < e_yg_class::TENTACLE_SEGMENT_COUNT; i++) { + int idx = s * e_yg_class::TENTACLE_SEGMENT_COUNT + i; + const cXyz& p0 = i_this->mTentacleInterpPrev[idx]; + const cXyz& p1 = i_this->mTentacleInterpCurr[idx]; + dst[i] = p0 + (p1 - p0) * alpha; + } + } +} +#endif + +static int daE_YG_Draw(e_yg_class* i_this) { if (i_this->mDispFlag) { return 1; } @@ -160,6 +181,23 @@ static int daE_YG_Draw(e_yg_class* i_this) { color.a = 0xFF; i_this->mLineMat.update(10, color, &actor->tevStr); dComIfGd_set3DlineMatDark(&i_this->mLineMat); + +#if TARGET_PC + if (dusk::getSettings().game.enableFrameInterpolation) { + if (i_this->mTentacleInterpCurrValid) { + memcpy(i_this->mTentacleInterpPrev, i_this->mTentacleInterpCurr, sizeof(i_this->mTentacleInterpCurr)); + i_this->mTentacleInterpPrevValid = true; + } + for (int s = 0; s < e_yg_class::TENTACLE_STRAND_COUNT; s++) { + cXyz* src = i_this->mLineMat.getPos(s); + memcpy(&i_this->mTentacleInterpCurr[s * e_yg_class::TENTACLE_SEGMENT_COUNT], src, + e_yg_class::TENTACLE_SEGMENT_COUNT * sizeof(cXyz)); + } + i_this->mTentacleInterpCurrValid = true; + dusk::frame_interp::add_interpolation_callback(&daE_YG_interp_callback, i_this); + } +#endif + dComIfGd_setList(); return 1; @@ -1378,6 +1416,11 @@ static cPhs_Step daE_YG_Create(fopAc_ac_c* actor) { return cPhs_ERROR_e; } +#if TARGET_PC + i_this->mTentacleInterpPrevValid = false; + i_this->mTentacleInterpCurrValid = false; +#endif + if (!hio_set) { i_this->mIsFirstSpawn = 1; hio_set = true; From e42c4d3174321c1fecd0a3b5ef376c753d891289 Mon Sep 17 00:00:00 2001 From: SuperDude88 <82904174+SuperDude88@users.noreply.github.com> Date: Fri, 8 May 2026 23:19:48 -0400 Subject: [PATCH 345/390] Number Button Fix - Add `is_editing` helper to BaseStringButton - Block left/right input from changing number while typing Resolves #706 --- src/dusk/ui/number_button.cpp | 4 ++-- src/dusk/ui/string_button.cpp | 10 +++++----- src/dusk/ui/string_button.hpp | 1 + 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/dusk/ui/number_button.cpp b/src/dusk/ui/number_button.cpp index ab5095cf3f..3735855140 100644 --- a/src/dusk/ui/number_button.cpp +++ b/src/dusk/ui/number_button.cpp @@ -54,7 +54,7 @@ void NumberButton::set_value(Rml::String value) { } bool NumberButton::handle_nav_command(NavCommand cmd) { - if (cmd == NavCommand::Left || cmd == NavCommand::Right) { + if (!is_editing() && (cmd == NavCommand::Left || cmd == NavCommand::Right)) { const int newValue = std::clamp( mGetValue() + (cmd == NavCommand::Right ? mStep : -mStep), mMin, mMax); if (newValue != mGetValue()) { @@ -66,4 +66,4 @@ bool NumberButton::handle_nav_command(NavCommand cmd) { return BaseStringButton::handle_nav_command(cmd); } -} // namespace dusk::ui \ No newline at end of file +} // namespace dusk::ui diff --git a/src/dusk/ui/string_button.cpp b/src/dusk/ui/string_button.cpp index a267e5b0e0..7210e87803 100644 --- a/src/dusk/ui/string_button.cpp +++ b/src/dusk/ui/string_button.cpp @@ -24,7 +24,7 @@ void BaseStringButton::update() { } void BaseStringButton::start_editing() { - if (mInputElem != nullptr) { + if (is_editing()) { return; } @@ -79,14 +79,14 @@ void BaseStringButton::request_stop_editing(bool commit, bool refocusRoot) { bool BaseStringButton::handle_nav_command(NavCommand cmd) { if (cmd == NavCommand::Confirm) { - if (mInputElem == nullptr) { + if (!is_editing()) { start_editing(); } else { request_stop_editing(true, true); } return true; } else if (cmd == NavCommand::Cancel) { - if (mInputElem != nullptr) { + if (is_editing()) { request_stop_editing(false, true); return true; } @@ -95,7 +95,7 @@ bool BaseStringButton::handle_nav_command(NavCommand cmd) { } void BaseStringButton::focus_input() { - if (mInputElem == nullptr) { + if (!is_editing()) { return; } @@ -111,7 +111,7 @@ void BaseStringButton::focus_input() { void BaseStringButton::stop_editing(bool commit, bool refocusRoot) { mPendingStopEditing = false; mPendingInputFocusFrames = 0; - if (mInputElem == nullptr) { + if (!is_editing()) { return; } if (commit) { diff --git a/src/dusk/ui/string_button.hpp b/src/dusk/ui/string_button.hpp index d84b977f37..94f2cebcbe 100644 --- a/src/dusk/ui/string_button.hpp +++ b/src/dusk/ui/string_button.hpp @@ -20,6 +20,7 @@ public: void request_stop_editing(bool commit, bool refocusRoot); protected: + bool is_editing() { return mInputElem != nullptr; } bool handle_nav_command(NavCommand cmd) override; virtual void set_value(Rml::String value) = 0; virtual Rml::String input_value() { return format_value(); } From 13dd3c3932e3db8c38aaec2a66953d9120c96062 Mon Sep 17 00:00:00 2001 From: SuperDude88 <82904174+SuperDude88@users.noreply.github.com> Date: Sat, 9 May 2026 08:30:46 -0400 Subject: [PATCH 346/390] Clamp LOD For Cutscene Midna (#728) - Sets max eye LOD level to 0 for `demo00_Midna_cut00_FC_tongue` and `demo00_Midna_cut00_BD_tmp` --- src/d/actor/d_a_midna.cpp | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/d/actor/d_a_midna.cpp b/src/d/actor/d_a_midna.cpp index 2356b693be..3bc500991d 100644 --- a/src/d/actor/d_a_midna.cpp +++ b/src/d/actor/d_a_midna.cpp @@ -419,9 +419,30 @@ int daMidna_c::createHeap() { return 0; } +#if TARGET_PC + if (mpDemoFCTongueBmd != NULL) { + if(!daAlink_c::initDemoBck(&mpDemoFCTmpBck, "demo00_Midna_cut00_FC_tmp.bck")) { + return 0; + } + + // Update Midna's eye maxLOD to prevent the eyes from disappearing + J3DTexture* tex = mpDemoFCTongueBmd->getModelData()->getTexture(); + JUTNameTab* nametable = mpDemoFCTongueBmd->getModelData()->getTextureName(); + if (tex != nullptr && nametable != nullptr) { + for (u16 i = 0; i < tex->getNum(); i++) { + const char* tex_name = nametable->getName(i); + if (tex_name != NULL && strcmp(tex_name, "midona_eyeball") == 0) { + ResTIMG* timg = tex->getResTIMG(i); + timg->maxLOD = 0; + } + } + } + } +#else if (mpDemoFCTongueBmd != NULL && !daAlink_c::initDemoBck(&mpDemoFCTmpBck, "demo00_Midna_cut00_FC_tmp.bck")) { return 0; } +#endif modelData = (J3DModelData*)dComIfG_getObjectRes(dStage_roomControl_c::getDemoArcName(), "demo00_Midna_cut00_BD_tmp.bmd"); @@ -433,6 +454,21 @@ int daMidna_c::createHeap() { modelData->getMaterialNodePointer(2)->setMaterialAnm(mpEyeMatAnm[0]); modelData->getMaterialNodePointer(3)->setMaterialAnm(mpEyeMatAnm[1]); + +#if TARGET_PC + // Update Midna's eye maxLOD to prevent the eyes from disappearing + J3DTexture* tex = modelData->getTexture(); + JUTNameTab* nametable = modelData->getTextureName(); + if (tex != nullptr && nametable != nullptr) { + for (u16 i = 0; i < tex->getNum(); i++) { + const char* tex_name = nametable->getName(i); + if (tex_name != NULL && strcmp(tex_name, "midona_eyeball") == 0) { + ResTIMG* timg = tex->getResTIMG(i); + timg->maxLOD = 0; + } + } + } +#endif } if (!initDemoModel(&mpDemoBDMaskBmd, "demo00_Midna_cut00_BD_mask.bmd", 0)) { From d8a1dd1da452b0fca4def6b130fa55d5a4bea1f9 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Sat, 9 May 2026 09:15:10 -0400 Subject: [PATCH 347/390] Recording Mode - Mute streams & Fix 1 note playing --- src/f_ap/f_ap_game.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/f_ap/f_ap_game.cpp b/src/f_ap/f_ap_game.cpp index dc14933b50..2c6cb0a925 100644 --- a/src/f_ap/f_ap_game.cpp +++ b/src/f_ap/f_ap_game.cpp @@ -745,7 +745,8 @@ static void duskExecute() { updateAutoSave(); if (dusk::getSettings().game.recordingMode) { - Z2GetSeqMgr()->bgmAllMute(0, 0); + Z2GetSoundMgr()->getSeqMgr()->getParams()->moveVolume(0.0f, 0); + Z2GetSoundMgr()->getStreamMgr()->getParams()->moveVolume(0.0f, 0); } if (mDoCPd_c::getHoldR(PAD_1) && mDoCPd_c::getTrigX(PAD_1)) { From 80dd5ff2780a15c29af2eea61c254ed09c8053dc Mon Sep 17 00:00:00 2001 From: TakaRikka Date: Sat, 9 May 2026 07:32:29 -0700 Subject: [PATCH 348/390] revert mirror mode message override for now --- src/d/d_msg_object.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/d/d_msg_object.cpp b/src/d/d_msg_object.cpp index 7e3be2cb08..44b5c66571 100644 --- a/src/d/d_msg_object.cpp +++ b/src/d/d_msg_object.cpp @@ -427,14 +427,15 @@ static void dummyStrings() { dMsgObject_HIO_c g_MsgObject_HIO_c; int dMsgObject_c::_execute() { -#if TARGET_PC +// TODO: enabling wii message overrides fixes direction text, but gives wrong item control text +/*#if TARGET_PC if (dusk::getSettings().game.enableMirrorMode) { // enable wii message index override g_MsgObject_HIO_c.mMessageDisplay = 1; } else if (!dusk::getSettings().game.enableMirrorMode && g_MsgObject_HIO_c.mMessageDisplay == 1) { g_MsgObject_HIO_c.mMessageDisplay = 0; } -#endif +#endif*/ field_0x4c7 = 0; From 4290726691b9818878e9fa76614dff6f84b5a841 Mon Sep 17 00:00:00 2001 From: TakaRikka Date: Sat, 9 May 2026 07:38:19 -0700 Subject: [PATCH 349/390] update setup instructions --- README.md | 17 ++++++++++--- docs/ios-install-altstore.md | 46 ++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 docs/ios-install-altstore.md diff --git a/README.md b/README.md index 5e7412e6aa..b5275e6bdc 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@

Official Website • - Discord + Discord

@@ -28,13 +28,24 @@ First, make sure your dump of the game is clean and supported by Dusk. You can d | GameCube USA | `75edd3ddff41f125d1b4ce1a40378f1b565519e7` | | GameCube EUR | `2601822a488eeb86fb89db16ca8f29c2c953e1ca` | +*Support for other versions of the game is planned in the future. + ### 2. Download [Dusk](https://github.com/TwilitRealm/dusk/releases) ### 3. Setup the game - +**Windows / macOS / Linux** - Extract the .zip file - Launch Dusk -- Press **Select Disc Image** and provide the path to your supported game dump. +- Press **Select Disc Image** and provide the path to your supported game dump +- Press **Play**! + +**iOS** +- Follow the [iOS setup guide](docs/ios-install-altstore.md) + +**Android** +- Install the Dusk apk +- Launch Dusk +- Press **Select Disc Image** and provide the path to your supported game dump - Press **Play**! # Building diff --git a/docs/ios-install-altstore.md b/docs/ios-install-altstore.md new file mode 100644 index 0000000000..fdfc7689d6 --- /dev/null +++ b/docs/ios-install-altstore.md @@ -0,0 +1,46 @@ +# Installing Dusk on iOS via AltStore + +## Prerequisites + +- Mac with Homebrew installed +- iPhone connected via USB +- Dusk IPA file (download the latest `Dusk-vX.X.X-ios-arm64.ipa` from the [releases page](https://github.com/TwilitRealm/dusk/releases)) +- Game disc - `GZ2E01` (Gamecube USA) or `GZ2PE01` (Gamecube PAL) + +## 1. Install AltServer + +```sh +brew install altserver +open -a AltServer +``` + +AltServer will appear in your menu bar. + +## 2. Enable Developer Mode (iOS 16+) + +- On your iPhone, go to **Settings > Privacy & Security > Developer Mode** +- Toggle it on and restart when prompted + +## 3. Install AltStore on Your iPhone + +- Click AltServer in the menu bar +- Click **Install AltStore > [Your iPhone]** +- Enter your Apple ID credentials when prompted +- On your iPhone, go to **Settings > General > VPN & Device Management** +- Tap your Apple ID under "Developer App" and tap **Trust** + +## 4. Copy Files to Your iPhone + +Transfer the IPA and game disc to your iPhone so they're accessible in the Files app. A few ways to do this: + +- **AirDrop** - Right-click the files on your Mac and choose Share > AirDrop +- **iCloud Drive** - Place files in iCloud Drive on your Mac and they'll sync to Files on your iPhone +- **USB transfer** - Connect your iPhone and drag files via Finder's sidebar +- **Cloud storage** - Upload to Google Drive, Dropbox, etc. and download on your iPhone + +## 5. Install via AltStore + +- Open **AltStore** on your iPhone +- Go to the **My Apps** tab +- Tap the **+** button (top left) +- Open the **Files** app and select the `.ipa` file \ No newline at end of file From 594cadcf7d0c49ec379e79ad6bc18ac056158130 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sat, 9 May 2026 09:55:18 -0600 Subject: [PATCH 350/390] Update Android app ID to dev.twilitrealm.dusk --- extern/aurora | 2 +- platforms/android/README.md | 5 ++--- platforms/android/app/build.gradle | 4 ++-- platforms/android/app/proguard-rules.pro | 4 ++-- platforms/android/app/src/main/AndroidManifest.xml | 2 +- .../src/main/java/com/twilitrealm/dusk/DuskActivity.java | 7 +------ .../src/main/java/com/twilitrealm/dusk/DuskHttpClient.java | 2 +- src/dusk/http/android.cpp | 2 +- 8 files changed, 11 insertions(+), 17 deletions(-) diff --git a/extern/aurora b/extern/aurora index 1eeff98783..9413f24f65 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 1eeff98783c36fba83970c011783a4fd9deac018 +Subproject commit 9413f24f65e20969b8320e651af306a2fd0798c8 diff --git a/platforms/android/README.md b/platforms/android/README.md index c7ecd684c1..f51b37db73 100644 --- a/platforms/android/README.md +++ b/platforms/android/README.md @@ -66,12 +66,11 @@ Output APK: You can pass command-line args through the activity intent: ```bash -adb shell am start -n com.twilitrealm.dusk/.DuskActivity \ - --es dusk_args "'/sdcard/Download/The Legend of Zelda: Twilight Princess (USA).iso'" +adb shell am start -n dev.twilitrealm.dusk/.DuskActivity \ + --es dusk_args "--backend vulkan" ``` Supported extras: - `dusk_args`: single shell-like argument string - `dusk_argv`: string-array argv -- `dusk_disc`: compatibility shortcut (single ISO path) diff --git a/platforms/android/app/build.gradle b/platforms/android/app/build.gradle index 01e706a382..9cf56899df 100644 --- a/platforms/android/app/build.gradle +++ b/platforms/android/app/build.gradle @@ -13,11 +13,11 @@ def syncDuskAssets = tasks.register('syncDuskAssets', Sync) { } android { - namespace 'com.twilitrealm.dusk' + namespace 'dev.twilitrealm.dusk' compileSdk 36 defaultConfig { - applicationId 'com.twilitrealm.dusk' + applicationId 'dev.twilitrealm.dusk' minSdk 26 targetSdk 36 versionCode 1 diff --git a/platforms/android/app/proguard-rules.pro b/platforms/android/app/proguard-rules.pro index 8f2cf4a4e2..72b7ca16fa 100644 --- a/platforms/android/app/proguard-rules.pro +++ b/platforms/android/app/proguard-rules.pro @@ -1,4 +1,4 @@ # Keep SDL activity and related JNI bridge methods. -keep class org.libsdl.app.** { *; } --keep class com.twilitrealm.dusk.DuskHttpClient { *; } --keep class com.twilitrealm.dusk.DuskHttpClient$Response { *; } +-keep class dev.twilitrealm.dusk.DuskHttpClient { *; } +-keep class dev.twilitrealm.dusk.DuskHttpClient$Response { *; } diff --git a/platforms/android/app/src/main/AndroidManifest.xml b/platforms/android/app/src/main/AndroidManifest.xml index a902065475..f3e11030ca 100644 --- a/platforms/android/app/src/main/AndroidManifest.xml +++ b/platforms/android/app/src/main/AndroidManifest.xml @@ -25,7 +25,7 @@ android:resource="@xml/game_mode_config" /> DeleteLocalRef(activity); if (clientClass == nullptr) { return { From eeb0ad77a4e4f4fee6b464407e2c98937d6c8ee6 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sat, 9 May 2026 10:03:05 -0600 Subject: [PATCH 351/390] Missed a spot --- src/dusk/http/android.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dusk/http/android.cpp b/src/dusk/http/android.cpp index 125ddf6808..3f4eef8d84 100644 --- a/src/dusk/http/android.cpp +++ b/src/dusk/http/android.cpp @@ -348,7 +348,7 @@ Result get(const Request& request) { jmethodID getMethod = env->GetStaticMethodID(clientClass, "get", "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;IJ)" - "Lcom/twilitrealm/dusk/DuskHttpClient$Response;"); + "Ldev/twilitrealm/dusk/DuskHttpClient$Response;"); if (getMethod == nullptr || clear_pending_exception(env)) { env->DeleteLocalRef(clientClass); return { From 2f83753260760c7bde6ca8326215ac950b89d7be Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sat, 9 May 2026 10:13:59 -0600 Subject: [PATCH 352/390] Fix Android release gradle build --- platforms/android/app/build.gradle | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platforms/android/app/build.gradle b/platforms/android/app/build.gradle index 9cf56899df..b7775df8e0 100644 --- a/platforms/android/app/build.gradle +++ b/platforms/android/app/build.gradle @@ -60,7 +60,8 @@ dependencies { } tasks.configureEach { task -> - if (task.name.startsWith('merge') && task.name.endsWith('Assets')) { + if ((task.name.startsWith('merge') && task.name.endsWith('Assets')) || + task.name.toLowerCase().contains('lint')) { task.dependsOn(syncDuskAssets) } } From d0b9b6d10f70856f921c8d004fa69f38507aee81 Mon Sep 17 00:00:00 2001 From: SuperDude88 <82904174+SuperDude88@users.noreply.github.com> Date: Sat, 9 May 2026 15:37:14 -0400 Subject: [PATCH 353/390] Fix Prelaunch Break-out (#738) - Prevent users from breaking out of the prelaunch menu through the GraphicsTuner pages --- src/dusk/ui/graphics_tuner.cpp | 8 +++++--- src/dusk/ui/graphics_tuner.hpp | 3 ++- src/dusk/ui/settings.cpp | 14 +++++++------- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/dusk/ui/graphics_tuner.cpp b/src/dusk/ui/graphics_tuner.cpp index 8a11528914..188f0911c5 100644 --- a/src/dusk/ui/graphics_tuner.cpp +++ b/src/dusk/ui/graphics_tuner.cpp @@ -193,9 +193,10 @@ Rml::String format_graphics_setting_value(GraphicsOption option, int value) { return ""; } -GraphicsTuner::GraphicsTuner(GraphicsTunerProps props) +GraphicsTuner::GraphicsTuner(GraphicsTunerProps props, bool prelaunch) : Document(kDocumentSource), mOption(props.option), mValueMin(props.valueMin), - mValueMax(props.valueMax), mDefaultValue(props.defaultValue) { + mValueMax(props.valueMax), mDefaultValue(props.defaultValue), mPrelaunch(prelaunch) +{ if (mDocument == nullptr) { return; } @@ -281,7 +282,8 @@ bool GraphicsTuner::handle_nav_command(Rml::Event& event, NavCommand cmd) { pop(); return true; } - return Document::handle_nav_command(event, cmd); + + return mPrelaunch ? false : Document::handle_nav_command(event, cmd); } void GraphicsTuner::reset_default() { diff --git a/src/dusk/ui/graphics_tuner.hpp b/src/dusk/ui/graphics_tuner.hpp index 3f2418ef30..b020db1128 100644 --- a/src/dusk/ui/graphics_tuner.hpp +++ b/src/dusk/ui/graphics_tuner.hpp @@ -59,7 +59,7 @@ struct GraphicsTunerProps { class GraphicsTuner : public Document { public: - explicit GraphicsTuner(GraphicsTunerProps props); + explicit GraphicsTuner(GraphicsTunerProps props, bool prelaunch); void show() override; void hide(bool close) override; @@ -87,6 +87,7 @@ private: int mDefaultValue = 0; std::vector > mComponents; Rml::Element* mRoot; + bool mPrelaunch; }; } // namespace dusk::ui diff --git a/src/dusk/ui/settings.cpp b/src/dusk/ui/settings.cpp index fd7365a39d..edb136e5e0 100644 --- a/src/dusk/ui/settings.cpp +++ b/src/dusk/ui/settings.cpp @@ -274,7 +274,7 @@ SelectButton& config_percent_select(Pane& leftPane, Pane& rightPane, ConfigVar void graphics_tuner_control(Window& window, Pane& leftPane, Pane& rightPane, ConfigVar& var, - const GraphicsTunerProps& props) { + const GraphicsTunerProps& props, bool prelaunch) { leftPane.register_control( leftPane .add_select_button({ @@ -292,10 +292,10 @@ void graphics_tuner_control(Window& window, Pane& leftPane, Pane& rightPane, Con .isModified = [&var] { return var.getValue() != var.getDefaultValue(); }, .submit = false, }) - .on_nav_command([&window, props](Rml::Event&, NavCommand cmd) { + .on_nav_command([&window, props, prelaunch](Rml::Event&, NavCommand cmd) { if (cmd == NavCommand::Confirm || cmd == NavCommand::Left || cmd == NavCommand::Right) { - window.push(std::make_unique(props)); + window.push(std::make_unique(props, prelaunch)); return true; } return false; @@ -551,7 +551,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) { .valueMin = 0, .valueMax = 12, .defaultValue = 0, - }); + }, mPrelaunch); graphics_tuner_control(*this, leftPane, rightPane, getSettings().game.shadowResolutionMultiplier, GraphicsTunerProps{ @@ -561,7 +561,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) { .valueMin = 1, .valueMax = 8, .defaultValue = 1, - }); + }, mPrelaunch); leftPane.add_section("Post-Processing"); graphics_tuner_control(*this, leftPane, rightPane, getSettings().game.bloomMode, @@ -572,7 +572,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) { .valueMin = static_cast(BloomMode::Off), .valueMax = static_cast(BloomMode::Dusk), .defaultValue = static_cast(BloomMode::Classic), - }); + }, mPrelaunch); graphics_tuner_control(*this, leftPane, rightPane, getSettings().game.bloomMultiplier, GraphicsTunerProps{ .option = GraphicsOption::BloomMultiplier, @@ -581,7 +581,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) { .valueMin = 0, .valueMax = 100, .defaultValue = 100, - }); + }, mPrelaunch); leftPane.add_section("Rendering"); config_bool_select(leftPane, rightPane, getSettings().game.enableFrameInterpolation, From bf23d44389261f000b8918625e09f2f2a185b41e Mon Sep 17 00:00:00 2001 From: SuperDude88 <82904174+SuperDude88@users.noreply.github.com> Date: Sat, 9 May 2026 16:14:36 -0400 Subject: [PATCH 354/390] Fix Syntax Warning (#743) - Remove invalid property value --- res/rml/window.rcss | 1 - 1 file changed, 1 deletion(-) diff --git a/res/rml/window.rcss b/res/rml/window.rcss index 8dd29b55e4..45473f312f 100644 --- a/res/rml/window.rcss +++ b/res/rml/window.rcss @@ -498,7 +498,6 @@ progress.verification-progress-bar { display: flex; flex-direction: row; flex-wrap: nowrap; - justify-content: stretch; align-items: stretch; gap: 12dp; width: 100%; From 23dc9bc39ac75b1017d6b08cf36293d3754b4500 Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Sat, 9 May 2026 13:14:45 -0700 Subject: [PATCH 355/390] Disable setting default mappings for now (#742) --- extern/aurora | 2 +- src/m_Do/m_Do_main.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/extern/aurora b/extern/aurora index 9413f24f65..bd46867176 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 9413f24f65e20969b8320e651af306a2fd0798c8 +Subproject commit bd46867176c8e0020ddd45368d952ef026584517 diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index 56ac05b16c..041c219fe9 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -544,7 +544,8 @@ int game_main(int argc, char* argv[]) { ApplyCVarOverrides(parsed_arg_options["cvar"]); dusk::InitializeCrashReporting(); EnsureInitialPipelineCache(dusk::ConfigPath); - PADSetDefaultMapping(&defaultPadMapping); + // TODO: How to handle this? + //PADSetDefaultMapping(&defaultPadMapping, PAD_TYPE_STANDARD); { const auto configPathString = dusk::ConfigPath.string(); From ad9c460ec9da7adaf7851a1a5b7d115e76cf4565 Mon Sep 17 00:00:00 2001 From: SuperDude88 <82904174+SuperDude88@users.noreply.github.com> Date: Sat, 9 May 2026 16:23:59 -0400 Subject: [PATCH 356/390] Navigate Carousel Without Focus (#741) * Navigate Carousel Without Focus - Allow left/right inputs to change the setting value without having the arrow explicitly clicked * Formatting --- src/dusk/ui/graphics_tuner.cpp | 9 ++++++--- src/dusk/ui/graphics_tuner.hpp | 3 ++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/dusk/ui/graphics_tuner.cpp b/src/dusk/ui/graphics_tuner.cpp index 188f0911c5..4f68d4a078 100644 --- a/src/dusk/ui/graphics_tuner.cpp +++ b/src/dusk/ui/graphics_tuner.cpp @@ -195,8 +195,7 @@ Rml::String format_graphics_setting_value(GraphicsOption option, int value) { GraphicsTuner::GraphicsTuner(GraphicsTunerProps props, bool prelaunch) : Document(kDocumentSource), mOption(props.option), mValueMin(props.valueMin), - mValueMax(props.valueMax), mDefaultValue(props.defaultValue), mPrelaunch(prelaunch) -{ + mValueMax(props.valueMax), mDefaultValue(props.defaultValue), mPrelaunch(prelaunch) { if (mDocument == nullptr) { return; } @@ -208,7 +207,7 @@ GraphicsTuner::GraphicsTuner(GraphicsTunerProps props, bool prelaunch) description->SetInnerRML(escape(props.helpText)); } if (auto* carouselParent = mDocument->GetElementById("carousel-container")) { - add_component(carouselParent, + mCarousel = &add_component(carouselParent, SteppedCarousel::Props{ .min = mValueMin, .max = mValueMax, @@ -283,6 +282,10 @@ bool GraphicsTuner::handle_nav_command(Rml::Event& event, NavCommand cmd) { return true; } + if (mCarousel && mCarousel->handle_nav_command(cmd)) { + return true; + } + return mPrelaunch ? false : Document::handle_nav_command(event, cmd); } diff --git a/src/dusk/ui/graphics_tuner.hpp b/src/dusk/ui/graphics_tuner.hpp index b020db1128..254aada22b 100644 --- a/src/dusk/ui/graphics_tuner.hpp +++ b/src/dusk/ui/graphics_tuner.hpp @@ -28,9 +28,9 @@ public: bool focus() override; void update() override; + bool handle_nav_command(NavCommand cmd); private: - bool handle_nav_command(NavCommand cmd); void apply(int value); Props mProps; @@ -86,6 +86,7 @@ private: int mValueMax = 0; int mDefaultValue = 0; std::vector > mComponents; + SteppedCarousel* mCarousel; Rml::Element* mRoot; bool mPrelaunch; }; From 45ef0d72b1555e33f63b40022fc1bb44933dfab9 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sat, 9 May 2026 15:03:21 -0600 Subject: [PATCH 357/390] Fix Android backgrounding & re-hide bars after swipe --- CMakeLists.txt | 4 -- extern/aurora | 2 +- .../com/twilitrealm/dusk/DuskActivity.java | 38 +++++++++++++++---- .../main/java/org/libsdl/app/SDLSurface.java | 5 +++ 4 files changed, 37 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 60aeb4e3fd..4d69993b5d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,10 +115,6 @@ option(DUSK_ENABLE_UPDATE_CHECKER "Enable update checking support" ON) if(ANDROID) set(DUSK_MOVIE_SUPPORT OFF) - set(NOD_COMPRESS_BZIP2 OFF CACHE BOOL "" FORCE) - set(NOD_COMPRESS_LZMA OFF CACHE BOOL "" FORCE) - set(NOD_COMPRESS_ZLIB OFF CACHE BOOL "" FORCE) - set(NOD_COMPRESS_ZSTD OFF CACHE BOOL "" FORCE) endif () option(DUSK_ENABLE_SENTRY_NATIVE "Enable sentry-native crash reporting support" OFF) diff --git a/extern/aurora b/extern/aurora index bd46867176..ac165cf1a6 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit bd46867176c8e0020ddd45368d952ef026584517 +Subproject commit ac165cf1a6b283b300021078bd322358fb865558 diff --git a/platforms/android/app/src/main/java/com/twilitrealm/dusk/DuskActivity.java b/platforms/android/app/src/main/java/com/twilitrealm/dusk/DuskActivity.java index f9046ad5fc..d7098239cd 100644 --- a/platforms/android/app/src/main/java/com/twilitrealm/dusk/DuskActivity.java +++ b/platforms/android/app/src/main/java/com/twilitrealm/dusk/DuskActivity.java @@ -10,6 +10,7 @@ import android.os.Bundle; import android.provider.OpenableColumns; import android.util.Log; import android.view.View; +import android.view.Window; import android.view.WindowInsets; import android.view.WindowInsetsController; @@ -70,19 +71,42 @@ public class DuskActivity extends SDLActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + hideSystemBars(); + } + @Override + protected void onResume() { + super.onResume(); + hideSystemBars(); + } + + @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + if (hasFocus) { + hideSystemBars(); + } + } + + private void hideSystemBars() { + Window window = getWindow(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - WindowInsetsController ctrl = getWindow().getDecorView().getWindowInsetsController(); + window.setDecorFitsSystemWindows(false); + WindowInsetsController ctrl = window.getDecorView().getWindowInsetsController(); if (ctrl != null) { + ctrl.setSystemBarsBehavior( + WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE); ctrl.hide(WindowInsets.Type.systemBars()); } - }else { - View decorView = getWindow().getDecorView(); - // Hide the status bar. - int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN; + } else { + View decorView = window.getDecorView(); + int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN | + View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | + View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | + View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_LAYOUT_STABLE; decorView.setSystemUiVisibility(uiOptions); - // Remember that you should never show the action bar if the - // status bar is hidden, so hide that too if necessary. ActionBar actionBar = getActionBar(); if (actionBar != null) { actionBar.hide(); diff --git a/platforms/android/app/src/main/java/org/libsdl/app/SDLSurface.java b/platforms/android/app/src/main/java/org/libsdl/app/SDLSurface.java index 1579b73345..5ed335ac39 100644 --- a/platforms/android/app/src/main/java/org/libsdl/app/SDLSurface.java +++ b/platforms/android/app/src/main/java/org/libsdl/app/SDLSurface.java @@ -35,6 +35,8 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, View.OnApplyWindowInsetsListener, View.OnKeyListener, View.OnTouchListener, SensorEventListener, ScaleGestureDetector.OnScaleGestureListener { + private static native void auroraNativeSetSurfaceReady(boolean ready); + // Sensors protected SensorManager mSensorManager; protected Display mDisplay; @@ -96,6 +98,7 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, @Override public void surfaceCreated(SurfaceHolder holder) { Log.v("SDL", "surfaceCreated()"); + auroraNativeSetSurfaceReady(false); SDLActivity.onNativeSurfaceCreated(); } @@ -103,6 +106,7 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, @Override public void surfaceDestroyed(SurfaceHolder holder) { Log.v("SDL", "surfaceDestroyed()"); + auroraNativeSetSurfaceReady(false); // Transition to pause, if needed SDLActivity.mNextNativeState = SDLActivity.NativeState.PAUSED; @@ -192,6 +196,7 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, /* Surface is ready */ mIsSurfaceReady = true; + auroraNativeSetSurfaceReady(true); SDLActivity.mNextNativeState = SDLActivity.NativeState.RESUMED; SDLActivity.handleNativeState(); From 8280ac00a0569c378005592ede87d8dd2bc2f212 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Sat, 9 May 2026 17:06:58 -0400 Subject: [PATCH 358/390] Always disable cursor if Gyro is set to Mouse mode and the menu is not open (#736) Co-authored-by: MelonSpeedruns --- src/dusk/imgui/ImGuiConsole.cpp | 24 ++++++++++++------------ src/dusk/ui/document.cpp | 15 +++++++++++++++ src/dusk/ui/document.hpp | 2 ++ src/dusk/ui/menu_bar.cpp | 2 ++ src/dusk/ui/prelaunch.cpp | 2 ++ 5 files changed, 33 insertions(+), 12 deletions(-) diff --git a/src/dusk/imgui/ImGuiConsole.cpp b/src/dusk/imgui/ImGuiConsole.cpp index 4793b717cc..13f785cdee 100644 --- a/src/dusk/imgui/ImGuiConsole.cpp +++ b/src/dusk/imgui/ImGuiConsole.cpp @@ -376,18 +376,18 @@ namespace dusk { } // Hide mouse cursor if the F1 menu is not open and the cursor is idle for 3 seconds. - ImGuiIO& io = ImGui::GetIO(); - if (showMenu) { - mouseHideTimer = 0.0f; - ImGui::GetIO().ConfigFlags &= ~ImGuiConfigFlags_NoMouseCursorChange; // Imgui will re-show cursor. - } else if (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f) { - mouseHideTimer = 0.0f; - ImGui::GetIO().ConfigFlags &= ~ImGuiConfigFlags_NoMouseCursorChange; // Imgui will re-show cursor. - } else if (mouseHideTimer <= 3.0f) { - mouseHideTimer += ImGui::GetIO().DeltaTime; - } else { - ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange; - SDL_HideCursor(); + if (dusk::getSettings().game.gyroMode.getValue() != GyroMode::Mouse) + { + ImGuiIO& io = ImGui::GetIO(); + if (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f) { + mouseHideTimer = 0.0f; + ImGui::GetIO().ConfigFlags &= ~ImGuiConfigFlags_NoMouseCursorChange; // Imgui will re-show cursor. + } else if (mouseHideTimer <= 3.0f) { + mouseHideTimer += ImGui::GetIO().DeltaTime; + } else { + ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange; + SDL_HideCursor(); + } } ShowToasts(); diff --git a/src/dusk/ui/document.cpp b/src/dusk/ui/document.cpp index a7bcc3f9ed..4296ac27d9 100644 --- a/src/dusk/ui/document.cpp +++ b/src/dusk/ui/document.cpp @@ -5,6 +5,7 @@ #include "Z2AudioLib/Z2SeMgr.h" #include "m_Do/m_Do_audio.h" +#include namespace dusk::ui { namespace { @@ -106,6 +107,7 @@ bool Document::visible() const { bool Document::handle_nav_command(Rml::Event& event, NavCommand cmd) { if (cmd == NavCommand::Menu) { + toggle_cursor_if_gyro(!visible()); mDoAud_seStartMenu(visible() ? kSoundMenuClose : kSoundMenuOpen); toggle(); return true; @@ -113,4 +115,17 @@ bool Document::handle_nav_command(Rml::Event& event, NavCommand cmd) { return false; } +void Document::toggle_cursor_if_gyro(bool cursor_enabled) { + if (dusk::getSettings().game.gyroMode.getValue() == GyroMode::Mouse) + { + if (cursor_enabled) { + ImGui::GetIO().ConfigFlags &= ~ImGuiConfigFlags_NoMouseCursorChange; + SDL_ShowCursor(); + } else { + ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange; + SDL_HideCursor(); + } + } +} + } // namespace dusk::ui diff --git a/src/dusk/ui/document.hpp b/src/dusk/ui/document.hpp index d0f4cae841..eed489beb3 100644 --- a/src/dusk/ui/document.hpp +++ b/src/dusk/ui/document.hpp @@ -43,6 +43,8 @@ public: bool pending_close() const { return mPendingClose; } bool closed() const { return mClosed; } + void toggle_cursor_if_gyro(bool); + protected: virtual bool handle_nav_command(Rml::Event& event, NavCommand cmd); diff --git a/src/dusk/ui/menu_bar.cpp b/src/dusk/ui/menu_bar.cpp index 81c2eea441..ea791d745b 100644 --- a/src/dusk/ui/menu_bar.cpp +++ b/src/dusk/ui/menu_bar.cpp @@ -42,6 +42,7 @@ MenuBar::MenuBar() : Document(kDocumentSource), mRoot(mDocument->GetElementById( mTabBar = std::make_unique(mRoot, TabBar::Props{ .onClose = [this] { + toggle_cursor_if_gyro(false); mDoAud_seStartMenu(kSoundMenuClose); hide(false); }, @@ -203,6 +204,7 @@ bool MenuBar::handle_nav_command(Rml::Event& event, NavCommand cmd) { return true; } if (cmd == NavCommand::Cancel && visible()) { + toggle_cursor_if_gyro(false); mDoAud_seStartMenu(kSoundMenuClose); hide(false); return true; diff --git a/src/dusk/ui/prelaunch.cpp b/src/dusk/ui/prelaunch.cpp index 5c41958409..0be1a3790c 100644 --- a/src/dusk/ui/prelaunch.cpp +++ b/src/dusk/ui/prelaunch.cpp @@ -687,6 +687,8 @@ Prelaunch::Prelaunch() : Document(kDocumentSource), mRoot(mDocument->GetElementB return; } + toggle_cursor_if_gyro(false); + mDoAud_seStartMenu(kSoundPlay); show_menu_notification(); From 63b3ce484929dfdc47680d8f059b5061bf297c5b Mon Sep 17 00:00:00 2001 From: TakaRikka Date: Sat, 9 May 2026 15:16:54 -0700 Subject: [PATCH 359/390] temp fix for speedrun timer controls --- src/dusk/imgui/ImGuiMenuGame.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dusk/imgui/ImGuiMenuGame.cpp b/src/dusk/imgui/ImGuiMenuGame.cpp index 79c032ee35..783bbbdeec 100644 --- a/src/dusk/imgui/ImGuiMenuGame.cpp +++ b/src/dusk/imgui/ImGuiMenuGame.cpp @@ -56,12 +56,12 @@ namespace dusk { } // L+R+A+Start to reset timer - if (mDoCPd_c::getHoldL(PAD_1) && mDoCPd_c::getHoldR(PAD_1) && mDoCPd_c::getHoldA(PAD_1) && mDoCPd_c::getTrigStart(PAD_1)) { + if (mDoCPd_c::getHoldL(PAD_1) && mDoCPd_c::getHoldR(PAD_1) && mDoCPd_c::getHoldA(PAD_1) && mDoCPd_c::getTrigZ(PAD_1)) { m_speedrunInfo.reset(); } // L+R+A+Z to manually stop timer - if (mDoCPd_c::getHoldL(PAD_1) && mDoCPd_c::getHoldR(PAD_1) && mDoCPd_c::getHoldA(PAD_1) && mDoCPd_c::getTrigZ(PAD_1)) { + if (mDoCPd_c::getHoldL(PAD_1) && mDoCPd_c::getHoldR(PAD_1) && mDoCPd_c::getHoldA(PAD_1) && mDoCPd_c::getTrigY(PAD_1)) { if (m_speedrunInfo.m_isRunStarted) { m_speedrunInfo.m_endTimestamp = OSGetTime() - m_speedrunInfo.m_startTimestamp; m_speedrunInfo.m_isRunStarted = false; From a2f463d14609295d0048f48e1d1ef0dfb722fc0d Mon Sep 17 00:00:00 2001 From: SuperDude88 <82904174+SuperDude88@users.noreply.github.com> Date: Sat, 9 May 2026 20:15:33 -0400 Subject: [PATCH 360/390] Fix Gyro Sensitivity Axes Fixes #759 --- src/dusk/gyro.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/dusk/gyro.cpp b/src/dusk/gyro.cpp index 4011cbb721..680d500631 100644 --- a/src/dusk/gyro.cpp +++ b/src/dusk/gyro.cpp @@ -140,8 +140,8 @@ void read(float dt) { float my_rel = 0.0f; SDL_GetRelativeMouseState(&mx_rel, &my_rel); // Convert pixels to radians - s_pitch_rad = my_rel * kMousePixelToRad * getSettings().game.gyroSensitivityX; - s_yaw_rad = -mx_rel * kMousePixelToRad * getSettings().game.gyroSensitivityY; + s_pitch_rad = my_rel * kMousePixelToRad * getSettings().game.gyroSensitivityY; + s_yaw_rad = -mx_rel * kMousePixelToRad * getSettings().game.gyroSensitivityX; s_roll_rad = 0.0f; s_pitch_rad = getSettings().game.gyroInvertPitch ? -s_pitch_rad : s_pitch_rad; @@ -184,7 +184,7 @@ void read(float dt) { const float yaw_rate = apply_deadband(s_smooth_gy, deadband); const float roll_rate = apply_deadband(s_smooth_gz, deadband); - s_pitch_rad = -pitch_rate * dt * getSettings().game.gyroSensitivityX; + s_pitch_rad = -pitch_rate * dt * getSettings().game.gyroSensitivityY; s_roll_rad = roll_rate * dt * getSettings().game.gyroSensitivityX; // GYRO NOTE: Exposing Z sensitivity seems unusual, so I'm just using X float horizontal_rate = yaw_rate; @@ -223,7 +223,7 @@ void read(float dt) { } } - s_yaw_rad = horizontal_rate * dt * getSettings().game.gyroSensitivityY; + s_yaw_rad = horizontal_rate * dt * getSettings().game.gyroSensitivityX; s_pitch_rad = getSettings().game.gyroInvertPitch ? -s_pitch_rad : s_pitch_rad; s_yaw_rad = getSettings().game.gyroInvertYaw ? -s_yaw_rad : s_yaw_rad; From 3b1118229b7ba4ae719adc13893fa9604ba18a36 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sat, 9 May 2026 20:22:30 -0600 Subject: [PATCH 361/390] Add Android DocumentsProvider --- .../android/app/src/main/AndroidManifest.xml | 11 + .../dusk/DuskDocumentsProvider.java | 373 ++++++++++++++++++ .../app/src/main/res/values/strings.xml | 2 + 3 files changed, 386 insertions(+) create mode 100644 platforms/android/app/src/main/java/com/twilitrealm/dusk/DuskDocumentsProvider.java diff --git a/platforms/android/app/src/main/AndroidManifest.xml b/platforms/android/app/src/main/AndroidManifest.xml index f3e11030ca..f5a0365856 100644 --- a/platforms/android/app/src/main/AndroidManifest.xml +++ b/platforms/android/app/src/main/AndroidManifest.xml @@ -24,6 +24,17 @@ + + + + + + 0 ? displayName.substring(0, dot) : displayName; + final String extension = dot > 0 ? displayName.substring(dot) : ""; + for (int i = 1; i < 100; ++i) { + file = new File(parent, baseName + " (" + i + ")" + extension); + if (!file.exists()) { + return file; + } + } + return new File(parent, baseName + " (" + System.currentTimeMillis() + ")" + extension); + } + + private static int modeToParcelMode(String mode) { + if ("r".equals(mode)) { + return ParcelFileDescriptor.MODE_READ_ONLY; + } + if ("w".equals(mode) || "wt".equals(mode)) { + return ParcelFileDescriptor.MODE_WRITE_ONLY | + ParcelFileDescriptor.MODE_CREATE | + ParcelFileDescriptor.MODE_TRUNCATE; + } + if ("wa".equals(mode)) { + return ParcelFileDescriptor.MODE_WRITE_ONLY | + ParcelFileDescriptor.MODE_CREATE | + ParcelFileDescriptor.MODE_APPEND; + } + if ("rw".equals(mode)) { + return ParcelFileDescriptor.MODE_READ_WRITE | + ParcelFileDescriptor.MODE_CREATE; + } + if ("rwt".equals(mode)) { + return ParcelFileDescriptor.MODE_READ_WRITE | + ParcelFileDescriptor.MODE_CREATE | + ParcelFileDescriptor.MODE_TRUNCATE; + } + return ParcelFileDescriptor.MODE_READ_ONLY; + } + + private static String getMimeType(File file) { + final int dot = file.getName().lastIndexOf('.'); + if (dot >= 0) { + final String extension = file.getName().substring(dot + 1).toLowerCase(); + final String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); + if (mimeType != null) { + return mimeType; + } + } + return "application/octet-stream"; + } + + private static void deleteRecursively(File file) throws FileNotFoundException { + if (file.isDirectory()) { + final File[] children = file.listFiles(); + if (children != null) { + for (File child : children) { + deleteRecursively(child); + } + } + } + if (!file.delete()) { + throw new FileNotFoundException("Unable to delete document: " + file); + } + } + + private static boolean isInside(File parent, File child) { + try { + final String parentPath = canonicalPath(parent); + final String childPath = canonicalPath(child); + return childPath.equals(parentPath) || childPath.startsWith(parentPath + File.separator); + } catch (FileNotFoundException e) { + return false; + } + } + + private static boolean sameFile(File a, File b) { + try { + return canonicalPath(a).equals(canonicalPath(b)); + } catch (FileNotFoundException e) { + return false; + } + } + + private static String canonicalPath(File file) throws FileNotFoundException { + try { + return file.getCanonicalPath(); + } catch (IOException e) { + throw asFileNotFound("Unable to resolve path", e); + } + } + + private static FileNotFoundException asFileNotFound(String message, IOException cause) { + final FileNotFoundException exception = new FileNotFoundException(message + ": " + cause.getMessage()); + exception.initCause(cause); + return exception; + } +} diff --git a/platforms/android/app/src/main/res/values/strings.xml b/platforms/android/app/src/main/res/values/strings.xml index 79d8812b82..752dae76bf 100644 --- a/platforms/android/app/src/main/res/values/strings.xml +++ b/platforms/android/app/src/main/res/values/strings.xml @@ -1,4 +1,6 @@ Dusk + Dusk Data + Saves, texture packs, settings, and logs From c66cccf6607a52f3621bf135bd8c99a321143379 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Sun, 10 May 2026 04:24:50 +0200 Subject: [PATCH 362/390] Fix handling of Unicode paths on Windows (#767) I love C++ --- include/dusk/io.hpp | 32 ++++++++++++++++++++++++++++++-- src/dusk/achievements.cpp | 4 ++-- src/dusk/config.cpp | 12 +++++++----- src/dusk/io.cpp | 28 +++++++++++++++++++++++++--- src/dusk/logging.cpp | 10 ++++++---- src/m_Do/m_Do_main.cpp | 6 +++--- 6 files changed, 73 insertions(+), 19 deletions(-) diff --git a/include/dusk/io.hpp b/include/dusk/io.hpp index fb71a77d68..57fda3feac 100644 --- a/include/dusk/io.hpp +++ b/include/dusk/io.hpp @@ -7,6 +7,10 @@ // C++ (no error codes) have a file system API functional enough for me to use. // Here you go, this one's inspired by C#. I only wrote the functions I need. +namespace std::filesystem { + class path; +} + namespace dusk::io { /** @@ -15,7 +19,7 @@ namespace dusk::io { * Methods on this class throw appropriate C++ exceptions when an error occurs. */ class FileStream { - void* file; + FILE* file; public: FileStream() noexcept; @@ -23,7 +27,7 @@ public: /** * \brief Take ownership of a FILE* handle. */ - explicit FileStream(void* file); + explicit FileStream(FILE* file); FileStream(const FileStream& other) = delete; FileStream(FileStream&& other) noexcept; @@ -34,6 +38,11 @@ public: */ static FileStream OpenRead(const char* utf8Path); + /** + * \brief Open a file for reading at the given path. + */ + static FileStream OpenRead(const std::filesystem::path& path); + /** * \brief Create a file for writing. * @@ -41,16 +50,33 @@ public: */ static FileStream Create(const char* utf8Path); + /** + * \brief Create a file for writing. + * + * If there is an existing file, its contents are demolished. + */ + static FileStream Create(const std::filesystem::path& path); + /** * \brief Read the byte contents of a file directly into a vector. */ static std::vector ReadAllBytes(const char* utf8Path); + /** + * \brief Read the byte contents of a file directly into a vector. + */ + static std::vector ReadAllBytes(const std::filesystem::path& path); + /** * \brief Read the byte contents of a file directly into a vector. */ static void WriteAllText(const char* utf8Path, std::string_view text); + /** + * \brief Read the byte contents of a file directly into a vector. + */ + static void WriteAllText(const std::filesystem::path& path, std::string_view text); + /** * \brief Read the remaining contents of the file directly into a vector. */ @@ -67,6 +93,8 @@ public: * Write data to the file. */ void Write(const char* data, size_t dataLen); + + FILE* ToInner(); }; } diff --git a/src/dusk/achievements.cpp b/src/dusk/achievements.cpp index cac6f776b6..28e66c891e 100644 --- a/src/dusk/achievements.cpp +++ b/src/dusk/achievements.cpp @@ -1030,7 +1030,7 @@ void AchievementSystem::load() { return; } try { - auto data = io::FileStream::ReadAllBytes(filePath.string().c_str()); + auto data = io::FileStream::ReadAllBytes(filePath); auto j = json::parse(data); if (!j.is_object()) { return; @@ -1067,7 +1067,7 @@ void AchievementSystem::save() { } try { io::FileStream::WriteAllText( - (dusk::ConfigPath / ACHIEVEMENTS_FILENAME).string().c_str(), + dusk::ConfigPath / ACHIEVEMENTS_FILENAME, j.dump(2) ); } catch (const std::exception&) {} diff --git a/src/dusk/config.cpp b/src/dusk/config.cpp index 940797c9ce..8225536d34 100644 --- a/src/dusk/config.cpp +++ b/src/dusk/config.cpp @@ -23,8 +23,8 @@ aurora::Module DuskConfigLog("dusk::config"); static absl::flat_hash_map RegisteredConfigVars; static bool RegistrationDone = false; -static std::string GetConfigJsonPath() { - return (dusk::ConfigPath / ConfigFileName).string(); +static std::u8string GetConfigJsonPath() { + return (dusk::ConfigPath / ConfigFileName).u8string(); } ConfigVarBase::ConfigVarBase(const char* name, const ConfigImplBase* impl) : name(name), registered(false), layer(ConfigVarLayer::Default), impl(impl) { @@ -189,7 +189,7 @@ void dusk::config::LoadFromUserPreferences() { if (configJsonPath.empty()) { return; } - LoadFromFileName(configJsonPath.c_str()); + LoadFromFileName(reinterpret_cast(configJsonPath.c_str())); } static void LoadFromPath(const char* path) { @@ -241,7 +241,9 @@ void dusk::config::Save() { return; } - DuskConfigLog.info("Saving config to '{}'", configJsonPath); + DuskConfigLog.info( + "Saving config to '{}'", + reinterpret_cast(configJsonPath.c_str())); json j; @@ -251,7 +253,7 @@ void dusk::config::Save() { } } - io::FileStream::WriteAllText(configJsonPath.c_str(), j.dump(4)); + io::FileStream::WriteAllText(reinterpret_cast(configJsonPath.c_str()), j.dump(4)); } ConfigVarBase* dusk::config::GetConfigVar(std::string_view name) { diff --git a/src/dusk/io.cpp b/src/dusk/io.cpp index 50b5cab5bd..dca8a25e82 100644 --- a/src/dusk/io.cpp +++ b/src/dusk/io.cpp @@ -58,7 +58,7 @@ static FILE* OpenCore(const char* path, const MODE_TYPE* mode) { FileStream::FileStream() noexcept : file(nullptr) { } -FileStream::FileStream(void* file) : file(file) { +FileStream::FileStream(FILE* file) : file(file) { if (!file) { CRASH("Invalid file handle"); } @@ -78,10 +78,18 @@ FileStream FileStream::OpenRead(const char* utf8Path) { return FileStream(OpenCore(utf8Path, MODE("rb"))); } +FileStream FileStream::OpenRead(const std::filesystem::path& path) { + return FileStream(OpenCore(path, MODE("rb"))); +} + FileStream FileStream::Create(const char* utf8Path) { return FileStream(OpenCore(utf8Path, MODE("wb"))); } +FileStream FileStream::Create(const std::filesystem::path& path) { + return FileStream(OpenCore(path, MODE("wb"))); +} + std::vector FileStream::ReadFull() { const auto fileHandle = ThrowIfNotOpen(*this); @@ -128,7 +136,11 @@ std::vector FileStream::ReadFull() { } std::vector FileStream::ReadAllBytes(const char* utf8Path) { - auto handle = OpenRead(utf8Path); + return ReadAllBytes(reinterpret_cast(utf8Path)); +} + +std::vector FileStream::ReadAllBytes(const std::filesystem::path& path) { + auto handle = OpenRead(path); return std::move(handle.ReadFull()); } @@ -142,6 +154,16 @@ void FileStream::Write(const char* data, size_t dataLen) { } void FileStream::WriteAllText(const char* utf8Path, const std::string_view text) { - auto handle = Create(utf8Path); + WriteAllText(reinterpret_cast(utf8Path), text); +} + +void FileStream::WriteAllText(const std::filesystem::path& path, const std::string_view text) { + auto handle = Create(path); handle.Write(text.data(), text.size()); } + +FILE* FileStream::ToInner() { + auto handle = file; + file = nullptr; + return handle; +} \ No newline at end of file diff --git a/src/dusk/logging.cpp b/src/dusk/logging.cpp index 8b96fcffd5..67723af4df 100644 --- a/src/dusk/logging.cpp +++ b/src/dusk/logging.cpp @@ -8,6 +8,7 @@ #include #include +#include "dusk/io.hpp" #include "tracy/Tracy.hpp" #if TARGET_ANDROID @@ -40,7 +41,7 @@ std::atomic g_logStateAlive(true); struct LogState { std::mutex mutex; FILE* file = nullptr; - std::string filePath; + std::u8string filePath; ~LogState() { CloseFile(); @@ -212,14 +213,14 @@ void dusk::InitializeFileLogging(const std::filesystem::path& configDir, AuroraL } const std::filesystem::path logPath = logsDir / MakeTimestampedLogName(); - g_logState.file = std::fopen(logPath.string().c_str(), "wb"); + g_logState.file = io::FileStream::Create(logPath).ToInner(); if (g_logState.file == nullptr) { std::fprintf(stderr, "[WARNING | dusk] Failed to open log file '%s'\n", logPath.string().c_str()); return; } - g_logState.filePath = logPath.string(); + g_logState.filePath = logPath.u8string(); aurora::g_config.logCallback = &aurora_log_callback; aurora::g_config.logLevel = logLevel; WriteLogLine(g_logState.file, "INFO", "dusk", "File logging initialized", 24); @@ -237,5 +238,6 @@ const char* dusk::GetLogFilePath() { return nullptr; } std::lock_guard lock(g_logState.mutex); - return g_logState.filePath.empty() ? nullptr : g_logState.filePath.c_str(); + return reinterpret_cast( + g_logState.filePath.empty() ? nullptr : g_logState.filePath.c_str()); } diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index 041c219fe9..55481cfeb5 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -398,7 +398,7 @@ static std::filesystem::path CalculateConfigPath() { DuskLog.fatal("Unable to get PrefPath: {}", SDL_GetError()); } - return result; + return reinterpret_cast(result); } static void EnsureInitialPipelineCache(const std::filesystem::path& configDir) { @@ -548,10 +548,10 @@ int game_main(int argc, char* argv[]) { //PADSetDefaultMapping(&defaultPadMapping, PAD_TYPE_STANDARD); { - const auto configPathString = dusk::ConfigPath.string(); + const auto configPathString = dusk::ConfigPath.u8string(); AuroraConfig config{}; config.appName = dusk::AppName; - config.configPath = configPathString.c_str(); + config.configPath = reinterpret_cast(configPathString.c_str()); config.vsync = dusk::getSettings().video.enableVsync; config.startFullscreen = dusk::getSettings().video.enableFullscreen; config.windowPosX = -1; From 5e08b810fc026116da95107a497d383cc6fa346f Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sat, 9 May 2026 20:26:37 -0600 Subject: [PATCH 363/390] Update aurora --- extern/aurora | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/aurora b/extern/aurora index ac165cf1a6..63606a4326 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit ac165cf1a6b283b300021078bd322358fb865558 +Subproject commit 63606a43265a3bc18dafd500ab4d7a2108f109e6 From 7562486449e58a9133acafcb9af681b70f25f26e Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sat, 9 May 2026 20:40:59 -0600 Subject: [PATCH 364/390] Log disc verification status --- src/dusk/io.cpp | 3 ++- src/dusk/iso_validate.cpp | 20 ++++++++++++++++++++ src/dusk/iso_validate.hpp | 1 + src/dusk/ui/prelaunch.cpp | 10 +++++++++- src/m_Do/m_Do_main.cpp | 4 ++++ 5 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/dusk/io.cpp b/src/dusk/io.cpp index dca8a25e82..3c87a66acf 100644 --- a/src/dusk/io.cpp +++ b/src/dusk/io.cpp @@ -1,7 +1,8 @@ -#include "dusk/io.hpp" #include #include +#include "dusk/io.hpp" + using namespace dusk::io; #if _WIN32 diff --git a/src/dusk/iso_validate.cpp b/src/dusk/iso_validate.cpp index 4d9c48d826..00cd365ca9 100644 --- a/src/dusk/iso_validate.cpp +++ b/src/dusk/iso_validate.cpp @@ -9,6 +9,8 @@ #include #include +#include "dusk/logging.h" + namespace { constexpr uint8_t hex_nibble_to_u8(char c) { @@ -42,6 +44,18 @@ constexpr XXH128_hash_t parse_xxh128(std::string_view hex) { }; } +const char* verification_state_name(dusk::DiscVerificationState state) noexcept { + switch (state) { + case dusk::DiscVerificationState::Success: + return "verified"; + case dusk::DiscVerificationState::HashMismatch: + return "hash mismatch"; + case dusk::DiscVerificationState::Unknown: + default: + return "unknown"; + } +} + } // namespace namespace dusk::iso { @@ -248,4 +262,10 @@ bool isPal(const char* path) { DiscInfo info{}; return inspect(path, info) == ValidationError::Success && info.isPal; } + +void log_verification_state(std::string_view path, DiscVerificationState state) { + const std::string pathText = path.empty() ? "" : std::string(path); + DuskLog.info( + "Disc verification status: {} (path: {})", verification_state_name(state), pathText); +} } // namespace dusk::iso diff --git a/src/dusk/iso_validate.hpp b/src/dusk/iso_validate.hpp index c737a017d9..176284fd02 100644 --- a/src/dusk/iso_validate.hpp +++ b/src/dusk/iso_validate.hpp @@ -31,6 +31,7 @@ struct DiscInfo { ValidationError inspect(const char* path, DiscInfo& info); ValidationError validate(const char* path, VerificationStatus& status, DiscInfo& info); bool isPal(const char* path); +void log_verification_state(std::string_view path, DiscVerificationState state); } // namespace dusk::iso diff --git a/src/dusk/ui/prelaunch.cpp b/src/dusk/ui/prelaunch.cpp index 0be1a3790c..03ad57a3bb 100644 --- a/src/dusk/ui/prelaunch.cpp +++ b/src/dusk/ui/prelaunch.cpp @@ -302,9 +302,17 @@ std::string get_error_msg(iso::ValidationError error) { } void persist_disc_choice(const std::string& path, iso::ValidationError validation) { + const auto previousPath = getSettings().backend.isoPath.getValue(); + const auto previousVerification = getSettings().backend.isoVerification.getValue(); + const auto verification = verification_to_config(validation); + getSettings().backend.isoPath.setValue(path); - getSettings().backend.isoVerification.setValue(verification_to_config(validation)); + getSettings().backend.isoVerification.setValue(verification); config::Save(); + + if (previousPath != path || previousVerification != verification) { + iso::log_verification_state(path, verification); + } } void apply_valid_disc_result( diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index 55481cfeb5..cf51f5fb86 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -649,6 +649,10 @@ int game_main(int argc, char* argv[]) { } } + dusk::iso::log_verification_state( + dusk::getSettings().backend.isoPath.getValue(), + dusk::getSettings().backend.isoVerification.getValue()); + if (!dvd_opened) { if (dusk::getSettings().backend.isoPath.getValue().empty()) { forcePreLaunchUI = true; From 0c23bd433248f634f2f2a6424b590b0e6eb67c5c Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sat, 9 May 2026 20:57:34 -0600 Subject: [PATCH 365/390] Add "Open Data Folder" to Interface menu --- include/dusk/main.h | 9 +++++++++ src/dusk/imgui/ImGuiConsole.hpp | 22 ---------------------- src/dusk/ui/settings.cpp | 13 +++++++++++++ src/m_Do/m_Do_main.cpp | 26 ++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 22 deletions(-) diff --git a/include/dusk/main.h b/include/dusk/main.h index 787c2541e2..c5c4fb27d1 100644 --- a/include/dusk/main.h +++ b/include/dusk/main.h @@ -7,6 +7,14 @@ #include +#if defined(_WIN32) || \ + (defined(__APPLE__) && !TARGET_OS_IOS && !TARGET_OS_TV && !TARGET_OS_MACCATALYST) || \ + (defined(__linux__) && !defined(__ANDROID__)) +#define DUSK_CAN_OPEN_DATA_FOLDER 1 +#else +#define DUSK_CAN_OPEN_DATA_FOLDER 0 +#endif + namespace dusk { extern bool IsRunning; extern bool IsShuttingDown; @@ -22,6 +30,7 @@ namespace dusk { #endif void RequestRestart() noexcept; + bool OpenDataFolder(); } #endif // DUSK_MAIN_H diff --git a/src/dusk/imgui/ImGuiConsole.hpp b/src/dusk/imgui/ImGuiConsole.hpp index 6715846e7b..6362a146b6 100644 --- a/src/dusk/imgui/ImGuiConsole.hpp +++ b/src/dusk/imgui/ImGuiConsole.hpp @@ -2,11 +2,9 @@ #define DUSK_IMGUI_HPP #include -#include #include #include -#include #include #include "ImGuiMenuGame.hpp" @@ -73,24 +71,4 @@ bool ImGuiButtonCenter(std::string_view text); float ImGuiScale(); } // namespace dusk -#if defined(_WIN32) || \ - (defined(__APPLE__) && !TARGET_OS_IOS && !TARGET_OS_TV && !TARGET_OS_MACCATALYST) || \ - (defined(__linux__) && !defined(__ANDROID__)) -#define DUSK_CAN_OPEN_DATA_FOLDER 1 - -namespace fs = std::filesystem; - -static void OpenDataFolder() { - const std::string path = fs::absolute(dusk::ConfigPath).generic_string(); -#if defined(_WIN32) - const std::string url = std::string("file:///") + path; -#else - const std::string url = std::string("file://") + path; -#endif - (void)SDL_OpenURL(url.c_str()); -} -#else -#define DUSK_CAN_OPEN_DATA_FOLDER 0 -#endif - #endif // DUSK_IMGUI_HPP diff --git a/src/dusk/ui/settings.cpp b/src/dusk/ui/settings.cpp index edb136e5e0..d904c823d7 100644 --- a/src/dusk/ui/settings.cpp +++ b/src/dusk/ui/settings.cpp @@ -9,6 +9,7 @@ #include "dusk/file_select.hpp" #include "dusk/imgui/ImGuiEngine.hpp" #include "dusk/livesplit.h" +#include "dusk/main.h" #include "graphics_tuner.hpp" #include "m_Do/m_Do_main.h" #include "menu_bar.hpp" @@ -946,6 +947,18 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) { auto& rightPane = add_child(content, Pane::Type::Uncontrolled); leftPane.add_section("Dusk"); +#if DUSK_CAN_OPEN_DATA_FOLDER + leftPane.register_control( + leftPane.add_button("Open Data Folder").on_pressed([] { + mDoAud_seStartMenu(kSoundClick); + dusk::OpenDataFolder(); + }), + rightPane, [](Pane& pane) { + pane.add_text( + "Open the folder where Dusk stores settings, saves, logs, texture " + "replacements, and other app data."); + }); +#endif leftPane.register_control( leftPane.add_select_button({ .key = "Notifications", diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index cf51f5fb86..937c9b81aa 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -71,6 +71,7 @@ #include #include "SDL3/SDL_filesystem.h" +#include "SDL3/SDL_misc.h" #include "cxxopts.hpp" #include "d/actor/d_a_movie_player.h" #include "dusk/audio/DuskAudioSystem.h" @@ -114,6 +115,31 @@ void dusk::RequestRestart() noexcept { IsRunning = false; } +bool dusk::OpenDataFolder() { +#if DUSK_CAN_OPEN_DATA_FOLDER + std::error_code ec; + std::filesystem::path path = std::filesystem::absolute(ConfigPath, ec); + if (ec) { + DuskLog.warn("Failed to resolve absolute data folder path '{}': {}", + ConfigPath.string(), ec.message()); + path = ConfigPath; + } + +#if defined(_WIN32) + const std::string url = "file:///" + path.generic_string(); +#else + const std::string url = "file://" + path.generic_string(); +#endif + if (!SDL_OpenURL(url.c_str())) { + DuskLog.warn("Failed to open data folder '{}': {}", path.string(), SDL_GetError()); + return false; + } + return true; +#else + return false; +#endif +} + s32 LOAD_COPYDATE(void*) { char buffer[32]; memset(buffer, 0, sizeof(buffer)); From daff15702787f35af52823ab28610df6ede87d89 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sat, 9 May 2026 21:42:32 -0600 Subject: [PATCH 366/390] Fix change notifications in Android DocumentsProvider --- .../dusk/DuskDocumentsProvider.java | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/platforms/android/app/src/main/java/com/twilitrealm/dusk/DuskDocumentsProvider.java b/platforms/android/app/src/main/java/com/twilitrealm/dusk/DuskDocumentsProvider.java index edab8d9bc1..79fa8894d0 100644 --- a/platforms/android/app/src/main/java/com/twilitrealm/dusk/DuskDocumentsProvider.java +++ b/platforms/android/app/src/main/java/com/twilitrealm/dusk/DuskDocumentsProvider.java @@ -1,10 +1,14 @@ package dev.twilitrealm.dusk; +import android.content.ContentResolver; import android.content.res.AssetFileDescriptor; import android.database.Cursor; import android.database.MatrixCursor; +import android.net.Uri; +import android.os.Bundle; import android.os.CancellationSignal; import android.os.ParcelFileDescriptor; +import android.provider.DocumentsContract; import android.provider.DocumentsContract.Document; import android.provider.DocumentsContract.Root; import android.provider.DocumentsProvider; @@ -76,10 +80,24 @@ public class DuskDocumentsProvider extends DocumentsProvider { @Override public Cursor queryChildDocuments(String parentDocumentId, String[] projection, String sortOrder) throws FileNotFoundException + { + return queryChildDocumentsInternal(parentDocumentId, projection); + } + + @Override + public Cursor queryChildDocuments(String parentDocumentId, String[] projection, Bundle queryArgs) + throws FileNotFoundException + { + return queryChildDocumentsInternal(parentDocumentId, projection); + } + + private Cursor queryChildDocumentsInternal(String parentDocumentId, String[] projection) + throws FileNotFoundException { final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection)); final File parent = getFileForDocumentId(parentDocumentId); final File[] files = parent.listFiles(); + result.setNotificationUri(getContext().getContentResolver(), getChildDocumentsUri(parentDocumentId)); if (files == null) { return result; @@ -129,6 +147,7 @@ public class DuskDocumentsProvider extends DocumentsProvider { throw new FileNotFoundException("Unable to create document: " + displayName); } + notifyChildrenChanged(parentDocumentId); return getDocumentIdForFile(file); } @@ -140,9 +159,13 @@ public class DuskDocumentsProvider extends DocumentsProvider { } final File target = buildUniqueFile(file.getParentFile(), sanitizeDisplayName(displayName)); + final String parentDocumentId = getDocumentIdForFile(file.getParentFile()); if (!file.renameTo(target)) { throw new FileNotFoundException("Unable to rename document: " + documentId); } + notifyDocumentChanged(documentId); + notifyDocumentChanged(getDocumentIdForFile(target)); + notifyChildrenChanged(parentDocumentId); return getDocumentIdForFile(target); } @@ -153,7 +176,10 @@ public class DuskDocumentsProvider extends DocumentsProvider { } final File file = getFileForDocumentId(documentId); + final String parentDocumentId = getDocumentIdForFile(file.getParentFile()); deleteRecursively(file); + notifyDocumentChanged(documentId); + notifyChildrenChanged(parentDocumentId); } @Override @@ -325,6 +351,20 @@ public class DuskDocumentsProvider extends DocumentsProvider { return "application/octet-stream"; } + private Uri getChildDocumentsUri(String parentDocumentId) { + return DocumentsContract.buildChildDocumentsUri(AUTHORITY, parentDocumentId); + } + + private void notifyChildrenChanged(String parentDocumentId) { + final ContentResolver resolver = getContext().getContentResolver(); + resolver.notifyChange(getChildDocumentsUri(parentDocumentId), null, false); + } + + private void notifyDocumentChanged(String documentId) { + final ContentResolver resolver = getContext().getContentResolver(); + resolver.notifyChange(DocumentsContract.buildDocumentUri(AUTHORITY, documentId), null, false); + } + private static void deleteRecursively(File file) throws FileNotFoundException { if (file.isDirectory()) { final File[] children = file.listFiles(); From df23edcb697d8bc72073d21368b7929c73c7d2c4 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sat, 9 May 2026 21:42:43 -0600 Subject: [PATCH 367/390] Add iOS UIFileSharingEnabled integration --- platforms/ios/Info.plist.in | 4 +++ src/m_Do/m_Do_main.cpp | 71 +++++++++++++++++++++++++++++++++++-- 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/platforms/ios/Info.plist.in b/platforms/ios/Info.plist.in index 881d5aff35..72174d487d 100644 --- a/platforms/ios/Info.plist.in +++ b/platforms/ios/Info.plist.in @@ -79,5 +79,9 @@ CADisableMinimumFrameDurationOnPhone + UIFileSharingEnabled + + LSSupportsOpeningDocumentsInPlace + diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index 937c9b81aa..98269c0817 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -84,6 +84,9 @@ #include "f_pc/f_pc_draw.h" #include "tracy/Tracy.hpp" #include +#ifdef __APPLE__ +#include +#endif // --- GLOBALS --- s8 mDoMain::developmentMode = -1; @@ -418,7 +421,71 @@ static void ApplyCVarOverrides(const cxxopts::OptionValue& option) { } } -static std::filesystem::path CalculateConfigPath() { +static void migrate_directory(const std::filesystem::path& from, const std::filesystem::path& to) { + std::error_code ec; + std::filesystem::create_directories(to, ec); + if (ec) { + return; + } + + for (std::filesystem::recursive_directory_iterator it( + from, std::filesystem::directory_options::skip_permission_denied, ec); + it != std::filesystem::recursive_directory_iterator(); it.increment(ec)) + { + if (ec) { + return; + } + + const auto relativePath = std::filesystem::relative(it->path(), from, ec); + if (ec) { + return; + } + + const auto targetPath = to / relativePath; + if (it->is_directory(ec)) { + std::filesystem::create_directories(targetPath, ec); + if (ec) { + return; + } + } else if (it->is_regular_file(ec) && !std::filesystem::exists(targetPath, ec)) { + std::filesystem::create_directories(targetPath.parent_path(), ec); + if (ec) { + return; + } + std::filesystem::copy_file( + it->path(), targetPath, std::filesystem::copy_options::skip_existing, ec); + if (ec) { + return; + } + } + } +} + +static std::filesystem::path calculate_config_path() { +#ifdef __APPLE__ +#if TARGET_OS_IOS && !TARGET_OS_TV + const char* documentsPath = SDL_GetUserFolder(SDL_FOLDER_DOCUMENTS); + if (!documentsPath) { + DuskLog.fatal("Unable to get iOS Documents path: {}", SDL_GetError()); + } + + std::filesystem::path configPath = reinterpret_cast(documentsPath); + + char* oldPrefPath = SDL_GetPrefPath(dusk::OrgName, dusk::AppName); + if (oldPrefPath) { + const std::filesystem::path oldConfigPath = reinterpret_cast(oldPrefPath); + SDL_free(oldPrefPath); + + std::error_code ec; + if (oldConfigPath != configPath && std::filesystem::exists(oldConfigPath, ec)) { + migrate_directory(oldConfigPath, configPath); + } + } + + return configPath; +#endif +#endif + const auto result = SDL_GetPrefPath(dusk::OrgName, dusk::AppName); if (!result) { DuskLog.fatal("Unable to get PrefPath: {}", SDL_GetError()); @@ -562,7 +629,7 @@ int game_main(int argc, char* argv[]) { exit(1); } - dusk::ConfigPath = CalculateConfigPath(); + dusk::ConfigPath = calculate_config_path(); const auto startupLogLevel = static_cast(parsed_arg_options["log-level"].as()); dusk::InitializeFileLogging(dusk::ConfigPath, startupLogLevel); From 8f71c70d1492938df43531b2574cd1946ce390cc Mon Sep 17 00:00:00 2001 From: Krutonium <3945538+Krutonium@users.noreply.github.com> Date: Sun, 10 May 2026 01:41:15 -0400 Subject: [PATCH 368/390] fix io.hpp to enable compiling on GCC15 (#790) --- include/dusk/io.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/include/dusk/io.hpp b/include/dusk/io.hpp index 57fda3feac..6de60e3449 100644 --- a/include/dusk/io.hpp +++ b/include/dusk/io.hpp @@ -2,14 +2,12 @@ #define DUSK_IO_HPP #include +#include // I can't believe it's 2026 and neither SDL (no error codes) nor // C++ (no error codes) have a file system API functional enough for me to use. // Here you go, this one's inspired by C#. I only wrote the functions I need. -namespace std::filesystem { - class path; -} namespace dusk::io { From e7d2fbcc0bae243fe1a1ae219fb514788f54d46e Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sun, 10 May 2026 00:08:42 -0600 Subject: [PATCH 369/390] Update CI --- .github/workflows/build.yml | 3 --- CMakeLists.txt | 21 +++++++++++---------- CMakePresets.json | 1 + extern/aurora | 2 +- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 37679e3f56..49d9bbd89c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -67,7 +67,6 @@ jobs: run: ci/build-appimage.sh - name: Upload artifacts - if: startsWith(github.event.ref, 'refs/tags/v') uses: actions/upload-artifact@v7 with: name: dusk-${{env.DUSK_VERSION}}-linux-${{matrix.preset}}-${{matrix.artifact_arch}} @@ -137,7 +136,6 @@ jobs: run: cmake --build --preset ${{matrix.preset}} - name: Upload artifacts - if: startsWith(github.event.ref, 'refs/tags/v') uses: actions/upload-artifact@v7 with: name: dusk-${{env.DUSK_VERSION}}-${{matrix.artifact_name}} @@ -203,7 +201,6 @@ jobs: run: cmake --build --preset x-windows-ci-${{matrix.preset}} - name: Upload artifacts - if: startsWith(github.event.ref, 'refs/tags/v') uses: actions/upload-artifact@v7 with: name: dusk-${{env.DUSK_VERSION}}-win32-msvc-${{matrix.artifact_arch}} diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d69993b5d..4c4f3180f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,6 +121,16 @@ option(DUSK_ENABLE_SENTRY_NATIVE "Enable sentry-native crash reporting support" set(DUSK_SENTRY_DSN "" CACHE STRING "Sentry DSN") set(DUSK_SENTRY_ENVIRONMENT "development" CACHE STRING "Sentry environment") +# Edit & Continue +if (MSVC) + if ("${CMAKE_MSVC_DEBUG_INFORMATION_FORMAT}" STREQUAL "" AND CMAKE_BUILD_TYPE STREQUAL "Debug") + set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "EditAndContinue") + endif () + if (CMAKE_MSVC_DEBUG_INFORMATION_FORMAT STREQUAL "EditAndContinue") + add_link_options("/INCREMENTAL") + endif () +endif () + if (DUSK_MOVIE_SUPPORT) find_package(libjpeg-turbo 3.0 CONFIG QUIET) if (libjpeg-turbo_FOUND) @@ -150,6 +160,7 @@ if (DUSK_MOVIE_SUPPORT) CMAKE_C_COMPILER_LAUNCHER CMAKE_MAKE_PROGRAM CMAKE_MSVC_RUNTIME_LIBRARY + CMAKE_MSVC_DEBUG_INFORMATION_FORMAT CMAKE_OSX_ARCHITECTURES DEPLOYMENT_TARGET ENABLE_ARC @@ -366,16 +377,6 @@ if (DUSK_ENABLE_DISCORD AND NOT ANDROID AND NOT IOS AND NOT TVOS) list(APPEND GAME_COMPILE_DEFS DUSK_DISCORD=1) endif () -# Edit & Continue -if (MSVC) - if ("${CMAKE_MSVC_DEBUG_INFORMATION_FORMAT}" STREQUAL "" AND CMAKE_BUILD_TYPE STREQUAL "Debug") - set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "EditAndContinue") - endif () - if (CMAKE_MSVC_DEBUG_INFORMATION_FORMAT STREQUAL "EditAndContinue") - add_link_options("/INCREMENTAL") - endif () -endif () - if(ANDROID) list(APPEND GAME_COMPILE_DEFS TARGET_ANDROID=1) endif () diff --git a/CMakePresets.json b/CMakePresets.json index 3b2f0cae67..187748c400 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -412,6 +412,7 @@ "x-macos-ci" ], "cacheVariables": { + "AURORA_DAWN_PROVIDER": "vendor", "CMAKE_OSX_ARCHITECTURES": "x86_64", "Rust_CARGO_TARGET": "x86_64-apple-darwin" } diff --git a/extern/aurora b/extern/aurora index 63606a4326..398054316e 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 63606a43265a3bc18dafd500ab4d7a2108f109e6 +Subproject commit 398054316ed66c554e5b900bb1b12f5ccb1104b3 From 453e9580682039fb4e2d3770eadc93f18b9367e1 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sun, 10 May 2026 00:11:05 -0600 Subject: [PATCH 370/390] Update CI (again) --- .github/workflows/build.yml | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 49d9bbd89c..f5560bab51 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,9 +8,9 @@ on: pull_request: env: - # SCCACHE_GHA_ENABLED: "true" + SCCACHE_GHA_ENABLED: "true" RUSTC_WRAPPER: "sccache" - SENTRY_DSN: ${{ secrets.SENTRY_DSN }} + # SENTRY_DSN: ${{ secrets.SENTRY_DSN }} jobs: build-linux: @@ -22,7 +22,7 @@ jobs: matrix: include: - name: GCC x86_64 - runner: [self-hosted, Linux] + runner: ubuntu-latest preset: gcc artifact_arch: x86_64 # - name: GCC aarch64 @@ -41,7 +41,6 @@ jobs: submodules: recursive - name: Install dependencies - if: 'false' # disabled for self-hosted run: | sudo apt-get update sudo apt-get -y install ninja-build clang lld openssl libcurl4-openssl-dev \ @@ -51,7 +50,6 @@ jobs: libxss-dev libfuse2 libusb-1.0-0-dev libdecor-0-dev libpipewire-0.3-dev libunwind-dev - name: Setup sccache - if: 'false' # disabled for self-hosted uses: mozilla-actions/sccache-action@v0.0.9 - name: Print sccache stats @@ -67,6 +65,7 @@ jobs: run: ci/build-appimage.sh - name: Upload artifacts + if: startsWith(github.event.ref, 'refs/tags/v') uses: actions/upload-artifact@v7 with: name: dusk-${{env.DUSK_VERSION}}-linux-${{matrix.preset}}-${{matrix.artifact_arch}} @@ -76,7 +75,7 @@ jobs: build-apple: name: Build Apple (${{matrix.name}}) - runs-on: [self-hosted, macOS] + runs-on: macos-latest strategy: fail-fast: false matrix: @@ -85,14 +84,14 @@ jobs: platform: macos preset: x-macos-ci-arm64 artifact_name: macos-appleclang-arm64 - # - name: AppleClang macOS x86_64 - # platform: macos - # preset: x-macos-ci-x86_64 - # artifact_name: macos-appleclang-x86_64 - # - name: AppleClang iOS arm64 - # platform: ios - # preset: x-ios-ci - # artifact_name: ios-appleclang-arm64 + - name: AppleClang macOS x86_64 + platform: macos + preset: x-macos-ci-x86_64 + artifact_name: macos-appleclang-x86_64 + - name: AppleClang iOS arm64 + platform: ios + preset: x-ios-ci + artifact_name: ios-appleclang-arm64 # - name: AppleClang tvOS arm64 # platform: tvos # preset: x-tvos-ci @@ -105,7 +104,6 @@ jobs: submodules: recursive - name: Install dependencies - if: 'false' run: brew install cmake ninja - name: Install Rust iOS target @@ -136,6 +134,7 @@ jobs: run: cmake --build --preset ${{matrix.preset}} - name: Upload artifacts + if: startsWith(github.event.ref, 'refs/tags/v') uses: actions/upload-artifact@v7 with: name: dusk-${{env.DUSK_VERSION}}-${{matrix.artifact_name}} @@ -152,7 +151,7 @@ jobs: matrix: include: - name: MSVC x86_64 - runner: [self-hosted, Windows] + runner: windows-latest preset: msvc msvc_arch: amd64 vcpkg_arch: x64 @@ -189,7 +188,6 @@ jobs: uses: mozilla-actions/sccache-action@v0.0.9 - name: Install dependencies - if: 'false' # disabled for self-hosted run: | choco install ninja vcpkg install freetype:${{matrix.vcpkg_arch}}-windows-static zstd:${{matrix.vcpkg_arch}}-windows-static @@ -201,6 +199,7 @@ jobs: run: cmake --build --preset x-windows-ci-${{matrix.preset}} - name: Upload artifacts + if: startsWith(github.event.ref, 'refs/tags/v') uses: actions/upload-artifact@v7 with: name: dusk-${{env.DUSK_VERSION}}-win32-msvc-${{matrix.artifact_arch}} From 04b5861f294441582d01f13df5d79a8eef18f629 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sun, 10 May 2026 00:12:11 -0600 Subject: [PATCH 371/390] Update CI (again x2) --- .github/workflows/build.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f5560bab51..2008997cec 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -65,7 +65,6 @@ jobs: run: ci/build-appimage.sh - name: Upload artifacts - if: startsWith(github.event.ref, 'refs/tags/v') uses: actions/upload-artifact@v7 with: name: dusk-${{env.DUSK_VERSION}}-linux-${{matrix.preset}}-${{matrix.artifact_arch}} @@ -134,7 +133,6 @@ jobs: run: cmake --build --preset ${{matrix.preset}} - name: Upload artifacts - if: startsWith(github.event.ref, 'refs/tags/v') uses: actions/upload-artifact@v7 with: name: dusk-${{env.DUSK_VERSION}}-${{matrix.artifact_name}} @@ -199,7 +197,6 @@ jobs: run: cmake --build --preset x-windows-ci-${{matrix.preset}} - name: Upload artifacts - if: startsWith(github.event.ref, 'refs/tags/v') uses: actions/upload-artifact@v7 with: name: dusk-${{env.DUSK_VERSION}}-win32-msvc-${{matrix.artifact_arch}} From 286532904ac0bfa05b9929780217779e332bd03c Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sun, 10 May 2026 00:31:49 -0600 Subject: [PATCH 372/390] Update aurora --- extern/aurora | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/aurora b/extern/aurora index 398054316e..22c2e5e55a 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 398054316ed66c554e5b900bb1b12f5ccb1104b3 +Subproject commit 22c2e5e55a7e00404149dd499e2639cd74fb1189 From 97d032f8b5cab89c1b0efe60dfe634c08ea5431e Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sun, 10 May 2026 00:26:00 -0600 Subject: [PATCH 373/390] Add Android CI --- .github/workflows/build.yml | 67 +++++++++++++++++++++++++++++++++++++ CMakePresets.json | 28 ++++++++++++++++ platforms/android/gradlew | 0 3 files changed, 95 insertions(+) mode change 100644 => 100755 platforms/android/gradlew diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2008997cec..82b387db4d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -140,6 +140,73 @@ jobs: build/install/Dusk.app build/install/debug.tar.* + build-android: + name: Build Android (${{matrix.name}}) + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + include: + - name: Clang arm64-v8a + preset: x-android-ci-arm64 + abi: arm64-v8a + artifact_arch: arm64 + rust_target: aarch64-linux-android + + env: + ANDROID_NDK_VERSION: "29.0.14206865" + + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + submodules: recursive + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get -y install ninja-build + + - name: Setup Java + uses: actions/setup-java@v5 + with: + distribution: temurin + java-version: 17 + + - name: Setup Android SDK + uses: android-actions/setup-android@v3 + + - name: Install Android SDK packages + run: sdkmanager "platforms;android-36" "build-tools;36.1.0" "ndk;${ANDROID_NDK_VERSION}" + + - name: Install Rust Android target + run: | + rustup toolchain install stable + rustup target add ${{matrix.rust_target}} + + - name: Setup sccache + uses: mozilla-actions/sccache-action@v0.0.9 + + - name: Configure CMake + run: cmake --preset ${{matrix.preset}} + + - name: Build native library + run: cmake --build --preset ${{matrix.preset}} --target dusk + + - name: Stage stripped JNI library + run: ANDROID_STAGE_ABIS="${{matrix.abi}}" platforms/android/scripts/stage-jni-libs.sh + + - name: Build APK + working-directory: platforms/android + run: ./gradlew :app:assembleRelease --rerun-tasks + + - name: Upload artifacts + uses: actions/upload-artifact@v7 + with: + name: dusk-${{env.DUSK_VERSION}}-android-${{matrix.artifact_arch}} + path: platforms/android/app/build/outputs/apk/release/app-${{matrix.abi}}-release-unsigned.apk + build-windows: name: Build Windows (${{matrix.name}}) runs-on: ${{matrix.runner}} diff --git a/CMakePresets.json b/CMakePresets.json index 187748c400..ea58a72243 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -352,6 +352,25 @@ "ANDROID_ABI": "x86_64" } }, + { + "name": "x-android-ci", + "hidden": true, + "inherits": [ + "android-base", + "ci" + ] + }, + { + "name": "x-android-ci-arm64", + "binaryDir": "${sourceDir}/build/android-arm64", + "inherits": [ + "x-android-ci" + ], + "cacheVariables": { + "ANDROID_ABI": "arm64-v8a", + "Rust_CARGO_TARGET": "aarch64-linux-android" + } + }, { "name": "x-linux-ci", "hidden": true, @@ -556,6 +575,15 @@ "dusk" ] }, + { + "name": "x-android-ci-arm64", + "configurePreset": "x-android-ci-arm64", + "description": "(Internal) Android CI arm64-v8a", + "displayName": "(Internal) Android CI arm64-v8a", + "targets": [ + "dusk" + ] + }, { "name": "windows-msvc-debug", "configurePreset": "windows-msvc-debug", diff --git a/platforms/android/gradlew b/platforms/android/gradlew old mode 100644 new mode 100755 From 4ec8c1aaeed847b6ff4521d6bcb41b2bbd206b7d Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Sun, 10 May 2026 11:32:55 -0400 Subject: [PATCH 374/390] Fix recording mode muting music until next reboot (#832) Co-authored-by: MelonSpeedruns --- src/f_ap/f_ap_game.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/f_ap/f_ap_game.cpp b/src/f_ap/f_ap_game.cpp index 2c6cb0a925..55ef94f8a3 100644 --- a/src/f_ap/f_ap_game.cpp +++ b/src/f_ap/f_ap_game.cpp @@ -740,6 +740,8 @@ static void fapGm_AfterRecord() { fapGm_After(); } +BOOL isRecording = false; + static void duskExecute() { handleGamepadColor(); updateAutoSave(); @@ -747,6 +749,11 @@ static void duskExecute() { if (dusk::getSettings().game.recordingMode) { Z2GetSoundMgr()->getSeqMgr()->getParams()->moveVolume(0.0f, 0); Z2GetSoundMgr()->getStreamMgr()->getParams()->moveVolume(0.0f, 0); + isRecording = true; + } else if (isRecording) { + Z2GetSoundMgr()->getSeqMgr()->getParams()->moveVolume(1.0f, 0); + Z2GetSoundMgr()->getStreamMgr()->getParams()->moveVolume(1.0f, 0); + isRecording = false; } if (mDoCPd_c::getHoldR(PAD_1) && mDoCPd_c::getTrigX(PAD_1)) { From a86fa9c16279a47172cd8b78e7538aedb15e7907 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Sun, 10 May 2026 18:35:11 +0200 Subject: [PATCH 375/390] State share Unicode fix (#834) --- src/dusk/imgui/ImGuiStateShare.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/dusk/imgui/ImGuiStateShare.cpp b/src/dusk/imgui/ImGuiStateShare.cpp index a0bd450984..48849e2bc3 100644 --- a/src/dusk/imgui/ImGuiStateShare.cpp +++ b/src/dusk/imgui/ImGuiStateShare.cpp @@ -48,19 +48,18 @@ void ImGuiStateShare::onMergeFileSelected(void* userdata, const char* path, cons -static std::string GetStatesFilePath() { - return (dusk::ConfigPath / STATES_FILENAME).string(); +static std::filesystem::path GetStatesFilePath() { + return ConfigPath / STATES_FILENAME; } void ImGuiStateShare::loadStatesFile() { m_loaded = true; - const std::filesystem::path filePath = dusk::ConfigPath / STATES_FILENAME; + const std::filesystem::path filePath = GetStatesFilePath(); if (!std::filesystem::exists(filePath)) { return; } try { - const std::string pathStr = filePath.string(); - auto data = io::FileStream::ReadAllBytes(pathStr.c_str()); + auto data = io::FileStream::ReadAllBytes(filePath); auto j = json::parse(data); if (!j.is_array()) { return; @@ -85,7 +84,7 @@ void ImGuiStateShare::saveStatesFile() { j.push_back(json{{"name", s.name}, {"data", s.encoded}}); } try { - io::FileStream::WriteAllText(GetStatesFilePath().c_str(), j.dump(2)); + io::FileStream::WriteAllText(GetStatesFilePath(), j.dump(2)); } catch (const std::exception& e) { m_statusMsg = fmt::format("Failed to save states: {}", e.what()); } From 5187fe90c3cb7e95bc74d30a9a0f5dc785a679c9 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sun, 10 May 2026 10:39:11 -0600 Subject: [PATCH 376/390] Seed initial pipeline cache through SDL IO & UTF8 path fixes --- include/dusk/io.hpp | 14 ++++--- src/dusk/logging.cpp | 4 +- src/dusk/main.cpp | 3 +- src/dusk/ui/ui.cpp | 3 +- src/m_Do/m_Do_main.cpp | 92 ++++++++++++++++++++++++++++++++++-------- 5 files changed, 90 insertions(+), 26 deletions(-) diff --git a/include/dusk/io.hpp b/include/dusk/io.hpp index 6de60e3449..2efc4a8d3b 100644 --- a/include/dusk/io.hpp +++ b/include/dusk/io.hpp @@ -1,14 +1,13 @@ #ifndef DUSK_IO_HPP #define DUSK_IO_HPP -#include #include +#include // I can't believe it's 2026 and neither SDL (no error codes) nor // C++ (no error codes) have a file system API functional enough for me to use. // Here you go, this one's inspired by C#. I only wrote the functions I need. - namespace dusk::io { /** @@ -83,9 +82,7 @@ public: /** * Get direct access to the underlying FILE* handle. */ - [[nodiscard]] void* GetFileHandle() const noexcept { - return file; - } + [[nodiscard]] void* GetFileHandle() const noexcept { return file; } /** * Write data to the file. @@ -95,7 +92,14 @@ public: FILE* ToInner(); }; +/** + * Converts a std::filesystem::path to a std::string, UTF-8, without exploding on Windows. + */ +inline std::string fs_path_to_string(const std::filesystem::path& path) { + const auto u8str = path.u8string(); + return {reinterpret_cast(u8str.c_str())}; } +} // namespace dusk::io #endif // DUSK_IO_HPP diff --git a/src/dusk/logging.cpp b/src/dusk/logging.cpp index 67723af4df..1c0a6ecbdb 100644 --- a/src/dusk/logging.cpp +++ b/src/dusk/logging.cpp @@ -208,7 +208,7 @@ void dusk::InitializeFileLogging(const std::filesystem::path& configDir, AuroraL std::filesystem::create_directories(logsDir, ec); if (ec) { std::fprintf(stderr, "[WARNING | dusk] Failed to create log directory '%s': %s\n", - logsDir.string().c_str(), ec.message().c_str()); + io::fs_path_to_string(logsDir).c_str(), ec.message().c_str()); return; } @@ -216,7 +216,7 @@ void dusk::InitializeFileLogging(const std::filesystem::path& configDir, AuroraL g_logState.file = io::FileStream::Create(logPath).ToInner(); if (g_logState.file == nullptr) { std::fprintf(stderr, "[WARNING | dusk] Failed to open log file '%s'\n", - logPath.string().c_str()); + io::fs_path_to_string(logPath).c_str()); return; } diff --git a/src/dusk/main.cpp b/src/dusk/main.cpp index e1b2fd0b6e..d88594248a 100644 --- a/src/dusk/main.cpp +++ b/src/dusk/main.cpp @@ -6,6 +6,7 @@ #include #include "dusk/main.h" +#include "dusk/io.hpp" #include #include @@ -91,7 +92,7 @@ bool RestartProcess(int argc, char* argv[]) { std::vector args; args.reserve(static_cast(std::max(argc, 1))); - args.push_back(executablePath.string()); + args.push_back(dusk::io::fs_path_to_string(executablePath)); for (int i = 1; i < argc; ++i) { args.emplace_back(argv[i] != nullptr ? argv[i] : ""); } diff --git a/src/dusk/ui/ui.cpp b/src/dusk/ui/ui.cpp index 0ee59e7938..5ef15a6c41 100644 --- a/src/dusk/ui/ui.cpp +++ b/src/dusk/ui/ui.cpp @@ -11,6 +11,7 @@ #include #include "aurora/lib/window.hpp" +#include "dusk/io.hpp" #include "input.hpp" #include "prelaunch.hpp" #include "window.hpp" @@ -19,7 +20,7 @@ namespace dusk::ui { namespace { void load_font(const char* filename, bool fallback = false) { - Rml::LoadFontFace(resource_path(filename).string(), fallback); + Rml::LoadFontFace(io::fs_path_to_string(resource_path(filename)), fallback); } bool sInitialized = false; diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index 98269c0817..6db94cc317 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -71,6 +71,7 @@ #include #include "SDL3/SDL_filesystem.h" +#include "SDL3/SDL_iostream.h" #include "SDL3/SDL_misc.h" #include "cxxopts.hpp" #include "d/actor/d_a_movie_player.h" @@ -78,6 +79,7 @@ #include "dusk/audio/DuskDsp.hpp" #include "dusk/config.hpp" #include "dusk/settings.h" +#include "dusk/io.hpp" #include "dusk/version.hpp" #include "dusk/discord_presence.hpp" #include "tracy/Tracy.hpp" @@ -124,7 +126,7 @@ bool dusk::OpenDataFolder() { std::filesystem::path path = std::filesystem::absolute(ConfigPath, ec); if (ec) { DuskLog.warn("Failed to resolve absolute data folder path '{}': {}", - ConfigPath.string(), ec.message()); + io::fs_path_to_string(ConfigPath), ec.message()); path = ConfigPath; } @@ -134,7 +136,8 @@ bool dusk::OpenDataFolder() { const std::string url = "file://" + path.generic_string(); #endif if (!SDL_OpenURL(url.c_str())) { - DuskLog.warn("Failed to open data folder '{}': {}", path.string(), SDL_GetError()); + DuskLog.warn( + "Failed to open data folder '{}': {}", io::fs_path_to_string(path), SDL_GetError()); return false; } return true; @@ -504,16 +507,21 @@ static void EnsureInitialPipelineCache(const std::filesystem::path& configDir) { return; } - const char* basePath = SDL_GetBasePath(); - if (basePath == nullptr) { - DuskLog.warn("Unable to resolve base path while seeding pipeline cache: {}", SDL_GetError()); - return; - } + std::string sourcePathString; + SDL_IOStream* source = nullptr; - const std::filesystem::path initialPipelineCachePath = - std::filesystem::path(basePath) / "initial_pipeline_cache.db"; - if (!std::filesystem::exists(initialPipelineCachePath)) { - DuskLog.info("No bundled initial pipeline cache found at '{}'", initialPipelineCachePath.string()); + const char* basePath = SDL_GetBasePath(); + if (basePath != nullptr) { + sourcePathString = dusk::io::fs_path_to_string( + std::filesystem::path(basePath) / "initial_pipeline_cache.db"); + source = SDL_IOFromFile(sourcePathString.c_str(), "rb"); + } + if (source == nullptr) { + sourcePathString = "initial_pipeline_cache.db"; + source = SDL_IOFromFile(sourcePathString.c_str(), "rb"); + } + if (source == nullptr) { + DuskLog.info("No bundled initial pipeline cache found"); return; } @@ -521,18 +529,68 @@ static void EnsureInitialPipelineCache(const std::filesystem::path& configDir) { std::filesystem::create_directories(configDir, ec); if (ec) { DuskLog.warn("Failed to create config directory '{}' for pipeline cache: {}", - configDir.string(), ec.message()); + dusk::io::fs_path_to_string(configDir), ec.message()); + SDL_CloseIO(source); return; } - std::filesystem::copy_file(initialPipelineCachePath, pipelineCachePath, std::filesystem::copy_options::none, ec); - if (ec) { - DuskLog.warn("Failed to seed pipeline cache from '{}' to '{}': {}", - initialPipelineCachePath.string(), pipelineCachePath.string(), ec.message()); + const auto pipelineCacheString = dusk::io::fs_path_to_string(pipelineCachePath); + SDL_IOStream* destination = SDL_IOFromFile(pipelineCacheString.c_str(), "wb"); + if (destination == nullptr) { + DuskLog.warn("Failed to open '{}' for seeded pipeline cache: {}", pipelineCacheString, + SDL_GetError()); + SDL_CloseIO(source); return; } - DuskLog.info("Seeded pipeline cache from '{}'", initialPipelineCachePath.string()); + bool copied = true; + std::array buffer{}; + while (true) { + const size_t bytesRead = SDL_ReadIO(source, buffer.data(), buffer.size()); + if (bytesRead > 0) { + size_t bytesWritten = 0; + while (bytesWritten < bytesRead) { + const size_t written = SDL_WriteIO( + destination, buffer.data() + bytesWritten, bytesRead - bytesWritten); + if (written == 0) { + DuskLog.warn("Failed to write seeded pipeline cache '{}': {}", + pipelineCacheString, SDL_GetError()); + copied = false; + break; + } + bytesWritten += written; + } + } + + if (!copied) { + break; + } + + if (bytesRead < buffer.size()) { + if (SDL_GetIOStatus(source) == SDL_IO_STATUS_EOF) { + break; + } + + DuskLog.warn( + "Failed to read bundled pipeline cache '{}': {}", sourcePathString, SDL_GetError()); + copied = false; + break; + } + } + + if (!SDL_CloseIO(destination)) { + DuskLog.warn("Failed to close seeded pipeline cache '{}': {}", + dusk::io::fs_path_to_string(pipelineCachePath), SDL_GetError()); + copied = false; + } + SDL_CloseIO(source); + + if (!copied) { + std::filesystem::remove(pipelineCachePath, ec); + return; + } + + DuskLog.info("Seeded pipeline cache from '{}'", sourcePathString); } static constexpr PADDefaultMapping defaultPadMapping = { From 4ec7b01213e28348f3c1c7bab78437b1a0ea5352 Mon Sep 17 00:00:00 2001 From: project516 <138796702+Project516@users.noreply.github.com> Date: Sun, 10 May 2026 11:39:55 -0500 Subject: [PATCH 377/390] update github actions in ci (#852) --- .github/workflows/build.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 82b387db4d..37a0849fd0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -50,7 +50,7 @@ jobs: libxss-dev libfuse2 libusb-1.0-0-dev libdecor-0-dev libpipewire-0.3-dev libunwind-dev - name: Setup sccache - uses: mozilla-actions/sccache-action@v0.0.9 + uses: mozilla-actions/sccache-action@v0.0.10 - name: Print sccache stats run: sccache --show-stats @@ -124,7 +124,7 @@ jobs: rustup target add x86_64-apple-darwin - name: Setup sccache - uses: mozilla-actions/sccache-action@v0.0.9 + uses: mozilla-actions/sccache-action@v0.0.10 - name: Configure CMake run: cmake --preset ${{matrix.preset}} @@ -175,7 +175,7 @@ jobs: java-version: 17 - name: Setup Android SDK - uses: android-actions/setup-android@v3 + uses: android-actions/setup-android@v4 - name: Install Android SDK packages run: sdkmanager "platforms;android-36" "build-tools;36.1.0" "ndk;${ANDROID_NDK_VERSION}" @@ -186,7 +186,7 @@ jobs: rustup target add ${{matrix.rust_target}} - name: Setup sccache - uses: mozilla-actions/sccache-action@v0.0.9 + uses: mozilla-actions/sccache-action@v0.0.10 - name: Configure CMake run: cmake --preset ${{matrix.preset}} From 0a1fea4bc76c4a378a06d2e3ad6c301a0064c2c7 Mon Sep 17 00:00:00 2001 From: Markos Theocharis <87304130+Markos-Th09@users.noreply.github.com> Date: Sun, 10 May 2026 19:51:45 +0300 Subject: [PATCH 378/390] Add `LSSupportsGameMode` to enable game mode (#859) --- platforms/ios/Info.plist.in | 2 ++ platforms/macos/Info.plist.in | 2 ++ platforms/tvos/Info.plist.in | 2 ++ 3 files changed, 6 insertions(+) diff --git a/platforms/ios/Info.plist.in b/platforms/ios/Info.plist.in index 72174d487d..395b29b7d7 100644 --- a/platforms/ios/Info.plist.in +++ b/platforms/ios/Info.plist.in @@ -83,5 +83,7 @@ LSSupportsOpeningDocumentsInPlace + LSSupportsGameMode + diff --git a/platforms/macos/Info.plist.in b/platforms/macos/Info.plist.in index b7bc7b706c..aee7393ee8 100644 --- a/platforms/macos/Info.plist.in +++ b/platforms/macos/Info.plist.in @@ -28,5 +28,7 @@ ${MACOSX_BUNDLE_SHORT_VERSION_STRING} NSHighResolutionCapable + LSSupportsGameMode + diff --git a/platforms/tvos/Info.plist.in b/platforms/tvos/Info.plist.in index 841d120cc2..49ed85edd7 100644 --- a/platforms/tvos/Info.plist.in +++ b/platforms/tvos/Info.plist.in @@ -45,5 +45,7 @@ LaunchScreen UIUserInterfaceStyle Automatic + LSSupportsGameMode + From 80245387f3d7264d2a49a4afbcb122620242d0b1 Mon Sep 17 00:00:00 2001 From: Irastris Date: Sun, 10 May 2026 12:52:34 -0400 Subject: [PATCH 379/390] Update README & fallback ImGui error message (#857) --- README.md | 3 +++ src/dusk/imgui/ImGuiConsole.cpp | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b5275e6bdc..54492e36d3 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,9 @@ It aims to be as accurate as possible to the original while also providing new o > [!IMPORTANT] > Dusk does *not* provide any copyrighted assets. You must provide your own copy of the original game. +> [!IMPORTANT] +> At a minimum, Dusk requires a GPU with support for either D3D12, Vulkan, or Metal. Your experience with specific hardware, operating systems, and drivers may vary. In particular, older Intel iGPUs have a high likelyhood of incompatibility. We are also aware of a number of issues on devices with Adreno GPUs and are working to resolve them. + ### 1. Verify your dump First, make sure your dump of the game is clean and supported by Dusk. You can do this by checking the SHA-1 hash of your dump against this list of supported versions: diff --git a/src/dusk/imgui/ImGuiConsole.cpp b/src/dusk/imgui/ImGuiConsole.cpp index 13f785cdee..dca2a88d79 100644 --- a/src/dusk/imgui/ImGuiConsole.cpp +++ b/src/dusk/imgui/ImGuiConsole.cpp @@ -313,7 +313,9 @@ namespace dusk { ImGui::PopFont(); } ImGui::PushFont(ImGuiEngine::fontLarge); - ImGuiTextCenter("Failed to initialize any graphics backend"); + ImGuiTextCenter("Failed to initialize any graphics backend."); + ImGuiTextCenter("\nYour system may be misconfigured, or your hardware may not support the required versions of any of the available backends."); + ImGuiTextCenter("\nA clean reinstall of Dusk may help. For further assistance, please visit #tech-support on the Twilit Realm Discord server."); const auto& style = ImGui::GetStyle(); const auto retrySize = ImGui::CalcTextSize("Retry (Auto backend)"); const auto quitSize = ImGui::CalcTextSize("Quit"); From 7f6212f9b7718f20e19911a1f079e564ae1dc1da Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Sun, 10 May 2026 18:52:47 +0200 Subject: [PATCH 380/390] Add some basic code conventions to the README (#831) --- README.md | 2 +- docs/code-conventions.md | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 docs/code-conventions.md diff --git a/README.md b/README.md index 54492e36d3..652eae2538 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ First, make sure your dump of the game is clean and supported by Dusk. You can d If you'd like to build Dusk from source, please read the [build instructions](docs/building.md). -Pull requests are welcomed! Note that we do not accept contributions that are primarily AI-generated and will close your PR if we suspect as much. +Pull requests are welcomed! Note that we do not accept contributions that are primarily AI-generated and will close your PR if we suspect as much. Please also see the [code conventions](docs/code-conventions.md). # Credits diff --git a/docs/code-conventions.md b/docs/code-conventions.md new file mode 100644 index 0000000000..9c2659ac02 --- /dev/null +++ b/docs/code-conventions.md @@ -0,0 +1,13 @@ +# Code conventions for Dusk + +## Upstream when appropriate + +Bug fixes, documentation improvements, code cleanup, etc that also apply to the [original decompilation project](https://github.com/zeldaret/tp) should preferably be PR'd there. + +## Properly indicate Dusk-modified code + +When modifying original game code (i.e. in decomp) for Dusk's purposes, please clearly delineate such code as being Dusk-specific. Generally, this can be done by using `#if TARGET_PC` and keeping the original code in place. Use `#if AVOID_UB` for Undefined Behavior fixes to the original codebase. + +## Miscellaneous things + +* The original codebase makes heavy use of global `operator new` and similar overloads to allocate into a strict tree of heaps. This would cause many linkage headaches for us, so effectively all uses of `new` or `delete` in the original game code have been replaced with `JKR_NEW`, `JKR_DELETE`, or similar macros. See `JKRHeap.h` for the full list. From bfd9917ca1b4d521bca4c59b8b75609c6495edf6 Mon Sep 17 00:00:00 2001 From: Krutonium <3945538+Krutonium@users.noreply.github.com> Date: Sun, 10 May 2026 12:53:07 -0400 Subject: [PATCH 381/390] Fix Flake to Build Successfully (#791) * Fix Flake to Build Successfully * Fix typo; Res Folder is now correctly placed --- flake.nix | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/flake.nix b/flake.nix index cd703bda64..c8e38a849b 100644 --- a/flake.nix +++ b/flake.nix @@ -5,9 +5,73 @@ outputs = { self, nixpkgs }: let pkgs = import nixpkgs { system = "x86_64-linux"; }; + + # Dependencies that are not packaged in nixpkgs: + aurora-src = pkgs.fetchFromGitHub { + owner = "encounter"; + repo = "aurora"; + rev = "63606a43265a3bc18dafd500ab4d7a2108f109e6"; + hash = "sha256-xBvnAwGwNzav67Ac6oUz7RqDUwqgL2bsME3OOMn8Tqw="; + }; + dawn-src = pkgs.fetchzip { + url = "https://github.com/encounter/dawn-build/releases/download/v20260423.175430/dawn-linux-x86_64.tar.gz"; + hash = "sha256-HXfKTLHtMPwupnFnaflCARtXVPuS/0PoCePXidjE5xs="; + stripRoot = false; + }; + nod-src = pkgs.fetchzip { + url = "https://github.com/encounter/nod/releases/download/v2.0.0-alpha.8/libnod-linux-x86_64.tar.gz"; + hash = "sha256-mUqvLsbsqaZ+HAjMmHYPYO+MgtanGRTw7Gzn5uXR5rE="; + stripRoot = false; + }; + # The version of imgui on nixpkgs does not map cleanly. + imgui-src = pkgs.fetchFromGitHub { + owner = "ocornut"; + repo = "imgui"; + rev = "v1.91.9b-docking"; + hash = "sha256-mQOJ6jCN+7VopgZ61yzaCnt4R1QLrW7+47xxMhFRHLQ="; + }; + sqlite-src = pkgs.fetchzip { + url = "https://sqlite.org/2026/sqlite-amalgamation-3510300.zip"; + hash = "sha256-pNMR8zxaaqfAzQ0AQBOXMct4usdjey1Q0Gnitg06UhM="; + }; + rmlui-src = pkgs.fetchzip { + url = "https://github.com/mikke89/RmlUi/archive/f9b8c9e2935d5df2c7dff2c190d3968e99b0c3dc.tar.gz"; + hash = "sha256-g4O/JZUrrcseOz8o2QJRt+2CeuiLnVeuDJc906xvuIg="; + }; + # Dusk Actual dusk = pkgs.stdenv.mkDerivation { name = "dusk"; src = ./.; + postUnpack = '' + mkdir -p $sourceRoot/extern/aurora + cp -r ${aurora-src}/. $sourceRoot/extern/aurora/ + chmod -R u+w $sourceRoot/extern/aurora + sed -i '/add_subdirectory(tests)/d' $sourceRoot/extern/aurora/CMakeLists.txt + ''; + # Remove last line to re-enable tests + cmakeFlags = [ + "-DFETCHCONTENT_FULLY_DISCONNECTED=ON" + "-DFETCHCONTENT_SOURCE_DIR_CXXOPTS=${pkgs.cxxopts.src}" + "-DFETCHCONTENT_SOURCE_DIR_JSON=${pkgs.nlohmann_json.src}" + "-DFETCHCONTENT_SOURCE_DIR_DAWN_PREBUILT=${dawn-src}" + "-DFETCHCONTENT_SOURCE_DIR_XXHASH=${pkgs.xxHash.src}" + "-DFETCHCONTENT_SOURCE_DIR_FMT=${pkgs.fmt.src}" + "-DFETCHCONTENT_SOURCE_DIR_TRACY=${pkgs.tracy.src}" + "-DAURORA_SDL3_PROVIDER=system" + "-DFETCHCONTENT_SOURCE_DIR_NOD_PREBUILT=${nod-src}" + "-DAURORA_NOD_PROVIDER=package" + "-DFETCHCONTENT_SOURCE_DIR_FREETYPE=${pkgs.freetype.src}" + "-DFETCHCONTENT_SOURCE_DIR_ZSTD=${pkgs.zstd.src}" + "-DFETCHCONTENT_SOURCE_DIR_SQLITE3=${sqlite-src}" + "-DFETCHCONTENT_SOURCE_DIR_IMGUI=${imgui-src}" + "-DFETCHCONTENT_SOURCE_DIR_RMLUI=${rmlui-src}" + "-DCMAKE_CROSSCOMPILING=ON" # Tests are not working as I didn't want to work through getting google's test suite working as well. This is the only guard I could find to disable it. + ]; + installPhase = '' + mkdir -p $out/bin + cp dusk $out/bin/dusk + cp -r ./res $out/bin/res + ''; nativeBuildInputs = [ pkgs.cmake pkgs.pkg-config @@ -25,6 +89,13 @@ pkgs.libjpeg8 pkgs.libxkbcommon pkgs.libglvnd + pkgs.cxxopts + pkgs.abseil-cpp + pkgs.sdl3 + pkgs.fmt + pkgs.tracy + pkgs.freetype + pkgs.zstd ]; }; in { From 4bcf4ca35436f279f630c9af55a6c5a19b328049 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sun, 10 May 2026 10:49:54 -0600 Subject: [PATCH 382/390] Improve build-appimage.sh --- ci/build-appimage.sh | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/ci/build-appimage.sh b/ci/build-appimage.sh index 078d6cabf0..cef4ddfaf0 100755 --- a/ci/build-appimage.sh +++ b/ci/build-appimage.sh @@ -1,18 +1,26 @@ #!/bin/bash -ex -shopt -s extglob + +if [[ -n "${GITHUB_WORKSPACE:-}" ]]; then + cd "$GITHUB_WORKSPACE" +fi + +build_dir="$PWD/build" +linuxdeploy="$build_dir/linuxdeploy-$(uname -m).AppImage" # Get linuxdeploy -cd "$RUNNER_WORKSPACE" -curl -fOL https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-$(uname -m).AppImage -chmod +x linuxdeploy-$(uname -m).AppImage +mkdir -p "$build_dir" +curl -fL "https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-$(uname -m).AppImage" -o "$linuxdeploy" +chmod +x "$linuxdeploy" # Build AppImage -cd "$GITHUB_WORKSPACE" mkdir -p build/appdir/usr/{bin,share/{applications,icons/hicolor}} -cp -r build/install/!(*.*) build/appdir/usr/bin +for install_path in build/install/*; do + [[ "$(basename "$install_path")" == *.* ]] && continue + cp -r "$install_path" build/appdir/usr/bin +done cp -r platforms/freedesktop/{16x16,32x32,48x48,64x64,128x128,256x256,512x512,1024x1024} build/appdir/usr/share/icons/hicolor cp platforms/freedesktop/dusk.desktop build/appdir/usr/share/applications cd build/install -VERSION="$DUSK_VERSION" NO_STRIP=1 "$RUNNER_WORKSPACE"/linuxdeploy-$(uname -m).AppImage \ - -l /usr/lib/x86_64-linux-gnu/libusb-1.0.so --appdir "$GITHUB_WORKSPACE"/build/appdir --output appimage +VERSION="$DUSK_VERSION" NO_STRIP=1 "$linuxdeploy" \ + -l /usr/lib/x86_64-linux-gnu/libusb-1.0.so --appdir "$build_dir/appdir" --output appimage From c948bffd3217ea57e4e47a24de7c7ae589c448b8 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sun, 10 May 2026 10:55:30 -0600 Subject: [PATCH 383/390] Update aurora --- extern/aurora | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/aurora b/extern/aurora index 22c2e5e55a..8444ecdc64 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 22c2e5e55a7e00404149dd499e2639cd74fb1189 +Subproject commit 8444ecdc6411a2094badd44ebcc0d6eb6f70a244 From a0ecdb1735a82a631220953f5da1693a1a5d8d44 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sun, 10 May 2026 12:10:32 -0600 Subject: [PATCH 384/390] Re-enable Sentry for release builds --- .github/workflows/build.yml | 2 +- CMakePresets.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 37a0849fd0..7ccde425c9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,7 +10,7 @@ on: env: SCCACHE_GHA_ENABLED: "true" RUSTC_WRAPPER: "sccache" - # SENTRY_DSN: ${{ secrets.SENTRY_DSN }} + SENTRY_DSN: ${{ secrets.SENTRY_DSN }} jobs: build-linux: diff --git a/CMakePresets.json b/CMakePresets.json index ea58a72243..9801c16393 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -30,7 +30,7 @@ "CMAKE_CXX_COMPILER_LAUNCHER": "sccache", "DUSK_ENABLE_SENTRY_NATIVE": { "type": "BOOL", - "value": false + "value": true }, "DUSK_SENTRY_DSN": "$env{SENTRY_DSN}", "DUSK_SENTRY_ENVIRONMENT": "production" From 800da8dbff0723aa58de4529a30db43777144aed Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sun, 10 May 2026 12:48:49 -0600 Subject: [PATCH 385/390] Update aurora --- extern/aurora | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/aurora b/extern/aurora index 8444ecdc64..449e7bf9b9 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 8444ecdc6411a2094badd44ebcc0d6eb6f70a244 +Subproject commit 449e7bf9b934a61b7c5736d8b87310a1f92829f0 From 4db8b51f2420667f3e39819c784a74582c2009a0 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sun, 10 May 2026 13:22:26 -0600 Subject: [PATCH 386/390] Disable Sentry on Android --- CMakePresets.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CMakePresets.json b/CMakePresets.json index 9801c16393..b72540225c 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -358,7 +358,13 @@ "inherits": [ "android-base", "ci" - ] + ], + "cacheVariables": { + "DUSK_ENABLE_SENTRY_NATIVE": { + "type": "BOOL", + "value": false + }, + } }, { "name": "x-android-ci-arm64", From 0665a78c8449bf7604785152e5b2402f54697d33 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sun, 10 May 2026 13:35:58 -0600 Subject: [PATCH 387/390] Update CMakePresets.json --- CMakePresets.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakePresets.json b/CMakePresets.json index b72540225c..629bbe9c18 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -363,7 +363,7 @@ "DUSK_ENABLE_SENTRY_NATIVE": { "type": "BOOL", "value": false - }, + } } }, { From b08d994e3224728c36b7bfe05d764d3d89381655 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Sun, 10 May 2026 17:27:30 -0600 Subject: [PATCH 388/390] Update aurora --- extern/aurora | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/aurora b/extern/aurora index 449e7bf9b9..aff6edf9de 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 449e7bf9b934a61b7c5736d8b87310a1f92829f0 +Subproject commit aff6edf9de39b3c211ccb252e76331abaa9e5e01 From 93c6106770adf2559cd69c5e9c734311586690ec Mon Sep 17 00:00:00 2001 From: qwertyquerty Date: Sun, 10 May 2026 16:30:39 -0700 Subject: [PATCH 389/390] cherry pick actor spawner (#920) --- files.cmake | 1 + src/dusk/imgui/ImGuiActorSpawner.cpp | 142 +++++++++++++++++++++++++++ src/dusk/imgui/ImGuiConsole.cpp | 1 + src/dusk/imgui/ImGuiMenuTools.cpp | 1 + src/dusk/imgui/ImGuiMenuTools.hpp | 2 + 5 files changed, 147 insertions(+) create mode 100644 src/dusk/imgui/ImGuiActorSpawner.cpp diff --git a/files.cmake b/files.cmake index 53aa7a2636..d0bcad2d30 100644 --- a/files.cmake +++ b/files.cmake @@ -1450,6 +1450,7 @@ set(DUSK_FILES src/dusk/imgui/ImGuiBloomWindow.hpp src/dusk/imgui/ImGuiMenuTools.cpp src/dusk/imgui/ImGuiMenuTools.hpp + src/dusk/imgui/ImGuiActorSpawner.cpp src/dusk/imgui/ImGuiProcessOverlay.cpp src/dusk/imgui/ImGuiCameraOverlay.cpp src/dusk/imgui/ImGuiHeapOverlay.cpp diff --git a/src/dusk/imgui/ImGuiActorSpawner.cpp b/src/dusk/imgui/ImGuiActorSpawner.cpp new file mode 100644 index 0000000000..f3aefd4c41 --- /dev/null +++ b/src/dusk/imgui/ImGuiActorSpawner.cpp @@ -0,0 +1,142 @@ +#include "imgui.h" + +#include "ImGuiMenuTools.hpp" +#include "d/actor/d_a_alink.h" +#include "d/d_com_inf_game.h" +#include "f_op/f_op_actor_mng.h" +#include "SSystem/SComponent/c_sxyz.h" +#include "SSystem/SComponent/c_xyz.h" + +namespace dusk { +namespace { + +struct ActorSpawnerState { + int actorId = 0; + int params = -1; + int argument = -1; + int angleX = 0; + int angleY = 0; + int angleZ = 0; + float scaleX = 1.0f; + float scaleY = 1.0f; + float scaleZ = 1.0f; + bool usePlayerRoom = true; + int manualRoom = 0; + int spawnCount = 1; + bool hasResult = false; + unsigned int lastResult = 0; + int lastAttempted = 0; +}; + +ActorSpawnerState s_state; + +} // namespace + +void ImGuiMenuTools::ShowActorSpawner() { + if (!m_showActorSpawner) { + return; + } + + if (!ImGui::Begin("Actor Spawner", &m_showActorSpawner)) { + ImGui::End(); + return; + } + + daAlink_c* player = (daAlink_c*)dComIfGp_getPlayer(0); + + ImGui::SeparatorText("Actor"); + ImGui::InputInt("Actor ID", &s_state.actorId); + ImGui::InputInt("Params (hex)", &s_state.params, 0, 0, ImGuiInputTextFlags_CharsHexadecimal); + ImGui::InputInt("Argument", &s_state.argument); + s_state.argument = (s_state.argument < -128) ? -128 : (s_state.argument > 127) ? 127 : s_state.argument; + + ImGui::SeparatorText("Angle"); + ImGui::InputInt("Angle X", &s_state.angleX); + ImGui::InputInt("Angle Y", &s_state.angleY); + ImGui::InputInt("Angle Z", &s_state.angleZ); + + ImGui::SeparatorText("Scale"); + ImGui::InputFloat("Scale X", &s_state.scaleX, 0.1f, 1.0f); + ImGui::InputFloat("Scale Y", &s_state.scaleY, 0.1f, 1.0f); + ImGui::InputFloat("Scale Z", &s_state.scaleZ, 0.1f, 1.0f); + + ImGui::SeparatorText("Spawn"); + ImGui::InputInt("Count", &s_state.spawnCount); + if (s_state.spawnCount < 1) { + s_state.spawnCount = 1; + } + + ImGui::SeparatorText("Position"); + ImGui::Checkbox("Use player room", &s_state.usePlayerRoom); + if (!s_state.usePlayerRoom) { + ImGui::InputInt("Room No", &s_state.manualRoom); + } + + if (player != nullptr) { + ImGui::Text("Spawn pos: %.2f, %.2f, %.2f", + player->current.pos.x, player->current.pos.y, player->current.pos.z); + } else { + ImGui::TextDisabled("Player not available"); + } + + ImGui::Separator(); + + bool canSpawn = player != nullptr; + if (!canSpawn) { + ImGui::BeginDisabled(); + } + + if (ImGui::Button("Spawn", ImVec2(-1, 0))) { + cXyz pos = player->current.pos; + csXyz angle; + angle.set((s16)s_state.angleX, (s16)s_state.angleY, (s16)s_state.angleZ); + cXyz scale(s_state.scaleX, s_state.scaleY, s_state.scaleZ); + int roomNo = s_state.usePlayerRoom ? player->current.roomNo : s_state.manualRoom; + + layer_class* savedLayer = fpcLy_CurrentLayer(); + base_process_class* playScene = fpcM_SearchByName(fpcNm_PLAY_SCENE_e); + if (playScene != nullptr) { + fpcLy_SetCurrentLayer(&((process_node_class*)playScene)->layer); + } + + s_state.lastResult = 0; + s_state.lastAttempted = s_state.spawnCount; + for (int i = 0; i < s_state.spawnCount; ++i) { + unsigned int result = fopAcM_create( + (s16)s_state.actorId, + (u32)s_state.params, + &pos, + roomNo, + &angle, + &scale, + (s8)s_state.argument + ); + if (result != 0) { + s_state.lastResult = result; + } + } + s_state.hasResult = true; + + fpcLy_SetCurrentLayer(savedLayer); + } + + if (!canSpawn) { + ImGui::EndDisabled(); + } + + if (s_state.hasResult) { + if (s_state.lastResult != 0) { + if (s_state.lastAttempted == 1) { + ImGui::Text("Spawned: proc ID %u", s_state.lastResult); + } else { + ImGui::Text("Spawned %d (last proc ID %u)", s_state.lastAttempted, s_state.lastResult); + } + } else { + ImGui::TextColored(ImVec4(1, 0.4f, 0.4f, 1), "Spawn failed (returned 0)"); + } + } + + ImGui::End(); +} + +} // namespace dusk diff --git a/src/dusk/imgui/ImGuiConsole.cpp b/src/dusk/imgui/ImGuiConsole.cpp index dca2a88d79..de62596308 100644 --- a/src/dusk/imgui/ImGuiConsole.cpp +++ b/src/dusk/imgui/ImGuiConsole.cpp @@ -375,6 +375,7 @@ namespace dusk { m_menuTools.ShowAudioDebug(); m_menuTools.ShowSaveEditor(); m_menuTools.ShowStateShare(); + m_menuTools.ShowActorSpawner(); } // Hide mouse cursor if the F1 menu is not open and the cursor is idle for 3 seconds. diff --git a/src/dusk/imgui/ImGuiMenuTools.cpp b/src/dusk/imgui/ImGuiMenuTools.cpp index 306298c28d..1cb0ec474c 100644 --- a/src/dusk/imgui/ImGuiMenuTools.cpp +++ b/src/dusk/imgui/ImGuiMenuTools.cpp @@ -107,6 +107,7 @@ namespace dusk { ImGui::MenuItem("Audio Debug", hotkeys::SHOW_AUDIO_DEBUG, &m_showAudioDebug); ImGui::MenuItem("Bloom", nullptr, &m_showBloomWindow); ImGui::MenuItem("Stub Log", nullptr, &m_showStubLog); + ImGui::MenuItem("Actor Spawner", nullptr, &m_showActorSpawner); if (!dusk::IsGameLaunched) { ImGui::EndDisabled(); diff --git a/src/dusk/imgui/ImGuiMenuTools.hpp b/src/dusk/imgui/ImGuiMenuTools.hpp index 6b925b7bf3..1c17ddbbe9 100644 --- a/src/dusk/imgui/ImGuiMenuTools.hpp +++ b/src/dusk/imgui/ImGuiMenuTools.hpp @@ -28,6 +28,7 @@ namespace dusk { void ShowSaveEditor(); void ShowStateShare(); void ShowInputViewer(); + void ShowActorSpawner(); private: bool m_showDebugOverlay = false; @@ -70,6 +71,7 @@ namespace dusk { bool m_showInputViewer = false; bool m_showInputViewerGyro = false; + bool m_showActorSpawner = false; int m_inputOverlayCorner = 3; std::string m_controllerName; }; From 3a02e129e74ad361eac22223212b90e823bb1c28 Mon Sep 17 00:00:00 2001 From: qwertyquerty Date: Sun, 10 May 2026 16:35:29 -0700 Subject: [PATCH 390/390] Fix keyboard not binding maybe (idk i cant repro) (#901) * fixkb * restore comment --- src/dusk/ui/controller_config.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/dusk/ui/controller_config.cpp b/src/dusk/ui/controller_config.cpp index 52c6f6c702..88baa7b29c 100644 --- a/src/dusk/ui/controller_config.cpp +++ b/src/dusk/ui/controller_config.cpp @@ -208,7 +208,15 @@ bool input_neutral(int port) { bool keyboard_escape_pressed() { int keyCount = 0; const bool* keys = SDL_GetKeyboardState(&keyCount); - return keys != nullptr && SDL_SCANCODE_ESCAPE < keyCount && keys[SDL_SCANCODE_ESCAPE]; + if (keys == nullptr || SDL_SCANCODE_ESCAPE >= keyCount || !keys[SDL_SCANCODE_ESCAPE]) { + return false; + } + for (int i = 0; i < keyCount; ++i) { + if (i != SDL_SCANCODE_ESCAPE && keys[i]) { + return false; + } + } + return true; } Rml::String keyboard_key_name(s32 scancode) {

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 iTrhOl=>G$?5-MH* literal 0 HcmV?d00001 diff --git a/res/rml/tabbing.rcss b/res/rml/tabbing.rcss index e223a4cfad..894316ff5c 100644 --- a/res/rml/tabbing.rcss +++ b/res/rml/tabbing.rcss @@ -1,10 +1,21 @@ tab-bar { display: flex; + position: relative; min-width: 0; overflow: auto hidden; + clip: always; text-transform: uppercase; } +tab-bar scrollbarhorizontal, +tab-bar scrollbarhorizontal sliderarrowdec, +tab-bar scrollbarhorizontal sliderarrowinc, +tab-bar scrollbarhorizontal slidertrack, +tab-bar scrollbarhorizontal sliderbar { + width: 0; + height: 0; +} + tab-bar tab { flex: 0 0 auto; padding: 0 24dp; @@ -31,3 +42,42 @@ tab-bar tab:hover { tab-bar tab:active { decorator: vertical-gradient(#c2a42d10 #c2a42d40); } + +tab-bar[closable] tab-end-spacer { + display: block; + flex: 0 0 64dp; + width: 64dp; + pointer-events: none; +} + +tab-bar[closable] close { + display: block; + position: fixed; + top: 8dp; + right: 8dp; + z-index: 1; + width: 48dp; + height: 48dp; + font-family: "Material Symbols Rounded"; + font-weight: normal; + font-size: 24dp; + line-height: 48dp; + text-align: center; + text-transform: none; + color: rgba(224, 219, 200, 70%); + backdrop-filter: blur(2dp); + border-radius: 6dp; + transition: color background-color 0.12s linear-in-out; + cursor: pointer; +} + +tab-bar[closable] close:hover, +tab-bar[closable] close:focus-visible { + color: #fff; + background-color: rgba(194, 164, 45, 24%); +} + +tab-bar[closable] close:active { + color: #fff; + background-color: rgba(194, 164, 45, 40%); +} diff --git a/src/dusk/ui/popup.cpp b/src/dusk/ui/popup.cpp index 461db91fc6..75658d965d 100644 --- a/src/dusk/ui/popup.cpp +++ b/src/dusk/ui/popup.cpp @@ -31,18 +31,21 @@ const Rml::String kDocumentSource = R"RML( } Popup::Popup() : Document(kDocumentSource), mRoot(mDocument->GetElementById("popup")) { - mTabBar = std::make_unique(mRoot, TabBar::Props{.autoSelect = false}); + mTabBar = std::make_unique(mRoot, TabBar::Props{ + .onClose = [this] { hide(false); }, + .autoSelect = false, + }); mTabBar->add_tab("Settings", [] { push_document(std::make_unique()); }); - mTabBar->add_tab("Warp", [] { - // TODO - }); + // mTabBar->add_tab("Warp", [] { + // // TODO + // }); mTabBar->add_tab("Editor", [] { push_document(std::make_unique()); }); mTabBar->add_tab("Reset", [this] { JUTGamePad::C3ButtonReset::sResetSwitchPushing = true; mTabBar->set_active_tab(-1); hide(false); }); - mTabBar->add_tab("Exit", [] { IsRunning = false; }); + mTabBar->add_tab("Quit", [] { IsRunning = false; }); // Hide document after transition completion listen(mRoot, Rml::EventId::Transitionend, [this](Rml::Event& event) { @@ -106,6 +109,11 @@ void Popup::update_safe_area() noexcept { Rml::PropertyId::PaddingRight, Rml::Property(safeInsets.right, Rml::Unit::PX)); tabBar->SetProperty( Rml::PropertyId::PaddingLeft, Rml::Property(safeInsets.left, Rml::Unit::PX)); + if (auto* close = tabBar->QuerySelector("close")) { + close->SetProperty(Rml::PropertyId::Right, + Rml::Property(safeInsets.right + 8.0f * context->GetDensityIndependentPixelRatio(), + Rml::Unit::PX)); + } } bool Popup::visible() const { diff --git a/src/dusk/ui/tab_bar.cpp b/src/dusk/ui/tab_bar.cpp index 1329d5f205..5d19d22b27 100644 --- a/src/dusk/ui/tab_bar.cpp +++ b/src/dusk/ui/tab_bar.cpp @@ -9,16 +9,78 @@ Rml::Element* createRoot(Rml::Element* parent) { return parent->AppendChild(std::move(elem)); } +int key_modifiers_from_event(const Rml::Event& event) { + int modifiers = 0; + if (event.GetParameter("ctrl_key", 0)) { + modifiers |= Rml::Input::KM_CTRL; + } + if (event.GetParameter("shift_key", 0)) { + modifiers |= Rml::Input::KM_SHIFT; + } + if (event.GetParameter("alt_key", 0)) { + modifiers |= Rml::Input::KM_ALT; + } + if (event.GetParameter("meta_key", 0)) { + modifiers |= Rml::Input::KM_META; + } + if (event.GetParameter("caps_lock_key", 0)) { + modifiers |= Rml::Input::KM_CAPSLOCK; + } + if (event.GetParameter("num_lock_key", 0)) { + modifiers |= Rml::Input::KM_NUMLOCK; + } + if (event.GetParameter("scroll_lock_key", 0)) { + modifiers |= Rml::Input::KM_SCROLLLOCK; + } + return modifiers; +} + } // namespace TabBar::TabBar(Rml::Element* parent, Props props) : FluentComponent(createRoot(parent)), mProps(std::move(props)) { + if (mProps.onClose) { + mRoot->SetAttribute("closable", ""); + auto& closeButton = + add_child + @@ -114,6 +123,44 @@ struct DiscVerificationTask { std::unique_ptr sDiscVerificationTask; bool sDiscVerificationModalPushed = false; +struct UpdateCheckTask { + UpdateCheckTask() { + worker = std::thread([this] { + try { + result = update_check::check_latest_github_release("TwilitRealm", "dusk"); + } catch (const std::exception& e) { + result = { + .status = update_check::Status::Failed, + .message = fmt::format("Update check failed with exception: {}", e.what()), + }; + } catch (...) { + result = { + .status = update_check::Status::Failed, + .message = "Update check failed with an unknown exception", + }; + } + done.store(true, std::memory_order_release); + }); + } + + ~UpdateCheckTask() { join(); } + + void join() { + if (worker.joinable()) { + worker.join(); + } + } + + [[nodiscard]] bool finished() const { return done.load(std::memory_order_acquire); } + + update_check::Result result; + std::atomic_bool done = false; + std::thread worker; +}; + +std::unique_ptr sUpdateCheckTask; +std::optional sUpdateCheckResult; + bool verification_state_allows_launch(iso::ValidationError validation) noexcept { return validation == iso::ValidationError::Unknown || validation == iso::ValidationError::Success || @@ -185,6 +232,52 @@ std::optional take_finished_disc_verification() { return result; } +void begin_update_check() { + if (!getSettings().backend.checkForUpdates.getValue()) { + return; + } + if (sUpdateCheckTask != nullptr || sUpdateCheckResult.has_value()) { + return; + } + sUpdateCheckTask = std::make_unique(); +} + +std::optional take_finished_update_check() { + if (sUpdateCheckTask == nullptr || !sUpdateCheckTask->finished()) { + return std::nullopt; + } + + sUpdateCheckTask->join(); + auto result = std::move(sUpdateCheckTask->result); + sUpdateCheckTask.reset(); + return result; +} + +std::string update_release_label(const update_check::Release& release) { + std::string_view tagName = release.tagName; + if (!tagName.empty() && tagName.front() == 'v') { + tagName.remove_prefix(1); + } + return std::string(tagName); +} + +void open_update_release() { + if (!sUpdateCheckResult.has_value() || + sUpdateCheckResult->status != update_check::Status::UpdateAvailable) + { + return; + } + + const std::string url = sUpdateCheckResult->latest.htmlUrl; + if (url.empty()) { + PrelaunchLog.warn("Update is available, but the release did not include a download URL"); + return; + } + if (!SDL_OpenURL(url.c_str())) { + PrelaunchLog.warn("Failed to open update URL '{}': {}", url, SDL_GetError()); + } +} + std::string get_error_msg(iso::ValidationError error) { switch (error) { default: @@ -582,6 +675,7 @@ void try_apply_mirrored_layout(Rml::Element* body) { Prelaunch::Prelaunch() : Document(kDocumentSource), mRoot(mDocument->GetElementById("root")) { ensure_initialized(); + begin_update_check(); if (auto* menuList = mDocument->GetElementById("menu-list")) { auto& state = prelaunch_state(); @@ -629,6 +723,23 @@ Prelaunch::Prelaunch() : Document(kDocumentSource), mRoot(mDocument->GetElementB mDiscStatus = mDocument->GetElementById("disc-status"); mDiscDetail = mDocument->GetElementById("disc-version"); mVersion = mDocument->GetElementById("version-text"); + mUpdateStatus = mDocument->GetElementById("update-status"); + mUpdateMessage = mDocument->GetElementById("update-message"); + mUpdateDownload = mDocument->GetElementById("update-download"); + mUpdateDownloadLabel = mDocument->GetElementById("update-download-label"); + + if (mUpdateDownload != nullptr) { + listen(mUpdateDownload, Rml::EventId::Click, [](Rml::Event& event) { + open_update_release(); + event.StopPropagation(); + }); + listen(mUpdateDownload, Rml::EventId::Keydown, [](Rml::Event& event) { + if (map_nav_event(event) == NavCommand::Confirm) { + open_update_release(); + event.StopPropagation(); + } + }); + } try_apply_mirrored_layout(mDocument); @@ -767,6 +878,34 @@ void Prelaunch::update() { } mVersion->SetInnerRML(escape(versionStr)); } + if (mUpdateStatus != nullptr && mUpdateMessage != nullptr) { + if (auto result = take_finished_update_check()) { + if (result->status == update_check::Status::Failed) { + PrelaunchLog.error("Failed to check for updates: {}", result->message); + } + sUpdateCheckResult = std::move(*result); + } + + if (sUpdateCheckTask != nullptr) { + mUpdateStatus->SetAttribute("state", "checking"); + mUpdateMessage->SetInnerRML("Checking for updates..."); + } else if (!sUpdateCheckResult.has_value() || + sUpdateCheckResult->status == update_check::Status::UpToDate) + { + mUpdateStatus->RemoveAttribute("state"); + mUpdateMessage->SetInnerRML(""); + } else if (sUpdateCheckResult->status == update_check::Status::UpdateAvailable) { + mUpdateStatus->SetAttribute("state", "available"); + mUpdateMessage->SetInnerRML("Update available!"); + if (mUpdateDownloadLabel != nullptr) { + mUpdateDownloadLabel->SetInnerRML(escape( + fmt::format("Download {}", update_release_label(sUpdateCheckResult->latest)))); + } + } else { + mUpdateStatus->SetAttribute("state", "failed"); + mUpdateMessage->SetInnerRML("Failed to check for updates"); + } + } Document::update(); } diff --git a/src/dusk/ui/prelaunch.hpp b/src/dusk/ui/prelaunch.hpp index 95ba2238f4..0fbb64ded9 100644 --- a/src/dusk/ui/prelaunch.hpp +++ b/src/dusk/ui/prelaunch.hpp @@ -31,6 +31,10 @@ private: Rml::Element* mDiscStatus = nullptr; Rml::Element* mDiscDetail = nullptr; Rml::Element* mVersion = nullptr; + Rml::Element* mUpdateStatus = nullptr; + Rml::Element* mUpdateMessage = nullptr; + Rml::Element* mUpdateDownload = nullptr; + Rml::Element* mUpdateDownloadLabel = nullptr; }; class PrelaunchOptions; diff --git a/src/dusk/ui/settings.cpp b/src/dusk/ui/settings.cpp index 972dc1421b..6f42f555c7 100644 --- a/src/dusk/ui/settings.cpp +++ b/src/dusk/ui/settings.cpp @@ -917,6 +917,12 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) { .key = "Show Pipeline Compilation", .helpText = "Show an overlay when shaders are being compiled for your hardware.", }); + config_bool_select(leftPane, rightPane, getSettings().backend.checkForUpdates, + { + .key = "Check for Updates", + .helpText = "Checks GitHub releases for a new Dusk version on startup.

" + "No personal information is transmitted or collected.", + }); config_bool_select(leftPane, rightPane, getSettings().backend.enableAdvancedSettings, { .key = "Enable Advanced Settings", diff --git a/src/dusk/update_check.cpp b/src/dusk/update_check.cpp new file mode 100644 index 0000000000..11c11795af --- /dev/null +++ b/src/dusk/update_check.cpp @@ -0,0 +1,196 @@ +#include "update_check.hpp" + +#include "dusk/http/http.hpp" +#include "fmt/format.h" +#include "nlohmann/json.hpp" +#include "version.h" + +#include +#include +#include + +namespace dusk::update_check { +namespace { + +using json = nlohmann::json; + +constexpr std::string_view GitHubApiVersion = "2026-03-10"; + +struct Version { + int major = 0; + int minor = 0; + int patch = 0; + + friend auto operator<=>(const Version&, const Version&) = default; +}; + +std::string json_string(const json& value, const char* key) { + const auto iter = value.find(key); + if (iter == value.end() || !iter->is_string()) { + return {}; + } + return iter->get(); +} + +std::optional parse_component(std::string_view& value) { + if (value.empty() || value.front() < '0' || value.front() > '9') { + return std::nullopt; + } + + int parsed = 0; + const char* begin = value.data(); + const char* end = value.data() + value.size(); + const auto [ptr, ec] = std::from_chars(begin, end, parsed); + if (ec != std::errc()) { + return std::nullopt; + } + + value.remove_prefix(static_cast(ptr - begin)); + return parsed; +} + +bool consume(std::string_view& value, char expected) { + if (value.empty() || value.front() != expected) { + return false; + } + value.remove_prefix(1); + return true; +} + +std::optional parse_version(std::string_view value) { + if (!value.empty() && value.front() == 'v') { + value.remove_prefix(1); + } + + Version version; + auto major = parse_component(value); + if (!major || !consume(value, '.')) { + return std::nullopt; + } + auto minor = parse_component(value); + if (!minor || !consume(value, '.')) { + return std::nullopt; + } + auto patch = parse_component(value); + if (!patch) { + return std::nullopt; + } + if (!value.empty() && value.front() != '-' && value.front() != '+') { + return std::nullopt; + } + + version.major = *major; + version.minor = *minor; + version.patch = *patch; + return version; +} + +Release parse_release(const json& value) { + Release release{ + .tagName = json_string(value, "tag_name"), + .name = json_string(value, "name"), + .htmlUrl = json_string(value, "html_url"), + .body = json_string(value, "body"), + }; + + const auto assets = value.find("assets"); + if (assets != value.end() && assets->is_array()) { + for (const auto& asset : *assets) { + if (!asset.is_object()) { + continue; + } + release.assets.push_back({ + .name = json_string(asset, "name"), + .browserDownloadUrl = json_string(asset, "browser_download_url"), + .digest = json_string(asset, "digest"), + }); + } + } + + return release; +} + +std::string release_url(std::string_view owner, std::string_view repo) { + return fmt::format("https://api.github.com/repos/{}/{}/releases/latest", owner, repo); +} + +std::string user_agent() { + return fmt::format("Dusk/{}", DUSK_WC_DESCRIBE); +} + +} // namespace + +Result check_latest_github_release(std::string_view owner, std::string_view repo) { + if (!http::available()) { + return { + .status = Status::Disabled, + .message = "No HTTP backend is available", + }; + } + if (owner.empty() || repo.empty()) { + return { + .status = Status::Failed, + .message = "GitHub owner and repo are required", + }; + } + + http::Request request{ + .url = release_url(owner, repo), + .headers = + { + {.name = "User-Agent", .value = user_agent()}, + {.name = "Accept", .value = "application/vnd.github+json"}, + {.name = "X-GitHub-Api-Version", .value = std::string(GitHubApiVersion)}, + }, + }; + + http::Result result = http::get(request); + if (result.error != http::Error::None) { + return { + .status = Status::Failed, + .message = result.message, + }; + } + if (result.response.statusCode != 200) { + return { + .status = Status::Failed, + .message = fmt::format("GitHub returned HTTP {}", result.response.statusCode), + }; + } + + Release latest; + try { + latest = parse_release(json::parse(result.response.body)); + } catch (const std::exception& e) { + return { + .status = Status::Failed, + .message = fmt::format("Failed to parse GitHub release JSON: {}", e.what()), + }; + } + + const std::optional latestVersion = parse_version(latest.tagName); + const std::optional currentVersion = parse_version(DUSK_WC_DESCRIBE); + if (!latestVersion) { + return { + .status = Status::Failed, + .message = fmt::format("Failed to parse release tag '{}'", latest.tagName), + .latest = std::move(latest), + }; + } + if (!currentVersion) { + return { + .status = Status::Failed, + .message = fmt::format("Failed to parse Dusk version '{}'", DUSK_WC_DESCRIBE), + .latest = std::move(latest), + }; + } + + const bool updateAvailable = *latestVersion > *currentVersion; + return { + .status = updateAvailable ? Status::UpdateAvailable : Status::UpToDate, + .message = updateAvailable ? "Update available" : "Dusk is up to date", + .latest = std::move(latest), + }; +} + +} // namespace dusk::update_check diff --git a/src/dusk/update_check.hpp b/src/dusk/update_check.hpp new file mode 100644 index 0000000000..72c66449dc --- /dev/null +++ b/src/dusk/update_check.hpp @@ -0,0 +1,41 @@ +#ifndef DUSK_UPDATE_CHECK_HPP +#define DUSK_UPDATE_CHECK_HPP + +#include +#include +#include + +namespace dusk::update_check { + +enum class Status { + Disabled, + UpToDate, + UpdateAvailable, + Failed, +}; + +struct Asset { + std::string name; + std::string browserDownloadUrl; + std::string digest; +}; + +struct Release { + std::string tagName; + std::string name; + std::string htmlUrl; + std::string body; + std::vector assets; +}; + +struct Result { + Status status = Status::Failed; + std::string message; + Release latest; +}; + +Result check_latest_github_release(std::string_view owner, std::string_view repo); + +} // namespace dusk::update_check + +#endif // DUSK_UPDATE_CHECK_HPP From 73a3bd9ae83f76bb61bba36a4ce568f717276ce5 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Fri, 8 May 2026 10:53:01 -0400 Subject: [PATCH 324/390] super clawshot warning about chains (#716) Co-authored-by: MelonSpeedruns --- src/dusk/ui/settings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dusk/ui/settings.cpp b/src/dusk/ui/settings.cpp index 6f42f555c7..7158a2460a 100644 --- a/src/dusk/ui/settings.cpp +++ b/src/dusk/ui/settings.cpp @@ -871,7 +871,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) { addCheat( "Moon Jump (R+A)", getSettings().game.moonJump, "Hold R and A to rise into the air."); addCheat("Super Clawshot", getSettings().game.superClawshot, - "Extends clawshot behavior beyond the normal game rules."); + "Extends Clawshot behavior beyond the normal game rules.
This will disable chains from rendering to prevent crashes."); addCheat("Always Greatspin", getSettings().game.alwaysGreatspin, "Allows the Great Spin attack without requiring full health."); addCheat("Fast Iron Boots", getSettings().game.enableFastIronBoots, From 97a11907135ae90e0cd6a6a1861bc6cf5a734320 Mon Sep 17 00:00:00 2001 From: Pheenoh Date: Fri, 8 May 2026 08:59:13 -0600 Subject: [PATCH 325/390] set max chain links to 600 --- src/d/actor/d_a_alink_hook.inc | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/d/actor/d_a_alink_hook.inc b/src/d/actor/d_a_alink_hook.inc index 73049af08b..b45adddf9a 100644 --- a/src/d/actor/d_a_alink_hook.inc +++ b/src/d/actor/d_a_alink_hook.inc @@ -17,11 +17,11 @@ enum { HS_MODE_RETURN_e = 6, }; -void daAlink_c::hsChainShape_c::draw() { - if (dusk::getSettings().game.superClawshot) { - return; - } +#if TARGET_PC +static const int HS_CHAIN_MAX_LINKS = 600; +#endif +void daAlink_c::hsChainShape_c::draw() { static const int dummy = 0; daAlink_c* alink = (daAlink_c*)getUserArea(); @@ -165,7 +165,14 @@ void daAlink_c::hsChainShape_c::draw() { } (void)0; - while (maxDistanceF > var_f30) { +#if TARGET_PC + int chainLinks = 0; +#endif + while (maxDistanceF > var_f30 +#if TARGET_PC + && chainLinks < HS_CHAIN_MAX_LINKS +#endif + ) { temp_f27 = var_f28 * cM_fsin(sp34 * var_f30); s16 spC = cM_atan2s(temp_f27 - var_f26, 5.0f); sp64.x = sp6C.x + spC; @@ -187,6 +194,9 @@ void daAlink_c::hsChainShape_c::draw() { var_f26 = temp_f27; var_f30 += fabsf(cM_scos(spC)) * 5.0f; +#if TARGET_PC + chainLinks++; +#endif } } @@ -202,7 +212,14 @@ void daAlink_c::hsChainShape_c::draw() { sp98 = subChainTopPos; sp6C.set(maxDistance.atan2sY_XZ(), maxDistance.atan2sX_Z(), 0); - while (maxDistanceF > var_f30) { +#if TARGET_PC + int subChainLinks = 0; +#endif + while (maxDistanceF > var_f30 +#if TARGET_PC + && subChainLinks < HS_CHAIN_MAX_LINKS +#endif + ) { mDoMtx_stack_c::copy(j3dSys.getViewMtx()); mDoMtx_stack_c::transM(sp98); mDoMtx_stack_c::ZXYrotM(sp6C); @@ -215,6 +232,9 @@ void daAlink_c::hsChainShape_c::draw() { sp98 += maxDistance * 5.0f; ANGLE_ADD_2(sp6C.z, 0x3000); var_f30 += 5.0f; +#if TARGET_PC + subChainLinks++; +#endif } } } From 6fd3762ffcd624bad5cd2b22ba501c9ad52a827e Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Fri, 8 May 2026 12:06:38 -0400 Subject: [PATCH 326/390] optimized code --- src/d/actor/d_a_alink_hook.inc | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/d/actor/d_a_alink_hook.inc b/src/d/actor/d_a_alink_hook.inc index b45adddf9a..c960d37a7b 100644 --- a/src/d/actor/d_a_alink_hook.inc +++ b/src/d/actor/d_a_alink_hook.inc @@ -168,11 +168,8 @@ void daAlink_c::hsChainShape_c::draw() { #if TARGET_PC int chainLinks = 0; #endif - while (maxDistanceF > var_f30 -#if TARGET_PC - && chainLinks < HS_CHAIN_MAX_LINKS -#endif - ) { + + while (maxDistanceF > var_f30 IF_DUSK(&&chainLinks < HS_CHAIN_MAX_LINKS)) { temp_f27 = var_f28 * cM_fsin(sp34 * var_f30); s16 spC = cM_atan2s(temp_f27 - var_f26, 5.0f); sp64.x = sp6C.x + spC; @@ -194,6 +191,7 @@ void daAlink_c::hsChainShape_c::draw() { var_f26 = temp_f27; var_f30 += fabsf(cM_scos(spC)) * 5.0f; + #if TARGET_PC chainLinks++; #endif @@ -215,11 +213,8 @@ void daAlink_c::hsChainShape_c::draw() { #if TARGET_PC int subChainLinks = 0; #endif - while (maxDistanceF > var_f30 -#if TARGET_PC - && subChainLinks < HS_CHAIN_MAX_LINKS -#endif - ) { + + while (maxDistanceF > var_f30 IF_DUSK(&&subChainLinks < HS_CHAIN_MAX_LINKS)) { mDoMtx_stack_c::copy(j3dSys.getViewMtx()); mDoMtx_stack_c::transM(sp98); mDoMtx_stack_c::ZXYrotM(sp6C); From 3934e09c8fca590a02f8075b47b315c9a2efb662 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Fri, 8 May 2026 12:07:00 -0400 Subject: [PATCH 327/390] remove mention of chains not rendering --- src/dusk/ui/settings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dusk/ui/settings.cpp b/src/dusk/ui/settings.cpp index 7158a2460a..e41dbbe46a 100644 --- a/src/dusk/ui/settings.cpp +++ b/src/dusk/ui/settings.cpp @@ -871,7 +871,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) { addCheat( "Moon Jump (R+A)", getSettings().game.moonJump, "Hold R and A to rise into the air."); addCheat("Super Clawshot", getSettings().game.superClawshot, - "Extends Clawshot behavior beyond the normal game rules.
This will disable chains from rendering to prevent crashes."); + "Extends Clawshot behavior beyond the normal game rules."); addCheat("Always Greatspin", getSettings().game.alwaysGreatspin, "Allows the Great Spin attack without requiring full health."); addCheat("Fast Iron Boots", getSettings().game.enableFastIronBoots, From d0f8ea56f9c70f8382955d5b3d64f64088c396c7 Mon Sep 17 00:00:00 2001 From: doop <56421834+dooplecks@users.noreply.github.com> Date: Fri, 8 May 2026 13:50:44 -0400 Subject: [PATCH 328/390] Interpolate more things (#699) * Interpolate trim height * Interpolate (some) fades --- libs/JSystem/src/JUtility/JUTFader.cpp | 20 ++++++-- src/d/d_camera.cpp | 63 +++++++++++++++++++++----- src/m_Do/m_Do_graphic.cpp | 8 ++++ 3 files changed, 76 insertions(+), 15 deletions(-) diff --git a/libs/JSystem/src/JUtility/JUTFader.cpp b/libs/JSystem/src/JUtility/JUTFader.cpp index 599ae22720..e7d33454b7 100644 --- a/libs/JSystem/src/JUtility/JUTFader.cpp +++ b/libs/JSystem/src/JUtility/JUTFader.cpp @@ -8,6 +8,10 @@ #include "JSystem/JUtility/JUTFader.h" #include "JSystem/J2DGraph/J2DOrthoGraph.h" +#ifdef TARGET_PC +#include +#endif + JUTFader::JUTFader(int x, int y, int width, int height, JUtility::TColor pColor) : mColor(pColor), mBox(x, y, x + width, y + height) { mStatus = None; @@ -63,14 +67,24 @@ void JUTFader::advance() { void JUTFader::control() { advance(); -#ifndef TARGET_PC - // FRAME INTERP NOTE: Draw is called by JFWDisplay when interpolation is active draw(); -#endif } void JUTFader::draw() { if (mColor.a != 0) { +#ifdef TARGET_PC + if (dusk::frame_interp::is_enabled() && mDuration != 0) { + const auto step = dusk::frame_interp::get_interpolation_step(); + const auto progress = static_cast(mTimer) / static_cast(mDuration); + const auto timer = mTimer - 1 + step + progress; + auto alpha = timer / mDuration; + if (mStatus == FadeIn) { + alpha = 1.0f - alpha; + } + alpha = std::clamp(alpha, 0.0f, 1.0f); + mColor.a = static_cast(alpha * 255.0f); + } +#endif J2DOrthoGraph orthograph; orthograph.setColor(mColor); orthograph.fillBox(mBox); diff --git a/src/d/d_camera.cpp b/src/d/d_camera.cpp index 8e13c6271f..0adf6d4bd6 100644 --- a/src/d/d_camera.cpp +++ b/src/d/d_camera.cpp @@ -11262,6 +11262,26 @@ static int camera_execute(camera_process_class* i_this) { return 1; } +#ifdef TARGET_PC +void set_ar_corrected_trim(dDlst_window_c* window, float trim_height) { + const auto viewport = window->getViewPort(); + + if (mDoGph_gInf_c::isWideZoom()) { + const auto target_ar = FB_WIDTH / (FB_HEIGHT - trim_height * 2.0f); + const auto current_ar = mDoGph_gInf_c::m_safeWidthF / mDoGph_gInf_c::m_safeHeightF; + + if (current_ar < target_ar) { + trim_height = FB_HEIGHT / 2.0f * (1.0f - current_ar / target_ar); + } else { + trim_height = 0.0f; + } + } + + trim_height *= viewport->height / FB_HEIGHT; + window->setScissor(0.0f, trim_height, viewport->width, viewport->height - trim_height * 2.0f); +} +#endif + static int camera_draw(camera_process_class* i_this) { camera_class* a_this = (camera_class*)i_this; dCamera_c* body = &i_this->mCamera; @@ -11315,21 +11335,40 @@ static int camera_draw(camera_process_class* i_this) { #endif #if TARGET_PC - auto trim_height = body->TrimHeight(); + set_ar_corrected_trim(window, body->TrimHeight()); - if (mDoGph_gInf_c::isWideZoom()) { - const auto target_ar = FB_WIDTH / (FB_HEIGHT - trim_height * 2.0f); - const auto current_ar = mDoGph_gInf_c::m_safeWidthF / mDoGph_gInf_c::m_safeHeightF; + if (dusk::getSettings().game.enableFrameInterpolation) { + dusk::frame_interp::add_interpolation_callback([](bool _, void* pUserWork) { + const auto i_this = static_cast(pUserWork); + const auto camera = &i_this->mCamera; - if (current_ar < target_ar) { - trim_height = FB_HEIGHT / 2.0f * (1.0f - current_ar / target_ar); - } else { - trim_height = 0.0f; - } + const auto trim_size = camera->mTrimSize; + + if (camera->mCurState != 2 && trim_size >= 0 && trim_size <= 3) { + // derive trim height at previous tick using current camera state + f32 target; + switch (trim_size) { + case 0: + target = 0.0f; + break; + case 1: + target = camera->mCamSetup.VistaTrimHeight(); + break; + case 2: + case 3: + target = camera->mCamSetup.CinemaScopeTrimHeight(); + break; + } + + const auto step = dusk::frame_interp::get_interpolation_step(); + const auto cur = camera->TrimHeight(); + const auto prev = (4.0f * cur - target) / 3.0f; + const auto trim_height = prev + (cur - prev) * step; + + set_ar_corrected_trim(get_window((camera_class*)i_this), trim_height); + } + }, i_this); } - - trim_height *= viewport->height / FB_HEIGHT; - window->setScissor(0.0f, trim_height, viewport->width, viewport->height - trim_height * 2.0f); #else int trim_height = body->TrimHeight(); diff --git a/src/m_Do/m_Do_graphic.cpp b/src/m_Do/m_Do_graphic.cpp index b6a53e15a5..61eaf3bc2d 100644 --- a/src/m_Do/m_Do_graphic.cpp +++ b/src/m_Do/m_Do_graphic.cpp @@ -502,6 +502,14 @@ void mDoGph_gInf_c::calcFade() { } if (mFadeColor.a != 0) { +#ifdef TARGET_PC + if (dusk::frame_interp::is_enabled() && mFade != 0) { + const auto step = dusk::frame_interp::get_interpolation_step(); + const auto progress = mFadeSpeed < 0.0f ? 1.0f - mFadeRate : mFadeRate; + const auto fade_amt = mFadeRate + mFadeSpeed * (step - 1.0f + progress); + mFadeColor.a = 255.0f * std::clamp(fade_amt, 0.0f, 1.0f); + } +#endif darwFilter(mFadeColor); } } From 44da1a9f7d8a3eb9886a8f53ff394a1608b43fad Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Fri, 8 May 2026 13:51:13 -0400 Subject: [PATCH 329/390] Added sounds to Reset & Quit modals (#718) Co-authored-by: MelonSpeedruns --- src/dusk/ui/menu_bar.cpp | 14 ++++++++++++-- src/dusk/ui/modal.cpp | 2 ++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/dusk/ui/menu_bar.cpp b/src/dusk/ui/menu_bar.cpp index fdd89e6967..81c2eea441 100644 --- a/src/dusk/ui/menu_bar.cpp +++ b/src/dusk/ui/menu_bar.cpp @@ -68,12 +68,17 @@ MenuBar::MenuBar() : Document(kDocumentSource), mRoot(mDocument->GetElementById( { ModalAction{ .label = "Cancel", - .onPressed = dismiss, + .onPressed = + [this, dismiss](Modal& modal) { + mDoAud_seStartMenu(kSoundWindowClose); + dismiss(modal); + }, }, ModalAction{ .label = "Reset", .onPressed = [this, dismiss](Modal& modal) { + mDoAud_seStartMenu(kSoundClick); if (fpcM_SearchByName(fpcNm_LOGO_SCENE_e)) { dismiss(modal); return; @@ -98,12 +103,17 @@ MenuBar::MenuBar() : Document(kDocumentSource), mRoot(mDocument->GetElementById( { ModalAction{ .label = "Cancel", - .onPressed = dismiss, + .onPressed = + [dismiss](Modal& modal) { + mDoAud_seStartMenu(kSoundWindowClose); + dismiss(modal); + }, }, ModalAction{ .label = "Quit", .onPressed = [dismiss](Modal& modal) { + mDoAud_seStartMenu(kSoundClick); dismiss(modal); IsRunning = false; }, diff --git a/src/dusk/ui/modal.cpp b/src/dusk/ui/modal.cpp index 6aa1637de7..b08a333163 100644 --- a/src/dusk/ui/modal.cpp +++ b/src/dusk/ui/modal.cpp @@ -36,6 +36,8 @@ Modal::Modal(Props props) : WindowSmall("modal", "modal-dialog"), mProps(std::mo }); mButtons.push_back(std::move(btn)); } + + mDoAud_seStartMenu(kSoundWindowOpen); } bool Modal::focus() { From be82e606b2ef228595508ebb8ab1857c15796d5c Mon Sep 17 00:00:00 2001 From: madeline Date: Fri, 8 May 2026 11:20:17 -0700 Subject: [PATCH 330/390] 45 achievements --- include/dusk/achievements.h | 3 +- res/rml/window.rcss | 14 ++++ src/dusk/achievements.cpp | 125 +++++++++++++++++++++++++++++------ src/dusk/ui/achievements.cpp | 27 +++++++- src/dusk/ui/achievements.hpp | 2 + src/f_ap/f_ap_game.cpp | 2 + src/m_Do/m_Do_main.cpp | 2 - 7 files changed, 149 insertions(+), 26 deletions(-) diff --git a/include/dusk/achievements.h b/include/dusk/achievements.h index bf0021c9d7..5c2758b6b7 100644 --- a/include/dusk/achievements.h +++ b/include/dusk/achievements.h @@ -12,9 +12,8 @@ namespace dusk { enum class AchievementCategory : uint8_t { - Story, - Collection, Challenge, + Collection, Minigame, Misc, Glitched diff --git a/res/rml/window.rcss b/res/rml/window.rcss index 817f3dc333..8dd29b55e4 100644 --- a/res/rml/window.rcss +++ b/res/rml/window.rcss @@ -17,6 +17,7 @@ body { window { display: flex; flex-flow: column; + position: relative; height: 100%; width: 100%; max-width: 1088dp; @@ -291,6 +292,19 @@ icon.question-mark { decorator: text("" center center); } +.achievement-total { + position: absolute; + top: 0; + right: 64dp; + height: 64dp; + line-height: 64dp; + font-family: "Fira Sans Condensed"; + font-weight: bold; + font-size: 16dp; + color: rgba(224, 219, 200, 55%); + pointer-events: none; +} + .achievement-row { display: flex; align-items: flex-start; diff --git a/src/dusk/achievements.cpp b/src/dusk/achievements.cpp index a39221988b..eefcda978f 100644 --- a/src/dusk/achievements.cpp +++ b/src/dusk/achievements.cpp @@ -48,13 +48,13 @@ static constexpr auto ACHIEVEMENTS_FILENAME = "achievements.json"; std::vector AchievementSystem::makeEntries() { return { - // Story + // Challenge { { "hero_of_twilight", "Hero of Twilight", "Deliver the finishing blow to Ganondorf.", - AchievementCategory::Story, + AchievementCategory::Challenge, false, 0, 0, false }, [](Achievement& a, json&) { @@ -69,8 +69,8 @@ std::vector AchievementSystem::makeEntries() { { "completionist", "Completionist", - "100% the game.", - AchievementCategory::Story, + "Complete the game after collecting all equipment, heart containers, portals, bugs, poes, and hidden skills.", + AchievementCategory::Challenge, false, 0, 0, false }, [](Achievement& a, json&) { @@ -352,7 +352,19 @@ std::vector AchievementSystem::makeEntries() { }, {} }, - // Challenge + { + { + "all_letters", + "We Deliver!", + "Collect all 16 postman letters.", + AchievementCategory::Collection, + true, 16, 0, false + }, + [](Achievement& a, json&) { + a.progress = dMeter2Info_getRecieveLetterNum(); + }, + {} + }, { { "cave_of_ordeals", @@ -428,7 +440,7 @@ std::vector AchievementSystem::makeEntries() { "dark_hammer_one_hit", "Mortal Edge", "Defeat Dark Hammer in a single hit.", - AchievementCategory::Challenge, + AchievementCategory::Misc, false, 0, 0, false }, [](Achievement& a, json&) { @@ -481,7 +493,7 @@ std::vector AchievementSystem::makeEntries() { "bow_100m_hit", "Long Shot", "Hit an enemy from over 100 meters away with the bow.", - AchievementCategory::Challenge, + AchievementCategory::Misc, false, 0, 0, false }, [](Achievement& a, json&) { @@ -616,6 +628,36 @@ std::vector AchievementSystem::makeEntries() { }, {} }, + { + { + "star_2_under_40s", + "Rising Star", + "Complete the STAR Prize 2 minigame in under 40 seconds.", + AchievementCategory::Minigame, + false, 0, 0, false + }, + [](Achievement& a, json&) { + if(dComIfGs_getHookGameTime() > 0 && dComIfGs_getHookGameTime() <= 40000) { + a.progress = 1; + } + }, + {} + }, + { + { + "star_2_under_30s", + "Shooting Star", + "Complete the STAR Prize 2 minigame in under 30 seconds.", + AchievementCategory::Minigame, + false, 0, 0, false + }, + [](Achievement& a, json&) { + if(dComIfGs_getHookGameTime() > 0 && dComIfGs_getHookGameTime() <= 30000) { + a.progress = 1; + } + }, + {} + }, // Misc { { @@ -800,19 +842,6 @@ std::vector AchievementSystem::makeEntries() { }, {} }, - { - { - "ultimate_delivery", - "The Ultimate Delivery", - "Have all 16 postman letters at the same time.", - AchievementCategory::Glitched, - true, 16, 0, false - }, - [](Achievement& a, json&) { - a.progress = dMeter2Info_getRecieveLetterNum(); - }, - {} - }, { { "speedrun_4h", @@ -918,6 +947,62 @@ std::vector AchievementSystem::makeEntries() { } }, {} + }, + { + { + "lakebed_before_lanayru", + "White Midna Glitch", + "Clear the Lakebed Temple before clearing Lanayru's Twilight.", + AchievementCategory::Glitched, + false, 0, 0, false + }, + [](Achievement& a, json&) { + if (dComIfGs_isEventBit(dSv_event_flag_c::M_045) && + !dComIfGs_isDarkClearLV(2)) { + a.progress = 1; + } + }, + {} + }, + { + { + "early_hidden_village", + "Quick Detour", + "Rescue the Hidden Village before clearing Goron Mines.", + AchievementCategory::Glitched, + false, 0, 0, false + }, + [](Achievement& a, json&) { + if (dComIfGs_isEventBit(dSv_event_flag_c::F_0278) && + !dComIfGs_isEventBit(dSv_event_flag_c::M_031)) { + a.progress = 1; + } + }, + {} + }, + { + { + "forest_temple_no_boomerang", + "Must Have Been The Wind", + "Complete the Forest Temple without obtaining the Gale Boomerang.", + AchievementCategory::Glitched, + false, 0, 0, false + }, + [](Achievement& a, json&) { + if (!dComIfGs_isEventBit(dSv_event_flag_c::M_022)) { + return; + } + if (daPy_getPlayerActorClass() == nullptr) { + return; + } + for (int i = 0; i < 24; ++i) { + if (dComIfGs_getItem(i, false) == dItemNo_BOOMERANG_e) { + return; + } + } + a.progress = 1; + }, + {} } }; } diff --git a/src/dusk/ui/achievements.cpp b/src/dusk/ui/achievements.cpp index 725d662ec1..b631d444f5 100644 --- a/src/dusk/ui/achievements.cpp +++ b/src/dusk/ui/achievements.cpp @@ -16,9 +16,8 @@ struct CategoryInfo { }; constexpr CategoryInfo kCategories[] = { - {AchievementCategory::Story, "Story"}, - {AchievementCategory::Collection, "Collection"}, {AchievementCategory::Challenge, "Challenge"}, + {AchievementCategory::Collection, "Collection"}, {AchievementCategory::Minigame, "Minigame"}, {AchievementCategory::Misc, "Misc"}, {AchievementCategory::Glitched, "Glitched"}, @@ -114,6 +113,13 @@ private: AchievementsWindow::AchievementsWindow() { const auto all = AchievementSystem::get().getAchievements(); + { + auto elem = mDocument->CreateElement("div"); + elem->SetClass("achievement-total", true); + mTotalEl = mRoot->AppendChild(std::move(elem)); + updateTotal(); + } + for (const auto& catInfo : kCategories) { int catTotal = 0; for (const auto& a : all) { @@ -201,8 +207,25 @@ void AchievementsWindow::update() { if (dirty) { mSnapshot = current; refresh_active_tab(); + updateTotal(); } Window::update(); } +void AchievementsWindow::updateTotal() { + if (mTotalEl == nullptr) { + return; + } + const auto all = AchievementSystem::get().getAchievements(); + int total = static_cast(all.size()); + int unlocked = 0; + for (const auto& a : all) { + if (a.unlocked) { + ++unlocked; + } + } + const int pct = total > 0 ? (unlocked * 100 / total) : 0; + mTotalEl->SetInnerRML(fmt::format("{}%", pct)); +} + } // namespace dusk::ui diff --git a/src/dusk/ui/achievements.hpp b/src/dusk/ui/achievements.hpp index 3a65705600..e0c6fe41ad 100644 --- a/src/dusk/ui/achievements.hpp +++ b/src/dusk/ui/achievements.hpp @@ -13,7 +13,9 @@ public: void update() override; private: + void updateTotal(); std::vector mSnapshot; + Rml::Element* mTotalEl = nullptr; }; } // namespace dusk::ui diff --git a/src/f_ap/f_ap_game.cpp b/src/f_ap/f_ap_game.cpp index 68d244ef72..dc14933b50 100644 --- a/src/f_ap/f_ap_game.cpp +++ b/src/f_ap/f_ap_game.cpp @@ -14,6 +14,7 @@ #include "d/actor/d_a_midna.h" #include "d/d_model.h" #include "d/d_tresure.h" +#include "dusk/achievements.h" #include "dusk/frame_interpolation.h" #include "dusk/livesplit.h" #include "dusk/logging.h" @@ -828,6 +829,7 @@ void fapGm_Execute() { cCt_Counter(0); #ifdef TARGET_PC dusk::speedrun::onGameFrame(); + dusk::AchievementSystem::get().tick(); #endif } diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index 61e65928f8..8719998bd5 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -46,7 +46,6 @@ #include #include #include "SSystem/SComponent/c_API.h" -#include "dusk/achievements.h" #include "dusk/app_info.hpp" #include "dusk/crash_reporting.h" #include "dusk/dusk.h" @@ -283,7 +282,6 @@ void main01(void) { dusk::gyro::read(pacing.sim_pace); fapGm_Execute(); mDoAud_Execute(); - dusk::AchievementSystem::get().tick(); dusk::game_clock::commit_sim_tick(); } } From 1c85ee63ebb3f08f2992dda709509e4b9ecee0b1 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Fri, 8 May 2026 16:57:19 -0600 Subject: [PATCH 331/390] Many mobile fixes, Android update check, "Background Input" & "Pause On Focus Lost" options --- CMakeLists.txt | 11 +- extern/aurora | 2 +- include/dusk/main.h | 1 - include/dusk/settings.h | 1 + platforms/android/app/build.gradle | 18 +- platforms/android/app/proguard-rules.pro | 2 + .../android/app/src/main/AndroidManifest.xml | 1 + .../com/twilitrealm/dusk/DuskActivity.java | 107 ++++- .../com/twilitrealm/dusk/DuskHttpClient.java | 237 +++++++++++ .../java/org/libsdl/app/HIDDeviceManager.java | 1 + .../main/java/org/libsdl/app/SDLActivity.java | 5 +- .../org/libsdl/app/SDLInputConnection.java | 20 +- platforms/android/scripts/stage-jni-libs.sh | 51 ++- res/rml/overlay.rcss | 39 +- res/rml/prelaunch.rcss | 69 ++- src/dusk/file_select.cpp | 105 +++++ src/dusk/file_select.hpp | 9 +- src/dusk/http/android.cpp | 402 ++++++++++++++++++ src/dusk/http/http.hpp | 1 + src/dusk/settings.cpp | 2 + src/dusk/ui/prelaunch.cpp | 3 +- src/dusk/ui/settings.cpp | 15 +- src/dusk/ui/ui.cpp | 6 +- src/dusk/ui/window.cpp | 5 +- src/m_Do/m_Do_main.cpp | 50 ++- 25 files changed, 1068 insertions(+), 95 deletions(-) create mode 100644 platforms/android/app/src/main/java/com/twilitrealm/dusk/DuskHttpClient.java mode change 100644 => 100755 platforms/android/scripts/stage-jni-libs.sh create mode 100644 src/dusk/http/android.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 6956574919..02eaeb183e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -109,12 +109,7 @@ add_subdirectory(libs/freeverb) option(DUSK_BUILD_WARNINGS "Enable compiler warnings (off by default)") option(DUSK_SELECTED_OPT "If on, selected parts of the project will be compiled with optimizations on Debug, intending to make the game run at 30 FPS. Note for MSVC: you will need to remove '/RTC1' from your debug flags in CMake.") option(DUSK_MOVIE_SUPPORT "If on, compile against libjpeg-turbo to enable THP file decoding" ON) -if (ANDROID) - set(DUSK_ENABLE_UPDATE_CHECKER_DEFAULT OFF) -else () - set(DUSK_ENABLE_UPDATE_CHECKER_DEFAULT ON) -endif () -option(DUSK_ENABLE_UPDATE_CHECKER "Enable update checking support" ${DUSK_ENABLE_UPDATE_CHECKER_DEFAULT}) +option(DUSK_ENABLE_UPDATE_CHECKER "Enable update checking support" ON) if(ANDROID) set(DUSK_MOVIE_SUPPORT OFF) @@ -328,6 +323,10 @@ if (DUSK_ENABLE_UPDATE_CHECKER) list(APPEND GAME_LIBS winhttp) list(APPEND GAME_COMPILE_DEFS DUSK_HTTP_BACKEND_WINHTTP=1) message(STATUS "dusk: Enabled update checker (WinHTTP)") + elseif (ANDROID) + set(DUSK_HTTP_BACKEND_SOURCE src/dusk/http/android.cpp) + list(APPEND GAME_COMPILE_DEFS DUSK_HTTP_BACKEND_ANDROID=1) + message(STATUS "dusk: Enabled update checker (Android)") elseif (APPLE) find_library(FOUNDATION_FRAMEWORK Foundation REQUIRED) set(DUSK_HTTP_BACKEND_SOURCE src/dusk/http/url_session.mm) diff --git a/extern/aurora b/extern/aurora index 17be93f0ae..1eeff98783 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 17be93f0ae011fc3202e87e3f2efda4aae250fa5 +Subproject commit 1eeff98783c36fba83970c011783a4fd9deac018 diff --git a/include/dusk/main.h b/include/dusk/main.h index d6b9c9927f..787c2541e2 100644 --- a/include/dusk/main.h +++ b/include/dusk/main.h @@ -11,7 +11,6 @@ namespace dusk { extern bool IsRunning; extern bool IsShuttingDown; extern bool IsGameLaunched; - extern bool IsFocusPaused; extern bool RestartRequested; extern std::filesystem::path ConfigPath; diff --git a/include/dusk/settings.h b/include/dusk/settings.h index 78c5540e58..cb4945801a 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -135,6 +135,7 @@ struct UserSettings { ConfigVar freeCameraSensitivity; ConfigVar debugFlyCam; ConfigVar debugFlyCamLockEvents; + ConfigVar allowBackgroundInput; // Cheats ConfigVar infiniteHearts; diff --git a/platforms/android/app/build.gradle b/platforms/android/app/build.gradle index 9375d06910..01e706a382 100644 --- a/platforms/android/app/build.gradle +++ b/platforms/android/app/build.gradle @@ -2,6 +2,16 @@ plugins { id 'com.android.application' } +def duskRepoDir = rootProject.projectDir.parentFile.parentFile +def duskGeneratedAssetsDir = layout.buildDirectory.dir('generated/assets/dusk').get().asFile +def syncDuskAssets = tasks.register('syncDuskAssets', Sync) { + from(new File(duskRepoDir, 'res')) { + into 'res' + exclude '**/.DS_Store' + } + into duskGeneratedAssetsDir +} + android { namespace 'com.twilitrealm.dusk' compileSdk 36 @@ -27,7 +37,7 @@ android { sourceSets { main { jniLibs.srcDirs = ['src/main/jniLibs'] - assets.srcDirs = ['../../assets'] + assets.srcDirs = [duskGeneratedAssetsDir] } } @@ -48,3 +58,9 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) } + +tasks.configureEach { task -> + if (task.name.startsWith('merge') && task.name.endsWith('Assets')) { + task.dependsOn(syncDuskAssets) + } +} diff --git a/platforms/android/app/proguard-rules.pro b/platforms/android/app/proguard-rules.pro index 952161ca8b..8f2cf4a4e2 100644 --- a/platforms/android/app/proguard-rules.pro +++ b/platforms/android/app/proguard-rules.pro @@ -1,2 +1,4 @@ # Keep SDL activity and related JNI bridge methods. -keep class org.libsdl.app.** { *; } +-keep class com.twilitrealm.dusk.DuskHttpClient { *; } +-keep class com.twilitrealm.dusk.DuskHttpClient$Response { *; } diff --git a/platforms/android/app/src/main/AndroidManifest.xml b/platforms/android/app/src/main/AndroidManifest.xml index e8c2bb29a8..a902065475 100644 --- a/platforms/android/app/src/main/AndroidManifest.xml +++ b/platforms/android/app/src/main/AndroidManifest.xml @@ -10,6 +10,7 @@ + out = new ArrayList<>(); StringBuilder current = new StringBuilder(); @@ -63,7 +72,10 @@ public class DuskActivity extends SDLActivity { super.onCreate(savedInstanceState); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - getWindow().getDecorView().getWindowInsetsController().hide(WindowInsets.Type.systemBars()); + WindowInsetsController ctrl = getWindow().getDecorView().getWindowInsetsController(); + if (ctrl != null) { + ctrl.hide(WindowInsets.Type.systemBars()); + } }else { View decorView = getWindow().getDecorView(); // Hide the status bar. @@ -72,7 +84,9 @@ public class DuskActivity extends SDLActivity { // Remember that you should never show the action bar if the // status bar is hidden, so hide that too if necessary. ActionBar actionBar = getActionBar(); - actionBar.hide(); + if (actionBar != null) { + actionBar.hide(); + } } } @@ -108,4 +122,93 @@ public class DuskActivity extends SDLActivity { } return new String[0]; } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (resultCode == RESULT_OK) { + persistUriPermissions(data); + } + super.onActivityResult(requestCode, resultCode, data); + } + + private void persistUriPermissions(Intent data) { + if (data == null) { + return; + } + + int permissionFlags = + data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + if (permissionFlags == 0) { + return; + } + + Uri uri = data.getData(); + if (uri != null) { + persistUriPermission(uri, permissionFlags); + } + + ClipData clipData = data.getClipData(); + if (clipData == null) { + return; + } + for (int i = 0; i < clipData.getItemCount(); ++i) { + Uri itemUri = clipData.getItemAt(i).getUri(); + if (itemUri != null) { + persistUriPermission(itemUri, permissionFlags); + } + } + } + + private void persistUriPermission(Uri uri, int permissionFlags) { + if ((permissionFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) { + persistUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION, "read"); + } + if ((permissionFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) { + persistUriPermission(uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, "write"); + } + } + + private void persistUriPermission(Uri uri, int permissionFlag, String permissionName) { + try { + getContentResolver().takePersistableUriPermission(uri, permissionFlag); + } catch (SecurityException | IllegalArgumentException e) { + Log.w(TAG, "Unable to persist " + permissionName + " URI permission for " + uri, e); + } + } + + public String getDisplayNameForUri(String uriString) { + if (uriString == null || uriString.isEmpty()) { + return ""; + } + + Uri uri = Uri.parse(uriString); + if ("content".equals(uri.getScheme())) { + try (Cursor cursor = getContentResolver().query( + uri, new String[] { OpenableColumns.DISPLAY_NAME }, null, null, null)) + { + if (cursor != null && cursor.moveToFirst()) { + int displayNameColumn = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); + if (displayNameColumn >= 0) { + String displayName = cursor.getString(displayNameColumn); + if (displayName != null && !displayName.isEmpty()) { + return displayName; + } + } + } + } catch (SecurityException | IllegalArgumentException e) { + Log.w(TAG, "Unable to query display name for " + uri, e); + } + } else if ("file".equals(uri.getScheme())) { + String path = uri.getPath(); + if (path != null && !path.isEmpty()) { + String name = new File(path).getName(); + if (!name.isEmpty()) { + return name; + } + } + } + + String lastSegment = uri.getLastPathSegment(); + return lastSegment != null ? lastSegment : ""; + } } diff --git a/platforms/android/app/src/main/java/com/twilitrealm/dusk/DuskHttpClient.java b/platforms/android/app/src/main/java/com/twilitrealm/dusk/DuskHttpClient.java new file mode 100644 index 0000000000..6e804e506f --- /dev/null +++ b/platforms/android/app/src/main/java/com/twilitrealm/dusk/DuskHttpClient.java @@ -0,0 +1,237 @@ +package com.twilitrealm.dusk; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.SocketTimeoutException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.net.ssl.HttpsURLConnection; + +public final class DuskHttpClient { + public static final int ERROR_NONE = 0; + public static final int ERROR_INVALID_URL = 1; + public static final int ERROR_UNSUPPORTED_SCHEME = 2; + public static final int ERROR_TIMEOUT = 3; + public static final int ERROR_TOO_LARGE = 4; + public static final int ERROR_NETWORK = 5; + + private static final int MAX_REDIRECTS = 5; + + public static final class Response { + public int error; + public String message; + public int statusCode; + public String[] headerNames; + public String[] headerValues; + public byte[] body; + + Response(int error, String message, int statusCode, String[] headerNames, + String[] headerValues, byte[] body) { + this.error = error; + this.message = message; + this.statusCode = statusCode; + this.headerNames = headerNames != null ? headerNames : new String[0]; + this.headerValues = headerValues != null ? headerValues : new String[0]; + this.body = body != null ? body : new byte[0]; + } + } + + private DuskHttpClient() { + } + + public static Response get(String url, String[] headerNames, String[] headerValues, + int timeoutMs, long maxBodyBytes) { + if (url == null || url.isEmpty()) { + return fail(ERROR_INVALID_URL, "URL is empty"); + } + + try { + URL currentUrl = new URL(url); + if (!isHttps(currentUrl)) { + return fail(ERROR_UNSUPPORTED_SCHEME, "Only https:// URLs are supported"); + } + + for (int redirect = 0; redirect <= MAX_REDIRECTS; ++redirect) { + HttpsURLConnection connection = + (HttpsURLConnection) currentUrl.openConnection(); + try { + connection.setRequestMethod("GET"); + connection.setConnectTimeout(timeoutMs); + connection.setReadTimeout(timeoutMs); + connection.setUseCaches(false); + connection.setInstanceFollowRedirects(false); + applyHeaders(connection, headerNames, headerValues); + + int statusCode = connection.getResponseCode(); + if (isRedirect(statusCode)) { + String location = connection.getHeaderField("Location"); + if (location == null || location.isEmpty()) { + return fail(ERROR_NETWORK, "Redirect response did not include Location", + statusCode, connection, new byte[0]); + } + + URL nextUrl = new URL(currentUrl, location); + if (!isHttps(nextUrl)) { + return fail(ERROR_UNSUPPORTED_SCHEME, + "Only https:// redirects are supported", statusCode, + connection, new byte[0]); + } + currentUrl = nextUrl; + continue; + } + + byte[] body = readBody(connection, statusCode, maxBodyBytes); + return success(statusCode, connection, body); + } catch (ResponseTooLargeException e) { + return fail(ERROR_TOO_LARGE, "Response body exceeded the configured limit", + safeStatusCode(connection), connection, e.partialBody); + } finally { + connection.disconnect(); + } + } + + return fail(ERROR_NETWORK, "Too many redirects"); + } catch (MalformedURLException e) { + return fail(ERROR_INVALID_URL, "Failed to parse URL"); + } catch (SocketTimeoutException e) { + return fail(ERROR_TIMEOUT, "Request timed out"); + } catch (IOException e) { + String message = e.getMessage(); + return fail(ERROR_NETWORK, message != null ? message : e.toString()); + } catch (ClassCastException e) { + return fail(ERROR_UNSUPPORTED_SCHEME, "Only https:// URLs are supported"); + } + } + + private static void applyHeaders(HttpsURLConnection connection, String[] names, + String[] values) { + if (names == null || values == null) { + return; + } + + int count = Math.min(names.length, values.length); + for (int i = 0; i < count; ++i) { + if (names[i] != null && values[i] != null) { + connection.setRequestProperty(names[i], values[i]); + } + } + } + + private static boolean isHttps(URL url) { + return "https".equalsIgnoreCase(url.getProtocol()); + } + + private static boolean isRedirect(int statusCode) { + return statusCode == HttpURLConnection.HTTP_MOVED_PERM || + statusCode == HttpURLConnection.HTTP_MOVED_TEMP || + statusCode == HttpURLConnection.HTTP_SEE_OTHER || + statusCode == 307 || + statusCode == 308; + } + + private static byte[] readBody(HttpsURLConnection connection, int statusCode, + long maxBodyBytes) throws IOException, + ResponseTooLargeException { + InputStream stream = statusCode >= HttpURLConnection.HTTP_BAD_REQUEST ? + connection.getErrorStream() : connection.getInputStream(); + if (stream == null) { + return new byte[0]; + } + + try (InputStream bodyStream = stream; + ByteArrayOutputStream out = new ByteArrayOutputStream()) { + byte[] buffer = new byte[8192]; + long total = 0; + while (true) { + int read = bodyStream.read(buffer); + if (read < 0) { + return out.toByteArray(); + } + if (read == 0) { + continue; + } + if (read > maxBodyBytes || total > maxBodyBytes - read) { + throw new ResponseTooLargeException(out.toByteArray()); + } + out.write(buffer, 0, read); + total += read; + } + } + } + + private static int safeStatusCode(HttpsURLConnection connection) { + try { + return connection.getResponseCode(); + } catch (IOException e) { + return 0; + } + } + + private static Response success(int statusCode, HttpsURLConnection connection, byte[] body) { + HeaderLists headers = readHeaders(connection); + return new Response(ERROR_NONE, "", statusCode, headers.names, headers.values, body); + } + + private static Response fail(int error, String message) { + return new Response(error, message, 0, null, null, null); + } + + private static Response fail(int error, String message, int statusCode, + HttpsURLConnection connection, byte[] body) { + HeaderLists headers = readHeaders(connection); + return new Response(error, message, statusCode, headers.names, headers.values, body); + } + + private static HeaderLists readHeaders(HttpsURLConnection connection) { + List names = new ArrayList<>(); + List values = new ArrayList<>(); + + Map> headerFields = connection.getHeaderFields(); + if (headerFields == null) { + return new HeaderLists(new String[0], new String[0]); + } + + for (Map.Entry> entry : headerFields.entrySet()) { + String name = entry.getKey(); + if (name == null) { + continue; + } + List entryValues = entry.getValue(); + if (entryValues == null || entryValues.isEmpty()) { + names.add(name); + values.add(""); + continue; + } + for (String value : entryValues) { + names.add(name); + values.add(value != null ? value : ""); + } + } + + return new HeaderLists(names.toArray(new String[0]), values.toArray(new String[0])); + } + + private static final class HeaderLists { + final String[] names; + final String[] values; + + HeaderLists(String[] names, String[] values) { + this.names = names; + this.values = values; + } + } + + private static final class ResponseTooLargeException extends Exception { + final byte[] partialBody; + + ResponseTooLargeException(byte[] partialBody) { + this.partialBody = partialBody; + } + } +} diff --git a/platforms/android/app/src/main/java/org/libsdl/app/HIDDeviceManager.java b/platforms/android/app/src/main/java/org/libsdl/app/HIDDeviceManager.java index b91a8211b1..1fb2bfb4a7 100644 --- a/platforms/android/app/src/main/java/org/libsdl/app/HIDDeviceManager.java +++ b/platforms/android/app/src/main/java/org/libsdl/app/HIDDeviceManager.java @@ -256,6 +256,7 @@ public class HIDDeviceManager { 0x24c6, // PowerA 0x2c22, // Qanba 0x2dc8, // 8BitDo + 0x37d7, // Flydigi 0x9886, // ASTRO Gaming }; diff --git a/platforms/android/app/src/main/java/org/libsdl/app/SDLActivity.java b/platforms/android/app/src/main/java/org/libsdl/app/SDLActivity.java index 9548c529c0..42f5a911f7 100644 --- a/platforms/android/app/src/main/java/org/libsdl/app/SDLActivity.java +++ b/platforms/android/app/src/main/java/org/libsdl/app/SDLActivity.java @@ -61,7 +61,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh private static final String TAG = "SDL"; private static final int SDL_MAJOR_VERSION = 3; private static final int SDL_MINOR_VERSION = 4; - private static final int SDL_MICRO_VERSION = 2; + private static final int SDL_MICRO_VERSION = 4; /* // Display InputType.SOURCE/CLASS of events and devices // @@ -2032,7 +2032,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh try { ParcelFileDescriptor pfd = mSingleton.getContentResolver().openFileDescriptor(Uri.parse(uri), mode); return pfd != null ? pfd.detachFd() : -1; - } catch (FileNotFoundException e) { + } catch (FileNotFoundException | SecurityException e) { e.printStackTrace(); return -1; } @@ -2227,4 +2227,3 @@ class SDLClipboardHandler implements SDLActivity.onNativeClipboardChanged(); } } - diff --git a/platforms/android/app/src/main/java/org/libsdl/app/SDLInputConnection.java b/platforms/android/app/src/main/java/org/libsdl/app/SDLInputConnection.java index 027b8fd3e5..fdc2994c15 100644 --- a/platforms/android/app/src/main/java/org/libsdl/app/SDLInputConnection.java +++ b/platforms/android/app/src/main/java/org/libsdl/app/SDLInputConnection.java @@ -65,17 +65,15 @@ class SDLInputConnection extends BaseInputConnection @Override public boolean deleteSurroundingText(int beforeLength, int afterLength) { - if (Build.VERSION.SDK_INT <= 29 /* Android 10.0 (Q) */) { - // Workaround to capture backspace key. Ref: http://stackoverflow.com/questions>/14560344/android-backspace-in-webview-baseinputconnection - // and https://bugzilla.libsdl.org/show_bug.cgi?id=2265 - if (beforeLength > 0 && afterLength == 0) { - // backspace(s) - while (beforeLength-- > 0) { - nativeGenerateScancodeForUnichar('\b'); - } - return true; - } - } + // Workaround to capture backspace key. Ref: http://stackoverflow.com/questions>/14560344/android-backspace-in-webview-baseinputconnection + // and https://bugzilla.libsdl.org/show_bug.cgi?id=2265 + if (beforeLength > 0 && afterLength == 0) { + // backspace(s) + while (beforeLength-- > 0) { + nativeGenerateScancodeForUnichar('\b'); + } + return true; + } if (!super.deleteSurroundingText(beforeLength, afterLength)) { return false; diff --git a/platforms/android/scripts/stage-jni-libs.sh b/platforms/android/scripts/stage-jni-libs.sh old mode 100644 new mode 100755 index ae25522e4d..42b08c13e6 --- a/platforms/android/scripts/stage-jni-libs.sh +++ b/platforms/android/scripts/stage-jni-libs.sh @@ -14,9 +14,22 @@ if [[ -z "$ANDROID_NDK_VER" ]] && [[ -d "$ANDROID_HOME_DIR/ndk" ]]; then fi if [[ -n "$ANDROID_NDK_VER" ]]; then - TOOLCHAIN_BIN="$ANDROID_HOME_DIR/ndk/$ANDROID_NDK_VER/toolchains/llvm/prebuilt/linux-x86_64/bin" - if [[ -x "$TOOLCHAIN_BIN/llvm-strip" ]]; then - STRIP_TOOL="$TOOLCHAIN_BIN/llvm-strip" + case "$(uname -s)" in + Darwin) HOST_TAG="darwin-x86_64" ;; + Linux) HOST_TAG="linux-x86_64" ;; + *) HOST_TAG="" ;; + esac + + PREBUILT_DIR="$ANDROID_HOME_DIR/ndk/$ANDROID_NDK_VER/toolchains/llvm/prebuilt" + if [[ -n "$HOST_TAG" && -x "$PREBUILT_DIR/$HOST_TAG/bin/llvm-strip" ]]; then + STRIP_TOOL="$PREBUILT_DIR/$HOST_TAG/bin/llvm-strip" + else + for candidate in "$PREBUILT_DIR"/*/bin/llvm-strip; do + if [[ -x "$candidate" ]]; then + STRIP_TOOL="$candidate" + break + fi + done fi fi @@ -25,29 +38,35 @@ copy_lib() { local src="$2" local dst_dir="$APP_DIR/$abi" local dst="$dst_dir/libmain.so" + local tmp="$dst_dir/.libmain.so.$$" + if [[ ! -f "$src" ]]; then + echo "Missing native library for $abi: $src" >&2 + exit 1 + fi + mkdir -p "$dst_dir" - cp -f "$src" "$dst" + cp -f "$src" "$tmp" if [[ "$ANDROID_STAGE_STRIP" != "0" ]] && [[ -n "$STRIP_TOOL" ]]; then - "$STRIP_TOOL" --strip-debug "$dst" - echo "Staged and stripped $src -> $dst" + "$STRIP_TOOL" --strip-unneeded "$tmp" + mv -f "$tmp" "$dst" + echo "Stripped and staged $src -> $dst" else + mv -f "$tmp" "$dst" echo "Staged $src -> $dst (strip disabled or strip tool unavailable)" fi } -declare -A ABI_TO_LIB=( - ["arm64-v8a"]="$ROOT_DIR/build/android-arm64/libmain.so" - ["x86_64"]="$ROOT_DIR/build/android-x86_64/libmain.so" -) - # Drop any previously staged ABI directories to avoid stale APK contents. rm -rf "$APP_DIR/x86" "$APP_DIR/arm64-v8a" "$APP_DIR/x86_64" for abi in $ANDROID_STAGE_ABIS; do - src="${ABI_TO_LIB[$abi]:-}" - if [[ -z "$src" ]]; then - echo "Unsupported ABI '$abi'. Supported ABIs: arm64-v8a x86_64" >&2 - exit 1 - fi + case "$abi" in + arm64-v8a) src="$ROOT_DIR/build/android-arm64/libmain.so" ;; + x86_64) src="$ROOT_DIR/build/android-x86_64/libmain.so" ;; + *) + echo "Unsupported ABI '$abi'. Supported ABIs: arm64-v8a x86_64" >&2 + exit 1 + ;; + esac copy_lib "$abi" "$src" done diff --git a/res/rml/overlay.rcss b/res/rml/overlay.rcss index 05c8440b55..3ce4d51068 100644 --- a/res/rml/overlay.rcss +++ b/res/rml/overlay.rcss @@ -163,30 +163,30 @@ icon { } icon.arrow-forward { - width: 24dp; - height: 24dp; - font-size: 24dp; + width: 1.2em; + height: 1.2em; + font-size: 1.2em; decorator: text("" center center); } icon.trophy { - width: 24dp; - height: 24dp; - font-size: 24dp; + width: 1.2em; + height: 1.2em; + font-size: 1.2em; decorator: text("" center center); } icon.controller { - width: 24dp; - height: 24dp; - font-size: 24dp; + width: 1.2em; + height: 1.2em; + font-size: 1.2em; decorator: text("" center center); } icon.warning { - width: 24dp; - height: 24dp; - font-size: 24dp; + width: 1.2em; + height: 1.2em; + font-size: 1.2em; decorator: text("" center center); } @@ -274,3 +274,18 @@ logo img.outer { transform: rotate(360deg); } } + +@media (max-height: 640dp) { + toast { + top: 20dp; + right: 20dp; + } + + toast.controller-warning { + bottom: 20dp; + } + + toast.menu-notification { + top: 20dp; + } +} diff --git a/res/rml/prelaunch.rcss b/res/rml/prelaunch.rcss index 9b83db4660..707d8b8234 100644 --- a/res/rml/prelaunch.rcss +++ b/res/rml/prelaunch.rcss @@ -275,7 +275,6 @@ body.mirrored version-info { .update { display: none; - font-size: 16dp; color: #A6A09B; align-items: center; justify-content: flex-end; @@ -375,8 +374,8 @@ body.animate-in .intro-item { } menu { - left: 20dp; - right: 20dp; + left: 32dp; + right: 32dp; width: auto; min-width: 0; max-width: none; @@ -387,8 +386,8 @@ body.animate-in .intro-item { } body.mirrored menu { - left: 20dp; - right: 20dp; + left: 32dp; + right: 32dp; flex-direction: row-reverse; } @@ -396,7 +395,7 @@ body.animate-in .intro-item { flex: 1 1 0; min-width: 0; max-width: 48%; - + margin-left: 32dp; } body.mirrored hero { @@ -438,9 +437,61 @@ body.animate-in .intro-item { decorator: horizontal-gradient(#FEE685FF #FEE68500); } - .eyebrow, - disc-info, - version-info { + .eyebrow { display: none; } + + disc-info { + right: 32dp; + left: auto; + bottom: 32dp; + top: auto; + text-align: right; + font-size: 16dp; + } + + #disc-status { + justify-content: flex-end; + } + + #disc-status icon { + font-size: 20dp; + } + + #disc-version { + font-size: 16dp; + } + + version-info { + right: 32dp; + left: auto; + bottom: auto; + top: 32dp; + text-align: right; + font-size: 16dp; + } + + .update { + font-size: 16dp; + } + + body.mirrored disc-info { + right: auto; + left: 32dp; + bottom: 32dp; + top: auto; + text-align: left; + } + + body.mirrored version-info { + right: auto; + left: 32dp; + bottom: auto; + top: 32dp; + text-align: left; + } + + body.mirrored #disc-status { + justify-content: flex-start; + } } diff --git a/src/dusk/file_select.cpp b/src/dusk/file_select.cpp index fcda233c56..188d491bf3 100644 --- a/src/dusk/file_select.cpp +++ b/src/dusk/file_select.cpp @@ -1,9 +1,16 @@ #include "file_select.hpp" #include +#include #include #include +#include + +#if defined(__ANDROID__) || defined(ANDROID) +#include +#include +#endif #if defined(__APPLE__) #include @@ -19,6 +26,92 @@ namespace dusk { namespace { +std::string fallback_display_name(std::string_view path) { + if (path.empty()) { + return {}; + } + + std::string pathString(path); + const std::size_t slash = pathString.find_last_of("/\\"); + if (slash == std::string::npos || slash + 1 >= pathString.size()) { + return pathString; + } + return pathString.substr(slash + 1); +} + +#if defined(__ANDROID__) || defined(ANDROID) +bool clear_pending_exception(JNIEnv* env) { + if (env == nullptr || !env->ExceptionCheck()) { + return false; + } + env->ExceptionClear(); + return true; +} + +std::string to_string(JNIEnv* env, jstring value) { + if (env == nullptr || value == nullptr) { + return {}; + } + + const char* utf8 = env->GetStringUTFChars(value, nullptr); + if (utf8 == nullptr) { + clear_pending_exception(env); + return {}; + } + + std::string result(utf8); + env->ReleaseStringUTFChars(value, utf8); + return result; +} + +std::string android_display_name(std::string_view path) { + auto* env = static_cast(SDL_GetAndroidJNIEnv()); + if (env == nullptr) { + return {}; + } + + jobject activity = static_cast(SDL_GetAndroidActivity()); + if (activity == nullptr || clear_pending_exception(env)) { + if (activity != nullptr) { + env->DeleteLocalRef(activity); + } + return {}; + } + + jclass activityClass = env->GetObjectClass(activity); + if (activityClass == nullptr || clear_pending_exception(env)) { + env->DeleteLocalRef(activity); + return {}; + } + + jmethodID getDisplayName = env->GetMethodID( + activityClass, "getDisplayNameForUri", "(Ljava/lang/String;)Ljava/lang/String;"); + env->DeleteLocalRef(activityClass); + if (getDisplayName == nullptr || clear_pending_exception(env)) { + env->DeleteLocalRef(activity); + return {}; + } + + jstring uri = env->NewStringUTF(std::string(path).c_str()); + if (uri == nullptr || clear_pending_exception(env)) { + env->DeleteLocalRef(activity); + return {}; + } + + auto* displayName = + static_cast(env->CallObjectMethod(activity, getDisplayName, uri)); + env->DeleteLocalRef(uri); + env->DeleteLocalRef(activity); + if (displayName == nullptr || clear_pending_exception(env)) { + return {}; + } + + std::string result = to_string(env, displayName); + env->DeleteLocalRef(displayName); + return result; +} +#endif + #if USE_IOS_DIALOG struct IOSDialogCallbackState { FileCallback callback; @@ -88,4 +181,16 @@ void ShowFileSelect(FileCallback callback, void* userdata, SDL_Window* window, default_location, allow_many); #endif } + +std::string display_name_for_path(std::string_view path) { +#if defined(__ANDROID__) || defined(ANDROID) + if (path.starts_with("content:") || path.starts_with("file:")) { + std::string displayName = android_display_name(path); + if (!displayName.empty()) { + return displayName; + } + } +#endif + return fallback_display_name(path); +} } // namespace dusk diff --git a/src/dusk/file_select.hpp b/src/dusk/file_select.hpp index 175c5aa086..8bef51cfe6 100644 --- a/src/dusk/file_select.hpp +++ b/src/dusk/file_select.hpp @@ -2,6 +2,9 @@ #include +#include +#include + struct SDL_Window; namespace dusk { @@ -9,7 +12,9 @@ namespace dusk { using FileCallback = void (*)(void* userdata, const char* path, const char* error); void ShowFileSelect(FileCallback callback, void* userdata, SDL_Window* window, - const SDL_DialogFileFilter* filters, int nfilters, const char* default_location, - bool allow_many); + const SDL_DialogFileFilter* filters, int nfilters, const char* default_location, + bool allow_many); + +std::string display_name_for_path(std::string_view path); } // namespace dusk diff --git a/src/dusk/http/android.cpp b/src/dusk/http/android.cpp new file mode 100644 index 0000000000..7debcc7ce2 --- /dev/null +++ b/src/dusk/http/android.cpp @@ -0,0 +1,402 @@ +#include "http.hpp" + +#include +#include + +#include +#include +#include +#include + +namespace dusk::http { +namespace { + +constexpr int JavaErrorNone = 0; +constexpr int JavaErrorInvalidUrl = 1; +constexpr int JavaErrorUnsupportedScheme = 2; +constexpr int JavaErrorTimeout = 3; +constexpr int JavaErrorTooLarge = 4; + +int timeout_ms(std::chrono::milliseconds timeout) { + const auto count = std::max(1, timeout.count()); + return static_cast( + std::min(count, std::numeric_limits::max())); +} + +jlong max_body_bytes(size_t maxBodyBytes) { + return static_cast(std::min( + maxBodyBytes, static_cast(std::numeric_limits::max()))); +} + +bool clear_pending_exception(JNIEnv* env) { + if (env == nullptr || !env->ExceptionCheck()) { + return false; + } + env->ExceptionClear(); + return true; +} + +std::string to_string(JNIEnv* env, jstring value) { + if (env == nullptr || value == nullptr) { + return {}; + } + + const char* utf8 = env->GetStringUTFChars(value, nullptr); + if (utf8 == nullptr) { + clear_pending_exception(env); + return {}; + } + + std::string result(utf8); + env->ReleaseStringUTFChars(value, utf8); + return result; +} + +jstring to_jstring(JNIEnv* env, std::string_view value) { + if (env == nullptr) { + return nullptr; + } + return env->NewStringUTF(std::string(value).c_str()); +} + +Error map_java_error(int error) { + switch (error) { + case JavaErrorNone: + return Error::None; + case JavaErrorInvalidUrl: + return Error::InvalidUrl; + case JavaErrorUnsupportedScheme: + return Error::UnsupportedScheme; + case JavaErrorTimeout: + return Error::Timeout; + case JavaErrorTooLarge: + return Error::TooLarge; + default: + return Error::Network; + } +} + +jclass load_dusk_class(JNIEnv* env, jobject activity, const char* className) { + jclass activityClass = env->GetObjectClass(activity); + if (activityClass == nullptr || clear_pending_exception(env)) { + return nullptr; + } + + jmethodID getClassLoader = + env->GetMethodID(activityClass, "getClassLoader", "()Ljava/lang/ClassLoader;"); + env->DeleteLocalRef(activityClass); + if (getClassLoader == nullptr || clear_pending_exception(env)) { + return nullptr; + } + + jobject classLoader = env->CallObjectMethod(activity, getClassLoader); + if (classLoader == nullptr || clear_pending_exception(env)) { + return nullptr; + } + + jclass classLoaderClass = env->FindClass("java/lang/ClassLoader"); + if (classLoaderClass == nullptr || clear_pending_exception(env)) { + env->DeleteLocalRef(classLoader); + return nullptr; + } + + jmethodID loadClass = env->GetMethodID( + classLoaderClass, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); + env->DeleteLocalRef(classLoaderClass); + if (loadClass == nullptr || clear_pending_exception(env)) { + env->DeleteLocalRef(classLoader); + return nullptr; + } + + jstring javaClassName = env->NewStringUTF(className); + if (javaClassName == nullptr || clear_pending_exception(env)) { + env->DeleteLocalRef(classLoader); + return nullptr; + } + + auto* loadedClass = + static_cast(env->CallObjectMethod(classLoader, loadClass, javaClassName)); + env->DeleteLocalRef(javaClassName); + env->DeleteLocalRef(classLoader); + if (loadedClass == nullptr || clear_pending_exception(env)) { + return nullptr; + } + + return loadedClass; +} + +jobjectArray make_string_array(JNIEnv* env, const std::vector