Entrance Rando (#1760)

This commit is contained in:
Adam Bird 2022-11-14 06:13:21 -05:00 committed by GitHub
commit 15a9975200
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 1341 additions and 142 deletions

View file

@ -31,6 +31,8 @@
#include "scenes/misc/hakaana_ouke/hakaana_ouke_scene.h"
#include "soh/Enhancements/randomizer/randomizer_entrance.h"
u16 D_8011E1C0 = 0;
u16 D_8011E1C4 = 0;
@ -1236,6 +1238,10 @@ void Cutscene_Command_Terminator(PlayState* play, CutsceneContext* csCtx, CsCmdB
play->fadeTransition = 3;
break;
}
if (randoCsSkip) {
Entrance_OverrideCutsceneEntrance(cmd->base);
}
}
}

View file

@ -4,6 +4,7 @@
#include "textures/do_action_static/do_action_static.h"
#include "textures/icon_item_static/icon_item_static.h"
#include "soh/Enhancements/randomizer/adult_trade_shuffle.h"
#include "soh/Enhancements/randomizer/randomizer_entrance.h"
#ifdef _MSC_VER
#include <stdlib.h>
@ -6361,6 +6362,12 @@ void Interface_Update(PlayState* play) {
gSaveContext.respawnFlag = -2;
play->nextEntranceIndex = gSaveContext.entranceIndex;
// In ER, handle sun song respawn from last entrance from grottos
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_ENTRANCES)) {
Grotto_ForceGrottoReturn();
}
play->sceneLoadFlag = 0x14;
gSaveContext.sunsSongState = SUNSSONG_INACTIVE;
func_800F6964(30);

View file

@ -7,6 +7,7 @@
#include <ImGuiImpl.h>
#include "soh/frame_interpolation.h"
#include "soh/Enhancements/debugconsole.h"
#include "soh/Enhancements/randomizer/randomizer_entrance.h"
#include <overlays/actors/ovl_En_Niw/z_en_niw.h>
#include <time.h>
@ -158,6 +159,11 @@ void Play_Destroy(GameState* thisx) {
PlayState* play = (PlayState*)thisx;
Player* player = GET_PLAYER(play);
// In ER, remove link from epona when entering somewhere that doesn't support epona
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_OVERWORLD_ENTRANCES)) {
Entrance_HandleEponaState();
}
play->state.gfxCtx->callback = NULL;
play->state.gfxCtx->callbackParam = 0;
SREG(91) = 0;
@ -512,6 +518,7 @@ void Play_Init(GameState* thisx) {
play,
gEntranceTable[((void)0, gSaveContext.entranceIndex) + ((void)0, gSaveContext.sceneSetupIndex)].scene,
gEntranceTable[((void)0, gSaveContext.sceneSetupIndex) + ((void)0, gSaveContext.entranceIndex)].spawn);
osSyncPrintf("\nSCENE_NO=%d COUNTER=%d\n", ((void)0, gSaveContext.entranceIndex), gSaveContext.sceneSetupIndex);
Cutscene_HandleEntranceTriggers(play);
@ -1754,6 +1761,10 @@ void* Play_LoadFile(PlayState* play, RomFile* file) {
}
void Play_InitEnvironment(PlayState* play, s16 skyboxId) {
// For entrance rando, ensure the correct weather state and sky mode is applied
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_ENTRANCES)) {
Entrance_OverrideWeatherState();
}
Skybox_Init(&play->state, &play->skyboxCtx, skyboxId);
Environment_Init(play, &play->envCtx, 0);
}
@ -1781,6 +1792,10 @@ void Play_InitScene(PlayState* play, s32 spawn)
void Play_SpawnScene(PlayState* play, s32 sceneNum, s32 spawn) {
OTRPlay_SpawnScene(play, sceneNum, spawn);
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_ENTRANCES)) {
Entrance_OverrideSpawnScene(sceneNum, spawn);
}
}
void func_800C016C(PlayState* play, Vec3f* src, Vec3f* dest) {

View file

@ -4,6 +4,7 @@
#include <string.h>
#include <soh/Enhancements/randomizer/randomizerTypes.h>
#include <soh/Enhancements/randomizer/randomizer_inf.h>
#include "soh/Enhancements/randomizer/randomizer_entrance.h"
#include "soh/Enhancements/randomizer/adult_trade_shuffle.h"
#define NUM_DUNGEONS 8
@ -196,6 +197,19 @@ void Sram_OpenSave() {
}
}
// Setup the modified entrance table and entrance shuffle table for rando
if (gSaveContext.n64ddFlag) {
Entrance_Init();
if (!CVar_GetS32("gRememberSaveLocation", 0) || gSaveContext.savedSceneNum == SCENE_YOUSEI_IZUMI_TATE ||
gSaveContext.savedSceneNum == SCENE_KAKUSIANA) {
Entrance_SetSavewarpEntrance();
}
} else {
// When going from a rando save to a vanilla save within the same game instance
// we need to reset the entrance table back to its vanilla state
Entrance_ResetEntranceTable();
}
osSyncPrintf("scene_no = %d\n", gSaveContext.entranceIndex);
osSyncPrintf(VT_RST);

