mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2025-08-19 04:50:05 -07:00
Fix grotto handling with the skip intro timesaver (#4252)
This commit is contained in:
parent
c68cecec71
commit
e66dada09d
5 changed files with 78 additions and 29 deletions
|
@ -3,11 +3,11 @@
|
||||||
#include "soh/OTRGlobals.h"
|
#include "soh/OTRGlobals.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "z64save.h"
|
#include "z64save.h"
|
||||||
#include "functions.h"
|
#include "functions.h"
|
||||||
#include "soh/Enhancements/randomizer/randomizer_grotto.h"
|
#include "soh/Enhancements/randomizer/randomizer_entrance.h"
|
||||||
extern PlayState* gPlayState;
|
extern PlayState* gPlayState;
|
||||||
extern SaveContext gSaveContext;
|
extern SaveContext gSaveContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkipIntro_Register() {
|
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
|
// 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.
|
// the cutscene regardless of the enhancement being on.
|
||||||
bool adultStart = gSaveContext.linkAge == LINK_AGE_ADULT;
|
bool adultStart = gSaveContext.linkAge == LINK_AGE_ADULT;
|
||||||
bool shuffleOverworldSpawns = OTRGlobals::Instance->gRandoContext->GetOption(RSK_SHUFFLE_OVERWORLD_SPAWNS).Is(true);
|
bool shuffleOverworldSpawns =
|
||||||
if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Intro"), IS_RANDO) || (IS_RANDO && (adultStart || shuffleOverworldSpawns))) {
|
OTRGlobals::Instance->gRandoContext->GetOption(RSK_SHUFFLE_OVERWORLD_SPAWNS).Is(true);
|
||||||
// Calculate spawn location. Start with vanilla, Link's house.
|
if ((CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Intro"), IS_RANDO) ||
|
||||||
int32_t spawnEntrance = ENTR_LINKS_HOUSE_0;
|
(IS_RANDO && (adultStart || shuffleOverworldSpawns)) && gSaveContext.cutsceneIndex == 0xFFF1)) {
|
||||||
// If we're not in rando, we can skip all of the below.
|
// Calculate spawn location. Start with vanilla, Link's house.
|
||||||
if (IS_RANDO) {
|
int32_t spawnEntrance = ENTR_LINKS_HOUSE_0;
|
||||||
// If starting age is shuffled, use vanilla adult spawn/prelude warp.
|
// 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) {
|
if (adultStart) {
|
||||||
spawnEntrance = ENTR_TEMPLE_OF_TIME_7;
|
spawnEntrance = ENTR_HYRULE_FIELD_10;
|
||||||
}
|
|
||||||
// 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 = Entrance_PeekNextIndexOverride(spawnEntrance);
|
||||||
}
|
}
|
||||||
// Skip the intro cutscene for whatever the spawnEntrance is calculated to be.
|
}
|
||||||
if (gSaveContext.entranceIndex == spawnEntrance) {
|
// Skip the intro cutscene for whatever the spawnEntrance is calculated to be.
|
||||||
gSaveContext.cutsceneIndex = 0;
|
if (gSaveContext.entranceIndex == spawnEntrance) {
|
||||||
*should = false;
|
gSaveContext.cutsceneIndex = 0;
|
||||||
}
|
*should = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -260,6 +260,10 @@ s16 Entrance_GetOverride(s16 index) {
|
||||||
return entranceOverrideTable[index];
|
return entranceOverrideTable[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s16 Entrance_PeekNextIndexOverride(int16_t nextEntranceIndex) {
|
||||||
|
return Grotto_GetEntranceValueHandlingGrottoRando(Entrance_GetOverride(nextEntranceIndex));
|
||||||
|
}
|
||||||
|
|
||||||
s16 Entrance_OverrideNextIndex(s16 nextEntranceIndex) {
|
s16 Entrance_OverrideNextIndex(s16 nextEntranceIndex) {
|
||||||
// When entering Spirit Temple, clear temp flags so they don't carry over to the randomized dungeon
|
// 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 &&
|
if (nextEntranceIndex == ENTR_SPIRIT_TEMPLE_0 && Entrance_GetOverride(nextEntranceIndex) != nextEntranceIndex &&
|
||||||
|
|
|
@ -81,6 +81,7 @@ void Entrance_ResetEntranceTable(void);
|
||||||
uint8_t Entrance_EntranceIsNull(EntranceOverride* entranceOverride);
|
uint8_t Entrance_EntranceIsNull(EntranceOverride* entranceOverride);
|
||||||
int16_t Entrance_GetOverride(int16_t index);
|
int16_t Entrance_GetOverride(int16_t index);
|
||||||
int16_t Entrance_OverrideNextIndex(int16_t nextEntranceIndex);
|
int16_t Entrance_OverrideNextIndex(int16_t nextEntranceIndex);
|
||||||
|
int16_t Entrance_PeekNextIndexOverride(int16_t nextEntranceIndex);
|
||||||
int16_t Entrance_OverrideDynamicExit(int16_t dynamicExitIndex);
|
int16_t Entrance_OverrideDynamicExit(int16_t dynamicExitIndex);
|
||||||
uint32_t Entrance_SceneAndSpawnAre(uint8_t scene, uint8_t spawn);
|
uint32_t Entrance_SceneAndSpawnAre(uint8_t scene, uint8_t spawn);
|
||||||
void Entrance_SetGameOverEntrance(void);
|
void Entrance_SetGameOverEntrance(void);
|
||||||
|
|
|
@ -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
|
// 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) {
|
s16 Grotto_OverrideSpecialEntrance(s16 nextEntranceIndex) {
|
||||||
|
|
||||||
// Don't change anything unless grotto shuffle has been enabled
|
// Don't change anything unless grotto shuffle has been enabled
|
||||||
|
|
|
@ -24,7 +24,8 @@ typedef struct {
|
||||||
void Grotto_InitExitAndLoadLists(void);
|
void Grotto_InitExitAndLoadLists(void);
|
||||||
void Grotto_SetExitOverride(s16 originalIndex, s16 overrideIndex);
|
void Grotto_SetExitOverride(s16 originalIndex, s16 overrideIndex);
|
||||||
void Grotto_SetLoadOverride(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_ForceGrottoReturnOnSpecialEntrance(void);
|
||||||
void Grotto_ForceGrottoReturn(void);
|
void Grotto_ForceGrottoReturn(void);
|
||||||
void Grotto_ForceRegularVoidOut(void);
|
void Grotto_ForceRegularVoidOut(void);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue