mirror of
https://github.com/HarbourMasters/Shipwright
synced 2026-09-29 03:17:52 -04:00
Refactor file select quest visibility, fix single quest handling (#7210)
Select single visible quest when only single quest visible Fix bad operator precedence
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
#include <ship/Context.h>
|
||||
|
||||
#include "soh/OTRGlobals.h"
|
||||
#include "soh/ResourceManagerHelpers.h"
|
||||
#include "soh/SohGui/SohModals.h"
|
||||
#include "soh/SohGui/SohGui.hpp"
|
||||
#include "soh/SohGui/UIWidgets.hpp"
|
||||
@@ -67,6 +68,34 @@ std::array<std::string, LANGUAGE_MAX> RandomizerSettingsMenuText[RSM_MAX] = {
|
||||
},
|
||||
};
|
||||
|
||||
// Quests are hidden when their O2R is missing or their File Select "Hide" option is on
|
||||
bool SohFileSelect_IsQuestHidden(u8 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;
|
||||
}
|
||||
}
|
||||
|
||||
u8 SohFileSelect_CountVisibleQuests() {
|
||||
u8 count = 0;
|
||||
for (u8 quest = QUEST_NORMAL; quest <= QUEST_BOSSRUSH; ++quest) {
|
||||
if (!SohFileSelect_IsQuestHidden(quest)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
const char* SohFileSelect_GetSettingText(uint8_t optionIndex, uint8_t language) {
|
||||
return RandomizerSettingsMenuText[optionIndex][language].c_str();
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ extern "C" {
|
||||
#endif
|
||||
const char* SohFileSelect_GetSettingText(u8 optionIndex, u8 language);
|
||||
void SohFileSelect_ShowPresetModal();
|
||||
bool SohFileSelect_IsQuestHidden(u8 quest);
|
||||
u8 SohFileSelect_CountVisibleQuests();
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "soh/Enhancements/SwitchAge.h"
|
||||
#include "soh/Enhancements/AdultMasks.h"
|
||||
#include "soh/Enhancements/BunnyHood.h"
|
||||
#include "soh/Enhancements/FileSelectEnhancements.h"
|
||||
#include <soh/Enhancements/game-interactor/GameInteractor.h>
|
||||
#include <soh/OTRGlobals.h>
|
||||
#include <soh/Enhancements/cosmetics/authenticGfxPatches.h>
|
||||
@@ -177,26 +178,20 @@ static const std::map<int32_t, const char*> 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;
|
||||
// Disables a File Select "Hide" checkbox when its O2R is missing, or when it would hide the last visible quest
|
||||
static WidgetFunc HideQuestPreFunc(Quest quest) {
|
||||
return [quest](WidgetInfo& info) {
|
||||
if (quest == QUEST_NORMAL && !ResourceMgr_GameHasOriginal()) {
|
||||
info.options->disabled = true;
|
||||
info.options->disabledTooltip = "This option requires a loaded original O2R.";
|
||||
} else if (quest == QUEST_MASTER && !ResourceMgr_GameHasMasterQuest()) {
|
||||
info.options->disabled = true;
|
||||
info.options->disabledTooltip = "This option requires a loaded Master Quest O2R.";
|
||||
} else if (!SohFileSelect_IsQuestHidden(quest) && SohFileSelect_CountVisibleQuests() <= 1) {
|
||||
info.options->disabled = true;
|
||||
info.options->disabledTooltip = "At least one quest type must remain visible.";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void SohMenu::AddMenuEnhancements() {
|
||||
@@ -806,55 +801,25 @@ void SohMenu::AddMenuEnhancements() {
|
||||
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.";
|
||||
}
|
||||
})
|
||||
.PreFunc(HideQuestPreFunc(QUEST_NORMAL))
|
||||
.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.";
|
||||
}
|
||||
})
|
||||
.PreFunc(HideQuestPreFunc(QUEST_MASTER))
|
||||
.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.";
|
||||
}
|
||||
})
|
||||
.PreFunc(HideQuestPreFunc(QUEST_RANDOMIZER))
|
||||
.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.";
|
||||
}
|
||||
})
|
||||
.PreFunc(HideQuestPreFunc(QUEST_BOSSRUSH))
|
||||
.Options(CheckboxOptions().Tooltip(
|
||||
"Hides the Boss Rush option when selecting a quest type on the File Select screen."));
|
||||
|
||||
|
||||
@@ -31,31 +31,22 @@
|
||||
#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++;
|
||||
// Step from quest in the given direction (1 or -1) to the next visible quest, wrapping around at the ends
|
||||
static s8 NextVisibleQuest(s8 quest, s8 dir) {
|
||||
// Try each quest at most once, so this can't loop forever if every quest is hidden
|
||||
for (int32_t tries = MAX_QUEST - MIN_QUEST + 1; tries > 0; --tries) {
|
||||
quest += dir;
|
||||
if (quest > MAX_QUEST) {
|
||||
quest = MIN_QUEST;
|
||||
} else if (quest < MIN_QUEST) {
|
||||
quest = MAX_QUEST;
|
||||
}
|
||||
if (!SohFileSelect_IsQuestHidden(quest)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
return quest;
|
||||
}
|
||||
// #endregion
|
||||
|
||||
@@ -706,35 +697,20 @@ void FileChoose_UpdateQuestMenu(GameState* thisx) {
|
||||
// #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;
|
||||
}
|
||||
}
|
||||
if (SohFileSelect_IsQuestHidden(this->questType[this->buttonIndex])) {
|
||||
this->questType[this->buttonIndex] = NextVisibleQuest(this->questType[this->buttonIndex], 1);
|
||||
}
|
||||
// #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))) {
|
||||
if (SohFileSelect_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]));
|
||||
this->questType[this->buttonIndex] = NextVisibleQuest(this->questType[this->buttonIndex], 1);
|
||||
} 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]));
|
||||
this->questType[this->buttonIndex] = NextVisibleQuest(this->questType[this->buttonIndex], -1);
|
||||
}
|
||||
// #endregion
|
||||
|
||||
@@ -934,7 +910,7 @@ void FileChoose_RotateToQuest(GameState* thisx) {
|
||||
this->windowRot -= VREG(16);
|
||||
|
||||
if (this->windowRot <= 314.0f) {
|
||||
if (CountVisibleQuests() > 1) {
|
||||
if (SohFileSelect_CountVisibleQuests() > 1) {
|
||||
this->windowRot = 314.0f;
|
||||
this->configMode = CM_START_QUEST_MENU;
|
||||
} else {
|
||||
@@ -946,21 +922,29 @@ void FileChoose_RotateToQuest(GameState* thisx) {
|
||||
this->windowRot += VREG(16);
|
||||
|
||||
if (this->windowRot >= 314.0f) {
|
||||
if (CountVisibleQuests() > 1) {
|
||||
if (SohFileSelect_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;
|
||||
// Only one quest is visible, so select it as if it was picked on the quest menu
|
||||
this->questType[this->buttonIndex] = NextVisibleQuest(MAX_QUEST, 1);
|
||||
gSaveContext.ship.quest.id = this->questType[this->buttonIndex];
|
||||
|
||||
// Needed to come back to main menu
|
||||
this->prevConfigMode = CM_MAIN_MENU;
|
||||
switch (this->questType[this->buttonIndex]) {
|
||||
case QUEST_RANDOMIZER:
|
||||
this->configMode = CM_START_RANDOMIZER_SETTINGS_MENU;
|
||||
break;
|
||||
case QUEST_BOSSRUSH:
|
||||
this->configMode = CM_START_BOSS_RUSH_MENU;
|
||||
break;
|
||||
default:
|
||||
this->configMode = CM_START_NAME_ENTRY;
|
||||
|
||||
// Needed to come back to main menu
|
||||
this->prevConfigMode = CM_MAIN_MENU;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1754,7 +1738,7 @@ void FileChoose_DrawWindowContents(GameState* thisx) {
|
||||
this->configMode == CM_NAME_ENTRY_TO_RANDOMIZER_SETTINGS_MENU) {
|
||||
// #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) {
|
||||
if (SohFileSelect_CountVisibleQuests() > 1) {
|
||||
// #endregion
|
||||
// draw control stick prompts.
|
||||
Gfx_SetupDL_39Opa(this->state.gfxCtx);
|
||||
|
||||
Reference in New Issue
Block a user