From fdcd9a750803e0a56f5053f91c49baa9802272ec Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Tue, 28 Nov 2023 22:42:37 -0600 Subject: [PATCH] Race Integrity QoL (#3445) * Add gDisableChangingSettings * Add support for dropping a config file to overwrite CVars --- .../controls/GameControlEditor.cpp | 2 + .../cosmetics/CosmeticsEditor.cpp | 2 + soh/soh/Enhancements/enhancementTypes.h | 5 ++ soh/soh/Enhancements/presets.h | 52 +++++++++++++- .../randomizer/3drando/playthrough.cpp | 6 ++ .../Enhancements/randomizer/randomizer.cpp | 72 ++++++++++--------- soh/soh/OTRGlobals.cpp | 71 ++++++++++++++++++ soh/soh/OTRGlobals.h | 1 + soh/soh/SohMenuBar.cpp | 12 ++++ soh/soh/util.cpp | 18 +++++ soh/soh/util.h | 2 + .../ovl_file_choose/z_file_choose.c | 12 +++- 12 files changed, 221 insertions(+), 34 deletions(-) diff --git a/soh/soh/Enhancements/controls/GameControlEditor.cpp b/soh/soh/Enhancements/controls/GameControlEditor.cpp index 935935c48..eb69f3cc8 100644 --- a/soh/soh/Enhancements/controls/GameControlEditor.cpp +++ b/soh/soh/Enhancements/controls/GameControlEditor.cpp @@ -312,6 +312,7 @@ namespace GameControlEditor { DrawHelpIcon("Allows the cursor on the pause menu to be over any slot. Sometimes required in rando to select " "certain items."); UIWidgets::Spacer(0); + ImGui::BeginDisabled(CVarGetInteger("gDisableChangingSettings", 0)); UIWidgets::PaddedEnhancementCheckbox("Enable walk speed modifiers", "gEnableWalkModify", true, false); DrawHelpIcon("Hold the assigned button to change the maximum walking speed\nTo change the assigned button, go into the Ports tabs above"); if (CVarGetInteger("gEnableWalkModify", 0)) { @@ -323,6 +324,7 @@ namespace GameControlEditor { UIWidgets::PaddedEnhancementSliderFloat("Modifier 2: %d %%", "##WalkMod2", "gWalkModifierTwo", 0.0f, 5.0f, "", 1.0f, true, true, false, true); window->EndGroupPanelPublic(0); } + ImGui::EndDisabled(); UIWidgets::Spacer(0); UIWidgets::PaddedEnhancementCheckbox("Answer Navi Prompt with L Button", "gNaviOnL"); DrawHelpIcon("Speak to Navi with L but enter first-person camera with C-Up"); diff --git a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp index 9c56ac32b..378197bcd 100644 --- a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp +++ b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp @@ -1485,6 +1485,7 @@ void Draw_Placements(){ } void DrawSillyTab() { + ImGui::BeginDisabled(CVarGetInteger("gDisableChangingSettings", 0)); if (CVarGetInteger("gLetItSnow", 0)) { if (UIWidgets::EnhancementCheckbox("Let It Snow", "gLetItSnow")) { LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); @@ -1569,6 +1570,7 @@ void DrawSillyTab() { CVarClear("gCosmetics.Kak_Windmill_Speed.Changed"); LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); } + ImGui::EndDisabled(); } // Copies the RGB values from one cosmetic option to another, multiplied by the passed in amount, this diff --git a/soh/soh/Enhancements/enhancementTypes.h b/soh/soh/Enhancements/enhancementTypes.h index 529ebed81..c8461bbf1 100644 --- a/soh/soh/Enhancements/enhancementTypes.h +++ b/soh/soh/Enhancements/enhancementTypes.h @@ -1,3 +1,6 @@ +#ifndef _ENHANCEMENT_TYPES_H_ +#define _ENHANCEMENT_TYPES_H_ + typedef enum { WARP_MODE_OVERRIDE_OFF, WARP_MODE_OVERRIDE_MQ_AS_VANILLA, @@ -74,3 +77,5 @@ typedef enum { DEKU_STICK_UNBREAKABLE, DEKU_STICK_UNBREAKABLE_AND_ALWAYS_ON_FIRE, } DekuStickType; + +#endif diff --git a/soh/soh/Enhancements/presets.h b/soh/soh/Enhancements/presets.h index f0f586e00..22c9dd7db 100644 --- a/soh/soh/Enhancements/presets.h +++ b/soh/soh/Enhancements/presets.h @@ -217,6 +217,31 @@ const std::vector enhancementsCvars = { "gFixTexturesOOB", "gIvanCoopModeEnabled", "gEnemySpawnsOverWaterboxes", + "gTreeStickDrops", + "gShadowTag", + "gRandomizedEnemySizes", + "gRandomizedEnemies", + "gMirroredWorldMode", + "gMirroredWorld", + "gHyperEnemies", + "gHookshotableReticle", + "gHideBunnyHood", + "gFixVineFall", + "gFileSelectMoreInfo", + "gEnemyHealthBar", + "gBushDropFix", + "gAllDogsRichard", + "gAddTraps.enabled", + "gAddTraps.Ammo", + "gAddTraps.Bomb", + "gAddTraps.Burn", + "gAddTraps.Ice", + "gAddTraps.Kill", + "gAddTraps.Knock", + "gAddTraps.Shock", + "gAddTraps.Speed", + "gAddTraps.Tele", + "gAddTraps.Void", }; const std::vector cheatCvars = { @@ -269,7 +294,23 @@ const std::vector cheatCvars = { "gNoRedeadFreeze", "gBombTimerMultiplier", "gNoFishDespawn", - "gNoBugsDespawn" + "gNoBugsDespawn", + "gWalkModifierDoesntChangeJump", + "gStatsEnabled", + "gSaveStatesEnabled", + "gSaveStatePromise", + "gRegEditEnabled", + "gPreset0", + "gPreset1", + "gDekuStickCheat", + "gDebugWarpScreenTranslation", + "gDebugSaveFileMode", + "gCosmetics.Link_BodyScale.Changed", + "gCosmetics.Link_BodyScale.Value", + "gCosmetics.Link_HeadScale.Changed", + "gCosmetics.Link_HeadScale.Value", + "gCosmetics.Link_SwordScale.Changed", + "gCosmetics.Link_SwordScale.Value", }; const std::vector randomizerCvars = { @@ -399,6 +440,15 @@ const std::vector randomizerCvars = { "gRandomizeGregHint", "gRandoManualSeedEntry", "gRandomizerSettingsEnabled", + "gRandomizeTriforceHuntTotalPieces", + "gRandomizeTriforceHuntRequiredPieces", + "gRandomizeTriforceHunt", + "gRandomizeShuffleMasterSword", + "gRandomizeSariaHint", + "gRandomizeRupeeNames", + "gRandomizeFrogsHint", + "gRandoRelevantNavi", + "gRandoQuestItemFanfares", }; const std::vector vanillaPlusPresetEntries = { diff --git a/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp b/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp index 088ba5067..62042246c 100644 --- a/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp @@ -1,5 +1,6 @@ #include "playthrough.hpp" +#include #include #include "custom_messages.hpp" #include "fill.hpp" @@ -8,6 +9,7 @@ #include "random.hpp" #include "spoiler_log.hpp" #include "soh/Enhancements/randomizer/randomizerTypes.h" +#include "variables.h" namespace Playthrough { @@ -39,6 +41,10 @@ int Playthrough_Init(uint32_t seed, std::unordered_map{}(std::to_string(Settings::seed) + settingsStr); Random_Init(finalHash); Settings::hash = std::to_string(finalHash); diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index b4964caf0..7f2613935 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -360,37 +360,35 @@ std::unordered_map SpoilerfileSettingNameToEn { "Shuffle Dungeon Quest:Ganon's Castle", RSK_MQ_GANONS_CASTLE }, }; -std::string sanitize(std::string stringValue) { - // Add backslashes. - for (auto i = stringValue.begin();;) { - auto const pos = std::find_if(i, stringValue.end(), [](char const c) { return '\\' == c || '\'' == c || '"' == c; }); - if (pos == stringValue.end()) { - break; - } - i = std::next(stringValue.insert(pos, '\\'), 2); - } - - // Removes others. - stringValue.erase(std::remove_if(stringValue.begin(), stringValue.end(), [](char const c) { - return '\n' == c || '\r' == c || '\0' == c || '\x1A' == c; }), stringValue.end()); - - return stringValue; -} - #pragma optimize("", off) #pragma GCC push_options #pragma GCC optimize ("O0") bool Randomizer::SpoilerFileExists(const char* spoilerFileName) { - if (strcmp(spoilerFileName, "") != 0) { - std::ifstream spoilerFileStream(sanitize(spoilerFileName)); - if (!spoilerFileStream) { - return false; - } else { + try { + if (strcmp(spoilerFileName, "") != 0) { + std::ifstream spoilerFileStream(SohUtils::Sanitize(spoilerFileName)); + if (!spoilerFileStream) { + return false; + } + + json spoilerFileJson; + spoilerFileStream >> spoilerFileJson; + + if (!spoilerFileJson.contains("version") || !spoilerFileJson.contains("finalSeed")) { + return false; + } + return true; } - } - return false; + return false; + } catch (std::exception& e) { + SPDLOG_ERROR("Error checking if spoiler file exists: {}", e.what()); + return false; + } catch (...) { + SPDLOG_ERROR("Error checking if spoiler file exists"); + return false; + } } #pragma GCC pop_options #pragma optimize("", on) @@ -659,7 +657,7 @@ void Randomizer::LoadMasterQuestDungeons(const char* spoilerFileName) { } void Randomizer::ParseRandomizerSettingsFile(const char* spoilerFileName) { - std::ifstream spoilerFileStream(sanitize(spoilerFileName)); + std::ifstream spoilerFileStream(SohUtils::Sanitize(spoilerFileName)); if (!spoilerFileStream) return; @@ -1293,7 +1291,7 @@ std::string FormatJsonHintText(std::string jsonHint) { } void Randomizer::ParseHintLocationsFile(const char* spoilerFileName) { - std::ifstream spoilerFileStream(sanitize(spoilerFileName)); + std::ifstream spoilerFileStream(SohUtils::Sanitize(spoilerFileName)); if (!spoilerFileStream) return; @@ -1394,7 +1392,7 @@ void Randomizer::ParseHintLocationsFile(const char* spoilerFileName) { } void Randomizer::ParseRequiredTrialsFile(const char* spoilerFileName) { - std::ifstream spoilerFileStream(sanitize(spoilerFileName)); + std::ifstream spoilerFileStream(SohUtils::Sanitize(spoilerFileName)); if (!spoilerFileStream) { return; } @@ -1415,7 +1413,7 @@ void Randomizer::ParseRequiredTrialsFile(const char* spoilerFileName) { } void Randomizer::ParseMasterQuestDungeonsFile(const char* spoilerFileName) { - std::ifstream spoilerFileStream(sanitize(spoilerFileName)); + std::ifstream spoilerFileStream(SohUtils::Sanitize(spoilerFileName)); if (!spoilerFileStream) { return; } @@ -1495,7 +1493,7 @@ int16_t Randomizer::GetVanillaMerchantPrice(RandomizerCheck check) { } void Randomizer::ParseItemLocationsFile(const char* spoilerFileName, bool silent) { - std::ifstream spoilerFileStream(sanitize(spoilerFileName)); + std::ifstream spoilerFileStream(SohUtils::Sanitize(spoilerFileName)); if (!spoilerFileStream) return; @@ -1558,7 +1556,7 @@ void Randomizer::ParseItemLocationsFile(const char* spoilerFileName, bool silent } void Randomizer::ParseEntranceDataFile(const char* spoilerFileName, bool silent) { - std::ifstream spoilerFileStream(sanitize(spoilerFileName)); + std::ifstream spoilerFileStream(SohUtils::Sanitize(spoilerFileName)); if (!spoilerFileStream) { return; } @@ -3144,7 +3142,9 @@ void RandomizerSettingsWindow::DrawElement() { UIWidgets::DisableComponent(ImGui::GetStyle().Alpha * 0.5f); } + ImGui::BeginDisabled(CVarGetInteger("gDisableChangingSettings", 0)); DrawPresetSelector(PRESET_TYPE_RANDOMIZER); + ImGui::EndDisabled(); UIWidgets::Spacer(0); UIWidgets::EnhancementCheckbox("Manual seed entry", "gRandoManualSeedEntry", false, ""); @@ -3167,13 +3167,17 @@ void RandomizerSettingsWindow::DrawElement() { } UIWidgets::Spacer(0); + ImGui::BeginDisabled(CVarGetInteger("gRandomizerDontGenerateSpoiler", 0) && gSaveContext.gameMode != GAMEMODE_FILE_SELECT); if (ImGui::Button("Generate Randomizer")) { GenerateRandomizer(CVarGetInteger("gRandoManualSeedEntry", 0) ? seedString : ""); } + ImGui::EndDisabled(); UIWidgets::Spacer(0); - std::string spoilerfilepath = CVarGetString("gSpoilerLog", ""); - ImGui::Text("Spoiler File: %s", spoilerfilepath.c_str()); + if (!CVarGetInteger("gRandomizerDontGenerateSpoiler", 0)) { + std::string spoilerfilepath = CVarGetString("gSpoilerLog", ""); + ImGui::Text("Spoiler File: %s", spoilerfilepath.c_str()); + } // RANDOTODO settings presets // std::string presetfilepath = CVarGetString("gLoadedPreset", ""); @@ -3181,6 +3185,8 @@ void RandomizerSettingsWindow::DrawElement() { UIWidgets::PaddedSeparator(); + ImGui::BeginDisabled(CVarGetInteger("gDisableChangingSettings", 0)); + ImGuiWindow* window = ImGui::GetCurrentWindow(); static ImVec2 cellPadding(8.0f, 8.0f); @@ -5225,6 +5231,8 @@ void RandomizerSettingsWindow::DrawElement() { ImGui::EndTabBar(); } + + ImGui::EndDisabled(); if (disableEditingRandoSettings) { UIWidgets::ReEnableComponent(""); diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 7587450b5..6372de060 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -49,6 +49,9 @@ #include "Fonts.h" #include #include "Enhancements/custom-message/CustomMessageManager.h" +#include "Enhancements/presets.h" +#include "util.h" +#include #if not defined (__SWITCH__) && not defined(__WIIU__) #include "Extractor/Extract.h" @@ -2573,3 +2576,71 @@ extern "C" void EntranceTracker_SetLastEntranceOverride(s16 entranceIndex) { extern "C" void Gfx_RegisterBlendedTexture(const char* name, u8* mask, u8* replacement) { gfx_register_blended_texture(name, mask, replacement); } + +// #region SOH [TODO] Ideally this should move to being event based, it's currently run every frame on the file select screen +extern "C" void SoH_ProcessDroppedFiles() { + const char* droppedFile = CVarGetString("gDroppedFile", ""); + if (CVarGetInteger("gNewFileDropped", 0) && strcmp(droppedFile, "") != 0) { + try { + std::ifstream configStream(SohUtils::Sanitize(droppedFile)); + if (!configStream) { + return; + } + + nlohmann::json configJson; + configStream >> configJson; + + if (!configJson.contains("CVars")) { + return; + } + + clearCvars(enhancementsCvars); + clearCvars(cheatCvars); + clearCvars(randomizerCvars); + + // Flatten everything under CVars into a single array + auto cvars = configJson["CVars"].flatten(); + + for (auto& [key, value] : cvars.items()) { + // Replace slashes with dots in key, and remove leading dot + std::string path = key; + std::replace(path.begin(), path.end(), '/', '.'); + if (path[0] == '.') { + path.erase(0, 1); + } + if (value.is_string()) { + CVarSetString(path.c_str(), value.get().c_str()); + } else if (value.is_number_integer()) { + CVarSetInteger(path.c_str(), value.get()); + } else if (value.is_number_float()) { + CVarSetFloat(path.c_str(), value.get()); + } + } + + auto gui = LUS::Context::GetInstance()->GetWindow()->GetGui(); + gui->GetGuiWindow("Console")->Hide(); + gui->GetGuiWindow("Actor Viewer")->Hide(); + gui->GetGuiWindow("Collision Viewer")->Hide(); + gui->GetGuiWindow("Save Editor")->Hide(); + gui->GetGuiWindow("Display List Viewer")->Hide(); + gui->GetGuiWindow("Stats")->Hide(); + std::dynamic_pointer_cast(LUS::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Console"))->ClearBindings(); + + gui->SaveConsoleVariablesOnNextTick(); + + uint32_t finalHash = boost::hash_32{}(configJson.dump()); + gui->GetGameOverlay()->TextDrawNotification(30.0f, true, "Configuration Loaded. Hash: %d", finalHash); + } catch (std::exception& e) { + SPDLOG_ERROR("Failed to load config file: {}", e.what()); + auto gui = LUS::Context::GetInstance()->GetWindow()->GetGui(); + gui->GetGameOverlay()->TextDrawNotification(30.0f, true, "Failed to load config file"); + return; + } catch (...) { + SPDLOG_ERROR("Failed to load config file"); + auto gui = LUS::Context::GetInstance()->GetWindow()->GetGui(); + gui->GetGameOverlay()->TextDrawNotification(30.0f, true, "Failed to load config file"); + return; + } + } +} +// #endregion diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h index 9b42e6895..88c57ced3 100644 --- a/soh/soh/OTRGlobals.h +++ b/soh/soh/OTRGlobals.h @@ -175,6 +175,7 @@ void EntranceTracker_SetLastEntranceOverride(s16 entranceIndex); void Gfx_RegisterBlendedTexture(const char* name, u8* mask, u8* replacement); void SaveManager_ThreadPoolWait(); void CheckTracker_OnMessageClose(); +void SoH_ProcessDroppedFiles(); int32_t GetGIID(uint32_t itemID); #endif diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index 006d5b4dc..65ee180bb 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -492,6 +492,8 @@ extern std::shared_ptr mGameplayStatsWindow; void DrawEnhancementsMenu() { if (ImGui::BeginMenu("Enhancements")) { + ImGui::BeginDisabled(CVarGetInteger("gDisableChangingSettings", 0)); + DrawPresetSelector(PRESET_TYPE_ENHANCEMENTS); UIWidgets::PaddedSeparator(); @@ -1199,6 +1201,8 @@ void DrawEnhancementsMenu() { UIWidgets::PaddedSeparator(true, true, 2.0f, 2.0f); + ImGui::EndDisabled(); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(12.0f, 6.0f)); ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0, 0)); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f); @@ -1240,6 +1244,8 @@ void DrawEnhancementsMenu() { void DrawCheatsMenu() { if (ImGui::BeginMenu("Cheats")) { + ImGui::BeginDisabled(CVarGetInteger("gDisableChangingSettings", 0)); + if (ImGui::BeginMenu("Infinite...")) { UIWidgets::EnhancementCheckbox("Money", "gInfiniteMoney"); UIWidgets::PaddedEnhancementCheckbox("Health", "gInfiniteHealth", true, false); @@ -1394,6 +1400,8 @@ void DrawCheatsMenu() { } UIWidgets::Tooltip("Clears the cutscene pointer to a value safe for wrong warps."); + ImGui::EndDisabled(); + ImGui::EndMenu(); } } @@ -1407,6 +1415,8 @@ extern std::shared_ptr mDLViewerWindow; void DrawDeveloperToolsMenu() { if (ImGui::BeginMenu("Developer Tools")) { + ImGui::BeginDisabled(CVarGetInteger("gDisableChangingSettings", 0)); + UIWidgets::EnhancementCheckbox("OoT Debug Mode", "gDebugEnabled"); UIWidgets::Tooltip("Enables Debug Mode, allowing you to select maps with L + R + Z, noclip with L + D-pad Right, and open the debug menu with L on the pause screen"); if (CVarGetInteger("gDebugEnabled", 0)) { @@ -1479,6 +1489,8 @@ void DrawDeveloperToolsMenu() { ImGui::PopStyleVar(3); ImGui::PopStyleColor(1); + ImGui::EndDisabled(); + ImGui::EndMenu(); } } diff --git a/soh/soh/util.cpp b/soh/soh/util.cpp index 62e1d2dce..856432cbb 100644 --- a/soh/soh/util.cpp +++ b/soh/soh/util.cpp @@ -2,6 +2,7 @@ #include #include +#include std::vector sceneNames = { "Inside the Deku Tree", @@ -318,3 +319,20 @@ void SohUtils::CopyStringToCharArray(char* destination, std::string source, size strncpy(destination, source.c_str(), size - 1); destination[size - 1] = '\0'; } + +std::string SohUtils::Sanitize(std::string stringValue) { + // Add backslashes. + for (auto i = stringValue.begin();;) { + auto const pos = std::find_if(i, stringValue.end(), [](char const c) { return '\\' == c || '\'' == c || '"' == c; }); + if (pos == stringValue.end()) { + break; + } + i = std::next(stringValue.insert(pos, '\\'), 2); + } + + // Removes others. + stringValue.erase(std::remove_if(stringValue.begin(), stringValue.end(), [](char const c) { + return '\n' == c || '\r' == c || '\0' == c || '\x1A' == c; }), stringValue.end()); + + return stringValue; +} diff --git a/soh/soh/util.h b/soh/soh/util.h index bdbfcd777..db5af8636 100644 --- a/soh/soh/util.h +++ b/soh/soh/util.h @@ -12,4 +12,6 @@ namespace SohUtils { // Copies a string and ensures the destination is null terminated if the source string is larger than size // Only up to size-1 characters are copied from the source string void CopyStringToCharArray(char* destination, std::string source, size_t size); + + std::string Sanitize(std::string stringValue); } // namespace SohUtils 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 9c83f9322..9e6150593 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 @@ -1,6 +1,7 @@ #include "file_choose.h" #include +#include #include "textures/title_static/title_static.h" #include "textures/parameter_static/parameter_static.h" @@ -1024,7 +1025,7 @@ void FileChoose_UpdateRandomizer() { return; } - if (!SpoilerFileExists(CVarGetString("gSpoilerLog", ""))) { + if (!SpoilerFileExists(CVarGetString("gSpoilerLog", "")) && !CVarGetInteger("gRandomizerDontGenerateSpoiler", 0)) { CVarSetString("gSpoilerLog", ""); fileSelectSpoilerFileLoaded = false; } @@ -1051,6 +1052,10 @@ void FileChoose_UpdateRandomizer() { Randomizer_LoadMasterQuestDungeons(fileLoc); Randomizer_LoadEntranceOverrides(fileLoc, silent); fileSelectSpoilerFileLoaded = true; + + if (SpoilerFileExists(CVarGetString("gSpoilerLog", "")) && CVarGetInteger("gRandomizerDontGenerateSpoiler", 0)) { + remove(fileLoc); + } } } @@ -1071,6 +1076,7 @@ void FileChoose_UpdateMainMenu(GameState* thisx) { Input* input = &this->state.input[0]; bool dpad = CVarGetInteger("gDpadText", 0); + SoH_ProcessDroppedFiles(); FileChoose_UpdateRandomizer(); if (CHECK_BTN_ALL(input->press.button, BTN_START) || CHECK_BTN_ALL(input->press.button, BTN_A)) { @@ -1261,6 +1267,7 @@ void FileChoose_UpdateQuestMenu(GameState* thisx) { s8 i = 0; bool dpad = CVarGetInteger("gDpadText", 0); + SoH_ProcessDroppedFiles(); FileChoose_UpdateRandomizer(); if (ABS(this->stickRelX) > 30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DLEFT | BTN_DRIGHT))) { @@ -3686,4 +3693,7 @@ void FileChoose_Init(GameState* thisx) { Font_LoadOrderedFont(&this->font); Audio_QueueSeqCmd(0xF << 28 | SEQ_PLAYER_BGM_MAIN << 24 | 0xA); func_800F5E18(SEQ_PLAYER_BGM_MAIN, NA_BGM_FILE_SELECT, 0, 7, 1); + + // Originally this was only set when transitioning from the title screen, but gSkipLogoTitle skips that process so we're ensuring it's set here + gSaveContext.gameMode = GAMEMODE_FILE_SELECT; }