View file

@ -47,7 +47,10 @@ void BgSpot01Idosoko_Init(Actor* thisx, PlayState* play) {
Actor_ProcessInitChain(&this->dyna.actor, sInitChain);
CollisionHeader_GetVirtual(&gKakarikoBOTWStoneCol, &colHeader);
this->dyna.bgId = DynaPoly_SetBgActor(play, &play->colCtx.dyna, &this->dyna.actor, colHeader);
if (!LINK_IS_ADULT) {
// If dungeon entrance randomizer is on, remove the well stone as adult Link when
// child Link has drained the water to the well
if (!LINK_IS_ADULT || gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_DUNGEON_ENTRANCES) &&
Flags_GetEventChkInf(0x67)) {
Actor_Kill(&this->dyna.actor);
} else {
BgSpot01Idosoko_SetupAction(this, func_808ABF54);

View file

@ -58,6 +58,12 @@ void func_808B3420(BgSpot12Saku* this, PlayState* play, CollisionHeader* collisi
void BgSpot12Saku_Init(Actor* thisx, PlayState* play) {
BgSpot12Saku* this = (BgSpot12Saku*)thisx;
// If ER is on, force the gate to always use its permanent flag
// (which it only uses in Child Gerudo Fortress in the vanilla game)
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_DUNGEON_ENTRANCES)) {
thisx->params = 0x0002;
}
func_808B3420(this, play, &gGerudoFortressGTGShutterCol, DPM_UNK);
Actor_ProcessInitChain(&this->dyna.actor, sInitChain);
if (Flags_GetSwitch(play, this->dyna.actor.params & 0x3F)) {
@ -125,6 +131,12 @@ void func_808B37AC(BgSpot12Saku* this, PlayState* play) {
void BgSpot12Saku_Update(Actor* thisx, PlayState* play) {
BgSpot12Saku* this = (BgSpot12Saku*)thisx;
// If ER is on, when the guard opens the GtG gate its permanent flag will be set.
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_DUNGEON_ENTRANCES) &&
Flags_GetSwitch(play, 0x3A)) {
Flags_SetSwitch(play, 0x2);
}
if (this->timer > 0) {
this->timer--;
}

View file

@ -73,7 +73,9 @@ void BgTreemouth_Init(Actor* thisx, PlayState* play) {
if ((gSaveContext.sceneSetupIndex < 4) && !LINK_IS_ADULT) {
BgTreemouth_SetupAction(this, func_808BC8B8);
} else if (LINK_IS_ADULT || (gSaveContext.sceneSetupIndex == 7)) {
// If dungeon entrance randomizer is on, keep the tree mouth open when link is adult and sword & shield have been shown to mido
} else if ((LINK_IS_ADULT && (!gSaveContext.n64ddFlag || !Randomizer_GetSettingValue(RSK_SHUFFLE_DUNGEON_ENTRANCES)) ||
!Flags_GetEventChkInf(0x4)) || (gSaveContext.sceneSetupIndex == 7)) {
this->unk_168 = 0.0f;
BgTreemouth_SetupAction(this, BgTreemouth_DoNothing);
} else {

View file

@ -867,7 +867,12 @@ void func_80986B2C(PlayState* play) {
if (Message_GetState(&play->msgCtx) == TEXT_STATE_CLOSING) {
Player* player = GET_PLAYER(play);
play->nextEntranceIndex = 0xCD;
// In entrance rando have impa bring link back to the front of castle grounds
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_OVERWORLD_ENTRANCES)) {
play->nextEntranceIndex = 0x0138;
} else {
play->nextEntranceIndex = 0xCD;
}
play->fadeTransition = 38;
play->sceneLoadFlag = 0x14;
func_8002DF54(play, &player->actor, 8);
@ -911,7 +916,12 @@ void GivePlayerRandoRewardImpa(Actor* impa, PlayState* play, RandomizerCheck che
play->sceneLoadFlag = 0x14;
play->fadeTransition = 3;
gSaveContext.nextTransition = 3;
play->nextEntranceIndex = 0x0594;
// In entrance rando have impa bring link back to the front of castle grounds
if (Randomizer_GetSettingValue(RSK_SHUFFLE_OVERWORLD_ENTRANCES)) {
play->nextEntranceIndex = 0x0138;
} else {
play->nextEntranceIndex = 0x0594;
}
gSaveContext.nextCutsceneIndex = 0;
}
}

View file

@ -6,6 +6,7 @@
#include "z_door_ana.h"
#include "objects/gameplay_field_keep/gameplay_field_keep.h"
#include "soh/Enhancements/randomizer/randomizer_entrance.h"
#define FLAGS ACTOR_FLAG_25
@ -139,6 +140,12 @@ void DoorAna_WaitOpen(DoorAna* this, PlayState* play) {
destinationIdx = this->actor.home.rot.z + 1;
}
play->nextEntranceIndex = entrances[destinationIdx];
// In ER, load the correct entrance based on the grotto link is falling into
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_ENTRANCES)) {
Grotto_OverrideActorEntrance(&this->actor);
}
DoorAna_SetupAction(this, DoorAna_GrabPlayer);
} else {
if (!Player_InCsMode(play) && !(player->stateFlags1 & 0x8800000) &&

View file

@ -1,5 +1,6 @@
#include "z_door_warp1.h"
#include "objects/object_warp1/object_warp1.h"
#include "soh/Enhancements/randomizer/randomizer_entrance.h"
#define FLAGS 0
@ -580,6 +581,11 @@ void DoorWarp1_ChildWarpOut(DoorWarp1* this, PlayState* play) {
play->nextEntranceIndex = 0x10E;
gSaveContext.nextCutsceneIndex = 0;
}
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_DUNGEON_ENTRANCES)) {
Entrance_OverrideBlueWarp();
}
osSyncPrintf("\n\n\nおわりおわり");
play->sceneLoadFlag = 0x14;
play->fadeTransition = 7;
@ -682,6 +688,10 @@ void DoorWarp1_RutoWarpOut(DoorWarp1* this, PlayState* play) {
gSaveContext.nextCutsceneIndex = 0xFFF0;
}
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_DUNGEON_ENTRANCES)) {
Entrance_OverrideBlueWarp();
}
play->sceneLoadFlag = 0x14;
play->fadeTransition = 7;
}
@ -890,6 +900,11 @@ void DoorWarp1_AdultWarpOut(DoorWarp1* this, PlayState* play) {
gSaveContext.nextCutsceneIndex = 0;
}
}
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_DUNGEON_ENTRANCES)) {
Entrance_OverrideBlueWarp();
}
play->sceneLoadFlag = 0x14;
play->fadeTransition = 3;
gSaveContext.nextTransition = 7;

