Remove FQwc preset. Skip learning song

Also render exempt settings on preset selection, with values they'll have in-game
This commit is contained in:
Philip Dubé
2026-10-05 23:38:48 +00:00
committed by GitHub
parent 0ce4c0fccd
commit 3d8cd5aa88
3 changed files with 66 additions and 140 deletions
@@ -18,6 +18,7 @@
"Autosave": 0,
"BetterAmmoRendering": 0,
"BetterFarore": 0,
"BetterOwl": 1,
"BombchuBowlingFirstPrize": 4,
"BombchusOOB": 1,
"BowArrowCycle": 1,
@@ -42,7 +43,9 @@
"EquipmentCanBeRemoved": 0,
"FastBoomerang": 0,
"FastChests": 1,
"FasterHeavyBlockLift": 1,
"FasterPauseMenu": 0,
"FasterShadowShip": 1,
"FileSelectMoreInfo": 1,
"FirstPersonGauntlets": 0,
"FishNeverEscape": 1,
@@ -88,18 +91,19 @@
"ShowDoorLocksOnBothSides": 0,
"SkipArrowAnimation": 1,
"SkipText": 1,
"SkulltulaFreeze": 1,
"SlowTextSpeed": 5,
"StaticExplosionRadius": 0,
"StrengthDisabled": 0,
"SwordToggle": 0,
"TextSpeed": 5,
"TextSpeed": 6,
"TimeFlowFileSelect": 0,
"TimeSavers": {
"SkipCutscene": {
"BossIntro": 1,
"Entrances": 1,
"Intro": 1,
"LearnSong": 0,
"LearnSong": 1,
"OnePoint": 0,
"QuickBossDeaths": 1,
"Story": 1
@@ -118,6 +122,8 @@
"exempt": [
"/gDeveloperTools/LogLevel",
"/gDeveloperTools/ResourceLogging",
"/gEnhancements/AskToEquip",
"/gEnhancements/BetterSaveMenu",
"/gEnhancements/DrawLineupTick",
"/gEnhancements/GraveHoles",
"/gEnhancements/IncludeHeldInputsBufferWindow",
@@ -1,123 +0,0 @@
{
"blocks": {
"enhancements": {
"gCheats": {
"EasyFrameAdvance": 0,
"HookshotReachMultiplier": 1.0,
"MoonJumpOnL": 0,
"SpeedModifier": {
"Value": 1.0
}
},
"gDeveloperTools": null,
"gEnhancements": {
"3DSceneRender": 0,
"AlwaysShowDungeonMinimapIcon": 0,
"AskToEquip": 0,
"AssignableTunicsAndBoots": 0,
"Autosave": 0,
"BetterAmmoRendering": 0,
"BetterFarore": 0,
"BombchuBowlingFirstPrize": 4,
"BombchusOOB": 1,
"BowArrowCycle": 1,
"ChildHookshotSoftlock": 1,
"CustomizeBombchuBowling": 1,
"CustomizeFishing": 1,
"CustomizeOcarinaGame": 0,
"DampeWin": 1,
"DisableBlackBars": 0,
"DisableBombBillboarding": 0,
"DisableCritWiggle": 1,
"DisableFixedCamera": 0,
"DisableGrottoRotation": 0,
"DisableLOD": 1,
"DisableLinkSwordTrail": 0,
"DpadEquips": 1,
"DpadNoDropOcarinaInput": 1,
"DrawLineupTick": 0,
"DynamicWalletIcon": 1,
"EarlyEyeballFrog": 1,
"EquipmentAlwaysVisible": 0,
"EquipmentCanBeRemoved": 0,
"FastBoomerang": 0,
"FastChests": 1,
"FasterPauseMenu": 0,
"FileSelectMoreInfo": 1,
"FirstPersonGauntlets": 0,
"FishNeverEscape": 1,
"FixDampeGoingBackwards": 0,
"FixDaruniaDanceSpeed": 1,
"FixDungeonMinimapIcon": 1,
"FixSawSoftlock": 1,
"FixVineFall": 1,
"ForgeTime": 1,
"GravediggingTourFix": 1,
"HoverFishing": 1,
"HyperBosses": 0,
"HyperEnemies": 0,
"IncludeHeldInputsBufferWindow": 0,
"InjectItemCounts": {
"GoldSkulltula": 1,
"HeartContainer": 1,
"HeartPiece": 1
},
"ItemUnequip": 0,
"MinimalUI": 0,
"MweepSpeed": 5.0,
"N64WeirdFrames": 1,
"NewDrops": 0,
"NoHUDHeartAnimation": 0,
"NoInputForCredits": 1,
"OcarinaGame": {
"StartingNotes": 8
},
"PauseAnyCursor": 2,
"PauseBufferWindow": 5,
"PauseMenuAnimatedLink": 0,
"QuickBongoKill": 1,
"QuickPutaway": 1,
"QuitFishingAtDoor": 1,
"RedGanonBlood": 1,
"RememberMapToggleState": 0,
"ReworkedTargeting": {
"Enabled": 0
},
"ScaleAdultEquipmentAsChild": 1,
"SceneSpecificDirtPathFix": 1,
"ShowDoorLocksOnBothSides": 0,
"SkipArrowAnimation": 1,
"SkipText": 1,
"SlowTextSpeed": 5,
"StaticExplosionRadius": 0,
"StrengthDisabled": 0,
"SwordToggle": 0,
"TextSpeed": 5,
"TimeFlowFileSelect": 0,
"TimeSavers": {
"SkipCutscene": {
"Intro": 1,
"QuickBossDeaths": 1
}
},
"ToTMedallionsColors": 0,
"ToggleStrength": 0,
"VisualAgony": 0,
"WideShutterDoorRange": 1
},
"gRandoEnhancements": null
}
},
"exempt": [
"/gDeveloperTools/LogLevel",
"/gDeveloperTools/ResourceLogging",
"/gEnhancements/DrawLineupTick",
"/gEnhancements/GraveHoles",
"/gEnhancements/IncludeHeldInputsBufferWindow",
"/gEnhancements/PauseBufferWindow"
],
"fileType": 2,
"presetName": "Speedrun - 3 Faster Quest with Cutscenes",
"isBuiltIn": true,
"ConfigVersion": 7
}
+58 -15
View File
@@ -47,7 +47,8 @@ static const std::array<const char*, 4> sOwnedBlocks = {
};
#define SPEEDRUN_PRESET_NONE "None"
#define SPEEDRUN_MAX_OPTIONS_ON_SCREEN 6
#define SPEEDRUN_MAX_OPTIONS_ON_SCREEN 4
#define SPEEDRUN_EXEMPT_ROWS 4
// {display name, preset name}, ending with "None" which has no preset.
static std::vector<std::pair<std::string, std::string>> sPresetChoices;
@@ -59,6 +60,9 @@ static nlohmann::json sExempt = nlohmann::json::array();
static std::string sPresetName = SPEEDRUN_PRESET_NONE;
static uint32_t sSettingsHash = 0;
static bool sMenuLocked = false;
// "Name: value" of each exempt setting for the preset picked in the menu, and which preset they were made for.
static std::vector<std::string> sExemptLines;
static int sExemptLinesIndex = -1;
// Everything else, menu included, is hidden so settings can't be changed mid-run.
static const std::vector<std::string> sAllowedWindows = {
@@ -104,10 +108,10 @@ static void SetOwnedBlocks(const nlohmann::json& blocks) {
ShipInit::InitAll();
}
static std::vector<nlohmann::json::json_pointer> GetExemptPaths() {
static std::vector<nlohmann::json::json_pointer> GetExemptPaths(const nlohmann::json& exempt) {
std::vector<nlohmann::json::json_pointer> paths;
for (const auto& path : sExempt) {
for (const auto& path : exempt) {
try {
paths.emplace_back(path.get<std::string>());
} catch (const std::exception& e) { SPDLOG_ERROR("Speedrun: bad exempt path {}: {}", path.dump(), e.what()); }
@@ -117,8 +121,8 @@ static std::vector<nlohmann::json::json_pointer> GetExemptPaths() {
}
// Copies the player's exempt settings onto blocks. Ones the player never set keep the preset's value.
static void OverlayExemptSettings(nlohmann::json& blocks, const nlohmann::json& custom) {
for (const auto& path : GetExemptPaths()) {
static void OverlayExemptSettings(nlohmann::json& blocks, const nlohmann::json& custom, const nlohmann::json& exempt) {
for (const auto& path : GetExemptPaths(exempt)) {
if (custom.contains(path)) {
blocks[path] = custom[path];
}
@@ -253,7 +257,7 @@ extern "C" bool Ship_QuestDebugEnabled(u8 questId) {
// same build and settings. nlohmann sorts object keys, so the dump is stable.
static uint32_t HashSettings() {
nlohmann::json stripped = sSettings;
for (const auto& path : GetExemptPaths()) {
for (const auto& path : GetExemptPaths(sExempt)) {
if (stripped.contains(path)) {
stripped[path.parent_pointer()].erase(path.back());
}
@@ -279,6 +283,41 @@ static void EmitHashNotification() {
});
}
// The settings a new file gets with this preset: the player's settings, then the preset, then the exempt ones put back.
static nlohmann::json BuildFileSettings(const std::string& presetKey, const nlohmann::json& custom,
const nlohmann::json& exempt) {
nlohmann::json settings = custom;
if (!presetKey.empty()) {
// Applied to the file's copy only, never the player's config.
settings = applyPresetToBlocks(presetKey, settings, { PRESET_SECTION_ENHANCEMENTS });
}
OverlayExemptSettings(settings, custom, exempt);
return settings;
}
static void UpdateExemptLines(uint8_t presetIndex) {
if (sExemptLinesIndex == presetIndex) {
return;
}
sExemptLinesIndex = presetIndex;
sExemptLines.clear();
const std::string& presetKey = sPresetChoices[presetIndex].second;
nlohmann::json exempt = GetPresetExempt(presetKey);
nlohmann::json settings = BuildFileSettings(presetKey, GetOwnedBlocks(), exempt);
for (const auto& path : GetExemptPaths(exempt)) {
std::string value = "default";
if (settings.contains(path)) {
const auto& entry = settings[path];
value = entry.is_string() ? entry.get<std::string>() : entry.dump();
}
sExemptLines.push_back(spdlog::fmt_lib::format("{}: {}", path.back(), value));
}
}
extern "C" void Speedrun_LoadPresetChoices(FileChooseContext* fileChooseContext) {
// "None" keeps the player's current settings.
sPresetChoices = GetSpeedrunPresets();
@@ -287,6 +326,8 @@ extern "C" void Speedrun_LoadPresetChoices(FileChooseContext* fileChooseContext)
fileChooseContext->speedrunIndex = 0;
fileChooseContext->speedrunOffset = 0;
}
// Player may have changed settings since the menu was last open.
sExemptLinesIndex = -1;
}
extern "C" void FileChoose_UpdateSpeedrunMenu(GameState* gameState) {
@@ -335,6 +376,15 @@ extern "C" void FileChoose_DrawSpeedrunMenuWindowContents(FileChooseContext* fil
static_cast<f32>(92 + textYOffset), false);
}
}
// Exempt settings of the selected preset, with the values the new file will get, in columns under the list.
UpdateExemptLines(fileChooseContext->speedrunIndex);
for (size_t i = 0; i < sExemptLines.size(); i++) {
int16_t x = 65 + (int16_t)(i / SPEEDRUN_EXEMPT_ROWS) * 100;
int16_t y = 87 + SPEEDRUN_MAX_OPTIONS_ON_SCREEN * 16 + (int16_t)(i % SPEEDRUN_EXEMPT_ROWS) * 7;
Interface_DrawTextLine(fileChooseContext->state.gfxCtx, (char*)sExemptLines[i].c_str(), x, y, 180, 180, 180,
textAlpha, 0.5f, false);
}
}
extern "C" void Speedrun_InitSaveFile(u8 presetIndex) {
@@ -342,16 +392,9 @@ extern "C" void Speedrun_InitSaveFile(u8 presetIndex) {
sPresetName = sPresetChoices[presetIndex].first;
nlohmann::json custom = GetOwnedBlocks();
sSettings = custom;
sConfigVersion = SOH::GetLatestConfigVersion();
sExempt = GetPresetExempt(presetKey);
if (!presetKey.empty()) {
// Applied to the file's copy only, never the player's config.
sSettings = applyPresetToBlocks(presetKey, sSettings, { PRESET_SECTION_ENHANCEMENTS });
}
OverlayExemptSettings(sSettings, custom);
sSettings = BuildFileSettings(presetKey, custom, sExempt);
// Runs are always timed in real time, whatever the "RTA Timing on new files" option says.
gSaveContext.ship.stats.rtaTiming = 1;
@@ -416,7 +459,7 @@ static void LoadSaveSection() {
blocks = GetOwnedBlocks();
}
OverlayExemptSettings(blocks, custom);
OverlayExemptSettings(blocks, custom, sExempt);
// No cosmetics during a run. Some scale Link or his sword, which changes his hitbox and reach.
blocks[CVAR_PREFIX_COSMETIC] = nlohmann::json::object();