From e66dada09dee7ff039bf1a82969441eedd5c5f2e Mon Sep 17 00:00:00 2001 From: Archez Date: Tue, 23 Jul 2024 21:31:01 -0400 Subject: [PATCH] Fix grotto handling with the skip intro timesaver (#4252) --- .../TimeSavers/SkipCutscene/SkipIntro.cpp | 56 ++++++++++--------- .../randomizer/randomizer_entrance.c | 4 ++ .../randomizer/randomizer_entrance.h | 1 + .../randomizer/randomizer_grotto.c | 43 +++++++++++++- .../randomizer/randomizer_grotto.h | 3 +- 5 files changed, 78 insertions(+), 29 deletions(-) diff --git a/soh/soh/Enhancements/TimeSavers/SkipCutscene/SkipIntro.cpp b/soh/soh/Enhancements/TimeSavers/SkipCutscene/SkipIntro.cpp index 2402f841c..dda8b7a6e 100644 --- a/soh/soh/Enhancements/TimeSavers/SkipCutscene/SkipIntro.cpp +++ b/soh/soh/Enhancements/TimeSavers/SkipCutscene/SkipIntro.cpp @@ -3,11 +3,11 @@ #include "soh/OTRGlobals.h" extern "C" { - #include "z64save.h" - #include "functions.h" - #include "soh/Enhancements/randomizer/randomizer_grotto.h" - extern PlayState* gPlayState; - extern SaveContext gSaveContext; +#include "z64save.h" +#include "functions.h" +#include "soh/Enhancements/randomizer/randomizer_entrance.h" +extern PlayState* gPlayState; +extern SaveContext gSaveContext; } void SkipIntro_Register() { @@ -15,31 +15,33 @@ void SkipIntro_Register() { // If we're playing rando and if starting age is adult and/or overworld spawns are shuffled we need to skip // the cutscene regardless of the enhancement being on. bool adultStart = gSaveContext.linkAge == LINK_AGE_ADULT; - bool shuffleOverworldSpawns = OTRGlobals::Instance->gRandoContext->GetOption(RSK_SHUFFLE_OVERWORLD_SPAWNS).Is(true); - if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Intro"), IS_RANDO) || (IS_RANDO && (adultStart || shuffleOverworldSpawns))) { - // Calculate spawn location. Start with vanilla, Link's house. - int32_t spawnEntrance = ENTR_LINKS_HOUSE_0; - // If we're not in rando, we can skip all of the below. - if (IS_RANDO) { - // If starting age is shuffled, use vanilla adult spawn/prelude warp. + bool shuffleOverworldSpawns = + OTRGlobals::Instance->gRandoContext->GetOption(RSK_SHUFFLE_OVERWORLD_SPAWNS).Is(true); + if ((CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Intro"), IS_RANDO) || + (IS_RANDO && (adultStart || shuffleOverworldSpawns)) && gSaveContext.cutsceneIndex == 0xFFF1)) { + // Calculate spawn location. Start with vanilla, Link's house. + int32_t spawnEntrance = ENTR_LINKS_HOUSE_0; + // If we're not in rando, we can skip all of the below. + if (IS_RANDO) { + // If starting age is shuffled, use vanilla adult spawn/prelude warp. + if (adultStart) { + spawnEntrance = ENTR_TEMPLE_OF_TIME_7; + } + // If we're shuffling overworld spawns we'll need to get the Entrance Override + if (shuffleOverworldSpawns) { + // If we're shuffling overworld spawns the adult spawn is ENTR_HYRULE_FIELD_10 instead of + // ENTR_TEMPLE_OF_TIME_7, so that spawn and Prelude don't share an entrance. if (adultStart) { - spawnEntrance = ENTR_TEMPLE_OF_TIME_7; - } - // If we're shuffling overworld spawns we'll need to get the Entrance Override - if (shuffleOverworldSpawns) { - // If we're shuffling overworld spawns the adult spawn is ENTR_HYRULE_FIELD_10 instead of - // ENTR_TEMPLE_OF_TIME_7, so that spawn and Prelude don't share an entrance. - if (adultStart){ - spawnEntrance = ENTR_HYRULE_FIELD_10; - } - spawnEntrance = Grotto_OverrideSpecialEntrance(Entrance_GetOverride(spawnEntrance)); + spawnEntrance = ENTR_HYRULE_FIELD_10; } + spawnEntrance = Entrance_PeekNextIndexOverride(spawnEntrance); } - // Skip the intro cutscene for whatever the spawnEntrance is calculated to be. - if (gSaveContext.entranceIndex == spawnEntrance) { - gSaveContext.cutsceneIndex = 0; - *should = false; - } + } + // Skip the intro cutscene for whatever the spawnEntrance is calculated to be. + if (gSaveContext.entranceIndex == spawnEntrance) { + gSaveContext.cutsceneIndex = 0; + *should = false; + } } }); } diff --git a/soh/soh/Enhancements/randomizer/randomizer_entrance.c b/soh/soh/Enhancements/randomizer/randomizer_entrance.c index 24bf8c03a..d52b09836 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_entrance.c +++ b/soh/soh/Enhancements/randomizer/randomizer_entrance.c @@ -260,6 +260,10 @@ s16 Entrance_GetOverride(s16 index) { return entranceOverrideTable[index]; } +s16 Entrance_PeekNextIndexOverride(int16_t nextEntranceIndex) { + return Grotto_GetEntranceValueHandlingGrottoRando(Entrance_GetOverride(nextEntranceIndex)); +} + s16 Entrance_OverrideNextIndex(s16 nextEntranceIndex) { // When entering Spirit Temple, clear temp flags so they don't carry over to the randomized dungeon if (nextEntranceIndex == ENTR_SPIRIT_TEMPLE_0 && Entrance_GetOverride(nextEntranceIndex) != nextEntranceIndex && diff --git a/soh/soh/Enhancements/randomizer/randomizer_entrance.h b/soh/soh/Enhancements/randomizer/randomizer_entrance.h index 8d8d3a678..cc22b31f3 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_entrance.h +++ b/soh/soh/Enhancements/randomizer/randomizer_entrance.h @@ -81,6 +81,7 @@ void Entrance_ResetEntranceTable(void); uint8_t Entrance_EntranceIsNull(EntranceOverride* entranceOverride); int16_t Entrance_GetOverride(int16_t index); int16_t Entrance_OverrideNextIndex(int16_t nextEntranceIndex); +int16_t Entrance_PeekNextIndexOverride(int16_t nextEntranceIndex); int16_t Entrance_OverrideDynamicExit(int16_t dynamicExitIndex); uint32_t Entrance_SceneAndSpawnAre(uint8_t scene, uint8_t spawn); void Entrance_SetGameOverEntrance(void); diff --git a/soh/soh/Enhancements/randomizer/randomizer_grotto.c b/soh/soh/Enhancements/randomizer/randomizer_grotto.c index b552dd2cd..6c92221b9 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_grotto.c +++ b/soh/soh/Enhancements/randomizer/randomizer_grotto.c @@ -128,8 +128,49 @@ static void Grotto_SetupReturnInfo(GrottoReturnInfo grotto, RespawnMode respawnM } } +// Get the next entrance value while handling conversion of grotto rando IDs to real entrance values. +// This method doesn't change player respawn data, so only use this if you are querying an entrance index. +s16 Grotto_GetEntranceValueHandlingGrottoRando(s16 nextEntranceIndex) { + // Don't change anything unless grotto shuffle has been enabled + if (!Randomizer_GetSettingValue(RSK_SHUFFLE_GROTTO_ENTRANCES) && !Randomizer_GetSettingValue(RSK_SHUFFLE_OVERWORLD_SPAWNS) && !Randomizer_GetSettingValue(RSK_SHUFFLE_WARP_SONGS)) { + return nextEntranceIndex; + } + + // If Link hits a grotto exit, load the entrance index from the grotto exit list + // based on the current grotto ID + if (nextEntranceIndex == ENTR_RETURN_GROTTO) { + nextEntranceIndex = grottoExitList[grottoId]; + } + + // Get the new grotto id from the next entrance + grottoId = nextEntranceIndex & 0x00FF; + + // Grotto Returns + if (nextEntranceIndex >= ENTRANCE_RANDO_GROTTO_EXIT_START && nextEntranceIndex < ENTRANCE_RANDO_GROTTO_EXIT_START + NUM_GROTTOS) { + GrottoReturnInfo grotto = grottoReturnTable[grottoId]; + + // When the nextEntranceIndex is determined by a dynamic exit, + // or set by Entrance_OverrideBlueWarp to mark a blue warp entrance, + // we have to set the respawn information and nextEntranceIndex manually + if (gPlayState != NULL && gPlayState->nextEntranceIndex != ENTR_LOAD_OPENING) { + nextEntranceIndex = grotto.entranceIndex; + } else if (gPlayState == NULL) { // Handle spawn position when loading from a save file + nextEntranceIndex = grotto.entranceIndex; + // Otherwise return 0x7FFF (ENTR_RETURN_GROTTO) and let the game handle it + } else { + nextEntranceIndex = ENTR_RETURN_GROTTO; + } + // Grotto Loads + } else if (nextEntranceIndex >= ENTRANCE_RANDO_GROTTO_LOAD_START && nextEntranceIndex < ENTRANCE_RANDO_GROTTO_EXIT_START) { + GrottoLoadInfo grotto = grottoLoadTable[grottoId]; + nextEntranceIndex = grotto.entranceIndex; + } + + return nextEntranceIndex; +} + // Translates and overrides the passed in entrance index if it corresponds to a -// special grotto entrance (grotto load or returnpoint) +// special grotto entrance (grotto load or returnpoint) and updates player respawn data correctly. s16 Grotto_OverrideSpecialEntrance(s16 nextEntranceIndex) { // Don't change anything unless grotto shuffle has been enabled diff --git a/soh/soh/Enhancements/randomizer/randomizer_grotto.h b/soh/soh/Enhancements/randomizer/randomizer_grotto.h index c516d32bf..938c4c6d6 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_grotto.h +++ b/soh/soh/Enhancements/randomizer/randomizer_grotto.h @@ -24,7 +24,8 @@ typedef struct { void Grotto_InitExitAndLoadLists(void); void Grotto_SetExitOverride(s16 originalIndex, s16 overrideIndex); void Grotto_SetLoadOverride(s16 originalIndex, s16 overrideIndex); -s16 Grotto_OverrideSpecialEntrance(s16 nextEntranceIndex); +s16 Grotto_GetEntranceValueHandlingGrottoRando(s16 nextEntranceIndex); +s16 Grotto_OverrideSpecialEntrance(s16 nextEntranceIndex); void Grotto_ForceGrottoReturnOnSpecialEntrance(void); void Grotto_ForceGrottoReturn(void); void Grotto_ForceRegularVoidOut(void);