View file

@ -7,6 +7,7 @@
#include "z_en_ge1.h"
#include "vt.h"
#include "objects/object_ge1/object_ge1.h"
#include "soh/Enhancements/randomizer/randomizer_entrance.h"
#define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_3)
@ -93,6 +94,20 @@ void EnGe1_Init(Actor* thisx, PlayState* play) {
s32 pad;
EnGe1* this = (EnGe1*)thisx;
// When spawning the gate operator, also spawn an extra gate operator on the wasteland side
if (gSaveContext.n64ddFlag && (Randomizer_GetSettingValue(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD) ||
Randomizer_GetSettingValue(RSK_SHUFFLE_OVERWORLD_ENTRANCES)) && (this->actor.params & 0xFF) == GE1_TYPE_GATE_OPERATOR) {
// Spawn the extra gaurd with params matching the custom type added (0x0300 + 0x02)
Actor_Spawn(&play->actorCtx, play, ACTOR_EN_GE1, -1358.0f, 88.0f, -3018.0f, 0, 0x95B0, 0,
0x0300 | GE1_TYPE_EXTRA_GATE_OPERATOR);
}
// Convert the "extra" gate operator into a normal one so it matches the same params
if ((this->actor.params & 0xFF) == GE1_TYPE_EXTRA_GATE_OPERATOR) {
this->actor.params &= ~0xFF;
this->actor.params |= GE1_TYPE_GATE_OPERATOR;
}
ActorShape_Init(&this->actor.shape, 0.0f, ActorShadow_DrawCircle, 30.0f);
SkelAnime_InitFlex(play, &this->skelAnime, &gGerudoWhiteSkel, &gGerudoWhiteIdleAnim, this->jointTable,
this->morphTable, GE1_LIMB_MAX);
@ -169,7 +184,12 @@ void EnGe1_Init(Actor* thisx, PlayState* play) {
this->hairstyle = GE1_HAIR_STRAIGHT;
if (EnGe1_CheckCarpentersFreed()) {
this->actionFunc = EnGe1_CheckForCard_GTGGuard;
// If the gtg gate is permanently open, don't let the gaurd charge to open it again
if (gSaveContext.n64ddFlag && gSaveContext.sceneFlags[93].swch & 0x00000004) {
this->actionFunc = EnGe1_SetNormalText;
} else {
this->actionFunc = EnGe1_CheckForCard_GTGGuard;
}
} else {
this->actionFunc = EnGe1_WatchForPlayerFrontOnly;
}
@ -247,6 +267,10 @@ void EnGe1_KickPlayer(EnGe1* this, PlayState* play) {
play->nextEntranceIndex = 0x3B4;
}
if (gSaveContext.n64ddFlag) {
Entrance_OverrideGeurdoGuardCapture();
}
play->fadeTransition = 0x26;
play->sceneLoadFlag = 0x14;
}

View file

@ -12,6 +12,7 @@ typedef void (*EnGe1ActionFunc)(struct EnGe1*, PlayState*);
typedef enum {
/* 0x00 */ GE1_TYPE_GATE_GUARD,
/* 0x01 */ GE1_TYPE_GATE_OPERATOR,
/* 0x02 */ GE1_TYPE_EXTRA_GATE_OPERATOR, // Custom guard type for entrance randomizer to open the gate
/* 0x04 */ GE1_TYPE_NORMAL = 4,
/* 0x05 */ GE1_TYPE_VALLEY_FLOOR,
/* 0x45 */ GE1_TYPE_HORSEBACK_ARCHERY = 0x45,

View file

@ -7,6 +7,7 @@
#include "z_en_ge2.h"
#include "vt.h"
#include "objects/object_gla/object_gla.h"
#include "soh/Enhancements/randomizer/randomizer_entrance.h"
#define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_3 | ACTOR_FLAG_4)
@ -253,6 +254,10 @@ void EnGe2_CaptureClose(EnGe2* this, PlayState* play) {
play->nextEntranceIndex = 0x3B4;
}
if (gSaveContext.n64ddFlag) {
Entrance_OverrideGeurdoGuardCapture();
}
play->fadeTransition = 0x26;
play->sceneLoadFlag = 0x14;
}
@ -279,6 +284,10 @@ void EnGe2_CaptureCharge(EnGe2* this, PlayState* play) {
play->nextEntranceIndex = 0x3B4;
}
if (gSaveContext.n64ddFlag) {
Entrance_OverrideGeurdoGuardCapture();
}
play->fadeTransition = 0x26;
play->sceneLoadFlag = 0x14;
}

