diff --git a/soh/assets/custom/presets/Enhancements - Curated First Time Vanilla.json b/soh/assets/custom/presets/Enhancements - Curated First Time Vanilla.json index 7033bcef32..c1bad53c3f 100644 --- a/soh/assets/custom/presets/Enhancements - Curated First Time Vanilla.json +++ b/soh/assets/custom/presets/Enhancements - Curated First Time Vanilla.json @@ -15,6 +15,9 @@ "DynamicWalletIcon": 1, "EnemySpawnsOverWaterboxes": 1, "FasterRupeeAccumulator": 1, + "FileSelect": { + "TimeFlow": 1 + }, "FixBrokenGiantsKnife": 1, "FixDaruniaDanceSpeed": 1, "FixDampeGoingBackwards": 1, @@ -45,7 +48,6 @@ "SkipSaveConfirmation": 1, "SkipText": 1, "TextSpeed": 5, - "TimeFlowFileSelect": 1, "TwoHandedIdle": 1, "VisualAgony": 1, "WidescreenActorCulling": 1 diff --git a/soh/assets/custom/presets/Enhancements - Curated Randomizer.json b/soh/assets/custom/presets/Enhancements - Curated Randomizer.json index 256487f929..c3532ea4b7 100644 --- a/soh/assets/custom/presets/Enhancements - Curated Randomizer.json +++ b/soh/assets/custom/presets/Enhancements - Curated Randomizer.json @@ -42,7 +42,10 @@ "FasterBlockPush": 5, "FasterHeavyBlockLift": 1, "FasterRupeeAccumulator": 1, - "FileSelectMoreInfo": 1, + "FileSelect": { + "MoreInfo": 1, + "TimeFlow": 1 + }, "FishNeverEscape": 1, "FixBrokenGiantsKnife": 1, "FixDaruniaDanceSpeed": 1, @@ -105,7 +108,6 @@ "SlowTextSpeed": 5, "SwordToggle": 1, "TextSpeed": 5, - "TimeFlowFileSelect": 1, "TimeSavers": { "DisableTitleCard": 1, "SkipChildStealth": 1, diff --git a/soh/assets/custom/presets/Enhancements - Curated Returning Vanilla.json b/soh/assets/custom/presets/Enhancements - Curated Returning Vanilla.json index dabf841f56..ee2fa0b69e 100644 --- a/soh/assets/custom/presets/Enhancements - Curated Returning Vanilla.json +++ b/soh/assets/custom/presets/Enhancements - Curated Returning Vanilla.json @@ -15,6 +15,9 @@ "DynamicWalletIcon": 1, "EnemySpawnsOverWaterboxes": 1, "FasterRupeeAccumulator": 1, + "FileSelect": { + "TimeFlow": 1 + }, "FixBrokenGiantsKnife": 1, "FixDampeGoingBackwards": 1, "FixDaruniaDanceSpeed": 1, @@ -45,7 +48,6 @@ "SkipSaveConfirmation": 1, "SkipText": 1, "TextSpeed": 5, - "TimeFlowFileSelect": 1, "TimeSavers": { "SkipJabuJabuFish": 1 }, diff --git a/soh/soh/Enhancements/cosmetics/FileSelectMoreInfo.cpp b/soh/soh/Enhancements/cosmetics/FileSelectMoreInfo.cpp index 19687795d7..f2216c31c5 100644 --- a/soh/soh/Enhancements/cosmetics/FileSelectMoreInfo.cpp +++ b/soh/soh/Enhancements/cosmetics/FileSelectMoreInfo.cpp @@ -757,7 +757,7 @@ static void DrawMoreInfo(FileChooseContext* thisx, s16 fileIndex, u8 alpha) { } #define CVAR_FILE_SELECT_MORE_INFO_DEFAULT false -#define CVAR_FILE_SELECT_MORE_INFO_NAME CVAR_ENHANCEMENT("FileSelectMoreInfo") +#define CVAR_FILE_SELECT_MORE_INFO_NAME CVAR_ENHANCEMENT("FileSelect.MoreInfo") #define CVAR_FILE_SELECT_MORE_INFO_VALUE \ CVarGetInteger(CVAR_FILE_SELECT_MORE_INFO_NAME, CVAR_FILE_SELECT_MORE_INFO_DEFAULT) diff --git a/soh/soh/Enhancements/cosmetics/TimeFlowFileSelect.cpp b/soh/soh/Enhancements/cosmetics/TimeFlowFileSelect.cpp index 24c52cb48a..cf92db662e 100644 --- a/soh/soh/Enhancements/cosmetics/TimeFlowFileSelect.cpp +++ b/soh/soh/Enhancements/cosmetics/TimeFlowFileSelect.cpp @@ -8,7 +8,7 @@ extern "C" { extern "C" SaveContext gSaveContext; static constexpr int32_t CVAR_TIMEFLOWFILESELECT_DEFAULT = 0; -#define CVAR_TIMEFLOWFILESELECT_NAME CVAR_ENHANCEMENT("TimeFlowFileSelect") +#define CVAR_TIMEFLOWFILESELECT_NAME CVAR_ENHANCEMENT("FileSelect.TimeFlow") #define CVAR_TIMEFLOWFILESELECT_VALUE CVarGetInteger(CVAR_TIMEFLOWFILESELECT_NAME, CVAR_TIMEFLOWFILESELECT_DEFAULT) void OnFileChooseMainTimeFlowFileSelect(void* gameState) { diff --git a/soh/soh/SohGui/SohMenuEnhancements.cpp b/soh/soh/SohGui/SohMenuEnhancements.cpp index 4fd53960bb..5efbdcdba2 100644 --- a/soh/soh/SohGui/SohMenuEnhancements.cpp +++ b/soh/soh/SohGui/SohMenuEnhancements.cpp @@ -10,6 +10,7 @@ #include "soh/Enhancements/Restorations/GetItemManipulation.h" #include "soh/Enhancements/randomizer/SeedContext.h" #include +#include extern "C" { #include "functions.h" @@ -174,6 +175,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("FileSelect.HideNormalQuest"), 0)) { + count++; + } + + if (ResourceMgr_GameHasMasterQuest() && !CVarGetInteger(CVAR_ENHANCEMENT("FileSelect.HideMasterQuest"), 0)) { + count++; + } + + if (!CVarGetInteger(CVAR_ENHANCEMENT("FileSelect.HideRandomizerQuest"), 0)) { + count++; + } + + if (!CVarGetInteger(CVAR_ENHANCEMENT("FileSelect.HideBossRushQuest"), 0)) { + count++; + } + + return count; +} + void SohMenu::AddMenuEnhancements() { // Add Enhancements Menu AddMenuEntry("Enhancements", CVAR_SETTING("Menu.EnhancementsSidebarSection")); @@ -758,22 +781,79 @@ 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) - .CVar(CVAR_ENHANCEMENT("TimeFlowFileSelect")) + + AddWidget(path, "File Select", WIDGET_SEPARATOR_TEXT); + AddWidget(path, "More Info", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("FileSelect.MoreInfo")) + .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("FileSelect.TimeFlow")) .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("FileSelect.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("FileSelect.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("FileSelect.HideMasterQuest")) + .RaceDisable(false) + .PreFunc([](const WidgetInfo& info) { + if (!ResourceMgr_GameHasMasterQuest()) { + info.options->disabled = true; + info.options->disabledTooltip = "This option requires a loaded Master Quest O2R."; + } else if (CountVisibleFileSelectQuests() <= 1 && + !CVarGetInteger(CVAR_ENHANCEMENT("FileSelect.HideMasterQuest"), 0)) { + info.options->disabled = true; + info.options->disabledTooltip = "At least one quest type must remain visible."; + } + }) + .Options(CheckboxOptions().Tooltip( + "Hides the Master Quest option when selecting a quest type on the File Select screen.")); + AddWidget(path, "Hide Randomizer", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("FileSelect.HideRandomizerQuest")) + .RaceDisable(false) + .PreFunc([](const WidgetInfo& info) { + if (CountVisibleFileSelectQuests() <= 1 && + !CVarGetInteger(CVAR_ENHANCEMENT("FileSelect.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("FileSelect.HideBossRushQuest")) + .RaceDisable(false) + .PreFunc([](const WidgetInfo& info) { + if (CountVisibleFileSelectQuests() <= 1 && + !CVarGetInteger(CVAR_ENHANCEMENT("FileSelect.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.")); + path.column = SECTION_COLUMN_3; AddWidget(path, "Misc.", WIDGET_SEPARATOR_TEXT); AddWidget(path, "N64 Mode", WIDGET_CVAR_CHECKBOX) diff --git a/soh/soh/config/ConfigUpdaters.cpp b/soh/soh/config/ConfigUpdaters.cpp index 61db0038b1..baf3183a61 100644 --- a/soh/soh/config/ConfigUpdaters.cpp +++ b/soh/soh/config/ConfigUpdaters.cpp @@ -1449,6 +1449,8 @@ static const Migration version6Migrations[] = { }; static const Migration version7Migrations[] = { + { "gEnhancements.FileSelectMoreInfo", "gEnhancements.FileSelect.MoreInfo" }, + { "gEnhancements.TimeFlowFileSelect", "gEnhancements.FileSelect.TimeFlow" }, { "gRandoSettings.LacsStoneCount", "gRandoSettings.GbkStoneCount" }, { "gRandoSettings.LacsMedallionCount", "gRandoSettings.GbkMedallionCount" }, { "gRandoSettings.LacsRewardCount", "gRandoSettings.GbkRewardCount" }, 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 77ea1c7a0e..1795e7db75 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 @@ -20,6 +20,7 @@ #include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" #include #include "z64save.h" +#include "variables.h" #include "soh/SaveManager.h" #include "soh/OTRGlobals.h" #include "soh/ResourceManagerHelpers.h" @@ -28,6 +29,35 @@ #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) { + switch (quest) { + case QUEST_NORMAL: + return !ResourceMgr_GameHasOriginal() || CVarGetInteger(CVAR_ENHANCEMENT("FileSelect.HideNormalQuest"), 0); + case QUEST_MASTER: + return !ResourceMgr_GameHasMasterQuest() || + CVarGetInteger(CVAR_ENHANCEMENT("FileSelect.HideMasterQuest"), 0); + case QUEST_RANDOMIZER: + return CVarGetInteger(CVAR_ENHANCEMENT("FileSelect.HideRandomizerQuest"), 0); + case QUEST_BOSSRUSH: + return CVarGetInteger(CVAR_ENHANCEMENT("FileSelect.HideBossRushQuest"), 0); + default: + 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); void Sram_InitBossRushSave(); @@ -420,9 +450,17 @@ static s16 sLastFileChooseButtonIndex; * Update function for `CM_MAIN_MENU` */ void FileChoose_UpdateMainMenu(GameState* thisx) { + static u8 emptyName[] = { 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E }; + static u8 emptyNameNES[] = { 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF }; + static u8 linkName[] = { 0x15, 0x2C, 0x31, 0x2E, 0x3E, 0x3E, 0x3E, 0x3E }; + static u8 linkNameNES[] = { 0xB6, 0xCD, 0xD2, 0xCF, 0xDF, 0xDF, 0xDF, 0xDF }; + static u8 linkNameJP[] = { 0x81, 0x87, 0x61, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF }; + FileChooseContext* this = (FileChooseContext*)thisx; Input* input = &this->state.input[0]; bool dpad = CVarGetInteger(CVAR_SETTING("DpadInText"), 0); + u8* defaultName; + u8 isDefaultNameOptionSet; FileChoose_UpdateRandomizer(); @@ -434,6 +472,32 @@ void FileChoose_UpdateMainMenu(GameState* thisx) { this->prevConfigMode = this->configMode; this->configMode = CM_ROTATE_TO_QUEST_MENU; this->logoAlpha = 0; + this->kbdButton = FS_KBD_BTN_NONE; + this->charPage = FS_CHAR_PAGE_ENG; + this->kbdX = 0; + this->kbdY = 0; + this->charIndex = 0; + this->charBgAlpha = 0; + + isDefaultNameOptionSet = CVarGetInteger(CVAR_ENHANCEMENT("LinkDefaultName"), 0); + this->newFileNameCharCount = isDefaultNameOptionSet ? 4 : 0; + this->nameEntryBoxPosX = 120; + this->nameEntryBoxAlpha = 0; + if (gSaveContext.language == LANGUAGE_JPN) { // Japanese + if (isDefaultNameOptionSet) { + // Set player name to "リンク" ("Link" in Katakana, 3 characters long) when playing in Japanese. + defaultName = &linkNameJP; + this->newFileNameCharCount = 3; + } else { + defaultName = &emptyNameNES; + } + this->charPage = FS_CHAR_PAGE_HIRA; // Default to Hiragana Keyboard + } else if (ResourceMgr_GetGameRegion(0) == GAME_REGION_PAL) { + defaultName = isDefaultNameOptionSet ? &linkName : &emptyName; + } else { // GAME_REGION_NTSC + defaultName = isDefaultNameOptionSet ? &linkNameNES : &emptyNameNES; + } + memcpy(Save_GetSaveMetaInfo(this->buttonIndex)->playerName, defaultName, 8); } else if (!FileChoose_IsSaveCompatible(Save_GetSaveMetaInfo(this->buttonIndex))) { Audio_PlaySfxGeneral(NA_SE_SY_FSEL_ERROR, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); @@ -626,11 +690,6 @@ void FileChoose_StartRandomizerMenu(GameState* thisx) { } void FileChoose_UpdateQuestMenu(GameState* thisx) { - static u8 emptyName[] = { 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E }; - static u8 emptyNameNES[] = { 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF }; - static u8 linkName[] = { 0x15, 0x2C, 0x31, 0x2E, 0x3E, 0x3E, 0x3E, 0x3E }; - static u8 linkNameNES[] = { 0xB6, 0xCD, 0xD2, 0xCF, 0xDF, 0xDF, 0xDF, 0xDF }; - static u8 linkNameJP[] = { 0x81, 0x87, 0x61, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF }; FileChoose_UpdateStickDirectionPromptAnim(thisx); FileChooseContext* this = (FileChooseContext*)thisx; Input* input = &this->state.input[0]; @@ -640,27 +699,40 @@ void FileChoose_UpdateQuestMenu(GameState* thisx) { FileChoose_UpdateRandomizer(); - if (ABS(this->stickRelX) > 30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DLEFT | BTN_DRIGHT))) { - 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. - this->questType[this->buttonIndex] += 1; - } - } 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. - this->questType[this->buttonIndex] -= 1; + // #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. + if (CountVisibleQuests() > 0) { + while (IsQuestSkipped(this->questType[this->buttonIndex])) { + this->questType[this->buttonIndex]++; + if (this->questType[this->buttonIndex] > MAX_QUEST) { + this->questType[this->buttonIndex] = MIN_QUEST; } } + } + // #endregion - // 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; + // #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 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 { + this->questType[this->buttonIndex]++; + 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))) { + do { + this->questType[this->buttonIndex]--; + if (this->questType[this->buttonIndex] < MIN_QUEST) { + this->questType[this->buttonIndex] = MAX_QUEST; + } + } while (IsQuestSkipped(this->questType[this->buttonIndex])); } + // #endregion Audio_PlaySfxGeneral(NA_SE_SY_FSEL_CURSOR, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); @@ -689,30 +761,6 @@ void FileChoose_UpdateQuestMenu(GameState* thisx) { this->prevConfigMode = this->configMode; this->configMode = CM_ROTATE_TO_NAME_ENTRY; this->logoAlpha = 0; - this->kbdButton = FS_KBD_BTN_NONE; - this->charPage = FS_CHAR_PAGE_ENG; - this->kbdX = 0; - this->kbdY = 0; - this->charIndex = 0; - this->charBgAlpha = 0; - this->newFileNameCharCount = CVarGetInteger(CVAR_ENHANCEMENT("LinkDefaultName"), 0) ? 4 : 0; - this->nameEntryBoxPosX = 120; - this->nameEntryBoxAlpha = 0; - if (ResourceMgr_GetGameRegion(0) == GAME_REGION_PAL && gSaveContext.language != LANGUAGE_JPN) { - defaultName = CVarGetInteger(CVAR_ENHANCEMENT("LinkDefaultName"), 0) ? &linkName : &emptyName; - } else if (gSaveContext.language == LANGUAGE_JPN) { // Japanese - if (CVarGetInteger(CVAR_ENHANCEMENT("LinkDefaultName"), 0) != 0) { - // Set player name to "リンク" ("Link" in Katakana, 3 characters long) when playing in Japanese. - defaultName = &linkNameJP; - this->newFileNameCharCount = 3; - } else { - defaultName = &emptyNameNES; - } - this->charPage = FS_CHAR_PAGE_HIRA; // Default to Hiragana Keyboard - } else { // GAME_REGION_NTSC - defaultName = CVarGetInteger(CVAR_ENHANCEMENT("LinkDefaultName"), 0) ? &linkNameNES : &emptyNameNES; - } - memcpy(Save_GetSaveMetaInfo(this->buttonIndex)->playerName, defaultName, 8); return; } } @@ -779,41 +827,10 @@ void FileChoose_UpdateRandomizerMenu(GameState* thisx) { SohFileSelect_ShowPresetModal(); Audio_PlaySfxGeneral(NA_SE_SY_FSEL_DECIDE_L, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); - static u8 emptyName[] = { 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E }; - static u8 emptyNameNES[] = { 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF }; - static u8 linkName[] = { 0x15, 0x2C, 0x31, 0x2E, 0x3E, 0x3E, 0x3E, 0x3E }; - static u8 linkNameNES[] = { 0xB6, 0xCD, 0xD2, 0xCF, 0xDF, 0xDF, 0xDF, 0xDF }; - static u8 linkNameJP[] = { 0x81, 0x87, 0x61, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF }; - u8* defaultName; this->prevConfigMode = this->configMode; this->configMode = CM_ROTATE_TO_NAME_ENTRY; - this->logoAlpha = 0; CVarSetInteger(CVAR_GENERAL("OnFileSelectNameEntry"), 1); - this->kbdButton = FS_KBD_BTN_NONE; - this->charPage = FS_CHAR_PAGE_ENG; - this->kbdX = 0; - this->kbdY = 0; - this->charIndex = 0; - this->charBgAlpha = 0; - this->newFileNameCharCount = CVarGetInteger(CVAR_ENHANCEMENT("LinkDefaultName"), 0) ? 4 : 0; - this->nameEntryBoxPosX = 120; - this->nameEntryBoxAlpha = 0; - if (ResourceMgr_GetGameRegion(0) == GAME_REGION_PAL && gSaveContext.language != LANGUAGE_JPN) { - defaultName = CVarGetInteger(CVAR_ENHANCEMENT("LinkDefaultName"), 0) ? &linkName : &emptyName; - } else if (gSaveContext.language == LANGUAGE_JPN) { // Japanese - if (CVarGetInteger(CVAR_ENHANCEMENT("LinkDefaultName"), 0) != 0) { - // Set player name to "リンク" ("Link" in Katakana, 3 characters long) when playing in Japanese. - defaultName = &linkNameJP; - this->newFileNameCharCount = 3; - } else { - defaultName = &emptyNameNES; - } - this->charPage = FS_CHAR_PAGE_HIRA; // Default to Hiragana Keyboard - } else { // GAME_REGION_NTSC - defaultName = CVarGetInteger(CVAR_ENHANCEMENT("LinkDefaultName"), 0) ? &linkNameNES : &emptyNameNES; - } - memcpy(Save_GetSaveMetaInfo(this->buttonIndex)->playerName, defaultName, 8); } else { Sfx_PlaySfxCentered(NA_SE_SY_OCARINA_ERROR); } @@ -895,20 +912,13 @@ void FileChoose_RotateToMain(GameState* thisx) { FileChooseContext* this = (FileChooseContext*)thisx; if (this->configMode == CM_QUEST_TO_MAIN || this->configMode == CM_OPTIONS_TO_MAIN) { this->windowRot -= VREG(16); - - if (this->windowRot <= 0.0f) { - this->windowRot = 0.0f; - this->configMode = CM_MAIN_MENU; - } + } else if (this->configMode == CM_NAME_ENTRY_TO_MAIN) { + this->windowRot += VREG(16); } - if (this->configMode == CM_NAME_ENTRY_TO_MAIN && this->prevConfigMode == CM_MAIN_MENU) { - this->windowRot += VREG(16); - - if (this->windowRot >= 942.0f) { - this->windowRot = 0.0f; - this->configMode = CM_MAIN_MENU; - } + if (this->windowRot <= 0.0f || this->windowRot >= 942.0f) { + this->windowRot = 0.0f; + this->configMode = CM_MAIN_MENU; } } @@ -920,15 +930,35 @@ void FileChoose_RotateToQuest(GameState* thisx) { this->windowRot -= VREG(16); if (this->windowRot <= 314.0f) { - this->windowRot = 314.0f; - this->configMode = CM_START_QUEST_MENU; + if (CountVisibleQuests() > 1) { + this->windowRot = 314.0f; + this->configMode = CM_START_QUEST_MENU; + } else { + this->windowRot = 0.0f; + this->configMode = CM_MAIN_MENU; + } } } else { this->windowRot += VREG(16); if (this->windowRot >= 314.0f) { - this->windowRot = 314.0f; - this->configMode = CM_START_QUEST_MENU; + if (CountVisibleQuests() > 1) { + this->windowRot = 314.0f; + this->configMode = CM_START_QUEST_MENU; + } else { + this->windowRot = 628.0f; + + if (!IsQuestSkipped(QUEST_RANDOMIZER)) { + this->configMode = CM_START_RANDOMIZER_SETTINGS_MENU; + } else if (!IsQuestSkipped(QUEST_BOSSRUSH)) { + this->configMode = CM_START_BOSS_RUSH_MENU; + } else { + this->configMode = CM_START_NAME_ENTRY; + + // Needed to come back to main menu + this->prevConfigMode = CM_MAIN_MENU; + } + } } } } @@ -1718,31 +1748,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: