From 21fb5a45b3056ab88acfa5b2fbccbbdf2df09687 Mon Sep 17 00:00:00 2001 From: Unreference <87878910+unreference@users.noreply.github.com> Date: Mon, 18 May 2026 18:26:36 -0700 Subject: [PATCH 1/7] feat(enhancement): Options to hide quest modes from File Select --- soh/soh/SohGui/SohMenuEnhancements.cpp | 10 ++++ .../ovl_file_choose/z_file_choose.c | 47 +++++++++++++------ 2 files changed, 42 insertions(+), 15 deletions(-) diff --git a/soh/soh/SohGui/SohMenuEnhancements.cpp b/soh/soh/SohGui/SohMenuEnhancements.cpp index fc4f9f95c80..16cf5dcfadd 100644 --- a/soh/soh/SohGui/SohMenuEnhancements.cpp +++ b/soh/soh/SohGui/SohMenuEnhancements.cpp @@ -689,6 +689,16 @@ void SohMenu::AddMenuEnhancements() { .RaceDisable(false) .Options(CheckboxOptions().Tooltip("The skybox in the background of the File Select screen will go through the " "day and night cycle over time.")); + AddWidget(path, "Hide Randomizer Quest", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("HideRandomizerQuest")) + .RaceDisable(false) + .Options(CheckboxOptions().Tooltip( + "Hides the Randomizer option when selecting a quest type on the File Select screen.")); + AddWidget(path, "Hide Boss Rush Quest", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("HideBossRushQuest")) + .RaceDisable(false) + .Options(CheckboxOptions().Tooltip( + "Hides the Boss Rush option when selecting a quest type on the File Select screen.")); path.column = SECTION_COLUMN_3; AddWidget(path, "Misc.", WIDGET_SEPARATOR_TEXT); diff --git a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c index 964ba69c232..87ac1341870 100644 --- a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c +++ b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c @@ -28,6 +28,24 @@ #define MIN_QUEST (ResourceMgr_GameHasOriginal() ? QUEST_NORMAL : QUEST_MASTER) #define MAX_QUEST QUEST_BOSSRUSH +// #region SOH [Enhancement] - Hide Quest Modes +static bool IsQuestSkipped(uint8_t quest) { + if (quest == QUEST_MASTER && !ResourceMgr_GameHasMasterQuest()) { + return true; + } + + if (quest == QUEST_RANDOMIZER && CVarGetInteger(CVAR_ENHANCEMENT("HideRandomizerQuest"), 0)) { + return true; + } + + if (quest == QUEST_BOSSRUSH && CVarGetInteger(CVAR_ENHANCEMENT("HideBossRushQuest"), 0)) { + return true; + } + + return false; +} +// #endregion + void Sram_InitDebugSave(void); void Sram_InitBossRushSave(); @@ -641,26 +659,25 @@ void FileChoose_UpdateQuestMenu(GameState* thisx) { FileChoose_UpdateRandomizer(); if (ABS(this->stickRelX) > 30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DLEFT | BTN_DRIGHT))) { + // #region SOH [Enhancement] - Hide Quest Modes + // Cycle through quest types, skipping any that are hidden (i.e., Master Quest without OTR, + // Randomizer/Boss Rush when their CVars are set). Wraps around if past min/max. if (this->stickRelX > 30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DRIGHT))) { - this->questType[this->buttonIndex] += 1; - while (this->questType[this->buttonIndex] == QUEST_MASTER && !ResourceMgr_GameHasMasterQuest()) { - // If Master Quest is selected without a Master Quest OTR present, skip past it. + do { this->questType[this->buttonIndex] += 1; - } + if (this->questType[this->buttonIndex] > MAX_QUEST) { + this->questType[this->buttonIndex] = MIN_QUEST; + } + } while (IsQuestSkipped(this->questType[this->buttonIndex])); } else if (this->stickRelX < -30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DLEFT))) { - this->questType[this->buttonIndex] -= 1; - while (this->questType[this->buttonIndex] == QUEST_MASTER && !ResourceMgr_GameHasMasterQuest()) { - // If Master Quest is selected without a Master Quest OTR present, skip past it. + do { this->questType[this->buttonIndex] -= 1; - } - } - - // If current buttonIndex is higher or lower than the min/max value, wrap around. - if (this->questType[this->buttonIndex] > MAX_QUEST) { - this->questType[this->buttonIndex] = MIN_QUEST; - } else if (this->questType[this->buttonIndex] < MIN_QUEST) { - this->questType[this->buttonIndex] = MAX_QUEST; + if (this->questType[this->buttonIndex] < MIN_QUEST) { + this->questType[this->buttonIndex] = MAX_QUEST; + } + } while (IsQuestSkipped(this->questType[this->buttonIndex])); } + // #endregion Audio_PlaySoundGeneral(NA_SE_SY_FSEL_CURSOR, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); From ad78cdc694fb92e18a215b878a23372d511d4a17 Mon Sep 17 00:00:00 2001 From: Unreference <87878910+unreference@users.noreply.github.com> Date: Mon, 18 May 2026 18:54:17 -0700 Subject: [PATCH 2/7] feat(enhancement): Don't draw control stick prompts if only one quest --- .../ovl_file_choose/z_file_choose.c | 74 ++++++++++++------- 1 file changed, 46 insertions(+), 28 deletions(-) diff --git a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c index 87ac1341870..f351d04f13f 100644 --- a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c +++ b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c @@ -44,6 +44,17 @@ static bool IsQuestSkipped(uint8_t quest) { return false; } + +static uint8_t CountVisibleQuests(void) { + uint8_t count = 0; + for (int32_t quest = MIN_QUEST; quest <= MAX_QUEST; ++quest) { + if (!IsQuestSkipped(quest)) { + count++; + } + } + + return count; +} // #endregion void Sram_InitDebugSave(void); @@ -658,8 +669,9 @@ void FileChoose_UpdateQuestMenu(GameState* thisx) { FileChoose_UpdateRandomizer(); - if (ABS(this->stickRelX) > 30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DLEFT | BTN_DRIGHT))) { - // #region SOH [Enhancement] - Hide Quest Modes + // #region SOH [Enhancement] - Hide Quest Modes + if (CountVisibleQuests() > 1 && ABS(this->stickRelX) > 30 || (dpad && CHECK_BTN_ANY(input->press.button, + BTN_DLEFT | BTN_DRIGHT))) { // Cycle through quest types, skipping any that are hidden (i.e., Master Quest without OTR, // Randomizer/Boss Rush when their CVars are set). Wraps around if past min/max. if (this->stickRelX > 30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DRIGHT))) { @@ -677,7 +689,7 @@ void FileChoose_UpdateQuestMenu(GameState* thisx) { } } while (IsQuestSkipped(this->questType[this->buttonIndex])); } - // #endregion + // #endregion Audio_PlaySoundGeneral(NA_SE_SY_FSEL_CURSOR, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); @@ -1735,31 +1747,37 @@ void FileChoose_DrawWindowContents(GameState* thisx) { if ((this->configMode == CM_QUEST_MENU) || (this->configMode == CM_START_QUEST_MENU) || this->configMode == CM_NAME_ENTRY_TO_QUEST_MENU || this->configMode == CM_NAME_ENTRY_TO_RANDOMIZER_SETTINGS_MENU) { - // draw control stick prompts. - Gfx_SetupDL_39Opa(this->state.gfxCtx); - gDPSetCombineMode(POLY_OPA_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); - gDPLoadTextureBlock(POLY_OPA_DISP++, gArrowCursorTex, G_IM_FMT_IA, G_IM_SIZ_8b, 16, 24, 0, - G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 4, G_TX_NOMASK, G_TX_NOLOD, - G_TX_NOLOD); - FileChoose_DrawTextRec(this->state.gfxCtx, this->stickLeftPrompt.arrowColorR, this->stickLeftPrompt.arrowColorG, - this->stickLeftPrompt.arrowColorB, this->stickLeftPrompt.arrowColorA, - this->stickLeftPrompt.arrowTexX, this->stickLeftPrompt.arrowTexY, - this->stickLeftPrompt.z, 0, 0, -1.0f, 1.0f); - FileChoose_DrawTextRec(this->state.gfxCtx, this->stickRightPrompt.arrowColorR, - this->stickRightPrompt.arrowColorG, this->stickRightPrompt.arrowColorB, - this->stickRightPrompt.arrowColorA, this->stickRightPrompt.arrowTexX, - this->stickRightPrompt.arrowTexY, this->stickRightPrompt.z, 0, 0, 1.0f, 1.0f); - gDPLoadTextureBlock(POLY_OPA_DISP++, gControlStickTex, G_IM_FMT_IA, G_IM_SIZ_8b, 16, 16, 0, - G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 4, G_TX_NOMASK, G_TX_NOLOD, - G_TX_NOLOD); - FileChoose_DrawTextRec(this->state.gfxCtx, this->stickLeftPrompt.stickColorR, this->stickLeftPrompt.stickColorG, - this->stickLeftPrompt.stickColorB, this->stickLeftPrompt.stickColorA, - this->stickLeftPrompt.stickTexX, this->stickLeftPrompt.stickTexY, - this->stickLeftPrompt.z, 0, 0, -1.0f, 1.0f); - FileChoose_DrawTextRec(this->state.gfxCtx, this->stickRightPrompt.stickColorR, - this->stickRightPrompt.stickColorG, this->stickRightPrompt.stickColorB, - this->stickRightPrompt.stickColorA, this->stickRightPrompt.stickTexX, - this->stickRightPrompt.stickTexY, this->stickRightPrompt.z, 0, 0, 1.0f, 1.0f); + // #region SOH [Enhancement] - Hide Quest Modes + // Only draw the control stick prompts and arrows when there's more than one quest to cycle through. + if (CountVisibleQuests() > 1) { + // #endregion + // draw control stick prompts. + Gfx_SetupDL_39Opa(this->state.gfxCtx); + gDPSetCombineMode(POLY_OPA_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + gDPLoadTextureBlock(POLY_OPA_DISP++, gArrowCursorTex, G_IM_FMT_IA, G_IM_SIZ_8b, 16, 24, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 4, G_TX_NOMASK, G_TX_NOLOD, + G_TX_NOLOD); + FileChoose_DrawTextRec(this->state.gfxCtx, this->stickLeftPrompt.arrowColorR, this->stickLeftPrompt.arrowColorG, + this->stickLeftPrompt.arrowColorB, this->stickLeftPrompt.arrowColorA, + this->stickLeftPrompt.arrowTexX, this->stickLeftPrompt.arrowTexY, + this->stickLeftPrompt.z, 0, 0, -1.0f, 1.0f); + FileChoose_DrawTextRec(this->state.gfxCtx, this->stickRightPrompt.arrowColorR, + this->stickRightPrompt.arrowColorG, this->stickRightPrompt.arrowColorB, + this->stickRightPrompt.arrowColorA, this->stickRightPrompt.arrowTexX, + this->stickRightPrompt.arrowTexY, this->stickRightPrompt.z, 0, 0, 1.0f, 1.0f); + gDPLoadTextureBlock(POLY_OPA_DISP++, gControlStickTex, G_IM_FMT_IA, G_IM_SIZ_8b, 16, 16, 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, 4, G_TX_NOMASK, G_TX_NOLOD, + G_TX_NOLOD); + FileChoose_DrawTextRec(this->state.gfxCtx, this->stickLeftPrompt.stickColorR, this->stickLeftPrompt.stickColorG, + this->stickLeftPrompt.stickColorB, this->stickLeftPrompt.stickColorA, + this->stickLeftPrompt.stickTexX, this->stickLeftPrompt.stickTexY, + this->stickLeftPrompt.z, 0, 0, -1.0f, 1.0f); + FileChoose_DrawTextRec(this->state.gfxCtx, this->stickRightPrompt.stickColorR, + this->stickRightPrompt.stickColorG, this->stickRightPrompt.stickColorB, + this->stickRightPrompt.stickColorA, this->stickRightPrompt.stickTexX, + this->stickRightPrompt.stickTexY, this->stickRightPrompt.z, 0, 0, 1.0f, 1.0f); + } + switch (this->questType[this->buttonIndex]) { case QUEST_NORMAL: default: From c9028468b41ffd499d7bd9c83a7ad17b94d2c338 Mon Sep 17 00:00:00 2001 From: Unreference <87878910+unreference@users.noreply.github.com> Date: Mon, 18 May 2026 19:31:13 -0700 Subject: [PATCH 3/7] feat(enhancement): Option to hide Master Quest from File Select --- soh/soh/SohGui/SohMenuEnhancements.cpp | 10 ++++++++++ .../gamestates/ovl_file_choose/z_file_choose.c | 4 +++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/soh/soh/SohGui/SohMenuEnhancements.cpp b/soh/soh/SohGui/SohMenuEnhancements.cpp index 16cf5dcfadd..45aa831563e 100644 --- a/soh/soh/SohGui/SohMenuEnhancements.cpp +++ b/soh/soh/SohGui/SohMenuEnhancements.cpp @@ -5,6 +5,7 @@ #include #include #include +#include extern "C" { #include "functions.h" @@ -689,6 +690,15 @@ void SohMenu::AddMenuEnhancements() { .RaceDisable(false) .Options(CheckboxOptions().Tooltip("The skybox in the background of the File Select screen will go through the " "day and night cycle over time.")); + AddWidget(path, "Hide Master Quest", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("HideMasterQuest")) + .RaceDisable(false) + .PreFunc([](const WidgetInfo& info) { + info.options->disabled = !ResourceMgr_GameHasMasterQuest(); + info.options->disabledTooltip = "This option requires a loaded Master Quest O2R."; + }) + .Options(CheckboxOptions().Tooltip( + "Hides the Master Quest option when selecting a quest type on the File Select screen.")); AddWidget(path, "Hide Randomizer Quest", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("HideRandomizerQuest")) .RaceDisable(false) diff --git a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c index f351d04f13f..2b973967b55 100644 --- a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c +++ b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c @@ -30,7 +30,8 @@ // #region SOH [Enhancement] - Hide Quest Modes static bool IsQuestSkipped(uint8_t quest) { - if (quest == QUEST_MASTER && !ResourceMgr_GameHasMasterQuest()) { + if (quest == QUEST_MASTER && (!ResourceMgr_GameHasMasterQuest() || + CVarGetInteger(CVAR_ENHANCEMENT("HideMasterQuest"), 0))) { return true; } @@ -55,6 +56,7 @@ static uint8_t CountVisibleQuests(void) { return count; } + // #endregion void Sram_InitDebugSave(void); From ccc5ea01152625380fd1667ed36fedc7f2a77e2d Mon Sep 17 00:00:00 2001 From: Unreference <87878910+unreference@users.noreply.github.com> Date: Mon, 18 May 2026 19:35:32 -0700 Subject: [PATCH 4/7] fix(enhancement): Validate current selection not hidden --- .../gamestates/ovl_file_choose/z_file_choose.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c index 2b973967b55..044136358f1 100644 --- a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c +++ b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c @@ -671,6 +671,17 @@ void FileChoose_UpdateQuestMenu(GameState* thisx) { FileChoose_UpdateRandomizer(); + // #region SOH [Enhancement] - Hide Quest Modes + // If the current quest type was hidden after being selected (i.e., CVar changed while on the quest menu), advance + // to the next visible one. + while (IsQuestSkipped(this->questType[this->buttonIndex])) { + this->questType[this->buttonIndex] += 1; + if (this->questType[this->buttonIndex] > MAX_QUEST) { + this->questType[this->buttonIndex] = MIN_QUEST; + } + } + // #endregion + // #region SOH [Enhancement] - Hide Quest Modes if (CountVisibleQuests() > 1 && ABS(this->stickRelX) > 30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DLEFT | BTN_DRIGHT))) { From 7cc62b7636dd88d36208e037c32f9bea35f4e61f Mon Sep 17 00:00:00 2001 From: Unreference <87878910+unreference@users.noreply.github.com> Date: Mon, 18 May 2026 19:45:32 -0700 Subject: [PATCH 5/7] feat(enhancement): File Select section in menu --- soh/soh/SohGui/SohMenuEnhancements.cpp | 14 ++++++++------ .../gamestates/ovl_file_choose/z_file_choose.c | 1 - 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/soh/soh/SohGui/SohMenuEnhancements.cpp b/soh/soh/SohGui/SohMenuEnhancements.cpp index 45aa831563e..58d11b76227 100644 --- a/soh/soh/SohGui/SohMenuEnhancements.cpp +++ b/soh/soh/SohGui/SohMenuEnhancements.cpp @@ -675,17 +675,19 @@ void SohMenu::AddMenuEnhancements() { .CVar(CVAR_ENHANCEMENT("AlwaysShowDungeonMinimapIcon")) .RaceDisable(false) .Options(CheckboxOptions().Tooltip("Always shows dungeon entrance icons on the Minimap.")); - AddWidget(path, "More Info in File Select", WIDGET_CVAR_CHECKBOX) - .CVar(CVAR_ENHANCEMENT("FileSelectMoreInfo")) - .RaceDisable(false) - .Options(CheckboxOptions().Tooltip( - "Shows what items you have collected in the File Select screen, like in N64 Randomizer.")); AddWidget(path, "Better Ammo Rendering in Pause Menu", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("BetterAmmoRendering")) .RaceDisable(false) .Options(CheckboxOptions().Tooltip( "Ammo counts in the pause menu will work correctly regardless of the position of items in the Inventory.")); - AddWidget(path, "Enable Passage of Time on File Select", WIDGET_CVAR_CHECKBOX) + + AddWidget(path, "File Select", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "More Info", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("FileSelectMoreInfo")) + .RaceDisable(false) + .Options(CheckboxOptions().Tooltip( + "Shows what items you have collected in the File Select screen, like in N64 Randomizer.")); + AddWidget(path, "Enable Passage of Time", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("TimeFlowFileSelect")) .RaceDisable(false) .Options(CheckboxOptions().Tooltip("The skybox in the background of the File Select screen will go through the " diff --git a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c index 044136358f1..c1390e0854d 100644 --- a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c +++ b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c @@ -56,7 +56,6 @@ static uint8_t CountVisibleQuests(void) { return count; } - // #endregion void Sram_InitDebugSave(void); From 0ddc3b97ee9e79e2353e2d24a54934b322597f3f Mon Sep 17 00:00:00 2001 From: Unreference <87878910+unreference@users.noreply.github.com> Date: Mon, 18 May 2026 20:48:47 -0700 Subject: [PATCH 6/7] fix(enhancement): MQ-only O2Rs cannot hide Master Quest --- soh/soh/SohGui/SohMenuEnhancements.cpp | 14 ++++++++++---- .../gamestates/ovl_file_choose/z_file_choose.c | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/soh/soh/SohGui/SohMenuEnhancements.cpp b/soh/soh/SohGui/SohMenuEnhancements.cpp index 58d11b76227..6e054264a32 100644 --- a/soh/soh/SohGui/SohMenuEnhancements.cpp +++ b/soh/soh/SohGui/SohMenuEnhancements.cpp @@ -696,17 +696,23 @@ void SohMenu::AddMenuEnhancements() { .CVar(CVAR_ENHANCEMENT("HideMasterQuest")) .RaceDisable(false) .PreFunc([](const WidgetInfo& info) { - info.options->disabled = !ResourceMgr_GameHasMasterQuest(); - info.options->disabledTooltip = "This option requires a loaded Master Quest O2R."; + if (!ResourceMgr_GameHasMasterQuest()) { + info.options->disabled = true; + info.options->disabledTooltip = "This option requires a loaded Master Quest O2R."; + } else if (!ResourceMgr_GameHasOriginal()) { + info.options->disabled = true; + info.options->disabledTooltip = "Master Quest cannot be hidden when it is the only base quest."; + CVarClear(CVAR_ENHANCEMENT("HideMasterQuest")); + } }) .Options(CheckboxOptions().Tooltip( "Hides the Master Quest option when selecting a quest type on the File Select screen.")); - AddWidget(path, "Hide Randomizer Quest", WIDGET_CVAR_CHECKBOX) + AddWidget(path, "Hide Randomizer", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("HideRandomizerQuest")) .RaceDisable(false) .Options(CheckboxOptions().Tooltip( "Hides the Randomizer option when selecting a quest type on the File Select screen.")); - AddWidget(path, "Hide Boss Rush Quest", WIDGET_CVAR_CHECKBOX) + AddWidget(path, "Hide Boss Rush", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("HideBossRushQuest")) .RaceDisable(false) .Options(CheckboxOptions().Tooltip( diff --git a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c index c1390e0854d..c220776e3f6 100644 --- a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c +++ b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c @@ -684,7 +684,7 @@ void FileChoose_UpdateQuestMenu(GameState* thisx) { // #region SOH [Enhancement] - Hide Quest Modes if (CountVisibleQuests() > 1 && ABS(this->stickRelX) > 30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DLEFT | BTN_DRIGHT))) { - // Cycle through quest types, skipping any that are hidden (i.e., Master Quest without OTR, + // Cycle through quest types, skipping any that are hidden (i.e., Master Quest without O2R, // Randomizer/Boss Rush when their CVars are set). Wraps around if past min/max. if (this->stickRelX > 30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DRIGHT))) { do { From 1141ca68bfc0546dacd881c57d64aac4ec557e38 Mon Sep 17 00:00:00 2001 From: Unreference <87878910+unreference@users.noreply.github.com> Date: Mon, 18 May 2026 21:23:44 -0700 Subject: [PATCH 7/7] feat(enhancement): Hide original game, prevent hiding all quests --- soh/soh/SohGui/SohMenuEnhancements.cpp | 54 +++++++++++++++++-- .../ovl_file_choose/z_file_choose.c | 4 ++ 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/soh/soh/SohGui/SohMenuEnhancements.cpp b/soh/soh/SohGui/SohMenuEnhancements.cpp index 6e054264a32..f3c1c3dfe98 100644 --- a/soh/soh/SohGui/SohMenuEnhancements.cpp +++ b/soh/soh/SohGui/SohMenuEnhancements.cpp @@ -136,6 +136,28 @@ static const std::map mirroredWorldModes = { { MIRRORED_WORLD_DUNGEONS_RANDOM_SEEDED, "Dungeons Random (Seeded)" }, }; +static uint8_t CountVisibleFileSelectQuests() { + uint8_t count = 0; + + if (ResourceMgr_GameHasOriginal() && !CVarGetInteger(CVAR_ENHANCEMENT("HideNormalQuest"), 0)) { + count++; + } + + if (ResourceMgr_GameHasMasterQuest() && !CVarGetInteger(CVAR_ENHANCEMENT("HideMasterQuest"), 0)) { + count++; + } + + if (!CVarGetInteger(CVAR_ENHANCEMENT("HideRandomizerQuest"), 0)) { + count++; + } + + if (!CVarGetInteger(CVAR_ENHANCEMENT("HideBossRushQuest"), 0)) { + count++; + } + + return count; +} + void SohMenu::AddMenuEnhancements() { // Add Enhancements Menu AddMenuEntry("Enhancements", CVAR_SETTING("Menu.EnhancementsSidebarSection")); @@ -692,6 +714,21 @@ void SohMenu::AddMenuEnhancements() { .RaceDisable(false) .Options(CheckboxOptions().Tooltip("The skybox in the background of the File Select screen will go through the " "day and night cycle over time.")); + + AddWidget(path, "Hide Original", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("HideNormalQuest")) + .RaceDisable(false) + .PreFunc([](const WidgetInfo& info) { + if (!ResourceMgr_GameHasOriginal()) { + info.options->disabled = true; + info.options->disabledTooltip = "This option requires a loaded original O2R."; + } else if (CountVisibleFileSelectQuests() <= 1 && !CVarGetInteger(CVAR_ENHANCEMENT("HideNormalQuest"), 0)) { + info.options->disabled = true; + info.options->disabledTooltip = "At least one quest type must remain visible."; + } + }) + .Options(CheckboxOptions().Tooltip( + "Hides the original game when selecting a quest type on the File Select screen.")); AddWidget(path, "Hide Master Quest", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("HideMasterQuest")) .RaceDisable(false) @@ -699,10 +736,9 @@ void SohMenu::AddMenuEnhancements() { if (!ResourceMgr_GameHasMasterQuest()) { info.options->disabled = true; info.options->disabledTooltip = "This option requires a loaded Master Quest O2R."; - } else if (!ResourceMgr_GameHasOriginal()) { + } else if (CountVisibleFileSelectQuests() <= 1 && !CVarGetInteger(CVAR_ENHANCEMENT("HideMasterQuest"), 0)) { info.options->disabled = true; - info.options->disabledTooltip = "Master Quest cannot be hidden when it is the only base quest."; - CVarClear(CVAR_ENHANCEMENT("HideMasterQuest")); + info.options->disabledTooltip = "At least one quest type must remain visible."; } }) .Options(CheckboxOptions().Tooltip( @@ -710,11 +746,23 @@ void SohMenu::AddMenuEnhancements() { AddWidget(path, "Hide Randomizer", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("HideRandomizerQuest")) .RaceDisable(false) + .PreFunc([](const WidgetInfo& info) { + if (CountVisibleFileSelectQuests() <= 1 && !CVarGetInteger(CVAR_ENHANCEMENT("HideRandomizerQuest"), 0)) { + info.options->disabled = true; + info.options->disabledTooltip = "At least one quest type must remain visible."; + } + }) .Options(CheckboxOptions().Tooltip( "Hides the Randomizer option when selecting a quest type on the File Select screen.")); AddWidget(path, "Hide Boss Rush", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("HideBossRushQuest")) .RaceDisable(false) + .PreFunc([](const WidgetInfo& info) { + if (CountVisibleFileSelectQuests() <= 1 && !CVarGetInteger(CVAR_ENHANCEMENT("HideBossRushQuest"), 0)) { + info.options->disabled = true; + info.options->disabledTooltip = "At least one quest type must remain visible."; + } + }) .Options(CheckboxOptions().Tooltip( "Hides the Boss Rush option when selecting a quest type on the File Select screen.")); diff --git a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c index c220776e3f6..604539d7bf9 100644 --- a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c +++ b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c @@ -30,6 +30,10 @@ // #region SOH [Enhancement] - Hide Quest Modes static bool IsQuestSkipped(uint8_t quest) { + if (quest == QUEST_NORMAL && CVarGetInteger(CVAR_ENHANCEMENT("HideNormalQuest"), 0)) { + return true; + } + if (quest == QUEST_MASTER && (!ResourceMgr_GameHasMasterQuest() || CVarGetInteger(CVAR_ENHANCEMENT("HideMasterQuest"), 0))) { return true;