View file

@ -330,6 +330,12 @@ void EnIshi_Init(Actor* thisx, PlayState* play) {
Actor_Kill(&this->actor);
return;
}
// If dungeon entrance randomizer is on, remove the grey boulders that normally
// block child Link from reaching the Fire Temple entrance.
if (type == ROCK_LARGE && gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_DUNGEON_ENTRANCES) &&
play->sceneNum == 0x061) { // Death Mountain Creater
Actor_Kill(&this->actor);
}
EnIshi_SetupWait(this);
}

View file

@ -2,6 +2,7 @@
#include "vt.h"
#include "overlays/actors/ovl_En_Syateki_Itm/z_en_syateki_itm.h"
#include "objects/object_ossan/object_ossan.h"
#include "soh/Enhancements/randomizer/randomizer_entrance.h"
#define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_3 | ACTOR_FLAG_4 | ACTOR_FLAG_27)
@ -154,6 +155,15 @@ void EnSyatekiMan_Init(Actor* thisx, PlayState* play) {
s32 pad;
EnSyatekiMan* this = (EnSyatekiMan*)thisx;
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_INTERIOR_ENTRANCES)) {
// If child is in the adult shooting gallery or adult in the child shooting gallery, then despawn the shooting gallery man
if ((LINK_IS_CHILD && Entrance_SceneAndSpawnAre(0x42, 0x00)) || //Kakariko Village -> Adult Shooting Gallery, index 003B in the entrance table
(LINK_IS_ADULT && Entrance_SceneAndSpawnAre(0x42, 0x01))) { //Market -> Child Shooting Gallery, index 016D in the entrance table
Actor_Kill(thisx);
return;
}
}
osSyncPrintf("\n\n");
// "Old man appeared!! Muhohohohohohohon"
osSyncPrintf(VT_FGCOL(GREEN) "☆☆☆☆☆ 親父登場!!むほほほほほほほーん ☆☆☆☆☆ \n" VT_RST);

