summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArchez <Archez@users.noreply.github.com>2024-07-23 21:31:01 -0400
committerGitHub <noreply@github.com>2024-07-23 21:31:01 -0400
commite66dada09dee7ff039bf1a82969441eedd5c5f2e (patch)
tree2cfc98cadd1dfcf8dcb25541832212c3b6f4e1cb
parentc68cecec71803e5fe8102aa06bdff61161cc1236 (diff)
Fix grotto handling with the skip intro timesaver (#4252)
-rw-r--r--soh/soh/Enhancements/TimeSavers/SkipCutscene/SkipIntro.cpp56
-rw-r--r--soh/soh/Enhancements/randomizer/randomizer_entrance.c4
-rw-r--r--soh/soh/Enhancements/randomizer/randomizer_entrance.h1
-rw-r--r--soh/soh/Enhancements/randomizer/randomizer_grotto.c43
-rw-r--r--soh/soh/Enhancements/randomizer/randomizer_grotto.h3
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);