From c9d24f2e9835048bafd64f5cd7586f7d0e713a05 Mon Sep 17 00:00:00 2001 From: Adam Bird Date: Thu, 1 Jun 2023 22:00:45 -0400 Subject: [PATCH] Fix: Better debug warp MQ detection and other warp menu bugs (#2932) * fix: add mq detection to better debug warp * replace special characters for debug warp translations * reorder better debug warp printing * adjust french translation --- soh/include/z64.h | 3 + soh/soh/OTRGlobals.cpp | 16 +- soh/soh/OTRGlobals.h | 1 + soh/src/code/z_play.c | 2 +- .../overlays/gamestates/ovl_select/z_select.c | 154 +++++++++++++----- 5 files changed, 128 insertions(+), 48 deletions(-) diff --git a/soh/include/z64.h b/soh/include/z64.h index a04dda12b..aa7b98eb5 100644 --- a/soh/include/z64.h +++ b/soh/include/z64.h @@ -1293,9 +1293,12 @@ typedef struct SelectContext { /* 0x0230 */ s32 lockDown; /* 0x0234 */ s32 unk_234; // unused /* 0x0238 */ u8* staticSegment; + // #region SOH [General] /* */ s32 currentEntrance; + /* */ u8 isBetterWarp; /* */ BetterSceneSelectEntry* betterScenes; /* */ BetterSceneSelectGrottoData* betterGrottos; + // #endregion } SelectContext; // size = 0x240 typedef struct { diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index ce9fb75bc..fa1824014 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -1028,9 +1028,9 @@ extern "C" uint32_t ResourceMgr_GetGameVersion(int index) { uint32_t IsSceneMasterQuest(s16 sceneNum) { uint32_t value = 0; uint8_t mqMode = CVarGetInteger("gBetterDebugWarpScreenMQMode", 0); - if (mqMode == 1) { //non-mq wants to be mq + if (mqMode == 1) { // non-mq wants to be mq return 1; - } else if (mqMode == 2) {//mq wants to be non-mq + } else if (mqMode == 2) { // mq wants to be non-mq return 0; } else { if (OTRGlobals::Instance->HasMasterQuest()) { @@ -1038,18 +1038,16 @@ uint32_t IsSceneMasterQuest(s16 sceneNum) { value = 1; } else if (gSaveContext.isMasterQuest) { value = 1; - } } else { value = 0; - if (gSaveContext.n64ddFlag) { - if (!OTRGlobals::Instance->gRandomizer->masterQuestDungeons.empty()) { - if (gPlayState != NULL && OTRGlobals::Instance->gRandomizer->masterQuestDungeons.contains(sceneNum)) { - value = 1; - } - } + if (gSaveContext.n64ddFlag && + !OTRGlobals::Instance->gRandomizer->masterQuestDungeons.empty() && + OTRGlobals::Instance->gRandomizer->masterQuestDungeons.contains(sceneNum)) { + value = 1; } } } + } return value; } diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h index 013831f70..ea2a2b5a8 100644 --- a/soh/soh/OTRGlobals.h +++ b/soh/soh/OTRGlobals.h @@ -54,6 +54,7 @@ void OTRGetPixelDepthPrepare(float x, float y); uint16_t OTRGetPixelDepth(float x, float y); int32_t OTRGetLastScancode(); uint32_t ResourceMgr_IsGameMasterQuest(); +uint32_t ResourceMgr_IsSceneMasterQuest(s16 sceneNum); uint32_t ResourceMgr_GameHasMasterQuest(); uint32_t ResourceMgr_GameHasOriginal(); uint32_t ResourceMgr_GetNumGameVersions(); diff --git a/soh/src/code/z_play.c b/soh/src/code/z_play.c index f4d0cdbe6..032191795 100644 --- a/soh/src/code/z_play.c +++ b/soh/src/code/z_play.c @@ -1925,7 +1925,7 @@ void Play_SpawnScene(PlayState* play, s32 sceneNum, s32 spawn) { Entrance_OverrideSpawnScene(sceneNum, spawn); } - CVarSetInteger("gBetterDebugWarpScreenMQMode", 0); + CVarClear("gBetterDebugWarpScreenMQMode"); } void func_800C016C(PlayState* play, Vec3f* src, Vec3f* dest) { diff --git a/soh/src/overlays/gamestates/ovl_select/z_select.c b/soh/src/overlays/gamestates/ovl_select/z_select.c index 0aac215d7..46a474849 100644 --- a/soh/src/overlays/gamestates/ovl_select/z_select.c +++ b/soh/src/overlays/gamestates/ovl_select/z_select.c @@ -11,6 +11,8 @@ #include "soh/Enhancements/randomizer/randomizer_entrance.h" +void Select_SwitchBetterWarpMode(SelectContext* this, u8 isBetterWarpMode); + void Select_LoadTitle(SelectContext* this) { this->state.running = false; SET_NEXT_GAMESTATE(&this->state, Title_Init, TitleContext); @@ -40,21 +42,24 @@ void Select_LoadGame(SelectContext* this, s32 entranceIndex) { Grotto_OverrideSpecialEntrance(Entrance_GetOverride(entranceIndex)); } - if (ResourceMgr_GameHasMasterQuest() && ResourceMgr_GameHasOriginal()) { - //check to see if the scene/entrance we just picked can be MQ'd - u8 isMQScene = this->betterScenes[this->currentScene].entrancePairs[this->pageDownIndex].canBeMQ; - if ((!gSaveContext.isMasterQuest && this->opt) && isMQScene) { - CVarSetInteger("gBetterDebugWarpScreenMQMode", 1); - } else if ((gSaveContext.isMasterQuest && !this->opt) && isMQScene) { - CVarSetInteger("gBetterDebugWarpScreenMQMode", 2); - } - }; - - if (CVarGetInteger("gBetterDebugWarpScreen", 0)) { + if (this->isBetterWarp) { CVarSetInteger("gBetterDebugWarpScreenCurrentScene", this->currentScene); CVarSetInteger("gBetterDebugWarpScreenTopDisplayedScene", this->topDisplayedScene); CVarSetInteger("gBetterDebugWarpScreenPageDownIndex", this->pageDownIndex); CVarSave(); + + if (ResourceMgr_GameHasMasterQuest() && ResourceMgr_GameHasOriginal()) { + BetterSceneSelectEntrancePair entrancePair = this->betterScenes[this->currentScene].entrancePairs[this->pageDownIndex]; + // Check to see if the scene/entrance we just picked can be MQ'd + if (entrancePair.canBeMQ) { + u8 isEntranceDefaultMQ = ResourceMgr_IsSceneMasterQuest(gEntranceTable[entrancePair.entranceIndex].scene); + if (!isEntranceDefaultMQ && this->opt) { + CVarSetInteger("gBetterDebugWarpScreenMQMode", 1); // Force vanilla for default MQ scene + } else if (isEntranceDefaultMQ && !this->opt) { + CVarSetInteger("gBetterDebugWarpScreenMQMode", 2); // Force MQ for default vanilla scene + } + } + } } gSaveContext.respawnFlag = 0; @@ -100,7 +105,7 @@ void Select_Grotto_LoadGame(SelectContext* this, s32 grottoIndex) { Grotto_OverrideSpecialEntrance(Entrance_GetOverride(grottoEntrance)); } - if (CVarGetInteger("gBetterDebugWarpScreen", 0)) { + if (this->isBetterWarp) { CVarSetInteger("gBetterDebugWarpScreenCurrentScene", this->currentScene); CVarSetInteger("gBetterDebugWarpScreenTopDisplayedScene", this->topDisplayedScene); CVarSetInteger("gBetterDebugWarpScreenPageDownIndex", this->pageDownIndex); @@ -462,7 +467,7 @@ static BetterSceneSelectEntry sBetterScenes[] = { { "From Gerudo Fortress", "Von der Gerudo-Festung", "Depuis la Forteresse Gerudo", 0x022D, 0 }, { "From Carpenter's Tent", "Vom Zelt der Zimmerleute", "Depuis la Tente du Charpentier", 0x03D0, 0 }, { "Carpenter's Tent/ Running Man Minigame", "Zelt der Zimmerleute/ Rennlaeufer Minispiel", "Tente du Charpentier/ Marathonien", 0x03A0, 0 }, - { "Thrown out of Fortress", "Aus der Festung geworfen", "Expulsé de la Forteresse", 0x01A5, 0 }, + { "Thrown out of Fortress", "Aus der Festung geworfen", "Expulse de la Forteresse", 0x01A5, 0 }, }}, { "28:Gerudo Fortress", "28:Gerudo-Festung", "28:Forteresse Gerudo", Select_LoadGame, 18, { { "From Gerudo Valley", "Vom Gerudotal", "Depuis la Vallee Gerudo", 0x0129, 0 }, @@ -632,8 +637,8 @@ static BetterSceneSelectEntry sBetterScenes[] = { { "Spider Grotto (Hyrule Castle)", "Spinnen-Grotte (Schloss Hyrule)", "Grotte Araignee (Chateau d'Hyrule)", 0x17, 0 }, { "Cow Grotto (Hyrule Field)", "Kuh-Grotte (Hylianische Steppe)", "Grotte a Vache (Plaine d'Hyrule)", 0x18, 0 }, { "Cow Grotto (Death Mountain Trail)", "Kuh-Grotte (Gebirgspfad)", "Grotte a Vache (Chemin du Peril)", 0x19, 0 }, - { "Flooded Grotto (Gerudo Valley)", "Geflutete Grotte (Gerudotal)", "Grotte Inondée (Vallee Gerudo)", 0x1A, 0 }, - { "Flooded Grotto (Hyrule Field)", "Geflutete Grotte (Hylianische Steppe)", "Grotte Inondée (Plaine d'Hyrule)", 0x1B, 0 }, + { "Flooded Grotto (Gerudo Valley)", "Geflutete Grotte (Gerudotal)", "Grotte Inondee (Vallee Gerudo)", 0x1A, 0 }, + { "Flooded Grotto (Hyrule Field)", "Geflutete Grotte (Hylianische Steppe)", "Grotte Inondee (Plaine d'Hyrule)", 0x1B, 0 }, }}, { "50:Debug (Use with caution)", "50:Debug (Mit Vorsicht benutzen)", "50:Debug (A utiliser avec prudence)", Select_LoadGame, 10, { { "Test Room", "Test Raum", "Salle de Test", 0x0520, 0 }, @@ -885,6 +890,7 @@ void Better_Select_UpdateMenu(SelectContext* this) { Input* input = &this->state.input[0]; s32 pad; BetterSceneSelectEntry* selectedScene; + uint8_t sceneChanged = 0; if (this->verticalInputAccumulator == 0) { if (CHECK_BTN_ALL(input->press.button, BTN_A) || CHECK_BTN_ALL(input->press.button, BTN_START)) { @@ -917,8 +923,9 @@ void Better_Select_UpdateMenu(SelectContext* this) { } if (CHECK_BTN_ALL(input->press.button, BTN_L)) { - //Hijacking opt as the "MQ" option for better select. Only change opt/play sound if displayed - if (this->betterScenes[this->currentScene].entrancePairs[this->pageDownIndex].canBeMQ) { + // Hijacking opt as the "MQ" option for better select. Only change opt/play sound if displayed + if (ResourceMgr_GameHasMasterQuest() && ResourceMgr_GameHasOriginal() && + this->betterScenes[this->currentScene].entrancePairs[this->pageDownIndex].canBeMQ) { this->opt = this->opt ? 0 : 1; if (this->opt) { Audio_PlaySoundGeneral(NA_SE_IT_SWORD_PICKOUT, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); @@ -981,6 +988,7 @@ void Better_Select_UpdateMenu(SelectContext* this) { this->verticalInputAccumulator += this->verticalInput; if (this->verticalInputAccumulator < -7) { + sceneChanged = 1; this->verticalInput = 0; this->verticalInputAccumulator = 0; @@ -995,6 +1003,7 @@ void Better_Select_UpdateMenu(SelectContext* this) { } if (this->verticalInputAccumulator > 7) { + sceneChanged = 1; this->verticalInput = 0; this->verticalInputAccumulator = 0; @@ -1013,13 +1022,19 @@ void Better_Select_UpdateMenu(SelectContext* this) { } } + if (sceneChanged) { + BetterSceneSelectEntrancePair entrancePair = this->betterScenes[this->currentScene].entrancePairs[this->pageDownIndex]; + // Update the MQ status to match the new scene + if (entrancePair.canBeMQ && ResourceMgr_IsSceneMasterQuest(gEntranceTable[entrancePair.entranceIndex].scene)) { + this->opt = 1; + } else { + this->opt = 0; + } + } + this->currentScene = (this->currentScene + this->count) % this->count; this->topDisplayedScene = (this->topDisplayedScene + this->count) % this->count; - dREG(80) = this->currentScene; - dREG(81) = this->topDisplayedScene; - dREG(82) = this->pageDownIndex; - if (this->timerUp != 0) { this->timerUp--; } @@ -1159,7 +1174,7 @@ void Better_Select_PrintMenu(SelectContext* this, GfxPrint* printer) { static SceneSelectLoadingMessages sLoadingMessages[] = { { GFXP_HIRAGANA "シバラクオマチクダサイ", "Please wait a minute", "Bitte warte eine Minute", "Veuillez patienter une minute" }, - { GFXP_HIRAGANA "チョット マッテネ", "Hold on a sec", "Warte mal 'ne Sekunde" "Une seconde, ça arrive" }, + { GFXP_HIRAGANA "チョット マッテネ", "Hold on a sec", "Warte mal 'ne Sekunde" "Une seconde, ca arrive" }, { GFXP_KATAKANA "ウェイト ア モーメント", "Wait a moment", "Warte einen Moment", "Patientez un instant" }, { GFXP_KATAKANA "ロード" GFXP_HIRAGANA "チュウ", "Loading", "Ladevorgang", "Chargement" }, { GFXP_HIRAGANA "ナウ ワーキング", "Now working", "Verarbeite", "Au travail" }, @@ -1167,7 +1182,7 @@ static SceneSelectLoadingMessages sLoadingMessages[] = { { GFXP_HIRAGANA "コショウジャナイヨ", "It's not broken", "Es ist nicht kaputt", "C'est pas casse!" }, { GFXP_KATAKANA "コーヒー ブレイク", "Coffee Break", "Kaffee-Pause", "Pause Cafe" }, { GFXP_KATAKANA "Bメンヲセットシテクダサイ", "Please set B side", "Please set B side", "Please set B side" }, - { GFXP_HIRAGANA "ジット" GFXP_KATAKANA "ガマン" GFXP_HIRAGANA "ノ" GFXP_KATAKANA "コ" GFXP_HIRAGANA "デアッタ", "Be patient, now", "Übe dich in Geduld", "Veuillez patientez" }, + { GFXP_HIRAGANA "ジット" GFXP_KATAKANA "ガマン" GFXP_HIRAGANA "ノ" GFXP_KATAKANA "コ" GFXP_HIRAGANA "デアッタ", "Be patient, now", "Ube dich in Geduld", "Veuillez patientez" }, { GFXP_HIRAGANA "イマシバラクオマチクダサイ", "Please wait just a minute", "Bitte warte noch eine Minute", "Patientez un peu" }, { GFXP_HIRAGANA "アワテナイアワテナイ。ヒトヤスミヒトヤスミ。", "Don't panic, don't panic. Take a break, take a break.", "Keine Panik! Nimm dir eine Auszeit", "Pas de panique. Prenez une pause." }, { "Enough! My ship sails in the morning!", "Enough! My ship sails in the morning!", "Enough! My ship sails in the morning!", "Enough! My ship sails in the morning!" }, @@ -1405,13 +1420,36 @@ void Better_Select_PrintMQSetting(SelectContext* this, GfxPrint* printer) { char* label; if (this->betterScenes[this->currentScene].entrancePairs[this->pageDownIndex].canBeMQ) { - label = this->opt ? "ON" : "OFF"; - + GfxPrint_SetColor(printer, 100, 100, 100, 255); GfxPrint_SetPos(printer, 3, 25); - GfxPrint_SetColor(printer, 0, 150, 194, 255); - GfxPrint_Printf(printer, "(L)MQ:%s", label); - } + // MQ can be toggled + if (ResourceMgr_GameHasMasterQuest() && ResourceMgr_GameHasOriginal()) { + GfxPrint_Printf(printer, "(L)MQ:"); + } else { + GfxPrint_Printf(printer, "MQ:"); + } + + if (CVarGetInteger("gDebugWarpScreenTranslation", 1)) { + switch (gSaveContext.language) { + case LANGUAGE_ENG: + default: + label = this->opt ? "ON" : "OFF"; + break; + case LANGUAGE_GER: + label = this->opt ? "AN" : "AUS"; + break; + case LANGUAGE_FRA: + label = this->opt ? "ACTIVE" : "DESACTIVE"; + break; + } + } else { + label = this->opt ? "ON" : "OFF"; + } + + GfxPrint_SetColor(printer, 0, 150, 194, 255); + GfxPrint_Printf(printer, "%s", label); + } } void Select_DrawMenu(SelectContext* this) { @@ -1429,11 +1467,11 @@ void Select_DrawMenu(SelectContext* this) { printer = alloca(sizeof(GfxPrint)); GfxPrint_Init(printer); GfxPrint_Open(printer, POLY_OPA_DISP); - if (CVarGetInteger("gBetterDebugWarpScreen", 0)) { - Better_Select_PrintMenu(this, printer); - Better_Select_PrintAgeSetting(this, printer, ((void)0, gSaveContext.linkAge)); + if (this->isBetterWarp) { Better_Select_PrintTimeSetting(this, printer); + Better_Select_PrintAgeSetting(this, printer, ((void)0, gSaveContext.linkAge)); Better_Select_PrintMQSetting(this, printer); + Better_Select_PrintMenu(this, printer); } else { Select_PrintMenu(this, printer); Select_PrintAgeSetting(this, printer, ((void)0, gSaveContext.linkAge)); @@ -1489,7 +1527,11 @@ void Select_Draw(SelectContext* this) { void Select_Main(GameState* thisx) { SelectContext* this = (SelectContext*)thisx; - if (CVarGetInteger("gBetterDebugWarpScreen", 0)) { + if (this->isBetterWarp != CVarGetInteger("gBetterDebugWarpScreen", 0)) { + Select_SwitchBetterWarpMode(this, !this->isBetterWarp); + } + + if (this->isBetterWarp) { Better_Select_UpdateMenu(this); } else { Select_UpdateMenu(this); @@ -1503,6 +1545,43 @@ void Select_Destroy(GameState* thisx) { osSyncPrintf("*** view_cleanupはハングアップするので、呼ばない ***\n"); } +// Switch better warp mode and re-init the list +void Select_SwitchBetterWarpMode(SelectContext* this, u8 isBetterWarpMode) { + this->isBetterWarp = isBetterWarpMode; + this->opt = 0; + this->currentScene = 0; + this->topDisplayedScene = 0; + this->pageDownIndex = 0; + gSaveContext.cutsceneIndex = 0x8000; + gSaveContext.linkAge = 1; + gSaveContext.nightFlag = 0; + gSaveContext.dayTime = 0x8000; + + if (isBetterWarpMode) { + s32 currScene = CVarGetInteger("gBetterDebugWarpScreenCurrentScene", 0); + this->count = ARRAY_COUNT(sBetterScenes); + + if (currScene >= 0 && currScene < this->count) { + this->currentScene = currScene; + this->topDisplayedScene = CVarGetInteger("gBetterDebugWarpScreenTopDisplayedScene", 0); + this->pageDownIndex = CVarGetInteger("gBetterDebugWarpScreenPageDownIndex", 0); + + BetterSceneSelectEntrancePair entrancePair = this->betterScenes[this->currentScene].entrancePairs[this->pageDownIndex]; + if (entrancePair.canBeMQ && ResourceMgr_IsSceneMasterQuest(gEntranceTable[entrancePair.entranceIndex].scene)) { + this->opt = 1; + } + } + } else { + this->count = ARRAY_COUNT(sScenes); + + if ((dREG(80) >= 0) && (dREG(80) < this->count)) { + this->currentScene = dREG(80); + this->topDisplayedScene = dREG(81); + this->pageDownIndex = dREG(82); + } + } +} + void Select_Init(GameState* thisx) { SelectContext* this = (SelectContext*)thisx; size_t size; @@ -1524,7 +1603,7 @@ void Select_Init(GameState* thisx) { this->pageDownStops[6] = 91; // Escaping Ganon's Tower 3 this->pageDownIndex = 0; this->opt = 0; - this->count = CVarGetInteger("gBetterDebugWarpScreen", 0) ? ARRAY_COUNT(sBetterScenes) : ARRAY_COUNT(sScenes); + this->count = ARRAY_COUNT(sScenes); View_Init(&this->view, this->state.gfxCtx); this->view.flags = (0x08 | 0x02); this->verticalInputAccumulator = 0; @@ -1542,11 +1621,7 @@ void Select_Init(GameState* thisx) { this->topDisplayedScene = dREG(81); this->pageDownIndex = dREG(82); } - if (CVarGetInteger("gBetterDebugWarpScreen", 0)) { - this->currentScene = CVarGetInteger("gBetterDebugWarpScreenCurrentScene", 0); - this->topDisplayedScene = CVarGetInteger("gBetterDebugWarpScreenTopDisplayedScene", 0); - this->pageDownIndex = CVarGetInteger("gBetterDebugWarpScreenPageDownIndex", 0); - } + R_UPDATE_RATE = 1; #if !defined(_MSC_VER) && !defined(__GNUC__) this->staticSegment = GAMESTATE_ALLOC_MC(&this->state, size); @@ -1556,4 +1631,7 @@ void Select_Init(GameState* thisx) { gSaveContext.linkAge = 1; gSaveContext.nightFlag = 0; gSaveContext.dayTime = 0x8000; + + CVarClear("gBetterDebugWarpScreenMQMode"); + Select_SwitchBetterWarpMode(this, CVarGetInteger("gBetterDebugWarpScreen", 0)); }