View file

@ -23,6 +23,7 @@
#include <soh/Enhancements/custom-message/CustomMessageTypes.h>
#include "soh/Enhancements/item-tables/ItemTableTypes.h"
#include "soh/Enhancements/debugconsole.h"
#include "soh/Enhancements/randomizer/randomizer_entrance.h"
typedef enum {
/* 0x00 */ KNOB_ANIM_ADULT_L,
@ -4221,14 +4222,26 @@ s32 func_80839034(PlayState* play, Player* this, CollisionPoly* poly, u32 bgId)
func_800994A0(play);
} else {
play->nextEntranceIndex = play->setupExitList[sp3C - 1];
// Main override for entrance rando and entrance skips
if (gSaveContext.n64ddFlag) {
play->nextEntranceIndex = Entrance_OverrideNextIndex(play->nextEntranceIndex);
}
if (play->nextEntranceIndex == 0x7FFF) {
gSaveContext.respawnFlag = 2;
play->nextEntranceIndex = gSaveContext.respawn[RESPAWN_MODE_RETURN].entranceIndex;
play->fadeTransition = 3;
gSaveContext.nextTransition = 3;
} else if (play->nextEntranceIndex >= 0x7FF9) {
play->nextEntranceIndex =
D_808544F8[D_80854514[play->nextEntranceIndex - 0x7FF9] + play->curSpawn];
// handle dynamic exits
if (gSaveContext.n64ddFlag) {
play->nextEntranceIndex = Entrance_OverrideDynamicExit(D_80854514[play->nextEntranceIndex - 0x7FF9] + play->curSpawn);
} else {
play->nextEntranceIndex =
D_808544F8[D_80854514[play->nextEntranceIndex - 0x7FF9] + play->curSpawn];
}
func_800994A0(play);
} else {
if (SurfaceType_GetSlope(&play->colCtx, poly, bgId) == 2) {
@ -13400,6 +13413,10 @@ void func_8084F88C(Player* this, PlayState* play) {
play->nextEntranceIndex = 0x0088;
} else if (this->unk_84F < 0) {
Play_TriggerRespawn(play);
// In ER, handle DMT and other special void outs to respawn from last entrance from grotto
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_ENTRANCES)) {
Grotto_ForceRegularVoidOut();
}
} else {
Play_TriggerVoidOut(play);
}

View file

@ -458,6 +458,7 @@ void FileChoose_UpdateRandomizer() {
Randomizer_LoadItemLocations(fileLoc, silent);
Randomizer_LoadMerchantMessages(fileLoc);
Randomizer_LoadMasterQuestDungeons(fileLoc);
Randomizer_LoadEntranceOverrides(fileLoc, silent);
fileSelectSpoilerFileLoaded = true;
}
}
@ -2136,6 +2137,7 @@ void FileChoose_LoadGame(GameState* thisx) {
Randomizer_LoadRequiredTrials("");
Randomizer_LoadMerchantMessages("");
Randomizer_LoadMasterQuestDungeons("");
Randomizer_LoadEntranceOverrides("", true);
gSaveContext.respawn[0].entranceIndex = -1;
gSaveContext.respawnFlag = 0;

View file

@ -9,6 +9,8 @@
#include "vt.h"
#include "alloca.h"
#include "soh/Enhancements/randomizer/randomizer_entrance.h"
void Select_LoadTitle(SelectContext* this) {
this->state.running = false;
SET_NEXT_GAMESTATE(&this->state, Title_Init, TitleContext);
@ -32,6 +34,12 @@ void Select_LoadGame(SelectContext* this, s32 entranceIndex) {
Audio_QueueSeqCmd(SEQ_PLAYER_BGM_MAIN << 24 | NA_BGM_STOP);
gSaveContext.entranceIndex = entranceIndex;
// Check the entrance to see if the exit should be overriden to a grotto return point for entrance rando
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_ENTRANCES)) {
// Ignore return value as we want to load into the entrance specified by the debug menu
Grotto_OverrideSpecialEntrance(Entrance_GetOverride(entranceIndex));
}
if (CVar_GetS32("gBetterDebugWarpScreen", 0)) {
CVar_SetS32("gBetterDebugWarpScreenCurrentScene", this->currentScene);
CVar_SetS32("gBetterDebugWarpScreenTopDisplayedScene", this->topDisplayedScene);
@ -74,6 +82,14 @@ void Select_Grotto_LoadGame(SelectContext* this, s32 grottoIndex) {
gSaveContext.respawn[RESPAWN_MODE_RETURN].playerParams = 0x4ff;
gSaveContext.respawn[RESPAWN_MODE_RETURN].pos = this->betterGrottos[grottoIndex].pos;
// Check the entrance to see if the exit should be overriden to a grotto return point for entrance rando
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_ENTRANCES)) {
// Use grotto content and parent scene num to identify the right grotto
s16 grottoEntrance = Grotto_GetRenamedGrottoIndexFromOriginal(this->betterGrottos[grottoIndex].data, this->betterGrottos[grottoIndex].exitScene);
// Ignore return value as we want to load into the entrance specified by the debug menu
Grotto_OverrideSpecialEntrance(Entrance_GetOverride(grottoEntrance));
}
if (CVar_GetS32("gBetterDebugWarpScreen", 0)) {
CVar_SetS32("gBetterDebugWarpScreenCurrentScene", this->currentScene);
CVar_SetS32("gBetterDebugWarpScreenTopDisplayedScene", this->topDisplayedScene);
@ -623,34 +639,34 @@ static BetterSceneSelectEntry sBetterScenes[] = {
};
static BetterSceneSelectGrottoData sBetterGrottos[] = {
{ 0x003F, 0x00EE, 0, 0x2C, { -504.0, 380.0, -1224.0 }},
{ 0x003F, 0x04D6, 2, 0x14, { 922.0, 0.0, -933.0 }},
{ 0x05B4, 0x00FC, 0, 0xFFFFFFED, { -201.0, 0.0, 1906.0 }},
{ 0x003F, 0x00CD, 0, 0x00, { -1428.0, 0.0, 790.0 }},
{ 0x003F, 0x0189, 0, 0x03, { -4026.0, -700.0, 13858.0 }},
{ 0x003F, 0x0189, 0, 0x22, { -259.0, -500.0, 12356.0 }},
{ 0x003F, 0x034D, 0, 0x28, { 861.0, 80.0, -253.0 }},
{ 0x05A0, 0x034D, 0, 0xFFFFFFE7, { -400.0, 0.0, 408.0 }},
{ 0x003F, 0x01B9, 0, 0x57, { -389.0, 1386.0, -1202.0 }},
{ 0x003F, 0x0147, 1, 0x7A, { 50.0, 1233.0, 1776.0 }},
{ 0x003F, 0x019D, 0, 0x29, { 369.0, 570.0, 128.0 }},
{ 0x059C, 0x0189, 0, 0xFFFFFFE6, { -5002.0, -700.0, 13823.0 }},
{ 0x05A4, 0x0246, 1, 0xFFFFFFF9, { -1703.0, 722.0, -481.0 }},
{ 0x05A4, 0x014D, 3, 0xFFFFFFFB, { 1091.0, 580.0, -1192.0 }},
{ 0x05A4, 0x05D4, 0, 0xFFFFFFFC, { 1798.0, 0.0, 1498.0 }},
{ 0x05A4, 0x021D, 0, 0xFFFFFFEF, { -3044.0, -1033.0, 6070.0 }},
{ 0x05B0, 0x01A9, 8, 0xFFFFFFF5, { 677.0, 0.0, -2515.0 }},
{ 0x05BC, 0x00EA, 0, 0xFFFFFFEB, { -1632.0, 100.0, -123.0 }},
{ 0x05BC, 0x0215, 0, 0xFFFFFFEE, { 317.0, 480.0, -2303.0 }},
{ 0x05BC, 0x03D0, 0, 0xFFFFFFF0, { -1321.0, 15.0, -968.0 }},
{ 0x05BC, 0x01F1, 0, 0xFFFFFFFD, { 71.0, -32.0, -1303.0 }},
{ 0x05C4, 0x04D6, 6, 0xFFFFFFF3, { 75.0, -20.0, -1596.0 }},
{ 0x0598, 0x017D, 0, 0xFFFFFFE5, { 2059.0, 20.0, -174.0 }},
{ 0x05B8, 0x023D, 0, 0xFFFFFFF6, { 986.0, 1571.0, 837.0 }},
{ 0x05A8, 0x018D, 0, 0xFFFFFFE4, { -7873.0, -300.0, 6916.0 }},
{ 0x05FC, 0x01B9, 0, 0xFFFFFFF8, { -678.0, 1946.0, -284.0 }},
{ 0x05AC, 0x0117, 0, 0xFFFFFFF2, { 271.0, -555.0, 1465.0 }},
{ 0x05C0, 0x00CD, 0, 0xFFFFFFE1, { -4945.0, -300.0, 2841.0 }},
{ 0x003F, 0x00EE, 0, 0x2C, 0x55, { -504.0, 380.0, -1224.0 }}, // Kokiri Forest -> KF Storms Grotto
{ 0x003F, 0x04D6, 2, 0x14, 0x5B, { 922.0, 0.0, -933.0 }}, // Lost Woods -> LW Near Shortcuts Grotto
{ 0x05B4, 0x00FC, 0, 0xED, 0x56, { -201.0, 0.0, 1906.0 }}, // SFM Entryway -> SFM Wolfos Grotto
{ 0x003F, 0x00CD, 0, 0x00, 0x51, { -1428.0, 0.0, 790.0 }}, // Hyrule Field -> HF Near Market Grotto
{ 0x003F, 0x0189, 0, 0x03, 0x51, { -4026.0, -700.0, 13858.0 }}, // Hyrule Field -> HF Open Grotto
{ 0x003F, 0x0189, 0, 0x22, 0x51, { -259.0, -500.0, 12356.0 }}, // Hyrule Field -> HF Southeast Grotto
{ 0x003F, 0x034D, 0, 0x28, 0x52, { 861.0, 80.0, -253.0 }}, // Kak Backyard -> Kak Open Grotto
{ 0x05A0, 0x034D, 0, 0xE7, 0x52, { -400.0, 0.0, 408.0 }}, // Kakariko Village -> Kak Redead Grotto
{ 0x003F, 0x01B9, 0, 0x57, 0x60, { -389.0, 1386.0, -1202.0 }}, // Death Mountain -> DMT Storms Grotto
{ 0x003F, 0x0147, 1, 0x7A, 0x61, { 50.0, 1233.0, 1776.0 }}, // DMC Upper Nearby -> DMC Upper Grotto
{ 0x003F, 0x019D, 0, 0x29, 0x54, { 369.0, 570.0, 128.0 }}, // Zora River -> ZR Open Grotto
{ 0x059C, 0x0189, 0, 0xE6, 0x51, { -5002.0, -700.0, 13823.0 }}, // Hyrule Field -> HF Inside Fence Grotto
{ 0x05A4, 0x0246, 1, 0xF9, 0x61, { -1703.0, 722.0, -481.0 }}, // DMC Lower Nearby -> DMC Hammer Grotto
{ 0x05A4, 0x014D, 3, 0xFB, 0x62, { 1091.0, 580.0, -1192.0 }}, // GC Grotto Platform -> GC Grotto
{ 0x05A4, 0x05D4, 0, 0xFC, 0x63, { 1798.0, 0.0, 1498.0 }}, // Lon Lon Ranch -> LLR Grotto
{ 0x05A4, 0x021D, 0, 0xEF, 0x57, { -3044.0, -1033.0, 6070.0 }}, // Lake Hylia -> LH Grotto
{ 0x05B0, 0x01A9, 8, 0xF5, 0x5B, { 677.0, 0.0, -2515.0 }}, // LW Beyond Mido -> LW Scrubs Grotto
{ 0x05BC, 0x00EA, 0, 0xEB, 0x54, { -1632.0, 100.0, -123.0 }}, // Zora River -> ZR Storms Grotto
{ 0x05BC, 0x0215, 0, 0xEE, 0x56, { 317.0, 480.0, -2303.0 }}, // Sacred Forest Meadow -> SFM Storms Grotto
{ 0x05BC, 0x03D0, 0, 0xF0, 0x5A, { -1321.0, 15.0, -968.0 }}, // GV Fortress Side -> GV Storms Grotto
{ 0x05BC, 0x01F1, 0, 0xFD, 0x5C, { 71.0, -32.0, -1303.0 }}, // Desert Colossus -> Colossus Grotto
{ 0x05C4, 0x04D6, 6, 0xF3, 0x5B, { 75.0, -20.0, -1596.0 }}, // LW Beyond Mido -> Deku Theater
{ 0x0598, 0x017D, 0, 0xE5, 0x51, { 2059.0, 20.0, -174.0 }}, // Hyrule Field -> HF Near Kak Grotto
{ 0x05B8, 0x023D, 0, 0xF6, 0x5F, { 986.0, 1571.0, 837.0 }}, // Hyrule Castle Grounds -> HC Storms Grotto
{ 0x05A8, 0x018D, 0, 0xE4, 0x51, { -7873.0, -300.0, 6916.0 }}, // Hyrule Field -> HF Cow Grotto
{ 0x05FC, 0x01B9, 0, 0xF8, 0x60, { -678.0, 1946.0, -284.0 }}, // Death Mountain Summit -> DMT Cow Grotto
{ 0x05AC, 0x0117, 0, 0xF2, 0x5A, { 271.0, -555.0, 1465.0 }}, // GV Grotto Ledge -> GV Octorok Grotto
{ 0x05C0, 0x00CD, 0, 0xE1, 0x51, { -4945.0, -300.0, 2841.0 }}, // Hyrule Field -> HF Tektite Grotto
};
void Select_UpdateMenu(SelectContext* this) {

View file

@ -14,6 +14,7 @@
#include "vt.h"
#include "soh/frame_interpolation.h"
#include "soh/Enhancements/randomizer/randomizer_entrance.h"
static void* sEquipmentFRATexs[] = {
gPauseEquipment00FRATex, gPauseEquipment01Tex, gPauseEquipment02Tex, gPauseEquipment03Tex, gPauseEquipment04Tex,
@ -4213,6 +4214,10 @@ void KaleidoScope_Update(PlayState* play)
if (pauseCtx->promptChoice == 0) {
Play_TriggerRespawn(play);
gSaveContext.respawnFlag = -2;
// In ER, handle death warp to last entrance from grottos
if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_SHUFFLE_ENTRANCES)) {
Grotto_ForceGrottoReturn();
}
gSaveContext.nextTransition = 2;
gSaveContext.health = 0x30;
Audio_QueueSeqCmd(0xF << 28 | SEQ_PLAYER_BGM_MAIN << 24 | 0xA);