From 4515fac4676e7ed1633282e358eb38d650275b4f Mon Sep 17 00:00:00 2001 From: Kenix3 Date: Thu, 7 Jul 2022 22:17:20 -0400 Subject: [PATCH 01/44] Fixes bug in demo effect due to removed display list set. --- soh/src/overlays/actors/ovl_Demo_Effect/z_demo_effect.c | 1 + 1 file changed, 1 insertion(+) diff --git a/soh/src/overlays/actors/ovl_Demo_Effect/z_demo_effect.c b/soh/src/overlays/actors/ovl_Demo_Effect/z_demo_effect.c index 92201fda9..fd790c63a 100644 --- a/soh/src/overlays/actors/ovl_Demo_Effect/z_demo_effect.c +++ b/soh/src/overlays/actors/ovl_Demo_Effect/z_demo_effect.c @@ -1859,6 +1859,7 @@ void DemoEffect_DrawLightEffect(Actor* thisx, GlobalContext* globalCtx) { if (this->light.flicker == 0) { this->light.flicker = 1; } else { + disp = (uintptr_t)gEffFlash1DL; alpha = &this->light.alpha; func_80093D84(globalCtx->state.gfxCtx); gDPSetPrimColor(POLY_XLU_DISP++, 0, 128, this->primXluColor[0], this->primXluColor[1], From c78d2828a729a9b9f6aaf3698e9a82adae79aade Mon Sep 17 00:00:00 2001 From: Baoulettes Date: Fri, 8 Jul 2022 04:17:57 +0200 Subject: [PATCH 02/44] King dodongo room crash (#613) * first attempt * force camera setting to be at least 0 (dirty!) * - * reverted something to just include fix --- soh/src/overlays/actors/ovl_Boss_Dodongo/z_boss_dodongo.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/soh/src/overlays/actors/ovl_Boss_Dodongo/z_boss_dodongo.c b/soh/src/overlays/actors/ovl_Boss_Dodongo/z_boss_dodongo.c index b5a8bf97f..37105d040 100644 --- a/soh/src/overlays/actors/ovl_Boss_Dodongo/z_boss_dodongo.c +++ b/soh/src/overlays/actors/ovl_Boss_Dodongo/z_boss_dodongo.c @@ -216,9 +216,10 @@ void BossDodongo_Init(Actor* thisx, GlobalContext* globalCtx) { Collider_SetJntSph(globalCtx, &this->collider, &this->actor, &sJntSphInit, this->items); if (Flags_GetClear(globalCtx, globalCtx->roomCtx.curRoom.num)) { // KD is dead - temp_s1_3 = SEGMENTED_TO_VIRTUAL(gDodongosCavernBossLavaFloorTex); - temp_s2 = SEGMENTED_TO_VIRTUAL(sLavaFloorRockTex); - + u16* LavaFloorTex = ResourceMgr_LoadTexByName(gDodongosCavernBossLavaFloorTex); + u16* LavaFloorRockTex = ResourceMgr_LoadTexByName(sLavaFloorRockTex); + temp_s1_3 = SEGMENTED_TO_VIRTUAL(LavaFloorTex); + temp_s2 = SEGMENTED_TO_VIRTUAL(LavaFloorRockTex); Actor_Kill(&this->actor); Actor_SpawnAsChild(&globalCtx->actorCtx, &this->actor, globalCtx, ACTOR_DOOR_WARP1, -890.0f, -1523.76f, -3304.0f, 0, 0, 0, WARP_DUNGEON_CHILD); From 1c9195373dd920a37a71ad4f9e9fe786ccc37518 Mon Sep 17 00:00:00 2001 From: vaguerant Date: Fri, 8 Jul 2022 12:18:11 +1000 Subject: [PATCH 03/44] Invalidate text box icon before drawing (#607) --- soh/src/code/z_message_PAL.c | 1 + 1 file changed, 1 insertion(+) diff --git a/soh/src/code/z_message_PAL.c b/soh/src/code/z_message_PAL.c index c6cfa9db5..dd6a52b47 100644 --- a/soh/src/code/z_message_PAL.c +++ b/soh/src/code/z_message_PAL.c @@ -543,6 +543,7 @@ void Message_DrawTextboxIcon(GlobalContext* globalCtx, Gfx** p, s16 x, s16 y) { s16 envG; s16 envB; u8* iconTexture = font->iconBuf; + gSPInvalidateTexCache(gfx++, iconTexture); if (sTextIsCredits) { return; From 0f34b991aafb8f10a973e8a564756c9d699d190a Mon Sep 17 00:00:00 2001 From: qurious-pixel <62252937+qurious-pixel@users.noreply.github.com> Date: Thu, 7 Jul 2022 19:18:29 -0700 Subject: [PATCH 04/44] [APPIMAGE] Set lib path for ZAPD (#611) --- appimage/soh.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/appimage/soh.sh b/appimage/soh.sh index bd4683e50..21ddcd5aa 100644 --- a/appimage/soh.sh +++ b/appimage/soh.sh @@ -2,6 +2,7 @@ HERE="$(dirname "$(readlink -f "${0}")")"/../.. export PATH="$HERE"/bin:"$HERE"/usr/bin:"$PATH" +export LD_LIBRARY_PATH="$HERE"/usr/lib:"$LD_LIBRARY_PATH" while [[ ! -e "$PWD"/oot.otr ]]; do export ASSETDIR="$(mktemp -d /tmp/assets-XXXXX)" From 60e713855abd536d03e58709c218a11fc1dfff88 Mon Sep 17 00:00:00 2001 From: Baoulettes Date: Fri, 8 Jul 2022 04:19:08 +0200 Subject: [PATCH 05/44] New drop runtime fix (#614) * inital rework * fixed default rotation for 2D sprites * fix tab/space issues --- soh/src/code/z_en_item00.c | 526 ++++++++++++++++--------------------- 1 file changed, 227 insertions(+), 299 deletions(-) diff --git a/soh/src/code/z_en_item00.c b/soh/src/code/z_en_item00.c index 160dcfe30..d5e6071bb 100644 --- a/soh/src/code/z_en_item00.c +++ b/soh/src/code/z_en_item00.c @@ -358,76 +358,16 @@ void EnItem00_Init(Actor* thisx, GlobalContext* globalCtx) { switch (this->actor.params) { case ITEM00_RUPEE_GREEN: - if (CVar_GetS32("gNewDrops", 0) !=0) { - Actor_SetScale(&this->actor, 0.3f); - this->scale = 0.3f; - yOffset = 50.0f; - shadowScale = 0.3f; - this->actor.world.rot.x = 0x4000; - break; - } case ITEM00_RUPEE_BLUE: - if (CVar_GetS32("gNewDrops", 0) !=0) { - Actor_SetScale(&this->actor, 0.3f); - this->scale = 0.3f; - yOffset = 50.0f; - shadowScale = 0.3f; - this->actor.world.rot.x = 0x4000; - } case ITEM00_RUPEE_RED: - if (CVar_GetS32("gNewDrops", 0) !=0) { - Actor_SetScale(&this->actor, 0.3f); - this->scale = 0.3f; - yOffset = 50.0f; - shadowScale = 0.3f; - this->actor.world.rot.x = 0x4000; - } else { - Actor_SetScale(&this->actor, 0.015f); - this->scale = 0.015f; - yOffset = 750.0f; - } break; case ITEM00_SMALL_KEY: this->unk_158 = 0; - if (CVar_GetS32("gNewDrops", 0) !=0) { - Actor_SetScale(&this->actor, 0.3f); - this->scale = 0.3f; - yOffset = 50.0f; - shadowScale = 0.5f; - this->actor.world.rot.x = 0x4000; - } else { - Actor_SetScale(&this->actor, 0.03f); - this->scale = 0.03f; - yOffset = 350.0f; - } break; case ITEM00_HEART_PIECE: this->unk_158 = 0; - if (CVar_GetS32("gNewDrops", 0) !=0) { - Actor_SetScale(&this->actor, 0.5f); - this->scale = 0.5f; - yOffset = 50.0f; - shadowScale = 0.5f; - this->actor.world.rot.x = 0x4000; - } else { - yOffset = 650.0f; - Actor_SetScale(&this->actor, 0.02f); - this->scale = 0.02f; - } break; case ITEM00_HEART: - if (CVar_GetS32("gNewDrops", 0) !=0) { - this->actor.home.rot.z = Rand_CenteredFloat(65535.0f); - yOffset = 25.0f; - Actor_SetScale(&this->actor, 0.3f); - this->scale = 0.3f; - shadowScale = 0.5f; - } else { - this->actor.home.rot.z = Rand_CenteredFloat(65535.0f); - yOffset = 430.0f; - Actor_SetScale(&this->actor, 0.02f); - this->scale = 0.02f; - } break; case ITEM00_HEART_CONTAINER: yOffset = 430.0f; @@ -436,155 +376,19 @@ void EnItem00_Init(Actor* thisx, GlobalContext* globalCtx) { this->scale = 0.02f; break; case ITEM00_ARROWS_SINGLE: - if (CVar_GetS32("gNewDrops", 0) !=0) { - Actor_SetScale(&this->actor, 0.2f); - this->scale = 0.2f; - yOffset = 50.0f; - shadowScale = 0.5f; - this->actor.world.rot.x = 0x4000; - } else { - yOffset = 400.0f; - Actor_SetScale(&this->actor, 0.02f); - this->scale = 0.02f; - } - break; case ITEM00_ARROWS_SMALL: - if (CVar_GetS32("gNewDrops", 0) !=0) { - Actor_SetScale(&this->actor, 0.2f); - this->scale = 0.2f; - yOffset = 50.0f; - shadowScale = 0.5f; - this->actor.world.rot.x = 0x4000; - break; - } case ITEM00_ARROWS_MEDIUM: - if (CVar_GetS32("gNewDrops", 0) !=0) { - Actor_SetScale(&this->actor, 0.2f); - this->scale = 0.2f; - yOffset = 50.0f; - shadowScale = 0.5f; - this->actor.world.rot.x = 0x4000; - break; - } case ITEM00_ARROWS_LARGE: - if (CVar_GetS32("gNewDrops", 0) !=0) { - Actor_SetScale(&this->actor, 0.2f); - this->scale = 0.2f; - yOffset = 50.0f; - shadowScale = 0.5f; - this->actor.world.rot.x = 0x4000; - } else { - Actor_SetScale(&this->actor, 0.035f); - this->scale = 0.035f; - yOffset = 250.0f; - } - break; case ITEM00_BOMBS_A: - if (CVar_GetS32("gNewDrops", 0) !=0) { - Actor_SetScale(&this->actor, 0.2f); - this->scale = 0.2f; - yOffset = 50.0f; - shadowScale = 0.5f; - this->actor.world.rot.x = 0x4000; - break; - } case ITEM00_BOMBS_B: - if (CVar_GetS32("gNewDrops", 0) !=0) { - Actor_SetScale(&this->actor, 0.2f); - this->scale = 0.2f; - yOffset = 50.0f; - shadowScale = 0.5f; - this->actor.world.rot.x = 0x4000; - break; - } case ITEM00_NUTS: - if (CVar_GetS32("gNewDrops", 0) !=0) { - Actor_SetScale(&this->actor, 0.2f); - this->scale = 0.2f; - yOffset = 50.0f; - shadowScale = 0.5f; - this->actor.world.rot.x = 0x4000; - break; - } case ITEM00_STICK: - if (CVar_GetS32("gNewDrops", 0) !=0) { - Actor_SetScale(&this->actor, 0.2f); - this->scale = 0.2f; - yOffset = 50.0f; - shadowScale = 0.5f; - this->actor.world.rot.x = 0x4000; - break; - } case ITEM00_MAGIC_SMALL: - if (CVar_GetS32("gNewDrops", 0) !=0) { - Actor_SetScale(&this->actor, 0.2f); - this->scale = 0.2f; - yOffset = 50.0f; - shadowScale = 0.5f; - this->actor.world.rot.x = 0x4000; - break; - } case ITEM00_SEEDS: - if (CVar_GetS32("gNewDrops", 0) !=0) { - Actor_SetScale(&this->actor, 0.2f); - this->scale = 0.2f; - yOffset = 50.0f; - shadowScale = 0.5f; - this->actor.world.rot.x = 0x4000; - break; - } case ITEM00_BOMBS_SPECIAL: - if (CVar_GetS32("gNewDrops", 0) !=0) { - Actor_SetScale(&this->actor, 0.2f); - this->scale = 0.2f; - yOffset = 50.0f; - shadowScale = 0.5f; - this->actor.world.rot.x = 0x4000; - } else { - Actor_SetScale(&this->actor, 0.03f); - this->scale = 0.03f; - yOffset = 320.0f; - } - break; case ITEM00_MAGIC_LARGE: - if (CVar_GetS32("gNewDrops", 0) !=0) { - Actor_SetScale(&this->actor, 0.2f); - this->scale = 0.2f; - yOffset = 50.0f; - shadowScale = 0.5f; - this->actor.world.rot.x = 0x4000; - } else { - Actor_SetScale(&this->actor, 0.045 - 1e-10); - this->scale = 0.045 - 1e-10; - yOffset = 320.0f; - } - break; case ITEM00_RUPEE_ORANGE: - if (CVar_GetS32("gNewDrops", 0) !=0) { - Actor_SetScale(&this->actor, 0.45f); - this->scale = 0.45f; - yOffset = 50.0f; - shadowScale = 0.3f; - this->actor.world.rot.x = 0x4000; - } else { - Actor_SetScale(&this->actor, 0.045 - 1e-10); - this->scale = 0.045 - 1e-10; - yOffset = 750.0f; - } - break; case ITEM00_RUPEE_PURPLE: - if (CVar_GetS32("gNewDrops", 0) !=0) { - Actor_SetScale(&this->actor, 0.4f); - this->scale = 0.4f; - yOffset = 50.0f; - shadowScale = 0.3f; - this->actor.world.rot.x = 0x4000; - } else { - Actor_SetScale(&this->actor, 0.03f); - this->scale = 0.03f; - yOffset = 750.0f; - } - break; case ITEM00_FLEXIBLE: yOffset = 500.0f; Actor_SetScale(&this->actor, 0.01f); @@ -721,18 +525,18 @@ void EnItem00_Destroy(Actor* thisx, GlobalContext* globalCtx) { void func_8001DFC8(EnItem00* this, GlobalContext* globalCtx) { - if (CVar_GetS32("gNewDrops", 0) !=0) { //set the rotation system on selected model only :) - if ((this->actor.params == ITEM_RUPEE_GOLD) || (this->actor.params == ITEM_RUPEE_PURPLE) || - (this->actor.params == ITEM00_ARROWS_SINGLE) || (this->actor.params == ITEM00_ARROWS_SMALL) || - (this->actor.params == ITEM00_ARROWS_MEDIUM) || (this->actor.params == ITEM00_ARROWS_LARGE) || - (this->actor.params == ITEM00_BOMBS_A) || (this->actor.params == ITEM00_BOMBS_B) || - (this->actor.params == ITEM00_NUTS) || (this->actor.params == ITEM00_STICK) || - (this->actor.params == ITEM00_MAGIC_SMALL) || (this->actor.params == ITEM00_SEEDS) || (this->actor.params == ITEM00_SMALL_KEY) || - (this->actor.params == ITEM00_MAGIC_LARGE) || (this->actor.params == ITEM00_HEART) || (this->actor.params == ITEM00_BOMBS_SPECIAL)) { - this->actor.shape.rot.y = DroppedItemRot; - } - } - + if (CVar_GetS32("gNewDrops", 0) !=0) { //set the rotation system on selected model only :) + if ((this->actor.params == ITEM_RUPEE_GOLD) || (this->actor.params == ITEM_RUPEE_PURPLE) || + (this->actor.params == ITEM00_ARROWS_SINGLE) || (this->actor.params == ITEM00_ARROWS_SMALL) || + (this->actor.params == ITEM00_ARROWS_MEDIUM) || (this->actor.params == ITEM00_ARROWS_LARGE) || + (this->actor.params == ITEM00_BOMBS_A) || (this->actor.params == ITEM00_BOMBS_B) || + (this->actor.params == ITEM00_NUTS) || (this->actor.params == ITEM00_STICK) || + (this->actor.params == ITEM00_MAGIC_SMALL) || (this->actor.params == ITEM00_SEEDS) || (this->actor.params == ITEM00_SMALL_KEY) || + (this->actor.params == ITEM00_MAGIC_LARGE) || (this->actor.params == ITEM00_HEART) || (this->actor.params == ITEM00_BOMBS_SPECIAL)) { + this->actor.shape.rot.y = DroppedItemRot; + } + } + if ((this->actor.params <= ITEM00_RUPEE_RED) || ((this->actor.params == ITEM00_HEART) && (this->unk_15A < 0)) || (this->actor.params == ITEM00_HEART_PIECE)) { this->actor.shape.rot.y += 960; @@ -910,9 +714,9 @@ void EnItem00_Update(Actor* thisx, GlobalContext* globalCtx) { EnItem00* this = (EnItem00*)thisx; s32 pad; - if (CVar_GetS32("gNewDrops", 0) !=0) { //Update 3D Model rotation on frame update :) - DroppedItemRot += 250; - } + if (CVar_GetS32("gNewDrops", 0) !=0) { //Update 3D Model rotation on frame update :) + DroppedItemRot += 120; + } if (this->unk_15A > 0) { this->unk_15A--; @@ -1120,40 +924,90 @@ void EnItem00_Update(Actor* thisx, GlobalContext* globalCtx) { void EnItem00_Draw(Actor* thisx, GlobalContext* globalCtx) { EnItem00* this = (EnItem00*)thisx; f32 mtxScale; - + if (!(this->unk_156 & this->unk_158)) { switch (this->actor.params) { case ITEM00_RUPEE_GREEN: - if (CVar_GetS32("gNewDrops", 0) !=0) { - GetItem_Draw(globalCtx, GID_RUPEE_GREEN); - break; - } + if (CVar_GetS32("gNewDrops", 0) !=0) { + Actor_SetScale(&this->actor, 0.3f); + this->scale = 0.3f; + this->actor.shape.yOffset = 50.0f; + this->actor.shape.shadowScale = 0.3f; + this->actor.world.rot.x = 0x4000; + GetItem_Draw(globalCtx, GID_RUPEE_GREEN); + break; + } case ITEM00_RUPEE_BLUE: - if (CVar_GetS32("gNewDrops", 0) !=0) { - GetItem_Draw(globalCtx, GID_RUPEE_BLUE); - break; - } + if (CVar_GetS32("gNewDrops", 0) !=0) { + Actor_SetScale(&this->actor, 0.3f); + this->scale = 0.3f; + this->actor.shape.yOffset = 50.0f; + this->actor.shape.shadowScale = 0.3f; + this->actor.world.rot.x = 0x4000; + GetItem_Draw(globalCtx, GID_RUPEE_BLUE); + break; + } case ITEM00_RUPEE_RED: - if (CVar_GetS32("gNewDrops", 0) !=0) { - GetItem_Draw(globalCtx, GID_RUPEE_RED); - break; - } + if (CVar_GetS32("gNewDrops", 0) !=0) { + Actor_SetScale(&this->actor, 0.3f); + this->scale = 0.3f; + this->actor.shape.yOffset = 50.0f; + this->actor.shape.shadowScale = 0.3f; + this->actor.world.rot.x = 0x4000; + GetItem_Draw(globalCtx, GID_RUPEE_RED); + break; + } else { + this->actor.shape.shadowScale = 6.0f; + Actor_SetScale(&this->actor, 0.015f); + this->scale = 0.015f; + this->actor.shape.yOffset = 750.0f; + EnItem00_DrawRupee(this, globalCtx); + break; + } case ITEM00_RUPEE_ORANGE: - if (CVar_GetS32("gNewDrops", 0) !=0) { - GetItem_Draw(globalCtx, GID_RUPEE_GOLD); - break; - } + if (CVar_GetS32("gNewDrops", 0) !=0) { + Actor_SetScale(&this->actor, 0.45f); + this->scale = 0.45f; + this->actor.shape.yOffset = 50.0f; + this->actor.shape.shadowScale = 0.3f; + this->actor.world.rot.x = 0x4000; + GetItem_Draw(globalCtx, GID_RUPEE_GOLD); + break; + } else { + Actor_SetScale(&this->actor, 0.045 - 1e-10); + this->actor.shape.shadowScale = 6.0f; + this->scale = 0.045 - 1e-10; + this->actor.shape.yOffset = 750.0f; + EnItem00_DrawRupee(this, globalCtx); + break; + } case ITEM00_RUPEE_PURPLE: - if (CVar_GetS32("gNewDrops", 0) !=0) { - GetItem_Draw(globalCtx, GID_RUPEE_PURPLE); - } else { - EnItem00_DrawRupee(this, globalCtx); - } - break; + if (CVar_GetS32("gNewDrops", 0) !=0) { + Actor_SetScale(&this->actor, 0.4f); + this->scale = 0.4f; + this->actor.shape.yOffset = 50.0f; + this->actor.shape.shadowScale = 0.3f; + this->actor.world.rot.x = 0x4000; + GetItem_Draw(globalCtx, GID_RUPEE_PURPLE); + } else { + Actor_SetScale(&this->actor, 0.03f); + this->actor.shape.shadowScale = 6.0f; + this->scale = 0.03f; + this->actor.shape.yOffset = 750.0f; + EnItem00_DrawRupee(this, globalCtx); + break; + } case ITEM00_HEART_PIECE: if (CVar_GetS32("gNewDrops", 0) !=0) { + Actor_SetScale(&this->actor, 0.5f); + this->scale = 0.5f; + this->actor.shape.yOffset = 50.0f; + this->actor.world.rot.x = 0x4000; GetItem_Draw(globalCtx, GID_HEART_PIECE); } else { + this->actor.shape.yOffset = 650.0f; + Actor_SetScale(&this->actor, 0.02f); + this->scale = 0.02f; EnItem00_DrawHeartPiece(this, globalCtx); } break; @@ -1161,89 +1015,163 @@ void EnItem00_Draw(Actor* thisx, GlobalContext* globalCtx) { EnItem00_DrawHeartContainer(this, globalCtx); break; case ITEM00_HEART: - if (CVar_GetS32("gNewDrops", 0) !=0) { - GetItem_Draw(globalCtx, GID_HEART); + if (CVar_GetS32("gNewDrops", 0) !=0) { + this->actor.home.rot.z = Rand_CenteredFloat(65535.0f); + this->actor.shape.yOffset = 25.0f; + Actor_SetScale(&this->actor, 0.3f); + this->scale = 0.3f; + GetItem_Draw(globalCtx, GID_HEART); mtxScale = 16.0f; Matrix_Scale(mtxScale, mtxScale, mtxScale, MTXMODE_APPLY); - break; - } else { - if (this->unk_15A < 0) { - if (this->unk_15A == -1) { - s8 bankIndex = Object_GetIndex(&globalCtx->objectCtx, OBJECT_GI_HEART); - - if (Object_IsLoaded(&globalCtx->objectCtx, bankIndex)) { - this->actor.objBankIndex = bankIndex; - Actor_SetObjectDependency(globalCtx, &this->actor); - this->unk_15A = -2; - } - } else { - mtxScale = 16.0f; - Matrix_Scale(mtxScale, mtxScale, mtxScale, MTXMODE_APPLY); - GetItem_Draw(globalCtx, GID_HEART); - } - break; - } + break; + } else { + this->actor.home.rot.z = Rand_CenteredFloat(65535.0f); + this->actor.shape.yOffset = 430.0f; + Actor_SetScale(&this->actor, 0.02f); + this->scale = 0.02f; + if (this->unk_15A < 0) { + if (this->unk_15A == -1) { + s8 bankIndex = Object_GetIndex(&globalCtx->objectCtx, OBJECT_GI_HEART); + + if (Object_IsLoaded(&globalCtx->objectCtx, bankIndex)) { + this->actor.objBankIndex = bankIndex; + Actor_SetObjectDependency(globalCtx, &this->actor); + this->unk_15A = -2; + } + } else { + mtxScale = 16.0f; + Matrix_Scale(mtxScale, mtxScale, mtxScale, MTXMODE_APPLY); + GetItem_Draw(globalCtx, GID_HEART); + } + break; + } } case ITEM00_BOMBS_A: - if (CVar_GetS32("gNewDrops", 0) !=0) { - GetItem_Draw(globalCtx, GID_BOMB); - break; - } + if (CVar_GetS32("gNewDrops", 0) !=0) { + Actor_SetScale(&this->actor, 0.2f); + this->scale = 0.2f; + this->actor.shape.yOffset = 50.0f; + this->actor.world.rot.x = 0x4000; + this->actor.shape.shadowScale = 0.3f; + GetItem_Draw(globalCtx, GID_BOMB); + break; + } case ITEM00_BOMBS_B: - if (CVar_GetS32("gNewDrops", 0) !=0) { - GetItem_Draw(globalCtx, GID_BOMB); - break; - } + if (CVar_GetS32("gNewDrops", 0) !=0) { + Actor_SetScale(&this->actor, 0.2f); + this->scale = 0.2f; + this->actor.shape.yOffset = 50.0f; + this->actor.world.rot.x = 0x4000; + this->actor.shape.shadowScale = 0.3f; + GetItem_Draw(globalCtx, GID_BOMB); + break; + } case ITEM00_BOMBS_SPECIAL: case ITEM00_ARROWS_SINGLE: - if (CVar_GetS32("gNewDrops", 0) !=0) { - GetItem_Draw(globalCtx, GID_ARROWS_SMALL); - break; + if (CVar_GetS32("gNewDrops", 0) !=0) { + Actor_SetScale(&this->actor, 0.2f); + this->scale = 0.2f; + this->actor.shape.yOffset = 50.0f; + this->actor.world.rot.x = 0x4000; + this->actor.shape.shadowScale = 0.3f; + GetItem_Draw(globalCtx, GID_ARROWS_SMALL); + break; } case ITEM00_ARROWS_SMALL: - if (CVar_GetS32("gNewDrops", 0) !=0) { - GetItem_Draw(globalCtx, GID_ARROWS_SMALL); - break; - } + if (CVar_GetS32("gNewDrops", 0) !=0) { + Actor_SetScale(&this->actor, 0.2f); + this->scale = 0.2f; + this->actor.shape.yOffset = 50.0f; + this->actor.world.rot.x = 0x4000; + this->actor.shape.shadowScale = 0.3f; + GetItem_Draw(globalCtx, GID_ARROWS_SMALL); + break; + } case ITEM00_ARROWS_MEDIUM: - if (CVar_GetS32("gNewDrops", 0) !=0) { - GetItem_Draw(globalCtx, GID_ARROWS_MEDIUM); - break; - } + if (CVar_GetS32("gNewDrops", 0) !=0) { + Actor_SetScale(&this->actor, 0.2f); + this->scale = 0.2f; + this->actor.shape.yOffset = 50.0f; + this->actor.world.rot.x = 0x4000; + this->actor.shape.shadowScale = 0.3f; + GetItem_Draw(globalCtx, GID_ARROWS_MEDIUM); + break; + } case ITEM00_ARROWS_LARGE: - if (CVar_GetS32("gNewDrops", 0) !=0) { - GetItem_Draw(globalCtx, GID_ARROWS_LARGE); - break; - } + if (CVar_GetS32("gNewDrops", 0) !=0) { + Actor_SetScale(&this->actor, 0.2f); + this->scale = 0.2f; + this->actor.shape.yOffset = 50.0f; + this->actor.world.rot.x = 0x4000; + this->actor.shape.shadowScale = 0.3f; + GetItem_Draw(globalCtx, GID_ARROWS_LARGE); + break; + } case ITEM00_NUTS: - if (CVar_GetS32("gNewDrops", 0) !=0) { - GetItem_Draw(globalCtx, GID_NUTS); - break; - } + if (CVar_GetS32("gNewDrops", 0) !=0) { + Actor_SetScale(&this->actor, 0.2f); + this->scale = 0.2f; + this->actor.shape.yOffset = 50.0f; + this->actor.world.rot.x = 0x4000; + this->actor.shape.shadowScale = 0.3f; + GetItem_Draw(globalCtx, GID_NUTS); + break; + } case ITEM00_STICK: - if (CVar_GetS32("gNewDrops", 0) !=0) { - GetItem_Draw(globalCtx, GID_STICK); - break; - } + if (CVar_GetS32("gNewDrops", 0) !=0) { + Actor_SetScale(&this->actor, 0.2f); + this->scale = 0.2f; + this->actor.shape.yOffset = 50.0f; + this->actor.world.rot.x = 0x4000; + this->actor.shape.shadowScale = 0.3f; + GetItem_Draw(globalCtx, GID_STICK); + break; + } case ITEM00_MAGIC_LARGE: - if (CVar_GetS32("gNewDrops", 0) !=0) { - GetItem_Draw(globalCtx, GID_MAGIC_LARGE); - break; - } + if (CVar_GetS32("gNewDrops", 0) !=0) { + Actor_SetScale(&this->actor, 0.2f); + this->scale = 0.2f; + this->actor.shape.yOffset = 50.0f; + this->actor.world.rot.x = 0x4000; + this->actor.shape.shadowScale = 0.3f; + GetItem_Draw(globalCtx, GID_MAGIC_LARGE); + break; + } case ITEM00_MAGIC_SMALL: - if (CVar_GetS32("gNewDrops", 0) !=0) { - GetItem_Draw(globalCtx, GID_MAGIC_SMALL); - break; - } + if (CVar_GetS32("gNewDrops", 0) !=0) { + Actor_SetScale(&this->actor, 0.2f); + this->scale = 0.2f; + this->actor.shape.yOffset = 50.0f; + this->actor.shape.shadowScale = 0.3f; + this->actor.world.rot.x = 0x4000; + GetItem_Draw(globalCtx, GID_MAGIC_SMALL); + break; + } case ITEM00_SEEDS: - if (CVar_GetS32("gNewDrops", 0) !=0) { - GetItem_Draw(globalCtx, GID_SEEDS); - break; - } + if (CVar_GetS32("gNewDrops", 0) !=0) { + Actor_SetScale(&this->actor, 0.2f); + this->scale = 0.2f; + this->actor.shape.yOffset = 50.0f; + this->actor.shape.shadowScale = 0.3f; + this->actor.world.rot.x = 0x4000; + GetItem_Draw(globalCtx, GID_SEEDS); + break; + } case ITEM00_SMALL_KEY: - if (CVar_GetS32("gNewDrops", 0) !=0) { + if (CVar_GetS32("gNewDrops", 0) !=0) { + Actor_SetScale(&this->actor, 0.2f); + this->scale = 0.2f; + this->actor.shape.yOffset = 50.0f; + this->actor.world.rot.x = 0x4000; + this->actor.shape.shadowScale = 0.5f; GetItem_Draw(globalCtx, GID_KEY_SMALL); - } else { + } else { + Actor_SetScale(&this->actor, 0.03f); + this->scale = 0.03f; + this->actor.shape.yOffset = 320.0f; + this->actor.shape.shadowScale = 6.0f; + this->actor.world.rot.x = 0; + this->actor.shape.rot.y = 0; EnItem00_DrawCollectible(this, globalCtx); } break; From a1f92d76ab5b60d29b07b0332dbfb6936bff74f7 Mon Sep 17 00:00:00 2001 From: vaguerant Date: Fri, 8 Jul 2022 12:19:41 +1000 Subject: [PATCH 06/44] Fix Ganon's Castle title cards (#606) --- soh/src/code/z_actor.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/soh/src/code/z_actor.c b/soh/src/code/z_actor.c index 79ae75d56..6c755966a 100644 --- a/soh/src/code/z_actor.c +++ b/soh/src/code/z_actor.c @@ -843,9 +843,12 @@ void TitleCard_InitPlaceName(GlobalContext* globalCtx, TitleCardContext* titleCt case SCENE_GERUDOWAY: texture = gThievesHideoutTitleCardENGTex; break; - case SCENE_GANONTIKA: + case SCENE_GANON_TOU: texture = gGanonsCastleTitleCardENGTex; break; + case SCENE_GANONTIKA: + texture = gInsideGanonsCastleTitleCardENGTex; + break; case SCENE_TAKARAYA: texture = gTreasureBoxShopTitleCardENGTex; break; From ee184b5a5162320c543493841975725324e02943 Mon Sep 17 00:00:00 2001 From: Sirius902 <10891979+Sirius902@users.noreply.github.com> Date: Thu, 7 Jul 2022 19:21:14 -0700 Subject: [PATCH 07/44] Checkered room crash workaround (#615) * Increase poly and vertex count for dyna actors * Add TODO * Only apply fix in Forest Temple * Enable globally --- soh/src/code/z_bgcheck.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/soh/src/code/z_bgcheck.c b/soh/src/code/z_bgcheck.c index 91d3951ca..6b5c2f613 100644 --- a/soh/src/code/z_bgcheck.c +++ b/soh/src/code/z_bgcheck.c @@ -1584,9 +1584,19 @@ void BgCheck_Allocate(CollisionContext* colCtx, GlobalContext* globalCtx, Collis BgCheck_SetSubdivisionDimension(colCtx->minBounds.z, colCtx->subdivAmount.z, &colCtx->maxBounds.z, &colCtx->subdivLength.z, &colCtx->subdivLengthInv.z); -#ifdef _SOH64 // BGCheck needs more memory on 64 bits because it crashes on some areas +// OTRTODO: Re-enable when the below DynaPoly workaround is removed. +// #ifdef _SOH64 // BGCheck needs more memory on 64 bits because it crashes on some areas +// colCtx->memSize *= 2; +// #endif + + // BGCheck needs a higher polygon and vertex count due to removed object dependencies. + // Otherwise Forest Temple checkered room will crash due to the hallway actor being killed a frame late. + // + // OTRTODO: This is a workaround. The proper solution to fix this crash is to manage object loading / unloading + // the same as N64. colCtx->memSize *= 2; -#endif + colCtx->dyna.polyListMax *= 2; + colCtx->dyna.vtxListMax *= 2; memSize = colCtx->subdivAmount.x * sizeof(StaticLookup) * colCtx->subdivAmount.y * colCtx->subdivAmount.z + colCtx->colHeader->numPolygons * sizeof(u8) + colCtx->dyna.polyNodesMax * sizeof(SSNode) + From ef3dd96eb45eb09498f58cecbf6b588b77ebe30d Mon Sep 17 00:00:00 2001 From: modestposer Date: Fri, 8 Jul 2022 17:39:21 -0400 Subject: [PATCH 08/44] Match case of 'Shipwright' in Linux build (#619) --- BUILDING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUILDING.md b/BUILDING.md index d6ffb26bf..4e2f35616 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -22,7 +22,7 @@ ```bash # Clone the repo git clone https://github.com/HarbourMasters/Shipwright.git -cd ShipWright +cd Shipwright # Copy the baserom to the OTRExporter folder cp OTRExporter # Build the docker image From 4371b582232ab034e2dd8b0f03ee21e3832b14ad Mon Sep 17 00:00:00 2001 From: Sirius902 <10891979+Sirius902@users.noreply.github.com> Date: Fri, 8 Jul 2022 14:39:50 -0700 Subject: [PATCH 09/44] Fix 0xabababab crash (#617) * Unconditionally setup the normal skybox * Only call Skybox_Setup once ever --- soh/src/code/graph.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/soh/src/code/graph.c b/soh/src/code/graph.c index f4a824cb4..f4dcf56e8 100644 --- a/soh/src/code/graph.c +++ b/soh/src/code/graph.c @@ -433,6 +433,7 @@ static void RunFrame() { u32 size; char faultMsg[0x50]; + static bool hasSetupSkybox = false; switch (runFrameContext.state) { case 0: @@ -465,6 +466,14 @@ static void RunFrame() } GameState_Init(runFrameContext.gameState, runFrameContext.ovl->init, &runFrameContext.gfxCtx); + // Setup the normal skybox once before entering any game states to avoid the 0xabababab crash. + // The crash is due to certain skyboxes not loading all the data they need from Skybox_Setup. + if (!hasSetupSkybox) { + GlobalContext* globalCtx = (GlobalContext*)runFrameContext.gameState; + Skybox_Setup(globalCtx, &globalCtx->skyboxCtx, SKYBOX_NORMAL_SKY); + hasSetupSkybox = true; + } + uint64_t freq = GetFrequency(); while (GameState_IsRunning(runFrameContext.gameState)) From 42383a1fe11dadd4fcdebae8396cc96219fb4fb8 Mon Sep 17 00:00:00 2001 From: Sirius902 <10891979+Sirius902@users.noreply.github.com> Date: Fri, 8 Jul 2022 20:06:11 -0700 Subject: [PATCH 10/44] Equipment upgrade text fix and any pause slot enhancement fix (#620) * Fix upgrade name text not rendering * Use cvar and don't render equip help for empty item slots * Fix rendering logic * Fix incorrect item name rendered for one frame * Reorder comparison * Remove extra indent * Remove accidental changes --- .../misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c index c126ec600..efb97f747 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c @@ -1817,13 +1817,8 @@ void KaleidoScope_DrawInfoPanel(GlobalContext* globalCtx) { } else { gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 255, 255); } - //TOOD CVAR - if (((CHECK_OWNED_EQUIP(pauseCtx->cursorY[PAUSE_EQUIP], pauseCtx->cursorX[PAUSE_EQUIP] - 1)) || - (pauseCtx->pageIndex != PAUSE_EQUIP) && (pauseCtx->cursorX[PAUSE_EQUIP] != 0)) && (pauseCtx->pageIndex != PAUSE_ITEM || - (gSaveContext.inventory.items[pauseCtx->cursorPoint[PAUSE_ITEM]] != ITEM_NONE))) { - POLY_KAL_DISP = KaleidoScope_QuadTextureIA4(POLY_KAL_DISP, pauseCtx->nameSegment, 128, 16, 0); - } + POLY_KAL_DISP = KaleidoScope_QuadTextureIA4(POLY_KAL_DISP, pauseCtx->nameSegment, 128, 16, 0); } if (pauseCtx->pageIndex == PAUSE_MAP && CVar_GetS32("gDebugEnabled", 0) != 0) { @@ -1929,7 +1924,7 @@ void KaleidoScope_DrawInfoPanel(GlobalContext* globalCtx) { } } } else { - if (!pauseCtx->pageIndex) { // pageIndex == PAUSE_ITEM + if (!pauseCtx->pageIndex && (!CVar_GetS32("gPauseAnyCursor", 0) || (gSaveContext.inventory.items[pauseCtx->cursorPoint[PAUSE_ITEM]] != ITEM_NONE))) { // pageIndex == PAUSE_ITEM pauseCtx->infoPanelVtx[16].v.ob[0] = pauseCtx->infoPanelVtx[18].v.ob[0] = WREG(49 + gSaveContext.language); @@ -2098,6 +2093,12 @@ void KaleidoScope_UpdateNamePanel(GlobalContext* globalCtx) { osCreateMesgQueue(&pauseCtx->loadQueue, &pauseCtx->loadMsg, 1); + if (CVar_GetS32("gPauseAnyCursor", 0) && + ((pauseCtx->pageIndex == PAUSE_EQUIP && pauseCtx->cursorX[PAUSE_EQUIP] != 0 && !CHECK_OWNED_EQUIP(pauseCtx->cursorY[PAUSE_EQUIP], pauseCtx->cursorX[PAUSE_EQUIP] - 1)) || + (pauseCtx->pageIndex == PAUSE_ITEM && gSaveContext.inventory.items[pauseCtx->cursorPoint[PAUSE_ITEM]] == ITEM_NONE))) { + pauseCtx->namedItem = PAUSE_ITEM_NONE; + } + if (pauseCtx->namedItem != PAUSE_ITEM_NONE) { if ((pauseCtx->pageIndex == PAUSE_MAP) && !sInDungeonScene) { if (gSaveContext.language) { From 24856a6e8cdfd04f80b0f02bb2635620f49d646f Mon Sep 17 00:00:00 2001 From: Ada <60364512+GreatArgorath@users.noreply.github.com> Date: Sun, 10 Jul 2022 01:37:38 +0100 Subject: [PATCH 11/44] ImGui grammer, consistency, and clarity fixes (#625) * ImGui grammer, consistency, and clarity fixes Co-Authored-By: Stormghetti <56653191+Stormghetti@users.noreply.github.com> * Adds more new lines for users on smaller displays Co-Authored-By: Stormghetti <56653191+Stormghetti@users.noreply.github.com> Co-authored-by: Stormghetti <56653191+Stormghetti@users.noreply.github.com> --- libultraship/libultraship/ImGuiImpl.cpp | 87 +++++++++++++------------ 1 file changed, 45 insertions(+), 42 deletions(-) diff --git a/libultraship/libultraship/ImGuiImpl.cpp b/libultraship/libultraship/ImGuiImpl.cpp index a9aaa7fb9..1886823c7 100644 --- a/libultraship/libultraship/ImGuiImpl.cpp +++ b/libultraship/libultraship/ImGuiImpl.cpp @@ -632,7 +632,7 @@ namespace SohImGui { CVar_SetS32(Cvar_RBM.c_str(), 0); //On click disable rainbow mode. needs_save = true; } - Tooltip("Revert colors to the game original colors (GameCube version)\nOverwrites previously chosen color"); + Tooltip("Revert colors to the game's original colors (GameCube version)\nOverwrites previously chosen color"); } void EnhancementColor(const char* text, const char* cvarName, ImVec4 ColorRGBA, ImVec4 default_colors, bool allow_rainbow, bool has_alpha, bool TitleSameLine) { @@ -718,7 +718,7 @@ namespace SohImGui { ImGui::DockBuilderRemoveNode(dockId); ImGui::DockBuilderAddNode(dockId, ImGuiDockNodeFlags_NoTabBar); - ImGui::DockBuilderDockWindow("OoT Master Quest", dockId); + ImGui::DockBuilderDockWindow("Main Game", dockId); ImGui::DockBuilderFinish(dockId); } @@ -806,6 +806,7 @@ namespace SohImGui { EnhancementCheckbox("D-pad Support in Ocarina and Text Choice", "gDpadOcarinaText"); EnhancementCheckbox("D-pad Support for Browsing Shop Items", "gDpadShop"); EnhancementCheckbox("D-pad as Equip Items", "gDpadEquips"); + Tooltip("Allows the D-pad to be used as extra C buttons\nNote: Incompatible with D-pad on pause and file select"); ImGui::Separator(); @@ -814,7 +815,7 @@ namespace SohImGui { EnhancementCheckbox("Rumble Enabled", "gRumbleEnabled"); EnhancementSliderFloat("Input Scale: %.1f", "##Input", "gInputScale", 1.0f, 3.0f, "", 1.0f, false); - Tooltip("Sets the on screen size of the displayed inputs from Show Inputs"); + Tooltip("Sets the on screen size of the displayed inputs from the Show Inputs setting"); ImGui::Separator(); @@ -853,10 +854,10 @@ namespace SohImGui { if (ImGui::BeginMenu("Graphics")) { EnhancementSliderInt("Internal Resolution: %dx", "##IMul", "gInternalResolution", 1, 8, ""); - Tooltip("Increases the render resolution of the game, up to 8x your output resolution,\nas a more intensive but effective form of anti-aliasing"); + Tooltip("Multiplies your output resolution by the value inputted,\nas a more intensive but effective form of anti-aliasing"); gfx_current_dimensions.internal_mul = CVar_GetS32("gInternalResolution", 1); EnhancementSliderInt("MSAA: %d", "##IMSAA", "gMSAAValue", 1, 8, ""); - Tooltip("Activates anti-aliasing when above 1, up to 8x for 8 samples for every pixel"); + Tooltip("Activates multi-sample anti-aliasing when above 1x\nup to 8x for 8 samples for every pixel"); gfx_msaa_level = CVar_GetS32("gMSAAValue", 1); if (impl.backend == Backend::DX11) @@ -882,9 +883,11 @@ namespace SohImGui { } Tooltip("When Interpolation FPS setting is at least this threshold,\n" - "add one frame of input lag (e.g. 16.6 ms for 60 FPS) in order to avoid jitter.\n" - "This setting allows the CPU to work on one frame while GPU works on the previous frame.\n" - "This setting should be used when your computer is too slow to do CPU + GPU work in time."); + "add one frame of input lag (e.g. 16.6 ms for 60 FPS)\n" + "in order to avoid jitter.This setting allows the CPU\n" + "to work on one frame while GPU works on the previous frame.\n" + "This setting should be used when your computer is too slow\n" + "to do CPU + GPU work in time."); } EXPERIMENTAL(); @@ -912,22 +915,22 @@ namespace SohImGui { EnhancementSliderInt("Text Speed: %dx", "##TEXTSPEED", "gTextSpeed", 1, 5, ""); EnhancementSliderInt("King Zora Speed: %dx", "##MWEEPSPEED", "gMweepSpeed", 1, 5, ""); EnhancementSliderInt("Biggoron Forge Time: %d days", "##FORGETIME", "gForgeTime", 0, 3, ""); - Tooltip("Allows you to change the number of days it takes for Biggoron to forge the Biggoron Sword"); + Tooltip("Allows you to change the number of days it takes for\nBiggoron to forge the Biggoron Sword"); EnhancementSliderInt("Vine/Ladder Climb speed +%d", "##CLIMBSPEED", "gClimbSpeed", 0, 12, ""); EnhancementCheckbox("Faster Block Push", "gFasterBlockPush"); EnhancementCheckbox("No Forced Navi", "gNoForcedNavi"); Tooltip("Prevent forced Navi conversations"); EnhancementCheckbox("No Skulltula Freeze", "gSkulltulaFreeze"); - Tooltip("Stops the game from freezing the player when picking up Gold Skulltulas"); + Tooltip("Stops the game from freezing the player\nwhen picking up Gold Skulltulas"); EnhancementCheckbox("MM Bunny Hood", "gMMBunnyHood"); - Tooltip("Wearing the Bunny Hood grants a speed increase like in Majora's Mask"); + Tooltip("Wearing the Bunny Hood grants a speed\nincrease like in Majora's Mask"); EnhancementCheckbox("Fast Chests", "gFastChests"); Tooltip("Kick open every chest"); EnhancementCheckbox("Fast Drops", "gFastDrops"); Tooltip("Skip first-time pickup messages for consumable items"); EnhancementCheckbox("Better Owl", "gBetterOwl"); - Tooltip("The default response to Kaepora Gaebora is always that you understood what he said"); + Tooltip("The default response to Kaepora Gaebora is\nalways that you understood what he said"); ImGui::EndMenu(); } @@ -939,12 +942,12 @@ namespace SohImGui { EnhancementSliderInt("Fall Damage Multiplier %dx", "##FALLDAMAGEMUL", "gFallDamageMul", 1, 4, ""); Tooltip("Modifies all fall damage"); EnhancementSliderInt("Void Damage Multiplier %dx", "##VOIDDAMAGEMUL", "gVoidDamageMul", 1, 4, ""); - Tooltip("Modifies all void out damage"); + Tooltip("Modifies damage taken after falling into a void"); EnhancementCheckbox("No Random Drops", "gNoRandomDrops"); Tooltip("Disables random drops, except from the Goron Pot, Dampe, and bosses"); EnhancementCheckbox("No Heart Drops", "gNoHeartDrops"); - Tooltip("Disables heart drops, but not heart placements, like from a Deku Scrub running off. This simulates Hero Mode from other games in the series."); + Tooltip("Disables heart drops, but not heart placements, like from a Deku Scrub running off\nThis simulates Hero Mode from other games in the series"); if (ImGui::BeginMenu("Potion Values")) { @@ -982,7 +985,7 @@ namespace SohImGui { Tooltip("Toggles from Milk restoring a fixed amount of health to a percent of the player's current max health"); EnhancementCheckbox("Separate Half Milk Effect", "gSeparateHalfMilkEffect"); - Tooltip("Enable the following changes to the amount of health restored by Half Milk.\nIf this is disabled, Half Milk will behave the same as Full Milk."); + Tooltip("Enable the following changes to the amount of health restored by Half Milk\nIf this is disabled, Half Milk will behave the same as Full Milk."); EnhancementSliderInt("Half Milk Health: %d", "##HALFMILKHEALTH", "gHalfMilkHealth", 1, 100, ""); Tooltip("Changes the amount of health restored by Half Milk"); EnhancementCheckbox("Half Milk Percent Restore", "gHalfMilkPercentRestore"); @@ -1013,7 +1016,7 @@ namespace SohImGui { EnhancementCheckbox("Mute Low HP Alarm", "gLowHpAlarm"); Tooltip("Disable the low HP beeping sound"); EnhancementCheckbox("Minimal UI", "gMinimalUI"); - Tooltip("Hides most of the UI when not needed"); + Tooltip("Hides most of the UI when not needed\nNote: Doesn't activate until after loading a new scene"); EnhancementCheckbox("Disable Navi Call Audio", "gDisableNaviCallAudio"); Tooltip("Disables the voice audio when Navi calls you"); @@ -1021,15 +1024,15 @@ namespace SohImGui { } EnhancementCheckbox("Visual Stone of Agony", "gVisualAgony"); - Tooltip("Displays an icon and plays a sound when Stone of Agony should be activated, for those without rumble"); + Tooltip("Displays an icon and plays a sound when Stone of Agony\nshould be activated, for those without rumble"); EnhancementCheckbox("Assignable Tunics and Boots", "gAssignableTunicsAndBoots"); Tooltip("Allows equipping the tunic and boots to c-buttons"); EnhancementCheckbox("Link's Cow in Both Time Periods", "gCowOfTime"); - Tooltip("Allows the Lon Lon Ranch obstacle course reward to be shared across time periods"); + Tooltip("Allows the Lon Lon Ranch obstacle course reward to be\nshared across time periods"); EnhancementCheckbox("Enable visible guard vision", "gGuardVision"); EnhancementCheckbox("Enable passage of time on file select", "gTimeFlowFileSelect"); EnhancementCheckbox("Allow the cursor to be on any slot", "gPauseAnyCursor"); - Tooltip("Allows the cursor on the pause menu to be over any slot. Similar to Rando and Spaceworld 97"); + Tooltip("Allows the cursor on the pause menu to be over any slot\nSimilar to Rando and Spaceworld 97"); ImGui::EndMenu(); } @@ -1078,9 +1081,9 @@ namespace SohImGui { EnhancementCheckbox("N64 Mode", "gN64Mode"); Tooltip("Sets aspect ratio to 4:3 and lowers resolution to 240p, the N64's native resolution"); EnhancementCheckbox("Enable 3D Dropped items/projectiles", "gNewDrops"); - Tooltip("Change most 2D items & projectiles to their a 3D version"); + Tooltip("Change most 2D items and projectiles on the overworld to their 3D versions"); EnhancementCheckbox("Disable Black Bar Letterboxes", "gDisableBlackBars"); - Tooltip("Disables Black Bar Letterboxes during cutscenes and Z-targeting\nNote: there may be minor visual glitches that were covered up by the black bars\nPlease disable this setting before reporting a bug"); + Tooltip("Disables Black Bar Letterboxes during cutscenes and Z-targeting\nNote: there may be minor visual glitches that\nwere covered up by the black bars\nPlease disable this setting before reporting a bug"); EnhancementCheckbox("Dynamic Wallet Icon", "gDynamicWalletIcon"); Tooltip("Changes the rupee in the wallet icon to match the wallet size you currently have"); EnhancementCheckbox("Always show dungeon entrances", "gAlwaysShowDungeonMinimapIcon"); @@ -1094,19 +1097,19 @@ namespace SohImGui { EnhancementCheckbox("Fix L&R Pause menu", "gUniformLR"); Tooltip("Makes the L and R buttons in the pause menu the same color"); EnhancementCheckbox("Fix L&Z Page switch in Pause menu", "gNGCKaleidoSwitcher"); - Tooltip("Enabling it make L and R be your page switch like on Gamecube\nZ become the button to open Debug Menu"); + Tooltip("Makes L and R switch pages like on the GameCube\nZ opens the Debug Menu instead"); EnhancementCheckbox("Fix Dungeon entrances", "gFixDungeonMinimapIcon"); - Tooltip("Show dungeon entrances icon only when it should be"); + Tooltip("Removes the dungeon entrance icon on the top-left corner\nof the screen when no dungeon is present on the current map"); EnhancementCheckbox("Fix Two Handed idle animations", "gTwoHandedIdle"); - Tooltip("Makes two handed idle animation play, a seemingly finished animation that was disabled on accident in the original game"); + Tooltip("Re-enables the two-handed idle animation, a seemingly\nfinished animation that was disabled on accident in the original game"); EnhancementCheckbox("Fix the Gravedigging Tour Glitch", "gGravediggingTourFix"); - Tooltip("Fixes a bug where you can permanently miss the Gravedigging Tour Heart Piece"); + Tooltip("Fixes a bug where the Gravedigging Tour Heart\nPiece disappears if the area reloads"); EnhancementCheckbox("Fix Deku Nut upgrade", "gDekuNutUpgradeFix"); - Tooltip("Prevents the Forest Stage Deku Nut upgrade from becoming unobtainable after receiving the Poacher's Saw"); + Tooltip("Prevents the Forest Stage Deku Nut upgrade from\nbecoming unobtainable after receiving the Poacher's Saw"); EnhancementCheckbox("Fix Navi text HUD position", "gNaviTextFix"); Tooltip("Correctly centers the Navi text prompt on the HUD's C-Up button"); EnhancementCheckbox("Fix Anubis fireballs", "gAnubisFix"); - Tooltip("Make Anubis fireballs do fire damage when reflected back at them with the Mirror Shield"); + Tooltip("Make Anubis fireballs do fire damage when reflected\nback at them with the Mirror Shield"); ImGui::EndMenu(); } @@ -1116,11 +1119,11 @@ namespace SohImGui { EnhancementCheckbox("Red Ganon blood", "gRedGanonBlood"); Tooltip("Restore the original red blood from NTSC 1.0/1.1. Disable for green blood"); EnhancementCheckbox("Fish while hovering", "gHoverFishing"); - Tooltip("Restore a bug from NTSC 1.0 that allows casting the Fishing Rod while using the Hover Boots"); + Tooltip("Restore a bug from NTSC 1.0 that allows casting\nthe Fishing Rod while using the Hover Boots"); EnhancementCheckbox("N64 Weird Frames", "gN64WeirdFrames"); Tooltip("Restores N64 Weird Frames allowing weirdshots to behave the same as N64"); EnhancementCheckbox("Bombchus out of bounds", "gBombchusOOB"); - Tooltip("Allows bombchus to explode out of bounds similar to GameCube and Wii VC"); + Tooltip("Allows bombchus to explode out of bounds\nSimilar to GameCube and Wii VC"); ImGui::EndMenu(); } @@ -1148,12 +1151,12 @@ namespace SohImGui { needs_save = true; } - Tooltip("Interpolate extra frames to get smoother graphics.\n" - "Set to match your monitor's refresh rate, or a divisor of it.\n" + Tooltip("Interpolate extra frames to get smoother graphics\n" + "Set to match your monitor's refresh rate, or a divisor of it\n" "A higher target FPS than your monitor's refresh rate will just waste resources,\n" "and might give a worse result.\n" - "For consistent input lag, set this value and your monitor's refresh rate to a multiple of 20.\n" - "Ctrl+Click for keyboard input."); + "For consistent input lag, set this value and your monitor's refresh rate to a multiple of 20\n" + "Ctrl+Click for keyboard input"); } if (impl.backend == Backend::DX11) { @@ -1168,17 +1171,17 @@ namespace SohImGui { } } EnhancementCheckbox("Disable LOD", "gDisableLOD"); - Tooltip("Turns off the level of detail setting, making models always use their higher poly variants"); + Tooltip("Turns off the Level of Detail setting, making models use their higher-poly variants at any distance"); EnhancementCheckbox("Disable Draw Distance", "gDisableDrawDistance"); - Tooltip("Turns off the objects draw distance, making objects being visible from a longer range"); + Tooltip("Turns off the objects draw distance,\nmaking objects being visible from a longer range"); if (CVar_GetS32("gDisableDrawDistance", 0) == 0) { CVar_SetS32("gDisableKokiriDrawDistance", 0); } else if (CVar_GetS32("gDisableDrawDistance", 0) == 1) { EnhancementCheckbox("Kokiri Draw Distance", "gDisableKokiriDrawDistance"); - Tooltip("Kokiris are mystical being that appear from a certain distance\nEnable this will remove their draw distance"); + Tooltip("The Kokiri are mystical beings that fade into view when approached\nEnabling this will remove their draw distance"); } EnhancementCheckbox("Skip Text", "gSkipText"); - Tooltip("Holding down B skips text.\nKnown to cause a cutscene softlock in Water Temple.\nSoftlock can be fixed by pressing D-Right in Debug mode."); + Tooltip("Holding down B skips text\nKnown to cause a cutscene softlock in Water Temple\nSoftlock can be fixed by pressing D-Right in Debug mode"); ImGui::EndMenu(); } @@ -1205,7 +1208,7 @@ namespace SohImGui { EnhancementCheckbox("Super Tunic", "gSuperTunic"); Tooltip("Makes every tunic have the effects of every other tunic"); EnhancementCheckbox("Easy ISG", "gEzISG"); - Tooltip("Automatically activates the Infinite Sword glitch, making you constantly swing your sword"); + Tooltip("Passive Infinite Sword Glitch\nIt makes your sword's swing effect and hitbox stay active indefinitely"); EnhancementCheckbox("Unrestricted Items", "gNoRestrictItems"); Tooltip("Allows you to use any item at any location"); EnhancementCheckbox("Freeze Time", "gFreezeTime"); @@ -1215,7 +1218,7 @@ namespace SohImGui { EnhancementCheckbox("Fireproof Deku Shield", "gFireproofDekuShield"); Tooltip("Prevents the Deku Shield from burning on contact with fire"); EnhancementCheckbox("Shield with Two-Handed Weapons", "gShieldTwoHanded"); - Tooltip("Allows Link to shield normally with two-handed swords and the Megaton Hammer"); + Tooltip("This allows you to put up your shield with any two-handed weapon in hand"); ImGui::EndMenu(); } @@ -1225,15 +1228,15 @@ namespace SohImGui { EnhancementCheckbox("OoT Debug Mode", "gDebugEnabled"); Tooltip("Enables Debug Mode, allowing you to select maps with L + R + Z, noclip with L + D-pad Right,\nand open the debug menu with L on the pause screen"); EnhancementCheckbox("Fast File Select", "gSkipLogoTitle"); - Tooltip("Directly load the game to selected slot bellow\nUse slot number 4 to load directly in Zelda Map Select\n(Do not require debug menu but you will be unable to save there)\n(you can also load Zelda map select with Debug mod + slot 0).\nWith Slot : 0 you can go directly in File Select menu\nAttention, Loading an empty save will result in crash"); + Tooltip("Load the game to the selected slot below upon launch\nUse slot number 4 to load directly into the game's internal Map Select\n(Does not require the Debug Menu, but you will be unable to save there\nYou can also load the Map Select with OoT Debug Mode + slot 0)\nWith slot 0 you can directly go to the File Select menu\nAttention: loading an empty save file will result in a crash"); if (CVar_GetS32("gSkipLogoTitle", 0)) { EnhancementSliderInt("Loading %d", "##SaveFileID", "gSaveFileID", 0, 4, ""); } ImGui::Separator(); EnhancementCheckbox("Stats", "gStatsEnabled"); - Tooltip("Shows the stats window, with your FPS and frametimes, and the OS you're playing on"); + Tooltip("Shows the stats window, with your FPS and frametimes,\nand the OS you're playing on"); EnhancementCheckbox("Console", "gConsoleEnabled"); - Tooltip("Enables the console window, allowing you to input commands, type help for some examples"); + Tooltip("Enables the console window, allowing you to input commands,\ntype help for some examples"); console->opened = CVar_GetS32("gConsoleEnabled", 0); ImGui::EndMenu(); From d1a2f98524428c6b476b4994429884fd046b2a25 Mon Sep 17 00:00:00 2001 From: Baoulettes Date: Sun, 10 Jul 2022 02:38:59 +0200 Subject: [PATCH 12/44] New drops shadows & rotation fixes (#627) * fixes * forgot to add heart pieces in rotation logic --- soh/src/code/z_en_item00.c | 111 +++++++++++++++++++------------------ 1 file changed, 56 insertions(+), 55 deletions(-) diff --git a/soh/src/code/z_en_item00.c b/soh/src/code/z_en_item00.c index d5e6071bb..69e0c64b4 100644 --- a/soh/src/code/z_en_item00.c +++ b/soh/src/code/z_en_item00.c @@ -5,9 +5,6 @@ #define FLAGS 0 -//Used to force variable to be used in different function, feel free to correct me if you have a better way -static s16 DroppedItemRot = 0; - void EnItem00_Init(Actor* thisx, GlobalContext* globalCtx); void EnItem00_Destroy(Actor* thisx, GlobalContext* globalCtx); void EnItem00_Update(Actor* thisx, GlobalContext* globalCtx); @@ -525,40 +522,30 @@ void EnItem00_Destroy(Actor* thisx, GlobalContext* globalCtx) { void func_8001DFC8(EnItem00* this, GlobalContext* globalCtx) { - if (CVar_GetS32("gNewDrops", 0) !=0) { //set the rotation system on selected model only :) - if ((this->actor.params == ITEM_RUPEE_GOLD) || (this->actor.params == ITEM_RUPEE_PURPLE) || - (this->actor.params == ITEM00_ARROWS_SINGLE) || (this->actor.params == ITEM00_ARROWS_SMALL) || - (this->actor.params == ITEM00_ARROWS_MEDIUM) || (this->actor.params == ITEM00_ARROWS_LARGE) || - (this->actor.params == ITEM00_BOMBS_A) || (this->actor.params == ITEM00_BOMBS_B) || - (this->actor.params == ITEM00_NUTS) || (this->actor.params == ITEM00_STICK) || - (this->actor.params == ITEM00_MAGIC_SMALL) || (this->actor.params == ITEM00_SEEDS) || (this->actor.params == ITEM00_SMALL_KEY) || - (this->actor.params == ITEM00_MAGIC_LARGE) || (this->actor.params == ITEM00_HEART) || (this->actor.params == ITEM00_BOMBS_SPECIAL)) { - this->actor.shape.rot.y = DroppedItemRot; - } - } - - if ((this->actor.params <= ITEM00_RUPEE_RED) || ((this->actor.params == ITEM00_HEART) && (this->unk_15A < 0)) || - (this->actor.params == ITEM00_HEART_PIECE)) { - this->actor.shape.rot.y += 960; - } else { - if ((this->actor.params >= ITEM00_SHIELD_DEKU) && (this->actor.params != ITEM00_BOMBS_SPECIAL)) { - if (this->unk_15A == -1) { - if (Math_SmoothStepToS(&this->actor.shape.rot.x, this->actor.world.rot.x - 0x4000, 2, 3000, 1500) == - 0) { - this->unk_15A = -2; - } - } else { - if (Math_SmoothStepToS(&this->actor.shape.rot.x, -this->actor.world.rot.x - 0x4000, 2, 3000, 1500) == - 0) { - this->unk_15A = -1; + if (!CVar_GetS32("gNewDrops", 0)){ + if ((this->actor.params <= ITEM00_RUPEE_RED) || ((this->actor.params == ITEM00_HEART) && (this->unk_15A < 0)) || + (this->actor.params == ITEM00_HEART_PIECE)) { + this->actor.shape.rot.y += 960; + } else { + if ((this->actor.params >= ITEM00_SHIELD_DEKU) && (this->actor.params != ITEM00_BOMBS_SPECIAL)) { + if (this->unk_15A == -1) { + if (Math_SmoothStepToS(&this->actor.shape.rot.x, this->actor.world.rot.x - 0x4000, 2, 3000, 1500) == + 0) { + this->unk_15A = -2; + } + } else { + if (Math_SmoothStepToS(&this->actor.shape.rot.x, -this->actor.world.rot.x - 0x4000, 2, 3000, 1500) == + 0) { + this->unk_15A = -1; + } } + Math_SmoothStepToS(&this->actor.world.rot.x, 0, 2, 2500, 500); } - Math_SmoothStepToS(&this->actor.world.rot.x, 0, 2, 2500, 500); } } if (this->actor.params == ITEM00_HEART_PIECE) { - if (CVar_GetS32("gNewDrops", 0) !=0) { + if (CVar_GetS32("gNewDrops", 0)) { this->actor.shape.yOffset = Math_SinS(this->actor.shape.rot.y) * 20.0f + 50.0f; } else { this->actor.shape.yOffset = Math_SinS(this->actor.shape.rot.y) * 150.0f + 850.0f; @@ -590,7 +577,7 @@ void func_8001E1C8(EnItem00* this, GlobalContext* globalCtx) { f32 originalVelocity; Vec3f effectPos; - if (this->actor.params <= ITEM00_RUPEE_RED) { + if (this->actor.params <= ITEM00_RUPEE_RED && !CVar_GetS32("gNewDrops", 0)) { this->actor.shape.rot.y += 960; } @@ -688,9 +675,9 @@ void func_8001E5C8(EnItem00* this, GlobalContext* globalCtx) { this->actor.world.pos = player->actor.world.pos; - if (this->actor.params <= ITEM00_RUPEE_RED) { + if (this->actor.params <= ITEM00_RUPEE_RED && !CVar_GetS32("gNewDrops", 0)) { this->actor.shape.rot.y += 960; - } else if (this->actor.params == ITEM00_HEART) { + } else if (this->actor.params == ITEM00_HEART && !CVar_GetS32("gNewDrops", 0)) { this->actor.shape.rot.y = 0; } @@ -714,8 +701,18 @@ void EnItem00_Update(Actor* thisx, GlobalContext* globalCtx) { EnItem00* this = (EnItem00*)thisx; s32 pad; - if (CVar_GetS32("gNewDrops", 0) !=0) { //Update 3D Model rotation on frame update :) - DroppedItemRot += 120; + if (CVar_GetS32("gNewDrops", 0)) { //set the rotation system on selected model only :) + + if ((this->actor.params == ITEM00_RUPEE_GREEN) || (this->actor.params == ITEM00_RUPEE_BLUE) || + (this->actor.params == ITEM00_RUPEE_RED) || (this->actor.params == ITEM00_ARROWS_SINGLE) || + (this->actor.params == ITEM00_ARROWS_SMALL) || (this->actor.params == ITEM00_ARROWS_MEDIUM) || + (this->actor.params == ITEM00_ARROWS_LARGE) || (this->actor.params == ITEM00_BOMBS_A) || + (this->actor.params == ITEM00_BOMBS_B) || (this->actor.params == ITEM00_NUTS) || + (this->actor.params == ITEM00_MAGIC_SMALL) || (this->actor.params == ITEM00_SEEDS) || + (this->actor.params == ITEM00_SMALL_KEY) || (this->actor.params == ITEM00_MAGIC_LARGE) || + (this->actor.params == ITEM00_HEART) || (this->actor.params == ITEM00_BOMBS_SPECIAL) || this->actor.params == ITEM00_HEART_PIECE) { + this->actor.shape.rot.y += 960; + } } if (this->unk_15A > 0) { @@ -928,7 +925,7 @@ void EnItem00_Draw(Actor* thisx, GlobalContext* globalCtx) { if (!(this->unk_156 & this->unk_158)) { switch (this->actor.params) { case ITEM00_RUPEE_GREEN: - if (CVar_GetS32("gNewDrops", 0) !=0) { + if (CVar_GetS32("gNewDrops", 0)) { Actor_SetScale(&this->actor, 0.3f); this->scale = 0.3f; this->actor.shape.yOffset = 50.0f; @@ -938,7 +935,7 @@ void EnItem00_Draw(Actor* thisx, GlobalContext* globalCtx) { break; } case ITEM00_RUPEE_BLUE: - if (CVar_GetS32("gNewDrops", 0) !=0) { + if (CVar_GetS32("gNewDrops", 0)) { Actor_SetScale(&this->actor, 0.3f); this->scale = 0.3f; this->actor.shape.yOffset = 50.0f; @@ -948,7 +945,7 @@ void EnItem00_Draw(Actor* thisx, GlobalContext* globalCtx) { break; } case ITEM00_RUPEE_RED: - if (CVar_GetS32("gNewDrops", 0) !=0) { + if (CVar_GetS32("gNewDrops", 0)) { Actor_SetScale(&this->actor, 0.3f); this->scale = 0.3f; this->actor.shape.yOffset = 50.0f; @@ -965,7 +962,7 @@ void EnItem00_Draw(Actor* thisx, GlobalContext* globalCtx) { break; } case ITEM00_RUPEE_ORANGE: - if (CVar_GetS32("gNewDrops", 0) !=0) { + if (CVar_GetS32("gNewDrops", 0)) { Actor_SetScale(&this->actor, 0.45f); this->scale = 0.45f; this->actor.shape.yOffset = 50.0f; @@ -982,7 +979,7 @@ void EnItem00_Draw(Actor* thisx, GlobalContext* globalCtx) { break; } case ITEM00_RUPEE_PURPLE: - if (CVar_GetS32("gNewDrops", 0) !=0) { + if (CVar_GetS32("gNewDrops", 0)) { Actor_SetScale(&this->actor, 0.4f); this->scale = 0.4f; this->actor.shape.yOffset = 50.0f; @@ -998,14 +995,16 @@ void EnItem00_Draw(Actor* thisx, GlobalContext* globalCtx) { break; } case ITEM00_HEART_PIECE: - if (CVar_GetS32("gNewDrops", 0) !=0) { + if (CVar_GetS32("gNewDrops", 0)) { Actor_SetScale(&this->actor, 0.5f); this->scale = 0.5f; this->actor.shape.yOffset = 50.0f; this->actor.world.rot.x = 0x4000; + this->actor.shape.shadowScale = 0.3f; GetItem_Draw(globalCtx, GID_HEART_PIECE); } else { this->actor.shape.yOffset = 650.0f; + this->actor.shape.shadowScale = 0.03f; Actor_SetScale(&this->actor, 0.02f); this->scale = 0.02f; EnItem00_DrawHeartPiece(this, globalCtx); @@ -1015,9 +1014,10 @@ void EnItem00_Draw(Actor* thisx, GlobalContext* globalCtx) { EnItem00_DrawHeartContainer(this, globalCtx); break; case ITEM00_HEART: - if (CVar_GetS32("gNewDrops", 0) !=0) { + if (CVar_GetS32("gNewDrops", 0)) { this->actor.home.rot.z = Rand_CenteredFloat(65535.0f); this->actor.shape.yOffset = 25.0f; + this->actor.shape.shadowScale = 0.3f; Actor_SetScale(&this->actor, 0.3f); this->scale = 0.3f; GetItem_Draw(globalCtx, GID_HEART); @@ -1027,6 +1027,7 @@ void EnItem00_Draw(Actor* thisx, GlobalContext* globalCtx) { } else { this->actor.home.rot.z = Rand_CenteredFloat(65535.0f); this->actor.shape.yOffset = 430.0f; + this->actor.shape.shadowScale = 0.03f; Actor_SetScale(&this->actor, 0.02f); this->scale = 0.02f; if (this->unk_15A < 0) { @@ -1047,7 +1048,7 @@ void EnItem00_Draw(Actor* thisx, GlobalContext* globalCtx) { } } case ITEM00_BOMBS_A: - if (CVar_GetS32("gNewDrops", 0) !=0) { + if (CVar_GetS32("gNewDrops", 0)) { Actor_SetScale(&this->actor, 0.2f); this->scale = 0.2f; this->actor.shape.yOffset = 50.0f; @@ -1057,7 +1058,7 @@ void EnItem00_Draw(Actor* thisx, GlobalContext* globalCtx) { break; } case ITEM00_BOMBS_B: - if (CVar_GetS32("gNewDrops", 0) !=0) { + if (CVar_GetS32("gNewDrops", 0)) { Actor_SetScale(&this->actor, 0.2f); this->scale = 0.2f; this->actor.shape.yOffset = 50.0f; @@ -1068,7 +1069,7 @@ void EnItem00_Draw(Actor* thisx, GlobalContext* globalCtx) { } case ITEM00_BOMBS_SPECIAL: case ITEM00_ARROWS_SINGLE: - if (CVar_GetS32("gNewDrops", 0) !=0) { + if (CVar_GetS32("gNewDrops", 0)) { Actor_SetScale(&this->actor, 0.2f); this->scale = 0.2f; this->actor.shape.yOffset = 50.0f; @@ -1078,7 +1079,7 @@ void EnItem00_Draw(Actor* thisx, GlobalContext* globalCtx) { break; } case ITEM00_ARROWS_SMALL: - if (CVar_GetS32("gNewDrops", 0) !=0) { + if (CVar_GetS32("gNewDrops", 0)) { Actor_SetScale(&this->actor, 0.2f); this->scale = 0.2f; this->actor.shape.yOffset = 50.0f; @@ -1088,7 +1089,7 @@ void EnItem00_Draw(Actor* thisx, GlobalContext* globalCtx) { break; } case ITEM00_ARROWS_MEDIUM: - if (CVar_GetS32("gNewDrops", 0) !=0) { + if (CVar_GetS32("gNewDrops", 0)) { Actor_SetScale(&this->actor, 0.2f); this->scale = 0.2f; this->actor.shape.yOffset = 50.0f; @@ -1098,7 +1099,7 @@ void EnItem00_Draw(Actor* thisx, GlobalContext* globalCtx) { break; } case ITEM00_ARROWS_LARGE: - if (CVar_GetS32("gNewDrops", 0) !=0) { + if (CVar_GetS32("gNewDrops", 0)) { Actor_SetScale(&this->actor, 0.2f); this->scale = 0.2f; this->actor.shape.yOffset = 50.0f; @@ -1108,7 +1109,7 @@ void EnItem00_Draw(Actor* thisx, GlobalContext* globalCtx) { break; } case ITEM00_NUTS: - if (CVar_GetS32("gNewDrops", 0) !=0) { + if (CVar_GetS32("gNewDrops", 0)) { Actor_SetScale(&this->actor, 0.2f); this->scale = 0.2f; this->actor.shape.yOffset = 50.0f; @@ -1118,7 +1119,7 @@ void EnItem00_Draw(Actor* thisx, GlobalContext* globalCtx) { break; } case ITEM00_STICK: - if (CVar_GetS32("gNewDrops", 0) !=0) { + if (CVar_GetS32("gNewDrops", 0)) { Actor_SetScale(&this->actor, 0.2f); this->scale = 0.2f; this->actor.shape.yOffset = 50.0f; @@ -1128,7 +1129,7 @@ void EnItem00_Draw(Actor* thisx, GlobalContext* globalCtx) { break; } case ITEM00_MAGIC_LARGE: - if (CVar_GetS32("gNewDrops", 0) !=0) { + if (CVar_GetS32("gNewDrops", 0)) { Actor_SetScale(&this->actor, 0.2f); this->scale = 0.2f; this->actor.shape.yOffset = 50.0f; @@ -1138,7 +1139,7 @@ void EnItem00_Draw(Actor* thisx, GlobalContext* globalCtx) { break; } case ITEM00_MAGIC_SMALL: - if (CVar_GetS32("gNewDrops", 0) !=0) { + if (CVar_GetS32("gNewDrops", 0)) { Actor_SetScale(&this->actor, 0.2f); this->scale = 0.2f; this->actor.shape.yOffset = 50.0f; @@ -1148,7 +1149,7 @@ void EnItem00_Draw(Actor* thisx, GlobalContext* globalCtx) { break; } case ITEM00_SEEDS: - if (CVar_GetS32("gNewDrops", 0) !=0) { + if (CVar_GetS32("gNewDrops", 0)) { Actor_SetScale(&this->actor, 0.2f); this->scale = 0.2f; this->actor.shape.yOffset = 50.0f; @@ -1158,7 +1159,7 @@ void EnItem00_Draw(Actor* thisx, GlobalContext* globalCtx) { break; } case ITEM00_SMALL_KEY: - if (CVar_GetS32("gNewDrops", 0) !=0) { + if (CVar_GetS32("gNewDrops", 0)) { Actor_SetScale(&this->actor, 0.2f); this->scale = 0.2f; this->actor.shape.yOffset = 50.0f; From 89e07f8dbbb42db6b0468d02c1e1e2b15106d93a Mon Sep 17 00:00:00 2001 From: Sirius902 <10891979+Sirius902@users.noreply.github.com> Date: Sun, 10 Jul 2022 06:30:19 -0700 Subject: [PATCH 13/44] Dodongo's Cavern blue warp crash fix (#622) * Doodong's Cavern blue warp crash fix * >= not > * Don't waste a line of space --- soh/include/z64bgcheck.h | 1 + soh/soh/z_scene_otr.cpp | 3 ++- soh/src/code/z_play.c | 13 +++++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/soh/include/z64bgcheck.h b/soh/include/z64bgcheck.h index 87c8e246a..30e18afed 100644 --- a/soh/include/z64bgcheck.h +++ b/soh/include/z64bgcheck.h @@ -89,6 +89,7 @@ typedef struct { /* 0x20 */ CamData* cameraDataList; /* 0x24 */ u16 numWaterBoxes; /* 0x28 */ WaterBox* waterBoxes; + size_t cameraDataListLen; // OTRTODO: Added to allow for bounds checking the cameraDataList. } CollisionHeader; // original name: BGDataInfo typedef struct { diff --git a/soh/soh/z_scene_otr.cpp b/soh/soh/z_scene_otr.cpp index 85c9e3c70..8c5839f6e 100644 --- a/soh/soh/z_scene_otr.cpp +++ b/soh/soh/z_scene_otr.cpp @@ -158,6 +158,7 @@ bool func_80098674(GlobalContext* globalCtx, Ship::SceneCommand* cmd) } colHeader->cameraDataList = (CamData*)malloc(sizeof(CamData) * colRes->camData->entries.size()); + colHeader->cameraDataListLen = colRes->camData->entries.size(); for (int i = 0; i < colRes->camData->entries.size(); i++) { @@ -930,4 +931,4 @@ extern "C" s32 OTRfunc_8009728C(GlobalContext* globalCtx, RoomContext* roomCtx, } return 0; -} \ No newline at end of file +} diff --git a/soh/src/code/z_play.c b/soh/src/code/z_play.c index bb579dce2..28582b0e4 100644 --- a/soh/src/code/z_play.c +++ b/soh/src/code/z_play.c @@ -383,6 +383,19 @@ void Gameplay_Init(GameState* thisx) { Camera_InitPlayerSettings(&globalCtx->mainCamera, player); Camera_ChangeMode(&globalCtx->mainCamera, CAM_MODE_NORMAL); + // OTRTODO: Bounds check cameraDataList to guard against scenes spawning the player with + // an out of bounds background camera index. This requires adding an extra field to the + // CollisionHeader struct to save the length of cameraDataList. + // Fixes Dodongo's Cavern blue warp crash. + { + CollisionHeader* colHeader = BgCheck_GetCollisionHeader(&globalCtx->colCtx, BGCHECK_SCENE); + + // If the player's start cam is out of bounds, set it to 0xFF so it isn't used. + if (colHeader != NULL && ((player->actor.params & 0xFF) >= colHeader->cameraDataListLen)) { + player->actor.params |= 0xFF; + } + } + playerStartCamId = player->actor.params & 0xFF; if (playerStartCamId != 0xFF) { osSyncPrintf("player has start camera ID (" VT_FGCOL(BLUE) "%d" VT_RST ")\n", playerStartCamId); From d4c1c40c1db2efaa5e0c15be6bf705d5f378c62d Mon Sep 17 00:00:00 2001 From: Jeffrey Crowell Date: Sun, 10 Jul 2022 10:51:12 -0400 Subject: [PATCH 14/44] add support for clang compiler (#592) * hacks to align strings for clang... wow just wow * start work to getting built with clang * fix issues with struct constructors, all builds, doesn't link still * fix some narrowing issues that clang complains about * fix compliation of zapd * fix null deref in VersionInfo * builds with clang * make stringbuilding use StringHelper instead of addition * fix linking * add CLANG SHIP overlay on clang built versions * doesn't need to be volatile * mark unknown strings as extern * rename some stuff * can't align extern * hopefully fix compilation for everythign * expandtab * allow setting LD * Revert "allow setting LD" This reverts commit 711aba6db2c41bab476bd34e878af6a37a7f5559. maybe to use lld it should be a LDFLAG? * -Wno-deprecated-declarations is required for newer versions of clang on macOS 13 beta sdk, the version of apple clang requires this * Add jenkins support for clang * Forward CXX flags to stormlib compilation * Move GCC only flags to check * use exports to set multiarch setup * Fix Jenkins forever * use make instead of cmake --build add some flags to build with clang-11 as well * address review coments - rework extraction to allow multi thread - misc readability cleanup * update makefile to add WARN on linux+clang Co-authored-by: David Chavez --- BUILDING.md | 6 +- Jenkinsfile | 4 +- .../OTRExporter/DisplayListExporter.cpp | 78 +++++++++---------- OTRExporter/OTRExporter/VersionInfo.cpp | 4 +- ZAPDTR/Makefile | 2 +- ZAPDTR/ZAPD/ZAudioDecode.cpp | 10 +-- ZAPDTR/ZAPD/ZFile.cpp | 6 +- ZAPDTR/ZAPD/ZResource.cpp | 18 ++++- ZAPDTR/ZAPD/ZResource.h | 3 +- ZAPDTR/ZAPD/ZString.cpp | 2 +- ZAPDTR/ZAPD/ZString.h | 2 +- ZAPDTR/ZAPD/ZSymbol.cpp | 2 +- ZAPDTR/ZAPD/ZSymbol.h | 2 +- libultraship/Makefile | 21 ++++- libultraship/libultraship/Console.cpp | 6 +- libultraship/libultraship/ImGuiImpl.cpp | 2 +- .../libultraship/Lib/Fast3D/gfx_pc.cpp | 2 +- libultraship/libultraship/mixer.c | 6 ++ soh/Makefile | 10 ++- soh/soh/Enhancements/bootcommands.c | 1 + soh/soh/Enhancements/debugconsole.cpp | 2 +- soh/soh/Enhancements/debugger/colViewer.cpp | 30 +++---- .../Enhancements/debugger/debugSaveEditor.cpp | 22 +++--- soh/soh/OTRGlobals.cpp | 14 ++-- soh/soh/gu_pc.c | 3 +- soh/src/code/game.c | 4 + .../overlays/gamestates/ovl_title/z_title.c | 2 + 27 files changed, 155 insertions(+), 109 deletions(-) diff --git a/BUILDING.md b/BUILDING.md index 4e2f35616..08ea20b35 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -48,7 +48,7 @@ make -j $(nproc) OPTFLAGS=-O2 DEBUG=0 ## macOS -1. Requires `gcc@12, sdl2, libpng, glew, dylibbundler` (can be installed via brew, etc) +1. Requires Xcode (or xcode-tools) && `sdl2, libpng, glew, dylibbundler` (can be installed via brew, etc) ```bash # Clone the repo git clone https://github.com/HarbourMasters/Shipwright.git @@ -59,9 +59,9 @@ cp OTRExporter cd soh # Extract the assets/Compile the exporter/Run the exporter # -jX defines number of cores to use for compilation - lower or remove entirely if having issues -make setup -j8 DEBUG=0 CC=gcc-12 CXX=g++-12 +make setup -j8 DEBUG=0 # Compile the code (watch the -j parameter as above) -make -j8 DEBUG=0 CC=gcc-12 CXX=g++-12 +make -j8 DEBUG=0 # Create macOS app bundle make filledappbundle ``` diff --git a/Jenkinsfile b/Jenkinsfile index 74e33c1b1..8ea6317a4 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -137,8 +137,8 @@ pipeline { sh ''' cp ../../ZELOOTD.z64 OTRExporter/baserom_non_mq.z64 cd soh - make setup -j4 DEBUG=0 OPTFLAGS=-O2 CC=gcc-12 CXX=g++-12 - make -j4 DEBUG=0 OPTFLAGS=-O2 CC=gcc-12 CXX=g++-12 + export CC="clang -arch arm64 -arch x86_64"; export CXX="clang++ -arch arm64 -arch x86_64"; make setup -j4 OPTFLAGS=-O2 DEBUG=0 LD="ld" + export CC="clang -arch arm64 -arch x86_64"; export CXX="clang++ -arch arm64 -arch x86_64"; make -j4 DEBUG=0 OPTFLAGS=-O2 LD="ld" make -j4 appbundle mv ../README.md readme.txt 7z a soh-mac.7z soh.app readme.txt diff --git a/OTRExporter/OTRExporter/DisplayListExporter.cpp b/OTRExporter/OTRExporter/DisplayListExporter.cpp index ed4694397..f233f2d78 100644 --- a/OTRExporter/OTRExporter/DisplayListExporter.cpp +++ b/OTRExporter/OTRExporter/DisplayListExporter.cpp @@ -96,14 +96,14 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina { case G_NOOP: { - Gfx value = gsDPNoOp(); + Gfx value = {gsDPNoOp()}; word0 = value.words.w0; word1 = value.words.w1; } break; case G_ENDDL: { - Gfx value = gsSPEndDisplayList(); + Gfx value = {gsSPEndDisplayList()}; word0 = value.words.w0; word1 = value.words.w1; } @@ -114,7 +114,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina int32_t nnnn = (data & 0x0000FFFF00000000ULL) >> 32; int32_t vvvvvvvv = (data & 0x00000000FFFFFFFFULL); - Gfx value = gsSPModifyVertex(nnnn / 2, ww, vvvvvvvv); + Gfx value = {gsSPModifyVertex(nnnn / 2, ww, vvvvvvvv)}; word0 = value.words.w0; word1 = value.words.w1; } @@ -131,35 +131,35 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina int32_t cccccc = (data & 0x00FFFFFF00000000) >> 32; int32_t ssssssss = (data & 0xFFFFFFFF); - Gfx value = gsSPGeometryMode(~cccccc, ssssssss); + Gfx value = {gsSPGeometryMode(~cccccc, ssssssss)}; word0 = value.words.w0; word1 = value.words.w1; } break; case G_RDPPIPESYNC: { - Gfx value = gsDPPipeSync(); + Gfx value = {gsDPPipeSync()}; word0 = value.words.w0; word1 = value.words.w1; } break; case G_RDPLOADSYNC: { - Gfx value = gsDPLoadSync(); + Gfx value = {gsDPLoadSync()}; word0 = value.words.w0; word1 = value.words.w1; } break; case G_RDPTILESYNC: { - Gfx value = gsDPTileSync(); + Gfx value = {gsDPTileSync()}; word0 = value.words.w0; word1 = value.words.w1; } break; case G_RDPFULLSYNC: { - Gfx value = gsDPFullSync(); + Gfx value = {gsDPFullSync()}; word0 = value.words.w0; word1 = value.words.w1; } @@ -169,14 +169,14 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina int32_t hhhhhh = (data & 0x00FFFFFF00000000) >> 32; int32_t llllllll = (data & 0x00000000FFFFFFFF); - Gfx value = gsDPSetOtherMode(hhhhhh, llllllll); + Gfx value = {gsDPSetOtherMode(hhhhhh, llllllll)}; word0 = value.words.w0; word1 = value.words.w1; } break; case G_POPMTX: { - Gfx value = gsSPPopMatrix(data); + Gfx value = {gsSPPopMatrix(data)}; word0 = value.words.w0; word1 = value.words.w1; } @@ -188,7 +188,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina uint8_t b = (uint8_t)((data & 0xFF00FF00) >> 8); uint8_t a = (uint8_t)((data & 0x000000FF) >> 0); - Gfx value = gsDPSetEnvColor(r, g, b, a); + Gfx value = {gsDPSetEnvColor(r, g, b, a)}; word0 = value.words.w0; word1 = value.words.w1; } @@ -204,7 +204,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina mm = (mm & 0x0FFFFFFF) + 1; - Gfx value = gsSPMatrix(mm, pp); + Gfx value = {gsSPMatrix(mm, pp)}; word0 = value.words.w0; word1 = value.words.w1; } @@ -214,7 +214,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina uint32_t mm = (data & 0x00000000FFFFFFFF); pp ^= G_MTX_PUSH; - Gfx value = gsSPMatrix(mm, pp); + Gfx value = {gsSPMatrix(mm, pp)}; word0 = value.words.w0; word1 = value.words.w1; @@ -253,7 +253,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina int32_t xxx = (data & 0x0000000000FFF000) >> 12; int32_t ddd = (data & 0x0000000000000FFF); - Gfx value = gsDPLoadBlock(i, sss, ttt, xxx, ddd); + Gfx value = {gsDPLoadBlock(i, sss, ttt, xxx, ddd)}; word0 = value.words.w0; word1 = value.words.w1; } @@ -263,7 +263,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina int32_t vvvv = (data & 0xFFFF00000000) >> 32; int32_t wwww = (data & 0x0000FFFF); - Gfx value = gsSPCullDisplayList(vvvv / 2, wwww / 2); + Gfx value = {gsSPCullDisplayList(vvvv / 2, wwww / 2)}; word0 = value.words.w0; word1 = value.words.w1; } @@ -279,7 +279,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina uint32_t z = (data & 0x00000000FFFFFFFF) >> 0; uint32_t h = (data & 0xFFFFFFFF); - Gfx value = gsSPBranchLessZraw3(h & 0x00FFFFFF); + Gfx value = {gsSPBranchLessZraw3(h & 0x00FFFFFF)}; word0 = value.words.w0; word1 = value.words.w1; } @@ -292,7 +292,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina break; case G_RDPHALF_2: { - Gfx value = gsDPWordLo(data & 0xFFFFFFFF); + Gfx value = {gsDPWordLo(data & 0xFFFFFFFF)}; word0 = value.words.w0; word1 = value.words.w1; } @@ -305,7 +305,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina int32_t XXX = (data & 0x0000000000FFF000) >> 12; int32_t YYY = (data & 0x0000000000000FFF); - Gfx value = gsSPTextureRectangle2(XXX, YYY, xxx, yyy, i); + Gfx value = {gsSPTextureRectangle2(XXX, YYY, xxx, yyy, i)}; word0 = value.words.w0; word1 = value.words.w1; } @@ -324,7 +324,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina int bp = 0; - Gfx value = gsSPBranchLessZraw2(0xDEADABCD, (a / 5) | (b / 2), z); + Gfx value = {gsSPBranchLessZraw2(0xDEADABCD, (a / 5) | (b / 2), z)}; word0 = (value.words.w0 & 0x00FFFFFF) + (G_BRANCH_Z_OTR << 24); word1 = value.words.w1; @@ -389,9 +389,9 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina u32 dListVal = (data & 0x0FFFFFFF) + 1; if (pp != 0) - value = gsSPBranchList(dListVal); + value = {gsSPBranchList(dListVal)}; else - value = gsSPDisplayList(dListVal); + value = {gsSPDisplayList(dListVal)}; word0 = value.words.w0; word1 = value.words.w1; @@ -469,7 +469,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina int32_t ddd = (____ & 0x700) >> 8; int32_t nnnnnnn = (____ & 0xFE) >> 1; - Gfx value = gsSPTexture(ssss, tttt, lll, ddd, nnnnnnn); + Gfx value = {gsSPTexture(ssss, tttt, lll, ddd, nnnnnnn)}; word0 = value.words.w0; word1 = value.words.w1; } @@ -480,7 +480,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina int32_t bb = ((data & 0x0000FF0000000000ULL) >> 40) / 2; int32_t cc = ((data & 0x000000FF00000000ULL) >> 32) / 2; - Gfx test = gsSP1Triangle(aa, bb, cc, 0); + Gfx test = {gsSP1Triangle(aa, bb, cc, 0)}; word0 = test.words.w0; word1 = test.words.w1; } @@ -494,7 +494,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina int32_t ee = ((data & 0x0000000000FF00ULL) >> 8) / 2; int32_t ff = ((data & 0x000000000000FFULL) >> 0) / 2; - Gfx test = gsSP2Triangles(aa, bb, cc, 0, dd, ee, ff, 0); + Gfx test = {gsSP2Triangles(aa, bb, cc, 0, dd, ee, ff, 0)}; word0 = test.words.w0; word1 = test.words.w1; } @@ -506,7 +506,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina int32_t cc = ((data & 0x000000FF00000000ULL) >> 32) / 2; int32_t dd = ((data & 0x000000000000FFULL)) / 2; - Gfx test = gsSP1Quadrangle(aa, bb, cc, dd, 0); + Gfx test = {gsSP1Quadrangle(aa, bb, cc, dd, 0)}; word0 = test.words.w0; word1 = test.words.w1; } @@ -520,7 +520,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina int32_t bb = (data & 0x000000000000FF00) >> 8; int32_t aa = (data & 0x00000000000000FF) >> 0; - Gfx value = gsDPSetPrimColor(mm, ff, rr, gg, bb, aa); + Gfx value = {gsDPSetPrimColor(mm, ff, rr, gg, bb, aa)}; word0 = value.words.w0; word1 = value.words.w1; } @@ -534,7 +534,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina // TODO: Output the correct render modes in data - Gfx value = gsSPSetOtherMode(0xE2, sft, len, dd); + Gfx value = {gsSPSetOtherMode(0xE2, sft, len, dd)}; word0 = value.words.w0; word1 = value.words.w1; } @@ -552,11 +552,11 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina if (sft == 14) // G_MDSFT_TEXTLUT { const char* types[] = { "G_TT_NONE", "G_TT_NONE", "G_TT_RGBA16", "G_TT_IA16" }; - value = gsDPSetTextureLUT(dd >> 14); + value = {gsDPSetTextureLUT(dd >> 14)}; } else { - value = gsSPSetOtherMode(0xE3, sft, nn + 1, dd); + value = {gsSPSetOtherMode(0xE3, sft, nn + 1, dd)}; } word0 = value.words.w0; @@ -583,7 +583,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina int32_t bbbb = (data & 0b0000000000000000000000000000000000000000000000000000000011110000) >> 4; int32_t uuuu = (data & 0b0000000000000000000000000000000000000000000000000000000000001111); - Gfx value = gsDPSetTile(fff, ii, nnnnnnnnn, mmmmmmmmm, ttt, pppp, cc, aaaa, ssss, dd, bbbb, uuuu); + Gfx value = {gsDPSetTile(fff, ii, nnnnnnnnn, mmmmmmmmm, ttt, pppp, cc, aaaa, ssss, dd, bbbb, uuuu)}; word0 = value.words.w0; word1 = value.words.w1; } @@ -607,7 +607,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina int32_t ab1 = (data & 0b00000000000000000000000000000000000000000000000000000000111000) >> 3; int32_t ad1 = (data & 0b00000000000000000000000000000000000000000000000000000000000111) >> 0; - Gfx value = gsDPSetCombineLERP2(a0, b0, c0, d0, aa0, ab0, ac0, ad0, a1, b1, c1, d1, aa1, ab1, ac1, ad1); + Gfx value = {gsDPSetCombineLERP2(a0, b0, c0, d0, aa0, ab0, ac0, ad0, a1, b1, c1, d1, aa1, ab1, ac1, ad1)}; word0 = value.words.w0; word1 = value.words.w1; } @@ -620,7 +620,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina int32_t vvv = (data & 0x0000000000000FFF); int32_t i = (data & 0x000000000F000000) >> 24; - Gfx value = gsDPSetTileSize(i, sss, ttt, uuu, vvv); + Gfx value = {gsDPSetTileSize(i, sss, ttt, uuu, vvv)}; word0 = value.words.w0; word1 = value.words.w1; } @@ -630,7 +630,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina int32_t t = (data & 0x0000000007000000) >> 24; int32_t ccc = (data & 0x00000000003FF000) >> 14; - Gfx value = gsDPLoadTLUTCmd(t, ccc); + Gfx value = {gsDPLoadTLUTCmd(t, ccc)}; word0 = value.words.w0; word1 = value.words.w1; } @@ -643,7 +643,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina int uuu = (data & 0x0000000000FFF000) >> 12; int vvv= (data & 0x0000000000000FFF); - Gfx value = gsDPLoadTile(i, sss, ttt, uuu, vvv); + Gfx value = {gsDPLoadTile(i, sss, ttt, uuu, vvv)}; word0 = value.words.w0; word1 = value.words.w1; } @@ -661,7 +661,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina uint32_t fmt = (__ & 0xE0) >> 5; uint32_t siz = (__ & 0x18) >> 3; - Gfx value = gsDPSetTextureImage(fmt, siz, www + 1, (seg & 0x0FFFFFFF) + 1); + Gfx value = {gsDPSetTextureImage(fmt, siz, www + 1, (seg & 0x0FFFFFFF) + 1)}; word0 = value.words.w0; word1 = value.words.w1; @@ -679,7 +679,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina uint32_t fmt = (__ & 0xE0) >> 5; uint32_t siz = (__ & 0x18) >> 3; - Gfx value = gsDPSetTextureImage(fmt, siz, www + 1, __); + Gfx value = {gsDPSetTextureImage(fmt, siz, www + 1, __)}; word0 = value.words.w0 & 0x00FFFFFF; word0 += (G_SETTIMG_OTR << 24); //word1 = value.words.w1; @@ -722,7 +722,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina int32_t aa = (data & 0x000000FF00000000ULL) >> 32; int32_t nn = (data & 0x000FF00000000000ULL) >> 44; - Gfx value = gsSPVertex(data & 0xFFFFFFFF, nn, ((aa >> 1) - nn)); + Gfx value = {gsSPVertex(data & 0xFFFFFFFF, nn, ((aa >> 1) - nn))}; word0 = value.words.w0; word1 = value.words.w1 | 1; @@ -745,7 +745,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina { uint32_t diff = segOffset - vtxDecl->address; - Gfx value = gsSPVertex(diff, nn, ((aa >> 1) - nn)); + Gfx value = {gsSPVertex(diff, nn, ((aa >> 1) - nn))}; word0 = value.words.w0; word0 &= 0x00FFFFFF; @@ -893,4 +893,4 @@ std::string OTRExporter_DisplayList::GetPrefix(ZResource* res) prefix = "code"; return prefix; -} \ No newline at end of file +} diff --git a/OTRExporter/OTRExporter/VersionInfo.cpp b/OTRExporter/OTRExporter/VersionInfo.cpp index 0a2004673..ba0146d41 100644 --- a/OTRExporter/OTRExporter/VersionInfo.cpp +++ b/OTRExporter/OTRExporter/VersionInfo.cpp @@ -5,7 +5,7 @@ std::map resourceVersions; void InitVersionInfo() { - resourceVersions = { + resourceVersions = std::map { { Ship::ResourceType::Animation, 0 }, { Ship::ResourceType::Model, 0 }, { Ship::ResourceType::Texture, 0 }, @@ -24,4 +24,4 @@ void InitVersionInfo() { Ship::ResourceType::Text, 0 }, { Ship::ResourceType::Blob, 0 }, }; -} \ No newline at end of file +} diff --git a/ZAPDTR/Makefile b/ZAPDTR/Makefile index 2e871b32f..d9a85b6db 100644 --- a/ZAPDTR/Makefile +++ b/ZAPDTR/Makefile @@ -124,7 +124,7 @@ lib/libgfxd/libgfxd.a: .PHONY: StormLib StormLib: LDFLAGS="" cmake -B ../StormLib/build -S ../StormLib - LDFLAGS="" cmake --build ../StormLib/build + $(MAKE) -C ../StormLib/build .PHONY: ExporterTest ExporterTest: diff --git a/ZAPDTR/ZAPD/ZAudioDecode.cpp b/ZAPDTR/ZAPD/ZAudioDecode.cpp index b8b066474..90ecfe35c 100644 --- a/ZAPDTR/ZAPD/ZAudioDecode.cpp +++ b/ZAPDTR/ZAPD/ZAudioDecode.cpp @@ -461,8 +461,8 @@ char* OldMain(char* infilename) else { char comprType[5] = { - CommChunk.compressionTypeH >> 8, CommChunk.compressionTypeH & 0xFF, - CommChunk.compressionTypeL >> 8, CommChunk.compressionTypeL & 0xFF, 0}; + static_cast(CommChunk.compressionTypeH >> 8), static_cast(CommChunk.compressionTypeH & 0xFF), + static_cast(CommChunk.compressionTypeL >> 8), static_cast(CommChunk.compressionTypeL & 0xFF), 0}; fail_parse("file is of the wrong compression type [got %s (%08x)]", &comprType, cType); } @@ -603,8 +603,8 @@ char* OldMain(char* infilename) { s32 startPos = aloops[0].start, endPos = aloops[0].end; const char* markerNames[2] = {"start", "end"}; - Marker markers[2] = {{1, startPos >> 16, startPos & 0xffff}, - {2, endPos >> 16, endPos & 0xffff}}; + Marker markers[2] = {{1, static_cast(startPos >> 16), static_cast(startPos & 0xffff)}, + {2, static_cast(endPos >> 16), static_cast(endPos & 0xffff)}}; write_header(ofile, "MARK", 2 + 2 * sizeof(Marker) + 1 + 5 + 1 + 3); s16 numMarkers = bswap16(2); fwrite(&numMarkers, sizeof(s16), 1, ofile); @@ -666,4 +666,4 @@ char* OldMain(char* infilename) fclose(ifile); fclose(ofile); return 0; -} \ No newline at end of file +} diff --git a/ZAPDTR/ZAPD/ZFile.cpp b/ZAPDTR/ZAPD/ZFile.cpp index 9ff7a6823..1ea5cd553 100644 --- a/ZAPDTR/ZAPD/ZFile.cpp +++ b/ZAPDTR/ZAPD/ZFile.cpp @@ -800,9 +800,11 @@ void ZFile::GenerateSourceHeaderFiles() { OutputFormatter formatter; + formatter.Write("#pragma once\n"); + std::set nameSet; for (ZResource* res : resources) { - std::string resSrc = res->GetSourceOutputHeader(""); + std::string resSrc = res->GetSourceOutputHeader("", &nameSet); formatter.Write(resSrc); if (resSrc != "") @@ -811,7 +813,7 @@ void ZFile::GenerateSourceHeaderFiles() for (auto& sym : symbolResources) { - formatter.Write(sym.second->GetSourceOutputHeader("")); + formatter.Write(sym.second->GetSourceOutputHeader("", &nameSet)); } formatter.Write(ProcessExterns()); diff --git a/ZAPDTR/ZAPD/ZResource.cpp b/ZAPDTR/ZAPD/ZResource.cpp index 550031ab4..89238d9a0 100644 --- a/ZAPDTR/ZAPD/ZResource.cpp +++ b/ZAPDTR/ZAPD/ZResource.cpp @@ -7,6 +7,7 @@ #include "WarningHandler.h" #include "ZFile.h" #include +#include #include #include @@ -304,7 +305,7 @@ void ZResource::GetSourceOutputCode([[maybe_unused]] const std::string& prefix) } } -std::string ZResource::GetSourceOutputHeader([[maybe_unused]] const std::string& prefix) +std::string ZResource::GetSourceOutputHeader([[maybe_unused]] const std::string& prefix, std::set *nameSet) { if (Globals::Instance->otrMode && genOTRDef) { @@ -342,9 +343,20 @@ std::string ZResource::GetSourceOutputHeader([[maybe_unused]] const std::string& prefix = "text"; if (prefix != "") - str += StringHelper::Sprintf("#define %s \"__OTR__%s/%s/%s\"", name.c_str(), prefix.c_str(), outName.c_str(), nameStr.c_str()); + str += StringHelper::Sprintf("#define d%s \"__OTR__%s/%s/%s\"", name.c_str(), prefix.c_str(), outName.c_str(), nameStr.c_str()); else - str += StringHelper::Sprintf("#define %s \"__OTR__%s/%s\"", name.c_str(), outName.c_str(), nameStr.c_str()); + str += StringHelper::Sprintf("#define d%s \"__OTR__%s/%s\"", name.c_str(), outName.c_str(), nameStr.c_str()); + + if (nameSet && nameSet->find(name) == nameSet->end()) { +#ifdef _WIN32 + str += StringHelper::Sprintf("\nstatic const __declspec(align(2)) char %s[] = d%s;", name.c_str(), name.c_str()); +#else + str += StringHelper::Sprintf("\nstatic const char %s[] __attribute__((aligned (2))) = d%s;", name.c_str(), name.c_str()); +#endif + if (nameSet) { + nameSet->insert(name); + } + } return str; } diff --git a/ZAPDTR/ZAPD/ZResource.h b/ZAPDTR/ZAPD/ZResource.h index 8b1055a4b..be272cf6b 100644 --- a/ZAPDTR/ZAPD/ZResource.h +++ b/ZAPDTR/ZAPD/ZResource.h @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -116,7 +117,7 @@ public: [[nodiscard]] virtual std::string GetDefaultName(const std::string& prefix) const; virtual void GetSourceOutputCode(const std::string& prefix); - virtual std::string GetSourceOutputHeader(const std::string& prefix); + virtual std::string GetSourceOutputHeader(const std::string& prefix, std::set *nameSet); virtual void CalcHash(); /** * Exports the resource to binary format diff --git a/ZAPDTR/ZAPD/ZString.cpp b/ZAPDTR/ZAPD/ZString.cpp index 965d4d636..2a0c1eaf8 100644 --- a/ZAPDTR/ZAPD/ZString.cpp +++ b/ZAPDTR/ZAPD/ZString.cpp @@ -48,7 +48,7 @@ std::string ZString::GetBodySourceCode() const return StringHelper::Sprintf("\t\"%s\"", strData.data()); } -std::string ZString::GetSourceOutputHeader([[maybe_unused]] const std::string& prefix) +std::string ZString::GetSourceOutputHeader([[maybe_unused]] const std::string& prefix, std::set *nameSet) { return StringHelper::Sprintf("#define %s_macro \"%s\"", name.c_str(), strData.data()); } diff --git a/ZAPDTR/ZAPD/ZString.h b/ZAPDTR/ZAPD/ZString.h index 6c58ebdcb..19f615a90 100644 --- a/ZAPDTR/ZAPD/ZString.h +++ b/ZAPDTR/ZAPD/ZString.h @@ -13,7 +13,7 @@ public: Declaration* DeclareVar(const std::string& prefix, const std::string& bodyStr) override; std::string GetBodySourceCode() const override; - std::string GetSourceOutputHeader(const std::string& prefix) override; + std::string GetSourceOutputHeader(const std::string& prefix, std::set *nameSet) override; std::string GetSourceTypeName() const override; ZResourceType GetResourceType() const override; diff --git a/ZAPDTR/ZAPD/ZSymbol.cpp b/ZAPDTR/ZAPD/ZSymbol.cpp index eabfc2faa..b5df68669 100644 --- a/ZAPDTR/ZAPD/ZSymbol.cpp +++ b/ZAPDTR/ZAPD/ZSymbol.cpp @@ -74,7 +74,7 @@ size_t ZSymbol::GetRawDataSize() const return typeSize; } -std::string ZSymbol::GetSourceOutputHeader([[maybe_unused]] const std::string& prefix) +std::string ZSymbol::GetSourceOutputHeader([[maybe_unused]] const std::string& prefix, std::set *nameSet) { if (isArray) { diff --git a/ZAPDTR/ZAPD/ZSymbol.h b/ZAPDTR/ZAPD/ZSymbol.h index 7cb14aa9b..e00f14c6b 100644 --- a/ZAPDTR/ZAPD/ZSymbol.h +++ b/ZAPDTR/ZAPD/ZSymbol.h @@ -18,7 +18,7 @@ public: Declaration* DeclareVar(const std::string& prefix, const std::string& bodyStr) override; - std::string GetSourceOutputHeader(const std::string& prefix) override; + std::string GetSourceOutputHeader(const std::string& prefix, std::set *nameSet) override; std::string GetSourceTypeName() const override; ZResourceType GetResourceType() const override; diff --git a/libultraship/Makefile b/libultraship/Makefile index 2d0b1b606..b3b7d2836 100644 --- a/libultraship/Makefile +++ b/libultraship/Makefile @@ -17,12 +17,23 @@ WARN := -Wall -Wextra -Werror \ -Wno-unused-function \ -Wno-parentheses \ -Wno-narrowing \ - -Wno-error=stringop-overflow \ -Wno-missing-field-initializers \ - -Wno-error=multichar + -Wno-error=multichar \ + -Wno-unused-command-line-argument \ + -Wno-delete-non-abstract-non-virtual-dtor \ + -Wno-unused-private-field \ + -Wno-deprecated-copy-with-user-provided-copy \ + -Wno-deprecated-declarations \ + -Wno-unknown-warning-option CWARN := -CXXWARN := -Wno-deprecated-enum-enum-conversion -Wno-error=maybe-uninitialized +CXXWARN := -Wno-deprecated-enum-enum-conversion -Wno-deprecated-copy + +COMPILER_VERSION := $(shell $(CXX) --version) +ifneq '' '$(findstring g++,$(COMPILER_VERSION))' + WARN += -Wno-error=stringop-overflow + CXXWARN += -Wno-error=maybe-uninitialized +endif CXXFLAGS := $(WARN) $(CXXWARN) -std=c++20 -D_GNU_SOURCE -DENABLE_OPENGL -DSPDLOG_ACTIVE_LEVEL=0 CFLAGS := $(WARN) $(CWARN) -std=c99 -D_GNU_SOURCE -DENABLE_OPENGL -DSPDLOG_ACTIVE_LEVEL=0 @@ -32,6 +43,10 @@ ifeq ($(UNAME), Darwin) #APPLE CPPFLAGS += $(shell pkg-config --cflags sdl2 glew) -framework OpenGL endif +ifeq ($(UNAME), Linux) + WARN += -Wno-error=stringop-overflow # This is required with clang on Linux. +endif + ifneq ($(DEBUG),0) CXXFLAGS += -g -D_DEBUG CFLAGS += -g -D_DEBUG diff --git a/libultraship/libultraship/Console.cpp b/libultraship/libultraship/Console.cpp index 6708f1bfb..da61e4056 100644 --- a/libultraship/libultraship/Console.cpp +++ b/libultraship/libultraship/Console.cpp @@ -28,7 +28,7 @@ static bool ClearCommand(const std::vector&) { std::string toLowerCase(std::string in) { std::string cpy(in); - std::ranges::transform(cpy, cpy.begin(), [](unsigned char c) { return std::tolower(c); }); + std::transform(cpy.begin(), cpy.end(), cpy.begin(), ::tolower); return cpy; } @@ -204,11 +204,11 @@ void Console::Draw() { for (int i = 0; i < static_cast(channel.size()); i++) { ConsoleLine line = channel[i]; if(!this->filter.empty() && line.text.find(this->filter) == std::string::npos) continue; - if(this->level_filter != NULLSTR && line.priority != (std::ranges::find(priority_filters, this->level_filter) - priority_filters.begin()) - 1) continue; + if(this->level_filter != NULLSTR && line.priority != (std::find(priority_filters.begin(), priority_filters.end(), this->level_filter) - priority_filters.begin()) - 1) continue; std::string id = line.text + "##" + std::to_string(i); ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); - const bool is_selected = (this->selectedId == i) || std::ranges::find(this->selectedEntries, i) != this->selectedEntries.end(); + const bool is_selected = (this->selectedId == i) || std::find(this->selectedEntries.begin(), this->selectedEntries.end(), i) != this->selectedEntries.end(); ImGui::PushStyleColor(ImGuiCol_Text, this->priority_colors[line.priority]); if (ImGui::Selectable(id.c_str(), is_selected)) { if (ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_LeftCtrl)) && !is_selected) diff --git a/libultraship/libultraship/ImGuiImpl.cpp b/libultraship/libultraship/ImGuiImpl.cpp index 1886823c7..7b1d905e7 100644 --- a/libultraship/libultraship/ImGuiImpl.cpp +++ b/libultraship/libultraship/ImGuiImpl.cpp @@ -1246,7 +1246,7 @@ namespace SohImGui { if (ImGui::BeginMenu(category.first.c_str())) { for (const std::string& name : category.second) { std::string varName(name); - varName.erase(std::ranges::remove_if(varName, isspace).begin(), varName.end()); + varName.erase(std::remove_if(varName.begin(), varName.end(), [](unsigned char x) { return std::isspace(x); }), varName.end()); std::string toggleName = "g" + varName + "Enabled"; EnhancementCheckbox(name.c_str(), toggleName.c_str()); diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_pc.cpp b/libultraship/libultraship/Lib/Fast3D/gfx_pc.cpp index b53c2550f..91e63227e 100644 --- a/libultraship/libultraship/Lib/Fast3D/gfx_pc.cpp +++ b/libultraship/libultraship/Lib/Fast3D/gfx_pc.cpp @@ -566,7 +566,7 @@ static bool gfx_texture_cache_lookup(int i, int tile) { static void gfx_texture_cache_delete(const uint8_t* orig_addr) { while (gfx_texture_cache.map.bucket_count() > 0) { - TextureCacheKey key = { orig_addr, 0, 0, 0 }; // bucket index only depends on the address + TextureCacheKey key = { orig_addr, {0}, 0, 0 }; // bucket index only depends on the address size_t bucket = gfx_texture_cache.map.bucket(key); bool again = false; for (auto it = gfx_texture_cache.map.begin(bucket); it != gfx_texture_cache.map.end(bucket); ++it) { diff --git a/libultraship/libultraship/mixer.c b/libultraship/libultraship/mixer.c index 1e66dc8a1..2e80ffb16 100644 --- a/libultraship/libultraship/mixer.c +++ b/libultraship/libultraship/mixer.c @@ -4,7 +4,9 @@ #include "mixer.h" +#ifndef __clang__ #pragma GCC optimize ("unroll-loops") +#endif #define ROUND_UP_64(v) (((v) + 63) & ~63) #define ROUND_UP_32(v) (((v) + 31) & ~31) @@ -449,10 +451,14 @@ void aFilterImpl(uint8_t flags, uint16_t count_or_buf, int16_t *state_or_filter) int16_t *buf = BUF_S16(count_or_buf); if (flags == A_INIT) { +#ifndef __clang__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wmemset-elt-size" +#endif memset(tmp, 0, 8 * sizeof(int16_t)); +#ifndef __clang__ #pragma GCC diagnostic pop +#endif memset(tmp2, 0, 8 * sizeof(int16_t)); } else { memcpy(tmp, state_or_filter, 8 * sizeof(int16_t)); diff --git a/soh/Makefile b/soh/Makefile index 43140dc95..14bb46827 100644 --- a/soh/Makefile +++ b/soh/Makefile @@ -18,8 +18,11 @@ LTO ?= 0 WARN := \ -Wno-return-type \ + -Wno-unused-command-line-argument \ + -Wno-implicit-function-declaration \ + -Wno-c++11-narrowing \ -funsigned-char \ - -fno-stack-protector -fno-common -fno-zero-initialized-in-bss -fno-strict-aliasing -fno-inline-functions -fno-inline-small-functions -fno-toplevel-reorder -ffreestanding -fwrapv \ + -fno-stack-protector -fno-common -fno-zero-initialized-in-bss -fno-strict-aliasing -fno-inline-functions -fno-inline-small-functions -ffreestanding -fwrapv \ CXXFLAGS := $(WARN) -std=c++20 -D_GNU_SOURCE -fpermissive -no-pie -nostdlib CFLAGS := $(WARN) -std=c99 -D_GNU_SOURCE -no-pie -nostdlib @@ -99,7 +102,6 @@ LDLIBS := \ bz2 \ z \ pthread \ - atomic \ ultraship \ ) @@ -116,7 +118,7 @@ endif ifeq ($(UNAME), Darwin) #APPLE LDLIBS += \ - $(addprefix -framework, \ + $(addprefix -framework , \ OpenGL \ ) \ $(shell sdl2-config --libs) $(shell pkg-config --libs glew) @@ -208,7 +210,7 @@ build/%.o: %.c $(TARGET): $(LIBULTRASHIP) $(TARGET): $(O_FILES) - $(CXX) $^ -o $@ $(LDFLAGS) -fuse-ld=$(LD) $(LDDIRS) $(LDLIBS) + $(CXX) $^ -o $@ $(LDFLAGS) $(LDDIRS) $(LDLIBS) -include $(D_FILES) diff --git a/soh/soh/Enhancements/bootcommands.c b/soh/soh/Enhancements/bootcommands.c index 90f3ae7a2..0b789b445 100644 --- a/soh/soh/Enhancements/bootcommands.c +++ b/soh/soh/Enhancements/bootcommands.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include diff --git a/soh/soh/Enhancements/debugconsole.cpp b/soh/soh/Enhancements/debugconsole.cpp index e96942893..445134f2a 100644 --- a/soh/soh/Enhancements/debugconsole.cpp +++ b/soh/soh/Enhancements/debugconsole.cpp @@ -509,7 +509,7 @@ void DebugConsole_LoadCVars() if (cfg.size() < 2) continue; if (cfg[1].find("\"") != std::string::npos) { std::string value(cfg[1]); - value.erase(std::ranges::remove(value, '\"').begin(), value.end()); + value.erase(std::remove(value.begin(), value.end(), '\"'), value.end()); CVar_SetString(cfg[0].c_str(), ImStrdup(value.c_str())); } if (is_number(cfg[1])) { diff --git a/soh/soh/Enhancements/debugger/colViewer.cpp b/soh/soh/Enhancements/debugger/colViewer.cpp index 366e228ae..1cab6ef64 100644 --- a/soh/soh/Enhancements/debugger/colViewer.cpp +++ b/soh/soh/Enhancements/debugger/colViewer.cpp @@ -194,9 +194,9 @@ void CreateSphereFace(std::vector>& faces, in // Create 3 new verticies at the midpoints Vec3f vs[3] = { - Vec3f((v0.n.ob[0] + v1.n.ob[0]) / 2.0f, (v0.n.ob[1] + v1.n.ob[1]) / 2.0f, (v0.n.ob[2] + v1.n.ob[2]) / 2.0f), - Vec3f((v1.n.ob[0] + v2.n.ob[0]) / 2.0f, (v1.n.ob[1] + v2.n.ob[1]) / 2.0f, (v1.n.ob[2] + v2.n.ob[2]) / 2.0f), - Vec3f((v2.n.ob[0] + v0.n.ob[0]) / 2.0f, (v2.n.ob[1] + v0.n.ob[1]) / 2.0f, (v2.n.ob[2] + v0.n.ob[2]) / 2.0f) + Vec3f{(v0.n.ob[0] + v1.n.ob[0]) / 2.0f, (v0.n.ob[1] + v1.n.ob[1]) / 2.0f, (v0.n.ob[2] + v1.n.ob[2]) / 2.0f}, + Vec3f{(v1.n.ob[0] + v2.n.ob[0]) / 2.0f, (v1.n.ob[1] + v2.n.ob[1]) / 2.0f, (v1.n.ob[2] + v2.n.ob[2]) / 2.0f}, + Vec3f{(v2.n.ob[0] + v0.n.ob[0]) / 2.0f, (v2.n.ob[1] + v0.n.ob[1]) / 2.0f, (v2.n.ob[2] + v0.n.ob[2]) / 2.0f} }; // Normalize vertex positions so they are on the sphere @@ -221,20 +221,20 @@ void CreateSphereData() { float d = (1.0f + sqrtf(5.0f)) / 2.0f; // Create the 12 starting verticies, 4 on each rectangle - base.emplace_back(-1, d, 0); - base.emplace_back(1, d, 0); - base.emplace_back(-1, -d, 0); - base.emplace_back(1, -d, 0); + base.emplace_back(Vec3f({-1, d, 0})); + base.emplace_back(Vec3f({1, d, 0})); + base.emplace_back(Vec3f({-1, -d, 0})); + base.emplace_back(Vec3f({1, -d, 0})); - base.emplace_back(0, -1, d); - base.emplace_back(0, 1, d); - base.emplace_back(0, -1, -d); - base.emplace_back(0, 1, -d); + base.emplace_back(Vec3f({0, -1, d})); + base.emplace_back(Vec3f({0, 1, d})); + base.emplace_back(Vec3f({0, -1, -d})); + base.emplace_back(Vec3f({0, 1, -d})); - base.emplace_back(d, 0, -1); - base.emplace_back(d, 0, 1); - base.emplace_back(-d, 0, -1); - base.emplace_back(-d, 0, 1); + base.emplace_back(Vec3f({d, 0, -1})); + base.emplace_back(Vec3f({d, 0, 1})); + base.emplace_back(Vec3f({-d, 0, -1})); + base.emplace_back(Vec3f({-d, 0, 1})); // Normalize verticies so they are on the unit sphere for (Vec3f& v : base) { diff --git a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp index 8ccd10ba5..0c9d0f25b 100644 --- a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp +++ b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp @@ -185,17 +185,17 @@ typedef struct { // Maps quest items ids to info for use in ImGui std::map questMapping = { - QUEST_MAP_ENTRY(QUEST_MEDALLION_FOREST, gForestMedallionIconTex), - QUEST_MAP_ENTRY(QUEST_MEDALLION_FIRE, gFireMedallionIconTex), - QUEST_MAP_ENTRY(QUEST_MEDALLION_WATER, gWaterMedallionIconTex), - QUEST_MAP_ENTRY(QUEST_MEDALLION_SPIRIT, gSpiritMedallionIconTex), - QUEST_MAP_ENTRY(QUEST_MEDALLION_SHADOW, gShadowMedallionIconTex), - QUEST_MAP_ENTRY(QUEST_MEDALLION_LIGHT, gLightMedallionIconTex), - QUEST_MAP_ENTRY(QUEST_KOKIRI_EMERALD, gKokiriEmeraldIconTex), - QUEST_MAP_ENTRY(QUEST_GORON_RUBY, gGoronRubyIconTex), - QUEST_MAP_ENTRY(QUEST_ZORA_SAPPHIRE, gZoraSapphireIconTex), - QUEST_MAP_ENTRY(QUEST_STONE_OF_AGONY, gStoneOfAgonyIconTex), - QUEST_MAP_ENTRY(QUEST_GERUDO_CARD, gGerudosCardIconTex), + QUEST_MAP_ENTRY(QUEST_MEDALLION_FOREST, dgForestMedallionIconTex), + QUEST_MAP_ENTRY(QUEST_MEDALLION_FIRE, dgFireMedallionIconTex), + QUEST_MAP_ENTRY(QUEST_MEDALLION_WATER, dgWaterMedallionIconTex), + QUEST_MAP_ENTRY(QUEST_MEDALLION_SPIRIT, dgSpiritMedallionIconTex), + QUEST_MAP_ENTRY(QUEST_MEDALLION_SHADOW, dgShadowMedallionIconTex), + QUEST_MAP_ENTRY(QUEST_MEDALLION_LIGHT, dgLightMedallionIconTex), + QUEST_MAP_ENTRY(QUEST_KOKIRI_EMERALD, dgKokiriEmeraldIconTex), + QUEST_MAP_ENTRY(QUEST_GORON_RUBY, dgGoronRubyIconTex), + QUEST_MAP_ENTRY(QUEST_ZORA_SAPPHIRE, dgZoraSapphireIconTex), + QUEST_MAP_ENTRY(QUEST_STONE_OF_AGONY, dgStoneOfAgonyIconTex), + QUEST_MAP_ENTRY(QUEST_GERUDO_CARD, dgGerudosCardIconTex), }; typedef struct { diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 9bb5da000..ff8755006 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -1330,17 +1330,17 @@ extern "C" int16_t OTRGetRectDimensionFromRightEdge(float v) { } extern "C" void bswapSoundFontSound(SoundFontSound* swappable) { - swappable->sample = (SoundFontSample*)BOMSWAP32((u32)swappable->sample); - swappable->tuningAsU32 = BOMSWAP32((u32)swappable->tuningAsU32); + swappable->sample = (SoundFontSample*)BOMSWAP32((u32)(uintptr_t(swappable->sample))); + swappable->tuningAsU32 = BOMSWAP32((u32)(swappable->tuningAsU32 & 0xFFFFFFFF)); } extern "C" void bswapDrum(Drum* swappable) { bswapSoundFontSound(&swappable->sound); - swappable->envelope = (AdsrEnvelope*)BOMSWAP32((u32)swappable->envelope); + swappable->envelope = (AdsrEnvelope*)BOMSWAP32((u32)uintptr_t(swappable->envelope)); } extern "C" void bswapInstrument(Instrument* swappable) { - swappable->envelope = (AdsrEnvelope*)BOMSWAP32((u32)swappable->envelope); + swappable->envelope = (AdsrEnvelope*)BOMSWAP32((u32)uintptr_t(swappable->envelope)); bswapSoundFontSound(&swappable->lowNotesSound); bswapSoundFontSound(&swappable->normalNotesSound); bswapSoundFontSound(&swappable->highNotesSound); @@ -1355,9 +1355,9 @@ extern "C" void bswapSoundFontSample(SoundFontSample* swappable) { swappable->unk_bit25 = (origBitfield >> 21) & 0x01; swappable->size = (origBitfield) & 0x00FFFFFF; - swappable->sampleAddr = (u8*)BOMSWAP32((u32)swappable->sampleAddr); - swappable->loop = (AdpcmLoop*)BOMSWAP32((u32)swappable->loop); - swappable->book = (AdpcmBook*)BOMSWAP32((u32)swappable->book); + swappable->sampleAddr = (u8*)BOMSWAP32((u32)uintptr_t(swappable->sampleAddr)); + swappable->loop = (AdpcmLoop*)BOMSWAP32((u32)uintptr_t(swappable->loop)); + swappable->book = (AdpcmBook*)BOMSWAP32((u32)uintptr_t(swappable->book)); } extern "C" void bswapAdpcmLoop(AdpcmLoop* swappable) { diff --git a/soh/soh/gu_pc.c b/soh/soh/gu_pc.c index 7bdcded98..be1954a5d 100644 --- a/soh/soh/gu_pc.c +++ b/soh/soh/gu_pc.c @@ -1,3 +1,4 @@ +#include #include "z64.h" void guMtxF2L(float mf[4][4], Mtx* m) { @@ -84,4 +85,4 @@ void guNormalize(f32* x, f32* y, f32* z) { *x = *x * tmp; *y = *y * tmp; *z = *z * tmp; -} \ No newline at end of file +} diff --git a/soh/src/code/game.c b/soh/src/code/game.c index 306b292bc..9e0cfb50b 100644 --- a/soh/src/code/game.c +++ b/soh/src/code/game.c @@ -1,3 +1,4 @@ +#include #include "global.h" #include "vt.h" @@ -9,6 +10,9 @@ ViMode sViMode; FaultClient sGameFaultClient; u16 sLastButtonPressed; +// Forward declared, because this in a C++ header. +int gfx_create_framebuffer(uint32_t width, uint32_t height); + void GameState_FaultPrint(void) { static char sBtnChars[] = "ABZSuldr*+LRudlr"; s32 i; diff --git a/soh/src/overlays/gamestates/ovl_title/z_title.c b/soh/src/overlays/gamestates/ovl_title/z_title.c index 065059a32..0ab8e699e 100644 --- a/soh/src/overlays/gamestates/ovl_title/z_title.c +++ b/soh/src/overlays/gamestates/ovl_title/z_title.c @@ -33,6 +33,8 @@ void Title_PrintBuildInfo(Gfx** gfxp) { #ifdef _MSC_VER GfxPrint_Printf(&printer, "MSVC SHIP"); +#elif __clang__ + GfxPrint_Printf(&printer, "CLANG SHIP"); #else GfxPrint_Printf(&printer, "GCC SHIP"); #endif From e04bc6037e09d609456aed9ea9238c1822008b27 Mon Sep 17 00:00:00 2001 From: Sirius902 <3645979-Sirius902@users.noreply.gitlab.com> Date: Sun, 10 Jul 2022 09:25:45 -0700 Subject: [PATCH 15/44] Fix develop --- soh/include/functions.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/soh/include/functions.h b/soh/include/functions.h index 78986cc85..3dcf5f936 100644 --- a/soh/include/functions.h +++ b/soh/include/functions.h @@ -2397,6 +2397,8 @@ char* SetQuote(); void Heaps_Alloc(void); void Heaps_Free(void); +CollisionHeader* BgCheck_GetCollisionHeader(CollisionContext* colCtx, s32 bgId); + #ifdef __cplusplus #undef this }; From 926fd3f40618c80884c89df94c0b94c14ef603c9 Mon Sep 17 00:00:00 2001 From: Ada <60364512+GreatArgorath@users.noreply.github.com> Date: Sun, 10 Jul 2022 11:59:48 +0100 Subject: [PATCH 16/44] Fixes grey screen issue + tooltip for 2 handed shield --- libultraship/libultraship/ImGuiImpl.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libultraship/libultraship/ImGuiImpl.cpp b/libultraship/libultraship/ImGuiImpl.cpp index 7b1d905e7..64798212c 100644 --- a/libultraship/libultraship/ImGuiImpl.cpp +++ b/libultraship/libultraship/ImGuiImpl.cpp @@ -1218,7 +1218,7 @@ namespace SohImGui { EnhancementCheckbox("Fireproof Deku Shield", "gFireproofDekuShield"); Tooltip("Prevents the Deku Shield from burning on contact with fire"); EnhancementCheckbox("Shield with Two-Handed Weapons", "gShieldTwoHanded"); - Tooltip("This allows you to put up your shield with any two-handed weapon in hand"); + Tooltip("This allows you to put up your shield with any two-handed weapon in hand\nexcept for Deku Sticks"); ImGui::EndMenu(); } @@ -1293,7 +1293,7 @@ namespace SohImGui { ImGui::PushStyleVar(ImGuiStyleVar_ChildBorderSize, 0.0f); ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f)); ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBackground; - ImGui::Begin("OoT Master Quest", nullptr, flags); + ImGui::Begin("Main Game", nullptr, flags); ImGui::PopStyleVar(3); ImGui::PopStyleColor(); From e3267a4e9bbae56a6569bdf1555ed32f57a4a1e4 Mon Sep 17 00:00:00 2001 From: Sirius902 <10891979+Sirius902@users.noreply.github.com> Date: Sun, 10 Jul 2022 18:40:00 -0700 Subject: [PATCH 17/44] Don't close controller after SDL has quit (#642) * Don't close controller after SDL has quit * Don't check if controller can rumble if null --- libultraship/libultraship/SDLController.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libultraship/libultraship/SDLController.cpp b/libultraship/libultraship/SDLController.cpp index 2d8e8bb0d..bc89cc78a 100644 --- a/libultraship/libultraship/SDLController.cpp +++ b/libultraship/libultraship/SDLController.cpp @@ -101,10 +101,10 @@ namespace Ship { } bool SDLController::Close() { - if (CanRumble()) { - SDL_GameControllerRumble(Cont, 0, 0, 0); - } - if (Cont != nullptr) { + if (Cont != nullptr && SDL_WasInit(SDL_INIT_GAMECONTROLLER)) { + if (CanRumble()) { + SDL_GameControllerRumble(Cont, 0, 0, 0); + } SDL_GameControllerClose(Cont); } Cont = nullptr; From 4ccc2bb12f4dabff55f7f6726345e9a835add116 Mon Sep 17 00:00:00 2001 From: Christopher Leggett Date: Sun, 10 Jul 2022 21:40:57 -0400 Subject: [PATCH 18/44] Fixes Barinade's set whenever boss fight is reloaded (#639) * Reimplements unused Barinade reset function. * Removes the Jellyfish from Barinade's body on reset. --- soh/src/overlays/actors/ovl_Boss_Va/z_boss_va.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/soh/src/overlays/actors/ovl_Boss_Va/z_boss_va.c b/soh/src/overlays/actors/ovl_Boss_Va/z_boss_va.c index 20627d434..6f492145b 100644 --- a/soh/src/overlays/actors/ovl_Boss_Va/z_boss_va.c +++ b/soh/src/overlays/actors/ovl_Boss_Va/z_boss_va.c @@ -121,6 +121,7 @@ void BossVa_Init(Actor* thisx, GlobalContext* globalCtx); void BossVa_Destroy(Actor* thisx, GlobalContext* globalCtx); void BossVa_Update(Actor* thisx, GlobalContext* globalCtx); void BossVa_Draw(Actor* thisx, GlobalContext* globalCtx); +void BossVa_Reset(void); void BossVa_UpdateEffects(GlobalContext* globalCtx); void BossVa_DrawEffects(BossVaEffect* effect, GlobalContext* globalCtx); @@ -204,7 +205,7 @@ const ActorInit Boss_Va_InitVars = { (ActorFunc)BossVa_Destroy, (ActorFunc)BossVa_Update, (ActorFunc)BossVa_Draw, - NULL, + (ActorResetFunc)BossVa_Reset, }; static ColliderCylinderInit sCylinderInit = { @@ -593,6 +594,8 @@ void BossVa_Init(Actor* thisx, GlobalContext* globalCtx2) { switch (this->actor.params) { case BOSSVA_BODY: + //sFightPhase = 0; + //sBodyState = 1; SkelAnime_Init(globalCtx, &this->skelAnime, &gBarinadeBodySkel, &gBarinadeBodyAnim, NULL, NULL, 0); this->actor.flags |= ACTOR_FLAG_24; break; @@ -4032,6 +4035,8 @@ void BossVa_DrawDoor(GlobalContext* globalCtx, s16 scale) { CLOSE_DISPS(globalCtx->state.gfxCtx); } +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + void BossVa_Reset(void) { sKillBari = 0; sCsCamera = 0; @@ -4046,4 +4051,7 @@ void BossVa_Reset(void) { sZapperRot.z = 0; sPhase2Timer = 0; sPhase4HP = 0; + for (u8 i = 0; i < ARRAY_SIZE(sBodyBari); i++) { + sBodyBari[i] = 0; + } } From a7c94bba8ca3568355239d136d0c511e15fdb306 Mon Sep 17 00:00:00 2001 From: louist103 <35883445+louist103@users.noreply.github.com> Date: Sun, 10 Jul 2022 21:42:35 -0400 Subject: [PATCH 19/44] add the ability to pull graves during the day (#637) --- libultraship/libultraship/ImGuiImpl.cpp | 2 ++ soh/src/overlays/actors/ovl_Bg_Haka/z_bg_haka.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/libultraship/libultraship/ImGuiImpl.cpp b/libultraship/libultraship/ImGuiImpl.cpp index 64798212c..460afdbda 100644 --- a/libultraship/libultraship/ImGuiImpl.cpp +++ b/libultraship/libultraship/ImGuiImpl.cpp @@ -1033,6 +1033,8 @@ namespace SohImGui { EnhancementCheckbox("Enable passage of time on file select", "gTimeFlowFileSelect"); EnhancementCheckbox("Allow the cursor to be on any slot", "gPauseAnyCursor"); Tooltip("Allows the cursor on the pause menu to be over any slot\nSimilar to Rando and Spaceworld 97"); + EnhancementCheckbox("Pull grave during the day", "gDayGravePull"); + Tooltip("Allows graves to be pulled when child during the day"); ImGui::EndMenu(); } diff --git a/soh/src/overlays/actors/ovl_Bg_Haka/z_bg_haka.c b/soh/src/overlays/actors/ovl_Bg_Haka/z_bg_haka.c index 5aae3399a..79b581db9 100644 --- a/soh/src/overlays/actors/ovl_Bg_Haka/z_bg_haka.c +++ b/soh/src/overlays/actors/ovl_Bg_Haka/z_bg_haka.c @@ -69,7 +69,7 @@ void func_8087B7E8(BgHaka* this, GlobalContext* globalCtx) { Player* player = GET_PLAYER(globalCtx); if (this->dyna.unk_150 != 0.0f) { - if (globalCtx->sceneNum == SCENE_SPOT02 && !LINK_IS_ADULT && IS_DAY) { + if ((globalCtx->sceneNum == SCENE_SPOT02 && !LINK_IS_ADULT && IS_DAY) && !CVar_GetS32("gDayGravePull", 0)) { this->dyna.unk_150 = 0.0f; player->stateFlags2 &= ~0x10; if (!Gameplay_InCsMode(globalCtx)) { From c9497060e95e432a0ff14933a98edbc709874a4c Mon Sep 17 00:00:00 2001 From: briaguya <70942617+briaguya-ai@users.noreply.github.com> Date: Sun, 10 Jul 2022 22:14:38 -0400 Subject: [PATCH 20/44] change max internal res multiplier to 3x, use float and % instead of int (#638) * change max internal res multiplier to 3x, use float and % instead of int * Update libultraship/libultraship/ImGuiImpl.cpp Co-authored-by: Kenix3 Co-authored-by: briaguya Co-authored-by: Kenix3 --- libultraship/libultraship/ImGuiImpl.cpp | 4 ++-- libultraship/libultraship/Lib/Fast3D/gfx_pc.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libultraship/libultraship/ImGuiImpl.cpp b/libultraship/libultraship/ImGuiImpl.cpp index 460afdbda..409675da2 100644 --- a/libultraship/libultraship/ImGuiImpl.cpp +++ b/libultraship/libultraship/ImGuiImpl.cpp @@ -853,9 +853,9 @@ namespace SohImGui { if (ImGui::BeginMenu("Graphics")) { - EnhancementSliderInt("Internal Resolution: %dx", "##IMul", "gInternalResolution", 1, 8, ""); + EnhancementSliderFloat("Internal Resolution: %d %%", "##IMul", "gInternalResolution", 0.5f, 2.0f, "", 1.0f, true); Tooltip("Multiplies your output resolution by the value inputted,\nas a more intensive but effective form of anti-aliasing"); - gfx_current_dimensions.internal_mul = CVar_GetS32("gInternalResolution", 1); + gfx_current_dimensions.internal_mul = CVar_GetFloat("gInternalResolution", 1); EnhancementSliderInt("MSAA: %d", "##IMSAA", "gMSAAValue", 1, 8, ""); Tooltip("Activates multi-sample anti-aliasing when above 1x\nup to 8x for 8 samples for every pixel"); gfx_msaa_level = CVar_GetS32("gMSAAValue", 1); diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_pc.h b/libultraship/libultraship/Lib/Fast3D/gfx_pc.h index f07147c14..4e620ef2d 100644 --- a/libultraship/libultraship/Lib/Fast3D/gfx_pc.h +++ b/libultraship/libultraship/Lib/Fast3D/gfx_pc.h @@ -23,7 +23,7 @@ struct XYWidthHeight { }; struct GfxDimensions { - uint32_t internal_mul; + float internal_mul; uint32_t width, height; float aspect_ratio; }; From 6b50b50a6ccabdf934c69bf2729ca5fe51fbdb30 Mon Sep 17 00:00:00 2001 From: Kenix3 Date: Mon, 11 Jul 2022 00:20:03 -0400 Subject: [PATCH 21/44] Fixes crash on Biggoron trade failure screen wipe Resolves #621 --- soh/src/code/z_fbdemo_wipe1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soh/src/code/z_fbdemo_wipe1.c b/soh/src/code/z_fbdemo_wipe1.c index 3c3587420..1dfb0a501 100644 --- a/soh/src/code/z_fbdemo_wipe1.c +++ b/soh/src/code/z_fbdemo_wipe1.c @@ -20,7 +20,7 @@ Gfx sWipeDList[] = { G_TX_MIRROR | G_TX_WRAP, 6, 6, 11, 1), gsDPSetTextureLUT(G_TT_NONE), gsSPTexture(0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON), - gsSPDisplayList(0x08000000), + gsSPDisplayList(SEG_ADDR(8, 0)), gsSPVertex(sWipe1Vtx, 25, 0), gsSP2Triangles(0, 1, 2, 0, 1, 3, 4, 0), gsSP2Triangles(5, 6, 7, 0, 6, 8, 9, 0), From 0fd779f002026fd9670ad27841975b13576c7923 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Mon, 11 Jul 2022 18:13:01 -0400 Subject: [PATCH 22/44] fixes center docking (#652) --- libultraship/libultraship/ImGuiImpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libultraship/libultraship/ImGuiImpl.cpp b/libultraship/libultraship/ImGuiImpl.cpp index 409675da2..fd4e298b3 100644 --- a/libultraship/libultraship/ImGuiImpl.cpp +++ b/libultraship/libultraship/ImGuiImpl.cpp @@ -723,7 +723,7 @@ namespace SohImGui { ImGui::DockBuilderFinish(dockId); } - ImGui::DockSpace(dockId, ImVec2(0.0f, 0.0f), ImGuiDockNodeFlags_None); + ImGui::DockSpace(dockId, ImVec2(0.0f, 0.0f), ImGuiDockNodeFlags_None | ImGuiDockNodeFlags_NoDockingInCentralNode); if (ImGui::IsKeyPressed(TOGGLE_BTN)) { bool menu_bar = CVar_GetS32("gOpenMenuBar", 0); From c25089b98ffea81d0156f212f2df3ee5caf7e05f Mon Sep 17 00:00:00 2001 From: briaguya <70942617+briaguya-ai@users.noreply.github.com> Date: Mon, 11 Jul 2022 20:11:07 -0400 Subject: [PATCH 23/44] testing out item replacement (#416) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * skip learning song of storms * don't set flag when getting goron tunic as child * Initiates prelude check when master sword unloads. Not quite how N64 rando does it but so far it's the only way I've found to make it trigger without also triggering the time travel again. * Stops Shadow Temple lore prompts from appearing in rando. * Skips cutscene of royal tomb explosion in rando. Explosion sound doesn't play correctly and I think the debris appears in the wrong place, but the functionality is here. * Improves visual of exploding gravestone. * Adds some comments explaining the rando differences * Skip ruto text box in jabu blue warp For rando * skip intro cutscene in dodongo's cavern * load spoiler files on boot, fix spoilerfile existing check when making new saves * name entry dropped spoiler logic * make sure to actually init the cvar * no chime on load * uncomment * Skip ganondrof cutscene Skip to scream part of the death animation, skipping the text boxes etc. For rando * Update z_boss_ganondrof.c * skip owl flight cutscenes in rando * Fixes skipped text so it only applies to shadow temple. Earlier fix inadvertently applied to some other text as well, changed logic so that only specified sceneNums and textIds can have this enabled, and text skipped by sceneNum can have the skip overriden by textId if needed. Currently there are no overrides so the textId section of the logic is commented out to avoid compilation errors. * Adds a default to the switch case statements that leaves the randoSkipText variable unchanged, just in case. * TEST: Text for item * Adding ganon flavor text * ADD: AMMO Count * format ganon text/hint text * Autoskip the tower cutscene if settings call for tower collapse. * ganon hint text logic * Improved prelude after time travel fix * swapped the sizes between ganon hint text and ganon text, as they were set to the wrong things. * this is all i did * not the cleanest code ever but it's working * ADD: GS Count * ADD: Wallter (crash for now) * TWEAK: Wallet check * FIX: Use DrawItem instread of DrawUpgrade... b-baka! * Fixes some vanilla bugs introduced by rando code. * Added cutscene skip for zelda escaping Using the debug cutscene skipping function. Also added a conditional so the bridge doesn't spawn closed when cutscene is ready to trigger * ADD: X Spacing + Placeholders for song * ADD: default case for items * TWEAK: Spacing * FIX: Light Arrow * ADD: Ammo Option * use groups instead * ADD: More spacing logic * songs and names * TWEAK: Color on wallet * colors * Added flags cutscene before nabooru fight * ADD: ChromaKey text * First attempt skip cs after nabooru defeat * Better implementation for specific rando cutscene skips * use pulseaudio defaults * spaces/tabs * move color push/pop to stop crash * make the colors work again * the real bottle fix * pulseaudio values tuned for n64 audio at 44.1khz * update tlength * remove one hardcoded samplerate * Cleaned up and fixed zelda escape skip The if statement is a freaking monster, but unless we want to skip more cutscenes in the same way later, this is the most compact way of doing it that I know of. * Revert one line to match original nothing functional * another hint line that breaks autonewline logic * don't autospawn epona if we don't have the song/ocarina * Trying to use iron knuckle death effects not working yet * Streamlined OoT cutscene skip for future additions Also cleaned up if statement in general * Made if statement more readable Also added clarity for what cutscene was skipped * Fixed typo in comment * Janky nabooru defeat cs skip * altar text formatting (gonna need help shortening some of the french ones) * more altar text formatting * english altar text formatting complete * make gtg blocking guard check for card not bridge * FIX: Typo! * FIX: Uppercases * FIX: Typo * TWEAK: Alter + some names * TWEAK: More caps! * ADD: Missing string TWEAK more uppercases and namefixe s * Hide nabooru death by covering her in flames * bandaid fix for death crash issue * Twinrova defeat cs skip Skips the animation and manually calls the function to show the "beam" around the sisters * fix crash * fix caps to match * fix great fairy reward mashing/shielding issue * TWEAK : Typo clé to Clé * TWEAK: Some Altar hints TWEAK: Some capitals * TWEAK: Unmatching text + some cap again * TWEAK: More tweaks * fix build * remove extra json.hpp, add hint * Update randomizer_item_tracker.cpp * TWEAK: Double Defense with RedParticles instead of white * make sure we don't optimize out the check to ensure a spoilerfile exists * vanilla ganon boss key hint formatting * TWEAK: FR- better way of the hero text * fix * and again * Initializes dungeonsDone items in gSaveContext to 0. * Replaces sizeof calculation with a NUM_DUNGEONS constant. * Fixes Saria's Gift on the LW Bridge from getting killed when holding shield. * More airtight fix for Saria's Gift on the Bridge. * Lifts one of the conditions in the if statement a little higher to prevent unnecessary lookups of getItemId. * Invalidate text box icon before drawing * Fixes the case where Saria's gift is an Ice Trap. We still get the Ice Trap once, but never again. This does mean you can now hold R while walking in to avoid the ice trap, but everything else seems to work fine. * Initial commit Might need changing when we change the settings in the future * Fixes Door of Time opening cutscene after warping with prelude. * Initial waterfall skip Very rudimentary way of doing things but it seems to work so :shrug: * inital rework * fixed default rotation for 2D sprites * fix tab/space issues * 3d drops rando merge fix again * Allows Impa to appear in the Lullaby check post drawbridge escape. * Changes Ganon's Trials Count setting to a checkbox The checkbox is whether or not to skip all of them. Leaving the box unchecked will mean doing all of them. Eventually this will be switched back to a slider once we implement the logic for which trials start out completed. * Sets all Ganon's Trials to incomplete in new saves. Fixes https://github.com/briaguya-ai/rando-issue-tracker/issues/131 * fix castle guards when oot throw cutscene has already played in rando * Properly removes the beams when trials are cleared. * Removes Question Mark from Skip Ganon's Trials UI. * Adds a todo comment about when to change back to slider. * make deku seeds check for bullet bag * Various tweaks TWEAK: Altar Text TWEAK: Hint names TWEAK: Replace more problematic œ to oe * upgrade ocarina on both child and adult equips * FIX: Jabu Item * update equipped hookshot/longshot when obtained as other age * add hint * don't give the bgs check without the claim check * Skips Darunia Cutscene in Fire Temple * Added a TODO note about not skipping the cutscene. There is a setting we will want to have eventually that will require this cutscene to not be skipped since it is used during a glitch. * remove todo * restore fast ocarina option in imgui that was lost in merge * Fixes grey screen issue + tooltip for 2 handed shield * update to use dg instead of g for textures in item tracker * TWEAK: Default color for cosmetic RAND button was not the corect one * fix texture crash, remove unused item tracker code * don't open mask shop until we get zelda's letter * Update README.md * Prevents "correct" chime under incorrect conditions. * Fixes typo in conditional and adds "bonk" sound effect. "Bonk" sound is NA_SE_SY_OCARINA_ERROR and it plays when conditions for the Door of Time have not been met after playing Song of Time. This is only possible in rando's "Intended" Door of Time option, in which the Ocarina of Time and all 3 spritual stones are required to open the door, instead of the vanilla requirements of just having the song of time. * remove modify dpad equips toggle, replace with checks for dpad menu * remove extra check * add ability to hold c-up to assign to dpad when dpad menuing is enabled * disable d-pad navigation on item menu when holding c-up to equip * dpad+c-up stuff for equipment menu * ADD: Checbox for songs colors * TWEAK: RandoColors for normal songs * kind of quick and dirty but it works * TWEAK: Clarity of the tooltip Co-authored-by: briaguya Co-authored-by: Christopher Leggett Co-authored-by: aMannus Co-authored-by: PurpleHato Co-authored-by: Dog <5172592+Dog@users.noreply.github.com> Co-authored-by: Vague Rant Co-authored-by: Baoulettes Co-authored-by: Ada <60364512+GreatArgorath@users.noreply.github.com> --- README.md | 2 - libultraship/libultraship/Cvar.cpp | 2 +- libultraship/libultraship/Cvar.h | 2 +- libultraship/libultraship/GameSettings.cpp | 2 +- libultraship/libultraship/ImGuiImpl.cpp | 56 +- libultraship/libultraship/ImGuiImpl.h | 2 +- .../Lib/Fast3D/gfx_direct3d11.cpp | 8 +- .../libultraship/Lib/Fast3D/gfx_dxgi.cpp | 24 +- .../libultraship/Lib/Fast3D/gfx_opengl.cpp | 7 +- .../Lib/Fast3D/gfx_rendering_api.h | 6 +- .../libultraship/Lib/Fast3D/gfx_sdl2.cpp | 11 +- .../libultraship/PulseAudioPlayer.cpp | 2 +- soh/include/functions.h | 1 + soh/include/z64.h | 1 + soh/include/z64actor.h | 1 + soh/include/z64item.h | 70 +- soh/include/z64player.h | 4 +- soh/include/z64save.h | 27 + soh/randomizerTypes.h | 1000 ++++ soh/randomizer_generation.cpp | 19 + soh/soh.vcxproj | 94 + soh/soh.vcxproj.filters | 284 +- .../Enhancements/debugger/debugSaveEditor.cpp | 43 +- soh/soh/Enhancements/gfx.c | 63 + soh/soh/Enhancements/gfx.h | 17 + .../randomizer/3drando/category.hpp | 71 + .../randomizer/3drando/cosmetics.cpp | 152 + .../randomizer/3drando/cosmetics.hpp | 50 + .../randomizer/3drando/custom_messages.cpp | 495 ++ .../randomizer/3drando/custom_messages.hpp | 93 + .../Enhancements/randomizer/3drando/debug.cpp | 5 + .../Enhancements/randomizer/3drando/debug.hpp | 5 + .../randomizer/3drando/dungeon.cpp | 616 +++ .../randomizer/3drando/dungeon.hpp | 104 + .../randomizer/3drando/entrance.cpp | 877 +++ .../randomizer/3drando/entrance.hpp | 320 ++ .../Enhancements/randomizer/3drando/fill.cpp | 1074 ++++ .../Enhancements/randomizer/3drando/fill.hpp | 27 + .../randomizer/3drando/hint_list.cpp | 2268 ++++++++ .../randomizer/3drando/hint_list.hpp | 16 + .../hint_list/hint_list_exclude_dungeon.cpp | 1964 +++++++ .../hint_list/hint_list_exclude_overworld.cpp | 1272 +++++ .../3drando/hint_list/hint_list_item.cpp | 1952 +++++++ .../Enhancements/randomizer/3drando/hints.cpp | 878 +++ .../Enhancements/randomizer/3drando/hints.hpp | 227 + .../Enhancements/randomizer/3drando/item.cpp | 84 + .../Enhancements/randomizer/3drando/item.hpp | 142 + .../randomizer/3drando/item_list.cpp | 290 + .../randomizer/3drando/item_list.hpp | 8 + .../randomizer/3drando/item_location.cpp | 1580 ++++++ .../randomizer/3drando/item_location.hpp | 490 ++ .../randomizer/3drando/item_pool.cpp | 1179 ++++ .../randomizer/3drando/item_pool.hpp | 18 + .../Enhancements/randomizer/3drando/keys.hpp | 1682 ++++++ .../randomizer/3drando/location_access.cpp | 898 ++++ .../randomizer/3drando/location_access.hpp | 266 + .../locacc_bottom_of_the_well.cpp | 88 + .../location_access/locacc_castle_town.cpp | 265 + .../location_access/locacc_death_mountain.cpp | 293 + .../location_access/locacc_deku_tree.cpp | 266 + .../locacc_dodongos_cavern.cpp | 319 ++ .../location_access/locacc_fire_temple.cpp | 456 ++ .../location_access/locacc_forest_temple.cpp | 452 ++ .../location_access/locacc_ganons_castle.cpp | 213 + .../locacc_gerudo_training_grounds.cpp | 199 + .../location_access/locacc_gerudo_valley.cpp | 234 + .../location_access/locacc_hyrule_field.cpp | 267 + .../location_access/locacc_ice_cavern.cpp | 86 + .../locacc_jabujabus_belly.cpp | 245 + .../location_access/locacc_kakariko.cpp | 303 ++ .../location_access/locacc_lost_woods.cpp | 275 + .../location_access/locacc_shadow_temple.cpp | 189 + .../location_access/locacc_spirit_temple.cpp | 232 + .../location_access/locacc_water_temple.cpp | 351 ++ .../location_access/locacc_zoras_domain.cpp | 188 + .../Enhancements/randomizer/3drando/logic.cpp | 1218 +++++ .../Enhancements/randomizer/3drando/logic.hpp | 387 ++ .../Enhancements/randomizer/3drando/menu.cpp | 550 ++ .../Enhancements/randomizer/3drando/menu.hpp | 52 + .../Enhancements/randomizer/3drando/music.cpp | 128 + .../Enhancements/randomizer/3drando/music.hpp | 29 + .../Enhancements/randomizer/3drando/patch.cpp | 25 + .../Enhancements/randomizer/3drando/patch.hpp | 12 + .../randomizer/3drando/playthrough.cpp | 97 + .../randomizer/3drando/playthrough.hpp | 9 + .../randomizer/3drando/pool_functions.hpp | 38 + .../randomizer/3drando/preset.cpp | 202 + .../randomizer/3drando/preset.hpp | 17 + .../randomizer/3drando/rando_main.cpp | 27 + .../randomizer/3drando/rando_main.hpp | 5 + .../randomizer/3drando/random.cpp | 29 + .../randomizer/3drando/random.hpp | 46 + .../randomizer/3drando/randomizer.hpp | 4 + .../3drando/setting_descriptions.cpp | 1696 ++++++ .../3drando/setting_descriptions.hpp | 541 ++ .../randomizer/3drando/settings.cpp | 2779 ++++++++++ .../randomizer/3drando/settings.hpp | 1282 +++++ .../Enhancements/randomizer/3drando/shops.cpp | 735 +++ .../Enhancements/randomizer/3drando/shops.hpp | 23 + .../randomizer/3drando/sound_effects.cpp | 1479 +++++ .../randomizer/3drando/sound_effects.hpp | 76 + .../randomizer/3drando/spoiler_log.cpp | 770 +++ .../randomizer/3drando/spoiler_log.hpp | 111 + .../randomizer/3drando/starting_inventory.cpp | 193 + .../randomizer/3drando/starting_inventory.hpp | 13 + .../Enhancements/randomizer/3drando/text.hpp | 90 + .../randomizer/3drando/tinyxml2.cpp | 2956 ++++++++++ .../randomizer/3drando/tinyxml2.h | 2365 ++++++++ .../Enhancements/randomizer/3drando/trial.cpp | 26 + .../Enhancements/randomizer/3drando/trial.hpp | 51 + .../Enhancements/randomizer/3drando/utils.cpp | 7 + .../Enhancements/randomizer/3drando/utils.hpp | 6 + .../Enhancements/randomizer/randomizer.cpp | 4759 +++++++++++++++++ soh/soh/Enhancements/randomizer/randomizer.h | 58 + .../randomizer/randomizer_item_tracker.cpp | 1019 ++++ .../randomizer/randomizer_item_tracker.h | 4 + soh/soh/OTRGlobals.cpp | 159 +- soh/soh/OTRGlobals.h | 17 + soh/soh/SaveManager.cpp | 118 +- soh/soh/SaveManager.h | 6 +- soh/src/code/z_actor.c | 73 + soh/src/code/z_demo.c | 63 +- soh/src/code/z_draw.c | 133 + soh/src/code/z_en_item00.c | 149 +- soh/src/code/z_horse.c | 4 +- soh/src/code/z_lights.c | 4 +- soh/src/code/z_message_PAL.c | 113 +- soh/src/code/z_onepointdemo.c | 7 +- soh/src/code/z_parameter.c | 160 +- soh/src/code/z_play.c | 82 +- soh/src/code/z_sram.c | 666 ++- .../ovl_Bg_Dy_Yoseizo/z_bg_dy_yoseizo.c | 25 + .../ovl_Bg_Gate_Shutter/z_bg_gate_shutter.c | 4 +- .../ovl_Bg_Gjyo_Bridge/z_bg_gjyo_bridge.c | 157 +- .../overlays/actors/ovl_Bg_Haka/z_bg_haka.c | 2 +- .../z_bg_spot00_hanebasi.c | 3 +- .../z_bg_spot02_objects.c | 29 +- .../z_bg_spot06_objects.c | 4 +- .../actors/ovl_Bg_Toki_Swd/z_bg_toki_swd.c | 25 +- .../actors/ovl_Boss_Ganon/z_boss_ganon.c | 14 +- .../ovl_Boss_Ganondrof/z_boss_ganondrof.c | 22 +- .../overlays/actors/ovl_Boss_Tw/z_boss_tw.c | 17 +- .../actors/ovl_Demo_Effect/z_demo_effect.c | 13 +- .../overlays/actors/ovl_Demo_Im/z_demo_im.c | 34 +- .../actors/ovl_Demo_Kekkai/z_demo_kekkai.c | 63 + .../actors/ovl_Door_Warp1/z_door_warp1.c | 175 +- soh/src/overlays/actors/ovl_En_Ani/z_en_ani.c | 15 +- .../ovl_En_Bom_Bowl_Man/z_en_bom_bowl_man.c | 49 +- .../ovl_En_Bom_Bowl_Pit/z_en_bom_bowl_pit.c | 20 +- soh/src/overlays/actors/ovl_En_Box/z_en_box.c | 66 +- .../ovl_En_Diving_Game/z_en_diving_game.c | 4 +- soh/src/overlays/actors/ovl_En_Dns/z_en_dns.c | 10 +- .../actors/ovl_En_Dnt_Demo/z_en_dnt_demo.c | 18 + .../actors/ovl_En_Dnt_Nomal/z_en_dnt_nomal.c | 12 +- .../overlays/actors/ovl_En_Door/z_en_door.c | 7 + soh/src/overlays/actors/ovl_En_Du/z_en_du.c | 25 +- .../actors/ovl_En_Ex_Item/z_en_ex_item.c | 99 +- soh/src/overlays/actors/ovl_En_Fr/z_en_fr.c | 12 +- soh/src/overlays/actors/ovl_En_Fu/z_en_fu.c | 35 +- soh/src/overlays/actors/ovl_En_Gb/z_en_gb.c | 4 +- soh/src/overlays/actors/ovl_En_Ge1/z_en_ge1.c | 80 +- soh/src/overlays/actors/ovl_En_Ge2/z_en_ge2.c | 12 +- soh/src/overlays/actors/ovl_En_Ge3/z_en_ge3.c | 4 +- .../overlays/actors/ovl_En_GirlA/z_en_girla.c | 2 +- soh/src/overlays/actors/ovl_En_Go/z_en_go.c | 5 +- soh/src/overlays/actors/ovl_En_Go2/z_en_go2.c | 93 +- soh/src/overlays/actors/ovl_En_Gs/z_en_gs.c | 11 +- .../actors/ovl_En_Heishi1/z_en_heishi1.c | 4 +- soh/src/overlays/actors/ovl_En_Hy/z_en_hy.c | 31 +- soh/src/overlays/actors/ovl_En_Ik/z_en_ik.c | 26 +- soh/src/overlays/actors/ovl_En_Ko/z_en_ko.c | 16 +- soh/src/overlays/actors/ovl_En_Kz/z_en_kz.c | 65 +- soh/src/overlays/actors/ovl_En_Ma1/z_en_ma1.c | 46 +- soh/src/overlays/actors/ovl_En_Md/z_en_md.c | 11 +- soh/src/overlays/actors/ovl_En_Mk/z_en_mk.c | 5 +- soh/src/overlays/actors/ovl_En_Nb/z_en_nb.c | 2 +- .../actors/ovl_En_Niw_Lady/z_en_niw_lady.c | 26 +- .../ovl_En_Okarina_Tag/z_en_okarina_tag.c | 58 +- .../overlays/actors/ovl_En_Ossan/z_en_ossan.c | 9 +- soh/src/overlays/actors/ovl_En_Owl/z_en_owl.c | 18 +- .../actors/ovl_En_Po_Relay/z_en_po_relay.c | 35 +- .../ovl_En_Po_Sisters/z_en_po_sisters.c | 11 + .../ovl_En_River_Sound/z_en_river_sound.c | 4 +- soh/src/overlays/actors/ovl_En_Sa/z_en_sa.c | 20 + soh/src/overlays/actors/ovl_En_Skj/z_en_skj.c | 23 +- soh/src/overlays/actors/ovl_En_Sth/z_en_sth.c | 48 +- .../ovl_En_Syateki_Man/z_en_syateki_man.c | 10 +- soh/src/overlays/actors/ovl_En_Ta/z_en_ta.c | 2 +- soh/src/overlays/actors/ovl_En_Tk/z_en_tk.c | 74 +- soh/src/overlays/actors/ovl_En_Tk/z_en_tk.h | 1 + .../ovl_En_Wonder_Talk/z_en_wonder_talk.c | 5 +- .../ovl_En_Wonder_Talk2/z_en_wonder_talk2.c | 34 +- soh/src/overlays/actors/ovl_En_Xc/z_en_xc.c | 95 +- soh/src/overlays/actors/ovl_En_Zl4/z_en_zl4.c | 31 + .../overlays/actors/ovl_Fishing/z_fishing.c | 104 +- .../actors/ovl_Item_B_Heart/z_item_b_heart.c | 34 +- .../ovl_Item_Etcetera/z_item_etcetera.c | 60 +- .../actors/ovl_Item_Ocarina/z_item_ocarina.c | 28 +- .../overlays/actors/ovl_Shot_Sun/z_shot_sun.c | 3 +- .../actors/ovl_player_actor/z_player.c | 98 +- .../ovl_file_choose/z_file_choose.c | 291 +- .../ovl_file_choose/z_file_copy_erase.c | 2 +- .../ovl_file_choose/z_file_nameset_PAL.c | 3 + .../ovl_kaleido_scope/z_kaleido_equipment.c | 4 +- .../misc/ovl_kaleido_scope/z_kaleido_item.c | 6 +- .../ovl_kaleido_scope/z_kaleido_scope_PAL.c | 14 +- 206 files changed, 53442 insertions(+), 525 deletions(-) create mode 100644 soh/randomizerTypes.h create mode 100644 soh/randomizer_generation.cpp create mode 100644 soh/soh/Enhancements/gfx.c create mode 100644 soh/soh/Enhancements/gfx.h create mode 100644 soh/soh/Enhancements/randomizer/3drando/category.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/cosmetics.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/cosmetics.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/custom_messages.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/custom_messages.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/debug.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/debug.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/dungeon.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/dungeon.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/entrance.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/entrance.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/fill.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/fill.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/hint_list.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/hint_list.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_exclude_dungeon.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_exclude_overworld.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/hints.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/hints.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/item.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/item.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/item_list.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/item_list.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/item_location.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/item_location.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/item_pool.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/item_pool.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/keys.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_bottom_of_the_well.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_castle_town.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_death_mountain.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_deku_tree.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_dodongos_cavern.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_fire_temple.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_forest_temple.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_ganons_castle.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_gerudo_training_grounds.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_gerudo_valley.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_hyrule_field.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_ice_cavern.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_jabujabus_belly.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_kakariko.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_lost_woods.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_shadow_temple.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_spirit_temple.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_water_temple.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_zoras_domain.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/logic.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/logic.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/menu.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/menu.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/music.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/music.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/patch.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/patch.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/playthrough.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/playthrough.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/pool_functions.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/preset.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/preset.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/rando_main.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/rando_main.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/random.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/random.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/randomizer.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/setting_descriptions.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/setting_descriptions.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/settings.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/settings.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/shops.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/shops.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/sound_effects.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/sound_effects.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/spoiler_log.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/starting_inventory.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/starting_inventory.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/text.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/tinyxml2.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/tinyxml2.h create mode 100644 soh/soh/Enhancements/randomizer/3drando/trial.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/trial.hpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/utils.cpp create mode 100644 soh/soh/Enhancements/randomizer/3drando/utils.hpp create mode 100644 soh/soh/Enhancements/randomizer/randomizer.cpp create mode 100644 soh/soh/Enhancements/randomizer/randomizer.h create mode 100644 soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp create mode 100644 soh/soh/Enhancements/randomizer/randomizer_item_tracker.h diff --git a/README.md b/README.md index 87cf1c639..5f07f45e3 100644 --- a/README.md +++ b/README.md @@ -128,5 +128,3 @@ Nightly builds of Ship of Harkinian are available [here](https://builds.shipofha MicTheMicrophone | Gwonam / The King Amphibibro | Link AceHeart | Zelda - -###### Lemons diff --git a/libultraship/libultraship/Cvar.cpp b/libultraship/libultraship/Cvar.cpp index 891ee73af..55fc70793 100644 --- a/libultraship/libultraship/Cvar.cpp +++ b/libultraship/libultraship/Cvar.cpp @@ -64,7 +64,7 @@ void CVar_SetFloat(const char* name, float value) { cvar->value.valueFloat = value; } -void CVar_SetString(const char* name, const char* value) { +extern "C" void CVar_SetString(const char* name, const char* value) { auto& cvar = cvars[name]; if (!cvar) { cvar = std::make_unique(); diff --git a/libultraship/libultraship/Cvar.h b/libultraship/libultraship/Cvar.h index e16f4469f..f9583ef0c 100644 --- a/libultraship/libultraship/Cvar.h +++ b/libultraship/libultraship/Cvar.h @@ -27,6 +27,7 @@ s32 CVar_GetS32(const char* name, s32 defaultValue); float CVar_GetFloat(const char* name, float defaultValue); const char* CVar_GetString(const char* name, const char* defaultValue); void CVar_SetS32(const char* name, s32 value); +void CVar_SetString(const char* name, const char* value); void CVar_RegisterS32(const char* name, s32 defaultValue); void CVar_RegisterFloat(const char* name, float defaultValue); @@ -44,6 +45,5 @@ void CVar_RegisterString(const char* name, const char* defaultValue); extern std::map, std::less<>> cvars; void CVar_SetFloat(const char* name, float value); -void CVar_SetString(const char* name, const char* value); #endif #endif diff --git a/libultraship/libultraship/GameSettings.cpp b/libultraship/libultraship/GameSettings.cpp index 7b22c7bf4..0cfbbd21a 100644 --- a/libultraship/libultraship/GameSettings.cpp +++ b/libultraship/libultraship/GameSettings.cpp @@ -56,7 +56,7 @@ namespace Game { void InitSettings() { ModInternal::RegisterHook(UpdateAudio); ModInternal::RegisterHook([] { - gfx_get_current_rendering_api()->set_texture_filter((FilteringMode) CVar_GetS32("gTextureFilter", THREE_POINT)); + gfx_get_current_rendering_api()->set_texture_filter((FilteringMode) CVar_GetS32("gTextureFilter", FILTER_THREE_POINT)); SohImGui::console->opened = CVar_GetS32("gConsoleEnabled", 0); UpdateAudio(); }); diff --git a/libultraship/libultraship/ImGuiImpl.cpp b/libultraship/libultraship/ImGuiImpl.cpp index fd4e298b3..20ae3f2e1 100644 --- a/libultraship/libultraship/ImGuiImpl.cpp +++ b/libultraship/libultraship/ImGuiImpl.cpp @@ -276,12 +276,12 @@ namespace SohImGui { u8 b = (current_hue / 60.0f + (1 - i)) * 255; switch (i) { - case 1: NewColor.x = 255; NewColor.y = b; NewColor.z = 0; break; - case 2: NewColor.x = a; NewColor.y = 255; NewColor.z = 0; break; - case 3: NewColor.x = 0; NewColor.y = 255; NewColor.z = b; break; - case 4: NewColor.x = 0; NewColor.y = a; NewColor.z = 255; break; - case 5: NewColor.x = b; NewColor.y = 0; NewColor.z = 255; break; - case 6: NewColor.x = 255; NewColor.y = 0; NewColor.z = a; break; + case 1: NewColor.x = 255; NewColor.y = b; NewColor.z = 0; break; + case 2: NewColor.x = a; NewColor.y = 255; NewColor.z = 0; break; + case 3: NewColor.x = 0; NewColor.y = 255; NewColor.z = b; break; + case 4: NewColor.x = 0; NewColor.y = a; NewColor.z = 255; break; + case 5: NewColor.x = b; NewColor.y = 0; NewColor.z = 255; break; + case 6: NewColor.x = 255; NewColor.y = 0; NewColor.z = a; break; } if (CVar_GetS32(Cvar_RBM.c_str(), 0) != 0) { @@ -389,7 +389,7 @@ namespace SohImGui { LoadTexture("C-Right", "assets/ship_of_harkinian/buttons/CRight.png"); LoadTexture("C-Up", "assets/ship_of_harkinian/buttons/CUp.png"); LoadTexture("C-Down", "assets/ship_of_harkinian/buttons/CDown.png"); - }); + }); for (const auto& [i, controllers] : Ship::Window::Controllers) { @@ -400,8 +400,14 @@ namespace SohImGui { ModInternal::RegisterHook([](OSContPad* cont_pad) { pads = cont_pad; - }); + }); Game::InitSettings(); + + CVar_SetS32("gRandoGenerating", 0); + CVar_SetS32("gNewSeedGenerated", 0); + CVar_SetS32("gNewFileDropped", 0); + CVar_SetString("gDroppedFile", ""); + Game::SaveSettings(); } void Update(EventImpl event) { @@ -492,9 +498,9 @@ namespace SohImGui { } } - void EnhancementSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format) + void EnhancementSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format, int defaultValue) { - int val = CVar_GetS32(cvarName, 0); + int val = CVar_GetS32(cvarName, defaultValue); ImGui::Text(text, val); @@ -662,8 +668,7 @@ namespace SohImGui { CVar_SetS32(Cvar_Blue.c_str(), ClampFloatToInt(ColorRGBA.z * 255, 0, 255)); needs_save = true; } - } - else { + } else { if (ImGui::ColorEdit4(text, (float*)&ColorRGBA, flags)) { CVar_SetS32(Cvar_Red.c_str(), ClampFloatToInt(ColorRGBA.x * 255, 0, 255)); CVar_SetS32(Cvar_Green.c_str(), ClampFloatToInt(ColorRGBA.y * 255, 0, 255)); @@ -800,14 +805,13 @@ namespace SohImGui { ImGui::Separator(); - // TODO mutual exclusions -- gDpadEquips and gDpadPauseName cause conflicts, but nothing stops a user from selecting both - // There should be some system to prevent conclifting enhancements from being selected + // TODO mutual exclusions -- There should be some system to prevent conclifting enhancements from being selected EnhancementCheckbox("D-pad Support on Pause and File Select", "gDpadPauseName"); + Tooltip("Enables Pause and File Select screen navigation with the D-pad\nIf used with D-pad as Equip Items, you must hold C-Up\nto equip instead of navigate"); EnhancementCheckbox("D-pad Support in Ocarina and Text Choice", "gDpadOcarinaText"); EnhancementCheckbox("D-pad Support for Browsing Shop Items", "gDpadShop"); EnhancementCheckbox("D-pad as Equip Items", "gDpadEquips"); - Tooltip("Allows the D-pad to be used as extra C buttons\nNote: Incompatible with D-pad on pause and file select"); - + Tooltip("Allows the D-pad to be used as extra C buttons"); ImGui::Separator(); EnhancementCheckbox("Show Inputs", "gInputEnabled"); @@ -931,7 +935,9 @@ namespace SohImGui { Tooltip("Skip first-time pickup messages for consumable items"); EnhancementCheckbox("Better Owl", "gBetterOwl"); Tooltip("The default response to Kaepora Gaebora is\nalways that you understood what he said"); - + EnhancementCheckbox("Fast Ocarina Playback", "gFastOcarinaPlayback"); + Tooltip("Skip the part where the Ocarina playback is called when you play\na song"); + ImGui::EndMenu(); } @@ -1007,7 +1013,19 @@ namespace SohImGui { ImGui::EndMenu(); } - + + if (ImGui::BeginMenu("Fishing")) { + EnhancementCheckbox("Instant Fishing", "gInstantFishing"); + Tooltip("All fish will be caught instantly"); + EnhancementCheckbox("Guarantee Bite", "gGuaranteeFishingBite"); + Tooltip("When a line is stable, guarantee bite. Otherwise use default logic"); + EnhancementSliderInt("Child Minimum Weight: %d", "##cMinimumWeight", "gChildMinimumWeightFish", 6, 10, "", 10); + Tooltip("The minimum weight for the unique fishing reward as a child"); + EnhancementSliderInt("Adult Minimum Weight: %d", "##aMinimumWeight", "gAdultMinimumWeightFish", 8, 13, "", 13); + Tooltip("The minimum weight for the unique fishing reward as an adult"); + ImGui::EndMenu(); + } + ImGui::EndMenu(); } @@ -1033,6 +1051,8 @@ namespace SohImGui { EnhancementCheckbox("Enable passage of time on file select", "gTimeFlowFileSelect"); EnhancementCheckbox("Allow the cursor to be on any slot", "gPauseAnyCursor"); Tooltip("Allows the cursor on the pause menu to be over any slot\nSimilar to Rando and Spaceworld 97"); + EnhancementCheckbox("Count Golden Skulltulas", "gInjectSkulltulaCount"); + Tooltip("Injects Golden Skulltula total count in pickup messages"); EnhancementCheckbox("Pull grave during the day", "gDayGravePull"); Tooltip("Allows graves to be pulled when child during the day"); ImGui::EndMenu(); diff --git a/libultraship/libultraship/ImGuiImpl.h b/libultraship/libultraship/ImGuiImpl.h index 00f494180..11d38a7b8 100644 --- a/libultraship/libultraship/ImGuiImpl.h +++ b/libultraship/libultraship/ImGuiImpl.h @@ -68,7 +68,7 @@ namespace SohImGui { void EnhancementRadioButton(const char* text, const char* cvarName, int id); void EnhancementCheckbox(const char* text, const char* cvarName); void EnhancementButton(const char* text, const char* cvarName); - void EnhancementSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format); + void EnhancementSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format, int defaultValue = 0); void EnhancementSliderFloat(const char* text, const char* id, const char* cvarName, float min, float max, const char* format, float defaultValue, bool isPercentage); void EnhancementCombobox(const char* name, const char* ComboArray[], size_t arraySize, uint8_t FirstTimeValue); void EnhancementColor(const char* text, const char* cvarName, ImVec4 ColorRGBA, ImVec4 default_colors, bool allow_rainbow = true, bool has_alpha=false, bool TitleSameLine=false); diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_direct3d11.cpp b/libultraship/libultraship/Lib/Fast3D/gfx_direct3d11.cpp index b8ee8291d..5d71e6ac5 100644 --- a/libultraship/libultraship/Lib/Fast3D/gfx_direct3d11.cpp +++ b/libultraship/libultraship/Lib/Fast3D/gfx_direct3d11.cpp @@ -137,7 +137,7 @@ static struct { //uint32_t current_width, current_height; uint32_t render_target_height; int current_framebuffer; - FilteringMode current_filter_mode = NONE; + FilteringMode current_filter_mode = FILTER_NONE; int8_t depth_test; int8_t depth_mask; @@ -413,7 +413,7 @@ static struct ShaderProgram *gfx_d3d11_create_and_load_new_shader(uint64_t shade char buf[4096]; size_t len, num_floats; - gfx_direct3d_common_build_shader(buf, len, num_floats, cc_features, false, d3d.current_filter_mode == THREE_POINT); + gfx_direct3d_common_build_shader(buf, len, num_floats, cc_features, false, d3d.current_filter_mode == FILTER_THREE_POINT); ComPtr vs, ps; ComPtr error_blob; @@ -580,7 +580,7 @@ static void gfx_d3d11_set_sampler_parameters(int tile, bool linear_filter, uint3 D3D11_SAMPLER_DESC sampler_desc; ZeroMemory(&sampler_desc, sizeof(D3D11_SAMPLER_DESC)); - sampler_desc.Filter = linear_filter && d3d.current_filter_mode == LINEAR ? D3D11_FILTER_MIN_MAG_MIP_LINEAR : D3D11_FILTER_MIN_MAG_MIP_POINT; + sampler_desc.Filter = linear_filter && d3d.current_filter_mode == FILTER_LINEAR ? D3D11_FILTER_MIN_MAG_MIP_LINEAR : D3D11_FILTER_MIN_MAG_MIP_POINT; sampler_desc.AddressU = gfx_cm_to_d3d11(cms); sampler_desc.AddressV = gfx_cm_to_d3d11(cmt); @@ -685,7 +685,7 @@ static void gfx_d3d11_draw_triangles(float buf_vbo[], size_t buf_vbo_len, size_t d3d.last_resource_views[i] = d3d.textures[d3d.current_texture_ids[i]].resource_view.Get(); d3d.context->PSSetShaderResources(i, 1, d3d.textures[d3d.current_texture_ids[i]].resource_view.GetAddressOf()); - if (d3d.current_filter_mode == THREE_POINT) { + if (d3d.current_filter_mode == FILTER_THREE_POINT) { d3d.per_draw_cb_data.textures[i].width = d3d.textures[d3d.current_texture_ids[i]].width; d3d.per_draw_cb_data.textures[i].height = d3d.textures[d3d.current_texture_ids[i]].height; d3d.per_draw_cb_data.textures[i].linear_filtering = d3d.textures[d3d.current_texture_ids[i]].linear_filtering; diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_dxgi.cpp b/libultraship/libultraship/Lib/Fast3D/gfx_dxgi.cpp index f2a401f6b..06ff5f60a 100644 --- a/libultraship/libultraship/Lib/Fast3D/gfx_dxgi.cpp +++ b/libultraship/libultraship/Lib/Fast3D/gfx_dxgi.cpp @@ -27,9 +27,11 @@ #include "gfx_screen_config.h" #include "gfx_pc.h" #include "../../ImGuiImpl.h" +#include "../../Cvar.h" #define DECLARE_GFX_DXGI_FUNCTIONS #include "gfx_dxgi.h" +#include "../../GameSettings.h" #define WINCLASS_NAME L"N64GAME" #define GFX_API_NAME "DirectX" @@ -85,8 +87,8 @@ static struct { static void load_dxgi_library(void) { dxgi.dxgi_module = LoadLibraryW(L"dxgi.dll"); - *(FARPROC *)&dxgi.CreateDXGIFactory1 = GetProcAddress(dxgi.dxgi_module, "CreateDXGIFactory1"); - *(FARPROC *)&dxgi.CreateDXGIFactory2 = GetProcAddress(dxgi.dxgi_module, "CreateDXGIFactory2"); + *(FARPROC*)&dxgi.CreateDXGIFactory1 = GetProcAddress(dxgi.dxgi_module, "CreateDXGIFactory1"); + *(FARPROC*)&dxgi.CreateDXGIFactory2 = GetProcAddress(dxgi.dxgi_module, "CreateDXGIFactory2"); } template @@ -110,8 +112,8 @@ static void run_as_dpi_aware(Fun f) { #define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((DPI_AWARENESS_CONTEXT)-4) #define DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED ((DPI_AWARENESS_CONTEXT)-5) - DPI_AWARENESS_CONTEXT (WINAPI *SetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT dpiContext); - *(FARPROC *)&SetThreadDpiAwarenessContext = GetProcAddress(GetModuleHandleW(L"user32.dll"), "SetThreadDpiAwarenessContext"); + DPI_AWARENESS_CONTEXT(WINAPI * SetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT dpiContext); + *(FARPROC*)&SetThreadDpiAwarenessContext = GetProcAddress(GetModuleHandleW(L"user32.dll"), "SetThreadDpiAwarenessContext"); DPI_AWARENESS_CONTEXT old_awareness_context = nullptr; if (SetThreadDpiAwarenessContext != nullptr) { old_awareness_context = SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); @@ -121,8 +123,8 @@ static void run_as_dpi_aware(Fun f) { if (!dxgi.process_dpi_awareness_done) { HMODULE shcore_module = LoadLibraryW(L"SHCore.dll"); if (shcore_module != nullptr) { - HRESULT (WINAPI *SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS value); - *(FARPROC *)&SetProcessDpiAwareness = GetProcAddress(shcore_module, "SetProcessDpiAwareness"); + HRESULT(WINAPI * SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS value); + *(FARPROC*)&SetProcessDpiAwareness = GetProcAddress(shcore_module, "SetProcessDpiAwareness"); if (SetProcessDpiAwareness != nullptr) { SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); // Ignore result, will fail if already called or manifest already specifies dpi awareness. @@ -226,6 +228,8 @@ static void onkeyup(WPARAM w_param, LPARAM l_param) { } } +char fileName[256]; + static LRESULT CALLBACK gfx_dxgi_wnd_proc(HWND h_wnd, UINT message, WPARAM w_param, LPARAM l_param) { SohImGui::EventImpl event_impl; event_impl.win32 = { h_wnd, static_cast(message), static_cast(w_param), static_cast(l_param) }; @@ -265,6 +269,12 @@ static LRESULT CALLBACK gfx_dxgi_wnd_proc(HWND h_wnd, UINT message, WPARAM w_par case WM_KEYUP: onkeyup(w_param, l_param); break; + case WM_DROPFILES: + DragQueryFileA((HDROP)w_param, 0, fileName, 256); + CVar_SetString("gDroppedFile", fileName); + CVar_SetS32("gNewFileDropped", 1); + Game::SaveSettings(); + break; case WM_SYSKEYDOWN: if ((w_param == VK_RETURN) && ((l_param & 1 << 30) == 0)) { toggle_borderless_window_full_screen(!dxgi.is_full_screen, true); @@ -334,6 +344,8 @@ void gfx_dxgi_init(const char *game_name, bool start_in_fullscreen, uint32_t wid if (start_in_fullscreen) { toggle_borderless_window_full_screen(true, false); } + + DragAcceptFiles(dxgi.h_wnd, TRUE); } static void gfx_dxgi_set_fullscreen_changed_callback(void (*on_fullscreen_changed)(bool is_now_fullscreen)) { diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_opengl.cpp b/libultraship/libultraship/Lib/Fast3D/gfx_opengl.cpp index 45118b2b3..d79c3aa8f 100644 --- a/libultraship/libultraship/Lib/Fast3D/gfx_opengl.cpp +++ b/libultraship/libultraship/Lib/Fast3D/gfx_opengl.cpp @@ -81,7 +81,7 @@ static uint32_t frame_count; static vector framebuffers; static size_t current_framebuffer; static float current_noise_scale; -static FilteringMode current_filter_mode = THREE_POINT; +static FilteringMode current_filter_mode = FILTER_THREE_POINT; GLuint pixel_depth_rb, pixel_depth_fb; size_t pixel_depth_rb_size; @@ -376,7 +376,7 @@ static struct ShaderProgram* gfx_opengl_create_and_load_new_shader(uint64_t shad append_line(fs_buf, &fs_len, "}"); } - if (current_filter_mode == THREE_POINT) { + if (current_filter_mode == FILTER_THREE_POINT) { #if __APPLE__ append_line(fs_buf, &fs_len, "#define TEX_OFFSET(off) texture(tex, texCoord - (off)/texSize)"); #else @@ -638,6 +638,7 @@ static void gfx_opengl_select_texture(int tile, GLuint texture_id) { glActiveTexture(GL_TEXTURE0 + tile); glBindTexture(GL_TEXTURE_2D, texture_id); } + static void gfx_opengl_upload_texture(const uint8_t *rgba32_buf, uint32_t width, uint32_t height) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba32_buf); } @@ -657,7 +658,7 @@ static uint32_t gfx_cm_to_opengl(uint32_t val) { } static void gfx_opengl_set_sampler_parameters(int tile, bool linear_filter, uint32_t cms, uint32_t cmt) { - const GLint filter = linear_filter && current_filter_mode == LINEAR ? GL_LINEAR : GL_NEAREST; + const GLint filter = linear_filter && current_filter_mode == FILTER_LINEAR ? GL_LINEAR : GL_NEAREST; glActiveTexture(GL_TEXTURE0 + tile); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_rendering_api.h b/libultraship/libultraship/Lib/Fast3D/gfx_rendering_api.h index 02bb5afbc..772aa9904 100644 --- a/libultraship/libultraship/Lib/Fast3D/gfx_rendering_api.h +++ b/libultraship/libultraship/Lib/Fast3D/gfx_rendering_api.h @@ -17,9 +17,9 @@ struct GfxClipParameters { }; enum FilteringMode { - THREE_POINT, - LINEAR, - NONE + FILTER_THREE_POINT, + FILTER_LINEAR, + FILTER_NONE }; // A hash function used to hash a: pair diff --git a/libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp b/libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp index 07b3d8061..44ad9ec37 100644 --- a/libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp +++ b/libultraship/libultraship/Lib/Fast3D/gfx_sdl2.cpp @@ -22,6 +22,7 @@ #endif #include "../../ImGuiImpl.h" +#include "../../Cvar.h" #include "gfx_window_manager_api.h" #include "gfx_screen_config.h" @@ -29,6 +30,7 @@ #include #endif #include +#include "../../GameSettings.h" #define GFX_API_NAME "SDL2 - OpenGL" @@ -106,7 +108,7 @@ static void set_fullscreen(bool on, bool call_callback) { SDL_GetDesktopDisplayMode(0, &mode); window_width = mode.w; window_height = mode.h; - SDL_ShowCursor(false); + //SDL_ShowCursor(false); } else { window_width = DESIRED_SCREEN_WIDTH; window_height = DESIRED_SCREEN_HEIGHT; @@ -133,6 +135,8 @@ static int target_fps = 60; static void gfx_sdl_init(const char *game_name, bool start_in_fullscreen, uint32_t width, uint32_t height) { SDL_Init(SDL_INIT_VIDEO); + SDL_EventState(SDL_DROPFILE, SDL_ENABLE); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); @@ -260,6 +264,11 @@ static void gfx_sdl_handle_events(void) { SDL_GL_GetDrawableSize(wnd, &window_width, &window_height); } break; + case SDL_DROPFILE: + CVar_SetString("gDroppedFile", event.drop.file); + CVar_SetS32("gNewFileDropped", 1); + Game::SaveSettings(); + break; case SDL_QUIT: SDL_Quit(); // bandaid fix for linux window closing issue exit(0); diff --git a/libultraship/libultraship/PulseAudioPlayer.cpp b/libultraship/libultraship/PulseAudioPlayer.cpp index 21603c2b9..d33e62ea1 100644 --- a/libultraship/libultraship/PulseAudioPlayer.cpp +++ b/libultraship/libultraship/PulseAudioPlayer.cpp @@ -182,4 +182,4 @@ namespace Ship } } -#endif \ No newline at end of file +#endif diff --git a/soh/include/functions.h b/soh/include/functions.h index 3dcf5f936..73f366bb5 100644 --- a/soh/include/functions.h +++ b/soh/include/functions.h @@ -448,6 +448,7 @@ u32 Actor_TextboxIsClosing(Actor* actor, GlobalContext* globalCtx); s8 func_8002F368(GlobalContext* globalCtx); void Actor_GetScreenPos(GlobalContext* globalCtx, Actor* actor, s16* x, s16* y); u32 Actor_HasParent(Actor* actor, GlobalContext* globalCtx); +s32 GiveItemWithoutActor(GlobalContext* globalCtx, s32 getItemId); s32 func_8002F434(Actor* actor, GlobalContext* globalCtx, s32 getItemId, f32 xzRange, f32 yRange); void func_8002F554(Actor* actor, GlobalContext* globalCtx, s32 getItemId); void func_8002F580(Actor* actor, GlobalContext* globalCtx); diff --git a/soh/include/z64.h b/soh/include/z64.h index 5057def3d..2d8a6f4a8 100644 --- a/soh/include/z64.h +++ b/soh/include/z64.h @@ -1293,6 +1293,7 @@ typedef struct { /* 0x1C9EC */ Vtx* keyboardVtx; /* 0x1C9F0 */ Vtx* nameEntryVtx; /* 0x1C9F4 */ u8 n64ddFlag; + /* 0x1CA28 */ s16 n64ddFlags[3]; /* 0x1CA38 */ s16 buttonIndex; /* 0x1CA3A */ s16 confirmButtonIndex; // 0: yes, 1: quit /* 0x1CA3C */ s16 menuMode; diff --git a/soh/include/z64actor.h b/soh/include/z64actor.h index d13069029..6ecb10c49 100644 --- a/soh/include/z64actor.h +++ b/soh/include/z64actor.h @@ -289,6 +289,7 @@ typedef struct EnItem00 { /* 0x15A */ s16 unk_15A; /* 0x15C */ f32 scale; /* 0x160 */ ColliderCylinder collider; + s16 ogParams; } EnItem00; // size = 0x1AC // Only A_OBJ_SIGNPOST_OBLONG and A_OBJ_SIGNPOST_ARROW are used in room files. diff --git a/soh/include/z64item.h b/soh/include/z64item.h index b42a2efc9..9e78487db 100644 --- a/soh/include/z64item.h +++ b/soh/include/z64item.h @@ -211,9 +211,9 @@ typedef enum { /* 0x78 */ ITEM_MAGIC_SMALL, /* 0x79 */ ITEM_MAGIC_LARGE, /* 0x7A */ ITEM_HEART_PIECE_2, - /* 0x7B */ ITEM_INVALID_1, - /* 0x7C */ ITEM_INVALID_2, - /* 0x7D */ ITEM_INVALID_3, + /* 0x7B */ ITEM_SINGLE_MAGIC, + /* 0x7C */ ITEM_DOUBLE_MAGIC, + /* 0x7D */ ITEM_DOUBLE_DEFENSE, /* 0x7E */ ITEM_INVALID_4, /* 0x7F */ ITEM_INVALID_5, /* 0x80 */ ITEM_INVALID_6, @@ -244,6 +244,15 @@ typedef enum { /* 0x99 */ ITEM_STICK_UPGRADE_30, /* 0x9A */ ITEM_NUT_UPGRADE_30, /* 0x9B */ ITEM_NUT_UPGRADE_40, + /* 0x9C */ ITEM_BOTTLE_WITH_RED_POTION, + /* 0x9D */ ITEM_BOTTLE_WITH_GREEN_POTION, + /* 0x9E */ ITEM_BOTTLE_WITH_BLUE_POTION, + /* 0x9F */ ITEM_BOTTLE_WITH_FAIRY, + /* 0xA0 */ ITEM_BOTTLE_WITH_FISH, + /* 0xA1 */ ITEM_BOTTLE_WITH_BLUE_FIRE, + /* 0xA2 */ ITEM_BOTTLE_WITH_BUGS, + /* 0xA3 */ ITEM_BOTTLE_WITH_POE, + /* 0xA4 */ ITEM_BOTTLE_WITH_BIG_POE, /* 0xFC */ ITEM_LAST_USED = 0xFC, /* 0xFE */ ITEM_NONE_FE = 0xFE, /* 0xFF */ ITEM_NONE = 0xFF @@ -380,7 +389,47 @@ typedef enum { /* 0x7B */ GI_BULLET_BAG_50, /* 0x7C */ GI_ICE_TRAP, // freezes link when opened from a chest /* 0x7D */ GI_TEXT_0, // no model appears over Link, shows text id 0 (pocket egg) - /* 0x7E */ GI_MAX + + /* 0x7E */ GI_MEDALLION_LIGHT, + /* 0x7F */ GI_MEDALLION_FOREST, + /* 0x80 */ GI_MEDALLION_FIRE, + /* 0x81 */ GI_MEDALLION_WATER, + /* 0x82 */ GI_MEDALLION_SHADOW, + /* 0x83 */ GI_MEDALLION_SPIRIT, + + /* 0x81 */ GI_STONE_KOKIRI, + /* 0x82 */ GI_STONE_GORON, + /* 0x83 */ GI_STONE_ZORA, + + /* 0x81 */ GI_ZELDAS_LULLABY, + /* 0x82 */ GI_SUNS_SONG, + /* 0x83 */ GI_EPONAS_SONG, + /* 0x81 */ GI_SONG_OF_STORMS, + /* 0x82 */ GI_SONG_OF_TIME, + /* 0x83 */ GI_SARIAS_SONG, + + /* 0x81 */ GI_MINUET_OF_FOREST, + /* 0x82 */ GI_BOLERO_OF_FIRE, + /* 0x83 */ GI_SERENADE_OF_WATER, + /* 0x81 */ GI_NOCTURNE_OF_SHADOW, + /* 0x82 */ GI_REQUIEM_OF_SPIRIT, + /* 0x83 */ GI_PRELUDE_OF_LIGHT, + + GI_SINGLE_MAGIC, + GI_DOUBLE_MAGIC, + GI_DOUBLE_DEFENSE, + + GI_BOTTLE_WITH_RED_POTION, + GI_BOTTLE_WITH_GREEN_POTION, + GI_BOTTLE_WITH_BLUE_POTION, + GI_BOTTLE_WITH_FAIRY, + GI_BOTTLE_WITH_FISH, + GI_BOTTLE_WITH_BLUE_FIRE, + GI_BOTTLE_WITH_BUGS, + GI_BOTTLE_WITH_POE, + GI_BOTTLE_WITH_BIG_POE, + + /* 0x84 */ GI_MAX } GetItemID; typedef enum { @@ -501,7 +550,18 @@ typedef enum { /* 0x72 */ GID_BULLET_BAG_50, /* 0x73 */ GID_SWORD_KOKIRI, /* 0x74 */ GID_SKULL_TOKEN_2, - /* 0x75 */ GID_MAXIMUM + /* 0x74 */ GID_KOKIRI_EMERALD, + /* 0x74 */ GID_GORON_RUBY, + /* 0x74 */ GID_ZORA_SAPPHIRE, + /* 0x75 */ GID_SONG_GENERIC, + /* 0x76 */ GID_SONG_ZELDA, + /* 0x77 */ GID_SONG_EPONA, + /* 0x78 */ GID_SONG_SARIA, + /* 0x79 */ GID_SONG_SUN, + /* 0x7A */ GID_SONG_TIME, + /* 0x7B */ GID_SONG_STORM, + /* 0x7C */ GID_MAXIMUM + } GetItemDrawID; typedef enum { diff --git a/soh/include/z64player.h b/soh/include/z64player.h index 9bce60ffe..954c36c14 100644 --- a/soh/include/z64player.h +++ b/soh/include/z64player.h @@ -481,7 +481,7 @@ typedef struct Player { /* 0x042D */ s8 doorDirection; /* 0x042E */ s16 doorTimer; /* 0x0430 */ Actor* doorActor; - /* 0x0434 */ s8 getItemId; + /* 0x0434 */ s16 getItemId; /* 0x0436 */ u16 getItemDirection; /* 0x0438 */ Actor* interactRangeActor; /* 0x043C */ s8 mountSide; @@ -614,4 +614,4 @@ typedef struct Player { /* 0x0A88 */ Vec3f unk_A88; // previous body part 0 position } Player; // size = 0xA94 -#endif \ No newline at end of file +#endif diff --git a/soh/include/z64save.h b/soh/include/z64save.h index daf316e0a..86e962799 100644 --- a/soh/include/z64save.h +++ b/soh/include/z64save.h @@ -3,6 +3,7 @@ #include "ultra64.h" #include "z64math.h" +#include typedef struct { /* 0x00 */ u8 buttonItems[8]; @@ -60,6 +61,21 @@ typedef struct { /* 0x24 */ s32 tempCollectFlags; } FaroresWindData; // size = 0x28 +typedef struct { + RandomizerCheck check; + RandomizerGet get; +} ItemLocationRando; + +typedef struct { + RandomizerCheck check; + char hintText[200]; +} HintLocationRando; + +typedef struct { + RandomizerSettingKey key; + u8 value; +} RandoSetting; + typedef struct { /* 0x0000 */ s32 entranceIndex; // start of `save` substruct, originally called "memory" /* 0x0004 */ s32 linkAge; // 0: Adult; 1: Child @@ -157,6 +173,17 @@ typedef struct { /* 0x1420 */ s16 worldMapArea; /* 0x1422 */ s16 sunsSongState; // controls the effects of suns song /* 0x1424 */ s16 healthAccumulator; + RandoSetting randoSettings[300]; + ItemLocationRando itemLocations[500]; + HintLocationRando hintLocations[50]; + char childAltarText[250]; + char adultAltarText[750]; + char ganonHintText[150]; + char ganonText[250]; + u8 seedIcons[5]; + u8 dungeonsDone[8]; + u8 trialsDone[6]; + u8 temporaryWeapon; } SaveContext; // size = 0x1428 typedef enum { diff --git a/soh/randomizerTypes.h b/soh/randomizerTypes.h new file mode 100644 index 000000000..551966828 --- /dev/null +++ b/soh/randomizerTypes.h @@ -0,0 +1,1000 @@ +#pragma once + +typedef struct { + char tex[512]; + uint16_t width; + uint16_t height; + uint8_t im_fmt; + uint8_t im_siz; + uint8_t id; +} Sprite; + +typedef enum { + RC_LINKS_POCKET, + RC_QUEEN_GOHMA, + RC_KING_DODONGO, + RC_BARINADE, + RC_PHANTOM_GANON, + RC_VOLVAGIA, + RC_MORPHA, + RC_BONGO_BONGO, + RC_TWINROVA, + RC_GANON, + RC_GIFT_FROM_SAGES, + RC_SONG_FROM_IMPA, + RC_SONG_FROM_MALON, + RC_SONG_FROM_SARIA, + RC_SONG_FROM_ROYAL_FAMILYS_TOMB, + RC_SONG_FROM_OCARINA_OF_TIME, + RC_SONG_FROM_WINDMILL, + RC_SHEIK_IN_FOREST, + RC_SHEIK_IN_CRATER, + RC_SHEIK_IN_ICE_CAVERN, + RC_SHEIK_AT_COLOSSUS, + RC_SHEIK_IN_KAKARIKO, + RC_SHEIK_AT_TEMPLE, + RC_KF_MIDOS_TOP_LEFT_CHEST, + RC_KF_MIDOS_TOP_RIGHT_CHEST, + RC_KF_MIDOS_BOTTOM_LEFT_CHEST, + RC_KF_MIDOS_BOTTOM_RIGHT_CHEST, + RC_KF_KOKIRI_SWORD_CHEST, + RC_KF_STORMS_GROTTO_CHEST, + RC_KF_LINKS_HOUSE_COW, + RC_KF_GS_KNOW_IT_ALL_HOUSE, + RC_KF_GS_BEAN_PATCH, + RC_KF_GS_HOUSE_OF_TWINS, + RC_KF_SHOP_ITEM_1, + RC_KF_SHOP_ITEM_2, + RC_KF_SHOP_ITEM_3, + RC_KF_SHOP_ITEM_4, + RC_KF_SHOP_ITEM_5, + RC_KF_SHOP_ITEM_6, + RC_KF_SHOP_ITEM_7, + RC_KF_SHOP_ITEM_8, + RC_LW_GIFT_FROM_SARIA, + RC_LW_OCARINA_MEMORY_GAME, + RC_LW_TARGET_IN_WOODS, + RC_LW_NEAR_SHORTCUTS_GROTTO_CHEST, + RC_LW_TRADE_COJIRO, + RC_DEKU_THEATER_SKULL_MASK, + RC_DEKU_THEATER_MASK_OF_TRUTH, + RC_LW_SKULL_KID, + RC_LW_TRADE_ODD_POTION, + RC_LW_DEKU_SCRUB_NEAR_BRIDGE, + RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, + RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT, + RC_LW_DEKU_SCRUB_GROTTO_FRONT, + RC_LW_DEKU_SCRUB_GROTTO_REAR, + RC_LW_GS_BEAN_PATCH_NEAR_BRIDGE, + RC_LW_GS_BEAN_PATCH_NEAR_THEATER, + RC_LW_GS_ABOVE_THEATER, + RC_SFM_WOLFOS_GROTTO_CHEST, + RC_SFM_DEKU_SCRUB_GROTTO_FRONT, + RC_SFM_DEKU_SCRUB_GROTTO_REAR, + RC_SFM_GS, + RC_HF_OCARINA_OF_TIME_ITEM, + RC_HF_NEAR_MARKET_GROTTO_CHEST, + RC_HF_TEKTITE_GROTTO_FREESTANDING_POH, + RC_HF_SOUTHEAST_GROTTO_CHEST, + RC_HF_OPEN_GROTTO_CHEST, + RC_HF_DEKU_SCRUB_GROTTO, + RC_HF_COW_GROTTO_COW, + RC_HF_GS_COW_GROTTO, + RC_HF_GS_NEAR_KAK_GROTTO, + RC_MARKET_SHOOTING_GALLERY_REWARD, + RC_MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, + RC_MARKET_BOMBCHU_BOWLING_SECOND_PRIZE, + RC_MARKET_BOMBCHU_BOWLING_BOMBCHUS, + RC_MARKET_LOST_DOG, + RC_MARKET_TREASURE_CHEST_GAME_REWARD, + RC_MARKET_10_BIG_POES, + RC_MARKET_TREASURE_CHEST_GAME_ITEM_1, + RC_MARKET_TREASURE_CHEST_GAME_ITEM_2, + RC_MARKET_TREASURE_CHEST_GAME_ITEM_3, + RC_MARKET_TREASURE_CHEST_GAME_ITEM_4, + RC_MARKET_TREASURE_CHEST_GAME_ITEM_5, + RC_MARKET_GS_GUARD_HOUSE, + RC_MARKET_BAZAAR_ITEM_1, + RC_MARKET_BAZAAR_ITEM_2, + RC_MARKET_BAZAAR_ITEM_3, + RC_MARKET_BAZAAR_ITEM_4, + RC_MARKET_BAZAAR_ITEM_5, + RC_MARKET_BAZAAR_ITEM_6, + RC_MARKET_BAZAAR_ITEM_7, + RC_MARKET_BAZAAR_ITEM_8, + RC_MARKET_POTION_SHOP_ITEM_1, + RC_MARKET_POTION_SHOP_ITEM_2, + RC_MARKET_POTION_SHOP_ITEM_3, + RC_MARKET_POTION_SHOP_ITEM_4, + RC_MARKET_POTION_SHOP_ITEM_5, + RC_MARKET_POTION_SHOP_ITEM_6, + RC_MARKET_POTION_SHOP_ITEM_7, + RC_MARKET_POTION_SHOP_ITEM_8, + RC_MARKET_BOMBCHU_SHOP_ITEM_1, + RC_MARKET_BOMBCHU_SHOP_ITEM_2, + RC_MARKET_BOMBCHU_SHOP_ITEM_3, + RC_MARKET_BOMBCHU_SHOP_ITEM_4, + RC_MARKET_BOMBCHU_SHOP_ITEM_5, + RC_MARKET_BOMBCHU_SHOP_ITEM_6, + RC_MARKET_BOMBCHU_SHOP_ITEM_7, + RC_MARKET_BOMBCHU_SHOP_ITEM_8, + RC_TOT_LIGHT_ARROWS_CUTSCENE, + RC_HC_MALON_EGG, + RC_HC_ZELDAS_LETTER, + RC_HC_GREAT_FAIRY_REWARD, + RC_HC_GS_TREE, + RC_HC_GS_STORMS_GROTTO, + RC_LLR_TALONS_CHICKENS, + RC_LLR_FREESTANDING_POH, + RC_LLR_DEKU_SCRUB_GROTTO_LEFT, + RC_LLR_DEKU_SCRUB_GROTTO_CENTER, + RC_LLR_DEKU_SCRUB_GROTTO_RIGHT, + RC_LLR_STABLES_LEFT_COW, + RC_LLR_STABLES_RIGHT_COW, + RC_LLR_TOWER_LEFT_COW, + RC_LLR_TOWER_RIGHT_COW, + RC_LLR_GS_HOUSE_WINDOW, + RC_LLR_GS_TREE, + RC_LLR_GS_RAIN_SHED, + RC_LLR_GS_BACK_WALL, + RC_KAK_ANJU_AS_CHILD, + RC_KAK_ANJU_AS_ADULT, + RC_KAK_IMPAS_HOUSE_FREESTANDING_POH, + RC_KAK_WINDMILL_FREESTANDING_POH, + RC_KAK_MAN_ON_ROOF, + RC_KAK_OPEN_GROTTO_CHEST, + RC_KAK_REDEAD_GROTTO_CHEST, + RC_KAK_SHOOTING_GALLERY_REWARD, + RC_KAK_TRADE_ODD_MUSHROOM, + RC_KAK_TRADE_POCKET_CUCCO, + RC_KAK_10_GOLD_SKULLTULA_REWARD, + RC_KAK_20_GOLD_SKULLTULA_REWARD, + RC_KAK_30_GOLD_SKULLTULA_REWARD, + RC_KAK_40_GOLD_SKULLTULA_REWARD, + RC_KAK_50_GOLD_SKULLTULA_REWARD, + RC_KAK_IMPAS_HOUSE_COW, + RC_KAK_GS_TREE, + RC_KAK_GS_GUARDS_HOUSE, + RC_KAK_GS_WATCHTOWER, + RC_KAK_GS_SKULLTULA_HOUSE, + RC_KAK_GS_HOUSE_UNDER_CONSTRUCTION, + RC_KAK_GS_ABOVE_IMPAS_HOUSE, + RC_KAK_BAZAAR_ITEM_1, + RC_KAK_BAZAAR_ITEM_2, + RC_KAK_BAZAAR_ITEM_3, + RC_KAK_BAZAAR_ITEM_4, + RC_KAK_BAZAAR_ITEM_5, + RC_KAK_BAZAAR_ITEM_6, + RC_KAK_BAZAAR_ITEM_7, + RC_KAK_BAZAAR_ITEM_8, + RC_KAK_POTION_SHOP_ITEM_1, + RC_KAK_POTION_SHOP_ITEM_2, + RC_KAK_POTION_SHOP_ITEM_3, + RC_KAK_POTION_SHOP_ITEM_4, + RC_KAK_POTION_SHOP_ITEM_5, + RC_KAK_POTION_SHOP_ITEM_6, + RC_KAK_POTION_SHOP_ITEM_7, + RC_KAK_POTION_SHOP_ITEM_8, + RC_GRAVEYARD_SHIELD_GRAVE_CHEST, + RC_GRAVEYARD_HEART_PIECE_GRAVE_CHEST, + RC_GRAVEYARD_ROYAL_FAMILYS_TOMB_CHEST, + RC_GRAVEYARD_FREESTANDING_POH, + RC_GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR, + RC_GRAVEYARD_HOOKSHOT_CHEST, + RC_GRAVEYARD_DAMPE_RACE_FREESTANDING_POH, + RC_GRAVEYARD_GS_BEAN_PATCH, + RC_GRAVEYARD_GS_WALL, + RC_DMT_FREESTANDING_POH, + RC_DMT_CHEST, + RC_DMT_STORMS_GROTTO_CHEST, + RC_DMT_TRADE_BROKEN_SWORD, + RC_DMT_TRADE_EYEDROPS, + RC_DMT_TRADE_CLAIM_CHECK, + RC_DMT_GREAT_FAIRY_REWARD, + RC_DMT_COW_GROTTO_COW, + RC_DMT_GS_NEAR_KAK, + RC_DMT_GS_BEAN_PATCH, + RC_DMT_GS_ABOVE_DODONGOS_CAVERN, + RC_DMT_GS_FALLING_ROCKS_PATH, + RC_GC_DARUNIAS_JOY, + RC_GC_POT_FREESTANDING_POH, + RC_GC_ROLLING_GORON_AS_CHILD, + RC_GC_ROLLING_GORON_AS_ADULT, + RC_GC_MEDIGORON, + RC_GC_MAZE_LEFT_CHEST, + RC_GC_MAZE_RIGHT_CHEST, + RC_GC_MAZE_CENTER_CHEST, + RC_GC_DEKU_SCRUB_GROTTO_LEFT, + RC_GC_DEKU_SCRUB_GROTTO_CENTER, + RC_GC_DEKU_SCRUB_GROTTO_RIGHT, + RC_GC_GS_CENTER_PLATFORM, + RC_GC_GS_BOULDER_MAZE, + RC_GC_SHOP_ITEM_1, + RC_GC_SHOP_ITEM_2, + RC_GC_SHOP_ITEM_3, + RC_GC_SHOP_ITEM_4, + RC_GC_SHOP_ITEM_5, + RC_GC_SHOP_ITEM_6, + RC_GC_SHOP_ITEM_7, + RC_GC_SHOP_ITEM_8, + RC_DMC_VOLCANO_FREESTANDING_POH, + RC_DMC_WALL_FREESTANDING_POH, + RC_DMC_UPPER_GROTTO_CHEST, + RC_DMC_GREAT_FAIRY_REWARD, + RC_DMC_DEKU_SCRUB, + RC_DMC_DEKU_SCRUB_GROTTO_LEFT, + RC_DMC_DEKU_SCRUB_GROTTO_CENTER, + RC_DMC_DEKU_SCRUB_GROTTO_RIGHT, + RC_DMC_GS_CRATE, + RC_DMC_GS_BEAN_PATCH, + RC_ZR_MAGIC_BEAN_SALESMAN, + RC_ZR_OPEN_GROTTO_CHEST, + RC_ZR_FROGS_ZELDAS_LULLABY, + RC_ZR_FROGS_EPONAS_SONG, + RC_ZR_FROGS_SARIAS_SONG, + RC_ZR_FROGS_SUNS_SONG, + RC_ZR_FROGS_SONG_OF_TIME, + RC_ZR_FROGS_IN_THE_RAIN, + RC_ZR_FROGS_OCARINA_GAME, + RC_ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH, + RC_ZR_NEAR_DOMAIN_FREESTANDING_POH, + RC_ZR_DEKU_SCRUB_GROTTO_FRONT, + RC_ZR_DEKU_SCRUB_GROTTO_REAR, + RC_ZR_GS_TREE, + RC_ZR_GS_LADDER, + RC_ZR_GS_NEAR_RAISED_GROTTOS, + RC_ZR_GS_ABOVE_BRIDGE, + RC_ZD_DIVING_MINIGAME, + RC_ZD_CHEST, + RC_ZD_KING_ZORA_THAWED, + RC_ZD_TRADE_PRESCRIPTION, + RC_ZD_GS_FROZEN_WATERFALL, + RC_ZD_SHOP_ITEM_1, + RC_ZD_SHOP_ITEM_2, + RC_ZD_SHOP_ITEM_3, + RC_ZD_SHOP_ITEM_4, + RC_ZD_SHOP_ITEM_5, + RC_ZD_SHOP_ITEM_6, + RC_ZD_SHOP_ITEM_7, + RC_ZD_SHOP_ITEM_8, + RC_ZF_GREAT_FAIRY_REWARD, + RC_ZF_ICEBERC_FREESTANDING_POH, + RC_ZF_BOTTOM_FREESTANDING_POH, + RC_ZF_GS_ABOVE_THE_LOG, + RC_ZF_GS_TREE, + RC_ZF_GS_HIDDEN_CAVE, + RC_LH_UNDERWATER_ITEM, + RC_LH_CHILD_FISHING, + RC_LH_ADULT_FISHING, + RC_LH_LAB_DIVE, + RC_LH_TRADE_FROG, + RC_LH_FREESTANDING_POH, + RC_LH_SUN, + RC_LH_DEKU_SCRUB_GROTTO_LEFT, + RC_LH_DEKU_SCRUB_GROTTO_CENTER, + RC_LH_DEKU_SCRUB_GROTTO_RIGHT, + RC_LH_GS_BEAN_PATCH, + RC_LH_GS_LAB_WALL, + RC_LH_GS_SMALL_ISLAND, + RC_LH_GS_LAB_CRATE, + RC_LH_GS_TREE, + RC_GV_CRATE_FREESTANDING_POH, + RC_GV_WATERFALL_FREESTANDING_POH, + RC_GV_CHEST, + RC_GV_TRADE_SAW, + RC_GV_DEKU_SCRUB_GROTTO_FRONT, + RC_GV_DEKU_SCRUB_GROTTO_REAR, + RC_GV_COW, + RC_GV_GS_SMALL_BRIDGE, + RC_GV_GS_BEAN_PATCH, + RC_GV_GS_BEHIND_TENT, + RC_GV_GS_PILLAR, + RC_GF_CHEST, + RC_GF_HBA_1000_POINTS, + RC_GF_HBA_1500_POINTS, + RC_GF_GERUDO_MEMBERSHIP_CARD, + RC_GF_NORTH_F1_CARPENTER, + RC_GF_NORTH_F2_CARPENTER, + RC_GF_SOUTH_F1_CARPENTER, + RC_GF_SOUTH_F2_CARPENTER, + RC_GF_GS_TOP_FLOOR, + RC_GF_GS_ARCHERY_RANGE, + RC_HIDEOUT_JAIL_GUARD_1_TORCH, + RC_HIDEOUT_JAIL_GUARD_2_TORCHES, + RC_HIDEOUT_JAIL_GUARD_3_TORCHES, + RC_HIDEOUT_JAIL_GUARD_4_TORCHES, + RC_HIDEOUT_GERUDO_MEMBERSHIP_CARD, + RC_WASTELAND_BOMBCHU_SALESMAN, + RC_WASTELAND_CHEST, + RC_WASTELAND_GS, + RC_COLOSSUS_GREAT_FAIRY_REWARD, + RC_COLOSSUS_FREESTANDING_POH, + RC_COLOSSUS_DEKU_SCRUB_GROTTO_FRONT, + RC_COLOSSUS_DEKU_SCRUB_GROTTO_REAR, + RC_COLOSSUS_GS_BEAN_PATCH, + RC_COLOSSUS_GS_TREE, + RC_COLOSSUS_GS_HILL, + RC_OGC_GREAT_FAIRY_REWARD, + RC_OGC_GS, + RC_DEKU_TREE_MAP_CHEST, + RC_DEKU_TREE_SLINGSHOT_ROOM_SIDE_CHEST, + RC_DEKU_TREE_SLINGSHOT_CHEST, + RC_DEKU_TREE_COMPASS_CHEST, + RC_DEKU_TREE_COMPASS_ROOM_SIDE_CHEST, + RC_DEKU_TREE_BASEMENT_CHEST, + RC_DEKU_TREE_GS_COMPASS_ROOM, + RC_DEKU_TREE_GS_BASEMENT_VINES, + RC_DEKU_TREE_GS_BASEMENT_GATE, + RC_DEKU_TREE_GS_BASEMENT_BACK_ROOM, + RC_DEKU_TREE_MQ_MAP_CHEST, + RC_DEKU_TREE_MQ_SLINGSHOT_CHEST, + RC_DEKU_TREE_MQ_SLINGSHOT_ROOM_BACK_CHEST, + RC_DEKU_TREE_MQ_COMPASS_CHEST, + RC_DEKU_TREE_MQ_BASEMENT_CHEST, + RC_DEKU_TREE_MQ_BEFORE_SPINNING_LOG_CHEST, + RC_DEKU_TREE_MQ_AFTER_SPINNING_LOG_CHEST, + RC_DEKU_TREE_MQ_DEKU_SCRUB, + RC_DEKU_TREE_MQ_GS_LOBBY, + RC_DEKU_TREE_MQ_GS_COMPASS_ROOM, + RC_DEKU_TREE_MQ_GS_BASEMENT_GRAVES_ROOM, + RC_DEKU_TREE_MQ_GS_BASEMENT_BACK_ROOM, + RC_DEKU_TREE_QUEEN_GOHMA_HEART, + RC_DODONGOS_CAVERN_MAP_CHEST, + RC_DODONGOS_CAVERN_COMPASS_CHEST, + RC_DODONGOS_CAVERN_BOMB_FLOWER_PLATFORM_CHEST, + RC_DODONGOS_CAVERN_BOMB_BAG_CHEST, + RC_DODONGOS_CAVERN_END_OF_BRIDGE_CHEST, + RC_DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS, + RC_DODONGOS_CAVERN_DEKU_SCRUB_LOBBY, + RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT, + RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT, + RC_DODONGOS_CAVERN_GS_SIDE_ROOM_NEAR_LOWER_LIZALFOS, + RC_DODONGOS_CAVERN_GS_SCARECROW, + RC_DODONGOS_CAVERN_GS_ALCOVE_ABOVE_STAIRS, + RC_DODONGOS_CAVERN_GS_VINES_ABOVE_STAIRS, + RC_DODONGOS_CAVERN_GS_BACK_ROOM, + RC_DODONGOS_CAVERN_MQ_MAP_CHEST, + RC_DODONGOS_CAVERN_MQ_BOMB_BAG_CHEST, + RC_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_ROOM_CHEST, + RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CHEST, + RC_DODONGOS_CAVERN_MQ_COMPASS_CHEST, + RC_DODONGOS_CAVERN_MQ_UNDER_GRAVE_CHEST, + RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT, + RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR, + RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS, + RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE, + RC_DODONGOS_CAVERN_MQ_GS_SCRUB_ROOM, + RC_DODONGOS_CAVERN_MQ_GS_LARVAE_ROOM, + RC_DODONGOS_CAVERN_MQ_GS_LIZALFOS_ROOM, + RC_DODONGOS_CAVERN_MQ_GS_SONG_OF_TIME_BLOCK_ROOM, + RC_DODONGOS_CAVERN_MQ_GS_BACK_AREA, + RC_DODONGOS_CAVERN_BOSS_ROOM_CHEST, + RC_DODONGOS_CAVERN_KING_DODONGO_HEART, + RC_JABU_JABUS_BELLY_BOOMERANG_CHEST, + RC_JABU_JABUS_BELLY_MAP_CHEST, + RC_JABU_JABUS_BELLY_COMPASS_CHEST, + RC_JABU_JABUS_BELLY_DEKU_SCRUB, + RC_JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM, + RC_JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_LOWER, + RC_JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_UPPER, + RC_JABU_JABUS_BELLY_GS_NEAR_BOSS, + RC_JABU_JABUS_BELLY_MQ_MAP_CHEST, + RC_JABU_JABUS_BELLY_MQ_FIRST_ROOM_SIDE_CHEST, + RC_JABU_JABUS_BELLY_MQ_SECOND_ROOM_LOWER_CHEST, + RC_JABU_JABUS_BELLY_MQ_COMPASS_CHEST, + RC_JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_SWITCHES_CHEST, + RC_JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_VINES_CHEST, + RC_JABU_JABUS_BELLY_MQ_BOOMERANG_ROOM_SMALL_CHEST, + RC_JABU_JABUS_BELLY_MQ_BOOMERANG_CHEST, + RC_JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_ROOM_CHEST, + RC_JABU_JABUS_BELLY_MQ_SECOND_ROOM_UPPER_CHEST, + RC_JABU_JABUS_BELLY_MQ_NEAR_BOSS_CHEST, + RC_JABU_JABUS_BELLY_MQ_COW, + RC_JABU_JABUS_BELLY_MQ_GS_BOOMERANG_CHEST_ROOM, + RC_JABU_JABUS_BELLY_MQ_GS_TAILPASARAN_ROOM, + RC_JABU_JABUS_BELLY_MQ_GS_INVISIBLE_ENEMIES_ROOM, + RC_JABU_JABUS_BELLY_MQ_GS_NEAR_BOSS, + RC_JABU_JABUS_BELLY_BARINADE_HEART, + RC_BOTTOM_OF_THE_WELL_FRONT_LEFT_FAKE_WALL_CHEST, + RC_BOTTOM_OF_THE_WELL_FRONT_CENTER_BOMBABLE_CHEST, + RC_BOTTOM_OF_THE_WELL_BACK_LEFT_BOMBABLE_CHEST, + RC_BOTTOM_OF_THE_WELL_UNDERWATER_LEFT_CHEST, + RC_BOTTOM_OF_THE_WELL_FREESTANDING_KEY, + RC_BOTTOM_OF_THE_WELL_COMPASS_CHEST, + RC_BOTTOM_OF_THE_WELL_CENTER_SKULLTULA_CHEST, + RC_BOTTOM_OF_THE_WELL_RIGHT_BOTTOM_FAKE_WALL_CHEST, + RC_BOTTOM_OF_THE_WELL_FIRE_KEESE_CHEST, + RC_BOTTOM_OF_THE_WELL_LIKE_LIKE_CHEST, + RC_BOTTOM_OF_THE_WELL_MAP_CHEST, + RC_BOTTOM_OF_THE_WELL_UNDERWATER_FRONT_CHEST, + RC_BOTTOM_OF_THE_WELL_INVISIBLE_CHEST, + RC_BOTTOM_OF_THE_WELL_LENS_OF_TRUTH_CHEST, + RC_BOTTOM_OF_THE_WELL_GS_WEST_INNER_ROOM, + RC_BOTTOM_OF_THE_WELL_GS_EAST_INNER_ROOM, + RC_BOTTOM_OF_THE_WELL_GS_LIKE_LIKE_CAGE, + RC_BOTTOM_OF_THE_WELL_MQ_MAP_CHEST, + RC_BOTTOM_OF_THE_WELL_MQ_EAST_INNER_ROOM_FREESTANDING_KEY, + RC_BOTTOM_OF_THE_WELL_MQ_COMPASS_CHEST, + RC_BOTTOM_OF_THE_WELL_MQ_DEAD_HAND_FREESTANDING_KEY, + RC_BOTTOM_OF_THE_WELL_MQ_LENS_OF_TRUTH_CHEST, + RC_BOTTOM_OF_THE_WELL_MQ_GS_COFFIN_ROOM, + RC_BOTTOM_OF_THE_WELL_MQ_GS_WEST_INNER_ROOM, + RC_BOTTOM_OF_THE_WELL_MQ_GS_BASEMENT, + RC_FOREST_TEMPLE_FIRST_ROOM_CHEST, + RC_FOREST_TEMPLE_FIRST_STALFOS_CHEST, + RC_FOREST_TEMPLE_RAISED_ISLAND_COURTYARD_CHEST, + RC_FOREST_TEMPLE_MAP_CHEST, + RC_FOREST_TEMPLE_WELL_CHEST, + RC_FOREST_TEMPLE_EYE_SWITCH_CHEST, + RC_FOREST_TEMPLE_BOSS_KEY_CHEST, + RC_FOREST_TEMPLE_FLOORMASTER_CHEST, + RC_FOREST_TEMPLE_RED_POE_CHEST, + RC_FOREST_TEMPLE_BOW_CHEST, + RC_FOREST_TEMPLE_BLUE_POE_CHEST, + RC_FOREST_TEMPLE_FALLING_CEILING_ROOM_CHEST, + RC_FOREST_TEMPLE_BASEMENT_CHEST, + RC_FOREST_TEMPLE_GS_FIRST_ROOM, + RC_FOREST_TEMPLE_GS_LOBBY, + RC_FOREST_TEMPLE_GS_RAISED_ISLAND_COURTYARD, + RC_FOREST_TEMPLE_GS_LEVEL_ISLAND_COURTYARD, + RC_FOREST_TEMPLE_GS_BASEMENT, + RC_FOREST_TEMPLE_MQ_FIRST_ROOM_CHEST, + RC_FOREST_TEMPLE_MQ_WOLFOS_CHEST, + RC_FOREST_TEMPLE_MQ_WELL_CHEST, + RC_FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_LOWER_CHEST, + RC_FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_UPPER_CHEST, + RC_FOREST_TEMPLE_MQ_BOSS_KEY_CHEST, + RC_FOREST_TEMPLE_MQ_REDEAD_CHEST, + RC_FOREST_TEMPLE_MQ_MAP_CHEST, + RC_FOREST_TEMPLE_MQ_BOW_CHEST, + RC_FOREST_TEMPLE_MQ_COMPASS_CHEST, + RC_FOREST_TEMPLE_MQ_FALLING_CEILING_ROOM_CHEST, + RC_FOREST_TEMPLE_MQ_BASEMENT_CHEST, + RC_FOREST_TEMPLE_MQ_GS_FIRST_HALLWAY, + RC_FOREST_TEMPLE_MQ_GS_RAISED_ISLAND_COURTYARD, + RC_FOREST_TEMPLE_MQ_GS_LEVEL_ISLAND_COURTYARD, + RC_FOREST_TEMPLE_MQ_GS_WELL, + RC_FOREST_TEMPLE_MQ_GS_BLOCK_PUSH_ROOM, + RC_FOREST_TEMPLE_PHANTOM_GANON_HEART, + RC_FIRE_TEMPLE_NEAR_BOSS_CHEST, + RC_FIRE_TEMPLE_FLARE_DANCER_CHEST, + RC_FIRE_TEMPLE_BOSS_KEY_CHEST, + RC_FIRE_TEMPLE_BIG_LAVA_ROOM_LOWER_OPEN_DOOR_CHEST, + RC_FIRE_TEMPLE_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST, + RC_FIRE_TEMPLE_BOULDER_MAZE_LOWER_CHEST, + RC_FIRE_TEMPLE_BOULDER_MAZE_SIDE_ROOM_CHEST, + RC_FIRE_TEMPLE_MAP_CHEST, + RC_FIRE_TEMPLE_BOULDER_MAZE_SHORTCUT_CHEST, + RC_FIRE_TEMPLE_BOULDER_MAZE_UPPER_CHEST, + RC_FIRE_TEMPLE_SCARECROW_CHEST, + RC_FIRE_TEMPLE_COMPASS_CHEST, + RC_FIRE_TEMPLE_MEGATON_HAMMER_CHEST, + RC_FIRE_TEMPLE_HIGHEST_GORON_CHEST, + RC_FIRE_TEMPLE_GS_BOSS_KEY_LOOP, + RC_FIRE_TEMPLE_GS_SONG_OF_TIME_ROOM, + RC_FIRE_TEMPLE_GS_BOULDER_MAZE, + RC_FIRE_TEMPLE_GS_SCARECROW_CLIMB, + RC_FIRE_TEMPLE_GS_SCARECROW_TOP, + RC_FIRE_TEMPLE_MQ_MAP_ROOM_SIDE_CHEST, + RC_FIRE_TEMPLE_MQ_MEGATON_HAMMER_CHEST, + RC_FIRE_TEMPLE_MQ_MAP_CHEST, + RC_FIRE_TEMPLE_MQ_NEAR_BOSS_CHEST, + RC_FIRE_TEMPLE_MQ_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST, + RC_FIRE_TEMPLE_MQ_BOSS_KEY_CHEST, + RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_SIDE_ROOM_CHEST, + RC_FIRE_TEMPLE_MQ_COMPASS_CHEST, + RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CHEST, + RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CHEST, + RC_FIRE_TEMPLE_MQ_FREESTANDING_KEY, + RC_FIRE_TEMPLE_MQ_CHEST_ON_FIRE, + RC_FIRE_TEMPLE_MQ_GS_BIG_LAVA_ROOM_OPEN_DOOR, + RC_FIRE_TEMPLE_MQ_GS_SKULL_ON_FIRE, + RC_FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_CENTER, + RC_FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_SIDE_ROOM, + RC_FIRE_TEMPLE_MQ_GS_ABOVE_FIRE_WALL_MAZE, + RC_FIRE_TEMPLE_VOLVAGIA_HEART, + RC_WATER_TEMPLE_COMPASS_CHEST, + RC_WATER_TEMPLE_MAP_CHEST, + RC_WATER_TEMPLE_CRACKED_WALL_CHEST, + RC_WATER_TEMPLE_TORCHES_CHEST, + RC_WATER_TEMPLE_BOSS_KEY_CHEST, + RC_WATER_TEMPLE_CENTRAL_PILLAR_CHEST, + RC_WATER_TEMPLE_CENTRAL_BOW_TARGET_CHEST, + RC_WATER_TEMPLE_LONGSHOT_CHEST, + RC_WATER_TEMPLE_RIVER_CHEST, + RC_WATER_TEMPLE_DRAGON_CHEST, + RC_WATER_TEMPLE_GS_BEHIND_GATE, + RC_WATER_TEMPLE_GS_NEAR_BOSS_KEY_CHEST, + RC_WATER_TEMPLE_GS_CENTRAL_PILLAR, + RC_WATER_TEMPLE_GS_FALLING_PLATFORM_ROOM, + RC_WATER_TEMPLE_GS_RIVER, + RC_WATER_TEMPLE_MQ_LONGSHOT_CHEST, + RC_WATER_TEMPLE_MQ_MAP_CHEST, + RC_WATER_TEMPLE_MQ_COMPASS_CHEST, + RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_CHEST, + RC_WATER_TEMPLE_MQ_BOSS_KEY_CHEST, + RC_WATER_TEMPLE_MQ_FREESTANDING_KEY, + RC_WATER_TEMPLE_MQ_GS_LIZALFOS_HALLWAY, + RC_WATER_TEMPLE_MQ_GS_BEFORE_UPPER_WATER_SWITCH, + RC_WATER_TEMPLE_MQ_GS_RIVER, + RC_WATER_TEMPLE_MQ_GS_FREESTANDING_KEY_AREA, + RC_WATER_TEMPLE_MQ_GS_TRIPLE_WALL_TORCH, + RC_WATER_TEMPLE_MORPHA_HEART, + RC_SHADOW_TEMPLE_MAP_CHEST, + RC_SHADOW_TEMPLE_HOVER_BOOTS_CHEST, + RC_SHADOW_TEMPLE_COMPASS_CHEST, + RC_SHADOW_TEMPLE_EARLY_SILVER_RUPEE_CHEST, + RC_SHADOW_TEMPLE_INVISIBLE_BLADES_VISIBLE_CHEST, + RC_SHADOW_TEMPLE_INVISIBLE_BLADES_INVISIBLE_CHEST, + RC_SHADOW_TEMPLE_FALLING_SPIKES_LOWER_CHEST, + RC_SHADOW_TEMPLE_FALLING_SPIKES_UPPER_CHEST, + RC_SHADOW_TEMPLE_FALLING_SPIKES_SWITCH_CHEST, + RC_SHADOW_TEMPLE_INVISIBLE_SPIKES_CHEST, + RC_SHADOW_TEMPLE_FREESTANDING_KEY, + RC_SHADOW_TEMPLE_WIND_HINT_CHEST, + RC_SHADOW_TEMPLE_AFTER_WIND_ENEMY_CHEST, + RC_SHADOW_TEMPLE_AFTER_WIND_HIDDEN_CHEST, + RC_SHADOW_TEMPLE_SPIKE_WALLS_LEFT_CHEST, + RC_SHADOW_TEMPLE_BOSS_KEY_CHEST, + RC_SHADOW_TEMPLE_INVISIBLE_FLOORMASTER_CHEST, + RC_SHADOW_TEMPLE_GS_LIKE_LIKE_ROOM, + RC_SHADOW_TEMPLE_GS_FALLING_SPIKES_ROOM, + RC_SHADOW_TEMPLE_GS_SINGLE_GIANT_POT, + RC_SHADOW_TEMPLE_GS_NEAR_SHIP, + RC_SHADOW_TEMPLE_GS_TRIPLE_GIANT_POT, + RC_SHADOW_TEMPLE_MQ_EARLY_GIBDOS_CHEST, + RC_SHADOW_TEMPLE_MQ_MAP_CHEST, + RC_SHADOW_TEMPLE_MQ_NEAR_SHIP_INVISIBLE_CHEST, + RC_SHADOW_TEMPLE_MQ_COMPASS_CHEST, + RC_SHADOW_TEMPLE_MQ_HOVER_BOOTS_CHEST, + RC_SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_INVISIBLE_CHEST, + RC_SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_VISIBLE_CHEST, + RC_SHADOW_TEMPLE_MQ_BEAMOS_SILVER_RUPEES_CHEST, + RC_SHADOW_TEMPLE_MQ_FALLING_SPIKES_LOWER_CHEST, + RC_SHADOW_TEMPLE_MQ_FALLING_SPIKES_UPPER_CHEST, + RC_SHADOW_TEMPLE_MQ_FALLING_SPIKES_SWITCH_CHEST, + RC_SHADOW_TEMPLE_MQ_INVISIBLE_SPIKES_CHEST, + RC_SHADOW_TEMPLE_MQ_STALFOS_ROOM_CHEST, + RC_SHADOW_TEMPLE_MQ_WIND_HINT_CHEST, + RC_SHADOW_TEMPLE_MQ_AFTER_WIND_HIDDEN_CHEST, + RC_SHADOW_TEMPLE_MQ_AFTER_WIND_ENEMY_CHEST, + RC_SHADOW_TEMPLE_MQ_BOSS_KEY_CHEST, + RC_SHADOW_TEMPLE_MQ_SPIKE_WALLS_LEFT_CHEST, + RC_SHADOW_TEMPLE_MQ_FREESTANDING_KEY, + RC_SHADOW_TEMPLE_MQ_BOMB_FLOWER_CHEST, + RC_SHADOW_TEMPLE_MQ_GS_FALLING_SPIKES_ROOM, + RC_SHADOW_TEMPLE_MQ_GS_WIND_HINT_ROOM, + RC_SHADOW_TEMPLE_MQ_GS_AFTER_WIND, + RC_SHADOW_TEMPLE_MQ_GS_AFTER_SHIP, + RC_SHADOW_TEMPLE_MQ_GS_NEAR_BOSS, + RC_SHADOW_TEMPLE_BONGO_BONGO_HEART, + RC_SPIRIT_TEMPLE_CHILD_BRIDGE_CHEST, + RC_SPIRIT_TEMPLE_CHILD_EARLY_TORCHES_CHEST, + RC_SPIRIT_TEMPLE_CHILD_CLIMB_NORTH_CHEST, + RC_SPIRIT_TEMPLE_CHILD_CLIMB_EAST_CHEST, + RC_SPIRIT_TEMPLE_MAP_CHEST, + RC_SPIRIT_TEMPLE_SUN_BLOCK_ROOM_CHEST, + RC_SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_LEFT_CHEST, + RC_SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_RIGHT_CHEST, + RC_SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_RIGHT_CHEST, + RC_SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_LEFT_CHEST, + RC_SPIRIT_TEMPLE_MQ_MAP_CHEST, + RC_SPIRIT_TEMPLE_MQ_MAP_ROOM_ENEMY_CHEST, + RC_SPIRIT_TEMPLE_MQ_CHILD_CLIMB_NORTH_CHEST, + RC_SPIRIT_TEMPLE_MQ_CHILD_CLIMB_SOUTH_CHEST, + RC_SPIRIT_TEMPLE_MQ_COMPASS_CHEST, + RC_SPIRIT_TEMPLE_MQ_SILVER_BLOCK_HALLWAY_CHEST, + RC_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM_CHEST, + RC_SPIRIT_TEMPLE_SILVER_GAUNTLETS_CHEST, + RC_SPIRIT_TEMPLE_COMPASS_CHEST, + RC_SPIRIT_TEMPLE_EARLY_ADULT_RIGHT_CHEST, + RC_SPIRIT_TEMPLE_FIRST_MIRROR_LEFT_CHEST, + RC_SPIRIT_TEMPLE_FIRST_MIRROR_RIGHT_CHEST, + RC_SPIRIT_TEMPLE_STATUE_ROOM_NORTHEAST_CHEST, + RC_SPIRIT_TEMPLE_STATUE_ROOM_HAND_CHEST, + RC_SPIRIT_TEMPLE_NEAR_FOUR_ARMOS_CHEST, + RC_SPIRIT_TEMPLE_HALLWAY_RIGHT_INVISIBLE_CHEST, + RC_SPIRIT_TEMPLE_HALLWAY_LEFT_INVISIBLE_CHEST, + RC_SPIRIT_TEMPLE_MQ_CHILD_HAMMER_SWITCH_CHEST, + RC_SPIRIT_TEMPLE_MQ_STATUE_ROOM_LULLABY_CHEST, + RC_SPIRIT_TEMPLE_MQ_STATUE_ROOM_INVISIBLE_CHEST, + RC_SPIRIT_TEMPLE_MQ_LEEVER_ROOM_CHEST, + RC_SPIRIT_TEMPLE_MQ_SYMPHONY_ROOM_CHEST, + RC_SPIRIT_TEMPLE_MQ_BEAMOS_ROOM_CHEST, + RC_SPIRIT_TEMPLE_MQ_CHEST_SWITCH_CHEST, + RC_SPIRIT_TEMPLE_MQ_BOSS_KEY_CHEST, + RC_SPIRIT_TEMPLE_MIRROR_SHIELD_CHEST, + RC_SPIRIT_TEMPLE_BOSS_KEY_CHEST, + RC_SPIRIT_TEMPLE_TOPMOST_CHEST, + RC_SPIRIT_TEMPLE_MQ_MIRROR_PUZZLE_INVISIBLE_CHEST, + RC_SPIRIT_TEMPLE_GS_METAL_FENCE, + RC_SPIRIT_TEMPLE_GS_SUN_ON_FLOOR_ROOM, + RC_SPIRIT_TEMPLE_GS_HALL_AFTER_SUN_BLOCK_ROOM, + RC_SPIRIT_TEMPLE_GS_LOBBY, + RC_SPIRIT_TEMPLE_GS_BOULDER_ROOM, + RC_SPIRIT_TEMPLE_MQ_GS_SUN_BLOCK_ROOM, + RC_SPIRIT_TEMPLE_MQ_GS_LEEVER_ROOM, + RC_SPIRIT_TEMPLE_MQ_GS_SYMPHONY_ROOM, + RC_SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_WEST, + RC_SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_NORTH, + RC_SPIRIT_TEMPLE_TWINROVA_HEART, + RC_ICE_CAVERN_MAP_CHEST, + RC_ICE_CAVERN_COMPASS_CHEST, + RC_ICE_CAVERN_FREESTANDING_POH, + RC_ICE_CAVERN_IRON_BOOTS_CHEST, + RC_ICE_CAVERN_GS_SPINNING_SCYTHE_ROOM, + RC_ICE_CAVERN_GS_HEART_PIECE_ROOM, + RC_ICE_CAVERN_GS_PUSH_BLOCK_ROOM, + RC_ICE_CAVERN_MQ_MAP_CHEST, + RC_ICE_CAVERN_MQ_COMPASS_CHEST, + RC_ICE_CAVERN_MQ_FREESTANDING_POH, + RC_ICE_CAVERN_MQ_IRON_BOOTS_CHEST, + RC_ICE_CAVERN_MQ_GS_RED_ICE, + RC_ICE_CAVERN_MQ_GS_ICE_BLOCK, + RC_ICE_CAVERN_MQ_GS_SCARECROW, + RC_GERUDO_TRAINING_GROUND_LOBBY_LEFT_CHEST, + RC_GERUDO_TRAINING_GROUND_LOBBY_RIGHT_CHEST, + RC_GERUDO_TRAINING_GROUND_STALFOS_CHEST, + RC_GERUDO_TRAINING_GROUND_BEFORE_HEAVY_BLOCK_CHEST, + RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_FIRST_CHEST, + RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_SECOND_CHEST, + RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_THIRD_CHEST, + RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_FOURTH_CHEST, + RC_GERUDO_TRAINING_GROUND_EYE_STATUE_CHEST, + RC_GERUDO_TRAINING_GROUND_NEAR_SCARECROW_CHEST, + RC_GERUDO_TRAINING_GROUND_HAMMER_ROOM_CLEAR_CHEST, + RC_GERUDO_TRAINING_GROUND_HAMMER_ROOM_SWITCH_CHEST, + RC_GERUDO_TRAINING_GROUND_FREESTANDING_KEY, + RC_GERUDO_TRAINING_GROUND_MAZE_RIGHT_CENTRAL_CHEST, + RC_GERUDO_TRAINING_GROUND_MAZE_RIGHT_SIDE_CHEST, + RC_GERUDO_TRAINING_GROUND_UNDERWATER_SILVER_RUPEE_CHEST, + RC_GERUDO_TRAINING_GROUND_BEAMOS_CHEST, + RC_GERUDO_TRAINING_GROUND_HIDDEN_CEILING_CHEST, + RC_GERUDO_TRAINING_GROUND_MAZE_PATH_FIRST_CHEST, + RC_GERUDO_TRAINING_GROUND_MAZE_PATH_SECOND_CHEST, + RC_GERUDO_TRAINING_GROUND_MAZE_PATH_THIRD_CHEST, + RC_GERUDO_TRAINING_GROUND_MAZE_PATH_FINAL_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_LEFT_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_RIGHT_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_FIRST_IRON_KNUCKLE_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_BEFORE_HEAVY_BLOCK_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_HEAVY_BLOCK_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_EYE_STATUE_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_ICE_ARROWS_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_SECOND_IRON_KNUCKLE_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_FLAME_CIRCLE_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_MAZE_RIGHT_CENTRAL_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_MAZE_RIGHT_SIDE_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_UNDERWATER_SILVER_RUPEE_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_DINOLFOS_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_HIDDEN_CEILING_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_FIRST_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_THIRD_CHEST, + RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_SECOND_CHEST, + RC_GANONS_CASTLE_FOREST_TRIAL_CHEST, + RC_GANONS_CASTLE_WATER_TRIAL_LEFT_CHEST, + RC_GANONS_CASTLE_WATER_TRIAL_RIGHT_CHEST, + RC_GANONS_CASTLE_SHADOW_TRIAL_FRONT_CHEST, + RC_GANONS_CASTLE_SHADOW_TRIAL_GOLDEN_GAUNTLETS_CHEST, + RC_GANONS_CASTLE_LIGHT_TRIAL_FIRST_LEFT_CHEST, + RC_GANONS_CASTLE_LIGHT_TRIAL_SECOND_LEFT_CHEST, + RC_GANONS_CASTLE_LIGHT_TRIAL_THIRD_LEFT_CHEST, + RC_GANONS_CASTLE_LIGHT_TRIAL_FIRST_RIGHT_CHEST, + RC_GANONS_CASTLE_LIGHT_TRIAL_SECOND_RIGHT_CHEST, + RC_GANONS_CASTLE_LIGHT_TRIAL_THIRD_RIGHT_CHEST, + RC_GANONS_CASTLE_LIGHT_TRIAL_INVISIBLE_ENEMIES_CHEST, + RC_GANONS_CASTLE_LIGHT_TRIAL_LULLABY_CHEST, + RC_GANONS_CASTLE_SPIRIT_TRIAL_CRYSTAL_SWITCH_CHEST, + RC_GANONS_CASTLE_SPIRIT_TRIAL_INVISIBLE_CHEST, + RC_GANONS_CASTLE_DEKU_SCRUB_LEFT, + RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT, + RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT, + RC_GANONS_CASTLE_DEKU_SCRUB_RIGHT, + RC_GANONS_CASTLE_MQ_FOREST_TRIAL_FREESTANDING_KEY, + RC_GANONS_CASTLE_MQ_FOREST_TRIAL_EYE_SWITCH_CHEST, + RC_GANONS_CASTLE_MQ_FOREST_TRIAL_FROZEN_EYE_SWITCH_CHEST, + RC_GANONS_CASTLE_MQ_WATER_TRIAL_CHEST, + RC_GANONS_CASTLE_MQ_SHADOW_TRIAL_BOMB_FLOWER_CHEST, + RC_GANONS_CASTLE_MQ_SHADOW_TRIAL_EYE_SWITCH_CHEST, + RC_GANONS_CASTLE_MQ_LIGHT_TRIAL_LULLABY_CHEST, + RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_FIRST_CHEST, + RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_INVISIBLE_CHEST, + RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_FRONT_LEFT_CHEST, + RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_LEFT_CHEST, + RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_RIGHT_CHEST, + RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_GOLDEN_GAUNTLETS_CHEST, + RC_GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT, + RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT, + RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER, + RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT, + RC_GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT, + RC_GANONS_TOWER_BOSS_KEY_CHEST, + RC_PIERRE, + RC_DELIVER_RUTOS_LETTER, + RC_MASTER_SWORD_PEDESTAL, + RC_COLOSSUS_GOSSIP_STONE, + RC_DMC_GOSSIP_STONE, + RC_DMC_UPPER_GROTTO_GOSSIP_STONE, + RC_DMT_GOSSIP_STONE, + RC_DMT_STORMS_GROTTO_GOSSIP_STONE, + RC_DODONGOS_CAVERN_GOSSIP_STONE, + RC_FAIRY_GOSSIP_STONE, + RC_GC_MAZE_GOSSIP_STONE, + RC_GC_MEDIGORON_GOSSIP_STONE, + RC_GV_GOSSIP_STONE, + RC_GY_GOSSIP_STONE, + RC_HC_MALON_GOSSIP_STONE, + RC_HC_ROCK_WALL_GOSSIP_STONE, + RC_HC_STORMS_GROTTO_GOSSIP_STONE, + RC_HF_COW_GROTTO_GOSSIP_STONE, + RC_HF_NEAR_MARKET_GOSSIP_STONE, + RC_HF_OPEN_GROTTO_GOSSIP_STONE, + RC_HF_SOUTHEAST_GOSSIP_STONE, + RC_JABU_GOSSIP_STONE, + RC_KF_DEKU_TREE_LEFT_GOSSIP_STONE, + RC_KF_DEKU_TREE_RIGHT_GOSSIP_STONE, + RC_KF_GOSSIP_STONE, + RC_KF_STORMS_GOSSIP_STONE, + RC_KAK_OPEN_GROTTO_GOSSIP_STONE, + RC_LH_LAB_GOSSIP_STONE, + RC_LH_SOUTHEAST_GOSSIP_STONE, + RC_LH_SOUTHWEST_GOSSIP_STONE, + RC_LW_GOSSIP_STONE, + RC_LW_NEAR_SHORTCUTS_GOSSIP_STONE, + RC_SFM_MAZE_LOWER_GOSSIP_STONE, + RC_SFM_MAZE_UPPER_GOSSIP_STONE, + RC_SFM_SARIA_GOSSIP_STONE, + RC_TOT_LEFT_CENTER_GOSSIP_STONE, + RC_TOT_LEFT_GOSSIP_STONE, + RC_TOT_RIGHT_CENTER_GOSSIP_STONE, + RC_TOT_RIGHT_GOSSIP_STONE, + RC_ZD_GOSSIP_STONE, + RC_ZR_NEAR_DOMAIN_GOSSIP_STONE, + RC_ZR_NEAR_GROTTOS_GOSSIP_STONE, + RC_ZR_OPEN_GROTTO_GOSSIP_STONE, + RC_UNKNOWN_CHECK +} RandomizerCheck; + +// based on https://github.com/TestRunnerSRL/OoT-Randomizer/blob/e337d7f603b91a6bacb618fb32cc7fd70ed9ffca/ItemList.py +typedef enum { + RG_NONE, + RG_KOKIRI_SWORD, + RG_GIANTS_KNIFE, + RG_BIGGORON_SWORD, + RG_DEKU_SHIELD, + RG_HYLIAN_SHIELD, + RG_MIRROR_SHIELD, + RG_GORON_TUNIC, + RG_ZORA_TUNIC, + RG_IRON_BOOTS, + RG_HOVER_BOOTS, + RG_BOOMERANG, + RG_LENS_OF_TRUTH, + RG_MEGATON_HAMMER, + RG_STONE_OF_AGONY, + RG_DINS_FIRE, + RG_FARORES_WIND, + RG_NAYRUS_LOVE, + RG_FIRE_ARROWS, + RG_ICE_ARROWS, + RG_LIGHT_ARROWS, + RG_GERUDO_MEMBERSHIP_CARD, + RG_MAGIC_BEAN, + RG_MAGIC_BEAN_PACK, + RG_DOUBLE_DEFENSE, + RG_WEIRD_EGG, + RG_ZELDAS_LETTER, + RG_POCKET_EGG, + RG_COJIRO, + RG_ODD_MUSHROOM, + RG_ODD_POTION, + RG_POACHERS_SAW, + RG_BROKEN_SWORD, + RG_PRESCRIPTION, + RG_EYEBALL_FROG, + RG_EYEDROPS, + RG_CLAIM_CHECK, + RG_GOLD_SKULLTULA_TOKEN, + RG_PROGRESSIVE_HOOKSHOT, + RG_PROGRESSIVE_STRENGTH, + RG_PROGRESSIVE_BOMB_BAG, + RG_PROGRESSIVE_BOW, + RG_PROGRESSIVE_SLINGSHOT, + RG_PROGRESSIVE_WALLET, + RG_PROGRESSIVE_SCALE, + RG_PROGRESSIVE_NUT_UPGRADE, + RG_PROGRESSIVE_STICK_UPGRADE, + RG_PROGRESSIVE_BOMBCHUS, + RG_PROGRESSIVE_MAGIC_METER, + RG_PROGRESSIVE_OCARINA, + RG_PROGRESSIVE_GORONSWORD, + RG_EMPTY_BOTTLE, + RG_BOTTLE_WITH_MILK, + RG_BOTTLE_WITH_RED_POTION, + RG_BOTTLE_WITH_GREEN_POTION, + RG_BOTTLE_WITH_BLUE_POTION, + RG_BOTTLE_WITH_FAIRY, + RG_BOTTLE_WITH_FISH, + RG_BOTTLE_WITH_BLUE_FIRE, + RG_BOTTLE_WITH_BUGS, + RG_BOTTLE_WITH_POE, + RG_RUTOS_LETTER, + RG_BOTTLE_WITH_BIG_POE, + RG_ZELDAS_LULLABY, + RG_EPONAS_SONG, + RG_SARIAS_SONG, + RG_SUNS_SONG, + RG_SONG_OF_TIME, + RG_SONG_OF_STORMS, + RG_MINUET_OF_FOREST, + RG_BOLERO_OF_FIRE, + RG_SERENADE_OF_WATER, + RG_REQUIEM_OF_SPIRIT, + RG_NOCTURNE_OF_SHADOW, + RG_PRELUDE_OF_LIGHT, + RG_DEKU_TREE_MAP, + RG_DODONGOS_CAVERN_MAP, + RG_JABU_JABUS_BELLY_MAP, + RG_FOREST_TEMPLE_MAP, + RG_FIRE_TEMPLE_MAP, + RG_WATER_TEMPLE_MAP, + RG_SPIRIT_TEMPLE_MAP, + RG_SHADOW_TEMPLE_MAP, + RG_BOTTOM_OF_THE_WELL_MAP, + RG_ICE_CAVERN_MAP, + RG_DEKU_TREE_COMPASS, + RG_DODONGOS_CAVERN_COMPASS, + RG_JABU_JABUS_BELLY_COMPASS, + RG_FOREST_TEMPLE_COMPASS, + RG_FIRE_TEMPLE_COMPASS, + RG_WATER_TEMPLE_COMPASS, + RG_SPIRIT_TEMPLE_COMPASS, + RG_SHADOW_TEMPLE_COMPASS, + RG_BOTTOM_OF_THE_WELL_COMPASS, + RG_ICE_CAVERN_COMPASS, + RG_FOREST_TEMPLE_BOSS_KEY, + RG_FIRE_TEMPLE_BOSS_KEY, + RG_WATER_TEMPLE_BOSS_KEY, + RG_SPIRIT_TEMPLE_BOSS_KEY, + RG_SHADOW_TEMPLE_BOSS_KEY, + RG_GANONS_CASTLE_BOSS_KEY, + RG_FOREST_TEMPLE_SMALL_KEY, + RG_FIRE_TEMPLE_SMALL_KEY, + RG_WATER_TEMPLE_SMALL_KEY, + RG_SPIRIT_TEMPLE_SMALL_KEY, + RG_SHADOW_TEMPLE_SMALL_KEY, + RG_BOTTOM_OF_THE_WELL_SMALL_KEY, + RG_GERUDO_TRAINING_GROUNDS_SMALL_KEY, + RG_GERUDO_FORTRESS_SMALL_KEY, + RG_GANONS_CASTLE_SMALL_KEY, + RG_TREASURE_GAME_SMALL_KEY, + RG_FOREST_TEMPLE_KEY_RING, + RG_FIRE_TEMPLE_KEY_RING, + RG_WATER_TEMPLE_KEY_RING, + RG_SPIRIT_TEMPLE_KEY_RING, + RG_SHADOW_TEMPLE_KEY_RING, + RG_BOTTOM_OF_THE_WELL_KEY_RING, + RG_GERUDO_TRAINING_GROUNDS_KEY_RING, + RG_GERUDO_FORTRESS_KEY_RING, + RG_GANONS_CASTLE_KEY_RING, + RG_KOKIRI_EMERALD, + RG_GORON_RUBY, + RG_ZORA_SAPPHIRE, + RG_FOREST_MEDALLION, + RG_FIRE_MEDALLION, + RG_WATER_MEDALLION, + RG_SPIRIT_MEDALLION, + RG_SHADOW_MEDALLION, + RG_LIGHT_MEDALLION, + RG_RECOVERY_HEART, + RG_GREEN_RUPEE, + RG_BLUE_RUPEE, + RG_RED_RUPEE, + RG_PURPLE_RUPEE, + RG_HUGE_RUPEE, + RG_PIECE_OF_HEART, + RG_HEART_CONTAINER, + RG_ICE_TRAP, + RG_MILK, + RG_BOMBS_5, + RG_BOMBS_10, + RG_BOMBS_20, + RG_BOMBCHU_5, + RG_BOMBCHU_10, + RG_BOMBCHU_20, + RG_BOMBCHU_DROP, + RG_ARROWS_5, + RG_ARROWS_10, + RG_ARROWS_30, + RG_DEKU_NUTS_5, + RG_DEKU_NUTS_10, + RG_DEKU_SEEDS_30, + RG_DEKU_STICK_1, + RG_RED_POTION_REFILL, + RG_GREEN_POTION_REFILL, + RG_BLUE_POTION_REFILL, + RG_TREASURE_GAME_HEART, + RG_TREASURE_GAME_GREEN_RUPEE, + RG_BUY_DEKU_NUT_5, + RG_BUY_ARROWS_30, + RG_BUY_ARROWS_50, + RG_BUY_BOMBS_525, + RG_BUY_DEKU_NUT_10, + RG_BUY_DEKU_STICK_1, + RG_BUY_BOMBS_10, + RG_BUY_FISH, + RG_BUY_RED_POTION_30, + RG_BUY_GREEN_POTION, + RG_BUY_BLUE_POTION, + RG_BUY_HYLIAN_SHIELD, + RG_BUY_DEKU_SHIELD, + RG_BUY_GORON_TUNIC, + RG_BUY_ZORA_TUNIC, + RG_BUY_HEART, + RG_BUY_BOMBCHU_10, + RG_BUY_BOMBCHU_20, + RG_BUY_BOMBCHU_5, + RG_BUY_DEKU_SEEDS_30, + RG_SOLD_OUT, + RG_BUY_BLUE_FIRE, + RG_BUY_BOTTLE_BUG, + RG_BUY_POE, + RG_BUY_FAIRYS_SPIRIT, + RG_BUY_ARROWS_10, + RG_BUY_BOMBS_20, + RG_BUY_BOMBS_30, + RG_BUY_BOMBS_535, + RG_BUY_RED_POTION_40, + RG_BUY_RED_POTION_50, + RG_TRIFORCE, + RG_HINT +} RandomizerGet; + +typedef enum { + RSK_NONE, + RSK_FOREST, + RSK_KAK_GATE, + RSK_DOOR_OF_TIME, + RSK_ZORAS_FOUNTAIN, + RSK_GERUDO_FORTRESS, + RSK_RAINBOW_BRIDGE, + RSK_RAINBOW_BRIDGE_STONE_COUNT, + RSK_RAINBOW_BRIDGE_MEDALLION_COUNT, + RSK_RAINBOW_BRIDGE_REWARD_COUNT, + RSK_RAINBOW_BRIDGE_DUNGEON_COUNT, + RSK_RAINBOW_BRIDGE_TOKEN_COUNT, + RSK_RANDOM_TRIALS, + RSK_TRIAL_COUNT, + RSK_STARTING_OCARINA, + RSK_SHUFFLE_OCARINA, + RSK_STARTING_DEKU_SHIELD, + RSK_STARTING_KOKIRI_SWORD, + RSK_SHUFFLE_KOKIRI_SWORD, + RSK_STARTING_MAPS_COMPASSES, //RANDOTODO more options for this, rn it's just start with or own dungeon + RSK_SHUFFLE_DUNGEON_REWARDS, + RSK_SHUFFLE_SONGS, + RSK_SHUFFLE_WEIRD_EGG, + RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD, + RSK_ITEM_POOL, + RSK_ICE_TRAPS, + RSK_GOSSIP_STONE_HINTS, + RSK_HINT_CLARITY, + RSK_HINT_DISTRIBUTION, + RSK_GANONS_BOSS_KEY, + RSK_SKIP_CHILD_STEALTH, + RSK_SKIP_CHILD_ZELDA, + RSK_STARTING_CONSUMABLES, + RSK_FULL_WALLETS, + RSK_EXCLUDE_DEKU_THEATER_MASK_OF_TRUTH, + RSK_LANGUAGE, + RSK_EXCLUDE_KAK_10_GOLD_SKULLTULA_REWARD, + RSK_EXCLUDE_KAK_20_GOLD_SKULLTULA_REWARD, + RSK_EXCLUDE_KAK_30_GOLD_SKULLTULA_REWARD, + RSK_EXCLUDE_KAK_40_GOLD_SKULLTULA_REWARD, + RSK_EXCLUDE_KAK_50_GOLD_SKULLTULA_REWARD, + RSK_SHUFFLE_CHEST_MINIGAME, + RSK_CUCCO_COUNT, + RSK_BIG_POE_COUNT, + RSK_SKIP_EPONA_RACE, + RSK_SKIP_TOWER_ESCAPE +} RandomizerSettingKey; diff --git a/soh/randomizer_generation.cpp b/soh/randomizer_generation.cpp new file mode 100644 index 000000000..a55d5fcf0 --- /dev/null +++ b/soh/randomizer_generation.cpp @@ -0,0 +1,19 @@ +#include + +void GenerateRandomizer() { + int ret = Playthrough::Playthrough_Init(std::hash{}(Settings::seed)); + + if (ret < 0) { + if (ret == -1) { // Failed to generate after 5 tries + SPDLOG_ERROR( + "\n\nFailed to generate after 5 tries.\nPress B to go back to the menu.\nA different seed might be " + "successful."); + return; + } else { + SPDLOG_ERROR("\n\nError %d with fill.\nPress Select to exit or B to go back to the menu.\n", ret); + return; + } + } + + const auto& randomizerHash = GetRandomizerHash(); +} \ No newline at end of file diff --git a/soh/soh.vcxproj b/soh/soh.vcxproj index b7a2a32de..5f7ea818f 100644 --- a/soh/soh.vcxproj +++ b/soh/soh.vcxproj @@ -181,6 +181,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -890,6 +945,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/soh/soh.vcxproj.filters b/soh/soh.vcxproj.filters index 08d6f332f..bbe6578f2 100644 --- a/soh/soh.vcxproj.filters +++ b/soh/soh.vcxproj.filters @@ -2211,6 +2211,174 @@ Header Files\include + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Header Files + + + Header Files\soh\Enhancements + + + Source Files\src + @@ -3788,6 +3956,120 @@ Header Files\include + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files\soh\Enhancements + + + Source Files\src + @@ -3800,4 +4082,4 @@ - \ No newline at end of file + diff --git a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp index 0c9d0f25b..60c3e6c4e 100644 --- a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp +++ b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp @@ -130,6 +130,9 @@ std::map itemMapping = { ITEM_MAP_ENTRY(ITEM_COMPASS), ITEM_MAP_ENTRY(ITEM_DUNGEON_MAP), ITEM_MAP_ENTRY(ITEM_KEY_SMALL), + ITEM_MAP_ENTRY(ITEM_HEART_CONTAINER), + ITEM_MAP_ENTRY(ITEM_MAGIC_SMALL), + ITEM_MAP_ENTRY(ITEM_MAGIC_LARGE) }; // Maps entries in the GS flag array to the area name it represents @@ -196,6 +199,7 @@ std::map questMapping = { QUEST_MAP_ENTRY(QUEST_ZORA_SAPPHIRE, dgZoraSapphireIconTex), QUEST_MAP_ENTRY(QUEST_STONE_OF_AGONY, dgStoneOfAgonyIconTex), QUEST_MAP_ENTRY(QUEST_GERUDO_CARD, dgGerudosCardIconTex), + QUEST_MAP_ENTRY(QUEST_SKULL_TOKEN, dgGoldSkulltulaIconTex), }; typedef struct { @@ -212,12 +216,12 @@ typedef struct { // Maps song ids to info for use in ImGui std::array songMapping = { { - SONG_MAP_ENTRY(QUEST_SONG_LULLABY, 255, 255, 255), - SONG_MAP_ENTRY(QUEST_SONG_EPONA, 255, 255, 255), - SONG_MAP_ENTRY(QUEST_SONG_SARIA, 255, 255, 255), - SONG_MAP_ENTRY(QUEST_SONG_SUN, 255, 255, 255), - SONG_MAP_ENTRY(QUEST_SONG_TIME, 255, 255, 255), - SONG_MAP_ENTRY(QUEST_SONG_STORMS, 255, 255, 255), + SONG_MAP_ENTRY(QUEST_SONG_LULLABY, 224, 107, 255), + SONG_MAP_ENTRY(QUEST_SONG_EPONA, 255, 195, 60), + SONG_MAP_ENTRY(QUEST_SONG_SARIA, 127, 255, 137), + SONG_MAP_ENTRY(QUEST_SONG_SUN, 255, 255, 60), + SONG_MAP_ENTRY(QUEST_SONG_TIME, 119, 236, 255), + SONG_MAP_ENTRY(QUEST_SONG_STORMS, 165, 165, 165), SONG_MAP_ENTRY(QUEST_SONG_MINUET, 150, 255, 100), SONG_MAP_ENTRY(QUEST_SONG_BOLERO, 255, 80, 40), SONG_MAP_ENTRY(QUEST_SONG_SERENADE, 100, 150, 255), @@ -226,6 +230,27 @@ std::array songMapping = { { SONG_MAP_ENTRY(QUEST_SONG_PRELUDE, 255, 240, 100), } }; +#define VANILLA_SONG_MAP_ENTRY(id, r, g, b) \ + { \ + id, #id "_Vanilla", #id "_Vanilla_Faded", ImVec4(r / 255.0f, g / 255.0f, b / 255.0f, 1.0f) \ + } + +// Maps song ids to info for use in ImGui +std::array vanillaSongMapping = { { + VANILLA_SONG_MAP_ENTRY(QUEST_SONG_LULLABY, 255, 255, 255), + VANILLA_SONG_MAP_ENTRY(QUEST_SONG_EPONA, 255, 255, 255), + VANILLA_SONG_MAP_ENTRY(QUEST_SONG_SARIA, 255, 255, 255), + VANILLA_SONG_MAP_ENTRY(QUEST_SONG_SUN, 255, 255, 255), + VANILLA_SONG_MAP_ENTRY(QUEST_SONG_TIME, 255, 255, 255), + VANILLA_SONG_MAP_ENTRY(QUEST_SONG_STORMS, 255, 255, 255), + VANILLA_SONG_MAP_ENTRY(QUEST_SONG_MINUET, 150, 255, 100), + VANILLA_SONG_MAP_ENTRY(QUEST_SONG_BOLERO, 255, 80, 40), + VANILLA_SONG_MAP_ENTRY(QUEST_SONG_SERENADE, 100, 150, 255), + VANILLA_SONG_MAP_ENTRY(QUEST_SONG_REQUIEM, 255, 160, 0), + VANILLA_SONG_MAP_ENTRY(QUEST_SONG_NOCTURNE, 255, 100, 255), + VANILLA_SONG_MAP_ENTRY(QUEST_SONG_PRELUDE, 255, 240, 100), +} }; + // Encapsulates what is drawn by the passed-in function within a border template void DrawGroupWithBorder(T&& drawFunc) { @@ -1610,4 +1635,10 @@ void InitSaveEditor() { fadedCol.w = 0.3f; SohImGui::LoadResource(entry.nameFaded, gSongNoteTex, fadedCol); } + for (const auto& entry : vanillaSongMapping) { + SohImGui::LoadResource(entry.name, gSongNoteTex, entry.color); + ImVec4 fadedCol = entry.color; + fadedCol.w = 0.3f; + SohImGui::LoadResource(entry.nameFaded, gSongNoteTex, fadedCol); + } } diff --git a/soh/soh/Enhancements/gfx.c b/soh/soh/Enhancements/gfx.c new file mode 100644 index 000000000..d63827a91 --- /dev/null +++ b/soh/soh/Enhancements/gfx.c @@ -0,0 +1,63 @@ +#include "gfx.h" + +#include "global.h" +#include "z64.h" + +extern GlobalContext* gGlobalCtx; + +/** + * Simple wrapper to load a texture to be drawn. + */ +void sprite_load(sprite_t* sprite) { + OPEN_DISPS(gGlobalCtx->state.gfxCtx); + + if (sprite->im_siz == G_IM_SIZ_16b) { + gDPLoadTextureBlock( + OVERLAY_DISP++, + sprite->tex, + sprite->im_fmt, + G_IM_SIZ_16b, // @TEMP until I figure out how to use sprite->im_siz + sprite->width, sprite->height, + 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMASK, G_TX_NOMASK, + G_TX_NOLOD, G_TX_NOLOD + ); + } else { + gDPLoadTextureBlock( + OVERLAY_DISP++, + sprite->tex, + sprite->im_fmt, + G_IM_SIZ_32b, // @TEMP until I figure out how to use sprite->im_siz + sprite->width, sprite->height, + 0, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMASK, G_TX_NOMASK, + G_TX_NOLOD, G_TX_NOLOD + ); + } + + CLOSE_DISPS(gGlobalCtx->state.gfxCtx); +} + +/** + * Simple wrapper to draw a sprite/texture on the screen. + * sprite_load needs to be ran right before this. + */ +void sprite_draw(sprite_t* sprite, int left, int top, int width, int height) { + int width_factor = (1 << 10) * sprite->width / width; + int height_factor = (1 << 10) * sprite->height / height; + + OPEN_DISPS(gGlobalCtx->state.gfxCtx); + + gSPWideTextureRectangle( + OVERLAY_DISP++, + OTRGetRectDimensionFromRightEdge(left) << 2, top << 2, + (OTRGetRectDimensionFromRightEdge(left) + width) << 2, (top + height) << 2, + G_TX_RENDERTILE, + 0, 0, + width_factor, height_factor + ); + + CLOSE_DISPS(gGlobalCtx->state.gfxCtx); +} diff --git a/soh/soh/Enhancements/gfx.h b/soh/soh/Enhancements/gfx.h new file mode 100644 index 000000000..e4fb27cf0 --- /dev/null +++ b/soh/soh/Enhancements/gfx.h @@ -0,0 +1,17 @@ +#ifndef GFX_ENHANCEMENT_H +#define GFX_EHHANCEMENT_H + +#include "z64.h" + +typedef struct { + void *tex; + uint16_t width; + uint16_t height; + uint8_t im_fmt; + uint8_t im_siz; +} sprite_t; + +void sprite_load(sprite_t *sprite); +void sprite_draw(sprite_t *sprite, int left, int top, int width, int height); + +#endif diff --git a/soh/soh/Enhancements/randomizer/3drando/category.hpp b/soh/soh/Enhancements/randomizer/3drando/category.hpp new file mode 100644 index 000000000..f49f06edc --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/category.hpp @@ -0,0 +1,71 @@ +#pragma once + +enum class Category { + cNull, + cKokiriForest, + cForest, + cGrotto, + cMinigame, + cChestMinigame, + cLostWoods, + cDekuScrub, + cDekuScrubUpgrades, + cNeedSpiritualStones, + cSacredForestMeadow, + cHyruleField, + cLakeHylia, + cGerudo, + cGerudoValley, + cGerudoFortress, + cHauntedWasteland, + cDesertColossus, + cInnerMarket, + cMarket, + cHyruleCastle, + cKakarikoVillage, + cKakariko, + cSkulltulaHouse, + cGraveyard, + cDeathMountainTrail, + cDeathMountain, + cGoronCity, + cDeathMountainCrater, + cZorasRiver, + cZorasDomain, + cZorasFountain, + cLonLonRanch, + cDekuTree, + cDodongosCavern, + cJabuJabusBelly, + cForestTemple, + cFireTemple, + cWaterTemple, + cSpiritTemple, + cShadowTemple, + cBottomOfTheWell, + cIceCavern, + cGerudoTrainingGrounds, + cGanonsCastle, + cSkulltula, + cBossHeart, + cTempleOfTime, + cFairies, + cOutsideGanonsCastle, + cSong, + cSongDungeonReward, + cCow, + cShop, + cMerchant, + cVanillaSmallKey, + cVanillaGFSmallKey, + cVanillaBossKey, + cVanillaMap, + cVanillaCompass, + cAdultTrade, +}; + +enum class OptionCategory { + Setting, + Cosmetic, + Toggle, +}; diff --git a/soh/soh/Enhancements/randomizer/3drando/cosmetics.cpp b/soh/soh/Enhancements/randomizer/3drando/cosmetics.cpp new file mode 100644 index 000000000..227fb2161 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/cosmetics.cpp @@ -0,0 +1,152 @@ +#include "cosmetics.hpp" +#include "random.hpp" +#include + +namespace Cosmetics { + + bool ValidHexString(std::string_view hexStr) { + return hexStr.find_first_not_of("0123456789ABCDEFabcdef") == std::string_view::npos && hexStr.length() == 6; + } + + Color_RGBAf HexStrToColorRGBAf(const std::string& hexStr) { + uint32_t hex = std::stoi(hexStr, nullptr, 16); + + return Color_RGBAf{ + .r = ((hex & 0xFF0000) >> 16) / 255.0f, + .g = ((hex & 0x00FF00) >> 8) / 255.0f, + .b = (hex & 0x0000FF) / 255.0f, + .a = 1.0f, + }; + } + + Color_RGBA8 HexStrToColorRGBA8(const std::string& hexStr) { + uint32_t hex = std::stoi(hexStr, nullptr, 16); + + return Color_RGBA8{ + .r = (uint8_t)((hex & 0xFF0000) >> 16), + .g = (uint8_t)((hex & 0x00FF00) >> 8), + .b = (uint8_t)(hex & 0x0000FF), + .a = 0xFF, + }; + } + + std::string CustomColorOptionText(std::string_view color) { + return std::string(CUSTOM_COLOR_STR.substr(0, CUSTOM_COLOR_STR.length() - 6)).append(color); + } + + std::string GetCustomColor(const std::string& str) { + return str.substr(str.length() - 6); + } + + const std::array gauntletColors = { + "FFFFFF", //Silver + "FECF0F", //Gold + "000006", //Black + "025918", //Green + "06025A", //Blue + "600602", //Bronze + "FF0000", //Red + "025DB0", //Sky Blue + "FA6A90", //Pink + "FF00FF", //Magenta + "D83A00", //Orange + "5B8A06", //Lime + "800080", //Purple + }; + const std::array tunicColors = { + "168A0E", //Kokiri Green + "96000E", //Goron Red + "002A8E", //Zora Blue + "202020", //Black + "FFFFFF", //White + "FF4A0A", //Orange + "86FF23", //Yellow + "0094B0", //Cyan + "362076", //Indigo + "7B0080", //Purple + "F04F7D", //Pink + "323232", //Dark Gray + "E44B4B", //Salmon + "5A1A20", //Wine Red + "7E705B", //Beige + "583923", //Brown + "72602B", //Sand + "6b7E5D", //Tea Green + "3C5800", //Dark Green + "6CFFF8", //Powder Blue + "005A4B", //Teal + "0259FF", //Sky Blue + "33405E", //Faded Blue + "635AD2", //Lavender + "9C1B4B", //Magenta + "52314F", //Mauve + "505A59", //Silver + "F16F16", //Gold + }; + const std::array naviInnerColors = { + "FFFFFF", //White + "00FF00", //Green + "9696FF", //Light Blue + "FFFF00", //Yellow + "FF0000", //Red + "FF00FF", //Magenta + "FECC3C", //Gold + "000000", //Black + "FFFFFF", //Tatl + "49146C", //Tael + "2C9EC4", //Fi + "E6DE83", //Ciela + "D14902", //Epona + "629C5F", //Ezlo + "A83317", //KoRL + "032660", //Linebeck + "D62E31", //Loftwing + "192426", //Midna + "977A6C", //Phantom Zelda + "FF0000", //Rainbow (starts at red) + }; + const std::array naviOuterColors = { + "0000FF", //White + "00FF00", //Green + "9696FF", //Light Blue + "C89B00", //Yellow + "FF0000", //Red + "C8009B", //Magenta + "FEC007", //Gold + "000000", //Black + "C89800", //Tatl + "FF0000", //Tael + "2C1983", //Fi + "C6BE5B", //Ciela + "551F08", //Epona + "3F5D37", //Ezlo + "DED7C5", //KoRL + "EFFFFF", //Linebeck + "FDE6CC", //Loftwing + "D28330", //Midna + "6F4667", //Phantom Zelda + "FF0000", //Rainbow (starts at red) + }; + const std::array weaponTrailColors = { + "FFFFFF", //White + "000000", //Black + "FF0000", //Red + "00FF00", //Green + "0000FF", //Blue + "FFFF00", //Yellow + "00FFFF", //Cyan + "FF00FF", //Magenta + "FFA500", //Orange + "FFD700", //Gold + "800080", //Purple + "FF69B4", //Pink + "FF0000", //Rainbow (starts at red) + }; + + //Generate random hex color + std::string RandomColor() { + std::ostringstream color; + color << std::hex << (rand() % 0x1000000); //use default rand to not interfere with main settings + return color.str(); + } +} //namespace Cosmetics diff --git a/soh/soh/Enhancements/randomizer/3drando/cosmetics.hpp b/soh/soh/Enhancements/randomizer/3drando/cosmetics.hpp new file mode 100644 index 000000000..6f770f011 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/cosmetics.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include +#include +#include + +namespace Cosmetics { + constexpr std::string_view RANDOM_CHOICE_STR = "Random Choice"; + constexpr std::string_view RANDOM_COLOR_STR = "Random Color"; + constexpr std::string_view CUSTOM_COLOR_STR = "Custom #FFFFFF"; + constexpr std::string_view CUSTOM_COLOR_PREFIX = "Custom #"; + + constexpr std::string_view RANDOM_CHOICE_DESC = "A random color from the list of colors will be\nchosen."; + constexpr std::string_view RANDOM_COLOR_DESC = "A completely random color will be chosen."; + constexpr std::string_view CUSTOM_COLOR_DESC = "Press A and type in a custom 6 digit hex color."; + + enum CosmeticSettings { + RANDOM_CHOICE, + RANDOM_COLOR, + CUSTOM_COLOR, + NON_COLOR_COUNT, + }; + + struct Color_RGBAf { + float r; + float g; + float b; + float a; + }; + + struct Color_RGBA8 { + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; + }; + + extern const std::array gauntletColors; + extern const std::array tunicColors; + extern const std::array naviInnerColors; + extern const std::array naviOuterColors; + extern const std::array weaponTrailColors; + + bool ValidHexString(std::string_view hexStr); + Color_RGBAf HexStrToColorRGBAf(const std::string& hexStr); + Color_RGBA8 HexStrToColorRGBA8(const std::string& hexStr); + std::string CustomColorOptionText(std::string_view color); + std::string GetCustomColor(const std::string& str); + std::string RandomColor(); +} //namespace Cosmetics diff --git a/soh/soh/Enhancements/randomizer/3drando/custom_messages.cpp b/soh/soh/Enhancements/randomizer/3drando/custom_messages.cpp new file mode 100644 index 000000000..e7b2ef7aa --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/custom_messages.cpp @@ -0,0 +1,495 @@ +#include "custom_messages.hpp" +#include "debug.hpp" +#include "shops.hpp" +#include "z64item.h" + +#include +#include +#include + +namespace CustomMessages { + +using namespace std::literals::string_literals; + +class MessageEntryComp { +public: + bool operator()(const MessageEntry& lhs, const MessageEntry& rhs) const { + return lhs.id < rhs.id; + } +}; + +constexpr std::array EnglishDungeonNames = { + "Deku Tree", + "Dodongo's Cavern", + "Jabu Jabu's Belly", + "Forest Temple", + "Fire Temple", + "Water Temple", + "Spirit Temple", + "Shadow Temple", + "Bottom of the Well", + "Ice Cavern", + "Ganon's Tower", + "Gerudo Training Grounds", + "Gerudo Fortress", + "Ganon's Castle", +}; + +constexpr std::array FrenchDungeonNames = { + "Vénérable Arbre Mojo", + "Caverne Dodongo", + "Ventre de Jabu-Jabu", + "Temple de la Forêt", + "Temple du Feu", + "Temple de l'Eau", + "Temple de l'Esprit", + "Temple de l'Ombre", + "Puits", + "Caverne Polaire", + "Tour de Ganon", + "Gymnase Gerudo", + "Repaire des Voleurs", + "Château de Ganon", +}; + +constexpr std::array FrenchDungeonArticles = { + "du ", + "de la ", + "du ", + "du ", + "du ", + "du ", + "du ", + "du ", + "du ", + "de la ", + "", + "du ", + "de la ", + "du ", +}; + +constexpr std::array SpanishDungeonNames = { + "Gran Árbol Deku", + "Cueva de los Dodongos", + "Tripa de Jabu-Jabu", + "Templo del Bosque", + "Templo del Fuego", + "Templo del Agua", + "Templo del Espíritu", + "Templo de las Sombras", + "Fondo del pozo", + "Caverna de hielo", + "Torre de Ganon", + "Centro de Instrucción Gerudo", + "Fortaleza Gerudo", + "Castillo de Ganon", +}; + +constexpr std::array SpanishDungeonArticles = { + "del", + "de la", + "de la", + "del", + "del", + "del", + "del", + "del", + "del", + "de la", + "de la", + "del", + "de la", + "del", +}; + +constexpr std::array DungeonColors = { + QM_GREEN, + QM_RED, + QM_BLUE, + QM_GREEN, + QM_RED, + QM_BLUE, + QM_YELLOW, + QM_PINK, + QM_PINK, + QM_LBLUE, + QM_BLACK, + QM_YELLOW, + QM_YELLOW, + QM_RED, +}; + + std::set messageEntries; + std::vector arrangedMessageEntries; + std::stringstream messageData; + std::string arrangedMessageData; + + //textBoxType and textBoxPosition are defined here: https://wiki.cloudmodding.com/oot/Text_Format#Message_Id + void CreateMessage(uint32_t textId, uint32_t unk_04, uint32_t textBoxType, uint32_t textBoxPosition, + std::string englishText, std::string frenchText, std::string spanishText) { + MessageEntry newEntry = { textId, unk_04, textBoxType, textBoxPosition, { 0 } }; + + while ((englishText.size() % 4) != 0) { + englishText += "\0"s; + } + messageData.seekg(0, messageData.end); + newEntry.info[ENGLISH_U].offset = (char*)((int)messageData.tellg()); + newEntry.info[ENGLISH_U].length = englishText.size(); + messageData << englishText; + + while ((frenchText.size() % 4) != 0) { + frenchText += "\0"s; + } + messageData.seekg(0, messageData.end); + newEntry.info[FRENCH_U].offset = (char*)((int)messageData.tellg()); + newEntry.info[FRENCH_U].length = frenchText.size(); + messageData << frenchText; + + while ((spanishText.size() % 4) != 0) { + spanishText += "\0"s; + } + messageData.seekg(0, messageData.end); + newEntry.info[SPANISH_U].offset = (char*)((int)messageData.tellg()); + newEntry.info[SPANISH_U].length = spanishText.size(); + messageData << spanishText; + + messageEntries.insert(newEntry); + } + + void CreateMessageFromTextObject(uint32_t textId, uint32_t unk_04, uint32_t textBoxType, uint32_t textBoxPosition, const Text& text) { + CreateMessage(textId, unk_04, textBoxType, textBoxPosition, text.GetEnglish(), text.GetFrench(), text.GetSpanish()); + } + + uint32_t NumMessages() { + return messageEntries.size(); + } + + std::pair RawMessageEntryData() { + arrangedMessageEntries.assign(messageEntries.begin(), messageEntries.end()); + const char* data = (const char*)arrangedMessageEntries.data(); + uint32_t size = arrangedMessageEntries.size() * sizeof(MessageEntry); + return { data, size }; + } + + std::pair RawMessageData() { + arrangedMessageData = messageData.str(); + const char* data = arrangedMessageData.data(); + uint32_t size = arrangedMessageData.size(); + return { data, size }; + } + + void CreateAlwaysIncludedMessages() { + // Bombchu (10) Purchase Prompt + CreateMessage(0x8C, 0, 2, 3, + INSTANT_TEXT_ON()+"Bombchu (10): 99 Rupees"+INSTANT_TEXT_OFF()+NEWLINE()+NEWLINE()+TWO_WAY_CHOICE()+COLOR(QM_GREEN)+"Buy"+NEWLINE()+"Don't buy"+COLOR(QM_WHITE)+MESSAGE_END(), + INSTANT_TEXT_ON()+"Bombchus (10): 99 rubis"+INSTANT_TEXT_OFF()+NEWLINE()+NEWLINE()+TWO_WAY_CHOICE()+COLOR(QM_GREEN)+"Acheter"+NEWLINE()+"Ne pas acheter"+COLOR(QM_WHITE)+MESSAGE_END(), + INSTANT_TEXT_ON()+"Bombchus (10): 99 rupias"+INSTANT_TEXT_OFF()+NEWLINE()+NEWLINE()+TWO_WAY_CHOICE()+COLOR(QM_GREEN)+"Comprar"+NEWLINE()+"No comprar"+COLOR(QM_WHITE)+MESSAGE_END()); + //Gold Skulltula Tokens (there are two text IDs the game uses) + for (const uint32_t textId : {0xB4, 0xB5}) { + CreateMessage(textId, 0, 2, 3, + INSTANT_TEXT_ON()+"You destroyed a "+COLOR(QM_RED)+"Gold Skulltula"+COLOR(QM_WHITE)+". You got a"+NEWLINE()+"token proving you destroyed it!"+NEWLINE()+NEWLINE()+"You have "+COLOR(QM_RED)+SKULLTULAS_DESTROYED()+COLOR(QM_WHITE)+" tokens!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + INSTANT_TEXT_ON()+"Vous venez de détruire une "+COLOR(QM_RED)+"Skulltula d'or"+COLOR(QM_WHITE)+"!"+NEWLINE()+"Ce symbole prouve votre prouesse!"+NEWLINE()+NEWLINE()+"Vous avez "+COLOR(QM_RED)+SKULLTULAS_DESTROYED()+COLOR(QM_WHITE)+" jetons!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + INSTANT_TEXT_ON()+"¡Has eliminado una "+COLOR(QM_RED)+"skulltula dorada"+COLOR(QM_WHITE)+" y has"+NEWLINE()+"conseguido un símbolo para probarlo!"+NEWLINE()+NEWLINE()+"¡Tienes "+COLOR(QM_RED)+SKULLTULAS_DESTROYED()+COLOR(QM_WHITE)+" símbolos!"+INSTANT_TEXT_OFF()+MESSAGE_END()); + } + + //Bombchu (10) Description + CreateMessage(0xBC, 0, 2, 3, + INSTANT_TEXT_ON()+COLOR(QM_RED)+"Bombchu (10): 99 Rupees"+NEWLINE()+COLOR(QM_WHITE)+"These look like toy mice, but they're"+NEWLINE()+"actually self-propelled time bombs!"+INSTANT_TEXT_OFF()+SHOP_MESSAGE_BOX()+MESSAGE_END(), + INSTANT_TEXT_ON()+COLOR(QM_RED)+"Bombchus (10): 99 rubis"+NEWLINE()+COLOR(QM_WHITE)+"Profilée comme une souris mécanique, il"+NEWLINE()+"s'agit en fait d'une bombe à retardement"+NEWLINE()+"autopropulsée!"+INSTANT_TEXT_OFF()+SHOP_MESSAGE_BOX()+MESSAGE_END(), + INSTANT_TEXT_ON()+COLOR(QM_RED)+"Bombchus (10): 99 rupias"+NEWLINE()+COLOR(QM_WHITE)+"Aunque parezcan ratoncitos de juguete,"+NEWLINE()+"¡son bombas de relojería autopropulsadas!"+INSTANT_TEXT_OFF()+SHOP_MESSAGE_BOX()+MESSAGE_END()); + //Boss Keys + for (uint32_t bossKey = 0; bossKey <= (DUNGEON_SHADOW_TEMPLE - DUNGEON_FOREST_TEMPLE); bossKey++) { + uint32_t dungeon = DUNGEON_FOREST_TEMPLE + bossKey; + CreateMessage(0x9D4 + bossKey, 0, 2, 3, + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_BOSS)+INSTANT_TEXT_ON()+"You got the "+COLOR(DungeonColors[dungeon])+EnglishDungeonNames[dungeon]+NEWLINE()+"Boss Key"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_BOSS)+INSTANT_TEXT_ON()+"Vous trouvez la "+COLOR(DungeonColors[dungeon])+"Clé d'Or "+NEWLINE()+FrenchDungeonArticles[dungeon]+" "+FrenchDungeonNames[dungeon]+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_BOSS)+INSTANT_TEXT_ON()+"¡Tienes la "+COLOR(DungeonColors[dungeon])+"gran llave "+SpanishDungeonArticles[dungeon]+NEWLINE()+SpanishDungeonNames[dungeon]+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END()); + } + CreateMessage(0x9D9, 0, 2, 3, + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_BOSS)+INSTANT_TEXT_ON()+"You got the "+COLOR(DungeonColors[DUNGEON_GANONS_CASTLE_FIRST_PART])+EnglishDungeonNames[DUNGEON_GANONS_CASTLE_FIRST_PART]+NEWLINE()+"Boss Key"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_BOSS)+INSTANT_TEXT_ON()+"Vous trouvez la "+COLOR(DungeonColors[DUNGEON_GANONS_CASTLE_FIRST_PART])+"Clé d'Or "+NEWLINE()+FrenchDungeonArticles[DUNGEON_GANONS_CASTLE_FIRST_PART]+" "+FrenchDungeonNames[DUNGEON_GANONS_CASTLE_FIRST_PART]+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_BOSS)+INSTANT_TEXT_ON()+"¡Tienes la "+COLOR(DungeonColors[DUNGEON_GANONS_CASTLE_FIRST_PART])+"gran llave "+SpanishDungeonArticles[DUNGEON_GANONS_CASTLE_FIRST_PART]+NEWLINE()+SpanishDungeonNames[DUNGEON_GANONS_CASTLE_FIRST_PART]+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END()); + //Compasses + for (uint32_t dungeon = DUNGEON_DEKU_TREE; dungeon <= DUNGEON_ICE_CAVERN; dungeon++) { + CreateMessage(0x9DA + dungeon, 0, 2, 3, + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_COMPASS)+INSTANT_TEXT_ON()+"You got the "+COLOR(DungeonColors[dungeon])+EnglishDungeonNames[dungeon]+NEWLINE()+"Compass"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_COMPASS)+INSTANT_TEXT_ON()+"Vous trouvez la "+COLOR(DungeonColors[dungeon])+"boussole "+NEWLINE()+FrenchDungeonArticles[dungeon]+FrenchDungeonNames[dungeon]+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_COMPASS)+INSTANT_TEXT_ON()+"¡Tienes la "+COLOR(DungeonColors[dungeon])+"brújula "+SpanishDungeonArticles[dungeon]+NEWLINE()+SpanishDungeonNames[dungeon]+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END()); + } + //Maps + for (uint32_t dungeon = DUNGEON_DEKU_TREE; dungeon <= DUNGEON_ICE_CAVERN; dungeon++) { + CreateMessage(0x9E4 + dungeon, 0, 2, 3, + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_DUNGEON_MAP)+INSTANT_TEXT_ON()+"You got the "+COLOR(DungeonColors[dungeon])+EnglishDungeonNames[dungeon]+NEWLINE()+"Map"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_DUNGEON_MAP)+INSTANT_TEXT_ON()+"Vous trouvez la "+COLOR(DungeonColors[dungeon])+"carte "+NEWLINE()+FrenchDungeonArticles[dungeon]+FrenchDungeonNames[dungeon]+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_DUNGEON_MAP)+INSTANT_TEXT_ON()+"¡Has obtenido el "+COLOR(DungeonColors[dungeon])+"mapa "+SpanishDungeonArticles[dungeon]+NEWLINE()+SpanishDungeonNames[dungeon]+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END()); + } + //Small Keys + for (uint32_t smallKey = 0; smallKey <= (DUNGEON_BOTTOM_OF_THE_WELL - DUNGEON_FOREST_TEMPLE); smallKey++) { + uint32_t dungeon = DUNGEON_FOREST_TEMPLE + smallKey; + CreateMessage(0x9EE + smallKey, 0, 2, 3, + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"You got a "+COLOR(DungeonColors[dungeon])+EnglishDungeonNames[dungeon]+NEWLINE()+"Small Key"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"Vous trouvez une "+COLOR(DungeonColors[dungeon])+"Petite Clé"+NEWLINE()+FrenchDungeonArticles[dungeon]+FrenchDungeonNames[dungeon]+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"¡Has obtenido una "+COLOR(DungeonColors[dungeon])+"llave pequeña "+SpanishDungeonArticles[dungeon]+NEWLINE()+SpanishDungeonNames[dungeon]+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END()); + } + for (uint32_t smallKey = 0; smallKey <= (DUNGEON_GANONS_CASTLE_FIRST_PART - DUNGEON_GERUDO_TRAINING_GROUNDS); smallKey++) { + uint32_t dungeon = DUNGEON_GERUDO_TRAINING_GROUNDS + smallKey; + CreateMessage(0x9F4 + smallKey, 0, 2, 3, + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"You got a "+COLOR(DungeonColors[dungeon])+EnglishDungeonNames[dungeon]+NEWLINE()+"Small Key"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"Vous trouvez une "+COLOR(DungeonColors[dungeon])+"Petite Clé"+NEWLINE()+FrenchDungeonArticles[dungeon]+FrenchDungeonNames[dungeon]+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"¡Has obtenido una "+COLOR(DungeonColors[dungeon])+"llave pequeña "+SpanishDungeonArticles[dungeon]+NEWLINE()+SpanishDungeonNames[dungeon]+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END()); + } + //Key Rings + for (uint32_t smallKey = 0; smallKey <= (DUNGEON_BOTTOM_OF_THE_WELL - DUNGEON_FOREST_TEMPLE); smallKey++) { + uint32_t dungeon = DUNGEON_FOREST_TEMPLE + smallKey; + CreateMessage(0x9300 + smallKey, 0, 2, 3, + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"You got a "+COLOR(DungeonColors[dungeon])+EnglishDungeonNames[dungeon]+NEWLINE()+"Key Ring"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"Vous trouvez un "+COLOR(DungeonColors[dungeon])+"trousseau"+NEWLINE()+FrenchDungeonArticles[dungeon]+FrenchDungeonNames[dungeon]+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"¡Has obtenido un "+COLOR(DungeonColors[dungeon])+"llavero "+SpanishDungeonArticles[dungeon]+NEWLINE()+SpanishDungeonNames[dungeon]+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END()); + } + for (uint32_t smallKey = 0; smallKey <= (DUNGEON_GANONS_CASTLE_FIRST_PART - DUNGEON_GERUDO_TRAINING_GROUNDS); smallKey++) { + uint32_t dungeon = DUNGEON_GERUDO_TRAINING_GROUNDS + smallKey; + CreateMessage(0x9306 + smallKey, 0, 2, 3, + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"You got a "+COLOR(DungeonColors[dungeon])+EnglishDungeonNames[dungeon]+NEWLINE()+"Key Ring"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"Vous trouvez un "+COLOR(DungeonColors[dungeon])+"trousseau"+NEWLINE()+FrenchDungeonArticles[dungeon]+FrenchDungeonNames[dungeon]+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"¡Has obtenido un "+COLOR(DungeonColors[dungeon])+"llavero "+SpanishDungeonArticles[dungeon]+NEWLINE()+SpanishDungeonNames[dungeon]+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END()); + } + //Tycoon's Wallet + CreateMessage(0x09F7, 0, 2, 3, + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_WALLET_GIANT)+INSTANT_TEXT_ON()+"You got a "+COLOR(QM_RED)+"Tycoon's Wallet"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+NEWLINE()+"It's gigantic! Now you can carry"+NEWLINE()+"up to "+COLOR(QM_YELLOW)+"999 "+COLOR(QM_WHITE)+COLOR(QM_YELLOW)+"Rupees"+COLOR(QM_WHITE)+"!"+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_WALLET_GIANT)+INSTANT_TEXT_ON()+"Vous obtenez la "+COLOR(QM_RED)+"Bourse de star"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+NEWLINE()+"Elle peut contenir jusqu'à "+COLOR(QM_YELLOW)+"999 "+COLOR(QM_WHITE)+COLOR(QM_YELLOW)+"rubis"+COLOR(QM_WHITE)+"!"+NEWLINE()+"C'est gigantesque!"+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_WALLET_GIANT)+INSTANT_TEXT_ON()+"¡Has conseguido una "+COLOR(QM_RED)+"bolsa para ricachones"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+NEWLINE()+"¡Qué descomunal! Ya puedes llevar"+NEWLINE()+"hasta "+COLOR(QM_YELLOW)+"999 "+COLOR(QM_WHITE)+COLOR(QM_YELLOW)+"rupias"+COLOR(QM_WHITE)+"!"+MESSAGE_END()); + //Saria's Song Default Hint + CreateMessage(0x0A00, 0, 2, 3, + UNSKIPPABLE()+"Have you tried talking to the gossip"+NEWLINE()+ "stones around Hyrule? They might have"+NEWLINE()+"some good advice... Hee hee!"+WAIT_FOR_INPUT()+"If you learn something from the gossip stones,"+NEWLINE()+"I will remember it!"+EVENT_TRIGGER()+MESSAGE_END(), + UNSKIPPABLE()+"As-tu parlé aux pierres à potins"+NEWLINE()+ "dans Hyrule? Elles sont de bons conseils..."+NEWLINE()+"Hi hi!"+WAIT_FOR_INPUT()+"Si elles te révèlent quelque chose,"+NEWLINE()+"je m'en souviendrai!"+EVENT_TRIGGER()+MESSAGE_END(), + UNSKIPPABLE()+"¿Has probado a consultarle a las"+NEWLINE()+ "piedras chismosas esparcidas por Hyrule? Puede"+NEWLINE()+"que sean de ayuda a tu empresa... ¡Ji, ji!"+WAIT_FOR_INPUT()+"¡Puedo recordarte todo lo que aprendas de ellas,"+NEWLINE()+"si así lo deseas!"+EVENT_TRIGGER()+MESSAGE_END()); + //Poe Collector (when enough has been sold) + CreateMessage(0x70F8, 0, 0, 0, + UNSKIPPABLE()+"Wait a minute! WOW!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"You have earned enough points!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"Young man, you are a genuine "+COLOR(QM_RED)+"ghost hunter"+COLOR(QM_WHITE)+"!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE() + +"Is that what you expected me to say?"+NEWLINE()+"Heh heh heh!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"Because of you, I have extra inventory of"+NEWLINE()+COLOR(QM_RED)+"Big Poes"+COLOR(QM_WHITE)+", so this will be the last time I can"+NEWLINE() + +"buy one of these ghosts."+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"You're thinking about what I promised would"+NEWLINE()+"happen when you earned enough points."+NEWLINE()+"Heh heh."+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE() + +"Don't worry. I didn't forget. Just take this."+MESSAGE_END(), + UNSKIPPABLE()+"Ooooh! WHOA!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"Tu as obtenu suffisamment de points!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"Tu es un véritable "+COLOR(QM_RED)+"chasseur de fantômes"+COLOR(QM_WHITE)+"!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE() + +"Il est content, hein?"+NEWLINE()+"Il est content le monsieur?"+NEWLINE()+"Hé hé hé!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"Grâce à toi, mon stock d'"+COLOR(QM_RED)+"Âmes"+COLOR(QM_WHITE)+" est plein!"+NEWLINE()+"C'est donc la dernière fois que nous"+NEWLINE()+"faisons affaire."+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE() + +"Je sais, je sais..."+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"Nous avions passé un pacte..."+NEWLINE()+"Tu as eu tes points et je t'en félicite..."+NEWLINE()+"Hé hé hé!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE() + +"Alors prends donc ceci, mon bon ami!"+MESSAGE_END(), + UNSKIPPABLE()+"¡Un momento! ¡OYE!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"¡Has conseguido los puntos suficientes!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"¡Jovencito, eres un auténtico "+COLOR(QM_RED)+"cazador de"+NEWLINE()+"fantasmas"+COLOR(QM_WHITE)+"!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE() + +"¿Era eso lo que esperabas que dijera?"+NEWLINE()+"¡Je, je je!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"Gracias a ti, ya tengo la cantidad necesaria"+NEWLINE()+"de "+COLOR(QM_RED)+"grandes poes"+COLOR(QM_WHITE)+", así que esta será la"+NEWLINE() + +"última vez que te compre unos de ese tipo."+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"¿Recuerdas lo que te dije que ocurriría"+NEWLINE()+"cuando tuvieses suficientes puntos?"+NEWLINE()+"Je, je, je."+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE() + +"Tranquilo, que no se me ha olvidado."+NEWLINE()+"Toma esto."+MESSAGE_END()); + //Ice Trap + CreateMessage(0x9002, 0, 2, 3, + UNSKIPPABLE()+INSTANT_TEXT_ON()+CENTER_TEXT()+COLOR(QM_RED)+"FOOL!"+COLOR(QM_WHITE)+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+INSTANT_TEXT_ON()+CENTER_TEXT()+COLOR(QM_RED)+"IDIOT!"+COLOR(QM_WHITE)+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+INSTANT_TEXT_ON()+CENTER_TEXT()+COLOR(QM_RED)+"¡TONTO!"+COLOR(QM_WHITE)+INSTANT_TEXT_OFF()+MESSAGE_END()); + //Business Scrubs + //The less significant byte represents the price of the item + for (uint32_t price = 0; price <= 95; price += 5) { + CreateMessage(0x9000 + price, 0, 0, 0, + INSTANT_TEXT_ON()+"I'll sell you something good for "+COLOR(QM_RED)+std::to_string(price)+" Rupees"+COLOR(QM_WHITE)+"!"+NEWLINE()+NEWLINE()+TWO_WAY_CHOICE()+COLOR(QM_GREEN)+"OK"+NEWLINE()+"No way"+COLOR(QM_WHITE)+INSTANT_TEXT_OFF()+MESSAGE_END(), + INSTANT_TEXT_ON()+"Je te vends un truc super pour "+COLOR(QM_RED)+std::to_string(price)+" Rubis"+COLOR(QM_WHITE)+"!"+NEWLINE()+NEWLINE()+TWO_WAY_CHOICE()+COLOR(QM_GREEN)+"D'accord"+NEWLINE()+"Hors de question"+COLOR(QM_WHITE)+INSTANT_TEXT_OFF()+MESSAGE_END(), + INSTANT_TEXT_ON()+"¡Te puedo vender algo bueno por "+COLOR(QM_RED)+std::to_string(price)+" rupias"+COLOR(QM_WHITE)+"!"+NEWLINE()+NEWLINE()+TWO_WAY_CHOICE()+COLOR(QM_GREEN)+"Vale"+NEWLINE()+"Ni hablar"+COLOR(QM_WHITE)+INSTANT_TEXT_OFF()+MESSAGE_END()); + } + //Poe Collector + //The last digit represent the number of poes needed to collect + for (uint32_t poes = 1; poes <= 10; poes++) { + CreateMessage(0x9080 + poes, 0, 0, 0, + UNSKIPPABLE()+"Oh, you brought a Poe today!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"Hmmmm!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"Very interesting! This is a "+COLOR(QM_RED)+"Big Poe"+COLOR(QM_WHITE)+"!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE() + +"I'll buy it for "+COLOR(QM_RED)+"50 Rupees"+COLOR(QM_WHITE)+"."+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"On top of that, I'll put "+COLOR(QM_RED)+"100 points "+COLOR(QM_WHITE)+"on"+NEWLINE()+"your card."+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE() + +"If you earn "+COLOR(QM_RED)+std::to_string(poes * 100)+" points"+COLOR(QM_WHITE)+", you'll be a"+NEWLINE()+"happy man! Heh heh."+MESSAGE_END(), + + UNSKIPPABLE()+"Oh! Tu as apporté un fantôme!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"Hmmmm!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"Magnifique!"+NEWLINE()+"C'est une "+COLOR(QM_RED)+"Âme"+COLOR(QM_WHITE)+"!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE() + +"Je t'en donne "+COLOR(QM_RED)+"50 Rubis"+COLOR(QM_WHITE)+"."+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"Et en plus, j'inscris "+COLOR(QM_RED)+"100 points "+COLOR(QM_WHITE)+NEWLINE()+"sur ta carte."+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE() + +"Obtiens "+COLOR(QM_RED)+std::to_string(poes * 100)+" points"+COLOR(QM_WHITE)+" et tu ne"+NEWLINE()+"seras pas déçu..."+NEWLINE()+"Hé hé hé."+MESSAGE_END(), + + UNSKIPPABLE()+"¡Vaya! ¡Traes un poe!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"¡Mmm! ¿A ver?"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"¡Qué interesante! ¡Es un "+COLOR(QM_RED)+"gran poe"+COLOR(QM_WHITE)+"!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE() + +"Te daré "+COLOR(QM_RED)+"50 rupias "+COLOR(QM_WHITE)+"por él."+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"Y además agregaré "+COLOR(QM_RED)+"100 puntos "+COLOR(QM_WHITE)+"a tu"+NEWLINE()+"tarjeta."+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE() + +"¡Si llegas a "+COLOR(QM_RED)+std::to_string(poes * 100)+" puntos"+COLOR(QM_WHITE)+", serás muy feliz!"+NEWLINE()+"Je, je, je..."+MESSAGE_END()); + } + + //Talon (this is to prevent accidentally skipping Malon in HC) + CreateMessage(0x9100, 0, 2, 0, + UNSKIPPABLE()+"You should go talk to my daughter Malon,"+NEWLINE()+"she has an item for you."+NEWLINE()+SET_SPEED(3)+"........."+SET_SPEED(0)+WAIT_FOR_INPUT()+"I have to think about some stuff now,"+NEWLINE()+"please don't distract me."+MESSAGE_END(), + UNSKIPPABLE()+"Zzzz... Muh... Malon..."+NEWLINE()+"Parler avec... Malon..."+NEWLINE()+SET_SPEED(3)+"........."+SET_SPEED(0)+WAIT_FOR_INPUT()+"Si fatigué..."+NEWLINE()+"Quelle vie..."+MESSAGE_END(), + UNSKIPPABLE()+"Habla con Malon, tiene algo que darte..."+SET_SPEED(3)+"........."+SET_SPEED(0)+MESSAGE_END()); + + //Bow Shooting Gallery reminder + CreateMessage(0x9140, 0, 0, 0, + UNSKIPPABLE()+"Wonderful! Bravo! Perfect!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"Here's a fantastic present! But I have"+COLOR(QM_RED)+NEWLINE()+"something else "+COLOR(QM_WHITE)+"for you once you have a bow."+SET_SPEED(30)+" "+EVENT_TRIGGER()+MESSAGE_END(), + UNSKIPPABLE()+"Merveilleux! Bravo! C'est parfait!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"Voici un prix fantastique! J'aurai "+COLOR(QM_RED)+"autre chose"+COLOR(QM_WHITE)+NEWLINE()+"pour toi quand tu auras un arc."+SET_SPEED(30)+" "+EVENT_TRIGGER()+MESSAGE_END(), + UNSKIPPABLE()+"¡Espectacular! ¡Bravo! ¡Perfecto!"+WAIT_FOR_INPUT()+NEWLINE()+UNSKIPPABLE()+"¡Toma este sensacional regalo! Pero te tengo"+NEWLINE()+"guardado "+COLOR(QM_RED)+"algo más "+COLOR(QM_WHITE)+"para cuando traigas tu"+NEWLINE()+"propio arco."+SET_SPEED(30)+" "+EVENT_TRIGGER()+MESSAGE_END()); + + //Shopsanity items + //64 textboxes, 2 for each of 32 potential shopsanity items + for(uint32_t shopitems = 0; shopitems < NonShopItems.size(); shopitems++) { + Text name = NonShopItems[shopitems].Name; + std::string price = std::to_string(NonShopItems[shopitems].Price); + //Prevent names from being too long and overflowing textbox + if (name.GetEnglish() == "Piece of Heart (Treasure Chest Minigame)") { + name = Text{"Piece of Heart", "Quart de Coeur", "Pieza de corazón"}; + } else if (name.GetEnglish() == "Green Rupee (Treasure Chest Minigame)") { + name = Text{"Green Rupee", "Rubis Vert", "Rupia verde"}; + } + //Message to display when hovering over the item + if (NonShopItems[shopitems].Repurchaseable) { //Different checkbox for repurchaseable items + CreateMessage(0x9200+shopitems*2, 0, 0, 0, + INSTANT_TEXT_ON()+COLOR(QM_RED)+name.GetEnglish()+": "+price+" Rupees"+NEWLINE()+COLOR(QM_WHITE)+"Special deal!"+NEWLINE()+"Buy as many as you want!"+SHOP_MESSAGE_BOX()+MESSAGE_END(), + INSTANT_TEXT_ON()+COLOR(QM_RED)+name.GetFrench()+": "+price+" rubis"+NEWLINE()+COLOR(QM_WHITE)+"Offre spéciale!"+NEWLINE()+"Achetez-en à volonté!"+SHOP_MESSAGE_BOX()+MESSAGE_END(), + INSTANT_TEXT_ON()+COLOR(QM_RED)+name.GetSpanish()+": "+price+" rupias"+NEWLINE()+COLOR(QM_WHITE)+"¡Oferta especial!"+NEWLINE()+"¡Compra todo lo que quieras!"+SHOP_MESSAGE_BOX()+MESSAGE_END()); + } + else { //Normal textbox + CreateMessage(0x9200+shopitems*2, 0, 0, 0, + INSTANT_TEXT_ON()+COLOR(QM_RED)+name.GetEnglish()+": "+price+" Rupees"+NEWLINE()+COLOR(QM_WHITE)+"Special deal! ONE LEFT!"+NEWLINE()+"Get it while it lasts!"+SHOP_MESSAGE_BOX()+MESSAGE_END(), + INSTANT_TEXT_ON()+COLOR(QM_RED)+name.GetFrench()+": "+price+" rubis"+NEWLINE()+COLOR(QM_WHITE)+"Offre spéciale! DERNIER EN STOCK!"+NEWLINE()+"Faites vite!"+SHOP_MESSAGE_BOX()+MESSAGE_END(), + INSTANT_TEXT_ON()+COLOR(QM_RED)+name.GetSpanish()+": "+price+" rupias"+NEWLINE()+COLOR(QM_WHITE)+"¡Oferta especial! ¡SOLO QUEDA UNA UNIDAD!"+NEWLINE()+"¡Hazte con ella antes de que se agote!"+SHOP_MESSAGE_BOX()+MESSAGE_END()); + } + //Message to display when going to buy the item + CreateMessage(0x9200+shopitems*2+1, 0, 0, 0, + INSTANT_TEXT_ON()+name.GetEnglish()+": "+price+" Rupees"+INSTANT_TEXT_OFF()+NEWLINE()+NEWLINE()+TWO_WAY_CHOICE()+COLOR(QM_GREEN)+"Buy"+NEWLINE()+"Don't buy"+COLOR(QM_WHITE)+INSTANT_TEXT_OFF()+MESSAGE_END(), + INSTANT_TEXT_ON()+name.GetFrench()+": "+price+" rubis"+INSTANT_TEXT_OFF()+NEWLINE()+NEWLINE()+TWO_WAY_CHOICE()+COLOR(QM_GREEN)+"Acheter"+NEWLINE()+"Ne pas acheter"+COLOR(QM_WHITE)+INSTANT_TEXT_OFF()+MESSAGE_END(), + INSTANT_TEXT_ON()+name.GetSpanish()+": "+price+" rupias"+INSTANT_TEXT_OFF()+NEWLINE()+NEWLINE()+TWO_WAY_CHOICE()+COLOR(QM_GREEN)+"Comprar"+NEWLINE()+"No comprar"+COLOR(QM_WHITE)+INSTANT_TEXT_OFF()+MESSAGE_END()); + } + //easter egg + CreateMessage(0x96F, 0, 2, 2, + UNSKIPPABLE()+INSTANT_TEXT_ON()+CENTER_TEXT()+"Oh hey, you watched all the credits!"+NEWLINE()+CENTER_TEXT()+"Here's a prize for your patience."+NEWLINE()+CENTER_TEXT()+"Unlocking MQ and saving..."+NEWLINE()+NEWLINE()+CENTER_TEXT()+COLOR(QM_RED)+"Do not remove the Game Card"+NEWLINE()+CENTER_TEXT()+"or turn the power off."+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+INSTANT_TEXT_ON()+CENTER_TEXT()+"The Legend of Zelda Ocarina of Time 3D"+NEWLINE()+CENTER_TEXT()+"Master Quest va être déverrouillé."+NEWLINE()+CENTER_TEXT()+"Sauvegarde... Veuillez patienter."+NEWLINE()+NEWLINE()+CENTER_TEXT()+COLOR(QM_RED)+"N'éteignez pas la console et"+NEWLINE()+CENTER_TEXT()+"ne retirez pas la carte de jeu"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+INSTANT_TEXT_ON()+CENTER_TEXT()+"Desbloqueando The Legend of Zelda"+NEWLINE()+CENTER_TEXT()+"Ocarina of Time 3D Master Quest."+NEWLINE()+CENTER_TEXT()+"Guardando. Espera un momento..."+NEWLINE()+NEWLINE()+CENTER_TEXT()+COLOR(QM_RED)+"No saques la tarjeta de juego"+NEWLINE()+CENTER_TEXT()+"ni apagues la consola."+INSTANT_TEXT_OFF()+MESSAGE_END()); + CreateMessage(0x970, 0, 2, 3, + UNSKIPPABLE()+INSTANT_TEXT_ON()+CENTER_TEXT()+"Master Quest doesn't affect the Randomizer,"+NEWLINE()+CENTER_TEXT()+"so you can use 3 more save slots now."+NEWLINE()+NEWLINE()+CENTER_TEXT()+"Thanks for playing!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+INSTANT_TEXT_ON()+CENTER_TEXT()+"Vous pouvez désormais jouer à"+NEWLINE()+CENTER_TEXT()+"The Legend of Zelda Ocarina of Time 3D"+NEWLINE()+CENTER_TEXT()+"Master Quest!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+INSTANT_TEXT_ON()+CENTER_TEXT()+"¡Ya puedes jugar The Legend of Zelda"+NEWLINE()+CENTER_TEXT()+"Ocarina of Time 3D Master Quest!"+INSTANT_TEXT_OFF()+MESSAGE_END()); + + //Messages for the new Lake Hylia switch + CreateMessage(0x346, 0, 1, 3, + UNSKIPPABLE()+INSTANT_TEXT_ON()+CENTER_TEXT()+"Water level control system."+NEWLINE()+CENTER_TEXT()+"Keep away!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+INSTANT_TEXT_ON()+CENTER_TEXT()+"Contrôle du niveau d'eau."+NEWLINE()+CENTER_TEXT()+"Ne pas toucher!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+INSTANT_TEXT_ON()+CENTER_TEXT()+"Control del nivel del agua."+NEWLINE()+CENTER_TEXT()+"¡No te acerques!"+INSTANT_TEXT_OFF()+MESSAGE_END()); + CreateMessage(0x1B3, 0, 0, 3, + UNSKIPPABLE()+"This switch is rustier than you think."+WAIT_FOR_INPUT()+"Something must be wrong with the pipe"+NEWLINE()+"system in the Water Temple."+MESSAGE_END(), + UNSKIPPABLE()+"Cet interrupteur est très rouillé."+WAIT_FOR_INPUT()+"Quelque chose ne va pas avec"+NEWLINE()+"la tuyauterie du Temple de l'Eau."+MESSAGE_END(), + UNSKIPPABLE()+"El interruptor está más oxidado de lo que"+NEWLINE()+"aparenta."+WAIT_FOR_INPUT()+"Algo debe andar mal en el sistema de"+NEWLINE()+"cañerías del Templo del Agua."+MESSAGE_END()); + + //Treasure chest shop keys. If they're not randomized leave the base game text + if (Settings::ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_SINGLE_KEYS)) { + CreateMessage(0x0F3, 0, 2, 3, + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"You got a "+COLOR(QM_RED)+"Treasure Chest Shop"+NEWLINE()+"Small Key"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"Vous trouvez une "+COLOR(QM_RED)+"Petite Clé"+NEWLINE()+"de la Chasse-aux-Trésors"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"¡Has obtenido una "+COLOR(QM_RED)+"llave pequeña del"+NEWLINE()+"Cofre del Tesoro"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END()); + } else if (Settings::ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_PACK)) { + CreateMessage(0x0F3, 0, 2, 3, + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"You got all 6 "+COLOR(QM_RED)+"Treasure Chest Shop"+NEWLINE()+"Small Keys"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"Vous trouvez les "+COLOR(QM_RED)+"petites clés"+NEWLINE()+"de la Chasse-aux-Trésors"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END(), + UNSKIPPABLE()+ITEM_OBTAINED(ITEM_KEY_SMALL)+INSTANT_TEXT_ON()+"¡Has obtenido todas las 6 "+COLOR(QM_RED)+"llaves"+NEWLINE()+"pequeñas del Cofre del Tesoro"+COLOR(QM_WHITE)+"!"+INSTANT_TEXT_OFF()+MESSAGE_END()); + } + } + + Text AddColorsAndFormat(Text text, const std::vector& colors /*= {}*/) { + + //for each language + for (std::string* textStr : {&text.english, &text.french, &text.spanish}) { + + //insert playername + size_t atSymbol = textStr->find('@'); + while (atSymbol != std::string::npos) { + textStr->replace(atSymbol, 1, PLAYER_NAME()); + atSymbol = textStr->find('@'); + } + //insert newlines either manually or when encountering a '&' + constexpr size_t lineLength = 44; + size_t lastNewline = 0; + while (lastNewline + lineLength < textStr->length()) { + size_t carrot = textStr->find('^', lastNewline); + size_t ampersand = textStr->find('&', lastNewline); + size_t lastSpace = textStr->rfind(' ', lastNewline + lineLength); + size_t lastPeriod = textStr->rfind('.', lastNewline + lineLength); + //replace '&' first if it's within the newline range + if (ampersand < lastNewline + lineLength) { + textStr->replace(ampersand, 1, NEWLINE()); + lastNewline = ampersand + NEWLINE().length(); + //or move the lastNewline cursor to the next line if a '^' is encountered + } else if (carrot < lastNewline + lineLength) { + lastNewline = carrot + 1; + //some lines need to be split but don't have spaces, look for periods instead + } else if (lastSpace == std::string::npos) { + textStr->replace(lastPeriod, 1, "."+NEWLINE()); + lastNewline = lastPeriod + NEWLINE().length() + 1; + } else { + textStr->replace(lastSpace, 1, NEWLINE()); + lastNewline = lastSpace + NEWLINE().length(); + } + } + //clean up any remaining '&' characters + size_t ampersand = textStr->find('&'); + while (ampersand != std::string::npos) { + textStr->replace(ampersand, 1, NEWLINE()); + ampersand = textStr->find('&'); + } + + //insert box break + size_t carrotSymbol = textStr->find('^'); + while (carrotSymbol != std::string::npos) { + textStr->replace(carrotSymbol, 1, INSTANT_TEXT_OFF()+WAIT_FOR_INPUT()+INSTANT_TEXT_ON()); + carrotSymbol = textStr->find('^'); + } + //add colors + for (auto color : colors) { + size_t firstHashtag = textStr->find('#'); + if (firstHashtag != std::string::npos) { + textStr->replace(firstHashtag, 1, COLOR(color)); + size_t secondHashtag = textStr->find('#'); + if (secondHashtag == std::string::npos) { + CitraPrint("ERROR: Couldn't find second '#' in " + (*textStr)); + } else { + textStr->replace(secondHashtag, 1, COLOR(QM_WHITE)); + } + } + } + } + return Text{"","",""}+UNSKIPPABLE()+INSTANT_TEXT_ON()+text+INSTANT_TEXT_OFF()+MESSAGE_END(); + } + + void ClearMessages() { + messageEntries.clear(); + arrangedMessageEntries.clear(); + messageData.str(""); + arrangedMessageData = ""; + } + + std::string MESSAGE_END() { return "\x7F\x00"s; } + std::string WAIT_FOR_INPUT() { return "\x7F\x01"s; } + std::string HORIZONTAL_SPACE(uint8_t x) { + return "\x7F\x02"s + char(x); + } + std::string GO_TO(uint16_t x) { + return "\x7F\x03"s + char(x >> 8) + char(x & 0x00FF); + } + std::string INSTANT_TEXT_ON() { return "\x7F\x04"s; } + std::string INSTANT_TEXT_OFF() { return "\x7F\x05"s; } + std::string SHOP_MESSAGE_BOX() { return "\x7F\x06\x00"s; } + std::string EVENT_TRIGGER() { return "\x7F\x07"s; } + std::string DELAY_FRAMES(uint8_t x) { + return "\x7F\x08"s + char(x); + } + std::string CLOSE_AFTER(uint8_t x) { + return "\x7F\x0A"s + char(x); + } + std::string PLAYER_NAME() { return "\x7F\x0B"s; } + std::string PLAY_OCARINA() { return "\x7F\x0C"s; } + std::string ITEM_OBTAINED(uint8_t x) { + return "\x7F\x0F"s + char(x); + } + std::string SET_SPEED(uint8_t x) { + return "\x7F\x10"s + char(x); + } + std::string SKULLTULAS_DESTROYED() { return "\x7F\x15"s; } + std::string CURRENT_TIME() { return "\x7F\x17"s; } + std::string UNSKIPPABLE() { return "\x7F\x19"s; } + std::string TWO_WAY_CHOICE() { return "\x7F\x1A\xFF\xFF\xFF\xFF"s; } + std::string NEWLINE() { return "\x7F\x1C"s; } + std::string COLOR(uint8_t x) { return "\x7F\x1D"s + char(x); } + std::string CENTER_TEXT() { return "\x7F\x1E"s; } + std::string IF_NOT_MQ() { return "\x7F\x29"s; } + std::string MQ_ELSE() { return "\x7F\x2A"s; } + std::string MQ_END() { return "\x7F\x2B"s; } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/custom_messages.hpp b/soh/soh/Enhancements/randomizer/3drando/custom_messages.hpp new file mode 100644 index 000000000..2f17b62ef --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/custom_messages.hpp @@ -0,0 +1,93 @@ +#pragma once + +#include +#include +#include + +#include "text.hpp" + +#define QM_WHITE 0x00 +#define QM_RED 0x41 +#define QM_GREEN 0x42 +#define QM_BLUE 0x43 +#define QM_LBLUE 0x44 +#define QM_PINK 0x45 +#define QM_YELLOW 0x46 +#define QM_BLACK 0x47 + +namespace CustomMessages { +typedef struct { + // In the true file format, offset is the offset into the QM file. + // In randomizer, offset will be a pointer to the text in the game's address space. + // Since these pointers will be much larger as u32 than the original script's offsets, + // We will be able to distinguish between original and custom text using their numerical value. + const char* offset; + uint32_t length; +} MessageLanguageInfo; + +typedef enum { + /* 0x00 */ JAPANESE_J, + /* 0x01 */ ENGLISH_U, + /* 0x02 */ ENGLISH_E, + /* 0x03 */ GERMAN_E, + /* 0x04 */ FRENCH_E, + /* 0x05 */ FRENCH_U, + /* 0x06 */ SPANISH_E, + /* 0x07 */ SPANISH_U, + /* 0x08 */ ITALIAN_E, + /* 0x09 */ DUTCH_E, +} MessageLanguage; + +typedef struct { + uint32_t id; + uint32_t unk_04; + uint32_t unk_08; + uint32_t unk_0C; + MessageLanguageInfo info[10]; +} MessageEntry; // size = 0x60 + +typedef struct { + char magic[4]; //"QM\0\0" + uint32_t unk_04; + uint32_t numEntries; + uint32_t unk_0C; +} MessageFileHeader; + + void CreateMessage(uint32_t textId, uint32_t unk_04, uint32_t textBoxType, uint32_t textBoxPosition, + std::string englishText, std::string frenchText, std::string spanishText); + void CreateMessageFromTextObject(uint32_t textId, uint32_t unk_04, uint32_t textBoxType, uint32_t textBoxPosition, const Text& text); + + uint32_t NumMessages(); + + std::pair RawMessageEntryData(); + std::pair RawMessageData(); + + void CreateAlwaysIncludedMessages(); + Text AddColorsAndFormat(Text text, const std::vector& colors = {}); + void ClearMessages(); + + std::string MESSAGE_END(); + std::string WAIT_FOR_INPUT(); + std::string HORIZONTAL_SPACE(uint8_t x); + std::string GO_TO(uint16_t x); + std::string INSTANT_TEXT_ON(); + std::string INSTANT_TEXT_OFF(); + std::string SHOP_MESSAGE_BOX(); + std::string EVENT_TRIGGER(); + std::string DELAY_FRAMES(uint8_t x); + std::string CLOSE_AFTER(uint8_t x); + std::string PLAYER_NAME(); + std::string PLAY_OCARINA(); + std::string ITEM_OBTAINED(uint8_t x); + std::string SET_SPEED(uint8_t x); + std::string SKULLTULAS_DESTROYED(); + std::string CURRENT_TIME(); + std::string UNSKIPPABLE(); + std::string TWO_WAY_CHOICE(); + std::string NEWLINE(); + std::string COLOR(uint8_t x); + std::string CENTER_TEXT(); + std::string IF_NOT_MQ(); + std::string MQ_ELSE(); + std::string MQ_END(); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/debug.cpp b/soh/soh/Enhancements/randomizer/3drando/debug.cpp new file mode 100644 index 000000000..a51181c1e --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/debug.cpp @@ -0,0 +1,5 @@ +#include "debug.hpp" + +void CitraPrint (std::string_view str) { + +} diff --git a/soh/soh/Enhancements/randomizer/3drando/debug.hpp b/soh/soh/Enhancements/randomizer/3drando/debug.hpp new file mode 100644 index 000000000..ebce65e0a --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/debug.hpp @@ -0,0 +1,5 @@ +#pragma once + +#include + +void CitraPrint(std::string_view str); diff --git a/soh/soh/Enhancements/randomizer/3drando/dungeon.cpp b/soh/soh/Enhancements/randomizer/3drando/dungeon.cpp new file mode 100644 index 000000000..4ab26aba0 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/dungeon.cpp @@ -0,0 +1,616 @@ +#include "dungeon.hpp" + +#include "category.hpp" +#include "item_location.hpp" +#include "pool_functions.hpp" +#include "keys.hpp" + +namespace Dungeon { + +DungeonInfo::DungeonInfo(std::string name_, uint32_t map_, uint32_t compass_, uint32_t smallKey_, uint32_t keyRing_, + uint32_t bossKey_, uint8_t vanillaKeyCount_, uint8_t mqKeyCount_, + std::vector vanillaLocations_, + std::vector mqLocations_, + std::vector sharedLocations_) + : name(std::move(name_)), + map(map_), + compass(compass_), + smallKey(smallKey_), + keyRing(keyRing_), + bossKey(bossKey_), + vanillaKeyCount(vanillaKeyCount_), + mqKeyCount(mqKeyCount_), + vanillaLocations(std::move(vanillaLocations_)), + mqLocations(std::move(mqLocations_)), + sharedLocations(std::move(sharedLocations_)) {} + +DungeonInfo::~DungeonInfo() = default; + +uint32_t DungeonInfo::GetSmallKey() const { + return smallKey; +} + +uint32_t DungeonInfo::GetKeyRing() const { + return keyRing; +} + +uint32_t DungeonInfo::GetMap() const { + return map; +} + +uint32_t DungeonInfo::GetCompass() const { + return compass; +} + +uint32_t DungeonInfo::GetBossKey() const { + return bossKey; +} + +void DungeonInfo::PlaceVanillaMap() { + if (map == NONE) { + return; + } + + auto dungeonLocations = GetDungeonLocations(); + auto mapLocation = FilterFromPool(dungeonLocations, [](const uint32_t loc){ return Location(loc)->IsCategory(Category::cVanillaMap); })[0]; + PlaceItemInLocation(mapLocation, map); +} + +void DungeonInfo::PlaceVanillaCompass() { + if (compass == NONE) { + return; + } + + auto dungeonLocations = GetDungeonLocations(); + auto compassLocation = FilterFromPool(dungeonLocations, [](const uint32_t loc){ return Location(loc)->IsCategory(Category::cVanillaCompass); })[0]; + PlaceItemInLocation(compassLocation, compass); +} + +void DungeonInfo::PlaceVanillaBossKey() { + if (bossKey == NONE || bossKey == GANONS_CASTLE_BOSS_KEY) { + return; + } + + auto dungeonLocations = GetDungeonLocations(); + auto bossKeyLocation = FilterFromPool(dungeonLocations, [](const uint32_t loc){ return Location(loc)->IsCategory(Category::cVanillaBossKey); })[0]; + PlaceItemInLocation(bossKeyLocation, bossKey); +} + +void DungeonInfo::PlaceVanillaSmallKeys() { + if (smallKey == NONE) { + return; + } + + auto dungeonLocations = GetDungeonLocations(); + auto smallKeyLocations = FilterFromPool(dungeonLocations, [](const uint32_t loc){ return Location(loc)->IsCategory(Category::cVanillaSmallKey); }); + for (auto location : smallKeyLocations) { + PlaceItemInLocation(location, smallKey); + } +} + +//Gets the chosen dungeon locations for a playthrough (so either MQ or Vanilla) +std::vector DungeonInfo::GetDungeonLocations() const { + auto locations = masterQuest ? mqLocations : vanillaLocations; + AddElementsToPool(locations, sharedLocations); + return locations; +} + +//Gets all dungeon locations (MQ + Vanilla) +std::vector DungeonInfo::GetEveryLocation() const { + auto locations = vanillaLocations; + AddElementsToPool(locations, mqLocations); + AddElementsToPool(locations, sharedLocations); + return locations; +} + + DungeonInfo DekuTree = DungeonInfo("Deku Tree", DEKU_TREE_MAP, DEKU_TREE_COMPASS, NONE, NONE, NONE, 0, 0, { + //Vanilla Locations + DEKU_TREE_MAP_CHEST, + DEKU_TREE_COMPASS_CHEST, + DEKU_TREE_COMPASS_ROOM_SIDE_CHEST, + DEKU_TREE_BASEMENT_CHEST, + DEKU_TREE_SLINGSHOT_CHEST, + DEKU_TREE_SLINGSHOT_ROOM_SIDE_CHEST, + DEKU_TREE_GS_BASEMENT_BACK_ROOM, + DEKU_TREE_GS_BASEMENT_GATE, + DEKU_TREE_GS_BASEMENT_VINES, + DEKU_TREE_GS_COMPASS_ROOM, + }, { + //MQ Locations + DEKU_TREE_MQ_MAP_CHEST, + DEKU_TREE_MQ_COMPASS_CHEST, + DEKU_TREE_MQ_SLINGSHOT_CHEST, + DEKU_TREE_MQ_SLINGSHOT_ROOM_BACK_CHEST, + DEKU_TREE_MQ_BASEMENT_CHEST, + DEKU_TREE_MQ_BEFORE_SPINNING_LOG_CHEST, + DEKU_TREE_MQ_AFTER_SPINNING_LOG_CHEST, + DEKU_TREE_MQ_DEKU_SCRUB, + DEKU_TREE_MQ_GS_LOBBY, + DEKU_TREE_MQ_GS_COMPASS_ROOM, + DEKU_TREE_MQ_GS_BASEMENT_GRAVES_ROOM, + DEKU_TREE_MQ_GS_BASEMENT_BACK_ROOM, + }, { + //Shared Locations + DEKU_TREE_QUEEN_GOHMA_HEART, + QUEEN_GOHMA, + }); + + DungeonInfo DodongosCavern = DungeonInfo("Dodongo's Cavern", DODONGOS_CAVERN_MAP, DODONGOS_CAVERN_COMPASS, NONE, NONE, NONE, 0, 0, { + //Vanilla Locations + DODONGOS_CAVERN_MAP_CHEST, + DODONGOS_CAVERN_COMPASS_CHEST, + DODONGOS_CAVERN_BOMB_FLOWER_PLATFORM_CHEST, + DODONGOS_CAVERN_BOMB_BAG_CHEST, + DODONGOS_CAVERN_END_OF_BRIDGE_CHEST, + DODONGOS_CAVERN_DEKU_SCRUB_LOBBY, + DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS, + DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT, + DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT, + DODONGOS_CAVERN_GS_VINES_ABOVE_STAIRS, + DODONGOS_CAVERN_GS_SCARECROW, + DODONGOS_CAVERN_GS_ALCOVE_ABOVE_STAIRS, + DODONGOS_CAVERN_GS_BACK_ROOM, + DODONGOS_CAVERN_GS_SIDE_ROOM_NEAR_LOWER_LIZALFOS, + }, { + //MQ Locations + DODONGOS_CAVERN_MQ_MAP_CHEST, + DODONGOS_CAVERN_MQ_BOMB_BAG_CHEST, + DODONGOS_CAVERN_MQ_COMPASS_CHEST, + DODONGOS_CAVERN_MQ_LARVAE_ROOM_CHEST, + DODONGOS_CAVERN_MQ_TORCH_PUZZLE_ROOM_CHEST, + DODONGOS_CAVERN_MQ_UNDER_GRAVE_CHEST, + DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR, + DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT, + DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE, + DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS, + DODONGOS_CAVERN_MQ_GS_SCRUB_ROOM, + DODONGOS_CAVERN_MQ_GS_SONG_OF_TIME_BLOCK_ROOM, + DODONGOS_CAVERN_MQ_GS_LIZALFOS_ROOM, + DODONGOS_CAVERN_MQ_GS_LARVAE_ROOM, + DODONGOS_CAVERN_MQ_GS_BACK_AREA, + }, { + //Shared Locations + DODONGOS_CAVERN_BOSS_ROOM_CHEST, + DODONGOS_CAVERN_KING_DODONGO_HEART, + KING_DODONGO, + }); + + DungeonInfo JabuJabusBelly = DungeonInfo("Jabu Jabu's Belly", JABU_JABUS_BELLY_MAP, JABU_JABUS_BELLY_COMPASS, NONE, NONE, NONE, 0, 0, { + //Vanilla Locations + JABU_JABUS_BELLY_MAP_CHEST, + JABU_JABUS_BELLY_COMPASS_CHEST, + JABU_JABUS_BELLY_BOOMERANG_CHEST, + JABU_JABUS_BELLY_DEKU_SCRUB, + JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_LOWER, + JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_UPPER, + JABU_JABUS_BELLY_GS_NEAR_BOSS, + JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM, + }, { + //MQ Locations + JABU_JABUS_BELLY_MQ_FIRST_ROOM_SIDE_CHEST, + JABU_JABUS_BELLY_MQ_MAP_CHEST, + JABU_JABUS_BELLY_MQ_SECOND_ROOM_LOWER_CHEST, + JABU_JABUS_BELLY_MQ_COMPASS_CHEST, + JABU_JABUS_BELLY_MQ_SECOND_ROOM_UPPER_CHEST, + JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_SWITCHES_CHEST, + JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_VINES_CHEST, + JABU_JABUS_BELLY_MQ_NEAR_BOSS_CHEST, + JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_ROOM_CHEST, + JABU_JABUS_BELLY_MQ_BOOMERANG_ROOM_SMALL_CHEST, + JABU_JABUS_BELLY_MQ_BOOMERANG_CHEST, + JABU_JABUS_BELLY_MQ_COW, + JABU_JABUS_BELLY_MQ_GS_TAILPASARAN_ROOM, + JABU_JABUS_BELLY_MQ_GS_INVISIBLE_ENEMIES_ROOM, + JABU_JABUS_BELLY_MQ_GS_BOOMERANG_CHEST_ROOM, + JABU_JABUS_BELLY_MQ_GS_NEAR_BOSS, + }, { + //Shared Locations + JABU_JABUS_BELLY_BARINADE_HEART, + BARINADE, + }); + + DungeonInfo ForestTemple = DungeonInfo("Forest Temple", FOREST_TEMPLE_MAP, FOREST_TEMPLE_COMPASS, FOREST_TEMPLE_SMALL_KEY, FOREST_TEMPLE_KEY_RING, FOREST_TEMPLE_BOSS_KEY, 5, 6, { + //Vanilla Locations + FOREST_TEMPLE_FIRST_ROOM_CHEST, + FOREST_TEMPLE_FIRST_STALFOS_CHEST, + FOREST_TEMPLE_RAISED_ISLAND_COURTYARD_CHEST, + FOREST_TEMPLE_MAP_CHEST, + FOREST_TEMPLE_WELL_CHEST, + FOREST_TEMPLE_FALLING_CEILING_ROOM_CHEST, + FOREST_TEMPLE_EYE_SWITCH_CHEST, + FOREST_TEMPLE_BOSS_KEY_CHEST, + FOREST_TEMPLE_FLOORMASTER_CHEST, + FOREST_TEMPLE_BOW_CHEST, + FOREST_TEMPLE_RED_POE_CHEST, + FOREST_TEMPLE_BLUE_POE_CHEST, + FOREST_TEMPLE_BASEMENT_CHEST, + FOREST_TEMPLE_GS_RAISED_ISLAND_COURTYARD, + FOREST_TEMPLE_GS_FIRST_ROOM, + FOREST_TEMPLE_GS_LEVEL_ISLAND_COURTYARD, + FOREST_TEMPLE_GS_LOBBY, + FOREST_TEMPLE_GS_BASEMENT, + }, { + //MQ Locations + FOREST_TEMPLE_MQ_FIRST_ROOM_CHEST, + FOREST_TEMPLE_MQ_WOLFOS_CHEST, + FOREST_TEMPLE_MQ_BOW_CHEST, + FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_LOWER_CHEST, + FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_UPPER_CHEST, + FOREST_TEMPLE_MQ_WELL_CHEST, + FOREST_TEMPLE_MQ_MAP_CHEST, + FOREST_TEMPLE_MQ_COMPASS_CHEST, + FOREST_TEMPLE_MQ_FALLING_CEILING_ROOM_CHEST, + FOREST_TEMPLE_MQ_BASEMENT_CHEST, + FOREST_TEMPLE_MQ_REDEAD_CHEST, + FOREST_TEMPLE_MQ_BOSS_KEY_CHEST, + FOREST_TEMPLE_MQ_GS_FIRST_HALLWAY, + FOREST_TEMPLE_MQ_GS_BLOCK_PUSH_ROOM, + FOREST_TEMPLE_MQ_GS_RAISED_ISLAND_COURTYARD, + FOREST_TEMPLE_MQ_GS_LEVEL_ISLAND_COURTYARD, + FOREST_TEMPLE_MQ_GS_WELL, + }, { + //Shared Locations + FOREST_TEMPLE_PHANTOM_GANON_HEART, + PHANTOM_GANON, + }); + + DungeonInfo FireTemple = DungeonInfo("Fire Temple", FIRE_TEMPLE_MAP, FIRE_TEMPLE_COMPASS, FIRE_TEMPLE_SMALL_KEY, FIRE_TEMPLE_KEY_RING, FIRE_TEMPLE_BOSS_KEY, 8, 5, { + //Vanilla Locations + FIRE_TEMPLE_NEAR_BOSS_CHEST, + FIRE_TEMPLE_FLARE_DANCER_CHEST, + FIRE_TEMPLE_BOSS_KEY_CHEST, + FIRE_TEMPLE_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST, + FIRE_TEMPLE_BIG_LAVA_ROOM_LOWER_OPEN_DOOR_CHEST, + FIRE_TEMPLE_BOULDER_MAZE_LOWER_CHEST, + FIRE_TEMPLE_BOULDER_MAZE_UPPER_CHEST, + FIRE_TEMPLE_BOULDER_MAZE_SIDE_ROOM_CHEST, + FIRE_TEMPLE_BOULDER_MAZE_SHORTCUT_CHEST, + FIRE_TEMPLE_SCARECROW_CHEST, + FIRE_TEMPLE_MAP_CHEST, + FIRE_TEMPLE_COMPASS_CHEST, + FIRE_TEMPLE_HIGHEST_GORON_CHEST, + FIRE_TEMPLE_MEGATON_HAMMER_CHEST, + FIRE_TEMPLE_GS_SONG_OF_TIME_ROOM, + FIRE_TEMPLE_GS_BOSS_KEY_LOOP, + FIRE_TEMPLE_GS_BOULDER_MAZE, + FIRE_TEMPLE_GS_SCARECROW_TOP, + FIRE_TEMPLE_GS_SCARECROW_CLIMB, + }, { + //MQ Locations + FIRE_TEMPLE_MQ_NEAR_BOSS_CHEST, + FIRE_TEMPLE_MQ_MEGATON_HAMMER_CHEST, + FIRE_TEMPLE_MQ_COMPASS_CHEST, + FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CHEST, + FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CHEST, + FIRE_TEMPLE_MQ_CHEST_ON_FIRE, + FIRE_TEMPLE_MQ_MAP_ROOM_SIDE_CHEST, + FIRE_TEMPLE_MQ_MAP_CHEST, + FIRE_TEMPLE_MQ_BOSS_KEY_CHEST, + FIRE_TEMPLE_MQ_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST, + FIRE_TEMPLE_MQ_LIZALFOS_MAZE_SIDE_ROOM_CHEST, + FIRE_TEMPLE_MQ_FREESTANDING_KEY, + FIRE_TEMPLE_MQ_GS_ABOVE_FIRE_WALL_MAZE, + FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_CENTER, + FIRE_TEMPLE_MQ_GS_BIG_LAVA_ROOM_OPEN_DOOR, + FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_SIDE_ROOM, + FIRE_TEMPLE_MQ_GS_SKULL_ON_FIRE, + }, { + //Shared Locations + FIRE_TEMPLE_VOLVAGIA_HEART, + VOLVAGIA, + }); + + DungeonInfo WaterTemple = DungeonInfo("Water Temple", WATER_TEMPLE_MAP, WATER_TEMPLE_COMPASS, WATER_TEMPLE_SMALL_KEY, WATER_TEMPLE_KEY_RING, WATER_TEMPLE_BOSS_KEY, 6, 2, { + //Vanilla Locations + WATER_TEMPLE_MAP_CHEST, + WATER_TEMPLE_COMPASS_CHEST, + WATER_TEMPLE_TORCHES_CHEST, + WATER_TEMPLE_DRAGON_CHEST, + WATER_TEMPLE_CENTRAL_BOW_TARGET_CHEST, + WATER_TEMPLE_CENTRAL_PILLAR_CHEST, + WATER_TEMPLE_CRACKED_WALL_CHEST, + WATER_TEMPLE_BOSS_KEY_CHEST, + WATER_TEMPLE_LONGSHOT_CHEST, + WATER_TEMPLE_RIVER_CHEST, + WATER_TEMPLE_GS_BEHIND_GATE, + WATER_TEMPLE_GS_FALLING_PLATFORM_ROOM, + WATER_TEMPLE_GS_CENTRAL_PILLAR, + WATER_TEMPLE_GS_NEAR_BOSS_KEY_CHEST, + WATER_TEMPLE_GS_RIVER, + }, { + //MQ Locations + WATER_TEMPLE_MQ_CENTRAL_PILLAR_CHEST, + WATER_TEMPLE_MQ_BOSS_KEY_CHEST, + WATER_TEMPLE_MQ_LONGSHOT_CHEST, + WATER_TEMPLE_MQ_COMPASS_CHEST, + WATER_TEMPLE_MQ_MAP_CHEST, + WATER_TEMPLE_MQ_FREESTANDING_KEY, + WATER_TEMPLE_MQ_GS_BEFORE_UPPER_WATER_SWITCH, + WATER_TEMPLE_MQ_GS_FREESTANDING_KEY_AREA, + WATER_TEMPLE_MQ_GS_LIZALFOS_HALLWAY, + WATER_TEMPLE_MQ_GS_RIVER, + WATER_TEMPLE_MQ_GS_TRIPLE_WALL_TORCH, + }, { + //Shared Locations + WATER_TEMPLE_MORPHA_HEART, + MORPHA, + }); + + DungeonInfo SpiritTemple = DungeonInfo("Spirit Temple", SPIRIT_TEMPLE_MAP, SPIRIT_TEMPLE_COMPASS, SPIRIT_TEMPLE_SMALL_KEY, SPIRIT_TEMPLE_KEY_RING, SPIRIT_TEMPLE_BOSS_KEY, 5, 7, { + //Vanilla Locations + SPIRIT_TEMPLE_CHILD_BRIDGE_CHEST, + SPIRIT_TEMPLE_CHILD_EARLY_TORCHES_CHEST, + SPIRIT_TEMPLE_COMPASS_CHEST, + SPIRIT_TEMPLE_EARLY_ADULT_RIGHT_CHEST, + SPIRIT_TEMPLE_FIRST_MIRROR_LEFT_CHEST, + SPIRIT_TEMPLE_FIRST_MIRROR_RIGHT_CHEST, + SPIRIT_TEMPLE_MAP_CHEST, + SPIRIT_TEMPLE_CHILD_CLIMB_NORTH_CHEST, + SPIRIT_TEMPLE_CHILD_CLIMB_EAST_CHEST, + SPIRIT_TEMPLE_SUN_BLOCK_ROOM_CHEST, + SPIRIT_TEMPLE_STATUE_ROOM_HAND_CHEST, + SPIRIT_TEMPLE_STATUE_ROOM_NORTHEAST_CHEST, + SPIRIT_TEMPLE_NEAR_FOUR_ARMOS_CHEST, + SPIRIT_TEMPLE_HALLWAY_LEFT_INVISIBLE_CHEST, + SPIRIT_TEMPLE_HALLWAY_RIGHT_INVISIBLE_CHEST, + SPIRIT_TEMPLE_BOSS_KEY_CHEST, + SPIRIT_TEMPLE_TOPMOST_CHEST, + SPIRIT_TEMPLE_GS_HALL_AFTER_SUN_BLOCK_ROOM, + SPIRIT_TEMPLE_GS_BOULDER_ROOM, + SPIRIT_TEMPLE_GS_LOBBY, + SPIRIT_TEMPLE_GS_SUN_ON_FLOOR_ROOM, + SPIRIT_TEMPLE_GS_METAL_FENCE, + }, { + //MQ Locations + SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_LEFT_CHEST, + SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_RIGHT_CHEST, + SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_RIGHT_CHEST, + SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_LEFT_CHEST, + SPIRIT_TEMPLE_MQ_CHILD_HAMMER_SWITCH_CHEST, + SPIRIT_TEMPLE_MQ_MAP_CHEST, + SPIRIT_TEMPLE_MQ_MAP_ROOM_ENEMY_CHEST, + SPIRIT_TEMPLE_MQ_CHILD_CLIMB_NORTH_CHEST, + SPIRIT_TEMPLE_MQ_CHILD_CLIMB_SOUTH_CHEST, + SPIRIT_TEMPLE_MQ_COMPASS_CHEST, + SPIRIT_TEMPLE_MQ_STATUE_ROOM_LULLABY_CHEST, + SPIRIT_TEMPLE_MQ_STATUE_ROOM_INVISIBLE_CHEST, + SPIRIT_TEMPLE_MQ_SILVER_BLOCK_HALLWAY_CHEST, + SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM_CHEST, + SPIRIT_TEMPLE_MQ_SYMPHONY_ROOM_CHEST, + SPIRIT_TEMPLE_MQ_LEEVER_ROOM_CHEST, + SPIRIT_TEMPLE_MQ_BEAMOS_ROOM_CHEST, + SPIRIT_TEMPLE_MQ_CHEST_SWITCH_CHEST, + SPIRIT_TEMPLE_MQ_BOSS_KEY_CHEST, + SPIRIT_TEMPLE_MQ_MIRROR_PUZZLE_INVISIBLE_CHEST, + SPIRIT_TEMPLE_MQ_GS_SYMPHONY_ROOM, + SPIRIT_TEMPLE_MQ_GS_LEEVER_ROOM, + SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_WEST, + SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_NORTH, + SPIRIT_TEMPLE_MQ_GS_SUN_BLOCK_ROOM, + }, { + //Shared Locations + SPIRIT_TEMPLE_SILVER_GAUNTLETS_CHEST, + SPIRIT_TEMPLE_MIRROR_SHIELD_CHEST, + SPIRIT_TEMPLE_TWINROVA_HEART, + TWINROVA, + }); + + DungeonInfo ShadowTemple = DungeonInfo("Shadow Temple", SHADOW_TEMPLE_MAP, SHADOW_TEMPLE_COMPASS, SHADOW_TEMPLE_SMALL_KEY, SHADOW_TEMPLE_KEY_RING, SHADOW_TEMPLE_BOSS_KEY, 5, 6, { + //Vanilla Locations + SHADOW_TEMPLE_MAP_CHEST, + SHADOW_TEMPLE_HOVER_BOOTS_CHEST, + SHADOW_TEMPLE_COMPASS_CHEST, + SHADOW_TEMPLE_EARLY_SILVER_RUPEE_CHEST, + SHADOW_TEMPLE_INVISIBLE_BLADES_VISIBLE_CHEST, + SHADOW_TEMPLE_INVISIBLE_BLADES_INVISIBLE_CHEST, + SHADOW_TEMPLE_FALLING_SPIKES_LOWER_CHEST, + SHADOW_TEMPLE_FALLING_SPIKES_UPPER_CHEST, + SHADOW_TEMPLE_FALLING_SPIKES_SWITCH_CHEST, + SHADOW_TEMPLE_INVISIBLE_SPIKES_CHEST, + SHADOW_TEMPLE_WIND_HINT_CHEST, + SHADOW_TEMPLE_AFTER_WIND_ENEMY_CHEST, + SHADOW_TEMPLE_AFTER_WIND_HIDDEN_CHEST, + SHADOW_TEMPLE_SPIKE_WALLS_LEFT_CHEST, + SHADOW_TEMPLE_BOSS_KEY_CHEST, + SHADOW_TEMPLE_INVISIBLE_FLOORMASTER_CHEST, + SHADOW_TEMPLE_FREESTANDING_KEY, + SHADOW_TEMPLE_GS_SINGLE_GIANT_POT, + SHADOW_TEMPLE_GS_FALLING_SPIKES_ROOM, + SHADOW_TEMPLE_GS_TRIPLE_GIANT_POT, + SHADOW_TEMPLE_GS_LIKE_LIKE_ROOM, + SHADOW_TEMPLE_GS_NEAR_SHIP, + }, { + //MQ Locations + SHADOW_TEMPLE_MQ_COMPASS_CHEST, + SHADOW_TEMPLE_MQ_HOVER_BOOTS_CHEST, + SHADOW_TEMPLE_MQ_EARLY_GIBDOS_CHEST, + SHADOW_TEMPLE_MQ_MAP_CHEST, + SHADOW_TEMPLE_MQ_BEAMOS_SILVER_RUPEES_CHEST, + SHADOW_TEMPLE_MQ_FALLING_SPIKES_SWITCH_CHEST, + SHADOW_TEMPLE_MQ_FALLING_SPIKES_LOWER_CHEST, + SHADOW_TEMPLE_MQ_FALLING_SPIKES_UPPER_CHEST, + SHADOW_TEMPLE_MQ_INVISIBLE_SPIKES_CHEST, + SHADOW_TEMPLE_MQ_BOSS_KEY_CHEST, + SHADOW_TEMPLE_MQ_SPIKE_WALLS_LEFT_CHEST, + SHADOW_TEMPLE_MQ_STALFOS_ROOM_CHEST, + SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_INVISIBLE_CHEST, + SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_VISIBLE_CHEST, + SHADOW_TEMPLE_MQ_BOMB_FLOWER_CHEST, + SHADOW_TEMPLE_MQ_WIND_HINT_CHEST, + SHADOW_TEMPLE_MQ_AFTER_WIND_HIDDEN_CHEST, + SHADOW_TEMPLE_MQ_AFTER_WIND_ENEMY_CHEST, + SHADOW_TEMPLE_MQ_NEAR_SHIP_INVISIBLE_CHEST, + SHADOW_TEMPLE_MQ_FREESTANDING_KEY, + SHADOW_TEMPLE_MQ_GS_FALLING_SPIKES_ROOM, + SHADOW_TEMPLE_MQ_GS_WIND_HINT_ROOM, + SHADOW_TEMPLE_MQ_GS_AFTER_WIND, + SHADOW_TEMPLE_MQ_GS_AFTER_SHIP, + SHADOW_TEMPLE_MQ_GS_NEAR_BOSS, + }, { + //Shared Locations + SHADOW_TEMPLE_BONGO_BONGO_HEART, + BONGO_BONGO, + }); + + DungeonInfo BottomOfTheWell = DungeonInfo("Bottom of the Well", BOTTOM_OF_THE_WELL_MAP, BOTTOM_OF_THE_WELL_COMPASS, BOTTOM_OF_THE_WELL_SMALL_KEY, BOTTOM_OF_THE_WELL_KEY_RING, NONE, 3, 2, { + //Vanilla Locations + BOTTOM_OF_THE_WELL_FRONT_LEFT_FAKE_WALL_CHEST, + BOTTOM_OF_THE_WELL_FRONT_CENTER_BOMBABLE_CHEST, + BOTTOM_OF_THE_WELL_RIGHT_BOTTOM_FAKE_WALL_CHEST, + BOTTOM_OF_THE_WELL_COMPASS_CHEST, + BOTTOM_OF_THE_WELL_CENTER_SKULLTULA_CHEST, + BOTTOM_OF_THE_WELL_BACK_LEFT_BOMBABLE_CHEST, + BOTTOM_OF_THE_WELL_LENS_OF_TRUTH_CHEST, + BOTTOM_OF_THE_WELL_INVISIBLE_CHEST, + BOTTOM_OF_THE_WELL_UNDERWATER_FRONT_CHEST, + BOTTOM_OF_THE_WELL_UNDERWATER_LEFT_CHEST, + BOTTOM_OF_THE_WELL_MAP_CHEST, + BOTTOM_OF_THE_WELL_FIRE_KEESE_CHEST, + BOTTOM_OF_THE_WELL_LIKE_LIKE_CHEST, + BOTTOM_OF_THE_WELL_FREESTANDING_KEY, + BOTTOM_OF_THE_WELL_GS_LIKE_LIKE_CAGE, + BOTTOM_OF_THE_WELL_GS_EAST_INNER_ROOM, + BOTTOM_OF_THE_WELL_GS_WEST_INNER_ROOM, + }, { + //MQ Locations + BOTTOM_OF_THE_WELL_MQ_MAP_CHEST, + BOTTOM_OF_THE_WELL_MQ_LENS_OF_TRUTH_CHEST, + BOTTOM_OF_THE_WELL_MQ_COMPASS_CHEST, + BOTTOM_OF_THE_WELL_MQ_DEAD_HAND_FREESTANDING_KEY, + BOTTOM_OF_THE_WELL_MQ_EAST_INNER_ROOM_FREESTANDING_KEY, + BOTTOM_OF_THE_WELL_MQ_GS_BASEMENT, + BOTTOM_OF_THE_WELL_MQ_GS_COFFIN_ROOM, + BOTTOM_OF_THE_WELL_MQ_GS_WEST_INNER_ROOM, + }, {}); + + DungeonInfo IceCavern = DungeonInfo("Ice Cavern", ICE_CAVERN_MAP, ICE_CAVERN_COMPASS, NONE, NONE, NONE, 0, 0, { + //Vanilla Locations + ICE_CAVERN_MAP_CHEST, + ICE_CAVERN_COMPASS_CHEST, + ICE_CAVERN_IRON_BOOTS_CHEST, + ICE_CAVERN_FREESTANDING_POH, + ICE_CAVERN_GS_PUSH_BLOCK_ROOM, + ICE_CAVERN_GS_SPINNING_SCYTHE_ROOM, + ICE_CAVERN_GS_HEART_PIECE_ROOM, + }, { + //MQ Locations + ICE_CAVERN_MQ_IRON_BOOTS_CHEST, + ICE_CAVERN_MQ_COMPASS_CHEST, + ICE_CAVERN_MQ_MAP_CHEST, + ICE_CAVERN_MQ_FREESTANDING_POH, + ICE_CAVERN_MQ_GS_SCARECROW, + ICE_CAVERN_MQ_GS_ICE_BLOCK, + ICE_CAVERN_MQ_GS_RED_ICE, + }, { + //Shared Locations + SHEIK_IN_ICE_CAVERN, + }); + + DungeonInfo GerudoTrainingGrounds = DungeonInfo("Gerudo Training Grounds", NONE, NONE, GERUDO_TRAINING_GROUNDS_SMALL_KEY, GERUDO_TRAINING_GROUNDS_KEY_RING, NONE, 9, 3, { + //Vanilla Locations + GERUDO_TRAINING_GROUNDS_LOBBY_LEFT_CHEST, + GERUDO_TRAINING_GROUNDS_LOBBY_RIGHT_CHEST, + GERUDO_TRAINING_GROUNDS_STALFOS_CHEST, + GERUDO_TRAINING_GROUNDS_BEAMOS_CHEST, + GERUDO_TRAINING_GROUNDS_HIDDEN_CEILING_CHEST, + GERUDO_TRAINING_GROUNDS_MAZE_PATH_FIRST_CHEST, + GERUDO_TRAINING_GROUNDS_MAZE_PATH_SECOND_CHEST, + GERUDO_TRAINING_GROUNDS_MAZE_PATH_THIRD_CHEST, + GERUDO_TRAINING_GROUNDS_MAZE_PATH_FINAL_CHEST, + GERUDO_TRAINING_GROUNDS_MAZE_RIGHT_CENTRAL_CHEST, + GERUDO_TRAINING_GROUNDS_MAZE_RIGHT_SIDE_CHEST, + GERUDO_TRAINING_GROUNDS_UNDERWATER_SILVER_RUPEE_CHEST, + GERUDO_TRAINING_GROUNDS_HAMMER_ROOM_CLEAR_CHEST, + GERUDO_TRAINING_GROUNDS_HAMMER_ROOM_SWITCH_CHEST, + GERUDO_TRAINING_GROUNDS_EYE_STATUE_CHEST, + GERUDO_TRAINING_GROUNDS_NEAR_SCARECROW_CHEST, + GERUDO_TRAINING_GROUNDS_BEFORE_HEAVY_BLOCK_CHEST, + GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_FIRST_CHEST, + GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_SECOND_CHEST, + GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_THIRD_CHEST, + GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_FOURTH_CHEST, + GERUDO_TRAINING_GROUNDS_FREESTANDING_KEY, + }, { + //MQ Locations + GERUDO_TRAINING_GROUNDS_MQ_LOBBY_RIGHT_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_LOBBY_LEFT_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_FIRST_IRON_KNUCKLE_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_BEFORE_HEAVY_BLOCK_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_EYE_STATUE_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_FLAME_CIRCLE_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_SECOND_IRON_KNUCKLE_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_DINOLFOS_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_ICE_ARROWS_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_MAZE_RIGHT_CENTRAL_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_FIRST_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_MAZE_RIGHT_SIDE_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_THIRD_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_SECOND_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_HIDDEN_CEILING_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER_SILVER_RUPEE_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_HEAVY_BLOCK_CHEST, + }, {}); + + DungeonInfo GanonsCastle = DungeonInfo("Ganon's Castle", NONE, NONE, GANONS_CASTLE_SMALL_KEY, GANONS_CASTLE_KEY_RING, GANONS_CASTLE_BOSS_KEY, 2, 3, { + //Vanilla Locations + GANONS_CASTLE_FOREST_TRIAL_CHEST, + GANONS_CASTLE_WATER_TRIAL_LEFT_CHEST, + GANONS_CASTLE_WATER_TRIAL_RIGHT_CHEST, + GANONS_CASTLE_SHADOW_TRIAL_FRONT_CHEST, + GANONS_CASTLE_SHADOW_TRIAL_GOLDEN_GAUNTLETS_CHEST, + GANONS_CASTLE_SPIRIT_TRIAL_CRYSTAL_SWITCH_CHEST, + GANONS_CASTLE_SPIRIT_TRIAL_INVISIBLE_CHEST, + GANONS_CASTLE_LIGHT_TRIAL_FIRST_LEFT_CHEST, + GANONS_CASTLE_LIGHT_TRIAL_SECOND_LEFT_CHEST, + GANONS_CASTLE_LIGHT_TRIAL_THIRD_LEFT_CHEST, + GANONS_CASTLE_LIGHT_TRIAL_FIRST_RIGHT_CHEST, + GANONS_CASTLE_LIGHT_TRIAL_SECOND_RIGHT_CHEST, + GANONS_CASTLE_LIGHT_TRIAL_THIRD_RIGHT_CHEST, + GANONS_CASTLE_LIGHT_TRIAL_INVISIBLE_ENEMIES_CHEST, + GANONS_CASTLE_LIGHT_TRIAL_LULLABY_CHEST, + GANONS_CASTLE_DEKU_SCRUB_LEFT, + GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT, + GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT, + GANONS_CASTLE_DEKU_SCRUB_RIGHT, + }, { + //MQ Locations + GANONS_CASTLE_MQ_WATER_TRIAL_CHEST, + GANONS_CASTLE_MQ_FOREST_TRIAL_EYE_SWITCH_CHEST, + GANONS_CASTLE_MQ_FOREST_TRIAL_FROZEN_EYE_SWITCH_CHEST, + GANONS_CASTLE_MQ_LIGHT_TRIAL_LULLABY_CHEST, + GANONS_CASTLE_MQ_SHADOW_TRIAL_BOMB_FLOWER_CHEST, + GANONS_CASTLE_MQ_SHADOW_TRIAL_EYE_SWITCH_CHEST, + GANONS_CASTLE_MQ_SPIRIT_TRIAL_GOLDEN_GAUNTLETS_CHEST, + GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_RIGHT_CHEST, + GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_LEFT_CHEST, + GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_FRONT_LEFT_CHEST, + GANONS_CASTLE_MQ_SPIRIT_TRIAL_FIRST_CHEST, + GANONS_CASTLE_MQ_SPIRIT_TRIAL_INVISIBLE_CHEST, + GANONS_CASTLE_MQ_FOREST_TRIAL_FREESTANDING_KEY, + GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT, + GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT, + GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER, + GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT, + GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT, + }, { + //Shared Locations + GANONS_TOWER_BOSS_KEY_CHEST, + GANON, + }); + + const DungeonArray dungeonList = { + &DekuTree, + &DodongosCavern, + &JabuJabusBelly, + &ForestTemple, + &FireTemple, + &WaterTemple, + &SpiritTemple, + &ShadowTemple, + &BottomOfTheWell, + &IceCavern, + &GerudoTrainingGrounds, + &GanonsCastle, + }; + +} //namespace Dungeon diff --git a/soh/soh/Enhancements/randomizer/3drando/dungeon.hpp b/soh/soh/Enhancements/randomizer/3drando/dungeon.hpp new file mode 100644 index 000000000..dad3cc938 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/dungeon.hpp @@ -0,0 +1,104 @@ +#pragma once + +#include +#include +#include + +#include "keys.hpp" + +namespace Dungeon { +class DungeonInfo { +public: + DungeonInfo(std::string name_, uint32_t map_, uint32_t compass_, uint32_t smallKey_, uint32_t keyRing_, uint32_t bossKey_, + uint8_t vanillaKeyCount_, uint8_t mqKeyCount_, + std::vector vanillaLocations_, + std::vector mqLocations_, + std::vector sharedLocations_); + ~DungeonInfo(); + + const std::string& GetName() const { + return name; + } + + void SetMQ() { + masterQuest = true; + } + + void ClearMQ() { + masterQuest = false; + } + + bool IsMQ() const { + return masterQuest; + } + + void SetKeyRing() { + hasKeyRing = true; + } + + void ClearKeyRing() { + hasKeyRing = false; + } + + bool HasKeyRing() const { + return hasKeyRing; + } + + bool IsVanilla() const { + return !masterQuest; + } + + uint8_t GetSmallKeyCount() const { + return (masterQuest) ? mqKeyCount : vanillaKeyCount; + } + + uint32_t GetSmallKey() const; + uint32_t GetKeyRing() const; + uint32_t GetMap() const; + uint32_t GetCompass() const; + uint32_t GetBossKey() const; + + void PlaceVanillaMap(); + void PlaceVanillaCompass(); + void PlaceVanillaBossKey(); + void PlaceVanillaSmallKeys(); + + // Gets the chosen dungeon locations for a playthrough (so either MQ or Vanilla) + std::vector GetDungeonLocations() const; + + // Gets all dungeon locations (MQ + Vanilla) + std::vector GetEveryLocation() const; + +private: + std::string name; + uint32_t map; + uint32_t compass; + uint32_t smallKey; + uint32_t keyRing; + uint32_t bossKey; + uint8_t vanillaKeyCount; + uint8_t mqKeyCount; + bool masterQuest = false; + bool hasKeyRing = false; + std::vector vanillaLocations; + std::vector mqLocations; + std::vector sharedLocations; +}; + +extern DungeonInfo DekuTree; +extern DungeonInfo DodongosCavern; +extern DungeonInfo JabuJabusBelly; +extern DungeonInfo ForestTemple; +extern DungeonInfo FireTemple; +extern DungeonInfo WaterTemple; +extern DungeonInfo SpiritTemple; +extern DungeonInfo ShadowTemple; +extern DungeonInfo BottomOfTheWell; +extern DungeonInfo IceCavern; +extern DungeonInfo GerudoTrainingGrounds; +extern DungeonInfo GanonsCastle; + +using DungeonArray = std::array; + +extern const DungeonArray dungeonList; +} // namespace Dungeon diff --git a/soh/soh/Enhancements/randomizer/3drando/entrance.cpp b/soh/soh/Enhancements/randomizer/3drando/entrance.cpp new file mode 100644 index 000000000..51be29bdf --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/entrance.cpp @@ -0,0 +1,877 @@ +#include "entrance.hpp" + +#include "fill.hpp" +#include "settings.hpp" +#include "item_list.hpp" +#include "item_pool.hpp" +#include "item_location.hpp" +#include "debug.hpp" +#include "spoiler_log.hpp" +#include "hints.hpp" +#include "location_access.hpp" + +#include +#include +#include +#include +#include + +std::list entranceOverrides = {}; +bool noRandomEntrances = false; +static bool entranceShuffleFailure = false; +static int totalRandomizableEntrances = 0; +static int curNumRandomizedEntrances = 0; + +typedef struct { + EntranceType type; + uint32_t parentRegion; + uint32_t connectedRegion; + int16_t index; + int16_t blueWarp; +} EntranceLinkInfo; + //primary, secondary +using EntranceInfoPair = std::pair; +using EntrancePair = std::pair; + +//The entrance randomization algorithm used here is a direct copy of +//the algorithm used in the original N64 randomizer (except now in C++ instead +//of python). It may be easier to understand the algorithm by looking at the +//base randomizer's code instead: +// https://github.com/TestRunnerSRL/OoT-Randomizer/blob/Dev/EntranceShuffle.py + +// Updates the user on how many entrances are currently shuffled +static void DisplayEntranceProgress() { + std::string dots = "."; + float progress = (float)curNumRandomizedEntrances / (float)totalRandomizableEntrances; + if (progress > 0.33) { + dots += "."; + } else { + dots += " "; + } + if (progress > 0.66) { + dots += "."; + } else { + dots += " "; + } + printf("\x1b[7;29H%s", dots.c_str()); + #ifdef ENABLE_DEBUG + if (curNumRandomizedEntrances == totalRandomizableEntrances) { + Areas::DumpWorldGraph("Finish Validation"); + } + #endif +} + +void SetAllEntrancesData(std::vector& entranceShuffleTable) { + for (auto& entrancePair: entranceShuffleTable) { + + auto& forwardEntry = entrancePair.first; + auto& returnEntry = entrancePair.second; + + //set data + Entrance* forwardEntrance = AreaTable(forwardEntry.parentRegion)->GetExit(forwardEntry.connectedRegion); + forwardEntrance->SetIndex(forwardEntry.index); + forwardEntrance->SetBlueWarp(forwardEntry.blueWarp); + forwardEntrance->SetType(forwardEntry.type); + forwardEntrance->SetAsPrimary(); + // if type == 'Grotto': + // forward_entrance.data['index'] = 0x0700 + forward_entrance.data['grotto_id'] + if (returnEntry.parentRegion != NONE) { + Entrance* returnEntrance = AreaTable(returnEntry.parentRegion)->GetExit(returnEntry.connectedRegion); + returnEntrance->SetIndex(returnEntry.index); + returnEntrance->SetBlueWarp(returnEntry.blueWarp); + returnEntrance->SetType(returnEntry.type); + forwardEntrance->BindTwoWay(returnEntrance); + // if type == 'Grotto': + // return_entrance.data['index'] = 0x0800 + return_entrance.data['grotto_id'] + } + } +} + +static std::vector AssumeEntrancePool(std::vector& entrancePool) { + std::vector assumedPool = {}; + for (Entrance* entrance : entrancePool) { + Entrance* assumedForward = entrance->AssumeReachable(); + if (entrance->GetReverse() != nullptr /*&& entrances are not decoupled*/) { + Entrance* assumedReturn = entrance->GetReverse()->AssumeReachable(); + //mixed pool assumption stuff + assumedForward->BindTwoWay(assumedReturn); + } + assumedPool.push_back(assumedForward); + } + return assumedPool; +} + +//returns restrictive entrances and soft entrances in an array of size 2 (restrictive vector is index 0, soft is index 1) +static std::array, 2> SplitEntrancesByRequirements(std::vector& entrancesToSplit, std::vector& assumedEntrances) { + //First, disconnect all root assumed entrances and save which regions they were originally connected to, so we can reconnect them later + std::map originalConnectedRegions = {}; + std::set entrancesToDisconnect = {}; + for (Entrance* entrance : assumedEntrances) { + entrancesToDisconnect.insert(entrance); + if (entrance->GetReverse() != nullptr) { + entrancesToDisconnect.insert(entrance->GetReverse()); + } + } + + //disconnect each entrance temporarily to find restrictive vs soft entrances + //soft entrances are ones that can be accessed by both ages (child/adult) at both times of day (day/night) + //restrictive entrances are ones that do not meet this criteria + for (Entrance* entrance : entrancesToDisconnect) { + if (entrance->GetConnectedRegionKey() != NONE) { + originalConnectedRegions[entrance] = entrance->Disconnect(); + } + } + + std::vector restrictiveEntrances = {}; + std::vector softEntrances = {}; + + Logic::LogicReset(); + // //Apply the effects of all advancement items to search for entrance accessibility + std::vector items = FilterFromPool(ItemPool, [](const auto i){ return ItemTable(i).IsAdvancement();}); + for (uint32_t unplacedItem : items) { + ItemTable(unplacedItem).ApplyEffect(); + } + // run a search to see what's accessible + GetAccessibleLocations({}); + + for (Entrance* entrance : entrancesToSplit) { + // if an entrance is accessible at all times of day by both ages, it's a soft entrance with no restrictions + if (entrance->ConditionsMet(true)) { + softEntrances.push_back(entrance); + } else { + restrictiveEntrances.push_back(entrance); + } + } + + //Reconnect all disconnected entrances + for (Entrance* entrance : entrancesToDisconnect) { + entrance->Connect(originalConnectedRegions[entrance]); + } + + return {restrictiveEntrances, softEntrances}; +} + +static bool AreEntrancesCompatible(Entrance* entrance, Entrance* target, std::vector& rollbacks) { + + //Entrances shouldn't connect to their own scene, fail in this situation + if (entrance->GetParentRegion()->scene != "" && entrance->GetParentRegion()->scene == target->GetConnectedRegion()->scene) { + auto message = "Entrance " + entrance->GetName() + " attempted to connect with own scene target " + target->to_string() + ". Connection failed.\n"; + SPDLOG_INFO(message); + return false; + } + + //one-way entrance stuff + + return true; +} + +//Change connections between an entrance and a target assumed entrance, in order to test the connections afterwards if necessary +static void ChangeConnections(Entrance* entrance, Entrance* targetEntrance) { + auto message = "Attempting to connect " + entrance->GetName() + " to " + targetEntrance->to_string() + "\n"; + SPDLOG_INFO(message); + entrance->Connect(targetEntrance->Disconnect()); + entrance->SetReplacement(targetEntrance->GetReplacement()); + if (entrance->GetReverse() != nullptr /*&& entrances aren't decoupled*/) { + targetEntrance->GetReplacement()->GetReverse()->Connect(entrance->GetReverse()->GetAssumed()->Disconnect()); + targetEntrance->GetReplacement()->GetReverse()->SetReplacement(entrance->GetReverse()); + } +} + +static void RestoreConnections(Entrance* entrance, Entrance* targetEntrance) { + targetEntrance->Connect(entrance->Disconnect()); + entrance->SetReplacement(nullptr); + if (entrance->GetReverse() != nullptr /*&& entrances are not decoupled*/) { + entrance->GetReverse()->GetAssumed()->Connect(targetEntrance->GetReplacement()->GetReverse()->Disconnect()); + targetEntrance->GetReplacement()->GetReverse()->SetReplacement(nullptr); + } +} + +static void DeleteTargetEntrance(Entrance* targetEntrance) { + if (targetEntrance->GetConnectedRegionKey() != NONE) { + targetEntrance->Disconnect(); + } + if (targetEntrance->GetParentRegionKey() != NONE) { + targetEntrance->GetParentRegion()->RemoveExit(targetEntrance); + targetEntrance->SetParentRegion(NONE); + } +} + +static void ConfirmReplacement(Entrance* entrance, Entrance* targetEntrance) { + DeleteTargetEntrance(targetEntrance); + if (entrance->GetReverse() != nullptr /*&& entrances are not decoupled*/) { + auto replacedReverse = targetEntrance->GetReplacement()->GetReverse(); + DeleteTargetEntrance(replacedReverse->GetReverse()->GetAssumed()); + } +} + +// Returns whether or not we can affirm the entrance can never be accessed as the given age +static bool EntranceUnreachableAs(Entrance* entrance, uint8_t age, std::vector& alreadyChecked) { + + if (entrance == nullptr) { + SPDLOG_INFO("Entrance is nullptr in EntranceUnreachableAs()"); + return true; + } + + alreadyChecked.push_back(entrance); + auto type = entrance->GetType(); + + // The following cases determine when we say an entrance is not safe to affirm unreachable as the given age + if (type == EntranceType::WarpSong || type == EntranceType::Overworld) { + // Note that we consider all overworld entrances as potentially accessible as both ages, to be completely safe + return false; + } else if (type == EntranceType::OwlDrop) { + return age == AGE_ADULT; + } else if (type == EntranceType::Spawn && entrance->GetConnectedRegionKey() == KF_LINKS_HOUSE) { + return age == AGE_ADULT; + } else if (type == EntranceType::Spawn && entrance->GetConnectedRegionKey() == TEMPLE_OF_TIME) { + return age == AGE_CHILD; + } + + // Other entrances such as Interior, Dungeon or Grotto are fine unless they have a parent which is one of the above + // cases Recursively check parent entrances to verify that they are also not reachable as the wrong age + auto& parentEntrances = entrance->GetParentRegion()->entrances; + for (Entrance* parentEntrance : parentEntrances) { + + // if parentEntrance is in alreadyChecked, then continue + if (ElementInContainer(parentEntrance, alreadyChecked)) { + continue; + } + + bool unreachable = EntranceUnreachableAs(parentEntrance, age, alreadyChecked); + if (!unreachable) { + return false; + } + } + + return true; +} + +static bool ValidateWorld(Entrance* entrancePlaced) { + SPDLOG_INFO("Validating world\n"); + + //check certain conditions when certain types of ER are enabled + EntranceType type = EntranceType::None; + if (entrancePlaced != nullptr) { + type = entrancePlaced->GetType(); + } + + bool checkPoeCollectorAccess = (Settings::ShuffleOverworldEntrances || Settings::ShuffleInteriorEntrances.Is(SHUFFLEINTERIORS_ALL)) && (entrancePlaced == nullptr /*|| Settings::MixedEntrancePools.IsNot(MIXEDENTRANCES_OFF)*/ || + type == EntranceType::Interior || type == EntranceType::SpecialInterior || type == EntranceType::Overworld || type == EntranceType::Spawn || type == EntranceType::WarpSong || type == EntranceType::OwlDrop); + bool checkOtherEntranceAccess = (Settings::ShuffleOverworldEntrances || Settings::ShuffleInteriorEntrances.Is(SHUFFLEINTERIORS_ALL) /*|| Settings::ShuffleOverworldSpawns*/) && (entrancePlaced == nullptr /*|| Settings::MixedEntrancePools.IsNot(MIXEDENTRANCES_OFF)*/ || + type == EntranceType::SpecialInterior || type == EntranceType::Overworld || type == EntranceType::Spawn || type == EntranceType::WarpSong || type == EntranceType::OwlDrop); + + // Check to make sure all locations are still reachable + Logic::LogicReset(); + GetAccessibleLocations({}, SearchMode::ValidateWorld, "", checkPoeCollectorAccess, checkOtherEntranceAccess); + + // if not world.decouple_entrances: + // Unless entrances are decoupled, we don't want the player to end up through certain entrances as the wrong age + // This means we need to hard check that none of the relevant entrances are ever reachable as that age + // This is mostly relevant when mixing entrance pools or shuffling special interiors (such as windmill or kak potion shop) + // Warp Songs and Overworld Spawns can also end up inside certain indoors so those need to be handled as well + std::array childForbidden = {"OGC Great Fairy Fountain -> Castle Grounds", "GV Carpenter Tent -> GV Fortress Side"}; + std::array adultForbidden = {"HC Great Fairy Fountain -> Castle Grounds", "HC Storms Grotto -> Castle Grounds"}; + + auto allShuffleableEntrances = GetShuffleableEntrances(EntranceType::All, false); + for (auto& entrance: allShuffleableEntrances) { + + std::vector alreadyChecked = {}; + + if (entrance->IsShuffled()) { + if (entrance->GetReplacement() != nullptr) { + + auto replacementName = entrance->GetReplacement()->GetName(); + alreadyChecked.push_back(entrance->GetReplacement()->GetReverse()); + + if (ElementInContainer(replacementName, childForbidden) && !EntranceUnreachableAs(entrance, AGE_CHILD, alreadyChecked)) { + auto message = replacementName + " is replaced by an entrance with a potential child access\n"; + SPDLOG_INFO(message); + return false; + } else if (ElementInContainer(replacementName, adultForbidden) && !EntranceUnreachableAs(entrance, AGE_ADULT, alreadyChecked)) { + auto message = replacementName + " is replaced by an entrance with a potential adult access\n"; + SPDLOG_INFO(message); + return false; + } + } + } else { + auto name = entrance->GetName(); + alreadyChecked.push_back(entrance->GetReverse()); + + if (ElementInContainer(name, childForbidden) && !EntranceUnreachableAs(entrance, AGE_CHILD, alreadyChecked)) { + auto message = name + " is potentially accessible as child\n"; + SPDLOG_INFO(message); + return false; + } else if (ElementInContainer(name, adultForbidden) && !EntranceUnreachableAs(entrance, AGE_ADULT, alreadyChecked)) { + auto message = name + " is potentially accessible as adult\n"; + SPDLOG_INFO(message); + return false; + } + } + } + + if (Settings::ShuffleInteriorEntrances.IsNot(SHUFFLEINTERIORS_OFF) && Settings::GossipStoneHints.IsNot(HINTS_NO_HINTS) && + (entrancePlaced == nullptr || type == EntranceType::Interior || type == EntranceType::SpecialInterior)) { + //When cows are shuffled, ensure both Impa's House entrances are in the same hint area because the cow is reachable from both sides + if (Settings::ShuffleCows) { + auto impasHouseFrontHintRegion = GetHintRegionHintKey(KAK_IMPAS_HOUSE); + auto impasHouseBackHintRegion = GetHintRegionHintKey(KAK_IMPAS_HOUSE_BACK); + if (impasHouseFrontHintRegion != NONE && impasHouseBackHintRegion != NONE && impasHouseBackHintRegion != LINKS_POCKET && impasHouseFrontHintRegion != LINKS_POCKET && impasHouseBackHintRegion != impasHouseFrontHintRegion) { + auto message = "Kak Impas House entrances are not in the same hint area\n"; + SPDLOG_INFO(message); + return false; + } + } + } + + // If all locations aren't reachable, that means that one of the conditions failed when searching + if (!allLocationsReachable) { + if (checkOtherEntranceAccess) { + // At least one valid starting region with all basic refills should be reachable without using any items at the beginning of the seed + if (!AreaTable(KOKIRI_FOREST)->HasAccess() && !AreaTable(KAKARIKO_VILLAGE)->HasAccess()) { + SPDLOG_INFO("Invalid starting area\n"); + return false; + } + + // Check that a region where time passes is always reachable as both ages without having collected any items + if (!Areas::HasTimePassAccess(AGE_CHILD) || !Areas::HasTimePassAccess(AGE_ADULT)) { + SPDLOG_INFO("Time passing is not guaranteed as both ages\n"); + return false; + } + + // The player should be able to get back to ToT after going through time, without having collected any items + // This is important to ensure that the player never loses access to the pedestal after going through time + if (Settings::ResolvedStartingAge == AGE_CHILD && !AreaTable(TEMPLE_OF_TIME)->Adult()) { + SPDLOG_INFO("Path to Temple of Time as adult is not guaranteed\n"); + return false; + } else if (Settings::ResolvedStartingAge == AGE_ADULT && !AreaTable(TEMPLE_OF_TIME)->Child()) { + SPDLOG_INFO("Path to Temple of Time as child is not guaranteed\n"); + return false; + } + } + + // The Big Poe shop should always be accessible as adult without the need to use any bottles + // This is important to ensure that players can never lock their only bottles by filling them with Big Poes they can't sell + if (checkPoeCollectorAccess) { + if (!AreaTable(MARKET_GUARD_HOUSE)->Adult()) { + SPDLOG_INFO("Big Poe Shop access is not guarenteed as adult\n"); + return false; + } + } + SPDLOG_INFO("All Locations NOT REACHABLE\n"); + return false; + } + return true; +} + +static bool ReplaceEntrance(Entrance* entrance, Entrance* target, std::vector& rollbacks) { + + if (!AreEntrancesCompatible(entrance, target, rollbacks)) { + return false; + } + ChangeConnections(entrance, target); + if (ValidateWorld(entrance)) { + #ifdef ENABLE_DEBUG + std::string ticks = std::to_string(svcGetSystemTick()); + auto message = "Dumping World Graph at " + ticks + "\n"; + //PlacementLog_Msg(message); + //Areas::DumpWorldGraph(ticks); + #endif + rollbacks.push_back(EntrancePair{entrance, target}); + curNumRandomizedEntrances++; + DisplayEntranceProgress(); + return true; + } else { + #ifdef ENABLE_DEBUG + std::string ticks = std::to_string(svcGetSystemTick()); + auto message = "Dumping World Graph at " + ticks + "\n"; + //PlacementLog_Msg(message); + //Areas::DumpWorldGraph(ticks); + #endif + if (entrance->GetConnectedRegionKey() != NONE) { + RestoreConnections(entrance, target); + } + } + DisplayEntranceProgress(); + return false; +} + +// Shuffle entrances by placing them instead of entrances in the provided target entrances list +static bool ShuffleEntrances(std::vector& entrances, std::vector& targetEntrances, std::vector& rollbacks) { + + Shuffle(entrances); + + //place all entrances in the pool, validating after every placement + for (Entrance* entrance : entrances) { + if (entrance->GetConnectedRegionKey() != NONE) { + continue; + } + + Shuffle(targetEntrances); + for (Entrance* target : targetEntrances) { + if (target->GetConnectedRegionKey() == NONE) { + continue; + } + + if (ReplaceEntrance(entrance, target, rollbacks)) { + break; + } + } + + if (entrance->GetConnectedRegionKey() == NONE) { + return false; + } + } + + //all entrances were validly connected + return true; +} + +static void ShuffleEntrancePool(std::vector& entrancePool, std::vector& targetEntrances) { + noRandomEntrances = false; + + auto splitEntrances = SplitEntrancesByRequirements(entrancePool, targetEntrances); + + auto& restrictiveEntrances = splitEntrances[0]; + auto& softEntrances = splitEntrances[1]; + + int retries = 20; + while (retries > 0) { + if (retries != 20) { + #ifdef ENABLE_DEBUG + std::string ticks = std::to_string(svcGetSystemTick()); + auto message = "Failed to connect entrances. Retrying " + std::to_string(retries) + " more times.\nDumping World Graph at " + ticks + "\n"; + PlacementLog_Msg(message); + Areas::DumpWorldGraph(ticks); + #endif + } + retries--; + + std::vector rollbacks = {}; + + //Shuffle Restrictive Entrances first while more regions are available in + //order to heavily reduce the chances of the placement failing + bool success = ShuffleEntrances(restrictiveEntrances, targetEntrances, rollbacks); + if (success) { + success = ShuffleEntrances(softEntrances, targetEntrances, rollbacks); + if(!success) { + for (auto& pair : rollbacks) { + RestoreConnections(pair.first, pair.second); + curNumRandomizedEntrances--; + } + continue; + } + } else { + for (auto& pair : rollbacks) { + RestoreConnections(pair.first, pair.second); + curNumRandomizedEntrances--; + } + continue; + } + + //If there are no issues, log the connections and continue + for (auto& pair : rollbacks) { + ConfirmReplacement(pair.first, pair.second); + } + break; + } + + if (retries <= 0) { + SPDLOG_INFO("Entrance placement attempt count exceeded. Restarting randomization completely"); + entranceShuffleFailure = true; + } +} + +//Process for setting up the shuffling of all entrances to be shuffled +int ShuffleAllEntrances() { + + totalRandomizableEntrances = 0; + curNumRandomizedEntrances = 0; + + std::vector entranceShuffleTable = { + //Parent Region Connected Region index blue warp + {{EntranceType::Dungeon, KF_OUTSIDE_DEKU_TREE, DEKU_TREE_ENTRYWAY, 0x0000}, + {EntranceType::Dungeon, DEKU_TREE_ENTRYWAY, KF_OUTSIDE_DEKU_TREE, 0x0209, 0x0457}}, + {{EntranceType::Dungeon, DEATH_MOUNTAIN_TRAIL, DODONGOS_CAVERN_ENTRYWAY, 0x0004}, + {EntranceType::Dungeon, DODONGOS_CAVERN_ENTRYWAY, DEATH_MOUNTAIN_TRAIL, 0x0242, 0x047A}}, + {{EntranceType::Dungeon, ZORAS_FOUNTAIN, JABU_JABUS_BELLY_ENTRYWAY, 0x0028}, + {EntranceType::Dungeon, JABU_JABUS_BELLY_ENTRYWAY, ZORAS_FOUNTAIN, 0x0221, 0x010E}}, + {{EntranceType::Dungeon, SACRED_FOREST_MEADOW, FOREST_TEMPLE_ENTRYWAY, 0x0169}, + {EntranceType::Dungeon, FOREST_TEMPLE_ENTRYWAY, SACRED_FOREST_MEADOW, 0x0215, 0x0608}}, + {{EntranceType::Dungeon, DMC_CENTRAL_LOCAL, FIRE_TEMPLE_ENTRYWAY, 0x0165}, + {EntranceType::Dungeon, FIRE_TEMPLE_ENTRYWAY, DMC_CENTRAL_LOCAL, 0x024A, 0x0564}}, + {{EntranceType::Dungeon, LAKE_HYLIA, WATER_TEMPLE_ENTRYWAY, 0x0010}, + {EntranceType::Dungeon, WATER_TEMPLE_ENTRYWAY, LAKE_HYLIA, 0x021D, 0x060C}}, + {{EntranceType::Dungeon, DESERT_COLOSSUS, SPIRIT_TEMPLE_ENTRYWAY, 0x0082}, + {EntranceType::Dungeon, SPIRIT_TEMPLE_ENTRYWAY, DESERT_COLOSSUS, 0x01E1, 0x0610}}, + {{EntranceType::Dungeon, GRAVEYARD_WARP_PAD_REGION, SHADOW_TEMPLE_ENTRYWAY, 0x0037}, + {EntranceType::Dungeon, SHADOW_TEMPLE_ENTRYWAY, GRAVEYARD_WARP_PAD_REGION, 0x0205, 0x0580}}, + {{EntranceType::Dungeon, KAKARIKO_VILLAGE, BOTTOM_OF_THE_WELL_ENTRYWAY, 0x0098}, + {EntranceType::Dungeon, BOTTOM_OF_THE_WELL_ENTRYWAY, KAKARIKO_VILLAGE, 0x02A6}}, + {{EntranceType::Dungeon, ZORAS_FOUNTAIN, ICE_CAVERN_ENTRYWAY, 0x0088}, + {EntranceType::Dungeon, ICE_CAVERN_ENTRYWAY, ZORAS_FOUNTAIN, 0x03D4}}, + {{EntranceType::Dungeon, GERUDO_FORTRESS, GERUDO_TRAINING_GROUNDS_ENTRYWAY, 0x0008}, + {EntranceType::Dungeon, GERUDO_TRAINING_GROUNDS_ENTRYWAY, GERUDO_FORTRESS, 0x03A8}}, + {{EntranceType::GanonDungeon, GANONS_CASTLE_GROUNDS, GANONS_CASTLE_ENTRYWAY, 0x0467}, + {EntranceType::GanonDungeon, GANONS_CASTLE_ENTRYWAY, GANONS_CASTLE_GROUNDS, 0x023D}}, + + {{EntranceType::Interior, KOKIRI_FOREST, KF_MIDOS_HOUSE, 0x0433}, + {EntranceType::Interior, KF_MIDOS_HOUSE, KOKIRI_FOREST, 0x0443}}, + {{EntranceType::Interior, KOKIRI_FOREST, KF_SARIAS_HOUSE, 0x0437}, + {EntranceType::Interior, KF_SARIAS_HOUSE, KOKIRI_FOREST, 0x0447}}, + {{EntranceType::Interior, KOKIRI_FOREST, KF_HOUSE_OF_TWINS, 0x009C}, + {EntranceType::Interior, KF_HOUSE_OF_TWINS, KOKIRI_FOREST, 0x033C}}, + {{EntranceType::Interior, KOKIRI_FOREST, KF_KNOW_IT_ALL_HOUSE, 0x00C9}, + {EntranceType::Interior, KF_KNOW_IT_ALL_HOUSE, KOKIRI_FOREST, 0x026A}}, + {{EntranceType::Interior, KOKIRI_FOREST, KF_KOKIRI_SHOP, 0x00C1}, + {EntranceType::Interior, KF_KOKIRI_SHOP, KOKIRI_FOREST, 0x0266}}, + {{EntranceType::Interior, LAKE_HYLIA, LH_LAB, 0x0043}, + {EntranceType::Interior, LH_LAB, LAKE_HYLIA, 0x03CC}}, + {{EntranceType::Interior, LH_FISHING_ISLAND, LH_FISHING_HOLE, 0x045F}, + {EntranceType::Interior, LH_FISHING_HOLE, LH_FISHING_ISLAND, 0x0309}}, + {{EntranceType::Interior, GV_FORTRESS_SIDE, GV_CARPENTER_TENT, 0x03A0}, + {EntranceType::Interior, GV_CARPENTER_TENT, GV_FORTRESS_SIDE, 0x03D0}}, + {{EntranceType::Interior, MARKET_ENTRANCE, MARKET_GUARD_HOUSE, 0x007E}, + {EntranceType::Interior, MARKET_GUARD_HOUSE, MARKET_ENTRANCE, 0x026E}}, + {{EntranceType::Interior, THE_MARKET, MARKET_MASK_SHOP, 0x0530}, + {EntranceType::Interior, MARKET_MASK_SHOP, THE_MARKET, 0x01D1}}, + {{EntranceType::Interior, THE_MARKET, MARKET_BOMBCHU_BOWLING, 0x0507}, + {EntranceType::Interior, MARKET_BOMBCHU_BOWLING, THE_MARKET, 0x03BC}}, + {{EntranceType::Interior, THE_MARKET, MARKET_POTION_SHOP, 0x0388}, + {EntranceType::Interior, MARKET_POTION_SHOP, THE_MARKET, 0x02A2}}, + {{EntranceType::Interior, THE_MARKET, MARKET_TREASURE_CHEST_GAME, 0x0063}, + {EntranceType::Interior, MARKET_TREASURE_CHEST_GAME, THE_MARKET, 0x01D5}}, + {{EntranceType::Interior, MARKET_BACK_ALLEY, MARKET_BOMBCHU_SHOP, 0x0528}, + {EntranceType::Interior, MARKET_BOMBCHU_SHOP, MARKET_BACK_ALLEY, 0x03C0}}, + {{EntranceType::Interior, MARKET_BACK_ALLEY, MARKET_MAN_IN_GREEN_HOUSE, 0x043B}, + {EntranceType::Interior, MARKET_MAN_IN_GREEN_HOUSE, MARKET_BACK_ALLEY, 0x0067}}, + {{EntranceType::Interior, KAKARIKO_VILLAGE, KAK_CARPENTER_BOSS_HOUSE, 0x02FD}, + {EntranceType::Interior, KAK_CARPENTER_BOSS_HOUSE, KAKARIKO_VILLAGE, 0x0349}}, + {{EntranceType::Interior, KAKARIKO_VILLAGE, KAK_HOUSE_OF_SKULLTULA, 0x0550}, + {EntranceType::Interior, KAK_HOUSE_OF_SKULLTULA, KAKARIKO_VILLAGE, 0x04EE}}, + {{EntranceType::Interior, KAKARIKO_VILLAGE, KAK_IMPAS_HOUSE, 0x039C}, + {EntranceType::Interior, KAK_IMPAS_HOUSE, KAKARIKO_VILLAGE, 0x0345}}, + {{EntranceType::Interior, KAK_IMPAS_LEDGE, KAK_IMPAS_HOUSE_BACK, 0x05C8}, + {EntranceType::Interior, KAK_IMPAS_HOUSE_BACK, KAK_IMPAS_LEDGE, 0x05DC}}, + {{EntranceType::Interior, KAK_BACKYARD, KAK_ODD_POTION_BUILDING, 0x0072}, + {EntranceType::Interior, KAK_ODD_POTION_BUILDING, KAK_BACKYARD, 0x034D}}, + {{EntranceType::Interior, THE_GRAVEYARD, GRAVEYARD_DAMPES_HOUSE, 0x030D}, + {EntranceType::Interior, GRAVEYARD_DAMPES_HOUSE, THE_GRAVEYARD, 0x0355}}, + {{EntranceType::Interior, GORON_CITY, GC_SHOP, 0x037C}, + {EntranceType::Interior, GC_SHOP, GORON_CITY, 0x03FC}}, + {{EntranceType::Interior, ZORAS_DOMAIN, ZD_SHOP, 0x0380}, + {EntranceType::Interior, ZD_SHOP, ZORAS_DOMAIN, 0x03C4}}, + {{EntranceType::Interior, LON_LON_RANCH, LLR_TALONS_HOUSE, 0x004F}, + {EntranceType::Interior, LLR_TALONS_HOUSE, LON_LON_RANCH, 0x0378}}, + {{EntranceType::Interior, LON_LON_RANCH, LLR_STABLES, 0x02F9}, + {EntranceType::Interior, LLR_STABLES, LON_LON_RANCH, 0x042F}}, + {{EntranceType::Interior, LON_LON_RANCH, LLR_TOWER, 0x05D0}, + {EntranceType::Interior, LLR_TOWER, LON_LON_RANCH, 0x05D4}}, + {{EntranceType::Interior, THE_MARKET, MARKET_BAZAAR, 0x052C}, + {EntranceType::Interior, MARKET_BAZAAR, THE_MARKET, 0x03B8}}, + {{EntranceType::Interior, THE_MARKET, MARKET_SHOOTING_GALLERY, 0x016D}, + {EntranceType::Interior, MARKET_SHOOTING_GALLERY, THE_MARKET, 0x01CD}}, + {{EntranceType::Interior, KAKARIKO_VILLAGE, KAK_BAZAAR, 0x00B7}, + {EntranceType::Interior, KAK_BAZAAR, KAKARIKO_VILLAGE, 0x0201}}, + {{EntranceType::Interior, KAKARIKO_VILLAGE, KAK_SHOOTING_GALLERY, 0x003B}, + {EntranceType::Interior, KAK_SHOOTING_GALLERY, KAKARIKO_VILLAGE, 0x0463}}, + {{EntranceType::Interior, DESERT_COLOSSUS, COLOSSUS_GREAT_FAIRY_FOUNTAIN, 0x0588}, + {EntranceType::Interior, COLOSSUS_GREAT_FAIRY_FOUNTAIN, DESERT_COLOSSUS, 0x057C}}, + {{EntranceType::Interior, HYRULE_CASTLE_GROUNDS, HC_GREAT_FAIRY_FOUNTAIN, 0x0578}, + {EntranceType::Interior, HC_GREAT_FAIRY_FOUNTAIN, CASTLE_GROUNDS, 0x0340}}, + {{EntranceType::Interior, GANONS_CASTLE_GROUNDS, OGC_GREAT_FAIRY_FOUNTAIN, 0x04C2}, + {EntranceType::Interior, OGC_GREAT_FAIRY_FOUNTAIN, CASTLE_GROUNDS, 0x03E8}}, //0x3E8 is an unused entrance index repruposed to differentiate between the HC and OGC fairy fountain exits (normally they both use 0x340) + {{EntranceType::Interior, DMC_LOWER_NEARBY, DMC_GREAT_FAIRY_FOUNTAIN, 0x04BE}, + {EntranceType::Interior, DMC_GREAT_FAIRY_FOUNTAIN, DMC_LOWER_LOCAL, 0x0482}}, + {{EntranceType::Interior, DEATH_MOUNTAIN_SUMMIT, DMT_GREAT_FAIRY_FOUNTAIN, 0x0315}, + {EntranceType::Interior, DMT_GREAT_FAIRY_FOUNTAIN, DEATH_MOUNTAIN_SUMMIT, 0x045B}}, + {{EntranceType::Interior, ZORAS_FOUNTAIN, ZF_GREAT_FAIRY_FOUNTAIN, 0x0371}, + {EntranceType::Interior, ZF_GREAT_FAIRY_FOUNTAIN, ZORAS_FOUNTAIN, 0x0394}}, + + {{EntranceType::SpecialInterior, KOKIRI_FOREST, KF_LINKS_HOUSE, 0x0272}, + {EntranceType::SpecialInterior, KF_LINKS_HOUSE, KOKIRI_FOREST, 0x0211}}, + {{EntranceType::SpecialInterior, TOT_ENTRANCE, TEMPLE_OF_TIME, 0x0053}, + {EntranceType::SpecialInterior, TEMPLE_OF_TIME, TOT_ENTRANCE, 0x0472}}, + {{EntranceType::SpecialInterior, KAKARIKO_VILLAGE, KAK_WINDMILL, 0x0453}, + {EntranceType::SpecialInterior, KAK_WINDMILL, KAKARIKO_VILLAGE, 0x0351}}, + {{EntranceType::SpecialInterior, KAKARIKO_VILLAGE, KAK_POTION_SHOP_FRONT, 0x0384}, + {EntranceType::SpecialInterior, KAK_POTION_SHOP_FRONT, KAKARIKO_VILLAGE, 0x044B}}, + {{EntranceType::SpecialInterior, KAK_BACKYARD, KAK_POTION_SHOP_BACK, 0x03EC}, + {EntranceType::SpecialInterior, KAK_POTION_SHOP_BACK, KAK_BACKYARD, 0x04FF}}, + + // Grotto Loads use an entrance index of 0x0700 + their grotto id. The id is used as index for the + // grottoLoadTable in src/grotto.c + // Grotto Returns use an entrance index of 0x0800 + their grotto id. The id is used as index for the + // grottoReturnTable in src/grotto.c + {{EntranceType::GrottoGrave, DESERT_COLOSSUS, COLOSSUS_GROTTO, 0x0700}, + {EntranceType::GrottoGrave, COLOSSUS_GROTTO, DESERT_COLOSSUS, 0x0800}}, + {{EntranceType::GrottoGrave, LAKE_HYLIA, LH_GROTTO, 0x0701}, + {EntranceType::GrottoGrave, LH_GROTTO, LAKE_HYLIA, 0x0801}}, + {{EntranceType::GrottoGrave, ZORAS_RIVER, ZR_STORMS_GROTTO, 0x0702}, + {EntranceType::GrottoGrave, ZR_STORMS_GROTTO, ZORAS_RIVER, 0x0802}}, + {{EntranceType::GrottoGrave, ZORAS_RIVER, ZR_FAIRY_GROTTO, 0x0703}, + {EntranceType::GrottoGrave, ZR_FAIRY_GROTTO, ZORAS_RIVER, 0x0803}}, + {{EntranceType::GrottoGrave, ZORAS_RIVER, ZR_OPEN_GROTTO, 0x0704}, + {EntranceType::GrottoGrave, ZR_OPEN_GROTTO, ZORAS_RIVER, 0x0804}}, + {{EntranceType::GrottoGrave, DMC_LOWER_NEARBY, DMC_HAMMER_GROTTO, 0x0705}, + {EntranceType::GrottoGrave, DMC_HAMMER_GROTTO, DMC_LOWER_LOCAL, 0x0805}}, + {{EntranceType::GrottoGrave, DMC_UPPER_NEARBY, DMC_UPPER_GROTTO, 0x0706}, + {EntranceType::GrottoGrave, DMC_UPPER_GROTTO, DMC_UPPER_LOCAL, 0x0806}}, + {{EntranceType::GrottoGrave, GC_GROTTO_PLATFORM, GC_GROTTO, 0x0707}, + {EntranceType::GrottoGrave, GC_GROTTO, GC_GROTTO_PLATFORM, 0x0807}}, + {{EntranceType::GrottoGrave, DEATH_MOUNTAIN_TRAIL, DMT_STORMS_GROTTO, 0x0708}, + {EntranceType::GrottoGrave, DMT_STORMS_GROTTO, DEATH_MOUNTAIN_TRAIL, 0x0808}}, + {{EntranceType::GrottoGrave, DEATH_MOUNTAIN_SUMMIT, DMT_COW_GROTTO, 0x0709}, + {EntranceType::GrottoGrave, DMT_COW_GROTTO, DEATH_MOUNTAIN_SUMMIT, 0x0809}}, + {{EntranceType::GrottoGrave, KAK_BACKYARD, KAK_OPEN_GROTTO, 0x070A}, + {EntranceType::GrottoGrave, KAK_OPEN_GROTTO, KAK_BACKYARD, 0x080A}}, + {{EntranceType::GrottoGrave, KAKARIKO_VILLAGE, KAK_REDEAD_GROTTO, 0x070B}, + {EntranceType::GrottoGrave, KAK_REDEAD_GROTTO, KAKARIKO_VILLAGE, 0x080B}}, + {{EntranceType::GrottoGrave, HYRULE_CASTLE_GROUNDS, HC_STORMS_GROTTO, 0x070C}, + {EntranceType::GrottoGrave, HC_STORMS_GROTTO, CASTLE_GROUNDS, 0x080C}}, + {{EntranceType::GrottoGrave, HYRULE_FIELD, HF_TEKTITE_GROTTO, 0x070D}, + {EntranceType::GrottoGrave, HF_TEKTITE_GROTTO, HYRULE_FIELD, 0x080D}}, + {{EntranceType::GrottoGrave, HYRULE_FIELD, HF_NEAR_KAK_GROTTO, 0x070E}, + {EntranceType::GrottoGrave, HF_NEAR_KAK_GROTTO, HYRULE_FIELD, 0x080E}}, + {{EntranceType::GrottoGrave, HYRULE_FIELD, HF_FAIRY_GROTTO, 0x070F}, + {EntranceType::GrottoGrave, HF_FAIRY_GROTTO, HYRULE_FIELD, 0x080F}}, + {{EntranceType::GrottoGrave, HYRULE_FIELD, HF_NEAR_MARKET_GROTTO, 0x0710}, + {EntranceType::GrottoGrave, HF_NEAR_MARKET_GROTTO, HYRULE_FIELD, 0x0810}}, + {{EntranceType::GrottoGrave, HYRULE_FIELD, HF_COW_GROTTO, 0x0711}, + {EntranceType::GrottoGrave, HF_COW_GROTTO, HYRULE_FIELD, 0x0811}}, + {{EntranceType::GrottoGrave, HYRULE_FIELD, HF_INSIDE_FENCE_GROTTO, 0x0712}, + {EntranceType::GrottoGrave, HF_INSIDE_FENCE_GROTTO, HYRULE_FIELD, 0x0812}}, + {{EntranceType::GrottoGrave, HYRULE_FIELD, HF_OPEN_GROTTO, 0x0713}, + {EntranceType::GrottoGrave, HF_OPEN_GROTTO, HYRULE_FIELD, 0x0813}}, + {{EntranceType::GrottoGrave, HYRULE_FIELD, HF_SOUTHEAST_GROTTO, 0x0714}, + {EntranceType::GrottoGrave, HF_SOUTHEAST_GROTTO, HYRULE_FIELD, 0x0814}}, + {{EntranceType::GrottoGrave, LON_LON_RANCH, LLR_GROTTO, 0x0715}, + {EntranceType::GrottoGrave, LLR_GROTTO, LON_LON_RANCH, 0x0815}}, + {{EntranceType::GrottoGrave, SFM_ENTRYWAY, SFM_WOLFOS_GROTTO, 0x0716}, + {EntranceType::GrottoGrave, SFM_WOLFOS_GROTTO, SFM_ENTRYWAY, 0x0816}}, + {{EntranceType::GrottoGrave, SACRED_FOREST_MEADOW, SFM_STORMS_GROTTO, 0x0717}, + {EntranceType::GrottoGrave, SFM_STORMS_GROTTO, SACRED_FOREST_MEADOW, 0x0817}}, + {{EntranceType::GrottoGrave, SACRED_FOREST_MEADOW, SFM_FAIRY_GROTTO, 0x0718}, + {EntranceType::GrottoGrave, SFM_FAIRY_GROTTO, SACRED_FOREST_MEADOW, 0x0818}}, + {{EntranceType::GrottoGrave, LW_BEYOND_MIDO, LW_SCRUBS_GROTTO, 0x0719}, + {EntranceType::GrottoGrave, LW_SCRUBS_GROTTO, LW_BEYOND_MIDO, 0x0819}}, + {{EntranceType::GrottoGrave, THE_LOST_WOODS, LW_NEAR_SHORTCUTS_GROTTO, 0x071A}, + {EntranceType::GrottoGrave, LW_NEAR_SHORTCUTS_GROTTO, THE_LOST_WOODS, 0x081A}}, + {{EntranceType::GrottoGrave, KOKIRI_FOREST, KF_STORMS_GROTTO, 0x071B}, + {EntranceType::GrottoGrave, KF_STORMS_GROTTO, KOKIRI_FOREST, 0x081B}}, + {{EntranceType::GrottoGrave, ZORAS_DOMAIN, ZD_STORMS_GROTTO, 0x071C}, + {EntranceType::GrottoGrave, ZD_STORMS_GROTTO, ZORAS_DOMAIN, 0x081C}}, + {{EntranceType::GrottoGrave, GERUDO_FORTRESS, GF_STORMS_GROTTO, 0x071D}, + {EntranceType::GrottoGrave, GF_STORMS_GROTTO, GERUDO_FORTRESS, 0x081D}}, + {{EntranceType::GrottoGrave, GV_FORTRESS_SIDE, GV_STORMS_GROTTO, 0x071E}, + {EntranceType::GrottoGrave, GV_STORMS_GROTTO, GV_FORTRESS_SIDE, 0x081E}}, + {{EntranceType::GrottoGrave, GV_GROTTO_LEDGE, GV_OCTOROK_GROTTO, 0x071F}, + {EntranceType::GrottoGrave, GV_OCTOROK_GROTTO, GV_GROTTO_LEDGE, 0x081F}}, + {{EntranceType::GrottoGrave, LW_BEYOND_MIDO, DEKU_THEATER, 0x0720}, + {EntranceType::GrottoGrave, DEKU_THEATER, LW_BEYOND_MIDO, 0x0820}}, + + // Graves have their own specified entrance indices + {{EntranceType::GrottoGrave, THE_GRAVEYARD, GRAVEYARD_SHIELD_GRAVE, 0x004B}, + {EntranceType::GrottoGrave, GRAVEYARD_SHIELD_GRAVE, THE_GRAVEYARD, 0x035D}}, + {{EntranceType::GrottoGrave, THE_GRAVEYARD, GRAVEYARD_HEART_PIECE_GRAVE, 0x031C}, + {EntranceType::GrottoGrave, GRAVEYARD_HEART_PIECE_GRAVE, THE_GRAVEYARD, 0x0361}}, + {{EntranceType::GrottoGrave, THE_GRAVEYARD, GRAVEYARD_COMPOSERS_GRAVE, 0x002D}, + {EntranceType::GrottoGrave, GRAVEYARD_COMPOSERS_GRAVE, THE_GRAVEYARD, 0x050B}}, + {{EntranceType::GrottoGrave, THE_GRAVEYARD, GRAVEYARD_DAMPES_GRAVE, 0x044F}, + {EntranceType::GrottoGrave, GRAVEYARD_DAMPES_GRAVE, THE_GRAVEYARD, 0x0359}}, + + {{EntranceType::Overworld, KOKIRI_FOREST, LW_BRIDGE_FROM_FOREST, 0x05E0}, + {EntranceType::Overworld, LW_BRIDGE, KOKIRI_FOREST, 0x020D}}, + {{EntranceType::Overworld, KOKIRI_FOREST, THE_LOST_WOODS, 0x011E}, + {EntranceType::Overworld, LW_FOREST_EXIT, KOKIRI_FOREST, 0x0286}}, + {{EntranceType::Overworld, THE_LOST_WOODS, GC_WOODS_WARP, 0x04E2}, + {EntranceType::Overworld, GC_WOODS_WARP, THE_LOST_WOODS, 0x04D6}}, + {{EntranceType::Overworld, THE_LOST_WOODS, ZORAS_RIVER, 0x01DD}, + {EntranceType::Overworld, ZORAS_RIVER, THE_LOST_WOODS, 0x04DA}}, + {{EntranceType::Overworld, LW_BEYOND_MIDO, SFM_ENTRYWAY, 0x00FC}, + {EntranceType::Overworld, SFM_ENTRYWAY, LW_BEYOND_MIDO, 0x01A9}}, + {{EntranceType::Overworld, LW_BRIDGE, HYRULE_FIELD, 0x0185}, + {EntranceType::Overworld, HYRULE_FIELD, LW_BRIDGE, 0x04DE}}, + {{EntranceType::Overworld, HYRULE_FIELD, LAKE_HYLIA, 0x0102}, + {EntranceType::Overworld, LAKE_HYLIA, HYRULE_FIELD, 0x0189}}, + {{EntranceType::Overworld, HYRULE_FIELD, GERUDO_VALLEY, 0x0117}, + {EntranceType::Overworld, GERUDO_VALLEY, HYRULE_FIELD, 0x018D}}, + {{EntranceType::Overworld, HYRULE_FIELD, MARKET_ENTRANCE, 0x0276}, + {EntranceType::Overworld, MARKET_ENTRANCE, HYRULE_FIELD, 0x01FD}}, + {{EntranceType::Overworld, HYRULE_FIELD, KAKARIKO_VILLAGE, 0x00DB}, + {EntranceType::Overworld, KAKARIKO_VILLAGE, HYRULE_FIELD, 0x017D}}, + {{EntranceType::Overworld, HYRULE_FIELD, ZR_FRONT, 0x00EA}, + {EntranceType::Overworld, ZR_FRONT, HYRULE_FIELD, 0x0181}}, + {{EntranceType::Overworld, HYRULE_FIELD, LON_LON_RANCH, 0x0157}, + {EntranceType::Overworld, LON_LON_RANCH, HYRULE_FIELD, 0x01F9}}, + {{EntranceType::Overworld, LAKE_HYLIA, ZORAS_DOMAIN, 0x0328}, + {EntranceType::Overworld, ZORAS_DOMAIN, LAKE_HYLIA, 0x0560}}, + {{EntranceType::Overworld, GV_FORTRESS_SIDE, GERUDO_FORTRESS, 0x0129}, + {EntranceType::Overworld, GERUDO_FORTRESS, GV_FORTRESS_SIDE, 0x022D}}, + {{EntranceType::Overworld, GF_OUTSIDE_GATE, WASTELAND_NEAR_FORTRESS, 0x0130}, + {EntranceType::Overworld, WASTELAND_NEAR_FORTRESS, GF_OUTSIDE_GATE, 0x03AC}}, + {{EntranceType::Overworld, WASTELAND_NEAR_COLOSSUS, DESERT_COLOSSUS, 0x0123}, + {EntranceType::Overworld, DESERT_COLOSSUS, WASTELAND_NEAR_COLOSSUS, 0x0365}}, + {{EntranceType::Overworld, MARKET_ENTRANCE, THE_MARKET, 0x00B1}, + {EntranceType::Overworld, THE_MARKET, MARKET_ENTRANCE, 0x0033}}, + {{EntranceType::Overworld, THE_MARKET, CASTLE_GROUNDS, 0x0138}, + {EntranceType::Overworld, CASTLE_GROUNDS, THE_MARKET, 0x025A}}, + {{EntranceType::Overworld, THE_MARKET, TOT_ENTRANCE, 0x0171}, + {EntranceType::Overworld, TOT_ENTRANCE, THE_MARKET, 0x025E}}, + {{EntranceType::Overworld, KAKARIKO_VILLAGE, THE_GRAVEYARD, 0x00E4}, + {EntranceType::Overworld, THE_GRAVEYARD, KAKARIKO_VILLAGE, 0x0195}}, + {{EntranceType::Overworld, KAK_BEHIND_GATE, DEATH_MOUNTAIN_TRAIL, 0x013D}, + {EntranceType::Overworld, DEATH_MOUNTAIN_TRAIL, KAK_BEHIND_GATE, 0x0191}}, + {{EntranceType::Overworld, DEATH_MOUNTAIN_TRAIL, GORON_CITY, 0x014D}, + {EntranceType::Overworld, GORON_CITY, DEATH_MOUNTAIN_TRAIL, 0x01B9}}, + {{EntranceType::Overworld, GC_DARUNIAS_CHAMBER, DMC_LOWER_LOCAL, 0x0246}, + {EntranceType::Overworld, DMC_LOWER_NEARBY, GC_DARUNIAS_CHAMBER, 0x01C1}}, + {{EntranceType::Overworld, DEATH_MOUNTAIN_SUMMIT, DMC_UPPER_LOCAL, 0x0147}, + {EntranceType::Overworld, DMC_UPPER_NEARBY, DEATH_MOUNTAIN_SUMMIT, 0x01BD}}, + {{EntranceType::Overworld, ZR_BEHIND_WATERFALL, ZORAS_DOMAIN, 0x0108}, + {EntranceType::Overworld, ZORAS_DOMAIN, ZR_BEHIND_WATERFALL, 0x019D}}, + {{EntranceType::Overworld, ZD_BEHIND_KING_ZORA, ZORAS_FOUNTAIN, 0x0225}, + {EntranceType::Overworld, ZORAS_FOUNTAIN, ZD_BEHIND_KING_ZORA, 0x01A1}}, + }; + + entranceShuffleFailure = false; + SetAllEntrancesData(entranceShuffleTable); + + // one_way_entrance_pools = OrderedDict() + std::map> entrancePools = {}; + // one_way_priorities = {} + + //owl drops + + //spawns + + //warpsongs + + //Shuffle Dungeon Entrances + if (Settings::ShuffleDungeonEntrances.IsNot(SHUFFLEDUNGEONS_OFF)) { + entrancePools[EntranceType::Dungeon] = GetShuffleableEntrances(EntranceType::Dungeon); + //Add Ganon's Castle, if set to On + Ganon + if (Settings::ShuffleDungeonEntrances.Is(SHUFFLEDUNGEONS_GANON)) { + AddElementsToPool(entrancePools[EntranceType::Dungeon], GetShuffleableEntrances(EntranceType::GanonDungeon)); + } + //If forest is closed don't allow a forest escape via spirit temple hands + if (Settings::OpenForest.Is(OPENFOREST_CLOSED) && !(Settings::ShuffleOverworldEntrances || Settings::ShuffleInteriorEntrances)) { + FilterAndEraseFromPool(entrancePools[EntranceType::Dungeon], [](const Entrance* entrance){return entrance->GetParentRegionKey() == KF_OUTSIDE_DEKU_TREE && + entrance->GetConnectedRegionKey() == DEKU_TREE_ENTRYWAY;}); + } + + //decoupled entrances stuff + } + + //interior entrances + if (Settings::ShuffleInteriorEntrances.IsNot(SHUFFLEINTERIORS_OFF)) { + entrancePools[EntranceType::Interior] = GetShuffleableEntrances(EntranceType::Interior); + //special interiors + if (Settings::ShuffleInteriorEntrances.Is(SHUFFLEINTERIORS_ALL)) { + AddElementsToPool(entrancePools[EntranceType::Interior], GetShuffleableEntrances(EntranceType::SpecialInterior)); + } + + //decoupled entrance stuff + } + + //grotto entrances + if (Settings::ShuffleGrottoEntrances) { + entrancePools[EntranceType::GrottoGrave] = GetShuffleableEntrances(EntranceType::GrottoGrave); + + //decoupled entrance stuff + } + + //overworld entrances + if (Settings::ShuffleOverworldEntrances) { + bool excludeOverworldReverse = false; //mix_entrance_pools == all && !decouple_entrances + entrancePools[EntranceType::Overworld] = GetShuffleableEntrances(EntranceType::Overworld, excludeOverworldReverse); + // if not worlds[0].decouple_entrances: + // entrance_pools['Overworld'].remove(world.get_entrance('GV Lower Stream -> Lake Hylia')) + if (!excludeOverworldReverse) { + totalRandomizableEntrances -= 26; //Only count each overworld entrance once + } + } + + //Set shuffled entrances as such + for (auto& pool : entrancePools) { + for (Entrance* entrance : pool.second) { + entrance->SetAsShuffled(); + totalRandomizableEntrances++; + if (entrance->GetReverse() != nullptr) { + entrance->GetReverse()->SetAsShuffled(); + } + } + } + + //combine entrance pools if mixing pools + + //Build target entrance pools and set the assumption for entrances being reachable + //one way entrance stuff + + //assume entrance pools for each type + std::map> targetEntrancePools = {}; + for (auto& pool : entrancePools) { + targetEntrancePools[pool.first] = AssumeEntrancePool(pool.second); + } + + //distribution stuff + + //check placed on-way entrances + //remove replaced entrances so we don't place two in one target + //remvoe priority targets if any placed entrances point at their regions + + //place priority entrances + + //delete all targets that we just placed from one way target pools so multiple one way entrances don't use the same target + + //shuffle all entrances among pools to shuffle + for (auto& pool : entrancePools) { + ShuffleEntrancePool(pool.second, targetEntrancePools[pool.first]); + if (entranceShuffleFailure) { + return ENTRANCE_SHUFFLE_FAILURE; + } + } + + return ENTRANCE_SHUFFLE_SUCCESS; +} + +//Create the set of entrances that will be overridden +void CreateEntranceOverrides() { + entranceOverrides.clear(); + if (noRandomEntrances) { + return; + } + SPDLOG_INFO("\nCREATING ENTRANCE OVERRIDES\n"); + auto allShuffleableEntrances = GetShuffleableEntrances(EntranceType::All, false); + + for (Entrance* entrance : allShuffleableEntrances) { + + //Double-check to make sure the entrance is actually shuffled + if (!entrance->IsShuffled()) { + continue; + } + + auto message = "Setting " + entrance->to_string() + "\n"; + SPDLOG_INFO(message); + + int16_t originalIndex = entrance->GetIndex(); + int16_t destinationIndex = entrance->GetReverse()->GetIndex(); + int16_t originalBlueWarp = entrance->GetBlueWarp(); + int16_t replacementIndex = entrance->GetReplacement()->GetIndex(); + int16_t replacementDestinationIndex = entrance->GetReplacement()->GetReverse()->GetIndex(); + + entranceOverrides.push_back({ + .index = originalIndex, + .destination = destinationIndex, + .blueWarp = originalBlueWarp, + .override = replacementIndex, + .overrideDestination = replacementDestinationIndex, + }); + + message = "\tOriginal: " + std::to_string(originalIndex) + "\n"; + SPDLOG_INFO(message); + message = "\tReplacement " + std::to_string(replacementIndex) + "\n"; + SPDLOG_INFO(message); + } +} + +std::vector> playthroughEntrances; diff --git a/soh/soh/Enhancements/randomizer/3drando/entrance.hpp b/soh/soh/Enhancements/randomizer/3drando/entrance.hpp new file mode 100644 index 000000000..a9b29bca5 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/entrance.hpp @@ -0,0 +1,320 @@ +#pragma once + +#include "keys.hpp" +#include "location_access.hpp" +#include "debug.hpp" + +#include +#include + +#define ENTRANCE_SHUFFLE_SUCCESS 0 +#define ENTRANCE_SHUFFLE_FAILURE 1 + + +typedef struct { + int16_t index; + int16_t destination; + int16_t blueWarp; + int16_t override; + int16_t overrideDestination; +} EntranceOverride; + +typedef enum { + ENTRANCE_GROUP_NO_GROUP, + ENTRANCE_GROUP_KOKIRI_FOREST, + ENTRANCE_GROUP_LOST_WOODS, + ENTRANCE_GROUP_KAKARIKO, + ENTRANCE_GROUP_GRAVEYARD, + ENTRANCE_GROUP_DEATH_MOUNTAIN_TRAIL, + ENTRANCE_GROUP_DEATH_MOUNTAIN_CRATER, + ENTRANCE_GROUP_GORON_CITY, + ENTRANCE_GROUP_ZORAS_DOMAIN, + ENTRANCE_GROUP_HYRULE_FIELD, + ENTRANCE_GROUP_LON_LON_RANCH, + ENTRANCE_GROUP_LAKE_HYLIA, + ENTRANCE_GROUP_GERUDO_VALLEY, + ENTRANCE_GROUP_HAUNTED_WASTELAND, + ENTRANCE_GROUP_MARKET, + ENTRANCE_GROUP_HYRULE_CASTLE, + SPOILER_ENTRANCE_GROUP_COUNT, +} SpoilerEntranceGroup; + +typedef enum { + ENTRANCE_TYPE_OVERWORLD, + ENTRANCE_TYPE_INTERIOR, + ENTRANCE_TYPE_GROTTO, + ENTRANCE_TYPE_DUNGEON, + ENTRANCE_TYPE_COUNT, +} TrackerEntranceType; + +typedef struct { + int16_t index; + char* name; + SpoilerEntranceGroup group; + TrackerEntranceType type; + uint8_t oneExit; +} EntranceData; + +typedef struct { + uint8_t EntranceCount; + uint16_t GroupEntranceCounts[SPOILER_ENTRANCE_GROUP_COUNT]; + uint16_t GroupOffsets[SPOILER_ENTRANCE_GROUP_COUNT]; +} EntranceTrackingData; + +extern std::list entranceOverrides; + +enum class EntranceType { + None, + OwlDrop, + Spawn, + WarpSong, + Dungeon, + GanonDungeon, + Interior, + SpecialInterior, + GrottoGrave, + Overworld, + Extra, + All, +}; + +class Entrance { +public: + + Entrance(uint32_t connectedRegion_, std::vector conditions_met_) + : connectedRegion(connectedRegion_) { + conditions_met.resize(2); + for (size_t i = 0; i < conditions_met_.size(); i++) { + conditions_met[i] = conditions_met_[i]; + } + } + + bool GetConditionsMet() const { + if (Settings::Logic.Is(LOGIC_NONE) || Settings::Logic.Is(LOGIC_VANILLA)) { + return true; + } else if (Settings::Logic.Is(LOGIC_GLITCHLESS)) { + return conditions_met[0](); + } else if (Settings::Logic.Is(LOGIC_GLITCHED)) { + if (conditions_met[0]()) { + return true; + } else if (conditions_met[1] != NULL) { + return conditions_met[1](); + } + } + return false; + } + + std::string to_string() const { + return AreaTable(parentRegion)->regionName + " -> " + AreaTable(connectedRegion)->regionName; + } + + void SetName(std::string name_ = "") { + if (name_ == "") { + name = AreaTable(parentRegion)->regionName + " -> " + AreaTable(connectedRegion)->regionName; + } else { + name = std::move(name_); + } + + } + + std::string GetName() const { + return name; + } + + void printAgeTimeAccess() { + CitraPrint("Name: "); + CitraPrint(name); + auto message = "Child Day: " + std::to_string(CheckConditionAtAgeTime(Logic::IsChild, Logic::AtDay)) + "\t" + "Child Night: " + std::to_string(CheckConditionAtAgeTime(Logic::IsChild, Logic::AtNight)) + "\t" + "Adult Day: " + std::to_string(CheckConditionAtAgeTime(Logic::IsAdult, Logic::AtDay)) + "\t" + "Adult Night: " + std::to_string(CheckConditionAtAgeTime(Logic::IsAdult, Logic::AtNight)); + CitraPrint(message); + } + + bool ConditionsMet(bool allAgeTimes = false) const { + + Area* parent = AreaTable(parentRegion); + int conditionsMet = 0; + + if (allAgeTimes && !parent->AllAccess()) { + return false; + } + + //check all possible day/night condition combinations + conditionsMet = (parent->childDay && CheckConditionAtAgeTime(Logic::IsChild, Logic::AtDay, allAgeTimes)) + + (parent->childNight && CheckConditionAtAgeTime(Logic::IsChild, Logic::AtNight, allAgeTimes)) + + (parent->adultDay && CheckConditionAtAgeTime(Logic::IsAdult, Logic::AtDay, allAgeTimes)) + + (parent->adultNight && CheckConditionAtAgeTime(Logic::IsAdult, Logic::AtNight, allAgeTimes)); + + return conditionsMet && (!allAgeTimes || conditionsMet == 4); + } + + uint32_t Getuint32_t() const { + return connectedRegion; + } + + //set the logic to be a specific age and time of day and see if the condition still holds + bool CheckConditionAtAgeTime(bool& age, bool& time, bool passAnyway = false) const { + + Logic::IsChild = false; + Logic::IsAdult = false; + Logic::AtDay = false; + Logic::AtNight = false; + + time = true; + age = true; + + Logic::UpdateHelpers(); + return GetConditionsMet() && (connectedRegion != NONE || passAnyway); + } + + uint32_t GetConnectedRegionKey() const { + return connectedRegion; + } + + Area* GetConnectedRegion() const { + return AreaTable(connectedRegion); + } + + void SetParentRegion(uint32_t newParent) { + parentRegion = newParent; + } + + uint32_t GetParentRegionKey() const { + return parentRegion; + } + + Area* GetParentRegion() const { + return AreaTable(parentRegion); + } + + void SetNewEntrance(uint32_t newRegion) { + connectedRegion = newRegion; + } + + void SetAsShuffled() { + shuffled = true; + } + + bool IsShuffled() const { + return shuffled; + } + + bool IsAddedToPool() const { + return addedToPool; + } + + void AddToPool() { + addedToPool = true; + } + + void RemoveFromPool() { + addedToPool = false; + } + + void SetAsPrimary() { + primary = true; + } + + bool IsPrimary() const { + return primary; + } + + int16_t GetIndex() const { + return index; + } + + void SetIndex(int16_t newIndex) { + index = newIndex; + } + + int16_t GetBlueWarp() const { + return blueWarp; + } + + void SetBlueWarp(int16_t newBlueWarp) { + blueWarp = newBlueWarp; + } + + Entrance* GetAssumed() const { + return assumed; + } + + void SetReplacement(Entrance* newReplacement) { + replacement = newReplacement; + } + + Entrance* GetReplacement() const { + return replacement; + } + + EntranceType GetType() const { + return type; + } + + void SetType(EntranceType newType) { + type = newType; + } + + Entrance* GetReverse() const { + return reverse; + } + + void Connect(uint32_t newConnectedRegion) { + connectedRegion = newConnectedRegion; + AreaTable(newConnectedRegion)->entrances.push_front(this); + } + + uint32_t Disconnect() { + AreaTable(connectedRegion)->entrances.remove_if([this](const auto entrance){return this == entrance;}); + uint32_t previouslyConnected = connectedRegion; + connectedRegion = NONE; + return previouslyConnected; + } + + void BindTwoWay(Entrance* otherEntrance) { + reverse = otherEntrance; + otherEntrance->reverse = this; + } + + Entrance* GetNewTarget() { + AreaTable(ROOT)->AddExit(ROOT, connectedRegion, []{return true;}); + Entrance* targetEntrance = AreaTable(ROOT)->GetExit(connectedRegion); + targetEntrance->SetReplacement(this); + targetEntrance->SetName(GetParentRegion()->regionName + " -> " + GetConnectedRegion()->regionName); + return targetEntrance; + } + + Entrance* AssumeReachable() { + if (assumed == nullptr) { + assumed = GetNewTarget(); + Disconnect(); + } + return assumed; + } + +private: + uint32_t parentRegion; + uint32_t connectedRegion; + std::vector conditions_met; + + //Entrance Randomizer stuff + EntranceType type = EntranceType::None; + Entrance* target = nullptr; + Entrance* reverse = nullptr; + Entrance* assumed = nullptr; + Entrance* replacement = nullptr; + int16_t index = 0xFFFF; + int16_t blueWarp = 0; + bool shuffled = false; + bool primary = false; + bool addedToPool = false; + std::string name = ""; +}; + +int ShuffleAllEntrances(); +void CreateEntranceOverrides(); +EntranceTrackingData* GetEntranceTrackingData(); + +extern std::vector> playthroughEntrances; +extern bool noRandomEntrances; diff --git a/soh/soh/Enhancements/randomizer/3drando/fill.cpp b/soh/soh/Enhancements/randomizer/3drando/fill.cpp new file mode 100644 index 000000000..b9cf75518 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/fill.cpp @@ -0,0 +1,1074 @@ +#include "fill.hpp" + +#include "custom_messages.hpp" +#include "dungeon.hpp" +#include "item_location.hpp" +#include "item_pool.hpp" +#include "location_access.hpp" +#include "logic.hpp" +#include "random.hpp" +#include "spoiler_log.hpp" +#include "starting_inventory.hpp" +#include "hints.hpp" +#include "hint_list.hpp" +#include "entrance.hpp" +#include "shops.hpp" +#include "debug.hpp" + +#include +#include +#include + +using namespace CustomMessages; +using namespace Logic; +using namespace Settings; + +static bool placementFailure = false; + +static void RemoveStartingItemsFromPool() { + for (uint32_t startingItem : StartingInventory) { + for (size_t i = 0; i < ItemPool.size(); i++) { + if (startingItem == BIGGORON_SWORD) { + if (ItemPool[i] == GIANTS_KNIFE || ItemPool[i] == BIGGORON_SWORD) { + ItemPool[i] = GetJunkItem(); + } + continue; + } else if (startingItem == ItemPool[i] || (ItemTable(startingItem).IsBottleItem() && ItemTable(ItemPool[i]).IsBottleItem())) { + if (AdditionalHeartContainers > 0 && (startingItem == PIECE_OF_HEART || startingItem == TREASURE_GAME_HEART)) { + ItemPool[i] = HEART_CONTAINER; + AdditionalHeartContainers--; + } else { + ItemPool[i] = GetJunkItem(); + } + break; + } + } + } +} + +//This function will propogate Time of Day access through the entrance +static bool UpdateToDAccess(Entrance* entrance, SearchMode mode) { + + bool ageTimePropogated = false; + + //propogate childDay, childNight, adultDay, and adultNight separately + Area* parent = entrance->GetParentRegion(); + Area* connection = entrance->GetConnectedRegion(); + + if (!connection->childDay && parent->childDay && entrance->CheckConditionAtAgeTime(Logic::IsChild, AtDay)) { + connection->childDay = true; + ageTimePropogated = true; + } + if (!connection->childNight && parent->childNight && entrance->CheckConditionAtAgeTime(Logic::IsChild, AtNight)) { + connection->childNight = true; + ageTimePropogated = true; + } + if (!connection->adultDay && parent->adultDay && entrance->CheckConditionAtAgeTime(IsAdult, AtDay)) { + connection->adultDay = true; + ageTimePropogated = true; + } + if (!connection->adultNight && parent->adultNight && entrance->CheckConditionAtAgeTime(IsAdult, AtNight)) { + connection->adultNight = true; + ageTimePropogated = true; + } + + //special check for temple of time + bool propogateTimeTravel = mode != SearchMode::TimePassAccess && mode != SearchMode::TempleOfTimeAccess; + if (!AreaTable(ROOT)->Adult() && AreaTable(TOT_BEYOND_DOOR_OF_TIME)->Child() && propogateTimeTravel) { + AreaTable(ROOT)->adultDay = AreaTable(TOT_BEYOND_DOOR_OF_TIME)->childDay; + AreaTable(ROOT)->adultNight = AreaTable(TOT_BEYOND_DOOR_OF_TIME)->childNight; + } else if (!AreaTable(ROOT)->Child() && AreaTable(TOT_BEYOND_DOOR_OF_TIME)->Adult() && propogateTimeTravel){ + AreaTable(ROOT)->childDay = AreaTable(TOT_BEYOND_DOOR_OF_TIME)->adultDay; + AreaTable(ROOT)->childNight = AreaTable(TOT_BEYOND_DOOR_OF_TIME)->adultNight; + } + + return ageTimePropogated; +} + +// Various checks that need to pass for the world to be validated as completable +static void ValidateWorldChecks(SearchMode& mode, bool checkPoeCollectorAccess, bool checkOtherEntranceAccess, std::vector& areaPool) { + // Condition for validating Temple of Time Access + if (mode == SearchMode::TempleOfTimeAccess && ((Settings::ResolvedStartingAge == AGE_CHILD && AreaTable(TEMPLE_OF_TIME)->Adult()) || (Settings::ResolvedStartingAge == AGE_ADULT && AreaTable(TEMPLE_OF_TIME)->Child()) || !checkOtherEntranceAccess)) { + mode = SearchMode::ValidStartingRegion; + } + // Condition for validating a valid starting region + if (mode == SearchMode::ValidStartingRegion) { + bool childAccess = Settings::ResolvedStartingAge == AGE_CHILD || AreaTable(TOT_BEYOND_DOOR_OF_TIME)->Child(); + bool adultAccess = Settings::ResolvedStartingAge == AGE_ADULT || AreaTable(TOT_BEYOND_DOOR_OF_TIME)->Adult(); + + Area* kokiri = AreaTable(KOKIRI_FOREST); + Area* kakariko = AreaTable(KAKARIKO_VILLAGE); + + if ((childAccess && (kokiri->Child() || kakariko->Child())) || + (adultAccess && (kokiri->Adult() || kakariko->Adult())) || + !checkOtherEntranceAccess) { + mode = SearchMode::PoeCollectorAccess; + ApplyStartingInventory(); + Logic::NoBottles = true; + } + } + // Condition for validating Poe Collector Access + if (mode == SearchMode::PoeCollectorAccess && (AreaTable(MARKET_GUARD_HOUSE)->Adult() || !checkPoeCollectorAccess)) { + // Apply all items that are necessary for checking all location access + std::vector itemsToPlace = + FilterFromPool(ItemPool, [](const auto i) { return ItemTable(i).IsAdvancement(); }); + for (uint32_t unplacedItem : itemsToPlace) { + ItemTable(unplacedItem).ApplyEffect(); + } + // Reset access as the non-starting age + if (Settings::ResolvedStartingAge == AGE_CHILD) { + for (uint32_t areaKey : areaPool) { + AreaTable(areaKey)->adultDay = false; + AreaTable(areaKey)->adultNight = false; + } + } else { + for (uint32_t areaKey : areaPool) { + AreaTable(areaKey)->childDay = false; + AreaTable(areaKey)->childNight = false; + } + } + mode = SearchMode::AllLocationsReachable; + } else { + Logic::NoBottles = false; + } +} + +//Get the max number of tokens that can possibly be useful +static int GetMaxGSCount() { + //If bridge or LACS is set to tokens, get how many are required + int maxBridge = 0; + int maxLACS = 0; + if (Settings::Bridge.Is(RAINBOWBRIDGE_TOKENS)) { + maxBridge = Settings::BridgeTokenCount.Value(); + } + if (Settings::GanonsBossKey.Is(GANONSBOSSKEY_LACS_TOKENS)) { + maxLACS = Settings::LACSTokenCount.Value(); + } + maxBridge = std::max(maxBridge, maxLACS); + //Get the max amount of GS which could be useful from token reward locations + int maxUseful = 0; + //If the highest advancement item is a token, we know it is useless since it won't lead to an otherwise useful item + if (Location(KAK_50_GOLD_SKULLTULA_REWARD)->GetPlacedItem().IsAdvancement() && Location(KAK_50_GOLD_SKULLTULA_REWARD)->GetPlacedItem().GetItemType() != ITEMTYPE_TOKEN) { + maxUseful = 50; + } + else if (Location(KAK_40_GOLD_SKULLTULA_REWARD)->GetPlacedItem().IsAdvancement() && Location(KAK_40_GOLD_SKULLTULA_REWARD)->GetPlacedItem().GetItemType() != ITEMTYPE_TOKEN) { + maxUseful = 40; + } + else if (Location(KAK_30_GOLD_SKULLTULA_REWARD)->GetPlacedItem().IsAdvancement() && Location(KAK_30_GOLD_SKULLTULA_REWARD)->GetPlacedItem().GetItemType() != ITEMTYPE_TOKEN) { + maxUseful = 30; + } + else if (Location(KAK_20_GOLD_SKULLTULA_REWARD)->GetPlacedItem().IsAdvancement() && Location(KAK_20_GOLD_SKULLTULA_REWARD)->GetPlacedItem().GetItemType() != ITEMTYPE_TOKEN) { + maxUseful = 20; + } + else if (Location(KAK_10_GOLD_SKULLTULA_REWARD)->GetPlacedItem().IsAdvancement() && Location(KAK_10_GOLD_SKULLTULA_REWARD)->GetPlacedItem().GetItemType() != ITEMTYPE_TOKEN) { + maxUseful = 10; + } + //Return max of the two possible reasons tokens could be important + return std::max(maxUseful, maxBridge); +} + +std::string GetShopItemBaseName(std::string itemName) { + std::string baseName = itemName.erase(0, 4); //Delete "Buy " + //Delete amount, if present (so when it looks like Buy Deku Nut (10) remove the (10)) + if (baseName.find("(") != std::string::npos) { + baseName = baseName.erase(baseName.find("(")); + } + //Do the same for [] (only applies to red potions, other things with [] also have a ()) + if (baseName.find("[") != std::string::npos) { + baseName = baseName.erase(baseName.find("[")); + } + return baseName; +} + +std::vector GetEmptyLocations(std::vector allowedLocations) { + return FilterFromPool(allowedLocations, [](const auto loc){ return Location(loc)->GetPlaceduint32_t() == NONE;}); +} + +std::vector GetAllEmptyLocations() { + return FilterFromPool(allLocations, [](const auto loc) { return Location(loc)->GetPlaceduint32_t() == NONE; }); +} + +//This function will return a vector of ItemLocations that are accessible with +//where items have been placed so far within the world. The allowedLocations argument +//specifies the pool of locations that we're trying to search for an accessible location in +std::vector GetAccessibleLocations(const std::vector& allowedLocations, SearchMode mode /* = SearchMode::ReachabilitySearch*/, std::string ignore /*= ""*/, bool checkPoeCollectorAccess /*= false*/, bool checkOtherEntranceAccess /*= false*/) { + std::vector accessibleLocations; + // Reset all access to begin a new search + if (mode < SearchMode::ValidateWorld) { + ApplyStartingInventory(); + } + Areas::AccessReset(); + LocationReset(); + std::vector areaPool = {ROOT}; + + if (mode == SearchMode::ValidateWorld) { + mode = SearchMode::TimePassAccess; + AreaTable(ROOT)->childNight = true; + AreaTable(ROOT)->adultNight = true; + AreaTable(ROOT)->childDay = true; + AreaTable(ROOT)->adultDay = true; + allLocationsReachable = false; + } + + //Variables for playthrough + int gsCount = 0; + const int maxGsCount = mode == SearchMode::GeneratePlaythrough ? GetMaxGSCount() : 0; //If generating playthrough want the max that's possibly useful, else doesn't matter + bool bombchusFound = false; + std::vector buyIgnores; + + //Variables for search + std::vector newItemLocations; + bool updatedEvents = false; + bool ageTimePropogated = false; + bool firstIteration = true; + + //Variables for Time Pass access + bool timePassChildDay = false; + bool timePassChildNight = false; + bool timePassAdultDay = false; + bool timePassAdultNight = false; + + // Main access checking loop + while (newItemLocations.size() > 0 || updatedEvents || ageTimePropogated || firstIteration) { + firstIteration = false; + ageTimePropogated = false; + updatedEvents = false; + + for (ItemLocation* location : newItemLocations) { + location->ApplyPlacedItemEffect(); + } + newItemLocations.clear(); + + std::vector itemSphere; + std::list entranceSphere; + + for (size_t i = 0; i < areaPool.size(); i++) { + Area* area = AreaTable(areaPool[i]); + + if (area->UpdateEvents(mode)){ + updatedEvents = true; + } + + // If we're checking for TimePass access do that for each area as it's being updated. + // TimePass Access is satisfied when every AgeTime can reach an area with TimePass + // without the aid of TimePass. During this mode, TimePass won't update ToD access + // in any area. + if (mode == SearchMode::TimePassAccess) { + if (area->timePass) { + if (area->childDay) { + timePassChildDay = true; + } + if (area->childNight) { + timePassChildNight = true; + } + if (area->adultDay) { + timePassAdultDay = true; + } + if (area->adultNight) { + timePassAdultNight = true; + } + } + // Condition for validating that all startring AgeTimes have timepass access + // Once satisifed, change the mode to begin checking for Temple of Time Access + if ((timePassChildDay && timePassChildNight && timePassAdultDay && timePassAdultNight) || !checkOtherEntranceAccess) { + mode = SearchMode::TempleOfTimeAccess; + } + } + + //for each exit in this area + for (auto& exit : area->exits) { + + //Update Time of Day Access for the exit + if (UpdateToDAccess(&exit, mode)) { + ageTimePropogated = true; + ValidateWorldChecks(mode, checkPoeCollectorAccess, checkOtherEntranceAccess, areaPool); + } + + //If the exit is accessible and hasn't been added yet, add it to the pool + Area* exitArea = exit.GetConnectedRegion(); + if (!exitArea->addedToPool && exit.ConditionsMet()) { + exitArea->addedToPool = true; + areaPool.push_back(exit.Getuint32_t()); + } + + // Add shuffled entrances to the entrance playthrough + if (mode == SearchMode::GeneratePlaythrough && exit.IsShuffled() && !exit.IsAddedToPool() && !noRandomEntrances) { + entranceSphere.push_back(&exit); + exit.AddToPool(); + // Don't list a coupled entrance from both directions + if (exit.GetReplacement()->GetReverse() != nullptr /*&& !DecoupleEntrances*/) { + exit.GetReplacement()->GetReverse()->AddToPool(); + } + } + } + + //for each ItemLocation in this area + if (mode < SearchMode::ValidateWorld) { + for (size_t k = 0; k < area->locations.size(); k++) { + LocationAccess& locPair = area->locations[k]; + uint32_t loc = locPair.GetLocation(); + ItemLocation* location = Location(loc); + + if (!location->IsAddedToPool() && locPair.ConditionsMet()) { + + location->AddToPool(); + + if (location->GetPlaceduint32_t() == NONE) { + accessibleLocations.push_back(loc); //Empty location, consider for placement + } else { + //If ignore has a value, we want to check if the item location should be considered or not + //This is necessary due to the below preprocessing for playthrough generation + if (ignore != "") { + ItemType type = location->GetPlacedItem().GetItemType(); + std::string itemName(location->GetPlacedItemName().GetEnglish()); + //If we want to ignore tokens, only add if not a token + if (ignore == "Tokens" && type != ITEMTYPE_TOKEN) { + newItemLocations.push_back(location); + } + //If we want to ignore bombchus, only add if bombchu is not in the name + else if (ignore == "Bombchus" && itemName.find("Bombchu") == std::string::npos) { + newItemLocations.push_back(location); + } + //We want to ignore a specific Buy item name + else if (ignore != "Tokens" && ignore != "Bombchus") { + if ((type == ITEMTYPE_SHOP && ignore != GetShopItemBaseName(itemName)) || type != ITEMTYPE_SHOP) { + newItemLocations.push_back(location); + } + } + } + //If it doesn't, we can just add the location + else { + newItemLocations.push_back(location); //Add item to cache to be considered in logic next iteration + } + } + + //Playthrough stuff + //Generate the playthrough, so we want to add advancement items, unless we know to ignore them + if (mode == SearchMode::GeneratePlaythrough) { + //Item is an advancement item, figure out if it should be added to this sphere + if (!playthroughBeatable && location->GetPlacedItem().IsAdvancement()) { + ItemType type = location->GetPlacedItem().GetItemType(); + std::string itemName(location->GetPlacedItemName().GetEnglish()); + bool bombchus = itemName.find("Bombchu") != std::string::npos; //Is a bombchu location + + //Decide whether to exclude this location + //This preprocessing is done to reduce the amount of searches performed in PareDownPlaythrough + //Want to exclude: + //1) Tokens after the last potentially useful one (the last one that gives an advancement item or last for token bridge) + //2) Bombchus after the first (including buy bombchus) + //3) Buy items of the same type, after the first (So only see Buy Deku Nut of any amount once) + bool exclude = true; + //Exclude tokens after the last possibly useful one + if (type == ITEMTYPE_TOKEN && gsCount < maxGsCount) { + gsCount++; + exclude = false; + } + //Only print first bombchu location found + else if (bombchus && !bombchusFound) { + bombchusFound = true; + exclude = false; + } + //Handle buy items + //If ammo drops are off, don't do this step, since buyable ammo becomes logically important + else if (AmmoDrops.IsNot(AMMODROPS_NONE) && !(bombchus && bombchusFound) && type == ITEMTYPE_SHOP) { + //Only check each buy item once + std::string buyItem = GetShopItemBaseName(itemName); + //Buy item not in list to ignore, add it to list and write to playthrough + if (std::find(buyIgnores.begin(), buyIgnores.end(), buyItem) == buyIgnores.end()) { + exclude = false; + buyIgnores.push_back(buyItem); + } + } + //Add all other advancement items + else if (!bombchus && type != ITEMTYPE_TOKEN && (AmmoDrops.Is(AMMODROPS_NONE) || type != ITEMTYPE_SHOP)) { + exclude = false; + } + //Has not been excluded, add to playthrough + if (!exclude) { + itemSphere.push_back(loc); + } + } + //Triforce has been found, seed is beatable, nothing else in this or future spheres matters + else if (location->GetPlaceduint32_t() == TRIFORCE) { + itemSphere.clear(); + itemSphere.push_back(loc); + playthroughBeatable = true; + } + } + //All we care about is if the game is beatable, used to pare down playthrough + else if (location->GetPlaceduint32_t() == TRIFORCE && mode == SearchMode::CheckBeatable) { + playthroughBeatable = true; + return {}; //Return early for efficiency + } + } + } + } + } + + if (mode == SearchMode::GeneratePlaythrough && itemSphere.size() > 0) { + playthroughLocations.push_back(itemSphere); + } + if (mode == SearchMode::GeneratePlaythrough && entranceSphere.size() > 0 && !noRandomEntrances) { + playthroughEntrances.push_back(entranceSphere); + } + } + + //Check to see if all locations were reached + if (mode == SearchMode::AllLocationsReachable) { + allLocationsReachable = true; + for (const uint32_t loc : allLocations) { + if (!Location(loc)->IsAddedToPool()) { + allLocationsReachable = false; + auto message = "Location " + Location(loc)->GetName() + " not reachable\n"; + SPDLOG_INFO(message); + #ifndef ENABLE_DEBUG + break; + #endif + } + } + return {}; + } + + erase_if(accessibleLocations, [&allowedLocations](uint32_t loc){ + for (uint32_t allowedLocation : allowedLocations) { + if (loc == allowedLocation || Location(loc)->GetPlaceduint32_t() != NONE) { + return false; + } + } + return true; + }); + return accessibleLocations; +} + +static void GeneratePlaythrough() { + playthroughBeatable = false; + LogicReset(); + GetAccessibleLocations(allLocations, SearchMode::GeneratePlaythrough); +} + +//Remove unnecessary items from playthrough by removing their location, and checking if game is still beatable +//To reduce searches, some preprocessing is done in playthrough generation to avoid adding obviously unnecessary items +static void PareDownPlaythrough() { + std::vector toAddBackItem; + //Start at sphere before Ganon's and count down + for (int i = playthroughLocations.size() - 2; i >= 0; i--) { + //Check each item location in sphere + std::vector erasableIndices; + std::vector sphere = playthroughLocations.at(i); + for (int j = sphere.size() - 1; j >= 0; j--) { + uint32_t loc = sphere.at(j); + uint32_t copy = Location(loc)->GetPlaceduint32_t(); //Copy out item + Location(loc)->SetPlacedItem(NONE); //Write in empty item + playthroughBeatable = false; + LogicReset(); + + std::string ignore = ""; + if (ItemTable(copy).GetItemType() == ITEMTYPE_TOKEN) { + ignore = "Tokens"; + } + else if (ItemTable(copy).GetName().GetEnglish().find("Bombchu") != std::string::npos) { + ignore = "Bombchus"; + } + else if (ItemTable(copy).GetItemType() == ITEMTYPE_SHOP) { + ignore = GetShopItemBaseName(ItemTable(copy).GetName().GetEnglish()); + } + + GetAccessibleLocations(allLocations, SearchMode::CheckBeatable, ignore); //Check if game is still beatable + + //Playthrough is still beatable without this item, therefore it can be removed from playthrough section. + if (playthroughBeatable) { + //Uncomment to print playthrough deletion log in citra + // std::string itemname(ItemTable(copy).GetName().GetEnglish()); + // std::string locationname(Location(loc)->GetName()); + // std::string removallog = itemname + " at " + locationname + " removed from playthrough"; + // CitraPrint(removallog); + playthroughLocations[i].erase(playthroughLocations[i].begin() + j); + Location(loc)->SetDelayedItem(copy); //Game is still beatable, don't add back until later + toAddBackItem.push_back(loc); + } + else { + Location(loc)->SetPlacedItem(copy); //Immediately put item back so game is beatable again + } + } + } + + //Some spheres may now be empty, remove these + for (int i = playthroughLocations.size() - 2; i >= 0; i--) { + if (playthroughLocations.at(i).size() == 0) { + playthroughLocations.erase(playthroughLocations.begin() + i); + } + } + + //Now we can add back items which were removed previously + for (uint32_t loc : toAddBackItem) { + Location(loc)->SaveDelayedItem(); + } +} + +//Very similar to PareDownPlaythrough except it creates the list of Way of the Hero items +//Way of the Hero items are more specific than playthrough items in that they are items which *must* +// be obtained to logically be able to complete the seed, rather than playthrough items which +// are just possible items you *can* collect to complete the seed. +static void CalculateWotH() { + //First copy locations from the 2-dimensional playthroughLocations into the 1-dimensional wothLocations + //size - 1 so Triforce is not counted + for (size_t i = 0; i < playthroughLocations.size() - 1; i++) { + for (size_t j = 0; j < playthroughLocations[i].size(); j++) { + if (Location(playthroughLocations[i][j])->IsHintable()) { + wothLocations.push_back(playthroughLocations[i][j]); + } + } + } + + //Now go through and check each location, seeing if it is strictly necessary for game completion + for (int i = wothLocations.size() - 1; i >= 0; i--) { + uint32_t loc = wothLocations[i]; + uint32_t copy = Location(loc)->GetPlaceduint32_t(); //Copy out item + Location(loc)->SetPlacedItem(NONE); //Write in empty item + playthroughBeatable = false; + LogicReset(); + GetAccessibleLocations(allLocations, SearchMode::CheckBeatable); //Check if game is still beatable + Location(loc)->SetPlacedItem(copy); //Immediately put item back + //If removing this item and no other item caused the game to become unbeatable, then it is strictly necessary, so keep it + //Else, delete from wothLocations + if (playthroughBeatable) { + wothLocations.erase(wothLocations.begin() + i); + } + } + + playthroughBeatable = true; + LogicReset(); + GetAccessibleLocations(allLocations); +} + +//Will place things completely randomly, no logic checks are performed +static void FastFill(std::vector items, std::vector locations, bool endOnItemsEmpty = false) { + //Loop until locations are empty, or also end if items are empty and the parameters specify to end then + while (!locations.empty() && (!endOnItemsEmpty || !items.empty())) { + uint32_t loc = RandomElement(locations, true); + Location(loc)->SetAsHintable(); + PlaceItemInLocation(loc, RandomElement(items, true)); + + if (items.empty() && !endOnItemsEmpty) { + items.push_back(GetJunkItem()); + } + } +} + +/* +| The algorithm places items in the world in reverse. +| This means we first assume we have every item in the item pool and +| remove an item and try to place it somewhere that is still reachable +| This method helps distribution of items locked behind many requirements. +| - OoT Randomizer +*/ +static void AssumedFill(const std::vector& items, const std::vector& allowedLocations, + bool setLocationsAsHintable = false) { + + if (items.size() > allowedLocations.size()) { + printf("\x1b[2;2HERROR: MORE ITEMS THAN LOCATIONS IN GIVEN LISTS"); + SPDLOG_INFO("Items:\n"); + for (const uint32_t item : items) { + SPDLOG_INFO("\t"); + SPDLOG_INFO(ItemTable(item).GetName().GetEnglish()); + SPDLOG_INFO("\n"); + } + SPDLOG_INFO("\nAllowed Locations:\n"); + for (const uint32_t loc : allowedLocations) { + SPDLOG_INFO("\t"); + SPDLOG_INFO(Location(loc)->GetName()); + SPDLOG_INFO("\n"); + } + placementFailure = true; + return; + } + + if (Settings::Logic.Is(LOGIC_NONE)) { + FastFill(items, GetEmptyLocations(allowedLocations), true); + return; + } + + // keep retrying to place everything until it works or takes too long + int retries = 10; + bool unsuccessfulPlacement = false; + std::vector attemptedLocations; + do { + retries--; + if (retries <= 0) { + placementFailure = true; + return; + } + unsuccessfulPlacement = false; + std::vector itemsToPlace = items; + + // copy all not yet placed advancement items so that we can apply their effects for the fill algorithm + std::vector itemsToNotPlace = + FilterFromPool(ItemPool, [](const auto i) { return ItemTable(i).IsAdvancement(); }); + + // shuffle the order of items to place + Shuffle(itemsToPlace); + while (!itemsToPlace.empty()) { + uint32_t item = std::move(itemsToPlace.back()); + ItemTable(item).SetAsPlaythrough(); + itemsToPlace.pop_back(); + + // assume we have all unplaced items + LogicReset(); + for (uint32_t unplacedItem : itemsToPlace) { + ItemTable(unplacedItem).ApplyEffect(); + } + for (uint32_t unplacedItem : itemsToNotPlace) { + ItemTable(unplacedItem).ApplyEffect(); + } + + // get all accessible locations that are allowed + const std::vector accessibleLocations = GetAccessibleLocations(allowedLocations); + + // retry if there are no more locations to place items + if (accessibleLocations.empty()) { + + SPDLOG_INFO("\nCANNOT PLACE "); + SPDLOG_INFO(ItemTable(item).GetName().GetEnglish()); + SPDLOG_INFO(". TRYING AGAIN...\n"); + +#ifdef ENABLE_DEBUG + Areas::DumpWorldGraph(ItemTable(item).GetName().GetEnglish()); + PlacementLog_Write(); +#endif + + // reset any locations that got an item + for (uint32_t loc : attemptedLocations) { + Location(loc)->SetPlacedItem(NONE); + itemsPlaced--; + } + attemptedLocations.clear(); + + unsuccessfulPlacement = true; + break; + } + + // place the item within one of the allowed locations + uint32_t selectedLocation = RandomElement(accessibleLocations); + PlaceItemInLocation(selectedLocation, item); + attemptedLocations.push_back(selectedLocation); + + // This tells us the location went through the randomization algorithm + // to distinguish it from locations which did not or that the player already + // knows + if (setLocationsAsHintable) { + Location(selectedLocation)->SetAsHintable(); + } + + // If ALR is off, then we check beatability after placing the item. + // If the game is beatable, then we can stop placing items with logic. + if (!LocationsReachable) { + playthroughBeatable = false; + LogicReset(); + GetAccessibleLocations(allLocations, SearchMode::CheckBeatable); + if (playthroughBeatable) { + SPDLOG_INFO("Game beatable, now placing items randomly. " + std::to_string(itemsToPlace.size()) + + " major items remaining.\n\n"); + FastFill(itemsToPlace, GetEmptyLocations(allowedLocations), true); + return; + } + } + } + } while (unsuccessfulPlacement); +} + +//This function will specifically randomize dungeon rewards for the End of Dungeons +//setting, or randomize one dungeon reward to Link's Pocket if that setting is on +static void RandomizeDungeonRewards() { + + //quest item bit mask of each stone/medallion for the savefile + static constexpr std::array bitMaskTable = { + 0x00040000, //Kokiri Emerald + 0x00080000, //Goron Ruby + 0x00100000, //Zora Sapphire + 0x00000001, //Forest Medallion + 0x00000002, //Fire Medallion + 0x00000004, //Water Medallion + 0x00000008, //Spirit Medallion + 0x00000010, //Shadow Medallion + 0x00000020, //Light Medallion + }; + int baseOffset = ItemTable(KOKIRI_EMERALD).GetItemID(); + + //End of Dungeons includes Link's Pocket + if (ShuffleRewards.Is(REWARDSHUFFLE_END_OF_DUNGEON)) { + //get stones and medallions + std::vector rewards = FilterAndEraseFromPool(ItemPool, [](const auto i) {return ItemTable(i).GetItemType() == ITEMTYPE_DUNGEONREWARD;}); + + // If there are less than 9 dungeon rewards, prioritize the actual dungeons + // for placement instead of Link's Pocket + if (rewards.size() < 9) { + PlaceItemInLocation(LINKS_POCKET, GREEN_RUPEE); + } + + if (Settings::Logic.Is(LOGIC_VANILLA)) { //Place dungeon rewards in vanilla locations + for (uint32_t loc : dungeonRewardLocations) { + Location(loc)->PlaceVanillaItem(); + } + } else { //Randomize dungeon rewards with assumed fill + AssumedFill(rewards, dungeonRewardLocations); + } + + for (size_t i = 0; i < dungeonRewardLocations.size(); i++) { + const auto index = Location(dungeonRewardLocations[i])->GetPlacedItem().GetItemID() - baseOffset; + rDungeonRewardOverrides[i] = index; + + //set the player's dungeon reward on file creation instead of pushing it to them at the start. + //This is done mainly because players are already familiar with seeing their dungeon reward + //before opening up their file + if (i == dungeonRewardLocations.size()-1) { + LinksPocketRewardBitMask = bitMaskTable[index]; + } + } + } else if (LinksPocketItem.Is(LINKSPOCKETITEM_DUNGEON_REWARD)) { + //get 1 stone/medallion + std::vector rewards = FilterFromPool(ItemPool, [](const auto i) {return ItemTable(i).GetItemType() == ITEMTYPE_DUNGEONREWARD;}); + // If there are no remaining stones/medallions, then Link's pocket won't get one + if (rewards.empty()) { + PlaceItemInLocation(LINKS_POCKET, GREEN_RUPEE); + return; + } + uint32_t startingReward = RandomElement(rewards, true); + + LinksPocketRewardBitMask = bitMaskTable[ItemTable(startingReward).GetItemID() - baseOffset]; + PlaceItemInLocation(LINKS_POCKET, startingReward); + //erase the stone/medallion from the Item Pool + FilterAndEraseFromPool(ItemPool, [startingReward](const uint32_t i) {return i == startingReward;}); + } +} + +//Fills any locations excluded by the player with junk items so that advancement items +//can't be placed there. +static void FillExcludedLocations() { + //Only fill in excluded locations that don't already have something and are forbidden + std::vector excludedLocations = FilterFromPool(allLocations, [](const auto loc){ + return Location(loc)->IsExcluded(); + }); + + for (uint32_t loc : excludedLocations) { + PlaceJunkInExcludedLocation(loc); + } +} + +//Function to handle the Own Dungeon setting +static void RandomizeOwnDungeon(const Dungeon::DungeonInfo* dungeon) { + std::vector dungeonLocations = dungeon->GetDungeonLocations(); + std::vector dungeonItems; + + //filter out locations that may be required to have songs placed at them + dungeonLocations = FilterFromPool(dungeonLocations, [](const auto loc){ + if (ShuffleSongs.Is(SONGSHUFFLE_SONG_LOCATIONS)) { + return !(Location(loc)->IsCategory(Category::cSong)); + } + if (ShuffleSongs.Is(SONGSHUFFLE_DUNGEON_REWARDS)) { + return !(Location(loc)->IsCategory(Category::cSongDungeonReward)); + } + return true; + }); + + //Add specific items that need be randomized within this dungeon + if (Keysanity.Is(KEYSANITY_OWN_DUNGEON) && dungeon->GetSmallKey() != NONE) { + std::vector dungeonSmallKeys = FilterAndEraseFromPool(ItemPool, [dungeon](const uint32_t i){ return i == dungeon->GetSmallKey();}); + AddElementsToPool(dungeonItems, dungeonSmallKeys); + } + + if ((BossKeysanity.Is(BOSSKEYSANITY_OWN_DUNGEON) && dungeon->GetBossKey() != GANONS_CASTLE_BOSS_KEY) || + (GanonsBossKey.Is(GANONSBOSSKEY_OWN_DUNGEON) && dungeon->GetBossKey() == GANONS_CASTLE_BOSS_KEY)) { + auto dungeonBossKey = FilterAndEraseFromPool(ItemPool, [dungeon](const uint32_t i){ return i == dungeon->GetBossKey();}); + AddElementsToPool(dungeonItems, dungeonBossKey); + } + + //randomize boss key and small keys together for even distribution + AssumedFill(dungeonItems, dungeonLocations); + + //randomize map and compass separately since they're not progressive + if (MapsAndCompasses.Is(MAPSANDCOMPASSES_OWN_DUNGEON) && dungeon->GetMap() != NONE && dungeon->GetCompass() != NONE) { + auto dungeonMapAndCompass = FilterAndEraseFromPool(ItemPool, [dungeon](const uint32_t i){ return i == dungeon->GetMap() || i == dungeon->GetCompass();}); + AssumedFill(dungeonMapAndCompass, dungeonLocations); + } +} + +/*Randomize items restricted to a certain set of locations. + The fill order of location groups is as follows: + - Own Dungeon + - Any Dungeon + - Overworld + Small Keys, Gerudo Keys, Boss Keys, Ganon's Boss Key, and/or dungeon rewards + will be randomized together if they have the same setting. Maps and Compasses + are randomized separately once the dungeon advancement items have all been placed.*/ +static void RandomizeDungeonItems() { + using namespace Dungeon; + + //Get Any Dungeon and Overworld group locations + std::vector anyDungeonLocations = FilterFromPool(allLocations, [](const auto loc){return Location(loc)->IsDungeon();}); + //overworldLocations defined in item_location.cpp + + //Create Any Dungeon and Overworld item pools + std::vector anyDungeonItems; + std::vector overworldItems; + + for (auto dungeon : dungeonList) { + if (Keysanity.Is(KEYSANITY_ANY_DUNGEON)) { + auto dungeonKeys = FilterAndEraseFromPool(ItemPool, [dungeon](const uint32_t i){return i == dungeon->GetSmallKey();}); + AddElementsToPool(anyDungeonItems, dungeonKeys); + } else if (Keysanity.Is(KEYSANITY_OVERWORLD)) { + auto dungeonKeys = FilterAndEraseFromPool(ItemPool, [dungeon](const uint32_t i){return i == dungeon->GetSmallKey();}); + AddElementsToPool(overworldItems, dungeonKeys); + } + + if (BossKeysanity.Is(BOSSKEYSANITY_ANY_DUNGEON) && dungeon->GetBossKey() != GANONS_CASTLE_BOSS_KEY) { + auto bossKey = FilterAndEraseFromPool(ItemPool, [dungeon](const uint32_t i){return i == dungeon->GetBossKey();}); + AddElementsToPool(anyDungeonItems, bossKey); + } else if (BossKeysanity.Is(BOSSKEYSANITY_OVERWORLD) && dungeon->GetBossKey() != GANONS_CASTLE_BOSS_KEY) { + auto bossKey = FilterAndEraseFromPool(ItemPool, [dungeon](const uint32_t i){return i == dungeon->GetBossKey();}); + AddElementsToPool(overworldItems, bossKey); + } + + if (GanonsBossKey.Is(GANONSBOSSKEY_ANY_DUNGEON)) { + auto ganonBossKey = FilterAndEraseFromPool(ItemPool, [](const auto i){return i == GANONS_CASTLE_BOSS_KEY;}); + AddElementsToPool(anyDungeonItems, ganonBossKey); + } else if (GanonsBossKey.Is(GANONSBOSSKEY_OVERWORLD)) { + auto ganonBossKey = FilterAndEraseFromPool(ItemPool, [](const auto i) { return i == GANONS_CASTLE_BOSS_KEY; }); + AddElementsToPool(overworldItems, ganonBossKey); + } + } + + if (GerudoKeys.Is(GERUDOKEYS_ANY_DUNGEON)) { + auto gerudoKeys = FilterAndEraseFromPool(ItemPool, [](const auto i) { return i == GERUDO_FORTRESS_SMALL_KEY; }); + AddElementsToPool(anyDungeonItems, gerudoKeys); + } else if (GerudoKeys.Is(GERUDOKEYS_OVERWORLD)) { + auto gerudoKeys = FilterAndEraseFromPool(ItemPool, [](const auto i) { return i == GERUDO_FORTRESS_SMALL_KEY; }); + AddElementsToPool(overworldItems, gerudoKeys); + } + + if (ShuffleRewards.Is(REWARDSHUFFLE_ANY_DUNGEON)) { + auto rewards = FilterAndEraseFromPool( + ItemPool, [](const auto i) { return ItemTable(i).GetItemType() == ITEMTYPE_DUNGEONREWARD; }); + AddElementsToPool(anyDungeonItems, rewards); + } else if (ShuffleRewards.Is(REWARDSHUFFLE_OVERWORLD)) { + auto rewards = FilterAndEraseFromPool( + ItemPool, [](const auto i) { return ItemTable(i).GetItemType() == ITEMTYPE_DUNGEONREWARD; }); + AddElementsToPool(overworldItems, rewards); + } + + //Randomize Any Dungeon and Overworld pools + AssumedFill(anyDungeonItems, anyDungeonLocations, true); + AssumedFill(overworldItems, overworldLocations, true); + + //Randomize maps and compasses after since they're not advancement items + for (auto dungeon : dungeonList) { + if (MapsAndCompasses.Is(MAPSANDCOMPASSES_ANY_DUNGEON)) { + auto mapAndCompassItems = FilterAndEraseFromPool(ItemPool, [dungeon](const uint32_t i){return i == dungeon->GetMap() || i == dungeon->GetCompass();}); + AssumedFill(mapAndCompassItems, anyDungeonLocations, true); + } else if (MapsAndCompasses.Is(MAPSANDCOMPASSES_OVERWORLD)) { + auto mapAndCompassItems = FilterAndEraseFromPool(ItemPool, [dungeon](const uint32_t i){return i == dungeon->GetMap() || i == dungeon->GetCompass();}); + AssumedFill(mapAndCompassItems, overworldLocations, true); + } + } +} + +static void RandomizeLinksPocket() { + if (LinksPocketItem.Is(LINKSPOCKETITEM_ADVANCEMENT)) { + //Get all the advancement items don't include tokens + std::vector advancementItems = FilterAndEraseFromPool(ItemPool, [](const auto i) { + return ItemTable(i).IsAdvancement() && ItemTable(i).GetItemType() != ITEMTYPE_TOKEN; + }); + //select a random one + uint32_t startingItem = RandomElement(advancementItems, true); + //add the others back + AddElementsToPool(ItemPool, advancementItems); + + PlaceItemInLocation(LINKS_POCKET, startingItem); + } else if (LinksPocketItem.Is(LINKSPOCKETITEM_NOTHING)) { + PlaceItemInLocation(LINKS_POCKET, GREEN_RUPEE); + } +} + +void VanillaFill() { + //Perform minimum needed initialization + AreaTable_Init(); + GenerateLocationPool(); + GenerateItemPool(); + GenerateStartingInventory(); + //Place vanilla item in each location + RandomizeDungeonRewards(); + for (uint32_t loc : allLocations) { + Location(loc)->PlaceVanillaItem(); + } + //If necessary, handle ER stuff + if (ShuffleEntrances) { + printf("\x1b[7;10HShuffling Entrances..."); + ShuffleAllEntrances(); + printf("\x1b[7;32HDone"); + } + //Finish up + CreateItemOverrides(); + CreateEntranceOverrides(); + CreateAlwaysIncludedMessages(); +} + +void ClearProgress() { + printf("\x1b[7;32H "); // Done + printf("\x1b[8;10H "); // Placing Items...Done + printf("\x1b[9;10H "); // Calculating Playthrough...Done + printf("\x1b[10;10H "); // Creating Hints...Done + printf("\x1b[11;10H "); // Writing Spoiler Log...Done +} + +int Fill() { + + int retries = 0; + while(retries < 5) { + placementFailure = false; + showItemProgress = false; + playthroughLocations.clear(); + playthroughEntrances.clear(); + wothLocations.clear(); + AreaTable_Init(); //Reset the world graph to intialize the proper locations + ItemReset(); //Reset shops incase of shopsanity random + GenerateLocationPool(); + GenerateItemPool(); + GenerateStartingInventory(); + RemoveStartingItemsFromPool(); + FillExcludedLocations(); + + //Temporarily add shop items to the ItemPool so that entrance randomization + //can validate the world using deku/hylian shields + AddElementsToPool(ItemPool, GetMinVanillaShopItems(32)); //assume worst case shopsanity 4 + if (ShuffleEntrances) { + printf("\x1b[7;10HShuffling Entrances"); + if (ShuffleAllEntrances() == ENTRANCE_SHUFFLE_FAILURE) { + retries++; + ClearProgress(); + continue; + } + printf("\x1b[7;32HDone"); + } + //erase temporary shop items + FilterAndEraseFromPool(ItemPool, [](const auto item) { return ItemTable(item).GetItemType() == ITEMTYPE_SHOP; }); + + showItemProgress = true; + //Place shop items first, since a buy shield is needed to place a dungeon reward on Gohma due to access + NonShopItems = {}; + if (Shopsanity.Is(SHOPSANITY_OFF)) { + PlaceVanillaShopItems(); //Place vanilla shop items in vanilla location + } else { + int total_replaced = 0; + if (Shopsanity.IsNot(SHOPSANITY_ZERO)) { //Shopsanity 1-4, random + //Initialize NonShopItems + ItemAndPrice init; + init.Name = Text{"No Item", "Sin objeto", "Pas d'objet"}; + init.Price = -1; + init.Repurchaseable = false; + NonShopItems.assign(32, init); + //Indices from OoTR. So shopsanity one will overwrite 7, three will overwrite 7, 5, 8, etc. + const std::array indices = {7, 5, 8, 6}; + //Overwrite appropriate number of shop items + for (size_t i = 0; i < ShopLocationLists.size(); i++) { + int num_to_replace = GetShopsanityReplaceAmount(); //1-4 shop items will be overwritten, depending on settings + total_replaced += num_to_replace; + for (int j = 0; j < num_to_replace; j++) { + int itemindex = indices[j]; + int shopsanityPrice = GetRandomShopPrice(); + NonShopItems[TransformShopIndex(i*8+itemindex-1)].Price = shopsanityPrice; //Set price to be retrieved by the patch and textboxes + Location(ShopLocationLists[i][itemindex - 1])->SetShopsanityPrice(shopsanityPrice); + } + } + } + //Get all locations and items that don't have a shopsanity price attached + std::vector shopLocations = {}; + //Get as many vanilla shop items as the total number of shop items minus the number of replaced items + //So shopsanity 0 will get all 64 vanilla items, shopsanity 4 will get 32, etc. + std::vector shopItems = GetMinVanillaShopItems(total_replaced); + + for (size_t i = 0; i < ShopLocationLists.size(); i++) { + for (size_t j = 0; j < ShopLocationLists[i].size(); j++) { + uint32_t loc = ShopLocationLists[i][j]; + if (!(Location(loc)->HasShopsanityPrice())) { + shopLocations.push_back(loc); + } + } + } + //Place the shop items which will still be at shop locations + AssumedFill(shopItems, shopLocations); + } + + //Place dungeon rewards + RandomizeDungeonRewards(); + + //Place dungeon items restricted to their Own Dungeon + for (auto dungeon : Dungeon::dungeonList) { + RandomizeOwnDungeon(dungeon); + } + + //Then Place songs if song shuffle is set to specific locations + if (ShuffleSongs.IsNot(SONGSHUFFLE_ANYWHERE)) { + + //Get each song + std::vector songs = + FilterAndEraseFromPool(ItemPool, [](const auto i) { return ItemTable(i).GetItemType() == ITEMTYPE_SONG; }); + + //Get each song location + std::vector songLocations; + if (ShuffleSongs.Is(SONGSHUFFLE_SONG_LOCATIONS)) { + songLocations = + FilterFromPool(allLocations, [](const auto loc) { return Location(loc)->IsCategory(Category::cSong); }); + + } else if (ShuffleSongs.Is(SONGSHUFFLE_DUNGEON_REWARDS)) { + songLocations = FilterFromPool( + allLocations, [](const auto loc) { return Location(loc)->IsCategory(Category::cSongDungeonReward); }); + } + + AssumedFill(songs, songLocations, true); + } + + //Then place dungeon items that are assigned to restrictive location pools + RandomizeDungeonItems(); + + //Then place Link's Pocket Item if it has to be an advancement item + RandomizeLinksPocket(); + //Then place the rest of the advancement items + std::vector remainingAdvancementItems = + FilterAndEraseFromPool(ItemPool, [](const auto i) { return ItemTable(i).IsAdvancement(); }); + AssumedFill(remainingAdvancementItems, allLocations, true); + + //Fast fill for the rest of the pool + std::vector remainingPool = FilterAndEraseFromPool(ItemPool, [](const auto i) { return true; }); + FastFill(remainingPool, GetAllEmptyLocations(), false); + GeneratePlaythrough(); + //Successful placement, produced beatable result + if(playthroughBeatable && !placementFailure) { + printf("Done"); + printf("\x1b[9;10HCalculating Playthrough..."); + PareDownPlaythrough(); + CalculateWotH(); + printf("Done"); + CreateItemOverrides(); + CreateEntranceOverrides(); + CreateAlwaysIncludedMessages(); + if (GossipStoneHints.IsNot(HINTS_NO_HINTS)) { + printf("\x1b[10;10HCreating Hints..."); + CreateAllHints(); + printf("Done"); + } + if (ShuffleMerchants.Is(SHUFFLEMERCHANTS_HINTS)) { + CreateMerchantsHints(); + } + return 1; + } + //Unsuccessful placement + if(retries < 4) { + SPDLOG_INFO("\nGOT STUCK. RETRYING...\n"); + Areas::ResetAllLocations(); + LogicReset(); + ClearProgress(); + } + retries++; + } + //All retries failed + return -1; +} diff --git a/soh/soh/Enhancements/randomizer/3drando/fill.hpp b/soh/soh/Enhancements/randomizer/3drando/fill.hpp new file mode 100644 index 000000000..427668985 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/fill.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include "keys.hpp" + +#include +#include + +enum class SearchMode { + ReachabilitySearch, + GeneratePlaythrough, + CheckBeatable, + AllLocationsReachable, + ValidateWorld, + TimePassAccess, + TempleOfTimeAccess, + ValidStartingRegion, + PoeCollectorAccess, +}; + +void ClearProgress(); +void VanillaFill(); +int Fill(); + +std::vector GetAccessibleLocations(const std::vector& allowedLocations, + SearchMode mode = SearchMode::ReachabilitySearch, std::string ignore = "", + bool checkPoeCollectorAccess = false, + bool checkOtherEntranceAccess = false); diff --git a/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp b/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp new file mode 100644 index 000000000..19329675a --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/hint_list.cpp @@ -0,0 +1,2268 @@ +#include "hint_list.hpp" +#include "custom_messages.hpp" + +#include + +using namespace CustomMessages; + +//Big thanks to Lioncache, Gabyelnuevo, Danius88, and Charade for their translations! + +//Text is {english, french, spanish} + +// there are special characters that are read for certain in game commands: +// ^ is a box break +// & is a new line +// @ will print the player name +// surrounding text with '#' will make it a different color +// - OoT Randomizer + +// '%d' indicates a number will be placed there. + +std::array hintTable; + +void HintTable_Init() { + /*-------------------------- + | GENERAL TEXT | + ---------------------------*/ + hintTable[NONE] = HintText::Exclude({Text{"No Hint","Pas d'Indice",""}}); + hintTable[PREFIX] = HintText::Exclude({Text{"They say that ", /*french*/"Selon moi, ", /*spanish*/"Según dicen, "}}); + hintTable[WAY_OF_THE_HERO] = HintText::Exclude({Text{" is on the way of the hero.", /*french*/" est sur la voie du héros." , /*spanish*/" conduce a la senda del héroe."}}); + hintTable[PLUNDERING] = HintText::Exclude({Text{"plundering ", /*french*/"explorer ", /*spanish*/"inspeccionar "}}); + hintTable[FOOLISH] = HintText::Exclude({Text{" is a foolish choice.", /*french*/" est futile.", /*spanish*/" no es una sabia decisión."}}); + hintTable[CAN_BE_FOUND_AT] = HintText::Exclude({Text{"can be found at", /*french*/"se trouve dans", /*spanish*/"aguarda en"}}); + hintTable[HOARDS] = HintText::Exclude({Text{"hoards", /*french*/"recèle", /*spanish*/"acapara"}}); + + HintTable_Init_Item(); + HintTable_Init_Exclude_Overworld(); + HintTable_Init_Exclude_Dungeon(); + + /*-------------------------- + | ALWAYS HINT TEXT | + ---------------------------*/ + + hintTable[ZR_FROGS_OCARINA_GAME] = HintText::Always({ + //obscure text + Text{"an #amphibian feast# yields", /*french*/"un #festin d'amphibiens# donne", /*spanish*/"una #fiesta anfibia# brinda"}, + Text{"the #croaking choir's magnum opus# awards", /*french*/"la #chorale coassante# donne", /*spanish*/"un #coro maestro de ancas# premia"}, + Text{"the #froggy finale# yields", /*french*/"la #finale amphibienne# donne", /*spanish*/"el #gran final batracio# brinda"}, + }, {}, + //clear text + Text{"the final reward from the #Frogs of Zora's River# is", /*french*/"la dernière récompense des #grenouilles de la Rivière Zora# est", /*spanish*/"la recompensa final de las #ranas del Río Zora# premia"} + ); + + hintTable[KF_LINKS_HOUSE_COW] = HintText::Always({ + //obscure text + Text{"the #bovine bounty of a horseback hustle# gifts", /*french*/"le cadeau #qui découle d'une réussite équestre# est", /*spanish*/"la #recompensa bovina de un paseo a caballo# brinda"}, + }, {}, + //clear text + Text{"#Malon's obstacle course# leads to", /*french*/"la #course à obstacle de Malon# amène à", /*spanish*/"la #carrera de obstáculos de Malon# brinda"} + ); + + /*-------------------------- + | SOMETIMES HINT TEXT | + ---------------------------*/ + + hintTable[SONG_FROM_OCARINA_OF_TIME] = HintText::Sometimes({ + //obscure text + Text{"the #Ocarina of Time# teaches", /*french*/"l'#Ocarina du Temps# est accompagné par", /*spanish*/"la #Ocarina del Tiempo# enseña"}, + }); + + hintTable[SONG_FROM_COMPOSERS_GRAVE] = HintText::Sometimes({ + //obscure text + Text{"#ReDead in the Composers' Grave# guard", /*french*/"les #Éffrois du tombeau des compositeurs# protègent", /*spanish*/"los #ReDeads del Panteón Real# guardan"}, + Text{"the #Composer Brothers wrote#", /*french*/"le #trésor des compositeurs# est", /*spanish*/"los #hermanos compositores escribieron#"}, + }); + + hintTable[SHEIK_IN_FOREST] = HintText::Sometimes({ + //obscure text + Text{"#in a meadow# Sheik teaches", /*french*/"Sheik confiera, #dans un bosquet#,", /*spanish*/"#en la pradera sagrada# Sheik enseña"}, + }); + + hintTable[SHEIK_AT_TEMPLE] = HintText::Sometimes({ + //obscure text + Text{"Sheik waits at a #monument to time# to teach", /*french*/"Sheik confiera, #au pied de l'épée légendaire#,", /*spanish*/"Sheik espera en el #momumento del tiempo# para enseñar"}, + }); + + hintTable[SHEIK_IN_CRATER] = HintText::Sometimes({ + //obscure text + Text{"the #crater's melody# is", /*french*/"Sheik confiera, #entouré de lave#,", /*spanish*/"la #melodía del cráter# otorga"}, + }); + + hintTable[SHEIK_IN_ICE_CAVERN] = HintText::Sometimes({ + //obscure text + Text{"the #frozen cavern# echoes with", /*french*/"Sheik confiera, #dans une caverne enneigée#,", /*spanish*/"en la #caverna de hielo# retumban los ecos de"}, + }); + + hintTable[SHEIK_IN_KAKARIKO] = HintText::Sometimes({ + //obscure text + Text{"a #ravaged village# mourns with", /*french*/"Sheik confirera, #au coeur d'un village ravagé#,", /*spanish*/"un #arrasado pueblo# llora"}, + }); + + hintTable[SHEIK_AT_COLOSSUS] = HintText::Sometimes({ + //obscure text + Text{"a hero ventures #beyond the wasteland# to learn", /*french*/"Sheik confiera, #au bout d'un chemin sableux#,", /*spanish*/"el héroe que se adentre #más allá del desierto# aprenderá"}, + }); + + + hintTable[MARKET_10_BIG_POES] = HintText::Sometimes({ + //obscure text + Text{"#ghost hunters# will be rewarded with", /*french*/"#les chasseurs de fantômes# sont récompensés avec", /*spanish*/"los #cazafantasmas# son premiados con"}, + }, {}, + //clear text + Text{"catching #Big Poes# leads to", /*french*/"#d'attraper des Àmes# donne", /*spanish*/"hacerte con #Grandes Poes# conduce a"} + ); + + hintTable[DEKU_THEATER_SKULL_MASK] = HintText::Sometimes({ + //obscure text + Text{"the #Skull Mask# yields", /*french*/"le #Masque de Mort# donne", /*spanish*/"la #máscara de calavera# otorga"}, + }); + + hintTable[DEKU_THEATER_MASK_OF_TRUTH] = HintText::Sometimes({ + //obscure text + Text{"showing a #truthful eye to the crowd# rewards", /*french*/"montrer #l'oeil de vérité à la foule# donne", /*spanish*/"#mostrarle el ojo verdadero# a una multitud brinda"}, + }, {}, + //clear text + Text{"the #Mask of Truth# yields", /*french*/"le #Masque de Vérité# donne", /*spanish*/"la #máscara de la verdad# premia"} + ); + + hintTable[HF_OCARINA_OF_TIME_ITEM] = HintText::Sometimes({ + //obscure text + Text{"the #treasure thrown by Princess Zelda# is", /*french*/"le trésor #laissé par la princesse# est", /*spanish*/"el #tesoro arrojado por la Princesa Zelda# se trata de"}, + }); + + hintTable[DMT_TRADE_BROKEN_SWORD] = HintText::Sometimes({ + //obscure text + Text{"a #blinded Biggoron# entrusts", /*french*/"un #Grogoron aveuglé# confie", /*spanish*/"un #miope Biggoron# otorga"}, + }); + + hintTable[DMT_TRADE_EYEDROPS] = HintText::Sometimes({ + //obscure text + Text{"while you wait, #Biggoron# gives", /*french*/"pendant que tu attends, #Biggoron# donne", /*spanish*/"#Biggoron# está a la espera de otorgar"}, + }); + + hintTable[DMT_TRADE_CLAIM_CHECK] = HintText::Sometimes({ + //obscure text + Text{"#Biggoron# crafts", /*french*/"#Biggoron# fabrique", /*spanish*/"#Biggoron# forja"}, + }); + + hintTable[KAK_50_GOLD_SKULLTULA_REWARD] = HintText::Sometimes({ + //obscure text + Text{"#50 bug badges# rewards", /*french*/"#50 écussons# donnent", /*spanish*/"#50 medallas de insectos# otorgan"}, + Text{"#50 spider souls# yields", /*french*/"#50 âmes d'arachnide# donnent", /*spanish*/"#50 almas de araña# otorgan"}, + Text{"#50 auriferous arachnids# lead to", /*french*/"#50 arachnides aurifères# donnent", /*spanish*/"#50 arácnidos auríferos# otorgan"}, + }, {}, + //clear text + Text{"slaying #50 Gold Skulltulas# reveals", /*french*/"détruire #50 Skulltulas d'or# donne", /*spanish*/"exterminar #50 skulltulas doradas# revela"} + ); + + hintTable[KAK_40_GOLD_SKULLTULA_REWARD] = HintText::Sometimes({ + //obscure text + Text{"#40 bug badges# rewards", /*french*/"#40 écussons# donnent", /*spanish*/"#40 medallas de insectos# otorgan"}, + Text{"#40 spider souls# yields", /*french*/"#40 âmes d'arachnide# donnent", /*spanish*/"#40 almas de araña# otorgan"}, + Text{"#40 auriferous arachnids# lead to", /*french*/"#40 arachnides aurifères# donnent", /*spanish*/"#40 arácnidos auríferos# otorgan"}, + }, {}, + //clear text + Text{"slaying #40 Gold Skulltulas# reveals", /*french*/"détruire #40 Skulltulas d'or# donne", /*spanish*/"exterminar #40 skulltulas doradas# revela"} + ); + + hintTable[KAK_30_GOLD_SKULLTULA_REWARD] = HintText::Sometimes({ + //obscure text + Text{"#30 bug badges# rewards", /*french*/"#30 écussons# donnent", /*spanish*/"#30 medallas de insectos# otorgan"}, + Text{"#30 spider souls# yields", /*french*/"#30 âmes d'arachnide# donnent", /*spanish*/"#30 almas de araña# otorgan"}, + Text{"#30 auriferous arachnids# lead to", /*french*/"#30 arachnides aurifères# donnent", /*spanish*/"#30 arácnidos auríferos# otorgan"}, + }, {}, + //clear text + Text{"slaying #30 Gold Skulltulas# reveals", /*french*/"détruire #30 Skulltulas d'or# donne", /*spanish*/"exterminar #30 skulltulas doradas# revela"} + ); + + hintTable[KAK_20_GOLD_SKULLTULA_REWARD] = HintText::Sometimes({ + //obscure text + Text{"#20 bug badges# rewards", /*french*/"#20 écussons# donnent", /*spanish*/"#20 medallas de insectos# otorgan"}, + Text{"#20 spider souls# yields", /*french*/"#20 âmes d'arachnide# donnent", /*spanish*/"#20 almas de araña# otorgan"}, + Text{"#20 auriferous arachnids# lead to", /*french*/"#20 arachnides aurifères# donnent", /*spanish*/"#20 arácnidos auríferos# otorgan"}, + }, {}, + //clear text + Text{"slaying #20 Gold Skulltulas# reveals", /*french*/"détruire #20 Skulltulas d'or# donne", /*spanish*/"exterminar #20 skulltulas doradas# revela"} + ); + + hintTable[KAK_ANJU_AS_CHILD] = HintText::Sometimes({ + //obscure text + Text{"#wrangling roosters# rewards", /*french*/"#plumer des poulets# donne", /*spanish*/"#atrapar a las gallinas# premia"}, + Text{"#chucking chickens# gifts", /*french*/"#lancer des poulets# donne", /*spanish*/"#reunir a unos emplumados# premia"}, + }, {}, + //clear text + Text{"#collecting cuccos# rewards", /*french*/"#rapporter les Cocottes# donne", /*spanish*/"#hacerte con todos los cucos# premia"} + ); + + hintTable[KAK_TRADE_POCKET_CUCCO] = HintText::Sometimes({ + //obscure text + Text{"an adult's #happy Cucco# awards", /*french*/"un adulte avec une #poulette joyeuse# obtient", /*spanish*/"un #alegre cuco# en la madurez otorga"}, + }); + + hintTable[KAK_TRADE_ODD_MUSHROOM] = HintText::Sometimes({ + //obscure text + Text{"the #potion shop lady# entrusts", /*french*/"la #gribiche du magasin de potion# confie", /*spanish*/"la #señora de la tienda de pociones# otorga"}, + }); + + hintTable[GC_DARUNIAS_JOY] = HintText::Sometimes({ + //obscure text + Text{"a #groovin' goron# gifts", /*french*/"#le Goron joyeux# donne", /*spanish*/"#un goron marchoso# otorga"}, + }, {}, + //clear text + Text{"#Darunia's dance# leads to", /*french*/"#la dance de Darunia# donne", /*spanish*/"#el baile de Darunia# conduce a"} + ); + + hintTable[LW_SKULL_KID] = HintText::Sometimes({ + //obscure text + Text{"the #Skull Kid# grants", /*french*/"le #Skull Kid# donne", /*spanish*/"#Skull Kid# otorga"}, + }); + + hintTable[LW_TRADE_COJIRO] = HintText::Sometimes({ + //obscure text + Text{"returning a #special Cucco# awards", /*french*/"ramener une #poulette précieuse# donne", /*spanish*/"quien devuelva un #cuco especial# encontrará"}, + }); + + hintTable[LW_TRADE_ODD_POTION] = HintText::Sometimes({ + //obscure text + Text{"a #Kokiri girl in the woods# leaves", /*french*/"la #fillette Kokiri dans les bois# laisse", /*spanish*/"una #chica kokiri del bosque# otorga"}, + }); + + hintTable[LH_SUN] = HintText::Sometimes({ + //obscure text + Text{"staring into #the sun# grants", /*french*/"regarder #le soleil# donne", /*spanish*/"#mirar al sol# revela"}, + }, {}, + //clear text + Text{"shooting #the sun# grants", /*french*/"tirer une flèche dans #sur le soleil# donne", /*spanish*/"#disparar al sol# revela"} + ); + + hintTable[LH_TRADE_FROG] = HintText::Sometimes({ + //obscure text + Text{"#Lake Hylia's scientist# hurriedly entrusts", /*french*/"le #scientifique du lac# confie rapidement", /*spanish*/"el #científico del Lago Hylia# otorga con prisa"}, + }); + + hintTable[MARKET_TREASURE_CHEST_GAME_REWARD] = HintText::Sometimes({ + //obscure text + Text{"#gambling# grants", /*french*/"#parier# donne", /*spanish*/"#los juegos de azar# revelan"}, + Text{"there is a #1/32 chance# to win", /*french*/"être #le gagnant parmi 32# donne", /*spanish*/"hay una #probabilidad de 1/32# de ganar"}, + }, {}, + //clear text + Text{"the #treasure chest game# grants", /*french*/"la #Chasse-aux-Trésors# donne", /*spanish*/"#el Cofre del Tesoro# premia"} + ); + + hintTable[MARKET_TREASURE_CHEST_GAME_ITEM_1] = HintText::Sometimes({ + //obscure text + Text{"#gambling once# grants", /*french*/"#parier une fois# donne", /*spanish*/"#apostar solo una vez# revelará"}, + Text{"the #first or second game chest# contains", /*french*/"le #premier ou deuxième coffre à jeu# contient", /*spanish*/"#el primer o segundo cofre del azar# revela"}, + }, {}, + //clear text + Text{"the #first locked room# in the chest game contains", /*french*/"la #première salle# de la Chasse-aux-Trésors contient", /*spanish*/"#en la primera sala del Cofre del Tesoro# aguarda"} + ); + + hintTable[MARKET_TREASURE_CHEST_GAME_ITEM_2] = HintText::Sometimes({ + //obscure text + Text{"#gambling twice# grants", /*french*/"#parier deux fois# donne", /*spanish*/"#apostar dos veces# revelará"}, + Text{"the #third or fourth game chest# contains", /*french*/"le #troisième ou quatrième coffre à jeu# contient", /*spanish*/"#el tercer o cuarto cofre del azar# revela"}, + }, {}, + //clear text + Text{"the #second locked room# in the chest game contains", /*french*/"la #deuxième salle# de la Chasse-aux-Trésors contient", /*spanish*/"#en la segunda sala del Cofre del Tesoro# aguarda"} + ); + + hintTable[MARKET_TREASURE_CHEST_GAME_ITEM_3] = HintText::Sometimes({ + //obscure text + Text{"#gambling 3 times# grants", /*french*/"#parier trois fois# donne", /*spanish*/"#apostar tres veces# revelará"}, + Text{"the #fifth or sixth game chest# contains", /*french*/"le #cinquième ou sixième coffre à jeu# contient", /*spanish*/"#el quinto o sexto cofre del azar# revela"}, + }, {}, + //clear text + Text{"the #third locked room# in the chest game contains", /*french*/"la #troisième salle# de la Chasse-aux-Trésors contient", /*spanish*/"#en la tercera sala del Cofre del Tesoro# aguarda"} + ); + + hintTable[MARKET_TREASURE_CHEST_GAME_ITEM_4] = HintText::Sometimes({ + //obscure text + Text{"#gambling 4 times# grants", /*french*/"#parier quatre fois# donne", /*spanish*/"#apostar cuatro veces# revelará"}, + Text{"the #seventh or eighth game chest# contains", /*french*/"le #septième ou huitième coffre à jeu# contient", /*spanish*/"#el séptimo u octavo cofre del azar# revela"}, + }, {}, + //clear text + Text{"the #fourth locked room# in the chest game contains", /*french*/"la #quatrième salle# de la Chasse-aux-Trésors contient", /*spanish*/"#en la cuarta sala del Cofre del Tesoro# aguarda"} + ); + + hintTable[MARKET_TREASURE_CHEST_GAME_ITEM_5] = HintText::Sometimes({ + //obscure text + Text{"#gambling 5 times# grants", /*french*/"#parier cinq fois# donne", /*spanish*/"#apostar cinco veces# revelará"}, + Text{"the #ninth or tenth game chest# contains", /*french*/"le #neuvième ou dixième coffre à jeu# contient", /*spanish*/"#el noveno o décimo cofre del azar# revela"}, + }, {}, + //clear text + Text{"the #fifth locked room# in the chest game contains", /*french*/"la #cinquième salle# de la Chasse-aux-Trésors contient", /*spanish*/"#en la quinta sala del Cofre del Tesoro# aguarda"} + ); + + hintTable[GF_HBA_1500_POINTS] = HintText::Sometimes({ + //obscure text + Text{"mastery of #horseback archery# grants", /*french*/"maîtriser l'#archerie équestre# donne", /*spanish*/"dominar el #tiro con arco a caballo# premia con"}, + }, {}, + //clear text + Text{"scoring 1500 in #horseback archery# grants", /*french*/"obtenir 1500 points dans l'#archerie équestre# donne", /*spanish*/"conseguir 1500 puntos en el #tiro con arco a caballo# premia"} + ); + + hintTable[GRAVEYARD_HEART_PIECE_GRAVE_CHEST] = HintText::Sometimes({ + //obscure text + Text{"playing #Sun's Song# in a grave spawns", /*french*/"jouer le #chant du soleil# dans un tombeau donne", /*spanish*/"#tocar la Canción del Sol# en una cripta conduce a"}, + }); + + hintTable[GC_MAZE_LEFT_CHEST] = HintText::Sometimes({ + //obscure text + Text{"in #Goron City# the hammer unlocks", /*french*/"dans le #village Goron#, le marteau donne accès à", /*spanish*/"en la #Ciudad Goron# el martillo desbloquea"}, + }); + + hintTable[GV_CHEST] = HintText::Sometimes({ + //obscure text + Text{"in #Gerudo Valley# the hammer unlocks", /*french*/"dans la #Vallée Gerudo#, le marteau donne accès à", /*spanish*/"en el #Valle Gerudo# el martillo desbloquea"}, + }); + + hintTable[GV_TRADE_SAW] = HintText::Sometimes({ + //obscure text + Text{"the #boss of the carpenters# leaves", /*french*/"le #patron des ouvriers# laisse", /*spanish*/"el #capataz de los carpinteros# otorga"}, + }); + + hintTable[GV_COW] = HintText::Sometimes({ + //obscure text + Text{"a #cow in Gerudo Valley# gifts", /*french*/"la #vache de la Vallée Gerudo# donne", /*spanish*/"una #vaca del Valle Gerudo# brinda"}, + }); + + hintTable[HC_GS_STORMS_GROTTO] = HintText::Sometimes({ + //obscure text + Text{"a #spider behind a muddy wall# in a grotto holds", /*french*/"l'#araignée derrière un mur de boue# dans une grotte donne", /*spanish*/"una #Skulltula tras la agrietada pared# de una cueva otorga"}, + }); + + hintTable[HF_GS_COW_GROTTO] = HintText::Sometimes({ + //obscure text + Text{"a #spider behind webs# in a grotto holds", /*french*/"l'#araignée derrière une toile# dans une grotte donne", /*spanish*/"una #Skulltula tras la telaraña# de una cueva otorga"}, + }); + + hintTable[HF_COW_GROTTO_COW] = HintText::Sometimes({ + //obscure text + Text{"the #cobwebbed cow# gifts", /*french*/"la #vache prisonnière d'araignées# donne", /*spanish*/"una #vaca tras una telaraña# brinda"}, + }, {}, + //clear text + Text{"a #cow behind webs# in a grotto gifts", /*french*/"la #vache derrière les toiles# d'une grotte donne", /*spanish*/"una #vaca tras la telaraña# de una cueva brinda"} + ); + + hintTable[ZF_GS_HIDDEN_CAVE] = HintText::Sometimes({ + //obscure text + Text{"a spider high #above the icy waters# holds", /*french*/"l'araignée #en haut des eaux glacées# donne", /*spanish*/"una Skulltula en lo #alto de las congeladas aguas# otorga"}, + }); + + hintTable[WASTELAND_CHEST] = HintText::Sometimes({ + //obscure text + Text{"#deep in the wasteland# is", /*french*/"#loin dans le désert# gît", /*spanish*/"en lo #profundo del desierto encantado# yace"}, + Text{"beneath #the sands#, flames reveal", /*french*/"#sous le désert#, les flammes font apparaître", /*spanish*/"tras las #arenas# unas llamas revelan"}, + }); + + hintTable[WASTELAND_GS] = HintText::Sometimes({ + //obscure text + Text{"a #spider in the wasteland# holds", /*french*/"#l'araignée dans le désert# donne", /*spanish*/"una #Skulltula del desierto encantado# otorga"}, + }); + + hintTable[GRAVEYARD_COMPOSERS_GRAVE_CHEST] = HintText::Sometimes({ + //obscure text + Text{"#flames in the Composers' Grave# reveal", /*french*/"#les flammes dans le tombeau des compositeurs# cachent", /*spanish*/"#las llamas del Panteón Real# revelan"}, + Text{"the #Composer Brothers hid#", /*french*/"#les Frères compositeurs on caché#", /*spanish*/"los #hermanos compositores esconden#"}, + }); + + hintTable[ZF_BOTTOM_FREESTANDING_POH] = HintText::Sometimes({ + //obscure text + Text{"#under the icy waters# lies", /*french*/"#sous les eaux glacées# se cache", /*spanish*/"#bajo las congeladas aguas# yace"}, + }); + + hintTable[GC_POT_FREESTANDING_POH] = HintText::Sometimes({ + //obscure text + Text{"spinning #Goron pottery# contains", /*french*/"la #potterie Goron# contient", /*spanish*/"una #cerámica goron# contiene"}, + }); + + hintTable[ZD_KING_ZORA_THAWED] = HintText::Sometimes({ + //obscure text + Text{"a #defrosted dignitary# gifts", /*french*/"le #monarque libéré# donne", /*spanish*/"una #liberación monárquica# brinda"}, + }, {}, + //clear text + Text{"unfreezing #King Zora# grants", /*french*/"dégeler # le Roi Zora# donne", /*spanish*/"#descongelar al Rey Zora# conduce a"} + ); + + hintTable[ZD_TRADE_PRESCRIPTION] = HintText::Sometimes({ + //obscure text + Text{"#King Zora# hurriedly entrusts", /*french*/"le #roi Zora# confie rapidement", /*spanish*/"el #Rey Zora# otorga con prisa"}, + }); + + hintTable[DMC_DEKU_SCRUB] = HintText::Sometimes({ + //obscure text + Text{"a single #scrub in the crater# sells", /*french*/"la #peste Mojo dans le cratère# vend", /*spanish*/"un solitario #deku del cráter# vende"}, + }); + + hintTable[DMC_GS_CRATE] = HintText::Sometimes({ + //obscure text + Text{"a spider under a #crate in the crater# holds", /*french*/"la Skulltula dans une #boîte volcanique# a", /*spanish*/"una Skulltula bajo una #caja del cráter# otorga"}, + }); + + + hintTable[DEKU_TREE_MQ_AFTER_SPINNING_LOG_CHEST] = HintText::Sometimes({ + //obscure text + Text{"a #temporal stone within a tree# contains", /*french*/"la #pierre bleue dans un arbre# mène à", /*spanish*/"un #bloque temporal de un árbol# contiene"}, + }, {}, + //clear text + Text{"a #temporal stone within the Deku Tree# contains", /*french*/"la #pierre temporelle dans l'Arbre Mojo# cache", /*spanish*/"un #bloque temporal del Gran Árbol Deku# contiene"} + ); + + hintTable[DEKU_TREE_MQ_GS_BASEMENT_GRAVES_ROOM] = HintText::Sometimes({ + //obscure text + Text{"a #spider on a ceiling in a tree# holds", /*french*/"l'#araignée haut-perchée dans un arbre# a", /*spanish*/"una #Skulltula en el techo de un árbol# otorga"}, + }, {}, + //clear text + Text{"a #spider on a ceiling in the Deku Tree# holds", /*french*/"la#Skulltula dans le Cimetière de l'Arbre Mojo# a", /*spanish*/"una #Skulltula en el techo del Gran Árbol Deku# otorga"} + ); + + hintTable[DODONGOS_CAVERN_MQ_GS_SONG_OF_TIME_BLOCK_ROOM] = HintText::Sometimes({ + //obscure text + Text{"a spider under #temporal stones in a cavern# holds", /*french*/"l'araignée sous #une pierre bleue dans une caverne# a", /*spanish*/"una Skulltula bajo #bloques temporales de una cueva# otorga"}, + }, {}, + //clear text + Text{"a spider under #temporal stones in Dodongo's Cavern# holds", /*french*/"la Skulltula sous #la pierre temporelle dans la Caverne Dodongo# a", /*spanish*/"una Skulltula bajo #bloques temporales de la Cueva de los Dodongos# otorga"} + ); + + hintTable[JABU_JABUS_BELLY_BOOMERANG_CHEST] = HintText::Sometimes({ + //obscure text + Text{"a school of #stingers swallowed by a deity# guard", /*french*/"les #raies dans un gardien# protègent", /*spanish*/"unos de #stingers engullidos por cierta deidad# guardan"}, + }, {}, + //clear text + Text{"a school of #stingers swallowed by Jabu-Jabu# guard", /*french*/"les #raies dans Jabu-Jabu# protègent", /*spanish*/"unos #stingers engullidos por Jabu-Jabu# guardan"} + ); + + hintTable[JABU_JABUS_BELLY_MQ_GS_INVISIBLE_ENEMIES_ROOM] = HintText::Sometimes({ + //obscure text + Text{"a spider surrounded by #shadows in the belly of a deity# holds", /*french*/"l'araignée entourée d'#ombres dans le ventre du gardien# possède", /*spanish*/"una Skulltula rodeada de #sombras en la tripa de cierta diedad# otorga"}, + }, {}, + //clear text + Text{"a spider surrounded by #shadows in Jabu-Jabu's Belly# holds", /*french*/"la Skulltula entourée d'#ombres dans Jabu-Jabu# possède", /*spanish*/"una Skulltula rodeada de #sombras en la Tripa de Jabu-Jabu# otorga"} + ); + + hintTable[JABU_JABUS_BELLY_MQ_COW] = HintText::Sometimes({ + //obscure text + Text{"a #cow swallowed by a deity# gifts", /*french*/"la #vache dans le gardien# donne", /*spanish*/"una #vaca engullida por cierta deidad# brinda"}, + }, {}, + //clear text + Text{"a #cow swallowed by Jabu-Jabu# gifts", /*french*/"la #vache avallée par Jabu-Jabu# donne", /*spanish*/"una #vaca engullida por Jabu-Jabu# brinda"} + ); + + hintTable[FIRE_TEMPLE_SCARECROW_CHEST] = HintText::Sometimes({ + //obscure text + Text{"a #scarecrow atop the volcano# hides", /*french*/"l'#épouvantail au sommet d'un volcan# donne", /*spanish*/"un #espantapájaros en lo alto del volcán# esconde"}, + }, {}, + //clear text + Text{"#Pierre atop the Fire Temple# hides", /*french*/"#Pierre au sommet du Temple du Feu# donne", /*spanish*/"#Pierre en lo alto del Templo del Fuego# esconde"} + ); + + hintTable[FIRE_TEMPLE_MEGATON_HAMMER_CHEST] = HintText::Sometimes({ + //obscure text + Text{"the #Flare Dancer atop the volcano# guards a chest containing", /*french*/"le #danseur au sommet du volcan# protège", /*spanish*/"el #Bailafuego en lo alto del volcán# otorga"}, + }, {}, + //clear text + Text{"the #Flare Dancer atop the Fire Temple# guards a chest containing", /*french*/"le #Danse-Flamme au sommet du Temple du Feu# protège", /*spanish*/"el #Bailaguego en lo alto del Templo del Fuego# otorga"} + ); + + hintTable[FIRE_TEMPLE_MQ_CHEST_ON_FIRE] = HintText::Sometimes({ + //obscure text + Text{"the #Flare Dancer atop the volcano# guards a chest containing", /*french*/"le #danseur au sommet du volcan# protège", /*spanish*/"el #Bailafuego en lo alto del volcán# otorga"}, + }, {}, + //clear text + Text{"the #Flare Dancer atop the Fire Temple# guards a chest containing", /*french*/"le #Danse-Flamme au sommet du Temple du Feu# protège", /*spanish*/"el #Bailafuego en lo alto del Templo del Fuego# otorga"} + ); + + hintTable[FIRE_TEMPLE_MQ_GS_SKULL_ON_FIRE] = HintText::Sometimes({ + //obscure text + Text{"a #spider under a block in the volcano# holds", /*french*/"l'#araignée sous un bloc dans le volcan# a", /*spanish*/"una #Skulltula bajo el bloque de un volcán# otorga"}, + }, {}, + //clear text + Text{"a #spider under a block in the Fire Temple# holds", /*french*/"une #Skulltula sous un bloc dans le Temple du Feu# a", /*spanish*/"una #Skulltula bajo un bloque del Templo del Fuego# otorga"} + ); + + hintTable[WATER_TEMPLE_RIVER_CHEST] = HintText::Sometimes({ + //obscure text + Text{"beyond the #river under the lake# waits", /*french*/"au delà de #la rivière sous le lac# se cache", /*spanish*/"tras el #río bajo el lago# yace"}, + }, {}, + //clear text + Text{"beyond the #river in the Water Temple# waits", /*french*/"au delà de #la rivière dans le Temple de l'Eau# se cache", /*spanish*/"tras el #río del Templo del Agua# yace"} + ); + + hintTable[WATER_TEMPLE_BOSS_KEY_CHEST] = HintText::Sometimes({ + //obscure text + Text{"dodging #rolling boulders under the lake# leads to", /*french*/"éviter des #rochers roulants sous le lac# mène à", /*spanish*/"esquivar #rocas rodantes bajo el lago# conduce a"}, + }, {}, + //clear text + Text{"dodging #rolling boulders in the Water Temple# leads to", /*french*/"éviter des #rochers roulants dans le Temple de l'Eau# mène à", /*spanish*/"esquivar #rocas rondantes del Templo del Agua# conduce a"} + ); + + hintTable[WATER_TEMPLE_GS_BEHIND_GATE] = HintText::Sometimes({ + //obscure text + Text{"a spider behind a #gate under the lake# holds", /*french*/"l'araignée derrière une #barrière sous le lac# a", /*spanish*/"una Skulltula tras #una valla bajo el lago# otorga"}, + }, {}, + //clear text + Text{"a spider behind a #gate in the Water Temple# holds", /*french*/"la Skulltula derrière une #barrière dans le Temple de l'Eau# a", /*spanish*/"una Skulltula tras #una valla del Templo del Agua# otorga"} + ); + + hintTable[WATER_TEMPLE_MQ_FREESTANDING_KEY] = HintText::Sometimes({ + //obscure text + Text{"hidden in a #box under the lake# lies", /*french*/"dans une #boîte sous le lac# gît", /*spanish*/"en una #caja bajo el lago# yace"}, + }, {}, + //clear text + Text{"hidden in a #box in the Water Temple# lies", /*french*/"dans une #boîte dans le Temple de l'Eau# gît", /*spanish*/"en una #caja del Templo del Agua# yace"} + ); + + hintTable[WATER_TEMPLE_MQ_GS_FREESTANDING_KEY_AREA] = HintText::Sometimes({ + //obscure text + Text{"the #locked spider under the lake# holds", /*french*/"l'#araignée emprisonnée sous le lac# a", /*spanish*/"la #Skulltula enjaulada bajo el lago# otorga"}, + }, {}, + //clear text + Text{"the #locked spider in the Water Temple# holds", /*french*/"une #Skulltula emprisonnée dans le Temple de l'Eau# a", /*spanish*/"la #Skulltula enjaulada del Templo del Agua# otorga"} + ); + + hintTable[WATER_TEMPLE_MQ_GS_TRIPLE_WALL_TORCH] = HintText::Sometimes({ + //obscure text + Text{"a spider behind a #gate under the lake# holds", /*french*/"l'#araignée derrière une barrière sous le lac# a", /*spanish*/"una Skulltula tras una #valla bajo el lago# otorga"}, + }, {}, + //clear text + Text{"a spider behind a #gate in the Water Temple# holds", /*french*/"une #Skulltula derrière une barrière dans le Temple de l'Eau# a", /*spanish*/"una Skulltula tras una #valla del Templo del Agua#"} + ); + + hintTable[GERUDO_TRAINING_GROUNDS_UNDERWATER_SILVER_RUPEE_CHEST] = HintText::Sometimes({ + //obscure text + Text{"those who seek #sunken silver rupees# will find", /*french*/"ceux qui pêchent les #joyaux argentés# trouveront", /*spanish*/"aquellos que busquen las #rupias plateadas sumergidas# encontrarán"}, + Text{"the #thieves' underwater training# rewards", /*french*/"l'#épreuve de plongée des voleurs# recèle", /*spanish*/"la #instrucción submarina de las bandidas# premia"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER_SILVER_RUPEE_CHEST] = HintText::Sometimes({ + //obscure text + Text{"those who seek #sunken silver rupees# will find", /*french*/"ceux qui pêchent les #joyaux argentés# trouveront", /*spanish*/"aquellos que busquen las #rupias plateadas sumergidas# encontrarán"}, + Text{"the #thieves' underwater training# rewards", /*french*/"l'#épreuve de plongée des voleurs# recèle", /*spanish*/"la #instrucción submarina de las bandidas# premia"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MAZE_PATH_FINAL_CHEST] = HintText::Sometimes({ + //obscure text + Text{"the final prize of #the thieves' training# is", /*french*/"la récompense ultime de #l'épreuve des voleurs# est", /*spanish*/"la recompensa final de la #instrucción de las bandida# brinda"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_ICE_ARROWS_CHEST] = HintText::Sometimes({ + //obscure text + Text{"the final prize of #the thieves' training# is", /*french*/"la récompense ultime de #l'épreuve des voleurs# est", /*spanish*/"el premio final de la #instrucción de las bandidas# brinda"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_LENS_OF_TRUTH_CHEST] = HintText::Sometimes({ + //obscure text + Text{"the well's #grasping ghoul# hides", /*french*/"la #terreur du Puits# cache", /*spanish*/"en las #profundidades del pozo# se esconde"}, + Text{"a #nether dweller in the well# holds", /*french*/"le #spectre qui réside dans le Puits# a", /*spanish*/"el #temido morador del pozo# concede"}, + }, {}, + //clear text + Text{"#Dead Hand in the well# holds", /*french*/"le #Poigneur dans le Puits# cache", /*spanish*/"la #Mano Muerta del pozo# concede"} + ); + + hintTable[BOTTOM_OF_THE_WELL_MQ_COMPASS_CHEST] = HintText::Sometimes({ + //obscure text + Text{"the well's #grasping ghoul# hides", /*french*/"la #terreur du Puits# cache", /*spanish*/"en las #profundidades del pozo# se esconde"}, + Text{"a #nether dweller in the well# holds", /*french*/"le #spectre qui réside dans le Puits# a", /*spanish*/"el #temido morador del pozo# concede"}, + }, {}, + //clear text + Text{"#Dead Hand in the well# holds", /*french*/"le #Poigneur dans le Puits# cache", /*spanish*/"la #Mano Muerta del pozo# concede"} + ); + + hintTable[SPIRIT_TEMPLE_SILVER_GAUNTLETS_CHEST] = HintText::Sometimes({ + //obscure text + Text{"the treasure #sought by Nabooru# is", /*french*/"le trésor que #recherche Nabooru# est", /*spanish*/"el #ansiado tesoro de Nabooru# brinda"}, + }, {}, + //clear text + Text{"upon the #Colossus's right hand# is", /*french*/"sur la #main droite du colosse# repose", /*spanish*/"en la #mano derecha del Coloso# yace"} + ); + + hintTable[SPIRIT_TEMPLE_MIRROR_SHIELD_CHEST] = HintText::Sometimes({ + //obscure text + Text{"upon the #Colossus's left hand# is", /*french*/"sur la #main gauche du colosse# repose", /*spanish*/"en la #mano izquierda del Coloso# yace"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_CHILD_HAMMER_SWITCH_CHEST] = HintText::Sometimes({ + //obscure text + Text{"a #temporal paradox in the Colossus# yields", /*french*/"un #paradoxe temporel dans le colosse# révèle", /*spanish*/"una #paradoja temporal del Coloso# conduce a"}, + }, {}, + //clear text + Text{"a #temporal paradox in the Spirit Temple# yields", /*french*/"le #paradoxe temporel dans le Temple de l'Esprit# révèle", /*spanish*/"una #paradoja temporal del Coloso# conduce a"} + ); + + hintTable[SPIRIT_TEMPLE_MQ_SYMPHONY_ROOM_CHEST] = HintText::Sometimes({ + //obscure text + Text{"a #symphony in the Colossus# yields", /*french*/"la #symphonie du colosse# révèle", /*spanish*/"una #sinfonía del Coloso# conduce a"}, + }, {}, + //clear text + Text{"a #symphony in the Spirit Temple# yields", /*french*/"les #cinq chansons du Temple de l'Esprit# révèlent", /*spanish*/"una #sinfonía del Coloso# conduce a"} + ); + + hintTable[SPIRIT_TEMPLE_MQ_GS_SYMPHONY_ROOM] = HintText::Sometimes({ + //obscure text + Text{"a #spider's symphony in the Colossus# yields", /*french*/"la #mélodie de l'araignée du colosse# révèle", /*spanish*/"la #Skulltula de la sinfonía del Coloso# otorga"}, + }, {}, + //clear text + Text{"a #spider's symphony in the Spirit Temple# yields", /*french*/"la #mélodie de la Skulltula du Temple de l'Esprit# révèle", /*spanish*/"la #Skulltula de la sinfonía del Coloso# otorga"} + ); + + hintTable[SHADOW_TEMPLE_INVISIBLE_FLOORMASTER_CHEST] = HintText::Sometimes({ + //obscure text + Text{"shadows in an #invisible maze# guard", /*french*/"les ombres dans le #labyrinthe invisible# protègent", /*spanish*/"las sombras del #laberinto misterioso# esconden"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_BOMB_FLOWER_CHEST] = HintText::Sometimes({ + //obscure text + Text{"shadows in an #invisible maze# guard", /*french*/"les ombres dans le #labyrinthe invisible# protègent", /*spanish*/"las sombras del #laberinto invisible# esconden"}, + }); + + /*-------------------------- + | ENTRANCE HINT TEXT | + ---------------------------*/ + + hintTable[DESERT_COLOSSUS_TO_COLOSSUS_GROTTO] = HintText::Entrance({ + //obscure text + Text{"lifting a #rock in the desert# reveals", /*french*/"soulever une #roche dans le désert# révèle", /*spanish*/"levantar una #roca del desierto# revela"}, + }); + + hintTable[GV_GROTTO_LEDGE_TO_GV_OCTOROK_GROTTO] = HintText::Entrance({ + //obscure text + Text{"a rock on #a ledge in the valley# hides", /*french*/"soulever une #roche dans la vallée# révèle", /*spanish*/"levantar una #roca al borde del valle# esconde"}, + }); + + hintTable[GC_GROTTO_PLATFORM_TO_GC_GROTTO] = HintText::Entrance({ + //obscure text + Text{"a #pool of lava# in Goron City blocks the way to", /*french*/"l'#étang de lave# dans le village Goron renferme", /*spanish*/"un #estanque de lava# en la Ciudad Goron bloquea el paso a"}, + }); + + hintTable[GERUDO_FORTRESS_TO_GF_STORMS_GROTTO] = HintText::Entrance({ + //obscure text + Text{"a #storm within Gerudo's Fortress# reveals", /*french*/"la #tempête dans la forteresse# révèle", /*spanish*/"una #tormenta en la Fortaleza Gerudo# revela"}, + }); + + hintTable[ZORAS_DOMAIN_TO_ZD_STORMS_GROTTO] = HintText::Entrance({ + //obscure text + Text{"a #storm within Zora's Domain# reveals", /*french*/"la #tempête dans le Domaine Zora# révèle", /*spanish*/"una #tormenta en la Región de los Zora# revela"}, + }); + + hintTable[HYRULE_CASTLE_GROUNDS_TO_HC_STORMS_GROTTO] = HintText::Entrance({ + //obscure text + Text{"a #storm near the castle# reveals", /*french*/"la #tempête près du château# révèle", /*spanish*/"una #tormenta junto al castillo# revela"}, + }); + + hintTable[GV_FORTRESS_SIDE_TO_GV_STORMS_GROTTO] = HintText::Entrance({ + //obscure text + Text{"a #storm in the valley# reveals", /*french*/"la #tempête dans la vallée# révèle", /*spanish*/"una #tormenta en el valle# revela"}, + }); + + hintTable[DESERT_COLOSSUS_TO_COLOSSUS_GREAT_FAIRY_FOUNTAIN] = HintText::Entrance({ + //obscure text + Text{"a #fractured desert wall# hides", /*french*/"le #mur fragile du désert# cache", /*spanish*/"una #agrietada pared del desierto# esconde"}, + }); + + hintTable[GANONS_CASTLE_GROUNDS_TO_OGC_GREAT_FAIRY_FOUNTAIN] = HintText::Entrance({ + //obscure text + Text{"a #heavy pillar# outside the castle obstructs", /*french*/"le #rocher fragile près du château# cache", /*spanish*/"una #pesada columna# fuera del castillo obstruye"}, + }); + + hintTable[ZORAS_FOUNTAIN_TO_ZF_GREAT_FAIRY_FOUNTAIN] = HintText::Entrance({ + //obscure text + Text{"a #fountain wall# hides", /*french*/"le #mur fragile du réservoir# cache", /*spanish*/"una #pared de la fuente# esconde"}, + }); + + hintTable[GV_FORTRESS_SIDE_TO_GV_CARPENTER_TENT] = HintText::Entrance({ + //obscure text + Text{"a #tent in the valley# covers", /*french*/"la #tente dans la vallée# recouvre", /*spanish*/"una #tienda de campaña del valle# cubre"}, + }); + + hintTable[GRAVEYARD_WARP_PAD_REGION_TO_SHADOW_TEMPLE_ENTRYWAY] = HintText::Entrance({ + //obscure text + Text{"at the #back of the Graveyard#, there is", /*french*/"#derrière le Cimetière# gît", /*spanish*/"en la #parte trasera del cementerio# se halla"}, + }); + + hintTable[LAKE_HYLIA_TO_WATER_TEMPLE_LOBBY] = HintText::Entrance({ + //obscure text + Text{"deep #under a vast lake#, one can find", /*french*/"#sous le lac# gît", /*spanish*/"en las #profundidades de un lago inmenso# se halla"}, + }); + + hintTable[GERUDO_FORTRESS_TO_GERUDO_TRAINING_GROUNDS_LOBBY] = HintText::Entrance({ + //obscure text + Text{"paying a #fee to the Gerudos# grants access to", /*french*/"l'#entrée payante des Gerudo# donne accès à", /*spanish*/"pagarle una #tasa a las gerudo# da acceso a"}, + }); + + hintTable[ZORAS_FOUNTAIN_TO_JABU_JABUS_BELLY_BEGINNING] = HintText::Entrance({ + //obscure text + Text{"inside #Jabu-Jabu#, one can find", /*french*/"#dans Jabu-Jabu# se trouve", /*spanish*/"dentro de #Jabu-Jabu# se halla"}, + }); + + hintTable[KAKARIKO_VILLAGE_TO_BOTTOM_OF_THE_WELL] = HintText::Entrance({ + //obscure text + Text{"a #village well# leads to", /*french*/"dans le fond du #Puits du village# gît", /*spanish*/"el #pozo de un pueblo# conduce a"}, + }); + + /*-------------------------- + | EXIT HINT TEXT | + ---------------------------*/ + //maybe make a new type for this? I'm not sure if it really matters + + hintTable[LINKS_POCKET] = HintText::Exclude({ + //obscure text + Text{"Link's Pocket", /*french*/"les Poches de @", /*spanish*/"el bolsillo de @"}, + }); + + hintTable[KOKIRI_FOREST] = HintText::Exclude({ + //obscure text + Text{"Kokiri Forest", /*french*/"la forêt Kokiri", /*spanish*/"el Bosque Kokiri"}, + }); + + hintTable[THE_LOST_WOODS] = HintText::Exclude({ + //obscure text + Text{"the Lost Woods", /*french*/"les Bois Perdus", /*spanish*/"el Bosque Perdido"}, + }); + + hintTable[SACRED_FOREST_MEADOW] = HintText::Exclude({ + //obscure text + Text{"Sacred Forest Meadow", /*french*/"le Bosquet Sacré", /*spanish*/"la pradera sagrada del bosque"}, + }); + + hintTable[HYRULE_FIELD] = HintText::Exclude({ + //obscure text + Text{"Hyrule Field", /*french*/"la Plaine d'Hyrule", /*spanish*/"la Llanura de Hyrule"}, + }); + + hintTable[LAKE_HYLIA] = HintText::Exclude({ + //obscure text + Text{"Lake Hylia", /*french*/"le Lac Hylia", /*spanish*/"el Lago Hylia"}, + }); + + hintTable[GERUDO_VALLEY] = HintText::Exclude({ + //obscure text + Text{"Gerudo Valley", /*french*/"la Vallée Gerudo", /*spanish*/"el Valle Gerudo"}, + }); + + hintTable[GERUDO_FORTRESS] = HintText::Exclude({ + //obscure text + Text{"Gerudo's Fortress", /*french*/"la Repaire des Voleurs", /*spanish*/"la Fortaleza Gerudo"}, + }); + + hintTable[HAUNTED_WASTELAND] = HintText::Exclude({ + //obscure text + Text{"Haunted Wasteland", /*french*/"le Désert Hanté", /*spanish*/"el desierto encantado"}, + }); + + hintTable[DESERT_COLOSSUS] = HintText::Exclude({ + //obscure text + Text{"Desert Colossus", /*french*/"le Colosse du Désert", /*spanish*/"el Coloso del Desierto"}, + }); + + hintTable[THE_MARKET] = HintText::Exclude({ + //obscure text + Text{"the Market", /*french*/"la Place du Marché", /*spanish*/"la plaza del mercado"}, + }); + + hintTable[TEMPLE_OF_TIME] = HintText::Exclude({ + //obscure text + Text{"Temple of Time", /*french*/"le Temple du Temps", /*spanish*/"el Templo del Tiempo"}, + }); + + hintTable[HYRULE_CASTLE] = HintText::Exclude({ + //obscure text + Text{"Hyrule Castle", /*french*/"le Château d'Hyrule", /*spanish*/"el Castillo de Hyrule"}, + }); + + hintTable[OUTSIDE_GANONS_CASTLE] = HintText::Exclude({ + //obscure text + Text{"outside Ganon's Castle", /*french*/"les alentours du Château&de Ganon", /*spanish*/"el exterior del Castillo de Ganon"}, + }); + + hintTable[KAKARIKO_VILLAGE] = HintText::Exclude({ + //obscure text + Text{"Kakariko Village", /*french*/"le Village Cocorico", /*spanish*/"Kakariko"}, + }); + + hintTable[THE_GRAVEYARD] = HintText::Exclude({ + //obscure text + Text{"the Graveyard", /*french*/"le Cimetière", /*spanish*/"el cementerio"}, + }); + + hintTable[DEATH_MOUNTAIN_TRAIL] = HintText::Exclude({ + //obscure text + Text{"Death Mountain Trail", /*french*/"le Chemin du Péril", /*spanish*/"el sendero de la Montaña de la Muerte"}, + }); + + hintTable[GORON_CITY] = HintText::Exclude({ + //obscure text + Text{"Goron City", /*french*/"le Village Goron", /*spanish*/"la Ciudad Goron"}, + }); + + hintTable[DEATH_MOUNTAIN_CRATER] = HintText::Exclude({ + //obscure text + Text{"Death Mountain Crater", /*french*/"le Cratère du Péril", /*spanish*/"el cráter de la Montaña de la Muerte"}, + }); + + hintTable[ZORAS_RIVER] = HintText::Exclude({ + //obscure text + Text{"Zora's River", /*french*/"la Rivière Zora", /*spanish*/"el Río Zora"}, + }); + + hintTable[ZORAS_DOMAIN] = HintText::Exclude({ + //obscure text + Text{"Zora's Domain", /*french*/"le Domaine Zora", /*spanish*/"la Región de los Zora"}, + }); + + hintTable[ZORAS_FOUNTAIN] = HintText::Exclude({ + //obscure text + Text{"Zora's Fountain", /*french*/"la Fontaine Zora", /*spanish*/"la Fuente Zora"}, + }); + + hintTable[LON_LON_RANCH] = HintText::Exclude({ + //obscure text + Text{"Lon Lon Ranch", /*french*/"le Ranch Lon Lon", /*spanish*/"el Rancho Lon Lon"}, + }); + + + /*-------------------------- + | REGION HINT TEXT | + ---------------------------*/ + + hintTable[KF_LINKS_HOUSE] = HintText::Region({ + //obscure text + Text{"Link's House", /*french*/"la #maison de @#", /*spanish*/"la casa de @"}, + }); + + // hintTable[TOT_MAIN] = HintText::Region({ + // //obscure text + // Text{"the #Temple of Time#", /*french*/"le #Temple du Temps#", /*spanish*/"el Templo del Tiempo"}, + // }); + + hintTable[KF_MIDOS_HOUSE] = HintText::Region({ + //obscure text + Text{"Mido's house", /*french*/"la #Cabane du Grand Mido#", /*spanish*/"la casa de Mido"}, + }); + + hintTable[KF_SARIAS_HOUSE] = HintText::Region({ + //obscure text + Text{"Saria's House", /*french*/"la #Cabane de Saria#", /*spanish*/"la casa de Saria"}, + }); + + hintTable[KF_HOUSE_OF_TWINS] = HintText::Region({ + //obscure text + Text{"the #House of Twins#", /*french*/"la #Cabane des Jumelles#", /*spanish*/"la casa de las gemelas"}, + }); + + hintTable[KF_KNOW_IT_ALL_HOUSE] = HintText::Region({ + //obscure text + Text{"Know-It-All Brothers' House", /*french*/"la #Cabane des frères Je-Sais-Tout#", /*spanish*/"la casa de los hermanos Sabelotodo"}, + }); + + hintTable[KF_KOKIRI_SHOP] = HintText::Region({ + //obscure text + Text{"the #Kokiri Shop#", /*french*/"le #Magasin Kokiri#", /*spanish*/"la tienda kokiri"}, + }); + + hintTable[LH_LAB] = HintText::Region({ + //obscure text + Text{"the #Lakeside Laboratory#", /*french*/"le #Laboratoire du Lac#", /*spanish*/"el laboratorio del lago"}, + }); + + hintTable[LH_FISHING_HOLE] = HintText::Region({ + //obscure text + Text{"the #Fishing Pond#", /*french*/"l'#Étang#", /*spanish*/"el estanque"}, + }); + + hintTable[GV_CARPENTER_TENT] = HintText::Region({ + //obscure text + Text{"the #Carpenters' tent#", /*french*/"la #Tente des charpentiers#", /*spanish*/"la #tienda de campaña de los carpinteros#"}, + }); + + hintTable[MARKET_GUARD_HOUSE] = HintText::Region({ + //obscure text + Text{"the #Guard House#", /*french*/"le #poste de garde#", /*spanish*/"la caseta de guardia"}, + }); + + hintTable[MARKET_MASK_SHOP] = HintText::Region({ + //obscure text + Text{"the #Happy Mask Shop#", /*french*/"la #Foire Aux Masques#", /*spanish*/"la tienda de La Máscara Feliz"}, + }); + + hintTable[MARKET_BOMBCHU_BOWLING] = HintText::Region({ + //obscure text + Text{"the #Bombchu Bowling Alley#", /*french*/"le #Bowling Teigneux#", /*spanish*/"la Bolera Bombchu"}, + }); + + hintTable[MARKET_POTION_SHOP] = HintText::Region({ + //obscure text + Text{"the #Market Potion Shop#", /*french*/"l'#apothicaire de la Place du Marché#", /*spanish*/"la tienda de pociones de la plaza del mercado"}, + }); + + hintTable[MARKET_TREASURE_CHEST_GAME] = HintText::Region({ + //obscure text + Text{"the #Treasure Chest Shop#", /*french*/"la #Chasse-aux-Trésors#", /*spanish*/"el Cofre del Tesoro"}, + }); + + hintTable[MARKET_BOMBCHU_SHOP] = HintText::Region({ + //obscure text + Text{"the #Bombchu Shop#", /*french*/"le #Magasin de Missiles#", /*spanish*/"la Tienda Bombchu"}, + }); + + hintTable[MARKET_MAN_IN_GREEN_HOUSE] = HintText::Region({ + //obscure text + Text{"Man in Green's House", /*french*/"la #Maison de l'Homme en Vert#", /*spanish*/"la casa del hombre de verde"}, + }); + + hintTable[KAK_WINDMILL] = HintText::Region({ + //obscure text + Text{"the #Windmill#", /*french*/"le #Moulin#", /*spanish*/"el #molino#"}, + }); + + hintTable[KAK_CARPENTER_BOSS_HOUSE] = HintText::Region({ + //obscure text + Text{"the #Carpenters' Boss House#", /*french*/"la #Maison du Chef des ouvriers#", /*spanish*/"la casa del capataz de los carpinteros"}, + }); + + hintTable[KAK_HOUSE_OF_SKULLTULA] = HintText::Region({ + //obscure text + Text{"the #House of Skulltula#", /*french*/"la #Maison des Skulltulas#", /*spanish*/"la casa de las Skulltulas"}, + }); + + hintTable[KAK_IMPAS_HOUSE] = HintText::Region({ + //obscure text + Text{"Impa's House", /*french*/"la #Maison d'Impa#", /*spanish*/"la casa de Impa"}, + }); + + hintTable[KAK_IMPAS_HOUSE_BACK] = HintText::Region({ + //obscure text + Text{"Impa's cow cage", /*french*/"la #cage à vache d'Impa#", /*spanish*/"la jaula de la vaca de Impa"}, + }); + + hintTable[KAK_ODD_POTION_BUILDING] = HintText::Region({ + //obscure text + Text{"Granny's Potion Shop", /*french*/"la #maison bleue de Cocorico#", /*spanish*/"la tienda de pociones de la abuela"}, + }); + + hintTable[GRAVEYARD_DAMPES_HOUSE] = HintText::Region({ + //obscure text + Text{"Dampé's Hut", /*french*/"la #Cabane du Fossoyeur#", /*spanish*/"la cabaña de Dampé"}, + }); + + hintTable[GC_SHOP] = HintText::Region({ + //obscure text + Text{"the #Goron Shop#", /*french*/"la #Boutique Goron#", /*spanish*/"la #tienda goron#"}, + }); + + hintTable[ZD_SHOP] = HintText::Region({ + //obscure text + Text{"the #Zora Shop#", /*french*/"la #Boutique Zora#", /*spanish*/"la #tienda zora#"}, + }); + + hintTable[LLR_TALONS_HOUSE] = HintText::Region({ + //obscure text + Text{"Talon's House", /*french*/"la #Maison de Talon#", /*spanish*/"la casa de Talon"}, + }); + + hintTable[LLR_STABLES] = HintText::Region({ + //obscure text + Text{"a #stable#", /*french*/"l'#Étable#", /*spanish*/"el establo"}, + }); + + hintTable[LLR_TOWER] = HintText::Region({ + //obscure text + Text{"the #Lon Lon Tower#", /*french*/"le #silo du Ranch Lon Lon#", /*spanish*/"la torre Lon Lon"}, + }); + + hintTable[MARKET_BAZAAR] = HintText::Region({ + //obscure text + Text{"the #Market Bazaar#", /*french*/"le #Bazar de la Place du Marché#", /*spanish*/"el bazar de la plaza del mercado"}, + }); + + hintTable[MARKET_SHOOTING_GALLERY] = HintText::Region({ + //obscure text + Text{"a #Slingshot Shooting Gallery#", /*french*/"le #Jeu d'Adresse de la Place du Marché#", /*spanish*/"el Tiro al Blanco con tirachinas"}, + }); + + hintTable[KAK_BAZAAR] = HintText::Region({ + //obscure text + Text{"the #Kakariko Bazaar#", /*french*/"le #Bazar de Cocorico#", /*spanish*/"el bazar de Kakariko"}, + }); + + hintTable[KAK_POTION_SHOP_FRONT] = HintText::Region({ + //obscure text + Text{"the #Kakariko Potion Shop#", /*french*/"l'#apothicaire de Cocorico#", /*spanish*/"la tienda de pociones de Kakariko"}, + }); + + hintTable[KAK_POTION_SHOP_BACK] = HintText::Region({ + //obscure text + Text{"the #Kakariko Potion Shop#", /*french*/"l'#apothicaire de Cocorico#", /*spanish*/"la tienda de pociones de Kakariko"}, + }); + + hintTable[KAK_SHOOTING_GALLERY] = HintText::Region({ + //obscure text + Text{"a #Bow Shooting Gallery#", /*french*/"le #jeu d'adresse de Cocorico#", /*spanish*/"el Tiro al Blanco con arco"}, + }); + + hintTable[COLOSSUS_GREAT_FAIRY_FOUNTAIN] = HintText::Region({ + //obscure text + Text{"a #Great Fairy Fountain#", /*french*/"une #Fontaine Royale des Fées#", /*spanish*/"una fuente de la Gran Hada"}, + }); + + hintTable[HC_GREAT_FAIRY_FOUNTAIN] = HintText::Region({ + //obscure text + Text{"a #Great Fairy Fountain#", /*french*/"une #Fontaine Royale des Fées#", /*spanish*/"una fuente de la Gran Hada"}, + }); + + hintTable[OGC_GREAT_FAIRY_FOUNTAIN] = HintText::Region({ + //obscure text + Text{"a #Great Fairy Fountain#", /*french*/"une #Fontaine Royale des Fées#", /*spanish*/"una fuente de la Gran Hada"}, + }); + + hintTable[DMC_GREAT_FAIRY_FOUNTAIN] = HintText::Region({ + //obscure text + Text{"a #Great Fairy Fountain#", /*french*/"une #Fontaine Royale des Fées#", /*spanish*/"una fuente de la Gran Hada"}, + }); + + hintTable[DMT_GREAT_FAIRY_FOUNTAIN] = HintText::Region({ + //obscure text + Text{"a #Great Fairy Fountain#", /*french*/"une #Fontaine Royale des Fées#", /*spanish*/"una fuente de la Gran Hada"}, + }); + + hintTable[ZF_GREAT_FAIRY_FOUNTAIN] = HintText::Region({ + //obscure text + Text{"a #Great Fairy Fountain#", /*french*/"une #Fontaine Royale des Fées#", /*spanish*/"una fuente de la Gran Hada"}, + }); + + hintTable[GRAVEYARD_SHIELD_GRAVE] = HintText::Region({ + //obscure text + Text{"a #grave with a free chest#", /*french*/"le #tombeau avec un trésor#", /*spanish*/"la #tumba con un cofre#"}, + }); + + hintTable[GRAVEYARD_HEART_PIECE_GRAVE] = HintText::Region({ + //obscure text + Text{"a chest spawned by #Sun's Song#", /*french*/"un #coffre apparaît avec le Chant du Soleil#", /*spanish*/"la #tumba de la Canción del Sol#"}, + }); + + hintTable[GRAVEYARD_COMPOSERS_GRAVE] = HintText::Region({ + //obscure text + Text{"the #Composers' Grave#", /*french*/"la #Tombe royale#", /*spanish*/"el #Panteón Real#"}, + }); + + hintTable[GRAVEYARD_DAMPES_GRAVE] = HintText::Region({ + //obscure text + Text{"Dampé's Grave", /*french*/"la #Tombe d'Igor#", /*spanish*/"la #tumba de Dampé#"}, + }); + + hintTable[DMT_COW_GROTTO] = HintText::Region({ + //obscure text + Text{"a solitary #Cow#", /*french*/"la #grotte avec une vache#", /*spanish*/"una #vaca# solitaria"}, + }); + + hintTable[HC_STORMS_GROTTO] = HintText::Region({ + //obscure text + Text{"a sandy grotto with #fragile walls#", /*french*/"la #grotte avec des murs fragiles#", /*spanish*/"la arenosa gruta de #frágiles paredes#"}, + }); + + hintTable[HF_TEKTITE_GROTTO] = HintText::Region({ + //obscure text + Text{"a pool guarded by a #Tektite#", /*french*/"l'#étang sous-terrain avec un Araknon#", /*spanish*/"un charco custodiado por un #Tektite#"}, + }); + + hintTable[HF_NEAR_KAK_GROTTO] = HintText::Region({ + //obscure text + Text{"a #Big Skulltula# guarding a Gold one", /*french*/"la #grotte d'araignées#", /*spanish*/"una #gran Skulltula# custodiando una dorada"}, + }); + + hintTable[HF_COW_GROTTO] = HintText::Region({ + //obscure text + Text{"a grotto full of #spider webs#", /*french*/"la #grotte couverte de toiles d'araignées#", /*spanish*/"una gruta llena de #telarañas#"}, + }); + + hintTable[KAK_REDEAD_GROTTO] = HintText::Region({ + //obscure text + Text{"#ReDeads# guarding a chest", /*french*/"le tombeau de #deux morts#", /*spanish*/"los #ReDeads# que custodian un cofre"}, + }); + + hintTable[SFM_WOLFOS_GROTTO] = HintText::Region({ + //obscure text + Text{"#Wolfos# guarding a chest", /*french*/"la #grotte iridescente#", /*spanish*/"los #Wolfos# que custodian un cofre"}, + }); + + hintTable[GV_OCTOROK_GROTTO] = HintText::Region({ + //obscure text + Text{"an #Octorok# guarding a rich pool", /*french*/"un #étang sous-terrain avec un Octorok#", /*spanish*/"un #Octorok# que custodia un lujoso charco"}, + }); + + hintTable[DEKU_THEATER] = HintText::Region({ + //obscure text + Text{"the #Lost Woods Stage#", /*french*/"le #théâtre sylvestre#", /*spanish*/"el #escenario del Bosque Perdido#"}, + }); + + hintTable[ZR_OPEN_GROTTO] = HintText::Region({ + //obscure text + Text{"a #generic grotto#", /*french*/"une #grotte avec un trésor#", /*spanish*/"una #cueva genérica#"}, + }); + + hintTable[DMC_UPPER_GROTTO] = HintText::Region({ + //obscure text + Text{"a #generic grotto#", /*french*/"une #grotte avec un trésor#", /*spanish*/"una #cueva genérica#"}, + }); + + hintTable[DMT_STORMS_GROTTO] = HintText::Region({ + //obscure text + Text{"a #generic grotto#", /*french*/"une #grotte avec un trésor#", /*spanish*/"una #cueva genérica#"}, + }); + + hintTable[KAK_OPEN_GROTTO] = HintText::Region({ + //obscure text + Text{"a #generic grotto#", /*french*/"une #grotte avec un trésor#", /*spanish*/"una #cueva genérica#"}, + }); + + hintTable[HF_NEAR_MARKET_GROTTO] = HintText::Region({ + //obscure text + Text{"a #generic grotto#", /*french*/"une #grotte avec un trésor#", /*spanish*/"una #cueva genérica#"}, + }); + + hintTable[HF_OPEN_GROTTO] = HintText::Region({ + //obscure text + Text{"a #generic grotto#", /*french*/"une #grotte avec un trésor#", /*spanish*/"una #cueva genérica#"}, + }); + + hintTable[HF_SOUTHEAST_GROTTO] = HintText::Region({ + //obscure text + Text{"a #generic grotto#", /*french*/"une #grotte avec un trésor#", /*spanish*/"una #cueva genérica#"}, + }); + + hintTable[KF_STORMS_GROTTO] = HintText::Region({ + //obscure text + Text{"a #generic grotto#", /*french*/"une #grotte avec un trésor#", /*spanish*/"una #cueva genérica#"}, + }); + + hintTable[LW_NEAR_SHORTCUTS_GROTTO] = HintText::Region({ + //obscure text + Text{"a #generic grotto#", /*french*/"une #grotte avec un trésor#", /*spanish*/"una #cueva genérica#"}, + }); + + hintTable[HF_INSIDE_FENCE_GROTTO] = HintText::Region({ + //obscure text + Text{"a #single Upgrade Deku Scrub#", /*french*/"une #grotte avec une peste Mojo#", /*spanish*/"una cueva con un #solitario mercader deku#"}, + }); + + hintTable[LW_SCRUBS_GROTTO] = HintText::Region({ + //obscure text + Text{"#2 Deku Scrubs# including an Upgrade one", /*french*/"une #grotte avec deux pestes Mojo#", /*spanish*/"una cueva con #dos mercaderes deku#"}, + }); + + hintTable[COLOSSUS_GROTTO] = HintText::Region({ + //obscure text + Text{"2 Deku Scrubs", /*french*/"une #grotte avec deux pestes Mojo#", /*spanish*/"una cueva con #dos mercaderes deku#"}, + }); + + hintTable[ZR_STORMS_GROTTO] = HintText::Region({ + //obscure text + Text{"2 Deku Scrubs", /*french*/"une #grotte avec deux pestes Mojo#", /*spanish*/"una cueva con #dos mercaderes deku#"}, + }); + + hintTable[SFM_STORMS_GROTTO] = HintText::Region({ + //obscure text + Text{"2 Deku Scrubs", /*french*/"une #grotte avec deux pestes Mojo#", /*spanish*/"una cueva con #dos mercaderes deku#"}, + }); + + hintTable[GV_STORMS_GROTTO] = HintText::Region({ + //obscure text + Text{"2 Deku Scrubs", /*french*/"une #grotte avec deux pestes Mojo#", /*spanish*/"una cueva con #dos mercaderes deku#"}, + }); + + hintTable[LH_GROTTO] = HintText::Region({ + //obscure text + Text{"3 Deku Scrubs", /*french*/"une #grotte avec trois pestes Mojo#", /*spanish*/"una cueva con #tres mercaderes deku#"}, + }); + + hintTable[DMC_HAMMER_GROTTO] = HintText::Region({ + //obscure text + Text{"3 Deku Scrubs", /*french*/"une #grotte avec trois pestes Mojo#", /*spanish*/"una cueva con #tres mercaderes deku#"}, + }); + + hintTable[GC_GROTTO] = HintText::Region({ + //obscure text + Text{"3 Deku Scrubs", /*french*/"une #grotte avec trois pestes Mojo#", /*spanish*/"una cueva con #tres mercaderes deku#"}, + }); + + hintTable[LLR_GROTTO] = HintText::Region({ + //obscure text + Text{"3 Deku Scrubs", /*french*/"une #grotte avec trois pestes Mojo#", /*spanish*/"una cueva con #tres mercaderes deku#"}, + }); + + hintTable[ZR_FAIRY_GROTTO] = HintText::Region({ + //obscure text + Text{"a small #Fairy Fountain#", /*french*/"une #fontaine de fées#", /*spanish*/"una pequeña #fuente de hadas#"}, + }); + + hintTable[HF_FAIRY_GROTTO] = HintText::Region({ + //obscure text + Text{"a small #Fairy Fountain#", /*french*/"une #fontaine de fées#", /*spanish*/"una pequeña #fuente de hadas#"}, + }); + + hintTable[SFM_FAIRY_GROTTO] = HintText::Region({ + //obscure text + Text{"a small #Fairy Fountain#", /*french*/"une #fontaine de fées#", /*spanish*/"una pequeña #fuente de hadas#"}, + }); + + hintTable[ZD_STORMS_GROTTO] = HintText::Region({ + //obscure text + Text{"a small #Fairy Fountain#", /*french*/"une #fontaine de fées#", /*spanish*/"una pequeña #fuente de hadas#"}, + }); + + hintTable[GF_STORMS_GROTTO] = HintText::Region({ + //obscure text + Text{"a small #Fairy Fountain#", /*french*/"une #fontaine de fées#", /*spanish*/"una pequeña #fuente de hadas#"}, + }); + + /*-------------------------- + | JUNK HINT TEXT | + ---------------------------*/ + + hintTable[JUNK01] = HintText::Junk({ + //obscure text + Text{"Remember to check your 3DS battery level&and save often.", /*french*/"Surveillez votre batterie 3DS et sauvegardez souvent!", /*spanish*/"No te olvides de revisar la batería de la 3DS y guarda partida de vez en cuando."}, + }); + + hintTable[JUNK02] = HintText::Junk({ + //obscure text + Text{"They say you must read the names of \"Special Deal\" shop items carefully.", /*french*/"Selon moi, les « Offres spéciales » sont parfois trompeuses... Lisez attentivement!", /*spanish*/"Según dicen, se debería prestar atención a los nombres de las ofertas especiales."}, + }); + + hintTable[JUNK03] = HintText::Junk({ + //obscure text + Text{"They say that Zelda is a poor leader.", /*french*/"Selon moi, Zelda ne ferait pas un bon monarque.", /*spanish*/"Según dicen, Zelda es mala líder."}, + }); + + hintTable[JUNK04] = HintText::Junk({ + //obscure text + Text{"These hints can be quite useful. This is an exception.", /*french*/"Ces indices sont très utiles, à l'exception de celui-ci.", /*spanish*/"Las pistas suelen servir de ayuda. En cambio, esta no."}, + }); + + hintTable[JUNK05] = HintText::Junk({ + //obscure text + Text{"They say that the Lizalfos in Dodongo's Cavern like to play in lava.", /*french*/"Selon moi, les Lézalfos de la Caverne Dodongo aiment patauger dans la lave.", /*spanish*/"Según dicen, a los Lizalfos de la Cueva de los Dodongos les gusta jugar en la lava."}, + }); + + hintTable[JUNK06] = HintText::Junk({ + //obscure text + Text{"They say that all the Zora drowned in Wind Waker.", /*french*/"Selon moi, les Zoras se sont noyés dans Wind Waker.", /*spanish*/"Según dicen, en Wind Waker todos los zora se ahogaron."}, + }); + + hintTable[JUNK07] = HintText::Junk({ + //obscure text + Text{"If Gorons eat rocks, does that mean I'm in danger?", /*french*/"Ne dis pas au Gorons que je suis ici. Ils mangent des roches, tu sais!", /*spanish*/"Si los Goron se tragan las piedras, ¿no me hace ser una especia vulnarable o algo así"}, + }); + + hintTable[JUNK08] = HintText::Junk({ + //obscure text + Text{"'Member when Ganon was a blue pig?^I 'member.", /*french*/"Dans mon temps, Ganon était un cochon bleu...^Pff! Les jeunes de nos jours, et leur Ganondorf!", /*spanish*/"¿T'acuerdas cuando Ganon era un cerdo azul?^Qué tiempos, chico."}, + }); + + hintTable[JUNK09] = HintText::Junk({ + //obscure text + Text{"One who does not have Triforce can't go in.", /*french*/"Ceux sans Triforce doivent rebrousser chemin.", /*spanish*/"Aquel que no porte la Trifuerza no podrá pasar."}, + }); + + hintTable[JUNK10] = HintText::Junk({ + //obscure text + Text{"Save your future, end the Happy Mask Salesman.", /*french*/"Selon moi, tu t'éviteras des jours de malheur si tu vaincs le vendeur de masques...", /*spanish*/"Salva tu futuro, acaba con el dueño de La Máscara Feliz."}, + }); + + hintTable[JUNK11] = HintText::Junk({ + //obscure text + Text{"Glitches are a pathway to many abilities some consider to be... Unnatural.", /*french*/"Les glitchs sont un moyen d'acquérir de nombreuses facultés considérées par certains comme... contraire à la nature.", /*spanish*/"Los glitches son el camino a muchas habilidades que varios consideran... nada natural."}, + }); + + hintTable[JUNK12] = HintText::Junk({ + //obscure text + Text{"I'm stoned. Get it?", /*french*/"Allez, roche, papier, ciseau...&Roche.", /*spanish*/"Me he quedado de piedra. ¿Lo pillas?"}, + }); + + hintTable[JUNK13] = HintText::Junk({ + //obscure text + Text{"Hoot! Hoot! Would you like me to repeat that?", /*french*/"Hou hou! Veux-tu que je répète tout ça?", /*spanish*/"¡Buuu, buuu! ¿Te lo vuelvo a repetir?"}, + }); + + hintTable[JUNK14] = HintText::Junk({ + //obscure text + Text{"Gorons are stupid. They eat rocks.", /*french*/"Les Gorons sont des vraies têtes dures.", /*spanish*/"Los Goron son tontos. Se comen las piedras."}, + }); + + hintTable[JUNK15] = HintText::Junk({ + //obscure text + Text{"They say that Lon Lon Ranch prospered under Ingo.", /*french*/"Selon moi, le Ranch Lon Lon était plus prospère sous Ingo.", /*spanish*/"Según dicen, el Rancho Lon Lon prosperó gracias a Ingo."}, + }); + + hintTable[JUNK16] = HintText::Junk({ + //obscure text + Text{"The single rupee is a unique item.", /*french*/"Nul objet n'est plus unique que le rubis vert.", /*spanish*/"La rupia de uno es un objeto singular."}, + }); + + hintTable[JUNK17] = HintText::Junk({ + //obscure text + Text{"Without the Lens of Truth, the Treasure Chest Mini-Game is a 1 out of 32 chance.^Good luck!", /*french*/"Gagner la Chasse-aux-Trésors est 1 chance sur 32.^Bonne chance!", /*spanish*/"Sin la Lupa de la Verdad, ganarías 1/32 veces en el Cofre del Tesoro.^¡Buena suerte con ello!"}, + }); + + hintTable[JUNK18] = HintText::Junk({ + //obscure text + Text{"Use bombs wisely.", /*french*/"Utilise les bombes avec précaution.", /*spanish*/"No desperdicies las bombas."}, + }); + + hintTable[JUNK19] = HintText::Junk({ + //obscure text + Text{"They say that Volvagia hates splinters", /*french*/"Selon moi, Volvagia déteste les échardes.", /*spanish*/"Según dicen, Volvagia le teme a las astillas."}, + }); + + hintTable[JUNK20] = HintText::Junk({ + //obscure text + Text{"They say that funky monkeys can be spotted on Friday.", /*french*/"Selon moi, des capucins coquins sortent le vendredi.", /*spanish*/"Según dicen, en los viernes puedes hallar monos marchosos."}, + }); + + hintTable[JUNK21] = HintText::Junk({ + //obscure text + Text{"I found you, faker!", /*french*/"Ah-ha! Je t'ai trouvé!", /*spanish*/"¡Ahí estás, impostor!"}, + }); + + hintTable[JUNK22] = HintText::Junk({ + //obscure text + Text{"They say the Groose is loose.", /*french*/"Selon moi, Hergo est le vrai héros.", /*spanish*/"Según dicen, Malton es un espanto."}, + }); + + hintTable[JUNK23] = HintText::Junk({ + //obscure text + Text{"They say that players who select the \"ON\" option for \"MOTION CONTROL\" are the real \"Zelda players!\"", /*french*/"Selon moi, ceux qui utilisent les contrôles gyroscopiques sont les VRAIS joueurs.", /*spanish*/"Según dicen, aquellos que juegan usando el control por movimiento son los verdaderos jugadores de Zelda."}, + }); + + hintTable[JUNK24] = HintText::Junk({ + //obscure text + Text{"What happened to Sheik?", /*french*/"Donc... Qu'est-ce qui arrive avec Sheik?", /*spanish*/"¿Qué la habrá pasado a Sheik?"}, + }); + + hintTable[JUNK25] = HintText::Junk({ + //obscure text + Text{"L2P @.", /*french*/"Arrête de lire les indices et joue comme un grand, @.", /*spanish*/"Mira que eres novato, @."}, + }); + + hintTable[JUNK26] = HintText::Junk({ + //obscure text + Text{"I've heard you can cheat at Sploosh Kaboom.", /*french*/"Selon moi, il y a une carte aux trésors à Mercantîle... Duh!", /*spanish*/"He oído por ahí que puedes hacer trampa en el Sploosh Kaboom."}, + }); + + hintTable[JUNK27] = HintText::Junk({ + //obscure text + Text{"I'm Lonk from Pennsylvania.", /*french*/"Je suis Lonk, le héros de Pennsylvanie!", /*spanish*/"Soy Lonk, de Pensilvania."}, + }); + + hintTable[JUNK28] = HintText::Junk({ + //obscure text + Text{"I bet you'd like to have more bombs.", /*french*/"Je parie que tu veux plus de bombes.", /*spanish*/"Me apuesto a que quisieras tener más bombas."}, + }); + + hintTable[JUNK29] = HintText::Junk({ + //obscure text + Text{"When all else fails, use Fire.", /*french*/"Quand rien ne marche, utilise le feu.", /*spanish*/"Cuando nada funcione, usa el fuego."}, + }); + + hintTable[JUNK30] = HintText::Junk({ + //obscure text + Text{"Here's a hint, @. Don't be bad.", /*french*/"Selon moi, la #Triforce# n'est pas dans le jeu... Duh!", /*spanish*/"Aquí tienes una pista, @: deja de ser manco."}, + }); + + hintTable[JUNK31] = HintText::Junk({ + //obscure text + Text{"Game Over. Return of Ganon.", /*french*/"Partie terminée. RETour de Ganon.", /*spanish*/"Fin de la partida. El regreso de Ganon."}, + }); + + hintTable[JUNK32] = HintText::Junk({ + //obscure text + Text{"May the way of the Hero lead to the Triforce.", /*french*/"Que le chemin du héros te mène à la Triforce.", /*spanish*/"Puede que la senda del héroe te lleve hacia la Trifuerza."}, + }); + + hintTable[JUNK33] = HintText::Junk({ + //obscure text + Text{"Can't find an item? Scan an Amiibo.", /*french*/"Tu cherches de quoi? Utilise un Amiibo!", /*spanish*/"¿No encuentras algo? Escanea un amiibo."}, + }); + + hintTable[JUNK34] = HintText::Junk({ + //obscure text + Text{"They say this game has just a few glitches.", /*french*/"Selon moi, ce jeu est complètement exempt de glitchs.", /*spanish*/"Dicen que este juego apenas tiene glitches."}, + }); + + hintTable[JUNK35] = HintText::Junk({ + //obscure text + Text{"BRRING BRRING This is Ulrira. Wrong number?", /*french*/"DRING DRING!! Pépé le Ramollo à l'appareil... Quoi? Faux numéro?", /*spanish*/"¡Ring! ¡Ring! Al habla Ulrira. ¿Me he equivocado de número?"}, + }); + + hintTable[JUNK36] = HintText::Junk({ + //obscure text + Text{"Tingle Tingle Kooloo Limpah!", /*french*/"Tingle! Tingle! Kooloolin... Pah!", /*spanish*/"Tingle, Tingle, Kurulín... ¡PA!"}, + }); + + hintTable[JUNK37] = HintText::Junk({ + //obscure text + Text{"L is real 2401", /*french*/"L is real 2401", /*spanish*/"L es real 2401."}, + }); + + hintTable[JUNK38] = HintText::Junk({ + //obscure text + Text{"They say that Ganondorf will appear in the next Mario Tennis.", /*french*/"Selon moi, Ganondorf sera la nouvelle recrue dans Mario Tennis.", /*spanish*/"Según dicen, Ganondorf estará en el próximo Mario Tennis."}, + }); + + hintTable[JUNK39] = HintText::Junk({ + //obscure text + Text{"Medigoron sells the earliest Breath of the Wild demo.", /*french*/"Selon moi, Medigoron vend une démo de #Breath of the Wild#.", /*spanish*/"Medigoron vende la primera demo del Breath of the Wild."}, + }); + + hintTable[JUNK40] = HintText::Junk({ + //obscure text + Text{"Can you move me? I don't get great service here.", /*french*/"Peux-tu me déplacer? J'ai pas une bonne réception ici.", /*spanish*/"¿Puedes llevarme a otro lado? Aquí nadie me presta atención."}, + }); + + hintTable[JUNK41] = HintText::Junk({ + //obscure text + Text{"They say if you use Strength on the truck, you can find Mew.", /*french*/"Selon moi, #Mew# se trouve dessous le camion... Duh!", /*spanish*/"Según dicen, puedes hallar un Mew usando Fuerza contra el camión de Ciudad Carmín."}, + }); + + hintTable[JUNK42] = HintText::Junk({ + //obscure text + Text{"I'm a helpful hint Gossip Stone!^See, I'm helping.", /*french*/"Salut! Je suis une pierre de bons conseils!^Tiens, tu vois? J'aide bien, hein?", /*spanish*/"Soy una Piedra Sheikah muy útil.^¡Mira cómo te ayudo!"}, + }); + + hintTable[JUNK43] = HintText::Junk({ + //obscure text + Text{"Dear @, please come to the castle. I've baked a cake for you.&Yours truly, Princess Zelda.", /*french*/"Mon très cher @:&Viens vite au château, je t'ai préparé&un délicieux gâteau...^À bientôt, Princesse Zelda", /*spanish*/"Querido @: Por favor, ven al castillo. He hecho una tarta para ti.&Sinceramente tuya: Princesa Zelda."}, + }); + + hintTable[JUNK44] = HintText::Junk({ + //obscure text + Text{"They say all toasters toast toast.", /*french*/"Selon moi, les grille-pains grillent du pain.", /*spanish*/"Según dicen, todas las tostadoras tostan tostadas tostadas."}, + }); + + hintTable[JUNK45] = HintText::Junk({ + //obscure text + Text{"You thought it would be a useful hint, but it was me, junk hint!", /*french*/"Tu t'attendais à un bon indice... Mais c'était moi, un mauvais indice!", /*spanish*/"Je... Creeías que iba a ser una piedra de utilidad, ¡pero no, era yo, la piedra de la agonía!"}, + }); + + hintTable[JUNK46] = HintText::Junk({ + //obscure text + Text{"They say that quest guidance can be found at a talking rock.", /*french*/"Selon moi, des #indices# se trouvent auprès d'une pierre parlante... Duh!", /*spanish*/"Según dicen, puedes consultarle ayuda a rocas parlanchinas."}, + }); + + hintTable[JUNK47] = HintText::Junk({ + //obscure text + Text{"They say that the final item you're looking for can be found somewhere in Hyrule.", /*french*/"Selon moi, le #dernier objet# se trouve quelque part dans Hyrule... Duh!", /*spanish*/"Según dicen, el último objeto que te falte puede estar en cualquier rincón de Hyrule."}, + }); + + hintTable[JUNK48] = HintText::Junk({ + //obscure text + Text{"Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.", /*french*/"Mwip.^Mwip.^Mwip.^Mwip.^Mwip.^Mwip.^Mwip.^Mwip.^Mwip.^Mwip.^Mwip.^Mwip.", /*spanish*/"Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep.^Mweep."}, + }); + + hintTable[JUNK49] = HintText::Junk({ + //obscure text + Text{"They say that Barinade fears Deku Nuts.", /*french*/"Selon moi, Barinade a la frousse des noix Mojo.", /*spanish*/"Según dicen, lo que más teme a Barinade son las nueces deku."}, + }); + + hintTable[JUNK50] = HintText::Junk({ + //obscure text + Text{"They say that Flare Dancers do not fear Goron-crafted blades.", /*french*/"Selon moi, le danse-flamme n'a pas peur des armes de Goron.", /*spanish*/"Según dicen, los Bailafuegos no le temen a las armas forjadas por Gorons."}, + }); + + hintTable[JUNK51] = HintText::Junk({ + //obscure text + Text{"They say that Morpha is easily trapped in a corner.", /*french*/"Selon moi, Morpha est facilement coincé.", /*spanish*/"Según dicen, puedes atrapar a Morpha con facilidad en una esquina."}, + }); + + hintTable[JUNK52] = HintText::Junk({ + //obscure text + Text{"They say that Bongo Bongo really hates the cold.", /*french*/"Selon moi, Bongo Bongo a facilement froid aux doigts.", /*spanish*/"Según dicen, Bongo Bongo odia a muerte el frío."}, + }); + + hintTable[JUNK53] = HintText::Junk({ + //obscure text + Text{"They say that your sword is most powerful when you put it away.", /*french*/"Selon moi, ton épée est à pleine puissance quand tu la rengaines.", /*spanish*/"Según dicen, tu espada se vuelve más poderosa si la guardas."}, + }); + + hintTable[JUNK54] = HintText::Junk({ + //obscure text + Text{"They say that bombing the hole Volvagia last flew into can be rewarding.", /*french*/"Selon moi, le trou où se creuse Volvagia est vulnérable aux bombes.", /*spanish*/"Según dicen, trae buena suerte colocar una bomba en el último agujero de donde salió Volvagia."}, + }); + + hintTable[JUNK55] = HintText::Junk({ + //obscure text + Text{"They say that invisible ghosts can be exposed with Deku Nuts.", /*french*/"Selon moi, des fantômes invisibles apparaissent avec des noix Mojo.", /*spanish*/"Según dicen, puedes exponer a los espectros invisibles con nueces deku."}, + }); + + hintTable[JUNK56] = HintText::Junk({ + //obscure text + Text{"They say that the real Phantom Ganon is bright and loud.", /*french*/"Selon moi, le vrai spectre de Ganon est clair et bruyant.", /*spanish*/"Según dicen, el verdadero Ganon Fantasma es brillante y ruidoso."}, + }); + + hintTable[JUNK57] = HintText::Junk({ + //obscure text + Text{"They say that walking backwards is very fast.", /*french*/"Selon moi, tu fais marche arrière très rapidement pour un héros.", /*spanish*/"Según dicen, es más rápido caminar hacia atrás."}, + }); + + hintTable[JUNK58] = HintText::Junk({ + //obscure text + Text{"They say that leaping above the Market entrance enriches most children.", /*french*/"Selon moi, les enfants riches se pavanent en haut du pont-levis.", /*spanish*/"Según dicen, saltar por las cadenas a la entrada de la plaza enriquece a muchos chiquillos."}, + }); + + hintTable[JUNK59] = HintText::Junk({ + //obscure text + Text{"They say Ingo is not very good at planning ahead.", /*french*/"Selon moi, Ingo ne fait pas un très bon geôlier.", /*spanish*/"Según dicen, a Ingo no se le da especialmente bien planificar con antelación."}, + }); + + hintTable[JUNK60] = HintText::Junk({ + //obscure text + Text{"You found a spiritual Stone! By which I mean, I worship Nayru.", /*french*/"Vous avez trouvé une Pierre Ancestrale! En effet, je vénère la déesse Hylia.", /*spanish*/"¡Has encontrado una piedra espiritual! Es que le rindo culto a Nayru..."}, + }); + + hintTable[JUNK61] = HintText::Junk({ + //obscure text + Text{"They say that a flying strike with a Deku Stick is no stronger than a grounded one.", /*french*/"Selon moi, un coup de bâton sauté n'est pas meilleur qu'au sol.", /*spanish*/"Según dicen, los golpes aéreos con palos deku son tan fuertes como los normales."}, + }); + + hintTable[JUNK62] = HintText::Junk({ + //obscure text + Text{"Open your eyes.^Open your eyes.^Wake up, @.", /*french*/"Réveille-toi...^Réveille-toi.^Ouvre les yeux, @.", /*spanish*/"Abre los ojos...^Abre los ojos...^Despierta, @..."}, + }); + + hintTable[JUNK63] = HintText::Junk({ + //obscure text + Text{"They say that the Nocturne of Shadow can bring you very close to Ganon.", /*french*/"Selon moi, le nocturne de l'ombre peut t'amener très près de Ganon.", /*spanish*/"Según dicen, el Nocturno de la sombra te puede acercar mucho a Ganon."}, + }); + + hintTable[JUNK64] = HintText::Junk({ + //obscure text + Text{"They say that Twinrova always casts the same spell the first three times.", /*french*/"Selon moi, Twinrova lance toujours les mêmes trois premiers sorts.", /*spanish*/"Según dicen, Birova siempre lanza el mismo hechizo las tres primeras veces."}, + }); + + hintTable[JUNK65] = HintText::Junk({ + //obscure text + Text{"They say that the nightly builds may be unstable.", /*french*/"Selon moi, les « nightly builds » peuvent être instables.", /*spanish*/"Según dicen, las últimas nightlies pueden llegar a ser algo inestables."}, + }); + + hintTable[JUNK66] = HintText::Junk({ + //obscure text + Text{"You're playing a Randomizer. I'm randomized!^Here's a random number: #4#.&Enjoy your Randomizer!", /*french*/"Tu joues à un randomizer. Je suis aléatoire!^Voici un nombre aléatoire: #4#.&Bonne partie!", /*spanish*/"¡Estás jugando un Randomizer! ¡Yo también estoy aleatorizada!^Aquí tienes un número aleatorio: #8#.&¡Diviértete!"}, + }); + + hintTable[JUNK67] = HintText::Junk({ + //obscure text + Text{"They say Ganondorf's bolts can be reflected with glass or steel.", /*french*/"Selon moi, les éclairs de Ganon se reflètent sur l'acier et le verre.", /*spanish*/"Según dicen, puedes reflejar las esferas de energía de Ganondorf con cristal y acero."}, + }); + + hintTable[JUNK68] = HintText::Junk({ + //obscure text + Text{"They say Ganon's tail is vulnerable to nuts, arrows, swords, explosives, hammers...^...sticks, seeds, boomerangs...^...rods, shovels, iron balls, angry bees...", /*french*/"Selon moi, la queue de Ganon est vulnérable aux noix, flèches, épées, bombes, marteaux...^...bâtons, graines, boomerangs...^...baguettes, pelles, boulets de fer, abeilles enragées...", /*spanish*/"Según dicen, la cola de Ganon es vulnerable a nueces, flechas, espadas, explosivos, martillos...^...palos, semillas, bumeráns...^...cetros, palas, bolas de hierro, abejas..."}, + }); + + hintTable[JUNK69] = HintText::Junk({ + //obscure text + Text{"They say that you're wasting time reading this hint, but I disagree. Talk to me again!", /*french*/"Selon moi... tu sais quoi? Parle-moi encore, et je te le dirai!", /*spanish*/"Según dicen, pierdes el tiempo en leer esta pista, pero no pienso igual. ¡Vuelve a hablarme, ya verás!"}, + }); + + hintTable[JUNK70] = HintText::Junk({ + //obscure text + Text{"They say Ganondorf knows where to find the instrument of his doom.", /*french*/"Selon moi, Ganondorf sait où il a caché son point faible.", /*spanish*/"Según dicen, Ganondorf sabe dónde hallar el instrumento de su perdición."}, + }); + + hintTable[JUNK71] = HintText::Junk({ + //obscure text + Text{"I heard @ is pretty good at Zelda.", /*french*/"Apparemment, @ est super bon à Zelda.", /*spanish*/"He oído que a @ se le dan muy bien los Zelda."}, + }); + + hintTable[JUNK72] = HintText::Junk({ + //obscure text + Text{"Hi @, we've been trying to reach you about your car's extended warranty. ", /*french*/"Bonjour, @. Vous avez une voiture? Vous savez, nous offrons des assurances abordables...", /*spanish*/"Buenas, @. Le llamamos para ofrecerle un nuevo seguro de hogar que puede pagar en cómodos plazos, sin intereses ni comisiones."}, + }); + + hintTable[JUNK73] = HintText::Junk({ + //obscure text + Text{"They say that the best weapon against Iron Knuckles is item 176.", /*french*/"Selon moi, les hache-viandes sont vulnérables contre l'objet 176.", /*spanish*/"Según dicen, la mejor arma para enfrentarse a los Nudillos de hierro es el objeto 176."}, + }); + + hintTable[JUNK74] = HintText::Junk({ + //obscure text + Text{"They say that it's actually possible to beat the running man.", /*french*/"Selon moi, il est possible de battre le coureur.&Donc, tu prends ton arc, et...", /*spanish*/"Según dicen, con mucha perseverancia puedes ganarle al corredor con la capucha de conejo."}, + }); + + hintTable[JUNK75] = HintText::Junk({ + //obscure text + Text{"They say that the stone-cold guardian of the Well is only present during work hours.", /*french*/"Selon moi, le gardien de pierre du Puits quitte le soir pour aller se coucher.", /*spanish*/"Según dicen, la inmensa roca que bloquea el pozo solo trabaja en horas laborales."}, + }); + + hintTable[JUNK76] = HintText::Junk({ + //obscure text + Text{"They say this hint makes more sense in other languages.", /*french*/"Selon moi, ces indices auraient pu être mieux traduits... Duh!", /*spanish*/"Según dicen, esta pista revela algo de vital importancia si cambias el idioma del juego..."}, + }); + + hintTable[JUNK77] = HintText::Junk({ + //obscure text + Text{"BOK? No way.", /*french*/"BD'accord? Hors de question.", /*spanish*/"¿BVale? Ni hablar."}, + }); + + // ^ junk hints above are from 3drando + // v junk hints below are new to soh rando + + #define HINT_TEXT_NEEDS_TRANSLATION_FR "Erreur 0x69a504:&Traduction manquante^C'est de la faute à Purple Hato!&J'vous jure!" + + hintTable[JUNK78] = HintText::Junk({ + //obscure text + Text{"They say blarg...^...or at least briaguya does.", /*french*/HINT_TEXT_NEEDS_TRANSLATION_FR, /*spanish*/"blarg"}, + }); + + hintTable[JUNK79] = HintText::Junk({ + //obscure text + Text{"They say this peace is what all true warriors strive for.", /*french*/HINT_TEXT_NEEDS_TRANSLATION_FR, /*spanish*/"blarg"}, + }); + + hintTable[JUNK80] = HintText::Junk({ + //obscure text + Text{"They say this ship is what all true gamers strive for.", /*french*/HINT_TEXT_NEEDS_TRANSLATION_FR, /*spanish*/"blarg"}, + }); + + hintTable[JUNK81] = HintText::Junk({ + //obscure text + Text{"They say that Glowsticks can be found in the Raveyard.", /*french*/"On peut trouver des Bâton Lumineux sur le dancefloor du cimetière.", /*spanish*/"blarg"}, + }); + + /*-------------------------- + | DUNGEON HINT TEXT | + ---------------------------*/ + + hintTable[DEKU_TREE] = HintText::DungeonName({ + //obscure text + Text{"an ancient tree", /*french*/"le vieil arbre", /*spanish*/"un ancestral árbol"}, + }, {}, + //clear text + Text{"Deku Tree", /*french*/"l'Arbre Mojo", /*spanish*/"el Gran Árbol Deku"} + ); + + hintTable[DODONGOS_CAVERN] = HintText::DungeonName({ + //obscure text + Text{"an immense cavern", /*french*/"l'immense caverne", /*spanish*/"una descomunal cueva"}, + }, {}, + //clear text + Text{ "Dodongo's Cavern", /*french*/"la Caverne Dodongo", /*spanish*/"la Cueva de los Dodongos"} + ); + + hintTable[JABU_JABUS_BELLY] = HintText::DungeonName({ + //obscure text + Text{"the belly of a deity", /*french*/"le ventre d'un gardien", /*spanish*/"la tripa de cierta deidad"}, + }, {}, + //clear text + Text{"Jabu-Jabu's Belly", /*french*/"le Ventre de Jabu-Jabu", /*spanish*/"tripa de Jabu-Jabu"} + ); + + hintTable[FOREST_TEMPLE] = HintText::DungeonName({ + //obscure text + Text{"a deep forest", /*french*/"la profonde forêt", /*spanish*/"las profundidades del bosque"}, + }, {}, + //clear text + Text{"Forest Temple", /*french*/"le Temple de la Forêt", /*spanish*/"el Templo del Bosque"} + ); + + hintTable[FIRE_TEMPLE] = HintText::DungeonName({ + //obscure text + Text{"a high mountain", /*french*/"la grande montagne", /*spanish*/"una alta montaña"}, + }, {}, + //clear text + Text{"Fire Temple", /*french*/"le Temple du Feu", /*spanish*/"el Templo del Fuego"} + ); + + hintTable[WATER_TEMPLE] = HintText::DungeonName({ + //obscure text + Text{"a vast lake", /*french*/"le vaste lac", /*spanish*/"un lago inmenso"}, + }, {}, + //clear text + Text{"Water Temple", /*french*/"le Temple de l'Eau", /*spanish*/"el Templo del Agua"} + ); + + hintTable[SPIRIT_TEMPLE] = HintText::DungeonName({ + //obscure text + Text{"the goddess of the sand", /*french*/"la déesse des sables", /*spanish*/"la diosa de las arenas"}, + }, {}, + //clear text + Text{"Spirit Temple", /*french*/"le Temple de l'Esprit", /*spanish*/"el Templo del Espíritu"} + + ); + + hintTable[SHADOW_TEMPLE] = HintText::DungeonName({ + //obscure text + Text{"the house of the dead", /*french*/"la maison des morts", /*spanish*/"la casa de la muerte"}, + }, {}, + //clear text + Text{"Shadow Temple", /*french*/"le Temple de l'Ombre", /*spanish*/"el Templo de las Sombras"} + ); + + hintTable[ICE_CAVERN] = HintText::DungeonName({ + //obscure text + Text{"a frozen maze", /*french*/"le dédale glacé", /*spanish*/"un gélido laberinto"}, + }, {}, + //clear text + Text{"Ice Cavern", /*french*/"la caverne de glace", /*spanish*/"la caverna de hielo"} + ); + + hintTable[BOTTOM_OF_THE_WELL] = HintText::DungeonName({ + //obscure text + Text{"a shadow\'s prison", /*french*/"la prison d'une ombre", /*spanish*/"la prisión de las sombras"}, + }, {}, + //clear text + Text{"Bottom of the Well", /*french*/"le fonds du Puits", /*spanish*/"el fondo del pozo"} + ); + + hintTable[GERUDO_TRAINING_GROUNDS] = HintText::DungeonName({ + //obscure text + Text{"the test of thieves", /*french*/"l'épreuve des voleurs", /*spanish*/"la prueba de las bandidas"}, + }, {}, + //clear text + Text{"Gerudo Training Grounds", /*french*/"le Gymnase Gerudo", /*spanish*/"el Centro de Instrucción Gerudo"} + ); + + hintTable[GANONS_CASTLE] = HintText::DungeonName({ + //obscure text + Text{"a conquered citadel", /*french*/"la citadelle assiégée", /*spanish*/"una conquistada ciudadela"}, + }, {}, + //clear text + Text{"Inside Ganon's Castle", /*french*/"l'intérieur du Château de Ganon", /*spanish*/"el interior del Castillo de Ganon"} + ); + + /*-------------------------- + | BOSS HINT TEXT | + ---------------------------*/ + + hintTable[QUEEN_GOHMA] = HintText::Boss({ + //obscure text + Text{"An #ancient tree# rewards", /*french*/"le #vieil arbre# octroie", /*spanish*/"un #ancestral árbol# premia con"}, + }, {}, + //clear text + Text{"the #Deku Tree# rewards", /*french*/"l'#Arbre Mojo# octroie", /*spanish*/"el #Gran Árbol Deku# premia con"} + ); + + hintTable[KING_DODONGO] = HintText::Boss({ + //obscure text + Text{"An #immense cavern# rewards", /*french*/"l'#immense caverne# octroie", /*spanish*/"una #descomunal cueva# premia con"}, + }, {}, + //clear text + Text{"#Dodongo's Cavern# rewards", /*french*/"la #Caverne Dodongo# octroie", /*spanish*/"la #Cueva de los Dodongos# premia con"} + ); + + hintTable[BARINADE] = HintText::Boss({ + //obscure text + Text{"the #belly of a deity# rewards", /*french*/"le #ventre du gardien# octroie", /*spanish*/"la #tripa de cierta deidad# premia con"}, + }, {}, + //clear text + Text{"#Jabu-Jabu's Belly# rewards", /*french*/"le #Ventre de Jabu-Jabu# octroie", /*spanish*/"la #tripa de Jabu-Jabu# premia con"} + ); + + hintTable[PHANTOM_GANON] = HintText::Boss({ + //obscure text + Text{"a #deep forest# rewards", /*french*/"la #profonde forêt# octroie", /*spanish*/"el #profundo bosque# premia con"}, + }, {}, + //clear text + Text{"the #Forest Temple# rewards", /*french*/"le #Temple de la Forêt# octroie", /*spanish*/"el #Templo del Bosque# premia con"} + ); + + hintTable[VOLVAGIA] = HintText::Boss({ + //obscure text + Text{"a #high mountain# rewards", /*french*/"la #grande montagne# octroie", /*spanish*/"una #alta montaña# premia con"}, + }, {}, + //clear text + Text{"the #Fire Temple# rewards", /*french*/"le #Temple du Feu# octroie", /*spanish*/"el #Templo del Fuego# premia con"} + ); + + hintTable[MORPHA] = HintText::Boss({ + //obscure text + Text{"a #vast lake# rewards", /*french*/"le #vaste lac# octroie", /*spanish*/"un #lago inmenso# premia con"}, + }, {}, + //clear text + Text{"the #Water Temple# rewards", /*french*/"le #Temple de l'Eau# octroie", /*spanish*/"el #Templo del Agua# premia con"} + ); + + hintTable[BONGO_BONGO] = HintText::Boss({ + //obscure text + Text{"the #house of the dead# rewards", /*french*/"la #maison des morts# octroie", /*spanish*/"la #casa de la muerte# premia con"}, + }, {}, + //clear text + Text{"the #Shadow Temple# rewards", /*french*/"le #Temple de l'Ombre# octroie", /*spanish*/"el #Templo de las Sombras#"} + ); + + hintTable[TWINROVA] = HintText::Boss({ + //obscure text + Text{"a #goddess of the sand# rewards", /*french*/"la #déesse des sables# octroie", /*spanish*/"la #diosa de la arena# premia con"}, + }, {}, + //clear text + Text{"the #Spirit Temple# rewards", /*french*/"le #Temple de l'Esprit# octroie", /*spanish*/"el #Templo del Espíritu# premia con"} + ); + // + // [LINKS_POCKET_BOSS] = HintText::Boss({ + // //obscure text + // Text{"#@'s pocket# rewards", /*french*/"#@ débute avec#", /*spanish*/"el #bolsillo de @# premia con"}, + // }, + // //clear text + // Text{"#@ already has#", /*french*/"#@ a déjà#", /*spanish*/"el #bolsillo de @ ya tiene#"} + // ); + + /*-------------------------- + | BRIDGE HINT TEXT | + ---------------------------*/ + + hintTable[BRIDGE_OPEN_HINT] = HintText::Bridge({ + //obscure text + Text{"The awakened ones have already&created a bridge to the castle&where the evil dwells.", + /*french*/"Les êtres de sagesse ont&déjà créé un pont vers&le repaire du mal.", + /*spanish*/"Los sabios #ya habrán creado un puente#&al castillo, de donde emana el mal."}, + }); + + hintTable[BRIDGE_VANILLA_HINT] = HintText::Bridge({ + //obscure text + Text{"The awakened ones require&the Shadow and Spirit Medallions&as well as the Light Arrows.", + /*french*/"Les êtres de sagesse attendront&le héros muni des #Médaillons de&l'Ombre et l'Esprit# et des&#Flèches de Lumière#.", + /*spanish*/"Los sabios aguardarán a que el héroe&obtenga tanto el #Medallón de las&Sombras y el del Espíritu# junto a la #flecha de luz#."}, + }); + + hintTable[BRIDGE_STONES_HINT] = HintText::Bridge({ + //obscure text singular plural + Text{"The awakened ones will&await for the Hero to collect&%d |Spiritual Stone|Spiritual Stones|.", + /*french*/"Les êtres de sagesse attendront&le héros muni de #%d |Pierre&Ancestrale|Pierres&Ancestrales|#.", + /*spanish*/"Los sabios aguardarán a que el héroe&obtenga #%d |piedra espiritual|piedras espirituales|#."}, + }); + + hintTable[BRIDGE_MEDALLIONS_HINT] = HintText::Bridge({ + //obscure text singular plural + Text{"The awakened ones will await&for the Hero to collect&%d |Medallion|Medallions|.", + /*french*/"Les êtres de sagesse attendront&le héros muni de #%d |médaillon|médaillons|#.", + /*spanish*/"Los sabios aguardarán a que el héroe&obtenga #%d |medallón|medallones|#."}, + }); + + hintTable[BRIDGE_REWARDS_HINT] = HintText::Bridge({ + //obscure text singular plural + Text{"The awakened ones will await&for the Hero to collect&%d |Spiritual Stone or Medallion|Spiritual Stones and Medallions|.", + /*french*/"Les êtres de sagesse attendront&le héros muni de #%d |Pierre&Ancestrale ou Médaillon|Pierres&Ancestrales ou Médaillons|#.", + /*spanish*/"Los sabios aguardarán a que el héroe&obtenga #%d |piedra espiritual o medallón|piedras espirtuales y medallones|#."}, + }); + + hintTable[BRIDGE_DUNGEONS_HINT] = HintText::Bridge({ + //obscure text singular plural + Text{"The awakened ones will await&for the Hero to conquer&%d |Dungeon|Dungeons|.", + /*french*/"Les êtres de sagesse attendront&la conquête de #%d |Donjon|Donjons|#.", + /*spanish*/"Los sabios aguardarán a que el héroe& complete #%d |mazmorra|mazmorras|#."}, + }); + + hintTable[BRIDGE_TOKENS_HINT] = HintText::Bridge({ + //obscure text + Text{"The awakened ones will await&for the Hero to collect&%d |Gold Skulltula Token|Gold Skulltula Tokens|.", + /*french*/"Les êtres de sagesse attendront&le héros muni de #%d |Symbole|Symboles| &de Skulltula d'or#.", + /*spanish*/"Los sabios aguardarán a que el héroe&obtenga #%d |símbolo|símbolos| de&skulltula dorada#."}, + }); + + /*-------------------------- + | GANON BOSS KEY HINT TEXT | + ---------------------------*/ + + hintTable[GANON_BK_START_WITH_HINT] = HintText::GanonsBossKey({ + //obscure text + Text{"And the evil one's key will&be given from the start.", + /*french*/"Aussi, la clé du Malin sera&possession même du héros.", + /*spanish*/"Y obtendrás la llave del #señor del mal# desde el #inicio#."}, + }); + + hintTable[GANON_BK_VANILLA_HINT] = HintText::GanonsBossKey({ + //obscure text + Text{"And the evil one's key will&be kept in a big chest&inside its tower.", + /*french*/"Aussi, la clé du #Malin# sera&encoffrée #dans sa tour#.", + /*spanish*/"Y la llave del #señor del mal# aguardará en un gran cofre de #su torre#."}, + }); + + hintTable[GANON_BK_OWN_DUNGEON_HINT] = HintText::GanonsBossKey({ + //obscure text + Text{"And the evil one's key will&be hidden somewhere inside&its castle.", + /*french*/"Aussi, la clé du #Malin# sera&cachée #dans son vaste château#.", + /*spanish*/"Y la llave del #señor del mal# aguardará en #algún lugar de su castillo#."}, + }); + + hintTable[GANON_BK_OVERWORLD_HINT] = HintText::GanonsBossKey({ + //obscure text + Text{"And the #evil one#'s key will be hidden #outside of dungeons# in Hyrule.", + /*french*/"Aussi, la clé du #Malin# se&trouve #hors des donjons# d'Hyrule.", + /*spanish*/"Y la llave del #señor del mal# aguardará #fuera de las mazmorras# de Hyrule."}, + }); + + hintTable[GANON_BK_ANY_DUNGEON_HINT] = HintText::GanonsBossKey({ + //obscure text + Text{"And the #evil one#'s key will be hidden #inside a dungeon# in Hyrule.", + /*french*/"Aussi, la clé du #Malin# se&trouve #dans un donjon# d'Hyrule.", + /*spanish*/"Y la llave del #señor del mal# aguardará #en una mazmorra# de Hyrule."}, + }); + + hintTable[GANON_BK_ANYWHERE_HINT] = HintText::GanonsBossKey({ + //obscure text + Text{"And the #evil one#'s key will be hidden somewhere #in Hyrule#.", + /*french*/"Aussi, la clé du #Malin# se&trouve quelque part #dans Hyrule#.", + /*spanish*/"Y la llave del #señor del mal# aguardará en #cualquier lugar de Hyrule#."}, + }); + + hintTable[GANON_BK_TRIFORCE_HINT] = HintText::GanonsBossKey({ + //obscure text + Text{"And the #evil one#'s key will be given to the Hero once the #Triforce# is completed.", + /*french*/"Aussi, la clé du #Malin# se&révèlera une fois la #Triforce#&assemblée.", + /*spanish*/"Y el héroe recibirá la llave del #señor del mal# cuando haya completado la #Trifuerza#."}, + }); + + /*-------------------------- + | LACS HINT TEXT | + ---------------------------*/ + + hintTable[LACS_VANILLA_HINT] = HintText::LACS({ + //obscure text + Text{"And the #evil one#'s key will be&provided by Zelda once the #Shadow&and Spirit Medallions# are retrieved.", + /*french*/"Aussi, Zelda crééra la clé du&#Malin# avec les #médaillons de&l'ombre et de l'esprit#.", + /*spanish*/"Y Zelda entregará la llave&del #señor del mal# tras obtener&#el medallón de las sombras y del espíritu#."}, + }); + + hintTable[LACS_MEDALLIONS_HINT] = HintText::LACS({ + //obscure text singular plural + Text{"And the #evil one#'s key will be&provided by Zelda once #%d&|Medallion# is|Medallions# are| retrieved.", + /*french*/"Aussi, Zelda crééra la clé du&#Malin# avec #%d |médaillon|médaillons|#.", + /*spanish*/"Y Zelda entregará la llave&del #señor del mal# tras obtener&#%d |medallón|medallones|#."}, + }); + + hintTable[LACS_STONES_HINT] = HintText::LACS({ + //obscure text singular plural + Text{"And the #evil one#'s key will be&provided by Zelda once #%d |Spiritual&Stone# is|Spiritual&Stones# are| retrieved.", + /*french*/"Aussi, Zelda crééra la clé du&#Malin# avec #%d des |pierre&spirituelle|pierres&spirituelles|#.", + /*spanish*/"Y Zelda entregará la llave&del #señor del mal# tras obtener&#%d |piedra espiritual|piedras espirituales|#."}, + }); + + hintTable[LACS_REWARDS_HINT] = HintText::LACS({ + //obscure text singular plural + Text{"And the #evil one#'s key will be&provided by Zelda once #%d |Spiritual&Stone or Medallion# is|Spiritual&Stones and Medallions# are| retrieved.", + /*french*/"Aussi, Zelda crééra la clé du&#Malin# avec #%d |Pierre Ancestrale&et des médaillon|Pierres Ancestrales&et des médaillons|#.", + /*spanish*/"Y Zelda entregará la llave&del #señor del mal# tras obtener&#%d |piedra espiritual o medallón|piedras espirituales o medallones|#."}, + }); + + hintTable[LACS_DUNGEONS_HINT] = HintText::LACS({ + //obscure text singular plural + Text{"And the #evil one#'s key will be&provided by Zelda once #%d |Dungeon#&is|Dungeons#&are| conquered.", + /*french*/"Aussi, Zelda crééra la clé du&#Malin# une fois #%d |donjon conquéri|donjons conquéris|#.", + /*spanish*/"Y Zelda entregará la llave&del #señor del mal# tras completar&#%d |mazmorra|mazmorras|#."}, + }); + + hintTable[LACS_TOKENS_HINT] = HintText::LACS({ + //obscure text singular plural + Text{"And the #evil one#'s key will be&provided by Zelda once #%d |Gold&Skulltula Token# is|Gold&Skulltula Tokens# are| retrieved.", + /*french*/"Aussi, Zelda crééra la clé du&#Malin# avec #%d |symbole|symboles| de&Skulltula d'or#.", + /*spanish*/"Y Zelda entregará la llave&del #señor del mal# tras obtener&#%d |símbolo|símbolos| de&skulltula dorada#."}, + }); + /*-------------------------- + | TRIAL HINT TEXT | + ---------------------------*/ + + hintTable[SIX_TRIALS] = HintText::Exclude({ + //obscure text + Text{"#Ganon's Tower# is protected by a powerful barrier.", /*french*/"#la Tour de Ganon# est protégée par une puissante barrière", /*spanish*/"la #torre de Ganon# está protegida por una poderosa barrera"}, + }); + + hintTable[ZERO_TRIALS] = HintText::Exclude({ + //obscure text + Text{"Sheik dispelled the barrier around #Ganon's Tower#.", /*french*/"Sheik a dissipé la barrière autour de #la Tour de Ganon#", /*spanish*/"Sheik disipó la barrera alrededor de la #torre de Ganon#."}, + }); + + hintTable[FOUR_TO_FIVE_TRIALS] = HintText::Exclude({ + //obscure text + Text{" was dispelled by Sheik.", /*french*/" a été dissipée par Sheik.", /*spanish*/" se disipó gracias a Sheik."}, + }); + + hintTable[ONE_TO_THREE_TRIALS] = HintText::Exclude({ + //obscure text + Text{" protects Ganons Tower.", /*french*/" protège la Tour de Ganon.", /*spanish*/" protege la torre de Ganon"}, + }); + + /*-------------------------- + | ALTAR TEXT | + ---------------------------*/ + + hintTable[SPIRITUAL_STONE_TEXT_START] = HintText::Altar({ + //obscure text + Text{"3 Spiritual Stones found in Hyrule...", + /*french*/"Les trois Pierres Ancestrales cachées&dans Hyrule...", + /*spanish*/"Tres piedras espirituales halladas por Hyrule..."}, + }); + + hintTable[CHILD_ALTAR_TEXT_END_DOTOPEN] = HintText::Altar({ + //obscure text + Text{"Ye who may become a Hero...&The path to the future is open...", + /*french*/"À celui qui a quête de devenir&héros...&Le futur vous accueille béant...", + /*spanish*/"Para aquel que se convierta en el héroe...&La puerta al futuro está a su disposición..."}, + }); + + hintTable[CHILD_ALTAR_TEXT_END_DOTCLOSED] = HintText::Altar({ + //obscure text + Text{"Ye who may become a Hero...&Stand with the Ocarina and&play the Song of Time.", + /*french*/"À celui qui a quête de devenir&héros...&Portez l'Ocarina et jouez&le chant du temps.", + /*spanish*/"Para aquel que se convierta en el héroe...&Tome la ocarina y&entone la Canción del Tiempo."}, + }); + + hintTable[CHILD_ALTAR_TEXT_END_DOTINTENDED] = HintText::Altar({ + //obscure text + Text{"Ye who may become a Hero...&Offer the spiritual stones and&play the Song of Time.", + /*french*/"À celui qui a quête de devenir&héros... Présentez les Pierres&Ancestrales et jouez&le chant du temps.", + /*spanish*/"Para aquel que se convierta en el héroe...&Tome las piedras espirituales y&entone la Canción del Tiempo."}, + }); + + hintTable[ADULT_ALTAR_TEXT_START] = HintText::Altar({ + //obscure text + Text{"An awakening voice from the Sacred&Realm will call those destined to be&Sages, who dwell in the five temples.", + /*french*/"Quand le mal aura triomphé, une voix&du Saint Royaume appellera ceux&cachés dans les cinq temples, destinés^à être Sages.", + /*spanish*/"Cuando el mal lo impregne todo, desde el Reino Sagrado surgirá una voz que hará despertar a los sabios que moran en los #cinco templos#."}, + }); + + hintTable[ADULT_ALTAR_TEXT_END] = HintText::Altar({ + //obscure text + Text{"$kTogether with the Hero of Time,&the awakened ones will return&the light of peace to the world...", + /*french*/"$kEnsemble avec le Héros du &Temps, ces Sages emprisonneront&le mal et réinstaureront la&lumière de paix dans le monde...", + /*spanish*/"Con el Héroe del Tiempo, aquellos&que despierten detendrán el mal y&volverán al mundo de luz la paz..."}, + }); + + /*-------------------------- + | VALIDATION LINE TEXT | + ---------------------------*/ + + hintTable[VALIDATION_LINE] = HintText::Validation({ + //obscure text + Text{"Hmph... Since you made it this far, I'll let you know what glorious prize of Ganon's you likely missed out on in my tower.^Behold...^", + /*french*/"Pah! Puisque tu t'es rendu ici, je te dirai quel trésor tu as manqué dans ma tour.^Et c'est...^", + /*spanish*/"Mmm... Ya que has llegado hasta aquí, te diré qué preciado objeto de mi propiedad puedes haberte dejado en mi torre.^He aquí...^"}, + }); + + /*-------------------------- + | LIGHT ARROW LOCATION TEXT| + ---------------------------*/ + + hintTable[LIGHT_ARROW_LOCATION_HINT] = HintText::LightArrow({ + //obscure text + Text{"Ha ha ha... You'll never beat me by reflecting my lightning bolts and unleashing the arrows from ", + /*french*/"Ha ha ha... Pauvre fou! Tu ne pourras jamais me vaincre sans les flèches que j'ai cachées dans ", + /*spanish*/"Ja, ja, ja... Nunca me derrotarás reflejando mis esferas de energía y desplegando la flecha de luz de "}, + }); + + hintTable[YOUR_POCKET] = HintText::Exclude({ + //obscure text + Text{"your pocket", /*french*/"tes poches", /*spanish*/"tu bolsillo"}, + }); + + /*-------------------------- + | GANON LINE TEXT | + ---------------------------*/ + + hintTable[GANON_LINE01] = HintText::GanonLine({ + //obscure text + Text{"Oh! It's @.&I was expecting someone called Sheik.&Do you know what happened to them?", + /*french*/"Ah, c'est @.&J'attendais un certain Sheik.&Tu sais ce qui lui est arrivé?", + /*spanish*/"¡Oh! Pero si es @.&Estaba esperando a alguien llamado Sheik. ¿Sabes qué puede haberle pasado?"}, + }); + + hintTable[GANON_LINE02] = HintText::GanonLine({ + //obscure text + Text{"I knew I shouldn't have put the key on the other side of my door.", + /*french*/"J'aurais dû garder la clé ici. Hélas...", + /*spanish*/"Sabía que no tendría que haber dejado la llave al otro lado de la puerta."}, + }); + + hintTable[GANON_LINE03] = HintText::GanonLine({ + //obscure text + Text{"Looks like it's time for a round of tennis.", + /*french*/"C'est l'heure de jouer au tennis.", + /*spanish*/"Parece que es hora de una pachanga de tenis."}, + }); + + hintTable[GANON_LINE04] = HintText::GanonLine({ + //obscure text + Text{"You'll never deflect my bolts of energy with your sword, then shoot me with those Light Arrows you happen to have.", + /*french*/"Ne perds pas ton temps à frapper mes éclairs d'énergie avec ton épée et me tirer avec tes flèches de Lumière!", + /*spanish*/"Nunca reflejarás mis esferas de energía con tu espada, para después dispararme con las flechas de luz que tendrás."}, + }); + + hintTable[GANON_LINE05] = HintText::GanonLine({ + //obscure text + Text{"Why did I leave my trident back in the desert?", + /*french*/"Sale bêtise... Et j'ai oublié mon trident dans le désert!", + /*spanish*/"Santa Hylia... ¿Por qué me habré dejado el tridente en el desierto?"}, + }); + + hintTable[GANON_LINE06] = HintText::GanonLine({ + //obscure text + Text{"Zelda is probably going to do something stupid, like send you back to your own timeline.^So this is quite meaningless. Do you really want to save this moron?", + /*french*/"Même si je suis vaincu... Zelda te renverra dans ton ère, et je reviendrai conquérir!^Telle est la prophécie d'Hyrule Historia!", + /*spanish*/"Seguro que Zelda trata de hacer alguna tontería, como enviarte de vuelta a tu línea temporal.^No tiene ningún sentido alguno. ¿De verdad quieres salvar a esa tonta?"}, + }); + + hintTable[GANON_LINE07] = HintText::GanonLine({ + //obscure text + Text{"What about Zelda makes you think she'd be a better ruler than I?^I saved Lon Lon Ranch,&fed the hungry,&and my castle floats.", + /*french*/"Zelda ne sera jamais un meilleur monarque que moi!^J'ai un château volant, mes sujets sont des belles amazones... et mes Moblins sont clairement plus puissants que jamais!", + /*spanish*/"¿Qué te hace pensar que Zelda gobierna mejor que yo?^Yo he salvado el Rancho Lon Lon,&he alimentado a los hambrientos&y hasta hago que mi castillo flote."}, + }); + + hintTable[GANON_LINE08] = HintText::GanonLine({ + //obscure text + Text{"I've learned this spell,&it's really neat,&I'll keep it later&for your treat!", + /*french*/"Gamin, ton destin achève,&sous mon sort tu périras!&Cette partie ne fut pas brève,&et cette mort, tu subiras!", + /*spanish*/"Veamos ahora que harás,&la batalla ha de comenzar,&te enviaré de una vez al más allá,&¿listo para afrontar la verdad?"}, + }); + + hintTable[GANON_LINE09] = HintText::GanonLine({ + //obscure text + Text{"Many tricks are up my sleeve,&to save yourself&you'd better leave!", + /*french*/"Sale petit garnement,&tu fais erreur!&C'est maintenant que marque&ta dernière heure!", + /*spanish*/"¿No osarás a mí enfrentarte?&Rimas aparte,&¡voy a matarte!"}, + }); + + hintTable[GANON_LINE10] = HintText::GanonLine({ + //obscure text + Text{"After what you did to Koholint Island, how can you call me the bad guy?", + /*french*/"J'admire ce que tu as fait à l'Île Koholint... Toi et moi, nous devrions faire équipe!", + /*spanish*/"Después de lo que le hiciste a la Isla Koholint, ¿cómo te atreves a llamarme malvado?"}, + }); + + hintTable[GANON_LINE11] = HintText::GanonLine({ + //obscure text + Text{"Today, let's begin down&'The Hero is Defeated' timeline.", + /*french*/"Si tu me vaincs, Hyrule sera englouti... mais si tu meurs, on aura A Link to the Past, le meilleur opus de la série!", + /*spanish*/"Hoy daremos lugar a la línea temporal del Héroe Derrotado.&¡Prepárate para el culmen de esta saga!"}, + }); + + /*-------------------------- + | MERCHANTS' ITEMS | + ---------------------------*/ + + hintTable[MEDIGORON_DIALOG_FIRST] = HintText::MerchantsDialogs({ + //obscure text + Text{"How about buying ", + /*french*/"Veux-tu acheter ", + /*spanish*/"¿Me compras "}, + }); + + hintTable[MEDIGORON_DIALOG_SECOND] = HintText::MerchantsDialogs({ + //obscure text + Text{" for #200 Rupees#?&"+TWO_WAY_CHOICE()+"#Buy&Don't buy#", + /*french*/" pour #200 rubis#?&"+TWO_WAY_CHOICE()+"#Acheter&Ne pas acheter#", + /*spanish*/" por #200 rupias#?&"+TWO_WAY_CHOICE()+"#Comprar&No comprar#"}, + }); + + hintTable[CARPET_SALESMAN_DIALOG_FIRST] = HintText::MerchantsDialogs({ + //obscure text + Text{"Welcome!^I am selling stuff, strange and rare, from&all over the world to everybody. Today's&special is...^", + /*french*/"Bienvenue!^Je vends des objets rares et merveilleux du&monde entier. En spécial aujourd'hui...^", + /*spanish*/"¡Acércate!^Vendo productos extraños y difíciles de&encontrar... De todo el mundo a todo el&mundo. La oferta de hoy es...^¡"}, + }); + + hintTable[CARPET_SALESMAN_DIALOG_SECOND] = HintText::MerchantsDialogs({ + //obscure text + Text{"! Terrifying!&I won't tell you what it is until I see the&money...^How about #200 Rupees#?&&"+TWO_WAY_CHOICE()+"#Buy&Don't buy#", + /*french*/"! Un&concentré de puissance! Mais montre tes&rubis avant que je te dise ce que c'est...^Disons #200 rubis#?&&"+TWO_WAY_CHOICE()+"#Acheter&Ne pas acheter#", + /*spanish*/"! ¡Terrorífico!&No te revelaré su nombre hasta que&vea el dinero...^#200 rupias#, ¿qué te parece?&&"+TWO_WAY_CHOICE()+"#Comprar&No comprar#"}, + }); + + hintTable[CARPET_SALESMAN_DIALOG_THIRD] = HintText::MerchantsDialogs({ + //obscure text + Text{"Thank you very much!^What I'm selling is... #", + /*french*/"Merci beaucoup!^Cet objet extraordinaire est... #", + /*spanish*/"¡Muchas gracias!^Lo que vendo es... #¡"}, + }); + + hintTable[CARPET_SALESMAN_DIALOG_FOURTH] = HintText::MerchantsDialogs({ + //obscure text + Text{"!#^The mark that will lead you to the #Spirit&Temple# is the #flag on the "+IF_NOT_MQ()+"left"+MQ_ELSE()+"right"+MQ_END()+"# outside the shop. Be seeing you!", + /*french*/"!#^La marque qui te mènera au #Temple de l'Esprit# est le #drapeau "+IF_NOT_MQ()+"gauche"+MQ_ELSE()+"droite"+MQ_END()+"# en sortant d'ici. À la prochaine!", + /*spanish*/"!#^La marca que te guiará al #Templo del&Espíritu# es la #bandera que está a la&"+IF_NOT_MQ()+"izquierda"+MQ_ELSE()+"derecha"+MQ_END()+"# al salir de aquí. ¡Nos vemos!"}, + }); +} + +int32_t StonesRequiredBySettings() { + int32_t stones = 0; + if (Settings::Bridge.Is(RAINBOWBRIDGE_STONES)) { + stones = std::max({ stones, (int32_t)Settings::BridgeStoneCount.Value() }); + } + if (Settings::Bridge.Is(RAINBOWBRIDGE_REWARDS)) { + stones = std::max({ stones, (int32_t)Settings::BridgeRewardCount.Value() - 6 }); + } + if ((Settings::Bridge.Is(RAINBOWBRIDGE_DUNGEONS)) && (Settings::ShuffleRewards.Is(REWARDSHUFFLE_END_OF_DUNGEON))) { + stones = std::max({ stones, (int32_t)Settings::BridgeDungeonCount.Value() - 6 }); + } + if (Settings::GanonsBossKey.Is(GANONSBOSSKEY_LACS_STONES)) { + stones = std::max({ stones, (int32_t)Settings::LACSStoneCount.Value() }); + } + if (Settings::GanonsBossKey.Is(GANONSBOSSKEY_LACS_REWARDS)) { + stones = std::max({ stones, (int32_t)Settings::LACSRewardCount.Value() - 6 }); + } + if (Settings::GanonsBossKey.Is(GANONSBOSSKEY_LACS_DUNGEONS)) { + stones = std::max({ stones, (int32_t)Settings::LACSDungeonCount.Value() - 6 }); + } + return stones; +} + +int32_t MedallionsRequiredBySettings() { + int32_t medallions = 0; + if (Settings::Bridge.Is(RAINBOWBRIDGE_MEDALLIONS)) { + medallions = std::max({ medallions, (int32_t)Settings::BridgeMedallionCount.Value() }); + } + if (Settings::Bridge.Is(RAINBOWBRIDGE_REWARDS)) { + medallions = std::max({ medallions, (int32_t)Settings::BridgeRewardCount.Value() - 3 }); + } + if ((Settings::Bridge.Is(RAINBOWBRIDGE_DUNGEONS)) && (Settings::ShuffleRewards.Is(REWARDSHUFFLE_END_OF_DUNGEON))) { + medallions = std::max({ medallions, (int32_t)Settings::BridgeDungeonCount.Value() - 3 }); + } + if (Settings::GanonsBossKey.Is(GANONSBOSSKEY_LACS_MEDALLIONS)) { + medallions = std::max({ medallions, (int32_t)Settings::LACSMedallionCount.Value() }); + } + if (Settings::GanonsBossKey.Is(GANONSBOSSKEY_LACS_REWARDS)) { + medallions = std::max({ medallions, (int32_t)Settings::LACSRewardCount.Value() - 3 }); + } + if (Settings::GanonsBossKey.Is(GANONSBOSSKEY_LACS_DUNGEONS)) { + medallions = std::max({ medallions, (int32_t)Settings::LACSDungeonCount.Value() - 3 }); + } + return medallions; +} + +int32_t TokensRequiredBySettings() { + int32_t tokens = 0; + if (Settings::Bridge.Is(RAINBOWBRIDGE_TOKENS)) { + tokens = std::max({ tokens, (int32_t)Settings::BridgeTokenCount.Value() }); + } + if (Settings::GanonsBossKey.Is(GANONSBOSSKEY_LACS_TOKENS)) { + tokens = std::max({ tokens, (int32_t)Settings::LACSTokenCount.Value() }); + } + return tokens; +} + +std::array conditionalAlwaysHints = { + std::make_pair(MARKET_10_BIG_POES, [](){ return Settings::BigPoeTargetCount.Value() >= 3; }), // Remember, the option's value being 3 means 4 are required + std::make_pair(DEKU_THEATER_MASK_OF_TRUTH, [](){ return !Settings::CompleteMaskQuest; }), + std::make_pair(SONG_FROM_OCARINA_OF_TIME, [](){ return StonesRequiredBySettings() < 2; }), + std::make_pair(HF_OCARINA_OF_TIME_ITEM, [](){ return StonesRequiredBySettings() < 2; }), + std::make_pair(SHEIK_IN_KAKARIKO, [](){ return MedallionsRequiredBySettings() < 5; }), + std::make_pair(DMT_TRADE_CLAIM_CHECK, [](){ return false; }), + std::make_pair(KAK_30_GOLD_SKULLTULA_REWARD, [](){ return TokensRequiredBySettings() < 30; }), + std::make_pair(KAK_40_GOLD_SKULLTULA_REWARD, [](){ return TokensRequiredBySettings() < 40; }), + std::make_pair(KAK_50_GOLD_SKULLTULA_REWARD, [](){ return TokensRequiredBySettings() < 50; }) +}; + +const HintText& Hint(const uint32_t hintKey) { + return hintTable[hintKey]; +} + +std::vector GetHintCategory(HintCategory category) { + + std::vector hintsInCategory = {}; + + for (const auto& hint : hintTable) { + if (hint.GetType() == category) { + hintsInCategory.push_back(hint); + } + } + return hintsInCategory; +} diff --git a/soh/soh/Enhancements/randomizer/3drando/hint_list.hpp b/soh/soh/Enhancements/randomizer/3drando/hint_list.hpp new file mode 100644 index 000000000..f60297179 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/hint_list.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "hints.hpp" +#include "keys.hpp" + +#include + +extern std::array hintTable; + +void HintTable_Init(); +const HintText& Hint(uint32_t hintKey); +std::vector GetHintCategory(HintCategory category); + +void HintTable_Init_Item(); +void HintTable_Init_Exclude_Overworld(); +void HintTable_Init_Exclude_Dungeon(); \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_exclude_dungeon.cpp b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_exclude_dungeon.cpp new file mode 100644 index 000000000..ed54508ca --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_exclude_dungeon.cpp @@ -0,0 +1,1964 @@ +#include "../hint_list.hpp" + +void HintTable_Init_Exclude_Dungeon() { + /*-------------------------- + | DEKU TREE | + ---------------------------*/ + hintTable[DEKU_TREE_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"in the #center of the Deku Tree# lies", /*french*/"#le coeur de l'Arbre Mojo# recèle", /*spanish*/"al #centro del Gran Árbol Deku# yace"}, + }); + + hintTable[DEKU_TREE_SLINGSHOT_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #treasure guarded by a scrub# in the Deku Tree is", /*french*/"le #trésor protégé par une peste# dans l'Arbre Mojo est", /*spanish*/"un #deku del Gran Árbol Deku# esconde"}, + }); + + hintTable[DEKU_TREE_SLINGSHOT_ROOM_SIDE_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #treasure guarded by a scrub# in the Deku Tree is", /*french*/"le #trésor protégé par une peste# dans l'Arbre Mojo est", /*spanish*/"un #deku del Gran Árbol Deku# esconde"}, + }); + + hintTable[DEKU_TREE_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#pillars of wood# in the Deku Tree lead to", /*french*/"les #piliers de bois# dans l'Arbre Mojo indiquent", /*spanish*/"los #salientes del Gran Árbol Deku# conducen a"}, + }); + + hintTable[DEKU_TREE_COMPASS_ROOM_SIDE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#pillars of wood# in the Deku Tree lead to", /*french*/"les #piliers de bois# dans l'Arbre Mojo indiquent", /*spanish*/"los #salientes del Gran Árbol Deku# conducen a"}, + }); + + hintTable[DEKU_TREE_BASEMENT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#webs in the Deku Tree# hide", /*french*/"les #toiles dans l'Arbre Mojo# cachent", /*spanish*/"entre #telarañas del Gran Árbol Deku# yace"}, + }); + + + hintTable[DEKU_TREE_MQ_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"in the #center of the Deku Tree# lies", /*french*/"#le coeur de l'Arbre Mojo# recèle", /*spanish*/"al #centro del Gran Árbol Deku# yace"}, + }); + + hintTable[DEKU_TREE_MQ_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #treasure guarded by a large spider# in the Deku Tree is", /*french*/"le #trésor protégé par une grosse araignée# dans l'Arbre Mojo est", /*spanish*/"una #gran araña del Gran Árbol Deku# esconde"}, + }); + + hintTable[DEKU_TREE_MQ_SLINGSHOT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#pillars of wood# in the Deku Tree lead to", /*french*/"les #piliers de bois# dans l'Arbre Mojo indiquent", /*spanish*/"los #salientes del Gran Árbol Deku# conducen a"}, + }); + + hintTable[DEKU_TREE_MQ_SLINGSHOT_ROOM_BACK_CHEST] = HintText::Exclude({ + //obscure text + Text{"#pillars of wood# in the Deku Tree lead to", /*french*/"les #piliers de bois# dans l'Arbre Mojo indiquent", /*spanish*/"los #salientes del Gran Árbol Deku# conducen a"}, + }); + + hintTable[DEKU_TREE_MQ_BASEMENT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#webs in the Deku Tree# hide", /*french*/"les #toiles dans l'Arbre Mojo# cachent", /*spanish*/"entre #telarañas del Gran Árbol Deku# yace"}, + }); + + hintTable[DEKU_TREE_MQ_BEFORE_SPINNING_LOG_CHEST] = HintText::Exclude({ + //obscure text + Text{"#magical fire in the Deku Tree# leads to", /*french*/"le #feu magique dans l'Arbre Mojo# éclaire", /*spanish*/"el #fuego mágico en el Gran Árbol Deku# conduce a"}, + }); + + hintTable[DEKU_TREE_QUEEN_GOHMA_HEART] = HintText::Exclude({ + //obscure text + Text{"the #Parasitic Armored Arachnid# holds", /*french*/"le #monstre insectoïde géant# possède", /*spanish*/"el #arácnido parasitario acorazado# porta"}, + }, {}, + //clear text + Text{"#Queen Gohma# holds", /*french*/"la #Reine Gohma# possède", /*spanish*/"la #Reina Goma# porta"} + ); + + hintTable[DEKU_TREE_GS_BASEMENT_BACK_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider deep within the Deku Tree# hides", /*french*/"une #Skulltula au coeur de l'Arbre Mojo# a", /*spanish*/"una #Skulltula en las profundidades del Árbol Deku# otorga"}, + }); + + hintTable[DEKU_TREE_GS_BASEMENT_GATE] = HintText::Exclude({ + //obscure text + Text{"a #web protects a spider# within the Deku Tree holding", /*french*/"une #Skulltula derrière une toile dans l'Arbre Mojo# a", /*spanish*/"una #Skulltula protegida por su tela# del Árbol Deku otorga"}, + }); + + hintTable[DEKU_TREE_GS_BASEMENT_VINES] = HintText::Exclude({ + //obscure text + Text{"a #web protects a spider# within the Deku Tree holding", /*french*/"une #Skulltula derrière une toile dans l'Arbre Mojo# a", /*spanish*/"una #Skulltula protegida por su tela# del Árbol Deku otorga"}, + }); + + hintTable[DEKU_TREE_GS_COMPASS_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider atop the Deku Tree# holds", /*french*/"une #Skulltula au sommet de l'Arbre Mojo# a", /*spanish*/"una #Skulltula en lo alto del Árbol Deku# otorga"}, + }); + + + hintTable[DEKU_TREE_MQ_GS_LOBBY] = HintText::Exclude({ + //obscure text + Text{"a #spider in a crate# within the Deku Tree hides", /*french*/"une #Skulltula dans une boîte dans l'Arbre Mojo# a", /*spanish*/"una #Skulltula bajo una caja# del Árbol Deku otorga"}, + }); + + hintTable[DEKU_TREE_MQ_GS_COMPASS_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #wall of rock protects a spider# within the Deku Tree holding", /*french*/"une #Skulltula derrière des rochers dans l'Arbre Mojo# a", /*spanish*/"una #Skulltula protegida por una pared rocosa# del Árbol Deku otorga"}, + }); + + hintTable[DEKU_TREE_MQ_GS_BASEMENT_BACK_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider deep within the Deku Tree# hides", /*french*/"une #Skulltula au coeur de l'Arbre Mojo# a", /*spanish*/"una #Skulltula en las profundidades del Árbol Deku# otorga"}, + }); + + hintTable[DEKU_TREE_MQ_DEKU_SCRUB] = HintText::Exclude({ + //obscure text + Text{"a #scrub in the Deku Tree# sells", /*french*/"la #peste Mojo dans l'Arbre Mojo# vend", /*spanish*/"un #deku del Gran Árbol Deku# vende"}, + }); + + /*-------------------------- + | DODONGOS CAVERN | + ---------------------------*/ + hintTable[DODONGOS_CAVERN_BOSS_ROOM_CHEST] = HintText::Exclude({ + //obscure text + Text{"#above King Dodongo# lies", /*french*/"#par dessus le Roi Dodongo# gît", /*spanish*/"#sobre el Rey Dodongo# yace"}, + }); + + hintTable[DODONGOS_CAVERN_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #muddy wall in Dodongo's Cavern# hides", /*french*/"le #mur fragile dans la Caverne Dodongo# recèle", /*spanish*/"tras una #agrietada pared en la Cueva de los Dodongos# yace"}, + }); + + hintTable[DODONGOS_CAVERN_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #statue in Dodongo's Cavern# guards", /*french*/"la #statue dans la Caverne Dodongo# protège", /*spanish*/"una #estatua de la Cueva de los Dodongos# esconde"}, + }); + + hintTable[DODONGOS_CAVERN_BOMB_FLOWER_PLATFORM_CHEST] = HintText::Exclude({ + //obscure text + Text{"above a #maze of stone# in Dodongo's Cavern lies", /*french*/"sur #un labyrinthe de pierre# dans la Caverne Dodongo gît", /*spanish*/"entre un #laberinto de piedra# en la Cueva de los Dodongos yace"}, + }); + + hintTable[DODONGOS_CAVERN_BOMB_BAG_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #second lizard cavern battle# yields", /*french*/"le #deuxième duel de lézards de caverne# octroie", /*spanish*/"#luchar dos veces contra reptiles en una cueva# conduce a"}, + }); + + hintTable[DODONGOS_CAVERN_END_OF_BRIDGE_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #chest at the end of a bridge# yields", /*french*/"le #trésor à l'extrémité d'un pont# contient", /*spanish*/"un #cofre al final de un quebrado puente# contiene"}, + }); + + + hintTable[DODONGOS_CAVERN_MQ_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #muddy wall in Dodongo's Cavern# hides", /*french*/"le #mur fragile dans la Caverne Dodongo# recèle", /*spanish*/"una #agrietada pared en la Cueva de los Dodongos# esconde"}, + }); + + hintTable[DODONGOS_CAVERN_MQ_BOMB_BAG_CHEST] = HintText::Exclude({ + //obscure text + Text{"an #elevated alcove# in Dodongo's Cavern holds", /*french*/"l'#alcove haut perchée# dans la Caverne Dodongo cache", /*spanish*/"una #elevada alcoba# en la Cueva de los Dodongos brinda"}, + }); + + hintTable[DODONGOS_CAVERN_MQ_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#fire-breathing lizards# in Dodongo's Cavern guard", /*french*/"les #lézards cracheurs de feu# dans la Caverne Dodongo protègent", /*spanish*/"unos #flamígeros reptiles# en la Cueva de los Dodongos esconden"}, + }); + + hintTable[DODONGOS_CAVERN_MQ_LARVAE_ROOM_CHEST] = HintText::Exclude({ + //obscure text + Text{"#baby spiders# in Dodongo's Cavern guard", /*french*/"les #petites araignées dans la Caverne Dodongo# protègent", /*spanish*/"unas #pequeñas larvas# en la Cueva de los Dodongos esconden"}, + }); + + hintTable[DODONGOS_CAVERN_MQ_TORCH_PUZZLE_ROOM_CHEST] = HintText::Exclude({ + //obscure text + Text{"above a #maze of stone# in Dodongo's Cavern lies", /*french*/"sur #un labyrinthe de pierre# dans la Caverne Dodongo gît", /*spanish*/"sobre un #laberinto de piedra# en la Cueva de los Dodongos yace"}, + }); + + hintTable[DODONGOS_CAVERN_MQ_UNDER_GRAVE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#beneath a headstone# in Dodongo's Cavern lies", /*french*/"#sous une pierre tombale# dans la Caverne Dodongo gît", /*spanish*/"#bajo una lápida# en la Cueva de los Dodongos yace"}, + }); + + hintTable[DODONGOS_CAVERN_KING_DODONGO_HEART] = HintText::Exclude({ + //obscure text + Text{"the #Infernal Dinosaur# holds", /*french*/"le #dinosaure infernal# possède", /*spanish*/"el #dinosaurio infernal# porta"}, + }, {}, + //clear text + Text{"#King Dodongo# holds", /*french*/"le #Roi Dodongo# possède", /*spanish*/"el #Rey Dodongo# porta"} + ); + + hintTable[DODONGOS_CAVERN_GS_VINES_ABOVE_STAIRS] = HintText::Exclude({ + //obscure text + Text{"a #spider entangled in vines# in Dodongo's Cavern guards", /*french*/"une #Skulltula sur les vignes dans la Caverne Dodongo# a", /*spanish*/"una #Skulltula sobre unas cepas# de la Cueva de los Dodongos otorga"}, + }); + + hintTable[DODONGOS_CAVERN_GS_SCARECROW] = HintText::Exclude({ + //obscure text + Text{"a #spider among explosive slugs# hides", /*french*/"une #Skulltula dans l'alcove du couloir dans la Caverne Dodongo# a", /*spanish*/"una #Skulltula rodeada de explosivos gusanos# otorga"}, + }); + + hintTable[DODONGOS_CAVERN_GS_ALCOVE_ABOVE_STAIRS] = HintText::Exclude({ + //obscure text + Text{"a #spider just out of reach# in Dodongo's Cavern holds", /*french*/"une #Skulltula au haut des escaliers de la Caverne Dodongo# a", /*spanish*/"una #Skulltula fuera del alcance# de la Cueva de los Dodongos otorga"}, + }); + + hintTable[DODONGOS_CAVERN_GS_BACK_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider behind a statue# in Dodongo's Cavern holds", /*french*/"une #Skulltula au coeur de la Caverne Dodongo# a", /*spanish*/"una #Skulltula tras una estatua# de la Cueva de los Dodongos otorga"}, + }); + + hintTable[DODONGOS_CAVERN_GS_SIDE_ROOM_NEAR_LOWER_LIZALFOS] = HintText::Exclude({ + //obscure text + Text{"a #spider among bats# in Dodongo's Cavern holds", /*french*/"une #Skulltula entourée de Saigneurs dans la Caverne Dodongo# a", /*spanish*/"una #Skulltula rodeada de murciélagos# de la Cueva de los Dodongos otorga"}, + }); + + + hintTable[DODONGOS_CAVERN_MQ_GS_SCRUB_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider high on a wall# in Dodongo's Cavern holds", /*french*/"une #Skulltula haut perchée dans la Caverne Dodongo# a", /*spanish*/"una #Skulltula en lo alto de una pared# de la Cueva de los Dodongos otorga"}, + }); + + hintTable[DODONGOS_CAVERN_MQ_GS_LIZALFOS_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider on top of a pillar of rock# in Dodongo's Cavern holds", /*french*/"une #Skulltula sur l'énorme pilier de roc de la Caverne Dodongo# a", /*spanish*/"una #Skulltula en lo alto de un pilar# de la Cueva de los Dodongos otorga"}, + }); + + hintTable[DODONGOS_CAVERN_MQ_GS_LARVAE_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider in a crate# in Dodongo's Cavern holds", /*french*/"une #Skulltula dans une boîte de la Caverne Dodongo# a", /*spanish*/"una #Skulltula bajo una caja# de la Cueva de los Dodongos otorga"}, + }); + + hintTable[DODONGOS_CAVERN_MQ_GS_BACK_AREA] = HintText::Exclude({ + //obscure text + Text{"a #spider among graves# in Dodongo's Cavern holds", /*french*/"une #Skulltula parmi les tombes de la Caverne Dodongo# a", /*spanish*/"una #Skulltula entre lápidas# en la Cueva de los Dodongos otorga"}, + }); + + hintTable[DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT] = HintText::Exclude({ + //obscure text + Text{"a pair of #scrubs in Dodongo's Cavern# sells", /*french*/"le #duo de peste Mojo dans la Caverne Dodongo# vend", /*spanish*/"un #par de dekus en la Cueva de los Dodongos# venden"}, + }); + + hintTable[DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS] = HintText::Exclude({ + //obscure text + Text{"a #scrub guarded by Lizalfos# sells", /*french*/"la #peste Mojo au coeur de la Caverne Dodongo# vend", /*spanish*/"un #deku custodiado por Lizalfos# vende"}, + }); + + hintTable[DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT] = HintText::Exclude({ + //obscure text + Text{"a pair of #scrubs in Dodongo's Cavern# sells", /*french*/"le #duo de peste Mojo dans la Caverne Dodongo# vend", /*spanish*/"un #par de dekus en la Cueva de los Dodongos# venden"}, + }); + + hintTable[DODONGOS_CAVERN_DEKU_SCRUB_LOBBY] = HintText::Exclude({ + //obscure text + Text{"a #scrub in Dodongo's Cavern# sells", /*french*/"la #peste Mojo dans l'entrée de la Caverne Dodongo# vend", /*spanish*/"un #deku en la Cueva de los Dodongos# vende"}, + }); + + + hintTable[DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR] = HintText::Exclude({ + //obscure text + Text{"a pair of #scrubs in Dodongo's Cavern# sells", /*french*/"le #duo de peste Mojo dans l'entrée de la Caverne Dodongo# vend", /*spanish*/"un #par de dekus en la Cueva de los Dodongos# venden"}, + }); + + hintTable[DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT] = HintText::Exclude({ + //obscure text + Text{"a pair of #scrubs in Dodongo's Cavern# sells", /*french*/"le #duo de peste Mojo dans l'entrée de la Caverne Dodongo# vend", /*spanish*/"un #par de dekus en la Cueva de los Dodongos# venden"}, + }); + + hintTable[DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE] = HintText::Exclude({ + //obscure text + Text{"a #scrub in Dodongo's Cavern# sells", /*french*/"la #peste Mojo au sommet des escaliers dans la Caverne Dodongo# vend", /*spanish*/"un #deku en la Cueva de los Dodongos# vende"}, + }); + + hintTable[DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS] = HintText::Exclude({ + //obscure text + Text{"a #scrub guarded by Lizalfos# sells", /*french*/"la #peste Mojo au coeur de la Caverne Dodongo# vend", /*spanish*/"un #deku custodiado por Lizalfos# vende"}, + }); + + /*-------------------------- + | JABU JABUS BELLY | + ---------------------------*/ + hintTable[JABU_JABUS_BELLY_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"#tentacle trouble# in a deity's belly guards", /*french*/"la #membrane# dans le ventre du gardien protège", /*spanish*/"un #problema tentaculoso# en la tripa de cierta deidad esconde"}, + }, {}, + //clear text + Text{"a #slimy thing# guards", /*french*/"la #chose gluante# gardien protège", /*spanish*/"un #tentáculo parasitario# protege"} + ); + + hintTable[JABU_JABUS_BELLY_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#bubble trouble# in a deity's belly guards", /*french*/"un #horde de bulles# dans le ventre du gardien protègent", /*spanish*/"un #problema burbujesco# en la tripa de cierta deidad esconde"}, + }, {}, + //clear text + Text{"#bubbles# guard", /*french*/"des #bulles# entourent", /*spanish*/"unas #burbujas# protegen"} + ); + + + hintTable[JABU_JABUS_BELLY_MQ_FIRST_ROOM_SIDE_CHEST] = HintText::Exclude({ + //obscure text + Text{"shooting a #mouth cow# reveals", /*french*/"tirer sur une #vache# révèle", /*spanish*/"#dispararle a una vaca# revela"}, + }); + + hintTable[JABU_JABUS_BELLY_MQ_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"#pop rocks# hide", /*french*/"des #pierres aux reins# cachent", /*spanish*/"#cepillarse los dientes con explosivos# revela"}, + Text{"an #explosive palate# holds", /*french*/"des #gargouillis explosifs# cachent", /*spanish*/"un #paladar explosivo# esconde"}, + }, {}, + //clear text + Text{"a #boulder before cows# hides", /*french*/"des #rochers près des vaches# cachent", /*spanish*/"cierta #roca rodeada de vacas# esconde"} + ); + + hintTable[JABU_JABUS_BELLY_MQ_SECOND_ROOM_LOWER_CHEST] = HintText::Exclude({ + //obscure text + Text{"near a #spiked elevator# lies", /*french*/"près d'un #ascenseur visqueux# gît", /*spanish*/"cerca de un #ascensor puntiagudo# yace"}, + }); + + hintTable[JABU_JABUS_BELLY_MQ_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #drowning cow# unveils", /*french*/"une #vache à l'eau# a", /*spanish*/"una #vaca sumergida# revela"}, + }); + + hintTable[JABU_JABUS_BELLY_MQ_SECOND_ROOM_UPPER_CHEST] = HintText::Exclude({ + //obscure text + Text{"#moving anatomy# creates a path to", /*french*/"un #organe descendant# mène à", /*spanish*/"un #ser movedizo entre paredes# conduce a"}, + }); + + hintTable[JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_SWITCHES_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #pair of digested cows# hold", /*french*/"#deux boeufs digérés# détiennent", /*spanish*/"un #par de digeridas vacas# otorgan"}, + }); + + hintTable[JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_VINES_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #pair of digested cows# hold", /*french*/"#deux boeufs digérés# détiennent", /*spanish*/"un #par de digeridas vacas# otorgan"}, + }); + + hintTable[JABU_JABUS_BELLY_MQ_NEAR_BOSS_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #final cows' reward# in a deity's belly is", /*french*/"le #cadeau des dernières vaches# estomacales est", /*spanish*/"las #vacas al final# de la tripa de cierta deidad otorgan"}, + }); + + hintTable[JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_ROOM_CHEST] = HintText::Exclude({ + //obscure text + Text{"#cows protected by falling monsters# in a deity's belly guard", /*french*/"des #vaches protégées par des monstres tombants# cachent", /*spanish*/"unas #vacas custodiadas por monstruos del techo# de la tripa de cierta deidad otorgan"}, + }); + + hintTable[JABU_JABUS_BELLY_MQ_BOOMERANG_ROOM_SMALL_CHEST] = HintText::Exclude({ + //obscure text + Text{"a school of #stingers swallowed by a deity# guard", /*french*/"les #raies avallées par le gardien# protègent", /*spanish*/"unos #stingers engullidos por cierta deidad# guardan"}, + }, {}, + //clear text + Text{"a school of #stingers swallowed by Jabu-Jabu# guard", /*french*/"les #raies avallées par Jabu-Jabu# protègent", /*spanish*/"unos #stingers engullidos por Jabu-Jabu# guardan"} + ); + + hintTable[JABU_JABUS_BELLY_MQ_BOOMERANG_CHEST] = HintText::Exclude({ + //obscure text + Text{"a school of #stingers swallowed by a deity# guard", /*french*/"les #raies avallées par le gardien# protègent", /*spanish*/"unos #stingers engullidos por cierta deidad# guardan"}, + }, {}, + //clear text + Text{"a school of #stingers swallowed by Jabu-Jabu# guard", /*french*/"les #raies avallées par Jabu-Jabu# protègent", /*spanish*/"unos #stingers engullidos por Jabu-Jabu# guardan"} + ); + + hintTable[JABU_JABUS_BELLY_BARINADE_HEART] = HintText::Exclude({ + //obscure text + Text{"the #Bio-Electric Anemone# holds", /*french*/"l'#anémone bioélectrique# possède", /*spanish*/"la #anémona bioeléctrica# porta"}, + }, {}, + //clear text + Text{"#Barinade# holds", /*french*/"#Barinade# possède", /*spanish*/"#Barinade# porta"} + ); + + hintTable[JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_LOWER] = HintText::Exclude({ + //obscure text + Text{"a #spider resting near a princess# in Jabu-Jabu's Belly holds", /*french*/"une #Skulltula près de la princesse dans le Ventre de Jabu-Jabu# a", /*spanish*/"una #Skulltula junto a una princesa# en la Tripa de Jabu-Jabu otorga"}, + }); + + hintTable[JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_UPPER] = HintText::Exclude({ + //obscure text + Text{"a #spider resting near a princess# in Jabu-Jabu's Belly holds", /*french*/"une #Skulltula près de la princesse dans le Ventre de Jabu-Jabu# a", /*spanish*/"una #Skulltula junto a una princesa# en la Tripa de Jabu-Jabu otorga"}, + }); + + hintTable[JABU_JABUS_BELLY_GS_NEAR_BOSS] = HintText::Exclude({ + //obscure text + Text{"#jellyfish surround a spider# holding", /*french*/"une #Skulltula entourée de méduses dans le Ventre de Jabu-Jabu# a", /*spanish*/"una #Skulltula rodeada de medusas# otorga"}, + }); + + hintTable[JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider guarded by a school of stingers# in Jabu-Jabu's Belly holds", /*french*/"une #Skulltula protégée par des raies dans le Ventre de Jabu-Jabu# a", /*spanish*/"una #Skulltula rodeada por unos stingers# en la Tripa de Jabu-Jabu otorga"}, + }); + + + hintTable[JABU_JABUS_BELLY_MQ_GS_TAILPASARAN_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider surrounded by electricity# in Jabu-Jabu's Belly holds", /*french*/"une #Skulltula entourée d'électricité dans le Ventre de Jabu-Jabu# a", /*spanish*/"una #Skulltula rodeada de electricidad# en la Tripa de Jabu-Jabu otorga"}, + }); + + hintTable[JABU_JABUS_BELLY_MQ_GS_BOOMERANG_CHEST_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider guarded by a school of stingers# in Jabu-Jabu's Belly holds", /*french*/"une #Skulltula protégée par des raies dans le Ventre de Jabu-Jabu# a", /*spanish*/"una #Skulltula protegida por unos stingers# en la Tripa de Jabu-Jabu otorga"}, + }); + + hintTable[JABU_JABUS_BELLY_MQ_GS_NEAR_BOSS] = HintText::Exclude({ + //obscure text + Text{"a #spider in a web within Jabu-Jabu's Belly# holds", /*french*/"une #Skulltula sur une toile dans le Ventre de Jabu-Jabu# a", /*spanish*/"una #Skulltula sobre una red# en la Tripa de Jabu-Jabu otorga"}, + }); + + hintTable[JABU_JABUS_BELLY_DEKU_SCRUB] = HintText::Exclude({ + //obscure text + Text{"a #scrub in a deity# sells", /*french*/"la #peste Mojo dans le ventre du gardien# vend", /*spanish*/"un #deku dentro de cierta deidad# vende"}, + }); + + /*-------------------------- + | FOREST TEMPLE | + ---------------------------*/ + hintTable[FOREST_TEMPLE_FIRST_ROOM_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #tree in the Forest Temple# supports", /*french*/"sur l'#arbre dans le Temple de la Forêt# gît", /*spanish*/"sobre un #árbol del Templo del Bosque# yace"}, + }); + + hintTable[FOREST_TEMPLE_FIRST_STALFOS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#defeating enemies beneath a falling ceiling# in Forest Temple yields", /*french*/"#deux squelettes# dans le Temple de la Forêt protègent", /*spanish*/"#derrotar enemigos caídos de lo alto# del Templo del Bosque revela"}, + }); + + hintTable[FOREST_TEMPLE_WELL_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #sunken chest deep in the woods# contains", /*french*/"le #coffre submergé dans la forêt# contient", /*spanish*/"un #sumergido cofre en lo profundo del bosque# contiene"}, + }); + + hintTable[FOREST_TEMPLE_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #fiery skull# in Forest Temple guards", /*french*/"le #crâne enflammé# dans le Temple de la Forêt protège", /*spanish*/"una #ardiente calavera# del Templo del Bosque esconde"}, + }); + + hintTable[FOREST_TEMPLE_RAISED_ISLAND_COURTYARD_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #chest on a small island# in the Forest Temple holds", /*french*/"le #coffre sur l'îlot# du Temple de la Forêt contient", /*spanish*/"un #cofre sobre una isla# del Templo del Bosque contiene"}, + }); + + hintTable[FOREST_TEMPLE_FALLING_CEILING_ROOM_CHEST] = HintText::Exclude({ + //obscure text + Text{"beneath a #checkerboard falling ceiling# lies", /*french*/"sous #l'échiquier tombant# gît", /*spanish*/"tras un #techo de ajedrez# yace"}, + }); + + hintTable[FOREST_TEMPLE_EYE_SWITCH_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #sharp eye# will spot", /*french*/"l'#oeil perçant# dans la forêt verra", /*spanish*/"un #afilado ojo# revela"}, + }, {}, + //clear text + Text{"#blocks of stone# in the Forest Temple surround", /*french*/"les #blocs dans le Temple de la Forêt# entourent", /*spanish*/"cerca de unos #bloques de piedra# del Templo del Bosque yace"} + ); + + hintTable[FOREST_TEMPLE_BOSS_KEY_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #turned trunk# contains", /*french*/"le #coffre pivoté# contient", /*spanish*/"en una #sala con otro punto de vista# se esconde"}, + }); + + hintTable[FOREST_TEMPLE_FLOORMASTER_CHEST] = HintText::Exclude({ + //obscure text + Text{"deep in the forest #shadows guard a chest# containing", /*french*/"l'#ombre de la forêt# protège un coffre contenant", /*spanish*/"en lo profundo del bosque #unas sombras# esconden"}, + }); + + hintTable[FOREST_TEMPLE_BOW_CHEST] = HintText::Exclude({ + //obscure text + Text{"an #army of the dead# guards", /*french*/"des #squelettes sylvestres# protègent", /*spanish*/"un #ejército de soldados caídos# guarda"}, + }, {}, + //clear text + Text{"#Stalfos deep in the Forest Temple# guard", /*french*/"#trois squelettes dans le Temple de la Forêt# protègent", /*spanish*/"los #Stalfos en lo profundo del Templo del Bosque# guardan"} + ); + + hintTable[FOREST_TEMPLE_RED_POE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#Joelle# guards", /*french*/"#Joelle# protège", /*spanish*/"#Joelle# guarda"}, + }, {}, + //clear text + Text{"a #red ghost# guards", /*french*/"le #fantôme rouge# protège", /*spanish*/"un #espectro rojo# guarda"} + ); + + hintTable[FOREST_TEMPLE_BLUE_POE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#Beth# guards", /*french*/"#Beth# protège", /*spanish*/"#Beth# guarda"}, + }, {}, + //clear text + Text{"a #blue ghost# guards", /*french*/"le #fantôme bleu# protège", /*spanish*/"un #espectro azul# guarda"} + ); + + hintTable[FOREST_TEMPLE_BASEMENT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#revolving walls# in the Forest Temple conceal", /*french*/"des #murs rotatifs dans la forêt# recèlent", /*spanish*/"las #paredes giratorias# del Templo del Bosque conceden"}, + }); + + + hintTable[FOREST_TEMPLE_MQ_FIRST_ROOM_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #tree in the Forest Temple# supports", /*french*/"sur l'#arbre dans le Temple de la Forêt# gît", /*spanish*/"sobre un #árbol del Templo del Bosque# yace"}, + }); + + hintTable[FOREST_TEMPLE_MQ_WOLFOS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#defeating enemies beneath a falling ceiling# in Forest Temple yields", /*french*/"#deux squelettes# dans le Temple de la Forêt protègent", /*spanish*/"#derrotar enemigos caídos de lo alto# del Templo del Bosque revela"}, + }); + + hintTable[FOREST_TEMPLE_MQ_BOW_CHEST] = HintText::Exclude({ + //obscure text + Text{"an #army of the dead# guards", /*french*/"des #squelettes sylvestres# protègent", /*spanish*/"un #ejército de soldados caídos# guarda"}, + }, {}, + //clear text + Text{"#Stalfos deep in the Forest Temple# guard", /*french*/"#trois squelettes dans le Temple de la Forêt# protègent", /*spanish*/"los #Stalfos en lo profundo del Templo del Bosque# guardan"} + ); + + hintTable[FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_LOWER_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #chest on a small island# in the Forest Temple holds", /*french*/"le #coffre sur l'îlot# du Temple de la Forêt contient", /*spanish*/"un #cofre sobre una isla# del Templo del Bosque contiene"}, + }); + + hintTable[FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_UPPER_CHEST] = HintText::Exclude({ + //obscure text + Text{"#high in a courtyard# within the Forest Temple is", /*french*/"#haut perché dans le jardin# du Temple de la Forêt gît", /*spanish*/"un #cofre en lo alto de un patio# del Templo del Bosque contiene"}, + }); + + hintTable[FOREST_TEMPLE_MQ_WELL_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #sunken chest deep in the woods# contains", /*french*/"le #coffre submergé dans la forêt# contient", /*spanish*/"un #sumergido cofre en lo profundo del bosque# contiene"}, + }); + + hintTable[FOREST_TEMPLE_MQ_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"#Joelle# guards", /*french*/"#Joelle# protège", /*spanish*/"#Joelle# guarda"}, + }, {}, + //clear text + Text{"a #red ghost# guards", /*french*/"le #fantôme rouge# protège", /*spanish*/"un #fantasma rojo# guarda"} + ); + + hintTable[FOREST_TEMPLE_MQ_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#Beth# guards", /*french*/"#Beth# protège", /*spanish*/"#Beth# guarda"}, + }, {}, + //clear text + Text{"a #blue ghost# guards", /*french*/"le #fantôme bleu# protège", /*spanish*/"un #fantasma azul# guarda"} + ); + + hintTable[FOREST_TEMPLE_MQ_FALLING_CEILING_ROOM_CHEST] = HintText::Exclude({ + //obscure text + Text{"beneath a #checkerboard falling ceiling# lies", /*french*/"sous #l'échiquier tombant# gît", /*spanish*/"tras un #techo de ajedrez# yace"}, + }); + + hintTable[FOREST_TEMPLE_MQ_BASEMENT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#revolving walls# in the Forest Temple conceal", /*french*/"des #murs rotatifs dans la forêt# recèlent", /*spanish*/"las #paredes giratorias# del Templo del Bosque conceden"}, + }); + + hintTable[FOREST_TEMPLE_MQ_REDEAD_CHEST] = HintText::Exclude({ + //obscure text + Text{"deep in the forest #undead guard a chest# containing", /*french*/"des #revenants dans le Temple de la Forêt# protègent", /*spanish*/"en lo profundo del bosque #guardias del más allá# guardan"}, + }); + + hintTable[FOREST_TEMPLE_MQ_BOSS_KEY_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #turned trunk# contains", /*french*/"le #coffre pivoté# contient", /*spanish*/"en una #sala con otro punto de vista# se esconde"}, + }); + + hintTable[FOREST_TEMPLE_PHANTOM_GANON_HEART] = HintText::Exclude({ + //obscure text + Text{"the #Evil Spirit from Beyond# holds", /*french*/"l'#esprit maléfique de l'au-delà# possède", /*spanish*/"el #espíritu maligno de ultratumba# porta"}, + }, {}, + //clear text + Text{"#Phantom Ganon# holds", /*french*/"#Ganon Spectral# possède", /*spanish*/"#Ganon Fantasma# porta"} + ); + + hintTable[FOREST_TEMPLE_GS_RAISED_ISLAND_COURTYARD] = HintText::Exclude({ + //obscure text + Text{"a #spider on a small island# in the Forest Temple holds", /*french*/"une #Skulltula sur l'îlot du Temple de la Forêt# a", /*spanish*/"una #Skulltula sobre una pequeña isla# del Templo del Bosque otorga"}, + }); + + hintTable[FOREST_TEMPLE_GS_FIRST_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider high on a wall of vines# in the Forest Temple holds", /*french*/"une #Skulltula sur un mur de vignes du Temple de la Forêt# a", /*spanish*/"una #Skulltula en lo alto de una pared de cepas# del Templo del Bosque otorga"}, + }); + + hintTable[FOREST_TEMPLE_GS_LEVEL_ISLAND_COURTYARD] = HintText::Exclude({ + //obscure text + Text{"#stone columns# lead to a spider in the Forest Temple hiding", /*french*/"une #Skulltula haut perchée dans le jardin du Temple de la Forêt# a", /*spanish*/"unas #columnas del Templo del Bosque# conducen a una Skulltula que otorga"}, + }); + + hintTable[FOREST_TEMPLE_GS_LOBBY] = HintText::Exclude({ + //obscure text + Text{"a #spider among ghosts# in the Forest Temple guards", /*french*/"une #Skulltula dans la grande salle du Temple de la Forêt# a", /*spanish*/"una #Skulltula rodeada de fantasmas# del Templo del Bosque otorga"}, + }); + + hintTable[FOREST_TEMPLE_GS_BASEMENT] = HintText::Exclude({ + //obscure text + Text{"a #spider within revolving walls# in the Forest Temple holds", /*french*/"une #Skulltula derrière les murs pivotants du Temple de la Forêt# a", /*spanish*/"una #Skulltula entre paredes giratorias# del Templo del Bosque otorga"}, + }); + + + hintTable[FOREST_TEMPLE_MQ_GS_FIRST_HALLWAY] = HintText::Exclude({ + //obscure text + Text{"an #ivy-hidden spider# in the Forest Temple hoards", /*french*/"une #Skulltula près de l'entrée du Temple de la Forêt# a", /*spanish*/"una #Skulltula escondida entre cepas# del Templo del Bosque otorga"}, + }); + + hintTable[FOREST_TEMPLE_MQ_GS_BLOCK_PUSH_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider in a hidden nook# within the Forest Temple holds", /*french*/"une #Skulltula dans un recoin caché du Temple de la Forêt# a", /*spanish*/"una #Skulltula en una esquina oculta# del Templo del Bosque otorga"}, + }); + + hintTable[FOREST_TEMPLE_MQ_GS_RAISED_ISLAND_COURTYARD] = HintText::Exclude({ + //obscure text + Text{"a #spider on an arch# in the Forest Temple holds", /*french*/"une #Skulltula sur une arche du Temple de la Forêt# a", /*spanish*/"una #Skulltula sobre un arco# del Templo del Bosque otorga"}, + }); + + hintTable[FOREST_TEMPLE_MQ_GS_LEVEL_ISLAND_COURTYARD] = HintText::Exclude({ + //obscure text + Text{"a #spider on a ledge# in the Forest Temple holds", /*french*/"une #Skulltula dans le jardin du Temple de la Forêt# a", /*spanish*/"una #Skulltula en un borde# del Templo del Bosque otorga"}, + }); + + hintTable[FOREST_TEMPLE_MQ_GS_WELL] = HintText::Exclude({ + //obscure text + Text{"#draining a well# in Forest Temple uncovers a spider with", /*french*/"une #Skulltula au fond du Puits du Temple de la Forêt# a", /*spanish*/"#vaciar el pozo# del Templo del Bosque desvela una Skulltula que otorga"}, + }); + + /*-------------------------- + | FIRE TEMPLE | + ---------------------------*/ + hintTable[FIRE_TEMPLE_NEAR_BOSS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#near a dragon# is", /*french*/"#près d'un dragon# gît", /*spanish*/"#cerca de un dragón# yace"}, + }); + + hintTable[FIRE_TEMPLE_FLARE_DANCER_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #Flare Dancer behind a totem# guards", /*french*/"le #Danse-Flamme derrière un totem# protège", /*spanish*/"el #Bailafuego tras unos tótems# esconde"}, + }); + + hintTable[FIRE_TEMPLE_BOSS_KEY_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #prison beyond a totem# holds", /*french*/"la #prison derrière un totem# contient", /*spanish*/"en una #prisión tras unos tótems# yace"}, + }); + + hintTable[FIRE_TEMPLE_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST] = HintText::Exclude({ + //obscure text + Text{"#explosives over a lava pit# unveil", /*french*/"des #explosifs dans un lac de lave# révèlent", /*spanish*/"los #explosivos en un mar de llamas# revelan"}, + }); + + hintTable[FIRE_TEMPLE_BIG_LAVA_ROOM_LOWER_OPEN_DOOR_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #Goron trapped near lava# holds", /*french*/"le #Goron emprisonné près de la lave# a", /*spanish*/"un #goron atrapado cerca de un mar de llamas# guarda"}, + }); + + hintTable[FIRE_TEMPLE_BOULDER_MAZE_LOWER_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #Goron at the end of a maze# holds", /*french*/"le #Goron dans le labyrinthe# a", /*spanish*/"un #goron al final de un laberinto# guarda"}, + }); + + hintTable[FIRE_TEMPLE_BOULDER_MAZE_UPPER_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #Goron above a maze# holds", /*french*/"le #Goron au dessus du labyrinthe# a", /*spanish*/"un #goron sobre un laberinto# guarda"}, + }); + + hintTable[FIRE_TEMPLE_BOULDER_MAZE_SIDE_ROOM_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #Goron hidden near a maze# holds", /*french*/"le #Goron caché près du labyrinthe# a", /*spanish*/"un #goron escondido tras un laberinto# guarda"}, + }); + + hintTable[FIRE_TEMPLE_BOULDER_MAZE_SHORTCUT_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #blocked path# in Fire Temple holds", /*french*/"un #sol fragile dans le Temple du Feu# contient", /*spanish*/"en un #camino bloqueado# del Templo del Fuego yace"}, + }); + + hintTable[FIRE_TEMPLE_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #caged chest# in the Fire Temple hoards", /*french*/"un #coffre emprisonné# dans le Temple du Feu contient", /*spanish*/"un #cofre entre rejas# del Templo del Fuego contiene"}, + }); + + hintTable[FIRE_TEMPLE_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #chest in a fiery maze# contains", /*french*/"un #coffre dans un labyrinthe enflammé# contient", /*spanish*/"un #cofre de un ardiente laberinto# contiene"}, + }); + + hintTable[FIRE_TEMPLE_HIGHEST_GORON_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #Goron atop the Fire Temple# holds", /*french*/"le #Goron au sommet du Temple du Feu# a", /*spanish*/"un #goron en lo alto del Templo del Fuego# guarda"}, + }); + + + hintTable[FIRE_TEMPLE_MQ_NEAR_BOSS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#near a dragon# is", /*french*/"#près d'un dragon# gît", /*spanish*/"#cerca de un dragón# yace"}, + }); + + hintTable[FIRE_TEMPLE_MQ_MEGATON_HAMMER_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #Flare Dancer in the depths of a volcano# guards", /*french*/"le #Danse-Flamme au coeur du volcan# a", /*spanish*/"el #Bailafuego en lo profundo del volcán# esconde"}, + }, {}, + //clear text + Text{"the #Flare Dancer in the depths of the Fire Temple# guards", /*french*/"le #Danse-Flamme au coeur du volcan# a", /*spanish*/"el #Bailafuego en lo profundo del Templo del Fuego# esconde"} + ); + + hintTable[FIRE_TEMPLE_MQ_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #blocked path# in Fire Temple holds", /*french*/"le #chemin scellé# dans le Temple du Feu contient", /*spanish*/"en un #camino bloqueado# del Templo del Fuego yace"}, + }); + + hintTable[FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CHEST] = HintText::Exclude({ + //obscure text + Text{"#crates in a maze# contain", /*french*/"des #boîtes dans le labyrinthe# contiennent", /*spanish*/"las #cajas de un laberinto# contienen"}, + }); + + hintTable[FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CHEST] = HintText::Exclude({ + //obscure text + Text{"#crates in a maze# contain", /*french*/"des #boîtes dans le labyrinthe# contiennent", /*spanish*/"las #cajas de un laberinto# contienen"}, + }); + + hintTable[FIRE_TEMPLE_MQ_MAP_ROOM_SIDE_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #falling slug# in the Fire Temple guards", /*french*/"la #limace tombante# dans le Temple du Feu protège", /*spanish*/"una #babosa del techo# del Templo del Fuego guarda"}, + }); + + hintTable[FIRE_TEMPLE_MQ_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"using a #hammer in the depths of the Fire Temple# reveals", "frapper du #marteau au coeur du volcan# révèle", /*spanish*/"usar el #martillo en lo profundo del Templo del Fuego# revela"}, + }); + + hintTable[FIRE_TEMPLE_MQ_BOSS_KEY_CHEST] = HintText::Exclude({ + //obscure text + Text{"#illuminating a lava pit# reveals the path to", /*french*/"#éclairer le lac de lave# révèle", /*spanish*/"#iluminar un mar de llamas# revela"}, + }); + + hintTable[FIRE_TEMPLE_MQ_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST] = HintText::Exclude({ + //obscure text + Text{"#explosives over a lava pit# unveil", /*french*/"des #explosifs dans un lac de lave# révèlent", /*spanish*/"los #explosivos en un mar de llamas# revelan"}, + }); + + hintTable[FIRE_TEMPLE_MQ_LIZALFOS_MAZE_SIDE_ROOM_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #Goron hidden near a maze# holds", /*french*/"le #Goron caché près du labyrinthe# a", /*spanish*/"un #goron cerca de un laberinto# guarda"}, + }); + + hintTable[FIRE_TEMPLE_MQ_FREESTANDING_KEY] = HintText::Exclude({ + //obscure text + Text{"hidden #beneath a block of stone# lies", /*french*/"caché #derrière un bloc de pierre# gît", /*spanish*/"#bajo unos bloques de piedra# yace"}, + }); + + hintTable[FIRE_TEMPLE_VOLVAGIA_HEART] = HintText::Exclude({ + //obscure text + Text{"the #Subterranean Lava Dragon# holds", /*french*/"le #dragon des profondeurs# possède", /*spanish*/"el #dragón de lava subterráneo# porta"}, + }, {}, + //clear text + Text{"#Volvagia# holds", /*french*/"#Volvagia# possède", /*spanish*/"#Volvagia# porta"} + ); + + hintTable[FIRE_TEMPLE_GS_SONG_OF_TIME_ROOM] = HintText::Exclude({ + //obscure text + Text{"#eight tiles of malice# guard a spider holding", /*french*/"une #Skulltula protégée par huit tuiles dans le Temple du Feu# a", /*spanish*/"#ocho baldosas de maldad# custodian una Skulltula que otorga"}, + }); + + hintTable[FIRE_TEMPLE_GS_BOSS_KEY_LOOP] = HintText::Exclude({ + //obscure text + Text{"#five tiles of malice# guard a spider holding", /*french*/"une #Skulltula protégée par cinq tuiles dans le Temple du Feu# a", /*spanish*/"#cinco baldosas de maldad# custodian una Skulltula que otorga"}, + }); + + hintTable[FIRE_TEMPLE_GS_BOULDER_MAZE] = HintText::Exclude({ + //obscure text + Text{"#explosives in a maze# unveil a spider hiding", /*french*/"une #Skulltula derrière un mur fragile du Temple du Feu# a", /*spanish*/"los #explosivos en un laberinto# desvelan una Skulltula que otorga"}, + }); + + hintTable[FIRE_TEMPLE_GS_SCARECROW_TOP] = HintText::Exclude({ + //obscure text + Text{"a #spider-friendly scarecrow# atop a volcano hides", /*french*/"une #Skulltula repérée par l'épouvantail du volcan# a", /*spanish*/"un #espantapájaros en lo alto de un volcán# custodia una Skulltula que otorga"}, + }, {}, + //clear text + Text{"a #spider-friendly scarecrow# atop the Fire Temple hides", /*french*/"une #Skulltula repérée par l'épouvantail du Temple du Feu# a", /*spanish*/"un #espantapájaros del Templo del Fuego# custodia una Skulltula que otorga"} + ); + + hintTable[FIRE_TEMPLE_GS_SCARECROW_CLIMB] = HintText::Exclude({ + //obscure text + Text{"a #spider-friendly scarecrow# atop a volcano hides", /*french*/"une #Skulltula repérée par l'épouvantail du volcan# a", /*spanish*/"un #espantapájaros en lo alto de un volcán# custodia una Skulltula que otorga"}, + }, {}, + //clear text + Text{"a #spider-friendly scarecrow# atop the Fire Temple hides", /*french*/"une #Skulltula repérée par l'épouvantail du Temple du Feu# a", /*spanish*/"un #espantapájaros del Templo del Fuego# custodia una Skulltula que otorga"} + ); + + + hintTable[FIRE_TEMPLE_MQ_GS_ABOVE_FIRE_WALL_MAZE] = HintText::Exclude({ + //obscure text + Text{"a #spider above a fiery maze# holds", /*french*/"une #Skulltula au dessus du labyrinthe enflammé du Temple du Feu# a", /*spanish*/"una #Skulltula sobre un ardiente laberinto# otorga"}, + }); + + hintTable[FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_CENTER] = HintText::Exclude({ + //obscure text + Text{"a #spider within a fiery maze# holds", /*french*/"une #Skulltula dans le labyrinthe enflammé du Temple du Feu# a", /*spanish*/"una #Skulltula en el interior de un ardiente laberinto# otorga"}, + }); + + hintTable[FIRE_TEMPLE_MQ_GS_BIG_LAVA_ROOM_OPEN_DOOR] = HintText::Exclude({ + //obscure text + Text{"a #Goron trapped near lava# befriended a spider with", /*french*/"une #Skulltula emprisonnée près du lac de lave du Temple du Feu# a", /*spanish*/"una #Skulltula amiga de un Goron atrapado junto a la lava# otorga"}, + }); + + hintTable[FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_SIDE_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider beside a fiery maze# holds", /*french*/"une #Skulltula près du labyrinthe enflammé du Temple du Feu# a", /*spanish*/"una #Skulltula junto a un ardiente laberinto# otorga"}, + }); + + /*-------------------------- + | WATER TEMPLE | + ---------------------------*/ + hintTable[WATER_TEMPLE_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"#rolling spikes# in the Water Temple surround", /*french*/"des #Spikes# dans le Temple de l'Eau entourent", /*spanish*/"unas #rodantes púas# del Templo del Agua guardan"}, + }); + + hintTable[WATER_TEMPLE_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#roaming stingers in the Water Temple# guard", /*french*/"des #raies dans le Temple de l'Eau# protègent", /*spanish*/"unos #errantes stingers# del Templo del Agua guardan"}, + }); + + hintTable[WATER_TEMPLE_TORCHES_CHEST] = HintText::Exclude({ + //obscure text + Text{"#fire in the Water Temple# reveals", /*french*/"des #flammes dans le Temple de l'Eau# révèlent", /*spanish*/"el #fuego en el Templo del Agua# revela"}, + }); + + hintTable[WATER_TEMPLE_DRAGON_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #serpent's prize# in the Water Temple is", /*french*/"la #récompense du dragon submergé# est", /*spanish*/"el #escamado premio# del Templo del Agua se trata de"}, + }); + + hintTable[WATER_TEMPLE_CENTRAL_BOW_TARGET_CHEST] = HintText::Exclude({ + //obscure text + Text{"#blinding an eye# in the Water Temple leads to", /*french*/"#l'oeil# du Temple de l'Eau voit", /*spanish*/"#cegar un ojo# del Templo del Agua conduce a"}, + }); + + hintTable[WATER_TEMPLE_CENTRAL_PILLAR_CHEST] = HintText::Exclude({ + //obscure text + Text{"in the #depths of the Water Temple# lies", /*french*/"le #coeur du Temple de l'Eau# cache", /*spanish*/"en las #profundidades del Templo del Agua# yace"}, + }); + + hintTable[WATER_TEMPLE_CRACKED_WALL_CHEST] = HintText::Exclude({ + //obscure text + Text{"#through a crack# in the Water Temple is", /*french*/"le #mur fragile# du Temple de l'Eau cache", /*spanish*/"tras una #agrietada pared# del Templo del Agua yace"}, + }); + + hintTable[WATER_TEMPLE_LONGSHOT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#facing yourself# reveals", /*french*/"se #vaincre soi-même# révèle", /*spanish*/"#luchar contra ti mismo# revela"}, + Text{"a #dark reflection# of yourself guards", /*french*/"son #propre reflet# cache", /*spanish*/"el #oscuro reflejo de ti mismo# guarda"}, + }, {}, + //clear text + Text{"#Dark Link# guards", /*french*/"l'#Ombre de @# protège", /*spanish*/"#@ Oscuro# guarda"} + ); + + + hintTable[WATER_TEMPLE_MQ_CENTRAL_PILLAR_CHEST] = HintText::Exclude({ + //obscure text + Text{"in the #depths of the Water Temple# lies", /*french*/"le #coeur du Temple de l'Eau# cache", /*spanish*/"en las #profundidades del Templo del Agua# yace"}, + }); + + hintTable[WATER_TEMPLE_MQ_BOSS_KEY_CHEST] = HintText::Exclude({ + //obscure text + Text{"fire in the Water Temple unlocks a #vast gate# revealing a chest with", /*french*/"des #flammes au coeur du Temple de l'Eau# révèlent", /*spanish*/"el fuego en el Templo del Agua alza una #gran valla# con"}, + }); + + hintTable[WATER_TEMPLE_MQ_LONGSHOT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#through a crack# in the Water Temple is", /*french*/"le #mur fragile# du Temple de l'Eau cache", /*spanish*/"tras una #agrietada pared# del Templo del Agua yace"}, + }); + + hintTable[WATER_TEMPLE_MQ_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#fire in the Water Temple# reveals", /*french*/"des #flammes dans le Temple de l'Eau# révèlent", /*spanish*/"el #fuego en el Templo del Agua# revela"}, + }); + + hintTable[WATER_TEMPLE_MQ_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"#sparring soldiers# in the Water Temple guard", /*french*/"les #soldats du Temple de l'Eau# protègent", /*spanish*/"#acabar con unos soldados# del Templo del Agua revela"}, + }); + + hintTable[WATER_TEMPLE_MORPHA_HEART] = HintText::Exclude({ + //obscure text + Text{"the #Giant Aquatic Amoeba# holds", /*french*/"l'#amibe aquatique géante# possède", /*spanish*/"la #ameba acuática gigante# porta"}, + }, {}, + //clear text + Text{"#Morpha# holds", /*french*/"#Morpha# possède", /*spanish*/"#Morpha# porta"} + ); + + hintTable[WATER_TEMPLE_GS_FALLING_PLATFORM_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider over a waterfall# in the Water Temple holds", /*french*/"une #Skulltula au dessus d'une cascade du Temple de l'Eau# a", /*spanish*/"una #Skulltula tras una cascada# del Templo del Agua otorga"}, + }); + + hintTable[WATER_TEMPLE_GS_CENTRAL_PILLAR] = HintText::Exclude({ + //obscure text + Text{"a #spider in the center of the Water Temple# holds", /*french*/"une #Skulltula au centre du Temple de l'Eau# a", /*spanish*/"una #Skulltula en el centro del Templo del Agua# otorga"}, + }); + + hintTable[WATER_TEMPLE_GS_NEAR_BOSS_KEY_CHEST] = HintText::Exclude({ + //obscure text + Text{"a spider protected by #rolling boulders under the lake# hides", /*french*/"une #Skulltula derrière les rochers roulants sous le lac# a", /*spanish*/"una #Skulltula protegida por rocas rodantes# bajo el lago otorga"}, + }, {}, + //clear text + Text{"a spider protected by #rolling boulders in the Water Temple# hides", /*french*/"une #Skulltula derrière les rochers roulants du Temple de l'Eau# a", /*spanish*/"una #Skulltula protegida por rocas rodantes# del Templo del Agua otorga"} + ); + + hintTable[WATER_TEMPLE_GS_RIVER] = HintText::Exclude({ + //obscure text + Text{"a #spider over a river# in the Water Temple holds", /*french*/"une #Skulltula au dessus de la rivière du Temple de l'Eau# a", /*spanish*/"una #Skulltula sobre un río# del Templo del Agua otorga"}, + }); + + + hintTable[WATER_TEMPLE_MQ_GS_BEFORE_UPPER_WATER_SWITCH] = HintText::Exclude({ + //obscure text + Text{"#beyond a pit of lizards# is a spider holding", /*french*/"une #Skulltula près des lézards du Temple de l'Eau# a", /*spanish*/"#más allá de un pozo de reptiles# una Skulltula otorga"}, + }); + + hintTable[WATER_TEMPLE_MQ_GS_LIZALFOS_HALLWAY] = HintText::Exclude({ + //obscure text + Text{"#lizards guard a spider# in the Water Temple with", /*french*/"une #Skulltula dans les couloirs croisés du Temple de l'Eau# a", /*spanish*/"unos #reptiles custodian una Skulltula# del Templo del Agua que otorga"}, + }); + + hintTable[WATER_TEMPLE_MQ_GS_RIVER] = HintText::Exclude({ + //obscure text + Text{"a #spider over a river# in the Water Temple holds", /*french*/"une #Skulltula au dessus de la rivière du Temple de l'Eau# a", /*spanish*/"una #Skulltula sobre un río# del Templo del Agua otorga"}, + }); + + /*-------------------------- + | SPIRIT TEMPLE | + ---------------------------*/ + hintTable[SPIRIT_TEMPLE_CHILD_BRIDGE_CHEST] = HintText::Exclude({ + //obscure text + Text{"a child conquers a #skull in green fire# in the Spirit Temple to reach", /*french*/"le #crâne au halo vert dans le colosse# cache", /*spanish*/"el joven que #baje el puente# del Templo del Espíritu encontrará"}, + }); + + hintTable[SPIRIT_TEMPLE_CHILD_EARLY_TORCHES_CHEST] = HintText::Exclude({ + //obscure text + Text{"a child can find a #caged chest# in the Spirit Temple with", /*french*/"le #coffre embarré dans le colosse# contient", /*spanish*/"un joven puede encontrar un #cofre entre rejas# del Templo del Espíritu con"}, + }); + + hintTable[SPIRIT_TEMPLE_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#across a pit of sand# in the Spirit Temple lies", /*french*/"le #trou sableux dans le colosse# a", /*spanish*/"tras un #pozo de arena# del Templo del Espíritu yace"}, + }); + + hintTable[SPIRIT_TEMPLE_EARLY_ADULT_RIGHT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#dodging boulders to collect silver rupees# in the Spirit Temple yields", /*french*/"les #pièces argentées entourées de rochers dans le colosse# révèlent", /*spanish*/"#esquivar rocas y conseguir plateadas rupias# en el Templo del Espíritu conduce a"}, + }); + + hintTable[SPIRIT_TEMPLE_FIRST_MIRROR_LEFT_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #shadow circling reflected light# in the Spirit Temple guards", /*french*/"l'#ombre près d'un miroir# protège", /*spanish*/"un #círculo de reflectante luz# del Templo del Espíritu guarda"}, + }); + + hintTable[SPIRIT_TEMPLE_FIRST_MIRROR_RIGHT_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #shadow circling reflected light# in the Spirit Temple guards", /*french*/"l'#ombre près d'un miroir# protège", /*spanish*/"un #círculo de reflectante luz# del Templo del Espíritu guarda"}, + }); + + hintTable[SPIRIT_TEMPLE_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"#before a giant statue# in the Spirit Temple lies", /*french*/"#devant la statue# dans le colosse gît", /*spanish*/"#ante una gran estatua# del Templo del Espíritu aguarda"}, + }); + + hintTable[SPIRIT_TEMPLE_CHILD_CLIMB_NORTH_CHEST] = HintText::Exclude({ + //obscure text + Text{"#lizards in the Spirit Temple# guard", /*french*/"les #lézards dans le colosse# protègent", /*spanish*/"los #reptiles del Templo del Espíritu# guardan"}, + }); + + hintTable[SPIRIT_TEMPLE_CHILD_CLIMB_EAST_CHEST] = HintText::Exclude({ + //obscure text + Text{"#lizards in the Spirit Temple# guard", /*french*/"les #lézards dans le colosse# protègent", /*spanish*/"los #reptiles del Templo del Espíritu# guardan"}, + }); + + hintTable[SPIRIT_TEMPLE_SUN_BLOCK_ROOM_CHEST] = HintText::Exclude({ + //obscure text + Text{"#torchlight among Beamos# in the Spirit Temple reveals", /*french*/"les #torches autour des Sentinelles# éclairent", /*spanish*/"las #antorchas junto a Beamos# del Templo del Espíritu revelan"}, + }); + + hintTable[SPIRIT_TEMPLE_STATUE_ROOM_HAND_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #statue in the Spirit Temple# holds", /*french*/"la #statue dans le colosse# tient", /*spanish*/"una #estatua del Templo del Espíritu# esconde"}, + }); + + hintTable[SPIRIT_TEMPLE_STATUE_ROOM_NORTHEAST_CHEST] = HintText::Exclude({ + //obscure text + Text{"on a #ledge by a statue# in the Spirit Temple rests", /*french*/"#haut perché près de la statue# dans le colosse gît", /*spanish*/"al #borde de una estatua# del Templo del Espíritu yace"}, + }); + + hintTable[SPIRIT_TEMPLE_NEAR_FOUR_ARMOS_CHEST] = HintText::Exclude({ + //obscure text + Text{"those who #show the light among statues# in the Spirit Temple find", /*french*/"le #soleil près des statues# cache", /*spanish*/"aquellos que #iluminen ante las estatuas# del Templo del Espíritu encontrarán"}, + }); + + hintTable[SPIRIT_TEMPLE_HALLWAY_RIGHT_INVISIBLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #Eye of Truth in the Spirit Temple# reveals", /*french*/"le #trésor invisible près du Hache-Viande# contient", /*spanish*/"el #Ojo de la Verdad# en el Templo del Espíritu revela"}, + }); + + hintTable[SPIRIT_TEMPLE_HALLWAY_LEFT_INVISIBLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #Eye of Truth in the Spirit Temple# reveals", /*french*/"le #trésor invisible près du Hache-Viande# contient", /*spanish*/"el #Ojo de la Verdad# en el Templo del Espíritu revela"}, + }); + + hintTable[SPIRIT_TEMPLE_BOSS_KEY_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #chest engulfed in flame# in the Spirit Temple holds", /*french*/"le #coffre enflammé dans le colosse# contient", /*spanish*/"un #cofre rodeado de llamas# del Templo del Espíritu contiene"}, + }); + + hintTable[SPIRIT_TEMPLE_TOPMOST_CHEST] = HintText::Exclude({ + //obscure text + Text{"those who #show the light above the Colossus# find", /*french*/"le #soleil au sommet du colosse# révèle", /*spanish*/"aquellos que #iluminen en lo alto del Coloso# encontrarán"}, + }); + + + hintTable[SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_LEFT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#lying unguarded# in the Spirit Temple is", /*french*/"dans #l'entrée du colosse# se trouve", /*spanish*/"en la #entrada del Templo del Espíritu# yace"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_RIGHT_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #switch in a pillar# within the Spirit Temple drops", /*french*/"l'#interrupteur dans un pilier# du colosse cache", /*spanish*/"el #interruptor de un pilar# del Templo del Espíritu revela"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_RIGHT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#collecting rupees through a water jet# reveals", /*french*/"les #pièces argentées dans le jet d'eau# du colosse révèlent", /*spanish*/"#hacerte con rupias tras un géiser# revela"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_LEFT_CHEST] = HintText::Exclude({ + //obscure text + Text{"an #eye blinded by stone# within the Spirit Temple conceals", /*french*/"#l'oeil derrière le rocher# dans le colosse voit", /*spanish*/"#cegar a un ojo# del Templo del Espíritu revela"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"surrounded by #fire and wrappings# lies", /*french*/"près des #pierres tombales dans le colosse# gît", /*spanish*/"rodeado de #fuego y vendas# yace"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_MAP_ROOM_ENEMY_CHEST] = HintText::Exclude({ + //obscure text + Text{"a child defeats a #gauntlet of monsters# within the Spirit Temple to find", /*french*/"l'enfant qui vainc #plusieurs monstres# dans le colosse trouvera", /*spanish*/"el joven que derrote #unos monstruos# del Templo del Espíritu encontrará"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_CHILD_CLIMB_NORTH_CHEST] = HintText::Exclude({ + //obscure text + Text{"#explosive sunlight# within the Spirit Temple uncovers", /*french*/"le #rayon de lumière explosif dans le colosse# révèle", /*spanish*/"una #explosiva luz solar# del Templo del Espíritu revela"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_CHILD_CLIMB_SOUTH_CHEST] = HintText::Exclude({ + //obscure text + Text{"#trapped by falling enemies# within the Spirit Temple is", /*french*/"des #ennemis tombants# dans le colosse protègent", /*spanish*/"#rodeado de enemigos del cielo# del Templo del Espíritu yace"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#blinding the colossus# unveils", /*french*/"#l'oeil dans le colosse# voit", /*spanish*/"#cegar al coloso# revela"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_STATUE_ROOM_LULLABY_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #royal melody awakens the colossus# to reveal", /*french*/"la #mélodie royale éveille le colosse# et révèle", /*spanish*/"la #melodía real que despierte al coloso# revelará"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_STATUE_ROOM_INVISIBLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #Eye of Truth# finds the colossus's hidden", /*french*/"#l'oeil de vérité# verra dans le colosse", /*spanish*/"el #Ojo de la Verdad# en el Templo del Espíritu encontrará"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_SILVER_BLOCK_HALLWAY_CHEST] = HintText::Exclude({ + //obscure text + Text{"#the old hide what the young find# to reveal", /*french*/"l'#oeil dans le trou du bloc argent# dans le colosse voit", /*spanish*/"el #adulto esconde lo que el joven anhela#, revelando"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM_CHEST] = HintText::Exclude({ + //obscure text + Text{"#sunlight in a maze of fire# hides", /*french*/"#la lumière dans le labyrinthe de feu# du colosse révèle", /*spanish*/"la #luz solar de un ígneo laberinto# esconde"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_LEEVER_ROOM_CHEST] = HintText::Exclude({ + //obscure text + Text{"#across a pit of sand# in the Spirit Temple lies", /*french*/"le #trou sableux# dans le colosse a", /*spanish*/"#a través del pozo de arena# del Templo del Espíritu yace"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_BEAMOS_ROOM_CHEST] = HintText::Exclude({ + //obscure text + Text{"where #temporal stone blocks the path# within the Spirit Temple lies", /*french*/"les #pierres temporelles# dans le colosse cachent", /*spanish*/"donde los #bloques temporales bloquean# en el Templo del Espíritu yace"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_CHEST_SWITCH_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #chest of double purpose# holds", /*french*/"le #coffre à usage double# du colosse contient", /*spanish*/"un #cofre de doble uso# contiene"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_BOSS_KEY_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #temporal stone blocks the light# leading to", /*french*/"la #pierre temporelle# le colosse fait ombre sur", /*spanish*/"un #bloque temporal bloquea la luz# que conduce a"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_MIRROR_PUZZLE_INVISIBLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"those who #show the light above the Colossus# find", /*french*/"le trésor invisible #au sommet du colosse# contient", /*spanish*/"aquellos que #revelen la luz sobre el Coloso# encontrarán"}, + }); + + hintTable[SPIRIT_TEMPLE_TWINROVA_HEART] = HintText::Exclude({ + //obscure text + Text{"the #Sorceress Sisters# hold", /*french*/"#les sorcières jumelles# possède", /*spanish*/"las #hermanas hechiceras# portan"}, + }, {}, + //clear text + Text{"#Twinrova# holds", /*french*/"#Twinrova# possède", /*spanish*/"#Birova# porta"} + ); + + hintTable[SPIRIT_TEMPLE_GS_HALL_AFTER_SUN_BLOCK_ROOM] = HintText::Exclude({ + //obscure text + Text{"a spider in the #hall of a knight# guards", /*french*/"une #Skulltula au dessus d'un escalier du Temple de l'Esprit# a", /*spanish*/"una #Skulltula en el salón de un guerrero# otorga"}, + }); + + hintTable[SPIRIT_TEMPLE_GS_BOULDER_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider behind a temporal stone# in the Spirit Temple yields", /*french*/"une #Skulltula derrière une pierre temporelle du Temple de l'Esprit# a", /*spanish*/"una #Skulltula tras un bloque temporal# del Templo del Espíritu otorga"}, + }); + + hintTable[SPIRIT_TEMPLE_GS_LOBBY] = HintText::Exclude({ + //obscure text + Text{"a #spider beside a statue# holds", /*french*/"une #Skulltula dans la grande salle du Temple de l'Esprit# a", /*spanish*/"una #Skulltula junto a una estatua# del Templo del Espíritu otorga"}, + }); + + hintTable[SPIRIT_TEMPLE_GS_SUN_ON_FLOOR_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider at the top of a deep shaft# in the Spirit Temple holds", /*french*/"une #Skulltula près d'un mur d'escalade du Temple de l'Esprit# a", /*spanish*/"una #Skulltula en lo alto de un gran hueco# del Templo del Espíritu otorga"}, + }); + + hintTable[SPIRIT_TEMPLE_GS_METAL_FENCE] = HintText::Exclude({ + //obscure text + Text{"a child defeats a #spider among bats# in the Spirit Temple to gain", /*french*/"une #Skulltula sur le grillage du Temple de l'Esprit# a", /*spanish*/"el joven que derrote la #Skulltula entre murciélagos# del Templo del Espíritu hallará"}, + }); + + + hintTable[SPIRIT_TEMPLE_MQ_GS_LEEVER_ROOM] = HintText::Exclude({ + //obscure text + Text{"#above a pit of sand# in the Spirit Temple hides", /*french*/"une #Skulltula au dessus du trou sableux du Temple de l'Esprit# a", /*spanish*/"una #Skulltula sobre un pozo de arena# del Templo del Espíritu otorga"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_WEST] = HintText::Exclude({ + //obscure text + Text{"a spider in the #hall of a knight# guards", /*french*/"une #Skulltula dans la salle aux neuf trônes du Temple de l'Esprit# a", /*spanish*/"una #Skulltula en el salón de un guerrero# otorga"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_NORTH] = HintText::Exclude({ + //obscure text + Text{"a spider in the #hall of a knight# guards", /*french*/"une #Skulltula dans la salle aux neuf trônes du Temple de l'Esprit# a", /*spanish*/"una #Skulltula en el salón de un guerrero# otorga"}, + }); + + hintTable[SPIRIT_TEMPLE_MQ_GS_SUN_BLOCK_ROOM] = HintText::Exclude({ + //obscure text + Text{"#upon a web of glass# in the Spirit Temple sits a spider holding", /*french*/"une #Skulltula sur une paroi de verre du Temple de l'Esprit# a", /*spanish*/"#sobre una plataforma de cristal# yace una Skulltula que otorga"}, + }); + + /*-------------------------- + | SHADOW TEMPLE | + ---------------------------*/ + hintTable[SHADOW_TEMPLE_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #Eye of Truth# pierces a hall of faces to reveal", /*french*/"l'#oeil de vérité# voit dans les couloirs du Temple de l'Ombre", /*spanish*/"el #Ojo de la Verdad# descubrirá un pasillo de facetas con"}, + }); + + hintTable[SHADOW_TEMPLE_HOVER_BOOTS_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #nether dweller in the Shadow Temple# holds", /*french*/"le #spectre du Temple de l'Ombre# a", /*spanish*/"un #temido morador del Templo de las Sombras# guarda"}, + }, {}, + //clear text + Text{"#Dead Hand in the Shadow Temple# holds", /*french*/"le #Poigneur dans le Temple de l'Ombre# cache", /*spanish*/"la #Mano Muerta del Templo de las Sombras# guarda"} + ); + + hintTable[SHADOW_TEMPLE_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#mummies revealed by the Eye of Truth# guard", /*french*/"les #Gibdos dans les couloirs# du Temple de l'Ombre protègent", /*spanish*/"las #momias reveladas por el Ojo de la Verdad# guardan"}, + }); + + hintTable[SHADOW_TEMPLE_EARLY_SILVER_RUPEE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#spinning scythes# protect", /*french*/"les #faucheurs danseurs# du Temple de l'Ombre protègent", /*spanish*/"las #giratorias guadañas# protegen"}, + }); + + hintTable[SHADOW_TEMPLE_INVISIBLE_BLADES_VISIBLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#invisible blades# guard", /*french*/"les #faucheurs invisibles# du Temple de l'Ombre protègent", /*spanish*/"las #hojas invisibles# guardan"}, + }); + + hintTable[SHADOW_TEMPLE_INVISIBLE_BLADES_INVISIBLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#invisible blades# guard", /*french*/"les #faucheurs invisibles# du Temple de l'Ombre protègent", /*spanish*/"las #hojas invisibles# guardan"}, + }); + + hintTable[SHADOW_TEMPLE_FALLING_SPIKES_LOWER_CHEST] = HintText::Exclude({ + //obscure text + Text{"#falling spikes# block the path to", /*french*/"la #pluie de clous# surplombe", /*spanish*/"los #pinchos de un techo# conducen a"}, + }); + + hintTable[SHADOW_TEMPLE_FALLING_SPIKES_UPPER_CHEST] = HintText::Exclude({ + //obscure text + Text{"#falling spikes# block the path to", /*french*/"la #pluie de clous# surplombe", /*spanish*/"los #pinchos de un techo# conducen a"}, + }); + + hintTable[SHADOW_TEMPLE_FALLING_SPIKES_SWITCH_CHEST] = HintText::Exclude({ + //obscure text + Text{"#falling spikes# block the path to", /*french*/"la #pluie de clous# surplombe", /*spanish*/"los #pinchos de un techo# conducen a"}, + }); + + hintTable[SHADOW_TEMPLE_INVISIBLE_SPIKES_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #dead roam among invisible spikes# guarding", /*french*/"#parmi les clous invisibles# du Temple de l'Ombre se cache", /*spanish*/"los #muertos que vagan por pinchos invisibles# protegen"}, + }); + + hintTable[SHADOW_TEMPLE_WIND_HINT_CHEST] = HintText::Exclude({ + //obscure text + Text{"an #invisible chest guarded by the dead# holds", /*french*/"le #trésor invisible du cul-de-sac# du Temple de l'Ombre contient", /*spanish*/"un #cofre invisible custodiado por los del más allá# contiene"}, + }); + + hintTable[SHADOW_TEMPLE_AFTER_WIND_ENEMY_CHEST] = HintText::Exclude({ + //obscure text + Text{"#mummies guarding a ferry# hide", /*french*/"les #Gibdos qui bloquent le traversier# cachent", /*spanish*/"las #momias que protegen un navío# esconden"}, + }); + + hintTable[SHADOW_TEMPLE_AFTER_WIND_HIDDEN_CHEST] = HintText::Exclude({ + //obscure text + Text{"#mummies guarding a ferry# hide", /*french*/"les #Gibdos qui bloquent le traversier# cachent", /*spanish*/"las #momias que protegen un navío# esconden"}, + }); + + hintTable[SHADOW_TEMPLE_SPIKE_WALLS_LEFT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#walls consumed by a ball of fire# reveal", /*french*/"le #piège de bois# du Temple de l'Ombre cache", /*spanish*/"las #paredes consumidas por una esfera ígnea# revelan"}, + }); + + hintTable[SHADOW_TEMPLE_BOSS_KEY_CHEST] = HintText::Exclude({ + //obscure text + Text{"#walls consumed by a ball of fire# reveal", /*french*/"le #piège de bois# du Temple de l'Ombre cache", /*spanish*/"las #paredes consumidas por una esfera ígnea# revelan"}, + }); + + hintTable[SHADOW_TEMPLE_FREESTANDING_KEY] = HintText::Exclude({ + //obscure text + Text{"#inside a burning skull# lies", /*french*/"#dans un crâne enflammé# gît", /*spanish*/"en el #interior de una calavera en llamas# aguarda"}, + }); + + + hintTable[SHADOW_TEMPLE_MQ_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #Eye of Truth# pierces a hall of faces to reveal", /*french*/"l'#oeil de vérité# voit dans les couloirs du Temple de l'Ombre", /*spanish*/"el #Ojo de la Verdad# descubre un pasillo de facetas con"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_HOVER_BOOTS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#Dead Hand in the Shadow Temple# holds", /*french*/"le #Poigneur dans le Temple de l'Ombre# cache", /*spanish*/"la #Mano Muerta del Templo de las Sombras# guarda"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_EARLY_GIBDOS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#mummies revealed by the Eye of Truth# guard", /*french*/"les #Gibdos dans les couloirs# du Temple de l'Ombre protègent", /*spanish*/"las #momias reveladas por el Ojo de la Verdad# guardan"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"#spinning scythes# protect", /*french*/"les #faucheurs danseurs# du Temple de l'Ombre protègent", /*spanish*/"las #giratorias guadañas# protegen"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_BEAMOS_SILVER_RUPEES_CHEST] = HintText::Exclude({ + //obscure text + Text{"#collecting rupees in a vast cavern# with the Shadow Temple unveils", /*french*/"les #pièces argentées dans le Temple de l'Ombre# révèlent", /*spanish*/"hacerte con las #rupias en una gran caverna# del Templo de las Sombras revela"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_FALLING_SPIKES_SWITCH_CHEST] = HintText::Exclude({ + //obscure text + Text{"#falling spikes# block the path to", /*french*/"la #pluie de clous# surplombe", /*spanish*/"los #pinchos de un techo# conducen a"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_FALLING_SPIKES_LOWER_CHEST] = HintText::Exclude({ + //obscure text + Text{"#falling spikes# block the path to", /*french*/"la #pluie de clous# surplombe", /*spanish*/"los #pinchos de un techo# conducen a"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_FALLING_SPIKES_UPPER_CHEST] = HintText::Exclude({ + //obscure text + Text{"#falling spikes# block the path to", /*french*/"la #pluie de clous# surplombe", /*spanish*/"los #pinchos de un techo# conducen a"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_INVISIBLE_SPIKES_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #dead roam among invisible spikes# guarding", /*french*/"#parmi les clous invisibles# du Temple de l'Ombre se cache", /*spanish*/"los #muertos que vagan por pinchos invisibles# protegen"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_BOSS_KEY_CHEST] = HintText::Exclude({ + //obscure text + Text{"#walls consumed by a ball of fire# reveal", /*french*/"le #piège de bois# du Temple de l'Ombre cache", /*spanish*/"las #paredes consumidas por una esfera ígnea# revelan"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_SPIKE_WALLS_LEFT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#walls consumed by a ball of fire# reveal", /*french*/"le #piège de bois# du Temple de l'Ombre cache", /*spanish*/"las #paredes consumidas por una esfera ígnea# revelan"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_STALFOS_ROOM_CHEST] = HintText::Exclude({ + //obscure text + Text{"near an #empty pedestal# within the Shadow Temple lies", /*french*/"#près d'un pédestal vide du Temple de l'Ombre# gît", /*spanish*/"cerca de un #vacío pedestal# del Templo de las Sombras yace"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_INVISIBLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#invisible blades# guard", /*french*/"les #faucheurs invisibles# du Temple de l'Ombre protègent", /*spanish*/"unas #hojas invisibles# guardan"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_VISIBLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#invisible blades# guard", /*french*/"les #faucheurs invisibles# du Temple de l'Ombre protègent", /*spanish*/"unas #hojas invisibles# guardan"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_WIND_HINT_CHEST] = HintText::Exclude({ + //obscure text + Text{"an #invisible chest guarded by the dead# holds", /*french*/"le #trésor invisible du cul-de-sac# du Temple de l'Ombre contient", /*spanish*/"un #cofre invisible custodiado por los del más allá# contiene"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_AFTER_WIND_HIDDEN_CHEST] = HintText::Exclude({ + //obscure text + Text{"#mummies guarding a ferry# hide", /*french*/"les #Gibdos qui bloquent le traversier# cachent", /*spanish*/"las #momias que protegen un navío# esconden"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_AFTER_WIND_ENEMY_CHEST] = HintText::Exclude({ + //obscure text + Text{"#mummies guarding a ferry# hide", /*french*/"les #Gibdos qui bloquent le traversier# cachent", /*spanish*/"las #momias que protegen un navío# esconden"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_NEAR_SHIP_INVISIBLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#caged near a ship# lies", /*french*/"#dans une cage près du traversier# gît", /*spanish*/"#entre rejas al lado de un navío# yace"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_FREESTANDING_KEY] = HintText::Exclude({ + //obscure text + Text{"#behind three burning skulls# lies", /*french*/"#derrière trois crânes enflammés# gît", /*spanish*/"tras #tres ardientes calaveras# yace"}, + }); + + hintTable[SHADOW_TEMPLE_BONGO_BONGO_HEART] = HintText::Exclude({ + //obscure text + Text{"the #Phantom Shadow Beast# holds", /*french*/"le #monstre de l'ombre# possède", /*spanish*/"la #alimaña oscura espectral# porta"}, + }, {}, + //clear text + Text{"#Bongo Bongo# holds", /*french*/"#Bongo Bongo# possède", /*spanish*/"#Bongo Bongo# porta"} + ); + + hintTable[SHADOW_TEMPLE_GS_SINGLE_GIANT_POT] = HintText::Exclude({ + //obscure text + Text{"#beyond a burning skull# lies a spider with", /*french*/"une #Skulltula derrière un crâne enflammé du Temple de l'Ombre# a", /*spanish*/"#tras una ardiente calavera# yace una Skulltula que otorga"}, + }); + + hintTable[SHADOW_TEMPLE_GS_FALLING_SPIKES_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider beyond falling spikes# holds", /*french*/"une #Skulltula au delà de la pluie de clous du Temple de l'Ombre# a", /*spanish*/"una #Skulltula tras los pinchos del techo# otorga"}, + }); + + hintTable[SHADOW_TEMPLE_GS_TRIPLE_GIANT_POT] = HintText::Exclude({ + //obscure text + Text{"#beyond three burning skulls# lies a spider with", /*french*/"une #Skulltula derrière trois crânes enflammés du Temple de l'Ombre# a", /*spanish*/"#tras tres ardientes calaveras# yace una Skulltula que otorga"}, + }); + + hintTable[SHADOW_TEMPLE_GS_LIKE_LIKE_ROOM] = HintText::Exclude({ + //obscure text + Text{"a spider guarded by #invisible blades# holds", /*french*/"une #Skulltula protégée par les faucheurs invisibles du Temple de l'Ombre# a", /*spanish*/"una #Skulltula custodiada por hojas invisibles# otorga"}, + }); + + hintTable[SHADOW_TEMPLE_GS_NEAR_SHIP] = HintText::Exclude({ + //obscure text + Text{"a spider near a #docked ship# hoards", /*french*/"une #Skulltula près du traversier du Temple de l'Ombre# a", /*spanish*/"una #Skulltula cercana a un navío# otorga"}, + }); + + + hintTable[SHADOW_TEMPLE_MQ_GS_FALLING_SPIKES_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider beyond falling spikes# holds", /*french*/"une #Skulltula au delà de la pluie de clous du Temple de l'Ombre# a", /*spanish*/"una #Skulltula tras los pinchos del techo# otorga"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_GS_WIND_HINT_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider amidst roaring winds# in the Shadow Temple holds", /*french*/"une #Skulltula près des vents du Temple de l'Ombre# a", /*spanish*/"una #Skulltula entre ventarrones# del Templo de las Sombras otorga"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_GS_AFTER_WIND] = HintText::Exclude({ + //obscure text + Text{"a #spider beneath gruesome debris# in the Shadow Temple hides", /*french*/"une #Skulltula sous des débris du Temple de l'Ombre# a", /*spanish*/"una #Skulltula bajo unos horripilantes escombros# del Templo de las Sombras otorga"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_GS_AFTER_SHIP] = HintText::Exclude({ + //obscure text + Text{"a #fallen statue# reveals a spider with", /*french*/"une #Skulltula près de la statue écroulée du Temple de l'Ombre# a", /*spanish*/"una #estatua caída# revelará una Skulltula que otorgue"}, + }); + + hintTable[SHADOW_TEMPLE_MQ_GS_NEAR_BOSS] = HintText::Exclude({ + //obscure text + Text{"a #suspended spider# guards", /*french*/"une #Skulltula près du repère du Temple de l'Ombre# a", /*spanish*/"una #Skulltula flotante# del Templo de las Sombras otorga"}, + }); + + /*-------------------------- + | BOTTOM OF THE WELL | + ---------------------------*/ + hintTable[BOTTOM_OF_THE_WELL_FRONT_LEFT_FAKE_WALL_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #Eye of Truth in the well# reveals", /*french*/"l'#oeil de vérité dans le Puits# révèle", /*spanish*/"el #Ojo de la Verdad en el pozo# revela"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_FRONT_CENTER_BOMBABLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#gruesome debris# in the well hides", /*french*/"des #débris dans le Puits# cachent", /*spanish*/"unos #horripilantes escombros# del pozo esconden"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_RIGHT_BOTTOM_FAKE_WALL_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #Eye of Truth in the well# reveals", /*french*/"l'#oeil de vérité dans le Puits# révèle", /*spanish*/"el #Ojo de la Verdad en el pozo# revela"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #hidden entrance to a cage# in the well leads to", /*french*/"dans un #chemin caché dans le Puits# gît", /*spanish*/"la #entrada oculta de una celda# del pozo conduce a"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_CENTER_SKULLTULA_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #spider guarding a cage# in the well protects", /*french*/"l'#araignée dans la cage du Puits# protège", /*spanish*/"una #araña protegiendo una celda# del pozo guarda"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_BACK_LEFT_BOMBABLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#gruesome debris# in the well hides", /*french*/"des #débris dans le Puits# cachent", /*spanish*/"unos #horripilantes escombros# del pozo esconden"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_INVISIBLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#Dead Hand's invisible secret# is", /*french*/"le #trésor invisible du Poigneur# est", /*spanish*/"el #secreto invisible de la Mano Muerta# esconde"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_UNDERWATER_FRONT_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #royal melody in the well# uncovers", /*french*/"la #mélodie royale révèle dans le Puits#", /*spanish*/"una #melodía real en el pozo# revela"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_UNDERWATER_LEFT_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #royal melody in the well# uncovers", /*french*/"la #mélodie royale révèle dans le Puits#", /*spanish*/"una #melodía real en el pozo# revela"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"in the #depths of the well# lies", /*french*/"#dans le coeur du Puits# gît", /*spanish*/"en las #profundidades del pozo# yace"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_FIRE_KEESE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#perilous pits# in the well guard the path to", /*french*/"#trois trous# dans le Puits protègent", /*spanish*/"#peligrosos fosos# del pozo conducen a"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_LIKE_LIKE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#locked in a cage# in the well lies", /*french*/"#dans une cage# du Puits gît", /*spanish*/"#entre rejas# en el pozo yace"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_FREESTANDING_KEY] = HintText::Exclude({ + //obscure text + Text{"#inside a coffin# hides", /*french*/"dans #un cercueil# gît", /*spanish*/"en el #interior de un ataúd# yace"}, + }); + + + hintTable[BOTTOM_OF_THE_WELL_MQ_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #royal melody in the well# uncovers", /*french*/"la #mélodie royale révèle dans le Puits#", /*spanish*/"una #melodía real en el pozo# revela"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_MQ_LENS_OF_TRUTH_CHEST] = HintText::Exclude({ + //obscure text + Text{"an #army of the dead# in the well guards", /*french*/"l'#armée des morts# dans le Puits protège", /*spanish*/"un #ejército del más allá# del pozo guarda"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_MQ_DEAD_HAND_FREESTANDING_KEY] = HintText::Exclude({ + //obscure text + Text{"#Dead Hand's explosive secret# is", /*french*/"le #secret explosif du Poigneur# est", /*spanish*/"el #explosivo secreto de la Mano Muerta# esconde"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_MQ_EAST_INNER_ROOM_FREESTANDING_KEY] = HintText::Exclude({ + //obscure text + Text{"an #invisible path in the well# leads to", /*french*/"dans un #chemin caché dans le Puits# gît", /*spanish*/"un #camino invisible del pozo# conduce a"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_GS_LIKE_LIKE_CAGE] = HintText::Exclude({ + //obscure text + Text{"a #spider locked in a cage# in the well holds", /*french*/"une #Skulltula dans une cage au fonds du Puits# a", /*spanish*/"una #Skulltula enjaulada# del pozo otorga"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_GS_EAST_INNER_ROOM] = HintText::Exclude({ + //obscure text + Text{"an #invisible path in the well# leads to", /*french*/"une #Skulltula dans le chemin invisible au fonds du Puits# a", /*spanish*/"un #camino invisible del pozo# conduce a una Skulltula que otorga"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_GS_WEST_INNER_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider locked in a crypt# within the well guards", /*french*/"une #Skulltula embarrée dans la crypte au fonds du Puits# a", /*spanish*/"una #Skulltula encerrada en una cripta# del pozo otorga"}, + }); + + + hintTable[BOTTOM_OF_THE_WELL_MQ_GS_BASEMENT] = HintText::Exclude({ + //obscure text + Text{"a #gauntlet of invisible spiders# protects", /*french*/"une #Skulltula protégée par les araignées invisibles au fonds du Puits# a", /*spanish*/"unas #arañas invisibles# custodian una Skulltula que otorga"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_MQ_GS_COFFIN_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider crawling near the dead# in the well holds", /*french*/"une #Skulltula près des cercueils au fonds du Puits# a", /*spanish*/"una #Skulltula junto a los muertos# del pozo otorga"}, + }); + + hintTable[BOTTOM_OF_THE_WELL_MQ_GS_WEST_INNER_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider locked in a crypt# within the well guards", /*french*/"une #Skulltula embarrée dans la crypte au fonds du Puits# a", /*spanish*/"una #Skulltula encerrada en una cripta# del pozo otorga"}, + }); + + /*-------------------------- + | ICE CAVERN | + ---------------------------*/ + hintTable[ICE_CAVERN_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"#winds of ice# surround", /*french*/"#figé dans la glace rouge# gît", /*spanish*/"#heladas borrascas# rodean"}, + }); + + hintTable[ICE_CAVERN_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #wall of ice# protects", /*french*/"#un mur de glace rouge# cache", /*spanish*/"una #gélida pared# protege"}, + }); + + hintTable[ICE_CAVERN_IRON_BOOTS_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #monster in a frozen cavern# guards", /*french*/"le #monstre de la caverne de glace# protège", /*spanish*/"un #monstruo de una helada caverna# guarda"}, + }); + + hintTable[ICE_CAVERN_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"a #wall of ice# protects", /*french*/"un #mur de glace rouge# cache", /*spanish*/"una #gélida pared# protege"}, + }); + + + hintTable[ICE_CAVERN_MQ_IRON_BOOTS_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #monster in a frozen cavern# guards", /*french*/"le #monstre de la caverne de glace# protège", /*spanish*/"un #monstruo de una helada caverna# guarda"}, + }); + + hintTable[ICE_CAVERN_MQ_COMPASS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#winds of ice# surround", /*french*/"#entouré de vent glacial# gît", /*spanish*/"#heladas borrascas# rodean"}, + }); + + hintTable[ICE_CAVERN_MQ_MAP_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #wall of ice# protects", /*french*/"#un mur de glace rouge# cache", /*spanish*/"una #gélida pared# protege"}, + }); + + hintTable[ICE_CAVERN_MQ_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"#winds of ice# surround", /*french*/"#entouré de vent glacial# gît", /*spanish*/"#heladas borrascas# rodean"}, + }); + + hintTable[ICE_CAVERN_GS_PUSH_BLOCK_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider above icy pits# holds", /*french*/"une #Skulltula au dessus d'un goufre glacial# a", /*spanish*/"una #Skulltula sobre gélidos vacíos# otorga"}, + }); + + hintTable[ICE_CAVERN_GS_SPINNING_SCYTHE_ROOM] = HintText::Exclude({ + //obscure text + Text{"#spinning ice# guards a spider holding", /*french*/"une #Skulltula près de deux lames de glace# a", /*spanish*/"unos #témpanos giratorios# custodian una Skulltula que otorga"}, + }); + + hintTable[ICE_CAVERN_GS_HEART_PIECE_ROOM] = HintText::Exclude({ + //obscure text + Text{"a #spider behind a wall of ice# hides", /*french*/"une #Skulltula derrière un mur de glace# a", /*spanish*/"una #Skulltula tras una gélida pared# otorga"}, + }); + + + hintTable[ICE_CAVERN_MQ_GS_SCARECROW] = HintText::Exclude({ + //obscure text + Text{"a #spider above icy pits# holds", /*french*/"une #Skulltula au dessus d'un goufre glacial# a", /*spanish*/"una #Skulltula sobre gélidos vacíos# otorga"}, + }); + + hintTable[ICE_CAVERN_MQ_GS_ICE_BLOCK] = HintText::Exclude({ + //obscure text + Text{"a #web of ice# surrounds a spider with", /*french*/"une #Skulltula protégée d'une toile glacée# a", /*spanish*/"una #gélida red# rodea a una Skulltula que otorga"}, + }); + + hintTable[ICE_CAVERN_MQ_GS_RED_ICE] = HintText::Exclude({ + //obscure text + Text{"a #spider in fiery ice# hoards", /*french*/"une #Skulltula figée dans la glace rouge# a", /*spanish*/"una #Skulltula tras un ardiente hielo# otorga"}, + }); + + /*-------------------------- + | GERUDO TRAINING GROUNDS | + ---------------------------*/ + hintTable[GERUDO_TRAINING_GROUNDS_LOBBY_LEFT_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #blinded eye in the Gerudo Training Grounds# drops", /*french*/"l'#Oeil dans le Gymnase Gerudo# voit", /*spanish*/"#cegar un ojo en el Centro de Instrucción Gerudo# revela"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_LOBBY_RIGHT_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #blinded eye in the Gerudo Training Grounds# drops", /*french*/"l'#Oeil dans le Gymnase Gerudo# voit", /*spanish*/"#cegar un ojo en el Centro de Instrucción Gerudo# revela"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_STALFOS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#soldiers walking on shifting sands# in the Gerudo Training Grounds guard", /*french*/"les #squelettes# du Gymnase Gerudo protègent", /*spanish*/"#soldados en resbaladizas arenas# del Centro de Instrucción Gerudo protegen"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_BEAMOS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#reptilian warriors# in the Gerudo Training Grounds protect", /*french*/"les #lézards# dans le Gymnase Gerudo protègent", /*spanish*/"#unos escamosos guerreros# del Centro de Instrucción Gerudo protegen"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_HIDDEN_CEILING_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #Eye of Truth# in the Gerudo Training Grounds reveals", /*french*/"#bien caché# dans le Gymnase Gerudo gît", /*spanish*/"el #Ojo de la Verdad# en el Centro de Instrucción Gerudo revela"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MAZE_PATH_FIRST_CHEST] = HintText::Exclude({ + //obscure text + Text{"the first prize of #the thieves' training# is", /*french*/"le #premier trésor du Gymnase Gerudo# est", /*spanish*/"el primer premio de la #instrucción bandida# se trata de"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MAZE_PATH_SECOND_CHEST] = HintText::Exclude({ + //obscure text + Text{"the second prize of #the thieves' training# is", /*french*/"le #deuxième trésor du Gymnase Gerudo# est", /*spanish*/"el segundo premio de la #instrucción bandida# se trata de"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MAZE_PATH_THIRD_CHEST] = HintText::Exclude({ + //obscure text + Text{"the third prize of #the thieves' training# is", /*french*/"le #troisième trésor du Gymnase Gerudo# est", /*spanish*/"el tercer premio de la #instrucción bandida# se trata de"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MAZE_RIGHT_CENTRAL_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #Song of Time# in the Gerudo Training Grounds leads to", /*french*/"le #chant du temps# révèle dans le Gymnase Gerudo", /*spanish*/"la #Canción del Tiempo# en el Centro de Instrucción Gerudo conduce a"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MAZE_RIGHT_SIDE_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #Song of Time# in the Gerudo Training Grounds leads to", /*french*/"le #chant du temps# révèle dans le Gymnase Gerudo", /*spanish*/"la #Canción del Tiempo# en el Centro de Instrucción Gerudo conduce a"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_HAMMER_ROOM_CLEAR_CHEST] = HintText::Exclude({ + //obscure text + Text{"#fiery foes# in the Gerudo Training Grounds guard", /*french*/"les #limaces de feu# du Gymnase Gerudo protègent", /*spanish*/"unos #flamígeros enemigos# del Centro de Instrucción Gerudo guardan"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_HAMMER_ROOM_SWITCH_CHEST] = HintText::Exclude({ + //obscure text + Text{"#engulfed in flame# where thieves train lies", /*french*/"le #trésor enflammé# du Gymnase Gerudo est", /*spanish*/"donde entrenan las bandidas #entre llamas# yace"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_EYE_STATUE_CHEST] = HintText::Exclude({ + //obscure text + Text{"thieves #blind four faces# to find", /*french*/"l'#épreuve d'archerie# du Gymnase Gerudo donne", /*spanish*/"las bandidas #ciegan cuatro bustos# para hallar"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_NEAR_SCARECROW_CHEST] = HintText::Exclude({ + //obscure text + Text{"thieves #blind four faces# to find", /*french*/"l'#épreuve d'archerie# du Gymnase Gerudo donne", /*spanish*/"las bandidas #ciegan cuatro bustos# para hallar"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_BEFORE_HEAVY_BLOCK_CHEST] = HintText::Exclude({ + //obscure text + Text{"#before a block of silver# thieves can find", /*french*/"#près d'un bloc argent# dans le Gymnase Gerudo gît", /*spanish*/"#ante un plateado bloque# las bandidas hallan"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_FIRST_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #feat of strength# rewards thieves with", /*french*/"#derrière un bloc argent# dans le Gymnase Gerudo gît", /*spanish*/"una #hazaña de fuerza# premia a las bandidas con"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_SECOND_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #feat of strength# rewards thieves with", /*french*/"#derrière un bloc argent# dans le Gymnase Gerudo gît", /*spanish*/"una #hazaña de fuerza# premia a las bandidas con"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_THIRD_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #feat of strength# rewards thieves with", /*french*/"#derrière un bloc argent# dans le Gymnase Gerudo gît", /*spanish*/"una #hazaña de fuerza# premia a las bandidas con"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_FOURTH_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #feat of strength# rewards thieves with", /*french*/"#derrière un bloc argent# dans le Gymnase Gerudo gît", /*spanish*/"una #hazaña de fuerza# premia a las bandidas con"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_FREESTANDING_KEY] = HintText::Exclude({ + //obscure text + Text{"the #Song of Time# in the Gerudo Training Grounds leads to", /*french*/"le #chant du temps# révèle dans le Gymnase Gerudo", /*spanish*/"la #Canción del Tiempo# en el Centro de Instrucción Gerudo conduce a"}, + }); + + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_LOBBY_RIGHT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#thieves prepare for training# with", /*french*/"dans #l'entrée du Gymnase Gerudo# gît", /*spanish*/"las #bandidas se instruyen# con"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_LOBBY_LEFT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#thieves prepare for training# with", /*french*/"dans #l'entrée du Gymnase Gerudo# gît", /*spanish*/"las #bandidas se instruyen# con"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_FIRST_IRON_KNUCKLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#soldiers walking on shifting sands# in the Gerudo Training Grounds guard", /*french*/"les #squelettes# du Gymnase Gerudo protègent", /*spanish*/"#soldados en resbaladizas arenas# del Centro de Instrucción Gerudo protegen"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_BEFORE_HEAVY_BLOCK_CHEST] = HintText::Exclude({ + //obscure text + Text{"#before a block of silver# thieves can find", /*french*/"#près d'un bloc argent# dans le Gymnase Gerudo gît", /*spanish*/"#ante un plateado bloque# las bandidas hallan"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_EYE_STATUE_CHEST] = HintText::Exclude({ + //obscure text + Text{"thieves #blind four faces# to find", /*french*/"l'#épreuve d'archerie# du Gymnase Gerudo donne", /*spanish*/"las bandidas #ciegan cuatro bustos# para hallar"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_FLAME_CIRCLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#engulfed in flame# where thieves train lies", /*french*/"le #trésor enflammé# du Gymnase Gerudo est", /*spanish*/"donde entrenan las bandidas #entre llamas# yace"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_SECOND_IRON_KNUCKLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#fiery foes# in the Gerudo Training Grounds guard", /*french*/"les #ennemis de feu# du Gymnase Gerudo protègent", /*spanish*/"unos #flamígeros enemigos# del Centro de Instrucción Gerudo guardan"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_DINOLFOS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#reptilian warriors# in the Gerudo Training Grounds protect", /*french*/"les #lézards# dans le Gymnase Gerudo protègent", /*spanish*/"#unos escamosos guerreros# del Centro de Instrucción Gerudo protegen"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_MAZE_RIGHT_CENTRAL_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #path of fire# leads thieves to", /*french*/"dans le #chemin enflammé# dans le Gymnase Gerudo gît", /*spanish*/"un #camino de fuego# conduce a las bandidas a"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_FIRST_CHEST] = HintText::Exclude({ + //obscure text + Text{"the first prize of #the thieves' training# is", /*french*/"le #premier trésor du Gymnase Gerudo# est", /*spanish*/"el primer premio de la #instrucción bandida# se trata de"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_MAZE_RIGHT_SIDE_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #path of fire# leads thieves to", /*french*/"dans le #chemin enflammé# dans le Gymnase Gerudo gît", /*spanish*/"un #camino de fuego# conduce a las bandidas a"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_THIRD_CHEST] = HintText::Exclude({ + //obscure text + Text{"the third prize of #the thieves' training# is", /*french*/"le #troisième trésor du Gymnase Gerudo# est", /*spanish*/"el tercer premio de la #instrucción bandida# se trata de"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_SECOND_CHEST] = HintText::Exclude({ + //obscure text + Text{"the second prize of #the thieves' training# is", /*french*/"le #deuxième trésor du Gymnase Gerudo# est", /*spanish*/"el segundo premio de la #instrucción bandida# se trata de"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_HIDDEN_CEILING_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #Eye of Truth# in the Gerudo Training Grounds reveals", /*french*/"#bien caché# dans le Gymnase Gerudo gît", /*spanish*/"el #Ojo de la Verdad# en el Centro de Instrucción Gerudo revela"}, + }); + + hintTable[GERUDO_TRAINING_GROUNDS_MQ_HEAVY_BLOCK_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #feat of strength# rewards thieves with", /*french*/"#derrière un bloc argent# dans le Gymnase Gerudo gît", /*spanish*/"una #hazaña de fuerza# premia a las bandidas con"}, + }); + + /*-------------------------- + | GANONS CASTLE | + ---------------------------*/ + hintTable[GANONS_TOWER_BOSS_KEY_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #Evil King# hoards", /*french*/"le #Roi du Mal# possède", /*spanish*/"el #Rey del Mal# acapara"}, + }); + + + hintTable[GANONS_CASTLE_FOREST_TRIAL_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of the wilds# holds", /*french*/"l'#épreuve des bois# contient", /*spanish*/"la #prueba de la naturaleza# brinda"}, + }); + + hintTable[GANONS_CASTLE_WATER_TRIAL_LEFT_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of the seas# holds", /*french*/"l'#épreuve des mers# contient", /*spanish*/"la #prueba del mar# brinda"}, + }); + + hintTable[GANONS_CASTLE_WATER_TRIAL_RIGHT_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of the seas# holds", /*french*/"l'#épreuve des mers# contient", /*spanish*/"la #prueba del mar# brinda"}, + }); + + hintTable[GANONS_CASTLE_SHADOW_TRIAL_FRONT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#music in the test of darkness# unveils", /*french*/"la #musique dans l'épreuve des ténèbres# révèle", /*spanish*/"la #música en la prueba de la oscuridad# revela"}, + }); + + hintTable[GANONS_CASTLE_SHADOW_TRIAL_GOLDEN_GAUNTLETS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#light in the test of darkness# unveils", /*french*/"la #lumière dans l'épreuve des ténèbres# révèle", /*spanish*/"la #luz en la prueba de la oscuridad# revela"}, + }); + + hintTable[GANONS_CASTLE_SPIRIT_TRIAL_CRYSTAL_SWITCH_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of the sands# holds", /*french*/"l'#épreuve des sables# contient", /*spanish*/"la #prueba de las arenas# brinda"}, + }); + + hintTable[GANONS_CASTLE_SPIRIT_TRIAL_INVISIBLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of the sands# holds", /*french*/"l'#épreuve des sables# contient", /*spanish*/"la #prueba de las arenas# brinda"}, + }); + + hintTable[GANONS_CASTLE_LIGHT_TRIAL_FIRST_LEFT_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of radiance# holds", /*french*/"l'#épreuve du ciel# contient", /*spanish*/"la #prueba del resplandor# brinda"}, + }); + + hintTable[GANONS_CASTLE_LIGHT_TRIAL_SECOND_LEFT_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of radiance# holds", /*french*/"l'#épreuve du ciel# contient", /*spanish*/"la #prueba del resplandor# brinda"}, + }); + + hintTable[GANONS_CASTLE_LIGHT_TRIAL_THIRD_LEFT_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of radiance# holds", /*french*/"l'#épreuve du ciel# contient", /*spanish*/"la #prueba del resplandor# brinda"}, + }); + + hintTable[GANONS_CASTLE_LIGHT_TRIAL_FIRST_RIGHT_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of radiance# holds", /*french*/"l'#épreuve du ciel# contient", /*spanish*/"la #prueba del resplandor# brinda"}, + }); + + hintTable[GANONS_CASTLE_LIGHT_TRIAL_SECOND_RIGHT_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of radiance# holds", /*french*/"l'#épreuve du ciel# contient", /*spanish*/"la #prueba del resplandor# brinda"}, + }); + + hintTable[GANONS_CASTLE_LIGHT_TRIAL_THIRD_RIGHT_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of radiance# holds", /*french*/"l'#épreuve du ciel# contient", /*spanish*/"la #prueba del resplandor# brinda"}, + }); + + hintTable[GANONS_CASTLE_LIGHT_TRIAL_INVISIBLE_ENEMIES_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of radiance# holds", /*french*/"l'#épreuve du ciel# contient", /*spanish*/"la #prueba del resplandor# brinda"}, + }); + + hintTable[GANONS_CASTLE_LIGHT_TRIAL_LULLABY_CHEST] = HintText::Exclude({ + //obscure text + Text{"#music in the test of radiance# reveals", /*french*/"la #musique dans l'épreuve du ciel# révèle", /*spanish*/"la #música en la prueba del resplandor# revela"}, + }); + + + hintTable[GANONS_CASTLE_MQ_WATER_TRIAL_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of the seas# holds", /*french*/"l'#épreuve des mers# contient", /*spanish*/"la #prueba del mar# brinda"}, + }); + + hintTable[GANONS_CASTLE_MQ_FOREST_TRIAL_EYE_SWITCH_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of the wilds# holds", /*french*/"l'#épreuve des bois# contient", /*spanish*/"la #prueba de la naturaleza# brinda"}, + }); + + hintTable[GANONS_CASTLE_MQ_FOREST_TRIAL_FROZEN_EYE_SWITCH_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of the wilds# holds", /*french*/"l'#épreuve des bois# contient", /*spanish*/"la #prueba de la naturaleza# brinda"}, + }); + + hintTable[GANONS_CASTLE_MQ_LIGHT_TRIAL_LULLABY_CHEST] = HintText::Exclude({ + //obscure text + Text{"#music in the test of radiance# reveals", /*french*/"la #musique dans l'épreuve du ciel# révèle", /*spanish*/"la #música en la prueba del resplandor# revela"}, + }); + + hintTable[GANONS_CASTLE_MQ_SHADOW_TRIAL_BOMB_FLOWER_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of darkness# holds", /*french*/"l'#épreuve des ténèbres# contient", /*spanish*/"la #prueba de la oscuridad# brinda"}, + }); + + hintTable[GANONS_CASTLE_MQ_SHADOW_TRIAL_EYE_SWITCH_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #test of darkness# holds", /*french*/"l'#épreuve des ténèbres# contient", /*spanish*/"la #prueba de la oscuridad# brinda"}, + }); + + hintTable[GANONS_CASTLE_MQ_SPIRIT_TRIAL_GOLDEN_GAUNTLETS_CHEST] = HintText::Exclude({ + //obscure text + Text{"#reflected light in the test of the sands# reveals", /*french*/"le #soleil dans l'épreuve des sables# révèle", /*spanish*/"#reflejar la luz en la prueba de las arenas# revela"}, + }); + + hintTable[GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_RIGHT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#reflected light in the test of the sands# reveals", /*french*/"le #soleil dans l'épreuve des sables# révèle", /*spanish*/"#reflejar la luz en la prueba de las arenas# revela"}, + }); + + hintTable[GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_LEFT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#reflected light in the test of the sands# reveals", /*french*/"le #soleil dans l'épreuve des sables# révèle", /*spanish*/"#reflejar la luz en la prueba de las arenas# revela"}, + }); + + hintTable[GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_FRONT_LEFT_CHEST] = HintText::Exclude({ + //obscure text + Text{"#reflected light in the test of the sands# reveals", /*french*/"le #soleil dans l'épreuve des sables# révèle", /*spanish*/"#reflejar la luz en la prueba de las arenas# revela"}, + }); + + hintTable[GANONS_CASTLE_MQ_SPIRIT_TRIAL_FIRST_CHEST] = HintText::Exclude({ + //obscure text + Text{"#reflected light in the test of the sands# reveals", /*french*/"le #soleil dans l'épreuve des sables# révèle", /*spanish*/"#reflejar la luz en la prueba de las arenas# revela"}, + }); + + hintTable[GANONS_CASTLE_MQ_SPIRIT_TRIAL_INVISIBLE_CHEST] = HintText::Exclude({ + //obscure text + Text{"#reflected light in the test of the sands# reveals", /*french*/"le #soleil dans l'épreuve des sables# révèle", /*spanish*/"#reflejar la luz en la prueba de las arenas# revela"}, + }); + + hintTable[GANONS_CASTLE_MQ_FOREST_TRIAL_FREESTANDING_KEY] = HintText::Exclude({ + //obscure text + Text{"the #test of the wilds# holds", /*french*/"l'#épreuve des bois# révèle", /*spanish*/"la #prueba de la naturaleza# brinda"}, + }); + + hintTable[GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT] = HintText::Exclude({ + //obscure text + Text{"#scrubs in Ganon's Castle# sell", /*french*/"les #pestes Mojo dans le Château de Ganon# vendent", /*spanish*/"los #dekus del Castillo de Ganon# venden"}, + }); + + hintTable[GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT] = HintText::Exclude({ + //obscure text + Text{"#scrubs in Ganon's Castle# sell", /*french*/"les #pestes Mojo dans le Château de Ganon# vendent", /*spanish*/"los #dekus del Castillo de Ganon# venden"}, + }); + + hintTable[GANONS_CASTLE_DEKU_SCRUB_RIGHT] = HintText::Exclude({ + //obscure text + Text{"#scrubs in Ganon's Castle# sell", /*french*/"les #pestes Mojo dans le Château de Ganon# vendent", /*spanish*/"los #dekus del Castillo de Ganon# venden"}, + }); + + hintTable[GANONS_CASTLE_DEKU_SCRUB_LEFT] = HintText::Exclude({ + //obscure text + Text{"#scrubs in Ganon's Castle# sell", /*french*/"les #pestes Mojo dans le Château de Ganon# vendent", /*spanish*/"los #dekus del Castillo de Ganon# venden"}, + }); + + + hintTable[GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT] = HintText::Exclude({ + //obscure text + Text{"#scrubs in Ganon's Castle# sell", /*french*/"les #pestes Mojo dans le Château de Ganon# vendent", /*spanish*/"los #dekus del Castillo de Ganon# venden"}, + }); + + hintTable[GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT] = HintText::Exclude({ + //obscure text + Text{"#scrubs in Ganon's Castle# sell", /*french*/"les #pestes Mojo dans le Château de Ganon# vendent", /*spanish*/"los #dekus del Castillo de Ganon# venden"}, + }); + + hintTable[GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER] = HintText::Exclude({ + //obscure text + Text{"#scrubs in Ganon's Castle# sell", /*french*/"les #pestes Mojo dans le Château de Ganon# vendent", /*spanish*/"los #dekus del Castillo de Ganon# venden"}, + }); + + hintTable[GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT] = HintText::Exclude({ + //obscure text + Text{"#scrubs in Ganon's Castle# sell", /*french*/"les #pestes Mojo dans le Château de Ganon# vendent", /*spanish*/"los #dekus del Castillo de Ganon# venden"}, + }); + + hintTable[GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT] = HintText::Exclude({ + //obscure text + Text{"#scrubs in Ganon's Castle# sell", /*french*/"les #pestes Mojo dans le Château de Ganon# vendent", /*spanish*/"los #dekus del Castillo de Ganon# venden"}, + }); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_exclude_overworld.cpp b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_exclude_overworld.cpp new file mode 100644 index 000000000..5adf816a8 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_exclude_overworld.cpp @@ -0,0 +1,1272 @@ +#include "../hint_list.hpp" + +void HintTable_Init_Exclude_Overworld() { + hintTable[KF_KOKIRI_SWORD_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #hidden treasure of the Kokiri# is", /*french*/"le #trésor des Kokiri# est", /*spanish*/"el #tesoro oculto de los Kokiri# esconde"}, + }); + + hintTable[KF_MIDOS_TOP_LEFT_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #leader of the Kokiri# hides", /*french*/"le #chef des Kokiri# possède", /*spanish*/"el #líder de los Kokiri# esconde"}, + }, {}, + //clear text + Text{"#inside Mido's house# is", /*french*/"#dans la maison de Mido# gît", /*spanish*/"en la #casa de Mido# yace"} + ); + + hintTable[KF_MIDOS_TOP_RIGHT_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #leader of the Kokiri# hides", /*french*/"le #chef des Kokiri# possède", /*spanish*/"el #líder de los Kokiri# esconde"}, + }, {}, + //clear text + Text{"#inside Mido's house# is", /*french*/"#dans la maison de Mido# gît", /*spanish*/"en la #casa de Mido# yace"} + ); + + hintTable[KF_MIDOS_BOTTOM_LEFT_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #leader of the Kokiri# hides", /*french*/"le #chef des Kokiri# possède", /*spanish*/"el #líder de los Kokiri# esconde"}, + }, {}, + //clear text + Text{"#inside Mido's house# is", /*french*/"#dans la maison de Mido# gît", /*spanish*/"en la #casa de Mido# yace"} + ); + + hintTable[KF_MIDOS_BOTTOM_RIGHT_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #leader of the Kokiri# hides", /*french*/"le #chef des Kokiri# possède", /*spanish*/"el #líder de los Kokiri# esconde"}, + }, {}, + //clear text + Text{"#inside Mido's house# is", /*french*/"#dans la maison de Mido# gît", /*spanish*/"en la #casa de Mido# yace"} + ); + + hintTable[GRAVEYARD_SHIELD_GRAVE_CHEST] = HintText::Exclude({ + //obscure text + Text{"the #treasure of a fallen soldier# is", /*french*/"le #trésor du soldat mort# est", /*spanish*/"el #tesoro de un soldado caído# esconde"}, + }); + + hintTable[DMT_CHEST] = HintText::Exclude({ + //obscure text + Text{"hidden behind a wall on a #mountain trail# is", /*french*/"derrière une façade du #chemin montagneux# est", /*spanish*/"tras una pared del #sendero de la montaña# yace"}, + }); + + hintTable[GC_MAZE_RIGHT_CHEST] = HintText::Exclude({ + //obscure text + Text{"in #Goron City# explosives unlock", /*french*/"des explosions dans le #village Goron# révèlent", /*spanish*/"en la #Ciudad Goron# unos explosivos desbloquean"}, + }); + + hintTable[GC_MAZE_CENTER_CHEST] = HintText::Exclude({ + //obscure text + Text{"in #Goron City# explosives unlock", /*french*/"des explosions dans le #village Goron# révèlent", /*spanish*/"en la #Ciudad Goron# unos explosivos desbloquean"}, + }); + + hintTable[ZD_CHEST] = HintText::Exclude({ + //obscure text + Text{"fire #beyond a waterfall# reveals", /*french*/"du feu #derrière la cascade# éclaire", /*spanish*/"las #llamas tras una una cascada# revelan"}, + }); + + hintTable[GRAVEYARD_HOOKSHOT_CHEST] = HintText::Exclude({ + //obscure text + Text{"a chest hidden by a #speedy spectre# holds", /*french*/"le #coffre du rapide revenant# contient", /*spanish*/"un cofre custodiado por un #espectro veloz# contiene"}, + }, {}, + //clear text + Text{"#dead Dampé's first prize# is", /*french*/"la #première course d'Igor# donne", /*spanish*/"el primer premio de #la carrera de Dampé# se trata de"} + ); + + hintTable[GF_CHEST] = HintText::Exclude({ + //obscure text + Text{"on a #rooftop in the desert# lies", /*french*/"sur un #toit du désert# gît", /*spanish*/"en una #azotea del desierto# yace"}, + }); + + hintTable[KAK_REDEAD_GROTTO_CHEST] = HintText::Exclude({ + //obscure text + Text{"#zombies beneath the earth# guard", /*french*/"les #revenants sous terre# protègent", /*spanish*/"unos #zombis subterráneos# esconden"}, + }); + + hintTable[SFM_WOLFOS_GROTTO_CHEST] = HintText::Exclude({ + //obscure text + Text{"#wolves beneath the earth# guard", /*french*/"les #loups sous terre# protègent", /*spanish*/"unos #lobos subterráneos# esconden"}, + }); + + hintTable[HF_NEAR_MARKET_GROTTO_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #hole in a field near a drawbridge# holds", /*french*/"la #grotte près d'un pont# contient", /*spanish*/"bajo el #hoyo de una llanura cercano a un puente# yace"}, + }); + + hintTable[HF_SOUTHEAST_GROTTO_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #hole amongst trees in a field# holds", /*french*/"la #grotte près des arbres# contient", /*spanish*/"bajo el #hoyo de una llanura rodeado de árboles# yace"}, + }); + + hintTable[HF_OPEN_GROTTO_CHEST] = HintText::Exclude({ + //obscure text + Text{"an #open hole in a field# holds", /*french*/"la #grotte dans les plaines# contient", /*spanish*/"bajo el #hoyo descubierto de una llanura# yace"}, + }); + + hintTable[KAK_OPEN_GROTTO_CHEST] = HintText::Exclude({ + //obscure text + Text{"an #open hole in a town# holds", /*french*/"la #grotte dans le village# contient", /*spanish*/"bajo el #hoyo descubierto de un pueblo# yace"}, + }); + + hintTable[ZR_OPEN_GROTTO_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #hole along a river# holds", /*french*/"la #grotte près du fleuve# contient", /*spanish*/"bajo un #hoyo junto a un río# yace"}, + }); + + hintTable[KF_STORMS_GROTTO_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #hole in a forest village# holds", /*french*/"la #grotte inondée de pluie dans le Village Kokiri# révèle", /*spanish*/"bajo el #hoyo de una tribu del bosque# yace"}, + }); + + hintTable[LW_NEAR_SHORTCUTS_GROTTO_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #hole in a wooded maze# holds", /*french*/"la #grotte dans le labyrinthe sylvestre# contient", /*spanish*/"bajo un #hoyo de un laberinto forestal# yace"}, + }); + + hintTable[DMT_STORMS_GROTTO_CHEST] = HintText::Exclude({ + //obscure text + Text{"#hole flooded with rain on a mountain# holds", /*french*/"la #grotte inondée de pluie sur la montagne# contient", /*spanish*/"bajo un #hoyo de una montaña inundado de lluvia# yace"}, + }); + + hintTable[DMC_UPPER_GROTTO_CHEST] = HintText::Exclude({ + //obscure text + Text{"a #hole in a volcano# holds", /*french*/"la #grotte dans le volcan# contient", /*spanish*/"bajo el #hoyo de un volcán# yace"}, + }); + + + hintTable[TOT_LIGHT_ARROWS_CUTSCENE] = HintText::Exclude({ + //obscure text + Text{"the #final gift of a princess# is", /*french*/"le #cadeau d'adieu de la princesse# est", /*spanish*/"el #obsequio final de la princesa# se trata de"}, + }); + + hintTable[LW_GIFT_FROM_SARIA] = HintText::Exclude({ + //obscure text + Text{"a #potato hoarder# holds", /*french*/"le #panini mélodieux# est en fait", /*spanish*/"cierta #jovencita verde# concede"}, + Text{"a rooty tooty #flutey cutey# gifts", /*french*/"la #patate musicale# est en fait", /*spanish*/"una #gran amiga# concede"}, + }, {}, + //clear text + Text{"#Saria's Gift# is", /*french*/"le #cadeau de Saria# est", /*spanish*/"el #regalo de Saria# se trata de"} + ); + + hintTable[ZF_GREAT_FAIRY_REWARD] = HintText::Exclude({ + //obscure text + Text{"the #fairy of winds# holds", /*french*/"la #fée du vent# a", /*spanish*/"el #hada del viento# brinda"}, + }); + + hintTable[HC_GREAT_FAIRY_REWARD] = HintText::Exclude({ + //obscure text + Text{"the #fairy of fire# holds", /*french*/"la #fée du feu# a", /*spanish*/"el #hada del fuego# brinda"}, + }); + + hintTable[COLOSSUS_GREAT_FAIRY_REWARD] = HintText::Exclude({ + //obscure text + Text{"the #fairy of love# holds", /*french*/"la #fée de l'amour# a", /*spanish*/"el #hada del amor# brinda"}, + }); + + hintTable[DMT_GREAT_FAIRY_REWARD] = HintText::Exclude({ + //obscure text + Text{"a #magical fairy# gifts", /*french*/"la #fée de la magie# a", /*spanish*/"un #hada mágica# brinda"}, + }); + + hintTable[DMC_GREAT_FAIRY_REWARD] = HintText::Exclude({ + //obscure text + Text{"a #magical fairy# gifts", /*french*/"la #fée de la magie# a", /*spanish*/"un #hada mágica# brinda"}, + }); + + hintTable[OGC_GREAT_FAIRY_REWARD] = HintText::Exclude({ + //obscure text + Text{"the #fairy of strength# holds", /*french*/"la #fée de la force# a", /*spanish*/"el #hada de la fuerza# brinda"}, + }); + + + hintTable[SONG_FROM_IMPA] = HintText::Exclude({ + //obscure text + Text{"#deep in a castle#, Impa teaches", /*french*/"#la gardienne de la princesse# donne", /*spanish*/"en el #jardín del castillo Impa enseña#"}, + }); + + hintTable[SONG_FROM_MALON] = HintText::Exclude({ + //obscure text + Text{"#a farm girl# sings", /*french*/"la #fillette de la ferme# donne", /*spanish*/"una #chica rupestre# canta"}, + }); + + hintTable[SONG_FROM_SARIA] = HintText::Exclude({ + //obscure text + Text{"#deep in the forest#, Saria teaches", /*french*/"la #fille de la forêt# donne", /*spanish*/"al #fondo del bosque# Saria enseña"}, + }); + + hintTable[SONG_FROM_WINDMILL] = HintText::Exclude({ + //obscure text + Text{"a man #in a windmill# is obsessed with", /*french*/"l'#homme du moulin# donne", /*spanish*/"el #hombre del molino# está obsesionado con"}, + }); + + + hintTable[HC_MALON_EGG] = HintText::Exclude({ + //obscure text + Text{"a #girl looking for her father# gives", /*french*/"la #fillette qui cherche son père# donne", /*spanish*/"una #chica en busca de su padre# otorga"}, + }); + + hintTable[HC_ZELDAS_LETTER] = HintText::Exclude({ + //obscure text + Text{"a #princess in a castle# gifts", /*french*/"la #princesse dans le château# donne", /*spanish*/"la #princesa de un castillo# otorga"}, + }); + + hintTable[ZD_DIVING_MINIGAME] = HintText::Exclude({ + //obscure text + Text{"an #unsustainable business model# gifts", /*french*/"le #mauvais modèle d'affaires# donne", /*spanish*/"un #mal modelo de negocio# premia con"}, + }, {}, + //clear text + Text{"those who #dive for Zora rupees# will find", /*french*/"ceux qui #plongent pour des rubis Zora# trouveront", /*spanish*/"aquellos que se #sumergan por las rupias zora# encontrarán"} + ); + + hintTable[LH_CHILD_FISHING] = HintText::Exclude({ + //obscure text + Text{"#fishing in youth# bestows", /*french*/"#pêcher dans sa jeunesse# promet", /*spanish*/"#pescar en la juventud# conduce a"}, + }); + + hintTable[LH_ADULT_FISHING] = HintText::Exclude({ + //obscure text + Text{"#fishing in maturity# bestows", /*french*/"#pêcher dans sa maturité# promet", /*spanish*/"#pescar en la madurez# conduce a"}, + }); + + hintTable[LH_LAB_DIVE] = HintText::Exclude({ + //obscure text + Text{"a #diving experiment# is rewarded with", /*french*/"l'#expérience de plongée# donne", /*spanish*/"#bucear para un experimento# se premia con"}, + }); + + hintTable[GC_ROLLING_GORON_AS_ADULT] = HintText::Exclude({ + //obscure text + Text{"#comforting yourself# provides", /*french*/"se #réconforter soi-même# donne", /*spanish*/"#confrontarte a ti mismo# otorga"}, + }, {}, + //clear text + Text{"#reassuring a young Goron# is rewarded with", /*french*/"#rassurer un jeune Goron# donne", /*spanish*/"#calmar a un joven Goron# otorga"} + ); + + hintTable[MARKET_BOMBCHU_BOWLING_FIRST_PRIZE] = HintText::Exclude({ + //obscure text + Text{"the #first explosive prize# is", /*french*/"le #premier prix explosif# est", /*spanish*/"el #primer premio explosivo# se trata de"}, + }); + + hintTable[MARKET_BOMBCHU_BOWLING_SECOND_PRIZE] = HintText::Exclude({ + //obscure text + Text{"the #second explosive prize# is", /*french*/"le #deuxième prix explosif# est", /*spanish*/"el #segundo premio explosivo# se trata de"}, + }); + + hintTable[MARKET_LOST_DOG] = HintText::Exclude({ + //obscure text + Text{"#puppy lovers# will find", /*french*/"les #amoureux canins# trouveront", /*spanish*/"los #amantes caninos# encontrarán"}, + }, {}, + //clear text + Text{"#rescuing Richard the Dog# is rewarded with", /*french*/"#retrouver Kiki le chien# promet", /*spanish*/"#rescatar al perrito Ricardo# conduce a"} + ); + + hintTable[LW_OCARINA_MEMORY_GAME] = HintText::Exclude({ + //obscure text + Text{"the prize for a #game of Simon Says# is", /*french*/"la #récompense de Jean Dit# est", /*spanish*/"#repetir ciertas melodías# otorga"}, + Text{"a #child sing-a-long# holds", /*french*/"les #jeunes flûtistes# donnent", /*spanish*/"#tocar junto a otros# otorga"}, + }, {}, + //clear text + Text{"#playing an Ocarina in Lost Woods# is rewarded with", /*french*/"#jouer l'ocarina dans les Bois Perdus# donne", /*spanish*/"#tocar la ocarina en el Bosque Perdido# otorga"} + ); + + hintTable[KAK_10_GOLD_SKULLTULA_REWARD] = HintText::Exclude({ + //obscure text + Text{"#10 bug badges# rewards", /*french*/"#10 écussons# donnent", /*spanish*/"#10 medallas de insectos# otorgan"}, + Text{"#10 spider souls# yields", /*french*/"#10 âmes# donnent", /*spanish*/"#10 almas de araña# otorgan"}, + Text{"#10 auriferous arachnids# lead to", /*french*/"#10 arachnides aurifères# donnent", /*spanish*/"#10 arácnidos auríferos# otorgan"}, + }, {}, + //clear text + Text{"slaying #10 Gold Skulltulas# reveals", /*french*/"détruire #10 Skulltulas d'or# donne", /*spanish*/"#exterminar 10 skulltulas doradas# revela"} + ); + + hintTable[KAK_MAN_ON_ROOF] = HintText::Exclude({ + //obscure text + Text{"a #rooftop wanderer# holds", /*french*/"une #rencontre sur un toit# donne", /*spanish*/"#alguien sobre un tejado# otorga"}, + }); + + hintTable[ZR_MAGIC_BEAN_SALESMAN] = HintText::Exclude({ + //obscure text + Text{"a seller of #colorful crops# has", /*french*/"le #marchand de légumes# vend", /*spanish*/"el vendedor de un #colorido cultivo# ofrece"}, + }, {}, + //clear text + Text{"a #bean seller# offers", /*french*/"le #marchand de haricots magiques# vend en fait", /*spanish*/"el #vendedor de judías# ofrece"} + ); + + hintTable[ZR_FROGS_IN_THE_RAIN] = HintText::Exclude({ + //obscure text + Text{"#frogs in a storm# gift", /*french*/"#des grenouilles mouillées# donnent", /*spanish*/"las #ancas bajo la tormenta# otorgan"}, + }); + + hintTable[GF_HBA_1000_POINTS] = HintText::Exclude({ + //obscure text + Text{"scoring 1000 in #horseback archery# grants", /*french*/"obtenir 1000 points dans l'#archerie équestre# donne", /*spanish*/"conseguir 1000 puntos en el #tiro con arco a caballo# premia"}, + }); + + hintTable[MARKET_SHOOTING_GALLERY_REWARD] = HintText::Exclude({ + //obscure text + Text{"#shooting in youth# grants", /*french*/"#faire du tir dans sa jeunesse# donne", /*spanish*/"#disparar en la juventud# otorga"}, + }); + + hintTable[KAK_SHOOTING_GALLERY_REWARD] = HintText::Exclude({ + //obscure text + Text{"#shooting in maturity# grants", /*french*/"#faire du tir dans sa maturité# donne", /*spanish*/"#disparar en la madurez# otorga"}, + }); + + hintTable[LW_TARGET_IN_WOODS] = HintText::Exclude({ + //obscure text + Text{"shooting a #target in the woods# grants", /*french*/"#tirer une cible dans les bois# donne", /*spanish*/"disparar a un #blanco forestal# brinda"}, + }); + + hintTable[KAK_ANJU_AS_ADULT] = HintText::Exclude({ + //obscure text + Text{"a #chicken caretaker# offers adults", /*french*/"devenir un #éleveur de Cocottes# donne", /*spanish*/"una #cuidadora de emplumados# le ofrece a los mayores"}, + }); + + hintTable[LLR_TALONS_CHICKENS] = HintText::Exclude({ + //obscure text + Text{"#finding Super Cuccos# is rewarded with", /*french*/"#trouver des Super Cocottes# donne", /*spanish*/"#hallar los supercucos# conduce a"}, + }); + + hintTable[GC_ROLLING_GORON_AS_CHILD] = HintText::Exclude({ + //obscure text + Text{"the prize offered by a #large rolling Goron# is", /*french*/"la récompense d'un #gros Goron roulant# est", /*spanish*/"un #gran Goron rodante# otorga"}, + }); + + hintTable[LH_UNDERWATER_ITEM] = HintText::Exclude({ + //obscure text + Text{"the #sunken treasure in a lake# is", /*french*/"le #trésor au fond du lac# est", /*spanish*/"el #tesoro hundido del lago# se trata de"}, + }); + + hintTable[GF_GERUDO_MEMBERSHIP_CARD] = HintText::Exclude({ + //obscure text + Text{"#rescuing captured carpenters# is rewarded with", /*french*/"#secourir les charpentiers capturés# assure", /*spanish*/"#rescatar los apresados carpinteros# se premia con"}, + }); + + hintTable[WASTELAND_BOMBCHU_SALESMAN] = HintText::Exclude({ + //obscure text + Text{"a #carpet guru# sells", /*french*/"#un marchand du désert# vend", /*spanish*/"el #genio de una alfombra# vende"}, + }); + + + hintTable[KAK_IMPAS_HOUSE_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"#imprisoned in a house# lies", /*french*/"#encagé dans une maison# gît", /*spanish*/"#en una casa entre rejas# yace"}, + }); + + hintTable[HF_TEKTITE_GROTTO_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"#deep underwater in a hole# is", /*french*/"#dans les profondeurs d'une grotte# gît", /*spanish*/"#en lo hondo bajo un hoyo# yace"}, + }); + + hintTable[KAK_WINDMILL_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"on a #windmill ledge# lies", /*french*/"#haut perché dans le moulin# gît", /*spanish*/"al #borde de un molino# yace"}, + }); + + hintTable[GRAVEYARD_DAMPE_RACE_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"#racing a ghost# leads to", /*french*/"le défi du #revenant rapide# donne", /*spanish*/"#perseguir a un fantasma# conduce a"}, + }, {}, + //clear text + Text{"#dead Dampe's second# prize is", /*french*/"la #deuxième course d'Igor# donne", /*spanish*/"el segundo premio de #la carrera de Dampé# se trata de"} + ); + + hintTable[LLR_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"in a #ranch silo# lies", /*french*/"#dans l'entrepôt de la ferme# gît", /*spanish*/"en un #granero rupestre# yace"}, + }); + + hintTable[GRAVEYARD_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"a #crate in a graveyard# hides", /*french*/"#la boîte dans le Cimetière# contient", /*spanish*/"bajo la #caja de un cementerio# yace"}, + }); + + hintTable[GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR] = HintText::Exclude({ + //obscure text + Text{"a #gravekeeper digs up#", /*french*/"#le jeu du fossoyeur# cache", /*spanish*/"cierto #sepultero desentierra#"}, + }); + + hintTable[ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"on top of a #pillar in a river# lies", /*french*/"#sur un pilier au dessus du fleuve# gît", /*spanish*/"en lo alto del #pilar de un río# yace"}, + }); + + hintTable[ZR_NEAR_DOMAIN_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"on a #river ledge by a waterfall# lies", /*french*/"#sur la falaise au dessus du fleuve# gît", /*spanish*/"al borde de #la entrada a una cascada# yace"}, + }); + + hintTable[LH_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"high on a #lab rooftop# one can find", /*french*/"#la tour d'observation du lac# cache", /*spanish*/"en lo #alto de un laboratorio# yace"}, + }); + + hintTable[ZF_ICEBERG_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"#floating on ice# is", /*french*/"#gisant sur la glace# gît", /*spanish*/"#flotando sobre hielo# yace"}, + }); + + hintTable[GV_WATERFALL_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"behind a #desert waterfall# is", /*french*/"#derrière la cascade du désert# se cache", /*spanish*/"tras una #desierta cascada# yace"}, + }); + + hintTable[GV_CRATE_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"a #crate in a valley# hides", /*french*/"la #boîte dans la vallée# contient", /*spanish*/"bajo la #caja de un valle# yace"}, + }); + + hintTable[COLOSSUS_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"on top of an #arch of stone# lies", /*french*/"#gisant sur une arche de pierre# gît", /*spanish*/"en lo alto de un #arco de piedra# yace"}, + }); + + hintTable[DMT_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"above a #mountain cavern entrance# is", /*french*/"gisant #au dessus de la caverne montagneuse# gît", /*spanish*/"en lo alto de la #entrada de una cueva en la montaña# yace"}, + }); + + hintTable[DMC_WALL_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"nestled in a #volcanic wall# is", /*french*/"dans une #alcove volcanique# gît", /*spanish*/"entre unas #murallas volcánicas# yace"}, + }); + + hintTable[DMC_VOLCANO_FREESTANDING_POH] = HintText::Exclude({ + //obscure text + Text{"obscured by #volcanic ash# is", /*french*/"#recouvert de cendres volcaniques# gît", /*spanish*/"bajo la #ceniza volcánica# yace"}, + }); + + hintTable[GF_NORTH_F1_CARPENTER] = HintText::Exclude({ + //obscure text + Text{"#defeating Gerudo guards# reveals", /*french*/"les #geôliers Gerudo# détiennent", /*spanish*/"#derrotar a las guardas Gerudo# revela"}, + }); + + hintTable[GF_NORTH_F2_CARPENTER] = HintText::Exclude({ + //obscure text + Text{"#defeating Gerudo guards# reveals", /*french*/"les #geôliers Gerudo# détiennent", /*spanish*/"#derrotar a las guardas Gerudo# revela"}, + }); + + hintTable[GF_SOUTH_F1_CARPENTER] = HintText::Exclude({ + //obscure text + Text{"#defeating Gerudo guards# reveals", /*french*/"les #geôliers Gerudo# détiennent", /*spanish*/"#derrotar a las guardas Gerudo# revela"}, + }); + + hintTable[GF_SOUTH_F2_CARPENTER] = HintText::Exclude({ + //obscure text + Text{"#defeating Gerudo guards# reveals", /*french*/"les #geôliers Gerudo# détiennent", /*spanish*/"#derrotar a las guardas Gerudo# revela"}, + }); + + + hintTable[HF_GS_NEAR_KAK_GROTTO] = HintText::Exclude({ + //obscure text + Text{"a #spider-guarded spider in a hole# hoards", /*french*/"une #Skulltula dans un trou d'arachnides# a", /*spanish*/"una #Skulltula custodiada por otra# de un hoyo otorga"}, + }); + + + hintTable[LLR_GS_BACK_WALL] = HintText::Exclude({ + //obscure text + Text{"night reveals a #spider in a ranch# holding", /*french*/"une #Skulltula sur la façade de la ferme# a", /*spanish*/"la noche revela una #Skulltula del rancho# que otorga"}, + }); + + hintTable[LLR_GS_RAIN_SHED] = HintText::Exclude({ + //obscure text + Text{"night reveals a #spider in a ranch# holding", /*french*/"une #Skulltula sur le mur de l'enclos# a", /*spanish*/"la noche revela una #Skulltula del rancho# que otorga"}, + }); + + hintTable[LLR_GS_HOUSE_WINDOW] = HintText::Exclude({ + //obscure text + Text{"night reveals a #spider in a ranch# holding", /*french*/"une #Skulltula sur la maison de ferme# a", /*spanish*/"la noche revela una #Skulltula del rancho# que otorga"}, + }); + + hintTable[LLR_GS_TREE] = HintText::Exclude({ + //obscure text + Text{"a spider hiding in a #ranch tree# holds", /*french*/"une #Skulltula dans l'arbre de la ferme# a", /*spanish*/"una Skulltula escondida en el #árbol de un rancho# otorga"}, + }); + + + hintTable[KF_GS_BEAN_PATCH] = HintText::Exclude({ + //obscure text + Text{"a #spider buried in a forest# holds", /*french*/"une #Skulltula enterrée dans la forêt# a", /*spanish*/"una #Skulltula enterrada en un bosque# otorga"}, + }); + + hintTable[KF_GS_KNOW_IT_ALL_HOUSE] = HintText::Exclude({ + //obscure text + Text{"night in the past reveals a #spider in a forest# holding", /*french*/"une #Skulltula derrière une cabane de la forêt# a", /*spanish*/"la noche revela en el pasado una #Skulltula del bosque# que otorga"}, + }); + + hintTable[KF_GS_HOUSE_OF_TWINS] = HintText::Exclude({ + //obscure text + Text{"night in the future reveals a #spider in a forest# holding", /*french*/"une #Skulltula sur une cabane de la forêt# a", /*spanish*/"la noche revela en el futuro una #Skulltula del rancho# que otorga"}, + }); + + + hintTable[LW_GS_BEAN_PATCH_NEAR_BRIDGE] = HintText::Exclude({ + //obscure text + Text{"a #spider buried deep in a forest maze# holds", /*french*/"une #Skulltula enterrée dans les bois# a", /*spanish*/"una #Skulltula enterrada en un laberinto forestal# otorga"}, + }); + + hintTable[LW_GS_BEAN_PATCH_NEAR_THEATER] = HintText::Exclude({ + //obscure text + Text{"a #spider buried deep in a forest maze# holds", /*french*/"une #Skulltula enterrée dans les bois# a", /*spanish*/"una #Skulltula enterrada en un laberinto forestal# otorga"}, + }); + + hintTable[LW_GS_ABOVE_THEATER] = HintText::Exclude({ + //obscure text + Text{"night reveals a #spider deep in a forest maze# holding", /*french*/"une #Skulltula haut perchée dans les bois# a", /*spanish*/"la noche revela una #Skulltula del laberinto forestal# que otorga"}, + }); + + hintTable[SFM_GS] = HintText::Exclude({ + //obscure text + Text{"night reveals a #spider in a forest meadow# holding", /*french*/"une #Skulltula dans le sanctuaire des bois# a", /*spanish*/"la noche revela una #Skulltula de la pradera del bosque# que otorga"}, + }); + + + hintTable[OGC_GS] = HintText::Exclude({ + //obscure text + Text{"a #spider outside a tyrant's tower# holds", /*french*/"une #Skulltula parmi les ruines du château# a", /*spanish*/"una #Skulltula a las afueras de la torre de un tirano# otorga"}, + }); + + hintTable[HC_GS_TREE] = HintText::Exclude({ + //obscure text + Text{"a spider hiding in a #tree outside of a castle# holds", /*french*/"une #Skulltula dans l'arbre près du château# a", /*spanish*/"una Skulltula escondida en el #árbol de las afueras de un castillo# otorga"}, + }); + + hintTable[MARKET_GS_GUARD_HOUSE] = HintText::Exclude({ + //obscure text + Text{"a #spider in a guarded crate# holds", /*french*/"une #Skulltula dans une boîte en ville# a", /*spanish*/"una #Skulltula bajo una custodiada caja# otorga"}, + }); + + + hintTable[DMC_GS_BEAN_PATCH] = HintText::Exclude({ + //obscure text + Text{"a #spider buried in a volcano# holds", /*french*/"une #Skulltula enterrée dans un volcan# a", /*spanish*/"una #Skulltula enterrada en un volcán# otorga"}, + }); + + + hintTable[DMT_GS_BEAN_PATCH] = HintText::Exclude({ + //obscure text + Text{"a #spider buried outside a cavern# holds", /*french*/"une #Skulltula enterrée près d'une caverne# a", /*spanish*/"una #Skulltula enterrada a la entrada de una cueva# otorga"}, + }); + + hintTable[DMT_GS_NEAR_KAK] = HintText::Exclude({ + //obscure text + Text{"a #spider hidden in a mountain nook# holds", /*french*/"une #Skulltula cachée dans le flanc d'une montagne# a", /*spanish*/"una #Skulltula oculta en el rincón de la montaña# otorga"}, + }); + + hintTable[DMT_GS_ABOVE_DODONGOS_CAVERN] = HintText::Exclude({ + //obscure text + Text{"the hammer reveals a #spider on a mountain# holding", /*french*/"une #Skulltula derrière un rocher massif près d'une caverne# a", /*spanish*/"el martillo revela #una Skulltula de la montaña# que otorga"}, + }); + + hintTable[DMT_GS_FALLING_ROCKS_PATH] = HintText::Exclude({ + //obscure text + Text{"the hammer reveals a #spider on a mountain# holding", /*french*/"une #Skulltula derrière un rocher massif près du sommet d'un volcan# a", /*spanish*/"el martillo revela #una Skulltula de la montaña# que otorga"}, + }); + + + hintTable[GC_GS_CENTER_PLATFORM] = HintText::Exclude({ + //obscure text + Text{"a #suspended spider# in Goron City holds", /*french*/"une #Skulltula perchée dans le village Goron# a", /*spanish*/"una #Skulltula suspendida# en la Ciudad Goron otorga"}, + }); + + hintTable[GC_GS_BOULDER_MAZE] = HintText::Exclude({ + //obscure text + Text{"a spider in a #Goron City crate# holds", /*french*/"une #Skulltula dans une boîte du village Goron# a", /*spanish*/"una #Skulltula bajo una caja# de la Ciudad Goron otorga"}, + }); + + + hintTable[KAK_GS_HOUSE_UNDER_CONSTRUCTION] = HintText::Exclude({ + //obscure text + Text{"night in the past reveals a #spider in a town# holding", /*french*/"une #Skulltula dans le chantier de construction# a", /*spanish*/"la noche del pasado revela una #Skulltula del pueblo# que otorga"}, + }); + + hintTable[KAK_GS_SKULLTULA_HOUSE] = HintText::Exclude({ + //obscure text + Text{"night in the past reveals a #spider in a town# holding", /*french*/"une #Skulltula sur une maison maudite# a", /*spanish*/"la noche del pasado revela una #Skulltula del pueblo# que otorga"}, + }); + + hintTable[KAK_GS_GUARDS_HOUSE] = HintText::Exclude({ + //obscure text + Text{"night in the past reveals a #spider in a town# holding", /*french*/"une #Skulltula sur une maison de village# a", /*spanish*/"la noche del pasado revela una #Skulltula del pueblo# que otorga"}, + }); + + hintTable[KAK_GS_TREE] = HintText::Exclude({ + //obscure text + Text{"night in the past reveals a #spider in a town# holding", /*french*/"une #Skulltula dans un arbre de village# a", /*spanish*/"la noche del pasado revela una #Skulltula del pueblo# que otorga"}, + }); + + hintTable[KAK_GS_WATCHTOWER] = HintText::Exclude({ + //obscure text + Text{"night in the past reveals a #spider in a town# holding", /*french*/"une #Skulltula sur une échelle dans un village# a", /*spanish*/"la noche del pasado revela una #Skulltula del pueblo# que otorga"}, + }); + + hintTable[KAK_GS_ABOVE_IMPAS_HOUSE] = HintText::Exclude({ + //obscure text + Text{"night in the future reveals a #spider in a town# holding", /*french*/"une #Skulltula au dessus d'une grande maison# a", /*spanish*/"la noche del futuro revela una #Skulltula del pueblo# que otorga"}, + }); + + + hintTable[GRAVEYARD_GS_WALL] = HintText::Exclude({ + //obscure text + Text{"night reveals a #spider in a graveyard# holding", /*french*/"une #Skulltula sur une façade du Cimetière# a", /*spanish*/"la noche revela una #Skulltula del cementerio# que otorga"}, + }); + + hintTable[GRAVEYARD_GS_BEAN_PATCH] = HintText::Exclude({ + //obscure text + Text{"a #spider buried in a graveyard# holds", /*french*/"une #Skulltula enterrée dans le Cimetière# a", /*spanish*/"una #Skulltula enterrada en el cementerio# otorga"}, + }); + + + hintTable[ZR_GS_LADDER] = HintText::Exclude({ + //obscure text + Text{"night in the past reveals a #spider in a river# holding", /*french*/"une #Skulltula sur une échelle près d'une cascade# a", /*spanish*/"la noche del pasado revela una #Skulltula del río# que otorga"}, + }); + + hintTable[ZR_GS_TREE] = HintText::Exclude({ + //obscure text + Text{"a spider hiding in a #tree by a river# holds", /*french*/"une #Skulltula dans un arbre près du fleuve# a", /*spanish*/"una Skulltula escondida en el #árbol de un río# otorga"}, + }); + + hintTable[ZR_GS_ABOVE_BRIDGE] = HintText::Exclude({ + //obscure text + Text{"night in the future reveals a #spider in a river# holding", /*french*/"une #Skulltula sur une façade près d'une cascade# a", /*spanish*/"la noche del futuro revela una #Skulltula del río# que otorga"}, + }); + + hintTable[ZR_GS_NEAR_RAISED_GROTTOS] = HintText::Exclude({ + //obscure text + Text{"night in the future reveals a #spider in a river# holding", /*french*/"une #Skulltula sur une façade près d'une grotte du fleuve# a", /*spanish*/"la noche del futuro revela una #Skulltula del río# que otorga"}, + }); + + + hintTable[ZD_GS_FROZEN_WATERFALL] = HintText::Exclude({ + //obscure text + Text{"night reveals a #spider by a frozen waterfall# holding", /*french*/"une #Skulltula près d'une cascade gelée# a", /*spanish*/"la noche revela una #Skulltula junto a una congelada cascada# que otorga"}, + }); + + hintTable[ZF_GS_ABOVE_THE_LOG] = HintText::Exclude({ + //obscure text + Text{"night reveals a #spider near a deity# holding", /*french*/"une #Skulltula près du gardien aquatique# a", /*spanish*/"la noche revela una #Skulltula junto a cierta deidad# que otorga"}, + }); + + hintTable[ZF_GS_TREE] = HintText::Exclude({ + //obscure text + Text{"a spider hiding in a #tree near a deity# holds", /*french*/"une #Skulltula dans un arbre dans un réservoir# a", /*spanish*/"una Skulltula escondida en el #árbol junto a cierta deidad# otorga"}, + }); + + + hintTable[LH_GS_BEAN_PATCH] = HintText::Exclude({ + //obscure text + Text{"a #spider buried by a lake# holds", /*french*/"une #Skulltula enterrée près d'un lac# a", /*spanish*/"una #Skulltula enterrada junto a un lago# otorga"}, + }); + + hintTable[LH_GS_SMALL_ISLAND] = HintText::Exclude({ + //obscure text + Text{"night reveals a #spider by a lake# holding", /*french*/"une #Skulltula sur un îlot du lac# a", /*spanish*/"la noche revela una #Skulltula junto a un lago# que otorga"}, + }); + + hintTable[LH_GS_LAB_WALL] = HintText::Exclude({ + //obscure text + Text{"night reveals a #spider by a lake# holding", /*french*/"une #Skulltula sur le mur d'un centre de recherche# a", /*spanish*/"la noche revela una #Skulltula junto a un lago# que otorga"}, + }); + + hintTable[LH_GS_LAB_CRATE] = HintText::Exclude({ + //obscure text + Text{"a spider deed underwater in a #lab crate# holds", /*french*/"une #Skulltula dans une boîte au fond d'une cuve d'eau# a", /*spanish*/"una #Skulltula bajo la sumergida caja de un laboratorio# otorga"}, + }); + + hintTable[LH_GS_TREE] = HintText::Exclude({ + //obscure text + Text{"night reveals a #spider by a lake high in a tree# holding", /*french*/"une #Skulltula dans un grand arbre du lac# a", /*spanish*/"la noche revela #una Skulltula del lago sobre un árbol# que otorga"}, + }); + + + hintTable[GV_GS_BEAN_PATCH] = HintText::Exclude({ + //obscure text + Text{"a #spider buried in a valley# holds", /*french*/"une #Skulltula enterré dans une vallée# a", /*spanish*/"una #Skulltula enterrada en un valle# otorga"}, + }); + + hintTable[GV_GS_SMALL_BRIDGE] = HintText::Exclude({ + //obscure text + Text{"night in the past reveals a #spider in a valley# holding", /*french*/"une #Skulltula au dessus d'une petite cascade# a", /*spanish*/"la noche del pasado revela una #Skulltula del valle# que otorga"}, + }); + + hintTable[GV_GS_PILLAR] = HintText::Exclude({ + //obscure text + Text{"night in the future reveals a #spider in a valley# holding", /*french*/"une #Skulltula sur une arche de pierre dans une vallée# a", /*spanish*/"la noche del futuro revela una #Skulltula del valle# que otorga"}, + }); + + hintTable[GV_GS_BEHIND_TENT] = HintText::Exclude({ + //obscure text + Text{"night in the future reveals a #spider in a valley# holding", /*french*/"une #Skulltula derrière une tente# a", /*spanish*/"la noche del futuro revela una #Skulltula del valle# que otorga"}, + }); + + + hintTable[GF_GS_ARCHERY_RANGE] = HintText::Exclude({ + //obscure text + Text{"night reveals a #spider in a fortress# holding", /*french*/"une #Skulltula sur une cible de tir# a", /*spanish*/"la noche revela una #Skulltula de una fortaleza# que otorga"}, + }); + + hintTable[GF_GS_TOP_FLOOR] = HintText::Exclude({ + //obscure text + Text{"night reveals a #spider in a fortress# holding", /*french*/"une #Skulltula au sommet d'une forteresse# a", /*spanish*/"la noche revela una #Skulltula de una fortaleza# que otorga"}, + }); + + + hintTable[COLOSSUS_GS_BEAN_PATCH] = HintText::Exclude({ + //obscure text + Text{"a #spider buried in the desert# holds", /*french*/"une #Skulltula enterrée au pied du colosse# a", /*spanish*/"una #Skulltula enterrada en el desierto# otorga"}, + }); + + hintTable[COLOSSUS_GS_HILL] = HintText::Exclude({ + //obscure text + Text{"night reveals a #spider deep in the desert# holding", /*french*/"une #Skulltula sur une colline dans le désert# a", /*spanish*/"la noche revela una #Skulltula en las profundidades del desierto# que otorga"}, + }); + + hintTable[COLOSSUS_GS_TREE] = HintText::Exclude({ + //obscure text + Text{"night reveals a #spider deep in the desert# holding", /*french*/"une #Skulltula dans un arbre du désert# a", /*spanish*/"la noche revela una #Skulltula en las profundidades del desierto# que otorga"}, + }); + + + hintTable[KF_SHOP_ITEM_1] = HintText::Exclude({ + //obscure text + Text{"a #child shopkeeper# sells", /*french*/"la #boutique Kokiri# vend", /*spanish*/"un #joven dependiente# vende"}, + }); + + hintTable[KF_SHOP_ITEM_2] = HintText::Exclude({ + //obscure text + Text{"a #child shopkeeper# sells", /*french*/"la #boutique Kokiri# vend", /*spanish*/"un #joven dependiente# vende"}, + }); + + hintTable[KF_SHOP_ITEM_3] = HintText::Exclude({ + //obscure text + Text{"a #child shopkeeper# sells", /*french*/"la #boutique Kokiri# vend", /*spanish*/"un #joven dependiente# vende"}, + }); + + hintTable[KF_SHOP_ITEM_4] = HintText::Exclude({ + //obscure text + Text{"a #child shopkeeper# sells", /*french*/"la #boutique Kokiri# vend", /*spanish*/"un #joven dependiente# vende"}, + }); + + hintTable[KF_SHOP_ITEM_5] = HintText::Exclude({ + //obscure text + Text{"a #child shopkeeper# sells", /*french*/"la #boutique Kokiri# vend", /*spanish*/"un #joven dependiente# vende"}, + }); + + hintTable[KF_SHOP_ITEM_6] = HintText::Exclude({ + //obscure text + Text{"a #child shopkeeper# sells", /*french*/"la #boutique Kokiri# vend", /*spanish*/"un #joven dependiente# vende"}, + }); + + hintTable[KF_SHOP_ITEM_7] = HintText::Exclude({ + //obscure text + Text{"a #child shopkeeper# sells", /*french*/"la #boutique Kokiri# vend", /*spanish*/"un #joven dependiente# vende"}, + }); + + hintTable[KF_SHOP_ITEM_8] = HintText::Exclude({ + //obscure text + Text{"a #child shopkeeper# sells", /*french*/"la #boutique Kokiri# vend", /*spanish*/"un #joven dependiente# vende"}, + }); + + + hintTable[KAK_POTION_SHOP_ITEM_1] = HintText::Exclude({ + //obscure text + Text{"a #potion seller# offers", /*french*/"l'#apothicaire# vend", /*spanish*/"un #vendedor de pociones# ofrece"}, + }, {}, + //clear text + Text{"the #Kakariko Potion Shop# offers", /*french*/"l'#apothicaire de Kakariko# vend", /*spanish*/"la #tienda de pociones de Kakariko# ofrece"} + ); + + hintTable[KAK_POTION_SHOP_ITEM_2] = HintText::Exclude({ + //obscure text + Text{"a #potion seller# offers", /*french*/"l'#apothicaire# vend", /*spanish*/"un #vendedor de pociones# ofrece"}, + }, {}, + //clear text + Text{"the #Kakariko Potion Shop# offers", /*french*/"l'#apothicaire de Kakariko# vend", /*spanish*/"la #tienda de pociones de Kakariko# ofrece"} + ); + + hintTable[KAK_POTION_SHOP_ITEM_3] = HintText::Exclude({ + //obscure text + Text{"a #potion seller# offers", /*french*/"l'#apothicaire# vend", /*spanish*/"un #vendedor de pociones# ofrece"}, + }, {}, + //clear text + Text{"the #Kakariko Potion Shop# offers", /*french*/"l'#apothicaire de Kakariko# vend", /*spanish*/"la #tienda de pociones de Kakariko# ofrece"} + ); + + hintTable[KAK_POTION_SHOP_ITEM_4] = HintText::Exclude({ + //obscure text + Text{"a #potion seller# offers", /*french*/"l'#apothicaire# vend", /*spanish*/"un #vendedor de pociones# ofrece"}, + }, {}, + //clear text + Text{"the #Kakariko Potion Shop# offers", /*french*/"l'#apothicaire de Kakariko# vend", /*spanish*/"la #tienda de pociones de Kakariko# ofrece"} + ); + + hintTable[KAK_POTION_SHOP_ITEM_5] = HintText::Exclude({ + //obscure text + Text{"a #potion seller# offers", /*french*/"l'#apothicaire# vend", /*spanish*/"un #vendedor de pociones# ofrece"}, + }, {}, + //clear text + Text{"the #Kakariko Potion Shop# offers", /*french*/"l'#apothicaire de Kakariko# vend", /*spanish*/"la #tienda de pociones de Kakariko# ofrece"} + ); + + hintTable[KAK_POTION_SHOP_ITEM_6] = HintText::Exclude({ + //obscure text + Text{"a #potion seller# offers", /*french*/"l'#apothicaire# vend", /*spanish*/"un #vendedor de pociones# ofrece"}, + }, {}, + //clear text + Text{"the #Kakariko Potion Shop# offers", /*french*/"l'#apothicaire de Kakariko# vend", /*spanish*/"la #tienda de pociones de Kakariko# ofrece"} + ); + + hintTable[KAK_POTION_SHOP_ITEM_7] = HintText::Exclude({ + //obscure text + Text{"a #potion seller# offers", /*french*/"l'#apothicaire# vend", /*spanish*/"un #vendedor de pociones# ofrece"}, + }, {}, + //clear text + Text{"the #Kakariko Potion Shop# offers", /*french*/"l'#apothicaire de Kakariko# vend", /*spanish*/"la #tienda de pociones de Kakariko# ofrece"} + ); + + hintTable[KAK_POTION_SHOP_ITEM_8] = HintText::Exclude({ + //obscure text + Text{"a #potion seller# offers", /*french*/"l'#apothicaire# vend", /*spanish*/"un #vendedor de pociones# ofrece"}, + }, {}, + //clear text + Text{"the #Kakariko Potion Shop# offers", /*french*/"l'#apothicaire de Kakariko# vend", /*spanish*/"la #tienda de pociones de Kakariko# ofrece"} + ); + + + hintTable[MARKET_BOMBCHU_SHOP_ITEM_1] = HintText::Exclude({ + //obscure text + Text{"a #Bombchu merchant# sells", /*french*/"le #marchand de Missiles# vend", /*spanish*/"un #mercader de bombchus# vende"}, + }); + + hintTable[MARKET_BOMBCHU_SHOP_ITEM_2] = HintText::Exclude({ + //obscure text + Text{"a #Bombchu merchant# sells", /*french*/"le #marchand de Missiles# vend", /*spanish*/"un #mercader de bombchus# vende"}, + }); + + hintTable[MARKET_BOMBCHU_SHOP_ITEM_3] = HintText::Exclude({ + //obscure text + Text{"a #Bombchu merchant# sells", /*french*/"le #marchand de Missiles# vend", /*spanish*/"un #mercader de bombchus# vende"}, + }); + + hintTable[MARKET_BOMBCHU_SHOP_ITEM_4] = HintText::Exclude({ + //obscure text + Text{"a #Bombchu merchant# sells", /*french*/"le #marchand de Missiles# vend", /*spanish*/"un #mercader de bombchus# vende"}, + }); + + hintTable[MARKET_BOMBCHU_SHOP_ITEM_5] = HintText::Exclude({ + //obscure text + Text{"a #Bombchu merchant# sells", /*french*/"le #marchand de Missiles# vend", /*spanish*/"un #mercader de bombchus# vende"}, + }); + + hintTable[MARKET_BOMBCHU_SHOP_ITEM_6] = HintText::Exclude({ + //obscure text + Text{"a #Bombchu merchant# sells", /*french*/"le #marchand de Missiles# vend", /*spanish*/"un #mercader de bombchus# vende"}, + }); + + hintTable[MARKET_BOMBCHU_SHOP_ITEM_7] = HintText::Exclude({ + //obscure text + Text{"a #Bombchu merchant# sells", /*french*/"le #marchand de Missiles# vend", /*spanish*/"un #mercader de bombchus# vende"}, + }); + + hintTable[MARKET_BOMBCHU_SHOP_ITEM_8] = HintText::Exclude({ + //obscure text + Text{"a #Bombchu merchant# sells", /*french*/"le #marchand de Missiles# vend", /*spanish*/"un #mercader de bombchus# vende"}, + }); + + + hintTable[MARKET_POTION_SHOP_ITEM_1] = HintText::Exclude({ + //obscure text + Text{"a #potion seller# offers", /*french*/"l'#apothicaire# vend", /*spanish*/"un #vendedor de pociones# ofrece"}, + }, {}, + //clear text + Text{"the #Market Potion Shop# offers", /*french*/"l'#apothicaire dans la Place du Marché# vend", /*spanish*/"la #tienda de pociones del mercado# ofrece"} + ); + + hintTable[MARKET_POTION_SHOP_ITEM_2] = HintText::Exclude({ + //obscure text + Text{"a #potion seller# offers", /*french*/"l'#apothicaire# vend", /*spanish*/"un #vendedor de pociones# ofrece"}, + }, {}, + //clear text + Text{"the #Market Potion Shop# offers", /*french*/"l'#apothicaire dans la Place du Marché# vend", /*spanish*/"la #tienda de pociones del mercado# ofrece"} + ); + + hintTable[MARKET_POTION_SHOP_ITEM_3] = HintText::Exclude({ + //obscure text + Text{"a #potion seller# offers", /*french*/"l'#apothicaire# vend", /*spanish*/"un #vendedor de pociones# ofrece"}, + }, {}, + //clear text + Text{"the #Market Potion Shop# offers", /*french*/"l'#apothicaire dans la Place du Marché# vend", /*spanish*/"la #tienda de pociones del mercado# ofrece"} + ); + + hintTable[MARKET_POTION_SHOP_ITEM_4] = HintText::Exclude({ + //obscure text + Text{"a #potion seller# offers", /*french*/"l'#apothicaire# vend", /*spanish*/"un #vendedor de pociones# ofrece"}, + }, {}, + //clear text + Text{"the #Market Potion Shop# offers", /*french*/"l'#apothicaire dans la Place du Marché# vend", /*spanish*/"la #tienda de pociones del mercado# ofrece"} + ); + + hintTable[MARKET_POTION_SHOP_ITEM_5] = HintText::Exclude({ + //obscure text + Text{"a #potion seller# offers", /*french*/"l'#apothicaire# vend", /*spanish*/"un #vendedor de pociones# ofrece"}, + }, {}, + //clear text + Text{"the #Market Potion Shop# offers", /*french*/"l'#apothicaire dans la Place du Marché# vend", /*spanish*/"la #tienda de pociones del mercado# ofrece"} + ); + + hintTable[MARKET_POTION_SHOP_ITEM_6] = HintText::Exclude({ + //obscure text + Text{"a #potion seller# offers", /*french*/"l'#apothicaire# vend", /*spanish*/"un #vendedor de pociones# ofrece"}, + }, {}, + //clear text + Text{"the #Market Potion Shop# offers", /*french*/"l'#apothicaire dans la Place du Marché# vend", /*spanish*/"la #tienda de pociones del mercado# ofrece"} + ); + + hintTable[MARKET_POTION_SHOP_ITEM_7] = HintText::Exclude({ + //obscure text + Text{"a #potion seller# offers", /*french*/"l'#apothicaire# vend", /*spanish*/"un #vendedor de pociones# ofrece"}, + }, {}, + //clear text + Text{"the #Market Potion Shop# offers", /*french*/"l'#apothicaire dans la Place du Marché# vend", /*spanish*/"la #tienda de pociones del mercado# ofrece"} + ); + + hintTable[MARKET_POTION_SHOP_ITEM_8] = HintText::Exclude({ + //obscure text + Text{"a #potion seller# offers", /*french*/"l'#apothicaire# vend", /*spanish*/"un #vendedor de pociones# ofrece"}, + }, {}, + //clear text + Text{"the #Market Potion Shop# offers", /*french*/"l'#apothicaire dans la Place du Marché# vend", /*spanish*/"la #tienda de pociones del mercado# ofrece"} + ); + + + hintTable[MARKET_BAZAAR_ITEM_1] = HintText::Exclude({ + //obscure text + Text{"the #Market Bazaar# offers", /*french*/"le #bazar de la Place du Marché# vend", /*spanish*/"el #bazar del mercado# ofrece"}, + }); + + hintTable[MARKET_BAZAAR_ITEM_2] = HintText::Exclude({ + //obscure text + Text{"the #Market Bazaar# offers", /*french*/"le #bazar de la Place du Marché# vend", /*spanish*/"el #bazar del mercado# ofrece"}, + }); + + hintTable[MARKET_BAZAAR_ITEM_3] = HintText::Exclude({ + //obscure text + Text{"the #Market Bazaar# offers", /*french*/"le #bazar de la Place du Marché# vend", /*spanish*/"el #bazar del mercado# ofrece"}, + }); + + hintTable[MARKET_BAZAAR_ITEM_4] = HintText::Exclude({ + //obscure text + Text{"the #Market Bazaar# offers", /*french*/"le #bazar de la Place du Marché# vend", /*spanish*/"el #bazar del mercado# ofrece"}, + }); + + hintTable[MARKET_BAZAAR_ITEM_5] = HintText::Exclude({ + //obscure text + Text{"the #Market Bazaar# offers", /*french*/"le #bazar de la Place du Marché# vend", /*spanish*/"el #bazar del mercado# ofrece"}, + }); + + hintTable[MARKET_BAZAAR_ITEM_6] = HintText::Exclude({ + //obscure text + Text{"the #Market Bazaar# offers", /*french*/"le #bazar de la Place du Marché# vend", /*spanish*/"el #bazar del mercado# ofrece"}, + }); + + hintTable[MARKET_BAZAAR_ITEM_7] = HintText::Exclude({ + //obscure text + Text{"the #Market Bazaar# offers", /*french*/"le #bazar de la Place du Marché# vend", /*spanish*/"el #bazar del mercado# ofrece"}, + }); + + hintTable[MARKET_BAZAAR_ITEM_8] = HintText::Exclude({ + //obscure text + Text{"the #Market Bazaar# offers", /*french*/"le #bazar de la Place du Marché# vend", /*spanish*/"el #bazar del mercado# ofrece"}, + }); + + + hintTable[KAK_BAZAAR_ITEM_1] = HintText::Exclude({ + //obscure text + Text{"the #Kakariko Bazaar# offers", /*french*/"le #bazar de Kakariko# vend", /*spanish*/"el #bazar de Kakariko# ofrece"}, + }); + + hintTable[KAK_BAZAAR_ITEM_2] = HintText::Exclude({ + //obscure text + Text{"the #Kakariko Bazaar# offers", /*french*/"le #bazar de Kakariko# vend", /*spanish*/"el #bazar de Kakariko# ofrece"}, + }); + + hintTable[KAK_BAZAAR_ITEM_3] = HintText::Exclude({ + //obscure text + Text{"the #Kakariko Bazaar# offers", /*french*/"le #bazar de Kakariko# vend", /*spanish*/"el #bazar de Kakariko# ofrece"}, + }); + + hintTable[KAK_BAZAAR_ITEM_4] = HintText::Exclude({ + //obscure text + Text{"the #Kakariko Bazaar# offers", /*french*/"le #bazar de Kakariko# vend", /*spanish*/"el #bazar de Kakariko# ofrece"}, + }); + + hintTable[KAK_BAZAAR_ITEM_5] = HintText::Exclude({ + //obscure text + Text{"the #Kakariko Bazaar# offers", /*french*/"le #bazar de Kakariko# vend", /*spanish*/"el #bazar de Kakariko# ofrece"}, + }); + + hintTable[KAK_BAZAAR_ITEM_6] = HintText::Exclude({ + //obscure text + Text{"the #Kakariko Bazaar# offers", /*french*/"le #bazar de Kakariko# vend", /*spanish*/"el #bazar de Kakariko# ofrece"}, + }); + + hintTable[KAK_BAZAAR_ITEM_7] = HintText::Exclude({ + //obscure text + Text{"the #Kakariko Bazaar# offers", /*french*/"le #bazar de Kakariko# vend", /*spanish*/"el #bazar de Kakariko# ofrece"}, + }); + + hintTable[KAK_BAZAAR_ITEM_8] = HintText::Exclude({ + //obscure text + Text{"the #Kakariko Bazaar# offers", /*french*/"le #bazar de Kakariko# vend", /*spanish*/"el #bazar de Kakariko# ofrece"}, + }); + + + hintTable[ZD_SHOP_ITEM_1] = HintText::Exclude({ + //obscure text + Text{"a #Zora shopkeeper# sells", /*french*/"la #boutique Zora# vend", /*spanish*/"el #dependiente Zora# vende"}, + }); + + hintTable[ZD_SHOP_ITEM_2] = HintText::Exclude({ + //obscure text + Text{"a #Zora shopkeeper# sells", /*french*/"la #boutique Zora# vend", /*spanish*/"el #dependiente Zora# vende"}, + }); + + hintTable[ZD_SHOP_ITEM_3] = HintText::Exclude({ + //obscure text + Text{"a #Zora shopkeeper# sells", /*french*/"la #boutique Zora# vend", /*spanish*/"el #dependiente Zora# vende"}, + }); + + hintTable[ZD_SHOP_ITEM_4] = HintText::Exclude({ + //obscure text + Text{"a #Zora shopkeeper# sells", /*french*/"la #boutique Zora# vend", /*spanish*/"el #dependiente Zora# vende"}, + }); + + hintTable[ZD_SHOP_ITEM_5] = HintText::Exclude({ + //obscure text + Text{"a #Zora shopkeeper# sells", /*french*/"la #boutique Zora# vend", /*spanish*/"el #dependiente Zora# vende"}, + }); + + hintTable[ZD_SHOP_ITEM_6] = HintText::Exclude({ + //obscure text + Text{"a #Zora shopkeeper# sells", /*french*/"la #boutique Zora# vend", /*spanish*/"el #dependiente Zora# vende"}, + }); + + hintTable[ZD_SHOP_ITEM_7] = HintText::Exclude({ + //obscure text + Text{"a #Zora shopkeeper# sells", /*french*/"la #boutique Zora# vend", /*spanish*/"el #dependiente Zora# vende"}, + }); + + hintTable[ZD_SHOP_ITEM_8] = HintText::Exclude({ + //obscure text + Text{"a #Zora shopkeeper# sells", /*french*/"la #boutique Zora# vend", /*spanish*/"el #dependiente Zora# vende"}, + }); + + + hintTable[GC_SHOP_ITEM_1] = HintText::Exclude({ + //obscure text + Text{"a #Goron shopkeeper# sells", /*french*/"la #boutique Goron# vend", /*spanish*/"el #dependiente Goron# vende"}, + }); + + hintTable[GC_SHOP_ITEM_2] = HintText::Exclude({ + //obscure text + Text{"a #Goron shopkeeper# sells", /*french*/"la #boutique Goron# vend", /*spanish*/"el #dependiente Goron# vende"}, + }); + + hintTable[GC_SHOP_ITEM_3] = HintText::Exclude({ + //obscure text + Text{"a #Goron shopkeeper# sells", /*french*/"la #boutique Goron# vend", /*spanish*/"el #dependiente Goron# vende"}, + }); + + hintTable[GC_SHOP_ITEM_4] = HintText::Exclude({ + //obscure text + Text{"a #Goron shopkeeper# sells", /*french*/"la #boutique Goron# vend", /*spanish*/"el #dependiente Goron# vende"}, + }); + + hintTable[GC_SHOP_ITEM_5] = HintText::Exclude({ + //obscure text + Text{"a #Goron shopkeeper# sells", /*french*/"la #boutique Goron# vend", /*spanish*/"el #dependiente Goron# vende"}, + }); + + hintTable[GC_SHOP_ITEM_6] = HintText::Exclude({ + //obscure text + Text{"a #Goron shopkeeper# sells", /*french*/"la #boutique Goron# vend", /*spanish*/"el #dependiente Goron# vende"}, + }); + + hintTable[GC_SHOP_ITEM_7] = HintText::Exclude({ + //obscure text + Text{"a #Goron shopkeeper# sells", /*french*/"la #boutique Goron# vend", /*spanish*/"el #dependiente Goron# vende"}, + }); + + hintTable[GC_SHOP_ITEM_8] = HintText::Exclude({ + //obscure text + Text{"a #Goron shopkeeper# sells", /*french*/"la #boutique Goron# vend", /*spanish*/"el #dependiente Goron# vende"}, + }); + + + hintTable[HF_DEKU_SCRUB_GROTTO] = HintText::Exclude({ + //obscure text + Text{"a lonely #scrub in a hole# sells", /*french*/"la #peste Mojo dans une grotte de la plaine# vend", /*spanish*/"un #singular deku bajo un hoyo# de la llanura vende"}, + }); + + hintTable[LLR_DEKU_SCRUB_GROTTO_LEFT] = HintText::Exclude({ + //obscure text + Text{"a #trio of scrubs# sells", /*french*/"le #trio de peste Mojo à la ferme# vend", /*spanish*/"un #trío de dekus# de una granja venden"}, + }); + + hintTable[LLR_DEKU_SCRUB_GROTTO_RIGHT] = HintText::Exclude({ + //obscure text + Text{"a #trio of scrubs# sells", /*french*/"le #trio de peste Mojo à la ferme# vend", /*spanish*/"un #trío de dekus# de una granja venden"}, + }); + + hintTable[LLR_DEKU_SCRUB_GROTTO_CENTER] = HintText::Exclude({ + //obscure text + Text{"a #trio of scrubs# sells", /*french*/"le #trio de peste Mojo à la ferme# vend", /*spanish*/"un #trío de dekus# de una granja venden"}, + }); + + + hintTable[LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT] = HintText::Exclude({ + //obscure text + Text{"a pair of #scrubs in the woods# sells", /*french*/"le #duo de peste Mojo près du théâtre# vend", /*spanish*/"un par de #dekus del bosque# venden"}, + }); + + hintTable[LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT] = HintText::Exclude({ + //obscure text + Text{"a pair of #scrubs in the woods# sells", /*french*/"le #duo de peste Mojo près du théâtre# vend", /*spanish*/"un par de #dekus del bosque# venden"}, + }); + + hintTable[LW_DEKU_SCRUB_NEAR_BRIDGE] = HintText::Exclude({ + //obscure text + Text{"a #scrub by a bridge# sells", /*french*/"la #peste Mojo près du pont dans les bois# vend", /*spanish*/"un #deku bajo un puente# del bosque venden"}, + }); + + hintTable[LW_DEKU_SCRUB_GROTTO_REAR] = HintText::Exclude({ + //obscure text + Text{"a #scrub underground duo# sells", /*french*/"le #duo de peste Mojo dans les sous-bois# vend", /*spanish*/"un #par de dekus subterráneos# del bosque venden"}, + }); + + hintTable[LW_DEKU_SCRUB_GROTTO_FRONT] = HintText::Exclude({ + //obscure text + Text{"a #scrub underground duo# sells", /*french*/"le #duo de peste Mojo dans les sous-bois# vend", /*spanish*/"un #par de dekus subterráneos# del bosque venden"}, + }); + + + hintTable[SFM_DEKU_SCRUB_GROTTO_REAR] = HintText::Exclude({ + //obscure text + Text{"a #scrub underground duo# sells", /*french*/"le #duo de peste Mojo au cœur du sanctuaire sylvestre# vend", /*spanish*/"un #par de dekus subterráneos# de la pradera sagrada venden"}, + }); + + hintTable[SFM_DEKU_SCRUB_GROTTO_FRONT] = HintText::Exclude({ + //obscure text + Text{"a #scrub underground duo# sells", /*french*/"le #duo de peste Mojo au cœur du sanctuaire sylvestre# vend", /*spanish*/"un #par de dekus subterráneos# de la pradera sagrada venden"}, + }); + + + hintTable[GC_DEKU_SCRUB_GROTTO_LEFT] = HintText::Exclude({ + //obscure text + Text{"a #trio of scrubs# sells", /*french*/"le #trio de peste Mojo dans le village Goron# vend", /*spanish*/"un #trío de dekus# de la Ciudad Goron venden"}, + }); + + hintTable[GC_DEKU_SCRUB_GROTTO_RIGHT] = HintText::Exclude({ + //obscure text + Text{"a #trio of scrubs# sells", /*french*/"le #trio de peste Mojo dans le village Goron# vend", /*spanish*/"un #trío de dekus# de la Ciudad Goron venden"}, + }); + + hintTable[GC_DEKU_SCRUB_GROTTO_CENTER] = HintText::Exclude({ + //obscure text + Text{"a #trio of scrubs# sells", /*french*/"le #trio de peste Mojo dans le village Goron# vend", /*spanish*/"un #trío de dekus# de la Ciudad Goron venden"}, + }); + + + hintTable[DMC_DEKU_SCRUB_GROTTO_LEFT] = HintText::Exclude({ + //obscure text + Text{"a #trio of scrubs# sells", /*french*/"le #trio de peste Mojo dans le volcan# vend", /*spanish*/"un #trío de dekus# del volcán venden"}, + }); + + hintTable[DMC_DEKU_SCRUB_GROTTO_RIGHT] = HintText::Exclude({ + //obscure text + Text{"a #trio of scrubs# sells", /*french*/"le #trio de peste Mojo dans le volcan# vend", /*spanish*/"un #trío de dekus# del volcán venden"}, + }); + + hintTable[DMC_DEKU_SCRUB_GROTTO_CENTER] = HintText::Exclude({ + //obscure text + Text{"a #trio of scrubs# sells", /*french*/"le #trio de peste Mojo dans le volcan# vend", /*spanish*/"un #trío de dekus# del volcán venden"}, + }); + + + hintTable[ZR_DEKU_SCRUB_GROTTO_REAR] = HintText::Exclude({ + //obscure text + Text{"a #scrub underground duo# sells", /*french*/"le #duo de peste Mojo près du fleuve# vend", /*spanish*/"un #par de dekus subterráneos# del río venden"}, + }); + + hintTable[ZR_DEKU_SCRUB_GROTTO_FRONT] = HintText::Exclude({ + //obscure text + Text{"a #scrub underground duo# sells", /*french*/"le #duo de peste Mojo près du fleuve# vend", /*spanish*/"un #par de dekus subterráneos# del río venden"}, + }); + + + hintTable[LH_DEKU_SCRUB_GROTTO_LEFT] = HintText::Exclude({ + //obscure text + Text{"a #trio of scrubs# sells", /*french*/"le #trio de peste Mojo près du lac# vend", /*spanish*/"un #trío de dekus# del lago venden"}, + }); + + hintTable[LH_DEKU_SCRUB_GROTTO_RIGHT] = HintText::Exclude({ + //obscure text + Text{"a #trio of scrubs# sells", /*french*/"le #trio de peste Mojo près du lac# vend", /*spanish*/"un #trío de dekus# del lago venden"}, + }); + + hintTable[LH_DEKU_SCRUB_GROTTO_CENTER] = HintText::Exclude({ + //obscure text + Text{"a #trio of scrubs# sells", /*french*/"le #trio de peste Mojo près du lac# vend", /*spanish*/"un #trío de dekus# del lago venden"}, + }); + + + hintTable[GV_DEKU_SCRUB_GROTTO_REAR] = HintText::Exclude({ + //obscure text + Text{"a #scrub underground duo# sells", /*french*/"le #duo de peste Mojo près de la vallée# vend", /*spanish*/"un #par de dekus subterráneos# del valle venden"}, + }); + + hintTable[GV_DEKU_SCRUB_GROTTO_FRONT] = HintText::Exclude({ + //obscure text + Text{"a #scrub underground duo# sells", /*french*/"le #duo de peste Mojo près de la vallée# vend", /*spanish*/"un #par de dekus subterráneos# del valle venden"}, + }); + + + hintTable[COLOSSUS_DEKU_SCRUB_GROTTO_FRONT] = HintText::Exclude({ + //obscure text + Text{"a #scrub underground duo# sells", /*french*/"le #duo de peste Mojo dans le désert# vend", /*spanish*/"un #par de dekus subterráneos# del desierto venden"}, + }); + + hintTable[COLOSSUS_DEKU_SCRUB_GROTTO_REAR] = HintText::Exclude({ + //obscure text + Text{"a #scrub underground duo# sells", /*french*/"le #duo de peste Mojo dans le désert# vend", /*spanish*/"un #par de dekus subterráneos# del desierto venden"}, + }); + + + hintTable[LLR_STABLES_LEFT_COW] = HintText::Exclude({ + //obscure text + Text{"a #cow in a stable# gifts", /*french*/"la #vache dans l'étable# donne", /*spanish*/"una #vaca del establo# brinda"}, + }); + + hintTable[LLR_STABLES_RIGHT_COW] = HintText::Exclude({ + //obscure text + Text{"a #cow in a stable# gifts", /*french*/"la #vache dans l'étable# donne", /*spanish*/"una #vaca del establo# brinda"}, + }); + + hintTable[LLR_TOWER_RIGHT_COW] = HintText::Exclude({ + //obscure text + Text{"a #cow in a ranch silo# gifts", /*french*/"la #vache dans le silo de la ferme# donne", /*spanish*/"una #vaca del granero# brinda"}, + }); + + hintTable[LLR_TOWER_LEFT_COW] = HintText::Exclude({ + //obscure text + Text{"a #cow in a ranch silo# gifts", /*french*/"la #vache dans le silo de la ferme# donne", /*spanish*/"una #vaca del granero# brinda"}, + }); + + hintTable[KAK_IMPAS_HOUSE_COW] = HintText::Exclude({ + //obscure text + Text{"a #cow imprisoned in a house# protects", /*french*/"la #vache en cage# donne", /*spanish*/"una #vaca enjaulada de una casa# brinda"}, + }); + + hintTable[DMT_COW_GROTTO_COW] = HintText::Exclude({ + //obscure text + Text{"a #cow in a luxurious hole# offers", /*french*/"la #vache dans une grotte luxueuse# donne", /*spanish*/"una #vaca de un lujoso hoyo# brinda"}, + }); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp new file mode 100644 index 000000000..182948828 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp @@ -0,0 +1,1952 @@ +#include "../hint_list.hpp" + +void HintTable_Init_Item() { + hintTable[KOKIRI_SWORD] = HintText::Item({ + //obscure text + Text{"a butter knife", /*french*/"un couteau à beurre", /*spanish*/"un ágil puñal"}, + Text{"a starter slasher", /*french*/"une arme de débutant", /*spanish*/"una hoja de principiantes"}, + Text{"a switchblade", /*french*/"un canif", /*spanish*/"una navaja"}, + }, { + //ambiguous text + Text{"a sword", /*french*/"une épée", /*spanish*/"una espada"}, + }, + //clear text + Text{"the Kokiri Sword", /*french*/"l'Épée Kokiri", /*spanish*/"la Espada Kokiri"} + ); + + hintTable[MASTER_SWORD] = HintText::Item({ + //obscure text + Text{"evil's bane", /*french*/"le fléau du mal", /*spanish*/"la destructora del mal"}, + Text{"a seven year limbo", /*french*/"une stase de sept ans", /*spanish*/"unos siete años de espera"}, + }, { + //ambiguous text + Text{"a sword", /*french*/"une épée", /*spanish*/"una espada"}, + }, + //clear text + Text{"the Master Sword", /*french*/"l'Épée de Légende", /*spanish*/"la Espada Maestra"} + ); + + hintTable[GIANTS_KNIFE] = HintText::Item({ + //obscure text + Text{"a fragile blade", /*french*/"une lame fragile", /*spanish*/"una frágil hoja"}, + Text{"a breakable cleaver", /*french*/"un espadon de verre", /*spanish*/"un rompible acero"}, + }, { + //ambiguous text + Text{"a sword", /*french*/"une épée", /*spanish*/"una espada"}, + }, + //clear text + Text{"the Giant's Knife", /*french*/"la Lame des Géants", /*spanish*/"la daga gigante"} + ); + + hintTable[BIGGORON_SWORD] = HintText::Item({ + //obscure text + Text{"the biggest blade", /*french*/"une lame gigantesque", /*spanish*/"el mayor mandoble"}, + Text{"a colossal cleaver", /*french*/"un espadon colossal", /*spanish*/"un estoque colosal"}, + }, { + //ambiguous text + Text{"a sword", /*french*/"une épée", /*spanish*/"una espada"}, + }, + //clear text + Text{"the Biggoron Sword", /*french*/"l'Épée de Biggoron", /*spanish*/"la Espada de Biggoron"} + ); + + hintTable[DEKU_SHIELD] = HintText::Item({ + //obscure text + Text{"a wooden ward", /*french*/"un écu d'écorce", /*spanish*/"una protección del bosque"}, + Text{"a burnable barrier", /*french*/"une protection inflammable", /*spanish*/"una barrera quemable"}, + }, { + //ambiguous text + Text{"a shield", /*french*/"un bouclier", /*spanish*/"un escudo"}, + }, + //clear text + Text{"a Deku Shield", /*french*/"un Bouclier Mojo", /*spanish*/"un escudo deku"} + ); + + hintTable[HYLIAN_SHIELD] = HintText::Item({ + //obscure text + Text{"a steel safeguard", /*french*/"une carapace d'acier", /*spanish*/"una protección de acero"}, + Text{"Like Like's metal meal", /*french*/"un amuse-gueule de Pudding", /*spanish*/"un alimento de Like Like"}, + }, { + //ambiguous text + Text{"a shield", /*french*/"un bouclier", /*spanish*/"un escudo"}, + }, + //clear text + Text{"a Hylian Shield", /*french*/"un Bouclier Hylien", /*spanish*/"un escudo hyliano"} + ); + + hintTable[MIRROR_SHIELD] = HintText::Item({ + //obscure text + Text{"a reflective rampart", /*french*/"un capteur de lumière", /*spanish*/"una muralla reflectora"}, + Text{"Medusa's weakness", /*french*/"la faiblesse de Méduse", /*spanish*/"la debilidad de Medusa"}, + Text{"a silvered surface", /*french*/"une surface argentée", /*spanish*/"una superficie plateada"}, + }, { + //ambiguous text + Text{"a shield", /*french*/"un bouclier", /*spanish*/"un escudo"}, + }, + //clear text + Text{"the Mirror Shield", /*french*/"le Bouclier Miroir", /*spanish*/"el escudo espejo"} + ); + + hintTable[GORON_TUNIC] = HintText::Item({ + //obscure text + Text{"ruby robes", /*french*/"un pigment rouge", /*spanish*/"una vestimenta rubí"}, + Text{"fireproof fabric", /*french*/"un trésor anti-flamme", /*spanish*/"una ignífuga prenda"}, + Text{"cooking clothes", /*french*/"une tenue de cuisine", /*spanish*/"unos abrasantes ropajes"}, + }, { + //ambiguous text + Text{"a tunic", /*french*/"une tunique", /*spanish*/"un sayo"}, + }, + //clear text + Text{"a Goron Tunic", /*french*/"une Tunique Goron", /*spanish*/"un sayo goron"} + ); + + hintTable[ZORA_TUNIC] = HintText::Item({ + //obscure text + Text{"a sapphire suit", /*french*/"un pigment bleuté", /*spanish*/"una vestidura zafiro"}, + Text{"scuba gear", /*french*/"un habit de plongée", /*spanish*/"un traje impermeable"}, + Text{"a swimsuit", /*french*/"un costume de baignade", /*spanish*/"unos ropajes sumergibles"}, + }, { + //ambiguous text + Text{"a tunic", /*french*/"une tunique", /*spanish*/"un sayo"}, + Text{"something expensive", /*french*/"une chose dispendieuse", /*spanish*/"algo caro"}, + }, + //clear text + Text{"a Zora Tunic", /*french*/"une Tunique Zora", /*spanish*/"un sayo zora"} + ); + + hintTable[IRON_BOOTS] = HintText::Item({ + //obscure text + Text{"sink shoes", /*french*/"un boulet de fer", /*spanish*/"un calzado de las profundidades"}, + Text{"clank cleats", /*french*/"une paire de talons bruyants", /*spanish*/"unas suelas férreas"}, + }, { + //ambiguous text + Text{"some boots", /*french*/"une paire de bottes", /*spanish*/"un par de botas"}, + Text{"a feature of the Water Temple", /*french*/"une particularité du Temple de l'Eau", /*spanish*/"algo particular del Templo del Agua"}, + Text{"something heavy", /*french*/"une chose pesante", /*spanish*/"algo de lo más pesado"}, + }, + //clear text + Text{"the Iron Boots", /*french*/"une paire de Bottes de plomb", /*spanish*/"las botas de hierro"} + ); + + hintTable[HOVER_BOOTS] = HintText::Item({ + //obscure text + Text{"butter boots", /*french*/"une paire de patins de beurre", /*spanish*/"unas suelas resvaladizas"}, + Text{"sacred slippers", /*french*/"une paire de pantoufles sacrées", /*spanish*/"unos escurridizos botines"}, + Text{"spacewalkers", /*french*/"une paire de bottes spatiales", /*spanish*/"un calzado antigravitatorio"}, + }, { + //ambiguous text + Text{"some boots", /*french*/"une paire de bottes", /*spanish*/"un par de botas"}, + }, + //clear text + Text{"the Hover Boots", /*french*/"une paire de Bottes des airs", /*spanish*/"las botas voladoras"} + ); + + + hintTable[ZELDAS_LETTER] = HintText::Item({ + //obscure text + Text{"an autograph", /*french*/"un autographe", /*spanish*/"un autógrafo"}, + Text{"royal stationery", /*french*/"du papier royal", /*spanish*/"un escrito real"}, + Text{"royal snail mail", /*french*/"une enveloppe royale", /*spanish*/"correo de la realeza"}, + }, {}, + //clear text + Text{"Zelda's Letter", /*french*/"la Lettre de Zelda", /*spanish*/"la carta de Zelda"} + ); + + hintTable[WEIRD_EGG] = HintText::Item({ + //obscure text + Text{"a chicken dilemma", /*french*/"un drôle d'ovale", /*spanish*/"el dilema de la gallina"}, + }, { + //ambiguous text + Text{"an egg", /*french*/"un oeuf", /*spanish*/"un huevo"}, + }, + //clear text + Text{"the Weird Egg", /*french*/"l'Oeuf Curieux", /*spanish*/"el huevo extraño"} + ); + + hintTable[BOOMERANG] = HintText::Item({ + //obscure text + Text{"a banana", /*french*/"une banane", /*spanish*/"un plátano"}, + Text{"a stun stick", /*french*/"un bâton étourdissant", /*spanish*/"un palo aturdidor"}, + Text{"a yellow angle", /*french*/"un angle jaune", /*spanish*/"un ángulo amarillo"}, + }, { + //ambiguous text + Text{"something that can grab things", /*french*/"une chose qui peut attraper", /*spanish*/"algo que pueda agarrar cosas"}, + Text{"something that can stun", /*french*/"une chose qui peut paralyser", /*spanish*/"algo que pueda paralizar"}, + }, + //clear text + Text{"the Boomerang", /*french*/"le Boomerang", /*spanish*/"el bumerán"} + ); + + hintTable[LENS_OF_TRUTH] = HintText::Item({ + //obscure text + Text{"a lie detector", /*french*/"un détecteur de mensonges", /*spanish*/"el detector de ilusiones"}, + Text{"a ghost tracker", /*french*/"un trouve-fantôme", /*spanish*/"el rastreador paranormal"}, + Text{"true sight", /*french*/"le troisième œil", /*spanish*/"el ojo que todo ve"}, + Text{"a detective's tool", /*french*/"un trésor Sheikah", /*spanish*/"la revelación verdadera"}, + }, { + //ambiguous text + Text{"a secret-finding tool", /*french*/"un cherche-secrets", /*spanish*/"un instrumento para hallar objetos"}, + }, + //clear text + Text{"the Lens of Truth", /*french*/"le Monocle de Vérité", /*spanish*/"la Lupa de la Verdad"} + ); + + hintTable[MEGATON_HAMMER] = HintText::Item({ + //obscure text + Text{"the dragon smasher", /*french*/"le tueur de dragons", /*spanish*/"un destructor de dragones"}, + Text{"the metal mallet", /*french*/"un outil de construction", /*spanish*/"un mazo de metal"}, + Text{"the heavy hitter", /*french*/"un poids lourd", /*spanish*/"un machacador"}, + }, { + //ambiguous text + Text{"something that can remove boulders", /*french*/"une chose qui enlève les rochers", /*spanish*/"algo que pueda quitar rocas"}, + }, + //clear text + Text{"the Megaton Hammer", /*french*/"la Masse des Titans", /*spanish*/"el martillo Megatón"} + ); + + hintTable[STONE_OF_AGONY] = HintText::Item({ + //obscure text + Text{"the shake shard", /*french*/"le fragment vibrant", /*spanish*/"el fragmento tintineante"}, + Text{"a blue alarm", /*french*/"une alerte bleue", /*spanish*/"una azul alarma"}, + }, { + //ambiguous text + Text{"a prize of the House of Skulltulas", /*french*/"un prix de la maison des Skulltulas", /*spanish*/"un obsequio de la Casa Skulltula"}, + Text{"a secret-finding tool", /*french*/"un cherche-secrets", /*spanish*/"un instrumento para hallar objetos"}, + }, + //clear text + Text{"the Stone of Agony", /*french*/"la Pierre de Souffrance", /*spanish*/"la Piedra de la Agonía"} + ); + + hintTable[DINS_FIRE] = HintText::Item({ + //obscure text + Text{"an inferno", /*french*/"un brasier", /*spanish*/"un incendio"}, + Text{"a heat wave", /*french*/"une vague de chaleur", /*spanish*/"una onda de calor"}, + Text{"a red ball", /*french*/"une explosion de flammes", /*spanish*/"una roja esfera"}, + }, { + //ambiguous text + Text{"a Great Fairy's power", /*french*/"le pouvoir d'une grande fée", /*spanish*/"el poder de una Gran Hada"}, + }, + //clear text + Text{"Din's Fire", /*french*/"le Feu de Din", /*spanish*/"el Fuego de Din"} + ); + + hintTable[FARORES_WIND] = HintText::Item({ + //obscure text + Text{"teleportation", /*french*/"la téléportation", /*spanish*/"un teletransportador"}, + Text{"a relocation rune", /*french*/"une rune de relocation", /*spanish*/"una runa de transporte"}, + Text{"a green ball", /*french*/"une boule verte", /*spanish*/"una verde esfera"}, + }, { + //ambiguous text + Text{"a Great Fairy's power", /*french*/"le pouvoir d'une grande fée", /*spanish*/"el poder de una Gran Hada"}, + }, + //clear text + Text{"Farore's Wind", /*french*/"le Vent de Farore", /*spanish*/"el Viento de Farore"} + ); + + hintTable[NAYRUS_LOVE] = HintText::Item({ + //obscure text + Text{"a safe space", /*french*/"une bulle de cristal", /*spanish*/"una seguridad temporal"}, + Text{"an impregnable aura", /*french*/"un aura impénétrable", /*spanish*/"un aura impenetrable"}, + Text{"a blue barrier", /*french*/"une toison bleu", /*spanish*/"una barrera azul"}, + }, { + //ambiguous text + Text{"a Great Fairy's power", /*french*/"le pouvoir d'une grande fée", /*spanish*/"el poder de una Gran Hada"}, + }, + //clear text + Text{"Nayru's Love", /*french*/"l'Amour de Nayru", /*spanish*/"el Amor de Nayru"} + ); + + hintTable[FIRE_ARROWS] = HintText::Item({ + //obscure text + Text{"the furnace firearm" , /*french*/"une fusée solaire", /*spanish*/"el ardiente aguijón"}, + Text{"the burning bolts", /*french*/"un obus enflammé", /*spanish*/"las puntas ígneas"}, + Text{"a magma missile", /*french*/"un missile volcanique", /*spanish*/"el misil abrasador"}, + }, { + //ambiguous text + Text{"a magic arrow", /*french*/"une flèche magique", /*spanish*/"una flecha mágica"}, + }, + //clear text + Text{"the Fire Arrows", /*french*/"les Flèches de Feu", /*spanish*/"la flecha de fuego"} + ); + + hintTable[ICE_ARROWS] = HintText::Item({ + //obscure text + Text{"the refrigerator rocket", /*french*/"un missile pétrifiant", /*spanish*/"el misil congelador"}, + Text{"the frostbite bolts", /*french*/"un froid mordant", /*spanish*/"las puntas gélidas"}, + Text{"an iceberg maker", /*french*/"une aiguille glaciale", /*spanish*/"el control de escarcha"}, + }, { + //ambiguous text + Text{"a magic arrow", /*french*/"une flèche magique", /*spanish*/"una flecha mágica"}, + Text{"something that can stun", /*french*/"une chose qui peut paralyser", /*spanish*/"algo que pueda paralizar"}, + }, + //clear text + Text{"the Ice Arrows", /*french*/"les Flèches de Glace", /*spanish*/"la flecha de hielo"} + ); + + hintTable[LIGHT_ARROWS] = HintText::Item({ + //obscure text + Text{"the shining shot", /*french*/"l'arme brillante", /*spanish*/"el haz de luz"}, + Text{"the luminous launcher", /*french*/"un jet de lumière", /*spanish*/"el disparo luminoso"}, + Text{"Ganondorf's bane", /*french*/"le fléau de Ganondorf", /*spanish*/"la perdición de Ganondorf"}, + Text{"the lighting bolts", /*french*/"l'éclair sacré", /*spanish*/"las puntas resplandecientes"}, + }, { + //ambiguous text + Text{"a magic arrow", /*french*/"une flèche magique", /*spanish*/"una flecha mágica"}, + }, + //clear text + Text{"the Light Arrows", /*french*/"les Flèches de Lumière", /*spanish*/"la flecha de luz"} + ); + + hintTable[GERUDO_MEMBERSHIP_CARD] = HintText::Item({ + //obscure text + Text{"a girl club membership", /*french*/"une carte de membre", /*spanish*/"una fémina membresía"}, + Text{"a desert tribe's pass", /*french*/"un laissez-passer", /*spanish*/"el vale del desierto"}, + }, { + Text{"a token of recognition", /*french*/"une preuve de reconnaissance", /*spanish*/"una prueba de reconocimiento"}, + }, + //clear text + Text{"the Gerudo Membership Card", /*french*/"la Carte Gerudo", /*spanish*/"el pase de socio gerudo"} + ); + + hintTable[MAGIC_BEAN] = HintText::Item({ + //obscure text + Text{"a wizardly legume", /*french*/"un légume ensorcelé", /*spanish*/"una legumbre hechizada"}, + }, { + //ambiguous text + Text{"something sometimes buried", /*french*/"une chose parfois enterrée", /*spanish*/"algo a veces enterrado"}, + }, + //clear text + Text{"a Magic Bean", /*french*/"un Haricot Magique", /*spanish*/"una judía mágica"} + ); + + hintTable[MAGIC_BEAN_PACK] = HintText::Item({ + //obscure text + Text{"wizardly legumes", /*french*/"un paquet de légumes ensorcelés", /*spanish*/"unas legumbres hechizadas"}, + }, { + //ambiguous text + Text{"something sometimes buried", /*french*/"une chose parfois enterrée", /*spanish*/"algo a veces enterrado"}, + }, + //clear text + Text{"Magic Beans", /*french*/"un Paquet de Haricots Magiques", /*spanish*/"unas judías mágicas"} + ); + + hintTable[DOUBLE_DEFENSE] = HintText::Item({ + //obscure text + Text{"a white outline", /*french*/"un rebord blanc", /*spanish*/"un contorno blanco"}, + Text{"damage decrease", /*french*/"une protection supplémentaire", /*spanish*/"una reducción de daño"}, + Text{"strengthened love", /*french*/"un amour coriace", /*spanish*/"un amor fortalecido"}, + }, { + //ambiguous text + Text{"a Great Fairy's power", /*french*/"le pouvoir d'une grande fée", /*spanish*/"el poder de una Gran Hada"}, + Text{"something heart-shaped", /*french*/"une chose en forme de coeur", /*spanish*/"algo con forma de corazón"}, + }, + //clear text + Text{"Double Defense", /*french*/"la Double Défence", /*spanish*/"la doble defensa"} + ); + + hintTable[GOLD_SKULLTULA_TOKEN] = HintText::Item({ + //obscure text + Text{"proof of destruction", /*french*/"un certificat d'élimination", /*spanish*/"una prueba de la destrucción"}, + Text{"an arachnid chip", /*french*/"un symbole cranien", /*spanish*/"una figura arácnida"}, + Text{"spider remains", /*french*/"une dépouille dorée", /*spanish*/"unos restos dorados"}, + Text{"one percent of a curse", /*french*/"un centième de malédiction", /*spanish*/"una centésima de una maldición"}, + }, { + //ambiguous text + Text{"a token of recognition", /*french*/"une preuve de reconnaissance", /*spanish*/"una prueba de reconocimiento"}, + Text{"something sometimes buried", /*french*/"une chose parfois enterrée", /*spanish*/"algo a veces enterrado"}, + }, + //clear text + Text{"a Gold Skulltula Token", /*french*/"un Symbole de Skulltula d'or", /*spanish*/"un símbolo de skulltula dorada"} + ); + + hintTable[POCKET_EGG] = HintText::Item({ + //obscure text + Text{"a Cucco container", /*french*/"un réservoir à Cocotte", /*spanish*/"cuco contenido"}, + Text{"a Cucco, eventually", /*french*/"un poussin éventuel", /*spanish*/"un futuro cuco"}, + Text{"a fowl youth", /*french*/"une omelette crue", /*spanish*/"una dulce juventud"}, + }, { + //ambiguous text + Text{"a trade quest item", /*french*/"un objet de quête d'échanges", /*spanish*/"un objeto de una misión secundaria"}, + Text{"an egg", /*french*/"un oeuf", /*spanish*/"un huevo"}, + }, + //clear text + Text{"the Pocket Egg", /*french*/"l'Oeuf de Poche", /*spanish*/"el huevo de bolsillo"} + ); + + hintTable[POCKET_CUCCO] = HintText::Item({ + //obscure text + Text{"a little clucker", /*french*/"un petit glousseur", /*spanish*/"un pollito chiquito"}, + }, { + //ambiguous text + Text{"a trade quest item", /*french*/"un objet de quête d'échanges", /*spanish*/"un objeto de una misión secundaria"}, + }, + //clear text + Text{"the Pocket Cucco", /*french*/"la Cocotte de Poche", /*spanish*/"el cuco de bolsillo"} + ); + + hintTable[COJIRO] = HintText::Item({ + //obscure text + Text{"a cerulean capon", /*french*/"un paon azur", /*spanish*/"un cerúleo capón"}, + }, { + //ambiguous text + Text{"a trade quest item", /*french*/"un objet de quête d'échanges", /*spanish*/"un objeto de una misión secundaria"}, + }, + //clear text + Text{"Cojiro", /*french*/"le p'tit poulet", /*spanish*/"a Cojiro"} + ); + + hintTable[ODD_MUSHROOM] = HintText::Item({ + //obscure text + Text{"a powder ingredient", /*french*/"un ingrédient à poudre", /*spanish*/"un oloroso ingrediente"}, + }, { + //ambiguous text + Text{"a trade quest item", /*french*/"un objet de quête d'échanges", /*spanish*/"un objeto de una misión secundaria"}, + }, + //clear text + Text{"an Odd Mushroom", /*french*/"un Champignon Suspect", /*spanish*/"un champiñón extraño"} + ); + + hintTable[ODD_POTION] = HintText::Item({ + //obscure text + Text{"Granny's goodies", /*french*/"la confiserie de mamie", /*spanish*/"la especialidad de la abuela"}, + }, { + //ambiguous text + Text{"something that contains medicine", /*french*/"une chose médicamenteuse", /*spanish*/"algo que contenga medicina"}, + Text{"something with a strange smell", /*french*/"une chose qui sent bizarre", /*spanish*/"algo con un olor extraño"}, + Text{"a trade quest item", /*french*/"un objet de quête d'échanges", /*spanish*/"un objeto de una misión secundaria"}, + }, + //clear text + Text{"an Odd Potion", /*french*/"une Mixture Suspecte", /*spanish*/"una medicina rara"} + ); + + hintTable[POACHERS_SAW] = HintText::Item({ + //obscure text + Text{"a tree killer", /*french*/"un coupeur d'arbres", /*spanish*/"un destructor de árboles"}, + }, { + //ambiguous text + Text{"a trade quest item", /*french*/"un objet de quête d'échanges", /*spanish*/"un objeto de una misión secundaria"}, + }, + //clear text + Text{"the Poacher's Saw", /*french*/"la Scie du Chasseur", /*spanish*/"la sierra del furtivo"} + ); + + hintTable[BROKEN_SWORD] = HintText::Item({ + //obscure text + Text{"a shattered slicer", /*french*/"une arme cassée", /*spanish*/"una rebanadora rota"}, + }, { + //ambiguous text + Text{"a trade quest item", /*french*/"un objet de quête d'échanges", /*spanish*/"un objeto de una misión secundaria"}, + Text{"a sword", /*french*/"une épée", /*spanish*/"una espada"}, + }, + //clear text + Text{"the Broken Goron's Sword", /*french*/"l'Épée Brisée de Goron", /*spanish*/"la espada goron rota"} + ); + + hintTable[PRESCRIPTION] = HintText::Item({ + //obscure text + Text{"a pill pamphlet", /*french*/"un document urgent", /*spanish*/"un instructivo medicinal"}, + Text{"a doctor's note", /*french*/"un papier médical", /*spanish*/"unas notas del doctor"}, + }, { + //ambiguous text + Text{"a trade quest item", /*french*/"un objet de quête d'échanges", /*spanish*/"un objeto de una misión secundaria"}, + }, + //clear text + Text{"the Prescription", /*french*/"une Ordonnance", /*spanish*/"la receta"} + ); + + hintTable[EYEBALL_FROG] = HintText::Item({ + //obscure text + Text{"a perceiving polliwog", /*french*/"un amphibien", /*spanish*/"un variopinto batracio"}, + }, { + //ambiguous text + Text{"a trade quest item", /*french*/"un objet de quête d'échanges", /*spanish*/"un objeto de una misión secundaria"}, + }, + //clear text + Text{"the Eyeball Frog", /*french*/"le Crapaud-qui-louche", /*spanish*/"la rana de ojos saltones"} + ); + + hintTable[EYEDROPS] = HintText::Item({ + //obscure text + Text{"a vision vial", /*french*/"une solution oculaire", /*spanish*/"un remedio para la vista"}, + }, { + //ambiguous text + Text{"a trade quest item", /*french*/"un objet de quête d'échanges", /*spanish*/"un objeto de una misión secundaria"}, + }, + //clear text + Text{"the Eyedrops", /*french*/"une phiole de Super-Gouttes", /*spanish*/"las supergotas oculares"} + ); + + hintTable[CLAIM_CHECK] = HintText::Item({ + //obscure text + Text{"a three day wait", /*french*/"un rendez-vous dans trois jours", /*spanish*/"unos tres días de espera"}, + }, { + //ambiguous text + Text{"a trade quest item", /*french*/"un objet de quête d'échanges", /*spanish*/"un objeto de una misión secundaria"}, + }, + //clear text + Text{"the Claim Check", /*french*/"un Certificat", /*spanish*/"el recibo"} + ); + + hintTable[PROGRESSIVE_HOOKSHOT] = HintText::Item({ + //obscure text + Text{"Dampé's keepsake", /*french*/"l'héritage d'Igor", /*spanish*/"un recuerdo de Dampé"}, + Text{"the Grapple Beam", /*french*/"le rayon grippeur", /*spanish*/"una garra metálica"}, + Text{"the BOING! chain", /*french*/"la chaîne de BOING!", /*spanish*/"una cadena retráctil"}, + }, { + //ambiguous text + Text{"something that can grab things", /*french*/"une chose qui peut attraper", /*spanish*/"algo que pueda agarrar cosas"}, + Text{"something that can stun", /*french*/"une chose qui peut paralyser", /*spanish*/"algo que pueda paralizar"}, + }, + //clear text + Text{"a Hookshot", /*french*/"un Grappin", /*spanish*/"un gancho"} + ); + + hintTable[PROGRESSIVE_STRENGTH] = HintText::Item({ + //obscure text + Text{"power gloves", /*french*/"une paire de gants de travail", /*spanish*/"unos poderosos guanteletes"}, + Text{"metal mittens", /*french*/"une paire de mitaines", /*spanish*/"unas manoplas metálicas"}, + Text{"the heavy lifty", /*french*/"la puissance de dix hommes", /*spanish*/"un levantamiento pesado"}, + }, { + //ambiguous text + Text{"something that can remove boulders", /*french*/"une chose qui enlève les rochers", /*spanish*/"algo que pueda quitar rocas"}, + }, + //clear text + Text{"a Strength Upgrade", /*french*/"une Amélioration de Force", /*spanish*/"un aumento de fuerza"} + ); + + hintTable[PROGRESSIVE_BOMB_BAG] = HintText::Item({ + //obscure text + Text{"an explosive container", /*french*/"un porte-grenade", /*spanish*/"un recipiente explosivo"}, + Text{"a blast bag", /*french*/"un estomac de Dodongo", /*spanish*/"un zurrón de estallidos"}, + }, { + //ambiguous text + Text{"explosives", /*french*/"un paquet d'explosifs", /*spanish*/"un montón de explosivos"}, + Text{"something that can remove boulders", /*french*/"une chose qui enlève les rochers", /*spanish*/"algo que pueda quitar rocas"}, + }, + //clear text + Text{"a Bomb Bag", /*french*/"un Sac de Bombes", /*spanish*/"un saco de bombas"} + ); + + hintTable[PROGRESSIVE_BOW] = HintText::Item({ + //obscure text + Text{"an archery enabler", /*french*/"un facilitateur de tir", /*spanish*/"un tiro al blanco"}, + Text{"a danger dart launcher", /*french*/"un tire-fléchette", /*spanish*/"un peligroso lanzadardos"}, + }, { + //ambiguous text + Text{"a projectile shooter", /*french*/"un tire-projectile", /*spanish*/"un arma de proyectil"}, + }, + //clear text + Text{"a Bow", /*french*/"l'Arc des Fées", /*spanish*/"un arco de las hadas"} + ); + + hintTable[PROGRESSIVE_SLINGSHOT] = HintText::Item({ + //obscure text + Text{"a seed shooter", /*french*/"un lance-noix", /*spanish*/"un lanzasemillas"}, + Text{"a rubberband", /*french*/"un élastique", /*spanish*/"un tirachinas"}, + Text{"a child's catapult", /*french*/"un jouet d'enfant", /*spanish*/"una catapulta infantil"}, + }, { + //ambiguous text + Text{"a projectile shooter", /*french*/"un tire-projectile", /*spanish*/"un arma de proyectil"}, + }, + //clear text + Text{"a Slingshot", /*french*/"un Lance-Pierre", /*spanish*/"una resortera de las hadas"} + ); + + hintTable[PROGRESSIVE_WALLET] = HintText::Item({ + //obscure text + Text{"a mo' money holder", /*french*/"un sac à sous", /*spanish*/"una cartera de dinero"}, + Text{"a gem purse", /*french*/"une sacoche", /*spanish*/"un zurrón de gemas"}, + Text{"a portable bank", /*french*/"une petite banque", /*spanish*/"un banco portable"}, + }, { + //ambiguous text + Text{"a prize of the House of Skulltulas", /*french*/"un prix de la maison des Skulltulas", /*spanish*/"un obsequio de la Casa Skulltula"}, + }, + //clear text + Text{"a Wallet", /*french*/"une Bourse", /*spanish*/"una bolsa de rupias"} + ); + + hintTable[PROGRESSIVE_SCALE] = HintText::Item({ + //obscure text + Text{"a deeper dive", /*french*/"une bulle de plongée", /*spanish*/"un profundo buceo"}, + Text{"a piece of Zora", /*french*/"un morceau de Zora", /*spanish*/"un fragmento de Zora"}, + }, { + //ambiguous text + Text{"a diving tool", /*french*/"un outil de plongée", /*spanish*/"un instrumento de buceo"}, + }, + //clear text + Text{"a Zora Scale", /*french*/"une Écaille Zora", /*spanish*/"una escama Zora"} + ); + + hintTable[PROGRESSIVE_NUT_UPGRADE] = HintText::Item({ + //obscure text + Text{"more nuts", /*french*/"ecnore plus de noix", /*spanish*/"más semillas de nogal"}, + Text{"flashbang storage", /*french*/"un sac à noix", /*spanish*/"más frutos aturdidores"}, + }, { + //ambiguous text + Text{"some Deku munitions", /*french*/"un paquet de munitions Mojo", /*spanish*/"un montón de municiones Deku"}, + Text{"something that can stun", /*french*/"une chose qui peut paralyser", /*spanish*/"algo que pueda paralizar"}, + }, + //clear text + Text{"Deku Nut Capacity", /*french*/"une Augmentation de Noix Mojo", /*spanish*/"un aumento de nueces deku"} + ); + + hintTable[PROGRESSIVE_STICK_UPGRADE] = HintText::Item({ + //obscure text + Text{"a lumber rack", /*french*/"un paquet de bois", /*spanish*/"más bastones"}, + Text{"more flammable twigs", /*french*/"beaucoup de branches", /*spanish*/"más varas"}, + }, { + //ambiguous text + Text{"some Deku munitions", /*french*/"un paquet de munitions Mojo", /*spanish*/"un montón de municiones Deku"}, + }, + //clear text + Text{"Deku Stick Capacity", /*french*/"une augmentation de bâtons Mojo", /*spanish*/"un aumento de palos deku"} + ); + + hintTable[PROGRESSIVE_MAGIC_METER] = HintText::Item({ + //obscure text + Text{"mystic training", /*french*/"un potentiel magique", /*spanish*/"una maestría mística"}, + Text{"pixie dust", /*french*/"de la poudre de fée", /*spanish*/"un polvo de hada"}, + Text{"a green rectangle", /*french*/"un rectangle vert", /*spanish*/"una verduzca barra"}, + }, { + //ambiguous text + Text{"a Great Fairy's power", /*french*/"le pouvoir d'une grande fée", /*spanish*/"el poder de una Gran Hada"}, + }, + //clear text + Text{"a Magic Meter", /*french*/"une Jauge de Magie", /*spanish*/"un aumento de poder mágico"} + ); + + hintTable[PROGRESSIVE_OCARINA] = HintText::Item({ + //obscure text + Text{"a flute", /*french*/"un bec musical", /*spanish*/"un utensilio musical"}, + Text{"a music maker", /*french*/"un porteur de chansons", /*spanish*/"un instrumento"}, + }, { + //ambiguous text + Text{"something given by Saria", /*french*/"un cadeau de Saria", /*spanish*/"un obsequio de Saria"}, + Text{"something kept by the royal family", /*french*/"une chose qui paralyse", /*spanish*/"algo guardado por la familia real"}, + }, + //clear text + Text{"an Ocarina", /*french*/"un ocarina", /*spanish*/"una ocarina"} + ); + + hintTable[PROGRESSIVE_BOMBCHUS] = HintText::Item({ + //obscure text + Text{"mice bombs", /*french*/"un adorable explosif", /*spanish*/"unas bombas roedoras"}, + Text{"proximity mice", /*french*/"une mine anti-rongeur", /*spanish*/"unos explosivos ratoncitos"}, + Text{"wall crawlers", /*french*/"un rapide grimpeur", /*spanish*/"unos trepaparedes"}, + Text{"trail blazers", /*french*/"un zigzag éclatant", /*spanish*/"unas ratas propulsadas"}, + }, { + //ambiguous text + Text{"a prize of the House of Skulltulas", /*french*/"un prix de la maison des Skulltulas", /*spanish*/"un obsequio de la Casa Skulltula"}, + Text{"explosives", /*french*/"un paquet d'explosifs", /*spanish*/"un montón de explosivos"}, + }, + //clear text + Text{"Bombchus", /*french*/"un paquet de Missiles", /*spanish*/"unos bombchus"} + ); + + hintTable[PROGRESSIVE_GORONSWORD] = HintText::Item({ + //obscure text + Text{"a long blade", /*french*/"une longue lame", /*spanish*/"una gran hoja"}, + Text{"a Goron weapon", /*french*/"une arme Goron", /*spanish*/"un arma goron"}, + }, { + //ambiguous text + Text{"a sword", /*french*/"une épée", /*spanish*/"una espada"}, + }, + //clear text + Text{"a Goron Sword", /*french*/"une épée Goron", /*spanish*/"una espada goron"} + ); + + hintTable[EMPTY_BOTTLE] = HintText::Item({ + //obscure text + Text{"a glass container", /*french*/"un cylindre de cristal", /*spanish*/"un recipiente de cristal"}, + Text{"an empty jar", /*french*/"une jarre incassable", /*spanish*/"un frasco vacío"}, + Text{"encased air", /*french*/"un bocal d'air", /*spanish*/"aire a presión"}, + }, { + //ambiguous text + Text{"a bottle", /*french*/"un flacon", /*spanish*/"una botella"}, + }, + //clear text + Text{"a Bottle", /*french*/"un flacon vide", /*spanish*/"una botella"} + ); + + hintTable[BOTTLE_WITH_MILK] = HintText::Item({ + //obscure text + Text{"cow juice", /*french*/"une source de calcium", /*spanish*/"una fuente de calcio"}, + Text{"a white liquid", /*french*/"un liquide blanc", /*spanish*/"una bebida nutritiva"}, + Text{"a baby's breakfast", /*french*/"du jus pour bébé", /*spanish*/"un trago para bebés"}, + }, { + //ambiguous text + Text{"a bottle", /*french*/"un flacon", /*spanish*/"una botella"}, + }, + //clear text + Text{"a Milk Bottle", /*french*/"un flacon de lait", /*spanish*/"una botella de leche"} + ); + + hintTable[BOTTLE_WITH_RED_POTION] = HintText::Item({ + //obscure text + Text{"a vitality vial", /*french*/"un mélange de vitalité", /*spanish*/"una pócima vitalicia"}, + Text{"a red liquid", /*french*/"un liquide rouge", /*spanish*/"un remedio rojizo"}, + }, { + //ambiguous text + Text{"a bottle", /*french*/"un flacon", /*spanish*/"una botella"}, + }, + //clear text + Text{"a Red Potion Bottle", /*french*/"un flacon de potion rouge", /*spanish*/"una botella de poción roja"} + ); + + hintTable[BOTTLE_WITH_GREEN_POTION] = HintText::Item({ + //obscure text + Text{"a magic mixture", /*french*/"une réserve magique", /*spanish*/"un potingue mágico"}, + Text{"a green liquid", /*french*/"un liquide vert", /*spanish*/"un remedio verduzco"}, + }, { + //ambiguous text + Text{"a bottle", /*french*/"un flacon", /*spanish*/"una botella"}, + }, + //clear text + Text{"a Green Potion Bottle", /*french*/"un flacon de potion verte", /*spanish*/"una botella de poción verde"} + ); + + hintTable[BOTTLE_WITH_BLUE_POTION] = HintText::Item({ + //obscure text + Text{"an ailment antidote", /*french*/"l'élixir ultime", /*spanish*/"un antídoto para el dolor"}, + Text{"a blue liquid", /*french*/"un liquide bleu", /*spanish*/"un remedio índigo"}, + }, { + //ambiguous text + Text{"a bottle", /*french*/"un flacon", /*spanish*/"una botella"}, + }, + //clear text + Text{"a Blue Potion Bottle", /*french*/"un flacon de potion bleue", /*spanish*/"una botella de poción azul"} + ); + + hintTable[BOTTLE_WITH_FAIRY] = HintText::Item({ + //obscure text + Text{"an imprisoned fairy", /*french*/"une fée emprisonnée", /*spanish*/"un hada atrapada"}, + Text{"an extra life", /*french*/"une vie de rechange", /*spanish*/"una oportunidad más"}, + Text{"Navi's cousin", /*french*/"le cousin de Navi", /*spanish*/"una prima de Navi"}, + }, { + //ambiguous text + Text{"a bottle", /*french*/"un flacon", /*spanish*/"una botella"}, + }, + //clear text + Text{"a Fairy Bottle", /*french*/"une fée en flacon", /*spanish*/"un hada en una botella"} + ); + + hintTable[BOTTLE_WITH_FISH] = HintText::Item({ + //obscure text + Text{"an aquarium", /*french*/"un aquarium", /*spanish*/"un escamado ser"}, + Text{"a deity's snack", /*french*/"le repas d'un dieu marin", /*spanish*/"un tentempié de cierta deidad"}, + }, { + //ambiguous text + Text{"a bottle", /*french*/"un flacon", /*spanish*/"una botella"}, + }, + //clear text + Text{"a Fish Bottle", /*french*/"un poisson en flacon", /*spanish*/"un pez en una botella"} + ); + + hintTable[BOTTLE_WITH_BLUE_FIRE] = HintText::Item({ + //obscure text + Text{"a conflagration canteen", /*french*/"une mystérieuse flamme", /*spanish*/"un incendio retenido"}, + Text{"an icemelt jar", /*french*/"un brasier glacial", /*spanish*/"unas brasas enfrascadas"}, + }, { + //ambiguous text + Text{"a bottle", /*french*/"un flacon", /*spanish*/"una botella"}, + }, + //clear text + Text{"a Blue Fire Bottle", /*french*/"une flamme bleue en flacon", /*spanish*/"una botella de fuego azul"} + ); + + hintTable[BOTTLE_WITH_BUGS] = HintText::Item({ + //obscure text + Text{"an insectarium", /*french*/"un insectarium", /*spanish*/"unos invertebrados seres"}, + Text{"Skulltula finders", /*french*/"une poignée de trouve-Skulltula", /*spanish*/"unos rastreadores de skulltulas"}, + }, { + //ambiguous text + Text{"a bottle", /*french*/"un flacon", /*spanish*/"una botella"}, + }, + //clear text + Text{"a Bug Bottle", /*french*/"un insecte en flacon", /*spanish*/"unos insectos en una botella"} + ); + + hintTable[BOTTLE_WITH_POE] = HintText::Item({ + //obscure text + Text{"a spooky ghost", /*french*/"un effroyable fantôme", /*spanish*/"un espantoso espectro"}, + Text{"a face in the jar", /*french*/"un visage dans un bocal", /*spanish*/"una expresión enfrascada"}, + }, { + //ambiguous text + Text{"a bottle", /*french*/"un flacon", /*spanish*/"una botella"}, + }, + //clear text + Text{"a Poe Bottle", /*french*/"un Esprit en flacon", /*spanish*/"un Poe en una botella"} + ); + + hintTable[BOTTLE_WITH_BIG_POE] = HintText::Item({ + //obscure text + Text{"the spookiest ghost", /*french*/"un épouvantable spectre", /*spanish*/"el espectro más espeluznante"}, + Text{"a sidequest spirit", /*french*/"un précieux esprit", /*spanish*/"un buen valorado espíritu"}, + }, { + //ambiguous text + Text{"a bottle", /*french*/"un flacon", /*spanish*/"una botella"}, + }, + //clear text + Text{"a Big Poe Bottle", /*french*/"une Ame en flacon", /*spanish*/"un Gran Poe en una botella"} + ); + + hintTable[RUTOS_LETTER] = HintText::Item({ + //obscure text + Text{"a call for help", /*french*/"un appel au secours", /*spanish*/"una llamada de auxilio"}, + Text{"the note that Mweeps", /*french*/"un message qui fait mwip", /*spanish*/"un escrito mweep"}, + Text{"an SOS call", /*french*/"un signal SOS", /*spanish*/"una nota de socorro"}, + Text{"a fishy stationery", /*french*/"un papier mouillé", /*spanish*/"un mensaje de ayuda"}, + }, { + //ambiguous text + Text{"a bottle", /*french*/"un flacon", /*spanish*/"una botella"}, + }, + //clear text + Text{"Ruto's Letter", /*french*/"la lettre de Ruto", /*spanish*/"la carta de Ruto"} + ); + + hintTable[ZELDAS_LULLABY] = HintText::Item({ + //obscure text + Text{"a song of royal slumber", /*french*/"une chanson royale", /*spanish*/"la canción real"}, + Text{"a triforce tune", /*french*/"la musique sacrée", /*spanish*/"la melodía de la trifuerza"}, + }, { + //ambiguous text + Text{"a regular song", /*french*/"une chanson normale", /*spanish*/"una cancion normal"}, + Text{"something kept by the royal family", /*french*/"une chose qui paralyse", /*spanish*/"algo guardado por la familia real"}, + }, + //clear text + Text{"Zelda's Lullaby", /*french*/"la berceuse de Zelda", /*spanish*/"la Nana de Zelda"} + ); + + hintTable[EPONAS_SONG] = HintText::Item({ + //obscure text + Text{"an equestrian etude", /*french*/"une hymne équestre", /*spanish*/"una copla ecuestre"}, + Text{"Malon's melody", /*french*/"la mélodie des vaches", /*spanish*/"la sonata de Malon"}, + Text{"a ranch song", /*french*/"le chant des champs", /*spanish*/"un canto rupestre"}, + }, { + //ambiguous text + Text{"a regular song", /*french*/"une chanson normale", /*spanish*/"una cancion normal"}, + }, + //clear text + Text{"Epona's Song", /*french*/"le chant d'Epona", /*spanish*/"la Canción de Epona"} + ); + + hintTable[SARIAS_SONG] = HintText::Item({ + //obscure text + Text{"a song of dancing Gorons", /*french*/"une chanson danceuse", /*spanish*/"un pegadizo tono goron"}, + Text{"Saria's phone number", /*french*/"le téléphone d'une amie", /*spanish*/"una consulta de asistencia"}, + }, { + //ambiguous text + Text{"a regular song", /*french*/"une chanson normale", /*spanish*/"una cancion normal"}, + Text{"something given by Saria", /*french*/"un cadeau de Saria", /*spanish*/"un obsequio de Saria"}, + }, + //clear text + Text{"Saria's Song", /*french*/"le chant de Saria", /*spanish*/"la Canción de Saria"} + ); + + hintTable[SUNS_SONG] = HintText::Item({ + //obscure text + Text{"Sunny Day", /*french*/"Zénith", /*spanish*/"un día soleado"}, + Text{"the ReDead's bane", /*french*/"le fléau des Éffrois", /*spanish*/"la destructora de Redeads"}, + Text{"the Gibdo's bane", /*french*/"le fléau des Gibdo", /*spanish*/"la destructora de Gibdos"}, + }, { + //ambiguous text + Text{"a regular song", /*french*/"une chanson normale", /*spanish*/"una cancion normal"}, + Text{"something that can stun", /*french*/"une chose qui peut paralyser", /*spanish*/"algo que pueda paralizar"}, + }, + //clear text + Text{"the Sun's Song", /*french*/"le chant du soleil", /*spanish*/"la Canción del Sol"} + ); + + hintTable[SONG_OF_TIME] = HintText::Item({ + //obscure text + Text{"a song 7 years long", /*french*/"le flot du temps", /*spanish*/"la setenada canción"}, + Text{"the tune of ages", /*french*/"le Chant des Âges", /*spanish*/"la melodía eónica"}, + }, { + //ambiguous text + Text{"a regular song", /*french*/"une chanson normale", /*spanish*/"una cancion normal"}, + }, + //clear text + Text{"the Song of Time", /*french*/"le chant du temps", /*spanish*/"la Canción del tiempo"} + ); + + hintTable[SONG_OF_STORMS] = HintText::Item({ + //obscure text + Text{"Rain Dance", /*french*/"Danse Pluie", /*spanish*/"la danza de la lluvia"}, + Text{"a thunderstorm tune", /*french*/"une hymne foudroyante", /*spanish*/"una sonata tormentosa"}, + Text{"windmill acceleration", /*french*/"l'accélérateur de moulins", /*spanish*/"el arranque de molinos"}, + }, { + //ambiguous text + Text{"a regular song", /*french*/"une chanson normale", /*spanish*/"una cancion normal"}, + }, + //clear text + Text{"the Song of Storms", /*french*/"le chant des tempêtes", /*spanish*/"la Canción de la Tormenta"} + ); + + hintTable[MINUET_OF_FOREST] = HintText::Item({ + //obscure text + Text{"the song of tall trees", /*french*/"le bruit des arbres", /*spanish*/"la canción de las copas"}, + Text{"an arboreal anthem", /*french*/"l'hymne sylvestre", /*spanish*/"el himno forestal"}, + Text{"a green spark trail", /*french*/"une comète verte", /*spanish*/"el sendero esmeralda"}, + }, { + //ambiguous text + Text{"a warp song", /*french*/"une chanson de téléportation", /*spanish*/"una canción de teletransportación"}, + }, + //clear text + Text{"the Minuet of Forest", /*french*/"le menuet de la forêt", /*spanish*/"el Minueto del bosque"} + ); + + hintTable[BOLERO_OF_FIRE] = HintText::Item({ + //obscure text + Text{"a song of lethal lava", /*french*/"une musique enflammée", /*spanish*/"la canción de la lava"}, + Text{"a red spark trail", /*french*/"une comète rouge", /*spanish*/"el sendero rubí"}, + Text{"a volcanic verse", /*french*/"le souffle du volcan", /*spanish*/"el verso volcánico"}, + }, { + //ambiguous text + Text{"a warp song", /*french*/"une chanson de téléportation", /*spanish*/"una canción de teletransportación"}, + }, + //clear text + Text{"the Bolero of Fire", /*french*/"le boléro du feu", /*spanish*/"el Bolero del fuego"} + ); + + hintTable[SERENADE_OF_WATER] = HintText::Item({ + //obscure text + Text{"a song of a damp ditch", /*french*/"le calme de l'eau", /*spanish*/"la canción del estanque"}, + Text{"a blue spark trail", /*french*/"une comète bleue", /*spanish*/"el sendero zafiro"}, + Text{"the lake's lyric", /*french*/"la voix du lac", /*spanish*/"la letra del lago"}, + }, { + //ambiguous text + Text{"a warp song", /*french*/"une chanson de téléportation", /*spanish*/"una canción de teletransportación"}, + }, + //clear text + Text{"the Serenade of Water", /*french*/"la sérénade de l'eau", /*spanish*/"la Serenata del agua"} + ); + + hintTable[REQUIEM_OF_SPIRIT] = HintText::Item({ + //obscure text + Text{"a song of sandy statues", /*french*/"la mélodie d'une grande statue", /*spanish*/"la canción de la gran estatua"}, + Text{"an orange spark trail", /*french*/"une comète orange", /*spanish*/"el sendero ámbar"}, + Text{"the desert ditty", /*french*/"le vent du désert", /*spanish*/"la estrofa del desierto"}, + }, { + //ambiguous text + Text{"a warp song", /*french*/"une chanson de téléportation", /*spanish*/"una canción de teletransportación"}, + }, + //clear text + Text{"the Requiem of Spirit", /*french*/"le requiem des esprits", /*spanish*/"el Réquiem del espíritu"} + ); + + hintTable[NOCTURNE_OF_SHADOW] = HintText::Item({ + //obscure text + Text{"a song of spooky spirits", /*french*/"une hymne de chair de poule", /*spanish*/"la canción de los espectros"}, + Text{"a graveyard boogie", /*french*/"un boogie de fantômes", /*spanish*/"una honra fúnebre"}, + Text{"a haunted hymn", /*french*/"une chanson lugubre", /*spanish*/"una estrofa encantada"}, + Text{"a purple spark trail", /*french*/"une comète mauve", /*spanish*/"el sendero malva"}, + }, { + //ambiguous text + Text{"a warp song", /*french*/"une chanson de téléportation", /*spanish*/"una canción de teletransportación"}, + }, + //clear text + Text{"the Nocturne of Shadow", /*french*/"le nocturne de l'ombre", /*spanish*/"el Nocturno de la sombra"} + ); + + hintTable[PRELUDE_OF_LIGHT] = HintText::Item({ + //obscure text + Text{"a luminous prologue melody", /*french*/"une matine illuminée", /*spanish*/"la melodía refulgente"}, + Text{"a yellow spark trail", /*french*/"une comète jaune", /*spanish*/"el sendero resplandeciente"}, + Text{"the temple traveler", /*french*/"un chant de sanctuaire", /*spanish*/"la ruta del templo"}, + }, { + //ambiguous text + Text{"a warp song", /*french*/"une chanson de téléportation", /*spanish*/"una canción de teletransportación"}, + }, + //clear text + Text{"the Prelude of Light", /*french*/"le prélude de la lumière", /*spanish*/"el Preludio de la luz"} + ); + hintTable[DEKU_TREE_MAP] = HintText::Item({ + //obscure text + Text{"a mossy atlas", /*french*/"un atlas boisé", /*spanish*/"un atlas musgoso"}, + Text{"some mossy blueprints", /*french*/"un plan boisé", /*spanish*/"unos planos musgosos"}, + }, { + //ambiguous text + Text{"a dungeon map", /*french*/"une carte", /*spanish*/"un mapa"}, + }, + //clear text + Text{"the Deku Tree Map", /*french*/"la carte de l'Arbre Mojo", /*spanish*/"el mapa del Gran Árbol Deku"} + ); + hintTable[DODONGOS_CAVERN_MAP] = HintText::Item({ + //obscure text + Text{"a rocky atlas", /*french*/"un atlas rocheux", /*spanish*/"un atlas rocoso"}, + Text{"some rocky blueprints", /*french*/"un plan rocheux", /*spanish*/"unos planos rocosos"}, + }, { + //ambiguous text + Text{"a dungeon map", /*french*/"une carte", /*spanish*/"un mapa"}, + }, + //clear text + Text{"the Dodongo's Cavern Map", /*french*/"la carte de la Caverne Dodongo", /*spanish*/"el mapa de la Cueva de los Dodongos"} + ); + hintTable[JABU_JABUS_BELLY_MAP] = HintText::Item({ + //obscure text + Text{"a fishy atlas", /*french*/"un atlas digéré", /*spanish*/"un atlas digesto"}, + Text{"some fishy blueprints", /*french*/"un plan digéré", /*spanish*/"unos planos digestos"}, + }, { + //ambiguous text + Text{"a dungeon map", /*french*/"une carte", /*spanish*/"un mapa"}, + }, + //clear text + Text{"the Jabu-Jabu's Belly Map", /*french*/"la carte de Jabu-Jabu", /*spanish*/"el mapa de la Tripa de Jabu-Jabu"} + ); + hintTable[FOREST_TEMPLE_MAP] = HintText::Item({ + //obscure text + Text{"a sylvan atlas", /*french*/"un atlas sylvestre", /*spanish*/"un atlas enselvado"}, + Text{"some sylvan blueprints", /*french*/"un plan sylvestre", /*spanish*/"unos planos enselvados"}, + }, { + //ambiguous text + Text{"a dungeon map", /*french*/"une carte", /*spanish*/"un mapa"}, + }, + //clear text + Text{"the Forest Temple Map", /*french*/"la carte du Temple de la Forêt", /*spanish*/"el mapa del Templo del Bosque"} + ); + hintTable[FIRE_TEMPLE_MAP] = HintText::Item({ + //obscure text + Text{"a molten atlas", /*french*/"un atlas fondu", /*spanish*/"un atlas fundido"}, + Text{"some molten blueprints", /*french*/"un plan fondu", /*spanish*/"unos planos fundidos"}, + }, { + //ambiguous text + Text{"a dungeon map", /*french*/"une carte", /*spanish*/"un mapa"}, + }, + //clear text + Text{"the Fire Temple Map", /*french*/"la carte du Temple du Feu", /*spanish*/"el mapa del Templo del Fuego"} + ); + hintTable[WATER_TEMPLE_MAP] = HintText::Item({ + //obscure text + Text{"a wet atlas", /*french*/"un atlas humide", /*spanish*/"un atlas mojado"}, + Text{"some wet blueprints", /*french*/"un plan humide", /*spanish*/"unos planos mojados"}, + }, { + //ambiguous text + Text{"a dungeon map", /*french*/"une carte", /*spanish*/"un mapa"}, + }, + //clear text + Text{"the Water Temple Map", /*french*/"la carte du Temple de l'Eau", /*spanish*/"el mapa del Templo del Agua"} + ); + hintTable[SPIRIT_TEMPLE_MAP] = HintText::Item({ + //obscure text + Text{"a sandy atlas", /*french*/"un atlas sableux", /*spanish*/"un atlas arenoso"}, + Text{"some sandy blueprints", /*french*/"un plan sableux", /*spanish*/"unos planos arenosos"}, + }, { + //ambiguous text + Text{"a dungeon map", /*french*/"une carte", /*spanish*/"un mapa"}, + }, + //clear text + Text{"the Spirit Temple Map", /*french*/"la carte du Temple de l'Esprit", /*spanish*/"el mapa del Templo del Espíritu"} + ); + hintTable[SHADOW_TEMPLE_MAP] = HintText::Item({ + //obscure text + Text{"a creepy atlas", /*french*/"un atlas sinistre", /*spanish*/"un atlas siniestra"}, + Text{"some creepy blueprints", /*french*/"un plan sinistre", /*spanish*/"unos planos siniestras"}, + }, { + //ambiguous text + Text{"a dungeon map", /*french*/"une carte", /*spanish*/"un mapa"}, + }, + //clear text + Text{"the Shadow Temple Map", /*french*/"la carte du Temple de l'Ombre", /*spanish*/"el mapa del Templo de las Sombras"} + ); + hintTable[BOTTOM_OF_THE_WELL_MAP] = HintText::Item({ + //obscure text + Text{"a moldy atlas", /*french*/"un atlas moisi", /*spanish*/"un atlas mohoso"}, + Text{"some moldy blueprints", /*french*/"un plan moisi", /*spanish*/"unos planos mohosos"}, + }, { + //ambiguous text + Text{"a dungeon map", /*french*/"une carte", /*spanish*/"un mapa"}, + }, + //clear text + Text{"the Bottom of the Well Map", /*french*/"la carte du fond du Puits", /*spanish*/"el mapa del Fondo del pozo"} + ); + hintTable[ICE_CAVERN_MAP] = HintText::Item({ + //obscure text + Text{"a polar atlas", /*french*/"un atlas polaire", /*spanish*/"un atlas polar"}, + Text{"some polar blueprints", /*french*/"un plan polaire", /*spanish*/"unos planos polars"}, + }, { + //ambiguous text + Text{"a dungeon map", /*french*/"une carte", /*spanish*/"un mapa"}, + }, + //clear text + Text{"the Ice Cavern Map", /*french*/"la carte de la Caverne Polaire", /*spanish*/"el mapa de la Caverna de hielo"} + ); + hintTable[DEKU_TREE_COMPASS] = HintText::Item({ + //obscure text + Text{"a mossy treasure tracker", /*french*/"un cherche-trésor boisé", /*spanish*/"un zahorí musgoso"}, + Text{"a mossy magnetic needle", /*french*/"une aimant boisée", /*spanish*/"un imán musgoso"}, + }, { + //ambiguous text + Text{"a compass", /*french*/"une boussole", /*spanish*/"una brújula"}, + }, + //clear text + Text{"the Deku Tree Compass", /*french*/"la boussole de l'Arbre Mojo", /*spanish*/"la brújula del Gran Árbol Deku"} + ); + hintTable[DODONGOS_CAVERN_COMPASS] = HintText::Item({ + //obscure text + Text{"a rocky treasure tracker", /*french*/"un cherche-trésor rocheux", /*spanish*/"un zahorí rocoso"}, + Text{"a rocky magnetic needle", /*french*/"une aimant rocheux", /*spanish*/"un imán rocoso"}, + }, { + //ambiguous text + Text{"a compass", /*french*/"une boussole", /*spanish*/"una brújula"}, + }, + //clear text + Text{"the Dodongo's Cavern Compass", /*french*/"la boussole de la Caverne Dodongo", /*spanish*/"la brújula de la Cueva de los Dodongos"} + ); + hintTable[JABU_JABUS_BELLY_COMPASS] = HintText::Item({ + //obscure text + Text{"a fishy treasure tracker", /*french*/"un cherche-trésor digéré", /*spanish*/"un zahorí digesto"}, + Text{"a fishy magnetic needle", /*french*/"une aimant digéré", /*spanish*/"un imán digesto"}, + }, { + //ambiguous text + Text{"a compass", /*french*/"une boussole", /*spanish*/"una brújula"}, + }, + //clear text + Text{"the Jabu-Jabu's Belly Compass", /*french*/"la boussole de Jabu-Jabu", /*spanish*/"la brújula de la Tripa de Jabu-Jabu"} + ); + hintTable[FOREST_TEMPLE_COMPASS] = HintText::Item({ + //obscure text + Text{"a sylvan treasure tracker", /*french*/"un cherche-trésor sylvestre", /*spanish*/"un zahorí enselvado"}, + Text{"a sylvan magnetic needle", /*french*/"une aimant sylvestre", /*spanish*/"un imán enselvado"}, + }, { + //ambiguous text + Text{"a compass", /*french*/"une boussole", /*spanish*/"una brújula"}, + }, + //clear text + Text{"the Forest Temple Compass", /*french*/"la boussole du Temple de la Forêt", /*spanish*/"la brújula del Templo del Bosque"} + ); + hintTable[FIRE_TEMPLE_COMPASS] = HintText::Item({ + //obscure text + Text{"a molten treasure tracker", /*french*/"un cherche-trésor fondu", /*spanish*/"un zahorí fundido"}, + Text{"a molten magnetic needle", /*french*/"une aimant fondu", /*spanish*/"un imán fundido"}, + }, { + //ambiguous text + Text{"a compass", /*french*/"une boussole", /*spanish*/"una brújula"}, + }, + //clear text + Text{"the Fire Temple Compass", /*french*/"la boussole du Temple du Feu", /*spanish*/"la brújula del Templo del Fuego"} + ); + hintTable[WATER_TEMPLE_COMPASS] = HintText::Item({ + //obscure text + Text{"a wet treasure tracker", /*french*/"un cherche-trésor humide", /*spanish*/"un zahorí mojado"}, + Text{"a wet magnetic needle", /*french*/"une aimant humide", /*spanish*/"un imán mojado"}, + }, { + //ambiguous text + Text{"a compass", /*french*/"une boussole", /*spanish*/"una brújula"}, + }, + //clear text + Text{"the Water Temple Compass", /*french*/"la boussole du Temple de l'Eau", /*spanish*/"la brújula del Templo del Agua"} + ); + hintTable[SPIRIT_TEMPLE_COMPASS] = HintText::Item({ + //obscure text + Text{"a sandy treasure tracker", /*french*/"un cherche-trésor sableux", /*spanish*/"un zahorí arenoso"}, + Text{"a sandy magnetic needle", /*french*/"une aimant sableux", /*spanish*/"un imán arenoso"}, + }, { + //ambiguous text + Text{"a compass", /*french*/"une boussole", /*spanish*/"una brújula"}, + }, + //clear text + Text{"the Spirit Temple Compass", /*french*/"la boussole du Temple de l'Esprit", /*spanish*/"la brújula del Templo del Espíritu"} + ); + hintTable[SHADOW_TEMPLE_COMPASS] = HintText::Item({ + //obscure text + Text{"a creepy treasure tracker", /*french*/"un cherche-trésor sinistre", /*spanish*/"un zahorí siniestra"}, + Text{"a creepy magnetic needle", /*french*/"une aimant sinistre", /*spanish*/"un imán siniestra"}, + }, { + //ambiguous text + Text{"a compass", /*french*/"une boussole", /*spanish*/"una brújula"}, + }, + //clear text + Text{"the Shadow Temple Compass", /*french*/"la boussole du Temple de l'Ombre", /*spanish*/"la brújula del Templo de las Sombras"} + ); + hintTable[BOTTOM_OF_THE_WELL_COMPASS] = HintText::Item({ + //obscure text + Text{"a dank treasure tracker", /*french*/"un cherche-trésor moisi", /*spanish*/"un zahorí mohoso"}, + Text{"a dank magnetic needle", /*french*/"une aimant moisi", /*spanish*/"un imán mohoso"}, + }, { + //ambiguous text + Text{"a compass", /*french*/"une boussole", /*spanish*/"una brújula"}, + }, + //clear text + Text{"the Bottom of the Well Compass", /*french*/"la boussole du fond du Puits", /*spanish*/"la brújula del Fondo del pozo"} + ); + hintTable[ICE_CAVERN_COMPASS] = HintText::Item({ + //obscure text + Text{"a polar treasure tracker", /*french*/"un cherche-trésor polaire", /*spanish*/"un zahorí polar"}, + Text{"a polar magnetic needle", /*french*/"une aimant polaire", /*spanish*/"un imán polar"}, + }, { + //ambiguous text + Text{"a compass", /*french*/"une boussole", /*spanish*/"una brújula"}, + }, + //clear text + Text{"the Ice Cavern Compass", /*french*/"la Boussole de la Caverne Polaire", /*spanish*/"la brújula de la Caverna de hielo"} + ); + hintTable[FOREST_TEMPLE_BOSS_KEY] = HintText::Item({ + //obscure text + Text{"a sylvan master of unlocking", /*french*/"un anti-grosse porte sylvestre", /*spanish*/"la clave enselvada de un jefe"}, + Text{"a sylvan dungeon's master pass", /*french*/"une clé maléfique sylvestree", /*spanish*/"el pase maestro enselvado"}, + }, { + //ambiguous text + Text{"a boss key", /*french*/"une Clé d'Or", /*spanish*/"una gran llave"}, + }, + //clear text + Text{"the Forest Temple Boss Key", /*french*/"la Clé d'Or du Temple de la Forêt", /*spanish*/"la gran llave del Templo del Bosque"} + ); + hintTable[FIRE_TEMPLE_BOSS_KEY] = HintText::Item({ + //obscure text + Text{"a molten master of unlocking", /*french*/"un anti-grosse porte fondu", /*spanish*/"la clave fundido de un jefe"}, + Text{"a molten dungeon's master pass", /*french*/"une clé maléfique fondu", /*spanish*/"el pase maestro fundido"}, + }, { + //ambiguous text + Text{"a boss key", /*french*/"une Clé d'Or", /*spanish*/"una gran llave"}, + }, + //clear text + Text{"the Fire Temple Boss Key", /*french*/"la Clé d'Or du Temple du Feu", /*spanish*/"la gran llave del Templo del Fuego"} + ); + hintTable[WATER_TEMPLE_BOSS_KEY] = HintText::Item({ + //obscure text + Text{"a wet master of unlocking", /*french*/"un anti-grosse porte humide", /*spanish*/"la clave mojado de un jefe"}, + Text{"a wet dungeon's master pass", /*french*/"une clé maléfique humide", /*spanish*/"el pase maestro mojado"}, + }, { + //ambiguous text + Text{"a boss key", /*french*/"une Clé d'Or", /*spanish*/"una gran llave"}, + }, + //clear text + Text{"the Water Temple Boss Key", /*french*/"la Clé d'Or du Temple de l'Eau", /*spanish*/"la gran llave del Templo del Agua"} + ); + hintTable[SPIRIT_TEMPLE_BOSS_KEY] = HintText::Item({ + //obscure text + Text{"a sandy master of unlocking", /*french*/"un anti-grosse porte sableux", /*spanish*/"la clave arenoso de un jefe"}, + Text{"a sandy dungeon's master pass", /*french*/"une clé maléfique sableux", /*spanish*/"el pase maestro arenoso"}, + }, { + //ambiguous text + Text{"a boss key", /*french*/"une Clé d'Or", /*spanish*/"una gran llave"}, + }, + //clear text + Text{"the Spirit Temple Boss Key", /*french*/"la Clé d'Or du Temple de l'Esprit", /*spanish*/"la gran llave del Templo del Espíritu"} + ); + hintTable[SHADOW_TEMPLE_BOSS_KEY] = HintText::Item({ + //obscure text + Text{"a creepy master of unlocking", /*french*/"un anti-grosse porte sinistre", /*spanish*/"la clave siniestra de un jefe"}, + Text{"a creepy dungeon's master pass", /*french*/"une clé maléfique sinistre", /*spanish*/"el pase maestro siniestra"}, + }, { + //ambiguous text + Text{"a boss key", /*french*/"une Clé d'Or", /*spanish*/"una gran llave"}, + }, + //clear text + Text{"the Shadow Temple Boss Key", /*french*/"la Clé d'Or du Temple de l'Ombre", /*spanish*/"la gran llave del Templo de las Sombras"} + ); + hintTable[GANONS_CASTLE_BOSS_KEY] = HintText::Item({ + //obscure text + Text{"a final master of unlocking", /*french*/"un anti-grosse porte final", /*spanish*/"la clave final de un jefe"}, + Text{"a final dungeon's master pass", /*french*/"une clé maléfique final", /*spanish*/"el pase maestro final"}, + }, { + //ambiguous text + Text{"a boss key", /*french*/"une Clé d'Or", /*spanish*/"una gran llave"}, + }, + //clear text + Text{"the Ganon's Castle Boss Key", /*french*/"la Clé d'Or du Château de Ganon", /*spanish*/"la gran llave del Castillo de Ganon"} + ); + hintTable[FOREST_TEMPLE_SMALL_KEY] = HintText::Item({ + //obscure text + Text{"a sylvan tool for unlocking", /*french*/"un anti-porte sylvestre", /*spanish*/"una clave de una entrada enselvada"}, + Text{"a sylvan dungeon pass", /*french*/"le rêve sylvestre d'un prisonnier", /*spanish*/"un pase de una mazmorra enselvada"}, + Text{"a sylvan lock remover", /*french*/"un efface-serrure sylvestre", /*spanish*/"un destructor de cerraduras enselvada"}, + Text{"a sylvan lockpick", /*french*/"un crochet à porte sylvestre", /*spanish*/"una apertura portentosa enselvada"}, + }, { + //ambiguous text + Text{"a small key", /*french*/"une petite clé", /*spanish*/"una llave pequeña"}, + }, + //clear text + Text{"a Forest Temple Small Key", /*french*/"une petite clé du Temple de la Forêt", /*spanish*/"una llave pequeña del Templo del Bosque"} + ); + hintTable[FIRE_TEMPLE_SMALL_KEY] = HintText::Item({ + //obscure text + Text{"a molten tool for unlocking", /*french*/"un anti-porte fondu", /*spanish*/"una clave de una entrada fundida"}, + Text{"a molten dungeon pass", /*french*/"le rêve fondu d'un prisonnier", /*spanish*/"un pase de una mazmorra fundida"}, + Text{"a molten lock remover", /*french*/"un efface-serrure fondu", /*spanish*/"un destructor de cerraduras fundida"}, + Text{"a molten lockpick", /*french*/"un crochet à porte fondu", /*spanish*/"una apertura portentosa fundida"}, + }, { + //ambiguous text + Text{"a small key", /*french*/"une petite clé", /*spanish*/"una llave pequeña"}, + }, + //clear text + Text{"a Fire Temple Small Key", /*french*/"une petite clé du Temple du Feu", /*spanish*/"una llave pequeña del Templo del Fuego"} + ); + hintTable[WATER_TEMPLE_SMALL_KEY] = HintText::Item({ + //obscure text + Text{"a wet tool for unlocking", /*french*/"un anti-porte humide", /*spanish*/"una clave de una entrada mojada"}, + Text{"a wet dungeon pass", /*french*/"le rêve humide d'un prisonnier", /*spanish*/"un pase de una mazmorra mojada"}, + Text{"a wet lock remover", /*french*/"un efface-serrure humide", /*spanish*/"un destructor de cerraduras mojada"}, + Text{"a wet lockpick", /*french*/"un crochet à porte humide", /*spanish*/"una apertura portentosa mojada"}, + }, { + //ambiguous text + Text{"a small key", /*french*/"une petite clé", /*spanish*/"una llave pequeña"}, + }, + //clear text + Text{"a Water Temple Small Key", /*french*/"une petite clé du Temple de l'Eau", /*spanish*/"una llave pequeña del Templo del Agua"} + ); + hintTable[SPIRIT_TEMPLE_SMALL_KEY] = HintText::Item({ + //obscure text + Text{"a sandy tool for unlocking", /*french*/"un anti-porte sableux", /*spanish*/"una clave de una entrada arenosa"}, + Text{"a sandy dungeon pass", /*french*/"le rêve sableux d'un prisonnier", /*spanish*/"un pase de una mazmorra arenosa"}, + Text{"a sandy lock remover", /*french*/"un efface-serrure sableux", /*spanish*/"un destructor de cerraduras arenosa"}, + Text{"a sandy lockpick", /*french*/"un crochet à porte sableux", /*spanish*/"una apertura portentosa arenosa"}, + }, { + //ambiguous text + Text{"a small key", /*french*/"une petite clé", /*spanish*/"una llave pequeña"}, + }, + //clear text + Text{"a Spirit Temple Small Key", /*french*/"une petite clé du Temple de l'Esprit", /*spanish*/"una llave pequeña del Templo del Espíritu"} + ); + hintTable[SHADOW_TEMPLE_SMALL_KEY] = HintText::Item({ + //obscure text + Text{"a creepy tool for unlocking", /*french*/"un anti-porte sinistre", /*spanish*/"una clave de una entrada siniestra:a"}, + Text{"a creepy dungeon pass", /*french*/"le rêve sinistre d'un prisonnier", /*spanish*/"un pase de una mazmorra siniestra:a"}, + Text{"a creepy lock remover", /*french*/"un efface-serrure sinistre", /*spanish*/"un destructor de cerraduras siniestra:a"}, + Text{"a creepy lockpick", /*french*/"un crochet à porte sinistre", /*spanish*/"una apertura portentosa siniestra:a"}, + }, { + //ambiguous text + Text{"a small key", /*french*/"une petite clé", /*spanish*/"una llave pequeña"}, + }, + //clear text + Text{"a Shadow Temple Small Key", /*french*/"une petite clé du Temple de l'Ombre", /*spanish*/"una llave pequeña del Templo de las Sombras"} + ); + hintTable[GERUDO_TRAINING_GROUNDS_SMALL_KEY] = HintText::Item({ + //obscure text + Text{"a labyrinthian tool for unlocking", /*french*/"un anti-porte labyrinthique", /*spanish*/"una clave de una entrada laberíntica"}, + Text{"a labyrinthian dungeon pass", /*french*/"le rêve labyrinthique d'un prisonnier", /*spanish*/"un pase de una mazmorra laberíntica"}, + Text{"a labyrinthian lock remover", /*french*/"un efface-serrure labyrinthique", /*spanish*/"un destructor de cerraduras laberíntica"}, + Text{"a labyrinthian lockpick", /*french*/"un crochet à porte labyrinthique", /*spanish*/"una apertura portentosa laberíntica"}, + }, { + //ambiguous text + Text{"a small key", /*french*/"une petite clé", /*spanish*/"una llave pequeña"}, + }, + //clear text + Text{"a Gerudo Training Ground Small Key", /*french*/"une petite clé du Gymnase Gerudo", /*spanish*/"una llave pequeña del Centro de Instrucción Gerudo"} + ); + hintTable[GERUDO_FORTRESS_SMALL_KEY] = HintText::Item({ + //obscure text + Text{"an imprisoned tool for unlocking", /*french*/"un anti-porte emprisonné", /*spanish*/"una clave de una entrada encarcelada"}, + Text{"an imprisoned dungeon pass", /*french*/"le rêve emprisonné d'un prisonnier", /*spanish*/"un pase de una mazmorra encarcelada"}, + Text{"an imprisoned lock remover", /*french*/"un efface-serrure emprisonné", /*spanish*/"un destructor de cerraduras encarcelada"}, + Text{"an imprisoned lockpick", /*french*/"un crochet à porte emprisonné", /*spanish*/"una apertura portentosa encarcelada"}, + }, { + //ambiguous text + Text{"a small key", /*french*/"une petite clé", /*spanish*/"una llave pequeña"}, + }, + //clear text + Text{"a Gerudo Fortress Small Key", /*french*/"une petite clé de la Repaire des Voleurs", /*spanish*/"una llave pequeña de la Fortaleza Gerudo"} + ); + hintTable[BOTTOM_OF_THE_WELL_SMALL_KEY] = HintText::Item({ + //obscure text + Text{"a moldy tool for unlocking", /*french*/"un anti-porte moisi", /*spanish*/"una clave de una entrada mohosa"}, + Text{"a moldy dungeon pass", /*french*/"le rêve moisi d'un prisonnier", /*spanish*/"un pase de una mazmorra mohosa"}, + Text{"a moldy lock remover", /*french*/"un efface-serrure moisi", /*spanish*/"un destructor de cerraduras mohosa"}, + Text{"a moldy lockpick", /*french*/"un crochet à porte moisi", /*spanish*/"una apertura portentosa mohosa"}, + }, { + //ambiguous text + Text{"a small key", /*french*/"une petite clé", /*spanish*/"una llave pequeña"}, + }, + //clear text + Text{"a Bottom of the Well Small Key", /*french*/"une petite clé du fond du Puits", /*spanish*/"una llave pequeña del Fondo del pozo"} + ); + hintTable[GANONS_CASTLE_SMALL_KEY] = HintText::Item({ + //obscure text + Text{"a final tool for unlocking", /*french*/"un anti-porte final", /*spanish*/"una clave de una entrada final"}, + Text{"a final dungeon pass", /*french*/"le rêve final d'un prisonnier", /*spanish*/"un pase de una mazmorra final"}, + Text{"a final lock remover", /*french*/"un efface-serrure final", /*spanish*/"un destructor de cerraduras final"}, + Text{"a final lockpick", /*french*/"un crochet à porte final", /*spanish*/"una apertura portentosa final"}, + }, { + //ambiguous text + Text{"a small key", /*french*/"une petite clé", /*spanish*/"una llave pequeña"}, + }, + //clear text + Text{"a Ganon's Castle Small Key", /*french*/"une petite clé du Château de Ganon", /*spanish*/"una llave pequeña del Castillo de Ganon"} + ); + hintTable[FOREST_TEMPLE_KEY_RING] = HintText::Item({ + //obscure text + Text{"a sylvan toolbox for unlocking", /*french*/"des anti-portes sylvestres", /*spanish*/"un conjunto silvestre de cerrajero"}, + Text{"a sylvan dungeon season pass", /*french*/"les rêves sylvestres d'un prisonnier", /*spanish*/"un pase vip de mazmorras silvestre"}, + Text{"a sylvan jingling ring", /*french*/"des efface-serrures sylvestres", /*spanish*/"una cadena multiusos silvestre"}, + Text{"a sylvan skeleton key", /*french*/"des crochets à porte sylvestres", /*spanish*/"un anillo silvestre contra cerrojos"}, + }, { + //ambiguous text + Text{"a key ring", /*french*/"un trousseau de clés", /*spanish*/"un llavero"}, + }, + //clear text + Text{"a Forest Temple Key Ring", /*french*/"un trousseau de clés du Temple de la Forêt", /*spanish*/"un llavero del Templo del Bosque"} + ); + hintTable[FIRE_TEMPLE_KEY_RING] = HintText::Item({ + //obscure text + Text{"a molten toolbox for unlocking", /*french*/"des anti-portes fondus", /*spanish*/"un conjunto fundido de cerrajero"}, + Text{"a molten dungeon season pass", /*french*/"les rêves fondus d'un prisonnier", /*spanish*/"un pase vip de mazmorras fundido"}, + Text{"a molten jingling ring", /*french*/"des efface-serrures fondus", /*spanish*/"una cadena multiusos fundida"}, + Text{"a molten skeleton key", /*french*/"des crochets à porte fondus", /*spanish*/"un anillo fundido contra cerrojos"}, + }, { + //ambiguous text + Text{"a key ring", /*french*/"un trousseau de clés", /*spanish*/"un llavero"}, + }, + //clear text + Text{"a Fire Temple Key Ring", /*french*/"un trousseau de clés du Temple du Feu", /*spanish*/"un llavero del Templo del Fuego"} + ); + hintTable[WATER_TEMPLE_KEY_RING] = HintText::Item({ + //obscure text + Text{"a wet toolbox for unlocking", /*french*/"des anti-portes humides", /*spanish*/"un conjunto abisal de cerrajero"}, + Text{"a wet dungeon season pass", /*french*/"les rêves humides d'un prisonnier", /*spanish*/"un pase vip de mazmorras abisal"}, + Text{"a wet jingling ring", /*french*/"des efface-serrures humides", /*spanish*/"una cadena multiusos abisal"}, + Text{"a wet skeleton key", /*french*/"des crochets à porte humides", /*spanish*/"un anillo abisal contra cerrojos"}, + }, { + //ambiguous text + Text{"a key ring", /*french*/"un trousseau de clés", /*spanish*/"un llavero"}, + }, + //clear text + Text{"a Water Temple Key Ring", /*french*/"un trousseau de clés du Temple de l'Eau", /*spanish*/"un llavero del Templo del Agua"} + ); + hintTable[SPIRIT_TEMPLE_KEY_RING] = HintText::Item({ + //obscure text + Text{"a sandy toolbox for unlocking", /*french*/"des anti-portes sableux", /*spanish*/"un conjunto arenoso de cerrajero"}, + Text{"a sandy dungeon season pass", /*french*/"les rêves sableux d'un prisonnier", /*spanish*/"un pase vip de mazmorras arenoso"}, + Text{"a sandy jingling ring", /*french*/"des efface-serrures sableux", /*spanish*/"una cadena multiusos arenosa"}, + Text{"a sandy skeleton key", /*french*/"des crochets à porte sableux", /*spanish*/"un anillo arenoso contra cerrojos"}, + }, { + //ambiguous text + Text{"a key ring", /*french*/"un trousseau de clés", /*spanish*/"un llavero"}, + }, + //clear text + Text{"a Spirit Temple Key Ring", /*french*/"un trousseau de clés du Temple de l'Esprit", /*spanish*/"un llavero del Templo del Espíritu"} + ); + hintTable[SHADOW_TEMPLE_KEY_RING] = HintText::Item({ + //obscure text + Text{"a creepy toolbox for unlocking", /*french*/"des anti-portes sinistres", /*spanish*/"un conjunto tenebroso de cerrajero"}, + Text{"a creepy dungeon season pass", /*french*/"les rêves sinistres d'un prisonnier", /*spanish*/"un pase vip de mazmorras tenebroso"}, + Text{"a creepy jingling ring", /*french*/"des efface-serrures sinistres", /*spanish*/"una cadena multiusos tenebrosa"}, + Text{"a creepy skeleton key", /*french*/"des crochets à porte sinistres", /*spanish*/"un anillo tenebroso contra cerrojos"}, + }, { + //ambiguous text + Text{"a key ring", /*french*/"un trousseau de clés", /*spanish*/"un llavero"}, + }, + //clear text + Text{"a Shadow Temple Key Ring", /*french*/"un trousseau de clés du Temple de l'Ombre", /*spanish*/"un llavero del Templo de las Sombras"} + ); + hintTable[GERUDO_TRAINING_GROUNDS_KEY_RING] = HintText::Item({ + //obscure text + Text{"a labyrinthian toolbox for unlocking", /*french*/"des anti-portes labyrinthiques", /*spanish*/"un conjunto laberíntico de cerrajero"}, + Text{"a labyrinthian dungeon season pass", /*french*/"les rêves labyrinthiques d'un prisonnier", /*spanish*/"un pase vip de mazmorras laberíntico"}, + Text{"a labyrinthian jingling ring", /*french*/"des efface-serrures labyrinthiques", /*spanish*/"una cadena multiusos laberíntica"}, + Text{"a labyrinthian skeleton key", /*french*/"des crochets à porte labyrinthiques", /*spanish*/"un anillo laberíntico contra cerrojos"}, + }, { + //ambiguous text + Text{"a key ring", /*french*/"un trousseau de clés", /*spanish*/"un llavero"}, + }, + //clear text + Text{"a Gerudo Training Ground Key Ring", /*french*/"un trousseau de clés du Gymnase Gerudo", /*spanish*/"un llavero del Centro de Instrucción Gerudo"} + ); + hintTable[GERUDO_FORTRESS_KEY_RING] = HintText::Item({ + //obscure text + Text{"an imprisoned toolbox for unlocking", /*french*/"des anti-portes emprisonnés", /*spanish*/"un conjunto enjaulado de cerrajero"}, + Text{"an imprisoned dungeon season pass", /*french*/"les rêves emprisonnés d'un prisonnier", /*spanish*/"un pase vip de una mazmorra enjaulado"}, + Text{"an imprisoned jingling ring", /*french*/"des efface-serrures emprisonnés", /*spanish*/"una cadena multiusos enjaulada"}, + Text{"an imprisoned skeleton key", /*french*/"des crochets à porte emprisonnés", /*spanish*/"un anillo enjaulado contra cerrojos"}, + }, { + //ambiguous text + Text{"a key ring", /*french*/"un trousseau de clés", /*spanish*/"un llavero"}, + }, + //clear text + Text{"a Gerudo Fortress Key Ring", /*french*/"un trousseau de clés de la Repaire des Voleurs", /*spanish*/"un llavero de la Fortaleza Gerudo"} + ); + hintTable[BOTTOM_OF_THE_WELL_KEY_RING] = HintText::Item({ + //obscure text + Text{"a moldy toolbox for unlocking", /*french*/"des anti-portes moisis", /*spanish*/"un conjunto subterráneo de cerrajero"}, + Text{"a moldy dungeon season pass", /*french*/"les rêves moisis d'un prisonnier", /*spanish*/"un pase vip de una mazmorra subterráneo"}, + Text{"a moldy jingling ring", /*french*/"des efface-serrures moisis", /*spanish*/"una cadena multiusos subterránea"}, + Text{"a moldy skeleton key", /*french*/"des crochets à porte moisis", /*spanish*/"un anillo subterráneo contra cerrojos"}, + }, { + //ambiguous text + Text{"a key ring", /*french*/"un trousseau de clés", /*spanish*/"un llavero"}, + }, + //clear text + Text{"a Bottom of the Well Key Ring", /*french*/"un trousseau de clés du fond du Puits", /*spanish*/"un llavero del Fondo del pozo"} + ); + hintTable[GANONS_CASTLE_KEY_RING] = HintText::Item({ + //obscure text + Text{"a final toolbox for unlocking", /*french*/"des anti-portes finaux", /*spanish*/"un conjunto decisivo de cerrajero"}, + Text{"a final dungeon season pass", /*french*/"les rêves finaux d'un prisonnier", /*spanish*/"un pase vip de una mazmorra decisivo"}, + Text{"a final jingling ring", /*french*/"des efface-serrures finaux", /*spanish*/"una cadena multiusos decisiva"}, + Text{"a final skeleton key", /*french*/"des crochets à porte finaux", /*spanish*/"un anillo decisivo multiusos"}, + }, { + //ambiguous text + Text{"a key ring", /*french*/"un trousseau de clés", /*spanish*/"un llavero"}, + }, + //clear text + Text{"a Ganon's Castle Key Ring", /*french*/"un trousseau de clés du Château de Ganon", /*spanish*/"un llavero del Castillo de Ganon"} + ); + + hintTable[TREASURE_GAME_SMALL_KEY] = HintText::Item({ + //obscure text + Text{"a gambler's tool for unlocking", /*french*/"un anti-porte de parieur", /*spanish*/"una clave de un juego de azar"}, + Text{"a gambler's dungeon pass", /*french*/"le rêve d'un prisonnier parieur", /*spanish*/"un pase de un juego de azar"}, + Text{"a gambler's lock remover", /*french*/"un efface-serrure de parieur", /*spanish*/"un destructor de cerraduras del juego de azar"}, + Text{"a gambler's lockpick", /*french*/"un crochet à serrure de parieur", /*spanish*/"una apertura portentosa del juego de azar"}, + }, { + //ambiguous text + Text{"a small key", /*french*/"une petite clé", /*spanish*/"una llave pequeña"}, + }, + //clear text + Text{"a Treasure Chest Shop Small Key", /*french*/"une petite clé de la chasse aux trésors", /*spanish*/"una llave pequeña del Cofre del Tesoro"} + ); + + hintTable[KOKIRI_EMERALD] = HintText::Item({ + //obscure text + Text{"a green stone", /*french*/"une pierre verte", /*spanish*/"una piedra verde"}, + Text{"a gift before death", /*french*/"le dernier souffle d'un arbre", /*spanish*/"un obsequio testamentario"}, + }, { + //ambiguous text + Text{"a spiritual stone", /*french*/"une Pierre Ancestrale", /*spanish*/"una piedra espiritual"}, + }, + //clear text + Text{"the Kokiri Emerald", /*french*/"l'Émeraude Kokiri", /*spanish*/"la Esmeralda de los Kokiri"} + ); + + hintTable[GORON_RUBY] = HintText::Item({ + //obscure text + Text{"a red stone", /*french*/"une pierre rouge", /*spanish*/"una piedra carmín"}, + Text{"sworn brotherhood", /*french*/"un serment de fraternité", /*spanish*/"el juramento de hermanos de sangre"}, + }, { + //ambiguous text + Text{"a spiritual stone", /*french*/"une Pierre Ancestrale", /*spanish*/"una piedra espiritual"}, + }, + //clear text + Text{"the Goron Ruby", /*french*/"le Rubis Goron", /*spanish*/"el Rubí de los Goron"} + ); + + hintTable[ZORA_SAPPHIRE] = HintText::Item({ + //obscure text + Text{"a blue stone", /*french*/"une pierre bleue", /*spanish*/"una piedra celeste"}, + Text{"an engagement gift", /*french*/"un cadeau de mariage", /*spanish*/"un regalo de compromiso"}, + }, { + //ambiguous text + Text{"a spiritual stone", /*french*/"une Pierre Ancestrale", /*spanish*/"una piedra espiritual"}, + }, + //clear text + Text{"the Zora Sapphire", /*french*/"le Saphir Zora", /*spanish*/"el Zafiro de los Zora"} + ); + + hintTable[FOREST_MEDALLION] = HintText::Item({ + //obscure text + Text{"a green coin", /*french*/"une pièce verte", /*spanish*/"una moneda esmeralda"}, + Text{"Saria's friendship", /*french*/"l'amitié de Saria", /*spanish*/"la amistad de Saria"}, + }, { + //ambiguous text + Text{"a medallion", /*french*/"un médaillon", /*spanish*/"un medallón"}, + }, + //clear text + Text{"the Forest Medallion", /*french*/"le Médaillon de la Forêt", /*spanish*/"el Medallón del Bosque"} + ); + + hintTable[FIRE_MEDALLION] = HintText::Item({ + //obscure text + Text{"a red coin", /*french*/"une pièce rouge", /*spanish*/"una moneda rubí"}, + Text{"Darunia's power", /*french*/"la fraternité de Darunia", /*spanish*/"la fraternidad de Darunia"}, + }, { + //ambiguous text + Text{"a medallion", /*french*/"un médaillon", /*spanish*/"un medallón"}, + }, + //clear text + Text{"the Fire Medallion", /*french*/"le Médaillon du Feu", /*spanish*/"el Medallón del Fuego"} + ); + + hintTable[WATER_MEDALLION] = HintText::Item({ + //obscure text + Text{"a blue coin", /*french*/"une pièce bleue", /*spanish*/"una moneda zafiro"}, + Text{"Ruto's power", /*french*/"l'amour de Ruto", /*spanish*/"el amor de Ruto"}, + }, { + //ambiguous text + Text{"a medallion", /*french*/"un médaillon", /*spanish*/"un medallón"}, + }, + //clear text + Text{"the Water Medallion", /*french*/"le Médaillon de l'Eau", /*spanish*/"el Medallón del Agua"} + ); + + hintTable[SPIRIT_MEDALLION] = HintText::Item({ + //obscure text + Text{"an orange coin", /*french*/"une pièce orange", /*spanish*/"una moneda ámbar"}, + Text{"Nabooru's power", /*french*/"le respect de Nabooru", /*spanish*/"el respeto de Nabooru"}, + }, { + //ambiguous text + Text{"a medallion", /*french*/"un médaillon", /*spanish*/"un medallón"}, + }, + //clear text + Text{"the Spirit Medallion", /*french*/"le Médaillon de l'Esprit", /*spanish*/"el Medallón del Espíritu"} + ); + + hintTable[SHADOW_MEDALLION] = HintText::Item({ + //obscure text + Text{"a purple coin", /*french*/"une pièce pourpre", /*spanish*/"una moneda malva"}, + Text{"Impa's power", /*french*/"la confiance d'Impa", /*spanish*/"la confianza de Impa"}, + }, { + //ambiguous text + Text{"a medallion", /*french*/"un médaillon", /*spanish*/"un medallón"}, + }, + //clear text + Text{"the Shadow Medallion", /*french*/"le Médaillon de l'Ombre", /*spanish*/"el Medallón de la Sombra"} + ); + + hintTable[LIGHT_MEDALLION] = HintText::Item({ + //obscure text + Text{"a yellow coin", /*french*/"une pièce jaune", /*spanish*/"una moneda resplandeciente"}, + Text{"Rauru's power", /*french*/"la foi de Rauru", /*spanish*/"la fe de Rauru"}, + }, { + //ambiguous text + Text{"a medallion", /*french*/"un médaillon", /*spanish*/"un medallón"}, + }, + //clear text + Text{"the Light Medallion", /*french*/"le Médaillon de la Lumière", /*spanish*/"el Medallón de la Luz"} + ); + + hintTable[RECOVERY_HEART] = HintText::Item({ + //obscure text + Text{"a free heal", /*french*/"un bec-au-bobo", /*spanish*/"una cura de regalo"}, + Text{"a hearty meal", /*french*/"un petit amour", /*spanish*/"una sanación romántica"}, + Text{"a Band-Aid", /*french*/"un diachylon", /*spanish*/"un corazoncito sanador"}, + }, { + //ambiguous text + Text{"something heart-shaped", /*french*/"une chose en forme de coeur", /*spanish*/"algo con forma de corazón"}, + }, + //clear text + Text{"a Recovery Heart", /*french*/"un coeur de vie", /*spanish*/"un corazón"} + ); + + hintTable[GREEN_RUPEE] = HintText::Item({ + //obscure text + Text{"a unique coin", /*french*/"un rubis bien mérité", /*spanish*/"una singular moneda"}, + Text{"a penny", /*french*/"un sou", /*spanish*/"un peso hyliano"}, + Text{"a green gem", /*french*/"un joyau vert", /*spanish*/"una gema verde"}, + }, { + //ambiguous text + Text{"some rupees", /*french*/"une quantité de rubis", /*spanish*/"una cantidad de rupias"}, + }, + //clear text + Text{"a Green Rupee", /*french*/"un rubis vert", /*spanish*/"una rupia verde"} + ); + + hintTable[BLUE_RUPEE] = HintText::Item({ + //obscure text + Text{"a common coin", /*french*/"quelques sous", /*spanish*/"una moneda usual"}, + Text{"a blue gem", /*french*/"un joyau bleu", /*spanish*/"una gema azul"}, + }, { + //ambiguous text + Text{"some rupees", /*french*/"une quantité de rubis", /*spanish*/"una cantidad de rupias"}, + }, + //clear text + Text{"a Blue Rupee", /*french*/"un rubis bleu", /*spanish*/"una rupia azul"} + ); + + hintTable[RED_RUPEE] = HintText::Item({ + //obscure text + Text{"couch cash", /*french*/"un peu de fric", /*spanish*/"una buena moneda"}, + Text{"a red gem", /*french*/"un joyau rouge", /*spanish*/"una gema roja"}, + }, { + //ambiguous text + Text{"some rupees", /*french*/"une quantité de rubis", /*spanish*/"una cantidad de rupias"}, + }, + //clear text + Text{"a Red Rupee", /*french*/"un rubis rouge", /*spanish*/"una rupia roja"} + ); + + hintTable[PURPLE_RUPEE] = HintText::Item({ + //obscure text + Text{"big bucks", /*french*/"plein de fric", /*spanish*/"plata de calidad"}, + Text{"a purple gem", /*french*/"un joyau mauve", /*spanish*/"una gema morada"}, + Text{"wealth", /*french*/"la richesse", /*spanish*/"una buena riqueza"}, + }, { + //ambiguous text + Text{"some rupees", /*french*/"une quantité de rubis", /*spanish*/"una cantidad de rupias"}, + }, + //clear text + Text{"a Purple Rupee", /*french*/"un rubis pourpre", /*spanish*/"una rupia morada"} + ); + + hintTable[HUGE_RUPEE] = HintText::Item({ + //obscure text + Text{"a juicy jackpot", /*french*/"le jackpot", /*spanish*/"el premio gordo"}, + Text{"a yellow gem", /*french*/"un joyau doré", /*spanish*/"una gema amarilla"}, + Text{"a giant gem", /*french*/"un gros joyau", /*spanish*/"una gema descomunal"}, + Text{"great wealth", /*french*/"l'aisance financière", /*spanish*/"dinero a caudales"}, + }, { + //ambiguous text + Text{"some rupees", /*french*/"une quantité de rubis", /*spanish*/"una cantidad de rupias"}, + }, + //clear text + Text{"a Huge Rupee", /*french*/"un énorme rubis", /*spanish*/"una rupia gigante"} + ); + + hintTable[PIECE_OF_HEART] = HintText::Item({ + //obscure text + Text{"a little love", /*french*/"un peu plus d'amour", /*spanish*/"un cuarto de amor"}, + Text{"a broken heart", /*french*/"un coeur brisé", /*spanish*/"un corazón roto"}, + }, { + //ambiguous text + Text{"something heart-shaped", /*french*/"une chose en forme de coeur", /*spanish*/"algo con forma de corazón"}, + }, + //clear text + Text{"a Piece of Heart", /*french*/"un Quart de Coeur", /*spanish*/"una pieza de corazón"} + ); + + hintTable[HEART_CONTAINER] = HintText::Item({ + //obscure text + Text{"a lot of love", /*french*/"le grand amour", /*spanish*/"amor por doquier"}, + Text{"a Valentine's gift", /*french*/"un cadeau de Saint-Valentin", /*spanish*/"un contenedor de afección"}, + Text{"a boss's organ", /*french*/"un organe de monstre", /*spanish*/"los órganos de un jefe"}, + }, { + //ambiguous text + Text{"something heart-shaped", /*french*/"une chose en forme de coeur", /*spanish*/"algo con forma de corazón"}, + }, + //clear text + Text{"a Heart Container", /*french*/"un Réceptacle de Coeur", /*spanish*/"un contenedor de corazón"} + ); + + hintTable[ICE_TRAP] = HintText::Item({ + //obscure text + Text{"a gift from Ganon", /*french*/"un cadeau de Ganon", /*spanish*/"un regalo de Ganon"}, + Text{"a chilling discovery", /*french*/"une frissonante découverte", /*spanish*/"un escalofriante hallazgo"}, + Text{"frosty fun", /*french*/"une engelure", /*spanish*/"una gélida diversión"}, + }, { + //ambiguous text + Text{"a Great Fairy's power", /*french*/"le pouvoir d'une grande fée", /*spanish*/"el poder de una Gran Hada"}, + Text{"a magic arrow", /*french*/"une flèche magique", /*spanish*/"una flecha mágica"}, + Text{"a medallion", /*french*/"un médaillon", /*spanish*/"un medallón"}, + Text{"a spiritual stone", /*french*/"une Pierre Ancestrale", /*spanish*/"una piedra espiritual"}, + Text{"something that can stun", /*french*/"une chose qui peut paralyser", /*spanish*/"algo que pueda paralizar"}, + }, + //clear text + Text{"an Ice Trap", /*french*/"un Piège de Glace", /*spanish*/"una trampa de hielo"} + ); + + //MILK + + hintTable[BOMBS_5] = HintText::Item({ + //obscure text + Text{"a few explosives", /*french*/"une poignée de pétards", /*spanish*/"un par de explosivos"}, + Text{"a few blast balls", /*french*/"une poignée de boules bleues", /*spanish*/"un par de estallidos"}, + }, { + //ambiguous text + Text{"explosives", /*french*/"un paquet d'explosifs", /*spanish*/"un montón de explosivos"}, + }, + //clear text + Text{"Bombs (5 pieces)", /*french*/"une demi-dizaine de bombes", /*spanish*/"unas (5) bombas"} + ); + + hintTable[BOMBS_10] = HintText::Item({ + //obscure text + Text{"some explosives", /*french*/"un paquet de pétards", /*spanish*/"unos cuantos explosivos"}, + Text{"some blast balls", /*french*/"un paquet de boules bleues", /*spanish*/"unos cuantos estallidos"}, + }, { + //ambiguous text + Text{"explosives", /*french*/"un paquet d'explosifs", /*spanish*/"un montón de explosivos"}, + }, + //clear text + Text{"Bombs (10 pieces)", /*french*/"une dizaine de bombes", /*spanish*/"unas (10) bombas"} + ); + + hintTable[BOMBS_20] = HintText::Item({ + //obscure text + Text{"lots-o-explosives", /*french*/"une abondance de pétards", /*spanish*/"un puñado de explosivos"}, + Text{"plenty of blast balls", /*french*/"une abondance de boules bleues", /*spanish*/"bastantes estallidos"}, + }, { + //ambiguous text + Text{"explosives", /*french*/"un paquet d'explosifs", /*spanish*/"un montón de explosivos"}, + }, + //clear text + Text{"Bombs (20 pieces)", /*french*/"une vingtaine de bombes", /*spanish*/"unas (20) bombas"} + ); + + hintTable[BOMBCHU_5] = HintText::Item({ + //obscure text + Text{"a few mice bombs", /*french*/"une poignée de mignons explosifs", /*spanish*/"un par de bombas roedoras"}, + Text{"a few proximity mice", /*french*/"une poignée de jouets à remonter", /*spanish*/"un par de explosivos ratoncitos"}, + Text{"a few wall crawlers", /*french*/"une poignée de rapides grimpeurs", /*spanish*/"un par de trepaparedes"}, + Text{"a few trail blazers", /*french*/"une poignée de zigzags éclatants", /*spanish*/"un par de ratas propulsadas"}, + }, { + //ambiguous text + Text{"a prize of the House of Skulltulas", /*french*/"un prix de la maison des Skulltulas", /*spanish*/"un obsequio de la Casa Skulltula"}, + Text{"explosives", /*french*/"un paquet d'explosifs", /*spanish*/"un montón de explosivos"}, + }, + //clear text + Text{"Bombchus (5 pieces)", /*french*/"une demi-dizaine de Missiles", /*spanish*/"unos (5) bombchus"} + ); + + hintTable[BOMBCHU_10] = HintText::Item({ + //obscure text + Text{"some mice bombs", /*french*/"un paquet de mignons explosifs", /*spanish*/"unas cuantas bombas roedoras"}, + Text{"some proximity mice", /*french*/"un paquet de jouets à remonter", /*spanish*/"unos cuantos explosivos ratoncitos"}, + Text{"some wall crawlers", /*french*/"un paquet de rapides grimpeurs", /*spanish*/"unos cuantos trepaparedes"}, + Text{"some trail blazers", /*french*/"un paquet de zigzags éclatants", /*spanish*/"unas cuantas ratas propulsadas"}, + }, { + //ambiguous text + Text{"a prize of the House of Skulltulas", /*french*/"un prix de la maison des Skulltulas", /*spanish*/"un obsequio de la Casa Skulltula"}, + Text{"explosives", /*french*/"un paquet d'explosifs", /*spanish*/"un montón de explosivos"}, + }, + //clear text + Text{"Bombchus (10 pieces)", /*french*/"une dizaine de Missiles", /*spanish*/"unos (10) bombchus"} + ); + + hintTable[BOMBCHU_20] = HintText::Item({ + //obscure text + Text{"plenty of mice bombs", /*french*/"une abondance de mignons explosifs", /*spanish*/"bastantes bombas roedoras"}, + Text{"plenty of proximity mice", /*french*/"une abondance de jouets à remonter", /*spanish*/"bastantes explosivos ratoncitos"}, + Text{"plenty of wall crawlers", /*french*/"une abondance de rapides grimpeurs", /*spanish*/"bastantes trepaparedes"}, + Text{"plenty of trail blazers", /*french*/"une abondance de zigzags éclatants", /*spanish*/"bastantes ratas propulsadas"}, + }, { + //ambiguous text + Text{"a prize of the House of Skulltulas", /*french*/"un prix de la maison des Skulltulas", /*spanish*/"un obsequio de la Casa Skulltula"}, + Text{"explosives", /*french*/"un paquet d'explosifs", /*spanish*/"un montón de explosivos"}, + }, + //clear text + Text{"Bombchus (20 pieces)", /*french*/"une vingtaine de Missiles", /*spanish*/"unos (20) bombchus"} + ); + + //BOMBCHU_DROP + + hintTable[ARROWS_5] = HintText::Item({ + //obscure text + Text{"a few danger darts", /*french*/"une poignée d'obus", /*spanish*/"un par de peligrosos dardos"}, + Text{"a few sharp shafts", /*french*/"une poignée de piquets", /*spanish*/"un par de puntas afiladas"}, + }, { + //ambiguous text + Text{"a projectile", /*french*/"un projectile", /*spanish*/"un proyectil"}, + }, + //clear text + Text{"Arrows (5 pieces)", /*french*/"une demi-dizaine de flèches", /*spanish*/"unas (5) flechas"} + ); + + hintTable[ARROWS_10] = HintText::Item({ + //obscure text + Text{"some danger darts", /*french*/"un paquet d'obus", /*spanish*/"unos cuantos peligrosos dardos"}, + Text{"some sharp shafts", /*french*/"un paquet de piquets", /*spanish*/"unas cuantas puntas afiladas"}, + }, { + //ambiguous text + Text{"a projectile", /*french*/"un projectile", /*spanish*/"un proyectil"}, + }, + //clear text + Text{"Arrows (10 pieces)", /*french*/"une dizaine de flèches", /*spanish*/"unas (10) flechas"} + ); + + hintTable[ARROWS_30] = HintText::Item({ + //obscure text + Text{"plenty of danger darts", /*french*/"une abondance d'obus", /*spanish*/"bastantes peligrosos dardos"}, + Text{"plenty of sharp shafts", /*french*/"une abondance de piquets", /*spanish*/"bastantes puntas afiladas"}, + }, { + //ambiguous text + Text{"a projectile", /*french*/"un projectile", /*spanish*/"un proyectil"}, + }, + //clear text + Text{"Arrows (30 pieces)", /*french*/"une trentaine de flèches", /*spanish*/"unas (30) flechas"} + ); + + hintTable[DEKU_NUTS_5] = HintText::Item({ + //obscure text + Text{"some nuts", /*french*/"une poignée de noisettes", /*spanish*/"un par de nueces"}, + Text{"some flashbangs", /*french*/"une poignée d'éclats", /*spanish*/"un par de semillas aturdidoras"}, + Text{"some scrub spit", /*french*/"une poignée de crachats Mojo", /*spanish*/"un par de escupitajos deku"}, + }, { + //ambiguous text + Text{"some Deku munitions", /*french*/"un paquet de munitions Mojo", /*spanish*/"un montón de municiones Deku"}, + Text{"something that can stun", /*french*/"une chose qui peut paralyser", /*spanish*/"algo que pueda paralizar"}, + }, + //clear text + Text{"Deku Nuts (5 pieces)", /*french*/"une demi-dizaine de noix Mojo", /*spanish*/"unas (5) nueces deku"} + ); + + hintTable[DEKU_NUTS_10] = HintText::Item({ + //obscure text + Text{"lots-o-nuts", /*french*/"un paquet de noisettes", /*spanish*/"un puñado de nueces"}, + Text{"plenty of flashbangs", /*french*/"un paquet d'éclats", /*spanish*/"unas cuantas semillas aturdidoras"}, + Text{"plenty of scrub spit", /*french*/"un paquet de crachats Mojo", /*spanish*/"unos cuantos escupitajos deku"}, + }, { + //ambiguous text + Text{"some Deku munitions", /*french*/"un paquet de munitions Mojo", /*spanish*/"un montón de municiones Deku"}, + Text{"something that can stun", /*french*/"une chose qui peut paralyser", /*spanish*/"algo que pueda paralizar"}, + }, + //clear text + Text{"Deku Nuts (10 pieces)", /*french*/"une dizaine de noix Mojo", /*spanish*/"unas (10) nueces deku"} + ); + + hintTable[DEKU_SEEDS_30] = HintText::Item({ + //obscure text + Text{"catapult ammo", /*french*/"un paquet de délicieuses munitions", /*spanish*/"un par de munición infantil"}, + Text{"lots-o-seeds", /*french*/"un paquet de germes séchés", /*spanish*/"un puñado de semillas"}, + }, { + //ambiguous text + Text{"a projectile", /*french*/"un projectile", /*spanish*/"un proyectil"}, + Text{"some Deku munitions", /*french*/"un paquet de munitions Mojo", /*spanish*/"un montón de municiones Deku"}, + }, + //clear text + Text{"Deku Seeds (30 pieces)", /*french*/"une trentaine de graines Mojo", /*spanish*/"unas (30) semillas deku"} + ); + + hintTable[DEKU_STICK_1] = HintText::Item({ + //obscure text + Text{"a breakable branch", /*french*/"un bout de bois", /*spanish*/"un pequeño báculo"}, + }, { + //ambiguous text + Text{"some Deku munitions", /*french*/"un paquet de munitions Mojo", /*spanish*/"un montón de municiones Deku"}, + }, + //clear text + Text{"a Deku Stick", /*french*/"un bâton Mojo", /*spanish*/"un palo deku"} + ); + + hintTable[TREASURE_GAME_HEART] = HintText::Item({ + //obscure text + Text{"a victory valentine", /*french*/"un amour gagnant", /*spanish*/"el amor victorioso"}, + }, { + //ambiguous text + Text{"something heart-shaped", /*french*/"une chose en forme de coeur", /*spanish*/"algo con forma de corazón"}, + }, + //clear text + Text{"a Piece of Heart", /*french*/"un Quart de Coeur", /*spanish*/"el amor de la victoria"} + ); + + hintTable[TREASURE_GAME_GREEN_RUPEE] = HintText::Item({ + //obscure text + Text{"the dollar of defeat", /*french*/"le rubis de la défaite", /*spanish*/"el peso de la derrota"}, + }, { + //ambiguous text + Text{"some rupees", /*french*/"une quantité de rubis", /*spanish*/"una cantidad de rupias"}, + }, + //clear text + Text{"a Green Rupee", /*french*/"un rubis vert", /*spanish*/"una rupia verde"} + ); + + hintTable[TRIFORCE_PIECE] = HintText::Item({ + //obscure text + Text{"a triumph fork", /*french*/"la Tribosse", /*spanish*/"un trígono del triunfo"}, + Text{"cheese", /*french*/"du fromage", /*spanish*/"un porción de queso"}, + Text{"a gold fragment", /*french*/"un fragment d'or", /*spanish*/"un fragmento dorado"}, + }, {}, + //clear text + Text{"a Piece of the Triforce", /*french*/"un fragment de la Triforce", /*spanish*/"un fragmento de la Trifuerza"} + ); + + hintTable[EPONA] = HintText::Item({ + //obscure text + Text{"a horse", /*french*/"un fidèle destrier", /*spanish*/"una yegua"}, + Text{"a four legged friend", /*french*/"un puissant animal", /*spanish*/"una amiga cuadrúpeda"}, + }, { + //ambiguous text + Text{"something from Malon", /*french*/"un cadeau de Malon", /*spanish*/"un obsequio de Malon"}, + Text{"a song sung by frogs", /*french*/"une chanson aimée des grenouilles", /*spanish*/"una melodía de ranas"}, + Text{"something to cross a broken bridge", /*french*/"une chose pour traverser un pont brisé", /*spanish*/"algo para cruzar un puente roto"}, + }, + //clear text + Text{"Epona", /*french*/"Epona", /*spanish*/"a Epona"} + ); + + // [HINT_ERROR] = HintText::Item({ + // //obscure text + // Text{"something mysterious", /*french*/"un sacré mystère", /*spanish*/"algo misterioso"}, + // Text{"an unknown treasure", /*french*/"un trésor inconnu", /*spanish*/"un desconocido tesoro"}, + // }, + // //clear text + // Text{"An Error (Please Report This)", /*french*/"une erreur (signaler S.V.P.)", /*spanish*/"un error (repórtelo si es posible)"} + // ); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/hints.cpp b/soh/soh/Enhancements/randomizer/3drando/hints.cpp new file mode 100644 index 000000000..33bd5edf0 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/hints.cpp @@ -0,0 +1,878 @@ +#include "hints.hpp" + +#include "custom_messages.hpp" +#include "dungeon.hpp" +#include "item_location.hpp" +#include "item_pool.hpp" +#include "logic.hpp" +#include "random.hpp" +#include "spoiler_log.hpp" +#include "fill.hpp" +#include "hint_list.hpp" +#include "trial.hpp" +#include "entrance.hpp" +#include "z64item.h" +#include + +using namespace CustomMessages; +using namespace Logic; +using namespace Settings; +using namespace Trial; + +constexpr std::array hintSettingTable{{ + // Useless hints + { + .dungeonsWothLimit = 2, + .dungeonsBarrenLimit = 1, + .namedItemsRequired = false, + .distTable = {{ + {.type = HintType::Trial, .order = 1, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HintType::Always, .order = 2, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HintType::Woth, .order = 3, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HintType::Barren, .order = 4, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HintType::Entrance, .order = 5, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HintType::Sometimes, .order = 6, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HintType::Random, .order = 7, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HintType::Item, .order = 8, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HintType::Song, .order = 9, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HintType::Overworld, .order = 10, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HintType::Dungeon, .order = 11, .weight = 0, .fixed = 0, .copies = 0}, + {.type = HintType::Junk, .order = 12, .weight = 99, .fixed = 0, .copies = 0}, + {.type = HintType::NamedItem, .order = 13, .weight = 0, .fixed = 0, .copies = 0}, + }}, + }, + + // Balanced hints + { + .dungeonsWothLimit = 2, + .dungeonsBarrenLimit = 1, + .namedItemsRequired = true, + .distTable = {{ + {.type = HintType::Trial, .order = 1, .weight = 0, .fixed = 0, .copies = 1}, + {.type = HintType::Always, .order = 2, .weight = 0, .fixed = 0, .copies = 1}, + {.type = HintType::Woth, .order = 3, .weight = 7, .fixed = 0, .copies = 1}, + {.type = HintType::Barren, .order = 4, .weight = 4, .fixed = 0, .copies = 1}, + {.type = HintType::Entrance, .order = 5, .weight = 6, .fixed = 0, .copies = 1}, + {.type = HintType::Sometimes, .order = 6, .weight = 0, .fixed = 0, .copies = 1}, + {.type = HintType::Random, .order = 7, .weight = 12, .fixed = 0, .copies = 1}, + {.type = HintType::Item, .order = 8, .weight = 10, .fixed = 0, .copies = 1}, + {.type = HintType::Song, .order = 9, .weight = 2, .fixed = 0, .copies = 1}, + {.type = HintType::Overworld, .order = 10, .weight = 4, .fixed = 0, .copies = 1}, + {.type = HintType::Dungeon, .order = 11, .weight = 3, .fixed = 0, .copies = 1}, + {.type = HintType::Junk, .order = 12, .weight = 6, .fixed = 0, .copies = 1}, + {.type = HintType::NamedItem, .order = 13, .weight = 0, .fixed = 0, .copies = 1}, + }}, + }, + + // Strong hints + { + .dungeonsWothLimit = 2, + .dungeonsBarrenLimit = 1, + .namedItemsRequired = true, + .distTable = {{ + {.type = HintType::Trial, .order = 1, .weight = 0, .fixed = 0, .copies = 1}, + {.type = HintType::Always, .order = 2, .weight = 0, .fixed = 0, .copies = 2}, + {.type = HintType::Woth, .order = 3, .weight = 12, .fixed = 0, .copies = 2}, + {.type = HintType::Barren, .order = 4, .weight = 12, .fixed = 0, .copies = 1}, + {.type = HintType::Entrance, .order = 5, .weight = 4, .fixed = 0, .copies = 1}, + {.type = HintType::Sometimes, .order = 6, .weight = 0, .fixed = 0, .copies = 1}, + {.type = HintType::Random, .order = 7, .weight = 8, .fixed = 0, .copies = 1}, + {.type = HintType::Item, .order = 8, .weight = 8, .fixed = 0, .copies = 1}, + {.type = HintType::Song, .order = 9, .weight = 4, .fixed = 0, .copies = 1}, + {.type = HintType::Overworld, .order = 10, .weight = 6, .fixed = 0, .copies = 1}, + {.type = HintType::Dungeon, .order = 11, .weight = 6, .fixed = 0, .copies = 1}, + {.type = HintType::Junk, .order = 12, .weight = 0, .fixed = 0, .copies = 1}, + {.type = HintType::NamedItem, .order = 13, .weight = 0, .fixed = 0, .copies = 1}, + }}, + }, + + // Very strong hints + { + .dungeonsWothLimit = 40, + .dungeonsBarrenLimit = 40, + .namedItemsRequired = true, + .distTable = {{ + {.type = HintType::Trial, .order = 1, .weight = 0, .fixed = 0, .copies = 1}, + {.type = HintType::Always, .order = 2, .weight = 0, .fixed = 0, .copies = 2}, + {.type = HintType::Woth, .order = 3, .weight = 15, .fixed = 0, .copies = 2}, + {.type = HintType::Barren, .order = 4, .weight = 15, .fixed = 0, .copies = 1}, + {.type = HintType::Entrance, .order = 5, .weight = 10, .fixed = 0, .copies = 1}, + {.type = HintType::Sometimes, .order = 6, .weight = 0, .fixed = 0, .copies = 1}, + {.type = HintType::Random, .order = 7, .weight = 0, .fixed = 0, .copies = 1}, + {.type = HintType::Item, .order = 8, .weight = 5, .fixed = 0, .copies = 1}, + {.type = HintType::Song, .order = 9, .weight = 2, .fixed = 0, .copies = 1}, + {.type = HintType::Overworld, .order = 10, .weight = 7, .fixed = 0, .copies = 1}, + {.type = HintType::Dungeon, .order = 11, .weight = 7, .fixed = 0, .copies = 1}, + {.type = HintType::Junk, .order = 12, .weight = 0, .fixed = 0, .copies = 1}, + {.type = HintType::NamedItem, .order = 13, .weight = 0, .fixed = 0, .copies = 1}, + }}, + }, +}}; + +std::array dungeonInfoData; + +Text childAltarText; +Text adultAltarText; +Text ganonText; +Text ganonHintText; + +Text& GetChildAltarText() { + return childAltarText; +} + +Text& GetAdultAltarText() { + return adultAltarText; +} + +Text& GetGanonText() { + return ganonText; +} + +Text& GetGanonHintText() { + return ganonHintText; +} + +static Area* GetHintRegion(const uint32_t area) { + + std::vector alreadyChecked = {}; + std::vector spotQueue = {area}; + + while (!spotQueue.empty()) { + uint32_t region = spotQueue.back(); + alreadyChecked.push_back(region); + spotQueue.pop_back(); + + if (AreaTable(region)->hintKey != NONE) { + return AreaTable(region); + } + + //add unchecked entrances to spot queue + bool checked = false; + for (auto& entrance : AreaTable(region)->entrances) { + for (uint32_t checkedEntrance : alreadyChecked) { + if (entrance->GetParentRegionKey() == checkedEntrance) { + checked = true; + break; + } + } + + if (!checked) { + spotQueue.insert(spotQueue.begin(), entrance->GetParentRegionKey()); + } + } + } + + return AreaTable(NONE); +} + +uint32_t GetHintRegionHintKey(const uint32_t area) { + return GetHintRegion(area)->hintKey; +} + +uint32_t GetHintRegionuint32_t(const uint32_t area) { + return GetHintRegion(area)->hintKey; +} + +uint32_t GetLocationRegionuint32_t(const uint32_t location) { + return GetHintRegion(Location(location)->GetParentRegionKey())->hintKey; +} + +static std::vector GetAccessibleGossipStones(const uint32_t hintedLocation = GANON) { + //temporarily remove the hinted location's item, and then perform a + //reachability search for gossip stone locations. + uint32_t originalItem = Location(hintedLocation)->GetPlaceduint32_t(); + Location(hintedLocation)->SetPlacedItem(NONE); + + LogicReset(); + auto accessibleGossipStones = GetAccessibleLocations(gossipStoneLocations); + //Give the item back to the location + Location(hintedLocation)->SetPlacedItem(originalItem); + + return accessibleGossipStones; +} + +static void AddHint(Text hint, const uint32_t gossipStone, const std::vector& colors = {}) { + //save hints as dummy items for writing to the spoiler log + NewItem(gossipStone, Item{hint, ITEMTYPE_EVENT, GI_RUPEE_BLUE_LOSE, false, &noVariable, NONE}); + Location(gossipStone)->SetPlacedItem(gossipStone); + + //create the in game message + // uint32_t messageId = 0x400 + Location(gossipStone)->GetFlag(); + // uint32_t sariaMessageId = 0xA00 + Location(gossipStone)->GetFlag(); + // CreateMessageFromTextObject(messageId, 0, 2, 3, AddColorsAndFormat(hint, colors)); + // CreateMessageFromTextObject(sariaMessageId, 0, 2, 3, AddColorsAndFormat(hint + EVENT_TRIGGER(), colors)); +} + +static void CreateLocationHint(const std::vector& possibleHintLocations) { + //return if there aren't any hintable locations or gossip stones available + if (possibleHintLocations.empty()) { + SPDLOG_INFO("\tNO LOCATIONS TO HINT\n\n"); + return; + } + + uint32_t hintedLocation = RandomElement(possibleHintLocations); + const std::vector accessibleGossipStones = GetAccessibleGossipStones(hintedLocation); + + SPDLOG_INFO("\tLocation: "); + SPDLOG_INFO(Location(hintedLocation)->GetName()); + SPDLOG_INFO("\n"); + + SPDLOG_INFO("\tItem: "); + SPDLOG_INFO(Location(hintedLocation)->GetPlacedItemName().GetEnglish()); + SPDLOG_INFO("\n"); + + if (accessibleGossipStones.empty()) { + SPDLOG_INFO("\tNO GOSSIP STONES TO PLACE HINT\n\n"); + return; + } + + uint32_t gossipStone = RandomElement(accessibleGossipStones); + Location(hintedLocation)->SetAsHinted(); + + //make hint text + Text locationHintText = Location(hintedLocation)->GetHint().GetText(); + Text itemHintText = Location(hintedLocation)->GetPlacedItem().GetHint().GetText(); + Text prefix = Hint(PREFIX).GetText(); + + Text finalHint = prefix + locationHintText + " #"+itemHintText+"#."; + SPDLOG_INFO("\tMessage: "); + SPDLOG_INFO(finalHint.english); + SPDLOG_INFO("\n\n"); + + AddHint(finalHint, gossipStone, {QM_GREEN, QM_RED}); +} + +static void CreateWothHint(uint8_t* remainingDungeonWothHints) { + // get locations that are in the current playthrough + std::vector possibleHintLocations = {}; + // iterate through playthrough locations by sphere + std::vector wothHintLocations = + FilterFromPool(wothLocations, [remainingDungeonWothHints](uint32_t loc) { + return Location(loc)->IsHintable() && // only filter hintable locations + !(Location(loc)->IsHintedAt()) && // only filter locations that haven't been hinted at + (Location(loc)->IsOverworld() || + (Location(loc)->IsDungeon() && + (*remainingDungeonWothHints) > 0)); // make sure we haven't surpassed the woth dungeon limit + }); + AddElementsToPool(possibleHintLocations, wothHintLocations); + + // If no more locations can be hinted at for woth, then just try to get another hint + if (possibleHintLocations.empty()) { + SPDLOG_INFO("\tNO LOCATIONS TO HINT\n\n"); + return; + } + uint32_t hintedLocation = RandomElement(possibleHintLocations); + + SPDLOG_INFO("\tLocation: "); + SPDLOG_INFO(Location(hintedLocation)->GetName()); + SPDLOG_INFO("\n"); + + SPDLOG_INFO("\tItem: "); + SPDLOG_INFO(Location(hintedLocation)->GetPlacedItemName().GetEnglish()); + SPDLOG_INFO("\n"); + + // get an accessible gossip stone + const std::vector gossipStoneLocations = GetAccessibleGossipStones(hintedLocation); + + if (gossipStoneLocations.empty()) { + SPDLOG_INFO("\tNO GOSSIP STONES TO PLACE HINT\n\n"); + return; + } + Location(hintedLocation)->SetAsHinted(); + uint32_t gossipStone = RandomElement(gossipStoneLocations); + + // form hint text + Text locationText; + if (Location(hintedLocation)->IsDungeon()) { + *remainingDungeonWothHints -= 1; + uint32_t parentRegion = Location(hintedLocation)->GetParentRegionKey(); + locationText = AreaTable(parentRegion)->GetHint().GetText(); + + } else { + uint32_t parentRegion = Location(hintedLocation)->GetParentRegionKey(); + locationText = GetHintRegion(parentRegion)->GetHint().GetText(); + } + Text finalWothHint = Hint(PREFIX).GetText() + "#" + locationText + "#" + Hint(WAY_OF_THE_HERO).GetText(); + SPDLOG_INFO("\tMessage: "); + SPDLOG_INFO(finalWothHint.english); + SPDLOG_INFO("\n\n"); + AddHint(finalWothHint, gossipStone, { QM_LBLUE }); +} + +static void CreateBarrenHint(uint8_t* remainingDungeonBarrenHints, std::vector& barrenLocations) { + // remove dungeon locations if necessary + if (*remainingDungeonBarrenHints < 1) { + barrenLocations = + FilterFromPool(barrenLocations, [](const uint32_t loc) { return !(Location(loc)->IsDungeon()); }); + } + + if (barrenLocations.empty()) { + return; + } + + uint32_t hintedLocation = RandomElement(barrenLocations, true); + + SPDLOG_INFO("\tLocation: "); + SPDLOG_INFO(Location(hintedLocation)->GetName()); + SPDLOG_INFO("\n"); + + SPDLOG_INFO("\tItem: "); + SPDLOG_INFO(Location(hintedLocation)->GetPlacedItemName().GetEnglish()); + SPDLOG_INFO("\n"); + + // get an accessible gossip stone + const std::vector gossipStoneLocations = GetAccessibleGossipStones(hintedLocation); + if (gossipStoneLocations.empty()) { + SPDLOG_INFO("\tNO GOSSIP STONES TO PLACE HINT\n\n"); + return; + } + Location(hintedLocation)->SetAsHinted(); + uint32_t gossipStone = RandomElement(gossipStoneLocations); + + // form hint text + Text locationText; + if (Location(hintedLocation)->IsDungeon()) { + *remainingDungeonBarrenHints -= 1; + uint32_t parentRegion = Location(hintedLocation)->GetParentRegionKey(); + locationText = Hint(AreaTable(parentRegion)->hintKey).GetText(); + } else { + uint32_t parentRegion = Location(hintedLocation)->GetParentRegionKey(); + locationText = Hint(GetHintRegion(parentRegion)->hintKey).GetText(); + } + Text finalBarrenHint = + Hint(PREFIX).GetText() + Hint(PLUNDERING).GetText() + "#" + locationText + "#" + Hint(FOOLISH).GetText(); + SPDLOG_INFO("\tMessage: "); + SPDLOG_INFO(finalBarrenHint.english); + SPDLOG_INFO("\n\n"); + AddHint(finalBarrenHint, gossipStone, { QM_PINK }); + + // get rid of all other locations in this same barren region + barrenLocations = FilterFromPool(barrenLocations, [hintedLocation](uint32_t loc) { + return GetHintRegion(Location(loc)->GetParentRegionKey())->hintKey != + GetHintRegion(Location(hintedLocation)->GetParentRegionKey())->hintKey; + }); +} + +static void CreateRandomLocationHint(const bool goodItem = false) { + const std::vector possibleHintLocations = FilterFromPool(allLocations, [goodItem](const uint32_t loc) { + return Location(loc)->IsHintable() && !(Location(loc)->IsHintedAt()) && (!goodItem || Location(loc)->GetPlacedItem().IsMajorItem()); + }); + //If no more locations can be hinted at, then just try to get another hint + if (possibleHintLocations.empty()) { + SPDLOG_INFO("\tNO LOCATIONS TO HINT\n\n"); + return; + } + uint32_t hintedLocation = RandomElement(possibleHintLocations); + + SPDLOG_INFO("\tLocation: "); + SPDLOG_INFO(Location(hintedLocation)->GetName()); + SPDLOG_INFO("\n"); + + SPDLOG_INFO("\tItem: "); + SPDLOG_INFO(Location(hintedLocation)->GetPlacedItemName().GetEnglish()); + SPDLOG_INFO("\n"); + + //get an acessible gossip stone + const std::vector gossipStoneLocations = GetAccessibleGossipStones(hintedLocation); + if (gossipStoneLocations.empty()) { + SPDLOG_INFO("\tNO GOSSIP STONES TO PLACE HINT\n\n"); + return; + } + Location(hintedLocation)->SetAsHinted(); + uint32_t gossipStone = RandomElement(gossipStoneLocations); + + //form hint text + Text itemText = Location(hintedLocation)->GetPlacedItem().GetHint().GetText(); + if (Location(hintedLocation)->IsDungeon()) { + uint32_t parentRegion = Location(hintedLocation)->GetParentRegionKey(); + Text locationText = AreaTable(parentRegion)->GetHint().GetText(); + Text finalHint = Hint(PREFIX).GetText()+"#"+locationText+"# "+Hint(HOARDS).GetText()+" #"+itemText+"#."; + SPDLOG_INFO("\tMessage: "); + SPDLOG_INFO(finalHint.english); + SPDLOG_INFO("\n\n"); + AddHint(finalHint, gossipStone, {QM_GREEN, QM_RED}); + } else { + Text locationText = GetHintRegion(Location(hintedLocation)->GetParentRegionKey())->GetHint().GetText(); + Text finalHint = Hint(PREFIX).GetText()+"#"+itemText+"# "+Hint(CAN_BE_FOUND_AT).GetText()+" #"+locationText+"#."; + SPDLOG_INFO("\tMessage: "); + SPDLOG_INFO(finalHint.english); + SPDLOG_INFO("\n\n"); + AddHint(finalHint, gossipStone, {QM_RED, QM_GREEN}); + } +} + +static void CreateGoodItemHint() { + CreateRandomLocationHint(true); +} + +static void CreateJunkHint() { + //duplicate junk hints are possible for now + const HintText junkHint = RandomElement(GetHintCategory(HintCategory::Junk)); + LogicReset(); + const std::vector gossipStones = GetAccessibleLocations(gossipStoneLocations); + if (gossipStones.empty()) { + SPDLOG_INFO("\tNO GOSSIP STONES TO PLACE HINT\n\n"); + return; + } + uint32_t gossipStone = RandomElement(gossipStones); + Text hint = junkHint.GetText(); + + SPDLOG_INFO("\tMessage: "); + SPDLOG_INFO(hint.english); + SPDLOG_INFO("\n\n"); + + AddHint(hint, gossipStone, {QM_PINK}); +} + +static std::vector CalculateBarrenRegions() { + std::vector barrenLocations = {}; + std::vector potentiallyUsefulLocations = {}; + + for (uint32_t loc : allLocations) { + // If a location has a major item or is a way of the hero location, it is not barren + if (Location(loc)->GetPlacedItem().IsMajorItem() || ElementInContainer(loc, wothLocations)) { + AddElementsToPool(potentiallyUsefulLocations, std::vector{loc}); + } else { + if (loc != LINKS_POCKET) { //Nobody cares to know if Link's Pocket is barren + AddElementsToPool(barrenLocations, std::vector{loc}); + } + } + } + + // Leave only locations at barren regions in the list + auto finalBarrenLocations = FilterFromPool(barrenLocations, [&potentiallyUsefulLocations](uint32_t loc){ + for (uint32_t usefulLoc : potentiallyUsefulLocations) { + uint32_t barrenKey = GetLocationRegionuint32_t(loc); + uint32_t usefulKey = GetLocationRegionuint32_t(usefulLoc); + if (barrenKey == usefulKey) { + return false; + } + } + return true; + }); + + return finalBarrenLocations; +} + +static void CreateTrialHints() { + //six trials + if (RandomGanonsTrials && GanonsTrialsCount.Is(6)) { + + //get a random gossip stone + auto gossipStones = GetAccessibleGossipStones(); + auto gossipStone = RandomElement(gossipStones, false); + + //make hint + auto hint = Hint(PREFIX).GetText() + Hint(SIX_TRIALS).GetText(); + AddHint(hint, gossipStone, {QM_PINK}); + + //zero trials + } else if (RandomGanonsTrials && GanonsTrialsCount.Is(0)) { + + //get a random gossip stone + auto gossipStones = GetAccessibleGossipStones(); + auto gossipStone = RandomElement(gossipStones, false); + + //make hint + auto hint = Hint(PREFIX).GetText() + Hint(ZERO_TRIALS).GetText(); + AddHint(hint, gossipStone, {QM_YELLOW}); + + //4 or 5 required trials + } else if (GanonsTrialsCount.Is(5) || GanonsTrialsCount.Is(4)) { + + //get skipped trials + std::vector trials = {}; + trials.assign(trialList.begin(), trialList.end()); + auto skippedTrials = FilterFromPool(trials, [](TrialInfo* trial){return trial->IsSkipped();}); + + //create a hint for each skipped trial + for (auto& trial : skippedTrials) { + //get a random gossip stone + auto gossipStones = GetAccessibleGossipStones(); + auto gossipStone = RandomElement(gossipStones, false); + + //make hint + auto hint = Hint(PREFIX).GetText()+"#"+trial->GetName()+"#"+Hint(FOUR_TO_FIVE_TRIALS).GetText(); + AddHint(hint, gossipStone, {QM_YELLOW}); + } + //1 to 3 trials + } else if (GanonsTrialsCount.Value() >= 1 && GanonsTrialsCount.Value() <= 3) { + //get requried trials + std::vector trials = {}; + trials.assign(trialList.begin(), trialList.end()); + auto requiredTrials = FilterFromPool(trials, [](TrialInfo* trial){return trial->IsRequired();}); + + //create a hint for each required trial + for (auto& trial : requiredTrials) { + //get a random gossip stone + auto gossipStones = GetAccessibleGossipStones(); + auto gossipStone = RandomElement(gossipStones, false); + + //make hint + auto hint = Hint(PREFIX).GetText()+"#"+trial->GetName()+"#"+Hint(ONE_TO_THREE_TRIALS).GetText(); + AddHint(hint, gossipStone, {QM_PINK}); + } + } +} + +static void CreateGanonText() { + + //funny ganon line + ganonText = RandomElement(GetHintCategory(HintCategory::GanonLine)).GetText(); + CreateMessageFromTextObject(0x70CB, 0, 2, 3, AddColorsAndFormat(ganonText)); + + //Get the location of the light arrows + auto lightArrowLocation = FilterFromPool(allLocations, [](const uint32_t loc){return Location(loc)->GetPlaceduint32_t() == LIGHT_ARROWS;}); + + //If there is no light arrow location, it was in the player's inventory at the start + if (lightArrowLocation.empty()) { + ganonHintText = Hint(LIGHT_ARROW_LOCATION_HINT).GetText()+Hint(YOUR_POCKET).GetText(); + } else { + ganonHintText = Hint(LIGHT_ARROW_LOCATION_HINT).GetText()+GetHintRegion(Location(lightArrowLocation[0])->GetParentRegionKey())->GetHint().GetText(); + } + ganonHintText = ganonHintText + "!"; + + CreateMessageFromTextObject(0x70CC, 0, 2, 3, AddColorsAndFormat(ganonHintText)); +} + +//Find the location which has the given itemKey and create the generic altar text for the reward +static Text BuildDungeonRewardText(const uint32_t itemKey) { + uint32_t location = FilterFromPool(allLocations, [itemKey](const uint32_t loc){return Location(loc)->GetPlaceduint32_t() == itemKey;})[0]; + Location(location)->SetAsHinted(); + + std::string rewardString = "$" + std::to_string(itemKey - KOKIRI_EMERALD); + + // RANDOTODO implement colors for locations + return Text()+rewardString+GetHintRegion(Location(location)->GetParentRegionKey())->GetHint().GetText()+"...^"; +} + +static Text BuildDoorOfTimeText() { + std::string itemObtained; + Text doorOfTimeText; + + if (OpenDoorOfTime.Is(OPENDOOROFTIME_OPEN)) { + itemObtained = "$o"; + doorOfTimeText = Hint(CHILD_ALTAR_TEXT_END_DOTOPEN).GetText(); + + } else if (OpenDoorOfTime.Is(OPENDOOROFTIME_CLOSED)) { + itemObtained = "$c"; + doorOfTimeText = Hint(CHILD_ALTAR_TEXT_END_DOTCLOSED).GetText(); + + } else if (OpenDoorOfTime.Is(OPENDOOROFTIME_INTENDED)) { + itemObtained = "$i"; + doorOfTimeText = Hint(CHILD_ALTAR_TEXT_END_DOTINTENDED).GetText(); + } + + return Text()+itemObtained+doorOfTimeText; +} + +//insert the required number into the hint and set the singular/plural form +static Text BuildCountReq(const uint32_t req, const Option& count) { + Text requirement = Hint(req).GetTextCopy(); + if (count.Value() == 1) { + requirement.SetForm(SINGULAR); + } else { + requirement.SetForm(PLURAL); + } + requirement.Replace("%d", std::to_string(count.Value())); + return requirement; +} + +static Text BuildBridgeReqsText() { + Text bridgeText; + + if (Bridge.Is(RAINBOWBRIDGE_OPEN)) { + bridgeText = Hint(BRIDGE_OPEN_HINT).GetText(); + + } else if (Bridge.Is(RAINBOWBRIDGE_VANILLA)) { + bridgeText = Hint(BRIDGE_VANILLA_HINT).GetText(); + + } else if (Bridge.Is(RAINBOWBRIDGE_STONES)) { + bridgeText = BuildCountReq(BRIDGE_STONES_HINT, BridgeStoneCount); + + } else if (Bridge.Is(RAINBOWBRIDGE_MEDALLIONS)) { + bridgeText = BuildCountReq(BRIDGE_MEDALLIONS_HINT, BridgeMedallionCount); + + } else if (Bridge.Is(RAINBOWBRIDGE_REWARDS)) { + bridgeText = BuildCountReq(BRIDGE_REWARDS_HINT, BridgeRewardCount); + + } else if (Bridge.Is(RAINBOWBRIDGE_DUNGEONS)) { + bridgeText = BuildCountReq(BRIDGE_DUNGEONS_HINT, BridgeDungeonCount); + + } else if (Bridge.Is(RAINBOWBRIDGE_TOKENS)) { + bridgeText = BuildCountReq(BRIDGE_TOKENS_HINT, BridgeTokenCount); + } + + return Text()+"$l"+bridgeText+"^"; +} + +static Text BuildGanonBossKeyText() { + Text ganonBossKeyText; + + if (GanonsBossKey.Is(GANONSBOSSKEY_START_WITH)) { + ganonBossKeyText = Hint(GANON_BK_START_WITH_HINT).GetText(); + + } else if (GanonsBossKey.Is(GANONSBOSSKEY_VANILLA)) { + ganonBossKeyText = Hint(GANON_BK_VANILLA_HINT).GetText(); + + } else if (GanonsBossKey.Is(GANONSBOSSKEY_OWN_DUNGEON)) { + ganonBossKeyText = Hint(GANON_BK_OWN_DUNGEON_HINT).GetText(); + + } else if (GanonsBossKey.Is(GANONSBOSSKEY_ANY_DUNGEON)) { + ganonBossKeyText = Hint(GANON_BK_ANY_DUNGEON_HINT).GetText(); + + } else if (GanonsBossKey.Is(GANONSBOSSKEY_OVERWORLD)) { + ganonBossKeyText = Hint(GANON_BK_OVERWORLD_HINT).GetText(); + + } else if (GanonsBossKey.Is(GANONSBOSSKEY_ANYWHERE)) { + ganonBossKeyText = Hint(GANON_BK_ANYWHERE_HINT).GetText(); + + } else if (GanonsBossKey.Is(GANONSBOSSKEY_LACS_VANILLA)) { + ganonBossKeyText = Hint(LACS_VANILLA_HINT).GetText(); + + } else if (GanonsBossKey.Is(GANONSBOSSKEY_LACS_STONES)) { + ganonBossKeyText = BuildCountReq(LACS_STONES_HINT, LACSStoneCount); + + } else if (GanonsBossKey.Is(GANONSBOSSKEY_LACS_MEDALLIONS)) { + ganonBossKeyText = BuildCountReq(LACS_MEDALLIONS_HINT, LACSMedallionCount); + + } else if (GanonsBossKey.Is(GANONSBOSSKEY_LACS_REWARDS)) { + ganonBossKeyText = BuildCountReq(LACS_REWARDS_HINT, LACSRewardCount); + + } else if (GanonsBossKey.Is(GANONSBOSSKEY_LACS_DUNGEONS)) { + ganonBossKeyText = BuildCountReq(LACS_DUNGEONS_HINT, LACSDungeonCount); + + } else if (GanonsBossKey.Is(GANONSBOSSKEY_LACS_TOKENS)) { + ganonBossKeyText = BuildCountReq(LACS_TOKENS_HINT, LACSTokenCount); + } + + return Text()+"$b"+ganonBossKeyText+"^"; +} + +static void CreateAltarText() { + + //Child Altar Text + childAltarText = Hint(SPIRITUAL_STONE_TEXT_START).GetText()+"^"+ + //Spiritual Stones + (StartingKokiriEmerald.Value() ? Text{ "##", "##", "##" } + : BuildDungeonRewardText(KOKIRI_EMERALD)) + + (StartingGoronRuby.Value() ? Text{ "##", "##", "##" } + : BuildDungeonRewardText(GORON_RUBY)) + + (StartingZoraSapphire.Value() ? Text{ "##", "##", "##" } + : BuildDungeonRewardText(ZORA_SAPPHIRE)) + + //How to open Door of Time, the event trigger is necessary to read the altar multiple times + BuildDoorOfTimeText(); + CreateMessageFromTextObject(0x7040, 0, 2, 3, AddColorsAndFormat(childAltarText, {QM_GREEN, QM_RED, QM_BLUE})); + + //Adult Altar Text + adultAltarText = Hint(ADULT_ALTAR_TEXT_START).GetText()+"^"+ + //Medallion Areas + (StartingLightMedallion.Value() ? Text{ "##", "##", "##" } + : BuildDungeonRewardText(LIGHT_MEDALLION)) + + (StartingForestMedallion.Value() ? Text{ "##", "##", "##" } + : BuildDungeonRewardText(FOREST_MEDALLION)) + + (StartingFireMedallion.Value() ? Text{ "##", "##", "##" } + : BuildDungeonRewardText(FIRE_MEDALLION)) + + (StartingWaterMedallion.Value() ? Text{ "##", "##", "##" } + : BuildDungeonRewardText(WATER_MEDALLION)) + + (StartingSpiritMedallion.Value() ? Text{ "##", "##", "##" } + : BuildDungeonRewardText(SPIRIT_MEDALLION)) + + (StartingShadowMedallion.Value() ? Text{ "##", "##", "##" } + : BuildDungeonRewardText(SHADOW_MEDALLION)) + + + //Bridge requirement + BuildBridgeReqsText()+ + + //Ganons Boss Key requirement + BuildGanonBossKeyText()+ + + //End + Hint(ADULT_ALTAR_TEXT_END).GetText(); + CreateMessageFromTextObject(0x7088, 0, 2, 3, AddColorsAndFormat(adultAltarText, {QM_RED, QM_YELLOW, QM_GREEN, QM_RED, QM_BLUE, QM_YELLOW, QM_PINK, QM_RED, QM_RED, QM_RED, QM_RED})); +} + +void CreateMerchantsHints() { + + Text medigoronItemText = Location(GC_MEDIGORON)->GetPlacedItem().GetHint().GetText(); + Text carpetSalesmanItemText = Location(WASTELAND_BOMBCHU_SALESMAN)->GetPlacedItem().GetHint().GetText(); + Text carpetSalesmanItemClearText = Location(WASTELAND_BOMBCHU_SALESMAN)->GetPlacedItem().GetHint().GetClear(); + + Text medigoronText = Hint(MEDIGORON_DIALOG_FIRST).GetText()+medigoronItemText+Hint(MEDIGORON_DIALOG_SECOND).GetText(); + Text carpetSalesmanTextOne = Hint(CARPET_SALESMAN_DIALOG_FIRST).GetText()+carpetSalesmanItemText+Hint(CARPET_SALESMAN_DIALOG_SECOND).GetText(); + Text carpetSalesmanTextTwo = Hint(CARPET_SALESMAN_DIALOG_THIRD).GetText()+carpetSalesmanItemClearText+Hint(CARPET_SALESMAN_DIALOG_FOURTH).GetText(); + + CreateMessageFromTextObject(0x9120, 0, 2, 3, AddColorsAndFormat(medigoronText, {QM_RED, QM_GREEN})); + CreateMessageFromTextObject(0x6077, 0, 2, 3, AddColorsAndFormat(carpetSalesmanTextOne, {QM_RED, QM_GREEN})); + CreateMessageFromTextObject(0x6078, 0, 2, 3, AddColorsAndFormat(carpetSalesmanTextTwo, {QM_RED, QM_YELLOW, QM_RED})); +} + +void CreateAllHints() { + + CreateGanonText(); + CreateAltarText(); + + SPDLOG_INFO("\nNOW CREATING HINTS\n"); + const HintSetting& hintSetting = hintSettingTable[Settings::HintDistribution.Value()]; + + uint8_t remainingDungeonWothHints = hintSetting.dungeonsWothLimit; + uint8_t remainingDungeonBarrenHints = hintSetting.dungeonsBarrenLimit; + + // Add 'always' location hints + if (hintSetting.distTable[static_cast(HintType::Always)].copies > 0) { + // Only filter locations that had a random item placed at them (e.g. don't get cow locations if shuffle cows is off) + auto alwaysHintLocations = FilterFromPool(allLocations, [](const uint32_t loc){ + return Location(loc)->GetHint().GetType() == HintCategory::Always && + Location(loc)->IsHintable() && !(Location(loc)->IsHintedAt()); + }); + + for (auto& hint : conditionalAlwaysHints) { + uint32_t loc = hint.first; + if (hint.second() && Location(loc)->IsHintable() && !Location(loc)->IsHintedAt()) { + alwaysHintLocations.push_back(loc); + } + } + + for (uint32_t location : alwaysHintLocations) { + CreateLocationHint({location}); + } + } + + //Add 'trial' location hints + if (hintSetting.distTable[static_cast(HintType::Trial)].copies > 0) { + CreateTrialHints(); + } + + //create a vector with each hint type proportional to it's weight in the distribution setting. + //ootr uses a weighted probability function to decide hint types, but selecting randomly from + //this vector will do for now + std::vector remainingHintTypes = {}; + for (HintDistributionSetting hds : hintSetting.distTable) { + remainingHintTypes.insert(remainingHintTypes.end(), hds.weight, hds.type); + } + Shuffle(remainingHintTypes); + + //get barren regions + auto barrenLocations = CalculateBarrenRegions(); + + //Calculate dungeon woth/barren info + + std::vector dungeonNames = {"Deku Tree", "Dodongos Cavern", "Jabu Jabus Belly", "Forest Temple", "Fire Temple", + "Water Temple", "Spirit Temple", "Shadow Temple", "Bottom of the Well", "Ice Cavern"}; + //Get list of all barren dungeons + std::vector barrenDungeons; + for (uint32_t barrenLocation : barrenLocations) { + std::string barrenRegion = GetHintRegion(Location(barrenLocation)->GetParentRegionKey())->scene; + bool isDungeon = std::find(dungeonNames.begin(), dungeonNames.end(), barrenRegion) != dungeonNames.end(); + //If it hasn't already been added to the list and is a dungeon, add to list + if (isDungeon && std::find(barrenDungeons.begin(), barrenDungeons.end(), barrenRegion) == barrenDungeons.end()) { + barrenDungeons.push_back(barrenRegion); + } + } + SPDLOG_INFO("\nBarren Dungeons:\n"); + for (std::string barrenDungeon : barrenDungeons) { + SPDLOG_INFO(barrenDungeon + "\n"); + } + + //Get list of all woth dungeons + std::vector wothDungeons; + for (uint32_t wothLocation : wothLocations) { + std::string wothRegion = GetHintRegion(Location(wothLocation)->GetParentRegionKey())->scene; + bool isDungeon = std::find(dungeonNames.begin(), dungeonNames.end(), wothRegion) != dungeonNames.end(); + //If it hasn't already been added to the list and is a dungeon, add to list + if (isDungeon && std::find(wothDungeons.begin(), wothDungeons.end(), wothRegion) == wothDungeons.end()) { + wothDungeons.push_back(wothRegion); + } + } + SPDLOG_INFO("\nWoth Dungeons:\n"); + for (std::string wothDungeon : wothDungeons) { + SPDLOG_INFO(wothDungeon + "\n"); + } + + //Set DungeonInfo array for each dungeon + for (uint32_t i = 0; i < dungeonInfoData.size(); i++) { + std::string dungeonName = dungeonNames[i]; + if (std::find(barrenDungeons.begin(), barrenDungeons.end(), dungeonName) != barrenDungeons.end()) { + dungeonInfoData[i] = DungeonInfo::DUNGEON_BARREN; + } else if (std::find(wothDungeons.begin(), wothDungeons.end(), dungeonName) != wothDungeons.end()) { + dungeonInfoData[i] = DungeonInfo::DUNGEON_WOTH; + } else { + dungeonInfoData[i] = DungeonInfo::DUNGEON_NEITHER; + } + } + + std::array hintTypeNames = { + "Trial", + "Always", + "WotH", + "Barren", + "Entrance", + "Sometimes", + "Random", + "Item", + "Song", + "Overworld", + "Dungeon", + "Junk", + "NamedItem", + }; + + //while there are still gossip stones remaining + while (FilterFromPool(gossipStoneLocations, [](const uint32_t loc){return Location(loc)->GetPlaceduint32_t() == NONE;}).size() != 0) { + //TODO: fixed hint types + + if (remainingHintTypes.empty()) { + break; + } + + //get a random hint type from the remaining hints + HintType type = RandomElement(remainingHintTypes, true); + + SPDLOG_INFO("Attempting to make hint of type: "); + SPDLOG_INFO(hintTypeNames[static_cast(type)]); + SPDLOG_INFO("\n"); + + //create the appropriate hint for the type + if (type == HintType::Woth) { + CreateWothHint(&remainingDungeonWothHints); + + } else if (type == HintType::Barren) { + CreateBarrenHint(&remainingDungeonBarrenHints, barrenLocations); + + } else if (type == HintType::Sometimes){ + std::vector sometimesHintLocations = FilterFromPool(allLocations, [](const uint32_t loc){return Location(loc)->GetHint().GetType() == HintCategory::Sometimes && Location(loc)->IsHintable() && !(Location(loc)->IsHintedAt());}); + CreateLocationHint(sometimesHintLocations); + + } else if (type == HintType::Random) { + CreateRandomLocationHint(); + + } else if (type == HintType::Item) { + CreateGoodItemHint(); + + } else if (type == HintType::Song){ + std::vector songHintLocations = FilterFromPool(allLocations, [](const uint32_t loc){return Location(loc)->IsCategory(Category::cSong) && Location(loc)->IsHintable() && !(Location(loc)->IsHintedAt());}); + CreateLocationHint(songHintLocations); + + } else if (type == HintType::Overworld){ + std::vector overworldHintLocations = FilterFromPool(allLocations, [](const uint32_t loc){return Location(loc)->IsOverworld() && Location(loc)->IsHintable() && !(Location(loc)->IsHintedAt());}); + CreateLocationHint(overworldHintLocations); + + } else if (type == HintType::Dungeon){ + std::vector dungeonHintLocations = FilterFromPool(allLocations, [](const uint32_t loc){return Location(loc)->IsDungeon() && Location(loc)->IsHintable() && !(Location(loc)->IsHintedAt());}); + CreateLocationHint(dungeonHintLocations); + + } else if (type == HintType::Junk) { + CreateJunkHint(); + } + } + + //If any gossip stones failed to have a hint placed on them for some reason, place a junk hint as a failsafe. + for (uint32_t gossipStone : FilterFromPool(gossipStoneLocations, [](const uint32_t loc){return Location(loc)->GetPlaceduint32_t() == NONE;})) { + const HintText junkHint = RandomElement(GetHintCategory(HintCategory::Junk)); + AddHint(junkHint.GetText(), gossipStone, {QM_PINK}); + } + + //Getting gossip stone locations temporarily sets one location to not be reachable. + //Call the function one last time to get rid of false positives on locations not + //being reachable. + GetAccessibleLocations({}); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/hints.hpp b/soh/soh/Enhancements/randomizer/3drando/hints.hpp new file mode 100644 index 000000000..e1c017284 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/hints.hpp @@ -0,0 +1,227 @@ +#pragma once + +#include +#include +#include + +#include "keys.hpp" +#include "text.hpp" +#include "random.hpp" +#include "settings.hpp" +#include + +enum class HintType { + Trial, + Always, + Woth, //Way of the Hero + Barren, + Entrance, + Sometimes, + Random, + Item, + Song, + Overworld, + Dungeon, + Junk, + NamedItem, + MaxCount, +}; + +struct HintDistributionSetting { + HintType type; + uint8_t order; + size_t weight; + uint8_t fixed; + uint8_t copies; +}; + +struct HintSetting { + using DistributionTable = std::array(HintType::MaxCount)>; + + uint8_t dungeonsWothLimit; + uint8_t dungeonsBarrenLimit; + bool namedItemsRequired; + DistributionTable distTable; +}; + +enum class HintCategory { + Item, + Always, + Sometimes, + Exclude, + Entrance, + Region, + Junk, + DungeonName, + Boss, + Bridge, + GanonsBossKey, + LACS, + Altar, + Validation, + LightArrow, + GanonLine, + MerchantsDialogs, +}; + +class HintText { +public: + HintText() = default; + HintText(std::vector obscureText_, std::vector ambiguousText_, Text clearText_, HintCategory type_) + : obscureText(std::move(obscureText_)), + ambiguousText(std::move(ambiguousText_)), + clearText(std::move(clearText_)), + type(type_) {} + + static auto Item(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Item}; + } + + static auto Always(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Always}; + } + + static auto Sometimes(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Sometimes}; + } + + static auto Exclude(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Exclude}; + } + + static auto Entrance(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Entrance}; + } + + static auto Region(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Region}; + } + + static auto Junk(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Junk}; + } + + static auto DungeonName(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::DungeonName}; + } + + static auto Boss(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Boss}; + } + + static auto Bridge(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Bridge}; + } + + static auto GanonsBossKey(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::GanonsBossKey}; + } + + static auto LACS(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::LACS}; + } + + static auto Altar(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Altar}; + } + + static auto Validation(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::Validation}; + } + + static auto LightArrow(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::LightArrow}; + } + + static auto GanonLine(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::GanonLine}; + } + + static auto MerchantsDialogs(std::vector&& obscureText, std::vector&& ambiguousText = {}, Text&& clearText = {}) { + return HintText{std::move(obscureText), std::move(ambiguousText), std::move(clearText), HintCategory::MerchantsDialogs}; + } + + Text& GetObscure() { + return RandomElement(obscureText); + } + + const Text& GetObscure() const { + return RandomElement(obscureText); + } + + Text& GetAmbiguous() { + if (ambiguousText.size() > 0) { + return RandomElement(ambiguousText); + } + return RandomElement(obscureText); + } + + const Text& GetAmbiguous() const { + if (ambiguousText.size() > 0) { + return RandomElement(ambiguousText); + } + return RandomElement(obscureText); + } + + const Text& GetClear() const { + if (clearText.GetEnglish().empty()) { + return GetObscure(); + } + return clearText; + } + + const Text& GetText() const { + if (Settings::ClearerHints.Is(HINTMODE_OBSCURE)) { + return GetObscure(); + } else if (Settings::ClearerHints.Is(HINTMODE_AMBIGUOUS)){ + return GetAmbiguous(); + } else { + return GetClear(); + } + } + + const Text GetTextCopy() const { + if (Settings::ClearerHints.Is(HINTMODE_OBSCURE)) { + return GetObscure(); + } else if (Settings::ClearerHints.Is(HINTMODE_AMBIGUOUS)){ + return GetAmbiguous(); + } else { + return GetClear(); + } + } + + HintCategory GetType() const { + return type; + } + + bool operator==(const HintText& right) const { + return obscureText == right.obscureText && + ambiguousText == right.ambiguousText && + clearText == right.clearText; + } + bool operator!=(const HintText& right) const { + return !operator==(right); + } + +private: + std::vector obscureText = {}; + std::vector ambiguousText = {}; + Text clearText; + HintCategory type; +}; + +using ConditionalAlwaysHint = std::pair>; + +//10 dungeons as GTG and GC are excluded +extern std::array dungeonInfoData; + +extern std::array conditionalAlwaysHints; + +extern uint32_t GetHintRegionHintKey(const uint32_t area); +extern void CreateAllHints(); +extern void CreateMerchantsHints(); + +Text& GetChildAltarText(); +Text& GetAdultAltarText(); +Text& GetGanonText(); +Text& GetGanonHintText(); diff --git a/soh/soh/Enhancements/randomizer/3drando/item.cpp b/soh/soh/Enhancements/randomizer/3drando/item.cpp new file mode 100644 index 000000000..13ddb99df --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/item.cpp @@ -0,0 +1,84 @@ +#include "item.hpp" + +#include + +#include "item_location.hpp" +#include "logic.hpp" +#include "random.hpp" +#include "item_pool.hpp" +#include "settings.hpp" +#include "z64item.h" + +Item::Item(Text name_, ItemType type_, int getItemId_, bool advancement_, bool* logicVar_, uint32_t hintKey_, + uint16_t price_) + : name(std::move(name_)), + type(type_), + getItemId(getItemId_), + advancement(advancement_), + logicVar(logicVar_), + hintKey(hintKey_), + price(price_) {} + +Item::Item(Text name_, ItemType type_, int getItemId_, bool advancement_, uint8_t* logicVar_, uint32_t hintKey_, + uint16_t price_) + : name(std::move(name_)), + type(type_), + getItemId(getItemId_), + advancement(advancement_), + logicVar(logicVar_), + hintKey(hintKey_), + price(price_) {} + +Item::~Item() = default; + +void Item::ApplyEffect() { + //If this is a key ring, logically add as many keys as we could need + if (FOREST_TEMPLE_KEY_RING <= hintKey && hintKey <= GANONS_CASTLE_KEY_RING) { + *std::get(logicVar) += 10; + } + else { + if (std::holds_alternative(logicVar)) { + *std::get(logicVar) = true; + } else { + *std::get(logicVar) += 1; + } + } + Logic::UpdateHelpers(); +} + +void Item::UndoEffect() { + if (FOREST_TEMPLE_KEY_RING <= hintKey && hintKey <= GANONS_CASTLE_KEY_RING) { + *std::get(logicVar) -= 10; + } + else { + if (std::holds_alternative(logicVar)) { + *std::get(logicVar) = false; + } else { + *std::get(logicVar) -= 1; + } + } + Logic::UpdateHelpers(); +} + +ItemOverride_Value Item::Value() const { + ItemOverride_Value val; + + val.all = 0; + val.itemId = getItemId; + if (getItemId == GI_ICE_TRAP) { + val.looksLikeItemId = RandomElement(IceTrapModels); + } + if (!Settings::ColoredBossKeys && (getItemId >= 0x95 && getItemId <= 0x9A)) { //Boss keys + val.looksLikeItemId = GI_KEY_BOSS; + } + if (!Settings::ColoredKeys && (getItemId >= 0xAF && getItemId <= 0xB7)) { //Small keys + val.looksLikeItemId = GI_KEY_SMALL; + } + if (type == ITEMTYPE_SHOP) { + // With the current shopsanity implementation, we need a way to detect + // regular shop items. This method should have no unintended side effects + // unless there was a multiworld with 256 players... so, it should be fine. + val.player = 0xFF; + } + return val; +} diff --git a/soh/soh/Enhancements/randomizer/3drando/item.hpp b/soh/soh/Enhancements/randomizer/3drando/item.hpp new file mode 100644 index 000000000..a424dbf2b --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/item.hpp @@ -0,0 +1,142 @@ +#pragma once + +#include +#include + +#include "keys.hpp" +#include "hint_list.hpp" +#include "settings.hpp" + +union ItemOverride_Value; + +enum ItemType { + ITEMTYPE_ITEM, + ITEMTYPE_MAP, + ITEMTYPE_COMPASS, + ITEMTYPE_BOSSKEY, + ITEMTYPE_SMALLKEY, + ITEMTYPE_TOKEN, + ITEMTYPE_FORTRESS_SMALLKEY, + ITEMTYPE_EVENT, + ITEMTYPE_DROP, + ITEMTYPE_REFILL, + ITEMTYPE_SONG, + ITEMTYPE_SHOP, + ITEMTYPE_DUNGEONREWARD +}; + +class Item { +public: + Item() = default; + Item(Text name_, ItemType type_, int getItemId_, bool advancement_, bool* logicVar_, uint32_t hintKey_, + uint16_t price_ = 0); + Item(Text name_, ItemType type_, int getItemId_, bool advancement_, uint8_t* logicVar_, uint32_t hintKey_, + uint16_t price_ = 0); + ~Item(); + + void ApplyEffect(); + void UndoEffect(); + + ItemOverride_Value Value() const; + + const Text& GetName() const { + return name; + } + + bool IsAdvancement() const { + return advancement; + } + + int GetItemID() const { + return getItemId; + } + + ItemType GetItemType() const { + return type; + } + + uint16_t GetPrice() const { + return price; + } + + void SetPrice(uint16_t price_) { + price = price_; + } + + void SetAsPlaythrough() { + playthrough = true; + } + + bool IsPlaythrough() const { + return playthrough; + } + + bool IsBottleItem() const { + return getItemId == 0x0F || //Empty Bottle + getItemId == 0X14 || //Bottle with Milk + (getItemId >= 0x8C && getItemId <= 0x94); //Rest of bottled contents + } + + bool IsMajorItem() const { + using namespace Settings; + if (type == ITEMTYPE_TOKEN) { + return Bridge.Is(RAINBOWBRIDGE_TOKENS) || LACSCondition == LACSCONDITION_TOKENS; + } + + if (type == ITEMTYPE_DROP || type == ITEMTYPE_EVENT || type == ITEMTYPE_SHOP || type == ITEMTYPE_MAP || type == ITEMTYPE_COMPASS) { + return false; + } + + if (type == ITEMTYPE_DUNGEONREWARD && (ShuffleRewards.Is(REWARDSHUFFLE_END_OF_DUNGEON))) { + return false; + } + // PURPLE TODO: LOCALIZATION + if (name.GetEnglish().find("Bombchus") != std::string::npos && !BombchusInLogic) { + return false; + } + + if (type == ITEMTYPE_SMALLKEY && (Keysanity.Is(KEYSANITY_VANILLA) || Keysanity.Is(KEYSANITY_OWN_DUNGEON))) { + return false; + } + + if (type == ITEMTYPE_FORTRESS_SMALLKEY && GerudoKeys.Is(GERUDOKEYS_VANILLA)) { + return false; + } + + if ((type == ITEMTYPE_BOSSKEY && getItemId != 0x9A) && (BossKeysanity.Is(BOSSKEYSANITY_VANILLA) || BossKeysanity.Is(BOSSKEYSANITY_OWN_DUNGEON))) { + return false; + } + //Ganons Castle Boss Key + if (getItemId == 0x9A && (GanonsBossKey.Is(GANONSBOSSKEY_VANILLA) || GanonsBossKey.Is(GANONSBOSSKEY_OWN_DUNGEON))) { + return false; + } + + return IsAdvancement(); + } + + const uint32_t GetHintKey() const { + return hintKey; + } + + const HintText& GetHint() const { + return Hint(hintKey); + } + + bool operator== (const Item& right) const { + return type == right.GetItemType() && getItemId == right.GetItemID(); + } + + bool operator!= (const Item& right) const { + return !operator==(right); + } + +private: + Text name; + ItemType type; + int getItemId; + bool advancement; + std::variant logicVar; + uint32_t hintKey; + uint16_t price; + bool playthrough = false; +}; diff --git a/soh/soh/Enhancements/randomizer/3drando/item_list.cpp b/soh/soh/Enhancements/randomizer/3drando/item_list.cpp new file mode 100644 index 000000000..b76f24754 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/item_list.cpp @@ -0,0 +1,290 @@ +#include "item_list.hpp" + +#include "logic.hpp" +#include +#include "z64item.h" + +using namespace Logic; + +static std::array itemTable; + +void ItemTable_Init() { //English name French Spanish Item Type getItemID advancement logic hint key + itemTable[NONE] = Item(Text{"No Item", "Rien", "Sin Objeto"}, ITEMTYPE_EVENT, GI_RUPEE_GREEN, false, &noVariable, NONE); + itemTable[KOKIRI_SWORD] = Item(Text{"Kokiri Sword", "Épée Kokiri", "Espada Kokiri"}, ITEMTYPE_ITEM, GI_SWORD_KOKIRI, true, &KokiriSword, KOKIRI_SWORD); + //[MASTER_SWORD] + itemTable[GIANTS_KNIFE] = Item(Text{"Giant's Knife", "Lame des Géants", "Espada de Biggoron"}, ITEMTYPE_ITEM, GI_SWORD_KNIFE, false, &noVariable, GIANTS_KNIFE); + itemTable[BIGGORON_SWORD] = Item(Text{"Biggoron's Sword", "Épée de Biggoron", "Espada de Biggoron"}, ITEMTYPE_ITEM, GI_SWORD_BGS, true, &BiggoronSword, BIGGORON_SWORD); + itemTable[DEKU_SHIELD] = Item(Text{"Deku Shield", "Bouclier Mojo", "Escudo deku"}, ITEMTYPE_ITEM, GI_SHIELD_DEKU, false, &noVariable, DEKU_SHIELD); + itemTable[HYLIAN_SHIELD] = Item(Text{"Hylian Shield", "Bouclier Hylien", "Escudo hyliano"}, ITEMTYPE_ITEM, GI_SHIELD_HYLIAN, false, &noVariable, HYLIAN_SHIELD); + itemTable[MIRROR_SHIELD] = Item(Text{"Mirror Shield", "Bouclier Miroir", "Escudo espejo"}, ITEMTYPE_ITEM, GI_SHIELD_MIRROR, true, &MirrorShield, MIRROR_SHIELD); + itemTable[GORON_TUNIC] = Item(Text{"Goron Tunic", "Tunique Goron", "Sayo goron"}, ITEMTYPE_ITEM, GI_TUNIC_GORON, true, &GoronTunic, GORON_TUNIC); + itemTable[ZORA_TUNIC] = Item(Text{"Zora Tunic", "Tunique Zora", "Sayo zora"}, ITEMTYPE_ITEM, GI_TUNIC_ZORA, true, &ZoraTunic, ZORA_TUNIC); + itemTable[IRON_BOOTS] = Item(Text{"Iron Boots", "Bottes de plomb", "Botas de hierro"}, ITEMTYPE_ITEM, GI_BOOTS_IRON, true, &IronBoots, IRON_BOOTS); + itemTable[HOVER_BOOTS] = Item(Text{"Hover Boots", "Bottes des airs", "Botas voladoras"}, ITEMTYPE_ITEM, GI_BOOTS_HOVER, true, &HoverBoots, HOVER_BOOTS); + + + itemTable[BOOMERANG] = Item(Text{"Boomerang", "Boomerang", "Búmeran"}, ITEMTYPE_ITEM, GI_BOOMERANG, true, &Boomerang, BOOMERANG); + itemTable[LENS_OF_TRUTH] = Item(Text{"Lens of Truth", "Monocle de Vérité", "Lupa de la Verdad"}, ITEMTYPE_ITEM, GI_LENS, true, &LensOfTruth, LENS_OF_TRUTH); + itemTable[MEGATON_HAMMER] = Item(Text{"Megaton Hammer", "Masse des Titans", "Martillo Megatón"}, ITEMTYPE_ITEM, GI_HAMMER, true, &Hammer, MEGATON_HAMMER); + itemTable[STONE_OF_AGONY] = Item(Text{"Stone of Agony", "Pierre de Souffrance", "Piedra de la Agonía"}, ITEMTYPE_ITEM, GI_STONE_OF_AGONY, true, &ShardOfAgony, STONE_OF_AGONY); + itemTable[DINS_FIRE] = Item(Text{"Din's Fire", "Feu de Din", "Fuego de Din"}, ITEMTYPE_ITEM, GI_DINS_FIRE, true, &DinsFire, DINS_FIRE); + itemTable[FARORES_WIND] = Item(Text{"Farore's Wind", "Vent de Farore", "Viento de Farore"}, ITEMTYPE_ITEM, GI_FARORES_WIND, true, &FaroresWind, FARORES_WIND); + itemTable[NAYRUS_LOVE] = Item(Text{"Nayru's Love", "Amour de Nayru", "Amor de Nayru"}, ITEMTYPE_ITEM, GI_NAYRUS_LOVE, true, &NayrusLove, NAYRUS_LOVE); + itemTable[FIRE_ARROWS] = Item(Text{"Fire Arrow", "Flèche de Feu", "Flecha de fuego"}, ITEMTYPE_ITEM, GI_ARROW_FIRE, true, &FireArrows, FIRE_ARROWS); + itemTable[ICE_ARROWS] = Item(Text{"Ice Arrow", "Flèche de Glace", "Flecha de hielo"}, ITEMTYPE_ITEM, GI_ARROW_ICE, true, &IceArrows, ICE_ARROWS); + itemTable[LIGHT_ARROWS] = Item(Text{"Light Arrow", "Flèche de Lumière", "Flecha de luz"}, ITEMTYPE_ITEM, GI_ARROW_LIGHT, true, &LightArrows, LIGHT_ARROWS); + itemTable[GERUDO_MEMBERSHIP_CARD] = Item(Text{"Gerudo Membership Card", "Carte Gerudo", "Pase de socio gerudo"}, ITEMTYPE_ITEM, GI_GERUDO_CARD, true, &GerudoToken, GERUDO_MEMBERSHIP_CARD); + itemTable[MAGIC_BEAN] = Item(Text{"Magic Bean", "Haricots Magiques", "Habichuelas mágicas"}, ITEMTYPE_ITEM, GI_BEAN, true, &MagicBean, MAGIC_BEAN); + itemTable[MAGIC_BEAN_PACK] = Item(Text{"Magic Bean Pack", "Paquet de Haricots Magiques", "Lote de habichuelas mágicas"}, ITEMTYPE_ITEM, 0xC9, true, &MagicBeanPack, MAGIC_BEAN_PACK); + itemTable[DOUBLE_DEFENSE] = Item(Text{"Double Defense", "Double Défence", "Doble poder defensivo"}, ITEMTYPE_ITEM, 0xB8, true, &DoubleDefense, DOUBLE_DEFENSE); + + itemTable[WEIRD_EGG] = Item(Text{"Weird Egg", "Oeuf Curieux", "Huevo extraño"}, ITEMTYPE_ITEM, GI_WEIRD_EGG, true, &WeirdEgg, WEIRD_EGG); +// itemTable[CUCCO] = Item(Text{"Cucco", "Cocotte", "Cuco"}, ITEMTYPE_ITEM, GI_CUCCO, true, &Cucco, CUCCO); + itemTable[ZELDAS_LETTER] = Item(Text{"Zelda's Letter", "Lettre de Zelda", "Carta de Zelda"}, ITEMTYPE_ITEM, GI_LETTER_ZELDA, true, &ZeldasLetter, ZELDAS_LETTER); +// itemTable[KEATON_MASK] = Item(Text{"Keaton Mask", "Masque du Renard", "Careta de Keaton"}, ITEMTYPE_ITEM, GI_MASK_KEATON, true, &KeatonMask, KEATON_MASK); +// itemTable[SKULL_MASK] = Item(Text{"Skull Mask", "Masque de Mort", "Máscara de calavera"}, ITEMTYPE_ITEM, GI_MASK_SKULL, true, &SkullMask, SKULL_MASK); +// itemTable[SPOOKY_MASK] = Item(Text{"Spooky Mask", "Masque d'Effroi", "Máscara tenebrosa"}, ITEMTYPE_ITEM, GI_MASK_SPOOKY, true, &SpookyMask, SPOOKY_MASK); +// itemTable[BUNNY_HOOD] = Item(Text{"Bunny Hood", "Masque du Lapin", "Capucha de conejo"}, ITEMTYPE_ITEM, GI_MASK_BUNNY, true, &BunnyHood, BUNNY_HOOD); +// itemTable[GORON_MASK] = Item(Text{"Goron Mask", "Masque de Goron", "Máscara Goron"}, ITEMTYPE_ITEM, GI_MASK_GORON, true, &GoronMask, GORON_MASK); +// itemTable[ZORA_MASK] = Item(Text{"Zora Mask", "Masque de Zora", "Máscara Zora"}, ITEMTYPE_ITEM, GI_MASK_ZORA, true, &ZoraMask, ZORA_MASK); +// itemTable[GERUDO_MASK] = Item(Text{"Gerudo Mask", "Masque de Gerudo", "Máscara Gerudo"}, ITEMTYPE_ITEM, GI_MASK_GERUDO, true, &GerudoMask, GERUDO_MASK); +// itemTable[MASK_OF_TRUTH] = Item(Text{"Mask of Truth", "Masque de Vérité", "Máscara de la Verdad"}, ITEMTYPE_ITEM, GI_MASK_MASK, true, &MaskofTruth, MASK_OF_TRUTH); + itemTable[POCKET_EGG] = Item(Text{"Pocket Egg", "Oeuf de poche", "Huevo de bolsillo"}, ITEMTYPE_ITEM, GI_POCKET_EGG, true, &PocketEgg, POCKET_EGG); +// itemTable[POCKET_CUCCO] = Item(Text{"Pocket Cucco", "Cocotte de poche", "Cuco de bolsillo"}, ITEMTYPE_ITEM, GI_POCKET_CUCCO, true, &PocketCucco, POCKET_CUCCO); + itemTable[COJIRO] = Item(Text{"Cojiro", "P'tit Poulet", "Cojiro"}, ITEMTYPE_ITEM, GI_COJIRO, true, &Cojiro, COJIRO); + itemTable[ODD_MUSHROOM] = Item(Text{"Odd Mushroom", "Champignon Suspect", "Champiñón extraño"}, ITEMTYPE_ITEM, GI_ODD_MUSHROOM, true, &OddMushroom, ODD_MUSHROOM); + itemTable[ODD_POTION] = Item(Text{"Odd Potion", "Mixture Suspecte", "Medicina rara"}, ITEMTYPE_ITEM, GI_ODD_POTION, true, &OddPoultice, ODD_POTION); + itemTable[POACHERS_SAW] = Item(Text{"Poacher's Saw", "Scie du Chasseur", "Sierra del furtivo"}, ITEMTYPE_ITEM, GI_SAW, true, &PoachersSaw, POACHERS_SAW); + itemTable[BROKEN_SWORD] = Item(Text{"Broken Goron's Sword", "Épée Brisée de Goron", "Espada goron rota"}, ITEMTYPE_ITEM, GI_SWORD_BROKEN, true, &BrokenSword, BROKEN_SWORD); + itemTable[PRESCRIPTION] = Item(Text{"Prescription", "Ordonnance", "Receta"}, ITEMTYPE_ITEM, GI_PRESCRIPTION, true, &Prescription, PRESCRIPTION); + itemTable[EYEBALL_FROG] = Item(Text{"Eyeball Frog", "Crapaud-qui-louche", "Rana de ojos saltones"}, ITEMTYPE_ITEM, GI_FROG, true, &EyeballFrog, EYEBALL_FROG); + itemTable[EYEDROPS] = Item(Text{"World's Finest Eyedrops", "Super Gouttes", "Supergotas oculares"}, ITEMTYPE_ITEM, GI_EYEDROPS, true, &Eyedrops, EYEDROPS); + itemTable[CLAIM_CHECK] = Item(Text{"Claim Check", "Certificat", "Recibo"}, ITEMTYPE_ITEM, GI_CLAIM_CHECK, true, &ClaimCheck, CLAIM_CHECK); + + itemTable[GOLD_SKULLTULA_TOKEN] = Item(Text{"Gold Skulltula Token", "Symbole de Skulltula d'Or", "Símbolo de skulltula dorada"}, ITEMTYPE_TOKEN, GI_SKULL_TOKEN, true, &GoldSkulltulaTokens, GOLD_SKULLTULA_TOKEN); + + //Progression Items + itemTable[PROGRESSIVE_HOOKSHOT] = Item(Text{"Progressive Hookshot", "Grappin (prog.)", "Gancho progresivo"}, ITEMTYPE_ITEM, 0x80, true, &ProgressiveHookshot, PROGRESSIVE_HOOKSHOT); + itemTable[PROGRESSIVE_STRENGTH] = Item(Text{"Progressive Strength Upgrade", "Amélioration de Force (prog.)", "Fuerza progresiva"}, ITEMTYPE_ITEM, 0x81, true, &ProgressiveStrength, PROGRESSIVE_STRENGTH); + itemTable[PROGRESSIVE_BOMB_BAG] = Item(Text{"Progressive Bomb Bag", "Sac de Bombes (prog.)", "Saco de bombas progresivo"}, ITEMTYPE_ITEM, 0x82, true, &ProgressiveBombBag, PROGRESSIVE_BOMB_BAG); + itemTable[PROGRESSIVE_BOW] = Item(Text{"Progressive Bow", "Arc (prog.)", "Arco progresivo"}, ITEMTYPE_ITEM, 0x83, true, &ProgressiveBow, PROGRESSIVE_BOW); + itemTable[PROGRESSIVE_SLINGSHOT] = Item(Text{"Progressive Slingshot", "Lance-Pierre (prog.)", "Resortera progresiva"}, ITEMTYPE_ITEM, 0x84, true, &ProgressiveBulletBag, PROGRESSIVE_SLINGSHOT); + itemTable[PROGRESSIVE_WALLET] = Item(Text{"Progressive Wallet", "Bourse (prog.)", "Bolsa de rupias progresiva"}, ITEMTYPE_ITEM, 0x85, true, &ProgressiveWallet, PROGRESSIVE_WALLET); + itemTable[PROGRESSIVE_SCALE] = Item(Text{"Progressive Scale", "Écaille (prog.)", "Escama progresiva"}, ITEMTYPE_ITEM, 0x86, true, &ProgressiveScale, PROGRESSIVE_SCALE); + itemTable[PROGRESSIVE_NUT_UPGRADE] = Item(Text{"Progressive Nut Capacity", "Capacité de Noix (prog.)", "Capacidad de nueces deku progresiva"}, ITEMTYPE_ITEM, 0x87, false, &noVariable, PROGRESSIVE_NUT_UPGRADE); + itemTable[PROGRESSIVE_STICK_UPGRADE] = Item(Text{"Progressive Stick Capacity", "Capacité de Bâtons (prog.)", "Capacidad de palos deku progresiva"}, ITEMTYPE_ITEM, 0x88, false, &noVariable, PROGRESSIVE_STICK_UPGRADE); + itemTable[PROGRESSIVE_BOMBCHUS] = Item(Text{"Progressive Bombchu", "Missiles (prog.)", "Bombchus progresivos"}, ITEMTYPE_ITEM, 0x89, true, &Bombchus, PROGRESSIVE_BOMBCHUS); + itemTable[PROGRESSIVE_MAGIC_METER] = Item(Text{"Progressive Magic Meter", "Jauge de Magie (prog.)", "Poder mágico progresivo"}, ITEMTYPE_ITEM, 0x8A, true, &ProgressiveMagic, PROGRESSIVE_MAGIC_METER); + itemTable[PROGRESSIVE_OCARINA] = Item(Text{"Progressive Ocarina", "Ocarina (prog.)", "Ocarina progresiva"}, ITEMTYPE_ITEM, 0x8B, true, &ProgressiveOcarina, PROGRESSIVE_OCARINA); + itemTable[PROGRESSIVE_GORONSWORD] = Item(Text{"Progressive Goron Sword", "Épée Goron (prog.)", "Espada Goron progresiva"}, ITEMTYPE_ITEM, 0xD4, true, &ProgressiveGiantKnife, PROGRESSIVE_GORONSWORD); + + //Bottles + itemTable[EMPTY_BOTTLE] = Item(Text{"Empty Bottle", "Bouteille Vide", "Botella vacía"}, ITEMTYPE_ITEM, 0x0F, true, &Bottles, EMPTY_BOTTLE); + itemTable[BOTTLE_WITH_MILK] = Item(Text{"Bottle with Milk", "Bouteille avec du Lait", "Botella de leche Lon Lon"}, ITEMTYPE_ITEM, 0x14, true, &Bottles, BOTTLE_WITH_MILK); + itemTable[BOTTLE_WITH_RED_POTION] = Item(Text{"Bottle with Red Potion", "Bouteille avec une Potion Rouge", "Botella de poción roja"}, ITEMTYPE_ITEM, 0x8C, true, &Bottles, BOTTLE_WITH_RED_POTION); + itemTable[BOTTLE_WITH_GREEN_POTION] = Item(Text{"Bottle with Green Potion", "Bouteille avec une Potion Verte", "Botella de poción verde"}, ITEMTYPE_ITEM, 0x8D, true, &Bottles, BOTTLE_WITH_GREEN_POTION); + itemTable[BOTTLE_WITH_BLUE_POTION] = Item(Text{"Bottle with Blue Potion", "Bouteille avec une Potion Bleue", "Botella de poción azul"}, ITEMTYPE_ITEM, 0x8E, true, &Bottles, BOTTLE_WITH_BLUE_POTION); + itemTable[BOTTLE_WITH_FAIRY] = Item(Text{"Bottle with Fairy", "Bouteille avec une Fée", "Hada en una botella"}, ITEMTYPE_ITEM, 0x8F, true, &Bottles, BOTTLE_WITH_FAIRY); + itemTable[BOTTLE_WITH_FISH] = Item(Text{"Bottle with Fish", "Bouteille avec un Poisson", "Pez en una botella"}, ITEMTYPE_ITEM, 0x90, true, &Bottles, BOTTLE_WITH_FISH); + itemTable[BOTTLE_WITH_BLUE_FIRE] = Item(Text{"Bottle with Blue Fire", "Bouteille avec une Flamme Bleue", "Botella de fuego azul"}, ITEMTYPE_ITEM, 0x91, true, &Bottles, BOTTLE_WITH_BLUE_FIRE); + itemTable[BOTTLE_WITH_BUGS] = Item(Text{"Bottle with Bugs", "Bouteille avec des Insectes", "Insecto en una botella"}, ITEMTYPE_ITEM, 0x92, true, &Bottles, BOTTLE_WITH_BUGS); + itemTable[BOTTLE_WITH_POE] = Item(Text{"Bottle with Poe", "Bouteille avec un Esprit", "Poe en una botella"}, ITEMTYPE_ITEM, 0x94, true, &Bottles, BOTTLE_WITH_POE); + + //Special bottles that can't immediately dump contents + itemTable[RUTOS_LETTER] = Item(Text{"Bottle with Ruto's Letter", "Bouteille avec la Lettre de Ruto", "Carta de Ruto"}, ITEMTYPE_ITEM, 0x15, true, &RutosLetter, RUTOS_LETTER); + itemTable[BOTTLE_WITH_BIG_POE] = Item(Text{"Bottle with Big Poe", "Bouteille avec une Âme", "Gran Poe en una botella"}, ITEMTYPE_ITEM, 0x93, true, &BottleWithBigPoe, BOTTLE_WITH_BIG_POE); + + //Songs + itemTable[ZELDAS_LULLABY] = Item(Text{"Zelda's Lullaby", "Berceuse de Zelda", "Nana de Zelda"}, ITEMTYPE_SONG, 0xC1, true, &ZeldasLullaby, ZELDAS_LULLABY); + itemTable[EPONAS_SONG] = Item(Text{"Epona's Song", "Chant d'Épona", "Canción de Epona"}, ITEMTYPE_SONG, 0xC2, true, &EponasSong, EPONAS_SONG); + itemTable[SARIAS_SONG] = Item(Text{"Saria's Song", "Chant de Saria", "Canción de Saria"}, ITEMTYPE_SONG, 0xC3, true, &SariasSong, SARIAS_SONG); + itemTable[SUNS_SONG] = Item(Text{"Sun's Song", "Chant du Soleil", "Canción del Sol"}, ITEMTYPE_SONG, 0xC4, true, &SunsSong, SUNS_SONG); + itemTable[SONG_OF_TIME] = Item(Text{"Song of Time", "Chant du Temps", "Canción del tiempo"}, ITEMTYPE_SONG, 0xC5, true, &SongOfTime, SONG_OF_TIME); + itemTable[SONG_OF_STORMS] = Item(Text{"Song of Storms", "Chant des Tempêtes", "Canción de la tormenta"}, ITEMTYPE_SONG, 0xC6, true, &SongOfStorms, SONG_OF_STORMS); + itemTable[MINUET_OF_FOREST] = Item(Text{"Minuet of Forest", "Menuet des Bois", "Minueto del bosque"}, ITEMTYPE_SONG, 0xBB, true, &MinuetOfForest, MINUET_OF_FOREST); + itemTable[BOLERO_OF_FIRE] = Item(Text{"Bolero of Fire", "Boléro du Feu", "Bolero del fuego"}, ITEMTYPE_SONG, 0xBC, true, &BoleroOfFire, BOLERO_OF_FIRE); + itemTable[SERENADE_OF_WATER] = Item(Text{"Serenade of Water", "Sérénade de l'Eau", "Serenata del agua"}, ITEMTYPE_SONG, 0xBD, true, &SerenadeOfWater, SERENADE_OF_WATER); + itemTable[REQUIEM_OF_SPIRIT] = Item(Text{"Requiem of Spirit", "Requiem des Esprits", "Réquiem del espíritu"}, ITEMTYPE_SONG, 0xBE, true, &RequiemOfSpirit, REQUIEM_OF_SPIRIT); + itemTable[NOCTURNE_OF_SHADOW] = Item(Text{"Nocturne of Shadow", "Nocturne de l'Ombre", "Nocturno de la sombra"}, ITEMTYPE_SONG, 0xBF, true, &NocturneOfShadow, NOCTURNE_OF_SHADOW); + itemTable[PRELUDE_OF_LIGHT] = Item(Text{"Prelude of Light", "Prélude de la Lumière", "Preludio de la luz"}, ITEMTYPE_SONG, 0xC0, true, &PreludeOfLight, PRELUDE_OF_LIGHT); + + //Maps and Compasses + itemTable[DEKU_TREE_MAP] = Item(Text{"Great Deku Tree Map", "Carte de l'Arbre Mojo", "Mapa del Gran Árbol Deku"}, ITEMTYPE_MAP, 0xA5, false, &noVariable, DEKU_TREE_MAP); + itemTable[DODONGOS_CAVERN_MAP] = Item(Text{"Dodongo's Cavern Map", "Carte de la Caverne Dodongo", "Mapa de la Cueva de los Dodongos"}, ITEMTYPE_MAP, 0xA6, false, &noVariable, DODONGOS_CAVERN_MAP); + itemTable[JABU_JABUS_BELLY_MAP] = Item(Text{"Jabu-Jabu's Belly Map", "Carte du Ventre de Jabu-Jabu", "Mapa de la tripa de Jabu-Jabu"}, ITEMTYPE_MAP, 0xA7, false, &noVariable, JABU_JABUS_BELLY_MAP); + itemTable[FOREST_TEMPLE_MAP] = Item(Text{"Forest Temple Map", "Carte du Temple de la Forêt", "Mapa del Templo del Bosque"}, ITEMTYPE_MAP, 0xA8, false, &noVariable, FOREST_TEMPLE_MAP); + itemTable[FIRE_TEMPLE_MAP] = Item(Text{"Fire Temple Map", "Carte du Temple du Feu", "Mapa del Templo del Fuego"}, ITEMTYPE_MAP, 0xA9, false, &noVariable, FIRE_TEMPLE_MAP); + itemTable[WATER_TEMPLE_MAP] = Item(Text{"Water Temple Map", "Carte du Temple de l'Eau", "Mapa del Templo del Agua"}, ITEMTYPE_MAP, 0xAA, false, &noVariable, WATER_TEMPLE_MAP); + itemTable[SPIRIT_TEMPLE_MAP] = Item(Text{"Spirit Temple Map", "Carte du Temple de l'Esprit", "Mapa del Templo del Espíritu"}, ITEMTYPE_MAP, 0xAB, false, &noVariable, SPIRIT_TEMPLE_MAP); + itemTable[SHADOW_TEMPLE_MAP] = Item(Text{"Shadow Temple Map", "Carte du Temple de l'Ombre", "Mapa del Templo de la Sombra"}, ITEMTYPE_MAP, 0xAC, false, &noVariable, SHADOW_TEMPLE_MAP); + itemTable[BOTTOM_OF_THE_WELL_MAP] = Item(Text{"Bottom of the Well Map", "Carte du Puits", "Mapa del fondo del pozo"}, ITEMTYPE_MAP, 0xAD, false, &noVariable, BOTTOM_OF_THE_WELL_MAP); + itemTable[ICE_CAVERN_MAP] = Item(Text{"Ice Cavern Map", "Carte de la Caverne Polaire", "Mapa de la caverna de hielo"}, ITEMTYPE_MAP, 0xAE, false, &noVariable, ICE_CAVERN_MAP); + + itemTable[DEKU_TREE_COMPASS] = Item(Text{"Great Deku Tree Compass", "Boussole de l'Arbre Mojo", "Brújula del Gran Árbol Deku"}, ITEMTYPE_COMPASS, 0x9B, false, &noVariable, DEKU_TREE_COMPASS); + itemTable[DODONGOS_CAVERN_COMPASS] = Item(Text{"Dodongo's Cavern Compass", "Boussole de la Caverne Dodongo", "Brújula de la Cueva de los Dodongos"}, ITEMTYPE_COMPASS, 0x9C, false, &noVariable, DODONGOS_CAVERN_COMPASS); + itemTable[JABU_JABUS_BELLY_COMPASS] = Item(Text{"Jabu-Jabu's Belly Compass", "Boussole du Ventre de Jabu-Jabu", "Brújula de la tripa de Jabu-Jabu"}, ITEMTYPE_COMPASS, 0x9D, false, &noVariable, JABU_JABUS_BELLY_COMPASS); + itemTable[FOREST_TEMPLE_COMPASS] = Item(Text{"Forest Temple Compass", "Boussole du Temple de la Forêt", "Brújula del Templo del Bosque"}, ITEMTYPE_COMPASS, 0x9E, false, &noVariable, FOREST_TEMPLE_COMPASS); + itemTable[FIRE_TEMPLE_COMPASS] = Item(Text{"Fire Temple Compass", "Boussole du Temple du Feu", "Brújula del Templo del Fuego"}, ITEMTYPE_COMPASS, 0x9F, false, &noVariable, FIRE_TEMPLE_COMPASS); + itemTable[WATER_TEMPLE_COMPASS] = Item(Text{"Water Temple Compass", "Boussole du Temple de l'Eau", "Brújula del Templo del Agua"}, ITEMTYPE_COMPASS, 0xA0, false, &noVariable, WATER_TEMPLE_COMPASS); + itemTable[SPIRIT_TEMPLE_COMPASS] = Item(Text{"Spirit Temple Compass", "Boussole du Temple de l'Esprit", "Brújula del Templo del Espíritu"}, ITEMTYPE_COMPASS, 0xA1, false, &noVariable, SPIRIT_TEMPLE_COMPASS); + itemTable[SHADOW_TEMPLE_COMPASS] = Item(Text{"Shadow Temple Compass", "Boussole du Temple de l'Ombre", "Brújula del Templo de las Sombras"}, ITEMTYPE_COMPASS, 0xA2, false, &noVariable, SHADOW_TEMPLE_COMPASS); + itemTable[BOTTOM_OF_THE_WELL_COMPASS] = Item(Text{"Bottom of the Well Compass", "Boussole du Puits", "Brújula del fondo del pozo"}, ITEMTYPE_COMPASS, 0xA3, false, &noVariable, BOTTOM_OF_THE_WELL_COMPASS); + itemTable[ICE_CAVERN_COMPASS] = Item(Text{"Ice Cavern Compass", "Boussole de la Caverne Polaire", "Brújula de la caverna de hielo"}, ITEMTYPE_COMPASS, 0xA4, false, &noVariable, ICE_CAVERN_COMPASS); + + //Boss Keys + itemTable[FOREST_TEMPLE_BOSS_KEY] = Item(Text{"Forest Temple Big Key", "Clé d'Or du Temple de la Forêt", "Gran llave del Templo del Bosque"}, ITEMTYPE_BOSSKEY, 0x95, true, &BossKeyForestTemple, FOREST_TEMPLE_BOSS_KEY); + itemTable[FIRE_TEMPLE_BOSS_KEY] = Item(Text{"Fire Temple Big Key", "Clé d'Or du Temple du Feu", "Gran llave del Templo del Fuego"}, ITEMTYPE_BOSSKEY, 0x96, true, &BossKeyFireTemple, FIRE_TEMPLE_BOSS_KEY); + itemTable[WATER_TEMPLE_BOSS_KEY] = Item(Text{"Water Temple Big Key", "Clé d'Or du Temple de l'Eau", "Gran llave del Templo del Agua"}, ITEMTYPE_BOSSKEY, 0x97, true, &BossKeyWaterTemple, WATER_TEMPLE_BOSS_KEY); + itemTable[SPIRIT_TEMPLE_BOSS_KEY] = Item(Text{"Spirit Temple Big Key", "Clé d'Or du Temple de l'Esprit", "Gran llave del Templo del Espíritu"}, ITEMTYPE_BOSSKEY, 0x98, true, &BossKeySpiritTemple, SPIRIT_TEMPLE_BOSS_KEY); + itemTable[SHADOW_TEMPLE_BOSS_KEY] = Item(Text{"Shadow Temple Big Key", "Clé d'Or du Temple de l'Ombre", "Gran llave del Templo de las Sombras"}, ITEMTYPE_BOSSKEY, 0x99, true, &BossKeyShadowTemple, SHADOW_TEMPLE_BOSS_KEY); + itemTable[GANONS_CASTLE_BOSS_KEY] = Item(Text{"Ganon's Castle Big Key", "Clé d'Or du Château de Ganon", "Gran llave del Castillo de Ganon"}, ITEMTYPE_BOSSKEY, 0x9A, true, &BossKeyGanonsCastle, GANONS_CASTLE_BOSS_KEY); + + //Small Keys + itemTable[FOREST_TEMPLE_SMALL_KEY] = Item(Text{"Forest Temple Small Key", "Petite Clé du Temple de la Forêt", "Llave del Templo del Bosque"}, ITEMTYPE_SMALLKEY, 0xAF, true, &ForestTempleKeys, FOREST_TEMPLE_SMALL_KEY); + itemTable[FIRE_TEMPLE_SMALL_KEY] = Item(Text{"Fire Temple Small Key", "Petite Clé du Temple du Feu", "Llave del Templo del Fuego"}, ITEMTYPE_SMALLKEY, 0xB0, true, &FireTempleKeys, FIRE_TEMPLE_SMALL_KEY); + itemTable[WATER_TEMPLE_SMALL_KEY] = Item(Text{"Water Temple Small Key", "Petite Clé du Temple de l'Eau", "Llave del Templo del Agua"}, ITEMTYPE_SMALLKEY, 0xB1, true, &WaterTempleKeys, WATER_TEMPLE_SMALL_KEY); + itemTable[SPIRIT_TEMPLE_SMALL_KEY] = Item(Text{"Spirit Temple Small Key", "Petite Clé du Temple de l'Esprit", "Llave del Templo del Espíritu"}, ITEMTYPE_SMALLKEY, 0xB2, true, &SpiritTempleKeys, SPIRIT_TEMPLE_SMALL_KEY); + itemTable[SHADOW_TEMPLE_SMALL_KEY] = Item(Text{"Shadow Temple Small Key", "Petite Clé du Temple de l'Ombre", "Llave del Templo de las Sombras"}, ITEMTYPE_SMALLKEY, 0xB3, true, &ShadowTempleKeys, SHADOW_TEMPLE_SMALL_KEY); + itemTable[BOTTOM_OF_THE_WELL_SMALL_KEY] = Item(Text{"Bottom of the Well Small Key", "Petite Clé du Puits", "Llave del fondo del pozo"}, ITEMTYPE_SMALLKEY, 0xB4, true, &BottomOfTheWellKeys, BOTTOM_OF_THE_WELL_SMALL_KEY); + itemTable[GERUDO_TRAINING_GROUNDS_SMALL_KEY] = Item(Text{"Training Grounds Small Key", "Petite Clé du Gymnase Gerudo", "Llave del Centro de Instrucción"}, ITEMTYPE_SMALLKEY, 0xB5, true, &GerudoTrainingGroundsKeys, GERUDO_TRAINING_GROUNDS_SMALL_KEY); + itemTable[GERUDO_FORTRESS_SMALL_KEY] = Item(Text{"Gerudo Fortress Small Key", "Petite Clé du Repaire des Voleurs","Llave de la Fortaleza Gerudo"}, ITEMTYPE_FORTRESS_SMALLKEY, 0xB6, true, &GerudoFortressKeys, GERUDO_FORTRESS_SMALL_KEY); + itemTable[GANONS_CASTLE_SMALL_KEY] = Item(Text{"Ganon's Castle Small Key", "Petite Clé du Château de Ganon", "Llave del Castillo de Ganon"}, ITEMTYPE_SMALLKEY, 0xB7, true, &GanonsCastleKeys, GANONS_CASTLE_SMALL_KEY); + itemTable[TREASURE_GAME_SMALL_KEY] = Item(Text{"Chest Game Small Key", "Petite Clé du jeu la Chasse-aux-Trésors", "Llave del Cofre del Tesoro"}, ITEMTYPE_ITEM, 0xDE, true, &TreasureGameKeys, TREASURE_GAME_SMALL_KEY); + + // Key Rings + itemTable[FOREST_TEMPLE_KEY_RING] = Item(Text{"Forest Temple Key Ring", "Trousseau du Temple de la Forêt", "Llavero del Templo del Bosque"}, ITEMTYPE_SMALLKEY, 0xD5, true, &ForestTempleKeys, FOREST_TEMPLE_KEY_RING); + itemTable[FIRE_TEMPLE_KEY_RING] = Item(Text{"Fire Temple Key Ring", "Trousseau du Temple du Feu", "Llavero del Templo del Fuego"}, ITEMTYPE_SMALLKEY, 0xD6, true, &FireTempleKeys, FIRE_TEMPLE_KEY_RING); + itemTable[WATER_TEMPLE_KEY_RING] = Item(Text{"Water Temple Key Ring", "Trousseau du Temple de l'Eau", "Llavero del Templo del Agua"}, ITEMTYPE_SMALLKEY, 0xD7, true, &WaterTempleKeys, WATER_TEMPLE_KEY_RING); + itemTable[SPIRIT_TEMPLE_KEY_RING] = Item(Text{"Spirit Temple Key Ring", "Trousseau du Temple de l'Esprit", "Llavero del Templo del Espíritu"}, ITEMTYPE_SMALLKEY, 0xD8, true, &SpiritTempleKeys, SPIRIT_TEMPLE_KEY_RING); + itemTable[SHADOW_TEMPLE_KEY_RING] = Item(Text{"Shadow Temple Key Ring", "Trousseau du Temple de l'Ombre", "Llavero del Templo de las Sombras"}, ITEMTYPE_SMALLKEY, 0xD9, true, &ShadowTempleKeys, SHADOW_TEMPLE_KEY_RING); + itemTable[BOTTOM_OF_THE_WELL_KEY_RING] = Item(Text{"Bottom of the Well Key Ring", "Trousseau du Puits", "Llavero del fondo del pozo"}, ITEMTYPE_SMALLKEY, 0xDA, true, &BottomOfTheWellKeys, BOTTOM_OF_THE_WELL_KEY_RING); + itemTable[GERUDO_TRAINING_GROUNDS_KEY_RING] = Item(Text{"Training Grounds Key Ring", "Trousseau du Gymnase Gerudo", "Llavero del Centro de Instrucción"}, ITEMTYPE_SMALLKEY, 0xDB, true, &GerudoTrainingGroundsKeys, GERUDO_TRAINING_GROUNDS_KEY_RING); + itemTable[GERUDO_FORTRESS_KEY_RING] = Item(Text{"Gerudo Fortress Key Ring", "Trousseau du Repaire des Voleurs", "Llavero de la Fortaleza Gerudo"}, ITEMTYPE_FORTRESS_SMALLKEY, 0xDC, true, &GerudoFortressKeys, GERUDO_FORTRESS_KEY_RING); + itemTable[GANONS_CASTLE_KEY_RING] = Item(Text{"Ganon's Castle Key Ring", "Trousseau du Château de Ganon", "Llavero del Castillo de Ganon"}, ITEMTYPE_SMALLKEY, 0xDD, true, &GanonsCastleKeys, GANONS_CASTLE_KEY_RING); + + //Stones and Medallions + itemTable[KOKIRI_EMERALD] = Item(Text{"Kokiri's Emerald", "Émeraude Kokiri", "Esmeralda de los Kokiri"}, ITEMTYPE_DUNGEONREWARD, 0xCB, true, &KokiriEmerald, KOKIRI_EMERALD); + itemTable[GORON_RUBY] = Item(Text{"Goron's Ruby", "Rubis Goron", "Rubí de los Goron"}, ITEMTYPE_DUNGEONREWARD, 0xCC, true, &GoronRuby, GORON_RUBY); + itemTable[ZORA_SAPPHIRE] = Item(Text{"Zora's Sapphire", "Saphir Zora", "Zafiro de los Zora"}, ITEMTYPE_DUNGEONREWARD, 0xCD, true, &ZoraSapphire, ZORA_SAPPHIRE); + itemTable[FOREST_MEDALLION] = Item(Text{"Forest Medallion", "Médaillon de la Forêt", "Medallón del Bosque"}, ITEMTYPE_DUNGEONREWARD, 0xCE, true, &ForestMedallion, FOREST_MEDALLION); + itemTable[FIRE_MEDALLION] = Item(Text{"Fire Medallion", "Médaillon du Feu", "Medallón del Fuego"}, ITEMTYPE_DUNGEONREWARD, 0xCF, true, &FireMedallion, FIRE_MEDALLION); + itemTable[WATER_MEDALLION] = Item(Text{"Water Medallion", "Médaillon de l'Eau", "Medallón del Agua"}, ITEMTYPE_DUNGEONREWARD, 0xD0, true, &WaterMedallion, WATER_MEDALLION); + itemTable[SPIRIT_MEDALLION] = Item(Text{"Spirit Medallion", "Médaillon de l'Esprit", "Medallón del Espíritu"}, ITEMTYPE_DUNGEONREWARD, 0xD1, true, &SpiritMedallion, SPIRIT_MEDALLION); + itemTable[SHADOW_MEDALLION] = Item(Text{"Shadow Medallion", "Médaillon de l'Ombre", "Medallón de la Sombra"}, ITEMTYPE_DUNGEONREWARD, 0xD2, true, &ShadowMedallion, SHADOW_MEDALLION); + itemTable[LIGHT_MEDALLION] = Item(Text{"Light Medallion", "Médaillon de la Lumière", "Medallón de la Luz"}, ITEMTYPE_DUNGEONREWARD, 0xD3, true, &LightMedallion, LIGHT_MEDALLION); + + //Generic Items + itemTable[RECOVERY_HEART] = Item(Text{"Recovery Heart", "Coeur de Vie", "Corazón"}, ITEMTYPE_ITEM, GI_HEART, false, &noVariable, RECOVERY_HEART); + itemTable[GREEN_RUPEE] = Item(Text{"Green Rupee", "Rubis Vert", "Rupia verde"}, ITEMTYPE_ITEM, GI_RUPEE_GREEN, false, &noVariable, GREEN_RUPEE); + itemTable[BLUE_RUPEE] = Item(Text{"Blue Rupee", "Rubis Bleu", "Rupia azul"}, ITEMTYPE_ITEM, GI_RUPEE_BLUE, false, &noVariable, BLUE_RUPEE); + itemTable[RED_RUPEE] = Item(Text{"Red Rupee", "Rubis Rouge", "Rupia roja"}, ITEMTYPE_ITEM, GI_RUPEE_RED, false, &noVariable, RED_RUPEE); + itemTable[PURPLE_RUPEE] = Item(Text{"Purple Rupee", "Rubis Pourpre", "Rupia morada"}, ITEMTYPE_ITEM, GI_RUPEE_PURPLE, false, &noVariable, PURPLE_RUPEE); + itemTable[HUGE_RUPEE] = Item(Text{"Huge Rupee", "Énorme Rubis", "Rupia gigante"}, ITEMTYPE_ITEM, GI_RUPEE_GOLD, false, &noVariable, HUGE_RUPEE); + itemTable[PIECE_OF_HEART] = Item(Text{"Piece of Heart", "Quart de Coeur", "Pieza de corazón"}, ITEMTYPE_ITEM, GI_HEART_PIECE, true, &PieceOfHeart, PIECE_OF_HEART); + itemTable[HEART_CONTAINER] = Item(Text{"Heart Container", "Réceptacle de Coeur", "Contenedor de corazón"}, ITEMTYPE_ITEM, GI_HEART_CONTAINER_2, true, &HeartContainer, HEART_CONTAINER); + itemTable[ICE_TRAP] = Item(Text{"Ice Trap", "Piège de Glace", "Trampa de hielo"}, ITEMTYPE_ITEM, GI_ICE_TRAP, false, &noVariable, ICE_TRAP); + itemTable[MILK] = Item(Text{"Milk", "Lait", "Leche Lon Lon"}, ITEMTYPE_ITEM, GI_MILK, false, &noVariable, NONE); + + //Refills + itemTable[BOMBS_5] = Item(Text{"Bombs (5)", "Bombes (5)", "Bombas (5)"}, ITEMTYPE_REFILL, GI_BOMBS_5, false, &noVariable, BOMBS_5); + itemTable[BOMBS_10] = Item(Text{"Bombs (10)", "Bombes (10)", "Bombas (10)"}, ITEMTYPE_REFILL, GI_BOMBS_10, false, &noVariable, BOMBS_10); + itemTable[BOMBS_20] = Item(Text{"Bombs (20)", "Bombes (20)", "Bombas (20)"}, ITEMTYPE_REFILL, GI_BOMBS_20, false, &noVariable, BOMBS_20); + itemTable[BOMBCHU_5] = Item(Text{"Bombchu (5)", "Missiles (5)", "Bombchus (5)"}, ITEMTYPE_REFILL, GI_BOMBCHUS_5, true, &Bombchus5, BOMBCHU_5); + itemTable[BOMBCHU_10] = Item(Text{"Bombchu (10)", "Missiles (10)", "Bombchus (10)"}, ITEMTYPE_REFILL, GI_BOMBCHUS_10, true, &Bombchus10, BOMBCHU_10); + itemTable[BOMBCHU_20] = Item(Text{"Bombchu (20)", "Missiles (20)", "Bombchus (20)"}, ITEMTYPE_REFILL, GI_BOMBCHUS_20, true, &Bombchus20, BOMBCHU_20); + itemTable[BOMBCHU_DROP] = Item(Text{"Bombchu Drop", "Drop Missiles", "Bombchus"}, ITEMTYPE_DROP, GI_BOMBCHUS_10, true, &BombchuDrop, NONE); + itemTable[ARROWS_5] = Item(Text{"Arrows (5)", "Flèches (5)", "Flechas (5)"}, ITEMTYPE_REFILL, GI_ARROWS_SMALL, false, &noVariable, ARROWS_5); + itemTable[ARROWS_10] = Item(Text{"Arrows (10)", "Flèches (10)", "Flechas (10)"}, ITEMTYPE_REFILL, GI_ARROWS_MEDIUM, false, &noVariable, ARROWS_10); + itemTable[ARROWS_30] = Item(Text{"Arrows (30)", "Flèches (30)", "Flechas (30)"}, ITEMTYPE_REFILL, GI_ARROWS_LARGE, false, &noVariable, ARROWS_30); + itemTable[DEKU_NUTS_5] = Item(Text{"Deku Nuts (5)", "Noix Mojo (5)", "Nueces deku (5)"}, ITEMTYPE_REFILL, GI_NUTS_5, false, &noVariable, DEKU_NUTS_5); + itemTable[DEKU_NUTS_10] = Item(Text{"Deku Nuts (10)", "Noix Mojo (10)", "Nueces deku (10)"}, ITEMTYPE_REFILL, GI_NUTS_10, false, &noVariable, DEKU_NUTS_10); + itemTable[DEKU_SEEDS_30] = Item(Text{"Deku Seeds (30)", "Graines Mojo (30)", "Semillas deku (30)"}, ITEMTYPE_REFILL, GI_SEEDS_30, false, &noVariable, DEKU_SEEDS_30); + itemTable[DEKU_STICK_1] = Item(Text{"Deku Stick (1)", "Bâton Mojo (1)", "Palo deku (1)"}, ITEMTYPE_REFILL, GI_STICKS_1, false, &noVariable, DEKU_STICK_1); + itemTable[RED_POTION_REFILL] = Item(Text{"Red Potion Refill", "Recharge de Potion Rouge", "Recarga de poción roja"}, ITEMTYPE_REFILL, GI_POTION_RED, false, &noVariable, NONE); + itemTable[GREEN_POTION_REFILL] = Item(Text{"Green Potion Refill", "Recharge de Potion Verte", "Recarga de poción verde"}, ITEMTYPE_REFILL, GI_POTION_GREEN, false, &noVariable, NONE); + itemTable[BLUE_POTION_REFILL] = Item(Text{"Blue Potion Refill", "Recharge de Potion Bleue", "Recarga de poción azul"}, ITEMTYPE_REFILL, GI_POTION_BLUE, false, &noVariable, NONE); + + //Treasure Game + itemTable[TREASURE_GAME_HEART] = Item(Text{"Piece of Heart (Treasure Chest Minigame)", "Quart de Coeur (Chasse-aux-Trésors)", "Pieza de corazón (Cofre del Tesoro)"}, ITEMTYPE_ITEM, GI_HEART_PIECE_WIN, true, &PieceOfHeart, TREASURE_GAME_HEART); + itemTable[TREASURE_GAME_GREEN_RUPEE] = Item(Text{"Green Rupee (Treasure Chest Minigame)", "Rubis Vert (Chasse-aux-Trésors)", "Rupia Verde (Cofre del Tesoro)"}, ITEMTYPE_ITEM, GI_RUPEE_GREEN_LOSE, false, &noVariable, TREASURE_GAME_GREEN_RUPEE); + + //Shop Items price + itemTable[BUY_DEKU_NUT_5] = Item(Text{"Buy Deku Nut (5)", "Acheter: Noix Mojo (5)", "Comprar nueces deku (5)"}, ITEMTYPE_SHOP, 0x00, true, &Nuts, DEKU_NUTS_5, 15); + itemTable[BUY_ARROWS_30] = Item(Text{"Buy Arrows (30)", "Acheter: Flèches (30)", "Comprar flechas (30)"}, ITEMTYPE_SHOP, 0x01, true, &BuyArrow, ARROWS_30, 60); + itemTable[BUY_ARROWS_50] = Item(Text{"Buy Arrows (50)", "Acheter: Flèches (50)", "Comprar flechas (50)"}, ITEMTYPE_SHOP, 0x02, true, &BuyArrow, ARROWS_30, 90); + itemTable[BUY_BOMBS_525] = Item(Text{"Buy Bombs (5) [25]", "Acheter: Bombes (5) [25]", "Comprar bombas (5) [25]"}, ITEMTYPE_SHOP, 0x03, true, &BuyBomb, BOMBS_5, 25); + itemTable[BUY_DEKU_NUT_10] = Item(Text{"Buy Deku Nut (10)", "Acheter: Noix Mojo (10)", "Comprar Nueces deku (10)"}, ITEMTYPE_SHOP, 0x04, true, &Nuts, DEKU_NUTS_10, 30); + itemTable[BUY_DEKU_STICK_1] = Item(Text{"Buy Deku Stick (1)", "Acheter: Bâton Mojo (1)", "Comprar palos deku (1)"}, ITEMTYPE_SHOP, 0x05, true, &Sticks, DEKU_STICK_1, 10); + itemTable[BUY_BOMBS_10] = Item(Text{"Buy Bombs (10)", "Acheter: Bombes (10)", "Comprar Bombas (10)"}, ITEMTYPE_SHOP, 0x06, true, &BuyBomb, BOMBS_10, 50); + itemTable[BUY_FISH] = Item(Text{"Buy Fish", "Acheter: Poisson", "Comprar pez"}, ITEMTYPE_SHOP, 0x07, true, &FishAccess, BOTTLE_WITH_FISH, 200); + itemTable[BUY_RED_POTION_30] = Item(Text{"Buy Red Potion [30]", "Acheter: Potion Rouge [30]", "Comprar poción roja [30]"}, ITEMTYPE_SHOP, 0x08, false, &noVariable, BOTTLE_WITH_RED_POTION, 30); + itemTable[BUY_GREEN_POTION] = Item(Text{"Buy Green Potion", "Acheter: Potion Verte", "Comprar poción verde"}, ITEMTYPE_SHOP, 0x09, true, &BuyGPotion, BOTTLE_WITH_GREEN_POTION, 30); + itemTable[BUY_BLUE_POTION] = Item(Text{"Buy Blue Potion", "Acheter: Potion Bleue", "Comprar poción azul"}, ITEMTYPE_SHOP, 0x0A, true, &BuyBPotion, BOTTLE_WITH_BLUE_POTION, 100); + itemTable[BUY_HYLIAN_SHIELD] = Item(Text{"Buy Hylian Shield", "Acheter: Bouclier Hylien", "Comprar escudo hyliano"}, ITEMTYPE_SHOP, 0x0C, true, &HylianShield, HYLIAN_SHIELD, 80); + itemTable[BUY_DEKU_SHIELD] = Item(Text{"Buy Deku Shield", "Acheter: Bouclier Mojo", "Comprar escudo deku"}, ITEMTYPE_SHOP, 0x0D, true, &DekuShield, DEKU_SHIELD, 40); + itemTable[BUY_GORON_TUNIC] = Item(Text{"Buy Goron Tunic", "Acheter: Tunique Goron", "Comprar sayo goron"}, ITEMTYPE_SHOP, 0x0E, true, &GoronTunic, GORON_TUNIC, 200); + itemTable[BUY_ZORA_TUNIC] = Item(Text{"Buy Zora Tunic", "Acheter: Tunique Zora", "Comprar sayo zora"}, ITEMTYPE_SHOP, 0x0F, true, &ZoraTunic, ZORA_TUNIC, 300); + itemTable[BUY_HEART] = Item(Text{"Buy Heart", "Acheter: Coeur de Vie", "Comprar corazón"}, ITEMTYPE_SHOP, 0x10, false, &noVariable, RECOVERY_HEART, 10); + itemTable[BUY_BOMBCHU_10] = Item(Text{"Buy Bombchu (10)", "Acheter: Missiles (10)", "Comprar bombchus (10)"}, ITEMTYPE_SHOP, 0x15, true, &BuyBombchus10, BOMBCHU_10, 99); + itemTable[BUY_BOMBCHU_20] = Item(Text{"Buy Bombchu (20)", "Acheter: Missiles (20)", "Comprar bombchus (20)"}, ITEMTYPE_SHOP, 0x16, true, &BuyBombchus20, BOMBCHU_20, 180); + itemTable[BUY_BOMBCHU_5] = Item(Text{"Buy Bombchu (5)", "Acheter: Missiles (5)", "Comprar bombchus (5)"}, ITEMTYPE_SHOP, 0x18, true, &BuyBombchus5, BOMBCHU_5, 60); + itemTable[BUY_DEKU_SEEDS_30] = Item(Text{"Buy Deku Seeds (30)", "Acheter: Graines Mojo (30)", "Comprar semillas deku (30)"}, ITEMTYPE_SHOP, 0x1D, true, &BuySeed, DEKU_SEEDS_30, 30); + itemTable[SOLD_OUT] = Item(Text{"Sold Out", "Vendu", "Vendido"}, ITEMTYPE_SHOP, 0x26, false, &noVariable, NONE, 0); + itemTable[BUY_BLUE_FIRE] = Item(Text{"Buy Blue Fire", "Acheter: Flamme Bleue", "Comprar fuego azul"}, ITEMTYPE_SHOP, 0x27, true, &BlueFireAccess, BOTTLE_WITH_BLUE_FIRE, 300); + itemTable[BUY_BOTTLE_BUG] = Item(Text{"Buy Bottle Bug", "Acheter: Insecte en bouteille", "Comprar bichos"}, ITEMTYPE_SHOP, 0x28, true, &BugsAccess, BOTTLE_WITH_BUGS, 50); + itemTable[BUY_POE] = Item(Text{"Buy Poe", "Acheter: Esprit", "Comprar Poe"}, ITEMTYPE_SHOP, 0x2A, false, &noVariable, BOTTLE_WITH_BIG_POE, 30); + itemTable[BUY_FAIRYS_SPIRIT] = Item(Text{"Buy Fairy's Spirit", "Acheter: Esprit de Fée", "Comprar hada"}, ITEMTYPE_SHOP, 0x2B, true, &FairyAccess, BOTTLE_WITH_FAIRY, 50); + itemTable[BUY_ARROWS_10] = Item(Text{"Buy Arrows (10)", "Acheter: Flèches (10)", "Comprar flechas (10)"}, ITEMTYPE_SHOP, 0x2C, true, &BuyArrow, ARROWS_10, 20); + itemTable[BUY_BOMBS_20] = Item(Text{"Buy Bombs (20)", "Acheter: Bombes (20)", "Comprar bombas (20)"}, ITEMTYPE_SHOP, 0x2D, true, &BuyBomb, BOMBS_20, 80); + itemTable[BUY_BOMBS_30] = Item(Text{"Buy Bombs (30)", "Acheter: Bombes (30)", "Comprar bombas (30)"}, ITEMTYPE_SHOP, 0x2E, true, &BuyBomb, BOMBS_20, 120); + itemTable[BUY_BOMBS_535] = Item(Text{"Buy Bombs (5) [35]", "Acheter: Bombes (5) [35]", "Comprar bombas (5) [35]"}, ITEMTYPE_SHOP, 0x2F, true, &BuyBomb, BOMBS_5, 35); + itemTable[BUY_RED_POTION_40] = Item(Text{"Buy Red Potion [40]", "Acheter: Potion Rouge [40]", "Comprar poción roja [40]"}, ITEMTYPE_SHOP, 0x30, false, &noVariable, BOTTLE_WITH_RED_POTION, 40); + itemTable[BUY_RED_POTION_50] = Item(Text{"Buy Red Potion [50]", "Acheter: Potion Rouge [50]", "Comprar poción roja [50]"}, ITEMTYPE_SHOP, 0x31, false, &noVariable, BOTTLE_WITH_RED_POTION, 50); + + itemTable[TRIFORCE] = Item(Text{"Triforce", "Triforce", "Trifuerza"}, ITEMTYPE_EVENT, GI_RUPEE_RED_LOSE, false, &noVariable, NONE); + itemTable[HINT] = Item(Text{"Hint", "Indice", "Pista"}, ITEMTYPE_EVENT, GI_RUPEE_BLUE_LOSE, false, &noVariable, NONE); + +// itemTable[HOOKSHOT] = Item(Text{"Hookshot", "Grappin", "Gancho"}, ITEMTYPE_ITEM, 0x80, true, &ProgressiveHookshot, HOOKSHOT); +// itemTable[LONGSHOT] = Item(Text{"Longshot", "Super-Grappin", "Supergancho"}, ITEMTYPE_ITEM, 0x80, true, &ProgressiveHookshot, LONGSHOT); +// itemTable[FAIRY_OCARINA] = Item(Text{"Fairy Ocarina", "Ocarina des fées", "Ocarina de las Hadas"}, ITEMTYPE_ITEM, 0x8B, true, &ProgressiveOcarina, FAIRY_OCARINA); +// itemTable[OCARINA_OF_TIME] = Item(Text{"Ocarina of Time", "Ocarina du Temps", "Ocarina del Tiempo"}, ITEMTYPE_ITEM, 0x8B, true, &ProgressiveOcarina, OCARINA_OF_TIME); +// itemTable[BOMB_BAG] = Item(Text{"Bomb Bag", "Sac de Bombes", "Saco de bombas"}, ITEMTYPE_ITEM, 0x82, true, &ProgressiveBombBag, BOMB_BAG); +// itemTable[BIG_BOMB_BAG] = Item(Text{"Big Bomb Bag", "Grand Sac de Bombes", "Saco de bombas grande"}, ITEMTYPE_ITEM, 0x82, true, &ProgressiveBombBag, BIG_BOMB_BAG); +// itemTable[BIGGEST_BOMB_BAG] = Item(Text{"Biggest Bomb Bag", "Énorme Sac de Bombes", "Saco de bombas gigante"}, ITEMTYPE_ITEM, 0x82, true, &ProgressiveBombBag, BIGGEST_BOMB_BAG); +// itemTable[FAIRY_BOW] = Item(Text{"Fairy Bow", "Arc des Fées", "Arco de las Hadas"}, ITEMTYPE_ITEM, 0x83, true, &ProgressiveBow, FAIRY_BOW); +// itemTable[BIG_QUIVER] = Item(Text{"Big Quiver", "Grand carquois", "Carcaj grande"}, ITEMTYPE_ITEM, 0x83, true, &ProgressiveBow, BIG_QUIVER); +// itemTable[BIGGEST_QUIVER] = Item(Text{"Biggest Quiver", "Énorme carquois", "Carcaj gigante"}, ITEMTYPE_ITEM, 0x83, true, &ProgressiveBow, BIGGEST_QUIVER); +// itemTable[FAIRY_SLINGSHOT] = Item(Text{"Fairy Slingshot", "Lance-Pierre des Fées", "Resortera de las hadas"}, ITEMTYPE_ITEM, 0x84, true, &ProgressiveBulletBag, FAIRY_SLINGSHOT); +// itemTable[BIG_BULLET_BAG] = Item(Text{"Big Deku Seed Bullet Bag", "Grand sac de graines mojo", "Bolsa de semillas deku grande"}, ITEMTYPE_ITEM, 0x84, true, &ProgressiveBulletBag, BIG_BULLET_BAG); +// itemTable[BIGGEST_BULLET_BAD] = Item(Text{"Biggest Deku Seed Bullet Bag", "Énorme sac de graines mojo", "Bolsa de semillas deku gigante"}, ITEMTYPE_ITEM, 0x84, true, &ProgressiveBulletBag, BIGGEST_BULLET_BAD); +// itemTable[GORONS_BRACELET] = Item(Text{"Goron's Bracelet", "Bracelet Goron", "Brazalete de los Goron"}, ITEMTYPE_ITEM, 0x81, true, &ProgressiveStrength, GORONS_BRACELET); +// itemTable[SILVER_GAUNTLETS] = Item(Text{"Silver Gauntlets", "Gantelets d'argent", "Guantes de plata"}, ITEMTYPE_ITEM, 0x81, true, &ProgressiveStrength, SILVER_GAUNTLETS); +// itemTable[GOLDEN_GAUNTLETS] = Item(Text{"Golden Gauntlets", "Gantelets d'or", "Guantes de oro"}, ITEMTYPE_ITEM, 0x81, true, &ProgressiveStrength, GOLDEN_GAUNTLETS); +// itemTable[SILVER_SCALE] = Item(Text{"Silver Scale", "Écaille d'argent", "Escama de Plata"}, ITEMTYPE_ITEM, 0x86, true, &ProgressiveScale, SILVER_SCALE); +// itemTable[GOLDEN_SCALE] = Item(Text{"Golden Scale", "Écaille d'or", "Escama de Oro"}, ITEMTYPE_ITEM, 0x86, true, &ProgressiveScale, GOLDEN_SCALE); +// itemTable[ADULT_WALLET] = Item(Text{"Adult Wallet", "Bourse d'adulte", "Bolsa de adulto"}, ITEMTYPE_ITEM, 0x85, true, &ProgressiveWallet, ADULT_WALLET); +// itemTable[GIANT_WALLET] = Item(Text{"Giant Wallet", "Bourse de géant", "Bolsa gigante"}, ITEMTYPE_ITEM, 0x85, true, &ProgressiveWallet, GIANT_WALLET); +// itemTable[TYCOON_WALLET] = Item(Text{"Tycoon Wallet", "Bourse de star", "Bolsa de ricachón"}, ITEMTYPE_ITEM, 0x85, true, &ProgressiveWallet, TYCOON_WALLET); +// itemTable[DEKU_NUT_CAPACITY_30] = Item(Text{"Deku Nut Capacity (30)", "Capacité de noix Mojo (20)", "Capacidad de nueces deku (40)"}, ITEMTYPE_ITEM, 0x87, false, &noVariable, DEKU_NUT_CAPACITY_30); +// itemTable[DEKU_NUT_CAPACITY_40] = Item(Text{"Deku Nut Capacity (40)", "Capacité de noix Mojo (30)", "Capacidad de nueces deku (50)"}, ITEMTYPE_ITEM, 0x87, false, &noVariable, DEKU_NUT_CAPACITY_40); +// itemTable[DEKU_NUT_CAPACITY_20] = Item(Text{"Deku Stick Capacity (20)", "Capacité de Bâtons Mojo (20)", "Capacidad de palos deku (20)"}, ITEMTYPE_ITEM, 0x88, false, &noVariable, DEKU_NUT_CAPACITY_20); +// itemTable[DEKU_NUT_CAPACITY_30] = Item(Text{"Deku Nut Capacity (30)", "Capacité de noix Mojo (20)", "Capacidad de nueces deku (40)"}, ITEMTYPE_ITEM, 0x88, false, &noVariable, DEKU_NUT_CAPACITY_30); +// itemTable[MAGIC_METER] = Item(Text{"Magic Meter", "Jauge de Magie", "Poder mágico"}, ITEMTYPE_ITEM, 0x8A, true, &ProgressiveMagic, MAGIC_METER); +// itemTable[ENHANCED_MAGIC_METER] = Item(Text{"Enhanced Magic Meter", "Jauge de Magie améliorée", "Poder mágico mejorado"}, ITEMTYPE_ITEM, 0x8A, true, &ProgressiveMagic, ENHANCED_MAGIC_METER); + +} + +Item& ItemTable(const uint32_t itemKey) { + return itemTable[itemKey]; +} + +//This function should only be used to place items containing hint text +//at gossip stone locations. +void NewItem(const uint32_t itemKey, const Item item) { + if (itemKey <= BUY_RED_POTION_50) { + printf("\x1b[25;0HWARNING: ATTEMPTED TO OVERWRITE ITEM %lu\n", itemKey); + return; + } + + itemTable[itemKey] = item; +} diff --git a/soh/soh/Enhancements/randomizer/3drando/item_list.hpp b/soh/soh/Enhancements/randomizer/3drando/item_list.hpp new file mode 100644 index 000000000..c1244c3ce --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/item_list.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "item.hpp" +#include "keys.hpp" + +void ItemTable_Init(); +Item& ItemTable(uint32_t itemKey); +void NewItem(uint32_t itemKey, Item item); diff --git a/soh/soh/Enhancements/randomizer/3drando/item_location.cpp b/soh/soh/Enhancements/randomizer/3drando/item_location.cpp new file mode 100644 index 000000000..18e5e8acf --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/item_location.cpp @@ -0,0 +1,1580 @@ +#include "item_location.hpp" + +#include "dungeon.hpp" +#include "settings.hpp" +#include "spoiler_log.hpp" +#include "shops.hpp" +#include "debug.hpp" +#include "keys.hpp" +#include + +//Location definitions +static std::array locationTable; + +void LocationTable_Init() { + locationTable[NONE] = ItemLocation::Base (0xFF, 0xFF, "Invalid Location", NONE, NONE, {}, SpoilerCollectionCheck::None()); + //Kokiri Forest scene flag name hint key (hint_list.cpp) vanilla item categories collection check (if needed) collection check group + locationTable[KF_KOKIRI_SWORD_CHEST] = ItemLocation::Chest (0x55, 0x00, "KF Kokiri Sword Chest", KF_KOKIRI_SWORD_CHEST, KOKIRI_SWORD, {Category::cKokiriForest, Category::cForest,}, SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + locationTable[KF_MIDOS_TOP_LEFT_CHEST] = ItemLocation::Chest (0x28, 0x00, "KF Mido Top Left Chest", KF_MIDOS_TOP_LEFT_CHEST, BLUE_RUPEE, {Category::cKokiriForest, Category::cForest,}, SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + locationTable[KF_MIDOS_TOP_RIGHT_CHEST] = ItemLocation::Chest (0x28, 0x01, "KF Mido Top Right Chest", KF_MIDOS_TOP_RIGHT_CHEST, BLUE_RUPEE, {Category::cKokiriForest, Category::cForest,}, SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + locationTable[KF_MIDOS_BOTTOM_LEFT_CHEST] = ItemLocation::Chest (0x28, 0x02, "KF Mido Bottom Left Chest", KF_MIDOS_BOTTOM_LEFT_CHEST, GREEN_RUPEE, {Category::cKokiriForest, Category::cForest,}, SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + locationTable[KF_MIDOS_BOTTOM_RIGHT_CHEST] = ItemLocation::Chest (0x28, 0x03, "KF Mido Bottom Right Chest", KF_MIDOS_BOTTOM_RIGHT_CHEST, RECOVERY_HEART, {Category::cKokiriForest, Category::cForest,}, SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + locationTable[KF_STORMS_GROTTO_CHEST] = ItemLocation::Chest (0x3E, 0x0C, "KF Storms Grotto Chest", KF_STORMS_GROTTO_CHEST, RED_RUPEE, {Category::cKokiriForest, Category::cForest, Category::cGrotto}, SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + + //Lost Woods + locationTable[LW_NEAR_SHORTCUTS_GROTTO_CHEST] = ItemLocation::Chest (0x3E, 0x14, "LW Near Shortcuts Grotto Chest", LW_NEAR_SHORTCUTS_GROTTO_CHEST, BLUE_RUPEE, {Category::cLostWoods, Category::cForest, Category::cGrotto}, SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[LW_SKULL_KID] = ItemLocation::Base (0x5B, 0x3E, "LW Skull Kid", LW_SKULL_KID, PIECE_OF_HEART, {Category::cLostWoods, Category::cForest,}, SpoilerCollectionCheck::ItemGetInf(30), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[LW_TRADE_COJIRO] = ItemLocation::Base (0x5B, 0x1F, "LW Trade Cojiro", LW_TRADE_COJIRO, ODD_MUSHROOM, {Category::cLostWoods, Category::cForest, Category::cAdultTrade}, SpoilerCollectionCheck::ItemGetInf(37), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[LW_TRADE_ODD_POTION] = ItemLocation::Base (0x5B, 0x21, "LW Trade Odd Potion", LW_TRADE_ODD_POTION, ODD_POTION, {Category::cLostWoods, Category::cForest, Category::cAdultTrade}, SpoilerCollectionCheck::ItemGetInf(57), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[LW_OCARINA_MEMORY_GAME] = ItemLocation::Base (0x5B, 0x76, "LW Ocarina Memory Game", LW_OCARINA_MEMORY_GAME, PIECE_OF_HEART, {Category::cLostWoods, Category::cForest, Category::cMinigame}, SpoilerCollectionCheck::ItemGetInf(31), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[LW_TARGET_IN_WOODS] = ItemLocation::Base (0x5B, 0x60, "LW Target in Woods", LW_TARGET_IN_WOODS, PROGRESSIVE_SLINGSHOT, {Category::cLostWoods, Category::cForest,}, SpoilerCollectionCheck::ItemGetInf(21), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT] = ItemLocation::Base (0x5B, 0x30, "LW Deku Scrub Near Deku Theater Right",LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT, BUY_DEKU_NUT_5, {Category::cLostWoods, Category::cForest, Category::cDekuScrub}, SpoilerCollectionCheck::Scrub(0x5B, 0x01), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT] = ItemLocation::Base (0x5B, 0x31, "LW Deku Scrub Near Deku Theater Left", LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, BUY_DEKU_STICK_1, {Category::cLostWoods, Category::cForest, Category::cDekuScrub}, SpoilerCollectionCheck::Scrub(0x5B, 0x02), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[LW_DEKU_SCRUB_NEAR_BRIDGE] = ItemLocation::Base (0x5B, 0x77, "LW Deku Scrub Near Bridge", LW_DEKU_SCRUB_NEAR_BRIDGE, PROGRESSIVE_STICK_UPGRADE, {Category::cLostWoods, Category::cForest, Category::cDekuScrub, Category::cDekuScrubUpgrades}, SpoilerCollectionCheck::Scrub(0x5B, 0x0A), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[LW_DEKU_SCRUB_GROTTO_REAR] = ItemLocation::GrottoScrub(0xF5, 0x33, "LW Deku Scrub Grotto Rear", LW_DEKU_SCRUB_GROTTO_REAR, BUY_DEKU_SEEDS_30, {Category::cLostWoods, Category::cForest, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x1F, 0x04), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[LW_DEKU_SCRUB_GROTTO_FRONT] = ItemLocation::GrottoScrub(0xF5, 0x79, "LW Deku Scrub Grotto Front", LW_DEKU_SCRUB_GROTTO_FRONT, PROGRESSIVE_NUT_UPGRADE, {Category::cLostWoods, Category::cForest, Category::cDekuScrub, Category::cDekuScrubUpgrades, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x1F, 0x0B), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[DEKU_THEATER_SKULL_MASK] = ItemLocation::Base (0x3E, 0x77, "Deku Theater Skull Mask", DEKU_THEATER_SKULL_MASK, PROGRESSIVE_STICK_UPGRADE, {Category::cLostWoods, Category::cForest, Category::cGrotto}, SpoilerCollectionCheck::ItemGetInf(22), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[DEKU_THEATER_MASK_OF_TRUTH] = ItemLocation::Base (0x3E, 0x7A, "Deku Theater Mask of Truth", DEKU_THEATER_MASK_OF_TRUTH, PROGRESSIVE_NUT_UPGRADE, {Category::cLostWoods, Category::cForest, Category::cNeedSpiritualStones, Category::cGrotto}, SpoilerCollectionCheck::ItemGetInf(23), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + + //Sacred Forest Meadow + locationTable[SFM_WOLFOS_GROTTO_CHEST] = ItemLocation::Chest (0x3E, 0x11, "SFM Wolfos Grotto Chest", SFM_WOLFOS_GROTTO_CHEST, PURPLE_RUPEE, {Category::cSacredForestMeadow, Category::cForest, Category::cGrotto}, SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[SFM_DEKU_SCRUB_GROTTO_REAR] = ItemLocation::GrottoScrub(0xEE, 0x39, "SFM Deku Scrub Grotto Rear", SFM_DEKU_SCRUB_GROTTO_REAR, BUY_RED_POTION_30, {Category::cSacredForestMeadow, Category::cForest, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x18, 0x08), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[SFM_DEKU_SCRUB_GROTTO_FRONT] = ItemLocation::GrottoScrub(0xEE, 0x3A, "SFM Deku Scrub Grotto Front", SFM_DEKU_SCRUB_GROTTO_FRONT, BUY_GREEN_POTION, {Category::cSacredForestMeadow, Category::cForest, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x18, 0x09), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + + //Hyrule Field + locationTable[HF_SOUTHEAST_GROTTO_CHEST] = ItemLocation::Chest (0x3E, 0x02, "HF Southeast Grotto Chest", HF_SOUTHEAST_GROTTO_CHEST, RED_RUPEE, {Category::cHyruleField, Category::cGrotto,}, SpoilerCollectionCheckGroup::GROUP_HYRULE_FIELD); + locationTable[HF_OPEN_GROTTO_CHEST] = ItemLocation::Chest (0x3E, 0x03, "HF Open Grotto Chest", HF_OPEN_GROTTO_CHEST, BLUE_RUPEE, {Category::cHyruleField, Category::cGrotto,}, SpoilerCollectionCheckGroup::GROUP_HYRULE_FIELD); + locationTable[HF_NEAR_MARKET_GROTTO_CHEST] = ItemLocation::Chest (0x3E, 0x00, "HF Near Market Grotto Chest", HF_NEAR_MARKET_GROTTO_CHEST, BLUE_RUPEE, {Category::cHyruleField, Category::cGrotto,}, SpoilerCollectionCheckGroup::GROUP_HYRULE_FIELD); + locationTable[HF_OCARINA_OF_TIME_ITEM] = ItemLocation::Base (0x51, 0x0C, "HF Ocarina of Time Item", HF_OCARINA_OF_TIME_ITEM, PROGRESSIVE_OCARINA, {Category::cHyruleField, Category::cNeedSpiritualStones,}, SpoilerCollectionCheck::EventChkInf(0x43), SpoilerCollectionCheckGroup::GROUP_HYRULE_FIELD); + locationTable[HF_TEKTITE_GROTTO_FREESTANDING_POH] = ItemLocation::Collectable(0x3E, 0x01, "HF Tektite Grotto Freestanding PoH", HF_TEKTITE_GROTTO_FREESTANDING_POH, PIECE_OF_HEART, {Category::cHyruleField, Category::cGrotto,}, SpoilerCollectionCheckGroup::GROUP_HYRULE_FIELD); + locationTable[HF_DEKU_SCRUB_GROTTO] = ItemLocation::GrottoScrub(0xE6, 0x3E, "HF Deku Scrub Grotto", HF_DEKU_SCRUB_GROTTO, PIECE_OF_HEART, {Category::cHyruleField, Category::cDekuScrub, Category::cDekuScrubUpgrades, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x10, 0x03), SpoilerCollectionCheckGroup::GROUP_HYRULE_FIELD); + + //Lake Hylia + locationTable[LH_CHILD_FISHING] = ItemLocation::Base (0x49, 0x3E, "LH Child Fishing", LH_CHILD_FISHING, PIECE_OF_HEART, {Category::cLakeHylia, Category::cMinigame,}, SpoilerCollectionCheck::Fishing(0x02), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); + locationTable[LH_ADULT_FISHING] = ItemLocation::Base (0x49, 0x38, "LH Adult Fishing", LH_ADULT_FISHING, PROGRESSIVE_SCALE, {Category::cLakeHylia, Category::cMinigame,}, SpoilerCollectionCheck::Fishing(0x03), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); + locationTable[LH_LAB_DIVE] = ItemLocation::Base (0x38, 0x3E, "LH Lab Dive", LH_LAB_DIVE, PIECE_OF_HEART, {Category::cLakeHylia,}, SpoilerCollectionCheck::ItemGetInf(24), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); + locationTable[LH_TRADE_FROG] = ItemLocation::Base (0x38, 0x25, "LH Lab Trade Eyeball Frog", LH_TRADE_FROG, EYEDROPS, {Category::cLakeHylia, Category::cAdultTrade}, SpoilerCollectionCheck::ItemGetInf(61), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); + locationTable[LH_UNDERWATER_ITEM] = ItemLocation::Base (0x57, 0x15, "LH Underwater Item", LH_UNDERWATER_ITEM, RUTOS_LETTER, {Category::cLakeHylia,}, SpoilerCollectionCheck::EventChkInf(0x31), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); + locationTable[LH_SUN] = ItemLocation::Base (0x57, 0x58, "LH Sun", LH_SUN, FIRE_ARROWS, {Category::cLakeHylia,}, SpoilerCollectionCheck::Chest(0x57, 0x00), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); + locationTable[LH_FREESTANDING_POH] = ItemLocation::Collectable(0x57, 0x1E, "LH Freestanding PoH", LH_FREESTANDING_POH, PIECE_OF_HEART, {Category::cLakeHylia,}, SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); + locationTable[LH_DEKU_SCRUB_GROTTO_LEFT] = ItemLocation::GrottoScrub(0xEF, 0x30, "LH Deku Scrub Grotto Left", LH_DEKU_SCRUB_GROTTO_LEFT, BUY_DEKU_NUT_5, {Category::cLakeHylia, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x19, 0x01), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); + locationTable[LH_DEKU_SCRUB_GROTTO_RIGHT] = ItemLocation::GrottoScrub(0xEF, 0x37, "LH Deku Scrub Grotto Right", LH_DEKU_SCRUB_GROTTO_RIGHT, BUY_BOMBS_535, {Category::cLakeHylia, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x19, 0x06), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); + locationTable[LH_DEKU_SCRUB_GROTTO_CENTER] = ItemLocation::GrottoScrub(0xEF, 0x33, "LH Deku Scrub Grotto Center", LH_DEKU_SCRUB_GROTTO_CENTER, BUY_DEKU_SEEDS_30, {Category::cLakeHylia, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x19, 0x04), SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); + + //Gerudo Valley + locationTable[GV_CHEST] = ItemLocation::Chest (0x5A, 0x00, "GV Chest", GV_CHEST, PURPLE_RUPEE, {Category::cGerudoValley, Category::cGerudo,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GV_TRADE_SAW] = ItemLocation::Base (0x5A, 0x22, "GV Trade Saw", GV_TRADE_SAW, BROKEN_SWORD, {Category::cGerudoValley, Category::cGerudo, Category::cAdultTrade}, SpoilerCollectionCheck::ItemGetInf(58), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GV_WATERFALL_FREESTANDING_POH] = ItemLocation::Collectable(0x5A, 0x01, "GV Waterfall Freestanding PoH", GV_WATERFALL_FREESTANDING_POH, PIECE_OF_HEART, {Category::cGerudoValley, Category::cGerudo,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GV_CRATE_FREESTANDING_POH] = ItemLocation::Collectable(0x5A, 0x02, "GV Crate Freestanding PoH", GV_CRATE_FREESTANDING_POH, PIECE_OF_HEART, {Category::cGerudoValley, Category::cGerudo,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GV_DEKU_SCRUB_GROTTO_REAR] = ItemLocation::GrottoScrub(0xF0, 0x39, "GV Deku Scrub Grotto Rear", GV_DEKU_SCRUB_GROTTO_REAR, BUY_RED_POTION_30, {Category::cGerudoValley, Category::cGerudo, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x1A, 0x08), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GV_DEKU_SCRUB_GROTTO_FRONT] = ItemLocation::GrottoScrub(0xF0, 0x3A, "GV Deku Scrub Grotto Front", GV_DEKU_SCRUB_GROTTO_FRONT, BUY_GREEN_POTION, {Category::cGerudoValley, Category::cGerudo, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x1A, 0x09), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + + //Gerudo Fortress + locationTable[GF_CHEST] = ItemLocation::Chest (0x5D, 0x00, "GF Chest", GF_CHEST, PIECE_OF_HEART, {Category::cGerudoFortress, Category::cGerudo,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GF_HBA_1000_POINTS] = ItemLocation::Base (0x5D, 0x3E, "GF HBA 1000 Points", GF_HBA_1000_POINTS, PIECE_OF_HEART, {Category::cGerudoFortress, Category::cGerudo, Category::cMinigame}, SpoilerCollectionCheck::InfTable(0x19, 0x08), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GF_HBA_1500_POINTS] = ItemLocation::Base (0x5D, 0x30, "GF HBA 1500 Points", GF_HBA_1500_POINTS, PROGRESSIVE_BOW, {Category::cGerudoFortress, Category::cGerudo, Category::cMinigame}, SpoilerCollectionCheck::ItemGetInf(7), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GF_GERUDO_MEMBERSHIP_CARD] = ItemLocation::Base (0x0C, 0x3A, "GF Gerudo Membership Card", GF_GERUDO_MEMBERSHIP_CARD, GERUDO_MEMBERSHIP_CARD, {Category::cGerudoFortress, Category::cGerudo,}, SpoilerCollectionCheck::GerudoToken(), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GF_NORTH_F1_CARPENTER] = ItemLocation::Collectable(0x0C, 0x0C, "GF North F1 Carpenter", GF_NORTH_F1_CARPENTER, GERUDO_FORTRESS_SMALL_KEY, {Category::cGerudoFortress, Category::cGerudo, Category::cVanillaGFSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GF_NORTH_F2_CARPENTER] = ItemLocation::Collectable(0x0C, 0x0A, "GF North F2 Carpenter", GF_NORTH_F2_CARPENTER, GERUDO_FORTRESS_SMALL_KEY, {Category::cGerudoFortress, Category::cGerudo, Category::cVanillaGFSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GF_SOUTH_F1_CARPENTER] = ItemLocation::Collectable(0x0C, 0x0E, "GF South F1 Carpenter", GF_SOUTH_F1_CARPENTER, GERUDO_FORTRESS_SMALL_KEY, {Category::cGerudoFortress, Category::cGerudo, Category::cVanillaGFSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GF_SOUTH_F2_CARPENTER] = ItemLocation::Collectable(0x0C, 0x0F, "GF South F2 Carpenter", GF_SOUTH_F2_CARPENTER, GERUDO_FORTRESS_SMALL_KEY, {Category::cGerudoFortress, Category::cGerudo, Category::cVanillaGFSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + + //Haunted Wasteland + locationTable[WASTELAND_CHEST] = ItemLocation::Chest (0x5E, 0x00, "Wasteland Chest", WASTELAND_CHEST, PURPLE_RUPEE, {Category::cHauntedWasteland,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[WASTELAND_BOMBCHU_SALESMAN] = ItemLocation::Base (0x5E, 0x03, "Wasteland Carpet Salesman", WASTELAND_BOMBCHU_SALESMAN, BOMBCHU_10, {Category::cHauntedWasteland, Category::cMerchant,}, SpoilerCollectionCheck::EventChkInf(0x34), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + + //Desert Colossus + locationTable[COLOSSUS_FREESTANDING_POH] = ItemLocation::Collectable(0x5C, 0x0D, "Colossus Freestanding PoH", COLOSSUS_FREESTANDING_POH, PIECE_OF_HEART, {Category::cDesertColossus,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[COLOSSUS_DEKU_SCRUB_GROTTO_REAR] = ItemLocation::GrottoScrub(0xFD, 0x39, "Colossus Deku Scrub Grotto Rear", COLOSSUS_DEKU_SCRUB_GROTTO_REAR, BUY_RED_POTION_30, {Category::cDesertColossus, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x27, 0x08), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[COLOSSUS_DEKU_SCRUB_GROTTO_FRONT] = ItemLocation::GrottoScrub(0xFD, 0x3A, "Colossus Deku Scrub Grotto Front", COLOSSUS_DEKU_SCRUB_GROTTO_FRONT, BUY_GREEN_POTION, {Category::cDesertColossus, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x27, 0x09), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + + //Market + locationTable[MARKET_TREASURE_CHEST_GAME_REWARD] = ItemLocation::Chest (0x10, 0x0A, "MK Treasure Chest Game Reward", MARKET_TREASURE_CHEST_GAME_REWARD, TREASURE_GAME_HEART, {Category::cInnerMarket, Category::cMarket, Category::cMinigame}, SpoilerCollectionCheck::ItemGetInf(19), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BOMBCHU_BOWLING_FIRST_PRIZE] = ItemLocation::Base (0x4B, 0x33, "MK Bombchu Bowling First Prize", MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, PROGRESSIVE_BOMB_BAG, {Category::cInnerMarket, Category::cMarket, Category::cMinigame}, SpoilerCollectionCheck::ItemGetInf(25), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BOMBCHU_BOWLING_SECOND_PRIZE] = ItemLocation::Base (0x4B, 0x3E, "MK Bombchu Bowling Second Prize", MARKET_BOMBCHU_BOWLING_SECOND_PRIZE, PIECE_OF_HEART, {Category::cInnerMarket, Category::cMarket, Category::cMinigame}, SpoilerCollectionCheck::ItemGetInf(26), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BOMBCHU_BOWLING_BOMBCHUS] = ItemLocation::Base (0x4B, 0xFF, "MK Bombchu Bowling Bombchus", NONE, BOMBCHU_DROP, {Category::cInnerMarket, Category::cMarket, Category::cMinigame}, SpoilerCollectionCheck::None(), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_LOST_DOG] = ItemLocation::Base (0x35, 0x3E, "MK Lost Dog", MARKET_LOST_DOG, PIECE_OF_HEART, {Category::cInnerMarket, Category::cMarket,}, SpoilerCollectionCheck::InfTable(0x19, 0x09), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_SHOOTING_GALLERY_REWARD] = ItemLocation::Base (0x42, 0x60, "MK Shooting Gallery", MARKET_SHOOTING_GALLERY_REWARD, PROGRESSIVE_SLINGSHOT, {Category::cInnerMarket, Category::cMarket, Category::cMinigame}, SpoilerCollectionCheck::ItemGetInf(5), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_10_BIG_POES] = ItemLocation::Base (0x4D, 0x0F, "MK 10 Big Poes", MARKET_10_BIG_POES, EMPTY_BOTTLE, {Category::cInnerMarket, Category::cMarket,}, SpoilerCollectionCheck::BigPoePoints(), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_TREASURE_CHEST_GAME_ITEM_1] = ItemLocation::Chest (0x10, 0x01, "MK Chest Game First Room Chest", MARKET_TREASURE_CHEST_GAME_ITEM_1, TREASURE_GAME_SMALL_KEY, {Category::cInnerMarket, Category::cMarket, Category::cMinigame, Category::cChestMinigame}, SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_TREASURE_CHEST_GAME_ITEM_2] = ItemLocation::Chest (0x10, 0x03, "MK Chest Game Second Room Chest", MARKET_TREASURE_CHEST_GAME_ITEM_2, TREASURE_GAME_SMALL_KEY, {Category::cInnerMarket, Category::cMarket, Category::cMinigame, Category::cChestMinigame}, SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_TREASURE_CHEST_GAME_ITEM_3] = ItemLocation::Chest (0x10, 0x05, "MK Chest Game Third Room Chest", MARKET_TREASURE_CHEST_GAME_ITEM_3, TREASURE_GAME_SMALL_KEY, {Category::cInnerMarket, Category::cMarket, Category::cMinigame, Category::cChestMinigame}, SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_TREASURE_CHEST_GAME_ITEM_4] = ItemLocation::Chest (0x10, 0x07, "MK Chest Game Fourth Room Chest", MARKET_TREASURE_CHEST_GAME_ITEM_4, TREASURE_GAME_SMALL_KEY, {Category::cInnerMarket, Category::cMarket, Category::cMinigame, Category::cChestMinigame}, SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_TREASURE_CHEST_GAME_ITEM_5] = ItemLocation::Chest (0x10, 0x09, "MK Chest Game Fifth Room Chest", MARKET_TREASURE_CHEST_GAME_ITEM_5, TREASURE_GAME_SMALL_KEY, {Category::cInnerMarket, Category::cMarket, Category::cMinigame, Category::cChestMinigame}, SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + + //Hyrule Castle + locationTable[HC_MALON_EGG] = ItemLocation::Base (0x5F, 0x47, "HC Malon Egg", HC_MALON_EGG, WEIRD_EGG, {Category::cHyruleCastle, Category::cMarket,}, SpoilerCollectionCheck::EventChkInf(0x12), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[HC_ZELDAS_LETTER] = ItemLocation::Base (0x4A, 0x0B, "HC Zeldas Letter", HC_ZELDAS_LETTER, ZELDAS_LETTER, {Category::cHyruleCastle, Category::cMarket,}, SpoilerCollectionCheck::EventChkInf(0x40), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + + //Kakariko + locationTable[KAK_REDEAD_GROTTO_CHEST] = ItemLocation::Chest (0x3E, 0x0A, "Kak Redead Grotto Chest", KAK_REDEAD_GROTTO_CHEST, HUGE_RUPEE, {Category::cKakarikoVillage, Category::cKakariko, Category::cGrotto}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_OPEN_GROTTO_CHEST] = ItemLocation::Chest (0x3E, 0x08, "Kak Open Grotto Chest", KAK_OPEN_GROTTO_CHEST, RED_RUPEE, {Category::cKakarikoVillage, Category::cKakariko, Category::cGrotto}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_10_GOLD_SKULLTULA_REWARD] = ItemLocation::Base (0x50, 0x45, "Kak 10 Gold Skulltula Reward", KAK_10_GOLD_SKULLTULA_REWARD, PROGRESSIVE_WALLET, {Category::cKakarikoVillage, Category::cKakariko, Category::cSkulltulaHouse}, SpoilerCollectionCheck::EventChkInf(0xDA), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_20_GOLD_SKULLTULA_REWARD] = ItemLocation::Base (0x50, 0x39, "Kak 20 Gold Skulltula Reward", KAK_20_GOLD_SKULLTULA_REWARD, STONE_OF_AGONY, {Category::cKakarikoVillage, Category::cKakariko, Category::cSkulltulaHouse}, SpoilerCollectionCheck::EventChkInf(0xDB), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_30_GOLD_SKULLTULA_REWARD] = ItemLocation::Base (0x50, 0x46, "Kak 30 Gold Skulltula Reward", KAK_30_GOLD_SKULLTULA_REWARD, PROGRESSIVE_WALLET, {Category::cKakarikoVillage, Category::cKakariko, Category::cSkulltulaHouse}, SpoilerCollectionCheck::EventChkInf(0xDC), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_40_GOLD_SKULLTULA_REWARD] = ItemLocation::Base (0x50, 0x03, "Kak 40 Gold Skulltula Reward", KAK_40_GOLD_SKULLTULA_REWARD, BOMBCHU_10, {Category::cKakarikoVillage, Category::cKakariko, Category::cSkulltulaHouse}, SpoilerCollectionCheck::EventChkInf(0xDD), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_50_GOLD_SKULLTULA_REWARD] = ItemLocation::Base (0x50, 0x3E, "Kak 50 Gold Skulltula Reward", KAK_50_GOLD_SKULLTULA_REWARD, PIECE_OF_HEART, {Category::cKakarikoVillage, Category::cKakariko, Category::cSkulltulaHouse}, SpoilerCollectionCheck::EventChkInf(0xDE), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_MAN_ON_ROOF] = ItemLocation::Base (0x52, 0x3E, "Kak Man on Roof", KAK_MAN_ON_ROOF, PIECE_OF_HEART, {Category::cKakarikoVillage, Category::cKakariko,}, SpoilerCollectionCheck::ItemGetInf(29), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_SHOOTING_GALLERY_REWARD] = ItemLocation::Base (0x42, 0x30, "Kak Shooting Gallery Reward", KAK_SHOOTING_GALLERY_REWARD, PROGRESSIVE_BOW, {Category::cKakarikoVillage, Category::cKakariko, Category::cMinigame}, SpoilerCollectionCheck::ItemGetInf(6), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_TRADE_ODD_MUSHROOM] = ItemLocation::Base (0x4E, 0x20, "Kak Trade Odd Mushroom", KAK_TRADE_ODD_MUSHROOM, ODD_POTION, {Category::cKakarikoVillage, Category::cKakariko, Category::cAdultTrade}, SpoilerCollectionCheck::ItemGetInf(56), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_ANJU_AS_ADULT] = ItemLocation::Base (0x52, 0x1D, "Kak Anju as Adult", KAK_ANJU_AS_ADULT, CLAIM_CHECK, {Category::cKakarikoVillage, Category::cKakariko,}, SpoilerCollectionCheck::ItemGetInf(36), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_ANJU_AS_CHILD] = ItemLocation::Base (0x52, 0x0F, "Kak Anju as Child", KAK_ANJU_AS_CHILD, EMPTY_BOTTLE, {Category::cKakarikoVillage, Category::cKakariko, Category::cMinigame}, SpoilerCollectionCheck::ItemGetInf(4), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_TRADE_POCKET_CUCCO] = ItemLocation::Base (0x52, 0x0E, "Kak Trade Pocket Cucco", KAK_TRADE_POCKET_CUCCO, COJIRO, {Category::cKakarikoVillage, Category::cKakariko, Category::cAdultTrade}, SpoilerCollectionCheck::ItemGetInf(38), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_IMPAS_HOUSE_FREESTANDING_POH] = ItemLocation::Collectable(0x37, 0x01, "Kak Impas House Freestanding PoH", KAK_IMPAS_HOUSE_FREESTANDING_POH, PIECE_OF_HEART, {Category::cKakarikoVillage, Category::cKakariko,}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_WINDMILL_FREESTANDING_POH] = ItemLocation::Collectable(0x48, 0x01, "Kak Windmill Freestanding PoH", KAK_WINDMILL_FREESTANDING_POH, PIECE_OF_HEART, {Category::cKakarikoVillage, Category::cKakariko,}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + + //Graveyard + locationTable[GRAVEYARD_SHIELD_GRAVE_CHEST] = ItemLocation::Chest (0x40, 0x00, "GY Shield Grave Chest", GRAVEYARD_SHIELD_GRAVE_CHEST, HYLIAN_SHIELD, {Category::cGraveyard, Category::cKakariko,}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[GRAVEYARD_HEART_PIECE_GRAVE_CHEST] = ItemLocation::Chest (0x3F, 0x00, "GY Heart Piece Grave Chest", GRAVEYARD_HEART_PIECE_GRAVE_CHEST, PIECE_OF_HEART, {Category::cGraveyard, Category::cKakariko,}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[GRAVEYARD_COMPOSERS_GRAVE_CHEST] = ItemLocation::Chest (0x41, 0x00, "GY Composers Grave Chest", GRAVEYARD_COMPOSERS_GRAVE_CHEST, BOMBS_5, {Category::cGraveyard, Category::cKakariko,}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[GRAVEYARD_HOOKSHOT_CHEST] = ItemLocation::Chest (0x48, 0x00, "GY Hookshot Chest", GRAVEYARD_HOOKSHOT_CHEST, PROGRESSIVE_HOOKSHOT, {Category::cGraveyard, Category::cKakariko,}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[GRAVEYARD_DAMPE_RACE_FREESTANDING_POH] = ItemLocation::Collectable(0x48, 0x07, "GY Dampe Race Freestanding PoH", GRAVEYARD_DAMPE_RACE_FREESTANDING_POH, PIECE_OF_HEART, {Category::cGraveyard, Category::cKakariko, Category::cMinigame}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[GRAVEYARD_FREESTANDING_POH] = ItemLocation::Collectable(0x53, 0x04, "GY Freestanding PoH", GRAVEYARD_FREESTANDING_POH, PIECE_OF_HEART, {Category::cGraveyard, Category::cKakariko,}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR] = ItemLocation::Collectable(0x53, 0x08, "GY Dampe Gravedigging Tour", GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR, PIECE_OF_HEART, {Category::cGraveyard, Category::cKakariko,}, SpoilerCollectionCheck::ItemGetInf(20), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + + //Death Mountain + locationTable[DMT_CHEST] = ItemLocation::Chest (0x60, 0x01, "DMT Chest", DMT_CHEST, PURPLE_RUPEE, {Category::cDeathMountainTrail, Category::cDeathMountain,}, SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[DMT_STORMS_GROTTO_CHEST] = ItemLocation::Chest (0x3E, 0x17, "DMT Storms Grotto Chest", DMT_STORMS_GROTTO_CHEST, HUGE_RUPEE, {Category::cDeathMountainTrail, Category::cDeathMountain, Category::cGrotto}, SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[DMT_TRADE_BROKEN_SWORD] = ItemLocation::Base (0x60, 0x23, "DMT Trade Broken Sword", DMT_TRADE_BROKEN_SWORD, PRESCRIPTION, {Category::cDeathMountainTrail, Category::cDeathMountain, Category::cAdultTrade}, SpoilerCollectionCheck::Biggoron(0x4), SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[DMT_TRADE_EYEDROPS] = ItemLocation::Base (0x60, 0x26, "DMT Trade Eyedrops", DMT_TRADE_EYEDROPS, CLAIM_CHECK, {Category::cDeathMountainTrail, Category::cDeathMountain, Category::cAdultTrade}, SpoilerCollectionCheck::Biggoron(0x2), SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[DMT_TRADE_CLAIM_CHECK] = ItemLocation::Base (0x60, 0x57, "DMT Trade Claim Check", DMT_TRADE_CLAIM_CHECK, BIGGORON_SWORD, {Category::cDeathMountainTrail, Category::cDeathMountain}, SpoilerCollectionCheck::Biggoron(0x1), SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[DMT_FREESTANDING_POH] = ItemLocation::Collectable(0x60, 0x1E, "DMT Freestanding PoH", DMT_FREESTANDING_POH, PIECE_OF_HEART, {Category::cDeathMountainTrail, Category::cDeathMountain,}, SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + + //Goron City + locationTable[GC_MAZE_LEFT_CHEST] = ItemLocation::Chest (0x62, 0x00, "GC Maze Left Chest", GC_MAZE_LEFT_CHEST, HUGE_RUPEE, {Category::cGoronCity,}, SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_MAZE_RIGHT_CHEST] = ItemLocation::Chest (0x62, 0x01, "GC Maze Right Chest", GC_MAZE_RIGHT_CHEST, PURPLE_RUPEE, {Category::cGoronCity,}, SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_MAZE_CENTER_CHEST] = ItemLocation::Chest (0x62, 0x02, "GC Maze Center Chest", GC_MAZE_CENTER_CHEST, PURPLE_RUPEE, {Category::cGoronCity,}, SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_ROLLING_GORON_AS_CHILD] = ItemLocation::Base (0x62, 0x34, "GC Rolling Goron as Child", GC_ROLLING_GORON_AS_CHILD, PROGRESSIVE_BOMB_BAG, {Category::cGoronCity,}, SpoilerCollectionCheck::InfTable(0x11, 0x06), SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_ROLLING_GORON_AS_ADULT] = ItemLocation::Base (0x62, 0x2C, "GC Rolling Goron as Adult", GC_ROLLING_GORON_AS_ADULT, GORON_TUNIC, {Category::cGoronCity,}, SpoilerCollectionCheck::InfTable(0x10, 0x01), SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_DARUNIAS_JOY] = ItemLocation::Base (0x62, 0x54, "GC Darunias Joy", GC_DARUNIAS_JOY, PROGRESSIVE_STRENGTH, {Category::cGoronCity,}, SpoilerCollectionCheck::EventChkInf(0x36), SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_POT_FREESTANDING_POH] = ItemLocation::Collectable(0x62, 0x1F, "GC Pot Freestanding PoH", GC_POT_FREESTANDING_POH, PIECE_OF_HEART, {Category::cGoronCity,}, SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_DEKU_SCRUB_GROTTO_LEFT] = ItemLocation::GrottoScrub(0xFB, 0x30, "GC Deku Scrub Grotto Left", GC_DEKU_SCRUB_GROTTO_LEFT, BUY_DEKU_NUT_5, {Category::cGoronCity, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x25, 0x01), SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_DEKU_SCRUB_GROTTO_RIGHT] = ItemLocation::GrottoScrub(0xFB, 0x37, "GC Deku Scrub Grotto Right", GC_DEKU_SCRUB_GROTTO_RIGHT, BUY_BOMBS_535, {Category::cGoronCity, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x25, 0x06), SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_DEKU_SCRUB_GROTTO_CENTER] = ItemLocation::GrottoScrub(0xFB, 0x33, "GC Deku Scrub Grotto Center", GC_DEKU_SCRUB_GROTTO_CENTER, BUY_ARROWS_30, {Category::cGoronCity, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x25, 0x04), SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_MEDIGORON] = ItemLocation::Base (0x62, 0x51, "GC Medigoron", GC_MEDIGORON, GIANTS_KNIFE, {Category::cGoronCity, Category::cMerchant,}, SpoilerCollectionCheck::EventChkInf(0x35), SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + + //Death Mountain Crater + locationTable[DMC_UPPER_GROTTO_CHEST] = ItemLocation::Chest (0x3E, 0x1A, "DMC Upper Grotto Chest", DMC_UPPER_GROTTO_CHEST, BOMBS_20, {Category::cDeathMountainCrater, Category::cDeathMountain, Category::cGrotto}, SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[DMC_WALL_FREESTANDING_POH] = ItemLocation::Collectable(0x61, 0x02, "DMC Wall Freestanding PoH", DMC_WALL_FREESTANDING_POH, PIECE_OF_HEART, {Category::cDeathMountainCrater, Category::cDeathMountain,}, SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[DMC_VOLCANO_FREESTANDING_POH] = ItemLocation::Collectable(0x61, 0x08, "DMC Volcano Freestanding PoH", DMC_VOLCANO_FREESTANDING_POH, PIECE_OF_HEART, {Category::cDeathMountainCrater, Category::cDeathMountain,}, SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[DMC_DEKU_SCRUB] = ItemLocation::Base (0x61, 0x37, "DMC Deku Scrub", DMC_DEKU_SCRUB, BUY_BOMBS_535, {Category::cDeathMountainCrater, Category::cDeathMountain, Category::cDekuScrub}, SpoilerCollectionCheck::Scrub(0x61, 0x06), SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[DMC_DEKU_SCRUB_GROTTO_LEFT] = ItemLocation::GrottoScrub(0xF9, 0x30, "DMC Deku Scrub Grotto Left", DMC_DEKU_SCRUB_GROTTO_LEFT, BUY_DEKU_NUT_5, {Category::cDeathMountainCrater, Category::cDeathMountain, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x23, 0x01), SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[DMC_DEKU_SCRUB_GROTTO_RIGHT] = ItemLocation::GrottoScrub(0xF9, 0x37, "DMC Deku Scrub Grotto Right", DMC_DEKU_SCRUB_GROTTO_RIGHT, BUY_BOMBS_535, {Category::cDeathMountainCrater, Category::cDeathMountain, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x23, 0x06), SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[DMC_DEKU_SCRUB_GROTTO_CENTER] = ItemLocation::GrottoScrub(0xF9, 0x33, "DMC Deku Scrub Grotto Center", DMC_DEKU_SCRUB_GROTTO_CENTER, BUY_ARROWS_30, {Category::cDeathMountainCrater, Category::cDeathMountain, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x23, 0x04), SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + + //Zoras River + locationTable[ZR_OPEN_GROTTO_CHEST] = ItemLocation::Chest (0x3E, 0x09, "ZR Open Grotto Chest", ZR_OPEN_GROTTO_CHEST, RED_RUPEE, {Category::cZorasRiver, Category::cGrotto,}, SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); + locationTable[ZR_MAGIC_BEAN_SALESMAN] = ItemLocation::Base (0x54, 0x16, "ZR Magic Bean Salesman", ZR_MAGIC_BEAN_SALESMAN, MAGIC_BEAN, {Category::cZorasRiver,}, SpoilerCollectionCheck::MagicBeans(0x54, 0x01), SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); + locationTable[ZR_FROGS_IN_THE_RAIN] = ItemLocation::Base (0x54, 0x3E, "ZR Frogs in the Rain", ZR_FROGS_IN_THE_RAIN, PIECE_OF_HEART, {Category::cZorasRiver,}, SpoilerCollectionCheck::EventChkInf(0xD6), SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); + locationTable[ZR_FROGS_OCARINA_GAME] = ItemLocation::Base (0x54, 0x76, "ZR Frogs Ocarina Game", ZR_FROGS_OCARINA_GAME, PIECE_OF_HEART, {Category::cZorasRiver, Category::cMinigame,}, SpoilerCollectionCheck::EventChkInf(0xD0), SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); + locationTable[ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH] = ItemLocation::Collectable(0x54, 0x04, "ZR Near Open Grotto Freestanding PoH", ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH, PIECE_OF_HEART, {Category::cZorasRiver,}, SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); + locationTable[ZR_NEAR_DOMAIN_FREESTANDING_POH] = ItemLocation::Collectable(0x54, 0x0B, "ZR Near Domain Freestanding PoH", ZR_NEAR_DOMAIN_FREESTANDING_POH, PIECE_OF_HEART, {Category::cZorasRiver,}, SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); + locationTable[ZR_DEKU_SCRUB_GROTTO_REAR] = ItemLocation::GrottoScrub(0xEB, 0x39, "ZR Deku Scrub Grotto Rear", ZR_DEKU_SCRUB_GROTTO_REAR, BUY_RED_POTION_30, {Category::cZorasRiver, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x15, 0x08), SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); + locationTable[ZR_DEKU_SCRUB_GROTTO_FRONT] = ItemLocation::GrottoScrub(0xEB, 0x3A, "ZR Deku Scrub Grotto Front", ZR_DEKU_SCRUB_GROTTO_FRONT, BUY_GREEN_POTION, {Category::cZorasRiver, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x15, 0x09), SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); + + //Zoras Domain + locationTable[ZD_CHEST] = ItemLocation::Chest (0x58, 0x00, "ZD Chest", ZD_CHEST, PIECE_OF_HEART, {Category::cZorasDomain,}, SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + locationTable[ZD_DIVING_MINIGAME] = ItemLocation::Base (0x58, 0x37, "ZD Diving Minigame", ZD_DIVING_MINIGAME, PROGRESSIVE_SCALE, {Category::cZorasDomain, Category::cMinigame,}, SpoilerCollectionCheck::EventChkInf(0x38), SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + locationTable[ZD_KING_ZORA_THAWED] = ItemLocation::Base (0x58, 0x2D, "ZD King Zora Thawed", ZD_KING_ZORA_THAWED, ZORA_TUNIC, {Category::cZorasDomain,}, SpoilerCollectionCheck::InfTable(0x13, 0x01), SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + locationTable[ZD_TRADE_PRESCRIPTION] = ItemLocation::Base (0x58, 0x24, "ZD Trade Prescription", ZD_TRADE_PRESCRIPTION, EYEBALL_FROG, {Category::cZorasDomain, Category::cAdultTrade}, SpoilerCollectionCheck::ItemGetInf(60), SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + + //Zoras Fountain + locationTable[ZF_ICEBERG_FREESTANDING_POH] = ItemLocation::Collectable(0x59, 0x01, "ZF Iceberg Freestanding PoH", ZF_ICEBERG_FREESTANDING_POH, PIECE_OF_HEART, {Category::cZorasFountain,}, SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + locationTable[ZF_BOTTOM_FREESTANDING_POH] = ItemLocation::Collectable(0x59, 0x14, "ZF Bottom Freestanding PoH", ZF_BOTTOM_FREESTANDING_POH, PIECE_OF_HEART, {Category::cZorasFountain,}, SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + + //Lon Lon Ranch + locationTable[LLR_TALONS_CHICKENS] = ItemLocation::Base (0x4C, 0x14, "LLR Talons Chickens", LLR_TALONS_CHICKENS, BOTTLE_WITH_MILK, {Category::cLonLonRanch, Category::cMinigame}, SpoilerCollectionCheck::ItemGetInf(10), SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); + locationTable[LLR_FREESTANDING_POH] = ItemLocation::Collectable(0x4C, 0x01, "LLR Freestanding PoH", LLR_FREESTANDING_POH, PIECE_OF_HEART, {Category::cLonLonRanch,}, SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); + locationTable[LLR_DEKU_SCRUB_GROTTO_LEFT] = ItemLocation::GrottoScrub(0xFC, 0x30, "LLR Deku Scrub Grotto Left", LLR_DEKU_SCRUB_GROTTO_LEFT, BUY_DEKU_NUT_5, {Category::cLonLonRanch, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x26, 0x01), SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); + locationTable[LLR_DEKU_SCRUB_GROTTO_RIGHT] = ItemLocation::GrottoScrub(0xFC, 0x37, "LLR Deku Scrub Grotto Right", LLR_DEKU_SCRUB_GROTTO_RIGHT, BUY_BOMBS_535, {Category::cLonLonRanch, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x26, 0x06), SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); + locationTable[LLR_DEKU_SCRUB_GROTTO_CENTER] = ItemLocation::GrottoScrub(0xFC, 0x33, "LLR Deku Scrub Grotto Center", LLR_DEKU_SCRUB_GROTTO_CENTER, BUY_DEKU_SEEDS_30, {Category::cLonLonRanch, Category::cDekuScrub, Category::cGrotto}, SpoilerCollectionCheck::Scrub(0x26, 0x04), SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); + + /*------------------- + --- DUNGEONS --- + -------------------*/ + + //Deku Tree Vanilla + locationTable[DEKU_TREE_MAP_CHEST] = ItemLocation::Chest (0x00, 0x03, "Deku Tree Map Chest", DEKU_TREE_MAP_CHEST, DEKU_TREE_MAP, {Category::cDekuTree, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_COMPASS_CHEST] = ItemLocation::Chest (0x00, 0x02, "Deku Tree Compass Chest", DEKU_TREE_COMPASS_CHEST, DEKU_TREE_COMPASS, {Category::cDekuTree, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_COMPASS_ROOM_SIDE_CHEST] = ItemLocation::Chest (0x00, 0x06, "Deku Tree Compass Room Side Chest", DEKU_TREE_COMPASS_ROOM_SIDE_CHEST, RECOVERY_HEART, {Category::cDekuTree,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_BASEMENT_CHEST] = ItemLocation::Chest (0x00, 0x04, "Deku Tree Basement Chest", DEKU_TREE_BASEMENT_CHEST, RECOVERY_HEART, {Category::cDekuTree,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_SLINGSHOT_CHEST] = ItemLocation::Chest (0x00, 0x01, "Deku Tree Slingshot Chest", DEKU_TREE_SLINGSHOT_CHEST, PROGRESSIVE_SLINGSHOT, {Category::cDekuTree,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_SLINGSHOT_ROOM_SIDE_CHEST] = ItemLocation::Chest (0x00, 0x05, "Deku Tree Slingshot Room Side Chest", DEKU_TREE_SLINGSHOT_ROOM_SIDE_CHEST, RECOVERY_HEART, {Category::cDekuTree,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + //Deku Tree MQ + locationTable[DEKU_TREE_MQ_MAP_CHEST] = ItemLocation::Chest (0x00, 0x03, "Deku Tree MQ Map Chest", DEKU_TREE_MQ_MAP_CHEST, DEKU_TREE_MAP, {Category::cDekuTree, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_MQ_COMPASS_CHEST] = ItemLocation::Chest (0x00, 0x01, "Deku Tree MQ Compass Chest", DEKU_TREE_MQ_COMPASS_CHEST, DEKU_TREE_COMPASS, {Category::cDekuTree, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_MQ_SLINGSHOT_CHEST] = ItemLocation::Chest (0x00, 0x06, "Deku Tree MQ Slingshot Chest", DEKU_TREE_MQ_SLINGSHOT_CHEST, PROGRESSIVE_SLINGSHOT, {Category::cDekuTree,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_MQ_SLINGSHOT_ROOM_BACK_CHEST] = ItemLocation::Chest (0x00, 0x02, "Deku Tree MQ Slingshot Room Back Chest", DEKU_TREE_MQ_SLINGSHOT_ROOM_BACK_CHEST, DEKU_SHIELD, {Category::cDekuTree,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_MQ_BASEMENT_CHEST] = ItemLocation::Chest (0x00, 0x04, "Deku Tree MQ Basement Chest", DEKU_TREE_MQ_BASEMENT_CHEST, DEKU_SHIELD, {Category::cDekuTree,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_MQ_BEFORE_SPINNING_LOG_CHEST] = ItemLocation::Chest (0x00, 0x05, "Deku Tree MQ Before Spinning Log Chest", DEKU_TREE_MQ_BEFORE_SPINNING_LOG_CHEST, RECOVERY_HEART, {Category::cDekuTree,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_MQ_AFTER_SPINNING_LOG_CHEST] = ItemLocation::Chest (0x00, 0x00, "Deku Tree MQ After Spinning Log Chest", DEKU_TREE_MQ_AFTER_SPINNING_LOG_CHEST, PURPLE_RUPEE, {Category::cDekuTree,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_MQ_DEKU_SCRUB] = ItemLocation::Base (0x00, 0x34, "Deku Tree MQ Deku Scrub", DEKU_TREE_MQ_DEKU_SCRUB, BUY_DEKU_SHIELD, {Category::cDekuTree, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x00, 0x05), SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + + //Dodongos Cavern Shared + locationTable[DODONGOS_CAVERN_BOSS_ROOM_CHEST] = ItemLocation::Chest (0x12, 0x00, "Dodongos Cavern Boss Room Chest", DODONGOS_CAVERN_BOSS_ROOM_CHEST, BOMBS_5, {Category::cDodongosCavern,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + //Dodongos Cavern Vanilla + locationTable[DODONGOS_CAVERN_MAP_CHEST] = ItemLocation::Chest (0x01, 0x08, "Dodongos Cavern Map Chest", DODONGOS_CAVERN_MAP_CHEST, DODONGOS_CAVERN_MAP, {Category::cDodongosCavern, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_COMPASS_CHEST] = ItemLocation::Chest (0x01, 0x05, "Dodongos Cavern Compass Chest", DODONGOS_CAVERN_COMPASS_CHEST, DODONGOS_CAVERN_COMPASS, {Category::cDodongosCavern, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_BOMB_FLOWER_PLATFORM_CHEST] = ItemLocation::Chest (0x01, 0x06, "Dodongos Cavern Bomb Flower Platform Chest", DODONGOS_CAVERN_BOMB_FLOWER_PLATFORM_CHEST, RED_RUPEE, {Category::cDodongosCavern,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_BOMB_BAG_CHEST] = ItemLocation::Chest (0x01, 0x04, "Dodongos Cavern Bomb Bag Chest", DODONGOS_CAVERN_BOMB_BAG_CHEST, PROGRESSIVE_BOMB_BAG, {Category::cDodongosCavern,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_END_OF_BRIDGE_CHEST] = ItemLocation::Chest (0x01, 0x0A, "Dodongos Cavern End Of Bridge Chest", DODONGOS_CAVERN_END_OF_BRIDGE_CHEST, DEKU_SHIELD, {Category::cDodongosCavern,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT] = ItemLocation::Base (0x01, 0x30, "Dodongos Cavern Deku Scrub Near Bomb Bag Left", DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT, BUY_DEKU_NUT_5, {Category::cDodongosCavern, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x01, 0x01), SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS] = ItemLocation::Base (0x01, 0x31, "Dodongos Cavern Deku Scrub Side Room Near Dodongos", DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS, BUY_DEKU_STICK_1, {Category::cDodongosCavern, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x01, 0x02), SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT] = ItemLocation::Base (0x01, 0x33, "Dodongos Cavern Deku Scrub Near Bomb Bag Right", DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT, BUY_DEKU_SEEDS_30, {Category::cDodongosCavern, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x01, 0x04), SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_DEKU_SCRUB_LOBBY] = ItemLocation::Base (0x01, 0x34, "Dodongos Cavern Deku Scrub Lobby", DODONGOS_CAVERN_DEKU_SCRUB_LOBBY, BUY_DEKU_SHIELD, {Category::cDodongosCavern, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x01, 0x05), SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + //Dodongos Cavern MQ + locationTable[DODONGOS_CAVERN_MQ_MAP_CHEST] = ItemLocation::Chest (0x01, 0x00, "Dodongos Cavern MQ Map Chest", DODONGOS_CAVERN_MQ_MAP_CHEST, DODONGOS_CAVERN_MAP, {Category::cDodongosCavern, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_MQ_BOMB_BAG_CHEST] = ItemLocation::Chest (0x01, 0x04, "Dodongos Cavern MQ Bomb Bag Chest", DODONGOS_CAVERN_MQ_BOMB_BAG_CHEST, PROGRESSIVE_BOMB_BAG, {Category::cDodongosCavern,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_MQ_COMPASS_CHEST] = ItemLocation::Chest (0x01, 0x05, "Dodongos Cavern MQ Compass Chest", DODONGOS_CAVERN_MQ_COMPASS_CHEST, DODONGOS_CAVERN_COMPASS, {Category::cDodongosCavern, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_MQ_LARVAE_ROOM_CHEST] = ItemLocation::Chest (0x01, 0x02, "Dodongos Cavern MQ Larvae Room Chest", DODONGOS_CAVERN_MQ_LARVAE_ROOM_CHEST, DEKU_SHIELD, {Category::cDodongosCavern,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_MQ_TORCH_PUZZLE_ROOM_CHEST] = ItemLocation::Chest (0x01, 0x03, "Dodongos Cavern MQ Torch Puzzle Room Chest", DODONGOS_CAVERN_MQ_TORCH_PUZZLE_ROOM_CHEST, BLUE_RUPEE, {Category::cDodongosCavern,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_MQ_UNDER_GRAVE_CHEST] = ItemLocation::Chest (0x01, 0x01, "Dodongos Cavern MQ Under Grave Chest", DODONGOS_CAVERN_MQ_UNDER_GRAVE_CHEST, HYLIAN_SHIELD, {Category::cDodongosCavern,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR] = ItemLocation::Base (0x01, 0x31, "Dodongos Cavern Deku Scrub Lobby Rear", DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR, BUY_DEKU_STICK_1, {Category::cDodongosCavern, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x01, 0x02), SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT] = ItemLocation::Base (0x01, 0x33, "Dodongos Cavern Deku Scrub Lobby Front", DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT, BUY_DEKU_SEEDS_30, {Category::cDodongosCavern, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x01, 0x04), SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE] = ItemLocation::Base (0x01, 0x34, "Dodongos Cavern Deku Scrub Staircase", DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE, BUY_DEKU_SHIELD, {Category::cDodongosCavern, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x01, 0x05), SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS] = ItemLocation::Base (0x01, 0x39, "Dodongos Cavern Deku Scrub Side Room Near Lower Lizalfos",DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS, BUY_RED_POTION_30, {Category::cDodongosCavern, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x01, 0x08), SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + + //Jabu Jabus Belly Vanilla + locationTable[JABU_JABUS_BELLY_MAP_CHEST] = ItemLocation::Chest (0x02, 0x02, "Jabu Jabus Belly Map Chest", JABU_JABUS_BELLY_MAP_CHEST, JABU_JABUS_BELLY_MAP, {Category::cJabuJabusBelly, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_COMPASS_CHEST] = ItemLocation::Chest (0x02, 0x04, "Jabu Jabus Belly Compass Chest", JABU_JABUS_BELLY_COMPASS_CHEST, JABU_JABUS_BELLY_COMPASS, {Category::cJabuJabusBelly, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_BOOMERANG_CHEST] = ItemLocation::Chest (0x02, 0x01, "Jabu Jabus Belly Boomerang Chest", JABU_JABUS_BELLY_BOOMERANG_CHEST, BOOMERANG, {Category::cJabuJabusBelly,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_DEKU_SCRUB] = ItemLocation::Base (0x02, 0x30, "Jabu Jabus Belly Deku Scrub", JABU_JABUS_BELLY_DEKU_SCRUB, BUY_DEKU_NUT_5, {Category::cJabuJabusBelly, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x02, 0x01), SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + //Jabu Jabus Belly MQ + locationTable[JABU_JABUS_BELLY_MQ_FIRST_ROOM_SIDE_CHEST] = ItemLocation::Chest (0x02, 0x05, "Jabu Jabus Belly MQ First Room Side Chest", JABU_JABUS_BELLY_MQ_FIRST_ROOM_SIDE_CHEST, DEKU_NUTS_5, {Category::cJabuJabusBelly,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_MQ_MAP_CHEST] = ItemLocation::Chest (0x02, 0x03, "Jabu Jabus Belly MQ Map Chest", JABU_JABUS_BELLY_MQ_MAP_CHEST, JABU_JABUS_BELLY_MAP, {Category::cJabuJabusBelly, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_MQ_SECOND_ROOM_LOWER_CHEST] = ItemLocation::Chest (0x02, 0x02, "Jabu Jabus Belly MQ Second Room Lower Chest", JABU_JABUS_BELLY_MQ_SECOND_ROOM_LOWER_CHEST, DEKU_NUTS_5, {Category::cJabuJabusBelly,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_MQ_COMPASS_CHEST] = ItemLocation::Chest (0x02, 0x00, "Jabu Jabus Belly MQ Compass Chest", JABU_JABUS_BELLY_MQ_COMPASS_CHEST, JABU_JABUS_BELLY_COMPASS, {Category::cJabuJabusBelly, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_MQ_SECOND_ROOM_UPPER_CHEST] = ItemLocation::Chest (0x02, 0x07, "Jabu Jabus Belly MQ Second Room Upper Chest", JABU_JABUS_BELLY_MQ_SECOND_ROOM_UPPER_CHEST, RECOVERY_HEART, {Category::cJabuJabusBelly,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_SWITCHES_CHEST] = ItemLocation::Chest (0x02, 0x08, "Jabu Jabus Belly MQ Basement Near Switches Chest", JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_SWITCHES_CHEST, DEKU_NUTS_5, {Category::cJabuJabusBelly,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_VINES_CHEST] = ItemLocation::Chest (0x02, 0x04, "Jabu Jabus Belly MQ Basement Near Vines Chest", JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_VINES_CHEST, BOMBCHU_10, {Category::cJabuJabusBelly,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_MQ_NEAR_BOSS_CHEST] = ItemLocation::Chest (0x02, 0x0A, "Jabu Jabus Belly MQ Near Boss Chest", JABU_JABUS_BELLY_MQ_NEAR_BOSS_CHEST, DEKU_SHIELD, {Category::cJabuJabusBelly,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_ROOM_CHEST] = ItemLocation::Chest (0x02, 0x09, "Jabu Jabus Belly MQ Falling Like Like Room Chest", JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_ROOM_CHEST, DEKU_STICK_1, {Category::cJabuJabusBelly,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_MQ_BOOMERANG_ROOM_SMALL_CHEST] = ItemLocation::Chest (0x02, 0x01, "Jabu Jabus Belly MQ Boomerang Room Small Chest", JABU_JABUS_BELLY_MQ_BOOMERANG_ROOM_SMALL_CHEST, DEKU_NUTS_5, {Category::cJabuJabusBelly,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_MQ_BOOMERANG_CHEST] = ItemLocation::Chest (0x02, 0x06, "Jabu Jabus Belly MQ Boomerang Chest", JABU_JABUS_BELLY_MQ_BOOMERANG_CHEST, BOOMERANG, {Category::cJabuJabusBelly,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + //COW + + //Forest Temple Vanilla + locationTable[FOREST_TEMPLE_FIRST_ROOM_CHEST] = ItemLocation::Chest (0x03, 0x03, "Forest Temple First Room Chest", FOREST_TEMPLE_FIRST_ROOM_CHEST, FOREST_TEMPLE_SMALL_KEY, {Category::cForestTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_FIRST_STALFOS_CHEST] = ItemLocation::Chest (0x03, 0x00, "Forest Temple First Stalfos Chest", FOREST_TEMPLE_FIRST_STALFOS_CHEST, FOREST_TEMPLE_SMALL_KEY, {Category::cForestTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_RAISED_ISLAND_COURTYARD_CHEST] = ItemLocation::Chest (0x03, 0x05, "Forest Temple Raised Island Courtyard Chest", FOREST_TEMPLE_RAISED_ISLAND_COURTYARD_CHEST, RECOVERY_HEART, {Category::cForestTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_MAP_CHEST] = ItemLocation::Chest (0x03, 0x01, "Forest Temple Map Chest", FOREST_TEMPLE_MAP_CHEST, FOREST_TEMPLE_MAP, {Category::cForestTemple, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_WELL_CHEST] = ItemLocation::Chest (0x03, 0x09, "Forest Temple Well Chest", FOREST_TEMPLE_WELL_CHEST, FOREST_TEMPLE_SMALL_KEY, {Category::cForestTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_FALLING_CEILING_ROOM_CHEST] = ItemLocation::Chest (0x03, 0x07, "Forest Temple Falling Ceiling Room Chest", FOREST_TEMPLE_FALLING_CEILING_ROOM_CHEST, ARROWS_10, {Category::cForestTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_EYE_SWITCH_CHEST] = ItemLocation::Chest (0x03, 0x04, "Forest Temple Eye Switch Chest", FOREST_TEMPLE_EYE_SWITCH_CHEST, ARROWS_30, {Category::cForestTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_BOSS_KEY_CHEST] = ItemLocation::Chest (0x03, 0x0E, "Forest Temple Boss Key Chest", FOREST_TEMPLE_BOSS_KEY_CHEST, FOREST_TEMPLE_BOSS_KEY, {Category::cForestTemple, Category::cVanillaBossKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_FLOORMASTER_CHEST] = ItemLocation::Chest (0x03, 0x02, "Forest Temple Floormaster Chest", FOREST_TEMPLE_FLOORMASTER_CHEST, FOREST_TEMPLE_SMALL_KEY, {Category::cForestTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_BOW_CHEST] = ItemLocation::Chest (0x03, 0x0C, "Forest Temple Bow Chest", FOREST_TEMPLE_BOW_CHEST, PROGRESSIVE_BOW, {Category::cForestTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_RED_POE_CHEST] = ItemLocation::Chest (0x03, 0x0D, "Forest Temple Red Poe Chest", FOREST_TEMPLE_RED_POE_CHEST, FOREST_TEMPLE_SMALL_KEY, {Category::cForestTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_BLUE_POE_CHEST] = ItemLocation::Chest (0x03, 0x0F, "Forest Temple Blue Poe Chest", FOREST_TEMPLE_BLUE_POE_CHEST, FOREST_TEMPLE_COMPASS, {Category::cForestTemple, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_BASEMENT_CHEST] = ItemLocation::Chest (0x03, 0x0B, "Forest Temple Basement Chest", FOREST_TEMPLE_BASEMENT_CHEST, ARROWS_5, {Category::cForestTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + //Forest Temple MQ + locationTable[FOREST_TEMPLE_MQ_FIRST_ROOM_CHEST] = ItemLocation::Chest (0x03, 0x03, "Forest Temple MQ First Room Chest", FOREST_TEMPLE_MQ_FIRST_ROOM_CHEST, FOREST_TEMPLE_SMALL_KEY, {Category::cForestTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_MQ_WOLFOS_CHEST] = ItemLocation::Chest (0x03, 0x00, "Forest Temple MQ Wolfos Chest", FOREST_TEMPLE_MQ_WOLFOS_CHEST, FOREST_TEMPLE_SMALL_KEY, {Category::cForestTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_MQ_BOW_CHEST] = ItemLocation::Chest (0x03, 0x0C, "Forest Temple MQ Bow Chest", FOREST_TEMPLE_MQ_BOW_CHEST, PROGRESSIVE_BOW, {Category::cForestTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_LOWER_CHEST] = ItemLocation::Chest (0x03, 0x01, "Forest Temple MQ Raised Island Courtyard Lower Chest", FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_LOWER_CHEST, FOREST_TEMPLE_SMALL_KEY, {Category::cForestTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_UPPER_CHEST] = ItemLocation::Chest (0x03, 0x05, "Forest Temple MQ Raised Island Courtyard Upper Chest", FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_UPPER_CHEST, FOREST_TEMPLE_SMALL_KEY, {Category::cForestTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_MQ_WELL_CHEST] = ItemLocation::Chest (0x03, 0x09, "Forest Temple MQ Well Chest", FOREST_TEMPLE_MQ_WELL_CHEST, FOREST_TEMPLE_SMALL_KEY, {Category::cForestTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_MQ_MAP_CHEST] = ItemLocation::Chest (0x03, 0x0D, "Forest Temple MQ Map Chest", FOREST_TEMPLE_MQ_MAP_CHEST, FOREST_TEMPLE_MAP, {Category::cForestTemple, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_MQ_COMPASS_CHEST] = ItemLocation::Chest (0x03, 0x0F, "Forest Temple MQ Compass Chest", FOREST_TEMPLE_MQ_COMPASS_CHEST, FOREST_TEMPLE_COMPASS, {Category::cForestTemple, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_MQ_FALLING_CEILING_ROOM_CHEST] = ItemLocation::Chest (0x03, 0x06, "Forest Temple MQ Falling Ceiling Room Chest", FOREST_TEMPLE_MQ_FALLING_CEILING_ROOM_CHEST, ARROWS_5, {Category::cForestTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_MQ_BASEMENT_CHEST] = ItemLocation::Chest (0x03, 0x0B, "Forest Temple MQ Basement Chest", FOREST_TEMPLE_MQ_BASEMENT_CHEST, ARROWS_5, {Category::cForestTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_MQ_REDEAD_CHEST] = ItemLocation::Chest (0x03, 0x02, "Forest Temple MQ Redead Chest", FOREST_TEMPLE_MQ_REDEAD_CHEST, FOREST_TEMPLE_SMALL_KEY, {Category::cForestTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_MQ_BOSS_KEY_CHEST] = ItemLocation::Chest (0x03, 0x0E, "Forest Temple MQ Boss Key Chest", FOREST_TEMPLE_MQ_BOSS_KEY_CHEST, FOREST_TEMPLE_BOSS_KEY, {Category::cForestTemple, Category::cVanillaBossKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + + //Fire Temple Vanilla + locationTable[FIRE_TEMPLE_NEAR_BOSS_CHEST] = ItemLocation::Chest (0x04, 0x01, "Fire Temple Near Boss Chest", FIRE_TEMPLE_NEAR_BOSS_CHEST, FIRE_TEMPLE_SMALL_KEY, {Category::cFireTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_FLARE_DANCER_CHEST] = ItemLocation::Chest (0x04, 0x00, "Fire Temple Flare Dancer Chest", FIRE_TEMPLE_FLARE_DANCER_CHEST, BOMBS_10, {Category::cFireTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_BOSS_KEY_CHEST] = ItemLocation::Chest (0x04, 0x0C, "Fire Temple Boss Key Chest", FIRE_TEMPLE_BOSS_KEY_CHEST, FIRE_TEMPLE_BOSS_KEY, {Category::cFireTemple, Category::cVanillaBossKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST] = ItemLocation::Chest (0x04, 0x02, "Fire Temple Big Lava Room Blocked Door Chest", FIRE_TEMPLE_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST, FIRE_TEMPLE_SMALL_KEY, {Category::cFireTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_BIG_LAVA_ROOM_LOWER_OPEN_DOOR_CHEST] = ItemLocation::Chest (0x04, 0x04, "Fire Temple Big Lava Room Lower Open Door Chest", FIRE_TEMPLE_BIG_LAVA_ROOM_LOWER_OPEN_DOOR_CHEST, FIRE_TEMPLE_SMALL_KEY, {Category::cFireTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_BOULDER_MAZE_LOWER_CHEST] = ItemLocation::Chest (0x04, 0x03, "Fire Temple Boulder Maze Lower Chest", FIRE_TEMPLE_BOULDER_MAZE_LOWER_CHEST, FIRE_TEMPLE_SMALL_KEY, {Category::cFireTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_BOULDER_MAZE_UPPER_CHEST] = ItemLocation::Chest (0x04, 0x06, "Fire Temple Boulder Maze Upper Chest", FIRE_TEMPLE_BOULDER_MAZE_UPPER_CHEST, FIRE_TEMPLE_SMALL_KEY, {Category::cFireTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_BOULDER_MAZE_SIDE_ROOM_CHEST] = ItemLocation::Chest (0x04, 0x08, "Fire Temple Boulder Maze Side Room Chest", FIRE_TEMPLE_BOULDER_MAZE_SIDE_ROOM_CHEST, FIRE_TEMPLE_SMALL_KEY, {Category::cFireTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_BOULDER_MAZE_SHORTCUT_CHEST] = ItemLocation::Chest (0x04, 0x0B, "Fire Temple Boulder Maze Shortcut Chest", FIRE_TEMPLE_BOULDER_MAZE_SHORTCUT_CHEST, FIRE_TEMPLE_SMALL_KEY, {Category::cFireTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_SCARECROW_CHEST] = ItemLocation::Chest (0x04, 0x0D, "Fire Temple Scarecrow Chest", FIRE_TEMPLE_SCARECROW_CHEST, HUGE_RUPEE, {Category::cFireTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MAP_CHEST] = ItemLocation::Chest (0x04, 0x0A, "Fire Temple Map Chest", FIRE_TEMPLE_MAP_CHEST, FIRE_TEMPLE_MAP, {Category::cFireTemple, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_COMPASS_CHEST] = ItemLocation::Chest (0x04, 0x07, "Fire Temple Compass Chest", FIRE_TEMPLE_COMPASS_CHEST, FIRE_TEMPLE_COMPASS, {Category::cFireTemple, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_HIGHEST_GORON_CHEST] = ItemLocation::Chest (0x04, 0x09, "Fire Temple Highest Goron Chest", FIRE_TEMPLE_HIGHEST_GORON_CHEST, FIRE_TEMPLE_SMALL_KEY, {Category::cFireTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MEGATON_HAMMER_CHEST] = ItemLocation::Chest (0x04, 0x05, "Fire Temple Megaton Hammer Chest", FIRE_TEMPLE_MEGATON_HAMMER_CHEST, MEGATON_HAMMER, {Category::cFireTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + //Fire Temple MQ + locationTable[FIRE_TEMPLE_MQ_NEAR_BOSS_CHEST] = ItemLocation::Chest (0x04, 0x07, "Fire Temple MQ Near Boss Chest", FIRE_TEMPLE_MQ_NEAR_BOSS_CHEST, FIRE_TEMPLE_SMALL_KEY, {Category::cFireTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MQ_MEGATON_HAMMER_CHEST] = ItemLocation::Chest (0x04, 0x00, "Fire Temple MQ Megaton Hammer Chest", FIRE_TEMPLE_MQ_MEGATON_HAMMER_CHEST, MEGATON_HAMMER, {Category::cFireTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MQ_COMPASS_CHEST] = ItemLocation::Chest (0x04, 0x0B, "Fire Temple MQ Compass Chest", FIRE_TEMPLE_MQ_COMPASS_CHEST, FIRE_TEMPLE_COMPASS, {Category::cFireTemple, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CHEST] = ItemLocation::Chest (0x04, 0x03, "Fire Temple MQ Lizalfos Maze Lower Chest", FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CHEST, BOMBS_10, {Category::cFireTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CHEST] = ItemLocation::Chest (0x04, 0x06, "Fire Temple MQ Lizalfos Maze Upper Chest", FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CHEST, BOMBS_10, {Category::cFireTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MQ_CHEST_ON_FIRE] = ItemLocation::Chest (0x04, 0x05, "Fire Temple MQ Chest on Fire", FIRE_TEMPLE_MQ_CHEST_ON_FIRE, FIRE_TEMPLE_SMALL_KEY, {Category::cFireTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MQ_MAP_ROOM_SIDE_CHEST] = ItemLocation::Chest (0x04, 0x02, "Fire Temple MQ Map Room Side Chest", FIRE_TEMPLE_MQ_MAP_ROOM_SIDE_CHEST, HYLIAN_SHIELD, {Category::cFireTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MQ_MAP_CHEST] = ItemLocation::Chest (0x04, 0x0C, "Fire Temple MQ Map Chest", FIRE_TEMPLE_MQ_MAP_CHEST, FIRE_TEMPLE_MAP, {Category::cFireTemple, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MQ_BOSS_KEY_CHEST] = ItemLocation::Chest (0x04, 0x04, "Fire Temple MQ Boss Key Chest", FIRE_TEMPLE_MQ_BOSS_KEY_CHEST, FIRE_TEMPLE_BOSS_KEY, {Category::cFireTemple, Category::cVanillaBossKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MQ_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST] = ItemLocation::Chest (0x04, 0x01, "Fire Temple MQ Big Lava Room Blocked Door Chest", FIRE_TEMPLE_MQ_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST, FIRE_TEMPLE_SMALL_KEY, {Category::cFireTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MQ_LIZALFOS_MAZE_SIDE_ROOM_CHEST] = ItemLocation::Chest (0x04, 0x08, "Fire Temple MQ Lizalfos Maze Side Room Chest", FIRE_TEMPLE_MQ_LIZALFOS_MAZE_SIDE_ROOM_CHEST, FIRE_TEMPLE_SMALL_KEY, {Category::cFireTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MQ_FREESTANDING_KEY] = ItemLocation::Collectable(0x04, 0x1C, "Fire Temple MQ Freestanding Key", FIRE_TEMPLE_MQ_FREESTANDING_KEY, FIRE_TEMPLE_SMALL_KEY, {Category::cFireTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + + //Water Temple Vanilla + locationTable[WATER_TEMPLE_MAP_CHEST] = ItemLocation::Chest (0x05, 0x02, "Water Temple Map Chest", WATER_TEMPLE_MAP_CHEST, WATER_TEMPLE_MAP, {Category::cWaterTemple, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_COMPASS_CHEST] = ItemLocation::Chest (0x05, 0x09, "Water Temple Compass Chest", WATER_TEMPLE_COMPASS_CHEST, WATER_TEMPLE_COMPASS, {Category::cWaterTemple, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_TORCHES_CHEST] = ItemLocation::Chest (0x05, 0x01, "Water Temple Torches Chest", WATER_TEMPLE_TORCHES_CHEST, WATER_TEMPLE_SMALL_KEY, {Category::cWaterTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_DRAGON_CHEST] = ItemLocation::Chest (0x05, 0x0A, "Water Temple Dragon Chest", WATER_TEMPLE_DRAGON_CHEST, WATER_TEMPLE_SMALL_KEY, {Category::cWaterTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_CENTRAL_BOW_TARGET_CHEST] = ItemLocation::Chest (0x05, 0x08, "Water Temple Central Bow Target Chest", WATER_TEMPLE_CENTRAL_BOW_TARGET_CHEST, WATER_TEMPLE_SMALL_KEY, {Category::cWaterTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_CENTRAL_PILLAR_CHEST] = ItemLocation::Chest (0x05, 0x06, "Water Temple Central Pillar Chest", WATER_TEMPLE_CENTRAL_PILLAR_CHEST, WATER_TEMPLE_SMALL_KEY, {Category::cWaterTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_CRACKED_WALL_CHEST] = ItemLocation::Chest (0x05, 0x00, "Water Temple Cracked Wall Chest", WATER_TEMPLE_CRACKED_WALL_CHEST, WATER_TEMPLE_SMALL_KEY, {Category::cWaterTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_BOSS_KEY_CHEST] = ItemLocation::Chest (0x05, 0x05, "Water Temple Boss Key Chest", WATER_TEMPLE_BOSS_KEY_CHEST, WATER_TEMPLE_BOSS_KEY, {Category::cWaterTemple, Category::cVanillaBossKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_LONGSHOT_CHEST] = ItemLocation::Chest (0x05, 0x07, "Water Temple Longshot Chest", WATER_TEMPLE_LONGSHOT_CHEST, PROGRESSIVE_HOOKSHOT, {Category::cWaterTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_RIVER_CHEST] = ItemLocation::Chest (0x05, 0x03, "Water Temple River Chest", WATER_TEMPLE_RIVER_CHEST, WATER_TEMPLE_SMALL_KEY, {Category::cWaterTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + //Water Temple MQ + locationTable[WATER_TEMPLE_MQ_CENTRAL_PILLAR_CHEST] = ItemLocation::Chest (0x05, 0x06, "Water Temple MQ Central Pillar Chest", WATER_TEMPLE_MQ_CENTRAL_PILLAR_CHEST, WATER_TEMPLE_SMALL_KEY, {Category::cWaterTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_MQ_BOSS_KEY_CHEST] = ItemLocation::Chest (0x05, 0x05, "Water Temple MQ Boss Key Chest", WATER_TEMPLE_MQ_BOSS_KEY_CHEST, WATER_TEMPLE_BOSS_KEY, {Category::cWaterTemple, Category::cVanillaBossKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_MQ_LONGSHOT_CHEST] = ItemLocation::Chest (0x05, 0x00, "Water Temple MQ Longshot Chest", WATER_TEMPLE_MQ_LONGSHOT_CHEST, PROGRESSIVE_HOOKSHOT, {Category::cWaterTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_MQ_COMPASS_CHEST] = ItemLocation::Chest (0x05, 0x01, "Water Temple MQ Compass Chest", WATER_TEMPLE_MQ_COMPASS_CHEST, WATER_TEMPLE_COMPASS, {Category::cWaterTemple, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_MQ_MAP_CHEST] = ItemLocation::Chest (0x05, 0x02, "Water Temple MQ Map Chest", WATER_TEMPLE_MQ_MAP_CHEST, WATER_TEMPLE_MAP, {Category::cWaterTemple, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_MQ_FREESTANDING_KEY] = ItemLocation::Collectable(0x05, 0x01, "Water Temple MQ Freestanding Key", WATER_TEMPLE_MQ_FREESTANDING_KEY, WATER_TEMPLE_SMALL_KEY, {Category::cWaterTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + + //Spirit Temple Shared + locationTable[SPIRIT_TEMPLE_SILVER_GAUNTLETS_CHEST] = ItemLocation::Chest (0x5C, 0x0B, "Spirit Temple Silver Gauntlets Chest", SPIRIT_TEMPLE_SILVER_GAUNTLETS_CHEST, PROGRESSIVE_STRENGTH, {Category::cSpiritTemple, Category::cDesertColossus}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MIRROR_SHIELD_CHEST] = ItemLocation::Chest (0x5C, 0x09, "Spirit Temple Mirror Shield Chest", SPIRIT_TEMPLE_MIRROR_SHIELD_CHEST, MIRROR_SHIELD, {Category::cSpiritTemple, Category::cDesertColossus}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + //Spirit Temple Vanilla + locationTable[SPIRIT_TEMPLE_CHILD_BRIDGE_CHEST] = ItemLocation::Chest (0x06, 0x08, "Spirit Temple Child Bridge Chest", SPIRIT_TEMPLE_CHILD_BRIDGE_CHEST, DEKU_SHIELD, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_CHILD_EARLY_TORCHES_CHEST] = ItemLocation::Chest (0x06, 0x00, "Spirit Temple Child Early Torches Chest", SPIRIT_TEMPLE_CHILD_EARLY_TORCHES_CHEST, SPIRIT_TEMPLE_SMALL_KEY, {Category::cSpiritTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_COMPASS_CHEST] = ItemLocation::Chest (0x06, 0x04, "Spirit Temple Compass Chest", SPIRIT_TEMPLE_COMPASS_CHEST, SPIRIT_TEMPLE_COMPASS, {Category::cSpiritTemple, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_EARLY_ADULT_RIGHT_CHEST] = ItemLocation::Chest (0x06, 0x07, "Spirit Temple Early Adult Right Chest", SPIRIT_TEMPLE_EARLY_ADULT_RIGHT_CHEST, SPIRIT_TEMPLE_SMALL_KEY, {Category::cSpiritTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_FIRST_MIRROR_LEFT_CHEST] = ItemLocation::Chest (0x06, 0x0D, "Spirit Temple First Mirror Left Chest", SPIRIT_TEMPLE_FIRST_MIRROR_LEFT_CHEST, ICE_TRAP, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_FIRST_MIRROR_RIGHT_CHEST] = ItemLocation::Chest (0x06, 0x0E, "Spirit Temple First Mirror Right Chest", SPIRIT_TEMPLE_FIRST_MIRROR_RIGHT_CHEST, RECOVERY_HEART, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MAP_CHEST] = ItemLocation::Chest (0x06, 0x03, "Spirit Temple Map Chest", SPIRIT_TEMPLE_MAP_CHEST, SPIRIT_TEMPLE_MAP, {Category::cSpiritTemple, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_CHILD_CLIMB_NORTH_CHEST] = ItemLocation::Chest (0x06, 0x06, "Spirit Temple Child Climb North Chest", SPIRIT_TEMPLE_CHILD_CLIMB_NORTH_CHEST, BOMBCHU_10, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_CHILD_CLIMB_EAST_CHEST] = ItemLocation::Chest (0x06, 0x0C, "Spirit Temple Child Climb East Chest", SPIRIT_TEMPLE_CHILD_CLIMB_EAST_CHEST, DEKU_SHIELD, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_SUN_BLOCK_ROOM_CHEST] = ItemLocation::Chest (0x06, 0x01, "Spirit Temple Sun Block Room Chest", SPIRIT_TEMPLE_SUN_BLOCK_ROOM_CHEST, SPIRIT_TEMPLE_SMALL_KEY, {Category::cSpiritTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_STATUE_ROOM_HAND_CHEST] = ItemLocation::Chest (0x06, 0x02, "Spirit Temple Statue Room Hand Chest", SPIRIT_TEMPLE_STATUE_ROOM_HAND_CHEST, SPIRIT_TEMPLE_SMALL_KEY, {Category::cSpiritTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_STATUE_ROOM_NORTHEAST_CHEST] = ItemLocation::Chest (0x06, 0x0F, "Spirit Temple Statue Room Northeast Chest", SPIRIT_TEMPLE_STATUE_ROOM_NORTHEAST_CHEST, BLUE_RUPEE, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_NEAR_FOUR_ARMOS_CHEST] = ItemLocation::Chest (0x06, 0x05, "Spirit Temple Near Four Armos Chest", SPIRIT_TEMPLE_NEAR_FOUR_ARMOS_CHEST, SPIRIT_TEMPLE_SMALL_KEY, {Category::cSpiritTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_HALLWAY_RIGHT_INVISIBLE_CHEST] = ItemLocation::Chest (0x06, 0x14, "Spirit Temple Hallway Right Invisible Chest", SPIRIT_TEMPLE_HALLWAY_RIGHT_INVISIBLE_CHEST, RECOVERY_HEART, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_HALLWAY_LEFT_INVISIBLE_CHEST] = ItemLocation::Chest (0x06, 0x15, "Spirit Temple Hallway Left Invisible Chest", SPIRIT_TEMPLE_HALLWAY_LEFT_INVISIBLE_CHEST, RECOVERY_HEART, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_BOSS_KEY_CHEST] = ItemLocation::Chest (0x06, 0x0A, "Spirit Temple Boss Key Chest", SPIRIT_TEMPLE_BOSS_KEY_CHEST, SPIRIT_TEMPLE_BOSS_KEY, {Category::cSpiritTemple, Category::cVanillaBossKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_TOPMOST_CHEST] = ItemLocation::Chest (0x06, 0x12, "Spirit Temple Topmost Chest", SPIRIT_TEMPLE_TOPMOST_CHEST, BOMBS_20, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + //Spirit Temple MQ + locationTable[SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_LEFT_CHEST] = ItemLocation::Chest (0x06, 0x1A, "Spirit Temple MQ Entrance Front Left Chest", SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_LEFT_CHEST, BOMBCHU_10, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_RIGHT_CHEST] = ItemLocation::Chest (0x06, 0x1F, "Spirit Temple MQ Entrance Back Right Chest", SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_RIGHT_CHEST, BOMBCHU_10, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_RIGHT_CHEST] = ItemLocation::Chest (0x06, 0x1B, "Spirit Temple MQ Entrance Front Right Chest", SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_RIGHT_CHEST, SPIRIT_TEMPLE_SMALL_KEY, {Category::cSpiritTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_LEFT_CHEST] = ItemLocation::Chest (0x06, 0x1E, "Spirit Temple MQ Entrance Back Left Chest", SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_LEFT_CHEST, SPIRIT_TEMPLE_SMALL_KEY, {Category::cSpiritTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_CHILD_HAMMER_SWITCH_CHEST] = ItemLocation::Chest (0x06, 0x1D, "Spirit Temple MQ Child Hammer Switch Chest", SPIRIT_TEMPLE_MQ_CHILD_HAMMER_SWITCH_CHEST, SPIRIT_TEMPLE_SMALL_KEY, {Category::cSpiritTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_MAP_CHEST] = ItemLocation::Chest (0x06, 0x00, "Spirit Temple MQ Map Chest", SPIRIT_TEMPLE_MQ_MAP_CHEST, SPIRIT_TEMPLE_MAP, {Category::cSpiritTemple, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_MAP_ROOM_ENEMY_CHEST] = ItemLocation::Chest (0x06, 0x08, "Spirit Temple MQ Map Room Enemy Chest", SPIRIT_TEMPLE_MQ_MAP_ROOM_ENEMY_CHEST, SPIRIT_TEMPLE_SMALL_KEY, {Category::cSpiritTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_CHILD_CLIMB_NORTH_CHEST] = ItemLocation::Chest (0x06, 0x06, "Spirit Temple MQ Child Climb North Chest", SPIRIT_TEMPLE_MQ_CHILD_CLIMB_NORTH_CHEST, BOMBCHU_10, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_CHILD_CLIMB_SOUTH_CHEST] = ItemLocation::Chest (0x06, 0x0C, "Spirit Temple MQ Child Climb South Chest", SPIRIT_TEMPLE_MQ_CHILD_CLIMB_SOUTH_CHEST, SPIRIT_TEMPLE_SMALL_KEY, {Category::cSpiritTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_COMPASS_CHEST] = ItemLocation::Chest (0x06, 0x03, "Spirit Temple MQ Compass Chest", SPIRIT_TEMPLE_MQ_COMPASS_CHEST, SPIRIT_TEMPLE_COMPASS, {Category::cSpiritTemple, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_STATUE_ROOM_LULLABY_CHEST] = ItemLocation::Chest (0x06, 0x0F, "Spirit Temple MQ Statue Room Lullaby Chest", SPIRIT_TEMPLE_MQ_STATUE_ROOM_LULLABY_CHEST, BLUE_RUPEE, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_STATUE_ROOM_INVISIBLE_CHEST] = ItemLocation::Chest (0x06, 0x02, "Spirit Temple MQ Statue Room Invisible Chest", SPIRIT_TEMPLE_MQ_STATUE_ROOM_INVISIBLE_CHEST, RECOVERY_HEART, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_SILVER_BLOCK_HALLWAY_CHEST] = ItemLocation::Chest (0x06, 0x1C, "Spirit Temple MQ Silver Block Hallway Chest", SPIRIT_TEMPLE_MQ_SILVER_BLOCK_HALLWAY_CHEST, SPIRIT_TEMPLE_SMALL_KEY, {Category::cSpiritTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM_CHEST] = ItemLocation::Chest (0x06, 0x01, "Spirit Temple MQ Sun Block Room Chest", SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM_CHEST, RECOVERY_HEART, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_SYMPHONY_ROOM_CHEST] = ItemLocation::Chest (0x06, 0x07, "Spirit Temple MQ Symphony Room Chest", SPIRIT_TEMPLE_MQ_SYMPHONY_ROOM_CHEST, PURPLE_RUPEE, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_LEEVER_ROOM_CHEST] = ItemLocation::Chest (0x06, 0x04, "Spirit Temple MQ Leever Room Chest", SPIRIT_TEMPLE_MQ_LEEVER_ROOM_CHEST, PURPLE_RUPEE, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_BEAMOS_ROOM_CHEST] = ItemLocation::Chest (0x06, 0x19, "Spirit Temple MQ Beamos Room Chest", SPIRIT_TEMPLE_MQ_BEAMOS_ROOM_CHEST, RECOVERY_HEART, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_CHEST_SWITCH_CHEST] = ItemLocation::Chest (0x06, 0x18, "Spirit Temple MQ Chest Switch Chest", SPIRIT_TEMPLE_MQ_CHEST_SWITCH_CHEST, ICE_TRAP, {Category::cSpiritTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_BOSS_KEY_CHEST] = ItemLocation::Chest (0x06, 0x05, "Spirit Temple MQ Boss Key Chest", SPIRIT_TEMPLE_MQ_BOSS_KEY_CHEST, SPIRIT_TEMPLE_BOSS_KEY, {Category::cSpiritTemple, Category::cVanillaBossKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_MIRROR_PUZZLE_INVISIBLE_CHEST] = ItemLocation::Chest (0x06, 0x12, "Spirit Temple MQ Mirror Puzzle Invisible Chest", SPIRIT_TEMPLE_MQ_MIRROR_PUZZLE_INVISIBLE_CHEST, SPIRIT_TEMPLE_SMALL_KEY, {Category::cSpiritTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + + //Shadow Temple Vanilla + locationTable[SHADOW_TEMPLE_MAP_CHEST] = ItemLocation::Chest (0x07, 0x01, "Shadow Temple Map Chest", SHADOW_TEMPLE_MAP_CHEST, SHADOW_TEMPLE_MAP, {Category::cShadowTemple, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_HOVER_BOOTS_CHEST] = ItemLocation::Chest (0x07, 0x07, "Shadow Temple Hover Boots Chest", SHADOW_TEMPLE_HOVER_BOOTS_CHEST, HOVER_BOOTS, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_COMPASS_CHEST] = ItemLocation::Chest (0x07, 0x03, "Shadow Temple Compass Chest", SHADOW_TEMPLE_COMPASS_CHEST, SHADOW_TEMPLE_COMPASS, {Category::cShadowTemple, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_EARLY_SILVER_RUPEE_CHEST] = ItemLocation::Chest (0x07, 0x02, "Shadow Temple Early Silver Rupee Chest", SHADOW_TEMPLE_EARLY_SILVER_RUPEE_CHEST, SHADOW_TEMPLE_SMALL_KEY, {Category::cShadowTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_INVISIBLE_BLADES_VISIBLE_CHEST] = ItemLocation::Chest (0x07, 0x0C, "Shadow Temple Invisible Blades Visible Chest", SHADOW_TEMPLE_INVISIBLE_BLADES_VISIBLE_CHEST, BLUE_RUPEE, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_INVISIBLE_BLADES_INVISIBLE_CHEST] = ItemLocation::Chest (0x07, 0x16, "Shadow Temple Invisible Blades Invisible Chest", SHADOW_TEMPLE_INVISIBLE_BLADES_INVISIBLE_CHEST, ARROWS_30, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_FALLING_SPIKES_LOWER_CHEST] = ItemLocation::Chest (0x07, 0x05, "Shadow Temple Falling Spikes Lower Chest", SHADOW_TEMPLE_FALLING_SPIKES_LOWER_CHEST, ARROWS_10, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_FALLING_SPIKES_UPPER_CHEST] = ItemLocation::Chest (0x07, 0x06, "Shadow Temple Falling Spikes Upper Chest", SHADOW_TEMPLE_FALLING_SPIKES_UPPER_CHEST, BLUE_RUPEE, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_FALLING_SPIKES_SWITCH_CHEST] = ItemLocation::Chest (0x07, 0x04, "Shadow Temple Falling Spikes Switch Chest", SHADOW_TEMPLE_FALLING_SPIKES_SWITCH_CHEST, SHADOW_TEMPLE_SMALL_KEY, {Category::cShadowTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_INVISIBLE_SPIKES_CHEST] = ItemLocation::Chest (0x07, 0x09, "Shadow Temple Invisible Spikes Chest", SHADOW_TEMPLE_INVISIBLE_SPIKES_CHEST, BLUE_RUPEE, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_WIND_HINT_CHEST] = ItemLocation::Chest (0x07, 0x15, "Shadow Temple Wind Hint Chest", SHADOW_TEMPLE_WIND_HINT_CHEST, ARROWS_10, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_AFTER_WIND_ENEMY_CHEST] = ItemLocation::Chest (0x07, 0x08, "Shadow Temple After Wind Enemy Chest", SHADOW_TEMPLE_AFTER_WIND_ENEMY_CHEST, BLUE_RUPEE, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_AFTER_WIND_HIDDEN_CHEST] = ItemLocation::Chest (0x07, 0x14, "Shadow Temple After Wind Hidden Chest", SHADOW_TEMPLE_AFTER_WIND_HIDDEN_CHEST, SHADOW_TEMPLE_SMALL_KEY, {Category::cShadowTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_SPIKE_WALLS_LEFT_CHEST] = ItemLocation::Chest (0x07, 0x0A, "Shadow Temple Spike Walls Left Chest", SHADOW_TEMPLE_SPIKE_WALLS_LEFT_CHEST, BLUE_RUPEE, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_BOSS_KEY_CHEST] = ItemLocation::Chest (0x07, 0x0B, "Shadow Temple Boss Key Chest", SHADOW_TEMPLE_BOSS_KEY_CHEST, SHADOW_TEMPLE_BOSS_KEY, {Category::cShadowTemple, Category::cVanillaBossKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_INVISIBLE_FLOORMASTER_CHEST] = ItemLocation::Chest (0x07, 0x0D, "Shadow Temple Invisible Floormaster Chest", SHADOW_TEMPLE_INVISIBLE_FLOORMASTER_CHEST, SHADOW_TEMPLE_SMALL_KEY, {Category::cShadowTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_FREESTANDING_KEY] = ItemLocation::Collectable(0x07, 0x01, "Shadow Temple Freestanding Key", SHADOW_TEMPLE_FREESTANDING_KEY, SHADOW_TEMPLE_SMALL_KEY, {Category::cShadowTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + //Shadow Temple MQ + locationTable[SHADOW_TEMPLE_MQ_COMPASS_CHEST] = ItemLocation::Chest (0x07, 0x01, "Shadow Temple MQ Compass Chest", SHADOW_TEMPLE_MQ_COMPASS_CHEST, SHADOW_TEMPLE_COMPASS, {Category::cShadowTemple, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_HOVER_BOOTS_CHEST] = ItemLocation::Chest (0x07, 0x07, "Shadow Temple MQ Hover Boots Chest", SHADOW_TEMPLE_MQ_HOVER_BOOTS_CHEST, HOVER_BOOTS, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_EARLY_GIBDOS_CHEST] = ItemLocation::Chest (0x07, 0x03, "Shadow Temple MQ Early Gibdos Chest", SHADOW_TEMPLE_MQ_EARLY_GIBDOS_CHEST, SHADOW_TEMPLE_SMALL_KEY, {Category::cShadowTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_MAP_CHEST] = ItemLocation::Chest (0x07, 0x02, "Shadow Temple MQ Map Chest", SHADOW_TEMPLE_MQ_MAP_CHEST, SHADOW_TEMPLE_MAP, {Category::cShadowTemple, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_BEAMOS_SILVER_RUPEES_CHEST] = ItemLocation::Chest (0x07, 0x0F, "Shadow Temple MQ Beamos Silver Rupees Chest", SHADOW_TEMPLE_MQ_BEAMOS_SILVER_RUPEES_CHEST, ARROWS_5, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_FALLING_SPIKES_SWITCH_CHEST] = ItemLocation::Chest (0x07, 0x04, "Shadow Temple MQ Falling Spikes Switch Chest", SHADOW_TEMPLE_MQ_FALLING_SPIKES_SWITCH_CHEST, SHADOW_TEMPLE_SMALL_KEY, {Category::cShadowTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_FALLING_SPIKES_LOWER_CHEST] = ItemLocation::Chest (0x07, 0x05, "Shadow Temple MQ Falling Spikes Lower Chest", SHADOW_TEMPLE_MQ_FALLING_SPIKES_LOWER_CHEST, ARROWS_10, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_FALLING_SPIKES_UPPER_CHEST] = ItemLocation::Chest (0x07, 0x06, "Shadow Temple MQ Falling Spikes Upper Chest", SHADOW_TEMPLE_MQ_FALLING_SPIKES_UPPER_CHEST, ARROWS_5, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_INVISIBLE_SPIKES_CHEST] = ItemLocation::Chest (0x07, 0x09, "Shadow Temple MQ Invisible Spikes Chest", SHADOW_TEMPLE_MQ_INVISIBLE_SPIKES_CHEST, BLUE_RUPEE, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_BOSS_KEY_CHEST] = ItemLocation::Chest (0x07, 0x0B, "Shadow Temple MQ Boss Key Chest", SHADOW_TEMPLE_MQ_BOSS_KEY_CHEST, SHADOW_TEMPLE_BOSS_KEY, {Category::cShadowTemple, Category::cVanillaBossKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_SPIKE_WALLS_LEFT_CHEST] = ItemLocation::Chest (0x07, 0x0A, "Shadow Temple MQ Spike Walls Left Chest", SHADOW_TEMPLE_MQ_SPIKE_WALLS_LEFT_CHEST, BLUE_RUPEE, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_STALFOS_ROOM_CHEST] = ItemLocation::Chest (0x07, 0x10, "Shadow Temple MQ Stalfos Room Chest", SHADOW_TEMPLE_MQ_STALFOS_ROOM_CHEST, RED_RUPEE, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_INVISIBLE_CHEST] = ItemLocation::Chest (0x07, 0x16, "Shadow Temple MQ Invisible Blades Invisible Chest", SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_INVISIBLE_CHEST, SHADOW_TEMPLE_SMALL_KEY, {Category::cShadowTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_VISIBLE_CHEST] = ItemLocation::Chest (0x07, 0x0C, "Shadow Temple MQ Invisible Blades Visible Chest", SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_VISIBLE_CHEST, BLUE_RUPEE, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_BOMB_FLOWER_CHEST] = ItemLocation::Chest (0x07, 0x0D, "Shadow Temple MQ Bomb Flower Chest", SHADOW_TEMPLE_MQ_BOMB_FLOWER_CHEST, ARROWS_10, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_WIND_HINT_CHEST] = ItemLocation::Chest (0x07, 0x15, "Shadow Temple MQ Wind Hint Chest", SHADOW_TEMPLE_MQ_WIND_HINT_CHEST, SHADOW_TEMPLE_SMALL_KEY, {Category::cShadowTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_AFTER_WIND_HIDDEN_CHEST] = ItemLocation::Chest (0x07, 0x14, "Shadow Temple MQ After Wind Hidden Chest", SHADOW_TEMPLE_MQ_AFTER_WIND_HIDDEN_CHEST, ARROWS_5, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_AFTER_WIND_ENEMY_CHEST] = ItemLocation::Chest (0x07, 0x08, "Shadow Temple MQ After Wind Enemy Chest", SHADOW_TEMPLE_MQ_AFTER_WIND_ENEMY_CHEST, BLUE_RUPEE, {Category::cShadowTemple,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_NEAR_SHIP_INVISIBLE_CHEST] = ItemLocation::Chest (0x07, 0x0E, "Shadow Temple MQ Near Ship Invisible Chest", SHADOW_TEMPLE_MQ_NEAR_SHIP_INVISIBLE_CHEST, SHADOW_TEMPLE_SMALL_KEY, {Category::cShadowTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_FREESTANDING_KEY] = ItemLocation::Collectable(0x07, 0x06, "Shadow Temple MQ Freestanding Key", SHADOW_TEMPLE_MQ_FREESTANDING_KEY, SHADOW_TEMPLE_SMALL_KEY, {Category::cShadowTemple, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + + //Bottom of the Well Vanilla + locationTable[BOTTOM_OF_THE_WELL_FRONT_LEFT_FAKE_WALL_CHEST] = ItemLocation::Chest (0x08, 0x08, "Bottom of the Well Front Left Fake Wall Chest", BOTTOM_OF_THE_WELL_FRONT_LEFT_FAKE_WALL_CHEST, BOTTOM_OF_THE_WELL_SMALL_KEY, {Category::cBottomOfTheWell, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_FRONT_CENTER_BOMBABLE_CHEST] = ItemLocation::Chest (0x08, 0x02, "Bottom of the Well Front Center Bombable Chest", BOTTOM_OF_THE_WELL_FRONT_CENTER_BOMBABLE_CHEST, BOMBCHU_10, {Category::cBottomOfTheWell,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_RIGHT_BOTTOM_FAKE_WALL_CHEST] = ItemLocation::Chest (0x08, 0x05, "Bottom of the Well Right Bottom Fake Wall Chest", BOTTOM_OF_THE_WELL_RIGHT_BOTTOM_FAKE_WALL_CHEST, BOTTOM_OF_THE_WELL_SMALL_KEY, {Category::cBottomOfTheWell, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_COMPASS_CHEST] = ItemLocation::Chest (0x08, 0x01, "Bottom of the Well Compass Chest", BOTTOM_OF_THE_WELL_COMPASS_CHEST, BOTTOM_OF_THE_WELL_COMPASS, {Category::cBottomOfTheWell, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_CENTER_SKULLTULA_CHEST] = ItemLocation::Chest (0x08, 0x0E, "Bottom of the Well Center Skulltula Chest", BOTTOM_OF_THE_WELL_CENTER_SKULLTULA_CHEST, DEKU_NUTS_5, {Category::cBottomOfTheWell,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_BACK_LEFT_BOMBABLE_CHEST] = ItemLocation::Chest (0x08, 0x04, "Bottom of the Well Back Left Bombable Chest", BOTTOM_OF_THE_WELL_BACK_LEFT_BOMBABLE_CHEST, DEKU_NUTS_10, {Category::cBottomOfTheWell,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_LENS_OF_TRUTH_CHEST] = ItemLocation::Chest (0x08, 0x03, "Bottom of the Well Lens of Truth Chest", BOTTOM_OF_THE_WELL_LENS_OF_TRUTH_CHEST, LENS_OF_TRUTH, {Category::cBottomOfTheWell, Category::cSongDungeonReward}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_INVISIBLE_CHEST] = ItemLocation::Chest (0x08, 0x14, "Bottom of the Well Invisible Chest", BOTTOM_OF_THE_WELL_INVISIBLE_CHEST, HUGE_RUPEE, {Category::cBottomOfTheWell,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_UNDERWATER_FRONT_CHEST] = ItemLocation::Chest (0x08, 0x10, "Bottom of the Well Underwater Front Chest", BOTTOM_OF_THE_WELL_UNDERWATER_FRONT_CHEST, BOMBS_10, {Category::cBottomOfTheWell,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_UNDERWATER_LEFT_CHEST] = ItemLocation::Chest (0x08, 0x09, "Bottom of the Well Underwater Left Chest", BOTTOM_OF_THE_WELL_UNDERWATER_LEFT_CHEST, RECOVERY_HEART, {Category::cBottomOfTheWell,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_MAP_CHEST] = ItemLocation::Chest (0x08, 0x07, "Bottom of the Well Map Chest", BOTTOM_OF_THE_WELL_MAP_CHEST, BOTTOM_OF_THE_WELL_MAP, {Category::cBottomOfTheWell, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_FIRE_KEESE_CHEST] = ItemLocation::Chest (0x08, 0x0A, "Bottom of the Well Fire Keese Chest", BOTTOM_OF_THE_WELL_FIRE_KEESE_CHEST, DEKU_SHIELD, {Category::cBottomOfTheWell,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_LIKE_LIKE_CHEST] = ItemLocation::Chest (0x08, 0x0C, "Bottom of the Well Like Like Chest", BOTTOM_OF_THE_WELL_LIKE_LIKE_CHEST, HYLIAN_SHIELD, {Category::cBottomOfTheWell,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_FREESTANDING_KEY] = ItemLocation::Collectable(0x08, 0x01, "Bottom of the Well Freestanding Key", BOTTOM_OF_THE_WELL_FREESTANDING_KEY, BOTTOM_OF_THE_WELL_SMALL_KEY, {Category::cBottomOfTheWell, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + //Bottom of the Well MQBottomOfTheWell] + locationTable[BOTTOM_OF_THE_WELL_MQ_MAP_CHEST] = ItemLocation::Chest (0x08, 0x03, "Bottom of the Well MQ Map Chest", BOTTOM_OF_THE_WELL_MQ_MAP_CHEST, BOTTOM_OF_THE_WELL_MAP, {Category::cBottomOfTheWell, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_MQ_LENS_OF_TRUTH_CHEST] = ItemLocation::Chest (0x08, 0x01, "Bottom of the Well MQ Lens of Truth Chest", BOTTOM_OF_THE_WELL_MQ_LENS_OF_TRUTH_CHEST, LENS_OF_TRUTH, {Category::cBottomOfTheWell, Category::cSongDungeonReward}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_MQ_COMPASS_CHEST] = ItemLocation::Chest (0x08, 0x02, "Bottom of the Well MQ Compass Chest", BOTTOM_OF_THE_WELL_MQ_COMPASS_CHEST, BOTTOM_OF_THE_WELL_COMPASS, {Category::cBottomOfTheWell, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_MQ_DEAD_HAND_FREESTANDING_KEY] = ItemLocation::Collectable(0x08, 0x02, "Bottom of the Well MQ Dead Hand Freestanding Key", BOTTOM_OF_THE_WELL_MQ_DEAD_HAND_FREESTANDING_KEY, BOTTOM_OF_THE_WELL_SMALL_KEY, {Category::cBottomOfTheWell, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_MQ_EAST_INNER_ROOM_FREESTANDING_KEY] = ItemLocation::Collectable(0x08, 0x01, "Bottom of the Well MQ East Inner Room Freestanding Key",BOTTOM_OF_THE_WELL_MQ_EAST_INNER_ROOM_FREESTANDING_KEY, BOTTOM_OF_THE_WELL_SMALL_KEY, {Category::cBottomOfTheWell, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + + //Ice Cavern Vanilla + locationTable[ICE_CAVERN_MAP_CHEST] = ItemLocation::Chest (0x09, 0x00, "Ice Cavern Map Chest", ICE_CAVERN_MAP_CHEST, ICE_CAVERN_MAP, {Category::cIceCavern, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_ICE_CAVERN); + locationTable[ICE_CAVERN_COMPASS_CHEST] = ItemLocation::Chest (0x09, 0x01, "Ice Cavern Compass Chest", ICE_CAVERN_COMPASS_CHEST, ICE_CAVERN_COMPASS, {Category::cIceCavern, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_ICE_CAVERN); + locationTable[ICE_CAVERN_IRON_BOOTS_CHEST] = ItemLocation::Chest (0x09, 0x02, "Ice Cavern Iron Boots Chest", ICE_CAVERN_IRON_BOOTS_CHEST, IRON_BOOTS, {Category::cIceCavern,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_ICE_CAVERN); + locationTable[ICE_CAVERN_FREESTANDING_POH] = ItemLocation::Collectable(0x09, 0x01, "Ice Cavern Freestanding PoH", ICE_CAVERN_FREESTANDING_POH, PIECE_OF_HEART, {Category::cIceCavern,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_ICE_CAVERN); + //Ice Cavern MQIceCavern] + locationTable[ICE_CAVERN_MQ_IRON_BOOTS_CHEST] = ItemLocation::Chest (0x09, 0x02, "Ice Cavern MQ Iron Boots Chest", ICE_CAVERN_MQ_IRON_BOOTS_CHEST, IRON_BOOTS, {Category::cIceCavern,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_ICE_CAVERN); + locationTable[ICE_CAVERN_MQ_COMPASS_CHEST] = ItemLocation::Chest (0x09, 0x00, "Ice Cavern MQ Compass Chest", ICE_CAVERN_MQ_COMPASS_CHEST, ICE_CAVERN_COMPASS, {Category::cIceCavern, Category::cVanillaCompass,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_ICE_CAVERN); + locationTable[ICE_CAVERN_MQ_MAP_CHEST] = ItemLocation::Chest (0x09, 0x01, "Ice Cavern MQ Map Chest", ICE_CAVERN_MQ_MAP_CHEST, ICE_CAVERN_MAP, {Category::cIceCavern, Category::cVanillaMap,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_ICE_CAVERN); + locationTable[ICE_CAVERN_MQ_FREESTANDING_POH] = ItemLocation::Collectable(0x09, 0x01, "Ice Cavern MQ Freestanding PoH", ICE_CAVERN_MQ_FREESTANDING_POH, PIECE_OF_HEART, {Category::cIceCavern,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_ICE_CAVERN); + + //Gerudo Training Ground Vanilla + locationTable[GERUDO_TRAINING_GROUNDS_LOBBY_LEFT_CHEST] = ItemLocation::Chest (0x0B, 0x13, "Gerudo Training Grounds Lobby Left Chest", GERUDO_TRAINING_GROUNDS_LOBBY_LEFT_CHEST, BLUE_RUPEE, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_LOBBY_RIGHT_CHEST] = ItemLocation::Chest (0x0B, 0x07, "Gerudo Training Grounds Lobby Right Chest", GERUDO_TRAINING_GROUNDS_LOBBY_RIGHT_CHEST, ARROWS_10, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_STALFOS_CHEST] = ItemLocation::Chest (0x0B, 0x00, "Gerudo Training Grounds Stalfos Chest", GERUDO_TRAINING_GROUNDS_STALFOS_CHEST, GERUDO_TRAINING_GROUNDS_SMALL_KEY, {Category::cGerudoTrainingGrounds, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_BEAMOS_CHEST] = ItemLocation::Chest (0x0B, 0x01, "Gerudo Training Grounds Beamos Chest", GERUDO_TRAINING_GROUNDS_BEAMOS_CHEST, GERUDO_TRAINING_GROUNDS_SMALL_KEY, {Category::cGerudoTrainingGrounds, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_HIDDEN_CEILING_CHEST] = ItemLocation::Chest (0x0B, 0x0B, "Gerudo Training Grounds Hidden Ceiling Chest", GERUDO_TRAINING_GROUNDS_HIDDEN_CEILING_CHEST, GERUDO_TRAINING_GROUNDS_SMALL_KEY, {Category::cGerudoTrainingGrounds, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MAZE_PATH_FIRST_CHEST] = ItemLocation::Chest (0x0B, 0x06, "Gerudo Training Grounds Maze Path First Chest", GERUDO_TRAINING_GROUNDS_MAZE_PATH_FIRST_CHEST, PURPLE_RUPEE, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MAZE_PATH_SECOND_CHEST] = ItemLocation::Chest (0x0B, 0x0A, "Gerudo Training Grounds Maze Path Second Chest", GERUDO_TRAINING_GROUNDS_MAZE_PATH_SECOND_CHEST, RED_RUPEE, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MAZE_PATH_THIRD_CHEST] = ItemLocation::Chest (0x0B, 0x09, "Gerudo Training Grounds Maze Path Third Chest", GERUDO_TRAINING_GROUNDS_MAZE_PATH_THIRD_CHEST, ARROWS_30, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MAZE_PATH_FINAL_CHEST] = ItemLocation::Chest (0x0B, 0x0C, "Gerudo Training Grounds Maze Path Final Chest", GERUDO_TRAINING_GROUNDS_MAZE_PATH_FINAL_CHEST, ICE_ARROWS, {Category::cGerudoTrainingGrounds, Category::cSongDungeonReward}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MAZE_RIGHT_CENTRAL_CHEST] = ItemLocation::Chest (0x0B, 0x05, "Gerudo Training Grounds Maze Right Central Chest", GERUDO_TRAINING_GROUNDS_MAZE_RIGHT_CENTRAL_CHEST, BOMBCHU_5, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MAZE_RIGHT_SIDE_CHEST] = ItemLocation::Chest (0x0B, 0x08, "Gerudo Training Grounds Maze Right Side Chest", GERUDO_TRAINING_GROUNDS_MAZE_RIGHT_SIDE_CHEST, ARROWS_30, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_UNDERWATER_SILVER_RUPEE_CHEST] = ItemLocation::Chest (0x0B, 0x0D, "Gerudo Training Grounds Underwater Silver Rupee Chest", GERUDO_TRAINING_GROUNDS_UNDERWATER_SILVER_RUPEE_CHEST, GERUDO_TRAINING_GROUNDS_SMALL_KEY, {Category::cGerudoTrainingGrounds, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_HAMMER_ROOM_CLEAR_CHEST] = ItemLocation::Chest (0x0B, 0x12, "Gerudo Training Grounds Hammer Room Clear Chest", GERUDO_TRAINING_GROUNDS_HAMMER_ROOM_CLEAR_CHEST, ARROWS_10, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_HAMMER_ROOM_SWITCH_CHEST] = ItemLocation::Chest (0x0B, 0x10, "Gerudo Training Grounds Hammer Room Switch Chest", GERUDO_TRAINING_GROUNDS_HAMMER_ROOM_SWITCH_CHEST, GERUDO_TRAINING_GROUNDS_SMALL_KEY, {Category::cGerudoTrainingGrounds, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_EYE_STATUE_CHEST] = ItemLocation::Chest (0x0B, 0x03, "Gerudo Training Grounds Eye Statue Chest", GERUDO_TRAINING_GROUNDS_EYE_STATUE_CHEST, GERUDO_TRAINING_GROUNDS_SMALL_KEY, {Category::cGerudoTrainingGrounds, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_NEAR_SCARECROW_CHEST] = ItemLocation::Chest (0x0B, 0x04, "Gerudo Training Grounds Near Scarecrow Chest", GERUDO_TRAINING_GROUNDS_NEAR_SCARECROW_CHEST, GERUDO_TRAINING_GROUNDS_SMALL_KEY, {Category::cGerudoTrainingGrounds, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_BEFORE_HEAVY_BLOCK_CHEST] = ItemLocation::Chest (0x0B, 0x11, "Gerudo Training Grounds Before Heavy Block Chest", GERUDO_TRAINING_GROUNDS_BEFORE_HEAVY_BLOCK_CHEST, ARROWS_30, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_FIRST_CHEST] = ItemLocation::Chest (0x0B, 0x0F, "Gerudo Training Grounds Heavy Block First Chest", GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_FIRST_CHEST, HUGE_RUPEE, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_SECOND_CHEST] = ItemLocation::Chest (0x0B, 0x0E, "Gerudo Training Grounds Heavy Block Second Chest", GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_SECOND_CHEST, BLUE_RUPEE, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_THIRD_CHEST] = ItemLocation::Chest (0x0B, 0x14, "Gerudo Training Grounds Heavy Block Third Chest", GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_THIRD_CHEST, GERUDO_TRAINING_GROUNDS_SMALL_KEY, {Category::cGerudoTrainingGrounds, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_FOURTH_CHEST] = ItemLocation::Chest (0x0B, 0x02, "Gerudo Training Grounds Heavy Block Fourth Chest", GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_FOURTH_CHEST, ICE_TRAP, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_FREESTANDING_KEY] = ItemLocation::Collectable(0x0B, 0x01, "Gerudo Training Grounds Freestanding Key", GERUDO_TRAINING_GROUNDS_FREESTANDING_KEY, GERUDO_TRAINING_GROUNDS_SMALL_KEY, {Category::cGerudoTrainingGrounds, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + //Gerudo Training Grounds MQ + locationTable[GERUDO_TRAINING_GROUNDS_MQ_LOBBY_RIGHT_CHEST] = ItemLocation::Chest (0x0B, 0x07, "Gerudo Training Grounds MQ Lobby Right Chest", GERUDO_TRAINING_GROUNDS_MQ_LOBBY_RIGHT_CHEST, BOMBCHU_5, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MQ_LOBBY_LEFT_CHEST] = ItemLocation::Chest (0x0B, 0x13, "Gerudo Training Grounds MQ Lobby Left Chest", GERUDO_TRAINING_GROUNDS_MQ_LOBBY_LEFT_CHEST, ARROWS_10, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MQ_FIRST_IRON_KNUCKLE_CHEST] = ItemLocation::Chest (0x0B, 0x00, "Gerudo Training Grounds MQ First Iron Knuckle Chest", GERUDO_TRAINING_GROUNDS_MQ_FIRST_IRON_KNUCKLE_CHEST, BLUE_RUPEE, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MQ_BEFORE_HEAVY_BLOCK_CHEST] = ItemLocation::Chest (0x0B, 0x11, "Gerudo Training Grounds MQ Before Heavy Block Chest", GERUDO_TRAINING_GROUNDS_MQ_BEFORE_HEAVY_BLOCK_CHEST, ARROWS_10, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MQ_EYE_STATUE_CHEST] = ItemLocation::Chest (0x0B, 0x03, "Gerudo Training Grounds MQ Eye Statue Chest", GERUDO_TRAINING_GROUNDS_MQ_EYE_STATUE_CHEST, BOMBCHU_10, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MQ_FLAME_CIRCLE_CHEST] = ItemLocation::Chest (0x0B, 0x0E, "Gerudo Training Grounds MQ Flame Circle Chest", GERUDO_TRAINING_GROUNDS_MQ_FLAME_CIRCLE_CHEST, GERUDO_TRAINING_GROUNDS_SMALL_KEY, {Category::cGerudoTrainingGrounds, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MQ_SECOND_IRON_KNUCKLE_CHEST] = ItemLocation::Chest (0x0B, 0x12, "Gerudo Training Grounds MQ Second Iron Knuckle Chest", GERUDO_TRAINING_GROUNDS_MQ_SECOND_IRON_KNUCKLE_CHEST, ARROWS_10, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MQ_DINOLFOS_CHEST] = ItemLocation::Chest (0x0B, 0x01, "Gerudo Training Grounds MQ Dinolfos Chest", GERUDO_TRAINING_GROUNDS_MQ_DINOLFOS_CHEST, GERUDO_TRAINING_GROUNDS_SMALL_KEY, {Category::cGerudoTrainingGrounds, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MQ_ICE_ARROWS_CHEST] = ItemLocation::Chest (0x0B, 0x04, "Gerudo Training Grounds MQ Ice Arrows Chest", GERUDO_TRAINING_GROUNDS_MQ_ICE_ARROWS_CHEST, ICE_ARROWS, {Category::cGerudoTrainingGrounds, Category::cSongDungeonReward}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MQ_MAZE_RIGHT_CENTRAL_CHEST] = ItemLocation::Chest (0x0B, 0x05, "Gerudo Training Grounds MQ Maze Right Central Chest", GERUDO_TRAINING_GROUNDS_MQ_MAZE_RIGHT_CENTRAL_CHEST, BLUE_RUPEE, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_FIRST_CHEST] = ItemLocation::Chest (0x0B, 0x06, "Gerudo Training Grounds MQ Maze Path First Chest", GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_FIRST_CHEST, GREEN_RUPEE, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MQ_MAZE_RIGHT_SIDE_CHEST] = ItemLocation::Chest (0x0B, 0x08, "Gerudo Training Grounds MQ Maze Right Side Chest", GERUDO_TRAINING_GROUNDS_MQ_MAZE_RIGHT_SIDE_CHEST, TREASURE_GAME_GREEN_RUPEE, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_THIRD_CHEST] = ItemLocation::Chest (0x0B, 0x09, "Gerudo Training Grounds MQ Maze Path Third Chest", GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_THIRD_CHEST, TREASURE_GAME_GREEN_RUPEE, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_SECOND_CHEST] = ItemLocation::Chest (0x0B, 0x0A, "Gerudo Training Grounds MQ Maze Path Second Chest", GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_SECOND_CHEST, RED_RUPEE, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MQ_HIDDEN_CEILING_CHEST] = ItemLocation::Chest (0x0B, 0x0B, "Gerudo Training Grounds MQ Hidden Ceiling Chest", GERUDO_TRAINING_GROUNDS_MQ_HIDDEN_CEILING_CHEST, PURPLE_RUPEE, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER_SILVER_RUPEE_CHEST] = ItemLocation::Chest (0x0B, 0x0D, "Gerudo Training Grounds MQ Underwater Silver Rupee Chest",GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER_SILVER_RUPEE_CHEST, TREASURE_GAME_GREEN_RUPEE, {Category::cGerudoTrainingGrounds, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + locationTable[GERUDO_TRAINING_GROUNDS_MQ_HEAVY_BLOCK_CHEST] = ItemLocation::Chest (0x0B, 0x02, "Gerudo Training Grounds MQ Heavy Block Chest", GERUDO_TRAINING_GROUNDS_MQ_HEAVY_BLOCK_CHEST, PURPLE_RUPEE, {Category::cGerudoTrainingGrounds,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_TRAINING_GROUND); + + //Ganons Castle Shared + locationTable[GANONS_TOWER_BOSS_KEY_CHEST] = ItemLocation::Chest (0x0A, 0x0B, "Ganon's Tower Boss Key Chest", GANONS_TOWER_BOSS_KEY_CHEST, GANONS_CASTLE_BOSS_KEY, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + //Ganons Castle Vanilla + locationTable[GANONS_CASTLE_FOREST_TRIAL_CHEST] = ItemLocation::Chest (0x0D, 0x09, "Ganon's Castle Forest Trial Chest", GANONS_CASTLE_FOREST_TRIAL_CHEST, BLUE_RUPEE, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_WATER_TRIAL_LEFT_CHEST] = ItemLocation::Chest (0x0D, 0x07, "Ganon's Castle Water Trial Left Chest", GANONS_CASTLE_WATER_TRIAL_LEFT_CHEST, ICE_TRAP, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_WATER_TRIAL_RIGHT_CHEST] = ItemLocation::Chest (0x0D, 0x06, "Ganon's Castle Water Trial Right Chest", GANONS_CASTLE_WATER_TRIAL_RIGHT_CHEST, RECOVERY_HEART, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_SHADOW_TRIAL_FRONT_CHEST] = ItemLocation::Chest (0x0D, 0x08, "Ganon's Castle Shadow Trial Front Chest", GANONS_CASTLE_SHADOW_TRIAL_FRONT_CHEST, BLUE_RUPEE, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_SHADOW_TRIAL_GOLDEN_GAUNTLETS_CHEST] = ItemLocation::Chest (0x0D, 0x05, "Ganon's Castle Shadow Trial Golden Gauntlets Chest", GANONS_CASTLE_SHADOW_TRIAL_GOLDEN_GAUNTLETS_CHEST, PROGRESSIVE_STRENGTH, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_SPIRIT_TRIAL_CRYSTAL_SWITCH_CHEST] = ItemLocation::Chest (0x0D, 0x12, "Ganon's Castle Spirit Trial Crystal Switch Chest", GANONS_CASTLE_SPIRIT_TRIAL_CRYSTAL_SWITCH_CHEST, BOMBCHU_20, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_SPIRIT_TRIAL_INVISIBLE_CHEST] = ItemLocation::Chest (0x0D, 0x14, "Ganon's Castle Spirit Trial Invisible Chest", GANONS_CASTLE_SPIRIT_TRIAL_INVISIBLE_CHEST, ARROWS_10, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_LIGHT_TRIAL_FIRST_LEFT_CHEST] = ItemLocation::Chest (0x0D, 0x0C, "Ganon's Castle Light Trial First Left Chest", GANONS_CASTLE_LIGHT_TRIAL_FIRST_LEFT_CHEST, BLUE_RUPEE, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_LIGHT_TRIAL_SECOND_LEFT_CHEST] = ItemLocation::Chest (0x0D, 0x0B, "Ganon's Castle Light Trial Second Left Chest", GANONS_CASTLE_LIGHT_TRIAL_SECOND_LEFT_CHEST, ICE_TRAP, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_LIGHT_TRIAL_THIRD_LEFT_CHEST] = ItemLocation::Chest (0x0D, 0x0D, "Ganon's Castle Light Trial Third Left Chest", GANONS_CASTLE_LIGHT_TRIAL_THIRD_LEFT_CHEST, RECOVERY_HEART, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_LIGHT_TRIAL_FIRST_RIGHT_CHEST] = ItemLocation::Chest (0x0D, 0x0E, "Ganon's Castle Light Trial First Right Chest", GANONS_CASTLE_LIGHT_TRIAL_FIRST_RIGHT_CHEST, ICE_TRAP, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_LIGHT_TRIAL_SECOND_RIGHT_CHEST] = ItemLocation::Chest (0x0D, 0x0A, "Ganon's Castle Light Trial Second Right Chest", GANONS_CASTLE_LIGHT_TRIAL_SECOND_RIGHT_CHEST, ARROWS_30, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_LIGHT_TRIAL_THIRD_RIGHT_CHEST] = ItemLocation::Chest (0x0D, 0x0F, "Ganon's Castle Light Trial Third Right Chest", GANONS_CASTLE_LIGHT_TRIAL_THIRD_RIGHT_CHEST, ICE_TRAP, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_LIGHT_TRIAL_INVISIBLE_ENEMIES_CHEST] = ItemLocation::Chest (0x0D, 0x10, "Ganon's Castle Light Trial Invisible Enemies Chest", GANONS_CASTLE_LIGHT_TRIAL_INVISIBLE_ENEMIES_CHEST, GANONS_CASTLE_SMALL_KEY, {Category::cGanonsCastle, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_LIGHT_TRIAL_LULLABY_CHEST] = ItemLocation::Chest (0x0D, 0x11, "Ganon's Castle Light Trial Lullaby Chest", GANONS_CASTLE_LIGHT_TRIAL_LULLABY_CHEST, GANONS_CASTLE_SMALL_KEY, {Category::cGanonsCastle, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT] = ItemLocation::Base (0x0D, 0x37, "Ganon's Castle Deku Scrub Center-Left", GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT, BUY_BOMBS_535, {Category::cGanonsCastle, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x0D, 0x06), SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT] = ItemLocation::Base (0x0D, 0x33, "Ganon's Castle Deku Scrub Center-Right", GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT, BUY_ARROWS_30, {Category::cGanonsCastle, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x0D, 0x04), SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_DEKU_SCRUB_RIGHT] = ItemLocation::Base (0x0D, 0x39, "Ganon's Castle Deku Scrub Right", GANONS_CASTLE_DEKU_SCRUB_RIGHT, BUY_RED_POTION_30, {Category::cGanonsCastle, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x0D, 0x08), SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_DEKU_SCRUB_LEFT] = ItemLocation::Base (0x0D, 0x3A, "Ganon's Castle Deku Scrub Left", GANONS_CASTLE_DEKU_SCRUB_LEFT, BUY_GREEN_POTION, {Category::cGanonsCastle, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x0D, 0x09), SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + //Ganons Castle MQ + locationTable[GANONS_CASTLE_MQ_WATER_TRIAL_CHEST] = ItemLocation::Chest (0x0D, 0x01, "Ganon's Castle MQ Water Trial Chest", GANONS_CASTLE_MQ_WATER_TRIAL_CHEST, RED_RUPEE, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_FOREST_TRIAL_EYE_SWITCH_CHEST] = ItemLocation::Chest (0x0D, 0x02, "Ganon's Castle MQ Forest Trial Eye Switch Chest", GANONS_CASTLE_MQ_FOREST_TRIAL_EYE_SWITCH_CHEST, ARROWS_10, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_FOREST_TRIAL_FROZEN_EYE_SWITCH_CHEST] = ItemLocation::Chest (0x0D, 0x03, "Ganon's Castle MQ Forest Trial Frozen Eye Switch Chest",GANONS_CASTLE_MQ_FOREST_TRIAL_FROZEN_EYE_SWITCH_CHEST, BOMBS_5, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_LIGHT_TRIAL_LULLABY_CHEST] = ItemLocation::Chest (0x0D, 0x04, "Ganon's Castle MQ Light Trial Lullaby Chest", GANONS_CASTLE_MQ_LIGHT_TRIAL_LULLABY_CHEST, RECOVERY_HEART, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_SHADOW_TRIAL_BOMB_FLOWER_CHEST] = ItemLocation::Chest (0x0D, 0x00, "Ganon's Castle MQ Shadow Trial Bomb Flower Chest", GANONS_CASTLE_MQ_SHADOW_TRIAL_BOMB_FLOWER_CHEST, ARROWS_10, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_SHADOW_TRIAL_EYE_SWITCH_CHEST] = ItemLocation::Chest (0x0D, 0x05, "Ganon's Castle MQ Shadow Trial Eye Switch Chest", GANONS_CASTLE_MQ_SHADOW_TRIAL_EYE_SWITCH_CHEST, GANONS_CASTLE_SMALL_KEY, {Category::cGanonsCastle, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_SPIRIT_TRIAL_GOLDEN_GAUNTLETS_CHEST] = ItemLocation::Chest (0x0D, 0x06, "Ganon's Castle MQ Spirit Trial Golden Gauntlets Chest", GANONS_CASTLE_MQ_SPIRIT_TRIAL_GOLDEN_GAUNTLETS_CHEST, PROGRESSIVE_STRENGTH, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_RIGHT_CHEST] = ItemLocation::Chest (0x0D, 0x07, "Ganon's Castle MQ Spirit Trial Sun Back Right Chest", GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_RIGHT_CHEST, RECOVERY_HEART, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_LEFT_CHEST] = ItemLocation::Chest (0x0D, 0x08, "Ganon's Castle MQ Spirit Trial Sun Back Left Chest", GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_LEFT_CHEST, GANONS_CASTLE_SMALL_KEY, {Category::cGanonsCastle, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_FRONT_LEFT_CHEST] = ItemLocation::Chest (0x0D, 0x09, "Ganon's Castle MQ Spirit Trial Sun Front Left Chest", GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_FRONT_LEFT_CHEST, RECOVERY_HEART, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_SPIRIT_TRIAL_FIRST_CHEST] = ItemLocation::Chest (0x0D, 0x0A, "Ganon's Castle MQ Spirit Trial First Chest", GANONS_CASTLE_MQ_SPIRIT_TRIAL_FIRST_CHEST, BOMBCHU_10, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_SPIRIT_TRIAL_INVISIBLE_CHEST] = ItemLocation::Chest (0x0D, 0x14, "Ganon's Castle MQ Spirit Trial Invisible Chest", GANONS_CASTLE_MQ_SPIRIT_TRIAL_INVISIBLE_CHEST, ARROWS_10, {Category::cGanonsCastle,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_FOREST_TRIAL_FREESTANDING_KEY] = ItemLocation::Collectable(0x0D, 0x01, "Ganon's Castle MQ Forest Trial Freestanding Key", GANONS_CASTLE_MQ_FOREST_TRIAL_FREESTANDING_KEY, GANONS_CASTLE_SMALL_KEY, {Category::cGanonsCastle, Category::cVanillaSmallKey}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT] = ItemLocation::Base (0x0D, 0x30, "Ganon's Castle MQ Deku Scrub Right", GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT, BUY_DEKU_NUT_5, {Category::cGanonsCastle, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x0D, 0x01), SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT] = ItemLocation::Base (0x0D, 0x37, "Ganon's Castle MQ Deku Scrub Center-Left", GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT, BUY_BOMBS_535, {Category::cGanonsCastle, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x0D, 0x06), SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER] = ItemLocation::Base (0x0D, 0x33, "Ganon's Castle MQ Deku Scrub Center", GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER, BUY_ARROWS_30, {Category::cGanonsCastle, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x0D, 0x04), SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT] = ItemLocation::Base (0x0D, 0x39, "Ganon's Castle MQ Deku Scrub Center-Right", GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT, BUY_RED_POTION_30, {Category::cGanonsCastle, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x0D, 0x08), SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT] = ItemLocation::Base (0x0D, 0x3A, "Ganon's Castle MQ Deku Scrub Left", GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT, BUY_GREEN_POTION, {Category::cGanonsCastle, Category::cDekuScrub,}, SpoilerCollectionCheck::Scrub(0x0D, 0x09), SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + + /*------------------------------- + --- GOLD SKULLTULA TOKENS --- + -------------------------------*/ + + //Dungeons + locationTable[DEKU_TREE_GS_BASEMENT_BACK_ROOM] = ItemLocation::GSToken(0x00, 0x01, "Deku Tree GS Basement Back Room", DEKU_TREE_GS_BASEMENT_BACK_ROOM, {Category::cDekuTree, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_GS_BASEMENT_GATE] = ItemLocation::GSToken(0x00, 0x02, "Deku Tree GS Basement Gate", DEKU_TREE_GS_BASEMENT_GATE, {Category::cDekuTree, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_GS_BASEMENT_VINES] = ItemLocation::GSToken(0x00, 0x04, "Deku Tree GS Basement Vines", DEKU_TREE_GS_BASEMENT_VINES, {Category::cDekuTree, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_GS_COMPASS_ROOM] = ItemLocation::GSToken(0x00, 0x08, "Deku Tree GS Compass Room", DEKU_TREE_GS_COMPASS_ROOM, {Category::cDekuTree, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + + locationTable[DEKU_TREE_MQ_GS_LOBBY] = ItemLocation::GSToken(0x00, 0x02, "Deku Tree MQ GS Lobby", DEKU_TREE_MQ_GS_LOBBY, {Category::cDekuTree, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_MQ_GS_COMPASS_ROOM] = ItemLocation::GSToken(0x00, 0x08, "Deku Tree MQ GS Compass Room", DEKU_TREE_MQ_GS_COMPASS_ROOM, {Category::cDekuTree, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_MQ_GS_BASEMENT_GRAVES_ROOM] = ItemLocation::GSToken(0x00, 0x04, "Deku Tree MQ GS Basement Graves Room", DEKU_TREE_MQ_GS_BASEMENT_GRAVES_ROOM, {Category::cDekuTree, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DEKU_TREE_MQ_GS_BASEMENT_BACK_ROOM] = ItemLocation::GSToken(0x00, 0x01, "Deku Tree MQ GS Basement Back Room", DEKU_TREE_MQ_GS_BASEMENT_BACK_ROOM, {Category::cDekuTree, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + + locationTable[DODONGOS_CAVERN_GS_VINES_ABOVE_STAIRS] = ItemLocation::GSToken(0x01, 0x01, "Dodongos Cavern GS Vines Above Stairs", DODONGOS_CAVERN_GS_VINES_ABOVE_STAIRS, {Category::cDodongosCavern, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_GS_SCARECROW] = ItemLocation::GSToken(0x01, 0x02, "Dodongos Cavern GS Scarecrow", DODONGOS_CAVERN_GS_SCARECROW, {Category::cDodongosCavern, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_GS_ALCOVE_ABOVE_STAIRS] = ItemLocation::GSToken(0x01, 0x04, "Dodongos Cavern GS Alcove Above Stairs", DODONGOS_CAVERN_GS_ALCOVE_ABOVE_STAIRS, {Category::cDodongosCavern, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_GS_BACK_ROOM] = ItemLocation::GSToken(0x01, 0x08, "Dodongos Cavern GS Back Room", DODONGOS_CAVERN_GS_BACK_ROOM, {Category::cDodongosCavern, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_GS_SIDE_ROOM_NEAR_LOWER_LIZALFOS] = ItemLocation::GSToken(0x01, 0x10, "Dodongos Cavern GS Side Room Near Lower Lizalfos", DODONGOS_CAVERN_GS_SIDE_ROOM_NEAR_LOWER_LIZALFOS, {Category::cDodongosCavern, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + + locationTable[DODONGOS_CAVERN_MQ_GS_SCRUB_ROOM] = ItemLocation::GSToken(0x01, 0x02, "Dodongos Cavern MQ GS Scrub Room", DODONGOS_CAVERN_MQ_GS_SCRUB_ROOM, {Category::cDodongosCavern, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_MQ_GS_SONG_OF_TIME_BLOCK_ROOM] = ItemLocation::GSToken(0x01, 0x08, "Dodongos Cavern MQ GS Song of Time Block Room", DODONGOS_CAVERN_MQ_GS_SONG_OF_TIME_BLOCK_ROOM, {Category::cDodongosCavern, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_MQ_GS_LIZALFOS_ROOM] = ItemLocation::GSToken(0x01, 0x04, "Dodongos Cavern MQ GS Lizalfos Room", DODONGOS_CAVERN_MQ_GS_LIZALFOS_ROOM, {Category::cDodongosCavern, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_MQ_GS_LARVAE_ROOM] = ItemLocation::GSToken(0x01, 0x10, "Dodongos Cavern MQ GS Larvae Room", DODONGOS_CAVERN_MQ_GS_LARVAE_ROOM, {Category::cDodongosCavern, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[DODONGOS_CAVERN_MQ_GS_BACK_AREA] = ItemLocation::GSToken(0x01, 0x01, "Dodongos Cavern MQ GS Back Room", DODONGOS_CAVERN_MQ_GS_BACK_AREA, {Category::cDodongosCavern, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + + locationTable[JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_LOWER] = ItemLocation::GSToken(0x02, 0x01, "Jabu Jabus Belly GS Lobby Basement Lower", JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_LOWER, {Category::cJabuJabusBelly, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_UPPER] = ItemLocation::GSToken(0x02, 0x02, "Jabu Jabus Belly GS Lobby Basement Upper", JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_UPPER, {Category::cJabuJabusBelly, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_GS_NEAR_BOSS] = ItemLocation::GSToken(0x02, 0x04, "Jabu Jabus Belly GS Near Boss", JABU_JABUS_BELLY_GS_NEAR_BOSS, {Category::cJabuJabusBelly, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM] = ItemLocation::GSToken(0x02, 0x08, "Jabu Jabus Belly GS Water Switch Room", JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM, {Category::cJabuJabusBelly, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + + locationTable[JABU_JABUS_BELLY_MQ_GS_TAILPASARAN_ROOM] = ItemLocation::GSToken(0x02, 0x04, "Jabu Jabus Belly MQ GS Tail Parasan Room", JABU_JABUS_BELLY_MQ_GS_TAILPASARAN_ROOM, {Category::cJabuJabusBelly, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_MQ_GS_INVISIBLE_ENEMIES_ROOM] = ItemLocation::GSToken(0x02, 0x08, "Jabu Jabus Belly MQ GS Invisible Enemies Room", JABU_JABUS_BELLY_MQ_GS_INVISIBLE_ENEMIES_ROOM, {Category::cJabuJabusBelly, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_MQ_GS_BOOMERANG_CHEST_ROOM] = ItemLocation::GSToken(0x02, 0x01, "Jabu Jabus Belly MQ GS Boomerang Chest Room", JABU_JABUS_BELLY_MQ_GS_BOOMERANG_CHEST_ROOM, {Category::cJabuJabusBelly, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[JABU_JABUS_BELLY_MQ_GS_NEAR_BOSS] = ItemLocation::GSToken(0x02, 0x02, "Jabu Jabus Belly MQ GS Near Boss", JABU_JABUS_BELLY_MQ_GS_NEAR_BOSS, {Category::cJabuJabusBelly, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + + locationTable[FOREST_TEMPLE_GS_RAISED_ISLAND_COURTYARD] = ItemLocation::GSToken(0x03, 0x01, "Forest Temple GS Raised Island Courtyard", FOREST_TEMPLE_GS_RAISED_ISLAND_COURTYARD, {Category::cForestTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_GS_FIRST_ROOM] = ItemLocation::GSToken(0x03, 0x02, "Forest Temple GS First Room", FOREST_TEMPLE_GS_FIRST_ROOM, {Category::cForestTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_GS_LEVEL_ISLAND_COURTYARD] = ItemLocation::GSToken(0x03, 0x04, "Forest Temple GS Level Island Courtyard", FOREST_TEMPLE_GS_LEVEL_ISLAND_COURTYARD, {Category::cForestTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_GS_LOBBY] = ItemLocation::GSToken(0x03, 0x08, "Forest Temple GS Lobby", FOREST_TEMPLE_GS_LOBBY, {Category::cForestTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_GS_BASEMENT] = ItemLocation::GSToken(0x03, 0x10, "Forest Temple GS Basement", FOREST_TEMPLE_GS_BASEMENT, {Category::cForestTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + + locationTable[FOREST_TEMPLE_MQ_GS_FIRST_HALLWAY] = ItemLocation::GSToken(0x03, 0x02, "Forest Temple MQ GS First Hallway", FOREST_TEMPLE_MQ_GS_FIRST_HALLWAY, {Category::cForestTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_MQ_GS_BLOCK_PUSH_ROOM] = ItemLocation::GSToken(0x03, 0x10, "Forest Temple MQ GS Block Push Room", FOREST_TEMPLE_MQ_GS_BLOCK_PUSH_ROOM, {Category::cForestTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_MQ_GS_RAISED_ISLAND_COURTYARD] = ItemLocation::GSToken(0x03, 0x01, "Forest Temple MQ GS Raised Island Courtyard", FOREST_TEMPLE_MQ_GS_RAISED_ISLAND_COURTYARD, {Category::cForestTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_MQ_GS_LEVEL_ISLAND_COURTYARD] = ItemLocation::GSToken(0x03, 0x04, "Forest Temple MQ GS Level Island Courtyard", FOREST_TEMPLE_MQ_GS_LEVEL_ISLAND_COURTYARD, {Category::cForestTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FOREST_TEMPLE_MQ_GS_WELL] = ItemLocation::GSToken(0x03, 0x08, "Forest Temple MQ GS Well", FOREST_TEMPLE_MQ_GS_WELL, {Category::cForestTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + + locationTable[FIRE_TEMPLE_GS_SONG_OF_TIME_ROOM] = ItemLocation::GSToken(0x04, 0x01, "Fire Temple GS Song of Time Room", FIRE_TEMPLE_GS_SONG_OF_TIME_ROOM, {Category::cFireTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_GS_BOSS_KEY_LOOP] = ItemLocation::GSToken(0x04, 0x02, "Fire Temple GS Boss Key Loop", FIRE_TEMPLE_GS_BOSS_KEY_LOOP, {Category::cFireTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_GS_BOULDER_MAZE] = ItemLocation::GSToken(0x04, 0x04, "Fire Temple GS Boulder Maze", FIRE_TEMPLE_GS_BOULDER_MAZE, {Category::cFireTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_GS_SCARECROW_TOP] = ItemLocation::GSToken(0x04, 0x08, "Fire Temple GS Scarecrow Top", FIRE_TEMPLE_GS_SCARECROW_TOP, {Category::cFireTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_GS_SCARECROW_CLIMB] = ItemLocation::GSToken(0x04, 0x10, "Fire Temple GS Scarecrow Climb", FIRE_TEMPLE_GS_SCARECROW_CLIMB, {Category::cFireTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + + locationTable[FIRE_TEMPLE_MQ_GS_ABOVE_FIRE_WALL_MAZE] = ItemLocation::GSToken(0x04, 0x02, "Fire Temple MQ GS Above Fire Wall Maze", FIRE_TEMPLE_MQ_GS_ABOVE_FIRE_WALL_MAZE, {Category::cFireTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_CENTER] = ItemLocation::GSToken(0x04, 0x08, "Fire Temple MQ GS Fire Wall Maze Center", FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_CENTER, {Category::cFireTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MQ_GS_BIG_LAVA_ROOM_OPEN_DOOR] = ItemLocation::GSToken(0x04, 0x01, "Fire Temple MQ GS Big Lava Room Open Door", FIRE_TEMPLE_MQ_GS_BIG_LAVA_ROOM_OPEN_DOOR, {Category::cFireTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_SIDE_ROOM] = ItemLocation::GSToken(0x04, 0x10, "Fire Temple MQ GS Fire Wall Maze Side Room", FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_SIDE_ROOM, {Category::cFireTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[FIRE_TEMPLE_MQ_GS_SKULL_ON_FIRE] = ItemLocation::GSToken(0x04, 0x04, "Fire Temple MQ GS Skull on Fire", FIRE_TEMPLE_MQ_GS_SKULL_ON_FIRE, {Category::cFireTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + + locationTable[WATER_TEMPLE_GS_BEHIND_GATE] = ItemLocation::GSToken(0x05, 0x01, "Water Temple GS Behind Gate", WATER_TEMPLE_GS_BEHIND_GATE, {Category::cWaterTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_GS_FALLING_PLATFORM_ROOM] = ItemLocation::GSToken(0x05, 0x02, "Water Temple GS Falling Platform Room", WATER_TEMPLE_GS_FALLING_PLATFORM_ROOM, {Category::cWaterTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_GS_CENTRAL_PILLAR] = ItemLocation::GSToken(0x05, 0x04, "Water Temple GS Central Pillar", WATER_TEMPLE_GS_CENTRAL_PILLAR, {Category::cWaterTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_GS_NEAR_BOSS_KEY_CHEST] = ItemLocation::GSToken(0x05, 0x08, "Water Temple GS Near Boss Key Chest", WATER_TEMPLE_GS_NEAR_BOSS_KEY_CHEST, {Category::cWaterTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_GS_RIVER] = ItemLocation::GSToken(0x05, 0x10, "Water Temple GS River", WATER_TEMPLE_GS_RIVER, {Category::cWaterTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + + locationTable[WATER_TEMPLE_MQ_GS_BEFORE_UPPER_WATER_SWITCH] = ItemLocation::GSToken(0x05, 0x04, "Water Temple MQ GS Before Upper Water Switch", WATER_TEMPLE_MQ_GS_BEFORE_UPPER_WATER_SWITCH, {Category::cWaterTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_MQ_GS_FREESTANDING_KEY_AREA] = ItemLocation::GSToken(0x05, 0x08, "Water Temple MQ GS Freestanding Key Area", WATER_TEMPLE_MQ_GS_FREESTANDING_KEY_AREA, {Category::cWaterTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_MQ_GS_LIZALFOS_HALLWAY] = ItemLocation::GSToken(0x05, 0x01, "Water Temple MQ GS Lizalfos Hallway", WATER_TEMPLE_MQ_GS_LIZALFOS_HALLWAY, {Category::cWaterTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_MQ_GS_RIVER] = ItemLocation::GSToken(0x05, 0x02, "Water Temple MQ GS River", WATER_TEMPLE_MQ_GS_RIVER, {Category::cWaterTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[WATER_TEMPLE_MQ_GS_TRIPLE_WALL_TORCH] = ItemLocation::GSToken(0x05, 0x10, "Water Temple MQ GS Triple Wall Torch", WATER_TEMPLE_MQ_GS_TRIPLE_WALL_TORCH, {Category::cWaterTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + + locationTable[SPIRIT_TEMPLE_GS_HALL_AFTER_SUN_BLOCK_ROOM] = ItemLocation::GSToken(0x06, 0x01, "Spirit Temple GS Hall After Sun Block Room", SPIRIT_TEMPLE_GS_HALL_AFTER_SUN_BLOCK_ROOM, {Category::cSpiritTemple, Category::cSkulltula}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_GS_BOULDER_ROOM] = ItemLocation::GSToken(0x06, 0x02, "Spirit Temple GS Boulder Room", SPIRIT_TEMPLE_GS_BOULDER_ROOM, {Category::cSpiritTemple, Category::cSkulltula}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_GS_LOBBY] = ItemLocation::GSToken(0x06, 0x04, "Spirit Temple GS Lobby", SPIRIT_TEMPLE_GS_LOBBY, {Category::cSpiritTemple, Category::cSkulltula}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_GS_SUN_ON_FLOOR_ROOM] = ItemLocation::GSToken(0x06, 0x08, "Spirit Temple GS Sun on Floor Room", SPIRIT_TEMPLE_GS_SUN_ON_FLOOR_ROOM, {Category::cSpiritTemple, Category::cSkulltula}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_GS_METAL_FENCE] = ItemLocation::GSToken(0x06, 0x10, "Spirit Temple GS Metal Fence", SPIRIT_TEMPLE_GS_METAL_FENCE, {Category::cSpiritTemple, Category::cSkulltula}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + + locationTable[SPIRIT_TEMPLE_MQ_GS_SYMPHONY_ROOM] = ItemLocation::GSToken(0x06, 0x08, "Spirit Temple MQ GS Symphony Room", SPIRIT_TEMPLE_MQ_GS_SYMPHONY_ROOM, {Category::cSpiritTemple, Category::cSkulltula}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_GS_LEEVER_ROOM] = ItemLocation::GSToken(0x06, 0x02, "Spirit Temple MQ GS Leever Room", SPIRIT_TEMPLE_MQ_GS_LEEVER_ROOM, {Category::cSpiritTemple, Category::cSkulltula}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_WEST] = ItemLocation::GSToken(0x06, 0x04, "Spirit Temple MQ GS Nine Thrones Room West", SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_WEST, {Category::cSpiritTemple, Category::cSkulltula}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_NORTH] = ItemLocation::GSToken(0x06, 0x10, "Spirit Temple MQ GS Nine Thrones Room North", SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_NORTH, {Category::cSpiritTemple, Category::cSkulltula}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SPIRIT_TEMPLE_MQ_GS_SUN_BLOCK_ROOM] = ItemLocation::GSToken(0x06, 0x01, "Spirit Temple MQ GS Sun Block Room", SPIRIT_TEMPLE_MQ_GS_SUN_BLOCK_ROOM, {Category::cSpiritTemple, Category::cSkulltula}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + + locationTable[SHADOW_TEMPLE_GS_SINGLE_GIANT_POT] = ItemLocation::GSToken(0x07, 0x01, "Shadow Temple GS Single Giant Pot", SHADOW_TEMPLE_GS_SINGLE_GIANT_POT, {Category::cShadowTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_GS_FALLING_SPIKES_ROOM] = ItemLocation::GSToken(0x07, 0x02, "Shadow Temple GS Falling Spikes Room", SHADOW_TEMPLE_GS_FALLING_SPIKES_ROOM, {Category::cShadowTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_GS_TRIPLE_GIANT_POT] = ItemLocation::GSToken(0x07, 0x04, "Shadow Temple GS Triple Giant Pot", SHADOW_TEMPLE_GS_TRIPLE_GIANT_POT, {Category::cShadowTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_GS_LIKE_LIKE_ROOM] = ItemLocation::GSToken(0x07, 0x08, "Shadow Temple GS Like Like Room", SHADOW_TEMPLE_GS_LIKE_LIKE_ROOM, {Category::cShadowTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_GS_NEAR_SHIP] = ItemLocation::GSToken(0x07, 0x10, "Shadow Temple GS Near Ship", SHADOW_TEMPLE_GS_NEAR_SHIP, {Category::cShadowTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + + locationTable[SHADOW_TEMPLE_MQ_GS_FALLING_SPIKES_ROOM] = ItemLocation::GSToken(0x07, 0x02, "Shadow Temple MQ GS Falling Spikes Room", SHADOW_TEMPLE_MQ_GS_FALLING_SPIKES_ROOM, {Category::cShadowTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_GS_WIND_HINT_ROOM] = ItemLocation::GSToken(0x07, 0x01, "Shadow Temple MQ GS Wind Hint Room", SHADOW_TEMPLE_MQ_GS_WIND_HINT_ROOM, {Category::cShadowTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_GS_AFTER_WIND] = ItemLocation::GSToken(0x07, 0x08, "Shadow Temple MQ GS After Wind", SHADOW_TEMPLE_MQ_GS_AFTER_WIND, {Category::cShadowTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_GS_AFTER_SHIP] = ItemLocation::GSToken(0x07, 0x10, "Shadow Temple MQ GS After Ship", SHADOW_TEMPLE_MQ_GS_AFTER_SHIP, {Category::cShadowTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[SHADOW_TEMPLE_MQ_GS_NEAR_BOSS] = ItemLocation::GSToken(0x07, 0x04, "Shadow Temple MQ GS Near Boss", SHADOW_TEMPLE_MQ_GS_NEAR_BOSS, {Category::cShadowTemple, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + + locationTable[BOTTOM_OF_THE_WELL_GS_LIKE_LIKE_CAGE] = ItemLocation::GSToken(0x08, 0x01, "Bottom of the Well GS Like Like Cage", BOTTOM_OF_THE_WELL_GS_LIKE_LIKE_CAGE, {Category::cBottomOfTheWell, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_GS_EAST_INNER_ROOM] = ItemLocation::GSToken(0x08, 0x02, "Bottom of the Well GS East Inner Room", BOTTOM_OF_THE_WELL_GS_EAST_INNER_ROOM, {Category::cBottomOfTheWell, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_GS_WEST_INNER_ROOM] = ItemLocation::GSToken(0x08, 0x04, "Bottom of the Well GS West Inner Room", BOTTOM_OF_THE_WELL_GS_WEST_INNER_ROOM, {Category::cBottomOfTheWell, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + + locationTable[BOTTOM_OF_THE_WELL_MQ_GS_BASEMENT] = ItemLocation::GSToken(0x08, 0x01, "Bottom of the Well MQ GS Basement", BOTTOM_OF_THE_WELL_MQ_GS_BASEMENT, {Category::cBottomOfTheWell, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_MQ_GS_COFFIN_ROOM] = ItemLocation::GSToken(0x08, 0x04, "Bottom of the Well MQ GS Coffin Room", BOTTOM_OF_THE_WELL_MQ_GS_COFFIN_ROOM, {Category::cBottomOfTheWell, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + locationTable[BOTTOM_OF_THE_WELL_MQ_GS_WEST_INNER_ROOM] = ItemLocation::GSToken(0x08, 0x02, "Bottom of the Well MQ GS West Inner Room", BOTTOM_OF_THE_WELL_MQ_GS_WEST_INNER_ROOM, {Category::cBottomOfTheWell, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_BOTTOM_OF_THE_WELL); + + locationTable[ICE_CAVERN_GS_PUSH_BLOCK_ROOM] = ItemLocation::GSToken(0x09, 0x01, "Ice Cavern GS Push Block Room", ICE_CAVERN_GS_PUSH_BLOCK_ROOM, {Category::cIceCavern, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_ICE_CAVERN); + locationTable[ICE_CAVERN_GS_SPINNING_SCYTHE_ROOM] = ItemLocation::GSToken(0x09, 0x02, "Ice Cavern GS Spinning Scythe Room", ICE_CAVERN_GS_SPINNING_SCYTHE_ROOM, {Category::cIceCavern, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_ICE_CAVERN); + locationTable[ICE_CAVERN_GS_HEART_PIECE_ROOM] = ItemLocation::GSToken(0x09, 0x04, "Ice Cavern GS Heart Piece Room", ICE_CAVERN_GS_HEART_PIECE_ROOM, {Category::cIceCavern, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_ICE_CAVERN); + + locationTable[ICE_CAVERN_MQ_GS_SCARECROW] = ItemLocation::GSToken(0x09, 0x01, "Ice Cavern MQ GS Scarecrow", ICE_CAVERN_MQ_GS_SCARECROW, {Category::cIceCavern, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_ICE_CAVERN); + locationTable[ICE_CAVERN_MQ_GS_ICE_BLOCK] = ItemLocation::GSToken(0x09, 0x04, "Ice Cavern MQ GS Ice Block", ICE_CAVERN_MQ_GS_ICE_BLOCK, {Category::cIceCavern, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_ICE_CAVERN); + locationTable[ICE_CAVERN_MQ_GS_RED_ICE] = ItemLocation::GSToken(0x09, 0x02, "Ice Cavern MQ GS Red Ice", ICE_CAVERN_MQ_GS_RED_ICE, {Category::cIceCavern, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_ICE_CAVERN); + + //Overworld + locationTable[KF_GS_BEAN_PATCH] = ItemLocation::GSToken(0x0C, 0x01, "KF GS Bean Patch", KF_GS_BEAN_PATCH, {Category::cKokiriForest, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + locationTable[KF_GS_KNOW_IT_ALL_HOUSE] = ItemLocation::GSToken(0x0C, 0x02, "KF GS Know It All House", KF_GS_KNOW_IT_ALL_HOUSE, {Category::cKokiriForest, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + locationTable[KF_GS_HOUSE_OF_TWINS] = ItemLocation::GSToken(0x0C, 0x04, "KF GS House of Twins", KF_GS_HOUSE_OF_TWINS, {Category::cKokiriForest, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + + locationTable[LW_GS_BEAN_PATCH_NEAR_BRIDGE] = ItemLocation::GSToken(0x0D, 0x01, "LW GS Bean Patch Near Bridge", LW_GS_BEAN_PATCH_NEAR_BRIDGE, {Category::cLostWoods, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[LW_GS_BEAN_PATCH_NEAR_THEATER] = ItemLocation::GSToken(0x0D, 0x02, "LW GS Bean Patch Near Theater", LW_GS_BEAN_PATCH_NEAR_THEATER, {Category::cLostWoods, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[LW_GS_ABOVE_THEATER] = ItemLocation::GSToken(0x0D, 0x04, "LW GS Above Theater", LW_GS_ABOVE_THEATER, {Category::cLostWoods, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[SFM_GS] = ItemLocation::GSToken(0x0D, 0x08, "SFM GS", SFM_GS, {Category::cSacredForestMeadow, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + + locationTable[HF_GS_COW_GROTTO] = ItemLocation::GSToken(0x0A, 0x01, "HF GS Cow Grotto", HF_GS_COW_GROTTO, {Category::cHyruleField, Category::cSkulltula, Category::cGrotto}, SpoilerCollectionCheckGroup::GROUP_HYRULE_FIELD); + locationTable[HF_GS_NEAR_KAK_GROTTO] = ItemLocation::GSToken(0x0A, 0x02, "HF GS Near Kak Grotto", HF_GS_NEAR_KAK_GROTTO, {Category::cHyruleField, Category::cSkulltula, Category::cGrotto}, SpoilerCollectionCheckGroup::GROUP_HYRULE_FIELD); + + locationTable[LH_GS_BEAN_PATCH] = ItemLocation::GSToken(0x12, 0x01, "LH GS Bean Patch", LH_GS_BEAN_PATCH, {Category::cLakeHylia, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); + locationTable[LH_GS_SMALL_ISLAND] = ItemLocation::GSToken(0x12, 0x02, "LH GS Small Island", LH_GS_SMALL_ISLAND, {Category::cLakeHylia, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); + locationTable[LH_GS_LAB_WALL] = ItemLocation::GSToken(0x12, 0x04, "LH GS Lab Wall", LH_GS_LAB_WALL, {Category::cLakeHylia, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); + locationTable[LH_GS_LAB_CRATE] = ItemLocation::GSToken(0x12, 0x08, "LH GS Lab Crate", LH_GS_LAB_CRATE, {Category::cLakeHylia, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); + locationTable[LH_GS_TREE] = ItemLocation::GSToken(0x12, 0x10, "LH GS Tree", LH_GS_TREE, {Category::cLakeHylia, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_LAKE_HYLIA); + + locationTable[GV_GS_BEAN_PATCH] = ItemLocation::GSToken(0x13, 0x01, "GV GS Bean Patch", GV_GS_BEAN_PATCH, {Category::cGerudoValley, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GV_GS_SMALL_BRIDGE] = ItemLocation::GSToken(0x13, 0x02, "GV GS Small Bridge", GV_GS_SMALL_BRIDGE, {Category::cGerudoValley, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GV_GS_PILLAR] = ItemLocation::GSToken(0x13, 0x04, "GV GS Pillar", GV_GS_PILLAR, {Category::cGerudoValley, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GV_GS_BEHIND_TENT] = ItemLocation::GSToken(0x13, 0x08, "GV GS Behind Tent", GV_GS_BEHIND_TENT, {Category::cGerudoValley, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + + locationTable[GF_GS_ARCHERY_RANGE] = ItemLocation::GSToken(0x14, 0x01, "GF GS Archery Range", GF_GS_ARCHERY_RANGE, {Category::cGerudoFortress, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[GF_GS_TOP_FLOOR] = ItemLocation::GSToken(0x14, 0x02, "GF GS Top Floor", GF_GS_TOP_FLOOR, {Category::cGerudoFortress, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + + locationTable[WASTELAND_GS] = ItemLocation::GSToken(0x15, 0x02, "Wasteland GS", WASTELAND_GS, {Category::cHauntedWasteland, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[COLOSSUS_GS_BEAN_PATCH] = ItemLocation::GSToken(0x15, 0x01, "Colossus GS Bean Patch", COLOSSUS_GS_BEAN_PATCH, {Category::cDesertColossus, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[COLOSSUS_GS_HILL] = ItemLocation::GSToken(0x15, 0x04, "Colossus GS Hill", COLOSSUS_GS_HILL, {Category::cDesertColossus, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[COLOSSUS_GS_TREE] = ItemLocation::GSToken(0x15, 0x08, "Colossus GS Tree", COLOSSUS_GS_TREE, {Category::cDesertColossus, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + + locationTable[OGC_GS] = ItemLocation::GSToken(0x0E, 0x01, "OGC GS", OGC_GS, {Category::cOutsideGanonsCastle, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + locationTable[HC_GS_STORMS_GROTTO] = ItemLocation::GSToken(0x0E, 0x02, "HC GS Storms Grotto", HC_GS_STORMS_GROTTO, {Category::cHyruleCastle, Category::cSkulltula, Category::cGrotto}, SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[HC_GS_TREE] = ItemLocation::GSToken(0x0E, 0x04, "HC GS Tree", HC_GS_TREE, {Category::cHyruleCastle, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_GS_GUARD_HOUSE] = ItemLocation::GSToken(0x0E, 0x08, "Market GS Guard House", MARKET_GS_GUARD_HOUSE, {Category::cInnerMarket, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + + locationTable[KAK_GS_HOUSE_UNDER_CONSTRUCTION] = ItemLocation::GSToken(0x10, 0x08, "Kak GS House Under Construction", KAK_GS_HOUSE_UNDER_CONSTRUCTION, {Category::cKakarikoVillage, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_GS_SKULLTULA_HOUSE] = ItemLocation::GSToken(0x10, 0x10, "Kak GS Skulltula House", KAK_GS_SKULLTULA_HOUSE, {Category::cKakarikoVillage, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_GS_GUARDS_HOUSE] = ItemLocation::GSToken(0x10, 0x02, "Kak GS Guards House", KAK_GS_GUARDS_HOUSE, {Category::cKakarikoVillage, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_GS_TREE] = ItemLocation::GSToken(0x10, 0x20, "Kak GS Tree", KAK_GS_TREE, {Category::cKakarikoVillage, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_GS_WATCHTOWER] = ItemLocation::GSToken(0x10, 0x04, "Kak GS Watchtower", KAK_GS_WATCHTOWER, {Category::cKakarikoVillage, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_GS_ABOVE_IMPAS_HOUSE] = ItemLocation::GSToken(0x10, 0x40, "Kak GS Above Impas House", KAK_GS_ABOVE_IMPAS_HOUSE, {Category::cKakarikoVillage, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + + locationTable[GRAVEYARD_GS_WALL] = ItemLocation::GSToken(0x10, 0x80, "Graveyard GS Wall", GRAVEYARD_GS_WALL, {Category::cGraveyard, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[GRAVEYARD_GS_BEAN_PATCH] = ItemLocation::GSToken(0x10, 0x01, "Graveyard GS Bean Patch", GRAVEYARD_GS_BEAN_PATCH, {Category::cGraveyard, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + + locationTable[DMC_GS_BEAN_PATCH] = ItemLocation::GSToken(0x0F, 0x01, "DMC GS Bean Patch", DMC_GS_BEAN_PATCH, {Category::cDeathMountainCrater, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[DMC_GS_CRATE] = ItemLocation::GSToken(0x0F, 0x80, "DMC GS Crate", DMC_GS_CRATE, {Category::cDeathMountainCrater, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + + locationTable[DMT_GS_BEAN_PATCH] = ItemLocation::GSToken(0x0F, 0x02, "DMT GS Bean Patch", DMT_GS_BEAN_PATCH, {Category::cDeathMountainTrail, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[DMT_GS_NEAR_KAK] = ItemLocation::GSToken(0x0F, 0x04, "DMT GS Near Kak", DMT_GS_NEAR_KAK, {Category::cDeathMountainTrail, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[DMT_GS_ABOVE_DODONGOS_CAVERN] = ItemLocation::GSToken(0x0F, 0x08, "DMT GS Above Dodongos Cavern", DMT_GS_ABOVE_DODONGOS_CAVERN, {Category::cDeathMountainTrail, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[DMT_GS_FALLING_ROCKS_PATH] = ItemLocation::GSToken(0x0F, 0x10, "DMT GS Falling Rocks Path", DMT_GS_FALLING_ROCKS_PATH, {Category::cDeathMountainTrail, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + + locationTable[GC_GS_CENTER_PLATFORM] = ItemLocation::GSToken(0x0F, 0x20, "GC GS Center Platform", GC_GS_CENTER_PLATFORM, {Category::cGoronCity, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_GS_BOULDER_MAZE] = ItemLocation::GSToken(0x0F, 0x40, "GC GS Boulder Maze", GC_GS_BOULDER_MAZE, {Category::cGoronCity, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + + locationTable[ZR_GS_LADDER] = ItemLocation::GSToken(0x11, 0x01, "ZR GS Ladder", ZR_GS_LADDER, {Category::cZorasRiver, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); + locationTable[ZR_GS_TREE] = ItemLocation::GSToken(0x11, 0x02, "ZR GS Tree", ZR_GS_TREE, {Category::cZorasRiver, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); + locationTable[ZR_GS_ABOVE_BRIDGE] = ItemLocation::GSToken(0x11, 0x08, "ZR GS Above Bridge", ZR_GS_ABOVE_BRIDGE, {Category::cZorasRiver, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); + locationTable[ZR_GS_NEAR_RAISED_GROTTOS] = ItemLocation::GSToken(0x11, 0x10, "ZR GS Near Raised Grottos", ZR_GS_NEAR_RAISED_GROTTOS, {Category::cZorasRiver, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_ZORAS_RIVER); + + locationTable[ZD_GS_FROZEN_WATERFALL] = ItemLocation::GSToken(0x11, 0x40, "ZD GS Frozen Waterfall", ZD_GS_FROZEN_WATERFALL, {Category::cZorasDomain, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + locationTable[ZF_GS_ABOVE_THE_LOG] = ItemLocation::GSToken(0x11, 0x04, "ZF GS Above The Log", ZF_GS_ABOVE_THE_LOG, {Category::cZorasFountain, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + locationTable[ZF_GS_HIDDEN_CAVE] = ItemLocation::GSToken(0x11, 0x20, "ZF GS Hidden Cave", ZF_GS_HIDDEN_CAVE, {Category::cZorasFountain, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + locationTable[ZF_GS_TREE] = ItemLocation::GSToken(0x11, 0x80, "ZF GS Tree", ZF_GS_TREE, {Category::cZorasFountain, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + + locationTable[LLR_GS_BACK_WALL] = ItemLocation::GSToken(0x0B, 0x01, "LLR GS Back Wall", LLR_GS_BACK_WALL, {Category::cLonLonRanch, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); + locationTable[LLR_GS_RAIN_SHED] = ItemLocation::GSToken(0x0B, 0x02, "LLR GS Rain Shed", LLR_GS_RAIN_SHED, {Category::cLonLonRanch, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); + locationTable[LLR_GS_HOUSE_WINDOW] = ItemLocation::GSToken(0x0B, 0x04, "LLR GS House Window", LLR_GS_HOUSE_WINDOW, {Category::cLonLonRanch, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); + locationTable[LLR_GS_TREE] = ItemLocation::GSToken(0x0B, 0x08, "LLR GS Tree", LLR_GS_TREE, {Category::cLonLonRanch, Category::cSkulltula,}, SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); + + /*------------------------------- + --- BOSSES --- + -------------------------------*/ + + locationTable[LINKS_POCKET] = ItemLocation::Reward (0xFF, 0xFF, "Link's Pocket", LINKS_POCKET, LIGHT_MEDALLION, {}, SpoilerCollectionCheck::AlwaysCollected(), SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + locationTable[QUEEN_GOHMA] = ItemLocation::Reward (0xFF, DUNGEON_DEKU_TREE, "Queen Gohma", QUEEN_GOHMA, KOKIRI_EMERALD, {}, SpoilerCollectionCheck::EventChkInf(0x09), SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[KING_DODONGO] = ItemLocation::Reward (0xFF, DUNGEON_DODONGOS_CAVERN, "King Dodongo", KING_DODONGO, GORON_RUBY, {}, SpoilerCollectionCheck::EventChkInf(0x25), SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[BARINADE] = ItemLocation::Reward (0xFF, DUNGEON_JABUJABUS_BELLY, "Barinade", BARINADE, ZORA_SAPPHIRE, {}, SpoilerCollectionCheck::EventChkInf(0x37), SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[PHANTOM_GANON] = ItemLocation::Reward (0xFF, DUNGEON_FOREST_TEMPLE, "Phantom Ganon", PHANTOM_GANON, FOREST_MEDALLION, {}, SpoilerCollectionCheck::EventChkInf(0x48), SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[VOLVAGIA] = ItemLocation::Reward (0xFF, DUNGEON_FIRE_TEMPLE, "Volvagia", VOLVAGIA, FIRE_MEDALLION, {}, SpoilerCollectionCheck::EventChkInf(0x49), SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[MORPHA] = ItemLocation::Reward (0xFF, DUNGEON_WATER_TEMPLE, "Morpha", MORPHA, WATER_MEDALLION, {}, SpoilerCollectionCheck::EventChkInf(0x4A), SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[TWINROVA] = ItemLocation::Reward (0xFF, DUNGEON_SPIRIT_TEMPLE, "Twinrova", TWINROVA, SPIRIT_MEDALLION, {}, SpoilerCollectionCheck::EventChkInf(0x47), SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[BONGO_BONGO] = ItemLocation::Reward (0xFF, DUNGEON_SHADOW_TEMPLE, "Bongo Bongo", BONGO_BONGO, SHADOW_MEDALLION, {}, SpoilerCollectionCheck::EventChkInf(0x46), SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + locationTable[GANON] = ItemLocation::Reward (0xFF, 0xF0, "Ganon", NONE, TRIFORCE, {}, SpoilerCollectionCheck::None(), SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + + /*------------------------------- + ---HEART CONTAINERS --- + -------------------------------*/ + + locationTable[DEKU_TREE_QUEEN_GOHMA_HEART] = ItemLocation::Base (0x11, 0x4F, "Deku Tree Queen Gohma Heart Container", DEKU_TREE_QUEEN_GOHMA_HEART, HEART_CONTAINER, {Category::cDekuTree, Category::cBossHeart, Category::cSongDungeonReward}, SpoilerCollectionCheck::Collectable(0x11, 0x1F), SpoilerCollectionCheckGroup::GROUP_DUNGEON_DEKU_TREE); + locationTable[DODONGOS_CAVERN_KING_DODONGO_HEART] = ItemLocation::Base (0x12, 0x4F, "Dodongos Cavern King Dodongo Heart Container", DODONGOS_CAVERN_KING_DODONGO_HEART, HEART_CONTAINER, {Category::cDodongosCavern, Category::cBossHeart, Category::cSongDungeonReward}, SpoilerCollectionCheck::Collectable(0x12, 0x1F), SpoilerCollectionCheckGroup::GROUP_DUNGEON_DODONGOS_CAVERN); + locationTable[JABU_JABUS_BELLY_BARINADE_HEART] = ItemLocation::Base (0x13, 0x4F, "Jabu Jabus Belly Barinade Heart Container", JABU_JABUS_BELLY_BARINADE_HEART, HEART_CONTAINER, {Category::cJabuJabusBelly, Category::cBossHeart, Category::cSongDungeonReward}, SpoilerCollectionCheck::Collectable(0x13, 0x1F), SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + locationTable[FOREST_TEMPLE_PHANTOM_GANON_HEART] = ItemLocation::Base (0x14, 0x4F, "Forest Temple Phantom Ganon Heart Container", FOREST_TEMPLE_PHANTOM_GANON_HEART, HEART_CONTAINER, {Category::cForestTemple, Category::cBossHeart, Category::cSongDungeonReward}, SpoilerCollectionCheck::Collectable(0x14, 0x1F), SpoilerCollectionCheckGroup::GROUP_DUNGEON_FOREST_TEMPLE); + locationTable[FIRE_TEMPLE_VOLVAGIA_HEART] = ItemLocation::Base (0x15, 0x4F, "Fire Temple Volvagia Heart Container", FIRE_TEMPLE_VOLVAGIA_HEART, HEART_CONTAINER, {Category::cFireTemple, Category::cBossHeart, Category::cSongDungeonReward}, SpoilerCollectionCheck::Collectable(0x15, 0x1F), SpoilerCollectionCheckGroup::GROUP_DUNGEON_FIRE_TEMPLE); + locationTable[WATER_TEMPLE_MORPHA_HEART] = ItemLocation::Base (0x16, 0x4F, "Water Temple Morpha Heart Container", WATER_TEMPLE_MORPHA_HEART, HEART_CONTAINER, {Category::cWaterTemple, Category::cBossHeart, Category::cSongDungeonReward}, SpoilerCollectionCheck::Collectable(0x16, 0x1F), SpoilerCollectionCheckGroup::GROUP_DUNGEON_WATER_TEMPLE); + locationTable[SPIRIT_TEMPLE_TWINROVA_HEART] = ItemLocation::Base (0x17, 0x4F, "Spirit Temple Twinrova Heart Container", SPIRIT_TEMPLE_TWINROVA_HEART, HEART_CONTAINER, {Category::cSpiritTemple, Category::cBossHeart, Category::cSongDungeonReward}, SpoilerCollectionCheck::Collectable(0x17, 0x1F), SpoilerCollectionCheckGroup::GROUP_DUNGEON_SPIRIT_TEMPLE); + locationTable[SHADOW_TEMPLE_BONGO_BONGO_HEART] = ItemLocation::Base (0x18, 0x4F, "Shadow Temple Bongo Bongo Heart Container", SHADOW_TEMPLE_BONGO_BONGO_HEART, HEART_CONTAINER, {Category::cShadowTemple, Category::cBossHeart, Category::cSongDungeonReward}, SpoilerCollectionCheck::Collectable(0x18, 0x1F), SpoilerCollectionCheckGroup::GROUP_DUNGEON_SHADOW_TEMPLE); + + /*------------------------------- + --- CUTSCENES --- + -------------------------------*/ + + locationTable[TOT_LIGHT_ARROWS_CUTSCENE] = ItemLocation::Delayed(0xFF, 0x01, "ToT Light Arrow Cutscene", TOT_LIGHT_ARROWS_CUTSCENE, LIGHT_ARROWS, {Category::cTempleOfTime, Category::cMarket}, SpoilerCollectionCheck::EventChkInf(0xC4), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[LW_GIFT_FROM_SARIA] = ItemLocation::Delayed(0xFF, 0x02, "LW Gift From Saria", LW_GIFT_FROM_SARIA, PROGRESSIVE_OCARINA, {Category::cLostWoods, Category::cForest}, SpoilerCollectionCheck::EventChkInf(0xC1), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[ZF_GREAT_FAIRY_REWARD] = ItemLocation::Delayed(0xFF, 0x10, "ZF Great Fairy Reward", ZF_GREAT_FAIRY_REWARD, FARORES_WIND, {Category::cZorasFountain, Category::cFairies}, SpoilerCollectionCheck::ItemGetInf(16), SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + locationTable[HC_GREAT_FAIRY_REWARD] = ItemLocation::Delayed(0xFF, 0x11, "HC Great Fairy Reward", HC_GREAT_FAIRY_REWARD, DINS_FIRE, {Category::cHyruleCastle, Category::cMarket, Category::cFairies}, SpoilerCollectionCheck::ItemGetInf(17), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[COLOSSUS_GREAT_FAIRY_REWARD] = ItemLocation::Delayed(0xFF, 0x12, "Colossus Great Fairy Reward", COLOSSUS_GREAT_FAIRY_REWARD, NAYRUS_LOVE, {Category::cDesertColossus, Category::cFairies}, SpoilerCollectionCheck::ItemGetInf(18), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[DMT_GREAT_FAIRY_REWARD] = ItemLocation::Delayed(0xFF, 0x13, "DMT Great Fairy Reward", DMT_GREAT_FAIRY_REWARD, PROGRESSIVE_MAGIC_METER, {Category::cDeathMountainTrail, Category::cDeathMountain, Category::cFairies}, SpoilerCollectionCheck::Chest(0x3B, 0x00), SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[DMC_GREAT_FAIRY_REWARD] = ItemLocation::Delayed(0xFF, 0x14, "DMC Great Fairy Reward", DMC_GREAT_FAIRY_REWARD, PROGRESSIVE_MAGIC_METER, {Category::cDeathMountainCrater, Category::cDeathMountain, Category::cFairies}, SpoilerCollectionCheck::Chest(0x3B, 0x01), SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[OGC_GREAT_FAIRY_REWARD] = ItemLocation::Delayed(0xFF, 0x15, "OGC Great Fairy Reward", OGC_GREAT_FAIRY_REWARD, DOUBLE_DEFENSE, {Category::cOutsideGanonsCastle, Category::cFairies}, SpoilerCollectionCheck::Chest(0x3B, 0x02), SpoilerCollectionCheckGroup::GROUP_DUNGEON_GANONS_CASTLE); + + locationTable[SHEIK_IN_FOREST] = ItemLocation::Delayed(0xFF, 0x20, "Sheik in Forest", SHEIK_IN_FOREST, MINUET_OF_FOREST, {Category::cSacredForestMeadow, Category::cForest, Category::cSong,}, SpoilerCollectionCheck::EventChkInf(0x50), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[SHEIK_IN_CRATER] = ItemLocation::Delayed(0xFF, 0x21, "Sheik in Crater", SHEIK_IN_CRATER, BOLERO_OF_FIRE, {Category::cDeathMountainCrater, Category::cDeathMountain, Category::cSong,}, SpoilerCollectionCheck::EventChkInf(0x51), SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[SHEIK_IN_ICE_CAVERN] = ItemLocation::Delayed(0xFF, 0x22, "Sheik in Ice Cavern", SHEIK_IN_ICE_CAVERN, SERENADE_OF_WATER, {Category::cIceCavern, Category::cSong, Category::cSongDungeonReward}, SpoilerCollectionCheck::EventChkInf(0x52), SpoilerCollectionCheckGroup::GROUP_DUNGEON_ICE_CAVERN); + locationTable[SHEIK_AT_COLOSSUS] = ItemLocation::Delayed(0xFF, 0x23, "Sheik at Colossus", SHEIK_AT_COLOSSUS, REQUIEM_OF_SPIRIT, {Category::cDesertColossus, Category::cSong,}, SpoilerCollectionCheck::EventChkInf(0xAC), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[SHEIK_IN_KAKARIKO] = ItemLocation::Delayed(0xFF, 0x24, "Sheik in Kakariko", SHEIK_IN_KAKARIKO, NOCTURNE_OF_SHADOW, {Category::cKakarikoVillage, Category::cKakariko, Category::cSong,}, SpoilerCollectionCheck::EventChkInf(0xAA), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[SHEIK_AT_TEMPLE] = ItemLocation::Delayed(0xFF, 0x25, "Sheik at Temple", SHEIK_AT_TEMPLE, PRELUDE_OF_LIGHT, {Category::cTempleOfTime, Category::cMarket, Category::cSong,}, SpoilerCollectionCheck::EventChkInf(0x55), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[SONG_FROM_IMPA] = ItemLocation::Delayed(0xFF, 0x26, "Song from Impa", SONG_FROM_IMPA, ZELDAS_LULLABY, {Category::cHyruleCastle, Category::cMarket, Category::cSong, Category::cSongDungeonReward}, SpoilerCollectionCheck::EventChkInf(0x59), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[SONG_FROM_MALON] = ItemLocation::Delayed(0xFF, 0x27, "Song from Malon", SONG_FROM_MALON, EPONAS_SONG, {Category::cLonLonRanch, Category::cSong,}, SpoilerCollectionCheck::EventChkInf(0x58), SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); + locationTable[SONG_FROM_SARIA] = ItemLocation::Delayed(0xFF, 0x28, "Song from Saria", SONG_FROM_SARIA, SARIAS_SONG, {Category::cSacredForestMeadow, Category::cForest, Category::cSong,}, SpoilerCollectionCheck::EventChkInf(0x57), SpoilerCollectionCheckGroup::GROUP_LOST_WOODS); + locationTable[SONG_FROM_COMPOSERS_GRAVE] = ItemLocation::Delayed(0xFF, 0x29, "Song from Composers Grave", SONG_FROM_COMPOSERS_GRAVE, SUNS_SONG, {Category::cGraveyard, Category::cKakariko, Category::cSong,}, SpoilerCollectionCheck::EventChkInf(0x5A), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[SONG_FROM_OCARINA_OF_TIME] = ItemLocation::Delayed(0xFF, 0x2A, "Song from Ocarina of Time", SONG_FROM_OCARINA_OF_TIME, SONG_OF_TIME, {Category::cHyruleField, Category::cSong, Category::cNeedSpiritualStones,}, SpoilerCollectionCheck::EventChkInf(0xA9), SpoilerCollectionCheckGroup::GROUP_HYRULE_FIELD); + locationTable[SONG_FROM_WINDMILL] = ItemLocation::Delayed(0xFF, 0x2B, "Song from Windmill", SONG_FROM_WINDMILL, SONG_OF_STORMS, {Category::cKakarikoVillage, Category::cKakariko, Category::cSong,}, SpoilerCollectionCheck::EventChkInf(0x5B), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + + /*------------------------------- + --- COWS --- + -------------------------------*/ + + locationTable[KF_LINKS_HOUSE_COW] = ItemLocation::Base (0x34, 0x15, "KF Links House Cow", KF_LINKS_HOUSE_COW, MILK, {Category::cForest, Category::cCow, Category::cMinigame}, SpoilerCollectionCheck::Cow(0x34, 0x15), SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + locationTable[HF_COW_GROTTO_COW] = ItemLocation::Base (0x3E, 0x16, "HF Cow Grotto Cow", HF_COW_GROTTO_COW, MILK, {Category::cHyruleField, Category::cCow, Category::cGrotto}, SpoilerCollectionCheck::Cow(0x3E, 0x16), SpoilerCollectionCheckGroup::GROUP_HYRULE_FIELD); + locationTable[LLR_STABLES_LEFT_COW] = ItemLocation::Base (0x36, 0x16, "LLR Stables Left Cow", LLR_STABLES_LEFT_COW, MILK, {Category::cLonLonRanch, Category::cCow}, SpoilerCollectionCheck::Cow(0x36, 0x16), SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); + locationTable[LLR_STABLES_RIGHT_COW] = ItemLocation::Base (0x36, 0x15, "LLR Stables Right Cow", LLR_STABLES_RIGHT_COW, MILK, {Category::cLonLonRanch, Category::cCow}, SpoilerCollectionCheck::Cow(0x36, 0x15), SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); + locationTable[LLR_TOWER_LEFT_COW] = ItemLocation::Base (0x4C, 0x15, "LLR Tower Left Cow", LLR_TOWER_LEFT_COW, MILK, {Category::cLonLonRanch, Category::cCow}, SpoilerCollectionCheck::Cow(0x4C, 0x16), SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); + locationTable[LLR_TOWER_RIGHT_COW] = ItemLocation::Base (0x4C, 0x16, "LLR Tower Right Cow", LLR_TOWER_RIGHT_COW, MILK, {Category::cLonLonRanch, Category::cCow}, SpoilerCollectionCheck::Cow(0x4C, 0x15), SpoilerCollectionCheckGroup::GROUP_LON_LON_RANCH); + locationTable[KAK_IMPAS_HOUSE_COW] = ItemLocation::Base (0x37, 0x15, "Kak Impas House Cow", KAK_IMPAS_HOUSE_COW, MILK, {Category::cKakarikoVillage, Category::cKakariko, Category::cCow}, SpoilerCollectionCheck::Cow(0x37, 0x15), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[DMT_COW_GROTTO_COW] = ItemLocation::Base (0x3E, 0x15, "DMT Cow Grotto Cow", DMT_COW_GROTTO_COW, MILK, {Category::cDeathMountainTrail, Category::cDeathMountain, Category::cCow, Category::cGrotto}, SpoilerCollectionCheck::Cow(0x3E, 0x15), SpoilerCollectionCheckGroup::GROUP_DEATH_MOUNTAIN); + locationTable[GV_COW] = ItemLocation::Base (0x5A, 0x15, "GV Cow", GV_COW, MILK, {Category::cGerudoValley, Category::cGerudo, Category::cCow}, SpoilerCollectionCheck::Cow(0x5A, 0x15), SpoilerCollectionCheckGroup::GROUP_GERUDO_VALLEY); + locationTable[JABU_JABUS_BELLY_MQ_COW] = ItemLocation::Base (0x02, 0x15, "Jabu Jabus Belly MQ Cow", JABU_JABUS_BELLY_MQ_COW, MILK, {Category::cJabuJabusBelly, Category::cCow}, SpoilerCollectionCheck::Cow(0x02, 0x15), SpoilerCollectionCheckGroup::GROUP_DUNGEON_JABUJABUS_BELLY); + + /*------------------------------- + --- SHOPS --- + 8 6 2 4 + + 7 5 1 3 + -------------------------------*/ + + locationTable[KF_SHOP_ITEM_1] = ItemLocation::Base(0x2D, 0x30, "KF Shop Item 1", KF_SHOP_ITEM_1, BUY_DEKU_SHIELD, {Category::cKokiriForest, Category::cForest, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2D, 0), SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + locationTable[KF_SHOP_ITEM_2] = ItemLocation::Base(0x2D, 0x31, "KF Shop Item 2", KF_SHOP_ITEM_2, BUY_DEKU_NUT_5, {Category::cKokiriForest, Category::cForest, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2D, 1), SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + locationTable[KF_SHOP_ITEM_3] = ItemLocation::Base(0x2D, 0x32, "KF Shop Item 3", KF_SHOP_ITEM_3, BUY_DEKU_NUT_10, {Category::cKokiriForest, Category::cForest, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2D, 2), SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + locationTable[KF_SHOP_ITEM_4] = ItemLocation::Base(0x2D, 0x33, "KF Shop Item 4", KF_SHOP_ITEM_4, BUY_DEKU_STICK_1, {Category::cKokiriForest, Category::cForest, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2D, 3), SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + locationTable[KF_SHOP_ITEM_5] = ItemLocation::Base(0x2D, 0x34, "KF Shop Item 5", KF_SHOP_ITEM_5, BUY_DEKU_SEEDS_30, {Category::cKokiriForest, Category::cForest, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2D, 4), SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + locationTable[KF_SHOP_ITEM_6] = ItemLocation::Base(0x2D, 0x35, "KF Shop Item 6", KF_SHOP_ITEM_6, BUY_ARROWS_10, {Category::cKokiriForest, Category::cForest, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2D, 5), SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + locationTable[KF_SHOP_ITEM_7] = ItemLocation::Base(0x2D, 0x36, "KF Shop Item 7", KF_SHOP_ITEM_7, BUY_ARROWS_30, {Category::cKokiriForest, Category::cForest, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2D, 6), SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + locationTable[KF_SHOP_ITEM_8] = ItemLocation::Base(0x2D, 0x37, "KF Shop Item 8", KF_SHOP_ITEM_8, BUY_HEART, {Category::cKokiriForest, Category::cForest, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2D, 7), SpoilerCollectionCheckGroup::GROUP_KOKIRI_FOREST); + + locationTable[KAK_POTION_SHOP_ITEM_1] = ItemLocation::Base(0x30, 0x30, "Kak Potion Shop Item 1", KAK_POTION_SHOP_ITEM_1, BUY_DEKU_NUT_5, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x30, 0), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_POTION_SHOP_ITEM_2] = ItemLocation::Base(0x30, 0x31, "Kak Potion Shop Item 2", KAK_POTION_SHOP_ITEM_2, BUY_FISH, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x30, 1), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_POTION_SHOP_ITEM_3] = ItemLocation::Base(0x30, 0x32, "Kak Potion Shop Item 3", KAK_POTION_SHOP_ITEM_3, BUY_RED_POTION_30, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x30, 2), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_POTION_SHOP_ITEM_4] = ItemLocation::Base(0x30, 0x33, "Kak Potion Shop Item 4", KAK_POTION_SHOP_ITEM_4, BUY_GREEN_POTION, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x30, 3), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_POTION_SHOP_ITEM_5] = ItemLocation::Base(0x30, 0x34, "Kak Potion Shop Item 5", KAK_POTION_SHOP_ITEM_5, BUY_BLUE_FIRE, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x30, 4), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_POTION_SHOP_ITEM_6] = ItemLocation::Base(0x30, 0x35, "Kak Potion Shop Item 6", KAK_POTION_SHOP_ITEM_6, BUY_BOTTLE_BUG, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x30, 5), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_POTION_SHOP_ITEM_7] = ItemLocation::Base(0x30, 0x36, "Kak Potion Shop Item 7", KAK_POTION_SHOP_ITEM_7, BUY_POE, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x30, 6), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_POTION_SHOP_ITEM_8] = ItemLocation::Base(0x30, 0x37, "Kak Potion Shop Item 8", KAK_POTION_SHOP_ITEM_8, BUY_FAIRYS_SPIRIT, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x30, 7), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + + locationTable[MARKET_BOMBCHU_SHOP_ITEM_1] = ItemLocation::Base(0x32, 0x30, "MK Bombchu Shop Item 1", MARKET_BOMBCHU_SHOP_ITEM_1, BUY_BOMBCHU_5, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x32, 0), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BOMBCHU_SHOP_ITEM_2] = ItemLocation::Base(0x32, 0x31, "MK Bombchu Shop Item 2", MARKET_BOMBCHU_SHOP_ITEM_2, BUY_BOMBCHU_10, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x32, 1), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BOMBCHU_SHOP_ITEM_3] = ItemLocation::Base(0x32, 0x32, "MK Bombchu Shop Item 3", MARKET_BOMBCHU_SHOP_ITEM_3, BUY_BOMBCHU_10, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x32, 2), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BOMBCHU_SHOP_ITEM_4] = ItemLocation::Base(0x32, 0x33, "MK Bombchu Shop Item 4", MARKET_BOMBCHU_SHOP_ITEM_4, BUY_BOMBCHU_10, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x32, 3), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BOMBCHU_SHOP_ITEM_5] = ItemLocation::Base(0x32, 0x34, "MK Bombchu Shop Item 5", MARKET_BOMBCHU_SHOP_ITEM_5, BUY_BOMBCHU_20, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x32, 4), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BOMBCHU_SHOP_ITEM_6] = ItemLocation::Base(0x32, 0x35, "MK Bombchu Shop Item 6", MARKET_BOMBCHU_SHOP_ITEM_6, BUY_BOMBCHU_20, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x32, 5), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BOMBCHU_SHOP_ITEM_7] = ItemLocation::Base(0x32, 0x36, "MK Bombchu Shop Item 7", MARKET_BOMBCHU_SHOP_ITEM_7, BUY_BOMBCHU_20, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x32, 6), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BOMBCHU_SHOP_ITEM_8] = ItemLocation::Base(0x32, 0x37, "MK Bombchu Shop Item 8", MARKET_BOMBCHU_SHOP_ITEM_8, BUY_BOMBCHU_20, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x32, 7), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + + locationTable[MARKET_POTION_SHOP_ITEM_1] = ItemLocation::Base(0x31, 0x30, "MK Potion Shop Item 1", MARKET_POTION_SHOP_ITEM_1, BUY_GREEN_POTION, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x31, 0), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_POTION_SHOP_ITEM_2] = ItemLocation::Base(0x31, 0x31, "MK Potion Shop Item 2", MARKET_POTION_SHOP_ITEM_2, BUY_BLUE_FIRE, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x31, 1), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_POTION_SHOP_ITEM_3] = ItemLocation::Base(0x31, 0x32, "MK Potion Shop Item 3", MARKET_POTION_SHOP_ITEM_3, BUY_RED_POTION_30, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x31, 2), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_POTION_SHOP_ITEM_4] = ItemLocation::Base(0x31, 0x33, "MK Potion Shop Item 4", MARKET_POTION_SHOP_ITEM_4, BUY_FAIRYS_SPIRIT, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x31, 3), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_POTION_SHOP_ITEM_5] = ItemLocation::Base(0x31, 0x34, "MK Potion Shop Item 5", MARKET_POTION_SHOP_ITEM_5, BUY_DEKU_NUT_5, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x31, 4), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_POTION_SHOP_ITEM_6] = ItemLocation::Base(0x31, 0x35, "MK Potion Shop Item 6", MARKET_POTION_SHOP_ITEM_6, BUY_BOTTLE_BUG, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x31, 5), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_POTION_SHOP_ITEM_7] = ItemLocation::Base(0x31, 0x36, "MK Potion Shop Item 7", MARKET_POTION_SHOP_ITEM_7, BUY_POE, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x31, 6), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_POTION_SHOP_ITEM_8] = ItemLocation::Base(0x31, 0x37, "MK Potion Shop Item 8", MARKET_POTION_SHOP_ITEM_8, BUY_FISH, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x31, 7), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + + locationTable[MARKET_BAZAAR_ITEM_1] = ItemLocation::Base(0x2C, 0x30, "MK Bazaar Item 1", MARKET_BAZAAR_ITEM_1, BUY_HYLIAN_SHIELD, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2C, 0), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BAZAAR_ITEM_2] = ItemLocation::Base(0x2C, 0x31, "MK Bazaar Item 2", MARKET_BAZAAR_ITEM_2, BUY_BOMBS_535, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2C, 1), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BAZAAR_ITEM_3] = ItemLocation::Base(0x2C, 0x32, "MK Bazaar Item 3", MARKET_BAZAAR_ITEM_3, BUY_DEKU_NUT_5, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2C, 2), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BAZAAR_ITEM_4] = ItemLocation::Base(0x2C, 0x33, "MK Bazaar Item 4", MARKET_BAZAAR_ITEM_4, BUY_HEART, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2C, 3), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BAZAAR_ITEM_5] = ItemLocation::Base(0x2C, 0x34, "MK Bazaar Item 5", MARKET_BAZAAR_ITEM_5, BUY_ARROWS_10, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2C, 4), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BAZAAR_ITEM_6] = ItemLocation::Base(0x2C, 0x35, "MK Bazaar Item 6", MARKET_BAZAAR_ITEM_6, BUY_ARROWS_50, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2C, 5), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BAZAAR_ITEM_7] = ItemLocation::Base(0x2C, 0x36, "MK Bazaar Item 7", MARKET_BAZAAR_ITEM_7, BUY_DEKU_STICK_1, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2C, 6), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + locationTable[MARKET_BAZAAR_ITEM_8] = ItemLocation::Base(0x2C, 0x37, "MK Bazaar Item 8", MARKET_BAZAAR_ITEM_8, BUY_ARROWS_30, {Category::cInnerMarket, Category::cMarket, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2C, 7), SpoilerCollectionCheckGroup::GROUP_HYRULE_CASTLE); + + locationTable[KAK_BAZAAR_ITEM_1] = ItemLocation::Base(0x2C, 0x38, "Kak Bazaar Item 1", KAK_BAZAAR_ITEM_1, BUY_HYLIAN_SHIELD, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x33, 0), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_BAZAAR_ITEM_2] = ItemLocation::Base(0x2C, 0x39, "Kak Bazaar Item 2", KAK_BAZAAR_ITEM_2, BUY_BOMBS_535, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x33, 1), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_BAZAAR_ITEM_3] = ItemLocation::Base(0x2C, 0x3A, "Kak Bazaar Item 3", KAK_BAZAAR_ITEM_3, BUY_DEKU_NUT_5, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x33, 2), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_BAZAAR_ITEM_4] = ItemLocation::Base(0x2C, 0x3B, "Kak Bazaar Item 4", KAK_BAZAAR_ITEM_4, BUY_HEART, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x33, 3), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_BAZAAR_ITEM_5] = ItemLocation::Base(0x2C, 0x3C, "Kak Bazaar Item 5", KAK_BAZAAR_ITEM_5, BUY_ARROWS_10, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x33, 4), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_BAZAAR_ITEM_6] = ItemLocation::Base(0x2C, 0x3D, "Kak Bazaar Item 6", KAK_BAZAAR_ITEM_6, BUY_ARROWS_50, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x33, 5), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_BAZAAR_ITEM_7] = ItemLocation::Base(0x2C, 0x3E, "Kak Bazaar Item 7", KAK_BAZAAR_ITEM_7, BUY_DEKU_STICK_1, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x33, 6), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + locationTable[KAK_BAZAAR_ITEM_8] = ItemLocation::Base(0x2C, 0x3F, "Kak Bazaar Item 8", KAK_BAZAAR_ITEM_8, BUY_ARROWS_30, {Category::cKakarikoVillage, Category::cKakariko, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x33, 7), SpoilerCollectionCheckGroup::GROUP_KAKARIKO); + + locationTable[ZD_SHOP_ITEM_1] = ItemLocation::Base(0x2F, 0x30, "ZD Shop Item 1", ZD_SHOP_ITEM_1, BUY_ZORA_TUNIC, {Category::cZorasDomain, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2F, 0), SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + locationTable[ZD_SHOP_ITEM_2] = ItemLocation::Base(0x2F, 0x31, "ZD Shop Item 2", ZD_SHOP_ITEM_2, BUY_ARROWS_10, {Category::cZorasDomain, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2F, 1), SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + locationTable[ZD_SHOP_ITEM_3] = ItemLocation::Base(0x2F, 0x32, "ZD Shop Item 3", ZD_SHOP_ITEM_3, BUY_HEART, {Category::cZorasDomain, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2F, 2), SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + locationTable[ZD_SHOP_ITEM_4] = ItemLocation::Base(0x2F, 0x33, "ZD Shop Item 4", ZD_SHOP_ITEM_4, BUY_ARROWS_30, {Category::cZorasDomain, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2F, 3), SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + locationTable[ZD_SHOP_ITEM_5] = ItemLocation::Base(0x2F, 0x34, "ZD Shop Item 5", ZD_SHOP_ITEM_5, BUY_DEKU_NUT_5, {Category::cZorasDomain, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2F, 4), SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + locationTable[ZD_SHOP_ITEM_6] = ItemLocation::Base(0x2F, 0x35, "ZD Shop Item 6", ZD_SHOP_ITEM_6, BUY_ARROWS_50, {Category::cZorasDomain, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2F, 5), SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + locationTable[ZD_SHOP_ITEM_7] = ItemLocation::Base(0x2F, 0x36, "ZD Shop Item 7", ZD_SHOP_ITEM_7, BUY_FISH, {Category::cZorasDomain, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2F, 6), SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + locationTable[ZD_SHOP_ITEM_8] = ItemLocation::Base(0x2F, 0x37, "ZD Shop Item 8", ZD_SHOP_ITEM_8, BUY_RED_POTION_50, {Category::cZorasDomain, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2F, 7), SpoilerCollectionCheckGroup::GROUP_ZORAS_DOMAIN); + + locationTable[GC_SHOP_ITEM_1] = ItemLocation::Base(0x2E, 0x30, "GC Shop Item 1", GC_SHOP_ITEM_1, BUY_BOMBS_525, {Category::cGoronCity, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2E, 0), SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_SHOP_ITEM_2] = ItemLocation::Base(0x2E, 0x31, "GC Shop Item 2", GC_SHOP_ITEM_2, BUY_BOMBS_10, {Category::cGoronCity, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2E, 1), SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_SHOP_ITEM_3] = ItemLocation::Base(0x2E, 0x32, "GC Shop Item 3", GC_SHOP_ITEM_3, BUY_BOMBS_20, {Category::cGoronCity, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2E, 2), SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_SHOP_ITEM_4] = ItemLocation::Base(0x2E, 0x33, "GC Shop Item 4", GC_SHOP_ITEM_4, BUY_BOMBS_30, {Category::cGoronCity, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2E, 3), SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_SHOP_ITEM_5] = ItemLocation::Base(0x2E, 0x34, "GC Shop Item 5", GC_SHOP_ITEM_5, BUY_GORON_TUNIC, {Category::cGoronCity, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2E, 4), SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_SHOP_ITEM_6] = ItemLocation::Base(0x2E, 0x35, "GC Shop Item 6", GC_SHOP_ITEM_6, BUY_HEART, {Category::cGoronCity, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2E, 5), SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_SHOP_ITEM_7] = ItemLocation::Base(0x2E, 0x36, "GC Shop Item 7", GC_SHOP_ITEM_7, BUY_RED_POTION_40, {Category::cGoronCity, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2E, 6), SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + locationTable[GC_SHOP_ITEM_8] = ItemLocation::Base(0x2E, 0x37, "GC Shop Item 8", GC_SHOP_ITEM_8, BUY_HEART, {Category::cGoronCity, Category::cShop}, SpoilerCollectionCheck::ShopItem(0x2E, 7), SpoilerCollectionCheckGroup::GROUP_GORON_CITY); + + /*------------------------------- + --- GOSSIP STONES --- + -------------------------------*/ + // These are not actual locations, but are filler spots used for hint reachability. - OoT Randomizer + // flag + 0x400 = message ID + locationTable[DMC_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x05, "DMC Gossip Stone", {}); + locationTable[DMT_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x04, "DMT Gossip Stone", {}); + locationTable[COLOSSUS_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x1A, "Colossus Gossip Stone", {}); + locationTable[DODONGOS_CAVERN_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x14, "Dodongo's Cavern Gossip Stone", {}); + locationTable[GV_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x11, "GV Gossip Stone", {}); + locationTable[GC_MAZE_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x15, "GC Maze Gossip Stone", {}); + locationTable[GC_MEDIGORON_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x19, "GC Medigoron Gossip Stone", {}); + locationTable[GRAVEYARD_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x0A, "GY Gossip Stone", {}); + locationTable[HC_MALON_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x12, "HC Malon Gossip Stone", {}); + locationTable[HC_ROCK_WALL_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x0B, "HC Rock Wall Gossip Stone", {}); + locationTable[HC_STORMS_GROTTO_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x13, "HC Storms Grotto Gossip Stone", {}); + locationTable[KF_DEKU_TREE_GOSSIP_STONE_LEFT] = ItemLocation::HintStone(0x00, 0x1F, "KF Deku Tree Left Gossip Stone", {}); + locationTable[KF_DEKU_TREE_GOSSIP_STONE_RIGHT] = ItemLocation::HintStone(0x00, 0x20, "KF Deku Tree Right Gossip Stone", {}); + locationTable[KF_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x1E, "KF Gossip Stone", {}); + locationTable[LH_LAB_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x03, "LH Lab Gossip Stone", {}); + locationTable[LH_GOSSIP_STONE_SOUTHEAST] = ItemLocation::HintStone(0x00, 0x0F, "LH Southeast Gossip Stone", {}); + locationTable[LH_GOSSIP_STONE_SOUTHWEST] = ItemLocation::HintStone(0x00, 0x08, "LH Southwest Gossip Stone", {}); + locationTable[LW_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x1D, "LW Gossip Stone", {}); + locationTable[SFM_MAZE_GOSSIP_STONE_LOWER] = ItemLocation::HintStone(0x00, 0x16, "SFM Maze Lower Gossip Stone", {}); + locationTable[SFM_MAZE_GOSSIP_STONE_UPPER] = ItemLocation::HintStone(0x00, 0x17, "SFM Maze Upper Gossip Stone", {}); + locationTable[SFM_SARIA_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x1C, "SFM Saria Gossip Stone", {}); + locationTable[TOT_GOSSIP_STONE_LEFT] = ItemLocation::HintStone(0x00, 0x06, "ToT Left Gossip Stone", {}); + locationTable[TOT_GOSSIP_STONE_RIGHT] = ItemLocation::HintStone(0x00, 0x07, "ToT Left Center Gossip Stone", {}); + locationTable[TOT_GOSSIP_STONE_RIGHT_CENTER] = ItemLocation::HintStone(0x00, 0x10, "ToT Right Center Gossip Stone", {}); + locationTable[TOT_GOSSIP_STONE_LEFT_CENTER] = ItemLocation::HintStone(0x00, 0x0E, "ToT Right Gossip Stone", {}); + locationTable[ZD_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x09, "ZD Gossip Stone", {}); + locationTable[ZF_FAIRY_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x01, "Fairy Gossip Stone", {}); + locationTable[ZF_JABU_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x02, "Jabu Gossip Stone", {}); + locationTable[ZR_NEAR_GROTTOS_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x0D, "ZR Near Grottos Gossip Stone", {}); + locationTable[ZR_NEAR_DOMAIN_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x0C, "ZR Near Domain Gossip Stone", {}); + locationTable[HF_COW_GROTTO_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x1B, "HF Cow Grotto Gossip Stone", {}); + + locationTable[HF_NEAR_MARKET_GROTTO_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x30, "HF Near Market Gossip Stone", {}); + locationTable[HF_SOUTHEAST_GROTTO_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x32, "HF Southeast Gossip Stone", {}); + locationTable[HF_OPEN_GROTTO_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x33, "HF Open Grotto Gossip Stone", {}); + locationTable[KAK_OPEN_GROTTO_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x38, "Kak Open Grotto Gossip Stone", {}); + locationTable[ZR_OPEN_GROTTO_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x39, "ZR Open Grotto Gossip Stone", {}); + locationTable[KF_STORMS_GROTTO_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x3C, "KF Storms Gossip Stone", {}); + locationTable[LW_NEAR_SHORTCUTS_GROTTO_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x34, "LW Near Shortcuts Gossip Stone", {}); + locationTable[DMT_STORMS_GROTTO_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x37, "DMT Storms Grotto Gossip Stone", {}); + locationTable[DMC_UPPER_GROTTO_GOSSIP_STONE] = ItemLocation::HintStone(0x00, 0x3A, "DMC Upper Grotto Gossip Stone", {}); + + locationTable[GANONDORF_HINT] = ItemLocation::OtherHint(0x00, 0x00, "Ganondorf Hint", {}); +} + +std::vector KF_ShopLocations = { + KF_SHOP_ITEM_1, + KF_SHOP_ITEM_2, + KF_SHOP_ITEM_3, + KF_SHOP_ITEM_4, + KF_SHOP_ITEM_5, + KF_SHOP_ITEM_6, + KF_SHOP_ITEM_7, + KF_SHOP_ITEM_8, +}; +std::vector Kak_PotionShopLocations = { + KAK_POTION_SHOP_ITEM_1, + KAK_POTION_SHOP_ITEM_2, + KAK_POTION_SHOP_ITEM_3, + KAK_POTION_SHOP_ITEM_4, + KAK_POTION_SHOP_ITEM_5, + KAK_POTION_SHOP_ITEM_6, + KAK_POTION_SHOP_ITEM_7, + KAK_POTION_SHOP_ITEM_8, +}; +std::vector MK_BombchuShopLocations = { + MARKET_BOMBCHU_SHOP_ITEM_1, + MARKET_BOMBCHU_SHOP_ITEM_2, + MARKET_BOMBCHU_SHOP_ITEM_3, + MARKET_BOMBCHU_SHOP_ITEM_4, + MARKET_BOMBCHU_SHOP_ITEM_5, + MARKET_BOMBCHU_SHOP_ITEM_6, + MARKET_BOMBCHU_SHOP_ITEM_7, + MARKET_BOMBCHU_SHOP_ITEM_8, +}; +std::vector MK_PotionShopLocations = { + MARKET_POTION_SHOP_ITEM_1, + MARKET_POTION_SHOP_ITEM_2, + MARKET_POTION_SHOP_ITEM_3, + MARKET_POTION_SHOP_ITEM_4, + MARKET_POTION_SHOP_ITEM_5, + MARKET_POTION_SHOP_ITEM_6, + MARKET_POTION_SHOP_ITEM_7, + MARKET_POTION_SHOP_ITEM_8, +}; +std::vector MK_BazaarLocations = { + MARKET_BAZAAR_ITEM_1, + MARKET_BAZAAR_ITEM_2, + MARKET_BAZAAR_ITEM_3, + MARKET_BAZAAR_ITEM_4, + MARKET_BAZAAR_ITEM_5, + MARKET_BAZAAR_ITEM_6, + MARKET_BAZAAR_ITEM_7, + MARKET_BAZAAR_ITEM_8, +}; +std::vector Kak_BazaarLocations = { + KAK_BAZAAR_ITEM_1, + KAK_BAZAAR_ITEM_2, + KAK_BAZAAR_ITEM_3, + KAK_BAZAAR_ITEM_4, + KAK_BAZAAR_ITEM_5, + KAK_BAZAAR_ITEM_6, + KAK_BAZAAR_ITEM_7, + KAK_BAZAAR_ITEM_8, +}; +std::vector ZD_ShopLocations = { + ZD_SHOP_ITEM_1, + ZD_SHOP_ITEM_2, + ZD_SHOP_ITEM_3, + ZD_SHOP_ITEM_4, + ZD_SHOP_ITEM_5, + ZD_SHOP_ITEM_6, + ZD_SHOP_ITEM_7, + ZD_SHOP_ITEM_8, +}; +std::vector GC_ShopLocations = { + GC_SHOP_ITEM_1, + GC_SHOP_ITEM_2, + GC_SHOP_ITEM_3, + GC_SHOP_ITEM_4, + GC_SHOP_ITEM_5, + GC_SHOP_ITEM_6, + GC_SHOP_ITEM_7, + GC_SHOP_ITEM_8, +}; +//List of shop location lists, used for shop shuffle +std::vector> ShopLocationLists = { + KF_ShopLocations, + Kak_PotionShopLocations, + MK_BombchuShopLocations, + MK_PotionShopLocations, + MK_BazaarLocations, + Kak_BazaarLocations, + ZD_ShopLocations, + GC_ShopLocations, +}; + +//List of gossip stone locations for hints +std::vector gossipStoneLocations = { + DMC_GOSSIP_STONE, + DMT_GOSSIP_STONE, + COLOSSUS_GOSSIP_STONE, + DODONGOS_CAVERN_GOSSIP_STONE, + GV_GOSSIP_STONE, + GC_MAZE_GOSSIP_STONE, + GC_MEDIGORON_GOSSIP_STONE, + GRAVEYARD_GOSSIP_STONE, + HC_MALON_GOSSIP_STONE, + HC_ROCK_WALL_GOSSIP_STONE, + HC_STORMS_GROTTO_GOSSIP_STONE, + KF_DEKU_TREE_GOSSIP_STONE_LEFT, + KF_DEKU_TREE_GOSSIP_STONE_RIGHT, + KF_GOSSIP_STONE, + LH_LAB_GOSSIP_STONE, + LH_GOSSIP_STONE_SOUTHEAST, + LH_GOSSIP_STONE_SOUTHWEST, + LW_GOSSIP_STONE, + SFM_MAZE_GOSSIP_STONE_LOWER, + SFM_MAZE_GOSSIP_STONE_UPPER, + SFM_SARIA_GOSSIP_STONE, + TOT_GOSSIP_STONE_LEFT, + TOT_GOSSIP_STONE_RIGHT, + TOT_GOSSIP_STONE_RIGHT_CENTER, + TOT_GOSSIP_STONE_LEFT_CENTER, + ZD_GOSSIP_STONE, + ZF_FAIRY_GOSSIP_STONE, + ZF_JABU_GOSSIP_STONE, + ZR_NEAR_GROTTOS_GOSSIP_STONE, + ZR_NEAR_DOMAIN_GOSSIP_STONE, + HF_COW_GROTTO_GOSSIP_STONE, + HF_NEAR_MARKET_GROTTO_GOSSIP_STONE, + HF_SOUTHEAST_GROTTO_GOSSIP_STONE, + HF_OPEN_GROTTO_GOSSIP_STONE, + KAK_OPEN_GROTTO_GOSSIP_STONE, + ZR_OPEN_GROTTO_GOSSIP_STONE, + KF_STORMS_GROTTO_GOSSIP_STONE, + LW_NEAR_SHORTCUTS_GROTTO_GOSSIP_STONE, + DMT_STORMS_GROTTO_GOSSIP_STONE, + DMC_UPPER_GROTTO_GOSSIP_STONE, +}; + +std::vector dungeonRewardLocations = { + //Bosses + QUEEN_GOHMA, + KING_DODONGO, + BARINADE, + PHANTOM_GANON, + VOLVAGIA, + MORPHA, + TWINROVA, + BONGO_BONGO, + LINKS_POCKET, +}; +std::vector overworldLocations = { + //Kokiri Forest + KF_KOKIRI_SWORD_CHEST, + KF_MIDOS_TOP_LEFT_CHEST, + KF_MIDOS_TOP_RIGHT_CHEST, + KF_MIDOS_BOTTOM_LEFT_CHEST, + KF_MIDOS_BOTTOM_RIGHT_CHEST, + KF_STORMS_GROTTO_CHEST, + KF_LINKS_HOUSE_COW, + + //Shop + KF_SHOP_ITEM_1, + KF_SHOP_ITEM_2, + KF_SHOP_ITEM_3, + KF_SHOP_ITEM_4, + KF_SHOP_ITEM_5, + KF_SHOP_ITEM_6, + KF_SHOP_ITEM_7, + KF_SHOP_ITEM_8, + + //Lost Woods + LW_GIFT_FROM_SARIA, + LW_SKULL_KID, + LW_TRADE_COJIRO, + LW_TRADE_ODD_POTION, + LW_OCARINA_MEMORY_GAME, + LW_TARGET_IN_WOODS, + LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT, + LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, + LW_DEKU_SCRUB_NEAR_BRIDGE, + LW_NEAR_SHORTCUTS_GROTTO_CHEST, + LW_DEKU_SCRUB_GROTTO_REAR, + LW_DEKU_SCRUB_GROTTO_FRONT, + DEKU_THEATER_SKULL_MASK, + DEKU_THEATER_MASK_OF_TRUTH, + + //Sacred Forest Meadow + SONG_FROM_SARIA, + SHEIK_IN_FOREST, + SFM_WOLFOS_GROTTO_CHEST, + SFM_DEKU_SCRUB_GROTTO_REAR, + SFM_DEKU_SCRUB_GROTTO_FRONT, + + //Hyrule Field + HF_SOUTHEAST_GROTTO_CHEST, + HF_OPEN_GROTTO_CHEST, + HF_NEAR_MARKET_GROTTO_CHEST, + HF_OCARINA_OF_TIME_ITEM, + SONG_FROM_OCARINA_OF_TIME, + HF_TEKTITE_GROTTO_FREESTANDING_POH, + HF_DEKU_SCRUB_GROTTO, + HF_COW_GROTTO_COW, + + //Lake Hylia + LH_CHILD_FISHING, + LH_ADULT_FISHING, + LH_LAB_DIVE, + LH_TRADE_FROG, + LH_UNDERWATER_ITEM, + LH_SUN, + LH_FREESTANDING_POH, + LH_DEKU_SCRUB_GROTTO_LEFT, + LH_DEKU_SCRUB_GROTTO_RIGHT, + LH_DEKU_SCRUB_GROTTO_CENTER, + + //Gerudo Valley + GV_CHEST, + GV_TRADE_SAW, + GV_WATERFALL_FREESTANDING_POH, + GV_CRATE_FREESTANDING_POH, + GV_DEKU_SCRUB_GROTTO_REAR, + GV_DEKU_SCRUB_GROTTO_FRONT, + GV_COW, + + //Gerudo Fortress + GF_CHEST, + GF_HBA_1000_POINTS, + GF_HBA_1500_POINTS, + GF_NORTH_F1_CARPENTER, + GF_NORTH_F2_CARPENTER, + GF_SOUTH_F1_CARPENTER, + GF_SOUTH_F2_CARPENTER, + GF_GERUDO_MEMBERSHIP_CARD, + + //Haunted Wasteland + WASTELAND_CHEST, + WASTELAND_BOMBCHU_SALESMAN, + + //Desert Colossus + SHEIK_AT_COLOSSUS, + COLOSSUS_FREESTANDING_POH, + COLOSSUS_GREAT_FAIRY_REWARD, + COLOSSUS_DEKU_SCRUB_GROTTO_REAR, + COLOSSUS_DEKU_SCRUB_GROTTO_FRONT, + + //Market + MARKET_TREASURE_CHEST_GAME_REWARD, + MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, + MARKET_BOMBCHU_BOWLING_SECOND_PRIZE, + MARKET_BOMBCHU_BOWLING_BOMBCHUS, + MARKET_LOST_DOG, + MARKET_SHOOTING_GALLERY_REWARD, + MARKET_10_BIG_POES, + MARKET_TREASURE_CHEST_GAME_ITEM_1, + MARKET_TREASURE_CHEST_GAME_ITEM_2, + MARKET_TREASURE_CHEST_GAME_ITEM_3, + MARKET_TREASURE_CHEST_GAME_ITEM_4, + MARKET_TREASURE_CHEST_GAME_ITEM_5, + + //Market Shops + MARKET_BOMBCHU_SHOP_ITEM_1, + MARKET_BOMBCHU_SHOP_ITEM_2, + MARKET_BOMBCHU_SHOP_ITEM_3, + MARKET_BOMBCHU_SHOP_ITEM_4, + MARKET_BOMBCHU_SHOP_ITEM_5, + MARKET_BOMBCHU_SHOP_ITEM_6, + MARKET_BOMBCHU_SHOP_ITEM_7, + MARKET_BOMBCHU_SHOP_ITEM_8, + MARKET_POTION_SHOP_ITEM_1, + MARKET_POTION_SHOP_ITEM_2, + MARKET_POTION_SHOP_ITEM_3, + MARKET_POTION_SHOP_ITEM_4, + MARKET_POTION_SHOP_ITEM_5, + MARKET_POTION_SHOP_ITEM_6, + MARKET_POTION_SHOP_ITEM_7, + MARKET_POTION_SHOP_ITEM_8, + MARKET_BAZAAR_ITEM_1, + MARKET_BAZAAR_ITEM_2, + MARKET_BAZAAR_ITEM_3, + MARKET_BAZAAR_ITEM_4, + MARKET_BAZAAR_ITEM_5, + MARKET_BAZAAR_ITEM_6, + MARKET_BAZAAR_ITEM_7, + MARKET_BAZAAR_ITEM_8, + + //Hyrule Castle + HC_MALON_EGG, + HC_ZELDAS_LETTER, + SONG_FROM_IMPA, + HC_GREAT_FAIRY_REWARD, + OGC_GREAT_FAIRY_REWARD, + + //Temple of Time + SHEIK_AT_TEMPLE, + TOT_LIGHT_ARROWS_CUTSCENE, + + //Kakariko + SHEIK_IN_KAKARIKO, + KAK_REDEAD_GROTTO_CHEST, + KAK_OPEN_GROTTO_CHEST, + KAK_10_GOLD_SKULLTULA_REWARD, + KAK_20_GOLD_SKULLTULA_REWARD, + KAK_30_GOLD_SKULLTULA_REWARD, + KAK_40_GOLD_SKULLTULA_REWARD, + KAK_50_GOLD_SKULLTULA_REWARD, + KAK_MAN_ON_ROOF, + KAK_SHOOTING_GALLERY_REWARD, + KAK_TRADE_ODD_MUSHROOM, + KAK_ANJU_AS_CHILD, + KAK_ANJU_AS_ADULT, + KAK_TRADE_POCKET_CUCCO, + KAK_IMPAS_HOUSE_FREESTANDING_POH, + KAK_WINDMILL_FREESTANDING_POH, + SONG_FROM_WINDMILL, + KAK_IMPAS_HOUSE_COW, + + //Kakariko Shops + KAK_POTION_SHOP_ITEM_1, + KAK_POTION_SHOP_ITEM_2, + KAK_POTION_SHOP_ITEM_3, + KAK_POTION_SHOP_ITEM_4, + KAK_POTION_SHOP_ITEM_5, + KAK_POTION_SHOP_ITEM_6, + KAK_POTION_SHOP_ITEM_7, + KAK_POTION_SHOP_ITEM_8, + KAK_BAZAAR_ITEM_1, + KAK_BAZAAR_ITEM_2, + KAK_BAZAAR_ITEM_3, + KAK_BAZAAR_ITEM_4, + KAK_BAZAAR_ITEM_5, + KAK_BAZAAR_ITEM_6, + KAK_BAZAAR_ITEM_7, + KAK_BAZAAR_ITEM_8, + + //Graveyard + GRAVEYARD_HOOKSHOT_CHEST, + GRAVEYARD_SHIELD_GRAVE_CHEST, + GRAVEYARD_HEART_PIECE_GRAVE_CHEST, + GRAVEYARD_COMPOSERS_GRAVE_CHEST, + SONG_FROM_COMPOSERS_GRAVE, + GRAVEYARD_FREESTANDING_POH, + GRAVEYARD_DAMPE_RACE_FREESTANDING_POH, + GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR, + + //Death Mountain Trail + DMT_CHEST, + DMT_STORMS_GROTTO_CHEST, + DMT_TRADE_BROKEN_SWORD, + DMT_TRADE_EYEDROPS, + DMT_TRADE_CLAIM_CHECK, + DMT_GREAT_FAIRY_REWARD, + DMT_FREESTANDING_POH, + DMT_COW_GROTTO_COW, + + //Goron City + GC_MAZE_LEFT_CHEST, + GC_MAZE_CENTER_CHEST, + GC_MAZE_RIGHT_CHEST, + GC_ROLLING_GORON_AS_CHILD, + GC_ROLLING_GORON_AS_ADULT, + GC_DARUNIAS_JOY, + GC_POT_FREESTANDING_POH, + GC_DEKU_SCRUB_GROTTO_LEFT, + GC_DEKU_SCRUB_GROTTO_RIGHT, + GC_DEKU_SCRUB_GROTTO_CENTER, + GC_MEDIGORON, + + //Goron City Shop + GC_SHOP_ITEM_1, + GC_SHOP_ITEM_2, + GC_SHOP_ITEM_3, + GC_SHOP_ITEM_4, + GC_SHOP_ITEM_5, + GC_SHOP_ITEM_6, + GC_SHOP_ITEM_7, + GC_SHOP_ITEM_8, + + //Death Mountain + DMC_UPPER_GROTTO_CHEST, + DMC_WALL_FREESTANDING_POH, + DMC_VOLCANO_FREESTANDING_POH, + SHEIK_IN_CRATER, + DMC_DEKU_SCRUB, + DMC_GREAT_FAIRY_REWARD, + DMC_DEKU_SCRUB_GROTTO_LEFT, + DMC_DEKU_SCRUB_GROTTO_RIGHT, + DMC_DEKU_SCRUB_GROTTO_CENTER, + + //Zoras River + ZR_OPEN_GROTTO_CHEST, + ZR_MAGIC_BEAN_SALESMAN, + ZR_FROGS_IN_THE_RAIN, + ZR_FROGS_OCARINA_GAME, + ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH, + ZR_NEAR_DOMAIN_FREESTANDING_POH, + ZR_DEKU_SCRUB_GROTTO_REAR, + ZR_DEKU_SCRUB_GROTTO_FRONT, + + //Zoras Domain + ZD_CHEST, + ZD_DIVING_MINIGAME, + ZD_KING_ZORA_THAWED, + ZD_TRADE_PRESCRIPTION, + + //Zora's Domain Shop + ZD_SHOP_ITEM_1, + ZD_SHOP_ITEM_2, + ZD_SHOP_ITEM_3, + ZD_SHOP_ITEM_4, + ZD_SHOP_ITEM_5, + ZD_SHOP_ITEM_6, + ZD_SHOP_ITEM_7, + ZD_SHOP_ITEM_8, + + //Zoras Fountain + ZF_ICEBERG_FREESTANDING_POH, + ZF_BOTTOM_FREESTANDING_POH, + ZF_GREAT_FAIRY_REWARD, + + //Lon Lon Ranch + SONG_FROM_MALON, + LLR_TALONS_CHICKENS, + LLR_FREESTANDING_POH, + LLR_DEKU_SCRUB_GROTTO_LEFT, + LLR_DEKU_SCRUB_GROTTO_RIGHT, + LLR_DEKU_SCRUB_GROTTO_CENTER, + LLR_STABLES_LEFT_COW, + LLR_STABLES_RIGHT_COW, + LLR_TOWER_LEFT_COW, + LLR_TOWER_RIGHT_COW, + + /*------------------------------- + --- GOLD SKULLTULA TOKENS --- + -------------------------------*/ + + //Overworld + KF_GS_BEAN_PATCH, + KF_GS_KNOW_IT_ALL_HOUSE, + KF_GS_HOUSE_OF_TWINS, + + LW_GS_BEAN_PATCH_NEAR_BRIDGE, + LW_GS_BEAN_PATCH_NEAR_THEATER, + LW_GS_ABOVE_THEATER, + SFM_GS, + + HF_GS_COW_GROTTO, + HF_GS_NEAR_KAK_GROTTO, + + LH_GS_BEAN_PATCH, + LH_GS_SMALL_ISLAND, + LH_GS_LAB_WALL, + LH_GS_LAB_CRATE, + LH_GS_TREE, + + GV_GS_BEAN_PATCH, + GV_GS_SMALL_BRIDGE, + GV_GS_PILLAR, + GV_GS_BEHIND_TENT, + + GF_GS_ARCHERY_RANGE, + GF_GS_TOP_FLOOR, + + WASTELAND_GS, + COLOSSUS_GS_BEAN_PATCH, + COLOSSUS_GS_HILL, + COLOSSUS_GS_TREE, + + OGC_GS, + HC_GS_STORMS_GROTTO, + HC_GS_TREE, + MARKET_GS_GUARD_HOUSE, + + KAK_GS_HOUSE_UNDER_CONSTRUCTION, + KAK_GS_SKULLTULA_HOUSE, + KAK_GS_GUARDS_HOUSE, + KAK_GS_TREE, + KAK_GS_WATCHTOWER, + KAK_GS_ABOVE_IMPAS_HOUSE, + + DMC_GS_BEAN_PATCH, + DMC_GS_CRATE, + + DMT_GS_BEAN_PATCH, + DMT_GS_NEAR_KAK, + DMT_GS_ABOVE_DODONGOS_CAVERN, + DMT_GS_FALLING_ROCKS_PATH, + + GC_GS_CENTER_PLATFORM, + GC_GS_BOULDER_MAZE, + GRAVEYARD_GS_WALL, + GRAVEYARD_GS_BEAN_PATCH, + + ZR_GS_LADDER, + ZR_GS_TREE, + ZR_GS_ABOVE_BRIDGE, + ZR_GS_NEAR_RAISED_GROTTOS, + + ZD_GS_FROZEN_WATERFALL, + ZF_GS_ABOVE_THE_LOG, + ZF_GS_HIDDEN_CAVE, + ZF_GS_TREE, + + LLR_GS_BACK_WALL, + LLR_GS_RAIN_SHED, + LLR_GS_HOUSE_WINDOW, + LLR_GS_TREE, +}; + +ItemLocation* Location(uint32_t locKey) { + return &(locationTable[locKey]); +} + +std::vector allLocations = {}; +std::vector everyPossibleLocation = {}; + +//set of overrides to write to the patch +std::set overrides = {}; + +std::vector> playthroughLocations; +std::vector wothLocations; +bool playthroughBeatable = false; +bool allLocationsReachable = false; +bool showItemProgress = false; + +uint16_t itemsPlaced = 0; + +void AddLocation(uint32_t loc, std::vector* destination = &allLocations) { + destination->push_back(loc); +} + +template +void AddLocations(const Container& locations, std::vector* destination = &allLocations) { + destination->insert(destination->end(), std::cbegin(locations), std::cend(locations)); +} + +//sort through Vanilla and MQ dungeon locations +void GenerateLocationPool() { + + allLocations.clear(); + AddLocation(LINKS_POCKET); + AddLocations(overworldLocations); + + for (auto dungeon : Dungeon::dungeonList) { + AddLocations(dungeon->GetDungeonLocations()); + } +} + +void PlaceItemInLocation(uint32_t locKey, uint32_t item, bool applyEffectImmediately /*= false*/, bool setHidden /*= false*/) { + auto loc = Location(locKey); + SPDLOG_INFO("\n"); + SPDLOG_INFO(ItemTable(item).GetName().GetEnglish()); + SPDLOG_INFO(" placed at "); + SPDLOG_INFO(loc->GetName()); + SPDLOG_INFO("\n\n"); + + if (applyEffectImmediately || Settings::Logic.Is(LOGIC_NONE) || Settings::Logic.Is(LOGIC_VANILLA)) { + ItemTable(item).ApplyEffect(); + } + + itemsPlaced++; + if (showItemProgress) { + double completion = (double) itemsPlaced / (double)(allLocations.size() + dungeonRewardLocations.size()); + std::string message = "\x1b[8;10HPlacing Items."; + message += completion > 0.25 ? "." : " "; + message += completion > 0.50 ? "." : " "; + printf("%s", message.c_str()); + } + + //If we're placing a non-shop item in a shop location, we want to record it for custom messages + if (ItemTable(item).GetItemType() != ITEMTYPE_SHOP && loc->IsCategory(Category::cShop)) { + int index = TransformShopIndex(GetShopIndex(locKey)); + NonShopItems[index].Name = ItemTable(item).GetName(); + NonShopItems[index].Repurchaseable = ItemTable(item).GetItemType() == ITEMTYPE_REFILL || ItemTable(item).GetHintKey() == PROGRESSIVE_BOMBCHUS; + } + + loc->SetPlacedItem(item); + if (setHidden) { + loc->SetHidden(true); + } +} + +std::vector GetLocations(const std::vector& locationPool, Category categoryInclude, Category categoryExclude /*= Category::cNull*/) { + std::vector locationsInCategory; + for (uint32_t locKey : locationPool) { + if (Location(locKey)->IsCategory(categoryInclude) && !Location(locKey)->IsCategory(categoryExclude)) { + locationsInCategory.push_back(locKey); + } + } + return locationsInCategory; +} + +void LocationReset() { + for (uint32_t il : allLocations) { + Location(il)->RemoveFromPool(); + } + + for (uint32_t il : dungeonRewardLocations) { + Location(il)->RemoveFromPool(); + } + + for (uint32_t il : gossipStoneLocations) { + Location(il)->RemoveFromPool(); + } + + Location(GANONDORF_HINT)->RemoveFromPool(); +} + +void ItemReset() { + for (uint32_t il : allLocations) { + Location(il)->ResetVariables(); + } + + for (uint32_t il : dungeonRewardLocations) { + Location(il)->ResetVariables(); + } + + itemsPlaced = 0; +} + +void HintReset() { + for (uint32_t il : gossipStoneLocations) { + Location(il)->ResetVariables(); + } +} + +//Fills everyPossibleLocation and creates an exclusion option for each location. +//everyPossibleLocation is used in the menu to lock/hide excluding locations +void AddExcludedOptions() { + AddLocations(overworldLocations, &everyPossibleLocation); + + for (auto dungeon : Dungeon::dungeonList) { + AddLocations(dungeon->GetEveryLocation(), &everyPossibleLocation); + } + + for (uint32_t il: everyPossibleLocation) { + Location(il)->AddExcludeOption(); + } +} + +void CreateItemOverrides() { + SPDLOG_INFO("NOW CREATING OVERRIDES\n\n"); + for (uint32_t locKey : allLocations) { + auto loc = Location(locKey); + ItemOverride_Value val = ItemTable(loc->GetPlaceduint32_t()).Value(); + // If this is an ice trap in a shop, change the name based on what the model will look like + if (loc->GetPlaceduint32_t() == ICE_TRAP && loc->IsCategory(Category::cShop)) { + NonShopItems[TransformShopIndex(GetShopIndex(locKey))].Name = GetIceTrapName(val.looksLikeItemId); + } + overrides.insert({ + .key = loc->Key(), + .value = val, + }); + SPDLOG_INFO("\tScene: "); + SPDLOG_INFO(std::to_string(loc->Key().scene)); + SPDLOG_INFO("\tType: "); + SPDLOG_INFO(std::to_string(loc->Key().type)); + SPDLOG_INFO("\tFlag: "); + SPDLOG_INFO(std::to_string(loc->Key().flag)); + SPDLOG_INFO("\t"); + SPDLOG_INFO(loc->GetName()); + SPDLOG_INFO(": "); + SPDLOG_INFO(loc->GetPlacedItemName().GetEnglish()); + SPDLOG_INFO("\n"); + } + SPDLOG_INFO("Overrides Created: "); + SPDLOG_INFO(std::to_string(overrides.size())); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/3drando/item_location.hpp b/soh/soh/Enhancements/randomizer/3drando/item_location.hpp new file mode 100644 index 000000000..2f6bdc52d --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/item_location.hpp @@ -0,0 +1,490 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include "spoiler_log.hpp" +#include "item_list.hpp" + +enum ItemOverride_Type { + OVR_BASE_ITEM = 0, + OVR_CHEST = 1, + OVR_COLLECTABLE = 2, + OVR_SKULL = 3, + OVR_GROTTO_SCRUB = 4, + OVR_DELAYED = 5, + OVR_TEMPLE = 6, +}; + +typedef enum { + DUNGEON_DEKU_TREE = 0, + DUNGEON_DODONGOS_CAVERN, + DUNGEON_JABUJABUS_BELLY, + DUNGEON_FOREST_TEMPLE, + DUNGEON_FIRE_TEMPLE, + DUNGEON_WATER_TEMPLE, + DUNGEON_SPIRIT_TEMPLE, + DUNGEON_SHADOW_TEMPLE, + DUNGEON_BOTTOM_OF_THE_WELL, + DUNGEON_ICE_CAVERN, + DUNGEON_GANONS_CASTLE_SECOND_PART, + DUNGEON_GERUDO_TRAINING_GROUNDS, + DUNGEON_GERUDO_FORTRESS, + DUNGEON_GANONS_CASTLE_FIRST_PART, + DUNGEON_GANONS_CASTLE_FLOOR_BENEATH_BOSS_CHAMBER, + DUNGEON_GANONS_CASTLE_CRUMBLING, + DUNGEON_TREASURE_CHEST_SHOP, + DUNGEON_DEKU_TREE_BOSS_ROOM, + DUNGEON_DODONGOS_CAVERN_BOSS_ROOM, + DUNGEON_JABUJABUS_BELLY_BOSS_ROOM, +} DungeonId; + +typedef union ItemOverride_Key { + uint32_t all; + struct { + char pad_; + uint8_t scene; + uint8_t type; + uint8_t flag; + }; +} ItemOverride_Key; + +typedef union ItemOverride_Value { + uint32_t all; + struct { + uint16_t itemId; + uint8_t player; + uint8_t looksLikeItemId; + }; +} ItemOverride_Value; + +typedef struct ItemOverride { + ItemOverride_Key key; + ItemOverride_Value value; +} ItemOverride; + +class Entrance; + +enum class ItemLocationType { + Base, + Chest, + Collectable, + GSToken, + GrottoScrub, + Delayed, + TempleReward, + HintStone, + OtherHint, +}; + +class SpoilerCollectionCheck { +public: + SpoilerCollectionCheckType type = SpoilerCollectionCheckType::SPOILER_CHK_NONE; + uint8_t scene = 0; + uint8_t flag = 0; + + SpoilerCollectionCheck() {} + SpoilerCollectionCheck(SpoilerCollectionCheckType type_, uint8_t scene_, uint8_t flag_) : type(type_), scene(scene_), flag(flag_) {} + + static auto None() { + return SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_NONE, 0x00, 0x00); + } + + static auto AlwaysCollected() { + return SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_ALWAYS_COLLECTED, 0x00, 0x00); + } + + static auto ItemGetInf(uint8_t slot) { + return SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_ITEM_GET_INF, 0x00, slot); + } + + static auto EventChkInf(uint8_t flag) { + return SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_EVENT_CHK_INF, 0xFF, flag); + } + + static auto InfTable(uint8_t offset, uint8_t bit) { + return SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_INF_TABLE, offset, bit); + } + + static auto Collectable(uint8_t scene, uint8_t flag) { + return SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_COLLECTABLE, scene, flag); + } + + static auto Chest(uint8_t scene, uint8_t flag) { + return SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_CHEST, scene, flag); + } + + static auto Cow(uint8_t scene, uint8_t flag) { + return SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_COW, scene, flag); + } + + static auto Fishing(uint8_t bit) { + return SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_MINIGAME, 0x00, bit); + } + + static auto Scrub(uint8_t scene, uint8_t bit) { + return SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_SCRUB, scene, bit); + } + + static auto Biggoron(uint8_t mask) { + return SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_BIGGORON, 0x00, mask); + } + + static auto GerudoToken() { + return SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_GERUDO_MEMBERSHIP_CARD, 0x00, 0x00); + } + + static auto BigPoePoints() { + return SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_POE_POINTS, 0x00, 0x00); + } + + static auto ShopItem(uint8_t scene, uint8_t itemSlot) { + return SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_SHOP_ITEM, scene, itemSlot); + } + + static auto MagicBeans(uint8_t scene, uint8_t flag) { + return SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_MAGIC_BEANS, scene, flag); + } +}; + +class ItemLocation { +public: + ItemLocation() = default; + ItemLocation(uint8_t scene_, ItemLocationType type_, uint8_t flag_, std::string name_, uint32_t hintKey_, uint32_t vanillaItem_, std::vector categories_, uint16_t price_ = 0, SpoilerCollectionCheck collectionCheck_ = SpoilerCollectionCheck(), SpoilerCollectionCheckGroup collectionCheckGroup_ = SpoilerCollectionCheckGroup::GROUP_NO_GROUP) + : scene(scene_), type(type_), flag(flag_), name(std::move(name_)), hintKey(hintKey_), vanillaItem(vanillaItem_), categories(std::move(categories_)), price(price_), collectionCheck(collectionCheck_), collectionCheckGroup(collectionCheckGroup_) {} + + ItemOverride_Key Key() const { + ItemOverride_Key key; + key.all = 0; + + key.scene = scene; + key.type = static_cast(type); //TODO make sure these match up + key.flag = flag; + return key; + } + + SpoilerCollectionCheck GetCollectionCheck() const { + return collectionCheck; + } + + SpoilerCollectionCheckGroup GetCollectionCheckGroup() const { + return collectionCheckGroup; + } + + uint8_t GetScene() const { + return scene; + } + + uint8_t GetFlag() const { + return flag; + } + + bool IsAddedToPool() const { + return addedToPool; + } + + void AddToPool() { + addedToPool = true; + } + + const uint32_t GetHintKey() const { + return hintKey; + } + + void RemoveFromPool() { + addedToPool = false; + } + + const std::string& GetName() const { + return name; + } + + const Text& GetPlacedItemName() const { + return ItemTable(placedItem).GetName(); + } + + const Item& GetPlacedItem() const { + return ItemTable(placedItem); + } + + uint32_t GetPlacedItemKey() const { + return placedItem; + } + + uint32_t GetPlaceduint32_t() const { + return placedItem; + } + + void SetPlacedItem(const uint32_t item) { + placedItem = item; + SetPrice(ItemTable(placedItem).GetPrice()); + } + + //Saves an item to be set as placedItem later + void SetDelayedItem(const uint32_t item) { + delayedItem = item; + } + + //Place the vanilla item in this location + void PlaceVanillaItem() { + placedItem = vanillaItem; + } + + void ApplyPlacedItemEffect() { + ItemTable(placedItem).ApplyEffect(); + } + + //Set placedItem as item saved in SetDelayedItem + void SaveDelayedItem() { + placedItem = delayedItem; + delayedItem = NONE; + } + + uint16_t GetPrice() const { + if (ItemTable(placedItem).GetItemType() == ITEMTYPE_SHOP) { + return ItemTable(placedItem).GetPrice(); + } + return price; + } + + void SetPrice(uint16_t price_) { + //don't override price if the price was set for shopsanity + if (hasShopsanityPrice) { + return; + } + price = price_; + } + + void SetShopsanityPrice(uint16_t price_) { + price = price_; + hasShopsanityPrice = true; + } + + bool HasShopsanityPrice() const { + return hasShopsanityPrice; + } + + bool IsExcluded() const { + return excludedOption.Value(); + } + + bool IsCategory(Category category) const { + return std::any_of(categories.begin(), categories.end(), + [category](auto entry) { return entry == category; }); + } + + bool IsDungeon() const { + return (type != ItemLocationType::GSToken && (scene < 0x0E || (scene > 0x10 && scene < 0x1A))) || (type == ItemLocationType::GSToken && scene < 0x0A); + } + + bool IsOverworld() const { + return !IsDungeon(); + } + + bool IsShop() const { + return (scene >= 0x2C && scene <= 0x32); + } + + Option * GetExcludedOption() { + return &excludedOption; + } + + const uint32_t Getuint32_t() const { + return hintKey; + } + + const HintText& GetHint() const { + return Hint(hintKey); + } + + bool IsHintedAt() const { + return hintedAt; + } + + void SetAsHinted() { + hintedAt = true; + } + + bool IsHidden() const { + return hidden; + } + + void SetHidden(const bool hidden_) { + hidden = hidden_; + } + + bool IsHintable() const { + return isHintable; + } + + void SetAsHintable() { + isHintable = true; + } + + void SetParentRegion(uint32_t region) { + parentRegion = region; + } + + uint32_t GetParentRegionKey() const { + return parentRegion; + } + + void AddExcludeOption() { + //setting description /*--------------------------------------------------*/ + std::string_view desc = "Decide which locations you want to exclude from\n" + "the location pool. Locations that require an item\n" + "to be placed at them based on your current\n" + "settings cannot be excluded and won't be shown\n" + "unless you change your settings.\n" + "\n" + "If you exclude too many locations, it might not\n" + "be possible to fill the world."; + + //add option to forbid any location from progress items + if (name.length() < 23) { + excludedOption = Option::Bool(name, {"Include", "Exclude"}, {desc}); + } else { + //insert a newline character if the text is too long for one row + size_t lastSpace = name.rfind(' ', 23); + std::string settingText = name; + settingText.replace(lastSpace, 1, "\n "); + + excludedOption = Option::Bool(settingText, {"Include", "Exclude"}, {desc}); + } + + // RANDOTODO: this without string compares and loops + bool alreadyAdded = false; + for(const Option* location : Settings::excludeLocationsOptionsVector[collectionCheckGroup]) { + if (location->GetName() == excludedOption.GetName()) { + alreadyAdded = true; + } + } + if (!alreadyAdded) { + Settings::excludeLocationsOptionsVector[collectionCheckGroup].push_back(&excludedOption); + } + } + + static auto Base(uint8_t scene, uint8_t flag, std::string&& name, const uint32_t hintKey, const uint32_t vanillaItem, std::vector&& categories, SpoilerCollectionCheck collectionCheck = SpoilerCollectionCheck(), SpoilerCollectionCheckGroup collectionCheckGroup = SpoilerCollectionCheckGroup::GROUP_NO_GROUP) { + return ItemLocation{scene, ItemLocationType::Base, flag, std::move(name), hintKey, vanillaItem, std::move(categories), 0, collectionCheck, collectionCheckGroup}; + } + + static auto Chest(uint8_t scene, uint8_t flag, std::string&& name, const uint32_t hintKey, const uint32_t vanillaItem, std::vector&& categories, SpoilerCollectionCheckGroup collectionCheckGroup = SpoilerCollectionCheckGroup::GROUP_NO_GROUP) { + return ItemLocation{scene, ItemLocationType::Chest, flag, std::move(name), hintKey, vanillaItem, std::move(categories), 0, SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_CHEST, scene, flag), collectionCheckGroup}; + } + + static auto Chest(uint8_t scene, uint8_t flag, std::string&& name, const uint32_t hintKey, const uint32_t vanillaItem, std::vector&& categories, SpoilerCollectionCheck collectionCheck, SpoilerCollectionCheckGroup collectionCheckGroup = SpoilerCollectionCheckGroup::GROUP_NO_GROUP) { + return ItemLocation{scene, ItemLocationType::Chest, flag, std::move(name), hintKey, vanillaItem, std::move(categories), 0, collectionCheck, collectionCheckGroup}; + } + + static auto Collectable(uint8_t scene, uint8_t flag, std::string&& name, const uint32_t hintKey, const uint32_t vanillaItem, std::vector&& categories, SpoilerCollectionCheckGroup collectionCheckGroup = SpoilerCollectionCheckGroup::GROUP_NO_GROUP) { + return ItemLocation{scene, ItemLocationType::Collectable, flag, std::move(name), hintKey, vanillaItem, std::move(categories), 0, SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_COLLECTABLE, scene, flag), collectionCheckGroup}; + } + + static auto Collectable(uint8_t scene, uint8_t flag, std::string&& name, const uint32_t hintKey, const uint32_t vanillaItem, std::vector&& categories, SpoilerCollectionCheck collectionCheck, SpoilerCollectionCheckGroup collectionCheckGroup = SpoilerCollectionCheckGroup::GROUP_NO_GROUP) { + return ItemLocation{scene, ItemLocationType::Collectable, flag, std::move(name), hintKey, vanillaItem, std::move(categories), 0, collectionCheck, collectionCheckGroup}; + } + + static auto GSToken(uint8_t scene, uint8_t flag, std::string&& name, const uint32_t hintKey, std::vector&& categories, SpoilerCollectionCheckGroup collectionCheckGroup = SpoilerCollectionCheckGroup::GROUP_NO_GROUP) { + return ItemLocation{scene, ItemLocationType::GSToken, flag, std::move(name), hintKey, GOLD_SKULLTULA_TOKEN, std::move(categories), 0, SpoilerCollectionCheck(SpoilerCollectionCheckType::SPOILER_CHK_GOLD_SKULLTULA, scene, flag), collectionCheckGroup}; + } + + static auto GrottoScrub(uint8_t scene, uint8_t flag, std::string&& name, const uint32_t hintKey, const uint32_t vanillaItem, std::vector&& categories, SpoilerCollectionCheck collectionCheck = SpoilerCollectionCheck(), SpoilerCollectionCheckGroup collectionCheckGroup = SpoilerCollectionCheckGroup::GROUP_NO_GROUP) { + return ItemLocation{scene, ItemLocationType::GrottoScrub, flag, std::move(name), hintKey, vanillaItem, std::move(categories), 0, collectionCheck, collectionCheckGroup}; + } + + static auto Delayed(uint8_t scene, uint8_t flag, std::string&& name, const uint32_t hintKey, const uint32_t vanillaItem, std::vector&& categories, SpoilerCollectionCheck collectionCheck = SpoilerCollectionCheck(), SpoilerCollectionCheckGroup collectionCheckGroup = SpoilerCollectionCheckGroup::GROUP_NO_GROUP) { + return ItemLocation{scene, ItemLocationType::Delayed, flag, std::move(name), hintKey, vanillaItem, std::move(categories), 0, collectionCheck, collectionCheckGroup}; + } + + static auto Reward(uint8_t scene, uint8_t flag, std::string&& name, const uint32_t hintKey, const uint32_t vanillaItem, std::vector&& categories, SpoilerCollectionCheck collectionCheck = SpoilerCollectionCheck(), SpoilerCollectionCheckGroup collectionCheckGroup = SpoilerCollectionCheckGroup::GROUP_NO_GROUP) { + return ItemLocation{scene, ItemLocationType::TempleReward, flag, std::move(name), hintKey, vanillaItem, std::move(categories), 0, collectionCheck, collectionCheckGroup}; + } + + static auto OtherHint(uint8_t scene, uint8_t flag, std::string&& name, std::vector&& categories) { + return ItemLocation{scene, ItemLocationType::OtherHint, flag, std::move(name), NONE, NONE, std::move(categories)}; + } + + static auto HintStone(uint8_t scene, uint8_t flag, std::string&& name, std::vector&& categories) { + return ItemLocation{scene, ItemLocationType::HintStone, flag, std::move(name), NONE, NONE, std::move(categories)}; + } + + void ResetVariables() { + checked = false; + addedToPool = false; + placedItem = NONE; + delayedItem = NONE; + hintedAt = false; + isHintable = false; + price = 0; + hasShopsanityPrice = false; + hidden = false; + } + +private: + uint8_t scene; + ItemLocationType type; + uint8_t flag; + bool checked = false; + + std::string name; + uint32_t hintKey = NONE; + uint32_t vanillaItem = NONE; + bool hintedAt = false; + std::vector categories; + bool addedToPool = false; + uint32_t placedItem = NONE; + uint32_t delayedItem = NONE; + Option excludedOption = Option::Bool(name, {"Include", "Exclude"}, {"", ""}); + uint16_t price = 0; + SpoilerCollectionCheck collectionCheck; + SpoilerCollectionCheckGroup collectionCheckGroup; + bool isHintable = false; + uint32_t parentRegion = NONE; + bool hasShopsanityPrice = false; + bool hidden = false; +}; + +class ItemOverride_Compare { +public: + bool operator()(ItemOverride lhs, ItemOverride rhs) const { + return lhs.key.all < rhs.key.all; + } +}; + +void LocationTable_Init(); + +ItemLocation* Location(uint32_t locKey); + +extern std::vector> ShopLocationLists; + +extern std::vector gossipStoneLocations; + +extern std::vector dungeonRewardLocations; +extern std::vector overworldLocations; +extern std::vector allLocations; +extern std::vector everyPossibleLocation; + +//set of overrides to write to the patch +extern std::set overrides; + +extern std::vector> playthroughLocations; +extern std::vector wothLocations; +extern bool playthroughBeatable; +extern bool allLocationsReachable; +extern bool showItemProgress; + +extern uint16_t itemsPlaced; + +void GenerateLocationPool(); +void PlaceItemInLocation(uint32_t loc, uint32_t item, bool applyEffectImmediately = false, bool setHidden = false); +std::vector GetLocations(const std::vector& locationPool, Category categoryInclude, + Category categoryExclude = Category::cNull); +void LocationReset(); +void ItemReset(); +void HintReset(); +void AddExcludedOptions(); +void CreateItemOverrides(); diff --git a/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp new file mode 100644 index 000000000..b46ad395f --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/item_pool.cpp @@ -0,0 +1,1179 @@ +#include "item_pool.hpp" + +#include "dungeon.hpp" +#include "fill.hpp" +#include "item_list.hpp" +#include "item_location.hpp" +#include "pool_functions.hpp" +#include "random.hpp" +#include "settings.hpp" +#include "spoiler_log.hpp" +#include "z64item.h" +#include + + +using namespace Settings; +using namespace Dungeon; + +std::vector ItemPool = {}; +std::vector PendingJunkPool = {}; +std::vector IceTrapModels = {}; +const std::array dungeonRewards = { + KOKIRI_EMERALD, + GORON_RUBY, + ZORA_SAPPHIRE, + FOREST_MEDALLION, + FIRE_MEDALLION, + WATER_MEDALLION, + SPIRIT_MEDALLION, + SHADOW_MEDALLION, + LIGHT_MEDALLION, +}; +const std::array JunkPoolItems = { + BOMBS_5, + BOMBS_10, + BOMBS_20, + DEKU_NUTS_5, + DEKU_STICK_1, + DEKU_SEEDS_30, + RECOVERY_HEART, + ARROWS_5, + ARROWS_10, + ARROWS_30, + BLUE_RUPEE, + RED_RUPEE, + PURPLE_RUPEE, + HUGE_RUPEE, + DEKU_NUTS_10, + ICE_TRAP, +}; +const std::array alwaysItems = { + BIGGORON_SWORD, + BOOMERANG, + LENS_OF_TRUTH, + MEGATON_HAMMER, + IRON_BOOTS, + GORON_TUNIC, + ZORA_TUNIC, + HOVER_BOOTS, + MIRROR_SHIELD, + STONE_OF_AGONY, + FIRE_ARROWS, + ICE_ARROWS, + LIGHT_ARROWS, + DINS_FIRE, + FARORES_WIND, + NAYRUS_LOVE, + GREEN_RUPEE, + PROGRESSIVE_HOOKSHOT, //2 progressive hookshots + PROGRESSIVE_HOOKSHOT, + DEKU_SHIELD, + HYLIAN_SHIELD, + PROGRESSIVE_STRENGTH, //3 progressive strength upgrades + PROGRESSIVE_STRENGTH, + PROGRESSIVE_STRENGTH, + PROGRESSIVE_SCALE, //2 progressive scales + PROGRESSIVE_SCALE, + PROGRESSIVE_BOW, //3 progressive Bows + PROGRESSIVE_BOW, + PROGRESSIVE_BOW, + PROGRESSIVE_SLINGSHOT, //3 progressive bullet bags + PROGRESSIVE_SLINGSHOT, + PROGRESSIVE_SLINGSHOT, + PROGRESSIVE_BOMB_BAG, //3 progressive bomb bags + PROGRESSIVE_BOMB_BAG, + PROGRESSIVE_BOMB_BAG, + PROGRESSIVE_WALLET, //2 progressive wallets + PROGRESSIVE_WALLET, + PROGRESSIVE_MAGIC_METER, //2 progressive magic meters + PROGRESSIVE_MAGIC_METER, + DOUBLE_DEFENSE, + PROGRESSIVE_STICK_UPGRADE, //2 stick upgrades + PROGRESSIVE_STICK_UPGRADE, + PROGRESSIVE_NUT_UPGRADE, //2 nut upgrades + PROGRESSIVE_NUT_UPGRADE, + RECOVERY_HEART, //6 recovery hearts + RECOVERY_HEART, + RECOVERY_HEART, + RECOVERY_HEART, + RECOVERY_HEART, + RECOVERY_HEART, + BOMBS_5, //2 + BOMBS_5, + BOMBS_10, + BOMBS_20, + ARROWS_5, + ARROWS_10, //5 + ARROWS_10, + ARROWS_10, + TREASURE_GAME_HEART, +}; +const std::array easyItems = { + BIGGORON_SWORD, + KOKIRI_SWORD, + BOOMERANG, + LENS_OF_TRUTH, + MEGATON_HAMMER, + IRON_BOOTS, + GORON_TUNIC, + ZORA_TUNIC, + HOVER_BOOTS, + MIRROR_SHIELD, + FIRE_ARROWS, + LIGHT_ARROWS, + DINS_FIRE, + PROGRESSIVE_HOOKSHOT, + PROGRESSIVE_STRENGTH, + PROGRESSIVE_SCALE, + PROGRESSIVE_WALLET, + PROGRESSIVE_MAGIC_METER, + PROGRESSIVE_STICK_UPGRADE, + PROGRESSIVE_NUT_UPGRADE, + PROGRESSIVE_BOW, + PROGRESSIVE_SLINGSHOT, + PROGRESSIVE_BOMB_BAG, + DOUBLE_DEFENSE, + HEART_CONTAINER, //16 Heart Containers + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + PIECE_OF_HEART, //3 heart pieces + PIECE_OF_HEART, + PIECE_OF_HEART, +}; +const std::array normalItems = { + PIECE_OF_HEART, //35 pieces of heart + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + PIECE_OF_HEART, + HEART_CONTAINER, //8 heart containers + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, + HEART_CONTAINER, +}; +const std::array DT_Vanilla = { + RECOVERY_HEART, + RECOVERY_HEART, +}; +const std::array DT_MQ = { + DEKU_SHIELD, + DEKU_SHIELD, + PURPLE_RUPEE, +}; +const std::array DC_Vanilla = { + RED_RUPEE, +}; +const std::array DC_MQ = { + HYLIAN_SHIELD, + BLUE_RUPEE, +}; +const std::array JB_MQ = { + DEKU_NUTS_5, + DEKU_NUTS_5, + DEKU_NUTS_5, + DEKU_NUTS_5, + RECOVERY_HEART, + DEKU_SHIELD, + DEKU_STICK_1, +}; +const std::array FoT_Vanilla = { + RECOVERY_HEART, + ARROWS_10, + ARROWS_30, +}; +const std::array FoT_MQ = { + ARROWS_5, +}; +const std::array FiT_Vanilla = { + HUGE_RUPEE, +}; +const std::array FiT_MQ = { + BOMBS_20, + HYLIAN_SHIELD, +}; +const std::array SpT_Vanilla = { + DEKU_SHIELD, + DEKU_SHIELD, + RECOVERY_HEART, + BOMBS_20, +}; +const std::array SpT_MQ = { + PURPLE_RUPEE, + PURPLE_RUPEE, + ARROWS_30, +}; +const std::array ShT_Vanilla = { + ARROWS_30, +}; +const std::array ShT_MQ = { + ARROWS_5, + ARROWS_5, + RED_RUPEE, +}; +const std::array BW_Vanilla = { + RECOVERY_HEART, + BOMBS_10, + HUGE_RUPEE, + DEKU_NUTS_5, + DEKU_NUTS_10, + DEKU_SHIELD, + HYLIAN_SHIELD, +}; +const std::array GTG_Vanilla = { + ARROWS_30, + ARROWS_30, + ARROWS_30, + HUGE_RUPEE, +}; +const std::array GTG_MQ = { + TREASURE_GAME_GREEN_RUPEE, + TREASURE_GAME_GREEN_RUPEE, + ARROWS_10, + GREEN_RUPEE, + PURPLE_RUPEE, +}; +const std::array GC_Vanilla = { + BLUE_RUPEE, + BLUE_RUPEE, + BLUE_RUPEE, + ARROWS_30, +}; +const std::array GC_MQ = { + ARROWS_10, + ARROWS_10, + BOMBS_5, + RED_RUPEE, + RECOVERY_HEART, +}; +const std::array normalBottles = { + EMPTY_BOTTLE, + BOTTLE_WITH_MILK, + BOTTLE_WITH_RED_POTION, + BOTTLE_WITH_GREEN_POTION, + BOTTLE_WITH_BLUE_POTION, + BOTTLE_WITH_FAIRY, + BOTTLE_WITH_FISH, + BOTTLE_WITH_BUGS, + BOTTLE_WITH_POE, + BOTTLE_WITH_BIG_POE, + BOTTLE_WITH_BLUE_FIRE, +}; +const std::array normalRupees = { + BLUE_RUPEE, + BLUE_RUPEE, + BLUE_RUPEE, + BLUE_RUPEE, + BLUE_RUPEE, + BLUE_RUPEE, + BLUE_RUPEE, + BLUE_RUPEE, + BLUE_RUPEE, + BLUE_RUPEE, + BLUE_RUPEE, + BLUE_RUPEE, + BLUE_RUPEE, + RED_RUPEE, + RED_RUPEE, + RED_RUPEE, + RED_RUPEE, + RED_RUPEE, + PURPLE_RUPEE, + PURPLE_RUPEE, + PURPLE_RUPEE, + PURPLE_RUPEE, + PURPLE_RUPEE, + PURPLE_RUPEE, + PURPLE_RUPEE, + HUGE_RUPEE, + HUGE_RUPEE, + HUGE_RUPEE, +}; +const std::array shopsanityRupees = { + BLUE_RUPEE, + BLUE_RUPEE, + RED_RUPEE, + RED_RUPEE, + RED_RUPEE, + RED_RUPEE, + RED_RUPEE, + RED_RUPEE, + RED_RUPEE, + RED_RUPEE, + RED_RUPEE, + RED_RUPEE, + PURPLE_RUPEE, + PURPLE_RUPEE, + PURPLE_RUPEE, + PURPLE_RUPEE, + PURPLE_RUPEE, + PURPLE_RUPEE, + PURPLE_RUPEE, + PURPLE_RUPEE, + PURPLE_RUPEE, + PURPLE_RUPEE, + HUGE_RUPEE, + HUGE_RUPEE, + HUGE_RUPEE, + HUGE_RUPEE, + HUGE_RUPEE, + PROGRESSIVE_WALLET, +}; +const std::array dekuScrubItems = { + DEKU_NUTS_5, + DEKU_NUTS_5, + DEKU_NUTS_5, + DEKU_NUTS_5, + DEKU_NUTS_5, + DEKU_STICK_1, + BOMBS_5, + BOMBS_5, + BOMBS_5, + BOMBS_5, + BOMBS_5, + RECOVERY_HEART, + RECOVERY_HEART, + RECOVERY_HEART, + RECOVERY_HEART, + BLUE_RUPEE, + BLUE_RUPEE, + BLUE_RUPEE, + BLUE_RUPEE, +}; +const std::array songList = { + ZELDAS_LULLABY, + EPONAS_SONG, + SUNS_SONG, + SARIAS_SONG, + SONG_OF_TIME, + SONG_OF_STORMS, + MINUET_OF_FOREST, + PRELUDE_OF_LIGHT, + BOLERO_OF_FIRE, + SERENADE_OF_WATER, + NOCTURNE_OF_SHADOW, + REQUIEM_OF_SPIRIT, +}; +const std::array tradeItems = { + POCKET_EGG, + //POCKET_CUCCO, + COJIRO, + ODD_MUSHROOM, + POACHERS_SAW, + BROKEN_SWORD, + PRESCRIPTION, + EYEBALL_FROG, + EYEDROPS, + CLAIM_CHECK, +}; + +void AddItemToPool(std::vector& pool, uint32_t item, size_t count /*= 1*/) { + pool.insert(pool.end(), count, item); +} + +template +static void AddItemsToPool(std::vector& toPool, const FromPool& fromPool) { + AddElementsToPool(toPool, fromPool); +} + +static void AddItemToMainPool(const uint32_t item, size_t count = 1) { + ItemPool.insert(ItemPool.end(), count, item); +} + +static void AddRandomBottle(std::vector& bottlePool) { + AddItemToMainPool(RandomElement(bottlePool, true)); +} + +uint32_t GetJunkItem() { + if (IceTrapValue.Is(ICETRAPS_MAYHEM) || IceTrapValue.Is(ICETRAPS_ONSLAUGHT)) { + return ICE_TRAP; + } else if (IceTrapValue.Is(ICETRAPS_EXTRA)) { + return RandomElement(JunkPoolItems); + } + //Ice Trap is the last item in JunkPoolItems, so subtract 1 to never hit that index + uint8_t idx = Random(0, JunkPoolItems.size() - 1); + return JunkPoolItems[idx]; +} + +static uint32_t GetPendingJunkItem() { + if (PendingJunkPool.empty()) { + return GetJunkItem(); + } + + return RandomElement(PendingJunkPool, true); +} + +//Replace junk items in the pool with pending junk +static void ReplaceMaxItem(const uint32_t itemToReplace, int max) { + int itemCount = 0; + for (size_t i = 0; i < ItemPool.size(); i++) { + if (ItemPool[i] == itemToReplace) { + if (itemCount >= max) { + ItemPool[i] = GetJunkItem(); + } + itemCount++; + } + } +} + +void PlaceJunkInExcludedLocation(const uint32_t il) { + //place a non-advancement item in this location + for (size_t i = 0; i < ItemPool.size(); i++) { + if (!ItemTable(ItemPool[i]).IsAdvancement()) { + PlaceItemInLocation(il, ItemPool[i]); + ItemPool.erase(ItemPool.begin() + i); + return; + } + } + printf("ERROR: No Junk to Place!!!\n"); +} + +static void PlaceVanillaDekuScrubItems() { + PlaceItemInLocation(ZR_DEKU_SCRUB_GROTTO_REAR, RED_POTION_REFILL, false, true); + PlaceItemInLocation(ZR_DEKU_SCRUB_GROTTO_FRONT, GREEN_POTION_REFILL, false, true); + PlaceItemInLocation(SFM_DEKU_SCRUB_GROTTO_REAR, RED_POTION_REFILL, false, true); + PlaceItemInLocation(SFM_DEKU_SCRUB_GROTTO_FRONT, GREEN_POTION_REFILL, false, true); + PlaceItemInLocation(LH_DEKU_SCRUB_GROTTO_LEFT, DEKU_NUTS_5, false, true); + PlaceItemInLocation(LH_DEKU_SCRUB_GROTTO_RIGHT, BOMBS_5, false, true); + PlaceItemInLocation(LH_DEKU_SCRUB_GROTTO_CENTER, DEKU_SEEDS_30, false, true); + PlaceItemInLocation(GV_DEKU_SCRUB_GROTTO_REAR, RED_POTION_REFILL, false, true); + PlaceItemInLocation(GV_DEKU_SCRUB_GROTTO_FRONT, GREEN_POTION_REFILL, false, true); + PlaceItemInLocation(LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT, DEKU_NUTS_5, false, true); + PlaceItemInLocation(LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, DEKU_STICK_1, false, true); + PlaceItemInLocation(LW_DEKU_SCRUB_GROTTO_REAR, DEKU_SEEDS_30, false, true); + PlaceItemInLocation(COLOSSUS_DEKU_SCRUB_GROTTO_REAR, RED_POTION_REFILL, false, true); + PlaceItemInLocation(COLOSSUS_DEKU_SCRUB_GROTTO_FRONT, GREEN_POTION_REFILL, false, true); + PlaceItemInLocation(DMC_DEKU_SCRUB, BOMBS_5, false, true); + PlaceItemInLocation(DMC_DEKU_SCRUB_GROTTO_LEFT, DEKU_NUTS_5, false, true); + PlaceItemInLocation(DMC_DEKU_SCRUB_GROTTO_RIGHT, BOMBS_5, false, true); + PlaceItemInLocation(DMC_DEKU_SCRUB_GROTTO_CENTER, DEKU_SEEDS_30, false, true); + PlaceItemInLocation(GC_DEKU_SCRUB_GROTTO_LEFT, DEKU_NUTS_5, false, true); + PlaceItemInLocation(GC_DEKU_SCRUB_GROTTO_RIGHT, BOMBS_5, false, true); + PlaceItemInLocation(GC_DEKU_SCRUB_GROTTO_CENTER, DEKU_SEEDS_30, false, true); + PlaceItemInLocation(LLR_DEKU_SCRUB_GROTTO_LEFT, DEKU_NUTS_5, false, true); + PlaceItemInLocation(LLR_DEKU_SCRUB_GROTTO_RIGHT, BOMBS_5, false, true); + PlaceItemInLocation(LLR_DEKU_SCRUB_GROTTO_CENTER, DEKU_SEEDS_30, false, true); + + //Dungeon Scrubs + if (DekuTree.IsMQ()) { + PlaceItemInLocation(DEKU_TREE_MQ_DEKU_SCRUB, DEKU_SHIELD, false, true); + } + if (DodongosCavern.IsMQ()) { + PlaceItemInLocation(DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR, DEKU_STICK_1, false, true); + PlaceItemInLocation(DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT, DEKU_SEEDS_30, false, true); + PlaceItemInLocation(DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE, DEKU_SHIELD, false, true); + PlaceItemInLocation(DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS, RED_POTION_REFILL, false, true); + } else { + PlaceItemInLocation(DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT, DEKU_NUTS_5, false, true); + PlaceItemInLocation(DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS, DEKU_STICK_1, false, true); + PlaceItemInLocation(DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT, DEKU_SEEDS_30, false, true); + PlaceItemInLocation(DODONGOS_CAVERN_DEKU_SCRUB_LOBBY, DEKU_SHIELD, false, true); + } + if (JabuJabusBelly.IsVanilla()) { + PlaceItemInLocation(JABU_JABUS_BELLY_DEKU_SCRUB, DEKU_NUTS_5); + } + if (GanonsCastle.IsMQ()) { + PlaceItemInLocation(GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT, GREEN_POTION_REFILL, false, true); + PlaceItemInLocation(GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT, BOMBS_5, false, true); + PlaceItemInLocation(GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER, ARROWS_30, false, true); + PlaceItemInLocation(GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT, RED_POTION_REFILL, false, true); + PlaceItemInLocation(GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT, DEKU_NUTS_5, false, true); + } else { + PlaceItemInLocation(GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT, BOMBS_5, false, true); + PlaceItemInLocation(GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT, DEKU_SEEDS_30, false, true); + PlaceItemInLocation(GANONS_CASTLE_DEKU_SCRUB_RIGHT, RED_POTION_REFILL, false, true); + PlaceItemInLocation(GANONS_CASTLE_DEKU_SCRUB_LEFT, GREEN_POTION_REFILL, false, true); + } + + +} + +static void PlaceVanillaMapsAndCompasses() { + for (auto dungeon : dungeonList) { + dungeon->PlaceVanillaMap(); + dungeon->PlaceVanillaCompass(); + } +} + +static void PlaceVanillaSmallKeys() { + for (auto dungeon : dungeonList) { + dungeon->PlaceVanillaSmallKeys(); + } +} + +static void PlaceVanillaBossKeys() { + for (auto dungeon : dungeonList) { + dungeon->PlaceVanillaBossKey(); + } +} + +static void PlaceVanillaCowMilk() { + PlaceItemInLocation(KF_LINKS_HOUSE_COW, MILK, false, true); + PlaceItemInLocation(HF_COW_GROTTO_COW, MILK, false, true); + PlaceItemInLocation(GV_COW, MILK, false, true); + PlaceItemInLocation(KAK_IMPAS_HOUSE_COW, MILK, false, true); + PlaceItemInLocation(DMT_COW_GROTTO_COW, MILK, false, true); + PlaceItemInLocation(LLR_STABLES_LEFT_COW, MILK, false, true); + PlaceItemInLocation(LLR_STABLES_RIGHT_COW, MILK, false, true); + PlaceItemInLocation(LLR_TOWER_LEFT_COW, MILK, false, true); + PlaceItemInLocation(LLR_TOWER_RIGHT_COW, MILK, false, true); + + if (JabuJabusBelly.IsMQ()) { + PlaceItemInLocation(JABU_JABUS_BELLY_MQ_COW, MILK, false, true); + } +} + +static void SetScarceItemPool() { + ReplaceMaxItem(PROGRESSIVE_BOMBCHUS, 3); + ReplaceMaxItem(BOMBCHU_5, 1); + ReplaceMaxItem(BOMBCHU_10, 2); + ReplaceMaxItem(BOMBCHU_20, 0); + ReplaceMaxItem(PROGRESSIVE_MAGIC_METER, 1); + ReplaceMaxItem(DOUBLE_DEFENSE, 0); + ReplaceMaxItem(PROGRESSIVE_STICK_UPGRADE, 1); + ReplaceMaxItem(PROGRESSIVE_NUT_UPGRADE, 1); + ReplaceMaxItem(PROGRESSIVE_BOW, 2); + ReplaceMaxItem(PROGRESSIVE_SLINGSHOT, 2); + ReplaceMaxItem(PROGRESSIVE_BOMB_BAG, 2); + ReplaceMaxItem(HEART_CONTAINER, 0); +} + +static void SetMinimalItemPool() { + ReplaceMaxItem(PROGRESSIVE_BOMBCHUS, 1); + ReplaceMaxItem(BOMBCHU_5, 1); + ReplaceMaxItem(BOMBCHU_10, 0); + ReplaceMaxItem(BOMBCHU_20, 0); + ReplaceMaxItem(NAYRUS_LOVE, 0); + ReplaceMaxItem(PROGRESSIVE_MAGIC_METER, 1); + ReplaceMaxItem(DOUBLE_DEFENSE, 0); + ReplaceMaxItem(PROGRESSIVE_STICK_UPGRADE, 0); + ReplaceMaxItem(PROGRESSIVE_NUT_UPGRADE, 0); + ReplaceMaxItem(PROGRESSIVE_BOW, 1); + ReplaceMaxItem(PROGRESSIVE_SLINGSHOT, 1); + ReplaceMaxItem(PROGRESSIVE_BOMB_BAG, 1); + ReplaceMaxItem(PIECE_OF_HEART, 0); + // Need an extra heart container when starting with 1 heart to be able to reach 3 hearts + ReplaceMaxItem(HEART_CONTAINER, (StartingHearts.Value() == 18)? 1 : 0); +} + +void GenerateItemPool() { + + ItemPool.clear(); + PendingJunkPool.clear(); + + //Initialize ice trap models to always major items + IceTrapModels = { + GI_SHIELD_MIRROR, + GI_BOOMERANG, + GI_LENS, + GI_HAMMER, + GI_BOOTS_IRON, + GI_BOOTS_HOVER, + GI_STONE_OF_AGONY, + GI_DINS_FIRE, + GI_FARORES_WIND, + GI_NAYRUS_LOVE, + GI_ARROW_FIRE, + GI_ARROW_ICE, + GI_ARROW_LIGHT, + 0xB8, //Double defense + GI_CLAIM_CHECK, + 0x80, //Progressive hookshot + 0x81, //Progressive strength + 0x82, //Progressive bomb bag + 0x83, //Progressive bow + 0x84, //Progressive slingshot + 0x85, //Progressive wallet + 0x86, //Progressive scale + 0x8A, //Progressive magic + }; + //Check song shuffle and dungeon reward shuffle just for ice traps + if (ShuffleSongs.Is(SONGSHUFFLE_ANYWHERE)) { + //Push item ids for songs + IceTrapModels.push_back(0xC1); + IceTrapModels.push_back(0xC2); + IceTrapModels.push_back(0xC3); + IceTrapModels.push_back(0xC4); + IceTrapModels.push_back(0xC5); + IceTrapModels.push_back(0xC6); + IceTrapModels.push_back(0xBB); + IceTrapModels.push_back(0xBC); + IceTrapModels.push_back(0xBD); + IceTrapModels.push_back(0xBE); + IceTrapModels.push_back(0xBF); + IceTrapModels.push_back(0xC0); + } + if (ShuffleRewards.Is(REWARDSHUFFLE_ANYWHERE)) { + //Push item ids for dungeon rewards + IceTrapModels.push_back(0xCB); + IceTrapModels.push_back(0xCC); + IceTrapModels.push_back(0xCD); + IceTrapModels.push_back(0xCE); + IceTrapModels.push_back(0xCF); + IceTrapModels.push_back(0xD0); + IceTrapModels.push_back(0xD1); + IceTrapModels.push_back(0xD2); + IceTrapModels.push_back(0xD3); + } + + //Fixed item locations + PlaceItemInLocation(HC_ZELDAS_LETTER, ZELDAS_LETTER); + PlaceItemInLocation(GANON, TRIFORCE); //The Triforce is only used to make sure Ganon is accessible + PlaceItemInLocation(MARKET_BOMBCHU_BOWLING_BOMBCHUS, BOMBCHU_DROP); + + if (ShuffleKokiriSword) { + AddItemToMainPool(KOKIRI_SWORD); + IceTrapModels.push_back(GI_SWORD_KOKIRI); + } else { + PlaceItemInLocation(KF_KOKIRI_SWORD_CHEST, KOKIRI_SWORD, false, true); + } + + if (ShuffleWeirdEgg) { + AddItemToMainPool(WEIRD_EGG); + IceTrapModels.push_back(GI_WEIRD_EGG); + } else { + PlaceItemInLocation(HC_MALON_EGG, WEIRD_EGG, false, true); + } + + if (ShuffleOcarinas) { + AddItemToMainPool(PROGRESSIVE_OCARINA, 2); + if (ItemPoolValue.Is(ITEMPOOL_PLENTIFUL)) { + AddItemToPool(PendingJunkPool, PROGRESSIVE_OCARINA); + } + IceTrapModels.push_back(0x8B); //Progressive ocarina + } else { + PlaceItemInLocation(LW_GIFT_FROM_SARIA, PROGRESSIVE_OCARINA, false, true); + PlaceItemInLocation(HF_OCARINA_OF_TIME_ITEM, PROGRESSIVE_OCARINA, false, true); + } + + if (ShuffleCows) { + //9 total cow locations + for (uint8_t i = 0; i < 9; i++) { + AddItemToMainPool(GetJunkItem()); + } + //extra location for Jabu MQ + if (JabuJabusBelly.IsMQ()) { + AddItemToMainPool(GetJunkItem()); + } + } else { + PlaceVanillaCowMilk(); + } + + if (ShuffleMagicBeans) { + AddItemToMainPool(MAGIC_BEAN_PACK); + if (ItemPoolValue.Is(ITEMPOOL_PLENTIFUL)) { + AddItemToPool(PendingJunkPool, MAGIC_BEAN_PACK); + } + IceTrapModels.push_back(0xC9); //Magic bean pack + } else { + PlaceItemInLocation(ZR_MAGIC_BEAN_SALESMAN, MAGIC_BEAN, false, true); + } + + if (ShuffleMerchants.IsNot(SHUFFLEMERCHANTS_OFF)) { + if (!ProgressiveGoronSword) { + AddItemToMainPool(GIANTS_KNIFE); + } + if (BombchusInLogic) { + AddItemToMainPool(PROGRESSIVE_BOMBCHUS); + } else { + AddItemToMainPool(BOMBCHU_10); + } + } else { + PlaceItemInLocation(GC_MEDIGORON, GIANTS_KNIFE, false, true); + PlaceItemInLocation(WASTELAND_BOMBCHU_SALESMAN, BOMBCHU_10, false, true); + } + + if (ShuffleAdultTradeQuest) { + AddItemToMainPool(POCKET_EGG); + AddItemToMainPool(COJIRO); + AddItemToMainPool(ODD_MUSHROOM); + AddItemToMainPool(ODD_POTION); + AddItemToMainPool(POACHERS_SAW); + AddItemToMainPool(BROKEN_SWORD); + AddItemToMainPool(PRESCRIPTION); + AddItemToMainPool(EYEBALL_FROG); + AddItemToMainPool(EYEDROPS); + } else { + PlaceItemInLocation(KAK_TRADE_POCKET_CUCCO, COJIRO, false, true); + PlaceItemInLocation(LW_TRADE_COJIRO, ODD_MUSHROOM, false, true); + PlaceItemInLocation(KAK_TRADE_ODD_MUSHROOM, ODD_POTION, false, true); + PlaceItemInLocation(LW_TRADE_ODD_POTION, POACHERS_SAW, false, true); + PlaceItemInLocation(GV_TRADE_SAW, BROKEN_SWORD, false, true); + PlaceItemInLocation(DMT_TRADE_BROKEN_SWORD, PRESCRIPTION, false, true); + PlaceItemInLocation(ZD_TRADE_PRESCRIPTION, EYEBALL_FROG, false, true); + PlaceItemInLocation(LH_TRADE_FROG, EYEDROPS, false, true); + PlaceItemInLocation(DMT_TRADE_EYEDROPS, CLAIM_CHECK, false, true); + } + AddItemToMainPool(CLAIM_CHECK); + + if (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_SINGLE_KEYS)) { + AddItemToMainPool(TREASURE_GAME_SMALL_KEY, 6); // 6 individual keys + } else if (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_PACK)) { + AddItemToMainPool(TREASURE_GAME_SMALL_KEY); // 1 key which will behave as a pack of 6 + } else { + PlaceItemInLocation(MARKET_TREASURE_CHEST_GAME_ITEM_1, TREASURE_GAME_SMALL_KEY, false, true); + PlaceItemInLocation(MARKET_TREASURE_CHEST_GAME_ITEM_2, TREASURE_GAME_SMALL_KEY, false, true); + PlaceItemInLocation(MARKET_TREASURE_CHEST_GAME_ITEM_3, TREASURE_GAME_SMALL_KEY, false, true); + PlaceItemInLocation(MARKET_TREASURE_CHEST_GAME_ITEM_4, TREASURE_GAME_SMALL_KEY, false, true); + PlaceItemInLocation(MARKET_TREASURE_CHEST_GAME_ITEM_5, TREASURE_GAME_SMALL_KEY, false, true); + }; + + if (Tokensanity.Is(TOKENSANITY_OFF)) { + for (uint32_t loc : GetLocations(allLocations, Category::cSkulltula)) { + PlaceItemInLocation(loc, GOLD_SKULLTULA_TOKEN, false, true); + } + } else if (Tokensanity.Is(TOKENSANITY_DUNGEONS)) { + for (uint32_t loc : GetLocations(allLocations, Category::cSkulltula)) { + if (Location(loc)->IsOverworld()) { + PlaceItemInLocation(loc, GOLD_SKULLTULA_TOKEN, false, true); + } else { + AddItemToMainPool(GOLD_SKULLTULA_TOKEN); + } + } + } else if (Tokensanity.Is(TOKENSANITY_OVERWORLD)) { + for (uint32_t loc : GetLocations(allLocations, Category::cSkulltula)) { + if (Location(loc)->IsDungeon()) { + PlaceItemInLocation(loc, GOLD_SKULLTULA_TOKEN, false, true); + } else { + AddItemToMainPool(GOLD_SKULLTULA_TOKEN); + } + } + } else { + AddItemToMainPool(GOLD_SKULLTULA_TOKEN, 100); + } + + if (BombchusInLogic) { + AddItemToMainPool(PROGRESSIVE_BOMBCHUS, 5); + } else { + AddItemToMainPool(BOMBCHU_5); + AddItemToMainPool(BOMBCHU_10, 3); + AddItemToMainPool(BOMBCHU_20); + } + + //Ice Traps + AddItemToMainPool(ICE_TRAP); + if (GerudoTrainingGrounds.IsVanilla()) { + AddItemToMainPool(ICE_TRAP); + } + if (GanonsCastle.IsVanilla()) { + AddItemToMainPool(ICE_TRAP, 4); + } + + //Gerudo Fortress + if (GerudoFortress.Is(GERUDOFORTRESS_OPEN)) { + PlaceItemInLocation(GF_NORTH_F1_CARPENTER, RECOVERY_HEART, false, true); + PlaceItemInLocation(GF_NORTH_F2_CARPENTER, RECOVERY_HEART, false, true); + PlaceItemInLocation(GF_SOUTH_F1_CARPENTER, RECOVERY_HEART, false, true); + PlaceItemInLocation(GF_SOUTH_F2_CARPENTER, RECOVERY_HEART, false, true); + } else if (GerudoKeys.IsNot(GERUDOKEYS_VANILLA)) { + if (GerudoFortress.Is(GERUDOFORTRESS_FAST)) { + AddItemToMainPool(GERUDO_FORTRESS_SMALL_KEY); + PlaceItemInLocation(GF_NORTH_F2_CARPENTER, RECOVERY_HEART, false, true); + PlaceItemInLocation(GF_SOUTH_F1_CARPENTER, RECOVERY_HEART, false, true); + PlaceItemInLocation(GF_SOUTH_F2_CARPENTER, RECOVERY_HEART, false, true); + } else { + //Only add key ring if 4 Fortress keys necessary + if (RingFortress) { + AddItemToMainPool(GERUDO_FORTRESS_KEY_RING); + //Add junk to make up for missing keys + for (uint8_t i = 0; i < 3; i++) { + AddItemToMainPool(GetJunkItem()); + } + } else { + AddItemToMainPool(GERUDO_FORTRESS_SMALL_KEY, 4); + } + } + if (ItemPoolValue.Is(ITEMPOOL_PLENTIFUL)) { + if (RingFortress && GerudoFortress.Is(GERUDOFORTRESS_NORMAL)) { + AddItemToPool(PendingJunkPool, GERUDO_FORTRESS_KEY_RING); + } else { + AddItemToPool(PendingJunkPool, GERUDO_FORTRESS_SMALL_KEY); + } + } + } else { + if (GerudoFortress.Is(GERUDOFORTRESS_FAST)) { + PlaceItemInLocation(GF_NORTH_F1_CARPENTER, GERUDO_FORTRESS_SMALL_KEY, false, true); + PlaceItemInLocation(GF_NORTH_F2_CARPENTER, RECOVERY_HEART, false, true); + PlaceItemInLocation(GF_SOUTH_F1_CARPENTER, RECOVERY_HEART, false, true); + PlaceItemInLocation(GF_SOUTH_F2_CARPENTER, RECOVERY_HEART, false, true); + } else { + PlaceItemInLocation(GF_NORTH_F1_CARPENTER, GERUDO_FORTRESS_SMALL_KEY, false, true); + PlaceItemInLocation(GF_NORTH_F2_CARPENTER, GERUDO_FORTRESS_SMALL_KEY, false, true); + PlaceItemInLocation(GF_SOUTH_F1_CARPENTER, GERUDO_FORTRESS_SMALL_KEY, false, true); + PlaceItemInLocation(GF_SOUTH_F2_CARPENTER, GERUDO_FORTRESS_SMALL_KEY, false, true); + } + } + + //Gerudo Membership Card + if (ShuffleGerudoToken && GerudoFortress.IsNot(GERUDOFORTRESS_OPEN)) { + AddItemToMainPool(GERUDO_MEMBERSHIP_CARD); + IceTrapModels.push_back(GI_GERUDO_CARD); + } else if (ShuffleGerudoToken) { + AddItemToPool(PendingJunkPool, GERUDO_MEMBERSHIP_CARD); + PlaceItemInLocation(GF_GERUDO_MEMBERSHIP_CARD, ICE_TRAP, false, true); + } else { + PlaceItemInLocation(GF_GERUDO_MEMBERSHIP_CARD, GERUDO_MEMBERSHIP_CARD, false, true); + } + + //Keys + + //For key rings, need to add as many junk items as "missing" keys + if (KeyRings) { + uint8_t ringJunkAmt = 0; + for (auto dungeon : dungeonList) { + if (dungeon->HasKeyRing()) { + ringJunkAmt += dungeon->GetSmallKeyCount() - 1; + } + } + for (uint8_t i = 0; i < ringJunkAmt; i++) { + AddItemToMainPool(GetJunkItem()); + } + } + + if (ItemPoolValue.Is(ITEMPOOL_PLENTIFUL)) { + if (ShuffleGerudoToken) { + AddItemToPool(PendingJunkPool, GERUDO_MEMBERSHIP_CARD); + } + + //Plentiful small keys + if (Keysanity.Is(KEYSANITY_ANYWHERE) || Keysanity.Is(KEYSANITY_ANY_DUNGEON) || Keysanity.Is(KEYSANITY_OVERWORLD)) { + if (BottomOfTheWell.HasKeyRing()) { + AddItemToPool(PendingJunkPool, BOTTOM_OF_THE_WELL_KEY_RING); + } else { + AddItemToPool(PendingJunkPool, BOTTOM_OF_THE_WELL_SMALL_KEY); + } + if (ForestTemple.HasKeyRing()) { + AddItemToPool(PendingJunkPool, FOREST_TEMPLE_KEY_RING); + } else { + AddItemToPool(PendingJunkPool, FOREST_TEMPLE_SMALL_KEY); + } + if (FireTemple.HasKeyRing()) { + AddItemToPool(PendingJunkPool, FIRE_TEMPLE_KEY_RING); + } else { + AddItemToPool(PendingJunkPool, FIRE_TEMPLE_SMALL_KEY); + } + if (WaterTemple.HasKeyRing()) { + AddItemToPool(PendingJunkPool, WATER_TEMPLE_KEY_RING); + } else { + AddItemToPool(PendingJunkPool, WATER_TEMPLE_SMALL_KEY); + } + if (SpiritTemple.HasKeyRing()) { + AddItemToPool(PendingJunkPool, SPIRIT_TEMPLE_KEY_RING); + } else { + AddItemToPool(PendingJunkPool, SPIRIT_TEMPLE_SMALL_KEY); + } + if (ShadowTemple.HasKeyRing()) { + AddItemToPool(PendingJunkPool, SHADOW_TEMPLE_KEY_RING); + } else { + AddItemToPool(PendingJunkPool, SHADOW_TEMPLE_SMALL_KEY); + } + if (GerudoTrainingGrounds.HasKeyRing()) { + AddItemToPool(PendingJunkPool, GERUDO_TRAINING_GROUNDS_KEY_RING); + } else { + AddItemToPool(PendingJunkPool, GERUDO_TRAINING_GROUNDS_SMALL_KEY); + } + if (GanonsCastle.HasKeyRing()) { + AddItemToPool(PendingJunkPool, GANONS_CASTLE_KEY_RING); + } else { + AddItemToPool(PendingJunkPool, GANONS_CASTLE_SMALL_KEY); + } + } + + if (BossKeysanity.Is(BOSSKEYSANITY_ANYWHERE) || BossKeysanity.Is(BOSSKEYSANITY_ANY_DUNGEON) || BossKeysanity.Is(BOSSKEYSANITY_OVERWORLD)) { + AddItemToPool(PendingJunkPool, FOREST_TEMPLE_BOSS_KEY); + AddItemToPool(PendingJunkPool, FIRE_TEMPLE_BOSS_KEY); + AddItemToPool(PendingJunkPool, WATER_TEMPLE_BOSS_KEY); + AddItemToPool(PendingJunkPool, SPIRIT_TEMPLE_BOSS_KEY); + AddItemToPool(PendingJunkPool, SHADOW_TEMPLE_BOSS_KEY); + } + + if (GanonsBossKey.Is(GANONSBOSSKEY_ANYWHERE) || GanonsBossKey.Is(GANONSBOSSKEY_ANY_DUNGEON) || GanonsBossKey.Is(GANONSBOSSKEY_OVERWORLD)) { + AddItemToPool(PendingJunkPool, GANONS_CASTLE_BOSS_KEY); + } + } + + //Shopsanity + if (Settings::Shopsanity.Is(SHOPSANITY_OFF) || Settings::Shopsanity.Is(SHOPSANITY_ZERO)) { + AddItemsToPool(ItemPool, normalRupees); + } else { //Shopsanity 1-4, random + AddItemsToPool(ItemPool, shopsanityRupees); //Shopsanity gets extra large rupees + } + + //Scrubsanity + if (Settings::Scrubsanity.IsNot(SCRUBSANITY_OFF)) { + //Deku Tree + if (DekuTree.IsMQ()) { + AddItemToMainPool(DEKU_SHIELD); + } + + //Dodongos Cavern + AddItemToMainPool(DEKU_STICK_1); + AddItemToMainPool(DEKU_SHIELD); + if (DodongosCavern.IsMQ()) { + AddItemToMainPool(RECOVERY_HEART); + } else { + AddItemToMainPool(DEKU_NUTS_5); + } + + //Jabu Jabus Belly + if (JabuJabusBelly.IsVanilla()) { + AddItemToMainPool(DEKU_NUTS_5); + } + + //Ganons Castle + AddItemToMainPool(BOMBS_5); + AddItemToMainPool(RECOVERY_HEART); + AddItemToMainPool(BLUE_RUPEE); + if (GanonsCastle.IsMQ()) { + AddItemToMainPool(DEKU_NUTS_5); + } + + //Overworld Scrubs + AddItemsToPool(ItemPool, dekuScrubItems); + + //I'm not sure what this is for, but it was in ootr so I copied it + for (uint8_t i = 0; i < 7; i++) { + if (Random(0, 3)) { + AddItemToMainPool(ARROWS_30); + } else { + AddItemToMainPool(DEKU_SEEDS_30); + } + } + } else { + PlaceVanillaDekuScrubItems(); + } + + AddItemsToPool(ItemPool, alwaysItems); + AddItemsToPool(ItemPool, dungeonRewards); + + //Dungeon pools + if (DekuTree.IsMQ()) { + AddItemsToPool(ItemPool, DT_MQ); + } else { + AddItemsToPool(ItemPool, DT_Vanilla); + } + if (DodongosCavern.IsMQ()) { + AddItemsToPool(ItemPool, DC_MQ); + } else { + AddItemsToPool(ItemPool, DC_Vanilla); + } + if (JabuJabusBelly.IsMQ()) { + AddItemsToPool(ItemPool, JB_MQ); + } + if (ForestTemple.IsMQ()) { + AddItemsToPool(ItemPool, FoT_MQ); + } else { + AddItemsToPool(ItemPool, FoT_Vanilla); + } + if (FireTemple.IsMQ()) { + AddItemsToPool(ItemPool, FiT_MQ); + } else { + AddItemsToPool(ItemPool, FiT_Vanilla); + } + if (SpiritTemple.IsMQ()) { + AddItemsToPool(ItemPool, SpT_MQ); + } else { + AddItemsToPool(ItemPool, SpT_Vanilla); + } + if (ShadowTemple.IsMQ()) { + AddItemsToPool(ItemPool, ShT_MQ); + } else { + AddItemsToPool(ItemPool, ShT_Vanilla); + } + if (BottomOfTheWell.IsVanilla()) { + AddItemsToPool(ItemPool, BW_Vanilla); + } + if (GerudoTrainingGrounds.IsMQ()) { + AddItemsToPool(ItemPool, GTG_MQ); + } else { + AddItemsToPool(ItemPool, GTG_Vanilla); + } + if (GanonsCastle.IsMQ()) { + AddItemsToPool(ItemPool, GC_MQ); + } else { + AddItemsToPool(ItemPool, GC_Vanilla); + } + + uint8_t rutoBottles = 1; + if (ZorasFountain.Is(ZORASFOUNTAIN_OPEN)) { + rutoBottles = 0; + } + + //Add 4 total bottles + uint8_t bottleCount = 4; + std::vector bottles; + bottles.assign(normalBottles.begin(), normalBottles.end()); + IceTrapModels.push_back(ItemTable(RandomElement(bottles)).GetItemID()); //Get one random bottle type for ice traps + for (uint8_t i = 0; i < bottleCount; i++) { + if (i >= rutoBottles) { + AddRandomBottle(bottles); + } else { + AddItemToMainPool(RUTOS_LETTER); + } + } + + //add extra songs only if song shuffle is anywhere + AddItemsToPool(ItemPool, songList); + if (ShuffleSongs.Is(SONGSHUFFLE_ANYWHERE) && ItemPoolValue.Is(ITEMPOOL_PLENTIFUL)) { + AddItemsToPool(PendingJunkPool, songList); + } + + /*For item pool generation, dungeon items are either placed in their vanilla + | location, or added to the pool now and filtered out later depending on when + | they need to get placed or removed in fill.cpp. These items are kept in the + | pool until removal because the filling algorithm needs to know all of the + | advancement items that haven't been placed yet for placing higher priority + | items like stones/medallions.*/ + + if (MapsAndCompasses.Is(MAPSANDCOMPASSES_VANILLA)) { + PlaceVanillaMapsAndCompasses(); + } else { + for (auto dungeon : dungeonList) { + if (dungeon->GetMap() != NONE) { + AddItemToMainPool(dungeon->GetMap()); + } + + if (dungeon->GetCompass() != NONE) { + AddItemToMainPool(dungeon->GetCompass()); + } + } + } + + if (Keysanity.Is(KEYSANITY_VANILLA)) { + PlaceVanillaSmallKeys(); + } else { + for (auto dungeon : dungeonList) { + if (dungeon->HasKeyRing() && Keysanity.IsNot(KEYSANITY_START_WITH)) { + AddItemToMainPool(dungeon->GetKeyRing()); + } else { + if (dungeon->GetSmallKeyCount() > 0) { + AddItemToMainPool(dungeon->GetSmallKey(), dungeon->GetSmallKeyCount()); + } + } + } + } + + if (BossKeysanity.Is(BOSSKEYSANITY_VANILLA)) { + PlaceVanillaBossKeys(); + } else { + AddItemToMainPool(FOREST_TEMPLE_BOSS_KEY); + AddItemToMainPool(FIRE_TEMPLE_BOSS_KEY); + AddItemToMainPool(WATER_TEMPLE_BOSS_KEY); + AddItemToMainPool(SPIRIT_TEMPLE_BOSS_KEY); + AddItemToMainPool(SHADOW_TEMPLE_BOSS_KEY); + } + + if (GanonsBossKey.Value() >= GANONSBOSSKEY_LACS_VANILLA) { + PlaceItemInLocation(TOT_LIGHT_ARROWS_CUTSCENE, GANONS_CASTLE_BOSS_KEY); + } else if (GanonsBossKey.Is(GANONSBOSSKEY_VANILLA)) { + PlaceItemInLocation(GANONS_TOWER_BOSS_KEY_CHEST, GANONS_CASTLE_BOSS_KEY); + } else { + AddItemToMainPool(GANONS_CASTLE_BOSS_KEY); + } + + if (ItemPoolValue.Is(ITEMPOOL_PLENTIFUL)) { + AddItemsToPool(ItemPool, easyItems); + } else { + AddItemsToPool(ItemPool, normalItems); + } + + if (!ShuffleKokiriSword) { + ReplaceMaxItem(KOKIRI_SWORD, 0); + } + + if (ProgressiveGoronSword) { + ReplaceMaxItem(BIGGORON_SWORD, 0); + AddItemToMainPool(PROGRESSIVE_GORONSWORD, 2); + IceTrapModels.push_back(0xD4); // Progressive Goron Sword + } else { + IceTrapModels.push_back(GI_SWORD_BGS); + } + + //Replace ice traps with junk from the pending junk pool if necessary + if (IceTrapValue.Is(ICETRAPS_OFF)) { + ReplaceMaxItem(ICE_TRAP, 0); + } + //Replace all junk items with ice traps for onslaught mode + else if (IceTrapValue.Is(ICETRAPS_ONSLAUGHT)) { + for (uint8_t i = 0; i < JunkPoolItems.size() - 3; i++) { // -3 Omits Huge Rupees and Deku Nuts 10 + ReplaceMaxItem(JunkPoolItems[i], 0); + } + } + + if (ItemPoolValue.Is(ITEMPOOL_SCARCE)) { + SetScarceItemPool(); + } else if (ItemPoolValue.Is(ITEMPOOL_MINIMAL)) { + SetMinimalItemPool(); + } else if (RemoveDoubleDefense) { + ReplaceMaxItem(DOUBLE_DEFENSE, 0); + } + + //this feels ugly and there's probably a better way, but + //it replaces random junk with pending junk. + bool junkSet; + for (uint32_t pendingJunk : PendingJunkPool) { + junkSet = false; + for (uint32_t& item : ItemPool) { + for (uint32_t junk : JunkPoolItems) { + if (item == junk && item != HUGE_RUPEE && item != DEKU_NUTS_10) { + item = pendingJunk; + junkSet = true; + break; + } + } + if (junkSet) break; + } + } + PendingJunkPool.clear(); +} + +void AddJunk() { + SPDLOG_INFO("HAD TO PLACE EXTRA JUNK "); + AddItemToMainPool(GetPendingJunkItem()); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/item_pool.hpp b/soh/soh/Enhancements/randomizer/3drando/item_pool.hpp new file mode 100644 index 000000000..d71e4cb2f --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/item_pool.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "keys.hpp" + +#include +#include +#include + +class ItemLocation; + +void AddItemToPool(std::vector& pool, const uint32_t item, size_t count = 1); +uint32_t GetJunkItem(); +void PlaceJunkInExcludedLocation(const uint32_t il); +void GenerateItemPool(); +void AddJunk(); + +extern std::vector ItemPool; +extern std::vector IceTrapModels; diff --git a/soh/soh/Enhancements/randomizer/3drando/keys.hpp b/soh/soh/Enhancements/randomizer/3drando/keys.hpp new file mode 100644 index 000000000..3e8d8f5cd --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/keys.hpp @@ -0,0 +1,1682 @@ +#pragma once + +#include + +using AreaKey = uint32_t; + +typedef enum { + NONE, + KOKIRI_SWORD, + MASTER_SWORD, + GIANTS_KNIFE, + BIGGORON_SWORD, + DEKU_SHIELD, + HYLIAN_SHIELD, + MIRROR_SHIELD, + GORON_TUNIC, + ZORA_TUNIC, + IRON_BOOTS, + HOVER_BOOTS, + WEIRD_EGG, + ZELDAS_LETTER, + BOOMERANG, + LENS_OF_TRUTH, + MEGATON_HAMMER, + STONE_OF_AGONY, + DINS_FIRE, + FARORES_WIND, + NAYRUS_LOVE, + FIRE_ARROWS, + ICE_ARROWS, + LIGHT_ARROWS, + GERUDO_MEMBERSHIP_CARD, + MAGIC_BEAN, + MAGIC_BEAN_PACK, + DOUBLE_DEFENSE, + GOLD_SKULLTULA_TOKEN, + + POCKET_EGG, + POCKET_CUCCO, + COJIRO, + ODD_MUSHROOM, + ODD_POTION, + POACHERS_SAW, + BROKEN_SWORD, + PRESCRIPTION, + EYEBALL_FROG, + EYEDROPS, + CLAIM_CHECK, + + PROGRESSIVE_HOOKSHOT, + PROGRESSIVE_STRENGTH, + PROGRESSIVE_BOMB_BAG, + PROGRESSIVE_BOW, + PROGRESSIVE_SLINGSHOT, + PROGRESSIVE_WALLET, + PROGRESSIVE_SCALE, + PROGRESSIVE_NUT_UPGRADE, + PROGRESSIVE_STICK_UPGRADE, + PROGRESSIVE_MAGIC_METER, + PROGRESSIVE_OCARINA, + PROGRESSIVE_BOMBCHUS, + PROGRESSIVE_GORONSWORD, + + //Keys just used for logic + BOW, + SLINGSHOT, + HOOKSHOT, + LONGSHOT, + SILVER_GAUNTLETS, + GOLDEN_GAUNTLETS, + SILVER_SCALE, + GOLD_SCALE, + SCARECROW, + DISTANT_SCARECROW, + STICKS, + + EMPTY_BOTTLE, + BOTTLE_WITH_MILK, + BOTTLE_WITH_RED_POTION, + BOTTLE_WITH_GREEN_POTION, + BOTTLE_WITH_BLUE_POTION, + BOTTLE_WITH_FAIRY, + BOTTLE_WITH_FISH, + BOTTLE_WITH_BLUE_FIRE, + BOTTLE_WITH_BUGS, + BOTTLE_WITH_POE, + BOTTLE_WITH_BIG_POE, + RUTOS_LETTER, + + ZELDAS_LULLABY, + EPONAS_SONG, + SARIAS_SONG, + SUNS_SONG, + SONG_OF_TIME, + SONG_OF_STORMS, + MINUET_OF_FOREST, + BOLERO_OF_FIRE, + SERENADE_OF_WATER, + REQUIEM_OF_SPIRIT, + NOCTURNE_OF_SHADOW, + PRELUDE_OF_LIGHT, + + MAP, + DEKU_TREE_MAP, + DODONGOS_CAVERN_MAP, + JABU_JABUS_BELLY_MAP, + FOREST_TEMPLE_MAP, + FIRE_TEMPLE_MAP, + WATER_TEMPLE_MAP, + SPIRIT_TEMPLE_MAP, + SHADOW_TEMPLE_MAP, + BOTTOM_OF_THE_WELL_MAP, + ICE_CAVERN_MAP, + + COMPASS, + DEKU_TREE_COMPASS, + DODONGOS_CAVERN_COMPASS, + JABU_JABUS_BELLY_COMPASS, + FOREST_TEMPLE_COMPASS, + FIRE_TEMPLE_COMPASS, + WATER_TEMPLE_COMPASS, + SPIRIT_TEMPLE_COMPASS, + SHADOW_TEMPLE_COMPASS, + BOTTOM_OF_THE_WELL_COMPASS, + ICE_CAVERN_COMPASS, + + BOSS_KEY, + FOREST_TEMPLE_BOSS_KEY, + FIRE_TEMPLE_BOSS_KEY, + WATER_TEMPLE_BOSS_KEY, + SPIRIT_TEMPLE_BOSS_KEY, + SHADOW_TEMPLE_BOSS_KEY, + GANONS_CASTLE_BOSS_KEY, + + SMALL_KEY, + FOREST_TEMPLE_SMALL_KEY, + FIRE_TEMPLE_SMALL_KEY, + WATER_TEMPLE_SMALL_KEY, + SPIRIT_TEMPLE_SMALL_KEY, + SHADOW_TEMPLE_SMALL_KEY, + BOTTOM_OF_THE_WELL_SMALL_KEY, + GERUDO_TRAINING_GROUNDS_SMALL_KEY, + GERUDO_FORTRESS_SMALL_KEY, + GANONS_CASTLE_SMALL_KEY, + TREASURE_GAME_SMALL_KEY, + + FOREST_TEMPLE_KEY_RING, + FIRE_TEMPLE_KEY_RING, + WATER_TEMPLE_KEY_RING, + SPIRIT_TEMPLE_KEY_RING, + SHADOW_TEMPLE_KEY_RING, + BOTTOM_OF_THE_WELL_KEY_RING, + GERUDO_TRAINING_GROUNDS_KEY_RING, + GERUDO_FORTRESS_KEY_RING, + GANONS_CASTLE_KEY_RING, + + KOKIRI_EMERALD, + GORON_RUBY, + ZORA_SAPPHIRE, + FOREST_MEDALLION, + FIRE_MEDALLION, + WATER_MEDALLION, + SPIRIT_MEDALLION, + SHADOW_MEDALLION, + LIGHT_MEDALLION, + + RECOVERY_HEART, + GREEN_RUPEE, + BLUE_RUPEE, + RED_RUPEE, + PURPLE_RUPEE, + HUGE_RUPEE, + PIECE_OF_HEART, + HEART_CONTAINER, + ICE_TRAP, + MILK, + + BOMBS_5, + BOMBS_10, + BOMBS_20, + BOMBCHU_5, + BOMBCHU_10, + BOMBCHU_20, + BOMBCHU_DROP, + ARROWS_5, + ARROWS_10, + ARROWS_30, + DEKU_NUTS_5, + DEKU_NUTS_10, + DEKU_SEEDS_30, + DEKU_STICK_1, + RED_POTION_REFILL, + GREEN_POTION_REFILL, + BLUE_POTION_REFILL, + + TREASURE_GAME_HEART, + TREASURE_GAME_GREEN_RUPEE, + + TRIFORCE, + TRIFORCE_PIECE, + EPONA, + HINT, + + //SHOP ITEMS + BUY_DEKU_NUT_5, + BUY_ARROWS_30, + BUY_ARROWS_50, + BUY_BOMBS_525, + BUY_DEKU_NUT_10, + BUY_DEKU_STICK_1, + BUY_BOMBS_10, + BUY_FISH, + BUY_RED_POTION_30, + BUY_GREEN_POTION, + BUY_BLUE_POTION, + BUY_HYLIAN_SHIELD, + BUY_DEKU_SHIELD, + BUY_GORON_TUNIC, + BUY_ZORA_TUNIC, + BUY_HEART, + BUY_BOMBCHU_10, + BUY_BOMBCHU_20, + BUY_BOMBCHU_5, + BUY_DEKU_SEEDS_30, + SOLD_OUT, + BUY_BLUE_FIRE, + BUY_BOTTLE_BUG, + BUY_POE, + BUY_FAIRYS_SPIRIT, + BUY_ARROWS_10, + BUY_BOMBS_20, + BUY_BOMBS_30, + BUY_BOMBS_535, + BUY_RED_POTION_40, + BUY_RED_POTION_50, + + //ITEMLOCATIONS + + //DUNGEON REWARDS + LINKS_POCKET, + QUEEN_GOHMA, + KING_DODONGO, + BARINADE, + PHANTOM_GANON, + VOLVAGIA, + MORPHA, + BONGO_BONGO, + TWINROVA, + GANON, + + //SONGS + SONG_FROM_IMPA, + SONG_FROM_MALON, + SONG_FROM_SARIA, + SONG_FROM_COMPOSERS_GRAVE, + SONG_FROM_OCARINA_OF_TIME, + SONG_FROM_WINDMILL, + SHEIK_IN_FOREST, + SHEIK_IN_CRATER, + SHEIK_IN_ICE_CAVERN, + SHEIK_AT_COLOSSUS, + SHEIK_IN_KAKARIKO, + SHEIK_AT_TEMPLE, + +//// Overworld +// Kokiri Forest + KF_MIDOS_TOP_LEFT_CHEST, + KF_MIDOS_TOP_RIGHT_CHEST, + KF_MIDOS_BOTTOM_LEFT_CHEST, + KF_MIDOS_BOTTOM_RIGHT_CHEST, + KF_KOKIRI_SWORD_CHEST, + KF_STORMS_GROTTO_CHEST, + KF_LINKS_HOUSE_COW, + KF_GS_KNOW_IT_ALL_HOUSE, + KF_GS_BEAN_PATCH, + KF_GS_HOUSE_OF_TWINS, + KF_SHOP_ITEM_1, + KF_SHOP_ITEM_2, + KF_SHOP_ITEM_3, + KF_SHOP_ITEM_4, + KF_SHOP_ITEM_5, + KF_SHOP_ITEM_6, + KF_SHOP_ITEM_7, + KF_SHOP_ITEM_8, +//LOST_WOODS + LW_GIFT_FROM_SARIA, + LW_OCARINA_MEMORY_GAME, + LW_TARGET_IN_WOODS, + LW_NEAR_SHORTCUTS_GROTTO_CHEST, + DEKU_THEATER_SKULL_MASK, + DEKU_THEATER_MASK_OF_TRUTH, + LW_SKULL_KID, + LW_TRADE_COJIRO, + LW_TRADE_ODD_POTION, + LW_DEKU_SCRUB_NEAR_BRIDGE, + LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, + LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT, + LW_DEKU_SCRUB_GROTTO_FRONT, + LW_DEKU_SCRUB_GROTTO_REAR, + LW_GS_BEAN_PATCH_NEAR_BRIDGE, + LW_GS_BEAN_PATCH_NEAR_THEATER, + LW_GS_ABOVE_THEATER, +//SACRED_FOREST_MEADOW + SFM_WOLFOS_GROTTO_CHEST, + SFM_DEKU_SCRUB_GROTTO_FRONT, + SFM_DEKU_SCRUB_GROTTO_REAR, + SFM_GS, +//HYRULE_FIELD + HF_OCARINA_OF_TIME_ITEM, + HF_NEAR_MARKET_GROTTO_CHEST, + HF_TEKTITE_GROTTO_FREESTANDING_POH, + HF_SOUTHEAST_GROTTO_CHEST, + HF_OPEN_GROTTO_CHEST, + HF_DEKU_SCRUB_GROTTO, + HF_COW_GROTTO_COW, + HF_GS_COW_GROTTO, + HF_GS_NEAR_KAK_GROTTO, +//MARKET + MARKET_SHOOTING_GALLERY_REWARD, + MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, + MARKET_BOMBCHU_BOWLING_SECOND_PRIZE, + MARKET_BOMBCHU_BOWLING_BOMBCHUS, + MARKET_LOST_DOG, + MARKET_TREASURE_CHEST_GAME_REWARD, + MARKET_TREASURE_CHEST_GAME_ITEM_1, + MARKET_TREASURE_CHEST_GAME_ITEM_2, + MARKET_TREASURE_CHEST_GAME_ITEM_3, + MARKET_TREASURE_CHEST_GAME_ITEM_4, + MARKET_TREASURE_CHEST_GAME_ITEM_5, + MARKET_10_BIG_POES, + MARKET_GS_GUARD_HOUSE, + MARKET_BAZAAR_ITEM_1, + MARKET_BAZAAR_ITEM_2, + MARKET_BAZAAR_ITEM_3, + MARKET_BAZAAR_ITEM_4, + MARKET_BAZAAR_ITEM_5, + MARKET_BAZAAR_ITEM_6, + MARKET_BAZAAR_ITEM_7, + MARKET_BAZAAR_ITEM_8, + MARKET_POTION_SHOP_ITEM_1, + MARKET_POTION_SHOP_ITEM_2, + MARKET_POTION_SHOP_ITEM_3, + MARKET_POTION_SHOP_ITEM_4, + MARKET_POTION_SHOP_ITEM_5, + MARKET_POTION_SHOP_ITEM_6, + MARKET_POTION_SHOP_ITEM_7, + MARKET_POTION_SHOP_ITEM_8, + MARKET_BOMBCHU_SHOP_ITEM_1, + MARKET_BOMBCHU_SHOP_ITEM_2, + MARKET_BOMBCHU_SHOP_ITEM_3, + MARKET_BOMBCHU_SHOP_ITEM_4, + MARKET_BOMBCHU_SHOP_ITEM_5, + MARKET_BOMBCHU_SHOP_ITEM_6, + MARKET_BOMBCHU_SHOP_ITEM_7, + MARKET_BOMBCHU_SHOP_ITEM_8, + TOT_LIGHT_ARROWS_CUTSCENE, +//HYRULE_CASTLE + HC_MALON_EGG, + HC_ZELDAS_LETTER, + HC_GREAT_FAIRY_REWARD, + HC_GS_TREE, + HC_GS_STORMS_GROTTO, +//LON_LON_RANCH + LLR_TALONS_CHICKENS, + LLR_FREESTANDING_POH, + LLR_DEKU_SCRUB_GROTTO_LEFT, + LLR_DEKU_SCRUB_GROTTO_CENTER, + LLR_DEKU_SCRUB_GROTTO_RIGHT, + LLR_STABLES_LEFT_COW, + LLR_STABLES_RIGHT_COW, + LLR_TOWER_LEFT_COW, + LLR_TOWER_RIGHT_COW, + LLR_GS_HOUSE_WINDOW, + LLR_GS_TREE, + LLR_GS_RAIN_SHED, + LLR_GS_BACK_WALL, +//KAKARIKO + KAK_ANJU_AS_CHILD, + KAK_ANJU_AS_ADULT, + KAK_TRADE_POCKET_CUCCO, + KAK_IMPAS_HOUSE_FREESTANDING_POH, + KAK_WINDMILL_FREESTANDING_POH, + KAK_MAN_ON_ROOF, + KAK_OPEN_GROTTO_CHEST, + KAK_REDEAD_GROTTO_CHEST, + KAK_SHOOTING_GALLERY_REWARD, + KAK_TRADE_ODD_MUSHROOM, + KAK_10_GOLD_SKULLTULA_REWARD, + KAK_20_GOLD_SKULLTULA_REWARD, + KAK_30_GOLD_SKULLTULA_REWARD, + KAK_40_GOLD_SKULLTULA_REWARD, + KAK_50_GOLD_SKULLTULA_REWARD, + KAK_IMPAS_HOUSE_COW, + KAK_GS_TREE, + KAK_GS_GUARDS_HOUSE, + KAK_GS_WATCHTOWER, + KAK_GS_SKULLTULA_HOUSE, + KAK_GS_HOUSE_UNDER_CONSTRUCTION, + KAK_GS_ABOVE_IMPAS_HOUSE, + KAK_BAZAAR_ITEM_1, + KAK_BAZAAR_ITEM_2, + KAK_BAZAAR_ITEM_3, + KAK_BAZAAR_ITEM_4, + KAK_BAZAAR_ITEM_5, + KAK_BAZAAR_ITEM_6, + KAK_BAZAAR_ITEM_7, + KAK_BAZAAR_ITEM_8, + KAK_POTION_SHOP_ITEM_1, + KAK_POTION_SHOP_ITEM_2, + KAK_POTION_SHOP_ITEM_3, + KAK_POTION_SHOP_ITEM_4, + KAK_POTION_SHOP_ITEM_5, + KAK_POTION_SHOP_ITEM_6, + KAK_POTION_SHOP_ITEM_7, + KAK_POTION_SHOP_ITEM_8, +//GRAVEYARD + GRAVEYARD_SHIELD_GRAVE_CHEST, + GRAVEYARD_HEART_PIECE_GRAVE_CHEST, + GRAVEYARD_COMPOSERS_GRAVE_CHEST, + GRAVEYARD_FREESTANDING_POH, + GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR, + GRAVEYARD_HOOKSHOT_CHEST, + GRAVEYARD_DAMPE_RACE_FREESTANDING_POH, + GRAVEYARD_GS_BEAN_PATCH, + GRAVEYARD_GS_WALL, +//DEATH_MOUNTAIN_TRAIL + DMT_FREESTANDING_POH, + DMT_CHEST, + DMT_STORMS_GROTTO_CHEST, + DMT_GREAT_FAIRY_REWARD, + DMT_TRADE_BROKEN_SWORD, + DMT_TRADE_EYEDROPS, + DMT_TRADE_CLAIM_CHECK, + DMT_COW_GROTTO_COW, + DMT_GS_NEAR_KAK, + DMT_GS_BEAN_PATCH, + DMT_GS_ABOVE_DODONGOS_CAVERN, + DMT_GS_FALLING_ROCKS_PATH, +//GORON_CITY + GC_DARUNIAS_JOY, + GC_POT_FREESTANDING_POH, + GC_ROLLING_GORON_AS_CHILD, + GC_ROLLING_GORON_AS_ADULT, + GC_MEDIGORON, + GC_MAZE_LEFT_CHEST, + GC_MAZE_RIGHT_CHEST, + GC_MAZE_CENTER_CHEST, + GC_DEKU_SCRUB_GROTTO_LEFT, + GC_DEKU_SCRUB_GROTTO_CENTER, + GC_DEKU_SCRUB_GROTTO_RIGHT, + GC_GS_CENTER_PLATFORM, + GC_GS_BOULDER_MAZE, + GC_SHOP_ITEM_1, + GC_SHOP_ITEM_2, + GC_SHOP_ITEM_3, + GC_SHOP_ITEM_4, + GC_SHOP_ITEM_5, + GC_SHOP_ITEM_6, + GC_SHOP_ITEM_7, + GC_SHOP_ITEM_8, +//DEATH_MOUNTAIN_CRATER + DMC_VOLCANO_FREESTANDING_POH, + DMC_WALL_FREESTANDING_POH, + DMC_UPPER_GROTTO_CHEST, + DMC_GREAT_FAIRY_REWARD, + DMC_DEKU_SCRUB, + DMC_DEKU_SCRUB_GROTTO_LEFT, + DMC_DEKU_SCRUB_GROTTO_CENTER, + DMC_DEKU_SCRUB_GROTTO_RIGHT, + DMC_GS_CRATE, + DMC_GS_BEAN_PATCH, +//ZORA'S_RIVER + ZR_MAGIC_BEAN_SALESMAN, + ZR_OPEN_GROTTO_CHEST, + ZR_FROGS_IN_THE_RAIN, + ZR_FROGS_OCARINA_GAME, + ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH, + ZR_NEAR_DOMAIN_FREESTANDING_POH, + ZR_DEKU_SCRUB_GROTTO_FRONT, + ZR_DEKU_SCRUB_GROTTO_REAR, + ZR_GS_TREE, + ZR_GS_LADDER, + ZR_GS_NEAR_RAISED_GROTTOS, + ZR_GS_ABOVE_BRIDGE, +//ZORA'S_DOMAIN + ZD_DIVING_MINIGAME, + ZD_CHEST, + ZD_KING_ZORA_THAWED, + ZD_TRADE_PRESCRIPTION, + ZD_GS_FROZEN_WATERFALL, + ZD_SHOP_ITEM_1, + ZD_SHOP_ITEM_2, + ZD_SHOP_ITEM_3, + ZD_SHOP_ITEM_4, + ZD_SHOP_ITEM_5, + ZD_SHOP_ITEM_6, + ZD_SHOP_ITEM_7, + ZD_SHOP_ITEM_8, +//ZORA'S_FOUNTAIN + ZF_GREAT_FAIRY_REWARD, + ZF_ICEBERG_FREESTANDING_POH, + ZF_BOTTOM_FREESTANDING_POH, + ZF_GS_ABOVE_THE_LOG, + ZF_GS_TREE, + ZF_GS_HIDDEN_CAVE, +//LAKE_HYLIA + LH_UNDERWATER_ITEM, + LH_CHILD_FISHING, + LH_ADULT_FISHING, + LH_LAB_DIVE, + LH_TRADE_FROG, + LH_FREESTANDING_POH, + LH_SUN, + LH_DEKU_SCRUB_GROTTO_LEFT, + LH_DEKU_SCRUB_GROTTO_CENTER, + LH_DEKU_SCRUB_GROTTO_RIGHT, + LH_GS_BEAN_PATCH, + LH_GS_LAB_WALL, + LH_GS_SMALL_ISLAND, + LH_GS_LAB_CRATE, + LH_GS_TREE, +//GERUDO_VALLEY + GV_CRATE_FREESTANDING_POH, + GV_WATERFALL_FREESTANDING_POH, + GV_CHEST, + GV_TRADE_SAW, + GV_DEKU_SCRUB_GROTTO_FRONT, + GV_DEKU_SCRUB_GROTTO_REAR, + GV_COW, + GV_GS_SMALL_BRIDGE, + GV_GS_BEAN_PATCH, + GV_GS_BEHIND_TENT, + GV_GS_PILLAR, +//GERUDO'S_FORTRESS + GF_NORTH_F1_CARPENTER, + GF_NORTH_F2_CARPENTER, + GF_SOUTH_F1_CARPENTER, + GF_SOUTH_F2_CARPENTER, + GF_GERUDO_MEMBERSHIP_CARD, + GF_CHEST, + GF_HBA_1000_POINTS, + GF_HBA_1500_POINTS, + GF_GS_TOP_FLOOR, + GF_GS_ARCHERY_RANGE, +//WASTELAND + WASTELAND_BOMBCHU_SALESMAN, + WASTELAND_CHEST, + WASTELAND_GS, +//COLOSSUS + COLOSSUS_GREAT_FAIRY_REWARD, + COLOSSUS_FREESTANDING_POH, + COLOSSUS_DEKU_SCRUB_GROTTO_FRONT, + COLOSSUS_DEKU_SCRUB_GROTTO_REAR, + COLOSSUS_GS_BEAN_PATCH, + COLOSSUS_GS_TREE, + COLOSSUS_GS_HILL, +//OUTSIDE_GANON'S_CASTLE + OGC_GREAT_FAIRY_REWARD, + OGC_GS, + +////DUNGEONS +//DEKU_TREE_VANILLA + DEKU_TREE_MAP_CHEST, + DEKU_TREE_SLINGSHOT_ROOM_SIDE_CHEST, + DEKU_TREE_SLINGSHOT_CHEST, + DEKU_TREE_COMPASS_CHEST, + DEKU_TREE_COMPASS_ROOM_SIDE_CHEST, + DEKU_TREE_BASEMENT_CHEST, + DEKU_TREE_GS_COMPASS_ROOM, + DEKU_TREE_GS_BASEMENT_VINES, + DEKU_TREE_GS_BASEMENT_GATE, + DEKU_TREE_GS_BASEMENT_BACK_ROOM, +//DEKU_TREE_MQ + DEKU_TREE_MQ_MAP_CHEST, + DEKU_TREE_MQ_SLINGSHOT_CHEST, + DEKU_TREE_MQ_SLINGSHOT_ROOM_BACK_CHEST, + DEKU_TREE_MQ_COMPASS_CHEST, + DEKU_TREE_MQ_BASEMENT_CHEST, + DEKU_TREE_MQ_BEFORE_SPINNING_LOG_CHEST, + DEKU_TREE_MQ_AFTER_SPINNING_LOG_CHEST, + DEKU_TREE_MQ_DEKU_SCRUB, + DEKU_TREE_MQ_GS_LOBBY, + DEKU_TREE_MQ_GS_COMPASS_ROOM, + DEKU_TREE_MQ_GS_BASEMENT_GRAVES_ROOM, + DEKU_TREE_MQ_GS_BASEMENT_BACK_ROOM, +//DEKU_TREE_SHARED + DEKU_TREE_QUEEN_GOHMA_HEART, +//DODONGO'S_CAVERN_VANILLA + DODONGOS_CAVERN_MAP_CHEST, + DODONGOS_CAVERN_COMPASS_CHEST, + DODONGOS_CAVERN_BOMB_FLOWER_PLATFORM_CHEST, + DODONGOS_CAVERN_BOMB_BAG_CHEST, + DODONGOS_CAVERN_END_OF_BRIDGE_CHEST, + DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS, + DODONGOS_CAVERN_DEKU_SCRUB_LOBBY, + DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT, + DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT, + DODONGOS_CAVERN_GS_SIDE_ROOM_NEAR_LOWER_LIZALFOS, + DODONGOS_CAVERN_GS_SCARECROW, + DODONGOS_CAVERN_GS_ALCOVE_ABOVE_STAIRS, + DODONGOS_CAVERN_GS_VINES_ABOVE_STAIRS, + DODONGOS_CAVERN_GS_BACK_ROOM, +//DODONGO'S_CAVERN_MQ + DODONGOS_CAVERN_MQ_MAP_CHEST, + DODONGOS_CAVERN_MQ_BOMB_BAG_CHEST, + DODONGOS_CAVERN_MQ_TORCH_PUZZLE_ROOM_CHEST, + DODONGOS_CAVERN_MQ_LARVAE_ROOM_CHEST, + DODONGOS_CAVERN_MQ_COMPASS_CHEST, + DODONGOS_CAVERN_MQ_UNDER_GRAVE_CHEST, + DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT, + DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR, + DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS, + DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE, + DODONGOS_CAVERN_MQ_GS_SCRUB_ROOM, + DODONGOS_CAVERN_MQ_GS_LARVAE_ROOM, + DODONGOS_CAVERN_MQ_GS_LIZALFOS_ROOM, + DODONGOS_CAVERN_MQ_GS_SONG_OF_TIME_BLOCK_ROOM, + DODONGOS_CAVERN_MQ_GS_BACK_AREA, +//DODONGO'S_CAVERN_SHARED + DODONGOS_CAVERN_BOSS_ROOM_CHEST, + DODONGOS_CAVERN_KING_DODONGO_HEART, +//JABU_JABU'S_BELLY_VANILLA + JABU_JABUS_BELLY_BOOMERANG_CHEST, + JABU_JABUS_BELLY_MAP_CHEST, + JABU_JABUS_BELLY_COMPASS_CHEST, + JABU_JABUS_BELLY_DEKU_SCRUB, + JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM, + JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_LOWER, + JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_UPPER, + JABU_JABUS_BELLY_GS_NEAR_BOSS, +//JABU_JABU'S_BELLY_MQ + JABU_JABUS_BELLY_MQ_MAP_CHEST, + JABU_JABUS_BELLY_MQ_FIRST_ROOM_SIDE_CHEST, + JABU_JABUS_BELLY_MQ_SECOND_ROOM_LOWER_CHEST, + JABU_JABUS_BELLY_MQ_COMPASS_CHEST, + JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_SWITCHES_CHEST, + JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_VINES_CHEST, + JABU_JABUS_BELLY_MQ_BOOMERANG_ROOM_SMALL_CHEST, + JABU_JABUS_BELLY_MQ_BOOMERANG_CHEST, + JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_ROOM_CHEST, + JABU_JABUS_BELLY_MQ_SECOND_ROOM_UPPER_CHEST, + JABU_JABUS_BELLY_MQ_NEAR_BOSS_CHEST, + JABU_JABUS_BELLY_MQ_COW, + JABU_JABUS_BELLY_MQ_GS_BOOMERANG_CHEST_ROOM, + JABU_JABUS_BELLY_MQ_GS_TAILPASARAN_ROOM, + JABU_JABUS_BELLY_MQ_GS_INVISIBLE_ENEMIES_ROOM, + JABU_JABUS_BELLY_MQ_GS_NEAR_BOSS, +//JABU_JABU'S_BELLY_SHARED + JABU_JABUS_BELLY_BARINADE_HEART, +//BOTTOM_OF_THE_WELL_VANILLA + BOTTOM_OF_THE_WELL_FRONT_LEFT_FAKE_WALL_CHEST, + BOTTOM_OF_THE_WELL_FRONT_CENTER_BOMBABLE_CHEST, + BOTTOM_OF_THE_WELL_BACK_LEFT_BOMBABLE_CHEST, + BOTTOM_OF_THE_WELL_UNDERWATER_LEFT_CHEST, + BOTTOM_OF_THE_WELL_FREESTANDING_KEY, + BOTTOM_OF_THE_WELL_COMPASS_CHEST, + BOTTOM_OF_THE_WELL_CENTER_SKULLTULA_CHEST, + BOTTOM_OF_THE_WELL_RIGHT_BOTTOM_FAKE_WALL_CHEST, + BOTTOM_OF_THE_WELL_FIRE_KEESE_CHEST, + BOTTOM_OF_THE_WELL_LIKE_LIKE_CHEST, + BOTTOM_OF_THE_WELL_MAP_CHEST, + BOTTOM_OF_THE_WELL_UNDERWATER_FRONT_CHEST, + BOTTOM_OF_THE_WELL_INVISIBLE_CHEST, + BOTTOM_OF_THE_WELL_LENS_OF_TRUTH_CHEST, + BOTTOM_OF_THE_WELL_GS_WEST_INNER_ROOM, + BOTTOM_OF_THE_WELL_GS_EAST_INNER_ROOM, + BOTTOM_OF_THE_WELL_GS_LIKE_LIKE_CAGE, +//BOTTOM_OF_THE_WELL_MQ + BOTTOM_OF_THE_WELL_MQ_MAP_CHEST, + BOTTOM_OF_THE_WELL_MQ_EAST_INNER_ROOM_FREESTANDING_KEY, + BOTTOM_OF_THE_WELL_MQ_COMPASS_CHEST, + BOTTOM_OF_THE_WELL_MQ_DEAD_HAND_FREESTANDING_KEY, + BOTTOM_OF_THE_WELL_MQ_LENS_OF_TRUTH_CHEST, + BOTTOM_OF_THE_WELL_MQ_GS_COFFIN_ROOM, + BOTTOM_OF_THE_WELL_MQ_GS_WEST_INNER_ROOM, + BOTTOM_OF_THE_WELL_MQ_GS_BASEMENT, +//FOREST_TEMPLE_VANILLA + FOREST_TEMPLE_FIRST_ROOM_CHEST, + FOREST_TEMPLE_FIRST_STALFOS_CHEST, + FOREST_TEMPLE_RAISED_ISLAND_COURTYARD_CHEST, + FOREST_TEMPLE_MAP_CHEST, + FOREST_TEMPLE_WELL_CHEST, + FOREST_TEMPLE_EYE_SWITCH_CHEST, + FOREST_TEMPLE_BOSS_KEY_CHEST, + FOREST_TEMPLE_FLOORMASTER_CHEST, + FOREST_TEMPLE_RED_POE_CHEST, + FOREST_TEMPLE_BOW_CHEST, + FOREST_TEMPLE_BLUE_POE_CHEST, + FOREST_TEMPLE_FALLING_CEILING_ROOM_CHEST, + FOREST_TEMPLE_BASEMENT_CHEST, + FOREST_TEMPLE_GS_FIRST_ROOM, + FOREST_TEMPLE_GS_LOBBY, + FOREST_TEMPLE_GS_RAISED_ISLAND_COURTYARD, + FOREST_TEMPLE_GS_LEVEL_ISLAND_COURTYARD, + FOREST_TEMPLE_GS_BASEMENT, +//FOREST_TEMPLE_MQ + FOREST_TEMPLE_MQ_FIRST_ROOM_CHEST, + FOREST_TEMPLE_MQ_WOLFOS_CHEST, + FOREST_TEMPLE_MQ_WELL_CHEST, + FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_LOWER_CHEST, + FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_UPPER_CHEST, + FOREST_TEMPLE_MQ_BOSS_KEY_CHEST, + FOREST_TEMPLE_MQ_REDEAD_CHEST, + FOREST_TEMPLE_MQ_MAP_CHEST, + FOREST_TEMPLE_MQ_BOW_CHEST, + FOREST_TEMPLE_MQ_COMPASS_CHEST, + FOREST_TEMPLE_MQ_FALLING_CEILING_ROOM_CHEST, + FOREST_TEMPLE_MQ_BASEMENT_CHEST, + FOREST_TEMPLE_MQ_GS_FIRST_HALLWAY, + FOREST_TEMPLE_MQ_GS_RAISED_ISLAND_COURTYARD, + FOREST_TEMPLE_MQ_GS_LEVEL_ISLAND_COURTYARD, + FOREST_TEMPLE_MQ_GS_WELL, + FOREST_TEMPLE_MQ_GS_BLOCK_PUSH_ROOM, +//FOREST_TEMPLE_SHARED + FOREST_TEMPLE_PHANTOM_GANON_HEART, +//FIRE_TEMPLE_VANILLA + FIRE_TEMPLE_NEAR_BOSS_CHEST, + FIRE_TEMPLE_FLARE_DANCER_CHEST, + FIRE_TEMPLE_BOSS_KEY_CHEST, + FIRE_TEMPLE_BIG_LAVA_ROOM_LOWER_OPEN_DOOR_CHEST, + FIRE_TEMPLE_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST, + FIRE_TEMPLE_BOULDER_MAZE_LOWER_CHEST, + FIRE_TEMPLE_BOULDER_MAZE_SIDE_ROOM_CHEST, + FIRE_TEMPLE_MAP_CHEST, + FIRE_TEMPLE_BOULDER_MAZE_SHORTCUT_CHEST, + FIRE_TEMPLE_BOULDER_MAZE_UPPER_CHEST, + FIRE_TEMPLE_SCARECROW_CHEST, + FIRE_TEMPLE_COMPASS_CHEST, + FIRE_TEMPLE_MEGATON_HAMMER_CHEST, + FIRE_TEMPLE_HIGHEST_GORON_CHEST, + FIRE_TEMPLE_GS_BOSS_KEY_LOOP, + FIRE_TEMPLE_GS_SONG_OF_TIME_ROOM, + FIRE_TEMPLE_GS_BOULDER_MAZE, + FIRE_TEMPLE_GS_SCARECROW_CLIMB, + FIRE_TEMPLE_GS_SCARECROW_TOP, +//FIRE_TEMPLE_MQ + FIRE_TEMPLE_MQ_MAP_ROOM_SIDE_CHEST, + FIRE_TEMPLE_MQ_MEGATON_HAMMER_CHEST, + FIRE_TEMPLE_MQ_MAP_CHEST, + FIRE_TEMPLE_MQ_NEAR_BOSS_CHEST, + FIRE_TEMPLE_MQ_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST, + FIRE_TEMPLE_MQ_BOSS_KEY_CHEST, + FIRE_TEMPLE_MQ_LIZALFOS_MAZE_SIDE_ROOM_CHEST, + FIRE_TEMPLE_MQ_COMPASS_CHEST, + FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CHEST, + FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CHEST, + FIRE_TEMPLE_MQ_FREESTANDING_KEY, + FIRE_TEMPLE_MQ_CHEST_ON_FIRE, + FIRE_TEMPLE_MQ_GS_BIG_LAVA_ROOM_OPEN_DOOR, + FIRE_TEMPLE_MQ_GS_SKULL_ON_FIRE, + FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_CENTER, + FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_SIDE_ROOM, + FIRE_TEMPLE_MQ_GS_ABOVE_FIRE_WALL_MAZE, +//FIRE_TEMPLE_SHARED + FIRE_TEMPLE_VOLVAGIA_HEART, +//WATER_TEMPLE_VANILLA + WATER_TEMPLE_COMPASS_CHEST, + WATER_TEMPLE_MAP_CHEST, + WATER_TEMPLE_CRACKED_WALL_CHEST, + WATER_TEMPLE_TORCHES_CHEST, + WATER_TEMPLE_BOSS_KEY_CHEST, + WATER_TEMPLE_CENTRAL_PILLAR_CHEST, + WATER_TEMPLE_CENTRAL_BOW_TARGET_CHEST, + WATER_TEMPLE_LONGSHOT_CHEST, + WATER_TEMPLE_RIVER_CHEST, + WATER_TEMPLE_DRAGON_CHEST, + WATER_TEMPLE_GS_BEHIND_GATE, + WATER_TEMPLE_GS_NEAR_BOSS_KEY_CHEST, + WATER_TEMPLE_GS_CENTRAL_PILLAR, + WATER_TEMPLE_GS_FALLING_PLATFORM_ROOM, + WATER_TEMPLE_GS_RIVER, +//WATER_TEMPLE_MQ + WATER_TEMPLE_MQ_LONGSHOT_CHEST, + WATER_TEMPLE_MQ_MAP_CHEST, + WATER_TEMPLE_MQ_COMPASS_CHEST, + WATER_TEMPLE_MQ_CENTRAL_PILLAR_CHEST, + WATER_TEMPLE_MQ_BOSS_KEY_CHEST, + WATER_TEMPLE_MQ_FREESTANDING_KEY, + WATER_TEMPLE_MQ_GS_LIZALFOS_HALLWAY, + WATER_TEMPLE_MQ_GS_BEFORE_UPPER_WATER_SWITCH, + WATER_TEMPLE_MQ_GS_RIVER, + WATER_TEMPLE_MQ_GS_FREESTANDING_KEY_AREA, + WATER_TEMPLE_MQ_GS_TRIPLE_WALL_TORCH, +//WATER_TEMPLE_SHARED + WATER_TEMPLE_MORPHA_HEART, +//SHADOW_TEMPLE_VANILLA + SHADOW_TEMPLE_MAP_CHEST, + SHADOW_TEMPLE_HOVER_BOOTS_CHEST, + SHADOW_TEMPLE_COMPASS_CHEST, + SHADOW_TEMPLE_EARLY_SILVER_RUPEE_CHEST, + SHADOW_TEMPLE_INVISIBLE_BLADES_VISIBLE_CHEST, + SHADOW_TEMPLE_INVISIBLE_BLADES_INVISIBLE_CHEST, + SHADOW_TEMPLE_FALLING_SPIKES_LOWER_CHEST, + SHADOW_TEMPLE_FALLING_SPIKES_UPPER_CHEST, + SHADOW_TEMPLE_FALLING_SPIKES_SWITCH_CHEST, + SHADOW_TEMPLE_INVISIBLE_SPIKES_CHEST, + SHADOW_TEMPLE_FREESTANDING_KEY, + SHADOW_TEMPLE_WIND_HINT_CHEST, + SHADOW_TEMPLE_AFTER_WIND_ENEMY_CHEST, + SHADOW_TEMPLE_AFTER_WIND_HIDDEN_CHEST, + SHADOW_TEMPLE_SPIKE_WALLS_LEFT_CHEST, + SHADOW_TEMPLE_BOSS_KEY_CHEST, + SHADOW_TEMPLE_INVISIBLE_FLOORMASTER_CHEST, + SHADOW_TEMPLE_GS_LIKE_LIKE_ROOM, + SHADOW_TEMPLE_GS_FALLING_SPIKES_ROOM, + SHADOW_TEMPLE_GS_SINGLE_GIANT_POT, + SHADOW_TEMPLE_GS_NEAR_SHIP, + SHADOW_TEMPLE_GS_TRIPLE_GIANT_POT, +//SHADOW_TEMPLE_MQ + SHADOW_TEMPLE_MQ_EARLY_GIBDOS_CHEST, + SHADOW_TEMPLE_MQ_MAP_CHEST, + SHADOW_TEMPLE_MQ_NEAR_SHIP_INVISIBLE_CHEST, + SHADOW_TEMPLE_MQ_COMPASS_CHEST, + SHADOW_TEMPLE_MQ_HOVER_BOOTS_CHEST, + SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_INVISIBLE_CHEST, + SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_VISIBLE_CHEST, + SHADOW_TEMPLE_MQ_BEAMOS_SILVER_RUPEES_CHEST, + SHADOW_TEMPLE_MQ_FALLING_SPIKES_LOWER_CHEST, + SHADOW_TEMPLE_MQ_FALLING_SPIKES_UPPER_CHEST, + SHADOW_TEMPLE_MQ_FALLING_SPIKES_SWITCH_CHEST, + SHADOW_TEMPLE_MQ_INVISIBLE_SPIKES_CHEST, + SHADOW_TEMPLE_MQ_STALFOS_ROOM_CHEST, + SHADOW_TEMPLE_MQ_WIND_HINT_CHEST, + SHADOW_TEMPLE_MQ_AFTER_WIND_HIDDEN_CHEST, + SHADOW_TEMPLE_MQ_AFTER_WIND_ENEMY_CHEST, + SHADOW_TEMPLE_MQ_BOSS_KEY_CHEST, + SHADOW_TEMPLE_MQ_SPIKE_WALLS_LEFT_CHEST, + SHADOW_TEMPLE_MQ_FREESTANDING_KEY, + SHADOW_TEMPLE_MQ_BOMB_FLOWER_CHEST, + SHADOW_TEMPLE_MQ_GS_FALLING_SPIKES_ROOM, + SHADOW_TEMPLE_MQ_GS_WIND_HINT_ROOM, + SHADOW_TEMPLE_MQ_GS_AFTER_WIND, + SHADOW_TEMPLE_MQ_GS_AFTER_SHIP, + SHADOW_TEMPLE_MQ_GS_NEAR_BOSS, +//SHADOW_TEMPLE_SHARED + SHADOW_TEMPLE_BONGO_BONGO_HEART, +//SPIRIT_TEMPLE_SHARED +//VANILLA_AND_MQ_LOCATIONS_ARE_MIXED_TO_ENSURE_THE_POSITIONS_OF_S + SPIRIT_TEMPLE_CHILD_BRIDGE_CHEST, + SPIRIT_TEMPLE_CHILD_EARLY_TORCHES_CHEST, + SPIRIT_TEMPLE_CHILD_CLIMB_NORTH_CHEST, + SPIRIT_TEMPLE_CHILD_CLIMB_EAST_CHEST, + SPIRIT_TEMPLE_MAP_CHEST, + SPIRIT_TEMPLE_SUN_BLOCK_ROOM_CHEST, + SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_LEFT_CHEST, + SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_RIGHT_CHEST, + SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_RIGHT_CHEST, + SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_LEFT_CHEST, + SPIRIT_TEMPLE_MQ_MAP_CHEST, + SPIRIT_TEMPLE_MQ_MAP_ROOM_ENEMY_CHEST, + SPIRIT_TEMPLE_MQ_CHILD_CLIMB_NORTH_CHEST, + SPIRIT_TEMPLE_MQ_CHILD_CLIMB_SOUTH_CHEST, + SPIRIT_TEMPLE_MQ_COMPASS_CHEST, + SPIRIT_TEMPLE_MQ_SILVER_BLOCK_HALLWAY_CHEST, + SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM_CHEST, + SPIRIT_TEMPLE_SILVER_GAUNTLETS_CHEST, + SPIRIT_TEMPLE_COMPASS_CHEST, + SPIRIT_TEMPLE_EARLY_ADULT_RIGHT_CHEST, + SPIRIT_TEMPLE_FIRST_MIRROR_LEFT_CHEST, + SPIRIT_TEMPLE_FIRST_MIRROR_RIGHT_CHEST, + SPIRIT_TEMPLE_STATUE_ROOM_NORTHEAST_CHEST, + SPIRIT_TEMPLE_STATUE_ROOM_HAND_CHEST, + SPIRIT_TEMPLE_NEAR_FOUR_ARMOS_CHEST, + SPIRIT_TEMPLE_HALLWAY_RIGHT_INVISIBLE_CHEST, + SPIRIT_TEMPLE_HALLWAY_LEFT_INVISIBLE_CHEST, + SPIRIT_TEMPLE_MQ_CHILD_HAMMER_SWITCH_CHEST, + SPIRIT_TEMPLE_MQ_STATUE_ROOM_LULLABY_CHEST, + SPIRIT_TEMPLE_MQ_STATUE_ROOM_INVISIBLE_CHEST, + SPIRIT_TEMPLE_MQ_LEEVER_ROOM_CHEST, + SPIRIT_TEMPLE_MQ_SYMPHONY_ROOM_CHEST, + SPIRIT_TEMPLE_MQ_BEAMOS_ROOM_CHEST, + SPIRIT_TEMPLE_MQ_CHEST_SWITCH_CHEST, + SPIRIT_TEMPLE_MQ_BOSS_KEY_CHEST, + SPIRIT_TEMPLE_MIRROR_SHIELD_CHEST, + SPIRIT_TEMPLE_BOSS_KEY_CHEST, + SPIRIT_TEMPLE_TOPMOST_CHEST, + SPIRIT_TEMPLE_MQ_MIRROR_PUZZLE_INVISIBLE_CHEST, + SPIRIT_TEMPLE_GS_METAL_FENCE, + SPIRIT_TEMPLE_GS_SUN_ON_FLOOR_ROOM, + SPIRIT_TEMPLE_GS_HALL_AFTER_SUN_BLOCK_ROOM, + SPIRIT_TEMPLE_GS_LOBBY, + SPIRIT_TEMPLE_GS_BOULDER_ROOM, + SPIRIT_TEMPLE_MQ_GS_SUN_BLOCK_ROOM, + SPIRIT_TEMPLE_MQ_GS_LEEVER_ROOM, + SPIRIT_TEMPLE_MQ_GS_SYMPHONY_ROOM, + SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_WEST, + SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_NORTH, + SPIRIT_TEMPLE_TWINROVA_HEART, +//ICE_CAVERN_VANILLA + ICE_CAVERN_MAP_CHEST, + ICE_CAVERN_COMPASS_CHEST, + ICE_CAVERN_FREESTANDING_POH, + ICE_CAVERN_IRON_BOOTS_CHEST, + ICE_CAVERN_GS_SPINNING_SCYTHE_ROOM, + ICE_CAVERN_GS_HEART_PIECE_ROOM, + ICE_CAVERN_GS_PUSH_BLOCK_ROOM, +//ICE_CAVERN_MQ + ICE_CAVERN_MQ_MAP_CHEST, + ICE_CAVERN_MQ_COMPASS_CHEST, + ICE_CAVERN_MQ_FREESTANDING_POH, + ICE_CAVERN_MQ_IRON_BOOTS_CHEST, + ICE_CAVERN_MQ_GS_RED_ICE, + ICE_CAVERN_MQ_GS_ICE_BLOCK, + ICE_CAVERN_MQ_GS_SCARECROW, +//GERUDO_TRAINING_GROUNDS_VANILLA + GERUDO_TRAINING_GROUNDS_LOBBY_LEFT_CHEST, + GERUDO_TRAINING_GROUNDS_LOBBY_RIGHT_CHEST, + GERUDO_TRAINING_GROUNDS_STALFOS_CHEST, + GERUDO_TRAINING_GROUNDS_BEFORE_HEAVY_BLOCK_CHEST, + GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_FIRST_CHEST, + GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_SECOND_CHEST, + GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_THIRD_CHEST, + GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_FOURTH_CHEST, + GERUDO_TRAINING_GROUNDS_EYE_STATUE_CHEST, + GERUDO_TRAINING_GROUNDS_NEAR_SCARECROW_CHEST, + GERUDO_TRAINING_GROUNDS_HAMMER_ROOM_CLEAR_CHEST, + GERUDO_TRAINING_GROUNDS_HAMMER_ROOM_SWITCH_CHEST, + GERUDO_TRAINING_GROUNDS_FREESTANDING_KEY, + GERUDO_TRAINING_GROUNDS_MAZE_RIGHT_CENTRAL_CHEST, + GERUDO_TRAINING_GROUNDS_MAZE_RIGHT_SIDE_CHEST, + GERUDO_TRAINING_GROUNDS_UNDERWATER_SILVER_RUPEE_CHEST, + GERUDO_TRAINING_GROUNDS_BEAMOS_CHEST, + GERUDO_TRAINING_GROUNDS_HIDDEN_CEILING_CHEST, + GERUDO_TRAINING_GROUNDS_MAZE_PATH_FIRST_CHEST, + GERUDO_TRAINING_GROUNDS_MAZE_PATH_SECOND_CHEST, + GERUDO_TRAINING_GROUNDS_MAZE_PATH_THIRD_CHEST, + GERUDO_TRAINING_GROUNDS_MAZE_PATH_FINAL_CHEST, +//GERUDO_TRAINING_GROUNDS_MQ + GERUDO_TRAINING_GROUNDS_MQ_LOBBY_LEFT_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_LOBBY_RIGHT_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_FIRST_IRON_KNUCKLE_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_BEFORE_HEAVY_BLOCK_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_HEAVY_BLOCK_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_EYE_STATUE_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_ICE_ARROWS_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_SECOND_IRON_KNUCKLE_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_FLAME_CIRCLE_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_MAZE_RIGHT_CENTRAL_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_MAZE_RIGHT_SIDE_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER_SILVER_RUPEE_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_DINOLFOS_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_HIDDEN_CEILING_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_FIRST_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_THIRD_CHEST, + GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_SECOND_CHEST, +//GANON'S_CASTLE_VANILLA + GANONS_CASTLE_FOREST_TRIAL_CHEST, + GANONS_CASTLE_WATER_TRIAL_LEFT_CHEST, + GANONS_CASTLE_WATER_TRIAL_RIGHT_CHEST, + GANONS_CASTLE_SHADOW_TRIAL_FRONT_CHEST, + GANONS_CASTLE_SHADOW_TRIAL_GOLDEN_GAUNTLETS_CHEST, + GANONS_CASTLE_LIGHT_TRIAL_FIRST_LEFT_CHEST, + GANONS_CASTLE_LIGHT_TRIAL_SECOND_LEFT_CHEST, + GANONS_CASTLE_LIGHT_TRIAL_THIRD_LEFT_CHEST, + GANONS_CASTLE_LIGHT_TRIAL_FIRST_RIGHT_CHEST, + GANONS_CASTLE_LIGHT_TRIAL_SECOND_RIGHT_CHEST, + GANONS_CASTLE_LIGHT_TRIAL_THIRD_RIGHT_CHEST, + GANONS_CASTLE_LIGHT_TRIAL_INVISIBLE_ENEMIES_CHEST, + GANONS_CASTLE_LIGHT_TRIAL_LULLABY_CHEST, + GANONS_CASTLE_SPIRIT_TRIAL_CRYSTAL_SWITCH_CHEST, + GANONS_CASTLE_SPIRIT_TRIAL_INVISIBLE_CHEST, + GANONS_CASTLE_DEKU_SCRUB_LEFT, + GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT, + GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT, + GANONS_CASTLE_DEKU_SCRUB_RIGHT, +//GANON'S_CASTLE_MQ + GANONS_CASTLE_MQ_FOREST_TRIAL_FREESTANDING_KEY, + GANONS_CASTLE_MQ_FOREST_TRIAL_EYE_SWITCH_CHEST, + GANONS_CASTLE_MQ_FOREST_TRIAL_FROZEN_EYE_SWITCH_CHEST, + GANONS_CASTLE_MQ_WATER_TRIAL_CHEST, + GANONS_CASTLE_MQ_SHADOW_TRIAL_BOMB_FLOWER_CHEST, + GANONS_CASTLE_MQ_SHADOW_TRIAL_EYE_SWITCH_CHEST, + GANONS_CASTLE_MQ_LIGHT_TRIAL_LULLABY_CHEST, + GANONS_CASTLE_MQ_SPIRIT_TRIAL_FIRST_CHEST, + GANONS_CASTLE_MQ_SPIRIT_TRIAL_INVISIBLE_CHEST, + GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_FRONT_LEFT_CHEST, + GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_LEFT_CHEST, + GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_RIGHT_CHEST, + GANONS_CASTLE_MQ_SPIRIT_TRIAL_GOLDEN_GAUNTLETS_CHEST, + GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT, + GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT, + GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER, + GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT, + GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT, +//GANON'S_CASTLE_SHARED + GANONS_TOWER_BOSS_KEY_CHEST, + +////EVENTS_AND_DROPS + PIERRE, + DELIVER_RUTOS_LETTER, + MASTER_SWORD_PEDESTAL, + DEKU_BABA_STICKS, + DEKU_BABA_NUTS, + STICK_POT, + NUT_POT, + NUT_CRATE, + BLUE_FIRE, + LONE_FISH, + FISH_GROUP, + BUG_ROCK, + BUG_SHRUB, + WANDERING_BUGS, + FAIRY_POT, + FREE_FAIRIES, + WALL_FAIRY, + BUTTERFLY_FAIRY, + GOSSIP_STONE_FAIRY, + BEAN_PLANT_FAIRY, + FAIRY_POND, + BIG_POE_KILL, + + //HINT LOACTIONS + DMC_GOSSIP_STONE, + DMT_GOSSIP_STONE, + COLOSSUS_GOSSIP_STONE, + DODONGOS_CAVERN_GOSSIP_STONE, + GV_GOSSIP_STONE, + GC_MAZE_GOSSIP_STONE, + GC_MEDIGORON_GOSSIP_STONE, + GRAVEYARD_GOSSIP_STONE, + HC_MALON_GOSSIP_STONE, + HC_ROCK_WALL_GOSSIP_STONE, + HC_STORMS_GROTTO_GOSSIP_STONE, + HF_COW_GROTTO_GOSSIP_STONE, + KF_DEKU_TREE_GOSSIP_STONE_LEFT, + KF_DEKU_TREE_GOSSIP_STONE_RIGHT, + KF_GOSSIP_STONE, + LH_LAB_GOSSIP_STONE, + LH_GOSSIP_STONE_SOUTHEAST, + LH_GOSSIP_STONE_SOUTHWEST, + LW_GOSSIP_STONE, + SFM_MAZE_GOSSIP_STONE_LOWER, + SFM_MAZE_GOSSIP_STONE_UPPER, + SFM_SARIA_GOSSIP_STONE, + TOT_GOSSIP_STONE_LEFT, + TOT_GOSSIP_STONE_LEFT_CENTER, + TOT_GOSSIP_STONE_RIGHT, + TOT_GOSSIP_STONE_RIGHT_CENTER, + ZD_GOSSIP_STONE, + ZF_FAIRY_GOSSIP_STONE, + ZF_JABU_GOSSIP_STONE, + ZR_NEAR_GROTTOS_GOSSIP_STONE, + ZR_NEAR_DOMAIN_GOSSIP_STONE, + HF_NEAR_MARKET_GROTTO_GOSSIP_STONE, + HF_SOUTHEAST_GROTTO_GOSSIP_STONE, + HF_OPEN_GROTTO_GOSSIP_STONE, + KAK_OPEN_GROTTO_GOSSIP_STONE, + ZR_OPEN_GROTTO_GOSSIP_STONE, + KF_STORMS_GROTTO_GOSSIP_STONE, + LW_NEAR_SHORTCUTS_GROTTO_GOSSIP_STONE, + DMT_STORMS_GROTTO_GOSSIP_STONE, + DMC_UPPER_GROTTO_GOSSIP_STONE, + GANONDORF_HINT, + + //ENTRANCES + DESERT_COLOSSUS_TO_COLOSSUS_GROTTO, + GV_GROTTO_LEDGE_TO_GV_OCTOROK_GROTTO, + GC_GROTTO_PLATFORM_TO_GC_GROTTO, + GERUDO_FORTRESS_TO_GF_STORMS_GROTTO, + ZORAS_DOMAIN_TO_ZD_STORMS_GROTTO, + HYRULE_CASTLE_GROUNDS_TO_HC_STORMS_GROTTO, + GV_FORTRESS_SIDE_TO_GV_STORMS_GROTTO, + DESERT_COLOSSUS_TO_COLOSSUS_GREAT_FAIRY_FOUNTAIN, + GANONS_CASTLE_GROUNDS_TO_OGC_GREAT_FAIRY_FOUNTAIN, + ZORAS_FOUNTAIN_TO_ZF_GREAT_FAIRY_FOUNTAIN, + GV_FORTRESS_SIDE_TO_GV_CARPENTER_TENT, + GRAVEYARD_WARP_PAD_REGION_TO_SHADOW_TEMPLE_ENTRYWAY, + LAKE_HYLIA_TO_WATER_TEMPLE_LOBBY, + GERUDO_FORTRESS_TO_GERUDO_TRAINING_GROUNDS_LOBBY, + ZORAS_FOUNTAIN_TO_JABU_JABUS_BELLY_BEGINNING, + KAKARIKO_VILLAGE_TO_BOTTOM_OF_THE_WELL, + + //EXITS + HYRULE_CASTLE, + OUTSIDE_GANONS_CASTLE, + DEATH_MOUNTAIN_CRATER, + + //AREAS + ROOT, + ROOT_EXITS, + KOKIRI_FOREST, + KF_LINKS_HOUSE, + KF_MIDOS_HOUSE, + KF_SARIAS_HOUSE, + KF_HOUSE_OF_TWINS, + KF_KNOW_IT_ALL_HOUSE, + KF_KOKIRI_SHOP, + KF_OUTSIDE_DEKU_TREE, + KF_STORMS_GROTTO, + THE_LOST_WOODS, + LW_BRIDGE_FROM_FOREST, + LW_BRIDGE, + LW_FOREST_EXIT, + LW_BEYOND_MIDO, + LW_NEAR_SHORTCUTS_GROTTO, + DEKU_THEATER, + LW_SCRUBS_GROTTO, + SFM_ENTRYWAY, + SACRED_FOREST_MEADOW, + SFM_WOLFOS_GROTTO, + SFM_FAIRY_GROTTO, + SFM_STORMS_GROTTO, + HYRULE_FIELD, + HF_SOUTHEAST_GROTTO, + HF_OPEN_GROTTO, + HF_INSIDE_FENCE_GROTTO, + HF_COW_GROTTO, + HF_NEAR_MARKET_GROTTO, + HF_FAIRY_GROTTO, + HF_NEAR_KAK_GROTTO, + HF_TEKTITE_GROTTO, + LAKE_HYLIA, + LH_FISHING_ISLAND, + LH_OWL_FLIGHT, + LH_LAB, + LH_FISHING_HOLE, + LH_GROTTO, + GERUDO_VALLEY, + GV_UPPER_STREAM, + GV_LOWER_STREAM, + GV_GROTTO_LEDGE, + GV_CRATE_LEDGE, + GV_OCTOROK_GROTTO, + GV_FORTRESS_SIDE, + GV_CARPENTER_TENT, + GV_STORMS_GROTTO, + GERUDO_FORTRESS, + GF_OUTSIDE_GATE, + GF_STORMS_GROTTO, + WASTELAND_NEAR_FORTRESS, + HAUNTED_WASTELAND, + WASTELAND_NEAR_COLOSSUS, + DESERT_COLOSSUS, + COLOSSUS_GREAT_FAIRY_FOUNTAIN, + COLOSSUS_GROTTO, + MARKET_ENTRANCE, + THE_MARKET, + MARKET_GUARD_HOUSE, + MARKET_BAZAAR, + MARKET_MASK_SHOP, + MARKET_SHOOTING_GALLERY, + MARKET_BOMBCHU_BOWLING, + MARKET_TREASURE_CHEST_GAME, + MARKET_POTION_SHOP, + MARKET_BACK_ALLEY, + MARKET_BOMBCHU_SHOP, + MARKET_DOG_LADY_HOUSE, + MARKET_MAN_IN_GREEN_HOUSE, + TOT_ENTRANCE, + TEMPLE_OF_TIME, + TOT_BEYOND_DOOR_OF_TIME, + CASTLE_GROUNDS, + HYRULE_CASTLE_GROUNDS, + HC_GARDEN, + HC_GREAT_FAIRY_FOUNTAIN, + HC_STORMS_GROTTO, + GANONS_CASTLE_GROUNDS, + OGC_GREAT_FAIRY_FOUNTAIN, + KAKARIKO_VILLAGE, + KAK_CARPENTER_BOSS_HOUSE, + KAK_HOUSE_OF_SKULLTULA, + KAK_IMPAS_HOUSE, + KAK_IMPAS_LEDGE, + KAK_IMPAS_HOUSE_BACK, + KAK_IMPAS_HOUSE_NEAR_COW, + KAK_WINDMILL, + KAK_BAZAAR, + KAK_SHOOTING_GALLERY, + KAK_POTION_SHOP_FRONT, + KAK_POTION_SHOP_BACK, + KAK_ROOFTOP, + KAK_BEHIND_GATE, + KAK_BACKYARD, + KAK_ODD_POTION_BUILDING, + KAK_REDEAD_GROTTO, + KAK_OPEN_GROTTO, + THE_GRAVEYARD, + GRAVEYARD_DAMPES_GRAVE, + GRAVEYARD_DAMPES_HOUSE, + GRAVEYARD_SHIELD_GRAVE, + GRAVEYARD_COMPOSERS_GRAVE, + GRAVEYARD_HEART_PIECE_GRAVE, + GRAVEYARD_WARP_PAD_REGION, + DEATH_MOUNTAIN_TRAIL, + DEATH_MOUNTAIN_SUMMIT, + DMT_OWL_FLIGHT, + DMT_GREAT_FAIRY_FOUNTAIN, + DMT_COW_GROTTO, + DMT_STORMS_GROTTO, + GORON_CITY, + GC_WOODS_WARP, + GC_DARUNIAS_CHAMBER, + GC_GROTTO_PLATFORM, + GC_SHOP, + GC_GROTTO, + DMC_UPPER_LOCAL, + DMC_CENTRAL_LOCAL, + DMC_LOWER_LOCAL, + DMC_LOWER_NEARBY, + DMC_UPPER_NEARBY, + DMC_CENTRAL_NEARBY, + DMC_LADDER_AREA_NEARBY, + DMC_UPPER_GROTTO, + DMC_HAMMER_GROTTO, + DMC_GREAT_FAIRY_FOUNTAIN, + ZR_FRONT, + ZORAS_RIVER, + ZR_BEHIND_WATERFALL, + ZR_OPEN_GROTTO, + ZR_FAIRY_GROTTO, + ZR_STORMS_GROTTO, + ZORAS_DOMAIN, + ZD_BEHIND_KING_ZORA, + ZD_SHOP, + ZD_STORMS_GROTTO, + ZORAS_FOUNTAIN, + ZF_GREAT_FAIRY_FOUNTAIN, + LON_LON_RANCH, + LLR_TALONS_HOUSE, + LLR_STABLES, + LLR_TOWER, + LLR_GROTTO, + + DEKU_TREE_ENTRYWAY, + DODONGOS_CAVERN_ENTRYWAY, + JABU_JABUS_BELLY_ENTRYWAY, + FOREST_TEMPLE_ENTRYWAY, + FIRE_TEMPLE_ENTRYWAY, + WATER_TEMPLE_ENTRYWAY, + SPIRIT_TEMPLE_ENTRYWAY, + SHADOW_TEMPLE_ENTRYWAY, + BOTTOM_OF_THE_WELL_ENTRYWAY, + ICE_CAVERN_ENTRYWAY, + GERUDO_TRAINING_GROUNDS_ENTRYWAY, + GANONS_CASTLE_ENTRYWAY, + + DEKU_TREE_LOBBY, + DEKU_TREE_2F_MIDDLE_ROOM, + DEKU_TREE_SLINGSHOT_ROOM, + DEKU_TREE_COMPASS_ROOM, + DEKU_TREE_BASEMENT_LOWER, + DEKU_TREE_BASEMENT_SCRUB_ROOM, + DEKU_TREE_BASEMENT_WATER_ROOM, + DEKU_TREE_BASEMENT_TORCH_ROOM, + DEKU_TREE_BASEMENT_BACK_LOBBY, + DEKU_TREE_BASEMENT_BACK_ROOM, + DEKU_TREE_BASEMENT_UPPER, + DEKU_TREE_OUTSIDE_BOSS_ROOM, + DEKU_TREE_BOSS_ROOM, + + DODONGOS_CAVERN_BEGINNING, + DODONGOS_CAVERN_LOBBY, + DODONGOS_CAVERN_LOBBY_SWITCH, + DODONGOS_CAVERN_SE_CORRIDOR, + DODONGOS_CAVERN_SE_ROOM, + DODONGOS_CAVERN_NEAR_LOWER_LIZALFOS, + DODONGOS_CAVERN_LOWER_LIZALFOS, + DODONGOS_CAVERN_DODONGO_ROOM, + DODONGOS_CAVERN_NEAR_DODONGO_ROOM, + DODONGOS_CAVERN_STAIRS_LOWER, + DODONGOS_CAVERN_STAIRS_UPPER, + DODONGOS_CAVERN_COMPASS_ROOM, + DODONGOS_CAVERN_ARMOS_ROOM, + DODONGOS_CAVERN_BOMB_ROOM_LOWER, + DODONGOS_CAVERN_2F_SIDE_ROOM, + DODONGOS_CAVERN_FIRST_SLINGSHOT_ROOM, + DODONGOS_CAVERN_UPPER_LIZALFOS, + DODONGOS_CAVERN_SECOND_SLINGSHOT_ROOM, + DODONGOS_CAVERN_BOMB_ROOM_UPPER, + DODONGOS_CAVERN_FAR_BRIDGE, + DODONGOS_CAVERN_BOSS_AREA, + DODONGOS_CAVERN_BACK_ROOM, + DODONGOS_CAVERN_BOSS_ROOM, + + JABU_JABUS_BELLY_BEGINNING, + JABU_JABUS_BELLY_LIFT_MIDDLE, + JABU_JABUS_BELLY_MAIN_UPPER, + JABU_JABUS_BELLY_MAIN_LOWER, + JABU_JABUS_BELLY_SHABOMB_CORRIDOR, + JABU_JABUS_BELLY_LOWER_SIDE_ROOM, + JABU_JABUS_BELLY_LIFT_LOWER, + JABU_JABUS_BELLY_FORKED_CORRIDOR, + JABU_JABUS_BELLY_BOOMERANG_ROOM, + JABU_JABUS_BELLY_MAP_ROOM, + JABU_JABUS_BELLY_COMPASS_ROOM, + JABU_JABUS_BELLY_BLUE_TENTACLE, + JABU_JABUS_BELLY_GREEN_TENTACLE, + JABU_JABUS_BELLY_BIGOCTO_ROOM, + JABU_JABUS_BELLY_ABOVE_BIGOCTO, + JABU_JABUS_BELLY_LIFT_UPPER, + JABU_JABUS_BELLY_NEAR_BOSS_ROOM, + JABU_JABUS_BELLY_BOSS_ROOM, + + FOREST_TEMPLE_FIRST_ROOM, + FOREST_TEMPLE_SOUTH_CORRIDOR, + FOREST_TEMPLE_LOBBY, + FOREST_TEMPLE_NORTH_CORRIDOR, + FOREST_TEMPLE_LOWER_STALFOS, + FOREST_TEMPLE_NW_OUTDOORS_LOWER, + FOREST_TEMPLE_NW_OUTDOORS_UPPER, + FOREST_TEMPLE_NE_OUTDOORS_LOWER, + FOREST_TEMPLE_NE_OUTDOORS_UPPER, + FOREST_TEMPLE_MAP_ROOM, + FOREST_TEMPLE_SEWER, + FOREST_TEMPLE_BELOW_BOSS_KEY_CHEST, + FOREST_TEMPLE_FLOORMASTER_ROOM, + FOREST_TEMPLE_WEST_CORRIDOR, + FOREST_TEMPLE_BLOCK_PUSH_ROOM, + FOREST_TEMPLE_NW_CORRIDOR_TWISTED, + FOREST_TEMPLE_NW_CORRIDOR_STRAIGHTENED, + FOREST_TEMPLE_RED_POE_ROOM, + FOREST_TEMPLE_UPPER_STALFOS, + FOREST_TEMPLE_BLUE_POE_ROOM, + FOREST_TEMPLE_NE_CORRIDOR_STRAIGHTENED, + FOREST_TEMPLE_NE_CORRIDOR_TWISTED, + FOREST_TEMPLE_FROZEN_EYE_ROOM, + FOREST_TEMPLE_FALLING_ROOM, + FOREST_TEMPLE_GREEN_POE_ROOM, + FOREST_TEMPLE_EAST_CORRIDOR, + FOREST_TEMPLE_BOSS_REGION, + FOREST_TEMPLE_BOSS_ROOM, + + FIRE_TEMPLE_FIRST_ROOM, + FIRE_TEMPLE_NEAR_BOSS_ROOM, + FIRE_TEMPLE_BOSS_ROOM, + FIRE_TEMPLE_LOOP_ENEMIES, + FIRE_TEMPLE_LOOP_TILES, + FIRE_TEMPLE_LOOP_FLARE_DANCER, + FIRE_TEMPLE_LOOP_HAMMER_SWITCH, + FIRE_TEMPLE_LOOP_GORON_ROOM, + FIRE_TEMPLE_LOOP_EXIT, + FIRE_TEMPLE_BIG_LAVA_ROOM, + FIRE_TEMPLE_BIG_LAVA_ROOM_NORTH_GORON, + FIRE_TEMPLE_BIG_LAVA_ROOM_NORTH_TILES, + FIRE_TEMPLE_BIG_LAVA_ROOM_SOUTH_GORON, + FIRE_TEMPLE_FIRE_PILLAR_ROOM, + FIRE_TEMPLE_SHORTCUT_ROOM, + FIRE_TEMPLE_SHORTCUT_CLIMB, + FIRE_TEMPLE_BOULDER_MAZE_LOWER, + FIRE_TEMPLE_BOULDER_MAZE_LOWER_SIDE_ROOM, + FIRE_TEMPLE_EAST_CENTRAL_ROOM, + FIRE_TEMPLE_FIRE_WALL_CHASE, + FIRE_TEMPLE_MAP_AREA, + FIRE_TEMPLE_BOULDER_MAZE_UPPER, + FIRE_TEMPLE_SCARECROW_ROOM, + FIRE_TEMPLE_EAST_PEAK, + FIRE_TEMPLE_CORRIDOR, + FIRE_TEMPLE_FIRE_MAZE_ROOM, + FIRE_TEMPLE_FIRE_MAZE_UPPER, + FIRE_TEMPLE_FIRE_MAZE_SIDE_ROOM, + FIRE_TEMPLE_WEST_CENTRAL_LOWER, + FIRE_TEMPLE_WEST_CENTRAL_UPPER, + FIRE_TEMPLE_LATE_FIRE_MAZE, + FIRE_TEMPLE_UPPER_FLARE_DANCER, + FIRE_TEMPLE_WEST_CLIMB, + FIRE_TEMPLE_WEST_PEAK, + FIRE_TEMPLE_HAMMER_RETURN_PATH, + FIRE_TEMPLE_ABOVE_FIRE_MAZE, + + WATER_TEMPLE_LOBBY, + WATER_TEMPLE_EAST_LOWER, + WATER_TEMPLE_MAP_ROOM, + WATER_TEMPLE_CRACKED_WALL, + WATER_TEMPLE_TORCH_ROOM, + WATER_TEMPLE_NORTH_LOWER, + WATER_TEMPLE_BOULDERS_LOWER, + WATER_TEMPLE_BLOCK_ROOM, + WATER_TEMPLE_JETS_ROOM, + WATER_TEMPLE_BOULDERS_UPPER, + WATER_TEMPLE_BOSS_KEY_ROOM, + WATER_TEMPLE_SOUTH_LOWER, + WATER_TEMPLE_WEST_LOWER, + WATER_TEMPLE_DRAGON_ROOM, + WATER_TEMPLE_CENTRAL_PILLAR_LOWER, + WATER_TEMPLE_CENTRAL_PILLAR_UPPER, + WATER_TEMPLE_CENTRAL_PILLAR_BASEMENT, + WATER_TEMPLE_EAST_MIDDLE, + WATER_TEMPLE_WEST_MIDDLE, + WATER_TEMPLE_HIGH_WATER, + WATER_TEMPLE_BLOCK_CORRIDOR, + WATER_TEMPLE_FALLING_PLATFORM_ROOM, + WATER_TEMPLE_DRAGON_PILLARS_ROOM, + WATER_TEMPLE_DARK_LINK_ROOM, + WATER_TEMPLE_LONGSHOT_ROOM, + WATER_TEMPLE_RIVER, + WATER_TEMPLE_PRE_BOSS_ROOM, + WATER_TEMPLE_BOSS_ROOM, + + SPIRIT_TEMPLE_LOBBY, + SPIRIT_TEMPLE_CHILD, + SPIRIT_TEMPLE_CHILD_CLIMB, + SPIRIT_TEMPLE_EARLY_ADULT, + SPIRIT_TEMPLE_CENTRAL_CHAMBER, + SPIRIT_TEMPLE_OUTDOOR_HANDS, + SPIRIT_TEMPLE_BEYOND_CENTRAL_LOCKED_DOOR, + SPIRIT_TEMPLE_BEYOND_FINAL_LOCKED_DOOR, + + SHADOW_TEMPLE_BEGINNING, + SHADOW_TEMPLE_FIRST_BEAMOS, + SHADOW_TEMPLE_HUGE_PIT, + SHADOW_TEMPLE_WIND_TUNNEL, + SHADOW_TEMPLE_BEYOND_BOAT, + + BOTTOM_OF_THE_WELL, + BOTTOM_OF_THE_WELL_MAIN_AREA, + + ICE_CAVERN_BEGINNING, + ICE_CAVERN_MAIN, + + GERUDO_TRAINING_GROUNDS_LOBBY, + GERUDO_TRAINING_GROUNDS_CENTRAL_MAZE, + GERUDO_TRAINING_GROUNDS_CENTRAL_MAZE_RIGHT, + GERUDO_TRAINING_GROUNDS_LAVA_ROOM, + GERUDO_TRAINING_GROUNDS_HAMMER_ROOM, + GERUDO_TRAINING_GROUNDS_EYE_STATUE_LOWER, + GERUDO_TRAINING_GROUNDS_EYE_STATUE_UPPER, + GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_ROOM, + GERUDO_TRAINING_GROUNDS_LIKE_LIKE_ROOM, + + GANONS_CASTLE_LOBBY, + GANONS_CASTLE_DEKU_SCRUBS, + GANONS_CASTLE_FOREST_TRIAL, + GANONS_CASTLE_FIRE_TRIAL, + GANONS_CASTLE_WATER_TRIAL, + GANONS_CASTLE_SHADOW_TRIAL, + GANONS_CASTLE_SPIRIT_TRIAL, + GANONS_CASTLE_LIGHT_TRIAL, + GANONS_CASTLE_TOWER, + + DEKU_TREE_MQ_LOBBY, + DEKU_TREE_MQ_COMPASS_ROOM, + DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT, + DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK, + DEKU_TREE_MQ_BASEMENT_BACK_ROOM, + DEKU_TREE_MQ_BASEMENT_LEDGE, + + DODONGOS_CAVERN_MQ_BEGINNING, + DODONGOS_CAVERN_MQ_LOBBY, + DODONGOS_CAVERN_MQ_LOWER_RIGHT_SIDE, + DODONGOS_CAVERN_MQ_BOMB_BAG_AREA, + DODONGOS_CAVERN_MQ_BOSS_AREA, + + JABU_JABUS_BELLY_MQ_BEGINNING, + JABU_JABUS_BELLY_MQ_MAIN, + JABU_JABUS_BELLY_MQ_DEPTHS, + JABU_JABUS_BELLY_MQ_BOSS_AREA, + + FOREST_TEMPLE_MQ_LOBBY, + FOREST_TEMPLE_MQ_CENTRAL_AREA, + FOREST_TEMPLE_MQ_AFTER_BLOCK_PUZZLE, + FOREST_TEMPLE_MQ_OUTDOOR_LEDGE, + FOREST_TEMPLE_MQ_NW_OUTDOORS, + FOREST_TEMPLE_MQ_NE_OUTDOORS, + FOREST_TEMPLE_MQ_OUTDOORS_TOP_LEDGES, + FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE, + FOREST_TEMPLE_MQ_BOW_REGION, + FOREST_TEMPLE_MQ_FALLING_ROOM, + FOREST_TEMPLE_MQ_BOSS_REGION, + + FIRE_TEMPLE_MQ_LOWER, + FIRE_TEMPLE_MQ_LOWER_LOCKED_DOOR, + FIRE_TEMPLE_MQ_BIG_LAVA_ROOM, + FIRE_TEMPLE_MQ_LOWER_MAZE, + FIRE_TEMPLE_MQ_UPPER_MAZE, + FIRE_TEMPLE_MQ_UPPER, + FIRE_TEMPLE_MQ_BOSS_ROOM, + + WATER_TEMPLE_MQ_LOBBY, + WATER_TEMPLE_MQ_DIVE, + WATER_TEMPLE_MQ_LOWERED_WATER_LEVELS, + WATER_TEMPLE_MQ_DARK_LINK_REGION, + WATER_TEMPLE_MQ_BASEMENT_GATED_AREAS, + + SPIRIT_TEMPLE_MQ_LOBBY, + SPIRIT_TEMPLE_MQ_CHILD, + SPIRIT_TEMPLE_MQ_ADULT, + SPIRIT_TEMPLE_MQ_SHARED, + SPIRIT_TEMPLE_MQ_LOWER_ADULT, + SPIRIT_TEMPLE_MQ_BOSS_AREA, + SPIRIT_TEMPLE_MQ_MIRROR_SHIELD_HAND, + SPIRIT_TEMPLE_MQ_SILVER_GAUNTLETS_HAND, + + SHADOW_TEMPLE_MQ_ENTRYWAY, + SHADOW_TEMPLE_MQ_BEGINNING, + SHADOW_TEMPLE_MQ_DEAD_HAND_AREA, + SHADOW_TEMPLE_MQ_FIRST_BEAMOS, + SHADOW_TEMPLE_MQ_UPPER_HUGE_PIT, + SHADOW_TEMPLE_MQ_LOWER_HUGE_PIT, + SHADOW_TEMPLE_MQ_WIND_TUNNEL, + SHADOW_TEMPLE_MQ_BEYOND_BOAT, + SHADOW_TEMPLE_MQ_INVISIBLE_MAZE, + + BOTTOM_OF_THE_WELL_MQ, + BOTTOM_OF_THE_WELL_MQ_PERIMETER, + BOTTOM_OF_THE_WELL_MQ_MIDDLE, + + ICE_CAVERN_MQ_BEGINNING, + ICE_CAVERN_MQ_MAP_ROOM, + ICE_CAVERN_MQ_IRON_BOOTS_REGION, + ICE_CAVERN_MQ_COMPASS_ROOM, + + GERUDO_TRAINING_GROUNDS_MQ_LOBBY, + GERUDO_TRAINING_GROUNDS_MQ_RIGHT_SIDE, + GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER, + GERUDO_TRAINING_GROUNDS_MQ_LEFT_SIDE, + GERUDO_TRAINING_GROUNDS_MQ_STALFOS_ROOM, + GERUDO_TRAINING_GROUNDS_MQ_BACK_AREAS, + GERUDO_TRAINING_GROUNDS_MQ_CENTRAL_MAZE_RIGHT, + + GANONS_CASTLE_MQ_LOBBY, + GANONS_CASTLE_MQ_DEKU_SCRUBS, + GANONS_CASTLE_MQ_FOREST_TRIAL, + GANONS_CASTLE_MQ_FIRE_TRIAL, + GANONS_CASTLE_MQ_WATER_TRIAL, + GANONS_CASTLE_MQ_SHADOW_TRIAL, + GANONS_CASTLE_MQ_SPIRIT_TRIAL, + GANONS_CASTLE_MQ_LIGHT_TRIAL, + + //DUNGEONS + DEKU_TREE, + DODONGOS_CAVERN, + JABU_JABUS_BELLY, + FOREST_TEMPLE, + FIRE_TEMPLE, + WATER_TEMPLE, + SPIRIT_TEMPLE, + SHADOW_TEMPLE, + ICE_CAVERN, + //BOTTOM_OF_THE_WELL, + GERUDO_TRAINING_GROUNDS, + GANONS_CASTLE, + + //HINTS + PREFIX, + WAY_OF_THE_HERO, + PLUNDERING, + FOOLISH, + CAN_BE_FOUND_AT, + HOARDS, + + JUNK01, + JUNK02, + JUNK03, + JUNK04, + JUNK05, + JUNK06, + JUNK07, + JUNK08, + JUNK09, + JUNK10, + JUNK11, + JUNK12, + JUNK13, + JUNK14, + JUNK15, + JUNK16, + JUNK17, + JUNK18, + JUNK19, + JUNK20, + JUNK21, + JUNK22, + JUNK23, + JUNK24, + JUNK25, + JUNK26, + JUNK27, + JUNK28, + JUNK29, + JUNK30, + JUNK31, + JUNK32, + JUNK33, + JUNK34, + JUNK35, + JUNK36, + JUNK37, + JUNK38, + JUNK39, + JUNK40, + JUNK41, + JUNK42, + JUNK43, + JUNK44, + JUNK45, + JUNK46, + JUNK47, + JUNK48, + JUNK49, + JUNK50, + JUNK51, + JUNK52, + JUNK53, + JUNK54, + JUNK55, + JUNK56, + JUNK57, + JUNK58, + JUNK59, + JUNK60, + JUNK61, + JUNK62, + JUNK63, + JUNK64, + JUNK65, + JUNK66, + JUNK67, + JUNK68, + JUNK69, + JUNK70, + JUNK71, + JUNK72, + JUNK73, + JUNK74, + JUNK75, + JUNK76, + JUNK77, + JUNK78, + JUNK79, + JUNK80, + JUNK81, + + BRIDGE_OPEN_HINT, + BRIDGE_VANILLA_HINT, + BRIDGE_STONES_HINT, + BRIDGE_MEDALLIONS_HINT, + BRIDGE_REWARDS_HINT, + BRIDGE_DUNGEONS_HINT, + BRIDGE_TOKENS_HINT, + + GANON_BK_START_WITH_HINT, + GANON_BK_VANILLA_HINT, + GANON_BK_OWN_DUNGEON_HINT, + GANON_BK_OVERWORLD_HINT, + GANON_BK_ANY_DUNGEON_HINT, + GANON_BK_ANYWHERE_HINT, + GANON_BK_TRIFORCE_HINT, + + LACS_VANILLA_HINT, + LACS_MEDALLIONS_HINT, + LACS_STONES_HINT, + LACS_REWARDS_HINT, + LACS_DUNGEONS_HINT, + LACS_TOKENS_HINT, + + SIX_TRIALS, + ZERO_TRIALS, + FOUR_TO_FIVE_TRIALS, + ONE_TO_THREE_TRIALS, + + SPIRITUAL_STONE_TEXT_START, + CHILD_ALTAR_TEXT_END_DOTOPEN, + CHILD_ALTAR_TEXT_END_DOTCLOSED, + CHILD_ALTAR_TEXT_END_DOTINTENDED, + ADULT_ALTAR_TEXT_START, + ADULT_ALTAR_TEXT_END, + + VALIDATION_LINE, + LIGHT_ARROW_LOCATION_HINT, + YOUR_POCKET, + + GANON_LINE01, + GANON_LINE02, + GANON_LINE03, + GANON_LINE04, + GANON_LINE05, + GANON_LINE06, + GANON_LINE07, + GANON_LINE08, + GANON_LINE09, + GANON_LINE10, + GANON_LINE11, + + MEDIGORON_DIALOG_FIRST, + MEDIGORON_DIALOG_SECOND, + CARPET_SALESMAN_DIALOG_FIRST, + CARPET_SALESMAN_DIALOG_SECOND, + CARPET_SALESMAN_DIALOG_THIRD, + CARPET_SALESMAN_DIALOG_FOURTH, + + KEY_ENUM_MAX, +} Key; \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access.cpp new file mode 100644 index 000000000..c4506a66d --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access.cpp @@ -0,0 +1,898 @@ +#include "location_access.hpp" + +#include "dungeon.hpp" +#include "item_list.hpp" +#include "item_location.hpp" +#include "item_pool.hpp" +#include "logic.hpp" +#include "settings.hpp" +#include "spoiler_log.hpp" +#include "trial.hpp" +#include "entrance.hpp" + +#include +#include + +using namespace Logic; +using namespace Settings; + +//generic grotto event list +std::vector grottoEvents = { + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || CanSummonGossipFairy;}}), + EventAccess(&ButterflyFairy, {[]{return ButterflyFairy || (CanUse(STICKS));}}), + EventAccess(&BugShrub, {[]{return CanCutShrubs;}}), + EventAccess(&LoneFish, {[]{return true;}}), +}; + +//set the logic to be a specific age and time of day and see if the condition still holds +bool LocationAccess::CheckConditionAtAgeTime(bool& age, bool& time) const { + + IsChild = false; + IsAdult = false; + AtDay = false; + AtNight = false; + + time = true; + age = true; + + UpdateHelpers(); + return GetConditionsMet(); +} + +bool LocationAccess::ConditionsMet() const { + + Area* parentRegion = AreaTable(Location(location)->GetParentRegionKey()); + bool conditionsMet = false; + + if ((parentRegion->childDay && CheckConditionAtAgeTime(IsChild, AtDay)) || + (parentRegion->childNight && CheckConditionAtAgeTime(IsChild, AtNight)) || + (parentRegion->adultDay && CheckConditionAtAgeTime(IsAdult, AtDay)) || + (parentRegion->adultNight && CheckConditionAtAgeTime(IsAdult, AtNight))) { + conditionsMet = true; + } + + return conditionsMet && CanBuy(); +} + +bool LocationAccess::CanBuy() const { + //Not a shop location, don't need to check if buyable + if (!(Location(location)->IsCategory(Category::cShop))) { + return true; + } + + //Check if wallet is large enough to buy item + bool SufficientWallet = true; + if (Location(location)->GetPrice() > 500) { + SufficientWallet = ProgressiveWallet >= 3; + } else if (Location(location)->GetPrice() > 200) { + SufficientWallet = ProgressiveWallet >= 2; + } else if (Location(location)->GetPrice() > 99) { + SufficientWallet = ProgressiveWallet >= 1; + } + + bool OtherCondition = true; + uint32_t placed = Location(location)->GetPlacedItemKey(); + //Need bottle to buy bottle items, only logically relevant bottle items included here + if (placed == BUY_BLUE_FIRE || placed == BUY_BOTTLE_BUG || placed == BUY_FISH || placed == BUY_FAIRYS_SPIRIT) { + OtherCondition = HasBottle; + } + //If bombchus in logic, need to have found chus to buy; if not just need bomb bag + else if (placed == BUY_BOMBCHU_5 || placed == BUY_BOMBCHU_10 || placed == BUY_BOMBCHU_20) { + OtherCondition = (!BombchusInLogic && Bombs) || (BombchusInLogic && FoundBombchus); + } + + return SufficientWallet && OtherCondition; +} + +Area::Area() = default; +Area::Area(std::string regionName_, std::string scene_, uint32_t hintKey_, + bool timePass_, + std::vector events_, + std::vector locations_, + std::list exits_) + : regionName(std::move(regionName_)), + scene(std::move(scene_)), + hintKey(hintKey_), + timePass(timePass_), + events(std::move(events_)), + locations(std::move(locations_)), + exits(std::move(exits_)) {} + +Area::~Area() = default; + +bool Area::UpdateEvents(SearchMode mode) { + + if (timePass && mode != SearchMode::TimePassAccess) { + if (Child()) { + childDay = true; + childNight = true; + AreaTable(ROOT)->childDay = true; + AreaTable(ROOT)->childNight = true; + } + if (Adult()) { + adultDay = true; + adultNight = true; + AreaTable(ROOT)->adultDay = true; + AreaTable(ROOT)->adultNight = true; + } + } + + bool eventsUpdated = false; + + for (EventAccess& event : events) { + //If the event has already happened, there's no reason to check it + if (event.GetEvent()) { + continue; + } + + if ((childDay && event.CheckConditionAtAgeTime(IsChild, AtDay)) || + (childNight && event.CheckConditionAtAgeTime(IsChild, AtNight)) || + (adultDay && event.CheckConditionAtAgeTime(IsAdult, AtDay)) || + (adultNight && event.CheckConditionAtAgeTime(IsAdult, AtNight))) { + event.EventOccurred(); + eventsUpdated = true; + } + } + return eventsUpdated; +} + +void Area::AddExit(uint32_t parentKey, uint32_t newExitKey, ConditionFn condition) { + Entrance newExit = Entrance(newExitKey, {condition}); + newExit.SetParentRegion(parentKey); + exits.push_front(newExit); +} + +//The exit will be completely removed from this area +void Area::RemoveExit(Entrance* exitToRemove) { + exits.remove_if([exitToRemove](const auto exit){return &exit == exitToRemove;}); +} + +void Area::SetAsPrimary(uint32_t exitToBePrimary) { + for (auto& exit : exits) { + if (exit.Getuint32_t() == exitToBePrimary) { + exit.SetAsPrimary(); + return; + } + } +} + +Entrance* Area::GetExit(uint32_t exitToReturn) { + for (auto& exit : exits) { + if (exit.Getuint32_t() == exitToReturn) { + return &exit; + } + } + auto message = "ERROR: EXIT " + AreaTable(exitToReturn)->regionName + " DOES NOT EXIST IN " + this->regionName; + CitraPrint(message); + return nullptr; +} + +bool Area::CanPlantBeanCheck() const { + return (Logic::MagicBean || Logic::MagicBeanPack) && BothAgesCheck(); +} + +bool Area::AllAccountedFor() const { + for (const EventAccess& event : events) { + if (!event.GetEvent()) { + return false; + } + } + + for (const LocationAccess& loc : locations) { + if (!(Location(loc.GetLocation())->IsAddedToPool())) { + return false; + } + } + + for (const auto& exit : exits) { + if (!exit.GetConnectedRegion()->AllAccess()) { + return false; + } + } + + return AllAccess(); +} + +bool Area::CheckAllAccess(const uint32_t exitKey) { + if (!AllAccess()) { + return false; + } + + for (Entrance& exit : exits) { + if (exit.Getuint32_t() == exitKey) { + return exit.CheckConditionAtAgeTime(Logic::IsChild, Logic::AtDay) && + exit.CheckConditionAtAgeTime(Logic::IsChild, Logic::AtNight) && + exit.CheckConditionAtAgeTime(Logic::IsAdult, Logic::AtDay) && + exit.CheckConditionAtAgeTime(Logic::IsAdult, Logic::AtNight); + } + } + return false; +} + +void Area::ResetVariables() { + childDay = false; + childNight = false; + adultDay = false; + adultNight = false; + addedToPool = false; + for (auto& exit : exits) { + exit.RemoveFromPool(); + } +} + +std::array areaTable; + +bool Here(const uint32_t area, ConditionFn condition) { + return areaTable[area].HereCheck(condition); +} + +bool CanPlantBean(const uint32_t area) { + return areaTable[area].CanPlantBeanCheck(); +} + +bool BothAges(const uint32_t area) { + return areaTable[area].BothAgesCheck(); +} + +bool ChildCanAccess(const uint32_t area) { + return areaTable[area].Child(); +} + +bool AdultCanAccess(const uint32_t area) { + return areaTable[area].Adult(); +} + +bool HasAccessTo(const uint32_t area) { + return areaTable[area].HasAccess(); +} + + + +void AreaTable_Init() { + //Clear the array from any previous playthrough attempts. This is important so that + //locations which appear in both MQ and Vanilla dungeons don't get set in both areas. + areaTable.fill(Area("Invalid Area", "Invalid Area", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, {})); + + //name, scene, hint text, events, locations, exits + areaTable[ROOT] = Area("Root", "", LINKS_POCKET, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(LINKS_POCKET, {[]{return true;}}) + }, { + //Exits + Entrance(ROOT_EXITS, {[]{return true;}}) + }); + + areaTable[ROOT_EXITS] = Area("Root Exits", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(KF_LINKS_HOUSE, {[]{return IsChild;}}), + Entrance(TEMPLE_OF_TIME, {[]{return (CanPlay(PreludeOfLight) && CanLeaveForest) || IsAdult;}, + /*Glitched*/[]{return (((IsChild && (ChildCanAccess(KOKIRI_FOREST) || ChildCanAccess(HYRULE_FIELD) || ChildCanAccess(LAKE_HYLIA))) || (IsAdult && (AdultCanAccess(KOKIRI_FOREST) || AdultCanAccess(HYRULE_FIELD) || AdultCanAccess(LAKE_HYLIA)))) && (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::NOVICE) || + ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && (IsAdult || KokiriSword || Sticks || Bombs || HasBombchus || Boomerang || Slingshot || CanUse(MEGATON_HAMMER)) && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::NOVICE)))) && PreludeOfLight && CanLeaveForest;}}), + Entrance(SACRED_FOREST_MEADOW, {[]{return CanPlay(MinuetOfForest);}, + /*Glitched*/[]{return (((IsChild && (ChildCanAccess(KOKIRI_FOREST) || ChildCanAccess(HYRULE_FIELD) || ChildCanAccess(LAKE_HYLIA))) || (IsAdult && (AdultCanAccess(KOKIRI_FOREST) || AdultCanAccess(HYRULE_FIELD) || AdultCanAccess(LAKE_HYLIA)))) && (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::NOVICE) || + ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && (IsAdult || KokiriSword || Sticks || Bombs || HasBombchus || Boomerang || Slingshot || CanUse(MEGATON_HAMMER)) && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::NOVICE)))) && MinuetOfForest;}}), + Entrance(DMC_CENTRAL_LOCAL, {[]{return CanPlay(BoleroOfFire) && CanLeaveForest;}, + /*Glitched*/[]{return (((IsChild && (ChildCanAccess(KOKIRI_FOREST) || ChildCanAccess(HYRULE_FIELD) || ChildCanAccess(LAKE_HYLIA))) || (IsAdult && (AdultCanAccess(KOKIRI_FOREST) || AdultCanAccess(HYRULE_FIELD) || AdultCanAccess(LAKE_HYLIA)))) && (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::NOVICE) || + ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && (IsAdult || KokiriSword || Sticks || Bombs || HasBombchus || Boomerang || Slingshot || CanUse(MEGATON_HAMMER)) && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::NOVICE)))) && BoleroOfFire && CanLeaveForest;}}), + Entrance(LAKE_HYLIA, {[]{return CanPlay(SerenadeOfWater) && CanLeaveForest;}, + /*Glitched*/[]{return (((IsChild && (ChildCanAccess(KOKIRI_FOREST) || ChildCanAccess(HYRULE_FIELD) || ChildCanAccess(LAKE_HYLIA))) || (IsAdult && (AdultCanAccess(KOKIRI_FOREST) || AdultCanAccess(HYRULE_FIELD) || AdultCanAccess(LAKE_HYLIA)))) && (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::NOVICE) || + ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && (IsAdult || KokiriSword || Sticks || Bombs || HasBombchus || Boomerang || Slingshot || CanUse(MEGATON_HAMMER)) && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::NOVICE)))) && SerenadeOfWater && CanLeaveForest;}}), + Entrance(GRAVEYARD_WARP_PAD_REGION, {[]{return CanPlay(NocturneOfShadow) && CanLeaveForest;}, + /*Glitched*/[]{return (((IsChild && (ChildCanAccess(KOKIRI_FOREST) || ChildCanAccess(HYRULE_FIELD) || ChildCanAccess(LAKE_HYLIA))) || (IsAdult && (AdultCanAccess(KOKIRI_FOREST) || AdultCanAccess(HYRULE_FIELD) || AdultCanAccess(LAKE_HYLIA)))) && (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::NOVICE) || + ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && (IsAdult || KokiriSword || Sticks || Bombs || HasBombchus || Boomerang || Slingshot || CanUse(MEGATON_HAMMER)) && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::NOVICE)))) && NocturneOfShadow && CanLeaveForest;}}), + Entrance(DESERT_COLOSSUS, {[]{return CanPlay(RequiemOfSpirit) && CanLeaveForest;}, + /*Glitched*/[]{return (((IsChild && (ChildCanAccess(KOKIRI_FOREST) || ChildCanAccess(HYRULE_FIELD) || ChildCanAccess(LAKE_HYLIA))) || (IsAdult && (AdultCanAccess(KOKIRI_FOREST) || AdultCanAccess(HYRULE_FIELD) || AdultCanAccess(LAKE_HYLIA)))) && (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::NOVICE) || + ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && (IsAdult || KokiriSword || Sticks || Bombs || HasBombchus || Boomerang || Slingshot || CanUse(MEGATON_HAMMER)) && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::NOVICE)))) && RequiemOfSpirit && CanLeaveForest;}}), + }); + + // Overworld + AreaTable_Init_LostWoods(); + AreaTable_Init_HyruleField(); + AreaTable_Init_CastleTown(); + AreaTable_Init_Kakariko(); + AreaTable_Init_DeathMountain(); + AreaTable_Init_ZorasDomain(); + AreaTable_Init_GerudoValley(); + // Dungeons + AreaTable_Init_DekuTree(); + AreaTable_Init_DodongosCavern(); + AreaTable_Init_JabuJabusBelly(); + AreaTable_Init_ForestTemple(); + AreaTable_Init_FireTemple(); + AreaTable_Init_WaterTemple(); + AreaTable_Init_SpiritTemple(); + AreaTable_Init_ShadowTemple(); + AreaTable_Init_BottomOfTheWell(); + AreaTable_Init_IceCavern(); + AreaTable_Init_GerudoTrainingGrounds(); + AreaTable_Init_GanonsCastle(); + + //Set parent regions + for (uint32_t i = ROOT; i <= GANONS_CASTLE; i++) { + for (LocationAccess& locPair : areaTable[i].locations) { + uint32_t location = locPair.GetLocation(); + Location(location)->SetParentRegion(i); + } + for (Entrance& exit : areaTable[i].exits) { + exit.SetParentRegion(i); + exit.SetName(); + exit.GetConnectedRegion()->entrances.push_front(&exit); + } + } + /* + //Events +}, { + //Locations +}, { + //Exits +*/ +} + +namespace Areas { + + static std::array allAreas = { + ROOT, + ROOT_EXITS, + + KOKIRI_FOREST, + KF_LINKS_HOUSE, + KF_MIDOS_HOUSE, + KF_SARIAS_HOUSE, + KF_HOUSE_OF_TWINS, + KF_KNOW_IT_ALL_HOUSE, + KF_KOKIRI_SHOP, + KF_STORMS_GROTTO, + KF_OUTSIDE_DEKU_TREE, + DEKU_TREE_ENTRYWAY, + + THE_LOST_WOODS, + LW_BRIDGE_FROM_FOREST, + LW_BRIDGE, + LW_FOREST_EXIT, + LW_BEYOND_MIDO, + LW_NEAR_SHORTCUTS_GROTTO, + DEKU_THEATER, + LW_SCRUBS_GROTTO, + SFM_ENTRYWAY, + SACRED_FOREST_MEADOW, + SFM_WOLFOS_GROTTO, + SFM_FAIRY_GROTTO, + SFM_STORMS_GROTTO, + FOREST_TEMPLE_ENTRYWAY, + + KAKARIKO_VILLAGE, + KAK_CARPENTER_BOSS_HOUSE, + KAK_HOUSE_OF_SKULLTULA, + KAK_IMPAS_HOUSE, + KAK_IMPAS_LEDGE, + KAK_IMPAS_HOUSE_BACK, + KAK_IMPAS_HOUSE_NEAR_COW, + KAK_WINDMILL, + KAK_BAZAAR, + KAK_SHOOTING_GALLERY, + KAK_POTION_SHOP_FRONT, + KAK_POTION_SHOP_BACK, + KAK_ROOFTOP, + KAK_BEHIND_GATE, + KAK_BACKYARD, + KAK_ODD_POTION_BUILDING, + KAK_REDEAD_GROTTO, + KAK_OPEN_GROTTO, + BOTTOM_OF_THE_WELL_ENTRYWAY, + + THE_GRAVEYARD, + GRAVEYARD_DAMPES_GRAVE, + GRAVEYARD_DAMPES_HOUSE, + GRAVEYARD_SHIELD_GRAVE, + GRAVEYARD_COMPOSERS_GRAVE, + GRAVEYARD_HEART_PIECE_GRAVE, + GRAVEYARD_WARP_PAD_REGION, + SHADOW_TEMPLE_ENTRYWAY, + + DEATH_MOUNTAIN_TRAIL, + DEATH_MOUNTAIN_SUMMIT, + DMT_OWL_FLIGHT, + DMT_GREAT_FAIRY_FOUNTAIN, + DMT_COW_GROTTO, + DMT_STORMS_GROTTO, + DODONGOS_CAVERN_ENTRYWAY, + + DMC_UPPER_LOCAL, + DMC_CENTRAL_LOCAL, + DMC_LOWER_LOCAL, + DMC_LOWER_NEARBY, + DMC_UPPER_NEARBY, + DMC_CENTRAL_NEARBY, + DMC_LADDER_AREA_NEARBY, + DMC_UPPER_GROTTO, + DMC_HAMMER_GROTTO, + DMC_GREAT_FAIRY_FOUNTAIN, + FIRE_TEMPLE_ENTRYWAY, + + GORON_CITY, + GC_WOODS_WARP, + GC_DARUNIAS_CHAMBER, + GC_GROTTO_PLATFORM, + GC_SHOP, + GC_GROTTO, + + ZR_FRONT, + ZORAS_RIVER, + ZR_BEHIND_WATERFALL, + ZR_OPEN_GROTTO, + ZR_FAIRY_GROTTO, + ZR_STORMS_GROTTO, + ZORAS_DOMAIN, + ZD_BEHIND_KING_ZORA, + ZD_SHOP, + ZD_STORMS_GROTTO, + ZORAS_FOUNTAIN, + ZF_GREAT_FAIRY_FOUNTAIN, + JABU_JABUS_BELLY_ENTRYWAY, + ICE_CAVERN_ENTRYWAY, + + HYRULE_FIELD, + HF_SOUTHEAST_GROTTO, + HF_OPEN_GROTTO, + HF_INSIDE_FENCE_GROTTO, + HF_COW_GROTTO, + HF_NEAR_MARKET_GROTTO, + HF_FAIRY_GROTTO, + HF_NEAR_KAK_GROTTO, + HF_TEKTITE_GROTTO, + + LON_LON_RANCH, + LLR_TALONS_HOUSE, + LLR_STABLES, + LLR_TOWER, + LLR_GROTTO, + + LAKE_HYLIA, + LH_OWL_FLIGHT, + LH_LAB, + LH_FISHING_ISLAND, + LH_FISHING_HOLE, + LH_GROTTO, + WATER_TEMPLE_ENTRYWAY, + + GERUDO_VALLEY, + GV_UPPER_STREAM, + GV_LOWER_STREAM, + GV_GROTTO_LEDGE, + GV_CRATE_LEDGE, + GV_OCTOROK_GROTTO, + GV_FORTRESS_SIDE, + GV_CARPENTER_TENT, + GV_STORMS_GROTTO, + GERUDO_FORTRESS, + GF_OUTSIDE_GATE, + GF_STORMS_GROTTO, + GERUDO_TRAINING_GROUNDS_ENTRYWAY, + + WASTELAND_NEAR_FORTRESS, + HAUNTED_WASTELAND, + WASTELAND_NEAR_COLOSSUS, + DESERT_COLOSSUS, + COLOSSUS_GREAT_FAIRY_FOUNTAIN, + COLOSSUS_GROTTO, + SPIRIT_TEMPLE_ENTRYWAY, + + MARKET_ENTRANCE, + THE_MARKET, + MARKET_GUARD_HOUSE, + MARKET_BAZAAR, + MARKET_MASK_SHOP, + MARKET_SHOOTING_GALLERY, + MARKET_BOMBCHU_BOWLING, + MARKET_TREASURE_CHEST_GAME, + MARKET_POTION_SHOP, + MARKET_BACK_ALLEY, + MARKET_BOMBCHU_SHOP, + MARKET_DOG_LADY_HOUSE, + MARKET_MAN_IN_GREEN_HOUSE, + TOT_ENTRANCE, + TEMPLE_OF_TIME, + TOT_BEYOND_DOOR_OF_TIME, + + CASTLE_GROUNDS, + HYRULE_CASTLE_GROUNDS, + HC_GARDEN, + HC_GREAT_FAIRY_FOUNTAIN, + HC_STORMS_GROTTO, + GANONS_CASTLE_GROUNDS, + OGC_GREAT_FAIRY_FOUNTAIN, + GANONS_CASTLE_ENTRYWAY, + + DEKU_TREE_LOBBY, + DEKU_TREE_2F_MIDDLE_ROOM, + DEKU_TREE_SLINGSHOT_ROOM, + DEKU_TREE_COMPASS_ROOM, + DEKU_TREE_BASEMENT_LOWER, + DEKU_TREE_BASEMENT_SCRUB_ROOM, + DEKU_TREE_BASEMENT_WATER_ROOM, + DEKU_TREE_BASEMENT_TORCH_ROOM, + DEKU_TREE_BASEMENT_BACK_LOBBY, + DEKU_TREE_BASEMENT_BACK_ROOM, + DEKU_TREE_BASEMENT_UPPER, + DEKU_TREE_OUTSIDE_BOSS_ROOM, + DEKU_TREE_BOSS_ROOM, + + DODONGOS_CAVERN_BEGINNING, + DODONGOS_CAVERN_LOBBY, + DODONGOS_CAVERN_LOBBY_SWITCH, + DODONGOS_CAVERN_SE_CORRIDOR, + DODONGOS_CAVERN_SE_ROOM, + DODONGOS_CAVERN_NEAR_LOWER_LIZALFOS, + DODONGOS_CAVERN_LOWER_LIZALFOS, + DODONGOS_CAVERN_DODONGO_ROOM, + DODONGOS_CAVERN_NEAR_DODONGO_ROOM, + DODONGOS_CAVERN_STAIRS_LOWER, + DODONGOS_CAVERN_STAIRS_UPPER, + DODONGOS_CAVERN_COMPASS_ROOM, + DODONGOS_CAVERN_ARMOS_ROOM, + DODONGOS_CAVERN_BOMB_ROOM_LOWER, + DODONGOS_CAVERN_2F_SIDE_ROOM, + DODONGOS_CAVERN_FIRST_SLINGSHOT_ROOM, + DODONGOS_CAVERN_UPPER_LIZALFOS, + DODONGOS_CAVERN_SECOND_SLINGSHOT_ROOM, + DODONGOS_CAVERN_BOMB_ROOM_UPPER, + DODONGOS_CAVERN_FAR_BRIDGE, + DODONGOS_CAVERN_BOSS_AREA, + DODONGOS_CAVERN_BACK_ROOM, + DODONGOS_CAVERN_BOSS_ROOM, + + JABU_JABUS_BELLY_BEGINNING, + JABU_JABUS_BELLY_LIFT_MIDDLE, + JABU_JABUS_BELLY_MAIN_UPPER, + JABU_JABUS_BELLY_MAIN_LOWER, + JABU_JABUS_BELLY_SHABOMB_CORRIDOR, + JABU_JABUS_BELLY_LOWER_SIDE_ROOM, + JABU_JABUS_BELLY_LIFT_LOWER, + JABU_JABUS_BELLY_FORKED_CORRIDOR, + JABU_JABUS_BELLY_BOOMERANG_ROOM, + JABU_JABUS_BELLY_MAP_ROOM, + JABU_JABUS_BELLY_COMPASS_ROOM, + JABU_JABUS_BELLY_BLUE_TENTACLE, + JABU_JABUS_BELLY_GREEN_TENTACLE, + JABU_JABUS_BELLY_BIGOCTO_ROOM, + JABU_JABUS_BELLY_ABOVE_BIGOCTO, + JABU_JABUS_BELLY_LIFT_UPPER, + JABU_JABUS_BELLY_NEAR_BOSS_ROOM, + JABU_JABUS_BELLY_BOSS_ROOM, + + FOREST_TEMPLE_FIRST_ROOM, + FOREST_TEMPLE_SOUTH_CORRIDOR, + FOREST_TEMPLE_LOBBY, + FOREST_TEMPLE_NORTH_CORRIDOR, + FOREST_TEMPLE_LOWER_STALFOS, + FOREST_TEMPLE_NW_OUTDOORS_LOWER, + FOREST_TEMPLE_NW_OUTDOORS_UPPER, + FOREST_TEMPLE_NE_OUTDOORS_LOWER, + FOREST_TEMPLE_NE_OUTDOORS_UPPER, + FOREST_TEMPLE_MAP_ROOM, + FOREST_TEMPLE_SEWER, + FOREST_TEMPLE_BELOW_BOSS_KEY_CHEST, + FOREST_TEMPLE_FLOORMASTER_ROOM, + FOREST_TEMPLE_WEST_CORRIDOR, + FOREST_TEMPLE_BLOCK_PUSH_ROOM, + FOREST_TEMPLE_NW_CORRIDOR_TWISTED, + FOREST_TEMPLE_NW_CORRIDOR_STRAIGHTENED, + FOREST_TEMPLE_RED_POE_ROOM, + FOREST_TEMPLE_UPPER_STALFOS, + FOREST_TEMPLE_BLUE_POE_ROOM, + FOREST_TEMPLE_NE_CORRIDOR_STRAIGHTENED, + FOREST_TEMPLE_NE_CORRIDOR_TWISTED, + FOREST_TEMPLE_FROZEN_EYE_ROOM, + FOREST_TEMPLE_FALLING_ROOM, + FOREST_TEMPLE_GREEN_POE_ROOM, + FOREST_TEMPLE_EAST_CORRIDOR, + FOREST_TEMPLE_BOSS_REGION, + FOREST_TEMPLE_BOSS_ROOM, + + FIRE_TEMPLE_FIRST_ROOM, + FIRE_TEMPLE_NEAR_BOSS_ROOM, + FIRE_TEMPLE_BOSS_ROOM, + FIRE_TEMPLE_LOOP_ENEMIES, + FIRE_TEMPLE_LOOP_TILES, + FIRE_TEMPLE_LOOP_FLARE_DANCER, + FIRE_TEMPLE_LOOP_HAMMER_SWITCH, + FIRE_TEMPLE_LOOP_GORON_ROOM, + FIRE_TEMPLE_LOOP_EXIT, + FIRE_TEMPLE_BIG_LAVA_ROOM, + FIRE_TEMPLE_BIG_LAVA_ROOM_NORTH_GORON, + FIRE_TEMPLE_BIG_LAVA_ROOM_NORTH_TILES, + FIRE_TEMPLE_BIG_LAVA_ROOM_SOUTH_GORON, + FIRE_TEMPLE_FIRE_PILLAR_ROOM, + FIRE_TEMPLE_SHORTCUT_ROOM, + FIRE_TEMPLE_SHORTCUT_CLIMB, + FIRE_TEMPLE_BOULDER_MAZE_LOWER, + FIRE_TEMPLE_BOULDER_MAZE_LOWER_SIDE_ROOM, + FIRE_TEMPLE_EAST_CENTRAL_ROOM, + FIRE_TEMPLE_FIRE_WALL_CHASE, + FIRE_TEMPLE_MAP_AREA, + FIRE_TEMPLE_BOULDER_MAZE_UPPER, + FIRE_TEMPLE_SCARECROW_ROOM, + FIRE_TEMPLE_EAST_PEAK, + FIRE_TEMPLE_CORRIDOR, + FIRE_TEMPLE_FIRE_MAZE_ROOM, + FIRE_TEMPLE_FIRE_MAZE_UPPER, + FIRE_TEMPLE_FIRE_MAZE_SIDE_ROOM, + FIRE_TEMPLE_WEST_CENTRAL_LOWER, + FIRE_TEMPLE_WEST_CENTRAL_UPPER, + FIRE_TEMPLE_LATE_FIRE_MAZE, + FIRE_TEMPLE_UPPER_FLARE_DANCER, + FIRE_TEMPLE_WEST_CLIMB, + FIRE_TEMPLE_WEST_PEAK, + FIRE_TEMPLE_HAMMER_RETURN_PATH, + FIRE_TEMPLE_ABOVE_FIRE_MAZE, + + WATER_TEMPLE_LOBBY, + WATER_TEMPLE_EAST_LOWER, + WATER_TEMPLE_MAP_ROOM, + WATER_TEMPLE_CRACKED_WALL, + WATER_TEMPLE_TORCH_ROOM, + WATER_TEMPLE_NORTH_LOWER, + WATER_TEMPLE_BOULDERS_LOWER, + WATER_TEMPLE_BLOCK_ROOM, + WATER_TEMPLE_JETS_ROOM, + WATER_TEMPLE_BOULDERS_UPPER, + WATER_TEMPLE_BOSS_KEY_ROOM, + WATER_TEMPLE_SOUTH_LOWER, + WATER_TEMPLE_WEST_LOWER, + WATER_TEMPLE_DRAGON_ROOM, + WATER_TEMPLE_CENTRAL_PILLAR_LOWER, + WATER_TEMPLE_CENTRAL_PILLAR_UPPER, + WATER_TEMPLE_CENTRAL_PILLAR_BASEMENT, + WATER_TEMPLE_EAST_MIDDLE, + WATER_TEMPLE_WEST_MIDDLE, + WATER_TEMPLE_HIGH_WATER, + WATER_TEMPLE_BLOCK_CORRIDOR, + WATER_TEMPLE_FALLING_PLATFORM_ROOM, + WATER_TEMPLE_DRAGON_PILLARS_ROOM, + WATER_TEMPLE_DARK_LINK_ROOM, + WATER_TEMPLE_LONGSHOT_ROOM, + WATER_TEMPLE_RIVER, + WATER_TEMPLE_PRE_BOSS_ROOM, + WATER_TEMPLE_BOSS_ROOM, + + SPIRIT_TEMPLE_LOBBY, + SPIRIT_TEMPLE_CHILD, + SPIRIT_TEMPLE_CHILD_CLIMB, + SPIRIT_TEMPLE_EARLY_ADULT, + SPIRIT_TEMPLE_CENTRAL_CHAMBER, + SPIRIT_TEMPLE_OUTDOOR_HANDS, + SPIRIT_TEMPLE_BEYOND_CENTRAL_LOCKED_DOOR, + SPIRIT_TEMPLE_BEYOND_FINAL_LOCKED_DOOR, + SHADOW_TEMPLE_BEGINNING, + SHADOW_TEMPLE_FIRST_BEAMOS, + SHADOW_TEMPLE_HUGE_PIT, + SHADOW_TEMPLE_WIND_TUNNEL, + SHADOW_TEMPLE_BEYOND_BOAT, + BOTTOM_OF_THE_WELL, + BOTTOM_OF_THE_WELL_MAIN_AREA, + ICE_CAVERN_BEGINNING, + ICE_CAVERN_MAIN, + GERUDO_TRAINING_GROUNDS_LOBBY, + GERUDO_TRAINING_GROUNDS_CENTRAL_MAZE, + GERUDO_TRAINING_GROUNDS_CENTRAL_MAZE_RIGHT, + GERUDO_TRAINING_GROUNDS_LAVA_ROOM, + GERUDO_TRAINING_GROUNDS_HAMMER_ROOM, + GERUDO_TRAINING_GROUNDS_EYE_STATUE_LOWER, + GERUDO_TRAINING_GROUNDS_EYE_STATUE_UPPER, + GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_ROOM, + GERUDO_TRAINING_GROUNDS_LIKE_LIKE_ROOM, + GANONS_CASTLE_LOBBY, + GANONS_CASTLE_DEKU_SCRUBS, + GANONS_CASTLE_FOREST_TRIAL, + GANONS_CASTLE_FIRE_TRIAL, + GANONS_CASTLE_WATER_TRIAL, + GANONS_CASTLE_SHADOW_TRIAL, + GANONS_CASTLE_SPIRIT_TRIAL, + GANONS_CASTLE_LIGHT_TRIAL, + GANONS_CASTLE_TOWER, + DEKU_TREE_MQ_LOBBY, + DEKU_TREE_MQ_COMPASS_ROOM, + DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT, + DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK, + DEKU_TREE_MQ_BASEMENT_BACK_ROOM, + DEKU_TREE_MQ_BASEMENT_LEDGE, + DODONGOS_CAVERN_MQ_BEGINNING, + DODONGOS_CAVERN_MQ_LOBBY, + DODONGOS_CAVERN_MQ_LOWER_RIGHT_SIDE, + DODONGOS_CAVERN_MQ_BOMB_BAG_AREA, + DODONGOS_CAVERN_MQ_BOSS_AREA, + JABU_JABUS_BELLY_MQ_BEGINNING, + JABU_JABUS_BELLY_MQ_MAIN, + JABU_JABUS_BELLY_MQ_DEPTHS, + JABU_JABUS_BELLY_MQ_BOSS_AREA, + FOREST_TEMPLE_MQ_LOBBY, + FOREST_TEMPLE_MQ_CENTRAL_AREA, + FOREST_TEMPLE_MQ_AFTER_BLOCK_PUZZLE, + FOREST_TEMPLE_MQ_OUTDOOR_LEDGE, + FOREST_TEMPLE_MQ_NW_OUTDOORS, + FOREST_TEMPLE_MQ_NE_OUTDOORS, + FOREST_TEMPLE_MQ_OUTDOORS_TOP_LEDGES, + FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE, + FOREST_TEMPLE_MQ_BOW_REGION, + FOREST_TEMPLE_MQ_FALLING_ROOM, + FOREST_TEMPLE_MQ_BOSS_REGION, + FIRE_TEMPLE_MQ_LOWER, + FIRE_TEMPLE_MQ_LOWER_LOCKED_DOOR, + FIRE_TEMPLE_MQ_BIG_LAVA_ROOM, + FIRE_TEMPLE_MQ_LOWER_MAZE, + FIRE_TEMPLE_MQ_UPPER_MAZE, + FIRE_TEMPLE_MQ_UPPER, + FIRE_TEMPLE_MQ_BOSS_ROOM, + WATER_TEMPLE_MQ_LOBBY, + WATER_TEMPLE_MQ_DIVE, + WATER_TEMPLE_MQ_LOWERED_WATER_LEVELS, + WATER_TEMPLE_MQ_DARK_LINK_REGION, + WATER_TEMPLE_MQ_BASEMENT_GATED_AREAS, + SPIRIT_TEMPLE_MQ_LOBBY, + SPIRIT_TEMPLE_MQ_CHILD, + SPIRIT_TEMPLE_MQ_ADULT, + SPIRIT_TEMPLE_MQ_SHARED, + SPIRIT_TEMPLE_MQ_LOWER_ADULT, + SPIRIT_TEMPLE_MQ_BOSS_AREA, + SPIRIT_TEMPLE_MQ_MIRROR_SHIELD_HAND, + SPIRIT_TEMPLE_MQ_SILVER_GAUNTLETS_HAND, + SHADOW_TEMPLE_MQ_ENTRYWAY, + SHADOW_TEMPLE_MQ_BEGINNING, + SHADOW_TEMPLE_MQ_DEAD_HAND_AREA, + SHADOW_TEMPLE_MQ_FIRST_BEAMOS, + SHADOW_TEMPLE_MQ_UPPER_HUGE_PIT, + SHADOW_TEMPLE_MQ_LOWER_HUGE_PIT, + SHADOW_TEMPLE_MQ_WIND_TUNNEL, + SHADOW_TEMPLE_MQ_BEYOND_BOAT, + SHADOW_TEMPLE_MQ_INVISIBLE_MAZE, + BOTTOM_OF_THE_WELL_MQ, + BOTTOM_OF_THE_WELL_MQ_PERIMETER, + BOTTOM_OF_THE_WELL_MQ_MIDDLE, + ICE_CAVERN_MQ_BEGINNING, + ICE_CAVERN_MQ_MAP_ROOM, + ICE_CAVERN_MQ_IRON_BOOTS_REGION, + ICE_CAVERN_MQ_COMPASS_ROOM, + GERUDO_TRAINING_GROUNDS_MQ_LOBBY, + GERUDO_TRAINING_GROUNDS_MQ_RIGHT_SIDE, + GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER, + GERUDO_TRAINING_GROUNDS_MQ_LEFT_SIDE, + GERUDO_TRAINING_GROUNDS_MQ_STALFOS_ROOM, + GERUDO_TRAINING_GROUNDS_MQ_BACK_AREAS, + GERUDO_TRAINING_GROUNDS_MQ_CENTRAL_MAZE_RIGHT, + GANONS_CASTLE_MQ_LOBBY, + GANONS_CASTLE_MQ_DEKU_SCRUBS, + GANONS_CASTLE_MQ_FOREST_TRIAL, + GANONS_CASTLE_MQ_FIRE_TRIAL, + GANONS_CASTLE_MQ_WATER_TRIAL, + GANONS_CASTLE_MQ_SHADOW_TRIAL, + GANONS_CASTLE_MQ_SPIRIT_TRIAL, + GANONS_CASTLE_MQ_LIGHT_TRIAL, + }; + + void AccessReset() { + for (const uint32_t area : allAreas) { + AreaTable(area)->ResetVariables(); + } + + if(Settings::HasNightStart) { + if(Settings::ResolvedStartingAge == AGE_CHILD) { + AreaTable(ROOT)->childNight = true; + } else { + AreaTable(ROOT)->adultNight = true; + } + } else { + if(Settings::ResolvedStartingAge == AGE_CHILD) { + AreaTable(ROOT)->childDay = true; + } else { + AreaTable(ROOT)->adultDay = true; + } + } + } + + //Reset exits and clear items from locations + void ResetAllLocations() { + for (const uint32_t area : allAreas) { + AreaTable(area)->ResetVariables(); + //Erase item from every location in this exit + for (LocationAccess& locPair : AreaTable(area)->locations) { + uint32_t location = locPair.GetLocation(); + Location(location)->ResetVariables(); + } + } + + if(Settings::HasNightStart) { + if(Settings::ResolvedStartingAge == AGE_CHILD) { + AreaTable(ROOT)->childNight = true; + } else { + AreaTable(ROOT)->adultNight = true; + } + } else { + if(Settings::ResolvedStartingAge == AGE_CHILD) { + AreaTable(ROOT)->childDay = true; + } else { + AreaTable(ROOT)->adultDay = true; + } + } + } + + bool HasTimePassAccess(uint8_t age) { + for (const uint32_t areaKey : allAreas) { + auto area = AreaTable(areaKey); + if (area->timePass && ((age == AGE_CHILD && area->Child()) || (age == AGE_ADULT && area->Adult()))) { + return true; + } + } + return false; + } + + // Will dump a file which can be turned into a visual graph using graphviz + // https://graphviz.org/download/ + // Use command: dot -Tsvg -o world.svg + // Then open in a browser and CTRL + F to find the area of interest + void DumpWorldGraph(std::string str) { + std::ofstream worldGraph; + worldGraph.open (str + ".dot"); + worldGraph << "digraph {\n\tcenter=true;\n"; + + for (const uint32_t areaKey : allAreas) { + auto area = AreaTable(areaKey); + for (auto exit : area->exits) { + if (exit.GetConnectedRegion()->regionName != "Invalid Area") { + std::string parent = exit.GetParentRegion()->regionName; + if (area->childDay) { + parent += " CD"; + } + if (area->childNight) { + parent += " CN"; + } + if (area->adultDay) { + parent += " AD"; + } + if (area->adultNight) { + parent += " AN"; + } + Area* connected = exit.GetConnectedRegion(); + auto connectedStr = connected->regionName; + if (connected->childDay) { + connectedStr += " CD"; + } + if (connected->childNight) { + connectedStr += " CN"; + } + if (connected->adultDay) { + connectedStr += " AD"; + } + if (connected->adultNight) { + connectedStr += " AN"; + } + worldGraph << "\t\"" + parent + "\"[shape=\"plain\"];\n"; + worldGraph << "\t\"" + connectedStr + "\"[shape=\"plain\"];\n"; + worldGraph << "\t\"" + parent + "\" -> \"" + connectedStr + "\"\n"; + } + } + } + worldGraph << "}"; + worldGraph.close(); + } + +} //namespace Areas + +Area* AreaTable(const uint32_t areaKey) { + if (areaKey > KEY_ENUM_MAX) { + printf("\x1b[1;1HERROR: AREAKEY TOO BIG"); + } + return &(areaTable[areaKey]); +} + +//Retrieve all the shuffable entrances of a specific type +std::vector GetShuffleableEntrances(EntranceType type, bool onlyPrimary /*= true*/) { + std::vector entrancesToShuffle = {}; + for (uint32_t area : Areas::allAreas) { + for (auto& exit: AreaTable(area)->exits) { + if ((exit.GetType() == type || type == EntranceType::All) && (exit.IsPrimary() || !onlyPrimary) && exit.GetType() != EntranceType::None) { + entrancesToShuffle.push_back(&exit); + } + } + } + return entrancesToShuffle; +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access.hpp b/soh/soh/Enhancements/randomizer/3drando/location_access.hpp new file mode 100644 index 000000000..7ec696ac1 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access.hpp @@ -0,0 +1,266 @@ +#pragma once + +#include +#include +#include + +#include "logic.hpp" +#include "hint_list.hpp" +#include "keys.hpp" +#include "fill.hpp" + +typedef bool (*ConditionFn)(); + +class EventAccess { +public: + + + explicit EventAccess(bool* event_, std::vector conditions_met_) + : event(event_) { + conditions_met.resize(2); + for (size_t i = 0; i < conditions_met_.size(); i++) { + conditions_met[i] = conditions_met_[i]; + } + } + + bool ConditionsMet() const { + if (Settings::Logic.Is(LOGIC_NONE) || Settings::Logic.Is(LOGIC_VANILLA)) { + return true; + } else if (Settings::Logic.Is(LOGIC_GLITCHLESS)) { + return conditions_met[0](); + } else if (Settings::Logic.Is(LOGIC_GLITCHED)) { + if (conditions_met[0]()) { + return true; + } else if (conditions_met[1] != NULL) { + return conditions_met[1](); + } + } + return false; + } + + bool CheckConditionAtAgeTime(bool& age, bool& time) { + + Logic::IsChild = false; + Logic::IsAdult = false; + Logic::AtDay = false; + Logic::AtNight = false; + + time = true; + age = true; + + Logic::UpdateHelpers(); + return ConditionsMet(); + } + + void EventOccurred() { + *event = true; + } + + bool GetEvent() const { + return *event; + } + +private: + bool* event; + std::vector conditions_met; +}; + +//this class is meant to hold an item location with a boolean function to determine its accessibility from a specific area +class LocationAccess { +public: + + explicit LocationAccess(uint32_t location_, std::vector conditions_met_) + : location(location_) { + conditions_met.resize(2); + for (size_t i = 0; i < conditions_met_.size(); i++) { + conditions_met[i] = conditions_met_[i]; + } + } + + bool GetConditionsMet() const { + if (Settings::Logic.Is(LOGIC_NONE) || Settings::Logic.Is(LOGIC_VANILLA)) { + return true; + } else if (Settings::Logic.Is(LOGIC_GLITCHLESS)) { + return conditions_met[0](); + } else if (Settings::Logic.Is(LOGIC_GLITCHED)) { + if (conditions_met[0]()) { + return true; + } else if (conditions_met[1] != NULL) { + return conditions_met[1](); + } + } + return false; + } + + bool CheckConditionAtAgeTime(bool& age, bool& time) const; + + bool ConditionsMet() const; + + uint32_t GetLocation() const { + return location; + } + +private: + uint32_t location; + std::vector conditions_met; + + //Makes sure shop locations are buyable + bool CanBuy() const; +}; + +class Entrance; +enum class EntranceType; + +class Area { +public: + Area(); + Area(std::string regionName_, std::string scene_, uint32_t hintKey_, + bool timePass_, + std::vector events_, + std::vector locations_, + std::list exits_); + ~Area(); + + std::string regionName; + std::string scene; + uint32_t hintKey; + bool timePass; + std::vector events; + std::vector locations; + std::list exits; + std::list entrances; + //^ The above exits are now stored in a list instead of a vector because + //the entrance randomization algorithm plays around with pointers to these + //entrances a lot. By putting the entrances in a list, we don't have to + //worry about a vector potentially reallocating itself and invalidating all our + //entrance pointers. + + bool childDay = false; + bool childNight = false; + bool adultDay = false; + bool adultNight = false; + bool addedToPool = false; + + bool UpdateEvents(SearchMode mode); + + void AddExit(uint32_t parentKey, uint32_t newExitKey, ConditionFn condition); + + void RemoveExit(Entrance* exitToRemove); + + void SetAsPrimary(uint32_t exitToBePrimary); + + Entrance* GetExit(uint32_t exit); + + bool Child() const { + return childDay || childNight; + } + + bool Adult() const { + return adultDay || adultNight; + } + + bool BothAgesCheck() const { + return Child() && Adult(); + } + + bool HasAccess() const { + return Child() || Adult(); + } + + bool AllAccess() const { + return childDay && childNight && adultDay && adultNight; + } + + //Check to see if an exit can be access as both ages at both times of day + bool CheckAllAccess(uint32_t exitKey); + + const HintText& GetHint() const { + return Hint(hintKey); + } + + //Here checks conditional access based on whether or not both ages have + //access to this area. For example: if there are rocks that block a path + //which both child and adult can access, adult having hammer can give + //both child and adult access to the path. + bool HereCheck(ConditionFn condition) { + + //store current age variables + bool pastAdult = Logic::IsAdult; + bool pastChild = Logic::IsChild; + + //set age access as this areas ages + Logic::IsChild = Child(); + Logic::IsAdult = Adult(); + + //update helpers and check condition as well as having at least child or adult access + Logic::UpdateHelpers(); + bool hereVal = condition() && (Logic::IsAdult || Logic::IsChild); + + //set back age variables + Logic::IsChild = pastChild; + Logic::IsAdult = pastAdult; + Logic::UpdateHelpers(); + + return hereVal; + } + + bool CanPlantBeanCheck() const; + bool AllAccountedFor() const; + + void ResetVariables(); + + void printAgeTimeAccess() const { + auto message = "Child Day: " + std::to_string(childDay) + "\t" + "Child Night: " + std::to_string(childNight) + "\t" + "Adult Day: " + std::to_string(adultDay) + "\t" + "Adult Night: " + std::to_string(adultNight); + CitraPrint(message); + } +}; + +extern std::array areaTable; +extern std::vector grottoEvents; + +bool Here(const AreaKey area, ConditionFn condition); +bool CanPlantBean(const AreaKey area); +bool BothAges(const AreaKey area); +bool ChildCanAccess(const AreaKey area); +bool AdultCanAccess(const AreaKey area); +bool HasAccessTo(const AreaKey area); + +#define DAY_NIGHT_CYCLE true +#define NO_DAY_NIGHT_CYCLE false + +namespace Areas { + + extern void AccessReset(); + extern void ResetAllLocations(); + extern bool HasTimePassAccess(uint8_t age); + extern void DumpWorldGraph(std::string str); +} //namespace Exits + +void AreaTable_Init(); +Area* AreaTable(const uint32_t areaKey); +std::vector GetShuffleableEntrances(EntranceType type, bool onlyPrimary = true); + +// Overworld +void AreaTable_Init_LostWoods(); +void AreaTable_Init_HyruleField(); +void AreaTable_Init_CastleTown(); +void AreaTable_Init_Kakariko(); +void AreaTable_Init_DeathMountain(); +void AreaTable_Init_ZorasDomain(); +void AreaTable_Init_GerudoValley(); +// Dungeons +void AreaTable_Init_DekuTree(); +void AreaTable_Init_DodongosCavern(); +void AreaTable_Init_JabuJabusBelly(); +void AreaTable_Init_ForestTemple(); +void AreaTable_Init_FireTemple(); +void AreaTable_Init_WaterTemple(); +void AreaTable_Init_SpiritTemple(); +void AreaTable_Init_ShadowTemple(); +void AreaTable_Init_BottomOfTheWell(); +void AreaTable_Init_IceCavern(); +void AreaTable_Init_GerudoTrainingGrounds(); +void AreaTable_Init_GanonsCastle(); diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_bottom_of_the_well.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_bottom_of_the_well.cpp new file mode 100644 index 000000000..f1532cfaf --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_bottom_of_the_well.cpp @@ -0,0 +1,88 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" +#include "../dungeon.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_BottomOfTheWell() { + /*-------------------------- + | VANILLA/MQ DECIDER | + ---------------------------*/ + areaTable[BOTTOM_OF_THE_WELL_ENTRYWAY] = Area("Bottom of the Well Entryway", "Bottom of the Well", BOTTOM_OF_THE_WELL, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(BOTTOM_OF_THE_WELL_MAIN_AREA, {[]{return Dungeon::BottomOfTheWell.IsVanilla() && IsChild && (CanChildAttack || Nuts);}, + /*Glitched*/[]{return Dungeon::BottomOfTheWell.IsVanilla() && IsChild && CanUse(MEGATON_HAMMER);}}), + Entrance(BOTTOM_OF_THE_WELL_MQ_PERIMETER, {[]{return Dungeon::BottomOfTheWell.IsMQ() && IsChild;}, + /*Glitched*/[]{return Dungeon::BottomOfTheWell.IsMQ() && CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::INTERMEDIATE) && Longshot;}}), + Entrance(KAKARIKO_VILLAGE, {[]{return true;}}), + }); + + /*-------------------------- + | VANILLA DUNGEON | + ---------------------------*/ + if (Dungeon::BottomOfTheWell.IsVanilla()) { + areaTable[BOTTOM_OF_THE_WELL_MAIN_AREA] = Area("Bottom of the Well Main Area", "Bottom of the Well", BOTTOM_OF_THE_WELL, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&StickPot, {[]{return true;}}), + EventAccess(&NutPot, {[]{return true;}}), + }, { + //Locations + LocationAccess(BOTTOM_OF_THE_WELL_FRONT_LEFT_FAKE_WALL_CHEST, {[]{return LogicLensBotw || CanUse(LENS_OF_TRUTH);}}), + LocationAccess(BOTTOM_OF_THE_WELL_FRONT_CENTER_BOMBABLE_CHEST, {[]{return HasExplosives;}}), + LocationAccess(BOTTOM_OF_THE_WELL_RIGHT_BOTTOM_FAKE_WALL_CHEST, {[]{return LogicLensBotw || CanUse(LENS_OF_TRUTH);}}), + LocationAccess(BOTTOM_OF_THE_WELL_COMPASS_CHEST, {[]{return LogicLensBotw || CanUse(LENS_OF_TRUTH);}}), + LocationAccess(BOTTOM_OF_THE_WELL_CENTER_SKULLTULA_CHEST, {[]{return LogicLensBotw || CanUse(LENS_OF_TRUTH);}}), + LocationAccess(BOTTOM_OF_THE_WELL_BACK_LEFT_BOMBABLE_CHEST, {[]{return (LogicLensBotw || CanUse(LENS_OF_TRUTH)) && HasExplosives;}}), + LocationAccess(BOTTOM_OF_THE_WELL_FREESTANDING_KEY, {[]{return Sticks || CanUse(DINS_FIRE);}}), + LocationAccess(BOTTOM_OF_THE_WELL_LENS_OF_TRUTH_CHEST, {[]{return CanPlay(ZeldasLullaby) && (KokiriSword || (Sticks && LogicChildDeadhand));}}), + LocationAccess(BOTTOM_OF_THE_WELL_INVISIBLE_CHEST, {[]{return CanPlay(ZeldasLullaby) && (LogicLensBotw || CanUse(LENS_OF_TRUTH));}}), + LocationAccess(BOTTOM_OF_THE_WELL_UNDERWATER_FRONT_CHEST, {[]{return CanPlay(ZeldasLullaby);}}), + LocationAccess(BOTTOM_OF_THE_WELL_UNDERWATER_LEFT_CHEST, {[]{return CanPlay(ZeldasLullaby);}}), + LocationAccess(BOTTOM_OF_THE_WELL_MAP_CHEST, {[]{return HasExplosives || (((SmallKeys(BOTTOM_OF_THE_WELL, 3) && (LogicLensBotw || CanUse(LENS_OF_TRUTH))) || CanUse(DINS_FIRE)) && GoronBracelet);}}), + LocationAccess(BOTTOM_OF_THE_WELL_FIRE_KEESE_CHEST, {[]{return SmallKeys(BOTTOM_OF_THE_WELL, 3) && (LogicLensBotw || CanUse(LENS_OF_TRUTH));}}), + LocationAccess(BOTTOM_OF_THE_WELL_LIKE_LIKE_CHEST, {[]{return SmallKeys(BOTTOM_OF_THE_WELL, 3) && (LogicLensBotw || CanUse(LENS_OF_TRUTH));}}), + LocationAccess(BOTTOM_OF_THE_WELL_GS_WEST_INNER_ROOM, {[]{return Boomerang && (LogicLensBotw || CanUse(LENS_OF_TRUTH)) && SmallKeys(BOTTOM_OF_THE_WELL, 3);}}), + LocationAccess(BOTTOM_OF_THE_WELL_GS_EAST_INNER_ROOM, {[]{return Boomerang && (LogicLensBotw || CanUse(LENS_OF_TRUTH)) && SmallKeys(BOTTOM_OF_THE_WELL, 3);}}), + LocationAccess(BOTTOM_OF_THE_WELL_GS_LIKE_LIKE_CAGE, {[]{return SmallKeys(BOTTOM_OF_THE_WELL, 3) && (LogicLensBotw || CanUse(LENS_OF_TRUTH)) && Boomerang;}}), + }, { + //Exits + Entrance(BOTTOM_OF_THE_WELL_ENTRYWAY, {[]{return true;}}), + }); + } + + /*--------------------------- + | MASTER QUEST DUNGEON | + ---------------------------*/ + if (Dungeon::BottomOfTheWell.IsMQ()) { + areaTable[BOTTOM_OF_THE_WELL_MQ_PERIMETER] = Area("Bottom of the Well MQ Perimeter", "Bottom of the Well", BOTTOM_OF_THE_WELL, NO_DAY_NIGHT_CYCLE, { + //Events + //EventAccess(&WallFairy, {[]{return WallFairy || Slingshot;}}), + }, { + //Locations + LocationAccess(BOTTOM_OF_THE_WELL_MQ_COMPASS_CHEST, {[]{return KokiriSword || (Sticks && LogicChildDeadhand);}}), + LocationAccess(BOTTOM_OF_THE_WELL_MQ_DEAD_HAND_FREESTANDING_KEY, {[]{return HasExplosives;}}), + //Trick: HasExplosives || (LogicBotWMQDeadHandKey && Boomerang) + LocationAccess(BOTTOM_OF_THE_WELL_MQ_GS_BASEMENT, {[]{return CanChildAttack;}}), + LocationAccess(BOTTOM_OF_THE_WELL_MQ_GS_COFFIN_ROOM, {[]{return CanChildAttack && SmallKeys(BOTTOM_OF_THE_WELL, 2);}}), + }, { + //Exits + Entrance(BOTTOM_OF_THE_WELL_ENTRYWAY, {[]{return true;}}), + Entrance(BOTTOM_OF_THE_WELL_MQ_MIDDLE, {[]{return CanPlay(ZeldasLullaby);}}), + //Trick: CanPlay(ZeldasLullaby) || (LogicBotWMQPits && HasExplosives) + }); + + areaTable[BOTTOM_OF_THE_WELL_MQ_MIDDLE] = Area("Bottom of the Well MQ Middle", "Bottom of the Well", BOTTOM_OF_THE_WELL, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(BOTTOM_OF_THE_WELL_MQ_MAP_CHEST, {[]{return true;}}), + LocationAccess(BOTTOM_OF_THE_WELL_MQ_LENS_OF_TRUTH_CHEST, {[]{return HasExplosives && SmallKeys(BOTTOM_OF_THE_WELL, 2);}}), + LocationAccess(BOTTOM_OF_THE_WELL_MQ_EAST_INNER_ROOM_FREESTANDING_KEY, {[]{return true;}}), + LocationAccess(BOTTOM_OF_THE_WELL_MQ_GS_WEST_INNER_ROOM, {[]{return CanChildAttack && HasExplosives;}}), + //Trick: CanChildAttack && (LogicBotWMQPits || HasExplosives) + }, { + //Exits + Entrance(BOTTOM_OF_THE_WELL_MQ_PERIMETER, {[]{return true;}}), + }); + } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_castle_town.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_castle_town.cpp new file mode 100644 index 000000000..7df38c193 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_castle_town.cpp @@ -0,0 +1,265 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_CastleTown() { + areaTable[MARKET_ENTRANCE] = Area("Market Entrance", "Market Entrance", THE_MARKET, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(HYRULE_FIELD, {[]{return IsAdult || AtDay;}}), + Entrance(THE_MARKET, {[]{return true;}}), + Entrance(MARKET_GUARD_HOUSE, {[]{return true;}}), + }); + + areaTable[THE_MARKET] = Area("Market", "Market", THE_MARKET, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(MARKET_ENTRANCE, {[]{return true;}}), + Entrance(TOT_ENTRANCE, {[]{return true;}}), + Entrance(CASTLE_GROUNDS, {[]{return true;}}), + Entrance(MARKET_BAZAAR, {[]{return IsChild && AtDay;}}), + Entrance(MARKET_MASK_SHOP, {[]{return IsChild && AtDay;}}), + Entrance(MARKET_SHOOTING_GALLERY, {[]{return IsChild && AtDay;}}), + Entrance(MARKET_BOMBCHU_BOWLING, {[]{return IsChild;}}), + Entrance(MARKET_TREASURE_CHEST_GAME, {[]{return IsChild && AtNight;}}), + Entrance(MARKET_POTION_SHOP, {[]{return IsChild && AtDay;}}), + Entrance(MARKET_BACK_ALLEY, {[]{return IsChild;}}), + }); + + areaTable[MARKET_BACK_ALLEY] = Area("Market Back Alley", "Market", THE_MARKET, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(THE_MARKET, {[]{return true;}}), + Entrance(MARKET_BOMBCHU_SHOP, {[]{return AtNight;}}), + Entrance(MARKET_DOG_LADY_HOUSE, {[]{return true;}}), + Entrance(MARKET_MAN_IN_GREEN_HOUSE, {[]{return AtNight;}}), + }); + + areaTable[TOT_ENTRANCE] = Area("ToT Entrance", "ToT Entrance", THE_MARKET, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || CanSummonGossipFairyWithoutSuns;}}), + }, { + //Locations + LocationAccess(TOT_GOSSIP_STONE_LEFT, {[]{return true;}}), + LocationAccess(TOT_GOSSIP_STONE_LEFT_CENTER, {[]{return true;}}), + LocationAccess(TOT_GOSSIP_STONE_RIGHT_CENTER, {[]{return true;}}), + LocationAccess(TOT_GOSSIP_STONE_RIGHT, {[]{return true;}}), + }, { + //Exits + Entrance(THE_MARKET, {[]{return true;}}), + Entrance(TEMPLE_OF_TIME, {[]{return true;}}), + }); + + areaTable[TEMPLE_OF_TIME] = Area("Temple of Time", "", TEMPLE_OF_TIME, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(TOT_LIGHT_ARROWS_CUTSCENE, {[]{return IsAdult && CanTriggerLACS;}}), + }, { + //Exits + Entrance(TOT_ENTRANCE, {[]{return true;}}), + Entrance(TOT_BEYOND_DOOR_OF_TIME, {[]{return OpenDoorOfTime.Is(OPENDOOROFTIME_OPEN) || (CanPlay(SongOfTime) && (OpenDoorOfTime.Is(OPENDOOROFTIME_CLOSED) || (HasAllStones && OcarinaOfTime)));}, + /*Glitched*/[]{return SongOfTime && OpenDoorOfTime.Is(OPENDOOROFTIME_CLOSED) && (CanDoGlitch(GlitchType::IndoorBombOI, GlitchDifficulty::ADVANCED) || + ((Bugs || Fish) && Bombs && (CanSurviveDamage || (Fairy && NumBottles >= 2)) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED) && CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE)));}}), + }); + + areaTable[TOT_BEYOND_DOOR_OF_TIME] = Area("Beyond Door of Time", "", TEMPLE_OF_TIME, NO_DAY_NIGHT_CYCLE, { + //Events + //EventAccess(&TimeTravel, {[]{return true;}}), + }, { + //Locations + LocationAccess(SHEIK_AT_TEMPLE, {[]{return ForestMedallion && IsAdult;}}), + }, { + //Exits + Entrance(TEMPLE_OF_TIME, {[]{return true;}}), + }); + + areaTable[CASTLE_GROUNDS] = Area("Castle Grounds", "Castle Grounds", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(THE_MARKET, {[]{return true;}}), + Entrance(HYRULE_CASTLE_GROUNDS, {[]{return IsChild;}}), + Entrance(GANONS_CASTLE_GROUNDS, {[]{return IsAdult;}}), + }); + + areaTable[HYRULE_CASTLE_GROUNDS] = Area("Hyrule Castle Grounds", "Castle Grounds", HYRULE_CASTLE, DAY_NIGHT_CYCLE, { + //Events + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || CanSummonGossipFairy;}}), + EventAccess(&ButterflyFairy, {[]{return ButterflyFairy || CanUse(STICKS);}}), + EventAccess(&BugRock, {[]{return true;}}), + }, { + //Locations + LocationAccess(HC_MALON_EGG, {[]{return true;}}), + LocationAccess(HC_GS_TREE, {[]{return CanChildAttack;}}), + LocationAccess(HC_MALON_GOSSIP_STONE, {[]{return true;}}), + LocationAccess(HC_ROCK_WALL_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(CASTLE_GROUNDS, {[]{return true;}}), + Entrance(HC_GARDEN, {[]{return WeirdEgg || !ShuffleWeirdEgg;}}), + Entrance(HC_GREAT_FAIRY_FOUNTAIN, {[]{return CanBlastOrSmash;}, + /*Glitched*/[]{return Sticks && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);}}), + Entrance(HC_STORMS_GROTTO, {[]{return CanOpenStormGrotto;}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && SongOfStorms && (ShardOfAgony || LogicGrottosWithoutAgony);}}), + }); + + areaTable[HC_GARDEN] = Area("HC Garden", "Castle Grounds", HYRULE_CASTLE, NO_DAY_NIGHT_CYCLE, { + //Events + }, { + //Locations + LocationAccess(HC_ZELDAS_LETTER, {[]{return true;}}), + LocationAccess(SONG_FROM_IMPA, {[]{return true;}}), + }, { + //Exits + Entrance(HYRULE_CASTLE_GROUNDS, {[]{return true;}}), + }); + + areaTable[HC_GREAT_FAIRY_FOUNTAIN] = Area("HC Great Fairy Fountain", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(HC_GREAT_FAIRY_REWARD, {[]{return CanPlay(ZeldasLullaby);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && Bombs && (CanSurviveDamage || (Fairy && NumBottles >= 2)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && ZeldasLullaby;}}), + }, { + //Exits + Entrance(CASTLE_GROUNDS, {[]{return true;}}), + }); + + areaTable[HC_STORMS_GROTTO] = Area("HC Storms Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&NutPot, {[]{return NutPot || CanBlastOrSmash;}}), + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || (CanBlastOrSmash && CanSummonGossipFairy);}}), + EventAccess(&WanderingBugs, {[]{return WanderingBugs || CanBlastOrSmash;}}), + }, { + //Locations + LocationAccess(HC_GS_STORMS_GROTTO, {[]{return CanBlastOrSmash && HookshotOrBoomerang;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE);}}), + LocationAccess(HC_STORMS_GROTTO_GOSSIP_STONE, {[]{return CanBlastOrSmash;}}), + }, { + //Exits + Entrance(CASTLE_GROUNDS, {[]{return true;}}), + }); + + areaTable[GANONS_CASTLE_GROUNDS] = Area("Ganon's Castle Grounds", "Castle Grounds", OUTSIDE_GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations //the terrain was lowered such that you can't get this GS with a simple sword slash + LocationAccess(OGC_GS, {[]{return HasExplosives || (IsAdult && (LogicOutsideGanonsGS || Bow || HookshotOrBoomerang || CanUse(DINS_FIRE)));}}), + }, { + //Exits + Entrance(CASTLE_GROUNDS, {[]{return AtNight;}}), + Entrance(OGC_GREAT_FAIRY_FOUNTAIN, {[]{return CanUse(GOLDEN_GAUNTLETS) && AtNight;}}), + Entrance(GANONS_CASTLE_ENTRYWAY, {[]{return CanBuildRainbowBridge;}, + /*Glitched*/[]{return (HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE)) || CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::ADVANCED) || (HoverBoots && CanShield && Bombs && CanDoGlitch(GlitchType::SuperSlide, GlitchDifficulty::EXPERT)) || (HoverBoots && CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::ADVANCED));}}), + }); + + areaTable[OGC_GREAT_FAIRY_FOUNTAIN] = Area("OGC Great Fairy Fountain", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(OGC_GREAT_FAIRY_REWARD, {[]{return CanPlay(ZeldasLullaby);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && Bombs && (CanSurviveDamage || (Fairy && NumBottles >= 2)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && ZeldasLullaby;}}), + }, { + //Exits + Entrance(CASTLE_GROUNDS, {[]{return true;}}), + }); + + areaTable[MARKET_GUARD_HOUSE] = Area("Market Guard House", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(MARKET_10_BIG_POES, {[]{return IsAdult && BigPoeKill;}}), + LocationAccess(MARKET_GS_GUARD_HOUSE, {[]{return IsChild;}}), + }, { + //Exits + Entrance(MARKET_ENTRANCE, {[]{return true;}}), + }); + + areaTable[MARKET_BAZAAR] = Area("Market Bazaar", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(MARKET_BAZAAR_ITEM_1, {[]{return true;}}), + LocationAccess(MARKET_BAZAAR_ITEM_2, {[]{return true;}}), + LocationAccess(MARKET_BAZAAR_ITEM_3, {[]{return true;}}), + LocationAccess(MARKET_BAZAAR_ITEM_4, {[]{return true;}}), + LocationAccess(MARKET_BAZAAR_ITEM_5, {[]{return true;}}), + LocationAccess(MARKET_BAZAAR_ITEM_6, {[]{return true;}}), + LocationAccess(MARKET_BAZAAR_ITEM_7, {[]{return true;}}), + LocationAccess(MARKET_BAZAAR_ITEM_8, {[]{return true;}}), + }, { + //Exits + Entrance(THE_MARKET, {[]{return true;}}), + }); + + areaTable[MARKET_MASK_SHOP] = Area("Market Mask Shop", "", NONE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&SkullMask, {[]{return SkullMask || (ZeldasLetter && (CompleteMaskQuest || ChildCanAccess(KAKARIKO_VILLAGE)));}}), + EventAccess(&MaskOfTruth, {[]{return MaskOfTruth || (SkullMask && (CompleteMaskQuest || (ChildCanAccess(THE_LOST_WOODS) && CanPlay(SariasSong) && AreaTable(THE_GRAVEYARD)->childDay && ChildCanAccess(HYRULE_FIELD) && HasAllStones)));}}), + }, {}, { + //Exits + Entrance(THE_MARKET, {[]{return true;}}), + }); + + areaTable[MARKET_SHOOTING_GALLERY] = Area("Market Shooting Gallery", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(MARKET_SHOOTING_GALLERY_REWARD, {[]{return IsChild;}}), + }, { + //Exits + Entrance(THE_MARKET, {[]{return true;}}), + }); + + areaTable[MARKET_BOMBCHU_BOWLING] = Area("Market Bombchu Bowling", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, {[]{return CanPlayBowling;}}), + LocationAccess(MARKET_BOMBCHU_BOWLING_SECOND_PRIZE, {[]{return CanPlayBowling;}}), + LocationAccess(MARKET_BOMBCHU_BOWLING_BOMBCHUS, {[]{return CanPlayBowling;}}), + }, { + //Exits + Entrance(THE_MARKET, {[]{return true;}}), + }); + + areaTable[MARKET_POTION_SHOP] = Area("Market Potion Shop", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(MARKET_POTION_SHOP_ITEM_1, {[]{return true;}}), + LocationAccess(MARKET_POTION_SHOP_ITEM_2, {[]{return true;}}), + LocationAccess(MARKET_POTION_SHOP_ITEM_3, {[]{return true;}}), + LocationAccess(MARKET_POTION_SHOP_ITEM_4, {[]{return true;}}), + LocationAccess(MARKET_POTION_SHOP_ITEM_5, {[]{return true;}}), + LocationAccess(MARKET_POTION_SHOP_ITEM_6, {[]{return true;}}), + LocationAccess(MARKET_POTION_SHOP_ITEM_7, {[]{return true;}}), + LocationAccess(MARKET_POTION_SHOP_ITEM_8, {[]{return true;}}), + }, { + //Exits + Entrance(THE_MARKET, {[]{return true;}}), + }); + + areaTable[MARKET_TREASURE_CHEST_GAME] = Area("Market Treasure Chest Game", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(MARKET_TREASURE_CHEST_GAME_REWARD, {[]{return (CanUse(LENS_OF_TRUTH) && !ShuffleChestMinigame) || (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_SINGLE_KEYS) && SmallKeys(MARKET_TREASURE_CHEST_GAME, 6)) || (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_PACK) && SmallKeys(MARKET_TREASURE_CHEST_GAME, 1));}, + /*Glitched*/[]{return !ShuffleChestMinigame && (CanUse(FARORES_WIND) && (HasBottle || WeirdEgg) && CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE));}}), + LocationAccess(MARKET_TREASURE_CHEST_GAME_ITEM_1, {[]{return (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_SINGLE_KEYS) && SmallKeys(MARKET_TREASURE_CHEST_GAME, 1)) || (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_PACK) && SmallKeys(MARKET_TREASURE_CHEST_GAME, 1)) || (CanUse(LENS_OF_TRUTH) && !ShuffleChestMinigame);}}), + LocationAccess(MARKET_TREASURE_CHEST_GAME_ITEM_2, {[]{return (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_SINGLE_KEYS) && SmallKeys(MARKET_TREASURE_CHEST_GAME, 2)) || (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_PACK) && SmallKeys(MARKET_TREASURE_CHEST_GAME, 1)) || (CanUse(LENS_OF_TRUTH) && !ShuffleChestMinigame);}}), + LocationAccess(MARKET_TREASURE_CHEST_GAME_ITEM_3, {[]{return (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_SINGLE_KEYS) && SmallKeys(MARKET_TREASURE_CHEST_GAME, 3)) || (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_PACK) && SmallKeys(MARKET_TREASURE_CHEST_GAME, 1)) || (CanUse(LENS_OF_TRUTH) && !ShuffleChestMinigame);}}), + LocationAccess(MARKET_TREASURE_CHEST_GAME_ITEM_4, {[]{return (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_SINGLE_KEYS) && SmallKeys(MARKET_TREASURE_CHEST_GAME, 4)) || (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_PACK) && SmallKeys(MARKET_TREASURE_CHEST_GAME, 1)) || (CanUse(LENS_OF_TRUTH) && !ShuffleChestMinigame);}}), + LocationAccess(MARKET_TREASURE_CHEST_GAME_ITEM_5, {[]{return (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_SINGLE_KEYS) && SmallKeys(MARKET_TREASURE_CHEST_GAME, 5)) || (ShuffleChestMinigame.Is(SHUFFLECHESTMINIGAME_PACK) && SmallKeys(MARKET_TREASURE_CHEST_GAME, 1)) || (CanUse(LENS_OF_TRUTH) && !ShuffleChestMinigame);}}), + }, { + //Exits + Entrance(THE_MARKET, {[]{return true;}}), + }); + + areaTable[MARKET_BOMBCHU_SHOP] = Area("Market Bombchu Shop", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(MARKET_BOMBCHU_SHOP_ITEM_1, {[]{return true;}}), + LocationAccess(MARKET_BOMBCHU_SHOP_ITEM_2, {[]{return true;}}), + LocationAccess(MARKET_BOMBCHU_SHOP_ITEM_3, {[]{return true;}}), + LocationAccess(MARKET_BOMBCHU_SHOP_ITEM_4, {[]{return true;}}), + LocationAccess(MARKET_BOMBCHU_SHOP_ITEM_5, {[]{return true;}}), + LocationAccess(MARKET_BOMBCHU_SHOP_ITEM_6, {[]{return true;}}), + LocationAccess(MARKET_BOMBCHU_SHOP_ITEM_7, {[]{return true;}}), + LocationAccess(MARKET_BOMBCHU_SHOP_ITEM_8, {[]{return true;}}), + }, { + //Exits + Entrance(MARKET_BACK_ALLEY, {[]{return true;}}), + }); + + areaTable[MARKET_DOG_LADY_HOUSE] = Area("Market Dog Lady House", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(MARKET_LOST_DOG, {[]{return IsChild && AtNight;}}), + }, { + //Exits + Entrance(MARKET_BACK_ALLEY, {[]{return true;}}), + }); + + areaTable[MARKET_MAN_IN_GREEN_HOUSE] = Area("Market Man in Green House", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(MARKET_BACK_ALLEY, {[]{return true;}}), + }); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_death_mountain.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_death_mountain.cpp new file mode 100644 index 000000000..b7a23c316 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_death_mountain.cpp @@ -0,0 +1,293 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_DeathMountain() { + areaTable[DEATH_MOUNTAIN_TRAIL] = Area("Death Mountain", "Death Mountain", DEATH_MOUNTAIN_TRAIL, DAY_NIGHT_CYCLE, { + //Events + EventAccess(&BeanPlantFairy, {[]{return BeanPlantFairy || (CanPlantBean(DEATH_MOUNTAIN_TRAIL) && CanPlay(SongOfStorms) && (HasExplosives || GoronBracelet));}}), + }, { + //Locations + LocationAccess(DMT_CHEST, {[]{return CanBlastOrSmash || (LogicDMTBombable && IsChild && GoronBracelet);}, + /*Glitched*/[]{return CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);}}), + LocationAccess(DMT_FREESTANDING_POH, {[]{return CanTakeDamage || CanUse(HOVER_BOOTS) || (IsAdult && CanPlantBean(DEATH_MOUNTAIN_TRAIL) && (HasExplosives || GoronBracelet));}}), + LocationAccess(DMT_GS_BEAN_PATCH, {[]{return CanPlantBugs && (HasExplosives || GoronBracelet || (LogicDMTSoilGS && (CanTakeDamage || CanUse(HOVER_BOOTS)) && CanUse(BOOMERANG)));}}), + LocationAccess(DMT_GS_NEAR_KAK, {[]{return CanBlastOrSmash;}, + /*Glitched*/[]{return (CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED));}}), + LocationAccess(DMT_GS_ABOVE_DODONGOS_CAVERN, {[]{return IsAdult && AtNight && CanUse(MEGATON_HAMMER) && CanGetNightTimeGS;}, + /*Glitched*/[]{return IsAdult && AtNight && CanGetNightTimeGS && CanUse(STICKS) && ((CanTakeDamageTwice && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::NOVICE)) || CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED));}}), + }, { + //Exits + Entrance(KAK_BEHIND_GATE, {[]{return true;}}), + Entrance(GORON_CITY, {[]{return true;}}), + Entrance(DEATH_MOUNTAIN_SUMMIT, {[]{return Here(DEATH_MOUNTAIN_TRAIL, []{return CanBlastOrSmash;}) || (IsAdult && ((CanPlantBean(DEATH_MOUNTAIN_TRAIL) && GoronBracelet) || (HoverBoots && LogicDMTSummitHover)));}, + /*Glitched*/[]{return IsAdult && Here(DEATH_MOUNTAIN_TRAIL, []{return CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);});}}), + Entrance(DODONGOS_CAVERN_ENTRYWAY, {[]{return HasExplosives || GoronBracelet || IsAdult;}}), + Entrance(DMT_STORMS_GROTTO, {[]{return CanOpenStormGrotto;}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && SongOfStorms && (ShardOfAgony || LogicGrottosWithoutAgony);}}), + }); + + areaTable[DEATH_MOUNTAIN_SUMMIT] = Area("Death Mountain Summit", "Death Mountain", DEATH_MOUNTAIN_TRAIL, DAY_NIGHT_CYCLE, { + //Events + EventAccess(&PrescriptionAccess, {[]{return PrescriptionAccess || (IsAdult && (BrokenSwordAccess || BrokenSword));}}), + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || CanSummonGossipFairy;}}), + EventAccess(&BugRock, {[]{return BugRock || IsChild;}}), + }, { + //Locations + LocationAccess(DMT_TRADE_BROKEN_SWORD, {[]{return IsAdult && BrokenSword;}}), + LocationAccess(DMT_TRADE_EYEDROPS, {[]{return IsAdult && Eyedrops;}}), + LocationAccess(DMT_TRADE_CLAIM_CHECK, {[]{return IsAdult && ClaimCheck;}}), + LocationAccess(DMT_GS_FALLING_ROCKS_PATH, {[]{return IsAdult && AtNight && CanUse(MEGATON_HAMMER) && CanGetNightTimeGS;}}), + LocationAccess(DMT_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(DEATH_MOUNTAIN_TRAIL, {[]{return true;}}), + Entrance(DMC_UPPER_LOCAL, {[]{return true;}}), + Entrance(DMT_OWL_FLIGHT, {[]{return IsChild;}}), + Entrance(DMT_COW_GROTTO, {[]{return Here(DEATH_MOUNTAIN_SUMMIT, []{return CanBlastOrSmash;});}, + /*Glitched*/[]{return Here(DEATH_MOUNTAIN_SUMMIT, []{return CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);});}}), + Entrance(DMT_GREAT_FAIRY_FOUNTAIN, {[]{return Here(DEATH_MOUNTAIN_SUMMIT, []{return CanBlastOrSmash;});}, + /*Glitched*/[]{return ((KokiriSword || Sticks || IsAdult) && CanDoGlitch(GlitchType::SeamWalk, GlitchDifficulty::ADVANCED)) || (IsChild && CanDoGlitch(GlitchType::TripleSlashClip, GlitchDifficulty::EXPERT));}}), + }); + + areaTable[DMT_OWL_FLIGHT] = Area("DMT Owl Flight", "Death Mountain", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(KAK_IMPAS_LEDGE, {[]{return true;}}), + }); + + areaTable[DMT_COW_GROTTO] = Area("DMT Cow Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DMT_COW_GROTTO_COW, {[]{return CanPlay(EponasSong);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && (CanSurviveDamage || (Fairy && NumBottles >= 2)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && EponasSong;}}), + }, { + //Exits + Entrance(DEATH_MOUNTAIN_SUMMIT, {[]{return true;}}), + + }); + + areaTable[DMT_STORMS_GROTTO] = Area("DMT Storms Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, { + //Locations + LocationAccess(DMT_STORMS_GROTTO_CHEST, {[]{return true;}}), + LocationAccess(DMT_STORMS_GROTTO_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(DEATH_MOUNTAIN_TRAIL, {[]{return true;}}), + }); + + areaTable[DMT_GREAT_FAIRY_FOUNTAIN] = Area("DMT Great Fairy Fountain", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DMT_GREAT_FAIRY_REWARD, {[]{return CanPlay(ZeldasLullaby);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && (CanSurviveDamage || (Fairy && NumBottles >= 2)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && ZeldasLullaby;}}), + }, { + //Exits + Entrance(DEATH_MOUNTAIN_SUMMIT, {[]{return true;}}), + }); + + areaTable[GORON_CITY] = Area("Goron City", "Goron City", GORON_CITY, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || CanSummonGossipFairyWithoutSuns;}}), + EventAccess(&StickPot, {[]{return StickPot || IsChild;}}), + EventAccess(&BugRock, {[]{return BugRock || (CanBlastOrSmash || CanUse(SILVER_GAUNTLETS));}}), + EventAccess(&GoronCityChildFire, {[]{return GoronCityChildFire || (IsChild && CanUse(DINS_FIRE));}, + /*Glitched*/[]{return IsChild && CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::INTERMEDIATE);}}), + EventAccess(&GCWoodsWarpOpen, {[]{return GCWoodsWarpOpen || (CanBlastOrSmash || CanUse(DINS_FIRE) || CanUse(BOW) || GoronBracelet || GoronCityChildFire);}, + /*Glitched*/[]{return (CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED));}}), + EventAccess(&GCDaruniasDoorOpenChild, {[]{return GCDaruniasDoorOpenChild || (IsChild && CanPlay(ZeldasLullaby));}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && IsChild && ZeldasLullaby;}}), + EventAccess(&StopGCRollingGoronAsAdult, {[]{return StopGCRollingGoronAsAdult || (IsAdult && (GoronBracelet || HasExplosives || Bow || (LogicLinkGoronDins && CanUse(DINS_FIRE))));}}), + }, { + //Locations + LocationAccess(GC_MAZE_LEFT_CHEST, {[]{return CanUse(MEGATON_HAMMER) || CanUse(SILVER_GAUNTLETS) || (LogicGoronCityLeftMost && HasExplosives && CanUse(HOVER_BOOTS));}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::ASlide, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE);}}), + LocationAccess(GC_MAZE_CENTER_CHEST, {[]{return CanBlastOrSmash || CanUse(SILVER_GAUNTLETS);}}), + LocationAccess(GC_MAZE_RIGHT_CHEST, {[]{return CanBlastOrSmash || CanUse(SILVER_GAUNTLETS);}}), + LocationAccess(GC_POT_FREESTANDING_POH, {[]{return IsChild && GoronCityChildFire && (Bombs || (GoronBracelet && LogicGoronCityPotWithStrength) || (HasBombchus && LogicGoronCityPot));}}), + LocationAccess(GC_ROLLING_GORON_AS_CHILD, {[]{return IsChild && (HasExplosives || (GoronBracelet && LogicChildRollingWithStrength));}}), + LocationAccess(GC_ROLLING_GORON_AS_ADULT, {[]{return StopGCRollingGoronAsAdult;}}), + LocationAccess(GC_GS_BOULDER_MAZE, {[]{return IsChild && CanBlastOrSmash;}}), + LocationAccess(GC_GS_CENTER_PLATFORM, {[]{return IsAdult;}}), + LocationAccess(GC_MEDIGORON, {[]{return IsAdult && AdultsWallet && (CanBlastOrSmash || GoronBracelet);}}), + LocationAccess(GC_MAZE_GOSSIP_STONE, {[]{return CanBlastOrSmash || CanUse(SILVER_GAUNTLETS);}}), + LocationAccess(GC_MEDIGORON_GOSSIP_STONE, {[]{return CanBlastOrSmash || GoronBracelet;}}), + }, { + //Exits + Entrance(DEATH_MOUNTAIN_TRAIL, {[]{return true;}}), + Entrance(GC_WOODS_WARP, {[]{return GCWoodsWarpOpen;}}), + Entrance(GC_SHOP, {[]{return (IsAdult && StopGCRollingGoronAsAdult) || (IsChild && (CanBlastOrSmash || GoronBracelet || GoronCityChildFire || CanUse(BOW)));}, + /*Glitched*/[]{return IsChild && Sticks && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);}}), + Entrance(GC_DARUNIAS_CHAMBER, {[]{return (IsAdult && StopGCRollingGoronAsAdult) || GCDaruniasDoorOpenChild;}}), + Entrance(GC_GROTTO, {[]{return IsAdult && ((CanPlay(SongOfTime) && ((EffectiveHealth > 2) || CanUse(GORON_TUNIC) || CanUse(LONGSHOT) || CanUse(NAYRUS_LOVE))) || (EffectiveHealth > 1 && CanUse(GORON_TUNIC) && CanUse(HOOKSHOT)) || (CanUse(NAYRUS_LOVE) && CanUse(HOOKSHOT)));}, + /*Glitched*/[]{return (HasBombchus && ((IsChild && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE)) || CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE))) || (IsChild && CanUse(LONGSHOT));}}), + }); + + areaTable[GC_WOODS_WARP] = Area("GC Woods Warp", "Goron City", NONE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&GCWoodsWarpOpen, {[]{return GCWoodsWarpOpen || (CanBlastOrSmash || CanUse(DINS_FIRE));}}), + }, {}, { + //Exits + Entrance(GORON_CITY, {[]{return CanLeaveForest && GCWoodsWarpOpen;}}), + Entrance(THE_LOST_WOODS, {[]{return true;}}), + }); + + areaTable[GC_DARUNIAS_CHAMBER] = Area("GC Darunias Chamber", "Goron City", GORON_CITY, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&GoronCityChildFire, {[]{return GoronCityChildFire || (IsChild && CanUse(STICKS));}}), + }, { + //Locations + LocationAccess(GC_DARUNIAS_JOY, {[]{return IsChild && CanPlay(SariasSong);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && ((Bombs && (CanSurviveDamage || (Fairy && NumBottles >= 2))) || GCDaruniasDoorOpenChild) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && IsChild && SariasSong;}}), + }, { + //Exits + Entrance(GORON_CITY, {[]{return true;}}), + Entrance(DMC_LOWER_LOCAL, {[]{return IsAdult;}, + /*Glitched*/[]{return IsChild && GCDaruniasDoorOpenChild && (KokiriSword || Sticks) && GlitchOccamsStatue;}}), + }); + + areaTable[GC_GROTTO_PLATFORM] = Area("GC Grotto Platform", "Goron City", GORON_CITY, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(GC_GROTTO, {[]{return true;}}), + Entrance(GORON_CITY, {[]{return EffectiveHealth > 2 || CanUse(GORON_TUNIC) || CanUse(NAYRUS_LOVE) || ((IsChild || CanPlay(SongOfTime)) && CanUse(LONGSHOT));}}), + }); + + areaTable[GC_SHOP] = Area("GC Shop", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GC_SHOP_ITEM_1, {[]{return true;}}), + LocationAccess(GC_SHOP_ITEM_2, {[]{return true;}}), + LocationAccess(GC_SHOP_ITEM_3, {[]{return true;}}), + LocationAccess(GC_SHOP_ITEM_4, {[]{return true;}}), + LocationAccess(GC_SHOP_ITEM_5, {[]{return true;}}), + LocationAccess(GC_SHOP_ITEM_6, {[]{return true;}}), + LocationAccess(GC_SHOP_ITEM_7, {[]{return true;}}), + LocationAccess(GC_SHOP_ITEM_8, {[]{return true;}}), + }, { + //Exits + Entrance(GORON_CITY, {[]{return true;}}), + }); + + areaTable[GC_GROTTO] = Area("GC Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GC_DEKU_SCRUB_GROTTO_LEFT, {[]{return CanStunDeku;}}), + LocationAccess(GC_DEKU_SCRUB_GROTTO_RIGHT, {[]{return CanStunDeku;}}), + LocationAccess(GC_DEKU_SCRUB_GROTTO_CENTER, {[]{return CanStunDeku;}}), + }, { + //Exits + Entrance(GC_GROTTO_PLATFORM, {[]{return true;}}), + }); + + areaTable[DMC_UPPER_NEARBY] = Area("DMC Upper Nearby", "Death Mountain Crater", DEATH_MOUNTAIN_CRATER, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DMC_UPPER_LOCAL, {[]{return FireTimer >= 48;}}), + Entrance(DEATH_MOUNTAIN_SUMMIT, {[]{return true;}}), + Entrance(DMC_UPPER_GROTTO, {[]{return Here(DMC_UPPER_NEARBY, []{return CanBlastOrSmash && (FireTimer >= 8 || Hearts >= 3);});}, + /*Glitched*/[]{return Here(DMC_UPPER_NEARBY, []{return CanUse(STICKS) && FireTimer >= 48 && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);});}}) + }); + + areaTable[DMC_UPPER_LOCAL] = Area("DMC Upper Local", "Death Mountain Crater", DEATH_MOUNTAIN_CRATER, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || (HasExplosives && CanSummonGossipFairyWithoutSuns && (FireTimer >= 16 || Hearts >= 3));}}), + }, { + //Locations + LocationAccess(DMC_WALL_FREESTANDING_POH, {[]{return FireTimer >= 16 || Hearts >= 3;}}), + LocationAccess(DMC_GS_CRATE, {[]{return (FireTimer >= 8 || Hearts >= 3) && IsChild && CanChildAttack;}}), + LocationAccess(DMC_GOSSIP_STONE, {[]{return HasExplosives && (FireTimer >= 16 || Hearts >= 3);}}), + }, { + //Exits + Entrance(DMC_UPPER_NEARBY, {[]{return true;}}), + Entrance(DMC_LADDER_AREA_NEARBY, {[]{return FireTimer >= 16 || Hearts >= 3;}}), + Entrance(DMC_CENTRAL_NEARBY, {[]{return IsAdult && CanUse(GORON_TUNIC) && CanUse(DISTANT_SCARECROW) && ((EffectiveHealth > 2) || (Fairy && ShuffleDungeonEntrances.IsNot(SHUFFLEDUNGEONS_OFF)) || CanUse(NAYRUS_LOVE));}, + /*Glitched*/[]{return FireTimer >= 24 && CanTakeDamage && CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE);}}), + Entrance(DMC_LOWER_NEARBY, {[]{return false;}, + /*Glitched*/[]{return FireTimer >= 24 && CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE);}}), + }); + + areaTable[DMC_LADDER_AREA_NEARBY] = Area("DMC Ladder Area Nearby", "Death Mountain Crater", DEATH_MOUNTAIN_CRATER, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DMC_DEKU_SCRUB, {[]{return IsChild && CanStunDeku;}}), + }, { + //Exits + Entrance(DMC_UPPER_NEARBY, {[]{return Hearts >= 3;}}), + Entrance(DMC_LOWER_NEARBY, {[]{return Hearts >= 3 && (CanUse(HOVER_BOOTS) || (LogicCraterUpperToLower && IsAdult && CanUse(MEGATON_HAMMER)));}}), + }); + + areaTable[DMC_LOWER_NEARBY] = Area("DMC Lower Nearby", "Death Mountain Crater", DEATH_MOUNTAIN_CRATER, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DMC_LOWER_LOCAL, {[]{return FireTimer >= 48;}}), + Entrance(GC_DARUNIAS_CHAMBER, {[]{return true;}}), + Entrance(DMC_GREAT_FAIRY_FOUNTAIN, {[]{return CanUse(MEGATON_HAMMER);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::ASlide, GlitchDifficulty::INTERMEDIATE) || (FireTimer >= 48 && CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::NOVICE) && (CanTakeDamageTwice || CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED))) || + (Bombs && CanShield && FireTimer >= 48 && CanDoGlitch(GlitchType::SuperSlide, GlitchDifficulty::EXPERT)) || Here(DMC_UPPER_LOCAL, []{return CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::ADVANCED);});}}), + Entrance(DMC_HAMMER_GROTTO, {[]{return IsAdult && CanUse(MEGATON_HAMMER);}, + /*Glitched*/[]{return IsAdult && FireTimer >= 48 && CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::NOVICE) && (CanTakeDamageTwice || CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED));}}), + }); + + areaTable[DMC_LOWER_LOCAL] = Area("DMC Lower Local", "Death Mountain Crater", DEATH_MOUNTAIN_CRATER, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DMC_LOWER_NEARBY, {[]{return true;}}), + Entrance(DMC_LADDER_AREA_NEARBY, {[]{return true;}}), + Entrance(DMC_CENTRAL_NEARBY, {[]{return (CanUse(HOVER_BOOTS) || CanUse(HOOKSHOT)) && (FireTimer >= 8 || Hearts >= 3);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE) && (FireTimer >= 8 || Hearts >= 3);}}), + Entrance(DMC_CENTRAL_LOCAL, {[]{return (CanUse(HOVER_BOOTS) || CanUse(HOOKSHOT)) && FireTimer >= 24;}}), + }); + + areaTable[DMC_CENTRAL_NEARBY] = Area("DMC Central Nearby", "Death Mountain Crater", DEATH_MOUNTAIN_CRATER, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DMC_VOLCANO_FREESTANDING_POH, {[]{return IsAdult && Hearts >= 3 && (CanPlantBean(DMC_CENTRAL_LOCAL) || (LogicCraterBeanPoHWithHovers && HoverBoots));}, + /*Glitched*/[]{return Here(DMC_LOWER_LOCAL, []{return CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE) && FireTimer >= 24;});}}), + LocationAccess(SHEIK_IN_CRATER, {[]{return IsAdult && (FireTimer >= 8 || Hearts >= 3);}}), + }, { + //Exits + Entrance(DMC_CENTRAL_LOCAL, {[]{return FireTimer >= 48;}}), + }); + + areaTable[DMC_CENTRAL_LOCAL] = Area("DMC Central Local", "Death Mountain Crater", DEATH_MOUNTAIN_CRATER, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&BeanPlantFairy, {[]{return BeanPlantFairy || (CanPlantBean(DMC_CENTRAL_LOCAL) && CanPlay(SongOfStorms));}}), + }, { + //Locations + LocationAccess(DMC_GS_BEAN_PATCH, {[]{return (FireTimer >= 8 || Hearts >= 3) && CanPlantBugs && CanChildAttack;}}), + }, { + //Exits + Entrance(DMC_CENTRAL_NEARBY, {[]{return true;}}), + Entrance(DMC_LOWER_NEARBY, {[]{return (IsAdult && CanPlantBean(DMC_CENTRAL_LOCAL)) || CanUse(HOVER_BOOTS) || CanUse(HOOKSHOT);}, + /*Glitched*/[]{return IsChild && Hearts >= 3 && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE);}}), + Entrance(DMC_UPPER_NEARBY, {[]{return IsAdult && CanPlantBean(DMC_CENTRAL_LOCAL);}}), + Entrance(FIRE_TEMPLE_ENTRYWAY, {[]{return (IsChild && Hearts >= 3 && ShuffleDungeonEntrances.IsNot(SHUFFLEDUNGEONS_OFF)) || (IsAdult && FireTimer >= 24);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::ASlide, GlitchDifficulty::INTERMEDIATE) && FireTimer >= 48;}}), + }); + + areaTable[DMC_GREAT_FAIRY_FOUNTAIN] = Area("DMC Great Fairy Fountain", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DMC_GREAT_FAIRY_REWARD, {[]{return CanPlay(ZeldasLullaby);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && (CanTakeDamage || (Fairy && NumBottles >= 2)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && ZeldasLullaby;}}), + }, { + //Exits + Entrance(DMC_LOWER_LOCAL, {[]{return true;}}), + }); + + areaTable[DMC_UPPER_GROTTO] = Area("DMC Upper Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, { + //Locations + LocationAccess(DMC_UPPER_GROTTO_CHEST, {[]{return true;}}), + LocationAccess(DMC_UPPER_GROTTO_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(DMC_UPPER_LOCAL, {[]{return true;}}), + }); + + areaTable[DMC_HAMMER_GROTTO] = Area("DMC Hammer Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DMC_DEKU_SCRUB_GROTTO_LEFT, {[]{return CanStunDeku;}}), + LocationAccess(DMC_DEKU_SCRUB_GROTTO_RIGHT, {[]{return CanStunDeku;}}), + LocationAccess(DMC_DEKU_SCRUB_GROTTO_CENTER, {[]{return CanStunDeku;}}), + }, { + //Exits + Entrance(DMC_LOWER_LOCAL, {[]{return true;}}), + }); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_deku_tree.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_deku_tree.cpp new file mode 100644 index 000000000..c67e5d3bd --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_deku_tree.cpp @@ -0,0 +1,266 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" +#include "../dungeon.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_DekuTree() { + /*-------------------------- + | VANILLA/MQ DECIDER | + ---------------------------*/ + areaTable[DEKU_TREE_ENTRYWAY] = Area("Deku Tree Entryway", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DEKU_TREE_LOBBY, {[]{return Dungeon::DekuTree.IsVanilla();}}), + Entrance(DEKU_TREE_MQ_LOBBY, {[]{return Dungeon::DekuTree.IsMQ();}}), + Entrance(KF_OUTSIDE_DEKU_TREE, {[]{return true;}}), + }); + + /*-------------------------- + | VANILLA DUNGEON | + ---------------------------*/ + if (Dungeon::DekuTree.IsVanilla()) { + areaTable[DEKU_TREE_LOBBY] = Area("Deku Tree Lobby", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DekuBabaSticks, {[]{return DekuBabaSticks || (IsAdult || KokiriSword || Boomerang);}}), + EventAccess(&DekuBabaNuts, {[]{return DekuBabaNuts || (IsAdult || KokiriSword || Slingshot || Sticks || HasExplosives || CanUse(DINS_FIRE));}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }, { + //Locations + LocationAccess(DEKU_TREE_MAP_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(DEKU_TREE_ENTRYWAY, {[]{return true;}}), + Entrance(DEKU_TREE_2F_MIDDLE_ROOM, {[]{return true;}}), + Entrance(DEKU_TREE_COMPASS_ROOM, {[]{return true;}}), + Entrance(DEKU_TREE_BASEMENT_LOWER, {[]{return Here(DEKU_TREE_LOBBY, []{return IsAdult || CanChildAttack || Nuts;});}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + Entrance(DEKU_TREE_OUTSIDE_BOSS_ROOM, {[]{return false;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE);}}), + Entrance(DEKU_TREE_BOSS_ROOM, {[]{return false;}, + /*Glitched*/[]{return IsChild && CanUse(KOKIRI_SWORD) && Nuts && CanDoGlitch(GlitchType::SeamWalk, GlitchDifficulty::EXPERT);}}), + }); + + areaTable[DEKU_TREE_2F_MIDDLE_ROOM] = Area("Deku Tree 2F Middle Room", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DEKU_TREE_LOBBY, {[]{return Here(DEKU_TREE_2F_MIDDLE_ROOM, []{return HasShield || CanUse(MEGATON_HAMMER);});}}), + Entrance(DEKU_TREE_SLINGSHOT_ROOM,{[]{return Here(DEKU_TREE_2F_MIDDLE_ROOM, []{return HasShield || CanUse(MEGATON_HAMMER);});}}), + }); + + areaTable[DEKU_TREE_SLINGSHOT_ROOM] = Area("Deku Tree Slingshot Room", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DEKU_TREE_SLINGSHOT_CHEST, {[]{return true;}}), + LocationAccess(DEKU_TREE_SLINGSHOT_ROOM_SIDE_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(DEKU_TREE_2F_MIDDLE_ROOM, {[]{return CanUse(SLINGSHOT) || CanUse(HOVER_BOOTS);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::INTERMEDIATE);}}), + }); + + areaTable[DEKU_TREE_COMPASS_ROOM] = Area("Deku Tree Compass Room", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DekuBabaSticks, {[]{return DekuBabaSticks || (IsAdult || KokiriSword || Boomerang);}}), + EventAccess(&DekuBabaNuts, {[]{return DekuBabaNuts || (IsAdult || KokiriSword || Slingshot || Sticks || HasExplosives || CanUse(DINS_FIRE));}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }, { + //Locations + LocationAccess(DEKU_TREE_COMPASS_CHEST, {[]{return true;}}), + LocationAccess(DEKU_TREE_COMPASS_ROOM_SIDE_CHEST, {[]{return true;}}), + LocationAccess(DEKU_TREE_GS_COMPASS_ROOM, {[]{return IsAdult || CanChildAttack;}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }, { + //Exits + Entrance(DEKU_TREE_LOBBY, {[]{return HasFireSourceWithTorch || CanUse(BOW);}}), + Entrance(DEKU_TREE_BOSS_ROOM, {[]{return false;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::ADVANCED);}}), + }); + + areaTable[DEKU_TREE_BASEMENT_LOWER] = Area("Deku Tree Basement Lower", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DekuBabaSticks, {[]{return DekuBabaSticks || (IsAdult || KokiriSword || Boomerang);}}), + EventAccess(&DekuBabaNuts, {[]{return DekuBabaNuts || (IsAdult || KokiriSword || Slingshot || Sticks || HasExplosives || CanUse(DINS_FIRE));}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }, { + //Locations + LocationAccess(DEKU_TREE_BASEMENT_CHEST, {[]{return true;}}), + LocationAccess(DEKU_TREE_GS_BASEMENT_GATE, {[]{return IsAdult || CanChildAttack;}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + LocationAccess(DEKU_TREE_GS_BASEMENT_VINES, {[]{return CanUseProjectile || CanUse(DINS_FIRE) || (LogicDekuBasementGS && (IsAdult || Sticks || KokiriSword));}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE);}}), + }, { + //Exits + Entrance(DEKU_TREE_LOBBY, {[]{return true;}}), + Entrance(DEKU_TREE_BASEMENT_SCRUB_ROOM, {[]{return Here(DEKU_TREE_BASEMENT_LOWER, []{return HasFireSourceWithTorch || CanUse(BOW);});}}), + Entrance(DEKU_TREE_BASEMENT_UPPER, {[]{return IsAdult || LogicDekuB1Skip || HasAccessTo(DEKU_TREE_BASEMENT_UPPER);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE);}}), + Entrance(DEKU_TREE_OUTSIDE_BOSS_ROOM, {[]{return false;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE);}}), + }); + + areaTable[DEKU_TREE_BASEMENT_SCRUB_ROOM] = Area("Deku Tree Basement Scrub Room", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DEKU_TREE_BASEMENT_LOWER, {[]{return true;}}), + Entrance(DEKU_TREE_BASEMENT_WATER_ROOM, {[]{return Here(DEKU_TREE_BASEMENT_SCRUB_ROOM, []{return CanUse(SLINGSHOT) || CanUse(BOW);});}}), + }); + + areaTable[DEKU_TREE_BASEMENT_WATER_ROOM] = Area("Deku Tree Basement Water Room", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DEKU_TREE_BASEMENT_SCRUB_ROOM, {[]{return true;}}), + Entrance(DEKU_TREE_BASEMENT_TORCH_ROOM, {[]{return true;}}), + }); + + areaTable[DEKU_TREE_BASEMENT_TORCH_ROOM] = Area("Deku Tree Basement Torch Room", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DekuBabaSticks, {[]{return DekuBabaSticks || (IsAdult || KokiriSword || Boomerang);}}), + EventAccess(&DekuBabaNuts, {[]{return DekuBabaNuts || (IsAdult || KokiriSword || Slingshot || Sticks || HasExplosives || CanUse(DINS_FIRE));}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }, {}, { + //Exits + Entrance(DEKU_TREE_BASEMENT_WATER_ROOM, {[]{return true;}}), + Entrance(DEKU_TREE_BASEMENT_BACK_LOBBY, {[]{return Here(DEKU_TREE_BASEMENT_TORCH_ROOM, []{return HasFireSourceWithTorch || CanUse(BOW);});}}), + }); + + areaTable[DEKU_TREE_BASEMENT_BACK_LOBBY] = Area("Deku Tree Basement Back Lobby", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DekuBabaSticks, {[]{return DekuBabaSticks || (IsAdult || KokiriSword || Boomerang);}}), + EventAccess(&DekuBabaNuts, {[]{return DekuBabaNuts || (Here(DEKU_TREE_BASEMENT_BACK_LOBBY, []{return HasFireSourceWithTorch || CanUse(BOW);}) && + (IsAdult || KokiriSword || Slingshot || Sticks || HasExplosives || CanUse(DINS_FIRE)));}, + /*Glitched*/[]{return Here(DEKU_TREE_BASEMENT_BACK_LOBBY, []{return HasFireSourceWithTorch || CanUse(BOW);}) && CanUse(MEGATON_HAMMER);}}), + }, {}, { + //Exits + Entrance(DEKU_TREE_BASEMENT_TORCH_ROOM, {[]{return true;}}), + Entrance(DEKU_TREE_BASEMENT_BACK_ROOM, {[]{return Here(DEKU_TREE_BASEMENT_BACK_LOBBY, []{return HasFireSourceWithTorch || CanUse(Bow);}) && + Here(DEKU_TREE_BASEMENT_BACK_LOBBY, []{return CanBlastOrSmash;});}, + /*Glitched*/[]{return Here(DEKU_TREE_BASEMENT_BACK_LOBBY, []{return HasFireSourceWithTorch || CanUse(Bow);}) && + Here(DEKU_TREE_BASEMENT_BACK_LOBBY, []{return (GlitchBlueFireWall && BlueFire) || (CanUse(STICKS) && CanTakeDamage && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::EXPERT));});}}), + Entrance(DEKU_TREE_BASEMENT_UPPER, {[]{return Here(DEKU_TREE_BASEMENT_BACK_LOBBY, []{return HasFireSourceWithTorch || CanUse(Bow);}) && IsChild;}}), + }); + + areaTable[DEKU_TREE_BASEMENT_BACK_ROOM] = Area("Deku Tree Basement Back Room", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DEKU_TREE_GS_BASEMENT_BACK_ROOM, {[]{return HookshotOrBoomerang;}, + /*Glitched*/[]{return Bombs && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE);}}), + }, { + //Exits + Entrance(DEKU_TREE_BASEMENT_BACK_LOBBY, {[]{return true;}}), + }); + + areaTable[DEKU_TREE_BASEMENT_UPPER] = Area("Deku Tree Basement Upper", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DekuBabaSticks, {[]{return DekuBabaSticks || (IsAdult || KokiriSword || Boomerang);}}), + EventAccess(&DekuBabaNuts, {[]{return DekuBabaNuts || (IsAdult || KokiriSword || Slingshot || Sticks || HasExplosives || CanUse(DINS_FIRE));}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }, {}, { + //Exits + Entrance(DEKU_TREE_BASEMENT_LOWER, {[]{return true;}}), + Entrance(DEKU_TREE_BASEMENT_BACK_LOBBY, {[]{return IsChild;}}), + Entrance(DEKU_TREE_OUTSIDE_BOSS_ROOM, {[]{return Here(DEKU_TREE_BASEMENT_UPPER, []{return HasFireSourceWithTorch || (LogicDekuB1WebsWithBow && IsAdult && CanUse(BOW));});}}), + }); + + areaTable[DEKU_TREE_OUTSIDE_BOSS_ROOM] = Area("Deku Tree Outside Boss Room", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DEKU_TREE_BASEMENT_UPPER, {[]{return true;}}), + Entrance(DEKU_TREE_BOSS_ROOM, {[]{return Here(DEKU_TREE_OUTSIDE_BOSS_ROOM, []{return HasShield;});}}), + }); + + areaTable[DEKU_TREE_BOSS_ROOM] = Area("Deku Tree Boss Room", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DekuTreeClear, {[]{return DekuTreeClear || ((IsAdult || KokiriSword || Sticks) && (Nuts || CanUse(SLINGSHOT) || CanUse(BOW) || HookshotOrBoomerang));}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE);}}), + }, { + //Locations + LocationAccess(QUEEN_GOHMA, {[]{return DekuTreeClear;}}), + LocationAccess(DEKU_TREE_QUEEN_GOHMA_HEART, {[]{return DekuTreeClear;}}), + }, { + //Exits + Entrance(DEKU_TREE_OUTSIDE_BOSS_ROOM, {[]{return true;}}), + Entrance(DEKU_TREE_ENTRYWAY, {[]{return DekuTreeClear;}}), + }); + } + + /*--------------------------- + | MASTER QUEST DUNGEON | + ---------------------------*/ + if (Dungeon::DekuTree.IsMQ()) { + areaTable[DEKU_TREE_MQ_LOBBY] = Area("Deku Tree MQ Lobby", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DekuBabaSticks, {[]{return DekuBabaSticks || (IsAdult || KokiriSword || Boomerang);}}), + EventAccess(&DekuBabaNuts, {[]{return DekuBabaNuts || (IsAdult || KokiriSword || Slingshot || Sticks || HasExplosives || CanUse(DINS_FIRE));}}), + }, { + //Locations + LocationAccess(DEKU_TREE_MQ_MAP_CHEST, {[]{return true;}}), + LocationAccess(DEKU_TREE_MQ_SLINGSHOT_CHEST, {[]{return IsAdult || CanChildAttack;}}), + LocationAccess(DEKU_TREE_MQ_SLINGSHOT_ROOM_BACK_CHEST, {[]{return HasFireSourceWithTorch || (IsAdult && CanUse(BOW));}}), + LocationAccess(DEKU_TREE_MQ_BASEMENT_CHEST, {[]{return HasFireSourceWithTorch || (IsAdult && CanUse(BOW));}}), + LocationAccess(DEKU_TREE_MQ_GS_LOBBY, {[]{return IsAdult || CanChildAttack;}}), + }, { + //Exits + Entrance(DEKU_TREE_ENTRYWAY, {[]{return true;}}), + Entrance(DEKU_TREE_MQ_COMPASS_ROOM, {[]{return Here(DEKU_TREE_MQ_LOBBY, []{return (IsChild && CanUse(SLINGSHOT)) || (IsAdult && CanUse(BOW));}) && + Here(DEKU_TREE_MQ_LOBBY, []{return HasFireSourceWithTorch || (IsAdult && CanUse(BOW));});}}), + Entrance(DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT, {[]{return Here(DEKU_TREE_MQ_LOBBY, []{return (IsChild && CanUse(SLINGSHOT)) || (IsAdult && CanUse(BOW));}) && + Here(DEKU_TREE_MQ_LOBBY, []{return HasFireSourceWithTorch;});}}), + Entrance(DEKU_TREE_MQ_BASEMENT_LEDGE, {[]{return LogicDekuB1Skip || Here(DEKU_TREE_MQ_LOBBY, []{return IsAdult;});}}), + }); + + areaTable[DEKU_TREE_MQ_COMPASS_ROOM] = Area("Deku Tree MQ Compass Room", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DEKU_TREE_MQ_COMPASS_CHEST, {[]{return true;}}), + LocationAccess(DEKU_TREE_MQ_GS_COMPASS_ROOM, {[]{return HookshotOrBoomerang && + Here(DEKU_TREE_MQ_COMPASS_ROOM, []{return HasBombchus || + (Bombs && (CanPlay(SongOfTime) || IsAdult)) || + (IsAdult && CanUse(MEGATON_HAMMER) && (CanPlay(SongOfTime) /*|| LogicDekuMQCompassGS*/));});}}), + }, { + //Exits + Entrance(DEKU_TREE_MQ_LOBBY, {[]{return true;}}), + }); + + areaTable[DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT] = Area("Deku Tree MQ Basement Water Room Front", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DEKU_TREE_MQ_BEFORE_SPINNING_LOG_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK, {[]{return /*LogicDekuMQLog || */ (IsChild && (DekuShield || HylianShield)) || + (IsAdult && (CanUse(LONGSHOT) || (CanUse(HOOKSHOT) && CanUse(IRON_BOOTS))));}}), + Entrance(DEKU_TREE_MQ_LOBBY, {[]{return true;}}), + }); + + areaTable[DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK] = Area("Deku Tree MQ Basement Water Room Front", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DEKU_TREE_MQ_AFTER_SPINNING_LOG_CHEST, {[]{return CanPlay(SongOfTime);}}), + }, { + //Exits + Entrance(DEKU_TREE_MQ_BASEMENT_BACK_ROOM, {[]{return Here(DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK, []{return (IsChild && CanUse(STICKS)) || CanUse(DINS_FIRE) || + Here(DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT, []{return IsAdult && CanUse(FIRE_ARROWS);});}) && + Here(DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK, []{return IsAdult || KokiriSword || CanUseProjectile || (Nuts && Sticks);});}}), + Entrance(DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT, {[]{return true;}}), + }); + + areaTable[DEKU_TREE_MQ_BASEMENT_BACK_ROOM] = Area("Deku Tree MQ Basement Back Room", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DEKU_TREE_MQ_GS_BASEMENT_GRAVES_ROOM, {[]{return (IsAdult && CanUse(LONGSHOT)) || (CanPlay(SongOfTime) && HookshotOrBoomerang);}}), + LocationAccess(DEKU_TREE_MQ_GS_BASEMENT_BACK_ROOM, {[]{return HasFireSourceWithTorch && HookshotOrBoomerang;}}), + }, { + //Exits + Entrance(DEKU_TREE_MQ_BASEMENT_LEDGE, {[]{return IsChild;}}), + Entrance(DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK, {[]{return (IsChild && CanUse(KOKIRI_SWORD)) || CanUseProjectile || (Nuts && (IsChild && CanUse(STICKS)));}}), + }); + + areaTable[DEKU_TREE_MQ_BASEMENT_LEDGE] = Area("Deku Tree MQ Basement Ledge", "Deku Tree", DEKU_TREE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DekuTreeClear, {[]{return DekuTreeClear || (Here(DEKU_TREE_MQ_BASEMENT_LEDGE, []{return HasFireSourceWithTorch;}) && + Here(DEKU_TREE_MQ_BASEMENT_LEDGE, []{return HasShield;}) && + (IsAdult || KokiriSword || Sticks) && (Nuts || CanUse(SLINGSHOT) || CanUse(BOW) || HookshotOrBoomerang));}}), + }, { + //Locations + LocationAccess(DEKU_TREE_MQ_DEKU_SCRUB, {[]{return CanStunDeku;}}), + LocationAccess(DEKU_TREE_QUEEN_GOHMA_HEART, {[]{return HasFireSourceWithTorch && HasShield && (IsAdult || KokiriSword || Sticks) && (Nuts || CanUse(SLINGSHOT) || CanUse(BOW) || HookshotOrBoomerang);}}), + LocationAccess(QUEEN_GOHMA, {[]{return HasFireSourceWithTorch && HasShield && (IsAdult || KokiriSword || Sticks) && (Nuts || CanUse(SLINGSHOT) || CanUse(BOW) || HookshotOrBoomerang);}}), + }, { + //Exits + Entrance(DEKU_TREE_MQ_BASEMENT_BACK_ROOM, {[]{return IsChild;}}), + Entrance(DEKU_TREE_MQ_LOBBY, {[]{return true;}}), + }); + } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_dodongos_cavern.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_dodongos_cavern.cpp new file mode 100644 index 000000000..e46bfff0a --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_dodongos_cavern.cpp @@ -0,0 +1,319 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" +#include "../dungeon.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_DodongosCavern() { + /*-------------------------- + | VANILLA/MQ DECIDER | + ---------------------------*/ + areaTable[DODONGOS_CAVERN_ENTRYWAY] = Area("Dodongos Cavern Entryway", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DODONGOS_CAVERN_BEGINNING, {[]{return Dungeon::DodongosCavern.IsVanilla();}}), + Entrance(DODONGOS_CAVERN_MQ_BEGINNING, {[]{return Dungeon::DodongosCavern.IsMQ();}}), + Entrance(DEATH_MOUNTAIN_TRAIL, {[]{return true;}}), + }); + + /*-------------------------- + | VANILLA DUNGEON | + ---------------------------*/ + if (Dungeon::DodongosCavern.IsVanilla()) { + areaTable[DODONGOS_CAVERN_BEGINNING] = Area("Dodongos Cavern Beginning", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DODONGOS_CAVERN_ENTRYWAY, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_LOBBY, {[]{return Here(DODONGOS_CAVERN_BEGINNING, []{return CanBlastOrSmash || GoronBracelet;});}, + /*Glitched*/[]{return Here(DODONGOS_CAVERN_BEGINNING, []{return GlitchBlueFireWall && BlueFire;});}}), + }); + + areaTable[DODONGOS_CAVERN_LOBBY] = Area("Dodongos Cavern Lobby", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || (CanSummonGossipFairy && Here(DODONGOS_CAVERN_LOBBY, []{return CanBlastOrSmash || GoronBracelet;}));}, + /*Glitched*/[]{return CanSummonGossipFairy && Here(DODONGOS_CAVERN_LOBBY, []{return GlitchBlueFireWall && BlueFire;});}}), + }, { + //Locations + LocationAccess(DODONGOS_CAVERN_MAP_CHEST, {[]{return Here(DODONGOS_CAVERN_LOBBY, []{return CanBlastOrSmash || GoronBracelet;});}, + /*Glitched*/[]{return Here(DODONGOS_CAVERN_LOBBY, []{return (GlitchBlueFireWall && BlueFire) || (CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED));}) || CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE);}}), + LocationAccess(DODONGOS_CAVERN_DEKU_SCRUB_LOBBY, {[]{return CanStunDeku || GoronBracelet;}}), + LocationAccess(DODONGOS_CAVERN_GOSSIP_STONE, {[]{return Here(DODONGOS_CAVERN_LOBBY, []{return CanBlastOrSmash || GoronBracelet;});}, + /*Glitched*/[]{return Here(DODONGOS_CAVERN_LOBBY, []{return (GlitchBlueFireWall && BlueFire) || (CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED));});}}), + }, { + //Exits + Entrance(DODONGOS_CAVERN_BEGINNING, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_LOBBY_SWITCH, {[]{return IsAdult;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE) || (HasExplosives && (CanUse(SLINGSHOT) || CanUse(HOOKSHOT) || CanUse(BOW)) && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED)) || (CanShield && GoronBracelet && GlitchModernHalfie) || ((KokiriSword || Sticks || CanUse(MEGATON_HAMMER)) && (Bombs || GoronBracelet) && Fairy && GlitchClassicHalfie);}}), + Entrance(DODONGOS_CAVERN_SE_CORRIDOR, {[]{return Here(DODONGOS_CAVERN_LOBBY, []{return CanBlastOrSmash || GoronBracelet;});}, + /*Glitched*/[]{return Here(DODONGOS_CAVERN_LOBBY, []{return (GlitchBlueFireWall && BlueFire) || (CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED));});}}), + Entrance(DODONGOS_CAVERN_STAIRS_LOWER, {[]{return HasAccessTo(DODONGOS_CAVERN_LOBBY_SWITCH);}}), + Entrance(DODONGOS_CAVERN_FAR_BRIDGE, {[]{return HasAccessTo(DODONGOS_CAVERN_FAR_BRIDGE);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::INTERMEDIATE);}}), + Entrance(DODONGOS_CAVERN_BOSS_AREA, {[]{return Here(DODONGOS_CAVERN_FAR_BRIDGE, []{return HasExplosives;});}}), + Entrance(DODONGOS_CAVERN_BOSS_ROOM, {[]{return false;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::ADVANCED);}}), + }); + + areaTable[DODONGOS_CAVERN_LOBBY_SWITCH] = Area("Dodongos Cavern Lobby Switch", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DODONGOS_CAVERN_LOBBY, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_DODONGO_ROOM, {[]{return true;}}), + }); + + areaTable[DODONGOS_CAVERN_SE_CORRIDOR] = Area("Dodongos Cavern SE Corridor", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DODONGOS_CAVERN_GS_SCARECROW, {[]{return CanUse(SCARECROW) || (IsAdult && CanUse(LONGSHOT)) || (LogicDCScarecrowGS && (IsAdult || CanChildAttack));}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) || (CanUse(LONGSHOT) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE));}}), + }, { + //Exits + Entrance(DODONGOS_CAVERN_LOBBY, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_SE_ROOM, {[]{return Here(DODONGOS_CAVERN_SE_CORRIDOR, []{return CanBlastOrSmash || IsAdult || CanChildAttack || (CanTakeDamage && CanShield);});}, + /*Glitched*/[]{return Here(DODONGOS_CAVERN_SE_CORRIDOR, []{return (GlitchBlueFireWall && BlueFire);});}}), + Entrance(DODONGOS_CAVERN_NEAR_LOWER_LIZALFOS, {[]{return true;}}), + }); + + areaTable[DODONGOS_CAVERN_SE_ROOM] = Area("Dodongos Cavern SE Room", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DODONGOS_CAVERN_GS_SIDE_ROOM_NEAR_LOWER_LIZALFOS, {[]{return IsAdult || CanChildAttack;}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }, { + //Exits + Entrance(DODONGOS_CAVERN_SE_CORRIDOR, {[]{return true;}}), + }); + + areaTable[DODONGOS_CAVERN_NEAR_LOWER_LIZALFOS] = Area("Dodongos Cavern Near Lower Lizalfos", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DODONGOS_CAVERN_SE_CORRIDOR, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_LOWER_LIZALFOS, {[]{return true;}}), + }); + + areaTable[DODONGOS_CAVERN_LOWER_LIZALFOS] = Area("Dodongos Cavern Lower Lizalfos", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DODONGOS_CAVERN_NEAR_LOWER_LIZALFOS, {[]{return Here(DODONGOS_CAVERN_LOWER_LIZALFOS, []{return IsAdult || Slingshot || Sticks || KokiriSword || HasExplosives;});}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + Entrance(DODONGOS_CAVERN_DODONGO_ROOM, {[]{return Here(DODONGOS_CAVERN_LOWER_LIZALFOS, []{return IsAdult || Slingshot || Sticks || KokiriSword || HasExplosives;});}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }); + + areaTable[DODONGOS_CAVERN_DODONGO_ROOM] = Area("Dodongos Cavern Dodongo Room", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DODONGOS_CAVERN_LOBBY_SWITCH, {[]{return HasFireSourceWithTorch;}}), + Entrance(DODONGOS_CAVERN_LOWER_LIZALFOS, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_NEAR_DODONGO_ROOM, {[]{return Here(DODONGOS_CAVERN_DODONGO_ROOM, []{return CanBlastOrSmash || GoronBracelet;});}, + /*Glitched*/[]{return Here(DODONGOS_CAVERN_DODONGO_ROOM, []{return GlitchBlueFireWall && BlueFire;});}}), + }); + + areaTable[DODONGOS_CAVERN_NEAR_DODONGO_ROOM] = Area("Dodongos Cavern Near Dodongo Room", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS, {[]{return CanStunDeku;}}), + }, { + //Exits + Entrance(DODONGOS_CAVERN_DODONGO_ROOM, {[]{return true;}}), + }); + + areaTable[DODONGOS_CAVERN_STAIRS_LOWER] = Area("Dodongos Cavern Stairs Lower", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DODONGOS_CAVERN_LOBBY, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_STAIRS_UPPER, {[]{return HasExplosives || GoronBracelet || CanUse(DINS_FIRE) || (LogicDCStaircase && CanUse(BOW));}}), + Entrance(DODONGOS_CAVERN_COMPASS_ROOM, {[]{return Here(DODONGOS_CAVERN_STAIRS_LOWER, []{return CanBlastOrSmash || GoronBracelet;});}, + /*Glitched*/[]{return Here(DODONGOS_CAVERN_STAIRS_LOWER, []{return GlitchBlueFireWall && BlueFire;});}}), + }); + + areaTable[DODONGOS_CAVERN_STAIRS_UPPER] = Area("Dodongos Cavern Stairs Upper", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DODONGOS_CAVERN_GS_ALCOVE_ABOVE_STAIRS, {[]{return Here(DODONGOS_CAVERN_FAR_BRIDGE, []{return HookshotOrBoomerang;}) || CanUse(LONGSHOT);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) || (CanDoGlitch(GlitchType::HammerSlide, GlitchDifficulty::NOVICE) && HookshotOrBoomerang);}}), + LocationAccess(DODONGOS_CAVERN_GS_VINES_ABOVE_STAIRS, {[]{return IsAdult || CanChildAttack;}}), + }, { + //Exits + Entrance(DODONGOS_CAVERN_STAIRS_LOWER, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_ARMOS_ROOM, {[]{return true;}}), + }); + + areaTable[DODONGOS_CAVERN_COMPASS_ROOM] = Area("Dodongos Cavern Compass Room", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DODONGOS_CAVERN_COMPASS_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(DODONGOS_CAVERN_STAIRS_LOWER, {[]{return IsAdult || HasExplosives || GoronBracelet;}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }); + + areaTable[DODONGOS_CAVERN_ARMOS_ROOM] = Area("Dodongos Cavern Armos Room", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DODONGOS_CAVERN_STAIRS_UPPER, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_BOMB_ROOM_LOWER, {[]{return true;}}), + }); + + areaTable[DODONGOS_CAVERN_BOMB_ROOM_LOWER] = Area("Dodongos Cavern Bomb Room Lower", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DODONGOS_CAVERN_BOMB_FLOWER_PLATFORM_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(DODONGOS_CAVERN_2F_SIDE_ROOM, {[]{return Here(DODONGOS_CAVERN_BOMB_ROOM_LOWER, []{return CanBlastOrSmash;});}, + /*Glitched*/[]{return Here(DODONGOS_CAVERN_BOMB_ROOM_LOWER, []{return (GlitchBlueFireWall && BlueFire) || (CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED));});}}), + Entrance(DODONGOS_CAVERN_FIRST_SLINGSHOT_ROOM, {[]{return Here(DODONGOS_CAVERN_BOMB_ROOM_LOWER, []{return CanBlastOrSmash || GoronBracelet;});}, + /*Glitched*/[]{return Here(DODONGOS_CAVERN_BOMB_ROOM_LOWER, []{return (GlitchBlueFireWall && BlueFire) || (CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED));});}}), + Entrance(DODONGOS_CAVERN_BOMB_ROOM_UPPER, {[]{return (IsAdult && LogicDCJump) || CanUse(HOVER_BOOTS) || (IsAdult && CanUse(LONGSHOT));}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::INTERMEDIATE) || + (IsAdult && (CanUse(BOW) || CanUse(HOOKSHOT) || CanUse(SLINGSHOT)) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED));}}), + }); + + areaTable[DODONGOS_CAVERN_2F_SIDE_ROOM] = Area("Dodongos Cavern 2F Side Room", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT, {[]{return CanStunDeku;}}), + LocationAccess(DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT, {[]{return CanStunDeku;}}), + }, { + //Exits + Entrance(DODONGOS_CAVERN_BOMB_ROOM_LOWER, {[]{return true;}}), + }); + + areaTable[DODONGOS_CAVERN_FIRST_SLINGSHOT_ROOM] = Area("Dodongos Cavern First Slingshot Room", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DODONGOS_CAVERN_BOMB_ROOM_LOWER, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_UPPER_LIZALFOS, {[]{return CanUse(SLINGSHOT) || CanUse(BOW) || LogicDCSlingshotSkip;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) || (IsAdult && CanUse(HOOKSHOT) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED));}}), + }); + + areaTable[DODONGOS_CAVERN_UPPER_LIZALFOS] = Area("Dodongos Cavern Upper Lizalfos", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DODONGOS_CAVERN_LOWER_LIZALFOS, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_FIRST_SLINGSHOT_ROOM, {[]{return Here(DODONGOS_CAVERN_LOWER_LIZALFOS, []{return IsAdult || Slingshot || Sticks || KokiriSword || HasExplosives;});}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + Entrance(DODONGOS_CAVERN_SECOND_SLINGSHOT_ROOM, {[]{return Here(DODONGOS_CAVERN_LOWER_LIZALFOS, []{return IsAdult || Slingshot || Sticks || KokiriSword || HasExplosives;});}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }); + + areaTable[DODONGOS_CAVERN_SECOND_SLINGSHOT_ROOM] = Area("Dodongos Cavern Second Slingshot Room", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DODONGOS_CAVERN_UPPER_LIZALFOS, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_BOMB_ROOM_UPPER, {[]{return CanUse(SLINGSHOT) || CanUse(BOW) || LogicDCSlingshotSkip;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) || (IsAdult && CanUse(HOOKSHOT) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED));}}), + }); + + areaTable[DODONGOS_CAVERN_BOMB_ROOM_UPPER] = Area("Dodongos Cavern Bomb Room Upper", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DODONGOS_CAVERN_BOMB_BAG_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(DODONGOS_CAVERN_BOMB_ROOM_LOWER, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_SECOND_SLINGSHOT_ROOM, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_FAR_BRIDGE, {[]{return true;}}), + }); + + areaTable[DODONGOS_CAVERN_FAR_BRIDGE] = Area("Dodongos Cavern Far Bridge", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DODONGOS_CAVERN_END_OF_BRIDGE_CHEST, {[]{return Here(DODONGOS_CAVERN_FAR_BRIDGE, []{return CanBlastOrSmash;});}, + /*Glitched*/[]{return Here(DODONGOS_CAVERN_FAR_BRIDGE, []{return (CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED));}) || + CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE);}}), + }, { + //Exits + Entrance(DODONGOS_CAVERN_LOBBY, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_BOMB_ROOM_UPPER, {[]{return true;}}), + }); + + areaTable[DODONGOS_CAVERN_BOSS_AREA] = Area("Dodongos Cavern Boss Area", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return true;}}), + }, {}, { + //Exits + Entrance(DODONGOS_CAVERN_LOBBY, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_BACK_ROOM, {[]{return Here(DODONGOS_CAVERN_BOSS_AREA, []{return CanBlastOrSmash;});}, + /*Glitched*/[]{return Here(DODONGOS_CAVERN_BOSS_AREA, []{return (GlitchBlueFireWall && BlueFire) || (CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED));});}}), + Entrance(DODONGOS_CAVERN_BOSS_ROOM, {[]{return true;}}), + }); + + areaTable[DODONGOS_CAVERN_BACK_ROOM] = Area("Dodongos Cavern Back Room", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DODONGOS_CAVERN_GS_BACK_ROOM, {[]{return IsAdult || CanChildAttack;}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }, { + //Exits + Entrance(DODONGOS_CAVERN_BOSS_AREA, {[]{return true;}}), + }); + + areaTable[DODONGOS_CAVERN_BOSS_ROOM] = Area("Dodongos Cavern Boss Room", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DodongosCavernClear, {[]{return DodongosCavernClear || (Here(DODONGOS_CAVERN_BOSS_ROOM, []{return HasExplosives || (CanUse(MEGATON_HAMMER) && CanShield);}) && (Bombs || GoronBracelet) && (IsAdult || Sticks || KokiriSword));}, + /*Glitched*/[]{return Here(DODONGOS_CAVERN_BOSS_ROOM, []{return HasExplosives || (CanUse(MEGATON_HAMMER) && CanShield) || (GlitchBlueFireWall && BlueFire);}) && (HasExplosives || GoronBracelet) && (IsAdult || Sticks || KokiriSword || CanUse(MEGATON_HAMMER));}}), + }, { + //Locations + LocationAccess(DODONGOS_CAVERN_BOSS_ROOM_CHEST, {[]{return true;}}), + LocationAccess(DODONGOS_CAVERN_KING_DODONGO_HEART, {[]{return DodongosCavernClear;}}), + LocationAccess(KING_DODONGO, {[]{return DodongosCavernClear;}}), + }, { + //Exits + Entrance(DODONGOS_CAVERN_BOSS_AREA, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_ENTRYWAY, {[]{return DodongosCavernClear;}}), + }); + } + + /*--------------------------- + | MASTER QUEST DUNGEON | + ---------------------------*/ + if (Dungeon::DodongosCavern.IsMQ()) { + areaTable[DODONGOS_CAVERN_MQ_BEGINNING] = Area("Dodongos Cavern MQ Beginning", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DODONGOS_CAVERN_ENTRYWAY, {[]{return true;}}), + Entrance(DODONGOS_CAVERN_MQ_LOBBY, {[]{return Here(DODONGOS_CAVERN_MQ_BEGINNING, []{return CanBlastOrSmash || GoronBracelet;});}}), + }); + + areaTable[DODONGOS_CAVERN_MQ_LOBBY] = Area("Dodongos Cavern MQ Lobby", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DekuBabaSticks, {[]{return DekuBabaSticks || (IsAdult || KokiriSword || Boomerang);}}), + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || CanSummonGossipFairy;}}), + }, { + //Locations + LocationAccess(DODONGOS_CAVERN_MQ_MAP_CHEST, {[]{return true;}}), + LocationAccess(DODONGOS_CAVERN_MQ_COMPASS_CHEST, {[]{return IsAdult || CanChildAttack || Nuts;}}), + LocationAccess(DODONGOS_CAVERN_MQ_LARVAE_ROOM_CHEST, {[]{return (IsChild && CanUse(STICKS)) || HasFireSource;}}), + LocationAccess(DODONGOS_CAVERN_MQ_TORCH_PUZZLE_ROOM_CHEST, {[]{return CanBlastOrSmash || (IsChild && CanUse(STICKS)) || CanUse(DINS_FIRE) || (IsAdult && (LogicDCJump || HoverBoots || Hookshot));}}), + LocationAccess(DODONGOS_CAVERN_MQ_GS_SONG_OF_TIME_BLOCK_ROOM, {[]{return CanPlay(SongOfTime) && (CanChildAttack || IsAdult);}}), + LocationAccess(DODONGOS_CAVERN_MQ_GS_LARVAE_ROOM, {[]{return (IsChild && CanUse(STICKS)) || HasFireSource;}}), + LocationAccess(DODONGOS_CAVERN_MQ_GS_LIZALFOS_ROOM, {[]{return CanBlastOrSmash;}}), + LocationAccess(DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR, {[]{return CanStunDeku;}}), + LocationAccess(DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT, {[]{return CanStunDeku;}}), + LocationAccess(DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE, {[]{return CanStunDeku;}}), + LocationAccess(DODONGOS_CAVERN_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(DODONGOS_CAVERN_MQ_LOWER_RIGHT_SIDE, {[]{return Here(DODONGOS_CAVERN_MQ_LOBBY, []{return CanBlastOrSmash || (((IsChild && CanUse(STICKS)) || CanUse(DINS_FIRE)) && CanTakeDamage);});}}), + Entrance(DODONGOS_CAVERN_MQ_BOMB_BAG_AREA, {[]{return IsAdult || (Here(DODONGOS_CAVERN_MQ_LOBBY, []{return IsAdult;}) && HasExplosives);}}), + //Trick: IsAdult || HasExplosives || (LogicDCMQChildBombs && (KokiriSword || Sticks) && DamageMultiplier.IsNot(DAMAGEMULTIPLIER_OHKO)) + Entrance(DODONGOS_CAVERN_MQ_BOSS_AREA, {[]{return HasExplosives;}}), + //Trick: HasExplosives || (LogicDCMQEyes && GoronBracelet && (IsAdult || LogicDCMQChildBack) && ((IsChild && CanUse(STICKS)) || CanUse(DINS_FIRE) || (IsAdult && (LogicDCJump || Hammer || HoverBoots || Hookshot)))) + }); + + areaTable[DODONGOS_CAVERN_MQ_LOWER_RIGHT_SIDE] = Area("Dodongos Cavern MQ Lower Right Side", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS, {[]{return CanStunDeku;}}), + }, { + //Exits + Entrance(DODONGOS_CAVERN_MQ_BOMB_BAG_AREA, {[]{return (Here(DODONGOS_CAVERN_MQ_LOWER_RIGHT_SIDE, []{return IsAdult && CanUse(BOW);}) || GoronBracelet || + CanUse(DINS_FIRE) || HasExplosives) && + IsChild && CanUse(SLINGSHOT);}}), + }); + + areaTable[DODONGOS_CAVERN_MQ_BOMB_BAG_AREA] = Area("Dodongos Cavern MQ Bomb Bag Area", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DODONGOS_CAVERN_MQ_BOMB_BAG_CHEST, {[]{return true;}}), + LocationAccess(DODONGOS_CAVERN_MQ_GS_SCRUB_ROOM, {[]{return (Here(DODONGOS_CAVERN_MQ_BOMB_BAG_AREA, []{return IsAdult && CanUse(BOW);}) || GoronBracelet || CanUse(DINS_FIRE) || HasExplosives) && HookshotOrBoomerang;}}), + }, { + //Exits + Entrance(DODONGOS_CAVERN_MQ_LOWER_RIGHT_SIDE, {[]{return true;}}), + }); + + areaTable[DODONGOS_CAVERN_MQ_BOSS_AREA] = Area("Dodongos Cavern MQ BossArea", "Dodongos Cavern", DODONGOS_CAVERN, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return true;}}), + EventAccess(&DodongosCavernClear, {[]{return DodongosCavernClear || (CanBlastOrSmash && (Bombs || GoronBracelet) && (IsAdult || Sticks || KokiriSword));}}), + }, { + //Locations + LocationAccess(DODONGOS_CAVERN_MQ_UNDER_GRAVE_CHEST, {[]{return true;}}), + LocationAccess(DODONGOS_CAVERN_BOSS_ROOM_CHEST, {[]{return true;}}), + LocationAccess(DODONGOS_CAVERN_KING_DODONGO_HEART, {[]{return CanBlastOrSmash && (Bombs || GoronBracelet) && (IsAdult || Sticks || KokiriSword);}}), + LocationAccess(KING_DODONGO, {[]{return CanBlastOrSmash && (Bombs || GoronBracelet) && (IsAdult || Sticks || KokiriSword);}}), + LocationAccess(DODONGOS_CAVERN_MQ_GS_BACK_AREA, {[]{return true;}}), + }, {}); + } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_fire_temple.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_fire_temple.cpp new file mode 100644 index 000000000..ae3c08374 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_fire_temple.cpp @@ -0,0 +1,456 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" +#include "../dungeon.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_FireTemple() { + /*-------------------------- + | VANILLA/MQ DECIDER | + ---------------------------*/ + areaTable[FIRE_TEMPLE_ENTRYWAY] = Area("Fire Temple Entryway", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_FIRST_ROOM, {[]{return Dungeon::FireTemple.IsVanilla();}}), + Entrance(FIRE_TEMPLE_MQ_LOWER, {[]{return Dungeon::FireTemple.IsMQ();}}), + Entrance(DMC_CENTRAL_LOCAL, {[]{return true;}}), + }); + + /*-------------------------- + | VANILLA DUNGEON | + ---------------------------*/ + if (Dungeon::FireTemple.IsVanilla()) { + areaTable[FIRE_TEMPLE_FIRST_ROOM] = Area("Fire Temple First Room", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + }, { + //Exits + Entrance(FIRE_TEMPLE_ENTRYWAY, {[]{return true;}}), + Entrance(FIRE_TEMPLE_NEAR_BOSS_ROOM, {[]{return FireTimer >= 24;}}), + Entrance(FIRE_TEMPLE_LOOP_ENEMIES, {[]{return Here(FIRE_TEMPLE_FIRST_ROOM, []{return CanUse(MEGATON_HAMMER);}) && (SmallKeys(FIRE_TEMPLE, 8) || !IsKeysanity);}, + /*Glitched*/[]{return ((IsAdult && CanDoGlitch(GlitchType::TripleSlashClip, GlitchDifficulty::EXPERT)) || + (GlitchFireGrunzClip && Bombs && IsAdult && CanUse(HOVER_BOOTS) && CanSurviveDamage)) && (SmallKeys(FIRE_TEMPLE, 8) || !IsKeysanity);}}), + Entrance(FIRE_TEMPLE_LOOP_EXIT, {[]{return true;}}), + Entrance(FIRE_TEMPLE_BIG_LAVA_ROOM, {[]{return SmallKeys(FIRE_TEMPLE, 2) && FireTimer >= 24;}}), + }); + + areaTable[FIRE_TEMPLE_NEAR_BOSS_ROOM] = Area("Fire Temple Near Boss Room", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return FairyPot || (CanUse(HOVER_BOOTS) || CanUse(HOOKSHOT));}}), + }, { + //Locations + LocationAccess(FIRE_TEMPLE_NEAR_BOSS_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_FIRST_ROOM, {[]{return true;}}), + Entrance(FIRE_TEMPLE_BOSS_ROOM, {[]{return BossKeyFireTemple && ((IsAdult && LogicFireBossDoorJump) || CanUse(HOVER_BOOTS) || Here(FIRE_TEMPLE_FIRE_MAZE_UPPER, []{return CanUse(MEGATON_HAMMER);}));}, + /*Glitched*/[]{return BossKeyFireTemple && (CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE) || + (Bombs && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE)));}}), + }); + + areaTable[FIRE_TEMPLE_BOSS_ROOM] = Area("Fire Temple Boss Room", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FireTempleClear, {[]{return FireTempleClear || (FireTimer >= 64 && CanUse(MEGATON_HAMMER));}, + /*Glitched*/[]{return FireTimer >= 48 && ((CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::NOVICE)) || + CanUse(MEGATON_HAMMER)) && Bombs && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE);}}), + }, { + //Locations + LocationAccess(FIRE_TEMPLE_VOLVAGIA_HEART, {[]{return FireTempleClear;}}), + LocationAccess(VOLVAGIA, {[]{return FireTempleClear;}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_ENTRYWAY, {[]{return FireTempleClear;}}), + }); + + areaTable[FIRE_TEMPLE_LOOP_ENEMIES] = Area("Fire Temple Loop Enemies", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_FIRST_ROOM, {[]{return SmallKeys(FIRE_TEMPLE, 8) || !IsKeysanity;}}), + Entrance(FIRE_TEMPLE_LOOP_TILES, {[]{return Here(FIRE_TEMPLE_LOOP_ENEMIES, []{return IsAdult || KokiriSword;});}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }); + + areaTable[FIRE_TEMPLE_LOOP_TILES] = Area("Fire Temple Loop Tiles", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_GS_BOSS_KEY_LOOP, {[]{return IsAdult || CanChildAttack;}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_LOOP_ENEMIES, {[]{return true;}}), + Entrance(FIRE_TEMPLE_LOOP_FLARE_DANCER, {[]{return true;}}), + }); + + areaTable[FIRE_TEMPLE_LOOP_FLARE_DANCER] = Area("Fire Temple Loop Flare Dancer", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_FLARE_DANCER_CHEST, {[]{return (HasExplosives || CanUse(MEGATON_HAMMER)) && IsAdult;}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE)) || + (CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED) && HasBombchus && CanShield && (Slingshot || CanUse(BOW) || CanUse(HOOKSHOT)));}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_LOOP_TILES, {[]{return true;}}), + Entrance(FIRE_TEMPLE_LOOP_HAMMER_SWITCH, {[]{return Here(FIRE_TEMPLE_LOOP_FLARE_DANCER, []{return (HasExplosives || CanUse(MEGATON_HAMMER) || CanUse(HOOKSHOT)) && (IsAdult || KokiriSword || Slingshot || Boomerang);});}}), + }); + + areaTable[FIRE_TEMPLE_LOOP_HAMMER_SWITCH] = Area("Fire Temple Loop Hammer Switch", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FireLoopSwitch, {[]{return FireLoopSwitch || CanUse(MEGATON_HAMMER);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::QPA, GlitchDifficulty::NOVICE) && Bombs && CanTakeDamage && CanUse(STICKS);}}), + }, {}, { + //Exits + Entrance(FIRE_TEMPLE_LOOP_FLARE_DANCER, {[]{return true;}}), + Entrance(FIRE_TEMPLE_LOOP_GORON_ROOM, {[]{return FireLoopSwitch;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::INTERMEDIATE);}}), + }); + + areaTable[FIRE_TEMPLE_LOOP_GORON_ROOM] = Area("Fire Temple Loop Goron Room", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_BOSS_KEY_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_LOOP_HAMMER_SWITCH, {[]{return FireLoopSwitch;}}), + Entrance(FIRE_TEMPLE_LOOP_EXIT, {[]{return FireLoopSwitch;}}), + }); + + areaTable[FIRE_TEMPLE_LOOP_EXIT] = Area("Fire Temple Loop Exit", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_FIRST_ROOM, {[]{return true;}}), + Entrance(FIRE_TEMPLE_LOOP_GORON_ROOM, {[]{return FireLoopSwitch;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::INTERMEDIATE);}}), + }); + + areaTable[FIRE_TEMPLE_BIG_LAVA_ROOM] = Area("Fire Temple Big Lava Room", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_FIRST_ROOM, {[]{return SmallKeys(FIRE_TEMPLE, 2);}}), + Entrance(FIRE_TEMPLE_BIG_LAVA_ROOM_NORTH_GORON, {[]{return true;}}), + Entrance(FIRE_TEMPLE_BIG_LAVA_ROOM_NORTH_TILES, {[]{return IsAdult && (CanPlay(SongOfTime) || LogicFireSongOfTime);}, + /*Glitched*/[]{return FireTimer >= 48 && ((CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE)) || + (IsAdult && (SongOfTime && (CanDoGlitch(GlitchType::DungeonBombOI, GlitchDifficulty::INTERMEDIATE) || (CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED) && (Bugs || Fish) && CanShield)))));}}), + Entrance(FIRE_TEMPLE_BIG_LAVA_ROOM_SOUTH_GORON, {[]{return IsAdult && HasExplosives;}, + /*Glitched*/[]{return FireTimer >= 48 && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE);}}), + Entrance(FIRE_TEMPLE_FIRE_PILLAR_ROOM, {[]{return SmallKeys(FIRE_TEMPLE, 3);}}), + }); + + areaTable[FIRE_TEMPLE_BIG_LAVA_ROOM_NORTH_GORON] = Area("Fire Temple Big Lava Room North Goron", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_BIG_LAVA_ROOM_LOWER_OPEN_DOOR_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_BIG_LAVA_ROOM, {[]{return true;}}), + }); + + areaTable[FIRE_TEMPLE_BIG_LAVA_ROOM_NORTH_TILES] = Area("Fire Temple Big Lava Room North Tiles", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_GS_SONG_OF_TIME_ROOM, {[]{return IsAdult;}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_BIG_LAVA_ROOM, {[]{return true;}}), + }); + + areaTable[FIRE_TEMPLE_BIG_LAVA_ROOM_SOUTH_GORON] = Area("Fire Temple Big Lava Room South Goron", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_BIG_LAVA_ROOM, {[]{return true;}}), + }); + + areaTable[FIRE_TEMPLE_FIRE_PILLAR_ROOM] = Area("Fire Temple Fire Pillar Room", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_BIG_LAVA_ROOM, {[]{return SmallKeys(FIRE_TEMPLE, 3);}}), + Entrance(FIRE_TEMPLE_SHORTCUT_ROOM, {[]{return FireTimer >= 56 && SmallKeys(FIRE_TEMPLE, 4);}}), + }); + + areaTable[FIRE_TEMPLE_SHORTCUT_ROOM] = Area("Fire Temple Shortcut Room", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_BOULDER_MAZE_SHORTCUT_CHEST, {[]{return Here(FIRE_TEMPLE_SHORTCUT_CLIMB, []{return true;});}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::INTERMEDIATE);}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_FIRE_PILLAR_ROOM, {[]{return SmallKeys(FIRE_TEMPLE, 4);}}), + Entrance(FIRE_TEMPLE_SHORTCUT_CLIMB, {[]{return Here(FIRE_TEMPLE_SHORTCUT_CLIMB, []{return true;});}, + /*Glitched*/[]{return (GoronBracelet || LogicFireStrength) && Bombs && CanSurviveDamage && CanDoGlitch(GlitchType::LedgeClip, GlitchDifficulty::INTERMEDIATE);}}), + Entrance(FIRE_TEMPLE_BOULDER_MAZE_LOWER, {[]{return (GoronBracelet || (IsAdult && LogicFireStrength)) && (HasExplosives || (IsAdult && (CanUse(BOW) || CanUse(HOOKSHOT) || CanUse(SLINGSHOT))));}, + /*Glitched*/[]{return (GoronBracelet || (IsAdult && LogicFireStrength)) && (CanDoGlitch(GlitchType::SuperStab, GlitchDifficulty::NOVICE) || + (CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED) && CanUse(STICKS)));}}), + }); + + areaTable[FIRE_TEMPLE_SHORTCUT_CLIMB] = Area("Fire Temple Shortcut Climb", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_SHORTCUT_ROOM, {[]{return true;}}), + Entrance(FIRE_TEMPLE_BOULDER_MAZE_UPPER, {[]{return true;}}), + }); + + areaTable[FIRE_TEMPLE_BOULDER_MAZE_LOWER] = Area("Fire Temple Boulder Maze Lower", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_BOULDER_MAZE_LOWER_CHEST, {[]{return true;}}), + LocationAccess(FIRE_TEMPLE_GS_BOULDER_MAZE, {[]{return HasExplosives && (IsAdult || Boomerang || CanUse(HOOKSHOT));}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE) && Bombs) || + Here(FIRE_TEMPLE_BOULDER_MAZE_UPPER, []{return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE);});}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_SHORTCUT_ROOM, {[]{return true;}}), + Entrance(FIRE_TEMPLE_BOULDER_MAZE_LOWER_SIDE_ROOM, {[]{return true;}}), + Entrance(FIRE_TEMPLE_EAST_CENTRAL_ROOM, {[]{return SmallKeys(FIRE_TEMPLE, 5, 7);}}), + Entrance(FIRE_TEMPLE_BOULDER_MAZE_UPPER, {[]{return false;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE) && Bombs;}}), + }); + + areaTable[FIRE_TEMPLE_BOULDER_MAZE_LOWER_SIDE_ROOM] = Area("Fire Temple Boulder Maze Lower Side Room", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_BOULDER_MAZE_SIDE_ROOM_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_BOULDER_MAZE_LOWER, {[]{return true;}}), + }); + + areaTable[FIRE_TEMPLE_EAST_CENTRAL_ROOM] = Area("Fire Temple East Central Room", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_BIG_LAVA_ROOM, {[]{return CanTakeDamage;}}), + Entrance(FIRE_TEMPLE_BOULDER_MAZE_LOWER, {[]{return SmallKeys(FIRE_TEMPLE, 5, 8);}}), + Entrance(FIRE_TEMPLE_FIRE_WALL_CHASE, {[]{return SmallKeys(FIRE_TEMPLE, 6, 8);}}), + Entrance(FIRE_TEMPLE_MAP_AREA, {[]{return CanUse(SLINGSHOT) || CanUse(BOW);}}), + }); + + areaTable[FIRE_TEMPLE_FIRE_WALL_CHASE] = Area("Fire Temple Fire Wall Chase", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_EAST_CENTRAL_ROOM, {[]{return FireTimer >= 24 && SmallKeys(FIRE_TEMPLE, 6, 8);}}), + Entrance(FIRE_TEMPLE_MAP_AREA, {[]{return IsAdult;}}), + Entrance(FIRE_TEMPLE_BOULDER_MAZE_UPPER, {[]{return FireTimer >= 24 && IsAdult;}, + /*Glitched*/[]{return FireTimer >= 32 && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE);}}), + Entrance(FIRE_TEMPLE_CORRIDOR, {[]{return FireTimer >= 24 && IsAdult && SmallKeys(FIRE_TEMPLE, 7);}, + /*Glitched*/[]{return FireTimer >= 32 && SmallKeys(FIRE_TEMPLE, 7) && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE) && Bombs && HasBombchus && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE);}}), + }); + + areaTable[FIRE_TEMPLE_MAP_AREA] = Area("Fire Temple Map Area", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_MAP_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_EAST_CENTRAL_ROOM, {[]{return true;}}), + }); + + areaTable[FIRE_TEMPLE_BOULDER_MAZE_UPPER] = Area("Fire Temple Boulder Maze Upper", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_BOULDER_MAZE_UPPER_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_SHORTCUT_CLIMB, {[]{return HasExplosives;}}), + Entrance(FIRE_TEMPLE_BOULDER_MAZE_LOWER, {[]{return true;}}), + Entrance(FIRE_TEMPLE_FIRE_WALL_CHASE, {[]{return true;}}), + Entrance(FIRE_TEMPLE_SCARECROW_ROOM, {[]{return CanUse(SCARECROW) || (LogicFireScarecrow && IsAdult && CanUse(LONGSHOT));}}), + }); + + areaTable[FIRE_TEMPLE_SCARECROW_ROOM] = Area("Fire Temple Scarecrow Room", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_GS_SCARECROW_CLIMB, {[]{return IsAdult || CanChildAttack;}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_BOULDER_MAZE_UPPER, {[]{return true;}}), + Entrance(FIRE_TEMPLE_EAST_PEAK, {[]{return true;}}), + }); + + areaTable[FIRE_TEMPLE_EAST_PEAK] = Area("Fire Temple East Peak", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_SCARECROW_CHEST, {[]{return true;}}), + LocationAccess(FIRE_TEMPLE_GS_SCARECROW_TOP, {[]{return CanUseProjectile;}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_SCARECROW_ROOM, {[]{return true;}}), + Entrance(FIRE_TEMPLE_EAST_CENTRAL_ROOM, {[]{return CanTakeDamage;}}), + }); + + areaTable[FIRE_TEMPLE_CORRIDOR] = Area("Fire Temple Corridor", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_FIRE_WALL_CHASE, {[]{return SmallKeys(FIRE_TEMPLE, 7);}}), + Entrance(FIRE_TEMPLE_FIRE_MAZE_ROOM, {[]{return true;}}), + }); + + areaTable[FIRE_TEMPLE_FIRE_MAZE_ROOM] = Area("Fire Temple Fire Maze Room", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_CORRIDOR, {[]{return true;}}), + Entrance(FIRE_TEMPLE_FIRE_MAZE_UPPER, {[]{return CanUse(HOVER_BOOTS);}, + /*Glitched*/[]{return Bombs && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE);}}), + Entrance(FIRE_TEMPLE_FIRE_MAZE_SIDE_ROOM, {[]{return true;}}), + Entrance(FIRE_TEMPLE_WEST_CENTRAL_LOWER, {[]{return SmallKeys(FIRE_TEMPLE, 8);}}), + Entrance(FIRE_TEMPLE_LATE_FIRE_MAZE, {[]{return LogicFireFlameMaze || false;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::INTERMEDIATE) || (CanDoGlitch(GlitchType::SuperSlide, GlitchDifficulty::ADVANCED) && Bombs && CanShield);}}), + }); + + areaTable[FIRE_TEMPLE_FIRE_MAZE_UPPER] = Area("Fire Temple Fire Maze Upper", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_NEAR_BOSS_ROOM, {[]{return CanUse(MEGATON_HAMMER);}}), + Entrance(FIRE_TEMPLE_FIRE_MAZE_ROOM, {[]{return true;}}), + Entrance(FIRE_TEMPLE_WEST_CENTRAL_UPPER, {[]{return CanUse(MEGATON_HAMMER);}, + /*Glitched*/[]{return CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::NOVICE);}}), + }); + + areaTable[FIRE_TEMPLE_FIRE_MAZE_SIDE_ROOM] = Area("Fire Temple Fire Maze Side Room", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_COMPASS_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_FIRE_MAZE_ROOM, {[]{return true;}}), + }); + + areaTable[FIRE_TEMPLE_WEST_CENTRAL_LOWER] = Area("Fire Temple West Central Lower", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_HIGHEST_GORON_CHEST, {[]{return Here(FIRE_TEMPLE_WEST_CENTRAL_UPPER, []{return CanPlay(SongOfTime) && CanUse(MEGATON_HAMMER);});}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::INTERMEDIATE) || Here(FIRE_TEMPLE_WEST_CENTRAL_UPPER, []{return (IsAdult || CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE) || + (Bombs && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE))) && + (((SongOfTime && (((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || CanDoGlitch(GlitchType::DungeonBombOI, GlitchDifficulty::NOVICE))) || + CanPlay(SongOfTime)) && ((CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::INTERMEDIATE)) || CanUse(MEGATON_HAMMER)));});}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_FIRE_MAZE_ROOM, {[]{return SmallKeys(FIRE_TEMPLE, 8);}}), + Entrance(FIRE_TEMPLE_WEST_CENTRAL_UPPER, {[]{return IsAdult && CanPlay(SongOfTime);}, + /*Glitched*/[]{return (IsAdult && SongOfTime && (((Bugs || Fish) && CanShield && (CanSurviveDamage || (CanTakeDamage && NumBottles >= 2)) && Bombs && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + (CanDoGlitch(GlitchType::DungeonBombOI, GlitchDifficulty::NOVICE)))) || (Bombs && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE));}}), + Entrance(FIRE_TEMPLE_LATE_FIRE_MAZE, {[]{return true;}}), + }); + + areaTable[FIRE_TEMPLE_WEST_CENTRAL_UPPER] = Area("Fire Temple West Central Upper", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_BOSS_ROOM, {[]{return false;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::LedgeClip, GlitchDifficulty::INTERMEDIATE);}}), + Entrance(FIRE_TEMPLE_FIRE_MAZE_UPPER, {[]{return true;}}), + Entrance(FIRE_TEMPLE_WEST_CENTRAL_LOWER, {[]{return true;}}), + }); + + areaTable[FIRE_TEMPLE_LATE_FIRE_MAZE] = Area("Fire Temple Late Fire Maze", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_FIRE_MAZE_ROOM, {[]{return false;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE) || (Bombs && CanShield && CanDoGlitch(GlitchType::SuperSlide, GlitchDifficulty::ADVANCED));}}), + Entrance(FIRE_TEMPLE_WEST_CENTRAL_LOWER, {[]{return true;}}), + Entrance(FIRE_TEMPLE_UPPER_FLARE_DANCER, {[]{return HasExplosives;}}), + }); + + areaTable[FIRE_TEMPLE_UPPER_FLARE_DANCER] = Area("Fire Temple Upper Flare Dancer", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_LATE_FIRE_MAZE, {[]{return Here(FIRE_TEMPLE_UPPER_FLARE_DANCER, []{return (HasExplosives || CanUse(MEGATON_HAMMER) || CanUse(HOOKSHOT)) && (IsAdult || KokiriSword || Slingshot || Boomerang);});}}), + Entrance(FIRE_TEMPLE_WEST_CLIMB, {[]{return Here(FIRE_TEMPLE_UPPER_FLARE_DANCER, []{return (HasExplosives || CanUse(MEGATON_HAMMER) || CanUse(HOOKSHOT)) && (IsAdult || KokiriSword || Slingshot || Boomerang);});}}), + }); + + areaTable[FIRE_TEMPLE_WEST_CLIMB] = Area("Fire Temple West Climb", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_UPPER_FLARE_DANCER, {[]{return true;}}), + Entrance(FIRE_TEMPLE_WEST_PEAK, {[]{return CanUseProjectile;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::SuperStab, GlitchDifficulty::NOVICE);}}), + }); + + areaTable[FIRE_TEMPLE_WEST_PEAK] = Area("Fire Temple West Peak", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_MEGATON_HAMMER_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_WEST_CENTRAL_UPPER, {[]{return CanTakeDamage;}}), + Entrance(FIRE_TEMPLE_WEST_CLIMB, {[]{return true;}}), + Entrance(FIRE_TEMPLE_HAMMER_RETURN_PATH, {[]{return CanUse(MEGATON_HAMMER);}}), + }); + + areaTable[FIRE_TEMPLE_HAMMER_RETURN_PATH] = Area("Fire Temple Hammer Return Path", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_ABOVE_FIRE_MAZE, {[]{return CanUse(MEGATON_HAMMER);}}), + }); + + areaTable[FIRE_TEMPLE_ABOVE_FIRE_MAZE] = Area("Fire Temple Above Fire Maze", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FIRE_TEMPLE_HAMMER_RETURN_PATH, {[]{return true;}}), + Entrance(FIRE_TEMPLE_FIRE_MAZE_UPPER, {[]{return CanUse(MEGATON_HAMMER);}}), + }); + } + + /*--------------------------- + | MASTER QUEST DUNGEON | + ---------------------------*/ + if (Dungeon::FireTemple.IsMQ()) { + areaTable[FIRE_TEMPLE_MQ_LOWER] = Area("Fire Temple MQ Lower", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_MQ_MAP_ROOM_SIDE_CHEST, {[]{return IsAdult || KokiriSword || Sticks || Slingshot || Bombs || CanUse(DINS_FIRE);}}), + LocationAccess(FIRE_TEMPLE_MQ_NEAR_BOSS_CHEST, {[]{return IsAdult && FireTimer >= 24 + && (CanUse(HOVER_BOOTS) || CanUse(HOOKSHOT)) + && (CanUse(FIRE_ARROWS) || (CanUse(DINS_FIRE) && + ((DamageMultiplier.IsNot(DAMAGEMULTIPLIER_OHKO) && DamageMultiplier.IsNot(DAMAGEMULTIPLIER_QUADRUPLE) && DamageMultiplier.IsNot(DAMAGEMULTIPLIER_OCTUPLE) && DamageMultiplier.IsNot(DAMAGEMULTIPLIER_SEXDECUPLE)) + || CanUse(GORON_TUNIC) + || CanUse(BOW) + || CanUse(LONGSHOT))));}}), + //Trick: IsAdult && (LogicFewerTunicRequirements || CanUse(GORON_TUNIC)) && (((CanUse(HOVER_BOOTS) || (LogicFireMQNearBoss && CanUse(BOW))) && HasFireSource) || (CanUse(HOOKSHOT) && CanUse(FIRE_ARROWS) || (CanUse(DINS_FIRE) && ((DamageMultiplier.IsNot(DAMAGEMULTIPLIER_OHKO) && DamageMultiplier.IsNot(DAMAGEMULTIPLIER_QUADRUPLE) && DamageMultiplier.IsNot(DAMAGEMULTIPLIER_OCTUPLE) && DamageMultiplier.IsNot(DAMAGEMULTIPLIER_SEXDECUPLE)) || CanUse(GORON_TUNIC) || CanUse(BOW) || CanUse(LONGSHOT))))) + }, { + //Exits + Entrance(FIRE_TEMPLE_ENTRYWAY, {[]{return true;}}), + Entrance(FIRE_TEMPLE_MQ_BOSS_ROOM, {[]{return IsAdult && CanUse(GORON_TUNIC) && CanUse(MEGATON_HAMMER) && BossKeyFireTemple && ((HasFireSource && (LogicFireBossDoorJump || HoverBoots)) || HasAccessTo(FIRE_TEMPLE_MQ_UPPER));}}), + Entrance(FIRE_TEMPLE_MQ_LOWER_LOCKED_DOOR, {[]{return SmallKeys(FIRE_TEMPLE, 5) && (IsAdult || KokiriSword);}}), + Entrance(FIRE_TEMPLE_MQ_BIG_LAVA_ROOM, {[]{return IsAdult && FireTimer >= 24 && CanUse(MEGATON_HAMMER);}}), + }); + + areaTable[FIRE_TEMPLE_MQ_LOWER_LOCKED_DOOR] = Area("Fire Temple MQ Lower Locked Door", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return true;}}), + }, { + //Locations + LocationAccess(FIRE_TEMPLE_MQ_MEGATON_HAMMER_CHEST, {[]{return IsAdult && (HasExplosives || Hammer || Hookshot);}}), + LocationAccess(FIRE_TEMPLE_MQ_MAP_CHEST, {[]{return IsAdult && CanUse(MEGATON_HAMMER);}}), + }, {}); + + areaTable[FIRE_TEMPLE_MQ_BIG_LAVA_ROOM] = Area("Fire Temple MQ Big Lava Room", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return FairyPot || (HasFireSource && Bow && IsAdult && (CanUse(HOOKSHOT) || LogicFireSongOfTime));}}), + //Trick: HasFireSource && (Bow || LogicFireMQBKChest) && IsAdult && (CanUse(HOOKSHOT) || LogicFireSongOfTime) + }, { + //Locations + LocationAccess(FIRE_TEMPLE_MQ_BOSS_KEY_CHEST, {[]{return HasFireSource && Bow && IsAdult && CanUse(HOOKSHOT);}}), + //Trick: HasFireSource && (Bow || LogicFireMQBKChest) && IsAdult && CanUse(HOOKSHOT) + LocationAccess(FIRE_TEMPLE_MQ_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST, {[]{return HasFireSource && HasExplosives && IsAdult && CanUse(HOOKSHOT);}}), + //Trick: HasFireSource && HasExplosives && IsAdult && (CanUse(HOOKSHOT) || LogicFireMQBlockedChest) + LocationAccess(FIRE_TEMPLE_MQ_GS_BIG_LAVA_ROOM_OPEN_DOOR, {[]{return true;}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_MQ_LOWER_MAZE, {[]{return IsAdult && CanUse(GORON_TUNIC) && SmallKeys(FIRE_TEMPLE, 2) && HasFireSource;}}), + //Trick: IsAdult && CanUse(GORON_TUNIC) && SmallKeys(FIRE_TEMPLE, 2) && (HasFireSource || (LogicFireMQClimb && HoverBoots)) + }); + + areaTable[FIRE_TEMPLE_MQ_LOWER_MAZE] = Area("Fire Temple MQ Lower Maze", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CHEST, {[]{return true;}}), + LocationAccess(FIRE_TEMPLE_MQ_LIZALFOS_MAZE_SIDE_ROOM_CHEST, {[]{return HasExplosives && HasAccessTo(FIRE_TEMPLE_MQ_UPPER_MAZE);}}), + //Trick: HasExplosives && (LogicFireMQMazeSideRoom || FIRE_TEMPLE_MQ_UPPER_MAZE.Adult()) + }, { + //Exits + Entrance(FIRE_TEMPLE_MQ_UPPER_MAZE, {[]{return HasExplosives && IsAdult && CanUse(HOOKSHOT);}}), + //Trick: (IsAdult && ((HasExplosives && CanUse(HOOKSHOT)) || (LogicFireMQMazeHovers && CanUse(HOVER_BOOTS)))) || LogicFireMQMazeJump + }); + + areaTable[FIRE_TEMPLE_MQ_UPPER_MAZE] = Area("Fire Temple MQ Upper Maze", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + //EventAccess(&WallFairy, {[]{return WallFairy || (IsAdult && (((CanPlay(SongOfTime) && CanUse(HOOKSHOT) && HasExplosives) || CanUse(LONGSHOT))));}}), + EventAccess(&FairyPot, {[]{return SmallKeys(FIRE_TEMPLE, 3);}}), + }, { + //Locations + LocationAccess(FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CHEST, {[]{return true;}}), + LocationAccess(FIRE_TEMPLE_MQ_COMPASS_CHEST, {[]{return HasExplosives;}}), + LocationAccess(FIRE_TEMPLE_MQ_GS_SKULL_ON_FIRE, {[]{return IsAdult && ((CanPlay(SongOfTime) && CanUse(HOOKSHOT) && HasExplosives) || CanUse(LONGSHOT));}}), + }, { + //Exits + Entrance(FIRE_TEMPLE_MQ_UPPER, {[]{return SmallKeys(FIRE_TEMPLE, 3) && IsAdult && ((CanUse(BOW) && CanUse(HOOKSHOT)) || CanUse(FIRE_ARROWS));}}), + }); + + areaTable[FIRE_TEMPLE_MQ_UPPER] = Area("Fire Temple MQ Upper", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FIRE_TEMPLE_MQ_FREESTANDING_KEY, {[]{return IsAdult && CanUse(HOOKSHOT);}}), + //Trick: (IsAdult && CanUse(HOOKSHOT)) || LogicFireMQFlameMaze + LocationAccess(FIRE_TEMPLE_MQ_CHEST_ON_FIRE, {[]{return IsAdult && CanUse(HOOKSHOT) && SmallKeys(FIRE_TEMPLE, 4);}}), + //Trick: ((IsAdult && CanUse(HOOKSHOT)) || LogicFireMQFlameMaze) && SmallKeys(FIRE_TEMPLE, 4) + LocationAccess(FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_SIDE_ROOM, {[]{return CanPlay(SongOfTime) || HoverBoots;}}), + //Trick: CanPlay(SongOfTime) || HoverBoots || LogicFireMQFlameMaze + LocationAccess(FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_CENTER, {[]{return HasExplosives;}}), + LocationAccess(FIRE_TEMPLE_MQ_GS_ABOVE_FIRE_WALL_MAZE, {[]{return IsAdult && CanUse(HOOKSHOT) && SmallKeys(FIRE_TEMPLE, 5);}}), + //Trick: (IsAdult && CanUse(HOOKSHOT) && SmallKeys(FIRE_TEMPLE, 5)) || (LogicFireMQAboveMazeGS && IsAdult && CanUse(LONGSHOT)) + }, {}); + + areaTable[FIRE_TEMPLE_MQ_BOSS_ROOM] = Area("Fire Temple MQ Boss Room", "Fire Temple", FIRE_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FireTempleClear, {[]{return true;}}), + }, { + //Locations + LocationAccess(FIRE_TEMPLE_VOLVAGIA_HEART, {[]{return true;}}), + LocationAccess(VOLVAGIA, {[]{return true;}}), + }, {}); + } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_forest_temple.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_forest_temple.cpp new file mode 100644 index 000000000..138f6672b --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_forest_temple.cpp @@ -0,0 +1,452 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" +#include "../dungeon.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_ForestTemple() { + /*-------------------------- + | VANILLA/MQ DECIDER | + ---------------------------*/ + areaTable[FOREST_TEMPLE_ENTRYWAY] = Area("Forest Temple Entryway", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FOREST_TEMPLE_FIRST_ROOM, {[]{return Dungeon::ForestTemple.IsVanilla();}}), + Entrance(FOREST_TEMPLE_MQ_LOBBY, {[]{return Dungeon::ForestTemple.IsMQ();}}), + Entrance(SACRED_FOREST_MEADOW, {[]{return true;}}), + }); + + /*-------------------------- + | VANILLA DUNGEON | + ---------------------------*/ + if (Dungeon::ForestTemple.IsVanilla()) { + areaTable[FOREST_TEMPLE_FIRST_ROOM] = Area("Forest Temple First Room", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FOREST_TEMPLE_FIRST_ROOM_CHEST, {[]{return true;}}), + LocationAccess(FOREST_TEMPLE_GS_FIRST_ROOM, {[]{return (IsAdult && Bombs) || CanUse(BOW) || CanUse(HOOKSHOT) || CanUse(BOOMERANG) || CanUse(SLINGSHOT) || HasBombchus || CanUse(DINS_FIRE);}, + /*Glitched*/[]{return (Bombs && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE)) || CanDoGlitch(GlitchType::SuperStab, GlitchDifficulty::NOVICE);}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_ENTRYWAY, {[]{return true;}}), + Entrance(FOREST_TEMPLE_SOUTH_CORRIDOR, {[]{return true;}}), + }); + + areaTable[FOREST_TEMPLE_SOUTH_CORRIDOR] = Area("Forest Temple South Corridor", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FOREST_TEMPLE_FIRST_ROOM, {[]{return true;}}), + Entrance(FOREST_TEMPLE_LOBBY, {[]{return IsAdult || CanChildAttack || Nuts;}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }); + + areaTable[FOREST_TEMPLE_LOBBY] = Area("Forest Temple Lobby", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&ForestTempleMeg, {[]{return ForestTempleMeg || (ForestTempleJoelle && ForestTempleBeth && ForestTempleAmy && CanUse(BOW));}}), + }, { + //Locations + LocationAccess(FOREST_TEMPLE_GS_LOBBY, {[]{return HookshotOrBoomerang;}, + /*Glitched*/[]{return IsAdult && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE);}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_SOUTH_CORRIDOR, {[]{return true;}}), + Entrance(FOREST_TEMPLE_NORTH_CORRIDOR, {[]{return true;}}), + Entrance(FOREST_TEMPLE_NW_OUTDOORS_LOWER, {[]{return CanPlay(SongOfTime) || IsChild;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::LedgeClip, GlitchDifficulty::NOVICE) || (SongOfTime && (CanDoGlitch(GlitchType::DungeonBombOI, GlitchDifficulty::INTERMEDIATE) || + ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))));}}), + Entrance(FOREST_TEMPLE_NE_OUTDOORS_LOWER, {[]{return CanUse(BOW) || CanUse(SLINGSHOT);}}), + Entrance(FOREST_TEMPLE_WEST_CORRIDOR, {[]{return SmallKeys(FOREST_TEMPLE, 1, 5);}}), + Entrance(FOREST_TEMPLE_EAST_CORRIDOR, {[]{return false;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE);}}), + Entrance(FOREST_TEMPLE_BOSS_REGION, {[]{return ForestTempleMeg;}}), + Entrance(FOREST_TEMPLE_BOSS_ROOM, {[]{return false;}, + /*Glitched*/[]{return IsAdult && (CanUse(HOOKSHOT) || CanUse(BOW) || CanUse(SLINGSHOT)) && GlitchForestBKSkip;}}), + }); + + areaTable[FOREST_TEMPLE_NORTH_CORRIDOR] = Area("Forest Temple North Corridor", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FOREST_TEMPLE_LOBBY, {[]{return true;}}), + Entrance(FOREST_TEMPLE_LOWER_STALFOS, {[]{return true;}}), + }); + + areaTable[FOREST_TEMPLE_LOWER_STALFOS] = Area("Forest Temple Lower Stalfos", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return true;}}), + }, { + //Locations + LocationAccess(FOREST_TEMPLE_FIRST_STALFOS_CHEST, {[]{return IsAdult || KokiriSword;}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_NORTH_CORRIDOR, {[]{return true;}}), + }); + + areaTable[FOREST_TEMPLE_NW_OUTDOORS_LOWER] = Area("Forest Temple NW Outdoors Lower", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DekuBabaSticks, {[]{return DekuBabaSticks || (IsAdult || KokiriSword || Boomerang);}}), + EventAccess(&DekuBabaNuts, {[]{return DekuBabaNuts || (IsAdult || KokiriSword || Slingshot || Sticks || HasExplosives || CanUse(DINS_FIRE));}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }, { + //Locations + LocationAccess(FOREST_TEMPLE_GS_LEVEL_ISLAND_COURTYARD, {[]{return CanUse(LONGSHOT) || Here(FOREST_TEMPLE_NW_OUTDOORS_UPPER, []{return HookshotOrBoomerang;});}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_LOBBY, {[]{return CanPlay(SongOfTime);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::LedgeClip, GlitchDifficulty::NOVICE) || (SongOfTime && (CanDoGlitch(GlitchType::DungeonBombOI, GlitchDifficulty::INTERMEDIATE) || + ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))));}}), + Entrance(FOREST_TEMPLE_NW_OUTDOORS_UPPER, {[]{return false;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::INTERMEDIATE) || (IsAdult && CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::NOVICE)) || (Bombs && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE));}}), + Entrance(FOREST_TEMPLE_MAP_ROOM, {[]{return true;}}), + Entrance(FOREST_TEMPLE_SEWER, {[]{return GoldScale || CanUse(IRON_BOOTS) || HasAccessTo(FOREST_TEMPLE_NE_OUTDOORS_UPPER);}}), + Entrance(FOREST_TEMPLE_BOSS_ROOM, {[]{return false;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::INTERMEDIATE);}}), + }); + + areaTable[FOREST_TEMPLE_NW_OUTDOORS_UPPER] = Area("Forest Temple NW Outdoors Upper", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DekuBabaSticks, {[]{return DekuBabaSticks || (IsAdult || KokiriSword || Boomerang);}}), + EventAccess(&DekuBabaNuts, {[]{return DekuBabaNuts || (IsAdult || KokiriSword || Slingshot || Sticks || HasExplosives || CanUse(DINS_FIRE));}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }, {}, { + //Exits + Entrance(FOREST_TEMPLE_NW_OUTDOORS_LOWER, {[]{return true;}}), + Entrance(FOREST_TEMPLE_BELOW_BOSS_KEY_CHEST, {[]{return true;}}), + Entrance(FOREST_TEMPLE_FLOORMASTER_ROOM, {[]{return true;}}), + Entrance(FOREST_TEMPLE_BLOCK_PUSH_ROOM, {[]{return true;}}), + }); + + areaTable[FOREST_TEMPLE_NE_OUTDOORS_LOWER] = Area("Forest Temple NE Outdoors Lower", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DekuBabaSticks, {[]{return DekuBabaSticks || (IsAdult || KokiriSword || Boomerang);}}), + EventAccess(&DekuBabaNuts, {[]{return DekuBabaNuts || (IsAdult || KokiriSword || Slingshot || Sticks || HasExplosives || CanUse(DINS_FIRE));}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }, { + //Locations + LocationAccess(FOREST_TEMPLE_RAISED_ISLAND_COURTYARD_CHEST, {[]{return CanUse(HOOKSHOT) || HasAccessTo(FOREST_TEMPLE_FALLING_ROOM);}}), + LocationAccess(FOREST_TEMPLE_GS_RAISED_ISLAND_COURTYARD, {[]{return CanUse(HOOKSHOT) || (LogicForestOutdoorEastGS && CanUse(BOOMERANG)) || Here(FOREST_TEMPLE_FALLING_ROOM, []{return CanUse(BOW) || CanUse(SLINGSHOT) || CanUse(DINS_FIRE) || HasExplosives;});}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_LOBBY, {[]{return true;}}), + Entrance(FOREST_TEMPLE_NE_OUTDOORS_UPPER, {[]{return CanUse(LONGSHOT);}}), + Entrance(FOREST_TEMPLE_SEWER, {[]{return GoldScale || CanUse(IRON_BOOTS) || HasAccessTo(FOREST_TEMPLE_NE_OUTDOORS_UPPER);}}), + Entrance(FOREST_TEMPLE_FALLING_ROOM, {[]{return false;}, + /*Glitched*/[]{return Bombs && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE);}}), + }); + + areaTable[FOREST_TEMPLE_NE_OUTDOORS_UPPER] = Area("Forest Temple NE Outdoors Upper", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DekuBabaSticks, {[]{return DekuBabaSticks || (IsAdult || KokiriSword || Boomerang);}}), + EventAccess(&DekuBabaNuts, {[]{return DekuBabaNuts || (IsAdult || KokiriSword || Slingshot || Sticks || HasExplosives || CanUse(DINS_FIRE));}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }, {}, { + //Exits + Entrance(FOREST_TEMPLE_NE_OUTDOORS_LOWER, {[]{return true;}}), + Entrance(FOREST_TEMPLE_MAP_ROOM, {[]{return true;}}), + Entrance(FOREST_TEMPLE_FALLING_ROOM, {[]{return LogicForestDoorFrame && CanUse(HOVER_BOOTS) && CanUse(SCARECROW);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::EXPERT);}}), + }); + + areaTable[FOREST_TEMPLE_MAP_ROOM] = Area("Forest Temple Map Room", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FOREST_TEMPLE_MAP_CHEST, {[]{return Here(FOREST_TEMPLE_MAP_ROOM, []{return HasExplosives || CanUse(MEGATON_HAMMER) || CanUse(BOW) || ((IsAdult || Sticks || KokiriSword || Slingshot) && (Nuts || HookshotOrBoomerang || CanShield));});}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_NW_OUTDOORS_LOWER, {[]{return Here(FOREST_TEMPLE_MAP_ROOM, []{return HasExplosives || CanUse(MEGATON_HAMMER) || CanUse(BOW) || ((IsAdult || Sticks || KokiriSword || Slingshot) && (Nuts || HookshotOrBoomerang || CanShield));});}}), + Entrance(FOREST_TEMPLE_NE_OUTDOORS_UPPER, {[]{return Here(FOREST_TEMPLE_MAP_ROOM, []{return HasExplosives || CanUse(MEGATON_HAMMER) || CanUse(BOW) || ((IsAdult || Sticks || KokiriSword || Slingshot) && (Nuts || HookshotOrBoomerang || CanShield));});}}), + }); + + areaTable[FOREST_TEMPLE_SEWER] = Area("Forest Temple Sewer", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FOREST_TEMPLE_WELL_CHEST, {[]{return HasAccessTo(FOREST_TEMPLE_NE_OUTDOORS_UPPER);}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_NW_OUTDOORS_LOWER, {[]{return true;}}), + Entrance(FOREST_TEMPLE_NE_OUTDOORS_LOWER, {[]{return true;}}), + }); + + areaTable[FOREST_TEMPLE_BELOW_BOSS_KEY_CHEST] = Area("Forest Temple Below Boss Key Chest", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FOREST_TEMPLE_NW_OUTDOORS_UPPER, {[]{return Here(FOREST_TEMPLE_BELOW_BOSS_KEY_CHEST, []{return HasExplosives || CanUse(MEGATON_HAMMER) || CanUse(BOW) || ((IsAdult || Sticks || KokiriSword || Slingshot) && (Nuts || HookshotOrBoomerang || CanShield));});}}), + }); + + areaTable[FOREST_TEMPLE_FLOORMASTER_ROOM] = Area("Forest Temple Floormaster Room", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FOREST_TEMPLE_FLOORMASTER_CHEST, {[]{return IsAdult || CanChildDamage;}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_NW_OUTDOORS_UPPER, {[]{return true;}}), + }); + + areaTable[FOREST_TEMPLE_WEST_CORRIDOR] = Area("Forest Temple West Corridor", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FOREST_TEMPLE_LOBBY, {[]{return SmallKeys(FOREST_TEMPLE, 1, 5);}}), + Entrance(FOREST_TEMPLE_BLOCK_PUSH_ROOM, {[]{return IsAdult || CanChildAttack || Nuts;}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }); + + areaTable[FOREST_TEMPLE_BLOCK_PUSH_ROOM] = Area("Forest Temple Block Push Room", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FOREST_TEMPLE_EYE_SWITCH_CHEST, {[]{return GoronBracelet && (CanUse(BOW) || CanUse(SLINGSHOT));}, + /*Glitched*/[]{return IsAdult && (CanUse(BOW) || CanUse(SLINGSHOT)) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED);}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_WEST_CORRIDOR, {[]{return true;}}), + Entrance(FOREST_TEMPLE_NW_OUTDOORS_UPPER, {[]{return CanUse(HOVER_BOOTS) || (LogicForestOutsideBackdoor && IsAdult && GoronBracelet);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE) || (Bombs && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE));}}), + Entrance(FOREST_TEMPLE_NW_CORRIDOR_TWISTED, {[]{return IsAdult && GoronBracelet && SmallKeys(FOREST_TEMPLE, 2);}, + /*Glitched*/[]{return ((IsAdult && (Bow || Hookshot || CanUse(SLINGSHOT)) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED)) || + (Bombs && GoronBracelet && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE))) && SmallKeys(FOREST_TEMPLE, 2);}}), + Entrance(FOREST_TEMPLE_NW_CORRIDOR_STRAIGHTENED, {[]{return CanUse(BOW) && GoronBracelet && SmallKeys(FOREST_TEMPLE, 2);}, + /*Glitched*/[]{return ((IsAdult && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED)) || + (IsChild && Bombs && GoronBracelet && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE))) && (CanUse(BOW) || CanUse(SLINGSHOT)) && SmallKeys(FOREST_TEMPLE, 2);}}), + }); + + areaTable[FOREST_TEMPLE_NW_CORRIDOR_TWISTED] = Area("Forest Temple NW Corridor Twisted", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FOREST_TEMPLE_BLOCK_PUSH_ROOM, {[]{return SmallKeys(FOREST_TEMPLE, 2);}}), + Entrance(FOREST_TEMPLE_RED_POE_ROOM, {[]{return SmallKeys(FOREST_TEMPLE, 3);}}), + }); + + areaTable[FOREST_TEMPLE_NW_CORRIDOR_STRAIGHTENED] = Area("Forest Temple NW Corridor Straightened", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FOREST_TEMPLE_BOSS_KEY_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_BELOW_BOSS_KEY_CHEST, {[]{return true;}}), + Entrance(FOREST_TEMPLE_BLOCK_PUSH_ROOM, {[]{return SmallKeys(FOREST_TEMPLE, 2);}}), + }); + + areaTable[FOREST_TEMPLE_RED_POE_ROOM] = Area("Forest Temple Red Poe Room", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&ForestTempleJoelle, {[]{return ForestTempleJoelle || CanUse(BOW);}}), + }, { + //Locations + LocationAccess(FOREST_TEMPLE_RED_POE_CHEST, {[]{return ForestTempleJoelle;}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_NW_CORRIDOR_TWISTED, {[]{return SmallKeys(FOREST_TEMPLE, 3);}}), + Entrance(FOREST_TEMPLE_UPPER_STALFOS, {[]{return true;}}), + }); + + areaTable[FOREST_TEMPLE_UPPER_STALFOS] = Area("Forest Temple Upper Stalfos", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FOREST_TEMPLE_BOW_CHEST, {[]{return IsAdult || KokiriSword;}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_RED_POE_ROOM, {[]{return IsAdult || KokiriSword;}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + Entrance(FOREST_TEMPLE_BLUE_POE_ROOM, {[]{return IsAdult || KokiriSword;}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }); + + areaTable[FOREST_TEMPLE_BLUE_POE_ROOM] = Area("Forest Temple Blue Poe Room", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&ForestTempleBeth, {[]{return ForestTempleBeth || CanUse(BOW);}}), + }, { + //Locations + LocationAccess(FOREST_TEMPLE_BLUE_POE_CHEST, {[]{return ForestTempleBeth;}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_UPPER_STALFOS, {[]{return true;}}), + Entrance(FOREST_TEMPLE_NE_CORRIDOR_STRAIGHTENED, {[]{return SmallKeys(FOREST_TEMPLE, 4);}}), + }); + + areaTable[FOREST_TEMPLE_NE_CORRIDOR_STRAIGHTENED] = Area("Forest Temple NE Corridor Straightened", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FOREST_TEMPLE_BLUE_POE_ROOM, {[]{return SmallKeys(FOREST_TEMPLE, 4);}}), + Entrance(FOREST_TEMPLE_FROZEN_EYE_ROOM, {[]{return SmallKeys(FOREST_TEMPLE, 5);}}), + }); + + areaTable[FOREST_TEMPLE_NE_CORRIDOR_TWISTED] = Area("Forest Temple NE Corridor Twisted", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FOREST_TEMPLE_FROZEN_EYE_ROOM, {[]{return SmallKeys(FOREST_TEMPLE, 5);}}), + Entrance(FOREST_TEMPLE_FALLING_ROOM, {[]{return true;}}), + }); + + areaTable[FOREST_TEMPLE_FROZEN_EYE_ROOM] = Area("Forest Temple Frozen Eye Room", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FOREST_TEMPLE_NE_CORRIDOR_STRAIGHTENED, {[]{return SmallKeys(FOREST_TEMPLE, 5);}}), + Entrance(FOREST_TEMPLE_NE_CORRIDOR_TWISTED, {[]{return SmallKeys(FOREST_TEMPLE, 5) && (CanUse(BOW) || CanUse(DINS_FIRE));}}), + }); + + areaTable[FOREST_TEMPLE_FALLING_ROOM] = Area("Forest Temple Falling Room", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FOREST_TEMPLE_FALLING_CEILING_ROOM_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_NE_OUTDOORS_LOWER, {[]{return true;}}), + Entrance(FOREST_TEMPLE_GREEN_POE_ROOM, {[]{return true;}}), + }); + + areaTable[FOREST_TEMPLE_GREEN_POE_ROOM] = Area("Forest Temple Green Poe Room", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&ForestTempleAmy, {[]{return ForestTempleAmy || CanUse(BOW);}}), + }, {}, { + //Exits + Entrance(FOREST_TEMPLE_FALLING_ROOM, {[]{return true;}}), + Entrance(FOREST_TEMPLE_EAST_CORRIDOR, {[]{return ForestTempleAmy;}}), + }); + + areaTable[FOREST_TEMPLE_EAST_CORRIDOR] = Area("Forest Temple East Corridor", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(FOREST_TEMPLE_LOBBY, {[]{return IsAdult || CanChildAttack || Nuts;}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + Entrance(FOREST_TEMPLE_GREEN_POE_ROOM, {[]{return IsAdult || CanChildAttack || Nuts;}, + /*Glitched*/[]{return CanUse(MEGATON_HAMMER);}}), + }); + + areaTable[FOREST_TEMPLE_BOSS_REGION] = Area("Forest Temple Boss Region", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FOREST_TEMPLE_BASEMENT_CHEST, {[]{return true;}}), + LocationAccess(FOREST_TEMPLE_GS_BASEMENT, {[]{return HookshotOrBoomerang;}, + /*Glitched*/[]{return Bombs && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE);}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_LOBBY, {[]{return true;}}), + Entrance(FOREST_TEMPLE_BOSS_ROOM, {[]{return BossKeyForestTemple;}}), + }); + + areaTable[FOREST_TEMPLE_BOSS_ROOM] = Area("Forest Temple Boss Room", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&ForestTempleClear, {[]{return ForestTempleClear || ((IsAdult || KokiriSword) && (CanUse(HOOKSHOT) || CanUse(BOW) || CanUse(SLINGSHOT)));}}), + }, { + //Locations + LocationAccess(FOREST_TEMPLE_PHANTOM_GANON_HEART, {[]{return ForestTempleClear;}}), + LocationAccess(PHANTOM_GANON, {[]{return ForestTempleClear;}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_ENTRYWAY, {[]{return ForestTempleClear;}}), + }); + } + + /*--------------------------- + | MASTER QUEST DUNGEON | + ---------------------------*/ + if (Dungeon::ForestTemple.IsMQ()) { + areaTable[FOREST_TEMPLE_MQ_LOBBY] = Area("Forest Temple MQ Lobby", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FOREST_TEMPLE_MQ_FIRST_ROOM_CHEST, {[]{return IsAdult || Bombs || CanUse(STICKS) || Nuts || CanUse(BOOMERANG) || CanUse(DINS_FIRE) || KokiriSword || CanUse(SLINGSHOT);}}), + LocationAccess(FOREST_TEMPLE_MQ_GS_FIRST_HALLWAY, {[]{return HookshotOrBoomerang;}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_ENTRYWAY, {[]{return true;}}), + Entrance(FOREST_TEMPLE_MQ_CENTRAL_AREA, {[]{return SmallKeys(FOREST_TEMPLE, 1) && (IsAdult || CanChildAttack || Nuts);}}), + }); + + areaTable[FOREST_TEMPLE_MQ_CENTRAL_AREA] = Area("Forest Temple MQ Central Area", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return true;}}), + }, { + //Locations + LocationAccess(FOREST_TEMPLE_MQ_WOLFOS_CHEST, {[]{return (CanPlay(SongOfTime) || IsChild) && (IsAdult || CanUse(DINS_FIRE) || CanUse(STICKS) || CanUse(SLINGSHOT) || KokiriSword);}}), + LocationAccess(FOREST_TEMPLE_MQ_GS_BLOCK_PUSH_ROOM, {[]{return IsAdult || KokiriSword;}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_MQ_NW_OUTDOORS, {[]{return (IsAdult && CanUse(BOW)) || (IsChild && CanUse(SLINGSHOT));}}), + Entrance(FOREST_TEMPLE_MQ_NE_OUTDOORS, {[]{return (IsAdult && CanUse(BOW)) || (IsChild && CanUse(SLINGSHOT));}}), //This is as far as child can get + Entrance(FOREST_TEMPLE_MQ_AFTER_BLOCK_PUZZLE, {[]{return IsAdult && GoronBracelet;}}), + //Trick: IsAdult && (GoronBracelet || (LogicForestMQBlockPuzzle && HasBombchus && IsAdult && CanUse(HOOKSHOT))) + Entrance(FOREST_TEMPLE_MQ_OUTDOOR_LEDGE, {[]{return false;}}), + //Trick: (LogicForestMQHallwaySwitchJumpslash && IsAdult && CanUse(HOVER_BOOTS)) || (LogicForestMQHallwaySwitchHookshot && IsAdult && CanUse(HOOKSHOT)) + Entrance(FOREST_TEMPLE_MQ_BOSS_REGION, {[]{return ForestTempleJoAndBeth && ForestTempleAmyAndMeg;}}), + }); + + areaTable[FOREST_TEMPLE_MQ_AFTER_BLOCK_PUZZLE] = Area("Forest Temple MQ After Block Puzzle", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FOREST_TEMPLE_MQ_BOSS_KEY_CHEST, {[]{return SmallKeys(FOREST_TEMPLE, 3);}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_MQ_BOW_REGION, {[]{return SmallKeys(FOREST_TEMPLE, 4);}}), + Entrance(FOREST_TEMPLE_MQ_OUTDOOR_LEDGE, {[]{return SmallKeys(FOREST_TEMPLE, 3);}}), + //Trick: SmallKeys(FOREST_TEMPLE, 3) || (LogicForestMQHallwaySwitchJumpslash && ((IsAdult && CanUse(HOOKSHOT)) || LogicForestOutsideBackdoor)) + Entrance(FOREST_TEMPLE_MQ_NW_OUTDOORS, {[]{return SmallKeys(FOREST_TEMPLE, 2);}}), + }); + + areaTable[FOREST_TEMPLE_MQ_OUTDOOR_LEDGE] = Area("Forest Temple MQ Outdoor Ledge", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FOREST_TEMPLE_MQ_REDEAD_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_MQ_NW_OUTDOORS, {[]{return true;}}), + }); + + areaTable[FOREST_TEMPLE_MQ_NW_OUTDOORS] = Area("Forest Temple MQ NW Outdoors", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FOREST_TEMPLE_MQ_GS_LEVEL_ISLAND_COURTYARD, {[]{return true;}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_MQ_NE_OUTDOORS, {[]{return (IsAdult && (CanUse(IRON_BOOTS) || CanUse(LONGSHOT))) || ProgressiveScale >= 2;}}), + //Trick: (IsAdult && (CanUse(IRON_BOOTS) || CanUse(LONGSHOT) || (LogicForestMQWellSwim && CanUse(HOOKSHOT)))) || ProgressiveScale >= 2 + Entrance(FOREST_TEMPLE_MQ_OUTDOORS_TOP_LEDGES, {[]{return IsAdult && CanUse(FIRE_ARROWS);}}), + }); + + areaTable[FOREST_TEMPLE_MQ_NE_OUTDOORS] = Area("Forest Temple MQ NE Outdoors", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DekuBabaSticks, {[]{return DekuBabaSticks || (IsAdult || KokiriSword || Boomerang);}}), + EventAccess(&DekuBabaNuts, {[]{return DekuBabaNuts || (IsAdult || KokiriSword || Slingshot || Sticks || HasExplosives || CanUse(DINS_FIRE));}}), + }, { + //Locations + LocationAccess(FOREST_TEMPLE_MQ_WELL_CHEST, {[]{return (IsAdult && CanUse(BOW)) || (IsChild && CanUse(SLINGSHOT));}}), + LocationAccess(FOREST_TEMPLE_MQ_GS_RAISED_ISLAND_COURTYARD, {[]{return HookshotOrBoomerang || (IsAdult && CanUse(FIRE_ARROWS) && (CanPlay(SongOfTime) || (CanUse(HOVER_BOOTS) && LogicForestDoorFrame)));}}), + LocationAccess(FOREST_TEMPLE_MQ_GS_WELL, {[]{return (IsAdult && ((CanUse(IRON_BOOTS) && CanUse(HOOKSHOT)) || CanUse(BOW))) || (IsChild && CanUse(SLINGSHOT));}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_MQ_OUTDOORS_TOP_LEDGES, {[]{return IsAdult && CanUse(HOOKSHOT) && (CanUse(LONGSHOT) || CanUse(HOVER_BOOTS) || CanPlay(SongOfTime));}}), + Entrance(FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE, {[]{return IsAdult && CanUse(LONGSHOT);}}), + }); + + areaTable[FOREST_TEMPLE_MQ_OUTDOORS_TOP_LEDGES] = Area("Forest Temple MQ Outdoors Top Ledges", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_UPPER_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_MQ_NE_OUTDOORS, {[]{return true;}}), + Entrance(FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE, {[]{return false;}}), + //Trick: LogicForestOutdoorsLedge && IsAdult && CanUse(HOVER_BOOTS) + }); + + areaTable[FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE] = Area("Forest Temple MQ NE Outdoors Ledge", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_LOWER_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_MQ_NE_OUTDOORS, {[]{return true;}}), + Entrance(FOREST_TEMPLE_MQ_FALLING_ROOM, {[]{return CanPlay(SongOfTime);}}), + }); + + areaTable[FOREST_TEMPLE_MQ_BOW_REGION] = Area("Forest Temple MQ Bow Region", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&ForestTempleJoAndBeth, {[]{return ForestTempleJoAndBeth || (IsAdult && CanUse(BOW));}}), + }, { + //Locations + LocationAccess(FOREST_TEMPLE_MQ_BOW_CHEST, {[]{return true;}}), + LocationAccess(FOREST_TEMPLE_MQ_MAP_CHEST, {[]{return IsAdult && CanUse(BOW);}}), + LocationAccess(FOREST_TEMPLE_MQ_COMPASS_CHEST, {[]{return IsAdult && CanUse(BOW);}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_MQ_FALLING_ROOM, {[]{return SmallKeys(FOREST_TEMPLE, 5) && ((IsAdult && CanUse(BOW)) || CanUse(DINS_FIRE));}}), + }); + + areaTable[FOREST_TEMPLE_MQ_FALLING_ROOM] = Area("Forest Temple MQ Falling Room", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&ForestTempleAmyAndMeg, {[]{return ForestTempleAmyAndMeg || (IsAdult && CanUse(BOW) && SmallKeys(FOREST_TEMPLE, 6));}}), + }, { + //Locations + LocationAccess(FOREST_TEMPLE_MQ_FALLING_CEILING_ROOM_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE, {[]{return true;}}), + }); + + areaTable[FOREST_TEMPLE_MQ_BOSS_REGION] = Area("Forest Temple MQ Boss Region", "Forest Temple", FOREST_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&ForestTempleClear, {[]{return ForestTempleClear || BossKeyForestTemple;}}), + }, { + //Locations + LocationAccess(FOREST_TEMPLE_MQ_BASEMENT_CHEST, {[]{return true;}}), + LocationAccess(FOREST_TEMPLE_PHANTOM_GANON_HEART, {[]{return BossKeyForestTemple;}}), + LocationAccess(PHANTOM_GANON, {[]{return BossKeyForestTemple;}}), + }, {}); + } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_ganons_castle.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_ganons_castle.cpp new file mode 100644 index 000000000..383b72b9f --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_ganons_castle.cpp @@ -0,0 +1,213 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" +#include "../dungeon.hpp" +#include "../trial.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_GanonsCastle() { + /*-------------------------- + | VANILLA/MQ DECIDER | + ---------------------------*/ + areaTable[GANONS_CASTLE_ENTRYWAY] = Area("Ganon's Castle Entryway", "Ganon's Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(GANONS_CASTLE_LOBBY, {[]{return Dungeon::GanonsCastle.IsVanilla();}}), + Entrance(GANONS_CASTLE_MQ_LOBBY, {[]{return Dungeon::GanonsCastle.IsMQ();}}), + Entrance(GANONS_CASTLE_GROUNDS, {[]{return true;}}), + }); + + /*-------------------------- + | VANILLA DUNGEON | + ---------------------------*/ + if (Dungeon::GanonsCastle.IsVanilla()) { + areaTable[GANONS_CASTLE_LOBBY] = Area("Ganon's Castle Lobby", "Ganon's Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(GANONS_CASTLE_ENTRYWAY, {[]{return true;}}), + Entrance(GANONS_CASTLE_FOREST_TRIAL, {[]{return true;}}), + Entrance(GANONS_CASTLE_FIRE_TRIAL, {[]{return true;}}), + Entrance(GANONS_CASTLE_WATER_TRIAL, {[]{return true;}}), + Entrance(GANONS_CASTLE_SHADOW_TRIAL, {[]{return true;}}), + Entrance(GANONS_CASTLE_SPIRIT_TRIAL, {[]{return true;}}), + Entrance(GANONS_CASTLE_LIGHT_TRIAL, {[]{return CanUse(GOLDEN_GAUNTLETS);}}), + Entrance(GANONS_CASTLE_TOWER, {[]{return (ForestTrialClear || Trial::ForestTrial.IsSkipped()) && + (FireTrialClear || Trial::FireTrial.IsSkipped()) && + (WaterTrialClear || Trial::WaterTrial.IsSkipped()) && + (ShadowTrialClear || Trial::ShadowTrial.IsSkipped()) && + (SpiritTrialClear || Trial::SpiritTrial.IsSkipped()) && + (LightTrialClear || Trial::LightTrial.IsSkipped());}}), + Entrance(GANONS_CASTLE_DEKU_SCRUBS, {[]{return LogicLensCastle || CanUse(LENS_OF_TRUTH);}}), + }); + + areaTable[GANONS_CASTLE_DEKU_SCRUBS] = Area("Ganon's Castle Deku Scrubs", "Ganon's Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FreeFairies, {[]{return true;}}), + }, { + //Locations + LocationAccess(GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT, {[]{return CanStunDeku;}}), + LocationAccess(GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT, {[]{return CanStunDeku;}}), + LocationAccess(GANONS_CASTLE_DEKU_SCRUB_RIGHT, {[]{return CanStunDeku;}}), + LocationAccess(GANONS_CASTLE_DEKU_SCRUB_LEFT, {[]{return CanStunDeku;}}), + }, {}); + + areaTable[GANONS_CASTLE_FOREST_TRIAL] = Area("Ganon's Castle Forest Trial", "Ganon's Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&ForestTrialClear, {[]{return CanUse(LIGHT_ARROWS) && (FireArrows || DinsFire);}}), + }, { + //Locations + LocationAccess(GANONS_CASTLE_FOREST_TRIAL_CHEST, {[]{return IsAdult || CanChildDamage;}}), + }, {}); + + areaTable[GANONS_CASTLE_FIRE_TRIAL] = Area("Ganon's Castle Fire Trial", "Ganon's Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FireTrialClear, {[]{return CanUse(GORON_TUNIC) && CanUse(GOLDEN_GAUNTLETS) && CanUse(LIGHT_ARROWS) && CanUse(LONGSHOT);}}), + }, {}, {}); + + areaTable[GANONS_CASTLE_WATER_TRIAL] = Area("Ganon's Castle Water Trial", "Ganon's Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&BlueFireAccess, {[]{return BlueFireAccess || HasBottle;}}), + EventAccess(&FairyPot, {[]{return FairyPot || BlueFire;}}), + EventAccess(&WaterTrialClear, {[]{return BlueFire && Hammer && CanUse(LIGHT_ARROWS);}}), + }, { + //Locations + LocationAccess(GANONS_CASTLE_WATER_TRIAL_LEFT_CHEST, {[]{return true;}}), + LocationAccess(GANONS_CASTLE_WATER_TRIAL_RIGHT_CHEST, {[]{return true;}}), + }, {}); + + areaTable[GANONS_CASTLE_SHADOW_TRIAL] = Area("Ganon's Castle Shadow Trial", "Ganon's Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&ShadowTrialClear, {[]{return CanUse(LIGHT_ARROWS) && Hammer && ((FireArrows && (LogicLensCastle || CanUse(LENS_OF_TRUTH))) || (CanUse(LONGSHOT) && (CanUse(HOVER_BOOTS) || (DinsFire && (LogicLensCastle || CanUse(LENS_OF_TRUTH))))));}}), + }, { + //Locations + LocationAccess(GANONS_CASTLE_SHADOW_TRIAL_FRONT_CHEST, {[]{return CanUse(FIRE_ARROWS) || CanUse(HOOKSHOT) || CanUse(HOVER_BOOTS) || CanPlay(SongOfTime) || IsChild;}}), + LocationAccess(GANONS_CASTLE_SHADOW_TRIAL_GOLDEN_GAUNTLETS_CHEST, {[]{return CanUse(FIRE_ARROWS) || (CanUse(LONGSHOT) && (CanUse(HOVER_BOOTS) || CanUse(DINS_FIRE)));}}), + }, {}); + + areaTable[GANONS_CASTLE_SPIRIT_TRIAL] = Area("Ganon's Castle Spirit Trial", "Ganon's Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&NutPot, {[]{return NutPot || ((LogicSpiritTrialHookshot || CanUse(HOOKSHOT)) && HasBombchus && Bow && MirrorShield && IsAdult);}}), + EventAccess(&SpiritTrialClear, {[]{return CanUse(LIGHT_ARROWS) && MirrorShield && HasBombchus && (LogicSpiritTrialHookshot || CanUse(HOOKSHOT));}}), + }, { + //Locations + LocationAccess(GANONS_CASTLE_SPIRIT_TRIAL_CRYSTAL_SWITCH_CHEST, {[]{return LogicSpiritTrialHookshot || CanUse(HOOKSHOT);}}), + LocationAccess(GANONS_CASTLE_SPIRIT_TRIAL_INVISIBLE_CHEST, {[]{return (LogicSpiritTrialHookshot || CanUse(HOOKSHOT)) && HasBombchus && (LogicLensCastle || CanUse(LENS_OF_TRUTH));}}), + }, {}); + + areaTable[GANONS_CASTLE_LIGHT_TRIAL] = Area("Ganon's Castle Light Trial", "Ganon's Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&LightTrialClear, {[]{return CanUse(LIGHT_ARROWS) && CanUse(HOOKSHOT) && SmallKeys(GANONS_CASTLE, 2) && (LogicLensCastle || CanUse(LENS_OF_TRUTH));}}), + }, { + //Locations + LocationAccess(GANONS_CASTLE_LIGHT_TRIAL_FIRST_LEFT_CHEST, {[]{return true;}}), + LocationAccess(GANONS_CASTLE_LIGHT_TRIAL_SECOND_LEFT_CHEST, {[]{return true;}}), + LocationAccess(GANONS_CASTLE_LIGHT_TRIAL_THIRD_LEFT_CHEST, {[]{return true;}}), + LocationAccess(GANONS_CASTLE_LIGHT_TRIAL_FIRST_RIGHT_CHEST, {[]{return true;}}), + LocationAccess(GANONS_CASTLE_LIGHT_TRIAL_SECOND_RIGHT_CHEST, {[]{return true;}}), + LocationAccess(GANONS_CASTLE_LIGHT_TRIAL_THIRD_RIGHT_CHEST, {[]{return true;}}), + LocationAccess(GANONS_CASTLE_LIGHT_TRIAL_INVISIBLE_ENEMIES_CHEST, {[]{return LogicLensCastle || CanUse(LENS_OF_TRUTH);}}), + LocationAccess(GANONS_CASTLE_LIGHT_TRIAL_LULLABY_CHEST, {[]{return CanPlay(ZeldasLullaby) && SmallKeys(GANONS_CASTLE, 1);}}), + }, {}); + } + + areaTable[GANONS_CASTLE_TOWER] = Area("Ganon's Castle Tower", "Ganons Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GANONS_TOWER_BOSS_KEY_CHEST, {[]{return true;}}), + LocationAccess(GANONDORF_HINT, {[]{return BossKeyGanonsCastle;}}), + LocationAccess(GANON, {[]{return BossKeyGanonsCastle && CanUse(LIGHT_ARROWS);}}), + }, {}); + + /*--------------------------- + | MASTER QUEST DUNGEON | + ---------------------------*/ + if (Dungeon::GanonsCastle.IsMQ()) { + areaTable[GANONS_CASTLE_MQ_LOBBY] = Area("Ganon's Castle MQ Lobby", "Ganons Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(GANONS_CASTLE_ENTRYWAY, {[]{return (IsAdult || (HasExplosives || ((Nuts || Boomerang) && (Sticks || KokiriSword))));}}), + Entrance(GANONS_CASTLE_MQ_FOREST_TRIAL, {[]{return true;}}), + Entrance(GANONS_CASTLE_MQ_FIRE_TRIAL, {[]{return true;}}), + Entrance(GANONS_CASTLE_MQ_WATER_TRIAL, {[]{return true;}}), + Entrance(GANONS_CASTLE_MQ_SHADOW_TRIAL, {[]{return true;}}), + Entrance(GANONS_CASTLE_MQ_SPIRIT_TRIAL, {[]{return true;}}), + Entrance(GANONS_CASTLE_MQ_LIGHT_TRIAL, {[]{return CanUse(GOLDEN_GAUNTLETS);}}), + Entrance(GANONS_CASTLE_TOWER, {[]{return (ForestTrialClear || Trial::ForestTrial.IsSkipped()) && + (FireTrialClear || Trial::FireTrial.IsSkipped()) && + (WaterTrialClear || Trial::WaterTrial.IsSkipped()) && + (ShadowTrialClear || Trial::ShadowTrial.IsSkipped()) && + (SpiritTrialClear || Trial::SpiritTrial.IsSkipped()) && + (LightTrialClear || Trial::LightTrial.IsSkipped());}}), + Entrance(GANONS_CASTLE_MQ_DEKU_SCRUBS, {[]{return LogicLensCastleMQ || CanUse(LENS_OF_TRUTH);}}), + }); + + areaTable[GANONS_CASTLE_MQ_DEKU_SCRUBS] = Area("Ganon's Castle MQ Deku Scrubs", "Ganon's Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FreeFairies, {[]{return true;}}), + }, { + //Locations + LocationAccess(GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT, {[]{return CanStunDeku;}}), + LocationAccess(GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER, {[]{return CanStunDeku;}}), + LocationAccess(GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT, {[]{return CanStunDeku;}}), + LocationAccess(GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT, {[]{return CanStunDeku;}}), + LocationAccess(GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT, {[]{return CanStunDeku;}}), + }, {}); + + areaTable[GANONS_CASTLE_MQ_FOREST_TRIAL] = Area("Ganon's Castle MQ Forest Trial", "Ganons Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&ForestTrialClear, {[]{return IsAdult && CanUse(LIGHT_ARROWS) && CanPlay(SongOfTime);}}), + }, { + //Locations + LocationAccess(GANONS_CASTLE_MQ_FOREST_TRIAL_EYE_SWITCH_CHEST, {[]{return (IsAdult && CanUse(BOW)) || (IsChild && CanUse(SLINGSHOT));}}), + LocationAccess(GANONS_CASTLE_MQ_FOREST_TRIAL_FROZEN_EYE_SWITCH_CHEST, {[]{return HasFireSource;}}), + LocationAccess(GANONS_CASTLE_MQ_FOREST_TRIAL_FREESTANDING_KEY, {[]{return HookshotOrBoomerang;}}), + }, {}); + + areaTable[GANONS_CASTLE_MQ_FIRE_TRIAL] = Area("Ganon's Castle MQ Fire Trial", "Ganons Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FireTrialClear, {[]{return CanUse(GORON_TUNIC) && CanUse(GOLDEN_GAUNTLETS) && CanUse(LIGHT_ARROWS) && (CanUse(LONGSHOT) || CanUse(HOVER_BOOTS));}}), + //Trick: CanUse(GORON_TUNIC) && CanUse(GOLDEN_GAUNTLETS) && CanUse(LIGHT_ARROWS) && (CanUse(LONGSHOT) || HoverBoots || (LogicFireTrialMQ && CanUse(HOOKSHOT))) + }, {}, {}); + + areaTable[GANONS_CASTLE_MQ_WATER_TRIAL] = Area("Ganon's Castle MQ Water Trial", "Ganons Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&WaterTrialClear, {[]{return BlueFire && IsAdult && CanUse(LIGHT_ARROWS) && SmallKeys(GANONS_CASTLE, 3);}}), + EventAccess(&BlueFireAccess, {[]{return BlueFireAccess || HasBottle;}}), + }, { + //Locations + LocationAccess(GANONS_CASTLE_MQ_WATER_TRIAL_CHEST, {[]{return BlueFire && (IsAdult || CanUse(STICKS) || KokiriSword || CanUseProjectile);}}), + }, {}); + + areaTable[GANONS_CASTLE_MQ_SHADOW_TRIAL] = Area("Ganon's Castle MQ Shadow Trial", "Ganons Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&ShadowTrialClear, {[]{return IsAdult && CanUse(LIGHT_ARROWS) && (LogicLensCastleMQ || CanUse(LENS_OF_TRUTH)) && (CanUse(HOVER_BOOTS) || (CanUse(HOOKSHOT) && HasFireSource));}}), + //Trick: IsAdult && CanUse(LIGHT_ARROWS) && (LogicLensCastleMQ || CanUse(LENS_OF_TRUTH)) && (HoverBoots || (Hookshot && (HasFireSource || LogicShadowTrialMQ))) + }, { + //Locations + LocationAccess(GANONS_CASTLE_MQ_SHADOW_TRIAL_BOMB_FLOWER_CHEST, {[]{return IsAdult && ((Bow && (CanUse(HOOKSHOT) || CanUse(HOVER_BOOTS))) || (CanUse(HOVER_BOOTS) && (LogicLensCastleMQ || CanUse(LENS_OF_TRUTH)) && (HasExplosives || GoronBracelet || CanUse(DINS_FIRE))));}}), + LocationAccess(GANONS_CASTLE_MQ_SHADOW_TRIAL_EYE_SWITCH_CHEST, {[]{return IsAdult && Bow && (LogicLensCastleMQ || CanUse(LENS_OF_TRUTH)) && (CanUse(HOVER_BOOTS) || (CanUse(HOOKSHOT) && HasFireSource));}}), + //Trick: IsAdult && Bow && (LogicLensCastleMQ || CanUse(LENS_OF_TRUTH)) && (HoverBoots || (Hookshot && (HasFireSource || LogicShadowTrialMQ))) + }, {}); + + areaTable[GANONS_CASTLE_MQ_SPIRIT_TRIAL] = Area("Ganon's Castle MQ Spirit Castle", "Ganons Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&SpiritTrialClear, {[]{return IsAdult && CanUse(LIGHT_ARROWS) && Hammer && HasBombchus && FireArrows && MirrorShield;}}), + EventAccess(&NutPot, {[]{return NutPot || (Hammer && HasBombchus && IsAdult && CanUse(FIRE_ARROWS) && MirrorShield);}}), + }, { + //Locations + LocationAccess(GANONS_CASTLE_MQ_SPIRIT_TRIAL_FIRST_CHEST, {[]{return IsAdult && Bow && Hammer;}}), + LocationAccess(GANONS_CASTLE_MQ_SPIRIT_TRIAL_INVISIBLE_CHEST, {[]{return IsAdult && Bow && Hammer && HasBombchus && (LogicLensCastleMQ || CanUse(LENS_OF_TRUTH));}}), + LocationAccess(GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_FRONT_LEFT_CHEST, {[]{return IsAdult && Hammer && HasBombchus && CanUse(FIRE_ARROWS) && CanUse(MIRROR_SHIELD);}}), + LocationAccess(GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_LEFT_CHEST, {[]{return IsAdult && Hammer && HasBombchus && CanUse(FIRE_ARROWS) && CanUse(MIRROR_SHIELD);}}), + LocationAccess(GANONS_CASTLE_MQ_SPIRIT_TRIAL_GOLDEN_GAUNTLETS_CHEST, {[]{return IsAdult && Hammer && HasBombchus && CanUse(FIRE_ARROWS) && CanUse(MIRROR_SHIELD);}}), + LocationAccess(GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_RIGHT_CHEST, {[]{return IsAdult && Hammer && HasBombchus && CanUse(FIRE_ARROWS) && CanUse(MIRROR_SHIELD);}}), + }, {}); + + areaTable[GANONS_CASTLE_MQ_LIGHT_TRIAL] = Area("Ganon's Castle MQ Light Trial", "Ganons Castle", GANONS_CASTLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&LightTrialClear, {[]{return IsAdult && CanUse(LIGHT_ARROWS) && SmallKeys(GANONS_CASTLE, 3) && (LogicLensCastleMQ || CanUse(LENS_OF_TRUTH)) && CanUse(HOOKSHOT);}}), + //Trick: IsAdult && CanUse(LIGHT_ARROWS) && SmallKeys(GANONS_CASTLE, 3) && (LogicLensCastleMQ || CanUse(LENS_OF_TRUTH)) && (Hookshot || LogicLightTrialMQ) + }, { + //Locations + LocationAccess(GANONS_CASTLE_MQ_LIGHT_TRIAL_LULLABY_CHEST, {[]{return CanPlay(ZeldasLullaby);}}), + }, {}); + } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_gerudo_training_grounds.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_gerudo_training_grounds.cpp new file mode 100644 index 000000000..41eca39a2 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_gerudo_training_grounds.cpp @@ -0,0 +1,199 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" +#include "../dungeon.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_GerudoTrainingGrounds() { + /*-------------------------- + | VANILLA/MQ DECIDER | + ---------------------------*/ + areaTable[GERUDO_TRAINING_GROUNDS_ENTRYWAY] = Area("Gerudo Training Grounds Entryway", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(GERUDO_TRAINING_GROUNDS_LOBBY, {[]{return Dungeon::GerudoTrainingGrounds.IsVanilla();}}), + Entrance(GERUDO_TRAINING_GROUNDS_MQ_LOBBY, {[]{return Dungeon::GerudoTrainingGrounds.IsMQ();}}), + Entrance(GERUDO_FORTRESS, {[]{return true;}}), + }); + + /*-------------------------- + | VANILLA DUNGEON | + ---------------------------*/ + if (Dungeon::GerudoTrainingGrounds.IsVanilla()) { + areaTable[GERUDO_TRAINING_GROUNDS_LOBBY] = Area("Gerudo Training Grounds Lobby", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GERUDO_TRAINING_GROUNDS_LOBBY_LEFT_CHEST, {[]{return CanUse(BOW) || CanUse(SLINGSHOT);}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_LOBBY_RIGHT_CHEST, {[]{return CanUse(BOW) || CanUse(SLINGSHOT);}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_STALFOS_CHEST, {[]{return IsAdult || KokiriSword;}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_BEAMOS_CHEST, {[]{return HasExplosives && (IsAdult || KokiriSword);}}), + }, { + //Exits + Entrance(GERUDO_TRAINING_GROUNDS_ENTRYWAY, {[]{return true;}}), + Entrance(GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_ROOM, {[]{return (IsAdult || KokiriSword) && (CanUse(HOOKSHOT) || LogicGtgWithoutHookshot);}}), + Entrance(GERUDO_TRAINING_GROUNDS_LAVA_ROOM, {[]{return Here(GERUDO_TRAINING_GROUNDS_LOBBY, []{return (IsAdult || KokiriSword) && HasExplosives;});}}), + Entrance(GERUDO_TRAINING_GROUNDS_CENTRAL_MAZE, {[]{return true;}}), + }); + + areaTable[GERUDO_TRAINING_GROUNDS_CENTRAL_MAZE] = Area("Gerudo Training Grounds Central Maze", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GERUDO_TRAINING_GROUNDS_HIDDEN_CEILING_CHEST, {[]{return SmallKeys(GERUDO_TRAINING_GROUNDS, 3) && (LogicLensGtg || CanUse(LENS_OF_TRUTH));}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE) && (LogicLensGtg || CanUse(LENS_OF_TRUTH));}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_MAZE_PATH_FIRST_CHEST, {[]{return SmallKeys(GERUDO_TRAINING_GROUNDS, 4);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE);}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_MAZE_PATH_SECOND_CHEST, {[]{return SmallKeys(GERUDO_TRAINING_GROUNDS, 6);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE);}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_MAZE_PATH_THIRD_CHEST, {[]{return SmallKeys(GERUDO_TRAINING_GROUNDS, 7);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE);}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_MAZE_PATH_FINAL_CHEST, {[]{return SmallKeys(GERUDO_TRAINING_GROUNDS, 9);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE);}}), + }, { + //Exits + Entrance(GERUDO_TRAINING_GROUNDS_CENTRAL_MAZE_RIGHT, {[]{return SmallKeys(GERUDO_TRAINING_GROUNDS, 9);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE);}}), + }); + + areaTable[GERUDO_TRAINING_GROUNDS_CENTRAL_MAZE_RIGHT] = Area("Gerudo Training Grounds Central Maze Right", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GERUDO_TRAINING_GROUNDS_MAZE_RIGHT_CENTRAL_CHEST, {[]{return true;}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_MAZE_RIGHT_SIDE_CHEST, {[]{return true;}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_FREESTANDING_KEY, {[]{return true;}}), + }, { + //Exits + Entrance(GERUDO_TRAINING_GROUNDS_HAMMER_ROOM, {[]{return CanUse(HOOKSHOT);}}), + Entrance(GERUDO_TRAINING_GROUNDS_LAVA_ROOM, {[]{return true;}}), + }); + + areaTable[GERUDO_TRAINING_GROUNDS_LAVA_ROOM] = Area("Gerudo Training Grounds Lava Room", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GERUDO_TRAINING_GROUNDS_UNDERWATER_SILVER_RUPEE_CHEST, {[]{return CanUse(HOOKSHOT) && CanPlay(SongOfTime) && IronBoots && WaterTimer >= 24;}}), + }, { + //Exits + Entrance(GERUDO_TRAINING_GROUNDS_CENTRAL_MAZE_RIGHT, {[]{return CanPlay(SongOfTime) || IsChild;}}), + Entrance(GERUDO_TRAINING_GROUNDS_HAMMER_ROOM, {[]{return CanUse(LONGSHOT) || (CanUse(HOVER_BOOTS) && CanUse(HOOKSHOT));}}), + }); + + areaTable[GERUDO_TRAINING_GROUNDS_HAMMER_ROOM] = Area("Gerudo Training Grounds Hammer Room", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GERUDO_TRAINING_GROUNDS_HAMMER_ROOM_CLEAR_CHEST, {[]{return true;}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_HAMMER_ROOM_SWITCH_CHEST, {[]{return CanUse(MEGATON_HAMMER) || (CanTakeDamage && LogicFlamingChests);}}), + }, { + //Exits + Entrance(GERUDO_TRAINING_GROUNDS_EYE_STATUE_LOWER, {[]{return CanUse(MEGATON_HAMMER) && Bow;}}), + Entrance(GERUDO_TRAINING_GROUNDS_LAVA_ROOM, {[]{return true;}}), + }); + + areaTable[GERUDO_TRAINING_GROUNDS_EYE_STATUE_LOWER] = Area("Gerudo Training Grounds Eye Statue Lower", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GERUDO_TRAINING_GROUNDS_EYE_STATUE_CHEST, {[]{return CanUse(BOW);}}), + }, { + //Exits + Entrance(GERUDO_TRAINING_GROUNDS_HAMMER_ROOM, {[]{return true;}}), + }); + + areaTable[GERUDO_TRAINING_GROUNDS_EYE_STATUE_UPPER] = Area("Gerudo Training Grounds Eye Statue Upper", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GERUDO_TRAINING_GROUNDS_NEAR_SCARECROW_CHEST, {[]{return CanUse(BOW);}}), + }, { + //Exits + Entrance(GERUDO_TRAINING_GROUNDS_EYE_STATUE_LOWER, {[]{return true;}}), + }); + + areaTable[GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_ROOM] = Area("Gerudo Training Grounds Heavy Block Room", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GERUDO_TRAINING_GROUNDS_BEFORE_HEAVY_BLOCK_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(GERUDO_TRAINING_GROUNDS_EYE_STATUE_UPPER, {[]{return (LogicLensGtg || CanUse(LENS_OF_TRUTH)) && (CanUse(HOOKSHOT) || (LogicGtgFakeWall && CanUse(HOVER_BOOTS)));}}), + Entrance(GERUDO_TRAINING_GROUNDS_LIKE_LIKE_ROOM, {[]{return (LogicLensGtg || CanUse(LENS_OF_TRUTH)) && (CanUse(HOOKSHOT) || (LogicGtgFakeWall && CanUse(HOVER_BOOTS))) && CanUse(SILVER_GAUNTLETS);}}), + }); + + areaTable[GERUDO_TRAINING_GROUNDS_LIKE_LIKE_ROOM] = Area("Gerudo Training Grounds Like Like Room", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_FIRST_CHEST, {[]{return true;}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_SECOND_CHEST, {[]{return true;}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_THIRD_CHEST, {[]{return true;}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_HEAVY_BLOCK_FOURTH_CHEST, {[]{return true;}}), + }, {}); + } + + /*--------------------------- + | MASTER QUEST DUNGEON | + ---------------------------*/ + if (Dungeon::GerudoTrainingGrounds.IsMQ()) { + areaTable[GERUDO_TRAINING_GROUNDS_MQ_LOBBY] = Area("Gerudo Training Grounds MQ Lobby", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_LOBBY_LEFT_CHEST, {[]{return true;}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_LOBBY_RIGHT_CHEST, {[]{return true;}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_HIDDEN_CEILING_CHEST, {[]{return LogicLensGtgMQ || CanUse(LENS_OF_TRUTH);}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_FIRST_CHEST, {[]{return true;}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_SECOND_CHEST, {[]{return true;}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_MAZE_PATH_THIRD_CHEST, {[]{return SmallKeys(GERUDO_TRAINING_GROUNDS, 1);}}), + }, { + //Exits + Entrance(GERUDO_TRAINING_GROUNDS_ENTRYWAY, {[]{return true;}}), + Entrance(GERUDO_TRAINING_GROUNDS_MQ_LEFT_SIDE, {[]{return Here(GERUDO_TRAINING_GROUNDS_MQ_LOBBY, []{return HasFireSource;});}}), + Entrance(GERUDO_TRAINING_GROUNDS_MQ_RIGHT_SIDE, {[]{return Here(GERUDO_TRAINING_GROUNDS_MQ_LOBBY, []{return (IsAdult && CanUse(BOW)) || (IsChild && CanUse(SLINGSHOT));});}}), + }); + + areaTable[GERUDO_TRAINING_GROUNDS_MQ_RIGHT_SIDE] = Area("Gerudo Training Grounds MQ Right Side", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, { + //Events + //EventAccess(&WallFairy, {[]{return WallFairy || (IsAdult && CanUse(BOW));}}), + }, { + //Locations + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_DINOLFOS_CHEST, {[]{return IsAdult;}}), + }, { + //Exits + Entrance(GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER, {[]{return (Bow || CanUse(LONGSHOT)) && CanUse(HOVER_BOOTS) && IsAdult;}}), + }); + + areaTable[GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER] = Area("Gerudo Training Grounds MQ Underwater", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER_SILVER_RUPEE_CHEST, {[]{return HasFireSource && IsAdult && CanUse(IRON_BOOTS) && WaterTimer >= 24 && CanTakeDamage;}}), + }, {}); + + areaTable[GERUDO_TRAINING_GROUNDS_MQ_LEFT_SIDE] = Area("Gerudo Training Grounds MQ Left Side", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_FIRST_IRON_KNUCKLE_CHEST, {[]{return IsAdult || KokiriSword || HasExplosives;}}), + }, { + //Exits + Entrance(GERUDO_TRAINING_GROUNDS_MQ_STALFOS_ROOM, {[]{return IsAdult && CanUse(LONGSHOT);}}), + //Trick: (IsAdult && CanUse(LONGSHOT)) || LogicGtgMQWithoutHookshot || (LogicGtgMQWithHookshot && IsAdult && CanUse(HOOKSHOT)) + }); + + areaTable[GERUDO_TRAINING_GROUNDS_MQ_STALFOS_ROOM] = Area("Gerudo Training Grounds MQ Stalfos Room", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&BlueFireAccess, {[]{return BlueFireAccess || HasBottle;}}), + }, { + //Locations + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_BEFORE_HEAVY_BLOCK_CHEST, {[]{return IsAdult;}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_HEAVY_BLOCK_CHEST, {[]{return CanUse(SILVER_GAUNTLETS);}}), + }, { + //Exits + Entrance(GERUDO_TRAINING_GROUNDS_MQ_BACK_AREAS, {[]{return IsAdult && (LogicLensGtgMQ || CanUse(LENS_OF_TRUTH)) && BlueFire && CanPlay(SongOfTime);}}), + //Trick: IsAdult && (LogicLensGtgMQ || CanUse(LENS_OF_TRUTH)) && BlueFire && (CanPlay(SongOfTime) || (LogicGtgFakeWall && IsAdult && CanUse(HOVER_BOOTS))) + }); + + areaTable[GERUDO_TRAINING_GROUNDS_MQ_BACK_AREAS] = Area("Gerudo Training Grounds MQ Back Areas", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_EYE_STATUE_CHEST, {[]{return Bow;}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_SECOND_IRON_KNUCKLE_CHEST, {[]{return true;}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_FLAME_CIRCLE_CHEST, {[]{return CanUse(HOOKSHOT) || Bow || HasExplosives;}}), + }, { + //Exits + Entrance(GERUDO_TRAINING_GROUNDS_MQ_CENTRAL_MAZE_RIGHT, {[]{return Hammer;}}), + Entrance(GERUDO_TRAINING_GROUNDS_MQ_RIGHT_SIDE, {[]{return CanUse(LONGSHOT);}}), + }); + + areaTable[GERUDO_TRAINING_GROUNDS_MQ_CENTRAL_MAZE_RIGHT] = Area("Gerudo Training Grounds MQ Central Maze Right", "Gerudo Training Grounds", GERUDO_TRAINING_GROUNDS, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_MAZE_RIGHT_CENTRAL_CHEST, {[]{return true;}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_MAZE_RIGHT_SIDE_CHEST, {[]{return true;}}), + LocationAccess(GERUDO_TRAINING_GROUNDS_MQ_ICE_ARROWS_CHEST, {[]{return SmallKeys(GERUDO_TRAINING_GROUNDS, 3);}}), + }, { + //Exits + Entrance(GERUDO_TRAINING_GROUNDS_MQ_UNDERWATER, {[]{return IsAdult && (CanUse(LONGSHOT) || (CanUse(HOOKSHOT) && Bow));}}), + Entrance(GERUDO_TRAINING_GROUNDS_MQ_RIGHT_SIDE, {[]{return IsAdult && CanUse(HOOKSHOT);}}), + }); + } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_gerudo_valley.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_gerudo_valley.cpp new file mode 100644 index 000000000..7f99b05ff --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_gerudo_valley.cpp @@ -0,0 +1,234 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_GerudoValley() { + areaTable[GERUDO_VALLEY] = Area("Gerudo Valley", "Gerudo Valley", GERUDO_VALLEY, DAY_NIGHT_CYCLE, { + //Events + EventAccess(&BugRock, {[]{return BugRock || IsChild;}}), + }, { + //Locations + LocationAccess(GV_GS_SMALL_BRIDGE, {[]{return IsChild && HookshotOrBoomerang && AtNight && CanGetNightTimeGS;}, + /*Glitched*/[]{return IsChild && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE) && AtNight && CanGetNightTimeGS;}}), + }, { + //Exits + Entrance(HYRULE_FIELD, {[]{return true;}}), + Entrance(GV_UPPER_STREAM, {[]{return true;}}), + Entrance(GV_CRATE_LEDGE, {[]{return IsChild || CanUse(LONGSHOT);}}), + Entrance(GV_GROTTO_LEDGE, {[]{return true;}}), + Entrance(GV_FORTRESS_SIDE, {[]{return (IsAdult && (CanRideEpona || CanUse(LONGSHOT) || GerudoFortress.Is(GERUDOFORTRESS_OPEN) || CarpenterRescue)) || (IsChild && CanUse(HOOKSHOT));}, + /*Glitched*/[]{return (HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE)) || (IsChild && CanDoGlitch(GlitchType::SeamWalk, GlitchDifficulty::HERO)) || (IsAdult && (CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::HammerSlide, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::ADVANCED) || + (CanUse(HOVER_BOOTS) && (CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::INTERMEDIATE) || (CanSurviveDamage && (Bombs || HasBombchus) && CanDoGlitch(GlitchType::SuperSlide, GlitchDifficulty::NOVICE)) || (Bombs && CanDoGlitch(GlitchType::SuperSlide, GlitchDifficulty::ADVANCED))))));}}), + }); + + areaTable[GV_UPPER_STREAM] = Area("GV Upper Stream", "Gerudo Valley", GERUDO_VALLEY, DAY_NIGHT_CYCLE, { + //Events + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || CanSummonGossipFairy;}}), + EventAccess(&BeanPlantFairy, {[]{return BeanPlantFairy || (CanPlantBean(GV_UPPER_STREAM) && CanPlay(SongOfStorms));}}), + }, { + //Locations + LocationAccess(GV_WATERFALL_FREESTANDING_POH, {[]{return true;}}), + LocationAccess(GV_GS_BEAN_PATCH, {[]{return CanPlantBugs && CanChildAttack;}}), + LocationAccess(GV_COW, {[]{return IsChild && CanPlay(EponasSong);}, + /*Glitched*/[]{return IsChild && EponasSong && (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED)));}}), + LocationAccess(GV_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(GV_LOWER_STREAM, {[]{return true;}}), + }); + + areaTable[GV_LOWER_STREAM] = Area("GV Lower Stream", "Gerudo Valley", GERUDO_VALLEY, DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(LAKE_HYLIA, {[]{return true;}}), + }); + + areaTable[GV_GROTTO_LEDGE] = Area("GV Grotto Ledge", "Gerudo Valley", GERUDO_VALLEY, DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(GV_LOWER_STREAM, {[]{return true;}}), + Entrance(GV_OCTOROK_GROTTO, {[]{return CanUse(SILVER_GAUNTLETS);}}), + Entrance(GV_CRATE_LEDGE, {[]{return CanUse(LONGSHOT);}}), + }); + + areaTable[GV_CRATE_LEDGE] = Area("GV Crate Ledge", "Gerudo Valley", GERUDO_VALLEY, DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GV_CRATE_FREESTANDING_POH, {[]{return true;}}), + }, { + //Exits + Entrance(GV_LOWER_STREAM, {[]{return true;}}), + }); + + areaTable[GV_FORTRESS_SIDE] = Area("GV Fortress Side", "Gerudo Valley", GERUDO_VALLEY, DAY_NIGHT_CYCLE, { + //Events + EventAccess(&BrokenSwordAccess, {[]{return IsAdult && (PoachersSawAccess || PoachersSaw);}}), + }, { + //Locations + LocationAccess(GV_CHEST, {[]{return IsAdult && (CanUse(MEGATON_HAMMER) || LogicGVHammerChest);}, + /*Glitched*/[]{return IsAdult && (CanDoGlitch(GlitchType::LedgeCancel, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) || (CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::NOVICE) && (CanTakeDamageTwice || CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED))));}}), + LocationAccess(GV_TRADE_SAW, {[]{return IsAdult && PoachersSaw;}}), + LocationAccess(GV_GS_BEHIND_TENT, {[]{return IsAdult && HookshotOrBoomerang && AtNight && CanGetNightTimeGS;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && IsAdult && AtNight && CanGetNightTimeGS;}}), + LocationAccess(GV_GS_PILLAR, {[]{return IsAdult && HookshotOrBoomerang && AtNight && CanGetNightTimeGS;}}), + }, { + //Exits + Entrance(GERUDO_FORTRESS, {[]{return true;}}), + Entrance(GV_UPPER_STREAM, {[]{return true;}}), + Entrance(GERUDO_VALLEY, {[]{return IsChild || CanRideEpona || CanUse(LONGSHOT) || GerudoFortress.Is(GERUDOFORTRESS_OPEN) || CarpenterRescue;}, + /*Glitched*/[]{return (HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE)) || CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::HammerSlide, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::ADVANCED) || + (CanUse(HOVER_BOOTS) && (CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::INTERMEDIATE) || (CanSurviveDamage && (Bombs || HasBombchus) && CanDoGlitch(GlitchType::SuperSlide, GlitchDifficulty::NOVICE)) || (Bombs && CanDoGlitch(GlitchType::SuperSlide, GlitchDifficulty::ADVANCED))));}}), + Entrance(GV_CARPENTER_TENT, {[]{return IsAdult;}, + /*Glitched*/[]{return GlitchGVTentAsChild.Value();}}), + Entrance(GV_STORMS_GROTTO, {[]{return IsAdult && CanOpenStormGrotto;}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && IsAdult && SongOfStorms && (ShardOfAgony || LogicGrottosWithoutAgony);}}), + }); + + areaTable[GV_CARPENTER_TENT] = Area("GV Carpenter Tent", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(GV_FORTRESS_SIDE, {[]{return true;}}), + }); + + areaTable[GV_OCTOROK_GROTTO] = Area("GV Octorok Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(GV_GROTTO_LEDGE, {[]{return true;}}), + }); + + areaTable[GV_STORMS_GROTTO] = Area("GV Storms Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GV_DEKU_SCRUB_GROTTO_REAR, {[]{return CanStunDeku;}}), + LocationAccess(GV_DEKU_SCRUB_GROTTO_FRONT, {[]{return CanStunDeku;}}), + }, { + //Exits + Entrance(GV_FORTRESS_SIDE, {[]{return true;}}), + }); + + areaTable[GERUDO_FORTRESS] = Area("Gerudo Fortress", "Gerudo Fortress", GERUDO_FORTRESS, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&CarpenterRescue, {[]{return CanFinishGerudoFortress;}}), + EventAccess(&GF_GateOpen, {[]{return IsAdult && GerudoToken;}}), + EventAccess(&GtG_GateOpen, {[]{return GtG_GateOpen || (IsAdult && GerudoToken);}}), + }, { + //Locations + LocationAccess(GF_CHEST, {[]{return CanUse(HOVER_BOOTS) || (IsAdult && CanUse(SCARECROW)) || CanUse(LONGSHOT);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE) || (Bombs && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE))) && (GerudoToken || CanUse(BOW) || CanUse(HOOKSHOT) || CanUse(HOVER_BOOTS) || LogicGerudoKitchen);}}), + LocationAccess(GF_HBA_1000_POINTS, {[]{return GerudoToken && CanRideEpona && Bow && AtDay;}}), + LocationAccess(GF_HBA_1500_POINTS, {[]{return GerudoToken && CanRideEpona && Bow && AtDay;}}), + LocationAccess(GF_NORTH_F1_CARPENTER, {[]{return IsAdult || KokiriSword || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE);}}), + LocationAccess(GF_NORTH_F2_CARPENTER, {[]{return (IsAdult || KokiriSword || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)) && (GerudoToken || CanUse(BOW) || CanUse(HOOKSHOT) || CanUse(HOVER_BOOTS) || LogicGerudoKitchen);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE) && (GerudoToken || CanUse(BOW) || CanUse(HOOKSHOT) || CanUse(HOVER_BOOTS) || LogicGerudoKitchen);}}), + LocationAccess(GF_SOUTH_F1_CARPENTER, {[]{return IsAdult || KokiriSword || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE);}}), + LocationAccess(GF_SOUTH_F2_CARPENTER, {[]{return IsAdult || KokiriSword || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE);}}), + LocationAccess(GF_GERUDO_MEMBERSHIP_CARD, {[]{return CanFinishGerudoFortress;}}), + LocationAccess(GF_GS_ARCHERY_RANGE, {[]{return IsAdult && HookshotOrBoomerang && GerudoToken && AtNight && CanGetNightTimeGS;}, + /*Glitched*/[]{return IsAdult && HookshotOrBoomerang && GlitchGFGuardSneak && AtNight && CanGetNightTimeGS;}}), + LocationAccess(GF_GS_TOP_FLOOR, {[]{return IsAdult && AtNight && (GerudoToken || CanUse(BOW) || CanUse(HOOKSHOT) || CanUse(HOVER_BOOTS) || LogicGerudoKitchen) && CanGetNightTimeGS;}}), + }, { + //Exits + Entrance(GV_FORTRESS_SIDE, {[]{return true;}}), + Entrance(GF_OUTSIDE_GATE, {[]{return GF_GateOpen;}, + /*Glitched*/[]{return (IsChild && CanDoGlitch(GlitchType::SeamWalk, GlitchDifficulty::ADVANCED)) || ((IsChild || ((CanUse(HOOKSHOT) || CanUse(BOW) || CanUse(BOOMERANG)) && GlitchGFGuardSneak)) && ((CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE) && CanDoGlitch(GlitchType::SeamWalk, GlitchDifficulty::NOVICE)) || + CanDoGlitch(GlitchType::SeamWalk, GlitchDifficulty::INTERMEDIATE)) && (CanUse(STICKS) || (BiggoronSword && IsAdult) || CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::INTERMEDIATE)));}}), + Entrance(GERUDO_TRAINING_GROUNDS_ENTRYWAY, {[]{return GtG_GateOpen && (IsAdult || ShuffleDungeonEntrances);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::LedgeClip, GlitchDifficulty::INTERMEDIATE) && (HoverBoots || CanDoGlitch(GlitchType::LedgeClip, GlitchDifficulty::ADVANCED))) || ((IsChild || ((CanUse(HOOKSHOT) || CanUse(BOW) || CanUse(BOOMERANG)) && GlitchGFGuardSneak)) && ((CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE) && + CanDoGlitch(GlitchType::SeamWalk, GlitchDifficulty::NOVICE)) || CanDoGlitch(GlitchType::SeamWalk, GlitchDifficulty::INTERMEDIATE)) && (CanUse(STICKS) || (BiggoronSword && IsAdult) || CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::INTERMEDIATE)));}}), + Entrance(GF_STORMS_GROTTO, {[]{return IsAdult && CanOpenStormGrotto;}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && IsAdult && SongOfStorms && (ShardOfAgony || LogicGrottosWithoutAgony);}}), + }); + + areaTable[GF_OUTSIDE_GATE] = Area("GF Outside Gate", "Gerudo Fortress", NONE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&GF_GateOpen, {[]{return IsAdult && GerudoToken && (ShuffleGerudoToken || ShuffleOverworldEntrances /*|| ShuffleSpecialIndoorEntrances*/);}}), + }, {}, { + //Exits + Entrance(GERUDO_FORTRESS, {[]{return (IsAdult && (Hookshot || !ShuffleOverworldEntrances)) || GF_GateOpen;}}), + Entrance(WASTELAND_NEAR_FORTRESS, {[]{return true;}}), + }); + + areaTable[GF_STORMS_GROTTO] = Area("GF Storms Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FreeFairies, {[]{return true;}}), + }, {}, { + //Exits + Entrance(GERUDO_FORTRESS, {[]{return true;}}), + }); + + areaTable[WASTELAND_NEAR_FORTRESS] = Area("Wasteland Near Fortress", "Haunted Wasteland", HAUNTED_WASTELAND, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(GF_OUTSIDE_GATE, {[]{return true;}}), + Entrance(HAUNTED_WASTELAND, {[]{return CanUse(HOVER_BOOTS) || CanUse(LONGSHOT);}, + /*Glitched*/[]{return ((Bombs || HasBombchus) && CanSurviveDamage && CanDoGlitch(GlitchType::SuperSlide, GlitchDifficulty::NOVICE)) || (CanUse(MEGATON_HAMMER) && CanShield && CanDoGlitch(GlitchType::SuperSlide, GlitchDifficulty::INTERMEDIATE)) || + (Bombs && CanDoGlitch(GlitchType::SuperSlide, GlitchDifficulty::ADVANCED)) || (Bombs && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE)) || GlitchItemlessWasteland;}}), + }); + + areaTable[HAUNTED_WASTELAND] = Area("Haunted Wasteland", "Haunted Wasteland", HAUNTED_WASTELAND, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return true;}}), + EventAccess(&NutPot, {[]{return true;}}), + }, { + //Locations + LocationAccess(WASTELAND_CHEST, {[]{return HasFireSource;}, + /*Glitched*/[]{return CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::INTERMEDIATE);}}), + LocationAccess(WASTELAND_BOMBCHU_SALESMAN, {[]{return AdultsWallet && (IsAdult || Sticks || KokiriSword);}, + /*Glitched*/[]{return AdultsWallet && CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE);}}), + LocationAccess(WASTELAND_GS, {[]{return HookshotOrBoomerang;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE);}}), + }, { + //Exits + Entrance(WASTELAND_NEAR_COLOSSUS, {[]{return LogicLensWasteland || CanUse(LENS_OF_TRUTH);}}), + Entrance(WASTELAND_NEAR_FORTRESS, {[]{return CanUse(HOVER_BOOTS) || CanUse(LONGSHOT);}, + /*Glitched*/[]{return ((Bombs || HasBombchus) && CanSurviveDamage && CanDoGlitch(GlitchType::SuperSlide, GlitchDifficulty::NOVICE)) || (CanUse(MEGATON_HAMMER) && CanShield && CanDoGlitch(GlitchType::SuperSlide, GlitchDifficulty::INTERMEDIATE)) || + (Bombs && CanDoGlitch(GlitchType::SuperSlide, GlitchDifficulty::ADVANCED)) || (HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE)) || GlitchItemlessWasteland;}}), + }); + + areaTable[WASTELAND_NEAR_COLOSSUS] = Area("Wasteland Near Colossus", "Haunted Wasteland", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(DESERT_COLOSSUS, {[]{return true;}}), + Entrance(HAUNTED_WASTELAND, {[]{return LogicReverseWasteland || false;}}), + }); + + areaTable[DESERT_COLOSSUS] = Area("Desert Colossus", "Desert Colossus", DESERT_COLOSSUS, DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPond, {[]{return FairyPond || CanPlay(SongOfStorms);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && Bombs && CanTakeDamage && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && SongOfStorms;}}), + EventAccess(&BugRock, {[]{return true;}}), + }, { + //Locations + LocationAccess(COLOSSUS_FREESTANDING_POH, {[]{return IsAdult && CanPlantBean(DESERT_COLOSSUS);}, + /*Glitched*/[]{return (HoverBoots && CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::ADVANCED)) || (((IsChild && (ChildCanAccess(SPIRIT_TEMPLE_OUTDOOR_HANDS) || ChildCanAccess(SPIRIT_TEMPLE_MQ_SILVER_GAUNTLETS_HAND) || ChildCanAccess(SPIRIT_TEMPLE_MQ_MIRROR_SHIELD_HAND))) || + (IsAdult && (AdultCanAccess(SPIRIT_TEMPLE_OUTDOOR_HANDS) || AdultCanAccess(SPIRIT_TEMPLE_MQ_SILVER_GAUNTLETS_HAND) || AdultCanAccess(SPIRIT_TEMPLE_MQ_MIRROR_SHIELD_HAND)))) && (CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::ADVANCED) || CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::INTERMEDIATE)));}}), + LocationAccess(SHEIK_AT_COLOSSUS, {[]{return true;}}), + LocationAccess(COLOSSUS_GS_BEAN_PATCH, {[]{return CanPlantBugs && CanChildAttack;}}), + LocationAccess(COLOSSUS_GS_TREE, {[]{return IsAdult && HookshotOrBoomerang && AtNight && CanGetNightTimeGS;}}), + LocationAccess(COLOSSUS_GS_HILL, {[]{return IsAdult && AtNight && (CanPlantBean(DESERT_COLOSSUS) || CanUse(LONGSHOT) || (LogicColossusGS && CanUse(HOOKSHOT))) && CanGetNightTimeGS;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::SeamWalk, GlitchDifficulty::EXPERT) && CanShield && IsAdult && AtNight && CanGetNightTimeGS;}}), + LocationAccess(COLOSSUS_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(COLOSSUS_GREAT_FAIRY_FOUNTAIN, {[]{return HasExplosives;}}), + Entrance(SPIRIT_TEMPLE_ENTRYWAY, {[]{return true;}}), + Entrance(WASTELAND_NEAR_COLOSSUS, {[]{return true;}}), + Entrance(COLOSSUS_GROTTO, {[]{return CanUse(SILVER_GAUNTLETS);}}), + }); + + areaTable[COLOSSUS_GREAT_FAIRY_FOUNTAIN] = Area("Colossus Great Fairy Fountain", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(COLOSSUS_GREAT_FAIRY_REWARD, {[]{return CanPlay(ZeldasLullaby);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && Bombs && CanTakeDamage && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && ZeldasLullaby;}}), + }, { + //Exits + Entrance(DESERT_COLOSSUS, {[]{return true;}}), + }); + + areaTable[COLOSSUS_GROTTO] = Area("Colossus Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(COLOSSUS_DEKU_SCRUB_GROTTO_REAR, {[]{return CanStunDeku;}}), + LocationAccess(COLOSSUS_DEKU_SCRUB_GROTTO_FRONT, {[]{return CanStunDeku;}}), + }, { + //Exits + Entrance(DESERT_COLOSSUS, {[]{return true;}}), + }); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_hyrule_field.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_hyrule_field.cpp new file mode 100644 index 000000000..c1ac29d54 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_hyrule_field.cpp @@ -0,0 +1,267 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_HyruleField() { + areaTable[HYRULE_FIELD] = Area("Hyrule Field", "Hyrule Field", HYRULE_FIELD, DAY_NIGHT_CYCLE, { + //Events + EventAccess(&BigPoeKill, {[]{return CanUse(BOW) && CanRideEpona && HasBottle;}}), + }, { + //Locations + LocationAccess(HF_OCARINA_OF_TIME_ITEM, {[]{return IsChild && HasAllStones;}}), + LocationAccess(SONG_FROM_OCARINA_OF_TIME, {[]{return IsChild && HasAllStones;}}), + }, { + //Exits + Entrance(LW_BRIDGE, {[]{return true;}}), + Entrance(LAKE_HYLIA, {[]{return true;}}), + Entrance(GERUDO_VALLEY, {[]{return true;}}), + Entrance(MARKET_ENTRANCE, {[]{return true;}}), + Entrance(KAKARIKO_VILLAGE, {[]{return true;}}), + Entrance(ZR_FRONT, {[]{return true;}}), + Entrance(LON_LON_RANCH, {[]{return true;}}), + Entrance(HF_SOUTHEAST_GROTTO, {[]{return Here(HYRULE_FIELD, []{return CanBlastOrSmash;});}, + /*Glitched*/[]{return Here(HYRULE_FIELD, []{return CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);});}}), + Entrance(HF_OPEN_GROTTO, {[]{return true;}}), + Entrance(HF_INSIDE_FENCE_GROTTO, {[]{return CanOpenBombGrotto;}, + /*Glitched*/[]{return Sticks && IsChild && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);}}), + Entrance(HF_COW_GROTTO, {[]{return (CanUse(MEGATON_HAMMER) || IsChild) && CanOpenBombGrotto;}, + /*Glitched*/[]{return (CanUse(STICKS) && (ShardOfAgony || LogicGrottosWithoutAgony) && (IsChild || (CanOpenBombGrotto && (CanTakeDamageTwice || CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)))) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::NOVICE));}}), + Entrance(HF_NEAR_MARKET_GROTTO, {[]{return Here(HYRULE_FIELD, []{return CanBlastOrSmash;});}, + /*Glitched*/[]{return Here(HYRULE_FIELD, []{return CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);});}}), + Entrance(HF_FAIRY_GROTTO, {[]{return Here(HYRULE_FIELD, []{return CanBlastOrSmash;});}, + /*Glitched*/[]{return Here(HYRULE_FIELD, []{return CanUse(STICKS) && ((IsChild && CanTakeDamage && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::EXPERT)) || (IsAdult && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)));});}}), + Entrance(HF_NEAR_KAK_GROTTO, {[]{return CanOpenBombGrotto;}, + /*Glitched*/[]{return Sticks && IsChild && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);}}), + Entrance(HF_TEKTITE_GROTTO, {[]{return CanOpenBombGrotto;}, + /*Glitched*/[]{return Sticks && IsChild && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);}}), + }); + + areaTable[HF_SOUTHEAST_GROTTO] = Area("HF Southeast Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, { + //Locations + LocationAccess(HF_SOUTHEAST_GROTTO_CHEST, {[]{return true;}}), + LocationAccess(HF_SOUTHEAST_GROTTO_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(HYRULE_FIELD, {[]{return true;}}), + }); + + areaTable[HF_OPEN_GROTTO] = Area("HF Open Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, { + //Locations + LocationAccess(HF_OPEN_GROTTO_CHEST, {[]{return true;}}), + LocationAccess(HF_OPEN_GROTTO_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(HYRULE_FIELD, {[]{return true;}}), + }); + + areaTable[HF_INSIDE_FENCE_GROTTO] = Area("HF Inside Fence Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(HF_DEKU_SCRUB_GROTTO, {[]{return CanStunDeku;}}), + }, { + //Exits + Entrance(HYRULE_FIELD, {[]{return true;}}), + }); + + areaTable[HF_COW_GROTTO] = Area("HF Cow Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, { + //Locations + LocationAccess(HF_GS_COW_GROTTO, {[]{return HasFireSource && HookshotOrBoomerang;}, + /*Glitched*/[]{return (CanUse(STICKS) && Bombs && CanSurviveDamage && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::NOVICE)) && HookshotOrBoomerang;}}), + LocationAccess(HF_COW_GROTTO_COW, {[]{return HasFireSource && CanPlay(EponasSong);}, + /*Glitched*/[]{return ((CanUse(STICKS) && Bombs && CanSurviveDamage && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::NOVICE)) || HasFireSource) && + (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && Bombs && (CanSurviveDamage || (NumBottles >= 2 && Fairy)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED)) || Ocarina) && EponasSong;}}), + LocationAccess(HF_COW_GROTTO_GOSSIP_STONE, {[]{return HasFireSource;}, + /*Glitched*/[]{return CanUse(STICKS) && Bombs && CanSurviveDamage && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::NOVICE);}}), + }, { + //Exits + Entrance(HYRULE_FIELD, {[]{return true;}}), + }); + + areaTable[HF_NEAR_MARKET_GROTTO] = Area("HF Near Market Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, { + //Locations + LocationAccess(HF_NEAR_MARKET_GROTTO_CHEST, {[]{return true;}}), + LocationAccess(HF_NEAR_MARKET_GROTTO_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(HYRULE_FIELD, {[]{return true;}}), + }); + + areaTable[HF_FAIRY_GROTTO] = Area("HF Fairy Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FreeFairies, {[]{return true;}}), + }, {}, { + //Exits + Entrance(HYRULE_FIELD, {[]{return true;}}), + }); + + areaTable[HF_NEAR_KAK_GROTTO] = Area("HF Near Kak Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(HF_GS_NEAR_KAK_GROTTO, {[]{return HookshotOrBoomerang;}}), + }, { + //Exits + Entrance(HYRULE_FIELD, {[]{return true;}}), + }); + + areaTable[HF_TEKTITE_GROTTO] = Area("HF Tektite Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(HF_TEKTITE_GROTTO_FREESTANDING_POH, {[]{return ProgressiveScale >= 2 || CanUse(IRON_BOOTS);}}), + }, { + //Exits + Entrance(HYRULE_FIELD, {[]{return true;}}), + }); + + areaTable[LAKE_HYLIA] = Area("Lake Hylia", "Lake Hylia", LAKE_HYLIA, DAY_NIGHT_CYCLE, { + //Events + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || CanSummonGossipFairy;}}), + EventAccess(&BeanPlantFairy, {[]{return BeanPlantFairy || (CanPlantBean(LAKE_HYLIA) && CanPlay(SongOfStorms));}}), + EventAccess(&ButterflyFairy, {[]{return ButterflyFairy || CanUse(STICKS);}}), + EventAccess(&BugShrub, {[]{return BugShrub || (IsChild && CanCutShrubs);}}), + EventAccess(&ChildScarecrow, {[]{return ChildScarecrow || (IsChild && Ocarina);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && (KokiriSword || Sticks || Bombs || HasBombchus || Boomerang || Slingshot || CanUse(MEGATON_HAMMER)) && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::NOVICE))) && IsChild;}}), + EventAccess(&AdultScarecrow, {[]{return AdultScarecrow || (IsAdult && Ocarina);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::NOVICE))) && IsAdult;}}), + }, { + //Locations + LocationAccess(LH_UNDERWATER_ITEM, {[]{return IsChild && CanDive;}}), + LocationAccess(LH_SUN, {[]{return IsAdult && WaterTempleClear && CanUse(BOW);}}), + LocationAccess(LH_FREESTANDING_POH, {[]{return IsAdult && (CanUse(SCARECROW) || CanPlantBean(LAKE_HYLIA));}, + /*Glitched*/[]{return (IsAdult && CanUse(HOOKSHOT) && ScarecrowSong && (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::NOVICE)))) || CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE);}}), + LocationAccess(LH_GS_BEAN_PATCH, {[]{return CanPlantBugs && CanChildAttack;}}), + LocationAccess(LH_GS_LAB_WALL, {[]{return IsChild && (HookshotOrBoomerang || (LogicLabWallGS && (Sticks || KokiriSword || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)))) && AtNight && CanGetNightTimeGS;}}), + LocationAccess(LH_GS_SMALL_ISLAND, {[]{return IsChild && CanChildAttack && AtNight && CanGetNightTimeGS;}}), + LocationAccess(LH_GS_TREE, {[]{return IsAdult && CanUse(LONGSHOT) && AtNight && CanGetNightTimeGS;}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::HookshotJump_Bonk, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::NOVICE)) && AtNight && CanGetNightTimeGS;}}), + LocationAccess(LH_LAB_GOSSIP_STONE, {[]{return true;}}), + LocationAccess(LH_GOSSIP_STONE_SOUTHEAST, {[]{return true;}}), + LocationAccess(LH_GOSSIP_STONE_SOUTHWEST, {[]{return true;}}), + }, { + //Exits + Entrance(HYRULE_FIELD, {[]{return true;}}), + Entrance(ZORAS_DOMAIN, {[]{return IsChild && (CanDive || CanUse(IRON_BOOTS));}, + /*Glitched*/[]{return IsChild && (CanDoGlitch(GlitchType::TripleSlashClip, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::NaviDive_Stick, GlitchDifficulty::INTERMEDIATE) || + (Bugs && CanUse(HOVER_BOOTS) && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::INTERMEDIATE)) || (CanUse(FARORES_WIND) && (FaroresWindAnywhere || (CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE) && (HasBottle || (IsAdult && (HasBoots || ClaimCheck)) || (IsChild && WeirdEgg)))) && + ((CanUse(NAYRUS_LOVE) && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::NOVICE)) || (CanUseMagicArrow && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::ADVANCED)))));}}), + Entrance(LH_OWL_FLIGHT, {[]{return IsChild;}}), + Entrance(LH_FISHING_ISLAND, {[]{return IsChild || CanUse(SCARECROW) || CanPlantBean(LAKE_HYLIA) || WaterTempleClear;}, + /*Glitched*/[]{return (CanUse(HOOKSHOT) && ScarecrowSong && (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::NOVICE)))) || CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE);}}), + Entrance(LH_LAB, {[]{return true;}}), + Entrance(WATER_TEMPLE_ENTRYWAY, {[]{return CanUse(HOOKSHOT) && (CanUse(IRON_BOOTS) || (IsAdult && CanUse(LONGSHOT) && ProgressiveScale >= 2));}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::LedgeClip, GlitchDifficulty::ADVANCED);}}), + Entrance(LH_GROTTO, {[]{return true;}}), + }); + + areaTable[LH_FISHING_ISLAND] = Area("LH Fishing Island", "Lake Hylia", LAKE_HYLIA, DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(LAKE_HYLIA, {[]{return true;}}), + Entrance(LH_FISHING_HOLE, {[]{return true;}}), + }); + + areaTable[LH_OWL_FLIGHT] = Area("LH Owl Flight", "Lake Hylia", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(HYRULE_FIELD, {[]{return true;}}), + }); + + areaTable[LH_LAB] = Area("LH Lab", "", NONE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&EyedropsAccess, {[]{return EyedropsAccess || (IsAdult && (EyeballFrogAccess || (EyeballFrog && DisableTradeRevert)));}}), + }, { + //Locations + LocationAccess(LH_LAB_DIVE, {[]{return ProgressiveScale >= 2 || (LogicLabDiving && CanUse(IRON_BOOTS) && CanUse(HOOKSHOT));}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::TripleSlashClip, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanUse(HOVER_BOOTS) && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::INTERMEDIATE)) || + (CanUse(FARORES_WIND) && (FaroresWindAnywhere || (CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE) && (HasBottle || (IsAdult && (HasBoots || ClaimCheck)) || (IsChild && WeirdEgg)))) && CanUse(NAYRUS_LOVE) && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::NOVICE));}}), + LocationAccess(LH_TRADE_FROG, {[]{return IsAdult && EyeballFrog;}}), + LocationAccess(LH_GS_LAB_CRATE, {[]{return CanUse(IRON_BOOTS) && CanUse(HOOKSHOT);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE) && HasBombchus && (HasBottle || (IsAdult && (HasBoots || ClaimCheck)) || (IsChild && WeirdEgg)) && + (CanDoGlitch(GlitchType::TripleSlashClip, GlitchDifficulty::ADVANCED) || ((Bugs || Fish) && CanUse(HOVER_BOOTS) && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::INTERMEDIATE)) || + (CanUse(FARORES_WIND) && CanUse(NAYRUS_LOVE) && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::NOVICE)) || ProgressiveScale >= 2 || CanUse(IRON_BOOTS))) || + (CanUse(IRON_BOOTS) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE));}}), + }, { + //Exits + Entrance(LAKE_HYLIA, {[]{return true;}}), + }); + + areaTable[LH_FISHING_HOLE] = Area("LH Fishing Hole", "", NONE, DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(LH_CHILD_FISHING, {[]{return IsChild;}}), + LocationAccess(LH_ADULT_FISHING, {[]{return IsAdult;}}), + }, { + //Exits + Entrance(LH_FISHING_ISLAND, {[]{return true;}}), + }); + + areaTable[LH_GROTTO] = Area("LH Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(LH_DEKU_SCRUB_GROTTO_LEFT, {[]{return CanStunDeku;}}), + LocationAccess(LH_DEKU_SCRUB_GROTTO_RIGHT, {[]{return CanStunDeku;}}), + LocationAccess(LH_DEKU_SCRUB_GROTTO_CENTER, {[]{return CanStunDeku;}}), + }, { + //Exits + Entrance(LAKE_HYLIA, {[]{return true;}}), + }); + + areaTable[LON_LON_RANCH] = Area("Lon Lon Ranch", "Lon Lon Ranch", LON_LON_RANCH, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&Epona, {[]{return Epona || (CanPlay(EponasSong) && IsAdult && AtDay);}}), + EventAccess(&LinksCow, {[]{return LinksCow || (CanPlay(EponasSong) && IsAdult && AtDay);}}), + }, { + //Locations + LocationAccess(SONG_FROM_MALON, {[]{return IsChild && ZeldasLetter && Ocarina && AtDay;}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && (CanSurviveDamage || (Fairy && NumBottles >= 2)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && IsChild && ZeldasLetter && AtDay;}}), + LocationAccess(LLR_GS_TREE, {[]{return IsChild;}}), + LocationAccess(LLR_GS_RAIN_SHED, {[]{return IsChild && AtNight && CanGetNightTimeGS;}}), + LocationAccess(LLR_GS_HOUSE_WINDOW, {[]{return IsChild && HookshotOrBoomerang && AtNight && CanGetNightTimeGS;}}), + LocationAccess(LLR_GS_BACK_WALL, {[]{return IsChild && HookshotOrBoomerang && AtNight && CanGetNightTimeGS;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && IsChild && AtNight && CanGetNightTimeGS;}}), + }, { + //Exits + Entrance(HYRULE_FIELD, {[]{return true;}}), + Entrance(LLR_TALONS_HOUSE, {[]{return true;}}), + Entrance(LLR_STABLES, {[]{return true;}}), + Entrance(LLR_TOWER, {[]{return true;}}), + Entrance(LLR_GROTTO, {[]{return IsChild;}}), + }); + + areaTable[LLR_TALONS_HOUSE] = Area("LLR Talons House", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(LLR_TALONS_CHICKENS, {[]{return IsChild && AtDay && ZeldasLetter;}}), + }, { + //Exits + Entrance(LON_LON_RANCH, {[]{return true;}}), + }); + + areaTable[LLR_STABLES] = Area("LLR Stables", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(LLR_STABLES_LEFT_COW, {[]{return CanPlay(EponasSong);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::IndoorBombOI, GlitchDifficulty::EXPERT) || ((Bugs || Fish) && CanShield && (CanSurviveDamage || (Fairy && NumBottles >= 2)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED) && CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE))) && EponasSong;}}), + LocationAccess(LLR_STABLES_RIGHT_COW, {[]{return CanPlay(EponasSong);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::IndoorBombOI, GlitchDifficulty::EXPERT) || ((Bugs || Fish) && CanShield && (CanSurviveDamage || (Fairy && NumBottles >= 2)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED) && CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE))) && EponasSong;}}), + }, { + //Exits + Entrance(LON_LON_RANCH, {[]{return true;}}), + }); + + areaTable[LLR_TOWER] = Area("LLR Tower", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(LLR_FREESTANDING_POH, {[]{return IsChild;}}), + LocationAccess(LLR_TOWER_LEFT_COW, {[]{return CanPlay(EponasSong);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::IndoorBombOI, GlitchDifficulty::EXPERT) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED) && CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE))) && EponasSong;}}), + LocationAccess(LLR_TOWER_RIGHT_COW, {[]{return CanPlay(EponasSong);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::IndoorBombOI, GlitchDifficulty::EXPERT) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED) && CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE))) && EponasSong;}}), + }, { + //Exits + Entrance(LON_LON_RANCH, {[]{return true;}}), + }); + + areaTable[LLR_GROTTO] = Area("LLR Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(LLR_DEKU_SCRUB_GROTTO_LEFT, {[]{return CanStunDeku;}}), + LocationAccess(LLR_DEKU_SCRUB_GROTTO_RIGHT, {[]{return CanStunDeku;}}), + LocationAccess(LLR_DEKU_SCRUB_GROTTO_CENTER, {[]{return CanStunDeku;}}), + }, { + //Exits + Entrance(LON_LON_RANCH, {[]{return true;}}), + }); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_ice_cavern.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_ice_cavern.cpp new file mode 100644 index 000000000..0431e5ca3 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_ice_cavern.cpp @@ -0,0 +1,86 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" +#include "../dungeon.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_IceCavern() { + /*-------------------------- + | VANILLA/MQ DECIDER | + ---------------------------*/ + areaTable[ICE_CAVERN_ENTRYWAY] = Area("Ice Cavern Entryway", "Ice Cavern", ICE_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(ICE_CAVERN_BEGINNING, {[]{return Dungeon::IceCavern.IsVanilla();}}), + Entrance(ICE_CAVERN_MQ_BEGINNING, {[]{return Dungeon::IceCavern.IsMQ();}}), + Entrance(ZORAS_FOUNTAIN, {[]{return true;}}), + }); + + /*-------------------------- + | VANILLA DUNGEON | + ---------------------------*/ + if (Dungeon::IceCavern.IsVanilla()) { + areaTable[ICE_CAVERN_BEGINNING] = Area("Ice Cavern Beginning", "Ice Cavern", ICE_CAVERN, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(ICE_CAVERN_ENTRYWAY, {[]{return true;}}), + Entrance(ICE_CAVERN_MAIN, {[]{return Here(ICE_CAVERN_BEGINNING, []{return IsAdult || HasExplosives || CanUse(DINS_FIRE);});}}), + }); + + areaTable[ICE_CAVERN_MAIN] = Area("Ice Cavern", "Ice Cavern", ICE_CAVERN, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&BlueFireAccess, {[]{return BlueFireAccess || (IsAdult && HasBottle);}}), + }, { + //Locations + LocationAccess(ICE_CAVERN_MAP_CHEST, {[]{return BlueFire && IsAdult;}}), + LocationAccess(ICE_CAVERN_COMPASS_CHEST, {[]{return BlueFire;}}), + LocationAccess(ICE_CAVERN_IRON_BOOTS_CHEST, {[]{return BlueFire && (IsAdult || Slingshot || Sticks || KokiriSword || CanUse(DINS_FIRE));}}), + LocationAccess(SHEIK_IN_ICE_CAVERN, {[]{return BlueFire && IsAdult;}}), + LocationAccess(ICE_CAVERN_FREESTANDING_POH, {[]{return BlueFire;}}), + LocationAccess(ICE_CAVERN_GS_SPINNING_SCYTHE_ROOM, {[]{return HookshotOrBoomerang;}}), + LocationAccess(ICE_CAVERN_GS_HEART_PIECE_ROOM, {[]{return BlueFire && HookshotOrBoomerang;}}), + LocationAccess(ICE_CAVERN_GS_PUSH_BLOCK_ROOM, {[]{return BlueFire && HookshotOrBoomerang;}}), + }, {}); + } + + /*--------------------------- + | MASTER QUEST DUNGEON | + ---------------------------*/ + if (Dungeon::IceCavern.IsMQ()) { + areaTable[ICE_CAVERN_MQ_BEGINNING] = Area("Ice Cavern MQ Beginning", "Ice Cavern", ICE_CAVERN, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return true;}}), + }, {}, { + //Exits + Entrance(ICE_CAVERN_ENTRYWAY, {[]{return true;}}), + Entrance(ICE_CAVERN_MQ_MAP_ROOM, {[]{return IsAdult || CanUse(DINS_FIRE) || (HasExplosives && (CanUse(STICKS) || CanUse(SLINGSHOT) || KokiriSword));}}), + Entrance(ICE_CAVERN_MQ_COMPASS_ROOM, {[]{return IsAdult && BlueFire;}}), + Entrance(ICE_CAVERN_MQ_IRON_BOOTS_REGION, {[]{return BlueFire;}}), + }); + + areaTable[ICE_CAVERN_MQ_MAP_ROOM] = Area("Ice Cavern MQ Map Room", "Ice Cavern", ICE_CAVERN, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&BlueFireAccess, {[]{return BlueFireAccess || HasBottle;}}), + }, { + //Locations + LocationAccess(ICE_CAVERN_MQ_MAP_CHEST, {[]{return BlueFire && (IsAdult || CanUse(STICKS) || KokiriSword || CanUseProjectile);}}), + }, {}); + + areaTable[ICE_CAVERN_MQ_IRON_BOOTS_REGION] = Area("Ice Cavern MQ Iron Boots Region", "Ice Cavern", ICE_CAVERN, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(ICE_CAVERN_MQ_IRON_BOOTS_CHEST, {[]{return IsAdult;}}), + LocationAccess(SHEIK_IN_ICE_CAVERN, {[]{return IsAdult;}}), + LocationAccess(ICE_CAVERN_MQ_GS_ICE_BLOCK, {[]{return IsAdult || CanUseProjectile;}}), + LocationAccess(ICE_CAVERN_MQ_GS_SCARECROW, {[]{return IsAdult && (CanUse(SCARECROW) || (CanUse(HOVER_BOOTS) && CanUse(LONGSHOT)));}}), + //Tricks: (CanUse(SCARECROW) || (HoverBoots && CanUse(LONGSHOT)) || LogicIceMQScarecrow) && IsAdult + }, {}); + + areaTable[ICE_CAVERN_MQ_COMPASS_ROOM] = Area("Ice Cavern MQ Compass Room", "Ice Cavern", ICE_CAVERN, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(ICE_CAVERN_MQ_COMPASS_CHEST, {[]{return true;}}), + LocationAccess(ICE_CAVERN_MQ_FREESTANDING_POH, {[]{return HasExplosives;}}), + LocationAccess(ICE_CAVERN_MQ_GS_RED_ICE, {[]{return CanPlay(SongOfTime);}}), + //Trick: CanPlay(SongOfTime) || LogicIceMQRedIceGS + }, {}); + } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_jabujabus_belly.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_jabujabus_belly.cpp new file mode 100644 index 000000000..9d24ab031 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_jabujabus_belly.cpp @@ -0,0 +1,245 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" +#include "../dungeon.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_JabuJabusBelly() { + /*-------------------------- + | VANILLA/MQ DECIDER | + ---------------------------*/ + areaTable[JABU_JABUS_BELLY_ENTRYWAY] = Area("Jabu Jabus Belly Entryway", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(JABU_JABUS_BELLY_BEGINNING, {[]{return Dungeon::JabuJabusBelly.IsVanilla();}}), + Entrance(JABU_JABUS_BELLY_MQ_BEGINNING, {[]{return Dungeon::JabuJabusBelly.IsMQ();}}), + Entrance(ZORAS_FOUNTAIN, {[]{return true;}}), + }); + + /*-------------------------- + | VANILLA DUNGEON | + ---------------------------*/ + if (Dungeon::JabuJabusBelly.IsVanilla()) { + areaTable[JABU_JABUS_BELLY_BEGINNING] = Area("Jabu Jabus Belly Beginning", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(JABU_JABUS_BELLY_ENTRYWAY, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_LIFT_MIDDLE, {[]{return CanUseProjectile;}, + /*Glitched*/[]{return CanUse(BOOMERANG) || CanUse(BOW) || CanUse(HOOKSHOT) || (CanUse(STICKS) && CanTakeDamage && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::EXPERT)) || CanDoGlitch(GlitchType::SuperStab, GlitchDifficulty::NOVICE);}}), + }); + + areaTable[JABU_JABUS_BELLY_LIFT_MIDDLE] = Area("Jabu Jabus Belly Lift Middle", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(JABU_JABUS_BELLY_BEGINNING, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_MAIN_UPPER, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_LIFT_LOWER, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_NEAR_BOSS_ROOM, {[]{return HasAccessTo(JABU_JABUS_BELLY_LIFT_UPPER) || (LogicJabuBossGSAdult && IsAdult && CanUse(HOVER_BOOTS));}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::INTERMEDIATE)) && + GlitchJabuSwitch && (Fish || Bugs || CanUse(FARORES_WIND) || (IsAdult && ClaimCheck));}}), + }); + + areaTable[JABU_JABUS_BELLY_MAIN_UPPER] = Area("Jabu Jabus Belly Main Upper", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(JABU_JABUS_BELLY_LIFT_MIDDLE, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_MAIN_LOWER, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_FORKED_CORRIDOR, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_BIGOCTO_ROOM, {[]{return Here(JABU_JABUS_BELLY_GREEN_TENTACLE, []{return CanUse(BOOMERANG);});}}), + }); + + areaTable[JABU_JABUS_BELLY_MAIN_LOWER] = Area("Jabu Jabus Belly Main Lower", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_LOWER, {[]{return HookshotOrBoomerang;}, + /*Glitched*/[]{return Bombs && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE);}}), + LocationAccess(JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_UPPER, {[]{return HookshotOrBoomerang;}, + /*Glitched*/[]{return Bombs && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE);}}), + }, { + //Exits + Entrance(JABU_JABUS_BELLY_MAIN_UPPER, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_SHABOMB_CORRIDOR, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_LOWER_SIDE_ROOM, {[]{return true;}}), + }); + + areaTable[JABU_JABUS_BELLY_SHABOMB_CORRIDOR] = Area("Jabu Jabus Belly Shabomb Corridor", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return true;}}), + }, { + //Locations + LocationAccess(JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM, {[]{return true;}}), + }, { + //Exits + Entrance(JABU_JABUS_BELLY_MAIN_LOWER, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_LIFT_LOWER, {[]{return CanUseProjectile;}, + /*Glitched*/[]{return CanUse(BOOMERANG) || CanUse(BOW) || CanUse(HOOKSHOT) || (CanUse(STICKS) && CanTakeDamage && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::EXPERT));}}), + }); + + areaTable[JABU_JABUS_BELLY_LOWER_SIDE_ROOM] = Area("Jabu Jabus Belly Lower Side Room", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return FairyPot || (CanUse(BOOMERANG) || CanUse(HOVER_BOOTS));}, + /*Glitched*/[]{return (Bombs && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE)) || CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::INTERMEDIATE);}}), + }, {}, { + //Exits + Entrance(JABU_JABUS_BELLY_MAIN_LOWER, {[]{return true;}}), + }); + + areaTable[JABU_JABUS_BELLY_LIFT_LOWER] = Area("Jabu Jabus Belly Lift Lower", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(JABU_JABUS_BELLY_DEKU_SCRUB, {[]{return (IsChild || CanDive || LogicJabuScrubJumpDive || CanUse(IRON_BOOTS)) && CanStunDeku;}}), + }, { + //Exits + Entrance(JABU_JABUS_BELLY_SHABOMB_CORRIDOR, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_LIFT_MIDDLE, {[]{return true;}}), + }); + + areaTable[JABU_JABUS_BELLY_FORKED_CORRIDOR] = Area("Jabu Jabus Belly Forked Corridor", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(JABU_JABUS_BELLY_MAIN_UPPER, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_BOOMERANG_ROOM, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_MAP_ROOM, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_COMPASS_ROOM, {[]{return Here(JABU_JABUS_BELLY_MAP_ROOM, []{return CanUse(BOOMERANG);});}}), + Entrance(JABU_JABUS_BELLY_BLUE_TENTACLE, {[]{return Here(JABU_JABUS_BELLY_MAP_ROOM, []{return CanUse(BOOMERANG);});}}), + Entrance(JABU_JABUS_BELLY_GREEN_TENTACLE, {[]{return Here(JABU_JABUS_BELLY_BLUE_TENTACLE, []{return CanUse(BOOMERANG);});}}), + }); + + areaTable[JABU_JABUS_BELLY_BOOMERANG_ROOM] = Area("Jabu Jabus Belly Boomerang Room", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(JABU_JABUS_BELLY_BOOMERANG_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(JABU_JABUS_BELLY_FORKED_CORRIDOR, {[]{return true;}}), + }); + + areaTable[JABU_JABUS_BELLY_MAP_ROOM] = Area("Jabu Jabus Belly Map Room", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(JABU_JABUS_BELLY_MAP_CHEST, {[]{return CanUse(BOOMERANG);}}), + }, { + //Exits + Entrance(JABU_JABUS_BELLY_FORKED_CORRIDOR, {[]{return true;}}), + }); + + areaTable[JABU_JABUS_BELLY_COMPASS_ROOM] = Area("Jabu Jabus Belly Compass Room", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(JABU_JABUS_BELLY_COMPASS_CHEST, {[]{return IsAdult || CanChildAttack;}}), + }, { + //Exits + Entrance(JABU_JABUS_BELLY_FORKED_CORRIDOR, {[]{return true;}}), + }); + + areaTable[JABU_JABUS_BELLY_BLUE_TENTACLE] = Area("Jabu Jabus Belly Blue Tentacle", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(JABU_JABUS_BELLY_FORKED_CORRIDOR, {[]{return Here(JABU_JABUS_BELLY_BLUE_TENTACLE, []{return CanUse(BOOMERANG);});}}), + }); + + areaTable[JABU_JABUS_BELLY_GREEN_TENTACLE] = Area("Jabu Jabus Belly Green Tentacle", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(JABU_JABUS_BELLY_FORKED_CORRIDOR, {[]{return Here(JABU_JABUS_BELLY_GREEN_TENTACLE, []{return CanUse(BOOMERANG);});}}), + }); + + areaTable[JABU_JABUS_BELLY_BIGOCTO_ROOM] = Area("Jabu Jabus Belly Bigocto Room", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(JABU_JABUS_BELLY_MAIN_LOWER, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_ABOVE_BIGOCTO, {[]{return Here(JABU_JABUS_BELLY_BIGOCTO_ROOM, []{return (CanUse(BOOMERANG) || Nuts) && (CanUse(KOKIRI_SWORD) || CanUse(STICKS));});}}), + }); + + areaTable[JABU_JABUS_BELLY_ABOVE_BIGOCTO] = Area("Jabu Jabus Belly Above Bigocto", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return true;}}), + EventAccess(&NutPot, {[]{return true;}}), + }, {}, { + //Exits + Entrance(JABU_JABUS_BELLY_LIFT_UPPER, {[]{return CanUse(BOOMERANG);}, + /*Glitched*/[]{return HasBombchus && CanShield && IsAdult && (CanUse(HOOKSHOT) || CanUse(BOW) || CanUse(SLINGSHOT)) && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED);}}), + }); + + areaTable[JABU_JABUS_BELLY_LIFT_UPPER] = Area("Jabu Jabus Belly Lift Upper", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(JABU_JABUS_BELLY_LIFT_MIDDLE, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_LIFT_LOWER, {[]{return true;}}), + }); + + areaTable[JABU_JABUS_BELLY_NEAR_BOSS_ROOM] = Area("Jabu Jabus Belly Near Boss Room", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(JABU_JABUS_BELLY_GS_NEAR_BOSS, {[]{return IsAdult || CanChildAttack;}}), + }, { + //Exits + Entrance(JABU_JABUS_BELLY_LIFT_MIDDLE, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_BOSS_ROOM, {[]{return CanUse(BOOMERANG);}, + /*Glitched*/[]{return (CanUse(HOVER_BOOTS) && (CanUse(BOW) || CanUse(SLINGSHOT))) || CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE) || + (CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::NOVICE)) || (Bombs && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE)) || CanDoGlitch(GlitchType::SuperStab, GlitchDifficulty::NOVICE);}}), + }); + + areaTable[JABU_JABUS_BELLY_BOSS_ROOM] = Area("Jabu Jabus Belly Boss Room", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&JabuJabusBellyClear, {[]{return JabuJabusBellyClear || CanUse(BOOMERANG);}}), + }, { + //Locations + LocationAccess(JABU_JABUS_BELLY_BARINADE_HEART, {[]{return JabuJabusBellyClear;}}), + LocationAccess(BARINADE, {[]{return JabuJabusBellyClear;}}), + }, { + //Exits + Entrance(JABU_JABUS_BELLY_NEAR_BOSS_ROOM, {[]{return JabuJabusBellyClear;}}), + Entrance(JABU_JABUS_BELLY_ENTRYWAY, {[]{return JabuJabusBellyClear;}}), + }); + } + + /*--------------------------- + | MASTER QUEST DUNGEON | + ---------------------------*/ + if (Dungeon::JabuJabusBelly.IsMQ()) { + areaTable[JABU_JABUS_BELLY_MQ_BEGINNING] = Area("Jabu Jabus Belly MQ Beginning", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&NutPot, {[]{return true;}}), + }, { + //Locations + LocationAccess(JABU_JABUS_BELLY_MQ_MAP_CHEST, {[]{return CanBlastOrSmash;}}), + LocationAccess(JABU_JABUS_BELLY_MQ_FIRST_ROOM_SIDE_CHEST, {[]{return IsChild && CanUse(SLINGSHOT);}}), + }, { + //Exits + Entrance(JABU_JABUS_BELLY_ENTRYWAY, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_MQ_MAIN, {[]{return Here(JABU_JABUS_BELLY_MQ_BEGINNING, []{return IsChild && CanUse(SLINGSHOT);});}}), + }); + + areaTable[JABU_JABUS_BELLY_MQ_MAIN] = Area("Jabu Jabus Belly MQ Main", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(JABU_JABUS_BELLY_MQ_SECOND_ROOM_LOWER_CHEST, {[]{return true;}}), + LocationAccess(JABU_JABUS_BELLY_MQ_SECOND_ROOM_UPPER_CHEST, {[]{return (IsAdult && (CanUse(HOVER_BOOTS) || CanUse(HOOKSHOT))) || ChildCanAccess(JABU_JABUS_BELLY_MQ_BOSS_AREA);}}), + LocationAccess(JABU_JABUS_BELLY_MQ_COMPASS_CHEST, {[]{return true;}}), + LocationAccess(JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_VINES_CHEST, {[]{return true;}}), + LocationAccess(JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_SWITCHES_CHEST, {[]{return true;}}), + LocationAccess(JABU_JABUS_BELLY_MQ_BOOMERANG_ROOM_SMALL_CHEST, {[]{return true;}}), + LocationAccess(JABU_JABUS_BELLY_MQ_BOOMERANG_CHEST, {[]{return true;}}), + LocationAccess(JABU_JABUS_BELLY_MQ_GS_BOOMERANG_CHEST_ROOM, {[]{return CanPlay(SongOfTime);}}), + //Trick: CanPlay(SongOfTime) || (LogicJabuMQSoTGS && IsChild && CanUse(BOOMERANG)) + }, { + //Exits + Entrance(JABU_JABUS_BELLY_MQ_BEGINNING, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_MQ_DEPTHS, {[]{return HasExplosives && IsChild && CanUse(BOOMERANG);}}), + }); + + areaTable[JABU_JABUS_BELLY_MQ_DEPTHS] = Area("Jabu Jabus Belly MQ Depths", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_ROOM_CHEST, {[]{return true;}}), + LocationAccess(JABU_JABUS_BELLY_MQ_GS_TAILPASARAN_ROOM, {[]{return Sticks || CanUse(DINS_FIRE);}}), + LocationAccess(JABU_JABUS_BELLY_MQ_GS_INVISIBLE_ENEMIES_ROOM, {[]{return (LogicLensJabuMQ || CanUse(LENS_OF_TRUTH)) || Here(JABU_JABUS_BELLY_MQ_MAIN, []{return IsAdult && CanUse(HOVER_BOOTS) && CanUse(HOOKSHOT);});}}), + }, { + //Exits + Entrance(JABU_JABUS_BELLY_MQ_MAIN, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_MQ_BOSS_AREA, {[]{return Sticks || (CanUse(DINS_FIRE) && KokiriSword);}}), + }); + + areaTable[JABU_JABUS_BELLY_MQ_BOSS_AREA] = Area("Jabu Jabus Belly MQ Boss Area", "Jabu Jabus Belly", JABU_JABUS_BELLY, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return true;}}), + EventAccess(&JabuJabusBellyClear, {[]{return true;}}), + }, { + //Locations + LocationAccess(JABU_JABUS_BELLY_MQ_COW, {[]{return CanPlay(EponasSong);}}), + LocationAccess(JABU_JABUS_BELLY_MQ_NEAR_BOSS_CHEST, {[]{return true;}}), + LocationAccess(JABU_JABUS_BELLY_BARINADE_HEART, {[]{return true;}}), + LocationAccess(BARINADE, {[]{return true;}}), + LocationAccess(JABU_JABUS_BELLY_MQ_GS_NEAR_BOSS, {[]{return true;}}), + }, { + //Exits + Entrance(JABU_JABUS_BELLY_MQ_MAIN, {[]{return true;}}), + }); + } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_kakariko.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_kakariko.cpp new file mode 100644 index 000000000..87523ef3b --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_kakariko.cpp @@ -0,0 +1,303 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_Kakariko() { + areaTable[KAKARIKO_VILLAGE] = Area("Kakariko Village", "Kakariko Village", KAKARIKO_VILLAGE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&CojiroAccess, {[]{return CojiroAccess || (IsAdult && WakeUpAdultTalon);}}), + EventAccess(&BugRock, {[]{return true;}}), + EventAccess(&KakarikoVillageGateOpen, {[]{return KakarikoVillageGateOpen || (IsChild && (ZeldasLetter || OpenKakariko.Is(OPENKAKARIKO_OPEN)));}}), + }, { + //Locations + LocationAccess(SHEIK_IN_KAKARIKO, {[]{return IsAdult && ForestMedallion && FireMedallion && WaterMedallion;}}), + LocationAccess(KAK_ANJU_AS_CHILD, {[]{return IsChild && AtDay;}}), + LocationAccess(KAK_ANJU_AS_ADULT, {[]{return IsAdult && AtDay;}}), + LocationAccess(KAK_TRADE_POCKET_CUCCO, {[]{return IsAdult && AtDay && PocketEgg && WakeUpAdultTalon;}}), + LocationAccess(KAK_GS_HOUSE_UNDER_CONSTRUCTION, {[]{return IsChild && AtNight && CanGetNightTimeGS;}}), + LocationAccess(KAK_GS_SKULLTULA_HOUSE, {[]{return IsChild && AtNight && CanGetNightTimeGS;}}), + LocationAccess(KAK_GS_GUARDS_HOUSE, {[]{return IsChild && AtNight && CanGetNightTimeGS;}}), + LocationAccess(KAK_GS_TREE, {[]{return IsChild && AtNight && CanGetNightTimeGS;}}), + LocationAccess(KAK_GS_WATCHTOWER, {[]{return IsChild && (Slingshot || HasBombchus || CanUse(BOW) || CanUse(LONGSHOT)) && AtNight && CanGetNightTimeGS;}, + /*Glitched*/[]{return IsChild && AtNight && CanGetNightTimeGS && (CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::SuperStab, GlitchDifficulty::NOVICE) || (Sticks && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::INTERMEDIATE)));}}), + LocationAccess(KAK_GS_ABOVE_IMPAS_HOUSE, {[]{return IsAdult && CanUse(HOOKSHOT) && AtNight && CanGetNightTimeGS;}, + /*Glitched*/[]{return IsAdult && AtNight && CanGetNightTimeGS && ((HoverBoots && CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::INTERMEDIATE)) || (Bombs && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE)) || CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::INTERMEDIATE));}}), + }, { + //Exits + Entrance(HYRULE_FIELD, {[]{return true;}}), + Entrance(KAK_CARPENTER_BOSS_HOUSE, {[]{return true;}}), + Entrance(KAK_HOUSE_OF_SKULLTULA, {[]{return true;}}), + Entrance(KAK_IMPAS_HOUSE, {[]{return true;}}), + Entrance(KAK_WINDMILL, {[]{return true;}}), + Entrance(KAK_BAZAAR, {[]{return IsAdult && AtDay;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::TripleSlashClip, GlitchDifficulty::NOVICE);}}), + Entrance(KAK_SHOOTING_GALLERY, {[]{return IsAdult && AtDay;}}), + Entrance(BOTTOM_OF_THE_WELL_ENTRYWAY, {[]{return DrainWell && (IsChild || ShuffleDungeonEntrances.IsNot(SHUFFLEDUNGEONS_OFF));}, + /*Glitched*/[]{return (IsChild && (CanDoGlitch(GlitchType::TripleSlashClip, GlitchDifficulty::NOVICE) || (AtNight && (CanDoGlitch(GlitchType::NaviDive_Stick, GlitchDifficulty::NOVICE) || ((Bugs || Fish) && CanUse(HOVER_BOOTS) && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::INTERMEDIATE)) || + (CanUse(FARORES_WIND) && (FaroresWindAnywhere || (CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE) && (HasBottle || WeirdEgg))) && ((CanUse(NAYRUS_LOVE) && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::NOVICE)) || + (CanUseMagicArrow && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::ADVANCED)))))))) || (IsAdult && CanUse(LONGSHOT) && AtDay && CanDoGlitch(GlitchType::TripleSlashClip, GlitchDifficulty::NOVICE));}}), + Entrance(KAK_POTION_SHOP_FRONT, {[]{return AtDay || IsChild;}}), + Entrance(KAK_REDEAD_GROTTO, {[]{return CanOpenBombGrotto;}}), + Entrance(KAK_IMPAS_LEDGE, {[]{return (IsChild && AtDay) || CanUse(HOOKSHOT);}, + /*Glitched*/[]{return IsAdult && ((HoverBoots && CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::INTERMEDIATE)) || (Bombs && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE)) || CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::INTERMEDIATE));}}), + Entrance(KAK_ROOFTOP, {[]{return CanUse(HOOKSHOT) || (LogicManOnRoof && (IsAdult || AtDay || Slingshot || HasBombchus || CanUse(BOW) || CanUse(LONGSHOT)));}, + /*Glitched*/[]{return LogicManOnRoof && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE);}}), + Entrance(THE_GRAVEYARD, {[]{return true;}}), + Entrance(KAK_BEHIND_GATE, {[]{return IsAdult || (KakarikoVillageGateOpen);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE);}}), + }); + + areaTable[KAK_IMPAS_LEDGE] = Area("Kak Impas Ledge", "Kakariko Village", KAKARIKO_VILLAGE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(KAK_IMPAS_HOUSE_BACK, {[]{return true;}}), + Entrance(KAKARIKO_VILLAGE, {[]{return true;}}), + }); + + areaTable[KAK_ROOFTOP] = Area("Kak Rooftop", "Kakariko Village", KAKARIKO_VILLAGE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(KAK_MAN_ON_ROOF, {[]{return true;}}), + }, { + //Exits + Entrance(KAK_BACKYARD, {[]{return true;}}), + }); + + areaTable[KAK_BACKYARD] = Area("Kak Backyard", "Kakariko Village", KAKARIKO_VILLAGE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(KAKARIKO_VILLAGE, {[]{return true;}}), + Entrance(KAK_OPEN_GROTTO, {[]{return true;}}), + Entrance(KAK_ODD_POTION_BUILDING, {[]{return IsAdult;}}), + Entrance(KAK_POTION_SHOP_BACK, {[]{return IsAdult && AtDay;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::TripleSlashClip, GlitchDifficulty::NOVICE);}}), + }); + + areaTable[KAK_CARPENTER_BOSS_HOUSE] = Area("Kak Carpenter Boss House", "", NONE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&WakeUpAdultTalon, {[]{return WakeUpAdultTalon || (IsAdult && PocketEgg);}}), + }, {}, { + //Exits + Entrance(KAKARIKO_VILLAGE, {[]{return true;}}), + }); + + areaTable[KAK_HOUSE_OF_SKULLTULA] = Area("Kak House of Skulltula", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(KAK_10_GOLD_SKULLTULA_REWARD, {[]{return GoldSkulltulaTokens >= 10;}}), + LocationAccess(KAK_20_GOLD_SKULLTULA_REWARD, {[]{return GoldSkulltulaTokens >= 20;}}), + LocationAccess(KAK_30_GOLD_SKULLTULA_REWARD, {[]{return GoldSkulltulaTokens >= 30;}}), + LocationAccess(KAK_40_GOLD_SKULLTULA_REWARD, {[]{return GoldSkulltulaTokens >= 40;}}), + LocationAccess(KAK_50_GOLD_SKULLTULA_REWARD, {[]{return GoldSkulltulaTokens >= 50;}}), + }, { + //Exits + Entrance(KAKARIKO_VILLAGE, {[]{return true;}}), + }); + + areaTable[KAK_IMPAS_HOUSE] = Area("Kak Impas House", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(KAK_IMPAS_HOUSE_NEAR_COW, {[]{return true;}}), + Entrance(KAKARIKO_VILLAGE, {[]{return true;}}), + }); + + areaTable[KAK_IMPAS_HOUSE_BACK] = Area("Kak Impas House Back", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(KAK_IMPAS_HOUSE_FREESTANDING_POH, {[]{return true;}}), + }, { + //Exits + Entrance(KAK_IMPAS_LEDGE, {[]{return true;}}), + Entrance(KAK_IMPAS_HOUSE_NEAR_COW, {[]{return true;}}), + }); + + areaTable[KAK_IMPAS_HOUSE_NEAR_COW] = Area("Kak Impas House Near Cow", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(KAK_IMPAS_HOUSE_COW, {[]{return CanPlay(EponasSong);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::IndoorBombOI, GlitchDifficulty::ADVANCED) || ((Bugs || Fish) && CanShield && (CanSurviveDamage || (Fairy && NumBottles >= 2)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED))) && EponasSong;}}), + }, {}); + + areaTable[KAK_WINDMILL] = Area("Kak Windmill", "", NONE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DrainWell, {[]{return DrainWell || (IsChild && CanPlay(SongOfStorms));}, + /*Glitched*/[]{return IsChild && SongOfStorms && (CanDoGlitch(GlitchType::WindmillBombOI, GlitchDifficulty::ADVANCED) || ((Fish || Bugs) && CanShield && ((Bombs && (CanSurviveDamage || (Fairy && NumBottles >= 2))) || CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE)) && + CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Fish || Bugs) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED)));}}), + }, { + //Locations + LocationAccess(KAK_WINDMILL_FREESTANDING_POH, {[]{return CanUse(BOOMERANG) || DampesWindmillAccess || (IsAdult && CanUse(HOOKSHOT) && LogicWindmillPoHHookshot);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE);}}), + LocationAccess(SONG_FROM_WINDMILL, {[]{return IsAdult && Ocarina;}, + /*Glitched*/[]{return IsAdult && (CanDoGlitch(GlitchType::WindmillBombOI, GlitchDifficulty::EXPERT) || ((Fish || Bugs) && CanShield && ((Bombs && (CanSurviveDamage || (Fairy && NumBottles >= 2))) || (DampesWindmillAccess || (IsAdult && CanUse(HOOKSHOT) && LogicWindmillPoHHookshot) || CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE))) && + CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Fish || Bugs) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED)));}}), + }, { + //Exits + Entrance(KAKARIKO_VILLAGE, {[]{return true;}}), + }); + + areaTable[KAK_BAZAAR] = Area("Kak Bazaar", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(KAK_BAZAAR_ITEM_1, {[]{return true;}}), + LocationAccess(KAK_BAZAAR_ITEM_2, {[]{return true;}}), + LocationAccess(KAK_BAZAAR_ITEM_3, {[]{return true;}}), + LocationAccess(KAK_BAZAAR_ITEM_4, {[]{return true;}}), + LocationAccess(KAK_BAZAAR_ITEM_5, {[]{return true;}}), + LocationAccess(KAK_BAZAAR_ITEM_6, {[]{return true;}}), + LocationAccess(KAK_BAZAAR_ITEM_7, {[]{return true;}}), + LocationAccess(KAK_BAZAAR_ITEM_8, {[]{return true;}}), + }, { + //Exits + Entrance(KAKARIKO_VILLAGE, {[]{return true;}}), + }); + + areaTable[KAK_SHOOTING_GALLERY] = Area("Kak Shooting Gallery", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(KAK_SHOOTING_GALLERY_REWARD, {[]{return IsAdult && Bow;}}), + }, { + //Exits + Entrance(KAKARIKO_VILLAGE, {[]{return true;}}), + }); + + areaTable[KAK_POTION_SHOP_FRONT] = Area("Kak Potion Shop Front", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(KAK_POTION_SHOP_ITEM_1, {[]{return IsAdult;}}), + LocationAccess(KAK_POTION_SHOP_ITEM_2, {[]{return IsAdult;}}), + LocationAccess(KAK_POTION_SHOP_ITEM_3, {[]{return IsAdult;}}), + LocationAccess(KAK_POTION_SHOP_ITEM_4, {[]{return IsAdult;}}), + LocationAccess(KAK_POTION_SHOP_ITEM_5, {[]{return IsAdult;}}), + LocationAccess(KAK_POTION_SHOP_ITEM_6, {[]{return IsAdult;}}), + LocationAccess(KAK_POTION_SHOP_ITEM_7, {[]{return IsAdult;}}), + LocationAccess(KAK_POTION_SHOP_ITEM_8, {[]{return IsAdult;}}), + }, { + //Exits + Entrance(KAKARIKO_VILLAGE, {[]{return true;}}), + Entrance(KAK_POTION_SHOP_BACK, {[]{return IsAdult;}}), + }); + + areaTable[KAK_POTION_SHOP_BACK] = Area("Kak Potion Shop Back", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(KAK_BACKYARD, {[]{return IsAdult;}}), + Entrance(KAK_POTION_SHOP_FRONT, {[]{return true;}}), + }); + + areaTable[KAK_ODD_POTION_BUILDING] = Area("Kak Granny's Potion Shop", "", NONE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&OddPoulticeAccess, {[]{return OddPoulticeAccess || (IsAdult && (OddMushroomAccess || (OddMushroom && DisableTradeRevert)));}}), + }, { + LocationAccess(KAK_TRADE_ODD_MUSHROOM, {[]{return IsAdult && OddMushroom;}}), + }, { + //Exits + Entrance(KAK_BACKYARD, {[]{return true;}}), + }); + + areaTable[KAK_REDEAD_GROTTO] = Area("Kak Redead Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(KAK_REDEAD_GROTTO_CHEST, {[]{return IsAdult || (Sticks || KokiriSword || CanUse(DINS_FIRE) || CanUse(MEGATON_HAMMER) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD));}}), + }, { + //Exits + Entrance(KAKARIKO_VILLAGE, {[]{return true;}}), + }); + + areaTable[KAK_OPEN_GROTTO] = Area("Kak Open Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, { + //Locations + LocationAccess(KAK_OPEN_GROTTO_CHEST, {[]{return true;}}), + LocationAccess(KAK_OPEN_GROTTO_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(KAK_BACKYARD, {[]{return true;}}), + }); + + areaTable[THE_GRAVEYARD] = Area("The Graveyard", "The Graveyard", THE_GRAVEYARD, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&ButterflyFairy, {[]{return ButterflyFairy || (CanUse(STICKS) && AtDay);}}), + EventAccess(&BeanPlantFairy, {[]{return BeanPlantFairy || (CanPlantBean(THE_GRAVEYARD) && CanPlay(SongOfStorms));}}), + EventAccess(&BugRock, {[]{return true;}}), + }, { + //Locations + LocationAccess(GRAVEYARD_FREESTANDING_POH, {[]{return (IsAdult && CanPlantBean(THE_GRAVEYARD)) || CanUse(LONGSHOT) || (LogicGraveyardPoH && CanUse(BOOMERANG));}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::HookshotJump_Bonk, GlitchDifficulty::NOVICE);}}), + LocationAccess(GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR, {[]{return IsChild && AtNight;}}), //TODO: This needs to change + LocationAccess(GRAVEYARD_GS_WALL, {[]{return IsChild && HookshotOrBoomerang && AtNight && CanGetNightTimeGS;}, + /*Glitched*/[]{return IsChild && AtNight && CanGetNightTimeGS && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE);}}), + LocationAccess(GRAVEYARD_GS_BEAN_PATCH, {[]{return CanPlantBugs && CanChildAttack;}}), + }, { + //Exits + Entrance(GRAVEYARD_SHIELD_GRAVE, {[]{return IsAdult || AtNight;}}), + Entrance(GRAVEYARD_COMPOSERS_GRAVE, {[]{return CanPlay(ZeldasLullaby);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::NOVICE) || ((Bugs || Fish) && CanShield && (IsChild || AdultCanAccess(GRAVEYARD_WARP_PAD_REGION) || (IsAdult && (CanPlantBean(THE_GRAVEYARD) || CanUse(LONGSHOT))) || CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) || (Bombs && (CanSurviveDamage || (Fairy && NumBottles >= 2)))) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && ZeldasLullaby;}}), + Entrance(GRAVEYARD_HEART_PIECE_GRAVE, {[]{return IsAdult || AtNight;}}), + Entrance(GRAVEYARD_DAMPES_GRAVE, {[]{return IsAdult;}}), + Entrance(GRAVEYARD_DAMPES_HOUSE, {[]{return IsAdult || AtDampeTime;}}), //TODO: This needs to be handled + Entrance(KAKARIKO_VILLAGE, {[]{return true;}}), + Entrance(GRAVEYARD_WARP_PAD_REGION, {[]{return false;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::HookshotJump_Bonk, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::NOVICE);}}), + }); + + areaTable[GRAVEYARD_SHIELD_GRAVE] = Area("Graveyard Shield Grave", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GRAVEYARD_SHIELD_GRAVE_CHEST, {[]{return true;}}), + //Free Fairies + }, { + //Exits + Entrance(THE_GRAVEYARD, {[]{return true;}}), + }); + + areaTable[GRAVEYARD_HEART_PIECE_GRAVE] = Area("Graveyard Heart Piece Grave", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GRAVEYARD_HEART_PIECE_GRAVE_CHEST, {[]{return CanPlay(SunsSong);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::NOVICE) || ((Bugs || Fish) && CanShield && (Bombs && (CanSurviveDamage || (Fairy && NumBottles >= 2))) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && SunsSong;}}), + }, { + //Exits + Entrance(THE_GRAVEYARD, {[]{return true;}}), + }); + + areaTable[GRAVEYARD_COMPOSERS_GRAVE] = Area("Graveyard Composers Grave", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(GRAVEYARD_COMPOSERS_GRAVE_CHEST, {[]{return HasFireSource;}, + /*Glitched*/[]{return CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::INTERMEDIATE);}}), + LocationAccess(SONG_FROM_COMPOSERS_GRAVE, {[]{return IsAdult || (Slingshot || Boomerang || Sticks || HasExplosives || KokiriSword || CanUse(MEGATON_HAMMER) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || CanUse(BOW) || CanUse(HOOKSHOT));}}), + }, { + //Exits + Entrance(THE_GRAVEYARD, {[]{return true;}}), + }); + + areaTable[GRAVEYARD_DAMPES_GRAVE] = Area("Graveyard Dampes Grave", "", NONE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&NutPot, {[]{return true;}}), + EventAccess(&DampesWindmillAccess, {[]{return DampesWindmillAccess || (IsAdult && CanPlay(SongOfTime));}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::WindmillBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && (CanSurviveDamage || (Fairy && NumBottles >= 2)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && IsAdult && SongOfTime;}}), + }, { + //Locations + LocationAccess(GRAVEYARD_HOOKSHOT_CHEST, {[]{return true;}}), + LocationAccess(GRAVEYARD_DAMPE_RACE_FREESTANDING_POH, {[]{return IsAdult || LogicChildDampeRacePoH;}}), + }, { + //Exits + Entrance(THE_GRAVEYARD, {[]{return true;}}), + Entrance(KAK_WINDMILL, {[]{return IsAdult && CanPlay(SongOfTime);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::WindmillBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && (CanSurviveDamage || (Fairy && NumBottles >= 2)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && IsAdult && SongOfTime;}}), + }); + + areaTable[GRAVEYARD_DAMPES_HOUSE] = Area("Graveyard Dampes House", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(THE_GRAVEYARD, {[]{return true;}}), + }); + + areaTable[GRAVEYARD_WARP_PAD_REGION] = Area("Graveyard Warp Pad Region", "Graveyard", THE_GRAVEYARD, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || CanSummonGossipFairyWithoutSuns;}}), + }, { + //Locations + LocationAccess(GRAVEYARD_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(THE_GRAVEYARD, {[]{return true;}}), + Entrance(SHADOW_TEMPLE_ENTRYWAY, {[]{return CanUse(DINS_FIRE) || (LogicShadowFireArrowEntry && IsAdult && CanUse(FIRE_ARROWS));}, + /*Glitched*/[]{return (CanUse(STICKS) && (CanDoGlitch(GlitchType::QPA, GlitchDifficulty::INTERMEDIATE) || CanUse(FIRE_ARROWS))) || (CanTakeDamage && ( + CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::HookshotJump_Bonk, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::NOVICE)));}}), + }); + + areaTable[KAK_BEHIND_GATE] = Area("Kak Behind Gate", "Kakariko Village", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(KAKARIKO_VILLAGE, {[]{return IsAdult || LogicVisibleCollision || KakarikoVillageGateOpen || OpenKakariko.Is(OPENKAKARIKO_OPEN);}}), + Entrance(DEATH_MOUNTAIN_TRAIL, {[]{return true;}}), + }); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_lost_woods.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_lost_woods.cpp new file mode 100644 index 000000000..fa68b8012 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_lost_woods.cpp @@ -0,0 +1,275 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_LostWoods() { + areaTable[KOKIRI_FOREST] = Area("Kokiri Forest", "Kokiri Forest", KOKIRI_FOREST, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&BeanPlantFairy, {[]{return BeanPlantFairy || (CanPlantBean(KOKIRI_FOREST) && CanPlay(SongOfStorms));}}), + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || CanSummonGossipFairyWithoutSuns;}}), + EventAccess(&ShowedMidoSwordAndShield, {[]{return ShowedMidoSwordAndShield || (IsChild && KokiriSword && DekuShield);}}), + }, { + //Locations + LocationAccess(KF_KOKIRI_SWORD_CHEST, {[]{return IsChild;}}), + LocationAccess(KF_GS_KNOW_IT_ALL_HOUSE, {[]{return IsChild && CanChildAttack && AtNight && (HasNightStart || CanLeaveForest || CanPlay(SunsSong)) && CanGetNightTimeGS;}}), + LocationAccess(KF_GS_BEAN_PATCH, {[]{return CanPlantBugs && CanChildAttack;}}), + LocationAccess(KF_GS_HOUSE_OF_TWINS, {[]{return IsAdult && AtNight && HookshotOrBoomerang && CanGetNightTimeGS;}, + /*Glitched*/[]{return IsAdult && AtNight && CanGetNightTimeGS && (CanDoGlitch(GlitchType::HammerSlide, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::INTERMEDIATE));}}), + LocationAccess(KF_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(KF_LINKS_HOUSE, {[]{return true;}}), + Entrance(KF_MIDOS_HOUSE, {[]{return true;}}), + Entrance(KF_SARIAS_HOUSE, {[]{return true;}}), + Entrance(KF_HOUSE_OF_TWINS, {[]{return true;}}), + Entrance(KF_KNOW_IT_ALL_HOUSE, {[]{return true;}}), + Entrance(KF_KOKIRI_SHOP, {[]{return true;}}), + Entrance(KF_OUTSIDE_DEKU_TREE, {[]{return IsAdult || OpenForest.Is(OPENFOREST_OPEN) || ShowedMidoSwordAndShield;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::LedgeCancel, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::ASlide, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE);}}), + Entrance(THE_LOST_WOODS, {[]{return true;}}), + Entrance(LW_BRIDGE_FROM_FOREST, {[]{return IsAdult || OpenForest.IsNot(OPENFOREST_CLOSED) || DekuTreeClear;}, + /*Glitched*/[]{return CanLeaveForest && (CanDoGlitch(GlitchType::LedgeCancel, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::ASlide, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) || GlitchWWTEscape);}}), + Entrance(KF_STORMS_GROTTO, {[]{return CanOpenStormGrotto;}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && SongOfStorms && (ShardOfAgony || LogicGrottosWithoutAgony);}}), + }); + + areaTable[KF_OUTSIDE_DEKU_TREE] = Area("KF Outside Deku Tree", "Kokiri Forest", KOKIRI_FOREST, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&DekuBabaSticks, {[]{return DekuBabaSticks || ((IsAdult && ShuffleDungeonEntrances.Is(SHUFFLEDUNGEONS_OFF)) || KokiriSword || Boomerang);}}), + EventAccess(&DekuBabaNuts, {[]{return DekuBabaNuts || ((IsAdult && ShuffleDungeonEntrances.Is(SHUFFLEDUNGEONS_OFF)) || KokiriSword || Slingshot || Sticks || HasExplosives || CanUse(DINS_FIRE));}}), + EventAccess(&ShowedMidoSwordAndShield, {[]{return ShowedMidoSwordAndShield || (IsChild && KokiriSword && DekuShield);}}), + }, { + //Locations + LocationAccess(KF_DEKU_TREE_GOSSIP_STONE_LEFT, {[]{return true;}}), + LocationAccess(KF_DEKU_TREE_GOSSIP_STONE_RIGHT, {[]{return true;}}), + }, { + //Exits + Entrance(DEKU_TREE_ENTRYWAY, {[]{return IsChild || (ShuffleDungeonEntrances.IsNot(SHUFFLEDUNGEONS_OFF) && (OpenForest.Is(OPENFOREST_OPEN) || ShowedMidoSwordAndShield));}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HammerSlide, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::INTERMEDIATE);}}), + Entrance(KOKIRI_FOREST, {[]{return IsAdult || OpenForest.Is(OPENFOREST_OPEN) || ShowedMidoSwordAndShield;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::ASlide, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE);}}), + }); + + areaTable[KF_LINKS_HOUSE] = Area("KF Link's House", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(KF_LINKS_HOUSE_COW, {[]{return IsAdult && CanPlay(EponasSong) && LinksCow;}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::IndoorBombOI, GlitchDifficulty::EXPERT) || ((Bugs || Fish) && CanShield && (CanSurviveDamage || (NumBottles >= 2 && Fairy)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::EXPERT))) && CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE) && Bombs && IsAdult && EponasSong && LinksCow;}}), + }, { + //Exits + Entrance(KOKIRI_FOREST, {[]{return true;}}) + }); + + areaTable[KF_MIDOS_HOUSE] = Area("KF Mido's House", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(KF_MIDOS_TOP_LEFT_CHEST, {[]{return true;}}), + LocationAccess(KF_MIDOS_TOP_RIGHT_CHEST, {[]{return true;}}), + LocationAccess(KF_MIDOS_BOTTOM_LEFT_CHEST, {[]{return true;}}), + LocationAccess(KF_MIDOS_BOTTOM_RIGHT_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(KOKIRI_FOREST, {[]{return true;}}), + }); + + areaTable[KF_SARIAS_HOUSE] = Area("KF Saria's House", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(KOKIRI_FOREST, {[]{return true;}}), + }); + + areaTable[KF_HOUSE_OF_TWINS] = Area("KF House of Twins", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(KOKIRI_FOREST, {[]{return true;}}), + }); + + areaTable[KF_KNOW_IT_ALL_HOUSE] = Area("KF Know It All House", "", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(KOKIRI_FOREST, {[]{return true;}}), + }); + + areaTable[KF_KOKIRI_SHOP] = Area("KF Kokiri Shop", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(KF_SHOP_ITEM_1, {[]{return true;}}), + LocationAccess(KF_SHOP_ITEM_2, {[]{return true;}}), + LocationAccess(KF_SHOP_ITEM_3, {[]{return true;}}), + LocationAccess(KF_SHOP_ITEM_4, {[]{return true;}}), + LocationAccess(KF_SHOP_ITEM_5, {[]{return true;}}), + LocationAccess(KF_SHOP_ITEM_6, {[]{return true;}}), + LocationAccess(KF_SHOP_ITEM_7, {[]{return true;}}), + LocationAccess(KF_SHOP_ITEM_8, {[]{return true;}}), + }, { + //Exits + Entrance(KOKIRI_FOREST, {[]{return true;}}), + }); + + areaTable[KF_STORMS_GROTTO] = Area("KF Storms Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, { + //Locations + LocationAccess(KF_STORMS_GROTTO_CHEST, {[]{return true;}}), + LocationAccess(KF_STORMS_GROTTO_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(KOKIRI_FOREST, {[]{return true;}}) + }); + + areaTable[LW_FOREST_EXIT] = Area("LW Forest Exit", "Lost Woods", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(KOKIRI_FOREST, {[]{return true;}}) + }); + + areaTable[THE_LOST_WOODS] = Area("Lost Woods", "Lost Woods", THE_LOST_WOODS, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&OddMushroomAccess, {[]{return OddMushroomAccess || (IsAdult && (CojiroAccess || Cojiro));}}), + EventAccess(&PoachersSawAccess, {[]{return PoachersSawAccess || (IsAdult && OddPoulticeAccess);}}), + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || CanSummonGossipFairyWithoutSuns;}}), + EventAccess(&BeanPlantFairy, {[]{return BeanPlantFairy || CanPlay(SongOfStorms);}}), + EventAccess(&BugShrub, {[]{return IsChild && CanCutShrubs;}, + /*Glitched*/[]{return IsChild && Sticks && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);}}), + }, { + //Locations + LocationAccess(LW_SKULL_KID, {[]{return IsChild && CanPlay(SariasSong);}, + /*Glitched*/[]{return IsChild && (Fish || Bugs) && SariasSong && CanShield && (CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED) || (HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED)));}}), + LocationAccess(LW_TRADE_COJIRO, {[]{return IsAdult && Cojiro;}}), + LocationAccess(LW_TRADE_ODD_POTION, {[]{return IsAdult && OddPoultice && Cojiro;}}), + LocationAccess(LW_OCARINA_MEMORY_GAME, {[]{return IsChild && Ocarina;}, + /*Glitched*/[]{return IsChild && (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Fish || Bugs) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED)));}}), + LocationAccess(LW_TARGET_IN_WOODS, {[]{return IsChild && CanUse(SLINGSHOT);}}), + LocationAccess(LW_DEKU_SCRUB_NEAR_BRIDGE, {[]{return IsChild && CanStunDeku;}}), + LocationAccess(LW_GS_BEAN_PATCH_NEAR_BRIDGE, {[]{return CanPlantBugs && CanChildAttack;}}), + LocationAccess(LW_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(LW_FOREST_EXIT, {[]{return true;}}), + Entrance(GC_WOODS_WARP, {[]{return true;}}), + Entrance(LW_BRIDGE, {[]{return CanLeaveForest && ((IsAdult && CanPlantBean(THE_LOST_WOODS)) || CanUse(HOVER_BOOTS) || CanUse(LONGSHOT));}, + /*Glitched*/[]{return CanLeaveForest && (CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE) || (CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE) && HasBombchus) || CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::INTERMEDIATE));}}), + Entrance(ZORAS_RIVER, {[]{return CanLeaveForest && (CanDive || CanUse(IRON_BOOTS));}, + /*Glitched*/[]{return CanLeaveForest && (CanDoGlitch(GlitchType::TripleSlashClip, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::NaviDive_Stick, GlitchDifficulty::ADVANCED) || + ((Bugs || Fish) && CanUse(HOVER_BOOTS) && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::INTERMEDIATE)) || (CanUse(FARORES_WIND) && (FaroresWindAnywhere || (CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE) && (HasBottle || (IsAdult && (HasBoots || ClaimCheck)) || (IsChild && WeirdEgg)))) && + ((CanUse(NAYRUS_LOVE) && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::NOVICE)) || (CanUseMagicArrow && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::ADVANCED)))));}}), + Entrance(LW_BEYOND_MIDO, {[]{return IsChild || CanPlay(SariasSong);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::LedgeCancel, GlitchDifficulty::NOVICE) || + CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::INTERMEDIATE) || (CanDoGlitch(GlitchType::HookshotJump_Bonk, GlitchDifficulty::ADVANCED) && (CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::INTERMEDIATE) || HoverBoots)) || + ((CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && SariasSong);}}), + Entrance(LW_NEAR_SHORTCUTS_GROTTO, {[]{return Here(THE_LOST_WOODS, []{return CanBlastOrSmash;});}, + /*Glitched*/[]{return Here(THE_LOST_WOODS, []{return CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);});}}), + }); + + areaTable[LW_BEYOND_MIDO] = Area("LW Beyond Mido", "Lost Woods", THE_LOST_WOODS, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&ButterflyFairy, {[]{return ButterflyFairy || CanUse(STICKS);}}), + }, { + //Locations + LocationAccess(LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT, {[]{return IsChild && CanStunDeku;}}), + LocationAccess(LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, {[]{return IsChild && CanStunDeku;}}), + LocationAccess(LW_GS_ABOVE_THEATER, {[]{return IsAdult && AtNight && (CanPlantBean(LW_BEYOND_MIDO) || (LogicLostWoodsGSBean && CanUse(HOOKSHOT) && (CanUse(LONGSHOT) || CanUse(BOW) || CanUse(SLINGSHOT) || HasBombchus || CanUse(DINS_FIRE)))) && CanGetNightTimeGS;}, + /*Glitched*/[]{return IsAdult && AtNight && CanGetNightTimeGS && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE);}}), + LocationAccess(LW_GS_BEAN_PATCH_NEAR_THEATER, {[]{return CanPlantBugs && (CanChildAttack || (Scrubsanity.Is(SCRUBSANITY_OFF) && DekuShield));}}), + }, { + //Exits + Entrance(LW_FOREST_EXIT, {[]{return true;}}), + Entrance(THE_LOST_WOODS, {[]{return IsChild || CanPlay(SariasSong);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE) || ((CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || + ((Bugs || Fish) && CanShield && Bombs && (CanSurviveDamage || (NumBottles >= 2 && Fairy)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && SariasSong);}}), + Entrance(SFM_ENTRYWAY, {[]{return true;}}), + Entrance(DEKU_THEATER, {[]{return true;}}), + Entrance(LW_SCRUBS_GROTTO, {[]{return Here(LW_BEYOND_MIDO, []{return CanBlastOrSmash;});}, + /*Glitched*/[]{return Here(LW_BEYOND_MIDO, []{return IsChild && CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);});}}), + }); + + areaTable[LW_NEAR_SHORTCUTS_GROTTO] = Area("LW Near Shortcuts Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, { + //Locations + LocationAccess(LW_NEAR_SHORTCUTS_GROTTO_CHEST, {[]{return true;}}), + LocationAccess(LW_NEAR_SHORTCUTS_GROTTO_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(THE_LOST_WOODS, {[]{return true;}}), + }); + + areaTable[DEKU_THEATER] = Area("Deku Theater", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(DEKU_THEATER_SKULL_MASK, {[]{return IsChild && SkullMask;}}), + LocationAccess(DEKU_THEATER_MASK_OF_TRUTH, {[]{return IsChild && MaskOfTruth;}}), + }, { + //Exits + Entrance(LW_BEYOND_MIDO, {[]{return true;}}), + }); + + areaTable[LW_SCRUBS_GROTTO] = Area("LW Scrubs Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(LW_DEKU_SCRUB_GROTTO_REAR, {[]{return CanStunDeku;}}), + LocationAccess(LW_DEKU_SCRUB_GROTTO_FRONT, {[]{return CanStunDeku;}}), + }, { + //Exits + Entrance(LW_BEYOND_MIDO, {[]{return true;}}), + }); + + areaTable[SFM_ENTRYWAY] = Area("SFM Entryway", "Sacred Forest Meadow", SACRED_FOREST_MEADOW, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(LW_BEYOND_MIDO, {[]{return true;}}), + Entrance(SACRED_FOREST_MEADOW, {[]{return IsAdult || Slingshot || Sticks || KokiriSword || CanUse(DINS_FIRE) || CanUse(MEGATON_HAMMER) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD);}}), + Entrance(SFM_WOLFOS_GROTTO, {[]{return CanOpenBombGrotto;}}), + }); + + areaTable[SACRED_FOREST_MEADOW] = Area("Sacred Forest Meadow", "Sacred Forest Meadow", SACRED_FOREST_MEADOW, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || CanSummonGossipFairyWithoutSuns;}}), + }, { + //Locations + LocationAccess(SONG_FROM_SARIA, {[]{return IsChild && ZeldasLetter;}}), + LocationAccess(SHEIK_IN_FOREST, {[]{return IsAdult;}}), + LocationAccess(SFM_GS, {[]{return IsAdult && HookshotOrBoomerang && AtNight && CanGetNightTimeGS;}}), + LocationAccess(SFM_MAZE_GOSSIP_STONE_LOWER, {[]{return true;}}), + LocationAccess(SFM_MAZE_GOSSIP_STONE_UPPER, {[]{return true;}}), + LocationAccess(SFM_SARIA_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(SFM_ENTRYWAY, {[]{return true;}}), + Entrance(FOREST_TEMPLE_ENTRYWAY, {[]{return CanUse(HOOKSHOT);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE);}}), + Entrance(SFM_FAIRY_GROTTO, {[]{return true;}}), + Entrance(SFM_STORMS_GROTTO, {[]{return CanOpenStormGrotto;}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && HasBombchus && CanShield && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && SongOfStorms && (ShardOfAgony || LogicGrottosWithoutAgony);}}), + }); + + areaTable[SFM_FAIRY_GROTTO] = Area("SFM Fairy Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FreeFairies, {[]{return true;}}), + }, {}, { + //Exits + Entrance(SACRED_FOREST_MEADOW, {[]{return true;}}), + }); + + areaTable[SFM_WOLFOS_GROTTO] = Area("SFM Wolfos Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SFM_WOLFOS_GROTTO_CHEST, {[]{return IsAdult || Slingshot || Sticks || KokiriSword || CanUse(DINS_FIRE) || CanUse(MEGATON_HAMMER) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD);}}), + }, { + //Exits + Entrance(SFM_ENTRYWAY, {[]{return true;}}), + }); + + areaTable[SFM_STORMS_GROTTO] = Area("SFM Storms Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SFM_DEKU_SCRUB_GROTTO_REAR, {[]{return CanStunDeku;}}), + LocationAccess(SFM_DEKU_SCRUB_GROTTO_FRONT, {[]{return CanStunDeku;}}), + }, { + //Exits + Entrance(SACRED_FOREST_MEADOW, {[]{return true;}}), + }); + + areaTable[LW_BRIDGE_FROM_FOREST] = Area("LW Bridge From Forest", "Lost Woods", THE_LOST_WOODS, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(LW_GIFT_FROM_SARIA, {[]{return true;}}), + }, { + //Exits + Entrance(LW_BRIDGE, {[]{return true;}}), + }); + + areaTable[LW_BRIDGE] = Area("LW Bridge", "Lost Woods", THE_LOST_WOODS, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(KOKIRI_FOREST, {[]{return true;}}), + Entrance(HYRULE_FIELD, {[]{return true;}}), + Entrance(THE_LOST_WOODS, {[]{return CanUse(LONGSHOT);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && Bombs && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE)) || CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::HookshotJump_Bonk, GlitchDifficulty::NOVICE);}}), + }); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_shadow_temple.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_shadow_temple.cpp new file mode 100644 index 000000000..e9216f743 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_shadow_temple.cpp @@ -0,0 +1,189 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" +#include "../dungeon.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_ShadowTemple() { + /*-------------------------- + | VANILLA/MQ DECIDER | + ---------------------------*/ + areaTable[SHADOW_TEMPLE_ENTRYWAY] = Area("Shadow Temple Entryway", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(SHADOW_TEMPLE_BEGINNING, {[]{return Dungeon::ShadowTemple.IsVanilla() && (LogicLensShadow || CanUse(LENS_OF_TRUTH)) && (CanUse(HOVER_BOOTS) || CanUse(HOOKSHOT));}, + /*Glitched*/[]{return Dungeon::ShadowTemple.IsVanilla() && (LogicLensShadow || CanUse(LENS_OF_TRUTH)) && CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::INTERMEDIATE);}}), + Entrance(SHADOW_TEMPLE_MQ_BEGINNING, {[]{return Dungeon::ShadowTemple.IsMQ() && (LogicLensShadowMQ || CanUse(LENS_OF_TRUTH)) && (CanUse(HOVER_BOOTS) || CanUse(HOOKSHOT));}, + /*Glitched*/[]{return Dungeon::ShadowTemple.IsMQ() && (LogicLensShadowMQ || CanUse(LENS_OF_TRUTH)) && CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::INTERMEDIATE);}}), + Entrance(GRAVEYARD_WARP_PAD_REGION, {[]{return true;}}), + }); + + /*-------------------------- + | VANILLA DUNGEON | + ---------------------------*/ + if (Dungeon::ShadowTemple.IsVanilla()) { + areaTable[SHADOW_TEMPLE_BEGINNING] = Area("Shadow Temple Beginning", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&NutPot, {[]{return true;}}), + }, { + //Locations + LocationAccess(SHADOW_TEMPLE_MAP_CHEST, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_HOVER_BOOTS_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(SHADOW_TEMPLE_ENTRYWAY, {[]{return true;}}), + Entrance(SHADOW_TEMPLE_FIRST_BEAMOS, {[]{return HoverBoots;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::NOVICE);}}), + }); + + areaTable[SHADOW_TEMPLE_FIRST_BEAMOS] = Area("Shadow Temple First Beamos", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return true;}}), //This fairy pot is only on 3DS + }, { + //Locations + LocationAccess(SHADOW_TEMPLE_COMPASS_CHEST, {[]{return IsAdult || KokiriSword || Sticks;}}), + LocationAccess(SHADOW_TEMPLE_EARLY_SILVER_RUPEE_CHEST, {[]{return CanUse(HOVER_BOOTS) || CanUse(HOOKSHOT);}}), + LocationAccess(SHADOW_TEMPLE_GS_NEAR_SHIP, {[]{return false;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE) && Longshot;}}), + }, { + //Exits + Entrance(SHADOW_TEMPLE_HUGE_PIT, {[]{return HasExplosives && IsAdult && SmallKeys(SHADOW_TEMPLE, 1, 2);}}), + Entrance(SHADOW_TEMPLE_BEYOND_BOAT, {[]{return false;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE) && Longshot && CanPlay(ZeldasLullaby);}}), + }); + + areaTable[SHADOW_TEMPLE_HUGE_PIT] = Area("Shadow Temple Huge Pit", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SHADOW_TEMPLE_INVISIBLE_BLADES_VISIBLE_CHEST, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_INVISIBLE_BLADES_INVISIBLE_CHEST, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_FALLING_SPIKES_LOWER_CHEST, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_FALLING_SPIKES_UPPER_CHEST, {[]{return LogicShadowUmbrella || GoronBracelet;}}), + LocationAccess(SHADOW_TEMPLE_FALLING_SPIKES_SWITCH_CHEST, {[]{return LogicShadowUmbrella || GoronBracelet;}}), + LocationAccess(SHADOW_TEMPLE_INVISIBLE_SPIKES_CHEST, {[]{return SmallKeys(SHADOW_TEMPLE, 2, 3) && (LogicLensShadowBack || CanUse(LENS_OF_TRUTH));}}), + LocationAccess(SHADOW_TEMPLE_FREESTANDING_KEY, {[]{return SmallKeys(SHADOW_TEMPLE, 2, 3) && (LogicLensShadowBack || CanUse(LENS_OF_TRUTH)) && Hookshot && (Bombs || GoronBracelet || (LogicShadowFreestandingKey && HasBombchus));}}), + LocationAccess(SHADOW_TEMPLE_GS_LIKE_LIKE_ROOM, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_GS_FALLING_SPIKES_ROOM, {[]{return Hookshot;}}), + LocationAccess(SHADOW_TEMPLE_GS_SINGLE_GIANT_POT, {[]{return SmallKeys(SHADOW_TEMPLE, 2, 3) && (LogicLensShadowBack || CanUse(LENS_OF_TRUTH)) && Hookshot;}}), + }, { + //Exits + Entrance(SHADOW_TEMPLE_WIND_TUNNEL, {[]{return (LogicLensShadowBack || CanUse(LENS_OF_TRUTH)) && Hookshot && SmallKeys(SHADOW_TEMPLE, 3, 4);}}), + }); + + areaTable[SHADOW_TEMPLE_WIND_TUNNEL] = Area("Shadow Temple Wind Tunnel", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SHADOW_TEMPLE_WIND_HINT_CHEST, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_AFTER_WIND_ENEMY_CHEST, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_AFTER_WIND_HIDDEN_CHEST, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_GS_NEAR_SHIP, {[]{return CanUse(LONGSHOT) && SmallKeys(SHADOW_TEMPLE, 4, 5);}}), + }, { + //Exits + Entrance(SHADOW_TEMPLE_BEYOND_BOAT, {[]{return CanPlay(ZeldasLullaby) && SmallKeys(SHADOW_TEMPLE, 4, 5);}}), + }); + + areaTable[SHADOW_TEMPLE_BEYOND_BOAT] = Area("Shadow Temple Beyond Boat", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&ShadowTempleClear, {[]{return ShadowTempleClear || (SmallKeys(SHADOW_TEMPLE, 5) && BossKeyShadowTemple && (Bow || CanUse(DISTANT_SCARECROW) || (LogicShadowStatue && HasBombchus)));}}), + }, { + //Locations + LocationAccess(SHADOW_TEMPLE_SPIKE_WALLS_LEFT_CHEST, {[]{return CanUse(DINS_FIRE);}}), + LocationAccess(SHADOW_TEMPLE_BOSS_KEY_CHEST, {[]{return CanUse(DINS_FIRE);}}), + LocationAccess(SHADOW_TEMPLE_INVISIBLE_FLOORMASTER_CHEST, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_BONGO_BONGO_HEART, {[]{return SmallKeys(SHADOW_TEMPLE, 5) && BossKeyShadowTemple && (Bow || CanUse(DISTANT_SCARECROW) || (LogicShadowStatue && HasBombchus));}}), + LocationAccess(BONGO_BONGO, {[]{return SmallKeys(SHADOW_TEMPLE, 5) && BossKeyShadowTemple && (Bow || CanUse(DISTANT_SCARECROW) || (LogicShadowStatue && HasBombchus));}}), + LocationAccess(SHADOW_TEMPLE_GS_TRIPLE_GIANT_POT, {[]{return true;}}), + }, {}); + } + + /*--------------------------- + | MASTER QUEST DUNGEON | + ---------------------------*/ + if (Dungeon::ShadowTemple.IsMQ()) { + areaTable[SHADOW_TEMPLE_MQ_BEGINNING] = Area("Shadow Temple MQ Beginning", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(SHADOW_TEMPLE_ENTRYWAY, {[]{return true;}}), + Entrance(SHADOW_TEMPLE_MQ_FIRST_BEAMOS, {[]{return IsAdult && (CanUse(FIRE_ARROWS) || CanUse(HOVER_BOOTS));}}), + //Trick: IsAdult && (CanUse(FIRE_ARROWS) || HoverBoots || (LogicShadowMQGap && CanUse(LONGSHOT))) + Entrance(SHADOW_TEMPLE_MQ_DEAD_HAND_AREA, {[]{return HasExplosives && SmallKeys(SHADOW_TEMPLE, 6);}}), + }); + + areaTable[SHADOW_TEMPLE_MQ_DEAD_HAND_AREA] = Area("Shadow Temple MQ Dead Hand Area", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SHADOW_TEMPLE_MQ_COMPASS_CHEST, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_MQ_HOVER_BOOTS_CHEST, {[]{return CanPlay(SongOfTime) && IsAdult && CanUse(BOW);}}), + }, {}); + + areaTable[SHADOW_TEMPLE_MQ_FIRST_BEAMOS] = Area("Shadow Temple MQ First Beamos", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SHADOW_TEMPLE_MQ_MAP_CHEST, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_MQ_EARLY_GIBDOS_CHEST, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_MQ_NEAR_SHIP_INVISIBLE_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(SHADOW_TEMPLE_MQ_UPPER_HUGE_PIT, {[]{return HasExplosives && SmallKeys(SHADOW_TEMPLE, 2);}}), + }); + + areaTable[SHADOW_TEMPLE_MQ_UPPER_HUGE_PIT] = Area("Shadow Temple MQ Upper Huge Pit", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_VISIBLE_CHEST, {[]{return CanPlay(SongOfTime);}}), + //Trick: CanPlay(SongOfTime) || (LogicShadowMQInvisibleBlades && DamageMultiplier.IsNot(DAMAGEMULTIPLIER_OHKO)) + LocationAccess(SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_INVISIBLE_CHEST, {[]{return CanPlay(SongOfTime);}}), + //Trick: CanPlay(SongOfTime) || (LogicShadowMQInvisibleBlades && DamageMultiplier.IsNot(DAMAGEMULTIPLIER_OHKO)) + }, { + //Exits + Entrance(SHADOW_TEMPLE_MQ_LOWER_HUGE_PIT, {[]{return HasFireSource;}}), + //Trick: HasFireSource || LogicShadowMQHugePit + }); + + areaTable[SHADOW_TEMPLE_MQ_LOWER_HUGE_PIT] = Area("Shadow Temple MQ Lower Huge Pit", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SHADOW_TEMPLE_MQ_BEAMOS_SILVER_RUPEES_CHEST, {[]{return IsAdult && CanUse(LONGSHOT);}}), + LocationAccess(SHADOW_TEMPLE_MQ_FALLING_SPIKES_LOWER_CHEST, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_MQ_FALLING_SPIKES_UPPER_CHEST, {[]{return (LogicShadowUmbrella && HoverBoots) || GoronBracelet;}}), + LocationAccess(SHADOW_TEMPLE_MQ_FALLING_SPIKES_SWITCH_CHEST, {[]{return (LogicShadowUmbrella && HoverBoots) || GoronBracelet;}}), + LocationAccess(SHADOW_TEMPLE_MQ_INVISIBLE_SPIKES_CHEST, {[]{return HoverBoots && SmallKeys(SHADOW_TEMPLE, 3) && (LogicLensShadowMQBack || CanUse(LENS_OF_TRUTH));}}), + LocationAccess(SHADOW_TEMPLE_MQ_STALFOS_ROOM_CHEST, {[]{return HoverBoots && SmallKeys(SHADOW_TEMPLE, 3) && Hookshot && (LogicLensShadowMQBack || CanUse(LENS_OF_TRUTH));}}), + LocationAccess(SHADOW_TEMPLE_MQ_GS_FALLING_SPIKES_ROOM, {[]{return Hookshot;}}), + }, { + //Exits + Entrance(SHADOW_TEMPLE_MQ_WIND_TUNNEL, {[]{return HoverBoots && (LogicLensShadowMQBack || CanUse(LENS_OF_TRUTH)) && Hookshot && SmallKeys(SHADOW_TEMPLE, 4);}}), + }); + + areaTable[SHADOW_TEMPLE_MQ_WIND_TUNNEL] = Area("Shadow Temple MQ Wind Tunnel", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&NutPot, {[]{return true;}}), + }, { + //Locations + LocationAccess(SHADOW_TEMPLE_MQ_WIND_HINT_CHEST, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_MQ_AFTER_WIND_ENEMY_CHEST, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_MQ_AFTER_WIND_HIDDEN_CHEST, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_MQ_GS_WIND_HINT_ROOM, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_MQ_GS_AFTER_WIND, {[]{return true;}}), + }, { + //Exits + Entrance(SHADOW_TEMPLE_MQ_BEYOND_BOAT, {[]{return CanPlay(ZeldasLullaby) && SmallKeys(SHADOW_TEMPLE, 5);}}), + }); + + areaTable[SHADOW_TEMPLE_MQ_BEYOND_BOAT] = Area("Shadow Temple MQ Beyond Boat", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&ShadowTempleClear, {[]{return ShadowTempleClear || ((Bow || (LogicShadowStatue && HasBombchus)) && BossKeyShadowTemple);}}), + }, { + //Locations + LocationAccess(SHADOW_TEMPLE_BONGO_BONGO_HEART, {[]{return (Bow || (LogicShadowStatue && HasBombchus)) && BossKeyShadowTemple;}}), + LocationAccess(BONGO_BONGO, {[]{return (Bow || (LogicShadowStatue && HasBombchus)) && BossKeyShadowTemple;}}), + LocationAccess(SHADOW_TEMPLE_MQ_GS_AFTER_SHIP, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_MQ_GS_NEAR_BOSS, {[]{return Bow || (LogicShadowStatue && HasBombchus);}}), + }, { + //Exits + Entrance(SHADOW_TEMPLE_MQ_INVISIBLE_MAZE, {[]{return Bow && CanPlay(SongOfTime) && IsAdult && CanUse(LONGSHOT);}}), + }); + + areaTable[SHADOW_TEMPLE_MQ_INVISIBLE_MAZE] = Area("Shadow Temple MQ Invisible Maze", "Shadow Temple", SHADOW_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SHADOW_TEMPLE_MQ_SPIKE_WALLS_LEFT_CHEST, {[]{return CanUse(DINS_FIRE) && SmallKeys(SHADOW_TEMPLE, 6);}}), + LocationAccess(SHADOW_TEMPLE_MQ_BOSS_KEY_CHEST, {[]{return CanUse(DINS_FIRE) && SmallKeys(SHADOW_TEMPLE, 6);}}), + LocationAccess(SHADOW_TEMPLE_MQ_BOMB_FLOWER_CHEST, {[]{return true;}}), + LocationAccess(SHADOW_TEMPLE_MQ_FREESTANDING_KEY, {[]{return true;}}), + }, {}); + } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_spirit_temple.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_spirit_temple.cpp new file mode 100644 index 000000000..4bfd7c269 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_spirit_temple.cpp @@ -0,0 +1,232 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" +#include "../dungeon.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_SpiritTemple() { + /*-------------------------- + | VANILLA/MQ DECIDER | + ---------------------------*/ + areaTable[SPIRIT_TEMPLE_ENTRYWAY] = Area("Spirit Temple Entryway", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(SPIRIT_TEMPLE_LOBBY, {[]{return Dungeon::SpiritTemple.IsVanilla();}}), + Entrance(SPIRIT_TEMPLE_MQ_LOBBY, {[]{return Dungeon::SpiritTemple.IsMQ();}}), + Entrance(DESERT_COLOSSUS, {[]{return true;}}), + }); + + /*-------------------------- + | VANILLA DUNGEON | + ---------------------------*/ + if (Dungeon::SpiritTemple.IsVanilla()) { + areaTable[SPIRIT_TEMPLE_LOBBY] = Area("Spirit Temple Lobby", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(SPIRIT_TEMPLE_ENTRYWAY, {[]{return true;}}), + Entrance(SPIRIT_TEMPLE_CHILD, {[]{return IsChild;}}), + Entrance(SPIRIT_TEMPLE_EARLY_ADULT, {[]{return CanUse(SILVER_GAUNTLETS);}}), + }); + + areaTable[SPIRIT_TEMPLE_CHILD] = Area("Child Spirit Temple", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&NutCrate, {[]{return true;}}), + }, { + //Locations + LocationAccess(SPIRIT_TEMPLE_CHILD_BRIDGE_CHEST, {[]{return (Boomerang || Slingshot || (HasExplosives && LogicSpiritChildBombchu)) && (HasExplosives || ((Nuts || Boomerang) && (Sticks || KokiriSword || Slingshot)));}}), + LocationAccess(SPIRIT_TEMPLE_CHILD_EARLY_TORCHES_CHEST, {[]{return (Boomerang || Slingshot || (HasExplosives && LogicSpiritChildBombchu)) && (HasExplosives || ((Nuts || Boomerang) && (Sticks || KokiriSword || Slingshot))) && (Sticks || CanUse(DINS_FIRE));}}), + LocationAccess(SPIRIT_TEMPLE_GS_METAL_FENCE, {[]{return (Boomerang || Slingshot || (HasExplosives && LogicSpiritChildBombchu)) && (HasExplosives || ((Nuts || Boomerang) && (Sticks || KokiriSword || Slingshot)));}}), + }, { + //Exits + Entrance(SPIRIT_TEMPLE_CHILD_CLIMB, {[]{return SmallKeys(SPIRIT_TEMPLE, 1);}}), + }); + + areaTable[SPIRIT_TEMPLE_CHILD_CLIMB] = Area("Child Spirit Temple Climb", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SPIRIT_TEMPLE_CHILD_CLIMB_NORTH_CHEST, {[]{return HasProjectile(HasProjectileAge::Both) || ((SmallKeys(SPIRIT_TEMPLE, 3) || (SmallKeys(SPIRIT_TEMPLE, 2) && BombchusInLogic && ShuffleDungeonEntrances.Is(SHUFFLEDUNGEONS_OFF))) && CanUse(SILVER_GAUNTLETS) && HasProjectile(HasProjectileAge::Adult)) || (SmallKeys(SPIRIT_TEMPLE, 5) && IsChild && HasProjectile(HasProjectileAge::Child));}}), + LocationAccess(SPIRIT_TEMPLE_CHILD_CLIMB_EAST_CHEST, {[]{return HasProjectile(HasProjectileAge::Both) || ((SmallKeys(SPIRIT_TEMPLE, 3) || (SmallKeys(SPIRIT_TEMPLE, 2) && BombchusInLogic && ShuffleDungeonEntrances.Is(SHUFFLEDUNGEONS_OFF))) && CanUse(SILVER_GAUNTLETS) && HasProjectile(HasProjectileAge::Adult)) || (SmallKeys(SPIRIT_TEMPLE, 5) && IsChild && HasProjectile(HasProjectileAge::Child));}}), + LocationAccess(SPIRIT_TEMPLE_GS_SUN_ON_FLOOR_ROOM, {[]{return HasProjectile(HasProjectileAge::Both) || CanUse(DINS_FIRE) || + (CanTakeDamage && (Sticks || KokiriSword || HasProjectile(HasProjectileAge::Child))) || + (IsChild && SmallKeys(SPIRIT_TEMPLE, 5) && HasProjectile(HasProjectileAge::Child)) || + ((SmallKeys(SPIRIT_TEMPLE, 3) || (SmallKeys(SPIRIT_TEMPLE, 2) && BombchusInLogic && ShuffleDungeonEntrances.Is(SHUFFLEDUNGEONS_OFF))) && CanUse(SILVER_GAUNTLETS) && (HasProjectile(HasProjectileAge::Adult) || CanTakeDamage));}}), + }, { + //Exits + Entrance(SPIRIT_TEMPLE_CENTRAL_CHAMBER, {[]{return HasExplosives;}}), + }); + + areaTable[SPIRIT_TEMPLE_EARLY_ADULT] = Area("Early Adult Spirit Temple", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SPIRIT_TEMPLE_COMPASS_CHEST, {[]{return CanUse(HOOKSHOT) && CanPlay(ZeldasLullaby);}}), + LocationAccess(SPIRIT_TEMPLE_EARLY_ADULT_RIGHT_CHEST, {[]{return Bow || Hookshot || HasBombchus || (Bombs && LogicSpiritLowerAdultSwitch);}}), + LocationAccess(SPIRIT_TEMPLE_FIRST_MIRROR_LEFT_CHEST, {[]{return SmallKeys(SPIRIT_TEMPLE, 3);}}), + LocationAccess(SPIRIT_TEMPLE_FIRST_MIRROR_RIGHT_CHEST, {[]{return SmallKeys(SPIRIT_TEMPLE, 3);}}), + LocationAccess(SPIRIT_TEMPLE_GS_BOULDER_ROOM, {[]{return CanPlay(SongOfTime) && (Bow || Hookshot || HasBombchus || (Bombs && LogicSpiritLowerAdultSwitch));}}), + }, { + //Exits + Entrance(SPIRIT_TEMPLE_CENTRAL_CHAMBER, {[]{return SmallKeys(SPIRIT_TEMPLE, 1);}}), + }); + + areaTable[SPIRIT_TEMPLE_CENTRAL_CHAMBER] = Area("Spirit Temple Central Chamber", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SPIRIT_TEMPLE_MAP_CHEST, {[]{return ((HasExplosives || SmallKeys(SPIRIT_TEMPLE, 3) || (SmallKeys(SPIRIT_TEMPLE, 2) && BombchusInLogic && ShuffleDungeonEntrances.Is(SHUFFLEDUNGEONS_OFF))) && + + (CanUse(DINS_FIRE) || + (((MagicMeter && FireArrows) || LogicSpiritMapChest) && Bow && Sticks))) || + (SmallKeys(SPIRIT_TEMPLE, 5) && HasExplosives && + CanUse(STICKS)) || + (SmallKeys(SPIRIT_TEMPLE, 3) && + (CanUse(FIRE_ARROWS) || (LogicSpiritMapChest && Bow)) && + CanUse(SILVER_GAUNTLETS));}}), + LocationAccess(SPIRIT_TEMPLE_SUN_BLOCK_ROOM_CHEST, {[]{return ((HasExplosives || SmallKeys(SPIRIT_TEMPLE, 3) || (SmallKeys(SPIRIT_TEMPLE, 2) && BombchusInLogic && ShuffleDungeonEntrances.Is(SHUFFLEDUNGEONS_OFF))) && + (CanUse(DINS_FIRE) || + (((MagicMeter && FireArrows) || LogicSpiritSunChest) && Bow && Sticks))) || + (SmallKeys(SPIRIT_TEMPLE, 5) && HasExplosives && + CanUse(STICKS)) || + (SmallKeys(SPIRIT_TEMPLE, 3) && + (CanUse(FIRE_ARROWS) || (LogicSpiritSunChest && Bow)) && + CanUse(SILVER_GAUNTLETS));}}), + LocationAccess(SPIRIT_TEMPLE_STATUE_ROOM_HAND_CHEST, {[]{return SmallKeys(SPIRIT_TEMPLE, 3) && CanUse(SILVER_GAUNTLETS) && CanPlay(ZeldasLullaby);}}), + LocationAccess(SPIRIT_TEMPLE_STATUE_ROOM_NORTHEAST_CHEST, {[]{return SmallKeys(SPIRIT_TEMPLE, 3) && CanUse(SILVER_GAUNTLETS) && CanPlay(ZeldasLullaby) && (Hookshot || HoverBoots);}}), + LocationAccess(SPIRIT_TEMPLE_GS_HALL_AFTER_SUN_BLOCK_ROOM, {[]{return (HasExplosives && Boomerang && Hookshot) || + (CanUse(BOOMERANG) && SmallKeys(SPIRIT_TEMPLE, 5) && HasExplosives) || + (Hookshot && CanUse(SILVER_GAUNTLETS) && + (SmallKeys(SPIRIT_TEMPLE, 3) || + (SmallKeys(SPIRIT_TEMPLE, 2) && Boomerang && BombchusInLogic && ShuffleDungeonEntrances.Is(SHUFFLEDUNGEONS_OFF))));}}), + LocationAccess(SPIRIT_TEMPLE_GS_LOBBY, {[]{return ((HasExplosives || SmallKeys(SPIRIT_TEMPLE, 3) || (SmallKeys(SPIRIT_TEMPLE, 2) && BombchusInLogic && ShuffleDungeonEntrances.Is(SHUFFLEDUNGEONS_OFF))) && + LogicSpiritLobbyGS && Boomerang && (Hookshot || HoverBoots)) || + (LogicSpiritLobbyGS && SmallKeys(SPIRIT_TEMPLE, 5) && HasExplosives && CanUse(BOOMERANG)) || + (SmallKeys(SPIRIT_TEMPLE, 3) && CanUse(SILVER_GAUNTLETS) && (Hookshot || HoverBoots));}}), + }, { + //Exits + Entrance(SPIRIT_TEMPLE_OUTDOOR_HANDS, {[]{return true;}}), + Entrance(SPIRIT_TEMPLE_BEYOND_CENTRAL_LOCKED_DOOR, {[]{return SmallKeys(SPIRIT_TEMPLE, 4) && CanUse(SILVER_GAUNTLETS);}}), + Entrance(SPIRIT_TEMPLE_CHILD_CLIMB, {[]{return true;}}), + }); + + areaTable[SPIRIT_TEMPLE_OUTDOOR_HANDS] = Area("Spirit Temple Outdoor Hands", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SPIRIT_TEMPLE_SILVER_GAUNTLETS_CHEST, {[]{return (SmallKeys(SPIRIT_TEMPLE, 3) && Longshot && HasExplosives) || SmallKeys(SPIRIT_TEMPLE, 5);}}), + LocationAccess(SPIRIT_TEMPLE_MIRROR_SHIELD_CHEST, {[]{return SmallKeys(SPIRIT_TEMPLE, 4) && CanUse(SILVER_GAUNTLETS) && HasExplosives;}}), + }, { + //Exits + Entrance(DESERT_COLOSSUS, {[]{return (IsChild && SmallKeys(SPIRIT_TEMPLE, 5)) || (CanUse(SILVER_GAUNTLETS) && ((SmallKeys(SPIRIT_TEMPLE, 3) && HasExplosives) || SmallKeys(SPIRIT_TEMPLE, 5)));}}), + }); + + areaTable[SPIRIT_TEMPLE_BEYOND_CENTRAL_LOCKED_DOOR] = Area("Spirit Temple Beyond Central Locked Door", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SPIRIT_TEMPLE_NEAR_FOUR_ARMOS_CHEST, {[]{return MirrorShield && HasExplosives;}}), + LocationAccess(SPIRIT_TEMPLE_HALLWAY_LEFT_INVISIBLE_CHEST, {[]{return (LogicLensSpirit || CanUse(LENS_OF_TRUTH)) && HasExplosives;}}), + LocationAccess(SPIRIT_TEMPLE_HALLWAY_RIGHT_INVISIBLE_CHEST, {[]{return (LogicLensSpirit || CanUse(LENS_OF_TRUTH)) && HasExplosives;}}), + }, { + //Exits + Entrance(SPIRIT_TEMPLE_BEYOND_FINAL_LOCKED_DOOR, {[]{return SmallKeys(SPIRIT_TEMPLE, 5) && (LogicSpiritWall || CanUse(LONGSHOT) || HasBombchus || ((Bombs || Nuts || CanUse(DINS_FIRE)) && (Bow || CanUse(HOOKSHOT) || Hammer)));}}), + }); + + areaTable[SPIRIT_TEMPLE_BEYOND_FINAL_LOCKED_DOOR] = Area("Spirit Temple Beyond Final Locked Door", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&SpiritTempleClear, {[]{return SpiritTempleClear || (MirrorShield && HasExplosives && Hookshot && BossKeySpiritTemple);}}), + }, { + //Locations + LocationAccess(SPIRIT_TEMPLE_BOSS_KEY_CHEST, {[]{return CanPlay(ZeldasLullaby) && ((CanTakeDamage && LogicFlamingChests) || (Bow && Hookshot));}}), + LocationAccess(SPIRIT_TEMPLE_TOPMOST_CHEST, {[]{return MirrorShield;}}), + LocationAccess(SPIRIT_TEMPLE_TWINROVA_HEART, {[]{return MirrorShield && HasExplosives && Hookshot && BossKeySpiritTemple;}}), + LocationAccess(TWINROVA, {[]{return MirrorShield && HasExplosives && Hookshot && BossKeySpiritTemple;}}), + }, {}); + } + + /*--------------------------- + | MASTER QUEST DUNGEON | + ---------------------------*/ + if (Dungeon::SpiritTemple.IsMQ()) { + areaTable[SPIRIT_TEMPLE_MQ_LOBBY] = Area("Spirit Temple MQ Lobby", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_LEFT_CHEST, {[]{return true;}}), + LocationAccess(SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_LEFT_CHEST, {[]{return Here(SPIRIT_TEMPLE_MQ_LOBBY, []{return CanBlastOrSmash;}) && ((IsChild && CanUse(SLINGSHOT)) || (IsAdult && CanUse(BOW)));}}), + LocationAccess(SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_RIGHT_CHEST, {[]{return HasBombchus || (IsAdult && (CanUse(BOW) || CanUse(HOOKSHOT))) || (IsChild && (CanUse(SLINGSHOT) || CanUse(BOOMERANG)));}}), + }, { + //Exits + Entrance(SPIRIT_TEMPLE_ENTRYWAY, {[]{return true;}}), + Entrance(SPIRIT_TEMPLE_MQ_CHILD, {[]{return IsChild;}}), + Entrance(SPIRIT_TEMPLE_MQ_ADULT, {[]{return HasBombchus && IsAdult && CanUse(LONGSHOT) && CanUse(SILVER_GAUNTLETS);}}), + }); + + areaTable[SPIRIT_TEMPLE_MQ_CHILD] = Area("Spirit Temple MQ Child", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return FairyPot || (KokiriSword && HasBombchus && Slingshot);}}), + }, { + //Locations + LocationAccess(SPIRIT_TEMPLE_MQ_CHILD_HAMMER_SWITCH_CHEST, {[]{return Here(SPIRIT_TEMPLE_MQ_ADULT, []{return SmallKeys(SPIRIT_TEMPLE, 7) && Hammer;});}}), + LocationAccess(SPIRIT_TEMPLE_MQ_MAP_ROOM_ENEMY_CHEST, {[]{return KokiriSword && HasBombchus && Slingshot && CanUse(DINS_FIRE);}}), + LocationAccess(SPIRIT_TEMPLE_MQ_MAP_CHEST, {[]{return KokiriSword || Bombs;}}), + LocationAccess(SPIRIT_TEMPLE_MQ_SILVER_BLOCK_HALLWAY_CHEST, {[]{return HasBombchus && SmallKeys(SPIRIT_TEMPLE, 7) && Slingshot && (CanUse(DINS_FIRE) || (Here(SPIRIT_TEMPLE_MQ_ADULT, []{return IsAdult && CanUse(FIRE_ARROWS);})));}}), + //Trick: HasBombchus && SmallKeys(SPIRIT_TEMPLE, 7) && Slingshot && (CanUse(DINS_FIRE) || (SPIRIT_TEMPLE_MQ_ADULT.Adult() && IsAdult && (CanUse(FIRE_ARROWS) || (LogicSpiritMQFrozenEye && CanUse(BOW) && CanPlay(SongOfTime))))) + }, { + //Exits + Entrance(SPIRIT_TEMPLE_MQ_SHARED, {[]{return HasBombchus && SmallKeys(SPIRIT_TEMPLE, 2);}}), + }); + + areaTable[SPIRIT_TEMPLE_MQ_ADULT] = Area("Spirit Temple MQ Adult", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SPIRIT_TEMPLE_MQ_CHILD_CLIMB_SOUTH_CHEST, {[]{return SmallKeys(SPIRIT_TEMPLE, 7);}}), + LocationAccess(SPIRIT_TEMPLE_MQ_STATUE_ROOM_LULLABY_CHEST, {[]{return CanPlay(ZeldasLullaby);}}), + LocationAccess(SPIRIT_TEMPLE_MQ_STATUE_ROOM_INVISIBLE_CHEST, {[]{return (LogicLensSpiritMQ || CanUse(LENS_OF_TRUTH));}}), + LocationAccess(SPIRIT_TEMPLE_MQ_BEAMOS_ROOM_CHEST, {[]{return SmallKeys(SPIRIT_TEMPLE, 5);}}), + LocationAccess(SPIRIT_TEMPLE_MQ_CHEST_SWITCH_CHEST, {[]{return SmallKeys(SPIRIT_TEMPLE, 5) && CanPlay(SongOfTime);}}), + LocationAccess(SPIRIT_TEMPLE_MQ_BOSS_KEY_CHEST, {[]{return SmallKeys(SPIRIT_TEMPLE, 5) && CanPlay(SongOfTime) && MirrorShield;}}), + LocationAccess(SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_WEST, {[]{return SmallKeys(SPIRIT_TEMPLE, 7);}}), + LocationAccess(SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_NORTH, {[]{return SmallKeys(SPIRIT_TEMPLE, 7);}}), + }, { + //Exits + Entrance(SPIRIT_TEMPLE_MQ_LOWER_ADULT, {[]{return MirrorShield && IsAdult && CanUse(FIRE_ARROWS);}}), + //Trick: MirrorShield && IsAdult && (CanUse(FIRE_ARROWS) || (LogicSpiritMQLowerAdult && CanUse(DINS_FIRE) && Bow)) + Entrance(SPIRIT_TEMPLE_MQ_SHARED, {[]{return true;}}), + Entrance(SPIRIT_TEMPLE_MQ_BOSS_AREA, {[]{return SmallKeys(SPIRIT_TEMPLE, 6) && CanPlay(ZeldasLullaby) && Hammer;}}), + Entrance(SPIRIT_TEMPLE_MQ_MIRROR_SHIELD_HAND, {[]{return SmallKeys(SPIRIT_TEMPLE, 5) && CanPlay(SongOfTime) && (LogicLensSpiritMQ || CanUse(LENS_OF_TRUTH));}}), + }); + + areaTable[SPIRIT_TEMPLE_MQ_SHARED] = Area("Spirit Temple MQ Shared", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SPIRIT_TEMPLE_MQ_CHILD_CLIMB_NORTH_CHEST, {[]{return SmallKeys(SPIRIT_TEMPLE, 6);}}), + LocationAccess(SPIRIT_TEMPLE_MQ_COMPASS_CHEST, {[]{return (IsChild && CanUse(SLINGSHOT) && SmallKeys(SPIRIT_TEMPLE, 7)) || (IsAdult && CanUse(BOW)) || (Bow && Slingshot);}}), + LocationAccess(SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM_CHEST, {[]{return CanPlay(SongOfTime) || IsAdult;}}), + //Trick: CanPlay(SongOfTime) || LogicSpiritMQSunBlockSoT || IsAdult + LocationAccess(SPIRIT_TEMPLE_MQ_GS_SUN_BLOCK_ROOM, {[]{return IsAdult;}}), + //Trick: (LogicSpiritMQSunBlockGS && Boomerange && (CanPlay(SongOfTime) || LogicSpiritMQSunBlockSoT)) || IsAdult + }, { + //Exits + Entrance(SPIRIT_TEMPLE_MQ_SILVER_GAUNTLETS_HAND, {[]{return (SmallKeys(SPIRIT_TEMPLE, 7) && (CanPlay(SongOfTime) || IsAdult)) || (SmallKeys(SPIRIT_TEMPLE, 4) && CanPlay(SongOfTime) && (LogicLensSpiritMQ || CanUse(LENS_OF_TRUTH)));}}), + //Trick: (SmallKeys(SPIRIT_TEMPLE, 7) && (CanPlay(SongOfTime) || LogicSpiritMQSunBlockSoT || IsAdult)) || (SmallKeys(SPIRIT_TEMPLE, 4) && CanPlay(SongOfTime) && (LogicLensSpiritMQ || CanUse(LENS_OF_TRUTH))) + Entrance(DESERT_COLOSSUS, {[]{return (SmallKeys(SPIRIT_TEMPLE, 7) && (CanPlay(SongOfTime) || IsAdult)) || (SmallKeys(SPIRIT_TEMPLE, 4) && CanPlay(SongOfTime) && (LogicLensSpiritMQ || CanUse(LENS_OF_TRUTH)) && IsAdult);}}), + //Trick: (SmallKeys(SPIRIT_TEMPLE, 7) && (CanPlay(SongOfTime) || LogicSpiritMQSunBlockSoT || IsAdult)) || (SmallKeys(SPIRIT_TEMPLE, 4) && CanPlay(SongOfTime) && (LogicLensSpiritMQ || CanUse(LENS_OF_TRUTH)) && IsAdult) + }); + + areaTable[SPIRIT_TEMPLE_MQ_LOWER_ADULT] = Area("Spirit Temple MQ Lower Adult", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SPIRIT_TEMPLE_MQ_LEEVER_ROOM_CHEST, {[]{return true;}}), + LocationAccess(SPIRIT_TEMPLE_MQ_SYMPHONY_ROOM_CHEST, {[]{return SmallKeys(SPIRIT_TEMPLE, 7) && Hammer && Ocarina && SongOfTime && EponasSong && SunsSong && SongOfStorms && ZeldasLullaby;}}), + LocationAccess(SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_RIGHT_CHEST, {[]{return Hammer;}}), + LocationAccess(SPIRIT_TEMPLE_MQ_GS_LEEVER_ROOM, {[]{return true;}}), + LocationAccess(SPIRIT_TEMPLE_MQ_GS_SYMPHONY_ROOM, {[]{return SmallKeys(SPIRIT_TEMPLE, 7) && Hammer && Ocarina && SongOfTime && EponasSong && SunsSong && SongOfStorms && ZeldasLullaby;}}), + }, {}); + + areaTable[SPIRIT_TEMPLE_MQ_BOSS_AREA] = Area("Spirit Temple MQ Boss Area", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&SpiritTempleClear, {[]{return SpiritTempleClear || (MirrorShield && BossKeySpiritTemple);}}), + }, { + //Locations + LocationAccess(SPIRIT_TEMPLE_MQ_MIRROR_PUZZLE_INVISIBLE_CHEST, {[]{return LogicLensSpiritMQ || CanUse(LENS_OF_TRUTH);}}), + LocationAccess(SPIRIT_TEMPLE_TWINROVA_HEART, {[]{return MirrorShield && BossKeySpiritTemple;}}), + LocationAccess(TWINROVA, {[]{return MirrorShield && BossKeySpiritTemple;}}), + }, {}); + + areaTable[SPIRIT_TEMPLE_MQ_MIRROR_SHIELD_HAND] = Area("Spirit Temple MQ Mirror Shield Hand", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SPIRIT_TEMPLE_MIRROR_SHIELD_CHEST, {[]{return true;}}), + }, {}); + + areaTable[SPIRIT_TEMPLE_MQ_SILVER_GAUNTLETS_HAND] = Area("Spirit Temple MQ Silver Gauntlets Hand", "Spirit Temple", SPIRIT_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(SPIRIT_TEMPLE_SILVER_GAUNTLETS_CHEST, {[]{return true;}}), + }, {}); + } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_water_temple.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_water_temple.cpp new file mode 100644 index 000000000..d2f566b2c --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_water_temple.cpp @@ -0,0 +1,351 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" +#include "../dungeon.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_WaterTemple() { + /*-------------------------- + | VANILLA/MQ DECIDER | + ---------------------------*/ + areaTable[WATER_TEMPLE_ENTRYWAY] = Area("Water Temple Entryway", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(WATER_TEMPLE_LOBBY, {[]{return Dungeon::WaterTemple.IsVanilla();}}), + Entrance(WATER_TEMPLE_MQ_LOBBY, {[]{return Dungeon::WaterTemple.IsMQ();}}), + Entrance(LAKE_HYLIA, {[]{return true;}}), + }); + + /*-------------------------- + | VANILLA DUNGEON | + ---------------------------*/ + if (Dungeon::WaterTemple.IsVanilla()) { + //Water Temple logic currently assumes that the locked door leading to the upper water raising location is unlocked from the start + areaTable[WATER_TEMPLE_LOBBY] = Area("Water Temple Lobby", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(WATER_TEMPLE_ENTRYWAY, {[]{return true;}}), + Entrance(WATER_TEMPLE_EAST_LOWER, {[]{return WaterTempleLow || ((LogicFewerTunicRequirements || CanUse(ZORA_TUNIC)) && (CanUse(IRON_BOOTS) || (CanUse(LONGSHOT) && LogicWaterTempleTorchLongshot)));}, + /*Glitched*/[]{return ((Bugs || Fish) && CanUse(HOVER_BOOTS) && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::INTERMEDIATE)) || (CanUse(FARORES_WIND) && + ((CanUse(NAYRUS_LOVE) && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::NOVICE)) || (CanUseMagicArrow && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::ADVANCED))));}}), + Entrance(WATER_TEMPLE_NORTH_LOWER, {[]{return WaterTempleLow || ((LogicFewerTunicRequirements || CanUse(ZORA_TUNIC)) && CanUse(IRON_BOOTS));}}), + Entrance(WATER_TEMPLE_SOUTH_LOWER, {[]{return WaterTempleLow && HasExplosives && (CanDive || CanUse(IRON_BOOTS)) && (LogicFewerTunicRequirements || CanUse(ZORA_TUNIC));}, + /*Glitched*/[]{return CanUse(IRON_BOOTS) && (WaterTempleMiddle || WaterTempleHigh) && (LogicFewerTunicRequirements || CanUse(ZORA_TUNIC)) && AdultCanAccess(WATER_TEMPLE_WEST_LOWER) && CanDoGlitch(GlitchType::LedgeClip, GlitchDifficulty::INTERMEDIATE);}}), + Entrance(WATER_TEMPLE_WEST_LOWER, {[]{return WaterTempleLow && GoronBracelet && (IsChild || CanDive || CanUse(IRON_BOOTS)) && (LogicFewerTunicRequirements || CanUse(ZORA_TUNIC));}}), + Entrance(WATER_TEMPLE_CENTRAL_PILLAR_LOWER, {[]{return WaterTempleLow && SmallKeys(WATER_TEMPLE, 5);}}), + Entrance(WATER_TEMPLE_CENTRAL_PILLAR_UPPER, {[]{return (WaterTempleLow || WaterTempleMiddle) && (HasFireSourceWithTorch || CanUse(BOW));}}), + Entrance(WATER_TEMPLE_EAST_MIDDLE, {[]{return (WaterTempleLow || WaterTempleMiddle || (CanUse(IRON_BOOTS) && WaterTimer >= 16)) && CanUse(HOOKSHOT);}}), + Entrance(WATER_TEMPLE_WEST_MIDDLE, {[]{return WaterTempleMiddle;}, + /*Glitched*/[]{return WaterTempleLow && (CanDoGlitch(GlitchType::HammerSlide, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::INTERMEDIATE));}}), + Entrance(WATER_TEMPLE_HIGH_WATER, {[]{return IsAdult && (CanUse(HOVER_BOOTS) || (LogicWaterTempleUpperBoost && Bombs && CanTakeDamage));}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::INTERMEDIATE) || (Bombs && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE));}}), + Entrance(WATER_TEMPLE_BLOCK_CORRIDOR, {[]{return (WaterTempleLow || WaterTempleMiddle) && (CanUse(SLINGSHOT) || CanUse(BOW)) && (CanUse(LONGSHOT) || CanUse(HOVER_BOOTS) || (LogicWaterCentralBow && (IsAdult || WaterTempleMiddle)));}, + /*Glitched*/[]{return (WaterTempleLow || WaterTempleMiddle) && IsAdult && CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::INTERMEDIATE);}}), + Entrance(WATER_TEMPLE_FALLING_PLATFORM_ROOM, {[]{return WaterTempleHigh && SmallKeys(WATER_TEMPLE, 4);}, + /*Glitched*/[]{return SmallKeys(WATER_TEMPLE, 4) && (CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::HammerSlide, GlitchDifficulty::NOVICE));}}), + Entrance(WATER_TEMPLE_PRE_BOSS_ROOM, {[]{return WaterTempleHigh && CanUse(LONGSHOT);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::HammerSlide, GlitchDifficulty::NOVICE) || + (Bombs && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE));}}), + }); + + areaTable[WATER_TEMPLE_EAST_LOWER] = Area("Water Temple East Lower", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&WaterTempleLow, {[]{return WaterTempleLow || CanPlay(ZeldasLullaby);}, + /*Glitched*/[]{return ZeldasLullaby && (CanDoGlitch(GlitchType::DungeonBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && + ((Bombs && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || (HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED)))));}}), + }, {}, { + //Exits + Entrance(WATER_TEMPLE_LOBBY, {[]{return WaterTempleLow || ((LogicFewerTunicRequirements || CanUse(ZORA_TUNIC)) && CanUse(IRON_BOOTS));}, + /*Glitched*/[]{return ((Bugs || Fish) && CanUse(HOVER_BOOTS) && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::INTERMEDIATE)) || (CanUse(FARORES_WIND) && + ((CanUse(NAYRUS_LOVE) && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::NOVICE)) || (CanUseMagicArrow && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::ADVANCED))));}}), + Entrance(WATER_TEMPLE_MAP_ROOM, {[]{return WaterTempleHigh;}}), + Entrance(WATER_TEMPLE_CRACKED_WALL, {[]{return WaterTempleMiddle || (WaterTempleHigh && WaterTempleLow && ((CanUse(HOVER_BOOTS) && LogicWaterCrackedWallHovers) || LogicWaterCrackedWallNothing));}, + /*Glitched*/[]{return WaterTempleHigh && WaterTempleLow && CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE);}}), + Entrance(WATER_TEMPLE_TORCH_ROOM, {[]{return WaterTempleLow && (HasFireSourceWithTorch || CanUse(BOW));}}), + }); + + areaTable[WATER_TEMPLE_MAP_ROOM] = Area("Water Temple Map Room", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(WATER_TEMPLE_MAP_CHEST, {[]{return (MagicMeter && CanUse(KOKIRI_SWORD)) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || CanUse(HOOKSHOT);}}), + }, { + //Exits + Entrance(WATER_TEMPLE_EAST_LOWER, {[]{return (MagicMeter && CanUse(KOKIRI_SWORD)) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || CanUse(HOOKSHOT);}}), + }); + + areaTable[WATER_TEMPLE_CRACKED_WALL] = Area("Water Temple Cracked Wall", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(WATER_TEMPLE_CRACKED_WALL_CHEST, {[]{return HasExplosives;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE);}}), + }, { + //Exits + Entrance(WATER_TEMPLE_EAST_LOWER, {[]{return true;}}), + }); + + areaTable[WATER_TEMPLE_TORCH_ROOM] = Area("Water Temple Torch Room", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(WATER_TEMPLE_TORCHES_CHEST, {[]{return (MagicMeter && CanUse(KOKIRI_SWORD)) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || CanUse(HOOKSHOT);}}), + }, { + //Exits + Entrance(WATER_TEMPLE_EAST_LOWER, {[]{return (MagicMeter && CanUse(KOKIRI_SWORD)) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD) || CanUse(HOOKSHOT);}}), + }); + + areaTable[WATER_TEMPLE_NORTH_LOWER] = Area("Water Temple North Lower", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(WATER_TEMPLE_LOBBY, {[]{return true;}}), + Entrance(WATER_TEMPLE_BOULDERS_LOWER, {[]{return (CanUse(LONGSHOT) || (LogicWaterBossKeyRegion && CanUse(HOVER_BOOTS))) && SmallKeys(WATER_TEMPLE, 4);}, + /*Glitched*/[]{return ((Bombs && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE)) || + CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::INTERMEDIATE)) && SmallKeys(WATER_TEMPLE, 4);}}), + }); + + areaTable[WATER_TEMPLE_BOULDERS_LOWER] = Area("Water Temple Boulders Lower", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(WATER_TEMPLE_GS_NEAR_BOSS_KEY_CHEST, {[]{return CanUse(LONGSHOT) || Here(WATER_TEMPLE_BOULDERS_UPPER, []{return (IsAdult && HookshotOrBoomerang) || (CanUse(IRON_BOOTS) && CanUse(HOOKSHOT));});}}), + }, { + //Exits + Entrance(WATER_TEMPLE_NORTH_LOWER, {[]{return SmallKeys(WATER_TEMPLE, 4);}}), + Entrance(WATER_TEMPLE_BLOCK_ROOM, {[]{return true;}}), + Entrance(WATER_TEMPLE_BOULDERS_UPPER, {[]{return (IsAdult && (CanUse(HOVER_BOOTS) || LogicWaterNorthBasementLedgeJump)) || (CanUse(HOVER_BOOTS) && CanUse(IRON_BOOTS));}}), + }); + + areaTable[WATER_TEMPLE_BLOCK_ROOM] = Area("Water Temple Block Room", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(WATER_TEMPLE_BOULDERS_LOWER, {[]{return (GoronBracelet && HasExplosives) || CanUse(HOOKSHOT);}}), + Entrance(WATER_TEMPLE_JETS_ROOM, {[]{return (GoronBracelet && HasExplosives) || (CanUse(HOOKSHOT) && CanUse(HOVER_BOOTS));}, + /*Glitched*/[]{return CanUse(HOOKSHOT) && CanDoGlitch(GlitchType::Megaflip, GlitchDifficulty::INTERMEDIATE);}}), + }); + + areaTable[WATER_TEMPLE_JETS_ROOM] = Area("Water Temple Jets Room", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(WATER_TEMPLE_BLOCK_ROOM, {[]{return CanUse(HOOKSHOT);}}), + Entrance(WATER_TEMPLE_BOULDERS_UPPER, {[]{return true;}}), + }); + + areaTable[WATER_TEMPLE_BOULDERS_UPPER] = Area("Water Temple Boulders Upper", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(WATER_TEMPLE_BOULDERS_LOWER, {[]{return true;}}), + Entrance(WATER_TEMPLE_JETS_ROOM, {[]{return IsAdult;}}), + Entrance(WATER_TEMPLE_BOSS_KEY_ROOM, {[]{return (CanUse(IRON_BOOTS) || (IsAdult && LogicWaterBKJumpDive)) && SmallKeys(WATER_TEMPLE, 5);}}), + }); + + areaTable[WATER_TEMPLE_BOSS_KEY_ROOM] = Area("Water Temple Boss Key Room", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return true;}}), + }, { + //Locations + LocationAccess(WATER_TEMPLE_BOSS_KEY_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(WATER_TEMPLE_BOULDERS_UPPER, {[]{return (CanUse(IRON_BOOTS) || (IsAdult && LogicWaterBKJumpDive) || IsChild || CanDive) && SmallKeys(WATER_TEMPLE, 5);}}), + }); + + areaTable[WATER_TEMPLE_SOUTH_LOWER] = Area("Water Temple South Lower", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(WATER_TEMPLE_GS_BEHIND_GATE, {[]{return CanUse(HOOKSHOT) || (IsAdult && CanUse(HOVER_BOOTS));}, + /*Glitched*/[]{return (CanUse(BOOMERANG) && CanDoGlitch(GlitchType::HoverBoost, GlitchDifficulty::INTERMEDIATE)) || + (Bombs && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE));}}), + }, { + //Exits + Entrance(WATER_TEMPLE_LOBBY, {[]{return CanUse(IRON_BOOTS);}}), + }); + + areaTable[WATER_TEMPLE_WEST_LOWER] = Area("Water Temple West Lower", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(WATER_TEMPLE_LOBBY, {[]{return CanUse(HOOKSHOT) && CanUse(IRON_BOOTS) && GoronBracelet;}, + /*Glitched*/[]{return CanUse(IRON_BOOTS) && (LogicFewerTunicRequirements || CanUse(ZORA_TUNIC)) && CanDoGlitch(GlitchType::LedgeClip, GlitchDifficulty::INTERMEDIATE);}}), + Entrance(WATER_TEMPLE_DRAGON_ROOM, {[]{return IsAdult || CanChildAttack;}}), + }); + + areaTable[WATER_TEMPLE_DRAGON_ROOM] = Area("Water Temple Dragon Room", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(WATER_TEMPLE_DRAGON_CHEST, {[]{return (CanUse(HOOKSHOT) && CanUse(IRON_BOOTS)) || (IsAdult && LogicWaterDragonAdult && HasBombchus && (CanDive || CanUse(IRON_BOOTS))) || + Here(WATER_TEMPLE_RIVER, []{return IsAdult && CanUse(BOW) && ((LogicWaterDragonAdult && (CanDive || CanUse(IRON_BOOTS))) || LogicWaterDragonJumpDive);});}, + /*Glitched*/[]{return Bombs && ((IsAdult && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::ADVANCED)) || (CanUse(IRON_BOOTS) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE)));}}), + }, { + //Exits + Entrance(WATER_TEMPLE_WEST_LOWER, {[]{return true;}}), + }); + + areaTable[WATER_TEMPLE_CENTRAL_PILLAR_LOWER] = Area("Water Temple Central Pillar Lower", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(WATER_TEMPLE_LOBBY, {[]{return SmallKeys(WATER_TEMPLE, 5);}}), + Entrance(WATER_TEMPLE_CENTRAL_PILLAR_UPPER, {[]{return CanUse(HOOKSHOT);}}), + Entrance(WATER_TEMPLE_CENTRAL_PILLAR_BASEMENT, {[]{return WaterTempleMiddle && CanUse(IRON_BOOTS) && WaterTimer >= 40;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::LedgeClip, GlitchDifficulty::NOVICE) && CanUse(IRON_BOOTS) && WaterTimer >= 40;}}), + }); + + areaTable[WATER_TEMPLE_CENTRAL_PILLAR_UPPER] = Area("Water Temple Central Pillar Upper", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&WaterTempleMiddle, {[]{return WaterTempleMiddle || CanPlay(ZeldasLullaby);}, + /*Glitched*/[]{return ZeldasLullaby && (CanDoGlitch(GlitchType::DungeonBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && + (CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED) || (HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED)))));}}), + }, { + //Locations + LocationAccess(WATER_TEMPLE_GS_CENTRAL_PILLAR, {[]{return CanUse(LONGSHOT) || (LogicWaterCentralGSFW && WaterTempleHigh && CanUse(FARORES_WIND) && HookshotOrBoomerang);}}), + }, { + //Exits + Entrance(WATER_TEMPLE_LOBBY, {[]{return true;}}), + Entrance(WATER_TEMPLE_CENTRAL_PILLAR_LOWER, {[]{return true;}}), + }); + + areaTable[WATER_TEMPLE_CENTRAL_PILLAR_BASEMENT] = Area("Water Temple Central Pillar Basement", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(WATER_TEMPLE_CENTRAL_PILLAR_CHEST, {[]{return CanUse(HOOKSHOT) && CanUse(IRON_BOOTS) && WaterTimer >= 40;}}), + }, { + //Exits + Entrance(WATER_TEMPLE_CENTRAL_PILLAR_LOWER, {[]{return CanUse(IRON_BOOTS) && WaterTimer >= 16;}}), + }); + + areaTable[WATER_TEMPLE_EAST_MIDDLE] = Area("Water Temple East Middle", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(WATER_TEMPLE_COMPASS_CHEST, {[]{return CanUseProjectile;}}), + }, { + //Exits + Entrance(WATER_TEMPLE_LOBBY, {[]{return CanUse(IRON_BOOTS);}}), + }); + + areaTable[WATER_TEMPLE_WEST_MIDDLE] = Area("Water Temple West Middle", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(WATER_TEMPLE_LOBBY, {[]{return true;}}), + Entrance(WATER_TEMPLE_HIGH_WATER, {[]{return CanUseProjectile;}}), + }); + + areaTable[WATER_TEMPLE_HIGH_WATER] = Area("Water Temple High Water", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&WaterTempleHigh, {[]{return WaterTempleHigh || CanPlay(ZeldasLullaby);}, + /*Glitched*/[]{return ZeldasLullaby && (CanDoGlitch(GlitchType::DungeonBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && + (CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED) || (HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED)))));}}), + }, {}, { + //Exits + Entrance(WATER_TEMPLE_LOBBY, {[]{return true;}}), + }); + + areaTable[WATER_TEMPLE_BLOCK_CORRIDOR] = Area("Water Temple Block Corridor", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(WATER_TEMPLE_CENTRAL_BOW_TARGET_CHEST, {[]{return GoronBracelet && (WaterTempleLow || WaterTempleMiddle);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::INTERMEDIATE) && (WaterTempleLow || WaterTempleMiddle);}}), + }, { + //Exits + Entrance(WATER_TEMPLE_LOBBY, {[]{return CanUse(HOOKSHOT);}}), + }); + + areaTable[WATER_TEMPLE_FALLING_PLATFORM_ROOM] = Area("Water Temple Falling Platform Room", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(WATER_TEMPLE_GS_FALLING_PLATFORM_ROOM, {[]{return CanUse(LONGSHOT) || (LogicWaterFallingPlatformGS && IsAdult && HookshotOrBoomerang);}}), + }, { + //Exits + Entrance(WATER_TEMPLE_LOBBY, {[]{return CanUse(HOOKSHOT) && SmallKeys(WATER_TEMPLE, 4);}}), + Entrance(WATER_TEMPLE_DRAGON_PILLARS_ROOM, {[]{return CanUse(HOOKSHOT) && SmallKeys(WATER_TEMPLE, 5);}}), + }); + + areaTable[WATER_TEMPLE_DRAGON_PILLARS_ROOM] = Area("Water Temple Dragon Pillars Room", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(WATER_TEMPLE_FALLING_PLATFORM_ROOM, {[]{return CanUseProjectile;}}), + Entrance(WATER_TEMPLE_DARK_LINK_ROOM, {[]{return CanUse(HOOKSHOT);}}), + }); + + areaTable[WATER_TEMPLE_DARK_LINK_ROOM] = Area("Water Temple Dark Link Room", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(WATER_TEMPLE_DRAGON_PILLARS_ROOM, {[]{return CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD);}}), + Entrance(WATER_TEMPLE_LONGSHOT_ROOM, {[]{return CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD);}}), + }); + + areaTable[WATER_TEMPLE_LONGSHOT_ROOM] = Area("Water Temple Longshot Room", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(WATER_TEMPLE_LONGSHOT_CHEST, {[]{return true;}}), + }, { + //Exits + Entrance(WATER_TEMPLE_DARK_LINK_ROOM, {[]{return true;}}), + Entrance(WATER_TEMPLE_RIVER, {[]{return IsChild || CanPlay(SongOfTime);}, + /*Glitched*/[]{return SongOfTime && (CanDoGlitch(GlitchType::DungeonBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && + (CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED) || (HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED)))));}}), + }); + + areaTable[WATER_TEMPLE_RIVER] = Area("Water Temple River", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(WATER_TEMPLE_RIVER_CHEST, {[]{return (CanUse(SLINGSHOT) || CanUse(BOW)) && (IsAdult || CanUse(HOVER_BOOTS) || CanUse(HOOKSHOT));}}), + LocationAccess(WATER_TEMPLE_GS_RIVER, {[]{return (CanUse(IRON_BOOTS) && CanUse(HOOKSHOT)) || (LogicWaterRiverGS && CanUse(LONGSHOT));}}), + }, { + //Exits + Entrance(WATER_TEMPLE_DRAGON_ROOM, {[]{return (CanUse(SLINGSHOT) || CanUse(BOW)) && (IsAdult || CanUse(HOVER_BOOTS) || CanUse(HOOKSHOT));}}), + }); + + areaTable[WATER_TEMPLE_PRE_BOSS_ROOM] = Area("Water Temple Pre Boss Room", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return true;}}), + }, {}, { + //Exits + Entrance(WATER_TEMPLE_LOBBY, {[]{return true;}}), + Entrance(WATER_TEMPLE_BOSS_ROOM, {[]{return BossKeyWaterTemple;}}), + }); + + areaTable[WATER_TEMPLE_BOSS_ROOM] = Area("Water Temple Boss Room", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&WaterTempleClear, {[]{return WaterTempleClear || (CanUse(HOOKSHOT) && (CanUse(KOKIRI_SWORD) || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)));}}), + }, { + //Locations + LocationAccess(WATER_TEMPLE_MORPHA_HEART, {[]{return WaterTempleClear;}}), + LocationAccess(MORPHA, {[]{return WaterTempleClear;}}), + }, { + //Exits + Entrance(WATER_TEMPLE_ENTRYWAY, {[]{return WaterTempleClear;}}), + }); + } + + /*--------------------------- + | MASTER QUEST DUNGEON | + ---------------------------*/ + if (Dungeon::WaterTemple.IsMQ()) { + areaTable[WATER_TEMPLE_MQ_LOBBY] = Area("Water Temple MQ Lobby", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&WaterTempleClear, {[]{return BossKeyWaterTemple && IsAdult && CanUse(LONGSHOT);}}), + }, { + //Locations + LocationAccess(WATER_TEMPLE_MORPHA_HEART, {[]{return BossKeyWaterTemple && IsAdult && CanUse(LONGSHOT);}}), + LocationAccess(MORPHA, {[]{return BossKeyWaterTemple && IsAdult && CanUse(LONGSHOT);}}), + }, { + //Exits + Entrance(WATER_TEMPLE_ENTRYWAY, {[]{return true;}}), + Entrance(WATER_TEMPLE_MQ_DIVE, {[]{return IsAdult && WaterTimer >= 24 && CanUse(IRON_BOOTS);}}), + Entrance(WATER_TEMPLE_MQ_DARK_LINK_REGION, {[]{return SmallKeys(WATER_TEMPLE, 1) && IsAdult && CanUse(LONGSHOT);}}), + }); + + areaTable[WATER_TEMPLE_MQ_DIVE] = Area("Water Temple MQ Dive", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(WATER_TEMPLE_MQ_MAP_CHEST, {[]{return HasFireSource && IsAdult && CanUse(HOOKSHOT);}}), + LocationAccess(WATER_TEMPLE_MQ_CENTRAL_PILLAR_CHEST, {[]{return IsAdult && CanUse(ZORA_TUNIC) && CanUse(HOOKSHOT) && (CanUse(DINS_FIRE) && CanPlay(SongOfTime));}}), + //Trick: IsAdult && CanUse(ZORA_TUNIC) && CanUse(HOOKSHOT) && ((LogicWaterMQCentralPillar && CanUse(FIRE_ARROWS)) || (CanUse(DINS_FIRE) && CanPlay(SongOfTime))) + }, { + //Exits + Entrance(WATER_TEMPLE_MQ_LOWERED_WATER_LEVELS, {[]{return CanPlay(ZeldasLullaby);}}), + }); + + areaTable[WATER_TEMPLE_MQ_LOWERED_WATER_LEVELS] = Area("Water Temple MQ Lowered Water Levels", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(WATER_TEMPLE_MQ_COMPASS_CHEST, {[]{return (IsAdult && CanUse(BOW)) || CanUse(DINS_FIRE) || Here(WATER_TEMPLE_MQ_LOBBY, []{return IsChild && CanUse(STICKS) && HasExplosives;});}}), + LocationAccess(WATER_TEMPLE_MQ_LONGSHOT_CHEST, {[]{return IsAdult && CanUse(HOOKSHOT);}}), + LocationAccess(WATER_TEMPLE_MQ_GS_LIZALFOS_HALLWAY, {[]{return CanUse(DINS_FIRE);}}), + LocationAccess(WATER_TEMPLE_MQ_GS_BEFORE_UPPER_WATER_SWITCH, {[]{return IsAdult && CanUse(LONGSHOT);}}), + }, {}); + + areaTable[WATER_TEMPLE_MQ_DARK_LINK_REGION] = Area("Water Temple MQ Dark Link Region", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FairyPot, {[]{return true;}}), + EventAccess(&NutPot, {[]{return true;}}), + }, { + //Locations + LocationAccess(WATER_TEMPLE_MQ_BOSS_KEY_CHEST, {[]{return IsAdult && WaterTimer >= 24 && CanUse(DINS_FIRE) && (LogicWaterDragonJumpDive || CanDive || CanUse(IRON_BOOTS));}}), + LocationAccess(WATER_TEMPLE_MQ_GS_RIVER, {[]{return true;}}), + }, { + //Exits + Entrance(WATER_TEMPLE_MQ_BASEMENT_GATED_AREAS, {[]{return IsAdult && WaterTimer >= 24 && CanUse(DINS_FIRE) && CanUse(IRON_BOOTS);}}), + }); + + areaTable[WATER_TEMPLE_MQ_BASEMENT_GATED_AREAS] = Area("Water Temple MQ Basement Gated Areas", "Water Temple", WATER_TEMPLE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(WATER_TEMPLE_MQ_FREESTANDING_KEY, {[]{return HoverBoots || CanUse(SCARECROW) || LogicWaterNorthBasementLedgeJump;}}), + LocationAccess(WATER_TEMPLE_MQ_GS_TRIPLE_WALL_TORCH, {[]{return CanUse(FIRE_ARROWS) && (HoverBoots || CanUse(SCARECROW));}}), + LocationAccess(WATER_TEMPLE_MQ_GS_FREESTANDING_KEY_AREA, {[]{return SmallKeys(WATER_TEMPLE, 2) && (HoverBoots || CanUse(SCARECROW) || LogicWaterNorthBasementLedgeJump);}}), + //Trick: LogicWaterMQLockedGS || (SmallKeys(WATER_TEMPLE, 2) && (HoverBoots || CanUse(SCARECROW) || LogicWaterNorthBasementLedgeJump)) + }, {}); + } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_zoras_domain.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_zoras_domain.cpp new file mode 100644 index 000000000..bff5d7563 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_zoras_domain.cpp @@ -0,0 +1,188 @@ +#include "../location_access.hpp" +#include "../logic.hpp" +#include "../entrance.hpp" + +using namespace Logic; +using namespace Settings; + +void AreaTable_Init_ZorasDomain() { + areaTable[ZR_FRONT] = Area("ZR Front", "Zora River", ZORAS_RIVER, DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(ZR_GS_TREE, {[]{return IsChild && CanChildAttack;}}), + }, { + //Exits + Entrance(ZORAS_RIVER, {[]{return IsAdult || CanBlastOrSmash;}, + /*Glitched*/[]{return CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);}}), + Entrance(HYRULE_FIELD, {[]{return true;}}), + }); + + areaTable[ZORAS_RIVER] = Area("Zora River", "Zora River", ZORAS_RIVER, DAY_NIGHT_CYCLE, { + //Events + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || CanSummonGossipFairy;}}), + EventAccess(&BeanPlantFairy, {[]{return BeanPlantFairy || (CanPlantBean(ZORAS_RIVER) && CanPlay(SongOfStorms));}}), + EventAccess(&ButterflyFairy, {[]{return ButterflyFairy || CanUse(STICKS);}}), + EventAccess(&BugShrub, {[]{return BugShrub || CanCutShrubs;}}), + }, { + //Locations + LocationAccess(ZR_MAGIC_BEAN_SALESMAN, {[]{return IsChild;}}), + LocationAccess(ZR_FROGS_OCARINA_GAME, {[]{return IsChild && CanPlay(ZeldasLullaby) && CanPlay(SariasSong) && CanPlay(SunsSong) && CanPlay(EponasSong) && CanPlay(SongOfTime) && CanPlay(SongOfStorms);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::ADVANCED) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && IsChild && ZeldasLullaby && SariasSong && SunsSong && EponasSong && SongOfTime && SongOfStorms;}}), + LocationAccess(ZR_FROGS_IN_THE_RAIN, {[]{return IsChild && CanPlay(SongOfStorms);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::ADVANCED) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && IsChild && SongOfStorms;}}), + LocationAccess(ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH, {[]{return IsChild || CanUse(HOVER_BOOTS) || (IsAdult && LogicZoraRiverLower);}}), + LocationAccess(ZR_NEAR_DOMAIN_FREESTANDING_POH, {[]{return IsChild || CanUse(HOVER_BOOTS) || (IsAdult && LogicZoraRiverUpper);}}), + LocationAccess(ZR_GS_LADDER, {[]{return IsChild && AtNight && CanChildAttack && CanGetNightTimeGS;}}), + LocationAccess(ZR_GS_NEAR_RAISED_GROTTOS, {[]{return IsAdult && HookshotOrBoomerang && AtNight && CanGetNightTimeGS;}}), + LocationAccess(ZR_GS_ABOVE_BRIDGE, {[]{return IsAdult && CanUse(HOOKSHOT) && AtNight && CanGetNightTimeGS;}}), + LocationAccess(ZR_NEAR_GROTTOS_GOSSIP_STONE, {[]{return true;}}), + LocationAccess(ZR_NEAR_DOMAIN_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(ZR_FRONT, {[]{return true;}}), + Entrance(ZR_OPEN_GROTTO, {[]{return true;}}), + Entrance(ZR_FAIRY_GROTTO, {[]{return Here(ZORAS_RIVER, []{return CanBlastOrSmash;});}, + /*Glitched*/[]{return Here(ZORAS_RIVER, []{return CanUse(STICKS) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED);});}}), + Entrance(THE_LOST_WOODS, {[]{return CanDive || CanUse(IRON_BOOTS);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::INTERMEDIATE) || (CanUse(FARORES_WIND) && (FaroresWindAnywhere || (CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE) && (HasBottle || (IsAdult && (HasBoots || ClaimCheck)) || (IsChild && WeirdEgg)))) && + ((CanUse(NAYRUS_LOVE) && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::NOVICE)) || (CanUseMagicArrow && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::ADVANCED))));}}), + Entrance(ZR_STORMS_GROTTO, {[]{return CanOpenStormGrotto;}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && SongOfStorms && (ShardOfAgony || LogicGrottosWithoutAgony);}}), + Entrance(ZR_BEHIND_WATERFALL, {[]{return CanPlay(ZeldasLullaby);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::HookshotJump_Boots, GlitchDifficulty::ADVANCED) || ((CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || + ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && ZeldasLullaby);}}), + }); + + areaTable[ZR_BEHIND_WATERFALL] = Area("ZR Behind Waterfall", "Zora River", NONE, DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(ZORAS_RIVER, {[]{return true;}}), + Entrance(ZORAS_DOMAIN, {[]{return true;}}), + }); + + areaTable[ZR_OPEN_GROTTO] = Area("ZR Open Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, grottoEvents, { + //Locations + LocationAccess(ZR_OPEN_GROTTO_CHEST, {[]{return true;}}), + LocationAccess(ZR_OPEN_GROTTO_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(ZORAS_RIVER, {[]{return true;}}), + }); + + areaTable[ZR_FAIRY_GROTTO] = Area("ZR Fairy Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, { + //Event + EventAccess(&FreeFairies, {[]{return true;}}), + }, {}, { + //Exits + Entrance(ZORAS_RIVER, {[]{return true;}}), + }); + + areaTable[ZR_STORMS_GROTTO] = Area("ZR Storms Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(ZR_DEKU_SCRUB_GROTTO_REAR, {[]{return CanStunDeku;}}), + LocationAccess(ZR_DEKU_SCRUB_GROTTO_FRONT, {[]{return CanStunDeku;}}), + }, { + //Exits + Entrance(ZORAS_RIVER, {[]{return true;}}), + }); + + areaTable[ZORAS_DOMAIN] = Area("Zoras Domain", "Zoras Domain", ZORAS_DOMAIN, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&EyeballFrogAccess, {[]{return EyeballFrogAccess || (IsAdult && KingZoraThawed && (Eyedrops || EyeballFrog || Prescription || PrescriptionAccess));}}), + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || CanSummonGossipFairyWithoutSuns;}}), + EventAccess(&NutPot, {[]{return true;}}), + EventAccess(&StickPot, {[]{return StickPot || IsChild;}}), + EventAccess(&FishGroup, {[]{return FishGroup || IsChild;}}), + EventAccess(&KingZoraThawed, {[]{return KingZoraThawed || (IsAdult && BlueFire);}}), + EventAccess(&DeliverLetter, {[]{return DeliverLetter || (RutosLetter && IsChild && ZorasFountain.IsNot(ZORASFOUNTAIN_OPEN));}}), + }, { + //Locations + LocationAccess(ZD_DIVING_MINIGAME, {[]{return IsChild;}}), + LocationAccess(ZD_CHEST, {[]{return IsChild && CanUse(STICKS);}}), + LocationAccess(ZD_KING_ZORA_THAWED, {[]{return KingZoraThawed;}}), + LocationAccess(ZD_TRADE_PRESCRIPTION, {[]{return KingZoraThawed && Prescription;}}), + LocationAccess(ZD_GS_FROZEN_WATERFALL, {[]{return IsAdult && AtNight && (HookshotOrBoomerang || CanUse(SLINGSHOT) || Bow || MagicMeter) && CanGetNightTimeGS;}}), + LocationAccess(ZD_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(ZR_BEHIND_WATERFALL, {[]{return true;}}), + Entrance(LAKE_HYLIA, {[]{return IsChild && (CanDive || CanUse(IRON_BOOTS));}, + /*Glitched*/[]{return (IsAdult && GlitchZDOoBJumpSlash) || (IsChild && CanUse(FARORES_WIND) && (FaroresWindAnywhere || (CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE) && (HasBottle || WeirdEgg))) && + ((CanUse(NAYRUS_LOVE) && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::NOVICE)) || (CanUseMagicArrow && CanDoGlitch(GlitchType::CutsceneDive, GlitchDifficulty::ADVANCED))));}}), + Entrance(ZD_BEHIND_KING_ZORA, {[]{return DeliverLetter || ZorasFountain.Is(ZORASFOUNTAIN_OPEN) || (ZorasFountain.Is(ZORASFOUNTAIN_ADULT) && IsAdult);}, + /*Glitched*/[]{return ((IsChild || CanUse(IRON_BOOTS)) && CanDoGlitch(GlitchType::TripleSlashClip, GlitchDifficulty::NOVICE)) || CanDoGlitch(GlitchType::ASlide, GlitchDifficulty::NOVICE) || + CanDoGlitch(GlitchType::LedgeCancel, GlitchDifficulty::NOVICE) || CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) || CanDoGlitch(GlitchType::LedgeClip, GlitchDifficulty::INTERMEDIATE);}}), + Entrance(ZD_SHOP, {[]{return IsChild || BlueFire;}, + /*Glitched*/[]{return GlitchZDOoBJumpSlash.Value();}}), + Entrance(ZD_STORMS_GROTTO, {[]{return CanOpenStormGrotto;}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && SongOfStorms && (ShardOfAgony || LogicGrottosWithoutAgony);}}), + }); + + areaTable[ZD_BEHIND_KING_ZORA] = Area("ZD Behind King Zora", "Zoras Domain", NONE, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(ZORAS_DOMAIN, {[]{return DeliverLetter || ZorasFountain.Is(ZORASFOUNTAIN_OPEN) || (ZorasFountain.Is(ZORASFOUNTAIN_ADULT) && IsAdult);}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::ASlide, GlitchDifficulty::NOVICE) || (CanUse(LONGSHOT) && CanDoGlitch(GlitchType::HookshotClip, GlitchDifficulty::NOVICE)) || (Bombs && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE) && CanDoGlitch(GlitchType::ISG, GlitchDifficulty::INTERMEDIATE));}}), + Entrance(ZORAS_FOUNTAIN, {[]{return true;}}), + }); + + areaTable[ZD_SHOP] = Area("ZD Shop", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(ZD_SHOP_ITEM_1, {[]{return true;}}), + LocationAccess(ZD_SHOP_ITEM_2, {[]{return true;}}), + LocationAccess(ZD_SHOP_ITEM_3, {[]{return true;}}), + LocationAccess(ZD_SHOP_ITEM_4, {[]{return true;}}), + LocationAccess(ZD_SHOP_ITEM_5, {[]{return true;}}), + LocationAccess(ZD_SHOP_ITEM_6, {[]{return true;}}), + LocationAccess(ZD_SHOP_ITEM_7, {[]{return true;}}), + LocationAccess(ZD_SHOP_ITEM_8, {[]{return true;}}), + }, { + //Exits + Entrance(ZORAS_DOMAIN, {[]{return true;}}), + }); + + areaTable[ZD_STORMS_GROTTO] = Area("ZD Storms Grotto", "", NONE, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&FreeFairies, {[]{return true;}}), + }, {}, { + //Exits + Entrance(ZORAS_DOMAIN, {[]{return true;}}), + }); + + areaTable[ZORAS_FOUNTAIN] = Area("Zoras Fountain", "Zoras Fountain", ZORAS_FOUNTAIN, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&GossipStoneFairy, {[]{return GossipStoneFairy || CanSummonGossipFairyWithoutSuns;}}), + EventAccess(&ButterflyFairy, {[]{return ButterflyFairy || (CanUse(STICKS) && AtDay);}}), + }, { + //Locations + LocationAccess(ZF_ICEBERG_FREESTANDING_POH, {[]{return IsAdult;}}), + LocationAccess(ZF_BOTTOM_FREESTANDING_POH, {[]{return IsAdult && IronBoots && WaterTimer >= 24;}}), + LocationAccess(ZF_GS_TREE, {[]{return IsChild;}}), + LocationAccess(ZF_GS_ABOVE_THE_LOG, {[]{return IsChild && HookshotOrBoomerang && AtNight && CanGetNightTimeGS;}, + /*Glitched*/[]{return IsChild && AtNight && CanGetNightTimeGS && HasBombchus && CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::NOVICE);}}), + LocationAccess(ZF_GS_HIDDEN_CAVE, {[]{return CanUse(SILVER_GAUNTLETS) && CanBlastOrSmash && HookshotOrBoomerang && IsAdult && AtNight && CanGetNightTimeGS;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::LedgeCancel, GlitchDifficulty::INTERMEDIATE) && IsAdult && HookshotOrBoomerang && AtNight && CanGetNightTimeGS;}}), + LocationAccess(ZF_FAIRY_GOSSIP_STONE, {[]{return true;}}), + LocationAccess(ZF_JABU_GOSSIP_STONE, {[]{return true;}}), + }, { + //Exits + Entrance(ZD_BEHIND_KING_ZORA, {[]{return true;}}), + Entrance(JABU_JABUS_BELLY_ENTRYWAY, {[]{return (IsChild && Fish);}, + /*Glitched*/[]{return (IsChild && CanUse(STICKS) && GlitchJabuStickRecoil) || (IsAdult && GlitchJabuAdult);}}), + Entrance(ICE_CAVERN_ENTRYWAY, {[]{return IsAdult;}, + /*Glitched*/[]{return CanDoGlitch(GlitchType::BombHover, GlitchDifficulty::INTERMEDIATE);}}), + Entrance(ZF_GREAT_FAIRY_FOUNTAIN, {[]{return HasExplosives || (CanUse(SILVER_GAUNTLETS) && Hammer && LogicZFGreatFairy);}, + /*Glitched*/[]{return IsChild && (KokiriSword || Sticks) && CanShield && (CanDoGlitch(GlitchType::SeamWalk, GlitchDifficulty::ADVANCED) || (CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE) && CanDoGlitch(GlitchType::SeamWalk, GlitchDifficulty::INTERMEDIATE)));}}), + }); + + areaTable[ZF_GREAT_FAIRY_FOUNTAIN] = Area("ZF Great Fairy Fountain", "", NONE, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LocationAccess(ZF_GREAT_FAIRY_REWARD, {[]{return CanPlay(ZeldasLullaby);}, + /*Glitched*/[]{return (CanDoGlitch(GlitchType::OutdoorBombOI, GlitchDifficulty::INTERMEDIATE) || ((Bugs || Fish) && CanShield && (CanSurviveDamage || (Fairy && NumBottles >= 2)) && CanDoGlitch(GlitchType::QPA, GlitchDifficulty::ADVANCED)) || + ((Bugs || Fish) && CanShield && HasBombchus && CanDoGlitch(GlitchType::ActionSwap, GlitchDifficulty::ADVANCED))) && ZeldasLullaby;}}), + }, { + //Exits + Entrance(ZORAS_FOUNTAIN, {[]{return true;}}), + }); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/logic.cpp b/soh/soh/Enhancements/randomizer/3drando/logic.cpp new file mode 100644 index 000000000..f85e4ed2a --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/logic.cpp @@ -0,0 +1,1218 @@ +#include "logic.hpp" + +#include +#include +#include +#include +#include + +#include "settings.hpp" +#include "dungeon.hpp" +#include "setting_descriptions.hpp" + +using namespace Settings; + +namespace Logic { + + bool noVariable = false; + + //Child item logic + bool KokiriSword = false; + bool ZeldasLetter = false; + bool WeirdEgg = false; + bool HasBottle = false; + bool Bombchus = false; + bool Bombchus5 = false; + bool Bombchus10 = false; + bool Bombchus20 = false; + bool MagicBean = false; + bool MagicBeanPack = false; + bool RutosLetter = false; + bool Boomerang = false; + bool DinsFire = false; + bool FaroresWind = false; + bool NayrusLove = false; + bool LensOfTruth = false; + bool ShardOfAgony = false; + bool SkullMask = false; + bool MaskOfTruth = false; + + //Adult logic + bool Hammer = false; + bool IronBoots = false; + bool HoverBoots = false; + bool MirrorShield = false; + bool GoronTunic = false; + bool ZoraTunic = false; + bool Epona = false; + bool BigPoe = false; + bool GerudoToken = false; + bool FireArrows = false; + bool IceArrows = false; + bool LightArrows = false; + bool MasterSword = false; + bool BiggoronSword = false; + + //Trade Quest + bool PocketEgg = false; + bool Cojiro = false; + bool OddMushroom = false; + bool OddPoultice = false; + bool PoachersSaw = false; + bool BrokenSword = false; + bool Prescription = false; + bool EyeballFrog = false; + bool Eyedrops = false; + bool ClaimCheck = false; + + //Trade Quest Events + bool WakeUpAdultTalon = false; + bool CojiroAccess = false; + bool OddMushroomAccess = false; + bool OddPoulticeAccess = false; + bool PoachersSawAccess = false; + bool BrokenSwordAccess = false; + bool PrescriptionAccess = false; + bool EyeballFrogAccess = false; + bool EyedropsAccess = false; + bool DisableTradeRevert = false; + + //Songs + bool ZeldasLullaby = false; + bool SariasSong = false; + bool SunsSong = false; + bool SongOfStorms = false; + bool EponasSong = false; + bool SongOfTime = false; + bool MinuetOfForest = false; + bool BoleroOfFire = false; + bool SerenadeOfWater = false; + bool RequiemOfSpirit = false; + bool NocturneOfShadow = false; + bool PreludeOfLight = false; + + //Stones and Meddallions + bool ForestMedallion = false; + bool FireMedallion = false; + bool WaterMedallion = false; + bool SpiritMedallion = false; + bool ShadowMedallion = false; + bool LightMedallion = false; + bool KokiriEmerald = false; + bool GoronRuby = false; + bool ZoraSapphire = false; + + //Dungeon Clears + bool DekuTreeClear = false; + bool DodongosCavernClear = false; + bool JabuJabusBellyClear = false; + bool ForestTempleClear = false; + bool FireTempleClear = false; + bool WaterTempleClear = false; + bool SpiritTempleClear = false; + bool ShadowTempleClear = false; + + //Trial Clears + bool ForestTrialClear = false; + bool FireTrialClear = false; + bool WaterTrialClear = false; + bool SpiritTrialClear = false; + bool ShadowTrialClear = false; + bool LightTrialClear = false; + + //Progressive Items + uint8_t ProgressiveBulletBag = 0; + uint8_t ProgressiveBombBag = 0; + uint8_t ProgressiveMagic = 0; + uint8_t ProgressiveScale = 0; + uint8_t ProgressiveHookshot = 0; + uint8_t ProgressiveBow = 0; + uint8_t ProgressiveWallet = 0; + uint8_t ProgressiveStrength = 0; + uint8_t ProgressiveOcarina = 0; + uint8_t ProgressiveGiantKnife = 0; + + //Logical keysanity + bool IsKeysanity = false; + + //Keys + uint8_t ForestTempleKeys = 0; + uint8_t FireTempleKeys = 0; + uint8_t WaterTempleKeys = 0; + uint8_t SpiritTempleKeys = 0; + uint8_t ShadowTempleKeys = 0; + uint8_t GanonsCastleKeys = 0; + uint8_t GerudoFortressKeys = 0; + uint8_t GerudoTrainingGroundsKeys = 0; + uint8_t BottomOfTheWellKeys = 0; + uint8_t TreasureGameKeys = 0; + + //Boss Keys + bool BossKeyForestTemple = false; + bool BossKeyFireTemple = false; + bool BossKeyWaterTemple = false; + bool BossKeySpiritTemple = false; + bool BossKeyShadowTemple = false; + bool BossKeyGanonsCastle = false; + + //Gold Skulltula Count + uint8_t GoldSkulltulaTokens = 0; + + //Bottle Count + uint8_t Bottles = 0; + uint8_t NumBottles = 0; + bool NoBottles = false; + + //Drops and Bottle Contents Access + bool DekuNutDrop = false; + bool NutPot = false; + bool NutCrate = false; + bool DekuBabaNuts = false; + bool DekuStickDrop = false; + bool StickPot = false; + bool DekuBabaSticks = false; + bool BugsAccess = false; + bool BugShrub = false; + bool WanderingBugs = false; + bool BugRock = false; + bool BlueFireAccess = false; + bool FishAccess = false; + bool FishGroup = false; + bool LoneFish = false; + bool FairyAccess = false; + bool GossipStoneFairy = false; + bool BeanPlantFairy = false; + bool ButterflyFairy = false; + bool FairyPot = false; + bool FreeFairies = false; + bool FairyPond = false; + bool BombchuDrop = false; + bool AmmoCanDrop = false; + + bool BuyBombchus5 = false; + bool BuyBombchus10 = false; + bool BuyBombchus20 = false; + bool BuySeed = false; + bool BuyArrow = false; + bool BuyBomb = false; + bool BuyGPotion = false; + bool BuyBPotion = false; + bool MagicRefill = false; + + uint8_t PieceOfHeart = 0; + uint8_t HeartContainer = 0; + bool DoubleDefense = false; + + /* --- HELPERS, EVENTS, AND LOCATION ACCESS --- */ + /* These are used to simplify reading the logic, but need to be updated + / every time a base value is updated. */ + + bool Slingshot = false; + bool Ocarina = false; + bool OcarinaOfTime = false; + bool BombBag = false; + bool MagicMeter = false; + bool Hookshot = false; + bool Longshot = false; + bool Bow = false; + bool GoronBracelet = false; + bool SilverGauntlets = false; + bool GoldenGauntlets = false; + bool SilverScale = false; + bool GoldScale = false; + bool AdultsWallet = false; + + bool ChildScarecrow = false; + bool AdultScarecrow = false; + bool ScarecrowSong = false; + bool Scarecrow = false; + bool DistantScarecrow = false; + + bool Bombs = false; + bool DekuShield = false; + bool HylianShield = false; + bool Nuts = false; + bool Sticks = false; + bool Bugs = false; + bool BlueFire = false; + bool Fish = false; + bool Fairy = false; + bool BottleWithBigPoe = false; + + bool FoundBombchus = false; + bool CanPlayBowling = false; + bool HasBombchus = false; + bool HasExplosives = false; + bool HasBoots = false; + bool IsChild = false; + bool IsAdult = false; + bool IsGlitched = false; + bool CanBlastOrSmash = false; + bool CanChildAttack = false; + bool CanChildDamage = false; + bool CanCutShrubs = false; + bool CanDive = false; + bool CanLeaveForest = false; + bool CanPlantBugs = false; + bool CanRideEpona = false; + bool CanStunDeku = false; + bool CanSummonGossipFairy = false; + bool CanSummonGossipFairyWithoutSuns = false; + bool NeedNayrusLove = false; + bool CanSurviveDamage = false; + bool CanTakeDamage = false; + bool CanTakeDamageTwice = false; + //bool CanPlantBean = false; + bool CanOpenBombGrotto = false; + bool CanOpenStormGrotto = false; + bool BigPoeKill = false; + bool HookshotOrBoomerang = false; + bool CanGetNightTimeGS = false; + + uint8_t BaseHearts = 0; + uint8_t Hearts = 0; + uint8_t Multiplier = 0; + uint8_t EffectiveHealth = 0; + uint8_t FireTimer = 0; + uint8_t WaterTimer = 0; + + bool GuaranteeTradePath = false; + bool GuaranteeHint = false; + bool HasFireSource = false; + bool HasFireSourceWithTorch = false; + + bool CanFinishGerudoFortress = false; + + bool HasShield = false; + bool CanShield = false; + bool CanJumpslash = false; + bool CanUseProjectile = false; + bool CanUseMagicArrow = false; + + //Bridge and LACS Requirements + uint8_t MedallionCount = 0; + uint8_t StoneCount = 0; + uint8_t DungeonCount = 0; + bool HasAllStones = false; + bool HasAllMedallions = false; + bool CanBuildRainbowBridge = false; + bool CanTriggerLACS = false; + + //Other + bool AtDay = false; + bool AtNight = false; + uint8_t Age = 0; + + //Events + bool ShowedMidoSwordAndShield = false; + bool CarpenterRescue = false; + bool GF_GateOpen = false; + bool GtG_GateOpen = false; + bool DampesWindmillAccess = false; + bool DrainWell = false; + bool GoronCityChildFire = false; + bool GCWoodsWarpOpen = false; + bool GCDaruniasDoorOpenChild = false; + bool StopGCRollingGoronAsAdult = false; + bool WaterTempleLow = false; + bool WaterTempleMiddle = false; + bool WaterTempleHigh = false; + bool KakarikoVillageGateOpen = false; + bool KingZoraThawed = false; + bool ForestTempleJoelle = false; + bool ForestTempleBeth = false; + bool ForestTempleJoAndBeth = false; + bool ForestTempleAmy = false; + bool ForestTempleMeg = false; + bool ForestTempleAmyAndMeg = false; + bool FireLoopSwitch = false; + bool LinksCow = false; + bool AtDampeTime = false; + bool DeliverLetter = false; + bool TimeTravel = false; + + /* --- END OF HELPERS AND LOCATION ACCESS --- */ + + //Placement Tracking + uint8_t AddedProgressiveBulletBags = 0; + uint8_t AddedProgressiveBombBags = 0; + uint8_t AddedProgressiveMagics = 0; + uint8_t AddedProgressiveScales = 0; + uint8_t AddedProgressiveHookshots = 0; + uint8_t AddedProgressiveBows = 0; + uint8_t AddedProgressiveWallets = 0; + uint8_t AddedProgressiveStrengths = 0; + uint8_t AddedProgressiveOcarinas = 0; + uint8_t TokensInPool = 0; + + //Event checking past + bool DrainWellPast = false; + bool DampesWindmillAccessPast = false; + bool DekuTreeClearPast = false; + bool GoronRubyPast = false; + bool ZoraSapphirePast = false; + bool ForestTrialClearPast = false; + bool FireTrialClearPast = false; + bool WaterTrialClearPast = false; + bool SpiritTrialClearPast = false; + bool ShadowTrialClearPast = false; + bool LightTrialClearPast = false; + bool BuyDekuShieldPast = false; + bool TimeTravelPast = false; + + bool CanPlay(bool song) { + return Ocarina && song; + } + + static bool IsMagicItem(uint32_t item) { + return item == DINS_FIRE || + item == FARORES_WIND || + item == NAYRUS_LOVE || + item == LENS_OF_TRUTH; + } + + static bool IsMagicArrow(uint32_t item) { + return item == FIRE_ARROWS || + item == ICE_ARROWS || + item == LIGHT_ARROWS; + } + + bool HasItem(uint32_t itemName) { + return (itemName == DINS_FIRE && DinsFire) || + (itemName == FARORES_WIND && FaroresWind) || + (itemName == NAYRUS_LOVE && NayrusLove) || + (itemName == LENS_OF_TRUTH && LensOfTruth) || + (itemName == BOW && Bow) || + (itemName == MEGATON_HAMMER && Hammer) || + (itemName == IRON_BOOTS && IronBoots) || + (itemName == HOVER_BOOTS && HoverBoots) || + (itemName == HOOKSHOT && Hookshot) || + (itemName == LONGSHOT && Longshot) || + (itemName == SILVER_GAUNTLETS && SilverGauntlets) || + (itemName == GOLDEN_GAUNTLETS && GoldenGauntlets) || + (itemName == GORON_TUNIC && GoronTunic) || + (itemName == ZORA_TUNIC && ZoraTunic) || + (itemName == SCARECROW && Scarecrow) || + (itemName == DISTANT_SCARECROW && DistantScarecrow)|| + (itemName == HYLIAN_SHIELD && HylianShield) || + (itemName == MIRROR_SHIELD && MirrorShield) || + (itemName == MASTER_SWORD && MasterSword) || + (itemName == BIGGORON_SWORD && BiggoronSword) || + (itemName == SLINGSHOT && Slingshot) || + (itemName == BOOMERANG && Boomerang) || + (itemName == KOKIRI_SWORD && KokiriSword) || + (itemName == STICKS && Sticks) || + (itemName == DEKU_SHIELD && DekuShield) || + (itemName == FIRE_ARROWS && FireArrows) || + (itemName == ICE_ARROWS && IceArrows) || + (itemName == LIGHT_ARROWS && LightArrows); + + } + + //Can the passed in item be used? + bool CanUse(uint32_t itemName) { + if (!HasItem(itemName)) + return false; + + switch (itemName) { + // Adult items + case BOW: return IsAdult || BowAsChild; + case MEGATON_HAMMER: return IsAdult || HammerAsChild; + case IRON_BOOTS: return IsAdult || IronBootsAsChild; + case HOVER_BOOTS: return IsAdult || HoverBootsAsChild; + case HOOKSHOT: return IsAdult || HookshotAsChild; + case LONGSHOT: return IsAdult || HookshotAsChild; + case SILVER_GAUNTLETS: return IsAdult; + case GOLDEN_GAUNTLETS: return IsAdult; + case GORON_TUNIC: return IsAdult || GoronTunicAsChild; + case ZORA_TUNIC: return IsAdult || ZoraTunicAsChild; + case SCARECROW: return IsAdult || HookshotAsChild; + case DISTANT_SCARECROW: return IsAdult || HookshotAsChild; + case HYLIAN_SHIELD: return IsAdult; + case MIRROR_SHIELD: return IsAdult || MirrorShieldAsChild; + case MASTER_SWORD: return IsAdult || MasterSwordAsChild; + case BIGGORON_SWORD: return IsAdult || BiggoronSwordAsChild; + + // Child items + case SLINGSHOT: return IsChild || SlingshotAsAdult; + case BOOMERANG: return IsChild || BoomerangAsAdult; + case KOKIRI_SWORD: return IsChild || KokiriSwordAsAdult; + case STICKS: return IsChild || StickAsAdult; + case DEKU_SHIELD: return IsChild || DekuShieldAsAdult; + + // Magic items + default: return MagicMeter && (IsMagicItem(itemName) || (IsMagicArrow(itemName) && CanUse(BOW))); + } + } + + bool HasProjectile(HasProjectileAge age) { + return HasExplosives || + (age == HasProjectileAge::Child && (Slingshot || Boomerang)) || + (age == HasProjectileAge::Adult && (Hookshot || Bow )) || + (age == HasProjectileAge::Both && (Slingshot || Boomerang) && (Hookshot || Bow)) || + (age == HasProjectileAge::Either && (Slingshot || Boomerang || Hookshot || Bow)); + } + + uint8_t GetDifficultyValueFromString(Option& glitchOption) { + for (size_t i = 0; i < GlitchDifficulties.size(); i++) { + if (glitchOption.GetSelectedOptionText() == GlitchDifficulties[i]) { + return i + 1; + } + } + return 0; + } + + bool CanDoGlitch(GlitchType glitch, GlitchDifficulty difficulty) { + uint8_t setDifficulty; + switch (glitch) { + //Restricted Items + case GlitchType::RestrictedItems: + setDifficulty = GetDifficultyValueFromString(GlitchRestrictedItems); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return true; + + //Super Stab + case GlitchType::SuperStab: + setDifficulty = GetDifficultyValueFromString(GlitchSuperStab); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return CanShield && CanUse(STICKS); + + //Infinite Sword Glitch + case GlitchType::ISG: + setDifficulty = GetDifficultyValueFromString(GlitchISG); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return CanShield && (IsAdult || KokiriSword || Sticks); + + //Bomb Hover + case GlitchType::BombHover: + setDifficulty = GetDifficultyValueFromString(GlitchHover); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return CanDoGlitch(GlitchType::ISG, GlitchDifficulty::NOVICE) && (HasBombchus || (Bombs && setDifficulty >= static_cast(GlitchDifficulty::ADVANCED))); + + //Bomb Ocarina Items + case GlitchType::BombOI: + setDifficulty = GetDifficultyValueFromString(GlitchBombOI); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return Bombs && CanSurviveDamage; + case GlitchType::OutdoorBombOI: + return ((CanUse(FARORES_WIND) && (DinsFire || NayrusLove || LensOfTruth || HasBottle || HasBombchus || Nuts || StartingConsumables || + (IsChild && (Sticks || ProgressiveBulletBag || (MagicBean || MagicBeanPack) || Boomerang || WeirdEgg || (Hammer && HammerAsChild))) || + (IsAdult && (ProgressiveBow || Hookshot || HasBoots || Hammer || (Sticks && StickAsAdult) || (Boomerang && BoomerangAsAdult)))) && + CanDoGlitch(GlitchType::BombOI, (static_cast(difficulty) >= 3) ? difficulty : GlitchDifficulty::ADVANCED) && CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE)) || + (((IsAdult && ClaimCheck) || Bugs || Fish || Fairy || (!NeedNayrusLove && (CanUse(NAYRUS_LOVE) || CanUse(DINS_FIRE))) || + (CanUse(FARORES_WIND) && FaroresWindAnywhere)) && CanDoGlitch(GlitchType::BombOI, difficulty))); + case GlitchType::WindmillBombOI: + return (((CanUse(FARORES_WIND) || (!NeedNayrusLove && (NayrusLove || DinsFire))) && (LensOfTruth || HasBottle || HasBombchus || Nuts || StartingConsumables || + (IsChild && (Sticks || ProgressiveBulletBag || (MagicBean || MagicBeanPack) || Boomerang || WeirdEgg || (Hammer && HammerAsChild))) || + (IsAdult && (ProgressiveBow || Hookshot || HasBoots || Hammer || (Sticks && StickAsAdult) || (Boomerang && BoomerangAsAdult)))) && + CanDoGlitch(GlitchType::BombOI, (static_cast(difficulty) >= 3) ? difficulty : GlitchDifficulty::ADVANCED) && CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE)) || + (((IsAdult && ClaimCheck) || Bugs || Fish || Fairy || (CanUse(FARORES_WIND) && FaroresWindAnywhere)) && CanDoGlitch(GlitchType::BombOI, difficulty))); + case GlitchType::IndoorBombOI: + return (((IsAdult && ClaimCheck) && (HasBottle || HasBoots || (CanUse(FARORES_WIND) && FaroresWindAnywhere))) || + ((Bugs || Fish || Fairy) && (NumBottles >= 2 || (IsAdult && (ClaimCheck || HasBoots)) || (IsChild && WeirdEgg) || (CanUse(FARORES_WIND) && FaroresWindAnywhere))) || + ((CanUse(FARORES_WIND) && FaroresWindAnywhere) && (HasBottle || (IsAdult && (ClaimCheck || HasBoots)) || (IsChild && WeirdEgg))) || + (((!NeedNayrusLove && (CanUse(NAYRUS_LOVE) || CanUse(DINS_FIRE))) || CanUse(FARORES_WIND)) && + (NumBottles + ((IsChild) ? ((WeirdEgg) ? 1 : 0) : (((IronBoots) ? 1 : 0) + ((HoverBoots) ? 1 : 0) + ((ClaimCheck) ? 1 : 0))) >= 2))) && + CanDoGlitch(GlitchType::BombOI, difficulty) && CanDoGlitch(GlitchType::RestrictedItems, GlitchDifficulty::NOVICE); + case GlitchType::DungeonBombOI: + return ((IsAdult && ClaimCheck) || Bugs || Fish || Fairy || (!NeedNayrusLove && (CanUse(NAYRUS_LOVE) || CanUse(DINS_FIRE))) || (CanUse(FARORES_WIND))) && CanDoGlitch(GlitchType::BombOI, difficulty); + + //Hover Boost + case GlitchType::HoverBoost: + setDifficulty = GetDifficultyValueFromString(GlitchHoverBoost); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return Bombs && CanUse(HOVER_BOOTS) && CanSurviveDamage; + + //Super Slide + case GlitchType::SuperSlide: + setDifficulty = GetDifficultyValueFromString(GlitchSuperSlide); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return true; + + //Megaflip + case GlitchType::Megaflip: + setDifficulty = GetDifficultyValueFromString(GlitchMegaflip); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + // Bombchu megaflips should be considered 2 difficulty levels higher + return CanShield && (Bombs || (HasBombchus && setDifficulty >= static_cast(difficulty) + 2)); + + //A-Slide + case GlitchType::ASlide: + setDifficulty = GetDifficultyValueFromString(GlitchASlide); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + // Same deal as bombchu megaflips + return IsChild && CanShield && (Bombs || (HasBombchus && setDifficulty >= static_cast(difficulty) + 2)); + + //Hammer Slide + case GlitchType::HammerSlide: + setDifficulty = GetDifficultyValueFromString(GlitchHammerSlide); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return CanUse(MEGATON_HAMMER) && CanUse(HOVER_BOOTS) && CanShield; + + //Ledge Cancel + case GlitchType::LedgeCancel: + setDifficulty = GetDifficultyValueFromString(GlitchLedgeCancel); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + // Similar to bombchu megaflips / A-slides but doesn't scale beyond advanced + return CanShield && (Bombs || (HasBombchus && setDifficulty >= static_cast(GlitchDifficulty::ADVANCED))); + + //Action Swap + case GlitchType::ActionSwap: + setDifficulty = GetDifficultyValueFromString(GlitchActionSwap); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return true; + + //Quick Put Away + case GlitchType::QPA: + setDifficulty = GetDifficultyValueFromString(GlitchQPA); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + // Boot Put Away Delay Method Frame Perfect Method Ledge Grab Method + return (CanTakeDamage && Bombs && ((CanUse(HOVER_BOOTS) || CanUse(IRON_BOOTS)) || setDifficulty >= static_cast(GlitchDifficulty::INTERMEDIATE))) || setDifficulty >= static_cast(GlitchDifficulty::ADVANCED); + + //Hookshot Clip + case GlitchType::HookshotClip: + setDifficulty = GetDifficultyValueFromString(GlitchHookshotClip); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return CanUse(HOOKSHOT); + + //Hookshot Jump: Bonk + case GlitchType::HookshotJump_Bonk: + setDifficulty = GetDifficultyValueFromString(GlitchHookshotJump_Bonk); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return IsAdult && Hookshot; // Child hookshot jumps are tiny so these stay as adult only until I check + + //Hookshot Jump: Boots + case GlitchType::HookshotJump_Boots: + setDifficulty = GetDifficultyValueFromString(GlitchHookshotJump_Boots); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return IsAdult && Hookshot && HasBoots; // Child hookshot jumps are tiny so these stay as adult only until I check + + //Cutscene Dives + case GlitchType::CutsceneDive: + setDifficulty = GetDifficultyValueFromString(GlitchCutsceneDive); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return true; + + //Navi Dives without TSC + case GlitchType::NaviDive_Stick: + setDifficulty = GetDifficultyValueFromString(GlitchNaviDive_Stick); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return IsChild && Sticks; + + //Triple Slash Clip + case GlitchType::TripleSlashClip: + setDifficulty = GetDifficultyValueFromString(GlitchTripleSlashClip); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return IsAdult || KokiriSword; + + //Ledge Clip + case GlitchType::LedgeClip: + setDifficulty = GetDifficultyValueFromString(GlitchLedgeClip); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return IsAdult; + + //Seam Walks + case GlitchType::SeamWalk: + setDifficulty = GetDifficultyValueFromString(GlitchSeamWalk); + if (setDifficulty < static_cast(difficulty)) { + return false; + } + return true; + } + + //Shouldn't be reached + return false; + } + + //Updates all logic helpers. Should be called whenever a non-helper is changed + void UpdateHelpers() { + NumBottles = ((NoBottles) ? 0 : (Bottles + ((DeliverLetter) ? 1 : 0))); + HasBottle = NumBottles >= 1; + Slingshot = (ProgressiveBulletBag >= 1) && (BuySeed || AmmoCanDrop); + Ocarina = ProgressiveOcarina >= 1; + OcarinaOfTime = ProgressiveOcarina >= 2; + MagicMeter = (ProgressiveMagic >= 1) && (AmmoCanDrop || (HasBottle && (BuyGPotion || BuyBPotion))); + BombBag = (ProgressiveBombBag >= 1) && (BuyBomb || AmmoCanDrop); + Hookshot = ProgressiveHookshot >= 1; + Longshot = ProgressiveHookshot >= 2; + Bow = (ProgressiveBow >= 1) && (BuyArrow || AmmoCanDrop); + GoronBracelet = ProgressiveStrength >= 1; + SilverGauntlets = ProgressiveStrength >= 2; + GoldenGauntlets = ProgressiveStrength >= 3; + SilverScale = ProgressiveScale >= 1; + GoldScale = ProgressiveScale >= 2; + AdultsWallet = ProgressiveWallet >= 1; + MasterSword = MasterSword || IsAdult; + BiggoronSword = BiggoronSword || ProgressiveGiantKnife >= 2; + + ScarecrowSong = ScarecrowSong || (ChildScarecrow && AdultScarecrow); + Scarecrow = Hookshot && CanPlay(ScarecrowSong); + DistantScarecrow = Longshot && CanPlay(ScarecrowSong); + + //Drop Access + DekuStickDrop = StickPot || DekuBabaSticks; + DekuNutDrop = (NutPot || NutCrate || DekuBabaNuts) && AmmoCanDrop; + BugsAccess = BugShrub || WanderingBugs || BugRock; + FishAccess = LoneFish || FishGroup; + FairyAccess = FairyPot || GossipStoneFairy || BeanPlantFairy || ButterflyFairy || FreeFairies || FairyPond; + + + //refills + Bombs = BombBag; + Nuts = DekuNutDrop || Nuts; + Sticks = DekuStickDrop || Sticks; + Bugs = HasBottle && BugsAccess; + BlueFire = HasBottle && BlueFireAccess; + Fish = HasBottle && FishAccess; + Fairy = HasBottle && FairyAccess; + + FoundBombchus = (BombchuDrop || Bombchus || Bombchus5 || Bombchus10 || Bombchus20); + CanPlayBowling = (BombchusInLogic && FoundBombchus) || (!BombchusInLogic && BombBag); + HasBombchus = (BuyBombchus5 || BuyBombchus10 || BuyBombchus20 || (AmmoDrops.Is(AMMODROPS_BOMBCHU) && FoundBombchus)); + + HasExplosives = Bombs || (BombchusInLogic && HasBombchus); + + HasBoots = IronBoots || HoverBoots; + + //Unshuffled adult trade quest + Eyedrops = Eyedrops || (!ShuffleAdultTradeQuest && ClaimCheck); + EyeballFrog = EyeballFrog || (!ShuffleAdultTradeQuest && Eyedrops); + Prescription = Prescription || (!ShuffleAdultTradeQuest && EyeballFrog); + BrokenSword = BrokenSword || (!ShuffleAdultTradeQuest && Prescription); + PoachersSaw = PoachersSaw || (!ShuffleAdultTradeQuest && BrokenSword); + OddPoultice = OddPoultice || (!ShuffleAdultTradeQuest && PoachersSaw); + OddMushroom = OddMushroom || (!ShuffleAdultTradeQuest && OddPoultice); + Cojiro = Cojiro || (!ShuffleAdultTradeQuest && OddMushroom); + PocketEgg = PocketEgg || (!ShuffleAdultTradeQuest && Cojiro); + + // IsChild = Age == AGE_CHILD; + // IsAdult = Age == AGE_ADULT; + + CanBlastOrSmash = HasExplosives || CanUse(MEGATON_HAMMER); + CanChildAttack = IsChild && (Slingshot || Boomerang || Sticks || KokiriSword || HasExplosives || CanUse(DINS_FIRE) || CanUse(MASTER_SWORD) || CanUse(MEGATON_HAMMER) || CanUse(BIGGORON_SWORD)); + CanChildDamage = IsChild && (Slingshot || Sticks || KokiriSword || HasExplosives || CanUse(DINS_FIRE) || CanUse(MASTER_SWORD) || CanUse(MEGATON_HAMMER) || CanUse(BIGGORON_SWORD)); + CanStunDeku = IsAdult || CanChildAttack || Nuts || HasShield; + CanCutShrubs = IsAdult /*|| Sticks*/ || KokiriSword || Boomerang || HasExplosives || CanUse(MASTER_SWORD) || CanUse(MEGATON_HAMMER) || CanUse(BIGGORON_SWORD); + CanDive = ProgressiveScale >= 1; + CanLeaveForest = OpenForest.IsNot(OPENFOREST_CLOSED) || IsAdult || DekuTreeClear || ShuffleInteriorEntrances || ShuffleOverworldEntrances; + CanPlantBugs = IsChild && Bugs; + CanRideEpona = IsAdult && Epona && CanPlay(EponasSong); + CanSummonGossipFairy = Ocarina && (ZeldasLullaby || EponasSong || SongOfTime || SunsSong); + CanSummonGossipFairyWithoutSuns = Ocarina && (ZeldasLullaby || EponasSong || SongOfTime); + Hearts = BaseHearts + HeartContainer + (PieceOfHeart >> 2); + EffectiveHealth = ((Hearts << (2 + DoubleDefense)) >> Multiplier) + ((Hearts << (2 + DoubleDefense)) % (1 << Multiplier) > 0); //Number of half heart hits to die, ranges from 1 to 160 + FireTimer = CanUse(GORON_TUNIC) ? 255 : (LogicFewerTunicRequirements) ? (Hearts * 8) : 0; + WaterTimer = CanUse( ZORA_TUNIC) ? 255 : (LogicFewerTunicRequirements) ? (Hearts * 8) : 0; + NeedNayrusLove = (EffectiveHealth == 1); + CanSurviveDamage = !NeedNayrusLove || CanUse(NAYRUS_LOVE); + CanTakeDamage = Fairy || CanSurviveDamage; + CanTakeDamageTwice = (Fairy && NumBottles >= 2) || ((EffectiveHealth == 2) && (CanUse(NAYRUS_LOVE) || Fairy)) || (EffectiveHealth > 2); + //CanPlantBean = IsChild && (MagicBean || MagicBeanPack); + CanOpenBombGrotto = CanBlastOrSmash && (ShardOfAgony || LogicGrottosWithoutAgony); + CanOpenStormGrotto = CanPlay(SongOfStorms) && (ShardOfAgony || LogicGrottosWithoutAgony); + HookshotOrBoomerang = CanUse(HOOKSHOT) || CanUse(BOOMERANG); + CanGetNightTimeGS = (CanPlay(SunsSong) || !NightGSExpectSuns); + + GuaranteeTradePath = ShuffleInteriorEntrances || ShuffleOverworldEntrances || LogicBiggoronBolero || CanBlastOrSmash || StopGCRollingGoronAsAdult; + //GuaranteeHint = (hints == "Mask" && MaskofTruth) || (hints == "Agony") || (hints != "Mask" && hints != "Agony"); + HasFireSource = CanUse(DINS_FIRE) || CanUse(FIRE_ARROWS); + HasFireSourceWithTorch = HasFireSource || CanUse(STICKS); + + //Gerudo Fortress + CanFinishGerudoFortress = (GerudoFortress.Is(GERUDOFORTRESS_NORMAL) && GerudoFortressKeys >= 4 && (IsAdult || KokiriSword || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD)) && (GerudoToken || CanUse(BOW) || CanUse(HOOKSHOT) || CanUse(HOVER_BOOTS) || LogicGerudoKitchen)) || + (GerudoFortress.Is(GERUDOFORTRESS_FAST) && GerudoFortressKeys >= 1 && (IsAdult || KokiriSword || CanUse(MASTER_SWORD) || CanUse(BIGGORON_SWORD))) || + (GerudoFortress.IsNot(GERUDOFORTRESS_NORMAL) && GerudoFortress.IsNot(GERUDOFORTRESS_FAST)); + + HasShield = CanUse(HYLIAN_SHIELD) || CanUse(DEKU_SHIELD); //Mirror shield can't reflect attacks + CanShield = CanUse(MIRROR_SHIELD) || HasShield; + CanJumpslash = IsAdult || Sticks || KokiriSword; + CanUseProjectile = HasExplosives || CanUse(BOW) || CanUse(HOOKSHOT) || CanUse(SLINGSHOT) || CanUse(BOOMERANG); + CanUseMagicArrow = CanUse(FIRE_ARROWS) || CanUse(ICE_ARROWS) || CanUse(LIGHT_ARROWS); + + //Bridge and LACS Requirements + MedallionCount = (ForestMedallion ? 1:0) + (FireMedallion ? 1:0) + (WaterMedallion ? 1:0) + (SpiritMedallion ? 1:0) + (ShadowMedallion ? 1:0) + (LightMedallion ? 1:0); + StoneCount = (KokiriEmerald ? 1:0) + (GoronRuby ? 1:0) + (ZoraSapphire ? 1:0); + DungeonCount = (DekuTreeClear ? 1:0) + (DodongosCavernClear ? 1:0) + (JabuJabusBellyClear ? 1:0) + (ForestTempleClear ? 1:0) + (FireTempleClear ? 1:0) + (WaterTempleClear ? 1:0) + (SpiritTempleClear ? 1:0) + (ShadowTempleClear ? 1:0); + HasAllStones = StoneCount == 3; + HasAllMedallions = MedallionCount == 6; + + CanBuildRainbowBridge = Bridge.Is(RAINBOWBRIDGE_OPEN) || + (Bridge.Is(RAINBOWBRIDGE_VANILLA) && ShadowMedallion && SpiritMedallion && LightArrows) || + (Bridge.Is(RAINBOWBRIDGE_STONES) && StoneCount >= BridgeStoneCount.Value()) || + (Bridge.Is(RAINBOWBRIDGE_MEDALLIONS) && MedallionCount >= BridgeMedallionCount.Value()) || + (Bridge.Is(RAINBOWBRIDGE_REWARDS) && StoneCount + MedallionCount >= BridgeRewardCount.Value()) || + (Bridge.Is(RAINBOWBRIDGE_DUNGEONS) && DungeonCount >= BridgeDungeonCount.Value()) || + (Bridge.Is(RAINBOWBRIDGE_TOKENS) && GoldSkulltulaTokens >= BridgeTokenCount.Value()); + + CanTriggerLACS = (LACSCondition == LACSCONDITION_VANILLA && ShadowMedallion && SpiritMedallion) || + (LACSCondition == LACSCONDITION_STONES && StoneCount >= LACSStoneCount.Value()) || + (LACSCondition == LACSCONDITION_MEDALLIONS && MedallionCount >= LACSMedallionCount.Value()) || + (LACSCondition == LACSCONDITION_REWARDS && StoneCount + MedallionCount >= LACSRewardCount.Value()) || + (LACSCondition == LACSCONDITION_DUNGEONS && DungeonCount >= LACSDungeonCount.Value()) || + (LACSCondition == LACSCONDITION_TOKENS && GoldSkulltulaTokens >= LACSTokenCount.Value()); + + } + + bool SmallKeys(Key dungeon, uint8_t requiredAmount) { + return SmallKeys(dungeon, requiredAmount, requiredAmount); + } + + bool SmallKeys(Key dungeon, uint8_t requiredAmountGlitchless, uint8_t requiredAmountGlitched) { + switch (dungeon) { + case FOREST_TEMPLE: + if (IsGlitched && (GetDifficultyValueFromString(GlitchHookshotJump_Boots) >= static_cast(GlitchDifficulty::INTERMEDIATE) || GetDifficultyValueFromString(GlitchHoverBoost) >= static_cast(GlitchDifficulty::NOVICE) || + (GetDifficultyValueFromString(GlitchHover) >= static_cast(GlitchDifficulty::NOVICE) && GetDifficultyValueFromString(GlitchISG) >= static_cast(GlitchDifficulty::INTERMEDIATE)))) { + return ForestTempleKeys >= requiredAmountGlitched; + } + return ForestTempleKeys >= requiredAmountGlitchless; + + case FIRE_TEMPLE: + if (IsGlitched && (GetDifficultyValueFromString(GlitchLedgeClip) >= static_cast(GlitchDifficulty::INTERMEDIATE) || GetDifficultyValueFromString(GlitchHover) >= static_cast(GlitchDifficulty::INTERMEDIATE))) { + return FireTempleKeys >= requiredAmountGlitched; + } + return FireTempleKeys >= requiredAmountGlitchless; + + case WATER_TEMPLE: + if (IsGlitched && (false)) { + return WaterTempleKeys >= requiredAmountGlitched; + } + return WaterTempleKeys >= requiredAmountGlitchless; + + case SPIRIT_TEMPLE: + if (IsGlitched && (false)) { + return SpiritTempleKeys >= requiredAmountGlitched; + } + return SpiritTempleKeys >= requiredAmountGlitchless; + + case SHADOW_TEMPLE: + if (IsGlitched && (GetDifficultyValueFromString(GlitchHookshotClip) >= static_cast(GlitchDifficulty::NOVICE))) { + return ShadowTempleKeys >= requiredAmountGlitched; + } + return ShadowTempleKeys >= requiredAmountGlitchless; + + case BOTTOM_OF_THE_WELL: + if (IsGlitched && (false)) { + return BottomOfTheWellKeys >= requiredAmountGlitched; + } + return BottomOfTheWellKeys >= requiredAmountGlitchless; + + case GERUDO_TRAINING_GROUNDS: + if (IsGlitched && (false)) { + return GerudoTrainingGroundsKeys >= requiredAmountGlitched; + } + return GerudoTrainingGroundsKeys >= requiredAmountGlitchless; + + case GANONS_CASTLE: + if (IsGlitched && (false)) { + return GanonsCastleKeys >= requiredAmountGlitched; + } + return GanonsCastleKeys >= requiredAmountGlitchless; + + case MARKET_TREASURE_CHEST_GAME: + if (IsGlitched && (false)) { + return TreasureGameKeys >= requiredAmountGlitched; + } + return TreasureGameKeys >= requiredAmountGlitchless; + + default: + return false; + } + } + + bool EventsUpdated() { + + if (DekuTreeClearPast != DekuTreeClear || + GoronRubyPast != GoronRuby || + ZoraSapphirePast != ZoraSapphire || + ForestTrialClearPast != ForestTrialClear || + FireTrialClearPast != FireTrialClear || + WaterTrialClearPast != WaterTrialClear || + ShadowTrialClearPast != ShadowTrialClear || + SpiritTrialClearPast != SpiritTrialClear || + LightTrialClearPast != LightTrialClear || + DrainWellPast != DrainWell || + DampesWindmillAccessPast != DampesWindmillAccess || + TimeTravelPast != TimeTravel) { + DekuTreeClearPast = DekuTreeClear; + GoronRubyPast = GoronRuby; + ZoraSapphirePast = ZoraSapphire; + ForestTrialClearPast = ForestTrialClear; + FireTrialClearPast = FireTrialClear; + WaterTrialClearPast = WaterTrialClear; + ShadowTrialClearPast = ShadowTrialClear; + SpiritTrialClearPast = SpiritTrialClear; + LightTrialClearPast = LightTrialClear; + DrainWellPast = DrainWell; + DampesWindmillAccessPast = DampesWindmillAccess; + return true; + } + return false; + } + + //Reset All Logic to false + void LogicReset() { + //Settings-dependent variables + IsKeysanity = Keysanity.Is(KEYSANITY_ANYWHERE) || Keysanity.Is(KEYSANITY_OVERWORLD) || Keysanity.Is(KEYSANITY_ANY_DUNGEON); + AmmoCanDrop = AmmoDrops.IsNot(AMMODROPS_NONE); + + //Child item logic + KokiriSword = false; + ZeldasLetter = false; + WeirdEgg = false; + HasBottle = false; + Bombchus = false; + Bombchus5 = false; + Bombchus10 = false; + Bombchus20 = false; + MagicBean = false; + MagicBeanPack = false; + RutosLetter = false; + Boomerang = false; + DinsFire = false; + FaroresWind = false; + NayrusLove = false; + LensOfTruth = false; + ShardOfAgony = false; + SkullMask = false; + MaskOfTruth = false; + + //Adult logic + Hammer = false; + IronBoots = false; + HoverBoots = false; + MirrorShield = false; + GoronTunic = false; + ZoraTunic = false; + Epona = false; + BigPoe = false; + GerudoToken = false; + FireArrows = false; + IceArrows = false; + LightArrows = false; + MasterSword = false; + BiggoronSword = false; + + //Trade Quest + PocketEgg = false; + Cojiro = false; + OddMushroom = false; + OddPoultice = false; + PoachersSaw = false; + BrokenSword = false; + Prescription = false; + EyeballFrog = false; + Eyedrops = false; + ClaimCheck = false; + + //Trade Quest Events + WakeUpAdultTalon = false; + CojiroAccess = false; + OddMushroomAccess = false; + OddPoulticeAccess = false; + PoachersSawAccess = false; + BrokenSwordAccess = false; + PrescriptionAccess = false; + EyeballFrogAccess = false; + EyedropsAccess = false; + DisableTradeRevert = false; + + //Songs + ZeldasLullaby = false; + SariasSong = false; + SunsSong = false; + SongOfStorms = false; + EponasSong = false; + SongOfTime = false; + MinuetOfForest = false; + BoleroOfFire = false; + SerenadeOfWater = false; + RequiemOfSpirit = false; + NocturneOfShadow = false; + PreludeOfLight = false; + + //Stones and Meddallions + ForestMedallion = false; + FireMedallion = false; + WaterMedallion = false; + SpiritMedallion = false; + ShadowMedallion = false; + LightMedallion = false; + KokiriEmerald = false; + GoronRuby = false; + ZoraSapphire = false; + + //Dungeon Clears + DekuTreeClear = false; + DodongosCavernClear = false; + JabuJabusBellyClear = false; + ForestTempleClear = false; + FireTempleClear = false; + WaterTempleClear = false; + SpiritTempleClear = false; + ShadowTempleClear = false; + + //Trial Clears + ForestTrialClear = false; + FireTrialClear = false; + WaterTrialClear = false; + SpiritTrialClear = false; + ShadowTrialClear = false; + LightTrialClear = false; + + //Progressive Items + ProgressiveBulletBag = 0; + ProgressiveBombBag = 0; + ProgressiveMagic = 0; + ProgressiveScale = 0; + ProgressiveHookshot = 0; + ProgressiveBow = 0; + ProgressiveWallet = 0; + ProgressiveStrength = 0; + ProgressiveOcarina = 0; + ProgressiveGiantKnife = 0; + + //Keys + ForestTempleKeys = 0; + //If not keysanity, start with 1 logical key to account for automatically unlocking the basement door in vanilla FiT + FireTempleKeys = IsKeysanity || Dungeon::FireTemple.IsMQ() ? 0 : 1; + WaterTempleKeys = 0; + SpiritTempleKeys = 0; + ShadowTempleKeys = 0; + GanonsCastleKeys = 0; + GerudoFortressKeys = 0; + GerudoTrainingGroundsKeys = 0; + BottomOfTheWellKeys = 0; + TreasureGameKeys = 0; + + //Boss Keys + BossKeyForestTemple = 0; + BossKeyFireTemple = 0; + BossKeyWaterTemple = 0; + BossKeySpiritTemple = 0; + BossKeyShadowTemple = 0; + BossKeyGanonsCastle = 0; + + //Gold Skulltula Count + GoldSkulltulaTokens = 0; + + //Bottle Count + Bottles = 0; + NumBottles = 0; + NoBottles = false; + + + + //Drops and Bottle Contents Access + DekuNutDrop = false; + NutPot = false; + NutCrate = false; + DekuBabaNuts = false; + DekuStickDrop = false; + StickPot = false; + DekuBabaSticks = false; + BugsAccess = false; + BugShrub = false; + WanderingBugs = false; + BugRock = false; + BlueFireAccess = false; + FishAccess = false; + FishGroup = false; + LoneFish = false; + FairyAccess = false; + GossipStoneFairy = false; + BeanPlantFairy = false; + ButterflyFairy = false; + FairyPot = false; + FreeFairies = false; + FairyPond = false; + BombchuDrop = false; + + BuyBombchus5 = false; + BuyBombchus10 = false; + BuyBombchus20 = false; + BuySeed = false; + BuyArrow = false; + BuyBomb = false; + BuyGPotion = false; + BuyBPotion = false; + MagicRefill = false; + + PieceOfHeart = 0; + HeartContainer = 0; + DoubleDefense = false; + + /* --- HELPERS, EVENTS, AND LOCATION ACCESS --- */ + /* These are used to simplify reading the logic, but need to be updated + / every time a base value is updated. */ + + Slingshot = false; + Ocarina = false; + OcarinaOfTime = false; + BombBag = false; + MagicMeter = false; + Hookshot = false; + Longshot = false; + Bow = false; + GoronBracelet = false; + SilverGauntlets = false; + GoldenGauntlets = false; + SilverScale = false; + GoldScale = false; + AdultsWallet = false; + + ChildScarecrow = false; + AdultScarecrow = false; + ScarecrowSong = false; + Scarecrow = false; + DistantScarecrow = false; + + Bombs = false; + DekuShield = false; + HylianShield = false; + Nuts = false; + Sticks = false; + Bugs = false; + BlueFire = false; + Fish = false; + Fairy = false; + BottleWithBigPoe = false; + + FoundBombchus = false; + CanPlayBowling = false; + HasBombchus = false; + HasExplosives = false; + HasBoots = false; + IsChild = false; + IsAdult = false; + IsGlitched = Settings::Logic.Is(LOGIC_GLITCHED); + CanBlastOrSmash = false; + CanChildAttack = false; + CanChildDamage = false; + CanCutShrubs = false; + CanDive = false; + CanLeaveForest = false; + CanPlantBugs = false; + CanRideEpona = false; + CanStunDeku = false; + CanSummonGossipFairy = false; + CanSummonGossipFairyWithoutSuns = false; + //CanPlantBean = false; + CanOpenBombGrotto = false; + CanOpenStormGrotto = false; + BigPoeKill = false; + HookshotOrBoomerang = false; + + BaseHearts = StartingHearts.Value() + 1; + Hearts = 0; + Multiplier = (DamageMultiplier.Value() < 6) ? DamageMultiplier.Value() : 10; + EffectiveHealth = 0; + FireTimer = 0; + WaterTimer = 0; + + GuaranteeTradePath = false; + GuaranteeHint = false; + HasFireSource = false; + HasFireSourceWithTorch = false; + + CanFinishGerudoFortress = false; + + HasShield = false; + CanShield = false; + CanJumpslash = false; + CanUseProjectile = false; + CanUseMagicArrow = false; + + //Bridge Requirements + HasAllStones = false; + HasAllMedallions = false; + CanBuildRainbowBridge = false; + CanTriggerLACS = false; + + //Other + AtDay = false; + AtNight = false; + Age = Settings::ResolvedStartingAge; + + //Events + ShowedMidoSwordAndShield = false; + CarpenterRescue = false; + GF_GateOpen = false; + GtG_GateOpen = false; + DampesWindmillAccess = false; + DrainWell = false; + GoronCityChildFire = false; + GCWoodsWarpOpen = false; + GCDaruniasDoorOpenChild = false; + StopGCRollingGoronAsAdult = false; + WaterTempleLow = false; + WaterTempleMiddle = false; + WaterTempleHigh = false; + KakarikoVillageGateOpen = false; + KingZoraThawed = false; + ForestTempleJoelle = false; + ForestTempleBeth = false; + ForestTempleJoAndBeth = false; + ForestTempleAmy = false; + ForestTempleMeg = false; + ForestTempleAmyAndMeg = false; + FireLoopSwitch = false; + LinksCow = false; + AtDampeTime = false; + DeliverLetter = false; + TimeTravel = false; + + DrainWellPast = false; + DampesWindmillAccessPast = false; + DekuTreeClearPast = false; + GoronRubyPast = false; + ZoraSapphirePast = false; + ForestTrialClearPast = false; + FireTrialClearPast = false; + WaterTrialClearPast = false; + SpiritTrialClearPast = false; + ShadowTrialClearPast = false; + LightTrialClearPast = false; + BuyDekuShieldPast = false; + TimeTravelPast = false; + } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/logic.hpp b/soh/soh/Enhancements/randomizer/3drando/logic.hpp new file mode 100644 index 000000000..9863878d1 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/logic.hpp @@ -0,0 +1,387 @@ +#pragma once + +#include "keys.hpp" +#include + +namespace Logic { +extern bool noVariable; + +// Child item logic +extern bool KokiriSword; +extern bool Slingshot; +extern bool ZeldasLetter; +extern bool WeirdEgg; +extern bool HasBottle; +extern bool BombBag; +extern bool Bombchus; +extern bool Bombchus5; +extern bool Bombchus10; +extern bool Bombchus20; +extern bool MagicBean; +extern bool MagicBeanPack; +extern bool RutosLetter; +extern bool Boomerang; +extern bool DinsFire; +extern bool FaroresWind; +extern bool NayrusLove; +extern bool LensOfTruth; +extern bool ShardOfAgony; +extern bool SkullMask; +extern bool MaskOfTruth; + +// Adult logic +extern bool Bow; +extern bool Hammer; +extern bool IronBoots; +extern bool HoverBoots; +extern bool MirrorShield; +extern bool GoronTunic; +extern bool ZoraTunic; +extern bool Epona; +extern bool BigPoe; +extern bool GerudoToken; +extern bool FireArrows; +extern bool IceArrows; +extern bool LightArrows; +extern bool MasterSword; +extern bool BiggoronSword; + +// Trade Quest +extern bool PocketEgg; +extern bool Cojiro; +extern bool OddMushroom; +extern bool OddPoultice; +extern bool PoachersSaw; +extern bool BrokenSword; +extern bool Prescription; +extern bool EyeballFrog; +extern bool Eyedrops; +extern bool ClaimCheck; + +// Trade Quest Events +extern bool WakeUpAdultTalon; +extern bool CojiroAccess; +extern bool OddMushroomAccess; +extern bool OddPoulticeAccess; +extern bool PoachersSawAccess; +extern bool BrokenSwordAccess; +extern bool PrescriptionAccess; +extern bool EyeballFrogAccess; +extern bool EyedropsAccess; +extern bool DisableTradeRevert; + +// Songs +extern bool ZeldasLullaby; +extern bool SariasSong; +extern bool SunsSong; +extern bool SongOfStorms; +extern bool EponasSong; +extern bool SongOfTime; +extern bool MinuetOfForest; +extern bool BoleroOfFire; +extern bool SerenadeOfWater; +extern bool RequiemOfSpirit; +extern bool NocturneOfShadow; +extern bool PreludeOfLight; + +// Stones and Meddallions +extern bool ForestMedallion; +extern bool FireMedallion; +extern bool WaterMedallion; +extern bool SpiritMedallion; +extern bool ShadowMedallion; +extern bool LightMedallion; +extern bool KokiriEmerald; +extern bool GoronRuby; +extern bool ZoraSapphire; + +// Dungeon Clears +extern bool DekuTreeClear; +extern bool DodongosCavernClear; +extern bool JabuJabusBellyClear; +extern bool ForestTempleClear; +extern bool FireTempleClear; +extern bool WaterTempleClear; +extern bool SpiritTempleClear; +extern bool ShadowTempleClear; + +// Trial Clears +extern bool ForestTrialClear; +extern bool FireTrialClear; +extern bool WaterTrialClear; +extern bool SpiritTrialClear; +extern bool ShadowTrialClear; +extern bool LightTrialClear; + +// Progression Items +extern uint8_t ProgressiveBulletBag; +extern uint8_t ProgressiveBombBag; +extern uint8_t ProgressiveScale; +extern uint8_t ProgressiveHookshot; +extern uint8_t ProgressiveBow; +extern uint8_t ProgressiveStrength; +extern uint8_t ProgressiveWallet; +extern uint8_t ProgressiveMagic; +extern uint8_t ProgressiveOcarina; +extern uint8_t ProgressiveGiantKnife; + +// Keysanity +extern bool IsKeysanity; + +// Keys +extern uint8_t ForestTempleKeys; +extern uint8_t FireTempleKeys; +extern uint8_t WaterTempleKeys; +extern uint8_t SpiritTempleKeys; +extern uint8_t ShadowTempleKeys; +extern uint8_t BottomOfTheWellKeys; +extern uint8_t GerudoTrainingGroundsKeys; +extern uint8_t GerudoFortressKeys; +extern uint8_t GanonsCastleKeys; +extern uint8_t TreasureGameKeys; + +// Boss Keys +extern bool BossKeyForestTemple; +extern bool BossKeyFireTemple; +extern bool BossKeyWaterTemple; +extern bool BossKeySpiritTemple; +extern bool BossKeyShadowTemple; +extern bool BossKeyGanonsCastle; + +// Gold Skulltula Count +extern uint8_t GoldSkulltulaTokens; + +// Bottle Count, with and without Ruto's Letter +extern uint8_t Bottles; +extern uint8_t NumBottles; +extern bool NoBottles; + +// item and bottle drops +extern bool DekuNutDrop; +extern bool NutPot; +extern bool NutCrate; +extern bool DekuBabaNuts; +extern bool DekuStickDrop; +extern bool StickPot; +extern bool DekuBabaSticks; +extern bool BugsAccess; +extern bool BugShrub; +extern bool WanderingBugs; +extern bool BugRock; +extern bool BlueFireAccess; +extern bool FishAccess; +extern bool FishGroup; +extern bool LoneFish; +extern bool FairyAccess; +extern bool GossipStoneFairy; +extern bool BeanPlantFairy; +extern bool ButterflyFairy; +extern bool FairyPot; +extern bool FreeFairies; +extern bool FairyPond; +extern bool BombchuDrop; + +extern bool BuyBombchus5; +extern bool BuyBombchus10; +extern bool BuyBombchus20; +extern bool BuyArrow; +extern bool BuyBomb; +extern bool BuyGPotion; +extern bool BuyBPotion; +extern bool BuySeed; +extern bool MagicRefill; + +extern uint8_t PieceOfHeart; +extern uint8_t HeartContainer; +extern bool DoubleDefense; + +/* --- HELPERS --- */ +/* These are used to simplify reading the logic, but need to be updated +/ every time a base value is updated. */ + +extern bool Ocarina; +extern bool OcarinaOfTime; +extern bool MagicMeter; +extern bool Hookshot; +extern bool Longshot; +extern bool GoronBracelet; +extern bool SilverGauntlets; +extern bool GoldenGauntlets; +extern bool SilverScale; +extern bool GoldScale; +extern bool AdultsWallet; + +extern bool ChildScarecrow; +extern bool AdultScarecrow; +extern bool ScarecrowSong; +extern bool Scarecrow; +extern bool DistantScarecrow; + +extern bool Bombs; +extern bool DekuShield; +extern bool HylianShield; +extern bool Nuts; +extern bool Sticks; +extern bool Bugs; +extern bool BlueFire; +extern bool Fish; +extern bool Fairy; +extern bool BottleWithBigPoe; + +extern bool Bombs; +extern bool FoundBombchus; +extern bool CanPlayBowling; +extern bool HasBombchus; +extern bool HasExplosives; +extern bool HasBoots; +extern bool IsChild; +extern bool IsAdult; +extern bool IsGlitched; +extern bool CanBlastOrSmash; +extern bool CanChildAttack; +extern bool CanChildDamage; +extern bool CanCutShrubs; +extern bool CanDive; +extern bool CanLeaveForest; +extern bool CanPlantBugs; +extern bool CanRideEpona; +extern bool CanStunDeku; +extern bool CanSummonGossipFairy; +extern bool CanSummonGossipFairyWithoutSuns; +extern bool NeedNayrusLove; +extern bool CanSurviveDamage; +extern bool CanTakeDamage; +extern bool CanTakeDamageTwice; +// extern bool CanPlantBean; +extern bool CanOpenBombGrotto; +extern bool CanOpenStormGrotto; +extern bool HookshotOrBoomerang; +extern bool CanGetNightTimeGS; +extern bool BigPoeKill; + +extern uint8_t BaseHearts; +extern uint8_t Hearts; +extern uint8_t Multiplier; +extern uint8_t EffectiveHealth; +extern uint8_t FireTimer; +extern uint8_t WaterTimer; + +extern bool GuaranteeTradePath; +extern bool GuaranteeHint; +extern bool HasFireSource; +extern bool HasFireSourceWithTorch; + +// Gerudo Fortress +extern bool CanFinishGerudoFortress; + +extern bool HasShield; +extern bool CanShield; +extern bool CanJumpslash; +extern bool CanUseProjectile; +extern bool CanUseMagicArrow; + +// Bridge Requirements +extern bool HasAllStones; +extern bool HasAllMedallions; +extern bool CanBuildRainbowBridge; +extern bool CanTriggerLACS; + +// Other +extern bool AtDay; +extern bool AtNight; +extern bool LinksCow; +extern uint8_t Age; + +// Events +extern bool ShowedMidoSwordAndShield; +extern bool CarpenterRescue; +extern bool DampesWindmillAccess; +extern bool GF_GateOpen; +extern bool GtG_GateOpen; +extern bool DrainWell; +extern bool GoronCityChildFire; +extern bool GCWoodsWarpOpen; +extern bool GCDaruniasDoorOpenChild; +extern bool StopGCRollingGoronAsAdult; +extern bool WaterTempleLow; +extern bool WaterTempleMiddle; +extern bool WaterTempleHigh; +extern bool KingZoraThawed; +extern bool AtDampeTime; +extern bool DeliverLetter; +extern bool KakarikoVillageGateOpen; +extern bool ForestTempleJoelle; +extern bool ForestTempleBeth; +extern bool ForestTempleJoAndBeth; +extern bool ForestTempleAmy; +extern bool ForestTempleMeg; +extern bool ForestTempleAmyAndMeg; +extern bool FireLoopSwitch; +extern bool TimeTravel; + +/* --- END OF HELPERS --- */ + +extern uint8_t AddedProgressiveBulletBags; +extern uint8_t AddedProgressiveBombBags; +extern uint8_t AddedProgressiveMagics; +extern uint8_t AddedProgressiveScales; +extern uint8_t AddedProgressiveHookshots; +extern uint8_t AddedProgressiveBows; +extern uint8_t AddedProgressiveWallets; +extern uint8_t AddedProgressiveStrengths; +extern uint8_t AddedProgressiveOcarinas; +extern uint8_t TokensInPool; + +enum class HasProjectileAge { + Adult, + Child, + Both, + Either, +}; + +enum class GlitchType { + RestrictedItems, + SuperStab, + ISG, + BombHover, + BombOI, + OutdoorBombOI, + WindmillBombOI, + IndoorBombOI, + DungeonBombOI, + HoverBoost, + SuperSlide, + Megaflip, + ASlide, + HammerSlide, + LedgeCancel, + ActionSwap, + QPA, + HookshotClip, + HookshotJump_Bonk, + HookshotJump_Boots, + CutsceneDive, + NaviDive_Stick, + TripleSlashClip, + LedgeClip, + SeamWalk, +}; + +enum class GlitchDifficulty { + NOVICE = 1, + INTERMEDIATE, + ADVANCED, + EXPERT, + HERO, +}; + +void UpdateHelpers(); +bool CanPlay(bool song); +bool CanUse(uint32_t itemName); +bool HasProjectile(HasProjectileAge age); +bool SmallKeys(Key dungeon, uint8_t requiredAmount); +bool SmallKeys(Key dungeon, uint8_t requiredAmountGlitchless, uint8_t requiredAmountGlitched); +bool CanDoGlitch(GlitchType glitch, GlitchDifficulty difficulty); +bool EventsUpdated(); +void LogicReset(); +} // namespace Logic \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/3drando/menu.cpp b/soh/soh/Enhancements/randomizer/3drando/menu.cpp new file mode 100644 index 000000000..80e5d63b2 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/menu.cpp @@ -0,0 +1,550 @@ +#include +#include +#include +#include +#include + +#include "cosmetics.hpp" +#include "menu.hpp" +#include "patch.hpp" +#include "preset.hpp" +#include "randomizer.hpp" +#include "settings.hpp" +#include "spoiler_log.hpp" +#include "location_access.hpp" +#include "debug.hpp" +#include +#include "randomizerTypes.h" + +namespace { +bool seedChanged; +uint16_t pastSeedLength; +std::vector presetEntries; +std::vector menuList; +Option* currentSetting; +Menu* currentMenu; +} // namespace + +void PrintTopScreen() { + SPDLOG_INFO("\x1b[2;11H%sOcarina of Time 3D Randomizer%s", CYAN, RESET); + SPDLOG_INFO("\x1b[3;18H%s%s-%s%s", CYAN, RANDOMIZER_VERSION, COMMIT_NUMBER, RESET); + SPDLOG_INFO("\x1b[4;10HA/B/D-pad: Navigate Menu\n"); + SPDLOG_INFO(" Select: Exit to Homebrew Menu\n"); + SPDLOG_INFO(" Y: New Random Seed\n"); + SPDLOG_INFO(" X: Input Custom Seed\n"); + SPDLOG_INFO("\x1b[11;7HCurrent Seed: %s", Settings::seed.c_str()); +} + +void MenuInit() { + Settings::InitSettings(); + + seedChanged = false; + pastSeedLength = Settings::seed.length(); + + Menu* main = new Menu("Main", MenuType::MainMenu, &Settings::mainMenu, MAIN_MENU); + menuList.push_back(main); + currentMenu = main; + + srand(time(NULL)); + + if (!CreatePresetDirectories()) { + printf("\x1b[20;5Failed to create preset directories."); + printf("\x1b[21;5Loading presets might crash."); + } + + // If cached presets exist, load them + LoadCachedSettings(); + LoadCachedCosmetics(); + // If Randomize all settings in a category is selected + // Re-randomize them + Settings::RandomizeAllSettings(); + + PrintTopScreen(); + + PrintMainMenu(); +} + +#define KEY_DUP 0 +#define KEY_DDOWN 1 +#define KEY_DLEFT 2 +#define KEY_DRIGHT 3 +#define KEY_A 4 +#define KEY_B 5 +#define KEY_Y 6 +#define KEY_X 7 + +void MoveCursor(uint32_t kDown, bool updatedByHeld) { + // Option sub menus need special checking for locked options + if (currentMenu->mode == OPTION_SUB_MENU) { + // Cancel if holding and reached first/last selectable option + if (updatedByHeld) { + bool noSelectableOption = true; + if (kDown & KEY_DUP) { + for (int i = currentMenu->menuIdx - 1; i >= 0; i--) { + if (!currentMenu->settingsList->at(i)->IsHidden() && + !currentMenu->settingsList->at(i)->IsLocked()) { + noSelectableOption = false; + break; + } + } + } + if (kDown & KEY_DDOWN) { + for (size_t i = currentMenu->menuIdx + 1; i < currentMenu->settingsList->size(); i++) { + if (!currentMenu->settingsList->at(i)->IsHidden() && + !currentMenu->settingsList->at(i)->IsLocked()) { + noSelectableOption = false; + break; + } + } + } + if (noSelectableOption) { + return; + } + } + // Loop through settings until an unlocked one is reached + do { + if ((kDown & KEY_DUP) != 0) { + currentMenu->menuIdx--; + } + if ((kDown & KEY_DDOWN) != 0) { + currentMenu->menuIdx++; + } + + // Bounds checking + if (currentMenu->menuIdx == currentMenu->settingsList->size()) { + currentMenu->menuIdx = 0; + } else if (currentMenu->menuIdx == 0xFFFF) { + currentMenu->menuIdx = static_cast(currentMenu->settingsList->size() - 1); + } + + currentSetting = currentMenu->settingsList->at(currentMenu->menuIdx); + } while (currentSetting->IsLocked() || currentSetting->IsHidden()); + } + // All other menus except reset-to-defaults confirmation + else if (currentMenu->mode != RESET_TO_DEFAULTS) { + // Cancel if holding and reached first/last menu + if (updatedByHeld) { + if ((kDown & KEY_DUP && currentMenu->menuIdx == 0) || + (kDown & KEY_DDOWN && currentMenu->menuIdx == currentMenu->itemsList->size() - 1)) { + return; + } + } + + if (kDown & KEY_DUP) { + currentMenu->menuIdx--; + } + if (kDown & KEY_DDOWN) { + currentMenu->menuIdx++; + } + + // Bounds checking + uint16_t max = -1; + if (currentMenu->mode == LOAD_PRESET || currentMenu->mode == DELETE_PRESET) { // Number of presets if applicable + max = presetEntries.size(); + } else if (currentMenu->mode == GENERATE_MODE) { // Generate menu: 2 options + max = 2; + } else if (currentMenu->itemsList != nullptr) { + max = currentMenu->itemsList->size(); // Default max: Number of items in menu + } + if (currentMenu->menuIdx == max) { + currentMenu->menuIdx = 0; + } else if (currentMenu->menuIdx == 0xFFFF) { + currentMenu->menuIdx = max - 1; + } + + // Scroll Check + if (currentMenu->menuIdx > currentMenu->settingBound + (MAX_SUBMENUS_ON_SCREEN - 1)) { + currentMenu->settingBound = currentMenu->menuIdx - (MAX_SUBMENUS_ON_SCREEN - 1); + } else if (currentMenu->menuIdx < currentMenu->settingBound) { + currentMenu->settingBound = currentMenu->menuIdx; + } + } +} + +void MenuUpdate(uint32_t kDown, bool updatedByHeld) { + // Check for menu change + // If user pressed A on a non-option, non-action menu, they're navigating to a new menu + if (kDown & KEY_A && currentMenu->mode != OPTION_SUB_MENU && currentMenu->type != MenuType::Action) { + if (currentMenu->itemsList->size() > currentMenu->menuIdx) { + Menu* newMenu; + newMenu = currentMenu->itemsList->at(currentMenu->menuIdx); + menuList.push_back(newMenu); + currentMenu = menuList.back(); + ModeChangeInit(); + kDown = 0; + } + // If they pressed B on any menu other than main, go backwards to the previous menu + } else if (kDown & KEY_B && currentMenu->mode != MAIN_MENU) { + // Want to reset generate menu when leaving + if (currentMenu->mode == POST_GENERATE) { + currentMenu->mode = GENERATE_MODE; + } + PrintTopScreen(); + menuList.pop_back(); + currentMenu = menuList.back(); + ModeChangeInit(); + kDown = 0; + } + + if (currentMenu->mode != GENERATE_MODE) { + + // New Random Seed + if (kDown & KEY_Y) { + pastSeedLength = Settings::seed.length(); + Settings::seed = std::to_string(rand()); + seedChanged = true; + } + + // Input Custom Seed + if (kDown & KEY_X) { + pastSeedLength = Settings::seed.length(); + Settings::seed = GetInput("Enter Seed"); + seedChanged = true; + } + + // Reprint seed if it changed + if (seedChanged) { + std::string spaces = ""; + spaces.append(pastSeedLength, ' '); + printf("\x1b[11;21H%s", spaces.c_str()); + printf("\x1b[11;21H%s", Settings::seed.c_str()); + seedChanged = false; + } + } + + // Print current menu (if applicable) + MoveCursor(kDown, updatedByHeld); // Move cursor, if applicable + if (currentMenu->mode == MAIN_MENU) { + PrintMainMenu(); + ClearDescription(); + } else if (currentMenu->mode == OPTION_SUB_MENU) { + UpdateOptionSubMenu(kDown); + PrintOptionSubMenu(); + } else if (currentMenu->mode == LOAD_PRESET) { + UpdatePresetsMenu(kDown); + PrintPresetsMenu(); + } else if (currentMenu->mode == DELETE_PRESET) { + UpdatePresetsMenu(kDown); + PrintPresetsMenu(); + } else if (currentMenu->mode == RESET_TO_DEFAULTS) { + UpdateResetToDefaultsMenu(kDown); + PrintResetToDefaultsMenu(); + } else if (currentMenu->mode == GENERATE_MODE) { + UpdateGenerateMenu(kDown); + if (currentMenu->mode != POST_GENERATE) { + PrintGenerateMenu(); + } + } else if (currentMenu->mode == SUB_MENU) { + PrintSubMenu(); + } +} + +void ModeChangeInit() { + if (currentMenu->mode == OPTION_SUB_MENU) { + // loop through until we reach an unlocked setting + while (currentMenu->settingsList->at(currentMenu->menuIdx)->IsLocked() || + currentMenu->settingsList->at(currentMenu->menuIdx)->IsHidden()) { + currentMenu->menuIdx++; + } + currentSetting = currentMenu->settingsList->at(currentMenu->menuIdx); + + } else if (currentMenu->mode == SAVE_PRESET) { + ClearDescription(); + if (SaveSpecifiedPreset(GetInput("Preset Name").substr(0, 19), OptionCategory::Setting)) { + printf("\x1b[24;5HPreset Saved!"); + printf("\x1b[26;5HPress B to return to the preset menu."); + } else { + printf("\x1b[24;5HFailed to save preset."); + printf("\x1b[26;5HPress B to return to the preset menu."); + } + + } else if (currentMenu->mode == LOAD_PRESET || currentMenu->mode == DELETE_PRESET) { + presetEntries = GetSettingsPresets(); + + } else if (currentMenu->mode == GENERATE_MODE) { + } +} + +void UpdateCustomCosmeticColors(uint32_t kDown) { + if (kDown & KEY_A) { + if (currentSetting->GetSelectedOptionText().compare(0, 8, Cosmetics::CUSTOM_COLOR_PREFIX) == 0) { + std::string newColor = GetInput("Enter a 6 digit hex color").substr(0, 6); + if (Cosmetics::ValidHexString(newColor)) { + currentSetting->SetSelectedOptionText(Cosmetics::CustomColorOptionText(newColor)); + } + } + } +} + +void UpdateOptionSubMenu(uint32_t kDown) { + if ((kDown & KEY_DRIGHT) != 0) { + currentSetting->NextOptionIndex(); + } + if ((kDown & KEY_DLEFT) != 0) { + currentSetting->PrevOptionIndex(); + } + + // Bounds checking + currentSetting->SanitizeSelectedOptionIndex(); + + currentSetting->SetVariable(); + Settings::ForceChange(kDown, currentSetting); + UpdateCustomCosmeticColors(kDown); +} + +void UpdatePresetsMenu(uint32_t kDown) { + // clear any potential message + ClearDescription(); + if (kDown & KEY_A && currentMenu->mode == LOAD_PRESET && !presetEntries.empty()) { + if (LoadPreset(presetEntries[currentMenu->menuIdx], OptionCategory::Setting)) { + Settings::ResolveExcludedLocationConflicts(); + for (Menu* menu : Settings::GetAllOptionMenus()) { + menu->ResetMenuIndex(); + } + printf("\x1b[24;5HPreset Loaded!"); + } else { + printf("\x1b[24;5HFailed to load preset."); + } + } else if (kDown & KEY_A && currentMenu->mode == DELETE_PRESET && !presetEntries.empty()) { + if (DeletePreset(presetEntries[currentMenu->menuIdx], OptionCategory::Setting)) { + presetEntries.erase(presetEntries.begin() + currentMenu->menuIdx); + if (currentMenu->menuIdx == presetEntries.size()) { // Catch when last preset is deleted + currentMenu->menuIdx--; + } + printf("\x1b[24;5HPreset Deleted."); + } else { + printf("\x1b[24;5HFailed to delete preset."); + } + } +} + +void UpdateResetToDefaultsMenu(uint32_t kDown) { + // clear any potential message + ClearDescription(); + if (kDown & KEY_A) { + Settings::SetDefaultSettings(); + printf("\x1b[24;5HSettings have been reset to defaults."); + } +} + +void UpdateGenerateMenu(uint32_t kDown) { + if ((kDown & KEY_A) != 0) { + Settings::PlayOption = currentMenu->menuIdx; + // GenerateRandomizer(); + // This is just a dummy mode to stop the prompt from appearing again + currentMenu->mode = POST_GENERATE; + } +} + +void PrintMainMenu() { + printf("\x1b[0;%dHMain Settings", 1 + (BOTTOM_WIDTH - 13) / 2); + + for (uint8_t i = 0; i < MAX_SUBMENUS_ON_SCREEN; i++) { + if (i >= Settings::mainMenu.size()) + break; + + Menu* menu = Settings::mainMenu[i]; + + uint8_t row = 3 + i; + // make the current menu green + if (currentMenu->menuIdx == i) { + printf("\x1b[%d;%dH%s>", row, 2, GREEN); + printf("\x1b[%d;%dH%s%s", row, 3, menu->name.c_str(), RESET); + } else { + printf("\x1b[%d;%dH%s", row, 3, menu->name.c_str()); + } + } +} + +void PrintOptionSubMenu() { + // bounds checking incase settings go off screen + // this is complicated to account for hidden settings and there's probably a better way to do it + uint16_t hiddenSettings = 0; + uint16_t visibleSettings = 0; + for (uint16_t i = currentMenu->settingBound; visibleSettings < MAX_SUBMENU_SETTINGS_ON_SCREEN; i++) { + if (i >= currentMenu->settingsList->size()) { + break; + } + if (currentMenu->settingsList->at(i)->IsHidden()) { + hiddenSettings++; + } else { + visibleSettings++; + } + } + bool isLastVisibleSetting = true; + for (size_t i = currentMenu->menuIdx + 1; i < currentMenu->settingsList->size(); i++) { + if (!currentMenu->settingsList->at(i)->IsHidden()) { + isLastVisibleSetting = false; + break; + } + } + if (currentMenu->menuIdx >= + currentMenu->settingBound - (isLastVisibleSetting ? 0 : 1) + MAX_SUBMENU_SETTINGS_ON_SCREEN + hiddenSettings) { + currentMenu->settingBound = currentMenu->menuIdx; + uint8_t offset = 0; + // skip over hidden settings + while (offset < MAX_SUBMENU_SETTINGS_ON_SCREEN - (isLastVisibleSetting ? 1 : 2)) { + currentMenu->settingBound--; + if (currentMenu->settingBound == 0) { + break; + } + offset += currentMenu->settingsList->at(currentMenu->settingBound)->IsHidden() ? 0 : 1; + } + } else if (currentMenu->menuIdx < currentMenu->settingBound + 1) { + currentMenu->settingBound = std::max(currentMenu->menuIdx - 1, 0); + } + + // print menu name + printf("\x1b[0;%dH%s", 1 + (BOTTOM_WIDTH - currentMenu->name.length()) / 2, currentMenu->name.c_str()); + + // keep count of hidden settings to not make blank spaces appear in the list + hiddenSettings = 0; + + for (uint8_t i = 0; i - hiddenSettings < MAX_SUBMENU_SETTINGS_ON_SCREEN; i++) { + // break if there are no more settings to print + if (i + currentMenu->settingBound >= currentMenu->settingsList->size()) + break; + + Option* setting = currentMenu->settingsList->at(i + currentMenu->settingBound); + + uint8_t row = 3 + ((i - hiddenSettings) * 2); + // make the current setting green + if (currentMenu->menuIdx == i + currentMenu->settingBound) { + printf("\x1b[%d;%dH%s>", row, 1, GREEN); + printf("\x1b[%d;%dH%s:", row, 2, setting->GetName().data()); + printf("\x1b[%d;%dH%s%s", row, 26, setting->GetSelectedOptionText().data(), RESET); + // dim to make a locked setting grey + } else if (setting->IsLocked()) { + printf("\x1b[%d;%dH%s%s:", row, 2, DIM, setting->GetName().data()); + printf("\x1b[%d;%dH%s%s", row, 26, setting->GetSelectedOptionText().data(), RESET); + // don't display hidden settings + } else if (setting->IsHidden()) { + hiddenSettings++; + continue; + } else { + printf("\x1b[%d;%dH%s:", row, 2, setting->GetName().data()); + printf("\x1b[%d;%dH%s", row, 26, setting->GetSelectedOptionText().data()); + } + } + + PrintOptionDescription(); +} + +void PrintSubMenu() { + printf("\x1b[0;%dH%s", 1 + (BOTTOM_WIDTH - currentMenu->name.length()) / 2, currentMenu->name.c_str()); + + for (uint8_t i = 0; i < MAX_SUBMENUS_ON_SCREEN; i++) { + if (i >= currentMenu->itemsList->size()) + break; + + uint8_t row = 3 + i; + // make the current menu green + if (currentMenu->menuIdx == currentMenu->settingBound + i) { + printf("\x1b[%d;%dH%s>", row, 2, GREEN); + printf("\x1b[%d;%dH%s%s", row, 3, currentMenu->itemsList->at(currentMenu->settingBound + i)->name.c_str(), + RESET); + } else { + printf("\x1b[%d;%dH%s", row, 3, currentMenu->itemsList->at(currentMenu->settingBound + i)->name.c_str()); + } + } +} + +void PrintPresetsMenu() { + if (presetEntries.empty()) { + printf("\x1b[10;4HNo Presets Detected!"); + printf("\x1b[12;4HPress B to return to the preset menu."); + return; + } + + if (currentMenu->mode == LOAD_PRESET) { + printf("\x1b[0;%dHSelect a Preset to Load", 1 + (BOTTOM_WIDTH - 23) / 2); + } else if (currentMenu->mode == DELETE_PRESET) { + printf("\x1b[0;%dHSelect a Preset to Delete", 1 + (BOTTOM_WIDTH - 25) / 2); + } + + for (uint8_t i = 0; i < MAX_SUBMENU_SETTINGS_ON_SCREEN; i++) { + if (i >= presetEntries.size()) + break; + + std::string preset = presetEntries[i]; + + uint8_t row = 3 + (i * 2); + // make the current preset green + if (currentMenu->menuIdx == i) { + printf("\x1b[%d;%dH%s>", row, 14, GREEN); + printf("\x1b[%d;%dH%s%s", row, 15, preset.c_str(), RESET); + } else { + printf("\x1b[%d;%dH%s", row, 15, preset.c_str()); + } + } +} + +void PrintResetToDefaultsMenu() { + printf("\x1b[10;4HPress A to reset to default settings."); + printf("\x1b[12;4HPress B to return to the preset menu."); +} + +void PrintGenerateMenu() { + printf("\x1b[3;%dHHow will you play?", 1+(BOTTOM_WIDTH-18)/2); + std::vector playOptions = {"3ds Console", "Citra Emulator"}; + + for (uint8_t i = 0; i < playOptions.size(); i++) { + + std::string option = playOptions[i]; + uint8_t row = 6 + (i * 2); + //make the current selection green + if (currentMenu->menuIdx == i) { + printf("\x1b[%d;%dH%s>", row, 14, GREEN); + printf("\x1b[%d;%dH%s%s", row, 15, option.c_str(), RESET); + } else { + printf("\x1b[%d;%dH%s", row, 15, option.c_str()); + } + } +} + +void ClearDescription() { + //clear the previous description + std::string spaces = ""; + spaces.append(9 * TOP_WIDTH, ' '); + printf("\x1b[22;0H%s", spaces.c_str()); +} + +void PrintOptionDescription() { + ClearDescription(); + std::string_view description = currentSetting->GetSelectedOptionDescription(); + + printf("\x1b[22;0H%s", description.data()); +} + +std::string GenerateRandomizer(std::unordered_map cvarSettings) { + // if a blank seed was entered, make a random one + srand(time(NULL)); + Settings::seed = std::to_string(rand()); + + int ret = Playthrough::Playthrough_Init(std::hash{}(Settings::seed), cvarSettings); + if (ret < 0) { + if (ret == -1) { // Failed to generate after 5 tries + printf("\n\nFailed to generate after 5 tries.\nPress B to go back to the menu.\nA different seed might be " + "successful."); + SPDLOG_INFO("\nRANDOMIZATION FAILED COMPLETELY. PLZ FIX\n"); + return ""; + } else { + printf("\n\nError %d with fill.\nPress Select to exit or B to go back to the menu.\n", ret); + return ""; + } + } + + // Restore settings that were set to a specific value for vanilla logic + if (Settings::Logic.Is(LOGIC_VANILLA)) { + for (Option* setting : Settings::vanillaLogicDefaults) { + setting->RestoreDelayedOption(); + } + Settings::Keysanity.RestoreDelayedOption(); + } + + return "./Randomizer/" + Settings::seed + ".json"; +} + +std::string GetInput(const char* hintText) { + return std::string(); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/3drando/menu.hpp b/soh/soh/Enhancements/randomizer/3drando/menu.hpp new file mode 100644 index 000000000..2f3933135 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/menu.hpp @@ -0,0 +1,52 @@ +#pragma once + +#include +#include +#include "randomizerTypes.h" + +#define MAIN_MENU 0 +#define OPTION_SUB_MENU 1 +#define SUB_MENU 2 +#define GENERATE_MODE 3 +#define LOAD_PRESET 4 +#define SAVE_PRESET 5 +#define DELETE_PRESET 6 +#define POST_GENERATE 7 +#define RESET_TO_DEFAULTS 8 + +#define MAX_SUBMENUS_ON_SCREEN 27 +#define MAX_SUBMENU_SETTINGS_ON_SCREEN 13 +#define TOP_WIDTH 50 +#define BOTTOM_WIDTH 40 +#define SCREEN_HEIGHT 30 + +#define RESET "\x1b[0m" +#define DIM "\x1b[2m" + +#define BLACK "\x1b[30m" +#define RED "\x1b[31m" +#define GREEN "\x1b[32m" +#define YELLOW "\x1b[33m" +#define BLUE "\x1b[34m" +#define MEGANTA "\x1b[35m" +#define CYAN "\x1b[36m" +#define WHITE "\x1b[37m" + +void ModeChangeInit(); +void UpdateOptionSubMenu(uint32_t kDown); +void UpdatePresetsMenu(uint32_t kdown); +void UpdateResetToDefaultsMenu(uint32_t kdown); +void UpdateGenerateMenu(uint32_t kDown); +void PrintMainMenu(); +void PrintOptionSubMenu(); +void PrintSubMenu(); +void PrintPresetsMenu(); +void PrintResetToDefaultsMenu(); +void PrintGenerateMenu(); +void ClearDescription(); +void PrintOptionDescription(); +std::string GenerateRandomizer(std::unordered_map cvarSettings); +std::string GetInput(const char* hintText); + +extern void MenuInit(); +extern void MenuUpdate(uint32_t kDown, bool updatedByHeld); diff --git a/soh/soh/Enhancements/randomizer/3drando/music.cpp b/soh/soh/Enhancements/randomizer/3drando/music.cpp new file mode 100644 index 000000000..6171d2a0e --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/music.cpp @@ -0,0 +1,128 @@ +#include "music.hpp" +#include + +namespace Music { + const std::array seqTypesMusic = { + /* NA_BGM_FIELD */ SEQ_BGM_WORLD, + /* NA_BGM_DUNGEON */ SEQ_BGM_WORLD, + /* NA_BGM_KAKARIKO_ADULT */ SEQ_BGM_WORLD, + /* NA_BGM_ENEMY */ SEQ_NOSHUFFLE, // Temporarily unshuffled: Override plays incorrect in some areas, like Lake Hylia, by continuously repeating the start + /* NA_BGM_BOSS00 */ SEQ_BGM_BATTLE, + /* NA_BGM_FAIRY_DUNGEON */ SEQ_BGM_WORLD, + /* NA_BGM_MARKET */ SEQ_BGM_WORLD, + /* NA_BGM_TITLE */ SEQ_BGM_WORLD, + /* NA_BGM_LINK_HOUSE */ SEQ_BGM_WORLD, + /* NA_BGM_GAME_OVER */ SEQ_FANFARE, + /* NA_BGM_BOSS_CLEAR */ SEQ_FANFARE, + /* NA_BGM_ITEM_GET */ SEQ_FANFARE, + /* NA_BGM_OPENING_GANON */ SEQ_FANFARE, + /* NA_BGM_HEART_GET */ SEQ_FANFARE, + /* NA_BGM_OCA_LIGHT */ SEQ_OCARINA, + /* NA_BGM_BUYO_DUNGEON */ SEQ_BGM_WORLD, + /* NA_BGM_KAKARIKO_KID */ SEQ_BGM_WORLD, + /* NA_BGM_GODESS */ SEQ_BGM_EVENT, + /* NA_BGM_HIME */ SEQ_BGM_EVENT, + /* NA_BGM_FIRE_DUNGEON */ SEQ_BGM_WORLD, + /* NA_BGM_OPEN_TRE_BOX */ SEQ_FANFARE, + /* NA_BGM_FORST_DUNGEON */ SEQ_BGM_WORLD, + /* NA_BGM_HIRAL_GARDEN */ SEQ_BGM_WORLD, + /* NA_BGM_GANON_TOWER */ SEQ_BGM_WORLD, + /* NA_BGM_RONRON */ SEQ_BGM_WORLD, + /* NA_BGM_GORON */ SEQ_BGM_WORLD, + /* NA_BGM_SPIRIT_STONE */ SEQ_FANFARE, + /* NA_BGM_OCA_FLAME */ SEQ_OCARINA, + /* NA_BGM_OCA_WIND */ SEQ_OCARINA, + /* NA_BGM_OCA_WATER */ SEQ_OCARINA, + /* NA_BGM_OCA_SOUL */ SEQ_OCARINA, + /* NA_BGM_OCA_DARKNESS */ SEQ_OCARINA, + /* NA_BGM_MIDDLE_BOSS */ SEQ_BGM_ERROR, + /* NA_BGM_S_ITEM_GET */ SEQ_FANFARE, + /* NA_BGM_SHRINE_OF_TIME */ SEQ_BGM_WORLD, + /* NA_BGM_EVENT_CLEAR */ SEQ_FANFARE, + /* NA_BGM_KOKIRI */ SEQ_BGM_WORLD, + /* NA_BGM_OCA_YOUSEI */ SEQ_FANFARE, + /* NA_BGM_MAYOIMORI */ SEQ_BGM_WORLD, + /* NA_BGM_SOUL_DUNGEON */ SEQ_BGM_WORLD, + /* NA_BGM_HORSE */ SEQ_BGM_EVENT, + /* NA_BGM_HORSE_GOAL */ SEQ_FANFARE, + /* NA_BGM_INGO */ SEQ_BGM_WORLD, + /* NA_BGM_MEDAL_GET */ SEQ_FANFARE, + /* NA_BGM_OCA_SARIA */ SEQ_OCARINA, + /* NA_BGM_OCA_EPONA */ SEQ_OCARINA, + /* NA_BGM_OCA_ZELDA */ SEQ_OCARINA, + /* NA_BGM_OCA_SUNMOON */ SEQ_NOSHUFFLE, /* Remove Sun's Song from the Ocarina pool for now due to bugs */ + /* NA_BGM_OCA_TIME */ SEQ_OCARINA, + /* NA_BGM_OCA_STORM */ SEQ_OCARINA, + /* NA_BGM_NAVI */ SEQ_BGM_EVENT, + /* NA_BGM_DEKUNOKI */ SEQ_BGM_EVENT, + /* NA_BGM_FUSHA */ SEQ_BGM_WORLD, + /* NA_BGM_HIRAL_DEMO */ SEQ_NOSHUFFLE, + /* NA_BGM_MINI_GAME */ SEQ_BGM_EVENT, + /* NA_BGM_SEAK */ SEQ_BGM_EVENT, + /* NA_BGM_ZORA */ SEQ_BGM_WORLD, + /* NA_BGM_APPEAR */ SEQ_FANFARE, + /* NA_BGM_ADULT_LINK */ SEQ_BGM_EVENT, + /* NA_BGM_MASTER_SWORD */ SEQ_FANFARE, + /* NA_BGM_INTRO_GANON */ SEQ_BGM_EVENT, + /* NA_BGM_SHOP */ SEQ_BGM_WORLD, + /* NA_BGM_KENJA */ SEQ_BGM_EVENT, + /* NA_BGM_FILE_SELECT */ SEQ_NOSHUFFLE, + /* NA_BGM_ICE_DUNGEON */ SEQ_BGM_WORLD, + /* NA_BGM_GATE_OPEN */ SEQ_NOSHUFFLE, + /* NA_BGM_OWL */ SEQ_BGM_EVENT, + /* NA_BGM_DARKNESS_DUNGEON */ SEQ_BGM_WORLD, + /* NA_BGM_AQUA_DUNGEON */ SEQ_BGM_WORLD, + /* NA_BGM_BRIDGE */ SEQ_NOSHUFFLE, + /* NA_BGM_SARIA */ SEQ_NOSHUFFLE, + /* NA_BGM_GERUDO */ SEQ_BGM_WORLD, + /* NA_BGM_DRUGSTORE */ SEQ_BGM_WORLD, + /* NA_BGM_KOTAKE_KOUME */ SEQ_BGM_EVENT, + /* NA_BGM_ESCAPE */ SEQ_BGM_EVENT, + /* NA_BGM_UNDERGROUND */ SEQ_BGM_WORLD, + /* NA_BGM_GANON_BATTLE_1 */ SEQ_BGM_BATTLE, + /* NA_BGM_GANON_BATTLE_2 */ SEQ_BGM_BATTLE, + /* NA_BGM_END_DEMO */ SEQ_NOSHUFFLE, + /* NA_BGM_STAFF_1 */ SEQ_NOSHUFFLE, + /* NA_BGM_STAFF_2 */ SEQ_NOSHUFFLE, + /* NA_BGM_STAFF_3 */ SEQ_NOSHUFFLE, + /* NA_BGM_STAFF_4 */ SEQ_NOSHUFFLE, + /* NA_BGM_BOSS01 */ SEQ_BGM_BATTLE, + /* NA_BGM_MINI_GAME_2 */ SEQ_BGM_ERROR, + }; + + std::array seqOverridesMusic; + + /* Initializes the list of music overrides to unshuffled */ + void InitMusicRandomizer() { + for(int i = 0; i < SEQ_COUNT; i++) + seqOverridesMusic[i] = BGM_BASE + i; + } + + /* Shuffles the sequences grouping them by type */ + /* type is a bitmask of SeqType */ + void ShuffleSequences(int type) { + std::vector seqs; + + // Get all sequences of the desired type(s) into a vector + for (int i = 0; i < SEQ_COUNT; i++) { + if (seqTypesMusic[i] & type) { + seqs.push_back(seqOverridesMusic[i]); + } + } + + // Shuffle the vector... + for (std::size_t i = 0; i < seqs.size(); i++) + { + std::swap(seqs[i], seqs[rand() % seqs.size()]); + } + + // ...and feed it back into the overrides array + for (int i = 0; i < SEQ_COUNT; i++) { + if (seqTypesMusic[i] & type) + { + seqOverridesMusic[i] = seqs.back(); + seqs.pop_back(); + } + } + } +} // namespace Music diff --git a/soh/soh/Enhancements/randomizer/3drando/music.hpp b/soh/soh/Enhancements/randomizer/3drando/music.hpp new file mode 100644 index 000000000..90f7fc9dd --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/music.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include + +namespace Music { + const uint32_t BGM_BASE = 0x1000585; + const int SEQ_COUNT = 85; + + enum SeqType { + SEQ_NOSHUFFLE = 0, + SEQ_BGM_WORLD = 1 << 0, + SEQ_BGM_EVENT = 1 << 1, + SEQ_BGM_BATTLE = 1 << 2, + SEQ_OCARINA = 1 << 3, + SEQ_FANFARE = 1 << 4, + // A soundtrack in this category has the issue where if another soundtrack that isn't + // in this category overrides it, it will keep playing when it should be stopped. + // For example when beating a mini-boss or finishing the zora diving game. + SEQ_BGM_ERROR = 1 << 5, + }; + + extern const std::array seqTypesMusic; + extern std::array seqOverridesMusic; + + void InitMusicRandomizer(); + void ShuffleSequences(int type); +} // namespace Music diff --git a/soh/soh/Enhancements/randomizer/3drando/patch.cpp b/soh/soh/Enhancements/randomizer/3drando/patch.cpp new file mode 100644 index 000000000..59ba85e1f --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/patch.cpp @@ -0,0 +1,25 @@ +#include "patch.hpp" + +#include "cosmetics.hpp" +#include "custom_messages.hpp" +#include "music.hpp" +#include "sound_effects.hpp" +#include "shops.hpp" +#include "spoiler_log.hpp" +#include "entrance.hpp" +#include "hints.hpp" + +#include +#include +#include +#include +#include +#include + +// For specification on the IPS file format, visit: https://zerosoft.zophar.net/ips.php + +using FILEPtr = std::unique_ptr; + +void WriteFloatToBuffer(std::vector& buffer, float f, size_t offset) { + memcpy(buffer.data() + offset, &f, sizeof(float)); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/3drando/patch.hpp b/soh/soh/Enhancements/randomizer/3drando/patch.hpp new file mode 100644 index 000000000..3dd95d8d4 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/patch.hpp @@ -0,0 +1,12 @@ +#pragma once +#include +#include "playthrough.hpp" +#include "settings.hpp" + +#define V_TO_P(addr) (addr - 0x100000) +#define P_TO_V(offset) (offset + 0x100000) +#define PATCH_CONSOLE 0 +#define PATCH_CITRA 1 +#define PATCH_SIZE_MAX 65535 + +bool WriteAllPatches(); diff --git a/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp b/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp new file mode 100644 index 000000000..772cd4a5f --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp @@ -0,0 +1,97 @@ +#include "playthrough.hpp" + +#include "custom_messages.hpp" +#include "fill.hpp" +#include "location_access.hpp" +#include "logic.hpp" +#include "random.hpp" +#include "spoiler_log.hpp" +#include "randomizerTypes.h" + +namespace Playthrough { + +int Playthrough_Init(uint32_t seed, std::unordered_map cvarSettings) { + // initialize the RNG with just the seed incase any settings need to be + // resolved to something random + Random_Init(seed); + + overrides.clear(); + CustomMessages::ClearMessages(); + ItemReset(); + HintReset(); + Areas::AccessReset(); + + Settings::UpdateSettings(cvarSettings); + // once the settings have been finalized turn them into a string for hashing + std::string settingsStr; + for (Menu* menu : Settings::GetAllOptionMenus()) { + // don't go through non-menus + if (menu->mode != OPTION_SUB_MENU) { + continue; + } + + for (size_t i = 0; i < menu->settingsList->size(); i++) { + Option* setting = menu->settingsList->at(i); + if (setting->IsCategory(OptionCategory::Setting)) { + settingsStr += setting->GetSelectedOptionText(); + } + } + } + unsigned int finalHash = std::hash{}(Settings::seed + settingsStr); + Random_Init(finalHash); + + Logic::UpdateHelpers(); + + if (Settings::Logic.Is(LOGIC_VANILLA)) { + VanillaFill(); // Just place items in their vanilla locations + } else { // Fill locations with logic + int ret = Fill(); + if (ret < 0) { + return ret; + } + } + + GenerateHash(); + WriteIngameSpoilerLog(); + + if (Settings::GenerateSpoilerLog) { + // write logs + printf("\x1b[11;10HWriting Spoiler Log..."); + if (SpoilerLog_Write(cvarSettings[RSK_LANGUAGE])) { + printf("Done"); + } else { + printf("Failed"); + } +#ifdef ENABLE_DEBUG + printf("\x1b[11;10HWriting Placement Log..."); + if (PlacementLog_Write()) { + printf("Done\n"); + } else { + printf("Failed\n"); + } +#endif + } + + playthroughLocations.clear(); + wothLocations.clear(); + playthroughBeatable = false; + + return 1; +} + +// used for generating a lot of seeds at once +int Playthrough_Repeat(int count /*= 1*/) { + printf("\x1b[0;0HGENERATING %d SEEDS", count); + uint32_t repeatedSeed = 0; + for (int i = 0; i < count; i++) { + repeatedSeed = rand() % 0xFFFFFFFF; + Settings::seed = std::to_string(repeatedSeed); + CitraPrint("testing seed: " + Settings::seed); + ClearProgress(); + // Playthrough_Init(std::hash{}(Settings::seed)); + printf("\x1b[15;15HSeeds Generated: %d\n", i + 1); + } + + return 1; +} +} // namespace Playthrough \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/3drando/playthrough.hpp b/soh/soh/Enhancements/randomizer/3drando/playthrough.hpp new file mode 100644 index 000000000..5fd0e19ff --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/playthrough.hpp @@ -0,0 +1,9 @@ +#pragma once +#include +#include +#include "item_location.hpp" + +namespace Playthrough { +int Playthrough_Init(uint32_t seed, std::unordered_map cvarSettings); + int Playthrough_Repeat(int count = 1); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/pool_functions.hpp b/soh/soh/Enhancements/randomizer/3drando/pool_functions.hpp new file mode 100644 index 000000000..1cb96c746 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/pool_functions.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include +#include +#include +#include + +template +static void erase_if(std::vector& vector, Predicate pred) { + vector.erase(std::remove_if(begin(vector), end(vector), pred), end(vector)); +} + +template +std::vector FilterFromPool(std::vector& vector, Predicate pred, bool eraseAfterFilter = false) { + std::vector filteredPool = {}; + std::copy_if(vector.begin(), vector.end(), std::back_inserter(filteredPool), pred); + + if (eraseAfterFilter) { + erase_if(vector, pred); + } + + return filteredPool; +} + +template +std::vector FilterAndEraseFromPool(std::vector& vector, Predicate pred) { + return FilterFromPool(vector, pred, true); +} + +template +void AddElementsToPool(std::vector& toPool, const FromPool& fromPool) { + toPool.insert(toPool.end(), std::cbegin(fromPool), std::cend(fromPool)); +} + +template +bool ElementInContainer(T& element, const Container& container) { + return std::find(container.begin(), container.end(), element) != container.end(); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/preset.cpp b/soh/soh/Enhancements/randomizer/3drando/preset.cpp new file mode 100644 index 000000000..ab036ab14 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/preset.cpp @@ -0,0 +1,202 @@ +#include "preset.hpp" + +#include +#include +#include +#include +#include +#include + +#include "category.hpp" +#include "settings.hpp" +#include "tinyxml2.h" +#include "utils.hpp" + +namespace fs = std::filesystem; + +static const std::string CACHED_SETTINGS_FILENAME = "CACHED_SETTINGS"; +static const std::string CACHED_COSMETICS_FILENAME = "CACHED_COSMETICS"; + +static std::string_view GetBasePath(OptionCategory category) { + static constexpr std::array paths{ + "/3ds/presets/oot3dr/settings/", + "/3ds/presets/oot3dr/cosmetics/", + }; + + switch(category) { + case OptionCategory::Setting : + case OptionCategory::Cosmetic : + return paths[static_cast(category)]; + case OptionCategory::Toggle : + break; + } + return ""; +} + +//Creates preset directories if they don't exist +bool CreatePresetDirectories() { + //Create the 3ds directory if it doesn't exist + std::filesystem::create_directory("./3ds"); + //Create the presets directory if it doesn't exist + std::filesystem::create_directory("./3ds/presets"); + //Create the oot3d directory if it doesn't exist + std::filesystem::create_directory("./3ds/presets/oot3dr"); + //Create the cosmetics directory if it doesn't exist + std::filesystem::create_directory("./3ds/presets/oot3dr/cosmetics"); + //Create the settings directory if it doesn't exist + std::filesystem::create_directory("./3ds/presets/oot3dr/settings"); + + return true; +} + +//Gets the preset filenames +std::vector GetSettingsPresets() { + std::vector presetEntries = {}; + for (const auto& entry : fs::directory_iterator(GetBasePath(OptionCategory::Setting))) { + if(entry.path().stem().string() != CACHED_SETTINGS_FILENAME) { + presetEntries.push_back(entry.path().stem().string()); + } + } + return presetEntries; +} + +static std::string PresetPath(std::string_view presetName, OptionCategory category) { + return std::string(GetBasePath(category)).append(presetName).append(".xml"); +} + +// Presets are now saved as XML files using the tinyxml2 library. +// Documentation: https://leethomason.github.io/tinyxml2/index.html +bool SavePreset(std::string_view presetName, OptionCategory category) { + using namespace tinyxml2; + + XMLDocument preset = XMLDocument(false); + + // Create and insert the XML declaration + preset.InsertEndChild(preset.NewDeclaration()); + + // Create the root node + XMLElement* rootNode = preset.NewElement("settings"); + preset.InsertEndChild(rootNode); + + for (Menu* menu : Settings::GetAllOptionMenus()) { + if (menu->mode != OPTION_SUB_MENU) { + continue; + } + for (const Option* setting : *menu->settingsList) { + if (!setting->IsCategory(category)) { + continue; + } + + XMLElement* newSetting = rootNode->InsertNewChildElement("setting"); + newSetting->SetAttribute("name", RemoveLineBreaks(setting->GetName()).c_str()); + newSetting->SetText(setting->GetSelectedOptionText().c_str()); + } + } + + XMLError e = preset.SaveFile(PresetPath(presetName, category).c_str()); + return e == XML_SUCCESS; +} + +//Read the preset XML file +bool LoadPreset(std::string_view presetName, OptionCategory category) { + using namespace tinyxml2; + + XMLDocument preset; + XMLError e = preset.LoadFile(PresetPath(presetName, category).c_str()); + if (e != XML_SUCCESS) { + return false; + } + + XMLElement* rootNode = preset.RootElement(); + if (strcmp(rootNode->Name(), "settings") != 0) { + // We do not have our root node, so it may be the old structure. We don't support that one anymore. + return false; + } + + XMLElement* curNode = rootNode->FirstChildElement(); + + for (Menu* menu : Settings::GetAllOptionMenus()) { + if (menu->mode != OPTION_SUB_MENU) { + continue; + } + + for (Option* setting : *menu->settingsList) { + if (!setting->IsCategory(category)) { + continue; + } + + // Since presets are saved linearly, we can simply loop through the nodes as + // we loop through the settings to find most of the matching elements. + const std::string& settingToFind = RemoveLineBreaks(setting->GetName()); + if (settingToFind == RemoveLineBreaks(curNode->Attribute("name"))) { + setting->SetSelectedIndexByString(curNode->GetText()); + curNode = curNode->NextSiblingElement(); + } else { + // If the current setting and element don't match, then search + // linearly from the beginning. This will get us back on track if the + // next setting and element line up with each other. + curNode = rootNode->FirstChildElement(); + while (curNode != nullptr) { + if (settingToFind == RemoveLineBreaks(curNode->Attribute("name"))) { + setting->SetSelectedIndexByString(curNode->GetText()); + curNode = curNode->NextSiblingElement(); + break; + } + curNode = curNode->NextSiblingElement(); + } + } + + // Reset to the beginning if we reached the end. + if (curNode == nullptr) { + curNode = rootNode->FirstChildElement(); + } + } + } + return true; +} + +//Delete the selected preset +bool DeletePreset(std::string_view presetName, OptionCategory category) { + const std::string filepath = PresetPath(presetName, category); + + std::filesystem::remove(filepath); + + return true; +} + +//Saves the new preset to a file +bool SaveSpecifiedPreset(std::string_view presetName, OptionCategory category) { + //don't save if the user cancelled + if (presetName.empty()) { + return false; + } + return SavePreset(presetName, category); +} + +void SaveCachedSettings() { + SavePreset(CACHED_SETTINGS_FILENAME, OptionCategory::Setting); +} + +void LoadCachedSettings() { + //If cache file exists, load it + for (const auto& entry : fs::directory_iterator(GetBasePath(OptionCategory::Setting))) { + if(entry.path().stem().string() == CACHED_SETTINGS_FILENAME) { + //File exists, open + LoadPreset(CACHED_SETTINGS_FILENAME, OptionCategory::Setting); + } + } +} + +bool SaveCachedCosmetics() { + return SavePreset(CACHED_COSMETICS_FILENAME, OptionCategory::Cosmetic); +} + +void LoadCachedCosmetics() { + //If cache file exists, load it + for (const auto& entry : fs::directory_iterator(GetBasePath(OptionCategory::Cosmetic))) { + if(entry.path().stem().string() == CACHED_COSMETICS_FILENAME) { + //File exists, open + LoadPreset(CACHED_COSMETICS_FILENAME, OptionCategory::Cosmetic); + } + } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/preset.hpp b/soh/soh/Enhancements/randomizer/3drando/preset.hpp new file mode 100644 index 000000000..64536757c --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/preset.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +enum class OptionCategory; + +bool CreatePresetDirectories(); +std::vector GetSettingsPresets(); +bool SavePreset(std::string_view presetName, OptionCategory category); +bool LoadPreset(std::string_view presetName, OptionCategory category); +bool DeletePreset(std::string_view presetName, OptionCategory category); +bool SaveSpecifiedPreset(std::string_view presetName, OptionCategory category); +void SaveCachedSettings(); +void LoadCachedSettings(); +bool SaveCachedCosmetics(); +void LoadCachedCosmetics(); diff --git a/soh/soh/Enhancements/randomizer/3drando/rando_main.cpp b/soh/soh/Enhancements/randomizer/3drando/rando_main.cpp new file mode 100644 index 000000000..a936b6567 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/rando_main.cpp @@ -0,0 +1,27 @@ +#include "menu.hpp" +#include "hint_list.hpp" +#include "item_list.hpp" +#include "item_location.hpp" +#include "location_access.hpp" +#include "rando_main.hpp" +// #include +#include +#include + +#define TICKS_PER_SEC 268123480.0 + +void RandoMain::GenerateRando(std::unordered_map cvarSettings) { + HintTable_Init(); + ItemTable_Init(); + LocationTable_Init(); + + // std::string settingsFileName = "./randomizer/latest_settings.json"; + // CVar_SetString("gLoadedPreset", settingsFileName.c_str()); + + std::string fileName = GenerateRandomizer(cvarSettings); + CVar_SetString("gSpoilerLog", fileName.c_str()); + + Game::SaveSettings(); + Game::LoadSettings(); + CVar_SetS32("gNewSeedGenerated", 1); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/3drando/rando_main.hpp b/soh/soh/Enhancements/randomizer/3drando/rando_main.hpp new file mode 100644 index 000000000..523620d1e --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/rando_main.hpp @@ -0,0 +1,5 @@ +#pragma once + +namespace RandoMain { +void GenerateRando(std::unordered_map cvarSettings); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/random.cpp b/soh/soh/Enhancements/randomizer/3drando/random.cpp new file mode 100644 index 000000000..4cd5c85f1 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/random.cpp @@ -0,0 +1,29 @@ +#include "random.hpp" + +#include + +static bool init = false; +static std::mt19937_64 generator; + +//Initialize with seed specified +void Random_Init(uint32_t seed) { + init = true; + generator = std::mt19937_64{seed}; +} + +//Returns a random integer in range [min, max-1] +uint32_t Random(int min, int max) { + if (!init) { + //No seed given, get a random number from device to seed + const auto seed = static_cast(std::random_device{}()); + Random_Init(seed); + } + std::uniform_int_distribution distribution(min, max-1); + return distribution(generator); +} + +//Returns a random floating point number in [0.0, 1.0] +double RandomDouble() { + std::uniform_real_distribution distribution(0.0, 1.0); + return distribution(generator); +} diff --git a/soh/soh/Enhancements/randomizer/3drando/random.hpp b/soh/soh/Enhancements/randomizer/3drando/random.hpp new file mode 100644 index 000000000..c8ccf0f50 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/random.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include +#include +#include +#include +#include + +void Random_Init(uint32_t seed); +uint32_t Random(int min, int max); +double RandomDouble(); + +//Get a random element from a vector or array +template +T RandomElement(std::vector& vector, bool erase) { + const auto idx = Random(0, vector.size()); + const T selected = vector[idx]; + if (erase) { + vector.erase(vector.begin() + idx); + } + return selected; +} +template +auto& RandomElement(Container& container) { + return container[Random(0, std::size(container))]; +} +template +const auto& RandomElement(const Container& container) { + return container[Random(0, std::size(container))]; +} + +//Shuffle items within a vector or array +template +void Shuffle(std::vector& vector) { + for (std::size_t i = 0; i + 1 < vector.size(); i++) + { + std::swap(vector[i], vector[Random(i, vector.size())]); + } +} +template +void Shuffle(std::array& arr) { + for (std::size_t i = 0; i + 1 < arr.size(); i++) + { + std::swap(arr[i], arr[Random(i, arr.size())]); + } +} diff --git a/soh/soh/Enhancements/randomizer/3drando/randomizer.hpp b/soh/soh/Enhancements/randomizer/3drando/randomizer.hpp new file mode 100644 index 000000000..1b02c9037 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/randomizer.hpp @@ -0,0 +1,4 @@ +#pragma once + +#define RANDOMIZER_VERSION "v3.1" +#define COMMIT_NUMBER "develop" diff --git a/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.cpp b/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.cpp new file mode 100644 index 000000000..edca583e5 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.cpp @@ -0,0 +1,1696 @@ +#include "setting_descriptions.hpp" + +//Setting descriptions are mostly copied from OoT Randomizer tooltips with minor edits + +/*------------------------------ +| RANDOMIZE SETTINGS | *SCREEN WIDTH* +------------------------------*/ /*--------------------------------------------------*/ +string_view openRandomize = "Randomize all Open Settings."; // +string_view worldRandomize = "Randomize all World Settings except for MQ\n" // + "dungeons."; // +string_view shuffleRandomize = "Randomize all Shuffle Settings."; // +string_view dungeonRandomize = "Randomize all Dungeon Shuffle Settings."; // + // +/*------------------------------ // +| LOGIC | // +------------------------------*/ // +string_view logicGlitchless = "No glitches are required, but may require some\n" // + "minor tricks. Add minor tricks to consider for\n" // + "logic in Logical Tricks."; // +string_view logicGlitched = "The glitches you enable at the set difficulty\n" // + "or below may be required.\n" // + "\n" // + "In development, but still usable."; // +string_view logicNoLogic = "Maximize randomization, All locations are\n" // + "considered available. MAY BE IMPOSSIBLE TO BEAT.";// +string_view logicVanilla = "For those who want to play the game normally but\n" + "with the improvements of the randomizer. All\n" // + "locations will contain their vanilla items. This\n" + "supercedes all item shuffle, logic, hint, and\n" // + "item pool settings. You can still use non-vanilla\n" + "world settings such as adult start or entrance\n" // + "shuffle, but the game may require glitches to\n" // + "complete if you do."; // +/*------------------------------ // +| FOREST | // +------------------------------*/ // +string_view forestOpen = "Mido no longer blocks the path to the Deku Tree,\n" + "and the Kokiri boy no longer blocks the path out\n" + "of the forest."; // +string_view forestClosed = "Beating Deku Tree is logically required to leave\n" + "the forest area (Kokiri Forest/Lost Woods/Sacred\n" + "Forest Meadow/Deku Tree), while the Kokiri Sword\n" + "and a Deku Shield are required to access the Deku\n" + "Tree. Items needed for this will be guaranteed\n" // + "inside the forest area. This setting is\n" // + "incompatible with starting as adult."; // +string_view forestClosedDeku = "The Kokiri boy no longer blocks the path out of\n"// + "the forest, but Mido still blocks the path to the\n" + "Deku Tree, requiring Kokiri Sword and Deku Shield\n" + "to access the Deku Tree."; // +/*------------------------------ // +| KAKARIKO GATE | // +------------------------------*/ // +string_view kakGateOpen = "The gate is always open instead of needing\n" // + "Zelda's Letter. The Happy Mask Shop opens upon\n" // + "obtaining Zelda's Letter without needing to show\n" + "it to the guard."; // +string_view kakGateClosed = "The gate and the Happy Mask Shop both remain\n" // + "closed until showing Zelda's Letter to the guard\n" + "in Kakariko."; // +/*------------------------------ // +| DOOR OF TIME | // +------------------------------*/ // +string_view doorOfTimeOpen = "The Door of Time starts opened instead of needing\n" + "to play the Song of Time."; // +string_view doorOfTimeClosed = "Only an Ocarina and the Song of Time need to be\n"// + "found to open the Door of Time."; // +string_view doorOfTimeIntended = "The Ocarina of Time, the Song of Time, and\n" // + "all Spiritual Stones need to be found to\n" // + "open the Door of Time."; // +/*------------------------------ // +| ZORA'S FOUNTAIN | // +------------------------------*/ // +string_view fountainNormal = "King Zora obstructs the way to Zora's Fountain.\n"// + "Ruto's Letter must be shown as child in order to\n" + "move him for both eras."; // +string_view fountainAdult = "King Zora is always moved in the adult era. This\n" + "means Ruto's Letter is only required to access\n" // + "Zora's Fountain as child."; // +string_view fountainOpen = "King Zora starts as moved in both the child and\n"// + "adult eras. This also removes Ruto's Letter from\n" + "the pool since it can't be used."; // +/*------------------------------ // +| GERUDO FORTRESS | // +------------------------------*/ // +string_view gerudoNormal = "All 4 carpenters can be rescued."; // +string_view gerudoFast = "Only the bottom left carpenter must be rescued."; // +string_view gerudoOpen = "The carpenters are rescued from the start of the\n" + "game, and if Shuffle Gerudo Card is disabled,\n" // + "the player starts with the Gerudo Card in the\n" // + "inventory allowing access to Gerudo Training\n" // + "Grounds."; // +/*------------------------------ // +| RAINBOW BRIDGE | // +------------------------------*/ // +string_view bridgeOpen = "The Rainbow Bridge is always present."; // +string_view bridgeVanilla = "The Rainbow Bridge requires Shadow and Spirit\n" // + "Medallions as well as Light Arrows."; // +string_view bridgeStones = "The Rainbow Bridge requires collecting a\n" // + "configurable number of Spiritual Stones."; // +string_view bridgeMedallions = "The Rainbow Bridge requires collecting a\n" // + "configurable number of Medallions."; // +string_view bridgeRewards = "The Rainbow Bridge requires collecting a\n" // + "configurable number of Dungeon Rewards."; // +string_view bridgeDungeons = "The Rainbow Bridge requires completing a\n" // + "configurable number of Dungeons.\n" // + "\n" // + "Dungeons are considered complete when Link steps\n" + "into the blue warp at the end of them."; // +string_view bridgeTokens = "The Rainbow Bridge requires collecting a\n" // + "configurable number of Gold Skulltula Tokens."; // +/*------------------------------ // +| BRIDGE CONDITIONS | // +------------------------------*/ // +string_view bridgeStoneCountDesc = "Set the number of Spiritual Stones required to\n" // + "spawn the Rainbow Bridge."; // +string_view bridgeMedallionCountDesc = "Set the number of Medallions required to spawn the" + "Rainbow Bridge."; // +string_view bridgeRewardCountDesc = "Set the number of Dungeon Rewards (Spiritual\n" // + "Stones and Medallions) required to spawn the\n" // + "Rainbow Bridge."; // +string_view bridgeDungeonCountDesc = "Set the number of completed dungeons required to\n" + "spawn the Rainbow Bridge."; // +string_view bridgeTokenCountDesc = "Set the number of Gold Skulltula Tokens required\n" + "to spawn the Rainbow Bridge."; // +/*------------------------------ // +| RANDOM GANONS TRIALS | // +------------------------------*/ // +string_view randomGanonsTrialsDesc = "Sets a random number of required trials to enter\n" + "Ganon's Tower."; // +/*------------------------------ // +| GANON'S TRIAL COUNT | // +------------------------------*/ // +string_view ganonsTrialCountDesc = "Set the number of trials required to enter\n" // + "Ganon's Tower. Trials will be randomly selected.";// +/*------------------------------ // +| STARTING AGE | // +------------------------------*/ // +string_view ageDesc = "Choose which age Link will start as.\n" // + "\n" // + "Starting as adult means you start with the Master\n" + "Sword in your inventory.\n" // + "\n" // + "Only the child option is compatible with Closed\n"// + "Forest."; // +/*------------------------------ // +| SHUFFLE ENTRANCES | // +------------------------------*/ // +string_view shuffleEntrancesDesc = "Shuffle where the entrances between areas lead to." + "If turned on, select which kinds of entrances you\n" + "want shuffled in the options below. Note that some" + "types of entrances can have wildly varying\n" // + "generation times."; // + // +/*------------------------------ // +| DUNGEON ENTRANCES | // +------------------------------*/ // +string_view dungeonEntrancesDesc = "Shuffle the pool of dungeon entrances, including\n" + "Bottom of the Well, Ice Cavern, and Gerudo\n" // + "Training Grounds. Shuffling Ganon's Castle can\n" // + "be enabled separately.\n" // + "\n" // + "Additionally, the entrances of Deku Tree, Fire\n" // + "Temple, Bottom of the Well and Gerudo Training\n" // + "Ground are opened for both adult and child."; // +/*------------------------------ // +| OVERWORLD ENTRANCES | // +------------------------------*/ // +string_view overworldEntrancesDesc = "Shuffle the pool of Overworld entrances, which\n" // + "corresponds to almost all loading zones between\n"// + "Overworld areas.\n" // + "\n" // + "Some entrances are unshuffled to avoid issues:\n" // + "- Hyrule Castle Courtyard and Garden entrance\n" // + "- Both Market Back Alley entrances\n" // + "- Gerudo Valley to Lake Hylia (unless entrances\n"// + " are decoupled)"; // +/*------------------------------ // +| INTERIOR ENTRANCES | // +------------------------------*/ // +string_view interiorEntrancesOff = "Interior entrances will not be shuffled."; // +string_view interiorEntrancesSimple = "Shuffle the pool of interior entrances which\n" // + "contains most Houses and all Great Fairies."; // +string_view interiorEntrancesAll = "An extended version of 'Simple' with some extra\n"// + "places:\n" // + "- Windmill\n" // + "- Link's House\n" // + "- Temple of Time\n" // + "- Kakariko Potion Shop."; // +/*------------------------------ // +| GROTTO ENTRANCES | // +------------------------------*/ // +string_view grottoEntrancesDesc = "Shuffle the pool of grotto entrances, including\n"// + "all graves, small Fairy Fountains and the Lost\n" // + "Woods Stage."; // +/*------------------------------ // +| BOMBCHUS IN LOGIC | // +------------------------------*/ // +string_view bombchuLogicDesc = "Bombchus are properly considered in logic.\n" // + "They can be replenished in shops, or through\n" // + "bombchu drops, if those are enabled.\n" // + "\n" // + "Bombchu Bowling is opened by bombchus."; // +/*------------------------------ // +| AMMO DROPS | // +------------------------------*/ // +string_view defaultAmmoDropsDesc = "Bombs, arrows, seeds, nuts, sticks and\n" // + "magic jars appear as normal.\n"; // +string_view bombchuDropsDesc = "Bombs, arrows, seeds, nuts, sticks and\n" // + "magic jars appear as normal.\n" // + "Bombchus can sometimes replace bomb drops."; // +string_view noAmmoDropsDesc = "All ammo drops will be replaced by blue rupees,\n"// + "except for Deku Sticks.\n" // + "Ammo upgrades will only refill ammo by 10 units.";// +/*------------------------------ // +| HEART DROPS AND REFILLS | // +------------------------------*/ // +string_view defaultHeartDropsDesc = "Heart drops will appear as normal.\n" // + "Health upgrades fully heal Link when picked up.\n"// + "Fairies heal Link as normal."; // +string_view noHeartDropsDesc = "Heart drops will be replaced by green rupees.\n" // + "Health upgrades fully heal Link when picked up.\n"// + "Fairies heal Link as normal."; // +string_view noHeartRefillDesc = "Heart drops will appear as normal.\n" // + "Health upgrades don't heal Link when picked up.\n"// + "Fairies heal Link by only 3 hearts."; // +string_view scarceHeartsDesc = "Heart drops will be replaced by green rupees.\n" // + "Health upgrades don't heal Link when picked up.\n"// + "Fairies heal Link by only 3 hearts."; // +/*------------------------------ // +| MQ DUNGEON COUNT | // +------------------------------*/ // +string_view mqDungeonCountDesc = "Specify the number of Master Quest dungeons to\n" // + "appear in the game. Which dungeons become Master\n" + "Quest will be chosen at random."; // +/*------------------------------ // +| SET MQ DUNGEONS | // +------------------------------*/ // +string_view setDungeonTypesDesc = "If set, you can choose specific dungeons to be\n" // + "vanilla, MQ, or random"; // +/*------------------------------ // +| SHUFFLE DUNGEON REWARDS | // +------------------------------*/ // +string_view shuffleRewardsEndOfDungeon= "Medallions and Spiritual Stones will be given as\n" + "rewards for beating dungeons.\n" // + "\n" // + "This setting will force Link's Pocket to be a\n" // + "Medallion or Spiritual Stone."; // +string_view shuffleRewardsAnyDungeon = "Medallions and Spiritual Stones can only appear\n"// + "inside of dungeons."; // +string_view shuffleRewardsOverworld = "Medallions and Spiritual Stones can only appear\n"// + "outside of dungeons."; // +string_view shuffleRewardsAnywhere = "Medallions and Spiritual Stones can appear\n" // + "anywhere."; // +/*------------------------------ // +| LINK'S POCKET | // +------------------------------*/ // +string_view linksPocketDungeonReward = "Link will start with a Dungeon Reward in his\n" // + "inventory."; // +string_view linksPocketAdvancement = "Link will receive a random advancement item at the" + "beginning of the playthrough."; // +string_view linksPocketAnything = "Link will receive a random item from the item pool" + "at the beginning of the playthrough."; // +string_view linksPocketNothing = "Link will start with a very useful green rupee."; // +/*------------------------------ // +| SONG SHUFFLE | // +------------------------------*/ // +string_view songsSongLocations = "Songs will only appear at locations that normally\n" + "teach songs."; // +string_view songsDungeonRewards = "Songs appear at the end of dungeons. For major\n" // + "dungeons, they will be at the boss heart container" + "location. The remaining 4 songs are placed at:\n" // + "- Zelda's Lullaby Location\n" // + "- Ice Cavern's Serenade of Water Location\n" // + "- Bottom of the Well's Lens of Truth Location\n" // + "- Gerudo Training Ground's Ice Arrow Location"; // +string_view songsAllLocations = "Songs can appear in any location."; // + // +/*------------------------------ // +| SHOPSANITY | // +------------------------------*/ // +string_view shopsOff = "All shop items will be the same as vanilla."; // +string_view shopsZero = "Vanilla shop items will be shuffled among\n" // + "different shops."; // +string_view shopsOne = "Vanilla shop items will be shuffled among\n" // + "different shops, and each shop will contain\n" // + "one non-vanilla shop item."; // +string_view shopsTwo = "Vanilla shop items will be shuffled among\n" // + "different shops, and each shop will contain\n" // + "two non-vanilla shop items."; // +string_view shopsThree = "Vanilla shop items will be shuffled among\n" // + "different shops, and each shop will contain\n" // + "three non-vanilla shop items."; // +string_view shopsFour = "Vanilla shop items will be shuffled among\n" // + "different shops, and each shop will contain\n" // + "four non-vanilla shop items."; // +string_view shopsRandom = "Vanilla shop items will be shuffled among\n" // + "different shops, and each shop will contain\n" // + "1-4 non-vanilla shop items."; // +/*------------------------------ // +| TOKENSANITY | // +------------------------------*/ // +string_view tokensOff = "GS locations will not be shuffled."; // +string_view tokensDungeon = "This only shuffles the GS locations that are\n" // + "within dungeons, increasing the value of most\n" // + "dungeons and making internal dungeon exploration\n" + "more diverse."; // +string_view tokensOverworld = "This only shuffles the GS locations that are\n" // + "outside of dungeons."; // +string_view tokensAllTokens = "Effectively adds 100 new locations for items to\n"// + "appear."; // + // +/*------------------------------ // +| SCRUB SHUFFLE | // +------------------------------*/ // +string_view scrubsOff = "Only the 3 Scrubs that give one-time items in the\n" + "vanilla game (PoH, Deku Nut capacity, and Deku\n" // + "Stick capacity) will have random items."; // +string_view scrubsAffordable = "All Scrub prices will be reduced to 10 rupees each"; +string_view scrubsExpensive = "All Scrub prices will be their vanilla prices.\n" // + "This will require spending over 1000 rupees on\n" // + "Scrubs."; // +string_view scrubsRandomPrices = "All Scrub prices will be between 0-95 rupees. This" + "will on average be very, very expensive overall.";// +/*------------------------------ // +| SHUFFLE COWS | // +------------------------------*/ // +string_view shuffleCowsDesc = "Enabling this will let cows give you items upon\n"// + "performing Epona's song in front of them. There\n"// + "are 9 cows, and an extra in MQ Jabu."; // + // +/*------------------------------ // +| SHUFFLE KOKIRI SWORD | // +------------------------------*/ // +string_view kokiriSwordDesc = "Enabling this shuffles the Kokiri Sword into the\n" + "item pool.\n" // + "\n" // + "This will require extensive use of sticks until\n"// + "the sword is found."; // +/*------------------------------ // +| SHUFFLE OCARINAS | // +------------------------------*/ // +string_view ocarinasDesc = "Enabling this shuffles the Fairy Ocarina and the\n" + "Ocarina of Time into the item pool.\n" // + "\n" // + "This will require finding an Ocarina before being\n" + "able to play songs."; // +/*------------------------------ // +| SHUFFLE WEIRD EGG | // +------------------------------*/ // +string_view weirdEggDesc = "Enabling this shuffles the Weird Egg from Malon\n"// + "into the item pool.\n" // + "This will require finding the Weird Egg to talk to" + "Zelda in Hyrule Castle, which in turn locks\n" // + "rewards from Impa, Saria, Malon, and Talon, as\n" // + "well as the Happy Mask Sidequest. The Weird Egg is" + "also required for Zelda's Letter to unlock the\n" // + "Kakariko Gate as child which can lock some\n" // + "progression"; // +/*------------------------------ // +| SHUFFLE Gerudo Membership Card | // +------------------------------*/ // +string_view gerudoTokenDesc = "Enabling this shuffles the Gerudo Membership Card into the\n" + "item pool.\n" // + "\n" // + "The Gerudo Membership Card is required to enter the Gerudo\n" + "Training Ground."; // +/*------------------------------ // +| SHUFFLE MAGIC BEANS | // +------------------------------*/ // +string_view magicBeansDesc = "Enabling this adds a pack of 10 beans to the item\n" + "pool and changes the Magic Bean Salesman to sell a" + "random item at a price of 60 rupees."; // +/*------------------------------ // +| SHUFFLE MERCHANTS | // +------------------------------*/ // +string_view merchantsDesc = "Enabling this adds a Giant's Knife and a pack\n" // + "of Bombchus to the item pool and changes both\n" // + "Medigoron and the Haunted Wasteland Carpet\n" // + "Salesman to sell a random item once at the price\n" + "of 200 rupees."; // +string_view merchantsHintsDesc = "These hints will make Medigoron and the Carpet\n" // + "Salesman tell you which item they're selling.\n" // + "\n" // + "The Clearer Hints setting will affect how they\n" // + "refer to the item."; // +/*------------------------------ // +| SHUFFLE ADULT TRADE | // +------------------------------*/ // +string_view adultTradeDesc = "Enabling this adds all of the adult trade quest\n"// + "items to the pool, each of which can be traded\n" // + "for a unique reward. You will be able to choose\n"// + "which of your owned adult trade items is visible\n" + "in the inventory by selecting the item and using\n" + "the L and R buttons. If disabled, only the Claim\n" + "Check will be found in the pool."; // +/*------------------------------ // +| SHUFFLE CHEST MINIGAME | // +------------------------------*/ // +string_view chestMinigameDesc = "The 5 key chests in the Treasure Chest Shop will\n" + "be randomized, and the 6 keys will be added to the"// + "pool. The rupee chests will be replaced by traps.\n" + "Also, the shop owner is on vacation, so he can't\n" + "close any chests or doors once you leave.\n" // + "\n" // + "If you choose the \"pack\" option, you will get\n"// + "all the keys at once, in a single item."; // +/*------------------------------ // +| MAPS AND COMPASSES | // +------------------------------*/ // +string_view mapCompassStartWith = "Maps and Compasses are given to you from the\n" // + "start. This will add a small amount of money and\n" + "refill items to the pool."; // +string_view mapCompassVanilla = "Maps and Compasses will appear in their vanilla\n"// + "locations."; // +string_view mapCompassOwnDungeon = "Maps and Compasses can only appear in their\n" // + "respective dungeon."; // +string_view mapCompassAnyDungeon = "Maps and Compasses can only appear in a dungeon,\n" + "but not necessarily the dungeon they are for."; // +string_view mapCompassOverworld = "Maps and Compasses can only appear outside of\n" // + "dungeons."; // +string_view mapCompassAnywhere = "Maps and Compasses can appear anywhere in the\n" // + "world."; // +/*------------------------------ // +| SMALL KEYS | // +------------------------------*/ // +string_view smallKeyStartWith = "Small Keys are given to you from the start so you\n" + "won't have to worry about locked doors. An easier\n" + "mode."; // +string_view smallKeyVanilla = "Small Keys will appear in their vanilla locations." + "You start with 3 keys in Spirit Temple MQ because\n" + "the vanilla key layout is not beatable in logic.";// +string_view smallKeyOwnDungeon = "Small Keys can only appear in their respective\n" // + "dungeon. If Fire Temple is not a Master Quest\n" // + "dungeon, the door to the Boss Key chest will be\n"// + "unlocked."; // +string_view smallKeyAnyDungeon = "Small Keys can only appear inside of any dungeon,\n" + "but won't necessarily be in the dungeon that the\n" + "key is for. A difficult mode since it is more\n" // + "likely to need to enter a dungeon multiple times."; +string_view smallKeyOverworld = "Small Keys can only appear outside of dungeons.\n"// + "You may need to enter a dungeon multiple times to\n" + "gain items to access the overworld locations with\n" + "the keys required to finish a dungeon."; // +string_view smallKeyAnywhere = "Small Keys can appear anywhere in the world. A\n" // + "difficult mode since it is more likely to need to\n" + "enter a dungeon multiple times."; // +/*------------------------------ // +| GERUDO FORTRESS KEYS | // +------------------------------*/ // +string_view gerudoKeysVanilla = "Gerudo Fortress Keys will appear in their vanilla\n" + "location, dropping from fighting Gerudo guards\n" // + "that attack when trying to free the jailed\n" // + "carpenters."; // +string_view gerudoKeysAnyDungeon = "Gerudo Fortress Keys can only appear inside of\n" // + "dungeons."; // +string_view gerudoKeysOverworld = "Gerudo Fortress Keys can only appear outside of\n"// + "dungeons."; // +string_view gerudoKeysAnywhere = "Gerudo Fortress Keys can appear anywhere in the\n"// + "world."; // +/*------------------------------ // +| Key Rings | // +------------------------------*/ // +string_view keyRingDesc = "Selected key ring dungeons will have all of their\n" + "keys found at once in a ring rather than\n" // + "individually.\n\n" // + "For example, instead of shuffling 5 Forest Temple\n" + "small keys into the pool, you will find a single\n" + "key ring which will give you all 5 keys at once.\n"; +/*------------------------------ // +| BOSS KEYS | // +------------------------------*/ // +string_view bossKeyStartWith = "Boss Keys are given to you from the start so you\n" + "won't have to worry about boss doors. An easier\n"// + "mode."; // +string_view bossKeyVanilla = "Boss Keys will appear in their vanilla locations."; +string_view bossKeyOwnDungeon = "Boss Keys can only appear in their respective\n" // + "dungeon."; // +string_view bossKeyAnyDungeon = "Boss Keys can only appear inside of any dungeon,\n" + "but won't necessarily be in the dungeon that the\n" + "key is for. A difficult mode since it is more\n" // + "likely to need to enter a dungeon multiple times."; +string_view bossKeyOverworld = "Boss Keys can only appear outside of dungeons.\n" // + "You may need to enter a dungeon without the boss\n" + "key to get items required to find the key in the\n" + "overworld."; // +string_view bossKeyAnywhere = "Boss Keys can appear anywhere in the world. A\n" // + "difficult mode since it is more likely to need to\n" + "enter a dungeon multiple times."; // +/*------------------------------ // +| GANON'S CASTLE BOSS KEY | // +------------------------------*/ // +string_view ganonKeyStartWith = "Ganon's Castle Boss Key is given to you from the\n" + "start and you don't have to worry about finding it"; +string_view ganonKeyVanilla = "Ganon's Castle Boss Key will appear in the vanilla" + "location."; // +string_view ganonKeyOwnDungeon = "Ganon's Castle Boss Key can only appear inside\n" // + "Ganon's Castle."; // +string_view ganonKeyAnyDungeon = "Ganon's Castle Boss Key can only appear inside of\n" + "a dungeon, but not necessarily Ganon's Castle."; // +string_view ganonKeyOverworld = "Ganon's Castle Boss Key can only appear outside of" + "dungeons."; // +string_view ganonKeyAnywhere = "Ganon's Castle Boss Key can appear anywhere in the" + "world."; // +string_view ganonKeyLACS = "These settings put the boss key on the Light Arrow" + "Cutscene location, from Zelda in Temple of Time as" + "adult, with differing requirements."; // +/*------------------------------ // +| LACS CONDITIONS | // +------------------------------*/ // +string_view lacsMedallionCountDesc = "Set the number of Medallions required to trigger\n" + "the Light Arrow Cutscene."; // +string_view lacsStoneCountDesc = "Set the number of Spiritual Stones required to\n" // + "trigger the Light Arrow Cutscene."; // +string_view lacsRewardCountDesc = "Set the number of Dungeon Rewards (Spiritual\n" // + "Stones and Medallions) required to trigger the\n" // + "Light Arrow Cutscene."; // +string_view lacsDungeonCountDesc = "Set the number of completed dungeons required to\n" + "trigger the Light Arrow Cutscene.\n" // + "\n" // + "Dungeons are considered complete when Link steps\n" + "into the blue warp at the end of them."; // +string_view lacsTokenCountDesc = "Set the number of Gold Skulltula Tokens required\n" + "to trigger the Light Arrow Cutscene."; // +/*------------------------------ // +| SKIP CHILD STEALTH | // +------------------------------*/ // +string_view childStealthDesc = "The crawlspace into Hyrule Castle goes straight to" + "Zelda, skipping the guards."; // +/*------------------------------ // +| SKIP TOWER ESCAPE | // +------------------------------*/ // +string_view skipTowerEscapeDesc = "The tower escape sequence between Ganondorf and\n"// + "Ganon will be skipped."; // +/*------------------------------ // +| SKIP EPONA RACE | // +------------------------------*/ // +string_view skipEponaRaceDesc = "Epona can be summoned with Epona's Song without\n"// + "needing to race Ingo."; // +/*------------------------------ // +| SKIP MINIGAME PHASES | // +------------------------------*/ // +string_view skipMinigamePhasesDesc = "Completing the second objective in the Dampe Race\n" + "and Gerudo Archery on the first attempt will give\n" + "both rewards at once for that minigame."; // +/*------------------------------ // +| FREE SCARECROW | // +------------------------------*/ // +string_view freeScarecrowDesc = "Pulling out the Ocarina near a spot at which\n" // + "Pierre can spawn will do so, without needing\n" // + "the song."; // +/*------------------------------ // +| FOUR POES CUTSCENE | // +------------------------------*/ // +string_view fourPoesDesc = "The cutscene with the 4 poes in Forest Temple will" + "be skipped. If the cutscene is not skipped, it can" + "be exploited to reach the basement early."; // +/*------------------------------ // +| LAKE HYLIA OWL | // +------------------------------*/ // +string_view lakeHyliaOwlDesc = "The owl flight cutscene in Lake Hylia will be\n" // + "skipped. This cutscene lets you see what item\n" // + "is on top of the laboratory roof."; // +/*------------------------------ // +| BIG POE TARGET COUNT | // +------------------------------*/ // +string_view bigPoeTargetCountDesc = "The Poe buyer will give a reward for turning in\n"// + "the chosen number of Big Poes."; // +/*------------------------------ // +| NUM REQUIRED CUCCOS | // +------------------------------*/ // +string_view numRequiredCuccosDesc = "The cucco lady will give a reward for returning\n"// + "this many of her cuccos to the pen."; // +/*------------------------------ // +| KING ZORA SPEED | // +-------------------------------*/ // +string_view kingZoraSpeedFast = "King Zora will move out of the way in 1 shuffle"; // + // +string_view kingZoraSpeedVanilla = "King Zora will move out of the way in 26 shuffles"; + // +string_view kingZoraSpeedRandom = "King Zora will move out of the way in 1 to 128\n" // + "shuffles, with lower numbers being more common"; // +/*------------------------------ // +| COMPLETE MASK QUEST | // +------------------------------*/ // +string_view completeMaskDesc = "Once the happy mask shop is opened, all masks\n" // + "will be available to be borrowed."; // +/*------------------------------ // +| QUICK TEXT | // +------------------------------*/ // +string_view quickTextDesc0 = "Quick text will be unchanged, requiring\n" // + "frame-perfect inputs like in the vanilla game."; // +string_view quickTextDesc1 = "Every text box will be completable by pressing B\n" + "at any point while it's scrolling."; // +string_view quickTextDesc2 = "Every text box will auto-complete instantly.\n" // + "No scrolling allowed!"; // +string_view quickTextDesc3 = "Holding B will advance and close text boxes\n" // + "automatically, except for choice selections."; // +/*------------------------------ // +| SKIP SONG REPLAYS | // +------------------------------*/ // +string_view skipSongReplaysDesc = "The automatic replay after you play a song will\n"// + "be skipped.\n" // + "You can choose to keep the sfx anyway, but you\n" // + "will have control of Link during it."; // +/*------------------------------ // +| KEEP FW WARP POINT | // +------------------------------*/ // +string_view keepFWWarpPointDesc = "The Farore's Wind warp point will stay active\n" // + "after having been warped to. The old point will\n"// + "need to be dispelled before setting a new one."; // +/*------------------------------ // +| FAST BUNNY HOOD | // +------------------------------*/ // +string_view fastBunnyHoodDesc = "The Bunny Hood mask behaves like it does in\n" // + "Majora's Mask and makes you run 50% faster."; // +/*------------------------------ // +| GOSSIP STONE HINTS | // +------------------------------*/ // +string_view gossipStonesHintsDesc = "Gossip Stones can be made to give hints about\n" // + "where items can be found.\n" // + "Different settings can be chosen to decide which\n" + "item is needed to speak to Gossip Stones. Choosing" + "to stick with the Mask of Truth will make the\n" // + "hints very difficult to obtain.\n" // + "Hints for 'on the way of the hero' are locations\n" + "that contain items that are required to beat the\n" + "game."; // + // +/*------------------------------ // +| HINT CLARITY | // +------------------------------*/ // +string_view obscureHintsDesc = "Sets the difficulty of hints.\n" // + "Obscure: Hints are unique for each thing, but\n" // + "the writing may be confusing.\n" // + "E.g. Kokiri Sword > a butter knife"; // +string_view ambiguousHintsDesc = "Sets the difficulty of hints.\n" // + "Ambiguous: Hints are clearly written, but may\n" // + "refer to more than one thing.\n" // + "E.g. Kokiri Sword > a sword"; // +string_view clearHintsDesc = "Sets the difficulty of hints.\n" // + "Clear: Hints are clearly written and are unique\n"// + "for each thing.\n" // + "E.g. Kokiri Sword > the Kokiri Sword"; // +/*------------------------------ // +| HINT DISTRIBUTION | // +------------------------------*/ // +string_view uselessHintsDesc = "Only junk hints."; // +string_view balancedHintsDesc = "Recommended hint spread."; // +string_view strongHintsDesc = "More useful hints."; // +string_view veryStrongHintsDesc = "Many powerful hints."; // + // +/*------------------------------ // +| MAP AND COMPASS GIVES INFO | // +------------------------------*/ // +string_view compassesShowRewardsDesc = "If dungeon rewards are set to be shuffled at the\n" + "end of dungeons, the in-game menu will reveal\n" // + "which reward is in each dungeon, if the compass\n"// + "for that dungeon has been collected."; // +string_view compassesShowWotHDesc = "The in-game menu will reveal whether each\n" // + "dungeon is on the Way of the Hero, a barren\n" // + "location, or neither, if the compass for that\n" // + "dungeon has been collected."; // +string_view mapsShowDungeonModesDesc = "If any Master Quest dungeons will be randomly\n" // + "shuffled, the in-game menu will reveal whether\n" // + "it is in its Vanilla or Master Quest form, if\n" // + "the map for the dungeon has been collected.\n" // + "Ganon's Castle and Gerudo Training Grounds are\n" // + "always revealed, as they do not have maps."; // +/*------------------------------ // +| DAMAGE MULTIPLIER | // +------------------------------*/ // +string_view damageMultiDesc = "Changes the amount of damage taken.\n" // + "\n" // + "If set to OHKO, Link will die in one hit."; // +/*------------------------------ // +| STARTING TIME | // +------------------------------*/ // +string_view startingTimeDesc = "Change up Link's sleep routine."; // + // +/*------------------------------ // +| ALL LOCATIONS REACHABLE | // +------------------------------*/ // +string_view locationsReachableDesc = "When this options is enabled, the randomizer will\n" + "guarantee that every item is obtainable and every\n" + "location is reachable. When disabled, only\n" // + "required items and locations to beat the game\n" // + "will be guaranteed reachable."; // +/*------------------------------ // +| NIGHT GS EXPECT SUNS | // +------------------------------*/ // +string_view nightGSDesc = "GS Tokens that can only be obtained during the\n" // + "night expect you to have Sun's Song to collect\n" // + "them. This prevents needing to wait until night\n"// + "for some locations."; // + // +/*------------------------------ // +| CHEST ANIMATIONS | // +------------------------------*/ // +string_view chestAnimDesc = "Choose if you want the slow animation to play\n" // + "if a chest contains a major item.\n"; // + // +/*------------------------------ // +| CHEST SIZE AND COLOR | // +------------------------------*/ // +string_view chestSizeDesc = "This option will change the appearance of all\n" // + "regular chests depending on their contents:\n" // + "Major Items = Big Wooden Chests\n" // + "Lesser Items = Small Wooden Chests\n" // + "Boss Keys = Big Fancy Chests\n" // + "Small Keys = Small Fancy Chests"; // + // +/*------------------------------ // +| INGAME SPOILERS | // +------------------------------*/ // +string_view ingameSpoilersShowDesc = "Every spoiler is shown."; // +string_view ingameSpoilersHideDesc = "Hides the spheres page and only shows a\n" // + "location's item after it has been found."; // + // +/*------------------------------ // +| MENU OPENING BUTTON | // +------------------------------*/ // +string_view menuButtonDesc = "Choose which button will bring up the Dungeon\n" // + "Information Menu. You can also use the menu to\n" // + "buffer frame perfect inputs if you choose D-Pad"; // + // +/*------------------------------ // +| START WITH CONSUMABLES | // +------------------------------*/ // +string_view startWithConsumablesDesc = "Start the game with maxed out Deku Sticks and Deku" + "Nuts."; // + // +/*------------------------------ // +| START WITH MAX RUPEES | // +------------------------------*/ // +string_view startWithMaxRupeesDesc = "Start the game with a full wallet.\n" // + "Wallet upgrades will also fill the wallet."; // + // +/*------------------------------ // +| ITEM POOL | // +------------------------------*/ // +string_view itemPoolPlentiful = "Extra major items are added to the pool."; // +string_view itemPoolBalanced = "Original item pool."; // +string_view itemPoolScarce = "Some excess items are removed, including health\n"// + "upgrades."; // +string_view itemPoolMinimal = "Most excess items are removed."; // + // +/*------------------------------ // +| ICE TRAPS | // +------------------------------*/ // +string_view iceTrapsOff = "All Ice Traps are removed."; // +string_view iceTrapsNormal = "Only Ice Traps from the base item pool are placed."; +string_view iceTrapsExtra = "Chance to add extra Ice Traps when junk items are\n" + "added to the itempool."; // +string_view iceTrapsMayhem = "All added junk items will be Ice Traps."; // +string_view iceTrapsOnslaught = "All junk items will be replaced by Ice Traps, even" + "those in the base pool."; // +/*------------------------------ // +| REMOVE DOUBLE DEFENSE | // +------------------------------*/ // +string_view removeDDDesc = "If set the double defense item will be removed\n" // + "from the item pool for balanced and plentiful."; // +/*------------------------------ // +| PROGRESSSIVE GORON SOWRD | // +------------------------------*/ // +string_view progGoronSword = "Giant's Knife will always be found\n" // + "before Biggoron's Sword. Medigoron only starts\n" // + "selling new knives once the Giant's Knife\n" // + "has been found and broken."; // +/*------------------------------ // +| USE FARORE'S WIND ANYWHERE | // +------------------------------*/ // +string_view faroresWindAnywhereDesc = "Farore's Wind can be used outside of dungeons."; // + // +/*------------------------------ // +| LIFT AGE RESTRICTIONS | // +------------------------------*/ // +string_view ageRestrictionsDesc = "Remove age restrictions for inventory items.\n" // + "Select \"Choose\" to open the list of individual\n" + "options.\n\n" // + "Most of the items won't appear correctly when\n" // + "used as the wrong version of Link, but they'll be\n" + "fully functional otherwise."; // + // +/*------------------------------ // +| ENABLE ADULT DEKU STICK | // +------------------------------*/ // +string_view adultStickDesc = "Adult Link can wield a deku stick. In game Adult\n" + "Link will look like he's holding a Hylian Shield,\n" + "but rest assured it is a deku stick."; // + // +/*------------------------------ // +| ENABLE ADULT BOOMERANG | // +------------------------------*/ // +string_view adultBoomerangDesc = "Adult Link can throw the boomerang."; // + // +/*------------------------------ // +| ENABLE CHILD HAMMER | // +------------------------------*/ // +string_view childHammerDesc = "Child Link can swing the Megaton Hammer."; // +/*------------------------------ // +| ENABLE ADULT SLINGSHOT | // +------------------------------*/ // +string_view adultSlingshotDesc = "Adult Link can use the Slingshot (but it looks\n" // + "like the Bow)."; // + // +/*------------------------------ // +| ENABLE CHILD BOW | // +------------------------------*/ // +string_view childBowDesc = "Child Link can use the Bow. It will look like the\n" + "Slingshot, but will shoot arrows."; // + // +/*------------------------------ // +| ENABLE CHILD HOOKSHOT | // +------------------------------*/ // +string_view childHookshotDesc = "Child Link can use the Hookshot/Longshot.\n" // + "It will be difficult to aim, the red dot and\n" // + "laser won't appear and the hook will look like\n" // + "a small bomb."; // +/*------------------------------ // +| ENABLE CHILD IRON BOOTS | // +------------------------------*/ // +string_view childIronBootsDesc = "Child Link can equip the Iron Boots."; // + // +/*------------------------------ // +| ENABLE CHILD HOVER BOOTS | // +------------------------------*/ // +string_view childHoverBootsDesc = "Child Link can equip the Hover Boots. The yellow\n" + "circle beneath Link's feet won't appear."; // + // +/*------------------------------ // +| ENABLE ADULT MASKS | // +------------------------------*/ // +string_view adultMasksDesc = "Adult Link can equip masks.\n" // + "\n" // + "This setting will not change the logic."; // + // +/*------------------------------ // +| ENABLE ADULT KOKIRI SWORD | // +------------------------------*/ // +string_view adultKokiriSwordDesc = "Adult Link can equip the Kokiri Sword."; // + // +/*------------------------------ // +| ENABLE CHILD MASTER SWORD | // +------------------------------*/ // +string_view childMasterSwordDesc = "Child Link can equip the Master Sword."; // + // +/*------------------------------ // +| ENABLE CHILD BIGGORON SWORD | // +------------------------------*/ // +string_view childBiggoronSwordDesc = "Child Link can equip the Biggoron Sword and the\n"// + "Giant's Knife."; // + // +/*------------------------------ // +| ENABLE ADULT DEKU SHIELD | // +------------------------------*/ // +string_view adultDekuShieldDesc = "Adult Link can equip the Deku Shield."; // + // +/*------------------------------ // +| ENABLE CHILD MIRROR SHIELD | // +------------------------------*/ // +string_view childMirrorShieldDesc = "Child Link can equip the Mirror Shield."; // + // +/*------------------------------ // +| ENABLE CHILD GORON TUNIC | // +------------------------------*/ // +string_view childGoronTunicDesc = "Child Link can equip the Goron Tunic."; // + // +/*------------------------------ // +| ENABLE CHILD ZORA TUNIC | // +------------------------------*/ // +string_view childZoraTunicDesc = "Child Link can equip the Zora Tunic."; // + // +/*------------------------------ // +| GK DURABILITY | // +------------------------------*/ // +string_view gkDurabilityVanilla = "The durability will always be set to 8."; // +string_view gkDurabilityRandomRisk = "Each Giant's Knife will get a random durability\n"// + "between 1 and 128, with low being more common,\n" // + "and with an average of 15."; // +string_view gkDurabilityRandomSafe = "Each Giant's Knife will get a random durability\n"// + "between 10 and 50, with an average of 30."; // + // +/*------------------------------ // +| MULTIPLAYER | // +------------------------------*/ // +string_view mp_EnabledDesc = "Enables multiplayer.\n" // + "Other players will always be seen and heard\n" // + "regardless of the other settings."; // +string_view mp_SharedProgressDesc = "Progress and certain actors will be synced between" + "everyone in the network that has this option on,\n" + "the same seed hash, and the same sync id."; // +string_view mp_SyncIdDesc = "Limits shared progress to only sync with other\n" // + "players that have the same sync ID. This is only\n" + "necessary to set if multiple groups of players\n" // + "play on the same seed hash, but only want to share" + "their progress with certan people.\n" // + "For example, when doing a 2v2 race."; // +string_view mp_SharedHealthDesc = "Syncs health when shared progress is on,\n" // + "otherwise just shares the damage and recovery."; // +string_view mp_SharedRupeesDesc = "Syncs rupees when shared progress is on,\n" // + "otherwise just shares the gain and loss."; // +string_view mp_SharedAmmoDesc = "Syncs ammo when shared progress is on,\n" // + "otherwise just shares the gain and loss."; // + // +/*------------------------------ // +| INGAME DEFAULTS | // +------------------------------*/ // +string_view zTargetingDesc = "Sets L-Targeting to start as switch or hold."; // +string_view cameraControlDesc = "Sets the camera controls to start as normal or\n" // + "with the y-axis inverted."; // +string_view motionControlDesc = "Sets the motion controls to start on or off."; // +string_view togglePlayMusicDesc = "Starts the game with the music on or off."; // +string_view togglePlaySFXDesc = "Starts the game with the sound effects on or off."; +string_view silenceNaviDesc = "Sets whether Navi should start silenced or not."; // +string_view ignoreMaskReactionDesc = "Sets whether NPCs ignore the worn mask or not.\n" // + "Does not apply when trading masks."; // + // +/*------------------------------ // +| NAVI & TRAIL COLORS | // +------------------------------*/ // +string_view naviColorsDesc = "Inner color is for the main light orb, outer color" + "is for the aura.\n\n" // + "The Rainbow option will make the color change\n" // + "continuously in a 3 seconds loop."; // +string_view necessarySimpleModeDesc = "For boomerang and sword trails, OoT3D uses a\n" // + "special texture that doesn't support every color.\n\n" + "Unsupported colors will always use the plain\n" // + "texture from OoT instead:\n" // + "- Black and Purple sword trails\n" // + "- White, Black and Purple boomerang trails\n" // + "- Random or Custom colors without at least one\n" // + " maxed out RGB component."; // +string_view alwaysSimpleModeDesc = "All boomerang and sword trails will use the plain\n" + "texture from OoT, regardless of what color is\n" // + "chosen."; // + // +/*------------------------------ // +| COLORED KEYS | // +------------------------------*/ // +string_view coloredKeysDesc = "If set, small key models will be colored\n" // + "differently depending on which dungeon they can be" + "used in. Forest Temple keys are green. Fire Temple" + "keys are red. etc."; // +string_view coloredBossKeysDesc = "If set, boss key models will be colored\n" // + "differently depending on which dungeon they can be" + "used in. The Forest Temple boss key is green. The " + "Fire Temple boss key is red. etc."; // +/*------------------------------ // +| MIRROR WORLD | // +------------------------------*/ // +string_view mirrorWorldDesc = "If set, the world will be mirrored."; // + // +/*------------------------------ // +| SHUFFLE MUSIC | // +------------------------------*/ // +string_view musicRandoDesc = "Randomize the music in the game."; // +string_view shuffleBGMDesc = "Randomize area background music, either\n" // + "grouped into categories or all mixed together."; // +string_view fanfaresOffDesc = "Fanfares are not shuffled."; // +string_view onlyFanfaresDesc = "Fanfares and ocarina songs are shuffled in\n" // + "separate pools."; // +string_view fanfaresOcarinaDesc = "Fanfares and ocarina songs are shuffled together\n" + "in the same pool."; // +string_view shuffleOcaMusicDesc = "The music that plays back after you play an" // + "ocarina song is randomized."; // +/*------------------------------ // +| SHUFFLE SFX | // +------------------------------*/ // +string_view shuffleSFXOff = "Sound effects will stay vanilla."; // +string_view shuffleSFXAll = "All sound effects will be shuffled."; // +string_view shuffleSFXSceneSpecific = "All sound effects will be shuffled, but will also\n" + "be different in each scene."; // +string_view shuffleSFXChaos = "Each sound effect will become random about\n" // + "every second."; // +string_view shuffleSFXCategorically = "Sound effects will be shuffled in categories.\n" // + "\n" // + "The sound may get annoying fast when disabled."; // +/*------------------------------ // +| RANDOM TRAP DAMAGE TYPE | // +------------------------------*/ // +string_view randomTrapDmgDesc = "All traps will be the base game ice trap"; // + // +string_view basicTrapDmgDesc = "All alternative traps will cause a small damage\n"// + "and no other negative effects"; // + // +string_view advancedTrapDmgDesc = "Some chest traps will burn your Deku Shield or\n" // + "cause a lot of damage (with one-hit protection)"; // + //--------------// +/*------------------------------ // +| DETAILED LOGIC EXPLANATIONS | // +------------------------------*/ +string_view ToggleLogicNoneDesc = "Disables all the Detailed Logic tricks."; // +string_view ToggleLogicNoviceDesc = "Enables only the easier Detailed Logic tricks"; // +string_view ToggleLogicIntermediateDesc = "Enables all but the harder Detailed Logic tricks."; +string_view ToggleLogicExpertDesc = "Enables all the Detailed Logic tricks."; // + // +string_view LogicGrottosWithoutAgonyDesc = "Difficulty: Novice\n" // + "Grottos can be accessed without Stone of Agony,\n"// + "simply by knowing where they are located."; // +string_view LogicVisibleCollisionDesc = "Difficulty: Novice\n" // + "The closed Kakariko Village Gate can be crossed\n"// + "when coming from Death Mountain Trail.\n" // + "Useful for Entrance Randomiser."; // +string_view LogicFewerTunicRequirementsDesc = "Difficulty: Novice\n" // + "Allows the following possible without Tunics:\n" // + "- Enter Water Temple.\n" // + "- Enter Fire Temple. Only the first floor\n" // + " is accessible, and not Volvagia.\n" // + "- Zora's Fountain Bottom Freestanding PoH.\n" // + "- Gerudo Training Grounds Underwater Silver Rupee\n" + "Chest. May need to make multiple trips."; // +string_view LogicLostWoodsGSBeanDesc = "Difficulty: Novice\n" // + "You can collect the token with a precise Hookshot\n" + "use, as long as you can kill the Skulltula first.\n" + "It can be killed using Longshot, Bow, Bombchus\n" // + "or Din's Fire."; // +string_view LogicLabDivingDesc = "Difficulty: Novice\n" // + "Remove the Iron Boots in the midst of Hookshotting" + "the underwater crate"; // +string_view LogicLabWallGSDesc = "Difficulty: Intermediate\n" // + "The jump slash to actually collect the token is\n"// + "somewhat precise"; // +string_view LogicGraveyardPoHDesc = "Difficulty: Novice\n" // + "Using a precise moving setup you can obtain the\n"// + "Piece of Heart by having the Boomerang interact\n"// + "with it along the return path."; // +string_view LogicChildDampeRacePoHDesc = "Difficulty: Intermediate\n" // + "It is possible to complete the second dampe race\n" + "as child in under a minute, but it is a strict\n" // + "time limit."; // +string_view LogicGVHammerChestDesc = "Difficulty: Novice\n" // + "The chest can be reached by sidehopping between\n"// + "the wall and the east most hammer rock."; // +string_view LogicGerudoKitchenDesc = "Difficulty: Intermediate\n" // + "The logic normally guarantees one of Bow,\n" // + "Hookshot, or Hover Boots."; // +string_view LogicLensWastelandDesc = "Difficulty: Expert\n" // + "By memorizing the path, you can travel through the" + "Wasteland without using the Lens of Truth to see\n" + "the Poe. The equivalent trick for going in reverse" + "through the Wasteland is \"Reverse Wasteland\"."; // +string_view LogicReverseWastelandDesc = "Difficulty: Expert\n" // + "By memorizing the path, you can travel through the" + "Wasteland in reverse."; // +string_view LogicColossusGSDesc = "Difficulty: Expert\n" // + "Somewhat precise. If you kill enough Leevers you\n" + "can get enough of a break to take some time to aim" + "more carefully."; // +string_view LogicOutsideGanonsGSDesc = "Difficulty: Intermediate\n" // + "Can be killed with a precise sidehop jumpslash\n" // + "from the top of the broken arch."; // +string_view LogicManOnRoofDesc = "Difficulty: Novice\n" // + "Can be reached by side-hopping off the watchtower."; +string_view LogicWindmillPoHHookshotDesc = "Difficulty: Novice\n" // + "Adult Link can reach the upper area of the windmill" + "using the hookshot and a midair jump slash."; // +string_view LogicDMTBombableDesc = "Difficulty: Expert\n" // + "Child Link can blow up the wall using a nearby\n" // + "bomb flower. You must backwalk with the flower and" + "then quickly throw it toward the wall."; // +string_view LogicDMTSoilGSDesc = "Difficulty: Intermediate\n" // + "Bugs will go into the soft soil even while the\n" // + "boulder is still blocking the entrance if dropped\n" + "from above. Then, using a precise moving setup you" + "can kill the Gold Skulltula and obtain the token by" + "having the Boomerang collect it while returning.";// +string_view LogicDMTSummitHoverDesc = "Difficulty: Intermediate\n" // + "By rolling around the lower boulder with hover\n" // + "boots and grabbing the ledge with the higher\n" // + "boulder near the wall, you'll be able to grab the\n" + "ledge above it to reach the summit."; // +string_view LogicLinkGoronDinsDesc = "Difficulty: Intermediate\n" // + "The timing is quite awkward."; // +string_view LogicGoronCityLeftMostDesc = "Difficulty: Novice\n" // + "A precise backwalk starting from on top of the\n" // + "crate and ending with a precisely-timed backflip\n" + "can reach this chest without needing either the\n"// + "Hammer or Silver Gauntlets."; // +string_view LogicGoronCityPotDesc = "Difficulty: Expert\n" // + "A Bombchu can be used to stop the spinning pot,\n"// + "but it can be quite finicky to get it to work."; // +string_view LogicGoronCityPotWithStrengthDesc = "Difficulty: Intermediate\n" // + "Allows for stopping the Goron City Spinning Pot\n"// + "using a bomb flower alone, requiring strength in\n" + "lieu of inventory explosives."; // +string_view LogicChildRollingWithStrengthDesc = "Difficulty: Expert\n" // + "Use the bombflower on the stairs or near\n" // + "Medigoron. Timing is tight, especially without\n" // + "backwalking."; // +string_view LogicCraterUpperToLowerDesc = "Difficulty: Intermediate\n" // + "With the Hammer, you can jump slash the rock twice" + "in the same jump in order to destroy it before you" + "fall into the lava."; // +string_view LogicCraterBeanPoHWithHoversDesc = "Difficulty: Expert\n" // + "Hover from the base of the bridge near Goron City\n" + "and walk up the very steep slope."; // +string_view LogicBiggoronBoleroDesc = "Difficulty: Intermediate\n" // + "Playing a warp song normally causes a trade item\n" + "to spoil immediately, however, it is possible use\n" + "Bolero to reach Biggoron and still deliver the Eye" + "Drops before they spoil. If you do not wear the\n" + "Goron Tunic, the heat timer inside the crater will" + "override the trade item's timer. When you exit to\n" + "Death Mountain Trail you will have one second to\n" + "show the Eye Drops before they expire."; // +string_view LogicZoraRiverLowerDesc = "Difficulty: Novice\n" // + "Adult can reach this PoH with a precise jump, no\n" + "Hover Boots required."; // +string_view LogicZoraRiverUpperDesc = "Difficulty: Novice\n" // + "Adult can reach this PoH with a precise jump, no\n" + "Hover Boots required."; // +string_view LogicZFGreatFairyDesc = "Difficulty: Novice\n" // + "Destroying the boulders blocking the hidden area\n" + "with silver gauntlets and hammer lets you pass\n" // + "under the wall to the great fairy fountain."; // +string_view LogicDekuB1WebsWithBowDesc = "Difficulty: Novice\n" // + "All spider web walls in the Deku Tree basement can" + "be burnt as adult with just a bow by shooting\n" // + "through torches. This trick only applies to the\n"// + "circular web leading to Gohma; the two vertical\n"// + "webs are always in logic. Backflip onto the chest\n" + "near the torch at the bottom of the vine wall.\n" // + "With precise positioning you can shoot through the" + "torch to the right edge of the circular web."; // +string_view LogicDekuB1SkipDesc = "Difficulty: Intermediate\n" // + "A precise jump can be used to skip needing to use\n" + "the Slingshot to go around B1 of the Deku Tree. If" + "used with the \"Closed Forest\" setting, a\n" // + "Slingshot will not be guaranteed to exist\n" // + "somewhere inside the Forest. This trick applies to" + "both Vanilla and Master Quest."; // +string_view LogicDekuBasementGSDesc = "Difficulty: Intermediate\n" // + "Can be defeated by doing a precise jump slash."; // +string_view LogicDCStaircaseDesc = "Difficulty: Intermediate\n" // + "The Bow can be used to knock down the stairs with\n" + "two well-timed shots."; // +string_view LogicDCJumpDesc = "Difficulty: Novice\n" // + "Jump is adult only."; // +string_view LogicDCSlingshotSkipDesc = "Difficulty: Expert\n" // + "With precise platforming, child can cross the\n" // + "platforms while the flame circles are there. When\n" + "enabling this trick, it's recommended that you\n" // + "also enable the Adult variant: \"Dodongo's Cavern\n" + "Spike Trap Room Jump without Hover Boots\"."; // +string_view LogicDCScarecrowGSDesc = "Difficulty: Intermediate\n" // + "You can jump off an Armos Statue to reach the\n" // + "alcove with the Gold Skulltula. It takes quite a\n" + "long time to pull the statue the entire way. The\n" + "jump to the alcove can be a bit picky when done\n"// + "as child."; // +string_view LogicJabuBossGSAdultDesc = "Difficulty: Intermediate\n" // + "You can easily get over to the door to the near\n"// + "boss area early with Hover Boots. The tricky part\n" + "is getting through the door without being able to\n" + "use a box to keep the switch pressed. One way is\n" + "to quickly roll from the switch and open the door\n" + "before it closes."; // +string_view LogicJabuScrubJumpDiveDesc = "Difficulty: Novice\n" // + "Standing above the underwater tunnel leading to\n"// + "the scrub, jump down and swim through the tunnel.\n" + "This allows adult to access the scrub with no\n" // + "Scale or Iron Boots."; // +string_view LogicForestOutsideBackdoorDesc = "Difficulty: Intermediate\n" // + "With a precise jump slash from above, you can\n" // + "reach the backdoor to the west courtyard without\n" + "Hover Boots. Applies to both Vanilla and Master\n"// + "Quest."; // +string_view LogicForestDoorFrameDesc = "Difficulty: Intermediate\n" // + "A precise Hover Boots movement from the upper\n" // + "balconies in this courtyard can be used to get on\n" + "top of the door frame. Applies to both Vanilla and" + "Master Quest. In Vanilla, from on top the door\n" // + "frame you can summon Pierre, allowing you to\n" // + "access the falling ceiling room early. In Master\n" + "Quest, this allows you to obtain the GS on the\n" // + "door frame as adult without Hookshot or Song of\n"// + "Time."; // +string_view LogicForestOutdoorEastGSDesc = "Difficulty: Novice\n" // + "Precise Boomerang throws can allow child to kill\n" + "the Skulltula and collect the token."; // +string_view LogicFireBossDoorJumpDesc = "Difficulty: Intermediate\n" // + "The Fire Temple Boss Door can be reached with a\n"// + "precise jump. You must be touching the side wall\n" + "of the room so that Link will grab the ledge from\n" + "farther away than is normally possible."; // +string_view LogicFireStrengthDesc = "Difficulty: Expert\n" // + "A precise jump can be used to skip pushing the\n" // + "block."; // +string_view LogicFireScarecrowDesc = "Difficulty: Novice\n" // + "Also known as \"Pixelshot\". The Longshot can\n" // + "reach the target on the elevator itself, allowing\n" + "you to skip needing to spawn the scarecrow."; // +string_view LogicFireFlameMazeDesc = "Difficulty: Expert\n" // + "If you move quickly you can sneak past the edge of" + "a flame wall before it can rise up to block you.\n" + "To do it without taking damage is more precise.\n"// + "Allows you to progress without needing either a\n"// + "Small Key or Hover Boots."; // +string_view LogicFireSongOfTimeDesc = "Difficulty: Intermediate\n" // + "A precise jump can be used to reach this room."; // +string_view LogicWaterTempleTorchLongshotDesc = "Difficulty: Novice\n" // + "Stand on the eastern side of the central pillar\n"// + "and longshot the torches on the bottom level.\n" // + "Swim through the corridor and float up to the top\n" + "level. This allows access to this area and lower\n" + "water levels without Iron Boots. The majority of\n" + "the tricks that allow you to skip Iron Boots in\n"// + "the Water Temple are not going to be relevant\n" // + "unless this trick is first enabled."; // +string_view LogicWaterTempleUpperBoostDesc = "Difficulty: Expert\n" // + "Stand on the corner closest to the upper ledge\n" // + "where you play Zelda's Lullaby to raise the water\n" + "and put a bomb down behind you. Hold forward when\n" + "the bomb explodes and Link should jump just far\n"// + "enough to grab the ledge."; // +string_view LogicWaterCentralBowDesc = "Difficulty: Intermediate\n" // + "A very precise Bow shot can hit the eye switch\n" // + "from the floor above. Then, you can jump down into" + "the hallway and make through it before the gate\n"// + "closes. It can also be done as child, using the\n"// + "Slingshot instead of the Bow."; // +string_view LogicWaterCentralGSFWDesc = "Difficulty: Novice\n" // + "If you set Farore's Wind inside the central pillar" + "and then return to that warp point after raising\n" + "the water to the highest level, you can obtain\n" // + "this Skulltula Token with Hookshot or Boomerang.";// +string_view LogicWaterCrackedWallNothingDesc = "Difficulty: Expert\n" // + "A precise jump slash (among other methods) will\n"// + "get you to the cracked wall without needing the\n"// + "Hover Boots or to raise the water to the middle\n"// + "level. This trick supersedes \"Water Temple\n" // + "Cracked Wall with Hover Boots\"."; // +string_view LogicWaterCrackedWallHoversDesc = "Difficulty: Expert\n" // + "With a midair side-hop while wearing the Hover\n" // + "Boots, you can reach the cracked wall without\n" // + "needing to raise the water up to the middle level."; +string_view LogicWaterBossKeyRegionDesc = "Difficulty: Intermediate\n" // + "With precise Hover Boots movement it is possible\n" + "to reach the boss key chest's region without\n" // + "needing the Longshot. It is not necessary to take\n" + "damage from the spikes. The Gold Skulltula Token\n" + "in the following room can also be obtained with\n"// + "just the Hover Boots."; // +string_view LogicWaterBKJumpDiveDesc = "Difficulty: Intermediate\n" // + "Stand on the very edge of the raised corridor\n" // + "leading from the push block room to the rolling\n"// + "boulder corridor. Face the gold skulltula on the\n" + "waterfall and jump over the boulder corridor floor" + "into the pool of water, swimming right once\n" // + "underwater. This allows access to the boss key\n" // + "room without Iron boots."; // +string_view LogicWaterNorthBasementLedgeJumpDesc = "Difficulty: Novice\n" // + "In the northern basement there's a ledge from\n" // + "where, in vanilla Water Temple, boulders roll out\n" + "into the room. Normally to jump directly to this\n" + "ledge logically requires the Hover Boots, but with" + "precise jump, it can be done without them. This\n"// + "trick applies to both Vanilla and Master Quest."; // +string_view LogicWaterDragonAdultDesc = "Difficulty: Expert\n" // + "Normally you need both Hookshot and Iron Boots to\n" + "hit the switch and swim through the tunnel to get\n" + "to the chest. But by hitting the switch from dry\n" + "land, using one of Bombchus, Hookshot, or Bow, it\n" + "is possible to skip one or both of those\n" // + "requirements. After the gate has been opened, a\n"// + "well-timed dive with at least the Silver Scale\n" // + "could be used to swim through the tunnel."; // +string_view LogicWaterDragonJumpDiveDesc = "Difficulty: Expert\n" // + "If you come into the dragon statue room from the\n" + "serpent river, you can jump down from above and\n"// + "get into the tunnel without needing either Iron\n"// + "Boots or a Scale. This trick applies to both\n" // + "Vanilla and Master Quest. In Vanilla, you must\n" // + "shoot the switch from above with the Bow, and then" + "quickly get through the tunnel before the gate\n" // + "closes."; // +string_view LogicWaterRiverGSDesc = "Difficulty: Novice\n" // + "Standing on the exposed ground toward the end of\n" + "the river, a precise Longshot use can obtain the\n" + "token."; // +string_view LogicWaterFallingPlatformGSDesc = "Difficulty: Intermediate\n" // + "If you stand on the very edge of the platform,\n" // + "this Gold Skulltula can be obtained with only the\n" + "Hookshot."; // +string_view LogicSpiritLowerAdultSwitchDesc = "Difficulty: Novice\n" // + "A bomb can be used to hit the switch on the\n" // + "ceiling, but it must be thrown from a particular\n" + "distance away and with precise timing."; // +string_view LogicSpiritChildBombchuDesc = "Difficulty: Intermediate\n" // + "A carefully-timed Bombchu can hit the switch."; // +string_view LogicSpiritWallDesc = "Difficulty: Expert\n" // + "The logic normally guarantees a way of dealing\n" // + "with both the Beamos and the Walltula before\n" // + "climbing the wall."; // +string_view LogicSpiritLobbyGSDesc = "Difficulty: Intermediate\n" // + "Standing on the highest part of the arm of the\n" // + "statue, a precise Boomerang throw can kill and\n" // + "obtain this Gold Skulltula. You must throw the\n" // + "Boomerang slightly off to the side so that it\n" // + "curves into the Skulltula, as aiming directly at\n" + "it will clank off of the wall in front."; // +string_view LogicSpiritMapChestDesc = "Difficulty: Intermediate\n" // + "To get a line of sight from the upper torch to the" + "map chest torches, you must pull an Armos statue\n" + "all the way up the stairs."; // +string_view LogicSpiritSunChestDesc = "Difficulty: Expert\n" // + "Using the blocks in the room as platforms you can\n" + "get lines of sight to all three torches. The timer" + "on the torches is quite short so you must move\n" // + "quickly in order to light all three."; // +string_view LogicShadowFireArrowEntryDesc = "Difficulty: Expert\n" // + "It is possible to light all of the torches to open" + "the Shadow Temple entrance with just Fire Arrows,\n" + "but you must be very quick, precise, and strategic" + "with how you take your shots."; // +string_view LogicShadowUmbrellaDesc = "Difficulty: Expert\n" // + "A very precise Hover Boots movement from off of\n"// + "the lower chest can get you on top of the crushing\n" + "spikes without needing to pull the block. Applies\n" + "to both Vanilla and Master Quest."; // +string_view LogicShadowFreestandingKeyDesc = "Difficulty: Intermediate\n" // + "Release the Bombchu with good timing so that it\n"// + "explodes near the bottom of the pot."; // +string_view LogicShadowStatueDesc = "Difficulty: Novice\n" // + "By sending a Bombchu around the edge of the gorge," + "you can knock down the statue without needing a\n"// + "Bow. Applies in both vanilla and MQ Shadow."; // +string_view LogicChildDeadhandDesc = "Difficulty: Novice\n" // + "Requires 9 sticks or 5 jump slashes."; // +string_view LogicGtgWithoutHookshotDesc = "Difficulty: Expert\n" // + "The final silver rupee on the ceiling can be\n" // + "reached by being pulled up into it by the\n" // + "Wallmaster.\n" // + "Then, you must also reach the exit of the room\n" // + "without the use of the Hookshot. If you move\n" // + "quickly, you can sneak past the edge of a\n" // + "flame wall before it can rise up to block you.\n" // + "To do so without taking damage is more precise"; // +string_view LogicGtgFakeWallDesc = "Difficulty: Novice\n" // + "A precise Hover Boots use from the top of the\n" // + "chest can allow you to grab the ledge without\n" // + "needing the usual requirements."; // +string_view LogicLensSpiritDesc = "Difficulty: Novice\n" // + "Removes the requirements for the Lens of Truth in\n" + "Spirit Temple."; // +string_view LogicLensShadowDesc = "Difficulty: Novice\n" // + "Removes the requirements for the Lens of Truth in\n" + "Shadow Temple before the invisible moving platform"; +string_view LogicLensShadowBackDesc = "Difficulty: Intermediate\n" // + "Removes the requirements for the Lens of Truth in\n" + "Shadow Temple beyond the invisible moving platform"; +string_view LogicLensBotwDesc = "Difficulty: Intermediate\n" // + "Removes the requirements for the Lens of Truth in\n" + "Bottom of the Well."; // +string_view LogicLensGtgDesc = "Difficulty: Novice\n" // + "Removes the requirements for the Lens of Truth in\n" + "Gerudo Training Grounds."; // +string_view LogicLensCastleDesc = "Difficulty: Intermediate\n" // + "Removes the requirements for the Lens of Truth in\n" + "Ganon's Castle."; // +string_view LogicLensJabuMQDesc = "Difficulty: Novice\n" // + "Removes the requirements for the Lens of Truth in\n" + "Jabu Jabu's Belly MQ."; // +string_view LogicLensSpiritMQDesc = "Difficulty: Novice\n" // + "Removes the requirements for the Lens of Truth in\n" + "Spirit Temple MQ."; // +string_view LogicLensShadowMQDesc = "Difficulty: Novice\n" // + "Removes the requirements for the Lens of Truth in\n" + "Shadow Temple MQ before the invisible moving \n" // + "platform"; // +string_view LogicLensShadowMQBackDesc = "Difficulty: Intermediate\n" // + "Removes the requirements for the Lens of Truth in\n" + "Shadow Temple MQ beyond the invisible moving \n" // + "platform"; // +string_view LogicLensBotwMQDesc = "Difficulty: Novice\n" // + "Removes the requirements for the Lens of Truth in\n" + "Bottom of the Well MQ."; // +string_view LogicLensGtgMQDesc = "Difficulty: Novice\n" // + "Removes the requirements for the Lens of Truth in\n" + "Gerudo Training Grounds MQ."; // +string_view LogicLensCastleMQDesc = "Difficulty: Intermediate\n" // + "Removes the requirements for the Lens of Truth in\n" + "Ganon's Castle MQ."; // +string_view LogicSpiritTrialHookshotDesc = "Difficulty: Intermediate\n" // + "A precise jump off of an Armos can collect the\n" // + "highest rupee."; // + // +string_view LogicFlamingChestsDesc = "Difficulty: Novice\n" // + "The chests encircled in flames in Gerudo Training\n" + "Grounds and in Spirit Temple can be opened by\n" // + "running into the flames while Link is invincible\n" + "after taking damage."; // + // +/*------------------------------ // +| GLITCHES | // +------------------------------*/ // +const std::vector GlitchDifficulties{"Novice", "Intermediate", "Advanced", "Expert", "Hero"}; // +/* Restricted Items */ // +string_view GlitchRestrictedItemsDescDisabled = "Swapping an item that can normally be used in an\n" + "area with one that would be dimmed will let you\n" + "use that item for 1 frame after closing your\n" // + "inventory. This can be useful on its own or in\n" // + "combination with other glitches."; // +string_view GlitchRestrictedItemsDescNovice = "You may be required to use restricted items."; // +/* Super Stab */ // +string_view GlitchSuperStabDescDisabled = "Forcing sticks to unequip during a crouch stab by\n" + "breaking it and moving them in your inventory has\n" + "the effect of hitting all spherical collision."; // +string_view GlitchSuperStabDescNovice = "You may be expected to hit switches or kill gold\n" + "skulltulas with a super stab."; // +/* ISG */ // +string_view GlitchISGDescDisabled = "Shortened to ISG, allows Link's melee weapon to\n"// + "be in a constant swinging state. Simply touching\n" + "objects with this causes them to get hit.\n" // + "Putting away the weapon while ISG is on hits\n" // + "any object with a spherical hitbox,\n" // + "such as small skulltulas. It is initiated by\n" // + "interrupting a crouch stab."; // +string_view GlitchISGDescNovice = "ISG may be required to kill certain enemies,\n" // + "or to Bomb Hover when enabled."; // +string_view GlitchISGDescIntermediate = "You may be required to use a bomb to activate ISG."; +string_view GlitchISGDescAdvanced = "You may be required to use a bomb to activate ISG\n" + "repeatedly or while under attack."; // +/* Hover */ // +string_view GlitchHoverDescDisabled = "Hovering allows Link to consecutively backflip\n" // + "in the air without falling. By shielding\n" // + "damage with ISG on, Link will stay in midair.\n" // + "While bombs aren't always required, this option\n"// + "will always expect them to be used.\n" // + "\n" // + "Requires ISG to be enabled."; // +string_view GlitchHoverDescNovice = "Only bombchus are required for hovering."; // +string_view GlitchHoverDescIntermediate = "Some hovers may require that you start from flat\n" + "terrain, which requires somewhat precise timing.";// +string_view GlitchHoverDescAdvanced = "Usage of regular bombs will now also be expected,\n" + "which may require consecutive precise timings."; // +/* Bomb OI */ // +string_view GlitchBombOIDescDisabled = "Allowing a bomb to explode in Link's hands while\n" + "moving and then attempting to pull out a cutscene\n" + "item on a specific frame will cause Link to play\n" + "an invisible ocarina instead.\n" // + "This will only work if bombs are not dimmed on the" + "frame you use the cutscene item."; // +string_view GlitchBombOIDescNovice = "You may be expected to use ocarina items with a\n"// + "bomb to play warp songs."; // +string_view GlitchBombOIDescIntermediate = "You may be expected to use ocarina items with a\n"// + "bomb to play the ocarina where Link's position\n" // + "matters."; // +string_view GlitchBombOIDescAdvanced = "You may be expected to use restricted items to use" + "the cutscene item or to make the bombs usable on\n" + "the correct frame."; // +string_view GlitchBombOIDescExpert = "You may be expected to use restricted items to\n" // + "perform ocarina items where Link's position isn't\n" + "particularly lenient"; // +/* Hover Boost */ // +string_view GlitchHoverBoostDescDisabled = "Equipping hover boots when Link takes damage will\n" + "cause him to keep the high knockback speed and\n" // + "lets him traverse large gaps.\n" // + "If performed at the edge of a platform Link will\n" + "instead perform a mega jump which has less range\n" + "but more height than a hover boost."; // +string_view GlitchHoverBoostDescNovice = "Hover boosts that do not need the maximum speed\n"// + "may be required."; // +string_view GlitchHoverBoostDescIntermediate = "Hover boosts that do need the maximum speed may be" + "required."; // +string_view GlitchHoverBoostDescAdvanced = "Hover boosts that use more complex movement during" + "the hover may be required."; // +/* Super Slide */ // +string_view GlitchSuperSlideDescDisabled = "Holding the circle pad just outside the dead zone\n" + "will cause Link to turn on the spot which locks\n"// + "his speed. This can be used to preserve high\n" // + "speeds indefinitely."; // +string_view GlitchSuperSlideDescNovice = "Forward extended super slides (FESSes) where Link\n" + "is damaged by an explosion may be required."; // +string_view GlitchSuperSlideDescIntermediate = "Hammer extended super slides where the recoil from" + "a hammer crouch stab is used may be required."; // +string_view GlitchSuperSlideDescAdvanced = "Hyper Extended Super Slides (HESSes) and\n" // + "damageless FESSes where Link rolls into a bomb may" + "be required."; // +string_view GlitchSuperSlideDescExpert = "HESSes with more precise movement may be required."; +/* Megaflip */ // +string_view GlitchMegaflipDescDisabled = "A backflip or sidehop with high speed from an\n" // + "attack hitting your shield during i-frames. This\n" + "is normally achieved by rolling into an explosion.\n" + "Equipping hover boots to preserve the high speed\n" + "when landing is known as a hoverflip."; // +string_view GlitchMegaflipDescNovice = "You may be expected to perform megaflips on flat\n" + "ground with bombs."; // +string_view GlitchMegaflipDescIntermediate = "You may be expected to perform megaflips in small\n" + "areas, distance megaflips, or hoverflips with a\n"// + "bomb."; // +string_view GlitchMegaflipDescAdvanced = "You may be expected to perform hoverflips with\n" // + "difficult midair movement, or distance megaflips\n" + "under time pressure with a bomb.\n\n" // + "Additionally, you may be expected to perform\n" // + "novice megaflips with a bombchu"; // +string_view GlitchMegaflipDescExpert = "You may be expected to perform intermediate\n" // + "megaflips with a bombchu."; // +string_view GlitchMegaflipDescHero = "You may be expected to perform any megaflip with a" + "bombchu."; // +/* A-Slide */ // +string_view GlitchASlideDescDisabled = "An A-slide is performed the same as a megaflip\n" // + "except without pressing the A button at the end.\n" + "This causes child Link's collision to glitch below" + "the ground and lets him bypass certain actors."; // +string_view GlitchASlideDescNovice = "You may be expected to perform A-slides to pass\n"// + "actors you can't press A to interact with."; // +string_view GlitchASlideDescIntermediate = "You may be expected to perform A-slides quickly or" + "around actors that can be interacted with."; // +string_view GlitchASlideDescAdvanced = "You may be expected to perform novice A-slides\n" // + "with a bombchu."; // +string_view GlitchASlideDescExpert = "You may be expected to perform intermediate\n" // + "A-slides with a bombchu."; +/* Hammer Slide */ // +string_view GlitchHammerSlideDescDisabled = "Equipping hover boots after a hammer crouch stab\n" + "against a wall preserves the recoil speed which\n"// + "allows Link to cross larger gaps than usual."; // +string_view GlitchHammerSlideDescNovice = "Simple hammer slides may be required"; // +string_view GlitchHammerSlideDescIntermediate = "Hammer slides which require good movement and high" + "speed may be required."; // +/* Ledge Cancel */ // +string_view GlitchLedgeCancelDescDisabled = "Climbing a short ledge and shielding damage will\n" + "prevent the ledge climbing state from ending.\n" // + "This state allows Link to walk through some actors" + "such as boulders and NPCs."; // +string_view GlitchLedgeCancelDescNovice = "You may be expected to perform ledge cancels using" + "bombs as a damage source."; // +string_view GlitchLedgeCancelDescIntermediate = "You may be expected to perform ledge cancels in\n"// + "places with little room."; // +string_view GlitchLedgeCancelDescAdvanced = "You may be expected to perform ledge cancels using" + "bombchus as a damage source."; // +/* Action Swap */ // +string_view GlitchActionSwapDescDisabled = "Action swap allows Link to switch between 2 held\n" + "items without the put away/equip animations.\n" // + "This can be exploited to produce various effects."; +string_view GlitchActionSwapDescNovice = "You may be expected to use shallow water to set up" + "action swap."; // +string_view GlitchActionSwapDescAdvanced = "You may be expected to use bombchus to set up\n" // + "action swap."; // +/* QPA */ // +string_view GlitchQPADescDisabled = "Certain events can cancel putting away an item\n" // + "which later lets Link put it away without an\n" // + "animation. This can be used with sticks to access\n" + "a glitched damage value with the properties of\n" // + "hammer and fire arrows, or with a bottle to store\n" + "a cutscene for ocarina items."; // +string_view GlitchQPADescNovice = "You may be expected to get QPA using the boots\n" // + "animation to delay putting away the item and a\n" // + "bomb."; // +string_view GlitchQPADescIntermediate = "You may be expected to get QPA using only a bomb."; +string_view GlitchQPADescAdvanced = "You may be expected to get QPA using a ledge grab\n" + "to interrupt putting away the item."; // +string_view GlitchQPADescExpert = "You may be expected to get QPA from enemy attacks."; +/* Hookshot Clip */ // +string_view GlitchHookshotClipDescDisabled = "Hookshot Clipping allows Link to hookshot through\n" + "certain walls, which is useful if a valid\n" // + "target is on the other side."; // +string_view GlitchHookshotClipDescNovice = "Basic Hookshot Clipping may be required."; // +string_view GlitchHookshotClipDescIntermediate = "Hookshot clips with precise angles and poor\n" // + "visibility may be required."; // +/* Hookshot Jump: Bonk */ // +string_view GlitchHookshotJump_BonkDescDisabled = "A Hookshot Jump is an umbrella term for techniques" + "that launch Link into the sky using the Hookshot\n" + "in various ways, sometimes together with\n" // + "other items. The bonk method only requires the\n" // + "Hookshot itself."; // +string_view GlitchHookshotJump_BonkDescNovice = "Simple hookshot jumps against large flat walls of\n" + "hookshottable surfaces may be required."; // +string_view GlitchHookshotJump_BonkDescIntermediate = "Less lenient hookshot jumps may be required."; // +string_view GlitchHookshotJump_BonkDescAdvanced = "Hookshot jumps with precise midair movement may be" + "required."; // +/* Hookshot Jump: Boots */ // +string_view GlitchHookshotJump_BootsDescDisabled = "This Hookshot Jump technique is one of the easier\n" + "ones, and require any pair of boots."; // +string_view GlitchHookshotJump_BootsDescNovice = "Only relatively short Hookshot Jumps with boots\n"// + "may be required."; // +string_view GlitchHookshotJump_BootsDescIntermediate = "Higher Hookshot Jumps with boots, where you look\n" + "further up or downwards may be required."; // +string_view GlitchHookshotJump_BootsDescAdvanced = "Hookshot jumps that require a lot of height and\n"// + "precise midair movement may be required."; // +/* Cutscene Dives */ // +string_view GlitchCutsceneDiveDescDisabled = "Water physics won't effect Link if he enters the\n" + "water while a cutscene is playing, allowing him\n"// + "to sink to the bottom."; // +string_view GlitchCutsceneDiveDescNovice = "Attempting to use Farore's Wind (when it's already" + "set) with another magic item active prevents the\n" + "water from clearing the FW cutscene until the\n" // + "other effect ends.\n" // + "You may be expected to use Nayru's Love as the\n" // + "other magic effect."; // +string_view GlitchCutsceneDiveDescIntermediate = "You can catch something in a bottle while standing" + "over water using the hover boots to fall through\n" + "the water during the catching cutscene."; // +string_view GlitchCutsceneDiveDescAdvanced = "You may be expected to use magic arrows to perform" + "Farore's Wind cutscene dives."; // +/* Navi Dive: Stick */ // +string_view GlitchNaviDive_StickDescDisabled = "A Navi dive is a type of cutscene dive achieved by" + "falling off a ledge while talking to Navi. While\n" + "the usual method for achieving this is a TSC, it\n" + "is also possible to perform using a jump attack\n"// + "with deku sticks."; // +string_view GlitchNaviDive_StickDescNovice = "You may be expected to enter BotW with a stick\n" // + "Navi dive."; // +string_view GlitchNaviDive_StickDescIntermediate = "You may be expected to use the LH to ZD shortcut\n" + "with a stick Navi dive."; // +string_view GlitchNaviDive_StickDescAdvanced = "You may be expected to use the LW to ZR shortcut\n" + "with a stick Navi dive."; // +/* TSC */ // +string_view GlitchTripleSlashClipDescDisabled = "When doing a three-slash-combo with either the\n" // + "Kokiri Sword or the Master Sword and put it away,\n" + "Link will be placed back a small distance.\n" // + "If, while slashing, you use the recoil of hitting\n" + "a wall and then put away the sword, Link may clip\n" + "into a wall behind him if angled correctly."; // +string_view GlitchTripleSlashClipDescNovice = "Basic Triple Slash Clipping may be required."; // +string_view GlitchTripleSlashClipDescIntermediate = "Some more complex OoB movement may be required."; // +string_view GlitchTripleSlashClipDescAdvanced = "Very precise OoB movement may be required."; // +string_view GlitchTripleSlashClipDescExpert = "Very precise TSCs may be required."; // +/* Ledge Clip */ // +string_view GlitchLedgeClipDescDisabled = "A Ledge Clip allows Link to fall through a floor\n" + "or pass through an object by facing a wall\n" // + "and dropping down to the left in various ways.\n" // + "These only work as an adult."; // +string_view GlitchLedgeClipDescNovice = "Basic Ledge Clips may be required.\n" // + "Some require that you let go of the ledge with\n" // + "a specific timing."; // +string_view GlitchLedgeClipDescIntermediate = "Certain harder clips may also be required."; // +string_view GlitchLedgeClipDescAdvanced = "Ledge clips with complex OoB movement may be\n" // + "required."; // +/* Seam Walk */ // +string_view GlitchSeamWalkDescDisabled = "Where 2 walls come together they form a seam that\n" + "Link can stand on. It is possible to use these to\n" + "gain height and reach normally inaccessible areas.\n" + "Additionally these seams can reach far above the\n" + "walls that form them, creating invisible seams."; // +string_view GlitchSeamWalkDescNovice = "Short seam walks up visible walls with ISG may be\n" + "required."; // +string_view GlitchSeamWalkDescIntermediate = "Short seam walks up visible walls without ISG or\n" + "longer seam walks with ISG may be required."; // +string_view GlitchSeamWalkDescAdvanced = "Longer seam walks without ISG may be required."; // +string_view GlitchSeamWalkDescExpert = "Very precise seam walks may be required."; // +string_view GlitchSeamWalkDescHero = "Crossing Gerudo Valley as child by walking up a\n"// + "wall with the cucco may be required."; // +/* Misc Glitches */ // +string_view GlitchWWTEscapeDesc = "Using deku nuts and the crawlspace to let you\n" // + "move while reading the nearby sign, you can walk\n" + "through the Kokiri guarding the exit. This only\n"// + "affects logic with shuffled entrances."; // +string_view GlitchGVTentAsChildDesc = "The loading zone for the carpenters' tent exists\n" + "in the child map despite the tent being removed.\n\n" + "With this setting enabled you may be expected to\n" + "use that loading zone."; // +string_view GlitchGFGuardSneakDesc = "By using the bow, hookshot, or boomerang while\n" // + "looking up and targeting the Fortress wall, you\n"// + "can walk\n past the guard on the slope without\n" // + "being caught."; // +string_view GlitchItemlessWastelandDesc = "By starting a backwalk and then targeting every\n"// + "other frame Link will maintain backwalk speed\n" // + "over the quicksand in the haunted wasteland which\n" + "lets him cross with no items."; // +string_view GlitchOccamsStatueDesc = "With some precise movement through loading zones\n" + "in Darunia's room, it is possible to unload the\n"// + "collision of the statue blocking the way to DMC.";// +string_view GlitchZDOoBJumpSlashDesc = "Jump slashing the wall next to the pillar above\n"// + "the ZD to LH shortcut as adult will let you clip\n" + "through. From here you can either jump to the shop" + "loading zone or fall OoB a little bit and swim\n" // + "into the shortcut loading zone."; // +string_view GlitchJabuStickRecoilDesc = "Child can enter Jabu without a fish in a bottle\n"// + "using the recoil from breaking a deku stick while\n" + "sidehopping next to the loading zone."; // +string_view GlitchJabuAdultDesc = "Adult can enter Jabu by walking over a specific\n"// + "section of ice on the side near ice cavern."; // +string_view GlitchBlueFireWallDesc = "Pouring blue fire on certain destructable walls\n"// + "will cause them to break."; // +string_view GlitchClassicHalfieDesc = "Dying during a jump attack towards a ledge just\n"// + "too high to climb will put Link on top of the\n" // + "ledge. Combined with a fairy this lets Link climb\n" + "ledges such as the one to the switch in DC."; // +string_view GlitchModernHalfieDesc = "Using a bomb flower and a twisted backflip, it is\n" + "possible to access the switch in DC with only a\n"// + "deku shield and the goron bracelet."; // +string_view GlitchJabuSwitchDesc = "Using a cutscene item the frame you land on the\n"// + "blue switches in Jabu Jabu's Belly will make them\n" + "stay held for a while after you step off them."; // +string_view GlitchForestBKSkipDesc = "Using the hookshot or bow to shorten a backflip\n"// + "it is possible to land on the other side of the\n"// + "railing in the north of the lobby and get clipped\n" + "out of bounds. From here it is possible to jump\n"// + "into the boss loading zone."; // +string_view GlitchFireGrunzClipDesc = "Grabbing a ledge in a corner partially clips Link\n" + "through the wall. A bomb can be used to push Link\n" + "fully through the wall to get out of bounds. This\n" + "can be used in the fire temple along with hover\n"// + "boots to skip hammer in the first room."; // diff --git a/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.hpp b/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.hpp new file mode 100644 index 000000000..396fdd24c --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/setting_descriptions.hpp @@ -0,0 +1,541 @@ +#pragma once +#include +#include + +using string_view = std::string_view; + +extern string_view openRandomize; +extern string_view worldRandomize; +extern string_view shuffleRandomize; +extern string_view dungeonRandomize; + +extern string_view logicGlitchless; +extern string_view logicGlitched; +extern string_view logicNoLogic; +extern string_view logicVanilla; + +extern string_view forestOpen; +extern string_view forestClosed; +extern string_view forestClosedDeku; + +extern string_view kakGateOpen; +extern string_view kakGateClosed; + +extern string_view doorOfTimeOpen; +extern string_view doorOfTimeClosed; +extern string_view doorOfTimeIntended; + +extern string_view fountainNormal; +extern string_view fountainAdult; +extern string_view fountainOpen; + +extern string_view gerudoNormal; +extern string_view gerudoFast; +extern string_view gerudoOpen; + +extern string_view bridgeOpen; +extern string_view bridgeVanilla; +extern string_view bridgeStones; +extern string_view bridgeMedallions; +extern string_view bridgeRewards; +extern string_view bridgeDungeons; +extern string_view bridgeTokens; + +extern string_view bridgeStoneCountDesc; +extern string_view bridgeMedallionCountDesc; +extern string_view bridgeRewardCountDesc; +extern string_view bridgeDungeonCountDesc; +extern string_view bridgeTokenCountDesc; + +extern string_view randomGanonsTrialsDesc; + +extern string_view ganonsTrialCountDesc; + +extern string_view ageDesc; + +extern string_view shuffleEntrancesDesc; + +extern string_view dungeonEntrancesDesc; + +extern string_view overworldEntrancesDesc; + +extern string_view grottoEntrancesDesc; + +extern string_view interiorEntrancesOff; +extern string_view interiorEntrancesSimple; +extern string_view interiorEntrancesAll; + +extern string_view bombchuLogicDesc; + +extern string_view defaultAmmoDropsDesc; +extern string_view bombchuDropsDesc; +extern string_view noAmmoDropsDesc; + +extern string_view defaultHeartDropsDesc; +extern string_view noHeartDropsDesc; +extern string_view noHeartRefillDesc; +extern string_view scarceHeartsDesc; + +extern string_view mqDungeonCountDesc; +extern string_view setDungeonTypesDesc; + +extern string_view shuffleRewardsEndOfDungeon; +extern string_view shuffleRewardsAnyDungeon; +extern string_view shuffleRewardsOverworld; +extern string_view shuffleRewardsAnywhere; + +extern string_view linksPocketDungeonReward; +extern string_view linksPocketAdvancement; +extern string_view linksPocketAnything; +extern string_view linksPocketNothing; + +extern string_view songsSongLocations; +extern string_view songsDungeonRewards; +extern string_view songsAllLocations; + +extern string_view shopsOff; +extern string_view shopsZero; +extern string_view shopsOne; +extern string_view shopsTwo; +extern string_view shopsThree; +extern string_view shopsFour; +extern string_view shopsRandom; + +extern string_view tokensOff; +extern string_view tokensDungeon; +extern string_view tokensOverworld; +extern string_view tokensAllTokens; + +extern string_view scrubsOff; +extern string_view scrubsAffordable; +extern string_view scrubsExpensive; +extern string_view scrubsRandomPrices; + +extern string_view shuffleCowsDesc; + +extern string_view kokiriSwordDesc; + +extern string_view ocarinasDesc; + +extern string_view weirdEggDesc; + +extern string_view gerudoTokenDesc; + +extern string_view magicBeansDesc; + +extern string_view merchantsDesc; +extern string_view merchantsHintsDesc; + +extern string_view adultTradeDesc; + +extern string_view chestMinigameDesc; + +extern string_view mapCompassStartWith; +extern string_view mapCompassVanilla; +extern string_view mapCompassOwnDungeon; +extern string_view mapCompassAnyDungeon; +extern string_view mapCompassOverworld; +extern string_view mapCompassAnywhere; + +extern string_view smallKeyStartWith; +extern string_view smallKeyVanilla; +extern string_view smallKeyOwnDungeon; +extern string_view smallKeyAnyDungeon; +extern string_view smallKeyOverworld; +extern string_view smallKeyAnywhere; + +extern string_view gerudoKeysVanilla; +extern string_view gerudoKeysAnyDungeon; +extern string_view gerudoKeysOverworld; +extern string_view gerudoKeysAnywhere; + +extern string_view keyRingDesc; + +extern string_view bossKeyStartWith; +extern string_view bossKeyVanilla; +extern string_view bossKeyOwnDungeon; +extern string_view bossKeyAnyDungeon; +extern string_view bossKeyOverworld; +extern string_view bossKeyAnywhere; + +extern string_view ganonKeyStartWith; +extern string_view ganonKeyVanilla; +extern string_view ganonKeyOwnDungeon; +extern string_view ganonKeyAnyDungeon; +extern string_view ganonKeyOverworld; +extern string_view ganonKeyAnywhere; +extern string_view ganonKeyLACS; + +extern string_view lacsMedallionCountDesc; +extern string_view lacsStoneCountDesc; +extern string_view lacsRewardCountDesc; +extern string_view lacsDungeonCountDesc; +extern string_view lacsTokenCountDesc; + +extern string_view childStealthDesc; + +extern string_view skipTowerEscapeDesc; + +extern string_view skipEponaRaceDesc; + +extern string_view skipMinigamePhasesDesc; + +extern string_view freeScarecrowDesc; + +extern string_view fourPoesDesc; + +extern string_view lakeHyliaOwlDesc; + +extern string_view bigPoeTargetCountDesc; + +extern string_view numRequiredCuccosDesc; + +extern string_view kingZoraSpeedFast; +extern string_view kingZoraSpeedVanilla; +extern string_view kingZoraSpeedRandom; + +extern string_view completeMaskDesc; + +extern string_view quickTextDesc0; +extern string_view quickTextDesc1; +extern string_view quickTextDesc2; +extern string_view quickTextDesc3; +extern string_view skipSongReplaysDesc; + +extern string_view keepFWWarpPointDesc; + +extern string_view fastBunnyHoodDesc; + +extern string_view gossipStonesHintsDesc; + +extern string_view obscureHintsDesc; +extern string_view ambiguousHintsDesc; +extern string_view clearHintsDesc; + +extern string_view uselessHintsDesc; +extern string_view balancedHintsDesc; +extern string_view strongHintsDesc; +extern string_view veryStrongHintsDesc; + +extern string_view compassesShowRewardsDesc; +extern string_view compassesShowWotHDesc; +extern string_view mapsShowDungeonModesDesc; + +extern string_view damageMultiDesc; + +extern string_view startingTimeDesc; + +extern string_view locationsReachableDesc; +extern string_view nightGSDesc; + +extern string_view chestAnimDesc; + +extern string_view chestSizeDesc; + +extern string_view ingameSpoilersShowDesc; +extern string_view ingameSpoilersHideDesc; + +extern string_view menuButtonDesc; + +extern string_view startWithConsumablesDesc; + +extern string_view startWithMaxRupeesDesc; + +extern string_view itemPoolPlentiful; +extern string_view itemPoolBalanced; +extern string_view itemPoolScarce; +extern string_view itemPoolMinimal; + +extern string_view iceTrapsOff; +extern string_view iceTrapsNormal; +extern string_view iceTrapsExtra; +extern string_view iceTrapsMayhem; +extern string_view iceTrapsOnslaught; + +extern string_view removeDDDesc; + +extern string_view progGoronSword; + +extern string_view faroresWindAnywhereDesc; + +extern string_view ageRestrictionsDesc; +extern string_view adultStickDesc; +extern string_view adultBoomerangDesc; +extern string_view childHammerDesc; +extern string_view adultSlingshotDesc; +extern string_view childBowDesc; +extern string_view childHookshotDesc; +extern string_view childIronBootsDesc; +extern string_view childHoverBootsDesc; +extern string_view adultMasksDesc; +extern string_view adultKokiriSwordDesc; +extern string_view childMasterSwordDesc; +extern string_view childBiggoronSwordDesc; +extern string_view adultDekuShieldDesc; +extern string_view childMirrorShieldDesc; +extern string_view childGoronTunicDesc; +extern string_view childZoraTunicDesc; + +extern string_view gkDurabilityVanilla; +extern string_view gkDurabilityRandomRisk; +extern string_view gkDurabilityRandomSafe; + +extern string_view mp_EnabledDesc; +extern string_view mp_SharedProgressDesc; +extern string_view mp_SyncIdDesc; +extern string_view mp_SharedHealthDesc; +extern string_view mp_SharedRupeesDesc; +extern string_view mp_SharedAmmoDesc; + +extern string_view zTargetingDesc; +extern string_view cameraControlDesc; +extern string_view motionControlDesc; +extern string_view togglePlayMusicDesc; +extern string_view togglePlaySFXDesc; +extern string_view silenceNaviDesc; +extern string_view ignoreMaskReactionDesc; + +extern string_view naviColorsDesc; +extern string_view necessarySimpleModeDesc; +extern string_view alwaysSimpleModeDesc; + +extern string_view coloredKeysDesc; +extern string_view coloredBossKeysDesc; + +extern string_view mirrorWorldDesc; + +extern string_view musicRandoDesc; +extern string_view shuffleBGMDesc; +extern string_view fanfaresOffDesc; +extern string_view onlyFanfaresDesc; +extern string_view fanfaresOcarinaDesc; +extern string_view shuffleOcaMusicDesc; + +extern string_view shuffleSFXOff; +extern string_view shuffleSFXAll; +extern string_view shuffleSFXSceneSpecific; +extern string_view shuffleSFXChaos; +extern string_view shuffleSFXCategorically; + +extern string_view randomTrapDmgDesc; +extern string_view basicTrapDmgDesc; +extern string_view advancedTrapDmgDesc; + +extern string_view ToggleAllTricksDesc; + +extern string_view ToggleLogicNoneDesc; +extern string_view ToggleLogicNoviceDesc; +extern string_view ToggleLogicIntermediateDesc; +extern string_view ToggleLogicExpertDesc; +extern string_view LogicGrottosWithoutAgonyDesc; +extern string_view LogicVisibleCollisionDesc; +extern string_view LogicFewerTunicRequirementsDesc; +extern string_view LogicLostWoodsGSBeanDesc; +extern string_view LogicLabDivingDesc; +extern string_view LogicLabWallGSDesc; +extern string_view LogicGraveyardPoHDesc; +extern string_view LogicChildDampeRacePoHDesc; +extern string_view LogicGVHammerChestDesc; +extern string_view LogicGerudoKitchenDesc; +extern string_view LogicLensWastelandDesc; +extern string_view LogicReverseWastelandDesc; +extern string_view LogicColossusGSDesc; +extern string_view LogicOutsideGanonsGSDesc; +extern string_view LogicManOnRoofDesc; +extern string_view LogicWindmillPoHHookshotDesc; +extern string_view LogicDMTBombableDesc; +extern string_view LogicDMTSoilGSDesc; +extern string_view LogicDMTSummitHoverDesc; +extern string_view LogicLinkGoronDinsDesc; +extern string_view LogicGoronCityLeftMostDesc; +extern string_view LogicGoronCityPotDesc; +extern string_view LogicGoronCityPotWithStrengthDesc; +extern string_view LogicChildRollingWithStrengthDesc; +extern string_view LogicCraterUpperToLowerDesc; +extern string_view LogicCraterBeanPoHWithHoversDesc; +extern string_view LogicBiggoronBoleroDesc; +extern string_view LogicZoraRiverLowerDesc; +extern string_view LogicZoraRiverUpperDesc; +extern string_view LogicZFGreatFairyDesc; +extern string_view LogicDekuB1WebsWithBowDesc; +extern string_view LogicDekuB1SkipDesc; +extern string_view LogicDekuBasementGSDesc; +extern string_view LogicDCStaircaseDesc; +extern string_view LogicDCJumpDesc; +extern string_view LogicDCSlingshotSkipDesc; +extern string_view LogicDCScarecrowGSDesc; +extern string_view LogicJabuBossGSAdultDesc; +extern string_view LogicJabuScrubJumpDiveDesc; +extern string_view LogicForestOutsideBackdoorDesc; +extern string_view LogicForestDoorFrameDesc; +extern string_view LogicForestOutdoorEastGSDesc; +extern string_view LogicFireBossDoorJumpDesc; +extern string_view LogicFireStrengthDesc; +extern string_view LogicFireScarecrowDesc; +extern string_view LogicFireFlameMazeDesc; +extern string_view LogicFireSongOfTimeDesc; +extern string_view LogicWaterTempleTorchLongshotDesc; +extern string_view LogicWaterTempleUpperBoostDesc; +extern string_view LogicWaterCentralBowDesc; +extern string_view LogicWaterCentralGSFWDesc; +extern string_view LogicWaterCrackedWallNothingDesc; +extern string_view LogicWaterCrackedWallHoversDesc; +extern string_view LogicWaterBossKeyRegionDesc; +extern string_view LogicWaterBKJumpDiveDesc; +extern string_view LogicWaterNorthBasementLedgeJumpDesc; +extern string_view LogicWaterDragonAdultDesc; +extern string_view LogicWaterDragonJumpDiveDesc; +extern string_view LogicWaterRiverGSDesc; +extern string_view LogicWaterFallingPlatformGSDesc; +extern string_view LogicSpiritLowerAdultSwitchDesc; +extern string_view LogicSpiritChildBombchuDesc; +extern string_view LogicSpiritWallDesc; +extern string_view LogicSpiritLobbyGSDesc; +extern string_view LogicSpiritMapChestDesc; +extern string_view LogicSpiritSunChestDesc; +extern string_view LogicShadowFireArrowEntryDesc; +extern string_view LogicShadowUmbrellaDesc; +extern string_view LogicShadowFreestandingKeyDesc; +extern string_view LogicShadowStatueDesc; +extern string_view LogicChildDeadhandDesc; +extern string_view LogicGtgWithoutHookshotDesc; +extern string_view LogicGtgFakeWallDesc; +extern string_view LogicLensSpiritDesc; +extern string_view LogicLensShadowDesc; +extern string_view LogicLensShadowBackDesc; +extern string_view LogicLensBotwDesc; +extern string_view LogicLensGtgDesc; +extern string_view LogicLensCastleDesc; +extern string_view LogicLensJabuMQDesc; +extern string_view LogicLensSpiritMQDesc; +extern string_view LogicLensShadowMQDesc; +extern string_view LogicLensShadowMQBackDesc; +extern string_view LogicLensBotwMQDesc; +extern string_view LogicLensGtgMQDesc; +extern string_view LogicLensCastleMQDesc; +extern string_view LogicSpiritTrialHookshotDesc; +extern string_view LogicFlamingChestsDesc; + +extern const std::vector GlitchDifficulties; + +extern string_view GlitchRestrictedItemsDescDisabled; +extern string_view GlitchRestrictedItemsDescNovice; + +extern string_view GlitchSuperStabDescDisabled; +extern string_view GlitchSuperStabDescNovice; + +extern string_view GlitchISGDescDisabled; +extern string_view GlitchISGDescNovice; +extern string_view GlitchISGDescIntermediate; +extern string_view GlitchISGDescAdvanced; + +extern string_view GlitchHoverDescDisabled; +extern string_view GlitchHoverDescNovice; +extern string_view GlitchHoverDescIntermediate; +extern string_view GlitchHoverDescAdvanced; + +extern string_view GlitchBombOIDescDisabled; +extern string_view GlitchBombOIDescNovice; +extern string_view GlitchBombOIDescIntermediate; +extern string_view GlitchBombOIDescAdvanced; +extern string_view GlitchBombOIDescExpert; + +extern string_view GlitchHoverBoostDescDisabled; +extern string_view GlitchHoverBoostDescNovice; +extern string_view GlitchHoverBoostDescIntermediate; +extern string_view GlitchHoverBoostDescAdvanced; + +extern string_view GlitchSuperSlideDescDisabled; +extern string_view GlitchSuperSlideDescNovice; +extern string_view GlitchSuperSlideDescIntermediate; +extern string_view GlitchSuperSlideDescAdvanced; +extern string_view GlitchSuperSlideDescExpert; + +extern string_view GlitchMegaflipDescDisabled; +extern string_view GlitchMegaflipDescNovice; +extern string_view GlitchMegaflipDescIntermediate; +extern string_view GlitchMegaflipDescAdvanced; +extern string_view GlitchMegaflipDescExpert; +extern string_view GlitchMegaflipDescHero; + +extern string_view GlitchASlideDescDisabled; +extern string_view GlitchASlideDescNovice; +extern string_view GlitchASlideDescIntermediate; +extern string_view GlitchASlideDescAdvanced; +extern string_view GlitchASlideDescExpert; + +extern string_view GlitchHammerSlideDescDisabled; +extern string_view GlitchHammerSlideDescNovice; +extern string_view GlitchHammerSlideDescIntermediate; + +extern string_view GlitchLedgeCancelDescDisabled; +extern string_view GlitchLedgeCancelDescNovice; +extern string_view GlitchLedgeCancelDescIntermediate; +extern string_view GlitchLedgeCancelDescAdvanced; + +extern string_view GlitchActionSwapDescDisabled; +extern string_view GlitchActionSwapDescNovice; +extern string_view GlitchActionSwapDescAdvanced; + +extern string_view GlitchQPADescDisabled; +extern string_view GlitchQPADescNovice; +extern string_view GlitchQPADescIntermediate; +extern string_view GlitchQPADescAdvanced; +extern string_view GlitchQPADescExpert; + +extern string_view GlitchHookshotClipDescDisabled; +extern string_view GlitchHookshotClipDescNovice; +extern string_view GlitchHookshotClipDescIntermediate; + +extern string_view GlitchHookshotJump_BonkDescDisabled; +extern string_view GlitchHookshotJump_BonkDescNovice; +extern string_view GlitchHookshotJump_BonkDescIntermediate; +extern string_view GlitchHookshotJump_BonkDescAdvanced; + +extern string_view GlitchHookshotJump_BootsDescDisabled; +extern string_view GlitchHookshotJump_BootsDescNovice; +extern string_view GlitchHookshotJump_BootsDescIntermediate; +extern string_view GlitchHookshotJump_BootsDescAdvanced; + +extern string_view GlitchCutsceneDiveDescDisabled; +extern string_view GlitchCutsceneDiveDescNovice; +extern string_view GlitchCutsceneDiveDescIntermediate; +extern string_view GlitchCutsceneDiveDescAdvanced; + +extern string_view GlitchNaviDive_StickDescDisabled; +extern string_view GlitchNaviDive_StickDescNovice; +extern string_view GlitchNaviDive_StickDescIntermediate; +extern string_view GlitchNaviDive_StickDescAdvanced; + +extern string_view GlitchTripleSlashClipDescDisabled; +extern string_view GlitchTripleSlashClipDescNovice; +extern string_view GlitchTripleSlashClipDescIntermediate; +extern string_view GlitchTripleSlashClipDescAdvanced; +extern string_view GlitchTripleSlashClipDescExpert; + +extern string_view GlitchLedgeClipDescDisabled; +extern string_view GlitchLedgeClipDescNovice; +extern string_view GlitchLedgeClipDescIntermediate; +extern string_view GlitchLedgeClipDescAdvanced; + +extern string_view GlitchSeamWalkDescDisabled; +extern string_view GlitchSeamWalkDescNovice; +extern string_view GlitchSeamWalkDescIntermediate; +extern string_view GlitchSeamWalkDescAdvanced; +extern string_view GlitchSeamWalkDescExpert; +extern string_view GlitchSeamWalkDescHero; + +extern string_view GlitchWWTEscapeDesc; +extern string_view GlitchGVTentAsChildDesc; +extern string_view GlitchGFGuardSneakDesc; +extern string_view GlitchItemlessWastelandDesc; +extern string_view GlitchOccamsStatueDesc; +extern string_view GlitchZDOoBJumpSlashDesc; +extern string_view GlitchJabuStickRecoilDesc; +extern string_view GlitchJabuAdultDesc; +extern string_view GlitchBlueFireWallDesc; +extern string_view GlitchClassicHalfieDesc; +extern string_view GlitchModernHalfieDesc; +extern string_view GlitchJabuSwitchDesc; +extern string_view GlitchForestBKSkipDesc; +extern string_view GlitchFireGrunzClipDesc; diff --git a/soh/soh/Enhancements/randomizer/3drando/settings.cpp b/soh/soh/Enhancements/randomizer/3drando/settings.cpp new file mode 100644 index 000000000..05fc10c4b --- /dev/null +++ b/soh/soh/Enhancements/randomizer/3drando/settings.cpp @@ -0,0 +1,2779 @@ +#include "settings.hpp" + +#include "cosmetics.hpp" +#include "dungeon.hpp" +#include "fill.hpp" +#include "item_location.hpp" +#include "music.hpp" +#include "sound_effects.hpp" +#include "random.hpp" +#include "randomizer.hpp" +#include "setting_descriptions.hpp" +#include "trial.hpp" +#include "keys.hpp" + +using namespace Cosmetics; +using namespace Dungeon; +using namespace Trial; +using namespace Music; +using namespace SFX; + +namespace Settings { + std::string seed; + std::string version = RANDOMIZER_VERSION "-" COMMIT_NUMBER; + std::array hashIconIndexes; + + bool skipChildZelda = false; + + std::vector NumOpts(int min, int max, int step = 1, std::string textBefore = {}, std::string textAfter = {}) { + std::vector options; + options.reserve((max - min) / step + 1); + for (int i = min; i <= max; i += step) { + options.push_back(textBefore + std::to_string(i) + textAfter); + } + return options; + } + + std::vector MultiVecOpts(std::vector> optionsVector) { + uint32_t totalSize = 0; + for (auto vector : optionsVector) { + totalSize += vector.size(); + } + std::vector options; + options.reserve(totalSize); + for (auto vector : optionsVector) { + for (auto op : vector) { + options.push_back(op); + } + } + return options; + } + + // Setting name, Options, Setting Descriptions (assigned in setting_descriptions.cpp) Category (default: Setting),Default index (default: 0), Default hidden (default: false) + //Open Settings Any option index past the last description will use the last description + Option RandomizeOpen = Option::Bool("Randomize Settings", {"No","Yes"}, {openRandomize}, OptionCategory::Toggle); + Option OpenForest = Option::U8 ("Forest", {"Closed", "Open", "Closed Deku"}, {forestClosed, forestOpen, forestClosedDeku}, OptionCategory::Setting, OPENFOREST_OPEN); + Option OpenKakariko = Option::U8 ("Kakariko Gate", {"Closed", "Open"}, {kakGateClosed, kakGateOpen}); + Option OpenDoorOfTime = Option::U8 ("Door of Time", {"Open", "Closed", "Intended"}, {doorOfTimeOpen, doorOfTimeClosed, doorOfTimeIntended}); + Option ZorasFountain = Option::U8 ("Zora's Fountain", {"Normal", "Adult", "Open"}, {fountainNormal, fountainAdult, fountainOpen}); + Option GerudoFortress = Option::U8 ("Gerudo Fortress", {"Normal", "Fast", "Open"}, {gerudoNormal, gerudoFast, gerudoOpen}); + Option Bridge = Option::U8 ("Rainbow Bridge", {"Open", "Vanilla", "Stones", "Medallions", "Rewards", "Dungeons", "Tokens"}, {bridgeOpen, bridgeVanilla, bridgeStones, bridgeMedallions, bridgeRewards, bridgeDungeons, bridgeTokens}, OptionCategory::Setting, RAINBOWBRIDGE_VANILLA); + Option BridgeStoneCount = Option::U8 (" Stone Count", {NumOpts(0, 3)}, {bridgeStoneCountDesc}, OptionCategory::Setting, 1, true); + Option BridgeMedallionCount= Option::U8 (" Medallion Count", {NumOpts(0, 6)}, {bridgeMedallionCountDesc}, OptionCategory::Setting, 1, true); + Option BridgeRewardCount = Option::U8 (" Reward Count", {NumOpts(0, 9)}, {bridgeRewardCountDesc}, OptionCategory::Setting, 1, true); + Option BridgeDungeonCount = Option::U8 (" Dungeon Count", {NumOpts(0, 8)}, {bridgeDungeonCountDesc}, OptionCategory::Setting, 1, true); + Option BridgeTokenCount = Option::U8 (" Token Count", {NumOpts(0, 100)}, {bridgeTokenCountDesc}, OptionCategory::Setting, 1, true); + Option RandomGanonsTrials = Option::Bool("Random Ganon's Trials", {"Off", "On"}, {randomGanonsTrialsDesc}, OptionCategory::Setting, ON); + Option GanonsTrialsCount = Option::U8 (" Trial Count", {NumOpts(0, 6)}, {ganonsTrialCountDesc}, OptionCategory::Setting, 1, true); + std::vector