From e7ecc0d194b4d6a572925e0c30d64a4febd68003 Mon Sep 17 00:00:00 2001 From: madeline Date: Mon, 6 Apr 2026 00:32:39 -0700 Subject: [PATCH 1/7] first run presets --- files.cmake | 2 + include/dusk/config.hpp | 7 ++ src/dusk/config.cpp | 6 ++ src/dusk/imgui/ImGuiConsole.cpp | 4 + src/dusk/imgui/ImGuiConsole.hpp | 2 + src/dusk/imgui/ImGuiEngine.cpp | 2 +- src/dusk/imgui/ImGuiFirstRunPreset.cpp | 130 +++++++++++++++++++++++++ src/dusk/imgui/ImGuiFirstRunPreset.hpp | 14 +++ 8 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 src/dusk/imgui/ImGuiFirstRunPreset.cpp create mode 100644 src/dusk/imgui/ImGuiFirstRunPreset.hpp diff --git a/files.cmake b/files.cmake index 7d07408613..c6cf3b5d3d 100644 --- a/files.cmake +++ b/files.cmake @@ -1358,6 +1358,8 @@ set(DUSK_FILES src/dusk/imgui/ImGuiMenuTools.hpp src/dusk/imgui/ImGuiMenuEnhancements.cpp src/dusk/imgui/ImGuiMenuEnhancements.hpp + src/dusk/imgui/ImGuiFirstRunPreset.hpp + src/dusk/imgui/ImGuiFirstRunPreset.cpp src/dusk/imgui/ImGuiProcessOverlay.cpp src/dusk/imgui/ImGuiCameraOverlay.cpp src/dusk/imgui/ImGuiHeapOverlay.cpp diff --git a/include/dusk/config.hpp b/include/dusk/config.hpp index 258e012f2b..0fd0ad8556 100644 --- a/include/dusk/config.hpp +++ b/include/dusk/config.hpp @@ -111,6 +111,13 @@ void Save(); */ ConfigVarBase* GetConfigVar(std::string_view name); +/** + * \brief Returns true if no config file was found on the last LoadFromUserPreferences() call. + * + * For detect first run to prompt the user to choose a preset. + */ +bool WasConfigFileMissing(); + template const ConfigImplBase* GetConfigImpl() { static ConfigImpl config; diff --git a/src/dusk/config.cpp b/src/dusk/config.cpp index 159706fac8..1fa2e689b6 100644 --- a/src/dusk/config.cpp +++ b/src/dusk/config.cpp @@ -21,6 +21,7 @@ aurora::Module DuskConfigLog("dusk::config"); static absl::flat_hash_map RegisteredConfigVars; static bool RegistrationDone; +static bool s_configFileMissing = false; static std::string GetConfigJsonPath() { return fmt::format("{}{}", configPath, ConfigFileName); @@ -187,6 +188,7 @@ void dusk::config::LoadFromFileName(const char* path) { } catch (const std::system_error& e) { if (e.code() == std::errc::no_such_file_or_directory) { DuskConfigLog.info("Config file did not exist, staying with defaults"); + s_configFileMissing = true; } else { DuskConfigLog.error("Failed to load from config! {}", e.what()); } @@ -212,6 +214,10 @@ void dusk::config::Save() { io::FileStream::WriteAllText(configJsonPath.c_str(), j.dump(4)); } +bool dusk::config::WasConfigFileMissing() { + return s_configFileMissing; +} + ConfigVarBase* dusk::config::GetConfigVar(std::string_view name) { const auto configVar = RegisteredConfigVars.find(name); if (configVar != RegisteredConfigVars.end()) { diff --git a/src/dusk/imgui/ImGuiConsole.cpp b/src/dusk/imgui/ImGuiConsole.cpp index fe5d3e7c9a..7140af5fc7 100644 --- a/src/dusk/imgui/ImGuiConsole.cpp +++ b/src/dusk/imgui/ImGuiConsole.cpp @@ -184,6 +184,10 @@ namespace dusk { m_isLaunchInitialized = true; } + if (config::WasConfigFileMissing()) { + m_firstRunPreset.draw(); + } + getTransientSettings().skipFrameRateLimit = getSettings().game.enableTurboKeybind && ImGui::IsKeyDown(ImGuiKey_Tab); if ((ImGui::IsKeyDown(ImGuiKey_LeftCtrl) || ImGui::IsKeyDown(ImGuiKey_RightCtrl)) && diff --git a/src/dusk/imgui/ImGuiConsole.hpp b/src/dusk/imgui/ImGuiConsole.hpp index 27032ed39b..75da71f6a3 100644 --- a/src/dusk/imgui/ImGuiConsole.hpp +++ b/src/dusk/imgui/ImGuiConsole.hpp @@ -5,6 +5,7 @@ #include #include +#include "ImGuiFirstRunPreset.hpp" #include "ImGuiMenuEnhancements.hpp" #include "ImGuiMenuGame.hpp" #include "ImGuiMenuTools.hpp" @@ -32,6 +33,7 @@ private: bool m_isLaunchInitialized = false; std::deque m_toasts; + ImGuiFirstRunPreset m_firstRunPreset; ImGuiMenuGame m_menuGame; ImGuiMenuEnhancements m_menuEnhancements; diff --git a/src/dusk/imgui/ImGuiEngine.cpp b/src/dusk/imgui/ImGuiEngine.cpp index a6abc5b0b9..37e0415f41 100644 --- a/src/dusk/imgui/ImGuiEngine.cpp +++ b/src/dusk/imgui/ImGuiEngine.cpp @@ -145,7 +145,7 @@ void ImGuiEngine_Initialize(float scale) { colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); - colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f); + colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.60f); } diff --git a/src/dusk/imgui/ImGuiFirstRunPreset.cpp b/src/dusk/imgui/ImGuiFirstRunPreset.cpp new file mode 100644 index 0000000000..275af7a0fc --- /dev/null +++ b/src/dusk/imgui/ImGuiFirstRunPreset.cpp @@ -0,0 +1,130 @@ +#include "ImGuiFirstRunPreset.hpp" + +#include "imgui.h" +#include "ImGuiConsole.hpp" +#include "ImGuiEngine.hpp" +#include "dusk/settings.h" +#include "dusk/config.hpp" + +namespace dusk { + +static void ApplyPresetVanilla() { + auto& s = getSettings(); + // todo: lock aspect ratio +} + +static void ApplyPresetDefault() { + auto& s = getSettings(); + // todo: unlock aspect ratio + // todo: instant saving + s.game.hideTvSettingsScreen.setValue(true); +} + +static void ApplyPresetQoL() { + auto& s = getSettings(); + // todo: unlock aspect ratio + // todo: instant saving + // todo: more save files + // todo: autosave + s.game.enableQuickTransform.setValue(true); + s.game.hideTvSettingsScreen.setValue(true); + s.game.noReturnRupees.setValue(true); + s.game.disableRupeeCutscenes.setValue(true); + s.game.noSwordRecoil.setValue(true); + s.game.fastClimbing.setValue(true); + s.game.noMissClimbing.setValue(true); + s.game.fastTears.setValue(true); + s.game.noLowHpSound.setValue(true); + s.game.midnasLamentNonStop.setValue(true); + s.game.enableFastIronBoots.setValue(true); + s.game.canTransformAnywhere.setValue(true); + s.game.enableTurboKeybind.setValue(true); +} + +// ========================================================================= + +void ImGuiFirstRunPreset::draw() { + const char* modalTitle = "Welcome to Dusk!"; + + if (m_done) return; + + if (!m_opened) { + ImGui::OpenPopup(modalTitle); + m_opened = true; + } + + const ImGuiViewport* viewport = ImGui::GetMainViewport(); + ImGui::SetNextWindowPos(viewport->GetCenter(), ImGuiCond_Always, ImVec2(0.5f, 0.5f)); + ImGui::SetNextWindowSize(ImVec2(800.0f * ImGuiScale(), 0.0f), ImGuiCond_Always); + + if (!ImGui::BeginPopupModal(modalTitle, nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove)) { + // force the user to actually pick one, and not just hit escape to skip the dialog + m_opened = false; + return; + } + + ImGui::TextWrapped("Choose a preset to get started. You can change any setting later from the Enhancements menu."); + ImGui::Spacing(); + ImGui::Separator(); + ImGui::Spacing(); + + int chosen = -1; + + if (ImGui::BeginTable("##presets", 5, ImGuiTableFlags_None)) { + ImGui::TableSetupColumn(nullptr, ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn(nullptr, ImGuiTableColumnFlags_WidthFixed, 16.0f * ImGuiScale()); + ImGui::TableSetupColumn(nullptr, ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn(nullptr, ImGuiTableColumnFlags_WidthFixed, 16.0f * ImGuiScale()); + ImGui::TableSetupColumn(nullptr, ImGuiTableColumnFlags_WidthStretch); + + ImGui::TableNextRow(); + + ImGui::PushFont(ImGuiEngine::fontLarge); + + ImGui::TableSetColumnIndex(0); + if (ImGui::Button("Vanilla##btn", ImVec2(ImGui::GetContentRegionAvail().x, 80.0f * ImGuiScale()))) { + chosen = 0; + } + + ImGui::TableSetColumnIndex(2); + if (ImGui::Button("Default##btn", ImVec2(ImGui::GetContentRegionAvail().x, 80.0f * ImGuiScale()))) { + chosen = 1; + } + + ImGui::TableSetColumnIndex(4); + if (ImGui::Button("Quality of Life##btn", ImVec2(ImGui::GetContentRegionAvail().x, 80.0f * ImGuiScale()))) { + chosen = 2; + } + + ImGui::PopFont(); + + ImGui::TableNextRow(); + + ImGui::TableSetColumnIndex(0); + ImGui::Spacing(); + ImGui::TextWrapped("All enhancements disabled. Plays closest to the original game; good for speedrunning or simple nostalgia!"); + + ImGui::TableSetColumnIndex(2); + ImGui::Spacing(); + ImGui::TextWrapped("Some enhancements enabled, maintaining a vanilla feel. A good starting point for most players!"); + + ImGui::TableSetColumnIndex(4); + ImGui::Spacing(); + ImGui::TextWrapped("Many quality of life enhancements enabled. Good for seasoned players!"); + + ImGui::EndTable(); + } + + if (chosen >= 0) { + if (chosen == 0) ApplyPresetVanilla(); + if (chosen == 1) ApplyPresetDefault(); + if (chosen == 2) ApplyPresetQoL(); + config::Save(); + m_done = true; + ImGui::CloseCurrentPopup(); + } + + ImGui::EndPopup(); +} + +} // namespace dusk diff --git a/src/dusk/imgui/ImGuiFirstRunPreset.hpp b/src/dusk/imgui/ImGuiFirstRunPreset.hpp new file mode 100644 index 0000000000..33ba6b3d0f --- /dev/null +++ b/src/dusk/imgui/ImGuiFirstRunPreset.hpp @@ -0,0 +1,14 @@ +#pragma once + +namespace dusk { + +class ImGuiFirstRunPreset { +public: + void draw(); + +private: + bool m_opened = false; + bool m_done = false; +}; + +} // namespace dusk From e49c1989af08db0a3e96416a965b775c4159b720 Mon Sep 17 00:00:00 2001 From: madeline Date: Mon, 6 Apr 2026 00:37:17 -0700 Subject: [PATCH 2/7] turn off turbo keybind by default --- src/dusk/imgui/ImGuiFirstRunPreset.cpp | 1 - src/dusk/settings.cpp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/dusk/imgui/ImGuiFirstRunPreset.cpp b/src/dusk/imgui/ImGuiFirstRunPreset.cpp index 275af7a0fc..6ac6791455 100644 --- a/src/dusk/imgui/ImGuiFirstRunPreset.cpp +++ b/src/dusk/imgui/ImGuiFirstRunPreset.cpp @@ -38,7 +38,6 @@ static void ApplyPresetQoL() { s.game.midnasLamentNonStop.setValue(true); s.game.enableFastIronBoots.setValue(true); s.game.canTransformAnywhere.setValue(true); - s.game.enableTurboKeybind.setValue(true); } // ========================================================================= diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index 278f783dbf..6a9887c27f 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -51,7 +51,7 @@ UserSettings g_userSettings = { .restoreWiiGlitches {"game.restoreWiiGlitches", false}, // Controls - .enableTurboKeybind {"game.enableTurboKeybind", true}, + .enableTurboKeybind {"game.enableTurboKeybind", false}, }, }; From 841b1bc563556076fa192125bc11af74fccf99da Mon Sep 17 00:00:00 2001 From: madeline Date: Mon, 6 Apr 2026 00:32:39 -0700 Subject: [PATCH 3/7] first run presets --- files.cmake | 2 + include/dusk/config.hpp | 7 ++ src/dusk/config.cpp | 6 ++ src/dusk/imgui/ImGuiConsole.cpp | 4 + src/dusk/imgui/ImGuiConsole.hpp | 2 + src/dusk/imgui/ImGuiEngine.cpp | 2 +- src/dusk/imgui/ImGuiFirstRunPreset.cpp | 130 +++++++++++++++++++++++++ src/dusk/imgui/ImGuiFirstRunPreset.hpp | 14 +++ 8 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 src/dusk/imgui/ImGuiFirstRunPreset.cpp create mode 100644 src/dusk/imgui/ImGuiFirstRunPreset.hpp diff --git a/files.cmake b/files.cmake index 7d07408613..c6cf3b5d3d 100644 --- a/files.cmake +++ b/files.cmake @@ -1358,6 +1358,8 @@ set(DUSK_FILES src/dusk/imgui/ImGuiMenuTools.hpp src/dusk/imgui/ImGuiMenuEnhancements.cpp src/dusk/imgui/ImGuiMenuEnhancements.hpp + src/dusk/imgui/ImGuiFirstRunPreset.hpp + src/dusk/imgui/ImGuiFirstRunPreset.cpp src/dusk/imgui/ImGuiProcessOverlay.cpp src/dusk/imgui/ImGuiCameraOverlay.cpp src/dusk/imgui/ImGuiHeapOverlay.cpp diff --git a/include/dusk/config.hpp b/include/dusk/config.hpp index 258e012f2b..0fd0ad8556 100644 --- a/include/dusk/config.hpp +++ b/include/dusk/config.hpp @@ -111,6 +111,13 @@ void Save(); */ ConfigVarBase* GetConfigVar(std::string_view name); +/** + * \brief Returns true if no config file was found on the last LoadFromUserPreferences() call. + * + * For detect first run to prompt the user to choose a preset. + */ +bool WasConfigFileMissing(); + template const ConfigImplBase* GetConfigImpl() { static ConfigImpl config; diff --git a/src/dusk/config.cpp b/src/dusk/config.cpp index 159706fac8..1fa2e689b6 100644 --- a/src/dusk/config.cpp +++ b/src/dusk/config.cpp @@ -21,6 +21,7 @@ aurora::Module DuskConfigLog("dusk::config"); static absl::flat_hash_map RegisteredConfigVars; static bool RegistrationDone; +static bool s_configFileMissing = false; static std::string GetConfigJsonPath() { return fmt::format("{}{}", configPath, ConfigFileName); @@ -187,6 +188,7 @@ void dusk::config::LoadFromFileName(const char* path) { } catch (const std::system_error& e) { if (e.code() == std::errc::no_such_file_or_directory) { DuskConfigLog.info("Config file did not exist, staying with defaults"); + s_configFileMissing = true; } else { DuskConfigLog.error("Failed to load from config! {}", e.what()); } @@ -212,6 +214,10 @@ void dusk::config::Save() { io::FileStream::WriteAllText(configJsonPath.c_str(), j.dump(4)); } +bool dusk::config::WasConfigFileMissing() { + return s_configFileMissing; +} + ConfigVarBase* dusk::config::GetConfigVar(std::string_view name) { const auto configVar = RegisteredConfigVars.find(name); if (configVar != RegisteredConfigVars.end()) { diff --git a/src/dusk/imgui/ImGuiConsole.cpp b/src/dusk/imgui/ImGuiConsole.cpp index fe5d3e7c9a..7140af5fc7 100644 --- a/src/dusk/imgui/ImGuiConsole.cpp +++ b/src/dusk/imgui/ImGuiConsole.cpp @@ -184,6 +184,10 @@ namespace dusk { m_isLaunchInitialized = true; } + if (config::WasConfigFileMissing()) { + m_firstRunPreset.draw(); + } + getTransientSettings().skipFrameRateLimit = getSettings().game.enableTurboKeybind && ImGui::IsKeyDown(ImGuiKey_Tab); if ((ImGui::IsKeyDown(ImGuiKey_LeftCtrl) || ImGui::IsKeyDown(ImGuiKey_RightCtrl)) && diff --git a/src/dusk/imgui/ImGuiConsole.hpp b/src/dusk/imgui/ImGuiConsole.hpp index 27032ed39b..75da71f6a3 100644 --- a/src/dusk/imgui/ImGuiConsole.hpp +++ b/src/dusk/imgui/ImGuiConsole.hpp @@ -5,6 +5,7 @@ #include #include +#include "ImGuiFirstRunPreset.hpp" #include "ImGuiMenuEnhancements.hpp" #include "ImGuiMenuGame.hpp" #include "ImGuiMenuTools.hpp" @@ -32,6 +33,7 @@ private: bool m_isLaunchInitialized = false; std::deque m_toasts; + ImGuiFirstRunPreset m_firstRunPreset; ImGuiMenuGame m_menuGame; ImGuiMenuEnhancements m_menuEnhancements; diff --git a/src/dusk/imgui/ImGuiEngine.cpp b/src/dusk/imgui/ImGuiEngine.cpp index a6abc5b0b9..37e0415f41 100644 --- a/src/dusk/imgui/ImGuiEngine.cpp +++ b/src/dusk/imgui/ImGuiEngine.cpp @@ -145,7 +145,7 @@ void ImGuiEngine_Initialize(float scale) { colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f); colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); - colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f); + colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.60f); } diff --git a/src/dusk/imgui/ImGuiFirstRunPreset.cpp b/src/dusk/imgui/ImGuiFirstRunPreset.cpp new file mode 100644 index 0000000000..275af7a0fc --- /dev/null +++ b/src/dusk/imgui/ImGuiFirstRunPreset.cpp @@ -0,0 +1,130 @@ +#include "ImGuiFirstRunPreset.hpp" + +#include "imgui.h" +#include "ImGuiConsole.hpp" +#include "ImGuiEngine.hpp" +#include "dusk/settings.h" +#include "dusk/config.hpp" + +namespace dusk { + +static void ApplyPresetVanilla() { + auto& s = getSettings(); + // todo: lock aspect ratio +} + +static void ApplyPresetDefault() { + auto& s = getSettings(); + // todo: unlock aspect ratio + // todo: instant saving + s.game.hideTvSettingsScreen.setValue(true); +} + +static void ApplyPresetQoL() { + auto& s = getSettings(); + // todo: unlock aspect ratio + // todo: instant saving + // todo: more save files + // todo: autosave + s.game.enableQuickTransform.setValue(true); + s.game.hideTvSettingsScreen.setValue(true); + s.game.noReturnRupees.setValue(true); + s.game.disableRupeeCutscenes.setValue(true); + s.game.noSwordRecoil.setValue(true); + s.game.fastClimbing.setValue(true); + s.game.noMissClimbing.setValue(true); + s.game.fastTears.setValue(true); + s.game.noLowHpSound.setValue(true); + s.game.midnasLamentNonStop.setValue(true); + s.game.enableFastIronBoots.setValue(true); + s.game.canTransformAnywhere.setValue(true); + s.game.enableTurboKeybind.setValue(true); +} + +// ========================================================================= + +void ImGuiFirstRunPreset::draw() { + const char* modalTitle = "Welcome to Dusk!"; + + if (m_done) return; + + if (!m_opened) { + ImGui::OpenPopup(modalTitle); + m_opened = true; + } + + const ImGuiViewport* viewport = ImGui::GetMainViewport(); + ImGui::SetNextWindowPos(viewport->GetCenter(), ImGuiCond_Always, ImVec2(0.5f, 0.5f)); + ImGui::SetNextWindowSize(ImVec2(800.0f * ImGuiScale(), 0.0f), ImGuiCond_Always); + + if (!ImGui::BeginPopupModal(modalTitle, nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove)) { + // force the user to actually pick one, and not just hit escape to skip the dialog + m_opened = false; + return; + } + + ImGui::TextWrapped("Choose a preset to get started. You can change any setting later from the Enhancements menu."); + ImGui::Spacing(); + ImGui::Separator(); + ImGui::Spacing(); + + int chosen = -1; + + if (ImGui::BeginTable("##presets", 5, ImGuiTableFlags_None)) { + ImGui::TableSetupColumn(nullptr, ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn(nullptr, ImGuiTableColumnFlags_WidthFixed, 16.0f * ImGuiScale()); + ImGui::TableSetupColumn(nullptr, ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn(nullptr, ImGuiTableColumnFlags_WidthFixed, 16.0f * ImGuiScale()); + ImGui::TableSetupColumn(nullptr, ImGuiTableColumnFlags_WidthStretch); + + ImGui::TableNextRow(); + + ImGui::PushFont(ImGuiEngine::fontLarge); + + ImGui::TableSetColumnIndex(0); + if (ImGui::Button("Vanilla##btn", ImVec2(ImGui::GetContentRegionAvail().x, 80.0f * ImGuiScale()))) { + chosen = 0; + } + + ImGui::TableSetColumnIndex(2); + if (ImGui::Button("Default##btn", ImVec2(ImGui::GetContentRegionAvail().x, 80.0f * ImGuiScale()))) { + chosen = 1; + } + + ImGui::TableSetColumnIndex(4); + if (ImGui::Button("Quality of Life##btn", ImVec2(ImGui::GetContentRegionAvail().x, 80.0f * ImGuiScale()))) { + chosen = 2; + } + + ImGui::PopFont(); + + ImGui::TableNextRow(); + + ImGui::TableSetColumnIndex(0); + ImGui::Spacing(); + ImGui::TextWrapped("All enhancements disabled. Plays closest to the original game; good for speedrunning or simple nostalgia!"); + + ImGui::TableSetColumnIndex(2); + ImGui::Spacing(); + ImGui::TextWrapped("Some enhancements enabled, maintaining a vanilla feel. A good starting point for most players!"); + + ImGui::TableSetColumnIndex(4); + ImGui::Spacing(); + ImGui::TextWrapped("Many quality of life enhancements enabled. Good for seasoned players!"); + + ImGui::EndTable(); + } + + if (chosen >= 0) { + if (chosen == 0) ApplyPresetVanilla(); + if (chosen == 1) ApplyPresetDefault(); + if (chosen == 2) ApplyPresetQoL(); + config::Save(); + m_done = true; + ImGui::CloseCurrentPopup(); + } + + ImGui::EndPopup(); +} + +} // namespace dusk diff --git a/src/dusk/imgui/ImGuiFirstRunPreset.hpp b/src/dusk/imgui/ImGuiFirstRunPreset.hpp new file mode 100644 index 0000000000..33ba6b3d0f --- /dev/null +++ b/src/dusk/imgui/ImGuiFirstRunPreset.hpp @@ -0,0 +1,14 @@ +#pragma once + +namespace dusk { + +class ImGuiFirstRunPreset { +public: + void draw(); + +private: + bool m_opened = false; + bool m_done = false; +}; + +} // namespace dusk From f0fad6280db1c2877fde404a14217ec2cc4797af Mon Sep 17 00:00:00 2001 From: madeline Date: Mon, 6 Apr 2026 00:37:17 -0700 Subject: [PATCH 4/7] turn off turbo keybind by default --- src/dusk/imgui/ImGuiFirstRunPreset.cpp | 1 - src/dusk/settings.cpp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/dusk/imgui/ImGuiFirstRunPreset.cpp b/src/dusk/imgui/ImGuiFirstRunPreset.cpp index 275af7a0fc..6ac6791455 100644 --- a/src/dusk/imgui/ImGuiFirstRunPreset.cpp +++ b/src/dusk/imgui/ImGuiFirstRunPreset.cpp @@ -38,7 +38,6 @@ static void ApplyPresetQoL() { s.game.midnasLamentNonStop.setValue(true); s.game.enableFastIronBoots.setValue(true); s.game.canTransformAnywhere.setValue(true); - s.game.enableTurboKeybind.setValue(true); } // ========================================================================= diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index 278f783dbf..6a9887c27f 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -51,7 +51,7 @@ UserSettings g_userSettings = { .restoreWiiGlitches {"game.restoreWiiGlitches", false}, // Controls - .enableTurboKeybind {"game.enableTurboKeybind", true}, + .enableTurboKeybind {"game.enableTurboKeybind", false}, }, }; From 411ca7e3a2170d98c1df3dba38fc7d699138778d Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Mon, 6 Apr 2026 13:14:14 -0400 Subject: [PATCH 5/7] First time setup preset menu with transition & cool sfx --- include/dusk/config.hpp | 2 +- libs/JSystem/src/JAudio2/JAIStream.cpp | 10 ++++++++++ src/d/actor/d_a_title.cpp | 16 ++++++++++++++++ src/d/d_s_play.cpp | 19 +++++++++++++++++++ src/dusk/config.cpp | 4 +++- src/dusk/imgui/ImGuiConsole.cpp | 9 +++++---- 6 files changed, 54 insertions(+), 6 deletions(-) diff --git a/include/dusk/config.hpp b/include/dusk/config.hpp index 0fd0ad8556..ace11cb424 100644 --- a/include/dusk/config.hpp +++ b/include/dusk/config.hpp @@ -116,7 +116,7 @@ ConfigVarBase* GetConfigVar(std::string_view name); * * For detect first run to prompt the user to choose a preset. */ -bool WasConfigFileMissing(); +bool IsConfigFileMissing(); template const ConfigImplBase* GetConfigImpl() { diff --git a/libs/JSystem/src/JAudio2/JAIStream.cpp b/libs/JSystem/src/JAudio2/JAIStream.cpp index 5799080b12..4c91b1a34a 100644 --- a/libs/JSystem/src/JAudio2/JAIStream.cpp +++ b/libs/JSystem/src/JAudio2/JAIStream.cpp @@ -6,6 +6,10 @@ #include "JSystem/JAudio2/JAIStreamDataMgr.h" #include "JSystem/JAudio2/JAIAudience.h" +#if TARGET_PC +#include +#endif + static void JAIStream_JASAramStreamCallback_(u32 type, JASAramStream* aramStream, void* userData) { JAIStream* stream = (JAIStream*)userData; @@ -35,6 +39,12 @@ JAIStream::JAIStream(JAIStreamMgr* streamMgr, JAISoundStrategyMgr* so void JAIStream::JAIStreamMgr_startID_(JAISoundID id, s32 streamFileEntry, const JGeometry::TVec3* posPtr, JAIAudience* audience, int category) { + #if TARGET_PC + if (dusk::config::IsConfigFileMissing()) { + return; + } + #endif + field_0x298 = category; field_0x294 = streamFileEntry; start_JAISound_(id, posPtr, audience); diff --git a/src/d/actor/d_a_title.cpp b/src/d/actor/d_a_title.cpp index 88ce62ec5c..dad25c74ce 100644 --- a/src/d/actor/d_a_title.cpp +++ b/src/d/actor/d_a_title.cpp @@ -18,6 +18,10 @@ #include "JSystem/J2DGraph/J2DTextBox.h" #include "m_Do/m_Do_graphic.h" +#if TARGET_PC +#include +#endif + class daTit_HIO_c : public JORReflexible { public: daTit_HIO_c(); @@ -152,6 +156,12 @@ int daTitle_c::createHeapCallBack(fopAc_ac_c* actor) { } int daTitle_c::Execute() { + #if TARGET_PC + if (dusk::config::IsConfigFileMissing()) { + return 0; + } + #endif + #if PLATFORM_WII || PLATFORM_SHIELD mDoGph_gInf_c::resetDimming(); #endif @@ -364,6 +374,12 @@ int daTitle_c::getDemoPrm() { } int daTitle_c::Draw() { + #if TARGET_PC + if (dusk::config::IsConfigFileMissing()) { + return 0; + } + #endif + J3DModelData* modelData = mpModel->getModelData(); cMtx_trans(mpModel->getBaseTRMtx(), IREG_F(7), IREG_F(8), IREG_F(9) + -430.0f); mpModel->getBaseScale()->x = -1.0f; diff --git a/src/d/d_s_play.cpp b/src/d/d_s_play.cpp index 3ef8ea7eb2..6dff510bc6 100644 --- a/src/d/d_s_play.cpp +++ b/src/d/d_s_play.cpp @@ -39,7 +39,10 @@ #include "JSystem/JKernel/JKRAram.h" #include "JSystem/JKernel/JKRAramArchive.h" +#if TARGET_PC #include "dusk/memory.h" +#include +#endif #if DEBUG #include "d/d_s_menu.h" @@ -698,6 +701,10 @@ static u8 lbl_8074CAE4; static u32 l_sceneChangeStartTick; #endif +#if TARGET_PC +BOOL firstTime = FALSE; +#endif + static int dScnPly_Execute(dScnPly_c* i_this) { #if DEBUG fapGm_HIO_c::startCpuTimer(); @@ -778,7 +785,19 @@ static int dScnPly_Execute(dScnPly_c* i_this) { dJprev_c::get()->update(); #endif + #if TARGET_PC + if (dusk::config::IsConfigFileMissing()) { + firstTime = true; + } else if (firstTime) { + mDoAud_seStart(Z2SE_TITLE_ENTER, NULL, 0, 0); + JUTGamePad::C3ButtonReset::sResetSwitchPushing = true; + firstTime = false; + } else { + dDemo_c::update(); + } + #else dDemo_c::update(); + #endif #if DEBUG dJcame_c::get()->update(); diff --git a/src/dusk/config.cpp b/src/dusk/config.cpp index 1fa2e689b6..45089ed726 100644 --- a/src/dusk/config.cpp +++ b/src/dusk/config.cpp @@ -212,9 +212,11 @@ void dusk::config::Save() { } io::FileStream::WriteAllText(configJsonPath.c_str(), j.dump(4)); + + s_configFileMissing = false; } -bool dusk::config::WasConfigFileMissing() { +bool dusk::config::IsConfigFileMissing() { return s_configFileMissing; } diff --git a/src/dusk/imgui/ImGuiConsole.cpp b/src/dusk/imgui/ImGuiConsole.cpp index 7140af5fc7..5b025e15ab 100644 --- a/src/dusk/imgui/ImGuiConsole.cpp +++ b/src/dusk/imgui/ImGuiConsole.cpp @@ -179,15 +179,16 @@ namespace dusk { ImGuiConsole::ImGuiConsole() {} void ImGuiConsole::PreDraw() { + if (config::IsConfigFileMissing()) { + m_firstRunPreset.draw(); + return; + } + if (!m_isLaunchInitialized) { m_toasts.emplace_back("Press F1 to toggle menu"s, 5.f); m_isLaunchInitialized = true; } - if (config::WasConfigFileMissing()) { - m_firstRunPreset.draw(); - } - getTransientSettings().skipFrameRateLimit = getSettings().game.enableTurboKeybind && ImGui::IsKeyDown(ImGuiKey_Tab); if ((ImGui::IsKeyDown(ImGuiKey_LeftCtrl) || ImGui::IsKeyDown(ImGuiKey_RightCtrl)) && From 3497ddbcd0921e772483edfd962fd962466fb0dd Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Sat, 11 Apr 2026 16:55:55 -0400 Subject: [PATCH 6/7] removed unused variables and includes --- libs/JSystem/src/JAudio2/JAIStream.cpp | 4 ---- src/d/actor/d_a_title.cpp | 2 +- src/d/d_s_play.cpp | 5 ----- 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/libs/JSystem/src/JAudio2/JAIStream.cpp b/libs/JSystem/src/JAudio2/JAIStream.cpp index 52c9da519d..5799080b12 100644 --- a/libs/JSystem/src/JAudio2/JAIStream.cpp +++ b/libs/JSystem/src/JAudio2/JAIStream.cpp @@ -6,10 +6,6 @@ #include "JSystem/JAudio2/JAIStreamDataMgr.h" #include "JSystem/JAudio2/JAIAudience.h" -#if TARGET_PC -#include -#endif - static void JAIStream_JASAramStreamCallback_(u32 type, JASAramStream* aramStream, void* userData) { JAIStream* stream = (JAIStream*)userData; diff --git a/src/d/actor/d_a_title.cpp b/src/d/actor/d_a_title.cpp index bae2ca7e14..2bf5f0bccb 100644 --- a/src/d/actor/d_a_title.cpp +++ b/src/d/actor/d_a_title.cpp @@ -162,7 +162,7 @@ int daTitle_c::Execute() { } #endif - #if PLATFORM_WII || PLATFORM_SHIELD +#if PLATFORM_WII || PLATFORM_SHIELD mDoGph_gInf_c::resetDimming(); #endif diff --git a/src/d/d_s_play.cpp b/src/d/d_s_play.cpp index 6b494b5bc8..3f3cd073b9 100644 --- a/src/d/d_s_play.cpp +++ b/src/d/d_s_play.cpp @@ -41,7 +41,6 @@ #if TARGET_PC #include "dusk/memory.h" -#include #endif #if DEBUG @@ -701,10 +700,6 @@ static u8 lbl_8074CAE4; static u32 l_sceneChangeStartTick; #endif -#if TARGET_PC -BOOL firstTime = FALSE; -#endif - static int dScnPly_Execute(dScnPly_c* i_this) { #if DEBUG fapGm_HIO_c::startCpuTimer(); From fd59a6e2814f587be9dec0144b3882b9af3cf33b Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Sat, 11 Apr 2026 17:16:40 -0400 Subject: [PATCH 7/7] Only 2 presets for now, Standard and HD --- src/dusk/imgui/ImGuiFirstRunPreset.cpp | 51 +++++++------------------- 1 file changed, 13 insertions(+), 38 deletions(-) diff --git a/src/dusk/imgui/ImGuiFirstRunPreset.cpp b/src/dusk/imgui/ImGuiFirstRunPreset.cpp index 2ab333fbc3..7fa5c11fa6 100644 --- a/src/dusk/imgui/ImGuiFirstRunPreset.cpp +++ b/src/dusk/imgui/ImGuiFirstRunPreset.cpp @@ -8,25 +8,13 @@ namespace dusk { -static void ApplyPresetVanilla() { +static void ApplyPresetStandard() { auto& s = getSettings(); - // todo: lock aspect ratio + s.video.lockAspectRatio.setValue(true); } -static void ApplyPresetDefault() { +static void ApplyPresetHD() { auto& s = getSettings(); - // todo: unlock aspect ratio - // todo: instant saving - s.game.hideTvSettingsScreen.setValue(true); -} - -static void ApplyPresetQoL() { - auto& s = getSettings(); - // todo: unlock aspect ratio - // todo: instant saving - // todo: more save files - // todo: autosave - s.game.enableQuickTransform.setValue(true); s.game.hideTvSettingsScreen.setValue(true); s.game.noReturnRupees.setValue(true); s.game.disableRupeeCutscenes.setValue(true); @@ -34,10 +22,8 @@ static void ApplyPresetQoL() { s.game.fastClimbing.setValue(true); s.game.noMissClimbing.setValue(true); s.game.fastTears.setValue(true); - s.game.noLowHpSound.setValue(true); - s.game.midnasLamentNonStop.setValue(true); - s.game.enableFastIronBoots.setValue(true); - s.game.canTransformAnywhere.setValue(true); + s.game.biggerWallets.setValue(true); + s.game.invertCameraXAxis.setValue(true); } // ========================================================================= @@ -69,55 +55,44 @@ void ImGuiFirstRunPreset::draw() { int chosen = -1; - if (ImGui::BeginTable("##presets", 5, ImGuiTableFlags_None)) { - ImGui::TableSetupColumn(nullptr, ImGuiTableColumnFlags_WidthStretch); - ImGui::TableSetupColumn(nullptr, ImGuiTableColumnFlags_WidthFixed, 16.0f * ImGuiScale()); + if (ImGui::BeginTable("##presets", 3, ImGuiTableFlags_None)) { ImGui::TableSetupColumn(nullptr, ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupColumn(nullptr, ImGuiTableColumnFlags_WidthFixed, 16.0f * ImGuiScale()); ImGui::TableSetupColumn(nullptr, ImGuiTableColumnFlags_WidthStretch); + ImGui::TableNextRow(); ImGui::PushFont(ImGuiEngine::fontLarge); ImGui::TableSetColumnIndex(0); - if (ImGui::Button("Vanilla##btn", ImVec2(ImGui::GetContentRegionAvail().x, 80.0f * ImGuiScale()))) { + if (ImGui::Button("Standard##btn", ImVec2(ImGui::GetContentRegionAvail().x, 80.0f * ImGuiScale()))) { chosen = 0; } ImGui::TableSetColumnIndex(2); - if (ImGui::Button("Default##btn", ImVec2(ImGui::GetContentRegionAvail().x, 80.0f * ImGuiScale()))) { + if (ImGui::Button("HD##btn", ImVec2(ImGui::GetContentRegionAvail().x, 80.0f * ImGuiScale()))) { chosen = 1; } - ImGui::TableSetColumnIndex(4); - if (ImGui::Button("Quality of Life##btn", ImVec2(ImGui::GetContentRegionAvail().x, 80.0f * ImGuiScale()))) { - chosen = 2; - } - ImGui::PopFont(); ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); ImGui::Spacing(); - ImGui::TextWrapped("All enhancements disabled. Plays closest to the original game; good for speedrunning or simple nostalgia!"); + ImGui::TextWrapped("All enhancements disabled to match the GameCube version. Good for speedrunning or simple nostalgia!"); ImGui::TableSetColumnIndex(2); ImGui::Spacing(); - ImGui::TextWrapped("Some enhancements enabled, maintaining a vanilla feel. A good starting point for most players!"); - - ImGui::TableSetColumnIndex(4); - ImGui::Spacing(); - ImGui::TextWrapped("Many quality of life enhancements enabled. Good for seasoned players!"); + ImGui::TextWrapped("Some enhancements enabled to match the HD version. A good starting point for most players!"); ImGui::EndTable(); } if (chosen >= 0) { - if (chosen == 0) ApplyPresetVanilla(); - if (chosen == 1) ApplyPresetDefault(); - if (chosen == 2) ApplyPresetQoL(); + if (chosen == 0) ApplyPresetStandard(); + if (chosen == 1) ApplyPresetHD(); getSettings().backend.wasPresetChosen.setValue(true); config::Save();