From 4e8ccce002ce1503887891cabc7577678bc95c5a Mon Sep 17 00:00:00 2001 From: Archez Date: Sat, 11 Jan 2025 00:33:19 -0500 Subject: [PATCH 01/26] Move Window calls to portside (#4833) * Move LUS window calls to portside * move dropped frame handling to port side * Use fast3d all in one draw * bump to upstream lus --- libultraship | 2 +- soh/soh/OTRGlobals.cpp | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/libultraship b/libultraship index 3e46fe77a..7fc73766e 160000 --- a/libultraship +++ b/libultraship @@ -1 +1 @@ -Subproject commit 3e46fe77a4581a84f9c0edfab9c3a69a5320fe01 +Subproject commit 7fc73766ed4c636b49e2218d948100ee7782456e diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 636687b33..7856de88f 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -1355,14 +1355,20 @@ extern "C" void Graph_StartFrame() { CVarClear(CVAR_NEW_FILE_DROPPED); CVarClear(CVAR_DROPPED_FILE); } - - OTRGlobals::Instance->context->GetWindow()->StartFrame(); } void RunCommands(Gfx* Commands, const std::vector>& mtx_replacements) { + auto wnd = std::dynamic_pointer_cast(OTRGlobals::Instance->context->GetWindow()); + + if (wnd == nullptr) { + return; + } + + // Process window events for resize, mouse, keyboard events + wnd->HandleEvents(); + for (const auto& m : mtx_replacements) { - gfx_run(Commands, m); - gfx_end_frame(); + wnd->DrawAndRunGraphicsCommands(Commands, m); } } From 8dc2b0cec2dc161b10ead9947156fdaa0c96f12a Mon Sep 17 00:00:00 2001 From: Pepper0ni <93387759+Pepper0ni@users.noreply.github.com> Date: Sat, 11 Jan 2025 06:13:04 +0000 Subject: [PATCH 02/26] fix a few default cutscene settings (#4834) --- soh/soh/Enhancements/timesaver_hook_handlers.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/soh/soh/Enhancements/timesaver_hook_handlers.cpp b/soh/soh/Enhancements/timesaver_hook_handlers.cpp index 85e0f0420..5a19feabc 100644 --- a/soh/soh/Enhancements/timesaver_hook_handlers.cpp +++ b/soh/soh/Enhancements/timesaver_hook_handlers.cpp @@ -550,7 +550,7 @@ void TimeSaverOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li break; } case VB_PLAY_GORON_FREE_CS: { - if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), 0)) { + if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), IS_RANDO)) { *should = false; } break; @@ -565,7 +565,7 @@ void TimeSaverOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li break; } case VB_PLAY_FIRE_ARROW_CS: { - if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions"), 0)) { + if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipMiscInteractions"), IS_RANDO)) { *should = false; } break; @@ -903,7 +903,7 @@ void TimeSaverOnActorInitHandler(void* actorRef) { // or poes from which the cutscene is triggered until we can have a "BeforeActorInit" hook. // So for now we're just going to set the flag before they get to the room the cutscene is in if (gPlayState->sceneNum == SCENE_FOREST_TEMPLE && actor->id == ACTOR_EN_ST && !Flags_GetSwitch(gPlayState, 0x1B) && !Flags_GetSwitch(gPlayState, 0x1C)) { - if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), 0) && !CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.GlitchAiding"), 0)) { + if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), IS_RANDO) && !CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.GlitchAiding"), 0)) { Flags_SetSwitch(gPlayState, 0x1B); } } @@ -929,7 +929,7 @@ void TimeSaverOnActorInitHandler(void* actorRef) { // Fire Temple Darunia cutscene if (actor->id == ACTOR_EN_DU && gPlayState->sceneNum == SCENE_FIRE_TEMPLE) { - if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), 0) && !CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.GlitchAiding"), 0)) { + if (CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.Story"), IS_RANDO) && !CVarGetInteger(CVAR_ENHANCEMENT("TimeSavers.SkipCutscene.GlitchAiding"), 0)) { Flags_SetInfTable(INFTABLE_SPOKE_TO_DARUNIA_IN_FIRE_TEMPLE); Actor_Kill(actor); } From 3b26bd04025057e05fc98ffbb6468efd4ceebcc2 Mon Sep 17 00:00:00 2001 From: Fredrik Andreasson Date: Sat, 11 Jan 2025 07:14:31 +0100 Subject: [PATCH 03/26] Fix Mido without Emerald softlock (#4824) * * fixes softlock when talking to Mido without Kokiri Emerald after killing Gohma * * moved scene check to hook * moved vanilla conditioon into GameInteractor_Should * * corrected hook condition * removed 'this' * * reverted GameInteractor and hook_handlers * changed actor to use existing hook * * updated kokiri emerald conditions * * missed parentheses --- soh/src/overlays/actors/ovl_En_Md/z_en_md.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/soh/src/overlays/actors/ovl_En_Md/z_en_md.c b/soh/src/overlays/actors/ovl_En_Md/z_en_md.c index eaa8d9b2d..27e8fcdf2 100644 --- a/soh/src/overlays/actors/ovl_En_Md/z_en_md.c +++ b/soh/src/overlays/actors/ovl_En_Md/z_en_md.c @@ -618,13 +618,13 @@ void func_80AAB5A4(EnMd* this, PlayState* play) { if (play->sceneNum != SCENE_MIDOS_HOUSE) { if (CVarGetInteger(CVAR_ENHANCEMENT("DisableKokiriDrawDistance"), 0) != 0) { - temp = (CHECK_QUEST_ITEM(QUEST_KOKIRI_EMERALD) && !Flags_GetEventChkInf(EVENTCHKINF_SPOKE_TO_MIDO_AFTER_DEKU_TREES_DEATH) && - (play->sceneNum == SCENE_KOKIRI_FOREST)) + temp = (GameInteractor_Should(VB_MIDO_CONSIDER_DEKU_TREE_DEAD, CHECK_QUEST_ITEM(QUEST_KOKIRI_EMERALD)) && + !Flags_GetEventChkInf(EVENTCHKINF_SPOKE_TO_MIDO_AFTER_DEKU_TREES_DEATH) && (play->sceneNum == SCENE_KOKIRI_FOREST)) ? 100.0f : 32767.0f; } else { - temp = (CHECK_QUEST_ITEM(QUEST_KOKIRI_EMERALD) && !Flags_GetEventChkInf(EVENTCHKINF_SPOKE_TO_MIDO_AFTER_DEKU_TREES_DEATH) && - (play->sceneNum == SCENE_KOKIRI_FOREST)) + temp = (GameInteractor_Should(VB_MIDO_CONSIDER_DEKU_TREE_DEAD, CHECK_QUEST_ITEM(QUEST_KOKIRI_EMERALD)) && + !Flags_GetEventChkInf(EVENTCHKINF_SPOKE_TO_MIDO_AFTER_DEKU_TREES_DEATH) && (play->sceneNum == SCENE_KOKIRI_FOREST)) ? 100.0f : 400.0f; } @@ -661,7 +661,7 @@ void EnMd_Init(Actor* thisx, PlayState* play) { if (((play->sceneNum == SCENE_KOKIRI_FOREST) && !Flags_GetEventChkInf(EVENTCHKINF_SHOWED_MIDO_SWORD_SHIELD)) || ((play->sceneNum == SCENE_KOKIRI_FOREST) && Flags_GetEventChkInf(EVENTCHKINF_SHOWED_MIDO_SWORD_SHIELD) && - CHECK_QUEST_ITEM(QUEST_KOKIRI_EMERALD)) || + GameInteractor_Should(VB_MIDO_CONSIDER_DEKU_TREE_DEAD, CHECK_QUEST_ITEM(QUEST_KOKIRI_EMERALD))) || ((play->sceneNum == SCENE_LOST_WOODS) && !Flags_GetEventChkInf(EVENTCHKINF_PLAYED_SARIAS_SONG_FOR_MIDO_AS_ADULT))) { this->actor.home.pos = this->actor.world.pos; this->actionFunc = func_80AAB948; @@ -727,8 +727,8 @@ void func_80AAB948(EnMd* this, PlayState* play) { (GameInteractor_Should(VB_MOVE_MIDO_IN_KOKIRI_FOREST, this->interactInfo.talkState == NPC_TALK_STATE_ACTION, this) && play->sceneNum == SCENE_KOKIRI_FOREST) || this->interactInfo.talkState == NPC_TALK_STATE_ACTION ) { - if (CHECK_QUEST_ITEM(QUEST_KOKIRI_EMERALD) && !Flags_GetEventChkInf(EVENTCHKINF_SPOKE_TO_MIDO_AFTER_DEKU_TREES_DEATH) && - (play->sceneNum == SCENE_KOKIRI_FOREST)) { + if (GameInteractor_Should(VB_MIDO_CONSIDER_DEKU_TREE_DEAD, CHECK_QUEST_ITEM(QUEST_KOKIRI_EMERALD)) && + !Flags_GetEventChkInf(EVENTCHKINF_SPOKE_TO_MIDO_AFTER_DEKU_TREES_DEATH) && (play->sceneNum == SCENE_KOKIRI_FOREST)) { play->msgCtx.msgMode = MSGMODE_PAUSED; } @@ -794,8 +794,10 @@ void func_80AABD0C(EnMd* this, PlayState* play) { return; } - if (CHECK_QUEST_ITEM(QUEST_KOKIRI_EMERALD) && !Flags_GetEventChkInf(EVENTCHKINF_SPOKE_TO_MIDO_AFTER_DEKU_TREES_DEATH) && - (play->sceneNum == SCENE_KOKIRI_FOREST)) { + if ( + GameInteractor_Should(VB_MIDO_CONSIDER_DEKU_TREE_DEAD, CHECK_QUEST_ITEM(QUEST_KOKIRI_EMERALD)) && + !Flags_GetEventChkInf(EVENTCHKINF_SPOKE_TO_MIDO_AFTER_DEKU_TREES_DEATH) && (play->sceneNum == SCENE_KOKIRI_FOREST) + ) { Message_CloseTextbox(play); Flags_SetEventChkInf(EVENTCHKINF_SPOKE_TO_MIDO_AFTER_DEKU_TREES_DEATH); Actor_Kill(&this->actor); From 6a5e5e2a75eb579cfa063074a11a57ef6a6b60f5 Mon Sep 17 00:00:00 2001 From: briaguya <70942617+briaguya-ai@users.noreply.github.com> Date: Sat, 11 Jan 2025 02:02:05 -0500 Subject: [PATCH 04/26] imgui 1.90.6 -> 1.91.6 (#4838) --- libultraship | 2 +- soh/soh/Enhancements/audio/AudioEditor.h | 3 - soh/soh/Enhancements/controls/InputViewer.cpp | 3 - .../controls/SohInputEditorWindow.h | 3 - soh/soh/Enhancements/debugconsole.cpp | 3 - .../Enhancements/debugger/debugSaveEditor.cpp | 56 +++++++++++++------ .../Enhancements/randomizer/Plandomizer.cpp | 56 +++++++++++++------ .../Enhancements/randomizer/randomizer.cpp | 3 - .../Enhancements/timesplits/TimeSplits.cpp | 35 ++++++++---- soh/soh/ImGuiUtils.h | 3 - soh/soh/SohGui.cpp | 3 - soh/soh/SohMenuBar.cpp | 3 - soh/soh/UIWidgets.cpp | 14 +++-- soh/soh/UIWidgets.hpp | 3 - 14 files changed, 113 insertions(+), 77 deletions(-) diff --git a/libultraship b/libultraship index 7fc73766e..9a974e002 160000 --- a/libultraship +++ b/libultraship @@ -1 +1 @@ -Subproject commit 7fc73766ed4c636b49e2218d948100ee7782456e +Subproject commit 9a974e002f84cd1fe834ee9d2fa4ccf16d899e0f diff --git a/soh/soh/Enhancements/audio/AudioEditor.h b/soh/soh/Enhancements/audio/AudioEditor.h index 93ae3c440..b1b034f24 100644 --- a/soh/soh/Enhancements/audio/AudioEditor.h +++ b/soh/soh/Enhancements/audio/AudioEditor.h @@ -4,9 +4,6 @@ #ifdef __cplusplus #include -#ifndef IMGUI_DEFINE_MATH_OPERATORS -#define IMGUI_DEFINE_MATH_OPERATORS -#endif #include #include "AudioCollection.h" diff --git a/soh/soh/Enhancements/controls/InputViewer.cpp b/soh/soh/Enhancements/controls/InputViewer.cpp index 0a4f83b0f..7d6b37179 100644 --- a/soh/soh/Enhancements/controls/InputViewer.cpp +++ b/soh/soh/Enhancements/controls/InputViewer.cpp @@ -5,9 +5,6 @@ #include "Context.h" #include "soh/OTRGlobals.h" #include "soh/cvar_prefixes.h" -#ifndef IMGUI_DEFINE_MATH_OPERATORS -#define IMGUI_DEFINE_MATH_OPERATORS -#endif #include #include #include diff --git a/soh/soh/Enhancements/controls/SohInputEditorWindow.h b/soh/soh/Enhancements/controls/SohInputEditorWindow.h index ee0942902..fdb3c77b0 100644 --- a/soh/soh/Enhancements/controls/SohInputEditorWindow.h +++ b/soh/soh/Enhancements/controls/SohInputEditorWindow.h @@ -2,9 +2,6 @@ #include "stdint.h" #include -#ifndef IMGUI_DEFINE_MATH_OPERATORS -#define IMGUI_DEFINE_MATH_OPERATORS -#endif #include #include #include diff --git a/soh/soh/Enhancements/debugconsole.cpp b/soh/soh/Enhancements/debugconsole.cpp index f2e7733a2..76f903eb1 100644 --- a/soh/soh/Enhancements/debugconsole.cpp +++ b/soh/soh/Enhancements/debugconsole.cpp @@ -18,9 +18,6 @@ #include #include -#ifndef IMGUI_DEFINE_MATH_OPERATORS -#define IMGUI_DEFINE_MATH_OPERATORS -#endif #include #include #undef PATH_HACK diff --git a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp index 5db0953b6..83fe7f676 100644 --- a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp +++ b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp @@ -455,8 +455,11 @@ void DrawInventoryTab() { uint8_t item = gSaveContext.inventory.items[index]; if (item != ITEM_NONE) { const ItemMapEntry& slotEntry = itemMapping.find(item)->second; - if (ImGui::ImageButton(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(slotEntry.name), ImVec2(32.0f, 32.0f), ImVec2(0, 0), - ImVec2(1, 1), 0)) { + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); + auto ret = ImGui::ImageButton(slotEntry.name.c_str(), Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(slotEntry.name), + ImVec2(32.0f, 32.0f), ImVec2(0, 0), ImVec2(1, 1)); + ImGui::PopStyleVar(); + if (ret) { selectedIndex = index; ImGui::OpenPopup(itemPopupPicker); } @@ -503,8 +506,11 @@ void DrawInventoryTab() { ImGui::SameLine(); } const ItemMapEntry& slotEntry = possibleItems[pickerIndex]; - if (ImGui::ImageButton(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(slotEntry.name), ImVec2(32.0f, 32.0f), - ImVec2(0, 0), ImVec2(1, 1), 0)) { + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); + auto ret = ImGui::ImageButton(slotEntry.name.c_str(), Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(slotEntry.name), + ImVec2(32.0f, 32.0f), ImVec2(0, 0), ImVec2(1, 1)); + ImGui::PopStyleVar(); + if (ret) { gSaveContext.inventory.items[selectedIndex] = slotEntry.id; // Set adult trade item flag if you're playing adult trade shuffle in rando if (IS_RANDO && @@ -986,8 +992,11 @@ void DrawUpgradeIcon(const std::string& categoryName, int32_t categoryId, const uint8_t item = items[CUR_UPG_VALUE(categoryId)]; if (item != ITEM_NONE) { const ItemMapEntry& slotEntry = itemMapping[item]; - if (ImGui::ImageButton(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(slotEntry.name), ImVec2(32.0f, 32.0f), ImVec2(0, 0), - ImVec2(1, 1), 0)) { + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); + auto ret = ImGui::ImageButton(slotEntry.name.c_str(), Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(slotEntry.name), + ImVec2(32.0f, 32.0f), ImVec2(0, 0), ImVec2(1, 1)); + ImGui::PopStyleVar(); + if (ret) { ImGui::OpenPopup(upgradePopupPicker); } } else { @@ -1014,8 +1023,11 @@ void DrawUpgradeIcon(const std::string& categoryName, int32_t categoryId, const UIWidgets::SetLastItemHoverText("None"); } else { const ItemMapEntry& slotEntry = itemMapping[items[pickerIndex]]; - if (ImGui::ImageButton(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(slotEntry.name), ImVec2(32.0f, 32.0f), ImVec2(0, 0), - ImVec2(1, 1), 0)) { + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); + auto ret = ImGui::ImageButton(slotEntry.name.c_str(), Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(slotEntry.name), + ImVec2(32.0f, 32.0f), ImVec2(0, 0), ImVec2(1, 1)); + ImGui::PopStyleVar(); + if (ret) { Inventory_ChangeUpgrade(categoryId, pickerIndex); ImGui::CloseCurrentPopup(); } @@ -1051,8 +1063,11 @@ void DrawEquipmentTab() { bool hasEquip = (bitMask & gSaveContext.inventory.equipment) != 0; const ItemMapEntry& entry = itemMapping[equipmentValues[i]]; ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); - if (ImGui::ImageButton(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(hasEquip ? entry.name : entry.nameFaded), - ImVec2(32.0f, 32.0f), ImVec2(0, 0), ImVec2(1, 1), 0)) { + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); + auto ret = ImGui::ImageButton(entry.name.c_str(), Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(hasEquip ? entry.name : entry.nameFaded), + ImVec2(32.0f, 32.0f), ImVec2(0, 0), ImVec2(1, 1)); + ImGui::PopStyleVar(); + if (ret) { if (hasEquip) { gSaveContext.inventory.equipment &= ~bitMask; } else { @@ -1150,8 +1165,11 @@ void DrawQuestItemButton(uint32_t item) { uint32_t bitMask = 1 << entry.id; bool hasQuestItem = (bitMask & gSaveContext.inventory.questItems) != 0; ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); - if (ImGui::ImageButton(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(hasQuestItem ? entry.name : entry.nameFaded), - ImVec2(32.0f, 32.0f), ImVec2(0, 0), ImVec2(1, 1), 0)) { + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); + auto ret = ImGui::ImageButton(entry.name.c_str(), Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(hasQuestItem ? entry.name : entry.nameFaded), + ImVec2(32.0f, 32.0f), ImVec2(0, 0), ImVec2(1, 1)); + ImGui::PopStyleVar(); + if (ret) { if (hasQuestItem) { gSaveContext.inventory.questItems &= ~bitMask; } else { @@ -1168,8 +1186,11 @@ void DrawDungeonItemButton(uint32_t item, uint32_t scene) { uint32_t bitMask = 1 << (entry.id - ITEM_KEY_BOSS); // Bitset starts at ITEM_KEY_BOSS == 0. the rest are sequential bool hasItem = (bitMask & gSaveContext.inventory.dungeonItems[scene]) != 0; ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); - if (ImGui::ImageButton(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(hasItem ? entry.name : entry.nameFaded), - ImVec2(32.0f, 32.0f), ImVec2(0, 0), ImVec2(1, 1), 0)) { + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); + auto ret = ImGui::ImageButton(entry.name.c_str(), Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(hasItem ? entry.name : entry.nameFaded), + ImVec2(32.0f, 32.0f), ImVec2(0, 0), ImVec2(1, 1)); + ImGui::PopStyleVar(); + if (ret) { if (hasItem) { gSaveContext.inventory.dungeonItems[scene] &= ~bitMask; } else { @@ -1215,8 +1236,11 @@ void DrawQuestStatusTab() { uint32_t bitMask = 1 << entry.id; bool hasQuestItem = (bitMask & gSaveContext.inventory.questItems) != 0; ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); - if (ImGui::ImageButton(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(hasQuestItem ? entry.name : entry.nameFaded), - ImVec2(16.0f, 24.0f), ImVec2(0, 0), ImVec2(1, 1), 0)) { + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); + auto ret = ImGui::ImageButton(entry.name.c_str(), Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(hasQuestItem ? entry.name : entry.nameFaded), + ImVec2(16.0f, 24.0f), ImVec2(0, 0), ImVec2(1, 1)); + ImGui::PopStyleVar(); + if (ret) { if (hasQuestItem) { gSaveContext.inventory.questItems &= ~bitMask; } else { diff --git a/soh/soh/Enhancements/randomizer/Plandomizer.cpp b/soh/soh/Enhancements/randomizer/Plandomizer.cpp index 6dd6a5175..3fc97eec7 100644 --- a/soh/soh/Enhancements/randomizer/Plandomizer.cpp +++ b/soh/soh/Enhancements/randomizer/Plandomizer.cpp @@ -715,15 +715,18 @@ void PlandomizerDrawItemPopup(uint32_t index) { ImGui::PushID(item); ImGui::TableNextColumn(); PlandomizerItemImageCorrection(plandomizerRandoRetrieveItem(item)); - if (ImGui::ImageButton(textureID, - imageSize, textureUV0, textureUV1, imagePadding, ImVec4(0, 0, 0, 0), itemColor)) { + auto name = plandomizerRandoRetrieveItem(item).GetName().english; + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(imagePadding, imagePadding)); + auto ret = ImGui::ImageButton(name.c_str(), textureID, imageSize, textureUV0, textureUV1, ImVec4(0, 0, 0, 0), itemColor); + ImGui::PopStyleVar(); + if (ret) { if (std::find(infiniteItemList.begin(), infiniteItemList.end(), plandoLogData[index].checkRewardItem.GetRandomizerGet()) == infiniteItemList.end()) { PlandomizerAddToItemList(plandoLogData[index].checkRewardItem); } plandoLogData[index].checkRewardItem = plandomizerRandoRetrieveItem(item); ImGui::CloseCurrentPopup(); } - UIWidgets::Tooltip(plandomizerRandoRetrieveItem(item).GetName().english.c_str()); + UIWidgets::Tooltip(name.c_str()); PlandomizerOverlayText(std::make_pair(plandomizerRandoRetrieveItem(item), 1)); ImGui::PopID(); } @@ -741,8 +744,11 @@ void PlandomizerDrawItemPopup(uint32_t index) { ImGui::PushID(itemIndex); auto itemToDraw = drawSlots.first; PlandomizerItemImageCorrection(drawSlots.first); - if (ImGui::ImageButton(textureID, - imageSize, textureUV0, textureUV1, imagePadding, ImVec4(0, 0, 0, 0), itemColor)) { + auto name = drawSlots.first.GetName().english; + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(imagePadding, imagePadding)); + auto ret = ImGui::ImageButton(name.c_str(), textureID, imageSize, textureUV0, textureUV1, ImVec4(0, 0, 0, 0), itemColor); + ImGui::PopStyleVar(); + if (ret) { if (itemToDraw.GetRandomizerGet() >= RG_PROGRESSIVE_HOOKSHOT && itemToDraw.GetRandomizerGet() <= RG_PROGRESSIVE_GORONSWORD) { plandoLogData[index].checkRewardItem = drawSlots.first; @@ -757,7 +763,7 @@ void PlandomizerDrawItemPopup(uint32_t index) { ImGui::CloseCurrentPopup(); } if (!isClicked) { - UIWidgets::Tooltip(drawSlots.first.GetName().english.c_str()); + UIWidgets::Tooltip(name.c_str()); } ImGui::PopID(); @@ -786,12 +792,16 @@ void PlandomizerDrawIceTrapPopUp(uint32_t index) { } ImGui::TableNextColumn(); ImGui::PushID(items.first); + auto name = Rando::StaticData::RetrieveItem(items.first).GetName().english; PlandomizerItemImageCorrection(Rando::StaticData::RetrieveItem(items.first)); - if (ImGui::ImageButton(textureID, imageSize, textureUV0, textureUV1, imagePadding, ImVec4(0, 0, 0, 0), itemColor)) { + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(imagePadding, imagePadding)); + auto ret = ImGui::ImageButton(name.c_str(), textureID, imageSize, textureUV0, textureUV1, ImVec4(0, 0, 0, 0), itemColor); + ImGui::PopStyleVar(); + if (ret) { plandoLogData[index].iceTrapModel = Rando::StaticData::RetrieveItem(items.first); ImGui::CloseCurrentPopup(); }; - UIWidgets::Tooltip(Rando::StaticData::RetrieveItem(items.first).GetName().english.c_str()); + UIWidgets::Tooltip(name.c_str()); auto itemObject = Rando::StaticData::RetrieveItem(items.first); PlandomizerOverlayText(std::make_pair(itemObject, 1)); @@ -808,13 +818,17 @@ void PlandomizerDrawItemSlots(uint32_t index) { ImGui::PushID(index); PlandoPushImageButtonStyle(); PlandomizerItemImageCorrection(plandoLogData[index].checkRewardItem); - if (ImGui::ImageButton(textureID, imageSize, textureUV0, textureUV1, imagePadding, ImVec4(0, 0, 0, 0), itemColor)) { + auto name = plandoLogData[index].checkRewardItem.GetName().english; + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(imagePadding, imagePadding)); + auto ret = ImGui::ImageButton(name.c_str(), textureID, imageSize, textureUV0, textureUV1, ImVec4(0, 0, 0, 0), itemColor); + ImGui::PopStyleVar(); + if (ret) { shouldPopup = true; temporaryItem = plandoLogData[index].checkRewardItem; ImGui::OpenPopup("ItemList"); }; PlandoPopImageButtonStyle(); - UIWidgets::Tooltip(plandoLogData[index].checkRewardItem.GetName().english.c_str()); + UIWidgets::Tooltip(name.c_str()); PlandomizerOverlayText(std::make_pair(plandoLogData[index].checkRewardItem, 1)); PlandomizerDrawItemPopup(index); ImGui::PopID(); @@ -852,12 +866,16 @@ void PlandomizerDrawIceTrapSetup(uint32_t index) { ImGui::TableNextColumn(); PlandomizerItemImageCorrection(plandoLogData[index].iceTrapModel); PlandoPushImageButtonStyle(); - if (ImGui::ImageButton(textureID, imageSize, textureUV0, textureUV1, imagePadding, ImVec4(0, 0, 0, 0), itemColor)) { + auto name = plandoLogData[index].iceTrapModel.GetName().english; + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(imagePadding, imagePadding)); + auto ret = ImGui::ImageButton(name.c_str(), textureID, imageSize, textureUV0, textureUV1, ImVec4(0, 0, 0, 0), itemColor); + ImGui::PopStyleVar(); + if (ret) { shouldTrapPopup = true; ImGui::OpenPopup("TrapList"); }; PlandoPopImageButtonStyle(); - UIWidgets::Tooltip(plandoLogData[index].iceTrapModel.GetName().english.c_str()); + UIWidgets::Tooltip(name.c_str()); PlandomizerDrawIceTrapPopUp(index); ImGui::SameLine(); ImGui::TableNextColumn(); @@ -934,8 +952,11 @@ void PlandomizerDrawOptions() { for (auto& hash : plandoHash) { ImGui::PushID(index); textureID = Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(gSeedTextures[hash].tex); - if (ImGui::ImageButton(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("HASH_ARROW_UP"), - ImVec2(35.0f, 18.0f), ImVec2(1, 1), ImVec2(0, 0), 2.0f, ImVec4(0, 0, 0, 0), ImVec4(1, 1, 1, 1))) { + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 2.0f)); + auto upRet = ImGui::ImageButton("HASH_ARROW_UP", Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("HASH_ARROW_UP"), + ImVec2(35.0f, 18.0f), ImVec2(1, 1), ImVec2(0, 0), ImVec4(0, 0, 0, 0), ImVec4(1, 1, 1, 1)); + ImGui::PopStyleVar(); + if (upRet) { if (hash + 1 >= gSeedTextures.size()) { hash = 0; } @@ -944,8 +965,11 @@ void PlandomizerDrawOptions() { } } ImGui::Image(textureID, ImVec2(35.0f, 35.0f)); - if (ImGui::ImageButton(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("HASH_ARROW_DWN"), - ImVec2(35.0f, 18.0f), ImVec2(0, 0), ImVec2(1, 1), 2.0f, ImVec4(0, 0, 0, 0), ImVec4(1, 1, 1, 1))) { + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 2.0f)); + auto downRet = ImGui::ImageButton("HASH_ARROW_DWN", Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("HASH_ARROW_DWN"), + ImVec2(35.0f, 18.0f), ImVec2(0, 0), ImVec2(1, 1), ImVec4(0, 0, 0, 0), ImVec4(1, 1, 1, 1)); + ImGui::PopStyleVar(); + if (downRet) { if (hash == 0) { hash = gSeedTextures.size() - 1; } diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 73125c2ff..0d2216755 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -14,9 +14,6 @@ #include "soh/UIWidgets.hpp" #include "3drando/custom_messages.hpp" #include "../../UIWidgets.hpp" -#ifndef IMGUI_DEFINE_MATH_OPERATORS -#define IMGUI_DEFINE_MATH_OPERATORS -#endif #include #include #include "../custom-message/CustomMessageTypes.h" diff --git a/soh/soh/Enhancements/timesplits/TimeSplits.cpp b/soh/soh/Enhancements/timesplits/TimeSplits.cpp index 57a73dd6f..01faf7bf5 100644 --- a/soh/soh/Enhancements/timesplits/TimeSplits.cpp +++ b/soh/soh/Enhancements/timesplits/TimeSplits.cpp @@ -432,8 +432,10 @@ void TimeSplitsPopUpContext() { ImGui::BeginTable("Token Table", 2); ImGui::TableNextColumn(); SplitsPushImageButtonStyle(); - ImGui::ImageButton(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("QUEST_SKULL_TOKEN"), - ImVec2(32.0f, 32.0f), ImVec2(0, 0), ImVec2(1, 1), 2.0f, ImVec4(0, 0, 0, 0)); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 2.0f)); + ImGui::ImageButton("QUEST_SKULL_TOKEN", Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("QUEST_SKULL_TOKEN"), + ImVec2(32.0f, 32.0f), ImVec2(0, 0), ImVec2(1, 1), ImVec4(0, 0, 0, 0)); + ImGui::PopStyleVar(); ImGui::TableNextColumn(); SplitsPopImageButtonStyle(); ImGui::PushItemWidth(150.0f); @@ -479,8 +481,11 @@ void TimeSplitsPopUpContext() { SplitObject& popupObject = *findID; ImGui::BeginGroup(); ImGui::PushID(popupObject.splitID); - if (ImGui::ImageButton(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(popupObject.splitImage), - ImVec2(32.0f, 32.0f), ImVec2(0, 0), ImVec2(1, 1), 2, ImVec4(0, 0, 0, 0), popupObject.splitTint)) { + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 2.0f)); + auto ret = ImGui::ImageButton(popupObject.splitImage.c_str(), Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(popupObject.splitImage), + ImVec2(32.0f, 32.0f), ImVec2(0, 0), ImVec2(1, 1), ImVec4(0, 0, 0, 0), popupObject.splitTint); + ImGui::PopStyleVar(); + if (ret) { splitList.push_back(popupObject); if (splitList.size() == 1) { splitList[0].splitTimeStatus = SPLIT_STATUS_ACTIVE; @@ -650,8 +655,11 @@ void TimeSplitsDrawSplitsList() { ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, IM_COL32(47, 79, 90, 255)); } TimeSplitsGetImageSize(split.splitID); - if (ImGui::ImageButton(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(split.splitImage), - imageSize, ImVec2(0, 0), ImVec2(1, 1), imagePadding, ImVec4(0, 0, 0, 0), split.splitTint)) { + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(imagePadding, imagePadding)); + auto ret = ImGui::ImageButton(split.splitImage.c_str(), Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(split.splitImage), + imageSize, ImVec2(0, 0), ImVec2(1, 1), ImVec4(0, 0, 0, 0), split.splitTint); + ImGui::PopStyleVar(); + if (ret) { TimeSplitsSkipSplit(dragIndex); } HandleDragAndDrop(splitList, dragIndex, split.splitName); @@ -722,9 +730,11 @@ void TimeSplitsDrawItemList(uint32_t type) { ImGui::PushID(split.splitID); TimeSplitsGetImageSize(split.splitID); SplitsPushImageButtonStyle(); - if (ImGui::ImageButton(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(split.splitImage), - imageSize, ImVec2(0, 0), ImVec2(1, 1), imagePadding, ImVec4(0, 0, 0, 0), split.splitTint)) { - + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(imagePadding, imagePadding)); + auto ret = ImGui::ImageButton(split.splitImage.c_str(), Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(split.splitImage), + imageSize, ImVec2(0, 0), ImVec2(1, 1), ImVec4(0, 0, 0, 0), split.splitTint); + ImGui::PopStyleVar(); + if (ret) { if (popupList.contains(split.splitID) && (split.splitType < SPLIT_TYPE_BOSS)) { popupID = split.splitID; ImGui::OpenPopup("TimeSplitsPopUp"); @@ -875,8 +885,11 @@ void TimeSplitsDrawManageList() { ImGui::SetCursorPosX(ImGui::GetCursorPosX() + offsetX); // Apply the offset to center } TimeSplitsGetImageSize(data.splitID); - if (ImGui::ImageButton(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(data.splitImage), - imageSize, ImVec2(0, 0), ImVec2(1, 1), imagePadding, ImVec4(0, 0, 0, 0), data.splitTint)) { + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(imagePadding, imagePadding)); + auto ret = ImGui::ImageButton(data.splitImage.c_str(), Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(data.splitImage), + imageSize, ImVec2(0, 0), ImVec2(1, 1), ImVec4(0, 0, 0, 0), data.splitTint); + ImGui::PopStyleVar(); + if (ret) { removeIndex = index; } HandleDragAndDrop(splitList, index, splitList[index].splitName); diff --git a/soh/soh/ImGuiUtils.h b/soh/soh/ImGuiUtils.h index ed735713a..763bae49b 100644 --- a/soh/soh/ImGuiUtils.h +++ b/soh/soh/ImGuiUtils.h @@ -3,9 +3,6 @@ #pragma once -#ifndef IMGUI_DEFINE_MATH_OPERATORS -#define IMGUI_DEFINE_MATH_OPERATORS -#endif #include #include #include diff --git a/soh/soh/SohGui.cpp b/soh/soh/SohGui.cpp index 42ba25de2..6cc4e1de6 100644 --- a/soh/soh/SohGui.cpp +++ b/soh/soh/SohGui.cpp @@ -8,9 +8,6 @@ #include "SohGui.hpp" #include -#ifndef IMGUI_DEFINE_MATH_OPERATORS -#define IMGUI_DEFINE_MATH_OPERATORS -#endif #include #include #include diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index 932a661d3..f3a9557c2 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -1,7 +1,4 @@ #include "SohMenuBar.h" -#ifndef IMGUI_DEFINE_MATH_OPERATORS -#define IMGUI_DEFINE_MATH_OPERATORS -#endif #include #include "regex" #include "public/bridge/consolevariablebridge.h" diff --git a/soh/soh/UIWidgets.cpp b/soh/soh/UIWidgets.cpp index 9272cbefc..2ffea11b4 100644 --- a/soh/soh/UIWidgets.cpp +++ b/soh/soh/UIWidgets.cpp @@ -7,9 +7,6 @@ #include "UIWidgets.hpp" -#ifndef IMGUI_DEFINE_MATH_OPERATORS -#define IMGUI_DEFINE_MATH_OPERATORS -#endif #include #include #include @@ -159,7 +156,7 @@ namespace UIWidgets { ImGui::RenderFrame(check_bb.Min, check_bb.Max, ImGui::GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding); ImU32 check_col = ImGui::GetColorU32(ImGuiCol_CheckMark); ImU32 cross_col = ImGui::GetColorU32(ImVec4(0.50f, 0.50f, 0.50f, 1.00f)); - bool mixed_value = (g.LastItemData.InFlags & ImGuiItemFlags_MixedValue) != 0; + bool mixed_value = (g.LastItemData.ItemFlags & ImGuiItemFlags_MixedValue) != 0; if (mixed_value) { // Undocumented tristate/mixed/indeterminate checkbox (#2644) // This may seem awkwardly designed because the aim is to make ImGuiItemFlags_MixedValue supported by all widgets (not just checkbox) @@ -789,12 +786,17 @@ namespace UIWidgets { if (!ImGui::ItemAdd(bb, id)) return false; - if (g.LastItemData.InFlags & ImGuiItemFlags_ButtonRepeat) - flags |= ImGuiButtonFlags_Repeat; + if (g.LastItemData.ItemFlags & ImGuiItemFlags_ButtonRepeat) { + ImGui::PushItemFlag(ImGuiItemFlags_ButtonRepeat, true); + } bool hovered, held; bool pressed = ImGui::ButtonBehavior(bb, id, &hovered, &held, flags); + if (g.LastItemData.ItemFlags & ImGuiItemFlags_ButtonRepeat) { + ImGui::PopItemFlag(); // ImGuiItemFlags_ButtonRepeat; + } + // Render const ImU32 bg_col = ImGui::GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered diff --git a/soh/soh/UIWidgets.hpp b/soh/soh/UIWidgets.hpp index c0e1b4504..97a367270 100644 --- a/soh/soh/UIWidgets.hpp +++ b/soh/soh/UIWidgets.hpp @@ -6,9 +6,6 @@ #include #include #include -#ifndef IMGUI_DEFINE_MATH_OPERATORS -#define IMGUI_DEFINE_MATH_OPERATORS -#endif #include #include "soh/ShipInit.hpp" From 1ee31e5d61b17b285463ee69d8b41951b2902bd4 Mon Sep 17 00:00:00 2001 From: Pepe20129 <72659707+Pepe20129@users.noreply.github.com> Date: Sat, 11 Jan 2025 08:28:23 +0100 Subject: [PATCH 05/26] Location access files cleanup (#4750) * Move/Rename locacc files * Format locacc files * Split hyrule field file into HF, LH & LLR files * Split castle town file into MK, TOT & HC/OGC files * Split kakariko file into KAK & GY files * Split death mountain file into DMT, GC & DMC * Split lost woods file into KF, LW & SFM files * Split gerudo valley file into GV, GF, HW & COLO files * Move most files into the overworld/dungeons folder Gerudo fortress needs to be split into gerudo fortress & thieves hideout, the former into overworld and the latter into dungeons * Remove the optional second condition function We won't need it as we're doing glitches differently from 3ds rando * Post-merge fixes * Split zora's domain file into ZR, ZD & ZF files * Post-merge fixes * Forgot to save the file * Remove the optional second condition function from entrances & events * Update bottom_of_the_well.cpp * Add clarifying comment in `gerudo_fortress.cpp` * Post-merge fixes * Post-merge fixes * Remove `s` from `RegionTable_Init_GerudoTrainingGrounds` * Post-merge fixes --- .../Enhancements/randomizer/3drando/fill.hpp | 2 +- .../randomizer/3drando/location_access.cpp | 558 ------------- .../randomizer/3drando/location_access.hpp | 376 --------- .../locacc_bottom_of_the_well.cpp | 300 ------- .../location_access/locacc_castle_town.cpp | 376 --------- .../location_access/locacc_death_mountain.cpp | 346 -------- .../location_access/locacc_deku_tree.cpp | 388 --------- .../locacc_dodongos_cavern.cpp | 572 ------------- .../location_access/locacc_fire_temple.cpp | 743 ----------------- .../location_access/locacc_forest_temple.cpp | 637 -------------- .../location_access/locacc_ganons_castle.cpp | 513 ------------ .../locacc_gerudo_training_ground.cpp | 340 -------- .../location_access/locacc_gerudo_valley.cpp | 281 ------- .../location_access/locacc_hyrule_field.cpp | 335 -------- .../location_access/locacc_ice_cavern.cpp | 152 ---- .../locacc_jabujabus_belly.cpp | 377 --------- .../location_access/locacc_kakariko.cpp | 359 -------- .../location_access/locacc_lost_woods.cpp | 344 -------- .../location_access/locacc_shadow_temple.cpp | 431 ---------- .../location_access/locacc_spirit_temple.cpp | 577 ------------- .../location_access/locacc_water_temple.cpp | 779 ------------------ .../location_access/locacc_zoras_domain.cpp | 257 ------ .../Enhancements/randomizer/3drando/menu.cpp | 2 +- .../randomizer/3drando/playthrough.cpp | 2 +- .../randomizer/3drando/rando_main.cpp | 2 +- .../Enhancements/randomizer/3drando/shops.cpp | 2 +- soh/soh/Enhancements/randomizer/entrance.cpp | 18 +- soh/soh/Enhancements/randomizer/entrance.h | 8 +- .../randomizer/location_access.cpp | 575 +++++++++++++ .../Enhancements/randomizer/location_access.h | 365 ++++++++ .../dungeons/bottom_of_the_well.cpp | 296 +++++++ .../location_access/dungeons/deku_tree.cpp | 363 ++++++++ .../dungeons/dodongos_cavern.cpp | 542 ++++++++++++ .../location_access/dungeons/fire_temple.cpp | 718 ++++++++++++++++ .../dungeons/forest_temple.cpp | 613 ++++++++++++++ .../dungeons/ganons_castle.cpp | 507 ++++++++++++ .../dungeons/gerudo_training_ground.cpp | 327 ++++++++ .../location_access/dungeons/ice_cavern.cpp | 147 ++++ .../dungeons/jabujabus_belly.cpp | 360 ++++++++ .../dungeons/shadow_temple.cpp | 416 ++++++++++ .../dungeons/spirit_temple.cpp | 557 +++++++++++++ .../location_access/dungeons/water_temple.cpp | 738 +++++++++++++++++ .../location_access/gerudo_fortress.cpp | 81 ++ .../overworld/castle_grounds.cpp | 117 +++ .../overworld/death_mountain_crater.cpp | 145 ++++ .../overworld/death_mountain_trail.cpp | 100 +++ .../overworld/desert_colossus.cpp | 77 ++ .../overworld/gerudo_valley.cpp | 108 +++ .../location_access/overworld/goron_city.cpp | 111 +++ .../location_access/overworld/graveyard.cpp | 122 +++ .../overworld/haunted_wasteland.cpp | 38 + .../overworld/hyrule_field.cpp | 143 ++++ .../location_access/overworld/kakariko.cpp | 242 ++++++ .../overworld/kokiri_forest.cpp | 152 ++++ .../location_access/overworld/lake_hylia.cpp | 131 +++ .../overworld/lon_lon_ranch.cpp | 74 ++ .../location_access/overworld/lost_woods.cpp | 130 +++ .../location_access/overworld/market.cpp | 216 +++++ .../overworld/sacred_forest_meadow.cpp | 74 ++ .../overworld/temple_of_time.cpp | 54 ++ .../location_access/overworld/zora_river.cpp | 107 +++ .../overworld/zoras_domain.cpp | 93 +++ .../overworld/zoras_fountain.cpp | 64 ++ .../randomizer/randomizer_check_tracker.cpp | 2 +- 64 files changed, 8918 insertions(+), 9064 deletions(-) delete mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access.cpp delete mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access.hpp delete mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_bottom_of_the_well.cpp delete mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_castle_town.cpp delete mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_death_mountain.cpp delete mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_deku_tree.cpp delete mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_dodongos_cavern.cpp delete mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_fire_temple.cpp delete mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_forest_temple.cpp delete mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_ganons_castle.cpp delete mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_gerudo_training_ground.cpp delete mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_gerudo_valley.cpp delete mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_hyrule_field.cpp delete mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_ice_cavern.cpp delete mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_jabujabus_belly.cpp delete mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_kakariko.cpp delete mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_lost_woods.cpp delete mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_shadow_temple.cpp delete mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_spirit_temple.cpp delete mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_water_temple.cpp delete mode 100644 soh/soh/Enhancements/randomizer/3drando/location_access/locacc_zoras_domain.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access.h create mode 100644 soh/soh/Enhancements/randomizer/location_access/dungeons/bottom_of_the_well.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access/dungeons/deku_tree.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access/dungeons/dodongos_cavern.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access/dungeons/fire_temple.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access/dungeons/forest_temple.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access/dungeons/ganons_castle.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access/dungeons/gerudo_training_ground.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access/dungeons/ice_cavern.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access/dungeons/jabujabus_belly.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access/dungeons/shadow_temple.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access/dungeons/spirit_temple.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access/dungeons/water_temple.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access/gerudo_fortress.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access/overworld/castle_grounds.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access/overworld/death_mountain_crater.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access/overworld/death_mountain_trail.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access/overworld/desert_colossus.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access/overworld/gerudo_valley.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access/overworld/goron_city.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access/overworld/graveyard.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access/overworld/haunted_wasteland.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access/overworld/hyrule_field.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access/overworld/kakariko.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access/overworld/kokiri_forest.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access/overworld/lake_hylia.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access/overworld/lon_lon_ranch.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access/overworld/lost_woods.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access/overworld/market.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access/overworld/sacred_forest_meadow.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access/overworld/temple_of_time.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access/overworld/zora_river.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access/overworld/zoras_domain.cpp create mode 100644 soh/soh/Enhancements/randomizer/location_access/overworld/zoras_fountain.cpp diff --git a/soh/soh/Enhancements/randomizer/3drando/fill.hpp b/soh/soh/Enhancements/randomizer/3drando/fill.hpp index 94cba70c7..106af7aab 100644 --- a/soh/soh/Enhancements/randomizer/3drando/fill.hpp +++ b/soh/soh/Enhancements/randomizer/3drando/fill.hpp @@ -1,7 +1,7 @@ #pragma once #include "../randomizerTypes.h" -#include "location_access.hpp" +#include "../location_access.h" #include "../entrance.h" #include diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access.cpp deleted file mode 100644 index 725844f10..000000000 --- a/soh/soh/Enhancements/randomizer/3drando/location_access.cpp +++ /dev/null @@ -1,558 +0,0 @@ -#include "location_access.hpp" - -#include "../dungeon.h" -#include "../static_data.h" -#include "../context.h" -#include "item_pool.hpp" -#include "spoiler_log.hpp" -#include "../trial.h" -#include "../entrance.h" -#include "soh/Enhancements/debugger/performanceTimer.h" - -#include - -//generic grotto event list -std::vector grottoEvents; - -//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 { - - logic->IsChild = false; - logic->IsAdult = false; - logic->AtDay = false; - logic->AtNight = false; - - time = true; - age = true; - - return GetConditionsMet(); -} - -bool LocationAccess::ConditionsMet() const { - //WARNING enterance validation can run this after resetting the access for sphere 0 validation - //When refactoring ToD access, either fix the above or do not assume that we - //have any access at all just because this is being run - Region* parentRegion = RegionTable(Rando::Context::GetInstance()->GetItemLocation(location)->GetParentRegionKey()); - bool conditionsMet = false; - - if ((parentRegion->childDay && CheckConditionAtAgeTime(logic->IsChild, logic->AtDay)) || - (parentRegion->childNight && CheckConditionAtAgeTime(logic->IsChild, logic->AtNight)) || - (parentRegion->adultDay && CheckConditionAtAgeTime(logic->IsAdult, logic->AtDay)) || - (parentRegion->adultNight && CheckConditionAtAgeTime(logic->IsAdult, logic->AtNight))) { - conditionsMet = true; - } - - return conditionsMet && CanBuy(); -} - -bool LocationAccess::CanBuy() const { - return CanBuyAnother(location); -} - -bool CanBuyAnother(RandomizerCheck rc) { - uint16_t price = ctx->GetItemLocation(rc)->GetPrice(); - - if (price > 500) { - return logic->HasItem(RG_TYCOON_WALLET); - } else if (price > 200) { - return logic->HasItem(RG_GIANT_WALLET); - } else if (price > 99) { - return logic->HasItem(RG_ADULT_WALLET); - } else if (price > 0) { - return logic->HasItem(RG_CHILD_WALLET); - } - return true; -} - -Region::Region() = default; -Region::Region(std::string regionName_, std::string scene_, std::set areas, - bool timePass_, - std::vector events_, - std::vector locations_, - std::list exits_) - : regionName(std::move(regionName_)), - scene(std::move(scene_)), - areas(areas), - timePass(timePass_), - events(std::move(events_)), - locations(std::move(locations_)), - exits(std::move(exits_)) {} - -Region::~Region() = default; - -void Region::ApplyTimePass(){ - if (timePass) { - StartPerformanceTimer(PT_TOD_ACCESS); - if (Child()) { - childDay = true; - childNight = true; - RegionTable(RR_ROOT)->childDay = true; - RegionTable(RR_ROOT)->childNight = true; - } - if (Adult()) { - adultDay = true; - adultNight = true; - RegionTable(RR_ROOT)->adultDay = true; - RegionTable(RR_ROOT)->adultNight = true; - } - StopPerformanceTimer(PT_TOD_ACCESS); - } -} - -bool Region::UpdateEvents() { - bool eventsUpdated = false; - StartPerformanceTimer(PT_EVENT_ACCESS); - 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(logic->IsChild, logic->AtDay)) || - (childNight && event.CheckConditionAtAgeTime(logic->IsChild, logic->AtNight)) || - (adultDay && event.CheckConditionAtAgeTime(logic->IsAdult, logic->AtDay)) || - (adultNight && event.CheckConditionAtAgeTime(logic->IsAdult, logic->AtNight))) { - event.EventOccurred(); - eventsUpdated = true; - } - } - StopPerformanceTimer(PT_EVENT_ACCESS); - return eventsUpdated; -} - -void Region::AddExit(RandomizerRegion parentKey, RandomizerRegion newExitKey, ConditionFn condition) { - Rando::Entrance newExit = Rando::Entrance(newExitKey, {condition}); - newExit.SetParentRegion(parentKey); - exits.push_front(newExit); -} - -//The exit will be completely removed from this region -void Region::RemoveExit(Rando::Entrance* exitToRemove) { - exits.remove_if([exitToRemove](const auto exit){return &exit == exitToRemove;}); -} - -void Region::SetAsPrimary(RandomizerRegion exitToBePrimary) { - for (auto& exit : exits) { - if (exit.Getuint32_t() == exitToBePrimary) { - exit.SetAsPrimary(); - return; - } - } -} - -Rando::Entrance* Region::GetExit(RandomizerRegion exitToReturn) { - for (auto& exit : exits) { - if (exit.Getuint32_t() == exitToReturn) { - return &exit; - } - } - //auto message = "ERROR: EXIT " + RegionTable(exitToReturn)->regionName + " DOES NOT EXIST IN " + this->regionName; - //CitraPrint(message); - return nullptr; -} - -bool Region::CanPlantBeanCheck() const { - return Rando::Context::GetInstance()->GetLogic()->GetAmmo(ITEM_BEAN) > 0 && BothAgesCheck(); -} - -bool Region::AllAccountedFor() const { - for (const EventAccess& event : events) { - if (!event.GetEvent()) { - return false; - } - } - - for (const LocationAccess& loc : locations) { - if (!(Rando::Context::GetInstance()->GetItemLocation(loc.GetLocation())->IsAddedToPool())) { - return false; - } - } - - for (const auto& exit : exits) { - if (!exit.GetConnectedRegion()->AllAccess()) { - return false; - } - } - - return AllAccess(); -} - -bool Region::CheckAllAccess(const RandomizerRegion exitKey) { - if (!AllAccess()) { - return false; - } - - for (Rando::Entrance& exit : exits) { - if (exit.GetConnectedRegionKey() == 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 Region::ResetVariables() { - childDay = false; - childNight = false; - adultDay = false; - adultNight = false; - addedToPool = false; - for (auto& exit : exits) { - exit.RemoveFromPool(); - } -} - -std::array areaTable; - -bool Here(const RandomizerRegion region, ConditionFn condition) { - return areaTable[region].Here(condition); -} - -bool MQSpiritSharedStatueRoom(const RandomizerRegion region, ConditionFn condition, bool anyAge) { - return areaTable[region].MQSpiritShared(condition, false, anyAge); -} - -bool MQSpiritSharedBrokenWallRoom(const RandomizerRegion region, ConditionFn condition, bool anyAge) { - return areaTable[region].MQSpiritShared(condition, true, anyAge); -} - -bool CanPlantBean(const RandomizerRegion region) { - return areaTable[region].CanPlantBeanCheck(); -} - -bool BothAges(const RandomizerRegion region) { - return areaTable[region].BothAgesCheck(); -} - -bool ChildCanAccess(const RandomizerRegion region) { - return areaTable[region].Child(); -} - -bool AdultCanAccess(const RandomizerRegion region) { - return areaTable[region].Adult(); -} - -bool HasAccessTo(const RandomizerRegion region) { - return areaTable[region].HasAccess(); -} - -Rando::Context* ctx; -std::shared_ptr logic; - -void RegionTable_Init() { - using namespace Rando; - ctx = Context::GetInstance().get(); - logic = ctx->GetLogic(); //RANDOTODO do not hardcode, instead allow accepting a Logic class somehow - grottoEvents = { - EventAccess(&logic->GossipStoneFairy, { [] { return logic->CallGossipFairy(); } }), - EventAccess(&logic->ButterflyFairy, { [] { return logic->ButterflyFairy || (logic->CanUse(RG_STICKS)); } }), - EventAccess(&logic->BugShrub, { [] { return logic->CanCutShrubs(); } }), - EventAccess(&logic->LoneFish, { [] { return true; } }), - }; - //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(Region("Invalid Region", "Invalid Region", {}, NO_DAY_NIGHT_CYCLE, {}, {}, {})); - - //name, scene, hint text, events, locations, exits - areaTable[RR_ROOT] = Region("Root", "", {RA_LINKS_POCKET}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->KakarikoVillageGateOpen, {[]{return ctx->GetOption(RSK_KAK_GATE).Is(RO_KAK_GATE_OPEN);}}), - }, { - //Locations - LOCATION(RC_LINKS_POCKET, true), - LOCATION(RC_TRIFORCE_COMPLETED, logic->GetSaveContext()->triforcePiecesCollected >= ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_REQUIRED).GetContextOptionIndex() + 1;), - LOCATION(RC_SARIA_SONG_HINT, logic->CanUse(RG_SARIAS_SONG)), - }, { - //Exits - Entrance(RR_ROOT_EXITS, {[]{return true;}}), - }); - - areaTable[RR_ROOT_EXITS] = Region("Root Exits", "", {RA_LINKS_POCKET}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_CHILD_SPAWN, {[]{return logic->IsChild;}}), - Entrance(RR_ADULT_SPAWN, {[]{return logic->IsAdult;}}), - Entrance(RR_MINUET_OF_FOREST_WARP, {[]{return logic->CanUse(RG_MINUET_OF_FOREST);}}), - Entrance(RR_BOLERO_OF_FIRE_WARP, {[]{return logic->CanUse(RG_BOLERO_OF_FIRE) && logic->CanLeaveForest();}}), - Entrance(RR_SERENADE_OF_WATER_WARP, {[]{return logic->CanUse(RG_SERENADE_OF_WATER) && logic->CanLeaveForest();}}), - Entrance(RR_NOCTURNE_OF_SHADOW_WARP, {[]{return logic->CanUse(RG_NOCTURNE_OF_SHADOW) && logic->CanLeaveForest();}}), - Entrance(RR_REQUIEM_OF_SPIRIT_WARP, {[]{return logic->CanUse(RG_REQUIEM_OF_SPIRIT) && logic->CanLeaveForest();}}), - Entrance(RR_PRELUDE_OF_LIGHT_WARP, {[]{return logic->CanUse(RG_PRELUDE_OF_LIGHT) && logic->CanLeaveForest();}}), - }); - - areaTable[RR_CHILD_SPAWN] = Region("Child Spawn", "", {RA_LINKS_POCKET}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_KF_LINKS_HOUSE, {[]{return true;}}), - }); - - areaTable[RR_ADULT_SPAWN] = Region("Adult Spawn", "", {RA_LINKS_POCKET}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_TEMPLE_OF_TIME, {[]{return true;}}), - }); - - areaTable[RR_MINUET_OF_FOREST_WARP] = Region("Minuet of Forest Warp", "", {RA_LINKS_POCKET}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_SACRED_FOREST_MEADOW, {[]{return true;}}), - }); - - areaTable[RR_BOLERO_OF_FIRE_WARP] = Region("Bolero of Fire Warp", "", {RA_LINKS_POCKET}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_DMC_CENTRAL_LOCAL, {[]{return true;}}), - }); - - areaTable[RR_SERENADE_OF_WATER_WARP] = Region("Serenade of Water Warp", "", {RA_LINKS_POCKET}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_LAKE_HYLIA, {[]{return true;}}), - }); - - areaTable[RR_REQUIEM_OF_SPIRIT_WARP] = Region("Requiem of Spirit Warp", "", {RA_LINKS_POCKET}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_DESERT_COLOSSUS, {[]{return true;}}), - }); - - areaTable[RR_NOCTURNE_OF_SHADOW_WARP] = Region("Nocturne of Shadow Warp", "", {RA_LINKS_POCKET}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_GRAVEYARD_WARP_PAD_REGION, {[]{return true;}}), - }); - - areaTable[RR_PRELUDE_OF_LIGHT_WARP] = Region("Prelude of Light Warp", "", {RA_LINKS_POCKET}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_TEMPLE_OF_TIME, {[]{return true;}}), - }); - - // Overworld - RegionTable_Init_LostWoods(); - RegionTable_Init_HyruleField(); - RegionTable_Init_CastleTown(); - RegionTable_Init_Kakariko(); - RegionTable_Init_DeathMountain(); - RegionTable_Init_ZorasDomain(); - RegionTable_Init_GerudoValley(); - // Dungeons - RegionTable_Init_DekuTree(); - RegionTable_Init_DodongosCavern(); - RegionTable_Init_JabuJabusBelly(); - RegionTable_Init_ForestTemple(); - RegionTable_Init_FireTemple(); - RegionTable_Init_WaterTemple(); - RegionTable_Init_SpiritTemple(); - RegionTable_Init_ShadowTemple(); - RegionTable_Init_BottomOfTheWell(); - RegionTable_Init_IceCavern(); - RegionTable_Init_GerudoTrainingGrounds(); - RegionTable_Init_GanonsCastle(); - - //Set parent regions - for (uint32_t i = RR_ROOT; i <= RR_GANONS_CASTLE; i++) { - for (LocationAccess& locPair : areaTable[i].locations) { - RandomizerCheck location = locPair.GetLocation(); - Rando::Context::GetInstance()->GetItemLocation(location)->SetParentRegion((RandomizerRegion)i); - } - for (Entrance& exit : areaTable[i].exits) { - exit.SetParentRegion((RandomizerRegion)i); - exit.SetName(); - exit.GetConnectedRegion()->entrances.push_front(&exit); - } - } -} - -void ReplaceFirstInString(std::string& s, std::string const& toReplace, std::string const& replaceWith) { - size_t pos = s.find(toReplace); - if (pos == std::string::npos) { - return; - } - s.replace(pos, toReplace.length(), replaceWith); -} - -void ReplaceAllInString(std::string& s, std::string const& toReplace, std::string const& replaceWith) { - std::string buf; - size_t pos = 0; - size_t prevPos; - - buf.reserve(s.size()); - - while (true) { - prevPos = pos; - pos = s.find(toReplace, pos); - if (pos == std::string::npos) { - break; - } - buf.append(s, prevPos, pos - prevPos); - buf += replaceWith; - pos += toReplace.size(); - } - - buf.append(s, prevPos, s.size() - prevPos); - s.swap(buf); -} - -std::string CleanCheckConditionString(std::string condition) { - ReplaceAllInString(condition, "logic->", ""); - ReplaceAllInString(condition, "ctx->", ""); - ReplaceAllInString(condition, ".GetContextOptionIndex()", ""); - ReplaceAllInString(condition, "GetSaveContext()->", ""); - return condition; -} - -namespace Regions { - - const auto GetAllRegions() { - static const size_t regionCount = RR_MAX - (RR_NONE + 1); - - static std::array allRegions = {}; - - static bool intialized = false; - if (!intialized) { - for (size_t i = 0; i < regionCount; i++) { - allRegions[i] = (RandomizerRegion)((RR_NONE + 1) + i); - } - intialized = true; - } - - return allRegions; - } - - void AccessReset() { - auto ctx = Rando::Context::GetInstance(); - for (const RandomizerRegion region : GetAllRegions()) { - RegionTable(region)->ResetVariables(); - } - - if(/*Settings::HasNightStart TODO:: Randomize Starting Time*/ false) { - if(ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_CHILD) { - RegionTable(RR_ROOT)->childNight = true; - } else { - RegionTable(RR_ROOT)->adultNight = true; - } - } else { - if(ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_CHILD) { - RegionTable(RR_ROOT)->childDay = true; - } else { - RegionTable(RR_ROOT)->adultDay = true; - } - } - } - - //Reset exits and clear items from locations - void ResetAllLocations() { - auto ctx = Rando::Context::GetInstance(); - for (const RandomizerRegion region : GetAllRegions()) { - RegionTable(region)->ResetVariables(); - //Erase item from every location in this exit - for (LocationAccess& locPair : RegionTable(region)->locations) { - RandomizerCheck location = locPair.GetLocation(); - Rando::Context::GetInstance()->GetItemLocation(location)->ResetVariables(); - } - } - - if (/*Settings::HasNightStart TODO:: Randomize Starting Time*/ false) { - if(ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_CHILD) { - RegionTable(RR_ROOT)->childNight = true; - } else { - RegionTable(RR_ROOT)->adultNight = true; - } - } else { - if(ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_CHILD) { - RegionTable(RR_ROOT)->childDay = true; - } else { - RegionTable(RR_ROOT)->adultDay = true; - } - } - } - - bool HasTimePassAccess(uint8_t age) { - for (const RandomizerRegion regionKey : GetAllRegions()) { - auto region = RegionTable(regionKey); - if (region->timePass && ((age == RO_AGE_CHILD && region->Child()) || (age == RO_AGE_ADULT && region->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 RandomizerRegion regionKey : GetAllRegions()) { - auto region = RegionTable(regionKey); - for (auto exit : region->exits) { - if (exit.GetConnectedRegion()->regionName != "Invalid Region") { - std::string parent = exit.GetParentRegion()->regionName; - if (region->childDay) { - parent += " CD"; - } - if (region->childNight) { - parent += " CN"; - } - if (region->adultDay) { - parent += " AD"; - } - if (region->adultNight) { - parent += " AN"; - } - Region* 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 Regions - -Region* RegionTable(const RandomizerRegion regionKey) { - if (regionKey > RR_MAX) { - printf("\x1b[1;1HERROR: AREAKEY TOO BIG"); - } - return &(areaTable[regionKey]); -} - -//Retrieve all the shuffable entrances of a specific type -std::vector GetShuffleableEntrances(Rando::EntranceType type, bool onlyPrimary /*= true*/) { - std::vector entrancesToShuffle = {}; - for (RandomizerRegion region : Regions::GetAllRegions()) { - for (auto& exit : RegionTable(region)->exits) { - if ((exit.GetType() == type || type == Rando::EntranceType::All) && (exit.IsPrimary() || !onlyPrimary) && exit.GetType() != Rando::EntranceType::None) { - entrancesToShuffle.push_back(&exit); - } - } - } - return entrancesToShuffle; -} - -// Get the specific entrance by name -Rando::Entrance* GetEntrance(const std::string name) { - for (RandomizerRegion region : Regions::GetAllRegions()) { - for (auto& exit : RegionTable(region)->exits) { - if (exit.GetName() == name) { - return &exit; - } - } - } - - return nullptr; -} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access.hpp b/soh/soh/Enhancements/randomizer/3drando/location_access.hpp deleted file mode 100644 index 27817d568..000000000 --- a/soh/soh/Enhancements/randomizer/3drando/location_access.hpp +++ /dev/null @@ -1,376 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "../randomizerTypes.h" -#include "../context.h" -#include "../logic.h" - -typedef bool (*ConditionFn)(); - -// I hate this but every alternative I can think of right now is worse -extern Rando::Context* ctx; -extern std::shared_ptr logic; - -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 { - auto ctx = Rando::Context::GetInstance(); - if (ctx->GetOption(RSK_LOGIC_RULES).Is(RO_LOGIC_NO_LOGIC) || ctx->GetOption(RSK_LOGIC_RULES).Is(RO_LOGIC_VANILLA)) { - return true; - } else if (ctx->GetOption(RSK_LOGIC_RULES).Is(RO_LOGIC_GLITCHLESS)) { - return conditions_met[0](); - } else if (ctx->GetOption(RSK_LOGIC_RULES).Is(RO_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; - - return ConditionsMet(); - } - - void EventOccurred() { - *event = true; - } - - bool GetEvent() const { - return *event; - } - -private: - bool* event; - std::vector conditions_met; -}; - -std::string CleanCheckConditionString(std::string condition); - -#define LOCATION(check, condition) LocationAccess(check, {[]{return condition;}}, CleanCheckConditionString(#condition)) - -//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(RandomizerCheck location_, std::vector conditions_met_) - : location(location_), condition_str("") { - conditions_met.resize(2); - for (size_t i = 0; i < conditions_met_.size(); i++) { - conditions_met[i] = conditions_met_[i]; - } - } - - explicit LocationAccess(RandomizerCheck location_, std::vector conditions_met_, std::string condition_str_) - : location(location_), condition_str(condition_str_) { - conditions_met.resize(2); - for (size_t i = 0; i < conditions_met_.size(); i++) { - conditions_met[i] = conditions_met_[i]; - } - } - - bool GetConditionsMet() const { - auto ctx = Rando::Context::GetInstance(); - if (ctx->GetOption(RSK_LOGIC_RULES).Is(RO_LOGIC_NO_LOGIC) || ctx->GetOption(RSK_LOGIC_RULES).Is(RO_LOGIC_VANILLA)) { - return true; - } else if (ctx->GetOption(RSK_LOGIC_RULES).Is(RO_LOGIC_GLITCHLESS)) { - return conditions_met[0](); - } else if (ctx->GetOption(RSK_LOGIC_RULES).Is(RO_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; - - RandomizerCheck GetLocation() const { - return location; - } - - std::string GetConditionStr() const { - return condition_str; - } - -protected: - RandomizerCheck location; - std::vector conditions_met; - std::string condition_str; - - //Makes sure shop locations are buyable - bool CanBuy() const; -}; - -bool CanBuyAnother(RandomizerCheck rc); - -namespace Rando { - class Entrance; - enum class EntranceType; -} - -class Region { -public: - Region(); - Region(std::string regionName_, std::string scene_, std::set areas, - bool timePass_, - std::vector events_, - std::vector locations_, - std::list exits_); - ~Region(); - - std::string regionName; - std::string scene; - std::set areas; - 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;; - - void ApplyTimePass(); - - bool UpdateEvents(); - - void AddExit(RandomizerRegion parentKey, RandomizerRegion newExitKey, ConditionFn condition); - - void RemoveExit(Rando::Entrance* exitToRemove); - - void SetAsPrimary(RandomizerRegion exitToBePrimary); - - Rando::Entrance* GetExit(RandomizerRegion 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(RandomizerRegion exitKey); - - std::set GetAllAreas() const{ - return areas; - } - -RandomizerArea GetFirstArea() const{ - if (areas.empty()){ - assert(false); - return RA_NONE; - } else { - return *areas.begin(); - } - } - - void ReplaceAreas(std::set newAreas) { - areas = newAreas; - } - - //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 Here(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(); - - //heck condition as well as having at least child or adult access - bool hereVal = condition() && (logic->IsAdult || logic->IsChild); - - //set back age variables - logic->IsChild = pastChild; - logic->IsAdult = pastAdult; - - 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); - } - -/*This logic covers checks that exist in the shared areas of MQ spirit from a glitchless standpoint. - This room has Quantum logic that I am currently handling with this function, however this is NOT suitable for glitch logic as it relies on specific ages - In this chunk there are 3 possibilities for passing a check, but first I have to talk about parallel universes. - - In MQ Spirit key logic, we mostly care about 2 possibilities for how the player can spend keys, creating 2 Parralel universes - In the first universe, the player did not enter spirit as adult until after climbing as child, thus child spends keys linearly, only needing 2 to reach statue room. - In the second universe, the player went in as adult, possibly out of logic, and started wasting the keys to lock child out. - These Universes converge when the player has 7 keys (meaning adult can no longer lock child out) and adult is known to be able to reach Statue room. This creates "Certain Access", which is tracked seperatly for each age. - Child Certain Access is simple, if we have 7 keys and child access, it's Certain Access. - Adult Certain Access is also simple, adult is not key locked, so if they make it to a location, it's Certain Access. - Things get complicated when we handle the overlap of the 2 universes, - though an important detail is that if we have Certain Access as either age, we don't need to checked the overlap because overlap logic is strictly stricter than either Certain Access. - - In order to track the first universe, the logic allows technical child access with the minimum number of keys, and then checks in this function for if we have 7 keys to determine if that is Certain or not. - This is for technical reasons, as areas with no access at all will simply not be checked. - Normally we would need to do similar shenanigans to track the second universe, however adult must have go through statue room to waste keys, - so can go back there and get new keys for Child to use if they do, and the navigation logic for shared MQ spirit from Statue Room is very simple for Adult. - Additionally, we don't need to know if adult can actually reach spirit temple or climb to statue room, because if the player can't do that, then universe 2 can't happen anyway, - and if the player does so out of logic, they can do it again, as the only consumable used sets a permanent flag. - - The Adult Navigation logic is as such: - - Broken Wall room is 6 key locked, because if the player tries to spend 6 keys in a way that would block adults access, they would have to give child access instead. - - The child side hammer switch for the time travelling chest is 7 key locked for adult - - Reaching gauntlets hand is 7 key locked - - Going back into big block room is complex, but the only check there is child only so not a concern - - Everything else is possible with basic adult movement, or is impossible for child to reach glitchlessly - Anything 7 key locked does not need to be checked as shared, as all child access is Certain and because of this workaround we don't need to fake Adult access, meaning that is also Certain. - All of this combined means that when checking if adult can reach a location in universe 2, we only have to ask if it is a 6 key locked location or not. - - Knowing all of this this, we can confirm things are logical in 3 different ways: - - If we have Adult Access, we know it is Certain Access, so they can get checks alone. - - If we have 7 keys, child has Certain Access as we know they cannot be locked out, so can get checks alone, otherwise we check the logical overlap - - If Child and Adult can get the check (ignoring actual adult access to the location), and the location is either not 6 key locked or we have 6 keys, we can get the check with the overlap*/ - bool MQSpiritShared(ConditionFn condition, bool IsBrokenWall, bool anyAge = false) { - //if we have Certain Access as child, we can check anyAge and if true, resolve a condition with Here as if adult is here it's also Certain Access - if (logic->SmallKeys(RR_SPIRIT_TEMPLE, 7)){ - if (anyAge){ - return Here(condition); - } - return condition(); - //else, if we are here as adult, we have Certain Access from that and don't need special handling for checking adult - } else if (Adult() && logic->IsAdult){ - return condition(); - //if we do not have Certain Access, we need to check the overlap by seeing if we are both here as child and meet the adult universe's access condition - //We only need to do it as child, as only child access matters for this check, as adult access is assumed based on keys - } else if (Child() && logic->IsChild && (!IsBrokenWall || logic->SmallKeys(RR_SPIRIT_TEMPLE, 6))) { - bool result = false; - //store current age variables - bool pastAdult = logic->IsAdult; - bool pastChild = logic->IsChild; - - //First check if the check is possible as child - logic->IsChild = true; - logic->IsAdult = false; - result = condition(); - //If so, check again as adult. both have to be true for result to be true - if (result) { - logic->IsChild = false; - logic->IsAdult = true; - result = condition(); - } - - //set back age variables - logic->IsChild = pastChild; - logic->IsAdult = pastAdult; - return result; - } - return false; - } -}; - -extern std::array areaTable; -extern std::vector grottoEvents; - -bool Here(const RandomizerRegion region, ConditionFn condition); //RANDOTODO make a less stupid way to check own at either age than self referencing with this -bool MQSpiritSharedStatueRoom(const RandomizerRegion region, ConditionFn condition, bool anyAge = false); -bool MQSpiritSharedBrokenWallRoom(const RandomizerRegion region, ConditionFn condition, bool anyAge = false); -bool CanPlantBean(const RandomizerRegion region); -bool BothAges(const RandomizerRegion region); -bool ChildCanAccess(const RandomizerRegion region); -bool AdultCanAccess(const RandomizerRegion region); -bool HasAccessTo(const RandomizerRegion region); - -#define DAY_NIGHT_CYCLE true -#define NO_DAY_NIGHT_CYCLE false - -namespace Regions { - - extern void AccessReset(); - extern void ResetAllLocations(); - extern bool HasTimePassAccess(uint8_t age); - extern void DumpWorldGraph(std::string str); -} //namespace Exits - -void RegionTable_Init(); -Region* RegionTable(const RandomizerRegion regionKey); -std::vector GetShuffleableEntrances(Rando::EntranceType type, bool onlyPrimary = true); -Rando::Entrance* GetEntrance(const std::string name); - -// Overworld -void RegionTable_Init_LostWoods(); -void RegionTable_Init_HyruleField(); -void RegionTable_Init_CastleTown(); -void RegionTable_Init_Kakariko(); -void RegionTable_Init_DeathMountain(); -void RegionTable_Init_ZorasDomain(); -void RegionTable_Init_GerudoValley(); -// Dungeons -void RegionTable_Init_DekuTree(); -void RegionTable_Init_DodongosCavern(); -void RegionTable_Init_JabuJabusBelly(); -void RegionTable_Init_ForestTemple(); -void RegionTable_Init_FireTemple(); -void RegionTable_Init_WaterTemple(); -void RegionTable_Init_SpiritTemple(); -void RegionTable_Init_ShadowTemple(); -void RegionTable_Init_BottomOfTheWell(); -void RegionTable_Init_IceCavern(); -void RegionTable_Init_GerudoTrainingGrounds(); -void RegionTable_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 deleted file mode 100644 index 7f309c206..000000000 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_bottom_of_the_well.cpp +++ /dev/null @@ -1,300 +0,0 @@ -#include "../location_access.hpp" -#include "../../entrance.h" -#include "../../dungeon.h" - -using namespace Rando; - -void RegionTable_Init_BottomOfTheWell() { - /*-------------------------- - | VANILLA/MQ DECIDER | - ---------------------------*/ - areaTable[RR_BOTTOM_OF_THE_WELL_ENTRYWAY] = Region("Bottom of the Well Entryway", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - //Technically involves an fake wall, but passing it lensless is intended in vanilla and it is well telegraphed - Entrance(RR_BOTTOM_OF_THE_WELL_PERIMETER, {[]{return ctx->GetDungeon(Rando::BOTTOM_OF_THE_WELL)->IsVanilla() && logic->IsChild && logic->CanPassEnemy(RE_BIG_SKULLTULA);}}), - Entrance(RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER, {[]{return ctx->GetDungeon(Rando::BOTTOM_OF_THE_WELL)->IsMQ() && logic->IsChild;}}), - Entrance(RR_KAK_WELL, {[]{return true;}}), - }); - - /*-------------------------- - | VANILLA DUNGEON | - ---------------------------*/ - if (ctx->GetDungeon(Rando::BOTTOM_OF_THE_WELL)->IsVanilla()) { - areaTable[RR_BOTTOM_OF_THE_WELL_PERIMETER] = Region("Bottom of the Well Perimeter", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->StickPot, {[]{return true;}}), - EventAccess(&logic->NutPot, {[]{return true;}}), - EventAccess(&logic->LoweredWaterInsideBotw, {[]{return logic->CanUse(RG_ZELDAS_LULLABY);}}), - }, { - //Locations - LOCATION(RC_BOTTOM_OF_THE_WELL_FRONT_CENTER_BOMBABLE_CHEST, logic->HasExplosives()), - LOCATION(RC_BOTTOM_OF_THE_WELL_FREESTANDING_KEY, (logic->HasItem(RG_BRONZE_SCALE) || logic->LoweredWaterInsideBotw) && logic->CanUse(RG_STICKS) || logic->CanUse(RG_DINS_FIRE)), - LOCATION(RC_BOTTOM_OF_THE_WELL_UNDERWATER_FRONT_CHEST, logic->LoweredWaterInsideBotw), - LOCATION(RC_BOTTOM_OF_THE_WELL_UNDERWATER_LEFT_CHEST, logic->LoweredWaterInsideBotw), - LOCATION(RC_BOTTOM_OF_THE_WELL_NEAR_ENTRANCE_POT_1, logic->CanBreakPots()), - LOCATION(RC_BOTTOM_OF_THE_WELL_NEAR_ENTRANCE_POT_2, logic->CanBreakPots()), - LOCATION(RC_BOTTOM_OF_THE_WELL_UNDERWATER_POT, (logic->CanBreakPots() && logic->LoweredWaterInsideBotw) || logic->CanUse(RG_BOOMERANG)), - }, { - //Exits - Entrance(RR_BOTTOM_OF_THE_WELL_ENTRYWAY, {[]{return logic->IsChild && logic->CanPassEnemy(RE_BIG_SKULLTULA);}}), - Entrance(RR_BOTTOM_OF_THE_WELL_BEHIND_FAKE_WALLS, {[]{return ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH);}}), - Entrance(RR_BOTTOM_OF_THE_WELL_SOUTHWEST_ROOM, {[]{return ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH);}}), - Entrance(RR_BOTTOM_OF_THE_WELL_KEESE_BEAMOS_ROOM, {[]{return logic->IsChild && logic->SmallKeys(RR_BOTTOM_OF_THE_WELL, 3);}}), - Entrance(RR_BOTTOM_OF_THE_WELL_COFFIN_ROOM, {[]{return logic->LoweredWaterInsideBotw || logic->HasItem(RG_BRONZE_SCALE);}}), - Entrance(RR_BOTTOM_OF_THE_WELL_DEAD_HAND_ROOM, {[]{return logic->LoweredWaterInsideBotw && logic->IsChild;}}), - //Falling down into basement requires nothing, but falling down somewhere specific requires lens or lens trick - //kinda questionable given several drops are blocked by rocks, but that's how it was handled before and on N64 - Entrance(RR_BOTTOM_OF_THE_WELL_BASEMENT, {[]{return true;}}), - }); - - //This region combines the Middle with the perimeter's hidden areas. If a warp puts link into the middle without crossing the perimeter or using lens, it will need it's own region - areaTable[RR_BOTTOM_OF_THE_WELL_BEHIND_FAKE_WALLS] = Region("Bottom of the Well Behind Fake Walls", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_BOTTOM_OF_THE_WELL_FRONT_LEFT_FAKE_WALL_CHEST, true), - LOCATION(RC_BOTTOM_OF_THE_WELL_RIGHT_BOTTOM_FAKE_WALL_CHEST, true), - LOCATION(RC_BOTTOM_OF_THE_WELL_COMPASS_CHEST, true), - //N64 has no extra check here, but I can't get past without dealing with the spider or taking a hit - LOCATION(RC_BOTTOM_OF_THE_WELL_CENTER_SKULLTULA_CHEST, logic->CanPassEnemy(RE_BIG_SKULLTULA) || logic->TakeDamage()), - //Not technically behind a wall, but still logically needs lens due to pits - LOCATION(RC_BOTTOM_OF_THE_WELL_BACK_LEFT_BOMBABLE_CHEST, logic->HasExplosives()), - }, { - //Exits - Entrance(RR_BOTTOM_OF_THE_WELL_PERIMETER, {[]{return ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH);}}), - Entrance(RR_BOTTOM_OF_THE_WELL_INNER_ROOMS, {[]{return logic->SmallKeys(RR_BOTTOM_OF_THE_WELL, 3);}}), - Entrance(RR_BOTTOM_OF_THE_WELL_BASEMENT, {[]{return true;}}), - Entrance(RR_BOTTOM_OF_THE_WELL_BASEMENT_PLATFORM, {[]{return ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH);}}), - }); - -//this area can be reached without lens in logic from basement, but that could require silver rupees if they are shuffled. - areaTable[RR_BOTTOM_OF_THE_WELL_SOUTHWEST_ROOM] = Region("Bottom of the Well Southwest Room", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_BOTTOM_OF_THE_WELL_LEFT_SIDE_POT_1, logic->CanBreakPots()), - LOCATION(RC_BOTTOM_OF_THE_WELL_LEFT_SIDE_POT_2, logic->CanBreakPots()), - LOCATION(RC_BOTTOM_OF_THE_WELL_LEFT_SIDE_POT_3, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_BOTTOM_OF_THE_WELL_PERIMETER, {[]{return ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH);}}), - }); - -//passing through this area needs lens, but entering doesn't, so that the fire keese can be killed without crossing the pits if enemy drops are ever shuffled - areaTable[RR_BOTTOM_OF_THE_WELL_KEESE_BEAMOS_ROOM] = Region("Bottom of the Well Keese-Beamos Room", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_BOTTOM_OF_THE_WELL_FIRE_KEESE_CHEST, ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH)), - LOCATION(RC_BOTTOM_OF_THE_WELL_FIRE_KEESE_POT_1, logic->CanBreakPots() && (ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH))), - }, { - //Exits - Entrance(RR_BOTTOM_OF_THE_WELL_PERIMETER, {[]{return logic->IsChild && logic->SmallKeys(RR_BOTTOM_OF_THE_WELL, 3) && (ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH));}}), - Entrance(RR_BOTTOM_OF_THE_WELL_LIKE_LIKE_CAGE, {[]{return ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH);}}), - //not sure if this lens check is needed, these holes are a bit too easy to find, but it matches existing logic - Entrance(RR_BOTTOM_OF_THE_WELL_BASEMENT_USEFUL_BOMB_FLOWERS, {[]{return ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH);}}), - }); - - areaTable[RR_BOTTOM_OF_THE_WELL_LIKE_LIKE_CAGE] = Region("Bottom of the Well Like-Like Cage", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_BOTTOM_OF_THE_WELL_LIKE_LIKE_CHEST, true), - LOCATION(RC_BOTTOM_OF_THE_WELL_GS_LIKE_LIKE_CAGE, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)), - }, { - //Exits - Entrance(RR_BOTTOM_OF_THE_WELL_KEESE_BEAMOS_ROOM, {[]{return true;}}), - }); - -//If the player can voidwarp into one of these rooms they will need splitting up, and Fake walls will need specifying into middle and the rest moved to perimeter - areaTable[RR_BOTTOM_OF_THE_WELL_INNER_ROOMS] = Region("Bottom of the Well Inner Rooms", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->DekuBabaSticks, {[]{return logic->CanGetDekuBabaSticks();}}), - EventAccess(&logic->DekuBabaNuts, {[]{return logic->CanGetDekuBabaNuts();}}), - }, { - //Locations - LOCATION(RC_BOTTOM_OF_THE_WELL_GS_WEST_INNER_ROOM, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)), - LOCATION(RC_BOTTOM_OF_THE_WELL_GS_EAST_INNER_ROOM, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)), - }, { - //Exits - Entrance(RR_BOTTOM_OF_THE_WELL_BEHIND_FAKE_WALLS, {[]{return logic->SmallKeys(RR_BOTTOM_OF_THE_WELL, 3);}}), - }); - - areaTable[RR_BOTTOM_OF_THE_WELL_COFFIN_ROOM] = Region("Bottom of the Well Coffin Room", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_BOTTOM_OF_THE_WELL_FREESTANDING_KEY, logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW)), - LOCATION(RC_BOTTOM_OF_THE_WELL_COFFIN_ROOM_FRONT_LEFT_HEART, logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW)), - LOCATION(RC_BOTTOM_OF_THE_WELL_COFFIN_ROOM_MIDDLE_RIGHT_HEART, logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW)), - }, { - //Exits - Entrance(RR_BOTTOM_OF_THE_WELL_PERIMETER, {[]{return logic->LoweredWaterInsideBotw || logic->HasItem(RG_BRONZE_SCALE);}}), - }); - - areaTable[RR_BOTTOM_OF_THE_WELL_DEAD_HAND_ROOM] = Region("Bottom of the Well Dead Hand Room", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_BOTTOM_OF_THE_WELL_LENS_OF_TRUTH_CHEST, logic->CanKillEnemy(RE_DEAD_HAND)), - LOCATION(RC_BOTTOM_OF_THE_WELL_INVISIBLE_CHEST, (ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH))), - }, { - //Exits - //This assumes we spawned in dead hand's room, if whatever trick made this relevant instead puts us in the previous room, remove the kill Dead Hand check. - Entrance(RR_BOTTOM_OF_THE_WELL_PERIMETER, {[]{return logic->IsChild && logic->CanKillEnemy(RE_DEAD_HAND);}}), - }); - - areaTable[RR_BOTTOM_OF_THE_WELL_BASEMENT] = Region("Bottom of the Well Basement", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_BOTTOM_OF_THE_WELL_MAP_CHEST, logic->BlastOrSmash()), - LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_1, logic->CanBreakPots()), - LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_2, logic->CanBreakPots()), - LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_3, logic->CanBreakPots()), - LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_4, logic->CanBreakPots()), - LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_5, logic->CanBreakPots()), - LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_6, logic->CanBreakPots()), - LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_7, logic->CanBreakPots()), - LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_8, logic->CanBreakPots()), - LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_9, logic->CanBreakPots()), - LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_10, logic->CanBreakPots()), - LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_11, logic->CanBreakPots()), - LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_12, logic->CanBreakPots()), - LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_SUN_FAIRY, logic->CanUse(RG_SUNS_SONG)), - }, { - //Exits - Entrance(RR_BOTTOM_OF_THE_WELL_SOUTHWEST_ROOM, {[]{return logic->IsChild && logic->CanPassEnemy(RE_BIG_SKULLTULA);}}), - //It's possible top abuse boulder's limited range of collision detection to detonate the flowers through the boulder with bow, but this is a glitch - //the exact range is just past the furthest away plank in the green goo section - Entrance(RR_BOTTOM_OF_THE_WELL_BASEMENT_USEFUL_BOMB_FLOWERS, {[]{return Here(RR_BOTTOM_OF_THE_WELL_BASEMENT, []{return logic->BlastOrSmash() || logic->CanUse(RG_DINS_FIRE) || (logic->CanUse(RG_STICKS) && ctx->GetTrickOption(RT_BOTW_BASEMENT));});}}), - }); - - areaTable[RR_BOTTOM_OF_THE_WELL_BASEMENT_USEFUL_BOMB_FLOWERS] = Region("Bottom of the Well Basement Useful Bomb Flowers", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - //Assumes RR_BOTTOM_OF_THE_WELL_BASEMENT access - LOCATION(RC_BOTTOM_OF_THE_WELL_MAP_CHEST, logic->HasItem(RG_GORONS_BRACELET)), - }, { - //Exits - Entrance(RR_BOTTOM_OF_THE_WELL_BASEMENT, {[]{return logic->CanDetonateUprightBombFlower();}}), - }); - - areaTable[RR_BOTTOM_OF_THE_WELL_BASEMENT_PLATFORM] = Region("Bottom of the Well Basement Platform", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_PLATFORM_LEFT_RUPEE, true), - LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_PLATFORM_BACK_LEFT_RUPEE, true), - LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_PLATFORM_MIDDLE_RUPEE, true), - LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_PLATFORM_BACK_RIGHT_RUPEE, true), - LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_PLATFORM_RIGHT_RUPEE, true), - }, { - //Exits - Entrance(RR_BOTTOM_OF_THE_WELL_BASEMENT, {[]{return true;}}), - }); - } - - /*--------------------------- - | MASTER QUEST DUNGEON | - ---------------------------*/ - if (ctx->GetDungeon(Rando::BOTTOM_OF_THE_WELL)->IsMQ()) { - areaTable[RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER] = Region("Bottom of the Well MQ Perimeter", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, { - //Events - //technically obsolete due to a wonder item fairy which only needs a projectile, but we don't have an event var for it yet - EventAccess(&logic->FairyPot, {[]{return Here(RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER, []{return logic->BlastOrSmash();}) && logic->CanHitEyeTargets();}}), - //It is possible to hit the water switch with a pot from RR_BOTTOM_OF_THE_WELL_MQ_MIDDLE, however the hitbox for making it activate is very unintuitive - //You have to throw the pot from further back to hit the switch from the front instead of the top, trying to hit the "fingers" directly - //This unintuitiveness means it should be a trick. ZL is needed to get a clear path to carry the pot - EventAccess(&logic->LoweredWaterInsideBotw, {[]{return logic->CanJumpslash() || logic->CanUseProjectile();}}), - }, { - //Locations - //Implies CanBreakPots() - LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_OUTER_LOBBY_POT, Here(RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER, []{return logic->BlastOrSmash();}) && logic->CanHitEyeTargets()), - LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_BOMB_LEFT_HEART, logic->HasExplosives()), - LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_BOMB_RIGHT_HEART, logic->HasExplosives()), - }, { - //Exits - Entrance(RR_BOTTOM_OF_THE_WELL_ENTRYWAY, {[]{return logic->IsChild;}}), - Entrance(RR_BOTTOM_OF_THE_WELL_MQ_WEST_ROOM_SWITCH, {[]{return Here(RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER, []{return logic->BlastOrSmash();}) && logic->CanPassEnemy(RE_BIG_SKULLTULA);}}), - Entrance(RR_BOTTOM_OF_THE_WELL_MQ_COFFIN_ROOM, {[]{return (logic->LoweredWaterInsideBotw || logic->HasItem(RG_BRONZE_SCALE)) && logic->SmallKeys(RR_BOTTOM_OF_THE_WELL, 2);}}), - Entrance(RR_BOTTOM_OF_THE_WELL_MQ_LOCKED_CAGE, {[]{return logic->IsChild && logic->SmallKeys(RR_BOTTOM_OF_THE_WELL, 2) && logic->CanUseProjectile();}}), - Entrance(RR_BOTTOM_OF_THE_WELL_MQ_DEAD_HAND_ROOM, {[]{return logic->IsChild && logic->LoweredWaterInsideBotw;}}), - Entrance(RR_BOTTOM_OF_THE_WELL_MQ_MIDDLE, {[]{return logic->CanUse(RG_ZELDAS_LULLABY);}}), - Entrance(RR_BOTTOM_OF_THE_WELL_MQ_BASEMENT, {[]{return true;}}), - }); - - areaTable[RR_BOTTOM_OF_THE_WELL_MQ_WEST_ROOM_SWITCH] = Region("Bottom of the Well MQ West Room Switch", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->OpenedWestRoomMQBotw, {[]{return true;}}), - }, {}, { - //Exits - Entrance(RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER, {[]{return logic->BlastOrSmash() && (logic->CanPassEnemy(RE_BIG_SKULLTULA) || ctx->GetTrickOption(RT_BOTW_MQ_PITS));}}), - Entrance(RR_BOTTOM_OF_THE_WELL_MQ_MIDDLE, {[]{return (bool)ctx->GetTrickOption(RT_BOTW_MQ_PITS);}}), - Entrance(RR_BOTTOM_OF_THE_WELL_MQ_BASEMENT, {[]{return true;}}), - }); - - areaTable[RR_BOTTOM_OF_THE_WELL_MQ_COFFIN_ROOM] = Region("Bottom of the Well MQ Coffin Room", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_GS_COFFIN_ROOM, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)), - LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_COFFIN_ROOM_FRONT_RIGHT_HEART, logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW)), - LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_COFFIN_ROOM_MIDDLE_LEFT_HEART, logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW)), - }, { - //Exits - Entrance(RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER, {[]{return (logic->LoweredWaterInsideBotw || logic->HasItem(RG_BRONZE_SCALE)) && logic->SmallKeys(RR_BOTTOM_OF_THE_WELL, 2);}}), - }); - - areaTable[RR_BOTTOM_OF_THE_WELL_MQ_LOCKED_CAGE] = Region("Bottom of the Well MQ Locked Cage", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->OpenedMiddleHoleMQBotw, {[]{return logic->HasExplosives();}}), - }, {}, { - //Exits - Entrance(RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER, {[]{return logic->IsChild && logic->SmallKeys(RR_BOTTOM_OF_THE_WELL, 2);}}), - }); - - areaTable[RR_BOTTOM_OF_THE_WELL_MQ_DEAD_HAND_ROOM] = Region("Bottom of the Well MQ Dead Hand Room", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_COMPASS_CHEST, logic->CanKillEnemy(RE_DEAD_HAND)), - LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_DEAD_HAND_FREESTANDING_KEY, logic->HasExplosives() || (ctx->GetTrickOption(RT_BOTW_MQ_DEADHAND_KEY) && logic->CanUse(RG_BOOMERANG))), - }, { - //Exits - //This assumes we spawned in dead hand's room, if whatever trick made this relevant instead puts us in the previous room, remove the kill Dead Hand check. - Entrance(RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER, {[]{return logic->IsChild && logic->CanKillEnemy(RE_DEAD_HAND);}}), - }); - - areaTable[RR_BOTTOM_OF_THE_WELL_MQ_MIDDLE] = Region("Bottom of the Well MQ Middle", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_MAP_CHEST, true), - //This location technically involves an invisible platform, but it's intended to do lensless in vanilla and is clearly signposted by pots. - LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_EAST_INNER_ROOM_FREESTANDING_KEY, true), - //The enemies in this room are invisible and crowd around the player, being awkward to deal with blind unless you already know how. - //the right wall is safe, and can be followed to get behind the grave which you can then pull easily assuming you can tank invisible keese - //Using a deku nut however stuns everything easily. and if you have a melee weapon you can kill the skull through the grave then grab the drop - //though it can be hard to tell where the safe direct path to the grave is without lens. - //Also you get cheap shotted on entry sometimes. - //An MQ lens trick is recommended here, and a review of this room for OHKO logic what that is added is advised. - //In the meantime I assume damage taken or the easy answer (nuts) - LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_GS_WEST_INNER_ROOM, logic->OpenedWestRoomMQBotw && (logic->TakeDamage() || logic->CanUse(RG_NUTS)) && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)), - LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_INNER_LOBBY_POT_1, logic->CanBreakPots()), - LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_INNER_LOBBY_POT_2, logic->CanBreakPots()), - LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_INNER_LOBBY_POT_3, logic->CanBreakPots()), - LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_EAST_INNER_ROOM_POT_1, logic->CanBreakPots()), - LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_EAST_INNER_ROOM_POT_2, logic->CanBreakPots()), - LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_EAST_INNER_ROOM_POT_3, logic->CanBreakPots()), - LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_CELL_SUN_FAIRY, logic->CanUse(RG_SUNS_SONG)), - }, { - //Exits - //If a relevant trick causes you to be able to warp into here without going through PERIMETER, a new eventAccess will be needed for lowering the gates with ZL - Entrance(RR_BOTTOM_OF_THE_WELL_MQ_BASEMENT_SWITCH_PLATFORM, {[]{return logic->OpenedMiddleHoleMQBotw;}}), - Entrance(RR_BOTTOM_OF_THE_WELL_MQ_BASEMENT, {[]{return true;}}), - }); - - areaTable[RR_BOTTOM_OF_THE_WELL_MQ_BASEMENT] = Region("Bottom of the Well MQ Basement", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - //behind invisible big skulltulas, but with navi spotting it's easy to avoid them, or at worst, tank your way through as they do not block the path - LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_GS_BASEMENT, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)), - LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_BASEMENT_HALLWAY_FRONT_HEART, true), - LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_BASEMENT_HALLWAY_LEFT_HEART, true), - LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_BASEMENT_HALLWAY_RIGHT_HEART, true), - LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_BASEMENT_SUN_FAIRY, logic->CanUse(RG_SUNS_SONG)), - }, { - //Exits - Entrance(RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER, {[]{return true;}}), - }); - - areaTable[RR_BOTTOM_OF_THE_WELL_MQ_BASEMENT_SWITCH_PLATFORM] = Region("Bottom of the Well MQ Basement Switch Platform", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - //Assumes RR_BOTTOM_OF_THE_WELL_MQ_BASEMENT access - //it is technically possible to get the chest before you get screamed at without rolling, but hard enough to be a trick if that is the requirement for something to be logical - //With some kind of movement tech it's much easier, easy enough to be default logic, as the redeads don't lock on immediately in addition to the extra speed - //leaving with no requirements for now but up for discussion. - LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_LENS_OF_TRUTH_CHEST, true), - }, { - //Exits - Entrance(RR_BOTTOM_OF_THE_WELL_MQ_BASEMENT, {[]{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 deleted file mode 100644 index 2e9178d6f..000000000 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_castle_town.cpp +++ /dev/null @@ -1,376 +0,0 @@ -#include "../location_access.hpp" -#include "../../entrance.h" - -using namespace Rando; - -void RegionTable_Init_CastleTown() { - areaTable[RR_MARKET_ENTRANCE] = Region("Market Entrance", "Market Entrance", {RA_THE_MARKET}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_HYRULE_FIELD, {[]{return logic->IsAdult || logic->AtDay;}}), - Entrance(RR_THE_MARKET, {[]{return true;}}), - Entrance(RR_MARKET_GUARD_HOUSE, {[]{return true;}}), - }); - - areaTable[RR_THE_MARKET] = Region("Market", "Market", {RA_THE_MARKET}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_MARKET_ENTRANCE, {[]{return true;}}), - Entrance(RR_TOT_ENTRANCE, {[]{return true;}}), - Entrance(RR_CASTLE_GROUNDS, {[]{return true;}}), - Entrance(RR_MARKET_BAZAAR, {[]{return logic->IsChild && logic->AtDay;}}), - Entrance(RR_MARKET_MASK_SHOP, {[]{return logic->IsChild && logic->AtDay;}}), - Entrance(RR_MARKET_SHOOTING_GALLERY, {[]{return logic->IsChild && logic->AtDay;}}), - Entrance(RR_MARKET_BOMBCHU_BOWLING, {[]{return logic->IsChild;}}), - Entrance(RR_MARKET_TREASURE_CHEST_GAME, {[]{return logic->IsChild && logic->AtNight;}}), - Entrance(RR_MARKET_POTION_SHOP, {[]{return logic->IsChild && logic->AtDay;}}), - Entrance(RR_MARKET_BACK_ALLEY, {[]{return logic->IsChild;}}), - }); - - areaTable[RR_MARKET_BACK_ALLEY] = Region("Market Back Alley", "Market", {RA_THE_MARKET}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_THE_MARKET, {[]{return true;}}), - Entrance(RR_MARKET_BOMBCHU_SHOP, {[]{return logic->AtNight;}}), - Entrance(RR_MARKET_DOG_LADY_HOUSE, {[]{return true;}}), - Entrance(RR_MARKET_MAN_IN_GREEN_HOUSE, {[]{return logic->AtNight;}}), - }); - - areaTable[RR_TOT_ENTRANCE] = Region("ToT Entrance", "ToT Entrance", {RA_THE_MARKET}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->GossipStoneFairy, {[]{return logic->CallGossipFairyExceptSuns();}}), - }, { - //Locations - LOCATION(RC_TOT_LEFTMOST_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns() || (logic->CanUse(RG_SUNS_SONG) && logic->IsAdult)), - LOCATION(RC_TOT_LEFTMOST_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_TOT_LEFT_CENTER_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns() || (logic->CanUse(RG_SUNS_SONG) && logic->IsAdult)), - LOCATION(RC_TOT_LEFT_CENTER_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_TOT_RIGHT_CENTER_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns() || (logic->CanUse(RG_SUNS_SONG) && logic->IsAdult)), - LOCATION(RC_TOT_RIGHT_CENTER_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_TOT_RIGHTMOST_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns() || (logic->CanUse(RG_SUNS_SONG) && logic->IsAdult)), - LOCATION(RC_TOT_RIGHTMOST_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_TOT_LEFTMOST_GOSSIP_STONE, true), - LOCATION(RC_TOT_LEFT_CENTER_GOSSIP_STONE, true), - LOCATION(RC_TOT_RIGHT_CENTER_GOSSIP_STONE, true), - LOCATION(RC_TOT_RIGHTMOST_GOSSIP_STONE, true), - }, { - //Exits - Entrance(RR_THE_MARKET, {[]{return true;}}), - Entrance(RR_TEMPLE_OF_TIME, {[]{return true;}}), - }); - - areaTable[RR_TEMPLE_OF_TIME] = Region("Temple of Time", "Temple of Time", {RA_TEMPLE_OF_TIME}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_TOT_LIGHT_ARROWS_CUTSCENE, logic->IsAdult && logic->CanTriggerLACS()), - LOCATION(RC_ALTAR_HINT_CHILD, logic->IsChild), - LOCATION(RC_ALTAR_HINT_ADULT, logic->IsAdult), - LOCATION(RC_TOT_SHEIK_HINT, logic->IsAdult), - }, { - //Exits - Entrance(RR_TOT_ENTRANCE, {[]{return true;}}), - Entrance(RR_TOT_BEYOND_DOOR_OF_TIME, {[]{return ctx->GetOption(RSK_DOOR_OF_TIME).Is(RO_DOOROFTIME_OPEN) || (logic->CanUse(RG_SONG_OF_TIME) && (ctx->GetOption(RSK_DOOR_OF_TIME).Is(RO_DOOROFTIME_SONGONLY) || (logic->StoneCount() == 3 && logic->HasItem(RG_OCARINA_OF_TIME))));}}), - }); - - areaTable[RR_TOT_BEYOND_DOOR_OF_TIME] = Region("Beyond Door of Time", "Beyond Door of Time", {RA_TEMPLE_OF_TIME}, NO_DAY_NIGHT_CYCLE, { - //Events - //EventAccess(&logic->TimeTravel, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_TOT_MASTER_SWORD, logic->IsAdult), - LOCATION(RC_GIFT_FROM_RAURU, logic->IsAdult), - LOCATION(RC_SHEIK_AT_TEMPLE, logic->HasItem(RG_FOREST_MEDALLION) && logic->IsAdult), - }, { - //Exits - Entrance(RR_TEMPLE_OF_TIME, {[]{return true;}}), - }); - -//With multi-area support {RA_CASTLE_GROUNDS} is not strictly required anymore, as any interior here could inherit both -//{RA_HYRULE_CASTLE} and {RA_OUTSIDE_GANONS_CASTLE}, but an setting to merge the latter 2 into the former may be preffered - areaTable[RR_CASTLE_GROUNDS] = Region("Castle Grounds", "Castle Grounds", {RA_CASTLE_GROUNDS}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_THE_MARKET, {[]{return true;}}), - Entrance(RR_HYRULE_CASTLE_GROUNDS, {[]{return logic->IsChild;}}), - Entrance(RR_GANONS_CASTLE_GROUNDS, {[]{return logic->IsAdult;}}), - }); - - areaTable[RR_HYRULE_CASTLE_GROUNDS] = Region("Hyrule Castle Grounds", "Castle Grounds", {RA_HYRULE_CASTLE}, DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->GossipStoneFairy, {[]{return logic->CallGossipFairy();}}), - EventAccess(&logic->ButterflyFairy, {[]{return logic->ButterflyFairy || logic->CanUse(RG_STICKS);}}), - EventAccess(&logic->BugRock, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_HC_MALON_EGG, true), - LOCATION(RC_HC_GS_TREE, logic->IsChild && logic->CanAttack()), - LOCATION(RC_HC_MALON_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), - LOCATION(RC_HC_MALON_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_HC_ROCK_WALL_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), - LOCATION(RC_HC_ROCK_WALL_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_HC_MALON_GOSSIP_STONE, true), - LOCATION(RC_HC_ROCK_WALL_GOSSIP_STONE, true), - }, { - //Exits - Entrance(RR_CASTLE_GROUNDS, {[]{return true;}}), - Entrance(RR_HC_GARDEN, {[]{return logic->CanUse(RG_WEIRD_EGG) || !ctx->GetOption(RSK_SHUFFLE_WEIRD_EGG) || (ctx->GetTrickOption(RT_DAMAGE_BOOST_SIMPLE) && logic->HasExplosives() && logic->CanJumpslash());}}), - Entrance(RR_HC_GREAT_FAIRY_FOUNTAIN, {[]{return logic->BlastOrSmash();}}), - Entrance(RR_HC_STORMS_GROTTO, {[]{return logic->CanOpenStormsGrotto();}}), - }); - - areaTable[RR_HC_GARDEN] = Region("HC Garden", "Castle Grounds", {RA_HYRULE_CASTLE}, NO_DAY_NIGHT_CYCLE, { - //Events - }, { - //Locations - LOCATION(RC_HC_ZELDAS_LETTER, true), - LOCATION(RC_SONG_FROM_IMPA, true), - }, { - //Exits - Entrance(RR_HYRULE_CASTLE_GROUNDS, {[]{return true;}}), - }); - - areaTable[RR_HC_GREAT_FAIRY_FOUNTAIN] = Region("HC Great Fairy Fountain", "HC Great Fairy Fountain", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_HC_GREAT_FAIRY_REWARD, logic->CanUse(RG_ZELDAS_LULLABY)), - }, { - //Exits - Entrance(RR_CASTLE_GROUNDS, {[]{return true;}}), - }); - - areaTable[RR_HC_STORMS_GROTTO] = Region("HC Storms Grotto", "HC Storms Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_HC_GS_STORMS_GROTTO, logic->CanUse(RG_BOOMERANG) && ctx->GetTrickOption(RT_HC_STORMS_GS)), - }, { - //Exits - Entrance(RR_CASTLE_GROUNDS, {[]{return true;}}), - Entrance(RR_HC_STORMS_GROTTO_BEHIND_WALLS, {[]{return logic->CanBreakMudWalls();}}), - }); - - areaTable[RR_HC_STORMS_GROTTO_BEHIND_WALLS] = Region("HC Storms Grotto Behind Walls", "HC Storms Grotto", {}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->NutPot, {[]{return true;}}), - EventAccess(&logic->GossipStoneFairy, {[]{return logic->CallGossipFairy();}}), - EventAccess(&logic->WanderingBugs, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_HC_GS_STORMS_GROTTO, logic->HookshotOrBoomerang()), - LOCATION(RC_HC_STORMS_GROTTO_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), - LOCATION(RC_HC_STORMS_GROTTO_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_HC_STORMS_GROTTO_GOSSIP_STONE, true), - LOCATION(RC_HC_STORMS_GROTTO_POT_1, logic->CanBreakPots()), - LOCATION(RC_HC_STORMS_GROTTO_POT_2, logic->CanBreakPots()), - LOCATION(RC_HC_STORMS_GROTTO_POT_3, logic->CanBreakPots()), - LOCATION(RC_HC_STORMS_GROTTO_POT_4, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_CASTLE_GROUNDS, {[]{return true;}}), - }); - - areaTable[RR_GANONS_CASTLE_GROUNDS] = Region("Ganon's Castle Grounds", "Castle Grounds", {RA_OUTSIDE_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { - EventAccess(&logic->BuiltRainbowBridge, {[]{return logic->CanBuildRainbowBridge();}}), - }, { - //Locations - LOCATION(RC_OGC_GS, logic->CanJumpslashExceptHammer() || logic->CanUseProjectile() || (logic->CanShield() && logic->CanUse(RG_MEGATON_HAMMER)) || logic->CanUse(RG_DINS_FIRE)), - }, { - //Exits - Entrance(RR_CASTLE_GROUNDS, {[]{return logic->AtNight;}}), - Entrance(RR_OGC_GREAT_FAIRY_FOUNTAIN, {[]{return logic->CanUse(RG_GOLDEN_GAUNTLETS) && logic->AtNight;}}), - Entrance(RR_GANONS_CASTLE_LEDGE, {[]{return logic->BuiltRainbowBridge;}}), - }); - - areaTable[RR_OGC_GREAT_FAIRY_FOUNTAIN] = Region("OGC Great Fairy Fountain", "OGC Great Fairy Fountain", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_OGC_GREAT_FAIRY_REWARD, logic->CanUse(RG_ZELDAS_LULLABY)), - }, { - //Exits - Entrance(RR_CASTLE_GROUNDS, {[]{return true;}}), - }); - - areaTable[RR_CASTLE_GROUNDS_FROM_GANONS_CASTLE] = Region("Castle Grounds From Ganon's Castle", "Castle Grounds From Ganon's Castle", {RA_CASTLE_GROUNDS}, NO_DAY_NIGHT_CYCLE, {}, {}, { - // Exits - Entrance(RR_HYRULE_CASTLE_GROUNDS, { [] { return logic->IsChild; }}), - Entrance(RR_GANONS_CASTLE_LEDGE, { [] { return logic->IsAdult; }}), - }); - - areaTable[RR_GANONS_CASTLE_LEDGE] = Region("Ganon's Castle Ledge", "OGC Ganon's Castle Ledge", {RA_OUTSIDE_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, - {}, {}, { - // Exits - Entrance(RR_GANONS_CASTLE_GROUNDS, {[]{return logic->BuiltRainbowBridge;}}), - Entrance(RR_GANONS_CASTLE_ENTRYWAY, {[]{return logic->IsAdult;}}), - }); - - areaTable[RR_MARKET_GUARD_HOUSE] = Region("Market Guard House", "Market Guard House", {}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->CanEmptyBigPoes, {[]{return logic->IsAdult;}}), - }, { - //Locations - LOCATION(RC_MARKET_10_BIG_POES, logic->IsAdult && logic->BigPoeKill), - LOCATION(RC_MARKET_GS_GUARD_HOUSE, logic->IsChild), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_1, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_2, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_3, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_4, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_5, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_6, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_7, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_8, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_9, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_10, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_11, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_12, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_13, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_14, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_15, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_16, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_17, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_18, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_19, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_20, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_21, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_22, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_23, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_24, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_25, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_26, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_27, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_28, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_29, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_30, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_31, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_32, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_33, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_34, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_35, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_36, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_37, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_38, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_39, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_40, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_41, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_42, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_43, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_44, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_ADULT_POT_1, logic->IsAdult && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_ADULT_POT_2, logic->IsAdult && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_ADULT_POT_3, logic->IsAdult && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_ADULT_POT_4, logic->IsAdult && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_ADULT_POT_5, logic->IsAdult && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_ADULT_POT_6, logic->IsAdult && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_ADULT_POT_7, logic->IsAdult && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_ADULT_POT_8, logic->IsAdult && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_ADULT_POT_9, logic->IsAdult && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_ADULT_POT_10, logic->IsAdult && logic->CanBreakPots()), - LOCATION(RC_MK_GUARD_HOUSE_ADULT_POT_11, logic->IsAdult && logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_MARKET_ENTRANCE, {[]{return true;}}), - }); - - areaTable[RR_MARKET_BAZAAR] = Region("Market Bazaar", "Market Bazaar", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_MARKET_BAZAAR_ITEM_1, true), - LOCATION(RC_MARKET_BAZAAR_ITEM_2, true), - LOCATION(RC_MARKET_BAZAAR_ITEM_3, true), - LOCATION(RC_MARKET_BAZAAR_ITEM_4, true), - LOCATION(RC_MARKET_BAZAAR_ITEM_5, true), - LOCATION(RC_MARKET_BAZAAR_ITEM_6, true), - LOCATION(RC_MARKET_BAZAAR_ITEM_7, true), - LOCATION(RC_MARKET_BAZAAR_ITEM_8, true), - }, { - //Exits - Entrance(RR_THE_MARKET, {[]{return true;}}), - }); - - areaTable[RR_MARKET_MASK_SHOP] = Region("Market Mask Shop", "Market Mask Shop", {}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->SkullMask, {[]{return logic->SkullMask || (logic->HasItem(RG_ZELDAS_LETTER) && (ctx->GetOption(RSK_COMPLETE_MASK_QUEST) || ChildCanAccess(RR_KAKARIKO_VILLAGE)));}}), //RANDOTODO Complete mask quest does not need this location, so should be tied to link's pocket - EventAccess(&logic->MaskOfTruth, {[]{return logic->MaskOfTruth || (logic->SkullMask && (ctx->GetOption(RSK_COMPLETE_MASK_QUEST) || (ChildCanAccess(RR_THE_LOST_WOODS) && logic->CanUse(RG_SARIAS_SONG) && RegionTable(RR_THE_GRAVEYARD)->childDay && ChildCanAccess(RR_HYRULE_FIELD) && logic->StoneCount() == 3)));}}), - }, { - LOCATION(RC_MASK_SHOP_HINT, true), - }, { - //Exits - Entrance(RR_THE_MARKET, {[]{return true;}}), - }); - - areaTable[RR_MARKET_SHOOTING_GALLERY] = Region("Market Shooting Gallery", "Market Shooting Gallery", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_MARKET_SHOOTING_GALLERY_REWARD, logic->IsChild && logic->HasItem(RG_CHILD_WALLET)), - }, { - //Exits - Entrance(RR_THE_MARKET, {[]{return true;}}), - }); - - areaTable[RR_MARKET_BOMBCHU_BOWLING] = Region("Market Bombchu Bowling", "Market Bombchu Bowling", {}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->CouldPlayBowling, {[]{return (logic->HasItem(RG_CHILD_WALLET));}}), - }, { - //Locations - LOCATION(RC_MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, logic->CouldPlayBowling && logic->BombchusEnabled()), - LOCATION(RC_MARKET_BOMBCHU_BOWLING_SECOND_PRIZE, logic->CouldPlayBowling && logic->BombchusEnabled()), - }, { - //Exits - Entrance(RR_THE_MARKET, {[]{return true;}}), - }); - - areaTable[RR_MARKET_POTION_SHOP] = Region("Market Potion Shop", "Market Potion Shop", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_MARKET_POTION_SHOP_ITEM_1, true), - LOCATION(RC_MARKET_POTION_SHOP_ITEM_2, true), - LOCATION(RC_MARKET_POTION_SHOP_ITEM_3, true), - LOCATION(RC_MARKET_POTION_SHOP_ITEM_4, true), - LOCATION(RC_MARKET_POTION_SHOP_ITEM_5, true), - LOCATION(RC_MARKET_POTION_SHOP_ITEM_6, true), - LOCATION(RC_MARKET_POTION_SHOP_ITEM_7, true), - LOCATION(RC_MARKET_POTION_SHOP_ITEM_8, true), - }, { - //Exits - Entrance(RR_THE_MARKET, {[]{return true;}}), - }); - - areaTable[RR_MARKET_TREASURE_CHEST_GAME] = Region("Market Treasure Chest Game", "Market Treasure Chest Game", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GREG_HINT, logic->HasItem(RG_CHILD_WALLET)), - LOCATION(RC_MARKET_TREASURE_CHEST_GAME_REWARD, logic->HasItem(RG_CHILD_WALLET) && ((logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 6)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)))), - LOCATION(RC_MARKET_TREASURE_CHEST_GAME_KEY_1, logic->HasItem(RG_CHILD_WALLET) && ((ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)))), - LOCATION(RC_MARKET_TREASURE_CHEST_GAME_ITEM_1, logic->HasItem(RG_CHILD_WALLET) && ((ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)))), - LOCATION(RC_MARKET_TREASURE_CHEST_GAME_KEY_2, logic->HasItem(RG_CHILD_WALLET) && ((ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 2)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)))), - LOCATION(RC_MARKET_TREASURE_CHEST_GAME_ITEM_2, logic->HasItem(RG_CHILD_WALLET) && ((ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 2)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)))), - LOCATION(RC_MARKET_TREASURE_CHEST_GAME_KEY_3, logic->HasItem(RG_CHILD_WALLET) && ((ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 3)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)))), - LOCATION(RC_MARKET_TREASURE_CHEST_GAME_ITEM_3, logic->HasItem(RG_CHILD_WALLET) && ((ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 3)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)))), - LOCATION(RC_MARKET_TREASURE_CHEST_GAME_KEY_4, logic->HasItem(RG_CHILD_WALLET) && ((ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 4)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)))), - LOCATION(RC_MARKET_TREASURE_CHEST_GAME_ITEM_4, logic->HasItem(RG_CHILD_WALLET) && ((ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 4)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)))), - LOCATION(RC_MARKET_TREASURE_CHEST_GAME_KEY_5, logic->HasItem(RG_CHILD_WALLET) && ((ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 5)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)))), - LOCATION(RC_MARKET_TREASURE_CHEST_GAME_ITEM_5, logic->HasItem(RG_CHILD_WALLET) && ((ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 5)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)))), - }, { - //Exits - Entrance(RR_THE_MARKET, {[]{return true;}}), - }); - - areaTable[RR_MARKET_BOMBCHU_SHOP] = Region("Market Bombchu Shop", "Market Bombchu Shop", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_MARKET_BOMBCHU_SHOP_ITEM_1, true), - LOCATION(RC_MARKET_BOMBCHU_SHOP_ITEM_2, true), - LOCATION(RC_MARKET_BOMBCHU_SHOP_ITEM_3, true), - LOCATION(RC_MARKET_BOMBCHU_SHOP_ITEM_4, true), - LOCATION(RC_MARKET_BOMBCHU_SHOP_ITEM_5, true), - LOCATION(RC_MARKET_BOMBCHU_SHOP_ITEM_6, true), - LOCATION(RC_MARKET_BOMBCHU_SHOP_ITEM_7, true), - LOCATION(RC_MARKET_BOMBCHU_SHOP_ITEM_8, true), - }, { - //Exits - Entrance(RR_MARKET_BACK_ALLEY, {[]{return true;}}), - }); - - areaTable[RR_MARKET_DOG_LADY_HOUSE] = Region("Market Dog Lady House", "Market Dog Lady House", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_MARKET_LOST_DOG, logic->IsChild && logic->AtNight), - }, { - //Exits - Entrance(RR_MARKET_BACK_ALLEY, {[]{return true;}}), - }); - - areaTable[RR_MARKET_MAN_IN_GREEN_HOUSE] = Region("Market Man in Green House", "Market Man in Green House", {}, NO_DAY_NIGHT_CYCLE, {}, { - // Locations - LOCATION(RC_MK_BACK_ALLEY_HOUSE_POT_1, logic->CanBreakPots()), - LOCATION(RC_MK_BACK_ALLEY_HOUSE_POT_2, logic->CanBreakPots()), - LOCATION(RC_MK_BACK_ALLEY_HOUSE_POT_3, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_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 deleted file mode 100644 index 9d443937d..000000000 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_death_mountain.cpp +++ /dev/null @@ -1,346 +0,0 @@ -#include "../location_access.hpp" -#include "../../entrance.h" - -using namespace Rando; - -void RegionTable_Init_DeathMountain() { - areaTable[RR_DEATH_MOUNTAIN_TRAIL] = Region("Death Mountain", "Death Mountain", {RA_DEATH_MOUNTAIN_TRAIL}, DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->BeanPlantFairy, {[]{return logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS) && (logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET));}}), - }, { - //Locations - LOCATION(RC_DMT_CHEST, logic->BlastOrSmash() || (ctx->GetTrickOption(RT_DMT_BOMBABLE) && logic->IsChild && logic->HasItem(RG_GORONS_BRACELET))), - LOCATION(RC_DMT_FREESTANDING_POH, logic->TakeDamage() || logic->CanUse(RG_HOVER_BOOTS) || (logic->IsAdult && CanPlantBean(RR_DEATH_MOUNTAIN_TRAIL) && (logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET)))), - LOCATION(RC_DMT_GS_BEAN_PATCH, logic->CanSpawnSoilSkull() && (logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET) || (ctx->GetTrickOption(RT_DMT_SOIL_GS) && (logic->TakeDamage() || logic->CanUse(RG_HOVER_BOOTS)) && logic->CanUse(RG_BOOMERANG)))), - LOCATION(RC_DMT_GS_NEAR_KAK, logic->BlastOrSmash()), - LOCATION(RC_DMT_GS_ABOVE_DODONGOS_CAVERN, logic->IsAdult && logic->AtNight && (logic->CanUse(RG_MEGATON_HAMMER) || (ctx->GetTrickOption(RT_DMT_HOOKSHOT_LOWER_GS) && logic->CanUse(RG_HOOKSHOT)) || (ctx->GetTrickOption(RT_DMT_BEAN_LOWER_GS) && CanPlantBean(RR_DEATH_MOUNTAIN_TRAIL)) || (ctx->GetTrickOption(RT_DMT_HOVERS_LOWER_GS) && logic->CanUse(RG_HOVER_BOOTS)) || ctx->GetTrickOption(RT_DMT_JS_LOWER_GS)) && logic->CanGetNightTimeGS()), - LOCATION(RC_DMT_BLUE_RUPEE, logic->IsChild && logic->BlastOrSmash()), - LOCATION(RC_DMT_RED_RUPEE, logic->IsChild && logic->BlastOrSmash()), - LOCATION(RC_DMT_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS) && (logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET))), - LOCATION(RC_DMT_BEAN_SPROUT_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS) && (logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET))), - LOCATION(RC_DMT_BEAN_SPROUT_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS) && (logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET))), - LOCATION(RC_DMT_FLAG_SUN_FAIRY, logic->CanUse(RG_SUNS_SONG)), - }, { - //Exits - Entrance(RR_KAK_BEHIND_GATE, {[]{return true;}}), - Entrance(RR_GORON_CITY, {[]{return true;}}), - Entrance(RR_DEATH_MOUNTAIN_SUMMIT, {[]{return Here(RR_DEATH_MOUNTAIN_TRAIL, []{return logic->BlastOrSmash();}) || (logic->IsAdult && ((CanPlantBean(RR_DEATH_MOUNTAIN_TRAIL) && logic->HasItem(RG_GORONS_BRACELET)) || (logic->CanUse(RG_HOVER_BOOTS) && ctx->GetTrickOption(RT_DMT_CLIMB_HOVERS))));}}), - Entrance(RR_DODONGOS_CAVERN_ENTRYWAY, {[]{return logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET) || logic->IsAdult;}}), - Entrance(RR_DMT_STORMS_GROTTO, {[]{return logic->CanOpenStormsGrotto();}}), - }); - - areaTable[RR_DEATH_MOUNTAIN_SUMMIT] = Region("Death Mountain Summit", "Death Mountain", {RA_DEATH_MOUNTAIN_TRAIL}, DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->GossipStoneFairy, {[]{return logic->CallGossipFairy();}}), - EventAccess(&logic->BugRock, {[]{return logic->BugRock || logic->IsChild;}}), - }, { - //Locations - LOCATION(RC_DMT_TRADE_BROKEN_SWORD, logic->IsAdult && logic->CanUse(RG_BROKEN_SWORD)), - LOCATION(RC_DMT_TRADE_EYEDROPS, logic->IsAdult && logic->CanUse(RG_EYEDROPS)), - LOCATION(RC_DMT_TRADE_CLAIM_CHECK, logic->IsAdult && logic->CanUse(RG_CLAIM_CHECK)), - LOCATION(RC_DMT_GS_FALLING_ROCKS_PATH, logic->IsAdult && logic->AtNight && (logic->CanUse(RG_MEGATON_HAMMER) || ctx->GetTrickOption(RT_DMT_UPPER_GS)) && logic->CanGetNightTimeGS()), - LOCATION(RC_DMT_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), - LOCATION(RC_DMT_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_DMT_GOSSIP_STONE, true), - }, { - //Exits - Entrance(RR_DEATH_MOUNTAIN_TRAIL, {[]{return true;}}), - Entrance(RR_DMC_UPPER_LOCAL, {[]{return true;}}), - Entrance(RR_DMT_OWL_FLIGHT, {[]{return logic->IsChild;}}, false), - Entrance(RR_DMT_COW_GROTTO, {[]{return Here(RR_DEATH_MOUNTAIN_SUMMIT, []{return logic->BlastOrSmash();});}}), - Entrance(RR_DMT_GREAT_FAIRY_FOUNTAIN, {[]{return Here(RR_DEATH_MOUNTAIN_SUMMIT, []{return logic->BlastOrSmash();});}}), - }); - - areaTable[RR_DMT_OWL_FLIGHT] = Region("DMT Owl Flight", "Death Mountain", {RA_DEATH_MOUNTAIN_TRAIL}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_KAK_IMPAS_ROOFTOP, {[]{return true;}}), - }); - - areaTable[RR_DMT_COW_GROTTO] = Region("DMT Cow Grotto", "DMT Cow Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DMT_COW_GROTTO_COW, logic->CanUse(RG_EPONAS_SONG)), - LOCATION(RC_DMT_COW_GROTTO_BEEHIVE, logic->CanBreakLowerBeehives()), - LOCATION(RC_DMT_COW_GROTTO_LEFT_HEART, true), - LOCATION(RC_DMT_COW_GROTTO_MIDDLE_LEFT_HEART, true), - LOCATION(RC_DMT_COW_GROTTO_MIDDLE_RIGHT_HEART, true), - LOCATION(RC_DMT_COW_GROTTO_RIGHT_HEART, true), - LOCATION(RC_DMT_COW_GROTTO_RUPEE_1, true), - LOCATION(RC_DMT_COW_GROTTO_RUPEE_2, true), - LOCATION(RC_DMT_COW_GROTTO_RUPEE_3, true), - LOCATION(RC_DMT_COW_GROTTO_RUPEE_4, true), - LOCATION(RC_DMT_COW_GROTTO_RUPEE_5, true), - LOCATION(RC_DMT_COW_GROTTO_RUPEE_6, true), - LOCATION(RC_DMT_COW_GROTTO_RED_RUPEE, true), - }, { - //Exits - Entrance(RR_DEATH_MOUNTAIN_SUMMIT, {[]{return true;}}), - - }); - - areaTable[RR_DMT_STORMS_GROTTO] = Region("DMT Storms Grotto", "DMT Storms Grotto", {}, NO_DAY_NIGHT_CYCLE, grottoEvents, { - //Locations - LOCATION(RC_DMT_STORMS_GROTTO_CHEST, true), - LOCATION(RC_DMT_STORMS_GROTTO_FISH, logic->HasBottle()), - LOCATION(RC_DMT_STORMS_GROTTO_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), - LOCATION(RC_DMT_STORMS_GROTTO_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_DMT_STORMS_GROTTO_GOSSIP_STONE, true), - LOCATION(RC_DMT_STORMS_GROTTO_BEEHIVE_LEFT, logic->CanBreakLowerBeehives()), - LOCATION(RC_DMT_STORMS_GROTTO_BEEHIVE_RIGHT, logic->CanBreakLowerBeehives()), - }, { - //Exits - Entrance(RR_DEATH_MOUNTAIN_TRAIL, {[]{return true;}}), - }); - - areaTable[RR_DMT_GREAT_FAIRY_FOUNTAIN] = Region("DMT Great Fairy Fountain", "DMT Great Fairy Fountain", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DMT_GREAT_FAIRY_REWARD, logic->CanUse(RG_ZELDAS_LULLABY)), - }, { - //Exits - Entrance(RR_DEATH_MOUNTAIN_SUMMIT, {[]{return true;}}), - }); - - areaTable[RR_GORON_CITY] = Region("Goron City", "Goron City", {RA_GORON_CITY}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->GossipStoneFairy, {[]{return logic->CallGossipFairyExceptSuns();}}), - EventAccess(&logic->StickPot, {[]{return logic->StickPot || logic->IsChild;}}), - EventAccess(&logic->BugRock, {[]{return logic->BugRock || (logic->BlastOrSmash() || logic->CanUse(RG_SILVER_GAUNTLETS));}}), - EventAccess(&logic->GoronCityChildFire, {[]{return logic->GoronCityChildFire || (logic->IsChild && logic->CanUse(RG_DINS_FIRE));}}), - EventAccess(&logic->GCWoodsWarpOpen, {[]{return logic->GCWoodsWarpOpen || (logic->BlastOrSmash() || logic->CanUse(RG_DINS_FIRE) || logic->CanUse(RG_FAIRY_BOW) || logic->HasItem(RG_GORONS_BRACELET) || logic->GoronCityChildFire);}}), - EventAccess(&logic->GCDaruniasDoorOpenChild, {[]{return logic->GCDaruniasDoorOpenChild || (logic->IsChild && logic->CanUse(RG_ZELDAS_LULLABY));}}), - EventAccess(&logic->StopGCRollingGoronAsAdult, {[]{return logic->StopGCRollingGoronAsAdult || (logic->IsAdult && (logic->HasItem(RG_GORONS_BRACELET) || logic->HasExplosives() || logic->CanUse(RG_FAIRY_BOW) || (ctx->GetTrickOption(RT_GC_LINK_GORON_DINS) && logic->CanUse(RG_DINS_FIRE))));}}), - }, { - //Locations - LOCATION(RC_GC_MAZE_LEFT_CHEST, logic->CanUse(RG_MEGATON_HAMMER) || logic->CanUse(RG_SILVER_GAUNTLETS) || (ctx->GetTrickOption(RT_GC_LEFTMOST) && logic->HasExplosives() && logic->CanUse(RG_HOVER_BOOTS))), - LOCATION(RC_GC_MAZE_CENTER_CHEST, logic->BlastOrSmash() || logic->CanUse(RG_SILVER_GAUNTLETS)), - LOCATION(RC_GC_MAZE_RIGHT_CHEST, logic->BlastOrSmash() || logic->CanUse(RG_SILVER_GAUNTLETS)), - LOCATION(RC_GC_POT_FREESTANDING_POH, logic->IsChild && logic->GoronCityChildFire && (logic->CanUse(RG_BOMB_BAG) || (logic->HasItem(RG_GORONS_BRACELET) && ctx->GetTrickOption(RT_GC_POT_STRENGTH)) || (logic->CanUse(RG_BOMBCHU_5) && ctx->GetTrickOption(RT_GC_POT)))), - LOCATION(RC_GC_ROLLING_GORON_AS_CHILD, logic->IsChild && (logic->HasExplosives() || (logic->HasItem(RG_GORONS_BRACELET) && ctx->GetTrickOption(RT_GC_ROLLING_STRENGTH)))), - LOCATION(RC_GC_ROLLING_GORON_AS_ADULT, logic->StopGCRollingGoronAsAdult), - LOCATION(RC_GC_GS_BOULDER_MAZE, logic->IsChild && logic->BlastOrSmash()), - LOCATION(RC_GC_GS_CENTER_PLATFORM, logic->IsAdult && logic->CanAttack()), - LOCATION(RC_GC_MEDIGORON, logic->IsAdult && (logic->CanBreakMudWalls() || logic->HasItem(RG_GORONS_BRACELET))), - LOCATION(RC_GC_MAZE_GOSSIP_STONE_FAIRY, (logic->BlastOrSmash() || logic->CanUse(RG_SILVER_GAUNTLETS)) && logic->CallGossipFairyExceptSuns()), - LOCATION(RC_GC_MAZE_GOSSIP_STONE_FAIRY_BIG, (logic->BlastOrSmash() || logic->CanUse(RG_SILVER_GAUNTLETS)) && logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_GC_MAZE_GOSSIP_STONE, logic->BlastOrSmash() || logic->CanUse(RG_SILVER_GAUNTLETS)), - LOCATION(RC_GC_LOWER_STAIRCASE_POT_1, logic->CanBreakPots()), - LOCATION(RC_GC_LOWER_STAIRCASE_POT_2, logic->CanBreakPots()), - LOCATION(RC_GC_UPPER_STAIRCASE_POT_1, logic->CanBreakPots()), - LOCATION(RC_GC_UPPER_STAIRCASE_POT_2, logic->CanBreakPots()), - LOCATION(RC_GC_UPPER_STAIRCASE_POT_3, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_DEATH_MOUNTAIN_TRAIL, {[]{return true;}}), - Entrance(RR_GC_MEDIGORON, {[]{return logic->CanBreakMudWalls() || logic->HasItem(RG_GORONS_BRACELET);}}), - Entrance(RR_GC_WOODS_WARP, {[]{return logic->GCWoodsWarpOpen;}}), - Entrance(RR_GC_SHOP, {[]{return (logic->IsAdult && logic->StopGCRollingGoronAsAdult) || (logic->IsChild && (logic->BlastOrSmash() || logic->HasItem(RG_GORONS_BRACELET) || logic->GoronCityChildFire || logic->CanUse(RG_FAIRY_BOW)));}}), - Entrance(RR_GC_DARUNIAS_CHAMBER, {[]{return (logic->IsAdult && logic->StopGCRollingGoronAsAdult) || (logic->IsChild && logic->GCDaruniasDoorOpenChild);}}), - Entrance(RR_GC_GROTTO_PLATFORM, {[]{return logic->IsAdult && ((logic->CanUse(RG_SONG_OF_TIME) && ((logic->EffectiveHealth() > 2) || logic->CanUse(RG_GORON_TUNIC) || logic->CanUse(RG_LONGSHOT) || logic->CanUse(RG_NAYRUS_LOVE))) || (logic->EffectiveHealth() > 1 && logic->CanUse(RG_GORON_TUNIC) && logic->CanUse(RG_HOOKSHOT)) || (logic->CanUse(RG_NAYRUS_LOVE) && logic->CanUse(RG_HOOKSHOT)) || (logic->EffectiveHealth() > 2 && logic->CanUse(RG_HOOKSHOT) && ctx->GetTrickOption(RT_GC_GROTTO)));}}), - }); - - areaTable[RR_GC_MEDIGORON] = Region("GC Medigoron", "Goron City", {RA_GORON_CITY}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GC_MEDIGORON_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns()), - LOCATION(RC_GC_MEDIGORON_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_GC_MEDIGORON_GOSSIP_STONE, true), - LOCATION(RC_GC_MEDIGORON_POT_1, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_GORON_CITY, {[]{return true;}}), - }); - - - areaTable[RR_GC_WOODS_WARP] = Region("GC Woods Warp", "Goron City", {RA_GORON_CITY}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->GCWoodsWarpOpen, {[]{return logic->GCWoodsWarpOpen || (logic->BlastOrSmash() || logic->CanUse(RG_DINS_FIRE));}}), - }, {}, { - //Exits - Entrance(RR_GORON_CITY, {[]{return logic->CanLeaveForest() && logic->GCWoodsWarpOpen;}}), - Entrance(RR_THE_LOST_WOODS, {[]{return true;}}), - }); - - areaTable[RR_GC_DARUNIAS_CHAMBER] = Region("GC Darunias Chamber", "Goron City", {RA_GORON_CITY}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->GoronCityChildFire, {[]{return logic->GoronCityChildFire || (logic->IsChild && logic->CanUse(RG_STICKS));}}), - }, { - //Locations - LOCATION(RC_GC_DARUNIAS_JOY, logic->IsChild && logic->CanUse(RG_SARIAS_SONG)), - LOCATION(RC_GC_DARUNIA_POT_1, logic->CanBreakPots()), - LOCATION(RC_GC_DARUNIA_POT_2, logic->CanBreakPots()), - LOCATION(RC_GC_DARUNIA_POT_3, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_GORON_CITY, {[]{return true;}}), - Entrance(RR_DMC_LOWER_LOCAL, {[]{return logic->IsAdult;}}), - }); - - areaTable[RR_GC_GROTTO_PLATFORM] = Region("GC Grotto Platform", "Goron City", {RA_GORON_CITY}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_GC_GROTTO, {[]{return true;}}), - Entrance(RR_GORON_CITY, {[]{return logic->EffectiveHealth() > 2 || logic->CanUse(RG_GORON_TUNIC) || logic->CanUse(RG_NAYRUS_LOVE) || ((logic->IsChild || logic->CanUse(RG_SONG_OF_TIME)) && logic->CanUse(RG_LONGSHOT));}}), - }); - - areaTable[RR_GC_SHOP] = Region("GC Shop", "GC Shop", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GC_SHOP_ITEM_1, true), - LOCATION(RC_GC_SHOP_ITEM_2, true), - LOCATION(RC_GC_SHOP_ITEM_3, true), - LOCATION(RC_GC_SHOP_ITEM_4, true), - LOCATION(RC_GC_SHOP_ITEM_5, true), - LOCATION(RC_GC_SHOP_ITEM_6, true), - LOCATION(RC_GC_SHOP_ITEM_7, true), - LOCATION(RC_GC_SHOP_ITEM_8, true), - }, { - //Exits - Entrance(RR_GORON_CITY, {[]{return true;}}), - }); - - areaTable[RR_GC_GROTTO] = Region("GC Grotto", "GC Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GC_DEKU_SCRUB_GROTTO_LEFT, logic->CanStunDeku()), - LOCATION(RC_GC_DEKU_SCRUB_GROTTO_RIGHT, logic->CanStunDeku()), - LOCATION(RC_GC_DEKU_SCRUB_GROTTO_CENTER, logic->CanStunDeku()), - LOCATION(RC_GC_GROTTO_BEEHIVE, logic->CanBreakUpperBeehives()), - }, { - //Exits - Entrance(RR_GC_GROTTO_PLATFORM, {[]{return true;}}), - }); - - areaTable[RR_DMC_UPPER_NEARBY] = Region("DMC Upper Nearby", "Death Mountain Crater", {RA_DEATH_MOUNTAIN_CRATER}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_DMC_UPPER_LOCAL, {[]{return logic->FireTimer() >= 48;}}), - Entrance(RR_DEATH_MOUNTAIN_SUMMIT, {[]{return true;}}), - Entrance(RR_DMC_UPPER_GROTTO, {[]{return Here(RR_DMC_UPPER_NEARBY, []{return logic->BlastOrSmash() && (logic->FireTimer() >= 8 || logic->Hearts() >= 3);});}}) - }); - - areaTable[RR_DMC_UPPER_LOCAL] = Region("DMC Upper Local", "Death Mountain Crater", {RA_DEATH_MOUNTAIN_CRATER}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->GossipStoneFairy, {[]{return logic->GossipStoneFairy || (logic->HasExplosives() && logic->CallGossipFairyExceptSuns() && (logic->FireTimer() >= 16 || logic->Hearts() >= 3));}}), - }, { - //Locations - LOCATION(RC_DMC_WALL_FREESTANDING_POH, logic->FireTimer() >= 16 || logic->Hearts() >= 3), - LOCATION(RC_DMC_GS_CRATE, (logic->FireTimer() >= 8 || logic->Hearts() >= 3) && logic->IsChild && logic->CanAttack()), - LOCATION(RC_DMC_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns() && logic->HasExplosives() && (logic->FireTimer() >= 16 || logic->Hearts() >= 3)), - LOCATION(RC_DMC_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS) && logic->HasExplosives() && (logic->FireTimer() >= 16 || logic->Hearts() >= 3)), - LOCATION(RC_DMC_GOSSIP_STONE, logic->HasExplosives() && (logic->FireTimer() >= 16 || logic->Hearts() >= 3)), - }, { - //Exits - Entrance(RR_DMC_UPPER_NEARBY, {[]{return true;}}), - Entrance(RR_DMC_LADDER_AREA_NEARBY, {[]{return logic->FireTimer() >= 16 || logic->Hearts() >= 3;}}), - Entrance(RR_DMC_CENTRAL_NEARBY, {[]{return logic->IsAdult && logic->CanUse(RG_GORON_TUNIC) && logic->CanUse(RG_DISTANT_SCARECROW) && ((logic->EffectiveHealth() > 2) || (logic->CanUse(RG_BOTTLE_WITH_FAIRY) && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).IsNot(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF)) || logic->CanUse(RG_NAYRUS_LOVE));}}), - Entrance(RR_DMC_LOWER_NEARBY, {[]{return false;}}), - Entrance(RR_DMC_DISTANT_PLATFORM, {[]{return (logic->FireTimer() >= 48 && logic->Hearts() >= 2) || logic->Hearts() >= 3;}}), - }); - - areaTable[RR_DMC_LADDER_AREA_NEARBY] = Region("DMC Ladder Region Nearby", "Death Mountain Crater", {RA_DEATH_MOUNTAIN_CRATER}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DMC_DEKU_SCRUB, logic->IsChild && logic->CanStunDeku()), - }, { - //Exits - Entrance(RR_DMC_UPPER_NEARBY, {[]{return logic->Hearts() >= 3;}}), - Entrance(RR_DMC_LOWER_NEARBY, {[]{return logic->Hearts() >= 3 && (logic->CanUse(RG_HOVER_BOOTS) || (ctx->GetTrickOption(RT_DMC_BOULDER_JS) && logic->IsAdult && logic->CanUse(RG_MEGATON_HAMMER)) || (ctx->GetTrickOption(RT_DMC_BOULDER_SKIP) && logic->IsAdult));}}), - }); - - areaTable[RR_DMC_LOWER_NEARBY] = Region("DMC Lower Nearby", "Death Mountain Crater", {RA_DEATH_MOUNTAIN_CRATER}, NO_DAY_NIGHT_CYCLE, {}, { - // Locations - LOCATION(RC_DMC_NEAR_GC_POT_1, logic->CanBreakPots()), - LOCATION(RC_DMC_NEAR_GC_POT_2, logic->CanBreakPots()), - LOCATION(RC_DMC_NEAR_GC_POT_3, logic->CanBreakPots()), - LOCATION(RC_DMC_NEAR_GC_POT_4, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_DMC_LOWER_LOCAL, {[]{return logic->FireTimer() >= 48;}}), - Entrance(RR_GC_DARUNIAS_CHAMBER, {[]{return true;}}), - Entrance(RR_DMC_GREAT_FAIRY_FOUNTAIN, {[]{return logic->CanUse(RG_MEGATON_HAMMER);}}), - Entrance(RR_DMC_HAMMER_GROTTO, {[]{return logic->IsAdult && logic->CanUse(RG_MEGATON_HAMMER);}}), - }); - - areaTable[RR_DMC_LOWER_LOCAL] = Region("DMC Lower Local", "Death Mountain Crater", {RA_DEATH_MOUNTAIN_CRATER}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_DMC_LOWER_NEARBY, {[]{return true;}}), - Entrance(RR_DMC_LADDER_AREA_NEARBY, {[]{return logic->FireTimer() >= 8 || logic->Hearts() >= 3;}}), - Entrance(RR_DMC_CENTRAL_NEARBY, {[]{return (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT)) && (logic->FireTimer() >= 8 || logic->Hearts() >= 3);}}), - Entrance(RR_DMC_CENTRAL_LOCAL, {[]{return (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT) || (logic->IsAdult && logic->CanShield() && ctx->GetTrickOption(RT_DMC_BOLERO_JUMP))) && logic->FireTimer() >= 24;}}), - }); - - areaTable[RR_DMC_CENTRAL_NEARBY] = Region("DMC Central Nearby", "Death Mountain Crater", {RA_DEATH_MOUNTAIN_CRATER}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DMC_VOLCANO_FREESTANDING_POH, logic->IsAdult && logic->Hearts() >= 3 && (CanPlantBean(RR_DMC_CENTRAL_LOCAL) || (ctx->GetTrickOption(RT_DMC_HOVER_BEAN_POH) && logic->CanUse(RG_HOVER_BOOTS)))), - LOCATION(RC_SHEIK_IN_CRATER, logic->IsAdult && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)), - }, { - //Exits - Entrance(RR_DMC_CENTRAL_LOCAL, {[]{return logic->FireTimer() >= 48;}}), - }); - - areaTable[RR_DMC_CENTRAL_LOCAL] = Region("DMC Central Local", "Death Mountain Crater", {RA_DEATH_MOUNTAIN_CRATER}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->BeanPlantFairy, {[]{return logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS) && (logic->FireTimer() >= 8 || logic->Hearts() >= 3);}}), - }, { - //Locations - LOCATION(RC_DMC_GS_BEAN_PATCH, ( logic->FireTimer() >= 8 || logic->Hearts() >= 3) && logic->CanSpawnSoilSkull() && logic->CanAttack()), - LOCATION(RC_DMC_NEAR_PLATFORM_RED_RUPEE, logic->IsChild), - LOCATION(RC_DMC_MIDDLE_PLATFORM_RED_RUPEE, logic->IsChild && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)), - LOCATION(RC_DMC_MIDDLE_PLATFORM_BLUE_RUPEE_1, logic->IsChild && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)), - LOCATION(RC_DMC_MIDDLE_PLATFORM_BLUE_RUPEE_2, logic->IsChild && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)), - LOCATION(RC_DMC_MIDDLE_PLATFORM_BLUE_RUPEE_3, logic->IsChild && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)), - LOCATION(RC_DMC_MIDDLE_PLATFORM_BLUE_RUPEE_4, logic->IsChild && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)), - LOCATION(RC_DMC_MIDDLE_PLATFORM_BLUE_RUPEE_5, logic->IsChild && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)), - LOCATION(RC_DMC_MIDDLE_PLATFORM_BLUE_RUPEE_6, logic->IsChild && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)), - LOCATION(RC_DMC_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS) && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)), - LOCATION(RC_DMC_BEAN_SPROUT_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS) && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)), - LOCATION(RC_DMC_BEAN_SPROUT_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS) && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)), - }, { - //Exits - Entrance(RR_DMC_CENTRAL_NEARBY, {[]{return true;}}), - Entrance(RR_DMC_LOWER_NEARBY, {[]{return (logic->IsAdult && CanPlantBean(RR_DMC_CENTRAL_LOCAL)) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT);}}), - Entrance(RR_DMC_UPPER_NEARBY, {[]{return logic->IsAdult && CanPlantBean(RR_DMC_CENTRAL_LOCAL);}}), - Entrance(RR_FIRE_TEMPLE_ENTRYWAY, {[]{return (logic->IsChild && logic->Hearts() >= 3 && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).IsNot(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF)) || (logic->IsAdult && logic->FireTimer() >= 24);}}), - Entrance(RR_DMC_DISTANT_PLATFORM, {[]{return logic->FireTimer() >= 48 && logic->CanUse(RG_DISTANT_SCARECROW);}}), - }); - - areaTable[RR_DMC_GREAT_FAIRY_FOUNTAIN] = Region("DMC Great Fairy Fountain", "DMC Great Fairy Fountain", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DMC_GREAT_FAIRY_REWARD, logic->CanUse(RG_ZELDAS_LULLABY)), - }, { - //Exits - Entrance(RR_DMC_LOWER_LOCAL, {[]{return true;}}), - }); - - areaTable[RR_DMC_UPPER_GROTTO] = Region("DMC Upper Grotto", "DMC Upper Grotto", {}, NO_DAY_NIGHT_CYCLE, grottoEvents, { - //Locations - LOCATION(RC_DMC_UPPER_GROTTO_CHEST, true), - LOCATION(RC_DMC_UPPER_GROTTO_FISH, logic->HasBottle()), - LOCATION(RC_DMC_UPPER_GROTTO_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), - LOCATION(RC_DMC_UPPER_GROTTO_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_DMC_UPPER_GROTTO_GOSSIP_STONE, true), - LOCATION(RC_DMC_UPPER_GROTTO_BEEHIVE_LEFT, logic->CanBreakLowerBeehives()), - LOCATION(RC_DMC_UPPER_GROTTO_BEEHIVE_RIGHT, logic->CanBreakLowerBeehives()), - }, { - //Exits - Entrance(RR_DMC_UPPER_LOCAL, {[]{return true;}}), - }); - - areaTable[RR_DMC_HAMMER_GROTTO] = Region("DMC Hammer Grotto", "DMC Hammer Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DMC_DEKU_SCRUB_GROTTO_LEFT, logic->CanStunDeku()), - LOCATION(RC_DMC_DEKU_SCRUB_GROTTO_RIGHT, logic->CanStunDeku()), - LOCATION(RC_DMC_DEKU_SCRUB_GROTTO_CENTER, logic->CanStunDeku()), - LOCATION(RC_DMC_HAMMER_GROTTO_BEEHIVE, logic->CanBreakUpperBeehives()), - }, { - //Exits - Entrance(RR_DMC_LOWER_LOCAL, {[]{return true;}}), - }); - - areaTable[RR_DMC_DISTANT_PLATFORM] = Region("DMC Distant Platform", "Death Mountain Crater", {RA_DEATH_MOUNTAIN_CRATER}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DMC_DISTANT_PLATFORM_GREEN_RUPEE_1, logic->IsAdult), - LOCATION(RC_DMC_DISTANT_PLATFORM_GREEN_RUPEE_2, logic->IsAdult), - LOCATION(RC_DMC_DISTANT_PLATFORM_GREEN_RUPEE_3, logic->IsAdult), - LOCATION(RC_DMC_DISTANT_PLATFORM_GREEN_RUPEE_4, logic->IsAdult), - LOCATION(RC_DMC_DISTANT_PLATFORM_GREEN_RUPEE_5, logic->IsAdult), - LOCATION(RC_DMC_DISTANT_PLATFORM_GREEN_RUPEE_6, logic->IsAdult), - LOCATION(RC_DMC_DISTANT_PLATFORM_RED_RUPEE, logic->IsAdult), - }, { - //Exits - Entrance(RR_DMC_CENTRAL_LOCAL, {[]{return logic->FireTimer() >= 48 && logic->CanUse(RG_DISTANT_SCARECROW);}}), - }); -} 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 deleted file mode 100644 index 90bb9a0da..000000000 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_deku_tree.cpp +++ /dev/null @@ -1,388 +0,0 @@ -#include "../location_access.hpp" -#include "../../entrance.h" -#include "../../dungeon.h" - -using namespace Rando; - -void RegionTable_Init_DekuTree() { - /*-------------------------- - | VANILLA/MQ DECIDER | - ---------------------------*/ - areaTable[RR_DEKU_TREE_ENTRYWAY] = Region("Deku Tree Entryway", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_DEKU_TREE_LOBBY, {[]{return ctx->GetDungeon(DEKU_TREE)->IsVanilla();}}), - Entrance(RR_DEKU_TREE_MQ_1F, {[]{return ctx->GetDungeon(DEKU_TREE)->IsMQ();}}), - Entrance(RR_KF_OUTSIDE_DEKU_TREE, {[]{return true;}}), - }); - - /*-------------------------- - | VANILLA DUNGEON | - ---------------------------*/ - if (ctx->GetDungeon(DEKU_TREE)->IsVanilla()) { - areaTable[RR_DEKU_TREE_LOBBY] = Region("Deku Tree Lobby", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->DekuBabaSticks, {[]{return logic->CanGetDekuBabaSticks();}}), - EventAccess(&logic->DekuBabaNuts, {[]{return logic->CanGetDekuBabaNuts();}}), - }, { - //Locations - LOCATION(RC_DEKU_TREE_MAP_CHEST, true), - LOCATION(RC_DEKU_TREE_LOBBY_LOWER_HEART, true), - LOCATION(RC_DEKU_TREE_LOBBY_UPPER_HEART, logic->CanPassEnemy(RE_BIG_SKULLTULA)), - }, { - //Exits - Entrance(RR_DEKU_TREE_ENTRYWAY, {[]{return true;}}), - Entrance(RR_DEKU_TREE_2F_MIDDLE_ROOM, {[]{return true;}}), - Entrance(RR_DEKU_TREE_COMPASS_ROOM, {[]{return true;}}), - Entrance(RR_DEKU_TREE_BASEMENT_LOWER, {[]{return Here(RR_DEKU_TREE_LOBBY, []{return logic->CanAttack() || logic->CanUse(RG_NUTS);});}}), - Entrance(RR_DEKU_TREE_OUTSIDE_BOSS_ROOM, {[]{return false;}}), - Entrance(RR_DEKU_TREE_BOSS_ENTRYWAY, {[]{return false;}}), - }); - - areaTable[RR_DEKU_TREE_2F_MIDDLE_ROOM] = Region("Deku Tree 2F Middle Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_DEKU_TREE_LOBBY, {[]{return Here(RR_DEKU_TREE_2F_MIDDLE_ROOM, []{return logic->CanReflectNuts() || logic->CanUse(RG_MEGATON_HAMMER);});}}), - Entrance(RR_DEKU_TREE_SLINGSHOT_ROOM,{[]{return Here(RR_DEKU_TREE_2F_MIDDLE_ROOM, []{return logic->CanReflectNuts() || logic->CanUse(RG_MEGATON_HAMMER);});}}), - }); - - areaTable[RR_DEKU_TREE_SLINGSHOT_ROOM] = Region("Deku Tree Slingshot Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DEKU_TREE_SLINGSHOT_CHEST, true), - LOCATION(RC_DEKU_TREE_SLINGSHOT_ROOM_SIDE_CHEST, true), - }, { - //Exits - Entrance(RR_DEKU_TREE_2F_MIDDLE_ROOM, {[]{return logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_HOVER_BOOTS);}}), - }); - - areaTable[RR_DEKU_TREE_COMPASS_ROOM] = Region("Deku Tree Compass Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->DekuBabaSticks, {[]{return logic->CanGetDekuBabaSticks();}}), - EventAccess(&logic->DekuBabaNuts, {[]{return logic->CanGetDekuBabaNuts();}}), - }, { - //Locations - LOCATION(RC_DEKU_TREE_COMPASS_CHEST, true), - LOCATION(RC_DEKU_TREE_COMPASS_ROOM_SIDE_CHEST, true), - LOCATION(RC_DEKU_TREE_GS_COMPASS_ROOM, logic->CanAttack()), - }, { - //Exits - Entrance(RR_DEKU_TREE_LOBBY, {[]{return logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW);}}), - Entrance(RR_DEKU_TREE_BOSS_ENTRYWAY, {[]{return false;}}), - }); - - areaTable[RR_DEKU_TREE_BASEMENT_LOWER] = Region("Deku Tree Basement Lower", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->DekuBabaSticks, {[]{return logic->CanGetDekuBabaSticks();}}), - EventAccess(&logic->DekuBabaNuts, {[]{return logic->CanGetDekuBabaNuts();}, - /*Glitched*/[]{return logic->CanUse(RG_MEGATON_HAMMER);}}), - }, { - //Locations - LOCATION(RC_DEKU_TREE_BASEMENT_CHEST, true), - LOCATION(RC_DEKU_TREE_GS_BASEMENT_GATE, logic->CanJumpslashExceptHammer() || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_BOOMERANG) || logic->HasExplosives() || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_DINS_FIRE)), - LOCATION(RC_DEKU_TREE_GS_BASEMENT_VINES, logic->CanUseProjectile() || logic->CanUse(RG_DINS_FIRE) || (ctx->GetTrickOption(RT_DEKU_MQ_COMPASS_GS) && logic->CanJumpslashExceptHammer())), - }, { - //Exits - Entrance(RR_DEKU_TREE_LOBBY, {[]{return true;}}), - Entrance(RR_DEKU_TREE_BASEMENT_SCRUB_ROOM, {[]{return Here(RR_DEKU_TREE_BASEMENT_LOWER, []{return logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW);});}}), - Entrance(RR_DEKU_TREE_BASEMENT_UPPER, {[]{return logic->IsAdult || ctx->GetTrickOption(RT_DEKU_B1_SKIP) || HasAccessTo(RR_DEKU_TREE_BASEMENT_UPPER);}}), - Entrance(RR_DEKU_TREE_OUTSIDE_BOSS_ROOM, {[]{return false;}}), - }); - - areaTable[RR_DEKU_TREE_BASEMENT_SCRUB_ROOM] = Region("Deku Tree Basement Scrub Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_DEKU_TREE_BASEMENT_LOWER, {[]{return true;}}), - Entrance(RR_DEKU_TREE_BASEMENT_WATER_ROOM_FRONT, {[]{return Here(RR_DEKU_TREE_BASEMENT_SCRUB_ROOM, []{return logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_FAIRY_BOW);});}}), - }); - - areaTable[RR_DEKU_TREE_BASEMENT_WATER_ROOM_FRONT] = Region("Deku Tree Basement Water Room Front", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_DEKU_TREE_BASEMENT_SCRUB_ROOM, {[]{return true;}}), - Entrance(RR_DEKU_TREE_BASEMENT_WATER_ROOM_BACK, {[]{return logic->HasItem(RG_BRONZE_SCALE) || ctx->GetTrickOption(RT_DEKU_B1_BACKFLIP_OVER_SPIKED_LOG);}}), - }); - - areaTable[RR_DEKU_TREE_BASEMENT_WATER_ROOM_BACK] = Region("Deku Tree Basement Water Room Back", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_DEKU_TREE_BASEMENT_WATER_ROOM_FRONT, {[]{return logic->HasItem(RG_BRONZE_SCALE) || ctx->GetTrickOption(RT_DEKU_B1_BACKFLIP_OVER_SPIKED_LOG);}}), - Entrance(RR_DEKU_TREE_BASEMENT_TORCH_ROOM, {[]{return true;}}), - }); - - areaTable[RR_DEKU_TREE_BASEMENT_TORCH_ROOM] = Region("Deku Tree Basement Torch Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->DekuBabaSticks, {[]{return logic->CanGetDekuBabaSticks();}}), - EventAccess(&logic->DekuBabaNuts, {[]{return logic->CanGetDekuBabaNuts();}}), - }, {}, { - //Exits - Entrance(RR_DEKU_TREE_BASEMENT_WATER_ROOM_BACK, {[]{return true;}}), - Entrance(RR_DEKU_TREE_BASEMENT_BACK_LOBBY, {[]{return Here(RR_DEKU_TREE_BASEMENT_TORCH_ROOM, []{return logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW);});}}), - }); - - areaTable[RR_DEKU_TREE_BASEMENT_BACK_LOBBY] = Region("Deku Tree Basement Back Lobby", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->DekuBabaSticks, {[]{return logic->CanKillEnemy(RE_WITHERED_DEKU_BABA);}}), - EventAccess(&logic->DekuBabaNuts, {[]{return logic->CanGetDekuBabaNuts();}}), - }, {}, { - //Exits - Entrance(RR_DEKU_TREE_BASEMENT_TORCH_ROOM, {[]{return true;}}), - Entrance(RR_DEKU_TREE_BASEMENT_BACK_ROOM, {[]{return Here(RR_DEKU_TREE_BASEMENT_BACK_LOBBY, []{return logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW);}) && - Here(RR_DEKU_TREE_BASEMENT_BACK_LOBBY, []{return logic->BlastOrSmash();});}}), - Entrance(RR_DEKU_TREE_BASEMENT_UPPER, {[]{return Here(RR_DEKU_TREE_BASEMENT_BACK_LOBBY, []{return logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW);}) && logic->IsChild;}}), - }); - - areaTable[RR_DEKU_TREE_BASEMENT_BACK_ROOM] = Region("Deku Tree Basement Back Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DEKU_TREE_GS_BASEMENT_BACK_ROOM, logic->HookshotOrBoomerang()), - }, { - //Exits - Entrance(RR_DEKU_TREE_BASEMENT_BACK_LOBBY, {[]{return true;}}), - }); - - areaTable[RR_DEKU_TREE_BASEMENT_UPPER] = Region("Deku Tree Basement Upper", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->DekuBabaSticks, {[]{return logic->CanGetDekuBabaSticks();}}), - EventAccess(&logic->DekuBabaNuts, {[]{return logic->CanGetDekuBabaNuts();}}), - }, {}, { - //Exits - Entrance(RR_DEKU_TREE_BASEMENT_LOWER, {[]{return true;}}), - Entrance(RR_DEKU_TREE_BASEMENT_BACK_LOBBY, {[]{return logic->IsChild;}}), - Entrance(RR_DEKU_TREE_OUTSIDE_BOSS_ROOM, {[]{return Here(RR_DEKU_TREE_BASEMENT_UPPER, []{return logic->HasFireSourceWithTorch() || (ctx->GetTrickOption(RT_DEKU_B1_BOW_WEBS) && logic->IsAdult && logic->CanUse(RG_FAIRY_BOW));});}}), - }); - - areaTable[RR_DEKU_TREE_OUTSIDE_BOSS_ROOM] = Region("Deku Tree Outside Boss Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DEKU_TREE_BEFORE_BOSS_LEFT_HEART, logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG)), - LOCATION(RC_DEKU_TREE_BEFORE_BOSS_MIDDLE_HEART, logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG)), - LOCATION(RC_DEKU_TREE_BEFORE_BOSS_RIGHT_HEART, logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG)), - }, { - //Exits - Entrance(RR_DEKU_TREE_BASEMENT_UPPER, {[]{return true;}}), - Entrance(RR_DEKU_TREE_BOSS_ENTRYWAY, {[]{return (logic->HasItem(RG_BRONZE_SCALE) || Here(RR_DEKU_TREE_OUTSIDE_BOSS_ROOM, []{return logic->CanUse(RG_IRON_BOOTS);})) && Here(RR_DEKU_TREE_OUTSIDE_BOSS_ROOM, []{return logic->CanReflectNuts();});}}), - }); - } - - /*--------------------------- - | MASTER QUEST DUNGEON | - ---------------------------*/ - if (ctx->GetDungeon(DEKU_TREE)->IsMQ()) { - areaTable[RR_DEKU_TREE_MQ_1F] = Region("Deku Tree MQ 1F", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->DekuBabaSticks, {[]{return logic->CanKillEnemy(RE_WITHERED_DEKU_BABA);}}), - EventAccess(&logic->BrokeDeku1FWeb, {[]{return logic->HasFireSource();}}), - }, {}, { - //Exits - Entrance(RR_DEKU_TREE_ENTRYWAY, {[]{return true;}}), - //may need canAvoid logic with enemy shuffle - Entrance(RR_DEKU_TREE_MQ_2F, {[]{return true;}}), - //Swim is not required because you can jump with enough momentum to hit land. - //You even avoid fall damage if you hit the shallow water, though it's obscure knowledge so may be a trick - //if it is, then we need a landing room with (IsAdult || HasItem(RG_BRONZE_SCALE) || TakeDamage() || that trick) to reach basement - Entrance(RR_DEKU_TREE_MQ_BASEMENT, {[]{return logic->BrokeDeku1FWeb;}}), - //is it possible to recoil from here to the ledge with a trick? - }); - - areaTable[RR_DEKU_TREE_MQ_2F] = Region("Deku Tree MQ 2F", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DEKU_TREE_MQ_MAP_CHEST, true), - LOCATION(RC_DEKU_TREE_MQ_GS_LOBBY, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)), - LOCATION(RC_DEKU_TREE_MQ_LOBBY_HEART, true), - }, { - //Exits - Entrance(RR_DEKU_TREE_MQ_1F, {[]{return true;}}), - //Will need canAvoid logic with enemy shuffle - Entrance(RR_DEKU_TREE_MQ_3F, {[]{return true;}}), - Entrance(RR_DEKU_TREE_MQ_EYE_TARGET_ROOM, {[]{return Here(RR_DEKU_TREE_MQ_2F, []{return logic->HasFireSource();});}}), - }); - - areaTable[RR_DEKU_TREE_MQ_3F] = Region("Deku Tree MQ 3F", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->DekuBabaSticks, {[]{return logic->CanGetDekuBabaSticks();}}), - EventAccess(&logic->DekuBabaNuts, {[]{return logic->CanGetDekuBabaNuts();}}), - EventAccess(&logic->BrokeDeku1FWeb, {[]{return true;}}), - }, { - //Locations - //Implies CanKillEnemy(RE_GOHMA_LARVA) - LOCATION(RC_DEKU_TREE_MQ_SLINGSHOT_CHEST, logic->CanKillEnemy(RE_DEKU_BABA)), - LOCATION(RC_DEKU_TREE_MQ_SLINGSHOT_ROOM_BACK_CHEST, logic->HasFireSourceWithTorch() || (logic->IsAdult && logic->CanUse(RG_FAIRY_BOW))), - LOCATION(RC_DEKU_TREE_MQ_SLINGSHOT_ROOM_HEART, true), - }, { - //Exits - Entrance(RR_DEKU_TREE_MQ_2F, {[]{return true;}}), - //Assumes RR_DEKU_TREE_MQ_2F access - Entrance(RR_DEKU_TREE_MQ_EYE_TARGET_ROOM, {[]{return Here(RR_DEKU_TREE_MQ_3F, []{return logic->CanUse(RG_STICKS) || logic->CanUse(RG_FAIRY_BOW);});}}), - Entrance(RR_DEKU_TREE_MQ_BASEMENT, {[]{return true;}}), - }); - - areaTable[RR_DEKU_TREE_MQ_EYE_TARGET_ROOM] = Region("Deku Tree MQ Eye Target Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DEKU_TREE_MQ_DEKU_BABA_HEART, true), - }, { - //Exits - Entrance(RR_DEKU_TREE_MQ_COMPASS_ROOM, {[]{return Here(RR_DEKU_TREE_MQ_EYE_TARGET_ROOM, []{return logic->CanHitEyeTargets();});}}), - Entrance(RR_DEKU_TREE_MQ_2F, {[]{return true;}}), - }); - - areaTable[RR_DEKU_TREE_MQ_COMPASS_ROOM] = Region("Deku Tree MQ Compass Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DEKU_TREE_MQ_COMPASS_CHEST, true), - }, { - //Exits - Entrance(RR_DEKU_TREE_MQ_EYE_TARGET_ROOM, {[]{return true;}}), - Entrance(RR_DEKU_TREE_MQ_PAST_BOULDER_VINES, {[]{return Here(RR_DEKU_TREE_MQ_COMPASS_ROOM, []{return logic->CanUse(RG_BOMBCHU_5) || - (logic->CanUse(RG_BOMB_BAG) && (logic->CanUse(RG_SONG_OF_TIME) || logic->IsAdult || logic->CanUse(RG_HOVER_BOOTS))) || - (logic->CanUse(RG_MEGATON_HAMMER) && (logic->CanUse(RG_SONG_OF_TIME) || ctx->GetTrickOption(RT_DEKU_MQ_COMPASS_GS)));});}}), - }); - - areaTable[RR_DEKU_TREE_MQ_PAST_BOULDER_VINES] = Region("Deku Tree MQ Past Boulder Vines", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DEKU_TREE_MQ_GS_PAST_BOULDER_VINES, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)), - LOCATION(RC_DEKU_TREE_MQ_COMPASS_ROOM_HEART, true), - }, { - //Exits - Entrance(RR_DEKU_TREE_MQ_COMPASS_ROOM, {[]{return logic->BlastOrSmash();}}), - }); - - areaTable[RR_DEKU_TREE_MQ_BASEMENT] = Region("Deku Tree MQ Basement", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->DekuBabaSticks, {[]{return logic->CanGetDekuBabaSticks();}}), - EventAccess(&logic->DekuBabaNuts, {[]{return logic->CanGetDekuBabaNuts();}}), - }, { - //Locations - LOCATION(RC_DEKU_TREE_MQ_BASEMENT_CHEST, logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW)), - }, { - //Exits - Entrance(RR_DEKU_TREE_MQ_1F, {[]{return true;}}), - Entrance(RR_DEKU_TREE_MQ_BASEMENT_SOUTHEAST_ROOM, {[]{return Here(RR_DEKU_TREE_MQ_BASEMENT, []{return logic->CanHitEyeTargets();});}}), - //includes RR_DEKU_TREE_MQ_BASEMENT_SOUTHEAST_ROOM Access, other fire sources clear directly from there - Entrance(RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT, {[]{return Here(RR_DEKU_TREE_MQ_BASEMENT, []{return logic->CanHitEyeTargets();}) && logic->ClearedMQDekuSERoom && - Here(RR_DEKU_TREE_MQ_BASEMENT, []{return logic->CanUse(RG_STICKS);});}}), - Entrance(RR_DEKU_TREE_MQ_BASEMENT_LEDGE, {[]{return ctx->GetTrickOption(RT_DEKU_B1_SKIP) || logic->PushedDekuBasementBlock || logic->IsAdult || logic->CanUse(RG_HOVER_BOOTS);}}), - }); - - areaTable[RR_DEKU_TREE_MQ_BASEMENT_SOUTHEAST_ROOM] = Region("Deku Tree MQ Southeast Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, { - //Events - //Implies CanKillEnemy(RE_GOHMA_LARVA) - EventAccess(&logic->ClearedMQDekuSERoom, {[]{return logic->CanKillEnemy(RE_MAD_SCRUB);}}), - }, {}, { - //Exits - Entrance(RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT, {[]{return logic->HasFireSource();}}), - Entrance(RR_DEKU_TREE_MQ_BASEMENT, {[]{return logic->ClearedMQDekuSERoom;}}), - }); - - areaTable[RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT] = Region("Deku Tree MQ Basement Water Room Front", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, { - //Events - //It's possible to get this with bow if you have move while in first person and one-point skips on, noticeably harder and jankier as child, but that's a trick - EventAccess(&logic->MQDekuWaterRoomTorches, {[]{return logic->CanUse(RG_FIRE_ARROWS) || (logic->CanUse(RG_STICKS) && (ctx->GetTrickOption(RT_DEKU_MQ_LOG) || (logic->IsChild && logic->CanShield())));}}), - }, { - //Locations - LOCATION(RC_DEKU_TREE_MQ_BEFORE_SPINNING_LOG_CHEST, true), - }, { - //Exits - Entrance(RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK, {[]{return ctx->GetTrickOption(RT_DEKU_MQ_LOG) || (logic->IsChild && logic->CanShield()) || - logic->CanUse(RG_LONGSHOT) || (logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_IRON_BOOTS));}}), - Entrance(RR_DEKU_TREE_MQ_BASEMENT_SOUTHEAST_ROOM, {[]{return true;}}), - }); - - areaTable[RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK] = Region("Deku Tree MQ Basement Water Room Back", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->DekuBabaSticks, {[]{return logic->CanKillEnemy(RE_WITHERED_DEKU_BABA);}}), - EventAccess(&logic->MQDekuWaterRoomTorches, {[]{return logic->HasFireSource();}}), - }, { - //Locations - //it blocks the chest while stunned unless you stun it from afar while it's slightly off the ground - LOCATION(RC_DEKU_TREE_MQ_AFTER_SPINNING_LOG_CHEST, logic->CanUse(RG_SONG_OF_TIME) && logic->CanPassEnemy(RE_BIG_SKULLTULA)), - }, { - //Exits - Entrance(RR_DEKU_TREE_MQ_BASEMENT_SOUTHWEST_ROOM, {[]{return logic->MQDekuWaterRoomTorches && logic->CanPassEnemy(RE_BIG_SKULLTULA, logic->CanUse(RG_SONG_OF_TIME) ? ED_CLOSE : ED_SHORT_JUMPSLASH);}}), - Entrance(RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT, {[]{return ctx->GetTrickOption(RT_DEKU_MQ_LOG) || (logic->IsChild && logic->CanShield()) || - logic->CanUse(RG_LONGSHOT) || logic->HasItem(RG_BRONZE_SCALE) || - (logic->CanUse(RG_IRON_BOOTS) && (logic->IsAdult || logic->CanUse(RG_HOOKSHOT)));}}), - }); - - areaTable[RR_DEKU_TREE_MQ_BASEMENT_SOUTHWEST_ROOM] = Region("Deku Tree MQ Basement Southwest Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - //both imply CanKillEnemy(RE_GOHMA_LARVA) - Entrance(RR_DEKU_TREE_MQ_BASEMENT_GRAVE_ROOM, {[]{return Here(RR_DEKU_TREE_MQ_BASEMENT_SOUTHWEST_ROOM, []{return logic->CanKillEnemy(RE_MAD_SCRUB) && logic->CanKillEnemy(RE_KEESE);});}}), - Entrance(RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK, {[]{return Here(RR_DEKU_TREE_MQ_BASEMENT_SOUTHWEST_ROOM, []{return logic->CanKillEnemy(RE_MAD_SCRUB) && logic->CanKillEnemy(RE_KEESE);});}}), - }); - - areaTable[RR_DEKU_TREE_MQ_BASEMENT_GRAVE_ROOM] = Region("Deku Tree MQ Basement Grave Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->DekuBabaSticks, {[]{return logic->CanGetDekuBabaSticks();}}), - EventAccess(&logic->DekuBabaNuts, {[]{return logic->CanGetDekuBabaNuts();}}) - }, { - //Locations - LOCATION(RC_DEKU_TREE_MQ_GS_BASEMENT_GRAVES_ROOM, logic->CanUse(RG_LONGSHOT) || (logic->CanUse(RG_SONG_OF_TIME) && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG))), - }, { - //Exits - Entrance(RR_DEKU_TREE_MQ_BASEMENT_LEDGE, {[]{return logic->IsChild && Here(RR_DEKU_TREE_MQ_BASEMENT_GRAVE_ROOM, []{return logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW);});}}), - Entrance(RR_DEKU_TREE_MQ_BASEMENT_SOUTHWEST_ROOM, {[]{return true;}}), - //Using a bow to get past here as adult is a bit precise on standing position but simple, doing as as child requires a side-hop with the bow out to shoot through the torch and may be trick worthy - Entrance(RR_DEKU_TREE_MQ_BASEMENT_BACK_ROOM, {[]{return Here(RR_DEKU_TREE_MQ_BASEMENT_GRAVE_ROOM, []{return logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW);});}}), - }); - - areaTable[RR_DEKU_TREE_MQ_BASEMENT_BACK_ROOM] = Region("Deku Tree MQ Basement Back Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DEKU_TREE_MQ_GS_BASEMENT_BACK_ROOM, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)), - }, { - //Exits - Entrance(RR_DEKU_TREE_MQ_BASEMENT_GRAVE_ROOM, {[]{return true;}}), - }); - - areaTable[RR_DEKU_TREE_MQ_BASEMENT_LEDGE] = Region("Deku Tree MQ Basement Ledge", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->PushedDekuBasementBlock, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_DEKU_TREE_MQ_DEKU_SCRUB, logic->CanStunDeku()), - }, { - //Exits - Entrance(RR_DEKU_TREE_MQ_BASEMENT_GRAVE_ROOM, {[]{return logic->IsChild;}}), - Entrance(RR_DEKU_TREE_MQ_BASEMENT, {[]{return true;}}), - //If strength 0 is shuffled, add hovers or block push to the stick check - //recoiling to skip swim is possible, but would be a trick - Entrance(RR_DEKU_TREE_MQ_OUTSIDE_BOSS_ROOM, {[]{return Here(RR_DEKU_TREE_MQ_BASEMENT_LEDGE, []{return logic->HasFireSource() || (/*logic->PushedDekuBasementBlock && */logic->CanUse(RG_STICKS));}) - && (logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS));}}), - }); - - areaTable[RR_DEKU_TREE_MQ_OUTSIDE_BOSS_ROOM] = - Region("Deku Tree MQ Outside Boss Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, { - LOCATION(RC_DEKU_TREE_MQ_BEFORE_BOSS_LEFT_HEART, logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG)), - LOCATION(RC_DEKU_TREE_MQ_BEFORE_BOSS_MIDDLE_HEART, logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG)), - LOCATION(RC_DEKU_TREE_MQ_BEFORE_BOSS_RIGHT_HEART, logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG)), - }, { - // Exits - Entrance(RR_DEKU_TREE_MQ_BASEMENT_LEDGE, {[]{return logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_HOOKSHOT);}}), - Entrance(RR_DEKU_TREE_BOSS_ENTRYWAY, {[]{return Here(RR_DEKU_TREE_MQ_OUTSIDE_BOSS_ROOM, []{return logic->CanReflectNuts();});}}), - }); - } - - /*--------------------------- - | BOSS ROOM | - ---------------------------*/ - areaTable[RR_DEKU_TREE_BOSS_ENTRYWAY] = - Region("Deku Tree Boss Entryway", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, {}, - { - // Exits - Entrance(RR_DEKU_TREE_OUTSIDE_BOSS_ROOM, { [] { return ctx->GetDungeon(DEKU_TREE)->IsVanilla(); } }), - Entrance(RR_DEKU_TREE_MQ_OUTSIDE_BOSS_ROOM, { [] { return ctx->GetDungeon(DEKU_TREE)->IsMQ(); } }), - Entrance(RR_DEKU_TREE_BOSS_ROOM, { [] { return true; } }), - }); - - areaTable[RR_DEKU_TREE_BOSS_ROOM] = - Region("Deku Tree Boss Room", "Deku Tree", {}, NO_DAY_NIGHT_CYCLE, - { - // Events - EventAccess(&logic->DekuTreeClear, { [] { - return logic->DekuTreeClear || (logic->HasBossSoul(RG_GOHMA_SOUL) && - (logic->CanJumpslashExceptHammer() && (logic->CanUse(RG_NUTS) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_FAIRY_BOW) || - logic->HookshotOrBoomerang()))); - }}), - }, - { - // Locations - LOCATION(RC_QUEEN_GOHMA, logic->DekuTreeClear), - LOCATION(RC_DEKU_TREE_QUEEN_GOHMA_HEART, logic->DekuTreeClear), - }, - { - // Exits - Entrance(RR_DEKU_TREE_BOSS_ENTRYWAY, { [] { return true; } }), - Entrance(RR_KF_OUTSIDE_DEKU_TREE, { [] { return logic->DekuTreeClear; } }, false), - }); -} 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 deleted file mode 100644 index 92ddd3f8a..000000000 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_dodongos_cavern.cpp +++ /dev/null @@ -1,572 +0,0 @@ -#include "../location_access.hpp" -#include "../../entrance.h" -#include "../../dungeon.h" - -using namespace Rando; - -void RegionTable_Init_DodongosCavern() { - /*-------------------------- - | VANILLA/MQ DECIDER | - ---------------------------*/ - areaTable[RR_DODONGOS_CAVERN_ENTRYWAY] = Region("Dodongos Cavern Entryway", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_DODONGOS_CAVERN_BEGINNING, {[]{return ctx->GetDungeon(DODONGOS_CAVERN)->IsVanilla();}}), - Entrance(RR_DODONGOS_CAVERN_MQ_BEGINNING, {[]{return ctx->GetDungeon(DODONGOS_CAVERN)->IsMQ();}}), - Entrance(RR_DEATH_MOUNTAIN_TRAIL, {[]{return true;}}), - }); - - /*-------------------------- - | VANILLA DUNGEON | - ---------------------------*/ - if (ctx->GetDungeon(DODONGOS_CAVERN)->IsVanilla()) { - areaTable[RR_DODONGOS_CAVERN_BEGINNING] = Region("Dodongos Cavern Beginning", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_DODONGOS_CAVERN_ENTRYWAY, {[]{return true;}}), - Entrance(RR_DODONGOS_CAVERN_LOBBY, {[]{return Here(RR_DODONGOS_CAVERN_BEGINNING, []{return logic->CanBreakMudWalls() || logic->HasItem(RG_GORONS_BRACELET);});}}), - }); - - areaTable[RR_DODONGOS_CAVERN_LOBBY] = Region("Dodongos Cavern Lobby", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->GossipStoneFairy, {[]{return (Here(RR_DODONGOS_CAVERN_LOBBY, []{return logic->CanBreakMudWalls();}) || logic->HasItem(RG_GORONS_BRACELET)) && logic->CallGossipFairy();}}), - }, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_MAP_CHEST, Here(RR_DODONGOS_CAVERN_LOBBY, []{return logic->CanBreakMudWalls() || logic->HasItem(RG_GORONS_BRACELET);})), - LOCATION(RC_DODONGOS_CAVERN_DEKU_SCRUB_LOBBY, logic->CanStunDeku() || logic->HasItem(RG_GORONS_BRACELET)), - LOCATION(RC_DODONGOS_CAVERN_GOSSIP_STONE_FAIRY, Here(RR_DODONGOS_CAVERN_LOBBY, []{return logic->CanBreakMudWalls() || logic->HasItem(RG_GORONS_BRACELET);}) && logic->CallGossipFairy()), - LOCATION(RC_DODONGOS_CAVERN_GOSSIP_STONE_FAIRY_BIG, Here(RR_DODONGOS_CAVERN_LOBBY, []{return logic->CanBreakMudWalls() || logic->HasItem(RG_GORONS_BRACELET);}) && logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_DODONGOS_CAVERN_GOSSIP_STONE, Here(RR_DODONGOS_CAVERN_LOBBY, []{return logic->CanBreakMudWalls() || logic->HasItem(RG_GORONS_BRACELET);})), - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_BEGINNING, {[]{return true;}}), - Entrance(RR_DODONGOS_CAVERN_LOBBY_SWITCH, {[]{return logic->IsAdult;}}), - Entrance(RR_DODONGOS_CAVERN_SE_CORRIDOR, {[]{return Here(RR_DODONGOS_CAVERN_LOBBY, []{return logic->BlastOrSmash() || logic->HasItem(RG_GORONS_BRACELET);});}}), - Entrance(RR_DODONGOS_CAVERN_STAIRS_LOWER, {[]{return HasAccessTo(RR_DODONGOS_CAVERN_LOBBY_SWITCH);}}), - Entrance(RR_DODONGOS_CAVERN_FAR_BRIDGE, {[]{return HasAccessTo(RR_DODONGOS_CAVERN_FAR_BRIDGE);}}), - Entrance(RR_DODONGOS_CAVERN_BOSS_AREA, {[]{return Here(RR_DODONGOS_CAVERN_FAR_BRIDGE, []{return logic->HasExplosives();});}}), - Entrance(RR_DODONGOS_CAVERN_BOSS_ENTRYWAY,{[]{return false;}}), - }); - - areaTable[RR_DODONGOS_CAVERN_LOBBY_SWITCH] = Region("Dodongos Cavern Lobby Switch", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_DODONGOS_CAVERN_LOBBY, {[]{return true;}}), - Entrance(RR_DODONGOS_CAVERN_DODONGO_ROOM, {[]{return true;}}), - }); - - areaTable[RR_DODONGOS_CAVERN_SE_CORRIDOR] = Region("Dodongos Cavern SE Corridor", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_GS_SCARECROW, logic->CanUse(RG_SCARECROW) || (logic->IsAdult && logic->CanUse(RG_LONGSHOT)) || (ctx->GetTrickOption(RT_DC_SCARECROW_GS) && (logic->CanAttack()))), - LOCATION(RC_DODONGOS_CAVERN_SIDE_ROOM_POT_1, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_SIDE_ROOM_POT_2, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_SIDE_ROOM_POT_3, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_SIDE_ROOM_POT_4, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_SIDE_ROOM_POT_5, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_SIDE_ROOM_POT_6, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_LOBBY, {[]{return true;}}), - //Shield seems to be in logic to drop a pot on thier head as they hit you to blow up the wall - Entrance(RR_DODONGOS_CAVERN_SE_ROOM, {[]{return Here(RR_DODONGOS_CAVERN_SE_CORRIDOR, []{return logic->BlastOrSmash() || logic->CanAttack() || (logic->TakeDamage() && logic->CanShield());});}}), - Entrance(RR_DODONGOS_CAVERN_NEAR_LOWER_LIZALFOS, {[]{return true;}}), - }); - - areaTable[RR_DODONGOS_CAVERN_SE_ROOM] = Region("Dodongos Cavern SE Room", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_GS_SIDE_ROOM_NEAR_LOWER_LIZALFOS, logic->CanAttack()), - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_SE_CORRIDOR, {[]{return true;}}), - }); - - areaTable[RR_DODONGOS_CAVERN_NEAR_LOWER_LIZALFOS] = Region("Dodongos Cavern Near Lower Lizalfos", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_DODONGOS_CAVERN_SE_CORRIDOR, {[]{return true;}}), - Entrance(RR_DODONGOS_CAVERN_LOWER_LIZALFOS, {[]{return true;}}), - }); - - areaTable[RR_DODONGOS_CAVERN_LOWER_LIZALFOS] = Region("Dodongos Cavern Lower Lizalfos", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_LIZALFOS_POT_1, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_LIZALFOS_POT_2, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_LIZALFOS_POT_3, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_LIZALFOS_POT_4, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_LOWER_LIZALFOS_HEART, true), - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_NEAR_LOWER_LIZALFOS, {[]{return Here(RR_DODONGOS_CAVERN_LOWER_LIZALFOS, []{return logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_STICKS) || logic->CanUse(RG_KOKIRI_SWORD) || - logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MEGATON_HAMMER) || logic->HasExplosives();});}}), - Entrance(RR_DODONGOS_CAVERN_DODONGO_ROOM, {[]{return Here(RR_DODONGOS_CAVERN_LOWER_LIZALFOS, []{return logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_STICKS) || logic->CanUse(RG_KOKIRI_SWORD) || - logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MEGATON_HAMMER) || logic->HasExplosives();});}}), - }); - - areaTable[RR_DODONGOS_CAVERN_DODONGO_ROOM] = Region("Dodongos Cavern Dodongo Room", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_TORCH_ROOM_POT_1, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_TORCH_ROOM_POT_2, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_TORCH_ROOM_POT_3, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_TORCH_ROOM_POT_4, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_LOBBY_SWITCH, {[]{return logic->HasFireSourceWithTorch();}}), - Entrance(RR_DODONGOS_CAVERN_LOWER_LIZALFOS, {[]{return true;}}), - Entrance(RR_DODONGOS_CAVERN_NEAR_DODONGO_ROOM, {[]{return Here(RR_DODONGOS_CAVERN_DODONGO_ROOM, []{return logic->BlastOrSmash() || logic->HasItem(RG_GORONS_BRACELET);});}}), - }); - - areaTable[RR_DODONGOS_CAVERN_NEAR_DODONGO_ROOM] = Region("Dodongos Cavern Near Dodongo Room", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS, logic->CanStunDeku()), - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_DODONGO_ROOM, {[]{return true;}}), - }); - - areaTable[RR_DODONGOS_CAVERN_STAIRS_LOWER] = Region("Dodongos Cavern Stairs Lower", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_DODONGOS_CAVERN_LOBBY, {[]{return true;}}), - Entrance(RR_DODONGOS_CAVERN_STAIRS_UPPER, {[]{return logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET) || logic->CanUse(RG_DINS_FIRE) || (ctx->GetTrickOption(RT_DC_STAIRCASE) && logic->CanUse(RG_FAIRY_BOW));}}), - Entrance(RR_DODONGOS_CAVERN_COMPASS_ROOM, {[]{return Here(RR_DODONGOS_CAVERN_STAIRS_LOWER, []{return logic->BlastOrSmash() || logic->HasItem(RG_GORONS_BRACELET);});}}), - }); - - areaTable[RR_DODONGOS_CAVERN_STAIRS_UPPER] = Region("Dodongos Cavern Stairs Upper", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_GS_ALCOVE_ABOVE_STAIRS, Here(RR_DODONGOS_CAVERN_FAR_BRIDGE, []{return logic->HookshotOrBoomerang();}) || logic->CanUse(RG_LONGSHOT)), - LOCATION(RC_DODONGOS_CAVERN_GS_VINES_ABOVE_STAIRS, logic->IsAdult || logic->CanAttack() || (HasAccessTo(RR_DODONGOS_CAVERN_STAIRS_LOWER) && logic->CanUse(RG_LONGSHOT) && ctx->GetTrickOption(RT_DC_VINES_GS))), - LOCATION(RC_DODONGOS_CAVERN_STAIRCASE_POT_1, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_STAIRCASE_POT_2, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_STAIRCASE_POT_3, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_STAIRCASE_POT_4, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_STAIRS_LOWER, {[]{return true;}}), - Entrance(RR_DODONGOS_CAVERN_ARMOS_ROOM, {[]{return true;}}), - }); - - areaTable[RR_DODONGOS_CAVERN_COMPASS_ROOM] = Region("Dodongos Cavern Compass Room", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_COMPASS_CHEST, true), - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_STAIRS_LOWER, {[]{return logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MEGATON_HAMMER) || logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET);}}), - }); - - areaTable[RR_DODONGOS_CAVERN_ARMOS_ROOM] = Region("Dodongos Cavern Armos Room", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_DODONGOS_CAVERN_STAIRS_UPPER, {[]{return true;}}), - Entrance(RR_DODONGOS_CAVERN_BOMB_ROOM_LOWER, {[]{return true;}}), - }); - - areaTable[RR_DODONGOS_CAVERN_BOMB_ROOM_LOWER] = Region("Dodongos Cavern Bomb Room Lower", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_BOMB_FLOWER_PLATFORM_CHEST, true), - LOCATION(RC_DODONGOS_CAVERN_BLADE_ROOM_HEART, true), - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_2F_SIDE_ROOM, {[]{return Here(RR_DODONGOS_CAVERN_BOMB_ROOM_LOWER, []{return logic->BlastOrSmash() || (ctx->GetTrickOption(RT_DC_SCRUB_ROOM) && logic->HasItem(RG_GORONS_BRACELET));});}}), - Entrance(RR_DODONGOS_CAVERN_FIRST_SLINGSHOT_ROOM, {[]{return Here(RR_DODONGOS_CAVERN_BOMB_ROOM_LOWER, []{return logic->BlastOrSmash() || logic->HasItem(RG_GORONS_BRACELET);});}}), - Entrance(RR_DODONGOS_CAVERN_BOMB_ROOM_UPPER, {[]{return (logic->IsAdult && ctx->GetTrickOption(RT_DC_JUMP)) || logic->CanUse(RG_HOVER_BOOTS) || (logic->IsAdult && logic->CanUse(RG_LONGSHOT)) || (ctx->GetTrickOption(RT_DAMAGE_BOOST_SIMPLE) && logic->HasExplosives() && logic->CanJumpslash());}}), - }); - - areaTable[RR_DODONGOS_CAVERN_2F_SIDE_ROOM] = Region("Dodongos Cavern 2F Side Room", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT, logic->CanStunDeku()), - LOCATION(RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT, logic->CanStunDeku()), - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_BOMB_ROOM_LOWER, {[]{return true;}}), - }); - - areaTable[RR_DODONGOS_CAVERN_FIRST_SLINGSHOT_ROOM] = Region("Dodongos Cavern First Slingshot Room", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_SINGLE_EYE_POT_1, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_SINGLE_EYE_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_BOMB_ROOM_LOWER, {[]{return true;}}), - Entrance(RR_DODONGOS_CAVERN_UPPER_LIZALFOS, {[]{return logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_FAIRY_BOW) || ctx->GetTrickOption(RT_DC_SLINGSHOT_SKIP);}}), - }); - - areaTable[RR_DODONGOS_CAVERN_UPPER_LIZALFOS] = Region("Dodongos Cavern Upper Lizalfos", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_LOWER_LIZALFOS_HEART, true), - LOCATION(RC_DODONGOS_CAVERN_UPPER_LIZALFOS_LEFT_HEART, true), - LOCATION(RC_DODONGOS_CAVERN_UPPER_LIZALFOS_RIGHT_HEART, true), - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_LOWER_LIZALFOS, {[]{return true;}}), - Entrance(RR_DODONGOS_CAVERN_FIRST_SLINGSHOT_ROOM, {[]{return Here(RR_DODONGOS_CAVERN_LOWER_LIZALFOS, []{return logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_STICKS) || logic->CanUse(RG_KOKIRI_SWORD) || - logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MEGATON_HAMMER) || logic->HasExplosives();});}}), - Entrance(RR_DODONGOS_CAVERN_SECOND_SLINGSHOT_ROOM, {[]{return Here(RR_DODONGOS_CAVERN_LOWER_LIZALFOS, []{return logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_STICKS) || logic->CanUse(RG_KOKIRI_SWORD) || - logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MEGATON_HAMMER) || logic->HasExplosives();});}}), - }); - - areaTable[RR_DODONGOS_CAVERN_SECOND_SLINGSHOT_ROOM] = Region("Dodongos Cavern Second Slingshot Room", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { - //Location - LOCATION(RC_DODONGOS_CAVERN_DOUBLE_EYE_POT_1, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_DOUBLE_EYE_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_UPPER_LIZALFOS, {[]{return true;}}), - Entrance(RR_DODONGOS_CAVERN_BOMB_ROOM_UPPER, {[]{return logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_FAIRY_BOW) || ctx->GetTrickOption(RT_DC_SLINGSHOT_SKIP);}}), - }); - - areaTable[RR_DODONGOS_CAVERN_BOMB_ROOM_UPPER] = Region("Dodongos Cavern Bomb Room Upper", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_BOMB_BAG_CHEST, true), - LOCATION(RC_DODONGOS_CAVERN_BLADE_POT_1, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_BLADE_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_BOMB_ROOM_LOWER, {[]{return true;}}), - Entrance(RR_DODONGOS_CAVERN_SECOND_SLINGSHOT_ROOM, {[]{return true;}}), - Entrance(RR_DODONGOS_CAVERN_FAR_BRIDGE, {[]{return true;}}), - }); - - areaTable[RR_DODONGOS_CAVERN_FAR_BRIDGE] = Region("Dodongos Cavern Far Bridge", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_END_OF_BRIDGE_CHEST, Here(RR_DODONGOS_CAVERN_FAR_BRIDGE, []{return logic->BlastOrSmash();})), - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_LOBBY, {[]{return true;}}), - Entrance(RR_DODONGOS_CAVERN_BOMB_ROOM_UPPER, {[]{return true;}}), - }); - - areaTable[RR_DODONGOS_CAVERN_BOSS_AREA] = Region("Dodongos Cavern Boss Region", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->FairyPot, {[]{return true;}}), - }, {}, { - //Exits - Entrance(RR_DODONGOS_CAVERN_LOBBY, {[]{return true;}}), - Entrance(RR_DODONGOS_CAVERN_BACK_ROOM, {[]{return Here(RR_DODONGOS_CAVERN_BOSS_AREA, []{return logic->BlastOrSmash();});}}), - Entrance(RR_DODONGOS_CAVERN_BOSS_ENTRYWAY, {[]{return true;}}), - }); - - areaTable[RR_DODONGOS_CAVERN_BACK_ROOM] = Region("Dodongos Cavern Back Room", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_GS_BACK_ROOM, logic->CanAttack()), - LOCATION(RC_DODONGOS_CAVERN_BACK_ROOM_POT_1, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_BACK_ROOM_POT_2, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_BACK_ROOM_POT_3, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_BACK_ROOM_POT_4, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_BOSS_AREA, {[]{return true;}}), - }); - } - - /*--------------------------- - | MASTER QUEST DUNGEON | - ---------------------------*/ - if (ctx->GetDungeon(DODONGOS_CAVERN)->IsMQ()) { - areaTable[RR_DODONGOS_CAVERN_MQ_BEGINNING] = Region("Dodongos Cavern MQ Beginning", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_DODONGOS_CAVERN_ENTRYWAY, {[]{return true;}}), - Entrance(RR_DODONGOS_CAVERN_MQ_LOBBY, {[]{return Here(RR_DODONGOS_CAVERN_MQ_BEGINNING, []{return logic->BlastOrSmash() || logic->HasItem(RG_GORONS_BRACELET);});}}), - }); - - areaTable[RR_DODONGOS_CAVERN_MQ_LOBBY] = Region("Dodongos Cavern MQ Lobby", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_MQ_MAP_CHEST, logic->CanBreakMudWalls() || logic->HasItem(RG_GORONS_BRACELET)), - LOCATION(RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR, logic->CanStunDeku()), - LOCATION(RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT, logic->CanStunDeku()), - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_MQ_GOSSIP_STONE, {[]{return Here(RR_DODONGOS_CAVERN_MQ_LOBBY, []{return logic->CanBreakMudWalls() || logic->HasItem(RG_GORONS_BRACELET);});}}), - Entrance(RR_DODONGOS_CAVERN_MQ_MOUTH_SIDE_BRIDGE, {[]{return Here(RR_DODONGOS_CAVERN_MQ_LOBBY, []{return logic->BlastOrSmash() || logic->HasItem(RG_GORONS_BRACELET);});}}), - Entrance(RR_DODONGOS_CAVERN_MQ_STAIRS_LOWER, {[]{return Here(RR_DODONGOS_CAVERN_MQ_LOBBY, []{return logic->BlastOrSmash() || logic->HasItem(RG_GORONS_BRACELET);});}}), - Entrance(RR_DODONGOS_CAVERN_MQ_LOWER_RIGHT_SIDE, {[]{return Here(RR_DODONGOS_CAVERN_MQ_LOBBY, []{return logic->CanBreakMudWalls();}) || - Here(RR_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_UPPER, []{return logic->HasItem(RG_GORONS_BRACELET) && logic->TakeDamage();});}}), //strength 1 and bunny speed works too - Entrance(RR_DODONGOS_CAVERN_MQ_POES_ROOM, {[]{return logic->IsAdult;}}), - Entrance(RR_DODONGOS_CAVERN_MQ_BEHIND_MOUTH, {[]{return Here(RR_DODONGOS_CAVERN_MQ_MOUTH_SIDE_BRIDGE, []{return logic->HasExplosives() || (logic->ClearMQDCUpperLobbyRocks && logic->HasItem(RG_GORONS_BRACELET) && - ((logic->IsAdult && ctx->GetTrickOption(RT_DC_MQ_ADULT_EYES)) || - (logic->IsChild && ctx->GetTrickOption(RT_DC_MQ_CHILD_EYES))));});}}), - }); - - areaTable[RR_DODONGOS_CAVERN_MQ_GOSSIP_STONE] = Region("Dodongos Cavern MQ Gossip Stone", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->GossipStoneFairy, {[]{return logic->CallGossipFairy();}}), - }, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_GOSSIP_STONE, true), - LOCATION(RC_DODONGOS_CAVERN_MQ_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), - LOCATION(RC_DODONGOS_CAVERN_MQ_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_MQ_LOBBY, {[]{return true;}}), -}); - - areaTable[RR_DODONGOS_CAVERN_MQ_MOUTH_SIDE_BRIDGE] = Region("Dodongos Cavern MQ Mouth Side Bridge", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->ClearMQDCUpperLobbyRocks, {[]{return logic->BlastOrSmash() || logic->CanUse(RG_DINS_FIRE);}}), - }, {}, { - //Exits - Entrance(RR_DODONGOS_CAVERN_MQ_LOBBY, {[]{return true;}}), - Entrance(RR_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_UPPER, {[]{return logic->ClearMQDCUpperLobbyRocks;}}), - //Bunny hood jump + jumpslash can also make it directly from the raising platform - Entrance(RR_DODONGOS_CAVERN_MQ_POES_ROOM, {[]{return logic->CanUse(RG_HOVER_BOOTS) || (ctx->GetTrickOption(RT_DC_MQ_CHILD_BOMBS) && logic->CanJumpslashExceptHammer() && logic->TakeDamage());}}), //RANDOTODO is this possible with equip swapped hammer? - //it is possible to use bunny hood speed, hovers and a jumpslash to go between here and the other bridge (included with TORCH_ROOM_LOWER), but this would be a trick - }); - - areaTable[RR_DODONGOS_CAVERN_MQ_STAIRS_LOWER] = Region("Dodongos Cavern MQ Stairs Lower", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, { - //Events - //EventAccess(&logic->CanClimbDCStairs, {[]{return logic->HasExplosives || logic->CanUse(RG_DINS_FIRE) || (ctx->GetTrickOption(RT_DC_STAIRCASE) && logic->CanUse(RG_FAIRY_BOW));}}), - }, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_MQ_STAIRCASE_POT_1, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_MQ_STAIRCASE_POT_2, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_MQ_STAIRCASE_POT_3, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_MQ_STAIRCASE_POT_4, logic->CanBreakPots()), - }, { - //Exits - //This is possible with sticks and shield, igniting a first flower by "touch" then very quickly crouch stabbing in a way that cuts the corner to light the 3rd bomb on the other side, but that's a trick - Entrance(RR_DODONGOS_CAVERN_MQ_STAIRS_UPPER, {[]{return Here(RR_DODONGOS_CAVERN_MQ_STAIRS_LOWER, []{return logic->HasExplosives() || logic->CanUse(RG_DINS_FIRE) || - (ctx->GetTrickOption(RT_DC_STAIRCASE) && logic->CanUse(RG_FAIRY_BOW));});}}), - Entrance(RR_DODONGOS_CAVERN_MQ_STAIRS_PAST_MUD_WALL, {[]{return Here(RR_DODONGOS_CAVERN_MQ_STAIRS_LOWER, []{return logic->CanBreakMudWalls();});}}), - }); - - areaTable[RR_DODONGOS_CAVERN_MQ_STAIRS_PAST_MUD_WALL] = Region("Dodongos Cavern MQ Stairs Past Mud Wall", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->DekuBabaSticks, {[]{return logic->CanGetDekuBabaSticks();}}), - //EventAccess(&logic->CanClimbDCStairs, {[]{return logic->HasItem(RG_GORONS_BRACELET) && (logic->CanUse(RG_STICKS));}}), - }, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_MQ_GS_SONG_OF_TIME_BLOCK_ROOM, logic->CanUse(RG_SONG_OF_TIME) && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)), - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_MQ_STAIRS_UPPER, {[]{return logic->HasItem(RG_GORONS_BRACELET) && (logic->CanUse(RG_STICKS));}}), - Entrance(RR_DODONGOS_CAVERN_MQ_STAIRS_LOWER, {[]{return true;}}), - }); - - areaTable[RR_DODONGOS_CAVERN_MQ_STAIRS_UPPER] = Region("Dodongos Cavern MQ Stairs Upper", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE, logic->CanStunDeku()), - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_MQ_STAIRS_LOWER, {[]{return true;}}), - Entrance(RR_DODONGOS_CAVERN_MQ_STAIRS_PAST_BIG_SKULLTULAS, {[]{return logic->CanPassEnemy(RE_BIG_SKULLTULA) || logic->CanUse(RG_HOVER_BOOTS);}}), - }); - - areaTable[RR_DODONGOS_CAVERN_MQ_STAIRS_PAST_BIG_SKULLTULAS] = Region("Dodongos Cavern MQ Past Big Skulltulas", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_DODONGOS_CAVERN_MQ_STAIRS_UPPER, {[]{return logic->CanPassEnemy(RE_BIG_SKULLTULA) || logic->CanUse(RG_HOVER_BOOTS);}}), - Entrance(RR_DODONGOS_CAVERN_MQ_STAIRS_LOWER, {[]{return logic->TakeDamage();}}), - //If some case comes up where you can directly (void?)warp here without going through Dodongo room or climbing up from below, - //the commented out logic is to handle going down and reclimbing to get silver rupees. A new eventVar will need decalring to handle this. - /*(logic->CanPassEnemy(RE_BIG_SKULLTULA) || CanUse(RG_HOVER_BOOTS)) && logic->CanClimbDCStairs;*/ - Entrance(RR_DODONGOS_CAVERN_MQ_DODONGO_ROOM, {[]{return true;}}),//if we add BONKO or other crate logic, logic for silver rupees goes here - }); - - areaTable[RR_DODONGOS_CAVERN_MQ_DODONGO_ROOM] = Region("Dodongos Cavern MQ Dodongo Room", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_MQ_COMPASS_CHEST, logic->CanKillEnemy(RE_DODONGO) || logic->HasItem(RG_GORONS_BRACELET)), - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_MQ_STAIRS_PAST_BIG_SKULLTULAS, {[]{return true;}}), - Entrance(RR_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_LOWER, {[]{return Here(RR_DODONGOS_CAVERN_MQ_DODONGO_ROOM, []{return logic->CanKillEnemy(RE_DODONGO) || logic->HasItem(RG_GORONS_BRACELET);});}}), - }); - - areaTable[RR_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_LOWER] = Region("Dodongos Cavern MQ Torch Puzzle Lower", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->ClearMQDCUpperLobbyRocks, {[]{return (((logic->IsAdult /*or bunny hood jump*/) && ctx->GetTrickOption(RT_DC_JUMP)) || logic->CanUse(RG_HOVER_BOOTS)) && logic->CanUse(RG_STICKS);}}), - }, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_MIDDLE_POT, logic->CanUse(RG_BOOMERANG)), - LOCATION(RC_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_ROOM_HEART, true), - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_MQ_LOBBY, {[]{return logic->TakeDamage();}}), - Entrance(RR_DODONGOS_CAVERN_MQ_DODONGO_ROOM, {[]{return true;}}), - Entrance(RR_DODONGOS_CAVERN_MQ_LARVAE_ROOM, {[]{return logic->HasFireSourceWithTorch();}}),//torch checks here need strength 0 with sticks when that is implemented - Entrance(RR_DODONGOS_CAVERN_MQ_BIG_BLOCK_ROOM, {[]{return Here(RR_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_LOWER, []{return logic->HasFireSourceWithTorch();});}}), //Includes an implied CanPass(RE_BIG_SKULLTULA) - Entrance(RR_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_UPPER, {[]{return ((logic->IsAdult /*or bunny hood jump*/) && ctx->GetTrickOption(RT_DC_JUMP)) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT);}}), - Entrance(RR_DODONGOS_CAVERN_MQ_UPPER_LIZALFOS, {[]{return logic->CanUse(RG_STICKS) && logic->HasItem(RG_GORONS_BRACELET);}}), //Implies access to RR_DODONGOS_CAVERN_MQ_BIG_BLOCK_ROOM from here - }); - - areaTable[RR_DODONGOS_CAVERN_MQ_BIG_BLOCK_ROOM] = Region("Dodongos Cavern MQ Torch Puzzle Lower", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_MQ_BIG_BLOCK_POT_1, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_MQ_BIG_BLOCK_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_LOWER, {[]{return logic->CanPassEnemy(RE_BIG_SKULLTULA);}}), - Entrance(RR_DODONGOS_CAVERN_MQ_UPPER_LIZALFOS, {[]{return (logic->HasFireSource() && logic->HasItem(RG_GORONS_BRACELET)) || logic->CanBreakMudWalls();}}), //Requires stregnth 0, If you can somehow warp into this room, add logic->CanPassEnemy(RE_BIG_SKULLTULA) - }); - - areaTable[RR_DODONGOS_CAVERN_MQ_LARVAE_ROOM] = Region("Dodongos Cavern MQ Larvae Room", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CHEST, true), //implied logic->CanKillEnemy(RE_GOHMA_LARVA) based on entry reqs with a trick to kill with nuts - LOCATION(RC_DODONGOS_CAVERN_MQ_GS_LARVAE_ROOM, true), //implied logic->CanKillEnemy(RE_GOLD_SKULTULLA) based on entry reqs. Add crate logic when BONKO is added - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_LOWER, {[]{return true;}}), //implied logic->CanKillEnemy(RE_GOHMA_LARVA) based on entry reqs with a trick to kill with nuts - }); - - areaTable[RR_DODONGOS_CAVERN_MQ_UPPER_LIZALFOS] = Region("Dodongos Cavern MQ Before Upper Lizalfos", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_MQ_GS_LIZALFOS_ROOM, logic->BlastOrSmash()), //Implied CanGetEnemyDrop(RE_GOLD_SKULLTULA) - LOCATION(RC_DODONGOS_CAVERN_MQ_UPPER_LIZALFOS_POT_1, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_MQ_UPPER_LIZALFOS_POT_2, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_MQ_UPPER_LIZALFOS_POT_3, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_MQ_UPPER_LIZALFOS_POT_4, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_MQ_LIZALFOS_ROOM_HEART, logic->BlastOrSmash()), - }, { - //Exits - //Falling down gets you stuck with nothing there, not a useful exit for logic - Entrance(RR_DODONGOS_CAVERN_MQ_BIG_BLOCK_ROOM, {[]{return Here(RR_DODONGOS_CAVERN_MQ_UPPER_LIZALFOS, []{return logic->CanKillEnemy(RE_LIZALFOS);});}}), - Entrance(RR_DODONGOS_CAVERN_MQ_TWO_FIRES_ROOM, {[]{return Here(RR_DODONGOS_CAVERN_MQ_UPPER_LIZALFOS, []{return logic->CanKillEnemy(RE_LIZALFOS);});}}), - }); - - areaTable[RR_DODONGOS_CAVERN_MQ_TWO_FIRES_ROOM] = Region("Dodongos Cavern MQ Before Upper Lizalfos", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_MQ_TWO_FLAMES_POT_1, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_MQ_TWO_FLAMES_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_MQ_UPPER_LIZALFOS, {[]{return true;}}), - Entrance(RR_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_UPPER, {[]{return logic->IsAdult || (Here(RR_DODONGOS_CAVERN_MQ_TWO_FIRES_ROOM, []{return logic->BlastOrSmash() || (logic->CanAttack() && logic->HasItem(RG_GORONS_BRACELET));}));}}), - }); - - areaTable[RR_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_UPPER] = Region("Dodongos Cavern MQ Torch Puzzle Upper", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->ClearMQDCUpperLobbyRocks, {[]{return logic->CanDetonateUprightBombFlower() || logic->CanUse(RG_MEGATON_HAMMER);}}), - }, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_ROOM_CHEST, true), - LOCATION(RC_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_CORNER_POT, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_MIDDLE_POT, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_MQ_MOUTH_SIDE_BRIDGE, {[]{return logic->ClearMQDCUpperLobbyRocks;}}), - Entrance(RR_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_LOWER, {[]{return true;}}), - Entrance(RR_DODONGOS_CAVERN_MQ_TWO_FIRES_ROOM, {[]{return true;}}), - }); - - areaTable[RR_DODONGOS_CAVERN_MQ_LOWER_RIGHT_SIDE] = Region("Dodongos Cavern MQ Lower Right Side", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS, (logic->CanBreakMudWalls() || logic->HasItem(RG_GORONS_BRACELET)) && logic->CanStunDeku()), - LOCATION(RC_DODONGOS_CAVERN_MQ_RIGHT_SIDE_POT_1, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_MQ_RIGHT_SIDE_POT_2, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_MQ_RIGHT_SIDE_POT_3, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_MQ_RIGHT_SIDE_POT_4, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_MQ_LOBBY, {[]{return true;}}), - Entrance(RR_DODONGOS_CAVERN_MQ_LOWER_LIZALFOS, {[]{return Here(RR_DODONGOS_CAVERN_MQ_LOWER_RIGHT_SIDE, []{return logic->CanDetonateBombFlowers() || logic->HasItem(RG_GORONS_BRACELET);}) && logic->CanHitEyeTargets();}}), - }); - - areaTable[RR_DODONGOS_CAVERN_MQ_LOWER_LIZALFOS] = Region("Dodongos Cavern MQ Lower Lizalfos", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, { - }, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_MQ_LIZALFOS_ROOM_HEART, true), - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_MQ_LOWER_RIGHT_SIDE, {[]{return Here(RR_DODONGOS_CAVERN_MQ_LOWER_LIZALFOS, []{return logic->CanKillEnemy(RE_LIZALFOS);});}}), - Entrance(RR_DODONGOS_CAVERN_MQ_POES_ROOM, {[]{return Here(RR_DODONGOS_CAVERN_MQ_LOWER_LIZALFOS, []{return logic->CanKillEnemy(RE_LIZALFOS);});}}), - }); - - areaTable[RR_DODONGOS_CAVERN_MQ_POES_ROOM] = Region("Dodongos Cavern MQ Poes Room", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_MQ_BOMB_BAG_CHEST, true), //If you can get to the locked part of POES_ROOM without a way to open it or passing the chest, this will need it's own room - LOCATION(RC_DODONGOS_CAVERN_MQ_GS_SCRUB_ROOM, (Here(RR_DODONGOS_CAVERN_MQ_POES_ROOM, []{return logic->CanDetonateBombFlowers() || logic->HasItem(RG_GORONS_BRACELET);}) && //could be a seperate room if it gets busy - logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG, true))), //Implies you can avoid/kill the enemies with what you use on the skull, if this assumption is broken, add - //&& (Here(RR_DODONGOS_CAVERN_MQ_POES_ROOM, []{return logic->CanKillEnemy(RE_FIRE_KEESE) && logic->CanKillEnemy(RE_MAD_SCRUB);}) || (logic->CanAvoidEnemy(RE_FIRE_KEESE) && logic->CanAvoidEnemy(RE_MAD_SCRUB))) - LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_POT_1, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_POT_2, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_POT_3, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_POT_4, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_MQ_LOWER_RIGHT_SIDE, {[]{return Here(RR_DODONGOS_CAVERN_MQ_POES_ROOM, []{return logic->CanDetonateBombFlowers() || logic->HasItem(RG_GORONS_BRACELET);});}}), - Entrance(RR_DODONGOS_CAVERN_MQ_LOWER_LIZALFOS, {[]{return true;}}), - Entrance(RR_DODONGOS_CAVERN_MQ_MAD_SCRUB_ROOM, {[]{return Here(RR_DODONGOS_CAVERN_MQ_POES_ROOM, []{return logic->CanDetonateBombFlowers() || logic->HasItem(RG_GORONS_BRACELET);});}}), - }); - - areaTable[RR_DODONGOS_CAVERN_MQ_MAD_SCRUB_ROOM] = Region("Dodongos Cavern Mad Scrub Room", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_MQ_GS_SCRUB_ROOM, (logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG, true))), //Implies you can avoid/kill the enemies with what you use on the skull, if this assumption is broken, add - //&& (Here(RR_DODONGOS_CAVERN_MQ_POES_ROOM, []{return logic->CanKillEnemy(RE_FIRE_KEESE) && logic->CanKillEnemy(RE_MAD_SCRUB);}) || (logic->CanAvoidEnemy(RE_FIRE_KEESE) && logic->CanAvoidEnemy(RE_MAD_SCRUB))) - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_MQ_POES_ROOM, {[]{return Here(RR_DODONGOS_CAVERN_MQ_MAD_SCRUB_ROOM, []{return logic->CanKillEnemy(RE_FIRE_KEESE) && logic->CanKillEnemy(RE_MAD_SCRUB);});}}), - }); - - areaTable[RR_DODONGOS_CAVERN_MQ_BEHIND_MOUTH] = Region("Dodongos Cavern MQ Behind Mouth", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_MQ_BEFORE_BOSS_SW_POT, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_MQ_BEFORE_BOSS_NE_POT, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_MQ_ARMOS_ROOM_SE_POT, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_MQ_ARMOS_ROOM_SW_POT, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_MQ_LOBBY, {[]{return true;}}), - //using pots to get past the fire is in default logic. if stregnth 0 gets added, this will need to be: - //stregnth 0 || explosives, or projectiles if str0 isn't needed to pull graves (it's a narrow shot though, may be trick worthy) - Entrance(RR_DODONGOS_CAVERN_MQ_BACK_BEHIND_FIRE, {[]{return true;}}), - Entrance(RR_DODONGOS_CAVERN_MQ_BACK_SWITCH_GRAVE, {[]{return logic->IsAdult;}}), - }); - - areaTable[RR_DODONGOS_CAVERN_MQ_BACK_BEHIND_FIRE] = Region("Dodongos Cavern MQ Back Behind Fire", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_MQ_UNDER_GRAVE_CHEST, true), //pulling the grave isn't required, as you can open the chest through it - LOCATION(RC_DODONGOS_CAVERN_MQ_BACKROOM_POT_1, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_MQ_BACKROOM_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_MQ_BEHIND_MOUTH, {[]{return logic->CanAttack();}}), - //There's a trick N64 rolls into the child eyes trick for using armos blow up the bomb flowers when dieing, which would be killing an armos - Entrance(RR_DODONGOS_CAVERN_MQ_BACK_SWITCH_GRAVE, {[]{return Here(RR_DODONGOS_CAVERN_MQ_BACK_BEHIND_FIRE, []{return logic->CanDetonateBombFlowers();}) || - Here(RR_DODONGOS_CAVERN_MQ_BACK_SWITCH_GRAVE, []{return logic->CanAttack();});}}), - }); - - areaTable[RR_DODONGOS_CAVERN_MQ_BACK_SWITCH_GRAVE] = Region("Dodongos Cavern MQ BossArea", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->FairyPot, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_DODONGOS_CAVERN_MQ_GS_BACK_AREA, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA) || logic->HasItem(RG_GORONS_BRACELET) || //even if you somehow warp to BACK_BEHIND_FIRE, if you can kill the skull at range, you can get to BEHIND_MOUTH - Here(RR_DODONGOS_CAVERN_MQ_BEHIND_MOUTH, []{return (logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)) || - (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS) /* || bunny jumps*/);})), - LOCATION(RC_DODONGOS_CAVERN_MQ_ARMOS_ROOM_NW_POT, logic->CanBreakPots()), - LOCATION(RC_DODONGOS_CAVERN_MQ_ARMOS_ROOM_NE_POT, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_DODONGOS_CAVERN_MQ_BACK_BEHIND_FIRE, {[]{return true;}}), - Entrance(RR_DODONGOS_CAVERN_BOSS_ENTRYWAY, {[]{return true;}}), //if strength 0 prevents grave pulls, add it here - }); - - } - - /*--------------------------- - | BOSS ROOM | - ---------------------------*/ - areaTable[RR_DODONGOS_CAVERN_BOSS_ENTRYWAY] = - Region("Dodongos Cavern Boss Entryway", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, {}, - { - // Exits - Entrance(RR_DODONGOS_CAVERN_BOSS_AREA, { [] { return ctx->GetDungeon(DODONGOS_CAVERN)->IsVanilla(); } }), - Entrance(RR_DODONGOS_CAVERN_MQ_BEHIND_MOUTH, { [] { return ctx->GetDungeon(DODONGOS_CAVERN)->IsMQ(); } }), - Entrance(RR_DODONGOS_CAVERN_BOSS_ROOM, { [] { return true; } }), - }); - - areaTable[RR_DODONGOS_CAVERN_BOSS_ROOM] = - Region("Dodongos Cavern Boss Room", "Dodongos Cavern", {}, NO_DAY_NIGHT_CYCLE, - { - // Events - EventAccess(&logic->DodongosCavernClear, - { [] { - return logic->DodongosCavernClear || (logic->HasBossSoul(RG_KING_DODONGO_SOUL) && - (Here(RR_DODONGOS_CAVERN_BOSS_ROOM, - [] { return logic->HasExplosives() || (logic->CanUse(RG_MEGATON_HAMMER) && ctx->GetTrickOption(RT_DC_HAMMER_FLOOR)); }) && - (logic->CanUse(RG_BOMB_BAG) || logic->HasItem(RG_GORONS_BRACELET)) && logic->CanJumpslashExceptHammer())); /*todo add chu kill to tricks*/ - }}), - }, - { - // Locations - LOCATION(RC_DODONGOS_CAVERN_BOSS_ROOM_CHEST, true), - LOCATION(RC_DODONGOS_CAVERN_KING_DODONGO_HEART, logic->DodongosCavernClear), - LOCATION(RC_KING_DODONGO, logic->DodongosCavernClear), - }, - { - // Exits - Entrance(RR_DODONGOS_CAVERN_BOSS_ENTRYWAY, { [] { return true; } }), - Entrance(RR_DEATH_MOUNTAIN_TRAIL, { [] { return logic->DodongosCavernClear; } }, false), - }); -} 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 deleted file mode 100644 index a719e1187..000000000 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_fire_temple.cpp +++ /dev/null @@ -1,743 +0,0 @@ -#include "../location_access.hpp" -#include "../../entrance.h" -#include "../../dungeon.h" - -using namespace Rando; - -void RegionTable_Init_FireTemple() { - /*-------------------------- - | VANILLA/MQ DECIDER | - ---------------------------*/ - areaTable[RR_FIRE_TEMPLE_ENTRYWAY] = Region("Fire Temple Entryway", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_FIRE_TEMPLE_FIRST_ROOM, {[]{return ctx->GetDungeon(FIRE_TEMPLE)->IsVanilla();}}), - Entrance(RR_FIRE_TEMPLE_MQ_FIRST_ROOM_LOWER, {[]{return ctx->GetDungeon(FIRE_TEMPLE)->IsMQ();}}), - Entrance(RR_DMC_CENTRAL_LOCAL, {[]{return true;}}), - }); - - /*-------------------------- - | VANILLA DUNGEON | - ---------------------------*/ - if (ctx->GetDungeon(FIRE_TEMPLE)->IsVanilla()) { - areaTable[RR_FIRE_TEMPLE_FIRST_ROOM] = Region("Fire Temple First Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_ENTRYWAY, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_NEAR_BOSS_ROOM, {[]{return logic->FireTimer() >= 24;}}), - Entrance(RR_FIRE_TEMPLE_LOOP_ENEMIES, {[]{return Here(RR_FIRE_TEMPLE_FIRST_ROOM, []{return logic->CanUse(RG_MEGATON_HAMMER);}) && (logic->SmallKeys(RR_FIRE_TEMPLE, 8) || !logic->IsKeysanity);}}), - Entrance(RR_FIRE_TEMPLE_LOOP_EXIT, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_BIG_LAVA_ROOM, {[]{return logic->SmallKeys(RR_FIRE_TEMPLE, 2) && logic->FireTimer() >= 24;}}), - }); - - areaTable[RR_FIRE_TEMPLE_NEAR_BOSS_ROOM] = Region("Fire Temple Near Boss Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->FairyPot, {[]{return logic->FairyPot || (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT));}}), - }, { - //Locations - LOCATION(RC_FIRE_TEMPLE_NEAR_BOSS_CHEST, true), - LOCATION(RC_FIRE_TEMPLE_NEAR_BOSS_POT_1, (logic->CanBreakPots() && (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT)))), - LOCATION(RC_FIRE_TEMPLE_NEAR_BOSS_POT_2, (logic->CanBreakPots() && (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT)))), - LOCATION(RC_FIRE_TEMPLE_NEAR_BOSS_POT_3, (logic->CanBreakPots() && (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT)))), - LOCATION(RC_FIRE_TEMPLE_NEAR_BOSS_POT_4, (logic->CanBreakPots() && (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT)))), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_FIRST_ROOM, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_BOSS_ENTRYWAY, {[]{return logic->HasItem(RG_FIRE_TEMPLE_BOSS_KEY) && ((logic->IsAdult && (ctx->GetTrickOption(RT_FIRE_BOSS_DOOR_JUMP) || Here(RR_FIRE_TEMPLE_FIRE_MAZE_UPPER, []{return logic->CanUse(RG_MEGATON_HAMMER);}))) || logic->CanUse(RG_HOVER_BOOTS));}}), - }); - - areaTable[RR_FIRE_TEMPLE_LOOP_ENEMIES] = Region("Fire Temple Loop Enemies", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_FIRE_TEMPLE_FIRST_ROOM, {[]{return logic->SmallKeys(RR_FIRE_TEMPLE, 8) || !logic->IsKeysanity;}}), - Entrance(RR_FIRE_TEMPLE_LOOP_TILES, {[]{return Here(RR_FIRE_TEMPLE_LOOP_ENEMIES, []{return logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MEGATON_HAMMER);});}}), - }); - - areaTable[RR_FIRE_TEMPLE_LOOP_TILES] = Region("Fire Temple Loop Tiles", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_GS_BOSS_KEY_LOOP, logic->CanAttack()), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_LOOP_ENEMIES, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_LOOP_FLARE_DANCER, {[]{return true;}}), - }); - - areaTable[RR_FIRE_TEMPLE_LOOP_FLARE_DANCER] = Region("Fire Temple Loop Flare Dancer", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_FLARE_DANCER_CHEST, (logic->HasExplosives() || logic->CanUse(RG_MEGATON_HAMMER)) && logic->IsAdult), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_LOOP_TILES, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_LOOP_HAMMER_SWITCH, {[]{return Here(RR_FIRE_TEMPLE_LOOP_FLARE_DANCER, []{return logic->CanKillEnemy(RE_FLARE_DANCER);});}}), - }); - - areaTable[RR_FIRE_TEMPLE_LOOP_HAMMER_SWITCH] = Region("Fire Temple Loop Hammer Switch", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->FireLoopSwitch, {[]{return logic->FireLoopSwitch || logic->CanUse(RG_MEGATON_HAMMER);}}), - }, {}, { - //Exits - Entrance(RR_FIRE_TEMPLE_LOOP_FLARE_DANCER, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_LOOP_GORON_ROOM, {[]{return logic->FireLoopSwitch;}}), - }); - - areaTable[RR_FIRE_TEMPLE_LOOP_GORON_ROOM] = Region("Fire Temple Loop Goron Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_BOSS_KEY_CHEST, true), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_LOOP_HAMMER_SWITCH, {[]{return logic->FireLoopSwitch;}}), - Entrance(RR_FIRE_TEMPLE_LOOP_EXIT, {[]{return logic->FireLoopSwitch;}}), - }); - - areaTable[RR_FIRE_TEMPLE_LOOP_EXIT] = Region("Fire Temple Loop Exit", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_FIRE_TEMPLE_FIRST_ROOM, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_LOOP_GORON_ROOM, {[]{return logic->FireLoopSwitch;}}), - }); - - areaTable[RR_FIRE_TEMPLE_BIG_LAVA_ROOM] = Region("Fire Temple Big Lava Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_BIG_LAVA_POT_1, logic->CanBreakPots()), - LOCATION(RC_FIRE_TEMPLE_BIG_LAVA_POT_2, logic->CanBreakPots()), - LOCATION(RC_FIRE_TEMPLE_BIG_LAVA_POT_3, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_FIRST_ROOM, {[]{return logic->SmallKeys(RR_FIRE_TEMPLE, 2);}}), - Entrance(RR_FIRE_TEMPLE_BIG_LAVA_ROOM_NORTH_GORON, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_BIG_LAVA_ROOM_NORTH_TILES, {[]{return logic->IsAdult && (logic->CanUse(RG_SONG_OF_TIME) || ctx->GetTrickOption(RT_FIRE_SOT));}}), - Entrance(RR_FIRE_TEMPLE_BIG_LAVA_ROOM_SOUTH_GORON, {[]{return logic->IsAdult && logic->HasExplosives();}}), - Entrance(RR_FIRE_TEMPLE_FIRE_PILLAR_ROOM, {[]{return logic->SmallKeys(RR_FIRE_TEMPLE, 3);}}), - }); - - areaTable[RR_FIRE_TEMPLE_BIG_LAVA_ROOM_NORTH_GORON] = Region("Fire Temple Big Lava Room North Goron", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_BIG_LAVA_ROOM_LOWER_OPEN_DOOR_CHEST, true), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_BIG_LAVA_ROOM, {[]{return true;}}), - }); - - areaTable[RR_FIRE_TEMPLE_BIG_LAVA_ROOM_NORTH_TILES] = Region("Fire Temple Big Lava Room North Tiles", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - //RANDOTODO check if child can reach - LOCATION(RC_FIRE_TEMPLE_GS_SONG_OF_TIME_ROOM, (logic->IsAdult && logic->CanAttack()) || logic->HookshotOrBoomerang()), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_BIG_LAVA_ROOM, {[]{return true;}}), - }); - - areaTable[RR_FIRE_TEMPLE_BIG_LAVA_ROOM_SOUTH_GORON] = Region("Fire Temple Big Lava Room South Goron", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST, true), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_BIG_LAVA_ROOM, {[]{return true;}}), - }); - - areaTable[RR_FIRE_TEMPLE_FIRE_PILLAR_ROOM] = Region("Fire Temple Fire Pillar Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_FIRE_PILLAR_LEFT_HEART, logic->FireTimer() >= 56), - LOCATION(RC_FIRE_TEMPLE_FIRE_PILLAR_RIGHT_HEART, logic->FireTimer() >= 56), - LOCATION(RC_FIRE_TEMPLE_FIRE_PILLAR_BACK_HEART, logic->FireTimer() >= 56), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_BIG_LAVA_ROOM, {[]{return logic->SmallKeys(RR_FIRE_TEMPLE, 3);}}), - Entrance(RR_FIRE_TEMPLE_SHORTCUT_ROOM, {[]{return logic->FireTimer() >= 56 && logic->SmallKeys(RR_FIRE_TEMPLE, 4);}}), - }); - - areaTable[RR_FIRE_TEMPLE_SHORTCUT_ROOM] = Region("Fire Temple Shortcut Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_BOULDER_MAZE_SHORTCUT_CHEST, Here(RR_FIRE_TEMPLE_SHORTCUT_CLIMB, []{return true;})), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_FIRE_PILLAR_ROOM, {[]{return logic->SmallKeys(RR_FIRE_TEMPLE, 4);}}), - Entrance(RR_FIRE_TEMPLE_SHORTCUT_CLIMB, {[]{return Here(RR_FIRE_TEMPLE_SHORTCUT_CLIMB, []{return true;});}}), - Entrance(RR_FIRE_TEMPLE_BOULDER_MAZE_LOWER, {[]{return logic->IsAdult && (logic->HasItem(RG_GORONS_BRACELET) || ctx->GetTrickOption(RT_FIRE_STRENGTH)) && (logic->HasExplosives() || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_FAIRY_SLINGSHOT));}}), - }); - - areaTable[RR_FIRE_TEMPLE_SHORTCUT_CLIMB] = Region("Fire Temple Shortcut Climb", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_FIRE_TEMPLE_SHORTCUT_ROOM, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_BOULDER_MAZE_UPPER, {[]{return true;}}), - }); - - areaTable[RR_FIRE_TEMPLE_BOULDER_MAZE_LOWER] = Region("Fire Temple Boulder Maze Lower", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_BOULDER_MAZE_LOWER_CHEST, true), - LOCATION(RC_FIRE_TEMPLE_GS_BOULDER_MAZE, logic->HasExplosives() && (logic->IsAdult || logic->HookshotOrBoomerang())), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_SHORTCUT_ROOM, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_BOULDER_MAZE_LOWER_SIDE_ROOM, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_EAST_CENTRAL_ROOM, {[]{return logic->SmallKeys(RR_FIRE_TEMPLE, 5, 7);}}), - Entrance(RR_FIRE_TEMPLE_BOULDER_MAZE_UPPER, {[]{return false;}}), - }); - - areaTable[RR_FIRE_TEMPLE_BOULDER_MAZE_LOWER_SIDE_ROOM] = Region("Fire Temple Boulder Maze Lower Side Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_BOULDER_MAZE_SIDE_ROOM_CHEST, true), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_BOULDER_MAZE_LOWER, {[]{return true;}}), - }); - - areaTable[RR_FIRE_TEMPLE_EAST_CENTRAL_ROOM] = Region("Fire Temple East Central Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_EAST_CENTRAL_LEFT_HEART, true), - LOCATION(RC_FIRE_TEMPLE_EAST_CENTRAL_RIGHT_HEART, true), - LOCATION(RC_FIRE_TEMPLE_EAST_CENTRAL_MIDDLE_HEART, true), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_BIG_LAVA_ROOM, {[]{return logic->TakeDamage();}}), - Entrance(RR_FIRE_TEMPLE_BOULDER_MAZE_LOWER, {[]{return logic->SmallKeys(RR_FIRE_TEMPLE, 5, 8);}}), - Entrance(RR_FIRE_TEMPLE_FIRE_WALL_CHASE, {[]{return logic->SmallKeys(RR_FIRE_TEMPLE, 6, 8);}}), - Entrance(RR_FIRE_TEMPLE_MAP_AREA, {[]{return logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_FAIRY_BOW);}}), - }); - - areaTable[RR_FIRE_TEMPLE_FIRE_WALL_CHASE] = Region("Fire Temple Fire Wall Chase", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_FIRE_WALL_EAST_HEART, logic->FireTimer() >= 24 && (logic->IsAdult || logic->CanUse(RG_BOOMERANG))), - LOCATION(RC_FIRE_TEMPLE_FIRE_WALL_WEST_HEART, logic->FireTimer() >= 24 && (logic->IsAdult || logic->CanUse(RG_BOOMERANG))), - LOCATION(RC_FIRE_TEMPLE_FIRE_WALL_EXIT_HEART, logic->FireTimer() >= 24), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_EAST_CENTRAL_ROOM, {[]{return logic->FireTimer() >= 24 && logic->SmallKeys(RR_FIRE_TEMPLE, 6, 8);}}), - Entrance(RR_FIRE_TEMPLE_MAP_AREA, {[]{return logic->IsAdult;}}), - Entrance(RR_FIRE_TEMPLE_BOULDER_MAZE_UPPER, {[]{return logic->FireTimer() >= 24 && logic->IsAdult;}}), - Entrance(RR_FIRE_TEMPLE_CORRIDOR, {[]{return logic->FireTimer() >= 24 && logic->IsAdult && logic->SmallKeys(RR_FIRE_TEMPLE, 7);}}), - }); - - areaTable[RR_FIRE_TEMPLE_MAP_AREA] = Region("Fire Temple Map Region", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_MAP_CHEST, true), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_EAST_CENTRAL_ROOM, {[]{return true;}}), - }); - - areaTable[RR_FIRE_TEMPLE_BOULDER_MAZE_UPPER] = Region("Fire Temple Boulder Maze Upper", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_BOULDER_MAZE_UPPER_CHEST, true), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_SHORTCUT_CLIMB, {[]{return logic->HasExplosives();}}), - Entrance(RR_FIRE_TEMPLE_BOULDER_MAZE_LOWER, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_FIRE_WALL_CHASE, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_SCARECROW_ROOM, {[]{return logic->CanUse(RG_SCARECROW) || (ctx->GetTrickOption(RT_FIRE_SCARECROW) && logic->IsAdult && logic->CanUse(RG_LONGSHOT));}}), - }); - - areaTable[RR_FIRE_TEMPLE_SCARECROW_ROOM] = Region("Fire Temple Scarecrow Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_GS_SCARECROW_CLIMB, logic->CanJumpslashExceptHammer() || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_BOOMERANG) || logic->HasExplosives() || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_DINS_FIRE)), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_BOULDER_MAZE_UPPER, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_EAST_PEAK, {[]{return true;}}), - }); - - areaTable[RR_FIRE_TEMPLE_EAST_PEAK] = Region("Fire Temple East Peak", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_SCARECROW_CHEST, true), - LOCATION(RC_FIRE_TEMPLE_GS_SCARECROW_TOP, logic->CanUseProjectile()), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_SCARECROW_ROOM, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_EAST_CENTRAL_ROOM, {[]{return logic->TakeDamage();}}), - }); - - areaTable[RR_FIRE_TEMPLE_CORRIDOR] = Region("Fire Temple Corridor", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_FIRE_TEMPLE_FIRE_WALL_CHASE, {[]{return logic->SmallKeys(RR_FIRE_TEMPLE, 7);}}), - Entrance(RR_FIRE_TEMPLE_FIRE_MAZE_ROOM, {[]{return true;}}), - }); - - areaTable[RR_FIRE_TEMPLE_FIRE_MAZE_ROOM] = Region("Fire Temple Fire Maze Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - // Locations - LOCATION(RC_FIRE_TEMPLE_FLAME_MAZE_LEFT_POT_1, logic->CanBreakPots()), - LOCATION(RC_FIRE_TEMPLE_FLAME_MAZE_LEFT_POT_2, logic->CanBreakPots()), - LOCATION(RC_FIRE_TEMPLE_FLAME_MAZE_LEFT_POT_3, logic->CanBreakPots()), - LOCATION(RC_FIRE_TEMPLE_FLAME_MAZE_LEFT_POT_4, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_CORRIDOR, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_FIRE_MAZE_UPPER, {[]{return logic->CanUse(RG_HOVER_BOOTS);}}), - Entrance(RR_FIRE_TEMPLE_FIRE_MAZE_SIDE_ROOM, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_WEST_CENTRAL_LOWER, {[]{return logic->SmallKeys(RR_FIRE_TEMPLE, 8);}}), - Entrance(RR_FIRE_TEMPLE_LATE_FIRE_MAZE, {[]{return ctx->GetTrickOption(RT_FIRE_FLAME_MAZE) || false;}}), - }); - - areaTable[RR_FIRE_TEMPLE_FIRE_MAZE_UPPER] = Region("Fire Temple Fire Maze Upper", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_FIRE_TEMPLE_NEAR_BOSS_ROOM, {[]{return logic->CanUse(RG_MEGATON_HAMMER);}}), - Entrance(RR_FIRE_TEMPLE_FIRE_MAZE_ROOM, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_WEST_CENTRAL_UPPER, {[]{return logic->CanUse(RG_MEGATON_HAMMER);}}), - }); - - areaTable[RR_FIRE_TEMPLE_FIRE_MAZE_SIDE_ROOM] = Region("Fire Temple Fire Maze Side Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_COMPASS_CHEST, true), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_FIRE_MAZE_ROOM, {[]{return true;}}), - }); - - areaTable[RR_FIRE_TEMPLE_WEST_CENTRAL_LOWER] = Region("Fire Temple West Central Lower", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_HIGHEST_GORON_CHEST, Here(RR_FIRE_TEMPLE_WEST_CENTRAL_UPPER, []{return (logic->CanUse(RG_SONG_OF_TIME) || ctx->GetTrickOption(RT_RUSTED_SWITCHES)) && logic->CanUse(RG_MEGATON_HAMMER);})), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_FIRE_MAZE_ROOM, {[]{return logic->SmallKeys(RR_FIRE_TEMPLE, 8);}}), - Entrance(RR_FIRE_TEMPLE_WEST_CENTRAL_UPPER, {[]{return logic->IsAdult && logic->CanUse(RG_SONG_OF_TIME);}}), - Entrance(RR_FIRE_TEMPLE_LATE_FIRE_MAZE, {[]{return true;}}), - }); - - areaTable[RR_FIRE_TEMPLE_WEST_CENTRAL_UPPER] = Region("Fire Temple West Central Upper", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_FIRE_TEMPLE_BOSS_ENTRYWAY, {[]{return false;}}), - Entrance(RR_FIRE_TEMPLE_FIRE_MAZE_UPPER, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_WEST_CENTRAL_LOWER, {[]{return true;}}), - }); - - areaTable[RR_FIRE_TEMPLE_LATE_FIRE_MAZE] = Region("Fire Temple Late Fire Maze", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - // Locations - LOCATION(RC_FIRE_TEMPLE_FLAME_MAZE_RIGHT_POT_1, logic->CanBreakPots()), - LOCATION(RC_FIRE_TEMPLE_FLAME_MAZE_RIGHT_POT_2, logic->CanBreakPots()), - LOCATION(RC_FIRE_TEMPLE_FLAME_MAZE_RIGHT_POT_3, logic->CanBreakPots()), - LOCATION(RC_FIRE_TEMPLE_FLAME_MAZE_RIGHT_POT_4, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_FIRE_MAZE_ROOM, {[]{return false;}}), - Entrance(RR_FIRE_TEMPLE_WEST_CENTRAL_LOWER, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_UPPER_FLARE_DANCER, {[]{return logic->HasExplosives();}}), - }); - - areaTable[RR_FIRE_TEMPLE_UPPER_FLARE_DANCER] = Region("Fire Temple Upper Flare Dancer", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_FIRE_TEMPLE_LATE_FIRE_MAZE, {[]{return Here(RR_FIRE_TEMPLE_UPPER_FLARE_DANCER, []{return logic->CanKillEnemy(RE_FLARE_DANCER);});}}), - Entrance(RR_FIRE_TEMPLE_WEST_CLIMB, {[]{return Here(RR_FIRE_TEMPLE_UPPER_FLARE_DANCER, []{return logic->CanKillEnemy(RE_FLARE_DANCER);});}}), - }); - - areaTable[RR_FIRE_TEMPLE_WEST_CLIMB] = Region("Fire Temple West Climb", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_FIRE_TEMPLE_UPPER_FLARE_DANCER, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_WEST_PEAK, {[]{return logic->CanUseProjectile();}}), - }); - - areaTable[RR_FIRE_TEMPLE_WEST_PEAK] = Region("Fire Temple West Peak", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_MEGATON_HAMMER_CHEST, true), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_WEST_CENTRAL_UPPER, {[]{return logic->TakeDamage();}}), - Entrance(RR_FIRE_TEMPLE_WEST_CLIMB, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_HAMMER_RETURN_PATH, {[]{return logic->CanUse(RG_MEGATON_HAMMER);}}), - }); - - areaTable[RR_FIRE_TEMPLE_HAMMER_RETURN_PATH] = Region("Fire Temple Hammer Return Path", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_FIRE_TEMPLE_ABOVE_FIRE_MAZE, {[]{return logic->CanUse(RG_MEGATON_HAMMER);}}), - }); - - areaTable[RR_FIRE_TEMPLE_ABOVE_FIRE_MAZE] = Region("Fire Temple Above Fire Maze", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_FIRE_TEMPLE_HAMMER_RETURN_PATH, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_FIRE_MAZE_UPPER, {[]{return logic->CanUse(RG_MEGATON_HAMMER);}}), - }); - } - - /*--------------------------- - | MASTER QUEST DUNGEON | - ---------------------------*/ - if (ctx->GetDungeon(FIRE_TEMPLE)->IsMQ()) { - //potentially dangerous temp flag on the first room's torches, should be made permanent if possible - areaTable[RR_FIRE_TEMPLE_MQ_FIRST_ROOM_LOWER] = Region("Fire Temple MQ First Room Lower", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_MQ_ENTRANCE_POT_1, logic->CanBreakPots()), - LOCATION(RC_FIRE_TEMPLE_MQ_ENTRANCE_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_ENTRYWAY, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_MQ_MAP_ROOM_SOUTH, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_MQ_FIRST_ROOM_UPPER, {[]{return logic->IsAdult || logic->CanUse(RG_HOOKSHOT);}}), - Entrance(RR_FIRE_TEMPLE_MQ_STALFOS_ROOM, {[]{return logic->SmallKeys(RR_FIRE_TEMPLE, 5);}}), - }); - - areaTable[RR_FIRE_TEMPLE_MQ_FIRST_ROOM_UPPER] = Region("Fire Temple MQ First Room Upper", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_FIRE_TEMPLE_MQ_FIRST_ROOM_LOWER, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_NEAR_BOSS_ROOM, {[]{return logic->HasFireSource();}}), - Entrance(RR_FIRE_TEMPLE_MQ_BIG_LAVA_ROOM, {[]{return Here(RR_FIRE_TEMPLE_MQ_FIRST_ROOM_UPPER, []{return logic->CanUse(RG_MEGATON_HAMMER);});}}), - }); - - areaTable[RR_FIRE_TEMPLE_MQ_MAP_ROOM_SOUTH] = Region("Fire Temple MQ Map Room South", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_MQ_MAP_ROOM_SIDE_CHEST, logic->CanKillEnemy(RE_LIKE_LIKE)), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_MQ_FIRST_ROOM_LOWER, {[]{return Here(RR_FIRE_TEMPLE_MQ_FIRST_ROOM_LOWER, []{return logic->CanKillEnemy(RE_LIKE_LIKE);});}}), - Entrance(RR_FIRE_TEMPLE_MQ_MAP_ROOM_CAGE, {[]{return logic->OpenedLowestGoronCage;}}), - }); - - areaTable[RR_FIRE_TEMPLE_MQ_STALFOS_ROOM] = Region("Fire Temple MQ Stalfos Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_MQ_LOOP_STALFOS_SUN_FAIRY, logic->CanUse(RG_SUNS_SONG)), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_MQ_FIRST_ROOM_LOWER, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_MQ_IRON_KNUCKLE_ROOM, {[]{return Here(RR_FIRE_TEMPLE_MQ_FIRST_ROOM_LOWER, []{return logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2);});}}), -}); - - areaTable[RR_FIRE_TEMPLE_MQ_IRON_KNUCKLE_ROOM] = Region("Fire Temple MQ Iron Knuckle Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->FairyPot, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_FIRE_TEMPLE_MQ_LOOP_KNUCKLE_SUN_FAIRY, logic->CanUse(RG_SUNS_SONG)), - LOCATION(RC_FIRE_TEMPLE_MQ_BEFORE_MINI_BOSS_POT_1, logic->CanBreakPots()), - LOCATION(RC_FIRE_TEMPLE_MQ_BEFORE_MINI_BOSS_POT_2, logic->CanBreakPots()), - LOCATION(RC_FIRE_TEMPLE_MQ_BEFORE_MINI_BOSS_POT_3, logic->CanBreakPots()), - LOCATION(RC_FIRE_TEMPLE_MQ_BEFORE_MINI_BOSS_POT_4, logic->CanBreakPots()), - LOCATION(RC_FIRE_TEMPLE_MQ_BEFORE_MINI_BOSS_POT_5, logic->CanBreakPots()), - LOCATION(RC_FIRE_TEMPLE_MQ_BEFORE_MINI_BOSS_POT_6, logic->CanBreakPots()), - LOCATION(RC_FIRE_TEMPLE_MQ_BEFORE_MINI_BOSS_POT_7, logic->CanBreakPots()), - LOCATION(RC_FIRE_TEMPLE_MQ_BEFORE_MINI_BOSS_POT_8, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_MQ_STALFOS_ROOM, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_MQ_LOWER_FLARE_DANCER, {[]{return Here(RR_FIRE_TEMPLE_MQ_FIRST_ROOM_LOWER, []{return logic->CanKillEnemy(RE_IRON_KNUCKLE);});}}), -}); - - areaTable[RR_FIRE_TEMPLE_MQ_LOWER_FLARE_DANCER] = Region("Fire Temple MQ Lower Flare Dancer", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_MQ_MEGATON_HAMMER_CHEST, (logic->IsAdult || logic->CanUse(RG_HOOKSHOT)) && Here(RR_FIRE_TEMPLE_MQ_LOWER_FLARE_DANCER, []{return logic->CanKillEnemy(RE_FLARE_DANCER);})), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_MQ_IRON_KNUCKLE_ROOM, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_MQ_MAP_ROOM_NORTH, {[]{return Here(RR_FIRE_TEMPLE_MQ_LOWER_FLARE_DANCER, []{return logic->CanKillEnemy(RE_FLARE_DANCER);});}}), -}); - - areaTable[RR_FIRE_TEMPLE_MQ_MAP_ROOM_NORTH] = Region("Fire Temple MQ Map Room North", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->OpenedLowestGoronCage, {[]{return logic->CanUse(RG_MEGATON_HAMMER);}}), - }, {}, { - //Exits - Entrance(RR_FIRE_TEMPLE_MQ_LOWER_FLARE_DANCER, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_MQ_MAP_ROOM_CAGE, {[]{return logic->OpenedLowestGoronCage;}}), -}); - - areaTable[RR_FIRE_TEMPLE_MQ_MAP_ROOM_CAGE] = Region("Fire Temple MQ Map Room Cage", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_MQ_MAP_CHEST, true), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_MQ_MAP_ROOM_NORTH, {[]{return logic->OpenedLowestGoronCage;}}), - Entrance(RR_FIRE_TEMPLE_MQ_MAP_ROOM_SOUTH, {[]{return logic->OpenedLowestGoronCage;}}), -}); - - areaTable[RR_FIRE_TEMPLE_NEAR_BOSS_ROOM] = Region("Fire Temple MQ Near Boss Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - //If we're using the south torch as the initial torch, or using FAs, we either have to cross to the north to remove the crate, or use a trick to ignore it - LOCATION(RC_FIRE_TEMPLE_MQ_NEAR_BOSS_CHEST, logic->FireTimer() > 25 && ctx->GetTrickOption(RT_FIRE_MQ_NEAR_BOSS) && - (logic->CanUse(RG_FIRE_ARROWS) || (logic->IsAdult && logic->CanUse(RG_DINS_FIRE) && logic->CanUse(RG_FAIRY_BOW)))) - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_MQ_FIRST_ROOM_UPPER, {[]{return true;}}), - //Child cannot make it to the north side torches without a hook without specifically bunny hood speed + hover boots - Entrance(RR_FIRE_TEMPLE_NEAR_BOSS_ROOM_NORTH, {[]{return logic->FireTimer() > 32 && (logic->CanUse(RG_HOOKSHOT) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)));}}), - Entrance(RR_FIRE_TEMPLE_BOSS_ENTRYWAY, {[]{return logic->HasItem(RG_FIRE_TEMPLE_BOSS_KEY) && logic->FireTimer() >= 15 && - ((logic->IsAdult && (ctx->GetTrickOption(RT_FIRE_BOSS_DOOR_JUMP) || logic->CanUse(RG_HOVER_BOOTS))) || - (logic->IsAdult && logic->HitFireTemplePlatform) || - (logic->HitFireTemplePlatform && logic->CanUse(RG_HOVER_BOOTS))) - ;}}), - }); - -//This room assumes tunic logic is handled on entry. -//Covers the upper section too, as all methods to reach this can climb up somehow - areaTable[RR_FIRE_TEMPLE_NEAR_BOSS_ROOM_NORTH] = Region("Fire Temple MQ Near Boss Room North", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - //If we have FAs, we can just remove the crate and use those to light the torches. - //otherwise, with Dins, we first light them with dins and then either use a bow shot or to cross back over to light the other torch - //Valid ways across are adult+hovers, bunny+hovers, longshot or running through the lava and then climbing back up as adult (child can't reach the ledge). - //The Damage logic here is for jumping down and running across the lava to get in dins range of the south torch - //Fairies cannot be used for this as it is time sensetive, and NL is only useful with sticks as it disables other magic while in use, so it's tunic or raw damage taking ability. - //testing tells me you take 3 ticks of lava damage, which is 12 internal damage or 3/4 of a heart at x1 damage multiplier, performing this run - //logic->EffectiveHealth() works in half hearts for whatever reason, meaning this needs a deeper refactor to be perfect, but it should be good enough for now - LOCATION(RC_FIRE_TEMPLE_MQ_NEAR_BOSS_CHEST, logic->CanUse(RG_FIRE_ARROWS) || - (logic->CanUse(RG_DINS_FIRE) && - (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_LONGSHOT) || - (logic->IsAdult && (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_GORON_TUNIC) || logic->EffectiveHealth() >= 2 || (logic->CanUse(RG_NAYRUS_LOVE) && logic->CanUse(RG_STICKS))))))), - LOCATION(RC_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_POT_1, logic->CanBreakPots()), - LOCATION(RC_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_NEAR_BOSS_ROOM, {[]{return true;}}), - }); - - areaTable[RR_FIRE_TEMPLE_MQ_BIG_LAVA_ROOM] = Region("Fire Temple MQ Big Lava Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - //I'm currently assuming the oversight version of RT_FIRE_MQ_BK_CHEST for the fire timer logic - LOCATION(RC_FIRE_TEMPLE_MQ_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST, logic->FireTimer() >= 40 && logic->HasFireSource() && logic->HasExplosives() && - (logic->CanUse(RG_HOOKSHOT) || (logic->IsAdult && ctx->GetTrickOption(RT_FIRE_MQ_BLOCKED_CHEST)))), - //implies CanGetEnemyDrop(RE_GOLD_SKULLTULA) - LOCATION(RC_FIRE_TEMPLE_MQ_GS_BIG_LAVA_ROOM_OPEN_DOOR, logic->FireTimer() >= 20 && logic->CanUse(RG_MEGATON_HAMMER)), - LOCATION(RC_FIRE_TEMPLE_MQ_LAVA_ROOM_NORTH_POT, logic->CanBreakPots()), - LOCATION(RC_FIRE_TEMPLE_MQ_LAVA_ROOM_HIGH_POT, logic->CanBreakPots()), - LOCATION(RC_FIRE_TEMPLE_MQ_LAVA_ROOM_SOUTH_POT, logic->FireTimer() >= 40 && - (logic->CanUse(RG_HOOKSHOT) || (ctx->GetTrickOption(RT_FIRE_MQ_BLOCKED_CHEST) && ((logic->IsAdult && logic->CanBreakPots()) || logic->CanUse(RG_BOOMERANG))))), - }, { - //Exits - // Fewer tunic requirements ends here - Entrance(RR_FIRE_TEMPLE_MQ_FIRST_ROOM_UPPER, {[]{return logic->FireTimer() >= 20;}}), - Entrance(RR_FIRE_TEMPLE_MQ_ELEVATOR_ROOM, {[]{return logic->CanUse(RG_GORON_TUNIC) && logic->SmallKeys(RR_FIRE_TEMPLE, 2);}}), - Entrance(RR_FIRE_TEMPLE_MQ_TORCH_FIREWALL_ROOM, {[]{return logic->HasFireSource() && ((logic->CanUse(RG_FAIRY_BOW) && logic->FireTimer() >= 25) || (ctx->GetTrickOption(RT_FIRE_MQ_BK_CHEST) && logic->FireTimer() >= 50)) && (logic->CanUse(RG_HOOKSHOT) || (logic->IsAdult && ctx->GetTrickOption(RT_FIRE_SOT)));}}), -}); - - areaTable[RR_FIRE_TEMPLE_MQ_TORCH_FIREWALL_ROOM] = Region("Fire Temple MQ Torch Firewall Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->FairyPot, {[]{return logic->CanUse(RG_HOOKSHOT);}}), - }, { - //Locations - LOCATION(RC_FIRE_TEMPLE_MQ_BOSS_KEY_CHEST, logic->CanUse(RG_HOOKSHOT)), - LOCATION(RC_FIRE_TEMPLE_MQ_LAVA_TORCH_POT_1, logic->HookshotOrBoomerang()), - LOCATION(RC_FIRE_TEMPLE_MQ_LAVA_TORCH_POT_2, logic->HookshotOrBoomerang()), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_MQ_BIG_LAVA_ROOM, {[]{return true;}}), -}); - -//This room assumes Goron Tunic until looser tunic requirements tricks are made - areaTable[RR_FIRE_TEMPLE_MQ_ELEVATOR_ROOM] = Region("Fire Temple MQ Elevator Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_MQ_FIRE_PILLAR_LEFT_HEART, true), - LOCATION(RC_FIRE_TEMPLE_MQ_FIRE_PILLAR_RIGHT_HEART, true), - LOCATION(RC_FIRE_TEMPLE_MQ_FIRE_PILLAR_LOWER_HEART, true), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_MQ_BIG_LAVA_ROOM, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_MQ_BIG_TORCH_ROOM, {[]{return true;}}), -}); - - areaTable[RR_FIRE_TEMPLE_MQ_BIG_TORCH_ROOM] = Region("Fire Temple MQ Big Torch Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_FIRE_TEMPLE_MQ_LOWER_MAZE, {[]{return (logic->HasFireSource() && logic->CanUse(RG_HOOKSHOT)) || (ctx->GetTrickOption(RT_FIRE_MQ_CLIMB) && logic->CanUse(RG_HOVER_BOOTS));}}), - Entrance(RR_FIRE_TEMPLE_MQ_ELEVATOR_ROOM, {[]{return logic->CanUse(RG_GORON_TUNIC);}}), - Entrance(RR_FIRE_TEMPLE_MQ_MAZE_SHORTCUT_CAGE, {[]{return logic->OpenedUpperFireShortcut;}}), -}); - - areaTable[RR_FIRE_TEMPLE_MQ_LOWER_MAZE] = Region("Fire Temple MQ Lower Maze", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - //Check handled on both floors - LOCATION(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_SIDE_ROOM_CHEST, logic->HasExplosives() && ctx->GetTrickOption(RT_FIRE_MQ_MAZE_SIDE_ROOM)), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_MQ_BIG_TORCH_ROOM, {[]{return true;}}), - //Explosives can also reach this room. Chus is relatively simple, they need to detonate on the first horizontal bar up from the floor while horizontally near the switch, but bombs are much harder - Entrance(RR_FIRE_TEMPLE_MQ_LOWER_MAZE_CRATE_CAGE, {[]{return Here(RR_FIRE_TEMPLE_MQ_LOWER_MAZE, []{return logic->CanJumpslash();});}}), - //it's possible to make the RT_FIRE_MQ_MAZE_HOVERS as child using bunny hood jumps, but not adult as adult bonks - Entrance(RR_FIRE_TEMPLE_MQ_UPPER_MAZE, {[]{return logic->HasExplosives() && logic->CanUse(RG_MEGATON_HAMMER) && logic->CanUse(RG_HOOKSHOT);}}), - }); - - areaTable[RR_FIRE_TEMPLE_MQ_LOWER_MAZE_CRATE_CAGE] = Region("Fire Temple MQ Lower Maze Crate Cage", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CHEST, true), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_MQ_LOWER_MAZE, {[]{return true;}}), - //it's possible to make the RT_FIRE_MQ_MAZE_HOVERS as child using bunny hood jumps, but not adult as adult bonks - Entrance(RR_FIRE_TEMPLE_MQ_UPPER_MAZE, {[]{return logic->IsAdult && ((ctx->GetTrickOption(RT_FIRE_MQ_MAZE_HOVERS) && logic->CanUse(RG_HOVER_BOOTS)) || ctx->GetTrickOption(RT_FIRE_MQ_MAZE_JUMP));}}), - }); - - areaTable[RR_FIRE_TEMPLE_MQ_UPPER_MAZE] = Region("Fire Temple MQ Upper Maze", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_FIRE_TEMPLE_MQ_LOWER_MAZE, {[]{return true;}}), - //this cage is much more lenient than the lower cage as the switch is close to the front. sling, rang and bow all hit the switch easily, though might be too unintuitive for default logic - //This shouldn't come up in most cases anyway as most methods to get here need either a melee weapon or explosives - Entrance(RR_FIRE_TEMPLE_MQ_UPPER_MAZE_BOX_CAGE, {[]{return Here(RR_FIRE_TEMPLE_MQ_UPPER_MAZE, []{return logic->CanJumpslash() || logic->HasExplosives();});}}), - Entrance(RR_FIRE_TEMPLE_MQ_MAZE_SHORTCUT, {[]{return logic->HasExplosives();}}), - //Implies RR_FIRE_TEMPLE_MQ_LOWER_MAZE access - Entrance(RR_FIRE_TEMPLE_MQ_BURNING_BLOCK_CLIMB, {[]{return logic->HasExplosives() && logic->CanUse(RG_MEGATON_HAMMER) && (logic->CanUse(RG_LONGSHOT) || (logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_SONG_OF_TIME)));}}), - Entrance(RR_FIRE_TEMPLE_MQ_HIGH_TORCH_ROOM, {[]{return logic->SmallKeys(RR_FIRE_TEMPLE, 3) && logic->CanUse(RG_GORON_TUNIC);}}), - }); - - areaTable[RR_FIRE_TEMPLE_MQ_UPPER_MAZE_BOX_CAGE] = Region("Fire Temple MQ Upper Maze Box Cage", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CHEST, true), - //Assumes maze access - LOCATION(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_SIDE_ROOM_CHEST, logic->HasExplosives()), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_MQ_UPPER_MAZE, {[]{return true;}}), - }); - - areaTable[RR_FIRE_TEMPLE_MQ_MAZE_SHORTCUT] = Region("Fire Temple MQ Maze Shortcut", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->OpenedUpperFireShortcut, {[]{return logic->CanUse(RG_MEGATON_HAMMER);}}), - }, {}, { - //Exits - Entrance(RR_FIRE_TEMPLE_MQ_UPPER_MAZE, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_MQ_MAZE_SHORTCUT_CAGE, {[]{return logic->OpenedUpperFireShortcut;}}), - }); - - areaTable[RR_FIRE_TEMPLE_MQ_MAZE_SHORTCUT_CAGE] = Region("Fire Temple MQ Maze Shortcut Cage", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_MQ_COMPASS_CHEST, logic->OpenedUpperFireShortcut;), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_MQ_MAZE_SHORTCUT, {[]{return logic->OpenedUpperFireShortcut;}}), - Entrance(RR_FIRE_TEMPLE_MQ_BIG_TORCH_ROOM, {[]{return logic->OpenedUpperFireShortcut;}}), - }); - - - areaTable[RR_FIRE_TEMPLE_MQ_BURNING_BLOCK_CLIMB] = Region("Fire Temple MQ Burning Block Climb", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - //EventAccess(&WallFairy, {[]{return logic->CanUse(RG_HOOKSHOT);}}), - }, { - //Locations - //There's definitely ways to do this hammerless, but with one points on it's a trick - LOCATION(RC_FIRE_TEMPLE_MQ_GS_SKULL_ON_FIRE, logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_MEGATON_HAMMER)), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_MQ_UPPER_MAZE, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_MQ_NARROW_PATH_ROOM, {[]{return logic->TakeDamage();}}), - }); - - areaTable[RR_FIRE_TEMPLE_MQ_NARROW_PATH_ROOM] = Region("Fire Temple MQ Narrow Path Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->FairyPot, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_FIRE_TEMPLE_MQ_ABOVE_LAVA_POT_1, logic->CanBreakPots()), - LOCATION(RC_FIRE_TEMPLE_MQ_ABOVE_LAVA_POT_2, logic->CanBreakPots()), - LOCATION(RC_FIRE_TEMPLE_MQ_ABOVE_LAVA_POT_3, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_MQ_LOWER_MAZE, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_MQ_BIG_LAVA_ROOM, {[]{return logic->TakeDamage();}}), - }); - - areaTable[RR_FIRE_TEMPLE_MQ_HIGH_TORCH_ROOM] = Region("Fire Temple MQ High Torch Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_MQ_FLAME_WALL_POT_1, logic->CanBreakPots()), - LOCATION(RC_FIRE_TEMPLE_MQ_FLAME_WALL_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_MQ_UPPER_MAZE, {[]{return logic->SmallKeys(RR_FIRE_TEMPLE, 3);}}), - Entrance(RR_FIRE_TEMPLE_MQ_NARROW_PATH_ROOM, {[]{return true;}}), - //Child has issues navigating the higher points of this room without an equip swapped hookshot - Entrance(RR_FIRE_TEMPLE_MQ_SOUTH_FIRE_MAZE, {[]{return Here(RR_FIRE_TEMPLE_MQ_HIGH_TORCH_ROOM, []{return logic->CanUse(RG_FIRE_ARROWS) || (logic->CanUse(RG_FAIRY_BOW) && logic->CanUse(RG_HOOKSHOT));}) && - (logic->IsAdult || logic->CanUse(RG_HOOKSHOT));}}), - }); - - areaTable[RR_FIRE_TEMPLE_MQ_SOUTH_FIRE_MAZE] = Region("Fire Temple MQ South Fire Maze", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_CENTER, logic->HasExplosives()), - LOCATION(RC_FIRE_TEMPLE_MQ_SOUTH_FIRE_MAZE_WEST_POT, logic->CanBreakPots()), - LOCATION(RC_FIRE_TEMPLE_MQ_SOUTH_FIRE_MAZE_EAST_POT, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_MQ_NEAR_BOSS_DOOR, {[]{return logic->HitFireTemplePlatform;}}), - Entrance(RR_FIRE_TEMPLE_MQ_HIGH_TORCH_ROOM, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_MQ_FIRE_MAZE_PLATFORMS, {[]{return logic->IsAdult || logic->CanUse(RG_SONG_OF_TIME) || logic->CanUse(RG_HOVER_BOOTS);}}), - //Hover boots get there via the platforms - Entrance(RR_FIRE_TEMPLE_MQ_NORTH_FIRE_MAZE, {[]{return (bool)ctx->GetTrickOption(RT_FIRE_MQ_FLAME_MAZE);}}), - Entrance(RR_FIRE_TEMPLE_MQ_WEST_FIRE_MAZE, {[]{return logic->OpenedFireMQFireMazeDoor;}}), - }); - - areaTable[RR_FIRE_TEMPLE_MQ_FIRE_MAZE_PLATFORMS] = Region("Fire Temple MQ Fire Maze Platforms", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->HitFireTemplePlatform, {[]{return logic->CanUse(RG_MEGATON_HAMMER);}}), - EventAccess(&logic->OpenedFireMQFireMazeDoor, {[]{return logic->CanUse(RG_MEGATON_HAMMER) && logic->CanUse(RG_HOOKSHOT);}}), - }, {}, { - Entrance(RR_FIRE_TEMPLE_MQ_SOUTH_FIRE_MAZE, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_MQ_NORTH_FIRE_MAZE, {[]{return logic->CanUse(RG_SONG_OF_TIME) || logic->CanUse(RG_HOVER_BOOTS);}}), - //trick to get to RR_FIRE_TEMPLE_MQ_WEST_FIRE_MAZE with hovers + taking damage is plausible - }); - - areaTable[RR_FIRE_TEMPLE_MQ_NORTH_FIRE_MAZE] = Region("Fire Temple MQ North Fire Maze", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_SIDE_ROOM, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)), - LOCATION(RC_FIRE_TEMPLE_MQ_PAST_FIRE_MAZE_SOUTH_POT, logic->CanUse(RG_BOOMERANG)), - LOCATION(RC_FIRE_TEMPLE_MQ_FIRE_MAZE_NORTHMOST_POT, logic->CanBreakPots()), - LOCATION(RC_FIRE_TEMPLE_MQ_FIRE_MAZE_NORTHWEST_POT, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_FIRE_TEMPLE_MQ_SOUTH_FIRE_MAZE, {[]{return logic->IsAdult || ctx->GetTrickOption(RT_FIRE_MQ_FLAME_MAZE);}}), - Entrance(RR_FIRE_TEMPLE_MQ_WEST_FIRE_MAZE, {[]{return (bool)ctx->GetTrickOption(RT_FIRE_MQ_FLAME_MAZE);}}), - }); - - areaTable[RR_FIRE_TEMPLE_MQ_WEST_FIRE_MAZE] = Region("Fire Temple MQ West Fire Maze", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - Entrance(RR_FIRE_TEMPLE_MQ_FIRE_MAZE_PAST_WALL, {[]{return true;}}), - Entrance(RR_FIRE_TEMPLE_MQ_NORTH_FIRE_MAZE, {[]{return (bool)ctx->GetTrickOption(RT_FIRE_MQ_FLAME_MAZE);}}), - }); - -//this area exists for the pots in case we void warp to the top of fire somehow, because there's no way to get back the way we came - areaTable[RR_FIRE_TEMPLE_MQ_FIRE_MAZE_PAST_WALL] = Region("Fire Temple MQ Fire Maze Past Wall", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_MQ_PAST_FIRE_MAZE_SOUTH_POT, logic->CanBreakPots()), - LOCATION(RC_FIRE_TEMPLE_MQ_PAST_FIRE_MAZE_NORTH_POT, logic->CanBreakPots()), - LOCATION(RC_FIRE_TEMPLE_MQ_FIRE_MAZE_NORTHWEST_POT, logic->CanUse(RG_BOOMERANG)), - }, { - Entrance(RR_FIRE_TEMPLE_MQ_UPPER_FLARE_DANCER, {[]{return true;}}), - }); - - areaTable[RR_FIRE_TEMPLE_MQ_UPPER_FLARE_DANCER] = Region("Fire Temple MQ North Fire Maze", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FIRE_TEMPLE_MQ_FREESTANDING_KEY, logic->CanKillEnemy(RE_FLARE_DANCER)), - }, { - Entrance(RR_FIRE_TEMPLE_MQ_FIRE_MAZE_PAST_WALL, {[]{return logic->CanKillEnemy(RE_FLARE_DANCER);}}), - Entrance(RR_FIRE_TEMPLE_MQ_SCARECROW_ROOM, {[]{return logic->CanKillEnemy(RE_FLARE_DANCER) && logic->SmallKeys(RR_FIRE_TEMPLE, 4);}}), - }); - - areaTable[RR_FIRE_TEMPLE_MQ_SCARECROW_ROOM] = Region("Fire Temple MQ Scarecrow Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - //This requires nothing in N64 logic, but is tight enough to need rollspam with the one-point on which is stricter than I would normally consider in logic - //Child basically needs the scarecrow or a bunny hood though due to a worse ledge grab. - LOCATION(RC_FIRE_TEMPLE_MQ_CHEST_ON_FIRE, logic->IsAdult || logic->CanUse(RG_SCARECROW)), - }, { - //The dropdown here is unusual in that it hits 1 of 3 locations: RR_FIRE_TEMPLE_MQ_SOUTH_FIRE_MAZE, RR_FIRE_TEMPLE_MQ_FIRE_MAZE_PLATFORMS and the section of RR_FIRE_TEMPLE_MQ_FIRE_MAZE_PLATFORMS with the hammer switch - //Using this dropdown is in N64 logic elsewhere, but not here, probably because it requires good foreknowlege to determine where to land - //This would be a logical method to reach the hammer switch without hookshot, but it practically requires access to the area that switch unlocks already. It could also be first child access to PLATFORMS if tricks ever enable that - //If a practical use for this drop is found, it should be made a trick - Entrance(RR_FIRE_TEMPLE_MQ_UPPER_FLARE_DANCER, {[]{return logic->SmallKeys(RR_FIRE_TEMPLE, 4);}}), - Entrance(RR_FIRE_TEMPLE_MQ_COLLAPSED_STAIRS, {[]{return Here(RR_FIRE_TEMPLE_MQ_SCARECROW_ROOM, []{return logic->CanUse(RG_MEGATON_HAMMER);}) && logic->SmallKeys(RR_FIRE_TEMPLE, 5);}}), - }); - - //The peg knocked down from here could have logical implications for child in the fire maze if tricks to gain height like bomb jumps exist - areaTable[RR_FIRE_TEMPLE_MQ_COLLAPSED_STAIRS] = Region("Fire Temple MQ Collapsed Stairs", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - //If someone manages to make a trick to get here from fire maze, this needs to be in a separate room as the door back is barred - LOCATION(RC_FIRE_TEMPLE_MQ_GS_ABOVE_FIRE_MAZE, logic->CanUse(RG_HOOKSHOT)), - }, { - Entrance(RR_FIRE_TEMPLE_MQ_FIRE_MAZE_PLATFORMS, {[]{return logic->CanUse(RG_HOOKSHOT) && Here(RR_FIRE_TEMPLE_MQ_COLLAPSED_STAIRS, []{return logic->CanUse(RG_MEGATON_HAMMER);});}}), - Entrance(RR_FIRE_TEMPLE_MQ_SCARECROW_ROOM, {[]{return logic->IsAdult && logic->CanUse(RG_HOOKSHOT);}}), - }); - } - - /*--------------------------- - | BOSS ROOM | - ---------------------------*/ - areaTable[RR_FIRE_TEMPLE_BOSS_ENTRYWAY] = - Region("Fire Temple Boss Entryway", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, - { - // Exits - Entrance(RR_FIRE_TEMPLE_NEAR_BOSS_ROOM, { [] { return ctx->GetDungeon(FIRE_TEMPLE)->IsVanilla() && false; } }), - Entrance(RR_FIRE_TEMPLE_MQ_NEAR_BOSS_DOOR, { [] { return ctx->GetDungeon(FIRE_TEMPLE)->IsMQ() && false; } }), - Entrance(RR_FIRE_TEMPLE_BOSS_ROOM, { [] { return true; } }), - }); - - areaTable[RR_FIRE_TEMPLE_BOSS_ROOM] = - Region("Fire Temple Boss Room", "Fire Temple", {}, NO_DAY_NIGHT_CYCLE, - { - // Events - EventAccess(&logic->FireTempleClear, - { [] { return logic->FireTempleClear || (logic->HasBossSoul(RG_VOLVAGIA_SOUL) && (logic->FireTimer() >= 64 && logic->CanUse(RG_MEGATON_HAMMER))); }}), - }, - { - // Locations - LOCATION(RC_FIRE_TEMPLE_VOLVAGIA_HEART, logic->FireTempleClear), - LOCATION(RC_VOLVAGIA, logic->FireTempleClear), - }, - { - // Exits - Entrance(RR_FIRE_TEMPLE_BOSS_ENTRYWAY, { [] { return false; } }), - Entrance(RR_DMC_CENTRAL_LOCAL, { [] { return logic->FireTempleClear; } }, false), - }); -} 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 deleted file mode 100644 index 31b8c382c..000000000 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_forest_temple.cpp +++ /dev/null @@ -1,637 +0,0 @@ -#include "../location_access.hpp" -#include "../../entrance.h" -#include "../../dungeon.h" - -using namespace Rando; - -void RegionTable_Init_ForestTemple() { - /*-------------------------- - | VANILLA/MQ DECIDER | - ---------------------------*/ - areaTable[RR_FOREST_TEMPLE_ENTRYWAY] = Region("Forest Temple Entryway", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_FOREST_TEMPLE_FIRST_ROOM, {[]{return ctx->GetDungeon(FOREST_TEMPLE)->IsVanilla();}}), - Entrance(RR_FOREST_TEMPLE_MQ_LOBBY, {[]{return ctx->GetDungeon(FOREST_TEMPLE)->IsMQ();}}), - Entrance(RR_SACRED_FOREST_MEADOW, {[]{return true;}}), - }); - - /*-------------------------- - | VANILLA DUNGEON | - ---------------------------*/ - if (ctx->GetDungeon(FOREST_TEMPLE)->IsVanilla()) { - areaTable[RR_FOREST_TEMPLE_FIRST_ROOM] = Region("Forest Temple First Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FOREST_TEMPLE_FIRST_ROOM_CHEST, true), - LOCATION(RC_FOREST_TEMPLE_GS_FIRST_ROOM, (logic->IsAdult && logic->CanUse(RG_BOMB_BAG)) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_BOOMERANG) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_BOMBCHU_5) || logic->CanUse(RG_DINS_FIRE) || (ctx->GetTrickOption(RT_FOREST_FIRST_GS) && (logic->CanJumpslashExceptHammer() || (logic->IsChild && logic->CanUse(RG_BOMB_BAG))))), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_ENTRYWAY, {[]{return true;}}), - Entrance(RR_FOREST_TEMPLE_SOUTH_CORRIDOR, {[]{return true;}}), - }); - - areaTable[RR_FOREST_TEMPLE_SOUTH_CORRIDOR] = Region("Forest Temple South Corridor", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_FOREST_TEMPLE_FIRST_ROOM, {[]{return true;}}), - Entrance(RR_FOREST_TEMPLE_LOBBY, {[]{return logic->CanAttack() || logic->CanUse(RG_NUTS);}}), - }); - - areaTable[RR_FOREST_TEMPLE_LOBBY] = Region("Forest Temple Lobby", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->ForestTempleMeg, {[]{return logic->ForestTempleMeg || (logic->ForestTempleJoelle && logic->ForestTempleBeth && logic->ForestTempleAmy && logic->CanUse(RG_FAIRY_BOW));}}), - }, { - //Locations - LOCATION(RC_FOREST_TEMPLE_GS_LOBBY, logic->HookshotOrBoomerang()), - LOCATION(RC_FOREST_TEMPLE_LOBBY_POT_1, logic->CanBreakPots()), - LOCATION(RC_FOREST_TEMPLE_LOBBY_POT_2, logic->CanBreakPots()), - LOCATION(RC_FOREST_TEMPLE_LOBBY_POT_3, logic->CanBreakPots()), - LOCATION(RC_FOREST_TEMPLE_LOBBY_POT_4, logic->CanBreakPots()), - LOCATION(RC_FOREST_TEMPLE_LOBBY_POT_5, logic->CanBreakPots()), - LOCATION(RC_FOREST_TEMPLE_LOBBY_POT_6, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_SOUTH_CORRIDOR, {[]{return true;}}), - Entrance(RR_FOREST_TEMPLE_NORTH_CORRIDOR, {[]{return true;}}), - Entrance(RR_FOREST_TEMPLE_NW_OUTDOORS_LOWER, {[]{return logic->CanUse(RG_SONG_OF_TIME) || logic->IsChild;}}), - Entrance(RR_FOREST_TEMPLE_NE_OUTDOORS_LOWER, {[]{return logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT);}}), - Entrance(RR_FOREST_TEMPLE_WEST_CORRIDOR, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 1, 5);}}), - Entrance(RR_FOREST_TEMPLE_EAST_CORRIDOR, {[]{return false;}}), - Entrance(RR_FOREST_TEMPLE_BOSS_REGION, {[]{return logic->ForestTempleMeg;}}), - Entrance(RR_FOREST_TEMPLE_BOSS_ENTRYWAY, {[]{return false;}}), - }); - - areaTable[RR_FOREST_TEMPLE_NORTH_CORRIDOR] = Region("Forest Temple North Corridor", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_FOREST_TEMPLE_LOBBY, {[]{return true;}}), - Entrance(RR_FOREST_TEMPLE_LOWER_STALFOS, {[]{return true;}}), - }); - - areaTable[RR_FOREST_TEMPLE_LOWER_STALFOS] = Region("Forest Temple Lower Stalfos", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->FairyPot, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_FOREST_TEMPLE_FIRST_STALFOS_CHEST, logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MEGATON_HAMMER)), - LOCATION(RC_FOREST_TEMPLE_LOWER_STALFOS_POT_1, logic->CanBreakPots()), - LOCATION(RC_FOREST_TEMPLE_LOWER_STALFOS_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_NORTH_CORRIDOR, {[]{return true;}}), - }); - - areaTable[RR_FOREST_TEMPLE_NW_OUTDOORS_LOWER] = Region("Forest Temple NW Outdoors Lower", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->DekuBabaSticks, {[]{return logic->CanGetDekuBabaSticks();}}), - EventAccess(&logic->DekuBabaNuts, {[]{return logic->CanGetDekuBabaNuts();}}), - }, { - //Locations - LOCATION(RC_FOREST_TEMPLE_GS_LEVEL_ISLAND_COURTYARD, logic->CanUse(RG_LONGSHOT) || Here(RR_FOREST_TEMPLE_NW_OUTDOORS_UPPER, []{return logic->HookshotOrBoomerang();})), - LOCATION(RC_FOREST_TEMPLE_COURTYARD_RIGHT_HEART, logic->CanUse(RG_BOOMERANG) && ctx->GetTrickOption(RT_FOREST_OUTDOORS_HEARTS_BOOMERANG)), - LOCATION(RC_FOREST_TEMPLE_COURTYARD_LEFT_HEART, logic->CanUse(RG_BOOMERANG) && ctx->GetTrickOption(RT_FOREST_OUTDOORS_HEARTS_BOOMERANG)), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_LOBBY, {[]{return logic->CanUse(RG_SONG_OF_TIME);}}), - Entrance(RR_FOREST_TEMPLE_NW_OUTDOORS_UPPER, {[]{return ctx->GetTrickOption(RT_HOVER_BOOST_SIMPLE) && ctx->GetTrickOption(RT_DAMAGE_BOOST_SIMPLE) && logic->HasExplosives() && logic->CanUse(RG_HOVER_BOOTS);}}), - Entrance(RR_FOREST_TEMPLE_MAP_ROOM, {[]{return true;}}), - Entrance(RR_FOREST_TEMPLE_SEWER, {[]{return logic->HasItem(RG_GOLDEN_SCALE) || logic->CanUse(RG_IRON_BOOTS) || HasAccessTo(RR_FOREST_TEMPLE_NE_OUTDOORS_UPPER);}}), - Entrance(RR_FOREST_TEMPLE_BOSS_ENTRYWAY, {[]{return false;}}), - }); - - areaTable[RR_FOREST_TEMPLE_NW_OUTDOORS_UPPER] = Region("Forest Temple NW Outdoors Upper", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->DekuBabaSticks, {[]{return logic->CanGetDekuBabaSticks();}}), - EventAccess(&logic->DekuBabaNuts, {[]{return logic->CanGetDekuBabaNuts();}}), - }, { - //Locations - LOCATION(RC_FOREST_TEMPLE_COURTYARD_RIGHT_HEART, true), - LOCATION(RC_FOREST_TEMPLE_COURTYARD_LEFT_HEART, true), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_NW_OUTDOORS_LOWER, {[]{return true;}}), - Entrance(RR_FOREST_TEMPLE_BELOW_BOSS_KEY_CHEST, {[]{return true;}}), - Entrance(RR_FOREST_TEMPLE_FLOORMASTER_ROOM, {[]{return true;}}), - Entrance(RR_FOREST_TEMPLE_BLOCK_PUSH_ROOM, {[]{return true;}}), - }); - - areaTable[RR_FOREST_TEMPLE_NE_OUTDOORS_LOWER] = Region("Forest Temple NE Outdoors Lower", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->DekuBabaSticks, {[]{return logic->CanGetDekuBabaSticks();}}), - EventAccess(&logic->DekuBabaNuts, {[]{return logic->CanGetDekuBabaNuts();}}), - }, { - //Locations - LOCATION(RC_FOREST_TEMPLE_RAISED_ISLAND_COURTYARD_CHEST, logic->CanUse(RG_HOOKSHOT) || HasAccessTo(RR_FOREST_TEMPLE_FALLING_ROOM) || (HasAccessTo(RR_FOREST_TEMPLE_NE_OUTDOORS_UPPER) && logic->IsAdult && ctx->GetTrickOption(RT_FOREST_OUTDOORS_LEDGE) && logic->CanUse(RG_HOVER_BOOTS))), - LOCATION(RC_FOREST_TEMPLE_GS_RAISED_ISLAND_COURTYARD, logic->CanUse(RG_HOOKSHOT) || (ctx->GetTrickOption(RT_FOREST_OUTDOORS_EAST_GS) && logic->CanUse(RG_BOOMERANG)) || Here(RR_FOREST_TEMPLE_FALLING_ROOM, []{return logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_DINS_FIRE) || logic->HasExplosives();})), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_LOBBY, {[]{return true;}}), - Entrance(RR_FOREST_TEMPLE_NE_OUTDOORS_UPPER, {[]{return logic->CanUse(RG_LONGSHOT) || (ctx->GetTrickOption(RT_FOREST_VINES) && logic->CanUse(RG_HOOKSHOT));}}), - Entrance(RR_FOREST_TEMPLE_SEWER, {[]{return logic->HasItem(RG_GOLDEN_SCALE) || logic->CanUse(RG_IRON_BOOTS) || HasAccessTo(RR_FOREST_TEMPLE_NE_OUTDOORS_UPPER);}}), - Entrance(RR_FOREST_TEMPLE_FALLING_ROOM, {[]{return false;}}), - }); - - areaTable[RR_FOREST_TEMPLE_NE_OUTDOORS_UPPER] = Region("Forest Temple NE Outdoors Upper", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->DekuBabaSticks, {[]{return logic->CanGetDekuBabaSticks();}}), - EventAccess(&logic->DekuBabaNuts, {[]{return logic->CanGetDekuBabaNuts();}}), - }, {}, { - //Exits - Entrance(RR_FOREST_TEMPLE_NE_OUTDOORS_LOWER, {[]{return true;}}), - Entrance(RR_FOREST_TEMPLE_MAP_ROOM, {[]{return true;}}), - Entrance(RR_FOREST_TEMPLE_FALLING_ROOM, {[]{return ctx->GetTrickOption(RT_FOREST_DOORFRAME) && logic->CanJumpslashExceptHammer() && logic->CanUse(RG_HOVER_BOOTS) && logic->CanUse(RG_SCARECROW);}}), - }); - - areaTable[RR_FOREST_TEMPLE_MAP_ROOM] = Region("Forest Temple Map Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FOREST_TEMPLE_MAP_CHEST, logic->CanKillEnemy(RE_BLUE_BUBBLE)), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_NW_OUTDOORS_LOWER, {[]{return Here(RR_FOREST_TEMPLE_MAP_ROOM, []{return logic->CanKillEnemy(RE_BLUE_BUBBLE);});}}), - Entrance(RR_FOREST_TEMPLE_NE_OUTDOORS_UPPER, {[]{return Here(RR_FOREST_TEMPLE_MAP_ROOM, []{return logic->CanKillEnemy(RE_BLUE_BUBBLE);});}}), - }); - - areaTable[RR_FOREST_TEMPLE_SEWER] = Region("Forest Temple Sewer", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FOREST_TEMPLE_WELL_CHEST, HasAccessTo(RR_FOREST_TEMPLE_NE_OUTDOORS_UPPER)), - LOCATION(RC_FOREST_TEMPLE_WELL_WEST_HEART, HasAccessTo(RR_FOREST_TEMPLE_NE_OUTDOORS_UPPER) || (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8)), - LOCATION(RC_FOREST_TEMPLE_WELL_EAST_HEART, HasAccessTo(RR_FOREST_TEMPLE_NE_OUTDOORS_UPPER) || (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8)), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_NW_OUTDOORS_LOWER, {[]{return true;}}), - Entrance(RR_FOREST_TEMPLE_NE_OUTDOORS_LOWER, {[]{return true;}}), - }); - - areaTable[RR_FOREST_TEMPLE_BELOW_BOSS_KEY_CHEST] = Region("Forest Temple Below Boss Key Chest", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_FOREST_TEMPLE_NW_OUTDOORS_UPPER, {[]{return Here(RR_FOREST_TEMPLE_BELOW_BOSS_KEY_CHEST, []{return logic->CanKillEnemy(RE_BLUE_BUBBLE);});}}), - }); - - areaTable[RR_FOREST_TEMPLE_FLOORMASTER_ROOM] = Region("Forest Temple Floormaster Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FOREST_TEMPLE_FLOORMASTER_CHEST, logic->CanDamage()), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_NW_OUTDOORS_UPPER, {[]{return true;}}), - }); - - areaTable[RR_FOREST_TEMPLE_WEST_CORRIDOR] = Region("Forest Temple West Corridor", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_FOREST_TEMPLE_LOBBY, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 1, 5);}}), - Entrance(RR_FOREST_TEMPLE_BLOCK_PUSH_ROOM, {[]{return logic->CanAttack() || logic->CanUse(RG_NUTS);}}), - }); - - areaTable[RR_FOREST_TEMPLE_BLOCK_PUSH_ROOM] = Region("Forest Temple Block Push Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FOREST_TEMPLE_EYE_SWITCH_CHEST, logic->HasItem(RG_GORONS_BRACELET) && (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT))), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_WEST_CORRIDOR, {[]{return true;}}), - Entrance(RR_FOREST_TEMPLE_NW_OUTDOORS_UPPER, {[]{return logic->CanUse(RG_HOVER_BOOTS) || (ctx->GetTrickOption(RT_FOREST_OUTSIDE_BACKDOOR) && logic->CanJumpslashExceptHammer() && logic->HasItem(RG_GORONS_BRACELET));}}), - Entrance(RR_FOREST_TEMPLE_NW_CORRIDOR_TWISTED, {[]{return logic->IsAdult && logic->HasItem(RG_GORONS_BRACELET) && logic->SmallKeys(RR_FOREST_TEMPLE, 2);}}), - Entrance(RR_FOREST_TEMPLE_NW_CORRIDOR_STRAIGHTENED, {[]{return logic->IsAdult && (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT)) && logic->HasItem(RG_GORONS_BRACELET) && logic->SmallKeys(RR_FOREST_TEMPLE, 2);}}), - }); - - areaTable[RR_FOREST_TEMPLE_NW_CORRIDOR_TWISTED] = Region("Forest Temple NW Corridor Twisted", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_FOREST_TEMPLE_BLOCK_PUSH_ROOM, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 2);}}), - Entrance(RR_FOREST_TEMPLE_RED_POE_ROOM, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 3);}}), - }); - - areaTable[RR_FOREST_TEMPLE_NW_CORRIDOR_STRAIGHTENED] = Region("Forest Temple NW Corridor Straightened", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FOREST_TEMPLE_BOSS_KEY_CHEST, true), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_BELOW_BOSS_KEY_CHEST, {[]{return true;}}), - Entrance(RR_FOREST_TEMPLE_BLOCK_PUSH_ROOM, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 2);}}), - }); - - areaTable[RR_FOREST_TEMPLE_RED_POE_ROOM] = Region("Forest Temple Red Poe Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->ForestTempleJoelle, {[]{return logic->ForestTempleJoelle || logic->CanUse(RG_FAIRY_BOW);}}), - }, { - //Locations - LOCATION(RC_FOREST_TEMPLE_RED_POE_CHEST, logic->ForestTempleJoelle), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_NW_CORRIDOR_TWISTED, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 3);}}), - Entrance(RR_FOREST_TEMPLE_UPPER_STALFOS, {[]{return true;}}), - }); - - areaTable[RR_FOREST_TEMPLE_UPPER_STALFOS] = Region("Forest Temple Upper Stalfos", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FOREST_TEMPLE_BOW_CHEST, logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MEGATON_HAMMER)), - LOCATION(RC_FOREST_TEMPLE_UPPER_STALFOS_POT_1, logic->CanBreakPots()), - LOCATION(RC_FOREST_TEMPLE_UPPER_STALFOS_POT_2, logic->CanBreakPots()), - LOCATION(RC_FOREST_TEMPLE_UPPER_STALFOS_POT_3, logic->CanBreakPots()), - LOCATION(RC_FOREST_TEMPLE_UPPER_STALFOS_POT_4, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_RED_POE_ROOM, {[]{return logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MEGATON_HAMMER);}}), - Entrance(RR_FOREST_TEMPLE_BLUE_POE_ROOM, {[]{return logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MEGATON_HAMMER);}}), - }); - - areaTable[RR_FOREST_TEMPLE_BLUE_POE_ROOM] = Region("Forest Temple Blue Poe Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->ForestTempleBeth, {[]{return logic->ForestTempleBeth || logic->CanUse(RG_FAIRY_BOW);}}), - }, { - //Locations - LOCATION(RC_FOREST_TEMPLE_BLUE_POE_CHEST, logic->ForestTempleBeth), - LOCATION(RC_FOREST_TEMPLE_BLUE_POE_POT_1, logic->CanBreakPots()), - LOCATION(RC_FOREST_TEMPLE_BLUE_POE_POT_2, logic->CanBreakPots()), - LOCATION(RC_FOREST_TEMPLE_BLUE_POE_POT_3, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_UPPER_STALFOS, {[]{return true;}}), - Entrance(RR_FOREST_TEMPLE_NE_CORRIDOR_STRAIGHTENED, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 4);}}), - }); - - areaTable[RR_FOREST_TEMPLE_NE_CORRIDOR_STRAIGHTENED] = Region("Forest Temple NE Corridor Straightened", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_FOREST_TEMPLE_BLUE_POE_ROOM, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 4);}}), - Entrance(RR_FOREST_TEMPLE_FROZEN_EYE_ROOM, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 5);}}), - }); - - areaTable[RR_FOREST_TEMPLE_NE_CORRIDOR_TWISTED] = Region("Forest Temple NE Corridor Twisted", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_FOREST_TEMPLE_FROZEN_EYE_ROOM, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 5);}}), - Entrance(RR_FOREST_TEMPLE_FALLING_ROOM, {[]{return true;}}), - }); - - areaTable[RR_FOREST_TEMPLE_FROZEN_EYE_ROOM] = Region("Forest Temple Frozen Eye Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FOREST_TEMPLE_FROZEN_EYE_POT_1, logic->CanBreakPots()), - LOCATION(RC_FOREST_TEMPLE_FROZEN_EYE_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_NE_CORRIDOR_STRAIGHTENED, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 5);}}), - Entrance(RR_FOREST_TEMPLE_NE_CORRIDOR_TWISTED, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 5) && (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_DINS_FIRE));}}), - }); - - areaTable[RR_FOREST_TEMPLE_FALLING_ROOM] = Region("Forest Temple Falling Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FOREST_TEMPLE_FALLING_CEILING_ROOM_CHEST, true), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_NE_OUTDOORS_LOWER, {[]{return true;}}), - Entrance(RR_FOREST_TEMPLE_GREEN_POE_ROOM, {[]{return true;}}), - }); - - areaTable[RR_FOREST_TEMPLE_GREEN_POE_ROOM] = Region("Forest Temple Green Poe Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->ForestTempleAmy, {[]{return logic->ForestTempleAmy || logic->CanUse(RG_FAIRY_BOW);}}), - }, { - //Locations - LOCATION(RC_FOREST_TEMPLE_GREEN_POE_POT_1, logic->CanBreakPots()), - LOCATION(RC_FOREST_TEMPLE_GREEN_POE_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_FALLING_ROOM, {[]{return true;}}), - Entrance(RR_FOREST_TEMPLE_EAST_CORRIDOR, {[]{return logic->ForestTempleAmy;}}), - }); - - areaTable[RR_FOREST_TEMPLE_EAST_CORRIDOR] = Region("Forest Temple East Corridor", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_FOREST_TEMPLE_LOBBY, {[]{return logic->CanAttack() || logic->CanUse(RG_NUTS);}}), - Entrance(RR_FOREST_TEMPLE_GREEN_POE_ROOM, {[]{return logic->CanAttack() || logic->CanUse(RG_NUTS);}}), - }); - - areaTable[RR_FOREST_TEMPLE_BOSS_REGION] = Region("Forest Temple Boss Region", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FOREST_TEMPLE_BASEMENT_CHEST, true), - LOCATION(RC_FOREST_TEMPLE_GS_BASEMENT, logic->HookshotOrBoomerang()), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_LOBBY, {[]{return true;}}), - Entrance(RR_FOREST_TEMPLE_BOSS_ENTRYWAY, {[]{return logic->HasItem(RG_FOREST_TEMPLE_BOSS_KEY);}}), - }); - } - - /*--------------------------- - | MASTER QUEST DUNGEON | - ---------------------------*/ - if (ctx->GetDungeon(FOREST_TEMPLE)->IsMQ()) { - areaTable[RR_FOREST_TEMPLE_MQ_LOBBY] = Region("Forest Temple MQ Lobby", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FOREST_TEMPLE_MQ_FIRST_ROOM_CHEST, logic->CanPassEnemy(RE_BIG_SKULLTULA, ED_SHORT_JUMPSLASH, false) || logic->CanUse(RG_HOVER_BOOTS)), - //Implies CanPassEnemy(RE_BIG_SKULLTULA) - LOCATION(RC_FOREST_TEMPLE_MQ_GS_FIRST_HALLWAY, logic->HookshotOrBoomerang()), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_ENTRYWAY, {[]{return true;}}), - Entrance(RR_FOREST_TEMPLE_MQ_CENTRAL_AREA, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 1) && logic->CanPassEnemy(RE_BIG_SKULLTULA);}}), - }); - - areaTable[RR_FOREST_TEMPLE_MQ_CENTRAL_AREA] = Region("Forest Temple MQ Central Region", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->ForestTempleMeg, {[]{return logic->ForestTempleJoelle && logic->ForestTempleBeth && logic->ForestTempleAmy && logic->CanKillEnemy(RE_MEG);}}), - }, { - //Locations - LOCATION(RC_FOREST_TEMPLE_MQ_LOBBY_POT_1, logic->CanBreakPots()), - LOCATION(RC_FOREST_TEMPLE_MQ_LOBBY_POT_2, logic->CanBreakPots()), - LOCATION(RC_FOREST_TEMPLE_MQ_LOBBY_POT_3, logic->CanBreakPots()), - LOCATION(RC_FOREST_TEMPLE_MQ_LOBBY_POT_4, logic->CanBreakPots()), - LOCATION(RC_FOREST_TEMPLE_MQ_LOBBY_POT_5, logic->CanBreakPots()), - LOCATION(RC_FOREST_TEMPLE_MQ_LOBBY_POT_6, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_MQ_WOLFOS_ROOM, {[]{return logic->IsChild || logic->CanUse(RG_SONG_OF_TIME);}}), - Entrance(RR_FOREST_TEMPLE_MQ_NW_OUTDOORS, {[]{return logic->CanHitEyeTargets();}}), - Entrance(RR_FOREST_TEMPLE_MQ_NE_OUTDOORS, {[]{return logic->CanHitEyeTargets();}}), - Entrance(RR_FOREST_TEMPLE_MQ_LOWER_BLOCK_PUZZLE, {[]{return Here(RR_FOREST_TEMPLE_MQ_CENTRAL_AREA, []{return logic->CanKillEnemy(RE_STALFOS);});}}), - //implies the other 3 poes - Entrance(RR_FOREST_TEMPLE_MQ_BASEMENT, {[]{return logic->ForestTempleMeg;}}), - }); - - areaTable[RR_FOREST_TEMPLE_MQ_WOLFOS_ROOM] = Region("Forest Temple MQ Wolfos Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->FairyPot, {[]{return true;}}), - EventAccess(&logic->ForestClearBelowBowChest, {[]{return logic->CanKillEnemy(RE_WOLFOS);}}), - }, { - //Locations - LOCATION(RC_FOREST_TEMPLE_MQ_WOLFOS_CHEST, logic->ForestClearBelowBowChest), - LOCATION(RC_FOREST_TEMPLE_MQ_WOLFOS_POT_1, logic->CanBreakPots()), - LOCATION(RC_FOREST_TEMPLE_MQ_WOLFOS_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_MQ_CENTRAL_AREA, {[]{return logic->ForestClearBelowBowChest && (logic->IsChild || logic->CanUse(RG_SONG_OF_TIME));}}), - }); - - areaTable[RR_FOREST_TEMPLE_MQ_LOWER_BLOCK_PUZZLE] = Region("Forest Temple MQ Lower Block Puzzle", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //longshot is capable of hitting the switch, but some invisible collision makes the shot harder than you would think, so it may be trickworthy - EventAccess(&logic->MQForestBlockRoomTargets, {[]{return (ctx->GetTrickOption(RT_FOREST_MQ_BLOCK_PUZZLE) && logic->CanUse(RG_BOMBCHU_5));}}), - //It is barely possible to get this as child with master + hovers, but it's tight without bunny speed - EventAccess(&logic->ForestCanTwistHallway, {[]{return (ctx->GetTrickOption(RT_FOREST_MQ_JS_HALLWAY_SWITCH) && logic->CanUse(RG_HOVER_BOOTS) && - (logic->IsAdult && logic->CanJumpslash()) || - (logic->CanUse(RG_STICKS) || logic->CanUse(RG_BIGGORON_SWORD) || (logic->MQForestBlockRoomTargets && logic->CanUse(RG_MASTER_SWORD)))) || - (ctx->GetTrickOption(RT_FOREST_MQ_RANG_HALLWAY_SWITCH) && logic->CanUse(RG_BOOMERANG)) || - (ctx->GetTrickOption(RT_FOREST_MQ_HOOKSHOT_HALLWAY_SWITCH) && logic->CanUse(RG_HOOKSHOT));}}), - }, { - //Locations - LOCATION(RC_FOREST_TEMPLE_MQ_GS_BLOCK_PUSH_ROOM, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_MQ_CENTRAL_AREA, {[]{return Here(RR_FOREST_TEMPLE_MQ_CENTRAL_AREA, []{return logic->CanKillEnemy(RE_STALFOS);});}}), - Entrance(RR_FOREST_TEMPLE_MQ_MIDDLE_BLOCK_PUZZLE, {[]{return logic->HasItem(RG_GORONS_BRACELET) || (logic->MQForestBlockRoomTargets && logic->CanUse(RG_HOOKSHOT));}}), - //Assumes RR_FOREST_TEMPLE_MQ_MIDDLE_BLOCK_PUZZLE access - Entrance(RR_FOREST_TEMPLE_MQ_UPPER_BLOCK_PUZZLE, {[]{return (logic->IsAdult && logic->HasItem(RG_GORONS_BRACELET)) || (logic->MQForestBlockRoomTargets && logic->CanUse(RG_HOOKSHOT));}}), - Entrance(RR_FOREST_TEMPLE_MQ_OUTDOOR_LEDGE, {[]{return logic->ForestCanTwistHallway && (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS));}}), - }); - - areaTable[RR_FOREST_TEMPLE_MQ_MIDDLE_BLOCK_PUZZLE] = Region("Forest Temple MQ Middle Block Puzzle", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //longshot is capable of hitting the switch, but some invisible collision makes the shot more annoying than you would think, so it may be trickworthy - EventAccess(&logic->MQForestBlockRoomTargets, {[]{return (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_LONGSHOT));}}), - EventAccess(&logic->ForestCanTwistHallway, {[]{return ctx->GetTrickOption(RT_FOREST_MQ_JS_HALLWAY_SWITCH) && - (logic->IsAdult && logic->CanJumpslash()) || - (logic->CanUse(RG_HOVER_BOOTS) && (logic->CanUse(RG_STICKS) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MASTER_SWORD)));}}), - }, {}, { - //Exits - Entrance(RR_FOREST_TEMPLE_MQ_LOWER_BLOCK_PUZZLE, {[]{return true;}}), - Entrance(RR_FOREST_TEMPLE_MQ_UPPER_BLOCK_PUZZLE, {[]{return (logic->IsAdult && logic->HasItem(RG_GORONS_BRACELET)) || (logic->MQForestBlockRoomTargets && logic->CanUse(RG_HOOKSHOT));}}), - //Hammer cannot recoil from here, but can make the jump forwards with a hammer jumpslash as adult - Entrance(RR_FOREST_TEMPLE_MQ_OUTDOOR_LEDGE, {[]{return logic->ForestCanTwistHallway && logic->CanUse(RG_HOVER_BOOTS) || - (ctx->GetTrickOption(RT_FOREST_OUTSIDE_BACKDOOR) && (logic->CanJumpslashExceptHammer() || (logic->IsAdult && logic->CanUse(RG_MEGATON_HAMMER))));}}), - }); - - areaTable[RR_FOREST_TEMPLE_MQ_UPPER_BLOCK_PUZZLE] = Region("Forest Temple MQ After Block Puzzle", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FOREST_TEMPLE_MQ_BOSS_KEY_CHEST, logic->SmallKeys(RR_FOREST_TEMPLE, 3)), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_MQ_STRAIGHT_HALLWAY, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 3);}}), - Entrance(RR_FOREST_TEMPLE_MQ_JOELLE_ROOM, {[]{return logic->ForestCanTwistHallway && logic->SmallKeys(RR_FOREST_TEMPLE, 4);}}), - //!QUANTUM LOGIC! - //As there is no way in default logic to reach the other possible key use without going through RR_FOREST_TEMPLE_MQ_NW_OUTDOORS, this is logically safe for now - //Breaks if there's any other way to RR_FOREST_TEMPLE_MQ_FALLING_ROOM than going through the eye targets in RR_FOREST_TEMPLE_MQ_CENTRAL_AREA - //Requires a bow/sling ammo source once ammo logic is done, to avoid edge cases. - Entrance(RR_FOREST_TEMPLE_MQ_NW_OUTDOORS, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 2) && Here(RR_FOREST_TEMPLE_MQ_UPPER_BLOCK_PUZZLE, []{return logic->CanKillEnemy(RE_FLOORMASTER);});}}), - }); - - areaTable[RR_FOREST_TEMPLE_MQ_STRAIGHT_HALLWAY] = Region("Forest Temple MQ Straight Hallway", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FOREST_TEMPLE_MQ_BOSS_KEY_CHEST, logic->SmallKeys(RR_FOREST_TEMPLE, 3)), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_MQ_FLOORMASTER_ROOM, {[]{return true;}}), - }); - - areaTable[RR_FOREST_TEMPLE_MQ_FLOORMASTER_ROOM] = Region("Forest Temple MQ Floormaster Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_FOREST_TEMPLE_MQ_OUTDOOR_LEDGE, {[]{return Here(RR_FOREST_TEMPLE_MQ_FLOORMASTER_ROOM, []{return logic->CanKillEnemy(RE_FLOORMASTER);});}}), - }); - - areaTable[RR_FOREST_TEMPLE_MQ_OUTDOOR_LEDGE] = Region("Forest Temple MQ Outdoor Ledge", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - EventAccess(&logic->ForestCanTwistHallway, {[]{return logic->CanHitSwitch();}}), - }, { - //Locations - LOCATION(RC_FOREST_TEMPLE_MQ_REDEAD_CHEST, logic->CanKillEnemy(RE_REDEAD)), - LOCATION(RC_FOREST_TEMPLE_MQ_COURTYARD_RIGHT_HEART, true), - LOCATION(RC_FOREST_TEMPLE_MQ_COURTYARD_MIDDLE_HEART, true), - LOCATION(RC_FOREST_TEMPLE_MQ_COURTYARD_LEFT_HEART, true), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_MQ_NW_OUTDOORS, {[]{return true;}}), - }); - - areaTable[RR_FOREST_TEMPLE_MQ_NW_OUTDOORS] = Region("Forest Temple MQ NW Outdoors", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FOREST_TEMPLE_MQ_GS_LEVEL_ISLAND_COURTYARD, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)), - //the well checks are considered from both areas instead of being a region because the draining is a temp flag and the skull (as well as the chest with hook glitch) has different breath timers from each side - LOCATION(RC_FOREST_TEMPLE_MQ_GS_WELL, (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8 && logic->CanUse(RG_HOOKSHOT))), - LOCATION(RC_FOREST_TEMPLE_MQ_COURTYARD_RIGHT_HEART, logic->CanUse(RG_BOOMERANG) && ctx->GetTrickOption(RT_FOREST_OUTDOORS_HEARTS_BOOMERANG)), - LOCATION(RC_FOREST_TEMPLE_MQ_COURTYARD_MIDDLE_HEART, logic->CanUse(RG_BOOMERANG) && ctx->GetTrickOption(RT_FOREST_OUTDOORS_HEARTS_BOOMERANG)), - LOCATION(RC_FOREST_TEMPLE_MQ_COURTYARD_LEFT_HEART, logic->CanUse(RG_BOOMERANG) && ctx->GetTrickOption(RT_FOREST_OUTDOORS_HEARTS_BOOMERANG)), - LOCATION(RC_FOREST_TEMPLE_MQ_WELL_WEST_HEART, logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8), - LOCATION(RC_FOREST_TEMPLE_MQ_WELL_MIDDLE_HEART, logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8), - LOCATION(RC_FOREST_TEMPLE_MQ_WELL_EAST_HEART, logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_MQ_NE_OUTDOORS, {[]{return (((logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_LONGSHOT) || (ctx->GetTrickOption(RT_FOREST_MQ_WELL_SWIM) && logic->CanUse(RG_HOOKSHOT))) && logic->HasItem(RG_BRONZE_SCALE)) || logic->HasItem(RG_GOLDEN_SCALE)) && logic->WaterTimer() >= 16;}}), - Entrance(RR_FOREST_TEMPLE_MQ_OUTDOORS_TOP_LEDGES, {[]{return logic->CanUse(RG_FIRE_ARROWS);}}), - }); - -//The well only coniders the eye target here because the eye target is a temp flag, making it unwieldy to use as an EventAccess or to make it it's own room - areaTable[RR_FOREST_TEMPLE_MQ_NE_OUTDOORS] = Region("Forest Temple MQ NE Outdoors", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->DekuBabaSticks, {[]{return logic->CanGetDekuBabaSticks();}}), - EventAccess(&logic->DekuBabaNuts, {[]{return logic->CanGetDekuBabaNuts();}}), - }, { - //Locations - LOCATION(RC_FOREST_TEMPLE_MQ_WELL_CHEST, logic->CanHitEyeTargets()), - LOCATION(RC_FOREST_TEMPLE_MQ_GS_RAISED_ISLAND_COURTYARD, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)), - //implies logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA) - LOCATION(RC_FOREST_TEMPLE_MQ_GS_WELL, logic->CanHitEyeTargets() || (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 24 && logic->CanUse(RG_HOOKSHOT))), - LOCATION(RC_FOREST_TEMPLE_MQ_WELL_WEST_HEART, (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8) || logic->CanHitEyeTargets()), - LOCATION(RC_FOREST_TEMPLE_MQ_WELL_MIDDLE_HEART, (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8) || logic->CanHitEyeTargets()), - LOCATION(RC_FOREST_TEMPLE_MQ_WELL_EAST_HEART, (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8) || logic->CanHitEyeTargets()), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_MQ_NW_OUTDOORS, {[]{return (((logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_LONGSHOT)) && logic->HasItem(RG_BRONZE_SCALE)) || logic->HasItem(RG_GOLDEN_SCALE)) && logic->WaterTimer() >= 16;}}), - Entrance(RR_FOREST_TEMPLE_MQ_OUTDOORS_TOP_LEDGES, {[]{return logic->CanUse(RG_LONGSHOT) || (logic->CanUse(RG_HOOKSHOT) && ((logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)) || logic->CanUse(RG_SONG_OF_TIME)));}}), - Entrance(RR_FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE, {[]{return logic->CanUse(RG_LONGSHOT);}}), - }); - - areaTable[RR_FOREST_TEMPLE_MQ_OUTDOORS_TOP_LEDGES] = Region("Forest Temple MQ Outdoors Top Ledges", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_UPPER_CHEST, true), - //Actually killing the skull from the doorframe with melee is annoying. Hammer swing hits low enough unaided, other swords need to crouch stab but the spot is precise based on range. kokiri sword doesn't reach at all for adult. - LOCATION(RC_FOREST_TEMPLE_MQ_GS_RAISED_ISLAND_COURTYARD, ((logic->IsAdult && logic->CanUse(RG_SONG_OF_TIME)) || (logic->CanUse(RG_HOVER_BOOTS) && ctx->GetTrickOption(RT_FOREST_DOORFRAME))) && logic->CanJumpslash() && - (logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->BlastOrSmash() || logic->CanUse(RG_DINS_FIRE) || logic->CanUse(RG_FAIRY_BOW) || logic->HookshotOrBoomerang() || - (logic->CanStandingShield() && (logic->CanUse(RG_STICKS) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MASTER_SWORD) || (logic->IsChild && logic->CanUse(RG_KOKIRI_SWORD)))))), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_MQ_NW_OUTDOORS, {[]{return logic->HasFireSourceWithTorch();}}), - Entrance(RR_FOREST_TEMPLE_MQ_NE_OUTDOORS, {[]{return true;}}), - //N64 logic doesn't check damage but I always take some so I'm adding it - Entrance(RR_FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE, {[]{return ctx->GetTrickOption(RT_FOREST_OUTDOORS_LEDGE) && logic->CanUse(RG_HOVER_BOOTS) && logic->CanJumpslash() && logic->TakeDamage();}}), - }); - - areaTable[RR_FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE] = Region("Forest Temple MQ NE Outdoors Ledge", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_LOWER_CHEST, true), - }, { - //Exits - //Skipping swim here is non-trival, needs a roll-jump. If a swim lock is added it's probably wise to copy deku baba events here - Entrance(RR_FOREST_TEMPLE_MQ_NE_OUTDOORS, {[]{return true;}}), - Entrance(RR_FOREST_TEMPLE_MQ_FALLING_ROOM, {[]{return logic->CanUse(RG_SONG_OF_TIME);}}), - }); - - areaTable[RR_FOREST_TEMPLE_MQ_JOELLE_ROOM] = Region("Forest Temple MQ Joelle room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->ForestTempleJoelle, {[]{return logic->CanUse(RG_FAIRY_BOW);}}), - }, { - //Locations - LOCATION(RC_FOREST_TEMPLE_MQ_MAP_CHEST, logic->ForestTempleJoelle), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_MQ_UPPER_BLOCK_PUZZLE, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 4);}}), - Entrance(RR_FOREST_TEMPLE_MQ_3_STALFOS_ROOM, {[]{return true;}}), - }); - - areaTable[RR_FOREST_TEMPLE_MQ_3_STALFOS_ROOM] = Region("Forest Temple MQ 3 Stalfos Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - //technically happens in RR_FOREST_TEMPLE_MQ_WOLFOS_ROOM, but the way this room blocks the hole means it cannot be logical to do anything else there. - EventAccess(&logic->ForestClearBelowBowChest, {[]{return logic->CanKillEnemy(RE_WOLFOS);}}), - }, { - //Locations - LOCATION(RC_FOREST_TEMPLE_MQ_BOW_CHEST, logic->ForestClearBelowBowChest && logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 3)), - LOCATION(RC_FOREST_TEMPLE_MQ_UPPER_STALFOS_POT_1, logic->CanBreakPots()), - LOCATION(RC_FOREST_TEMPLE_MQ_UPPER_STALFOS_POT_2, logic->CanBreakPots()), - LOCATION(RC_FOREST_TEMPLE_MQ_UPPER_STALFOS_POT_3, logic->CanBreakPots()), - LOCATION(RC_FOREST_TEMPLE_MQ_UPPER_STALFOS_POT_4, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_MQ_JOELLE_ROOM, {[]{return logic->ForestClearBelowBowChest && logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 3);}}), - Entrance(RR_FOREST_TEMPLE_MQ_BETH_ROOM, {[]{return logic->ForestClearBelowBowChest && logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 3);}}), - }); - - areaTable[RR_FOREST_TEMPLE_MQ_BETH_ROOM] = Region("Forest Temple MQ Beth Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->ForestTempleBeth, {[]{return logic->CanUse(RG_FAIRY_BOW);}}), - }, { - //Locations - LOCATION(RC_FOREST_TEMPLE_MQ_COMPASS_CHEST, logic->ForestTempleBeth), - LOCATION(RC_FOREST_TEMPLE_MQ_BLUE_POE_POT_1, logic->CanBreakPots()), - LOCATION(RC_FOREST_TEMPLE_MQ_BLUE_POE_POT_2, logic->CanBreakPots()), - LOCATION(RC_FOREST_TEMPLE_MQ_BLUE_POE_POT_3, logic->CanBreakPots()), - }, { - //Exits - //!QUANTUM LOGIC! - //This key logic assumes that you can get to falling room either by spending the 5th key here, or by wasting a key in falling room itself. - //While being the 5th key makes this simpler in theory, if a different age can waste the key compared to reaching this room it breaks - Entrance(RR_FOREST_TEMPLE_MQ_FALLING_ROOM, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 5) && - Here(RR_FOREST_TEMPLE_MQ_BETH_ROOM, []{return logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_DINS_FIRE);});}}), - Entrance(RR_FOREST_TEMPLE_MQ_TORCH_SHOT_ROOM, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 6);}}), - Entrance(RR_FOREST_TEMPLE_MQ_3_STALFOS_ROOM, {[]{return true;}}), - }); - - //This room exists to show the actual map layout, and for when the crates get added to logic - areaTable[RR_FOREST_TEMPLE_MQ_TORCH_SHOT_ROOM] = Region("Forest Temple MQ Torch Shot Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_FOREST_TEMPLE_MQ_FALLING_ROOM, {[]{return logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_DINS_FIRE);}}), - Entrance(RR_FOREST_TEMPLE_MQ_BETH_ROOM, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 6);}}), - }); - - areaTable[RR_FOREST_TEMPLE_MQ_FALLING_ROOM] = Region("Forest Temple MQ Falling Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FOREST_TEMPLE_MQ_FALLING_CEILING_ROOM_CHEST, true), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE, {[]{return true;}}), - Entrance(RR_FOREST_TEMPLE_MQ_AMY_ROOM, {[]{return logic->SmallKeys(RR_FOREST_TEMPLE, 6);}}), - }); - - areaTable[RR_FOREST_TEMPLE_MQ_AMY_ROOM] = Region("Forest Temple MQ Amy Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->ForestTempleAmy, {[]{return logic->CanUse(RG_FAIRY_BOW);}}), - }, { - //Locations - LOCATION(RC_FOREST_TEMPLE_MQ_GREEN_POE_POT_1, logic->CanBreakPots()), - LOCATION(RC_FOREST_TEMPLE_MQ_GREEN_POE_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_MQ_CENTRAL_AREA, {[]{return logic->ForestTempleAmy;}}), - Entrance(RR_FOREST_TEMPLE_MQ_FALLING_ROOM, {[]{return true;}}), - }); - - areaTable[RR_FOREST_TEMPLE_MQ_BASEMENT] = Region("Forest Temple MQ Basement", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - //Implies CanHitSwitch() - EventAccess(&logic->ForestOpenBossCorridor, {[]{return logic->CanHitEyeTargets();}}), - }, { - //Locations - LOCATION(RC_FOREST_TEMPLE_MQ_BASEMENT_CHEST, true), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_MQ_CENTRAL_AREA, {[]{return logic->ForestTempleMeg;}}), - Entrance(RR_FOREST_TEMPLE_MQ_BASEMENT_POT_ROOM, {[]{return logic->CanPassEnemy(RE_BIG_SKULLTULA) || logic->TakeDamage();}}), - Entrance(RR_FOREST_TEMPLE_MQ_BOSS_REGION, {[]{return logic->ForestOpenBossCorridor;}}), - }); - - areaTable[RR_FOREST_TEMPLE_MQ_BASEMENT_POT_ROOM] = Region("Forest Temple MQ Basement Pot Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_FOREST_TEMPLE_MQ_BASEMENT_POT_1, logic->CanBreakPots()), - LOCATION(RC_FOREST_TEMPLE_MQ_BASEMENT_POT_2, logic->CanBreakPots()), - LOCATION(RC_FOREST_TEMPLE_MQ_BASEMENT_POT_3, logic->CanBreakPots()), - LOCATION(RC_FOREST_TEMPLE_MQ_BASEMENT_POT_4, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_FOREST_TEMPLE_MQ_BASEMENT, {[]{return logic->CanPassEnemy(RE_BIG_SKULLTULA);}}), - }); - - areaTable[RR_FOREST_TEMPLE_MQ_BOSS_REGION] = Region("Forest Temple MQ Boss Region", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_FOREST_TEMPLE_MQ_BASEMENT, {[]{return logic->ForestOpenBossCorridor;}}), - Entrance(RR_FOREST_TEMPLE_BOSS_ENTRYWAY, {[]{return logic->HasItem(RG_FOREST_TEMPLE_BOSS_KEY);}}), - }); - } - - /*--------------------------- - | BOSS ROOM | - ---------------------------*/ - areaTable[RR_FOREST_TEMPLE_BOSS_ENTRYWAY] = - Region("Forest Temple Boss Entryway", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, - { - // Exits - Entrance(RR_FOREST_TEMPLE_BOSS_REGION, { [] { return ctx->GetDungeon(FOREST_TEMPLE)->IsVanilla() && false; } }), - Entrance(RR_FOREST_TEMPLE_MQ_BOSS_REGION, { [] { return ctx->GetDungeon(FOREST_TEMPLE)->IsMQ() && false; } }), - Entrance(RR_FOREST_TEMPLE_BOSS_ROOM, { [] { return true; } }), - }); - - areaTable[RR_FOREST_TEMPLE_BOSS_ROOM] = Region("Forest Temple Boss Room", "Forest Temple", {}, NO_DAY_NIGHT_CYCLE, - { - // Events - EventAccess(&logic->ForestTempleClear, { [] { - return logic->ForestTempleClear || (logic->HasBossSoul(RG_PHANTOM_GANON_SOUL) && ((logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD)) && - (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT)))); - } }), - }, - { - // Locations - LOCATION(RC_FOREST_TEMPLE_PHANTOM_GANON_HEART, logic->ForestTempleClear), - LOCATION(RC_PHANTOM_GANON, logic->ForestTempleClear), - }, - { - // Exits - Entrance(RR_FOREST_TEMPLE_BOSS_ENTRYWAY, { [] { return false; } }), - Entrance(RR_SACRED_FOREST_MEADOW, { [] { return logic->ForestTempleClear; } }, false), - }); -} 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 deleted file mode 100644 index 83b9540aa..000000000 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_ganons_castle.cpp +++ /dev/null @@ -1,513 +0,0 @@ -#include "../location_access.hpp" -#include "../../entrance.h" -#include "../../dungeon.h" -#include "../../trial.h" - -using namespace Rando; - -void RegionTable_Init_GanonsCastle() { - /*-------------------------- - | VANILLA/MQ DECIDER | - ---------------------------*/ - areaTable[RR_GANONS_CASTLE_ENTRYWAY] = Region("Ganon's Castle Entryway", "Ganon's Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_GANONS_CASTLE_LOBBY, {[]{return ctx->GetDungeon(GANONS_CASTLE)->IsVanilla();}}), - Entrance(RR_GANONS_CASTLE_MQ_LOBBY, {[]{return ctx->GetDungeon(GANONS_CASTLE)->IsMQ();}}), - Entrance(RR_CASTLE_GROUNDS_FROM_GANONS_CASTLE, {[]{return true;}}), - }); - - /*-------------------------- - | VANILLA DUNGEON | - ---------------------------*/ - if (ctx->GetDungeon(GANONS_CASTLE)->IsVanilla()) { - areaTable[RR_GANONS_CASTLE_LOBBY] = Region("Ganon's Castle Lobby", "Ganon's Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SHEIK_HINT_GC, true), - }, { - //Exits - Entrance(RR_GANONS_CASTLE_ENTRYWAY, {[]{return true;}}), - Entrance(RR_GANONS_CASTLE_FOREST_TRIAL, {[]{return true;}}), - Entrance(RR_GANONS_CASTLE_FIRE_TRIAL, {[]{return true;}}), - Entrance(RR_GANONS_CASTLE_WATER_TRIAL, {[]{return true;}}), - Entrance(RR_GANONS_CASTLE_SHADOW_TRIAL, {[]{return true;}}), - Entrance(RR_GANONS_CASTLE_SPIRIT_TRIAL, {[]{return true;}}), - Entrance(RR_GANONS_CASTLE_LIGHT_TRIAL, {[]{return logic->CanUse(RG_GOLDEN_GAUNTLETS);}}), - Entrance(RR_GANONS_TOWER_FLOOR_1, {[]{return (logic->ForestTrialClear || ctx->GetTrial(TK_FOREST_TRIAL)->IsSkipped()) && - (logic->FireTrialClear || ctx->GetTrial(TK_FIRE_TRIAL)->IsSkipped()) && - (logic->WaterTrialClear || ctx->GetTrial(TK_WATER_TRIAL)->IsSkipped()) && - (logic->ShadowTrialClear || ctx->GetTrial(TK_SHADOW_TRIAL)->IsSkipped()) && - (logic->SpiritTrialClear || ctx->GetTrial(TK_SPIRIT_TRIAL)->IsSkipped()) && - (logic->LightTrialClear || ctx->GetTrial(TK_LIGHT_TRIAL)->IsSkipped());}}), - Entrance(RR_GANONS_CASTLE_DEKU_SCRUBS, {[]{return ctx->GetTrickOption(RT_LENS_GANON) || logic->CanUse(RG_LENS_OF_TRUTH);}}), - }); - - areaTable[RR_GANONS_CASTLE_DEKU_SCRUBS] = Region("Ganon's Castle Deku Scrubs", "Ganon's Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->FreeFairies, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT, logic->CanStunDeku()), - LOCATION(RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT, logic->CanStunDeku()), - LOCATION(RC_GANONS_CASTLE_DEKU_SCRUB_RIGHT, logic->CanStunDeku()), - LOCATION(RC_GANONS_CASTLE_DEKU_SCRUB_LEFT, logic->CanStunDeku()), - LOCATION(RC_GANONS_CASTLE_SCRUBS_FAIRY_1, true), - LOCATION(RC_GANONS_CASTLE_SCRUBS_FAIRY_2, true), - LOCATION(RC_GANONS_CASTLE_SCRUBS_FAIRY_3, true), - LOCATION(RC_GANONS_CASTLE_SCRUBS_FAIRY_4, true), - LOCATION(RC_GANONS_CASTLE_SCRUBS_FAIRY_5, true), - LOCATION(RC_GANONS_CASTLE_SCRUBS_FAIRY_6, true), - LOCATION(RC_GANONS_CASTLE_SCRUBS_FAIRY_7, true), - LOCATION(RC_GANONS_CASTLE_SCRUBS_FAIRY_8, true), - }, {}); - - areaTable[RR_GANONS_CASTLE_FOREST_TRIAL] = Region("Ganon's Castle Forest Trial", "Ganon's Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->ForestTrialClear, {[]{return logic->CanUse(RG_LIGHT_ARROWS) && (logic->CanUse(RG_FIRE_ARROWS) || logic->CanUse(RG_DINS_FIRE));}}), - }, { - //Locations - LOCATION(RC_GANONS_CASTLE_FOREST_TRIAL_CHEST, logic->CanDamage()), - LOCATION(RC_GANONS_CASTLE_FOREST_TRIAL_POT_1, logic->CanBreakPots() && (logic->CanUse(RG_FIRE_ARROWS) || logic->CanUse(RG_DINS_FIRE))), - LOCATION(RC_GANONS_CASTLE_FOREST_TRIAL_POT_2, logic->CanBreakPots() && (logic->CanUse(RG_FIRE_ARROWS) || logic->CanUse(RG_DINS_FIRE))), - }, {}); - - areaTable[RR_GANONS_CASTLE_FIRE_TRIAL] = Region("Ganon's Castle Fire Trial", "Ganon's Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->FireTrialClear, {[]{return logic->CanUse(RG_GORON_TUNIC) && logic->CanUse(RG_GOLDEN_GAUNTLETS) && logic->CanUse(RG_LIGHT_ARROWS) && logic->CanUse(RG_LONGSHOT);}}), - }, { - //Locations - LOCATION(RC_GANONS_CASTLE_FIRE_TRIAL_POT_1, logic->CanBreakPots() && logic->CanUse(RG_GORON_TUNIC) && logic->CanUse(RG_GOLDEN_GAUNTLETS) && logic->CanUse(RG_LONGSHOT)), - LOCATION(RC_GANONS_CASTLE_FIRE_TRIAL_POT_2, logic->CanBreakPots() && logic->CanUse(RG_GORON_TUNIC) && logic->CanUse(RG_GOLDEN_GAUNTLETS) && logic->CanUse(RG_LONGSHOT)), - LOCATION(RC_GANONS_CASTLE_FIRE_TRIAL_HEART, logic->CanUse(RG_GORON_TUNIC)), - }, {}); - - areaTable[RR_GANONS_CASTLE_WATER_TRIAL] = Region("Ganon's Castle Water Trial", "Ganon's Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->BlueFireAccess, {[]{return logic->BlueFireAccess || logic->HasBottle();}}), - EventAccess(&logic->FairyPot, {[]{return logic->FairyPot || (logic->BlueFire() && logic->CanKillEnemy(RE_FREEZARD));}}), - EventAccess(&logic->WaterTrialClear, {[]{return logic->BlueFire() && logic->IsAdult && logic->CanUse(RG_MEGATON_HAMMER) && logic->CanUse(RG_LIGHT_ARROWS);}}), - }, { - //Locations - LOCATION(RC_GANONS_CASTLE_WATER_TRIAL_LEFT_CHEST, true), - LOCATION(RC_GANONS_CASTLE_WATER_TRIAL_RIGHT_CHEST, true), - LOCATION(RC_GANONS_CASTLE_WATER_TRIAL_POT_1, logic->CanBreakPots() && logic->BlueFire() && logic->IsAdult && logic->CanUse(RG_MEGATON_HAMMER)), - LOCATION(RC_GANONS_CASTLE_WATER_TRIAL_POT_2, logic->CanBreakPots() && logic->BlueFire() && logic->IsAdult && logic->CanUse(RG_MEGATON_HAMMER)), - LOCATION(RC_GANONS_CASTLE_WATER_TRIAL_POT_3, logic->CanBreakPots() && logic->BlueFire() && logic->CanKillEnemy(RE_FREEZARD)), - }, {}); - - areaTable[RR_GANONS_CASTLE_SHADOW_TRIAL] = Region("Ganon's Castle Shadow Trial", "Ganon's Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->ShadowTrialClear, {[]{return logic->CanUse(RG_LIGHT_ARROWS) && logic->CanUse(RG_MEGATON_HAMMER) && ((logic->CanUse(RG_FIRE_ARROWS) && (ctx->GetTrickOption(RT_LENS_GANON) || logic->CanUse(RG_LENS_OF_TRUTH))) || (logic->CanUse(RG_LONGSHOT) && (logic->CanUse(RG_HOVER_BOOTS) || (logic->CanUse(RG_DINS_FIRE) && (ctx->GetTrickOption(RT_LENS_GANON) || logic->CanUse(RG_LENS_OF_TRUTH))))));}}), - }, { - //Locations - LOCATION(RC_GANONS_CASTLE_SHADOW_TRIAL_FRONT_CHEST, logic->CanUse(RG_FIRE_ARROWS) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_SONG_OF_TIME) || logic->IsChild), - LOCATION(RC_GANONS_CASTLE_SHADOW_TRIAL_GOLDEN_GAUNTLETS_CHEST, logic->CanUse(RG_FIRE_ARROWS) || (logic->CanUse(RG_LONGSHOT) && (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_DINS_FIRE)))), - LOCATION(RC_GANONS_CASTLE_SHADOW_TRIAL_POT_1, logic->CanUse(RG_FIRE_ARROWS) || logic->CanUse(RG_LONGSHOT)), - LOCATION(RC_GANONS_CASTLE_SHADOW_TRIAL_POT_2, logic->CanUse(RG_FIRE_ARROWS) || logic->CanUse(RG_LONGSHOT)), - LOCATION(RC_GANONS_CASTLE_SHADOW_TRIAL_POT_3, logic->CanBreakPots() && logic->CanUse(RG_MEGATON_HAMMER) && ((logic->CanUse(RG_FIRE_ARROWS) && (ctx->GetTrickOption(RT_LENS_GANON) || logic->CanUse(RG_LENS_OF_TRUTH))) || (logic->CanUse(RG_LONGSHOT) && (logic->CanUse(RG_HOVER_BOOTS) || (logic->CanUse(RG_DINS_FIRE) && (ctx->GetTrickOption(RT_LENS_GANON) || logic->CanUse(RG_LENS_OF_TRUTH))))))), - LOCATION(RC_GANONS_CASTLE_SHADOW_TRIAL_POT_4, logic->CanBreakPots() && logic->CanUse(RG_MEGATON_HAMMER) && ((logic->CanUse(RG_FIRE_ARROWS) && (ctx->GetTrickOption(RT_LENS_GANON) || logic->CanUse(RG_LENS_OF_TRUTH))) || (logic->CanUse(RG_LONGSHOT) && (logic->CanUse(RG_HOVER_BOOTS) || (logic->CanUse(RG_DINS_FIRE) && (ctx->GetTrickOption(RT_LENS_GANON) || logic->CanUse(RG_LENS_OF_TRUTH))))))), - LOCATION(RC_GANONS_CASTLE_SHADOW_TRIAL_HEART_1, (logic->CanUse(RG_FIRE_ARROWS) || (logic->CanUse(RG_LONGSHOT) && (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_DINS_FIRE)))) && (ctx->GetTrickOption(RT_LENS_GANON) || logic->CanUse(RG_LENS_OF_TRUTH) || logic->CanUse(RG_BOOMERANG))), - LOCATION(RC_GANONS_CASTLE_SHADOW_TRIAL_HEART_2, (logic->CanUse(RG_FIRE_ARROWS) || (logic->CanUse(RG_LONGSHOT) && (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_DINS_FIRE)))) && (ctx->GetTrickOption(RT_LENS_GANON) || logic->CanUse(RG_LENS_OF_TRUTH) || logic->CanUse(RG_BOOMERANG))), - LOCATION(RC_GANONS_CASTLE_SHADOW_TRIAL_HEART_3, (logic->CanUse(RG_FIRE_ARROWS) || (logic->CanUse(RG_LONGSHOT) && (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_DINS_FIRE)))) && (ctx->GetTrickOption(RT_LENS_GANON) || logic->CanUse(RG_LENS_OF_TRUTH) || logic->CanUse(RG_BOOMERANG))), - }, {}); - - areaTable[RR_GANONS_CASTLE_SPIRIT_TRIAL] = Region("Ganon's Castle Spirit Trial", "Ganon's Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->NutPot, {[]{return logic->NutPot || (((ctx->GetTrickOption(RT_GANON_SPIRIT_TRIAL_HOOKSHOT) && logic->CanJumpslashExceptHammer()) || logic->CanUse(RG_HOOKSHOT)) && logic->CanUse(RG_BOMBCHU_5) && logic->CanUse(RG_FAIRY_BOW) && (logic->CanUse(RG_MIRROR_SHIELD) || (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS))));}}), - EventAccess(&logic->SpiritTrialClear, {[]{return logic->CanUse(RG_LIGHT_ARROWS) && (logic->CanUse(RG_MIRROR_SHIELD) || ctx->GetOption(RSK_SUNLIGHT_ARROWS)) && logic->CanUse(RG_BOMBCHU_5) && ((ctx->GetTrickOption(RT_GANON_SPIRIT_TRIAL_HOOKSHOT) && logic->CanJumpslashExceptHammer()) || logic->CanUse(RG_HOOKSHOT));}}), - }, { - //Locations - LOCATION(RC_GANONS_CASTLE_SPIRIT_TRIAL_CRYSTAL_SWITCH_CHEST, (ctx->GetTrickOption(RT_GANON_SPIRIT_TRIAL_HOOKSHOT) || logic->CanUse(RG_HOOKSHOT)) && logic->CanJumpslashExceptHammer()), - LOCATION(RC_GANONS_CASTLE_SPIRIT_TRIAL_INVISIBLE_CHEST, (ctx->GetTrickOption(RT_GANON_SPIRIT_TRIAL_HOOKSHOT) || logic->CanUse(RG_HOOKSHOT)) && logic->CanUse(RG_BOMBCHU_5) && (ctx->GetTrickOption(RT_LENS_GANON) || logic->CanUse(RG_LENS_OF_TRUTH))), - LOCATION(RC_GANONS_CASTLE_SPIRIT_TRIAL_POT_1, ((ctx->GetTrickOption(RT_GANON_SPIRIT_TRIAL_HOOKSHOT) && logic->CanJumpslashExceptHammer()) || logic->CanUse(RG_HOOKSHOT)) && logic->CanUse(RG_BOMBCHU_5) && logic->CanUse(RG_FAIRY_BOW) && (logic->CanUse(RG_MIRROR_SHIELD) || (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS)))), - LOCATION(RC_GANONS_CASTLE_SPIRIT_TRIAL_POT_2, ((ctx->GetTrickOption(RT_GANON_SPIRIT_TRIAL_HOOKSHOT) && logic->CanJumpslashExceptHammer()) || logic->CanUse(RG_HOOKSHOT)) && logic->CanUse(RG_BOMBCHU_5) && logic->CanUse(RG_FAIRY_BOW) && (logic->CanUse(RG_MIRROR_SHIELD) || (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS)))), - LOCATION(RC_GANONS_CASTLE_SPIRIT_TRIAL_SUN_FAIRY, logic->CanUse(RG_SUNS_SONG)), - LOCATION(RC_GANONS_CASTLE_SPIRIT_TRIAL_HEART, true), - }, {}); - - areaTable[RR_GANONS_CASTLE_LIGHT_TRIAL] = Region("Ganon's Castle Light Trial", "Ganon's Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->LightTrialClear, {[]{return logic->CanUse(RG_LIGHT_ARROWS) && logic->CanUse(RG_HOOKSHOT) && logic->SmallKeys(RR_GANONS_CASTLE, 2) && (ctx->GetTrickOption(RT_LENS_GANON) || logic->CanUse(RG_LENS_OF_TRUTH));}}), - }, { - //Locations - LOCATION(RC_GANONS_CASTLE_LIGHT_TRIAL_FIRST_LEFT_CHEST, true), - LOCATION(RC_GANONS_CASTLE_LIGHT_TRIAL_SECOND_LEFT_CHEST, true), - LOCATION(RC_GANONS_CASTLE_LIGHT_TRIAL_THIRD_LEFT_CHEST, true), - LOCATION(RC_GANONS_CASTLE_LIGHT_TRIAL_FIRST_RIGHT_CHEST, true), - LOCATION(RC_GANONS_CASTLE_LIGHT_TRIAL_SECOND_RIGHT_CHEST, true), - LOCATION(RC_GANONS_CASTLE_LIGHT_TRIAL_THIRD_RIGHT_CHEST, true), - LOCATION(RC_GANONS_CASTLE_LIGHT_TRIAL_INVISIBLE_ENEMIES_CHEST, ctx->GetTrickOption(RT_LENS_GANON) || logic->CanUse(RG_LENS_OF_TRUTH)), - LOCATION(RC_GANONS_CASTLE_LIGHT_TRIAL_LULLABY_CHEST, logic->CanUse(RG_ZELDAS_LULLABY) && logic->SmallKeys(RR_GANONS_CASTLE, 1)), - LOCATION(RC_GANONS_CASTLE_LIGHT_TRIAL_BOULDER_POT_1, logic->CanBreakPots() && logic->SmallKeys(RR_GANONS_CASTLE, 2)), - LOCATION(RC_GANONS_CASTLE_LIGHT_TRIAL_POT_1, logic->CanBreakPots() && logic->CanUse(RG_HOOKSHOT) && logic->SmallKeys(RR_GANONS_CASTLE, 2) && (ctx->GetTrickOption(RT_LENS_GANON) || logic->CanUse(RG_LENS_OF_TRUTH))), - LOCATION(RC_GANONS_CASTLE_LIGHT_TRIAL_POT_2, logic->CanBreakPots() && logic->CanUse(RG_HOOKSHOT) && logic->SmallKeys(RR_GANONS_CASTLE, 2) && (ctx->GetTrickOption(RT_LENS_GANON) || logic->CanUse(RG_LENS_OF_TRUTH))), - }, {}); - - } - - /*--------------------------- - | MASTER QUEST DUNGEON | - ---------------------------*/ - if (ctx->GetDungeon(GANONS_CASTLE)->IsMQ()) { - areaTable[RR_GANONS_CASTLE_MQ_LOBBY] = Region("Ganon's Castle MQ Lobby", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_GANONS_CASTLE_ENTRYWAY, {[]{return logic->CanPassEnemy(RE_GREEN_BUBBLE) || Here(RR_GANONS_CASTLE_MQ_LOBBY, []{return logic->CanKillEnemy(RE_IRON_KNUCKLE) && logic->CanKillEnemy(RE_ARMOS);});}}), - //Implies CanKillEnemy(RE_GREEN_BUBBLE) - Entrance(RR_GANONS_CASTLE_MQ_MAIN, {[]{return Here(RR_GANONS_CASTLE_MQ_LOBBY, []{return logic->CanKillEnemy(RE_IRON_KNUCKLE) && logic->CanKillEnemy(RE_ARMOS);});}}), - }); - - areaTable[RR_GANONS_CASTLE_MQ_MAIN] = Region("Ganon's Castle MQ Main", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SHEIK_HINT_MQ_GC, true), - }, { - //Exits - Entrance(RR_GANONS_CASTLE_MQ_LOBBY, {[]{return true;}}), - Entrance(RR_GANONS_CASTLE_MQ_FOREST_TRIAL_STALFOS_ROOM, {[]{return true;}}), - Entrance(RR_GANONS_CASTLE_MQ_FIRE_TRIAL_MAIN_ROOM, {[]{return true;}}), - Entrance(RR_GANONS_CASTLE_MQ_WATER_TRIAL_GEYSER_ROOM, {[]{return true;}}), - Entrance(RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_STARTING_LEDGE, {[]{return true;}}), - Entrance(RR_GANONS_CASTLE_MQ_SPIRIT_TRIAL_CHAIRS_ROOM, {[]{return true;}}), - Entrance(RR_GANONS_CASTLE_MQ_LIGHT_TRIAL_DINOLFOS_ROOM, {[]{return Here(RR_GANONS_CASTLE_MQ_MAIN, []{return logic->CanUse(RG_GOLDEN_GAUNTLETS);});}}), - //RANDOTODO could we just set these events automatically based on the setting? - Entrance(RR_GANONS_TOWER_FLOOR_1, {[]{return (logic->ForestTrialClear || ctx->GetTrial(TK_FOREST_TRIAL)->IsSkipped()) && - (logic->FireTrialClear || ctx->GetTrial(TK_FIRE_TRIAL)->IsSkipped()) && - (logic->WaterTrialClear || ctx->GetTrial(TK_WATER_TRIAL)->IsSkipped()) && - (logic->ShadowTrialClear || ctx->GetTrial(TK_SHADOW_TRIAL)->IsSkipped()) && - (logic->SpiritTrialClear || ctx->GetTrial(TK_SPIRIT_TRIAL)->IsSkipped()) && - (logic->LightTrialClear || ctx->GetTrial(TK_LIGHT_TRIAL)->IsSkipped());}}), - Entrance(RR_GANONS_CASTLE_MQ_DEKU_SCRUBS, {[]{return ctx->GetTrickOption(RT_LENS_GANON_MQ) || logic->CanUse(RG_LENS_OF_TRUTH);}}), - }); - - areaTable[RR_GANONS_CASTLE_MQ_DEKU_SCRUBS] = Region("Ganon's Castle MQ Deku Scrubs", "Ganon's Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->FreeFairies, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT, logic->CanStunDeku()), - LOCATION(RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER, logic->CanStunDeku()), - LOCATION(RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT, logic->CanStunDeku()), - LOCATION(RC_GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT, logic->CanStunDeku()), - LOCATION(RC_GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT, logic->CanStunDeku()), - LOCATION(RC_GANONS_CASTLE_MQ_SCRUBS_FAIRY_1, true), - LOCATION(RC_GANONS_CASTLE_MQ_SCRUBS_FAIRY_2, true), - LOCATION(RC_GANONS_CASTLE_MQ_SCRUBS_FAIRY_3, true), - LOCATION(RC_GANONS_CASTLE_MQ_SCRUBS_FAIRY_4, true), - LOCATION(RC_GANONS_CASTLE_MQ_SCRUBS_FAIRY_5, true), - LOCATION(RC_GANONS_CASTLE_MQ_SCRUBS_FAIRY_6, true), - LOCATION(RC_GANONS_CASTLE_MQ_SCRUBS_FAIRY_7, true), - LOCATION(RC_GANONS_CASTLE_MQ_SCRUBS_FAIRY_8, true), - }, { - //Exits - Entrance(RR_GANONS_CASTLE_MQ_MAIN, {[]{return true;}}), - }); - - areaTable[RR_GANONS_CASTLE_MQ_FOREST_TRIAL_STALFOS_ROOM] = Region("Ganon's Castle MQ Forest Trial Stalfos Room", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GANONS_CASTLE_MQ_FOREST_TRIAL_FREESTANDING_KEY, logic->HookshotOrBoomerang()), - }, { - //Exits - Entrance(RR_GANONS_CASTLE_MQ_MAIN, {[]{return true;}}), - Entrance(RR_GANONS_CASTLE_MQ_FOREST_TRIAL_BEAMOS_ROOM, {[]{return Here(RR_GANONS_CASTLE_MQ_FOREST_TRIAL_STALFOS_ROOM, []{return logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2);});}}), - }); - -//If it is ever possible to warp into the RR_GANONS_CASTLE_MQ_FOREST_TRIAL_FINAL_ROOM, this needs splitting up as the requirements to reach things from the other side are more complex - areaTable[RR_GANONS_CASTLE_MQ_FOREST_TRIAL_BEAMOS_ROOM] = Region("Ganon's Castle MQ Forest Trial Beamos Room", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GANONS_CASTLE_MQ_FOREST_TRIAL_EYE_SWITCH_CHEST, logic->CanHitEyeTargets()), - LOCATION(RC_GANONS_CASTLE_MQ_FOREST_TRIAL_FROZEN_EYE_SWITCH_CHEST, logic->HasFireSource()), - }, { - //Exits - Entrance(RR_GANONS_CASTLE_MQ_FOREST_TRIAL_STALFOS_ROOM, {[]{return true;}}), - Entrance(RR_GANONS_CASTLE_MQ_FOREST_TRIAL_FINAL_ROOM, {[]{return logic->IsAdult && logic->CanUse(RG_SONG_OF_TIME);}}), - - }); - - areaTable[RR_GANONS_CASTLE_MQ_FOREST_TRIAL_FINAL_ROOM] = Region("Ganon's Castle MQ Forest Trial Final Room", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->ForestTrialClear, {[]{return logic->CanUse(RG_LIGHT_ARROWS);}}), - }, { - //Locations - LOCATION(RC_GANONS_CASTLE_MQ_FOREST_TRIAL_POT_1, logic->CanBreakPots()), - LOCATION(RC_GANONS_CASTLE_MQ_FOREST_TRIAL_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_GANONS_CASTLE_MQ_FOREST_TRIAL_BEAMOS_ROOM, {[]{return true;}}), - }); - - areaTable[RR_GANONS_CASTLE_MQ_FIRE_TRIAL_MAIN_ROOM] = Region("Ganon's Castle MQ Fire Trial Main Room", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_GANONS_CASTLE_MQ_MAIN, {[]{return true;}}), - //2 checks, 1 for the rupees, 1 for actually making it, as the rupees are permanent but throwing a pillar is not - Entrance(RR_GANONS_CASTLE_MQ_FIRE_TRIAL_FINAL_ROOM, {[]{return Here(RR_GANONS_CASTLE_MQ_FIRE_TRIAL_MAIN_ROOM, []{return logic->CanUse(RG_GORON_TUNIC) && logic->CanUse(RG_GOLDEN_GAUNTLETS);}) && - logic->CanUse(RG_GORON_TUNIC) && (logic->CanUse(RG_LONGSHOT) || (logic->CanUse(RG_GOLDEN_GAUNTLETS) && (logic->CanUse(RG_HOVER_BOOTS) || (ctx->GetTrickOption(RT_GANON_MQ_FIRE_TRIAL) && logic->IsAdult && logic->CanUse(RG_HOOKSHOT)))));}}), - }); - - areaTable[RR_GANONS_CASTLE_MQ_FIRE_TRIAL_FINAL_ROOM] = Region("Ganon's Castle MQ Fire Trial Final Room", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->FireTrialClear, {[]{return logic->CanUse(RG_LIGHT_ARROWS);}}), - //There's no way back across the lava without glitches - }, { - //Locations - LOCATION(RC_GANONS_CASTLE_MQ_FIRE_TRIAL_POT_1, logic->CanBreakPots()), - LOCATION(RC_GANONS_CASTLE_MQ_FIRE_TRIAL_POT_2, logic->CanBreakPots()), - }, {}); - - areaTable[RR_GANONS_CASTLE_MQ_WATER_TRIAL_GEYSER_ROOM] = Region("Ganon's Castle MQ Water Trial Geyser Room", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->BlueFireAccess, {[]{return logic->CanJumpslash() || logic->HasExplosives();}}), - }, { - //Locations - LOCATION(RC_GANONS_CASTLE_MQ_WATER_TRIAL_CHEST, logic->BlueFire()), - LOCATION(RC_GANONS_CASTLE_MQ_WATER_TRIAL_HEART, logic->BlueFire()), - }, { - //Exits - Entrance(RR_GANONS_CASTLE_MQ_MAIN, {[]{return true;}}), - Entrance(RR_GANONS_CASTLE_MQ_WATER_TRIAL_BLOCK_ROOM, {[]{return logic->SmallKeys(RR_GANONS_CASTLE, 3) && Here(RR_GANONS_CASTLE_MQ_WATER_TRIAL_GEYSER_ROOM, []{return logic->BlueFire();});}}), - }); - - areaTable[RR_GANONS_CASTLE_MQ_WATER_TRIAL_BLOCK_ROOM] = Region("Ganon's Castle MQ Water Trial Block Room", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_GANONS_CASTLE_MQ_WATER_TRIAL_GEYSER_ROOM, {[]{return logic->SmallKeys(RR_GANONS_CASTLE, 3);}}), - //This assumes there's no way for child to have blue fire and not adult. - Entrance(RR_GANONS_CASTLE_MQ_WATER_TRIAL_FINAL_ROOM, {[]{return logic->IsAdult && logic->BlueFire();}}), - }); - - areaTable[RR_GANONS_CASTLE_MQ_WATER_TRIAL_FINAL_ROOM] = Region("Ganon's Castle MQ Water Trial Final Room", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->WaterTrialClear, {[]{return logic->CanUse(RG_LIGHT_ARROWS);}}), - }, { - //Locations - LOCATION(RC_GANONS_CASTLE_MQ_WATER_TRIAL_POT_1, logic->CanBreakPots()), - LOCATION(RC_GANONS_CASTLE_MQ_WATER_TRIAL_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_GANONS_CASTLE_MQ_WATER_TRIAL_BLOCK_ROOM, {[]{return Here(RR_GANONS_CASTLE_MQ_WATER_TRIAL_FINAL_ROOM, []{return logic->BlueFire();});}}), - }); - - areaTable[RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_STARTING_LEDGE] = Region("Ganon's Castle MQ Shadow Trial Starting Ledge", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->ShadowTrialFirstChest, {[]{return logic->CanUse(RG_FAIRY_BOW);}}), - }, {}, { - //Exits - Entrance(RR_GANONS_CASTLE_MQ_MAIN, {[]{return true;}}), - Entrance(RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_CHEST_PLATFORM, {[]{return (logic->ShadowTrialFirstChest && logic->CanUse(RG_HOOKSHOT)) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS));}}), - }); - - areaTable[RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_CHEST_PLATFORM] = Region("Ganon's Castle MQ Shadow Trial Chest Platform", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->ShadowTrialFirstChest, {[]{return logic->CanUse(RG_FAIRY_BOW);}}), - }, { - //Locations - LOCATION(RC_GANONS_CASTLE_MQ_SHADOW_TRIAL_BOMB_FLOWER_CHEST, logic->ShadowTrialFirstChest), - }, { - //Exits - //Hookshot here is possible but very tight, but it's basically never relevant - Entrance(RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_STARTING_LEDGE, {[]{return logic->CanUse(RG_LONGSHOT) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS));}}), - Entrance(RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_MOVING_PLATFORM, {[]{return (ctx->GetTrickOption(RT_LENS_GANON_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)) && (logic->IsAdult || logic->CanUse(RG_HOVER_BOOTS));}}), - }); - - areaTable[RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_MOVING_PLATFORM] = Region("Ganon's Castle MQ Shadow Trial Moving Platform", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { - //Events - //A torch run from RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_STARTING_LEDGE is possible but tight, so would be a trick - EventAccess(&logic->ShadowTrialFirstChest, {[]{return logic->CanDetonateUprightBombFlower();}}), - }, {}, { - //Exits - Entrance(RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_CHEST_PLATFORM, {[]{return logic->IsAdult || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS);}}), - Entrance(RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_BEAMOS_TORCH, {[]{return true;}}), - }); - - - areaTable[RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_BEAMOS_TORCH] = Region("Ganon's Castle MQ Shadow Trial Beamos Torch", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_MOVING_PLATFORM, {[]{return ctx->GetTrickOption(RT_LENS_GANON_MQ) || logic->CanUse(RG_LENS_OF_TRUTH);}}), - //A torch run from RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_STARTING_LEDGE is possible but very tight, so would be a trick - //The bow trick assumes RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_STARTING_LEDGE access, if you can somehow void warp directly here it will need handling properly - //Hovers is possible as child but a bit tight, requires good rolls - Entrance(RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_FAR_SIDE, {[]{return logic->HasFireSource() || logic->CanUse(RG_HOVER_BOOTS) || (logic->IsAdult && ctx->GetTrickOption(RT_GANON_MQ_SHADOW_TRIAL) && logic->CanUse(RG_FAIRY_BOW));}}), - }); - - areaTable[RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_FAR_SIDE] = Region("Ganon's Castle MQ Shadow Trial Far Side", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GANONS_CASTLE_MQ_SHADOW_TRIAL_EYE_SWITCH_CHEST, logic->CanHitEyeTargets()), - }, { - //Exits - Entrance(RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_BEAMOS_TORCH, {[]{return logic->CanUse(RG_FIRE_ARROWS) || logic->CanUse(RG_HOVER_BOOTS);}}), - //Modelling the silver rupees properly will require a way to check temp flags in different regions. - //It may be tempting to use a Here-like command for this but it could cause sphere skipping in playthroughs - //So a system like event access which sets based on TimeAge would be preferable, as the application of these can be tracked and accounted for, unlike Here-like commands - //For Now I am assuming the player has made it all the way from RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_STARTING_LEDGE, which logically means every rupee is available - //with no extra requirements except the lens logic needed to reach the door, which also enables the beamos-platform rupee - Entrance(RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_FINAL_ROOM, {[]{return (ctx->GetTrickOption(RT_LENS_GANON_MQ) || logic->CanUse(RG_LENS_OF_TRUTH));}}), - }); - - areaTable[RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_FINAL_ROOM] = Region("Ganon's Castle MQ Shadow Trial Final Room", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->ShadowTrialClear, {[]{return logic->CanUse(RG_LIGHT_ARROWS);}}), - }, { - //Locations - LOCATION(RC_GANONS_CASTLE_MQ_SHADOW_TRIAL_POT_1, logic->CanBreakPots()), - LOCATION(RC_GANONS_CASTLE_MQ_SHADOW_TRIAL_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_FAR_SIDE, {[]{return (ctx->GetTrickOption(RT_LENS_GANON_MQ) || logic->CanUse(RG_LENS_OF_TRUTH));}}), - }); - - areaTable[RR_GANONS_CASTLE_MQ_SPIRIT_TRIAL_CHAIRS_ROOM] = Region("Ganon's Castle MQ Spirit Trial Chairs Room", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_GANONS_CASTLE_MQ_MAIN, {[]{return true;}}), - Entrance(RR_GANONS_CASTLE_MQ_SPIRIT_TRIAL_BEFORE_SWITCH, {[]{return Here(RR_GANONS_CASTLE_MQ_SPIRIT_TRIAL_CHAIRS_ROOM, []{return (logic->CanHitEyeTargets() || ctx->GetTrickOption(RT_RUSTED_SWITCHES)) && logic->CanUse(RG_MEGATON_HAMMER);});}}), - }); - - areaTable[RR_GANONS_CASTLE_MQ_SPIRIT_TRIAL_BEFORE_SWITCH] = Region("Ganon's Castle MQ Spirit Trial Before Switch", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_FIRST_CHEST, logic->CanPassEnemy(RE_GREEN_BUBBLE)), - }, { - //Exits - Entrance(RR_GANONS_CASTLE_MQ_SPIRIT_TRIAL_CHAIRS_ROOM, {[]{return true;}}), - Entrance(RR_GANONS_CASTLE_MQ_SPIRIT_TRIAL_AFTER_SWITCH, {[]{return Here(RR_GANONS_CASTLE_MQ_SPIRIT_TRIAL_BEFORE_SWITCH, []{return logic->CanUse(RG_BOMBCHU_5);});}}), - }); - - areaTable[RR_GANONS_CASTLE_MQ_SPIRIT_TRIAL_AFTER_SWITCH] = Region("Ganon's Castle MQ Spirit Trial After Switch", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_INVISIBLE_CHEST, ctx->GetTrickOption(RT_LENS_GANON_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)), - //better names for these would be nice. - LOCATION(RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_FRONT_LEFT_CHEST, (logic->CanUse(RG_FIRE_ARROWS) && logic->CanUse(RG_MIRROR_SHIELD)) || (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS))), - LOCATION(RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_LEFT_CHEST, (logic->CanUse(RG_FIRE_ARROWS) && logic->CanUse(RG_MIRROR_SHIELD)) || (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS))), - LOCATION(RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_GOLDEN_GAUNTLETS_CHEST, (logic->CanUse(RG_FIRE_ARROWS) && logic->CanUse(RG_MIRROR_SHIELD)) || (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS))), - LOCATION(RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_RIGHT_CHEST, (logic->CanUse(RG_FIRE_ARROWS) && logic->CanUse(RG_MIRROR_SHIELD)) || (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS))), - }, { - //Exits - Entrance(RR_GANONS_CASTLE_MQ_SPIRIT_TRIAL_BEFORE_SWITCH, {[]{return Here(RR_GANONS_CASTLE_MQ_SPIRIT_TRIAL_AFTER_SWITCH, []{return logic->CanUse(RG_BOMBCHU_5);});}}), - //Sunlight arrows are bugged, should set a perm flag like mirror shield - Entrance(RR_GANONS_CASTLE_MQ_SPIRIT_TRIAL_FINAL_ROOM, {[]{return Here(RR_GANONS_CASTLE_MQ_SPIRIT_TRIAL_AFTER_SWITCH, []{return (logic->CanUse(RG_FIRE_ARROWS) && logic->CanUse(RG_MIRROR_SHIELD));}) || (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS));}}), - }); - - areaTable[RR_GANONS_CASTLE_MQ_SPIRIT_TRIAL_FINAL_ROOM] = Region("Ganon's Castle MQ Spirit Trial Final Room", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->SpiritTrialClear, {[]{return logic->CanUse(RG_LIGHT_ARROWS);}}), - EventAccess(&logic->NutPot, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_POT_1, logic->CanBreakPots()), - LOCATION(RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_GANONS_CASTLE_MQ_SPIRIT_TRIAL_AFTER_SWITCH, {[]{return true;}}), - }); - - areaTable[RR_GANONS_CASTLE_MQ_LIGHT_TRIAL_DINOLFOS_ROOM] = Region("Ganon's Castle MQ Light Trial Dinolfos Room", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_GANONS_CASTLE_MQ_MAIN, {[]{return true;}}), - Entrance(RR_GANONS_CASTLE_MQ_LIGHT_TRIAL_TRIFORCE_ROOM, {[]{return Here(RR_GANONS_CASTLE_MQ_LIGHT_TRIAL_DINOLFOS_ROOM, []{return logic->CanKillEnemy(RE_DINOLFOS) && logic->CanKillEnemy(RE_TORCH_SLUG);});}}), - }); - - areaTable[RR_GANONS_CASTLE_MQ_LIGHT_TRIAL_TRIFORCE_ROOM] = Region("Ganon's Castle MQ Light Trial Triforce Room", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GANONS_CASTLE_MQ_LIGHT_TRIAL_LULLABY_CHEST, logic->CanUse(RG_ZELDAS_LULLABY)), - }, { - //Exits - Entrance(RR_GANONS_CASTLE_MQ_LIGHT_TRIAL_DINOLFOS_ROOM, {[]{return true;}}), - Entrance(RR_GANONS_CASTLE_MQ_LIGHT_TRIAL_BOULDER_ROOM_FRONT, {[]{return logic->SmallKeys(RR_GANONS_CASTLE, 2);}}), - }); - - areaTable[RR_GANONS_CASTLE_MQ_LIGHT_TRIAL_BOULDER_ROOM_FRONT] = Region("Ganon's Castle MQ Light Trial Boulder Room Front", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_GANONS_CASTLE_MQ_LIGHT_TRIAL_TRIFORCE_ROOM, {[]{return logic->SmallKeys(RR_GANONS_CASTLE, 2);}}), - Entrance(RR_GANONS_CASTLE_MQ_LIGHT_TRIAL_BOULDER_ROOM_BACK, {[]{return logic->CanUse(RG_HOOKSHOT) || ctx->GetTrickOption(RT_GANON_MQ_LIGHT_TRIAL);}}), - }); - - areaTable[RR_GANONS_CASTLE_MQ_LIGHT_TRIAL_BOULDER_ROOM_BACK] = Region("Ganon's Castle MQ Light Trial Boulder Room Back", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - //I got the trick going backwards, but only while taking damage. this isn't relevant anyway though - Entrance(RR_GANONS_CASTLE_MQ_LIGHT_TRIAL_BOULDER_ROOM_FRONT, {[]{return logic->CanUse(RG_HOOKSHOT) || ctx->GetTrickOption(RT_GANON_MQ_LIGHT_TRIAL);}}), - Entrance(RR_GANONS_CASTLE_MQ_LIGHT_TRIAL_FINAL_ROOM, {[]{return logic->SmallKeys(RR_GANONS_CASTLE, 3) && (ctx->GetTrickOption(RT_LENS_GANON_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)) && - (logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanJumpslash() || logic->HasExplosives() || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_BOOMERANG));}}), - - }); - - areaTable[RR_GANONS_CASTLE_MQ_LIGHT_TRIAL_FINAL_ROOM] = Region("Ganon's Castle MQ Light Trial Final Room", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->LightTrialClear, {[]{return logic->CanUse(RG_LIGHT_ARROWS);}}), - }, { - //Locations - LOCATION(RC_GANONS_CASTLE_MQ_LIGHT_TRIAL_POT_1, logic->CanBreakPots()), - LOCATION(RC_GANONS_CASTLE_MQ_LIGHT_TRIAL_POT_2, logic->CanBreakPots()), - }, {}); - } - - /*-------------------------- - | TOWER AND ESCAPE | - ---------------------------*/ - areaTable[RR_GANONS_TOWER_FLOOR_1] = Region("Ganon's Tower Floor 1", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_GANONS_CASTLE_LOBBY, {[]{return Here(RR_GANONS_TOWER_FLOOR_1, []{return logic->CanKillEnemy(RE_DINOLFOS, ED_CLOSE, true, 2);});}}), - Entrance(RR_GANONS_TOWER_FLOOR_2, {[]{return Here(RR_GANONS_TOWER_FLOOR_1, []{return logic->CanKillEnemy(RE_DINOLFOS, ED_CLOSE, true, 2);});}}), - }); - - areaTable[RR_GANONS_TOWER_FLOOR_2] = Region("Ganon's Tower Floor 2", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GANONS_TOWER_BOSS_KEY_CHEST, logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2)), - }, { - //Exits - Entrance(RR_GANONS_TOWER_FLOOR_1, {[]{return Here(RR_GANONS_TOWER_FLOOR_2, []{return logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2);});}}), - Entrance(RR_GANONS_TOWER_FLOOR_3, {[]{return Here(RR_GANONS_TOWER_FLOOR_2, []{return logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2);});}}), - }); - - areaTable[RR_GANONS_TOWER_FLOOR_3] = Region("Ganon's Tower Floor 3", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_GANONS_TOWER_FLOOR_2, {[]{return Here(RR_GANONS_TOWER_FLOOR_3, []{return logic->CanKillEnemy(RE_IRON_KNUCKLE, ED_CLOSE, true, 2);});}}), - Entrance(RR_GANONS_TOWER_BEFORE_GANONDORF_LAIR, {[]{return Here(RR_GANONS_TOWER_FLOOR_3, []{return logic->CanKillEnemy(RE_IRON_KNUCKLE, ED_CLOSE, true, 2);});}}), - }); - - areaTable[RR_GANONS_TOWER_BEFORE_GANONDORF_LAIR] = Region("Ganon's Tower Before Ganondorf's Lair", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, { - // Locations - LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_1, logic->CanBreakPots()), - LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_2, logic->CanBreakPots()), - LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_3, logic->CanBreakPots()), - LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_4, logic->CanBreakPots()), - LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_5, logic->CanBreakPots()), - LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_6, logic->CanBreakPots()), - LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_7, logic->CanBreakPots()), - LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_8, logic->CanBreakPots()), - LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_9, logic->CanBreakPots()), - LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_10, logic->CanBreakPots()), - LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_11, logic->CanBreakPots()), - LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_12, logic->CanBreakPots()), - LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_13, logic->CanBreakPots()), - LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_14, logic->CanBreakPots()), - LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_15, logic->CanBreakPots()), - LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_16, logic->CanBreakPots()), - LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_17, logic->CanBreakPots()), - LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_18, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_GANONS_TOWER_FLOOR_3, {[]{return Here(RR_GANONS_TOWER_BEFORE_GANONDORF_LAIR, []{return true;});}}), - Entrance(RR_GANONS_TOWER_GANONDORF_LAIR, {[]{return Here(RR_GANONS_TOWER_BEFORE_GANONDORF_LAIR, []{return logic->HasItem(RG_GANONS_CASTLE_BOSS_KEY);});}}), - }); - - areaTable[RR_GANONS_TOWER_GANONDORF_LAIR] = Region("Ganondorf's Lair", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GANONDORF_HINT, logic->HasBossSoul(RG_GANON_SOUL)), - }, { - //Exits - Entrance(RR_GANONS_CASTLE_ESCAPE, {[]{return logic->CanKillEnemy(RE_GANONDORF);}}), - }); - - areaTable[RR_GANONS_CASTLE_ESCAPE] = Region("Ganon's Castle Escape", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - //10 pots - //RANDOTODO hook potsanity pots up to escape. - }, { - //Exits - //temporary - Entrance(RR_GANONS_CASTLE_GANON_ARENA, {[]{return true;}}), - //real logic once we figure out how to deal with castle escape skip - //Entrance(RR_GANONS_CASTLE_GANON_ARENA, {[]{return logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2, true);}}), - }); - - areaTable[RR_GANONS_CASTLE_GANON_ARENA] = Region("Ganon's Arena", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GANON, logic->CanKillEnemy(RE_GANON)), - LOCATION(RC_GANONS_CASTLE_MQ_LIGHT_TRIAL_RIGHT_HEART, (logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_BIGGORON_SWORD)) && logic->SmallKeys(RR_GANONS_CASTLE, 2)), - LOCATION(RC_GANONS_CASTLE_MQ_LIGHT_TRIAL_LEFT_HEART, (logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_BIGGORON_SWORD)) && logic->SmallKeys(RR_GANONS_CASTLE, 2)), - }, {}); -} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_gerudo_training_ground.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_gerudo_training_ground.cpp deleted file mode 100644 index ba781b882..000000000 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_gerudo_training_ground.cpp +++ /dev/null @@ -1,340 +0,0 @@ -#include "../location_access.hpp" -#include "../../entrance.h" -#include "../../dungeon.h" - -using namespace Rando; - -void RegionTable_Init_GerudoTrainingGrounds() { - /*-------------------------- - | VANILLA/MQ DECIDER | - ---------------------------*/ - areaTable[RR_GERUDO_TRAINING_GROUND_ENTRYWAY] = Region("Gerudo Training Ground Entryway", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_GERUDO_TRAINING_GROUND_LOBBY, {[]{return ctx->GetDungeon(GERUDO_TRAINING_GROUND)->IsVanilla();}}), - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_LOBBY, {[]{return ctx->GetDungeon(GERUDO_TRAINING_GROUND)->IsMQ();}}), - Entrance(RR_GERUDO_FORTRESS, {[]{return true;}}), - }); - - /*-------------------------- - | VANILLA DUNGEON | - ---------------------------*/ - if (ctx->GetDungeon(GERUDO_TRAINING_GROUND)->IsVanilla()) { - areaTable[RR_GERUDO_TRAINING_GROUND_LOBBY] = Region("Gerudo Training Ground Lobby", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GERUDO_TRAINING_GROUND_LOBBY_LEFT_CHEST, logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT)), - LOCATION(RC_GERUDO_TRAINING_GROUND_LOBBY_RIGHT_CHEST, logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT)), - LOCATION(RC_GERUDO_TRAINING_GROUND_STALFOS_CHEST, logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD)), - LOCATION(RC_GERUDO_TRAINING_GROUND_BEAMOS_CHEST, logic->HasExplosives() && (logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD))), - LOCATION(RC_GERUDO_TRAINING_GROUND_ENTRANCE_STORMS_FAIRY, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_GERUDO_TRAINING_GROUND_BEAMOS_SOUTH_HEART, true), - LOCATION(RC_GERUDO_TRAINING_GROUND_BEAMOS_EAST_HEART, true), - }, { - //Exits - Entrance(RR_GERUDO_TRAINING_GROUND_ENTRYWAY, {[]{return true;}}), - Entrance(RR_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_ROOM, {[]{return (logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD)) && (logic->CanUse(RG_HOOKSHOT) || ctx->GetTrickOption(RT_GTG_WITHOUT_HOOKSHOT));}}), - Entrance(RR_GERUDO_TRAINING_GROUND_LAVA_ROOM, {[]{return Here(RR_GERUDO_TRAINING_GROUND_LOBBY, []{return (logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD)) && logic->HasExplosives();});}}), - Entrance(RR_GERUDO_TRAINING_GROUND_CENTRAL_MAZE, {[]{return true;}}), - }); - - areaTable[RR_GERUDO_TRAINING_GROUND_CENTRAL_MAZE] = Region("Gerudo Training Ground Central Maze", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GERUDO_TRAINING_GROUND_HIDDEN_CEILING_CHEST, logic->SmallKeys(RR_GERUDO_TRAINING_GROUND, 3) && (ctx->GetTrickOption(RT_LENS_GTG) || logic->CanUse(RG_LENS_OF_TRUTH))), - LOCATION(RC_GERUDO_TRAINING_GROUND_MAZE_PATH_FIRST_CHEST, logic->SmallKeys(RR_GERUDO_TRAINING_GROUND, 4)), - LOCATION(RC_GERUDO_TRAINING_GROUND_MAZE_PATH_SECOND_CHEST, logic->SmallKeys(RR_GERUDO_TRAINING_GROUND, 6)), - LOCATION(RC_GERUDO_TRAINING_GROUND_MAZE_PATH_THIRD_CHEST, logic->SmallKeys(RR_GERUDO_TRAINING_GROUND, 7)), - LOCATION(RC_GERUDO_TRAINING_GROUND_MAZE_PATH_FINAL_CHEST, logic->SmallKeys(RR_GERUDO_TRAINING_GROUND, 9)), - }, { - //Exits - Entrance(RR_GERUDO_TRAINING_GROUND_CENTRAL_MAZE_RIGHT, {[]{return logic->SmallKeys(RR_GERUDO_TRAINING_GROUND, 9);}}), - }); - - areaTable[RR_GERUDO_TRAINING_GROUND_CENTRAL_MAZE_RIGHT] = Region("Gerudo Training Ground Central Maze Right", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GERUDO_TRAINING_GROUND_MAZE_RIGHT_CENTRAL_CHEST, true), - LOCATION(RC_GERUDO_TRAINING_GROUND_MAZE_RIGHT_SIDE_CHEST, true), - LOCATION(RC_GERUDO_TRAINING_GROUND_FREESTANDING_KEY, true), - }, { - //Exits - Entrance(RR_GERUDO_TRAINING_GROUND_HAMMER_ROOM, {[]{return logic->CanUse(RG_HOOKSHOT);}}), - Entrance(RR_GERUDO_TRAINING_GROUND_LAVA_ROOM, {[]{return true;}}), - }); - - areaTable[RR_GERUDO_TRAINING_GROUND_LAVA_ROOM] = Region("Gerudo Training Ground Lava Room", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GERUDO_TRAINING_GROUND_UNDERWATER_SILVER_RUPEE_CHEST, logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_SONG_OF_TIME) && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 24), - }, { - //Exits - Entrance(RR_GERUDO_TRAINING_GROUND_CENTRAL_MAZE_RIGHT, {[]{return logic->CanUse(RG_SONG_OF_TIME) || logic->IsChild;}}), - Entrance(RR_GERUDO_TRAINING_GROUND_HAMMER_ROOM, {[]{return logic->CanUse(RG_LONGSHOT) || (logic->CanUse(RG_HOVER_BOOTS) && logic->CanUse(RG_HOOKSHOT));}}), - }); - - areaTable[RR_GERUDO_TRAINING_GROUND_HAMMER_ROOM] = Region("Gerudo Training Ground Hammer Room", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GERUDO_TRAINING_GROUND_HAMMER_ROOM_CLEAR_CHEST, logic->CanAttack()), - LOCATION(RC_GERUDO_TRAINING_GROUND_HAMMER_ROOM_SWITCH_CHEST, logic->CanUse(RG_MEGATON_HAMMER) || (logic->TakeDamage() && ctx->GetTrickOption(RT_FLAMING_CHESTS))), - }, { - //Exits - Entrance(RR_GERUDO_TRAINING_GROUND_EYE_STATUE_LOWER, {[]{return logic->CanUse(RG_MEGATON_HAMMER) && logic->CanUse(RG_FAIRY_BOW);}}), - Entrance(RR_GERUDO_TRAINING_GROUND_LAVA_ROOM, {[]{return true;}}), - }); - - areaTable[RR_GERUDO_TRAINING_GROUND_EYE_STATUE_LOWER] = Region("Gerudo Training Ground Eye Statue Lower", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GERUDO_TRAINING_GROUND_EYE_STATUE_CHEST, logic->CanUse(RG_FAIRY_BOW)), - }, { - //Exits - Entrance(RR_GERUDO_TRAINING_GROUND_HAMMER_ROOM, {[]{return true;}}), - }); - - areaTable[RR_GERUDO_TRAINING_GROUND_EYE_STATUE_UPPER] = Region("Gerudo Training Ground Eye Statue Upper", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GERUDO_TRAINING_GROUND_NEAR_SCARECROW_CHEST, logic->CanUse(RG_FAIRY_BOW)), - }, { - //Exits - Entrance(RR_GERUDO_TRAINING_GROUND_EYE_STATUE_LOWER, {[]{return true;}}), - }); - - areaTable[RR_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_ROOM] = Region("Gerudo Training Ground Heavy Block Room", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GERUDO_TRAINING_GROUND_BEFORE_HEAVY_BLOCK_CHEST, logic->CanJumpslashExceptHammer()), - }, { - //Exits - Entrance(RR_GERUDO_TRAINING_GROUND_EYE_STATUE_UPPER, {[]{return (ctx->GetTrickOption(RT_LENS_GTG) || logic->CanUse(RG_LENS_OF_TRUTH)) && (logic->CanUse(RG_HOOKSHOT) || (ctx->GetTrickOption(RT_GTG_FAKE_WALL) && logic->CanUse(RG_HOVER_BOOTS)));}}), - Entrance(RR_GERUDO_TRAINING_GROUND_LIKE_LIKE_ROOM, {[]{return (ctx->GetTrickOption(RT_LENS_GTG) || logic->CanUse(RG_LENS_OF_TRUTH)) && (logic->CanUse(RG_HOOKSHOT) || (ctx->GetTrickOption(RT_GTG_FAKE_WALL) && logic->CanUse(RG_HOVER_BOOTS))) && logic->CanUse(RG_SILVER_GAUNTLETS);}}), - }); - - areaTable[RR_GERUDO_TRAINING_GROUND_LIKE_LIKE_ROOM] = Region("Gerudo Training Ground Like Like Room", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_FIRST_CHEST, logic->CanJumpslashExceptHammer()), - LOCATION(RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_SECOND_CHEST, logic->CanJumpslashExceptHammer()), - LOCATION(RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_THIRD_CHEST, logic->CanJumpslashExceptHammer()), - LOCATION(RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_FOURTH_CHEST, logic->CanJumpslashExceptHammer()), - }, {}); - } - - /*--------------------------- - | MASTER QUEST DUNGEON | - ---------------------------*/ - if (ctx->GetDungeon(GERUDO_TRAINING_GROUND)->IsMQ()) { - areaTable[RR_GERUDO_TRAINING_GROUND_MQ_LOBBY] = Region("Gerudo Training Ground MQ Lobby", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_LEFT_CHEST, true), - LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_RIGHT_CHEST, true), - LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_FIRST_CHEST, true), - LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_SECOND_CHEST, true), - LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_LEFT_POT_1, logic->CanBreakPots()), - LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_LEFT_POT_2, logic->CanBreakPots()), - LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_RIGHT_POT_1, logic->CanBreakPots()), - LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_RIGHT_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_GERUDO_TRAINING_GROUND_ENTRYWAY, {[]{return true;}}), - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_MAZE_HIDDEN_ROOM, {[]{return ctx->GetTrickOption(RT_LENS_GTG_MQ) || logic->CanUse(RG_LENS_OF_TRUTH);}}), - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_MAZE_FIRST_LOCK, {[]{return logic->SmallKeys(RR_GERUDO_TRAINING_GROUND, 1);}}), - //It's possible to use the torch in RR_GERUDO_TRAINING_GROUND_MQ_MAZE_HIDDEN_ROOM with flame storage to light these - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_SAND_ROOM, {[]{return Here(RR_GERUDO_TRAINING_GROUND_MQ_LOBBY, []{return logic->HasFireSource();});}}), - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_DINOLFOS_ROOM, {[]{return Here(RR_GERUDO_TRAINING_GROUND_MQ_LOBBY, []{return (logic->IsAdult && logic->CanUse(RG_FAIRY_BOW)) || (logic->IsChild && logic->CanUse(RG_FAIRY_SLINGSHOT));});}}), - }); - - areaTable[RR_GERUDO_TRAINING_GROUND_MQ_MAZE_HIDDEN_ROOM] = Region("Gerudo Training Ground MQ Maze Hidden Room", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_HIDDEN_CEILING_CHEST, true), - }, { - //Exits - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_LOBBY, {[]{return true;}}), - }); - - areaTable[RR_GERUDO_TRAINING_GROUND_MQ_MAZE_FIRST_LOCK] = Region("Gerudo Training Ground MQ Maze First Lock", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_THIRD_CHEST, true), - }, { - //Exits - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_LOBBY, {[]{return logic->SmallKeys(RR_GERUDO_TRAINING_GROUND, 1);}}), - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_MAZE_CENTER, {[]{return logic->SmallKeys(RR_GERUDO_TRAINING_GROUND, 3);}}), - }); - - areaTable[RR_GERUDO_TRAINING_GROUND_MQ_MAZE_CENTER] = Region("Gerudo Training Ground MQ Center", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->MQGTGMazeSwitch, {[]{return logic->CanUse(RG_MEGATON_HAMMER);}}), - }, {}, { - //Exits - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_MAZE_FIRST_LOCK, {[]{return logic->SmallKeys(RR_GERUDO_TRAINING_GROUND, 3);}}), - }); - - areaTable[RR_GERUDO_TRAINING_GROUND_MQ_SAND_ROOM] = Region("Gerudo Training Ground MQ Sand Room", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_FIRST_IRON_KNUCKLE_CHEST, logic->CanKillEnemy(RE_IRON_KNUCKLE)), - }, { - //Exits - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_LOBBY, {[]{return true;}}), - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_LEFT_SIDE, {[]{return Here(RR_GERUDO_TRAINING_GROUND_MQ_SAND_ROOM, []{return logic->CanKillEnemy(RE_IRON_KNUCKLE);});}}), - }); - - areaTable[RR_GERUDO_TRAINING_GROUND_MQ_LEFT_SIDE] = Region("Gerudo Training Ground MQ Left Side", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_SAND_ROOM, {[]{return true;}}), - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_STALFOS_ROOM, {[]{return Here(RR_GERUDO_TRAINING_GROUND_MQ_LEFT_SIDE, []{return logic->CanUse(RG_LONGSHOT) || - ctx->GetTrickOption(RT_GTG_MQ_WIHTOUT_HOOKSHOT) || - (ctx->GetTrickOption(RT_GTG_MQ_WITH_HOOKSHOT) && logic->IsAdult && logic->CanJumpslash() && logic->CanUse(RG_HOOKSHOT));});}}), - }); - - areaTable[RR_GERUDO_TRAINING_GROUND_MQ_STALFOS_ROOM] = Region("Gerudo Training Ground MQ Stalfos Room", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->BlueFireAccess, {[]{return true;}}), - }, { - //Locations - //implies logic->CanKillEnemy(RE_BIG_SKULLTULA) - LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_BEFORE_HEAVY_BLOCK_CHEST, logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2, true)), - }, { - //Exits - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_BEHIND_BLOCK, {[]{return Here(RR_GERUDO_TRAINING_GROUND_MQ_STALFOS_ROOM, []{return logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2, true);}) && logic->CanUse(RG_SILVER_GAUNTLETS);}}), - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_STATUE_ROOM_LEDGE, {[]{return logic->IsAdult && Here(RR_GERUDO_TRAINING_GROUND_MQ_STALFOS_ROOM, []{return logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2, true);}) && - (ctx->GetTrickOption(RT_LENS_GTG_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)) && logic->BlueFire() && - (logic->CanUse(RG_SONG_OF_TIME) || (ctx->GetTrickOption(RT_GTG_FAKE_WALL) && logic->CanUse(RG_HOVER_BOOTS)));}}), - }); - - areaTable[RR_GERUDO_TRAINING_GROUND_MQ_BEHIND_BLOCK] = Region("Gerudo Training Ground MQ Behind Block", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - //implies logic->CanKillEnemy(RE_SPIKE) - LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_HEAVY_BLOCK_CHEST, logic->CanKillEnemy(RE_FREEZARD)), - }, {}); - - areaTable[RR_GERUDO_TRAINING_GROUND_MQ_STATUE_ROOM_LEDGE] = Region("Gerudo Training Ground MQ Statue Room Ledge", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_STALFOS_ROOM, {[]{return true;}}), - //implies dropping down to hit the switch. Using swords, especially master, is a bit awkward, may be trick worthy, but is only relevant with other tricks - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_MAGENTA_FIRE_ROOM, {[]{return Here(RR_GERUDO_TRAINING_GROUND_MQ_STATUE_ROOM_LEDGE, []{return logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_STICKS) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_BOOMERANG);});}}), - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_STATUE_ROOM, {[]{return true;}}), - }); - - areaTable[RR_GERUDO_TRAINING_GROUND_MQ_MAGENTA_FIRE_ROOM] = Region("Gerudo Training Ground MQ Magenta Fire Room", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_ICE_ARROWS_CHEST, logic->MQGTGMazeSwitch),}, { - //Exits - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_STATUE_ROOM_LEDGE, {[]{return true;}}), - }); - - areaTable[RR_GERUDO_TRAINING_GROUND_MQ_STATUE_ROOM] = Region("Gerudo Training Ground MQ Statue ROom", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_EYE_STATUE_CHEST, logic->CanUse(RG_FAIRY_BOW)), - }, { - //Exits - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_STATUE_ROOM_LEDGE, {[]{return logic->CanUse(RG_LONGSHOT);}}), - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_TORCH_SLUG_ROOM, {[]{return true;}}), - }); - - areaTable[RR_GERUDO_TRAINING_GROUND_MQ_TORCH_SLUG_ROOM] = Region("Gerudo Training Ground MQ Torch Slug Room", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - //implies logic->CanKillEnemy(RE_TORCH_SLUG) - LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_SECOND_IRON_KNUCKLE_CHEST, logic->CanKillEnemy(RE_IRON_KNUCKLE)), - LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_FLAME_CIRCLE_CHEST, logic->CanHitSwitch(ED_BOMB_THROW)), - }, { - //Exits - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_STATUE_ROOM, {[]{return Here(RR_GERUDO_TRAINING_GROUND_MQ_TORCH_SLUG_ROOM, []{return logic->CanKillEnemy(RE_IRON_KNUCKLE);});}}), - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_SWITCH_LEDGE, {[]{return Here(RR_GERUDO_TRAINING_GROUND_MQ_TORCH_SLUG_ROOM, []{return logic->CanKillEnemy(RE_IRON_KNUCKLE);});}}), - }); - - areaTable[RR_GERUDO_TRAINING_GROUND_MQ_SWITCH_LEDGE] = Region("Gerudo Training Ground MQ Switch Ledge", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->MQGTGRightSideSwitch, {[]{return logic->CanUse(RG_MEGATON_HAMMER);}}), - EventAccess(&logic->GTGPlatformSilverRupees, {[]{return logic->CanUse(RG_FIRE_ARROWS) && logic->CanUse(RG_HOVER_BOOTS);}}), - }, { - //Locations - LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_DINOLFOS_CHEST, logic->IsAdult && (logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_BIGGORON_SWORD))), - }, { - //Exits - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_LEDGE_SIDE_PLATFORMS, {[]{return logic->CanUse(RG_FIRE_ARROWS);}}), - //the fire bubble here is a jerk if you are aiming for the nearest hook platform, you have to aim to the right hand side with hook to dodge it - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_PLATFORMS_UNLIT_TORCH, {[]{return logic->CanUse(RG_LONGSHOT) || (logic->GTGPlatformSilverRupees && logic->CanUse(RG_HOOKSHOT)) || - ((logic->CanUse(RG_FIRE_ARROWS) && logic->GTGPlatformSilverRupees) && logic->CanUse(RG_HOVER_BOOTS));}}), - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_MAZE_RIGHT, {[]{return logic->MQGTGRightSideSwitch && logic->CanUse(RG_LONGSHOT);}}), - }); - -//this region exists to place silver rupee items on later, normally it's all on fire and cannot be stood on without access from another area -//This covers the 2 platforms that can be jumped to directly from RR_GERUDO_TRAINING_GROUND_MQ_SWITCH_LEDGE -//the unshuffled rupee collection is handled by the event GTGPlatformSilverRupees - areaTable[RR_GERUDO_TRAINING_GROUND_MQ_LEDGE_SIDE_PLATFORMS] = Region("Gerudo Training Ground MQ Ledge Side Platforms", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - //This is merely to extend this region's logic if you have hovers - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_FURTHEST_PLATFORM, {[]{return logic->CanUse(RG_HOVER_BOOTS);}}), - }); - -//this region exists to place silver rupee items on later, normally it's all on fire and cannot be stood on without access from another area -//This covers the platform that needs hover boots or the spawned targets to reach from any starting point other than RR_GERUDO_TRAINING_GROUND_MQ_MAZE_RIGHT -//the unshuffled rupee collection is handled by the event GTGPlatformSilverRupees - areaTable[RR_GERUDO_TRAINING_GROUND_MQ_FURTHEST_PLATFORM] = Region("Gerudo Training Ground MQ Furthest Platform", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - //This is merely to extend this region's logic if you have hovers - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_LEDGE_SIDE_PLATFORMS, {[]{return logic->CanUse(RG_HOVER_BOOTS);}}), - }); - - areaTable[RR_GERUDO_TRAINING_GROUND_MQ_PLATFORMS_UNLIT_TORCH] = Region("Gerudo Training Ground MQ Platforms Unlit Torch", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->GTGPlatformSilverRupees, {[]{return logic->HasFireSource() && logic->CanUse(RG_HOVER_BOOTS);}}), - }, {}, { - //Exits - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_UNDERWATER, {[]{return logic->GTGPlatformSilverRupees;}}), - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_LEDGE_SIDE_PLATFORMS, {[]{return logic->HasFireSource() && logic->CanUse(RG_HOVER_BOOTS);}}), - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_TORCH_SIDE_PLATFORMS, {[]{return logic->HasFireSource() || logic->CanUse(RG_LONGSHOT);}}), - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_MAZE_RIGHT, {[]{return logic->MQGTGRightSideSwitch && (logic->CanUse(RG_LONGSHOT) || (logic->CanUse(RG_HOOKSHOT) && logic->HasFireSource()));}}), - }); - - areaTable[RR_GERUDO_TRAINING_GROUND_MQ_TORCH_SIDE_PLATFORMS] = Region("Gerudo Training Ground Torch Side Platforms", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, { - //Events - //this torch shot is possible as child but tight and obtuse enough to be a trick - EventAccess(&logic->GTGPlatformSilverRupees, {[]{return ((logic->CanUse(RG_FAIRY_BOW) && logic->IsAdult) || logic->CanUse(RG_FIRE_ARROWS)) && logic->CanUse(RG_HOVER_BOOTS);}}), - }, {}, { - //Exits - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_LEDGE_SIDE_PLATFORMS, {[]{return ((logic->CanUse(RG_FAIRY_BOW) && logic->IsAdult) || logic->CanUse(RG_FIRE_ARROWS)) && logic->CanUse(RG_HOVER_BOOTS);}}), - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_PLATFORMS_UNLIT_TORCH, {[]{return (logic->CanUse(RG_FAIRY_BOW) && logic->IsAdult) || logic->CanUse(RG_FIRE_ARROWS) || - logic->CanUse(RG_LONGSHOT);}}), - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_MAZE_RIGHT, {[]{return logic->MQGTGRightSideSwitch && ((logic->CanUse(RG_FAIRY_BOW) && logic->IsAdult) || logic->CanUse(RG_FIRE_ARROWS) || - logic->CanUse(RG_LONGSHOT));}}), - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_DINOLFOS_ROOM, {[]{return true;}}), - }); - - areaTable[RR_GERUDO_TRAINING_GROUND_MQ_UNDERWATER] = Region("Gerudo Training Ground MQ Underwater", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - //it is possible to snipe the stingers with bow or sling before dropping in, or just get really lucky, and avoid needing to take damage, but that might be trick worthy - LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_UNDERWATER_SILVER_RUPEE_CHEST, logic->HasFireSource() && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 24 && logic->TakeDamage()), - }, { - //Exits - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_PLATFORMS_UNLIT_TORCH, {[]{return true;}}), - }); - - - areaTable[RR_GERUDO_TRAINING_GROUND_MQ_MAZE_RIGHT] = Region("Gerudo Training Ground MQ Maze Right", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->GTGPlatformSilverRupees, {[]{return logic->CanUse(RG_FIRE_ARROWS) && logic->CanUse(RG_HOVER_BOOTS);}}), - }, { - //Locations - LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_MAZE_RIGHT_CENTRAL_CHEST, true), - LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_MAZE_RIGHT_SIDE_CHEST, true), - }, { - //Exits - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_LOBBY, {[]{return true;}}), - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_LEDGE_SIDE_PLATFORMS, {[]{return logic->CanUse(RG_FIRE_ARROWS) || logic->CanUse(RG_LONGSHOT);}}), - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_PLATFORMS_UNLIT_TORCH, {[]{return logic->CanUse(RG_FIRE_ARROWS) || logic->CanUse(RG_LONGSHOT) || (logic->GTGPlatformSilverRupees && logic->CanUse(RG_HOVER_BOOTS));}}), - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_LEDGE_SIDE_PLATFORMS, {[]{return logic->CanUse(RG_FIRE_ARROWS);}}), - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_FURTHEST_PLATFORM, {[]{return logic->CanUse(RG_FIRE_ARROWS);}}), - }); - - areaTable[RR_GERUDO_TRAINING_GROUND_MQ_DINOLFOS_ROOM] = Region("Gerudo Training Ground MQ Dinolfos Room", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, { - //Events - //EventAccess(&WallFairy, {[]{return WallFairy || (logic->IsAdult && logic->CanUse(RG_FAIRY_BOW));}}), - }, { - //Locations - //implies logic->CanKillEnemy(RE_LIZALFOS and logic->CanKillEnemy(RE_DODONGO) - //is logic->CanKillEnemy(RE_DINOLFOS, ED_CLOSE, true, 2, true) && logic->CanKillEnemy(RE_ARMOS, ED_CLOSE, true, 1, true) broken down to exclude sticks, as it take too many to clear the room - //Proper enemy kill room ammo logic is needed to handle this room - //some combinations may be impossible without taking damage, keep an eye out for issues here - LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_DINOLFOS_CHEST, logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MEGATON_HAMMER) || logic->CanUse(RG_FAIRY_BOW) || - ((logic->CanUse(RG_NUTS) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_BOOMERANG)) && (logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_FAIRY_SLINGSHOT)))), - }, { - //Exits - Entrance(RR_GERUDO_TRAINING_GROUND_MQ_TORCH_SIDE_PLATFORMS, {[]{return Here(RR_GERUDO_TRAINING_GROUND_MQ_DINOLFOS_ROOM, []{return logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MEGATON_HAMMER) || logic->CanUse(RG_FAIRY_BOW) || - ((logic->CanUse(RG_NUTS) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_BOOMERANG)) && (logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_FAIRY_SLINGSHOT)));});}}), - }); - - } -} 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 deleted file mode 100644 index f662dd082..000000000 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_gerudo_valley.cpp +++ /dev/null @@ -1,281 +0,0 @@ -#include "../location_access.hpp" -#include "../../entrance.h" - -using namespace Rando; - -void RegionTable_Init_GerudoValley() { - areaTable[RR_GERUDO_VALLEY] = Region("Gerudo Valley", "Gerudo Valley", {RA_GERUDO_VALLEY}, DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->BugRock, {[]{return logic->BugRock || logic->IsChild;}}), - }, { - //Locations - LOCATION(RC_GV_GS_SMALL_BRIDGE, logic->IsChild && logic->HookshotOrBoomerang() && logic->CanGetNightTimeGS()), - }, { - //Exits - Entrance(RR_HYRULE_FIELD, {[]{return true;}}), - Entrance(RR_GV_UPPER_STREAM, {[]{return true;}}), - Entrance(RR_GV_CRATE_LEDGE, {[]{return logic->IsChild || logic->CanUse(RG_LONGSHOT);}}), - Entrance(RR_GV_GROTTO_LEDGE, {[]{return true;}}), - Entrance(RR_GV_FORTRESS_SIDE, {[]{return (logic->IsAdult && (logic->CanUse(RG_EPONA) || logic->CanUse(RG_LONGSHOT) || ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FREE) || logic->CarpenterRescue)) || (logic->IsChild && logic->CanUse(RG_HOOKSHOT));}}), - }); - - areaTable[RR_GV_UPPER_STREAM] = Region("GV Upper Stream", "Gerudo Valley", {RA_GERUDO_VALLEY}, DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->GossipStoneFairy, {[]{return logic->CallGossipFairy();}}), - EventAccess(&logic->BeanPlantFairy, {[]{return logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS);}}), - }, { - //Locations - LOCATION(RC_GV_WATERFALL_FREESTANDING_POH, logic->IsChild || logic->HasItem(RG_BRONZE_SCALE)),//can use cucco as child - LOCATION(RC_GV_GS_BEAN_PATCH, logic->CanSpawnSoilSkull() && logic->CanAttack()), - LOCATION(RC_GV_COW, logic->IsChild && logic->CanUse(RG_EPONAS_SONG)), - LOCATION(RC_GV_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_GV_BEAN_SPROUT_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_GV_BEAN_SPROUT_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_GV_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), - LOCATION(RC_GV_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_GV_GOSSIP_STONE, true), - }, { - //Exits - Entrance(RR_GV_LOWER_STREAM, {[]{return true;}}), - }); - - areaTable[RR_GV_LOWER_STREAM] = Region("GV Lower Stream", "Gerudo Valley", {RA_GERUDO_VALLEY}, DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_LAKE_HYLIA, {[]{return logic->IsChild || logic->HasItem(RG_BRONZE_SCALE);}}),//can use cucco as child - }); - - areaTable[RR_GV_GROTTO_LEDGE] = Region("GV Grotto Ledge", "Gerudo Valley", {RA_GERUDO_VALLEY}, DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_GV_LOWER_STREAM, {[]{return true;}}), - Entrance(RR_GV_OCTOROK_GROTTO, {[]{return logic->CanUse(RG_SILVER_GAUNTLETS);}}), - Entrance(RR_GV_CRATE_LEDGE, {[]{return logic->CanUse(RG_LONGSHOT);}}), - }); - - areaTable[RR_GV_CRATE_LEDGE] = Region("GV Crate Ledge", "Gerudo Valley", {RA_GERUDO_VALLEY}, DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GV_CRATE_FREESTANDING_POH, true), - }, { - //Exits - Entrance(RR_GV_UPPER_STREAM, {[]{return ctx->GetTrickOption(RT_DAMAGE_BOOST_SIMPLE) && logic->HasExplosives();}}), - Entrance(RR_GV_LOWER_STREAM, {[]{return true;}}), - }); - - areaTable[RR_GV_FORTRESS_SIDE] = Region("GV Fortress Side", "Gerudo Valley", {RA_GERUDO_VALLEY}, DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GV_CHEST, logic->IsAdult && logic->CanUse(RG_MEGATON_HAMMER)), - LOCATION(RC_GV_TRADE_SAW, logic->IsAdult && logic->CanUse(RG_POACHERS_SAW)), - LOCATION(RC_GV_GS_BEHIND_TENT, logic->IsAdult && logic->HookshotOrBoomerang() && logic->CanGetNightTimeGS()), - LOCATION(RC_GV_GS_PILLAR, logic->IsAdult && logic->HookshotOrBoomerang() && logic->CanGetNightTimeGS()), - }, { - //Exits - Entrance(RR_GERUDO_FORTRESS, {[]{return true;}}), - Entrance(RR_GV_UPPER_STREAM, {[]{return true;}}), - Entrance(RR_GERUDO_VALLEY, {[]{return logic->IsChild || logic->CanUse(RG_EPONA) || logic->CanUse(RG_LONGSHOT) || ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FREE) || logic->CarpenterRescue;}}), - Entrance(RR_GV_CARPENTER_TENT, {[]{return logic->IsAdult;}}), - Entrance(RR_GV_STORMS_GROTTO, {[]{return logic->IsAdult && logic->CanOpenStormsGrotto();}}), - Entrance(RR_GV_CRATE_LEDGE, {[]{return ctx->GetTrickOption(RT_DAMAGE_BOOST_SIMPLE) && logic->HasExplosives();}}), - }); - - areaTable[RR_GV_CARPENTER_TENT] = Region("GV Carpenter Tent", "GV Carpenter Tent", {}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_GV_FORTRESS_SIDE, {[]{return true;}}), - }); - - areaTable[RR_GV_OCTOROK_GROTTO] = Region("GV Octorok Grotto", "GV Octorok Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GV_OCTOROK_GROTTO_FRONT_LEFT_BLUE_RUPEE, logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG)), - LOCATION(RC_GV_OCTOROK_GROTTO_FRONT_RIGHT_BLUE_RUPEE, logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG)), - LOCATION(RC_GV_OCTOROK_GROTTO_BACK_BLUE_RUPEE, logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG)), - LOCATION(RC_GV_OCTOROK_GROTTO_FRONT_LEFT_GREEN_RUPEE, logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG)), - LOCATION(RC_GV_OCTOROK_GROTTO_FRONT_RIGHT_GREEN_RUPEE, logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG)), - LOCATION(RC_GV_OCTOROK_GROTTO_BACK_LEFT_GREEN_RUPEE, logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG)), - LOCATION(RC_GV_OCTOROK_GROTTO_BACK_RIGHT_GREEN_RUPEE, logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG)), - LOCATION(RC_GV_OCTOROK_GROTTO_RED_RUPEE, logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG)), - }, { - //Exits - Entrance(RR_GV_GROTTO_LEDGE, {[]{return true;}}), - }); - - areaTable[RR_GV_STORMS_GROTTO] = Region("GV Storms Grotto", "GV Storms Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GV_DEKU_SCRUB_GROTTO_REAR, logic->CanStunDeku()), - LOCATION(RC_GV_DEKU_SCRUB_GROTTO_FRONT, logic->CanStunDeku()), - LOCATION(RC_GV_DEKU_SCRUB_GROTTO_BEEHIVE, logic->CanBreakUpperBeehives()), - }, { - //Exits - Entrance(RR_GV_FORTRESS_SIDE, {[]{return true;}}), - }); - - areaTable[RR_GERUDO_FORTRESS] = Region("Gerudo Fortress", "Gerudo Fortress", {RA_GERUDO_FORTRESS}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->CarpenterRescue, {[]{return logic->CanFinishGerudoFortress();}}), - EventAccess(&logic->GF_GateOpen, {[]{return logic->IsAdult && logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD);}}), - EventAccess(&logic->GtG_GateOpen, {[]{return logic->GtG_GateOpen || (logic->IsAdult && logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) && logic->HasItem(RG_CHILD_WALLET));}}), - }, { - //Locations - LOCATION(RC_GF_CHEST, logic->CanUse(RG_HOVER_BOOTS) || (logic->IsAdult && logic->CanUse(RG_SCARECROW)) || logic->CanUse(RG_LONGSHOT)), - LOCATION(RC_GF_HBA_1000_POINTS, logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) && logic->CanUse(RG_EPONA) && logic->CanUse(RG_FAIRY_BOW) && logic->AtDay), - LOCATION(RC_GF_HBA_1500_POINTS, logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) && logic->CanUse(RG_EPONA) && logic->CanUse(RG_FAIRY_BOW) && logic->AtDay), - LOCATION(RC_GF_NORTH_F1_CARPENTER, logic->CanKillEnemy(RE_GERUDO_WARRIOR)), - LOCATION(RC_GF_NORTH_F2_CARPENTER, logic->CanKillEnemy(RE_GERUDO_WARRIOR) && (logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS) || ctx->GetTrickOption(RT_GF_KITCHEN))), - LOCATION(RC_GF_SOUTH_F1_CARPENTER, logic->CanKillEnemy(RE_GERUDO_WARRIOR)), - LOCATION(RC_GF_SOUTH_F2_CARPENTER, logic->CanKillEnemy(RE_GERUDO_WARRIOR)), - LOCATION(RC_GF_GERUDO_MEMBERSHIP_CARD, logic->CanFinishGerudoFortress()), - LOCATION(RC_GF_GS_ARCHERY_RANGE, logic->IsAdult && logic->HookshotOrBoomerang() && logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) && logic->CanGetNightTimeGS()), - LOCATION(RC_GF_GS_TOP_FLOOR, logic->IsAdult && (logic->CanJumpslashExceptHammer() || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_BOOMERANG) || logic->HasExplosives() || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_DINS_FIRE)) && (logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS) || ctx->GetTrickOption(RT_GF_KITCHEN) || ctx->GetTrickOption(RT_GF_JUMP)) && logic->CanGetNightTimeGS()), - LOCATION(RC_GF_BREAK_ROOM_POT_1, logic->CanBreakPots()), - LOCATION(RC_GF_BREAK_ROOM_POT_2, logic->CanBreakPots()), - LOCATION(RC_GF_KITCHEN_POT_1, (logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT)) && logic->CanBreakPots()), - LOCATION(RC_GF_KITCHEN_POT_2, (logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT)) && logic->CanBreakPots()), - LOCATION(RC_GF_NORTH_F1_CARPENTER_POT_1, logic->CanBreakPots()), - LOCATION(RC_GF_NORTH_F1_CARPENTER_POT_2, logic->CanBreakPots()), - LOCATION(RC_GF_NORTH_F1_CARPENTER_POT_3, logic->CanBreakPots()), - LOCATION(RC_GF_NORTH_F2_CARPENTER_POT_1, logic->CanBreakPots()), - LOCATION(RC_GF_NORTH_F2_CARPENTER_POT_2, logic->CanBreakPots()), - LOCATION(RC_GF_SOUTH_F1_CARPENTER_POT_1, logic->CanBreakPots()), - LOCATION(RC_GF_SOUTH_F1_CARPENTER_POT_2, logic->CanBreakPots()), - LOCATION(RC_GF_SOUTH_F1_CARPENTER_POT_3, logic->CanBreakPots()), - LOCATION(RC_GF_SOUTH_F1_CARPENTER_CELL_POT_1, logic->CanBreakPots()), - LOCATION(RC_GF_SOUTH_F1_CARPENTER_CELL_POT_2, logic->CanBreakPots()), - LOCATION(RC_GF_SOUTH_F1_CARPENTER_CELL_POT_3, logic->CanBreakPots()), - LOCATION(RC_GF_SOUTH_F1_CARPENTER_CELL_POT_4, logic->CanBreakPots()), - //RANDOTODO doublecheck when GF isn't a blob - LOCATION(RC_GF_KITCHEN_SUN_FAIRY, (logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT)) && logic->CanUse(RG_SUNS_SONG)), - }, { - //Exits - Entrance(RR_GV_FORTRESS_SIDE, {[]{return true;}}), - Entrance(RR_GF_OUTSIDE_GATE, {[]{return logic->GF_GateOpen;}}), - Entrance(RR_GERUDO_TRAINING_GROUND_ENTRYWAY, {[]{return logic->GtG_GateOpen && (logic->IsAdult || ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES));}}), - Entrance(RR_GF_STORMS_GROTTO, {[]{return logic->IsAdult && logic->CanOpenStormsGrotto();}}), - }); - - areaTable[RR_GF_OUTSIDE_GATE] = Region("GF Outside Gate", "Gerudo Fortress", {RA_GERUDO_FORTRESS}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->GF_GateOpen, {[]{return logic->IsAdult && logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) && (ctx->GetOption(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD) || ctx->GetOption(RSK_SHUFFLE_OVERWORLD_ENTRANCES) /*|| ShuffleSpecialIndoorEntrances*/);}}), - }, {}, { - //Exits - Entrance(RR_GERUDO_FORTRESS, {[]{return (logic->IsAdult && (logic->CanUse(RG_HOOKSHOT) || !ctx->GetOption(RSK_SHUFFLE_OVERWORLD_ENTRANCES))) || logic->GF_GateOpen;}}), - Entrance(RR_WASTELAND_NEAR_FORTRESS, {[]{return true;}}), - }); - - areaTable[RR_GF_STORMS_GROTTO] = Region("GF Storms Grotto", "GF Storms Grotto", {}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->FreeFairies, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_GF_FAIRY_GROTTO_FAIRY_1, true), - LOCATION(RC_GF_FAIRY_GROTTO_FAIRY_2, true), - LOCATION(RC_GF_FAIRY_GROTTO_FAIRY_3, true), - LOCATION(RC_GF_FAIRY_GROTTO_FAIRY_4, true), - LOCATION(RC_GF_FAIRY_GROTTO_FAIRY_5, true), - LOCATION(RC_GF_FAIRY_GROTTO_FAIRY_6, true), - LOCATION(RC_GF_FAIRY_GROTTO_FAIRY_7, true), - LOCATION(RC_GF_FAIRY_GROTTO_FAIRY_8, true), - }, { - //Exits - Entrance(RR_GERUDO_FORTRESS, {[]{return true;}}), - }); - - areaTable[RR_WASTELAND_NEAR_FORTRESS] = Region("Wasteland Near Fortress", "Haunted Wasteland", {RA_HAUNTED_WASTELAND}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_GF_OUTSIDE_GATE, {[]{return true;}}), - Entrance(RR_HAUNTED_WASTELAND, {[]{return logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_LONGSHOT) || ctx->GetTrickOption(RT_HW_CROSSING);}}), - }); - - areaTable[RR_HAUNTED_WASTELAND] = Region("Haunted Wasteland", "Haunted Wasteland", {RA_HAUNTED_WASTELAND}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->FairyPot, {[]{return true;}}), - EventAccess(&logic->NutPot, {[]{return true;}}), - EventAccess(&logic->CarpetMerchant, {[]{return logic->HasItem(RG_ADULT_WALLET) && CanBuyAnother(RC_WASTELAND_BOMBCHU_SALESMAN) && (logic->CanJumpslashExceptHammer() || logic->CanUse(RG_HOVER_BOOTS));}}), - }, { - //Locations - LOCATION(RC_WASTELAND_CHEST, logic->HasFireSource()), - LOCATION(RC_WASTELAND_BOMBCHU_SALESMAN, logic->CanJumpslashExceptHammer() || logic->CanUse(RG_HOVER_BOOTS)), - LOCATION(RC_WASTELAND_GS, logic->HookshotOrBoomerang()), - LOCATION(RC_WASTELAND_NEAR_GS_POT_1, logic->CanBreakPots()), - LOCATION(RC_WASTELAND_NEAR_GS_POT_2, logic->CanBreakPots()), - LOCATION(RC_WASTELAND_NEAR_GS_POT_3, logic->CanBreakPots()), - LOCATION(RC_WASTELAND_NEAR_GS_POT_4, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_WASTELAND_NEAR_COLOSSUS, {[]{return ctx->GetTrickOption(RT_LENS_HW) || logic->CanUse(RG_LENS_OF_TRUTH);}}), - Entrance(RR_WASTELAND_NEAR_FORTRESS, {[]{return logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_LONGSHOT) || ctx->GetTrickOption(RT_HW_CROSSING);}}), - }); - - areaTable[RR_WASTELAND_NEAR_COLOSSUS] = Region("Wasteland Near Colossus", "Haunted Wasteland", {RA_HAUNTED_WASTELAND}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_DESERT_COLOSSUS, {[]{return true;}}), - Entrance(RR_HAUNTED_WASTELAND, {[]{return ctx->GetTrickOption(RT_HW_REVERSE) || false;}}), - }); - - areaTable[RR_DESERT_COLOSSUS] = Region("Desert Colossus", "Desert Colossus", {RA_DESERT_COLOSSUS}, DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->FairyPond, {[]{return logic->FairyPond || logic->CanUse(RG_SONG_OF_STORMS);}}), - EventAccess(&logic->BugRock, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_COLOSSUS_FREESTANDING_POH, logic->IsAdult && CanPlantBean(RR_DESERT_COLOSSUS)), - LOCATION(RC_COLOSSUS_GS_BEAN_PATCH, logic->CanSpawnSoilSkull() && logic->CanAttack()), - LOCATION(RC_COLOSSUS_GS_TREE, logic->IsAdult && logic->HookshotOrBoomerang() && logic->CanGetNightTimeGS()), - LOCATION(RC_COLOSSUS_GS_HILL, logic->IsAdult && ((CanPlantBean(RR_DESERT_COLOSSUS) && logic->CanAttack()) || logic->CanUse(RG_LONGSHOT) || (ctx->GetTrickOption(RT_COLOSSUS_GS) && logic->CanUse(RG_HOOKSHOT))) && logic->CanGetNightTimeGS()), - LOCATION(RC_COLOSSUS_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_COLOSSUS_BEAN_SPROUT_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_COLOSSUS_BEAN_SPROUT_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_COLOSSUS_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), - LOCATION(RC_COLOSSUS_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_COLOSSUS_GOSSIP_STONE, true), - }, { - //Exits - //You can kinda get the fairies without entering the water, but it relies on them cooperating and leevers are jerks. should be a trick - Entrance(RR_DESERT_COLOSSUS_OASIS, {[]{return logic->CanUse(RG_SONG_OF_STORMS) && (logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS));}}), - Entrance(RR_COLOSSUS_GREAT_FAIRY_FOUNTAIN, {[]{return logic->HasExplosives();}}), - Entrance(RR_SPIRIT_TEMPLE_ENTRYWAY, {[]{return true;}}), - Entrance(RR_WASTELAND_NEAR_COLOSSUS, {[]{return true;}}), - Entrance(RR_COLOSSUS_GROTTO, {[]{return logic->CanUse(RG_SILVER_GAUNTLETS);}}), - }); - -//specifically the full oasis, after the fairies have spawned - areaTable[RR_DESERT_COLOSSUS_OASIS] = Region("Desert Colossus Oasis", "Desert Colossus", {RA_DESERT_COLOSSUS}, DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->FairyPond, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_COLOSSUS_OASIS_FAIRY_1, true), - LOCATION(RC_COLOSSUS_OASIS_FAIRY_2, true), - LOCATION(RC_COLOSSUS_OASIS_FAIRY_3, true), - LOCATION(RC_COLOSSUS_OASIS_FAIRY_4, true), - LOCATION(RC_COLOSSUS_OASIS_FAIRY_5, true), - LOCATION(RC_COLOSSUS_OASIS_FAIRY_6, true), - LOCATION(RC_COLOSSUS_OASIS_FAIRY_7, true), - LOCATION(RC_COLOSSUS_OASIS_FAIRY_8, true), - }, { - //Exits - Entrance(RR_DESERT_COLOSSUS, {[]{return true;}}), - }); - - areaTable[RR_DESERT_COLOSSUS_OUTSIDE_TEMPLE] = Region("Desert Colossus From Spirit Entryway", "Desert Colossus", {RA_DESERT_COLOSSUS}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SHEIK_AT_COLOSSUS, true), - }, { - //Exist - Entrance(RR_DESERT_COLOSSUS, {[]{return true;}}), - }); - - areaTable[RR_COLOSSUS_GREAT_FAIRY_FOUNTAIN] = Region("Colossus Great Fairy Fountain", "Colossus Great Fairy Fountain", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_COLOSSUS_GREAT_FAIRY_REWARD, logic->CanUse(RG_ZELDAS_LULLABY)), - }, { - //Exits - Entrance(RR_DESERT_COLOSSUS, {[]{return true;}}), - }); - - areaTable[RR_COLOSSUS_GROTTO] = Region("Colossus Grotto", "Colossus Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_COLOSSUS_DEKU_SCRUB_GROTTO_REAR, logic->CanStunDeku()), - LOCATION(RC_COLOSSUS_DEKU_SCRUB_GROTTO_FRONT, logic->CanStunDeku()), - LOCATION(RC_COLOSSUS_GROTTO_BEEHIVE, logic->CanBreakUpperBeehives()), - }, { - //Exits - Entrance(RR_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 deleted file mode 100644 index 540cb0e34..000000000 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_hyrule_field.cpp +++ /dev/null @@ -1,335 +0,0 @@ -#include "../location_access.hpp" -#include "../../entrance.h" - -using namespace Rando; - -void RegionTable_Init_HyruleField() { - areaTable[RR_HYRULE_FIELD] = Region("Hyrule Field", "Hyrule Field", {RA_HYRULE_FIELD}, DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->BigPoeKill, {[]{return logic->CanUse(RG_FAIRY_BOW) && logic->CanUse(RG_EPONA) && logic->HasBottle();}}), - }, { - //Locations - LOCATION(RC_HF_OCARINA_OF_TIME_ITEM, logic->IsChild && logic->StoneCount() == 3 && logic->HasItem(RG_BRONZE_SCALE)), - LOCATION(RC_SONG_FROM_OCARINA_OF_TIME, logic->IsChild && logic->StoneCount() == 3 && logic->HasItem(RG_BRONZE_SCALE)), - LOCATION(RC_HF_POND_STORMS_FAIRY, logic->CanUse(RG_SONG_OF_STORMS)), - }, { - //Exits - Entrance(RR_LW_BRIDGE, {[]{return true;}}), - Entrance(RR_LAKE_HYLIA, {[]{return true;}}), - Entrance(RR_GERUDO_VALLEY, {[]{return true;}}), - Entrance(RR_MARKET_ENTRANCE, {[]{return true;}}), - Entrance(RR_KAKARIKO_VILLAGE, {[]{return true;}}), - Entrance(RR_ZR_FRONT, {[]{return true;}}), - Entrance(RR_LON_LON_RANCH, {[]{return true;}}), - Entrance(RR_HF_SOUTHEAST_GROTTO, {[]{return Here(RR_HYRULE_FIELD, []{return logic->BlastOrSmash();});}}), - Entrance(RR_HF_OPEN_GROTTO, {[]{return true;}}), - Entrance(RR_HF_INSIDE_FENCE_GROTTO, {[]{return logic->CanOpenBombGrotto();}}), - Entrance(RR_HF_COW_GROTTO, {[]{return (logic->CanUse(RG_MEGATON_HAMMER) || logic->IsChild) && logic->CanOpenBombGrotto();}}), - Entrance(RR_HF_NEAR_MARKET_GROTTO, {[]{return Here(RR_HYRULE_FIELD, []{return logic->BlastOrSmash();});}}), - Entrance(RR_HF_FAIRY_GROTTO, {[]{return Here(RR_HYRULE_FIELD, []{return logic->BlastOrSmash();});}}), - Entrance(RR_HF_NEAR_KAK_GROTTO, {[]{return logic->CanOpenBombGrotto();}}), - Entrance(RR_HF_TEKTITE_GROTTO, {[]{return logic->CanOpenBombGrotto();}}), - }); - - areaTable[RR_HF_SOUTHEAST_GROTTO] = Region("HF Southeast Grotto", "HF Southeast Grotto", {}, NO_DAY_NIGHT_CYCLE, grottoEvents, { - //Locations - LOCATION(RC_HF_SOUTHEAST_GROTTO_CHEST, true), - LOCATION(RC_HF_SOUTHEAST_GROTTO_FISH, logic->HasBottle()), - LOCATION(RC_HF_SOUTHEAST_GROTTO_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), - LOCATION(RC_HF_SOUTHEAST_GROTTO_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_HF_SOUTHEAST_GROTTO_GOSSIP_STONE, true), - LOCATION(RC_HF_SOUTHEAST_GROTTO_BEEHIVE_LEFT, logic->CanBreakLowerBeehives()), - LOCATION(RC_HF_SOUTHEAST_GROTTO_BEEHIVE_RIGHT, logic->CanBreakLowerBeehives()), - }, { - //Exits - Entrance(RR_HYRULE_FIELD, {[]{return true;}}), - }); - - areaTable[RR_HF_OPEN_GROTTO] = Region("HF Open Grotto", "HF Open Grotto", {}, NO_DAY_NIGHT_CYCLE, grottoEvents, { - //Locations - LOCATION(RC_HF_OPEN_GROTTO_CHEST, true), - LOCATION(RC_HF_OPEN_GROTTO_FISH, logic->HasBottle()), - LOCATION(RC_HF_OPEN_GROTTO_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), - LOCATION(RC_HF_OPEN_GROTTO_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_HF_OPEN_GROTTO_GOSSIP_STONE, true), - LOCATION(RC_HF_OPEN_GROTTO_BEEHIVE_LEFT, logic->CanBreakLowerBeehives()), - LOCATION(RC_HF_OPEN_GROTTO_BEEHIVE_RIGHT, logic->CanBreakLowerBeehives()), - }, { - //Exits - Entrance(RR_HYRULE_FIELD, {[]{return true;}}), - }); - - areaTable[RR_HF_INSIDE_FENCE_GROTTO] = Region("HF Inside Fence Grotto", "HF Inside Fence Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_HF_DEKU_SCRUB_GROTTO, logic->CanStunDeku()), - LOCATION(RC_HF_INSIDE_FENCE_GROTTO_BEEHIVE, logic->CanBreakLowerBeehives()), - LOCATION(RC_HF_FENCE_GROTTO_STORMS_FAIRY, logic->CanUse(RG_SONG_OF_STORMS)), - }, { - //Exits - Entrance(RR_HYRULE_FIELD, {[]{return true;}}), - }); - - areaTable[RR_HF_COW_GROTTO] = Region("HF Cow Grotto", "HF Cow Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_HYRULE_FIELD, {[]{return true;}}), - Entrance(RR_HF_COW_GROTTO_BEHIND_WEBS, {[]{return logic->HasFireSource();}}), - }); - - areaTable[RR_HF_COW_GROTTO_BEHIND_WEBS] = Region("HF Cow Grotto Behind Webs", "HF Cow Grotto", {}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->BugShrub, {[]{return logic->CanCutShrubs();}}), - EventAccess(&logic->GossipStoneFairy, {[]{return logic->CallGossipFairy();}}), - }, { - //Locations - LOCATION(RC_HF_GS_COW_GROTTO, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)), - LOCATION(RC_HF_COW_GROTTO_COW, logic->CanUse(RG_EPONAS_SONG)), - LOCATION(RC_HF_COW_GROTTO_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), - LOCATION(RC_HF_COW_GROTTO_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_HF_COW_GROTTO_GOSSIP_STONE, true), - LOCATION(RC_HF_COW_GROTTO_POT_1, logic->CanBreakPots()), - LOCATION(RC_HF_COW_GROTTO_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_HF_COW_GROTTO, {[]{return true;}}), - }); - - areaTable[RR_HF_NEAR_MARKET_GROTTO] = Region("HF Near Market Grotto", "HF Near Market Grotto", {}, NO_DAY_NIGHT_CYCLE, grottoEvents, { - //Locations - LOCATION(RC_HF_NEAR_MARKET_GROTTO_CHEST, true), - LOCATION(RC_HF_NEAR_MARKET_GROTTO_FISH, logic->HasBottle()), - LOCATION(RC_HF_NEAR_MARKET_GROTTO_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), - LOCATION(RC_HF_NEAR_MARKET_GROTTO_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_HF_NEAR_MARKET_GROTTO_GOSSIP_STONE, true), - LOCATION(RC_HF_NEAR_MARKET_GROTTO_BEEHIVE_LEFT, logic->CanBreakLowerBeehives()), - LOCATION(RC_HF_NEAR_MARKET_GROTTO_BEEHIVE_RIGHT, logic->CanBreakLowerBeehives()), - }, { - //Exits - Entrance(RR_HYRULE_FIELD, {[]{return true;}}), - }); - - areaTable[RR_HF_FAIRY_GROTTO] = Region("HF Fairy Grotto", "HF Fairy Grotto", {}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->FreeFairies, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_HF_FAIRY_GROTTO_FAIRY_1, true), - LOCATION(RC_HF_FAIRY_GROTTO_FAIRY_2, true), - LOCATION(RC_HF_FAIRY_GROTTO_FAIRY_3, true), - LOCATION(RC_HF_FAIRY_GROTTO_FAIRY_4, true), - LOCATION(RC_HF_FAIRY_GROTTO_FAIRY_5, true), - LOCATION(RC_HF_FAIRY_GROTTO_FAIRY_6, true), - LOCATION(RC_HF_FAIRY_GROTTO_FAIRY_7, true), - LOCATION(RC_HF_FAIRY_GROTTO_FAIRY_8, true), - }, { - //Exits - Entrance(RR_HYRULE_FIELD, {[]{return true;}}), - }); - - areaTable[RR_HF_NEAR_KAK_GROTTO] = Region("HF Near Kak Grotto", "HF Near Kak Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_HF_GS_NEAR_KAK_GROTTO, logic->HookshotOrBoomerang()), - }, { - //Exits - Entrance(RR_HYRULE_FIELD, {[]{return true;}}), - }); - - areaTable[RR_HF_TEKTITE_GROTTO] = Region("HF Tektite Grotto", "HF Tektite Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_HF_TEKTITE_GROTTO_FREESTANDING_POH, logic->HasItem(RG_GOLDEN_SCALE) || logic->CanUse(RG_IRON_BOOTS)), - }, { - //Exits - Entrance(RR_HYRULE_FIELD, {[]{return true;}}), - }); - - areaTable[RR_LAKE_HYLIA] = Region("Lake Hylia", "Lake Hylia", {RA_LAKE_HYLIA}, DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->GossipStoneFairy, {[]{return logic->CallGossipFairy();}}), - EventAccess(&logic->BeanPlantFairy, {[]{return logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS);}}), - EventAccess(&logic->ButterflyFairy, {[]{return logic->ButterflyFairy || logic->CanUse(RG_STICKS);}}), - EventAccess(&logic->BugShrub, {[]{return logic->BugShrub || (logic->IsChild && logic->CanCutShrubs());}}), - EventAccess(&logic->ChildScarecrow, {[]{return logic->ChildScarecrow || (logic->IsChild && logic->HasItem(RG_FAIRY_OCARINA) && logic->OcarinaButtons() >= 2);}}), - EventAccess(&logic->AdultScarecrow, {[]{return logic->AdultScarecrow || (logic->IsAdult && logic->HasItem(RG_FAIRY_OCARINA) && logic->OcarinaButtons() >= 2);}}), - }, { - //Locations - LOCATION(RC_LH_UNDERWATER_ITEM, logic->IsChild && logic->HasItem(RG_SILVER_SCALE)), - LOCATION(RC_LH_SUN, logic->IsAdult && ((logic->WaterTempleClear && logic->HasItem(RG_BRONZE_SCALE)) || logic->CanUse(RG_DISTANT_SCARECROW)) && logic->CanUse(RG_FAIRY_BOW)), - LOCATION(RC_LH_FREESTANDING_POH, logic->IsAdult && (logic->CanUse(RG_SCARECROW) || CanPlantBean(RR_LAKE_HYLIA))), - LOCATION(RC_LH_GS_BEAN_PATCH, logic->CanSpawnSoilSkull() && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)), - LOCATION(RC_LH_GS_LAB_WALL, logic->IsChild && (logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG) || (ctx->GetTrickOption(RT_LH_LAB_WALL_GS) && logic->CanJumpslashExceptHammer())) && logic->CanGetNightTimeGS()), - LOCATION(RC_LH_GS_SMALL_ISLAND, logic->IsChild && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA) && logic->CanGetNightTimeGS() && logic->HasItem(RG_BRONZE_SCALE)), - LOCATION(RC_LH_GS_TREE, logic->IsAdult && logic->CanUse(RG_LONGSHOT) && logic->CanGetNightTimeGS()), - LOCATION(RC_LH_FRONT_RUPEE, logic->IsChild && logic->HasItem(RG_BRONZE_SCALE)), - LOCATION(RC_LH_MIDDLE_RUPEE, logic->IsChild && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS))), - LOCATION(RC_LH_BACK_RUPEE, logic->IsChild && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS))), - LOCATION(RC_LH_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_LH_BEAN_SPROUT_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_LH_BEAN_SPROUT_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_LH_LAB_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), - LOCATION(RC_LH_LAB_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - //You can walk along the edge of the lake to get these without swimming, the fairy is created going backwards, which is convenient here, - LOCATION(RC_LH_SOUTHEAST_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), - LOCATION(RC_LH_SOUTHEAST_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_LH_SOUTHWEST_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), - LOCATION(RC_LH_SOUTHWEST_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_LH_ISLAND_SUN_FAIRY, logic->CanUse(RG_SUNS_SONG) && ((logic->HasItem(RG_BRONZE_SCALE) && (logic->IsChild || logic->WaterTempleClear)) || logic->CanUse(RG_DISTANT_SCARECROW))), - LOCATION(RC_LH_LAB_GOSSIP_STONE, true), - LOCATION(RC_LH_SOUTHEAST_GOSSIP_STONE, true), - LOCATION(RC_LH_SOUTHWEST_GOSSIP_STONE, true), - }, { - //Exits - Entrance(RR_HYRULE_FIELD, {[]{return true;}}), - Entrance(RR_ZORAS_DOMAIN, {[]{return logic->IsChild && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS));}}), - Entrance(RR_LH_OWL_FLIGHT, {[]{return logic->IsChild;}}), - Entrance(RR_LH_FISHING_ISLAND, {[]{return ((logic->IsChild || logic->WaterTempleClear) && logic->HasItem(RG_BRONZE_SCALE)) || (logic->IsAdult && (logic->CanUse(RG_SCARECROW) || CanPlantBean(RR_LAKE_HYLIA)));}}), - Entrance(RR_LH_LAB, {[]{return true;}}), - Entrance(RR_WATER_TEMPLE_ENTRYWAY, {[]{return logic->CanUse(RG_HOOKSHOT) && ((logic->CanUse(RG_IRON_BOOTS) || (ctx->GetTrickOption(RT_LH_WATER_HOOKSHOT) && logic->HasItem(RG_GOLDEN_SCALE))) || (logic->IsAdult && logic->CanUse(RG_LONGSHOT) && logic->HasItem(RG_GOLDEN_SCALE)));}}), - Entrance(RR_LH_GROTTO, {[]{return true;}}), - }); - - areaTable[RR_LH_FISHING_ISLAND] = Region("LH Fishing Island", "Lake Hylia", {RA_LAKE_HYLIA}, DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_LAKE_HYLIA, {[]{return logic->HasItem(RG_BRONZE_SCALE);}}), - Entrance(RR_LH_FISHING_POND, {[]{return true;}}), - }); - - areaTable[RR_LH_OWL_FLIGHT] = Region("LH Owl Flight", "Lake Hylia", {RA_LAKE_HYLIA}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_HYRULE_FIELD, {[]{return true;}}, false), - }); - - areaTable[RR_LH_LAB] = Region("LH Lab", "LH Lab", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_LH_LAB_DIVE, logic->HasItem(RG_GOLDEN_SCALE) || (ctx->GetTrickOption(RT_LH_LAB_DIVING) && logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT))), - LOCATION(RC_LH_TRADE_FROG, logic->IsAdult && logic->CanUse(RG_EYEBALL_FROG)), - LOCATION(RC_LH_GS_LAB_CRATE, logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT)), - LOCATION(RC_LH_LAB_FRONT_RUPEE, logic->CanUse(RG_IRON_BOOTS) || logic->HasItem(RG_GOLDEN_SCALE)), - LOCATION(RC_LH_LAB_LEFT_RUPEE, logic->CanUse(RG_IRON_BOOTS) || logic->HasItem(RG_GOLDEN_SCALE)), - LOCATION(RC_LH_LAB_RIGHT_RUPEE, logic->CanUse(RG_IRON_BOOTS) || logic->HasItem(RG_GOLDEN_SCALE)), - }, { - //Exits - Entrance(RR_LAKE_HYLIA, {[]{return true;}}), - }); - - areaTable[RR_LH_FISHING_POND] = Region("LH Fishing Hole", "LH Fishing Hole", {}, DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_LH_CHILD_FISHING, logic->CanUse(RG_FISHING_POLE) && logic->IsChild), - LOCATION(RC_LH_CHILD_FISH_1, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), - LOCATION(RC_LH_CHILD_FISH_2, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), - LOCATION(RC_LH_CHILD_FISH_3, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), - LOCATION(RC_LH_CHILD_FISH_4, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), - LOCATION(RC_LH_CHILD_FISH_5, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), - LOCATION(RC_LH_CHILD_FISH_6, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), - LOCATION(RC_LH_CHILD_FISH_7, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), - LOCATION(RC_LH_CHILD_FISH_8, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), - LOCATION(RC_LH_CHILD_FISH_9, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), - LOCATION(RC_LH_CHILD_FISH_10, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), - LOCATION(RC_LH_CHILD_FISH_11, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), - LOCATION(RC_LH_CHILD_FISH_12, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), - LOCATION(RC_LH_CHILD_FISH_13, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), - LOCATION(RC_LH_CHILD_FISH_14, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), - LOCATION(RC_LH_CHILD_FISH_15, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), - LOCATION(RC_LH_CHILD_LOACH_1, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), - LOCATION(RC_LH_CHILD_LOACH_2, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), - LOCATION(RC_LH_ADULT_FISHING, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult), - LOCATION(RC_LH_ADULT_FISH_1, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult && ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT)), - LOCATION(RC_LH_ADULT_FISH_2, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult && ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT)), - LOCATION(RC_LH_ADULT_FISH_3, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult && ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT)), - LOCATION(RC_LH_ADULT_FISH_4, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult && ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT)), - LOCATION(RC_LH_ADULT_FISH_5, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult && ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT)), - LOCATION(RC_LH_ADULT_FISH_6, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult && ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT)), - LOCATION(RC_LH_ADULT_FISH_7, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult && ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT)), - LOCATION(RC_LH_ADULT_FISH_8, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult && ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT)), - LOCATION(RC_LH_ADULT_FISH_9, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult && ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT)), - LOCATION(RC_LH_ADULT_FISH_10, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult && ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT)), - LOCATION(RC_LH_ADULT_FISH_11, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult && ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT)), - LOCATION(RC_LH_ADULT_FISH_12, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult && ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT)), - LOCATION(RC_LH_ADULT_FISH_13, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult && ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT)), - LOCATION(RC_LH_ADULT_FISH_14, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult && ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT)), - LOCATION(RC_LH_ADULT_FISH_15, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult && ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT)), - LOCATION(RC_LH_ADULT_LOACH, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult && ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT)), - LOCATION(RC_LH_HYRULE_LOACH, logic->CanUse(RG_FISHING_POLE)), - LOCATION(RC_FISHING_POLE_HINT, true), - }, { - //Exits - Entrance(RR_LH_FISHING_ISLAND, {[]{return true;}}), - }); - - areaTable[RR_LH_GROTTO] = Region("LH Grotto", "LH Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_LH_DEKU_SCRUB_GROTTO_LEFT, logic->CanStunDeku()), - LOCATION(RC_LH_DEKU_SCRUB_GROTTO_RIGHT, logic->CanStunDeku()), - LOCATION(RC_LH_DEKU_SCRUB_GROTTO_CENTER, logic->CanStunDeku()), - LOCATION(RC_LH_GROTTO_BEEHIVE, logic->CanBreakUpperBeehives()), - }, { - //Exits - Entrance(RR_LAKE_HYLIA, {[]{return true;}}), - }); - - areaTable[RR_LON_LON_RANCH] = Region("Lon Lon Ranch", "Lon Lon Ranch", {RA_LON_LON_RANCH}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->FreedEpona, {[]{return logic->FreedEpona || ((logic->HasItem(RG_CHILD_WALLET) || ctx->GetOption(RSK_SKIP_EPONA_RACE)) && logic->CanUse(RG_EPONAS_SONG) && logic->IsAdult && logic->AtDay);}}), - EventAccess(&logic->LinksCow, {[]{return logic->LinksCow || (logic->HasItem(RG_CHILD_WALLET) && logic->CanUse(RG_EPONAS_SONG) && logic->IsAdult && logic->AtDay);}}), - }, { - //Locations - LOCATION(RC_SONG_FROM_MALON, logic->IsChild && logic->HasItem(RG_ZELDAS_LETTER) && logic->HasItem(RG_FAIRY_OCARINA) && logic->AtDay), - LOCATION(RC_LLR_GS_TREE, logic->IsChild), - LOCATION(RC_LLR_GS_RAIN_SHED, logic->IsChild && logic->CanGetNightTimeGS()), - LOCATION(RC_LLR_GS_HOUSE_WINDOW, logic->IsChild && logic->HookshotOrBoomerang() && logic->CanGetNightTimeGS()), - LOCATION(RC_LLR_GS_BACK_WALL, logic->IsChild && logic->HookshotOrBoomerang() && logic->CanGetNightTimeGS()), - LOCATION(RC_LLR_FRONT_POT_1, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_LLR_FRONT_POT_2, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_LLR_FRONT_POT_3, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_LLR_FRONT_POT_4, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_LLR_RAIN_SHED_POT_1, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_LLR_RAIN_SHED_POT_2, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_LLR_RAIN_SHED_POT_3, logic->IsChild && logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_HYRULE_FIELD, {[]{return true;}}), - Entrance(RR_LLR_TALONS_HOUSE, {[]{return true;}}), - Entrance(RR_LLR_STABLES, {[]{return true;}}), - Entrance(RR_LLR_TOWER, {[]{return true;}}), - Entrance(RR_LLR_GROTTO, {[]{return logic->IsChild;}}), - }); - - areaTable[RR_LLR_TALONS_HOUSE] = Region("LLR Talons House", "LLR Talons House", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_LLR_TALONS_CHICKENS, logic->HasItem(RG_CHILD_WALLET) && logic->IsChild && logic->AtDay && logic->HasItem(RG_ZELDAS_LETTER)), - LOCATION(RC_LLR_TALONS_HOUSE_POT_1, logic->CanBreakPots()), - LOCATION(RC_LLR_TALONS_HOUSE_POT_2, logic->CanBreakPots()), - LOCATION(RC_LLR_TALONS_HOUSE_POT_3, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_LON_LON_RANCH, {[]{return true;}}), - }); - - areaTable[RR_LLR_STABLES] = Region("LLR Stables", "LLR Stables", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_LLR_STABLES_LEFT_COW, logic->CanUse(RG_EPONAS_SONG)), - LOCATION(RC_LLR_STABLES_RIGHT_COW, logic->CanUse(RG_EPONAS_SONG)), - }, { - //Exits - Entrance(RR_LON_LON_RANCH, {[]{return true;}}), - }); - - areaTable[RR_LLR_TOWER] = Region("LLR Tower", "LLR Tower", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_LLR_FREESTANDING_POH, logic->IsChild), - LOCATION(RC_LLR_TOWER_LEFT_COW, logic->CanUse(RG_EPONAS_SONG)), - LOCATION(RC_LLR_TOWER_RIGHT_COW, logic->CanUse(RG_EPONAS_SONG)), - }, { - //Exits - Entrance(RR_LON_LON_RANCH, {[]{return true;}}), - }); - - areaTable[RR_LLR_GROTTO] = Region("LLR Grotto", "LLR Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_LLR_DEKU_SCRUB_GROTTO_LEFT, logic->CanStunDeku()), - LOCATION(RC_LLR_DEKU_SCRUB_GROTTO_RIGHT, logic->CanStunDeku()), - LOCATION(RC_LLR_DEKU_SCRUB_GROTTO_CENTER, logic->CanStunDeku()), - LOCATION(RC_LLR_GROTTO_BEEHIVE, logic->CanBreakUpperBeehives()), - }, { - //Exits - Entrance(RR_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 deleted file mode 100644 index e5f24ab55..000000000 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_ice_cavern.cpp +++ /dev/null @@ -1,152 +0,0 @@ -#include "../location_access.hpp" -#include "../../entrance.h" -#include "../../dungeon.h" - -using namespace Rando; - -void RegionTable_Init_IceCavern() { - /*-------------------------- - | VANILLA/MQ DECIDER | - ---------------------------*/ - areaTable[RR_ICE_CAVERN_ENTRYWAY] = Region("Ice Cavern Entryway", "Ice Cavern", {RA_ICE_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_ICE_CAVERN_BEGINNING, {[]{return ctx->GetDungeon(ICE_CAVERN)->IsVanilla();}}), - Entrance(RR_ICE_CAVERN_MQ_BEGINNING, {[]{return ctx->GetDungeon(ICE_CAVERN)->IsMQ() && logic->CanUseProjectile();}}), - Entrance(RR_ZORAS_FOUNTAIN, {[]{return true;}}), - }); - - /*-------------------------- - | VANILLA DUNGEON | - ---------------------------*/ - if (ctx->GetDungeon(ICE_CAVERN)->IsVanilla()) { - areaTable[RR_ICE_CAVERN_BEGINNING] = Region("Ice Cavern Beginning", "Ice Cavern", {RA_ICE_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_ICE_CAVERN_ENTRANCE_STORMS_FAIRY, logic->CanUse(RG_SONG_OF_STORMS)), - }, { - //Exits - Entrance(RR_ICE_CAVERN_ENTRYWAY, {[]{return true;}}), - Entrance(RR_ICE_CAVERN_MAIN, {[]{return Here(RR_ICE_CAVERN_BEGINNING, []{return (logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD)) || logic->CanUse(RG_MEGATON_HAMMER) || logic->HasExplosives() || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_DINS_FIRE);});}}), - }); - - areaTable[RR_ICE_CAVERN_MAIN] = Region("Ice Cavern", "Ice Cavern", {RA_ICE_CAVERN}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->BlueFireAccess, {[]{return logic->BlueFireAccess || (logic->IsAdult && logic->HasBottle());}}), - }, { - //Locations - LOCATION(RC_ICE_CAVERN_MAP_CHEST, logic->BlueFire() && logic->IsAdult), - LOCATION(RC_ICE_CAVERN_COMPASS_CHEST, logic->BlueFire()), - LOCATION(RC_ICE_CAVERN_IRON_BOOTS_CHEST, logic->BlueFire() && (logic->CanJumpslash() || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_DINS_FIRE))), - LOCATION(RC_SHEIK_IN_ICE_CAVERN, logic->BlueFire() && (logic->CanJumpslash() || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_DINS_FIRE)) && logic->IsAdult), - LOCATION(RC_ICE_CAVERN_FREESTANDING_POH, logic->BlueFire()), - LOCATION(RC_ICE_CAVERN_GS_SPINNING_SCYTHE_ROOM, logic->HookshotOrBoomerang()), - LOCATION(RC_ICE_CAVERN_GS_HEART_PIECE_ROOM, logic->BlueFire() && logic->HookshotOrBoomerang()), - LOCATION(RC_ICE_CAVERN_GS_PUSH_BLOCK_ROOM, logic->BlueFire() && (logic->HookshotOrBoomerang() || (ctx->GetTrickOption(RT_ICE_BLOCK_GS) && logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)))), - LOCATION(RC_ICE_CAVERN_HALL_POT_1, logic->CanBreakPots()), - LOCATION(RC_ICE_CAVERN_HALL_POT_2, logic->CanBreakPots()), - LOCATION(RC_ICE_CAVERN_SPINNING_BLADE_POT_1, logic->CanBreakPots()), - LOCATION(RC_ICE_CAVERN_SPINNING_BLADE_POT_2, logic->CanBreakPots()), - LOCATION(RC_ICE_CAVERN_SPINNING_BLADE_POT_3, logic->CanBreakPots()), - LOCATION(RC_ICE_CAVERN_NEAR_END_POT_1, logic->CanBreakPots() && logic->BlueFire()), - LOCATION(RC_ICE_CAVERN_NEAR_END_POT_2, logic->CanBreakPots() && logic->BlueFire()), - LOCATION(RC_ICE_CAVERN_FROZEN_POT_1, logic->CanBreakPots() && logic->BlueFire() && logic->IsAdult), - LOCATION(RC_ICE_CAVERN_LOBBY_RUPEE, logic->BlueFire()), - LOCATION(RC_ICE_CAVERN_MAP_ROOM_LEFT_HEART, logic->IsAdult), - LOCATION(RC_ICE_CAVERN_MAP_ROOM_MIDDLE_HEART, logic->IsAdult), - LOCATION(RC_ICE_CAVERN_MAP_ROOM_RIGHT_HEART, logic->IsAdult), - LOCATION(RC_ICE_CAVERN_SLIDING_BLOCK_RUPEE_1, logic->BlueFire() && (logic->CanUse(RG_SONG_OF_TIME) || logic->CanUse(RG_BOOMERANG))), - LOCATION(RC_ICE_CAVERN_SLIDING_BLOCK_RUPEE_2, logic->BlueFire() && (logic->CanUse(RG_SONG_OF_TIME) || logic->CanUse(RG_BOOMERANG))), - LOCATION(RC_ICE_CAVERN_SLIDING_BLOCK_RUPEE_3, logic->BlueFire() && (logic->CanUse(RG_SONG_OF_TIME) || logic->CanUse(RG_BOOMERANG))), - }, {}); - } - - /*--------------------------- - | MASTER QUEST DUNGEON | - ---------------------------*/ - if (ctx->GetDungeon(ICE_CAVERN)->IsMQ()) { - areaTable[RR_ICE_CAVERN_MQ_BEGINNING] = Region("Ice Cavern MQ Beginning", "Ice Cavern", {RA_ICE_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_ICE_CAVERN_MQ_ENTRANCE_POT, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_ICE_CAVERN_ENTRYWAY, {[]{return true;}}), - //It is in logic to use a pot to hit the toggle switch here. - Entrance(RR_ICE_CAVERN_MQ_HUB, {[]{return true;}}), - }); - - areaTable[RR_ICE_CAVERN_MQ_HUB] = Region("Ice Cavern MQ Hub", "Ice Cavern", {RA_ICE_CAVERN}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->FairyPot, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_ICE_CAVERN_MQ_FIRST_CRYSTAL_POT_1, logic->CanBreakPots()), - LOCATION(RC_ICE_CAVERN_MQ_FIRST_CRYSTAL_POT_2, logic->CanBreakPots()), - LOCATION(RC_ICE_CAVERN_MQ_EARLY_WOLFOS_POT_1, logic->CanBreakPots()), - LOCATION(RC_ICE_CAVERN_MQ_EARLY_WOLFOS_POT_2, logic->CanBreakPots()), - LOCATION(RC_ICE_CAVERN_MQ_EARLY_WOLFOS_POT_3, logic->CanBreakPots()), - LOCATION(RC_ICE_CAVERN_MQ_EARLY_WOLFOS_POT_4, logic->CanBreakPots()), - }, { - //Exits - //the switch for the glass blocking the entrance is linked to the switch that controls the glass around the skulltulla in RR_ICE_CAVERN_MQ_SCARECROW_ROOM - //if you clear the ice, you can hit it with a pot from here. - Entrance(RR_ICE_CAVERN_BEGINNING, {[]{return logic->BlueFire();}}), - Entrance(RR_ICE_CAVERN_MQ_MAP_ROOM, {[]{return Here(RR_ICE_CAVERN_MQ_BEGINNING, []{return logic->CanKillEnemy(RE_WHITE_WOLFOS) && logic->CanKillEnemy(RE_FREEZARD);});}}), - Entrance(RR_ICE_CAVERN_MQ_COMPASS_ROOM, {[]{return logic->IsAdult && logic->BlueFire();}}), - Entrance(RR_ICE_CAVERN_MQ_SCARECROW_ROOM, {[]{return logic->BlueFire();}}), - }); - - areaTable[RR_ICE_CAVERN_MQ_MAP_ROOM] = Region("Ice Cavern MQ Map Room", "Ice Cavern", {RA_ICE_CAVERN}, NO_DAY_NIGHT_CYCLE, { - //Events - //Child can fit between the stalagmites on the left hand side - EventAccess(&logic->BlueFireAccess, {[]{return logic->IsChild || logic->CanJumpslash() || logic->HasExplosives();}}), - }, { - //Locations - LOCATION(RC_ICE_CAVERN_MQ_MAP_CHEST, logic->BlueFire() && Here(RR_ICE_CAVERN_MQ_MAP_ROOM, []{return logic->CanHitSwitch();})), - }, {}); - - areaTable[RR_ICE_CAVERN_MQ_SCARECROW_ROOM] = Region("Ice Cavern MQ Scarecrow Room", "Ice Cavern", {RA_ICE_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_ICE_CAVERN_MQ_GS_ICE_BLOCK, (logic->BlueFire() && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)) || (logic->IsAdult && logic->CanHitSwitch(ED_LONG_JUMPSLASH))), - LOCATION(RC_ICE_CAVERN_MQ_GS_SCARECROW, logic->CanUse(RG_SCARECROW) || (logic->IsAdult && (logic->CanUse(RG_LONGSHOT) || ctx->GetTrickOption(RT_ICE_MQ_SCARECROW)))), - }, { - //Exits - Entrance(RR_ICE_CAVERN_MQ_HUB, {[]{return logic->BlueFire();}}), - //Assumes RR_ICE_CAVERN_MQ_HUB access for a pot if using blue fire - Entrance(RR_ICE_CAVERN_MQ_WEST_CORRIDOR, {[]{return logic->IsAdult && logic->BlueFire();}}), - }); - - areaTable[RR_ICE_CAVERN_MQ_WEST_CORRIDOR] = Region("Ice Cavern MQ West Corridor", "Ice Cavern", {RA_ICE_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_ICE_CAVERN_MQ_PUSH_BLOCK_POT_1, logic->CanBreakPots()), - LOCATION(RC_ICE_CAVERN_MQ_PUSH_BLOCK_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_ICE_CAVERN_MQ_SCARECROW_ROOM, {[]{return logic->BlueFire();}}), - Entrance(RR_ICE_CAVERN_MQ_STALFOS_ROOM, {[]{return true;}}), - }); - - areaTable[RR_ICE_CAVERN_MQ_STALFOS_ROOM] = Region("Ice Cavern MQ Stalfos Room", "Ice Cavern", {RA_ICE_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_ICE_CAVERN_MQ_IRON_BOOTS_CHEST, logic->CanKillEnemy(RE_STALFOS)), - LOCATION(RC_SHEIK_IN_ICE_CAVERN, logic->CanKillEnemy(RE_STALFOS)), - }, { - //Exits - Entrance(RR_ICE_CAVERN_MQ_SCARECROW_ROOM, {[]{return logic->BlueFire() && Here(RR_ICE_CAVERN_MQ_STALFOS_ROOM, []{return logic->CanKillEnemy(RE_STALFOS);});}}), - Entrance(RR_ICE_CAVERN_MQ_BEGINNING, {[]{return logic->CanUse(RG_IRON_BOOTS) && Here(RR_ICE_CAVERN_MQ_STALFOS_ROOM, []{return logic->CanKillEnemy(RE_STALFOS);});}}), - }); - - areaTable[RR_ICE_CAVERN_MQ_COMPASS_ROOM] = Region("Ice Cavern MQ Compass Room", "Ice Cavern", {RA_ICE_CAVERN}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->BlueFireAccess, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_ICE_CAVERN_MQ_COMPASS_CHEST, true), - //It is possible for child with master, BGS or sticks, or adult with BGS, to hit this switch through the ice with a crouchstab, but it's precise and unintuitive for a trick - LOCATION(RC_ICE_CAVERN_MQ_FREESTANDING_POH, logic->HasExplosives()), - //doing RT_ICE_MQ_RED_ICE_GS as child is untested, as I could not perform the trick reliably even as adult - LOCATION(RC_ICE_CAVERN_MQ_GS_RED_ICE, (ctx->GetOption(RSK_BLUE_FIRE_ARROWS) && logic->CanUse(RG_ICE_ARROWS)) || - (logic->CanUse(RG_BOTTLE_WITH_BLUE_FIRE) && (logic->CanUse(RG_SONG_OF_TIME) || (logic->IsAdult && ctx->GetTrickOption(RT_ICE_MQ_RED_ICE_GS))) && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA))), - LOCATION(RC_ICE_CAVERN_MQ_COMPASS_POT_1, logic->CanBreakPots()), - LOCATION(RC_ICE_CAVERN_MQ_COMPASS_POT_2, logic->CanBreakPots()), - }, {}); - } -} 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 deleted file mode 100644 index 73ad909c7..000000000 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_jabujabus_belly.cpp +++ /dev/null @@ -1,377 +0,0 @@ -#include "../location_access.hpp" -#include "../../entrance.h" -#include "../../dungeon.h" - -using namespace Rando; - -void RegionTable_Init_JabuJabusBelly() { - /*-------------------------- - | VANILLA/MQ DECIDER | - ---------------------------*/ - areaTable[RR_JABU_JABUS_BELLY_ENTRYWAY] = Region("Jabu Jabus Belly Entryway", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_JABU_JABUS_BELLY_BEGINNING, {[]{return ctx->GetDungeon(JABU_JABUS_BELLY)->IsVanilla();}}), - Entrance(RR_JABU_JABUS_BELLY_MQ_BEGINNING, {[]{return ctx->GetDungeon(JABU_JABUS_BELLY)->IsMQ();}}), - Entrance(RR_ZORAS_FOUNTAIN, {[]{return true;}}), - }); - - /*-------------------------- - | VANILLA DUNGEON | - ---------------------------*/ - if (ctx->GetDungeon(JABU_JABUS_BELLY)->IsVanilla()) { - areaTable[RR_JABU_JABUS_BELLY_BEGINNING] = Region("Jabu Jabus Belly Beginning", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_JABU_JABUS_BELLY_ENTRYWAY, {[]{return true;}}), - Entrance(RR_JABU_JABUS_BELLY_MAIN, {[]{return logic->CanUseProjectile();}}), - }); - -//Combines Lift room middle and lower, 1F holes room, the forked corridor, and it's side rooms - areaTable[RR_JABU_JABUS_BELLY_MAIN] = Region("Jabu Jabus Belly Main", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->JabuRutoInB1, {[]{return true;}}), - EventAccess(&logic->JabuWestTentacle, {[]{return logic->JabuRutoIn1F && logic->CanKillEnemy(RE_TENTACLE, ED_BOOMERANG);}}), - }, { - //Locations - LOCATION(RC_JABU_JABUS_BELLY_DEKU_SCRUB, logic->HasItem(RG_BRONZE_SCALE) && (logic->IsChild || logic->HasItem(RG_SILVER_SCALE) || ctx->GetTrickOption(RT_JABU_ALCOVE_JUMP_DIVE) || logic->CanUse(RG_IRON_BOOTS)) && logic->CanStunDeku()), - //We can kill the Stingers with ruto - LOCATION(RC_JABU_JABUS_BELLY_BOOMERANG_CHEST, logic->JabuRutoIn1F), - LOCATION(RC_JABU_JABUS_BELLY_MAP_CHEST, logic->JabuWestTentacle), - }, { - //Exits - Entrance(RR_JABU_JABUS_BELLY_BEGINNING, {[]{return true;}}), - Entrance(RR_JABU_JABUS_BELLY_B1_NORTH, {[]{return true;}}), - Entrance(RR_JABU_JABUS_BELLY_COMPASS_ROOM, {[]{return logic->JabuWestTentacle;}}), - Entrance(RR_JABU_JABUS_BELLY_BLUE_TENTACLE, {[]{return logic->JabuWestTentacle;}}), - Entrance(RR_JABU_JABUS_BELLY_GREEN_TENTACLE, {[]{return logic->JabuEastTentacle;}}), - Entrance(RR_JABU_JABUS_BELLY_BIGOCTO_LEDGE, {[]{return logic->JabuNorthTentacle;}}), - Entrance(RR_JABU_JABUS_BELLY_NEAR_BOSS_ROOM, {[]{return logic->LoweredJabuPath || (ctx->GetTrickOption(RT_JABU_BOSS_HOVER) && logic->CanUse(RG_HOVER_BOOTS));}}), - }); - -//contains B1 of hole room (aside from the ledge leading to big octo), 2 octorock room and north water switch room - areaTable[RR_JABU_JABUS_BELLY_B1_NORTH] = Region("Jabu Jabus Belly B1 North", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->JabuRutoIn1F, {[]{return logic->IsAdult || logic->HasItem(RG_BRONZE_SCALE);}}), - EventAccess(&logic->FairyPot, {[]{return logic->CanUse(RG_BOOMERANG) || (logic->CanUse(RG_HOVER_BOOTS) && logic->CanKillEnemy(RE_OCTOROK));}}), - }, { - //Locations - LOCATION(RC_JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_LOWER, logic->HookshotOrBoomerang()), - LOCATION(RC_JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_UPPER, logic->HookshotOrBoomerang()), - LOCATION(RC_JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM, logic->HookshotOrBoomerang()), - LOCATION(RC_JABU_JABUS_BELLY_TWO_OCTOROK_POT_1, (logic->CanBreakPots() && (logic->CanUse(RG_BOOMERANG) || (logic->CanUse(RG_HOVER_BOOTS) && logic->CanKillEnemy(RE_OCTOROK, ED_BOOMERANG, false))))), - LOCATION(RC_JABU_JABUS_BELLY_TWO_OCTOROK_POT_2, (logic->CanBreakPots() && (logic->CanUse(RG_BOOMERANG) || (logic->CanUse(RG_HOVER_BOOTS) && logic->CanKillEnemy(RE_OCTOROK, ED_BOOMERANG, false))))), - LOCATION(RC_JABU_JABUS_BELLY_TWO_OCTOROK_POT_3, (logic->CanBreakPots() && (logic->CanUse(RG_BOOMERANG) || (logic->CanUse(RG_HOVER_BOOTS) && logic->CanKillEnemy(RE_OCTOROK, ED_BOOMERANG, false))))), - LOCATION(RC_JABU_JABUS_BELLY_TWO_OCTOROK_POT_4, (logic->CanBreakPots() && (logic->CanUse(RG_BOOMERANG) || (logic->CanUse(RG_HOVER_BOOTS) && logic->CanKillEnemy(RE_OCTOROK, ED_BOOMERANG, false))))), - LOCATION(RC_JABU_JABUS_BELLY_TWO_OCTOROK_POT_5, (logic->CanBreakPots() && (logic->CanUse(RG_BOOMERANG) || (logic->CanUse(RG_HOVER_BOOTS) && logic->CanKillEnemy(RE_OCTOROK, ED_BOOMERANG, false))))), - }, { - //Exits - Entrance(RR_JABU_JABUS_BELLY_MAIN, {[]{return true;}}), - //there's tricks for getting here with bunny-jumps or just side-hops - Entrance(RR_JABU_JABUS_BELLY_WATER_SWITCH_ROOM_LEDGE, {[]{return logic->HasItem(RG_BRONZE_SCALE) || logic->HasItem(RG_HOVER_BOOTS);}}), - Entrance(RR_JABU_JABUS_BELLY_WATER_SWITCH_ROOM_SOUTH, {[]{return logic->IsAdult || logic->HasItem(RG_BRONZE_SCALE);}}), - }); - - areaTable[RR_JABU_JABUS_BELLY_WATER_SWITCH_ROOM_LEDGE] = Region("Jabu Jabus Belly Water Switch Room Ledge", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->FairyPot, {[]{return true;}}), - }, { - //Locations - //this is the logic for climbing back and forth to use the pots to kill the skull... - LOCATION(RC_JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM, logic->HasItem(RG_BRONZE_SCALE) || - (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)) || - //or killing the skull before climbing to grab the token - logic->CanKillEnemy(RE_GOLD_SKULLTULA, ED_BOMB_THROW)), - LOCATION(RC_JABU_JABUS_BELLY_BASEMENT_POT_1, logic->CanBreakPots()), - LOCATION(RC_JABU_JABUS_BELLY_BASEMENT_POT_2, logic->CanBreakPots()), - LOCATION(RC_JABU_JABUS_BELLY_BASEMENT_POT_3, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_JABU_JABUS_BELLY_B1_NORTH, {[]{return true;}}), - Entrance(RR_JABU_JABUS_BELLY_WATER_SWITCH_ROOM_SOUTH, {[]{return true;}}), - }); - - areaTable[RR_JABU_JABUS_BELLY_WATER_SWITCH_ROOM_SOUTH] = Region("Jabu Jabus Belly Water Switch Room South", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM, logic->HookshotOrBoomerang()), - }, { - //Exits - Entrance(RR_JABU_JABUS_BELLY_B1_NORTH, {[]{return logic->IsAdult || logic->HasItem(RG_BRONZE_SCALE);}}), - Entrance(RR_JABU_JABUS_BELLY_WATER_SWITCH_ROOM_LEDGE, {[]{return logic->HasItem(RG_BRONZE_SCALE) || logic->HasItem(RG_HOVER_BOOTS);}}), - Entrance(RR_JABU_JABUS_BELLY_MAIN, {[]{return logic->CanUseProjectile();}}), - }); - - areaTable[RR_JABU_JABUS_BELLY_COMPASS_ROOM] = Region("Jabu Jabus Belly Compass Room", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - //ruto could theoretically clear this room, but it's hard because of the timer and she doesn't appear with you when you respawn after failing, which would force a savewarp - LOCATION(RC_JABU_JABUS_BELLY_COMPASS_CHEST, logic->CanKillEnemy(RE_SHABOM)), - }, { - //Exits - Entrance(RR_JABU_JABUS_BELLY_MAIN, {[]{return Here(RR_JABU_JABUS_BELLY_COMPASS_ROOM, []{return logic->CanKillEnemy(RE_SHABOM);});}}), - }); - - areaTable[RR_JABU_JABUS_BELLY_BLUE_TENTACLE] = Region("Jabu Jabus Belly Blue Tentacle", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { - EventAccess(&logic->JabuEastTentacle, {[]{return logic->CanKillEnemy(RE_TENTACLE, ED_BOOMERANG);}}), - }, {}, { - //Exits - Entrance(RR_JABU_JABUS_BELLY_MAIN, {[]{return logic->JabuEastTentacle;}}), - }); - - areaTable[RR_JABU_JABUS_BELLY_GREEN_TENTACLE] = Region("Jabu Jabus Belly Green Tentacle", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { - EventAccess(&logic->JabuNorthTentacle, {[]{return logic->CanKillEnemy(RE_TENTACLE, ED_BOOMERANG);}}), - }, {}, { - //Exits - //implied logic->CanKillEnemy(RE_BARI) - Entrance(RR_JABU_JABUS_BELLY_MAIN, {[]{return logic->JabuNorthTentacle;}}), - }); - - areaTable[RR_JABU_JABUS_BELLY_BIGOCTO_LEDGE] = Region("Jabu Jabus Belly Bigocto Room", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - //Only adult can get the token without assistance - LOCATION(RC_JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_UPPER, logic->IsAdult && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_SHORT_JUMPSLASH)), - //You can get the LOWER skull token from here as aduly with hovers backwalk and a backflip, but it's trickworthy and not relevant unless you can beat tentacles without rang - }, { - //Exits - Entrance(RR_JABU_JABUS_BELLY_B1_NORTH, {[]{return true;}}), - Entrance(RR_JABU_JABUS_BELLY_ABOVE_BIGOCTO, {[]{return logic->JabuRutoIn1F && Here(RR_JABU_JABUS_BELLY_BIGOCTO_LEDGE, []{return logic->CanKillEnemy(RE_BIG_OCTO);});}}), - }); - - areaTable[RR_JABU_JABUS_BELLY_ABOVE_BIGOCTO] = Region("Jabu Jabus Belly Above Bigocto", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->FairyPot, {[]{return true;}}), - EventAccess(&logic->NutPot, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_JABU_JABUS_BELLY_ABOVE_BIG_OCTO_POT_1, logic->CanBreakPots()), - LOCATION(RC_JABU_JABUS_BELLY_ABOVE_BIG_OCTO_POT_2, logic->CanBreakPots()), - LOCATION(RC_JABU_JABUS_BELLY_ABOVE_BIG_OCTO_POT_3, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_JABU_JABUS_BELLY_LIFT_UPPER, {[]{return logic->CanUse(RG_BOOMERANG);}}), - }); - - areaTable[RR_JABU_JABUS_BELLY_LIFT_UPPER] = Region("Jabu Jabus Belly Lift Upper", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->LoweredJabuPath, {[]{return true;}}), - }, {}, { - //Exits - Entrance(RR_JABU_JABUS_BELLY_MAIN, {[]{return true;}}), - }); - - areaTable[RR_JABU_JABUS_BELLY_NEAR_BOSS_ROOM] = Region("Jabu Jabus Belly Near Boss Room", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_JABU_JABUS_BELLY_GS_NEAR_BOSS, logic->CanKillEnemy(RE_GOLD_SKULLTULA, ED_BOMB_THROW)), - }, { - //Exits - Entrance(RR_JABU_JABUS_BELLY_MAIN, {[]{return true;}}), - Entrance(RR_JABU_JABUS_BELLY_BOSS_ENTRYWAY, {[]{return logic->CanUse(RG_BOOMERANG) || (ctx->GetTrickOption(RT_JABU_NEAR_BOSS_RANGED) && (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT))) || (ctx->GetTrickOption(RT_JABU_NEAR_BOSS_EXPLOSIVES) && (logic->CanUse(RG_BOMBCHU_5) || (logic->CanUse(RG_HOVER_BOOTS) && logic->CanUse(RG_BOMB_BAG))));}}), - }); - } - - /*--------------------------- - | MASTER QUEST DUNGEON | - ---------------------------*/ - if (ctx->GetDungeon(JABU_JABUS_BELLY)->IsMQ()) { - areaTable[RR_JABU_JABUS_BELLY_MQ_BEGINNING] = Region("Jabu Jabus Belly MQ Beginning", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->NutPot, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_JABU_JABUS_BELLY_MQ_MAP_CHEST, logic->BlastOrSmash()), - LOCATION(RC_JABU_JABUS_BELLY_MQ_FIRST_ROOM_SIDE_CHEST, logic->CanUse(RG_FAIRY_SLINGSHOT)), - LOCATION(RC_JABU_JABUS_BELLY_MQ_ENTRANCE_POT_1, logic->CanBreakPots()), - LOCATION(RC_JABU_JABUS_BELLY_MQ_ENTRANCE_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_JABU_JABUS_BELLY_ENTRYWAY, {[]{return true;}}), - Entrance(RR_JABU_JABUS_BELLY_MQ_LIFT_ROOM, {[]{return Here(RR_JABU_JABUS_BELLY_MQ_BEGINNING, []{return logic->CanUse(RG_FAIRY_SLINGSHOT);});}}), - }); - - areaTable[RR_JABU_JABUS_BELLY_MQ_LIFT_ROOM] = Region("Jabu Jabus Belly MQ Lift Room", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->MQJabuLiftRoomCow, {[]{return logic->CanUse(RG_FAIRY_SLINGSHOT);}}), - }, { - //Locations - LOCATION(RC_JABU_JABUS_BELLY_MQ_SECOND_ROOM_LOWER_CHEST, true), - LOCATION(RC_JABU_JABUS_BELLY_MQ_LIFT_HEART_1, true), - LOCATION(RC_JABU_JABUS_BELLY_MQ_LIFT_HEART_2, true), - LOCATION(RC_JABU_JABUS_BELLY_MQ_LIFT_RUPEE_1, logic->CanUse(RG_IRON_BOOTS)), - LOCATION(RC_JABU_JABUS_BELLY_MQ_LIFT_RUPEE_2, logic->CanUse(RG_IRON_BOOTS)), - LOCATION(RC_JABU_JABUS_BELLY_MQ_LIFT_RUPEE_3, logic->CanUse(RG_IRON_BOOTS)), - }, { - //Exits - Entrance(RR_JABU_JABUS_BELLY_MQ_BEGINNING, {[]{return true;}}), - Entrance(RR_JABU_JABUS_BELLY_MQ_UNDERWATER_ALCOVE, {[]{return logic->HasItem(RG_SILVER_SCALE) || (logic->HasItem(RG_BRONZE_SCALE) && ((logic->IsChild || logic->CanUse(RG_IRON_BOOTS) || ctx->GetTrickOption(RT_JABU_ALCOVE_JUMP_DIVE))));}}), - Entrance(RR_JABU_JABUS_BELLY_MQ_HOLES_ROOM, {[]{return logic->MQJabuHolesRoomDoor;}}), - Entrance(RR_JABU_JABUS_BELLY_MQ_LIFT_ROOM_EAST_LEDGE, {[]{return logic->LoweredJabuPath || logic->CanUse(RG_HOVER_BOOTS) || (logic->CanUse(RG_HOOKSHOT) && logic->MQJabuLiftRoomCow);}}), - //If opening RR_JABU_JABUS_BELLY_MQ_WATER_SWITCH_ROOM by lowering the geyser as 1 age is to let the other through is relevant, it needs an eventAccess - }); - - areaTable[RR_JABU_JABUS_BELLY_MQ_UNDERWATER_ALCOVE] = Region("Jabu Jabus Belly MQ Underwater Alcove", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->MQJabuHolesRoomDoor, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_JABU_JABUS_BELLY_MQ_COMPASS_CHEST, logic->CanHitSwitch(ED_HOOKSHOT, true) || (ctx->GetTrickOption(RT_JABU_MQ_RANG_JUMP) && logic->CanUse(RG_BOOMERANG) && logic->HasItem(RG_BRONZE_SCALE))), - LOCATION(RC_JABU_JABUS_BELLY_MQ_GEYSER_POT_1, logic->CanBreakPots()), - LOCATION(RC_JABU_JABUS_BELLY_MQ_GEYSER_POT_2, logic->CanBreakPots()), - //Getting the ones closest to the ledge with rang may be a trick due to the awkward angle without blind shooting through the flesh - LOCATION(RC_JABU_JABUS_BELLY_MQ_LIFT_RUPEE_1, logic->HasItem(RG_GOLDEN_SCALE) || logic->CanUse(RG_BOOMERANG)), - LOCATION(RC_JABU_JABUS_BELLY_MQ_LIFT_RUPEE_2, logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_BOOMERANG)), - LOCATION(RC_JABU_JABUS_BELLY_MQ_LIFT_RUPEE_3, logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_BOOMERANG)), - }, { - //Exits - Entrance(RR_JABU_JABUS_BELLY_MQ_LIFT_ROOM, {[]{return logic->HasItem(RG_BRONZE_SCALE);}}), - }); - - areaTable[RR_JABU_JABUS_BELLY_MQ_HOLES_ROOM] = Region("Jabu Jabus Belly MQ Holes Room", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_VINES_CHEST, logic->CanUse(RG_FAIRY_SLINGSHOT)), - LOCATION(RC_JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_SWITCHES_CHEST, logic->CanUse(RG_FAIRY_SLINGSHOT)), - }, { - //Exits - Entrance(RR_JABU_JABUS_BELLY_MQ_LIFT_ROOM, {[]{return true;}}), - Entrance(RR_JABU_JABUS_BELLY_MQ_WATER_SWITCH_ROOM, {[]{return true;}}), - Entrance(RR_JABU_JABUS_BELLY_MQ_FORKED_CORRIDOR, {[]{return logic->CanUse(RG_BOOMERANG) && logic->HasExplosives() && Here(RR_JABU_JABUS_BELLY_MQ_HOLES_ROOM, []{return logic->CanUse(RG_FAIRY_SLINGSHOT);});}}), - Entrance(RR_JABU_JABUS_BELLY_MQ_INVISIBLE_KEESE_ROOM, {[]{return logic->JabuNorthTentacle;}}), - Entrance(RR_JABU_JABUS_BELLY_MQ_PAST_OCTO, {[]{return logic->JabuWestTentacle && Here(RR_JABU_JABUS_BELLY_MQ_HOLES_ROOM, []{return logic->CanKillEnemy(RE_BIG_OCTO);}) && logic->CanUse(RG_FAIRY_SLINGSHOT);}}), - }); - - areaTable[RR_JABU_JABUS_BELLY_MQ_WATER_SWITCH_ROOM] = Region("Jabu Jabus Belly MQ Water Switch Room", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_JABU_JABUS_BELLY_MQ_BOOMERANG_ROOM_SMALL_CHEST, true), - //Implies logic->CanKillEnemy(RE_LIKE_LIKE) && logic->CanKillEnemy(RE_STINGER). Without swim, jump from the song of time block to the vines. - LOCATION(RC_JABU_JABUS_BELLY_MQ_BOOMERANG_CHEST, logic->CanKillEnemy(RE_LIZALFOS)), - LOCATION(RC_JABU_JABUS_BELLY_MQ_GS_BOOMERANG_CHEST_ROOM, (logic->CanUse(RG_SONG_OF_TIME) && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)) || (ctx->GetTrickOption(RT_JABU_MQ_SOT_GS) && logic->CanUse(RG_BOOMERANG))), - LOCATION(RC_JABU_JABUS_BELLY_MQ_TIME_BLOCK_POT_1, logic->CanBreakPots()), - LOCATION(RC_JABU_JABUS_BELLY_MQ_TIME_BLOCK_POT_2, logic->CanBreakPots()), - }, { - //Exits - //without swim, jump from rang chest to the other side - Entrance(RR_JABU_JABUS_BELLY_MQ_BEGINNING, {[]{return Here(RR_JABU_JABUS_BELLY_MQ_WATER_SWITCH_ROOM, []{return logic->CanKillEnemy(RE_LIZALFOS);});}}), - Entrance(RR_JABU_JABUS_BELLY_MQ_HOLES_ROOM, {[]{return (logic->IsAdult || logic->HasItem(RG_BRONZE_SCALE)) && Here(RR_JABU_JABUS_BELLY_MQ_WATER_SWITCH_ROOM, []{return logic->CanKillEnemy(RE_LIZALFOS);});}}), - }); - - //Includes Like Like room - areaTable[RR_JABU_JABUS_BELLY_MQ_FORKED_CORRIDOR] = Region("Jabu Jabus Belly MQ Forked Corridor", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->JabuNorthTentacle, {[]{return Here(RR_JABU_JABUS_BELLY_MQ_FORKED_CORRIDOR, []{return logic->BlastOrSmash();}) && logic->CanUse(RG_BOOMERANG);}}), - }, { - //Locations - //Implies CanKillEnemy(RE_LIKE_LIKE) - LOCATION(RC_JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_ROOM_CHEST, logic->CanUse(RG_FAIRY_SLINGSHOT)), - LOCATION(RC_JABU_JABUS_BELLY_MQ_LIKE_LIKES_POT_1, logic->CanBreakPots()), - LOCATION(RC_JABU_JABUS_BELLY_MQ_LIKE_LIKES_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_JABU_JABUS_BELLY_MQ_HOLES_ROOM, {[]{return logic->CanUse(RG_BOOMERANG);}}), - //If some mode lets an age use sticks and not sling, and other use sling and not sticks, this needs changing - Entrance(RR_JABU_JABUS_BELLY_MQ_WEST_FORKED_ROOMS, {[]{return Here(RR_JABU_JABUS_BELLY_MQ_FORKED_CORRIDOR, []{return logic->CanUse(RG_BOOMERANG);}) && - (Here(RR_JABU_JABUS_BELLY_MQ_FORKED_CORRIDOR, []{return logic->CanUse(RG_FAIRY_SLINGSHOT) && logic->CanUse(RG_STICKS);}) || - Here(RR_JABU_JABUS_BELLY_MQ_FORKED_CORRIDOR, []{return logic->HasFireSource();}));}}), - }); - - areaTable[RR_JABU_JABUS_BELLY_MQ_WEST_FORKED_ROOMS] = Region("Jabu Jabus Belly MQ West Forked Rooms", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->JabuWestTentacle, {[]{return logic->CanUse(RG_BOOMERANG);}}), - }, { - //Locations - LOCATION(RC_JABU_JABUS_BELLY_MQ_GS_TAILPASARAN_ROOM, Here(RR_JABU_JABUS_BELLY_MQ_WEST_FORKED_ROOMS, []{return logic->HasExplosives();}) && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)), - }, { - //Exits - Entrance(RR_JABU_JABUS_BELLY_MQ_FORKED_CORRIDOR, {[]{return true;}}), - }); - - areaTable[RR_JABU_JABUS_BELLY_MQ_INVISIBLE_KEESE_ROOM] = Region("Jabu Jabus Belly MQ Invisible Keese Room", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_JABU_JABUS_BELLY_MQ_GS_INVISIBLE_ENEMIES_ROOM, //firstly, we can just use FAs to clear the web and then longshot the skull - logic->CanUse(RG_FIRE_ARROWS) && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_LONGSHOT) || - //Otherwise, we we have to cross the gap and kill the skull. - (logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG) && - //We can cheese the gap with hovers - ((logic->CanUse(RG_HOVER_BOOTS) || - //Otherwise we have to kill the enemies to raise the platform. This persists so we can do it as the other age. - Here(RR_JABU_JABUS_BELLY_MQ_INVISIBLE_KEESE_ROOM, []{return (ctx->GetTrickOption(RT_LENS_JABU_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)) && - logic->CanKillEnemy(RE_STINGER, ED_BOOMERANG, false, 2, false, true) && - //we can hit the keese farthest from the water with irons and hookshot, but we won't be able to see it while doing so - (logic->CanKillEnemy(RE_KEESE, ED_LONGSHOT, false) || (ctx->GetTrickOption(RT_LENS_JABU_MQ) && logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_IRON_BOOTS)));})) - //If we kill the enemies, we then need to cross the water using the platform. Note that adult cannot do so while swimming because MQ jank. - && ((logic->IsChild && logic->HasItem(RG_BRONZE_SCALE)) || (logic->IsAdult && logic->CanUse(RG_IRON_BOOTS)))))), - }, { - //Exits - Entrance(RR_JABU_JABUS_BELLY_MQ_HOLES_ROOM, {[]{return (logic->JabuNorthTentacle || logic->TakeDamage()) && logic->HasItem(RG_BRONZE_SCALE);}}), - }); - - areaTable[RR_JABU_JABUS_BELLY_MQ_PAST_OCTO] = Region("Jabu Jabus Belly MQ Past Octo", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { - //Events - //if a hover up to the path is added, this will want it's own room - EventAccess(&logic->LoweredJabuPath, {[]{return logic->CanUse(RG_BOOMERANG) && logic->CanUse(RG_FAIRY_SLINGSHOT);}}), - }, { - //Locations - LOCATION(RC_JABU_JABUS_BELLY_MQ_COW, logic->CanUse(RG_EPONAS_SONG) && logic->CanUse(RG_FAIRY_SLINGSHOT)), - }, { - //Exits - Entrance(RR_JABU_JABUS_BELLY_MQ_LIFT_ROOM, {[]{return logic->CanUse(RG_BOOMERANG) && logic->CanUse(RG_FAIRY_SLINGSHOT);}}), - //you take both fall damage and tentacle damage, unless the tentacle is down. need better damage logic - Entrance(RR_JABU_JABUS_BELLY_MQ_HOLES_ROOM, {[]{return logic->TakeDamage() && Here(RR_JABU_JABUS_BELLY_MQ_PAST_OCTO, []{return logic->CanKillEnemy(RE_BIG_OCTO);});}}), - }); - - areaTable[RR_JABU_JABUS_BELLY_MQ_LIFT_ROOM_EAST_LEDGE] = Region("Jabu Jabus Belly MQ Lift Room East Ledge", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_JABU_JABUS_BELLY_MQ_SECOND_ROOM_UPPER_CHEST, logic->MQJabuLiftRoomCow), - }, { - //Exits - Entrance(RR_JABU_JABUS_BELLY_MQ_LIFT_ROOM, {[]{return true;}}), - Entrance(RR_JABU_JABUS_BELLY_MQ_EAST_ROOM, {[]{return logic->JabuNorthTentacle;}}), - }); - - areaTable[RR_JABU_JABUS_BELLY_MQ_EAST_ROOM] = Region("Jabu Jabus Belly MQ Boss Region", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->FairyPot, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_JABU_JABUS_BELLY_MQ_NEAR_BOSS_CHEST, logic->CanUse(RG_FAIRY_SLINGSHOT)), - LOCATION(RC_JABU_JABUS_BELLY_MQ_GS_NEAR_BOSS, logic->CanUse(RG_BOOMERANG) || (ctx->GetTrickOption(RT_JABU_NEAR_BOSS_RANGED) && logic->CanUse(RG_HOOKSHOT))), - LOCATION(RC_JABU_JABUS_BELLY_MQ_BEFORE_BOSS_POT_1, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_JABU_JABUS_BELLY_MQ_LIFT_ROOM_EAST_LEDGE, {[]{return true;}}), - Entrance(RR_JABU_JABUS_BELLY_BOSS_ENTRYWAY, {[]{return Here(RR_JABU_JABUS_BELLY_MQ_EAST_ROOM, []{return logic->CanUse(RG_FAIRY_SLINGSHOT);});}}), - }); - } - - /*--------------------------- - | BOSS ROOM | - ---------------------------*/ - areaTable[RR_JABU_JABUS_BELLY_BOSS_ENTRYWAY] = - Region("Jabu Jabus Belly Boss Entryway", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, {}, - { - // Exits - Entrance(RR_JABU_JABUS_BELLY_NEAR_BOSS_ROOM, { [] { return ctx->GetDungeon(JABU_JABUS_BELLY)->IsVanilla(); } }), - Entrance(RR_JABU_JABUS_BELLY_MQ_EAST_ROOM, { [] { return ctx->GetDungeon(JABU_JABUS_BELLY)->IsMQ(); } }), - Entrance(RR_JABU_JABUS_BELLY_BOSS_ROOM, { [] { return true; } }), - }); - - areaTable[RR_JABU_JABUS_BELLY_BOSS_ROOM] = - Region("Jabu Jabus Belly Boss Room", "Jabu Jabus Belly", {}, NO_DAY_NIGHT_CYCLE, - { - // Events //todo: add pot kill trick - EventAccess(&logic->JabuJabusBellyClear, - { [] { return logic->JabuJabusBellyClear || (logic->HasBossSoul(RG_BARINADE_SOUL) && (logic->CanUse(RG_BOOMERANG) && logic->CanJumpslashExceptHammer())); } }), - }, - { - // Locations - LOCATION(RC_JABU_JABUS_BELLY_BARINADE_POT_1, logic->CanBreakPots()), - LOCATION(RC_JABU_JABUS_BELLY_BARINADE_POT_2, logic->CanBreakPots()), - LOCATION(RC_JABU_JABUS_BELLY_BARINADE_POT_3, logic->CanBreakPots()), - LOCATION(RC_JABU_JABUS_BELLY_BARINADE_POT_4, logic->CanBreakPots()), - LOCATION(RC_JABU_JABUS_BELLY_BARINADE_POT_5, logic->CanBreakPots()), - LOCATION(RC_JABU_JABUS_BELLY_BARINADE_POT_6, logic->CanBreakPots()), - LOCATION(RC_JABU_JABUS_BELLY_BARINADE_HEART, logic->JabuJabusBellyClear), - LOCATION(RC_BARINADE, logic->JabuJabusBellyClear), - }, - { - // Exits - Entrance(RR_JABU_JABUS_BELLY_BOSS_ENTRYWAY, { [] { return false; } }), - Entrance(RR_ZORAS_FOUNTAIN, { [] { return logic->JabuJabusBellyClear; } }, false), - }); - -} diff --git a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_kakariko.cpp b/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_kakariko.cpp deleted file mode 100644 index 8d1b2a35a..000000000 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_kakariko.cpp +++ /dev/null @@ -1,359 +0,0 @@ -#include "../location_access.hpp" -#include "../../entrance.h" - -using namespace Rando; - -void RegionTable_Init_Kakariko() { - areaTable[RR_KAKARIKO_VILLAGE] = Region("Kakariko Village", "Kakariko Village", {RA_KAKARIKO_VILLAGE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->BugRock, {[]{return true;}}), - //Open Gate setting is applies in RR_ROOT - EventAccess(&logic->KakarikoVillageGateOpen, {[]{return logic->IsChild && logic->HasItem(RG_ZELDAS_LETTER);}}), - }, { - //Locations - LOCATION(RC_SHEIK_IN_KAKARIKO, logic->IsAdult && logic->HasItem(RG_FOREST_MEDALLION) && logic->HasItem(RG_FIRE_MEDALLION) && logic->HasItem(RG_WATER_MEDALLION)), - LOCATION(RC_KAK_ANJU_AS_CHILD, logic->IsChild && logic->AtDay), - LOCATION(RC_KAK_ANJU_AS_ADULT, logic->IsAdult && logic->AtDay), - LOCATION(RC_KAK_TRADE_POCKET_CUCCO, logic->IsAdult && logic->AtDay && (logic->CanUse(RG_POCKET_EGG) && logic->WakeUpAdultTalon)), - //Can kill lower kak skulls with pots - LOCATION(RC_KAK_GS_HOUSE_UNDER_CONSTRUCTION, logic->IsChild && logic->CanGetNightTimeGS()), - LOCATION(RC_KAK_GS_SKULLTULA_HOUSE, logic->IsChild && logic->CanGetNightTimeGS()), - LOCATION(RC_KAK_GS_GUARDS_HOUSE, logic->IsChild && logic->CanGetNightTimeGS()), - LOCATION(RC_KAK_GS_TREE, logic->IsChild && logic->CanGetNightTimeGS()), - LOCATION(RC_KAK_GS_WATCHTOWER, logic->IsChild && (logic->CanKillEnemy(RE_GOLD_SKULLTULA, ED_LONGSHOT) || (ctx->GetTrickOption(RT_KAK_TOWER_GS) && logic->CanJumpslashExceptHammer())) && logic->CanGetNightTimeGS()), - LOCATION(RC_KAK_NEAR_POTION_SHOP_POT_1, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_KAK_NEAR_POTION_SHOP_POT_2, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_KAK_NEAR_POTION_SHOP_POT_3, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_KAK_NEAR_IMPAS_HOUSE_POT_1, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_KAK_NEAR_IMPAS_HOUSE_POT_2, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_KAK_NEAR_IMPAS_HOUSE_POT_3, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_KAK_NEAR_GUARDS_HOUSE_POT_1, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_KAK_NEAR_GUARDS_HOUSE_POT_2, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_KAK_NEAR_GUARDS_HOUSE_POT_3, logic->IsChild && logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_HYRULE_FIELD, {[]{return true;}}), - Entrance(RR_KAK_CARPENTER_BOSS_HOUSE, {[]{return true;}}), - Entrance(RR_KAK_HOUSE_OF_SKULLTULA, {[]{return true;}}), - Entrance(RR_KAK_IMPAS_HOUSE, {[]{return true;}}), - Entrance(RR_KAK_WINDMILL, {[]{return true;}}), - Entrance(RR_KAK_BAZAAR, {[]{return logic->IsAdult && logic->AtDay;}}), - Entrance(RR_KAK_SHOOTING_GALLERY, {[]{return logic->IsAdult && logic->AtDay;}}), - Entrance(RR_KAK_WELL, {[]{return logic->IsAdult || logic->DrainWell || logic->CanUse(RG_IRON_BOOTS);}}), - Entrance(RR_KAK_POTION_SHOP_FRONT, {[]{return logic->AtDay || logic->IsChild;}}), - Entrance(RR_KAK_REDEAD_GROTTO, {[]{return logic->CanOpenBombGrotto();}}), - Entrance(RR_KAK_IMPAS_LEDGE, {[]{return (logic->IsChild && logic->AtDay) || (logic->IsAdult && ctx->GetTrickOption(RT_VISIBLE_COLLISION));}}), - Entrance(RR_KAK_WATCHTOWER, {[]{return logic->IsAdult || logic->AtDay || logic->CanKillEnemy(RE_GOLD_SKULLTULA, ED_LONGSHOT) || (ctx->GetTrickOption(RT_KAK_TOWER_GS) && logic->CanJumpslashExceptHammer());}}), - Entrance(RR_KAK_ROOFTOP, {[]{return logic->CanUse(RG_HOOKSHOT) || (ctx->GetTrickOption(RT_KAK_MAN_ON_ROOF) && logic->IsAdult);}}), - Entrance(RR_KAK_IMPAS_ROOFTOP, {[]{return logic->CanUse(RG_HOOKSHOT) || (ctx->GetTrickOption(RT_KAK_ROOFTOP_GS) && logic->CanUse(RG_HOVER_BOOTS));}}), - Entrance(RR_THE_GRAVEYARD, {[]{return true;}}), - Entrance(RR_KAK_BEHIND_GATE, {[]{return logic->IsAdult || logic->KakarikoVillageGateOpen;}}), - //adult can jump from the fence near the windmill to ledgegrab the fence near granny's shop. is in logic on N64 - Entrance(RR_KAK_BACKYARD, {[]{return logic->IsAdult || logic->AtDay;}}), - }); - - areaTable[RR_KAK_IMPAS_LEDGE] = Region("Kak Impas Ledge", "Kakariko Village", {RA_KAKARIKO_VILLAGE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_KAK_IMPAS_HOUSE_BACK, {[]{return true;}}), - Entrance(RR_KAKARIKO_VILLAGE, {[]{return true;}}), - }); - - areaTable[RR_KAK_IMPAS_ROOFTOP] = Region("Kak Impas Rooftop", "Kakariko Village", {RA_KAKARIKO_VILLAGE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_KAK_GS_ABOVE_IMPAS_HOUSE, logic->IsAdult && logic->CanGetNightTimeGS() && logic->CanKillEnemy(RE_GOLD_SKULLTULA)), - }, { - //Exits - Entrance(RR_KAK_IMPAS_LEDGE, {[]{return true;}}), - Entrance(RR_KAKARIKO_VILLAGE, {[]{return true;}}), - }); - - areaTable[RR_KAK_WATCHTOWER] = Region("Kak Watchtower", "Kakariko Village", {RA_KAKARIKO_VILLAGE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - //exists for when age change is in logic. - LOCATION(RC_KAK_GS_WATCHTOWER, logic->IsChild && logic->CanUse(RG_DINS_FIRE) && logic->CanGetNightTimeGS()), - }, { - //Exits - Entrance(RR_KAKARIKO_VILLAGE, {[]{return true;}}), - Entrance(RR_KAK_ROOFTOP, {[]{return ctx->GetTrickOption(RT_KAK_MAN_ON_ROOF) && logic->IsChild;}}), - }); - - areaTable[RR_KAK_ROOFTOP] = Region("Kak Rooftop", "Kakariko Village", {RA_KAKARIKO_VILLAGE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_KAK_MAN_ON_ROOF, true), - }, { - //Exits - Entrance(RR_KAK_BACKYARD, {[]{return true;}}), - Entrance(RR_KAKARIKO_VILLAGE, {[]{return true;}}), - }); - - areaTable[RR_KAK_BACKYARD] = Region("Kak Backyard", "Kakariko Village", {RA_KAKARIKO_VILLAGE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - //There's probably a trick to get these with rang from the main region - LOCATION(RC_KAK_NEAR_MEDICINE_SHOP_POT_1, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_KAK_NEAR_MEDICINE_SHOP_POT_2, logic->IsChild && logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_KAKARIKO_VILLAGE, {[]{return true;}}), - Entrance(RR_KAK_OPEN_GROTTO, {[]{return true;}}), - Entrance(RR_KAK_ODD_POTION_BUILDING, {[]{return logic->IsAdult;}}), - Entrance(RR_KAK_POTION_SHOP_BACK, {[]{return logic->IsAdult && logic->AtDay;}}), - }); - - areaTable[RR_KAK_CARPENTER_BOSS_HOUSE] = Region("Kak Carpenter Boss House", "Kak Carpenter Boss House", {}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->WakeUpAdultTalon, {[]{return logic->IsAdult && logic->CanUse(RG_POCKET_EGG);}}), - }, {}, { - //Exits - Entrance(RR_KAKARIKO_VILLAGE, {[]{return true;}}), - }); - - areaTable[RR_KAK_HOUSE_OF_SKULLTULA] = Region("Kak House of Skulltula", "Kak House of Skulltula", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_KAK_10_GOLD_SKULLTULA_REWARD, logic->GetGSCount() >= 10), - LOCATION(RC_KAK_20_GOLD_SKULLTULA_REWARD, logic->GetGSCount() >= 20), - LOCATION(RC_KAK_30_GOLD_SKULLTULA_REWARD, logic->GetGSCount() >= 30), - LOCATION(RC_KAK_40_GOLD_SKULLTULA_REWARD, logic->GetGSCount() >= 40), - LOCATION(RC_KAK_50_GOLD_SKULLTULA_REWARD, logic->GetGSCount() >= 50), - LOCATION(RC_KAK_100_GOLD_SKULLTULA_REWARD, logic->GetGSCount() >= 100) - }, { - //Exits - Entrance(RR_KAKARIKO_VILLAGE, {[]{return true;}}), - }); - - areaTable[RR_KAK_IMPAS_HOUSE] = Region("Kak Impas House", "Kak Impas House", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_KAK_IMPAS_HOUSE_COW, logic->CanUse(RG_EPONAS_SONG)) - }, { - //Exits - Entrance(RR_KAKARIKO_VILLAGE, {[]{return true;}}), - }); - - areaTable[RR_KAK_IMPAS_HOUSE_BACK] = Region("Kak Impas House Back", "Kak Impas House", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_KAK_IMPAS_HOUSE_FREESTANDING_POH, true), - LOCATION(RC_KAK_IMPAS_HOUSE_COW, logic->CanUse(RG_EPONAS_SONG)) - }, { - //Exits - Entrance(RR_KAK_IMPAS_LEDGE, {[]{return true;}}), - }); - - areaTable[RR_KAK_WINDMILL] = Region("Kak Windmill", "Windmill and Dampes Grave", {}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->DrainWell, {[]{return logic->DrainWell || (logic->IsChild && logic->CanUse(RG_SONG_OF_STORMS));}}), - }, { - //Locations - LOCATION(RC_KAK_WINDMILL_FREESTANDING_POH, logic->CanUse(RG_BOOMERANG) || logic->DampesWindmillAccess || (logic->IsAdult && ctx->GetTrickOption(RT_KAK_ADULT_WINDMILL_POH)) || (logic->IsChild && logic->CanJumpslashExceptHammer() && ctx->GetTrickOption(RT_KAK_CHILD_WINDMILL_POH))), - LOCATION(RC_SONG_FROM_WINDMILL, logic->IsAdult && logic->HasItem(RG_FAIRY_OCARINA)), - }, { - //Exits - Entrance(RR_KAKARIKO_VILLAGE, {[]{return true;}}), - }); - - areaTable[RR_KAK_BAZAAR] = Region("Kak Bazaar", "Kak Bazaar", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_KAK_BAZAAR_ITEM_1, true), - LOCATION(RC_KAK_BAZAAR_ITEM_2, true), - LOCATION(RC_KAK_BAZAAR_ITEM_3, true), - LOCATION(RC_KAK_BAZAAR_ITEM_4, true), - LOCATION(RC_KAK_BAZAAR_ITEM_5, true), - LOCATION(RC_KAK_BAZAAR_ITEM_6, true), - LOCATION(RC_KAK_BAZAAR_ITEM_7, true), - LOCATION(RC_KAK_BAZAAR_ITEM_8, true), - }, { - //Exits - Entrance(RR_KAKARIKO_VILLAGE, {[]{return true;}}), - }); - - areaTable[RR_KAK_SHOOTING_GALLERY] = Region("Kak Shooting Gallery", "Kak Shooting Gallery", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_KAK_SHOOTING_GALLERY_REWARD, logic->HasItem(RG_CHILD_WALLET) && logic->IsAdult && logic->CanUse(RG_FAIRY_BOW)), - }, { - //Exits - Entrance(RR_KAKARIKO_VILLAGE, {[]{return true;}}), - }); - - areaTable[RR_KAK_POTION_SHOP_FRONT] = Region("Kak Potion Shop Front", "Kak Potion Shop", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_KAK_POTION_SHOP_ITEM_1, logic->IsAdult), - LOCATION(RC_KAK_POTION_SHOP_ITEM_2, logic->IsAdult), - LOCATION(RC_KAK_POTION_SHOP_ITEM_3, logic->IsAdult), - LOCATION(RC_KAK_POTION_SHOP_ITEM_4, logic->IsAdult), - LOCATION(RC_KAK_POTION_SHOP_ITEM_5, logic->IsAdult), - LOCATION(RC_KAK_POTION_SHOP_ITEM_6, logic->IsAdult), - LOCATION(RC_KAK_POTION_SHOP_ITEM_7, logic->IsAdult), - LOCATION(RC_KAK_POTION_SHOP_ITEM_8, logic->IsAdult), - }, { - //Exits - Entrance(RR_KAKARIKO_VILLAGE, {[]{return true;}}), - Entrance(RR_KAK_POTION_SHOP_BACK, {[]{return logic->IsAdult;}}), - }); - - areaTable[RR_KAK_POTION_SHOP_BACK] = Region("Kak Potion Shop Back", "Kak Potion Shop", {}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_KAK_BACKYARD, {[]{return logic->IsAdult;}}), - Entrance(RR_KAK_POTION_SHOP_FRONT, {[]{return true;}}), - }); - - areaTable[RR_KAK_ODD_POTION_BUILDING] = - Region("Kak Granny's Potion Shop", "Kak Granny's Potion Shop", {}, NO_DAY_NIGHT_CYCLE, {}, - // RANDOTODO blue pot access - { - LOCATION(RC_KAK_TRADE_ODD_MUSHROOM, logic->IsAdult && logic->CanUse(RG_ODD_MUSHROOM)), - LOCATION(RC_KAK_GRANNYS_SHOP, logic->IsAdult && (logic->CanUse(RG_ODD_MUSHROOM) || logic->TradeQuestStep(RG_ODD_MUSHROOM))), - }, - { - // Exits - Entrance(RR_KAK_BACKYARD, { [] { return true; } }), - }); - - areaTable[RR_KAK_REDEAD_GROTTO] = Region("Kak Redead Grotto", "Kak Redead Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_KAK_REDEAD_GROTTO_CHEST, logic->CanKillEnemy(RE_REDEAD)), - }, { - //Exits - Entrance(RR_KAKARIKO_VILLAGE, {[]{return true;}}), - }); - - areaTable[RR_KAK_OPEN_GROTTO] = Region("Kak Open Grotto", "Kak Open Grotto", {}, NO_DAY_NIGHT_CYCLE, grottoEvents, { - //Locations - LOCATION(RC_KAK_OPEN_GROTTO_CHEST, true), - LOCATION(RC_KAK_OPEN_GROTTO_FISH, logic->HasBottle()), - LOCATION(RC_KAK_OPEN_GROTTO_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), - LOCATION(RC_KAK_OPEN_GROTTO_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_KAK_OPEN_GROTTO_GOSSIP_STONE, true), - LOCATION(RC_KAK_OPEN_GROTTO_BEEHIVE_LEFT, logic->CanBreakLowerBeehives()), - LOCATION(RC_KAK_OPEN_GROTTO_BEEHIVE_RIGHT, logic->CanBreakLowerBeehives()), - }, { - //Exits - Entrance(RR_KAK_BACKYARD, {[]{return true;}}), - }); - - areaTable[RR_KAK_BEHIND_GATE] = Region("Kak Behind Gate", "Kakariko Village", {RA_KAKARIKO_VILLAGE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_KAKARIKO_VILLAGE, {[]{return logic->IsAdult || ctx->GetTrickOption(RT_VISIBLE_COLLISION) || logic->KakarikoVillageGateOpen;}}), - Entrance(RR_DEATH_MOUNTAIN_TRAIL, {[]{return true;}}), - }); - - areaTable[RR_KAK_WELL] = Region("Kak Behind Gate", "Kakariko Village", {RA_KAKARIKO_VILLAGE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_KAKARIKO_VILLAGE, {[]{return logic->IsAdult || logic->HasItem(RG_BRONZE_SCALE) || logic->DrainWell;}}), - Entrance(RR_BOTTOM_OF_THE_WELL_ENTRYWAY, {[]{return logic->IsChild || (logic->DrainWell && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).IsNot(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF));}}), - }); - - areaTable[RR_THE_GRAVEYARD] = Region("The Graveyard", "The Graveyard", {RA_THE_GRAVEYARD}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->ButterflyFairy, {[]{return logic->ButterflyFairy || (logic->CanUse(RG_STICKS) && logic->AtDay);}}), - EventAccess(&logic->BeanPlantFairy, {[]{return logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS);}}), - EventAccess(&logic->BugRock, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_GRAVEYARD_FREESTANDING_POH, (logic->IsAdult && CanPlantBean(RR_THE_GRAVEYARD)) || logic->CanUse(RG_LONGSHOT) || (ctx->GetTrickOption(RT_GY_POH) && logic->CanUse(RG_BOOMERANG))), - LOCATION(RC_GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR, logic->HasItem(RG_CHILD_WALLET) && logic->IsChild && logic->AtNight), //TODO: This needs to change - LOCATION(RC_GRAVEYARD_GS_WALL, logic->IsChild && logic->HookshotOrBoomerang() && logic->CanGetNightTimeGS()), - LOCATION(RC_GRAVEYARD_GS_BEAN_PATCH, logic->CanSpawnSoilSkull() && logic->CanAttack()), - LOCATION(RC_GRAVEYARD_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_GRAVEYARD_BEAN_SPROUT_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_GRAVEYARD_BEAN_SPROUT_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), - }, { - //Exits - Entrance(RR_GRAVEYARD_SHIELD_GRAVE, {[]{return logic->IsAdult || logic->AtNight;}}), - Entrance(RR_GRAVEYARD_COMPOSERS_GRAVE, {[]{return logic->CanUse(RG_ZELDAS_LULLABY);}}), - Entrance(RR_GRAVEYARD_HEART_PIECE_GRAVE, {[]{return logic->IsAdult || logic->AtNight;}}), - Entrance(RR_GRAVEYARD_DAMPES_GRAVE, {[]{return logic->IsAdult;}}), - Entrance(RR_GRAVEYARD_DAMPES_HOUSE, {[]{return logic->IsAdult /*|| logic->AtDampeTime*/;}}), //TODO: This needs to be handled in ToD rework - Entrance(RR_KAKARIKO_VILLAGE, {[]{return true;}}), - Entrance(RR_GRAVEYARD_WARP_PAD_REGION, {[]{return false;}}), - }); - - areaTable[RR_GRAVEYARD_SHIELD_GRAVE] = Region("Graveyard Shield Grave", "Graveyard Shield Grave", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GRAVEYARD_SHIELD_GRAVE_CHEST, true), - }, { - //Exits - Entrance(RR_THE_GRAVEYARD, {[]{return true;}}), - Entrance(RR_GRAVEYARD_SHIELD_GRAVE_BACK, {[]{return Here(RR_GRAVEYARD_SHIELD_GRAVE, []{return logic->CanBreakMudWalls();});}}), - }); - - areaTable[RR_GRAVEYARD_SHIELD_GRAVE_BACK] = Region("Graveyard Shield Grave Back", "Graveyard Shield Grave", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GRAVEYARD_SHIELD_GRAVE_FAIRY_1, true), - LOCATION(RC_GRAVEYARD_SHIELD_GRAVE_FAIRY_2, true), - LOCATION(RC_GRAVEYARD_SHIELD_GRAVE_FAIRY_3, true), - LOCATION(RC_GRAVEYARD_SHIELD_GRAVE_FAIRY_4, true), - LOCATION(RC_GRAVEYARD_SHIELD_GRAVE_FAIRY_5, true), - LOCATION(RC_GRAVEYARD_SHIELD_GRAVE_FAIRY_6, true), - LOCATION(RC_GRAVEYARD_SHIELD_GRAVE_FAIRY_7, true), - LOCATION(RC_GRAVEYARD_SHIELD_GRAVE_FAIRY_8, true), - }, { - //Exits - Entrance(RR_THE_GRAVEYARD, {[]{return true;}}), - }); - - areaTable[RR_GRAVEYARD_HEART_PIECE_GRAVE] = Region("Graveyard Heart Piece Grave", "Graveyard Heart Piece Grave", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GRAVEYARD_HEART_PIECE_GRAVE_CHEST, logic->CanUse(RG_SUNS_SONG)), - }, { - //Exits - Entrance(RR_THE_GRAVEYARD, {[]{return true;}}), - }); - - areaTable[RR_GRAVEYARD_COMPOSERS_GRAVE] = Region("Graveyard Composers Grave", "Graveyard Composers Grave", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_GRAVEYARD_ROYAL_FAMILYS_TOMB_CHEST, logic->HasFireSource()), - LOCATION(RC_SONG_FROM_ROYAL_FAMILYS_TOMB, logic->CanUseProjectile() || logic->CanJumpslash()), - }, { - //Exits - Entrance(RR_THE_GRAVEYARD, {[]{return true;}}), - }); - - areaTable[RR_GRAVEYARD_DAMPES_GRAVE] = Region("Graveyard Dampes Grave", "Windmill and Dampes Grave", {}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->NutPot, {[]{return true;}}), - EventAccess(&logic->DampesWindmillAccess, {[]{return logic->DampesWindmillAccess || (logic->IsAdult && logic->CanUse(RG_SONG_OF_TIME));}}), - }, { - //Locations - LOCATION(RC_GRAVEYARD_HOOKSHOT_CHEST, true), - LOCATION(RC_GRAVEYARD_DAMPE_RACE_FREESTANDING_POH, logic->IsAdult || ctx->GetTrickOption(RT_GY_CHILD_DAMPE_RACE_POH)), - LOCATION(RC_GY_DAMPES_GRAVE_POT_1, logic->CanBreakPots()), - LOCATION(RC_GY_DAMPES_GRAVE_POT_2, logic->CanBreakPots()), - LOCATION(RC_GY_DAMPES_GRAVE_POT_3, logic->CanBreakPots()), - LOCATION(RC_GY_DAMPES_GRAVE_POT_4, logic->CanBreakPots()), - LOCATION(RC_GY_DAMPES_GRAVE_POT_5, logic->CanBreakPots()), - LOCATION(RC_GY_DAMPES_GRAVE_POT_6, logic->CanBreakPots()), - LOCATION(RC_GRAVEYARD_DAMPE_RACE_RUPEE_1, true), - LOCATION(RC_GRAVEYARD_DAMPE_RACE_RUPEE_2, true), - LOCATION(RC_GRAVEYARD_DAMPE_RACE_RUPEE_3, true), - LOCATION(RC_GRAVEYARD_DAMPE_RACE_RUPEE_4, true), - LOCATION(RC_GRAVEYARD_DAMPE_RACE_RUPEE_5, true), - LOCATION(RC_GRAVEYARD_DAMPE_RACE_RUPEE_6, true), - LOCATION(RC_GRAVEYARD_DAMPE_RACE_RUPEE_7, true), - LOCATION(RC_GRAVEYARD_DAMPE_RACE_RUPEE_8, true), - }, { - //Exits - Entrance(RR_THE_GRAVEYARD, {[]{return true;}}), - Entrance(RR_KAK_WINDMILL, {[]{return logic->IsAdult && logic->CanUse(RG_SONG_OF_TIME);}}, false), - }); - - areaTable[RR_GRAVEYARD_DAMPES_HOUSE] = Region("Graveyard Dampes House", "Graveyard Dampes House", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DAMPE_HINT, logic->IsAdult), - }, { - //Exits - Entrance(RR_THE_GRAVEYARD, {[]{return true;}}), - }); - - areaTable[RR_GRAVEYARD_WARP_PAD_REGION] = Region("Graveyard Warp Pad Region", "Graveyard", {RA_THE_GRAVEYARD}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->GossipStoneFairy, {[]{return logic->CallGossipFairyExceptSuns();}}), - }, { - //Locations - LOCATION(RC_GRAVEYARD_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns()), - LOCATION(RC_GRAVEYARD_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_GRAVEYARD_GOSSIP_STONE, true), - }, { - //Exits - Entrance(RR_THE_GRAVEYARD, {[]{return true;}}), - Entrance(RR_SHADOW_TEMPLE_ENTRYWAY, {[]{return logic->CanUse(RG_DINS_FIRE) || (ctx->GetTrickOption(RT_GY_SHADOW_FIRE_ARROWS) && logic->IsAdult && logic->CanUse(RG_FIRE_ARROWS));}}), - }); - -} 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 deleted file mode 100644 index e81e03505..000000000 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_lost_woods.cpp +++ /dev/null @@ -1,344 +0,0 @@ -#include "../location_access.hpp" -#include "../../entrance.h" - -using namespace Rando; - -void RegionTable_Init_LostWoods() { - areaTable[RR_KOKIRI_FOREST] = Region("Kokiri Forest", "Kokiri Forest", {RA_KOKIRI_FOREST}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->BeanPlantFairy, {[]{return logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS);}}), - EventAccess(&logic->GossipStoneFairy, {[]{return logic->CallGossipFairyExceptSuns();}}), - EventAccess(&logic->ShowedMidoSwordAndShield, {[]{return logic->ShowedMidoSwordAndShield || (logic->IsChild && logic->CanUse(RG_KOKIRI_SWORD) && logic->CanUse(RG_DEKU_SHIELD));}}), - }, { - //Locations - LOCATION(RC_KF_KOKIRI_SWORD_CHEST, logic->IsChild), - LOCATION(RC_KF_GS_KNOW_IT_ALL_HOUSE, logic->IsChild && logic->CanAttack() && (/*TODO: HasNightStart ||*/ logic->CanLeaveForest() || logic->CanUse(RG_SUNS_SONG)) && logic->CanGetNightTimeGS()), - LOCATION(RC_KF_GS_BEAN_PATCH, logic->CanSpawnSoilSkull() && logic->CanAttack()), - LOCATION(RC_KF_GS_HOUSE_OF_TWINS, logic->IsAdult && (logic->HookshotOrBoomerang() || (ctx->GetTrickOption(RT_KF_ADULT_GS) && logic->CanUse(RG_HOVER_BOOTS))) && logic->CanGetNightTimeGS()), - LOCATION(RC_KF_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_KF_BEAN_SPROUT_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_KF_BEAN_SPROUT_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_KF_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns()), - LOCATION(RC_KF_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_KF_BRIDGE_RUPEE, logic->IsChild), - LOCATION(RC_KF_BEHIND_MIDOS_RUPEE, logic->IsChild), - LOCATION(RC_KF_SOUTH_GRASS_WEST_RUPEE, logic->IsChild), - LOCATION(RC_KF_SOUTH_GRASS_EAST_RUPEE, logic->IsChild), - LOCATION(RC_KF_NORTH_GRASS_WEST_RUPEE, logic->IsChild), - LOCATION(RC_KF_NORTH_GRASS_EAST_RUPEE, logic->IsChild), - LOCATION(RC_KF_BOULDER_RUPEE_1, logic->IsChild), - LOCATION(RC_KF_BOULDER_RUPEE_2, logic->IsChild), - LOCATION(RC_KF_BEAN_RUPEE_1, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))), - LOCATION(RC_KF_BEAN_RUPEE_2, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))), - LOCATION(RC_KF_BEAN_RUPEE_3, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))), - LOCATION(RC_KF_BEAN_RUPEE_4, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))), - LOCATION(RC_KF_BEAN_RUPEE_5, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))), - LOCATION(RC_KF_BEAN_RUPEE_6, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))), - LOCATION(RC_KF_BEAN_RED_RUPEE, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))), - LOCATION(RC_KF_SARIAS_ROOF_WEST_HEART, logic->IsChild), - LOCATION(RC_KF_SARIAS_ROOF_EAST_HEART, logic->IsChild), - LOCATION(RC_KF_SARIAS_ROOF_NORTH_HEART, logic->IsChild), - LOCATION(RC_KF_GOSSIP_STONE, true), - }, { - //Exits - Entrance(RR_KF_LINKS_HOUSE, {[]{return true;}}), - Entrance(RR_KF_MIDOS_HOUSE, {[]{return true;}}), - Entrance(RR_KF_SARIAS_HOUSE, {[]{return true;}}), - Entrance(RR_KF_HOUSE_OF_TWINS, {[]{return true;}}), - Entrance(RR_KF_KNOW_IT_ALL_HOUSE, {[]{return true;}}), - Entrance(RR_KF_KOKIRI_SHOP, {[]{return true;}}), - Entrance(RR_KF_OUTSIDE_DEKU_TREE, {[]{return (logic->IsAdult && (logic->CanPassEnemy(RE_BIG_SKULLTULA) || logic->ForestTempleClear)) || ctx->GetOption(RSK_FOREST).Is(RO_CLOSED_FOREST_OFF) || logic->ShowedMidoSwordAndShield;}}), - Entrance(RR_THE_LOST_WOODS, {[]{return true;}}), - Entrance(RR_LW_BRIDGE_FROM_FOREST, {[]{return logic->IsAdult || ctx->GetOption(RSK_FOREST).IsNot(RO_CLOSED_FOREST_ON) || logic->DekuTreeClear;}}), - Entrance(RR_KF_STORMS_GROTTO, {[]{return logic->CanOpenStormsGrotto();}}), - }); - - areaTable[RR_KF_OUTSIDE_DEKU_TREE] = Region("KF Outside Deku Tree", "Kokiri Forest", {RA_KOKIRI_FOREST}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->DekuBabaSticks, {[]{return logic->CanKillEnemy(RE_WITHERED_DEKU_BABA);}}), - EventAccess(&logic->DekuBabaNuts, {[]{return logic->CanGetDekuBabaNuts();}}), - EventAccess(&logic->ShowedMidoSwordAndShield, {[]{return logic->ShowedMidoSwordAndShield || (logic->IsChild && logic->CanUse(RG_KOKIRI_SWORD) && logic->CanUse(RG_DEKU_SHIELD));}}), - }, { - //Locations - LOCATION(RC_KF_DEKU_TREE_LEFT_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns()), - LOCATION(RC_KF_DEKU_TREE_LEFT_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_KF_DEKU_TREE_RIGHT_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns()), - LOCATION(RC_KF_DEKU_TREE_RIGHT_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_KF_DEKU_TREE_LEFT_GOSSIP_STONE, true), - LOCATION(RC_KF_DEKU_TREE_RIGHT_GOSSIP_STONE, true), - }, { - //Exits - Entrance(RR_DEKU_TREE_ENTRYWAY, {[]{return logic->IsChild || (ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).IsNot(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF) && (ctx->GetOption(RSK_FOREST).Is(RO_CLOSED_FOREST_OFF) || logic->ShowedMidoSwordAndShield));}}), - Entrance(RR_KOKIRI_FOREST, {[]{return (logic->IsAdult && (logic->CanPassEnemy(RE_BIG_SKULLTULA) || logic->ForestTempleClear)) || ctx->GetOption(RSK_FOREST).Is(RO_CLOSED_FOREST_OFF) || logic->ShowedMidoSwordAndShield;}}), - }); - - areaTable[RR_KF_LINKS_HOUSE] = Region("KF Link's House", "KF Link's House", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_KF_LINKS_HOUSE_COW, logic->IsAdult && logic->CanUse(RG_EPONAS_SONG) && logic->LinksCow), - LOCATION(RC_KF_LINKS_HOUSE_POT, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_KOKIRI_FOREST, {[]{return true;}}) - }); - - areaTable[RR_KF_MIDOS_HOUSE] = Region("KF Mido's House", "KF Mido's House", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_KF_MIDOS_TOP_LEFT_CHEST, true), - LOCATION(RC_KF_MIDOS_TOP_RIGHT_CHEST, true), - LOCATION(RC_KF_MIDOS_BOTTOM_LEFT_CHEST, true), - LOCATION(RC_KF_MIDOS_BOTTOM_RIGHT_CHEST, true), - }, { - //Exits - Entrance(RR_KOKIRI_FOREST, {[]{return true;}}), - }); - - areaTable[RR_KF_SARIAS_HOUSE] = Region("KF Saria's House", "KF Saria's House", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_KF_SARIAS_TOP_LEFT_HEART, true), - LOCATION(RC_KF_SARIAS_TOP_RIGHT_HEART, true), - LOCATION(RC_KF_SARIAS_BOTTOM_LEFT_HEART, true), - LOCATION(RC_KF_SARIAS_BOTTOM_RIGHT_HEART, true), - }, { - //Exits - Entrance(RR_KOKIRI_FOREST, {[]{return true;}}), - }); - - areaTable[RR_KF_HOUSE_OF_TWINS] = Region("KF House of Twins", "KF House of Twins", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_KF_TWINS_HOUSE_POT_1, logic->CanBreakPots()), - LOCATION(RC_KF_TWINS_HOUSE_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_KOKIRI_FOREST, {[]{return true;}}), - }); - - areaTable[RR_KF_KNOW_IT_ALL_HOUSE] = Region("KF Know It All House", "KF Know It All House", {}, NO_DAY_NIGHT_CYCLE, {}, { - // Locations - LOCATION(RC_KF_BROTHERS_HOUSE_POT_1, logic->CanBreakPots()), - LOCATION(RC_KF_BROTHERS_HOUSE_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_KOKIRI_FOREST, {[]{return true;}}), - }); - - areaTable[RR_KF_KOKIRI_SHOP] = Region("KF Kokiri Shop", "KF Kokiri Shop", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_KF_SHOP_ITEM_1, true), - LOCATION(RC_KF_SHOP_ITEM_2, true), - LOCATION(RC_KF_SHOP_ITEM_3, true), - LOCATION(RC_KF_SHOP_ITEM_4, true), - LOCATION(RC_KF_SHOP_ITEM_5, true), - LOCATION(RC_KF_SHOP_ITEM_6, true), - LOCATION(RC_KF_SHOP_ITEM_7, true), - LOCATION(RC_KF_SHOP_ITEM_8, true), - }, { - //Exits - Entrance(RR_KOKIRI_FOREST, {[]{return true;}}), - }); - - areaTable[RR_KF_STORMS_GROTTO] = Region("KF Storms Grotto", "KF Storms Grotto", {}, NO_DAY_NIGHT_CYCLE, grottoEvents, { - //Locations - LOCATION(RC_KF_STORMS_GROTTO_CHEST, true), - LOCATION(RC_KF_STORMS_GROTTO_FISH, logic->HasBottle()), - LOCATION(RC_KF_STORMS_GROTTO_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), - LOCATION(RC_KF_STORMS_GROTTO_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_KF_STORMS_GROTTO_GOSSIP_STONE, true), - LOCATION(RC_KF_STORMS_GROTTO_BEEHIVE_LEFT, logic->CanBreakLowerBeehives()), - LOCATION(RC_KF_STORMS_GROTTO_BEEHIVE_RIGHT, logic->CanBreakLowerBeehives()), - }, { - //Exits - Entrance(RR_KOKIRI_FOREST, {[]{return true;}}) - }); - - areaTable[RR_LW_FOREST_EXIT] = Region("LW Forest Exit", "Lost Woods", {RA_THE_LOST_WOODS}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_KOKIRI_FOREST, {[]{return true;}}) - }); - - areaTable[RR_THE_LOST_WOODS] = Region("Lost Woods", "Lost Woods", {RA_THE_LOST_WOODS}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->GossipStoneFairy, {[]{return logic->CallGossipFairyExceptSuns();}}), - EventAccess(&logic->BeanPlantFairy, {[]{return logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS);}}), - EventAccess(&logic->BugShrub, {[]{return logic->IsChild && logic->CanCutShrubs();}}), - }, { - //Locations - LOCATION(RC_LW_SKULL_KID, logic->IsChild && logic->CanUse(RG_SARIAS_SONG)), - LOCATION(RC_LW_TRADE_COJIRO, logic->IsAdult && logic->CanUse(RG_COJIRO)), - //I cannot think of a case where you can use Odd pot but not Cojiro to reset the quadrant should you have both. If one exists, add it to logic - LOCATION(RC_LW_TRADE_ODD_POTION, logic->IsAdult && logic->CanUse(RG_ODD_POTION)), - //all 5 buttons are logically required for memory game - //because the chances of being able to beat it - //every time you attempt it are as follows: - //0 or 1 button(s) => 0% - //2 buttons => 0.15625% - //3 buttons => 3.75% - //4 buttons => 25.3125% - //5 buttons => 100% - LOCATION(RC_LW_OCARINA_MEMORY_GAME, logic->IsChild && logic->HasItem(RG_FAIRY_OCARINA) && logic->OcarinaButtons() >= 5), - LOCATION(RC_LW_TARGET_IN_WOODS, logic->IsChild && logic->CanUse(RG_FAIRY_SLINGSHOT)), - LOCATION(RC_LW_DEKU_SCRUB_NEAR_BRIDGE, logic->IsChild && logic->CanStunDeku()), - LOCATION(RC_LW_GS_BEAN_PATCH_NEAR_BRIDGE, logic->CanSpawnSoilSkull() && logic->CanAttack()), - //RANDOTODO handle collecting some of these as you leave the shortcut from the other side - LOCATION(RC_LW_SHORTCUT_RUPEE_1, logic->IsChild && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS))), - LOCATION(RC_LW_SHORTCUT_RUPEE_2, logic->IsChild && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS))), - LOCATION(RC_LW_SHORTCUT_RUPEE_3, logic->IsChild && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS))), - LOCATION(RC_LW_SHORTCUT_RUPEE_4, logic->IsChild && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS))), - LOCATION(RC_LW_SHORTCUT_RUPEE_5, logic->IsChild && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS))), - LOCATION(RC_LW_SHORTCUT_RUPEE_6, logic->IsChild && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS))), - LOCATION(RC_LW_SHORTCUT_RUPEE_7, logic->IsChild && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS))), - LOCATION(RC_LW_SHORTCUT_RUPEE_8, logic->IsChild && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS))), - LOCATION(RC_LW_BEAN_SPROUT_NEAR_BRIDGE_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_LW_BEAN_SPROUT_NEAR_BRIDGE_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_LW_BEAN_SPROUT_NEAR_BRIDGE_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_LW_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns()), - LOCATION(RC_LW_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_LW_SHORTCUT_STORMS_FAIRY, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_LW_GOSSIP_STONE, true), - }, { - //Exits - Entrance(RR_LW_FOREST_EXIT, {[]{return true;}}), - Entrance(RR_GC_WOODS_WARP, {[]{return true;}}), - Entrance(RR_LW_BRIDGE, {[]{return logic->CanLeaveForest() && ((logic->IsAdult && (CanPlantBean(RR_THE_LOST_WOODS) || ctx->GetTrickOption(RT_LW_BRIDGE))) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_LONGSHOT));}}), - Entrance(RR_ZORAS_RIVER, {[]{return logic->CanLeaveForest() && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS));}}), - Entrance(RR_LW_BEYOND_MIDO, {[]{return logic->IsChild || logic->CanUse(RG_SARIAS_SONG) || ctx->GetTrickOption(RT_LW_MIDO_BACKFLIP);}}), - Entrance(RR_LW_NEAR_SHORTCUTS_GROTTO, {[]{return Here(RR_THE_LOST_WOODS, []{return logic->BlastOrSmash();});}}), - }); - - areaTable[RR_LW_BEYOND_MIDO] = Region("LW Beyond Mido", "Lost Woods", {RA_THE_LOST_WOODS}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->ButterflyFairy, {[]{return logic->ButterflyFairy || logic->CanUse(RG_STICKS);}}), - }, { - //Locations - LOCATION(RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT, logic->IsChild && logic->CanStunDeku()), - LOCATION(RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, logic->IsChild && logic->CanStunDeku()), - LOCATION(RC_LW_GS_ABOVE_THEATER, logic->IsAdult && ((CanPlantBean(RR_LW_BEYOND_MIDO) && logic->CanAttack()) || (ctx->GetTrickOption(RT_LW_GS_BEAN) && logic->CanUse(RG_HOOKSHOT) && (logic->CanUse(RG_LONGSHOT) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_BOMBCHU_5) || logic->CanUse(RG_DINS_FIRE)))) && logic->CanGetNightTimeGS()), - LOCATION(RC_LW_GS_BEAN_PATCH_NEAR_THEATER, logic->CanSpawnSoilSkull() && (logic->CanAttack() || (ctx->GetOption(RSK_SHUFFLE_SCRUBS).Is(RO_SCRUBS_OFF) && logic->CanReflectNuts()))), - LOCATION(RC_LW_BOULDER_RUPEE, logic->BlastOrSmash()), - LOCATION(RC_LW_BEAN_SPROUT_NEAR_THEATER_FAIRY_1, logic->IsChild && logic->HasItem(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_LW_BEAN_SPROUT_NEAR_THEATER_FAIRY_2, logic->IsChild && logic->HasItem(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_LW_BEAN_SPROUT_NEAR_THEATER_FAIRY_3, logic->IsChild && logic->HasItem(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), - }, { - //Exits - Entrance(RR_LW_FOREST_EXIT, {[]{return true;}}), - Entrance(RR_THE_LOST_WOODS, {[]{return logic->IsChild || logic->CanUse(RG_SARIAS_SONG);}}), - Entrance(RR_SFM_ENTRYWAY, {[]{return true;}}), - Entrance(RR_DEKU_THEATER, {[]{return true;}}), - Entrance(RR_LW_SCRUBS_GROTTO, {[]{return Here(RR_LW_BEYOND_MIDO, []{return logic->BlastOrSmash();});}}), - }); - - areaTable[RR_LW_NEAR_SHORTCUTS_GROTTO] = Region("LW Near Shortcuts Grotto", "LW Near Shortcuts Grotto", {}, NO_DAY_NIGHT_CYCLE, grottoEvents, { - //Locations - LOCATION(RC_LW_NEAR_SHORTCUTS_GROTTO_CHEST, true), - LOCATION(RC_LW_NEAR_SHORTCUTS_GROTTO_FISH, logic->HasBottle()), - LOCATION(RC_LW_NEAR_SHORTCUTS_GROTTO_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), - LOCATION(RC_LW_NEAR_SHORTCUTS_GROTTO_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_LW_NEAR_SHORTCUTS_GROTTO_GOSSIP_STONE, true), - LOCATION(RC_LW_NEAR_SHORTCUTS_GROTTO_BEEHIVE_LEFT, logic->CanBreakLowerBeehives()), - LOCATION(RC_LW_NEAR_SHORTCUTS_GROTTO_BEEHIVE_RIGHT, logic->CanBreakLowerBeehives()), - }, { - //Exits - Entrance(RR_THE_LOST_WOODS, {[]{return true;}}), - }); - - areaTable[RR_DEKU_THEATER] = Region("Deku Theater", "Deku Theater", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_DEKU_THEATER_SKULL_MASK, logic->IsChild && logic->SkullMask), - LOCATION(RC_DEKU_THEATER_MASK_OF_TRUTH, logic->IsChild && logic->MaskOfTruth), - }, { - //Exits - Entrance(RR_LW_BEYOND_MIDO, {[]{return true;}}), - }); - - areaTable[RR_LW_SCRUBS_GROTTO] = Region("LW Scrubs Grotto", "LW Scrubs Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_LW_DEKU_SCRUB_GROTTO_REAR, logic->CanStunDeku()), - LOCATION(RC_LW_DEKU_SCRUB_GROTTO_FRONT, logic->CanStunDeku()), - LOCATION(RC_LW_DEKU_SCRUB_GROTTO_BEEHIVE, logic->CanBreakUpperBeehives()), - }, { - //Exits - Entrance(RR_LW_BEYOND_MIDO, {[]{return true;}}), - }); - - areaTable[RR_SFM_ENTRYWAY] = Region("SFM Entryway", "Sacred Forest Meadow", {RA_SACRED_FOREST_MEADOW}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_LW_BEYOND_MIDO, {[]{return true;}}), - Entrance(RR_SACRED_FOREST_MEADOW, {[]{return logic->CanJumpslash() || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_DINS_FIRE);}}), - Entrance(RR_SFM_WOLFOS_GROTTO, {[]{return logic->CanOpenBombGrotto();}}), - }); - - areaTable[RR_SACRED_FOREST_MEADOW] = Region("Sacred Forest Meadow", "Sacred Forest Meadow", {RA_SACRED_FOREST_MEADOW}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->GossipStoneFairy, {[]{return logic->CallGossipFairyExceptSuns();}}), - }, { - //Locations - LOCATION(RC_SONG_FROM_SARIA, logic->IsChild && logic->HasItem(RG_ZELDAS_LETTER)), - LOCATION(RC_SHEIK_IN_FOREST, logic->IsAdult), - LOCATION(RC_SFM_GS, logic->IsAdult && logic->HookshotOrBoomerang() && logic->CanGetNightTimeGS()), - LOCATION(RC_SFM_MAZE_LOWER_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns()), - LOCATION(RC_SFM_MAZE_LOWER_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_SFM_MAZE_UPPER_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns()), - LOCATION(RC_SFM_MAZE_UPPER_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_SFM_SARIA_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns()), - LOCATION(RC_SFM_SARIA_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_SFM_MAZE_LOWER_GOSSIP_STONE, true), - LOCATION(RC_SFM_MAZE_UPPER_GOSSIP_STONE, true), - LOCATION(RC_SFM_SARIA_GOSSIP_STONE, true), - }, { - //Exits - Entrance(RR_SFM_ENTRYWAY, {[]{return true;}}), - Entrance(RR_FOREST_TEMPLE_ENTRYWAY, {[]{return logic->CanUse(RG_HOOKSHOT);}}), - Entrance(RR_SFM_FAIRY_GROTTO, {[]{return true;}}), - Entrance(RR_SFM_STORMS_GROTTO, {[]{return logic->CanOpenStormsGrotto();}}), - }); - - areaTable[RR_SFM_FAIRY_GROTTO] = Region("SFM Fairy Grotto", "SFM Fairy Grotto", {}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->FreeFairies, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_SFM_FAIRY_GROTTO_FAIRY_1, true), - LOCATION(RC_SFM_FAIRY_GROTTO_FAIRY_2, true), - LOCATION(RC_SFM_FAIRY_GROTTO_FAIRY_3, true), - LOCATION(RC_SFM_FAIRY_GROTTO_FAIRY_4, true), - LOCATION(RC_SFM_FAIRY_GROTTO_FAIRY_5, true), - LOCATION(RC_SFM_FAIRY_GROTTO_FAIRY_6, true), - LOCATION(RC_SFM_FAIRY_GROTTO_FAIRY_7, true), - LOCATION(RC_SFM_FAIRY_GROTTO_FAIRY_8, true), - }, { - //Exits - Entrance(RR_SACRED_FOREST_MEADOW, {[]{return true;}}), - }); - - areaTable[RR_SFM_WOLFOS_GROTTO] = Region("SFM Wolfos Grotto", "SFM Wolfos Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SFM_WOLFOS_GROTTO_CHEST, logic->CanKillEnemy(RE_WOLFOS, ED_CLOSE, true, 2)), - }, { - //Exits - Entrance(RR_SFM_ENTRYWAY, {[]{return true;}}), - }); - - areaTable[RR_SFM_STORMS_GROTTO] = Region("SFM Storms Grotto", "SFM Storms Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SFM_DEKU_SCRUB_GROTTO_REAR, logic->CanStunDeku()), - LOCATION(RC_SFM_DEKU_SCRUB_GROTTO_FRONT, logic->CanStunDeku()), - LOCATION(RC_SFM_STORMS_GROTTO_BEEHIVE, logic->CanBreakUpperBeehives()), - }, { - //Exits - Entrance(RR_SACRED_FOREST_MEADOW, {[]{return true;}}), - }); - - areaTable[RR_LW_BRIDGE_FROM_FOREST] = Region("LW Bridge From Forest", "Lost Woods", {RA_THE_LOST_WOODS}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_LW_GIFT_FROM_SARIA, true), - }, { - //Exits - Entrance(RR_LW_BRIDGE, {[]{return true;}}), - }); - - areaTable[RR_LW_BRIDGE] = Region("LW Bridge", "Lost Woods", {RA_THE_LOST_WOODS}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_KOKIRI_FOREST, {[]{return true;}}), - Entrance(RR_HYRULE_FIELD, {[]{return true;}}), - Entrance(RR_THE_LOST_WOODS, {[]{return logic->CanUse(RG_LONGSHOT);}}), - }); -} 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 deleted file mode 100644 index 6a6f20e15..000000000 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_shadow_temple.cpp +++ /dev/null @@ -1,431 +0,0 @@ -#include "../location_access.hpp" -#include "../../entrance.h" -#include "../../dungeon.h" - -using namespace Rando; - -void RegionTable_Init_ShadowTemple() { - /*-------------------------- - | VANILLA/MQ DECIDER | - ---------------------------*/ - areaTable[RR_SHADOW_TEMPLE_ENTRYWAY] = Region("Shadow Temple Entryway", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_SHADOW_TEMPLE_BEGINNING, {[]{return ctx->GetDungeon(SHADOW_TEMPLE)->IsVanilla() && (ctx->GetTrickOption(RT_LENS_SHADOW) || logic->CanUse(RG_LENS_OF_TRUTH)) && (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT));}}), - Entrance(RR_SHADOW_TEMPLE_MQ_BEGINNING, {[]{return ctx->GetDungeon(SHADOW_TEMPLE)->IsMQ();}}), - Entrance(RR_GRAVEYARD_WARP_PAD_REGION, {[]{return true;}}), - }); - - /*-------------------------- - | VANILLA DUNGEON | - ---------------------------*/ - if (ctx->GetDungeon(SHADOW_TEMPLE)->IsVanilla()) { - areaTable[RR_SHADOW_TEMPLE_BEGINNING] = Region("Shadow Temple Beginning", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->NutPot, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_SHADOW_TEMPLE_MAP_CHEST, logic->CanJumpslashExceptHammer()), - LOCATION(RC_SHADOW_TEMPLE_HOVER_BOOTS_CHEST, logic->CanKillEnemy(RE_DEAD_HAND)), - LOCATION(RC_SHADOW_TEMPLE_NEAR_DEAD_HAND_POT_1, logic->CanBreakPots()), - LOCATION(RC_SHADOW_TEMPLE_WHISPERING_WALLS_POT_1, logic->CanBreakPots()), - LOCATION(RC_SHADOW_TEMPLE_WHISPERING_WALLS_POT_2, logic->CanBreakPots()), - LOCATION(RC_SHADOW_TEMPLE_WHISPERING_WALLS_POT_3, logic->CanBreakPots()), - LOCATION(RC_SHADOW_TEMPLE_WHISPERING_WALLS_POT_4, logic->CanBreakPots()), - LOCATION(RC_SHADOW_TEMPLE_WHISPERING_WALLS_POT_5, logic->CanBreakPots()), - LOCATION(RC_SHADOW_TEMPLE_MAP_CHEST_POT_1, logic->CanBreakPots()), - LOCATION(RC_SHADOW_TEMPLE_MAP_CHEST_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_SHADOW_TEMPLE_ENTRYWAY, {[]{return true;}}), - Entrance(RR_SHADOW_TEMPLE_FIRST_BEAMOS, {[]{return logic->CanUse(RG_HOVER_BOOTS);}}), - }); - - areaTable[RR_SHADOW_TEMPLE_FIRST_BEAMOS] = Region("Shadow Temple First Beamos", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->FairyPot, {[]{return true;}}), //This fairy pot is only on 3DS - }, { - //Locations - LOCATION(RC_SHADOW_TEMPLE_COMPASS_CHEST, logic->CanJumpslashExceptHammer()), - LOCATION(RC_SHADOW_TEMPLE_EARLY_SILVER_RUPEE_CHEST, logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT)), - LOCATION(RC_SHADOW_TEMPLE_GS_NEAR_SHIP, false), - LOCATION(RC_SHADOW_TEMPLE_BEAMOS_STORM_FAIRY, logic->CanUse(RG_SONG_OF_STORMS)), - }, { - //Exits - Entrance(RR_SHADOW_TEMPLE_HUGE_PIT, {[]{return logic->HasExplosives() && logic->IsAdult && logic->SmallKeys(RR_SHADOW_TEMPLE, 1, 2);}}), - Entrance(RR_SHADOW_TEMPLE_BEYOND_BOAT, {[]{return false;}}), - }); - - areaTable[RR_SHADOW_TEMPLE_HUGE_PIT] = Region("Shadow Temple Huge Pit", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SHADOW_TEMPLE_INVISIBLE_BLADES_VISIBLE_CHEST, logic->CanJumpslashExceptHammer()), - LOCATION(RC_SHADOW_TEMPLE_INVISIBLE_BLADES_INVISIBLE_CHEST, logic->CanJumpslashExceptHammer()), - LOCATION(RC_SHADOW_TEMPLE_FALLING_SPIKES_LOWER_CHEST, true), - LOCATION(RC_SHADOW_TEMPLE_FALLING_SPIKES_UPPER_CHEST, (ctx->GetTrickOption(RT_SHADOW_UMBRELLA) && logic->CanUse(RG_HOVER_BOOTS)) || logic->HasItem(RG_GORONS_BRACELET)), - LOCATION(RC_SHADOW_TEMPLE_FALLING_SPIKES_SWITCH_CHEST, (ctx->GetTrickOption(RT_SHADOW_UMBRELLA) && logic->CanUse(RG_HOVER_BOOTS)) || logic->HasItem(RG_GORONS_BRACELET)), - LOCATION(RC_SHADOW_TEMPLE_INVISIBLE_SPIKES_CHEST, logic->SmallKeys(RR_SHADOW_TEMPLE, 2, 3) && ((ctx->GetTrickOption(RT_LENS_SHADOW_PLATFORM) && ctx->GetTrickOption(RT_LENS_SHADOW)) || logic->CanUse(RG_LENS_OF_TRUTH))), - LOCATION(RC_SHADOW_TEMPLE_FREESTANDING_KEY, logic->SmallKeys(RR_SHADOW_TEMPLE, 2, 3) && ((ctx->GetTrickOption(RT_LENS_SHADOW_PLATFORM) && ctx->GetTrickOption(RT_LENS_SHADOW)) || logic->CanUse(RG_LENS_OF_TRUTH)) && logic->CanUse(RG_HOOKSHOT) && (logic->CanUse(RG_BOMB_BAG) || logic->HasItem(RG_GORONS_BRACELET) || (ctx->GetTrickOption(RT_SHADOW_FREESTANDING_KEY) && logic->CanUse(RG_BOMBCHU_5)))), - LOCATION(RC_SHADOW_TEMPLE_GS_LIKE_LIKE_ROOM, logic->CanJumpslashExceptHammer()), - LOCATION(RC_SHADOW_TEMPLE_GS_FALLING_SPIKES_ROOM, logic->CanUse(RG_HOOKSHOT) || (ctx->GetTrickOption(RT_SHADOW_UMBRELLA_GS) && logic->CanUse(RG_HOVER_BOOTS))), - LOCATION(RC_SHADOW_TEMPLE_GS_SINGLE_GIANT_POT, logic->SmallKeys(RR_SHADOW_TEMPLE, 2, 3) && ((ctx->GetTrickOption(RT_LENS_SHADOW_PLATFORM) && ctx->GetTrickOption(RT_LENS_SHADOW)) || logic->CanUse(RG_LENS_OF_TRUTH)) && logic->CanUse(RG_HOOKSHOT)), - LOCATION(RC_SHADOW_TEMPLE_FALLING_SPIKES_POT_1, logic->CanBreakPots()), - LOCATION(RC_SHADOW_TEMPLE_FALLING_SPIKES_POT_2, logic->CanBreakPots()), - LOCATION(RC_SHADOW_TEMPLE_FALLING_SPIKES_POT_3, logic->CanBreakPots() && (ctx->GetTrickOption(RT_SHADOW_UMBRELLA) && logic->CanUse(RG_HOVER_BOOTS)) || logic->HasItem(RG_GORONS_BRACELET)), - LOCATION(RC_SHADOW_TEMPLE_FALLING_SPIKES_POT_4, logic->CanBreakPots() && (ctx->GetTrickOption(RT_SHADOW_UMBRELLA) && logic->CanUse(RG_HOVER_BOOTS)) || logic->HasItem(RG_GORONS_BRACELET)), - //We cannot repeat the MQ invisible blades trick for these hearts as the like-like does not respawn if the room is cleared - LOCATION(RC_SHADOW_TEMPLE_INVISIBLE_BLADES_LEFT_HEART, (logic->CanUse(RG_SONG_OF_TIME) && logic->IsAdult) || logic->CanUse(RG_BOOMERANG)), - LOCATION(RC_SHADOW_TEMPLE_INVISIBLE_BLADES_RIGHT_HEART, (logic->CanUse(RG_SONG_OF_TIME) && logic->IsAdult) || logic->CanUse(RG_BOOMERANG)), - LOCATION(RC_SHADOW_TEMPLE_PIT_STORM_FAIRY, logic->CanUse(RG_SONG_OF_STORMS)), - }, { - //Exits - Entrance(RR_SHADOW_TEMPLE_WIND_TUNNEL, {[]{return ((ctx->GetTrickOption(RT_LENS_SHADOW_PLATFORM) && ctx->GetTrickOption(RT_LENS_SHADOW)) || logic->CanUse(RG_LENS_OF_TRUTH)) && logic->CanUse(RG_HOOKSHOT) && logic->SmallKeys(RR_SHADOW_TEMPLE, 3, 4);}}), - }); - - areaTable[RR_SHADOW_TEMPLE_WIND_TUNNEL] = Region("Shadow Temple Wind Tunnel", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SHADOW_TEMPLE_WIND_HINT_CHEST, true), - LOCATION(RC_SHADOW_TEMPLE_AFTER_WIND_ENEMY_CHEST, logic->CanJumpslashExceptHammer()), - LOCATION(RC_SHADOW_TEMPLE_AFTER_WIND_HIDDEN_CHEST, true), - LOCATION(RC_SHADOW_TEMPLE_GS_NEAR_SHIP, logic->CanUse(RG_LONGSHOT) && logic->SmallKeys(RR_SHADOW_TEMPLE, 4, 5)), - LOCATION(RC_SHADOW_TEMPLE_WIND_HINT_SUN_FAIRY, logic->CanUse(RG_SUNS_SONG)), - LOCATION(RC_SHADOW_TEMPLE_AFTER_WIND_POT_1, logic->CanBreakPots()), - LOCATION(RC_SHADOW_TEMPLE_AFTER_WIND_POT_2, logic->CanBreakPots()), - LOCATION(RC_SHADOW_TEMPLE_SCARECROW_NORTH_HEART, logic->CanUse(RG_DISTANT_SCARECROW) && logic->SmallKeys(RR_SHADOW_TEMPLE, 4, 5)), - LOCATION(RC_SHADOW_TEMPLE_SCARECROW_SOUTH_HEART, logic->CanUse(RG_DISTANT_SCARECROW) && logic->SmallKeys(RR_SHADOW_TEMPLE, 4, 5)), - }, { - //Exits - Entrance(RR_SHADOW_TEMPLE_BEYOND_BOAT, {[]{return logic->CanJumpslashExceptHammer() && logic->CanUse(RG_ZELDAS_LULLABY) && logic->SmallKeys(RR_SHADOW_TEMPLE, 4, 5);}}), - }); - - areaTable[RR_SHADOW_TEMPLE_BEYOND_BOAT] = Region("Shadow Temple Beyond Boat", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SHADOW_TEMPLE_SPIKE_WALLS_LEFT_CHEST, logic->CanUse(RG_DINS_FIRE)), - LOCATION(RC_SHADOW_TEMPLE_BOSS_KEY_CHEST, logic->CanUse(RG_DINS_FIRE)), - LOCATION(RC_SHADOW_TEMPLE_INVISIBLE_FLOORMASTER_CHEST, logic->CanJumpslashExceptHammer()), - //RANDOTODO check if child can reach the token - LOCATION(RC_SHADOW_TEMPLE_GS_TRIPLE_GIANT_POT, logic->IsAdult && logic->CanAttack()), - LOCATION(RC_SHADOW_TEMPLE_AFTER_BOAT_POT_1, logic->CanBreakPots()), - LOCATION(RC_SHADOW_TEMPLE_AFTER_BOAT_POT_2, logic->CanBreakPots()), - LOCATION(RC_SHADOW_TEMPLE_AFTER_BOAT_POT_3, logic->CanBreakPots() && (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_DISTANT_SCARECROW) || (ctx->GetTrickOption(RT_SHADOW_STATUE) && logic->CanUse(RG_BOMBCHU_5)))), - LOCATION(RC_SHADOW_TEMPLE_AFTER_BOAT_POT_4, logic->CanBreakPots() && (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_DISTANT_SCARECROW) || (ctx->GetTrickOption(RT_SHADOW_STATUE) && logic->CanUse(RG_BOMBCHU_5)))), - LOCATION(RC_SHADOW_TEMPLE_SPIKE_WALLS_POT_1, logic->CanBreakPots()), - LOCATION(RC_SHADOW_TEMPLE_FLOORMASTER_POT_1, logic->CanBreakPots()), - LOCATION(RC_SHADOW_TEMPLE_FLOORMASTER_POT_2, logic->CanBreakPots()), - LOCATION(RC_SHADOW_TEMPLE_AFTER_SHIP_UPPER_LEFT_HEART, logic->CanUse(RG_DISTANT_SCARECROW)), - LOCATION(RC_SHADOW_TEMPLE_AFTER_SHIP_UPPER_RIGHT_HEART, logic->CanUse(RG_DISTANT_SCARECROW)), - LOCATION(RC_SHADOW_TEMPLE_AFTER_SHIP_LOWER_HEART, (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_DISTANT_SCARECROW) || (ctx->GetTrickOption(RT_SHADOW_STATUE) && logic->CanUse(RG_BOMBCHU_5))) && logic->CanUse(RG_SONG_OF_TIME) || (logic->CanUse(RG_DISTANT_SCARECROW) && logic->CanUse(RG_HOVER_BOOTS))), - }, { - //Exits - Entrance(RR_SHADOW_TEMPLE_BOSS_ENTRYWAY, {[]{return (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_DISTANT_SCARECROW) || (ctx->GetTrickOption(RT_SHADOW_STATUE) && logic->CanUse(RG_BOMBCHU_5))) && logic->SmallKeys(RR_SHADOW_TEMPLE, 5) && logic->CanUse(RG_HOVER_BOOTS) && logic->HasItem(RG_SHADOW_TEMPLE_BOSS_KEY);}}) - }); - } - - /*--------------------------- - | MASTER QUEST DUNGEON | - ---------------------------*/ - if (ctx->GetDungeon(SHADOW_TEMPLE)->IsMQ()) { - //RANDOTODO doublecheck CanAttack when rewriting, as I assumed it only checked adult due to the entrance - areaTable[RR_SHADOW_TEMPLE_MQ_BEGINNING] = Region("Shadow Temple MQ Beginning", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_SHADOW_TEMPLE_ENTRYWAY, {[]{return true;}}), - Entrance(RR_SHADOW_TEMPLE_MQ_SPINNER_ROOM, {[]{return logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT);}}), - }); - - areaTable[RR_SHADOW_TEMPLE_MQ_SPINNER_ROOM] = Region("Shadow Temple MQ Spinner Room", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_SHADOW_TEMPLE_ENTRYWAY, {[]{return true;}}), - Entrance(RR_SHADOW_TEMPLE_MQ_FIRST_BEAMOS, {[]{return Here(RR_SHADOW_TEMPLE_MQ_SPINNER_ROOM, []{return logic->CanUse(RG_HOVER_BOOTS) || (ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH));}) && - (logic->CanUse(RG_HOVER_BOOTS) || Here(RR_SHADOW_TEMPLE_MQ_SPINNER_ROOM, []{return logic->CanUse(RG_FIRE_ARROWS);}) || (ctx->GetTrickOption(RT_SHADOW_MQ_GAP) && logic->CanUse(RG_LONGSHOT) && logic->CanJumpslashExceptHammer()));}}), - Entrance(RR_SHADOW_TEMPLE_MQ_DEAD_HAND_AREA, {[]{return Here(RR_SHADOW_TEMPLE_MQ_SPINNER_ROOM, []{return logic->HasExplosives();}) && logic->SmallKeys(RR_SHADOW_TEMPLE, 6) && (ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH));}}), - }); - -//Assumes we're in the "main" area and needed lens to enter. logic will need changes if a void warp puts us somewhere weird - areaTable[RR_SHADOW_TEMPLE_MQ_DEAD_HAND_AREA] = Region("Shadow Temple MQ Dead Hand Region", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SHADOW_TEMPLE_MQ_COMPASS_CHEST, logic->CanKillEnemy(RE_REDEAD)), - //There's a shared flag tied to some glass here. eye target here and killing an enemy group later in the dungeon toggles. I'm building the logic as "intended", assuming the switch needs flipping - LOCATION(RC_SHADOW_TEMPLE_MQ_HOVER_BOOTS_CHEST, logic->CanKillEnemy(RE_DEAD_HAND) && (logic->IsChild || logic->CanUse(RG_SONG_OF_TIME)) && logic->CanHitEyeTargets()), - LOCATION(RC_SHADOW_TEMPLE_MQ_WHISPERING_WALLS_POT_1, logic->CanBreakPots()), - LOCATION(RC_SHADOW_TEMPLE_MQ_WHISPERING_WALLS_POT_2, logic->CanBreakPots()), - LOCATION(RC_SHADOW_TEMPLE_MQ_ENTRANCE_REDEAD_POT_1, logic->CanBreakPots()), - LOCATION(RC_SHADOW_TEMPLE_MQ_ENTRANCE_REDEAD_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_SHADOW_TEMPLE_MQ_SPINNER_ROOM, {[]{return true;}}), - }); - -//also includes the B2 gibdo room - areaTable[RR_SHADOW_TEMPLE_MQ_FIRST_BEAMOS] = Region("Shadow Temple MQ First Beamos", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - //Doing this sets the shared flag for the glass in RR_SHADOW_TEMPLE_MQ_DEAD_HAND_AREA, but doesn't seem to affect the chest - LOCATION(RC_SHADOW_TEMPLE_MQ_EARLY_GIBDOS_CHEST, logic->CanKillEnemy(RE_GIBDO) && (ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH))), - LOCATION(RC_SHADOW_TEMPLE_MQ_BEAMOS_STORM_FAIRY, logic->CanUse(RG_SONG_OF_STORMS)), - }, { - //Exits - Entrance(RR_SHADOW_TEMPLE_MQ_UPPER_HUGE_PIT, {[]{return logic->HasExplosives() && logic->SmallKeys(RR_SHADOW_TEMPLE, 2);}}), - Entrance(RR_SHADOW_TEMPLE_MQ_B2_SPINNING_BLADE_ROOM, {[]{return ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH);}}), - }); - - areaTable[RR_SHADOW_TEMPLE_MQ_B2_SPINNING_BLADE_ROOM] = Region("Shadow Temple MQ B2 Spinning Blade Room", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SHADOW_TEMPLE_MQ_MAP_CHEST, logic->CanPassEnemy(RE_BIG_SKULLTULA) && (logic->CanUse(RG_HOOKSHOT) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)))), - }, { - //Exits - Entrance(RR_SHADOW_TEMPLE_MQ_FIRST_BEAMOS, {[]{return Here(RR_SHADOW_TEMPLE_MQ_B2_SPINNING_BLADE_ROOM, []{return logic->CanKillEnemy(RE_BIG_SKULLTULA) && (logic->CanUse(RG_HOOKSHOT) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)));});}}), - Entrance(RR_SHADOW_TEMPLE_MQ_SHORTCUT_PATH, {[]{return logic->CanPassEnemy(RE_BIG_SKULLTULA);}}), - }); - - areaTable[RR_SHADOW_TEMPLE_MQ_SHORTCUT_PATH] = Region("Shadow Temple MQ Shortcut Path", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SHADOW_TEMPLE_MQ_NEAR_SHIP_INVISIBLE_CHEST, ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)), - }, { - //Exits - Entrance(RR_SHADOW_TEMPLE_MQ_B2_SPINNING_BLADE_ROOM, {[]{return logic->CanPassEnemy(RE_BIG_SKULLTULA);}}), - Entrance(RR_SHADOW_TEMPLE_MQ_DOCK, {[]{return logic->ShadowShortcutBlock;}}), - //WARNING if there's any way past here to ship without already reaching the other side the key logic in this dungeon becomes Quantum - }); - -//Room exists for if it's ever possible to go backwards or void warp into the middle of shadow - areaTable[RR_SHADOW_TEMPLE_MQ_B2_TO_B3_CORRIDOR] = Region("Shadow Temple MQ B2 to B3 Corridor", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_SHADOW_TEMPLE_MQ_FIRST_BEAMOS, {[]{return logic->HasExplosives() && logic->SmallKeys(RR_SHADOW_TEMPLE, 2);}}), - Entrance(RR_SHADOW_TEMPLE_MQ_UPPER_HUGE_PIT, {[]{return true;}}), - //bunnyhovers + lens lets you go from the very top of upper pit to the stationary invisible platform below quite easily - }); - - areaTable[RR_SHADOW_TEMPLE_MQ_UPPER_HUGE_PIT] = Region("Shadow Temple MQ Upper Huge Pit", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SHADOW_TEMPLE_MQ_PIT_STORM_FAIRY, logic->CanUse(RG_SONG_OF_STORMS)), - }, { - //Exits - Entrance(RR_SHADOW_TEMPLE_MQ_LOWER_HUGE_PIT, {[]{return (logic->HasFireSource() && (ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH))) || ctx->GetTrickOption(RT_SHADOW_MQ_HUGE_PIT);}}), - Entrance(RR_SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_ROOM, {[]{return ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH);}}), - }); - - areaTable[RR_SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_ROOM] = Region("Shadow Temple MQ Invisible Blades Room", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - //RT_SHADOW_MQ_INVISIBLE_BLADES does not work with NL as like-likes will not swallow you, likewise like-likes will not spit you with a fairy revive - //you take half a heart base from a spit out, double check EffectiveHealth when damage logic gets reworked - //Child is too small to get hit by the blades doesn't need the trick or lens for dodging them - LOCATION(RC_SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_VISIBLE_CHEST, (logic->CanUse(RG_SONG_OF_TIME) || (ctx->GetTrickOption(RT_SHADOW_MQ_INVISIBLE_BLADES) && logic->EffectiveHealth() > 1)) && - (ctx->GetTrickOption(RT_LENS_SHADOW_MQ_INVISIBLE_BLADES) || logic->IsChild || logic->CanUse(RG_NAYRUS_LOVE) || logic->CanUse(RG_LENS_OF_TRUTH))), - LOCATION(RC_SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_INVISIBLE_CHEST, (logic->CanUse(RG_SONG_OF_TIME) || (ctx->GetTrickOption(RT_SHADOW_MQ_INVISIBLE_BLADES) && logic->EffectiveHealth() > 1)) && - ((ctx->GetTrickOption(RT_LENS_SHADOW_MQ) && (ctx->GetTrickOption(RT_LENS_SHADOW_MQ_INVISIBLE_BLADES) || logic->IsChild || logic->CanUse(RG_NAYRUS_LOVE))) || logic->CanUse(RG_LENS_OF_TRUTH))), - LOCATION(RC_SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_LEFT_HEART, (logic->CanUse(RG_SONG_OF_TIME) && logic->IsAdult) || (ctx->GetTrickOption(RT_SHADOW_MQ_INVISIBLE_BLADES) && logic->EffectiveHealth() > 1) || logic->CanUse(RG_BOOMERANG)), - LOCATION(RC_SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_RIGHT_HEART, (logic->CanUse(RG_SONG_OF_TIME) && logic->IsAdult) || (ctx->GetTrickOption(RT_SHADOW_MQ_INVISIBLE_BLADES) && logic->EffectiveHealth() > 1) || logic->CanUse(RG_BOOMERANG)), - }, { - //Exits - Entrance(RR_SHADOW_TEMPLE_MQ_UPPER_HUGE_PIT, {[]{return true;}}), - }); - - areaTable[RR_SHADOW_TEMPLE_MQ_LOWER_HUGE_PIT] = Region("Shadow Temple MQ Lower Huge Pit", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SHADOW_TEMPLE_MQ_BEAMOS_SILVER_RUPEES_CHEST, logic->CanUse(RG_LONGSHOT)), - }, { - //Exits - Entrance(RR_SHADOW_TEMPLE_MQ_STONE_UMBRELLA_ROOM, {[]{return Here(RR_SHADOW_TEMPLE_MQ_LOWER_HUGE_PIT, []{return logic->CanJumpslash() || logic->HasExplosives();});}}), - Entrance(RR_SHADOW_TEMPLE_MQ_FLOOR_SPIKES_ROOM, {[]{return logic->CanUse(RG_HOVER_BOOTS) && (ctx->GetTrickOption(RT_LENS_SHADOW_MQ_PLATFORM) || logic->CanUse(RG_LENS_OF_TRUTH)) && logic->SmallKeys(RR_SHADOW_TEMPLE, 3);}}), - }); - - areaTable[RR_SHADOW_TEMPLE_MQ_STONE_UMBRELLA_ROOM] = Region("Shadow Temple MQ Stone Umbrella Room", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SHADOW_TEMPLE_MQ_FALLING_SPIKES_LOWER_CHEST, true), - //Assuming the known setup for RT_SHADOW_UMBRELLA and RT_SHADOW_UMBRELLA_GS, probably possible without sword + shield. - //Handling the trick here instead of upper as using the block to climb is not a valid method for getting this skull without other tricks to use the block before it is intended - LOCATION(RC_SHADOW_TEMPLE_MQ_GS_FALLING_SPIKES_ROOM, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG) || - (ctx->GetTrickOption(RT_SHADOW_UMBRELLA_GS) && ctx->GetTrickOption(RT_SHADOW_UMBRELLA) && logic->CanUse(RG_HOVER_BOOTS) && logic->CanStandingShield() && logic->CanUse(RG_MASTER_SWORD))), - LOCATION(RC_SHADOW_TEMPLE_MQ_LOWER_UMBRELLA_WEST_POT, logic->CanBreakPots()), - LOCATION(RC_SHADOW_TEMPLE_MQ_LOWER_UMBRELLA_EAST_POT, logic->CanBreakPots()), - LOCATION(RC_SHADOW_TEMPLE_MQ_UPPER_UMBRELLA_SOUTH_POT, logic->CanUse(RG_BOOMERANG)), - }, { - //Exits - Entrance(RR_SHADOW_TEMPLE_MQ_LOWER_HUGE_PIT, {[]{return Here(RR_SHADOW_TEMPLE_MQ_STONE_UMBRELLA_ROOM, []{return ctx->GetTrickOption(RT_VISIBLE_COLLISION) || logic->CanHitSwitch();});}}), - //Assuming the known setup for RT_SHADOW_UMBRELLA, probably possible without sword + shield - Entrance(RR_SHADOW_TEMPLE_MQ_UPPER_STONE_UMBRELLA, {[]{return logic->IsAdult && (logic->HasItem(RG_GORONS_BRACELET) || (ctx->GetTrickOption(RT_SHADOW_UMBRELLA) && logic->CanUse(RG_HOVER_BOOTS) && logic->CanStandingShield() && logic->CanUse(RG_MASTER_SWORD)));}}), - }); - - areaTable[RR_SHADOW_TEMPLE_MQ_UPPER_STONE_UMBRELLA] = Region("Shadow Temple MQ Upper Stone Umbrella", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SHADOW_TEMPLE_MQ_FALLING_SPIKES_UPPER_CHEST, true), - LOCATION(RC_SHADOW_TEMPLE_MQ_FALLING_SPIKES_SWITCH_CHEST, true), - LOCATION(RC_SHADOW_TEMPLE_MQ_UPPER_UMBRELLA_NORTH_POT, logic->CanBreakPots()), - LOCATION(RC_SHADOW_TEMPLE_MQ_UPPER_UMBRELLA_SOUTH_POT, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_SHADOW_TEMPLE_MQ_STONE_UMBRELLA_ROOM, {[]{return true;}}), - }); - -//while the spikes here are annoying, they don't really stop you doing anything, so I'll assume either lens trick, lens to see them, or taking damage from them. Not hovers though as a new player won't see the threat without lens to react properly - areaTable[RR_SHADOW_TEMPLE_MQ_FLOOR_SPIKES_ROOM] = Region("Shadow Temple MQ Floor Spikes Room", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events //lens or trick is always required for hookshot targets. We handle it here to not complicate the RR_SHADOW_TEMPLE_MQ_FLOOR_SPIKES_UPPER_DOOR logic - EventAccess(&logic->MQShadowFloorSpikeRupees, {[]{return (ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)) && - //Upper door side high rupee needs (hookshot and redead kill(as either age) for chest and adult) or longshot. hovers can cross from the left side with a backflip but that would be a trick - //East midair rupee needs (hookshot and(hover boots or jumpslash from the upper door platform)) or longshot. - //Combined these are longshot or (IsAdult && hookshot && (CanJumpslash || (Hover Boots && Here(CanKillRedeads)))) - (logic->CanUse(RG_LONGSHOT) || (logic->IsAdult && logic->CanUse(RG_HOOKSHOT) && (logic->CanJumpslash() || (logic->CanUse(RG_HOVER_BOOTS) && Here(RR_SHADOW_TEMPLE_MQ_FLOOR_SPIKES_ROOM, []{return logic->CanKillEnemy(RE_REDEAD);}))))) && - //1 rupee is in spikes, needs hovers or damage - (logic->TakeDamage() || logic->CanUse(RG_HOVER_BOOTS));}}), - }, { - //Locations - LOCATION(RC_SHADOW_TEMPLE_MQ_INVISIBLE_SPIKES_CHEST, logic->CanKillEnemy(RE_REDEAD) && (ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->TakeDamage() || logic->CanUse(RG_LENS_OF_TRUTH))), - }, { - //Exits - Entrance(RR_SHADOW_TEMPLE_MQ_STALFOS_ROOM, {[]{return logic->MQShadowFloorSpikeRupees;}}), - //We need to assume we can get here with or without the glass platforms - Entrance(RR_SHADOW_TEMPLE_MQ_WIND_TUNNEL, {[]{return logic->SmallKeys(RR_SHADOW_TEMPLE, 4) && - (logic->CanUse(RG_LONGSHOT) || (logic->IsAdult && logic->CanUse(RG_HOOKSHOT) && (logic->MQShadowFloorSpikeRupees || Here(RR_SHADOW_TEMPLE_MQ_FLOOR_SPIKES_ROOM, []{return logic->CanKillEnemy(RE_REDEAD);})))) && - (logic->CanJumpslash() || logic->CanUse(RG_HOVER_BOOTS));}}), - }); - - areaTable[RR_SHADOW_TEMPLE_MQ_STALFOS_ROOM] = Region("Shadow Temple MQ Stalfos Room", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SHADOW_TEMPLE_MQ_STALFOS_ROOM_CHEST, logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2)), - }, { - //Exits - Entrance(RR_SHADOW_TEMPLE_MQ_FLOOR_SPIKES_ROOM, {[]{return Here(RR_SHADOW_TEMPLE_MQ_STALFOS_ROOM, []{return logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2);});}}), - }); - - areaTable[RR_SHADOW_TEMPLE_MQ_WIND_TUNNEL] = Region("Shadow Temple MQ Wind Tunnel", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_SHADOW_TEMPLE_MQ_FLOOR_SPIKES_ROOM, {[]{return logic->SmallKeys(RR_SHADOW_TEMPLE, 4) && logic->CanPassEnemy(RE_BIG_SKULLTULA) && (logic->CanUse(RG_HOOKSHOT));}}), - Entrance(RR_SHADOW_TEMPLE_MQ_WIND_HINT_ROOM, {[]{return logic->CanPassEnemy(RE_BIG_SKULLTULA) && (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS));}}), - Entrance(RR_SHADOW_TEMPLE_MQ_B4_GIBDO_ROOM, {[]{return logic->CanPassEnemy(RE_BIG_SKULLTULA) && (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS));}}), - }); - - areaTable[RR_SHADOW_TEMPLE_MQ_WIND_HINT_ROOM] = Region("Shadow Temple MQ Wind Hint Room", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SHADOW_TEMPLE_MQ_WIND_HINT_CHEST, (ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)) && logic->CanPassEnemy(RE_REDEAD)), - LOCATION(RC_SHADOW_TEMPLE_MQ_GS_WIND_HINT_ROOM, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)), - LOCATION(RC_SHADOW_TEMPLE_MQ_WIND_HINT_SUN_FAIRY, logic->CanUse(RG_SUNS_SONG)), - }, { - //Exits - Entrance(RR_SHADOW_TEMPLE_MQ_WIND_TUNNEL, {[]{return true;}}), - }); - - areaTable[RR_SHADOW_TEMPLE_MQ_B4_GIBDO_ROOM] = Region("Shadow Temple MQ B4 Gibdo Room", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->NutPot, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_SHADOW_TEMPLE_MQ_AFTER_WIND_ENEMY_CHEST, logic->CanKillEnemy(RE_GIBDO)), - LOCATION(RC_SHADOW_TEMPLE_MQ_AFTER_WIND_HIDDEN_CHEST, logic->HasExplosives() && (ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH))), - LOCATION(RC_SHADOW_TEMPLE_MQ_GS_AFTER_WIND, logic->HasExplosives()), - LOCATION(RC_SHADOW_TEMPLE_MQ_BEFORE_BOAT_POT_1, logic->CanBreakPots()), - LOCATION(RC_SHADOW_TEMPLE_MQ_BEFORE_BOAT_POT_2, logic->CanBreakPots()), - }, { - //Exits - //child can make it using the wind strat - Entrance(RR_SHADOW_TEMPLE_MQ_WIND_TUNNEL, {[]{return (ctx->GetTrickOption(RT_SHADOW_MQ_WINDY_WALKWAY)) || logic->CanUse(RG_HOVER_BOOTS);}}), - Entrance(RR_SHADOW_TEMPLE_MQ_DOCK, {[]{return logic->SmallKeys(RR_SHADOW_TEMPLE, 5);}}), - }); - - areaTable[RR_SHADOW_TEMPLE_MQ_DOCK] = Region("Shadow Temple MQ Dock", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->ShadowShortcutBlock, {[]{return logic->HasItem(RG_GORONS_BRACELET);}}), - }, { - //Locations - LOCATION(RC_SHADOW_TEMPLE_MQ_SCARECROW_NORTH_HEART, logic->CanUse(RG_DISTANT_SCARECROW)), - LOCATION(RC_SHADOW_TEMPLE_MQ_SCARECROW_SOUTH_HEART, logic->CanUse(RG_DISTANT_SCARECROW)), - }, { - //Exits - Entrance(RR_SHADOW_TEMPLE_MQ_SHORTCUT_PATH, {[]{return logic->ShadowShortcutBlock;}}), - Entrance(RR_SHADOW_TEMPLE_MQ_B4_GIBDO_ROOM, {[]{return logic->SmallKeys(RR_SHADOW_TEMPLE, 5);}}), - //funnily enough, the wheel jump seems to be in logic as there's no strength requirement in N64 - Entrance(RR_SHADOW_TEMPLE_MQ_BEYOND_BOAT, {[]{return (logic->IsAdult || logic->CanUse(RG_HOOKSHOT)) && logic->CanUse(RG_ZELDAS_LULLABY);}}), - }); - - areaTable[RR_SHADOW_TEMPLE_MQ_BEYOND_BOAT] = Region("Shadow Temple MQ Beyond Boat", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - //It's a trick on N64 to kill this and drop down to collect this with normal weapons, as doing so without the statue being dropped voids you to before the boat - //hilariously, you can also hit this with a pot before you bring down the statue, but there's no great way to reset it without crossing. the statues collision is very inconvenient afterwards - LOCATION(RC_SHADOW_TEMPLE_MQ_GS_AFTER_SHIP, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)), - LOCATION(RC_SHADOW_TEMPLE_MQ_BEFORE_CHASM_WEST_POT, logic->CanBreakPots()), - LOCATION(RC_SHADOW_TEMPLE_MQ_BEFORE_CHASM_EAST_POT, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_SHADOW_TEMPLE_MQ_ACROSS_CHASM, {[]{return Here(RR_SHADOW_TEMPLE_MQ_BEYOND_BOAT, []{return logic->CanUse(RG_FAIRY_BOW) || (ctx->GetTrickOption(RT_SHADOW_STATUE) && logic->CanUse(RG_BOMBCHU_5));});}}), - }); - - areaTable[RR_SHADOW_TEMPLE_MQ_ACROSS_CHASM] = Region("Shadow Temple MQ Across Chasm", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SHADOW_TEMPLE_MQ_AFTER_CHASM_WEST_POT, logic->CanBreakPots()), - LOCATION(RC_SHADOW_TEMPLE_MQ_AFTER_CHASM_EAST_POT, logic->CanBreakPots()), - LOCATION(RC_SHADOW_TEMPLE_MQ_AFTER_SHIP_UPPER_LEFT_HEART, logic->CanUse(RG_SONG_OF_TIME) && logic->CanHitEyeTargets() && logic->CanUse(RG_LONGSHOT)), - LOCATION(RC_SHADOW_TEMPLE_MQ_AFTER_SHIP_UPPER_RIGHT_HEART, logic->CanUse(RG_SONG_OF_TIME) && logic->CanHitEyeTargets() && logic->CanUse(RG_LONGSHOT)), - //There's invisible floor collision that makes aiming for the heart with rang harder than it should be, so it's a trick. - LOCATION(RC_SHADOW_TEMPLE_MQ_AFTER_SHIP_LOWER_HEART, logic->IsAdult), - }, { - //Exits - Entrance(RR_SHADOW_TEMPLE_MQ_BEYOND_BOAT, {[]{return Here(RR_SHADOW_TEMPLE_MQ_ACROSS_CHASM, []{return logic->CanDetonateUprightBombFlower();}) && logic->IsAdult;}}), - //assumes RR_SHADOW_TEMPLE_MQ_BEYOND_BOAT by previous access. If backwards shadow ever exists remember that child cannot jump onto the statue from this side and make an event for the switch - //Lens isn't needed to reach it but is needed to navigate the next room - Entrance(RR_SHADOW_TEMPLE_MQ_INVISIBLE_MAZE, {[]{return Here(RR_SHADOW_TEMPLE_MQ_ACROSS_CHASM, []{return logic->CanHitEyeTargets() && logic->CanUse(RG_SONG_OF_TIME) && logic->CanUse(RG_LONGSHOT);});}}), - Entrance(RR_SHADOW_TEMPLE_MQ_BOSS_DOOR, {[]{return logic->CanUse(RG_HOVER_BOOTS) && (ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH));}}), - }); - - areaTable[RR_SHADOW_TEMPLE_MQ_BOSS_DOOR] = Region("Shadow Temple MQ Boss Door", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - //you can drop onto this and the respawn is reasonable - LOCATION(RC_SHADOW_TEMPLE_MQ_GS_NEAR_BOSS, (logic->CanKillEnemy(RE_GOLD_SKULLTULA, ED_BOMB_THROW) || logic->CanUse(RG_MEGATON_HAMMER)) && (ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH))), - }, { - //Exits - Entrance(RR_SHADOW_TEMPLE_MQ_ACROSS_CHASM, {[]{return logic->CanUse(RG_HOVER_BOOTS) && (ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH));}}), - Entrance(RR_SHADOW_TEMPLE_BOSS_ENTRYWAY, {[]{return logic->HasItem(RG_SHADOW_TEMPLE_BOSS_KEY);}}), - }); - - //Assumes lens is checked on entry - areaTable[RR_SHADOW_TEMPLE_MQ_INVISIBLE_MAZE] = Region("Shadow Temple MQ Invisible Maze", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SHADOW_TEMPLE_MQ_BOMB_FLOWER_CHEST, (logic->CanUse(RG_LENS_OF_TRUTH) || ctx->GetTrickOption(RT_LENS_SHADOW_MQ_DEADHAND)) && logic->CanKillEnemy(RE_DEAD_HAND) && logic->CanDetonateUprightBombFlower()), - LOCATION(RC_SHADOW_TEMPLE_MQ_FREESTANDING_KEY, true), - LOCATION(RC_SHADOW_TEMPLE_MQ_DEAD_HAND_POT_1, logic->CanBreakPots()), - LOCATION(RC_SHADOW_TEMPLE_MQ_DEAD_HAND_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_SHADOW_TEMPLE_MQ_BEYOND_BOAT, {[]{return true;}}), - Entrance(RR_SHADOW_TEMPLE_MQ_SPIKE_WALLS_ROOM, {[]{return logic->SmallKeys(RR_SHADOW_TEMPLE, 6);}}), - }); - - areaTable[RR_SHADOW_TEMPLE_MQ_SPIKE_WALLS_ROOM] = Region("Shadow Temple MQ Spike Walls Room", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SHADOW_TEMPLE_MQ_SPIKE_WALLS_LEFT_CHEST, logic->CanUse(RG_DINS_FIRE)), - LOCATION(RC_SHADOW_TEMPLE_MQ_BOSS_KEY_CHEST, logic->CanUse(RG_DINS_FIRE)), - LOCATION(RC_SHADOW_TEMPLE_MQ_SPIKE_BARICADE_POT, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_SHADOW_TEMPLE_MQ_INVISIBLE_MAZE, {[]{return logic->SmallKeys(RR_SHADOW_TEMPLE, 6) && (ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH));}}),}); - } - - /*--------------------------- - | BOSS ROOM | - ---------------------------*/ - areaTable[RR_SHADOW_TEMPLE_BOSS_ENTRYWAY] = - Region("Shadow Temple Boss Entryway", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, - { - // Exits - Entrance(RR_SHADOW_TEMPLE_BEYOND_BOAT, { [] { return ctx->GetDungeon(SHADOW_TEMPLE)->IsVanilla() && false; } }), - Entrance(RR_SHADOW_TEMPLE_MQ_BEYOND_BOAT, { [] { return ctx->GetDungeon(SHADOW_TEMPLE)->IsMQ() && false; } }), - Entrance(RR_SHADOW_TEMPLE_BOSS_ROOM, { [] { return true; } }), - }); - - areaTable[RR_SHADOW_TEMPLE_BOSS_ROOM] = - Region("Shadow Temple Boss Room", "Shadow Temple", {}, NO_DAY_NIGHT_CYCLE, - { - // Events - EventAccess(&logic->ShadowTempleClear, { [] { - return logic->ShadowTempleClear || (logic->HasBossSoul(RG_BONGO_BONGO_SOUL) && - ((logic->CanUse(RG_LENS_OF_TRUTH) || ctx->GetTrickOption(RT_LENS_BONGO)) && - (logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD)) && - (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT) || ctx->GetTrickOption(RT_SHADOW_BONGO)))); - } }), - }, - { - // Locations - LOCATION(RC_SHADOW_TEMPLE_BONGO_BONGO_HEART, logic->ShadowTempleClear), - LOCATION(RC_BONGO_BONGO, logic->ShadowTempleClear), - }, - { - // Exits - Entrance(RR_SHADOW_TEMPLE_BOSS_ENTRYWAY, { [] { return false; } }), - Entrance(RR_GRAVEYARD_WARP_PAD_REGION, { [] { return logic->ShadowTempleClear; } }, false), - }); -} 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 deleted file mode 100644 index 6be9bb707..000000000 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_spirit_temple.cpp +++ /dev/null @@ -1,577 +0,0 @@ -#include "../location_access.hpp" -#include "../../entrance.h" -#include "../../dungeon.h" - -using namespace Rando; - -void RegionTable_Init_SpiritTemple() { - /*-------------------------- - | VANILLA/MQ DECIDER | - ---------------------------*/ - areaTable[RR_SPIRIT_TEMPLE_ENTRYWAY] = Region("Spirit Temple Entryway", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_SPIRIT_TEMPLE_LOBBY, {[]{return ctx->GetDungeon(SPIRIT_TEMPLE)->IsVanilla();}}), - Entrance(RR_SPIRIT_TEMPLE_MQ_LOBBY, {[]{return ctx->GetDungeon(SPIRIT_TEMPLE)->IsMQ();}}), - Entrance(RR_DESERT_COLOSSUS_OUTSIDE_TEMPLE, {[]{return true;}}), - }); - - /*-------------------------- - | VANILLA DUNGEON | - ---------------------------*/ - if (ctx->GetDungeon(SPIRIT_TEMPLE)->IsVanilla()) { - areaTable[RR_SPIRIT_TEMPLE_LOBBY] = Region("Spirit Temple Lobby", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SPIRIT_TEMPLE_LOBBY_POT_1, logic->CanBreakPots()), - LOCATION(RC_SPIRIT_TEMPLE_LOBBY_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_SPIRIT_TEMPLE_ENTRYWAY, {[]{return true;}}), - Entrance(RR_SPIRIT_TEMPLE_CHILD, {[]{return logic->IsChild;}}), - Entrance(RR_SPIRIT_TEMPLE_EARLY_ADULT, {[]{return logic->CanUse(RG_SILVER_GAUNTLETS);}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_CHILD] = Region("Child Spirit Temple", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->NutCrate, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_SPIRIT_TEMPLE_CHILD_BRIDGE_CHEST, (logic->CanUse(RG_BOOMERANG) || logic->CanUse(RG_FAIRY_SLINGSHOT) || (logic->CanUse(RG_BOMBCHU_5) && ctx->GetTrickOption(RT_SPIRIT_CHILD_CHU))) && (logic->HasExplosives() || ((logic->CanUse(RG_NUTS) || logic->CanUse(RG_BOOMERANG)) && (logic->CanUse(RG_STICKS) || logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_FAIRY_SLINGSHOT))))), - LOCATION(RC_SPIRIT_TEMPLE_CHILD_EARLY_TORCHES_CHEST, (logic->CanUse(RG_BOOMERANG) || logic->CanUse(RG_FAIRY_SLINGSHOT) || (logic->CanUse(RG_BOMBCHU_5) && ctx->GetTrickOption(RT_SPIRIT_CHILD_CHU))) && (logic->HasExplosives() || ((logic->CanUse(RG_NUTS) || logic->CanUse(RG_BOOMERANG)) && (logic->CanUse(RG_STICKS) || logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_FAIRY_SLINGSHOT)))) && (logic->CanUse(RG_STICKS) || logic->CanUse(RG_DINS_FIRE))), - LOCATION(RC_SPIRIT_TEMPLE_GS_METAL_FENCE, (logic->CanUse(RG_BOOMERANG) || logic->CanUse(RG_FAIRY_SLINGSHOT) || (logic->CanUse(RG_BOMBCHU_5) && ctx->GetTrickOption(RT_SPIRIT_CHILD_CHU))) && (logic->HasExplosives() || ((logic->CanUse(RG_NUTS) || logic->CanUse(RG_BOOMERANG)) && (logic->CanUse(RG_STICKS) || logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_FAIRY_SLINGSHOT))))), - LOCATION(RC_SPIRIT_TEMPLE_ANUBIS_POT_1, (logic->CanUse(RG_BOOMERANG) || logic->CanUse(RG_FAIRY_SLINGSHOT) || (logic->CanUse(RG_BOMBCHU_5) && ctx->GetTrickOption(RT_SPIRIT_CHILD_CHU))) && (logic->HasExplosives() || ((logic->CanUse(RG_NUTS) || logic->CanUse(RG_BOOMERANG)) && (logic->CanUse(RG_STICKS) || logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_FAIRY_SLINGSHOT))))), - LOCATION(RC_SPIRIT_TEMPLE_ANUBIS_POT_2, (logic->CanUse(RG_BOOMERANG) || logic->CanUse(RG_FAIRY_SLINGSHOT) || (logic->CanUse(RG_BOMBCHU_5) && ctx->GetTrickOption(RT_SPIRIT_CHILD_CHU))) && (logic->HasExplosives() || ((logic->CanUse(RG_NUTS) || logic->CanUse(RG_BOOMERANG)) && (logic->CanUse(RG_STICKS) || logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_FAIRY_SLINGSHOT))))), - LOCATION(RC_SPIRIT_TEMPLE_ANUBIS_POT_3, (logic->CanUse(RG_BOOMERANG) || logic->CanUse(RG_FAIRY_SLINGSHOT) || (logic->CanUse(RG_BOMBCHU_5) && ctx->GetTrickOption(RT_SPIRIT_CHILD_CHU))) && (logic->HasExplosives() || ((logic->CanUse(RG_NUTS) || logic->CanUse(RG_BOOMERANG)) && (logic->CanUse(RG_STICKS) || logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_FAIRY_SLINGSHOT))))), - LOCATION(RC_SPIRIT_TEMPLE_ANUBIS_POT_4, (logic->CanUse(RG_BOOMERANG) || logic->CanUse(RG_FAIRY_SLINGSHOT) || (logic->CanUse(RG_BOMBCHU_5) && ctx->GetTrickOption(RT_SPIRIT_CHILD_CHU))) && (logic->HasExplosives() || ((logic->CanUse(RG_NUTS) || logic->CanUse(RG_BOOMERANG)) && (logic->CanUse(RG_STICKS) || logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_FAIRY_SLINGSHOT))))), - }, { - //Exits - Entrance(RR_SPIRIT_TEMPLE_CHILD_CLIMB, {[]{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 1);}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_CHILD_CLIMB] = Region("Child Spirit Temple Climb", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SPIRIT_TEMPLE_CHILD_CLIMB_NORTH_CHEST, logic->HasProjectile(HasProjectileAge::Both) || ((logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 2) && ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && logic->BombchuRefill() && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF))) && logic->CanUse(RG_SILVER_GAUNTLETS) && logic->HasProjectile(HasProjectileAge::Adult)) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 5) && logic->IsChild && logic->HasProjectile(HasProjectileAge::Child))), - LOCATION(RC_SPIRIT_TEMPLE_CHILD_CLIMB_EAST_CHEST, logic->HasProjectile(HasProjectileAge::Both) || ((logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 2) && ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && logic->BombchuRefill() && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF))) && logic->CanUse(RG_SILVER_GAUNTLETS) && logic->HasProjectile(HasProjectileAge::Adult)) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 5) && logic->IsChild && logic->HasProjectile(HasProjectileAge::Child))), - LOCATION(RC_SPIRIT_TEMPLE_GS_SUN_ON_FLOOR_ROOM, logic->HasProjectile(HasProjectileAge::Both) || logic->CanUse(RG_DINS_FIRE) || - (logic->TakeDamage() && (logic->CanJumpslashExceptHammer() || logic->HasProjectile(HasProjectileAge::Child))) || - (logic->IsChild && logic->SmallKeys(RR_SPIRIT_TEMPLE, 5) && logic->HasProjectile(HasProjectileAge::Child)) || - ((logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 2) && ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && logic->BombchuRefill() && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF))) && logic->CanUse(RG_SILVER_GAUNTLETS) && (logic->HasProjectile(HasProjectileAge::Adult) || (logic->TakeDamage() && logic->CanJumpslashExceptHammer())))), - LOCATION(RC_SPIRIT_TEMPLE_CHILD_CLIMB_POT_1, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_SPIRIT_TEMPLE_CENTRAL_CHAMBER, {[]{return logic->HasExplosives() || (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS));}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_EARLY_ADULT] = Region("Early Adult Spirit Temple", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SPIRIT_TEMPLE_COMPASS_CHEST, logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_ZELDAS_LULLABY)), - LOCATION(RC_SPIRIT_TEMPLE_EARLY_ADULT_RIGHT_CHEST, (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_BOOMERANG) || logic->CanUse(RG_BOMBCHU_5) || (logic->CanUse(RG_BOMB_BAG) && logic->IsAdult && ctx->GetTrickOption(RT_SPIRIT_LOWER_ADULT_SWITCH))) && (logic->CanUse(RG_HOVER_BOOTS) || logic->CanJumpslashExceptHammer())), - LOCATION(RC_SPIRIT_TEMPLE_FIRST_MIRROR_LEFT_CHEST, logic->SmallKeys(RR_SPIRIT_TEMPLE, 3)), - LOCATION(RC_SPIRIT_TEMPLE_FIRST_MIRROR_RIGHT_CHEST, logic->SmallKeys(RR_SPIRIT_TEMPLE, 3)), - LOCATION(RC_SPIRIT_TEMPLE_GS_BOULDER_ROOM, logic->CanUse(RG_SONG_OF_TIME) && (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_BOMBCHU_5) || (logic->CanUse(RG_BOMB_BAG) && ctx->GetTrickOption(RT_SPIRIT_LOWER_ADULT_SWITCH)))), - LOCATION(RC_SPIRIT_TEMPLE_BOULDER_ROOM_SUN_FAIRY, logic->CanUse(RG_SUNS_SONG) && (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_BOOMERANG) || logic->CanUse(RG_BOMBCHU_5) || (logic->CanUse(RG_BOMB_BAG) && logic->IsAdult && ctx->GetTrickOption(RT_SPIRIT_LOWER_ADULT_SWITCH))) && (logic->CanUse(RG_HOVER_BOOTS) || logic->CanJumpslash())), - }, { - //Exits - Entrance(RR_SPIRIT_TEMPLE_CENTRAL_CHAMBER, {[]{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 1);}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_CENTRAL_CHAMBER] = Region("Spirit Temple Central Chamber", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SPIRIT_TEMPLE_MAP_CHEST, ((logic->HasExplosives() || logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 2) && ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && logic->BombchuRefill() && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF))) && - (logic->CanUse(RG_DINS_FIRE) || ((logic->CanUse(RG_FIRE_ARROWS) || ctx->GetTrickOption(RT_SPIRIT_MAP_CHEST)) && logic->CanUse(RG_FAIRY_BOW) && logic->CanUse(RG_STICKS) ))) || - (logic->SmallKeys(RR_SPIRIT_TEMPLE, 5) && logic->HasExplosives() && logic->CanUse(RG_STICKS)) || - (logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) && (logic->CanUse(RG_FIRE_ARROWS) || (ctx->GetTrickOption(RT_SPIRIT_MAP_CHEST) && logic->CanUse(RG_FAIRY_BOW))) && logic->CanUse(RG_SILVER_GAUNTLETS))), - - LOCATION(RC_SPIRIT_TEMPLE_SUN_BLOCK_ROOM_CHEST, ((logic->HasExplosives() || logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 2) && ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && logic->BombchuRefill() && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF))) && - (logic->CanUse(RG_DINS_FIRE) || ((logic->CanUse(RG_FIRE_ARROWS) || ctx->GetTrickOption(RT_SPIRIT_SUN_CHEST)) && logic->CanUse(RG_FAIRY_BOW) && logic->CanUse(RG_STICKS) ))) || - (logic->SmallKeys(RR_SPIRIT_TEMPLE, 5) && logic->HasExplosives() && logic->CanUse(RG_STICKS)) || - (logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) && (logic->CanUse(RG_FIRE_ARROWS) || (ctx->GetTrickOption(RT_SPIRIT_SUN_CHEST) && logic->CanUse(RG_FAIRY_BOW))) && logic->CanUse(RG_SILVER_GAUNTLETS))), - - LOCATION(RC_SPIRIT_TEMPLE_STATUE_ROOM_HAND_CHEST, logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) && logic->CanUse(RG_SILVER_GAUNTLETS) && logic->CanUse(RG_ZELDAS_LULLABY)), - LOCATION(RC_SPIRIT_TEMPLE_STATUE_ROOM_NORTHEAST_CHEST, logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) && logic->CanUse(RG_SILVER_GAUNTLETS) && logic->CanUse(RG_ZELDAS_LULLABY) && (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS) || ctx->GetTrickOption(RT_SPIRIT_LOBBY_JUMP))), - LOCATION(RC_SPIRIT_TEMPLE_GS_HALL_AFTER_SUN_BLOCK_ROOM, (logic->HasExplosives() && logic->CanUse(RG_BOOMERANG) && logic->CanUse(RG_HOOKSHOT)) || - (logic->CanUse(RG_BOOMERANG) && logic->SmallKeys(RR_SPIRIT_TEMPLE, 5) && logic->HasExplosives()) || - (logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_SILVER_GAUNTLETS) && (logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 2) && - logic->CanUse(RG_BOOMERANG) && ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && logic->BombchuRefill() && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF))))), - - LOCATION(RC_SPIRIT_TEMPLE_GS_LOBBY, ((logic->HasExplosives() || logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 2) && ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && logic->BombchuRefill() && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF))) && - ctx->GetTrickOption(RT_SPIRIT_LOBBY_GS) && logic->CanUse(RG_BOOMERANG) && (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS) || ctx->GetTrickOption(RT_SPIRIT_LOBBY_JUMP))) || - (ctx->GetTrickOption(RT_SPIRIT_LOBBY_GS) && logic->SmallKeys(RR_SPIRIT_TEMPLE, 5) && logic->HasExplosives() && logic->CanUse(RG_BOOMERANG)) || - (logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) && logic->CanUse(RG_SILVER_GAUNTLETS) && (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS) || ctx->GetTrickOption(RT_SPIRIT_LOBBY_JUMP)))), - LOCATION(RC_SPIRIT_TEMPLE_AFTER_SUN_BLOCK_POT_1, logic->CanBreakPots() && (logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 2) && ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && logic->BombchuRefill() && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF)))), - LOCATION(RC_SPIRIT_TEMPLE_AFTER_SUN_BLOCK_POT_2, logic->CanBreakPots() && (logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 2) && ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && logic->BombchuRefill() && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF)))), - LOCATION(RC_SPIRIT_TEMPLE_CENTRAL_CHAMBER_POT_1, logic->CanBreakPots() && (logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 2) && ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && logic->BombchuRefill() && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF)))), - LOCATION(RC_SPIRIT_TEMPLE_CENTRAL_CHAMBER_POT_2, logic->CanBreakPots() && (logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 2) && ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && logic->BombchuRefill() && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF)))), - LOCATION(RC_SPIRIT_TEMPLE_CENTRAL_CHAMBER_POT_3, logic->CanBreakPots() && (logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 2) && ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && logic->BombchuRefill() && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF)))), - LOCATION(RC_SPIRIT_TEMPLE_CENTRAL_CHAMBER_POT_4, logic->CanBreakPots() && (logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 2) && ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && logic->BombchuRefill() && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF)))), - LOCATION(RC_SPIRIT_TEMPLE_CENTRAL_CHAMBER_POT_5, logic->CanBreakPots() && (logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 2) && ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && logic->BombchuRefill() && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF)))), - LOCATION(RC_SPIRIT_TEMPLE_CENTRAL_CHAMBER_POT_6, logic->CanBreakPots() && (logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 2) && ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && logic->BombchuRefill() && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF)))), - }, { - //Exits - Entrance(RR_SPIRIT_TEMPLE_OUTDOOR_HANDS, {[]{return logic->CanJumpslashExceptHammer() || logic->HasExplosives();}}), - Entrance(RR_SPIRIT_TEMPLE_BEYOND_CENTRAL_LOCKED_DOOR, {[]{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 4) && logic->CanUse(RG_SILVER_GAUNTLETS);}}), - Entrance(RR_SPIRIT_TEMPLE_CHILD_CLIMB, {[]{return true;}}), - // RT_SPIRIT_PLATFORM_HOOKSHOT is currently disabled - Entrance(RR_SPIRIT_TEMPLE_INSIDE_STATUE_HEAD, {[]{return ctx->GetTrickOption(RT_SPIRIT_PLATFORM_HOOKSHOT) && logic->CanUse(RG_HOOKSHOT);}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_OUTDOOR_HANDS] = Region("Spirit Temple Outdoor Hands", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SPIRIT_TEMPLE_SILVER_GAUNTLETS_CHEST, (logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) && logic->CanUse(RG_LONGSHOT) && logic->HasExplosives()) || logic->SmallKeys(RR_SPIRIT_TEMPLE, 5)), - LOCATION(RC_SPIRIT_TEMPLE_MIRROR_SHIELD_CHEST, logic->SmallKeys(RR_SPIRIT_TEMPLE, 4) && logic->CanUse(RG_SILVER_GAUNTLETS) && logic->HasExplosives()), - }, { - //Exits - Entrance(RR_DESERT_COLOSSUS, {[]{return (logic->IsChild && logic->SmallKeys(RR_SPIRIT_TEMPLE, 5)) || (logic->CanUse(RG_SILVER_GAUNTLETS) && ((logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) && logic->HasExplosives()) || logic->SmallKeys(RR_SPIRIT_TEMPLE, 5)));}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_BEYOND_CENTRAL_LOCKED_DOOR] = Region("Spirit Temple Beyond Central Locked Door", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SPIRIT_TEMPLE_NEAR_FOUR_ARMOS_CHEST, (logic->CanUse(RG_MIRROR_SHIELD) || (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS))) && logic->HasExplosives()), - LOCATION(RC_SPIRIT_TEMPLE_HALLWAY_LEFT_INVISIBLE_CHEST, (ctx->GetTrickOption(RT_LENS_SPIRIT) || logic->CanUse(RG_LENS_OF_TRUTH)) && logic->HasExplosives()), - LOCATION(RC_SPIRIT_TEMPLE_HALLWAY_RIGHT_INVISIBLE_CHEST, (ctx->GetTrickOption(RT_LENS_SPIRIT) || logic->CanUse(RG_LENS_OF_TRUTH)) && logic->HasExplosives()), - LOCATION(RC_SPIRIT_TEMPLE_BEAMOS_HALL_POT_1, logic->CanBreakPots()), - LOCATION(RC_SPIRIT_TEMPLE_ARMOS_ROOM_SUN_FAIRY, logic->HasExplosives() && logic->CanUse(RG_SUNS_SONG)), - }, { - //Exits - Entrance(RR_SPIRIT_TEMPLE_BEYOND_FINAL_LOCKED_DOOR, {[]{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 5) && (ctx->GetTrickOption(RT_SPIRIT_WALL) || logic->CanUse(RG_LONGSHOT) || logic->CanUse(RG_BOMBCHU_5) || ((logic->CanUse(RG_BOMB_BAG) || logic->CanUse(RG_NUTS) || logic->CanUse(RG_DINS_FIRE)) && (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_MEGATON_HAMMER))));}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_BEYOND_FINAL_LOCKED_DOOR] = Region("Spirit Temple Beyond Final Locked Door", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SPIRIT_TEMPLE_BOSS_KEY_CHEST, logic->CanUse(RG_ZELDAS_LULLABY) && ((logic->TakeDamage() && ctx->GetTrickOption(RT_FLAMING_CHESTS)) || (logic->CanUse(RG_FAIRY_BOW) && logic->CanUse(RG_HOOKSHOT)))), - LOCATION(RC_SPIRIT_TEMPLE_TOPMOST_CHEST, (logic->CanUse(RG_MIRROR_SHIELD) && logic->CanAttack()) || (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS))), - LOCATION(RC_SPIRIT_TEMPLE_ADULT_CLIMB_LEFT_HEART, logic->CanUse(RG_HOOKSHOT)), - LOCATION(RC_SPIRIT_TEMPLE_ADULT_CLIMB_RIGHT_HEART, logic->CanUse(RG_HOOKSHOT)), - }, { - //Exits - Entrance(RR_SPIRIT_TEMPLE_INSIDE_STATUE_HEAD, {[]{return logic->CanUse(RG_MIRROR_SHIELD) && logic->HasExplosives() && logic->CanUse(RG_HOOKSHOT);}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_INSIDE_STATUE_HEAD] = - Region("Spirit Temple Inside Statue Head", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, - { - // Exits - Entrance(RR_SPIRIT_TEMPLE_CENTRAL_CHAMBER, { [] { return true; } }), - Entrance(RR_SPIRIT_TEMPLE_BOSS_ENTRYWAY, { [] { return logic->HasItem(RG_SPIRIT_TEMPLE_BOSS_KEY); } }), - }); - } - - /*--------------------------- - | MASTER QUEST DUNGEON | - ---------------------------*/ - if (ctx->GetDungeon(SPIRIT_TEMPLE)->IsMQ()) { - areaTable[RR_SPIRIT_TEMPLE_MQ_LOBBY] = Region("Spirit Temple MQ Lobby", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_LEFT_CHEST, true), - LOCATION(RC_SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_LEFT_CHEST, Here(RR_SPIRIT_TEMPLE_MQ_LOBBY, []{return logic->BlastOrSmash();}) && logic->CanHitEyeTargets()), - LOCATION(RC_SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_RIGHT_CHEST, logic->CanHitSwitch(ED_BOOMERANG)), - LOCATION(RC_SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_RIGHT_CHEST, logic->Spirit1FSilverRupees), - LOCATION(RC_SPIRIT_TEMPLE_MQ_ENTRANCE_POT_1, logic->CanBreakPots()), - LOCATION(RC_SPIRIT_TEMPLE_MQ_ENTRANCE_POT_2, logic->CanBreakPots()), - LOCATION(RC_SPIRIT_TEMPLE_MQ_ENTRANCE_POT_3, logic->CanBreakPots()), - LOCATION(RC_SPIRIT_TEMPLE_MQ_ENTRANCE_POT_4, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_SPIRIT_TEMPLE_ENTRYWAY, {[]{return true;}}), - Entrance(RR_SPIRIT_TEMPLE_MQ_1F_WEST, {[]{return logic->IsChild;}}), - Entrance(RR_SPIRIT_TEMPLE_MQ_BIG_BLOCK_ROOM_SOUTH, {[]{return logic->CanUse(RG_LONGSHOT) && logic->CanUse(RG_BOMBCHU_5);}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_MQ_1F_WEST] = Region("Spirit Temple MQ 1F West", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - //not technically a rusted switch, but a boulder through a wall, but is part of the same trick on N64 - EventAccess(&logic->MQSpiritCrawlBoulder, {[]{return logic->CanUse(RG_BOMBCHU_5) || (ctx->GetTrickOption(RT_RUSTED_SWITCHES) && logic->CanUse(RG_MEGATON_HAMMER));}}), - }, { - //Locations - LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_HAMMER_SWITCH_CHEST, logic->MQSpiritTimeTravelChest), - LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_SLUGMA_POT, logic->CanBreakPots()), - LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_LEFT_HEART, logic->CanHitEyeTargets()), - LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_RIGHT_HEART, logic->CanHitEyeTargets()), - }, { - //Exits - Entrance(RR_SPIRIT_TEMPLE_MQ_1F_GIBDO_ROOM_SOUTH, {[]{return Here(RR_SPIRIT_TEMPLE_MQ_1F_WEST, []{return logic->CanKillEnemy(RE_TORCH_SLUG);});}}), - Entrance(RR_SPIRIT_TEMPLE_MQ_MAP_ROOM_SOUTH, {[]{return Here(RR_SPIRIT_TEMPLE_MQ_1F_WEST, []{return logic->CanKillEnemy(RE_TORCH_SLUG);});}}), - Entrance(RR_SPIRIT_TEMPLE_MQ_WEST_1F_RUSTED_SWITCH, {[]{return logic->IsChild && logic->MQSpiritCrawlBoulder;}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_MQ_1F_GIBDO_ROOM_SOUTH] = Region("Spirit Temple MQ 1F Gibdo Room South", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_SPIRIT_TEMPLE_MQ_1F_WEST, {[]{return true;}}), - Entrance(RR_SPIRIT_TEMPLE_MQ_1F_GIBDO_ROOM_NORTH, {[]{return logic->CanUse(RG_BOMBCHU_5) && logic->CanHitEyeTargets();}}), - Entrance(RR_SPIRIT_TEMPLE_MQ_TURNTABLE_ROOM, {[]{return logic->CanUse(RG_BOMBCHU_5) && logic->CanHitEyeTargets() && logic->CanKillEnemy(RE_GIBDO);}}), - }); - -// Room to store the 2 pots in to handle glitch logic going backwards around the loop later - areaTable[RR_SPIRIT_TEMPLE_MQ_1F_GIBDO_ROOM_NORTH] = Region("Spirit Temple MQ Gibdo Room North", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_GIBDO_POT_1, logic->CanBreakPots()), - LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_GIBDO_POT_2, logic->CanBreakPots()), - }, {}); - - areaTable[RR_SPIRIT_TEMPLE_MQ_TURNTABLE_ROOM] = Region("Spirit Temple Turntable Room", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - //For non-fairy pot items, you can also get them with rang without killing the stalfos - EventAccess(&logic->FairyPot, {[]{return Here(RR_SPIRIT_TEMPLE_MQ_TURNTABLE_ROOM, []{return logic->CanKillEnemy(RE_STALFOS);});}}), - }, { - //Locations - //implies logic->CanBreakPots() - LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_STALFOS_POT_1, logic->CanUse(RG_BOOMERANG) || logic->CanKillEnemy(RE_STALFOS)), - LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_STALFOS_POT_2, logic->CanUse(RG_BOOMERANG) || logic->CanKillEnemy(RE_STALFOS)), - LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_STALFOS_POT_3, logic->CanUse(RG_BOOMERANG) || logic->CanKillEnemy(RE_STALFOS)), - LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_STALFOS_POT_4, logic->CanUse(RG_BOOMERANG) || logic->CanKillEnemy(RE_STALFOS)), - }, { - //Exits - Entrance(RR_SPIRIT_TEMPLE_MQ_1F_GIBDO_ROOM_NORTH, {[]{return true;}}), - Entrance(RR_SPIRIT_TEMPLE_MQ_MAP_ROOM_NORTH, {[]{return Here(RR_SPIRIT_TEMPLE_MQ_TURNTABLE_ROOM, []{return logic->CanKillEnemy(RE_STALFOS);});}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_MQ_MAP_ROOM_NORTH] = Region("Spirit Temple MQ Map Room North", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->MQSpiritMapRoomEnemies, {[]{return logic->CanKillEnemy(RE_ANUBIS) && logic->CanKillEnemy(RE_KEESE);}}), - }, { - //Locations - LOCATION(RC_SPIRIT_TEMPLE_MQ_MAP_ROOM_ENEMY_CHEST, logic->MQSpiritMapRoomEnemies), - }, { - //Exits - //Stalfos room blocks you in with fire until you kill the stalfos, which won't spawn from behind the fire - Entrance(RR_SPIRIT_TEMPLE_MQ_MAP_ROOM_SOUTH, {[]{return true;}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_MQ_MAP_ROOM_SOUTH] = Region("Spirit Temple MQ Map Room South", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - //You can lure the keese over by aggroing them with dins if you use it as close to the torch keese as possible, but it's a trick as it's not intuitive and basically never comes up - EventAccess(&logic->MQSpiritMapRoomEnemies, {[]{return logic->CanKillEnemy(RE_ANUBIS) && logic->CanKillEnemy(RE_KEESE, ED_BOOMERANG);}}), - }, { - //Locations - LOCATION(RC_SPIRIT_TEMPLE_MQ_MAP_CHEST, true), - }, { - //Exits - //The bridge is a temp flag, so not a way to cross south to north in logic - Entrance(RR_SPIRIT_TEMPLE_MQ_MAP_ROOM_NORTH, {[]{return logic->CanUse(RG_HOOKSHOT);}}), - Entrance(RR_SPIRIT_TEMPLE_MQ_1F_WEST, {[]{return true;}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_MQ_WEST_1F_RUSTED_SWITCH] = Region("Spirit Temple MQ West 1F Rusted Switch", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->MQSpiritTimeTravelChest, {[]{return logic->CanUse(RG_MEGATON_HAMMER);}}), - EventAccess(&logic->MQSpiritCrawlBoulder, {[]{return logic->CanUse(RG_BOMBCHU_5) || (ctx->GetTrickOption(RT_RUSTED_SWITCHES) && logic->CanUse(RG_MEGATON_HAMMER));}}), - }, {}, { - //Exits - Entrance(RR_SPIRIT_TEMPLE_MQ_1F_WEST, {[]{return logic->IsChild && logic->MQSpiritCrawlBoulder;}}), - //This tracks possible child access, if adult has not entered STATUE_ROOM. Certain Child Access is checked for separately as 7 Keys - Entrance(RR_SPIRIT_TEMPLE_MQ_UNDER_LIKE_LIKE, {[]{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 1);}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_MQ_UNDER_LIKE_LIKE] = Region("Spirit Temple MQ Under Like Like", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_LIKE_LIKE_POT, MQSpiritSharedBrokenWallRoom(RR_SPIRIT_TEMPLE_MQ_UNDER_LIKE_LIKE, []{return logic->CanBreakPots();})), - }, { - //Exits - //This covers adult access only, as child arrives here from the other side of this door - Entrance(RR_SPIRIT_TEMPLE_MQ_WEST_1F_RUSTED_SWITCH, {[]{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 7);}}), - Entrance(RR_SPIRIT_TEMPLE_MQ_BROKEN_WALL_ROOM, {[]{return logic->CanHitSwitch();}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_MQ_BROKEN_WALL_ROOM] = Region("Spirit Temple MQ Broken Wall Room", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - //Implies CanKillEnemy(RE_LIKE_LIKE) - LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_CLIMB_NORTH_CHEST, MQSpiritSharedBrokenWallRoom(RR_SPIRIT_TEMPLE_MQ_BROKEN_WALL_ROOM, []{return logic->CanKillEnemy(RE_BEAMOS);})), - //Sunlights only temp spawn this chest, which is unintuitive/a bug. - //chest is only reachable as adult glitchlessly, so we can skip the shared in favour of IsAdult as adult access is always Certain - LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_CLIMB_SOUTH_CHEST, logic->IsAdult && logic->HasExplosives() && (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS)) && logic->CanUse(RG_HOOKSHOT)), - }, { - //Exits - Entrance(RR_SPIRIT_TEMPLE_MQ_UNDER_LIKE_LIKE, {[]{return logic->CanHitSwitch();}}), - //This exit only governs child possible access, adult access starts on the other side so never checks this - Entrance(RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM, {[]{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 2);}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM] = Region("Spirit Temple MQ Statue Room", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SPIRIT_TEMPLE_MQ_COMPASS_CHEST, MQSpiritSharedStatueRoom(RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM, []{return logic->CanHitEyeTargets();})), - LOCATION(RC_SPIRIT_TEMPLE_MQ_STATUE_3F_EAST_POT, MQSpiritSharedStatueRoom(RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM, []{return ((logic->IsAdult || logic->CanJumpslash()) && logic->CanUse(RG_BOOMERANG)) || - ((logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_SONG_OF_TIME) || (logic->IsAdult && ctx->GetTrickOption(RT_SPIRIT_LOBBY_JUMP))) && logic->CanBreakPots());})), - LOCATION(RC_SPIRIT_TEMPLE_MQ_STATUE_3F_WEST_POT, MQSpiritSharedStatueRoom(RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM, []{return (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_SONG_OF_TIME) || (logic->IsAdult && ctx->GetTrickOption(RT_SPIRIT_LOBBY_JUMP)) && logic->CanBreakPots());})), - LOCATION(RC_SPIRIT_TEMPLE_MQ_STATUE_2F_CENTER_EAST_POT, MQSpiritSharedStatueRoom(RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM, []{return logic->CanBreakPots();})), - LOCATION(RC_SPIRIT_TEMPLE_MQ_STATUE_2F_WEST_POT, MQSpiritSharedStatueRoom(RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM, []{return logic->CanBreakPots();})), - LOCATION(RC_SPIRIT_TEMPLE_MQ_STATUE_2F_EASTMOST_POT, MQSpiritSharedStatueRoom(RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM, []{return logic->CanBreakPots();})), - }, { - //Exits - //we check possible adult access directly in MQSpiritSharedBrokenWallRoom, so this exit only covers Certain Access - Entrance(RR_SPIRIT_TEMPLE_MQ_BROKEN_WALL_ROOM, {[]{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 7);}}), - //We can use Here instead of Shared here because adult will never need to rely on child access to reach this room, and adult access is Certain - Entrance(RR_SPIRIT_TEMPLE_MQ_BIG_BLOCK_ROOM_NORTH, {[]{return Here(RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM, []{return logic->HasFireSource() || (ctx->GetTrickOption(RT_SPIRIT_MQ_FROZEN_EYE) && logic->CanUse(RG_FAIRY_BOW) && logic->CanUse(RG_SONG_OF_TIME));});}}), - Entrance(RR_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM, {[]{return logic->IsAdult || ctx->GetTrickOption(RT_SPIRIT_MQ_SUN_BLOCK_SOT) || logic->CanUse(RG_SONG_OF_TIME);}}), - //explicit adult check here is a precaution against possible child logic leaking, child with a hookshot can do this - Entrance(RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM_EAST, {[]{return logic->IsAdult && logic->CanUse(RG_HOOKSHOT);}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM] = Region("Spirit Temple MQ Sun Block Room", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - //We don't need Shared here because If we are checking as child, universe 2 adult access needs nothing so it always passes, and if we are checking as adult, it is Certain Access - LOCATION(RC_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM_CHEST, true), - LOCATION(RC_SPIRIT_TEMPLE_MQ_GS_SUN_BLOCK_ROOM, MQSpiritSharedStatueRoom(RR_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM, []{return logic->CanUse(RG_HOOKSHOT) || (ctx->GetTrickOption(RT_SPIRIT_MQ_SUN_BLOCK_GS) && logic->CanUse(RG_BOOMERANG));})), - LOCATION(RC_SPIRIT_TEMPLE_MQ_SUN_BLOCKS_POT_1, MQSpiritSharedStatueRoom(RR_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM, []{return logic->CanBreakPots();})), - LOCATION(RC_SPIRIT_TEMPLE_MQ_SUN_BLOCKS_POT_2, MQSpiritSharedStatueRoom(RR_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM, []{return logic->CanBreakPots();})), - }, { - //Exits - Entrance(RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM, {[]{return true;}}), - //This door causes the Universes to merge as it requires 7 keys for both ages - Entrance(RR_SPIRIT_TEMPLE_MQ_WEST_IRON_KNUCKLE, {[]{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 7);}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_MQ_WEST_IRON_KNUCKLE] = Region("Spirit Temple MQ East Iron Knuckle", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM, {[]{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 7);}}), - Entrance(RR_SPIRIT_TEMPLE_MQ_SILVER_GAUNTLETS_HAND, {[]{return logic->CanKillEnemy(RE_IRON_KNUCKLE);}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_MQ_SILVER_GAUNTLETS_HAND] = Region("Spirit Temple MQ Silver Gauntlets Hand", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SPIRIT_TEMPLE_SILVER_GAUNTLETS_CHEST, true), - }, { - //Exits - //If it is ever relevent for 1 age to spawn the mirror shield chest for the other can longshot across, it needs an eventAccess - Entrance(RR_SPIRIT_TEMPLE_MQ_WEST_IRON_KNUCKLE, {[]{return true;}}), - Entrance(RR_DESERT_COLOSSUS, {[]{return true;}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_MQ_BIG_BLOCK_ROOM_SOUTH] = Region("Spirit Temple MQ Block Room South", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_SPIRIT_TEMPLE_MQ_LOBBY, {[]{return true;}}), - //The block here is unusual in that it is a permanent flag, but reset anyway as child. This is because there's a check that would be blocked off by pushing them otherwise - //It may be worth considering making this always temp in future so adult doesn't have the same issue - Entrance(RR_SPIRIT_TEMPLE_MQ_BIG_BLOCK_ROOM_NORTH, {[]{return logic->IsChild ? logic->CanUse(RG_SILVER_GAUNTLETS) : Here(RR_SPIRIT_TEMPLE_MQ_LOBBY, []{return logic->CanUse(RG_SILVER_GAUNTLETS);});}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_MQ_BIG_BLOCK_ROOM_NORTH] = Region("Spirit Temple MQ Block Room North", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - //Does not need to be shared as it's hard child locked, because adult pushing the block is a permanent flag that blocks the eye target and cannot be undone - LOCATION(RC_SPIRIT_TEMPLE_MQ_SILVER_BLOCK_HALLWAY_CHEST, logic->IsChild && logic->SmallKeys(RR_SPIRIT_TEMPLE, 7) && logic->CanHitEyeTargets()), - }, { - //Exits - //if going to RR_SPIRIT_TEMPLE_MQ_BIG_BLOCK_ROOM_SOUTH from here is ever relevant, there needs to be an event to handle the block - Entrance(RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM, {[]{return true;}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM_EAST] = Region("Spirit Temple MQ Statue Room East", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SPIRIT_TEMPLE_MQ_STATUE_ROOM_LULLABY_CHEST, logic->CanUse(RG_HOOKSHOT) & logic->CanUse(RG_ZELDAS_LULLABY) && (logic->CanJumpslash() || logic->CanUse(RG_HOVER_BOOTS))), - LOCATION(RC_SPIRIT_TEMPLE_MQ_STATUE_ROOM_INVISIBLE_CHEST, (ctx->GetTrickOption(RT_LENS_SPIRIT_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)) && (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS))), - }, { - //Exits - Entrance(RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM, {[]{return true;}}), - //!QUANTUM LOGIC! - //We only need 4 keys, access to Shield hand and longshot to reach Gauntlets hand, as if we waste the 5th key we have given ourselves Gauntlets hand access through child climb - //This exit handles that possibility as cleanly as possible without quantum logic, but will not survive glitch logic - //logic->CanKillEnemy(RE_FLOORMASTER) is implied - Entrance(RR_SPIRIT_TEMPLE_MQ_SILVER_GAUNTLETS_HAND, {[]{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 4) && - logic->CanAvoidEnemy(RE_BEAMOS, true, 4) && logic->CanUse(RG_SONG_OF_TIME) && - logic->CanJumpslash() && - (ctx->GetTrickOption(RT_LENS_SPIRIT_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)) && - logic->CanKillEnemy(RE_IRON_KNUCKLE) && - logic->CanUse(RG_LONGSHOT);}}), - Entrance(RR_SPIRIT_TEMPLE_MQ_FOUR_BEAMOS_ROOM, {[]{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 5) && logic->CanUse(RG_HOOKSHOT);}}), - Entrance(RR_SPIRIT_TEMPLE_MQ_THREE_SUNS_ROOM_2F, {[]{return logic->CanUse(RG_FIRE_ARROWS) || (ctx->GetTrickOption(RT_SPIRIT_MQ_LOWER_ADULT) && logic->CanUse(RG_DINS_FIRE));}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_MQ_THREE_SUNS_ROOM_2F] = Region("Spirit Temple MQ Three Suns Room 2F", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - //implies logic->CanKillEnemy(RE_WALLMASTER). If we have lights, we can kill stalfos and wallmasters with bow - EventAccess(&logic->MQSpirit3SunsEnemies, {[]{return (logic->CanUse(RG_MIRROR_SHIELD) && logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2)) || - (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS));}}), - }, {}, { - Entrance(RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM_EAST, {[]{return true;}}), - Entrance(RR_SPIRIT_TEMPLE_MQ_THREE_SUNS_ROOM_1F, {[]{return logic->MQSpirit3SunsEnemies;}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_MQ_THREE_SUNS_ROOM_1F] = Region("Spirit Temple MQ Three Suns Room 1F", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - Entrance(RR_SPIRIT_TEMPLE_MQ_THREE_SUNS_ROOM_2F, {[]{return logic->MQSpirit3SunsEnemies;}}), - Entrance(RR_SPIRIT_TEMPLE_MQ_1F_EAST, {[]{return true;}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_MQ_1F_EAST] = Region("Spirit Temple MQ 1F East", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - //Assumes RR_SPIRIT_TEMPLE_MQ_LOBBY access - EventAccess(&logic->Spirit1FSilverRupees, {[]{return logic->CanUse(RG_MEGATON_HAMMER);}}), - }, { - //Locations - LOCATION(RC_SPIRIT_TEMPLE_MQ_EARLY_ADULT_POT_1, logic->CanBreakPots()), - LOCATION(RC_SPIRIT_TEMPLE_MQ_EARLY_ADULT_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_SPIRIT_TEMPLE_MQ_LOBBY, {[]{return logic->CanUse(RG_MEGATON_HAMMER);}}), - Entrance(RR_SPIRIT_TEMPLE_MQ_THREE_SUNS_ROOM_1F, {[]{return true;}}), - Entrance(RR_SPIRIT_TEMPLE_MQ_LEEVER_ROOM, {[]{return true;}}), - Entrance(RR_SPIRIT_TEMPLE_MQ_SYMPHONY_ROOM, {[]{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 7);}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_MQ_LEEVER_ROOM] = Region("Spirit Temple MQ Leever Room", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SPIRIT_TEMPLE_MQ_LEEVER_ROOM_CHEST, logic->CanKillEnemy(RE_PURPLE_LEEVER) && logic->CanUse(RG_HOOKSHOT)), - LOCATION(RC_SPIRIT_TEMPLE_MQ_GS_LEEVER_ROOM, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)), - }, { - Entrance(RR_SPIRIT_TEMPLE_MQ_1F_EAST, {[]{return logic->CanUse(RG_ZELDAS_LULLABY);}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_MQ_SYMPHONY_ROOM] = Region("Spirit Temple MQ Symphony Room", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_SPIRIT_TEMPLE_MQ_1F_EAST, {[]{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 7);}}), - //Implies CanPassEnemy(RE_MOBLIN_CHIEF) - Entrance(RR_SPIRIT_TEMPLE_MQ_AFTER_SYMPHONY_ROOM, {[]{return logic->CanUse(RG_MEGATON_HAMMER) && logic->CanUse(RG_SONG_OF_TIME) && logic->CanUse(RG_EPONAS_SONG) && - logic->CanUse(RG_SUNS_SONG) && logic->CanUse(RG_SONG_OF_STORMS) && logic->CanUse(RG_ZELDAS_LULLABY);}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_MQ_AFTER_SYMPHONY_ROOM] = Region("Spirit Temple MQ After Symphony Room", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SPIRIT_TEMPLE_MQ_SYMPHONY_ROOM_CHEST, logic->CanPassEnemy(RE_BIG_SKULLTULA)), - LOCATION(RC_SPIRIT_TEMPLE_MQ_GS_SYMPHONY_ROOM, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)), - }, { - //Exits - Entrance(RR_SPIRIT_TEMPLE_MQ_SYMPHONY_ROOM, {[]{return true;}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_MQ_FOUR_BEAMOS_ROOM] = Region("Spirit Temple MQ Four Beamos Room", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SPIRIT_TEMPLE_MQ_BEAMOS_ROOM_CHEST, logic->CanKillEnemy(RE_BEAMOS)), - }, { - //Exits - Entrance(RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM_EAST, {[]{return logic->CanAvoidEnemy(RE_BEAMOS, true, 4) && logic->CanUse(RG_SONG_OF_TIME) && logic->SmallKeys(RR_SPIRIT_TEMPLE, 5) && logic->CanUse(RG_HOOKSHOT);}}), - Entrance(RR_SPIRIT_TEMPLE_MQ_SOT_SUN_ROOM, {[]{return logic->CanAvoidEnemy(RE_BEAMOS, true, 4) && logic->CanUse(RG_SONG_OF_TIME);}}), - Entrance(RR_SPIRIT_TEMPLE_MQ_BIG_WALL, {[]{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 6);}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_MQ_SOT_SUN_ROOM] = Region("Spirit Temple MQ SoT Sun Room", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SPIRIT_TEMPLE_MQ_CHEST_SWITCH_CHEST, true), - LOCATION(RC_SPIRIT_TEMPLE_MQ_DINALFOS_ROOM_SUN_FAIRY, logic->CanUse(RG_SUNS_SONG)), - }, { - //Exits - Entrance(RR_SPIRIT_TEMPLE_MQ_FOUR_BEAMOS_ROOM, {[]{return true;}}), - Entrance(RR_SPIRIT_TEMPLE_MQ_EAST_STAIRS_TO_HAND, {[]{return logic->CanJumpslash();}}), - Entrance(RR_SPIRIT_TEMPLE_MQ_3F_GIBDO_ROOM, {[]{return Here(RR_SPIRIT_TEMPLE_MQ_SOT_SUN_ROOM, []{return (logic->IsAdult || logic->CanUse(RG_SONG_OF_TIME)) && logic->CanUse(RG_MIRROR_SHIELD);});}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_MQ_EAST_STAIRS_TO_HAND] = Region("Spirit Temple MQ East Stairs to Hand", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_SPIRIT_TEMPLE_MQ_SOT_SUN_ROOM, {[]{return true;}}), - Entrance(RR_SPIRIT_TEMPLE_MQ_EAST_IRON_KNUCKLE, {[]{return (ctx->GetTrickOption(RT_LENS_SPIRIT_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)) && - Here(RR_SPIRIT_TEMPLE_MQ_EAST_STAIRS_TO_HAND, []{return logic->CanKillEnemy(RE_FLOORMASTER);});}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_MQ_EAST_IRON_KNUCKLE] = Region("Spirit Temple MQ East Iron Knuckle", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_SPIRIT_TEMPLE_MQ_EAST_STAIRS_TO_HAND, {[]{return true;}}), - Entrance(RR_SPIRIT_TEMPLE_MQ_MIRROR_SHIELD_HAND, {[]{return Here(RR_SPIRIT_TEMPLE_MQ_EAST_STAIRS_TO_HAND, []{return logic->CanKillEnemy(RE_IRON_KNUCKLE);});}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_MQ_MIRROR_SHIELD_HAND] = Region("Spirit Temple MQ Mirror Shield Hand", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SPIRIT_TEMPLE_MIRROR_SHIELD_CHEST, true), - }, { - //Exits - Entrance(RR_SPIRIT_TEMPLE_MQ_SILVER_GAUNTLETS_HAND, {[]{return logic->CanUse(RG_LONGSHOT);}}), - Entrance(RR_SPIRIT_TEMPLE_MQ_EAST_IRON_KNUCKLE, {[]{return true;}}), - Entrance(RR_DESERT_COLOSSUS, {[]{return true;}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_MQ_3F_GIBDO_ROOM] = Region("Spirit Temple MQ 3F Gibdo Room", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SPIRIT_TEMPLE_MQ_BOSS_KEY_CHEST, true), - }, { - //Exits - Entrance(RR_SPIRIT_TEMPLE_MQ_SOT_SUN_ROOM, {[]{return true;}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_MQ_BIG_WALL] = Region("Spirit Temple MQ Big Wall", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SPIRIT_TEMPLE_MQ_LONG_CLIMB_POT_1, logic->CanBreakPots()), - LOCATION(RC_SPIRIT_TEMPLE_MQ_LONG_CLIMB_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_SPIRIT_TEMPLE_MQ_FOUR_BEAMOS_ROOM, {[]{return true;}}), - //technically we only need to avoid them, but the sheer height and the moving walls makes getting to the top after only stunning them very difficult/impossible - //The silver rupees are irrelevant without silver shuffle - Entrance(RR_SPIRIT_TEMPLE_MQ_4F_CENTRAL, {[]{return logic->CanKillEnemy(RE_KEESE);}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_MQ_4F_CENTRAL] = Region("Spirit Temple MQ 4F Central", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SPIRIT_TEMPLE_MQ_BEFORE_MIRROR_POT_1, logic->CanBreakPots()), - LOCATION(RC_SPIRIT_TEMPLE_MQ_BEFORE_MIRROR_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_SPIRIT_TEMPLE_MQ_BIG_WALL, {[]{return true;}}), - Entrance(RR_SPIRIT_TEMPLE_MQ_NINE_CHAIRS_ROOM, {[]{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 7);}}), - Entrance(RR_SPIRIT_TEMPLE_MQ_BIG_MIRROR_ROOM, {[]{return logic->CanUse(RG_ZELDAS_LULLABY);}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_MQ_NINE_CHAIRS_ROOM] = Region("Spirit Temple MQ Nine Chairs Room", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - //These skulls rely on the iron knuckle existing without a trick to shoot through the chairs - LOCATION(RC_SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_WEST, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)), - LOCATION(RC_SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_NORTH, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)), - }, { - //Exits - Entrance(RR_SPIRIT_TEMPLE_MQ_4F_CENTRAL, {[]{return true;}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_MQ_BIG_MIRROR_ROOM] = Region("Spirit Temple MQ Big Mirror Room", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SPIRIT_TEMPLE_MQ_BIG_MIRROR_POT_1, logic->CanBreakPots()), - LOCATION(RC_SPIRIT_TEMPLE_MQ_BIG_MIRROR_POT_2, logic->CanBreakPots()), - LOCATION(RC_SPIRIT_TEMPLE_MQ_BIG_MIRROR_POT_3, logic->CanBreakPots()), - LOCATION(RC_SPIRIT_TEMPLE_MQ_BIG_MIRROR_POT_4, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_SPIRIT_TEMPLE_MQ_4F_CENTRAL, {[]{return true;}}), - Entrance(RR_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CAVE, {[]{return Here(RR_SPIRIT_TEMPLE_MQ_BIG_MIRROR_ROOM, []{return logic->CanUse(RG_MEGATON_HAMMER);});}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CAVE] = Region("Spirit Temple MQ Big Mirror Cave", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_SPIRIT_TEMPLE_MQ_MIRROR_PUZZLE_INVISIBLE_CHEST, ctx->GetTrickOption(RT_LENS_SPIRIT_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)), - }, { - //Exits - //If it's ever relevant to longshot into head from lobby, this needs to be an event access - Entrance(RR_SPIRIT_TEMPLE_MQ_INSIDE_STATUE_HEAD, {[]{return Here(RR_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CAVE, []{return logic->CanUse(RG_MIRROR_SHIELD);}) && logic->CanUse(RG_HOOKSHOT);}}), - Entrance(RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM, {[]{return Here(RR_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CAVE, []{return logic->CanUse(RG_MIRROR_SHIELD);});}}), - }); - - areaTable[RR_SPIRIT_TEMPLE_MQ_INSIDE_STATUE_HEAD] = Region("Spirit Temple MQ Inside Statue Head", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - // Exits - Entrance(RR_SPIRIT_TEMPLE_MQ_LOBBY, {[]{return true;} }), - Entrance(RR_SPIRIT_TEMPLE_BOSS_ENTRYWAY, {[]{return logic->HasItem(RG_SPIRIT_TEMPLE_BOSS_KEY);}}), - }); - } - - /*--------------------------- - | BOSS ROOM | - ---------------------------*/ - areaTable[RR_SPIRIT_TEMPLE_BOSS_ENTRYWAY] = Region( - "Spirit Temple Boss Entryway", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, - { - // Exits - Entrance(RR_SPIRIT_TEMPLE_INSIDE_STATUE_HEAD, { [] { return ctx->GetDungeon(SPIRIT_TEMPLE)->IsVanilla() && false; } }), - Entrance(RR_SPIRIT_TEMPLE_MQ_INSIDE_STATUE_HEAD, { [] { return ctx->GetDungeon(SPIRIT_TEMPLE)->IsMQ() && false; } }), - Entrance(RR_SPIRIT_TEMPLE_BOSS_ROOM, { [] { return true; } }), - }); - - areaTable[RR_SPIRIT_TEMPLE_BOSS_ROOM] = Region("Spirit Temple Boss Room", "Spirit Temple", {}, NO_DAY_NIGHT_CYCLE, - { - // Events - EventAccess(&logic->SpiritTempleClear, { [] { - return logic->SpiritTempleClear || (logic->HasBossSoul(RG_TWINROVA_SOUL) && (logic->CanUse(RG_MIRROR_SHIELD) && - (logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD)))); - } }), - }, - { - // Locations - LOCATION(RC_SPIRIT_TEMPLE_TWINROVA_HEART, logic->SpiritTempleClear), - LOCATION(RC_TWINROVA, logic->SpiritTempleClear), - }, - { - // Exits - Entrance(RR_SPIRIT_TEMPLE_BOSS_ENTRYWAY, { [] { return false; } }), - Entrance(RR_DESERT_COLOSSUS, { [] { return logic->SpiritTempleClear; } }, false), - }); -} 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 deleted file mode 100644 index e630c997e..000000000 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_water_temple.cpp +++ /dev/null @@ -1,779 +0,0 @@ -#include "../location_access.hpp" -#include "../../entrance.h" -#include "../../dungeon.h" - -using namespace Rando; - -void RegionTable_Init_WaterTemple() { - /*-------------------------- - | VANILLA/MQ DECIDER | - ---------------------------*/ - areaTable[RR_WATER_TEMPLE_ENTRYWAY] = Region("Water Temple Entryway", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_WATER_TEMPLE_LOBBY, {[]{return logic->HasItem(RG_BRONZE_SCALE) && ctx->GetDungeon(WATER_TEMPLE)->IsVanilla();}}), - Entrance(RR_WATER_TEMPLE_MQ_3F_CENTRAL, {[]{return logic->HasItem(RG_BRONZE_SCALE) && ctx->GetDungeon(WATER_TEMPLE)->IsMQ();}}), - Entrance(RR_LAKE_HYLIA, {[]{return true;}}), - }); - - /*-------------------------- - | VANILLA DUNGEON | - ---------------------------*/ - if (ctx->GetDungeon(WATER_TEMPLE)->IsVanilla()) { - //Water Temple logic currently assumes that the locked door leading to the upper water raising location is unlocked from the start - areaTable[RR_WATER_TEMPLE_LOBBY] = Region("Water Temple Lobby", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_WATER_TEMPLE_MAIN_LEVEL_2_POT_1, logic->CanBreakPots() && (logic->CanWaterTempleLowFromHigh || logic->CanWaterTempleMiddle || (logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT)))), - LOCATION(RC_WATER_TEMPLE_MAIN_LEVEL_2_POT_2, logic->CanBreakPots() && (logic->CanWaterTempleLowFromHigh || logic->CanWaterTempleMiddle || (logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT)))), - }, { - //Exits - Entrance(RR_WATER_TEMPLE_ENTRYWAY, {[]{return true;}}), - Entrance(RR_WATER_TEMPLE_EAST_LOWER, {[]{return logic->CanWaterTempleLowFromHigh || ((ctx->GetTrickOption(RT_FEWER_TUNIC_REQUIREMENTS) || logic->CanUse(RG_ZORA_TUNIC)) && (logic->CanUse(RG_IRON_BOOTS) || (logic->CanUse(RG_LONGSHOT) && ctx->GetTrickOption(RT_WATER_LONGSHOT_TORCH))));}}), - Entrance(RR_WATER_TEMPLE_NORTH_LOWER, {[]{return logic->CanWaterTempleLowFromHigh || ((ctx->GetTrickOption(RT_FEWER_TUNIC_REQUIREMENTS) || logic->CanUse(RG_ZORA_TUNIC)) && logic->CanUse(RG_IRON_BOOTS));}}), - Entrance(RR_WATER_TEMPLE_SOUTH_LOWER, {[]{return logic->CanWaterTempleLowFromHigh && logic->HasExplosives() && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS)) && (ctx->GetTrickOption(RT_FEWER_TUNIC_REQUIREMENTS) || logic->CanUse(RG_ZORA_TUNIC));}}), - Entrance(RR_WATER_TEMPLE_WEST_LOWER, {[]{return logic->CanWaterTempleLowFromHigh && logic->HasItem(RG_GORONS_BRACELET) && (logic->IsChild || logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS)) && (ctx->GetTrickOption(RT_FEWER_TUNIC_REQUIREMENTS) || logic->CanUse(RG_ZORA_TUNIC));}}), - Entrance(RR_WATER_TEMPLE_CENTRAL_PILLAR_LOWER, {[]{return logic->CanWaterTempleLowFromHigh && logic->SmallKeys(RR_WATER_TEMPLE, 5);}}), - Entrance(RR_WATER_TEMPLE_CENTRAL_PILLAR_UPPER, {[]{return (logic->CanWaterTempleLowFromHigh || logic->CanWaterTempleMiddle) && (logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW));}}), - Entrance(RR_WATER_TEMPLE_EAST_MIDDLE, {[]{return (logic->CanWaterTempleLowFromHigh || logic->CanWaterTempleMiddle || (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16)) && logic->CanUse(RG_HOOKSHOT);}}), - Entrance(RR_WATER_TEMPLE_WEST_MIDDLE, {[]{return logic->CanWaterTempleMiddle;}}), - Entrance(RR_WATER_TEMPLE_HIGH_WATER, {[]{return logic->IsAdult && (logic->CanUse(RG_HOVER_BOOTS) || (ctx->GetTrickOption(RT_DAMAGE_BOOST) && logic->CanUse(RG_BOMB_BAG) && logic->TakeDamage()));}}), - Entrance(RR_WATER_TEMPLE_BLOCK_CORRIDOR, {[]{return (logic->CanWaterTempleLowFromHigh || logic->CanWaterTempleMiddle) && (logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_FAIRY_BOW)) && (logic->CanUse(RG_LONGSHOT) || logic->CanUse(RG_HOVER_BOOTS) || (ctx->GetTrickOption(RT_WATER_CENTRAL_BOW) && (logic->IsAdult || logic->CanWaterTempleMiddle)));}}), - Entrance(RR_WATER_TEMPLE_FALLING_PLATFORM_ROOM, {[]{return logic->CanWaterTempleHigh && logic->SmallKeys(RR_WATER_TEMPLE, 4);}}), - Entrance(RR_WATER_TEMPLE_PRE_BOSS_ROOM, {[]{return (logic->CanWaterTempleHigh && logic->CanUse(RG_LONGSHOT)) || (ctx->GetTrickOption(RT_HOVER_BOOST_SIMPLE) && ctx->GetTrickOption(RT_DAMAGE_BOOST_SIMPLE) && logic->HasExplosives() && logic->CanUse(RG_HOVER_BOOTS));}}), - }); - - areaTable[RR_WATER_TEMPLE_EAST_LOWER] = Region("Water Temple East Lower", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->CanWaterTempleLowFromHigh, {[]{return logic->CanWaterTempleLowFromHigh || logic->CanUse(RG_ZELDAS_LULLABY);}}), - }, { - //Locations - LOCATION(RC_WATER_TEMPLE_TORCH_POT_1, logic->CanBreakPots() && (logic->CanWaterTempleLowFromHigh || (logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_IRON_BOOTS)))), - LOCATION(RC_WATER_TEMPLE_TORCH_POT_2, logic->CanBreakPots() && (logic->CanWaterTempleLowFromHigh || (logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_IRON_BOOTS)))), - }, { - //Exits - Entrance(RR_WATER_TEMPLE_LOBBY, {[]{return logic->CanWaterTempleLowFromHigh || ((ctx->GetTrickOption(RT_FEWER_TUNIC_REQUIREMENTS) || logic->CanUse(RG_ZORA_TUNIC)) && logic->CanUse(RG_IRON_BOOTS));}}), - Entrance(RR_WATER_TEMPLE_MAP_ROOM, {[]{return logic->CanWaterTempleHigh;}}), - Entrance(RR_WATER_TEMPLE_CRACKED_WALL, {[]{return logic->CanWaterTempleMiddle || (logic->CanWaterTempleHigh && logic->CanWaterTempleLowFromHigh && ((logic->CanUse(RG_HOVER_BOOTS) && ctx->GetTrickOption(RT_WATER_CRACKED_WALL_HOVERS)) || ctx->GetTrickOption(RT_WATER_CRACKED_WALL)));}}), - Entrance(RR_WATER_TEMPLE_TORCH_ROOM, {[]{return logic->CanWaterTempleLowFromHigh && (logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW));}}), - }); - - areaTable[RR_WATER_TEMPLE_MAP_ROOM] = Region("Water Temple Map Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_WATER_TEMPLE_MAP_CHEST, (logic->CanUse(RG_MAGIC_SINGLE) && logic->CanUse(RG_KOKIRI_SWORD)) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_HOOKSHOT)), - }, { - //Exits - Entrance(RR_WATER_TEMPLE_EAST_LOWER, {[]{return (logic->CanUse(RG_MAGIC_SINGLE) && logic->CanUse(RG_KOKIRI_SWORD)) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_HOOKSHOT);}}), - }); - - areaTable[RR_WATER_TEMPLE_CRACKED_WALL] = Region("Water Temple Cracked Wall", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_WATER_TEMPLE_CRACKED_WALL_CHEST, logic->HasExplosives()), - }, { - //Exits - Entrance(RR_WATER_TEMPLE_EAST_LOWER, {[]{return true;}}), - }); - - areaTable[RR_WATER_TEMPLE_TORCH_ROOM] = Region("Water Temple Torch Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_WATER_TEMPLE_TORCHES_CHEST, (logic->CanUse(RG_MAGIC_SINGLE) && logic->CanUse(RG_KOKIRI_SWORD)) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_HOOKSHOT)), - }, { - //Exits - Entrance(RR_WATER_TEMPLE_EAST_LOWER, {[]{return (logic->CanUse(RG_MAGIC_SINGLE) && logic->CanUse(RG_KOKIRI_SWORD)) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_HOOKSHOT);}}), - }); - - areaTable[RR_WATER_TEMPLE_NORTH_LOWER] = Region("Water Temple North Lower", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_WATER_TEMPLE_LOBBY, {[]{return true;}}), - Entrance(RR_WATER_TEMPLE_BOULDERS_LOWER, {[]{return (logic->CanUse(RG_LONGSHOT) || (ctx->GetTrickOption(RT_WATER_BK_REGION) && logic->CanUse(RG_HOVER_BOOTS))) && logic->SmallKeys(RR_WATER_TEMPLE, 4);}}), - }); - - areaTable[RR_WATER_TEMPLE_BOULDERS_LOWER] = Region("Water Temple Boulders Lower", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_WATER_TEMPLE_GS_NEAR_BOSS_KEY_CHEST, logic->CanUse(RG_LONGSHOT) || Here(RR_WATER_TEMPLE_BOULDERS_UPPER, []{return (logic->IsAdult && logic->HookshotOrBoomerang()) || (logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT));})), - }, { - //Exits - Entrance(RR_WATER_TEMPLE_NORTH_LOWER, {[]{return logic->SmallKeys(RR_WATER_TEMPLE, 4);}}), - Entrance(RR_WATER_TEMPLE_BLOCK_ROOM, {[]{return true;}}), - Entrance(RR_WATER_TEMPLE_BOULDERS_UPPER, {[]{return (logic->IsAdult && (logic->CanUse(RG_HOVER_BOOTS) || ctx->GetTrickOption(RT_WATER_NORTH_BASEMENT_LEDGE_JUMP))) || (logic->CanUse(RG_HOVER_BOOTS) && logic->CanUse(RG_IRON_BOOTS));}}), - }); - - areaTable[RR_WATER_TEMPLE_BLOCK_ROOM] = Region("Water Temple Block Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_WATER_TEMPLE_BASEMENT_BLOCK_PUZZLE_POT_1, logic->CanBreakPots()), - LOCATION(RC_WATER_TEMPLE_BASEMENT_BLOCK_PUZZLE_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_WATER_TEMPLE_BOULDERS_LOWER, {[]{return (logic->HasItem(RG_GORONS_BRACELET) && logic->HasExplosives()) || logic->CanUse(RG_HOOKSHOT);}}), - Entrance(RR_WATER_TEMPLE_JETS_ROOM, {[]{return (logic->HasItem(RG_GORONS_BRACELET) && logic->HasExplosives()) || (logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_HOVER_BOOTS));}}), - }); - - areaTable[RR_WATER_TEMPLE_JETS_ROOM] = Region("Water Temple Jets Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_WATER_TEMPLE_BLOCK_ROOM, {[]{return logic->CanUse(RG_HOOKSHOT);}}), - Entrance(RR_WATER_TEMPLE_BOULDERS_UPPER, {[]{return true;}}), - }); - - areaTable[RR_WATER_TEMPLE_BOULDERS_UPPER] = Region("Water Temple Boulders Upper", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_WATER_TEMPLE_BOULDERS_LOWER, {[]{return true;}}), - Entrance(RR_WATER_TEMPLE_JETS_ROOM, {[]{return logic->IsAdult;}}), - Entrance(RR_WATER_TEMPLE_BOSS_KEY_ROOM, {[]{return (logic->CanUse(RG_IRON_BOOTS) || (logic->IsAdult && ctx->GetTrickOption(RT_WATER_BK_JUMP_DIVE))) && logic->SmallKeys(RR_WATER_TEMPLE, 5);}}), - }); - - areaTable[RR_WATER_TEMPLE_BOSS_KEY_ROOM] = Region("Water Temple Boss Key Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->FairyPot, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_WATER_TEMPLE_BOSS_KEY_CHEST, true), - LOCATION(RC_WATER_TEMPLE_BOSS_KEY_POT_1, logic->CanBreakPots()), - LOCATION(RC_WATER_TEMPLE_BOSS_KEY_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_WATER_TEMPLE_BOULDERS_UPPER, {[]{return (logic->CanUse(RG_IRON_BOOTS) || (logic->IsAdult && ctx->GetTrickOption(RT_WATER_BK_JUMP_DIVE)) || logic->IsChild || logic->HasItem(RG_SILVER_SCALE)) && logic->SmallKeys(RR_WATER_TEMPLE, 5);}}), - }); - - areaTable[RR_WATER_TEMPLE_SOUTH_LOWER] = Region("Water Temple South Lower", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_WATER_TEMPLE_GS_BEHIND_GATE, logic->CanJumpslash() && (logic->CanUse(RG_HOOKSHOT) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)))), - LOCATION(RC_WATER_TEMPLE_BEHIND_GATE_POT_1, logic->CanJumpslash() && (logic->CanUse(RG_HOOKSHOT) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)))), - LOCATION(RC_WATER_TEMPLE_BEHIND_GATE_POT_2, logic->CanJumpslash() && (logic->CanUse(RG_HOOKSHOT) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)))), - LOCATION(RC_WATER_TEMPLE_BEHIND_GATE_POT_3, logic->CanJumpslash() && (logic->CanUse(RG_HOOKSHOT) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)))), - LOCATION(RC_WATER_TEMPLE_BEHIND_GATE_POT_4, logic->CanJumpslash() && (logic->CanUse(RG_HOOKSHOT) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)))), - }, { - //Exits - Entrance(RR_WATER_TEMPLE_LOBBY, {[]{return logic->CanUse(RG_IRON_BOOTS);}}), - }); - - areaTable[RR_WATER_TEMPLE_WEST_LOWER] = Region("Water Temple West Lower", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_WATER_TEMPLE_LOBBY, {[]{return logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_IRON_BOOTS) && logic->HasItem(RG_GORONS_BRACELET);}}), - Entrance(RR_WATER_TEMPLE_DRAGON_ROOM, {[]{return logic->CanJumpslashExceptHammer() || logic->CanUseProjectile();}}), - }); - - areaTable[RR_WATER_TEMPLE_DRAGON_ROOM] = Region("Water Temple Dragon Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_WATER_TEMPLE_DRAGON_CHEST, (logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_IRON_BOOTS)) || (((logic->IsAdult && ctx->GetTrickOption(RT_WATER_ADULT_DRAGON) && (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_BOMBCHU_5))) || (logic->IsChild && ctx->GetTrickOption(RT_WATER_CHILD_DRAGON) && (logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_BOOMERANG) || logic->CanUse(RG_BOMBCHU_5)))) && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS))) || - Here(RR_WATER_TEMPLE_RIVER, []{return logic->IsAdult && logic->CanUse(RG_FAIRY_BOW) && ((ctx->GetTrickOption(RT_WATER_ADULT_DRAGON) && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS))) || ctx->GetTrickOption(RT_WATER_DRAGON_JUMP_DIVE));})), - }, { - //Exits - Entrance(RR_WATER_TEMPLE_WEST_LOWER, {[]{return true;}}), - }); - - areaTable[RR_WATER_TEMPLE_CENTRAL_PILLAR_LOWER] = Region("Water Temple Central Pillar Lower", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_WATER_TEMPLE_LOBBY, {[]{return logic->SmallKeys(RR_WATER_TEMPLE, 5);}}), - Entrance(RR_WATER_TEMPLE_CENTRAL_PILLAR_UPPER, {[]{return logic->CanUse(RG_HOOKSHOT);}}), - Entrance(RR_WATER_TEMPLE_CENTRAL_PILLAR_BASEMENT, {[]{return logic->CanWaterTempleMiddle && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 40;}}), - }); - - areaTable[RR_WATER_TEMPLE_CENTRAL_PILLAR_UPPER] = Region("Water Temple Central Pillar Upper", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->CanWaterTempleMiddle, {[]{return logic->CanWaterTempleMiddle || logic->CanUse(RG_ZELDAS_LULLABY);}}), - }, { - //Locations - LOCATION(RC_WATER_TEMPLE_GS_CENTRAL_PILLAR, logic->CanUse(RG_LONGSHOT) || (((ctx->GetTrickOption(RT_WATER_FW_CENTRAL_GS) && logic->CanUse(RG_FARORES_WIND) && (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_DINS_FIRE) || logic->SmallKeys(RR_WATER_TEMPLE, 5))) || (ctx->GetTrickOption(RT_WATER_IRONS_CENTRAL_GS) && logic->CanUse(RG_IRON_BOOTS) && ((logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_FAIRY_BOW)) || (logic->CanUse(RG_DINS_FIRE))))) && logic->CanWaterTempleHigh && logic->HookshotOrBoomerang())), - }, { - //Exits - Entrance(RR_WATER_TEMPLE_LOBBY, {[]{return true;}}), - Entrance(RR_WATER_TEMPLE_CENTRAL_PILLAR_LOWER, {[]{return true;}}), - }); - - areaTable[RR_WATER_TEMPLE_CENTRAL_PILLAR_BASEMENT] = Region("Water Temple Central Pillar Basement", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_WATER_TEMPLE_CENTRAL_PILLAR_CHEST, logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 40), - }, { - //Exits - Entrance(RR_WATER_TEMPLE_CENTRAL_PILLAR_LOWER, {[]{return logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16;}}), - }); - - areaTable[RR_WATER_TEMPLE_EAST_MIDDLE] = Region("Water Temple East Middle", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_WATER_TEMPLE_COMPASS_CHEST, logic->CanUseProjectile()), - LOCATION(RC_WATER_TEMPLE_NEAR_COMPASS_POT_1, logic->CanBreakPots()), - LOCATION(RC_WATER_TEMPLE_NEAR_COMPASS_POT_2, logic->CanBreakPots()), - LOCATION(RC_WATER_TEMPLE_NEAR_COMPASS_POT_3, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_WATER_TEMPLE_LOBBY, {[]{return logic->CanUse(RG_IRON_BOOTS);}}), - }); - - areaTable[RR_WATER_TEMPLE_WEST_MIDDLE] = Region("Water Temple West Middle", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_WATER_TEMPLE_LOBBY, {[]{return true;}}), - Entrance(RR_WATER_TEMPLE_HIGH_WATER, {[]{return logic->CanUseProjectile();}}), - }); - - areaTable[RR_WATER_TEMPLE_HIGH_WATER] = Region("Water Temple High Water", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->CanWaterTempleHigh, {[]{return logic->CanWaterTempleHigh || logic->CanUse(RG_ZELDAS_LULLABY);}}), - }, {}, { - //Exits - Entrance(RR_WATER_TEMPLE_LOBBY, {[]{return true;}}), - }); - - areaTable[RR_WATER_TEMPLE_BLOCK_CORRIDOR] = Region("Water Temple Block Corridor", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_WATER_TEMPLE_CENTRAL_BOW_TARGET_CHEST, logic->HasItem(RG_GORONS_BRACELET) && (logic->CanWaterTempleLowFromHigh || logic->CanWaterTempleMiddle)), - LOCATION(RC_WATER_TEMPLE_CENTRAL_BOW_POT_1, logic->CanBreakPots() && logic->HasItem(RG_GORONS_BRACELET) && (logic->CanWaterTempleLowFromHigh || logic->CanWaterTempleMiddle)), - LOCATION(RC_WATER_TEMPLE_CENTRAL_BOW_POT_2, logic->CanBreakPots() && logic->HasItem(RG_GORONS_BRACELET) && (logic->CanWaterTempleLowFromHigh || logic->CanWaterTempleMiddle)), - }, { - //Exits - Entrance(RR_WATER_TEMPLE_LOBBY, {[]{return logic->CanUse(RG_HOOKSHOT);}}), - }); - - areaTable[RR_WATER_TEMPLE_FALLING_PLATFORM_ROOM] = Region("Water Temple Falling Platform Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_WATER_TEMPLE_GS_FALLING_PLATFORM_ROOM, logic->CanUse(RG_LONGSHOT) || (ctx->GetTrickOption(RT_WATER_RANG_FALLING_PLATFORM_GS) && logic->IsChild && logic->CanUse(RG_BOOMERANG)) || (ctx->GetTrickOption(RT_WATER_HOOKSHOT_FALLING_PLATFORM_GS) && logic->IsAdult && logic->CanUse(RG_HOOKSHOT))), - }, { - //Exits - Entrance(RR_WATER_TEMPLE_LOBBY, {[]{return logic->CanUse(RG_HOOKSHOT) && logic->SmallKeys(RR_WATER_TEMPLE, 4);}}), - Entrance(RR_WATER_TEMPLE_DRAGON_PILLARS_ROOM, {[]{return logic->CanUse(RG_HOOKSHOT) && logic->SmallKeys(RR_WATER_TEMPLE, 5);}}), - }); - - areaTable[RR_WATER_TEMPLE_DRAGON_PILLARS_ROOM] = Region("Water Temple Dragon Pillars Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_WATER_TEMPLE_LIKE_LIKE_POT_1, logic->CanUse(RG_HOOKSHOT)), - LOCATION(RC_WATER_TEMPLE_LIKE_LIKE_POT_2, logic->CanUse(RG_HOOKSHOT)), - }, { - //Exits - Entrance(RR_WATER_TEMPLE_FALLING_PLATFORM_ROOM, {[]{return logic->CanUseProjectile();}}), - Entrance(RR_WATER_TEMPLE_DARK_LINK_ROOM, {[]{return logic->CanUse(RG_HOOKSHOT);}}), - }); - - areaTable[RR_WATER_TEMPLE_DARK_LINK_ROOM] = Region("Water Temple Dark Link Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_WATER_TEMPLE_DRAGON_PILLARS_ROOM, {[]{return logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD);}}), - Entrance(RR_WATER_TEMPLE_LONGSHOT_ROOM, {[]{return logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD);}}), - }); - - areaTable[RR_WATER_TEMPLE_LONGSHOT_ROOM] = Region("Water Temple Longshot Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_WATER_TEMPLE_LONGSHOT_CHEST, true), - }, { - //Exits - Entrance(RR_WATER_TEMPLE_DARK_LINK_ROOM, {[]{return true;}}), - Entrance(RR_WATER_TEMPLE_RIVER, {[]{return logic->IsChild || logic->CanUse(RG_SONG_OF_TIME);}}), - }); - - areaTable[RR_WATER_TEMPLE_RIVER] = Region("Water Temple River", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_WATER_TEMPLE_RIVER_CHEST, (logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_FAIRY_BOW)) && (logic->IsAdult || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT))), - LOCATION(RC_WATER_TEMPLE_GS_RIVER, (logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT)) || (ctx->GetTrickOption(RT_WATER_RIVER_GS) && logic->CanUse(RG_LONGSHOT))), - LOCATION(RC_WATER_TEMPLE_RIVER_POT_1, logic->CanBreakPots()), - LOCATION(RC_WATER_TEMPLE_RIVER_POT_2, logic->CanBreakPots()), - LOCATION(RC_WATER_TEMPLE_RIVER_HEART_1, (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16) || logic->HasItem(RG_BRONZE_SCALE)), - LOCATION(RC_WATER_TEMPLE_RIVER_HEART_2, (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16) || logic->HasItem(RG_BRONZE_SCALE)), - LOCATION(RC_WATER_TEMPLE_RIVER_HEART_3, (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16) || logic->HasItem(RG_BRONZE_SCALE)), - LOCATION(RC_WATER_TEMPLE_RIVER_HEART_4, (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 24) || logic->HasItem(RG_BRONZE_SCALE)), - }, { - //Exits - Entrance(RR_WATER_TEMPLE_DRAGON_ROOM, {[]{return (logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_FAIRY_BOW)) && (logic->IsAdult || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT));}}), - }); - - areaTable[RR_WATER_TEMPLE_PRE_BOSS_ROOM] = Region("Water Temple Pre Boss Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->FairyPot, {[]{return true;}}), - }, { - // Locations - LOCATION(RC_WATER_TEMPLE_MAIN_LEVEL_1_POT_1, logic->CanBreakPots()), - LOCATION(RC_WATER_TEMPLE_MAIN_LEVEL_1_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_WATER_TEMPLE_LOBBY, {[]{return true;}}), - Entrance(RR_WATER_TEMPLE_BOSS_ENTRYWAY, {[]{return logic->HasItem(RG_WATER_TEMPLE_BOSS_KEY);}}), - }); - } - - /*--------------------------- - | MASTER QUEST DUNGEON | - ---------------------------*/ - if (ctx->GetDungeon(WATER_TEMPLE)->IsMQ()) { - areaTable[RR_WATER_TEMPLE_MQ_3F_SOUTH_LEDGE] = Region("Water Temple MQ 3F South Ledge", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_WATER_TEMPLE_ENTRYWAY, {[]{return logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS);}}), - Entrance(RR_WATER_TEMPLE_MQ_MAIN, {[]{return true;}}), - //If we are not on WL_HIGH, we reach RR_WATER_TEMPLE_MQ_3F_MAIN with hookshot via 2F, otherwise we can reach the platform - Entrance(RR_WATER_TEMPLE_MQ_3F_CENTRAL, {[]{return logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS);}}), - Entrance(RR_WATER_TEMPLE_MQ_2F_CENTRAL, {[]{return logic->MQWaterLevel(WL_LOW_OR_MID);}}), - }); - -//This region covers simply existing in the area around the central pillar without being on a specific platform, either swimming or walking on the lakebed -//Entry should only include being in the correct area, taking any possible fall damage, and floating up to the surface of WL_HIGH if coming from below -//This area then leads to others based on level and worst-case water timers for follow-up exits from the water's surface -//remember that any solution that works for any level doesn't need to be given a level, even if that solution is overkill for a lower level - areaTable[RR_WATER_TEMPLE_MQ_MAIN] = Region("Water Temple MQ Main", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_WATER_TEMPLE_MQ_3F_SOUTH_LEDGE, {[]{return logic->HasItem(RG_BRONZE_SCALE) && logic->MQWaterLevel(WL_HIGH);}}), - //Jumping across is possible but a trick due to the janky ledge - Entrance(RR_WATER_TEMPLE_MQ_EAST_TOWER, {[]{return (logic->WaterTimer() >= 24 && logic->CanUse(RG_IRON_BOOTS)) || - (logic->MQWaterLevel(WL_MID) && logic->HasItem(RG_GOLDEN_SCALE) && logic->WaterTimer() >= 16) || - logic->MQWaterLevel(WL_LOW);}}), - Entrance(RR_WATER_TEMPLE_MQ_3F_CENTRAL, {[]{return logic->MQWaterLevel(WL_HIGH) && logic->HasItem(RG_BRONZE_SCALE);}}), - //First water timer uses the hook to go from the top of center to storage room/central pillar as coming from the bottom - //Second water timer is simply diving down and entering the door as fast as possible from the surface - Entrance(RR_WATER_TEMPLE_MQ_2F_CENTRAL, {[]{return ((logic->MQWaterLevel(WL_LOW) || (logic->CanUse(RG_IRON_BOOTS) && (logic->MQWaterLevel(WL_MID) || logic->WaterTimer() >= 16))) && logic->CanUse(RG_LONGSHOT)) || - ((logic->MQWaterLevel(WL_MID) || (logic->MQWaterLevel(WL_HIGH_OR_MID) && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8)) && logic->HasItem(RG_BRONZE_SCALE));}}), - Entrance(RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_1F, {[]{return logic->MQWaterLevel(WL_LOW);}}), - //A special entry as we can't set it to high after entering at a lower height - Entrance(RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_HIGH, {[]{return logic->MQWaterLevel(WL_HIGH) && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && (logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_LONGSHOT));}}), - Entrance(RR_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY, {[]{return (logic->MQWaterLevel(WL_MID) || (logic->MQWaterLevel(WL_HIGH_OR_MID) && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16)) && logic->HasItem(RG_BRONZE_SCALE);}}), - Entrance(RR_WATER_TEMPLE_MQ_B1_GATE_SWITCH, {[]{return logic->MQWaterB1Switch && (logic->MQWaterLevel(WL_LOW) || ((logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 24) && logic->HasItem(RG_BRONZE_SCALE)));}}), - Entrance(RR_WATER_TEMPLE_MQ_TRIANGLE_TORCH_ROOM, {[]{return logic->MQWaterB1Switch && - ((logic->MQWaterLevel(WL_LOW) && logic->HasItem(RG_SILVER_SCALE)) || - (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && (logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_LONGSHOT))));}}), - //Adult needs to jump in instead of dive for swim access, but you just hold forward. RT_WATER_BK_REGION Isn't relevant unless the Dark Link loop can be done without longshot with other tricks - Entrance(RR_WATER_TEMPLE_MQ_CRATES_WHIRLPOOLS_ROOM, {[]{return logic->MQWaterB1Switch && - ((logic->MQWaterLevel(WL_LOW) && logic->HasItem(RG_BRONZE_SCALE)) || (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && logic->CanUse(RG_HOOKSHOT))) && - (logic->CanUse(RG_LONGSHOT) || (ctx->GetTrickOption(RT_WATER_BK_REGION) && logic->CanUse(RG_HOVER_BOOTS)));}}), - }); - -//This region specifically covers the topmost platform around central pillar - areaTable[RR_WATER_TEMPLE_MQ_3F_CENTRAL] = Region("Water Temple MQ 3F Central", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_WATER_TEMPLE_MQ_MAIN, {[]{return true;}}), - Entrance(RR_WATER_TEMPLE_MQ_3F_SOUTH_LEDGE, {[]{return logic->CanUse(RG_LONGSHOT) || logic->CanUse(RG_HOVER_BOOTS);}}), - Entrance(RR_WATER_TEMPLE_MQ_2F_CENTRAL, {[]{return (logic->MQWaterLevel(WL_LOW_OR_MID) || (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16)) && logic->CanUse(RG_HOOKSHOT);}}), - Entrance(RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_HIGH, {[]{return logic->MQWaterLevel(WL_HIGH) && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && logic->CanUse(RG_HOOKSHOT);}}), - Entrance(RR_WATER_TEMPLE_MQ_3F_NORTH_LEDGE, {[]{return (logic->MQWaterLevel(WL_HIGH) && logic->CanUse(RG_LONGSHOT)) || (ctx->GetTrickOption(RT_HOVER_BOOST_SIMPLE) && ctx->GetTrickOption(RT_DAMAGE_BOOST_SIMPLE) && logic->HasExplosives() && logic->CanUse(RG_HOVER_BOOTS));}}), - //Jumping across is possible but a trick due to the janky ledge - Entrance(RR_WATER_TEMPLE_MQ_HIGH_EMBLEM, {[]{return logic->CanUse(RG_HOOKSHOT) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS));}}), - //room access is (logic->IsAdult || (logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT))) - Entrance(RR_WATER_TEMPLE_MQ_WATERFALL, {[]{return logic->SmallKeys(RR_WATER_TEMPLE, 1) && logic->MQWaterLevel(WL_HIGH) && logic->CanUse(RG_LONGSHOT);}}), - //this swimless jump with irons may be a trick as you have to put irons on quite late. - Entrance(RR_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY, {[]{return (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16) || logic->MQWaterLevel(WL_LOW_OR_MID);}}), - }); - -//This region specifically covers walking on the lower platform around central pillar. This is underwater when WL_HIGH -//RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_HIGH should be accessed directly to use the central pillar door while at WL_HIGH - areaTable[RR_WATER_TEMPLE_MQ_2F_CENTRAL] = Region("Water Temple MQ 2F Central", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_WATER_TEMPLE_MQ_MAIN, {[]{return true;}}), - Entrance(RR_WATER_TEMPLE_MQ_3F_CENTRAL, {[]{return logic->CanUse(RG_HOOKSHOT);}}), - Entrance(RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_2F, {[]{return logic->MQWaterLevel(WL_LOW_OR_MID);}}), - Entrance(RR_WATER_TEMPLE_MQ_STORAGE_ROOM, {[]{return logic->CanUse(RG_HOOKSHOT);}}), - Entrance(RR_WATER_TEMPLE_MQ_BEHIND_BLUE_SWITCH_2F, {[]{return logic->MQWaterLevel(WL_LOW_OR_MID) && (logic->IsAdult || logic->CanUse(RG_HOVER_BOOTS)) && logic->CanUse(RG_HOOKSHOT);}}), - Entrance(RR_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY, {[]{return logic->MQWaterLevel(WL_LOW_OR_MID) && logic->CanUse(RG_HOVER_BOOTS);}}), - }); - - areaTable[RR_WATER_TEMPLE_MQ_HIGH_EMBLEM] = Region("Water Temple MQ High Emblem", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->ReachedWaterHighEmblem, {[]{return true;}}), - EventAccess(&logic->CanWaterTempleHigh, {[]{return logic->CanUse(RG_ZELDAS_LULLABY);}}), - }, {}, { - //Exits - Entrance(RR_WATER_TEMPLE_MQ_3F_CENTRAL, {[]{return true;}}), - Entrance(RR_WATER_TEMPLE_MQ_MAIN, {[]{return true;}}), - }); - - areaTable[RR_WATER_TEMPLE_MQ_3F_NORTH_LEDGE] = Region("Water Temple MQ 3F North Ledge", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - //what we need if WL_LOW, we can't guarantee repeated access otherwise. - Entrance(RR_WATER_TEMPLE_MQ_MAIN, {[]{return logic->HasItem(RG_BRONZE_SCALE) || logic->TakeDamage();}}), - Entrance(RR_WATER_TEMPLE_MQ_3F_CENTRAL, {[]{return logic->CanUse(RG_LONGSHOT);}}), - Entrance(RR_WATER_TEMPLE_MQ_BOSS_DOOR, {[]{return logic->CanUse(RG_LONGSHOT) || logic->CanUse(RG_ICE_ARROWS) || logic->CanUse(RG_NAYRUS_LOVE);}}), - }); - - areaTable[RR_WATER_TEMPLE_MQ_BOSS_DOOR] = Region("Water Temple MQ Main", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_WATER_TEMPLE_MQ_3F_NORTH_LEDGE, {[]{return logic->CanUse(RG_ICE_ARROWS) || logic->TakeDamage();}}), - Entrance(RR_WATER_TEMPLE_BOSS_ENTRYWAY, {[]{return logic->HasItem(RG_WATER_TEMPLE_BOSS_KEY);}}), - }); - - areaTable[RR_WATER_TEMPLE_MQ_EAST_TOWER] = Region("Water Temple MQ East Tower", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - //if we can't reach these, we can't move the water at all, so no need to specify level or account for WL_LOW access here - //review is some way to play ocarina underwater exists - EventAccess(&logic->CouldWaterTempleLow, {[]{return true;}}), - EventAccess(&logic->CanWaterTempleLowFromHigh, {[]{return logic->CanUse(RG_ZELDAS_LULLABY);}}), - //Reserved for glitches/tricks that could do this - //EventAccess(&logic->CanWaterTempleLowFromMid, {[]{return false;}}), - }, { - //Locations - LOCATION(RC_WATER_TEMPLE_MQ_MAP_CHEST, logic->MQWaterLevel(WL_HIGH) && logic->HasFireSource() && logic->CanUse(RG_HOOKSHOT)), - //easy to get at WL_HIGH with the hook-the-underwater-chest glitch - LOCATION(RC_WATER_TEMPLE_MQ_LONGSHOT_CHEST, logic->MQWaterLevel(WL_MID) && logic->CanUse(RG_HOOKSHOT)), - LOCATION(RC_WATER_TEMPLE_MQ_LOWER_TORCHES_POT_1, (logic->MQWaterLevel(WL_LOW) && logic->CanBreakPots()) || - (logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT) && logic->WaterTimer() >= 16)), - LOCATION(RC_WATER_TEMPLE_MQ_LOWER_TORCHES_POT_2, (logic->MQWaterLevel(WL_LOW) && logic->CanBreakPots()) || - (logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT) && logic->WaterTimer() >= 16)), - }, { - Entrance(RR_WATER_TEMPLE_MQ_EAST_TOWER_1F_ROOM, {[]{return logic->MQWaterLevel(WL_LOW) && (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_DINS_FIRE) || logic->CanUse(RG_STICKS));}}), - }); - - //Raising the targets by clearing this room achieves nothing logically because it requires WL_LOW to do and hookshot to use, which implies access to WL_MID and WL_HIGH already - areaTable[RR_WATER_TEMPLE_MQ_EAST_TOWER_1F_ROOM] = Region("Water Temple MQ East Tower 1F Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_WATER_TEMPLE_MQ_COMPASS_CHEST, logic->CanKillEnemy(RE_LIZALFOS) && logic->CanKillEnemy(RE_SPIKE)), - }, { - Entrance(RR_WATER_TEMPLE_MQ_EAST_TOWER, {[]{return true;}}), - }); - -//This area assumes we entered through the lower door, so water is low and cannot be changed without leaving. - areaTable[RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_1F] = Region("Water Temple MQ Central Pillar 1F", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - //This is harder than the other possibilities as you have to move between shots on top of the extra range, but there's basically no universe this should matter. - EventAccess(&logic->MQWaterB1Switch, {[]{return ctx->GetTrickOption(RT_WATER_MQ_CENTRAL_PILLAR) && logic->CanUse(RG_FIRE_ARROWS);}}), - }, {}, { - //Exits - Entrance(RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_HIGH, {[]{return logic->MQWaterLevel(WL_HIGH) && ctx->GetTrickOption(RT_WATER_FW_CENTRAL_GS) && logic->CanUse(RG_FARORES_WIND) && logic->HasItem(RG_BRONZE_SCALE);}}), - //I don't know if this FW trick can ever matter but maybe it's needed to get child to CENTRAL_2F or something - Entrance(RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_2F, {[]{return logic->CanUse(RG_HOOKSHOT) || - (logic->MQWaterLevel(WL_MID) && ctx->GetTrickOption(RT_WATER_FW_CENTRAL_GS) && logic->CanUse(RG_FARORES_WIND) && logic->HasItem(RG_BRONZE_SCALE));}}), - //if the gate is open, you sink straight in, so you can't climb up this way in logic without swimming - Entrance(RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_B1, {[]{return logic->MQWaterOpenedPillarB1 && logic->MQWaterLevel(WL_HIGH_OR_MID) && - ctx->GetTrickOption(RT_WATER_FW_CENTRAL_GS) && logic->CanUse(RG_FARORES_WIND) && - logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_ZORA_TUNIC);}}), - }); - -//If we enter here in WL_HIGH, go to RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_HIGH instead, Assumes WL_MID_OR_LOW - areaTable[RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_2F] = Region("Water Temple MQ Central Pillar 2F", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->CouldWaterTempleMiddle, {[]{return true;}}), - EventAccess(&logic->CanWaterTempleMiddle, {[]{return logic->CanUse(RG_ZELDAS_LULLABY);}}), - //It's possible to do this even on low water, but more awkward. I'm not sure if it's even possible for it to be relevant though. - EventAccess(&logic->MQWaterOpenedPillarB1, {[]{return ctx->GetTrickOption(RT_WATER_MQ_CENTRAL_PILLAR) && logic->CanUse(RG_FIRE_ARROWS);}}), - //this could theoretically matter once OI and equip swap is in logic, as one age may be able to get here dry and not wet, and the other may not be able to OI, but as you can OI with hookshot it probably never happens - //EventAccess(&logic->MQWaterPillarSoTBlock, {[]{return logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_SONG_OF_TIME);}}), - }, {}, { - //Exits - Entrance(RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_HIGH, {[]{return logic->MQWaterLevel(WL_HIGH) && logic->CanUse(RG_FARORES_WIND) && (logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS));}}), - Entrance(RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_B1, {[]{return logic->MQWaterOpenedPillarB1 && logic->MQWaterLevel(WL_MID) && logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_ZORA_TUNIC);}}), - }); - - areaTable[RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_HIGH] = Region("Water Temple MQ Central Pillar High", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->MQWaterOpenedPillarB1, {[]{return ((logic->CanUse(RG_SONG_OF_TIME) && logic->CanUse(RG_DINS_FIRE)) || (ctx->GetTrickOption(RT_WATER_MQ_CENTRAL_PILLAR) && logic->CanUse(RG_FIRE_ARROWS))) && - (logic->HasItem(RG_BRONZE_SCALE) || (logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_LONGSHOT) && logic->CanJumpslash()));}}), - }, {}, { - //Exits - Entrance(RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_B1, {[]{return logic->MQWaterB1Switch && logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_ZORA_TUNIC);}}), - }); - -//Assuming tunic and irons was checked on entry - areaTable[RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_B1] = Region("Water Temple MQ Central Pillar B1", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - //Can't know water level, so we'll just assume any possibility and skip to MAIN - Entrance(RR_WATER_TEMPLE_MQ_MAIN, {[]{return logic->MQWaterOpenedPillarB1 && logic->CanUse(RG_IRON_BOOTS) && logic->HasItem(RG_BRONZE_SCALE);}}), - //Child needs to release irons for height to push down the larger "peg", however they can push the lower one down by climbing and then hit the switch through the larger peg, but it's a trick - Entrance(RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_B1_FINAL, {[]{return ((logic->IsAdult && logic->CanUse(RG_LONGSHOT)) || (logic->CanUse(RG_HOOKSHOT) && logic->HasItem(RG_BRONZE_SCALE)));}}), - }); - - areaTable[RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_B1_FINAL] = Region("Water Temple MQ Central Pillar B1 Final", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_CHEST, logic->CanUse(RG_HOOKSHOT)), - }, {}); - -//Region exists to add crate/pot/box locations - areaTable[RR_WATER_TEMPLE_MQ_STORAGE_ROOM] = Region("Water Temple MQ Storage Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_POT_1, logic->CanBreakPots()), - LOCATION(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_POT_2, logic->CanBreakPots()), - LOCATION(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_POT_3, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_WATER_TEMPLE_MQ_MAIN, {[]{return logic->MQWaterLevel(WL_LOW_OR_MID) || (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8);}}), - }); - - areaTable[RR_WATER_TEMPLE_MQ_BEHIND_BLUE_SWITCH_2F] = Region("Water Temple MQ Behind Blue Switch 2F", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_POT_1, logic->CanBreakPots()), - LOCATION(RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_POT_2, logic->CanBreakPots()), - LOCATION(RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_POT_3, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_WATER_TEMPLE_MQ_MAIN, {[]{return true;}}), - Entrance(RR_WATER_TEMPLE_MQ_BEHIND_BLUE_SWITCH_3F, {[]{return logic->CanUse(RG_LONGSHOT);}}), - }); - - areaTable[RR_WATER_TEMPLE_MQ_BEHIND_BLUE_SWITCH_3F] = Region("Water Temple MQ Behind Blue Switch 2F", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_WATER_TEMPLE_MQ_GS_BEFORE_UPPER_WATER_SWITCH, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)), - }, { - //Exits - Entrance(RR_WATER_TEMPLE_MQ_BEHIND_BLUE_SWITCH_2F, {[]{return true;}}), - Entrance(RR_WATER_TEMPLE_MQ_HIGH_EMBLEM, {[]{return true;}}), - }); - - areaTable[RR_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY] = Region("Water Temple MQ Lizalfos Hallway", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_WEST_POT, logic->CanBreakPots()), - LOCATION(RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_SOUTH_POT, logic->CanBreakPots()), - LOCATION(RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_SE_POT, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_WATER_TEMPLE_MQ_LIZALFOS_CAGE, {[]{return logic->MQWaterLevel(WL_LOW_OR_MID) && logic->CanUse(RG_DINS_FIRE);}}), - //this technically exists, but only complicates things, uncomment if some edge case/glitch can use RR_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY to reach RR_WATER_TEMPLE_MQ_3F_CENTRAL, or if a void warp goes here - /*Entrance(RR_WATER_TEMPLE_MQ_3F_EAST_LEDGE, {[]{return (logic->CanUse(RG_HOOKSHOT) && (logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS))) || - (logic->MQWaterLevel(WL_LOW_OR_MID) && logic->CanUse(RG_HOOKSHOT)) || - logic->MQWaterLevel(WL_HIGH) && (logic->HasItem(RG_BRONZE_SCALE));}}), - }); - - areaTable[RR_WATER_TEMPLE_MQ_3F_EAST_LEDGE] = Region("Water Temple MQ 3F East Ledge", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_WATER_TEMPLE_MQ_MAIN, {[]{return true;}}), - Entrance(RR_WATER_TEMPLE_MQ_3F_CENTRAL, {[]{return logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS);}}),*/ - }); - - areaTable[RR_WATER_TEMPLE_MQ_LIZALFOS_CAGE] = Region("Water Temple MQ Lizalfos Cage", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_WATER_TEMPLE_MQ_GS_LIZALFOS_HALLWAY, logic->CanKillEnemy(RE_GOLD_SKULLTULA)), - LOCATION(RC_WATER_TEMPLE_MQ_LIZALFOS_CAGE_SOUTH_POT, logic->CanBreakPots()), - LOCATION(RC_WATER_TEMPLE_MQ_LIZALFOS_CAGE_NORTH_POT, logic->CanBreakPots()), - }, {}); - -//This room exists to hold the wonderitems that drop from the emblems here. Specifically this assumes you are standing on the final ledge - areaTable[RR_WATER_TEMPLE_MQ_WATERFALL] = Region("Water Temple Waterfall", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_WATER_TEMPLE_MQ_3F_CENTRAL, {[]{return logic->SmallKeys(RR_WATER_TEMPLE, 1) && logic->CanUse(RG_LONGSHOT);}}), - Entrance(RR_WATER_TEMPLE_MQ_STALFOS_PIT, {[]{return true;}}), - Entrance(RR_WATER_TEMPLE_MQ_STALFOS_PIT_POTS, {[]{return (logic->MQWaterStalfosPit && logic->IsAdult && logic->CanUse(RG_HOOKSHOT)) || logic->CanUse(RG_HOVER_BOOTS);}}), - Entrance(RR_WATER_TEMPLE_MQ_STALFOS_PIT_UPPER, {[]{return logic->MQWaterStalfosPit && logic->CanUse(RG_LONGSHOT);}}), - }); - - areaTable[RR_WATER_TEMPLE_MQ_STALFOS_PIT] = Region("Water Temple MQ Stalfos Pit", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->MQWaterStalfosPit, {[]{return ((logic->IsAdult && logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 3, false, true)) || - (logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT) && logic->CanKillEnemy(RE_STALFOS, ED_BOMB_THROW, true, 3, false, true)));}}), - }, {}, { - //Exits - Entrance(RR_WATER_TEMPLE_MQ_WATERFALL, {[]{return logic->MQWaterStalfosPit && logic->CanUse(RG_HOOKSHOT) && (logic->IsAdult || logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8);}}), - Entrance(RR_WATER_TEMPLE_MQ_STALFOS_PIT_POTS, {[]{return (logic->IsAdult && logic->CanUse(RG_HOOKSHOT)) || - (logic->CanUse(RG_HOOKSHOT) && (logic->IsAdult || logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8) && (logic->CanUse(RG_HOVER_BOOTS) || logic->MQWaterStalfosPit));}}), - Entrance(RR_WATER_TEMPLE_MQ_STALFOS_PIT_UPPER, {[]{return logic->MQWaterStalfosPit && (logic->IsAdult || logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8) && logic->CanUse(RG_HOOKSHOT);}}), - }); - - //also includes the suns fairy in the middle - areaTable[RR_WATER_TEMPLE_MQ_STALFOS_PIT_POTS] = Region("Water Temple MQ Stalfos Pit Pots", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->FairyPot, {[]{return true;}}), - EventAccess(&logic->NutPot, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_WATER_TEMPLE_MQ_STALFOS_PIT_SOUTH_POT, logic->CanBreakPots()), - LOCATION(RC_WATER_TEMPLE_MQ_STALFOS_PIT_MIDDLE_POT, logic->CanBreakPots()), - LOCATION(RC_WATER_TEMPLE_MQ_STALFOS_PIT_NORTH_POT, logic->CanBreakPots()), - LOCATION(RC_WATER_TEMPLE_MQ_DARK_LINK_PILAR_SUN_FAIRY, logic->CanUse(RG_SUNS_SONG)), - - }, { - //Exits - Entrance(RR_WATER_TEMPLE_MQ_WATERFALL, {[]{return logic->MQWaterStalfosPit && (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_LONGSHOT));}}), - Entrance(RR_WATER_TEMPLE_MQ_STALFOS_PIT, {[]{return true;}}), - Entrance(RR_WATER_TEMPLE_MQ_STALFOS_PIT_UPPER, {[]{return logic->MQWaterStalfosPit && logic->CanUse(RG_HOOKSHOT);}}), - }); - -//specifically the area past the spikes - areaTable[RR_WATER_TEMPLE_MQ_STALFOS_PIT_UPPER] = Region("Water Temple MQ Stalfos Pit Upper", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_WATER_TEMPLE_MQ_BEFORE_DARK_LINK_POT_1, logic->CanBreakPots()), - LOCATION(RC_WATER_TEMPLE_MQ_BEFORE_DARK_LINK_POT_2, logic->CanBreakPots()), - LOCATION(RC_WATER_TEMPLE_MQ_DARK_LINK_LEFT_STORM_FAIRY, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_WATER_TEMPLE_MQ_DARK_LINK_RIGHT_SUN_FAIRY, logic->CanUse(RG_SUNS_SONG)), - }, { - //Exits - Entrance(RR_WATER_TEMPLE_MQ_STALFOS_PIT, {[]{return logic->IsAdult || logic->TakeDamage();}}), - Entrance(RR_WATER_TEMPLE_MQ_STALFOS_PIT_POTS, {[]{return logic->IsAdult || logic->TakeDamage();}}), - Entrance(RR_WATER_TEMPLE_MQ_AFTER_DARK_LINK, {[]{return logic->CanKillEnemy(RE_DARK_LINK);}}), - }); - - areaTable[RR_WATER_TEMPLE_MQ_AFTER_DARK_LINK] = Region("Water Temple MQ After Dark Link", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->FairyPot, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_WATER_TEMPLE_MQ_AFTER_DARK_LINK_POT_1, logic->CanBreakPots()), - LOCATION(RC_WATER_TEMPLE_MQ_AFTER_DARK_LINK_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_WATER_TEMPLE_MQ_STALFOS_PIT_UPPER, {[]{return logic->CanKillEnemy(RE_DARK_LINK);}}), - Entrance(RR_WATER_TEMPLE_MQ_RIVER_SKULL, {[]{return logic->CanUse(RG_HOOKSHOT) && (logic->HasItem(RG_BRONZE_SCALE) || (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8) || logic->CanUse(RG_LONGSHOT));}}), - }); - -//if we can use hookshot, we are standing on the targets, otherwise assume we're in the water - areaTable[RR_WATER_TEMPLE_MQ_RIVER_SKULL] = Region("Water Temple MQ River Skull", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_WATER_TEMPLE_MQ_GS_RIVER, logic->CanUse(RG_LONGSHOT) || (logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT))), - }, { - //Exits - Entrance(RR_WATER_TEMPLE_MQ_RIVER_POTS, {[]{return logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_LONGSHOT);}}), - }); - - areaTable[RR_WATER_TEMPLE_MQ_RIVER_POTS] = Region("Water Temple MQ River Pots", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->FairyPot, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_WATER_TEMPLE_MQ_RIVER_POT_1, logic->CanBreakPots()), - LOCATION(RC_WATER_TEMPLE_MQ_RIVER_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_WATER_TEMPLE_MQ_RIVER_SKULL, {[]{return logic->CanUse(RG_LONGSHOT) || (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8 && logic->CanUse(RG_HOOKSHOT));}}), - //You don't need to swim for this if you put irons on in midair and hold forward while aiming for the tunnel with a tight angle, but if you miss you have to void unless you have a hook. It's only relevant with glitches anyway - Entrance(RR_WATER_TEMPLE_MQ_DRAGON_ROOM_TUNNEL, {[]{return logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16;}}), - Entrance(RR_WATER_TEMPLE_MQ_DRAGON_ROOM_ALCOVE, {[]{return logic->HasItem(RG_SILVER_SCALE) || (logic->IsAdult && logic->HasItem(RG_BRONZE_SCALE) && ctx->GetTrickOption(RT_WATER_DRAGON_JUMP_DIVE));}}), - Entrance(RR_WATER_TEMPLE_MQ_DRAGON_ROOM_DOOR, {[]{return logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_LONGSHOT) || (logic->CanUse(RG_HOVER_BOOTS) && logic->CanJumpslash());}}), - }); - -//This region assumes Iron boots to access - areaTable[RR_WATER_TEMPLE_MQ_DRAGON_ROOM_TUNNEL] = Region("Water Temple MQ Dragon Room Tunnel", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_WATER_TEMPLE_MQ_RIVER_POTS, {[]{return logic->CanUse(RG_LONGSHOT);}}), - Entrance(RR_WATER_TEMPLE_MQ_DRAGON_ROOM_ALCOVE, {[]{return logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_HOOKSHOT);}}), - Entrance(RR_WATER_TEMPLE_MQ_DRAGON_ROOM_DOOR, {[]{return logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_LONGSHOT);}}), - }); - - areaTable[RR_WATER_TEMPLE_MQ_DRAGON_ROOM_ALCOVE] = Region("Water Temple MQ Dragon Room Alcove", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->MQWaterDragonTorches, {[]{return true;}}), - }, {}, { - //Exits - Entrance(RR_WATER_TEMPLE_MQ_DRAGON_ROOM_TUNNEL, {[]{return logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16;}}), - Entrance(RR_WATER_TEMPLE_MQ_DRAGON_ROOM_DOOR, {[]{return logic->HasItem(RG_SILVER_SCALE);}}), - }); - - areaTable[RR_WATER_TEMPLE_MQ_DRAGON_ROOM_DOOR] = Region("Water Temple MQ Dragon Room Door", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_WATER_TEMPLE_MQ_RIVER_POTS, {[]{return logic->CanUse(RG_LONGSHOT);}}), - Entrance(RR_WATER_TEMPLE_MQ_DRAGON_ROOM_TUNNEL, {[]{return logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && logic->CanUse(RG_HOOKSHOT);}}), - Entrance(RR_WATER_TEMPLE_MQ_DRAGON_ROOM_ALCOVE, {[]{return logic->HasItem(RG_SILVER_SCALE);}}), - Entrance(RR_WATER_TEMPLE_MQ_BOSS_KEY_ROOM_SWITCH, {[]{return logic->MQWaterDragonTorches;}}), - }); - - areaTable[RR_WATER_TEMPLE_MQ_BOSS_KEY_ROOM_SWITCH] = Region("Water Temple MQ Boss Key Room Switch", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_WATER_TEMPLE_MQ_BOSS_KEY_POT, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_WATER_TEMPLE_MQ_DRAGON_ROOM_DOOR, {[]{return true;}}), - Entrance(RR_WATER_TEMPLE_MQ_BOSS_KEY_ROOM_PIT, {[]{return true;}}), - Entrance(RR_WATER_TEMPLE_MQ_BOSS_KEY_ROOM_CHEST, {[]{return logic->CanHitSwitch() && Here(RR_WATER_TEMPLE_MQ_BOSS_KEY_ROOM_SWITCH, []{return logic->CanUse(RG_DINS_FIRE);});}}), - }); - -//this exists for the crates in preparation for clips through the grate - areaTable[RR_WATER_TEMPLE_MQ_BOSS_KEY_ROOM_PIT] = Region("Water Temple MQ Boss Key Room Pit", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_WATER_TEMPLE_MQ_BOSS_KEY_ROOM_SWITCH, {[]{return logic->CanHitSwitch(ED_BOOMERANG);}}), - }); - - areaTable[RR_WATER_TEMPLE_MQ_BOSS_KEY_ROOM_CHEST] = Region("Water Temple MQ Boss Key Room Chest", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_WATER_TEMPLE_MQ_BOSS_KEY_CHEST, true), - }, { - //Exits - Entrance(RR_WATER_TEMPLE_MQ_BOSS_KEY_ROOM_SWITCH, {[]{return logic->CanHitSwitch(ED_BOMB_THROW) || logic->CanUse(RG_HOVER_BOOTS);}}), - Entrance(RR_WATER_TEMPLE_MQ_BOSS_KEY_ROOM_PIT, {[]{return true;}}), - Entrance(RR_WATER_TEMPLE_MQ_B1_GATE_SWITCH, {[]{return logic->HasItem(RG_SILVER_SCALE) || (logic->CanUse(RG_IRON_BOOTS) && (logic->HasItem(RG_BRONZE_SCALE) || (logic->WaterTimer() >= 24 && logic->CanUse(RG_LONGSHOT))));}}), - }); - - areaTable[RR_WATER_TEMPLE_MQ_B1_GATE_SWITCH] = Region("Water Temple MQ B1 Gate Switch", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, { - //Events - //If the water is low, the switch is underwater and needs irons to press, otherwise, the water is too low to climb up and you need irons to hookshot a target - //If a glitch clips through the gate on low, have it logically press the switch and let entrance logic enter - EventAccess(&logic->MQWaterB1Switch, {[]{return logic->CanUse(RG_IRON_BOOTS);}}), - }, {}, { - //Exits - Entrance(RR_WATER_TEMPLE_MQ_MAIN, {[]{return logic->MQWaterB1Switch && (logic->MQWaterLevel(WL_LOW) || (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16));}}), - Entrance(RR_WATER_TEMPLE_MQ_BOSS_KEY_ROOM_CHEST, {[]{return logic->CanUse(RG_IRON_BOOTS) && logic->HasItem(RG_BRONZE_SCALE) && (logic->MQWaterLevel(WL_LOW) || logic->WaterTimer() >= 24);}}) - }); - - areaTable[RR_WATER_TEMPLE_MQ_TRIANGLE_TORCH_ROOM] = Region("Water Temple MQ Triangle Torch Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_WATER_TEMPLE_MQ_MAIN, {[]{return logic->MQWaterB1Switch && - ((logic->MQWaterLevel(WL_LOW) && logic->HasItem(RG_GOLDEN_SCALE)) || - (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 40 && (logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_LONGSHOT))));}}), - Entrance(RR_WATER_TEMPLE_MQ_TRIANGLE_TORCH_CAGE, {[]{return logic->CanUse(RG_FIRE_ARROWS) && - ((logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)) || (logic->CanUse(RG_LONGSHOT) && Here(RR_WATER_TEMPLE_MQ_TRIANGLE_TORCH_CAGE, []{return logic->ScarecrowsSong();})));}}) - }); - - areaTable[RR_WATER_TEMPLE_MQ_TRIANGLE_TORCH_CAGE] = Region("Water Temple MQ Triangle Torch Cage", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_WATER_TEMPLE_MQ_GS_TRIPLE_WALL_TORCH, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)), - LOCATION(RC_WATER_TEMPLE_MQ_LOWEST_GS_POT_1, logic->CanBreakPots()), - LOCATION(RC_WATER_TEMPLE_MQ_LOWEST_GS_POT_2, logic->CanBreakPots()), - LOCATION(RC_WATER_TEMPLE_MQ_LOWEST_GS_POT_3, logic->CanBreakPots()), - LOCATION(RC_WATER_TEMPLE_MQ_LOWEST_GS_POT_4, logic->CanBreakPots()), - }, {}); - - areaTable[RR_WATER_TEMPLE_MQ_CRATES_WHIRLPOOLS_ROOM] = Region("Water Temple MQ Crates Whirlpools Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - //we can backflip over the spikes, but land in water. - Entrance(RR_WATER_TEMPLE_MQ_MAIN, {[]{return logic->MQWaterB1Switch && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 24 && (logic->CanUse(RG_LONGSHOT) || logic->HasItem(RG_BRONZE_SCALE));}}), - //Child can use the crate to get the height to make it with hovers, but it's annoyingly tight so would be a trick - Entrance(RR_WATER_TEMPLE_MQ_SINGLE_STALFOS_ROOM, {[]{return logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8 && - //We're putting the requirement to get out of the water here as the scarecrow method in includes hook which satisfies it - ((logic->IsAdult && (logic->CanUse(RG_HOVER_BOOTS) || ctx->GetTrickOption(RT_WATER_NORTH_BASEMENT_LEDGE_JUMP)) && (logic->CanUse(RG_HOOKSHOT) || logic->HasItem(RG_BRONZE_SCALE))) || - (Here(RR_WATER_TEMPLE_MQ_CRATES_WHIRLPOOLS_ROOM, []{return logic->ScarecrowsSong();}) && logic->CanUse(RG_HOOKSHOT)));}}), - Entrance(RR_WATER_TEMPLE_MQ_4_TORCH_ROOM, {[]{return logic->IsAdult && - (logic->CanUse(RG_HOVER_BOOTS) || ctx->GetTrickOption(RT_WATER_NORTH_BASEMENT_LEDGE_JUMP) || - (Here(RR_WATER_TEMPLE_MQ_CRATES_WHIRLPOOLS_ROOM, []{return logic->ScarecrowsSong();}) && logic->CanUse(RG_HOOKSHOT)));}}), - Entrance(RR_WATER_TEMPLE_MQ_CRATES_WHIRLPOOLS_CAGE, {[]{return ctx->GetTrickOption(RT_WATER_MQ_LOCKED_GS) && (logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT));}}), - }); - - areaTable[RR_WATER_TEMPLE_MQ_SINGLE_STALFOS_ROOM] = Region("Water Temple MQ Single Stalfos Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_WATER_TEMPLE_MQ_FREESTANDING_KEY, true), - LOCATION(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_B_POT_1, logic->CanBreakPots()), - LOCATION(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_B_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_WATER_TEMPLE_MQ_CRATES_WHIRLPOOLS_ROOM, {[]{return logic->HasItem(RG_SILVER_SCALE) || (logic->IsChild && logic->HasItem(RG_BRONZE_SCALE)) || - (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8 && (logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_HOOKSHOT)));}}) - }); - - areaTable[RR_WATER_TEMPLE_MQ_4_TORCH_ROOM] = Region("Water Temple MQ 4 Torch Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_WATER_TEMPLE_MQ_CRATES_WHIRLPOOLS_ROOM, {[]{return (logic->IsAdult && (logic->CanUse(RG_HOVER_BOOTS) || logic->CanJumpslash())) || - (logic->HasItem(RG_BRONZE_SCALE) || (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8 && logic->CanUse(RG_HOOKSHOT) ));}}), - Entrance(RR_WATER_TEMPLE_MQ_DODONGO_ROOM, {[]{return logic->CanHitSwitch() && logic->HasFireSource();}}) - }); - - areaTable[RR_WATER_TEMPLE_MQ_DODONGO_ROOM] = Region("Water Temple MQ Dodongo Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_WATER_TEMPLE_MQ_MINI_DODONGO_POT_1, logic->CanBreakPots()), - LOCATION(RC_WATER_TEMPLE_MQ_MINI_DODONGO_POT_2, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_WATER_TEMPLE_MQ_4_TORCH_ROOM, {[]{return (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS)) && - Here(RR_WATER_TEMPLE_MQ_DODONGO_ROOM, []{return logic->CanKillEnemy(RE_DODONGO, ED_CLOSE, true, 5);});}}), - Entrance(RR_WATER_TEMPLE_MQ_CRATES_WHIRLPOOLS_CAGE, {[]{return (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS)) && - Here(RR_WATER_TEMPLE_MQ_DODONGO_ROOM, []{return logic->CanKillEnemy(RE_DODONGO, ED_CLOSE, true, 5);});}}) - }); - - areaTable[RR_WATER_TEMPLE_MQ_CRATES_WHIRLPOOLS_CAGE] = Region("Water Temple MQ Basement Gated Areas", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_WATER_TEMPLE_MQ_GS_FREESTANDING_KEY_AREA, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)), - }, { - Entrance(RR_WATER_TEMPLE_MQ_DODONGO_ROOM, {[]{return true;}}) - }); - } - - /*--------------------------- - | BOSS ROOM | - ---------------------------*/ - areaTable[RR_WATER_TEMPLE_BOSS_ENTRYWAY] = - Region("Water Temple Boss Entryway", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, - { - // Exits - Entrance(RR_WATER_TEMPLE_PRE_BOSS_ROOM, {[]{return ctx->GetDungeon(WATER_TEMPLE)->IsVanilla() && false;}}), - Entrance(RR_WATER_TEMPLE_MQ_BOSS_DOOR, {[]{return ctx->GetDungeon(WATER_TEMPLE)->IsMQ() && false;}}), - Entrance(RR_WATER_TEMPLE_BOSS_ROOM, {[]{return true;}}), - }); - - areaTable[RR_WATER_TEMPLE_BOSS_ROOM] = Region("Water Temple Boss Room", "Water Temple", {}, NO_DAY_NIGHT_CYCLE, - { - // Events - EventAccess(&logic->WaterTempleClear, { [] { - return logic->WaterTempleClear || (logic->HasBossSoul(RG_MORPHA_SOUL) && - (logic->CanUse(RG_HOOKSHOT) && (logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD)))); - } }), - }, - { - // Locations - LOCATION(RC_WATER_TEMPLE_MORPHA_HEART, logic->WaterTempleClear), - LOCATION(RC_MORPHA, logic->WaterTempleClear), - }, - { - // Exits - Entrance(RR_WATER_TEMPLE_BOSS_ENTRYWAY, { [] { return false; } }), - Entrance(RR_LAKE_HYLIA, { [] { return logic->WaterTempleClear; } }, false), - }); -} 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 deleted file mode 100644 index ab1fd4366..000000000 --- a/soh/soh/Enhancements/randomizer/3drando/location_access/locacc_zoras_domain.cpp +++ /dev/null @@ -1,257 +0,0 @@ -#include "../location_access.hpp" -#include "../../entrance.h" - -using namespace Rando; - -void RegionTable_Init_ZorasDomain() { - areaTable[RR_ZR_FRONT] = Region("ZR Front", "Zora River", {RA_ZORAS_RIVER}, DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_ZR_GS_TREE, logic->IsChild && logic->CanAttack()), - }, { - //Exits - Entrance(RR_ZORAS_RIVER, {[]{return logic->IsAdult || logic->BlastOrSmash();}}), - Entrance(RR_HYRULE_FIELD, {[]{return true;}}), - }); - - areaTable[RR_ZORAS_RIVER] = Region("Zora River", "Zora River", {RA_ZORAS_RIVER}, DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->GossipStoneFairy, {[]{return logic->CallGossipFairy();}}), - EventAccess(&logic->BeanPlantFairy, {[]{return logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS);}}), - EventAccess(&logic->ButterflyFairy, {[]{return logic->ButterflyFairy || logic->CanUse(RG_STICKS);}}), - EventAccess(&logic->BugShrub, {[]{return logic->BugShrub || logic->CanCutShrubs();}}), - }, { - //Locations - LOCATION(RC_ZR_MAGIC_BEAN_SALESMAN, logic->HasItem(RG_CHILD_WALLET) && logic->IsChild), - LOCATION(RC_ZR_FROGS_OCARINA_GAME, logic->IsChild && logic->CanUse(RG_ZELDAS_LULLABY) && logic->CanUse(RG_SARIAS_SONG) && logic->CanUse(RG_SUNS_SONG) && logic->CanUse(RG_EPONAS_SONG) && logic->CanUse(RG_SONG_OF_TIME) && logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_ZR_FROGS_IN_THE_RAIN, logic->IsChild && logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_ZR_FROGS_ZELDAS_LULLABY, logic->IsChild && logic->CanUse(RG_ZELDAS_LULLABY)), - LOCATION(RC_ZR_FROGS_EPONAS_SONG, logic->IsChild && logic->CanUse(RG_EPONAS_SONG)), - LOCATION(RC_ZR_FROGS_SARIAS_SONG, logic->IsChild && logic->CanUse(RG_SARIAS_SONG)), - LOCATION(RC_ZR_FROGS_SUNS_SONG, logic->IsChild && logic->CanUse(RG_SUNS_SONG)), - LOCATION(RC_ZR_FROGS_SONG_OF_TIME, logic->IsChild && logic->CanUse(RG_SONG_OF_TIME)), - LOCATION(RC_ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH, logic->IsChild || logic->CanUse(RG_HOVER_BOOTS) || (logic->IsAdult && ctx->GetTrickOption(RT_ZR_LOWER))), - LOCATION(RC_ZR_NEAR_DOMAIN_FREESTANDING_POH, logic->IsChild || logic->CanUse(RG_HOVER_BOOTS) || (logic->IsAdult && ctx->GetTrickOption(RT_ZR_UPPER))), - LOCATION(RC_ZR_GS_LADDER, logic->IsChild && logic->CanAttack() && logic->CanGetNightTimeGS()), - LOCATION(RC_ZR_GS_NEAR_RAISED_GROTTOS, logic->IsAdult && logic->HookshotOrBoomerang() && logic->CanGetNightTimeGS()), - LOCATION(RC_ZR_GS_ABOVE_BRIDGE, logic->IsAdult && logic->CanUse(RG_HOOKSHOT) && logic->CanGetNightTimeGS()), - LOCATION(RC_ZR_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_ZR_BEAN_SPROUT_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_ZR_BEAN_SPROUT_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_ZR_NEAR_GROTTOS_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), - LOCATION(RC_ZR_NEAR_GROTTOS_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_ZR_NEAR_DOMAIN_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), - LOCATION(RC_ZR_NEAR_DOMAIN_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_ZR_BENEATH_WATERFALL_LEFT_RUPEE, logic->IsAdult && (logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG))), - LOCATION(RC_ZR_BENEATH_WATERFALL_MIDDLE_LEFT_RUPEE, logic->IsAdult && (logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG))), - LOCATION(RC_ZR_BENEATH_WATERFALL_MIDDLE_RIGHT_RUPEE, logic->IsAdult && (logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG))), - LOCATION(RC_ZR_BENEATH_WATERFALL_RIGHT_RUPEE, logic->IsAdult && (logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG))), - LOCATION(RC_ZR_NEAR_GROTTOS_GOSSIP_STONE, true), - LOCATION(RC_ZR_NEAR_DOMAIN_GOSSIP_STONE, true), - }, { - //Exits - Entrance(RR_ZR_FRONT, {[]{return true;}}), - Entrance(RR_ZR_OPEN_GROTTO, {[]{return true;}}), - Entrance(RR_ZR_FAIRY_GROTTO, {[]{return Here(RR_ZORAS_RIVER, []{return logic->BlastOrSmash();});}}), - Entrance(RR_THE_LOST_WOODS, {[]{return logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS);}}), - Entrance(RR_ZR_STORMS_GROTTO, {[]{return logic->CanOpenStormsGrotto();}}), - Entrance(RR_ZR_BEHIND_WATERFALL, {[]{ - return ctx->GetOption(RSK_SLEEPING_WATERFALL).Is(RO_WATERFALL_OPEN) || - Here(RR_ZORAS_RIVER, []{return logic->CanUse(RG_ZELDAS_LULLABY);}) || - (logic->IsChild && ctx->GetTrickOption(RT_ZR_CUCCO)) || - (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS) && ctx->GetTrickOption(RT_ZR_HOVERS)); - }}), - }); - - areaTable[RR_ZR_BEHIND_WATERFALL] = Region("ZR Behind Waterfall", "Zora River", {RA_ZORAS_RIVER}, DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_ZORAS_RIVER, {[]{return true;}}), - Entrance(RR_ZORAS_DOMAIN, {[]{return true;}}), - }); - - areaTable[RR_ZR_OPEN_GROTTO] = Region("ZR Open Grotto", "ZR Open Grotto", {}, NO_DAY_NIGHT_CYCLE, grottoEvents, { - //Locations - LOCATION(RC_ZR_OPEN_GROTTO_CHEST, true), - LOCATION(RC_ZR_OPEN_GROTTO_FISH, logic->HasBottle()), - LOCATION(RC_ZR_OPEN_GROTTO_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), - LOCATION(RC_ZR_OPEN_GROTTO_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_ZR_OPEN_GROTTO_GOSSIP_STONE, true), - LOCATION(RC_ZR_OPEN_GROTTO_BEEHIVE_LEFT, logic->CanBreakLowerBeehives()), - LOCATION(RC_ZR_OPEN_GROTTO_BEEHIVE_RIGHT, logic->CanBreakLowerBeehives()), - }, { - //Exits - Entrance(RR_ZORAS_RIVER, {[]{return true;}}), - }); - - areaTable[RR_ZR_FAIRY_GROTTO] = Region("ZR Fairy Grotto", "ZR Fairy Grotto", {}, NO_DAY_NIGHT_CYCLE, { - //Event - EventAccess(&logic->FreeFairies, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_ZR_FAIRY_GROTTO_FAIRY_1, true), - LOCATION(RC_ZR_FAIRY_GROTTO_FAIRY_2, true), - LOCATION(RC_ZR_FAIRY_GROTTO_FAIRY_3, true), - LOCATION(RC_ZR_FAIRY_GROTTO_FAIRY_4, true), - LOCATION(RC_ZR_FAIRY_GROTTO_FAIRY_5, true), - LOCATION(RC_ZR_FAIRY_GROTTO_FAIRY_6, true), - LOCATION(RC_ZR_FAIRY_GROTTO_FAIRY_7, true), - LOCATION(RC_ZR_FAIRY_GROTTO_FAIRY_8, true), - }, { - //Exits - Entrance(RR_ZORAS_RIVER, {[]{return true;}}), - }); - - areaTable[RR_ZR_STORMS_GROTTO] = Region("ZR Storms Grotto", "ZR Storms Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_ZR_DEKU_SCRUB_GROTTO_REAR, logic->CanStunDeku()), - LOCATION(RC_ZR_DEKU_SCRUB_GROTTO_FRONT, logic->CanStunDeku()), - LOCATION(RC_ZR_STORMS_GROTTO_BEEHIVE, logic->CanBreakUpperBeehives()), - }, { - //Exits - Entrance(RR_ZORAS_RIVER, {[]{return true;}}), - }); - - areaTable[RR_ZORAS_DOMAIN] = Region("Zoras Domain", "Zoras Domain", {RA_ZORAS_DOMAIN}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->GossipStoneFairy, {[]{return logic->CallGossipFairyExceptSuns();}}), - EventAccess(&logic->NutPot, {[]{return true;}}), - EventAccess(&logic->StickPot, {[]{return logic->StickPot || logic->IsChild;}}), - EventAccess(&logic->FishGroup, {[]{return logic->FishGroup || logic->IsChild;}}), - EventAccess(&logic->KingZoraThawed, {[]{return logic->KingZoraThawed || (logic->IsAdult && logic->BlueFire());}}), - EventAccess(&logic->DeliverLetter, {[]{return logic->DeliverLetter || (logic->CanUse(RG_RUTOS_LETTER) && logic->IsChild && ctx->GetOption(RSK_ZORAS_FOUNTAIN).IsNot(RO_ZF_OPEN));}}), - }, { - //Locations - LOCATION(RC_ZD_DIVING_MINIGAME, logic->HasItem(RG_BRONZE_SCALE) && logic->HasItem(RG_CHILD_WALLET) && logic->IsChild), - LOCATION(RC_ZD_CHEST, logic->IsChild && logic->CanUse(RG_STICKS)), - LOCATION(RC_ZD_KING_ZORA_THAWED, logic->KingZoraThawed), - LOCATION(RC_ZD_TRADE_PRESCRIPTION, logic->KingZoraThawed && logic->CanUse(RG_PRESCRIPTION)), - LOCATION(RC_ZD_GS_FROZEN_WATERFALL, logic->IsAdult && (logic->HookshotOrBoomerang() || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_FAIRY_BOW) || (logic->CanUse(RG_MAGIC_SINGLE) && (logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_BIGGORON_SWORD))) || (ctx->GetTrickOption(RT_ZD_GS) && logic->CanJumpslashExceptHammer())) && logic->CanGetNightTimeGS()), - LOCATION(RC_ZD_FISH_1, logic->IsChild && logic->HasBottle()), - LOCATION(RC_ZD_FISH_2, logic->IsChild && logic->HasBottle()), - LOCATION(RC_ZD_FISH_3, logic->IsChild && logic->HasBottle()), - LOCATION(RC_ZD_FISH_4, logic->IsChild && logic->HasBottle()), - LOCATION(RC_ZD_FISH_5, logic->IsChild && logic->HasBottle()), - LOCATION(RC_ZD_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns()), - LOCATION(RC_ZD_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_ZD_GOSSIP_STONE, true), - LOCATION(RC_ZD_IN_FRONT_OF_KING_ZORA_BEEHIVE_LEFT, logic->CanBreakUpperBeehives()), - LOCATION(RC_ZD_IN_FRONT_OF_KING_ZORA_BEEHIVE_RIGHT, logic->CanBreakUpperBeehives()), - LOCATION(RC_ZD_NEAR_SHOP_POT_1, logic->CanBreakPots()), - LOCATION(RC_ZD_NEAR_SHOP_POT_2, logic->CanBreakPots()), - LOCATION(RC_ZD_NEAR_SHOP_POT_3, logic->CanBreakPots()), - LOCATION(RC_ZD_NEAR_SHOP_POT_4, logic->CanBreakPots()), - LOCATION(RC_ZD_NEAR_SHOP_POT_5, logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_ZR_BEHIND_WATERFALL, {[]{return true;}}), - Entrance(RR_LAKE_HYLIA, {[]{return logic->IsChild && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS));}}), - Entrance(RR_ZD_BEHIND_KING_ZORA, {[]{return logic->DeliverLetter || ctx->GetOption(RSK_ZORAS_FOUNTAIN).Is(RO_ZF_OPEN) || (ctx->GetOption(RSK_ZORAS_FOUNTAIN).Is(RO_ZF_CLOSED_CHILD) && logic->IsAdult) || (ctx->GetTrickOption(RT_ZD_KING_ZORA_SKIP) && logic->IsAdult);}}), - Entrance(RR_ZD_SHOP, {[]{return logic->IsChild || logic->BlueFire();}}), - Entrance(RR_ZORAS_DOMAIN_ISLAND, {[]{return true;}}), - }); - - areaTable[RR_ZORAS_DOMAIN_ISLAND] = Region("Zoras Domain Island", "Zoras Domain", {RA_ZORAS_DOMAIN}, NO_DAY_NIGHT_CYCLE, {}, {}, { - //Exits - Entrance(RR_ZORAS_DOMAIN, {[]{return logic->IsAdult || logic->HasItem(RG_BRONZE_SCALE);}}), - Entrance(RR_ZD_STORMS_GROTTO, {[]{return logic->CanOpenStormsGrotto();}}), - }); - - areaTable[RR_ZD_BEHIND_KING_ZORA] = Region("ZD Behind King Zora", "Zoras Domain", {RA_ZORAS_DOMAIN}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_ZD_BEHIND_KING_ZORA_BEEHIVE, logic->CanBreakUpperBeehives()), - }, { - //Exits - Entrance(RR_ZORAS_DOMAIN, {[]{return logic->DeliverLetter || ctx->GetOption(RSK_ZORAS_FOUNTAIN).Is(RO_ZF_OPEN) || (ctx->GetOption(RSK_ZORAS_FOUNTAIN).Is(RO_ZF_CLOSED_CHILD) && logic->IsAdult);}}), - Entrance(RR_ZORAS_FOUNTAIN, {[]{return true;}}), - }); - - areaTable[RR_ZD_SHOP] = Region("ZD Shop", "ZD Shop", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_ZD_SHOP_ITEM_1, true), - LOCATION(RC_ZD_SHOP_ITEM_2, true), - LOCATION(RC_ZD_SHOP_ITEM_3, true), - LOCATION(RC_ZD_SHOP_ITEM_4, true), - LOCATION(RC_ZD_SHOP_ITEM_5, true), - LOCATION(RC_ZD_SHOP_ITEM_6, true), - LOCATION(RC_ZD_SHOP_ITEM_7, true), - LOCATION(RC_ZD_SHOP_ITEM_8, true), - }, { - //Exits - Entrance(RR_ZORAS_DOMAIN, {[]{return true;}}), - }); - - areaTable[RR_ZD_STORMS_GROTTO] = Region("ZD Storms Grotto", "ZD Storms Grotto", {}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->FreeFairies, {[]{return true;}}), - }, { - //Locations - LOCATION(RC_ZD_FAIRY_GROTTO_FAIRY_1, true), - LOCATION(RC_ZD_FAIRY_GROTTO_FAIRY_2, true), - LOCATION(RC_ZD_FAIRY_GROTTO_FAIRY_3, true), - LOCATION(RC_ZD_FAIRY_GROTTO_FAIRY_4, true), - LOCATION(RC_ZD_FAIRY_GROTTO_FAIRY_5, true), - LOCATION(RC_ZD_FAIRY_GROTTO_FAIRY_6, true), - LOCATION(RC_ZD_FAIRY_GROTTO_FAIRY_7, true), - LOCATION(RC_ZD_FAIRY_GROTTO_FAIRY_8, true), - }, { - //Exits - Entrance(RR_ZORAS_DOMAIN_ISLAND, {[]{return true;}}), - }); - - areaTable[RR_ZORAS_FOUNTAIN] = Region("Zoras Fountain", "Zoras Fountain", {RA_ZORAS_FOUNTAIN}, NO_DAY_NIGHT_CYCLE, { - //Events - EventAccess(&logic->GossipStoneFairy, {[]{return logic->CallGossipFairyExceptSuns();}}), - EventAccess(&logic->ButterflyFairy, {[]{return logic->ButterflyFairy || (logic->CanUse(RG_STICKS) && logic->AtDay);}}), - }, { - //Locations - LOCATION(RC_ZF_ICEBERG_FREESTANDING_POH, logic->IsAdult), - LOCATION(RC_ZF_BOTTOM_FREESTANDING_POH, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), - LOCATION(RC_ZF_GS_TREE, logic->IsChild), - LOCATION(RC_ZF_GS_ABOVE_THE_LOG, logic->IsChild && logic->HookshotOrBoomerang() && logic->CanGetNightTimeGS()), - LOCATION(RC_ZF_GS_HIDDEN_CAVE, logic->CanUse(RG_SILVER_GAUNTLETS) && logic->BlastOrSmash() && logic->HookshotOrBoomerang() && logic->IsAdult && logic->CanGetNightTimeGS()), - LOCATION(RC_ZF_HIDDEN_CAVE_POT_1, logic->CanUse(RG_SILVER_GAUNTLETS) && logic->IsAdult && logic->BlastOrSmash() && logic->CanBreakPots()), - LOCATION(RC_ZF_HIDDEN_CAVE_POT_2, logic->CanUse(RG_SILVER_GAUNTLETS) && logic->IsAdult && logic->BlastOrSmash() && logic->CanBreakPots()), - LOCATION(RC_ZF_HIDDEN_CAVE_POT_3, logic->CanUse(RG_SILVER_GAUNTLETS) && logic->IsAdult && logic->BlastOrSmash() && logic->CanBreakPots()), - LOCATION(RC_ZF_FAIRY_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns()), - LOCATION(RC_ZF_FAIRY_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_ZF_JABU_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns()), - LOCATION(RC_ZF_JABU_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), - LOCATION(RC_ZF_BOTTOM_NORTH_INNER_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), - LOCATION(RC_ZF_BOTTOM_NORTHEAST_INNER_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), - LOCATION(RC_ZF_BOTTOM_SOUTHEAST_INNER_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), - LOCATION(RC_ZF_BOTTOM_SOUTH_INNER_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), - LOCATION(RC_ZF_BOTTOM_SOUTHWEST_INNER_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), - LOCATION(RC_ZF_BOTTOM_NORTHWEST_INNER_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), - LOCATION(RC_ZF_BOTTOM_NORTH_MIDDLE_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), - LOCATION(RC_ZF_BOTTOM_NORTHEAST_MIDDLE_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), - LOCATION(RC_ZF_BOTTOM_SOUTHEAST_MIDDLE_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), - LOCATION(RC_ZF_BOTTOM_SOUTH_MIDDLE_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), - LOCATION(RC_ZF_BOTTOM_SOUTHWEST_MIDDLE_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), - LOCATION(RC_ZF_BOTTOM_NORTHWEST_MIDDLE_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), - LOCATION(RC_ZF_BOTTOM_NORTH_OUTER_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), - LOCATION(RC_ZF_BOTTOM_NORTHEAST_OUTER_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), - LOCATION(RC_ZF_BOTTOM_SOUTHEAST_OUTER_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), - LOCATION(RC_ZF_BOTTOM_SOUTH_OUTER_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), - LOCATION(RC_ZF_BOTTOM_SOUTHWEST_OUTER_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), - LOCATION(RC_ZF_BOTTOM_NORTHWEST_OUTER_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), - LOCATION(RC_ZF_FAIRY_GOSSIP_STONE, true), - LOCATION(RC_ZF_JABU_GOSSIP_STONE, true), - LOCATION(RC_ZF_NEAR_JABU_POT_1, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_ZF_NEAR_JABU_POT_2, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_ZF_NEAR_JABU_POT_3, logic->IsChild && logic->CanBreakPots()), - LOCATION(RC_ZF_NEAR_JABU_POT_4, logic->IsChild && logic->CanBreakPots()), - }, { - //Exits - Entrance(RR_ZD_BEHIND_KING_ZORA, {[]{return true;}}), - Entrance(RR_JABU_JABUS_BELLY_ENTRYWAY, {[]{return (logic->IsChild && logic->CanUse(RG_BOTTLE_WITH_FISH));}}), - Entrance(RR_ICE_CAVERN_ENTRYWAY, {[]{return logic->IsAdult;}}), - Entrance(RR_ZF_GREAT_FAIRY_FOUNTAIN, {[]{return logic->HasExplosives() || (ctx->GetTrickOption(RT_ZF_GREAT_FAIRY_WITHOUT_EXPLOSIVES) && logic->CanUse(RG_MEGATON_HAMMER) && logic->CanUse(RG_SILVER_GAUNTLETS));}}), - }); - - areaTable[RR_ZF_GREAT_FAIRY_FOUNTAIN] = Region("ZF Great Fairy Fountain", "ZF Great Fairy Fountain", {}, NO_DAY_NIGHT_CYCLE, {}, { - //Locations - LOCATION(RC_ZF_GREAT_FAIRY_REWARD, logic->CanUse(RG_ZELDAS_LULLABY)), - }, { - //Exits - Entrance(RR_ZORAS_FOUNTAIN, {[]{return true;}}), - }); -} diff --git a/soh/soh/Enhancements/randomizer/3drando/menu.cpp b/soh/soh/Enhancements/randomizer/3drando/menu.cpp index b15bfd552..07ba4fd07 100644 --- a/soh/soh/Enhancements/randomizer/3drando/menu.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/menu.cpp @@ -8,7 +8,7 @@ #include "menu.hpp" #include "playthrough.hpp" #include "spoiler_log.hpp" -#include "location_access.hpp" +#include "../location_access.h" #include "soh/Enhancements/debugger/performanceTimer.h" #include #include "../../randomizer/randomizerTypes.h" diff --git a/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp b/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp index 23503638d..7787ee468 100644 --- a/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/playthrough.cpp @@ -4,7 +4,7 @@ #include #include "custom_messages.hpp" #include "fill.hpp" -#include "location_access.hpp" +#include "../location_access.h" #include "random.hpp" #include "spoiler_log.hpp" #include "soh/Enhancements/randomizer/randomizerTypes.h" diff --git a/soh/soh/Enhancements/randomizer/3drando/rando_main.cpp b/soh/soh/Enhancements/randomizer/3drando/rando_main.cpp index a2ed98072..d26e89adb 100644 --- a/soh/soh/Enhancements/randomizer/3drando/rando_main.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/rando_main.cpp @@ -1,7 +1,7 @@ #include "menu.hpp" #include "../static_data.h" #include "../item_location.h" -#include "location_access.hpp" +#include "../location_access.h" #include "rando_main.hpp" #include "../context.h" #include diff --git a/soh/soh/Enhancements/randomizer/3drando/shops.cpp b/soh/soh/Enhancements/randomizer/3drando/shops.cpp index ecf4ea1be..b778efccf 100644 --- a/soh/soh/Enhancements/randomizer/3drando/shops.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/shops.cpp @@ -1,5 +1,5 @@ #include "item_pool.hpp" -#include "location_access.hpp" +#include "../location_access.h" #include "random.hpp" #include "shops.hpp" #include "../location.h" diff --git a/soh/soh/Enhancements/randomizer/entrance.cpp b/soh/soh/Enhancements/randomizer/entrance.cpp index 030181e40..1e28aa2c3 100644 --- a/soh/soh/Enhancements/randomizer/entrance.cpp +++ b/soh/soh/Enhancements/randomizer/entrance.cpp @@ -10,17 +10,13 @@ namespace Rando { EntranceLinkInfo NO_RETURN_ENTRANCE = { EntranceType::None, RR_NONE, RR_NONE, -1 }; -Entrance::Entrance(RandomizerRegion connectedRegion_, std::vector conditions_met_, bool spreadsAreasWithPriority_) - : connectedRegion(connectedRegion_), spreadsAreasWithPriority(spreadsAreasWithPriority_){ +Entrance::Entrance(RandomizerRegion connectedRegion_, ConditionFn condition_function_, bool spreadsAreasWithPriority_) + : connectedRegion(connectedRegion_), condition_function(condition_function_), spreadsAreasWithPriority(spreadsAreasWithPriority_){ originalConnectedRegion = connectedRegion_; - conditions_met.resize(2); - for (size_t i = 0; i < conditions_met_.size(); i++) { - conditions_met[i] = conditions_met_[i]; - } } void Entrance::SetCondition(ConditionFn newCondition) { - conditions_met[0] = newCondition; + condition_function = newCondition; } bool Entrance::GetConditionsMet() const { @@ -28,13 +24,9 @@ bool Entrance::GetConditionsMet() const { if (ctx->GetOption(RSK_LOGIC_RULES).Is(RO_LOGIC_NO_LOGIC) || ctx->GetOption(RSK_LOGIC_RULES).Is(RO_LOGIC_VANILLA)) { return true; } else if (ctx->GetOption(RSK_LOGIC_RULES).Is(RO_LOGIC_GLITCHLESS)) { - return conditions_met[0](); + return condition_function(); } else if (ctx->GetOption(RSK_LOGIC_RULES).Is(RO_LOGIC_GLITCHED)) { - if (conditions_met[0]()) { - return true; - } else if (conditions_met[1] != NULL) { - return conditions_met[1](); - } + return condition_function(); } return false; } diff --git a/soh/soh/Enhancements/randomizer/entrance.h b/soh/soh/Enhancements/randomizer/entrance.h index ffecad562..48a80c550 100644 --- a/soh/soh/Enhancements/randomizer/entrance.h +++ b/soh/soh/Enhancements/randomizer/entrance.h @@ -2,7 +2,7 @@ #ifdef __cplusplus #include "randomizerTypes.h" -#include "3drando/location_access.hpp" +#include "location_access.h" #include @@ -38,7 +38,7 @@ enum class EntranceType { class Entrance { public: - Entrance(RandomizerRegion connectedRegion_, std::vector conditions_met_, bool spreadsAreasWithPriority_ = true); + Entrance(RandomizerRegion connectedRegion_, ConditionFn condition_function_, bool spreadsAreasWithPriority_ = true); void SetCondition(ConditionFn newCondition); bool GetConditionsMet() const; std::string to_string() const; @@ -83,7 +83,7 @@ class Entrance { RandomizerRegion parentRegion; RandomizerRegion connectedRegion; RandomizerRegion originalConnectedRegion; - std::vector conditions_met; + ConditionFn condition_function; EntranceType type = EntranceType::None; Entrance* target = nullptr; @@ -98,7 +98,7 @@ class Entrance { std::string name = ""; //If this is false, areas only spread to interiors through this entrance if there is no other choice //Set to false for owl drops, the windmill path between dampe's grave and windmill and blue warps - bool spreadsAreasWithPriority = true; + bool spreadsAreasWithPriority = true; }; typedef struct { diff --git a/soh/soh/Enhancements/randomizer/location_access.cpp b/soh/soh/Enhancements/randomizer/location_access.cpp new file mode 100644 index 000000000..f8bb8f421 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access.cpp @@ -0,0 +1,575 @@ +#include "location_access.h" + +#include "soh/Enhancements/randomizer/dungeon.h" +#include "soh/Enhancements/randomizer/static_data.h" +#include "soh/Enhancements/randomizer/context.h" +#include "soh/Enhancements/randomizer/3drando/item_pool.hpp" +#include "soh/Enhancements/randomizer/3drando/spoiler_log.hpp" +#include "soh/Enhancements/randomizer/trial.h" +#include "soh/Enhancements/randomizer/entrance.h" +#include "soh/Enhancements/debugger/performanceTimer.h" + +#include + +//generic grotto event list +std::vector grottoEvents; + +//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 { + logic->IsChild = false; + logic->IsAdult = false; + logic->AtDay = false; + logic->AtNight = false; + + time = true; + age = true; + + return GetConditionsMet(); +} + +bool LocationAccess::ConditionsMet() const { + //WARNING enterance validation can run this after resetting the access for sphere 0 validation + //When refactoring ToD access, either fix the above or do not assume that we + //have any access at all just because this is being run + Region* parentRegion = RegionTable(Rando::Context::GetInstance()->GetItemLocation(location)->GetParentRegionKey()); + bool conditionsMet = false; + + if ( + (parentRegion->childDay && CheckConditionAtAgeTime(logic->IsChild, logic->AtDay)) || + (parentRegion->childNight && CheckConditionAtAgeTime(logic->IsChild, logic->AtNight)) || + (parentRegion->adultDay && CheckConditionAtAgeTime(logic->IsAdult, logic->AtDay)) || + (parentRegion->adultNight && CheckConditionAtAgeTime(logic->IsAdult, logic->AtNight)) + ) { + conditionsMet = true; + } + + return conditionsMet && CanBuy(); +} + +bool LocationAccess::CanBuy() const { + return CanBuyAnother(location); +} + +bool CanBuyAnother(RandomizerCheck rc) { + uint16_t price = ctx->GetItemLocation(rc)->GetPrice(); + + if (price > 500) { + return logic->HasItem(RG_TYCOON_WALLET); + } else if (price > 200) { + return logic->HasItem(RG_GIANT_WALLET); + } else if (price > 99) { + return logic->HasItem(RG_ADULT_WALLET); + } else if (price > 0) { + return logic->HasItem(RG_CHILD_WALLET); + } + return true; +} + +Region::Region() = default; +Region::Region( + std::string regionName_, + std::string scene_, + std::set areas, + bool timePass_, + std::vector events_, + std::vector locations_, + std::list exits_ +) : regionName(std::move(regionName_)), + scene(std::move(scene_)), + areas(areas), + timePass(timePass_), + events(std::move(events_)), + locations(std::move(locations_)), + exits(std::move(exits_)) {} + +Region::~Region() = default; + +void Region::ApplyTimePass(){ + if (timePass) { + StartPerformanceTimer(PT_TOD_ACCESS); + if (Child()) { + childDay = true; + childNight = true; + RegionTable(RR_ROOT)->childDay = true; + RegionTable(RR_ROOT)->childNight = true; + } + if (Adult()) { + adultDay = true; + adultNight = true; + RegionTable(RR_ROOT)->adultDay = true; + RegionTable(RR_ROOT)->adultNight = true; + } + StopPerformanceTimer(PT_TOD_ACCESS); + } +} + +bool Region::UpdateEvents() { + bool eventsUpdated = false; + StartPerformanceTimer(PT_EVENT_ACCESS); + 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(logic->IsChild, logic->AtDay)) || + (childNight && event.CheckConditionAtAgeTime(logic->IsChild, logic->AtNight)) || + (adultDay && event.CheckConditionAtAgeTime(logic->IsAdult, logic->AtDay)) || + (adultNight && event.CheckConditionAtAgeTime(logic->IsAdult, logic->AtNight)) + ) { + event.EventOccurred(); + eventsUpdated = true; + } + } + StopPerformanceTimer(PT_EVENT_ACCESS); + return eventsUpdated; +} + +void Region::AddExit(RandomizerRegion parentKey, RandomizerRegion newExitKey, ConditionFn condition) { + Rando::Entrance newExit = Rando::Entrance(newExitKey, {condition}); + newExit.SetParentRegion(parentKey); + exits.push_front(newExit); +} + +//The exit will be completely removed from this region +void Region::RemoveExit(Rando::Entrance* exitToRemove) { + exits.remove_if([exitToRemove](const auto exit){return &exit == exitToRemove;}); +} + +void Region::SetAsPrimary(RandomizerRegion exitToBePrimary) { + for (auto& exit : exits) { + if (exit.Getuint32_t() == exitToBePrimary) { + exit.SetAsPrimary(); + return; + } + } +} + +Rando::Entrance* Region::GetExit(RandomizerRegion exitToReturn) { + for (auto& exit : exits) { + if (exit.Getuint32_t() == exitToReturn) { + return &exit; + } + } + + LUSLOG_ERROR("ERROR: EXIT \"%s\" DOES NOT EXIST IN \"%s\"", RegionTable(exitToReturn)->regionName.c_str(), this->regionName.c_str()); + assert(false); + return nullptr; +} + +bool Region::CanPlantBeanCheck() const { + return Rando::Context::GetInstance()->GetLogic()->GetAmmo(ITEM_BEAN) > 0 && BothAgesCheck(); +} + +bool Region::AllAccountedFor() const { + for (const EventAccess& event : events) { + if (!event.GetEvent()) { + return false; + } + } + + for (const LocationAccess& loc : locations) { + if (!(Rando::Context::GetInstance()->GetItemLocation(loc.GetLocation())->IsAddedToPool())) { + return false; + } + } + + for (const auto& exit : exits) { + if (!exit.GetConnectedRegion()->AllAccess()) { + return false; + } + } + + return AllAccess(); +} + +bool Region::CheckAllAccess(const RandomizerRegion exitKey) { + if (!AllAccess()) { + return false; + } + + for (Rando::Entrance& exit : exits) { + if (exit.GetConnectedRegionKey() == 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 Region::ResetVariables() { + childDay = false; + childNight = false; + adultDay = false; + adultNight = false; + addedToPool = false; + for (auto& exit : exits) { + exit.RemoveFromPool(); + } +} + +std::array areaTable; + +bool Here(const RandomizerRegion region, ConditionFn condition) { + return areaTable[region].Here(condition); +} + +bool MQSpiritSharedStatueRoom(const RandomizerRegion region, ConditionFn condition, bool anyAge) { + return areaTable[region].MQSpiritShared(condition, false, anyAge); +} + +bool MQSpiritSharedBrokenWallRoom(const RandomizerRegion region, ConditionFn condition, bool anyAge) { + return areaTable[region].MQSpiritShared(condition, true, anyAge); +} + +bool CanPlantBean(const RandomizerRegion region) { + return areaTable[region].CanPlantBeanCheck(); +} + +bool BothAges(const RandomizerRegion region) { + return areaTable[region].BothAgesCheck(); +} + +bool ChildCanAccess(const RandomizerRegion region) { + return areaTable[region].Child(); +} + +bool AdultCanAccess(const RandomizerRegion region) { + return areaTable[region].Adult(); +} + +bool HasAccessTo(const RandomizerRegion region) { + return areaTable[region].HasAccess(); +} + +Rando::Context* ctx; +std::shared_ptr logic; + +void RegionTable_Init() { + using namespace Rando; + ctx = Context::GetInstance().get(); + logic = ctx->GetLogic(); //RANDOTODO do not hardcode, instead allow accepting a Logic class somehow + grottoEvents = { + EventAccess(&logic->GossipStoneFairy, []{return logic->CallGossipFairy();}), + EventAccess(&logic->ButterflyFairy, []{return logic->ButterflyFairy || (logic->CanUse(RG_STICKS));}), + EventAccess(&logic->BugShrub, []{return logic->CanCutShrubs();}), + EventAccess(&logic->LoneFish, []{return true;}), + }; + //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(Region("Invalid Region", "Invalid Region", {}, NO_DAY_NIGHT_CYCLE, {}, {}, {})); + + areaTable[RR_ROOT] = Region("Root", "", {RA_LINKS_POCKET}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->KakarikoVillageGateOpen, []{return ctx->GetOption(RSK_KAK_GATE).Is(RO_KAK_GATE_OPEN);}), + }, { + //Locations + LOCATION(RC_LINKS_POCKET, true), + LOCATION(RC_TRIFORCE_COMPLETED, logic->GetSaveContext()->triforcePiecesCollected >= ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_REQUIRED).GetContextOptionIndex() + 1;), + LOCATION(RC_SARIA_SONG_HINT, logic->CanUse(RG_SARIAS_SONG)), + }, { + //Exits + Entrance(RR_ROOT_EXITS, []{return true;}), + }); + + areaTable[RR_ROOT_EXITS] = Region("Root Exits", "", {RA_LINKS_POCKET}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_CHILD_SPAWN, []{return logic->IsChild;}), + Entrance(RR_ADULT_SPAWN, []{return logic->IsAdult;}), + Entrance(RR_MINUET_OF_FOREST_WARP, []{return logic->CanUse(RG_MINUET_OF_FOREST);}), + Entrance(RR_BOLERO_OF_FIRE_WARP, []{return logic->CanUse(RG_BOLERO_OF_FIRE) && logic->CanLeaveForest();}), + Entrance(RR_SERENADE_OF_WATER_WARP, []{return logic->CanUse(RG_SERENADE_OF_WATER) && logic->CanLeaveForest();}), + Entrance(RR_NOCTURNE_OF_SHADOW_WARP, []{return logic->CanUse(RG_NOCTURNE_OF_SHADOW) && logic->CanLeaveForest();}), + Entrance(RR_REQUIEM_OF_SPIRIT_WARP, []{return logic->CanUse(RG_REQUIEM_OF_SPIRIT) && logic->CanLeaveForest();}), + Entrance(RR_PRELUDE_OF_LIGHT_WARP, []{return logic->CanUse(RG_PRELUDE_OF_LIGHT) && logic->CanLeaveForest();}), + }); + + areaTable[RR_CHILD_SPAWN] = Region("Child Spawn", "", {RA_LINKS_POCKET}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_KF_LINKS_HOUSE, []{return true;}), + }); + + areaTable[RR_ADULT_SPAWN] = Region("Adult Spawn", "", {RA_LINKS_POCKET}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_TEMPLE_OF_TIME, []{return true;}), + }); + + areaTable[RR_MINUET_OF_FOREST_WARP] = Region("Minuet of Forest Warp", "", {RA_LINKS_POCKET}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_SACRED_FOREST_MEADOW, []{return true;}), + }); + + areaTable[RR_BOLERO_OF_FIRE_WARP] = Region("Bolero of Fire Warp", "", {RA_LINKS_POCKET}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_DMC_CENTRAL_LOCAL, []{return true;}), + }); + + areaTable[RR_SERENADE_OF_WATER_WARP] = Region("Serenade of Water Warp", "", {RA_LINKS_POCKET}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_LAKE_HYLIA, []{return true;}), + }); + + areaTable[RR_REQUIEM_OF_SPIRIT_WARP] = Region("Requiem of Spirit Warp", "", {RA_LINKS_POCKET}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_DESERT_COLOSSUS, []{return true;}), + }); + + areaTable[RR_NOCTURNE_OF_SHADOW_WARP] = Region("Nocturne of Shadow Warp", "", {RA_LINKS_POCKET}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_GRAVEYARD_WARP_PAD_REGION, []{return true;}), + }); + + areaTable[RR_PRELUDE_OF_LIGHT_WARP] = Region("Prelude of Light Warp", "", {RA_LINKS_POCKET}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_TEMPLE_OF_TIME, []{return true;}), + }); + + // Overworld + RegionTable_Init_KokiriForest(); + RegionTable_Init_LostWoods(); + RegionTable_Init_SacredForestMeadow(); + RegionTable_Init_HyruleField(); + RegionTable_Init_LakeHylia(); + RegionTable_Init_LonLonRanch(); + RegionTable_Init_Market(); + RegionTable_Init_TempleOfTime(); + RegionTable_Init_CastleGrounds(); + RegionTable_Init_Kakariko(); + RegionTable_Init_Graveyard(); + RegionTable_Init_DeathMountainTrail(); + RegionTable_Init_GoronCity(); + RegionTable_Init_DeathMountainCrater(); + RegionTable_Init_ZoraRiver(); + RegionTable_Init_ZorasDomain(); + RegionTable_Init_ZorasFountain(); + RegionTable_Init_GerudoValley(); + RegionTable_Init_GerudoFortress(); + RegionTable_Init_HauntedWasteland(); + RegionTable_Init_DesertColossus(); + // Dungeons + RegionTable_Init_DekuTree(); + RegionTable_Init_DodongosCavern(); + RegionTable_Init_JabuJabusBelly(); + RegionTable_Init_ForestTemple(); + RegionTable_Init_FireTemple(); + RegionTable_Init_WaterTemple(); + RegionTable_Init_SpiritTemple(); + RegionTable_Init_ShadowTemple(); + RegionTable_Init_BottomOfTheWell(); + RegionTable_Init_IceCavern(); + RegionTable_Init_GerudoTrainingGround(); + RegionTable_Init_GanonsCastle(); + + //Set parent regions + for (uint32_t i = RR_ROOT; i <= RR_GANONS_CASTLE; i++) { + for (LocationAccess& locPair : areaTable[i].locations) { + RandomizerCheck location = locPair.GetLocation(); + Rando::Context::GetInstance()->GetItemLocation(location)->SetParentRegion((RandomizerRegion)i); + } + for (Entrance& exit : areaTable[i].exits) { + exit.SetParentRegion((RandomizerRegion)i); + exit.SetName(); + exit.GetConnectedRegion()->entrances.push_front(&exit); + } + } +} + +void ReplaceFirstInString(std::string& s, std::string const& toReplace, std::string const& replaceWith) { + size_t pos = s.find(toReplace); + if (pos == std::string::npos) { + return; + } + s.replace(pos, toReplace.length(), replaceWith); +} + +void ReplaceAllInString(std::string& s, std::string const& toReplace, std::string const& replaceWith) { + std::string buf; + size_t pos = 0; + size_t prevPos; + + buf.reserve(s.size()); + + while (true) { + prevPos = pos; + pos = s.find(toReplace, pos); + if (pos == std::string::npos) { + break; + } + buf.append(s, prevPos, pos - prevPos); + buf += replaceWith; + pos += toReplace.size(); + } + + buf.append(s, prevPos, s.size() - prevPos); + s.swap(buf); +} + +std::string CleanCheckConditionString(std::string condition) { + ReplaceAllInString(condition, "logic->", ""); + ReplaceAllInString(condition, "ctx->", ""); + ReplaceAllInString(condition, ".GetContextOptionIndex()", ""); + ReplaceAllInString(condition, "GetSaveContext()->", ""); + return condition; +} + +namespace Regions { + const auto GetAllRegions() { + static const size_t regionCount = RR_MAX - (RR_NONE + 1); + + static std::array allRegions = {}; + + static bool intialized = false; + if (!intialized) { + for (size_t i = 0; i < regionCount; i++) { + allRegions[i] = (RandomizerRegion)((RR_NONE + 1) + i); + } + intialized = true; + } + + return allRegions; + } + + void AccessReset() { + auto ctx = Rando::Context::GetInstance(); + for (const RandomizerRegion region : GetAllRegions()) { + RegionTable(region)->ResetVariables(); + } + + if (/*Settings::HasNightStart TODO:: Randomize Starting Time*/ false) { + if (ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_CHILD) { + RegionTable(RR_ROOT)->childNight = true; + } else { + RegionTable(RR_ROOT)->adultNight = true; + } + } else { + if (ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_CHILD) { + RegionTable(RR_ROOT)->childDay = true; + } else { + RegionTable(RR_ROOT)->adultDay = true; + } + } + } + + //Reset exits and clear items from locations + void ResetAllLocations() { + auto ctx = Rando::Context::GetInstance(); + for (const RandomizerRegion region : GetAllRegions()) { + RegionTable(region)->ResetVariables(); + //Erase item from every location in this exit + for (LocationAccess& locPair : RegionTable(region)->locations) { + RandomizerCheck location = locPair.GetLocation(); + Rando::Context::GetInstance()->GetItemLocation(location)->ResetVariables(); + } + } + + if (/*Settings::HasNightStart TODO:: Randomize Starting Time*/ false) { + if (ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_CHILD) { + RegionTable(RR_ROOT)->childNight = true; + } else { + RegionTable(RR_ROOT)->adultNight = true; + } + } else { + if (ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_CHILD) { + RegionTable(RR_ROOT)->childDay = true; + } else { + RegionTable(RR_ROOT)->adultDay = true; + } + } + } + + bool HasTimePassAccess(uint8_t age) { + for (const RandomizerRegion regionKey : GetAllRegions()) { + auto region = RegionTable(regionKey); + if (region->timePass && ((age == RO_AGE_CHILD && region->Child()) || (age == RO_AGE_ADULT && region->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 RandomizerRegion regionKey : GetAllRegions()) { + auto region = RegionTable(regionKey); + for (auto exit : region->exits) { + if (exit.GetConnectedRegion()->regionName != "Invalid Region") { + std::string parent = exit.GetParentRegion()->regionName; + if (region->childDay) { + parent += " CD"; + } + if (region->childNight) { + parent += " CN"; + } + if (region->adultDay) { + parent += " AD"; + } + if (region->adultNight) { + parent += " AN"; + } + Region* 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 Regions + +Region* RegionTable(const RandomizerRegion regionKey) { + if (regionKey > RR_MAX) { + printf("\x1b[1;1HERROR: AREAKEY TOO BIG"); + } + return &(areaTable[regionKey]); +} + +//Retrieve all the shuffable entrances of a specific type +std::vector GetShuffleableEntrances(Rando::EntranceType type, bool onlyPrimary /*= true*/) { + std::vector entrancesToShuffle = {}; + for (RandomizerRegion region : Regions::GetAllRegions()) { + for (auto& exit : RegionTable(region)->exits) { + if ((exit.GetType() == type || type == Rando::EntranceType::All) && (exit.IsPrimary() || !onlyPrimary) && exit.GetType() != Rando::EntranceType::None) { + entrancesToShuffle.push_back(&exit); + } + } + } + return entrancesToShuffle; +} + +// Get the specific entrance by name +Rando::Entrance* GetEntrance(const std::string name) { + for (RandomizerRegion region : Regions::GetAllRegions()) { + for (auto& exit : RegionTable(region)->exits) { + if (exit.GetName() == name) { + return &exit; + } + } + } + + return nullptr; +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access.h b/soh/soh/Enhancements/randomizer/location_access.h new file mode 100644 index 000000000..1f2cdfcab --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access.h @@ -0,0 +1,365 @@ +#pragma once + +#include +#include +#include +#include + +#include "soh/Enhancements/randomizer/randomizerTypes.h" +#include "soh/Enhancements/randomizer/context.h" +#include "soh/Enhancements/randomizer/logic.h" + +typedef bool (*ConditionFn)(); + +// I hate this but every alternative I can think of right now is worse +extern Rando::Context* ctx; +extern std::shared_ptr logic; + +class EventAccess { + public: + explicit EventAccess(bool* event_, ConditionFn condition_function_) : event(event_), condition_function(condition_function_) {} + + bool ConditionsMet() const { + auto ctx = Rando::Context::GetInstance(); + if (ctx->GetOption(RSK_LOGIC_RULES).Is(RO_LOGIC_NO_LOGIC) || ctx->GetOption(RSK_LOGIC_RULES).Is(RO_LOGIC_VANILLA)) { + return true; + } else if (ctx->GetOption(RSK_LOGIC_RULES).Is(RO_LOGIC_GLITCHLESS)) { + return condition_function(); + } else if (ctx->GetOption(RSK_LOGIC_RULES).Is(RO_LOGIC_GLITCHED)) { + return condition_function(); + } + return false; + } + + bool CheckConditionAtAgeTime(bool& age, bool& time) { + logic->IsChild = false; + logic->IsAdult = false; + logic->AtDay = false; + logic->AtNight = false; + + time = true; + age = true; + + return ConditionsMet(); + } + + void EventOccurred() { + *event = true; + } + + bool GetEvent() const { + return *event; + } + + private: + bool* event; + ConditionFn condition_function; +}; + +std::string CleanCheckConditionString(std::string condition); + +#define LOCATION(check, condition) LocationAccess(check, []{return condition;}, CleanCheckConditionString(#condition)) + +//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(RandomizerCheck location_, ConditionFn condition_function_) : location(location_), condition_function(condition_function_), condition_str("") {} + + explicit LocationAccess(RandomizerCheck location_, ConditionFn condition_function_, std::string condition_str_) : location(location_), condition_function(condition_function_), condition_str(condition_str_) {} + + bool GetConditionsMet() const { + auto ctx = Rando::Context::GetInstance(); + if (ctx->GetOption(RSK_LOGIC_RULES).Is(RO_LOGIC_NO_LOGIC) || ctx->GetOption(RSK_LOGIC_RULES).Is(RO_LOGIC_VANILLA)) { + return true; + } else if (ctx->GetOption(RSK_LOGIC_RULES).Is(RO_LOGIC_GLITCHLESS)) { + return condition_function(); + } else if (ctx->GetOption(RSK_LOGIC_RULES).Is(RO_LOGIC_GLITCHED)) { + return condition_function(); + } + return false; + } + + bool CheckConditionAtAgeTime(bool& age, bool& time) const; + + bool ConditionsMet() const; + + RandomizerCheck GetLocation() const { + return location; + } + + std::string GetConditionStr() const { + return condition_str; + } + + protected: + RandomizerCheck location; + ConditionFn condition_function; + std::string condition_str; + + //Makes sure shop locations are buyable + bool CanBuy() const; +}; + +bool CanBuyAnother(RandomizerCheck rc); + +namespace Rando { + class Entrance; + enum class EntranceType; +} + +class Region { + public: + Region(); + Region( + std::string regionName_, + std::string scene_, + std::set areas, + bool timePass_, + std::vector events_, + std::vector locations_, + std::list exits_ + ); + ~Region(); + + std::string regionName; + std::string scene; + std::set areas; + 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;; + + void ApplyTimePass(); + + bool UpdateEvents(); + + void AddExit(RandomizerRegion parentKey, RandomizerRegion newExitKey, ConditionFn condition); + + void RemoveExit(Rando::Entrance* exitToRemove); + + void SetAsPrimary(RandomizerRegion exitToBePrimary); + + Rando::Entrance* GetExit(RandomizerRegion 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(RandomizerRegion exitKey); + + std::set GetAllAreas() const{ + return areas; + } + + RandomizerArea GetFirstArea() const{ + if (areas.empty()){ + assert(false); + return RA_NONE; + } else { + return *areas.begin(); + } + } + + void ReplaceAreas(std::set newAreas) { + areas = newAreas; + } + + //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 Here(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(); + + //heck condition as well as having at least child or adult access + bool hereVal = condition() && (logic->IsAdult || logic->IsChild); + + //set back age variables + logic->IsChild = pastChild; + logic->IsAdult = pastAdult; + + 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); + } + + /* + * This logic covers checks that exist in the shared areas of MQ spirit from a glitchless standpoint. + * This room has Quantum logic that I am currently handling with this function, however this is NOT suitable for glitch logic as it relies on specific ages + * In this chunk there are 3 possibilities for passing a check, but first I have to talk about parallel universes. + + * In MQ Spirit key logic, we mostly care about 2 possibilities for how the player can spend keys, creating 2 Parralel universes + * In the first universe, the player did not enter spirit as adult until after climbing as child, thus child spends keys linearly, only needing 2 to reach statue room. + * In the second universe, the player went in as adult, possibly out of logic, and started wasting the keys to lock child out. + * These Universes converge when the player has 7 keys (meaning adult can no longer lock child out) and adult is known to be able to reach Statue room. This creates "Certain Access", which is tracked seperatly for each age. + * Child Certain Access is simple, if we have 7 keys and child access, it's Certain Access. + * Adult Certain Access is also simple, adult is not key locked, so if they make it to a location, it's Certain Access. + * Things get complicated when we handle the overlap of the 2 universes, + * though an important detail is that if we have Certain Access as either age, we don't need to checked the overlap because overlap logic is strictly stricter than either Certain Access. + + * In order to track the first universe, the logic allows technical child access with the minimum number of keys, and then checks in this function for if we have 7 keys to determine if that is Certain or not. + * This is for technical reasons, as areas with no access at all will simply not be checked. + * Normally we would need to do similar shenanigans to track the second universe, however adult must have go through statue room to waste keys, + * so can go back there and get new keys for Child to use if they do, and the navigation logic for shared MQ spirit from Statue Room is very simple for Adult. + * Additionally, we don't need to know if adult can actually reach spirit temple or climb to statue room, because if the player can't do that, then universe 2 can't happen anyway, + * and if the player does so out of logic, they can do it again, as the only consumable used sets a permanent flag. + + * The Adult Navigation logic is as such: + * - Broken Wall room is 6 key locked, because if the player tries to spend 6 keys in a way that would block adults access, they would have to give child access instead. + * - The child side hammer switch for the time travelling chest is 7 key locked for adult + * - Reaching gauntlets hand is 7 key locked + * - Going back into big block room is complex, but the only check there is child only so not a concern + * - Everything else is possible with basic adult movement, or is impossible for child to reach glitchlessly + * Anything 7 key locked does not need to be checked as shared, as all child access is Certain and because of this workaround we don't need to fake Adult access, meaning that is also Certain. + * All of this combined means that when checking if adult can reach a location in universe 2, we only have to ask if it is a 6 key locked location or not. + + * Knowing all of this this, we can confirm things are logical in 3 different ways: + * - If we have Adult Access, we know it is Certain Access, so they can get checks alone. + * - If we have 7 keys, child has Certain Access as we know they cannot be locked out, so can get checks alone, otherwise we check the logical overlap + * - If Child and Adult can get the check (ignoring actual adult access to the location), and the location is either not 6 key locked or we have 6 keys, we can get the check with the overlap + */ + bool MQSpiritShared(ConditionFn condition, bool IsBrokenWall, bool anyAge = false) { + //if we have Certain Access as child, we can check anyAge and if true, resolve a condition with Here as if adult is here it's also Certain Access + if (logic->SmallKeys(RR_SPIRIT_TEMPLE, 7)){ + if (anyAge){ + return Here(condition); + } + return condition(); + //else, if we are here as adult, we have Certain Access from that and don't need special handling for checking adult + } else if (Adult() && logic->IsAdult){ + return condition(); + //if we do not have Certain Access, we need to check the overlap by seeing if we are both here as child and meet the adult universe's access condition + //We only need to do it as child, as only child access matters for this check, as adult access is assumed based on keys + } else if (Child() && logic->IsChild && (!IsBrokenWall || logic->SmallKeys(RR_SPIRIT_TEMPLE, 6))) { + bool result = false; + //store current age variables + bool pastAdult = logic->IsAdult; + bool pastChild = logic->IsChild; + + //First check if the check is possible as child + logic->IsChild = true; + logic->IsAdult = false; + result = condition(); + //If so, check again as adult. both have to be true for result to be true + if (result) { + logic->IsChild = false; + logic->IsAdult = true; + result = condition(); + } + + //set back age variables + logic->IsChild = pastChild; + logic->IsAdult = pastAdult; + return result; + } + return false; + } +}; + +extern std::array areaTable; +extern std::vector grottoEvents; + +bool Here(const RandomizerRegion region, ConditionFn condition); //RANDOTODO make a less stupid way to check own at either age than self referencing with this +bool MQSpiritSharedStatueRoom(const RandomizerRegion region, ConditionFn condition, bool anyAge = false); +bool MQSpiritSharedBrokenWallRoom(const RandomizerRegion region, ConditionFn condition, bool anyAge = false); +bool CanPlantBean(const RandomizerRegion region); +bool BothAges(const RandomizerRegion region); +bool ChildCanAccess(const RandomizerRegion region); +bool AdultCanAccess(const RandomizerRegion region); +bool HasAccessTo(const RandomizerRegion region); + +#define DAY_NIGHT_CYCLE true +#define NO_DAY_NIGHT_CYCLE false + +namespace Regions { + extern void AccessReset(); + extern void ResetAllLocations(); + extern bool HasTimePassAccess(uint8_t age); + extern void DumpWorldGraph(std::string str); +} //namespace Exits + +void RegionTable_Init(); +Region* RegionTable(const RandomizerRegion regionKey); +std::vector GetShuffleableEntrances(Rando::EntranceType type, bool onlyPrimary = true); +Rando::Entrance* GetEntrance(const std::string name); + +// Overworld +void RegionTable_Init_KokiriForest(); +void RegionTable_Init_LostWoods(); +void RegionTable_Init_SacredForestMeadow(); +void RegionTable_Init_HyruleField(); +void RegionTable_Init_LakeHylia(); +void RegionTable_Init_LonLonRanch(); +void RegionTable_Init_Market(); +void RegionTable_Init_TempleOfTime(); +void RegionTable_Init_CastleGrounds(); +void RegionTable_Init_Kakariko(); +void RegionTable_Init_Graveyard(); +void RegionTable_Init_DeathMountainTrail(); +void RegionTable_Init_GoronCity(); +void RegionTable_Init_DeathMountainCrater(); +void RegionTable_Init_ZoraRiver(); +void RegionTable_Init_ZorasDomain(); +void RegionTable_Init_ZorasFountain(); +void RegionTable_Init_GerudoValley(); +void RegionTable_Init_GerudoFortress(); +void RegionTable_Init_HauntedWasteland(); +void RegionTable_Init_DesertColossus(); +// Dungeons +void RegionTable_Init_DekuTree(); +void RegionTable_Init_DodongosCavern(); +void RegionTable_Init_JabuJabusBelly(); +void RegionTable_Init_ForestTemple(); +void RegionTable_Init_FireTemple(); +void RegionTable_Init_WaterTemple(); +void RegionTable_Init_SpiritTemple(); +void RegionTable_Init_ShadowTemple(); +void RegionTable_Init_BottomOfTheWell(); +void RegionTable_Init_IceCavern(); +void RegionTable_Init_GerudoTrainingGround(); +void RegionTable_Init_GanonsCastle(); \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/bottom_of_the_well.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/bottom_of_the_well.cpp new file mode 100644 index 000000000..588d32bf1 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/bottom_of_the_well.cpp @@ -0,0 +1,296 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" +#include "soh/Enhancements/randomizer/dungeon.h" + +using namespace Rando; + +void RegionTable_Init_BottomOfTheWell() { + // Vanilla/MQ Decider + areaTable[RR_BOTTOM_OF_THE_WELL_ENTRYWAY] = Region("Bottom of the Well Entryway", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + //Technically involves an fake wall, but passing it lensless is intended in vanilla and it is well telegraphed + Entrance(RR_BOTTOM_OF_THE_WELL_PERIMETER, []{return ctx->GetDungeon(Rando::BOTTOM_OF_THE_WELL)->IsVanilla() && logic->IsChild && logic->CanPassEnemy(RE_BIG_SKULLTULA);}), + Entrance(RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER, []{return ctx->GetDungeon(Rando::BOTTOM_OF_THE_WELL)->IsMQ() && logic->IsChild;}), + Entrance(RR_KAK_WELL, []{return true;}), + }); + +#pragma region Vanilla + + areaTable[RR_BOTTOM_OF_THE_WELL_PERIMETER] = Region("Bottom of the Well Perimeter", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->StickPot, []{return true;}), + EventAccess(&logic->NutPot, []{return true;}), + EventAccess(&logic->LoweredWaterInsideBotw, []{return logic->CanUse(RG_ZELDAS_LULLABY);}), + }, { + //Locations + LOCATION(RC_BOTTOM_OF_THE_WELL_FRONT_CENTER_BOMBABLE_CHEST, logic->HasExplosives()), + LOCATION(RC_BOTTOM_OF_THE_WELL_FREESTANDING_KEY, (logic->HasItem(RG_BRONZE_SCALE) || logic->LoweredWaterInsideBotw) && logic->CanUse(RG_STICKS) || logic->CanUse(RG_DINS_FIRE)), + LOCATION(RC_BOTTOM_OF_THE_WELL_UNDERWATER_FRONT_CHEST, logic->LoweredWaterInsideBotw), + LOCATION(RC_BOTTOM_OF_THE_WELL_UNDERWATER_LEFT_CHEST, logic->LoweredWaterInsideBotw), + LOCATION(RC_BOTTOM_OF_THE_WELL_NEAR_ENTRANCE_POT_1, logic->CanBreakPots()), + LOCATION(RC_BOTTOM_OF_THE_WELL_NEAR_ENTRANCE_POT_2, logic->CanBreakPots()), + LOCATION(RC_BOTTOM_OF_THE_WELL_UNDERWATER_POT, (logic->CanBreakPots() && logic->LoweredWaterInsideBotw) || logic->CanUse(RG_BOOMERANG)), + }, { + //Exits + Entrance(RR_BOTTOM_OF_THE_WELL_ENTRYWAY, []{return logic->IsChild && logic->CanPassEnemy(RE_BIG_SKULLTULA);}), + Entrance(RR_BOTTOM_OF_THE_WELL_BEHIND_FAKE_WALLS, []{return ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH);}), + Entrance(RR_BOTTOM_OF_THE_WELL_SOUTHWEST_ROOM, []{return ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH);}), + Entrance(RR_BOTTOM_OF_THE_WELL_KEESE_BEAMOS_ROOM, []{return logic->IsChild && logic->SmallKeys(RR_BOTTOM_OF_THE_WELL, 3);}), + Entrance(RR_BOTTOM_OF_THE_WELL_COFFIN_ROOM, []{return logic->LoweredWaterInsideBotw || logic->HasItem(RG_BRONZE_SCALE);}), + Entrance(RR_BOTTOM_OF_THE_WELL_DEAD_HAND_ROOM, []{return logic->LoweredWaterInsideBotw && logic->IsChild;}), + //Falling down into basement requires nothing, but falling down somewhere specific requires lens or lens trick + //kinda questionable given several drops are blocked by rocks, but that's how it was handled before and on N64 + Entrance(RR_BOTTOM_OF_THE_WELL_BASEMENT, []{return true;}), + }); + + //This region combines the Middle with the perimeter's hidden areas. If a warp puts link into the middle without crossing the perimeter or using lens, it will need it's own region + areaTable[RR_BOTTOM_OF_THE_WELL_BEHIND_FAKE_WALLS] = Region("Bottom of the Well Behind Fake Walls", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_BOTTOM_OF_THE_WELL_FRONT_LEFT_FAKE_WALL_CHEST, true), + LOCATION(RC_BOTTOM_OF_THE_WELL_RIGHT_BOTTOM_FAKE_WALL_CHEST, true), + LOCATION(RC_BOTTOM_OF_THE_WELL_COMPASS_CHEST, true), + //N64 has no extra check here, but I can't get past without dealing with the spider or taking a hit + LOCATION(RC_BOTTOM_OF_THE_WELL_CENTER_SKULLTULA_CHEST, logic->CanPassEnemy(RE_BIG_SKULLTULA) || logic->TakeDamage()), + //Not technically behind a wall, but still logically needs lens due to pits + LOCATION(RC_BOTTOM_OF_THE_WELL_BACK_LEFT_BOMBABLE_CHEST, logic->HasExplosives()), + }, { + //Exits + Entrance(RR_BOTTOM_OF_THE_WELL_PERIMETER, []{return ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH);}), + Entrance(RR_BOTTOM_OF_THE_WELL_INNER_ROOMS, []{return logic->SmallKeys(RR_BOTTOM_OF_THE_WELL, 3);}), + Entrance(RR_BOTTOM_OF_THE_WELL_BASEMENT, []{return true;}), + Entrance(RR_BOTTOM_OF_THE_WELL_BASEMENT_PLATFORM, []{return ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH);}), + }); + + //This area can be reached without lens in logic from basement, but that could require silver rupees if they are shuffled. + areaTable[RR_BOTTOM_OF_THE_WELL_SOUTHWEST_ROOM] = Region("Bottom of the Well Southwest Room", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_BOTTOM_OF_THE_WELL_LEFT_SIDE_POT_1, logic->CanBreakPots()), + LOCATION(RC_BOTTOM_OF_THE_WELL_LEFT_SIDE_POT_2, logic->CanBreakPots()), + LOCATION(RC_BOTTOM_OF_THE_WELL_LEFT_SIDE_POT_3, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_BOTTOM_OF_THE_WELL_PERIMETER, []{return ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH);}), + }); + + //Passing through this area needs lens, but entering doesn't, so that the fire keese can be killed without crossing the pits if enemy drops are ever shuffled + areaTable[RR_BOTTOM_OF_THE_WELL_KEESE_BEAMOS_ROOM] = Region("Bottom of the Well Keese-Beamos Room", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_BOTTOM_OF_THE_WELL_FIRE_KEESE_CHEST, ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH)), + LOCATION(RC_BOTTOM_OF_THE_WELL_FIRE_KEESE_POT_1, logic->CanBreakPots() && (ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH))), + }, { + //Exits + Entrance(RR_BOTTOM_OF_THE_WELL_PERIMETER, []{return logic->IsChild && logic->SmallKeys(RR_BOTTOM_OF_THE_WELL, 3) && (ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH));}), + Entrance(RR_BOTTOM_OF_THE_WELL_LIKE_LIKE_CAGE, []{return ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH);}), + //not sure if this lens check is needed, these holes are a bit too easy to find, but it matches existing logic + Entrance(RR_BOTTOM_OF_THE_WELL_BASEMENT_USEFUL_BOMB_FLOWERS, []{return ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH);}), + }); + + areaTable[RR_BOTTOM_OF_THE_WELL_LIKE_LIKE_CAGE] = Region("Bottom of the Well Like-Like Cage", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_BOTTOM_OF_THE_WELL_LIKE_LIKE_CHEST, true), + LOCATION(RC_BOTTOM_OF_THE_WELL_GS_LIKE_LIKE_CAGE, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)), + }, { + //Exits + Entrance(RR_BOTTOM_OF_THE_WELL_KEESE_BEAMOS_ROOM, []{return true;}), + }); + + //If the player can voidwarp into one of these rooms they will need splitting up, and Fake walls will need specifying into middle and the rest moved to perimeter + areaTable[RR_BOTTOM_OF_THE_WELL_INNER_ROOMS] = Region("Bottom of the Well Inner Rooms", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->DekuBabaSticks, []{return logic->CanGetDekuBabaSticks();}), + EventAccess(&logic->DekuBabaNuts, []{return logic->CanGetDekuBabaNuts();}), + }, { + //Locations + LOCATION(RC_BOTTOM_OF_THE_WELL_GS_WEST_INNER_ROOM, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)), + LOCATION(RC_BOTTOM_OF_THE_WELL_GS_EAST_INNER_ROOM, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)), + }, { + //Exits + Entrance(RR_BOTTOM_OF_THE_WELL_BEHIND_FAKE_WALLS, []{return logic->SmallKeys(RR_BOTTOM_OF_THE_WELL, 3);}), + }); + + areaTable[RR_BOTTOM_OF_THE_WELL_COFFIN_ROOM] = Region("Bottom of the Well Coffin Room", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_BOTTOM_OF_THE_WELL_FREESTANDING_KEY, logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW)), + LOCATION(RC_BOTTOM_OF_THE_WELL_COFFIN_ROOM_FRONT_LEFT_HEART, logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW)), + LOCATION(RC_BOTTOM_OF_THE_WELL_COFFIN_ROOM_MIDDLE_RIGHT_HEART, logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW)), + }, { + //Exits + Entrance(RR_BOTTOM_OF_THE_WELL_PERIMETER, []{return logic->LoweredWaterInsideBotw || logic->HasItem(RG_BRONZE_SCALE);}), + }); + + areaTable[RR_BOTTOM_OF_THE_WELL_DEAD_HAND_ROOM] = Region("Bottom of the Well Dead Hand Room", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_BOTTOM_OF_THE_WELL_LENS_OF_TRUTH_CHEST, logic->CanKillEnemy(RE_DEAD_HAND)), + LOCATION(RC_BOTTOM_OF_THE_WELL_INVISIBLE_CHEST, (ctx->GetTrickOption(RT_LENS_BOTW) || logic->CanUse(RG_LENS_OF_TRUTH))), + }, { + //Exits + //This assumes we spawned in dead hand's room, if whatever trick made this relevant instead puts us in the previous room, remove the kill Dead Hand check. + Entrance(RR_BOTTOM_OF_THE_WELL_PERIMETER, []{return logic->IsChild && logic->CanKillEnemy(RE_DEAD_HAND);}), + }); + + areaTable[RR_BOTTOM_OF_THE_WELL_BASEMENT] = Region("Bottom of the Well Basement", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_BOTTOM_OF_THE_WELL_MAP_CHEST, logic->BlastOrSmash()), + LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_1, logic->CanBreakPots()), + LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_2, logic->CanBreakPots()), + LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_3, logic->CanBreakPots()), + LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_4, logic->CanBreakPots()), + LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_5, logic->CanBreakPots()), + LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_6, logic->CanBreakPots()), + LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_7, logic->CanBreakPots()), + LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_8, logic->CanBreakPots()), + LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_9, logic->CanBreakPots()), + LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_10, logic->CanBreakPots()), + LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_11, logic->CanBreakPots()), + LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_POT_12, logic->CanBreakPots()), + LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_SUN_FAIRY, logic->CanUse(RG_SUNS_SONG)), + }, { + //Exits + Entrance(RR_BOTTOM_OF_THE_WELL_SOUTHWEST_ROOM, []{return logic->IsChild && logic->CanPassEnemy(RE_BIG_SKULLTULA);}), + //It's possible top abuse boulder's limited range of collision detection to detonate the flowers through the boulder with bow, but this is a glitch + //the exact range is just past the furthest away plank in the green goo section + Entrance(RR_BOTTOM_OF_THE_WELL_BASEMENT_USEFUL_BOMB_FLOWERS, []{return Here(RR_BOTTOM_OF_THE_WELL_BASEMENT, []{return logic->BlastOrSmash() || logic->CanUse(RG_DINS_FIRE) || (logic->CanUse(RG_STICKS) && ctx->GetTrickOption(RT_BOTW_BASEMENT));});}), + }); + + areaTable[RR_BOTTOM_OF_THE_WELL_BASEMENT_USEFUL_BOMB_FLOWERS] = Region("Bottom of the Well Basement Useful Bomb Flowers", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + //Assumes RR_BOTTOM_OF_THE_WELL_BASEMENT access + LOCATION(RC_BOTTOM_OF_THE_WELL_MAP_CHEST, logic->HasItem(RG_GORONS_BRACELET)), + }, { + //Exits + Entrance(RR_BOTTOM_OF_THE_WELL_BASEMENT, []{return logic->CanDetonateUprightBombFlower();}), + }); + + areaTable[RR_BOTTOM_OF_THE_WELL_BASEMENT_PLATFORM] = Region("Bottom of the Well Basement Platform", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_PLATFORM_LEFT_RUPEE, true), + LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_PLATFORM_BACK_LEFT_RUPEE, true), + LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_PLATFORM_MIDDLE_RUPEE, true), + LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_PLATFORM_BACK_RIGHT_RUPEE, true), + LOCATION(RC_BOTTOM_OF_THE_WELL_BASEMENT_PLATFORM_RIGHT_RUPEE, true), + }, { + //Exits + Entrance(RR_BOTTOM_OF_THE_WELL_BASEMENT, []{return true;}), + }); + +#pragma endregion + +#pragma region MQ + + areaTable[RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER] = Region("Bottom of the Well MQ Perimeter", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, { + //Events + //technically obsolete due to a wonder item fairy which only needs a projectile, but we don't have an event var for it yet + EventAccess(&logic->FairyPot, []{return Here(RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER, []{return logic->BlastOrSmash();}) && logic->CanHitEyeTargets();}), + //It is possible to hit the water switch with a pot from RR_BOTTOM_OF_THE_WELL_MQ_MIDDLE, however the hitbox for making it activate is very unintuitive + //You have to throw the pot from further back to hit the switch from the front instead of the top, trying to hit the "fingers" directly + //This unintuitiveness means it should be a trick. ZL is needed to get a clear path to carry the pot + EventAccess(&logic->LoweredWaterInsideBotw, []{return logic->CanJumpslash() || logic->CanUseProjectile();}), + }, { + //Locations + //Implies CanBreakPots() + LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_OUTER_LOBBY_POT, Here(RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER, []{return logic->BlastOrSmash();}) && logic->CanHitEyeTargets()), + LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_BOMB_LEFT_HEART, logic->HasExplosives()), + LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_BOMB_RIGHT_HEART, logic->HasExplosives()), + }, { + //Exits + Entrance(RR_BOTTOM_OF_THE_WELL_ENTRYWAY, []{return logic->IsChild;}), + Entrance(RR_BOTTOM_OF_THE_WELL_MQ_WEST_ROOM_SWITCH, []{return Here(RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER, []{return logic->BlastOrSmash();}) && logic->CanPassEnemy(RE_BIG_SKULLTULA);}), + Entrance(RR_BOTTOM_OF_THE_WELL_MQ_COFFIN_ROOM, []{return (logic->LoweredWaterInsideBotw || logic->HasItem(RG_BRONZE_SCALE)) && logic->SmallKeys(RR_BOTTOM_OF_THE_WELL, 2);}), + Entrance(RR_BOTTOM_OF_THE_WELL_MQ_LOCKED_CAGE, []{return logic->IsChild && logic->SmallKeys(RR_BOTTOM_OF_THE_WELL, 2) && logic->CanUseProjectile();}), + Entrance(RR_BOTTOM_OF_THE_WELL_MQ_DEAD_HAND_ROOM, []{return logic->IsChild && logic->LoweredWaterInsideBotw;}), + Entrance(RR_BOTTOM_OF_THE_WELL_MQ_MIDDLE, []{return logic->CanUse(RG_ZELDAS_LULLABY);}), + Entrance(RR_BOTTOM_OF_THE_WELL_MQ_BASEMENT, []{return true;}), + }); + + areaTable[RR_BOTTOM_OF_THE_WELL_MQ_WEST_ROOM_SWITCH] = Region("Bottom of the Well MQ West Room Switch", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->OpenedWestRoomMQBotw, []{return true;}), + }, {}, { + //Exits + Entrance(RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER, []{return logic->BlastOrSmash() && (logic->CanPassEnemy(RE_BIG_SKULLTULA) || ctx->GetTrickOption(RT_BOTW_MQ_PITS));}), + Entrance(RR_BOTTOM_OF_THE_WELL_MQ_MIDDLE, []{return (bool)ctx->GetTrickOption(RT_BOTW_MQ_PITS);}), + Entrance(RR_BOTTOM_OF_THE_WELL_MQ_BASEMENT, []{return true;}), + }); + + areaTable[RR_BOTTOM_OF_THE_WELL_MQ_COFFIN_ROOM] = Region("Bottom of the Well MQ Coffin Room", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_GS_COFFIN_ROOM, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)), + LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_COFFIN_ROOM_FRONT_RIGHT_HEART, logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW)), + LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_COFFIN_ROOM_MIDDLE_LEFT_HEART, logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW)), + }, { + //Exits + Entrance(RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER, []{return (logic->LoweredWaterInsideBotw || logic->HasItem(RG_BRONZE_SCALE)) && logic->SmallKeys(RR_BOTTOM_OF_THE_WELL, 2);}), + }); + + areaTable[RR_BOTTOM_OF_THE_WELL_MQ_LOCKED_CAGE] = Region("Bottom of the Well MQ Locked Cage", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->OpenedMiddleHoleMQBotw, []{return logic->HasExplosives();}), + }, {}, { + //Exits + Entrance(RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER, []{return logic->IsChild && logic->SmallKeys(RR_BOTTOM_OF_THE_WELL, 2);}), + }); + + areaTable[RR_BOTTOM_OF_THE_WELL_MQ_DEAD_HAND_ROOM] = Region("Bottom of the Well MQ Dead Hand Room", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_COMPASS_CHEST, logic->CanKillEnemy(RE_DEAD_HAND)), + LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_DEAD_HAND_FREESTANDING_KEY, logic->HasExplosives() || (ctx->GetTrickOption(RT_BOTW_MQ_DEADHAND_KEY) && logic->CanUse(RG_BOOMERANG))), + }, { + //Exits + //This assumes we spawned in dead hand's room, if whatever trick made this relevant instead puts us in the previous room, remove the kill Dead Hand check. + Entrance(RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER, []{return logic->IsChild && logic->CanKillEnemy(RE_DEAD_HAND);}), + }); + + areaTable[RR_BOTTOM_OF_THE_WELL_MQ_MIDDLE] = Region("Bottom of the Well MQ Middle", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_MAP_CHEST, true), + //This location technically involves an invisible platform, but it's intended to do lensless in vanilla and is clearly signposted by pots. + LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_EAST_INNER_ROOM_FREESTANDING_KEY, true), + //The enemies in this room are invisible and crowd around the player, being awkward to deal with blind unless you already know how. + //the right wall is safe, and can be followed to get behind the grave which you can then pull easily assuming you can tank invisible keese + //Using a deku nut however stuns everything easily. and if you have a melee weapon you can kill the skull through the grave then grab the drop + //though it can be hard to tell where the safe direct path to the grave is without lens. + //Also you get cheap shotted on entry sometimes. + //An MQ lens trick is recommended here, and a review of this room for OHKO logic what that is added is advised. + //In the meantime I assume damage taken or the easy answer (nuts) + LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_GS_WEST_INNER_ROOM, logic->OpenedWestRoomMQBotw && (logic->TakeDamage() || logic->CanUse(RG_NUTS)) && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)), + LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_INNER_LOBBY_POT_1, logic->CanBreakPots()), + LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_INNER_LOBBY_POT_2, logic->CanBreakPots()), + LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_INNER_LOBBY_POT_3, logic->CanBreakPots()), + LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_EAST_INNER_ROOM_POT_1, logic->CanBreakPots()), + LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_EAST_INNER_ROOM_POT_2, logic->CanBreakPots()), + LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_EAST_INNER_ROOM_POT_3, logic->CanBreakPots()), + LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_CELL_SUN_FAIRY, logic->CanUse(RG_SUNS_SONG)), + }, { + //Exits + //If a relevant trick causes you to be able to warp into here without going through PERIMETER, a new eventAccess will be needed for lowering the gates with ZL + Entrance(RR_BOTTOM_OF_THE_WELL_MQ_BASEMENT_SWITCH_PLATFORM, []{return logic->OpenedMiddleHoleMQBotw;}), + Entrance(RR_BOTTOM_OF_THE_WELL_MQ_BASEMENT, []{return true;}), + }); + + areaTable[RR_BOTTOM_OF_THE_WELL_MQ_BASEMENT] = Region("Bottom of the Well MQ Basement", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + //behind invisible big skulltulas, but with navi spotting it's easy to avoid them, or at worst, tank your way through as they do not block the path + LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_GS_BASEMENT, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)), + LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_BASEMENT_HALLWAY_FRONT_HEART, true), + LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_BASEMENT_HALLWAY_LEFT_HEART, true), + LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_BASEMENT_HALLWAY_RIGHT_HEART, true), + LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_BASEMENT_SUN_FAIRY, logic->CanUse(RG_SUNS_SONG)), + }, { + //Exits + Entrance(RR_BOTTOM_OF_THE_WELL_MQ_PERIMETER, []{return true;}), + }); + + areaTable[RR_BOTTOM_OF_THE_WELL_MQ_BASEMENT_SWITCH_PLATFORM] = Region("Bottom of the Well MQ Basement Switch Platform", "Bottom of the Well", {RA_BOTTOM_OF_THE_WELL}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + //Assumes RR_BOTTOM_OF_THE_WELL_MQ_BASEMENT access + //it is technically possible to get the chest before you get screamed at without rolling, but hard enough to be a trick if that is the requirement for something to be logical + //With some kind of movement tech it's much easier, easy enough to be default logic, as the redeads don't lock on immediately in addition to the extra speed + //leaving with no requirements for now but up for discussion. + LOCATION(RC_BOTTOM_OF_THE_WELL_MQ_LENS_OF_TRUTH_CHEST, true), + }, { + //Exits + Entrance(RR_BOTTOM_OF_THE_WELL_MQ_BASEMENT, []{return true;}), + }); + +#pragma endregion +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/deku_tree.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/deku_tree.cpp new file mode 100644 index 000000000..9d3febe36 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/deku_tree.cpp @@ -0,0 +1,363 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" +#include "soh/Enhancements/randomizer/dungeon.h" + +using namespace Rando; + +void RegionTable_Init_DekuTree() { + // Vanilla/MQ Decider + areaTable[RR_DEKU_TREE_ENTRYWAY] = Region("Deku Tree Entryway", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_DEKU_TREE_LOBBY, []{return ctx->GetDungeon(DEKU_TREE)->IsVanilla();}), + Entrance(RR_DEKU_TREE_MQ_1F, []{return ctx->GetDungeon(DEKU_TREE)->IsMQ();}), + Entrance(RR_KF_OUTSIDE_DEKU_TREE, []{return true;}), + }); + +#pragma region Vanilla + + areaTable[RR_DEKU_TREE_LOBBY] = Region("Deku Tree Lobby", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->DekuBabaSticks, []{return logic->CanGetDekuBabaSticks();}), + EventAccess(&logic->DekuBabaNuts, []{return logic->CanGetDekuBabaNuts();}), + }, { + //Locations + LOCATION(RC_DEKU_TREE_MAP_CHEST, true), + LOCATION(RC_DEKU_TREE_LOBBY_LOWER_HEART, true), + LOCATION(RC_DEKU_TREE_LOBBY_UPPER_HEART, logic->CanPassEnemy(RE_BIG_SKULLTULA)), + }, { + //Exits + Entrance(RR_DEKU_TREE_ENTRYWAY, []{return true;}), + Entrance(RR_DEKU_TREE_2F_MIDDLE_ROOM, []{return true;}), + Entrance(RR_DEKU_TREE_COMPASS_ROOM, []{return true;}), + Entrance(RR_DEKU_TREE_BASEMENT_LOWER, []{return Here(RR_DEKU_TREE_LOBBY, []{return logic->CanAttack() || logic->CanUse(RG_NUTS);});}), + Entrance(RR_DEKU_TREE_OUTSIDE_BOSS_ROOM, []{return false;}), + Entrance(RR_DEKU_TREE_BOSS_ENTRYWAY, []{return false;}), + }); + + areaTable[RR_DEKU_TREE_2F_MIDDLE_ROOM] = Region("Deku Tree 2F Middle Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_DEKU_TREE_LOBBY, []{return Here(RR_DEKU_TREE_2F_MIDDLE_ROOM, []{return logic->CanReflectNuts() || logic->CanUse(RG_MEGATON_HAMMER);});}), + Entrance(RR_DEKU_TREE_SLINGSHOT_ROOM, []{return Here(RR_DEKU_TREE_2F_MIDDLE_ROOM, []{return logic->CanReflectNuts() || logic->CanUse(RG_MEGATON_HAMMER);});}), + }); + + areaTable[RR_DEKU_TREE_SLINGSHOT_ROOM] = Region("Deku Tree Slingshot Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DEKU_TREE_SLINGSHOT_CHEST, true), + LOCATION(RC_DEKU_TREE_SLINGSHOT_ROOM_SIDE_CHEST, true), + }, { + //Exits + Entrance(RR_DEKU_TREE_2F_MIDDLE_ROOM, []{return logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_HOVER_BOOTS);}), + }); + + areaTable[RR_DEKU_TREE_COMPASS_ROOM] = Region("Deku Tree Compass Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->DekuBabaSticks, []{return logic->CanGetDekuBabaSticks();}), + EventAccess(&logic->DekuBabaNuts, []{return logic->CanGetDekuBabaNuts();}), + }, { + //Locations + LOCATION(RC_DEKU_TREE_COMPASS_CHEST, true), + LOCATION(RC_DEKU_TREE_COMPASS_ROOM_SIDE_CHEST, true), + LOCATION(RC_DEKU_TREE_GS_COMPASS_ROOM, logic->CanAttack()), + }, { + //Exits + Entrance(RR_DEKU_TREE_LOBBY, []{return logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW);}), + Entrance(RR_DEKU_TREE_BOSS_ENTRYWAY, []{return false;}), + }); + + areaTable[RR_DEKU_TREE_BASEMENT_LOWER] = Region("Deku Tree Basement Lower", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->DekuBabaSticks, []{return logic->CanGetDekuBabaSticks();}), + EventAccess(&logic->DekuBabaNuts, []{return logic->CanGetDekuBabaNuts();}), + }, { + //Locations + LOCATION(RC_DEKU_TREE_BASEMENT_CHEST, true), + LOCATION(RC_DEKU_TREE_GS_BASEMENT_GATE, logic->CanJumpslashExceptHammer() || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_BOOMERANG) || logic->HasExplosives() || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_DINS_FIRE)), + LOCATION(RC_DEKU_TREE_GS_BASEMENT_VINES, logic->CanUseProjectile() || logic->CanUse(RG_DINS_FIRE) || (ctx->GetTrickOption(RT_DEKU_MQ_COMPASS_GS) && logic->CanJumpslashExceptHammer())), + }, { + //Exits + Entrance(RR_DEKU_TREE_LOBBY, []{return true;}), + Entrance(RR_DEKU_TREE_BASEMENT_SCRUB_ROOM, []{return Here(RR_DEKU_TREE_BASEMENT_LOWER, []{return logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW);});}), + Entrance(RR_DEKU_TREE_BASEMENT_UPPER, []{return logic->IsAdult || ctx->GetTrickOption(RT_DEKU_B1_SKIP) || HasAccessTo(RR_DEKU_TREE_BASEMENT_UPPER);}), + Entrance(RR_DEKU_TREE_OUTSIDE_BOSS_ROOM, []{return false;}), + }); + + areaTable[RR_DEKU_TREE_BASEMENT_SCRUB_ROOM] = Region("Deku Tree Basement Scrub Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_DEKU_TREE_BASEMENT_LOWER, []{return true;}), + Entrance(RR_DEKU_TREE_BASEMENT_WATER_ROOM_FRONT, []{return Here(RR_DEKU_TREE_BASEMENT_SCRUB_ROOM, []{return logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_FAIRY_BOW);});}), + }); + + areaTable[RR_DEKU_TREE_BASEMENT_WATER_ROOM_FRONT] = Region("Deku Tree Basement Water Room Front", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_DEKU_TREE_BASEMENT_SCRUB_ROOM, []{return true;}), + Entrance(RR_DEKU_TREE_BASEMENT_WATER_ROOM_BACK, []{return logic->HasItem(RG_BRONZE_SCALE) || ctx->GetTrickOption(RT_DEKU_B1_BACKFLIP_OVER_SPIKED_LOG);}), + }); + + areaTable[RR_DEKU_TREE_BASEMENT_WATER_ROOM_BACK] = Region("Deku Tree Basement Water Room Back", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_DEKU_TREE_BASEMENT_WATER_ROOM_FRONT, []{return logic->HasItem(RG_BRONZE_SCALE) || ctx->GetTrickOption(RT_DEKU_B1_BACKFLIP_OVER_SPIKED_LOG);}), + Entrance(RR_DEKU_TREE_BASEMENT_TORCH_ROOM, []{return true;}), + }); + + areaTable[RR_DEKU_TREE_BASEMENT_TORCH_ROOM] = Region("Deku Tree Basement Torch Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->DekuBabaSticks, []{return logic->CanGetDekuBabaSticks();}), + EventAccess(&logic->DekuBabaNuts, []{return logic->CanGetDekuBabaNuts();}), + }, {}, { + //Exits + Entrance(RR_DEKU_TREE_BASEMENT_WATER_ROOM_BACK, []{return true;}), + Entrance(RR_DEKU_TREE_BASEMENT_BACK_LOBBY, []{return Here(RR_DEKU_TREE_BASEMENT_TORCH_ROOM, []{return logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW);});}), + }); + + areaTable[RR_DEKU_TREE_BASEMENT_BACK_LOBBY] = Region("Deku Tree Basement Back Lobby", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->DekuBabaSticks, []{return logic->CanGetDekuBabaSticks();}), + EventAccess(&logic->DekuBabaNuts, []{return logic->CanGetDekuBabaNuts();}), + }, {}, { + //Exits + Entrance(RR_DEKU_TREE_BASEMENT_TORCH_ROOM, []{return true;}), + Entrance(RR_DEKU_TREE_BASEMENT_BACK_ROOM, []{return Here(RR_DEKU_TREE_BASEMENT_BACK_LOBBY, []{return logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW);}) && Here(RR_DEKU_TREE_BASEMENT_BACK_LOBBY, []{return logic->BlastOrSmash();});}), + Entrance(RR_DEKU_TREE_BASEMENT_UPPER, []{return Here(RR_DEKU_TREE_BASEMENT_BACK_LOBBY, []{return logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW);}) && logic->IsChild;}), + }); + + areaTable[RR_DEKU_TREE_BASEMENT_BACK_ROOM] = Region("Deku Tree Basement Back Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DEKU_TREE_GS_BASEMENT_BACK_ROOM, logic->HookshotOrBoomerang()), + }, { + //Exits + Entrance(RR_DEKU_TREE_BASEMENT_BACK_LOBBY, []{return true;}), + }); + + areaTable[RR_DEKU_TREE_BASEMENT_UPPER] = Region("Deku Tree Basement Upper", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->DekuBabaSticks, []{return logic->CanGetDekuBabaSticks();}), + EventAccess(&logic->DekuBabaNuts, []{return logic->CanGetDekuBabaNuts();}), + }, {}, { + //Exits + Entrance(RR_DEKU_TREE_BASEMENT_LOWER, []{return true;}), + Entrance(RR_DEKU_TREE_BASEMENT_BACK_LOBBY, []{return logic->IsChild;}), + Entrance(RR_DEKU_TREE_OUTSIDE_BOSS_ROOM, []{return Here(RR_DEKU_TREE_BASEMENT_UPPER, []{return logic->HasFireSourceWithTorch() || (ctx->GetTrickOption(RT_DEKU_B1_BOW_WEBS) && logic->IsAdult && logic->CanUse(RG_FAIRY_BOW));});}), + }); + + areaTable[RR_DEKU_TREE_OUTSIDE_BOSS_ROOM] = Region("Deku Tree Outside Boss Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DEKU_TREE_BEFORE_BOSS_LEFT_HEART, logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG)), + LOCATION(RC_DEKU_TREE_BEFORE_BOSS_MIDDLE_HEART, logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG)), + LOCATION(RC_DEKU_TREE_BEFORE_BOSS_RIGHT_HEART, logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG)), + }, { + //Exits + Entrance(RR_DEKU_TREE_BASEMENT_UPPER, []{return true;}), + Entrance(RR_DEKU_TREE_BOSS_ENTRYWAY, []{return (logic->HasItem(RG_BRONZE_SCALE) || Here(RR_DEKU_TREE_OUTSIDE_BOSS_ROOM, []{return logic->CanUse(RG_IRON_BOOTS);})) && Here(RR_DEKU_TREE_OUTSIDE_BOSS_ROOM, []{return logic->CanReflectNuts();});}), + }); + +#pragma endregion + +#pragma region MQ + + areaTable[RR_DEKU_TREE_MQ_1F] = Region("Deku Tree MQ 1F", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->DekuBabaSticks, []{return logic->CanKillEnemy(RE_WITHERED_DEKU_BABA);}), + EventAccess(&logic->BrokeDeku1FWeb, []{return logic->HasFireSource();}), + }, {}, { + //Exits + Entrance(RR_DEKU_TREE_ENTRYWAY, []{return true;}), + //may need canAvoid logic with enemy shuffle + Entrance(RR_DEKU_TREE_MQ_2F, []{return true;}), + //Swim is not required because you can jump with enough momentum to hit land. + //You even avoid fall damage if you hit the shallow water, though it's obscure knowledge so may be a trick + //if it is, then we need a landing room with (IsAdult || HasItem(RG_BRONZE_SCALE) || TakeDamage() || that trick) to reach basement + Entrance(RR_DEKU_TREE_MQ_BASEMENT, []{return logic->BrokeDeku1FWeb;}), + //is it possible to recoil from here to the ledge with a trick? + }); + + areaTable[RR_DEKU_TREE_MQ_2F] = Region("Deku Tree MQ 2F", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DEKU_TREE_MQ_MAP_CHEST, true), + LOCATION(RC_DEKU_TREE_MQ_GS_LOBBY, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)), + LOCATION(RC_DEKU_TREE_MQ_LOBBY_HEART, true), + }, { + //Exits + Entrance(RR_DEKU_TREE_MQ_1F, []{return true;}), + //Will need canAvoid logic with enemy shuffle + Entrance(RR_DEKU_TREE_MQ_3F, []{return true;}), + Entrance(RR_DEKU_TREE_MQ_EYE_TARGET_ROOM, []{return Here(RR_DEKU_TREE_MQ_2F, []{return logic->HasFireSource();});}), + }); + + areaTable[RR_DEKU_TREE_MQ_3F] = Region("Deku Tree MQ 3F", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->DekuBabaSticks, []{return logic->CanGetDekuBabaSticks();}), + EventAccess(&logic->DekuBabaNuts, []{return logic->CanGetDekuBabaNuts();}), + EventAccess(&logic->BrokeDeku1FWeb, []{return true;}), + }, { + //Locations + //Implies CanKillEnemy(RE_GOHMA_LARVA) + LOCATION(RC_DEKU_TREE_MQ_SLINGSHOT_CHEST, logic->CanKillEnemy(RE_DEKU_BABA)), + LOCATION(RC_DEKU_TREE_MQ_SLINGSHOT_ROOM_BACK_CHEST, logic->HasFireSourceWithTorch() || (logic->IsAdult && logic->CanUse(RG_FAIRY_BOW))), + LOCATION(RC_DEKU_TREE_MQ_SLINGSHOT_ROOM_HEART, true), + }, { + //Exits + Entrance(RR_DEKU_TREE_MQ_2F, []{return true;}), + //Assumes RR_DEKU_TREE_MQ_2F access + Entrance(RR_DEKU_TREE_MQ_EYE_TARGET_ROOM, []{return Here(RR_DEKU_TREE_MQ_3F, []{return logic->CanUse(RG_STICKS) || logic->CanUse(RG_FAIRY_BOW);});}), + Entrance(RR_DEKU_TREE_MQ_BASEMENT, []{return true;}), + }); + + areaTable[RR_DEKU_TREE_MQ_EYE_TARGET_ROOM] = Region("Deku Tree MQ Eye Target Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DEKU_TREE_MQ_DEKU_BABA_HEART, true), + }, { + //Exits + Entrance(RR_DEKU_TREE_MQ_COMPASS_ROOM, []{return Here(RR_DEKU_TREE_MQ_EYE_TARGET_ROOM, []{return logic->CanHitEyeTargets();});}), + Entrance(RR_DEKU_TREE_MQ_2F, []{return true;}), + }); + + areaTable[RR_DEKU_TREE_MQ_COMPASS_ROOM] = Region("Deku Tree MQ Compass Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DEKU_TREE_MQ_COMPASS_CHEST, true), + }, { + //Exits + Entrance(RR_DEKU_TREE_MQ_EYE_TARGET_ROOM, []{return true;}), + Entrance(RR_DEKU_TREE_MQ_PAST_BOULDER_VINES, []{return Here(RR_DEKU_TREE_MQ_COMPASS_ROOM, []{return logic->CanUse(RG_BOMBCHU_5) || (logic->CanUse(RG_BOMB_BAG) && (logic->CanUse(RG_SONG_OF_TIME) || logic->IsAdult || logic->CanUse(RG_HOVER_BOOTS))) || (logic->CanUse(RG_MEGATON_HAMMER) && (logic->CanUse(RG_SONG_OF_TIME) || ctx->GetTrickOption(RT_DEKU_MQ_COMPASS_GS)));});}), + }); + + areaTable[RR_DEKU_TREE_MQ_PAST_BOULDER_VINES] = Region("Deku Tree MQ Past Boulder Vines", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DEKU_TREE_MQ_GS_PAST_BOULDER_VINES, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)), + LOCATION(RC_DEKU_TREE_MQ_COMPASS_ROOM_HEART, true), + }, { + //Exits + Entrance(RR_DEKU_TREE_MQ_COMPASS_ROOM, []{return logic->BlastOrSmash();}), + }); + + areaTable[RR_DEKU_TREE_MQ_BASEMENT] = Region("Deku Tree MQ Basement", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->DekuBabaSticks, []{return logic->CanGetDekuBabaSticks();}), + EventAccess(&logic->DekuBabaNuts, []{return logic->CanGetDekuBabaNuts();}), + }, { + //Locations + LOCATION(RC_DEKU_TREE_MQ_BASEMENT_CHEST, logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW)), + }, { + //Exits + Entrance(RR_DEKU_TREE_MQ_1F, []{return true;}), + Entrance(RR_DEKU_TREE_MQ_BASEMENT_SOUTHEAST_ROOM, []{return Here(RR_DEKU_TREE_MQ_BASEMENT, []{return logic->CanHitEyeTargets();});}), + //includes RR_DEKU_TREE_MQ_BASEMENT_SOUTHEAST_ROOM Access, other fire sources clear directly from there + Entrance(RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT, []{return Here(RR_DEKU_TREE_MQ_BASEMENT, []{return logic->CanHitEyeTargets();}) && logic->ClearedMQDekuSERoom && Here(RR_DEKU_TREE_MQ_BASEMENT, []{return logic->CanUse(RG_STICKS);});}), + Entrance(RR_DEKU_TREE_MQ_BASEMENT_LEDGE, []{return ctx->GetTrickOption(RT_DEKU_B1_SKIP) || logic->PushedDekuBasementBlock || logic->IsAdult || logic->CanUse(RG_HOVER_BOOTS);}), + }); + + areaTable[RR_DEKU_TREE_MQ_BASEMENT_SOUTHEAST_ROOM] = Region("Deku Tree MQ Southeast Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, { + //Events + //Implies CanKillEnemy(RE_GOHMA_LARVA) + EventAccess(&logic->ClearedMQDekuSERoom, []{return logic->CanKillEnemy(RE_MAD_SCRUB);}), + }, {}, { + //Exits + Entrance(RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT, []{return logic->HasFireSource();}), + Entrance(RR_DEKU_TREE_MQ_BASEMENT, []{return logic->ClearedMQDekuSERoom;}), + }); + + areaTable[RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT] = Region("Deku Tree MQ Basement Water Room Front", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, { + //Events + //It's possible to get this with bow if you have move while in first person and one-point skips on, noticeably harder and jankier as child, but that's a trick + EventAccess(&logic->MQDekuWaterRoomTorches, []{return logic->CanUse(RG_FIRE_ARROWS) || (logic->CanUse(RG_STICKS) && (ctx->GetTrickOption(RT_DEKU_MQ_LOG) || (logic->IsChild && logic->CanShield())));}), + }, { + //Locations + LOCATION(RC_DEKU_TREE_MQ_BEFORE_SPINNING_LOG_CHEST, true), + }, { + //Exits + Entrance(RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK, []{return ctx->GetTrickOption(RT_DEKU_MQ_LOG) || (logic->IsChild && logic->CanShield()) || logic->CanUse(RG_LONGSHOT) || (logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_IRON_BOOTS));}), + Entrance(RR_DEKU_TREE_MQ_BASEMENT_SOUTHEAST_ROOM, []{return true;}), + }); + + areaTable[RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK] = Region("Deku Tree MQ Basement Water Room Back", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->DekuBabaSticks, []{return logic->CanKillEnemy(RE_WITHERED_DEKU_BABA);}), + EventAccess(&logic->MQDekuWaterRoomTorches, []{return logic->HasFireSource();}), + }, { + //Locations + //it blocks the chest while stunned unless you stun it from afar while it's slightly off the ground + LOCATION(RC_DEKU_TREE_MQ_AFTER_SPINNING_LOG_CHEST, logic->CanUse(RG_SONG_OF_TIME) && logic->CanPassEnemy(RE_BIG_SKULLTULA)), + }, { + //Exits + Entrance(RR_DEKU_TREE_MQ_BASEMENT_SOUTHWEST_ROOM, []{return logic->MQDekuWaterRoomTorches && logic->CanPassEnemy(RE_BIG_SKULLTULA, logic->CanUse(RG_SONG_OF_TIME) ? ED_CLOSE : ED_SHORT_JUMPSLASH);}), + Entrance(RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_FRONT, []{return ctx->GetTrickOption(RT_DEKU_MQ_LOG) || (logic->IsChild && logic->CanShield()) || logic->CanUse(RG_LONGSHOT) || logic->HasItem(RG_BRONZE_SCALE) || (logic->CanUse(RG_IRON_BOOTS) && (logic->IsAdult || logic->CanUse(RG_HOOKSHOT)));}), + }); + + areaTable[RR_DEKU_TREE_MQ_BASEMENT_SOUTHWEST_ROOM] = Region("Deku Tree MQ Basement Southwest Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + //both imply CanKillEnemy(RE_GOHMA_LARVA) + Entrance(RR_DEKU_TREE_MQ_BASEMENT_GRAVE_ROOM, []{return Here(RR_DEKU_TREE_MQ_BASEMENT_SOUTHWEST_ROOM, []{return logic->CanKillEnemy(RE_MAD_SCRUB) && logic->CanKillEnemy(RE_KEESE);});}), + Entrance(RR_DEKU_TREE_MQ_BASEMENT_WATER_ROOM_BACK, []{return Here(RR_DEKU_TREE_MQ_BASEMENT_SOUTHWEST_ROOM, []{return logic->CanKillEnemy(RE_MAD_SCRUB) && logic->CanKillEnemy(RE_KEESE);});}), + }); + + areaTable[RR_DEKU_TREE_MQ_BASEMENT_GRAVE_ROOM] = Region("Deku Tree MQ Basement Grave Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->DekuBabaSticks, []{return logic->CanGetDekuBabaSticks();}), + EventAccess(&logic->DekuBabaNuts, []{return logic->CanGetDekuBabaNuts();}) + }, { + //Locations + LOCATION(RC_DEKU_TREE_MQ_GS_BASEMENT_GRAVES_ROOM, logic->CanUse(RG_LONGSHOT) || (logic->CanUse(RG_SONG_OF_TIME) && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG))), + }, { + //Exits + Entrance(RR_DEKU_TREE_MQ_BASEMENT_LEDGE, []{return logic->IsChild && Here(RR_DEKU_TREE_MQ_BASEMENT_GRAVE_ROOM, []{return logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW);});}), + Entrance(RR_DEKU_TREE_MQ_BASEMENT_SOUTHWEST_ROOM, []{return true;}), + //Using a bow to get past here as adult is a bit precise on standing position but simple, doing as as child requires a side-hop with the bow out to shoot through the torch and may be trick worthy + Entrance(RR_DEKU_TREE_MQ_BASEMENT_BACK_ROOM, []{return Here(RR_DEKU_TREE_MQ_BASEMENT_GRAVE_ROOM, []{return logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW);});}), + }); + + areaTable[RR_DEKU_TREE_MQ_BASEMENT_BACK_ROOM] = Region("Deku Tree MQ Basement Back Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DEKU_TREE_MQ_GS_BASEMENT_BACK_ROOM, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)), + }, { + //Exits + Entrance(RR_DEKU_TREE_MQ_BASEMENT_GRAVE_ROOM, []{return true;}), + }); + + areaTable[RR_DEKU_TREE_MQ_BASEMENT_LEDGE] = Region("Deku Tree MQ Basement Ledge", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->PushedDekuBasementBlock, []{return true;}), + }, { + //Locations + LOCATION(RC_DEKU_TREE_MQ_DEKU_SCRUB, logic->CanStunDeku()), + }, { + //Exits + Entrance(RR_DEKU_TREE_MQ_BASEMENT_GRAVE_ROOM, []{return logic->IsChild;}), + Entrance(RR_DEKU_TREE_MQ_BASEMENT, []{return true;}), + //If strength 0 is shuffled, add hovers or block push to the stick check + //recoiling to skip swim is possible, but would be a trick + Entrance(RR_DEKU_TREE_MQ_OUTSIDE_BOSS_ROOM, []{return Here(RR_DEKU_TREE_MQ_BASEMENT_LEDGE, []{return logic->HasFireSource() || (/*logic->PushedDekuBasementBlock && */logic->CanUse(RG_STICKS));}) && (logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS));}), + }); + + areaTable[RR_DEKU_TREE_MQ_OUTSIDE_BOSS_ROOM] = Region("Deku Tree MQ Outside Boss Room", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DEKU_TREE_MQ_BEFORE_BOSS_LEFT_HEART, logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG)), + LOCATION(RC_DEKU_TREE_MQ_BEFORE_BOSS_MIDDLE_HEART, logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG)), + LOCATION(RC_DEKU_TREE_MQ_BEFORE_BOSS_RIGHT_HEART, logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG)), + }, { + //Exits + Entrance(RR_DEKU_TREE_MQ_BASEMENT_LEDGE, []{return logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_HOOKSHOT);}), + Entrance(RR_DEKU_TREE_BOSS_ENTRYWAY, []{return Here(RR_DEKU_TREE_MQ_OUTSIDE_BOSS_ROOM, []{return logic->CanReflectNuts();});}), + }); + +#pragma endregion + + // Boss Room + areaTable[RR_DEKU_TREE_BOSS_ENTRYWAY] = Region("Deku Tree Boss Entryway", "Deku Tree", {RA_DEKU_TREE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + // Exits + Entrance(RR_DEKU_TREE_OUTSIDE_BOSS_ROOM, []{return ctx->GetDungeon(DEKU_TREE)->IsVanilla();}), + Entrance(RR_DEKU_TREE_MQ_OUTSIDE_BOSS_ROOM, []{return ctx->GetDungeon(DEKU_TREE)->IsMQ();}), + Entrance(RR_DEKU_TREE_BOSS_ROOM, []{return true;}), + }); + + areaTable[RR_DEKU_TREE_BOSS_ROOM] = Region("Deku Tree Boss Room", "Deku Tree", {}, NO_DAY_NIGHT_CYCLE, { + // Events + EventAccess(&logic->DekuTreeClear, []{return logic->DekuTreeClear || (logic->HasBossSoul(RG_GOHMA_SOUL) && (logic->CanJumpslashExceptHammer() && (logic->CanUse(RG_NUTS) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_FAIRY_BOW) || logic->HookshotOrBoomerang())));}), + }, { + // Locations + LOCATION(RC_QUEEN_GOHMA, logic->DekuTreeClear), + LOCATION(RC_DEKU_TREE_QUEEN_GOHMA_HEART, logic->DekuTreeClear), + }, { + // Exits + Entrance(RR_DEKU_TREE_BOSS_ENTRYWAY, []{return true;}), + Entrance(RR_KF_OUTSIDE_DEKU_TREE, []{return logic->DekuTreeClear;}, false), + }); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/dodongos_cavern.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/dodongos_cavern.cpp new file mode 100644 index 000000000..eb8be8bb7 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/dodongos_cavern.cpp @@ -0,0 +1,542 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" +#include "soh/Enhancements/randomizer/dungeon.h" + +using namespace Rando; + +void RegionTable_Init_DodongosCavern() { + // Vanilla/MQ Decider + areaTable[RR_DODONGOS_CAVERN_ENTRYWAY] = Region("Dodongos Cavern Entryway", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_DODONGOS_CAVERN_BEGINNING, []{return ctx->GetDungeon(DODONGOS_CAVERN)->IsVanilla();}), + Entrance(RR_DODONGOS_CAVERN_MQ_BEGINNING, []{return ctx->GetDungeon(DODONGOS_CAVERN)->IsMQ();}), + Entrance(RR_DEATH_MOUNTAIN_TRAIL, []{return true;}), + }); + +#pragma region Vanilla + + areaTable[RR_DODONGOS_CAVERN_BEGINNING] = Region("Dodongos Cavern Beginning", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_DODONGOS_CAVERN_ENTRYWAY, []{return true;}), + Entrance(RR_DODONGOS_CAVERN_LOBBY, []{return Here(RR_DODONGOS_CAVERN_BEGINNING, []{return logic->CanBreakMudWalls() || logic->HasItem(RG_GORONS_BRACELET);});}), + }); + + areaTable[RR_DODONGOS_CAVERN_LOBBY] = Region("Dodongos Cavern Lobby", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->GossipStoneFairy, []{return (Here(RR_DODONGOS_CAVERN_LOBBY, []{return logic->CanBreakMudWalls();}) || logic->HasItem(RG_GORONS_BRACELET)) && logic->CallGossipFairy();}), + }, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_MAP_CHEST, Here(RR_DODONGOS_CAVERN_LOBBY, []{return logic->CanBreakMudWalls() || logic->HasItem(RG_GORONS_BRACELET);})), + LOCATION(RC_DODONGOS_CAVERN_DEKU_SCRUB_LOBBY, logic->CanStunDeku() || logic->HasItem(RG_GORONS_BRACELET)), + LOCATION(RC_DODONGOS_CAVERN_GOSSIP_STONE_FAIRY, Here(RR_DODONGOS_CAVERN_LOBBY, []{return logic->CanBreakMudWalls() || logic->HasItem(RG_GORONS_BRACELET);}) && logic->CallGossipFairy()), + LOCATION(RC_DODONGOS_CAVERN_GOSSIP_STONE_FAIRY_BIG, Here(RR_DODONGOS_CAVERN_LOBBY, []{return logic->CanBreakMudWalls() || logic->HasItem(RG_GORONS_BRACELET);}) && logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_DODONGOS_CAVERN_GOSSIP_STONE, Here(RR_DODONGOS_CAVERN_LOBBY, []{return logic->CanBreakMudWalls() || logic->HasItem(RG_GORONS_BRACELET);})), + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_BEGINNING, []{return true;}), + Entrance(RR_DODONGOS_CAVERN_LOBBY_SWITCH, []{return logic->IsAdult;}), + Entrance(RR_DODONGOS_CAVERN_SE_CORRIDOR, []{return Here(RR_DODONGOS_CAVERN_LOBBY, []{return logic->BlastOrSmash() || logic->HasItem(RG_GORONS_BRACELET);});}), + Entrance(RR_DODONGOS_CAVERN_STAIRS_LOWER, []{return HasAccessTo(RR_DODONGOS_CAVERN_LOBBY_SWITCH);}), + Entrance(RR_DODONGOS_CAVERN_FAR_BRIDGE, []{return HasAccessTo(RR_DODONGOS_CAVERN_FAR_BRIDGE);}), + Entrance(RR_DODONGOS_CAVERN_BOSS_AREA, []{return Here(RR_DODONGOS_CAVERN_FAR_BRIDGE, []{return logic->HasExplosives();});}), + Entrance(RR_DODONGOS_CAVERN_BOSS_ENTRYWAY, []{return false;}), + }); + + areaTable[RR_DODONGOS_CAVERN_LOBBY_SWITCH] = Region("Dodongos Cavern Lobby Switch", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_DODONGOS_CAVERN_LOBBY, []{return true;}), + Entrance(RR_DODONGOS_CAVERN_DODONGO_ROOM, []{return true;}), + }); + + areaTable[RR_DODONGOS_CAVERN_SE_CORRIDOR] = Region("Dodongos Cavern SE Corridor", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_GS_SCARECROW, logic->CanUse(RG_SCARECROW) || (logic->IsAdult && logic->CanUse(RG_LONGSHOT)) || (ctx->GetTrickOption(RT_DC_SCARECROW_GS) && (logic->CanAttack()))), + LOCATION(RC_DODONGOS_CAVERN_SIDE_ROOM_POT_1, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_SIDE_ROOM_POT_2, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_SIDE_ROOM_POT_3, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_SIDE_ROOM_POT_4, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_SIDE_ROOM_POT_5, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_SIDE_ROOM_POT_6, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_LOBBY, []{return true;}), + //Shield seems to be in logic to drop a pot on thier head as they hit you to blow up the wall + Entrance(RR_DODONGOS_CAVERN_SE_ROOM, []{return Here(RR_DODONGOS_CAVERN_SE_CORRIDOR, []{return logic->BlastOrSmash() || logic->CanAttack() || (logic->TakeDamage() && logic->CanShield());});}), + Entrance(RR_DODONGOS_CAVERN_NEAR_LOWER_LIZALFOS, []{return true;}), + }); + + areaTable[RR_DODONGOS_CAVERN_SE_ROOM] = Region("Dodongos Cavern SE Room", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_GS_SIDE_ROOM_NEAR_LOWER_LIZALFOS, logic->CanAttack()), + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_SE_CORRIDOR, []{return true;}), + }); + + areaTable[RR_DODONGOS_CAVERN_NEAR_LOWER_LIZALFOS] = Region("Dodongos Cavern Near Lower Lizalfos", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_DODONGOS_CAVERN_SE_CORRIDOR, []{return true;}), + Entrance(RR_DODONGOS_CAVERN_LOWER_LIZALFOS, []{return true;}), + }); + + areaTable[RR_DODONGOS_CAVERN_LOWER_LIZALFOS] = Region("Dodongos Cavern Lower Lizalfos", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_LIZALFOS_POT_1, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_LIZALFOS_POT_2, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_LIZALFOS_POT_3, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_LIZALFOS_POT_4, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_LOWER_LIZALFOS_HEART, true), + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_NEAR_LOWER_LIZALFOS, []{return Here(RR_DODONGOS_CAVERN_LOWER_LIZALFOS, []{return logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_STICKS) || logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MEGATON_HAMMER) || logic->HasExplosives();});}), + Entrance(RR_DODONGOS_CAVERN_DODONGO_ROOM, []{return Here(RR_DODONGOS_CAVERN_LOWER_LIZALFOS, []{return logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_STICKS) || logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MEGATON_HAMMER) || logic->HasExplosives();});}), + }); + + areaTable[RR_DODONGOS_CAVERN_DODONGO_ROOM] = Region("Dodongos Cavern Dodongo Room", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_TORCH_ROOM_POT_1, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_TORCH_ROOM_POT_2, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_TORCH_ROOM_POT_3, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_TORCH_ROOM_POT_4, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_LOBBY_SWITCH, []{return logic->HasFireSourceWithTorch();}), + Entrance(RR_DODONGOS_CAVERN_LOWER_LIZALFOS, []{return true;}), + Entrance(RR_DODONGOS_CAVERN_NEAR_DODONGO_ROOM, []{return Here(RR_DODONGOS_CAVERN_DODONGO_ROOM, []{return logic->BlastOrSmash() || logic->HasItem(RG_GORONS_BRACELET);});}), + }); + + areaTable[RR_DODONGOS_CAVERN_NEAR_DODONGO_ROOM] = Region("Dodongos Cavern Near Dodongo Room", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_DEKU_SCRUB_SIDE_ROOM_NEAR_DODONGOS, logic->CanStunDeku()), + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_DODONGO_ROOM, []{return true;}), + }); + + areaTable[RR_DODONGOS_CAVERN_STAIRS_LOWER] = Region("Dodongos Cavern Stairs Lower", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_DODONGOS_CAVERN_LOBBY, []{return true;}), + Entrance(RR_DODONGOS_CAVERN_STAIRS_UPPER, []{return logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET) || logic->CanUse(RG_DINS_FIRE) || (ctx->GetTrickOption(RT_DC_STAIRCASE) && logic->CanUse(RG_FAIRY_BOW));}), + Entrance(RR_DODONGOS_CAVERN_COMPASS_ROOM, []{return Here(RR_DODONGOS_CAVERN_STAIRS_LOWER, []{return logic->BlastOrSmash() || logic->HasItem(RG_GORONS_BRACELET);});}), + }); + + areaTable[RR_DODONGOS_CAVERN_STAIRS_UPPER] = Region("Dodongos Cavern Stairs Upper", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_GS_ALCOVE_ABOVE_STAIRS, Here(RR_DODONGOS_CAVERN_FAR_BRIDGE, []{return logic->HookshotOrBoomerang();}) || logic->CanUse(RG_LONGSHOT)), + LOCATION(RC_DODONGOS_CAVERN_GS_VINES_ABOVE_STAIRS, logic->IsAdult || logic->CanAttack() || (HasAccessTo(RR_DODONGOS_CAVERN_STAIRS_LOWER) && logic->CanUse(RG_LONGSHOT) && ctx->GetTrickOption(RT_DC_VINES_GS))), + LOCATION(RC_DODONGOS_CAVERN_STAIRCASE_POT_1, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_STAIRCASE_POT_2, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_STAIRCASE_POT_3, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_STAIRCASE_POT_4, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_STAIRS_LOWER, []{return true;}), + Entrance(RR_DODONGOS_CAVERN_ARMOS_ROOM, []{return true;}), + }); + + areaTable[RR_DODONGOS_CAVERN_COMPASS_ROOM] = Region("Dodongos Cavern Compass Room", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_COMPASS_CHEST, true), + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_STAIRS_LOWER, []{return logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MEGATON_HAMMER) || logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET);}), + }); + + areaTable[RR_DODONGOS_CAVERN_ARMOS_ROOM] = Region("Dodongos Cavern Armos Room", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_DODONGOS_CAVERN_STAIRS_UPPER, []{return true;}), + Entrance(RR_DODONGOS_CAVERN_BOMB_ROOM_LOWER, []{return true;}), + }); + + areaTable[RR_DODONGOS_CAVERN_BOMB_ROOM_LOWER] = Region("Dodongos Cavern Bomb Room Lower", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_BOMB_FLOWER_PLATFORM_CHEST, true), + LOCATION(RC_DODONGOS_CAVERN_BLADE_ROOM_HEART, true), + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_2F_SIDE_ROOM, []{return Here(RR_DODONGOS_CAVERN_BOMB_ROOM_LOWER, []{return logic->BlastOrSmash() || (ctx->GetTrickOption(RT_DC_SCRUB_ROOM) && logic->HasItem(RG_GORONS_BRACELET));});}), + Entrance(RR_DODONGOS_CAVERN_FIRST_SLINGSHOT_ROOM, []{return Here(RR_DODONGOS_CAVERN_BOMB_ROOM_LOWER, []{return logic->BlastOrSmash() || logic->HasItem(RG_GORONS_BRACELET);});}), + Entrance(RR_DODONGOS_CAVERN_BOMB_ROOM_UPPER, []{return (logic->IsAdult && ctx->GetTrickOption(RT_DC_JUMP)) || logic->CanUse(RG_HOVER_BOOTS) || (logic->IsAdult && logic->CanUse(RG_LONGSHOT)) || (ctx->GetTrickOption(RT_DAMAGE_BOOST_SIMPLE) && logic->HasExplosives() && logic->CanJumpslash());}), + }); + + areaTable[RR_DODONGOS_CAVERN_2F_SIDE_ROOM] = Region("Dodongos Cavern 2F Side Room", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_LEFT, logic->CanStunDeku()), + LOCATION(RC_DODONGOS_CAVERN_DEKU_SCRUB_NEAR_BOMB_BAG_RIGHT, logic->CanStunDeku()), + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_BOMB_ROOM_LOWER, []{return true;}), + }); + + areaTable[RR_DODONGOS_CAVERN_FIRST_SLINGSHOT_ROOM] = Region("Dodongos Cavern First Slingshot Room", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_SINGLE_EYE_POT_1, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_SINGLE_EYE_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_BOMB_ROOM_LOWER, []{return true;}), + Entrance(RR_DODONGOS_CAVERN_UPPER_LIZALFOS, []{return logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_FAIRY_BOW) || ctx->GetTrickOption(RT_DC_SLINGSHOT_SKIP);}), + }); + + areaTable[RR_DODONGOS_CAVERN_UPPER_LIZALFOS] = Region("Dodongos Cavern Upper Lizalfos", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_LOWER_LIZALFOS_HEART, true), + LOCATION(RC_DODONGOS_CAVERN_UPPER_LIZALFOS_LEFT_HEART, true), + LOCATION(RC_DODONGOS_CAVERN_UPPER_LIZALFOS_RIGHT_HEART, true), + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_LOWER_LIZALFOS, []{return true;}), + Entrance(RR_DODONGOS_CAVERN_FIRST_SLINGSHOT_ROOM, []{return Here(RR_DODONGOS_CAVERN_LOWER_LIZALFOS, []{return logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_STICKS) || logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MEGATON_HAMMER) || logic->HasExplosives();});}), + Entrance(RR_DODONGOS_CAVERN_SECOND_SLINGSHOT_ROOM, []{return Here(RR_DODONGOS_CAVERN_LOWER_LIZALFOS, []{return logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_STICKS) || logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MEGATON_HAMMER) || logic->HasExplosives();});}), + }); + + areaTable[RR_DODONGOS_CAVERN_SECOND_SLINGSHOT_ROOM] = Region("Dodongos Cavern Second Slingshot Room", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Location + LOCATION(RC_DODONGOS_CAVERN_DOUBLE_EYE_POT_1, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_DOUBLE_EYE_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_UPPER_LIZALFOS, []{return true;}), + Entrance(RR_DODONGOS_CAVERN_BOMB_ROOM_UPPER, []{return logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_FAIRY_BOW) || ctx->GetTrickOption(RT_DC_SLINGSHOT_SKIP);}), + }); + + areaTable[RR_DODONGOS_CAVERN_BOMB_ROOM_UPPER] = Region("Dodongos Cavern Bomb Room Upper", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_BOMB_BAG_CHEST, true), + LOCATION(RC_DODONGOS_CAVERN_BLADE_POT_1, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_BLADE_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_BOMB_ROOM_LOWER, []{return true;}), + Entrance(RR_DODONGOS_CAVERN_SECOND_SLINGSHOT_ROOM, []{return true;}), + Entrance(RR_DODONGOS_CAVERN_FAR_BRIDGE, []{return true;}), + }); + + areaTable[RR_DODONGOS_CAVERN_FAR_BRIDGE] = Region("Dodongos Cavern Far Bridge", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_END_OF_BRIDGE_CHEST, Here(RR_DODONGOS_CAVERN_FAR_BRIDGE, []{return logic->BlastOrSmash();})), + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_LOBBY, []{return true;}), + Entrance(RR_DODONGOS_CAVERN_BOMB_ROOM_UPPER, []{return true;}), + }); + + areaTable[RR_DODONGOS_CAVERN_BOSS_AREA] = Region("Dodongos Cavern Boss Region", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->FairyPot, []{return true;}), + }, {}, { + //Exits + Entrance(RR_DODONGOS_CAVERN_LOBBY, []{return true;}), + Entrance(RR_DODONGOS_CAVERN_BACK_ROOM, []{return Here(RR_DODONGOS_CAVERN_BOSS_AREA, []{return logic->BlastOrSmash();});}), + Entrance(RR_DODONGOS_CAVERN_BOSS_ENTRYWAY, []{return true;}), + }); + + areaTable[RR_DODONGOS_CAVERN_BACK_ROOM] = Region("Dodongos Cavern Back Room", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_GS_BACK_ROOM, logic->CanAttack()), + LOCATION(RC_DODONGOS_CAVERN_BACK_ROOM_POT_1, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_BACK_ROOM_POT_2, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_BACK_ROOM_POT_3, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_BACK_ROOM_POT_4, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_BOSS_AREA, []{return true;}), + }); + +#pragma endregion + +#pragma region MQ + + areaTable[RR_DODONGOS_CAVERN_MQ_BEGINNING] = Region("Dodongos Cavern MQ Beginning", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_DODONGOS_CAVERN_ENTRYWAY, []{return true;}), + Entrance(RR_DODONGOS_CAVERN_MQ_LOBBY, []{return Here(RR_DODONGOS_CAVERN_MQ_BEGINNING, []{return logic->BlastOrSmash() || logic->HasItem(RG_GORONS_BRACELET);});}), + }); + + areaTable[RR_DODONGOS_CAVERN_MQ_LOBBY] = Region("Dodongos Cavern MQ Lobby", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_MQ_MAP_CHEST, logic->CanBreakMudWalls() || logic->HasItem(RG_GORONS_BRACELET)), + LOCATION(RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_REAR, logic->CanStunDeku()), + LOCATION(RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_LOBBY_FRONT, logic->CanStunDeku()), + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_MQ_GOSSIP_STONE, []{return Here(RR_DODONGOS_CAVERN_MQ_LOBBY, []{return logic->CanBreakMudWalls() || logic->HasItem(RG_GORONS_BRACELET);});}), + Entrance(RR_DODONGOS_CAVERN_MQ_MOUTH_SIDE_BRIDGE, []{return Here(RR_DODONGOS_CAVERN_MQ_LOBBY, []{return logic->BlastOrSmash() || logic->HasItem(RG_GORONS_BRACELET);});}), + Entrance(RR_DODONGOS_CAVERN_MQ_STAIRS_LOWER, []{return Here(RR_DODONGOS_CAVERN_MQ_LOBBY, []{return logic->BlastOrSmash() || logic->HasItem(RG_GORONS_BRACELET);});}), + Entrance(RR_DODONGOS_CAVERN_MQ_LOWER_RIGHT_SIDE, []{return Here(RR_DODONGOS_CAVERN_MQ_LOBBY, []{return logic->CanBreakMudWalls();}) || Here(RR_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_UPPER, []{return logic->HasItem(RG_GORONS_BRACELET) && logic->TakeDamage();});}), //strength 1 and bunny speed works too + Entrance(RR_DODONGOS_CAVERN_MQ_POES_ROOM, []{return logic->IsAdult;}), + Entrance(RR_DODONGOS_CAVERN_MQ_BEHIND_MOUTH, []{return Here(RR_DODONGOS_CAVERN_MQ_MOUTH_SIDE_BRIDGE, []{return logic->HasExplosives() || (logic->ClearMQDCUpperLobbyRocks && logic->HasItem(RG_GORONS_BRACELET) && ((logic->IsAdult && ctx->GetTrickOption(RT_DC_MQ_ADULT_EYES)) || (logic->IsChild && ctx->GetTrickOption(RT_DC_MQ_CHILD_EYES))));});}), + }); + + areaTable[RR_DODONGOS_CAVERN_MQ_GOSSIP_STONE] = Region("Dodongos Cavern MQ Gossip Stone", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->GossipStoneFairy, []{return logic->CallGossipFairy();}), + }, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_GOSSIP_STONE, true), + LOCATION(RC_DODONGOS_CAVERN_MQ_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), + LOCATION(RC_DODONGOS_CAVERN_MQ_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_MQ_LOBBY, []{return true;}), + }); + + areaTable[RR_DODONGOS_CAVERN_MQ_MOUTH_SIDE_BRIDGE] = Region("Dodongos Cavern MQ Mouth Side Bridge", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->ClearMQDCUpperLobbyRocks, []{return logic->BlastOrSmash() || logic->CanUse(RG_DINS_FIRE);}), + }, {}, { + //Exits + Entrance(RR_DODONGOS_CAVERN_MQ_LOBBY, []{return true;}), + Entrance(RR_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_UPPER, []{return logic->ClearMQDCUpperLobbyRocks;}), + //Bunny hood jump + jumpslash can also make it directly from the raising platform + Entrance(RR_DODONGOS_CAVERN_MQ_POES_ROOM, []{return logic->CanUse(RG_HOVER_BOOTS) || (ctx->GetTrickOption(RT_DC_MQ_CHILD_BOMBS) && logic->CanJumpslashExceptHammer() && logic->TakeDamage());}), //RANDOTODO is this possible with equip swapped hammer? + //it is possible to use bunny hood speed, hovers and a jumpslash to go between here and the other bridge (included with TORCH_ROOM_LOWER), but this would be a trick + }); + + areaTable[RR_DODONGOS_CAVERN_MQ_STAIRS_LOWER] = Region("Dodongos Cavern MQ Stairs Lower", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, { + //Events + //EventAccess(&logic->CanClimbDCStairs, []{return logic->HasExplosives || logic->CanUse(RG_DINS_FIRE) || (ctx->GetTrickOption(RT_DC_STAIRCASE) && logic->CanUse(RG_FAIRY_BOW));}), + }, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_MQ_STAIRCASE_POT_1, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_MQ_STAIRCASE_POT_2, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_MQ_STAIRCASE_POT_3, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_MQ_STAIRCASE_POT_4, logic->CanBreakPots()), + }, { + //Exits + //This is possible with sticks and shield, igniting a first flower by "touch" then very quickly crouch stabbing in a way that cuts the corner to light the 3rd bomb on the other side, but that's a trick + Entrance(RR_DODONGOS_CAVERN_MQ_STAIRS_UPPER, []{return Here(RR_DODONGOS_CAVERN_MQ_STAIRS_LOWER, []{return logic->HasExplosives() || logic->CanUse(RG_DINS_FIRE) || (ctx->GetTrickOption(RT_DC_STAIRCASE) && logic->CanUse(RG_FAIRY_BOW));});}), + Entrance(RR_DODONGOS_CAVERN_MQ_STAIRS_PAST_MUD_WALL, []{return Here(RR_DODONGOS_CAVERN_MQ_STAIRS_LOWER, []{return logic->CanBreakMudWalls();});}), + }); + + areaTable[RR_DODONGOS_CAVERN_MQ_STAIRS_PAST_MUD_WALL] = Region("Dodongos Cavern MQ Stairs Past Mud Wall", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->DekuBabaSticks, []{return logic->CanGetDekuBabaSticks();}), + //EventAccess(&logic->CanClimbDCStairs, []{return logic->HasItem(RG_GORONS_BRACELET) && (logic->CanUse(RG_STICKS));}), + }, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_MQ_GS_SONG_OF_TIME_BLOCK_ROOM, logic->CanUse(RG_SONG_OF_TIME) && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)), + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_MQ_STAIRS_UPPER, []{return logic->HasItem(RG_GORONS_BRACELET) && (logic->CanUse(RG_STICKS));}), + Entrance(RR_DODONGOS_CAVERN_MQ_STAIRS_LOWER, []{return true;}), + }); + + areaTable[RR_DODONGOS_CAVERN_MQ_STAIRS_UPPER] = Region("Dodongos Cavern MQ Stairs Upper", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_STAIRCASE, logic->CanStunDeku()), + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_MQ_STAIRS_LOWER, []{return true;}), + Entrance(RR_DODONGOS_CAVERN_MQ_STAIRS_PAST_BIG_SKULLTULAS, []{return logic->CanPassEnemy(RE_BIG_SKULLTULA) || logic->CanUse(RG_HOVER_BOOTS);}), + }); + + areaTable[RR_DODONGOS_CAVERN_MQ_STAIRS_PAST_BIG_SKULLTULAS] = Region("Dodongos Cavern MQ Past Big Skulltulas", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_DODONGOS_CAVERN_MQ_STAIRS_UPPER, []{return logic->CanPassEnemy(RE_BIG_SKULLTULA) || logic->CanUse(RG_HOVER_BOOTS);}), + Entrance(RR_DODONGOS_CAVERN_MQ_STAIRS_LOWER, []{return logic->TakeDamage();}), + //If some case comes up where you can directly (void?)warp here without going through Dodongo room or climbing up from below, + //the commented out logic is to handle going down and reclimbing to get silver rupees. A new eventVar will need decalring to handle this. + /*(logic->CanPassEnemy(RE_BIG_SKULLTULA) || CanUse(RG_HOVER_BOOTS)) && logic->CanClimbDCStairs;*/ + Entrance(RR_DODONGOS_CAVERN_MQ_DODONGO_ROOM, []{return true;}),//if we add BONKO or other crate logic, logic for silver rupees goes here + }); + + areaTable[RR_DODONGOS_CAVERN_MQ_DODONGO_ROOM] = Region("Dodongos Cavern MQ Dodongo Room", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_MQ_COMPASS_CHEST, logic->CanKillEnemy(RE_DODONGO) || logic->HasItem(RG_GORONS_BRACELET)), + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_MQ_STAIRS_PAST_BIG_SKULLTULAS, []{return true;}), + Entrance(RR_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_LOWER, []{return Here(RR_DODONGOS_CAVERN_MQ_DODONGO_ROOM, []{return logic->CanKillEnemy(RE_DODONGO) || logic->HasItem(RG_GORONS_BRACELET);});}), + }); + + areaTable[RR_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_LOWER] = Region("Dodongos Cavern MQ Torch Puzzle Lower", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->ClearMQDCUpperLobbyRocks, []{return (((logic->IsAdult /*or bunny hood jump*/) && ctx->GetTrickOption(RT_DC_JUMP)) || logic->CanUse(RG_HOVER_BOOTS)) && logic->CanUse(RG_STICKS);}), + }, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_MIDDLE_POT, logic->CanUse(RG_BOOMERANG)), + LOCATION(RC_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_ROOM_HEART, true), + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_MQ_LOBBY, []{return logic->TakeDamage();}), + Entrance(RR_DODONGOS_CAVERN_MQ_DODONGO_ROOM, []{return true;}), + Entrance(RR_DODONGOS_CAVERN_MQ_LARVAE_ROOM, []{return logic->HasFireSourceWithTorch();}),//torch checks here need strength 0 with sticks when that is implemented + Entrance(RR_DODONGOS_CAVERN_MQ_BIG_BLOCK_ROOM, []{return Here(RR_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_LOWER, []{return logic->HasFireSourceWithTorch();});}), //Includes an implied CanPass(RE_BIG_SKULLTULA) + Entrance(RR_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_UPPER, []{return ((logic->IsAdult /*or bunny hood jump*/) && ctx->GetTrickOption(RT_DC_JUMP)) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT);}), + Entrance(RR_DODONGOS_CAVERN_MQ_UPPER_LIZALFOS, []{return logic->CanUse(RG_STICKS) && logic->HasItem(RG_GORONS_BRACELET);}), //Implies access to RR_DODONGOS_CAVERN_MQ_BIG_BLOCK_ROOM from here + }); + + areaTable[RR_DODONGOS_CAVERN_MQ_BIG_BLOCK_ROOM] = Region("Dodongos Cavern MQ Torch Puzzle Lower", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_MQ_BIG_BLOCK_POT_1, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_MQ_BIG_BLOCK_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_LOWER, []{return logic->CanPassEnemy(RE_BIG_SKULLTULA);}), + Entrance(RR_DODONGOS_CAVERN_MQ_UPPER_LIZALFOS, []{return (logic->HasFireSource() && logic->HasItem(RG_GORONS_BRACELET)) || logic->CanBreakMudWalls();}), //Requires stregnth 0, If you can somehow warp into this room, add logic->CanPassEnemy(RE_BIG_SKULLTULA) + }); + + areaTable[RR_DODONGOS_CAVERN_MQ_LARVAE_ROOM] = Region("Dodongos Cavern MQ Larvae Room", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_MQ_LARVAE_ROOM_CHEST, true), //implied logic->CanKillEnemy(RE_GOHMA_LARVA) based on entry reqs with a trick to kill with nuts + LOCATION(RC_DODONGOS_CAVERN_MQ_GS_LARVAE_ROOM, true), //implied logic->CanKillEnemy(RE_GOLD_SKULTULLA) based on entry reqs. Add crate logic when BONKO is added + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_LOWER, []{return true;}), //implied logic->CanKillEnemy(RE_GOHMA_LARVA) based on entry reqs with a trick to kill with nuts + }); + + areaTable[RR_DODONGOS_CAVERN_MQ_UPPER_LIZALFOS] = Region("Dodongos Cavern MQ Before Upper Lizalfos", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_MQ_GS_LIZALFOS_ROOM, logic->BlastOrSmash()), //Implied CanGetEnemyDrop(RE_GOLD_SKULLTULA) + LOCATION(RC_DODONGOS_CAVERN_MQ_UPPER_LIZALFOS_POT_1, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_MQ_UPPER_LIZALFOS_POT_2, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_MQ_UPPER_LIZALFOS_POT_3, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_MQ_UPPER_LIZALFOS_POT_4, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_MQ_LIZALFOS_ROOM_HEART, logic->BlastOrSmash()), + }, { + //Exits + //Falling down gets you stuck with nothing there, not a useful exit for logic + Entrance(RR_DODONGOS_CAVERN_MQ_BIG_BLOCK_ROOM, []{return Here(RR_DODONGOS_CAVERN_MQ_UPPER_LIZALFOS, []{return logic->CanKillEnemy(RE_LIZALFOS);});}), + Entrance(RR_DODONGOS_CAVERN_MQ_TWO_FIRES_ROOM, []{return Here(RR_DODONGOS_CAVERN_MQ_UPPER_LIZALFOS, []{return logic->CanKillEnemy(RE_LIZALFOS);});}), + }); + + areaTable[RR_DODONGOS_CAVERN_MQ_TWO_FIRES_ROOM] = Region("Dodongos Cavern MQ Before Upper Lizalfos", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_MQ_TWO_FLAMES_POT_1, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_MQ_TWO_FLAMES_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_MQ_UPPER_LIZALFOS, []{return true;}), + Entrance(RR_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_UPPER, []{return logic->IsAdult || (Here(RR_DODONGOS_CAVERN_MQ_TWO_FIRES_ROOM, []{return logic->BlastOrSmash() || (logic->CanAttack() && logic->HasItem(RG_GORONS_BRACELET));}));}), + }); + + areaTable[RR_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_UPPER] = Region("Dodongos Cavern MQ Torch Puzzle Upper", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->ClearMQDCUpperLobbyRocks, []{return logic->CanDetonateUprightBombFlower() || logic->CanUse(RG_MEGATON_HAMMER);}), + }, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_ROOM_CHEST, true), + LOCATION(RC_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_CORNER_POT, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_MIDDLE_POT, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_MQ_MOUTH_SIDE_BRIDGE, []{return logic->ClearMQDCUpperLobbyRocks;}), + Entrance(RR_DODONGOS_CAVERN_MQ_TORCH_PUZZLE_LOWER, []{return true;}), + Entrance(RR_DODONGOS_CAVERN_MQ_TWO_FIRES_ROOM, []{return true;}), + }); + + areaTable[RR_DODONGOS_CAVERN_MQ_LOWER_RIGHT_SIDE] = Region("Dodongos Cavern MQ Lower Right Side", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_MQ_DEKU_SCRUB_SIDE_ROOM_NEAR_LOWER_LIZALFOS, (logic->CanBreakMudWalls() || logic->HasItem(RG_GORONS_BRACELET)) && logic->CanStunDeku()), + LOCATION(RC_DODONGOS_CAVERN_MQ_RIGHT_SIDE_POT_1, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_MQ_RIGHT_SIDE_POT_2, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_MQ_RIGHT_SIDE_POT_3, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_MQ_RIGHT_SIDE_POT_4, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_MQ_LOBBY, []{return true;}), + Entrance(RR_DODONGOS_CAVERN_MQ_LOWER_LIZALFOS, []{return Here(RR_DODONGOS_CAVERN_MQ_LOWER_RIGHT_SIDE, []{return logic->CanDetonateBombFlowers() || logic->HasItem(RG_GORONS_BRACELET);}) && logic->CanHitEyeTargets();}), + }); + + areaTable[RR_DODONGOS_CAVERN_MQ_LOWER_LIZALFOS] = Region("Dodongos Cavern MQ Lower Lizalfos", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_MQ_LIZALFOS_ROOM_HEART, true), + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_MQ_LOWER_RIGHT_SIDE, []{return Here(RR_DODONGOS_CAVERN_MQ_LOWER_LIZALFOS, []{return logic->CanKillEnemy(RE_LIZALFOS);});}), + Entrance(RR_DODONGOS_CAVERN_MQ_POES_ROOM, []{return Here(RR_DODONGOS_CAVERN_MQ_LOWER_LIZALFOS, []{return logic->CanKillEnemy(RE_LIZALFOS);});}), + }); + + areaTable[RR_DODONGOS_CAVERN_MQ_POES_ROOM] = Region("Dodongos Cavern MQ Poes Room", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_MQ_BOMB_BAG_CHEST, true), //If you can get to the locked part of POES_ROOM without a way to open it or passing the chest, this will need it's own room + LOCATION(RC_DODONGOS_CAVERN_MQ_GS_SCRUB_ROOM, (Here(RR_DODONGOS_CAVERN_MQ_POES_ROOM, []{return logic->CanDetonateBombFlowers() || logic->HasItem(RG_GORONS_BRACELET);}) && //could be a seperate room if it gets busy + logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG, true))), //Implies you can avoid/kill the enemies with what you use on the skull, if this assumption is broken, add + //&& (Here(RR_DODONGOS_CAVERN_MQ_POES_ROOM, []{return logic->CanKillEnemy(RE_FIRE_KEESE) && logic->CanKillEnemy(RE_MAD_SCRUB);}) || (logic->CanAvoidEnemy(RE_FIRE_KEESE) && logic->CanAvoidEnemy(RE_MAD_SCRUB))) + LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_POT_1, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_POT_2, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_POT_3, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_MQ_POE_ROOM_POT_4, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_MQ_LOWER_RIGHT_SIDE, []{return Here(RR_DODONGOS_CAVERN_MQ_POES_ROOM, []{return logic->CanDetonateBombFlowers() || logic->HasItem(RG_GORONS_BRACELET);});}), + Entrance(RR_DODONGOS_CAVERN_MQ_LOWER_LIZALFOS, []{return true;}), + Entrance(RR_DODONGOS_CAVERN_MQ_MAD_SCRUB_ROOM, []{return Here(RR_DODONGOS_CAVERN_MQ_POES_ROOM, []{return logic->CanDetonateBombFlowers() || logic->HasItem(RG_GORONS_BRACELET);});}), + }); + + areaTable[RR_DODONGOS_CAVERN_MQ_MAD_SCRUB_ROOM] = Region("Dodongos Cavern Mad Scrub Room", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_MQ_GS_SCRUB_ROOM, (logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG, true))), //Implies you can avoid/kill the enemies with what you use on the skull, if this assumption is broken, add + //&& (Here(RR_DODONGOS_CAVERN_MQ_POES_ROOM, []{return logic->CanKillEnemy(RE_FIRE_KEESE) && logic->CanKillEnemy(RE_MAD_SCRUB);}) || (logic->CanAvoidEnemy(RE_FIRE_KEESE) && logic->CanAvoidEnemy(RE_MAD_SCRUB))) + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_MQ_POES_ROOM, []{return Here(RR_DODONGOS_CAVERN_MQ_MAD_SCRUB_ROOM, []{return logic->CanKillEnemy(RE_FIRE_KEESE) && logic->CanKillEnemy(RE_MAD_SCRUB);});}), + }); + + areaTable[RR_DODONGOS_CAVERN_MQ_BEHIND_MOUTH] = Region("Dodongos Cavern MQ Behind Mouth", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_MQ_BEFORE_BOSS_SW_POT, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_MQ_BEFORE_BOSS_NE_POT, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_MQ_ARMOS_ROOM_SE_POT, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_MQ_ARMOS_ROOM_SW_POT, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_MQ_LOBBY, []{return true;}), + //using pots to get past the fire is in default logic. if stregnth 0 gets added, this will need to be: + //stregnth 0 || explosives, or projectiles if str0 isn't needed to pull graves (it's a narrow shot though, may be trick worthy) + Entrance(RR_DODONGOS_CAVERN_MQ_BACK_BEHIND_FIRE, []{return true;}), + Entrance(RR_DODONGOS_CAVERN_MQ_BACK_SWITCH_GRAVE, []{return logic->IsAdult;}), + }); + + areaTable[RR_DODONGOS_CAVERN_MQ_BACK_BEHIND_FIRE] = Region("Dodongos Cavern MQ Back Behind Fire", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_MQ_UNDER_GRAVE_CHEST, true), //pulling the grave isn't required, as you can open the chest through it + LOCATION(RC_DODONGOS_CAVERN_MQ_BACKROOM_POT_1, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_MQ_BACKROOM_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_MQ_BEHIND_MOUTH, []{return logic->CanAttack();}), + //There's a trick N64 rolls into the child eyes trick for using armos blow up the bomb flowers when dieing, which would be killing an armos + Entrance(RR_DODONGOS_CAVERN_MQ_BACK_SWITCH_GRAVE, []{return Here(RR_DODONGOS_CAVERN_MQ_BACK_BEHIND_FIRE, []{return logic->CanDetonateBombFlowers();}) || Here(RR_DODONGOS_CAVERN_MQ_BACK_SWITCH_GRAVE, []{return logic->CanAttack();});}), + }); + + areaTable[RR_DODONGOS_CAVERN_MQ_BACK_SWITCH_GRAVE] = Region("Dodongos Cavern MQ BossArea", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->FairyPot, []{return true;}), + }, { + //Locations + LOCATION(RC_DODONGOS_CAVERN_MQ_GS_BACK_AREA, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA) || logic->HasItem(RG_GORONS_BRACELET) || //even if you somehow warp to BACK_BEHIND_FIRE, if you can kill the skull at range, you can get to BEHIND_MOUTH + Here(RR_DODONGOS_CAVERN_MQ_BEHIND_MOUTH, []{return (logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS) /* || bunny jumps*/);})), + LOCATION(RC_DODONGOS_CAVERN_MQ_ARMOS_ROOM_NW_POT, logic->CanBreakPots()), + LOCATION(RC_DODONGOS_CAVERN_MQ_ARMOS_ROOM_NE_POT, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_DODONGOS_CAVERN_MQ_BACK_BEHIND_FIRE, []{return true;}), + Entrance(RR_DODONGOS_CAVERN_BOSS_ENTRYWAY, []{return true;}), //if strength 0 prevents grave pulls, add it here + }); + +#pragma endregion + + // Boss Room + areaTable[RR_DODONGOS_CAVERN_BOSS_ENTRYWAY] = Region("Dodongos Cavern Boss Entryway", "Dodongos Cavern", {RA_DODONGOS_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, {}, { + // Exits + Entrance(RR_DODONGOS_CAVERN_BOSS_AREA, []{return ctx->GetDungeon(DODONGOS_CAVERN)->IsVanilla();}), + Entrance(RR_DODONGOS_CAVERN_MQ_BEHIND_MOUTH, []{return ctx->GetDungeon(DODONGOS_CAVERN)->IsMQ();}), + Entrance(RR_DODONGOS_CAVERN_BOSS_ROOM, []{return true;}), + }); + + areaTable[RR_DODONGOS_CAVERN_BOSS_ROOM] = Region("Dodongos Cavern Boss Room", "Dodongos Cavern", {}, NO_DAY_NIGHT_CYCLE, { + // Events + EventAccess(&logic->DodongosCavernClear, []{return logic->DodongosCavernClear || (logic->HasBossSoul(RG_KING_DODONGO_SOUL) && (Here(RR_DODONGOS_CAVERN_BOSS_ROOM, []{return logic->HasExplosives() || (logic->CanUse(RG_MEGATON_HAMMER) && ctx->GetTrickOption(RT_DC_HAMMER_FLOOR));}) && (logic->CanUse(RG_BOMB_BAG) || logic->HasItem(RG_GORONS_BRACELET)) && logic->CanJumpslashExceptHammer())); /*todo add chu kill to tricks*/}), + }, { + // Locations + LOCATION(RC_DODONGOS_CAVERN_BOSS_ROOM_CHEST, true), + LOCATION(RC_DODONGOS_CAVERN_KING_DODONGO_HEART, logic->DodongosCavernClear), + LOCATION(RC_KING_DODONGO, logic->DodongosCavernClear), + }, { + // Exits + Entrance(RR_DODONGOS_CAVERN_BOSS_ENTRYWAY, []{return true;}), + Entrance(RR_DEATH_MOUNTAIN_TRAIL, []{return logic->DodongosCavernClear;}, false), + }); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/fire_temple.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/fire_temple.cpp new file mode 100644 index 000000000..4abfa9c23 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/fire_temple.cpp @@ -0,0 +1,718 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" +#include "soh/Enhancements/randomizer/dungeon.h" + +using namespace Rando; + +void RegionTable_Init_FireTemple() { + // Vanilla/MQ Decider + areaTable[RR_FIRE_TEMPLE_ENTRYWAY] = Region("Fire Temple Entryway", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_FIRE_TEMPLE_FIRST_ROOM, []{return ctx->GetDungeon(FIRE_TEMPLE)->IsVanilla();}), + Entrance(RR_FIRE_TEMPLE_MQ_FIRST_ROOM_LOWER, []{return ctx->GetDungeon(FIRE_TEMPLE)->IsMQ();}), + Entrance(RR_DMC_CENTRAL_LOCAL, []{return true;}), + }); + +#pragma region Vanilla + + areaTable[RR_FIRE_TEMPLE_FIRST_ROOM] = Region("Fire Temple First Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_FIRE_TEMPLE_ENTRYWAY, []{return true;}), + Entrance(RR_FIRE_TEMPLE_NEAR_BOSS_ROOM, []{return logic->FireTimer() >= 24;}), + Entrance(RR_FIRE_TEMPLE_LOOP_ENEMIES, []{return Here(RR_FIRE_TEMPLE_FIRST_ROOM, []{return logic->CanUse(RG_MEGATON_HAMMER);}) && (logic->SmallKeys(RR_FIRE_TEMPLE, 8) || !logic->IsKeysanity);}), + Entrance(RR_FIRE_TEMPLE_LOOP_EXIT, []{return true;}), + Entrance(RR_FIRE_TEMPLE_BIG_LAVA_ROOM, []{return logic->SmallKeys(RR_FIRE_TEMPLE, 2) && logic->FireTimer() >= 24;}), + }); + + areaTable[RR_FIRE_TEMPLE_NEAR_BOSS_ROOM] = Region("Fire Temple Near Boss Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->FairyPot, []{return logic->FairyPot || (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT));}), + }, { + //Locations + LOCATION(RC_FIRE_TEMPLE_NEAR_BOSS_CHEST, true), + LOCATION(RC_FIRE_TEMPLE_NEAR_BOSS_POT_1, (logic->CanBreakPots() && (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT)))), + LOCATION(RC_FIRE_TEMPLE_NEAR_BOSS_POT_2, (logic->CanBreakPots() && (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT)))), + LOCATION(RC_FIRE_TEMPLE_NEAR_BOSS_POT_3, (logic->CanBreakPots() && (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT)))), + LOCATION(RC_FIRE_TEMPLE_NEAR_BOSS_POT_4, (logic->CanBreakPots() && (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT)))), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_FIRST_ROOM, []{return true;}), + Entrance(RR_FIRE_TEMPLE_BOSS_ENTRYWAY, []{return logic->HasItem(RG_FIRE_TEMPLE_BOSS_KEY) && ((logic->IsAdult && (ctx->GetTrickOption(RT_FIRE_BOSS_DOOR_JUMP) || Here(RR_FIRE_TEMPLE_FIRE_MAZE_UPPER, []{return logic->CanUse(RG_MEGATON_HAMMER);}))) || logic->CanUse(RG_HOVER_BOOTS));}), + }); + + areaTable[RR_FIRE_TEMPLE_LOOP_ENEMIES] = Region("Fire Temple Loop Enemies", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_FIRE_TEMPLE_FIRST_ROOM, []{return logic->SmallKeys(RR_FIRE_TEMPLE, 8) || !logic->IsKeysanity;}), + Entrance(RR_FIRE_TEMPLE_LOOP_TILES, []{return Here(RR_FIRE_TEMPLE_LOOP_ENEMIES, []{return logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MEGATON_HAMMER);});}), + }); + + areaTable[RR_FIRE_TEMPLE_LOOP_TILES] = Region("Fire Temple Loop Tiles", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_GS_BOSS_KEY_LOOP, logic->CanAttack()), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_LOOP_ENEMIES, []{return true;}), + Entrance(RR_FIRE_TEMPLE_LOOP_FLARE_DANCER, []{return true;}), + }); + + areaTable[RR_FIRE_TEMPLE_LOOP_FLARE_DANCER] = Region("Fire Temple Loop Flare Dancer", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_FLARE_DANCER_CHEST, (logic->HasExplosives() || logic->CanUse(RG_MEGATON_HAMMER)) && logic->IsAdult), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_LOOP_TILES, []{return true;}), + Entrance(RR_FIRE_TEMPLE_LOOP_HAMMER_SWITCH, []{return Here(RR_FIRE_TEMPLE_LOOP_FLARE_DANCER, []{return logic->CanKillEnemy(RE_FLARE_DANCER);});}), + }); + + areaTable[RR_FIRE_TEMPLE_LOOP_HAMMER_SWITCH] = Region("Fire Temple Loop Hammer Switch", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->FireLoopSwitch, []{return logic->FireLoopSwitch || logic->CanUse(RG_MEGATON_HAMMER);}), + }, {}, { + //Exits + Entrance(RR_FIRE_TEMPLE_LOOP_FLARE_DANCER, []{return true;}), + Entrance(RR_FIRE_TEMPLE_LOOP_GORON_ROOM, []{return logic->FireLoopSwitch;}), + }); + + areaTable[RR_FIRE_TEMPLE_LOOP_GORON_ROOM] = Region("Fire Temple Loop Goron Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_BOSS_KEY_CHEST, true), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_LOOP_HAMMER_SWITCH, []{return logic->FireLoopSwitch;}), + Entrance(RR_FIRE_TEMPLE_LOOP_EXIT, []{return logic->FireLoopSwitch;}), + }); + + areaTable[RR_FIRE_TEMPLE_LOOP_EXIT] = Region("Fire Temple Loop Exit", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_FIRE_TEMPLE_FIRST_ROOM, []{return true;}), + Entrance(RR_FIRE_TEMPLE_LOOP_GORON_ROOM, []{return logic->FireLoopSwitch;}), + }); + + areaTable[RR_FIRE_TEMPLE_BIG_LAVA_ROOM] = Region("Fire Temple Big Lava Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_BIG_LAVA_POT_1, logic->CanBreakPots()), + LOCATION(RC_FIRE_TEMPLE_BIG_LAVA_POT_2, logic->CanBreakPots()), + LOCATION(RC_FIRE_TEMPLE_BIG_LAVA_POT_3, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_FIRST_ROOM, []{return logic->SmallKeys(RR_FIRE_TEMPLE, 2);}), + Entrance(RR_FIRE_TEMPLE_BIG_LAVA_ROOM_NORTH_GORON, []{return true;}), + Entrance(RR_FIRE_TEMPLE_BIG_LAVA_ROOM_NORTH_TILES, []{return logic->IsAdult && (logic->CanUse(RG_SONG_OF_TIME) || ctx->GetTrickOption(RT_FIRE_SOT));}), + Entrance(RR_FIRE_TEMPLE_BIG_LAVA_ROOM_SOUTH_GORON, []{return logic->IsAdult && logic->HasExplosives();}), + Entrance(RR_FIRE_TEMPLE_FIRE_PILLAR_ROOM, []{return logic->SmallKeys(RR_FIRE_TEMPLE, 3);}), + }); + + areaTable[RR_FIRE_TEMPLE_BIG_LAVA_ROOM_NORTH_GORON] = Region("Fire Temple Big Lava Room North Goron", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_BIG_LAVA_ROOM_LOWER_OPEN_DOOR_CHEST, true), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_BIG_LAVA_ROOM, []{return true;}), + }); + + areaTable[RR_FIRE_TEMPLE_BIG_LAVA_ROOM_NORTH_TILES] = Region("Fire Temple Big Lava Room North Tiles", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + //RANDOTODO check if child can reach + LOCATION(RC_FIRE_TEMPLE_GS_SONG_OF_TIME_ROOM, (logic->IsAdult && logic->CanAttack()) || logic->HookshotOrBoomerang()), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_BIG_LAVA_ROOM, []{return true;}), + }); + + areaTable[RR_FIRE_TEMPLE_BIG_LAVA_ROOM_SOUTH_GORON] = Region("Fire Temple Big Lava Room South Goron", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST, true), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_BIG_LAVA_ROOM, []{return true;}), + }); + + areaTable[RR_FIRE_TEMPLE_FIRE_PILLAR_ROOM] = Region("Fire Temple Fire Pillar Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_FIRE_PILLAR_LEFT_HEART, logic->FireTimer() >= 56), + LOCATION(RC_FIRE_TEMPLE_FIRE_PILLAR_RIGHT_HEART, logic->FireTimer() >= 56), + LOCATION(RC_FIRE_TEMPLE_FIRE_PILLAR_BACK_HEART, logic->FireTimer() >= 56), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_BIG_LAVA_ROOM, []{return logic->SmallKeys(RR_FIRE_TEMPLE, 3);}), + Entrance(RR_FIRE_TEMPLE_SHORTCUT_ROOM, []{return logic->FireTimer() >= 56 && logic->SmallKeys(RR_FIRE_TEMPLE, 4);}), + }); + + areaTable[RR_FIRE_TEMPLE_SHORTCUT_ROOM] = Region("Fire Temple Shortcut Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_BOULDER_MAZE_SHORTCUT_CHEST, Here(RR_FIRE_TEMPLE_SHORTCUT_CLIMB, []{return true;})), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_FIRE_PILLAR_ROOM, []{return logic->SmallKeys(RR_FIRE_TEMPLE, 4);}), + Entrance(RR_FIRE_TEMPLE_SHORTCUT_CLIMB, []{return Here(RR_FIRE_TEMPLE_SHORTCUT_CLIMB, []{return true;});}), + Entrance(RR_FIRE_TEMPLE_BOULDER_MAZE_LOWER, []{return logic->IsAdult && (logic->HasItem(RG_GORONS_BRACELET) || ctx->GetTrickOption(RT_FIRE_STRENGTH)) && (logic->HasExplosives() || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_FAIRY_SLINGSHOT));}), + }); + + areaTable[RR_FIRE_TEMPLE_SHORTCUT_CLIMB] = Region("Fire Temple Shortcut Climb", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_FIRE_TEMPLE_SHORTCUT_ROOM, []{return true;}), + Entrance(RR_FIRE_TEMPLE_BOULDER_MAZE_UPPER, []{return true;}), + }); + + areaTable[RR_FIRE_TEMPLE_BOULDER_MAZE_LOWER] = Region("Fire Temple Boulder Maze Lower", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_BOULDER_MAZE_LOWER_CHEST, true), + LOCATION(RC_FIRE_TEMPLE_GS_BOULDER_MAZE, logic->HasExplosives() && (logic->IsAdult || logic->HookshotOrBoomerang())), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_SHORTCUT_ROOM, []{return true;}), + Entrance(RR_FIRE_TEMPLE_BOULDER_MAZE_LOWER_SIDE_ROOM, []{return true;}), + Entrance(RR_FIRE_TEMPLE_EAST_CENTRAL_ROOM, []{return logic->SmallKeys(RR_FIRE_TEMPLE, 5, 7);}), + Entrance(RR_FIRE_TEMPLE_BOULDER_MAZE_UPPER, []{return false;}), + }); + + areaTable[RR_FIRE_TEMPLE_BOULDER_MAZE_LOWER_SIDE_ROOM] = Region("Fire Temple Boulder Maze Lower Side Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_BOULDER_MAZE_SIDE_ROOM_CHEST, true), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_BOULDER_MAZE_LOWER, []{return true;}), + }); + + areaTable[RR_FIRE_TEMPLE_EAST_CENTRAL_ROOM] = Region("Fire Temple East Central Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_EAST_CENTRAL_LEFT_HEART, true), + LOCATION(RC_FIRE_TEMPLE_EAST_CENTRAL_RIGHT_HEART, true), + LOCATION(RC_FIRE_TEMPLE_EAST_CENTRAL_MIDDLE_HEART, true), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_BIG_LAVA_ROOM, []{return logic->TakeDamage();}), + Entrance(RR_FIRE_TEMPLE_BOULDER_MAZE_LOWER, []{return logic->SmallKeys(RR_FIRE_TEMPLE, 5, 8);}), + Entrance(RR_FIRE_TEMPLE_FIRE_WALL_CHASE, []{return logic->SmallKeys(RR_FIRE_TEMPLE, 6, 8);}), + Entrance(RR_FIRE_TEMPLE_MAP_AREA, []{return logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_FAIRY_BOW);}), + }); + + areaTable[RR_FIRE_TEMPLE_FIRE_WALL_CHASE] = Region("Fire Temple Fire Wall Chase", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_FIRE_WALL_EAST_HEART, logic->FireTimer() >= 24 && (logic->IsAdult || logic->CanUse(RG_BOOMERANG))), + LOCATION(RC_FIRE_TEMPLE_FIRE_WALL_WEST_HEART, logic->FireTimer() >= 24 && (logic->IsAdult || logic->CanUse(RG_BOOMERANG))), + LOCATION(RC_FIRE_TEMPLE_FIRE_WALL_EXIT_HEART, logic->FireTimer() >= 24), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_EAST_CENTRAL_ROOM, []{return logic->FireTimer() >= 24 && logic->SmallKeys(RR_FIRE_TEMPLE, 6, 8);}), + Entrance(RR_FIRE_TEMPLE_MAP_AREA, []{return logic->IsAdult;}), + Entrance(RR_FIRE_TEMPLE_BOULDER_MAZE_UPPER, []{return logic->FireTimer() >= 24 && logic->IsAdult;}), + Entrance(RR_FIRE_TEMPLE_CORRIDOR, []{return logic->FireTimer() >= 24 && logic->IsAdult && logic->SmallKeys(RR_FIRE_TEMPLE, 7);}), + }); + + areaTable[RR_FIRE_TEMPLE_MAP_AREA] = Region("Fire Temple Map Region", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_MAP_CHEST, true), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_EAST_CENTRAL_ROOM, []{return true;}), + }); + + areaTable[RR_FIRE_TEMPLE_BOULDER_MAZE_UPPER] = Region("Fire Temple Boulder Maze Upper", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_BOULDER_MAZE_UPPER_CHEST, true), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_SHORTCUT_CLIMB, []{return logic->HasExplosives();}), + Entrance(RR_FIRE_TEMPLE_BOULDER_MAZE_LOWER, []{return true;}), + Entrance(RR_FIRE_TEMPLE_FIRE_WALL_CHASE, []{return true;}), + Entrance(RR_FIRE_TEMPLE_SCARECROW_ROOM, []{return logic->CanUse(RG_SCARECROW) || (ctx->GetTrickOption(RT_FIRE_SCARECROW) && logic->IsAdult && logic->CanUse(RG_LONGSHOT));}), + }); + + areaTable[RR_FIRE_TEMPLE_SCARECROW_ROOM] = Region("Fire Temple Scarecrow Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_GS_SCARECROW_CLIMB, logic->CanJumpslashExceptHammer() || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_BOOMERANG) || logic->HasExplosives() || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_DINS_FIRE)), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_BOULDER_MAZE_UPPER, []{return true;}), + Entrance(RR_FIRE_TEMPLE_EAST_PEAK, []{return true;}), + }); + + areaTable[RR_FIRE_TEMPLE_EAST_PEAK] = Region("Fire Temple East Peak", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_SCARECROW_CHEST, true), + LOCATION(RC_FIRE_TEMPLE_GS_SCARECROW_TOP, logic->CanUseProjectile()), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_SCARECROW_ROOM, []{return true;}), + Entrance(RR_FIRE_TEMPLE_EAST_CENTRAL_ROOM, []{return logic->TakeDamage();}), + }); + + areaTable[RR_FIRE_TEMPLE_CORRIDOR] = Region("Fire Temple Corridor", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_FIRE_TEMPLE_FIRE_WALL_CHASE, []{return logic->SmallKeys(RR_FIRE_TEMPLE, 7);}), + Entrance(RR_FIRE_TEMPLE_FIRE_MAZE_ROOM, []{return true;}), + }); + + areaTable[RR_FIRE_TEMPLE_FIRE_MAZE_ROOM] = Region("Fire Temple Fire Maze Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + // Locations + LOCATION(RC_FIRE_TEMPLE_FLAME_MAZE_LEFT_POT_1, logic->CanBreakPots()), + LOCATION(RC_FIRE_TEMPLE_FLAME_MAZE_LEFT_POT_2, logic->CanBreakPots()), + LOCATION(RC_FIRE_TEMPLE_FLAME_MAZE_LEFT_POT_3, logic->CanBreakPots()), + LOCATION(RC_FIRE_TEMPLE_FLAME_MAZE_LEFT_POT_4, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_CORRIDOR, []{return true;}), + Entrance(RR_FIRE_TEMPLE_FIRE_MAZE_UPPER, []{return logic->CanUse(RG_HOVER_BOOTS);}), + Entrance(RR_FIRE_TEMPLE_FIRE_MAZE_SIDE_ROOM, []{return true;}), + Entrance(RR_FIRE_TEMPLE_WEST_CENTRAL_LOWER, []{return logic->SmallKeys(RR_FIRE_TEMPLE, 8);}), + Entrance(RR_FIRE_TEMPLE_LATE_FIRE_MAZE, []{return ctx->GetTrickOption(RT_FIRE_FLAME_MAZE) || false;}), + }); + + areaTable[RR_FIRE_TEMPLE_FIRE_MAZE_UPPER] = Region("Fire Temple Fire Maze Upper", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_FIRE_TEMPLE_NEAR_BOSS_ROOM, []{return logic->CanUse(RG_MEGATON_HAMMER);}), + Entrance(RR_FIRE_TEMPLE_FIRE_MAZE_ROOM, []{return true;}), + Entrance(RR_FIRE_TEMPLE_WEST_CENTRAL_UPPER, []{return logic->CanUse(RG_MEGATON_HAMMER);}), + }); + + areaTable[RR_FIRE_TEMPLE_FIRE_MAZE_SIDE_ROOM] = Region("Fire Temple Fire Maze Side Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_COMPASS_CHEST, true), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_FIRE_MAZE_ROOM, []{return true;}), + }); + + areaTable[RR_FIRE_TEMPLE_WEST_CENTRAL_LOWER] = Region("Fire Temple West Central Lower", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_HIGHEST_GORON_CHEST, Here(RR_FIRE_TEMPLE_WEST_CENTRAL_UPPER, []{return (logic->CanUse(RG_SONG_OF_TIME) || ctx->GetTrickOption(RT_RUSTED_SWITCHES)) && logic->CanUse(RG_MEGATON_HAMMER);})), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_FIRE_MAZE_ROOM, []{return logic->SmallKeys(RR_FIRE_TEMPLE, 8);}), + Entrance(RR_FIRE_TEMPLE_WEST_CENTRAL_UPPER, []{return logic->IsAdult && logic->CanUse(RG_SONG_OF_TIME);}), + Entrance(RR_FIRE_TEMPLE_LATE_FIRE_MAZE, []{return true;}), + }); + + areaTable[RR_FIRE_TEMPLE_WEST_CENTRAL_UPPER] = Region("Fire Temple West Central Upper", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_FIRE_TEMPLE_BOSS_ENTRYWAY, []{return false;}), + Entrance(RR_FIRE_TEMPLE_FIRE_MAZE_UPPER, []{return true;}), + Entrance(RR_FIRE_TEMPLE_WEST_CENTRAL_LOWER, []{return true;}), + }); + + areaTable[RR_FIRE_TEMPLE_LATE_FIRE_MAZE] = Region("Fire Temple Late Fire Maze", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + // Locations + LOCATION(RC_FIRE_TEMPLE_FLAME_MAZE_RIGHT_POT_1, logic->CanBreakPots()), + LOCATION(RC_FIRE_TEMPLE_FLAME_MAZE_RIGHT_POT_2, logic->CanBreakPots()), + LOCATION(RC_FIRE_TEMPLE_FLAME_MAZE_RIGHT_POT_3, logic->CanBreakPots()), + LOCATION(RC_FIRE_TEMPLE_FLAME_MAZE_RIGHT_POT_4, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_FIRE_MAZE_ROOM, []{return false;}), + Entrance(RR_FIRE_TEMPLE_WEST_CENTRAL_LOWER, []{return true;}), + Entrance(RR_FIRE_TEMPLE_UPPER_FLARE_DANCER, []{return logic->HasExplosives();}), + }); + + areaTable[RR_FIRE_TEMPLE_UPPER_FLARE_DANCER] = Region("Fire Temple Upper Flare Dancer", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_FIRE_TEMPLE_LATE_FIRE_MAZE, []{return Here(RR_FIRE_TEMPLE_UPPER_FLARE_DANCER, []{return logic->CanKillEnemy(RE_FLARE_DANCER);});}), + Entrance(RR_FIRE_TEMPLE_WEST_CLIMB, []{return Here(RR_FIRE_TEMPLE_UPPER_FLARE_DANCER, []{return logic->CanKillEnemy(RE_FLARE_DANCER);});}), + }); + + areaTable[RR_FIRE_TEMPLE_WEST_CLIMB] = Region("Fire Temple West Climb", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_FIRE_TEMPLE_UPPER_FLARE_DANCER, []{return true;}), + Entrance(RR_FIRE_TEMPLE_WEST_PEAK, []{return logic->CanUseProjectile();}), + }); + + areaTable[RR_FIRE_TEMPLE_WEST_PEAK] = Region("Fire Temple West Peak", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_MEGATON_HAMMER_CHEST, true), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_WEST_CENTRAL_UPPER, []{return logic->TakeDamage();}), + Entrance(RR_FIRE_TEMPLE_WEST_CLIMB, []{return true;}), + Entrance(RR_FIRE_TEMPLE_HAMMER_RETURN_PATH, []{return logic->CanUse(RG_MEGATON_HAMMER);}), + }); + + areaTable[RR_FIRE_TEMPLE_HAMMER_RETURN_PATH] = Region("Fire Temple Hammer Return Path", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_FIRE_TEMPLE_ABOVE_FIRE_MAZE, []{return logic->CanUse(RG_MEGATON_HAMMER);}), + }); + + areaTable[RR_FIRE_TEMPLE_ABOVE_FIRE_MAZE] = Region("Fire Temple Above Fire Maze", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_FIRE_TEMPLE_HAMMER_RETURN_PATH, []{return true;}), + Entrance(RR_FIRE_TEMPLE_FIRE_MAZE_UPPER, []{return logic->CanUse(RG_MEGATON_HAMMER);}), + }); + +#pragma endregion + +#pragma region MQ + + //potentially dangerous temp flag on the first room's torches, should be made permanent if possible + areaTable[RR_FIRE_TEMPLE_MQ_FIRST_ROOM_LOWER] = Region("Fire Temple MQ First Room Lower", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_MQ_ENTRANCE_POT_1, logic->CanBreakPots()), + LOCATION(RC_FIRE_TEMPLE_MQ_ENTRANCE_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_ENTRYWAY, []{return true;}), + Entrance(RR_FIRE_TEMPLE_MQ_MAP_ROOM_SOUTH, []{return true;}), + Entrance(RR_FIRE_TEMPLE_MQ_FIRST_ROOM_UPPER, []{return logic->IsAdult || logic->CanUse(RG_HOOKSHOT);}), + Entrance(RR_FIRE_TEMPLE_MQ_STALFOS_ROOM, []{return logic->SmallKeys(RR_FIRE_TEMPLE, 5);}), + }); + + areaTable[RR_FIRE_TEMPLE_MQ_FIRST_ROOM_UPPER] = Region("Fire Temple MQ First Room Upper", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_FIRE_TEMPLE_MQ_FIRST_ROOM_LOWER, []{return true;}), + Entrance(RR_FIRE_TEMPLE_NEAR_BOSS_ROOM, []{return logic->HasFireSource();}), + Entrance(RR_FIRE_TEMPLE_MQ_BIG_LAVA_ROOM, []{return Here(RR_FIRE_TEMPLE_MQ_FIRST_ROOM_UPPER, []{return logic->CanUse(RG_MEGATON_HAMMER);});}), + }); + + areaTable[RR_FIRE_TEMPLE_MQ_MAP_ROOM_SOUTH] = Region("Fire Temple MQ Map Room South", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_MQ_MAP_ROOM_SIDE_CHEST, logic->CanKillEnemy(RE_LIKE_LIKE)), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_MQ_FIRST_ROOM_LOWER, []{return Here(RR_FIRE_TEMPLE_MQ_FIRST_ROOM_LOWER, []{return logic->CanKillEnemy(RE_LIKE_LIKE);});}), + Entrance(RR_FIRE_TEMPLE_MQ_MAP_ROOM_CAGE, []{return logic->OpenedLowestGoronCage;}), + }); + + areaTable[RR_FIRE_TEMPLE_MQ_STALFOS_ROOM] = Region("Fire Temple MQ Stalfos Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_MQ_LOOP_STALFOS_SUN_FAIRY, logic->CanUse(RG_SUNS_SONG)), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_MQ_FIRST_ROOM_LOWER, []{return true;}), + Entrance(RR_FIRE_TEMPLE_MQ_IRON_KNUCKLE_ROOM, []{return Here(RR_FIRE_TEMPLE_MQ_FIRST_ROOM_LOWER, []{return logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2);});}), + }); + + areaTable[RR_FIRE_TEMPLE_MQ_IRON_KNUCKLE_ROOM] = Region("Fire Temple MQ Iron Knuckle Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->FairyPot, []{return true;}), + }, { + //Locations + LOCATION(RC_FIRE_TEMPLE_MQ_LOOP_KNUCKLE_SUN_FAIRY, logic->CanUse(RG_SUNS_SONG)), + LOCATION(RC_FIRE_TEMPLE_MQ_BEFORE_MINI_BOSS_POT_1, logic->CanBreakPots()), + LOCATION(RC_FIRE_TEMPLE_MQ_BEFORE_MINI_BOSS_POT_2, logic->CanBreakPots()), + LOCATION(RC_FIRE_TEMPLE_MQ_BEFORE_MINI_BOSS_POT_3, logic->CanBreakPots()), + LOCATION(RC_FIRE_TEMPLE_MQ_BEFORE_MINI_BOSS_POT_4, logic->CanBreakPots()), + LOCATION(RC_FIRE_TEMPLE_MQ_BEFORE_MINI_BOSS_POT_5, logic->CanBreakPots()), + LOCATION(RC_FIRE_TEMPLE_MQ_BEFORE_MINI_BOSS_POT_6, logic->CanBreakPots()), + LOCATION(RC_FIRE_TEMPLE_MQ_BEFORE_MINI_BOSS_POT_7, logic->CanBreakPots()), + LOCATION(RC_FIRE_TEMPLE_MQ_BEFORE_MINI_BOSS_POT_8, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_MQ_STALFOS_ROOM, []{return true;}), + Entrance(RR_FIRE_TEMPLE_MQ_LOWER_FLARE_DANCER, []{return Here(RR_FIRE_TEMPLE_MQ_FIRST_ROOM_LOWER, []{return logic->CanKillEnemy(RE_IRON_KNUCKLE);});}), + }); + + areaTable[RR_FIRE_TEMPLE_MQ_LOWER_FLARE_DANCER] = Region("Fire Temple MQ Lower Flare Dancer", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_MQ_MEGATON_HAMMER_CHEST, (logic->IsAdult || logic->CanUse(RG_HOOKSHOT)) && Here(RR_FIRE_TEMPLE_MQ_LOWER_FLARE_DANCER, []{return logic->CanKillEnemy(RE_FLARE_DANCER);})), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_MQ_IRON_KNUCKLE_ROOM, []{return true;}), + Entrance(RR_FIRE_TEMPLE_MQ_MAP_ROOM_NORTH, []{return Here(RR_FIRE_TEMPLE_MQ_LOWER_FLARE_DANCER, []{return logic->CanKillEnemy(RE_FLARE_DANCER);});}), + }); + + areaTable[RR_FIRE_TEMPLE_MQ_MAP_ROOM_NORTH] = Region("Fire Temple MQ Map Room North", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->OpenedLowestGoronCage, []{return logic->CanUse(RG_MEGATON_HAMMER);}), + }, {}, { + //Exits + Entrance(RR_FIRE_TEMPLE_MQ_LOWER_FLARE_DANCER, []{return true;}), + Entrance(RR_FIRE_TEMPLE_MQ_MAP_ROOM_CAGE, []{return logic->OpenedLowestGoronCage;}), + }); + + areaTable[RR_FIRE_TEMPLE_MQ_MAP_ROOM_CAGE] = Region("Fire Temple MQ Map Room Cage", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_MQ_MAP_CHEST, true), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_MQ_MAP_ROOM_NORTH, []{return logic->OpenedLowestGoronCage;}), + Entrance(RR_FIRE_TEMPLE_MQ_MAP_ROOM_SOUTH, []{return logic->OpenedLowestGoronCage;}), + }); + + areaTable[RR_FIRE_TEMPLE_NEAR_BOSS_ROOM] = Region("Fire Temple MQ Near Boss Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + //If we're using the south torch as the initial torch, or using FAs, we either have to cross to the north to remove the crate, or use a trick to ignore it + LOCATION(RC_FIRE_TEMPLE_MQ_NEAR_BOSS_CHEST, logic->FireTimer() > 25 && ctx->GetTrickOption(RT_FIRE_MQ_NEAR_BOSS) && (logic->CanUse(RG_FIRE_ARROWS) || (logic->IsAdult && logic->CanUse(RG_DINS_FIRE) && logic->CanUse(RG_FAIRY_BOW)))) + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_MQ_FIRST_ROOM_UPPER, []{return true;}), + //Child cannot make it to the north side torches without a hook without specifically bunny hood speed + hover boots + Entrance(RR_FIRE_TEMPLE_NEAR_BOSS_ROOM_NORTH, []{return logic->FireTimer() > 32 && (logic->CanUse(RG_HOOKSHOT) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)));}), + Entrance(RR_FIRE_TEMPLE_BOSS_ENTRYWAY, []{return logic->HasItem(RG_FIRE_TEMPLE_BOSS_KEY) && logic->FireTimer() >= 15 && ((logic->IsAdult && (ctx->GetTrickOption(RT_FIRE_BOSS_DOOR_JUMP) || logic->CanUse(RG_HOVER_BOOTS))) || (logic->IsAdult && logic->HitFireTemplePlatform) || (logic->HitFireTemplePlatform && logic->CanUse(RG_HOVER_BOOTS)));}), + }); + + //This room assumes tunic logic is handled on entry. + //Covers the upper section too, as all methods to reach this can climb up somehow + areaTable[RR_FIRE_TEMPLE_NEAR_BOSS_ROOM_NORTH] = Region("Fire Temple MQ Near Boss Room North", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + //If we have FAs, we can just remove the crate and use those to light the torches. + //otherwise, with Dins, we first light them with dins and then either use a bow shot or to cross back over to light the other torch + //Valid ways across are adult+hovers, bunny+hovers, longshot or running through the lava and then climbing back up as adult (child can't reach the ledge). + //The Damage logic here is for jumping down and running across the lava to get in dins range of the south torch + //Fairies cannot be used for this as it is time sensetive, and NL is only useful with sticks as it disables other magic while in use, so it's tunic or raw damage taking ability. + //testing tells me you take 3 ticks of lava damage, which is 12 internal damage or 3/4 of a heart at x1 damage multiplier, performing this run + //logic->EffectiveHealth() works in half hearts for whatever reason, meaning this needs a deeper refactor to be perfect, but it should be good enough for now + LOCATION(RC_FIRE_TEMPLE_MQ_NEAR_BOSS_CHEST, logic->CanUse(RG_FIRE_ARROWS) || (logic->CanUse(RG_DINS_FIRE) && (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_LONGSHOT) || (logic->IsAdult && (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_GORON_TUNIC) || logic->EffectiveHealth() >= 2 || (logic->CanUse(RG_NAYRUS_LOVE) && logic->CanUse(RG_STICKS))))))), + LOCATION(RC_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_POT_1, logic->CanBreakPots()), + LOCATION(RC_FIRE_TEMPLE_MQ_OUTSIDE_BOSS_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_NEAR_BOSS_ROOM, []{return true;}), + }); + + areaTable[RR_FIRE_TEMPLE_MQ_BIG_LAVA_ROOM] = Region("Fire Temple MQ Big Lava Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + //I'm currently assuming the oversight version of RT_FIRE_MQ_BK_CHEST for the fire timer logic + LOCATION(RC_FIRE_TEMPLE_MQ_BIG_LAVA_ROOM_BLOCKED_DOOR_CHEST, logic->FireTimer() >= 40 && logic->HasFireSource() && logic->HasExplosives() && (logic->CanUse(RG_HOOKSHOT) || (logic->IsAdult && ctx->GetTrickOption(RT_FIRE_MQ_BLOCKED_CHEST)))), + //implies CanGetEnemyDrop(RE_GOLD_SKULLTULA) + LOCATION(RC_FIRE_TEMPLE_MQ_GS_BIG_LAVA_ROOM_OPEN_DOOR, logic->FireTimer() >= 20 && logic->CanUse(RG_MEGATON_HAMMER)), + LOCATION(RC_FIRE_TEMPLE_MQ_LAVA_ROOM_NORTH_POT, logic->CanBreakPots()), + LOCATION(RC_FIRE_TEMPLE_MQ_LAVA_ROOM_HIGH_POT, logic->CanBreakPots()), + LOCATION(RC_FIRE_TEMPLE_MQ_LAVA_ROOM_SOUTH_POT, logic->FireTimer() >= 40 && (logic->CanUse(RG_HOOKSHOT) || (ctx->GetTrickOption(RT_FIRE_MQ_BLOCKED_CHEST) && ((logic->IsAdult && logic->CanBreakPots()) || logic->CanUse(RG_BOOMERANG))))), + }, { + //Exits + // Fewer tunic requirements ends here + Entrance(RR_FIRE_TEMPLE_MQ_FIRST_ROOM_UPPER, []{return logic->FireTimer() >= 20;}), + Entrance(RR_FIRE_TEMPLE_MQ_ELEVATOR_ROOM, []{return logic->CanUse(RG_GORON_TUNIC) && logic->SmallKeys(RR_FIRE_TEMPLE, 2);}), + Entrance(RR_FIRE_TEMPLE_MQ_TORCH_FIREWALL_ROOM, []{return logic->HasFireSource() && ((logic->CanUse(RG_FAIRY_BOW) && logic->FireTimer() >= 25) || (ctx->GetTrickOption(RT_FIRE_MQ_BK_CHEST) && logic->FireTimer() >= 50)) && (logic->CanUse(RG_HOOKSHOT) || (logic->IsAdult && ctx->GetTrickOption(RT_FIRE_SOT)));}), + }); + + areaTable[RR_FIRE_TEMPLE_MQ_TORCH_FIREWALL_ROOM] = Region("Fire Temple MQ Torch Firewall Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->FairyPot, []{return logic->CanUse(RG_HOOKSHOT);}), + }, { + //Locations + LOCATION(RC_FIRE_TEMPLE_MQ_BOSS_KEY_CHEST, logic->CanUse(RG_HOOKSHOT)), + LOCATION(RC_FIRE_TEMPLE_MQ_LAVA_TORCH_POT_1, logic->HookshotOrBoomerang()), + LOCATION(RC_FIRE_TEMPLE_MQ_LAVA_TORCH_POT_2, logic->HookshotOrBoomerang()), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_MQ_BIG_LAVA_ROOM, []{return true;}), + }); + + //This room assumes Goron Tunic until looser tunic requirements tricks are made + areaTable[RR_FIRE_TEMPLE_MQ_ELEVATOR_ROOM] = Region("Fire Temple MQ Elevator Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_MQ_FIRE_PILLAR_LEFT_HEART, true), + LOCATION(RC_FIRE_TEMPLE_MQ_FIRE_PILLAR_RIGHT_HEART, true), + LOCATION(RC_FIRE_TEMPLE_MQ_FIRE_PILLAR_LOWER_HEART, true), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_MQ_BIG_LAVA_ROOM, []{return true;}), + Entrance(RR_FIRE_TEMPLE_MQ_BIG_TORCH_ROOM, []{return true;}), + }); + + areaTable[RR_FIRE_TEMPLE_MQ_BIG_TORCH_ROOM] = Region("Fire Temple MQ Big Torch Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_FIRE_TEMPLE_MQ_LOWER_MAZE, []{return (logic->HasFireSource() && logic->CanUse(RG_HOOKSHOT)) || (ctx->GetTrickOption(RT_FIRE_MQ_CLIMB) && logic->CanUse(RG_HOVER_BOOTS));}), + Entrance(RR_FIRE_TEMPLE_MQ_ELEVATOR_ROOM, []{return logic->CanUse(RG_GORON_TUNIC);}), + Entrance(RR_FIRE_TEMPLE_MQ_MAZE_SHORTCUT_CAGE, []{return logic->OpenedUpperFireShortcut;}), + }); + + areaTable[RR_FIRE_TEMPLE_MQ_LOWER_MAZE] = Region("Fire Temple MQ Lower Maze", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + //Check handled on both floors + LOCATION(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_SIDE_ROOM_CHEST, logic->HasExplosives() && ctx->GetTrickOption(RT_FIRE_MQ_MAZE_SIDE_ROOM)), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_MQ_BIG_TORCH_ROOM, []{return true;}), + //Explosives can also reach this room. Chus is relatively simple, they need to detonate on the first horizontal bar up from the floor while horizontally near the switch, but bombs are much harder + Entrance(RR_FIRE_TEMPLE_MQ_LOWER_MAZE_CRATE_CAGE, []{return Here(RR_FIRE_TEMPLE_MQ_LOWER_MAZE, []{return logic->CanJumpslash();});}), + //it's possible to make the RT_FIRE_MQ_MAZE_HOVERS as child using bunny hood jumps, but not adult as adult bonks + Entrance(RR_FIRE_TEMPLE_MQ_UPPER_MAZE, []{return logic->HasExplosives() && logic->CanUse(RG_MEGATON_HAMMER) && logic->CanUse(RG_HOOKSHOT);}), + }); + + areaTable[RR_FIRE_TEMPLE_MQ_LOWER_MAZE_CRATE_CAGE] = Region("Fire Temple MQ Lower Maze Crate Cage", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_LOWER_CHEST, true), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_MQ_LOWER_MAZE, []{return true;}), + //it's possible to make the RT_FIRE_MQ_MAZE_HOVERS as child using bunny hood jumps, but not adult as adult bonks + Entrance(RR_FIRE_TEMPLE_MQ_UPPER_MAZE, []{return logic->IsAdult && ((ctx->GetTrickOption(RT_FIRE_MQ_MAZE_HOVERS) && logic->CanUse(RG_HOVER_BOOTS)) || ctx->GetTrickOption(RT_FIRE_MQ_MAZE_JUMP));}), + }); + + areaTable[RR_FIRE_TEMPLE_MQ_UPPER_MAZE] = Region("Fire Temple MQ Upper Maze", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_FIRE_TEMPLE_MQ_LOWER_MAZE, []{return true;}), + //this cage is much more lenient than the lower cage as the switch is close to the front. sling, rang and bow all hit the switch easily, though might be too unintuitive for default logic + //This shouldn't come up in most cases anyway as most methods to get here need either a melee weapon or explosives + Entrance(RR_FIRE_TEMPLE_MQ_UPPER_MAZE_BOX_CAGE, []{return Here(RR_FIRE_TEMPLE_MQ_UPPER_MAZE, []{return logic->CanJumpslash() || logic->HasExplosives();});}), + Entrance(RR_FIRE_TEMPLE_MQ_MAZE_SHORTCUT, []{return logic->HasExplosives();}), + //Implies RR_FIRE_TEMPLE_MQ_LOWER_MAZE access + Entrance(RR_FIRE_TEMPLE_MQ_BURNING_BLOCK_CLIMB, []{return logic->HasExplosives() && logic->CanUse(RG_MEGATON_HAMMER) && (logic->CanUse(RG_LONGSHOT) || (logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_SONG_OF_TIME)));}), + Entrance(RR_FIRE_TEMPLE_MQ_HIGH_TORCH_ROOM, []{return logic->SmallKeys(RR_FIRE_TEMPLE, 3) && logic->CanUse(RG_GORON_TUNIC);}), + }); + + areaTable[RR_FIRE_TEMPLE_MQ_UPPER_MAZE_BOX_CAGE] = Region("Fire Temple MQ Upper Maze Box Cage", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_UPPER_CHEST, true), + //Assumes maze access + LOCATION(RC_FIRE_TEMPLE_MQ_LIZALFOS_MAZE_SIDE_ROOM_CHEST, logic->HasExplosives()), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_MQ_UPPER_MAZE, []{return true;}), + }); + + areaTable[RR_FIRE_TEMPLE_MQ_MAZE_SHORTCUT] = Region("Fire Temple MQ Maze Shortcut", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->OpenedUpperFireShortcut, []{return logic->CanUse(RG_MEGATON_HAMMER);}), + }, {}, { + //Exits + Entrance(RR_FIRE_TEMPLE_MQ_UPPER_MAZE, []{return true;}), + Entrance(RR_FIRE_TEMPLE_MQ_MAZE_SHORTCUT_CAGE, []{return logic->OpenedUpperFireShortcut;}), + }); + + areaTable[RR_FIRE_TEMPLE_MQ_MAZE_SHORTCUT_CAGE] = Region("Fire Temple MQ Maze Shortcut Cage", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_MQ_COMPASS_CHEST, logic->OpenedUpperFireShortcut;), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_MQ_MAZE_SHORTCUT, []{return logic->OpenedUpperFireShortcut;}), + Entrance(RR_FIRE_TEMPLE_MQ_BIG_TORCH_ROOM, []{return logic->OpenedUpperFireShortcut;}), + }); + + + areaTable[RR_FIRE_TEMPLE_MQ_BURNING_BLOCK_CLIMB] = Region("Fire Temple MQ Burning Block Climb", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + //EventAccess(&WallFairy, []{return logic->CanUse(RG_HOOKSHOT);}), + }, { + //Locations + //There's definitely ways to do this hammerless, but with one points on it's a trick + LOCATION(RC_FIRE_TEMPLE_MQ_GS_SKULL_ON_FIRE, logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_MEGATON_HAMMER)), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_MQ_UPPER_MAZE, []{return true;}), + Entrance(RR_FIRE_TEMPLE_MQ_NARROW_PATH_ROOM, []{return logic->TakeDamage();}), + }); + + areaTable[RR_FIRE_TEMPLE_MQ_NARROW_PATH_ROOM] = Region("Fire Temple MQ Narrow Path Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->FairyPot, []{return true;}), + }, { + //Locations + LOCATION(RC_FIRE_TEMPLE_MQ_ABOVE_LAVA_POT_1, logic->CanBreakPots()), + LOCATION(RC_FIRE_TEMPLE_MQ_ABOVE_LAVA_POT_2, logic->CanBreakPots()), + LOCATION(RC_FIRE_TEMPLE_MQ_ABOVE_LAVA_POT_3, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_MQ_LOWER_MAZE, []{return true;}), + Entrance(RR_FIRE_TEMPLE_MQ_BIG_LAVA_ROOM, []{return logic->TakeDamage();}), + }); + + areaTable[RR_FIRE_TEMPLE_MQ_HIGH_TORCH_ROOM] = Region("Fire Temple MQ High Torch Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_MQ_FLAME_WALL_POT_1, logic->CanBreakPots()), + LOCATION(RC_FIRE_TEMPLE_MQ_FLAME_WALL_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_MQ_UPPER_MAZE, []{return logic->SmallKeys(RR_FIRE_TEMPLE, 3);}), + Entrance(RR_FIRE_TEMPLE_MQ_NARROW_PATH_ROOM, []{return true;}), + //Child has issues navigating the higher points of this room without an equip swapped hookshot + Entrance(RR_FIRE_TEMPLE_MQ_SOUTH_FIRE_MAZE, []{return Here(RR_FIRE_TEMPLE_MQ_HIGH_TORCH_ROOM, []{return logic->CanUse(RG_FIRE_ARROWS) || (logic->CanUse(RG_FAIRY_BOW) && logic->CanUse(RG_HOOKSHOT));}) && (logic->IsAdult || logic->CanUse(RG_HOOKSHOT));}), + }); + + areaTable[RR_FIRE_TEMPLE_MQ_SOUTH_FIRE_MAZE] = Region("Fire Temple MQ South Fire Maze", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_CENTER, logic->HasExplosives()), + LOCATION(RC_FIRE_TEMPLE_MQ_SOUTH_FIRE_MAZE_WEST_POT, logic->CanBreakPots()), + LOCATION(RC_FIRE_TEMPLE_MQ_SOUTH_FIRE_MAZE_EAST_POT, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_MQ_NEAR_BOSS_DOOR, []{return logic->HitFireTemplePlatform;}), + Entrance(RR_FIRE_TEMPLE_MQ_HIGH_TORCH_ROOM, []{return true;}), + Entrance(RR_FIRE_TEMPLE_MQ_FIRE_MAZE_PLATFORMS, []{return logic->IsAdult || logic->CanUse(RG_SONG_OF_TIME) || logic->CanUse(RG_HOVER_BOOTS);}), + //Hover boots get there via the platforms + Entrance(RR_FIRE_TEMPLE_MQ_NORTH_FIRE_MAZE, []{return (bool)ctx->GetTrickOption(RT_FIRE_MQ_FLAME_MAZE);}), + Entrance(RR_FIRE_TEMPLE_MQ_WEST_FIRE_MAZE, []{return logic->OpenedFireMQFireMazeDoor;}), + }); + + areaTable[RR_FIRE_TEMPLE_MQ_FIRE_MAZE_PLATFORMS] = Region("Fire Temple MQ Fire Maze Platforms", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->HitFireTemplePlatform, []{return logic->CanUse(RG_MEGATON_HAMMER);}), + EventAccess(&logic->OpenedFireMQFireMazeDoor, []{return logic->CanUse(RG_MEGATON_HAMMER) && logic->CanUse(RG_HOOKSHOT);}), + }, {}, { + Entrance(RR_FIRE_TEMPLE_MQ_SOUTH_FIRE_MAZE, []{return true;}), + Entrance(RR_FIRE_TEMPLE_MQ_NORTH_FIRE_MAZE, []{return logic->CanUse(RG_SONG_OF_TIME) || logic->CanUse(RG_HOVER_BOOTS);}), + //trick to get to RR_FIRE_TEMPLE_MQ_WEST_FIRE_MAZE with hovers + taking damage is plausible + }); + + areaTable[RR_FIRE_TEMPLE_MQ_NORTH_FIRE_MAZE] = Region("Fire Temple MQ North Fire Maze", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_MQ_GS_FIRE_WALL_MAZE_SIDE_ROOM, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)), + LOCATION(RC_FIRE_TEMPLE_MQ_PAST_FIRE_MAZE_SOUTH_POT, logic->CanUse(RG_BOOMERANG)), + LOCATION(RC_FIRE_TEMPLE_MQ_FIRE_MAZE_NORTHMOST_POT, logic->CanBreakPots()), + LOCATION(RC_FIRE_TEMPLE_MQ_FIRE_MAZE_NORTHWEST_POT, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_FIRE_TEMPLE_MQ_SOUTH_FIRE_MAZE, []{return logic->IsAdult || ctx->GetTrickOption(RT_FIRE_MQ_FLAME_MAZE);}), + Entrance(RR_FIRE_TEMPLE_MQ_WEST_FIRE_MAZE, []{return (bool)ctx->GetTrickOption(RT_FIRE_MQ_FLAME_MAZE);}), + }); + + areaTable[RR_FIRE_TEMPLE_MQ_WEST_FIRE_MAZE] = Region("Fire Temple MQ West Fire Maze", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + Entrance(RR_FIRE_TEMPLE_MQ_FIRE_MAZE_PAST_WALL, []{return true;}), + Entrance(RR_FIRE_TEMPLE_MQ_NORTH_FIRE_MAZE, []{return (bool)ctx->GetTrickOption(RT_FIRE_MQ_FLAME_MAZE);}), + }); + + //this area exists for the pots in case we void warp to the top of fire somehow, because there's no way to get back the way we came + areaTable[RR_FIRE_TEMPLE_MQ_FIRE_MAZE_PAST_WALL] = Region("Fire Temple MQ Fire Maze Past Wall", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_MQ_PAST_FIRE_MAZE_SOUTH_POT, logic->CanBreakPots()), + LOCATION(RC_FIRE_TEMPLE_MQ_PAST_FIRE_MAZE_NORTH_POT, logic->CanBreakPots()), + LOCATION(RC_FIRE_TEMPLE_MQ_FIRE_MAZE_NORTHWEST_POT, logic->CanUse(RG_BOOMERANG)), + }, { + Entrance(RR_FIRE_TEMPLE_MQ_UPPER_FLARE_DANCER, []{return true;}), + }); + + areaTable[RR_FIRE_TEMPLE_MQ_UPPER_FLARE_DANCER] = Region("Fire Temple MQ North Fire Maze", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FIRE_TEMPLE_MQ_FREESTANDING_KEY, logic->CanKillEnemy(RE_FLARE_DANCER)), + }, { + Entrance(RR_FIRE_TEMPLE_MQ_FIRE_MAZE_PAST_WALL, []{return logic->CanKillEnemy(RE_FLARE_DANCER);}), + Entrance(RR_FIRE_TEMPLE_MQ_SCARECROW_ROOM, []{return logic->CanKillEnemy(RE_FLARE_DANCER) && logic->SmallKeys(RR_FIRE_TEMPLE, 4);}), + }); + + areaTable[RR_FIRE_TEMPLE_MQ_SCARECROW_ROOM] = Region("Fire Temple MQ Scarecrow Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + //This requires nothing in N64 logic, but is tight enough to need rollspam with the one-point on which is stricter than I would normally consider in logic + //Child basically needs the scarecrow or a bunny hood though due to a worse ledge grab. + LOCATION(RC_FIRE_TEMPLE_MQ_CHEST_ON_FIRE, logic->IsAdult || logic->CanUse(RG_SCARECROW)), + }, { + //The dropdown here is unusual in that it hits 1 of 3 locations: RR_FIRE_TEMPLE_MQ_SOUTH_FIRE_MAZE, RR_FIRE_TEMPLE_MQ_FIRE_MAZE_PLATFORMS and the section of RR_FIRE_TEMPLE_MQ_FIRE_MAZE_PLATFORMS with the hammer switch + //Using this dropdown is in N64 logic elsewhere, but not here, probably because it requires good foreknowlege to determine where to land + //This would be a logical method to reach the hammer switch without hookshot, but it practically requires access to the area that switch unlocks already. It could also be first child access to PLATFORMS if tricks ever enable that + //If a practical use for this drop is found, it should be made a trick + Entrance(RR_FIRE_TEMPLE_MQ_UPPER_FLARE_DANCER, []{return logic->SmallKeys(RR_FIRE_TEMPLE, 4);}), + Entrance(RR_FIRE_TEMPLE_MQ_COLLAPSED_STAIRS, []{return Here(RR_FIRE_TEMPLE_MQ_SCARECROW_ROOM, []{return logic->CanUse(RG_MEGATON_HAMMER);}) && logic->SmallKeys(RR_FIRE_TEMPLE, 5);}), + }); + + //The peg knocked down from here could have logical implications for child in the fire maze if tricks to gain height like bomb jumps exist + areaTable[RR_FIRE_TEMPLE_MQ_COLLAPSED_STAIRS] = Region("Fire Temple MQ Collapsed Stairs", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + //If someone manages to make a trick to get here from fire maze, this needs to be in a separate room as the door back is barred + LOCATION(RC_FIRE_TEMPLE_MQ_GS_ABOVE_FIRE_MAZE, logic->CanUse(RG_HOOKSHOT)), + }, { + Entrance(RR_FIRE_TEMPLE_MQ_FIRE_MAZE_PLATFORMS, []{return logic->CanUse(RG_HOOKSHOT) && Here(RR_FIRE_TEMPLE_MQ_COLLAPSED_STAIRS, []{return logic->CanUse(RG_MEGATON_HAMMER);});}), + Entrance(RR_FIRE_TEMPLE_MQ_SCARECROW_ROOM, []{return logic->IsAdult && logic->CanUse(RG_HOOKSHOT);}), + }); + +#pragma endregion + + // Boss Room + areaTable[RR_FIRE_TEMPLE_BOSS_ENTRYWAY] = Region("Fire Temple Boss Entryway", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + // Exits + Entrance(RR_FIRE_TEMPLE_NEAR_BOSS_ROOM, []{return ctx->GetDungeon(FIRE_TEMPLE)->IsVanilla() && false;}), + Entrance(RR_FIRE_TEMPLE_MQ_NEAR_BOSS_DOOR, []{return ctx->GetDungeon(FIRE_TEMPLE)->IsMQ() && false;}), + Entrance(RR_FIRE_TEMPLE_BOSS_ROOM, []{return true;}), + }); + + areaTable[RR_FIRE_TEMPLE_BOSS_ROOM] = Region("Fire Temple Boss Room", "Fire Temple", {}, NO_DAY_NIGHT_CYCLE, { + // Events + EventAccess(&logic->FireTempleClear, []{return logic->FireTempleClear || (logic->HasBossSoul(RG_VOLVAGIA_SOUL) && (logic->FireTimer() >= 64 && logic->CanUse(RG_MEGATON_HAMMER)));}), + }, { + // Locations + LOCATION(RC_FIRE_TEMPLE_VOLVAGIA_HEART, logic->FireTempleClear), + LOCATION(RC_VOLVAGIA, logic->FireTempleClear), + }, { + // Exits + Entrance(RR_FIRE_TEMPLE_BOSS_ENTRYWAY, []{return false;}), + Entrance(RR_DMC_CENTRAL_LOCAL, []{return logic->FireTempleClear;}, false), + }); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/forest_temple.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/forest_temple.cpp new file mode 100644 index 000000000..241a82064 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/forest_temple.cpp @@ -0,0 +1,613 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" +#include "soh/Enhancements/randomizer/dungeon.h" + +using namespace Rando; + +void RegionTable_Init_ForestTemple() { + // Vanilla/MQ Decider + areaTable[RR_FOREST_TEMPLE_ENTRYWAY] = Region("Forest Temple Entryway", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_FOREST_TEMPLE_FIRST_ROOM, []{return ctx->GetDungeon(FOREST_TEMPLE)->IsVanilla();}), + Entrance(RR_FOREST_TEMPLE_MQ_LOBBY, []{return ctx->GetDungeon(FOREST_TEMPLE)->IsMQ();}), + Entrance(RR_SACRED_FOREST_MEADOW, []{return true;}), + }); + +#pragma region Vanilla + + areaTable[RR_FOREST_TEMPLE_FIRST_ROOM] = Region("Forest Temple First Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FOREST_TEMPLE_FIRST_ROOM_CHEST, true), + LOCATION(RC_FOREST_TEMPLE_GS_FIRST_ROOM, (logic->IsAdult && logic->CanUse(RG_BOMB_BAG)) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_BOOMERANG) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_BOMBCHU_5) || logic->CanUse(RG_DINS_FIRE) || (ctx->GetTrickOption(RT_FOREST_FIRST_GS) && (logic->CanJumpslashExceptHammer() || (logic->IsChild && logic->CanUse(RG_BOMB_BAG))))), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_ENTRYWAY, []{return true;}), + Entrance(RR_FOREST_TEMPLE_SOUTH_CORRIDOR, []{return true;}), + }); + + areaTable[RR_FOREST_TEMPLE_SOUTH_CORRIDOR] = Region("Forest Temple South Corridor", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_FOREST_TEMPLE_FIRST_ROOM, []{return true;}), + Entrance(RR_FOREST_TEMPLE_LOBBY, []{return logic->CanAttack() || logic->CanUse(RG_NUTS);}), + }); + + areaTable[RR_FOREST_TEMPLE_LOBBY] = Region("Forest Temple Lobby", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->ForestTempleMeg, []{return logic->ForestTempleMeg || (logic->ForestTempleJoelle && logic->ForestTempleBeth && logic->ForestTempleAmy && logic->CanUse(RG_FAIRY_BOW));}), + }, { + //Locations + LOCATION(RC_FOREST_TEMPLE_GS_LOBBY, logic->HookshotOrBoomerang()), + LOCATION(RC_FOREST_TEMPLE_LOBBY_POT_1, logic->CanBreakPots()), + LOCATION(RC_FOREST_TEMPLE_LOBBY_POT_2, logic->CanBreakPots()), + LOCATION(RC_FOREST_TEMPLE_LOBBY_POT_3, logic->CanBreakPots()), + LOCATION(RC_FOREST_TEMPLE_LOBBY_POT_4, logic->CanBreakPots()), + LOCATION(RC_FOREST_TEMPLE_LOBBY_POT_5, logic->CanBreakPots()), + LOCATION(RC_FOREST_TEMPLE_LOBBY_POT_6, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_SOUTH_CORRIDOR, []{return true;}), + Entrance(RR_FOREST_TEMPLE_NORTH_CORRIDOR, []{return true;}), + Entrance(RR_FOREST_TEMPLE_NW_OUTDOORS_LOWER, []{return logic->CanUse(RG_SONG_OF_TIME) || logic->IsChild;}), + Entrance(RR_FOREST_TEMPLE_NE_OUTDOORS_LOWER, []{return logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT);}), + Entrance(RR_FOREST_TEMPLE_WEST_CORRIDOR, []{return logic->SmallKeys(RR_FOREST_TEMPLE, 1, 5);}), + Entrance(RR_FOREST_TEMPLE_EAST_CORRIDOR, []{return false;}), + Entrance(RR_FOREST_TEMPLE_BOSS_REGION, []{return logic->ForestTempleMeg;}), + Entrance(RR_FOREST_TEMPLE_BOSS_ENTRYWAY, []{return false;}), + }); + + areaTable[RR_FOREST_TEMPLE_NORTH_CORRIDOR] = Region("Forest Temple North Corridor", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_FOREST_TEMPLE_LOBBY, []{return true;}), + Entrance(RR_FOREST_TEMPLE_LOWER_STALFOS, []{return true;}), + }); + + areaTable[RR_FOREST_TEMPLE_LOWER_STALFOS] = Region("Forest Temple Lower Stalfos", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->FairyPot, []{return true;}), + }, { + //Locations + LOCATION(RC_FOREST_TEMPLE_FIRST_STALFOS_CHEST, logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MEGATON_HAMMER)), + LOCATION(RC_FOREST_TEMPLE_LOWER_STALFOS_POT_1, logic->CanBreakPots()), + LOCATION(RC_FOREST_TEMPLE_LOWER_STALFOS_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_NORTH_CORRIDOR, []{return true;}), + }); + + areaTable[RR_FOREST_TEMPLE_NW_OUTDOORS_LOWER] = Region("Forest Temple NW Outdoors Lower", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->DekuBabaSticks, []{return logic->CanGetDekuBabaSticks();}), + EventAccess(&logic->DekuBabaNuts, []{return logic->CanGetDekuBabaNuts();}), + }, { + //Locations + LOCATION(RC_FOREST_TEMPLE_GS_LEVEL_ISLAND_COURTYARD, logic->CanUse(RG_LONGSHOT) || Here(RR_FOREST_TEMPLE_NW_OUTDOORS_UPPER, []{return logic->HookshotOrBoomerang();})), + LOCATION(RC_FOREST_TEMPLE_COURTYARD_RIGHT_HEART, logic->CanUse(RG_BOOMERANG) && ctx->GetTrickOption(RT_FOREST_OUTDOORS_HEARTS_BOOMERANG)), + LOCATION(RC_FOREST_TEMPLE_COURTYARD_LEFT_HEART, logic->CanUse(RG_BOOMERANG) && ctx->GetTrickOption(RT_FOREST_OUTDOORS_HEARTS_BOOMERANG)), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_LOBBY, []{return logic->CanUse(RG_SONG_OF_TIME);}), + Entrance(RR_FOREST_TEMPLE_NW_OUTDOORS_UPPER, []{return ctx->GetTrickOption(RT_HOVER_BOOST_SIMPLE) && ctx->GetTrickOption(RT_DAMAGE_BOOST_SIMPLE) && logic->HasExplosives() && logic->CanUse(RG_HOVER_BOOTS);}), + Entrance(RR_FOREST_TEMPLE_MAP_ROOM, []{return true;}), + Entrance(RR_FOREST_TEMPLE_SEWER, []{return logic->HasItem(RG_GOLDEN_SCALE) || logic->CanUse(RG_IRON_BOOTS) || HasAccessTo(RR_FOREST_TEMPLE_NE_OUTDOORS_UPPER);}), + Entrance(RR_FOREST_TEMPLE_BOSS_ENTRYWAY, []{return false;}), + }); + + areaTable[RR_FOREST_TEMPLE_NW_OUTDOORS_UPPER] = Region("Forest Temple NW Outdoors Upper", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->DekuBabaSticks, []{return logic->CanGetDekuBabaSticks();}), + EventAccess(&logic->DekuBabaNuts, []{return logic->CanGetDekuBabaNuts();}), + }, { + //Locations + LOCATION(RC_FOREST_TEMPLE_COURTYARD_RIGHT_HEART, true), + LOCATION(RC_FOREST_TEMPLE_COURTYARD_LEFT_HEART, true), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_NW_OUTDOORS_LOWER, []{return true;}), + Entrance(RR_FOREST_TEMPLE_BELOW_BOSS_KEY_CHEST, []{return true;}), + Entrance(RR_FOREST_TEMPLE_FLOORMASTER_ROOM, []{return true;}), + Entrance(RR_FOREST_TEMPLE_BLOCK_PUSH_ROOM, []{return true;}), + }); + + areaTable[RR_FOREST_TEMPLE_NE_OUTDOORS_LOWER] = Region("Forest Temple NE Outdoors Lower", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->DekuBabaSticks, []{return logic->CanGetDekuBabaSticks();}), + EventAccess(&logic->DekuBabaNuts, []{return logic->CanGetDekuBabaNuts();}), + }, { + //Locations + LOCATION(RC_FOREST_TEMPLE_RAISED_ISLAND_COURTYARD_CHEST, logic->CanUse(RG_HOOKSHOT) || HasAccessTo(RR_FOREST_TEMPLE_FALLING_ROOM) || (HasAccessTo(RR_FOREST_TEMPLE_NE_OUTDOORS_UPPER) && logic->IsAdult && ctx->GetTrickOption(RT_FOREST_OUTDOORS_LEDGE) && logic->CanUse(RG_HOVER_BOOTS))), + LOCATION(RC_FOREST_TEMPLE_GS_RAISED_ISLAND_COURTYARD, logic->CanUse(RG_HOOKSHOT) || (ctx->GetTrickOption(RT_FOREST_OUTDOORS_EAST_GS) && logic->CanUse(RG_BOOMERANG)) || Here(RR_FOREST_TEMPLE_FALLING_ROOM, []{return logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_DINS_FIRE) || logic->HasExplosives();})), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_LOBBY, []{return true;}), + Entrance(RR_FOREST_TEMPLE_NE_OUTDOORS_UPPER, []{return logic->CanUse(RG_LONGSHOT) || (ctx->GetTrickOption(RT_FOREST_VINES) && logic->CanUse(RG_HOOKSHOT));}), + Entrance(RR_FOREST_TEMPLE_SEWER, []{return logic->HasItem(RG_GOLDEN_SCALE) || logic->CanUse(RG_IRON_BOOTS) || HasAccessTo(RR_FOREST_TEMPLE_NE_OUTDOORS_UPPER);}), + Entrance(RR_FOREST_TEMPLE_FALLING_ROOM, []{return false;}), + }); + + areaTable[RR_FOREST_TEMPLE_NE_OUTDOORS_UPPER] = Region("Forest Temple NE Outdoors Upper", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->DekuBabaSticks, []{return logic->CanGetDekuBabaSticks();}), + EventAccess(&logic->DekuBabaNuts, []{return logic->CanGetDekuBabaNuts();}), + }, {}, { + //Exits + Entrance(RR_FOREST_TEMPLE_NE_OUTDOORS_LOWER, []{return true;}), + Entrance(RR_FOREST_TEMPLE_MAP_ROOM, []{return true;}), + Entrance(RR_FOREST_TEMPLE_FALLING_ROOM, []{return ctx->GetTrickOption(RT_FOREST_DOORFRAME) && logic->CanJumpslashExceptHammer() && logic->CanUse(RG_HOVER_BOOTS) && logic->CanUse(RG_SCARECROW);}), + }); + + areaTable[RR_FOREST_TEMPLE_MAP_ROOM] = Region("Forest Temple Map Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FOREST_TEMPLE_MAP_CHEST, logic->CanKillEnemy(RE_BLUE_BUBBLE)), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_NW_OUTDOORS_LOWER, []{return Here(RR_FOREST_TEMPLE_MAP_ROOM, []{return logic->CanKillEnemy(RE_BLUE_BUBBLE);});}), + Entrance(RR_FOREST_TEMPLE_NE_OUTDOORS_UPPER, []{return Here(RR_FOREST_TEMPLE_MAP_ROOM, []{return logic->CanKillEnemy(RE_BLUE_BUBBLE);});}), + }); + + areaTable[RR_FOREST_TEMPLE_SEWER] = Region("Forest Temple Sewer", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FOREST_TEMPLE_WELL_CHEST, HasAccessTo(RR_FOREST_TEMPLE_NE_OUTDOORS_UPPER)), + LOCATION(RC_FOREST_TEMPLE_WELL_WEST_HEART, HasAccessTo(RR_FOREST_TEMPLE_NE_OUTDOORS_UPPER) || (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8)), + LOCATION(RC_FOREST_TEMPLE_WELL_EAST_HEART, HasAccessTo(RR_FOREST_TEMPLE_NE_OUTDOORS_UPPER) || (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8)), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_NW_OUTDOORS_LOWER, []{return true;}), + Entrance(RR_FOREST_TEMPLE_NE_OUTDOORS_LOWER, []{return true;}), + }); + + areaTable[RR_FOREST_TEMPLE_BELOW_BOSS_KEY_CHEST] = Region("Forest Temple Below Boss Key Chest", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_FOREST_TEMPLE_NW_OUTDOORS_UPPER, []{return Here(RR_FOREST_TEMPLE_BELOW_BOSS_KEY_CHEST, []{return logic->CanKillEnemy(RE_BLUE_BUBBLE);});}), + }); + + areaTable[RR_FOREST_TEMPLE_FLOORMASTER_ROOM] = Region("Forest Temple Floormaster Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FOREST_TEMPLE_FLOORMASTER_CHEST, logic->CanDamage()), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_NW_OUTDOORS_UPPER, []{return true;}), + }); + + areaTable[RR_FOREST_TEMPLE_WEST_CORRIDOR] = Region("Forest Temple West Corridor", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_FOREST_TEMPLE_LOBBY, []{return logic->SmallKeys(RR_FOREST_TEMPLE, 1, 5);}), + Entrance(RR_FOREST_TEMPLE_BLOCK_PUSH_ROOM, []{return logic->CanAttack() || logic->CanUse(RG_NUTS);}), + }); + + areaTable[RR_FOREST_TEMPLE_BLOCK_PUSH_ROOM] = Region("Forest Temple Block Push Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FOREST_TEMPLE_EYE_SWITCH_CHEST, logic->HasItem(RG_GORONS_BRACELET) && (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT))), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_WEST_CORRIDOR, []{return true;}), + Entrance(RR_FOREST_TEMPLE_NW_OUTDOORS_UPPER, []{return logic->CanUse(RG_HOVER_BOOTS) || (ctx->GetTrickOption(RT_FOREST_OUTSIDE_BACKDOOR) && logic->CanJumpslashExceptHammer() && logic->HasItem(RG_GORONS_BRACELET));}), + Entrance(RR_FOREST_TEMPLE_NW_CORRIDOR_TWISTED, []{return logic->IsAdult && logic->HasItem(RG_GORONS_BRACELET) && logic->SmallKeys(RR_FOREST_TEMPLE, 2);}), + Entrance(RR_FOREST_TEMPLE_NW_CORRIDOR_STRAIGHTENED, []{return logic->IsAdult && (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT)) && logic->HasItem(RG_GORONS_BRACELET) && logic->SmallKeys(RR_FOREST_TEMPLE, 2);}), + }); + + areaTable[RR_FOREST_TEMPLE_NW_CORRIDOR_TWISTED] = Region("Forest Temple NW Corridor Twisted", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_FOREST_TEMPLE_BLOCK_PUSH_ROOM, []{return logic->SmallKeys(RR_FOREST_TEMPLE, 2);}), + Entrance(RR_FOREST_TEMPLE_RED_POE_ROOM, []{return logic->SmallKeys(RR_FOREST_TEMPLE, 3);}), + }); + + areaTable[RR_FOREST_TEMPLE_NW_CORRIDOR_STRAIGHTENED] = Region("Forest Temple NW Corridor Straightened", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FOREST_TEMPLE_BOSS_KEY_CHEST, true), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_BELOW_BOSS_KEY_CHEST, []{return true;}), + Entrance(RR_FOREST_TEMPLE_BLOCK_PUSH_ROOM, []{return logic->SmallKeys(RR_FOREST_TEMPLE, 2);}), + }); + + areaTable[RR_FOREST_TEMPLE_RED_POE_ROOM] = Region("Forest Temple Red Poe Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->ForestTempleJoelle, []{return logic->ForestTempleJoelle || logic->CanUse(RG_FAIRY_BOW);}), + }, { + //Locations + LOCATION(RC_FOREST_TEMPLE_RED_POE_CHEST, logic->ForestTempleJoelle), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_NW_CORRIDOR_TWISTED, []{return logic->SmallKeys(RR_FOREST_TEMPLE, 3);}), + Entrance(RR_FOREST_TEMPLE_UPPER_STALFOS, []{return true;}), + }); + + areaTable[RR_FOREST_TEMPLE_UPPER_STALFOS] = Region("Forest Temple Upper Stalfos", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FOREST_TEMPLE_BOW_CHEST, logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MEGATON_HAMMER)), + LOCATION(RC_FOREST_TEMPLE_UPPER_STALFOS_POT_1, logic->CanBreakPots()), + LOCATION(RC_FOREST_TEMPLE_UPPER_STALFOS_POT_2, logic->CanBreakPots()), + LOCATION(RC_FOREST_TEMPLE_UPPER_STALFOS_POT_3, logic->CanBreakPots()), + LOCATION(RC_FOREST_TEMPLE_UPPER_STALFOS_POT_4, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_RED_POE_ROOM, []{return logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MEGATON_HAMMER);}), + Entrance(RR_FOREST_TEMPLE_BLUE_POE_ROOM, []{return logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MEGATON_HAMMER);}), + }); + + areaTable[RR_FOREST_TEMPLE_BLUE_POE_ROOM] = Region("Forest Temple Blue Poe Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->ForestTempleBeth, []{return logic->ForestTempleBeth || logic->CanUse(RG_FAIRY_BOW);}), + }, { + //Locations + LOCATION(RC_FOREST_TEMPLE_BLUE_POE_CHEST, logic->ForestTempleBeth), + LOCATION(RC_FOREST_TEMPLE_BLUE_POE_POT_1, logic->CanBreakPots()), + LOCATION(RC_FOREST_TEMPLE_BLUE_POE_POT_2, logic->CanBreakPots()), + LOCATION(RC_FOREST_TEMPLE_BLUE_POE_POT_3, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_UPPER_STALFOS, []{return true;}), + Entrance(RR_FOREST_TEMPLE_NE_CORRIDOR_STRAIGHTENED, []{return logic->SmallKeys(RR_FOREST_TEMPLE, 4);}), + }); + + areaTable[RR_FOREST_TEMPLE_NE_CORRIDOR_STRAIGHTENED] = Region("Forest Temple NE Corridor Straightened", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_FOREST_TEMPLE_BLUE_POE_ROOM, []{return logic->SmallKeys(RR_FOREST_TEMPLE, 4);}), + Entrance(RR_FOREST_TEMPLE_FROZEN_EYE_ROOM, []{return logic->SmallKeys(RR_FOREST_TEMPLE, 5);}), + }); + + areaTable[RR_FOREST_TEMPLE_NE_CORRIDOR_TWISTED] = Region("Forest Temple NE Corridor Twisted", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_FOREST_TEMPLE_FROZEN_EYE_ROOM, []{return logic->SmallKeys(RR_FOREST_TEMPLE, 5);}), + Entrance(RR_FOREST_TEMPLE_FALLING_ROOM, []{return true;}), + }); + + areaTable[RR_FOREST_TEMPLE_FROZEN_EYE_ROOM] = Region("Forest Temple Frozen Eye Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FOREST_TEMPLE_FROZEN_EYE_POT_1, logic->CanBreakPots()), + LOCATION(RC_FOREST_TEMPLE_FROZEN_EYE_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_NE_CORRIDOR_STRAIGHTENED, []{return logic->SmallKeys(RR_FOREST_TEMPLE, 5);}), + Entrance(RR_FOREST_TEMPLE_NE_CORRIDOR_TWISTED, []{return logic->SmallKeys(RR_FOREST_TEMPLE, 5) && (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_DINS_FIRE));}), + }); + + areaTable[RR_FOREST_TEMPLE_FALLING_ROOM] = Region("Forest Temple Falling Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FOREST_TEMPLE_FALLING_CEILING_ROOM_CHEST, true), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_NE_OUTDOORS_LOWER, []{return true;}), + Entrance(RR_FOREST_TEMPLE_GREEN_POE_ROOM, []{return true;}), + }); + + areaTable[RR_FOREST_TEMPLE_GREEN_POE_ROOM] = Region("Forest Temple Green Poe Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->ForestTempleAmy, []{return logic->ForestTempleAmy || logic->CanUse(RG_FAIRY_BOW);}), + }, { + //Locations + LOCATION(RC_FOREST_TEMPLE_GREEN_POE_POT_1, logic->CanBreakPots()), + LOCATION(RC_FOREST_TEMPLE_GREEN_POE_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_FALLING_ROOM, []{return true;}), + Entrance(RR_FOREST_TEMPLE_EAST_CORRIDOR, []{return logic->ForestTempleAmy;}), + }); + + areaTable[RR_FOREST_TEMPLE_EAST_CORRIDOR] = Region("Forest Temple East Corridor", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_FOREST_TEMPLE_LOBBY, []{return logic->CanAttack() || logic->CanUse(RG_NUTS);}), + Entrance(RR_FOREST_TEMPLE_GREEN_POE_ROOM, []{return logic->CanAttack() || logic->CanUse(RG_NUTS);}), + }); + + areaTable[RR_FOREST_TEMPLE_BOSS_REGION] = Region("Forest Temple Boss Region", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FOREST_TEMPLE_BASEMENT_CHEST, true), + LOCATION(RC_FOREST_TEMPLE_GS_BASEMENT, logic->HookshotOrBoomerang()), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_LOBBY, []{return true;}), + Entrance(RR_FOREST_TEMPLE_BOSS_ENTRYWAY, []{return logic->HasItem(RG_FOREST_TEMPLE_BOSS_KEY);}), + }); + +#pragma endregion + +#pragma region MQ + + areaTable[RR_FOREST_TEMPLE_MQ_LOBBY] = Region("Forest Temple MQ Lobby", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FOREST_TEMPLE_MQ_FIRST_ROOM_CHEST, logic->CanPassEnemy(RE_BIG_SKULLTULA, ED_SHORT_JUMPSLASH, false) || logic->CanUse(RG_HOVER_BOOTS)), + //Implies CanPassEnemy(RE_BIG_SKULLTULA) + LOCATION(RC_FOREST_TEMPLE_MQ_GS_FIRST_HALLWAY, logic->HookshotOrBoomerang()), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_ENTRYWAY, []{return true;}), + Entrance(RR_FOREST_TEMPLE_MQ_CENTRAL_AREA, []{return logic->SmallKeys(RR_FOREST_TEMPLE, 1) && logic->CanPassEnemy(RE_BIG_SKULLTULA);}), + }); + + areaTable[RR_FOREST_TEMPLE_MQ_CENTRAL_AREA] = Region("Forest Temple MQ Central Region", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->ForestTempleMeg, []{return logic->ForestTempleJoelle && logic->ForestTempleBeth && logic->ForestTempleAmy && logic->CanKillEnemy(RE_MEG);}), + }, { + //Locations + LOCATION(RC_FOREST_TEMPLE_MQ_LOBBY_POT_1, logic->CanBreakPots()), + LOCATION(RC_FOREST_TEMPLE_MQ_LOBBY_POT_2, logic->CanBreakPots()), + LOCATION(RC_FOREST_TEMPLE_MQ_LOBBY_POT_3, logic->CanBreakPots()), + LOCATION(RC_FOREST_TEMPLE_MQ_LOBBY_POT_4, logic->CanBreakPots()), + LOCATION(RC_FOREST_TEMPLE_MQ_LOBBY_POT_5, logic->CanBreakPots()), + LOCATION(RC_FOREST_TEMPLE_MQ_LOBBY_POT_6, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_MQ_WOLFOS_ROOM, []{return logic->IsChild || logic->CanUse(RG_SONG_OF_TIME);}), + Entrance(RR_FOREST_TEMPLE_MQ_NW_OUTDOORS, []{return logic->CanHitEyeTargets();}), + Entrance(RR_FOREST_TEMPLE_MQ_NE_OUTDOORS, []{return logic->CanHitEyeTargets();}), + Entrance(RR_FOREST_TEMPLE_MQ_LOWER_BLOCK_PUZZLE, []{return Here(RR_FOREST_TEMPLE_MQ_CENTRAL_AREA, []{return logic->CanKillEnemy(RE_STALFOS);});}), + //implies the other 3 poes + Entrance(RR_FOREST_TEMPLE_MQ_BASEMENT, []{return logic->ForestTempleMeg;}), + }); + + areaTable[RR_FOREST_TEMPLE_MQ_WOLFOS_ROOM] = Region("Forest Temple MQ Wolfos Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->FairyPot, []{return true;}), + EventAccess(&logic->ForestClearBelowBowChest, []{return logic->CanKillEnemy(RE_WOLFOS);}), + }, { + //Locations + LOCATION(RC_FOREST_TEMPLE_MQ_WOLFOS_CHEST, logic->ForestClearBelowBowChest), + LOCATION(RC_FOREST_TEMPLE_MQ_WOLFOS_POT_1, logic->CanBreakPots()), + LOCATION(RC_FOREST_TEMPLE_MQ_WOLFOS_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_MQ_CENTRAL_AREA, []{return logic->ForestClearBelowBowChest && (logic->IsChild || logic->CanUse(RG_SONG_OF_TIME));}), + }); + + areaTable[RR_FOREST_TEMPLE_MQ_LOWER_BLOCK_PUZZLE] = Region("Forest Temple MQ Lower Block Puzzle", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //longshot is capable of hitting the switch, but some invisible collision makes the shot harder than you would think, so it may be trickworthy + EventAccess(&logic->MQForestBlockRoomTargets, []{return (ctx->GetTrickOption(RT_FOREST_MQ_BLOCK_PUZZLE) && logic->CanUse(RG_BOMBCHU_5));}), + //It is barely possible to get this as child with master + hovers, but it's tight without bunny speed + EventAccess(&logic->ForestCanTwistHallway, []{return (ctx->GetTrickOption(RT_FOREST_MQ_JS_HALLWAY_SWITCH) && logic->CanUse(RG_HOVER_BOOTS) && (logic->IsAdult && logic->CanJumpslash()) || (logic->CanUse(RG_STICKS) || logic->CanUse(RG_BIGGORON_SWORD) || (logic->MQForestBlockRoomTargets && logic->CanUse(RG_MASTER_SWORD)))) || (ctx->GetTrickOption(RT_FOREST_MQ_RANG_HALLWAY_SWITCH) && logic->CanUse(RG_BOOMERANG)) || (ctx->GetTrickOption(RT_FOREST_MQ_HOOKSHOT_HALLWAY_SWITCH) && logic->CanUse(RG_HOOKSHOT));}), + }, { + //Locations + LOCATION(RC_FOREST_TEMPLE_MQ_GS_BLOCK_PUSH_ROOM, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_MQ_CENTRAL_AREA, []{return Here(RR_FOREST_TEMPLE_MQ_CENTRAL_AREA, []{return logic->CanKillEnemy(RE_STALFOS);});}), + Entrance(RR_FOREST_TEMPLE_MQ_MIDDLE_BLOCK_PUZZLE, []{return logic->HasItem(RG_GORONS_BRACELET) || (logic->MQForestBlockRoomTargets && logic->CanUse(RG_HOOKSHOT));}), + //Assumes RR_FOREST_TEMPLE_MQ_MIDDLE_BLOCK_PUZZLE access + Entrance(RR_FOREST_TEMPLE_MQ_UPPER_BLOCK_PUZZLE, []{return (logic->IsAdult && logic->HasItem(RG_GORONS_BRACELET)) || (logic->MQForestBlockRoomTargets && logic->CanUse(RG_HOOKSHOT));}), + Entrance(RR_FOREST_TEMPLE_MQ_OUTDOOR_LEDGE, []{return logic->ForestCanTwistHallway && (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS));}), + }); + + areaTable[RR_FOREST_TEMPLE_MQ_MIDDLE_BLOCK_PUZZLE] = Region("Forest Temple MQ Middle Block Puzzle", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //longshot is capable of hitting the switch, but some invisible collision makes the shot more annoying than you would think, so it may be trickworthy + EventAccess(&logic->MQForestBlockRoomTargets, []{return (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_LONGSHOT));}), + EventAccess(&logic->ForestCanTwistHallway, []{return ctx->GetTrickOption(RT_FOREST_MQ_JS_HALLWAY_SWITCH) && (logic->IsAdult && logic->CanJumpslash()) || (logic->CanUse(RG_HOVER_BOOTS) && (logic->CanUse(RG_STICKS) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MASTER_SWORD)));}), + }, {}, { + //Exits + Entrance(RR_FOREST_TEMPLE_MQ_LOWER_BLOCK_PUZZLE, []{return true;}), + Entrance(RR_FOREST_TEMPLE_MQ_UPPER_BLOCK_PUZZLE, []{return (logic->IsAdult && logic->HasItem(RG_GORONS_BRACELET)) || (logic->MQForestBlockRoomTargets && logic->CanUse(RG_HOOKSHOT));}), + //Hammer cannot recoil from here, but can make the jump forwards with a hammer jumpslash as adult + Entrance(RR_FOREST_TEMPLE_MQ_OUTDOOR_LEDGE, []{return logic->ForestCanTwistHallway && logic->CanUse(RG_HOVER_BOOTS) || (ctx->GetTrickOption(RT_FOREST_OUTSIDE_BACKDOOR) && (logic->CanJumpslashExceptHammer() || (logic->IsAdult && logic->CanUse(RG_MEGATON_HAMMER))));}), + }); + + areaTable[RR_FOREST_TEMPLE_MQ_UPPER_BLOCK_PUZZLE] = Region("Forest Temple MQ After Block Puzzle", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FOREST_TEMPLE_MQ_BOSS_KEY_CHEST, logic->SmallKeys(RR_FOREST_TEMPLE, 3)), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_MQ_STRAIGHT_HALLWAY, []{return logic->SmallKeys(RR_FOREST_TEMPLE, 3);}), + Entrance(RR_FOREST_TEMPLE_MQ_JOELLE_ROOM, []{return logic->ForestCanTwistHallway && logic->SmallKeys(RR_FOREST_TEMPLE, 4);}), + //!QUANTUM LOGIC! + //As there is no way in default logic to reach the other possible key use without going through RR_FOREST_TEMPLE_MQ_NW_OUTDOORS, this is logically safe for now + //Breaks if there's any other way to RR_FOREST_TEMPLE_MQ_FALLING_ROOM than going through the eye targets in RR_FOREST_TEMPLE_MQ_CENTRAL_AREA + //Requires a bow/sling ammo source once ammo logic is done, to avoid edge cases. + Entrance(RR_FOREST_TEMPLE_MQ_NW_OUTDOORS, []{return logic->SmallKeys(RR_FOREST_TEMPLE, 2) && Here(RR_FOREST_TEMPLE_MQ_UPPER_BLOCK_PUZZLE, []{return logic->CanKillEnemy(RE_FLOORMASTER);});}), + }); + + areaTable[RR_FOREST_TEMPLE_MQ_STRAIGHT_HALLWAY] = Region("Forest Temple MQ Straight Hallway", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FOREST_TEMPLE_MQ_BOSS_KEY_CHEST, logic->SmallKeys(RR_FOREST_TEMPLE, 3)), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_MQ_FLOORMASTER_ROOM, []{return true;}), + }); + + areaTable[RR_FOREST_TEMPLE_MQ_FLOORMASTER_ROOM] = Region("Forest Temple MQ Floormaster Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_FOREST_TEMPLE_MQ_OUTDOOR_LEDGE, []{return Here(RR_FOREST_TEMPLE_MQ_FLOORMASTER_ROOM, []{return logic->CanKillEnemy(RE_FLOORMASTER);});}), + }); + + areaTable[RR_FOREST_TEMPLE_MQ_OUTDOOR_LEDGE] = Region("Forest Temple MQ Outdoor Ledge", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + EventAccess(&logic->ForestCanTwistHallway, []{return logic->CanHitSwitch();}), + }, { + //Locations + LOCATION(RC_FOREST_TEMPLE_MQ_REDEAD_CHEST, logic->CanKillEnemy(RE_REDEAD)), + LOCATION(RC_FOREST_TEMPLE_MQ_COURTYARD_RIGHT_HEART, true), + LOCATION(RC_FOREST_TEMPLE_MQ_COURTYARD_MIDDLE_HEART, true), + LOCATION(RC_FOREST_TEMPLE_MQ_COURTYARD_LEFT_HEART, true), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_MQ_NW_OUTDOORS, []{return true;}), + }); + + areaTable[RR_FOREST_TEMPLE_MQ_NW_OUTDOORS] = Region("Forest Temple MQ NW Outdoors", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FOREST_TEMPLE_MQ_GS_LEVEL_ISLAND_COURTYARD, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)), + //the well checks are considered from both areas instead of being a region because the draining is a temp flag and the skull (as well as the chest with hook glitch) has different breath timers from each side + LOCATION(RC_FOREST_TEMPLE_MQ_GS_WELL, (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8 && logic->CanUse(RG_HOOKSHOT))), + LOCATION(RC_FOREST_TEMPLE_MQ_COURTYARD_RIGHT_HEART, logic->CanUse(RG_BOOMERANG) && ctx->GetTrickOption(RT_FOREST_OUTDOORS_HEARTS_BOOMERANG)), + LOCATION(RC_FOREST_TEMPLE_MQ_COURTYARD_MIDDLE_HEART, logic->CanUse(RG_BOOMERANG) && ctx->GetTrickOption(RT_FOREST_OUTDOORS_HEARTS_BOOMERANG)), + LOCATION(RC_FOREST_TEMPLE_MQ_COURTYARD_LEFT_HEART, logic->CanUse(RG_BOOMERANG) && ctx->GetTrickOption(RT_FOREST_OUTDOORS_HEARTS_BOOMERANG)), + LOCATION(RC_FOREST_TEMPLE_MQ_WELL_WEST_HEART, logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8), + LOCATION(RC_FOREST_TEMPLE_MQ_WELL_MIDDLE_HEART, logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8), + LOCATION(RC_FOREST_TEMPLE_MQ_WELL_EAST_HEART, logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_MQ_NE_OUTDOORS, []{return (((logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_LONGSHOT) || (ctx->GetTrickOption(RT_FOREST_MQ_WELL_SWIM) && logic->CanUse(RG_HOOKSHOT))) && logic->HasItem(RG_BRONZE_SCALE)) || logic->HasItem(RG_GOLDEN_SCALE)) && logic->WaterTimer() >= 16;}), + Entrance(RR_FOREST_TEMPLE_MQ_OUTDOORS_TOP_LEDGES, []{return logic->CanUse(RG_FIRE_ARROWS);}), + }); + + //The well only coniders the eye target here because the eye target is a temp flag, making it unwieldy to use as an EventAccess to make it it's own room + areaTable[RR_FOREST_TEMPLE_MQ_NE_OUTDOORS] = Region("Forest Temple MQ NE Outdoors", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->DekuBabaSticks, []{return logic->CanGetDekuBabaSticks();}), + EventAccess(&logic->DekuBabaNuts, []{return logic->CanGetDekuBabaNuts();}), + }, { + //Locations + LOCATION(RC_FOREST_TEMPLE_MQ_WELL_CHEST, logic->CanHitEyeTargets()), + LOCATION(RC_FOREST_TEMPLE_MQ_GS_RAISED_ISLAND_COURTYARD, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)), + //implies logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA) + LOCATION(RC_FOREST_TEMPLE_MQ_GS_WELL, logic->CanHitEyeTargets() || (logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT))), + LOCATION(RC_FOREST_TEMPLE_MQ_WELL_WEST_HEART, (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8) || logic->CanHitEyeTargets()), + LOCATION(RC_FOREST_TEMPLE_MQ_WELL_MIDDLE_HEART, (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8) || logic->CanHitEyeTargets()), + LOCATION(RC_FOREST_TEMPLE_MQ_WELL_EAST_HEART, (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8) || logic->CanHitEyeTargets()), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_MQ_NW_OUTDOORS, []{return (((logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_LONGSHOT)) && logic->HasItem(RG_BRONZE_SCALE)) || logic->HasItem(RG_GOLDEN_SCALE)) && logic->WaterTimer() >= 16;}), + Entrance(RR_FOREST_TEMPLE_MQ_OUTDOORS_TOP_LEDGES, []{return logic->CanUse(RG_LONGSHOT) || (logic->CanUse(RG_HOOKSHOT) && ((logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)) || logic->CanUse(RG_SONG_OF_TIME)));}), + Entrance(RR_FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE, []{return logic->CanUse(RG_LONGSHOT);}), + }); + + areaTable[RR_FOREST_TEMPLE_MQ_OUTDOORS_TOP_LEDGES] = Region("Forest Temple MQ Outdoors Top Ledges", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_UPPER_CHEST, true), + //Actually killing the skull from the doorframe with melee is annoying. Hammer swing hits low enough unaided, other swords need to crouch stab but the spot is precise based on range. kokiri sword doesn't reach at all for adult. + LOCATION(RC_FOREST_TEMPLE_MQ_GS_RAISED_ISLAND_COURTYARD, ((logic->IsAdult && logic->CanUse(RG_SONG_OF_TIME)) || (logic->CanUse(RG_HOVER_BOOTS) && ctx->GetTrickOption(RT_FOREST_DOORFRAME))) && logic->CanJumpslash() && (logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->BlastOrSmash() || logic->CanUse(RG_DINS_FIRE) || logic->CanUse(RG_FAIRY_BOW) || logic->HookshotOrBoomerang() || (logic->CanStandingShield() && (logic->CanUse(RG_STICKS) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MASTER_SWORD) || (logic->IsChild && logic->CanUse(RG_KOKIRI_SWORD)))))), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_MQ_NW_OUTDOORS, []{return logic->HasFireSourceWithTorch();}), + Entrance(RR_FOREST_TEMPLE_MQ_NE_OUTDOORS, []{return true;}), + //N64 logic doesn't check damage but I always take some so I'm adding it + Entrance(RR_FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE, []{return ctx->GetTrickOption(RT_FOREST_OUTDOORS_LEDGE) && logic->CanUse(RG_HOVER_BOOTS) && logic->CanJumpslash() && logic->TakeDamage();}), + }); + + areaTable[RR_FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE] = Region("Forest Temple MQ NE Outdoors Ledge", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FOREST_TEMPLE_MQ_RAISED_ISLAND_COURTYARD_LOWER_CHEST, true), + }, { + //Exits + //Skipping swim here is non-trival, needs a roll-jump. If a swim lock is added it's probably wise to copy deku baba events here + Entrance(RR_FOREST_TEMPLE_MQ_NE_OUTDOORS, []{return true;}), + Entrance(RR_FOREST_TEMPLE_MQ_FALLING_ROOM, []{return logic->CanUse(RG_SONG_OF_TIME);}), + }); + + areaTable[RR_FOREST_TEMPLE_MQ_JOELLE_ROOM] = Region("Forest Temple MQ Joelle room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->ForestTempleJoelle, []{return logic->CanUse(RG_FAIRY_BOW);}), + }, { + //Locations + LOCATION(RC_FOREST_TEMPLE_MQ_MAP_CHEST, logic->ForestTempleJoelle), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_MQ_UPPER_BLOCK_PUZZLE, []{return logic->SmallKeys(RR_FOREST_TEMPLE, 4);}), + Entrance(RR_FOREST_TEMPLE_MQ_3_STALFOS_ROOM, []{return true;}), + }); + + areaTable[RR_FOREST_TEMPLE_MQ_3_STALFOS_ROOM] = Region("Forest Temple MQ 3 Stalfos Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + //technically happens in RR_FOREST_TEMPLE_MQ_WOLFOS_ROOM, but the way this room blocks the hole means it cannot be logical to do anything else there. + EventAccess(&logic->ForestClearBelowBowChest, []{return logic->CanKillEnemy(RE_WOLFOS);}), + }, { + //Locations + LOCATION(RC_FOREST_TEMPLE_MQ_BOW_CHEST, logic->ForestClearBelowBowChest && logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 3)), + LOCATION(RC_FOREST_TEMPLE_MQ_UPPER_STALFOS_POT_1, logic->CanBreakPots()), + LOCATION(RC_FOREST_TEMPLE_MQ_UPPER_STALFOS_POT_2, logic->CanBreakPots()), + LOCATION(RC_FOREST_TEMPLE_MQ_UPPER_STALFOS_POT_3, logic->CanBreakPots()), + LOCATION(RC_FOREST_TEMPLE_MQ_UPPER_STALFOS_POT_4, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_MQ_JOELLE_ROOM, []{return logic->ForestClearBelowBowChest && logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 3);}), + Entrance(RR_FOREST_TEMPLE_MQ_BETH_ROOM, []{return logic->ForestClearBelowBowChest && logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 3);}), + }); + + areaTable[RR_FOREST_TEMPLE_MQ_BETH_ROOM] = Region("Forest Temple MQ Beth Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->ForestTempleBeth, []{return logic->CanUse(RG_FAIRY_BOW);}), + }, { + //Locations + LOCATION(RC_FOREST_TEMPLE_MQ_COMPASS_CHEST, logic->ForestTempleBeth), + LOCATION(RC_FOREST_TEMPLE_MQ_BLUE_POE_POT_1, logic->CanBreakPots()), + LOCATION(RC_FOREST_TEMPLE_MQ_BLUE_POE_POT_2, logic->CanBreakPots()), + LOCATION(RC_FOREST_TEMPLE_MQ_BLUE_POE_POT_3, logic->CanBreakPots()), + }, { + //Exits + //!QUANTUM LOGIC! + //This key logic assumes that you can get to falling room either by spending the 5th key here, or by wasting a key in falling room itself. + //While being the 5th key makes this simpler in theory, if a different age can waste the key compared to reaching this room it breaks + Entrance(RR_FOREST_TEMPLE_MQ_FALLING_ROOM, []{return logic->SmallKeys(RR_FOREST_TEMPLE, 5) && Here(RR_FOREST_TEMPLE_MQ_BETH_ROOM, []{return logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_DINS_FIRE);});}), + Entrance(RR_FOREST_TEMPLE_MQ_TORCH_SHOT_ROOM, []{return logic->SmallKeys(RR_FOREST_TEMPLE, 6);}), + Entrance(RR_FOREST_TEMPLE_MQ_3_STALFOS_ROOM, []{return true;}), + }); + + //This room exists to show the actual map layout, and for when the crates get added to logic + areaTable[RR_FOREST_TEMPLE_MQ_TORCH_SHOT_ROOM] = Region("Forest Temple MQ Torch Shot Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_FOREST_TEMPLE_MQ_FALLING_ROOM, []{return logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_DINS_FIRE);}), + Entrance(RR_FOREST_TEMPLE_MQ_BETH_ROOM, []{return logic->SmallKeys(RR_FOREST_TEMPLE, 6);}), + }); + + areaTable[RR_FOREST_TEMPLE_MQ_FALLING_ROOM] = Region("Forest Temple MQ Falling Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FOREST_TEMPLE_MQ_FALLING_CEILING_ROOM_CHEST, true), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_MQ_NE_OUTDOORS_LEDGE, []{return true;}), + Entrance(RR_FOREST_TEMPLE_MQ_AMY_ROOM, []{return logic->SmallKeys(RR_FOREST_TEMPLE, 6);}), + }); + + areaTable[RR_FOREST_TEMPLE_MQ_AMY_ROOM] = Region("Forest Temple MQ Amy Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->ForestTempleAmy, []{return logic->CanUse(RG_FAIRY_BOW);}), + }, { + //Locations + LOCATION(RC_FOREST_TEMPLE_MQ_GREEN_POE_POT_1, logic->CanBreakPots()), + LOCATION(RC_FOREST_TEMPLE_MQ_GREEN_POE_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_MQ_CENTRAL_AREA, []{return logic->ForestTempleAmy;}), + Entrance(RR_FOREST_TEMPLE_MQ_FALLING_ROOM, []{return true;}), + }); + + areaTable[RR_FOREST_TEMPLE_MQ_BASEMENT] = Region("Forest Temple MQ Basement", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + //Implies CanHitSwitch() + EventAccess(&logic->ForestOpenBossCorridor, []{return logic->CanHitEyeTargets();}), + }, { + //Locations + LOCATION(RC_FOREST_TEMPLE_MQ_BASEMENT_CHEST, true), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_MQ_CENTRAL_AREA, []{return logic->ForestTempleMeg;}), + Entrance(RR_FOREST_TEMPLE_MQ_BASEMENT_POT_ROOM, []{return logic->CanPassEnemy(RE_BIG_SKULLTULA) || logic->TakeDamage();}), + Entrance(RR_FOREST_TEMPLE_MQ_BOSS_REGION, []{return logic->ForestOpenBossCorridor;}), + }); + + areaTable[RR_FOREST_TEMPLE_MQ_BASEMENT_POT_ROOM] = Region("Forest Temple MQ Basement Pot Room", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_FOREST_TEMPLE_MQ_BASEMENT_POT_1, logic->CanBreakPots()), + LOCATION(RC_FOREST_TEMPLE_MQ_BASEMENT_POT_2, logic->CanBreakPots()), + LOCATION(RC_FOREST_TEMPLE_MQ_BASEMENT_POT_3, logic->CanBreakPots()), + LOCATION(RC_FOREST_TEMPLE_MQ_BASEMENT_POT_4, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_FOREST_TEMPLE_MQ_BASEMENT, []{return logic->CanPassEnemy(RE_BIG_SKULLTULA);}), + }); + + areaTable[RR_FOREST_TEMPLE_MQ_BOSS_REGION] = Region("Forest Temple MQ Boss Region", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_FOREST_TEMPLE_MQ_BASEMENT, []{return logic->ForestOpenBossCorridor;}), + Entrance(RR_FOREST_TEMPLE_BOSS_ENTRYWAY, []{return logic->HasItem(RG_FOREST_TEMPLE_BOSS_KEY);}), + }); + +#pragma endregion + + // Boss Room + areaTable[RR_FOREST_TEMPLE_BOSS_ENTRYWAY] = Region("Forest Temple Boss Entryway", "Forest Temple", {RA_FOREST_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + // Exits + Entrance(RR_FOREST_TEMPLE_BOSS_REGION, []{return ctx->GetDungeon(FOREST_TEMPLE)->IsVanilla() && false;}), + Entrance(RR_FOREST_TEMPLE_MQ_BOSS_REGION, []{return ctx->GetDungeon(FOREST_TEMPLE)->IsMQ() && false;}), + Entrance(RR_FOREST_TEMPLE_BOSS_ROOM, []{return true;}), + }); + + areaTable[RR_FOREST_TEMPLE_BOSS_ROOM] = Region("Forest Temple Boss Room", "Forest Temple", {}, NO_DAY_NIGHT_CYCLE, { + // Events + EventAccess(&logic->ForestTempleClear, []{return logic->ForestTempleClear || (logic->HasBossSoul(RG_PHANTOM_GANON_SOUL) && ((logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD)) && (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT))));}), + }, { + // Locations + LOCATION(RC_FOREST_TEMPLE_PHANTOM_GANON_HEART, logic->ForestTempleClear), + LOCATION(RC_PHANTOM_GANON, logic->ForestTempleClear), + }, { + // Exits + Entrance(RR_FOREST_TEMPLE_BOSS_ENTRYWAY, []{return false;}), + Entrance(RR_SACRED_FOREST_MEADOW, []{return logic->ForestTempleClear;}, false), + }); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/ganons_castle.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/ganons_castle.cpp new file mode 100644 index 000000000..2a7301701 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/ganons_castle.cpp @@ -0,0 +1,507 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" +#include "soh/Enhancements/randomizer/dungeon.h" +#include "soh/Enhancements/randomizer/trial.h" + +using namespace Rando; + +void RegionTable_Init_GanonsCastle() { + // Vanilla/MQ Decider + areaTable[RR_GANONS_CASTLE_ENTRYWAY] = Region("Ganon's Castle Entryway", "Ganon's Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_GANONS_CASTLE_LOBBY, []{return ctx->GetDungeon(GANONS_CASTLE)->IsVanilla();}), + Entrance(RR_GANONS_CASTLE_MQ_LOBBY, []{return ctx->GetDungeon(GANONS_CASTLE)->IsMQ();}), + Entrance(RR_CASTLE_GROUNDS_FROM_GANONS_CASTLE, []{return true;}), + }); + +#pragma region Vanilla + + areaTable[RR_GANONS_CASTLE_LOBBY] = Region("Ganon's Castle Lobby", "Ganon's Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SHEIK_HINT_GC, true), + }, { + //Exits + Entrance(RR_GANONS_CASTLE_ENTRYWAY, []{return true;}), + Entrance(RR_GANONS_CASTLE_FOREST_TRIAL, []{return true;}), + Entrance(RR_GANONS_CASTLE_FIRE_TRIAL, []{return true;}), + Entrance(RR_GANONS_CASTLE_WATER_TRIAL, []{return true;}), + Entrance(RR_GANONS_CASTLE_SHADOW_TRIAL, []{return true;}), + Entrance(RR_GANONS_CASTLE_SPIRIT_TRIAL, []{return true;}), + Entrance(RR_GANONS_CASTLE_LIGHT_TRIAL, []{return logic->CanUse(RG_GOLDEN_GAUNTLETS);}), + Entrance(RR_GANONS_TOWER_FLOOR_1, []{return (logic->ForestTrialClear || ctx->GetTrial(TK_FOREST_TRIAL)->IsSkipped()) && + (logic->FireTrialClear || ctx->GetTrial(TK_FIRE_TRIAL)->IsSkipped()) && + (logic->WaterTrialClear || ctx->GetTrial(TK_WATER_TRIAL)->IsSkipped()) && + (logic->ShadowTrialClear || ctx->GetTrial(TK_SHADOW_TRIAL)->IsSkipped()) && + (logic->SpiritTrialClear || ctx->GetTrial(TK_SPIRIT_TRIAL)->IsSkipped()) && + (logic->LightTrialClear || ctx->GetTrial(TK_LIGHT_TRIAL)->IsSkipped());}), + Entrance(RR_GANONS_CASTLE_DEKU_SCRUBS, []{return ctx->GetTrickOption(RT_LENS_GANON) || logic->CanUse(RG_LENS_OF_TRUTH);}), + }); + + areaTable[RR_GANONS_CASTLE_DEKU_SCRUBS] = Region("Ganon's Castle Deku Scrubs", "Ganon's Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->FreeFairies, []{return true;}), + }, { + //Locations + LOCATION(RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_LEFT, logic->CanStunDeku()), + LOCATION(RC_GANONS_CASTLE_DEKU_SCRUB_CENTER_RIGHT, logic->CanStunDeku()), + LOCATION(RC_GANONS_CASTLE_DEKU_SCRUB_RIGHT, logic->CanStunDeku()), + LOCATION(RC_GANONS_CASTLE_DEKU_SCRUB_LEFT, logic->CanStunDeku()), + LOCATION(RC_GANONS_CASTLE_SCRUBS_FAIRY_1, true), + LOCATION(RC_GANONS_CASTLE_SCRUBS_FAIRY_2, true), + LOCATION(RC_GANONS_CASTLE_SCRUBS_FAIRY_3, true), + LOCATION(RC_GANONS_CASTLE_SCRUBS_FAIRY_4, true), + LOCATION(RC_GANONS_CASTLE_SCRUBS_FAIRY_5, true), + LOCATION(RC_GANONS_CASTLE_SCRUBS_FAIRY_6, true), + LOCATION(RC_GANONS_CASTLE_SCRUBS_FAIRY_7, true), + LOCATION(RC_GANONS_CASTLE_SCRUBS_FAIRY_8, true), + }, {}); + + areaTable[RR_GANONS_CASTLE_FOREST_TRIAL] = Region("Ganon's Castle Forest Trial", "Ganon's Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->ForestTrialClear, []{return logic->CanUse(RG_LIGHT_ARROWS) && (logic->CanUse(RG_FIRE_ARROWS) || logic->CanUse(RG_DINS_FIRE));}), + }, { + //Locations + LOCATION(RC_GANONS_CASTLE_FOREST_TRIAL_CHEST, logic->CanDamage()), + LOCATION(RC_GANONS_CASTLE_FOREST_TRIAL_POT_1, logic->CanBreakPots() && (logic->CanUse(RG_FIRE_ARROWS) || logic->CanUse(RG_DINS_FIRE))), + LOCATION(RC_GANONS_CASTLE_FOREST_TRIAL_POT_2, logic->CanBreakPots() && (logic->CanUse(RG_FIRE_ARROWS) || logic->CanUse(RG_DINS_FIRE))), + }, {}); + + areaTable[RR_GANONS_CASTLE_FIRE_TRIAL] = Region("Ganon's Castle Fire Trial", "Ganon's Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->FireTrialClear, []{return logic->CanUse(RG_GORON_TUNIC) && logic->CanUse(RG_GOLDEN_GAUNTLETS) && logic->CanUse(RG_LIGHT_ARROWS) && logic->CanUse(RG_LONGSHOT);}), + }, { + //Locations + LOCATION(RC_GANONS_CASTLE_FIRE_TRIAL_POT_1, logic->CanBreakPots() && logic->CanUse(RG_GORON_TUNIC) && logic->CanUse(RG_GOLDEN_GAUNTLETS) && logic->CanUse(RG_LONGSHOT)), + LOCATION(RC_GANONS_CASTLE_FIRE_TRIAL_POT_2, logic->CanBreakPots() && logic->CanUse(RG_GORON_TUNIC) && logic->CanUse(RG_GOLDEN_GAUNTLETS) && logic->CanUse(RG_LONGSHOT)), + LOCATION(RC_GANONS_CASTLE_FIRE_TRIAL_HEART, logic->CanUse(RG_GORON_TUNIC)), + }, {}); + + areaTable[RR_GANONS_CASTLE_WATER_TRIAL] = Region("Ganon's Castle Water Trial", "Ganon's Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->BlueFireAccess, []{return logic->BlueFireAccess || logic->HasBottle();}), + EventAccess(&logic->FairyPot, []{return logic->FairyPot || (logic->BlueFire() && logic->CanKillEnemy(RE_FREEZARD));}), + EventAccess(&logic->WaterTrialClear, []{return logic->BlueFire() && logic->IsAdult && logic->CanUse(RG_MEGATON_HAMMER) && logic->CanUse(RG_LIGHT_ARROWS);}), + }, { + //Locations + LOCATION(RC_GANONS_CASTLE_WATER_TRIAL_LEFT_CHEST, true), + LOCATION(RC_GANONS_CASTLE_WATER_TRIAL_RIGHT_CHEST, true), + LOCATION(RC_GANONS_CASTLE_WATER_TRIAL_POT_1, logic->CanBreakPots() && logic->BlueFire() && logic->IsAdult && logic->CanUse(RG_MEGATON_HAMMER)), + LOCATION(RC_GANONS_CASTLE_WATER_TRIAL_POT_2, logic->CanBreakPots() && logic->BlueFire() && logic->IsAdult && logic->CanUse(RG_MEGATON_HAMMER)), + LOCATION(RC_GANONS_CASTLE_WATER_TRIAL_POT_3, logic->CanBreakPots() && logic->BlueFire() && logic->CanKillEnemy(RE_FREEZARD)), + }, {}); + + areaTable[RR_GANONS_CASTLE_SHADOW_TRIAL] = Region("Ganon's Castle Shadow Trial", "Ganon's Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->ShadowTrialClear, []{return logic->CanUse(RG_LIGHT_ARROWS) && logic->CanUse(RG_MEGATON_HAMMER) && ((logic->CanUse(RG_FIRE_ARROWS) && (ctx->GetTrickOption(RT_LENS_GANON) || logic->CanUse(RG_LENS_OF_TRUTH))) || (logic->CanUse(RG_LONGSHOT) && (logic->CanUse(RG_HOVER_BOOTS) || (logic->CanUse(RG_DINS_FIRE) && (ctx->GetTrickOption(RT_LENS_GANON) || logic->CanUse(RG_LENS_OF_TRUTH))))));}), + }, { + //Locations + LOCATION(RC_GANONS_CASTLE_SHADOW_TRIAL_FRONT_CHEST, logic->CanUse(RG_FIRE_ARROWS) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_SONG_OF_TIME) || logic->IsChild), + LOCATION(RC_GANONS_CASTLE_SHADOW_TRIAL_GOLDEN_GAUNTLETS_CHEST, logic->CanUse(RG_FIRE_ARROWS) || (logic->CanUse(RG_LONGSHOT) && (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_DINS_FIRE)))), + LOCATION(RC_GANONS_CASTLE_SHADOW_TRIAL_POT_1, logic->CanUse(RG_FIRE_ARROWS) || logic->CanUse(RG_LONGSHOT)), + LOCATION(RC_GANONS_CASTLE_SHADOW_TRIAL_POT_2, logic->CanUse(RG_FIRE_ARROWS) || logic->CanUse(RG_LONGSHOT)), + LOCATION(RC_GANONS_CASTLE_SHADOW_TRIAL_POT_3, logic->CanBreakPots() && logic->CanUse(RG_MEGATON_HAMMER) && ((logic->CanUse(RG_FIRE_ARROWS) && (ctx->GetTrickOption(RT_LENS_GANON) || logic->CanUse(RG_LENS_OF_TRUTH))) || (logic->CanUse(RG_LONGSHOT) && (logic->CanUse(RG_HOVER_BOOTS) || (logic->CanUse(RG_DINS_FIRE) && (ctx->GetTrickOption(RT_LENS_GANON) || logic->CanUse(RG_LENS_OF_TRUTH))))))), + LOCATION(RC_GANONS_CASTLE_SHADOW_TRIAL_POT_4, logic->CanBreakPots() && logic->CanUse(RG_MEGATON_HAMMER) && ((logic->CanUse(RG_FIRE_ARROWS) && (ctx->GetTrickOption(RT_LENS_GANON) || logic->CanUse(RG_LENS_OF_TRUTH))) || (logic->CanUse(RG_LONGSHOT) && (logic->CanUse(RG_HOVER_BOOTS) || (logic->CanUse(RG_DINS_FIRE) && (ctx->GetTrickOption(RT_LENS_GANON) || logic->CanUse(RG_LENS_OF_TRUTH))))))), + LOCATION(RC_GANONS_CASTLE_SHADOW_TRIAL_HEART_1, (logic->CanUse(RG_FIRE_ARROWS) || (logic->CanUse(RG_LONGSHOT) && (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_DINS_FIRE)))) && (ctx->GetTrickOption(RT_LENS_GANON) || logic->CanUse(RG_LENS_OF_TRUTH) || logic->CanUse(RG_BOOMERANG))), + LOCATION(RC_GANONS_CASTLE_SHADOW_TRIAL_HEART_2, (logic->CanUse(RG_FIRE_ARROWS) || (logic->CanUse(RG_LONGSHOT) && (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_DINS_FIRE)))) && (ctx->GetTrickOption(RT_LENS_GANON) || logic->CanUse(RG_LENS_OF_TRUTH) || logic->CanUse(RG_BOOMERANG))), + LOCATION(RC_GANONS_CASTLE_SHADOW_TRIAL_HEART_3, (logic->CanUse(RG_FIRE_ARROWS) || (logic->CanUse(RG_LONGSHOT) && (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_DINS_FIRE)))) && (ctx->GetTrickOption(RT_LENS_GANON) || logic->CanUse(RG_LENS_OF_TRUTH) || logic->CanUse(RG_BOOMERANG))), + }, {}); + + areaTable[RR_GANONS_CASTLE_SPIRIT_TRIAL] = Region("Ganon's Castle Spirit Trial", "Ganon's Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->NutPot, []{return logic->NutPot || (((ctx->GetTrickOption(RT_GANON_SPIRIT_TRIAL_HOOKSHOT) && logic->CanJumpslashExceptHammer()) || logic->CanUse(RG_HOOKSHOT)) && logic->CanUse(RG_BOMBCHU_5) && logic->CanUse(RG_FAIRY_BOW) && (logic->CanUse(RG_MIRROR_SHIELD) || (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS))));}), + EventAccess(&logic->SpiritTrialClear, []{return logic->CanUse(RG_LIGHT_ARROWS) && (logic->CanUse(RG_MIRROR_SHIELD) || ctx->GetOption(RSK_SUNLIGHT_ARROWS)) && logic->CanUse(RG_BOMBCHU_5) && ((ctx->GetTrickOption(RT_GANON_SPIRIT_TRIAL_HOOKSHOT) && logic->CanJumpslashExceptHammer()) || logic->CanUse(RG_HOOKSHOT));}), + }, { + //Locations + LOCATION(RC_GANONS_CASTLE_SPIRIT_TRIAL_CRYSTAL_SWITCH_CHEST, (ctx->GetTrickOption(RT_GANON_SPIRIT_TRIAL_HOOKSHOT) || logic->CanUse(RG_HOOKSHOT)) && logic->CanJumpslashExceptHammer()), + LOCATION(RC_GANONS_CASTLE_SPIRIT_TRIAL_INVISIBLE_CHEST, (ctx->GetTrickOption(RT_GANON_SPIRIT_TRIAL_HOOKSHOT) || logic->CanUse(RG_HOOKSHOT)) && logic->CanUse(RG_BOMBCHU_5) && (ctx->GetTrickOption(RT_LENS_GANON) || logic->CanUse(RG_LENS_OF_TRUTH))), + LOCATION(RC_GANONS_CASTLE_SPIRIT_TRIAL_POT_1, ((ctx->GetTrickOption(RT_GANON_SPIRIT_TRIAL_HOOKSHOT) && logic->CanJumpslashExceptHammer()) || logic->CanUse(RG_HOOKSHOT)) && logic->CanUse(RG_BOMBCHU_5) && logic->CanUse(RG_FAIRY_BOW) && (logic->CanUse(RG_MIRROR_SHIELD) || (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS)))), + LOCATION(RC_GANONS_CASTLE_SPIRIT_TRIAL_POT_2, ((ctx->GetTrickOption(RT_GANON_SPIRIT_TRIAL_HOOKSHOT) && logic->CanJumpslashExceptHammer()) || logic->CanUse(RG_HOOKSHOT)) && logic->CanUse(RG_BOMBCHU_5) && logic->CanUse(RG_FAIRY_BOW) && (logic->CanUse(RG_MIRROR_SHIELD) || (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS)))), + LOCATION(RC_GANONS_CASTLE_SPIRIT_TRIAL_SUN_FAIRY, logic->CanUse(RG_SUNS_SONG)), + LOCATION(RC_GANONS_CASTLE_SPIRIT_TRIAL_HEART, true), + }, {}); + + areaTable[RR_GANONS_CASTLE_LIGHT_TRIAL] = Region("Ganon's Castle Light Trial", "Ganon's Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->LightTrialClear, []{return logic->CanUse(RG_LIGHT_ARROWS) && logic->CanUse(RG_HOOKSHOT) && logic->SmallKeys(RR_GANONS_CASTLE, 2) && (ctx->GetTrickOption(RT_LENS_GANON) || logic->CanUse(RG_LENS_OF_TRUTH));}), + }, { + //Locations + LOCATION(RC_GANONS_CASTLE_LIGHT_TRIAL_FIRST_LEFT_CHEST, true), + LOCATION(RC_GANONS_CASTLE_LIGHT_TRIAL_SECOND_LEFT_CHEST, true), + LOCATION(RC_GANONS_CASTLE_LIGHT_TRIAL_THIRD_LEFT_CHEST, true), + LOCATION(RC_GANONS_CASTLE_LIGHT_TRIAL_FIRST_RIGHT_CHEST, true), + LOCATION(RC_GANONS_CASTLE_LIGHT_TRIAL_SECOND_RIGHT_CHEST, true), + LOCATION(RC_GANONS_CASTLE_LIGHT_TRIAL_THIRD_RIGHT_CHEST, true), + LOCATION(RC_GANONS_CASTLE_LIGHT_TRIAL_INVISIBLE_ENEMIES_CHEST, ctx->GetTrickOption(RT_LENS_GANON) || logic->CanUse(RG_LENS_OF_TRUTH)), + LOCATION(RC_GANONS_CASTLE_LIGHT_TRIAL_LULLABY_CHEST, logic->CanUse(RG_ZELDAS_LULLABY) && logic->SmallKeys(RR_GANONS_CASTLE, 1)), + LOCATION(RC_GANONS_CASTLE_LIGHT_TRIAL_BOULDER_POT_1, logic->CanBreakPots() && logic->SmallKeys(RR_GANONS_CASTLE, 2)), + LOCATION(RC_GANONS_CASTLE_LIGHT_TRIAL_POT_1, logic->CanBreakPots() && logic->CanUse(RG_HOOKSHOT) && logic->SmallKeys(RR_GANONS_CASTLE, 2) && (ctx->GetTrickOption(RT_LENS_GANON) || logic->CanUse(RG_LENS_OF_TRUTH))), + LOCATION(RC_GANONS_CASTLE_LIGHT_TRIAL_POT_2, logic->CanBreakPots() && logic->CanUse(RG_HOOKSHOT) && logic->SmallKeys(RR_GANONS_CASTLE, 2) && (ctx->GetTrickOption(RT_LENS_GANON) || logic->CanUse(RG_LENS_OF_TRUTH))), + }, {}); + +#pragma endregion + +#pragma region MQ + + areaTable[RR_GANONS_CASTLE_MQ_LOBBY] = Region("Ganon's Castle MQ Lobby", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_GANONS_CASTLE_ENTRYWAY, []{return logic->CanPassEnemy(RE_GREEN_BUBBLE) || Here(RR_GANONS_CASTLE_MQ_LOBBY, []{return logic->CanKillEnemy(RE_IRON_KNUCKLE) && logic->CanKillEnemy(RE_ARMOS);});}), + //Implies CanKillEnemy(RE_GREEN_BUBBLE) + Entrance(RR_GANONS_CASTLE_MQ_MAIN, []{return Here(RR_GANONS_CASTLE_MQ_LOBBY, []{return logic->CanKillEnemy(RE_IRON_KNUCKLE) && logic->CanKillEnemy(RE_ARMOS);});}), + }); + + areaTable[RR_GANONS_CASTLE_MQ_MAIN] = Region("Ganon's Castle MQ Main", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SHEIK_HINT_MQ_GC, true), + }, { + //Exits + Entrance(RR_GANONS_CASTLE_MQ_LOBBY, []{return true;}), + Entrance(RR_GANONS_CASTLE_MQ_FOREST_TRIAL_STALFOS_ROOM, []{return true;}), + Entrance(RR_GANONS_CASTLE_MQ_FIRE_TRIAL_MAIN_ROOM, []{return true;}), + Entrance(RR_GANONS_CASTLE_MQ_WATER_TRIAL_GEYSER_ROOM, []{return true;}), + Entrance(RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_STARTING_LEDGE, []{return true;}), + Entrance(RR_GANONS_CASTLE_MQ_SPIRIT_TRIAL_CHAIRS_ROOM, []{return true;}), + Entrance(RR_GANONS_CASTLE_MQ_LIGHT_TRIAL_DINOLFOS_ROOM, []{return Here(RR_GANONS_CASTLE_MQ_MAIN, []{return logic->CanUse(RG_GOLDEN_GAUNTLETS);});}), + //RANDOTODO could we just set these events automatically based on the setting? + Entrance(RR_GANONS_TOWER_FLOOR_1, []{return (logic->ForestTrialClear || ctx->GetTrial(TK_FOREST_TRIAL)->IsSkipped()) && + (logic->FireTrialClear || ctx->GetTrial(TK_FIRE_TRIAL)->IsSkipped()) && + (logic->WaterTrialClear || ctx->GetTrial(TK_WATER_TRIAL)->IsSkipped()) && + (logic->ShadowTrialClear || ctx->GetTrial(TK_SHADOW_TRIAL)->IsSkipped()) && + (logic->SpiritTrialClear || ctx->GetTrial(TK_SPIRIT_TRIAL)->IsSkipped()) && + (logic->LightTrialClear || ctx->GetTrial(TK_LIGHT_TRIAL)->IsSkipped());}), + Entrance(RR_GANONS_CASTLE_MQ_DEKU_SCRUBS, []{return ctx->GetTrickOption(RT_LENS_GANON_MQ) || logic->CanUse(RG_LENS_OF_TRUTH);}), + }); + + areaTable[RR_GANONS_CASTLE_MQ_DEKU_SCRUBS] = Region("Ganon's Castle MQ Deku Scrubs", "Ganon's Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->FreeFairies, []{return true;}), + }, { + //Locations + LOCATION(RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_LEFT, logic->CanStunDeku()), + LOCATION(RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER, logic->CanStunDeku()), + LOCATION(RC_GANONS_CASTLE_MQ_DEKU_SCRUB_CENTER_RIGHT, logic->CanStunDeku()), + LOCATION(RC_GANONS_CASTLE_MQ_DEKU_SCRUB_LEFT, logic->CanStunDeku()), + LOCATION(RC_GANONS_CASTLE_MQ_DEKU_SCRUB_RIGHT, logic->CanStunDeku()), + LOCATION(RC_GANONS_CASTLE_MQ_SCRUBS_FAIRY_1, true), + LOCATION(RC_GANONS_CASTLE_MQ_SCRUBS_FAIRY_2, true), + LOCATION(RC_GANONS_CASTLE_MQ_SCRUBS_FAIRY_3, true), + LOCATION(RC_GANONS_CASTLE_MQ_SCRUBS_FAIRY_4, true), + LOCATION(RC_GANONS_CASTLE_MQ_SCRUBS_FAIRY_5, true), + LOCATION(RC_GANONS_CASTLE_MQ_SCRUBS_FAIRY_6, true), + LOCATION(RC_GANONS_CASTLE_MQ_SCRUBS_FAIRY_7, true), + LOCATION(RC_GANONS_CASTLE_MQ_SCRUBS_FAIRY_8, true), + }, { + //Exits + Entrance(RR_GANONS_CASTLE_MQ_MAIN, []{return true;}), + }); + + areaTable[RR_GANONS_CASTLE_MQ_FOREST_TRIAL_STALFOS_ROOM] = Region("Ganon's Castle MQ Forest Trial Stalfos Room", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GANONS_CASTLE_MQ_FOREST_TRIAL_FREESTANDING_KEY, logic->HookshotOrBoomerang()), + }, { + //Exits + Entrance(RR_GANONS_CASTLE_MQ_MAIN, []{return true;}), + Entrance(RR_GANONS_CASTLE_MQ_FOREST_TRIAL_BEAMOS_ROOM, []{return Here(RR_GANONS_CASTLE_MQ_FOREST_TRIAL_STALFOS_ROOM, []{return logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2);});}), + }); + + //If it is ever possible to warp into the RR_GANONS_CASTLE_MQ_FOREST_TRIAL_FINAL_ROOM, this needs splitting up as the requirements to reach things from the other side are more complex + areaTable[RR_GANONS_CASTLE_MQ_FOREST_TRIAL_BEAMOS_ROOM] = Region("Ganon's Castle MQ Forest Trial Beamos Room", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GANONS_CASTLE_MQ_FOREST_TRIAL_EYE_SWITCH_CHEST, logic->CanHitEyeTargets()), + LOCATION(RC_GANONS_CASTLE_MQ_FOREST_TRIAL_FROZEN_EYE_SWITCH_CHEST, logic->HasFireSource()), + }, { + //Exits + Entrance(RR_GANONS_CASTLE_MQ_FOREST_TRIAL_STALFOS_ROOM, []{return true;}), + Entrance(RR_GANONS_CASTLE_MQ_FOREST_TRIAL_FINAL_ROOM, []{return logic->IsAdult && logic->CanUse(RG_SONG_OF_TIME);}), + }); + + areaTable[RR_GANONS_CASTLE_MQ_FOREST_TRIAL_FINAL_ROOM] = Region("Ganon's Castle MQ Forest Trial Final Room", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->ForestTrialClear, []{return logic->CanUse(RG_LIGHT_ARROWS);}), + }, { + //Locations + LOCATION(RC_GANONS_CASTLE_MQ_FOREST_TRIAL_POT_1, logic->CanBreakPots()), + LOCATION(RC_GANONS_CASTLE_MQ_FOREST_TRIAL_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_GANONS_CASTLE_MQ_FOREST_TRIAL_BEAMOS_ROOM, []{return true;}), + }); + + areaTable[RR_GANONS_CASTLE_MQ_FIRE_TRIAL_MAIN_ROOM] = Region("Ganon's Castle MQ Fire Trial Main Room", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_GANONS_CASTLE_MQ_MAIN, []{return true;}), + //2 checks, 1 for the rupees, 1 for actually making it, as the rupees are permanent but throwing a pillar is not + Entrance(RR_GANONS_CASTLE_MQ_FIRE_TRIAL_FINAL_ROOM, []{return Here(RR_GANONS_CASTLE_MQ_FIRE_TRIAL_MAIN_ROOM, []{return logic->CanUse(RG_GORON_TUNIC) && logic->CanUse(RG_GOLDEN_GAUNTLETS);}) && logic->CanUse(RG_GORON_TUNIC) && (logic->CanUse(RG_LONGSHOT) || (logic->CanUse(RG_GOLDEN_GAUNTLETS) && (logic->CanUse(RG_HOVER_BOOTS) || (ctx->GetTrickOption(RT_GANON_MQ_FIRE_TRIAL) && logic->IsAdult && logic->CanUse(RG_HOOKSHOT)))));}), + }); + + areaTable[RR_GANONS_CASTLE_MQ_FIRE_TRIAL_FINAL_ROOM] = Region("Ganon's Castle MQ Fire Trial Final Room", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->FireTrialClear, []{return logic->CanUse(RG_LIGHT_ARROWS);}), + //There's no way back across the lava without glitches + }, { + //Locations + LOCATION(RC_GANONS_CASTLE_MQ_FIRE_TRIAL_POT_1, logic->CanBreakPots()), + LOCATION(RC_GANONS_CASTLE_MQ_FIRE_TRIAL_POT_2, logic->CanBreakPots()), + }, {}); + + areaTable[RR_GANONS_CASTLE_MQ_WATER_TRIAL_GEYSER_ROOM] = Region("Ganon's Castle MQ Water Trial Geyser Room", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->BlueFireAccess, []{return logic->CanJumpslash() || logic->HasExplosives();}), + }, { + //Locations + LOCATION(RC_GANONS_CASTLE_MQ_WATER_TRIAL_CHEST, logic->BlueFire()), + LOCATION(RC_GANONS_CASTLE_MQ_WATER_TRIAL_HEART, logic->BlueFire()), + }, { + //Exits + Entrance(RR_GANONS_CASTLE_MQ_MAIN, []{return true;}), + Entrance(RR_GANONS_CASTLE_MQ_WATER_TRIAL_BLOCK_ROOM, []{return logic->SmallKeys(RR_GANONS_CASTLE, 3) && Here(RR_GANONS_CASTLE_MQ_WATER_TRIAL_GEYSER_ROOM, []{return logic->BlueFire();});}), + }); + + areaTable[RR_GANONS_CASTLE_MQ_WATER_TRIAL_BLOCK_ROOM] = Region("Ganon's Castle MQ Water Trial Block Room", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_GANONS_CASTLE_MQ_WATER_TRIAL_GEYSER_ROOM, []{return logic->SmallKeys(RR_GANONS_CASTLE, 3);}), + //This assumes there's no way for child to have blue fire and not adult. + Entrance(RR_GANONS_CASTLE_MQ_WATER_TRIAL_FINAL_ROOM, []{return logic->IsAdult && logic->BlueFire();}), + }); + + areaTable[RR_GANONS_CASTLE_MQ_WATER_TRIAL_FINAL_ROOM] = Region("Ganon's Castle MQ Water Trial Final Room", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->WaterTrialClear, []{return logic->CanUse(RG_LIGHT_ARROWS);}), + }, { + //Locations + LOCATION(RC_GANONS_CASTLE_MQ_WATER_TRIAL_POT_1, logic->CanBreakPots()), + LOCATION(RC_GANONS_CASTLE_MQ_WATER_TRIAL_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_GANONS_CASTLE_MQ_WATER_TRIAL_BLOCK_ROOM, []{return Here(RR_GANONS_CASTLE_MQ_WATER_TRIAL_FINAL_ROOM, []{return logic->BlueFire();});}), + }); + + areaTable[RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_STARTING_LEDGE] = Region("Ganon's Castle MQ Shadow Trial Starting Ledge", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->ShadowTrialFirstChest, []{return logic->CanUse(RG_FAIRY_BOW);}), + }, {}, { + //Exits + Entrance(RR_GANONS_CASTLE_MQ_MAIN, []{return true;}), + Entrance(RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_CHEST_PLATFORM, []{return (logic->ShadowTrialFirstChest && logic->CanUse(RG_HOOKSHOT)) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS));}), + }); + + areaTable[RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_CHEST_PLATFORM] = Region("Ganon's Castle MQ Shadow Trial Chest Platform", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->ShadowTrialFirstChest, []{return logic->CanUse(RG_FAIRY_BOW);}), + }, { + //Locations + LOCATION(RC_GANONS_CASTLE_MQ_SHADOW_TRIAL_BOMB_FLOWER_CHEST, logic->ShadowTrialFirstChest), + }, { + //Exits + //Hookshot here is possible but very tight, but it's basically never relevant + Entrance(RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_STARTING_LEDGE, []{return logic->CanUse(RG_LONGSHOT) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS));}), + Entrance(RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_MOVING_PLATFORM, []{return (ctx->GetTrickOption(RT_LENS_GANON_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)) && (logic->IsAdult || logic->CanUse(RG_HOVER_BOOTS));}), + }); + + areaTable[RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_MOVING_PLATFORM] = Region("Ganon's Castle MQ Shadow Trial Moving Platform", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { + //Events + //A torch run from RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_STARTING_LEDGE is possible but tight, so would be a trick + EventAccess(&logic->ShadowTrialFirstChest, []{return logic->CanDetonateUprightBombFlower();}), + }, {}, { + //Exits + Entrance(RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_CHEST_PLATFORM, []{return logic->IsAdult || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS);}), + Entrance(RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_BEAMOS_TORCH, []{return true;}), + }); + + + areaTable[RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_BEAMOS_TORCH] = Region("Ganon's Castle MQ Shadow Trial Beamos Torch", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_MOVING_PLATFORM, []{return ctx->GetTrickOption(RT_LENS_GANON_MQ) || logic->CanUse(RG_LENS_OF_TRUTH);}), + //A torch run from RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_STARTING_LEDGE is possible but very tight, so would be a trick + //The bow trick assumes RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_STARTING_LEDGE access, if you can somehow void warp directly here it will need handling properly + //Hovers is possible as child but a bit tight, requires good rolls + Entrance(RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_FAR_SIDE, []{return logic->HasFireSource() || logic->CanUse(RG_HOVER_BOOTS) || (logic->IsAdult && ctx->GetTrickOption(RT_GANON_MQ_SHADOW_TRIAL) && logic->CanUse(RG_FAIRY_BOW));}), + }); + + areaTable[RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_FAR_SIDE] = Region("Ganon's Castle MQ Shadow Trial Far Side", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GANONS_CASTLE_MQ_SHADOW_TRIAL_EYE_SWITCH_CHEST, logic->CanHitEyeTargets()), + }, { + //Exits + Entrance(RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_BEAMOS_TORCH, []{return logic->CanUse(RG_FIRE_ARROWS) || logic->CanUse(RG_HOVER_BOOTS);}), + //Modelling the silver rupees properly will require a way to check temp flags in different regions. + //It may be tempting to use a Here-like command for this but it could cause sphere skipping in playthroughs + //So a system like event access which sets based on TimeAge would be preferable, as the application of these can be tracked and accounted for, unlike Here-like commands + //For Now I am assuming the player has made it all the way from RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_STARTING_LEDGE, which logically means every rupee is available + //with no extra requirements except the lens logic needed to reach the door, which also enables the beamos-platform rupee + Entrance(RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_FINAL_ROOM, []{return (ctx->GetTrickOption(RT_LENS_GANON_MQ) || logic->CanUse(RG_LENS_OF_TRUTH));}), + }); + + areaTable[RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_FINAL_ROOM] = Region("Ganon's Castle MQ Shadow Trial Final Room", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->ShadowTrialClear, []{return logic->CanUse(RG_LIGHT_ARROWS);}), + }, { + //Locations + LOCATION(RC_GANONS_CASTLE_MQ_SHADOW_TRIAL_POT_1, logic->CanBreakPots()), + LOCATION(RC_GANONS_CASTLE_MQ_SHADOW_TRIAL_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_GANONS_CASTLE_MQ_SHADOW_TRIAL_FAR_SIDE, []{return (ctx->GetTrickOption(RT_LENS_GANON_MQ) || logic->CanUse(RG_LENS_OF_TRUTH));}), + }); + + areaTable[RR_GANONS_CASTLE_MQ_SPIRIT_TRIAL_CHAIRS_ROOM] = Region("Ganon's Castle MQ Spirit Trial Chairs Room", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_GANONS_CASTLE_MQ_MAIN, []{return true;}), + Entrance(RR_GANONS_CASTLE_MQ_SPIRIT_TRIAL_BEFORE_SWITCH, []{return Here(RR_GANONS_CASTLE_MQ_SPIRIT_TRIAL_CHAIRS_ROOM, []{return (logic->CanHitEyeTargets() || ctx->GetTrickOption(RT_RUSTED_SWITCHES)) && logic->CanUse(RG_MEGATON_HAMMER);});}), + }); + + areaTable[RR_GANONS_CASTLE_MQ_SPIRIT_TRIAL_BEFORE_SWITCH] = Region("Ganon's Castle MQ Spirit Trial Before Switch", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_FIRST_CHEST, logic->CanPassEnemy(RE_GREEN_BUBBLE)), + }, { + //Exits + Entrance(RR_GANONS_CASTLE_MQ_SPIRIT_TRIAL_CHAIRS_ROOM, []{return true;}), + Entrance(RR_GANONS_CASTLE_MQ_SPIRIT_TRIAL_AFTER_SWITCH, []{return Here(RR_GANONS_CASTLE_MQ_SPIRIT_TRIAL_BEFORE_SWITCH, []{return logic->CanUse(RG_BOMBCHU_5);});}), + }); + + areaTable[RR_GANONS_CASTLE_MQ_SPIRIT_TRIAL_AFTER_SWITCH] = Region("Ganon's Castle MQ Spirit Trial After Switch", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_INVISIBLE_CHEST, ctx->GetTrickOption(RT_LENS_GANON_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)), + //better names for these would be nice. + LOCATION(RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_FRONT_LEFT_CHEST, (logic->CanUse(RG_FIRE_ARROWS) && logic->CanUse(RG_MIRROR_SHIELD)) || (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS))), + LOCATION(RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_LEFT_CHEST, (logic->CanUse(RG_FIRE_ARROWS) && logic->CanUse(RG_MIRROR_SHIELD)) || (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS))), + LOCATION(RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_GOLDEN_GAUNTLETS_CHEST, (logic->CanUse(RG_FIRE_ARROWS) && logic->CanUse(RG_MIRROR_SHIELD)) || (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS))), + LOCATION(RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_SUN_BACK_RIGHT_CHEST, (logic->CanUse(RG_FIRE_ARROWS) && logic->CanUse(RG_MIRROR_SHIELD)) || (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS))), + }, { + //Exits + Entrance(RR_GANONS_CASTLE_MQ_SPIRIT_TRIAL_BEFORE_SWITCH, []{return Here(RR_GANONS_CASTLE_MQ_SPIRIT_TRIAL_AFTER_SWITCH, []{return logic->CanUse(RG_BOMBCHU_5);});}), + //Sunlight arrows are bugged, should set a perm flag like mirror shield + Entrance(RR_GANONS_CASTLE_MQ_SPIRIT_TRIAL_FINAL_ROOM, []{return Here(RR_GANONS_CASTLE_MQ_SPIRIT_TRIAL_AFTER_SWITCH, []{return (logic->CanUse(RG_FIRE_ARROWS) && logic->CanUse(RG_MIRROR_SHIELD));}) || (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS));}), + }); + + areaTable[RR_GANONS_CASTLE_MQ_SPIRIT_TRIAL_FINAL_ROOM] = Region("Ganon's Castle MQ Spirit Trial Final Room", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->SpiritTrialClear, []{return logic->CanUse(RG_LIGHT_ARROWS);}), + EventAccess(&logic->NutPot, []{return true;}), + }, { + //Locations + LOCATION(RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_POT_1, logic->CanBreakPots()), + LOCATION(RC_GANONS_CASTLE_MQ_SPIRIT_TRIAL_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_GANONS_CASTLE_MQ_SPIRIT_TRIAL_AFTER_SWITCH, []{return true;}), + }); + + areaTable[RR_GANONS_CASTLE_MQ_LIGHT_TRIAL_DINOLFOS_ROOM] = Region("Ganon's Castle MQ Light Trial Dinolfos Room", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_GANONS_CASTLE_MQ_MAIN, []{return true;}), + Entrance(RR_GANONS_CASTLE_MQ_LIGHT_TRIAL_TRIFORCE_ROOM, []{return Here(RR_GANONS_CASTLE_MQ_LIGHT_TRIAL_DINOLFOS_ROOM, []{return logic->CanKillEnemy(RE_DINOLFOS) && logic->CanKillEnemy(RE_TORCH_SLUG);});}), + }); + + areaTable[RR_GANONS_CASTLE_MQ_LIGHT_TRIAL_TRIFORCE_ROOM] = Region("Ganon's Castle MQ Light Trial Triforce Room", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GANONS_CASTLE_MQ_LIGHT_TRIAL_LULLABY_CHEST, logic->CanUse(RG_ZELDAS_LULLABY)), + }, { + //Exits + Entrance(RR_GANONS_CASTLE_MQ_LIGHT_TRIAL_DINOLFOS_ROOM, []{return true;}), + Entrance(RR_GANONS_CASTLE_MQ_LIGHT_TRIAL_BOULDER_ROOM_FRONT, []{return logic->SmallKeys(RR_GANONS_CASTLE, 2);}), + }); + + areaTable[RR_GANONS_CASTLE_MQ_LIGHT_TRIAL_BOULDER_ROOM_FRONT] = Region("Ganon's Castle MQ Light Trial Boulder Room Front", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_GANONS_CASTLE_MQ_LIGHT_TRIAL_TRIFORCE_ROOM, []{return logic->SmallKeys(RR_GANONS_CASTLE, 2);}), + Entrance(RR_GANONS_CASTLE_MQ_LIGHT_TRIAL_BOULDER_ROOM_BACK, []{return logic->CanUse(RG_HOOKSHOT) || ctx->GetTrickOption(RT_GANON_MQ_LIGHT_TRIAL);}), + }); + + areaTable[RR_GANONS_CASTLE_MQ_LIGHT_TRIAL_BOULDER_ROOM_BACK] = Region("Ganon's Castle MQ Light Trial Boulder Room Back", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GANONS_CASTLE_MQ_LIGHT_TRIAL_LEFT_HEART, true), + LOCATION(RC_GANONS_CASTLE_MQ_LIGHT_TRIAL_RIGHT_HEART, true), + }, { + //Exits + //I got the trick going backwards, but only while taking damage. this isn't relevant anyway though + Entrance(RR_GANONS_CASTLE_MQ_LIGHT_TRIAL_BOULDER_ROOM_FRONT, []{return logic->CanUse(RG_HOOKSHOT) || ctx->GetTrickOption(RT_GANON_MQ_LIGHT_TRIAL);}), + Entrance(RR_GANONS_CASTLE_MQ_LIGHT_TRIAL_FINAL_ROOM, []{return logic->SmallKeys(RR_GANONS_CASTLE, 3) && (ctx->GetTrickOption(RT_LENS_GANON_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)) && (logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanJumpslash() || logic->HasExplosives() || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_BOOMERANG));}), + }); + + areaTable[RR_GANONS_CASTLE_MQ_LIGHT_TRIAL_FINAL_ROOM] = Region("Ganon's Castle MQ Light Trial Final Room", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->LightTrialClear, []{return logic->CanUse(RG_LIGHT_ARROWS);}), + }, { + //Locations + LOCATION(RC_GANONS_CASTLE_MQ_LIGHT_TRIAL_POT_1, logic->CanBreakPots()), + LOCATION(RC_GANONS_CASTLE_MQ_LIGHT_TRIAL_POT_2, logic->CanBreakPots()), + }, {}); + +#pragma endregion + +#pragma region Tower and Escape + + areaTable[RR_GANONS_TOWER_FLOOR_1] = Region("Ganon's Tower Floor 1", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_GANONS_CASTLE_LOBBY, []{return Here(RR_GANONS_TOWER_FLOOR_1, []{return logic->CanKillEnemy(RE_DINOLFOS, ED_CLOSE, true, 2);});}), + Entrance(RR_GANONS_TOWER_FLOOR_2, []{return Here(RR_GANONS_TOWER_FLOOR_1, []{return logic->CanKillEnemy(RE_DINOLFOS, ED_CLOSE, true, 2);});}), + }); + + areaTable[RR_GANONS_TOWER_FLOOR_2] = Region("Ganon's Tower Floor 2", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GANONS_TOWER_BOSS_KEY_CHEST, logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2)), + }, { + //Exits + Entrance(RR_GANONS_TOWER_FLOOR_1, []{return Here(RR_GANONS_TOWER_FLOOR_2, []{return logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2);});}), + Entrance(RR_GANONS_TOWER_FLOOR_3, []{return Here(RR_GANONS_TOWER_FLOOR_2, []{return logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2);});}), + }); + + areaTable[RR_GANONS_TOWER_FLOOR_3] = Region("Ganon's Tower Floor 3", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_GANONS_TOWER_FLOOR_2, []{return Here(RR_GANONS_TOWER_FLOOR_3, []{return logic->CanKillEnemy(RE_IRON_KNUCKLE, ED_CLOSE, true, 2);});}), + Entrance(RR_GANONS_TOWER_BEFORE_GANONDORF_LAIR, []{return Here(RR_GANONS_TOWER_FLOOR_3, []{return logic->CanKillEnemy(RE_IRON_KNUCKLE, ED_CLOSE, true, 2);});}), + }); + + areaTable[RR_GANONS_TOWER_BEFORE_GANONDORF_LAIR] = Region("Ganon's Tower Before Ganondorf's Lair", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, { + // Locations + LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_1, logic->CanBreakPots()), + LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_2, logic->CanBreakPots()), + LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_3, logic->CanBreakPots()), + LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_4, logic->CanBreakPots()), + LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_5, logic->CanBreakPots()), + LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_6, logic->CanBreakPots()), + LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_7, logic->CanBreakPots()), + LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_8, logic->CanBreakPots()), + LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_9, logic->CanBreakPots()), + LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_10, logic->CanBreakPots()), + LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_11, logic->CanBreakPots()), + LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_12, logic->CanBreakPots()), + LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_13, logic->CanBreakPots()), + LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_14, logic->CanBreakPots()), + LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_15, logic->CanBreakPots()), + LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_16, logic->CanBreakPots()), + LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_17, logic->CanBreakPots()), + LOCATION(RC_GANONS_CASTLE_GANONS_TOWER_POT_18, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_GANONS_TOWER_FLOOR_3, []{return Here(RR_GANONS_TOWER_BEFORE_GANONDORF_LAIR, []{return true;});}), + Entrance(RR_GANONS_TOWER_GANONDORF_LAIR, []{return Here(RR_GANONS_TOWER_BEFORE_GANONDORF_LAIR, []{return logic->HasItem(RG_GANONS_CASTLE_BOSS_KEY);});}), + }); + + areaTable[RR_GANONS_TOWER_GANONDORF_LAIR] = Region("Ganondorf's Lair", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GANONDORF_HINT, logic->HasBossSoul(RG_GANON_SOUL)), + }, { + //Exits + Entrance(RR_GANONS_CASTLE_ESCAPE, []{return logic->CanKillEnemy(RE_GANONDORF);}), + }); + + areaTable[RR_GANONS_CASTLE_ESCAPE] = Region("Ganon's Castle Escape", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + //10 pots + //RANDOTODO hook potsanity pots up to escape. + }, { + //Exits + //temporary + Entrance(RR_GANONS_CASTLE_GANON_ARENA, []{return true;}), + //real logic once we figure out how to deal with castle escape skip + //Entrance(RR_GANONS_CASTLE_GANON_ARENA, []{return logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2, true);}), + }); + + areaTable[RR_GANONS_CASTLE_GANON_ARENA] = Region("Ganon's Arena", "Ganons Castle", {RA_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GANON, logic->CanKillEnemy(RE_GANON)), + }, {}); + +#pragma endregion +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/gerudo_training_ground.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/gerudo_training_ground.cpp new file mode 100644 index 000000000..b2e09a8c2 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/gerudo_training_ground.cpp @@ -0,0 +1,327 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" +#include "soh/Enhancements/randomizer/dungeon.h" + +using namespace Rando; + +void RegionTable_Init_GerudoTrainingGround() { + // Vanilla/MQ Decider + areaTable[RR_GERUDO_TRAINING_GROUND_ENTRYWAY] = Region("Gerudo Training Ground Entryway", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_GERUDO_TRAINING_GROUND_LOBBY, []{return ctx->GetDungeon(GERUDO_TRAINING_GROUND)->IsVanilla();}), + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_LOBBY, []{return ctx->GetDungeon(GERUDO_TRAINING_GROUND)->IsMQ();}), + Entrance(RR_GERUDO_FORTRESS, []{return true;}), + }); + +#pragma region Vanilla + + areaTable[RR_GERUDO_TRAINING_GROUND_LOBBY] = Region("Gerudo Training Ground Lobby", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GERUDO_TRAINING_GROUND_LOBBY_LEFT_CHEST, logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT)), + LOCATION(RC_GERUDO_TRAINING_GROUND_LOBBY_RIGHT_CHEST, logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT)), + LOCATION(RC_GERUDO_TRAINING_GROUND_STALFOS_CHEST, logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD)), + LOCATION(RC_GERUDO_TRAINING_GROUND_BEAMOS_CHEST, logic->HasExplosives() && (logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD))), + LOCATION(RC_GERUDO_TRAINING_GROUND_ENTRANCE_STORMS_FAIRY, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_GERUDO_TRAINING_GROUND_BEAMOS_SOUTH_HEART, true), + LOCATION(RC_GERUDO_TRAINING_GROUND_BEAMOS_EAST_HEART, true), + }, { + //Exits + Entrance(RR_GERUDO_TRAINING_GROUND_ENTRYWAY, []{return true;}), + Entrance(RR_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_ROOM, []{return (logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD)) && (logic->CanUse(RG_HOOKSHOT) || ctx->GetTrickOption(RT_GTG_WITHOUT_HOOKSHOT));}), + Entrance(RR_GERUDO_TRAINING_GROUND_LAVA_ROOM, []{return Here(RR_GERUDO_TRAINING_GROUND_LOBBY, []{return (logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD)) && logic->HasExplosives();});}), + Entrance(RR_GERUDO_TRAINING_GROUND_CENTRAL_MAZE, []{return true;}), + }); + + areaTable[RR_GERUDO_TRAINING_GROUND_CENTRAL_MAZE] = Region("Gerudo Training Ground Central Maze", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GERUDO_TRAINING_GROUND_HIDDEN_CEILING_CHEST, logic->SmallKeys(RR_GERUDO_TRAINING_GROUND, 3) && (ctx->GetTrickOption(RT_LENS_GTG) || logic->CanUse(RG_LENS_OF_TRUTH))), + LOCATION(RC_GERUDO_TRAINING_GROUND_MAZE_PATH_FIRST_CHEST, logic->SmallKeys(RR_GERUDO_TRAINING_GROUND, 4)), + LOCATION(RC_GERUDO_TRAINING_GROUND_MAZE_PATH_SECOND_CHEST, logic->SmallKeys(RR_GERUDO_TRAINING_GROUND, 6)), + LOCATION(RC_GERUDO_TRAINING_GROUND_MAZE_PATH_THIRD_CHEST, logic->SmallKeys(RR_GERUDO_TRAINING_GROUND, 7)), + LOCATION(RC_GERUDO_TRAINING_GROUND_MAZE_PATH_FINAL_CHEST, logic->SmallKeys(RR_GERUDO_TRAINING_GROUND, 9)), + }, { + //Exits + Entrance(RR_GERUDO_TRAINING_GROUND_CENTRAL_MAZE_RIGHT, []{return logic->SmallKeys(RR_GERUDO_TRAINING_GROUND, 9);}), + }); + + areaTable[RR_GERUDO_TRAINING_GROUND_CENTRAL_MAZE_RIGHT] = Region("Gerudo Training Ground Central Maze Right", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GERUDO_TRAINING_GROUND_MAZE_RIGHT_CENTRAL_CHEST, true), + LOCATION(RC_GERUDO_TRAINING_GROUND_MAZE_RIGHT_SIDE_CHEST, true), + LOCATION(RC_GERUDO_TRAINING_GROUND_FREESTANDING_KEY, true), + }, { + //Exits + Entrance(RR_GERUDO_TRAINING_GROUND_HAMMER_ROOM, []{return logic->CanUse(RG_HOOKSHOT);}), + Entrance(RR_GERUDO_TRAINING_GROUND_LAVA_ROOM, []{return true;}), + }); + + areaTable[RR_GERUDO_TRAINING_GROUND_LAVA_ROOM] = Region("Gerudo Training Ground Lava Room", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GERUDO_TRAINING_GROUND_UNDERWATER_SILVER_RUPEE_CHEST, logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_SONG_OF_TIME) && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 24), + }, { + //Exits + Entrance(RR_GERUDO_TRAINING_GROUND_CENTRAL_MAZE_RIGHT, []{return logic->CanUse(RG_SONG_OF_TIME) || logic->IsChild;}), + Entrance(RR_GERUDO_TRAINING_GROUND_HAMMER_ROOM, []{return logic->CanUse(RG_LONGSHOT) || (logic->CanUse(RG_HOVER_BOOTS) && logic->CanUse(RG_HOOKSHOT));}), + }); + + areaTable[RR_GERUDO_TRAINING_GROUND_HAMMER_ROOM] = Region("Gerudo Training Ground Hammer Room", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GERUDO_TRAINING_GROUND_HAMMER_ROOM_CLEAR_CHEST, logic->CanAttack()), + LOCATION(RC_GERUDO_TRAINING_GROUND_HAMMER_ROOM_SWITCH_CHEST, logic->CanUse(RG_MEGATON_HAMMER) || (logic->TakeDamage() && ctx->GetTrickOption(RT_FLAMING_CHESTS))), + }, { + //Exits + Entrance(RR_GERUDO_TRAINING_GROUND_EYE_STATUE_LOWER, []{return logic->CanUse(RG_MEGATON_HAMMER) && logic->CanUse(RG_FAIRY_BOW);}), + Entrance(RR_GERUDO_TRAINING_GROUND_LAVA_ROOM, []{return true;}), + }); + + areaTable[RR_GERUDO_TRAINING_GROUND_EYE_STATUE_LOWER] = Region("Gerudo Training Ground Eye Statue Lower", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GERUDO_TRAINING_GROUND_EYE_STATUE_CHEST, logic->CanUse(RG_FAIRY_BOW)), + }, { + //Exits + Entrance(RR_GERUDO_TRAINING_GROUND_HAMMER_ROOM, []{return true;}), + }); + + areaTable[RR_GERUDO_TRAINING_GROUND_EYE_STATUE_UPPER] = Region("Gerudo Training Ground Eye Statue Upper", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GERUDO_TRAINING_GROUND_NEAR_SCARECROW_CHEST, logic->CanUse(RG_FAIRY_BOW)), + }, { + //Exits + Entrance(RR_GERUDO_TRAINING_GROUND_EYE_STATUE_LOWER, []{return true;}), + }); + + areaTable[RR_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_ROOM] = Region("Gerudo Training Ground Heavy Block Room", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GERUDO_TRAINING_GROUND_BEFORE_HEAVY_BLOCK_CHEST, logic->CanJumpslashExceptHammer()), + }, { + //Exits + Entrance(RR_GERUDO_TRAINING_GROUND_EYE_STATUE_UPPER, []{return (ctx->GetTrickOption(RT_LENS_GTG) || logic->CanUse(RG_LENS_OF_TRUTH)) && (logic->CanUse(RG_HOOKSHOT) || (ctx->GetTrickOption(RT_GTG_FAKE_WALL) && logic->CanUse(RG_HOVER_BOOTS)));}), + Entrance(RR_GERUDO_TRAINING_GROUND_LIKE_LIKE_ROOM, []{return (ctx->GetTrickOption(RT_LENS_GTG) || logic->CanUse(RG_LENS_OF_TRUTH)) && (logic->CanUse(RG_HOOKSHOT) || (ctx->GetTrickOption(RT_GTG_FAKE_WALL) && logic->CanUse(RG_HOVER_BOOTS))) && logic->CanUse(RG_SILVER_GAUNTLETS);}), + }); + + areaTable[RR_GERUDO_TRAINING_GROUND_LIKE_LIKE_ROOM] = Region("Gerudo Training Ground Like Like Room", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_FIRST_CHEST, logic->CanJumpslashExceptHammer()), + LOCATION(RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_SECOND_CHEST, logic->CanJumpslashExceptHammer()), + LOCATION(RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_THIRD_CHEST, logic->CanJumpslashExceptHammer()), + LOCATION(RC_GERUDO_TRAINING_GROUND_HEAVY_BLOCK_FOURTH_CHEST, logic->CanJumpslashExceptHammer()), + }, {}); + +#pragma endregion + +#pragma region MQ + + areaTable[RR_GERUDO_TRAINING_GROUND_MQ_LOBBY] = Region("Gerudo Training Ground MQ Lobby", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_LEFT_CHEST, true), + LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_RIGHT_CHEST, true), + LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_FIRST_CHEST, true), + LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_SECOND_CHEST, true), + LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_LEFT_POT_1, logic->CanBreakPots()), + LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_LEFT_POT_2, logic->CanBreakPots()), + LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_RIGHT_POT_1, logic->CanBreakPots()), + LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_LOBBY_RIGHT_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_GERUDO_TRAINING_GROUND_ENTRYWAY, []{return true;}), + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_MAZE_HIDDEN_ROOM, []{return ctx->GetTrickOption(RT_LENS_GTG_MQ) || logic->CanUse(RG_LENS_OF_TRUTH);}), + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_MAZE_FIRST_LOCK, []{return logic->SmallKeys(RR_GERUDO_TRAINING_GROUND, 1);}), + //It's possible to use the torch in RR_GERUDO_TRAINING_GROUND_MQ_MAZE_HIDDEN_ROOM with flame storage to light these + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_SAND_ROOM, []{return Here(RR_GERUDO_TRAINING_GROUND_MQ_LOBBY, []{return logic->HasFireSource();});}), + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_DINOLFOS_ROOM, []{return Here(RR_GERUDO_TRAINING_GROUND_MQ_LOBBY, []{return (logic->IsAdult && logic->CanUse(RG_FAIRY_BOW)) || (logic->IsChild && logic->CanUse(RG_FAIRY_SLINGSHOT));});}), + }); + + areaTable[RR_GERUDO_TRAINING_GROUND_MQ_MAZE_HIDDEN_ROOM] = Region("Gerudo Training Ground MQ Maze Hidden Room", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_HIDDEN_CEILING_CHEST, true), + }, { + //Exits + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_LOBBY, []{return true;}), + }); + + areaTable[RR_GERUDO_TRAINING_GROUND_MQ_MAZE_FIRST_LOCK] = Region("Gerudo Training Ground MQ Maze First Lock", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_MAZE_PATH_THIRD_CHEST, true), + }, { + //Exits + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_LOBBY, []{return logic->SmallKeys(RR_GERUDO_TRAINING_GROUND, 1);}), + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_MAZE_CENTER, []{return logic->SmallKeys(RR_GERUDO_TRAINING_GROUND, 3);}), + }); + + areaTable[RR_GERUDO_TRAINING_GROUND_MQ_MAZE_CENTER] = Region("Gerudo Training Ground MQ Center", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->MQGTGMazeSwitch, []{return logic->CanUse(RG_MEGATON_HAMMER);}), + }, {}, { + //Exits + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_MAZE_FIRST_LOCK, []{return logic->SmallKeys(RR_GERUDO_TRAINING_GROUND, 3);}), + }); + + areaTable[RR_GERUDO_TRAINING_GROUND_MQ_SAND_ROOM] = Region("Gerudo Training Ground MQ Sand Room", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_FIRST_IRON_KNUCKLE_CHEST, logic->CanKillEnemy(RE_IRON_KNUCKLE)), + }, { + //Exits + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_LOBBY, []{return true;}), + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_LEFT_SIDE, []{return Here(RR_GERUDO_TRAINING_GROUND_MQ_SAND_ROOM, []{return logic->CanKillEnemy(RE_IRON_KNUCKLE);});}), + }); + + areaTable[RR_GERUDO_TRAINING_GROUND_MQ_LEFT_SIDE] = Region("Gerudo Training Ground MQ Left Side", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_SAND_ROOM, []{return true;}), + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_STALFOS_ROOM, []{return Here(RR_GERUDO_TRAINING_GROUND_MQ_LEFT_SIDE, []{return logic->CanUse(RG_LONGSHOT) || ctx->GetTrickOption(RT_GTG_MQ_WIHTOUT_HOOKSHOT) || (ctx->GetTrickOption(RT_GTG_MQ_WITH_HOOKSHOT) && logic->IsAdult && logic->CanJumpslash() && logic->CanUse(RG_HOOKSHOT));});}), + }); + + areaTable[RR_GERUDO_TRAINING_GROUND_MQ_STALFOS_ROOM] = Region("Gerudo Training Ground MQ Stalfos Room", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->BlueFireAccess, []{return true;}), + }, { + //Locations + //implies logic->CanKillEnemy(RE_BIG_SKULLTULA) + LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_BEFORE_HEAVY_BLOCK_CHEST, logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2, true)), + }, { + //Exits + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_BEHIND_BLOCK, []{return Here(RR_GERUDO_TRAINING_GROUND_MQ_STALFOS_ROOM, []{return logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2, true);}) && logic->CanUse(RG_SILVER_GAUNTLETS);}), + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_STATUE_ROOM_LEDGE, []{return logic->IsAdult && Here(RR_GERUDO_TRAINING_GROUND_MQ_STALFOS_ROOM, []{return logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2, true);}) && (ctx->GetTrickOption(RT_LENS_GTG_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)) && logic->BlueFire() && (logic->CanUse(RG_SONG_OF_TIME) || (ctx->GetTrickOption(RT_GTG_FAKE_WALL) && logic->CanUse(RG_HOVER_BOOTS)));}), + }); + + areaTable[RR_GERUDO_TRAINING_GROUND_MQ_BEHIND_BLOCK] = Region("Gerudo Training Ground MQ Behind Block", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + //implies logic->CanKillEnemy(RE_SPIKE) + LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_HEAVY_BLOCK_CHEST, logic->CanKillEnemy(RE_FREEZARD)), + }, {}); + + areaTable[RR_GERUDO_TRAINING_GROUND_MQ_STATUE_ROOM_LEDGE] = Region("Gerudo Training Ground MQ Statue Room Ledge", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_STALFOS_ROOM, []{return true;}), + //implies dropping down to hit the switch. Using swords, especially master, is a bit awkward, may be trick worthy, but is only relevant with other tricks + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_MAGENTA_FIRE_ROOM, []{return Here(RR_GERUDO_TRAINING_GROUND_MQ_STATUE_ROOM_LEDGE, []{return logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_STICKS) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_BOOMERANG);});}), + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_STATUE_ROOM, []{return true;}), + }); + + areaTable[RR_GERUDO_TRAINING_GROUND_MQ_MAGENTA_FIRE_ROOM] = Region("Gerudo Training Ground MQ Magenta Fire Room", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_ICE_ARROWS_CHEST, logic->MQGTGMazeSwitch), + }, { + //Exits + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_STATUE_ROOM_LEDGE, []{return true;}), + }); + + areaTable[RR_GERUDO_TRAINING_GROUND_MQ_STATUE_ROOM] = Region("Gerudo Training Ground MQ Statue ROom", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_EYE_STATUE_CHEST, logic->CanUse(RG_FAIRY_BOW)), + }, { + //Exits + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_STATUE_ROOM_LEDGE, []{return logic->CanUse(RG_LONGSHOT);}), + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_TORCH_SLUG_ROOM, []{return true;}), + }); + + areaTable[RR_GERUDO_TRAINING_GROUND_MQ_TORCH_SLUG_ROOM] = Region("Gerudo Training Ground MQ Torch Slug Room", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + //implies logic->CanKillEnemy(RE_TORCH_SLUG) + LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_SECOND_IRON_KNUCKLE_CHEST, logic->CanKillEnemy(RE_IRON_KNUCKLE)), + LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_FLAME_CIRCLE_CHEST, logic->CanHitSwitch(ED_BOMB_THROW)), + }, { + //Exits + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_STATUE_ROOM, []{return Here(RR_GERUDO_TRAINING_GROUND_MQ_TORCH_SLUG_ROOM, []{return logic->CanKillEnemy(RE_IRON_KNUCKLE);});}), + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_SWITCH_LEDGE, []{return Here(RR_GERUDO_TRAINING_GROUND_MQ_TORCH_SLUG_ROOM, []{return logic->CanKillEnemy(RE_IRON_KNUCKLE);});}), + }); + + areaTable[RR_GERUDO_TRAINING_GROUND_MQ_SWITCH_LEDGE] = Region("Gerudo Training Ground MQ Switch Ledge", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->MQGTGRightSideSwitch, []{return logic->CanUse(RG_MEGATON_HAMMER);}), + EventAccess(&logic->GTGPlatformSilverRupees, []{return logic->CanUse(RG_FIRE_ARROWS) && logic->CanUse(RG_HOVER_BOOTS);}), + }, { + //Locations + LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_DINOLFOS_CHEST, logic->IsAdult && (logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_BIGGORON_SWORD))), + }, { + //Exits + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_LEDGE_SIDE_PLATFORMS, []{return logic->CanUse(RG_FIRE_ARROWS);}), + //the fire bubble here is a jerk if you are aiming for the nearest hook platform, you have to aim to the right hand side with hook to dodge it + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_PLATFORMS_UNLIT_TORCH, []{return logic->CanUse(RG_LONGSHOT) || (logic->GTGPlatformSilverRupees && logic->CanUse(RG_HOOKSHOT)) || ((logic->CanUse(RG_FIRE_ARROWS) && logic->GTGPlatformSilverRupees) && logic->CanUse(RG_HOVER_BOOTS));}), + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_MAZE_RIGHT, []{return logic->MQGTGRightSideSwitch && logic->CanUse(RG_LONGSHOT);}), + }); + + //this region exists to place silver rupee items on later, normally it's all on fire and cannot be stood on without access from another area + //This covers the 2 platforms that can be jumped to directly from RR_GERUDO_TRAINING_GROUND_MQ_SWITCH_LEDGE + //the unshuffled rupee collection is handled by the event GTGPlatformSilverRupees + areaTable[RR_GERUDO_TRAINING_GROUND_MQ_LEDGE_SIDE_PLATFORMS] = Region("Gerudo Training Ground MQ Ledge Side Platforms", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + //This is merely to extend this region's logic if you have hovers + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_FURTHEST_PLATFORM, []{return logic->CanUse(RG_HOVER_BOOTS);}), + }); + + //this region exists to place silver rupee items on later, normally it's all on fire and cannot be stood on without access from another area + //This covers the platform that needs hover boots or the spawned targets to reach from any starting point other than RR_GERUDO_TRAINING_GROUND_MQ_MAZE_RIGHT + //the unshuffled rupee collection is handled by the event GTGPlatformSilverRupees + areaTable[RR_GERUDO_TRAINING_GROUND_MQ_FURTHEST_PLATFORM] = Region("Gerudo Training Ground MQ Furthest Platform", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + //This is merely to extend this region's logic if you have hovers + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_LEDGE_SIDE_PLATFORMS, []{return logic->CanUse(RG_HOVER_BOOTS);}), + }); + + areaTable[RR_GERUDO_TRAINING_GROUND_MQ_PLATFORMS_UNLIT_TORCH] = Region("Gerudo Training Ground MQ Platforms Unlit Torch", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->GTGPlatformSilverRupees, []{return logic->HasFireSource() && logic->CanUse(RG_HOVER_BOOTS);}), + }, {}, { + //Exits + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_UNDERWATER, []{return logic->GTGPlatformSilverRupees;}), + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_LEDGE_SIDE_PLATFORMS, []{return logic->HasFireSource() && logic->CanUse(RG_HOVER_BOOTS);}), + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_TORCH_SIDE_PLATFORMS, []{return logic->HasFireSource() || logic->CanUse(RG_LONGSHOT);}), + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_MAZE_RIGHT, []{return logic->MQGTGRightSideSwitch && (logic->CanUse(RG_LONGSHOT) || (logic->CanUse(RG_HOOKSHOT) && logic->HasFireSource()));}), + }); + + areaTable[RR_GERUDO_TRAINING_GROUND_MQ_TORCH_SIDE_PLATFORMS] = Region("Gerudo Training Ground Torch Side Platforms", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, { + //Events + //this torch shot is possible as child but tight and obtuse enough to be a trick + EventAccess(&logic->GTGPlatformSilverRupees, []{return ((logic->CanUse(RG_FAIRY_BOW) && logic->IsAdult) || logic->CanUse(RG_FIRE_ARROWS)) && logic->CanUse(RG_HOVER_BOOTS);}), + }, {}, { + //Exits + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_LEDGE_SIDE_PLATFORMS, []{return ((logic->CanUse(RG_FAIRY_BOW) && logic->IsAdult) || logic->CanUse(RG_FIRE_ARROWS)) && logic->CanUse(RG_HOVER_BOOTS);}), + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_PLATFORMS_UNLIT_TORCH, []{return (logic->CanUse(RG_FAIRY_BOW) && logic->IsAdult) || logic->CanUse(RG_FIRE_ARROWS) || logic->CanUse(RG_LONGSHOT);}), + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_MAZE_RIGHT, []{return logic->MQGTGRightSideSwitch && ((logic->CanUse(RG_FAIRY_BOW) && logic->IsAdult) || logic->CanUse(RG_FIRE_ARROWS) || logic->CanUse(RG_LONGSHOT));}), + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_DINOLFOS_ROOM, []{return true;}), + }); + + areaTable[RR_GERUDO_TRAINING_GROUND_MQ_UNDERWATER] = Region("Gerudo Training Ground MQ Underwater", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + //it is possible to snipe the stingers with bow or sling before dropping in, or just get really lucky, and avoid needing to take damage, but that might be trick worthy + LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_UNDERWATER_SILVER_RUPEE_CHEST, logic->HasFireSource() && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 24 && logic->TakeDamage()), + }, { + //Exits + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_PLATFORMS_UNLIT_TORCH, []{return true;}), + }); + + + areaTable[RR_GERUDO_TRAINING_GROUND_MQ_MAZE_RIGHT] = Region("Gerudo Training Ground MQ Maze Right", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->GTGPlatformSilverRupees, []{return logic->CanUse(RG_FIRE_ARROWS) && logic->CanUse(RG_HOVER_BOOTS);}), + }, { + //Locations + LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_MAZE_RIGHT_CENTRAL_CHEST, true), + LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_MAZE_RIGHT_SIDE_CHEST, true), + }, { + //Exits + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_LOBBY, []{return true;}), + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_LEDGE_SIDE_PLATFORMS, []{return logic->CanUse(RG_FIRE_ARROWS) || logic->CanUse(RG_LONGSHOT);}), + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_PLATFORMS_UNLIT_TORCH, []{return logic->CanUse(RG_FIRE_ARROWS) || logic->CanUse(RG_LONGSHOT) || (logic->GTGPlatformSilverRupees && logic->CanUse(RG_HOVER_BOOTS));}), + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_LEDGE_SIDE_PLATFORMS, []{return logic->CanUse(RG_FIRE_ARROWS);}), + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_FURTHEST_PLATFORM, []{return logic->CanUse(RG_FIRE_ARROWS);}), + }); + + areaTable[RR_GERUDO_TRAINING_GROUND_MQ_DINOLFOS_ROOM] = Region("Gerudo Training Ground MQ Dinolfos Room", "Gerudo Training Ground", {RA_GERUDO_TRAINING_GROUND}, NO_DAY_NIGHT_CYCLE, { + //Events + //EventAccess(&WallFairy, []{return WallFairy || (logic->IsAdult && logic->CanUse(RG_FAIRY_BOW));}), + }, { + //Locations + //implies logic->CanKillEnemy(RE_LIZALFOS and logic->CanKillEnemy(RE_DODONGO) + //is logic->CanKillEnemy(RE_DINOLFOS, ED_CLOSE, true, 2, true) && logic->CanKillEnemy(RE_ARMOS, ED_CLOSE, true, 1, true) broken down to exclude sticks, as it take too many to clear the room + //Proper enemy kill room ammo logic is needed to handle this room + //some combinations may be impossible without taking damage, keep an eye out for issues here + LOCATION(RC_GERUDO_TRAINING_GROUND_MQ_DINOLFOS_CHEST, logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MEGATON_HAMMER) || logic->CanUse(RG_FAIRY_BOW) || ((logic->CanUse(RG_NUTS) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_BOOMERANG)) && (logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_FAIRY_SLINGSHOT)))), + }, { + //Exits + Entrance(RR_GERUDO_TRAINING_GROUND_MQ_TORCH_SIDE_PLATFORMS, []{return Here(RR_GERUDO_TRAINING_GROUND_MQ_DINOLFOS_ROOM, []{return logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_MEGATON_HAMMER) || logic->CanUse(RG_FAIRY_BOW) || ((logic->CanUse(RG_NUTS) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_BOOMERANG)) && (logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_FAIRY_SLINGSHOT)));});}), + }); + +#pragma endregion +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/ice_cavern.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/ice_cavern.cpp new file mode 100644 index 000000000..ff9b171c8 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/ice_cavern.cpp @@ -0,0 +1,147 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" +#include "soh/Enhancements/randomizer/dungeon.h" + +using namespace Rando; + +void RegionTable_Init_IceCavern() { + // Vanilla/MQ Decider + areaTable[RR_ICE_CAVERN_ENTRYWAY] = Region("Ice Cavern Entryway", "Ice Cavern", {RA_ICE_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_ICE_CAVERN_BEGINNING, []{return ctx->GetDungeon(ICE_CAVERN)->IsVanilla();}), + Entrance(RR_ICE_CAVERN_MQ_BEGINNING, []{return ctx->GetDungeon(ICE_CAVERN)->IsMQ() && logic->CanUseProjectile();}), + Entrance(RR_ZORAS_FOUNTAIN, []{return true;}), + }); + +#pragma region Vanilla + + areaTable[RR_ICE_CAVERN_BEGINNING] = Region("Ice Cavern Beginning", "Ice Cavern", {RA_ICE_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_ICE_CAVERN_ENTRANCE_STORMS_FAIRY, logic->CanUse(RG_SONG_OF_STORMS)), + }, { + //Exits + Entrance(RR_ICE_CAVERN_ENTRYWAY, []{return true;}), + Entrance(RR_ICE_CAVERN_MAIN, []{return Here(RR_ICE_CAVERN_BEGINNING, []{return (logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD)) || logic->CanUse(RG_MEGATON_HAMMER) || logic->HasExplosives() || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_DINS_FIRE);});}), + }); + + areaTable[RR_ICE_CAVERN_MAIN] = Region("Ice Cavern", "Ice Cavern", {RA_ICE_CAVERN}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->BlueFireAccess, []{return logic->BlueFireAccess || (logic->IsAdult && logic->HasBottle());}), + }, { + //Locations + LOCATION(RC_ICE_CAVERN_MAP_CHEST, logic->BlueFire() && logic->IsAdult), + LOCATION(RC_ICE_CAVERN_COMPASS_CHEST, logic->BlueFire()), + LOCATION(RC_ICE_CAVERN_IRON_BOOTS_CHEST, logic->BlueFire() && (logic->CanJumpslash() || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_DINS_FIRE))), + LOCATION(RC_SHEIK_IN_ICE_CAVERN, logic->BlueFire() && (logic->CanJumpslash() || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_DINS_FIRE)) && logic->IsAdult), + LOCATION(RC_ICE_CAVERN_FREESTANDING_POH, logic->BlueFire()), + LOCATION(RC_ICE_CAVERN_GS_SPINNING_SCYTHE_ROOM, logic->HookshotOrBoomerang()), + LOCATION(RC_ICE_CAVERN_GS_HEART_PIECE_ROOM, logic->BlueFire() && logic->HookshotOrBoomerang()), + LOCATION(RC_ICE_CAVERN_GS_PUSH_BLOCK_ROOM, logic->BlueFire() && (logic->HookshotOrBoomerang() || (ctx->GetTrickOption(RT_ICE_BLOCK_GS) && logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)))), + LOCATION(RC_ICE_CAVERN_HALL_POT_1, logic->CanBreakPots()), + LOCATION(RC_ICE_CAVERN_HALL_POT_2, logic->CanBreakPots()), + LOCATION(RC_ICE_CAVERN_SPINNING_BLADE_POT_1, logic->CanBreakPots()), + LOCATION(RC_ICE_CAVERN_SPINNING_BLADE_POT_2, logic->CanBreakPots()), + LOCATION(RC_ICE_CAVERN_SPINNING_BLADE_POT_3, logic->CanBreakPots()), + LOCATION(RC_ICE_CAVERN_NEAR_END_POT_1, logic->CanBreakPots() && logic->BlueFire()), + LOCATION(RC_ICE_CAVERN_NEAR_END_POT_2, logic->CanBreakPots() && logic->BlueFire()), + LOCATION(RC_ICE_CAVERN_FROZEN_POT_1, logic->CanBreakPots() && logic->BlueFire() && logic->IsAdult), + LOCATION(RC_ICE_CAVERN_LOBBY_RUPEE, logic->BlueFire()), + LOCATION(RC_ICE_CAVERN_MAP_ROOM_LEFT_HEART, logic->IsAdult), + LOCATION(RC_ICE_CAVERN_MAP_ROOM_MIDDLE_HEART, logic->IsAdult), + LOCATION(RC_ICE_CAVERN_MAP_ROOM_RIGHT_HEART, logic->IsAdult), + LOCATION(RC_ICE_CAVERN_SLIDING_BLOCK_RUPEE_1, logic->BlueFire() && (logic->CanUse(RG_SONG_OF_TIME) || logic->CanUse(RG_BOOMERANG))), + LOCATION(RC_ICE_CAVERN_SLIDING_BLOCK_RUPEE_2, logic->BlueFire() && (logic->CanUse(RG_SONG_OF_TIME) || logic->CanUse(RG_BOOMERANG))), + LOCATION(RC_ICE_CAVERN_SLIDING_BLOCK_RUPEE_3, logic->BlueFire() && (logic->CanUse(RG_SONG_OF_TIME) || logic->CanUse(RG_BOOMERANG))), + }, {}); + +#pragma endregion + +#pragma region MQ + + areaTable[RR_ICE_CAVERN_MQ_BEGINNING] = Region("Ice Cavern MQ Beginning", "Ice Cavern", {RA_ICE_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_ICE_CAVERN_MQ_ENTRANCE_POT, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_ICE_CAVERN_ENTRYWAY, []{return true;}), + //It is in logic to use a pot to hit the toggle switch here. + Entrance(RR_ICE_CAVERN_MQ_HUB, []{return true;}), + }); + + areaTable[RR_ICE_CAVERN_MQ_HUB] = Region("Ice Cavern MQ Hub", "Ice Cavern", {RA_ICE_CAVERN}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->FairyPot, []{return true;}), + }, { + //Locations + LOCATION(RC_ICE_CAVERN_MQ_FIRST_CRYSTAL_POT_1, logic->CanBreakPots()), + LOCATION(RC_ICE_CAVERN_MQ_FIRST_CRYSTAL_POT_2, logic->CanBreakPots()), + LOCATION(RC_ICE_CAVERN_MQ_EARLY_WOLFOS_POT_1, logic->CanBreakPots()), + LOCATION(RC_ICE_CAVERN_MQ_EARLY_WOLFOS_POT_2, logic->CanBreakPots()), + LOCATION(RC_ICE_CAVERN_MQ_EARLY_WOLFOS_POT_3, logic->CanBreakPots()), + LOCATION(RC_ICE_CAVERN_MQ_EARLY_WOLFOS_POT_4, logic->CanBreakPots()), + }, { + //Exits + //the switch for the glass blocking the entrance is linked to the switch that controls the glass around the skulltulla in RR_ICE_CAVERN_MQ_SCARECROW_ROOM + //if you clear the ice, you can hit it with a pot from here. + Entrance(RR_ICE_CAVERN_BEGINNING, []{return logic->BlueFire();}), + Entrance(RR_ICE_CAVERN_MQ_MAP_ROOM, []{return Here(RR_ICE_CAVERN_MQ_BEGINNING, []{return logic->CanKillEnemy(RE_WHITE_WOLFOS) && logic->CanKillEnemy(RE_FREEZARD);});}), + Entrance(RR_ICE_CAVERN_MQ_COMPASS_ROOM, []{return logic->IsAdult && logic->BlueFire();}), + Entrance(RR_ICE_CAVERN_MQ_SCARECROW_ROOM, []{return logic->BlueFire();}), + }); + + areaTable[RR_ICE_CAVERN_MQ_MAP_ROOM] = Region("Ice Cavern MQ Map Room", "Ice Cavern", {RA_ICE_CAVERN}, NO_DAY_NIGHT_CYCLE, { + //Events + //Child can fit between the stalagmites on the left hand side + EventAccess(&logic->BlueFireAccess, []{return logic->IsChild || logic->CanJumpslash() || logic->HasExplosives();}), + }, { + //Locations + LOCATION(RC_ICE_CAVERN_MQ_MAP_CHEST, logic->BlueFire() && Here(RR_ICE_CAVERN_MQ_MAP_ROOM, []{return logic->CanHitSwitch();})), + }, {}); + + areaTable[RR_ICE_CAVERN_MQ_SCARECROW_ROOM] = Region("Ice Cavern MQ Scarecrow Room", "Ice Cavern", {RA_ICE_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_ICE_CAVERN_MQ_GS_ICE_BLOCK, (logic->BlueFire() && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)) || (logic->IsAdult && logic->CanHitSwitch(ED_LONG_JUMPSLASH))), + LOCATION(RC_ICE_CAVERN_MQ_GS_SCARECROW, logic->CanUse(RG_SCARECROW) || (logic->IsAdult && (logic->CanUse(RG_LONGSHOT) || ctx->GetTrickOption(RT_ICE_MQ_SCARECROW)))), + }, { + //Exits + Entrance(RR_ICE_CAVERN_MQ_HUB, []{return logic->BlueFire();}), + //Assumes RR_ICE_CAVERN_MQ_HUB access for a pot if using blue fire + Entrance(RR_ICE_CAVERN_MQ_WEST_CORRIDOR, []{return logic->IsAdult && logic->BlueFire();}), + }); + + areaTable[RR_ICE_CAVERN_MQ_WEST_CORRIDOR] = Region("Ice Cavern MQ West Corridor", "Ice Cavern", {RA_ICE_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_ICE_CAVERN_MQ_PUSH_BLOCK_POT_1, logic->CanBreakPots()), + LOCATION(RC_ICE_CAVERN_MQ_PUSH_BLOCK_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_ICE_CAVERN_MQ_SCARECROW_ROOM, []{return logic->BlueFire();}), + Entrance(RR_ICE_CAVERN_MQ_STALFOS_ROOM, []{return true;}), + }); + + areaTable[RR_ICE_CAVERN_MQ_STALFOS_ROOM] = Region("Ice Cavern MQ Stalfos Room", "Ice Cavern", {RA_ICE_CAVERN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_ICE_CAVERN_MQ_IRON_BOOTS_CHEST, logic->CanKillEnemy(RE_STALFOS)), + LOCATION(RC_SHEIK_IN_ICE_CAVERN, logic->CanKillEnemy(RE_STALFOS)), + }, { + //Exits + Entrance(RR_ICE_CAVERN_MQ_SCARECROW_ROOM, []{return logic->BlueFire() && Here(RR_ICE_CAVERN_MQ_STALFOS_ROOM, []{return logic->CanKillEnemy(RE_STALFOS);});}), + Entrance(RR_ICE_CAVERN_MQ_BEGINNING, []{return logic->CanUse(RG_IRON_BOOTS) && Here(RR_ICE_CAVERN_MQ_STALFOS_ROOM, []{return logic->CanKillEnemy(RE_STALFOS);});}), + }); + + areaTable[RR_ICE_CAVERN_MQ_COMPASS_ROOM] = Region("Ice Cavern MQ Compass Room", "Ice Cavern", {RA_ICE_CAVERN}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->BlueFireAccess, []{return true;}), + }, { + //Locations + LOCATION(RC_ICE_CAVERN_MQ_COMPASS_CHEST, true), + //It is possible for child with master, BGS or sticks, or adult with BGS, to hit this switch through the ice with a crouchstab, but it's precise and unintuitive for a trick + LOCATION(RC_ICE_CAVERN_MQ_FREESTANDING_POH, logic->HasExplosives()), + //doing RT_ICE_MQ_RED_ICE_GS as child is untested, as I could not perform the trick reliably even as adult + LOCATION(RC_ICE_CAVERN_MQ_GS_RED_ICE, (ctx->GetOption(RSK_BLUE_FIRE_ARROWS) && logic->CanUse(RG_ICE_ARROWS)) || (logic->CanUse(RG_BOTTLE_WITH_BLUE_FIRE) && (logic->CanUse(RG_SONG_OF_TIME) || (logic->IsAdult && ctx->GetTrickOption(RT_ICE_MQ_RED_ICE_GS))) && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA))), + LOCATION(RC_ICE_CAVERN_MQ_COMPASS_POT_1, logic->CanBreakPots()), + LOCATION(RC_ICE_CAVERN_MQ_COMPASS_POT_2, logic->CanBreakPots()), + }, {}); + +#pragma endregion +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/jabujabus_belly.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/jabujabus_belly.cpp new file mode 100644 index 000000000..fe043caa3 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/jabujabus_belly.cpp @@ -0,0 +1,360 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" +#include "soh/Enhancements/randomizer/dungeon.h" + +using namespace Rando; + +void RegionTable_Init_JabuJabusBelly() { + // Vanilla/MQ Decider + areaTable[RR_JABU_JABUS_BELLY_ENTRYWAY] = Region("Jabu Jabus Belly Entryway", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_JABU_JABUS_BELLY_BEGINNING, []{return ctx->GetDungeon(JABU_JABUS_BELLY)->IsVanilla();}), + Entrance(RR_JABU_JABUS_BELLY_MQ_BEGINNING, []{return ctx->GetDungeon(JABU_JABUS_BELLY)->IsMQ();}), + Entrance(RR_ZORAS_FOUNTAIN, []{return true;}), + }); + +#pragma region Vanilla + + areaTable[RR_JABU_JABUS_BELLY_BEGINNING] = Region("Jabu Jabus Belly Beginning", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_JABU_JABUS_BELLY_ENTRYWAY, []{return true;}), + Entrance(RR_JABU_JABUS_BELLY_MAIN, []{return logic->CanUseProjectile();}), + }); + + //Combines Lift room middle and lower, 1F holes room, the forked corridor, and it's side rooms + areaTable[RR_JABU_JABUS_BELLY_MAIN] = Region("Jabu Jabus Belly Main", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->JabuRutoInB1, []{return true;}), + EventAccess(&logic->JabuWestTentacle, []{return logic->JabuRutoIn1F && logic->CanKillEnemy(RE_TENTACLE, ED_BOOMERANG);}), + }, { + //Locations + LOCATION(RC_JABU_JABUS_BELLY_DEKU_SCRUB, logic->HasItem(RG_BRONZE_SCALE) && (logic->IsChild || logic->HasItem(RG_SILVER_SCALE) || ctx->GetTrickOption(RT_JABU_ALCOVE_JUMP_DIVE) || logic->CanUse(RG_IRON_BOOTS)) && logic->CanStunDeku()), + //We can kill the Stingers with ruto + LOCATION(RC_JABU_JABUS_BELLY_BOOMERANG_CHEST, logic->JabuRutoIn1F), + LOCATION(RC_JABU_JABUS_BELLY_MAP_CHEST, logic->JabuWestTentacle), + }, { + //Exits + Entrance(RR_JABU_JABUS_BELLY_BEGINNING, []{return true;}), + Entrance(RR_JABU_JABUS_BELLY_B1_NORTH, []{return true;}), + Entrance(RR_JABU_JABUS_BELLY_COMPASS_ROOM, []{return logic->JabuWestTentacle;}), + Entrance(RR_JABU_JABUS_BELLY_BLUE_TENTACLE, []{return logic->JabuWestTentacle;}), + Entrance(RR_JABU_JABUS_BELLY_GREEN_TENTACLE, []{return logic->JabuEastTentacle;}), + Entrance(RR_JABU_JABUS_BELLY_BIGOCTO_LEDGE, []{return logic->JabuNorthTentacle;}), + Entrance(RR_JABU_JABUS_BELLY_NEAR_BOSS_ROOM, []{return logic->LoweredJabuPath || (ctx->GetTrickOption(RT_JABU_BOSS_HOVER) && logic->CanUse(RG_HOVER_BOOTS));}), + }); + + //contains B1 of hole room (aside from the ledge leading to big octo), 2 octorock room and north water switch room + areaTable[RR_JABU_JABUS_BELLY_B1_NORTH] = Region("Jabu Jabus Belly B1 North", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->JabuRutoIn1F, []{return logic->IsAdult || logic->HasItem(RG_BRONZE_SCALE);}), + EventAccess(&logic->FairyPot, []{return logic->CanUse(RG_BOOMERANG) || (logic->CanUse(RG_HOVER_BOOTS) && logic->CanKillEnemy(RE_OCTOROK));}), + }, { + //Locations + LOCATION(RC_JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_LOWER, logic->HookshotOrBoomerang()), + LOCATION(RC_JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_UPPER, logic->HookshotOrBoomerang()), + LOCATION(RC_JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM, logic->HookshotOrBoomerang()), + LOCATION(RC_JABU_JABUS_BELLY_TWO_OCTOROK_POT_1, (logic->CanBreakPots() && (logic->CanUse(RG_BOOMERANG) || (logic->CanUse(RG_HOVER_BOOTS) && logic->CanKillEnemy(RE_OCTOROK, ED_BOOMERANG, false))))), + LOCATION(RC_JABU_JABUS_BELLY_TWO_OCTOROK_POT_2, (logic->CanBreakPots() && (logic->CanUse(RG_BOOMERANG) || (logic->CanUse(RG_HOVER_BOOTS) && logic->CanKillEnemy(RE_OCTOROK, ED_BOOMERANG, false))))), + LOCATION(RC_JABU_JABUS_BELLY_TWO_OCTOROK_POT_3, (logic->CanBreakPots() && (logic->CanUse(RG_BOOMERANG) || (logic->CanUse(RG_HOVER_BOOTS) && logic->CanKillEnemy(RE_OCTOROK, ED_BOOMERANG, false))))), + LOCATION(RC_JABU_JABUS_BELLY_TWO_OCTOROK_POT_4, (logic->CanBreakPots() && (logic->CanUse(RG_BOOMERANG) || (logic->CanUse(RG_HOVER_BOOTS) && logic->CanKillEnemy(RE_OCTOROK, ED_BOOMERANG, false))))), + LOCATION(RC_JABU_JABUS_BELLY_TWO_OCTOROK_POT_5, (logic->CanBreakPots() && (logic->CanUse(RG_BOOMERANG) || (logic->CanUse(RG_HOVER_BOOTS) && logic->CanKillEnemy(RE_OCTOROK, ED_BOOMERANG, false))))), + }, { + //Exits + Entrance(RR_JABU_JABUS_BELLY_MAIN, []{return true;}), + //there's tricks for getting here with bunny-jumps or just side-hops + Entrance(RR_JABU_JABUS_BELLY_WATER_SWITCH_ROOM_LEDGE, []{return logic->HasItem(RG_BRONZE_SCALE) || logic->HasItem(RG_HOVER_BOOTS);}), + Entrance(RR_JABU_JABUS_BELLY_WATER_SWITCH_ROOM_SOUTH, []{return logic->IsAdult || logic->HasItem(RG_BRONZE_SCALE);}), + }); + + areaTable[RR_JABU_JABUS_BELLY_WATER_SWITCH_ROOM_LEDGE] = Region("Jabu Jabus Belly Water Switch Room Ledge", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->FairyPot, []{return true;}), + }, { + //Locations + //this is the logic for climbing back and forth to use the pots to kill the skull... or killing the skull before climbing to grab the token + LOCATION(RC_JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM, logic->HasItem(RG_BRONZE_SCALE) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)) || logic->CanKillEnemy(RE_GOLD_SKULLTULA, ED_BOMB_THROW)), + LOCATION(RC_JABU_JABUS_BELLY_BASEMENT_POT_1, logic->CanBreakPots()), + LOCATION(RC_JABU_JABUS_BELLY_BASEMENT_POT_2, logic->CanBreakPots()), + LOCATION(RC_JABU_JABUS_BELLY_BASEMENT_POT_3, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_JABU_JABUS_BELLY_B1_NORTH, []{return true;}), + Entrance(RR_JABU_JABUS_BELLY_WATER_SWITCH_ROOM_SOUTH, []{return true;}), + }); + + areaTable[RR_JABU_JABUS_BELLY_WATER_SWITCH_ROOM_SOUTH] = Region("Jabu Jabus Belly Water Switch Room South", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_JABU_JABUS_BELLY_GS_WATER_SWITCH_ROOM, logic->HookshotOrBoomerang()), + }, { + //Exits + Entrance(RR_JABU_JABUS_BELLY_B1_NORTH, []{return logic->IsAdult || logic->HasItem(RG_BRONZE_SCALE);}), + Entrance(RR_JABU_JABUS_BELLY_WATER_SWITCH_ROOM_LEDGE, []{return logic->HasItem(RG_BRONZE_SCALE) || logic->HasItem(RG_HOVER_BOOTS);}), + Entrance(RR_JABU_JABUS_BELLY_MAIN, []{return logic->CanUseProjectile();}), + }); + + areaTable[RR_JABU_JABUS_BELLY_COMPASS_ROOM] = Region("Jabu Jabus Belly Compass Room", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + //ruto could theoretically clear this room, but it's hard because of the timer and she doesn't appear with you when you respawn after failing, which would force a savewarp + LOCATION(RC_JABU_JABUS_BELLY_COMPASS_CHEST, logic->CanKillEnemy(RE_SHABOM)), + }, { + //Exits + Entrance(RR_JABU_JABUS_BELLY_MAIN, []{return Here(RR_JABU_JABUS_BELLY_COMPASS_ROOM, []{return logic->CanKillEnemy(RE_SHABOM);});}), + }); + + areaTable[RR_JABU_JABUS_BELLY_BLUE_TENTACLE] = Region("Jabu Jabus Belly Blue Tentacle", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->JabuEastTentacle, []{return logic->CanKillEnemy(RE_TENTACLE, ED_BOOMERANG);}), + }, {}, { + //Exits + Entrance(RR_JABU_JABUS_BELLY_MAIN, []{return logic->JabuEastTentacle;}), + }); + + areaTable[RR_JABU_JABUS_BELLY_GREEN_TENTACLE] = Region("Jabu Jabus Belly Green Tentacle", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->JabuNorthTentacle, []{return logic->CanKillEnemy(RE_TENTACLE, ED_BOOMERANG);}), + }, {}, { + //Exits + //implied logic->CanKillEnemy(RE_BARI) + Entrance(RR_JABU_JABUS_BELLY_MAIN, []{return logic->JabuNorthTentacle;}), + }); + + areaTable[RR_JABU_JABUS_BELLY_BIGOCTO_LEDGE] = Region("Jabu Jabus Belly Bigocto Room", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + //Only adult can get the token without assistance + LOCATION(RC_JABU_JABUS_BELLY_GS_LOBBY_BASEMENT_UPPER, logic->IsAdult && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_SHORT_JUMPSLASH)), + //You can get the LOWER skull token from here as aduly with hovers backwalk and a backflip, but it's trickworthy and not relevant unless you can beat tentacles without rang + }, { + //Exits + Entrance(RR_JABU_JABUS_BELLY_B1_NORTH, []{return true;}), + Entrance(RR_JABU_JABUS_BELLY_ABOVE_BIGOCTO, []{return logic->JabuRutoIn1F && Here(RR_JABU_JABUS_BELLY_BIGOCTO_LEDGE, []{return logic->CanKillEnemy(RE_BIG_OCTO);});}), + }); + + areaTable[RR_JABU_JABUS_BELLY_ABOVE_BIGOCTO] = Region("Jabu Jabus Belly Above Bigocto", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->FairyPot, []{return true;}), + EventAccess(&logic->NutPot, []{return true;}), + }, { + //Locations + LOCATION(RC_JABU_JABUS_BELLY_ABOVE_BIG_OCTO_POT_1, logic->CanBreakPots()), + LOCATION(RC_JABU_JABUS_BELLY_ABOVE_BIG_OCTO_POT_2, logic->CanBreakPots()), + LOCATION(RC_JABU_JABUS_BELLY_ABOVE_BIG_OCTO_POT_3, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_JABU_JABUS_BELLY_LIFT_UPPER, []{return logic->CanUse(RG_BOOMERANG);}), + }); + + areaTable[RR_JABU_JABUS_BELLY_LIFT_UPPER] = Region("Jabu Jabus Belly Lift Upper", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->LoweredJabuPath, []{return true;}), + }, {}, { + //Exits + Entrance(RR_JABU_JABUS_BELLY_MAIN, []{return true;}), + }); + + areaTable[RR_JABU_JABUS_BELLY_NEAR_BOSS_ROOM] = Region("Jabu Jabus Belly Near Boss Room", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_JABU_JABUS_BELLY_GS_NEAR_BOSS, logic->CanKillEnemy(RE_GOLD_SKULLTULA, ED_BOMB_THROW)), + }, { + //Exits + Entrance(RR_JABU_JABUS_BELLY_MAIN, []{return true;}), + Entrance(RR_JABU_JABUS_BELLY_BOSS_ENTRYWAY, []{return logic->CanUse(RG_BOOMERANG) || (ctx->GetTrickOption(RT_JABU_NEAR_BOSS_RANGED) && (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT))) || (ctx->GetTrickOption(RT_JABU_NEAR_BOSS_EXPLOSIVES) && (logic->CanUse(RG_BOMBCHU_5) || (logic->CanUse(RG_HOVER_BOOTS) && logic->CanUse(RG_BOMB_BAG))));}), + }); + +#pragma endregion + +#pragma region MQ + + areaTable[RR_JABU_JABUS_BELLY_MQ_BEGINNING] = Region("Jabu Jabus Belly MQ Beginning", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->NutPot, []{return true;}), + }, { + //Locations + LOCATION(RC_JABU_JABUS_BELLY_MQ_MAP_CHEST, logic->BlastOrSmash()), + LOCATION(RC_JABU_JABUS_BELLY_MQ_FIRST_ROOM_SIDE_CHEST, logic->CanUse(RG_FAIRY_SLINGSHOT)), + LOCATION(RC_JABU_JABUS_BELLY_MQ_ENTRANCE_POT_1, logic->CanBreakPots()), + LOCATION(RC_JABU_JABUS_BELLY_MQ_ENTRANCE_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_JABU_JABUS_BELLY_ENTRYWAY, []{return true;}), + Entrance(RR_JABU_JABUS_BELLY_MQ_LIFT_ROOM, []{return Here(RR_JABU_JABUS_BELLY_MQ_BEGINNING, []{return logic->CanUse(RG_FAIRY_SLINGSHOT);});}), + }); + + areaTable[RR_JABU_JABUS_BELLY_MQ_LIFT_ROOM] = Region("Jabu Jabus Belly MQ Lift Room", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->MQJabuLiftRoomCow, []{return logic->CanUse(RG_FAIRY_SLINGSHOT);}), + }, { + //Locations + LOCATION(RC_JABU_JABUS_BELLY_MQ_SECOND_ROOM_LOWER_CHEST, true), + LOCATION(RC_JABU_JABUS_BELLY_MQ_LIFT_HEART_1, true), + LOCATION(RC_JABU_JABUS_BELLY_MQ_LIFT_HEART_2, true), + LOCATION(RC_JABU_JABUS_BELLY_MQ_LIFT_RUPEE_1, logic->CanUse(RG_IRON_BOOTS)), + LOCATION(RC_JABU_JABUS_BELLY_MQ_LIFT_RUPEE_2, logic->CanUse(RG_IRON_BOOTS)), + LOCATION(RC_JABU_JABUS_BELLY_MQ_LIFT_RUPEE_3, logic->CanUse(RG_IRON_BOOTS)), + }, { + //Exits + Entrance(RR_JABU_JABUS_BELLY_MQ_BEGINNING, []{return true;}), + Entrance(RR_JABU_JABUS_BELLY_MQ_UNDERWATER_ALCOVE, []{return logic->HasItem(RG_SILVER_SCALE) || (logic->HasItem(RG_BRONZE_SCALE) && ((logic->IsChild || logic->CanUse(RG_IRON_BOOTS) || ctx->GetTrickOption(RT_JABU_ALCOVE_JUMP_DIVE))));}), + Entrance(RR_JABU_JABUS_BELLY_MQ_HOLES_ROOM, []{return logic->MQJabuHolesRoomDoor;}), + Entrance(RR_JABU_JABUS_BELLY_MQ_LIFT_ROOM_EAST_LEDGE, []{return logic->LoweredJabuPath || logic->CanUse(RG_HOVER_BOOTS) || (logic->CanUse(RG_HOOKSHOT) && logic->MQJabuLiftRoomCow);}), + //If opening RR_JABU_JABUS_BELLY_MQ_WATER_SWITCH_ROOM by lowering the geyser as 1 age is to let the other through is relevant, it needs an eventAccess + }); + + areaTable[RR_JABU_JABUS_BELLY_MQ_UNDERWATER_ALCOVE] = Region("Jabu Jabus Belly MQ Underwater Alcove", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->MQJabuHolesRoomDoor, []{return true;}), + }, { + //Locations + LOCATION(RC_JABU_JABUS_BELLY_MQ_COMPASS_CHEST, logic->CanHitSwitch(ED_HOOKSHOT, true) || (ctx->GetTrickOption(RT_JABU_MQ_RANG_JUMP) && logic->CanUse(RG_BOOMERANG) && logic->HasItem(RG_BRONZE_SCALE))), + LOCATION(RC_JABU_JABUS_BELLY_MQ_GEYSER_POT_1, logic->CanBreakPots()), + LOCATION(RC_JABU_JABUS_BELLY_MQ_GEYSER_POT_2, logic->CanBreakPots()), + //Getting the ones closest to the ledge with rang may be a trick due to the awkward angle without blind shooting through the flesh + LOCATION(RC_JABU_JABUS_BELLY_MQ_LIFT_RUPEE_1, logic->HasItem(RG_GOLDEN_SCALE) || logic->CanUse(RG_BOOMERANG)), + LOCATION(RC_JABU_JABUS_BELLY_MQ_LIFT_RUPEE_2, logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_BOOMERANG)), + LOCATION(RC_JABU_JABUS_BELLY_MQ_LIFT_RUPEE_3, logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_BOOMERANG)), + }, { + //Exits + Entrance(RR_JABU_JABUS_BELLY_MQ_LIFT_ROOM, []{return logic->HasItem(RG_BRONZE_SCALE);}), + }); + + areaTable[RR_JABU_JABUS_BELLY_MQ_HOLES_ROOM] = Region("Jabu Jabus Belly MQ Holes Room", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_VINES_CHEST, logic->CanUse(RG_FAIRY_SLINGSHOT)), + LOCATION(RC_JABU_JABUS_BELLY_MQ_BASEMENT_NEAR_SWITCHES_CHEST, logic->CanUse(RG_FAIRY_SLINGSHOT)), + }, { + //Exits + Entrance(RR_JABU_JABUS_BELLY_MQ_LIFT_ROOM, []{return true;}), + Entrance(RR_JABU_JABUS_BELLY_MQ_WATER_SWITCH_ROOM, []{return true;}), + Entrance(RR_JABU_JABUS_BELLY_MQ_FORKED_CORRIDOR, []{return logic->CanUse(RG_BOOMERANG) && logic->HasExplosives() && Here(RR_JABU_JABUS_BELLY_MQ_HOLES_ROOM, []{return logic->CanUse(RG_FAIRY_SLINGSHOT);});}), + Entrance(RR_JABU_JABUS_BELLY_MQ_INVISIBLE_KEESE_ROOM, []{return logic->JabuNorthTentacle;}), + Entrance(RR_JABU_JABUS_BELLY_MQ_PAST_OCTO, []{return logic->JabuWestTentacle && Here(RR_JABU_JABUS_BELLY_MQ_HOLES_ROOM, []{return logic->CanKillEnemy(RE_BIG_OCTO);}) && logic->CanUse(RG_FAIRY_SLINGSHOT);}), + }); + + areaTable[RR_JABU_JABUS_BELLY_MQ_WATER_SWITCH_ROOM] = Region("Jabu Jabus Belly MQ Water Switch Room", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_JABU_JABUS_BELLY_MQ_BOOMERANG_ROOM_SMALL_CHEST, true), + //Implies logic->CanKillEnemy(RE_LIKE_LIKE) && logic->CanKillEnemy(RE_STINGER). Without swim, jump from the song of time block to the vines. + LOCATION(RC_JABU_JABUS_BELLY_MQ_BOOMERANG_CHEST, logic->CanKillEnemy(RE_LIZALFOS)), + LOCATION(RC_JABU_JABUS_BELLY_MQ_GS_BOOMERANG_CHEST_ROOM, (logic->CanUse(RG_SONG_OF_TIME) && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)) || (ctx->GetTrickOption(RT_JABU_MQ_SOT_GS) && logic->CanUse(RG_BOOMERANG))), + LOCATION(RC_JABU_JABUS_BELLY_MQ_TIME_BLOCK_POT_1, logic->CanBreakPots()), + LOCATION(RC_JABU_JABUS_BELLY_MQ_TIME_BLOCK_POT_2, logic->CanBreakPots()), + }, { + //Exits + //without swim, jump from rang chest to the other side + Entrance(RR_JABU_JABUS_BELLY_MQ_BEGINNING, []{return Here(RR_JABU_JABUS_BELLY_MQ_WATER_SWITCH_ROOM, []{return logic->CanKillEnemy(RE_LIZALFOS);});}), + Entrance(RR_JABU_JABUS_BELLY_MQ_HOLES_ROOM, []{return (logic->IsAdult || logic->HasItem(RG_BRONZE_SCALE)) && Here(RR_JABU_JABUS_BELLY_MQ_WATER_SWITCH_ROOM, []{return logic->CanKillEnemy(RE_LIZALFOS);});}), + }); + + //Includes Like Like room + areaTable[RR_JABU_JABUS_BELLY_MQ_FORKED_CORRIDOR] = Region("Jabu Jabus Belly MQ Forked Corridor", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->JabuNorthTentacle, []{return Here(RR_JABU_JABUS_BELLY_MQ_FORKED_CORRIDOR, []{return logic->BlastOrSmash();}) && logic->CanUse(RG_BOOMERANG);}), + }, { + //Locations + //Implies CanKillEnemy(RE_LIKE_LIKE) + LOCATION(RC_JABU_JABUS_BELLY_MQ_FALLING_LIKE_LIKE_ROOM_CHEST, logic->CanUse(RG_FAIRY_SLINGSHOT)), + LOCATION(RC_JABU_JABUS_BELLY_MQ_LIKE_LIKES_POT_1, logic->CanBreakPots()), + LOCATION(RC_JABU_JABUS_BELLY_MQ_LIKE_LIKES_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_JABU_JABUS_BELLY_MQ_HOLES_ROOM, []{return logic->CanUse(RG_BOOMERANG);}), + //If some mode lets an age use sticks and not sling, and other use sling and not sticks, this needs changing + Entrance(RR_JABU_JABUS_BELLY_MQ_WEST_FORKED_ROOMS, []{return Here(RR_JABU_JABUS_BELLY_MQ_FORKED_CORRIDOR, []{return logic->CanUse(RG_BOOMERANG);}) && (Here(RR_JABU_JABUS_BELLY_MQ_FORKED_CORRIDOR, []{return logic->CanUse(RG_FAIRY_SLINGSHOT) && logic->CanUse(RG_STICKS);}) || Here(RR_JABU_JABUS_BELLY_MQ_FORKED_CORRIDOR, []{return logic->HasFireSource();}));}), + }); + + areaTable[RR_JABU_JABUS_BELLY_MQ_WEST_FORKED_ROOMS] = Region("Jabu Jabus Belly MQ West Forked Rooms", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->JabuWestTentacle, []{return logic->CanUse(RG_BOOMERANG);}), + }, { + //Locations + LOCATION(RC_JABU_JABUS_BELLY_MQ_GS_TAILPASARAN_ROOM, Here(RR_JABU_JABUS_BELLY_MQ_WEST_FORKED_ROOMS, []{return logic->HasExplosives();}) && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)), + }, { + //Exits + Entrance(RR_JABU_JABUS_BELLY_MQ_FORKED_CORRIDOR, []{return true;}), + }); + + areaTable[RR_JABU_JABUS_BELLY_MQ_INVISIBLE_KEESE_ROOM] = Region("Jabu Jabus Belly MQ Invisible Keese Room", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_JABU_JABUS_BELLY_MQ_GS_INVISIBLE_ENEMIES_ROOM, //firstly, we can just use FAs to clear the web and then longshot the skull + logic->CanUse(RG_FIRE_ARROWS) && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_LONGSHOT) || + //Otherwise, we we have to cross the gap and kill the skull. + (logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG) && + //We can cheese the gap with hovers + ((logic->CanUse(RG_HOVER_BOOTS) || + //Otherwise we have to kill the enemies to raise the platform. This persists so we can do it as the other age. + Here(RR_JABU_JABUS_BELLY_MQ_INVISIBLE_KEESE_ROOM, []{return (ctx->GetTrickOption(RT_LENS_JABU_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)) && + logic->CanKillEnemy(RE_STINGER, ED_BOOMERANG, false, 2, false, true) && + //we can hit the keese farthest from the water with irons and hookshot, but we won't be able to see it while doing so + (logic->CanKillEnemy(RE_KEESE, ED_LONGSHOT, false) || (ctx->GetTrickOption(RT_LENS_JABU_MQ) && logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_IRON_BOOTS)));})) + //If we kill the enemies, we then need to cross the water using the platform. Note that adult cannot do so while swimming because MQ jank. + && ((logic->IsChild && logic->HasItem(RG_BRONZE_SCALE)) || (logic->IsAdult && logic->CanUse(RG_IRON_BOOTS)))))), + }, { + //Exits + Entrance(RR_JABU_JABUS_BELLY_MQ_HOLES_ROOM, []{return (logic->JabuNorthTentacle || logic->TakeDamage()) && logic->HasItem(RG_BRONZE_SCALE);}), + }); + + areaTable[RR_JABU_JABUS_BELLY_MQ_PAST_OCTO] = Region("Jabu Jabus Belly MQ Past Octo", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { + //Events + //if a hover up to the path is added, this will want it's own room + EventAccess(&logic->LoweredJabuPath, []{return logic->CanUse(RG_BOOMERANG) && logic->CanUse(RG_FAIRY_SLINGSHOT);}), + }, { + //Locations + LOCATION(RC_JABU_JABUS_BELLY_MQ_COW, logic->CanUse(RG_EPONAS_SONG) && logic->CanUse(RG_FAIRY_SLINGSHOT)), + }, { + //Exits + Entrance(RR_JABU_JABUS_BELLY_MQ_LIFT_ROOM, []{return logic->CanUse(RG_BOOMERANG) && logic->CanUse(RG_FAIRY_SLINGSHOT);}), + //you take both fall damage and tentacle damage, unless the tentacle is down. need better damage logic + Entrance(RR_JABU_JABUS_BELLY_MQ_HOLES_ROOM, []{return logic->TakeDamage() && Here(RR_JABU_JABUS_BELLY_MQ_PAST_OCTO, []{return logic->CanKillEnemy(RE_BIG_OCTO);});}), + }); + + areaTable[RR_JABU_JABUS_BELLY_MQ_LIFT_ROOM_EAST_LEDGE] = Region("Jabu Jabus Belly MQ Lift Room East Ledge", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_JABU_JABUS_BELLY_MQ_SECOND_ROOM_UPPER_CHEST, logic->MQJabuLiftRoomCow), + }, { + //Exits + Entrance(RR_JABU_JABUS_BELLY_MQ_LIFT_ROOM, []{return true;}), + Entrance(RR_JABU_JABUS_BELLY_MQ_EAST_ROOM, []{return logic->JabuNorthTentacle;}), + }); + + areaTable[RR_JABU_JABUS_BELLY_MQ_EAST_ROOM] = Region("Jabu Jabus Belly MQ Boss Region", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->FairyPot, []{return true;}), + }, { + //Locations + LOCATION(RC_JABU_JABUS_BELLY_MQ_NEAR_BOSS_CHEST, logic->CanUse(RG_FAIRY_SLINGSHOT)), + LOCATION(RC_JABU_JABUS_BELLY_MQ_GS_NEAR_BOSS, logic->CanUse(RG_BOOMERANG) || (ctx->GetTrickOption(RT_JABU_NEAR_BOSS_RANGED) && logic->CanUse(RG_HOOKSHOT))), + LOCATION(RC_JABU_JABUS_BELLY_MQ_BEFORE_BOSS_POT_1, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_JABU_JABUS_BELLY_MQ_LIFT_ROOM_EAST_LEDGE, []{return true;}), + Entrance(RR_JABU_JABUS_BELLY_BOSS_ENTRYWAY, []{return Here(RR_JABU_JABUS_BELLY_MQ_EAST_ROOM, []{return logic->CanUse(RG_FAIRY_SLINGSHOT);});}), + }); + +#pragma endregion + + // Boss Room + areaTable[RR_JABU_JABUS_BELLY_BOSS_ENTRYWAY] = Region("Jabu Jabus Belly Boss Entryway", "Jabu Jabus Belly", {RA_JABU_JABUS_BELLY}, NO_DAY_NIGHT_CYCLE, {}, {}, { + // Exits + Entrance(RR_JABU_JABUS_BELLY_NEAR_BOSS_ROOM, []{return ctx->GetDungeon(JABU_JABUS_BELLY)->IsVanilla();}), + Entrance(RR_JABU_JABUS_BELLY_MQ_EAST_ROOM, []{return ctx->GetDungeon(JABU_JABUS_BELLY)->IsMQ();}), + Entrance(RR_JABU_JABUS_BELLY_BOSS_ROOM, []{return true;}), + }); + + areaTable[RR_JABU_JABUS_BELLY_BOSS_ROOM] = Region("Jabu Jabus Belly Boss Room", "Jabu Jabus Belly", {}, NO_DAY_NIGHT_CYCLE, { + // Events //todo: add pot kill trick + EventAccess(&logic->JabuJabusBellyClear, []{return logic->JabuJabusBellyClear || (logic->HasBossSoul(RG_BARINADE_SOUL) && (logic->CanUse(RG_BOOMERANG) && logic->CanJumpslashExceptHammer()));}), + }, { + // Locations + LOCATION(RC_JABU_JABUS_BELLY_BARINADE_POT_1, logic->CanBreakPots()), + LOCATION(RC_JABU_JABUS_BELLY_BARINADE_POT_2, logic->CanBreakPots()), + LOCATION(RC_JABU_JABUS_BELLY_BARINADE_POT_3, logic->CanBreakPots()), + LOCATION(RC_JABU_JABUS_BELLY_BARINADE_POT_4, logic->CanBreakPots()), + LOCATION(RC_JABU_JABUS_BELLY_BARINADE_POT_5, logic->CanBreakPots()), + LOCATION(RC_JABU_JABUS_BELLY_BARINADE_POT_6, logic->CanBreakPots()), + LOCATION(RC_JABU_JABUS_BELLY_BARINADE_HEART, logic->JabuJabusBellyClear), + LOCATION(RC_BARINADE, logic->JabuJabusBellyClear), + }, { + // Exits + Entrance(RR_JABU_JABUS_BELLY_BOSS_ENTRYWAY, []{return false;}), + Entrance(RR_ZORAS_FOUNTAIN, []{return logic->JabuJabusBellyClear;}, false), + }); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/shadow_temple.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/shadow_temple.cpp new file mode 100644 index 000000000..1267e2408 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/shadow_temple.cpp @@ -0,0 +1,416 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" +#include "soh/Enhancements/randomizer/dungeon.h" + +using namespace Rando; + +void RegionTable_Init_ShadowTemple() { + // Vanilla/MQ Decider + areaTable[RR_SHADOW_TEMPLE_ENTRYWAY] = Region("Shadow Temple Entryway", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_SHADOW_TEMPLE_BEGINNING, []{return ctx->GetDungeon(SHADOW_TEMPLE)->IsVanilla() && (ctx->GetTrickOption(RT_LENS_SHADOW) || logic->CanUse(RG_LENS_OF_TRUTH)) && (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT));}), + Entrance(RR_SHADOW_TEMPLE_MQ_BEGINNING, []{return ctx->GetDungeon(SHADOW_TEMPLE)->IsMQ();}), + Entrance(RR_GRAVEYARD_WARP_PAD_REGION, []{return true;}), + }); + +#pragma region Vanilla + + areaTable[RR_SHADOW_TEMPLE_BEGINNING] = Region("Shadow Temple Beginning", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->NutPot, []{return true;}), + }, { + //Locations + LOCATION(RC_SHADOW_TEMPLE_MAP_CHEST, logic->CanJumpslashExceptHammer()), + LOCATION(RC_SHADOW_TEMPLE_HOVER_BOOTS_CHEST, logic->CanKillEnemy(RE_DEAD_HAND)), + LOCATION(RC_SHADOW_TEMPLE_NEAR_DEAD_HAND_POT_1, logic->CanBreakPots()), + LOCATION(RC_SHADOW_TEMPLE_WHISPERING_WALLS_POT_1, logic->CanBreakPots()), + LOCATION(RC_SHADOW_TEMPLE_WHISPERING_WALLS_POT_2, logic->CanBreakPots()), + LOCATION(RC_SHADOW_TEMPLE_WHISPERING_WALLS_POT_3, logic->CanBreakPots()), + LOCATION(RC_SHADOW_TEMPLE_WHISPERING_WALLS_POT_4, logic->CanBreakPots()), + LOCATION(RC_SHADOW_TEMPLE_WHISPERING_WALLS_POT_5, logic->CanBreakPots()), + LOCATION(RC_SHADOW_TEMPLE_MAP_CHEST_POT_1, logic->CanBreakPots()), + LOCATION(RC_SHADOW_TEMPLE_MAP_CHEST_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_SHADOW_TEMPLE_ENTRYWAY, []{return true;}), + Entrance(RR_SHADOW_TEMPLE_FIRST_BEAMOS, []{return logic->CanUse(RG_HOVER_BOOTS);}), + }); + + areaTable[RR_SHADOW_TEMPLE_FIRST_BEAMOS] = Region("Shadow Temple First Beamos", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->FairyPot, []{return true;}), //This fairy pot is only on 3DS + }, { + //Locations + LOCATION(RC_SHADOW_TEMPLE_COMPASS_CHEST, logic->CanJumpslashExceptHammer()), + LOCATION(RC_SHADOW_TEMPLE_EARLY_SILVER_RUPEE_CHEST, logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT)), + LOCATION(RC_SHADOW_TEMPLE_GS_NEAR_SHIP, false), + LOCATION(RC_SHADOW_TEMPLE_BEAMOS_STORM_FAIRY, logic->CanUse(RG_SONG_OF_STORMS)), + }, { + //Exits + Entrance(RR_SHADOW_TEMPLE_HUGE_PIT, []{return logic->HasExplosives() && logic->IsAdult && logic->SmallKeys(RR_SHADOW_TEMPLE, 1, 2);}), + Entrance(RR_SHADOW_TEMPLE_BEYOND_BOAT, []{return false;}), + }); + + areaTable[RR_SHADOW_TEMPLE_HUGE_PIT] = Region("Shadow Temple Huge Pit", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SHADOW_TEMPLE_INVISIBLE_BLADES_VISIBLE_CHEST, logic->CanJumpslashExceptHammer()), + LOCATION(RC_SHADOW_TEMPLE_INVISIBLE_BLADES_INVISIBLE_CHEST, logic->CanJumpslashExceptHammer()), + LOCATION(RC_SHADOW_TEMPLE_FALLING_SPIKES_LOWER_CHEST, true), + LOCATION(RC_SHADOW_TEMPLE_FALLING_SPIKES_UPPER_CHEST, (ctx->GetTrickOption(RT_SHADOW_UMBRELLA) && logic->CanUse(RG_HOVER_BOOTS)) || logic->HasItem(RG_GORONS_BRACELET)), + LOCATION(RC_SHADOW_TEMPLE_FALLING_SPIKES_SWITCH_CHEST, (ctx->GetTrickOption(RT_SHADOW_UMBRELLA) && logic->CanUse(RG_HOVER_BOOTS)) || logic->HasItem(RG_GORONS_BRACELET)), + LOCATION(RC_SHADOW_TEMPLE_INVISIBLE_SPIKES_CHEST, logic->SmallKeys(RR_SHADOW_TEMPLE, 2, 3) && ((ctx->GetTrickOption(RT_LENS_SHADOW_PLATFORM) && ctx->GetTrickOption(RT_LENS_SHADOW)) || logic->CanUse(RG_LENS_OF_TRUTH))), + LOCATION(RC_SHADOW_TEMPLE_FREESTANDING_KEY, logic->SmallKeys(RR_SHADOW_TEMPLE, 2, 3) && ((ctx->GetTrickOption(RT_LENS_SHADOW_PLATFORM) && ctx->GetTrickOption(RT_LENS_SHADOW)) || logic->CanUse(RG_LENS_OF_TRUTH)) && logic->CanUse(RG_HOOKSHOT) && (logic->CanUse(RG_BOMB_BAG) || logic->HasItem(RG_GORONS_BRACELET) || (ctx->GetTrickOption(RT_SHADOW_FREESTANDING_KEY) && logic->CanUse(RG_BOMBCHU_5)))), + LOCATION(RC_SHADOW_TEMPLE_GS_LIKE_LIKE_ROOM, logic->CanJumpslashExceptHammer()), + LOCATION(RC_SHADOW_TEMPLE_GS_FALLING_SPIKES_ROOM, logic->CanUse(RG_HOOKSHOT) || (ctx->GetTrickOption(RT_SHADOW_UMBRELLA_GS) && logic->CanUse(RG_HOVER_BOOTS))), + LOCATION(RC_SHADOW_TEMPLE_GS_SINGLE_GIANT_POT, logic->SmallKeys(RR_SHADOW_TEMPLE, 2, 3) && ((ctx->GetTrickOption(RT_LENS_SHADOW_PLATFORM) && ctx->GetTrickOption(RT_LENS_SHADOW)) || logic->CanUse(RG_LENS_OF_TRUTH)) && logic->CanUse(RG_HOOKSHOT)), + LOCATION(RC_SHADOW_TEMPLE_FALLING_SPIKES_POT_1, logic->CanBreakPots()), + LOCATION(RC_SHADOW_TEMPLE_FALLING_SPIKES_POT_2, logic->CanBreakPots()), + LOCATION(RC_SHADOW_TEMPLE_FALLING_SPIKES_POT_3, logic->CanBreakPots() && (ctx->GetTrickOption(RT_SHADOW_UMBRELLA) && logic->CanUse(RG_HOVER_BOOTS)) || logic->HasItem(RG_GORONS_BRACELET)), + LOCATION(RC_SHADOW_TEMPLE_FALLING_SPIKES_POT_4, logic->CanBreakPots() && (ctx->GetTrickOption(RT_SHADOW_UMBRELLA) && logic->CanUse(RG_HOVER_BOOTS)) || logic->HasItem(RG_GORONS_BRACELET)), + //We cannot repeat the MQ invisible blades trick for these hearts as the like-like does not respawn if the room is cleared + LOCATION(RC_SHADOW_TEMPLE_INVISIBLE_BLADES_LEFT_HEART, (logic->CanUse(RG_SONG_OF_TIME) && logic->IsAdult) || logic->CanUse(RG_BOOMERANG)), + LOCATION(RC_SHADOW_TEMPLE_INVISIBLE_BLADES_RIGHT_HEART, (logic->CanUse(RG_SONG_OF_TIME) && logic->IsAdult) || logic->CanUse(RG_BOOMERANG)), + LOCATION(RC_SHADOW_TEMPLE_PIT_STORM_FAIRY, logic->CanUse(RG_SONG_OF_STORMS)), + }, { + //Exits + Entrance(RR_SHADOW_TEMPLE_WIND_TUNNEL, []{return ((ctx->GetTrickOption(RT_LENS_SHADOW_PLATFORM) && ctx->GetTrickOption(RT_LENS_SHADOW)) || logic->CanUse(RG_LENS_OF_TRUTH)) && logic->CanUse(RG_HOOKSHOT) && logic->SmallKeys(RR_SHADOW_TEMPLE, 3, 4);}), + }); + + areaTable[RR_SHADOW_TEMPLE_WIND_TUNNEL] = Region("Shadow Temple Wind Tunnel", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SHADOW_TEMPLE_WIND_HINT_CHEST, true), + LOCATION(RC_SHADOW_TEMPLE_AFTER_WIND_ENEMY_CHEST, logic->CanJumpslashExceptHammer()), + LOCATION(RC_SHADOW_TEMPLE_AFTER_WIND_HIDDEN_CHEST, true), + LOCATION(RC_SHADOW_TEMPLE_GS_NEAR_SHIP, logic->CanUse(RG_LONGSHOT) && logic->SmallKeys(RR_SHADOW_TEMPLE, 4, 5)), + LOCATION(RC_SHADOW_TEMPLE_WIND_HINT_SUN_FAIRY, logic->CanUse(RG_SUNS_SONG)), + LOCATION(RC_SHADOW_TEMPLE_AFTER_WIND_POT_1, logic->CanBreakPots()), + LOCATION(RC_SHADOW_TEMPLE_AFTER_WIND_POT_2, logic->CanBreakPots()), + LOCATION(RC_SHADOW_TEMPLE_SCARECROW_NORTH_HEART, logic->CanUse(RG_DISTANT_SCARECROW) && logic->SmallKeys(RR_SHADOW_TEMPLE, 4, 5)), + LOCATION(RC_SHADOW_TEMPLE_SCARECROW_SOUTH_HEART, logic->CanUse(RG_DISTANT_SCARECROW) && logic->SmallKeys(RR_SHADOW_TEMPLE, 4, 5)), + }, { + //Exits + Entrance(RR_SHADOW_TEMPLE_BEYOND_BOAT, []{return logic->CanJumpslashExceptHammer() && logic->CanUse(RG_ZELDAS_LULLABY) && logic->SmallKeys(RR_SHADOW_TEMPLE, 4, 5);}), + }); + + areaTable[RR_SHADOW_TEMPLE_BEYOND_BOAT] = Region("Shadow Temple Beyond Boat", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SHADOW_TEMPLE_SPIKE_WALLS_LEFT_CHEST, logic->CanUse(RG_DINS_FIRE)), + LOCATION(RC_SHADOW_TEMPLE_BOSS_KEY_CHEST, logic->CanUse(RG_DINS_FIRE)), + LOCATION(RC_SHADOW_TEMPLE_INVISIBLE_FLOORMASTER_CHEST, logic->CanJumpslashExceptHammer()), + //RANDOTODO check if child can reach the token + LOCATION(RC_SHADOW_TEMPLE_GS_TRIPLE_GIANT_POT, logic->IsAdult && logic->CanAttack()), + LOCATION(RC_SHADOW_TEMPLE_AFTER_BOAT_POT_1, logic->CanBreakPots()), + LOCATION(RC_SHADOW_TEMPLE_AFTER_BOAT_POT_2, logic->CanBreakPots()), + LOCATION(RC_SHADOW_TEMPLE_AFTER_BOAT_POT_3, logic->CanBreakPots() && (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_DISTANT_SCARECROW) || (ctx->GetTrickOption(RT_SHADOW_STATUE) && logic->CanUse(RG_BOMBCHU_5)))), + LOCATION(RC_SHADOW_TEMPLE_AFTER_BOAT_POT_4, logic->CanBreakPots() && (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_DISTANT_SCARECROW) || (ctx->GetTrickOption(RT_SHADOW_STATUE) && logic->CanUse(RG_BOMBCHU_5)))), + LOCATION(RC_SHADOW_TEMPLE_SPIKE_WALLS_POT_1, logic->CanBreakPots()), + LOCATION(RC_SHADOW_TEMPLE_FLOORMASTER_POT_1, logic->CanBreakPots()), + LOCATION(RC_SHADOW_TEMPLE_FLOORMASTER_POT_2, logic->CanBreakPots()), + LOCATION(RC_SHADOW_TEMPLE_AFTER_SHIP_UPPER_LEFT_HEART, logic->CanUse(RG_DISTANT_SCARECROW)), + LOCATION(RC_SHADOW_TEMPLE_AFTER_SHIP_UPPER_RIGHT_HEART, logic->CanUse(RG_DISTANT_SCARECROW)), + LOCATION(RC_SHADOW_TEMPLE_AFTER_SHIP_LOWER_HEART, (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_DISTANT_SCARECROW) || (ctx->GetTrickOption(RT_SHADOW_STATUE) && logic->CanUse(RG_BOMBCHU_5))) && logic->CanUse(RG_SONG_OF_TIME) || (logic->CanUse(RG_DISTANT_SCARECROW) && logic->CanUse(RG_HOVER_BOOTS))), + }, { + //Exits + Entrance(RR_SHADOW_TEMPLE_BOSS_ENTRYWAY, []{return (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_DISTANT_SCARECROW) || (ctx->GetTrickOption(RT_SHADOW_STATUE) && logic->CanUse(RG_BOMBCHU_5))) && logic->SmallKeys(RR_SHADOW_TEMPLE, 5) && logic->CanUse(RG_HOVER_BOOTS) && logic->HasItem(RG_SHADOW_TEMPLE_BOSS_KEY);}) + }); + +#pragma endregion + +#pragma region MQ + + //RANDOTODO doublecheck CanAttack when rewriting, as I assumed it only checked adult due to the entrance + areaTable[RR_SHADOW_TEMPLE_MQ_BEGINNING] = Region("Shadow Temple MQ Beginning", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_SHADOW_TEMPLE_ENTRYWAY, []{return true;}), + Entrance(RR_SHADOW_TEMPLE_MQ_SPINNER_ROOM, []{return logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT);}), + }); + + areaTable[RR_SHADOW_TEMPLE_MQ_SPINNER_ROOM] = Region("Shadow Temple MQ Spinner Room", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_SHADOW_TEMPLE_ENTRYWAY, []{return true;}), + Entrance(RR_SHADOW_TEMPLE_MQ_FIRST_BEAMOS, []{return Here(RR_SHADOW_TEMPLE_MQ_SPINNER_ROOM, []{return logic->CanUse(RG_HOVER_BOOTS) || (ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH));}) && (logic->CanUse(RG_HOVER_BOOTS) || Here(RR_SHADOW_TEMPLE_MQ_SPINNER_ROOM, []{return logic->CanUse(RG_FIRE_ARROWS);}) || (ctx->GetTrickOption(RT_SHADOW_MQ_GAP) && logic->CanUse(RG_LONGSHOT) && logic->CanJumpslashExceptHammer()));}), + Entrance(RR_SHADOW_TEMPLE_MQ_DEAD_HAND_AREA, []{return Here(RR_SHADOW_TEMPLE_MQ_SPINNER_ROOM, []{return logic->HasExplosives();}) && logic->SmallKeys(RR_SHADOW_TEMPLE, 6) && (ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH));}), + }); + + //Assumes we're in the "main" area and needed lens to enter. logic will need changes if a void warp puts us somewhere weird + areaTable[RR_SHADOW_TEMPLE_MQ_DEAD_HAND_AREA] = Region("Shadow Temple MQ Dead Hand Region", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SHADOW_TEMPLE_MQ_COMPASS_CHEST, logic->CanKillEnemy(RE_REDEAD)), + //There's a shared flag tied to some glass here. eye target here and killing an enemy group later in the dungeon toggles. I'm building the logic as "intended", assuming the switch needs flipping + LOCATION(RC_SHADOW_TEMPLE_MQ_HOVER_BOOTS_CHEST, logic->CanKillEnemy(RE_DEAD_HAND) && (logic->IsChild || logic->CanUse(RG_SONG_OF_TIME)) && logic->CanHitEyeTargets()), + LOCATION(RC_SHADOW_TEMPLE_MQ_WHISPERING_WALLS_POT_1, logic->CanBreakPots()), + LOCATION(RC_SHADOW_TEMPLE_MQ_WHISPERING_WALLS_POT_2, logic->CanBreakPots()), + LOCATION(RC_SHADOW_TEMPLE_MQ_ENTRANCE_REDEAD_POT_1, logic->CanBreakPots()), + LOCATION(RC_SHADOW_TEMPLE_MQ_ENTRANCE_REDEAD_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_SHADOW_TEMPLE_MQ_SPINNER_ROOM, []{return true;}), + }); + + //also includes the B2 gibdo room + areaTable[RR_SHADOW_TEMPLE_MQ_FIRST_BEAMOS] = Region("Shadow Temple MQ First Beamos", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + //Doing this sets the shared flag for the glass in RR_SHADOW_TEMPLE_MQ_DEAD_HAND_AREA, but doesn't seem to affect the chest + LOCATION(RC_SHADOW_TEMPLE_MQ_EARLY_GIBDOS_CHEST, logic->CanKillEnemy(RE_GIBDO) && (ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH))), + LOCATION(RC_SHADOW_TEMPLE_MQ_BEAMOS_STORM_FAIRY, logic->CanUse(RG_SONG_OF_STORMS)), + }, { + //Exits + Entrance(RR_SHADOW_TEMPLE_MQ_UPPER_HUGE_PIT, []{return logic->HasExplosives() && logic->SmallKeys(RR_SHADOW_TEMPLE, 2);}), + Entrance(RR_SHADOW_TEMPLE_MQ_B2_SPINNING_BLADE_ROOM, []{return ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH);}), + }); + + areaTable[RR_SHADOW_TEMPLE_MQ_B2_SPINNING_BLADE_ROOM] = Region("Shadow Temple MQ B2 Spinning Blade Room", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SHADOW_TEMPLE_MQ_MAP_CHEST, logic->CanPassEnemy(RE_BIG_SKULLTULA) && (logic->CanUse(RG_HOOKSHOT) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)))), + }, { + //Exits + Entrance(RR_SHADOW_TEMPLE_MQ_FIRST_BEAMOS, []{return Here(RR_SHADOW_TEMPLE_MQ_B2_SPINNING_BLADE_ROOM, []{return logic->CanKillEnemy(RE_BIG_SKULLTULA) && (logic->CanUse(RG_HOOKSHOT) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)));});}), + Entrance(RR_SHADOW_TEMPLE_MQ_SHORTCUT_PATH, []{return logic->CanPassEnemy(RE_BIG_SKULLTULA);}), + }); + + areaTable[RR_SHADOW_TEMPLE_MQ_SHORTCUT_PATH] = Region("Shadow Temple MQ Shortcut Path", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SHADOW_TEMPLE_MQ_NEAR_SHIP_INVISIBLE_CHEST, ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)), + }, { + //Exits + Entrance(RR_SHADOW_TEMPLE_MQ_B2_SPINNING_BLADE_ROOM, []{return logic->CanPassEnemy(RE_BIG_SKULLTULA);}), + Entrance(RR_SHADOW_TEMPLE_MQ_DOCK, []{return logic->ShadowShortcutBlock;}), + //WARNING if there's any way past here to ship without already reaching the other side the key logic in this dungeon becomes Quantum + }); + + //Room exists for if it's ever possible to go backwards or void warp into the middle of shadow + areaTable[RR_SHADOW_TEMPLE_MQ_B2_TO_B3_CORRIDOR] = Region("Shadow Temple MQ B2 to B3 Corridor", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_SHADOW_TEMPLE_MQ_FIRST_BEAMOS, []{return logic->HasExplosives() && logic->SmallKeys(RR_SHADOW_TEMPLE, 2);}), + Entrance(RR_SHADOW_TEMPLE_MQ_UPPER_HUGE_PIT, []{return true;}), + //bunnyhovers + lens lets you go from the very top of upper pit to the stationary invisible platform below quite easily + }); + + areaTable[RR_SHADOW_TEMPLE_MQ_UPPER_HUGE_PIT] = Region("Shadow Temple MQ Upper Huge Pit", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SHADOW_TEMPLE_MQ_PIT_STORM_FAIRY, logic->CanUse(RG_SONG_OF_STORMS)), + }, { + //Exits + Entrance(RR_SHADOW_TEMPLE_MQ_LOWER_HUGE_PIT, []{return (logic->HasFireSource() && (ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH))) || ctx->GetTrickOption(RT_SHADOW_MQ_HUGE_PIT);}), + Entrance(RR_SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_ROOM, []{return ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH);}), + }); + + areaTable[RR_SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_ROOM] = Region("Shadow Temple MQ Invisible Blades Room", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + //RT_SHADOW_MQ_INVISIBLE_BLADES does not work with NL as like-likes will not swallow you, likewise like-likes will not spit you with a fairy revive + //you take half a heart base from a spit out, double check EffectiveHealth when damage logic gets reworked + //Child is too small to get hit by the blades doesn't need the trick or lens for dodging them + LOCATION(RC_SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_VISIBLE_CHEST, (logic->CanUse(RG_SONG_OF_TIME) || (ctx->GetTrickOption(RT_SHADOW_MQ_INVISIBLE_BLADES) && logic->EffectiveHealth() > 1)) && + (ctx->GetTrickOption(RT_LENS_SHADOW_MQ_INVISIBLE_BLADES) || logic->IsChild || logic->CanUse(RG_NAYRUS_LOVE) || logic->CanUse(RG_LENS_OF_TRUTH))), + LOCATION(RC_SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_INVISIBLE_CHEST, (logic->CanUse(RG_SONG_OF_TIME) || (ctx->GetTrickOption(RT_SHADOW_MQ_INVISIBLE_BLADES) && logic->EffectiveHealth() > 1)) && + ((ctx->GetTrickOption(RT_LENS_SHADOW_MQ) && (ctx->GetTrickOption(RT_LENS_SHADOW_MQ_INVISIBLE_BLADES) || logic->IsChild || logic->CanUse(RG_NAYRUS_LOVE))) || logic->CanUse(RG_LENS_OF_TRUTH))), + LOCATION(RC_SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_LEFT_HEART, (logic->CanUse(RG_SONG_OF_TIME) && logic->IsAdult) || (ctx->GetTrickOption(RT_SHADOW_MQ_INVISIBLE_BLADES) && logic->EffectiveHealth() > 1) || logic->CanUse(RG_BOOMERANG)), + LOCATION(RC_SHADOW_TEMPLE_MQ_INVISIBLE_BLADES_RIGHT_HEART, (logic->CanUse(RG_SONG_OF_TIME) && logic->IsAdult) || (ctx->GetTrickOption(RT_SHADOW_MQ_INVISIBLE_BLADES) && logic->EffectiveHealth() > 1) || logic->CanUse(RG_BOOMERANG)), + }, { + //Exits + Entrance(RR_SHADOW_TEMPLE_MQ_UPPER_HUGE_PIT, []{return true;}), + }); + + areaTable[RR_SHADOW_TEMPLE_MQ_LOWER_HUGE_PIT] = Region("Shadow Temple MQ Lower Huge Pit", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SHADOW_TEMPLE_MQ_BEAMOS_SILVER_RUPEES_CHEST, logic->CanUse(RG_LONGSHOT)), + }, { + //Exits + Entrance(RR_SHADOW_TEMPLE_MQ_STONE_UMBRELLA_ROOM, []{return Here(RR_SHADOW_TEMPLE_MQ_LOWER_HUGE_PIT, []{return logic->CanJumpslash() || logic->HasExplosives();});}), + Entrance(RR_SHADOW_TEMPLE_MQ_FLOOR_SPIKES_ROOM, []{return logic->CanUse(RG_HOVER_BOOTS) && (ctx->GetTrickOption(RT_LENS_SHADOW_MQ_PLATFORM) || logic->CanUse(RG_LENS_OF_TRUTH)) && logic->SmallKeys(RR_SHADOW_TEMPLE, 3);}), + }); + + areaTable[RR_SHADOW_TEMPLE_MQ_STONE_UMBRELLA_ROOM] = Region("Shadow Temple MQ Stone Umbrella Room", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SHADOW_TEMPLE_MQ_FALLING_SPIKES_LOWER_CHEST, true), + //Assuming the known setup for RT_SHADOW_UMBRELLA and RT_SHADOW_UMBRELLA_GS, probably possible without sword + shield. + //Handling the trick here instead of upper as using the block to climb is not a valid method for getting this skull without other tricks to use the block before it is intended + LOCATION(RC_SHADOW_TEMPLE_MQ_GS_FALLING_SPIKES_ROOM, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG) || + (ctx->GetTrickOption(RT_SHADOW_UMBRELLA_GS) && ctx->GetTrickOption(RT_SHADOW_UMBRELLA) && logic->CanUse(RG_HOVER_BOOTS) && logic->CanStandingShield() && logic->CanUse(RG_MASTER_SWORD))), + LOCATION(RC_SHADOW_TEMPLE_MQ_LOWER_UMBRELLA_WEST_POT, logic->CanBreakPots()), + LOCATION(RC_SHADOW_TEMPLE_MQ_LOWER_UMBRELLA_EAST_POT, logic->CanBreakPots()), + LOCATION(RC_SHADOW_TEMPLE_MQ_UPPER_UMBRELLA_SOUTH_POT, logic->CanUse(RG_BOOMERANG)), + }, { + //Exits + Entrance(RR_SHADOW_TEMPLE_MQ_LOWER_HUGE_PIT, []{return Here(RR_SHADOW_TEMPLE_MQ_STONE_UMBRELLA_ROOM, []{return ctx->GetTrickOption(RT_VISIBLE_COLLISION) || logic->CanHitSwitch();});}), + //Assuming the known setup for RT_SHADOW_UMBRELLA, probably possible without sword + shield + Entrance(RR_SHADOW_TEMPLE_MQ_UPPER_STONE_UMBRELLA, []{return logic->IsAdult && (logic->HasItem(RG_GORONS_BRACELET) || (ctx->GetTrickOption(RT_SHADOW_UMBRELLA) && logic->CanUse(RG_HOVER_BOOTS) && logic->CanStandingShield() && logic->CanUse(RG_MASTER_SWORD)));}), + }); + + areaTable[RR_SHADOW_TEMPLE_MQ_UPPER_STONE_UMBRELLA] = Region("Shadow Temple MQ Upper Stone Umbrella", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SHADOW_TEMPLE_MQ_FALLING_SPIKES_UPPER_CHEST, true), + LOCATION(RC_SHADOW_TEMPLE_MQ_FALLING_SPIKES_SWITCH_CHEST, true), + LOCATION(RC_SHADOW_TEMPLE_MQ_UPPER_UMBRELLA_NORTH_POT, logic->CanBreakPots()), + LOCATION(RC_SHADOW_TEMPLE_MQ_UPPER_UMBRELLA_SOUTH_POT, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_SHADOW_TEMPLE_MQ_STONE_UMBRELLA_ROOM, []{return true;}), + }); + + //while the spikes here are annoying, they don't really stop you doing anything, so I'll assume either lens trick, lens to see them, or taking damage from them. Not hovers though as a new player won't see the threat without lens to react properly + areaTable[RR_SHADOW_TEMPLE_MQ_FLOOR_SPIKES_ROOM] = Region("Shadow Temple MQ Floor Spikes Room", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events //lens or trick is always required for hookshot targets. We handle it here to not complicate the RR_SHADOW_TEMPLE_MQ_FLOOR_SPIKES_UPPER_DOOR logic + EventAccess(&logic->MQShadowFloorSpikeRupees, []{return (ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)) && + //Upper door side high rupee needs (hookshot and redead kill(as either age) for chest and adult) or longshot. hovers can cross from the left side with a backflip but that would be a trick + //East midair rupee needs (hookshot and(hover boots or jumpslash from the upper door platform)) or longshot. + //Combined these are longshot or (IsAdult && hookshot && (CanJumpslash || (Hover Boots && Here(CanKillRedeads)))) + (logic->CanUse(RG_LONGSHOT) || (logic->IsAdult && logic->CanUse(RG_HOOKSHOT) && (logic->CanJumpslash() || (logic->CanUse(RG_HOVER_BOOTS) && Here(RR_SHADOW_TEMPLE_MQ_FLOOR_SPIKES_ROOM, []{return logic->CanKillEnemy(RE_REDEAD);}))))) && + //1 rupee is in spikes, needs hovers or damage + (logic->TakeDamage() || logic->CanUse(RG_HOVER_BOOTS));}), + }, { + //Locations + LOCATION(RC_SHADOW_TEMPLE_MQ_INVISIBLE_SPIKES_CHEST, logic->CanKillEnemy(RE_REDEAD) && (ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->TakeDamage() || logic->CanUse(RG_LENS_OF_TRUTH))), + }, { + //Exits + Entrance(RR_SHADOW_TEMPLE_MQ_STALFOS_ROOM, []{return logic->MQShadowFloorSpikeRupees;}), + //We need to assume we can get here with or without the glass platforms + Entrance(RR_SHADOW_TEMPLE_MQ_WIND_TUNNEL, []{return logic->SmallKeys(RR_SHADOW_TEMPLE, 4) && (logic->CanUse(RG_LONGSHOT) || (logic->IsAdult && logic->CanUse(RG_HOOKSHOT) && (logic->MQShadowFloorSpikeRupees || Here(RR_SHADOW_TEMPLE_MQ_FLOOR_SPIKES_ROOM, []{return logic->CanKillEnemy(RE_REDEAD);})))) && (logic->CanJumpslash() || logic->CanUse(RG_HOVER_BOOTS));}), + }); + + areaTable[RR_SHADOW_TEMPLE_MQ_STALFOS_ROOM] = Region("Shadow Temple MQ Stalfos Room", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SHADOW_TEMPLE_MQ_STALFOS_ROOM_CHEST, logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2)), + }, { + //Exits + Entrance(RR_SHADOW_TEMPLE_MQ_FLOOR_SPIKES_ROOM, []{return Here(RR_SHADOW_TEMPLE_MQ_STALFOS_ROOM, []{return logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2);});}), + }); + + areaTable[RR_SHADOW_TEMPLE_MQ_WIND_TUNNEL] = Region("Shadow Temple MQ Wind Tunnel", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_SHADOW_TEMPLE_MQ_FLOOR_SPIKES_ROOM, []{return logic->SmallKeys(RR_SHADOW_TEMPLE, 4) && logic->CanPassEnemy(RE_BIG_SKULLTULA) && (logic->CanUse(RG_HOOKSHOT));}), + Entrance(RR_SHADOW_TEMPLE_MQ_WIND_HINT_ROOM, []{return logic->CanPassEnemy(RE_BIG_SKULLTULA) && (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS));}), + Entrance(RR_SHADOW_TEMPLE_MQ_B4_GIBDO_ROOM, []{return logic->CanPassEnemy(RE_BIG_SKULLTULA) && (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS));}), + }); + + areaTable[RR_SHADOW_TEMPLE_MQ_WIND_HINT_ROOM] = Region("Shadow Temple MQ Wind Hint Room", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SHADOW_TEMPLE_MQ_WIND_HINT_CHEST, (ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)) && logic->CanPassEnemy(RE_REDEAD)), + LOCATION(RC_SHADOW_TEMPLE_MQ_GS_WIND_HINT_ROOM, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)), + LOCATION(RC_SHADOW_TEMPLE_MQ_WIND_HINT_SUN_FAIRY, logic->CanUse(RG_SUNS_SONG)), + }, { + //Exits + Entrance(RR_SHADOW_TEMPLE_MQ_WIND_TUNNEL, []{return true;}), + }); + + areaTable[RR_SHADOW_TEMPLE_MQ_B4_GIBDO_ROOM] = Region("Shadow Temple MQ B4 Gibdo Room", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->NutPot, []{return true;}), + }, { + //Locations + LOCATION(RC_SHADOW_TEMPLE_MQ_AFTER_WIND_ENEMY_CHEST, logic->CanKillEnemy(RE_GIBDO)), + LOCATION(RC_SHADOW_TEMPLE_MQ_AFTER_WIND_HIDDEN_CHEST, logic->HasExplosives() && (ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH))), + LOCATION(RC_SHADOW_TEMPLE_MQ_GS_AFTER_WIND, logic->HasExplosives()), + LOCATION(RC_SHADOW_TEMPLE_MQ_BEFORE_BOAT_POT_1, logic->CanBreakPots()), + LOCATION(RC_SHADOW_TEMPLE_MQ_BEFORE_BOAT_POT_2, logic->CanBreakPots()), + }, { + //Exits + //child can make it using the wind strat + Entrance(RR_SHADOW_TEMPLE_MQ_WIND_TUNNEL, []{return (ctx->GetTrickOption(RT_SHADOW_MQ_WINDY_WALKWAY)) || logic->CanUse(RG_HOVER_BOOTS);}), + Entrance(RR_SHADOW_TEMPLE_MQ_DOCK, []{return logic->SmallKeys(RR_SHADOW_TEMPLE, 5);}), + }); + + areaTable[RR_SHADOW_TEMPLE_MQ_DOCK] = Region("Shadow Temple MQ Dock", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->ShadowShortcutBlock, []{return logic->HasItem(RG_GORONS_BRACELET);}), + }, { + //Locations + LOCATION(RC_SHADOW_TEMPLE_MQ_SCARECROW_NORTH_HEART, logic->CanUse(RG_DISTANT_SCARECROW)), + LOCATION(RC_SHADOW_TEMPLE_MQ_SCARECROW_SOUTH_HEART, logic->CanUse(RG_DISTANT_SCARECROW)), + }, { + //Exits + Entrance(RR_SHADOW_TEMPLE_MQ_SHORTCUT_PATH, []{return logic->ShadowShortcutBlock;}), + Entrance(RR_SHADOW_TEMPLE_MQ_B4_GIBDO_ROOM, []{return logic->SmallKeys(RR_SHADOW_TEMPLE, 5);}), + //funnily enough, the wheel jump seems to be in logic as there's no strength requirement in N64 + Entrance(RR_SHADOW_TEMPLE_MQ_BEYOND_BOAT, []{return (logic->IsAdult || logic->CanUse(RG_HOOKSHOT)) && logic->CanUse(RG_ZELDAS_LULLABY);}), + }); + + areaTable[RR_SHADOW_TEMPLE_MQ_BEYOND_BOAT] = Region("Shadow Temple MQ Beyond Boat", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + //It's a trick on N64 to kill this and drop down to collect this with normal weapons, as doing so without the statue being dropped voids you to before the boat + //hilariously, you can also hit this with a pot before you bring down the statue, but there's no great way to reset it without crossing. the statues collision is very inconvenient afterwards + LOCATION(RC_SHADOW_TEMPLE_MQ_GS_AFTER_SHIP, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)), + LOCATION(RC_SHADOW_TEMPLE_MQ_BEFORE_CHASM_WEST_POT, logic->CanBreakPots()), + LOCATION(RC_SHADOW_TEMPLE_MQ_BEFORE_CHASM_EAST_POT, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_SHADOW_TEMPLE_MQ_ACROSS_CHASM, []{return Here(RR_SHADOW_TEMPLE_MQ_BEYOND_BOAT, []{return logic->CanUse(RG_FAIRY_BOW) || (ctx->GetTrickOption(RT_SHADOW_STATUE) && logic->CanUse(RG_BOMBCHU_5));});}), + }); + + areaTable[RR_SHADOW_TEMPLE_MQ_ACROSS_CHASM] = Region("Shadow Temple MQ Across Chasm", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SHADOW_TEMPLE_MQ_AFTER_CHASM_WEST_POT, logic->CanBreakPots()), + LOCATION(RC_SHADOW_TEMPLE_MQ_AFTER_CHASM_EAST_POT, logic->CanBreakPots()), + LOCATION(RC_SHADOW_TEMPLE_MQ_AFTER_SHIP_UPPER_LEFT_HEART, logic->CanUse(RG_SONG_OF_TIME) && logic->CanHitEyeTargets() && logic->CanUse(RG_LONGSHOT)), + LOCATION(RC_SHADOW_TEMPLE_MQ_AFTER_SHIP_UPPER_RIGHT_HEART, logic->CanUse(RG_SONG_OF_TIME) && logic->CanHitEyeTargets() && logic->CanUse(RG_LONGSHOT)), + //There's invisible floor collision that makes aiming for the heart with rang harder than it should be, so it's a trick. + LOCATION(RC_SHADOW_TEMPLE_MQ_AFTER_SHIP_LOWER_HEART, logic->IsAdult), + }, { + //Exits + Entrance(RR_SHADOW_TEMPLE_MQ_BEYOND_BOAT, []{return Here(RR_SHADOW_TEMPLE_MQ_ACROSS_CHASM, []{return logic->CanDetonateUprightBombFlower();}) && logic->IsAdult;}), + //assumes RR_SHADOW_TEMPLE_MQ_BEYOND_BOAT by previous access. If backwards shadow ever exists remember that child cannot jump onto the statue from this side and make an event for the switch + //Lens isn't needed to reach it but is needed to navigate the next room + Entrance(RR_SHADOW_TEMPLE_MQ_INVISIBLE_MAZE, []{return Here(RR_SHADOW_TEMPLE_MQ_ACROSS_CHASM, []{return logic->CanHitEyeTargets() && logic->CanUse(RG_SONG_OF_TIME) && logic->CanUse(RG_LONGSHOT);});}), + Entrance(RR_SHADOW_TEMPLE_MQ_BOSS_DOOR, []{return logic->CanUse(RG_HOVER_BOOTS) && (ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH));}), + }); + + areaTable[RR_SHADOW_TEMPLE_MQ_BOSS_DOOR] = Region("Shadow Temple MQ Boss Door", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + //you can drop onto this and the respawn is reasonable + LOCATION(RC_SHADOW_TEMPLE_MQ_GS_NEAR_BOSS, (logic->CanKillEnemy(RE_GOLD_SKULLTULA, ED_BOMB_THROW) || logic->CanUse(RG_MEGATON_HAMMER)) && (ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH))), + }, { + //Exits + Entrance(RR_SHADOW_TEMPLE_MQ_ACROSS_CHASM, []{return logic->CanUse(RG_HOVER_BOOTS) && (ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH));}), + Entrance(RR_SHADOW_TEMPLE_BOSS_ENTRYWAY, []{return logic->HasItem(RG_SHADOW_TEMPLE_BOSS_KEY);}), + }); + + //Assumes lens is checked on entry + areaTable[RR_SHADOW_TEMPLE_MQ_INVISIBLE_MAZE] = Region("Shadow Temple MQ Invisible Maze", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SHADOW_TEMPLE_MQ_BOMB_FLOWER_CHEST, (logic->CanUse(RG_LENS_OF_TRUTH) || ctx->GetTrickOption(RT_LENS_SHADOW_MQ_DEADHAND)) && logic->CanKillEnemy(RE_DEAD_HAND) && logic->CanDetonateUprightBombFlower()), + LOCATION(RC_SHADOW_TEMPLE_MQ_FREESTANDING_KEY, true), + LOCATION(RC_SHADOW_TEMPLE_MQ_DEAD_HAND_POT_1, logic->CanBreakPots()), + LOCATION(RC_SHADOW_TEMPLE_MQ_DEAD_HAND_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_SHADOW_TEMPLE_MQ_BEYOND_BOAT, []{return true;}), + Entrance(RR_SHADOW_TEMPLE_MQ_SPIKE_WALLS_ROOM, []{return logic->SmallKeys(RR_SHADOW_TEMPLE, 6);}), + }); + + areaTable[RR_SHADOW_TEMPLE_MQ_SPIKE_WALLS_ROOM] = Region("Shadow Temple MQ Spike Walls Room", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SHADOW_TEMPLE_MQ_SPIKE_WALLS_LEFT_CHEST, logic->CanUse(RG_DINS_FIRE)), + LOCATION(RC_SHADOW_TEMPLE_MQ_BOSS_KEY_CHEST, logic->CanUse(RG_DINS_FIRE)), + LOCATION(RC_SHADOW_TEMPLE_MQ_SPIKE_BARICADE_POT, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_SHADOW_TEMPLE_MQ_INVISIBLE_MAZE, []{return logic->SmallKeys(RR_SHADOW_TEMPLE, 6) && (ctx->GetTrickOption(RT_LENS_SHADOW_MQ) || logic->CanUse(RG_LENS_OF_TRUTH));}), + }); + +#pragma endregion + + // Boss Room + areaTable[RR_SHADOW_TEMPLE_BOSS_ENTRYWAY] = Region("Shadow Temple Boss Entryway", "Shadow Temple", {RA_SHADOW_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + // Exits + Entrance(RR_SHADOW_TEMPLE_BEYOND_BOAT, []{return ctx->GetDungeon(SHADOW_TEMPLE)->IsVanilla() && false;}), + Entrance(RR_SHADOW_TEMPLE_MQ_BEYOND_BOAT, []{return ctx->GetDungeon(SHADOW_TEMPLE)->IsMQ() && false;}), + Entrance(RR_SHADOW_TEMPLE_BOSS_ROOM, []{return true;}), + }); + + areaTable[RR_SHADOW_TEMPLE_BOSS_ROOM] = Region("Shadow Temple Boss Room", "Shadow Temple", {}, NO_DAY_NIGHT_CYCLE, { + // Events + EventAccess(&logic->ShadowTempleClear, []{ + return logic->ShadowTempleClear || (logic->HasBossSoul(RG_BONGO_BONGO_SOUL) && ((logic->CanUse(RG_LENS_OF_TRUTH) || ctx->GetTrickOption(RT_LENS_BONGO)) && + (logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD)) && + (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT) || ctx->GetTrickOption(RT_SHADOW_BONGO)))); + }), + }, { + // Locations + LOCATION(RC_SHADOW_TEMPLE_BONGO_BONGO_HEART, logic->ShadowTempleClear), + LOCATION(RC_BONGO_BONGO, logic->ShadowTempleClear), + }, { + // Exits + Entrance(RR_SHADOW_TEMPLE_BOSS_ENTRYWAY, []{return false;}), + Entrance(RR_GRAVEYARD_WARP_PAD_REGION, []{return logic->ShadowTempleClear;}, false), + }); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/spirit_temple.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/spirit_temple.cpp new file mode 100644 index 000000000..30481922c --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/spirit_temple.cpp @@ -0,0 +1,557 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" +#include "soh/Enhancements/randomizer/dungeon.h" + +using namespace Rando; + +void RegionTable_Init_SpiritTemple() { + // Vanilla/MQ Decider + areaTable[RR_SPIRIT_TEMPLE_ENTRYWAY] = Region("Spirit Temple Entryway", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_LOBBY, []{return ctx->GetDungeon(SPIRIT_TEMPLE)->IsVanilla();}), + Entrance(RR_SPIRIT_TEMPLE_MQ_LOBBY, []{return ctx->GetDungeon(SPIRIT_TEMPLE)->IsMQ();}), + Entrance(RR_DESERT_COLOSSUS_OUTSIDE_TEMPLE, []{return true;}), + }); + +#pragma region Vanilla + + areaTable[RR_SPIRIT_TEMPLE_LOBBY] = Region("Spirit Temple Lobby", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SPIRIT_TEMPLE_LOBBY_POT_1, logic->CanBreakPots()), + LOCATION(RC_SPIRIT_TEMPLE_LOBBY_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_ENTRYWAY, []{return true;}), + Entrance(RR_SPIRIT_TEMPLE_CHILD, []{return logic->IsChild;}), + Entrance(RR_SPIRIT_TEMPLE_EARLY_ADULT, []{return logic->CanUse(RG_SILVER_GAUNTLETS);}), + }); + + areaTable[RR_SPIRIT_TEMPLE_CHILD] = Region("Child Spirit Temple", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->NutCrate, []{return true;}), + }, { + //Locations + LOCATION(RC_SPIRIT_TEMPLE_CHILD_BRIDGE_CHEST, (logic->CanUse(RG_BOOMERANG) || logic->CanUse(RG_FAIRY_SLINGSHOT) || (logic->CanUse(RG_BOMBCHU_5) && ctx->GetTrickOption(RT_SPIRIT_CHILD_CHU))) && (logic->HasExplosives() || ((logic->CanUse(RG_NUTS) || logic->CanUse(RG_BOOMERANG)) && (logic->CanUse(RG_STICKS) || logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_FAIRY_SLINGSHOT))))), + LOCATION(RC_SPIRIT_TEMPLE_CHILD_EARLY_TORCHES_CHEST, (logic->CanUse(RG_BOOMERANG) || logic->CanUse(RG_FAIRY_SLINGSHOT) || (logic->CanUse(RG_BOMBCHU_5) && ctx->GetTrickOption(RT_SPIRIT_CHILD_CHU))) && (logic->HasExplosives() || ((logic->CanUse(RG_NUTS) || logic->CanUse(RG_BOOMERANG)) && (logic->CanUse(RG_STICKS) || logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_FAIRY_SLINGSHOT)))) && (logic->CanUse(RG_STICKS) || logic->CanUse(RG_DINS_FIRE))), + LOCATION(RC_SPIRIT_TEMPLE_GS_METAL_FENCE, (logic->CanUse(RG_BOOMERANG) || logic->CanUse(RG_FAIRY_SLINGSHOT) || (logic->CanUse(RG_BOMBCHU_5) && ctx->GetTrickOption(RT_SPIRIT_CHILD_CHU))) && (logic->HasExplosives() || ((logic->CanUse(RG_NUTS) || logic->CanUse(RG_BOOMERANG)) && (logic->CanUse(RG_STICKS) || logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_FAIRY_SLINGSHOT))))), + LOCATION(RC_SPIRIT_TEMPLE_ANUBIS_POT_1, (logic->CanUse(RG_BOOMERANG) || logic->CanUse(RG_FAIRY_SLINGSHOT) || (logic->CanUse(RG_BOMBCHU_5) && ctx->GetTrickOption(RT_SPIRIT_CHILD_CHU))) && (logic->HasExplosives() || ((logic->CanUse(RG_NUTS) || logic->CanUse(RG_BOOMERANG)) && (logic->CanUse(RG_STICKS) || logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_FAIRY_SLINGSHOT))))), + LOCATION(RC_SPIRIT_TEMPLE_ANUBIS_POT_2, (logic->CanUse(RG_BOOMERANG) || logic->CanUse(RG_FAIRY_SLINGSHOT) || (logic->CanUse(RG_BOMBCHU_5) && ctx->GetTrickOption(RT_SPIRIT_CHILD_CHU))) && (logic->HasExplosives() || ((logic->CanUse(RG_NUTS) || logic->CanUse(RG_BOOMERANG)) && (logic->CanUse(RG_STICKS) || logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_FAIRY_SLINGSHOT))))), + LOCATION(RC_SPIRIT_TEMPLE_ANUBIS_POT_3, (logic->CanUse(RG_BOOMERANG) || logic->CanUse(RG_FAIRY_SLINGSHOT) || (logic->CanUse(RG_BOMBCHU_5) && ctx->GetTrickOption(RT_SPIRIT_CHILD_CHU))) && (logic->HasExplosives() || ((logic->CanUse(RG_NUTS) || logic->CanUse(RG_BOOMERANG)) && (logic->CanUse(RG_STICKS) || logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_FAIRY_SLINGSHOT))))), + LOCATION(RC_SPIRIT_TEMPLE_ANUBIS_POT_4, (logic->CanUse(RG_BOOMERANG) || logic->CanUse(RG_FAIRY_SLINGSHOT) || (logic->CanUse(RG_BOMBCHU_5) && ctx->GetTrickOption(RT_SPIRIT_CHILD_CHU))) && (logic->HasExplosives() || ((logic->CanUse(RG_NUTS) || logic->CanUse(RG_BOOMERANG)) && (logic->CanUse(RG_STICKS) || logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_FAIRY_SLINGSHOT))))), + }, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_CHILD_CLIMB, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 1);}), + }); + + areaTable[RR_SPIRIT_TEMPLE_CHILD_CLIMB] = Region("Child Spirit Temple Climb", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SPIRIT_TEMPLE_CHILD_CLIMB_NORTH_CHEST, logic->HasProjectile(HasProjectileAge::Both) || ((logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 2) && ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && logic->BombchuRefill() && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF))) && logic->CanUse(RG_SILVER_GAUNTLETS) && logic->HasProjectile(HasProjectileAge::Adult)) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 5) && logic->IsChild && logic->HasProjectile(HasProjectileAge::Child))), + LOCATION(RC_SPIRIT_TEMPLE_CHILD_CLIMB_EAST_CHEST, logic->HasProjectile(HasProjectileAge::Both) || ((logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 2) && ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && logic->BombchuRefill() && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF))) && logic->CanUse(RG_SILVER_GAUNTLETS) && logic->HasProjectile(HasProjectileAge::Adult)) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 5) && logic->IsChild && logic->HasProjectile(HasProjectileAge::Child))), + LOCATION(RC_SPIRIT_TEMPLE_GS_SUN_ON_FLOOR_ROOM, logic->HasProjectile(HasProjectileAge::Both) || logic->CanUse(RG_DINS_FIRE) || + (logic->TakeDamage() && (logic->CanJumpslashExceptHammer() || logic->HasProjectile(HasProjectileAge::Child))) || + (logic->IsChild && logic->SmallKeys(RR_SPIRIT_TEMPLE, 5) && logic->HasProjectile(HasProjectileAge::Child)) || + ((logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 2) && ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && logic->BombchuRefill() && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF))) && logic->CanUse(RG_SILVER_GAUNTLETS) && (logic->HasProjectile(HasProjectileAge::Adult) || (logic->TakeDamage() && logic->CanJumpslashExceptHammer())))), + LOCATION(RC_SPIRIT_TEMPLE_CHILD_CLIMB_POT_1, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_CENTRAL_CHAMBER, []{return logic->HasExplosives() || (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS));}), + }); + + areaTable[RR_SPIRIT_TEMPLE_EARLY_ADULT] = Region("Early Adult Spirit Temple", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SPIRIT_TEMPLE_COMPASS_CHEST, logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_ZELDAS_LULLABY)), + LOCATION(RC_SPIRIT_TEMPLE_EARLY_ADULT_RIGHT_CHEST, (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_BOOMERANG) || logic->CanUse(RG_BOMBCHU_5) || (logic->CanUse(RG_BOMB_BAG) && logic->IsAdult && ctx->GetTrickOption(RT_SPIRIT_LOWER_ADULT_SWITCH))) && (logic->CanUse(RG_HOVER_BOOTS) || logic->CanJumpslashExceptHammer())), + LOCATION(RC_SPIRIT_TEMPLE_FIRST_MIRROR_LEFT_CHEST, logic->SmallKeys(RR_SPIRIT_TEMPLE, 3)), + LOCATION(RC_SPIRIT_TEMPLE_FIRST_MIRROR_RIGHT_CHEST, logic->SmallKeys(RR_SPIRIT_TEMPLE, 3)), + LOCATION(RC_SPIRIT_TEMPLE_GS_BOULDER_ROOM, logic->CanUse(RG_SONG_OF_TIME) && (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_BOMBCHU_5) || (logic->CanUse(RG_BOMB_BAG) && ctx->GetTrickOption(RT_SPIRIT_LOWER_ADULT_SWITCH)))), + LOCATION(RC_SPIRIT_TEMPLE_BOULDER_ROOM_SUN_FAIRY, logic->CanUse(RG_SUNS_SONG) && (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_BOOMERANG) || logic->CanUse(RG_BOMBCHU_5) || (logic->CanUse(RG_BOMB_BAG) && logic->IsAdult && ctx->GetTrickOption(RT_SPIRIT_LOWER_ADULT_SWITCH))) && (logic->CanUse(RG_HOVER_BOOTS) || logic->CanJumpslash())), + }, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_CENTRAL_CHAMBER, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 1);}), + }); + + areaTable[RR_SPIRIT_TEMPLE_CENTRAL_CHAMBER] = Region("Spirit Temple Central Chamber", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SPIRIT_TEMPLE_MAP_CHEST, ((logic->HasExplosives() || logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 2) && ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && logic->BombchuRefill() && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF))) && + (logic->CanUse(RG_DINS_FIRE) || ((logic->CanUse(RG_FIRE_ARROWS) || ctx->GetTrickOption(RT_SPIRIT_MAP_CHEST)) && logic->CanUse(RG_FAIRY_BOW) && logic->CanUse(RG_STICKS) ))) || + (logic->SmallKeys(RR_SPIRIT_TEMPLE, 5) && logic->HasExplosives() && logic->CanUse(RG_STICKS)) || + (logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) && (logic->CanUse(RG_FIRE_ARROWS) || (ctx->GetTrickOption(RT_SPIRIT_MAP_CHEST) && logic->CanUse(RG_FAIRY_BOW))) && logic->CanUse(RG_SILVER_GAUNTLETS))), + LOCATION(RC_SPIRIT_TEMPLE_SUN_BLOCK_ROOM_CHEST, ((logic->HasExplosives() || logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 2) && ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && logic->BombchuRefill() && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF))) && + (logic->CanUse(RG_DINS_FIRE) || ((logic->CanUse(RG_FIRE_ARROWS) || ctx->GetTrickOption(RT_SPIRIT_SUN_CHEST)) && logic->CanUse(RG_FAIRY_BOW) && logic->CanUse(RG_STICKS) ))) || + (logic->SmallKeys(RR_SPIRIT_TEMPLE, 5) && logic->HasExplosives() && logic->CanUse(RG_STICKS)) || + (logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) && (logic->CanUse(RG_FIRE_ARROWS) || (ctx->GetTrickOption(RT_SPIRIT_SUN_CHEST) && logic->CanUse(RG_FAIRY_BOW))) && logic->CanUse(RG_SILVER_GAUNTLETS))), + LOCATION(RC_SPIRIT_TEMPLE_STATUE_ROOM_HAND_CHEST, logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) && logic->CanUse(RG_SILVER_GAUNTLETS) && logic->CanUse(RG_ZELDAS_LULLABY)), + LOCATION(RC_SPIRIT_TEMPLE_STATUE_ROOM_NORTHEAST_CHEST, logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) && logic->CanUse(RG_SILVER_GAUNTLETS) && logic->CanUse(RG_ZELDAS_LULLABY) && (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS) || ctx->GetTrickOption(RT_SPIRIT_LOBBY_JUMP))), + LOCATION(RC_SPIRIT_TEMPLE_GS_HALL_AFTER_SUN_BLOCK_ROOM, (logic->HasExplosives() && logic->CanUse(RG_BOOMERANG) && logic->CanUse(RG_HOOKSHOT)) || + (logic->CanUse(RG_BOOMERANG) && logic->SmallKeys(RR_SPIRIT_TEMPLE, 5) && logic->HasExplosives()) || + (logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_SILVER_GAUNTLETS) && (logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 2) && + logic->CanUse(RG_BOOMERANG) && ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && logic->BombchuRefill() && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF))))), + LOCATION(RC_SPIRIT_TEMPLE_GS_LOBBY, ((logic->HasExplosives() || logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 2) && ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && logic->BombchuRefill() && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF))) && + ctx->GetTrickOption(RT_SPIRIT_LOBBY_GS) && logic->CanUse(RG_BOOMERANG) && (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS) || ctx->GetTrickOption(RT_SPIRIT_LOBBY_JUMP))) || + (ctx->GetTrickOption(RT_SPIRIT_LOBBY_GS) && logic->SmallKeys(RR_SPIRIT_TEMPLE, 5) && logic->HasExplosives() && logic->CanUse(RG_BOOMERANG)) || + (logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) && logic->CanUse(RG_SILVER_GAUNTLETS) && (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS) || ctx->GetTrickOption(RT_SPIRIT_LOBBY_JUMP)))), + LOCATION(RC_SPIRIT_TEMPLE_AFTER_SUN_BLOCK_POT_1, logic->CanBreakPots() && (logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 2) && ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && logic->BombchuRefill() && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF)))), + LOCATION(RC_SPIRIT_TEMPLE_AFTER_SUN_BLOCK_POT_2, logic->CanBreakPots() && (logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 2) && ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && logic->BombchuRefill() && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF)))), + LOCATION(RC_SPIRIT_TEMPLE_CENTRAL_CHAMBER_POT_1, logic->CanBreakPots() && (logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 2) && ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && logic->BombchuRefill() && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF)))), + LOCATION(RC_SPIRIT_TEMPLE_CENTRAL_CHAMBER_POT_2, logic->CanBreakPots() && (logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 2) && ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && logic->BombchuRefill() && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF)))), + LOCATION(RC_SPIRIT_TEMPLE_CENTRAL_CHAMBER_POT_3, logic->CanBreakPots() && (logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 2) && ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && logic->BombchuRefill() && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF)))), + LOCATION(RC_SPIRIT_TEMPLE_CENTRAL_CHAMBER_POT_4, logic->CanBreakPots() && (logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 2) && ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && logic->BombchuRefill() && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF)))), + LOCATION(RC_SPIRIT_TEMPLE_CENTRAL_CHAMBER_POT_5, logic->CanBreakPots() && (logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 2) && ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && logic->BombchuRefill() && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF)))), + LOCATION(RC_SPIRIT_TEMPLE_CENTRAL_CHAMBER_POT_6, logic->CanBreakPots() && (logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) || (logic->SmallKeys(RR_SPIRIT_TEMPLE, 2) && ctx->GetOption(RSK_BOMBCHUS_IN_LOGIC) && logic->BombchuRefill() && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).Is(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF)))), + }, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_OUTDOOR_HANDS, []{return logic->CanJumpslashExceptHammer() || logic->HasExplosives();}), + Entrance(RR_SPIRIT_TEMPLE_BEYOND_CENTRAL_LOCKED_DOOR, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 4) && logic->CanUse(RG_SILVER_GAUNTLETS);}), + Entrance(RR_SPIRIT_TEMPLE_CHILD_CLIMB, []{return true;}), + // RT_SPIRIT_PLATFORM_HOOKSHOT is currently disabled + Entrance(RR_SPIRIT_TEMPLE_INSIDE_STATUE_HEAD, []{return ctx->GetTrickOption(RT_SPIRIT_PLATFORM_HOOKSHOT) && logic->CanUse(RG_HOOKSHOT);}), + }); + + areaTable[RR_SPIRIT_TEMPLE_OUTDOOR_HANDS] = Region("Spirit Temple Outdoor Hands", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SPIRIT_TEMPLE_SILVER_GAUNTLETS_CHEST, (logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) && logic->CanUse(RG_LONGSHOT) && logic->HasExplosives()) || logic->SmallKeys(RR_SPIRIT_TEMPLE, 5)), + LOCATION(RC_SPIRIT_TEMPLE_MIRROR_SHIELD_CHEST, logic->SmallKeys(RR_SPIRIT_TEMPLE, 4) && logic->CanUse(RG_SILVER_GAUNTLETS) && logic->HasExplosives()), + }, { + //Exits + Entrance(RR_DESERT_COLOSSUS, []{return (logic->IsChild && logic->SmallKeys(RR_SPIRIT_TEMPLE, 5)) || (logic->CanUse(RG_SILVER_GAUNTLETS) && ((logic->SmallKeys(RR_SPIRIT_TEMPLE, 3) && logic->HasExplosives()) || logic->SmallKeys(RR_SPIRIT_TEMPLE, 5)));}), + }); + + areaTable[RR_SPIRIT_TEMPLE_BEYOND_CENTRAL_LOCKED_DOOR] = Region("Spirit Temple Beyond Central Locked Door", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SPIRIT_TEMPLE_NEAR_FOUR_ARMOS_CHEST, (logic->CanUse(RG_MIRROR_SHIELD) || (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS))) && logic->HasExplosives()), + LOCATION(RC_SPIRIT_TEMPLE_HALLWAY_LEFT_INVISIBLE_CHEST, (ctx->GetTrickOption(RT_LENS_SPIRIT) || logic->CanUse(RG_LENS_OF_TRUTH)) && logic->HasExplosives()), + LOCATION(RC_SPIRIT_TEMPLE_HALLWAY_RIGHT_INVISIBLE_CHEST, (ctx->GetTrickOption(RT_LENS_SPIRIT) || logic->CanUse(RG_LENS_OF_TRUTH)) && logic->HasExplosives()), + LOCATION(RC_SPIRIT_TEMPLE_BEAMOS_HALL_POT_1, logic->CanBreakPots()), + LOCATION(RC_SPIRIT_TEMPLE_ARMOS_ROOM_SUN_FAIRY, logic->HasExplosives() && logic->CanUse(RG_SUNS_SONG)), + }, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_BEYOND_FINAL_LOCKED_DOOR, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 5) && (ctx->GetTrickOption(RT_SPIRIT_WALL) || logic->CanUse(RG_LONGSHOT) || logic->CanUse(RG_BOMBCHU_5) || ((logic->CanUse(RG_BOMB_BAG) || logic->CanUse(RG_NUTS) || logic->CanUse(RG_DINS_FIRE)) && (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_MEGATON_HAMMER))));}), + }); + + areaTable[RR_SPIRIT_TEMPLE_BEYOND_FINAL_LOCKED_DOOR] = Region("Spirit Temple Beyond Final Locked Door", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SPIRIT_TEMPLE_BOSS_KEY_CHEST, logic->CanUse(RG_ZELDAS_LULLABY) && ((logic->TakeDamage() && ctx->GetTrickOption(RT_FLAMING_CHESTS)) || (logic->CanUse(RG_FAIRY_BOW) && logic->CanUse(RG_HOOKSHOT)))), + LOCATION(RC_SPIRIT_TEMPLE_TOPMOST_CHEST, (logic->CanUse(RG_MIRROR_SHIELD) && logic->CanAttack()) || (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS))), + LOCATION(RC_SPIRIT_TEMPLE_ADULT_CLIMB_LEFT_HEART, logic->CanUse(RG_HOOKSHOT)), + LOCATION(RC_SPIRIT_TEMPLE_ADULT_CLIMB_RIGHT_HEART, logic->CanUse(RG_HOOKSHOT)), + }, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_INSIDE_STATUE_HEAD, []{return logic->CanUse(RG_MIRROR_SHIELD) && logic->HasExplosives() && logic->CanUse(RG_HOOKSHOT);}), + }); + + areaTable[RR_SPIRIT_TEMPLE_INSIDE_STATUE_HEAD] = Region("Spirit Temple Inside Statue Head", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + // Exits + Entrance(RR_SPIRIT_TEMPLE_CENTRAL_CHAMBER, []{return true;}), + Entrance(RR_SPIRIT_TEMPLE_BOSS_ENTRYWAY, []{return logic->HasItem(RG_SPIRIT_TEMPLE_BOSS_KEY);}), + }); + +#pragma endregion + +#pragma region MQ + + areaTable[RR_SPIRIT_TEMPLE_MQ_LOBBY] = Region("Spirit Temple MQ Lobby", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_LEFT_CHEST, true), + LOCATION(RC_SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_LEFT_CHEST, Here(RR_SPIRIT_TEMPLE_MQ_LOBBY, []{return logic->BlastOrSmash();}) && logic->CanHitEyeTargets()), + LOCATION(RC_SPIRIT_TEMPLE_MQ_ENTRANCE_BACK_RIGHT_CHEST, logic->CanHitSwitch(ED_BOOMERANG)), + LOCATION(RC_SPIRIT_TEMPLE_MQ_ENTRANCE_FRONT_RIGHT_CHEST, logic->Spirit1FSilverRupees), + LOCATION(RC_SPIRIT_TEMPLE_MQ_ENTRANCE_POT_1, logic->CanBreakPots()), + LOCATION(RC_SPIRIT_TEMPLE_MQ_ENTRANCE_POT_2, logic->CanBreakPots()), + LOCATION(RC_SPIRIT_TEMPLE_MQ_ENTRANCE_POT_3, logic->CanBreakPots()), + LOCATION(RC_SPIRIT_TEMPLE_MQ_ENTRANCE_POT_4, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_ENTRYWAY, []{return true;}), + Entrance(RR_SPIRIT_TEMPLE_MQ_1F_WEST, []{return logic->IsChild;}), + Entrance(RR_SPIRIT_TEMPLE_MQ_BIG_BLOCK_ROOM_SOUTH, []{return logic->CanUse(RG_LONGSHOT) && logic->CanUse(RG_BOMBCHU_5);}), + }); + + areaTable[RR_SPIRIT_TEMPLE_MQ_1F_WEST] = Region("Spirit Temple MQ 1F West", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + //not technically a rusted switch, but a boulder through a wall, but is part of the same trick on N64 + EventAccess(&logic->MQSpiritCrawlBoulder, []{return logic->CanUse(RG_BOMBCHU_5) || (ctx->GetTrickOption(RT_RUSTED_SWITCHES) && logic->CanUse(RG_MEGATON_HAMMER));}), + }, { + //Locations + LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_HAMMER_SWITCH_CHEST, logic->MQSpiritTimeTravelChest), + LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_SLUGMA_POT, logic->CanBreakPots()), + LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_LEFT_HEART, logic->CanHitEyeTargets()), + LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_RIGHT_HEART, logic->CanHitEyeTargets()), + }, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_MQ_1F_GIBDO_ROOM_SOUTH, []{return Here(RR_SPIRIT_TEMPLE_MQ_1F_WEST, []{return logic->CanKillEnemy(RE_TORCH_SLUG);});}), + Entrance(RR_SPIRIT_TEMPLE_MQ_MAP_ROOM_SOUTH, []{return Here(RR_SPIRIT_TEMPLE_MQ_1F_WEST, []{return logic->CanKillEnemy(RE_TORCH_SLUG);});}), + Entrance(RR_SPIRIT_TEMPLE_MQ_WEST_1F_RUSTED_SWITCH, []{return logic->IsChild && logic->MQSpiritCrawlBoulder;}), + }); + + areaTable[RR_SPIRIT_TEMPLE_MQ_1F_GIBDO_ROOM_SOUTH] = Region("Spirit Temple MQ 1F Gibdo Room South", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_MQ_1F_WEST, []{return true;}), + Entrance(RR_SPIRIT_TEMPLE_MQ_1F_GIBDO_ROOM_NORTH, []{return logic->CanUse(RG_BOMBCHU_5) && logic->CanHitEyeTargets();}), + Entrance(RR_SPIRIT_TEMPLE_MQ_TURNTABLE_ROOM, []{return logic->CanUse(RG_BOMBCHU_5) && logic->CanHitEyeTargets() && logic->CanKillEnemy(RE_GIBDO);}), + }); + + // Room to store the 2 pots in to handle glitch logic going backwards around the loop later + areaTable[RR_SPIRIT_TEMPLE_MQ_1F_GIBDO_ROOM_NORTH] = Region("Spirit Temple MQ Gibdo Room North", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_GIBDO_POT_1, logic->CanBreakPots()), + LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_GIBDO_POT_2, logic->CanBreakPots()), + }, {}); + + areaTable[RR_SPIRIT_TEMPLE_MQ_TURNTABLE_ROOM] = Region("Spirit Temple Turntable Room", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + //For non-fairy pot items, you can also get them with rang without killing the stalfos + EventAccess(&logic->FairyPot, []{return Here(RR_SPIRIT_TEMPLE_MQ_TURNTABLE_ROOM, []{return logic->CanKillEnemy(RE_STALFOS);});}), + }, { + //Locations + //implies logic->CanBreakPots() + LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_STALFOS_POT_1, logic->CanUse(RG_BOOMERANG) || logic->CanKillEnemy(RE_STALFOS)), + LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_STALFOS_POT_2, logic->CanUse(RG_BOOMERANG) || logic->CanKillEnemy(RE_STALFOS)), + LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_STALFOS_POT_3, logic->CanUse(RG_BOOMERANG) || logic->CanKillEnemy(RE_STALFOS)), + LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_STALFOS_POT_4, logic->CanUse(RG_BOOMERANG) || logic->CanKillEnemy(RE_STALFOS)), + }, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_MQ_1F_GIBDO_ROOM_NORTH, []{return true;}), + Entrance(RR_SPIRIT_TEMPLE_MQ_MAP_ROOM_NORTH, []{return Here(RR_SPIRIT_TEMPLE_MQ_TURNTABLE_ROOM, []{return logic->CanKillEnemy(RE_STALFOS);});}), + }); + + areaTable[RR_SPIRIT_TEMPLE_MQ_MAP_ROOM_NORTH] = Region("Spirit Temple MQ Map Room North", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->MQSpiritMapRoomEnemies, []{return logic->CanKillEnemy(RE_ANUBIS) && logic->CanKillEnemy(RE_KEESE);}), + }, { + //Locations + LOCATION(RC_SPIRIT_TEMPLE_MQ_MAP_ROOM_ENEMY_CHEST, logic->MQSpiritMapRoomEnemies), + }, { + //Exits + //Stalfos room blocks you in with fire until you kill the stalfos, which won't spawn from behind the fire + Entrance(RR_SPIRIT_TEMPLE_MQ_MAP_ROOM_SOUTH, []{return true;}), + }); + + areaTable[RR_SPIRIT_TEMPLE_MQ_MAP_ROOM_SOUTH] = Region("Spirit Temple MQ Map Room South", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + //You can lure the keese over by aggroing them with dins if you use it as close to the torch keese as possible, but it's a trick as it's not intuitive and basically never comes up + EventAccess(&logic->MQSpiritMapRoomEnemies, []{return logic->CanKillEnemy(RE_ANUBIS) && logic->CanKillEnemy(RE_KEESE, ED_BOOMERANG);}), + }, { + //Locations + LOCATION(RC_SPIRIT_TEMPLE_MQ_MAP_CHEST, true), + }, { + //Exits + //The bridge is a temp flag, so not a way to cross south to north in logic + Entrance(RR_SPIRIT_TEMPLE_MQ_MAP_ROOM_NORTH, []{return logic->CanUse(RG_HOOKSHOT);}), + Entrance(RR_SPIRIT_TEMPLE_MQ_1F_WEST, []{return true;}), + }); + + areaTable[RR_SPIRIT_TEMPLE_MQ_WEST_1F_RUSTED_SWITCH] = Region("Spirit Temple MQ West 1F Rusted Switch", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->MQSpiritTimeTravelChest, []{return logic->CanUse(RG_MEGATON_HAMMER);}), + EventAccess(&logic->MQSpiritCrawlBoulder, []{return logic->CanUse(RG_BOMBCHU_5) || (ctx->GetTrickOption(RT_RUSTED_SWITCHES) && logic->CanUse(RG_MEGATON_HAMMER));}), + }, {}, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_MQ_1F_WEST, []{return logic->IsChild && logic->MQSpiritCrawlBoulder;}), + //This tracks possible child access, if adult has not entered STATUE_ROOM. Certain Child Access is checked for separately as 7 Keys + Entrance(RR_SPIRIT_TEMPLE_MQ_UNDER_LIKE_LIKE, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 1);}), + }); + + areaTable[RR_SPIRIT_TEMPLE_MQ_UNDER_LIKE_LIKE] = Region("Spirit Temple MQ Under Like Like", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_LIKE_LIKE_POT, MQSpiritSharedBrokenWallRoom(RR_SPIRIT_TEMPLE_MQ_UNDER_LIKE_LIKE, []{return logic->CanBreakPots();})), + }, { + //Exits + //This covers adult access only, as child arrives here from the other side of this door + Entrance(RR_SPIRIT_TEMPLE_MQ_WEST_1F_RUSTED_SWITCH, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 7);}), + Entrance(RR_SPIRIT_TEMPLE_MQ_BROKEN_WALL_ROOM, []{return logic->CanHitSwitch();}), + }); + + areaTable[RR_SPIRIT_TEMPLE_MQ_BROKEN_WALL_ROOM] = Region("Spirit Temple MQ Broken Wall Room", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + //Implies CanKillEnemy(RE_LIKE_LIKE) + LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_CLIMB_NORTH_CHEST, MQSpiritSharedBrokenWallRoom(RR_SPIRIT_TEMPLE_MQ_BROKEN_WALL_ROOM, []{return logic->CanKillEnemy(RE_BEAMOS);})), + //Sunlights only temp spawn this chest, which is unintuitive/a bug. + //chest is only reachable as adult glitchlessly, so we can skip the shared in favour of IsAdult as adult access is always Certain + LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_CLIMB_SOUTH_CHEST, logic->IsAdult && logic->HasExplosives() && (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS)) && logic->CanUse(RG_HOOKSHOT)), + }, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_MQ_UNDER_LIKE_LIKE, []{return logic->CanHitSwitch();}), + //This exit only governs child possible access, adult access starts on the other side so never checks this + Entrance(RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 2);}), + }); + + areaTable[RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM] = Region("Spirit Temple MQ Statue Room", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SPIRIT_TEMPLE_MQ_COMPASS_CHEST, MQSpiritSharedStatueRoom(RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM, []{return logic->CanHitEyeTargets();})), + LOCATION(RC_SPIRIT_TEMPLE_MQ_STATUE_3F_EAST_POT, MQSpiritSharedStatueRoom(RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM, []{return ((logic->IsAdult || logic->CanJumpslash()) && logic->CanUse(RG_BOOMERANG)) || ((logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_SONG_OF_TIME) || (logic->IsAdult && ctx->GetTrickOption(RT_SPIRIT_LOBBY_JUMP))) && logic->CanBreakPots());})), + LOCATION(RC_SPIRIT_TEMPLE_MQ_STATUE_3F_WEST_POT, MQSpiritSharedStatueRoom(RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM, []{return (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_SONG_OF_TIME) || (logic->IsAdult && ctx->GetTrickOption(RT_SPIRIT_LOBBY_JUMP)) && logic->CanBreakPots());})), + LOCATION(RC_SPIRIT_TEMPLE_MQ_STATUE_2F_CENTER_EAST_POT, MQSpiritSharedStatueRoom(RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM, []{return logic->CanBreakPots();})), + LOCATION(RC_SPIRIT_TEMPLE_MQ_STATUE_2F_WEST_POT, MQSpiritSharedStatueRoom(RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM, []{return logic->CanBreakPots();})), + LOCATION(RC_SPIRIT_TEMPLE_MQ_STATUE_2F_EASTMOST_POT, MQSpiritSharedStatueRoom(RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM, []{return logic->CanBreakPots();})), + }, { + //Exits + //we check possible adult access directly in MQSpiritSharedBrokenWallRoom, so this exit only covers Certain Access + Entrance(RR_SPIRIT_TEMPLE_MQ_BROKEN_WALL_ROOM, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 7);}), + //We can use Here instead of Shared here because adult will never need to rely on child access to reach this room, and adult access is Certain + Entrance(RR_SPIRIT_TEMPLE_MQ_BIG_BLOCK_ROOM_NORTH, []{return Here(RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM, []{return logic->HasFireSource() || (ctx->GetTrickOption(RT_SPIRIT_MQ_FROZEN_EYE) && logic->CanUse(RG_FAIRY_BOW) && logic->CanUse(RG_SONG_OF_TIME));});}), + Entrance(RR_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM, []{return logic->IsAdult || ctx->GetTrickOption(RT_SPIRIT_MQ_SUN_BLOCK_SOT) || logic->CanUse(RG_SONG_OF_TIME);}), + //explicit adult check here is a precaution against possible child logic leaking, child with a hookshot can do this + Entrance(RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM_EAST, []{return logic->IsAdult && logic->CanUse(RG_HOOKSHOT);}), + }); + + areaTable[RR_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM] = Region("Spirit Temple MQ Sun Block Room", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + //We don't need Shared here because If we are checking as child, universe 2 adult access needs nothing so it always passes, and if we are checking as adult, it is Certain Access + LOCATION(RC_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM_CHEST, true), + LOCATION(RC_SPIRIT_TEMPLE_MQ_GS_SUN_BLOCK_ROOM, MQSpiritSharedStatueRoom(RR_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM, []{return logic->CanUse(RG_HOOKSHOT) || (ctx->GetTrickOption(RT_SPIRIT_MQ_SUN_BLOCK_GS) && logic->CanUse(RG_BOOMERANG));})), + LOCATION(RC_SPIRIT_TEMPLE_MQ_SUN_BLOCKS_POT_1, MQSpiritSharedStatueRoom(RR_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM, []{return logic->CanBreakPots();})), + LOCATION(RC_SPIRIT_TEMPLE_MQ_SUN_BLOCKS_POT_2, MQSpiritSharedStatueRoom(RR_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM, []{return logic->CanBreakPots();})), + }, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM, []{return true;}), + //This door causes the Universes to merge as it requires 7 keys for both ages + Entrance(RR_SPIRIT_TEMPLE_MQ_WEST_IRON_KNUCKLE, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 7);}), + }); + + areaTable[RR_SPIRIT_TEMPLE_MQ_WEST_IRON_KNUCKLE] = Region("Spirit Temple MQ East Iron Knuckle", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_MQ_SUN_BLOCK_ROOM, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 7);}), + Entrance(RR_SPIRIT_TEMPLE_MQ_SILVER_GAUNTLETS_HAND, []{return logic->CanKillEnemy(RE_IRON_KNUCKLE);}), + }); + + areaTable[RR_SPIRIT_TEMPLE_MQ_SILVER_GAUNTLETS_HAND] = Region("Spirit Temple MQ Silver Gauntlets Hand", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SPIRIT_TEMPLE_SILVER_GAUNTLETS_CHEST, true), + }, { + //Exits + //If it is ever relevent for 1 age to spawn the mirror shield chest for the other can longshot across, it needs an eventAccess + Entrance(RR_SPIRIT_TEMPLE_MQ_WEST_IRON_KNUCKLE, []{return true;}), + Entrance(RR_DESERT_COLOSSUS, []{return true;}), + }); + + areaTable[RR_SPIRIT_TEMPLE_MQ_BIG_BLOCK_ROOM_SOUTH] = Region("Spirit Temple MQ Block Room South", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_MQ_LOBBY, []{return true;}), + //The block here is unusual in that it is a permanent flag, but reset anyway as child. This is because there's a check that would be blocked off by pushing them otherwise + //It may be worth considering making this always temp in future so adult doesn't have the same issue + Entrance(RR_SPIRIT_TEMPLE_MQ_BIG_BLOCK_ROOM_NORTH, []{return logic->IsChild ? logic->CanUse(RG_SILVER_GAUNTLETS) : Here(RR_SPIRIT_TEMPLE_MQ_LOBBY, []{return logic->CanUse(RG_SILVER_GAUNTLETS);});}), + }); + + areaTable[RR_SPIRIT_TEMPLE_MQ_BIG_BLOCK_ROOM_NORTH] = Region("Spirit Temple MQ Block Room North", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + //Does not need to be shared as it's hard child locked, because adult pushing the block is a permanent flag that blocks the eye target and cannot be undone + LOCATION(RC_SPIRIT_TEMPLE_MQ_SILVER_BLOCK_HALLWAY_CHEST, logic->IsChild && logic->SmallKeys(RR_SPIRIT_TEMPLE, 7) && logic->CanHitEyeTargets()), + }, { + //Exits + //if going to RR_SPIRIT_TEMPLE_MQ_BIG_BLOCK_ROOM_SOUTH from here is ever relevant, there needs to be an event to handle the block + Entrance(RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM, []{return true;}), + }); + + areaTable[RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM_EAST] = Region("Spirit Temple MQ Statue Room East", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SPIRIT_TEMPLE_MQ_STATUE_ROOM_LULLABY_CHEST, logic->CanUse(RG_HOOKSHOT) & logic->CanUse(RG_ZELDAS_LULLABY) && (logic->CanJumpslash() || logic->CanUse(RG_HOVER_BOOTS))), + LOCATION(RC_SPIRIT_TEMPLE_MQ_STATUE_ROOM_INVISIBLE_CHEST, (ctx->GetTrickOption(RT_LENS_SPIRIT_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)) && (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS))), + }, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM, []{return true;}), + //!QUANTUM LOGIC! + //We only need 4 keys, access to Shield hand and longshot to reach Gauntlets hand, as if we waste the 5th key we have given ourselves Gauntlets hand access through child climb + //This exit handles that possibility as cleanly as possible without quantum logic, but will not survive glitch logic + //logic->CanKillEnemy(RE_FLOORMASTER) is implied + Entrance(RR_SPIRIT_TEMPLE_MQ_SILVER_GAUNTLETS_HAND, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 4) && + logic->CanAvoidEnemy(RE_BEAMOS, true, 4) && logic->CanUse(RG_SONG_OF_TIME) && + logic->CanJumpslash() && + (ctx->GetTrickOption(RT_LENS_SPIRIT_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)) && + logic->CanKillEnemy(RE_IRON_KNUCKLE) && + logic->CanUse(RG_LONGSHOT);}), + Entrance(RR_SPIRIT_TEMPLE_MQ_FOUR_BEAMOS_ROOM, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 5) && logic->CanUse(RG_HOOKSHOT);}), + Entrance(RR_SPIRIT_TEMPLE_MQ_THREE_SUNS_ROOM_2F, []{return logic->CanUse(RG_FIRE_ARROWS) || (ctx->GetTrickOption(RT_SPIRIT_MQ_LOWER_ADULT) && logic->CanUse(RG_DINS_FIRE));}), + }); + + areaTable[RR_SPIRIT_TEMPLE_MQ_THREE_SUNS_ROOM_2F] = Region("Spirit Temple MQ Three Suns Room 2F", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + //implies logic->CanKillEnemy(RE_WALLMASTER). If we have lights, we can kill stalfos and wallmasters with bow + EventAccess(&logic->MQSpirit3SunsEnemies, []{return (logic->CanUse(RG_MIRROR_SHIELD) && logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 2)) || (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS));}), + }, {}, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM_EAST, []{return true;}), + Entrance(RR_SPIRIT_TEMPLE_MQ_THREE_SUNS_ROOM_1F, []{return logic->MQSpirit3SunsEnemies;}), + }); + + areaTable[RR_SPIRIT_TEMPLE_MQ_THREE_SUNS_ROOM_1F] = Region("Spirit Temple MQ Three Suns Room 1F", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_MQ_THREE_SUNS_ROOM_2F, []{return logic->MQSpirit3SunsEnemies;}), + Entrance(RR_SPIRIT_TEMPLE_MQ_1F_EAST, []{return true;}), + }); + + areaTable[RR_SPIRIT_TEMPLE_MQ_1F_EAST] = Region("Spirit Temple MQ 1F East", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + //Assumes RR_SPIRIT_TEMPLE_MQ_LOBBY access + EventAccess(&logic->Spirit1FSilverRupees, []{return logic->CanUse(RG_MEGATON_HAMMER);}), + }, { + //Locations + LOCATION(RC_SPIRIT_TEMPLE_MQ_EARLY_ADULT_POT_1, logic->CanBreakPots()), + LOCATION(RC_SPIRIT_TEMPLE_MQ_EARLY_ADULT_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_MQ_LOBBY, []{return logic->CanUse(RG_MEGATON_HAMMER);}), + Entrance(RR_SPIRIT_TEMPLE_MQ_THREE_SUNS_ROOM_1F, []{return true;}), + Entrance(RR_SPIRIT_TEMPLE_MQ_LEEVER_ROOM, []{return true;}), + Entrance(RR_SPIRIT_TEMPLE_MQ_SYMPHONY_ROOM, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 7);}), + }); + + areaTable[RR_SPIRIT_TEMPLE_MQ_LEEVER_ROOM] = Region("Spirit Temple MQ Leever Room", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SPIRIT_TEMPLE_MQ_LEEVER_ROOM_CHEST, logic->CanKillEnemy(RE_PURPLE_LEEVER) && logic->CanUse(RG_HOOKSHOT)), + LOCATION(RC_SPIRIT_TEMPLE_MQ_GS_LEEVER_ROOM, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)), + }, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_MQ_1F_EAST, []{return logic->CanUse(RG_ZELDAS_LULLABY);}), + }); + + areaTable[RR_SPIRIT_TEMPLE_MQ_SYMPHONY_ROOM] = Region("Spirit Temple MQ Symphony Room", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_MQ_1F_EAST, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 7);}), + //Implies CanPassEnemy(RE_MOBLIN_CHIEF) + Entrance(RR_SPIRIT_TEMPLE_MQ_AFTER_SYMPHONY_ROOM, []{return logic->CanUse(RG_MEGATON_HAMMER) && logic->CanUse(RG_SONG_OF_TIME) && logic->CanUse(RG_EPONAS_SONG) && logic->CanUse(RG_SUNS_SONG) && logic->CanUse(RG_SONG_OF_STORMS) && logic->CanUse(RG_ZELDAS_LULLABY);}), + }); + + areaTable[RR_SPIRIT_TEMPLE_MQ_AFTER_SYMPHONY_ROOM] = Region("Spirit Temple MQ After Symphony Room", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SPIRIT_TEMPLE_MQ_SYMPHONY_ROOM_CHEST, logic->CanPassEnemy(RE_BIG_SKULLTULA)), + LOCATION(RC_SPIRIT_TEMPLE_MQ_GS_SYMPHONY_ROOM, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)), + }, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_MQ_SYMPHONY_ROOM, []{return true;}), + }); + + areaTable[RR_SPIRIT_TEMPLE_MQ_FOUR_BEAMOS_ROOM] = Region("Spirit Temple MQ Four Beamos Room", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SPIRIT_TEMPLE_MQ_BEAMOS_ROOM_CHEST, logic->CanKillEnemy(RE_BEAMOS)), + }, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM_EAST, []{return logic->CanAvoidEnemy(RE_BEAMOS, true, 4) && logic->CanUse(RG_SONG_OF_TIME) && logic->SmallKeys(RR_SPIRIT_TEMPLE, 5) && logic->CanUse(RG_HOOKSHOT);}), + Entrance(RR_SPIRIT_TEMPLE_MQ_SOT_SUN_ROOM, []{return logic->CanAvoidEnemy(RE_BEAMOS, true, 4) && logic->CanUse(RG_SONG_OF_TIME);}), + Entrance(RR_SPIRIT_TEMPLE_MQ_BIG_WALL, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 6);}), + }); + + areaTable[RR_SPIRIT_TEMPLE_MQ_SOT_SUN_ROOM] = Region("Spirit Temple MQ SoT Sun Room", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SPIRIT_TEMPLE_MQ_CHEST_SWITCH_CHEST, true), + LOCATION(RC_SPIRIT_TEMPLE_MQ_DINALFOS_ROOM_SUN_FAIRY, logic->CanUse(RG_SUNS_SONG)), + }, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_MQ_FOUR_BEAMOS_ROOM, []{return true;}), + Entrance(RR_SPIRIT_TEMPLE_MQ_EAST_STAIRS_TO_HAND, []{return logic->CanJumpslash();}), + Entrance(RR_SPIRIT_TEMPLE_MQ_3F_GIBDO_ROOM, []{return Here(RR_SPIRIT_TEMPLE_MQ_SOT_SUN_ROOM, []{return (logic->IsAdult || logic->CanUse(RG_SONG_OF_TIME)) && logic->CanUse(RG_MIRROR_SHIELD);});}), + }); + + areaTable[RR_SPIRIT_TEMPLE_MQ_EAST_STAIRS_TO_HAND] = Region("Spirit Temple MQ East Stairs to Hand", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_MQ_SOT_SUN_ROOM, []{return true;}), + Entrance(RR_SPIRIT_TEMPLE_MQ_EAST_IRON_KNUCKLE, []{return (ctx->GetTrickOption(RT_LENS_SPIRIT_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)) && Here(RR_SPIRIT_TEMPLE_MQ_EAST_STAIRS_TO_HAND, []{return logic->CanKillEnemy(RE_FLOORMASTER);});}), + }); + + areaTable[RR_SPIRIT_TEMPLE_MQ_EAST_IRON_KNUCKLE] = Region("Spirit Temple MQ East Iron Knuckle", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_MQ_EAST_STAIRS_TO_HAND, []{return true;}), + Entrance(RR_SPIRIT_TEMPLE_MQ_MIRROR_SHIELD_HAND, []{return Here(RR_SPIRIT_TEMPLE_MQ_EAST_STAIRS_TO_HAND, []{return logic->CanKillEnemy(RE_IRON_KNUCKLE);});}), + }); + + areaTable[RR_SPIRIT_TEMPLE_MQ_MIRROR_SHIELD_HAND] = Region("Spirit Temple MQ Mirror Shield Hand", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SPIRIT_TEMPLE_MIRROR_SHIELD_CHEST, true), + }, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_MQ_SILVER_GAUNTLETS_HAND, []{return logic->CanUse(RG_LONGSHOT);}), + Entrance(RR_SPIRIT_TEMPLE_MQ_EAST_IRON_KNUCKLE, []{return true;}), + Entrance(RR_DESERT_COLOSSUS, []{return true;}), + }); + + areaTable[RR_SPIRIT_TEMPLE_MQ_3F_GIBDO_ROOM] = Region("Spirit Temple MQ 3F Gibdo Room", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SPIRIT_TEMPLE_MQ_BOSS_KEY_CHEST, true), + }, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_MQ_SOT_SUN_ROOM, []{return true;}), + }); + + areaTable[RR_SPIRIT_TEMPLE_MQ_BIG_WALL] = Region("Spirit Temple MQ Big Wall", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SPIRIT_TEMPLE_MQ_LONG_CLIMB_POT_1, logic->CanBreakPots()), + LOCATION(RC_SPIRIT_TEMPLE_MQ_LONG_CLIMB_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_MQ_FOUR_BEAMOS_ROOM, []{return true;}), + //technically we only need to avoid them, but the sheer height and the moving walls makes getting to the top after only stunning them very difficult/impossible + //The silver rupees are irrelevant without silver shuffle + Entrance(RR_SPIRIT_TEMPLE_MQ_4F_CENTRAL, []{return logic->CanKillEnemy(RE_KEESE);}), + }); + + areaTable[RR_SPIRIT_TEMPLE_MQ_4F_CENTRAL] = Region("Spirit Temple MQ 4F Central", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SPIRIT_TEMPLE_MQ_BEFORE_MIRROR_POT_1, logic->CanBreakPots()), + LOCATION(RC_SPIRIT_TEMPLE_MQ_BEFORE_MIRROR_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_MQ_BIG_WALL, []{return true;}), + Entrance(RR_SPIRIT_TEMPLE_MQ_NINE_CHAIRS_ROOM, []{return logic->SmallKeys(RR_SPIRIT_TEMPLE, 7);}), + Entrance(RR_SPIRIT_TEMPLE_MQ_BIG_MIRROR_ROOM, []{return logic->CanUse(RG_ZELDAS_LULLABY);}), + }); + + areaTable[RR_SPIRIT_TEMPLE_MQ_NINE_CHAIRS_ROOM] = Region("Spirit Temple MQ Nine Chairs Room", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + //These skulls rely on the iron knuckle existing without a trick to shoot through the chairs + LOCATION(RC_SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_WEST, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)), + LOCATION(RC_SPIRIT_TEMPLE_MQ_GS_NINE_THRONES_ROOM_NORTH, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)), + }, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_MQ_4F_CENTRAL, []{return true;}), + }); + + areaTable[RR_SPIRIT_TEMPLE_MQ_BIG_MIRROR_ROOM] = Region("Spirit Temple MQ Big Mirror Room", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SPIRIT_TEMPLE_MQ_BIG_MIRROR_POT_1, logic->CanBreakPots()), + LOCATION(RC_SPIRIT_TEMPLE_MQ_BIG_MIRROR_POT_2, logic->CanBreakPots()), + LOCATION(RC_SPIRIT_TEMPLE_MQ_BIG_MIRROR_POT_3, logic->CanBreakPots()), + LOCATION(RC_SPIRIT_TEMPLE_MQ_BIG_MIRROR_POT_4, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_SPIRIT_TEMPLE_MQ_4F_CENTRAL, []{return true;}), + Entrance(RR_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CAVE, []{return Here(RR_SPIRIT_TEMPLE_MQ_BIG_MIRROR_ROOM, []{return logic->CanUse(RG_MEGATON_HAMMER);});}), + }); + + areaTable[RR_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CAVE] = Region("Spirit Temple MQ Big Mirror Cave", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SPIRIT_TEMPLE_MQ_MIRROR_PUZZLE_INVISIBLE_CHEST, ctx->GetTrickOption(RT_LENS_SPIRIT_MQ) || logic->CanUse(RG_LENS_OF_TRUTH)), + }, { + //Exits + //If it's ever relevant to longshot into head from lobby, this needs to be an event access + Entrance(RR_SPIRIT_TEMPLE_MQ_INSIDE_STATUE_HEAD, []{return Here(RR_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CAVE, []{return logic->CanUse(RG_MIRROR_SHIELD);}) && logic->CanUse(RG_HOOKSHOT);}), + Entrance(RR_SPIRIT_TEMPLE_MQ_STATUE_ROOM, []{return Here(RR_SPIRIT_TEMPLE_MQ_BIG_MIRROR_CAVE, []{return logic->CanUse(RG_MIRROR_SHIELD);});}), + }); + + areaTable[RR_SPIRIT_TEMPLE_MQ_INSIDE_STATUE_HEAD] = Region("Spirit Temple MQ Inside Statue Head", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + // Exits + Entrance(RR_SPIRIT_TEMPLE_MQ_LOBBY, []{return true;}), + Entrance(RR_SPIRIT_TEMPLE_BOSS_ENTRYWAY, []{return logic->HasItem(RG_SPIRIT_TEMPLE_BOSS_KEY);}), + }); + +#pragma endregion + + // Boss Room + areaTable[RR_SPIRIT_TEMPLE_BOSS_ENTRYWAY] = Region("Spirit Temple Boss Entryway", "Spirit Temple", {RA_SPIRIT_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + // Exits + Entrance(RR_SPIRIT_TEMPLE_INSIDE_STATUE_HEAD, []{return ctx->GetDungeon(SPIRIT_TEMPLE)->IsVanilla() && false;}), + Entrance(RR_SPIRIT_TEMPLE_MQ_INSIDE_STATUE_HEAD, []{return ctx->GetDungeon(SPIRIT_TEMPLE)->IsMQ() && false;}), + Entrance(RR_SPIRIT_TEMPLE_BOSS_ROOM, []{return true;}), + }); + + areaTable[RR_SPIRIT_TEMPLE_BOSS_ROOM] = Region("Spirit Temple Boss Room", "Spirit Temple", {}, NO_DAY_NIGHT_CYCLE, { + // Events + EventAccess(&logic->SpiritTempleClear, []{return logic->SpiritTempleClear || (logic->HasBossSoul(RG_TWINROVA_SOUL) && (logic->CanUse(RG_MIRROR_SHIELD) && (logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD))));}), + }, { + // Locations + LOCATION(RC_SPIRIT_TEMPLE_TWINROVA_HEART, logic->SpiritTempleClear), + LOCATION(RC_TWINROVA, logic->SpiritTempleClear), + }, { + // Exits + Entrance(RR_SPIRIT_TEMPLE_BOSS_ENTRYWAY, []{return false;}), + Entrance(RR_DESERT_COLOSSUS, []{return logic->SpiritTempleClear;}, false), + }); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/water_temple.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/water_temple.cpp new file mode 100644 index 000000000..ab206f6ef --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/water_temple.cpp @@ -0,0 +1,738 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" +#include "soh/Enhancements/randomizer/dungeon.h" + +using namespace Rando; + +void RegionTable_Init_WaterTemple() { + // Vanilla/MQ Decider + areaTable[RR_WATER_TEMPLE_ENTRYWAY] = Region("Water Temple Entryway", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_WATER_TEMPLE_LOBBY, []{return logic->HasItem(RG_BRONZE_SCALE) && ctx->GetDungeon(WATER_TEMPLE)->IsVanilla();}), + Entrance(RR_WATER_TEMPLE_MQ_3F_CENTRAL, []{return logic->HasItem(RG_BRONZE_SCALE) && ctx->GetDungeon(WATER_TEMPLE)->IsMQ();}), + Entrance(RR_LAKE_HYLIA, []{return true;}), + }); + +#pragma region Vanilla + + //Water Temple logic currently assumes that the locked door leading to the upper water raising location is unlocked from the start + areaTable[RR_WATER_TEMPLE_LOBBY] = Region("Water Temple Lobby", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_WATER_TEMPLE_MAIN_LEVEL_2_POT_1, logic->CanBreakPots() && (logic->CanWaterTempleLowFromHigh || logic->CanWaterTempleMiddle || (logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT)))), + LOCATION(RC_WATER_TEMPLE_MAIN_LEVEL_2_POT_2, logic->CanBreakPots() && (logic->CanWaterTempleLowFromHigh || logic->CanWaterTempleMiddle || (logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT)))), + }, { + //Exits + Entrance(RR_WATER_TEMPLE_ENTRYWAY, []{return true;}), + Entrance(RR_WATER_TEMPLE_EAST_LOWER, []{return logic->CanWaterTempleLowFromHigh || ((ctx->GetTrickOption(RT_FEWER_TUNIC_REQUIREMENTS) || logic->CanUse(RG_ZORA_TUNIC)) && (logic->CanUse(RG_IRON_BOOTS) || (logic->CanUse(RG_LONGSHOT) && ctx->GetTrickOption(RT_WATER_LONGSHOT_TORCH))));}), + Entrance(RR_WATER_TEMPLE_NORTH_LOWER, []{return logic->CanWaterTempleLowFromHigh || ((ctx->GetTrickOption(RT_FEWER_TUNIC_REQUIREMENTS) || logic->CanUse(RG_ZORA_TUNIC)) && logic->CanUse(RG_IRON_BOOTS));}), + Entrance(RR_WATER_TEMPLE_SOUTH_LOWER, []{return logic->CanWaterTempleLowFromHigh && logic->HasExplosives() && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS)) && (ctx->GetTrickOption(RT_FEWER_TUNIC_REQUIREMENTS) || logic->CanUse(RG_ZORA_TUNIC));}), + Entrance(RR_WATER_TEMPLE_WEST_LOWER, []{return logic->CanWaterTempleLowFromHigh && logic->HasItem(RG_GORONS_BRACELET) && (logic->IsChild || logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS)) && (ctx->GetTrickOption(RT_FEWER_TUNIC_REQUIREMENTS) || logic->CanUse(RG_ZORA_TUNIC));}), + Entrance(RR_WATER_TEMPLE_CENTRAL_PILLAR_LOWER, []{return logic->CanWaterTempleLowFromHigh && logic->SmallKeys(RR_WATER_TEMPLE, 5);}), + Entrance(RR_WATER_TEMPLE_CENTRAL_PILLAR_UPPER, []{return (logic->CanWaterTempleLowFromHigh || logic->CanWaterTempleMiddle) && (logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW));}), + Entrance(RR_WATER_TEMPLE_EAST_MIDDLE, []{return (logic->CanWaterTempleLowFromHigh || logic->CanWaterTempleMiddle || (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16)) && logic->CanUse(RG_HOOKSHOT);}), + Entrance(RR_WATER_TEMPLE_WEST_MIDDLE, []{return logic->CanWaterTempleMiddle;}), + Entrance(RR_WATER_TEMPLE_HIGH_WATER, []{return logic->IsAdult && (logic->CanUse(RG_HOVER_BOOTS) || (ctx->GetTrickOption(RT_DAMAGE_BOOST) && logic->CanUse(RG_BOMB_BAG) && logic->TakeDamage()));}), + Entrance(RR_WATER_TEMPLE_BLOCK_CORRIDOR, []{return (logic->CanWaterTempleLowFromHigh || logic->CanWaterTempleMiddle) && (logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_FAIRY_BOW)) && (logic->CanUse(RG_LONGSHOT) || logic->CanUse(RG_HOVER_BOOTS) || (ctx->GetTrickOption(RT_WATER_CENTRAL_BOW) && (logic->IsAdult || logic->CanWaterTempleMiddle)));}), + Entrance(RR_WATER_TEMPLE_FALLING_PLATFORM_ROOM, []{return logic->CanWaterTempleHigh && logic->SmallKeys(RR_WATER_TEMPLE, 4);}), + Entrance(RR_WATER_TEMPLE_PRE_BOSS_ROOM, []{return (logic->CanWaterTempleHigh && logic->CanUse(RG_LONGSHOT)) || (ctx->GetTrickOption(RT_HOVER_BOOST_SIMPLE) && ctx->GetTrickOption(RT_DAMAGE_BOOST_SIMPLE) && logic->HasExplosives() && logic->CanUse(RG_HOVER_BOOTS));}), + }); + + areaTable[RR_WATER_TEMPLE_EAST_LOWER] = Region("Water Temple East Lower", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->CanWaterTempleLowFromHigh, []{return logic->CanWaterTempleLowFromHigh || logic->CanUse(RG_ZELDAS_LULLABY);}), + }, { + //Locations + LOCATION(RC_WATER_TEMPLE_TORCH_POT_1, logic->CanBreakPots() && (logic->CanWaterTempleLowFromHigh || (logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_IRON_BOOTS)))), + LOCATION(RC_WATER_TEMPLE_TORCH_POT_2, logic->CanBreakPots() && (logic->CanWaterTempleLowFromHigh || (logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_IRON_BOOTS)))), + }, { + //Exits + Entrance(RR_WATER_TEMPLE_LOBBY, []{return logic->CanWaterTempleLowFromHigh || ((ctx->GetTrickOption(RT_FEWER_TUNIC_REQUIREMENTS) || logic->CanUse(RG_ZORA_TUNIC)) && logic->CanUse(RG_IRON_BOOTS));}), + Entrance(RR_WATER_TEMPLE_MAP_ROOM, []{return logic->CanWaterTempleHigh;}), + Entrance(RR_WATER_TEMPLE_CRACKED_WALL, []{return logic->CanWaterTempleMiddle || (logic->CanWaterTempleHigh && logic->CanWaterTempleLowFromHigh && ((logic->CanUse(RG_HOVER_BOOTS) && ctx->GetTrickOption(RT_WATER_CRACKED_WALL_HOVERS)) || ctx->GetTrickOption(RT_WATER_CRACKED_WALL)));}), + Entrance(RR_WATER_TEMPLE_TORCH_ROOM, []{return logic->CanWaterTempleLowFromHigh && (logic->HasFireSourceWithTorch() || logic->CanUse(RG_FAIRY_BOW));}), + }); + + areaTable[RR_WATER_TEMPLE_MAP_ROOM] = Region("Water Temple Map Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_WATER_TEMPLE_MAP_CHEST, (logic->CanUse(RG_MAGIC_SINGLE) && logic->CanUse(RG_KOKIRI_SWORD)) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_HOOKSHOT)), + }, { + //Exits + Entrance(RR_WATER_TEMPLE_EAST_LOWER, []{return (logic->CanUse(RG_MAGIC_SINGLE) && logic->CanUse(RG_KOKIRI_SWORD)) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_HOOKSHOT);}), + }); + + areaTable[RR_WATER_TEMPLE_CRACKED_WALL] = Region("Water Temple Cracked Wall", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_WATER_TEMPLE_CRACKED_WALL_CHEST, logic->HasExplosives()), + }, { + //Exits + Entrance(RR_WATER_TEMPLE_EAST_LOWER, []{return true;}), + }); + + areaTable[RR_WATER_TEMPLE_TORCH_ROOM] = Region("Water Temple Torch Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_WATER_TEMPLE_TORCHES_CHEST, (logic->CanUse(RG_MAGIC_SINGLE) && logic->CanUse(RG_KOKIRI_SWORD)) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_HOOKSHOT)), + }, { + //Exits + Entrance(RR_WATER_TEMPLE_EAST_LOWER, []{return (logic->CanUse(RG_MAGIC_SINGLE) && logic->CanUse(RG_KOKIRI_SWORD)) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD) || logic->CanUse(RG_HOOKSHOT);}), + }); + + areaTable[RR_WATER_TEMPLE_NORTH_LOWER] = Region("Water Temple North Lower", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_WATER_TEMPLE_LOBBY, []{return true;}), + Entrance(RR_WATER_TEMPLE_BOULDERS_LOWER, []{return (logic->CanUse(RG_LONGSHOT) || (ctx->GetTrickOption(RT_WATER_BK_REGION) && logic->CanUse(RG_HOVER_BOOTS))) && logic->SmallKeys(RR_WATER_TEMPLE, 4);}), + }); + + areaTable[RR_WATER_TEMPLE_BOULDERS_LOWER] = Region("Water Temple Boulders Lower", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_WATER_TEMPLE_GS_NEAR_BOSS_KEY_CHEST, logic->CanUse(RG_LONGSHOT) || Here(RR_WATER_TEMPLE_BOULDERS_UPPER, []{return (logic->IsAdult && logic->HookshotOrBoomerang()) || (logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT));})), + }, { + //Exits + Entrance(RR_WATER_TEMPLE_NORTH_LOWER, []{return logic->SmallKeys(RR_WATER_TEMPLE, 4);}), + Entrance(RR_WATER_TEMPLE_BLOCK_ROOM, []{return true;}), + Entrance(RR_WATER_TEMPLE_BOULDERS_UPPER, []{return (logic->IsAdult && (logic->CanUse(RG_HOVER_BOOTS) || ctx->GetTrickOption(RT_WATER_NORTH_BASEMENT_LEDGE_JUMP))) || (logic->CanUse(RG_HOVER_BOOTS) && logic->CanUse(RG_IRON_BOOTS));}), + }); + + areaTable[RR_WATER_TEMPLE_BLOCK_ROOM] = Region("Water Temple Block Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_WATER_TEMPLE_BASEMENT_BLOCK_PUZZLE_POT_1, logic->CanBreakPots()), + LOCATION(RC_WATER_TEMPLE_BASEMENT_BLOCK_PUZZLE_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_WATER_TEMPLE_BOULDERS_LOWER, []{return (logic->HasItem(RG_GORONS_BRACELET) && logic->HasExplosives()) || logic->CanUse(RG_HOOKSHOT);}), + Entrance(RR_WATER_TEMPLE_JETS_ROOM, []{return (logic->HasItem(RG_GORONS_BRACELET) && logic->HasExplosives()) || (logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_HOVER_BOOTS));}), + }); + + areaTable[RR_WATER_TEMPLE_JETS_ROOM] = Region("Water Temple Jets Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_WATER_TEMPLE_BLOCK_ROOM, []{return logic->CanUse(RG_HOOKSHOT);}), + Entrance(RR_WATER_TEMPLE_BOULDERS_UPPER, []{return true;}), + }); + + areaTable[RR_WATER_TEMPLE_BOULDERS_UPPER] = Region("Water Temple Boulders Upper", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_WATER_TEMPLE_BOULDERS_LOWER, []{return true;}), + Entrance(RR_WATER_TEMPLE_JETS_ROOM, []{return logic->IsAdult;}), + Entrance(RR_WATER_TEMPLE_BOSS_KEY_ROOM, []{return (logic->CanUse(RG_IRON_BOOTS) || (logic->IsAdult && ctx->GetTrickOption(RT_WATER_BK_JUMP_DIVE))) && logic->SmallKeys(RR_WATER_TEMPLE, 5);}), + }); + + areaTable[RR_WATER_TEMPLE_BOSS_KEY_ROOM] = Region("Water Temple Boss Key Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->FairyPot, []{return true;}), + }, { + //Locations + LOCATION(RC_WATER_TEMPLE_BOSS_KEY_CHEST, true), + LOCATION(RC_WATER_TEMPLE_BOSS_KEY_POT_1, logic->CanBreakPots()), + LOCATION(RC_WATER_TEMPLE_BOSS_KEY_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_WATER_TEMPLE_BOULDERS_UPPER, []{return (logic->CanUse(RG_IRON_BOOTS) || (logic->IsAdult && ctx->GetTrickOption(RT_WATER_BK_JUMP_DIVE)) || logic->IsChild || logic->HasItem(RG_SILVER_SCALE)) && logic->SmallKeys(RR_WATER_TEMPLE, 5);}), + }); + + areaTable[RR_WATER_TEMPLE_SOUTH_LOWER] = Region("Water Temple South Lower", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_WATER_TEMPLE_GS_BEHIND_GATE, logic->CanJumpslash() && (logic->CanUse(RG_HOOKSHOT) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)))), + LOCATION(RC_WATER_TEMPLE_BEHIND_GATE_POT_1, logic->CanJumpslash() && (logic->CanUse(RG_HOOKSHOT) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)))), + LOCATION(RC_WATER_TEMPLE_BEHIND_GATE_POT_2, logic->CanJumpslash() && (logic->CanUse(RG_HOOKSHOT) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)))), + LOCATION(RC_WATER_TEMPLE_BEHIND_GATE_POT_3, logic->CanJumpslash() && (logic->CanUse(RG_HOOKSHOT) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)))), + LOCATION(RC_WATER_TEMPLE_BEHIND_GATE_POT_4, logic->CanJumpslash() && (logic->CanUse(RG_HOOKSHOT) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)))), + }, { + //Exits + Entrance(RR_WATER_TEMPLE_LOBBY, []{return logic->CanUse(RG_IRON_BOOTS);}), + }); + + areaTable[RR_WATER_TEMPLE_WEST_LOWER] = Region("Water Temple West Lower", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_WATER_TEMPLE_LOBBY, []{return logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_IRON_BOOTS) && logic->HasItem(RG_GORONS_BRACELET);}), + Entrance(RR_WATER_TEMPLE_DRAGON_ROOM, []{return logic->CanJumpslashExceptHammer() || logic->CanUseProjectile();}), + }); + + areaTable[RR_WATER_TEMPLE_DRAGON_ROOM] = Region("Water Temple Dragon Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_WATER_TEMPLE_DRAGON_CHEST, (logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_IRON_BOOTS)) || (((logic->IsAdult && ctx->GetTrickOption(RT_WATER_ADULT_DRAGON) && (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_BOMBCHU_5))) || (logic->IsChild && ctx->GetTrickOption(RT_WATER_CHILD_DRAGON) && (logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_BOOMERANG) || logic->CanUse(RG_BOMBCHU_5)))) && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS))) || + Here(RR_WATER_TEMPLE_RIVER, []{return logic->IsAdult && logic->CanUse(RG_FAIRY_BOW) && ((ctx->GetTrickOption(RT_WATER_ADULT_DRAGON) && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS))) || ctx->GetTrickOption(RT_WATER_DRAGON_JUMP_DIVE));})), + }, { + //Exits + Entrance(RR_WATER_TEMPLE_WEST_LOWER, []{return true;}), + }); + + areaTable[RR_WATER_TEMPLE_CENTRAL_PILLAR_LOWER] = Region("Water Temple Central Pillar Lower", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_WATER_TEMPLE_LOBBY, []{return logic->SmallKeys(RR_WATER_TEMPLE, 5);}), + Entrance(RR_WATER_TEMPLE_CENTRAL_PILLAR_UPPER, []{return logic->CanUse(RG_HOOKSHOT);}), + Entrance(RR_WATER_TEMPLE_CENTRAL_PILLAR_BASEMENT, []{return logic->CanWaterTempleMiddle && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 40;}), + }); + + areaTable[RR_WATER_TEMPLE_CENTRAL_PILLAR_UPPER] = Region("Water Temple Central Pillar Upper", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->CanWaterTempleMiddle, []{return logic->CanWaterTempleMiddle || logic->CanUse(RG_ZELDAS_LULLABY);}), + }, { + //Locations + LOCATION(RC_WATER_TEMPLE_GS_CENTRAL_PILLAR, logic->CanUse(RG_LONGSHOT) || (((ctx->GetTrickOption(RT_WATER_FW_CENTRAL_GS) && logic->CanUse(RG_FARORES_WIND) && (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_DINS_FIRE) || logic->SmallKeys(RR_WATER_TEMPLE, 5))) || (ctx->GetTrickOption(RT_WATER_IRONS_CENTRAL_GS) && logic->CanUse(RG_IRON_BOOTS) && ((logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_FAIRY_BOW)) || (logic->CanUse(RG_DINS_FIRE))))) && logic->CanWaterTempleHigh && logic->HookshotOrBoomerang())), + }, { + //Exits + Entrance(RR_WATER_TEMPLE_LOBBY, []{return true;}), + Entrance(RR_WATER_TEMPLE_CENTRAL_PILLAR_LOWER, []{return true;}), + }); + + areaTable[RR_WATER_TEMPLE_CENTRAL_PILLAR_BASEMENT] = Region("Water Temple Central Pillar Basement", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_WATER_TEMPLE_CENTRAL_PILLAR_CHEST, logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 40), + }, { + //Exits + Entrance(RR_WATER_TEMPLE_CENTRAL_PILLAR_LOWER, []{return logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16;}), + }); + + areaTable[RR_WATER_TEMPLE_EAST_MIDDLE] = Region("Water Temple East Middle", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_WATER_TEMPLE_COMPASS_CHEST, logic->CanUseProjectile()), + LOCATION(RC_WATER_TEMPLE_NEAR_COMPASS_POT_1, logic->CanBreakPots()), + LOCATION(RC_WATER_TEMPLE_NEAR_COMPASS_POT_2, logic->CanBreakPots()), + LOCATION(RC_WATER_TEMPLE_NEAR_COMPASS_POT_3, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_WATER_TEMPLE_LOBBY, []{return logic->CanUse(RG_IRON_BOOTS);}), + }); + + areaTable[RR_WATER_TEMPLE_WEST_MIDDLE] = Region("Water Temple West Middle", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_WATER_TEMPLE_LOBBY, []{return true;}), + Entrance(RR_WATER_TEMPLE_HIGH_WATER, []{return logic->CanUseProjectile();}), + }); + + areaTable[RR_WATER_TEMPLE_HIGH_WATER] = Region("Water Temple High Water", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->CanWaterTempleHigh, []{return logic->CanWaterTempleHigh || logic->CanUse(RG_ZELDAS_LULLABY);}), + }, {}, { + //Exits + Entrance(RR_WATER_TEMPLE_LOBBY, []{return true;}), + }); + + areaTable[RR_WATER_TEMPLE_BLOCK_CORRIDOR] = Region("Water Temple Block Corridor", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_WATER_TEMPLE_CENTRAL_BOW_TARGET_CHEST, logic->HasItem(RG_GORONS_BRACELET) && (logic->CanWaterTempleLowFromHigh || logic->CanWaterTempleMiddle)), + LOCATION(RC_WATER_TEMPLE_CENTRAL_BOW_POT_1, logic->CanBreakPots() && logic->HasItem(RG_GORONS_BRACELET) && (logic->CanWaterTempleLowFromHigh || logic->CanWaterTempleMiddle)), + LOCATION(RC_WATER_TEMPLE_CENTRAL_BOW_POT_2, logic->CanBreakPots() && logic->HasItem(RG_GORONS_BRACELET) && (logic->CanWaterTempleLowFromHigh || logic->CanWaterTempleMiddle)), + }, { + //Exits + Entrance(RR_WATER_TEMPLE_LOBBY, []{return logic->CanUse(RG_HOOKSHOT);}), + }); + + areaTable[RR_WATER_TEMPLE_FALLING_PLATFORM_ROOM] = Region("Water Temple Falling Platform Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_WATER_TEMPLE_GS_FALLING_PLATFORM_ROOM, logic->CanUse(RG_LONGSHOT) || (ctx->GetTrickOption(RT_WATER_RANG_FALLING_PLATFORM_GS) && logic->IsChild && logic->CanUse(RG_BOOMERANG)) || (ctx->GetTrickOption(RT_WATER_HOOKSHOT_FALLING_PLATFORM_GS) && logic->IsAdult && logic->CanUse(RG_HOOKSHOT))), + }, { + //Exits + Entrance(RR_WATER_TEMPLE_LOBBY, []{return logic->CanUse(RG_HOOKSHOT) && logic->SmallKeys(RR_WATER_TEMPLE, 4);}), + Entrance(RR_WATER_TEMPLE_DRAGON_PILLARS_ROOM, []{return logic->CanUse(RG_HOOKSHOT) && logic->SmallKeys(RR_WATER_TEMPLE, 5);}), + }); + + areaTable[RR_WATER_TEMPLE_DRAGON_PILLARS_ROOM] = Region("Water Temple Dragon Pillars Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_WATER_TEMPLE_LIKE_LIKE_POT_1, logic->CanUse(RG_HOOKSHOT)), + LOCATION(RC_WATER_TEMPLE_LIKE_LIKE_POT_2, logic->CanUse(RG_HOOKSHOT)), + }, { + //Exits + Entrance(RR_WATER_TEMPLE_FALLING_PLATFORM_ROOM, []{return logic->CanUseProjectile();}), + Entrance(RR_WATER_TEMPLE_DARK_LINK_ROOM, []{return logic->CanUse(RG_HOOKSHOT);}), + }); + + areaTable[RR_WATER_TEMPLE_DARK_LINK_ROOM] = Region("Water Temple Dark Link Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_WATER_TEMPLE_DRAGON_PILLARS_ROOM, []{return logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD);}), + Entrance(RR_WATER_TEMPLE_LONGSHOT_ROOM, []{return logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD);}), + }); + + areaTable[RR_WATER_TEMPLE_LONGSHOT_ROOM] = Region("Water Temple Longshot Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_WATER_TEMPLE_LONGSHOT_CHEST, true), + }, { + //Exits + Entrance(RR_WATER_TEMPLE_DARK_LINK_ROOM, []{return true;}), + Entrance(RR_WATER_TEMPLE_RIVER, []{return logic->IsChild || logic->CanUse(RG_SONG_OF_TIME);}), + }); + + areaTable[RR_WATER_TEMPLE_RIVER] = Region("Water Temple River", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_WATER_TEMPLE_RIVER_CHEST, (logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_FAIRY_BOW)) && (logic->IsAdult || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT))), + LOCATION(RC_WATER_TEMPLE_GS_RIVER, (logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT)) || (ctx->GetTrickOption(RT_WATER_RIVER_GS) && logic->CanUse(RG_LONGSHOT))), + LOCATION(RC_WATER_TEMPLE_RIVER_POT_1, logic->CanBreakPots()), + LOCATION(RC_WATER_TEMPLE_RIVER_POT_2, logic->CanBreakPots()), + LOCATION(RC_WATER_TEMPLE_RIVER_HEART_1, (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16) || logic->HasItem(RG_BRONZE_SCALE)), + LOCATION(RC_WATER_TEMPLE_RIVER_HEART_2, (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16) || logic->HasItem(RG_BRONZE_SCALE)), + LOCATION(RC_WATER_TEMPLE_RIVER_HEART_3, (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16) || logic->HasItem(RG_BRONZE_SCALE)), + LOCATION(RC_WATER_TEMPLE_RIVER_HEART_4, (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 24) || logic->HasItem(RG_BRONZE_SCALE)), + }, { + //Exits + Entrance(RR_WATER_TEMPLE_DRAGON_ROOM, []{return (logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_FAIRY_BOW)) && (logic->IsAdult || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT));}), + }); + + areaTable[RR_WATER_TEMPLE_PRE_BOSS_ROOM] = Region("Water Temple Pre Boss Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->FairyPot, []{return true;}), + }, { + // Locations + LOCATION(RC_WATER_TEMPLE_MAIN_LEVEL_1_POT_1, logic->CanBreakPots()), + LOCATION(RC_WATER_TEMPLE_MAIN_LEVEL_1_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_WATER_TEMPLE_LOBBY, []{return true;}), + Entrance(RR_WATER_TEMPLE_BOSS_ENTRYWAY, []{return logic->HasItem(RG_WATER_TEMPLE_BOSS_KEY);}), + }); + +#pragma endregion + +#pragma region MQ + + areaTable[RR_WATER_TEMPLE_MQ_3F_SOUTH_LEDGE] = Region("Water Temple MQ 3F South Ledge", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_WATER_TEMPLE_ENTRYWAY, []{return logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS);}), + Entrance(RR_WATER_TEMPLE_MQ_MAIN, []{return true;}), + //If we are not on WL_HIGH, we reach RR_WATER_TEMPLE_MQ_3F_MAIN with hookshot via 2F, otherwise we can reach the platform + Entrance(RR_WATER_TEMPLE_MQ_3F_CENTRAL, []{return logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS);}), + Entrance(RR_WATER_TEMPLE_MQ_2F_CENTRAL, []{return logic->MQWaterLevel(WL_LOW_OR_MID);}), + }); + + //This region covers simply existing in the area around the central pillar without being on a specific platform, either swimming or walking on the lakebed + //Entry should only include being in the correct area, taking any possible fall damage, and floating up to the surface of WL_HIGH if coming from below + //This area then leads to others based on level and worst-case water timers for follow-up exits from the water's surface + //remember that any solution that works for any level doesn't need to be given a level, even if that solution is overkill for a lower level + areaTable[RR_WATER_TEMPLE_MQ_MAIN] = Region("Water Temple MQ Main", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_WATER_TEMPLE_MQ_3F_SOUTH_LEDGE, []{return logic->HasItem(RG_BRONZE_SCALE) && logic->MQWaterLevel(WL_HIGH);}), + //Jumping across is possible but a trick due to the janky ledge + Entrance(RR_WATER_TEMPLE_MQ_EAST_TOWER, []{return (logic->WaterTimer() >= 24 && logic->CanUse(RG_IRON_BOOTS)) || (logic->MQWaterLevel(WL_MID) && logic->HasItem(RG_GOLDEN_SCALE) && logic->WaterTimer() >= 16) || logic->MQWaterLevel(WL_LOW);}), + Entrance(RR_WATER_TEMPLE_MQ_3F_CENTRAL, []{return logic->MQWaterLevel(WL_HIGH) && logic->HasItem(RG_BRONZE_SCALE);}), + //First water timer uses the hook to go from the top of center to storage room/central pillar as coming from the bottom + //Second water timer is simply diving down and entering the door as fast as possible from the surface + Entrance(RR_WATER_TEMPLE_MQ_2F_CENTRAL, []{return ((logic->MQWaterLevel(WL_LOW) || (logic->CanUse(RG_IRON_BOOTS) && (logic->MQWaterLevel(WL_MID) || logic->WaterTimer() >= 16))) && logic->CanUse(RG_LONGSHOT)) || ((logic->MQWaterLevel(WL_MID) || (logic->MQWaterLevel(WL_HIGH_OR_MID) && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8)) && logic->HasItem(RG_BRONZE_SCALE));}), + Entrance(RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_1F, []{return logic->MQWaterLevel(WL_LOW);}), + //A special entry as we can't set it to high after entering at a lower height + Entrance(RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_HIGH, []{return logic->MQWaterLevel(WL_HIGH) && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && (logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_LONGSHOT));}), + Entrance(RR_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY, []{return (logic->MQWaterLevel(WL_MID) || (logic->MQWaterLevel(WL_HIGH_OR_MID) && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16)) && logic->HasItem(RG_BRONZE_SCALE);}), + Entrance(RR_WATER_TEMPLE_MQ_B1_GATE_SWITCH, []{return logic->MQWaterB1Switch && (logic->MQWaterLevel(WL_LOW) || ((logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 24) && logic->HasItem(RG_BRONZE_SCALE)));}), + Entrance(RR_WATER_TEMPLE_MQ_TRIANGLE_TORCH_ROOM, []{return logic->MQWaterB1Switch && ((logic->MQWaterLevel(WL_LOW) && logic->HasItem(RG_SILVER_SCALE)) || (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && (logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_LONGSHOT))));}), + //Adult needs to jump in instead of dive for swim access, but you just hold forward. RT_WATER_BK_REGION Isn't relevant unless the Dark Link loop can be done without longshot with other tricks + Entrance(RR_WATER_TEMPLE_MQ_CRATES_WHIRLPOOLS_ROOM, []{return logic->MQWaterB1Switch && ((logic->MQWaterLevel(WL_LOW) && logic->HasItem(RG_BRONZE_SCALE)) || (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && logic->CanUse(RG_HOOKSHOT))) && (logic->CanUse(RG_LONGSHOT) || (ctx->GetTrickOption(RT_WATER_BK_REGION) && logic->CanUse(RG_HOVER_BOOTS)));}), + }); + + //This region specifically covers the topmost platform around central pillar + areaTable[RR_WATER_TEMPLE_MQ_3F_CENTRAL] = Region("Water Temple MQ 3F Central", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_WATER_TEMPLE_MQ_MAIN, []{return true;}), + Entrance(RR_WATER_TEMPLE_MQ_3F_SOUTH_LEDGE, []{return logic->CanUse(RG_LONGSHOT) || logic->CanUse(RG_HOVER_BOOTS);}), + Entrance(RR_WATER_TEMPLE_MQ_2F_CENTRAL, []{return (logic->MQWaterLevel(WL_LOW_OR_MID) || (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16)) && logic->CanUse(RG_HOOKSHOT);}), + Entrance(RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_HIGH, []{return logic->MQWaterLevel(WL_HIGH) && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && logic->CanUse(RG_HOOKSHOT);}), + Entrance(RR_WATER_TEMPLE_MQ_3F_NORTH_LEDGE, []{return (logic->MQWaterLevel(WL_HIGH) && logic->CanUse(RG_LONGSHOT)) || (ctx->GetTrickOption(RT_HOVER_BOOST_SIMPLE) && ctx->GetTrickOption(RT_DAMAGE_BOOST_SIMPLE) && logic->HasExplosives() && logic->CanUse(RG_HOVER_BOOTS));}), + //Jumping across is possible but a trick due to the janky ledge + Entrance(RR_WATER_TEMPLE_MQ_HIGH_EMBLEM, []{return logic->CanUse(RG_HOOKSHOT) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS));}), + //room access is (logic->IsAdult || (logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT))) + Entrance(RR_WATER_TEMPLE_MQ_WATERFALL, []{return logic->SmallKeys(RR_WATER_TEMPLE, 1) && logic->MQWaterLevel(WL_HIGH) && logic->CanUse(RG_LONGSHOT);}), + //this swimless jump with irons may be a trick as you have to put irons on quite late. + Entrance(RR_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY, []{return (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16) || logic->MQWaterLevel(WL_LOW_OR_MID);}), + }); + + //This region specifically covers walking on the lower platform around central pillar. This is underwater when WL_HIGH + //RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_HIGH should be accessed directly to use the central pillar door while at WL_HIGH + areaTable[RR_WATER_TEMPLE_MQ_2F_CENTRAL] = Region("Water Temple MQ 2F Central", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_WATER_TEMPLE_MQ_MAIN, []{return true;}), + Entrance(RR_WATER_TEMPLE_MQ_3F_CENTRAL, []{return logic->CanUse(RG_HOOKSHOT);}), + Entrance(RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_2F, []{return logic->MQWaterLevel(WL_LOW_OR_MID);}), + Entrance(RR_WATER_TEMPLE_MQ_STORAGE_ROOM, []{return logic->CanUse(RG_HOOKSHOT);}), + Entrance(RR_WATER_TEMPLE_MQ_BEHIND_BLUE_SWITCH_2F, []{return logic->MQWaterLevel(WL_LOW_OR_MID) && (logic->IsAdult || logic->CanUse(RG_HOVER_BOOTS)) && logic->CanUse(RG_HOOKSHOT);}), + Entrance(RR_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY, []{return logic->MQWaterLevel(WL_LOW_OR_MID) && logic->CanUse(RG_HOVER_BOOTS);}), + }); + + areaTable[RR_WATER_TEMPLE_MQ_HIGH_EMBLEM] = Region("Water Temple MQ High Emblem", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->ReachedWaterHighEmblem, []{return true;}), + EventAccess(&logic->CanWaterTempleHigh, []{return logic->CanUse(RG_ZELDAS_LULLABY);}), + }, {}, { + //Exits + Entrance(RR_WATER_TEMPLE_MQ_3F_CENTRAL, []{return true;}), + Entrance(RR_WATER_TEMPLE_MQ_MAIN, []{return true;}), + }); + + areaTable[RR_WATER_TEMPLE_MQ_3F_NORTH_LEDGE] = Region("Water Temple MQ 3F North Ledge", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + //what we need if WL_LOW, we can't guarantee repeated access otherwise. + Entrance(RR_WATER_TEMPLE_MQ_MAIN, []{return logic->HasItem(RG_BRONZE_SCALE) || logic->TakeDamage();}), + Entrance(RR_WATER_TEMPLE_MQ_3F_CENTRAL, []{return logic->CanUse(RG_LONGSHOT);}), + Entrance(RR_WATER_TEMPLE_MQ_BOSS_DOOR, []{return logic->CanUse(RG_LONGSHOT) || logic->CanUse(RG_ICE_ARROWS) || logic->CanUse(RG_NAYRUS_LOVE);}), + }); + + areaTable[RR_WATER_TEMPLE_MQ_BOSS_DOOR] = Region("Water Temple MQ Main", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_WATER_TEMPLE_MQ_3F_NORTH_LEDGE, []{return logic->CanUse(RG_ICE_ARROWS) || logic->TakeDamage();}), + Entrance(RR_WATER_TEMPLE_BOSS_ENTRYWAY, []{return logic->HasItem(RG_WATER_TEMPLE_BOSS_KEY);}), + }); + + areaTable[RR_WATER_TEMPLE_MQ_EAST_TOWER] = Region("Water Temple MQ East Tower", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + //if we can't reach these, we can't move the water at all, so no need to specify level or account for WL_LOW access here + //review is some way to play ocarina underwater exists + EventAccess(&logic->CouldWaterTempleLow, []{return true;}), + EventAccess(&logic->CanWaterTempleLowFromHigh, []{return logic->CanUse(RG_ZELDAS_LULLABY);}), + //Reserved for glitches/tricks that could do this + //EventAccess(&logic->CanWaterTempleLowFromMid, []{return false;}), + }, { + //Locations + LOCATION(RC_WATER_TEMPLE_MQ_MAP_CHEST, logic->MQWaterLevel(WL_HIGH) && logic->HasFireSource() && logic->CanUse(RG_HOOKSHOT)), + //easy to get at WL_HIGH with the hook-the-underwater-chest glitch + LOCATION(RC_WATER_TEMPLE_MQ_LONGSHOT_CHEST, logic->MQWaterLevel(WL_MID) && logic->CanUse(RG_HOOKSHOT)), + LOCATION(RC_WATER_TEMPLE_MQ_LOWER_TORCHES_POT_1, (logic->MQWaterLevel(WL_LOW) && logic->CanBreakPots()) || (logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT) && logic->WaterTimer() >= 16)), + LOCATION(RC_WATER_TEMPLE_MQ_LOWER_TORCHES_POT_2, (logic->MQWaterLevel(WL_LOW) && logic->CanBreakPots()) || (logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT) && logic->WaterTimer() >= 16)), + }, { + Entrance(RR_WATER_TEMPLE_MQ_EAST_TOWER_1F_ROOM, []{return logic->MQWaterLevel(WL_LOW) && (logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_DINS_FIRE) || logic->CanUse(RG_STICKS));}), + }); + + //Raising the targets by clearing this room achieves nothing logically because it requires WL_LOW to do and hookshot to use, which implies access to WL_MID and WL_HIGH already + areaTable[RR_WATER_TEMPLE_MQ_EAST_TOWER_1F_ROOM] = Region("Water Temple MQ East Tower 1F Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_WATER_TEMPLE_MQ_COMPASS_CHEST, logic->CanKillEnemy(RE_LIZALFOS) && logic->CanKillEnemy(RE_SPIKE)), + }, { + Entrance(RR_WATER_TEMPLE_MQ_EAST_TOWER, []{return true;}), + }); + + //This area assumes we entered through the lower door, so water is low and cannot be changed without leaving. + areaTable[RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_1F] = Region("Water Temple MQ Central Pillar 1F", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + //This is harder than the other possibilities as you have to move between shots on top of the extra range, but there's basically no universe this should matter. + EventAccess(&logic->MQWaterB1Switch, []{return ctx->GetTrickOption(RT_WATER_MQ_CENTRAL_PILLAR) && logic->CanUse(RG_FIRE_ARROWS);}), + }, {}, { + //Exits + Entrance(RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_HIGH, []{return logic->MQWaterLevel(WL_HIGH) && ctx->GetTrickOption(RT_WATER_FW_CENTRAL_GS) && logic->CanUse(RG_FARORES_WIND) && logic->HasItem(RG_BRONZE_SCALE);}), + //I don't know if this FW trick can ever matter but maybe it's needed to get child to CENTRAL_2F or something + Entrance(RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_2F, []{return logic->CanUse(RG_HOOKSHOT) || (logic->MQWaterLevel(WL_MID) && ctx->GetTrickOption(RT_WATER_FW_CENTRAL_GS) && logic->CanUse(RG_FARORES_WIND) && logic->HasItem(RG_BRONZE_SCALE));}), + //if the gate is open, you sink straight in, so you can't climb up this way in logic without swimming + Entrance(RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_B1, []{return logic->MQWaterOpenedPillarB1 && logic->MQWaterLevel(WL_HIGH_OR_MID) && ctx->GetTrickOption(RT_WATER_FW_CENTRAL_GS) && logic->CanUse(RG_FARORES_WIND) && logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_ZORA_TUNIC);}), + }); + + //If we enter here in WL_HIGH, go to RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_HIGH instead, Assumes WL_MID_OR_LOW + areaTable[RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_2F] = Region("Water Temple MQ Central Pillar 2F", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->CouldWaterTempleMiddle, []{return true;}), + EventAccess(&logic->CanWaterTempleMiddle, []{return logic->CanUse(RG_ZELDAS_LULLABY);}), + //It's possible to do this even on low water, but more awkward. I'm not sure if it's even possible for it to be relevant though. + EventAccess(&logic->MQWaterOpenedPillarB1, []{return ctx->GetTrickOption(RT_WATER_MQ_CENTRAL_PILLAR) && logic->CanUse(RG_FIRE_ARROWS);}), + //this could theoretically matter once OI and equip swap is in logic, as one age may be able to get here dry and not wet, and the other may not be able to OI, but as you can OI with hookshot it probably never happens + //EventAccess(&logic->MQWaterPillarSoTBlock, []{return logic->CanUse(RG_HOOKSHOT) && logic->CanUse(RG_SONG_OF_TIME);}), + }, {}, { + //Exits + Entrance(RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_HIGH, []{return logic->MQWaterLevel(WL_HIGH) && logic->CanUse(RG_FARORES_WIND) && (logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS));}), + Entrance(RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_B1, []{return logic->MQWaterOpenedPillarB1 && logic->MQWaterLevel(WL_MID) && logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_ZORA_TUNIC);}), + }); + + areaTable[RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_HIGH] = Region("Water Temple MQ Central Pillar High", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->MQWaterOpenedPillarB1, []{return ((logic->CanUse(RG_SONG_OF_TIME) && logic->CanUse(RG_DINS_FIRE)) || (ctx->GetTrickOption(RT_WATER_MQ_CENTRAL_PILLAR) && logic->CanUse(RG_FIRE_ARROWS))) && (logic->HasItem(RG_BRONZE_SCALE) || (logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_LONGSHOT) && logic->CanJumpslash()));}), + }, {}, { + //Exits + Entrance(RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_B1, []{return logic->MQWaterB1Switch && logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_ZORA_TUNIC);}), + }); + + //Assuming tunic and irons was checked on entry + areaTable[RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_B1] = Region("Water Temple MQ Central Pillar B1", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + //Can't know water level, so we'll just assume any possibility and skip to MAIN + Entrance(RR_WATER_TEMPLE_MQ_MAIN, []{return logic->MQWaterOpenedPillarB1 && logic->CanUse(RG_IRON_BOOTS) && logic->HasItem(RG_BRONZE_SCALE);}), + //Child needs to release irons for height to push down the larger "peg", however they can push the lower one down by climbing and then hit the switch through the larger peg, but it's a trick + Entrance(RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_B1_FINAL, []{return ((logic->IsAdult && logic->CanUse(RG_LONGSHOT)) || (logic->CanUse(RG_HOOKSHOT) && logic->HasItem(RG_BRONZE_SCALE)));}), + }); + + areaTable[RR_WATER_TEMPLE_MQ_CENTRAL_PILLAR_B1_FINAL] = Region("Water Temple MQ Central Pillar B1 Final", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_WATER_TEMPLE_MQ_CENTRAL_PILLAR_CHEST, logic->CanUse(RG_HOOKSHOT)), + }, {}); + + //Region exists to add crate/pot/box locations + areaTable[RR_WATER_TEMPLE_MQ_STORAGE_ROOM] = Region("Water Temple MQ Storage Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_POT_1, logic->CanBreakPots()), + LOCATION(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_POT_2, logic->CanBreakPots()), + LOCATION(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_A_POT_3, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_WATER_TEMPLE_MQ_MAIN, []{return logic->MQWaterLevel(WL_LOW_OR_MID) || (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8);}), + }); + + areaTable[RR_WATER_TEMPLE_MQ_BEHIND_BLUE_SWITCH_2F] = Region("Water Temple MQ Behind Blue Switch 2F", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_POT_1, logic->CanBreakPots()), + LOCATION(RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_POT_2, logic->CanBreakPots()), + LOCATION(RC_WATER_TEMPLE_MQ_GS_STORAGE_ROOM_POT_3, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_WATER_TEMPLE_MQ_MAIN, []{return true;}), + Entrance(RR_WATER_TEMPLE_MQ_BEHIND_BLUE_SWITCH_3F, []{return logic->CanUse(RG_LONGSHOT);}), + }); + + areaTable[RR_WATER_TEMPLE_MQ_BEHIND_BLUE_SWITCH_3F] = Region("Water Temple MQ Behind Blue Switch 2F", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_WATER_TEMPLE_MQ_GS_BEFORE_UPPER_WATER_SWITCH, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)), + }, { + //Exits + Entrance(RR_WATER_TEMPLE_MQ_BEHIND_BLUE_SWITCH_2F, []{return true;}), + Entrance(RR_WATER_TEMPLE_MQ_HIGH_EMBLEM, []{return true;}), + }); + + areaTable[RR_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY] = Region("Water Temple MQ Lizalfos Hallway", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_WEST_POT, logic->CanBreakPots()), + LOCATION(RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_SOUTH_POT, logic->CanBreakPots()), + LOCATION(RC_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY_SE_POT, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_WATER_TEMPLE_MQ_LIZALFOS_CAGE, []{return logic->MQWaterLevel(WL_LOW_OR_MID) && logic->CanUse(RG_DINS_FIRE);}), + //this technically exists, but only complicates things, uncomment if some edge case/glitch can use RR_WATER_TEMPLE_MQ_LIZALFOS_HALLWAY to reach RR_WATER_TEMPLE_MQ_3F_CENTRAL, or if a void warp goes here + /*Entrance(RR_WATER_TEMPLE_MQ_3F_EAST_LEDGE, []{return (logic->CanUse(RG_HOOKSHOT) && (logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS))) || (logic->MQWaterLevel(WL_LOW_OR_MID) && logic->CanUse(RG_HOOKSHOT)) || logic->MQWaterLevel(WL_HIGH) && (logic->HasItem(RG_BRONZE_SCALE));}), + }); + + areaTable[RR_WATER_TEMPLE_MQ_3F_EAST_LEDGE] = Region("Water Temple MQ 3F East Ledge", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_WATER_TEMPLE_MQ_MAIN, []{return true;}), + Entrance(RR_WATER_TEMPLE_MQ_3F_CENTRAL, []{return logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS);}),*/ + }); + + areaTable[RR_WATER_TEMPLE_MQ_LIZALFOS_CAGE] = Region("Water Temple MQ Lizalfos Cage", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_WATER_TEMPLE_MQ_GS_LIZALFOS_HALLWAY, logic->CanKillEnemy(RE_GOLD_SKULLTULA)), + LOCATION(RC_WATER_TEMPLE_MQ_LIZALFOS_CAGE_SOUTH_POT, logic->CanBreakPots()), + LOCATION(RC_WATER_TEMPLE_MQ_LIZALFOS_CAGE_NORTH_POT, logic->CanBreakPots()), + }, {}); + + //This room exists to hold the wonderitems that drop from the emblems here. Specifically this assumes you are standing on the final ledge + areaTable[RR_WATER_TEMPLE_MQ_WATERFALL] = Region("Water Temple Waterfall", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_WATER_TEMPLE_MQ_3F_CENTRAL, []{return logic->SmallKeys(RR_WATER_TEMPLE, 1) && logic->CanUse(RG_LONGSHOT);}), + Entrance(RR_WATER_TEMPLE_MQ_STALFOS_PIT, []{return true;}), + Entrance(RR_WATER_TEMPLE_MQ_STALFOS_PIT_POTS, []{return (logic->MQWaterStalfosPit && logic->IsAdult && logic->CanUse(RG_HOOKSHOT)) || logic->CanUse(RG_HOVER_BOOTS);}), + Entrance(RR_WATER_TEMPLE_MQ_STALFOS_PIT_UPPER, []{return logic->MQWaterStalfosPit && logic->CanUse(RG_LONGSHOT);}), + }); + + areaTable[RR_WATER_TEMPLE_MQ_STALFOS_PIT] = Region("Water Temple MQ Stalfos Pit", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->MQWaterStalfosPit, []{return ((logic->IsAdult && logic->CanKillEnemy(RE_STALFOS, ED_CLOSE, true, 3, false, true)) || (logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT) && logic->CanKillEnemy(RE_STALFOS, ED_BOMB_THROW, true, 3, false, true)));}), + }, {}, { + //Exits + Entrance(RR_WATER_TEMPLE_MQ_WATERFALL, []{return logic->MQWaterStalfosPit && logic->CanUse(RG_HOOKSHOT) && (logic->IsAdult || logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8);}), + Entrance(RR_WATER_TEMPLE_MQ_STALFOS_PIT_POTS, []{return (logic->IsAdult && logic->CanUse(RG_HOOKSHOT)) || (logic->CanUse(RG_HOOKSHOT) && (logic->IsAdult || logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8) && (logic->CanUse(RG_HOVER_BOOTS) || logic->MQWaterStalfosPit));}), + Entrance(RR_WATER_TEMPLE_MQ_STALFOS_PIT_UPPER, []{return logic->MQWaterStalfosPit && (logic->IsAdult || logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8) && logic->CanUse(RG_HOOKSHOT);}), + }); + + //also includes the suns fairy in the middle + areaTable[RR_WATER_TEMPLE_MQ_STALFOS_PIT_POTS] = Region("Water Temple MQ Stalfos Pit Pots", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->FairyPot, []{return true;}), + EventAccess(&logic->NutPot, []{return true;}), + }, { + //Locations + LOCATION(RC_WATER_TEMPLE_MQ_STALFOS_PIT_SOUTH_POT, logic->CanBreakPots()), + LOCATION(RC_WATER_TEMPLE_MQ_STALFOS_PIT_MIDDLE_POT, logic->CanBreakPots()), + LOCATION(RC_WATER_TEMPLE_MQ_STALFOS_PIT_NORTH_POT, logic->CanBreakPots()), + LOCATION(RC_WATER_TEMPLE_MQ_DARK_LINK_PILAR_SUN_FAIRY, logic->CanUse(RG_SUNS_SONG)), + }, { + //Exits + Entrance(RR_WATER_TEMPLE_MQ_WATERFALL, []{return logic->MQWaterStalfosPit && (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_LONGSHOT));}), + Entrance(RR_WATER_TEMPLE_MQ_STALFOS_PIT, []{return true;}), + Entrance(RR_WATER_TEMPLE_MQ_STALFOS_PIT_UPPER, []{return logic->MQWaterStalfosPit && logic->CanUse(RG_HOOKSHOT);}), + }); + + //specifically the area past the spikes + areaTable[RR_WATER_TEMPLE_MQ_STALFOS_PIT_UPPER] = Region("Water Temple MQ Stalfos Pit Upper", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_WATER_TEMPLE_MQ_BEFORE_DARK_LINK_POT_1, logic->CanBreakPots()), + LOCATION(RC_WATER_TEMPLE_MQ_BEFORE_DARK_LINK_POT_2, logic->CanBreakPots()), + LOCATION(RC_WATER_TEMPLE_MQ_DARK_LINK_LEFT_STORM_FAIRY, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_WATER_TEMPLE_MQ_DARK_LINK_RIGHT_SUN_FAIRY, logic->CanUse(RG_SUNS_SONG)), + }, { + //Exits + Entrance(RR_WATER_TEMPLE_MQ_STALFOS_PIT, []{return logic->IsAdult || logic->TakeDamage();}), + Entrance(RR_WATER_TEMPLE_MQ_STALFOS_PIT_POTS, []{return logic->IsAdult || logic->TakeDamage();}), + Entrance(RR_WATER_TEMPLE_MQ_AFTER_DARK_LINK, []{return logic->CanKillEnemy(RE_DARK_LINK);}), + }); + + areaTable[RR_WATER_TEMPLE_MQ_AFTER_DARK_LINK] = Region("Water Temple MQ After Dark Link", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->FairyPot, []{return true;}), + }, { + //Locations + LOCATION(RC_WATER_TEMPLE_MQ_AFTER_DARK_LINK_POT_1, logic->CanBreakPots()), + LOCATION(RC_WATER_TEMPLE_MQ_AFTER_DARK_LINK_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_WATER_TEMPLE_MQ_STALFOS_PIT_UPPER, []{return logic->CanKillEnemy(RE_DARK_LINK);}), + Entrance(RR_WATER_TEMPLE_MQ_RIVER_SKULL, []{return logic->CanUse(RG_HOOKSHOT) && (logic->HasItem(RG_BRONZE_SCALE) || (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8) || logic->CanUse(RG_LONGSHOT));}), + }); + + //if we can use hookshot, we are standing on the targets, otherwise assume we're in the water + areaTable[RR_WATER_TEMPLE_MQ_RIVER_SKULL] = Region("Water Temple MQ River Skull", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_WATER_TEMPLE_MQ_GS_RIVER, logic->CanUse(RG_LONGSHOT) || (logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT))), + }, { + //Exits + Entrance(RR_WATER_TEMPLE_MQ_RIVER_POTS, []{return logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_LONGSHOT);}), + }); + + areaTable[RR_WATER_TEMPLE_MQ_RIVER_POTS] = Region("Water Temple MQ River Pots", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->FairyPot, []{return true;}), + }, { + //Locations + LOCATION(RC_WATER_TEMPLE_MQ_RIVER_POT_1, logic->CanBreakPots()), + LOCATION(RC_WATER_TEMPLE_MQ_RIVER_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_WATER_TEMPLE_MQ_RIVER_SKULL, []{return logic->CanUse(RG_LONGSHOT) || (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8 && logic->CanUse(RG_HOOKSHOT));}), + //You don't need to swim for this if you put irons on in midair and hold forward while aiming for the tunnel with a tight angle, but if you miss you have to void unless you have a hook. It's only relevant with glitches anyway + Entrance(RR_WATER_TEMPLE_MQ_DRAGON_ROOM_TUNNEL, []{return logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16;}), + Entrance(RR_WATER_TEMPLE_MQ_DRAGON_ROOM_ALCOVE, []{return logic->HasItem(RG_SILVER_SCALE) || (logic->IsAdult && logic->HasItem(RG_BRONZE_SCALE) && ctx->GetTrickOption(RT_WATER_DRAGON_JUMP_DIVE));}), + Entrance(RR_WATER_TEMPLE_MQ_DRAGON_ROOM_DOOR, []{return logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_LONGSHOT) || (logic->CanUse(RG_HOVER_BOOTS) && logic->CanJumpslash());}), + }); + + //This region assumes Iron boots to access + areaTable[RR_WATER_TEMPLE_MQ_DRAGON_ROOM_TUNNEL] = Region("Water Temple MQ Dragon Room Tunnel", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_WATER_TEMPLE_MQ_RIVER_POTS, []{return logic->CanUse(RG_LONGSHOT);}), + Entrance(RR_WATER_TEMPLE_MQ_DRAGON_ROOM_ALCOVE, []{return logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_HOOKSHOT);}), + Entrance(RR_WATER_TEMPLE_MQ_DRAGON_ROOM_DOOR, []{return logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_LONGSHOT);}), + }); + + areaTable[RR_WATER_TEMPLE_MQ_DRAGON_ROOM_ALCOVE] = Region("Water Temple MQ Dragon Room Alcove", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->MQWaterDragonTorches, []{return true;}), + }, {}, { + //Exits + Entrance(RR_WATER_TEMPLE_MQ_DRAGON_ROOM_TUNNEL, []{return logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16;}), + Entrance(RR_WATER_TEMPLE_MQ_DRAGON_ROOM_DOOR, []{return logic->HasItem(RG_SILVER_SCALE);}), + }); + + areaTable[RR_WATER_TEMPLE_MQ_DRAGON_ROOM_DOOR] = Region("Water Temple MQ Dragon Room Door", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_WATER_TEMPLE_MQ_RIVER_POTS, []{return logic->CanUse(RG_LONGSHOT);}), + Entrance(RR_WATER_TEMPLE_MQ_DRAGON_ROOM_TUNNEL, []{return logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16 && logic->CanUse(RG_HOOKSHOT);}), + Entrance(RR_WATER_TEMPLE_MQ_DRAGON_ROOM_ALCOVE, []{return logic->HasItem(RG_SILVER_SCALE);}), + Entrance(RR_WATER_TEMPLE_MQ_BOSS_KEY_ROOM_SWITCH, []{return logic->MQWaterDragonTorches;}), + }); + + areaTable[RR_WATER_TEMPLE_MQ_BOSS_KEY_ROOM_SWITCH] = Region("Water Temple MQ Boss Key Room Switch", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_WATER_TEMPLE_MQ_BOSS_KEY_POT, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_WATER_TEMPLE_MQ_DRAGON_ROOM_DOOR, []{return true;}), + Entrance(RR_WATER_TEMPLE_MQ_BOSS_KEY_ROOM_PIT, []{return true;}), + Entrance(RR_WATER_TEMPLE_MQ_BOSS_KEY_ROOM_CHEST, []{return logic->CanHitSwitch() && Here(RR_WATER_TEMPLE_MQ_BOSS_KEY_ROOM_SWITCH, []{return logic->CanUse(RG_DINS_FIRE);});}), + }); + + //this exists for the crates in preparation for clips through the grate + areaTable[RR_WATER_TEMPLE_MQ_BOSS_KEY_ROOM_PIT] = Region("Water Temple MQ Boss Key Room Pit", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_WATER_TEMPLE_MQ_BOSS_KEY_ROOM_SWITCH, []{return logic->CanHitSwitch(ED_BOOMERANG);}), + }); + + areaTable[RR_WATER_TEMPLE_MQ_BOSS_KEY_ROOM_CHEST] = Region("Water Temple MQ Boss Key Room Chest", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_WATER_TEMPLE_MQ_BOSS_KEY_CHEST, true), + }, { + //Exits + Entrance(RR_WATER_TEMPLE_MQ_BOSS_KEY_ROOM_SWITCH, []{return logic->CanHitSwitch(ED_BOMB_THROW) || logic->CanUse(RG_HOVER_BOOTS);}), + Entrance(RR_WATER_TEMPLE_MQ_BOSS_KEY_ROOM_PIT, []{return true;}), + Entrance(RR_WATER_TEMPLE_MQ_B1_GATE_SWITCH, []{return logic->HasItem(RG_SILVER_SCALE) || (logic->CanUse(RG_IRON_BOOTS) && (logic->HasItem(RG_BRONZE_SCALE) || (logic->WaterTimer() >= 24 && logic->CanUse(RG_LONGSHOT))));}), + }); + + areaTable[RR_WATER_TEMPLE_MQ_B1_GATE_SWITCH] = Region("Water Temple MQ B1 Gate Switch", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, { + //Events + //If the water is low, the switch is underwater and needs irons to press, otherwise, the water is too low to climb up and you need irons to hookshot a target + //If a glitch clips through the gate on low, have it logically press the switch and let entrance logic enter + EventAccess(&logic->MQWaterB1Switch, []{return logic->CanUse(RG_IRON_BOOTS);}), + }, {}, { + //Exits + Entrance(RR_WATER_TEMPLE_MQ_MAIN, []{return logic->MQWaterB1Switch && (logic->MQWaterLevel(WL_LOW) || (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16));}), + Entrance(RR_WATER_TEMPLE_MQ_BOSS_KEY_ROOM_CHEST, []{return logic->CanUse(RG_IRON_BOOTS) && logic->HasItem(RG_BRONZE_SCALE) && (logic->MQWaterLevel(WL_LOW) || logic->WaterTimer() >= 24);}) + }); + + areaTable[RR_WATER_TEMPLE_MQ_TRIANGLE_TORCH_ROOM] = Region("Water Temple MQ Triangle Torch Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_WATER_TEMPLE_MQ_MAIN, []{return logic->MQWaterB1Switch && ((logic->MQWaterLevel(WL_LOW) && logic->HasItem(RG_GOLDEN_SCALE)) || (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 40 && (logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_LONGSHOT))));}), + Entrance(RR_WATER_TEMPLE_MQ_TRIANGLE_TORCH_CAGE, []{return logic->CanUse(RG_FIRE_ARROWS) && ((logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)) || (logic->CanUse(RG_LONGSHOT) && Here(RR_WATER_TEMPLE_MQ_TRIANGLE_TORCH_CAGE, []{return logic->ScarecrowsSong();})));}) + }); + + areaTable[RR_WATER_TEMPLE_MQ_TRIANGLE_TORCH_CAGE] = Region("Water Temple MQ Triangle Torch Cage", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_WATER_TEMPLE_MQ_GS_TRIPLE_WALL_TORCH, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)), + LOCATION(RC_WATER_TEMPLE_MQ_LOWEST_GS_POT_1, logic->CanBreakPots()), + LOCATION(RC_WATER_TEMPLE_MQ_LOWEST_GS_POT_2, logic->CanBreakPots()), + LOCATION(RC_WATER_TEMPLE_MQ_LOWEST_GS_POT_3, logic->CanBreakPots()), + LOCATION(RC_WATER_TEMPLE_MQ_LOWEST_GS_POT_4, logic->CanBreakPots()), + }, {}); + + areaTable[RR_WATER_TEMPLE_MQ_CRATES_WHIRLPOOLS_ROOM] = Region("Water Temple MQ Crates Whirlpools Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + //we can backflip over the spikes, but land in water. + Entrance(RR_WATER_TEMPLE_MQ_MAIN, []{return logic->MQWaterB1Switch && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 24 && (logic->CanUse(RG_LONGSHOT) || logic->HasItem(RG_BRONZE_SCALE));}), + //Child can use the crate to get the height to make it with hovers, but it's annoyingly tight so would be a trick + Entrance(RR_WATER_TEMPLE_MQ_SINGLE_STALFOS_ROOM, []{return logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8 && + //We're putting the requirement to get out of the water here as the scarecrow method in includes hook which satisfies it + ((logic->IsAdult && (logic->CanUse(RG_HOVER_BOOTS) || ctx->GetTrickOption(RT_WATER_NORTH_BASEMENT_LEDGE_JUMP)) && (logic->CanUse(RG_HOOKSHOT) || logic->HasItem(RG_BRONZE_SCALE))) || + (Here(RR_WATER_TEMPLE_MQ_CRATES_WHIRLPOOLS_ROOM, []{return logic->ScarecrowsSong();}) && logic->CanUse(RG_HOOKSHOT)));}), + Entrance(RR_WATER_TEMPLE_MQ_4_TORCH_ROOM, []{return logic->IsAdult && (logic->CanUse(RG_HOVER_BOOTS) || ctx->GetTrickOption(RT_WATER_NORTH_BASEMENT_LEDGE_JUMP) || (Here(RR_WATER_TEMPLE_MQ_CRATES_WHIRLPOOLS_ROOM, []{return logic->ScarecrowsSong();}) && logic->CanUse(RG_HOOKSHOT)));}), + Entrance(RR_WATER_TEMPLE_MQ_CRATES_WHIRLPOOLS_CAGE, []{return ctx->GetTrickOption(RT_WATER_MQ_LOCKED_GS) && (logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT));}), + }); + + areaTable[RR_WATER_TEMPLE_MQ_SINGLE_STALFOS_ROOM] = Region("Water Temple MQ Single Stalfos Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_WATER_TEMPLE_MQ_FREESTANDING_KEY, true), + LOCATION(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_B_POT_1, logic->CanBreakPots()), + LOCATION(RC_WATER_TEMPLE_MQ_STORAGE_ROOM_B_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_WATER_TEMPLE_MQ_CRATES_WHIRLPOOLS_ROOM, []{return logic->HasItem(RG_SILVER_SCALE) || (logic->IsChild && logic->HasItem(RG_BRONZE_SCALE)) || (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8 && (logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_HOOKSHOT)));}) + }); + + areaTable[RR_WATER_TEMPLE_MQ_4_TORCH_ROOM] = Region("Water Temple MQ 4 Torch Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_WATER_TEMPLE_MQ_CRATES_WHIRLPOOLS_ROOM, []{return (logic->IsAdult && (logic->CanUse(RG_HOVER_BOOTS) || logic->CanJumpslash())) || (logic->HasItem(RG_BRONZE_SCALE) || (logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 8 && logic->CanUse(RG_HOOKSHOT) ));}), + Entrance(RR_WATER_TEMPLE_MQ_DODONGO_ROOM, []{return logic->CanHitSwitch() && logic->HasFireSource();}) + }); + + areaTable[RR_WATER_TEMPLE_MQ_DODONGO_ROOM] = Region("Water Temple MQ Dodongo Room", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_WATER_TEMPLE_MQ_MINI_DODONGO_POT_1, logic->CanBreakPots()), + LOCATION(RC_WATER_TEMPLE_MQ_MINI_DODONGO_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_WATER_TEMPLE_MQ_4_TORCH_ROOM, []{return (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS)) && Here(RR_WATER_TEMPLE_MQ_DODONGO_ROOM, []{return logic->CanKillEnemy(RE_DODONGO, ED_CLOSE, true, 5);});}), + Entrance(RR_WATER_TEMPLE_MQ_CRATES_WHIRLPOOLS_CAGE, []{return (logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS)) && Here(RR_WATER_TEMPLE_MQ_DODONGO_ROOM, []{return logic->CanKillEnemy(RE_DODONGO, ED_CLOSE, true, 5);});}) + }); + + areaTable[RR_WATER_TEMPLE_MQ_CRATES_WHIRLPOOLS_CAGE] = Region("Water Temple MQ Basement Gated Areas", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_WATER_TEMPLE_MQ_GS_FREESTANDING_KEY_AREA, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)), + }, { + Entrance(RR_WATER_TEMPLE_MQ_DODONGO_ROOM, []{return true;}) + }); + +#pragma endregion + + // Boss Room + areaTable[RR_WATER_TEMPLE_BOSS_ENTRYWAY] = Region("Water Temple Boss Entryway", "Water Temple", {RA_WATER_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + // Exits + Entrance(RR_WATER_TEMPLE_PRE_BOSS_ROOM, []{return ctx->GetDungeon(WATER_TEMPLE)->IsVanilla() && false;}), + Entrance(RR_WATER_TEMPLE_MQ_BOSS_DOOR, []{return ctx->GetDungeon(WATER_TEMPLE)->IsMQ() && false;}), + Entrance(RR_WATER_TEMPLE_BOSS_ROOM, []{return true;}), + }); + + areaTable[RR_WATER_TEMPLE_BOSS_ROOM] = Region("Water Temple Boss Room", "Water Temple", {}, NO_DAY_NIGHT_CYCLE, { + // Events + EventAccess(&logic->WaterTempleClear, []{return logic->WaterTempleClear || (logic->HasBossSoul(RG_MORPHA_SOUL) && (logic->CanUse(RG_HOOKSHOT) && (logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_BIGGORON_SWORD))));}), + }, { + // Locations + LOCATION(RC_WATER_TEMPLE_MORPHA_HEART, logic->WaterTempleClear), + LOCATION(RC_MORPHA, logic->WaterTempleClear), + }, { + // Exits + Entrance(RR_WATER_TEMPLE_BOSS_ENTRYWAY, []{return false;}), + Entrance(RR_LAKE_HYLIA, []{return logic->WaterTempleClear;}, false), + }); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/gerudo_fortress.cpp b/soh/soh/Enhancements/randomizer/location_access/gerudo_fortress.cpp new file mode 100644 index 000000000..6af0551e0 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/gerudo_fortress.cpp @@ -0,0 +1,81 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" + +using namespace Rando; + +/* + * This file should be split into "gerudo_fortress.cpp" (overworld) & "thieves_hideout.cpp" (dungeons) + * when the gerudo fortress refactor is done + */ + +void RegionTable_Init_GerudoFortress() { + areaTable[RR_GERUDO_FORTRESS] = Region("Gerudo Fortress", "Gerudo Fortress", {RA_GERUDO_FORTRESS}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->CarpenterRescue, []{return logic->CanFinishGerudoFortress();}), + EventAccess(&logic->GF_GateOpen, []{return logic->IsAdult && logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD);}), + EventAccess(&logic->GtG_GateOpen, []{return logic->GtG_GateOpen || (logic->IsAdult && logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) && logic->HasItem(RG_CHILD_WALLET));}), + }, { + //Locations + LOCATION(RC_GF_CHEST, logic->CanUse(RG_HOVER_BOOTS) || (logic->IsAdult && logic->CanUse(RG_SCARECROW)) || logic->CanUse(RG_LONGSHOT)), + LOCATION(RC_GF_HBA_1000_POINTS, logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) && logic->CanUse(RG_EPONA) && logic->CanUse(RG_FAIRY_BOW) && logic->AtDay), + LOCATION(RC_GF_HBA_1500_POINTS, logic->HasItem(RG_CHILD_WALLET) && logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) && logic->CanUse(RG_EPONA) && logic->CanUse(RG_FAIRY_BOW) && logic->AtDay), + LOCATION(RC_GF_NORTH_F1_CARPENTER, logic->CanKillEnemy(RE_GERUDO_WARRIOR)), + LOCATION(RC_GF_NORTH_F2_CARPENTER, (logic->CanKillEnemy(RE_GERUDO_WARRIOR)) && (logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS) || ctx->GetTrickOption(RT_GF_KITCHEN))), + LOCATION(RC_GF_SOUTH_F1_CARPENTER, logic->CanKillEnemy(RE_GERUDO_WARRIOR)), + LOCATION(RC_GF_SOUTH_F2_CARPENTER, logic->CanKillEnemy(RE_GERUDO_WARRIOR)), + LOCATION(RC_GF_GERUDO_MEMBERSHIP_CARD, logic->CanFinishGerudoFortress()), + LOCATION(RC_GF_GS_ARCHERY_RANGE, logic->IsAdult && logic->HookshotOrBoomerang() && logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) && logic->CanGetNightTimeGS()), + LOCATION(RC_GF_GS_TOP_FLOOR, logic->IsAdult && (logic->CanJumpslashExceptHammer() || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_BOOMERANG) || logic->HasExplosives() || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_DINS_FIRE)) && (logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT) || logic->CanUse(RG_HOVER_BOOTS) || ctx->GetTrickOption(RT_GF_KITCHEN) || ctx->GetTrickOption(RT_GF_JUMP)) && logic->CanGetNightTimeGS()), + LOCATION(RC_GF_BREAK_ROOM_POT_1, logic->CanBreakPots()), + LOCATION(RC_GF_BREAK_ROOM_POT_2, logic->CanBreakPots()), + LOCATION(RC_GF_KITCHEN_POT_1, (logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT)) && logic->CanBreakPots()), + LOCATION(RC_GF_KITCHEN_POT_2, (logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT)) && logic->CanBreakPots()), + LOCATION(RC_GF_NORTH_F1_CARPENTER_POT_1, logic->CanBreakPots()), + LOCATION(RC_GF_NORTH_F1_CARPENTER_POT_2, logic->CanBreakPots()), + LOCATION(RC_GF_NORTH_F1_CARPENTER_POT_3, logic->CanBreakPots()), + LOCATION(RC_GF_NORTH_F2_CARPENTER_POT_1, logic->CanBreakPots()), + LOCATION(RC_GF_NORTH_F2_CARPENTER_POT_2, logic->CanBreakPots()), + LOCATION(RC_GF_SOUTH_F1_CARPENTER_POT_1, logic->CanBreakPots()), + LOCATION(RC_GF_SOUTH_F1_CARPENTER_POT_2, logic->CanBreakPots()), + LOCATION(RC_GF_SOUTH_F1_CARPENTER_POT_3, logic->CanBreakPots()), + LOCATION(RC_GF_SOUTH_F1_CARPENTER_CELL_POT_1, logic->CanBreakPots()), + LOCATION(RC_GF_SOUTH_F1_CARPENTER_CELL_POT_2, logic->CanBreakPots()), + LOCATION(RC_GF_SOUTH_F1_CARPENTER_CELL_POT_3, logic->CanBreakPots()), + LOCATION(RC_GF_SOUTH_F1_CARPENTER_CELL_POT_4, logic->CanBreakPots()), + //RANDOTODO doublecheck when GF isn't a blob + LOCATION(RC_GF_KITCHEN_SUN_FAIRY, (logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_HOOKSHOT)) && logic->CanUse(RG_SUNS_SONG)), + }, { + //Exits + Entrance(RR_GV_FORTRESS_SIDE, []{return true;}), + Entrance(RR_GF_OUTSIDE_GATE, []{return logic->GF_GateOpen;}), + Entrance(RR_GERUDO_TRAINING_GROUND_ENTRYWAY, []{return logic->GtG_GateOpen && (logic->IsAdult || ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES));}), + Entrance(RR_GF_STORMS_GROTTO, []{return logic->IsAdult && logic->CanOpenStormsGrotto();}), + }); + + areaTable[RR_GF_OUTSIDE_GATE] = Region("GF Outside Gate", "Gerudo Fortress", {RA_GERUDO_FORTRESS}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->GF_GateOpen, []{return logic->IsAdult && logic->HasItem(RG_GERUDO_MEMBERSHIP_CARD) && (ctx->GetOption(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD) || ctx->GetOption(RSK_SHUFFLE_OVERWORLD_ENTRANCES) /*|| ShuffleSpecialIndoorEntrances*/);}), + }, {}, { + //Exits + Entrance(RR_GERUDO_FORTRESS, []{return (logic->IsAdult && (logic->CanUse(RG_HOOKSHOT) || !ctx->GetOption(RSK_SHUFFLE_OVERWORLD_ENTRANCES))) || logic->GF_GateOpen;}), + Entrance(RR_WASTELAND_NEAR_FORTRESS, []{return true;}), + }); + + areaTable[RR_GF_STORMS_GROTTO] = Region("GF Storms Grotto", "GF Storms Grotto", {}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->FreeFairies, []{return true;}), + }, { + //Locations + LOCATION(RC_GF_FAIRY_GROTTO_FAIRY_1, true), + LOCATION(RC_GF_FAIRY_GROTTO_FAIRY_2, true), + LOCATION(RC_GF_FAIRY_GROTTO_FAIRY_3, true), + LOCATION(RC_GF_FAIRY_GROTTO_FAIRY_4, true), + LOCATION(RC_GF_FAIRY_GROTTO_FAIRY_5, true), + LOCATION(RC_GF_FAIRY_GROTTO_FAIRY_6, true), + LOCATION(RC_GF_FAIRY_GROTTO_FAIRY_7, true), + LOCATION(RC_GF_FAIRY_GROTTO_FAIRY_8, true), + }, { + //Exits + Entrance(RR_GERUDO_FORTRESS, []{return true;}), + }); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/castle_grounds.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/castle_grounds.cpp new file mode 100644 index 000000000..6a3069b18 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/overworld/castle_grounds.cpp @@ -0,0 +1,117 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" + +using namespace Rando; + +void RegionTable_Init_CastleGrounds() { + //With multi-area support {RA_CASTLE_GROUNDS} is not strictly required anymore, as any interior here could inherit both + //{RA_HYRULE_CASTLE} and {RA_OUTSIDE_GANONS_CASTLE}, but an setting to merge the latter 2 into the former may be preffered + areaTable[RR_CASTLE_GROUNDS] = Region("Castle Grounds", "Castle Grounds", {RA_CASTLE_GROUNDS}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_THE_MARKET, []{return true;}), + Entrance(RR_HYRULE_CASTLE_GROUNDS, []{return logic->IsChild;}), + Entrance(RR_GANONS_CASTLE_GROUNDS, []{return logic->IsAdult;}), + }); + + areaTable[RR_HYRULE_CASTLE_GROUNDS] = Region("Hyrule Castle Grounds", "Castle Grounds", {RA_HYRULE_CASTLE}, DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->GossipStoneFairy, []{return logic->CallGossipFairy();}), + EventAccess(&logic->ButterflyFairy, []{return logic->ButterflyFairy || logic->CanUse(RG_STICKS);}), + EventAccess(&logic->BugRock, []{return true;}), + }, { + //Locations + LOCATION(RC_HC_MALON_EGG, true), + LOCATION(RC_HC_GS_TREE, logic->IsChild && logic->CanAttack()), + LOCATION(RC_HC_MALON_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), + LOCATION(RC_HC_MALON_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_HC_ROCK_WALL_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), + LOCATION(RC_HC_ROCK_WALL_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_HC_MALON_GOSSIP_STONE, true), + LOCATION(RC_HC_ROCK_WALL_GOSSIP_STONE, true), + }, { + //Exits + Entrance(RR_CASTLE_GROUNDS, []{return true;}), + Entrance(RR_HC_GARDEN, []{return logic->CanUse(RG_WEIRD_EGG) || !ctx->GetOption(RSK_SHUFFLE_WEIRD_EGG) || (ctx->GetTrickOption(RT_DAMAGE_BOOST_SIMPLE) && logic->HasExplosives() && logic->CanJumpslash());}), + Entrance(RR_HC_GREAT_FAIRY_FOUNTAIN, []{return logic->BlastOrSmash();}), + Entrance(RR_HC_STORMS_GROTTO, []{return logic->CanOpenStormsGrotto();}), + }); + + areaTable[RR_HC_GARDEN] = Region("HC Garden", "Castle Grounds", {RA_HYRULE_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_HC_ZELDAS_LETTER, true), + LOCATION(RC_SONG_FROM_IMPA, true), + }, { + //Exits + Entrance(RR_HYRULE_CASTLE_GROUNDS, []{return true;}), + }); + + areaTable[RR_HC_GREAT_FAIRY_FOUNTAIN] = Region("HC Great Fairy Fountain", "HC Great Fairy Fountain", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_HC_GREAT_FAIRY_REWARD, logic->CanUse(RG_ZELDAS_LULLABY)), + }, { + //Exits + Entrance(RR_CASTLE_GROUNDS, []{return true;}), + }); + + areaTable[RR_HC_STORMS_GROTTO] = Region("HC Storms Grotto", "HC Storms Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_HC_GS_STORMS_GROTTO, logic->CanUse(RG_BOOMERANG) && ctx->GetTrickOption(RT_HC_STORMS_GS)), + }, { + //Exits + Entrance(RR_CASTLE_GROUNDS, []{return true;}), + Entrance(RR_HC_STORMS_GROTTO_BEHIND_WALLS, []{return logic->CanBreakMudWalls();}), + }); + + areaTable[RR_HC_STORMS_GROTTO_BEHIND_WALLS] = Region("HC Storms Grotto Behind Walls", "HC Storms Grotto", {}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->NutPot, []{return true;}), + EventAccess(&logic->GossipStoneFairy, []{return logic->CallGossipFairy();}), + EventAccess(&logic->WanderingBugs, []{return true;}), + }, { + //Locations + LOCATION(RC_HC_GS_STORMS_GROTTO, logic->HookshotOrBoomerang()), + LOCATION(RC_HC_STORMS_GROTTO_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), + LOCATION(RC_HC_STORMS_GROTTO_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_HC_STORMS_GROTTO_GOSSIP_STONE, true), + LOCATION(RC_HC_STORMS_GROTTO_POT_1, logic->CanBreakPots()), + LOCATION(RC_HC_STORMS_GROTTO_POT_2, logic->CanBreakPots()), + LOCATION(RC_HC_STORMS_GROTTO_POT_3, logic->CanBreakPots()), + LOCATION(RC_HC_STORMS_GROTTO_POT_4, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_CASTLE_GROUNDS, []{return true;}), + }); + + areaTable[RR_GANONS_CASTLE_GROUNDS] = Region("Ganon's Castle Grounds", "Castle Grounds", {RA_OUTSIDE_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->BuiltRainbowBridge, []{return logic->CanBuildRainbowBridge();}), + }, { + //Locations + LOCATION(RC_OGC_GS, logic->CanJumpslashExceptHammer() || logic->CanUseProjectile() || (logic->CanShield() && logic->CanUse(RG_MEGATON_HAMMER)) || logic->CanUse(RG_DINS_FIRE)), + }, { + //Exits + Entrance(RR_CASTLE_GROUNDS, []{return logic->AtNight;}), + Entrance(RR_OGC_GREAT_FAIRY_FOUNTAIN, []{return logic->CanUse(RG_GOLDEN_GAUNTLETS) && logic->AtNight;}), + Entrance(RR_GANONS_CASTLE_LEDGE, []{return logic->BuiltRainbowBridge;}), + }); + + areaTable[RR_OGC_GREAT_FAIRY_FOUNTAIN] = Region("OGC Great Fairy Fountain", "OGC Great Fairy Fountain", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_OGC_GREAT_FAIRY_REWARD, logic->CanUse(RG_ZELDAS_LULLABY)), + }, { + //Exits + Entrance(RR_CASTLE_GROUNDS, []{return true;}), + }); + + areaTable[RR_CASTLE_GROUNDS_FROM_GANONS_CASTLE] = Region("Castle Grounds From Ganon's Castle", "Castle Grounds From Ganon's Castle", {RA_CASTLE_GROUNDS}, NO_DAY_NIGHT_CYCLE, {}, {}, { + // Exits + Entrance(RR_HYRULE_CASTLE_GROUNDS, []{return logic->IsChild;}), + Entrance(RR_GANONS_CASTLE_LEDGE, []{return logic->IsAdult;}), + }); + + areaTable[RR_GANONS_CASTLE_LEDGE] = Region("Ganon's Castle Ledge", "OGC Ganon's Castle Ledge", {RA_OUTSIDE_GANONS_CASTLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + // Exits + Entrance(RR_GANONS_CASTLE_GROUNDS, []{return logic->BuiltRainbowBridge;}), + Entrance(RR_GANONS_CASTLE_ENTRYWAY, []{return logic->IsAdult;}), + }); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/death_mountain_crater.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/death_mountain_crater.cpp new file mode 100644 index 000000000..6ba8bfc6e --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/overworld/death_mountain_crater.cpp @@ -0,0 +1,145 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" + +using namespace Rando; + +void RegionTable_Init_DeathMountainCrater() { + areaTable[RR_DMC_UPPER_NEARBY] = Region("DMC Upper Nearby", "Death Mountain Crater", {RA_DEATH_MOUNTAIN_CRATER}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_DMC_UPPER_LOCAL, []{return logic->FireTimer() >= 48;}), + Entrance(RR_DEATH_MOUNTAIN_SUMMIT, []{return true;}), + Entrance(RR_DMC_UPPER_GROTTO, []{return Here(RR_DMC_UPPER_NEARBY, []{return logic->BlastOrSmash() && (logic->FireTimer() >= 8 || logic->Hearts() >= 3);});}) + }); + + areaTable[RR_DMC_UPPER_LOCAL] = Region("DMC Upper Local", "Death Mountain Crater", {RA_DEATH_MOUNTAIN_CRATER}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->GossipStoneFairy, []{return logic->GossipStoneFairy || (logic->HasExplosives() && logic->CallGossipFairyExceptSuns() && (logic->FireTimer() >= 16 || logic->Hearts() >= 3));}), + }, { + //Locations + LOCATION(RC_DMC_WALL_FREESTANDING_POH, logic->FireTimer() >= 16 || logic->Hearts() >= 3), + LOCATION(RC_DMC_GS_CRATE, (logic->FireTimer() >= 8 || logic->Hearts() >= 3) && logic->IsChild && logic->CanAttack()), + LOCATION(RC_DMC_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns() && logic->HasExplosives() && (logic->FireTimer() >= 16 || logic->Hearts() >= 3)), + LOCATION(RC_DMC_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS) && logic->HasExplosives() && (logic->FireTimer() >= 16 || logic->Hearts() >= 3)), + LOCATION(RC_DMC_GOSSIP_STONE, logic->HasExplosives() && (logic->FireTimer() >= 16 || logic->Hearts() >= 3)), + }, { + //Exits + Entrance(RR_DMC_UPPER_NEARBY, []{return true;}), + Entrance(RR_DMC_LADDER_AREA_NEARBY, []{return logic->FireTimer() >= 16 || logic->Hearts() >= 3;}), + Entrance(RR_DMC_CENTRAL_NEARBY, []{return logic->IsAdult && logic->CanUse(RG_GORON_TUNIC) && logic->CanUse(RG_DISTANT_SCARECROW) && ((logic->EffectiveHealth() > 2) || (logic->CanUse(RG_BOTTLE_WITH_FAIRY) && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).IsNot(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF)) || logic->CanUse(RG_NAYRUS_LOVE));}), + Entrance(RR_DMC_LOWER_NEARBY, []{return false;}), + Entrance(RR_DMC_DISTANT_PLATFORM, []{return (logic->FireTimer() >= 48 && logic->Hearts() >= 2) || logic->Hearts() >= 3;}), + }); + + areaTable[RR_DMC_LADDER_AREA_NEARBY] = Region("DMC Ladder Region Nearby", "Death Mountain Crater", {RA_DEATH_MOUNTAIN_CRATER}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DMC_DEKU_SCRUB, logic->IsChild && logic->CanStunDeku()), + }, { + //Exits + Entrance(RR_DMC_UPPER_NEARBY, []{return logic->Hearts() >= 3;}), + Entrance(RR_DMC_LOWER_NEARBY, []{return logic->Hearts() >= 3 && (logic->CanUse(RG_HOVER_BOOTS) || (ctx->GetTrickOption(RT_DMC_BOULDER_JS) && logic->IsAdult && logic->CanUse(RG_MEGATON_HAMMER)) || (ctx->GetTrickOption(RT_DMC_BOULDER_SKIP) && logic->IsAdult));}), + }); + + areaTable[RR_DMC_LOWER_NEARBY] = Region("DMC Lower Nearby", "Death Mountain Crater", {RA_DEATH_MOUNTAIN_CRATER}, NO_DAY_NIGHT_CYCLE, {}, { + // Locations + LOCATION(RC_DMC_NEAR_GC_POT_1, logic->CanBreakPots()), + LOCATION(RC_DMC_NEAR_GC_POT_2, logic->CanBreakPots()), + LOCATION(RC_DMC_NEAR_GC_POT_3, logic->CanBreakPots()), + LOCATION(RC_DMC_NEAR_GC_POT_4, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_DMC_LOWER_LOCAL, []{return logic->FireTimer() >= 48;}), + Entrance(RR_GC_DARUNIAS_CHAMBER, []{return true;}), + Entrance(RR_DMC_GREAT_FAIRY_FOUNTAIN, []{return logic->CanUse(RG_MEGATON_HAMMER);}), + Entrance(RR_DMC_HAMMER_GROTTO, []{return logic->IsAdult && logic->CanUse(RG_MEGATON_HAMMER);}), + }); + + areaTable[RR_DMC_LOWER_LOCAL] = Region("DMC Lower Local", "Death Mountain Crater", {RA_DEATH_MOUNTAIN_CRATER}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_DMC_LOWER_NEARBY, []{return true;}), + Entrance(RR_DMC_LADDER_AREA_NEARBY, []{return logic->FireTimer() >= 8 || logic->Hearts() >= 3;}), + Entrance(RR_DMC_CENTRAL_NEARBY, []{return (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT)) && (logic->FireTimer() >= 8 || logic->Hearts() >= 3);}), + Entrance(RR_DMC_CENTRAL_LOCAL, []{return (logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT) || (logic->IsAdult && logic->CanShield() && ctx->GetTrickOption(RT_DMC_BOLERO_JUMP))) && logic->FireTimer() >= 24;}), + }); + + areaTable[RR_DMC_CENTRAL_NEARBY] = Region("DMC Central Nearby", "Death Mountain Crater", {RA_DEATH_MOUNTAIN_CRATER}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DMC_VOLCANO_FREESTANDING_POH, logic->IsAdult && logic->Hearts() >= 3 && (CanPlantBean(RR_DMC_CENTRAL_LOCAL) || (ctx->GetTrickOption(RT_DMC_HOVER_BEAN_POH) && logic->CanUse(RG_HOVER_BOOTS)))), + LOCATION(RC_SHEIK_IN_CRATER, logic->IsAdult && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)), + }, { + //Exits + Entrance(RR_DMC_CENTRAL_LOCAL, []{return logic->FireTimer() >= 48;}), + }); + + areaTable[RR_DMC_CENTRAL_LOCAL] = Region("DMC Central Local", "Death Mountain Crater", {RA_DEATH_MOUNTAIN_CRATER}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->BeanPlantFairy, []{return logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS) && (logic->FireTimer() >= 8 || logic->Hearts() >= 3);}), + }, { + //Locations + LOCATION(RC_DMC_GS_BEAN_PATCH, (logic->FireTimer() >= 8 || logic->Hearts() >= 3) && logic->CanSpawnSoilSkull() && logic->CanAttack()), + LOCATION(RC_DMC_NEAR_PLATFORM_RED_RUPEE, logic->IsChild), + LOCATION(RC_DMC_MIDDLE_PLATFORM_RED_RUPEE, logic->IsChild && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)), + LOCATION(RC_DMC_MIDDLE_PLATFORM_BLUE_RUPEE_1, logic->IsChild && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)), + LOCATION(RC_DMC_MIDDLE_PLATFORM_BLUE_RUPEE_2, logic->IsChild && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)), + LOCATION(RC_DMC_MIDDLE_PLATFORM_BLUE_RUPEE_3, logic->IsChild && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)), + LOCATION(RC_DMC_MIDDLE_PLATFORM_BLUE_RUPEE_4, logic->IsChild && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)), + LOCATION(RC_DMC_MIDDLE_PLATFORM_BLUE_RUPEE_5, logic->IsChild && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)), + LOCATION(RC_DMC_MIDDLE_PLATFORM_BLUE_RUPEE_6, logic->IsChild && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)), + LOCATION(RC_DMC_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS) && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)), + LOCATION(RC_DMC_BEAN_SPROUT_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS) && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)), + LOCATION(RC_DMC_BEAN_SPROUT_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS) && (logic->FireTimer() >= 8 || logic->Hearts() >= 3)), + }, { + //Exits + Entrance(RR_DMC_CENTRAL_NEARBY, []{return true;}), + Entrance(RR_DMC_LOWER_NEARBY, []{return (logic->IsAdult && CanPlantBean(RR_DMC_CENTRAL_LOCAL)) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_HOOKSHOT);}), + Entrance(RR_DMC_UPPER_NEARBY, []{return logic->IsAdult && CanPlantBean(RR_DMC_CENTRAL_LOCAL);}), + Entrance(RR_FIRE_TEMPLE_ENTRYWAY, []{return (logic->IsChild && logic->Hearts() >= 3 && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).IsNot(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF)) || (logic->IsAdult && logic->FireTimer() >= 24);}), + Entrance(RR_DMC_DISTANT_PLATFORM, []{return logic->FireTimer() >= 48 && logic->CanUse(RG_DISTANT_SCARECROW);}), + }); + + areaTable[RR_DMC_GREAT_FAIRY_FOUNTAIN] = Region("DMC Great Fairy Fountain", "DMC Great Fairy Fountain", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DMC_GREAT_FAIRY_REWARD, logic->CanUse(RG_ZELDAS_LULLABY)), + }, { + //Exits + Entrance(RR_DMC_LOWER_LOCAL, []{return true;}), + }); + + areaTable[RR_DMC_UPPER_GROTTO] = Region("DMC Upper Grotto", "DMC Upper Grotto", {}, NO_DAY_NIGHT_CYCLE, grottoEvents, { + //Locations + LOCATION(RC_DMC_UPPER_GROTTO_CHEST, true), + LOCATION(RC_DMC_UPPER_GROTTO_FISH, logic->HasBottle()), + LOCATION(RC_DMC_UPPER_GROTTO_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), + LOCATION(RC_DMC_UPPER_GROTTO_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_DMC_UPPER_GROTTO_GOSSIP_STONE, true), + LOCATION(RC_DMC_UPPER_GROTTO_BEEHIVE_LEFT, logic->CanBreakLowerBeehives()), + LOCATION(RC_DMC_UPPER_GROTTO_BEEHIVE_RIGHT, logic->CanBreakLowerBeehives()), + }, { + //Exits + Entrance(RR_DMC_UPPER_LOCAL, []{return true;}), + }); + + areaTable[RR_DMC_HAMMER_GROTTO] = Region("DMC Hammer Grotto", "DMC Hammer Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DMC_DEKU_SCRUB_GROTTO_LEFT, logic->CanStunDeku()), + LOCATION(RC_DMC_DEKU_SCRUB_GROTTO_RIGHT, logic->CanStunDeku()), + LOCATION(RC_DMC_DEKU_SCRUB_GROTTO_CENTER, logic->CanStunDeku()), + LOCATION(RC_DMC_HAMMER_GROTTO_BEEHIVE, logic->CanBreakUpperBeehives()), + }, { + //Exits + Entrance(RR_DMC_LOWER_LOCAL, []{return true;}), + }); + + areaTable[RR_DMC_DISTANT_PLATFORM] = Region("DMC Distant Platform", "Death Mountain Crater", {RA_DEATH_MOUNTAIN_CRATER}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DMC_DISTANT_PLATFORM_GREEN_RUPEE_1, logic->IsAdult), + LOCATION(RC_DMC_DISTANT_PLATFORM_GREEN_RUPEE_2, logic->IsAdult), + LOCATION(RC_DMC_DISTANT_PLATFORM_GREEN_RUPEE_3, logic->IsAdult), + LOCATION(RC_DMC_DISTANT_PLATFORM_GREEN_RUPEE_4, logic->IsAdult), + LOCATION(RC_DMC_DISTANT_PLATFORM_GREEN_RUPEE_5, logic->IsAdult), + LOCATION(RC_DMC_DISTANT_PLATFORM_GREEN_RUPEE_6, logic->IsAdult), + LOCATION(RC_DMC_DISTANT_PLATFORM_RED_RUPEE, logic->IsAdult), + }, { + //Exits + Entrance(RR_DMC_CENTRAL_LOCAL, []{return logic->FireTimer() >= 48 && logic->CanUse(RG_DISTANT_SCARECROW);}), + }); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/death_mountain_trail.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/death_mountain_trail.cpp new file mode 100644 index 000000000..d67086371 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/overworld/death_mountain_trail.cpp @@ -0,0 +1,100 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" + +using namespace Rando; + +void RegionTable_Init_DeathMountainTrail() { + areaTable[RR_DEATH_MOUNTAIN_TRAIL] = Region("Death Mountain", "Death Mountain", {RA_DEATH_MOUNTAIN_TRAIL}, DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->BeanPlantFairy, []{return logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS) && (logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET));}), + }, { + //Locations + LOCATION(RC_DMT_CHEST, logic->BlastOrSmash() || (ctx->GetTrickOption(RT_DMT_BOMBABLE) && logic->IsChild && logic->HasItem(RG_GORONS_BRACELET))), + LOCATION(RC_DMT_FREESTANDING_POH, logic->TakeDamage() || logic->CanUse(RG_HOVER_BOOTS) || (logic->IsAdult && CanPlantBean(RR_DEATH_MOUNTAIN_TRAIL) && (logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET)))), + LOCATION(RC_DMT_GS_BEAN_PATCH, logic->CanSpawnSoilSkull() && (logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET) || (ctx->GetTrickOption(RT_DMT_SOIL_GS) && (logic->TakeDamage() || logic->CanUse(RG_HOVER_BOOTS)) && logic->CanUse(RG_BOOMERANG)))), + LOCATION(RC_DMT_GS_NEAR_KAK, logic->BlastOrSmash()), + LOCATION(RC_DMT_GS_ABOVE_DODONGOS_CAVERN, logic->IsAdult && logic->AtNight && (logic->CanUse(RG_MEGATON_HAMMER) || (ctx->GetTrickOption(RT_DMT_HOOKSHOT_LOWER_GS) && logic->CanUse(RG_HOOKSHOT)) || (ctx->GetTrickOption(RT_DMT_BEAN_LOWER_GS) && CanPlantBean(RR_DEATH_MOUNTAIN_TRAIL)) || (ctx->GetTrickOption(RT_DMT_HOVERS_LOWER_GS) && logic->CanUse(RG_HOVER_BOOTS)) || ctx->GetTrickOption(RT_DMT_JS_LOWER_GS)) && logic->CanGetNightTimeGS()), + LOCATION(RC_DMT_BLUE_RUPEE, logic->IsChild && logic->BlastOrSmash()), + LOCATION(RC_DMT_RED_RUPEE, logic->IsChild && logic->BlastOrSmash()), + LOCATION(RC_DMT_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS) && (logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET))), + LOCATION(RC_DMT_BEAN_SPROUT_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS) && (logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET))), + LOCATION(RC_DMT_BEAN_SPROUT_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS) && (logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET))), + LOCATION(RC_DMT_FLAG_SUN_FAIRY, logic->CanUse(RG_SUNS_SONG)), + }, { + //Exits + Entrance(RR_KAK_BEHIND_GATE, []{return true;}), + Entrance(RR_GORON_CITY, []{return true;}), + Entrance(RR_DEATH_MOUNTAIN_SUMMIT, []{return Here(RR_DEATH_MOUNTAIN_TRAIL, []{return logic->BlastOrSmash();}) || (logic->IsAdult && ((CanPlantBean(RR_DEATH_MOUNTAIN_TRAIL) && logic->HasItem(RG_GORONS_BRACELET)) || (logic->CanUse(RG_HOVER_BOOTS) && ctx->GetTrickOption(RT_DMT_CLIMB_HOVERS))));}), + Entrance(RR_DODONGOS_CAVERN_ENTRYWAY, []{return logic->HasExplosives() || logic->HasItem(RG_GORONS_BRACELET) || logic->IsAdult;}), + Entrance(RR_DMT_STORMS_GROTTO, []{return logic->CanOpenStormsGrotto();}), + }); + + areaTable[RR_DEATH_MOUNTAIN_SUMMIT] = Region("Death Mountain Summit", "Death Mountain", {RA_DEATH_MOUNTAIN_TRAIL}, DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->GossipStoneFairy, []{return logic->CallGossipFairy();}), + EventAccess(&logic->BugRock, []{return logic->BugRock || logic->IsChild;}), + }, { + //Locations + LOCATION(RC_DMT_TRADE_BROKEN_SWORD, logic->IsAdult && logic->CanUse(RG_BROKEN_SWORD)), + LOCATION(RC_DMT_TRADE_EYEDROPS, logic->IsAdult && logic->CanUse(RG_EYEDROPS)), + LOCATION(RC_DMT_TRADE_CLAIM_CHECK, logic->IsAdult && logic->CanUse(RG_CLAIM_CHECK)), + LOCATION(RC_DMT_GS_FALLING_ROCKS_PATH, logic->IsAdult && logic->AtNight && (logic->CanUse(RG_MEGATON_HAMMER) || ctx->GetTrickOption(RT_DMT_UPPER_GS)) && logic->CanGetNightTimeGS()), + LOCATION(RC_DMT_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), + LOCATION(RC_DMT_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_DMT_GOSSIP_STONE, true), + }, { + //Exits + Entrance(RR_DEATH_MOUNTAIN_TRAIL, []{return true;}), + Entrance(RR_DMC_UPPER_LOCAL, []{return true;}), + Entrance(RR_DMT_OWL_FLIGHT, []{return logic->IsChild;}, false), + Entrance(RR_DMT_COW_GROTTO, []{return Here(RR_DEATH_MOUNTAIN_SUMMIT, []{return logic->BlastOrSmash();});}), + Entrance(RR_DMT_GREAT_FAIRY_FOUNTAIN, []{return Here(RR_DEATH_MOUNTAIN_SUMMIT, []{return logic->BlastOrSmash();});}), + }); + + areaTable[RR_DMT_OWL_FLIGHT] = Region("DMT Owl Flight", "Death Mountain", {RA_DEATH_MOUNTAIN_TRAIL}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_KAK_IMPAS_ROOFTOP, []{return true;}), + }); + + areaTable[RR_DMT_COW_GROTTO] = Region("DMT Cow Grotto", "DMT Cow Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DMT_COW_GROTTO_COW, logic->CanUse(RG_EPONAS_SONG)), + LOCATION(RC_DMT_COW_GROTTO_BEEHIVE, logic->CanBreakLowerBeehives()), + LOCATION(RC_DMT_COW_GROTTO_LEFT_HEART, true), + LOCATION(RC_DMT_COW_GROTTO_MIDDLE_LEFT_HEART, true), + LOCATION(RC_DMT_COW_GROTTO_MIDDLE_RIGHT_HEART, true), + LOCATION(RC_DMT_COW_GROTTO_RIGHT_HEART, true), + LOCATION(RC_DMT_COW_GROTTO_RUPEE_1, true), + LOCATION(RC_DMT_COW_GROTTO_RUPEE_2, true), + LOCATION(RC_DMT_COW_GROTTO_RUPEE_3, true), + LOCATION(RC_DMT_COW_GROTTO_RUPEE_4, true), + LOCATION(RC_DMT_COW_GROTTO_RUPEE_5, true), + LOCATION(RC_DMT_COW_GROTTO_RUPEE_6, true), + LOCATION(RC_DMT_COW_GROTTO_RED_RUPEE, true), + }, { + //Exits + Entrance(RR_DEATH_MOUNTAIN_SUMMIT, []{return true;}), + }); + + areaTable[RR_DMT_STORMS_GROTTO] = Region("DMT Storms Grotto", "DMT Storms Grotto", {}, NO_DAY_NIGHT_CYCLE, grottoEvents, { + //Locations + LOCATION(RC_DMT_STORMS_GROTTO_CHEST, true), + LOCATION(RC_DMT_STORMS_GROTTO_FISH, logic->HasBottle()), + LOCATION(RC_DMT_STORMS_GROTTO_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), + LOCATION(RC_DMT_STORMS_GROTTO_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_DMT_STORMS_GROTTO_GOSSIP_STONE, true), + LOCATION(RC_DMT_STORMS_GROTTO_BEEHIVE_LEFT, logic->CanBreakLowerBeehives()), + LOCATION(RC_DMT_STORMS_GROTTO_BEEHIVE_RIGHT, logic->CanBreakLowerBeehives()), + }, { + //Exits + Entrance(RR_DEATH_MOUNTAIN_TRAIL, []{return true;}), + }); + + areaTable[RR_DMT_GREAT_FAIRY_FOUNTAIN] = Region("DMT Great Fairy Fountain", "DMT Great Fairy Fountain", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DMT_GREAT_FAIRY_REWARD, logic->CanUse(RG_ZELDAS_LULLABY)), + }, { + //Exits + Entrance(RR_DEATH_MOUNTAIN_SUMMIT, []{return true;}), + }); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/desert_colossus.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/desert_colossus.cpp new file mode 100644 index 000000000..0ef2bbdfc --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/overworld/desert_colossus.cpp @@ -0,0 +1,77 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" + +using namespace Rando; + +void RegionTable_Init_DesertColossus() { + areaTable[RR_DESERT_COLOSSUS] = Region("Desert Colossus", "Desert Colossus", {RA_DESERT_COLOSSUS}, DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->FairyPond, []{return logic->FairyPond || logic->CanUse(RG_SONG_OF_STORMS);}), + EventAccess(&logic->BugRock, []{return true;}), + }, { + //Locations + LOCATION(RC_COLOSSUS_FREESTANDING_POH, logic->IsAdult && CanPlantBean(RR_DESERT_COLOSSUS)), + LOCATION(RC_COLOSSUS_GS_BEAN_PATCH, logic->CanSpawnSoilSkull() && logic->CanAttack()), + LOCATION(RC_COLOSSUS_GS_TREE, logic->IsAdult && logic->HookshotOrBoomerang() && logic->CanGetNightTimeGS()), + LOCATION(RC_COLOSSUS_GS_HILL, logic->IsAdult && ((CanPlantBean(RR_DESERT_COLOSSUS) && logic->CanAttack()) || logic->CanUse(RG_LONGSHOT) || (ctx->GetTrickOption(RT_COLOSSUS_GS) && logic->CanUse(RG_HOOKSHOT))) && logic->CanGetNightTimeGS()), + LOCATION(RC_COLOSSUS_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_COLOSSUS_BEAN_SPROUT_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_COLOSSUS_BEAN_SPROUT_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_COLOSSUS_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), + LOCATION(RC_COLOSSUS_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_COLOSSUS_GOSSIP_STONE, true), + }, { + //Exits + //You can kinda get the fairies without entering the water, but it relies on them cooperating and leevers are jerks. should be a trick + Entrance(RR_DESERT_COLOSSUS_OASIS, []{return logic->CanUse(RG_SONG_OF_STORMS) && (logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS));}), + Entrance(RR_COLOSSUS_GREAT_FAIRY_FOUNTAIN, []{return logic->HasExplosives();}), + Entrance(RR_SPIRIT_TEMPLE_ENTRYWAY, []{return true;}), + Entrance(RR_WASTELAND_NEAR_COLOSSUS, []{return true;}), + Entrance(RR_COLOSSUS_GROTTO, []{return logic->CanUse(RG_SILVER_GAUNTLETS);}), + }); + + //specifically the full oasis, after the fairies have spawned + areaTable[RR_DESERT_COLOSSUS_OASIS] = Region("Desert Colossus Oasis", "Desert Colossus", {RA_DESERT_COLOSSUS}, DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->FairyPond, []{return true;}), + }, { + //Locations + LOCATION(RC_COLOSSUS_OASIS_FAIRY_1, true), + LOCATION(RC_COLOSSUS_OASIS_FAIRY_2, true), + LOCATION(RC_COLOSSUS_OASIS_FAIRY_3, true), + LOCATION(RC_COLOSSUS_OASIS_FAIRY_4, true), + LOCATION(RC_COLOSSUS_OASIS_FAIRY_5, true), + LOCATION(RC_COLOSSUS_OASIS_FAIRY_6, true), + LOCATION(RC_COLOSSUS_OASIS_FAIRY_7, true), + LOCATION(RC_COLOSSUS_OASIS_FAIRY_8, true), + }, { + //Exits + Entrance(RR_DESERT_COLOSSUS, []{return true;}), + }); + + areaTable[RR_DESERT_COLOSSUS_OUTSIDE_TEMPLE] = Region("Desert Colossus From Spirit Entryway", "Desert Colossus", {RA_DESERT_COLOSSUS}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SHEIK_AT_COLOSSUS, true), + }, { + //Exist + Entrance(RR_DESERT_COLOSSUS, []{return true;}), + }); + + areaTable[RR_COLOSSUS_GREAT_FAIRY_FOUNTAIN] = Region("Colossus Great Fairy Fountain", "Colossus Great Fairy Fountain", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_COLOSSUS_GREAT_FAIRY_REWARD, logic->CanUse(RG_ZELDAS_LULLABY)), + }, { + //Exits + Entrance(RR_DESERT_COLOSSUS, []{return true;}), + }); + + areaTable[RR_COLOSSUS_GROTTO] = Region("Colossus Grotto", "Colossus Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_COLOSSUS_DEKU_SCRUB_GROTTO_REAR, logic->CanStunDeku()), + LOCATION(RC_COLOSSUS_DEKU_SCRUB_GROTTO_FRONT, logic->CanStunDeku()), + LOCATION(RC_COLOSSUS_GROTTO_BEEHIVE, logic->CanBreakUpperBeehives()), + }, { + //Exits + Entrance(RR_DESERT_COLOSSUS, []{return true;}), + }); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/gerudo_valley.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/gerudo_valley.cpp new file mode 100644 index 000000000..1c4714e52 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/overworld/gerudo_valley.cpp @@ -0,0 +1,108 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" + +using namespace Rando; + +void RegionTable_Init_GerudoValley() { + areaTable[RR_GERUDO_VALLEY] = Region("Gerudo Valley", "Gerudo Valley", {RA_GERUDO_VALLEY}, DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->BugRock, []{return logic->BugRock || logic->IsChild;}), + }, { + //Locations + LOCATION(RC_GV_GS_SMALL_BRIDGE, logic->IsChild && logic->HookshotOrBoomerang() && logic->CanGetNightTimeGS()), + }, { + //Exits + Entrance(RR_HYRULE_FIELD, []{return true;}), + Entrance(RR_GV_UPPER_STREAM, []{return true;}), + Entrance(RR_GV_CRATE_LEDGE, []{return logic->IsChild || logic->CanUse(RG_LONGSHOT);}), + Entrance(RR_GV_GROTTO_LEDGE, []{return true;}), + Entrance(RR_GV_FORTRESS_SIDE, []{return (logic->IsAdult && (logic->CanUse(RG_EPONA) || logic->CanUse(RG_LONGSHOT) || ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FREE) || logic->CarpenterRescue)) || (logic->IsChild && logic->CanUse(RG_HOOKSHOT));}), + }); + + areaTable[RR_GV_UPPER_STREAM] = Region("GV Upper Stream", "Gerudo Valley", {RA_GERUDO_VALLEY}, DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->GossipStoneFairy, []{return logic->CallGossipFairy();}), + EventAccess(&logic->BeanPlantFairy, []{return logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS);}), + }, { + //Locations + LOCATION(RC_GV_WATERFALL_FREESTANDING_POH, logic->IsChild || logic->HasItem(RG_BRONZE_SCALE)),//can use cucco as child + LOCATION(RC_GV_GS_BEAN_PATCH, logic->CanSpawnSoilSkull() && logic->CanAttack()), + LOCATION(RC_GV_COW, logic->IsChild && logic->CanUse(RG_EPONAS_SONG)), + LOCATION(RC_GV_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_GV_BEAN_SPROUT_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_GV_BEAN_SPROUT_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_GV_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), + LOCATION(RC_GV_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_GV_GOSSIP_STONE, true), + }, { + //Exits + Entrance(RR_GV_LOWER_STREAM, []{return true;}), + }); + + areaTable[RR_GV_LOWER_STREAM] = Region("GV Lower Stream", "Gerudo Valley", {RA_GERUDO_VALLEY}, DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_LAKE_HYLIA, []{return logic->IsChild || logic->HasItem(RG_BRONZE_SCALE);}),//can use cucco as child + }); + + areaTable[RR_GV_GROTTO_LEDGE] = Region("GV Grotto Ledge", "Gerudo Valley", {RA_GERUDO_VALLEY}, DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_GV_LOWER_STREAM, []{return true;}), + Entrance(RR_GV_OCTOROK_GROTTO, []{return logic->CanUse(RG_SILVER_GAUNTLETS);}), + Entrance(RR_GV_CRATE_LEDGE, []{return logic->CanUse(RG_LONGSHOT);}), + }); + + areaTable[RR_GV_CRATE_LEDGE] = Region("GV Crate Ledge", "Gerudo Valley", {RA_GERUDO_VALLEY}, DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GV_CRATE_FREESTANDING_POH, true), + }, { + //Exits + Entrance(RR_GV_UPPER_STREAM, []{return ctx->GetTrickOption(RT_DAMAGE_BOOST_SIMPLE) && logic->HasExplosives();}), + Entrance(RR_GV_LOWER_STREAM, []{return true;}), + }); + + areaTable[RR_GV_FORTRESS_SIDE] = Region("GV Fortress Side", "Gerudo Valley", {RA_GERUDO_VALLEY}, DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GV_CHEST, logic->IsAdult && logic->CanUse(RG_MEGATON_HAMMER)), + LOCATION(RC_GV_TRADE_SAW, logic->IsAdult && logic->CanUse(RG_POACHERS_SAW)), + LOCATION(RC_GV_GS_BEHIND_TENT, logic->IsAdult && logic->HookshotOrBoomerang() && logic->CanGetNightTimeGS()), + LOCATION(RC_GV_GS_PILLAR, logic->IsAdult && logic->HookshotOrBoomerang() && logic->CanGetNightTimeGS()), + }, { + //Exits + Entrance(RR_GERUDO_FORTRESS, []{return true;}), + Entrance(RR_GV_UPPER_STREAM, []{return true;}), + Entrance(RR_GERUDO_VALLEY, []{return logic->IsChild || logic->CanUse(RG_EPONA) || logic->CanUse(RG_LONGSHOT) || ctx->GetOption(RSK_GERUDO_FORTRESS).Is(RO_GF_CARPENTERS_FREE) || logic->CarpenterRescue;}), + Entrance(RR_GV_CARPENTER_TENT, []{return logic->IsAdult;}), + Entrance(RR_GV_STORMS_GROTTO, []{return logic->IsAdult && logic->CanOpenStormsGrotto();}), + Entrance(RR_GV_CRATE_LEDGE, []{return ctx->GetTrickOption(RT_DAMAGE_BOOST_SIMPLE) && logic->HasExplosives();}), + }); + + areaTable[RR_GV_CARPENTER_TENT] = Region("GV Carpenter Tent", "GV Carpenter Tent", {}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_GV_FORTRESS_SIDE, []{return true;}), + }); + + areaTable[RR_GV_OCTOROK_GROTTO] = Region("GV Octorok Grotto", "GV Octorok Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GV_OCTOROK_GROTTO_FRONT_LEFT_BLUE_RUPEE, logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG)), + LOCATION(RC_GV_OCTOROK_GROTTO_FRONT_RIGHT_BLUE_RUPEE, logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG)), + LOCATION(RC_GV_OCTOROK_GROTTO_BACK_BLUE_RUPEE, logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG)), + LOCATION(RC_GV_OCTOROK_GROTTO_FRONT_LEFT_GREEN_RUPEE, logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG)), + LOCATION(RC_GV_OCTOROK_GROTTO_FRONT_RIGHT_GREEN_RUPEE, logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG)), + LOCATION(RC_GV_OCTOROK_GROTTO_BACK_LEFT_GREEN_RUPEE, logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG)), + LOCATION(RC_GV_OCTOROK_GROTTO_BACK_RIGHT_GREEN_RUPEE, logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG)), + LOCATION(RC_GV_OCTOROK_GROTTO_RED_RUPEE, logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG)), + }, { + //Exits + Entrance(RR_GV_GROTTO_LEDGE, []{return true;}), + }); + + areaTable[RR_GV_STORMS_GROTTO] = Region("GV Storms Grotto", "GV Storms Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GV_DEKU_SCRUB_GROTTO_REAR, logic->CanStunDeku()), + LOCATION(RC_GV_DEKU_SCRUB_GROTTO_FRONT, logic->CanStunDeku()), + LOCATION(RC_GV_DEKU_SCRUB_GROTTO_BEEHIVE, logic->CanBreakUpperBeehives()), + }, { + //Exits + Entrance(RR_GV_FORTRESS_SIDE, []{return true;}), + }); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/goron_city.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/goron_city.cpp new file mode 100644 index 000000000..722402ae9 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/overworld/goron_city.cpp @@ -0,0 +1,111 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" + +using namespace Rando; + +void RegionTable_Init_GoronCity() { + areaTable[RR_GORON_CITY] = Region("Goron City", "Goron City", {RA_GORON_CITY}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->GossipStoneFairy, []{return logic->CallGossipFairyExceptSuns();}), + EventAccess(&logic->StickPot, []{return logic->StickPot || logic->IsChild;}), + EventAccess(&logic->BugRock, []{return logic->BugRock || (logic->BlastOrSmash() || logic->CanUse(RG_SILVER_GAUNTLETS));}), + EventAccess(&logic->GoronCityChildFire, []{return logic->GoronCityChildFire || (logic->IsChild && logic->CanUse(RG_DINS_FIRE));}), + EventAccess(&logic->GCWoodsWarpOpen, []{return logic->GCWoodsWarpOpen || (logic->BlastOrSmash() || logic->CanUse(RG_DINS_FIRE) || logic->CanUse(RG_FAIRY_BOW) || logic->HasItem(RG_GORONS_BRACELET) || logic->GoronCityChildFire);}), + EventAccess(&logic->GCDaruniasDoorOpenChild, []{return logic->GCDaruniasDoorOpenChild || (logic->IsChild && logic->CanUse(RG_ZELDAS_LULLABY));}), + EventAccess(&logic->StopGCRollingGoronAsAdult, []{return logic->StopGCRollingGoronAsAdult || (logic->IsAdult && (logic->HasItem(RG_GORONS_BRACELET) || logic->HasExplosives() || logic->CanUse(RG_FAIRY_BOW) || (ctx->GetTrickOption(RT_GC_LINK_GORON_DINS) && logic->CanUse(RG_DINS_FIRE))));}), + }, { + //Locations + LOCATION(RC_GC_MAZE_LEFT_CHEST, logic->CanUse(RG_MEGATON_HAMMER) || logic->CanUse(RG_SILVER_GAUNTLETS) || (ctx->GetTrickOption(RT_GC_LEFTMOST) && logic->HasExplosives() && logic->CanUse(RG_HOVER_BOOTS))), + LOCATION(RC_GC_MAZE_CENTER_CHEST, logic->BlastOrSmash() || logic->CanUse(RG_SILVER_GAUNTLETS)), + LOCATION(RC_GC_MAZE_RIGHT_CHEST, logic->BlastOrSmash() || logic->CanUse(RG_SILVER_GAUNTLETS)), + LOCATION(RC_GC_POT_FREESTANDING_POH, logic->IsChild && logic->GoronCityChildFire && (logic->CanUse(RG_BOMB_BAG) || (logic->HasItem(RG_GORONS_BRACELET) && ctx->GetTrickOption(RT_GC_POT_STRENGTH)) || (logic->CanUse(RG_BOMBCHU_5) && ctx->GetTrickOption(RT_GC_POT)))), + LOCATION(RC_GC_ROLLING_GORON_AS_CHILD, logic->IsChild && (logic->HasExplosives() || (logic->HasItem(RG_GORONS_BRACELET) && ctx->GetTrickOption(RT_GC_ROLLING_STRENGTH)))), + LOCATION(RC_GC_ROLLING_GORON_AS_ADULT, logic->StopGCRollingGoronAsAdult), + LOCATION(RC_GC_GS_BOULDER_MAZE, logic->IsChild && logic->BlastOrSmash()), + LOCATION(RC_GC_GS_CENTER_PLATFORM, logic->IsAdult && logic->CanAttack()), + LOCATION(RC_GC_MEDIGORON, logic->IsAdult && (logic->CanBreakMudWalls() || logic->HasItem(RG_GORONS_BRACELET))), + LOCATION(RC_GC_MAZE_GOSSIP_STONE_FAIRY, (logic->BlastOrSmash() || logic->CanUse(RG_SILVER_GAUNTLETS)) && logic->CallGossipFairyExceptSuns()), + LOCATION(RC_GC_MAZE_GOSSIP_STONE_FAIRY_BIG, (logic->BlastOrSmash() || logic->CanUse(RG_SILVER_GAUNTLETS)) && logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_GC_MAZE_GOSSIP_STONE, logic->BlastOrSmash() || logic->CanUse(RG_SILVER_GAUNTLETS)), + LOCATION(RC_GC_LOWER_STAIRCASE_POT_1, logic->CanBreakPots()), + LOCATION(RC_GC_LOWER_STAIRCASE_POT_2, logic->CanBreakPots()), + LOCATION(RC_GC_UPPER_STAIRCASE_POT_1, logic->CanBreakPots()), + LOCATION(RC_GC_UPPER_STAIRCASE_POT_2, logic->CanBreakPots()), + LOCATION(RC_GC_UPPER_STAIRCASE_POT_3, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_DEATH_MOUNTAIN_TRAIL, []{return true;}), + Entrance(RR_GC_MEDIGORON, []{return logic->CanBreakMudWalls() || logic->HasItem(RG_GORONS_BRACELET);}), + Entrance(RR_GC_WOODS_WARP, []{return logic->GCWoodsWarpOpen;}), + Entrance(RR_GC_SHOP, []{return (logic->IsAdult && logic->StopGCRollingGoronAsAdult) || (logic->IsChild && (logic->BlastOrSmash() || logic->HasItem(RG_GORONS_BRACELET) || logic->GoronCityChildFire || logic->CanUse(RG_FAIRY_BOW)));}), + Entrance(RR_GC_DARUNIAS_CHAMBER, []{return (logic->IsAdult && logic->StopGCRollingGoronAsAdult) || (logic->IsChild && logic->GCDaruniasDoorOpenChild);}), + Entrance(RR_GC_GROTTO_PLATFORM, []{return logic->IsAdult && ((logic->CanUse(RG_SONG_OF_TIME) && ((logic->EffectiveHealth() > 2) || logic->CanUse(RG_GORON_TUNIC) || logic->CanUse(RG_LONGSHOT) || logic->CanUse(RG_NAYRUS_LOVE))) || (logic->EffectiveHealth() > 1 && logic->CanUse(RG_GORON_TUNIC) && logic->CanUse(RG_HOOKSHOT)) || (logic->CanUse(RG_NAYRUS_LOVE) && logic->CanUse(RG_HOOKSHOT)) || (logic->EffectiveHealth() > 2 && logic->CanUse(RG_HOOKSHOT) && ctx->GetTrickOption(RT_GC_GROTTO)));}), + }); + + areaTable[RR_GC_MEDIGORON] = Region("GC Medigoron", "Goron City", {RA_GORON_CITY}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GC_MEDIGORON_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns()), + LOCATION(RC_GC_MEDIGORON_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_GC_MEDIGORON_GOSSIP_STONE, true), + LOCATION(RC_GC_MEDIGORON_POT_1, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_GORON_CITY, []{return true;}), + }); + + areaTable[RR_GC_WOODS_WARP] = Region("GC Woods Warp", "Goron City", {RA_GORON_CITY}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->GCWoodsWarpOpen, []{return logic->GCWoodsWarpOpen || (logic->BlastOrSmash() || logic->CanUse(RG_DINS_FIRE));}), + }, {}, { + //Exits + Entrance(RR_GORON_CITY, []{return logic->CanLeaveForest() && logic->GCWoodsWarpOpen;}), + Entrance(RR_THE_LOST_WOODS, []{return true;}), + }); + + areaTable[RR_GC_DARUNIAS_CHAMBER] = Region("GC Darunias Chamber", "Goron City", {RA_GORON_CITY}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->GoronCityChildFire, []{return logic->GoronCityChildFire || (logic->IsChild && logic->CanUse(RG_STICKS));}), + }, { + //Locations + LOCATION(RC_GC_DARUNIAS_JOY, logic->IsChild && logic->CanUse(RG_SARIAS_SONG)), + LOCATION(RC_GC_DARUNIA_POT_1, logic->CanBreakPots()), + LOCATION(RC_GC_DARUNIA_POT_2, logic->CanBreakPots()), + LOCATION(RC_GC_DARUNIA_POT_3, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_GORON_CITY, []{return true;}), + Entrance(RR_DMC_LOWER_LOCAL, []{return logic->IsAdult;}), + }); + + areaTable[RR_GC_GROTTO_PLATFORM] = Region("GC Grotto Platform", "Goron City", {RA_GORON_CITY}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_GC_GROTTO, []{return true;}), + Entrance(RR_GORON_CITY, []{return logic->EffectiveHealth() > 2 || logic->CanUse(RG_GORON_TUNIC) || logic->CanUse(RG_NAYRUS_LOVE) || ((logic->IsChild || logic->CanUse(RG_SONG_OF_TIME)) && logic->CanUse(RG_LONGSHOT));}), + }); + + areaTable[RR_GC_SHOP] = Region("GC Shop", "GC Shop", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GC_SHOP_ITEM_1, true), + LOCATION(RC_GC_SHOP_ITEM_2, true), + LOCATION(RC_GC_SHOP_ITEM_3, true), + LOCATION(RC_GC_SHOP_ITEM_4, true), + LOCATION(RC_GC_SHOP_ITEM_5, true), + LOCATION(RC_GC_SHOP_ITEM_6, true), + LOCATION(RC_GC_SHOP_ITEM_7, true), + LOCATION(RC_GC_SHOP_ITEM_8, true), + }, { + //Exits + Entrance(RR_GORON_CITY, []{return true;}), + }); + + areaTable[RR_GC_GROTTO] = Region("GC Grotto", "GC Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GC_DEKU_SCRUB_GROTTO_LEFT, logic->CanStunDeku()), + LOCATION(RC_GC_DEKU_SCRUB_GROTTO_RIGHT, logic->CanStunDeku()), + LOCATION(RC_GC_DEKU_SCRUB_GROTTO_CENTER, logic->CanStunDeku()), + LOCATION(RC_GC_GROTTO_BEEHIVE, logic->CanBreakUpperBeehives()), + }, { + //Exits + Entrance(RR_GC_GROTTO_PLATFORM, []{return true;}), + }); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/graveyard.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/graveyard.cpp new file mode 100644 index 000000000..d6ded1312 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/overworld/graveyard.cpp @@ -0,0 +1,122 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" + +using namespace Rando; + +void RegionTable_Init_Graveyard() { + areaTable[RR_THE_GRAVEYARD] = Region("The Graveyard", "The Graveyard", {RA_THE_GRAVEYARD}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->ButterflyFairy, []{return logic->ButterflyFairy || (logic->CanUse(RG_STICKS) && logic->AtDay);}), + EventAccess(&logic->BeanPlantFairy, []{return logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS);}), + EventAccess(&logic->BugRock, []{return true;}), + }, { + //Locations + LOCATION(RC_GRAVEYARD_FREESTANDING_POH, (logic->IsAdult && CanPlantBean(RR_THE_GRAVEYARD)) || logic->CanUse(RG_LONGSHOT) || (ctx->GetTrickOption(RT_GY_POH) && logic->CanUse(RG_BOOMERANG))), + LOCATION(RC_GRAVEYARD_DAMPE_GRAVEDIGGING_TOUR, logic->HasItem(RG_CHILD_WALLET) && logic->IsChild && logic->AtNight), //TODO: This needs to change + LOCATION(RC_GRAVEYARD_GS_WALL, logic->IsChild && logic->HookshotOrBoomerang() && logic->AtNight && logic->CanGetNightTimeGS()), + LOCATION(RC_GRAVEYARD_GS_BEAN_PATCH, logic->CanSpawnSoilSkull() && logic->CanAttack()), + LOCATION(RC_GRAVEYARD_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_GRAVEYARD_BEAN_SPROUT_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_GRAVEYARD_BEAN_SPROUT_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), + }, { + //Exits + Entrance(RR_GRAVEYARD_SHIELD_GRAVE, []{return logic->IsAdult || logic->AtNight;}), + Entrance(RR_GRAVEYARD_COMPOSERS_GRAVE, []{return logic->CanUse(RG_ZELDAS_LULLABY);}), + Entrance(RR_GRAVEYARD_HEART_PIECE_GRAVE, []{return logic->IsAdult || logic->AtNight;}), + Entrance(RR_GRAVEYARD_DAMPES_GRAVE, []{return logic->IsAdult;}), + Entrance(RR_GRAVEYARD_DAMPES_HOUSE, []{return logic->IsAdult /*|| logic->AtDampeTime*/;}), //TODO: This needs to be handled in ToD rework + Entrance(RR_KAKARIKO_VILLAGE, []{return true;}), + Entrance(RR_GRAVEYARD_WARP_PAD_REGION, []{return false;}), + }); + + areaTable[RR_GRAVEYARD_SHIELD_GRAVE] = Region("Graveyard Shield Grave", "Graveyard Shield Grave", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GRAVEYARD_SHIELD_GRAVE_CHEST, true), + }, { + //Exits + Entrance(RR_THE_GRAVEYARD, []{return true;}), + Entrance(RR_GRAVEYARD_SHIELD_GRAVE_BACK, []{return Here(RR_GRAVEYARD_SHIELD_GRAVE, []{return logic->CanBreakMudWalls();});}), + }); + + areaTable[RR_GRAVEYARD_SHIELD_GRAVE_BACK] = Region("Graveyard Shield Grave Back", "Graveyard Shield Grave", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GRAVEYARD_SHIELD_GRAVE_FAIRY_1, true), + LOCATION(RC_GRAVEYARD_SHIELD_GRAVE_FAIRY_2, true), + LOCATION(RC_GRAVEYARD_SHIELD_GRAVE_FAIRY_3, true), + LOCATION(RC_GRAVEYARD_SHIELD_GRAVE_FAIRY_4, true), + LOCATION(RC_GRAVEYARD_SHIELD_GRAVE_FAIRY_5, true), + LOCATION(RC_GRAVEYARD_SHIELD_GRAVE_FAIRY_6, true), + LOCATION(RC_GRAVEYARD_SHIELD_GRAVE_FAIRY_7, true), + LOCATION(RC_GRAVEYARD_SHIELD_GRAVE_FAIRY_8, true), + }, { + //Exits + Entrance(RR_THE_GRAVEYARD, []{return true;}), + }); + + areaTable[RR_GRAVEYARD_HEART_PIECE_GRAVE] = Region("Graveyard Heart Piece Grave", "Graveyard Heart Piece Grave", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GRAVEYARD_HEART_PIECE_GRAVE_CHEST, logic->CanUse(RG_SUNS_SONG)), + }, { + //Exits + Entrance(RR_THE_GRAVEYARD, []{return true;}), + }); + + areaTable[RR_GRAVEYARD_COMPOSERS_GRAVE] = Region("Graveyard Composers Grave", "Graveyard Composers Grave", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GRAVEYARD_ROYAL_FAMILYS_TOMB_CHEST, logic->HasFireSource()), + LOCATION(RC_SONG_FROM_ROYAL_FAMILYS_TOMB, logic->CanUseProjectile() || logic->CanJumpslash()), + }, { + //Exits + Entrance(RR_THE_GRAVEYARD, []{return true;}), + }); + + areaTable[RR_GRAVEYARD_DAMPES_GRAVE] = Region("Graveyard Dampes Grave", "Windmill and Dampes Grave", {}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->NutPot, []{return true;}), + EventAccess(&logic->DampesWindmillAccess, []{return logic->DampesWindmillAccess || (logic->IsAdult && logic->CanUse(RG_SONG_OF_TIME));}), + }, { + //Locations + LOCATION(RC_GRAVEYARD_HOOKSHOT_CHEST, true), + LOCATION(RC_GRAVEYARD_DAMPE_RACE_FREESTANDING_POH, logic->IsAdult || ctx->GetTrickOption(RT_GY_CHILD_DAMPE_RACE_POH)), + LOCATION(RC_GY_DAMPES_GRAVE_POT_1, logic->CanBreakPots()), + LOCATION(RC_GY_DAMPES_GRAVE_POT_2, logic->CanBreakPots()), + LOCATION(RC_GY_DAMPES_GRAVE_POT_3, logic->CanBreakPots()), + LOCATION(RC_GY_DAMPES_GRAVE_POT_4, logic->CanBreakPots()), + LOCATION(RC_GY_DAMPES_GRAVE_POT_5, logic->CanBreakPots()), + LOCATION(RC_GY_DAMPES_GRAVE_POT_6, logic->CanBreakPots()), + LOCATION(RC_GRAVEYARD_DAMPE_RACE_RUPEE_1, true), + LOCATION(RC_GRAVEYARD_DAMPE_RACE_RUPEE_2, true), + LOCATION(RC_GRAVEYARD_DAMPE_RACE_RUPEE_3, true), + LOCATION(RC_GRAVEYARD_DAMPE_RACE_RUPEE_4, true), + LOCATION(RC_GRAVEYARD_DAMPE_RACE_RUPEE_5, true), + LOCATION(RC_GRAVEYARD_DAMPE_RACE_RUPEE_6, true), + LOCATION(RC_GRAVEYARD_DAMPE_RACE_RUPEE_7, true), + LOCATION(RC_GRAVEYARD_DAMPE_RACE_RUPEE_8, true), + }, { + //Exits + Entrance(RR_THE_GRAVEYARD, []{return true;}), + Entrance(RR_KAK_WINDMILL, []{return logic->IsAdult && logic->CanUse(RG_SONG_OF_TIME);}, false), + }); + + areaTable[RR_GRAVEYARD_DAMPES_HOUSE] = Region("Graveyard Dampes House", "Graveyard Dampes House", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DAMPE_HINT, logic->IsAdult), + }, { + //Exits + Entrance(RR_THE_GRAVEYARD, []{return true;}), + }); + + areaTable[RR_GRAVEYARD_WARP_PAD_REGION] = Region("Graveyard Warp Pad Region", "Graveyard", {RA_THE_GRAVEYARD}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->GossipStoneFairy, []{return logic->CallGossipFairyExceptSuns();}), + }, { + //Locations + LOCATION(RC_GRAVEYARD_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns()), + LOCATION(RC_GRAVEYARD_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_GRAVEYARD_GOSSIP_STONE, true), + }, { + //Exits + Entrance(RR_THE_GRAVEYARD, []{return true;}), + Entrance(RR_SHADOW_TEMPLE_ENTRYWAY, []{return logic->CanUse(RG_DINS_FIRE) || (ctx->GetTrickOption(RT_GY_SHADOW_FIRE_ARROWS) && logic->IsAdult && logic->CanUse(RG_FIRE_ARROWS));}), + }); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/haunted_wasteland.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/haunted_wasteland.cpp new file mode 100644 index 000000000..60e616f76 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/overworld/haunted_wasteland.cpp @@ -0,0 +1,38 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" + +using namespace Rando; + +void RegionTable_Init_HauntedWasteland() { + areaTable[RR_WASTELAND_NEAR_FORTRESS] = Region("Wasteland Near Fortress", "Haunted Wasteland", {RA_HAUNTED_WASTELAND}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_GF_OUTSIDE_GATE, []{return true;}), + Entrance(RR_HAUNTED_WASTELAND, []{return logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_LONGSHOT) || ctx->GetTrickOption(RT_HW_CROSSING);}), + }); + + areaTable[RR_HAUNTED_WASTELAND] = Region("Haunted Wasteland", "Haunted Wasteland", {RA_HAUNTED_WASTELAND}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->FairyPot, []{return true;}), + EventAccess(&logic->NutPot, []{return true;}), + EventAccess(&logic->CarpetMerchant, []{return logic->HasItem(RG_ADULT_WALLET) && CanBuyAnother(RC_WASTELAND_BOMBCHU_SALESMAN) && (logic->CanJumpslashExceptHammer() || logic->CanUse(RG_HOVER_BOOTS));}), + }, { + //Locations + LOCATION(RC_WASTELAND_CHEST, logic->HasFireSource()), + LOCATION(RC_WASTELAND_BOMBCHU_SALESMAN, logic->CanJumpslashExceptHammer() || logic->CanUse(RG_HOVER_BOOTS)), + LOCATION(RC_WASTELAND_GS, logic->HookshotOrBoomerang()), + LOCATION(RC_WASTELAND_NEAR_GS_POT_1, logic->CanBreakPots()), + LOCATION(RC_WASTELAND_NEAR_GS_POT_2, logic->CanBreakPots()), + LOCATION(RC_WASTELAND_NEAR_GS_POT_3, logic->CanBreakPots()), + LOCATION(RC_WASTELAND_NEAR_GS_POT_4, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_WASTELAND_NEAR_COLOSSUS, []{return ctx->GetTrickOption(RT_LENS_HW) || logic->CanUse(RG_LENS_OF_TRUTH);}), + Entrance(RR_WASTELAND_NEAR_FORTRESS, []{return logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_LONGSHOT) || ctx->GetTrickOption(RT_HW_CROSSING);}), + }); + + areaTable[RR_WASTELAND_NEAR_COLOSSUS] = Region("Wasteland Near Colossus", "Haunted Wasteland", {RA_HAUNTED_WASTELAND}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_DESERT_COLOSSUS, []{return true;}), + Entrance(RR_HAUNTED_WASTELAND, []{return ctx->GetTrickOption(RT_HW_REVERSE) || false;}), + }); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/hyrule_field.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/hyrule_field.cpp new file mode 100644 index 000000000..d73c09162 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/overworld/hyrule_field.cpp @@ -0,0 +1,143 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" + +using namespace Rando; + +void RegionTable_Init_HyruleField() { + areaTable[RR_HYRULE_FIELD] = Region("Hyrule Field", "Hyrule Field", {RA_HYRULE_FIELD}, DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->BigPoeKill, []{return logic->CanUse(RG_FAIRY_BOW) && logic->CanUse(RG_EPONA) && logic->HasBottle();}), + }, { + //Locations + LOCATION(RC_HF_OCARINA_OF_TIME_ITEM, logic->IsChild && logic->StoneCount() == 3 && logic->HasItem(RG_BRONZE_SCALE)), + LOCATION(RC_SONG_FROM_OCARINA_OF_TIME, logic->IsChild && logic->StoneCount() == 3 && logic->HasItem(RG_BRONZE_SCALE)), + LOCATION(RC_HF_POND_STORMS_FAIRY, logic->CanUse(RG_SONG_OF_STORMS)), + }, { + //Exits + Entrance(RR_LW_BRIDGE, []{return true;}), + Entrance(RR_LAKE_HYLIA, []{return true;}), + Entrance(RR_GERUDO_VALLEY, []{return true;}), + Entrance(RR_MARKET_ENTRANCE, []{return true;}), + Entrance(RR_KAKARIKO_VILLAGE, []{return true;}), + Entrance(RR_ZR_FRONT, []{return true;}), + Entrance(RR_LON_LON_RANCH, []{return true;}), + Entrance(RR_HF_SOUTHEAST_GROTTO, []{return Here(RR_HYRULE_FIELD, []{return logic->BlastOrSmash();});}), + Entrance(RR_HF_OPEN_GROTTO, []{return true;}), + Entrance(RR_HF_INSIDE_FENCE_GROTTO, []{return logic->CanOpenBombGrotto();}), + Entrance(RR_HF_COW_GROTTO, []{return (logic->CanUse(RG_MEGATON_HAMMER) || logic->IsChild) && logic->CanOpenBombGrotto();}), + Entrance(RR_HF_NEAR_MARKET_GROTTO, []{return Here(RR_HYRULE_FIELD, []{return logic->BlastOrSmash();});}), + Entrance(RR_HF_FAIRY_GROTTO, []{return Here(RR_HYRULE_FIELD, []{return logic->BlastOrSmash();});}), + Entrance(RR_HF_NEAR_KAK_GROTTO, []{return logic->CanOpenBombGrotto();}), + Entrance(RR_HF_TEKTITE_GROTTO, []{return logic->CanOpenBombGrotto();}), + }); + + areaTable[RR_HF_SOUTHEAST_GROTTO] = Region("HF Southeast Grotto", "HF Southeast Grotto", {}, NO_DAY_NIGHT_CYCLE, grottoEvents, { + //Locations + LOCATION(RC_HF_SOUTHEAST_GROTTO_CHEST, true), + LOCATION(RC_HF_SOUTHEAST_GROTTO_FISH, logic->HasBottle()), + LOCATION(RC_HF_SOUTHEAST_GROTTO_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), + LOCATION(RC_HF_SOUTHEAST_GROTTO_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_HF_SOUTHEAST_GROTTO_GOSSIP_STONE, true), + LOCATION(RC_HF_SOUTHEAST_GROTTO_BEEHIVE_LEFT, logic->CanBreakLowerBeehives()), + LOCATION(RC_HF_SOUTHEAST_GROTTO_BEEHIVE_RIGHT, logic->CanBreakLowerBeehives()), + }, { + //Exits + Entrance(RR_HYRULE_FIELD, []{return true;}), + }); + + areaTable[RR_HF_OPEN_GROTTO] = Region("HF Open Grotto", "HF Open Grotto", {}, NO_DAY_NIGHT_CYCLE, grottoEvents, { + //Locations + LOCATION(RC_HF_OPEN_GROTTO_CHEST, true), + LOCATION(RC_HF_OPEN_GROTTO_FISH, logic->HasBottle()), + LOCATION(RC_HF_OPEN_GROTTO_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), + LOCATION(RC_HF_OPEN_GROTTO_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_HF_OPEN_GROTTO_GOSSIP_STONE, true), + LOCATION(RC_HF_OPEN_GROTTO_BEEHIVE_LEFT, logic->CanBreakLowerBeehives()), + LOCATION(RC_HF_OPEN_GROTTO_BEEHIVE_RIGHT, logic->CanBreakLowerBeehives()), + }, { + //Exits + Entrance(RR_HYRULE_FIELD, []{return true;}), + }); + + areaTable[RR_HF_INSIDE_FENCE_GROTTO] = Region("HF Inside Fence Grotto", "HF Inside Fence Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_HF_DEKU_SCRUB_GROTTO, logic->CanStunDeku()), + LOCATION(RC_HF_INSIDE_FENCE_GROTTO_BEEHIVE, logic->CanBreakLowerBeehives()), + LOCATION(RC_HF_FENCE_GROTTO_STORMS_FAIRY, logic->CanUse(RG_SONG_OF_STORMS)), + }, { + //Exits + Entrance(RR_HYRULE_FIELD, []{return true;}), + }); + + areaTable[RR_HF_COW_GROTTO] = Region("HF Cow Grotto", "HF Cow Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_HYRULE_FIELD, []{return true;}), + Entrance(RR_HF_COW_GROTTO_BEHIND_WEBS, []{return logic->HasFireSource();}), + }); + + areaTable[RR_HF_COW_GROTTO_BEHIND_WEBS] = Region("HF Cow Grotto Behind Webs", "HF Cow Grotto", {}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->BugShrub, []{return logic->CanCutShrubs();}), + EventAccess(&logic->GossipStoneFairy, []{return logic->CallGossipFairy();}), + }, { + //Locations + LOCATION(RC_HF_GS_COW_GROTTO, logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG)), + LOCATION(RC_HF_COW_GROTTO_COW, logic->CanUse(RG_EPONAS_SONG)), + LOCATION(RC_HF_COW_GROTTO_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), + LOCATION(RC_HF_COW_GROTTO_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_HF_COW_GROTTO_GOSSIP_STONE, true), + LOCATION(RC_HF_COW_GROTTO_POT_1, logic->CanBreakPots()), + LOCATION(RC_HF_COW_GROTTO_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_HF_COW_GROTTO, []{return true;}), + }); + + areaTable[RR_HF_NEAR_MARKET_GROTTO] = Region("HF Near Market Grotto", "HF Near Market Grotto", {}, NO_DAY_NIGHT_CYCLE, grottoEvents, { + //Locations + LOCATION(RC_HF_NEAR_MARKET_GROTTO_CHEST, true), + LOCATION(RC_HF_NEAR_MARKET_GROTTO_FISH, logic->HasBottle()), + LOCATION(RC_HF_NEAR_MARKET_GROTTO_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), + LOCATION(RC_HF_NEAR_MARKET_GROTTO_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_HF_NEAR_MARKET_GROTTO_GOSSIP_STONE, true), + LOCATION(RC_HF_NEAR_MARKET_GROTTO_BEEHIVE_LEFT, logic->CanBreakLowerBeehives()), + LOCATION(RC_HF_NEAR_MARKET_GROTTO_BEEHIVE_RIGHT, logic->CanBreakLowerBeehives()), + }, { + //Exits + Entrance(RR_HYRULE_FIELD, []{return true;}), + }); + + areaTable[RR_HF_FAIRY_GROTTO] = Region("HF Fairy Grotto", "HF Fairy Grotto", {}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->FreeFairies, []{return true;}), + }, { + //Locations + LOCATION(RC_HF_FAIRY_GROTTO_FAIRY_1, true), + LOCATION(RC_HF_FAIRY_GROTTO_FAIRY_2, true), + LOCATION(RC_HF_FAIRY_GROTTO_FAIRY_3, true), + LOCATION(RC_HF_FAIRY_GROTTO_FAIRY_4, true), + LOCATION(RC_HF_FAIRY_GROTTO_FAIRY_5, true), + LOCATION(RC_HF_FAIRY_GROTTO_FAIRY_6, true), + LOCATION(RC_HF_FAIRY_GROTTO_FAIRY_7, true), + LOCATION(RC_HF_FAIRY_GROTTO_FAIRY_8, true), + }, { + //Exits + Entrance(RR_HYRULE_FIELD, []{return true;}), + }); + + areaTable[RR_HF_NEAR_KAK_GROTTO] = Region("HF Near Kak Grotto", "HF Near Kak Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_HF_GS_NEAR_KAK_GROTTO, logic->HookshotOrBoomerang()), + }, { + //Exits + Entrance(RR_HYRULE_FIELD, []{return true;}), + }); + + areaTable[RR_HF_TEKTITE_GROTTO] = Region("HF Tektite Grotto", "HF Tektite Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_HF_TEKTITE_GROTTO_FREESTANDING_POH, logic->HasItem(RG_GOLDEN_SCALE) || logic->CanUse(RG_IRON_BOOTS)), + }, { + //Exits + Entrance(RR_HYRULE_FIELD, []{return true;}), + }); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/kakariko.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/kakariko.cpp new file mode 100644 index 000000000..7d22f30a0 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/overworld/kakariko.cpp @@ -0,0 +1,242 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" + +using namespace Rando; + +void RegionTable_Init_Kakariko() { + areaTable[RR_KAKARIKO_VILLAGE] = Region("Kakariko Village", "Kakariko Village", {RA_KAKARIKO_VILLAGE}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->BugRock, []{return true;}), + //Open Gate setting is applies in RR_ROOT + EventAccess(&logic->KakarikoVillageGateOpen, []{return logic->IsChild && logic->HasItem(RG_ZELDAS_LETTER);}), + }, { + //Locations + LOCATION(RC_SHEIK_IN_KAKARIKO, logic->IsAdult && logic->HasItem(RG_FOREST_MEDALLION) && logic->HasItem(RG_FIRE_MEDALLION) && logic->HasItem(RG_WATER_MEDALLION)), + LOCATION(RC_KAK_ANJU_AS_CHILD, logic->IsChild && logic->AtDay), + LOCATION(RC_KAK_ANJU_AS_ADULT, logic->IsAdult && logic->AtDay), + LOCATION(RC_KAK_TRADE_POCKET_CUCCO, logic->IsAdult && logic->AtDay && (logic->CanUse(RG_POCKET_EGG) && logic->WakeUpAdultTalon)), + //Can kill lower kak skulls with pots + LOCATION(RC_KAK_GS_HOUSE_UNDER_CONSTRUCTION, logic->IsChild && logic->CanGetNightTimeGS()), + LOCATION(RC_KAK_GS_SKULLTULA_HOUSE, logic->IsChild && logic->CanGetNightTimeGS()), + LOCATION(RC_KAK_GS_GUARDS_HOUSE, logic->IsChild && logic->CanGetNightTimeGS()), + LOCATION(RC_KAK_GS_TREE, logic->IsChild && logic->CanGetNightTimeGS()), + LOCATION(RC_KAK_GS_WATCHTOWER, logic->IsChild && (logic->CanKillEnemy(RE_GOLD_SKULLTULA, ED_LONGSHOT) || (ctx->GetTrickOption(RT_KAK_TOWER_GS) && logic->CanJumpslashExceptHammer())) && logic->CanGetNightTimeGS()), + LOCATION(RC_KAK_NEAR_POTION_SHOP_POT_1, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_KAK_NEAR_POTION_SHOP_POT_2, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_KAK_NEAR_POTION_SHOP_POT_3, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_KAK_NEAR_IMPAS_HOUSE_POT_1, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_KAK_NEAR_IMPAS_HOUSE_POT_2, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_KAK_NEAR_IMPAS_HOUSE_POT_3, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_KAK_NEAR_GUARDS_HOUSE_POT_1, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_KAK_NEAR_GUARDS_HOUSE_POT_2, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_KAK_NEAR_GUARDS_HOUSE_POT_3, logic->IsChild && logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_HYRULE_FIELD, []{return true;}), + Entrance(RR_KAK_CARPENTER_BOSS_HOUSE, []{return true;}), + Entrance(RR_KAK_HOUSE_OF_SKULLTULA, []{return true;}), + Entrance(RR_KAK_IMPAS_HOUSE, []{return true;}), + Entrance(RR_KAK_WINDMILL, []{return true;}), + Entrance(RR_KAK_BAZAAR, []{return logic->IsAdult && logic->AtDay;}), + Entrance(RR_KAK_SHOOTING_GALLERY, []{return logic->IsAdult && logic->AtDay;}), + Entrance(RR_KAK_WELL, []{return logic->IsAdult || logic->DrainWell || logic->CanUse(RG_IRON_BOOTS);}), + Entrance(RR_KAK_POTION_SHOP_FRONT, []{return logic->AtDay || logic->IsChild;}), + Entrance(RR_KAK_REDEAD_GROTTO, []{return logic->CanOpenBombGrotto();}), + Entrance(RR_KAK_IMPAS_LEDGE, []{return (logic->IsChild && logic->AtDay) || (logic->IsAdult && ctx->GetTrickOption(RT_VISIBLE_COLLISION));}), + Entrance(RR_KAK_WATCHTOWER, []{return logic->IsAdult || logic->AtDay || logic->CanKillEnemy(RE_GOLD_SKULLTULA, ED_LONGSHOT) || (ctx->GetTrickOption(RT_KAK_TOWER_GS) && logic->CanJumpslashExceptHammer());}), + Entrance(RR_KAK_ROOFTOP, []{return logic->CanUse(RG_HOOKSHOT) || (ctx->GetTrickOption(RT_KAK_MAN_ON_ROOF) && logic->IsAdult);}), + Entrance(RR_KAK_IMPAS_ROOFTOP, []{return logic->CanUse(RG_HOOKSHOT) || (ctx->GetTrickOption(RT_KAK_ROOFTOP_GS) && logic->CanUse(RG_HOVER_BOOTS));}), + Entrance(RR_THE_GRAVEYARD, []{return true;}), + Entrance(RR_KAK_BEHIND_GATE, []{return logic->IsAdult || logic->KakarikoVillageGateOpen;}), + //adult can jump from the fence near the windmill to ledgegrab the fence near granny's shop. is in logic on N64 + Entrance(RR_KAK_BACKYARD, []{return logic->IsAdult || logic->AtDay;}), + }); + + areaTable[RR_KAK_IMPAS_LEDGE] = Region("Kak Impas Ledge", "Kakariko Village", {RA_KAKARIKO_VILLAGE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_KAK_IMPAS_HOUSE_BACK, []{return true;}), + Entrance(RR_KAKARIKO_VILLAGE, []{return true;}), + }); + + areaTable[RR_KAK_IMPAS_ROOFTOP] = Region("Kak Impas Rooftop", "Kakariko Village", {RA_KAKARIKO_VILLAGE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_KAK_GS_ABOVE_IMPAS_HOUSE, logic->IsAdult && logic->CanGetNightTimeGS() && logic->CanKillEnemy(RE_GOLD_SKULLTULA)), + }, { + //Exits + Entrance(RR_KAK_IMPAS_LEDGE, []{return true;}), + Entrance(RR_KAKARIKO_VILLAGE, []{return true;}), + }); + + areaTable[RR_KAK_WATCHTOWER] = Region("Kak Watchtower", "Kakariko Village", {RA_KAKARIKO_VILLAGE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + //exists for when age change is in logic. + LOCATION(RC_KAK_GS_WATCHTOWER, logic->IsChild && logic->CanUse(RG_DINS_FIRE) && logic->CanGetNightTimeGS()), + }, { + //Exits + Entrance(RR_KAKARIKO_VILLAGE, []{return true;}), + Entrance(RR_KAK_ROOFTOP, []{return ctx->GetTrickOption(RT_KAK_MAN_ON_ROOF) && logic->IsChild;}), + }); + + areaTable[RR_KAK_ROOFTOP] = Region("Kak Rooftop", "Kakariko Village", {RA_KAKARIKO_VILLAGE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_KAK_MAN_ON_ROOF, true), + }, { + //Exits + Entrance(RR_KAK_BACKYARD, []{return true;}), + Entrance(RR_KAKARIKO_VILLAGE, []{return true;}), + }); + + areaTable[RR_KAK_BACKYARD] = Region("Kak Backyard", "Kakariko Village", {RA_KAKARIKO_VILLAGE}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + //There's probably a trick to get these with rang from the main region + LOCATION(RC_KAK_NEAR_MEDICINE_SHOP_POT_1, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_KAK_NEAR_MEDICINE_SHOP_POT_2, logic->IsChild && logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_KAKARIKO_VILLAGE, []{return true;}), + Entrance(RR_KAK_OPEN_GROTTO, []{return true;}), + Entrance(RR_KAK_ODD_POTION_BUILDING, []{return logic->IsAdult;}), + Entrance(RR_KAK_POTION_SHOP_BACK, []{return logic->IsAdult && logic->AtDay;}), + }); + + areaTable[RR_KAK_CARPENTER_BOSS_HOUSE] = Region("Kak Carpenter Boss House", "Kak Carpenter Boss House", {}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->WakeUpAdultTalon, []{return logic->IsAdult && logic->CanUse(RG_POCKET_EGG);}), + }, {}, { + //Exits + Entrance(RR_KAKARIKO_VILLAGE, []{return true;}), + }); + + areaTable[RR_KAK_HOUSE_OF_SKULLTULA] = Region("Kak House of Skulltula", "Kak House of Skulltula", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_KAK_10_GOLD_SKULLTULA_REWARD, logic->GetGSCount() >= 10), + LOCATION(RC_KAK_20_GOLD_SKULLTULA_REWARD, logic->GetGSCount() >= 20), + LOCATION(RC_KAK_30_GOLD_SKULLTULA_REWARD, logic->GetGSCount() >= 30), + LOCATION(RC_KAK_40_GOLD_SKULLTULA_REWARD, logic->GetGSCount() >= 40), + LOCATION(RC_KAK_50_GOLD_SKULLTULA_REWARD, logic->GetGSCount() >= 50), + LOCATION(RC_KAK_100_GOLD_SKULLTULA_REWARD, logic->GetGSCount() >= 100), + }, { + //Exits + Entrance(RR_KAKARIKO_VILLAGE, []{return true;}), + }); + + areaTable[RR_KAK_IMPAS_HOUSE] = Region("Kak Impas House", "Kak Impas House", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_KAK_IMPAS_HOUSE_COW, logic->CanUse(RG_EPONAS_SONG)), + }, { + //Exits + Entrance(RR_KAKARIKO_VILLAGE, []{return true;}), + }); + + areaTable[RR_KAK_IMPAS_HOUSE_BACK] = Region("Kak Impas House Back", "Kak Impas House", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_KAK_IMPAS_HOUSE_FREESTANDING_POH, true), + LOCATION(RC_KAK_IMPAS_HOUSE_COW, logic->CanUse(RG_EPONAS_SONG)), + }, { + //Exits + Entrance(RR_KAK_IMPAS_LEDGE, []{return true;}), + }); + + areaTable[RR_KAK_WINDMILL] = Region("Kak Windmill", "Windmill and Dampes Grave", {}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->DrainWell, []{return logic->DrainWell || (logic->IsChild && logic->CanUse(RG_SONG_OF_STORMS));}), + }, { + //Locations + LOCATION(RC_KAK_WINDMILL_FREESTANDING_POH, logic->CanUse(RG_BOOMERANG) || logic->DampesWindmillAccess || (logic->IsAdult && ctx->GetTrickOption(RT_KAK_ADULT_WINDMILL_POH)) || (logic->IsChild && logic->CanJumpslashExceptHammer() && ctx->GetTrickOption(RT_KAK_CHILD_WINDMILL_POH))), + LOCATION(RC_SONG_FROM_WINDMILL, logic->IsAdult && logic->HasItem(RG_FAIRY_OCARINA)), + }, { + //Exits + Entrance(RR_KAKARIKO_VILLAGE, []{return true;}), + }); + + areaTable[RR_KAK_BAZAAR] = Region("Kak Bazaar", "Kak Bazaar", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_KAK_BAZAAR_ITEM_1, true), + LOCATION(RC_KAK_BAZAAR_ITEM_2, true), + LOCATION(RC_KAK_BAZAAR_ITEM_3, true), + LOCATION(RC_KAK_BAZAAR_ITEM_4, true), + LOCATION(RC_KAK_BAZAAR_ITEM_5, true), + LOCATION(RC_KAK_BAZAAR_ITEM_6, true), + LOCATION(RC_KAK_BAZAAR_ITEM_7, true), + LOCATION(RC_KAK_BAZAAR_ITEM_8, true), + }, { + //Exits + Entrance(RR_KAKARIKO_VILLAGE, []{return true;}), + }); + + areaTable[RR_KAK_SHOOTING_GALLERY] = Region("Kak Shooting Gallery", "Kak Shooting Gallery", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_KAK_SHOOTING_GALLERY_REWARD, logic->HasItem(RG_CHILD_WALLET) && logic->IsAdult && logic->CanUse(RG_FAIRY_BOW)), + }, { + //Exits + Entrance(RR_KAKARIKO_VILLAGE, []{return true;}), + }); + + areaTable[RR_KAK_POTION_SHOP_FRONT] = Region("Kak Potion Shop Front", "Kak Potion Shop", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_KAK_POTION_SHOP_ITEM_1, logic->IsAdult), + LOCATION(RC_KAK_POTION_SHOP_ITEM_2, logic->IsAdult), + LOCATION(RC_KAK_POTION_SHOP_ITEM_3, logic->IsAdult), + LOCATION(RC_KAK_POTION_SHOP_ITEM_4, logic->IsAdult), + LOCATION(RC_KAK_POTION_SHOP_ITEM_5, logic->IsAdult), + LOCATION(RC_KAK_POTION_SHOP_ITEM_6, logic->IsAdult), + LOCATION(RC_KAK_POTION_SHOP_ITEM_7, logic->IsAdult), + LOCATION(RC_KAK_POTION_SHOP_ITEM_8, logic->IsAdult), + }, { + //Exits + Entrance(RR_KAKARIKO_VILLAGE, []{return true;}), + Entrance(RR_KAK_POTION_SHOP_BACK, []{return logic->IsAdult;}), + }); + + areaTable[RR_KAK_POTION_SHOP_BACK] = Region("Kak Potion Shop Back", "Kak Potion Shop", {}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_KAK_BACKYARD, []{return logic->IsAdult;}), + Entrance(RR_KAK_POTION_SHOP_FRONT, []{return true;}), + }); + + areaTable[RR_KAK_ODD_POTION_BUILDING] = Region("Kak Granny's Potion Shop", "Kak Granny's Potion Shop", {}, NO_DAY_NIGHT_CYCLE, { + //Events + // RANDOTODO blue pot access + }, { + //Locations + LOCATION(RC_KAK_TRADE_ODD_MUSHROOM, logic->IsAdult && logic->CanUse(RG_ODD_MUSHROOM)), + LOCATION(RC_KAK_GRANNYS_SHOP, logic->IsAdult && (logic->CanUse(RG_ODD_MUSHROOM) || logic->TradeQuestStep(RG_ODD_MUSHROOM))), + }, { + // Exits + Entrance(RR_KAK_BACKYARD, []{return true;}), + }); + + areaTable[RR_KAK_REDEAD_GROTTO] = Region("Kak Redead Grotto", "Kak Redead Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_KAK_REDEAD_GROTTO_CHEST, logic->CanKillEnemy(RE_REDEAD, ED_CLOSE, true, 2)), + }, { + //Exits + Entrance(RR_KAKARIKO_VILLAGE, []{return true;}), + }); + + areaTable[RR_KAK_OPEN_GROTTO] = Region("Kak Open Grotto", "Kak Open Grotto", {}, NO_DAY_NIGHT_CYCLE, grottoEvents, { + //Locations + LOCATION(RC_KAK_OPEN_GROTTO_CHEST, true), + LOCATION(RC_KAK_OPEN_GROTTO_FISH, logic->HasBottle()), + LOCATION(RC_KAK_OPEN_GROTTO_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), + LOCATION(RC_KAK_OPEN_GROTTO_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_KAK_OPEN_GROTTO_GOSSIP_STONE, true), + LOCATION(RC_KAK_OPEN_GROTTO_BEEHIVE_LEFT, logic->CanBreakLowerBeehives()), + LOCATION(RC_KAK_OPEN_GROTTO_BEEHIVE_RIGHT, logic->CanBreakLowerBeehives()), + }, { + //Exits + Entrance(RR_KAK_BACKYARD, []{return true;}), + }); + + areaTable[RR_KAK_BEHIND_GATE] = Region("Kak Behind Gate", "Kakariko Village", {RA_KAKARIKO_VILLAGE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_KAKARIKO_VILLAGE, []{return logic->IsAdult || ctx->GetTrickOption(RT_VISIBLE_COLLISION) || logic->KakarikoVillageGateOpen;}), + Entrance(RR_DEATH_MOUNTAIN_TRAIL, []{return true;}), + }); + + areaTable[RR_KAK_WELL] = Region("Kak Behind Gate", "Kakariko Village", {RA_KAKARIKO_VILLAGE}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_KAKARIKO_VILLAGE, []{return logic->IsAdult || logic->HasItem(RG_BRONZE_SCALE) || logic->DrainWell;}), + Entrance(RR_BOTTOM_OF_THE_WELL_ENTRYWAY, []{return logic->IsChild || (logic->DrainWell && ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).IsNot(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF));}), + }); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/kokiri_forest.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/kokiri_forest.cpp new file mode 100644 index 000000000..fd7c340de --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/overworld/kokiri_forest.cpp @@ -0,0 +1,152 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" + +using namespace Rando; + +void RegionTable_Init_KokiriForest() { + areaTable[RR_KOKIRI_FOREST] = Region("Kokiri Forest", "Kokiri Forest", {RA_KOKIRI_FOREST}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->BeanPlantFairy, []{return logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS);}), + EventAccess(&logic->GossipStoneFairy, []{return logic->CallGossipFairyExceptSuns();}), + EventAccess(&logic->ShowedMidoSwordAndShield, []{return logic->ShowedMidoSwordAndShield || (logic->IsChild && logic->CanUse(RG_KOKIRI_SWORD) && logic->CanUse(RG_DEKU_SHIELD));}), + }, { + //Locations + LOCATION(RC_KF_KOKIRI_SWORD_CHEST, logic->IsChild), + LOCATION(RC_KF_GS_KNOW_IT_ALL_HOUSE, logic->IsChild && logic->CanAttack() && (/*TODO: HasNightStart ||*/ logic->CanLeaveForest() || logic->CanUse(RG_SUNS_SONG)) && logic->CanGetNightTimeGS()), + LOCATION(RC_KF_GS_BEAN_PATCH, logic->CanSpawnSoilSkull() && logic->CanAttack()), + LOCATION(RC_KF_GS_HOUSE_OF_TWINS, logic->IsAdult && (logic->HookshotOrBoomerang() || (ctx->GetTrickOption(RT_KF_ADULT_GS) && logic->CanUse(RG_HOVER_BOOTS))) && logic->CanGetNightTimeGS()), + LOCATION(RC_KF_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_KF_BEAN_SPROUT_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_KF_BEAN_SPROUT_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_KF_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns()), + LOCATION(RC_KF_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_KF_BRIDGE_RUPEE, logic->IsChild), + LOCATION(RC_KF_BEHIND_MIDOS_RUPEE, logic->IsChild), + LOCATION(RC_KF_SOUTH_GRASS_WEST_RUPEE, logic->IsChild), + LOCATION(RC_KF_SOUTH_GRASS_EAST_RUPEE, logic->IsChild), + LOCATION(RC_KF_NORTH_GRASS_WEST_RUPEE, logic->IsChild), + LOCATION(RC_KF_NORTH_GRASS_EAST_RUPEE, logic->IsChild), + LOCATION(RC_KF_BOULDER_RUPEE_1, logic->IsChild), + LOCATION(RC_KF_BOULDER_RUPEE_2, logic->IsChild), + LOCATION(RC_KF_BEAN_RUPEE_1, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))), + LOCATION(RC_KF_BEAN_RUPEE_2, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))), + LOCATION(RC_KF_BEAN_RUPEE_3, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))), + LOCATION(RC_KF_BEAN_RUPEE_4, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))), + LOCATION(RC_KF_BEAN_RUPEE_5, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))), + LOCATION(RC_KF_BEAN_RUPEE_6, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))), + LOCATION(RC_KF_BEAN_RED_RUPEE, logic->IsAdult && (CanPlantBean(RR_KOKIRI_FOREST) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_BOOMERANG))), + LOCATION(RC_KF_SARIAS_ROOF_WEST_HEART, logic->IsChild), + LOCATION(RC_KF_SARIAS_ROOF_EAST_HEART, logic->IsChild), + LOCATION(RC_KF_SARIAS_ROOF_NORTH_HEART, logic->IsChild), + LOCATION(RC_KF_GOSSIP_STONE, true), + }, { + //Exits + Entrance(RR_KF_LINKS_HOUSE, []{return true;}), + Entrance(RR_KF_MIDOS_HOUSE, []{return true;}), + Entrance(RR_KF_SARIAS_HOUSE, []{return true;}), + Entrance(RR_KF_HOUSE_OF_TWINS, []{return true;}), + Entrance(RR_KF_KNOW_IT_ALL_HOUSE, []{return true;}), + Entrance(RR_KF_KOKIRI_SHOP, []{return true;}), + Entrance(RR_KF_OUTSIDE_DEKU_TREE, []{return (logic->IsAdult && (logic->CanPassEnemy(RE_BIG_SKULLTULA) || logic->ForestTempleClear)) || ctx->GetOption(RSK_FOREST).Is(RO_CLOSED_FOREST_OFF) || logic->ShowedMidoSwordAndShield;}), + Entrance(RR_THE_LOST_WOODS, []{return true;}), + Entrance(RR_LW_BRIDGE_FROM_FOREST, []{return logic->IsAdult || ctx->GetOption(RSK_FOREST).IsNot(RO_CLOSED_FOREST_ON) || logic->DekuTreeClear;}), + Entrance(RR_KF_STORMS_GROTTO, []{return logic->CanOpenStormsGrotto();}), + }); + + areaTable[RR_KF_OUTSIDE_DEKU_TREE] = Region("KF Outside Deku Tree", "Kokiri Forest", {RA_KOKIRI_FOREST}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->DekuBabaSticks, []{return logic->CanGetDekuBabaSticks();}), + EventAccess(&logic->DekuBabaNuts, []{return logic->CanGetDekuBabaNuts();}), + EventAccess(&logic->ShowedMidoSwordAndShield, []{return logic->ShowedMidoSwordAndShield || (logic->IsChild && logic->CanUse(RG_KOKIRI_SWORD) && logic->CanUse(RG_DEKU_SHIELD));}), + }, { + //Locations + LOCATION(RC_KF_DEKU_TREE_LEFT_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns()), + LOCATION(RC_KF_DEKU_TREE_LEFT_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_KF_DEKU_TREE_RIGHT_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns()), + LOCATION(RC_KF_DEKU_TREE_RIGHT_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_KF_DEKU_TREE_LEFT_GOSSIP_STONE, true), + LOCATION(RC_KF_DEKU_TREE_RIGHT_GOSSIP_STONE, true), + }, { + //Exits + Entrance(RR_DEKU_TREE_ENTRYWAY, []{return logic->IsChild || (ctx->GetOption(RSK_SHUFFLE_DUNGEON_ENTRANCES).IsNot(RO_DUNGEON_ENTRANCE_SHUFFLE_OFF) && (ctx->GetOption(RSK_FOREST).Is(RO_CLOSED_FOREST_OFF) || logic->ShowedMidoSwordAndShield));}), + Entrance(RR_KOKIRI_FOREST, []{return (logic->IsAdult && (logic->CanPassEnemy(RE_BIG_SKULLTULA) || logic->ForestTempleClear)) || ctx->GetOption(RSK_FOREST).Is(RO_CLOSED_FOREST_OFF) || logic->ShowedMidoSwordAndShield;}), + }); + + areaTable[RR_KF_LINKS_HOUSE] = Region("KF Link's House", "KF Link's House", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_KF_LINKS_HOUSE_COW, logic->IsAdult && logic->CanUse(RG_EPONAS_SONG) && logic->LinksCow), + LOCATION(RC_KF_LINKS_HOUSE_POT, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_KOKIRI_FOREST, []{return true;}) + }); + + areaTable[RR_KF_MIDOS_HOUSE] = Region("KF Mido's House", "KF Mido's House", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_KF_MIDOS_TOP_LEFT_CHEST, true), + LOCATION(RC_KF_MIDOS_TOP_RIGHT_CHEST, true), + LOCATION(RC_KF_MIDOS_BOTTOM_LEFT_CHEST, true), + LOCATION(RC_KF_MIDOS_BOTTOM_RIGHT_CHEST, true), + }, { + //Exits + Entrance(RR_KOKIRI_FOREST, []{return true;}), + }); + + areaTable[RR_KF_SARIAS_HOUSE] = Region("KF Saria's House", "KF Saria's House", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_KF_SARIAS_TOP_LEFT_HEART, true), + LOCATION(RC_KF_SARIAS_TOP_RIGHT_HEART, true), + LOCATION(RC_KF_SARIAS_BOTTOM_LEFT_HEART, true), + LOCATION(RC_KF_SARIAS_BOTTOM_RIGHT_HEART, true), + }, { + //Exits + Entrance(RR_KOKIRI_FOREST, []{return true;}), + }); + + areaTable[RR_KF_HOUSE_OF_TWINS] = Region("KF House of Twins", "KF House of Twins", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_KF_TWINS_HOUSE_POT_1, logic->CanBreakPots()), + LOCATION(RC_KF_TWINS_HOUSE_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_KOKIRI_FOREST, []{return true;}), + }); + + areaTable[RR_KF_KNOW_IT_ALL_HOUSE] = Region("KF Know It All House", "KF Know It All House", {}, NO_DAY_NIGHT_CYCLE, {}, { + // Locations + LOCATION(RC_KF_BROTHERS_HOUSE_POT_1, logic->CanBreakPots()), + LOCATION(RC_KF_BROTHERS_HOUSE_POT_2, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_KOKIRI_FOREST, []{return true;}), + }); + + areaTable[RR_KF_KOKIRI_SHOP] = Region("KF Kokiri Shop", "KF Kokiri Shop", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_KF_SHOP_ITEM_1, true), + LOCATION(RC_KF_SHOP_ITEM_2, true), + LOCATION(RC_KF_SHOP_ITEM_3, true), + LOCATION(RC_KF_SHOP_ITEM_4, true), + LOCATION(RC_KF_SHOP_ITEM_5, true), + LOCATION(RC_KF_SHOP_ITEM_6, true), + LOCATION(RC_KF_SHOP_ITEM_7, true), + LOCATION(RC_KF_SHOP_ITEM_8, true), + }, { + //Exits + Entrance(RR_KOKIRI_FOREST, []{return true;}), + }); + + areaTable[RR_KF_STORMS_GROTTO] = Region("KF Storms Grotto", "KF Storms Grotto", {}, NO_DAY_NIGHT_CYCLE, grottoEvents, { + //Locations + LOCATION(RC_KF_STORMS_GROTTO_CHEST, true), + LOCATION(RC_KF_STORMS_GROTTO_FISH, logic->HasBottle()), + LOCATION(RC_KF_STORMS_GROTTO_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), + LOCATION(RC_KF_STORMS_GROTTO_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_KF_STORMS_GROTTO_GOSSIP_STONE, true), + LOCATION(RC_KF_STORMS_GROTTO_BEEHIVE_LEFT, logic->CanBreakLowerBeehives()), + LOCATION(RC_KF_STORMS_GROTTO_BEEHIVE_RIGHT, logic->CanBreakLowerBeehives()), + }, { + //Exits + Entrance(RR_KOKIRI_FOREST, []{return true;}) + }); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/lake_hylia.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/lake_hylia.cpp new file mode 100644 index 000000000..148acad13 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/overworld/lake_hylia.cpp @@ -0,0 +1,131 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" + +using namespace Rando; + +void RegionTable_Init_LakeHylia() { + areaTable[RR_LAKE_HYLIA] = Region("Lake Hylia", "Lake Hylia", {RA_LAKE_HYLIA}, DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->GossipStoneFairy, []{return logic->CallGossipFairy();}), + EventAccess(&logic->BeanPlantFairy, []{return logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS);}), + EventAccess(&logic->ButterflyFairy, []{return logic->ButterflyFairy || logic->CanUse(RG_STICKS);}), + EventAccess(&logic->BugShrub, []{return logic->BugShrub || (logic->IsChild && logic->CanCutShrubs());}), + EventAccess(&logic->ChildScarecrow, []{return logic->ChildScarecrow || (logic->IsChild && logic->HasItem(RG_FAIRY_OCARINA) && logic->OcarinaButtons() >= 2);}), + EventAccess(&logic->AdultScarecrow, []{return logic->AdultScarecrow || (logic->IsAdult && logic->HasItem(RG_FAIRY_OCARINA) && logic->OcarinaButtons() >= 2);}), + }, { + //Locations + LOCATION(RC_LH_UNDERWATER_ITEM, logic->IsChild && logic->HasItem(RG_SILVER_SCALE)), + LOCATION(RC_LH_SUN, logic->IsAdult && ((logic->WaterTempleClear && logic->HasItem(RG_BRONZE_SCALE)) || logic->CanUse(RG_DISTANT_SCARECROW)) && logic->CanUse(RG_FAIRY_BOW)), + LOCATION(RC_LH_FREESTANDING_POH, logic->IsAdult && (logic->CanUse(RG_SCARECROW) || CanPlantBean(RR_LAKE_HYLIA))), + LOCATION(RC_LH_GS_BEAN_PATCH, logic->CanSpawnSoilSkull() && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA)), + LOCATION(RC_LH_GS_LAB_WALL, logic->IsChild && (logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA, ED_BOOMERANG) || (ctx->GetTrickOption(RT_LH_LAB_WALL_GS) && logic->CanJumpslashExceptHammer())) && logic->CanGetNightTimeGS()), + LOCATION(RC_LH_GS_SMALL_ISLAND, logic->IsChild && logic->CanGetEnemyDrop(RE_GOLD_SKULLTULA) && logic->CanGetNightTimeGS() && logic->HasItem(RG_BRONZE_SCALE)), + LOCATION(RC_LH_GS_TREE, logic->IsAdult && logic->CanUse(RG_LONGSHOT) && logic->CanGetNightTimeGS()), + LOCATION(RC_LH_FRONT_RUPEE, logic->IsChild && logic->HasItem(RG_BRONZE_SCALE)), + LOCATION(RC_LH_MIDDLE_RUPEE, logic->IsChild && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS))), + LOCATION(RC_LH_BACK_RUPEE, logic->IsChild && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS))), + LOCATION(RC_LH_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_LH_BEAN_SPROUT_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_LH_BEAN_SPROUT_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_LH_LAB_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), + LOCATION(RC_LH_LAB_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + //You can walk along the edge of the lake to get these without swimming, the fairy is created going backwards, which is convenient here + LOCATION(RC_LH_SOUTHEAST_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), + LOCATION(RC_LH_SOUTHEAST_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_LH_SOUTHWEST_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), + LOCATION(RC_LH_SOUTHWEST_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_LH_ISLAND_SUN_FAIRY, logic->CanUse(RG_SUNS_SONG) && ((logic->HasItem(RG_BRONZE_SCALE) && (logic->IsChild || logic->WaterTempleClear)) || logic->CanUse(RG_DISTANT_SCARECROW))), + LOCATION(RC_LH_LAB_GOSSIP_STONE, true), + LOCATION(RC_LH_SOUTHEAST_GOSSIP_STONE, true), + LOCATION(RC_LH_SOUTHWEST_GOSSIP_STONE, true), + }, { + //Exits + Entrance(RR_HYRULE_FIELD, []{return true;}), + Entrance(RR_ZORAS_DOMAIN, []{return logic->IsChild && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS));}), + Entrance(RR_LH_OWL_FLIGHT, []{return logic->IsChild;}), + Entrance(RR_LH_FISHING_ISLAND, []{return ((logic->IsChild || logic->WaterTempleClear) && logic->HasItem(RG_BRONZE_SCALE)) || (logic->IsAdult && (logic->CanUse(RG_SCARECROW) || CanPlantBean(RR_LAKE_HYLIA)));}), + Entrance(RR_LH_LAB, []{return true;}), + Entrance(RR_WATER_TEMPLE_ENTRYWAY, []{return logic->CanUse(RG_HOOKSHOT) && ((logic->CanUse(RG_IRON_BOOTS) || (ctx->GetTrickOption(RT_LH_WATER_HOOKSHOT) && logic->HasItem(RG_GOLDEN_SCALE))) || (logic->IsAdult && logic->CanUse(RG_LONGSHOT) && logic->HasItem(RG_GOLDEN_SCALE)));}), + Entrance(RR_LH_GROTTO, []{return true;}), + }); + + areaTable[RR_LH_FISHING_ISLAND] = Region("LH Fishing Island", "Lake Hylia", {RA_LAKE_HYLIA}, DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_LAKE_HYLIA, []{return logic->HasItem(RG_BRONZE_SCALE);}), + Entrance(RR_LH_FISHING_POND, []{return true;}), + }); + + areaTable[RR_LH_OWL_FLIGHT] = Region("LH Owl Flight", "Lake Hylia", {RA_LAKE_HYLIA}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_HYRULE_FIELD, []{return true;}, false), + }); + + areaTable[RR_LH_LAB] = Region("LH Lab", "LH Lab", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_LH_LAB_DIVE, logic->HasItem(RG_GOLDEN_SCALE) || (ctx->GetTrickOption(RT_LH_LAB_DIVING) && logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT))), + LOCATION(RC_LH_TRADE_FROG, logic->IsAdult && logic->CanUse(RG_EYEBALL_FROG)), + LOCATION(RC_LH_GS_LAB_CRATE, logic->CanUse(RG_IRON_BOOTS) && logic->CanUse(RG_HOOKSHOT)), + LOCATION(RC_LH_LAB_FRONT_RUPEE, logic->CanUse(RG_IRON_BOOTS) || logic->HasItem(RG_GOLDEN_SCALE)), + LOCATION(RC_LH_LAB_LEFT_RUPEE, logic->CanUse(RG_IRON_BOOTS) || logic->HasItem(RG_GOLDEN_SCALE)), + LOCATION(RC_LH_LAB_RIGHT_RUPEE, logic->CanUse(RG_IRON_BOOTS) || logic->HasItem(RG_GOLDEN_SCALE)), + }, { + //Exits + Entrance(RR_LAKE_HYLIA, []{return true;}), + }); + + // TODO: should some of these helpers be done via events instead? + areaTable[RR_LH_FISHING_POND] = Region("LH Fishing Hole", "LH Fishing Hole", {}, DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_LH_CHILD_FISHING, logic->CanUse(RG_FISHING_POLE) && logic->IsChild), + LOCATION(RC_LH_CHILD_FISH_1, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), + LOCATION(RC_LH_CHILD_FISH_2, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), + LOCATION(RC_LH_CHILD_FISH_3, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), + LOCATION(RC_LH_CHILD_FISH_4, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), + LOCATION(RC_LH_CHILD_FISH_5, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), + LOCATION(RC_LH_CHILD_FISH_6, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), + LOCATION(RC_LH_CHILD_FISH_7, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), + LOCATION(RC_LH_CHILD_FISH_8, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), + LOCATION(RC_LH_CHILD_FISH_9, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), + LOCATION(RC_LH_CHILD_FISH_10, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), + LOCATION(RC_LH_CHILD_FISH_11, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), + LOCATION(RC_LH_CHILD_FISH_12, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), + LOCATION(RC_LH_CHILD_FISH_13, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), + LOCATION(RC_LH_CHILD_FISH_14, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), + LOCATION(RC_LH_CHILD_FISH_15, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), + LOCATION(RC_LH_CHILD_LOACH_1, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), + LOCATION(RC_LH_CHILD_LOACH_2, logic->CanUse(RG_FISHING_POLE) && (logic->IsChild || !ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT))), + LOCATION(RC_LH_ADULT_FISHING, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult), + LOCATION(RC_LH_ADULT_FISH_1, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult && ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT)), + LOCATION(RC_LH_ADULT_FISH_2, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult && ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT)), + LOCATION(RC_LH_ADULT_FISH_3, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult && ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT)), + LOCATION(RC_LH_ADULT_FISH_4, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult && ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT)), + LOCATION(RC_LH_ADULT_FISH_5, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult && ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT)), + LOCATION(RC_LH_ADULT_FISH_6, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult && ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT)), + LOCATION(RC_LH_ADULT_FISH_7, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult && ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT)), + LOCATION(RC_LH_ADULT_FISH_8, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult && ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT)), + LOCATION(RC_LH_ADULT_FISH_9, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult && ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT)), + LOCATION(RC_LH_ADULT_FISH_10, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult && ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT)), + LOCATION(RC_LH_ADULT_FISH_11, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult && ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT)), + LOCATION(RC_LH_ADULT_FISH_12, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult && ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT)), + LOCATION(RC_LH_ADULT_FISH_13, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult && ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT)), + LOCATION(RC_LH_ADULT_FISH_14, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult && ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT)), + LOCATION(RC_LH_ADULT_FISH_15, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult && ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT)), + LOCATION(RC_LH_ADULT_LOACH, logic->CanUse(RG_FISHING_POLE) && logic->IsAdult && ctx->GetOption(RSK_FISHSANITY_AGE_SPLIT)), + LOCATION(RC_LH_HYRULE_LOACH, logic->CanUse(RG_FISHING_POLE)), + LOCATION(RC_FISHING_POLE_HINT, true), + }, { + //Exits + Entrance(RR_LH_FISHING_ISLAND, []{return true;}), + }); + + areaTable[RR_LH_GROTTO] = Region("LH Grotto", "LH Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_LH_DEKU_SCRUB_GROTTO_LEFT, logic->CanStunDeku()), + LOCATION(RC_LH_DEKU_SCRUB_GROTTO_RIGHT, logic->CanStunDeku()), + LOCATION(RC_LH_DEKU_SCRUB_GROTTO_CENTER, logic->CanStunDeku()), + LOCATION(RC_LH_GROTTO_BEEHIVE, logic->CanBreakUpperBeehives()), + }, { + //Exits + Entrance(RR_LAKE_HYLIA, []{return true;}), + }); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/lon_lon_ranch.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/lon_lon_ranch.cpp new file mode 100644 index 000000000..df73b78d9 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/overworld/lon_lon_ranch.cpp @@ -0,0 +1,74 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" + +using namespace Rando; + +void RegionTable_Init_LonLonRanch() { + areaTable[RR_LON_LON_RANCH] = Region("Lon Lon Ranch", "Lon Lon Ranch", {RA_LON_LON_RANCH}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->FreedEpona, []{return logic->FreedEpona || ((logic->HasItem(RG_CHILD_WALLET) || ctx->GetOption(RSK_SKIP_EPONA_RACE)) && logic->CanUse(RG_EPONAS_SONG) && logic->IsAdult && logic->AtDay);}), + EventAccess(&logic->LinksCow, []{return logic->LinksCow || (logic->HasItem(RG_CHILD_WALLET) && logic->CanUse(RG_EPONAS_SONG) && logic->IsAdult && logic->AtDay);}), + }, { + //Locations + LOCATION(RC_SONG_FROM_MALON, logic->IsChild && logic->HasItem(RG_ZELDAS_LETTER) && logic->HasItem(RG_FAIRY_OCARINA) && logic->AtDay), + LOCATION(RC_LLR_GS_TREE, logic->IsChild), + LOCATION(RC_LLR_GS_RAIN_SHED, logic->IsChild && logic->CanGetNightTimeGS()), + LOCATION(RC_LLR_GS_HOUSE_WINDOW, logic->IsChild && logic->HookshotOrBoomerang() && logic->CanGetNightTimeGS()), + LOCATION(RC_LLR_GS_BACK_WALL, logic->IsChild && logic->HookshotOrBoomerang() && logic->CanGetNightTimeGS()), + LOCATION(RC_LLR_FRONT_POT_1, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_LLR_FRONT_POT_2, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_LLR_FRONT_POT_3, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_LLR_FRONT_POT_4, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_LLR_RAIN_SHED_POT_1, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_LLR_RAIN_SHED_POT_2, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_LLR_RAIN_SHED_POT_3, logic->IsChild && logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_HYRULE_FIELD, []{return true;}), + Entrance(RR_LLR_TALONS_HOUSE, []{return true;}), + Entrance(RR_LLR_STABLES, []{return true;}), + Entrance(RR_LLR_TOWER, []{return true;}), + Entrance(RR_LLR_GROTTO, []{return logic->IsChild;}), + }); + + areaTable[RR_LLR_TALONS_HOUSE] = Region("LLR Talons House", "LLR Talons House", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_LLR_TALONS_CHICKENS, logic->HasItem(RG_CHILD_WALLET) && logic->IsChild && logic->AtDay && logic->HasItem(RG_ZELDAS_LETTER)), + LOCATION(RC_LLR_TALONS_HOUSE_POT_1, logic->CanBreakPots()), + LOCATION(RC_LLR_TALONS_HOUSE_POT_2, logic->CanBreakPots()), + LOCATION(RC_LLR_TALONS_HOUSE_POT_3, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_LON_LON_RANCH, []{return true;}), + }); + + areaTable[RR_LLR_STABLES] = Region("LLR Stables", "LLR Stables", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_LLR_STABLES_LEFT_COW, logic->CanUse(RG_EPONAS_SONG)), + LOCATION(RC_LLR_STABLES_RIGHT_COW, logic->CanUse(RG_EPONAS_SONG)), + }, { + //Exits + Entrance(RR_LON_LON_RANCH, []{return true;}), + }); + + areaTable[RR_LLR_TOWER] = Region("LLR Tower", "LLR Tower", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_LLR_FREESTANDING_POH, logic->IsChild), + LOCATION(RC_LLR_TOWER_LEFT_COW, logic->CanUse(RG_EPONAS_SONG)), + LOCATION(RC_LLR_TOWER_RIGHT_COW, logic->CanUse(RG_EPONAS_SONG)), + }, { + //Exits + Entrance(RR_LON_LON_RANCH, []{return true;}), + }); + + areaTable[RR_LLR_GROTTO] = Region("LLR Grotto", "LLR Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_LLR_DEKU_SCRUB_GROTTO_LEFT, logic->CanStunDeku()), + LOCATION(RC_LLR_DEKU_SCRUB_GROTTO_RIGHT, logic->CanStunDeku()), + LOCATION(RC_LLR_DEKU_SCRUB_GROTTO_CENTER, logic->CanStunDeku()), + LOCATION(RC_LLR_GROTTO_BEEHIVE, logic->CanBreakUpperBeehives()), + }, { + //Exits + Entrance(RR_LON_LON_RANCH, []{return true;}), + }); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/lost_woods.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/lost_woods.cpp new file mode 100644 index 000000000..6d38b05bd --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/overworld/lost_woods.cpp @@ -0,0 +1,130 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" + +using namespace Rando; + +void RegionTable_Init_LostWoods() { + areaTable[RR_LW_FOREST_EXIT] = Region("LW Forest Exit", "Lost Woods", {RA_THE_LOST_WOODS}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_KOKIRI_FOREST, []{return true;}) + }); + + areaTable[RR_THE_LOST_WOODS] = Region("Lost Woods", "Lost Woods", {RA_THE_LOST_WOODS}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->GossipStoneFairy, []{return logic->CallGossipFairyExceptSuns();}), + EventAccess(&logic->BeanPlantFairy, []{return logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS);}), + EventAccess(&logic->BugShrub, []{return logic->IsChild && logic->CanCutShrubs();}), + }, { + //Locations + LOCATION(RC_LW_SKULL_KID, logic->IsChild && logic->CanUse(RG_SARIAS_SONG)), + LOCATION(RC_LW_TRADE_COJIRO, logic->IsAdult && logic->CanUse(RG_COJIRO)), + //I cannot think of a case where you can use Odd pot but not Cojiro to reset the quadrant should you have both. If one exists, add it to logic + LOCATION(RC_LW_TRADE_ODD_POTION, logic->IsAdult && logic->CanUse(RG_ODD_POTION)), + //all 5 buttons are logically required for memory game + //because the chances of being able to beat it + //every time you attempt it are as follows: + //0 or 1 button(s) => 0% + //2 buttons => 0.15625% + //3 buttons => 3.75% + //4 buttons => 25.3125% + //5 buttons => 100% + LOCATION(RC_LW_OCARINA_MEMORY_GAME, logic->IsChild && logic->HasItem(RG_FAIRY_OCARINA) && logic->OcarinaButtons() >= 5), + LOCATION(RC_LW_TARGET_IN_WOODS, logic->IsChild && logic->CanUse(RG_FAIRY_SLINGSHOT)), + LOCATION(RC_LW_DEKU_SCRUB_NEAR_BRIDGE, logic->IsChild && logic->CanStunDeku()), + LOCATION(RC_LW_GS_BEAN_PATCH_NEAR_BRIDGE, logic->CanSpawnSoilSkull() && logic->CanAttack()), + //RANDOTODO handle collecting some of these as you leave the shortcut from the other side + LOCATION(RC_LW_SHORTCUT_RUPEE_1, logic->IsChild && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS))), + LOCATION(RC_LW_SHORTCUT_RUPEE_2, logic->IsChild && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS))), + LOCATION(RC_LW_SHORTCUT_RUPEE_3, logic->IsChild && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS))), + LOCATION(RC_LW_SHORTCUT_RUPEE_4, logic->IsChild && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS))), + LOCATION(RC_LW_SHORTCUT_RUPEE_5, logic->IsChild && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS))), + LOCATION(RC_LW_SHORTCUT_RUPEE_6, logic->IsChild && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS))), + LOCATION(RC_LW_SHORTCUT_RUPEE_7, logic->IsChild && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS))), + LOCATION(RC_LW_SHORTCUT_RUPEE_8, logic->IsChild && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS))), + LOCATION(RC_LW_BEAN_SPROUT_NEAR_BRIDGE_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_LW_BEAN_SPROUT_NEAR_BRIDGE_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_LW_BEAN_SPROUT_NEAR_BRIDGE_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_LW_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns()), + LOCATION(RC_LW_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_LW_SHORTCUT_STORMS_FAIRY, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_LW_GOSSIP_STONE, true), + }, { + //Exits + Entrance(RR_LW_FOREST_EXIT, []{return true;}), + Entrance(RR_GC_WOODS_WARP, []{return true;}), + Entrance(RR_LW_BRIDGE, []{return logic->CanLeaveForest() && ((logic->IsAdult && (CanPlantBean(RR_THE_LOST_WOODS) || ctx->GetTrickOption(RT_LW_BRIDGE))) || logic->CanUse(RG_HOVER_BOOTS) || logic->CanUse(RG_LONGSHOT));}), + Entrance(RR_ZORAS_RIVER, []{return logic->CanLeaveForest() && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS));}), + Entrance(RR_LW_BEYOND_MIDO, []{return logic->IsChild || logic->CanUse(RG_SARIAS_SONG) || ctx->GetTrickOption(RT_LW_MIDO_BACKFLIP);}), + Entrance(RR_LW_NEAR_SHORTCUTS_GROTTO, []{return Here(RR_THE_LOST_WOODS, []{return logic->BlastOrSmash();});}), + }); + + areaTable[RR_LW_BEYOND_MIDO] = Region("LW Beyond Mido", "Lost Woods", {RA_THE_LOST_WOODS}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->ButterflyFairy, []{return logic->ButterflyFairy || logic->CanUse(RG_STICKS);}), + }, { + //Locations + LOCATION(RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_RIGHT, logic->IsChild && logic->CanStunDeku()), + LOCATION(RC_LW_DEKU_SCRUB_NEAR_DEKU_THEATER_LEFT, logic->IsChild && logic->CanStunDeku()), + LOCATION(RC_LW_GS_ABOVE_THEATER, logic->IsAdult && ((CanPlantBean(RR_LW_BEYOND_MIDO) && logic->CanAttack()) || (ctx->GetTrickOption(RT_LW_GS_BEAN) && logic->CanUse(RG_HOOKSHOT) && (logic->CanUse(RG_LONGSHOT) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_BOMBCHU_5) || logic->CanUse(RG_DINS_FIRE)))) && logic->CanGetNightTimeGS()), + LOCATION(RC_LW_GS_BEAN_PATCH_NEAR_THEATER, logic->CanSpawnSoilSkull() && (logic->CanAttack() || (ctx->GetOption(RSK_SHUFFLE_SCRUBS).Is(RO_SCRUBS_OFF) && logic->CanReflectNuts()))), + LOCATION(RC_LW_BOULDER_RUPEE, logic->BlastOrSmash()), + LOCATION(RC_LW_BEAN_SPROUT_NEAR_THEATER_FAIRY_1, logic->IsChild && logic->HasItem(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_LW_BEAN_SPROUT_NEAR_THEATER_FAIRY_2, logic->IsChild && logic->HasItem(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_LW_BEAN_SPROUT_NEAR_THEATER_FAIRY_3, logic->IsChild && logic->HasItem(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), + }, { + //Exits + Entrance(RR_LW_FOREST_EXIT, []{return true;}), + Entrance(RR_THE_LOST_WOODS, []{return logic->IsChild || logic->CanUse(RG_SARIAS_SONG);}), + Entrance(RR_SFM_ENTRYWAY, []{return true;}), + Entrance(RR_DEKU_THEATER, []{return true;}), + Entrance(RR_LW_SCRUBS_GROTTO, []{return Here(RR_LW_BEYOND_MIDO, []{return logic->BlastOrSmash();});}), + }); + + areaTable[RR_LW_NEAR_SHORTCUTS_GROTTO] = Region("LW Near Shortcuts Grotto", "LW Near Shortcuts Grotto", {}, NO_DAY_NIGHT_CYCLE, grottoEvents, { + //Locations + LOCATION(RC_LW_NEAR_SHORTCUTS_GROTTO_CHEST, true), + LOCATION(RC_LW_NEAR_SHORTCUTS_GROTTO_FISH, logic->HasBottle()), + LOCATION(RC_LW_NEAR_SHORTCUTS_GROTTO_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), + LOCATION(RC_LW_NEAR_SHORTCUTS_GROTTO_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_LW_NEAR_SHORTCUTS_GROTTO_GOSSIP_STONE, true), + LOCATION(RC_LW_NEAR_SHORTCUTS_GROTTO_BEEHIVE_LEFT, logic->CanBreakLowerBeehives()), + LOCATION(RC_LW_NEAR_SHORTCUTS_GROTTO_BEEHIVE_RIGHT, logic->CanBreakLowerBeehives()), + }, { + //Exits + Entrance(RR_THE_LOST_WOODS, []{return true;}), + }); + + areaTable[RR_DEKU_THEATER] = Region("Deku Theater", "Deku Theater", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_DEKU_THEATER_SKULL_MASK, logic->IsChild && logic->SkullMask), + LOCATION(RC_DEKU_THEATER_MASK_OF_TRUTH, logic->IsChild && logic->MaskOfTruth), + }, { + //Exits + Entrance(RR_LW_BEYOND_MIDO, []{return true;}), + }); + + areaTable[RR_LW_SCRUBS_GROTTO] = Region("LW Scrubs Grotto", "LW Scrubs Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_LW_DEKU_SCRUB_GROTTO_REAR, logic->CanStunDeku()), + LOCATION(RC_LW_DEKU_SCRUB_GROTTO_FRONT, logic->CanStunDeku()), + LOCATION(RC_LW_DEKU_SCRUB_GROTTO_BEEHIVE, logic->CanBreakUpperBeehives()), + }, { + //Exits + Entrance(RR_LW_BEYOND_MIDO, []{return true;}), + }); + + areaTable[RR_LW_BRIDGE_FROM_FOREST] = Region("LW Bridge From Forest", "Lost Woods", {RA_THE_LOST_WOODS}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_LW_GIFT_FROM_SARIA, true), + }, { + //Exits + Entrance(RR_LW_BRIDGE, []{return true;}), + }); + + areaTable[RR_LW_BRIDGE] = Region("LW Bridge", "Lost Woods", {RA_THE_LOST_WOODS}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_KOKIRI_FOREST, []{return true;}), + Entrance(RR_HYRULE_FIELD, []{return true;}), + Entrance(RR_THE_LOST_WOODS, []{return logic->CanUse(RG_LONGSHOT);}), + }); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/market.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/market.cpp new file mode 100644 index 000000000..8a6991301 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/overworld/market.cpp @@ -0,0 +1,216 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" + +using namespace Rando; + +void RegionTable_Init_Market() { + areaTable[RR_MARKET_ENTRANCE] = Region("Market Entrance", "Market Entrance", {RA_THE_MARKET}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_HYRULE_FIELD, []{return logic->IsAdult || logic->AtDay;}), + Entrance(RR_THE_MARKET, []{return true;}), + Entrance(RR_MARKET_GUARD_HOUSE, []{return true;}), + }); + + areaTable[RR_THE_MARKET] = Region("Market", "Market", {RA_THE_MARKET}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_MARKET_ENTRANCE, []{return true;}), + Entrance(RR_TOT_ENTRANCE, []{return true;}), + Entrance(RR_CASTLE_GROUNDS, []{return true;}), + Entrance(RR_MARKET_BAZAAR, []{return logic->IsChild && logic->AtDay;}), + Entrance(RR_MARKET_MASK_SHOP, []{return logic->IsChild && logic->AtDay;}), + Entrance(RR_MARKET_SHOOTING_GALLERY, []{return logic->IsChild && logic->AtDay;}), + Entrance(RR_MARKET_BOMBCHU_BOWLING, []{return logic->IsChild;}), + Entrance(RR_MARKET_TREASURE_CHEST_GAME, []{return logic->IsChild && logic->AtNight;}), + Entrance(RR_MARKET_POTION_SHOP, []{return logic->IsChild && logic->AtDay;}), + Entrance(RR_MARKET_BACK_ALLEY, []{return logic->IsChild;}), + }); + + areaTable[RR_MARKET_BACK_ALLEY] = Region("Market Back Alley", "Market", {RA_THE_MARKET}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_THE_MARKET, []{return true;}), + Entrance(RR_MARKET_BOMBCHU_SHOP, []{return logic->AtNight;}), + Entrance(RR_MARKET_DOG_LADY_HOUSE, []{return true;}), + Entrance(RR_MARKET_MAN_IN_GREEN_HOUSE, []{return logic->AtNight;}), + }); + + areaTable[RR_MARKET_GUARD_HOUSE] = Region("Market Guard House", "Market Guard House", {}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->CanEmptyBigPoes, []{return logic->IsAdult;}), + }, { + //Locations + LOCATION(RC_MARKET_10_BIG_POES, logic->IsAdult && logic->BigPoeKill), + LOCATION(RC_MARKET_GS_GUARD_HOUSE, logic->IsChild), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_1, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_2, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_3, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_4, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_5, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_6, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_7, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_8, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_9, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_10, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_11, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_12, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_13, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_14, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_15, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_16, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_17, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_18, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_19, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_20, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_21, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_22, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_23, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_24, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_25, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_26, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_27, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_28, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_29, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_30, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_31, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_32, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_33, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_34, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_35, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_36, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_37, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_38, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_39, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_40, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_41, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_42, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_43, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_CHILD_POT_44, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_ADULT_POT_1, logic->IsAdult && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_ADULT_POT_2, logic->IsAdult && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_ADULT_POT_3, logic->IsAdult && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_ADULT_POT_4, logic->IsAdult && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_ADULT_POT_5, logic->IsAdult && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_ADULT_POT_6, logic->IsAdult && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_ADULT_POT_7, logic->IsAdult && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_ADULT_POT_8, logic->IsAdult && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_ADULT_POT_9, logic->IsAdult && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_ADULT_POT_10, logic->IsAdult && logic->CanBreakPots()), + LOCATION(RC_MK_GUARD_HOUSE_ADULT_POT_11, logic->IsAdult && logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_MARKET_ENTRANCE, []{return true;}), + }); + + areaTable[RR_MARKET_BAZAAR] = Region("Market Bazaar", "Market Bazaar", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_MARKET_BAZAAR_ITEM_1, true), + LOCATION(RC_MARKET_BAZAAR_ITEM_2, true), + LOCATION(RC_MARKET_BAZAAR_ITEM_3, true), + LOCATION(RC_MARKET_BAZAAR_ITEM_4, true), + LOCATION(RC_MARKET_BAZAAR_ITEM_5, true), + LOCATION(RC_MARKET_BAZAAR_ITEM_6, true), + LOCATION(RC_MARKET_BAZAAR_ITEM_7, true), + LOCATION(RC_MARKET_BAZAAR_ITEM_8, true), + }, { + //Exits + Entrance(RR_THE_MARKET, []{return true;}), + }); + + areaTable[RR_MARKET_MASK_SHOP] = Region("Market Mask Shop", "Market Mask Shop", {}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->SkullMask, []{return logic->SkullMask || (logic->HasItem(RG_ZELDAS_LETTER) && (ctx->GetOption(RSK_COMPLETE_MASK_QUEST) || ChildCanAccess(RR_KAKARIKO_VILLAGE)));}), //RANDOTODO Complete mask quest does not need this location, so should be tied to link's pocket + EventAccess(&logic->MaskOfTruth, []{return logic->MaskOfTruth || (logic->SkullMask && (ctx->GetOption(RSK_COMPLETE_MASK_QUEST) || (ChildCanAccess(RR_THE_LOST_WOODS) && logic->CanUse(RG_SARIAS_SONG) && RegionTable(RR_THE_GRAVEYARD)->childDay && ChildCanAccess(RR_HYRULE_FIELD) && logic->StoneCount() == 3)));}), + }, { + //Locations + LOCATION(RC_MASK_SHOP_HINT, true), + }, { + //Exits + Entrance(RR_THE_MARKET, []{return true;}), + }); + + areaTable[RR_MARKET_SHOOTING_GALLERY] = Region("Market Shooting Gallery", "Market Shooting Gallery", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_MARKET_SHOOTING_GALLERY_REWARD, logic->IsChild && logic->HasItem(RG_CHILD_WALLET)), + }, { + //Exits + Entrance(RR_THE_MARKET, []{return true;}), + }); + + areaTable[RR_MARKET_BOMBCHU_BOWLING] = Region("Market Bombchu Bowling", "Market Bombchu Bowling", {}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->CouldPlayBowling, []{return (logic->HasItem(RG_CHILD_WALLET));}), + }, { + //Locations + LOCATION(RC_MARKET_BOMBCHU_BOWLING_FIRST_PRIZE, logic->CouldPlayBowling && logic->BombchusEnabled()), + LOCATION(RC_MARKET_BOMBCHU_BOWLING_SECOND_PRIZE, logic->CouldPlayBowling && logic->BombchusEnabled()), + }, { + //Exits + Entrance(RR_THE_MARKET, []{return true;}), + }); + + areaTable[RR_MARKET_POTION_SHOP] = Region("Market Potion Shop", "Market Potion Shop", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_MARKET_POTION_SHOP_ITEM_1, true), + LOCATION(RC_MARKET_POTION_SHOP_ITEM_2, true), + LOCATION(RC_MARKET_POTION_SHOP_ITEM_3, true), + LOCATION(RC_MARKET_POTION_SHOP_ITEM_4, true), + LOCATION(RC_MARKET_POTION_SHOP_ITEM_5, true), + LOCATION(RC_MARKET_POTION_SHOP_ITEM_6, true), + LOCATION(RC_MARKET_POTION_SHOP_ITEM_7, true), + LOCATION(RC_MARKET_POTION_SHOP_ITEM_8, true), + }, { + //Exits + Entrance(RR_THE_MARKET, []{return true;}), + }); + + areaTable[RR_MARKET_TREASURE_CHEST_GAME] = Region("Market Treasure Chest Game", "Market Treasure Chest Game", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_GREG_HINT, logic->HasItem(RG_CHILD_WALLET)), + LOCATION(RC_MARKET_TREASURE_CHEST_GAME_REWARD, logic->HasItem(RG_CHILD_WALLET) && ((logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 6)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)))), + LOCATION(RC_MARKET_TREASURE_CHEST_GAME_KEY_1, logic->HasItem(RG_CHILD_WALLET) && ((ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)))), + LOCATION(RC_MARKET_TREASURE_CHEST_GAME_ITEM_1, logic->HasItem(RG_CHILD_WALLET) && ((ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)))), + LOCATION(RC_MARKET_TREASURE_CHEST_GAME_KEY_2, logic->HasItem(RG_CHILD_WALLET) && ((ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 2)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)))), + LOCATION(RC_MARKET_TREASURE_CHEST_GAME_ITEM_2, logic->HasItem(RG_CHILD_WALLET) && ((ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 2)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)))), + LOCATION(RC_MARKET_TREASURE_CHEST_GAME_KEY_3, logic->HasItem(RG_CHILD_WALLET) && ((ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 3)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)))), + LOCATION(RC_MARKET_TREASURE_CHEST_GAME_ITEM_3, logic->HasItem(RG_CHILD_WALLET) && ((ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 3)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)))), + LOCATION(RC_MARKET_TREASURE_CHEST_GAME_KEY_4, logic->HasItem(RG_CHILD_WALLET) && ((ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 4)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)))), + LOCATION(RC_MARKET_TREASURE_CHEST_GAME_ITEM_4, logic->HasItem(RG_CHILD_WALLET) && ((ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 4)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)))), + LOCATION(RC_MARKET_TREASURE_CHEST_GAME_KEY_5, logic->HasItem(RG_CHILD_WALLET) && ((ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 5)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)))), + LOCATION(RC_MARKET_TREASURE_CHEST_GAME_ITEM_5, logic->HasItem(RG_CHILD_WALLET) && ((ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_SINGLE_KEYS) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 5)) || (ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME).Is(RO_CHEST_GAME_PACK) && logic->SmallKeys(RR_MARKET_TREASURE_CHEST_GAME, 1)) || (logic->CanUse(RG_LENS_OF_TRUTH) && !ctx->GetOption(RSK_SHUFFLE_CHEST_MINIGAME)))), + }, { + //Exits + Entrance(RR_THE_MARKET, []{return true;}), + }); + + areaTable[RR_MARKET_BOMBCHU_SHOP] = Region("Market Bombchu Shop", "Market Bombchu Shop", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_MARKET_BOMBCHU_SHOP_ITEM_1, true), + LOCATION(RC_MARKET_BOMBCHU_SHOP_ITEM_2, true), + LOCATION(RC_MARKET_BOMBCHU_SHOP_ITEM_3, true), + LOCATION(RC_MARKET_BOMBCHU_SHOP_ITEM_4, true), + LOCATION(RC_MARKET_BOMBCHU_SHOP_ITEM_5, true), + LOCATION(RC_MARKET_BOMBCHU_SHOP_ITEM_6, true), + LOCATION(RC_MARKET_BOMBCHU_SHOP_ITEM_7, true), + LOCATION(RC_MARKET_BOMBCHU_SHOP_ITEM_8, true), + }, { + //Exits + Entrance(RR_MARKET_BACK_ALLEY, []{return true;}), + }); + + areaTable[RR_MARKET_DOG_LADY_HOUSE] = Region("Market Dog Lady House", "Market Dog Lady House", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_MARKET_LOST_DOG, logic->IsChild && logic->AtNight), + }, { + //Exits + Entrance(RR_MARKET_BACK_ALLEY, []{return true;}), + }); + + areaTable[RR_MARKET_MAN_IN_GREEN_HOUSE] = Region("Market Man in Green House", "Market Man in Green House", {}, NO_DAY_NIGHT_CYCLE, {}, { + // Locations + LOCATION(RC_MK_BACK_ALLEY_HOUSE_POT_1, logic->CanBreakPots()), + LOCATION(RC_MK_BACK_ALLEY_HOUSE_POT_2, logic->CanBreakPots()), + LOCATION(RC_MK_BACK_ALLEY_HOUSE_POT_3, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_MARKET_BACK_ALLEY, []{return true;}), + }); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/sacred_forest_meadow.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/sacred_forest_meadow.cpp new file mode 100644 index 000000000..ecc0577e2 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/overworld/sacred_forest_meadow.cpp @@ -0,0 +1,74 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" + +using namespace Rando; + +void RegionTable_Init_SacredForestMeadow() { + areaTable[RR_SFM_ENTRYWAY] = Region("SFM Entryway", "Sacred Forest Meadow", {RA_SACRED_FOREST_MEADOW}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_LW_BEYOND_MIDO, []{return true;}), + Entrance(RR_SACRED_FOREST_MEADOW, []{return logic->CanJumpslash() || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_FAIRY_BOW) || logic->CanUse(RG_DINS_FIRE);}), + Entrance(RR_SFM_WOLFOS_GROTTO, []{return logic->CanOpenBombGrotto();}), + }); + + areaTable[RR_SACRED_FOREST_MEADOW] = Region("Sacred Forest Meadow", "Sacred Forest Meadow", {RA_SACRED_FOREST_MEADOW}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->GossipStoneFairy, []{return logic->CallGossipFairyExceptSuns();}), + }, { + //Locations + LOCATION(RC_SONG_FROM_SARIA, logic->IsChild && logic->HasItem(RG_ZELDAS_LETTER)), + LOCATION(RC_SHEIK_IN_FOREST, logic->IsAdult), + LOCATION(RC_SFM_GS, logic->IsAdult && logic->HookshotOrBoomerang() && logic->CanGetNightTimeGS()), + LOCATION(RC_SFM_MAZE_LOWER_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns()), + LOCATION(RC_SFM_MAZE_LOWER_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_SFM_MAZE_UPPER_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns()), + LOCATION(RC_SFM_MAZE_UPPER_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_SFM_SARIA_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns()), + LOCATION(RC_SFM_SARIA_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_SFM_MAZE_LOWER_GOSSIP_STONE, true), + LOCATION(RC_SFM_MAZE_UPPER_GOSSIP_STONE, true), + LOCATION(RC_SFM_SARIA_GOSSIP_STONE, true), + }, { + //Exits + Entrance(RR_SFM_ENTRYWAY, []{return true;}), + Entrance(RR_FOREST_TEMPLE_ENTRYWAY, []{return logic->CanUse(RG_HOOKSHOT);}), + Entrance(RR_SFM_FAIRY_GROTTO, []{return true;}), + Entrance(RR_SFM_STORMS_GROTTO, []{return logic->CanOpenStormsGrotto();}), + }); + + areaTable[RR_SFM_FAIRY_GROTTO] = Region("SFM Fairy Grotto", "SFM Fairy Grotto", {}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->FreeFairies, []{return true;}), + }, { + //Locations + LOCATION(RC_SFM_FAIRY_GROTTO_FAIRY_1, true), + LOCATION(RC_SFM_FAIRY_GROTTO_FAIRY_2, true), + LOCATION(RC_SFM_FAIRY_GROTTO_FAIRY_3, true), + LOCATION(RC_SFM_FAIRY_GROTTO_FAIRY_4, true), + LOCATION(RC_SFM_FAIRY_GROTTO_FAIRY_5, true), + LOCATION(RC_SFM_FAIRY_GROTTO_FAIRY_6, true), + LOCATION(RC_SFM_FAIRY_GROTTO_FAIRY_7, true), + LOCATION(RC_SFM_FAIRY_GROTTO_FAIRY_8, true), + }, { + //Exits + Entrance(RR_SACRED_FOREST_MEADOW, []{return true;}), + }); + + areaTable[RR_SFM_WOLFOS_GROTTO] = Region("SFM Wolfos Grotto", "SFM Wolfos Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SFM_WOLFOS_GROTTO_CHEST, logic->CanKillEnemy(RE_WOLFOS, ED_CLOSE, true, 2)), + }, { + //Exits + Entrance(RR_SFM_ENTRYWAY, []{return true;}), + }); + + areaTable[RR_SFM_STORMS_GROTTO] = Region("SFM Storms Grotto", "SFM Storms Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_SFM_DEKU_SCRUB_GROTTO_REAR, logic->CanStunDeku()), + LOCATION(RC_SFM_DEKU_SCRUB_GROTTO_FRONT, logic->CanStunDeku()), + LOCATION(RC_SFM_STORMS_GROTTO_BEEHIVE, logic->CanBreakUpperBeehives()), + }, { + //Exits + Entrance(RR_SACRED_FOREST_MEADOW, []{return true;}), + }); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/temple_of_time.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/temple_of_time.cpp new file mode 100644 index 000000000..06865772d --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/overworld/temple_of_time.cpp @@ -0,0 +1,54 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" + +using namespace Rando; + +void RegionTable_Init_TempleOfTime() { + areaTable[RR_TOT_ENTRANCE] = Region("ToT Entrance", "ToT Entrance", {RA_THE_MARKET}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->GossipStoneFairy, []{return logic->CallGossipFairyExceptSuns();}), + }, { + //Locations + LOCATION(RC_TOT_LEFTMOST_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns() || (logic->CanUse(RG_SUNS_SONG) && logic->IsAdult)), + LOCATION(RC_TOT_LEFTMOST_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_TOT_LEFT_CENTER_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns() || (logic->CanUse(RG_SUNS_SONG) && logic->IsAdult)), + LOCATION(RC_TOT_LEFT_CENTER_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_TOT_RIGHT_CENTER_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns() || (logic->CanUse(RG_SUNS_SONG) && logic->IsAdult)), + LOCATION(RC_TOT_RIGHT_CENTER_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_TOT_RIGHTMOST_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns() || (logic->CanUse(RG_SUNS_SONG) && logic->IsAdult)), + LOCATION(RC_TOT_RIGHTMOST_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_TOT_LEFTMOST_GOSSIP_STONE, true), + LOCATION(RC_TOT_LEFT_CENTER_GOSSIP_STONE, true), + LOCATION(RC_TOT_RIGHT_CENTER_GOSSIP_STONE, true), + LOCATION(RC_TOT_RIGHTMOST_GOSSIP_STONE, true), + }, { + //Exits + Entrance(RR_THE_MARKET, []{return true;}), + Entrance(RR_TEMPLE_OF_TIME, []{return true;}), + }); + + areaTable[RR_TEMPLE_OF_TIME] = Region("Temple of Time", "Temple of Time", {RA_TEMPLE_OF_TIME}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_TOT_LIGHT_ARROWS_CUTSCENE, logic->IsAdult && logic->CanTriggerLACS()), + LOCATION(RC_ALTAR_HINT_CHILD, logic->IsChild), + LOCATION(RC_ALTAR_HINT_ADULT, logic->IsAdult), + LOCATION(RC_TOT_SHEIK_HINT, logic->IsAdult), + }, { + //Exits + Entrance(RR_TOT_ENTRANCE, []{return true;}), + Entrance(RR_TOT_BEYOND_DOOR_OF_TIME, []{return ctx->GetOption(RSK_DOOR_OF_TIME).Is(RO_DOOROFTIME_OPEN) || (logic->CanUse(RG_SONG_OF_TIME) && (ctx->GetOption(RSK_DOOR_OF_TIME).Is(RO_DOOROFTIME_SONGONLY) || (logic->StoneCount() == 3 && logic->HasItem(RG_OCARINA_OF_TIME))));}), + }); + + areaTable[RR_TOT_BEYOND_DOOR_OF_TIME] = Region("Beyond Door of Time", "Beyond Door of Time", {RA_TEMPLE_OF_TIME}, NO_DAY_NIGHT_CYCLE, { + //Events + //EventAccess(&logic->TimeTravel, []{return true;}), + }, { + //Locations + LOCATION(RC_TOT_MASTER_SWORD, logic->IsAdult), + LOCATION(RC_GIFT_FROM_RAURU, logic->IsAdult), + LOCATION(RC_SHEIK_AT_TEMPLE, logic->HasItem(RG_FOREST_MEDALLION) && logic->IsAdult), + }, { + //Exits + Entrance(RR_TEMPLE_OF_TIME, []{return true;}), + }); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/zora_river.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/zora_river.cpp new file mode 100644 index 000000000..16ac1b271 --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/overworld/zora_river.cpp @@ -0,0 +1,107 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" + +using namespace Rando; + +void RegionTable_Init_ZoraRiver() { + areaTable[RR_ZR_FRONT] = Region("ZR Front", "Zora River", {RA_ZORAS_RIVER}, DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_ZR_GS_TREE, logic->IsChild && logic->CanAttack()), + }, { + //Exits + Entrance(RR_ZORAS_RIVER, []{return logic->IsAdult || logic->BlastOrSmash();}), + Entrance(RR_HYRULE_FIELD, []{return true;}), + }); + + areaTable[RR_ZORAS_RIVER] = Region("Zora River", "Zora River", {RA_ZORAS_RIVER}, DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->GossipStoneFairy, []{return logic->CallGossipFairy();}), + EventAccess(&logic->BeanPlantFairy, []{return logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS);}), + EventAccess(&logic->ButterflyFairy, []{return logic->ButterflyFairy || logic->CanUse(RG_STICKS);}), + EventAccess(&logic->BugShrub, []{return logic->BugShrub || logic->CanCutShrubs();}), + }, { + //Locations + LOCATION(RC_ZR_MAGIC_BEAN_SALESMAN, logic->HasItem(RG_CHILD_WALLET) && logic->IsChild), + LOCATION(RC_ZR_FROGS_OCARINA_GAME, logic->IsChild && logic->CanUse(RG_ZELDAS_LULLABY) && logic->CanUse(RG_SARIAS_SONG) && logic->CanUse(RG_SUNS_SONG) && logic->CanUse(RG_EPONAS_SONG) && logic->CanUse(RG_SONG_OF_TIME) && logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_ZR_FROGS_IN_THE_RAIN, logic->IsChild && logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_ZR_FROGS_ZELDAS_LULLABY, logic->IsChild && logic->CanUse(RG_ZELDAS_LULLABY)), + LOCATION(RC_ZR_FROGS_EPONAS_SONG, logic->IsChild && logic->CanUse(RG_EPONAS_SONG)), + LOCATION(RC_ZR_FROGS_SARIAS_SONG, logic->IsChild && logic->CanUse(RG_SARIAS_SONG)), + LOCATION(RC_ZR_FROGS_SUNS_SONG, logic->IsChild && logic->CanUse(RG_SUNS_SONG)), + LOCATION(RC_ZR_FROGS_SONG_OF_TIME, logic->IsChild && logic->CanUse(RG_SONG_OF_TIME)), + LOCATION(RC_ZR_NEAR_OPEN_GROTTO_FREESTANDING_POH, logic->IsChild || logic->CanUse(RG_HOVER_BOOTS) || (logic->IsAdult && ctx->GetTrickOption(RT_ZR_LOWER))), + LOCATION(RC_ZR_NEAR_DOMAIN_FREESTANDING_POH, logic->IsChild || logic->CanUse(RG_HOVER_BOOTS) || (logic->IsAdult && ctx->GetTrickOption(RT_ZR_UPPER))), + LOCATION(RC_ZR_GS_LADDER, logic->IsChild && logic->CanAttack() && logic->CanGetNightTimeGS()), + LOCATION(RC_ZR_GS_NEAR_RAISED_GROTTOS, logic->IsAdult && logic->HookshotOrBoomerang() && logic->CanGetNightTimeGS()), + LOCATION(RC_ZR_GS_ABOVE_BRIDGE, logic->IsAdult && logic->CanUse(RG_HOOKSHOT) && logic->CanGetNightTimeGS()), + LOCATION(RC_ZR_BEAN_SPROUT_FAIRY_1, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_ZR_BEAN_SPROUT_FAIRY_2, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_ZR_BEAN_SPROUT_FAIRY_3, logic->IsChild && logic->CanUse(RG_MAGIC_BEAN) && logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_ZR_NEAR_GROTTOS_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), + LOCATION(RC_ZR_NEAR_GROTTOS_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_ZR_NEAR_DOMAIN_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), + LOCATION(RC_ZR_NEAR_DOMAIN_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_ZR_BENEATH_WATERFALL_LEFT_RUPEE, logic->IsAdult && (logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG))), + LOCATION(RC_ZR_BENEATH_WATERFALL_MIDDLE_LEFT_RUPEE, logic->IsAdult && (logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG))), + LOCATION(RC_ZR_BENEATH_WATERFALL_MIDDLE_RIGHT_RUPEE, logic->IsAdult && (logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG))), + LOCATION(RC_ZR_BENEATH_WATERFALL_RIGHT_RUPEE, logic->IsAdult && (logic->HasItem(RG_BRONZE_SCALE) || logic->CanUse(RG_IRON_BOOTS) || logic->CanUse(RG_BOOMERANG))), + LOCATION(RC_ZR_NEAR_GROTTOS_GOSSIP_STONE, true), + LOCATION(RC_ZR_NEAR_DOMAIN_GOSSIP_STONE, true), + }, { + //Exits + Entrance(RR_ZR_FRONT, []{return true;}), + Entrance(RR_ZR_OPEN_GROTTO, []{return true;}), + Entrance(RR_ZR_FAIRY_GROTTO, []{return Here(RR_ZORAS_RIVER, []{return logic->BlastOrSmash();});}), + Entrance(RR_THE_LOST_WOODS, []{return logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS);}), + Entrance(RR_ZR_STORMS_GROTTO, []{return logic->CanOpenStormsGrotto();}), + Entrance(RR_ZR_BEHIND_WATERFALL, []{return ctx->GetOption(RSK_SLEEPING_WATERFALL).Is(RO_WATERFALL_OPEN) || Here(RR_ZORAS_RIVER, []{return logic->CanUse(RG_ZELDAS_LULLABY);}) || (logic->IsChild && ctx->GetTrickOption(RT_ZR_CUCCO)) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS) && ctx->GetTrickOption(RT_ZR_HOVERS));}), + }); + + areaTable[RR_ZR_BEHIND_WATERFALL] = Region("ZR Behind Waterfall", "Zora River", {RA_ZORAS_RIVER}, DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_ZORAS_RIVER, []{return true;}), + Entrance(RR_ZORAS_DOMAIN, []{return true;}), + }); + + areaTable[RR_ZR_OPEN_GROTTO] = Region("ZR Open Grotto", "ZR Open Grotto", {}, NO_DAY_NIGHT_CYCLE, grottoEvents, { + //Locations + LOCATION(RC_ZR_OPEN_GROTTO_CHEST, true), + LOCATION(RC_ZR_OPEN_GROTTO_FISH, logic->HasBottle()), + LOCATION(RC_ZR_OPEN_GROTTO_GOSSIP_STONE_FAIRY, logic->CallGossipFairy()), + LOCATION(RC_ZR_OPEN_GROTTO_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_ZR_OPEN_GROTTO_GOSSIP_STONE, true), + LOCATION(RC_ZR_OPEN_GROTTO_BEEHIVE_LEFT, logic->CanBreakLowerBeehives()), + LOCATION(RC_ZR_OPEN_GROTTO_BEEHIVE_RIGHT, logic->CanBreakLowerBeehives()), + }, { + //Exits + Entrance(RR_ZORAS_RIVER, []{return true;}), + }); + + areaTable[RR_ZR_FAIRY_GROTTO] = Region("ZR Fairy Grotto", "ZR Fairy Grotto", {}, NO_DAY_NIGHT_CYCLE, { + //Event + EventAccess(&logic->FreeFairies, []{return true;}), + }, { + //Locations + LOCATION(RC_ZR_FAIRY_GROTTO_FAIRY_1, true), + LOCATION(RC_ZR_FAIRY_GROTTO_FAIRY_2, true), + LOCATION(RC_ZR_FAIRY_GROTTO_FAIRY_3, true), + LOCATION(RC_ZR_FAIRY_GROTTO_FAIRY_4, true), + LOCATION(RC_ZR_FAIRY_GROTTO_FAIRY_5, true), + LOCATION(RC_ZR_FAIRY_GROTTO_FAIRY_6, true), + LOCATION(RC_ZR_FAIRY_GROTTO_FAIRY_7, true), + LOCATION(RC_ZR_FAIRY_GROTTO_FAIRY_8, true), + }, { + //Exits + Entrance(RR_ZORAS_RIVER, []{return true;}), + }); + + areaTable[RR_ZR_STORMS_GROTTO] = Region("ZR Storms Grotto", "ZR Storms Grotto", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_ZR_DEKU_SCRUB_GROTTO_REAR, logic->CanStunDeku()), + LOCATION(RC_ZR_DEKU_SCRUB_GROTTO_FRONT, logic->CanStunDeku()), + LOCATION(RC_ZR_STORMS_GROTTO_BEEHIVE, logic->CanBreakUpperBeehives()), + }, { + //Exits + Entrance(RR_ZORAS_RIVER, []{return true;}), + }); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/zoras_domain.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/zoras_domain.cpp new file mode 100644 index 000000000..0bf91e43a --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/overworld/zoras_domain.cpp @@ -0,0 +1,93 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" + +using namespace Rando; + +void RegionTable_Init_ZorasDomain() { + areaTable[RR_ZORAS_DOMAIN] = Region("Zoras Domain", "Zoras Domain", {RA_ZORAS_DOMAIN}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->GossipStoneFairy, []{return logic->CallGossipFairyExceptSuns();}), + EventAccess(&logic->NutPot, []{return true;}), + EventAccess(&logic->StickPot, []{return logic->StickPot || logic->IsChild;}), + EventAccess(&logic->FishGroup, []{return logic->FishGroup || logic->IsChild;}), + EventAccess(&logic->KingZoraThawed, []{return logic->KingZoraThawed || (logic->IsAdult && logic->BlueFire());}), + EventAccess(&logic->DeliverLetter, []{return logic->DeliverLetter || (logic->CanUse(RG_RUTOS_LETTER) && logic->IsChild && ctx->GetOption(RSK_ZORAS_FOUNTAIN).IsNot(RO_ZF_OPEN));}), + }, { + //Locations + LOCATION(RC_ZD_DIVING_MINIGAME, logic->HasItem(RG_BRONZE_SCALE) && logic->HasItem(RG_CHILD_WALLET) && logic->IsChild), + LOCATION(RC_ZD_CHEST, logic->IsChild && logic->CanUse(RG_STICKS)), + LOCATION(RC_ZD_KING_ZORA_THAWED, logic->KingZoraThawed), + LOCATION(RC_ZD_TRADE_PRESCRIPTION, logic->KingZoraThawed && logic->CanUse(RG_PRESCRIPTION)), + LOCATION(RC_ZD_GS_FROZEN_WATERFALL, logic->IsAdult && (logic->HookshotOrBoomerang() || logic->CanUse(RG_FAIRY_SLINGSHOT) || logic->CanUse(RG_FAIRY_BOW) || (logic->CanUse(RG_MAGIC_SINGLE) && (logic->CanUse(RG_MASTER_SWORD) || logic->CanUse(RG_KOKIRI_SWORD) || logic->CanUse(RG_BIGGORON_SWORD))) || (ctx->GetTrickOption(RT_ZD_GS) && logic->CanJumpslashExceptHammer())) && logic->CanGetNightTimeGS()), + LOCATION(RC_ZD_FISH_1, logic->IsChild && logic->HasBottle()), + LOCATION(RC_ZD_FISH_2, logic->IsChild && logic->HasBottle()), + LOCATION(RC_ZD_FISH_3, logic->IsChild && logic->HasBottle()), + LOCATION(RC_ZD_FISH_4, logic->IsChild && logic->HasBottle()), + LOCATION(RC_ZD_FISH_5, logic->IsChild && logic->HasBottle()), + LOCATION(RC_ZD_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns()), + LOCATION(RC_ZD_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_ZD_GOSSIP_STONE, true), + LOCATION(RC_ZD_IN_FRONT_OF_KING_ZORA_BEEHIVE_LEFT, logic->CanBreakUpperBeehives()), + LOCATION(RC_ZD_IN_FRONT_OF_KING_ZORA_BEEHIVE_RIGHT, logic->CanBreakUpperBeehives()), + LOCATION(RC_ZD_NEAR_SHOP_POT_1, logic->CanBreakPots()), + LOCATION(RC_ZD_NEAR_SHOP_POT_2, logic->CanBreakPots()), + LOCATION(RC_ZD_NEAR_SHOP_POT_3, logic->CanBreakPots()), + LOCATION(RC_ZD_NEAR_SHOP_POT_4, logic->CanBreakPots()), + LOCATION(RC_ZD_NEAR_SHOP_POT_5, logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_ZR_BEHIND_WATERFALL, []{return true;}), + Entrance(RR_LAKE_HYLIA, []{return logic->IsChild && (logic->HasItem(RG_SILVER_SCALE) || logic->CanUse(RG_IRON_BOOTS));}), + Entrance(RR_ZD_BEHIND_KING_ZORA, []{return logic->DeliverLetter || ctx->GetOption(RSK_ZORAS_FOUNTAIN).Is(RO_ZF_OPEN) || (ctx->GetOption(RSK_ZORAS_FOUNTAIN).Is(RO_ZF_CLOSED_CHILD) && logic->IsAdult) || (ctx->GetTrickOption(RT_ZD_KING_ZORA_SKIP) && logic->IsAdult);}), + Entrance(RR_ZD_SHOP, []{return logic->IsChild || logic->BlueFire();}), + Entrance(RR_ZORAS_DOMAIN_ISLAND, []{return true;}), + }); + + areaTable[RR_ZORAS_DOMAIN_ISLAND] = Region("Zoras Domain Island", "Zoras Domain", {RA_ZORAS_DOMAIN}, NO_DAY_NIGHT_CYCLE, {}, {}, { + //Exits + Entrance(RR_ZORAS_DOMAIN, []{return logic->IsAdult || logic->HasItem(RG_BRONZE_SCALE);}), + Entrance(RR_ZD_STORMS_GROTTO, []{return logic->CanOpenStormsGrotto();}), + }); + + areaTable[RR_ZD_BEHIND_KING_ZORA] = Region("ZD Behind King Zora", "Zoras Domain", {RA_ZORAS_DOMAIN}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_ZD_BEHIND_KING_ZORA_BEEHIVE, logic->CanBreakUpperBeehives()), + }, { + //Exits + Entrance(RR_ZORAS_DOMAIN, []{return logic->DeliverLetter || ctx->GetOption(RSK_ZORAS_FOUNTAIN).Is(RO_ZF_OPEN) || (ctx->GetOption(RSK_ZORAS_FOUNTAIN).Is(RO_ZF_CLOSED_CHILD) && logic->IsAdult);}), + Entrance(RR_ZORAS_FOUNTAIN, []{return true;}), + }); + + areaTable[RR_ZD_SHOP] = Region("ZD Shop", "ZD Shop", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_ZD_SHOP_ITEM_1, true), + LOCATION(RC_ZD_SHOP_ITEM_2, true), + LOCATION(RC_ZD_SHOP_ITEM_3, true), + LOCATION(RC_ZD_SHOP_ITEM_4, true), + LOCATION(RC_ZD_SHOP_ITEM_5, true), + LOCATION(RC_ZD_SHOP_ITEM_6, true), + LOCATION(RC_ZD_SHOP_ITEM_7, true), + LOCATION(RC_ZD_SHOP_ITEM_8, true), + }, { + //Exits + Entrance(RR_ZORAS_DOMAIN, []{return true;}), + }); + + areaTable[RR_ZD_STORMS_GROTTO] = Region("ZD Storms Grotto", "ZD Storms Grotto", {}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->FreeFairies, []{return true;}), + }, { + //Locations + LOCATION(RC_ZD_FAIRY_GROTTO_FAIRY_1, true), + LOCATION(RC_ZD_FAIRY_GROTTO_FAIRY_2, true), + LOCATION(RC_ZD_FAIRY_GROTTO_FAIRY_3, true), + LOCATION(RC_ZD_FAIRY_GROTTO_FAIRY_4, true), + LOCATION(RC_ZD_FAIRY_GROTTO_FAIRY_5, true), + LOCATION(RC_ZD_FAIRY_GROTTO_FAIRY_6, true), + LOCATION(RC_ZD_FAIRY_GROTTO_FAIRY_7, true), + LOCATION(RC_ZD_FAIRY_GROTTO_FAIRY_8, true), + }, { + //Exits + Entrance(RR_ZORAS_DOMAIN_ISLAND, []{return true;}), + }); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/location_access/overworld/zoras_fountain.cpp b/soh/soh/Enhancements/randomizer/location_access/overworld/zoras_fountain.cpp new file mode 100644 index 000000000..ccdca0eca --- /dev/null +++ b/soh/soh/Enhancements/randomizer/location_access/overworld/zoras_fountain.cpp @@ -0,0 +1,64 @@ +#include "soh/Enhancements/randomizer/location_access.h" +#include "soh/Enhancements/randomizer/entrance.h" + +using namespace Rando; + +void RegionTable_Init_ZorasFountain() { + areaTable[RR_ZORAS_FOUNTAIN] = Region("Zoras Fountain", "Zoras Fountain", {RA_ZORAS_FOUNTAIN}, NO_DAY_NIGHT_CYCLE, { + //Events + EventAccess(&logic->GossipStoneFairy, []{return logic->CallGossipFairyExceptSuns();}), + EventAccess(&logic->ButterflyFairy, []{return logic->ButterflyFairy || (logic->CanUse(RG_STICKS) && logic->AtDay);}), + }, { + //Locations + LOCATION(RC_ZF_ICEBERG_FREESTANDING_POH, logic->IsAdult), + LOCATION(RC_ZF_BOTTOM_FREESTANDING_POH, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), + LOCATION(RC_ZF_GS_TREE, logic->IsChild), + LOCATION(RC_ZF_GS_ABOVE_THE_LOG, logic->IsChild && logic->HookshotOrBoomerang() && logic->CanGetNightTimeGS()), + LOCATION(RC_ZF_GS_HIDDEN_CAVE, logic->CanUse(RG_SILVER_GAUNTLETS) && logic->BlastOrSmash() && logic->HookshotOrBoomerang() && logic->IsAdult && logic->CanGetNightTimeGS()), + LOCATION(RC_ZF_HIDDEN_CAVE_POT_1, logic->CanUse(RG_SILVER_GAUNTLETS) && logic->IsAdult && logic->BlastOrSmash() && logic->CanBreakPots()), + LOCATION(RC_ZF_HIDDEN_CAVE_POT_2, logic->CanUse(RG_SILVER_GAUNTLETS) && logic->IsAdult && logic->BlastOrSmash() && logic->CanBreakPots()), + LOCATION(RC_ZF_HIDDEN_CAVE_POT_3, logic->CanUse(RG_SILVER_GAUNTLETS) && logic->IsAdult && logic->BlastOrSmash() && logic->CanBreakPots()), + LOCATION(RC_ZF_FAIRY_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns()), + LOCATION(RC_ZF_FAIRY_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_ZF_JABU_GOSSIP_STONE_FAIRY, logic->CallGossipFairyExceptSuns()), + LOCATION(RC_ZF_JABU_GOSSIP_STONE_FAIRY_BIG, logic->CanUse(RG_SONG_OF_STORMS)), + LOCATION(RC_ZF_BOTTOM_NORTH_INNER_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), + LOCATION(RC_ZF_BOTTOM_NORTHEAST_INNER_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), + LOCATION(RC_ZF_BOTTOM_SOUTHEAST_INNER_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), + LOCATION(RC_ZF_BOTTOM_SOUTH_INNER_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), + LOCATION(RC_ZF_BOTTOM_SOUTHWEST_INNER_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), + LOCATION(RC_ZF_BOTTOM_NORTHWEST_INNER_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), + LOCATION(RC_ZF_BOTTOM_NORTH_MIDDLE_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), + LOCATION(RC_ZF_BOTTOM_NORTHEAST_MIDDLE_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), + LOCATION(RC_ZF_BOTTOM_SOUTHEAST_MIDDLE_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), + LOCATION(RC_ZF_BOTTOM_SOUTH_MIDDLE_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), + LOCATION(RC_ZF_BOTTOM_SOUTHWEST_MIDDLE_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), + LOCATION(RC_ZF_BOTTOM_NORTHWEST_MIDDLE_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), + LOCATION(RC_ZF_BOTTOM_NORTH_OUTER_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), + LOCATION(RC_ZF_BOTTOM_NORTHEAST_OUTER_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), + LOCATION(RC_ZF_BOTTOM_SOUTHEAST_OUTER_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), + LOCATION(RC_ZF_BOTTOM_SOUTH_OUTER_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), + LOCATION(RC_ZF_BOTTOM_SOUTHWEST_OUTER_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), + LOCATION(RC_ZF_BOTTOM_NORTHWEST_OUTER_RUPEE, logic->IsAdult && logic->CanUse(RG_IRON_BOOTS) && logic->WaterTimer() >= 16), + LOCATION(RC_ZF_FAIRY_GOSSIP_STONE, true), + LOCATION(RC_ZF_JABU_GOSSIP_STONE, true), + LOCATION(RC_ZF_NEAR_JABU_POT_1, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_ZF_NEAR_JABU_POT_2, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_ZF_NEAR_JABU_POT_3, logic->IsChild && logic->CanBreakPots()), + LOCATION(RC_ZF_NEAR_JABU_POT_4, logic->IsChild && logic->CanBreakPots()), + }, { + //Exits + Entrance(RR_ZD_BEHIND_KING_ZORA, []{return true;}), + Entrance(RR_JABU_JABUS_BELLY_ENTRYWAY, []{return (logic->IsChild && logic->CanUse(RG_BOTTLE_WITH_FISH));}), + Entrance(RR_ICE_CAVERN_ENTRYWAY, []{return logic->IsAdult;}), + Entrance(RR_ZF_GREAT_FAIRY_FOUNTAIN, []{return logic->HasExplosives() || (ctx->GetTrickOption(RT_ZF_GREAT_FAIRY_WITHOUT_EXPLOSIVES) && logic->CanUse(RG_MEGATON_HAMMER) && logic->CanUse(RG_SILVER_GAUNTLETS));}), + }); + + areaTable[RR_ZF_GREAT_FAIRY_FOUNTAIN] = Region("ZF Great Fairy Fountain", "ZF Great Fairy Fountain", {}, NO_DAY_NIGHT_CYCLE, {}, { + //Locations + LOCATION(RC_ZF_GREAT_FAIRY_REWARD, logic->CanUse(RG_ZELDAS_LULLABY)), + }, { + //Exits + Entrance(RR_ZORAS_FOUNTAIN, []{return true;}), + }); +} \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp index c78ff62ce..0af0b0128 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp @@ -8,7 +8,7 @@ #include "soh/ResourceManagerHelpers.h" #include "soh/UIWidgets.hpp" #include "dungeon.h" -#include "3drando/location_access.hpp" +#include "location_access.h" #include #include From 7ea6422b6f605ab77d90f3ba1143118e9e96ba6a Mon Sep 17 00:00:00 2001 From: Pepper0ni <93387759+Pepper0ni@users.noreply.github.com> Date: Sat, 11 Jan 2025 07:44:02 +0000 Subject: [PATCH 06/26] fix LW Boulder (#4835) --- soh/soh/Enhancements/randomizer/location_list.cpp | 2 +- soh/soh/Enhancements/randomizer/randomizer_inf.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/soh/soh/Enhancements/randomizer/location_list.cpp b/soh/soh/Enhancements/randomizer/location_list.cpp index 8f93b414e..19ee1c7d0 100644 --- a/soh/soh/Enhancements/randomizer/location_list.cpp +++ b/soh/soh/Enhancements/randomizer/location_list.cpp @@ -1850,7 +1850,7 @@ void Rando::StaticData::InitLocationTable() { // locationTable[RC_KF_BEAN_RUPEE_6] = Location::Collectable(RC_KF_BEAN_RUPEE_6, RCQUEST_BOTH, RCTYPE_FREESTANDING, ACTOR_EN_ITEM00, SCENE_KOKIRI_FOREST, TWO_ACTOR_PARAMS(1304, -508), "Bean Platform Rupee 6", RHT_KOKIRI_FOREST_RUPEE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KF_BEAN_RUPEE_6)); locationTable[RC_KF_BEAN_RED_RUPEE] = Location::Collectable(RC_KF_BEAN_RED_RUPEE, RCQUEST_BOTH, RCTYPE_FREESTANDING, ACTOR_EN_ITEM00, SCENE_KOKIRI_FOREST, TWO_ACTOR_PARAMS(1304, -548), "Bean Platform Red Rupee", RHT_KOKIRI_FOREST_RUPEE, RG_RED_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_KF_BEAN_RED_RUPEE)); - locationTable[RC_LW_BOULDER_RUPEE] = Location::Collectable(RC_LW_BOULDER_RUPEE, RCQUEST_BOTH, RCTYPE_FREESTANDING, ACTOR_EN_ITEM00, SCENE_LOST_WOODS, TWO_ACTOR_PARAMS(1720, -2510), 0x13, "Boulder Rupee", RHT_LOST_WOODS_RUPEE, RG_BLUE_RUPEE); + locationTable[RC_LW_BOULDER_RUPEE] = Location::Collectable(RC_LW_BOULDER_RUPEE, RCQUEST_BOTH, RCTYPE_FREESTANDING, ACTOR_EN_ITEM00, SCENE_LOST_WOODS, TWO_ACTOR_PARAMS(1720, -2510), "Boulder Rupee", RHT_LOST_WOODS_RUPEE, RG_BLUE_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_LW_BOULDER_RUPEE)); locationTable[RC_LW_SHORTCUT_RUPEE_1] = Location::Collectable(RC_LW_SHORTCUT_RUPEE_1, RCQUEST_BOTH, RCTYPE_FREESTANDING, ACTOR_EN_ITEM00, SCENE_LOST_WOODS, TWO_ACTOR_PARAMS(2215, -850), "Underwater Shortcut Rupee 1", RHT_LOST_WOODS_SHORTCUT_RUPEE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_LW_SHORTCUT_RUPEE_1)); locationTable[RC_LW_SHORTCUT_RUPEE_2] = Location::Collectable(RC_LW_SHORTCUT_RUPEE_2, RCQUEST_BOTH, RCTYPE_FREESTANDING, ACTOR_EN_ITEM00, SCENE_LOST_WOODS, TWO_ACTOR_PARAMS(2164, -850), "Underwater Shortcut Rupee 2", RHT_LOST_WOODS_SHORTCUT_RUPEE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_LW_SHORTCUT_RUPEE_2)); locationTable[RC_LW_SHORTCUT_RUPEE_3] = Location::Collectable(RC_LW_SHORTCUT_RUPEE_3, RCQUEST_BOTH, RCTYPE_FREESTANDING, ACTOR_EN_ITEM00, SCENE_LOST_WOODS, TWO_ACTOR_PARAMS(2113, -850), "Underwater Shortcut Rupee 3", RHT_LOST_WOODS_SHORTCUT_RUPEE, RG_GREEN_RUPEE, SpoilerCollectionCheck::RandomizerInf(RAND_INF_LW_SHORTCUT_RUPEE_3)); diff --git a/soh/soh/Enhancements/randomizer/randomizer_inf.h b/soh/soh/Enhancements/randomizer/randomizer_inf.h index 4d06a0271..c66c06fab 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_inf.h +++ b/soh/soh/Enhancements/randomizer/randomizer_inf.h @@ -873,6 +873,7 @@ typedef enum { RAND_INF_KF_BEAN_RUPEE_5, RAND_INF_KF_BEAN_RUPEE_6, RAND_INF_KF_BEAN_RED_RUPEE, + RAND_INF_LW_BOULDER_RUPEE, RAND_INF_LW_SHORTCUT_RUPEE_1, RAND_INF_LW_SHORTCUT_RUPEE_2, RAND_INF_LW_SHORTCUT_RUPEE_3, From 8e8befc6d542dac85af82cfc9271bfc918135b65 Mon Sep 17 00:00:00 2001 From: Pepe20129 <72659707+Pepe20129@users.noreply.github.com> Date: Sat, 11 Jan 2025 10:53:45 +0100 Subject: [PATCH 07/26] Update settings.cpp (#4830) --- soh/soh/Enhancements/randomizer/settings.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/soh/soh/Enhancements/randomizer/settings.cpp b/soh/soh/Enhancements/randomizer/settings.cpp index 417ec53a6..f5abde703 100644 --- a/soh/soh/Enhancements/randomizer/settings.cpp +++ b/soh/soh/Enhancements/randomizer/settings.cpp @@ -707,6 +707,7 @@ void Settings::CreateOptions() { &mTrickOptions[RT_GANON_MQ_SHADOW_TRIAL], &mTrickOptions[RT_GANON_MQ_LIGHT_TRIAL], }); + mTricksByArea.clear(); for (int i = 0; i < RT_MAX; i++) { auto& trick = mTrickOptions[i]; if (!trick.GetName().empty()) { From 0ae7f626a1dccc17a9d98ea0fc701616f955ac7f Mon Sep 17 00:00:00 2001 From: Jordan Longstaff Date: Sat, 11 Jan 2025 04:55:36 -0500 Subject: [PATCH 08/26] Added skip of Forest Stage leader cutscene (#4818) --- soh/soh/Enhancements/timesaver_hook_handlers.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/soh/soh/Enhancements/timesaver_hook_handlers.cpp b/soh/soh/Enhancements/timesaver_hook_handlers.cpp index 5a19feabc..1056f9c9b 100644 --- a/soh/soh/Enhancements/timesaver_hook_handlers.cpp +++ b/soh/soh/Enhancements/timesaver_hook_handlers.cpp @@ -331,6 +331,7 @@ void TimeSaverOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li case ACTOR_SHOT_SUN: case ACTOR_BG_HAKA_GATE: case ACTOR_EN_KAKASI2: + case ACTOR_EN_DNT_JIJI: *should = false; RateLimitedSuccessChime(); break; From 4a91d945079fe11a27581ea3e5c72e70558232b1 Mon Sep 17 00:00:00 2001 From: Eric Hoey <121978037+A-Green-Spoon@users.noreply.github.com> Date: Sat, 11 Jan 2025 19:48:27 -0500 Subject: [PATCH 09/26] pass one + pass two + pass three (#4863) --- .../Enhancements/randomizer/randomizer.cpp | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index 0d2216755..b6c520ceb 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -2955,7 +2955,7 @@ CustomMessage Randomizer::GetIceTrapMessage() { "Thank you #@#! But your item is in another castle!", "#FREEZE#! Don't move!", "Wouldn't it be #ice# if we were colder?", - "Greetings from #Snowhead#! Wish you were here", + "Greetings from #Snowhead#! Wish you were here.", "Too #cool# for you?", "#Ice#, #ice#, baby...", "Time to break the #ice#.", @@ -2964,12 +2964,12 @@ CustomMessage Randomizer::GetIceTrapMessage() { "#Ice# to meet you!", "Do you want to #freeze# a snowman?", "Isn't there a #mansion# around here?", - "Now you know how #King Zora# feels", + "Now you know how #King Zora# feels.", "May the #Frost# be with you.", "Carpe diem. #Freeze# the day.", "There #snow# place like home.", "That'll do, #ice#. That'll do.", - "All that is #cold# does not glitter, Not all those who wander are #frost#.", + "All that is #cold# does not glitter. Not all those who wander are #frost#.", "I Used To Be An Adventurer Like You. Then I Took An #Icetrap# To The Knee.", "Would you like #ice# with that?", "You have obtained the #Ice# Medallion!", @@ -2991,9 +2991,9 @@ CustomMessage Randomizer::GetIceTrapMessage() { "Stay hydrated and brush your teeth!", "Isn't it too hot here? Let's turn the #AC# on.", "One serving of #cold# @, coming right up!", - "Is it #cold# in here is that just me?", + "Is it #cold# in here or is that just me?", "Yahaha! You found me!", - "You'd made a great #ice#-tronaut!", + "You'd make a great #ice#-tronaut!", "That's just the tip of the #iceberg#!", "It's the triforce!&No, just kidding, it's an #ice trap#.", "WINNER!", @@ -3019,7 +3019,7 @@ CustomMessage Randomizer::GetIceTrapMessage() { "Ice puns are #snow# problem!", "This #ice# is #snow# joke!", "There's no business like #snow# business!", - "no, dude", + "No, dude.", "N#ice# trap ya got here!", "Quick do your best impression of #Zoras Domain#!", "Ganon used #ice beam#, it's super effective!", @@ -3035,9 +3035,9 @@ CustomMessage Randomizer::GetIceTrapMessage() { "I know, I know... #FREEZE#!", "#Ice# of you to drop by!", "STOP!&You violated the #Thaw#!", - "I wanted to give you a treasure, but it looks like you got #cold feet#", + "I wanted to give you a treasure, but it looks like you got #cold feet#.", "You told me you wanted to deliver #just ice# to Ganondorf!", - "You got the triforce!&This ancient artifact of divine power can grant any- wait, no, sorry, it's just an ice trap. My bad", + "You got the triforce!&This ancient artifact of divine power can grant any- wait, no, sorry, it's just an ice trap. My bad.", "Time to #cool off#!", "The #Ice Cavern# sends its regards.", "Loading item, please #wait#...", @@ -3045,12 +3045,12 @@ CustomMessage Randomizer::GetIceTrapMessage() { "Sorry, your item is in another location.", //would be better if it could have the name of the item "You only wish this was %gGreg%w.", "Do you want to drink a hot chocolate?", - "The #cold# never bothered me anyway", + "The #cold# never bothered me anyway.", "Hope you're too school for #cool#!", "Be thankful this isn't #absolute zero#.", "Did you know the F in ZFG stands for #Freeze#?", "You got #Ice Age (2002)#!", - "Now you can cast a #spell# you don't know", + "Now you can cast a #spell# you don't know.", "How's about a hero #on the rocks#?", "Ain't no tunic for #this#!", "I knew you were #part metroid#!", @@ -3068,14 +3068,14 @@ CustomMessage Randomizer::GetIceTrapMessage() { "Mweep... mweep... mweep...", "Scum, #freezebag#! I mean #freeze#, scumbag!", "Is it #chilly# in here or is it just #you#?", - "#Proceed#", + "#Proceed#.", "WHAT'S SHE GONNA DO, MAKE ME AN #[Ice Cream]#!?", "You've met with a #terrible fate#, haven't you?", "So I heard you like the Shining, here's how it #ends#.", "Minor routing mistake. #I win#.", "Hold this #L#, @.", - "#SKILL ISSUE#", - "All you heat are belong to us", + "#SKILL ISSUE#.", + "All your heat are belong to us.", "Wait a second, don't you already have #this item#?", "#Freeze#! We have you surrounded!", "Error 404 - Item not #found#.", From 61de721fe51a36c913b420055d6eaca8ceed933f Mon Sep 17 00:00:00 2001 From: Eric Hoey <121978037+A-Green-Spoon@users.noreply.github.com> Date: Sat, 11 Jan 2025 19:49:24 -0500 Subject: [PATCH 10/26] Fix Skeleton Key Hint (#4860) * add skeleton key hint text * Update soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp Co-authored-by: PurpleHato * Update soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp Co-authored-by: PurpleHato * add end quote back, oops --------- Co-authored-by: PurpleHato --- .../randomizer/3drando/hint_list/hint_list_item.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) 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 index cd33fd441..0bf60eb81 100644 --- a/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/hint_list/hint_list_item.cpp @@ -2057,7 +2057,14 @@ void StaticData::HintTable_Init_Item() { }, { CustomMessage("a fish-puller", /*german*/"ein Fischzieher", /*french*/"(canne à pêche)")}); // /*spanish*/(caña de pescar) - + hintTextTable[RHT_SKELETON_KEY] = HintText(CustomMessage("a Skeleton Key", /*german*/ "ein Universalschlüssel", /*french*/ "une Clé Squelette"), + // /*spanish*/una Llave Maestra + { + CustomMessage("a key", /*german*/ "ein Schlüssel", /*french*/ "une clé") + // /*spanish*/una llave + }, + { CustomMessage("a master unlocker", /*german*/ "ein Meisterentsperrer", /*french*/ "un Kit de Déverrouillage") }); + // /*spanish*/un desbloqueador maestro hintTextTable[RHT_QUIVER_INF] = HintText(CustomMessage("", /*german*/"!!!", /*french*/"!!!"), { CustomMessage("", /*german*/"!!!", /*french*/"!!!"), From 66f5e6c26c2558e8e25d513a08ac9dc07d3ec4ae Mon Sep 17 00:00:00 2001 From: Pepper0ni <93387759+Pepper0ni@users.noreply.github.com> Date: Sun, 12 Jan 2025 00:50:50 +0000 Subject: [PATCH 11/26] Fix generation errors exposed by loccacc refactor (#4861) * Fix generation errors exposed by loccacc refactor * oops --- soh/soh/Enhancements/randomizer/3drando/fill.cpp | 6 +++--- soh/soh/Enhancements/randomizer/item_location.cpp | 1 + .../Enhancements/randomizer/location_access.cpp | 3 +-- soh/soh/Enhancements/randomizer/location_access.h | 4 +++- .../location_access/dungeons/fire_temple.cpp | 14 +++++++------- soh/soh/Enhancements/randomizer/randomizerTypes.h | 4 ++-- 6 files changed, 17 insertions(+), 15 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/3drando/fill.cpp b/soh/soh/Enhancements/randomizer/3drando/fill.cpp index e7a6ce38b..248fd960d 100644 --- a/soh/soh/Enhancements/randomizer/3drando/fill.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/fill.cpp @@ -391,14 +391,14 @@ void ApplyOrStoreItem(Rando::ItemLocation* loc, GetAccessibleLocationsStruct& ga } // Adds the contents of a location to the current progression and optionally playthrough -bool AddCheckToLogic(LocationAccess& locPair, GetAccessibleLocationsStruct& gals, RandomizerGet ignore, bool stopOnBeatable, bool addToPlaythrough=false){ +bool AddCheckToLogic(LocationAccess& locPair, GetAccessibleLocationsStruct& gals, RandomizerGet ignore, bool stopOnBeatable, Region* parentRegion, bool addToPlaythrough=false){ auto ctx = Rando::Context::GetInstance(); StartPerformanceTimer(PT_LOCATION_LOGIC); RandomizerCheck loc = locPair.GetLocation(); Rando::ItemLocation* location = ctx->GetItemLocation(loc); RandomizerGet locItem = location->GetPlacedRandomizerGet(); - if (!location->IsAddedToPool() && locPair.ConditionsMet()) { + if (!location->IsAddedToPool() && locPair.ConditionsMet(parentRegion)) { location->AddToPool(); if (locItem == RG_NONE) { @@ -486,7 +486,7 @@ void ProcessRegion(Region* region, GetAccessibleLocationsStruct& gals, Randomize PropagateTimeTravel(gals, ignore, stopOnBeatable, addToPlaythrough); for (size_t k = 0; k < region->locations.size(); k++) { - if(AddCheckToLogic(region->locations[k], gals, ignore, stopOnBeatable, addToPlaythrough)){ + if(AddCheckToLogic(region->locations[k], gals, ignore, stopOnBeatable, region, addToPlaythrough)){ Rando::Context::GetInstance()->playthroughBeatable = true; return; } diff --git a/soh/soh/Enhancements/randomizer/item_location.cpp b/soh/soh/Enhancements/randomizer/item_location.cpp index 9f0f84509..47c1f09f1 100644 --- a/soh/soh/Enhancements/randomizer/item_location.cpp +++ b/soh/soh/Enhancements/randomizer/item_location.cpp @@ -56,6 +56,7 @@ void ItemLocation::SetParentRegion(const RandomizerRegion region) { parentRegion = region; } +//RANDOTODO only used in tracker now, could possibly be removed RandomizerRegion ItemLocation::GetParentRegionKey() const { return parentRegion; } diff --git a/soh/soh/Enhancements/randomizer/location_access.cpp b/soh/soh/Enhancements/randomizer/location_access.cpp index f8bb8f421..7c9cf7e7f 100644 --- a/soh/soh/Enhancements/randomizer/location_access.cpp +++ b/soh/soh/Enhancements/randomizer/location_access.cpp @@ -27,11 +27,10 @@ bool LocationAccess::CheckConditionAtAgeTime(bool& age, bool& time) const { return GetConditionsMet(); } -bool LocationAccess::ConditionsMet() const { +bool LocationAccess::ConditionsMet(Region* parentRegion) const { //WARNING enterance validation can run this after resetting the access for sphere 0 validation //When refactoring ToD access, either fix the above or do not assume that we //have any access at all just because this is being run - Region* parentRegion = RegionTable(Rando::Context::GetInstance()->GetItemLocation(location)->GetParentRegionKey()); bool conditionsMet = false; if ( diff --git a/soh/soh/Enhancements/randomizer/location_access.h b/soh/soh/Enhancements/randomizer/location_access.h index 1f2cdfcab..3af0a498d 100644 --- a/soh/soh/Enhancements/randomizer/location_access.h +++ b/soh/soh/Enhancements/randomizer/location_access.h @@ -15,6 +15,8 @@ typedef bool (*ConditionFn)(); extern Rando::Context* ctx; extern std::shared_ptr logic; +class Region; + class EventAccess { public: explicit EventAccess(bool* event_, ConditionFn condition_function_) : event(event_), condition_function(condition_function_) {} @@ -81,7 +83,7 @@ class LocationAccess { bool CheckConditionAtAgeTime(bool& age, bool& time) const; - bool ConditionsMet() const; + bool ConditionsMet(Region* parentRegion) const; RandomizerCheck GetLocation() const { return location; diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/fire_temple.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/fire_temple.cpp index 4abfa9c23..65efe4cfe 100644 --- a/soh/soh/Enhancements/randomizer/location_access/dungeons/fire_temple.cpp +++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/fire_temple.cpp @@ -426,21 +426,21 @@ void RegionTable_Init_FireTemple() { Entrance(RR_FIRE_TEMPLE_MQ_MAP_ROOM_SOUTH, []{return logic->OpenedLowestGoronCage;}), }); - areaTable[RR_FIRE_TEMPLE_NEAR_BOSS_ROOM] = Region("Fire Temple MQ Near Boss Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + areaTable[RR_FIRE_TEMPLE_MQ_NEAR_BOSS_ROOM] = Region("Fire Temple MQ Near Boss Room", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { //Locations //If we're using the south torch as the initial torch, or using FAs, we either have to cross to the north to remove the crate, or use a trick to ignore it LOCATION(RC_FIRE_TEMPLE_MQ_NEAR_BOSS_CHEST, logic->FireTimer() > 25 && ctx->GetTrickOption(RT_FIRE_MQ_NEAR_BOSS) && (logic->CanUse(RG_FIRE_ARROWS) || (logic->IsAdult && logic->CanUse(RG_DINS_FIRE) && logic->CanUse(RG_FAIRY_BOW)))) }, { //Exits - Entrance(RR_FIRE_TEMPLE_MQ_FIRST_ROOM_UPPER, []{return true;}), + Entrance(RR_FIRE_TEMPLE_MQ_FIRST_ROOM_UPPER, []{return true;}), //Child cannot make it to the north side torches without a hook without specifically bunny hood speed + hover boots - Entrance(RR_FIRE_TEMPLE_NEAR_BOSS_ROOM_NORTH, []{return logic->FireTimer() > 32 && (logic->CanUse(RG_HOOKSHOT) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)));}), - Entrance(RR_FIRE_TEMPLE_BOSS_ENTRYWAY, []{return logic->HasItem(RG_FIRE_TEMPLE_BOSS_KEY) && logic->FireTimer() >= 15 && ((logic->IsAdult && (ctx->GetTrickOption(RT_FIRE_BOSS_DOOR_JUMP) || logic->CanUse(RG_HOVER_BOOTS))) || (logic->IsAdult && logic->HitFireTemplePlatform) || (logic->HitFireTemplePlatform && logic->CanUse(RG_HOVER_BOOTS)));}), + Entrance(RR_FIRE_TEMPLE_MQ_NEAR_BOSS_ROOM_NORTH, []{return logic->FireTimer() > 32 && (logic->CanUse(RG_HOOKSHOT) || (logic->IsAdult && logic->CanUse(RG_HOVER_BOOTS)));}), + Entrance(RR_FIRE_TEMPLE_BOSS_ENTRYWAY, []{return logic->HasItem(RG_FIRE_TEMPLE_BOSS_KEY) && logic->FireTimer() >= 15 && ((logic->IsAdult && (ctx->GetTrickOption(RT_FIRE_BOSS_DOOR_JUMP) || logic->CanUse(RG_HOVER_BOOTS))) || (logic->IsAdult && logic->HitFireTemplePlatform) || (logic->HitFireTemplePlatform && logic->CanUse(RG_HOVER_BOOTS)));}), }); //This room assumes tunic logic is handled on entry. //Covers the upper section too, as all methods to reach this can climb up somehow - areaTable[RR_FIRE_TEMPLE_NEAR_BOSS_ROOM_NORTH] = Region("Fire Temple MQ Near Boss Room North", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { + areaTable[RR_FIRE_TEMPLE_MQ_NEAR_BOSS_ROOM_NORTH] = Region("Fire Temple MQ Near Boss Room North", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, { //Locations //If we have FAs, we can just remove the crate and use those to light the torches. //otherwise, with Dins, we first light them with dins and then either use a bow shot or to cross back over to light the other torch @@ -616,7 +616,7 @@ void RegionTable_Init_FireTemple() { LOCATION(RC_FIRE_TEMPLE_MQ_SOUTH_FIRE_MAZE_EAST_POT, logic->CanBreakPots()), }, { //Exits - Entrance(RR_FIRE_TEMPLE_MQ_NEAR_BOSS_DOOR, []{return logic->HitFireTemplePlatform;}), + Entrance(RR_FIRE_TEMPLE_MQ_NEAR_BOSS_ROOM, []{return logic->HitFireTemplePlatform;}), Entrance(RR_FIRE_TEMPLE_MQ_HIGH_TORCH_ROOM, []{return true;}), Entrance(RR_FIRE_TEMPLE_MQ_FIRE_MAZE_PLATFORMS, []{return logic->IsAdult || logic->CanUse(RG_SONG_OF_TIME) || logic->CanUse(RG_HOVER_BOOTS);}), //Hover boots get there via the platforms @@ -699,7 +699,7 @@ void RegionTable_Init_FireTemple() { areaTable[RR_FIRE_TEMPLE_BOSS_ENTRYWAY] = Region("Fire Temple Boss Entryway", "Fire Temple", {RA_FIRE_TEMPLE}, NO_DAY_NIGHT_CYCLE, {}, {}, { // Exits Entrance(RR_FIRE_TEMPLE_NEAR_BOSS_ROOM, []{return ctx->GetDungeon(FIRE_TEMPLE)->IsVanilla() && false;}), - Entrance(RR_FIRE_TEMPLE_MQ_NEAR_BOSS_DOOR, []{return ctx->GetDungeon(FIRE_TEMPLE)->IsMQ() && false;}), + Entrance(RR_FIRE_TEMPLE_MQ_NEAR_BOSS_ROOM, []{return ctx->GetDungeon(FIRE_TEMPLE)->IsMQ() && false;}), Entrance(RR_FIRE_TEMPLE_BOSS_ROOM, []{return true;}), }); diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index 72dd800e6..87ba34adf 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -666,7 +666,6 @@ typedef enum { RR_FIRE_TEMPLE_FIRST_ROOM, RR_FIRE_TEMPLE_NEAR_BOSS_ROOM, - RR_FIRE_TEMPLE_NEAR_BOSS_ROOM_NORTH, RR_FIRE_TEMPLE_LOOP_ENEMIES, RR_FIRE_TEMPLE_LOOP_TILES, RR_FIRE_TEMPLE_LOOP_FLARE_DANCER, @@ -709,7 +708,8 @@ typedef enum { RR_FIRE_TEMPLE_MQ_LOWER_FLARE_DANCER, RR_FIRE_TEMPLE_MQ_MAP_ROOM_NORTH, RR_FIRE_TEMPLE_MQ_MAP_ROOM_CAGE, - RR_FIRE_TEMPLE_MQ_NEAR_BOSS_DOOR, + RR_FIRE_TEMPLE_MQ_NEAR_BOSS_ROOM, + RR_FIRE_TEMPLE_MQ_NEAR_BOSS_ROOM_NORTH, RR_FIRE_TEMPLE_MQ_BIG_LAVA_ROOM, RR_FIRE_TEMPLE_MQ_TORCH_FIREWALL_ROOM, RR_FIRE_TEMPLE_MQ_ELEVATOR_ROOM, From b774d39bc787fd803d42222d365c88caa59c3636 Mon Sep 17 00:00:00 2001 From: briaguya <70942617+briaguya-ai@users.noreply.github.com> Date: Sat, 11 Jan 2025 20:06:34 -0500 Subject: [PATCH 12/26] fix tooltip wonkyness (#4856) --- soh/soh/UIWidgets.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/soh/soh/UIWidgets.cpp b/soh/soh/UIWidgets.cpp index 2ffea11b4..050c6714c 100644 --- a/soh/soh/UIWidgets.cpp +++ b/soh/soh/UIWidgets.cpp @@ -213,11 +213,11 @@ namespace UIWidgets { } void ReEnableComponent(const char* disabledTooltipText) { - // End of disable region of previous component - ImGui::PopStyleVar(1); if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && strcmp(disabledTooltipText, "") != 0) { ImGui::SetTooltip("%s", disabledTooltipText); } + // End of disable region of previous component + ImGui::PopStyleVar(1); ImGui::PopItemFlag(); } From 2fc3a563c9da566bc67122818d3763815f68ec59 Mon Sep 17 00:00:00 2001 From: Pepper0ni <93387759+Pepper0ni@users.noreply.github.com> Date: Mon, 13 Jan 2025 18:17:12 +0000 Subject: [PATCH 13/26] fix spirit MQ south child climb chest logic (#4850) --- .../randomizer/location_access/dungeons/bottom_of_the_well.cpp | 2 +- .../randomizer/location_access/dungeons/spirit_temple.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/bottom_of_the_well.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/bottom_of_the_well.cpp index 588d32bf1..4ad3f7528 100644 --- a/soh/soh/Enhancements/randomizer/location_access/dungeons/bottom_of_the_well.cpp +++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/bottom_of_the_well.cpp @@ -49,7 +49,7 @@ void RegionTable_Init_BottomOfTheWell() { LOCATION(RC_BOTTOM_OF_THE_WELL_FRONT_LEFT_FAKE_WALL_CHEST, true), LOCATION(RC_BOTTOM_OF_THE_WELL_RIGHT_BOTTOM_FAKE_WALL_CHEST, true), LOCATION(RC_BOTTOM_OF_THE_WELL_COMPASS_CHEST, true), - //N64 has no extra check here, but I can't get past without dealing with the spider or taking a hit + //N64 has no extra check here, but I can't get past without dealing with the spider or taking a hit, they probably assume sticks LOCATION(RC_BOTTOM_OF_THE_WELL_CENTER_SKULLTULA_CHEST, logic->CanPassEnemy(RE_BIG_SKULLTULA) || logic->TakeDamage()), //Not technically behind a wall, but still logically needs lens due to pits LOCATION(RC_BOTTOM_OF_THE_WELL_BACK_LEFT_BOMBABLE_CHEST, logic->HasExplosives()), diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/spirit_temple.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/spirit_temple.cpp index 30481922c..36ee1d5ab 100644 --- a/soh/soh/Enhancements/randomizer/location_access/dungeons/spirit_temple.cpp +++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/spirit_temple.cpp @@ -267,7 +267,7 @@ void RegionTable_Init_SpiritTemple() { LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_CLIMB_NORTH_CHEST, MQSpiritSharedBrokenWallRoom(RR_SPIRIT_TEMPLE_MQ_BROKEN_WALL_ROOM, []{return logic->CanKillEnemy(RE_BEAMOS);})), //Sunlights only temp spawn this chest, which is unintuitive/a bug. //chest is only reachable as adult glitchlessly, so we can skip the shared in favour of IsAdult as adult access is always Certain - LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_CLIMB_SOUTH_CHEST, logic->IsAdult && logic->HasExplosives() && (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS)) && logic->CanUse(RG_HOOKSHOT)), + LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_CLIMB_SOUTH_CHEST, logic->IsAdult && (logic->HasExplosives() || (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS))) && logic->CanUse(RG_HOOKSHOT)), }, { //Exits Entrance(RR_SPIRIT_TEMPLE_MQ_UNDER_LIKE_LIKE, []{return logic->CanHitSwitch();}), From 0d80c4695f1ca275167821b42377741fc0828c58 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Tue, 14 Jan 2025 21:49:49 -0700 Subject: [PATCH 14/26] Change `UnregisterGameHook` type for freestanding handler to `OnVanillaBehavior` to match registration type. (#4883) --- soh/soh/Enhancements/randomizer/hook_handlers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soh/soh/Enhancements/randomizer/hook_handlers.cpp b/soh/soh/Enhancements/randomizer/hook_handlers.cpp index 409fa45d1..86fb79418 100644 --- a/soh/soh/Enhancements/randomizer/hook_handlers.cpp +++ b/soh/soh/Enhancements/randomizer/hook_handlers.cpp @@ -2392,7 +2392,7 @@ void RandomizerRegisterHooks() { GameInteractor::Instance->UnregisterGameHook(shufflePotsOnActorInitHook); GameInteractor::Instance->UnregisterGameHook(shufflePotsOnVanillaBehaviorHook); - GameInteractor::Instance->UnregisterGameHook(shuffleFreestandingOnVanillaBehaviorHook); + GameInteractor::Instance->UnregisterGameHook(shuffleFreestandingOnVanillaBehaviorHook); onFlagSetHook = 0; onSceneFlagSetHook = 0; From 7f31fd2e4ee0f2facafec4aaba5591fed52da9f5 Mon Sep 17 00:00:00 2001 From: Pepe20129 <72659707+Pepe20129@users.noreply.github.com> Date: Wed, 15 Jan 2025 13:04:47 +0100 Subject: [PATCH 15/26] Organize ship specific save context additions (#4597) * Basic restructure * Undo most randomizerInf changes for now * Small fixes * Fix linux & mac builds? * Fix remnants of randomizerInf changes * Post-merge fix * Post-merge fix --- soh/include/z64save.h | 64 +++-- soh/soh/Enhancements/boss-rush/BossRush.cpp | 57 ++-- soh/soh/Enhancements/debugconsole.cpp | 2 +- .../Enhancements/debugger/debugSaveEditor.cpp | 16 +- soh/soh/Enhancements/enemyrandomizer.cpp | 2 +- .../GameInteractor_RawAction.cpp | 14 +- soh/soh/Enhancements/gameplaystats.cpp | 264 +++++++++--------- soh/soh/Enhancements/gameplaystats.h | 14 +- soh/soh/Enhancements/kaleido.cpp | 2 +- soh/soh/Enhancements/mods.cpp | 112 ++++---- .../randomizer/adult_trade_shuffle.c | 6 +- .../randomizer/adult_trade_shuffle.h | 2 +- soh/soh/Enhancements/randomizer/draw.cpp | 4 +- .../Enhancements/randomizer/hook_handlers.cpp | 2 +- .../randomizer/location_access.cpp | 2 +- soh/soh/Enhancements/randomizer/logic.cpp | 25 +- .../Enhancements/randomizer/randomizer.cpp | 40 +-- .../randomizer/randomizer_check_tracker.cpp | 2 +- .../randomizer/randomizer_entrance.c | 8 +- .../randomizer/randomizer_item_tracker.cpp | 14 +- soh/soh/Enhancements/randomizer/savefile.cpp | 40 +-- .../Enhancements/timesplits/TimeSplits.cpp | 4 +- soh/soh/OTRGlobals.cpp | 4 +- soh/soh/SaveManager.cpp | 242 ++++++++-------- soh/src/code/z_actor.c | 33 ++- soh/src/code/z_demo.c | 4 +- soh/src/code/z_draw.c | 2 +- soh/src/code/z_kaleido_scope_call.c | 8 +- soh/src/code/z_parameter.c | 58 ++-- soh/src/code/z_play.c | 96 +++---- soh/src/code/z_room.c | 20 +- soh/src/code/z_sram.c | 6 +- soh/src/overlays/actors/ovl_En_Box/z_en_box.c | 2 +- soh/src/overlays/actors/ovl_En_Dns/z_en_dns.c | 4 +- soh/src/overlays/actors/ovl_En_Ds/z_en_ds.c | 4 +- .../overlays/actors/ovl_En_GirlA/z_en_girla.c | 80 +++--- soh/src/overlays/actors/ovl_En_Js/z_en_js.c | 4 +- .../overlays/actors/ovl_En_Kusa/z_en_kusa.c | 4 +- soh/src/overlays/actors/ovl_En_Ta/z_en_ta.c | 4 +- .../actors/ovl_Obj_Tsubo/z_obj_tsubo.c | 4 +- .../actors/ovl_player_actor/z_player.c | 36 +-- .../ovl_file_choose/z_file_choose.c | 24 +- 42 files changed, 695 insertions(+), 640 deletions(-) diff --git a/soh/include/z64save.h b/soh/include/z64save.h index 47a2d18c4..7138d0e0a 100644 --- a/soh/include/z64save.h +++ b/soh/include/z64save.h @@ -157,6 +157,42 @@ typedef struct { char hintText[200]; } HintLocationRando; +#pragma region SoH + +typedef struct ShipRandomizerSaveContextData { + u16 adultTradeItems; + u8 triforcePiecesCollected; +} ShipRandomizerSaveContextData; + +typedef struct ShipBossRushSaveContextData { + u32 isPaused; + u8 options[BR_OPTIONS_MAX]; +} ShipBossRushSaveContextData; + +typedef union ShipQuestSpecificSaveContextData { + ShipRandomizerSaveContextData randomizer; + ShipBossRushSaveContextData bossRush; +} ShipQuestSpecificSaveContextData; + +typedef struct ShipQuestSaveContextData { + u8 id; + ShipQuestSpecificSaveContextData data; +} ShipQuestSaveContextData; + +typedef struct ShipSaveContextData { + u16 pendingSale; + u16 pendingSaleMod; + u8 pendingIceTrapCount; + SohStats stats; + FaroresWindData backupFW; + ShipQuestSaveContextData quest; + u8 maskMemory; + //TODO: Move non-rando specific flags to a new sohInf and move the remaining randomizerInf to ShipRandomizerSaveContextData + u16 randomizerInf[(RAND_INF_MAX + 15) / 16]; +} ShipSaveContextData; + +#pragma endregion + typedef struct { /* 0x0000 */ s32 entranceIndex; // start of `save` substruct, originally called "memory" /* 0x0004 */ s32 linkAge; // 0: Adult; 1: Child (see enum `LinkAge`) @@ -270,25 +306,7 @@ typedef struct { /* 0x1420 */ s16 worldMapArea; /* 0x1422 */ s16 sunsSongState; // controls the effects of suns song /* 0x1424 */ s16 healthAccumulator; - // #region SOH [General] - // Upstream TODO: Move these to their own struct or name to more obviously specific to SoH - /* */ u16 pendingSale; - /* */ u16 pendingSaleMod; - /* */ uint8_t questId; - /* */ uint32_t isBossRushPaused; - /* */ uint8_t bossRushOptions[BR_OPTIONS_MAX]; - /* */ u8 pendingIceTrapCount; - /* */ SohStats sohStats; - /* */ FaroresWindData backupFW; - /* */ u8 maskMemory; - // #endregion - // #region SOH [Randomizer] - // Upstream TODO: Move these to their own struct or name to more obviously specific to Randomizer - /* */ u16 randomizerInf[(RAND_INF_MAX + 15) / 16]; - /* */ u8 mqDungeonCount; - /* */ u16 adultTradeItems; - /* */ u8 triforcePiecesCollected; - // #endregion + /* */ ShipSaveContextData ship; } SaveContext; // size = 0x1428 typedef enum { @@ -298,10 +316,10 @@ typedef enum { /* 03 */ QUEST_BOSSRUSH, } Quest; -#define IS_VANILLA (gSaveContext.questId == QUEST_NORMAL) -#define IS_MASTER_QUEST (gSaveContext.questId == QUEST_MASTER) -#define IS_RANDO (gSaveContext.questId == QUEST_RANDOMIZER) -#define IS_BOSS_RUSH (gSaveContext.questId == QUEST_BOSSRUSH) +#define IS_VANILLA (gSaveContext.ship.quest.id == QUEST_NORMAL) +#define IS_MASTER_QUEST (gSaveContext.ship.quest.id == QUEST_MASTER) +#define IS_RANDO (gSaveContext.ship.quest.id == QUEST_RANDOMIZER) +#define IS_BOSS_RUSH (gSaveContext.ship.quest.id == QUEST_BOSSRUSH) typedef enum { /* 0x00 */ BTN_ENABLED, diff --git a/soh/soh/Enhancements/boss-rush/BossRush.cpp b/soh/soh/Enhancements/boss-rush/BossRush.cpp index d4997cca9..96220f057 100644 --- a/soh/soh/Enhancements/boss-rush/BossRush.cpp +++ b/soh/soh/Enhancements/boss-rush/BossRush.cpp @@ -265,10 +265,10 @@ void BossRush_HandleBlueWarp(PlayState* play, f32 warpPosX, f32 warpPosZ) { gSaveContext.linkAge = LINK_AGE_ADULT; // Change to Adult Link. - if (gSaveContext.bossRushOptions[BR_OPTIONS_BOSSES] == BR_CHOICE_BOSSES_ALL) { + if (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_BOSSES] == BR_CHOICE_BOSSES_ALL) { BossRush_SetEquipment(LINK_AGE_ADULT); // Warp to credits. - } else if (gSaveContext.bossRushOptions[BR_OPTIONS_BOSSES] == BR_CHOICE_BOSSES_CHILD) { + } else if (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_BOSSES] == BR_CHOICE_BOSSES_CHILD) { play->nextEntranceIndex = ENTR_CHAMBER_OF_THE_SAGES_0; gSaveContext.nextCutsceneIndex = 0xFFF2; play->transitionTrigger = TRANS_TRIGGER_START; @@ -285,14 +285,14 @@ void BossRush_HandleBlueWarp(PlayState* play, f32 warpPosX, f32 warpPosZ) { void BossRush_HandleBlueWarpHeal(PlayState* play) { // This function gets called multiple times per blue warp, so only heal when player isn't at max HP. - if (gSaveContext.bossRushOptions[BR_OPTIONS_HEAL] == BR_CHOICE_HEAL_EVERYBOSS && + if (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_HEAL] == BR_CHOICE_HEAL_EVERYBOSS && gSaveContext.health != gSaveContext.healthCapacity) { Health_ChangeBy(play, 320); } } void BossRush_HandleCompleteBoss(PlayState* play) { - gSaveContext.isBossRushPaused = 1; + gSaveContext.ship.quest.data.bossRush.isPaused = true; switch (play->sceneNum) { case SCENE_DEKU_TREE_BOSS: Flags_SetEventChkInf(EVENTCHKINF_USED_DEKU_TREE_BLUE_WARP); @@ -323,16 +323,16 @@ void BossRush_HandleCompleteBoss(PlayState* play) { } // Fully heal the player after Ganondorf - if (gSaveContext.bossRushOptions[BR_OPTIONS_HEAL] == BR_CHOICE_HEAL_EVERYBOSS && + if (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_HEAL] == BR_CHOICE_HEAL_EVERYBOSS && play->sceneNum == SCENE_GANONDORF_BOSS) { Health_ChangeBy(play, 320); } - if ((CheckDungeonCount() == 3 && gSaveContext.bossRushOptions[BR_OPTIONS_BOSSES] == BR_CHOICE_BOSSES_CHILD) || + if ((CheckDungeonCount() == 3 && gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_BOSSES] == BR_CHOICE_BOSSES_CHILD) || play->sceneNum == SCENE_GANON_BOSS) { - gSaveContext.sohStats.playTimer += 2; - gSaveContext.sohStats.gameComplete = 1; - gSaveContext.sohStats.itemTimestamp[TIMESTAMP_BOSSRUSH_FINISH] = GAMEPLAYSTAT_TOTAL_TIME; + gSaveContext.ship.stats.playTimer += 2; + gSaveContext.ship.stats.gameComplete = 1; + gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_BOSSRUSH_FINISH] = GAMEPLAYSTAT_TOTAL_TIME; } } @@ -344,14 +344,14 @@ void BossRush_InitSave() { gSaveContext.playerName[i] = brPlayerName[i]; } - gSaveContext.questId = QUEST_BOSSRUSH; - gSaveContext.isBossRushPaused = 1; + gSaveContext.ship.quest.id = QUEST_BOSSRUSH; + gSaveContext.ship.quest.data.bossRush.isPaused = true; gSaveContext.entranceIndex = ENTR_CHAMBER_OF_THE_SAGES_0; gSaveContext.cutsceneIndex = 0x8000; gSaveContext.isMagicAcquired = 1; // Set magic - if (gSaveContext.bossRushOptions[BR_OPTIONS_MAGIC] == BR_CHOICE_MAGIC_SINGLE) { + if (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_MAGIC] == BR_CHOICE_MAGIC_SINGLE) { gSaveContext.magicLevel = 1; gSaveContext.magic = 48; } else { @@ -362,7 +362,7 @@ void BossRush_InitSave() { // Set health u16 health = 16; - switch (gSaveContext.bossRushOptions[BR_OPTIONS_HEARTS]) { + switch (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_HEARTS]) { case BR_CHOICE_HEARTS_7: health *= 7; break; @@ -399,8 +399,9 @@ void BossRush_InitSave() { gSaveContext.eventChkInf[7] |= 0x80; // bongo bongo // Sets all rando flags to false - for (s32 i = 0; i < ARRAY_COUNT(gSaveContext.randomizerInf); i++) { - gSaveContext.randomizerInf[i] = 0; + // Boss Rush currently uses 2 randomizer flags (RAND_INF_DUNGEONS_DONE_SPIRIT_TEMPLE & RAND_INF_DUNGEONS_DONE_SHADOW_TEMPLE) + for (s32 i = 0; i < ARRAY_COUNT(gSaveContext.ship.randomizerInf); i++) { + gSaveContext.ship.randomizerInf[i] = 0; } // Set items @@ -411,11 +412,11 @@ void BossRush_InitSave() { ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE, }; - if (gSaveContext.bossRushOptions[BR_OPTIONS_LONGSHOT] == BR_CHOICE_LONGSHOT_YES) { + if (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_LONGSHOT] == BR_CHOICE_LONGSHOT_YES) { brItems[9] = ITEM_LONGSHOT; } - switch (gSaveContext.bossRushOptions[BR_OPTIONS_BOTTLE]) { + switch (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_BOTTLE]) { case BR_CHOICE_BOTTLE_EMPTY: brItems[18] = ITEM_BOTTLE; break; @@ -435,7 +436,7 @@ void BossRush_InitSave() { break; } - if (gSaveContext.bossRushOptions[BR_OPTIONS_BUNNYHOOD] == BR_CHOICE_BUNNYHOOD_YES) { + if (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_BUNNYHOOD] == BR_CHOICE_BUNNYHOOD_YES) { brItems[23] = ITEM_MASK_BUNNY; } @@ -446,9 +447,9 @@ void BossRush_InitSave() { // Set consumable counts std::array brAmmo = { 5, 5, 10, 10, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - if (gSaveContext.bossRushOptions[BR_OPTIONS_AMMO] == BR_CHOICE_AMMO_FULL) { + if (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_AMMO] == BR_CHOICE_AMMO_FULL) { brAmmo = { 10, 20, 20, 30, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - } else if (gSaveContext.bossRushOptions[BR_OPTIONS_AMMO] == BR_CHOICE_AMMO_MAXED) { + } else if (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_AMMO] == BR_CHOICE_AMMO_MAXED) { brAmmo = { 30, 40, 40, 50, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; } @@ -462,17 +463,17 @@ void BossRush_InitSave() { gSaveContext.inventory.equipment |= 1 << 4; // Deku Shield gSaveContext.inventory.equipment |= 1 << 6; // Mirror Shield gSaveContext.inventory.equipment |= 1 << 9; // Goron Tunic - if (gSaveContext.bossRushOptions[BR_OPTIONS_BGS] == BR_CHOICE_BGS_YES) { + if (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_BGS] == BR_CHOICE_BGS_YES) { gSaveContext.inventory.equipment |= 1 << 2; // Biggoron Sword gSaveContext.bgsFlag = 1; } - if (gSaveContext.bossRushOptions[BR_OPTIONS_HOVERBOOTS] == BR_CHOICE_HOVERBOOTS_YES) { + if (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_HOVERBOOTS] == BR_CHOICE_HOVERBOOTS_YES) { gSaveContext.inventory.equipment |= 1 << 14; // Hover Boots } // Upgrades u8 upgradeLevel = 1; - if (gSaveContext.bossRushOptions[BR_OPTIONS_AMMO] == BR_CHOICE_AMMO_MAXED) { + if (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_AMMO] == BR_CHOICE_AMMO_MAXED) { upgradeLevel = 3; } Inventory_ChangeUpgrade(UPG_QUIVER, upgradeLevel); @@ -483,12 +484,12 @@ void BossRush_InitSave() { Inventory_ChangeUpgrade(UPG_STRENGTH, 1); // Set flags and Link's age based on chosen settings. - if (gSaveContext.bossRushOptions[BR_OPTIONS_BOSSES] == BR_CHOICE_BOSSES_ADULT || - gSaveContext.bossRushOptions[BR_OPTIONS_BOSSES] == BR_CHOICE_BOSSES_GANONDORF_GANON) { + if (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_BOSSES] == BR_CHOICE_BOSSES_ADULT || + gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_BOSSES] == BR_CHOICE_BOSSES_GANONDORF_GANON) { Flags_SetEventChkInf(EVENTCHKINF_USED_DEKU_TREE_BLUE_WARP); Flags_SetEventChkInf(EVENTCHKINF_USED_DODONGOS_CAVERN_BLUE_WARP); Flags_SetEventChkInf(EVENTCHKINF_USED_JABU_JABUS_BELLY_BLUE_WARP); - if (gSaveContext.bossRushOptions[BR_OPTIONS_BOSSES] == BR_CHOICE_BOSSES_GANONDORF_GANON) { + if (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_BOSSES] == BR_CHOICE_BOSSES_GANONDORF_GANON) { Flags_SetEventChkInf(EVENTCHKINF_USED_FOREST_TEMPLE_BLUE_WARP); Flags_SetEventChkInf(EVENTCHKINF_USED_FIRE_TEMPLE_BLUE_WARP); Flags_SetEventChkInf(EVENTCHKINF_USED_WATER_TEMPLE_BLUE_WARP); @@ -516,7 +517,7 @@ void BossRush_OnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li switch (id) { // Allow not healing before ganon case VB_GANON_HEAL_BEFORE_FIGHT: { - if (gSaveContext.bossRushOptions[BR_OPTIONS_HEAL] == BR_CHOICE_HEAL_NEVER) { + if (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_HEAL] == BR_CHOICE_HEAL_NEVER) { *should = false; } break; @@ -669,7 +670,7 @@ void BossRush_OnActorInitHandler(void* actorRef) { void BossRush_OnSceneInitHandler(s16 sceneNum) { // Unpause the timer when the scene loaded isn't the Chamber of Sages. if (sceneNum != SCENE_CHAMBER_OF_THE_SAGES) { - gSaveContext.isBossRushPaused = 0; + gSaveContext.ship.quest.data.bossRush.isPaused = false; } } diff --git a/soh/soh/Enhancements/debugconsole.cpp b/soh/soh/Enhancements/debugconsole.cpp index 76f903eb1..580fafc14 100644 --- a/soh/soh/Enhancements/debugconsole.cpp +++ b/soh/soh/Enhancements/debugconsole.cpp @@ -470,7 +470,7 @@ static bool FWHandler(std::shared_ptr Console, const std::vector< break; case 2: //backup if (CVarGetInteger(CVAR_ENHANCEMENT("BetterFarore"), 0)) { - gSaveContext.fw = gSaveContext.backupFW; + gSaveContext.fw = gSaveContext.ship.backupFW; gSaveContext.fw.set = 1; INFO_MESSAGE("[SOH] Backup FW data copied! Reload scene to take effect."); return 0; diff --git a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp index 83fe7f676..5fedd54be 100644 --- a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp +++ b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp @@ -314,7 +314,7 @@ void DrawInfoTab() { UIWidgets::InsertHelpHoverText("Z-Targeting behavior"); if (IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_TRIFORCE_HUNT)) { - ImGui::InputScalar("Triforce Pieces", ImGuiDataType_U8, &gSaveContext.triforcePiecesCollected); + ImGui::InputScalar("Triforce Pieces", ImGuiDataType_U8, &gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected); UIWidgets::InsertHelpHoverText("Currently obtained Triforce Pieces. For Triforce Hunt."); } @@ -416,17 +416,17 @@ void DrawBGSItemFlag(uint8_t itemID) { ImGui::Image(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(slotEntry.name), ImVec2(32.0f, 32.0f), ImVec2(0, 0), ImVec2(1, 1)); ImGui::SameLine(); int tradeIndex = itemID - ITEM_POCKET_EGG; - bool hasItem = (gSaveContext.adultTradeItems & (1 << tradeIndex)) != 0; + bool hasItem = (gSaveContext.ship.quest.data.randomizer.adultTradeItems & (1 << tradeIndex)) != 0; bool shouldHaveItem = hasItem; ImGui::Checkbox(("##adultTradeFlag" + std::to_string(itemID)).c_str(), &shouldHaveItem); if (hasItem != shouldHaveItem) { if (shouldHaveItem) { - gSaveContext.adultTradeItems |= (1 << tradeIndex); + gSaveContext.ship.quest.data.randomizer.adultTradeItems |= (1 << tradeIndex); if (INV_CONTENT(ITEM_TRADE_ADULT) == ITEM_NONE) { INV_CONTENT(ITEM_TRADE_ADULT) = ITEM_POCKET_EGG + tradeIndex; } } else { - gSaveContext.adultTradeItems &= ~(1 << tradeIndex); + gSaveContext.ship.quest.data.randomizer.adultTradeItems &= ~(1 << tradeIndex); Inventory_ReplaceItem(gPlayState, itemID, Randomizer_GetNextAdultTradeItem()); } } @@ -477,7 +477,7 @@ void DrawInventoryTab() { if (ImGui::Button("##itemNonePicker", ImVec2(32.0f, 32.0f))) { gSaveContext.inventory.items[selectedIndex] = ITEM_NONE; if (selectedIndex == SLOT_TRADE_ADULT) { - gSaveContext.adultTradeItems = 0; + gSaveContext.ship.quest.data.randomizer.adultTradeItems = 0; } ImGui::CloseCurrentPopup(); } @@ -517,7 +517,7 @@ void DrawInventoryTab() { OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_ADULT_TRADE) && selectedIndex == SLOT_TRADE_ADULT && slotEntry.id >= ITEM_POCKET_EGG && slotEntry.id <= ITEM_CLAIM_CHECK) { - gSaveContext.adultTradeItems |= ADULT_TRADE_FLAG(slotEntry.id); + gSaveContext.ship.quest.data.randomizer.adultTradeItems |= ADULT_TRADE_FLAG(slotEntry.id); } ImGui::CloseCurrentPopup(); } @@ -923,7 +923,7 @@ void DrawFlagsTab() { DrawFlagTableArray16(flagTable, j, gSaveContext.eventInf[j]); break; case RANDOMIZER_INF: - DrawFlagTableArray16(flagTable, j, gSaveContext.randomizerInf[j]); + DrawFlagTableArray16(flagTable, j, gSaveContext.ship.randomizerInf[j]); break; } }); @@ -1305,7 +1305,7 @@ void DrawQuestStatusTab() { ImGui::Image(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(itemMapping[ITEM_KEY_SMALL].name), ImVec2(lineHeight, lineHeight)); ImGui::SameLine(); if (ImGui::InputScalar("##Keys", ImGuiDataType_S8, gSaveContext.inventory.dungeonKeys + dungeonItemsScene)) { - gSaveContext.sohStats.dungeonKeys[dungeonItemsScene] = gSaveContext.inventory.dungeonKeys[dungeonItemsScene]; + gSaveContext.ship.stats.dungeonKeys[dungeonItemsScene] = gSaveContext.inventory.dungeonKeys[dungeonItemsScene]; }; } else { // dungeonItems is size 20 but dungeonKeys is size 19, so there are no keys for the last scene (Barinade's Lair) diff --git a/soh/soh/Enhancements/enemyrandomizer.cpp b/soh/soh/Enhancements/enemyrandomizer.cpp index 89aab7e00..73042b25f 100644 --- a/soh/soh/Enhancements/enemyrandomizer.cpp +++ b/soh/soh/Enhancements/enemyrandomizer.cpp @@ -305,7 +305,7 @@ EnemyEntry GetRandomizedEnemyEntry(uint32_t seed) { GetSelectedEnemies(); } if (CVarGetInteger(CVAR_ENHANCEMENT("RandomizedEnemies"), ENEMY_RANDOMIZER_OFF) == ENEMY_RANDOMIZER_RANDOM_SEEDED) { - uint32_t finalSeed = seed + (IS_RANDO ? Rando::Context::GetInstance()->GetSettings()->GetSeed() : gSaveContext.sohStats.fileCreatedAt); + uint32_t finalSeed = seed + (IS_RANDO ? Rando::Context::GetInstance()->GetSettings()->GetSeed() : gSaveContext.ship.stats.fileCreatedAt); Random_Init(finalSeed); uint32_t randomNumber = Random(0, RANDOMIZED_ENEMY_SPAWN_TABLE_SIZE); return selectedEnemyList[randomNumber]; diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_RawAction.cpp b/soh/soh/Enhancements/game-interactor/GameInteractor_RawAction.cpp index bb04e72b8..aa8c72d00 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor_RawAction.cpp +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_RawAction.cpp @@ -238,7 +238,12 @@ void GameInteractor::RawAction::SetFlag(int16_t flagType, int16_t flag) { gSaveContext.eventInf[flag >> 4] |= (1 << (flag & 0xF)); break; case FlagType::FLAG_RANDOMIZER_INF: - gSaveContext.randomizerInf[flag >> 4] |= (1 << (flag & 0xF)); + if (!IS_RANDO) { + LUSLOG_ERROR("Tried to set randomizerInf flag outside of rando (%d)", flag); + assert(false); + break; + } + gSaveContext.ship.randomizerInf[flag >> 4] |= (1 << (flag & 0xF)); break; case FlagType::FLAG_GS_TOKEN: SET_GS_FLAGS((flag & 0x1F00) >> 8, flag & 0xFF); @@ -261,7 +266,12 @@ void GameInteractor::RawAction::UnsetFlag(int16_t flagType, int16_t flag) { gSaveContext.eventInf[flag >> 4] &= ~(1 << (flag & 0xF)); break; case FlagType::FLAG_RANDOMIZER_INF: - gSaveContext.randomizerInf[flag >> 4] &= ~(1 << (flag & 0xF)); + if (!IS_RANDO) { + LUSLOG_ERROR("Tried to unset randomizerInf flag outside of rando (%d)", flag); + assert(false); + break; + } + gSaveContext.ship.randomizerInf[flag >> 4] &= ~(1 << (flag & 0xF)); break; } }; diff --git a/soh/soh/Enhancements/gameplaystats.cpp b/soh/soh/Enhancements/gameplaystats.cpp index 3f7691741..ddff16c7d 100644 --- a/soh/soh/Enhancements/gameplaystats.cpp +++ b/soh/soh/Enhancements/gameplaystats.cpp @@ -252,7 +252,7 @@ typedef struct { // Timestamps are an array of structs, each with a name, time, and color // Names and colors are set up at the bottom of this file -// Times are stored in gSaveContext.sohStats.itemTimestamp +// Times are stored in gSaveContext.ship.stats.itemTimestamp TimestampInfo itemTimestampDisplay[TIMESTAMP_MAX]; TimestampInfo sceneTimestampDisplay[8191]; //std::vector sceneTimestampDisplay; @@ -287,25 +287,25 @@ extern "C" char* GameplayStats_GetCurrentTime() { } void LoadStatsVersion1() { - SaveManager::Instance->LoadCharArray("buildVersion", gSaveContext.sohStats.buildVersion, - ARRAY_COUNT(gSaveContext.sohStats.buildVersion)); - SaveManager::Instance->LoadData("buildVersionMajor", gSaveContext.sohStats.buildVersionMajor); - SaveManager::Instance->LoadData("buildVersionMinor", gSaveContext.sohStats.buildVersionMinor); - SaveManager::Instance->LoadData("buildVersionPatch", gSaveContext.sohStats.buildVersionPatch); + SaveManager::Instance->LoadCharArray("buildVersion", gSaveContext.ship.stats.buildVersion, + ARRAY_COUNT(gSaveContext.ship.stats.buildVersion)); + SaveManager::Instance->LoadData("buildVersionMajor", gSaveContext.ship.stats.buildVersionMajor); + SaveManager::Instance->LoadData("buildVersionMinor", gSaveContext.ship.stats.buildVersionMinor); + SaveManager::Instance->LoadData("buildVersionPatch", gSaveContext.ship.stats.buildVersionPatch); - SaveManager::Instance->LoadData("heartPieces", gSaveContext.sohStats.heartPieces); - SaveManager::Instance->LoadData("heartContainers", gSaveContext.sohStats.heartContainers); - SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.sohStats.dungeonKeys), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.dungeonKeys[i]); + SaveManager::Instance->LoadData("heartPieces", gSaveContext.ship.stats.heartPieces); + SaveManager::Instance->LoadData("heartContainers", gSaveContext.ship.stats.heartContainers); + SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.ship.stats.dungeonKeys), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.stats.dungeonKeys[i]); }); - SaveManager::Instance->LoadData("rtaTiming", gSaveContext.sohStats.rtaTiming); - SaveManager::Instance->LoadData("fileCreatedAt", gSaveContext.sohStats.fileCreatedAt); - SaveManager::Instance->LoadData("playTimer", gSaveContext.sohStats.playTimer); - SaveManager::Instance->LoadData("pauseTimer", gSaveContext.sohStats.pauseTimer); - SaveManager::Instance->LoadArray("itemTimestamps", ARRAY_COUNT(gSaveContext.sohStats.itemTimestamp), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.itemTimestamp[i]); + SaveManager::Instance->LoadData("rtaTiming", gSaveContext.ship.stats.rtaTiming); + SaveManager::Instance->LoadData("fileCreatedAt", gSaveContext.ship.stats.fileCreatedAt); + SaveManager::Instance->LoadData("playTimer", gSaveContext.ship.stats.playTimer); + SaveManager::Instance->LoadData("pauseTimer", gSaveContext.ship.stats.pauseTimer); + SaveManager::Instance->LoadArray("itemTimestamps", ARRAY_COUNT(gSaveContext.ship.stats.itemTimestamp), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.stats.itemTimestamp[i]); }); - SaveManager::Instance->LoadArray("sceneTimestamps", ARRAY_COUNT(gSaveContext.sohStats.sceneTimestamps), [&](size_t i) { + SaveManager::Instance->LoadArray("sceneTimestamps", ARRAY_COUNT(gSaveContext.ship.stats.sceneTimestamps), [&](size_t i) { SaveManager::Instance->LoadStruct("", [&]() { int scene, room, sceneTime, roomTime, isRoom; SaveManager::Instance->LoadData("scene", scene); @@ -316,63 +316,63 @@ void LoadStatsVersion1() { if (scene == 0 && room == 0 && sceneTime == 0 && roomTime == 0 && isRoom == 0) { return; } - gSaveContext.sohStats.sceneTimestamps[i].scene = scene; - gSaveContext.sohStats.sceneTimestamps[i].room = room; - gSaveContext.sohStats.sceneTimestamps[i].sceneTime = sceneTime; - gSaveContext.sohStats.sceneTimestamps[i].roomTime = roomTime; - gSaveContext.sohStats.sceneTimestamps[i].isRoom = isRoom; + gSaveContext.ship.stats.sceneTimestamps[i].scene = scene; + gSaveContext.ship.stats.sceneTimestamps[i].room = room; + gSaveContext.ship.stats.sceneTimestamps[i].sceneTime = sceneTime; + gSaveContext.ship.stats.sceneTimestamps[i].roomTime = roomTime; + gSaveContext.ship.stats.sceneTimestamps[i].isRoom = isRoom; }); }); - SaveManager::Instance->LoadData("tsIdx", gSaveContext.sohStats.tsIdx); - SaveManager::Instance->LoadArray("counts", ARRAY_COUNT(gSaveContext.sohStats.count), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.count[i]); + SaveManager::Instance->LoadData("tsIdx", gSaveContext.ship.stats.tsIdx); + SaveManager::Instance->LoadArray("counts", ARRAY_COUNT(gSaveContext.ship.stats.count), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.stats.count[i]); }); - SaveManager::Instance->LoadArray("scenesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.scenesDiscovered), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.scenesDiscovered[i]); + SaveManager::Instance->LoadArray("scenesDiscovered", ARRAY_COUNT(gSaveContext.ship.stats.scenesDiscovered), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.stats.scenesDiscovered[i]); }); - SaveManager::Instance->LoadArray("entrancesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.entrancesDiscovered), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.entrancesDiscovered[i]); + SaveManager::Instance->LoadArray("entrancesDiscovered", ARRAY_COUNT(gSaveContext.ship.stats.entrancesDiscovered), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.stats.entrancesDiscovered[i]); }); } void SaveStats(SaveContext* saveContext, int sectionID, bool fullSave) { - SaveManager::Instance->SaveData("buildVersion", saveContext->sohStats.buildVersion); - SaveManager::Instance->SaveData("buildVersionMajor", saveContext->sohStats.buildVersionMajor); - SaveManager::Instance->SaveData("buildVersionMinor", saveContext->sohStats.buildVersionMinor); - SaveManager::Instance->SaveData("buildVersionPatch", saveContext->sohStats.buildVersionPatch); + SaveManager::Instance->SaveData("buildVersion", saveContext->ship.stats.buildVersion); + SaveManager::Instance->SaveData("buildVersionMajor", saveContext->ship.stats.buildVersionMajor); + SaveManager::Instance->SaveData("buildVersionMinor", saveContext->ship.stats.buildVersionMinor); + SaveManager::Instance->SaveData("buildVersionPatch", saveContext->ship.stats.buildVersionPatch); - SaveManager::Instance->SaveData("heartPieces", saveContext->sohStats.heartPieces); - SaveManager::Instance->SaveData("heartContainers", saveContext->sohStats.heartContainers); - SaveManager::Instance->SaveArray("dungeonKeys", ARRAY_COUNT(saveContext->sohStats.dungeonKeys), [&](size_t i) { - SaveManager::Instance->SaveData("", saveContext->sohStats.dungeonKeys[i]); + SaveManager::Instance->SaveData("heartPieces", saveContext->ship.stats.heartPieces); + SaveManager::Instance->SaveData("heartContainers", saveContext->ship.stats.heartContainers); + SaveManager::Instance->SaveArray("dungeonKeys", ARRAY_COUNT(saveContext->ship.stats.dungeonKeys), [&](size_t i) { + SaveManager::Instance->SaveData("", saveContext->ship.stats.dungeonKeys[i]); }); - SaveManager::Instance->SaveData("rtaTiming", saveContext->sohStats.rtaTiming); - SaveManager::Instance->SaveData("fileCreatedAt", saveContext->sohStats.fileCreatedAt); - SaveManager::Instance->SaveData("playTimer", saveContext->sohStats.playTimer); - SaveManager::Instance->SaveData("pauseTimer", saveContext->sohStats.pauseTimer); - SaveManager::Instance->SaveArray("itemTimestamps", ARRAY_COUNT(saveContext->sohStats.itemTimestamp), [&](size_t i) { - SaveManager::Instance->SaveData("", saveContext->sohStats.itemTimestamp[i]); + SaveManager::Instance->SaveData("rtaTiming", saveContext->ship.stats.rtaTiming); + SaveManager::Instance->SaveData("fileCreatedAt", saveContext->ship.stats.fileCreatedAt); + SaveManager::Instance->SaveData("playTimer", saveContext->ship.stats.playTimer); + SaveManager::Instance->SaveData("pauseTimer", saveContext->ship.stats.pauseTimer); + SaveManager::Instance->SaveArray("itemTimestamps", ARRAY_COUNT(saveContext->ship.stats.itemTimestamp), [&](size_t i) { + SaveManager::Instance->SaveData("", saveContext->ship.stats.itemTimestamp[i]); }); - SaveManager::Instance->SaveArray("sceneTimestamps", ARRAY_COUNT(saveContext->sohStats.sceneTimestamps), [&](size_t i) { - if (saveContext->sohStats.sceneTimestamps[i].scene != 254 && saveContext->sohStats.sceneTimestamps[i].room != 254) { + SaveManager::Instance->SaveArray("sceneTimestamps", ARRAY_COUNT(saveContext->ship.stats.sceneTimestamps), [&](size_t i) { + if (saveContext->ship.stats.sceneTimestamps[i].scene != 254 && saveContext->ship.stats.sceneTimestamps[i].room != 254) { SaveManager::Instance->SaveStruct("", [&]() { - SaveManager::Instance->SaveData("scene", saveContext->sohStats.sceneTimestamps[i].scene); - SaveManager::Instance->SaveData("room", saveContext->sohStats.sceneTimestamps[i].room); - SaveManager::Instance->SaveData("sceneTime", saveContext->sohStats.sceneTimestamps[i].sceneTime); - SaveManager::Instance->SaveData("roomTime", saveContext->sohStats.sceneTimestamps[i].roomTime); - SaveManager::Instance->SaveData("isRoom", saveContext->sohStats.sceneTimestamps[i].isRoom); + SaveManager::Instance->SaveData("scene", saveContext->ship.stats.sceneTimestamps[i].scene); + SaveManager::Instance->SaveData("room", saveContext->ship.stats.sceneTimestamps[i].room); + SaveManager::Instance->SaveData("sceneTime", saveContext->ship.stats.sceneTimestamps[i].sceneTime); + SaveManager::Instance->SaveData("roomTime", saveContext->ship.stats.sceneTimestamps[i].roomTime); + SaveManager::Instance->SaveData("isRoom", saveContext->ship.stats.sceneTimestamps[i].isRoom); }); } }); - SaveManager::Instance->SaveData("tsIdx", saveContext->sohStats.tsIdx); - SaveManager::Instance->SaveArray("counts", ARRAY_COUNT(saveContext->sohStats.count), [&](size_t i) { - SaveManager::Instance->SaveData("", saveContext->sohStats.count[i]); + SaveManager::Instance->SaveData("tsIdx", saveContext->ship.stats.tsIdx); + SaveManager::Instance->SaveArray("counts", ARRAY_COUNT(saveContext->ship.stats.count), [&](size_t i) { + SaveManager::Instance->SaveData("", saveContext->ship.stats.count[i]); }); - SaveManager::Instance->SaveArray("scenesDiscovered", ARRAY_COUNT(saveContext->sohStats.scenesDiscovered), [&](size_t i) { - SaveManager::Instance->SaveData("", saveContext->sohStats.scenesDiscovered[i]); + SaveManager::Instance->SaveArray("scenesDiscovered", ARRAY_COUNT(saveContext->ship.stats.scenesDiscovered), [&](size_t i) { + SaveManager::Instance->SaveData("", saveContext->ship.stats.scenesDiscovered[i]); }); - SaveManager::Instance->SaveArray("entrancesDiscovered", ARRAY_COUNT(saveContext->sohStats.entrancesDiscovered), [&](size_t i) { - SaveManager::Instance->SaveData("", saveContext->sohStats.entrancesDiscovered[i]); + SaveManager::Instance->SaveArray("entrancesDiscovered", ARRAY_COUNT(saveContext->ship.stats.entrancesDiscovered), [&](size_t i) { + SaveManager::Instance->SaveData("", saveContext->ship.stats.entrancesDiscovered[i]); }); } @@ -443,16 +443,16 @@ void DrawGameplayStatsHeader() { } else { GameplayStatsRow("Build Version:", (char*)gBuildVersion); } - if (gSaveContext.sohStats.rtaTiming) { - GameplayStatsRow("Total Time (RTA):", formatTimestampGameplayStat(GAMEPLAYSTAT_TOTAL_TIME), gSaveContext.sohStats.gameComplete ? COLOR_GREEN : COLOR_WHITE); + if (gSaveContext.ship.stats.rtaTiming) { + GameplayStatsRow("Total Time (RTA):", formatTimestampGameplayStat(GAMEPLAYSTAT_TOTAL_TIME), gSaveContext.ship.stats.gameComplete ? COLOR_GREEN : COLOR_WHITE); } else { - GameplayStatsRow("Total Game Time:", formatTimestampGameplayStat(GAMEPLAYSTAT_TOTAL_TIME), gSaveContext.sohStats.gameComplete ? COLOR_GREEN : COLOR_WHITE); + GameplayStatsRow("Total Game Time:", formatTimestampGameplayStat(GAMEPLAYSTAT_TOTAL_TIME), gSaveContext.ship.stats.gameComplete ? COLOR_GREEN : COLOR_WHITE); } if (CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.ShowAdditionalTimers"), 0)) { // !Only display total game time - GameplayStatsRow("Gameplay Time:", formatTimestampGameplayStat(gSaveContext.sohStats.playTimer / 2), COLOR_GREY); - GameplayStatsRow("Pause Menu Time:", formatTimestampGameplayStat(gSaveContext.sohStats.pauseTimer / 3), COLOR_GREY); - GameplayStatsRow("Time in scene:", formatTimestampGameplayStat(gSaveContext.sohStats.sceneTimer / 2), COLOR_LIGHT_BLUE); - GameplayStatsRow("Time in room:", formatTimestampGameplayStat(gSaveContext.sohStats.roomTimer / 2), COLOR_LIGHT_BLUE); + GameplayStatsRow("Gameplay Time:", formatTimestampGameplayStat(gSaveContext.ship.stats.playTimer / 2), COLOR_GREY); + GameplayStatsRow("Pause Menu Time:", formatTimestampGameplayStat(gSaveContext.ship.stats.pauseTimer / 3), COLOR_GREY); + GameplayStatsRow("Time in scene:", formatTimestampGameplayStat(gSaveContext.ship.stats.sceneTimer / 2), COLOR_LIGHT_BLUE); + GameplayStatsRow("Time in room:", formatTimestampGameplayStat(gSaveContext.ship.stats.roomTimer / 2), COLOR_LIGHT_BLUE); } if (gPlayState != NULL && CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.ShowDebugInfo"), 0)) { // && display debug info GameplayStatsRow("play->sceneNum:", formatHexGameplayStat(gPlayState->sceneNum), COLOR_YELLOW); @@ -468,7 +468,7 @@ void DrawGameplayStatsTimestampsTab() { // Set up the array of item timestamps and then sort it chronologically for (int i = 0; i < TIMESTAMP_MAX; i++) { strcpy(itemTimestampDisplay[i].name, itemTimestampDisplayName[i]); - itemTimestampDisplay[i].time = gSaveContext.sohStats.itemTimestamp[i]; + itemTimestampDisplay[i].time = gSaveContext.ship.stats.itemTimestamp[i]; itemTimestampDisplay[i].color = itemTimestampDisplayColor[i]; } @@ -497,18 +497,18 @@ void DrawGameplayStatsCountsTab() { for (int i = COUNT_ENEMIES_DEFEATED_ANUBIS; i <= COUNT_ENEMIES_DEFEATED_WOLFOS; i++) { if (i == COUNT_ENEMIES_DEFEATED_FLOORMASTER) { // Special case: You must kill 3 mini Floormasters for it count as one defeated Floormaster - enemiesDefeated += gSaveContext.sohStats.count[i] / 3; + enemiesDefeated += gSaveContext.ship.stats.count[i] / 3; } else { - enemiesDefeated += gSaveContext.sohStats.count[i]; + enemiesDefeated += gSaveContext.ship.stats.count[i]; } } // Sum of all ammo used for (int i = COUNT_AMMO_USED_STICK; i <= COUNT_AMMO_USED_BEAN; i++) { - ammoUsed += gSaveContext.sohStats.count[i]; + ammoUsed += gSaveContext.ship.stats.count[i]; } // Sum of all button presses for (int i = COUNT_BUTTON_PRESSES_A; i <= COUNT_BUTTON_PRESSES_START; i++) { - buttonPresses += gSaveContext.sohStats.count[i]; + buttonPresses += gSaveContext.ship.stats.count[i]; } ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, { 4.0f, 4.0f }); @@ -520,47 +520,47 @@ void DrawGameplayStatsCountsTab() { if (ImGui::TreeNodeEx("Enemy Details...", ImGuiTreeNodeFlags_NoTreePushOnOpen)) { for (int i = COUNT_ENEMIES_DEFEATED_ANUBIS; i <= COUNT_ENEMIES_DEFEATED_WOLFOS; i++) { if (i == COUNT_ENEMIES_DEFEATED_FLOORMASTER) { - GameplayStatsRow(countMappings[i], formatIntGameplayStat(gSaveContext.sohStats.count[i] / 3)); + GameplayStatsRow(countMappings[i], formatIntGameplayStat(gSaveContext.ship.stats.count[i] / 3)); } else { - GameplayStatsRow(countMappings[i], formatIntGameplayStat(gSaveContext.sohStats.count[i])); + GameplayStatsRow(countMappings[i], formatIntGameplayStat(gSaveContext.ship.stats.count[i])); } } } } - GameplayStatsRow("Rupees Collected:", formatIntGameplayStat(gSaveContext.sohStats.count[COUNT_RUPEES_COLLECTED])); + GameplayStatsRow("Rupees Collected:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_RUPEES_COLLECTED])); UIWidgets::Tooltip("Includes rupees collected with a full wallet."); - GameplayStatsRow("Rupees Spent:", formatIntGameplayStat(gSaveContext.sohStats.count[COUNT_RUPEES_SPENT])); - GameplayStatsRow("Chests Opened:", formatIntGameplayStat(gSaveContext.sohStats.count[COUNT_CHESTS_OPENED])); + GameplayStatsRow("Rupees Spent:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_RUPEES_SPENT])); + GameplayStatsRow("Chests Opened:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_CHESTS_OPENED])); GameplayStatsRow("Ammo Used:", formatIntGameplayStat(ammoUsed)); if (ammoUsed > 0) { ImGui::TableNextRow(); ImGui::TableNextColumn(); if (ImGui::TreeNodeEx("Ammo Details...", ImGuiTreeNodeFlags_NoTreePushOnOpen)) { for (int i = COUNT_AMMO_USED_STICK; i <= COUNT_AMMO_USED_BEAN; i++) { - GameplayStatsRow(countMappings[i], formatIntGameplayStat(gSaveContext.sohStats.count[i])); + GameplayStatsRow(countMappings[i], formatIntGameplayStat(gSaveContext.ship.stats.count[i])); } } } - GameplayStatsRow("Damage Taken:", formatIntGameplayStat(gSaveContext.sohStats.count[COUNT_DAMAGE_TAKEN])); - GameplayStatsRow("Sword Swings:", formatIntGameplayStat(gSaveContext.sohStats.count[COUNT_SWORD_SWINGS])); - GameplayStatsRow("Steps Taken:", formatIntGameplayStat(gSaveContext.sohStats.count[COUNT_STEPS])); + GameplayStatsRow("Damage Taken:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_DAMAGE_TAKEN])); + GameplayStatsRow("Sword Swings:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_SWORD_SWINGS])); + GameplayStatsRow("Steps Taken:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_STEPS])); // If using MM Bunny Hood enhancement, show how long it's been equipped (not counting pause time) - if (CVarGetInteger(CVAR_ENHANCEMENT("MMBunnyHood"), BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA || gSaveContext.sohStats.count[COUNT_TIME_BUNNY_HOOD] > 0) { - GameplayStatsRow("Bunny Hood Time:", formatTimestampGameplayStat(gSaveContext.sohStats.count[COUNT_TIME_BUNNY_HOOD] / 2)); + if (CVarGetInteger(CVAR_ENHANCEMENT("MMBunnyHood"), BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA || gSaveContext.ship.stats.count[COUNT_TIME_BUNNY_HOOD] > 0) { + GameplayStatsRow("Bunny Hood Time:", formatTimestampGameplayStat(gSaveContext.ship.stats.count[COUNT_TIME_BUNNY_HOOD] / 2)); } - GameplayStatsRow("Rolls:", formatIntGameplayStat(gSaveContext.sohStats.count[COUNT_ROLLS])); - GameplayStatsRow("Bonks:", formatIntGameplayStat(gSaveContext.sohStats.count[COUNT_BONKS])); - GameplayStatsRow("Sidehops:", formatIntGameplayStat(gSaveContext.sohStats.count[COUNT_SIDEHOPS])); - GameplayStatsRow("Backflips:", formatIntGameplayStat(gSaveContext.sohStats.count[COUNT_BACKFLIPS])); - GameplayStatsRow("Ice Traps:", formatIntGameplayStat(gSaveContext.sohStats.count[COUNT_ICE_TRAPS])); - GameplayStatsRow("Pauses:", formatIntGameplayStat(gSaveContext.sohStats.count[COUNT_PAUSES])); - GameplayStatsRow("Pots Smashed:", formatIntGameplayStat(gSaveContext.sohStats.count[COUNT_POTS_BROKEN])); - GameplayStatsRow("Bushes Cut:", formatIntGameplayStat(gSaveContext.sohStats.count[COUNT_BUSHES_CUT])); + GameplayStatsRow("Rolls:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_ROLLS])); + GameplayStatsRow("Bonks:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_BONKS])); + GameplayStatsRow("Sidehops:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_SIDEHOPS])); + GameplayStatsRow("Backflips:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_BACKFLIPS])); + GameplayStatsRow("Ice Traps:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_ICE_TRAPS])); + GameplayStatsRow("Pauses:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_PAUSES])); + GameplayStatsRow("Pots Smashed:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_POTS_BROKEN])); + GameplayStatsRow("Bushes Cut:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_BUSHES_CUT])); GameplayStatsRow("Buttons Pressed:", formatIntGameplayStat(buttonPresses)); if (buttonPresses > 0) { ImGui::TableNextRow(); ImGui::TableNextColumn(); if (ImGui::TreeNodeEx("Buttons...", ImGuiTreeNodeFlags_NoTreePushOnOpen)) { for (int i = COUNT_BUTTON_PRESSES_A; i <= COUNT_BUTTON_PRESSES_START; i++) { - GameplayStatsRow(countMappings[i], formatIntGameplayStat(gSaveContext.sohStats.count[i])); + GameplayStatsRow(countMappings[i], formatIntGameplayStat(gSaveContext.ship.stats.count[i])); } } } @@ -569,25 +569,25 @@ void DrawGameplayStatsCountsTab() { } void DrawGameplayStatsBreakdownTab() { - for (int i = 0; i < gSaveContext.sohStats.tsIdx; i++) { - std::string sceneName = ResolveSceneID(gSaveContext.sohStats.sceneTimestamps[i].scene, gSaveContext.sohStats.sceneTimestamps[i].room); + for (int i = 0; i < gSaveContext.ship.stats.tsIdx; i++) { + std::string sceneName = ResolveSceneID(gSaveContext.ship.stats.sceneTimestamps[i].scene, gSaveContext.ship.stats.sceneTimestamps[i].room); std::string name; - if (CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.RoomBreakdown"), 0) && gSaveContext.sohStats.sceneTimestamps[i].scene != SCENE_GROTTOS) { - name = fmt::format("{:s} Room {:d}", sceneName, gSaveContext.sohStats.sceneTimestamps[i].room); + if (CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.RoomBreakdown"), 0) && gSaveContext.ship.stats.sceneTimestamps[i].scene != SCENE_GROTTOS) { + name = fmt::format("{:s} Room {:d}", sceneName, gSaveContext.ship.stats.sceneTimestamps[i].room); } else { name = sceneName; } strcpy(sceneTimestampDisplay[i].name, name.c_str()); - sceneTimestampDisplay[i].time = CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.RoomBreakdown"), 0) ? - gSaveContext.sohStats.sceneTimestamps[i].roomTime : gSaveContext.sohStats.sceneTimestamps[i].sceneTime; + sceneTimestampDisplay[i].time = CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.RoomBreakdown"), 0) ? + gSaveContext.ship.stats.sceneTimestamps[i].roomTime : gSaveContext.ship.stats.sceneTimestamps[i].sceneTime; sceneTimestampDisplay[i].color = COLOR_GREY; - sceneTimestampDisplay[i].isRoom = gSaveContext.sohStats.sceneTimestamps[i].isRoom; + sceneTimestampDisplay[i].isRoom = gSaveContext.ship.stats.sceneTimestamps[i].isRoom; } ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, { 4.0f, 4.0f }); ImGui::BeginTable("gameplayStatsCounts", 1, ImGuiTableFlags_BordersOuter); ImGui::TableSetupColumn("stat", ImGuiTableColumnFlags_WidthStretch); - for (int i = 0; i < gSaveContext.sohStats.tsIdx; i++) { + for (int i = 0; i < gSaveContext.ship.stats.tsIdx; i++) { TimestampInfo tsInfo = sceneTimestampDisplay[i]; bool canShow = !tsInfo.isRoom || CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.RoomBreakdown"), 0); if (tsInfo.time > 0 && strnlen(tsInfo.name, 40) > 1 && canShow) { @@ -595,10 +595,10 @@ void DrawGameplayStatsBreakdownTab() { } } std::string toPass; - if (CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.RoomBreakdown"), 0) && gSaveContext.sohStats.sceneNum != SCENE_GROTTOS) { - toPass = fmt::format("{:s} Room {:d}", ResolveSceneID(gSaveContext.sohStats.sceneNum, gSaveContext.sohStats.roomNum), gSaveContext.sohStats.roomNum); + if (CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.RoomBreakdown"), 0) && gSaveContext.ship.stats.sceneNum != SCENE_GROTTOS) { + toPass = fmt::format("{:s} Room {:d}", ResolveSceneID(gSaveContext.ship.stats.sceneNum, gSaveContext.ship.stats.roomNum), gSaveContext.ship.stats.roomNum); } else { - toPass = ResolveSceneID(gSaveContext.sohStats.sceneNum, gSaveContext.sohStats.roomNum); + toPass = ResolveSceneID(gSaveContext.ship.stats.sceneNum, gSaveContext.ship.stats.roomNum); } GameplayStatsRow(toPass.c_str(), formatTimestampGameplayStat(CURRENT_MODE_TIMER / 2)); ImGui::EndTable(); @@ -611,14 +611,14 @@ void DrawGameplayStatsOptionsTab() { UIWidgets::PaddedEnhancementCheckbox("Show latest timestamps on top", CVAR_ENHANCEMENT("GameplayStats.ReverseTimestamps"), true, false); UIWidgets::PaddedEnhancementCheckbox("Room Breakdown", CVAR_ENHANCEMENT("GameplayStats.RoomBreakdown"), true, false); ImGui::SameLine(); - UIWidgets::InsertHelpHoverText("Allows a more in-depth perspective of time spent in a certain map."); + UIWidgets::InsertHelpHoverText("Allows a more in-depth perspective of time spent in a certain map."); UIWidgets::PaddedEnhancementCheckbox("RTA Timing on new files", CVAR_ENHANCEMENT("GameplayStats.RTATiming"), true, false); ImGui::SameLine(); UIWidgets::InsertHelpHoverText( "Timestamps are relative to starting timestamp rather than in game time, usually necessary for races/speedruns.\n\n" "Starting timestamp is on first non-c-up input after intro cutscene.\n\n" "NOTE: THIS NEEDS TO BE SET BEFORE CREATING A FILE TO TAKE EFFECT" - ); + ); UIWidgets::PaddedEnhancementCheckbox("Show additional detail timers", CVAR_ENHANCEMENT("GameplayStats.ShowAdditionalTimers"), true, false); UIWidgets::PaddedEnhancementCheckbox("Show Debug Info", CVAR_ENHANCEMENT("GameplayStats.ShowDebugInfo")); } @@ -645,46 +645,46 @@ void GameplayStatsWindow::DrawElement() { } ImGui::EndTabBar(); } - + ImGui::Text("Note: Gameplay stats are saved to the current file and will be\nlost if you quit without saving."); } void InitStats(bool isDebug) { - gSaveContext.sohStats.heartPieces = isDebug ? 8 : 0; - gSaveContext.sohStats.heartContainers = isDebug ? 8 : 0; - for (int dungeon = 0; dungeon < ARRAY_COUNT(gSaveContext.sohStats.dungeonKeys); dungeon++) { - gSaveContext.sohStats.dungeonKeys[dungeon] = isDebug ? 8 : 0; + gSaveContext.ship.stats.heartPieces = isDebug ? 8 : 0; + gSaveContext.ship.stats.heartContainers = isDebug ? 8 : 0; + for (int dungeon = 0; dungeon < ARRAY_COUNT(gSaveContext.ship.stats.dungeonKeys); dungeon++) { + gSaveContext.ship.stats.dungeonKeys[dungeon] = isDebug ? 8 : 0; } - gSaveContext.sohStats.rtaTiming = CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.RTATiming"), 0); - gSaveContext.sohStats.fileCreatedAt = 0; - gSaveContext.sohStats.playTimer = 0; - gSaveContext.sohStats.pauseTimer = 0; - for (int timestamp = 0; timestamp < ARRAY_COUNT(gSaveContext.sohStats.itemTimestamp); timestamp++) { - gSaveContext.sohStats.itemTimestamp[timestamp] = 0; + gSaveContext.ship.stats.rtaTiming = CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.RTATiming"), 0); + gSaveContext.ship.stats.fileCreatedAt = 0; + gSaveContext.ship.stats.playTimer = 0; + gSaveContext.ship.stats.pauseTimer = 0; + for (int timestamp = 0; timestamp < ARRAY_COUNT(gSaveContext.ship.stats.itemTimestamp); timestamp++) { + gSaveContext.ship.stats.itemTimestamp[timestamp] = 0; } - for (int timestamp = 0; timestamp < ARRAY_COUNT(gSaveContext.sohStats.sceneTimestamps); timestamp++) { - gSaveContext.sohStats.sceneTimestamps[timestamp].sceneTime = 0; - gSaveContext.sohStats.sceneTimestamps[timestamp].roomTime = 0; - gSaveContext.sohStats.sceneTimestamps[timestamp].scene = 254; - gSaveContext.sohStats.sceneTimestamps[timestamp].room = 254; - gSaveContext.sohStats.sceneTimestamps[timestamp].isRoom = 0; + for (int timestamp = 0; timestamp < ARRAY_COUNT(gSaveContext.ship.stats.sceneTimestamps); timestamp++) { + gSaveContext.ship.stats.sceneTimestamps[timestamp].sceneTime = 0; + gSaveContext.ship.stats.sceneTimestamps[timestamp].roomTime = 0; + gSaveContext.ship.stats.sceneTimestamps[timestamp].scene = 254; + gSaveContext.ship.stats.sceneTimestamps[timestamp].room = 254; + gSaveContext.ship.stats.sceneTimestamps[timestamp].isRoom = 0; } - gSaveContext.sohStats.tsIdx = 0; - for (int count = 0; count < ARRAY_COUNT(gSaveContext.sohStats.count); count++) { - gSaveContext.sohStats.count[count] = 0; + gSaveContext.ship.stats.tsIdx = 0; + for (int count = 0; count < ARRAY_COUNT(gSaveContext.ship.stats.count); count++) { + gSaveContext.ship.stats.count[count] = 0; } - gSaveContext.sohStats.gameComplete = false; - for (int scenesIdx = 0; scenesIdx < ARRAY_COUNT(gSaveContext.sohStats.scenesDiscovered); scenesIdx++) { - gSaveContext.sohStats.scenesDiscovered[scenesIdx] = 0; + gSaveContext.ship.stats.gameComplete = false; + for (int scenesIdx = 0; scenesIdx < ARRAY_COUNT(gSaveContext.ship.stats.scenesDiscovered); scenesIdx++) { + gSaveContext.ship.stats.scenesDiscovered[scenesIdx] = 0; } - for (int entrancesIdx = 0; entrancesIdx < ARRAY_COUNT(gSaveContext.sohStats.entrancesDiscovered); entrancesIdx++) { - gSaveContext.sohStats.entrancesDiscovered[entrancesIdx] = 0; + for (int entrancesIdx = 0; entrancesIdx < ARRAY_COUNT(gSaveContext.ship.stats.entrancesDiscovered); entrancesIdx++) { + gSaveContext.ship.stats.entrancesDiscovered[entrancesIdx] = 0; } - SohUtils::CopyStringToCharArray(gSaveContext.sohStats.buildVersion, std::string((char*)gBuildVersion), - ARRAY_COUNT(gSaveContext.sohStats.buildVersion)); - gSaveContext.sohStats.buildVersionMajor = gBuildVersionMajor; - gSaveContext.sohStats.buildVersionMinor = gBuildVersionMinor; - gSaveContext.sohStats.buildVersionPatch = gBuildVersionPatch; + SohUtils::CopyStringToCharArray(gSaveContext.ship.stats.buildVersion, std::string((char*)gBuildVersion), + ARRAY_COUNT(gSaveContext.ship.stats.buildVersion)); + gSaveContext.ship.stats.buildVersionMajor = gBuildVersionMajor; + gSaveContext.ship.stats.buildVersionMinor = gBuildVersionMinor; + gSaveContext.ship.stats.buildVersionPatch = gBuildVersionPatch; } // Entries listed here will have a timestamp shown in the stat window diff --git a/soh/soh/Enhancements/gameplaystats.h b/soh/soh/Enhancements/gameplaystats.h index 9d41f2560..27d811b8a 100644 --- a/soh/soh/Enhancements/gameplaystats.h +++ b/soh/soh/Enhancements/gameplaystats.h @@ -19,14 +19,14 @@ extern "C" { // Total gameplay time is tracked in tenths of seconds // I.E. game time counts frames at 20fps/2, pause time counts frames at 30fps/3 // Frame counts in z_play.c and z_kaleido_scope_call.c -#define GAMEPLAYSTAT_TOTAL_TIME (gSaveContext.sohStats.rtaTiming ?\ - (!gSaveContext.sohStats.gameComplete ?\ - (!gSaveContext.sohStats.fileCreatedAt ? 0 : ((GetUnixTimestamp() - gSaveContext.sohStats.fileCreatedAt) / 100)) :\ - (gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_GANON])) :\ - (gSaveContext.sohStats.playTimer / 2 + gSaveContext.sohStats.pauseTimer / 3)) +#define GAMEPLAYSTAT_TOTAL_TIME (gSaveContext.ship.stats.rtaTiming ?\ + (!gSaveContext.ship.stats.gameComplete ?\ + (!gSaveContext.ship.stats.fileCreatedAt ? 0 : ((GetUnixTimestamp() - gSaveContext.ship.stats.fileCreatedAt) / 100)) :\ + (gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_DEFEAT_GANON])) :\ + (gSaveContext.ship.stats.playTimer / 2 + gSaveContext.ship.stats.pauseTimer / 3)) #define CURRENT_MODE_TIMER (CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.RoomBreakdown"), 0) ?\ - gSaveContext.sohStats.roomTimer :\ - gSaveContext.sohStats.sceneTimer) + gSaveContext.ship.stats.roomTimer :\ + gSaveContext.ship.stats.sceneTimer) void InitStatTracker(); diff --git a/soh/soh/Enhancements/kaleido.cpp b/soh/soh/Enhancements/kaleido.cpp index 36cf9d0a2..42c135c94 100644 --- a/soh/soh/Enhancements/kaleido.cpp +++ b/soh/soh/Enhancements/kaleido.cpp @@ -124,7 +124,7 @@ namespace Rando { mEntries.push_back( std::make_shared( gTriforcePieceTex, G_IM_FMT_RGBA, G_IM_SIZ_32b, 32, 32, Color_RGBA8{ 255,255,255,255 }, 0, - yOffset, reinterpret_cast(&gSaveContext.triforcePiecesCollected), + yOffset, reinterpret_cast(&gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected), ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_REQUIRED).GetContextOptionIndex() + 1, ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_TOTAL).GetContextOptionIndex() + 1)); yOffset += 18; diff --git a/soh/soh/Enhancements/mods.cpp b/soh/soh/Enhancements/mods.cpp index ac76ef53d..19cd34b89 100644 --- a/soh/soh/Enhancements/mods.cpp +++ b/soh/soh/Enhancements/mods.cpp @@ -272,7 +272,7 @@ void AutoSave(GetItemEntry itemEntry) { // Don't autosave immediately after buying items from shops to prevent getting them for free! // Don't autosave in the Chamber of Sages since resuming from that map breaks the game // Don't autosave during the Ganon fight when picking up the Master Sword - if ((CVarGetInteger(CVAR_ENHANCEMENT("Autosave"), AUTOSAVE_OFF) != AUTOSAVE_OFF) && (gPlayState != NULL) && (gSaveContext.pendingSale == ITEM_NONE) && + if ((CVarGetInteger(CVAR_ENHANCEMENT("Autosave"), AUTOSAVE_OFF) != AUTOSAVE_OFF) && (gPlayState != NULL) && (gSaveContext.ship.pendingSale == ITEM_NONE) && (gPlayState->gameplayFrames > 60 && gSaveContext.cutsceneIndex < 0xFFF0) && (gPlayState->sceneNum != SCENE_GANON_BOSS) && (gPlayState->sceneNum != SCENE_CHAMBER_OF_THE_SAGES)) { if (((CVarGetInteger(CVAR_ENHANCEMENT("Autosave"), AUTOSAVE_OFF) == AUTOSAVE_LOCATION_AND_ALL_ITEMS) || (CVarGetInteger(CVAR_ENHANCEMENT("Autosave"), AUTOSAVE_OFF) == AUTOSAVE_ALL_ITEMS)) && (item != ITEM_NONE)) { // Autosave for all items @@ -409,8 +409,8 @@ void UpdatePermanentHeartLossState() { if (!GameInteractor::IsSaveLoaded()) return; if (!CVarGetInteger(CVAR_ENHANCEMENT("PermanentHeartLoss"), 0) && hasAffectedHealth) { - uint8_t heartContainers = gSaveContext.sohStats.heartContainers; // each worth 16 health - uint8_t heartPieces = gSaveContext.sohStats.heartPieces; // each worth 4 health, but only in groups of 4 + uint8_t heartContainers = gSaveContext.ship.stats.heartContainers; // each worth 16 health + uint8_t heartPieces = gSaveContext.ship.stats.heartPieces; // each worth 4 health, but only in groups of 4 uint8_t startingHealth = 16 * (IS_RANDO ? (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_STARTING_HEARTS) + 1) : 3); @@ -508,7 +508,7 @@ void RegisterDaytimeGoldSkultullas() { bool IsHyperBossesActive() { return CVarGetInteger(CVAR_ENHANCEMENT("HyperBosses"), 0) || - (IS_BOSS_RUSH && gSaveContext.bossRushOptions[BR_OPTIONS_HYPERBOSSES] == BR_CHOICE_HYPERBOSSES_YES); + (IS_BOSS_RUSH && gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_HYPERBOSSES] == BR_CHOICE_HYPERBOSSES_YES); } void UpdateHyperBossesState() { @@ -667,7 +667,7 @@ void UpdateMirrorModeState(int32_t sceneNum) { if (mirroredMode == MIRRORED_WORLD_RANDOM_SEEDED || mirroredMode == MIRRORED_WORLD_DUNGEONS_RANDOM_SEEDED) { uint32_t seed = sceneNum + (IS_RANDO ? Rando::Context::GetInstance()->GetSettings()->GetSeed() - : gSaveContext.sohStats.fileCreatedAt); + : gSaveContext.ship.stats.fileCreatedAt); Random_Init(seed); } @@ -849,60 +849,60 @@ void RegisterEnemyDefeatCounts() { GameInteractor::Instance->RegisterGameHook([](void* refActor) { Actor* actor = static_cast(refActor); if (uniqueEnemyIdToStatCount.contains(actor->id)) { - gSaveContext.sohStats.count[uniqueEnemyIdToStatCount[actor->id]]++; + gSaveContext.ship.stats.count[uniqueEnemyIdToStatCount[actor->id]]++; } else { switch (actor->id) { case ACTOR_EN_BB: if (actor->params == ENBB_GREEN || actor->params == ENBB_GREEN_BIG) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_BUBBLE_GREEN]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_BUBBLE_GREEN]++; } else if (actor->params == ENBB_BLUE) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_BUBBLE_BLUE]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_BUBBLE_BLUE]++; } else if (actor->params == ENBB_WHITE) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_BUBBLE_WHITE]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_BUBBLE_WHITE]++; } else if (actor->params == ENBB_RED) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_BUBBLE_RED]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_BUBBLE_RED]++; } break; case ACTOR_EN_DEKUBABA: if (actor->params == DEKUBABA_BIG) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_DEKU_BABA_BIG]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_DEKU_BABA_BIG]++; } else { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_DEKU_BABA]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_DEKU_BABA]++; } break; case ACTOR_EN_ZF: if (actor->params == ENZF_TYPE_DINOLFOS) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_DINOLFOS]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_DINOLFOS]++; } else { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_LIZALFOS]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_LIZALFOS]++; } break; case ACTOR_EN_RD: if (actor->params >= -1) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_REDEAD]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_REDEAD]++; } else { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_GIBDO]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_GIBDO]++; } break; case ACTOR_EN_IK: if (actor->params == 0) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_IRON_KNUCKLE_NABOORU]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_IRON_KNUCKLE_NABOORU]++; } else { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_IRON_KNUCKLE]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_IRON_KNUCKLE]++; } break; case ACTOR_EN_FIREFLY: if (actor->params == KEESE_NORMAL_FLY || actor->params == KEESE_NORMAL_PERCH) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_KEESE]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_KEESE]++; } else if (actor->params == KEESE_FIRE_FLY || actor->params == KEESE_FIRE_PERCH) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_KEESE_FIRE]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_KEESE_FIRE]++; } else if (actor->params == KEESE_ICE_FLY) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_KEESE_ICE]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_KEESE_ICE]++; } break; @@ -910,80 +910,80 @@ void RegisterEnemyDefeatCounts() { { EnReeba* reeba = (EnReeba*)actor; if (reeba->isBig) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_LEEVER_BIG]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_LEEVER_BIG]++; } else { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_LEEVER]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_LEEVER]++; } } break; case ACTOR_EN_MB: if (actor->params == 0) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_MOBLIN_CLUB]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_MOBLIN_CLUB]++; } else { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_MOBLIN]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_MOBLIN]++; } break; case ACTOR_EN_PEEHAT: if (actor->params == PEAHAT_TYPE_LARVA) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_PEAHAT_LARVA]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_PEAHAT_LARVA]++; } else { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_PEAHAT]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_PEAHAT]++; } break; - + case ACTOR_EN_POH: if (actor->params == EN_POH_FLAT || actor->params == EN_POH_SHARP) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_POE_COMPOSER]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_POE_COMPOSER]++; } else { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_POE]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_POE]++; } break; case ACTOR_EN_PO_FIELD: if (actor->params == EN_PO_FIELD_BIG) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_POE_BIG]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_POE_BIG]++; } else { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_POE]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_POE]++; } break; case ACTOR_EN_ST: if (actor->params == 1) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_SKULLTULA_BIG]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_SKULLTULA_BIG]++; } else { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_SKULLTULA]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_SKULLTULA]++; } break; case ACTOR_EN_SW: if (((actor->params & 0xE000) >> 0xD) != 0) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_SKULLTULA_GOLD]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_SKULLTULA_GOLD]++; } else { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_SKULLWALLTULA]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_SKULLWALLTULA]++; } break; case ACTOR_EN_TP: if (actor->params == TAILPASARAN_HEAD) { // Only count the head, otherwise each body segment will increment - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_TAILPASARAN]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_TAILPASARAN]++; } break; case ACTOR_EN_TITE: if (actor->params == TEKTITE_BLUE) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_TEKTITE_BLUE]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_TEKTITE_BLUE]++; } else { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_TEKTITE_RED]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_TEKTITE_RED]++; } break; case ACTOR_EN_WF: if (actor->params == WOLFOS_WHITE) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_WOLFOS_WHITE]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_WOLFOS_WHITE]++; } else { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_WOLFOS]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_WOLFOS]++; } break; } @@ -996,35 +996,35 @@ void RegisterBossDefeatTimestamps() { Actor* actor = static_cast(refActor); switch (actor->id) { case ACTOR_BOSS_DODONGO: - gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_KING_DODONGO] = GAMEPLAYSTAT_TOTAL_TIME; + gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_DEFEAT_KING_DODONGO] = GAMEPLAYSTAT_TOTAL_TIME; break; case ACTOR_BOSS_FD2: - gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_VOLVAGIA] = GAMEPLAYSTAT_TOTAL_TIME; + gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_DEFEAT_VOLVAGIA] = GAMEPLAYSTAT_TOTAL_TIME; break; case ACTOR_BOSS_GANON: - gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_GANONDORF] = GAMEPLAYSTAT_TOTAL_TIME; + gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_DEFEAT_GANONDORF] = GAMEPLAYSTAT_TOTAL_TIME; break; case ACTOR_BOSS_GANON2: - gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_GANON] = GAMEPLAYSTAT_TOTAL_TIME; - gSaveContext.sohStats.gameComplete = true; + gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_DEFEAT_GANON] = GAMEPLAYSTAT_TOTAL_TIME; + gSaveContext.ship.stats.gameComplete = true; break; case ACTOR_BOSS_GANONDROF: - gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_PHANTOM_GANON] = GAMEPLAYSTAT_TOTAL_TIME; + gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_DEFEAT_PHANTOM_GANON] = GAMEPLAYSTAT_TOTAL_TIME; break; case ACTOR_BOSS_GOMA: - gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_GOHMA] = GAMEPLAYSTAT_TOTAL_TIME; + gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_DEFEAT_GOHMA] = GAMEPLAYSTAT_TOTAL_TIME; break; case ACTOR_BOSS_MO: - gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_MORPHA] = GAMEPLAYSTAT_TOTAL_TIME; + gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_DEFEAT_MORPHA] = GAMEPLAYSTAT_TOTAL_TIME; break; case ACTOR_BOSS_SST: - gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_BONGO_BONGO] = GAMEPLAYSTAT_TOTAL_TIME; + gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_DEFEAT_BONGO_BONGO] = GAMEPLAYSTAT_TOTAL_TIME; break; case ACTOR_BOSS_TW: - gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_TWINROVA] = GAMEPLAYSTAT_TOTAL_TIME; + gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_DEFEAT_TWINROVA] = GAMEPLAYSTAT_TOTAL_TIME; break; case ACTOR_BOSS_VA: - gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_BARINADE] = GAMEPLAYSTAT_TOTAL_TIME; + gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_DEFEAT_BARINADE] = GAMEPLAYSTAT_TOTAL_TIME; break; } }); @@ -1193,10 +1193,10 @@ void UpdateHurtContainerModeState(bool newState) { } hurtEnabled = newState; - uint16_t getHeartPieces = gSaveContext.sohStats.heartPieces / 4; - uint16_t getHeartContainers = gSaveContext.sohStats.heartContainers; - - if (hurtEnabled) { + uint16_t getHeartPieces = gSaveContext.ship.stats.heartPieces / 4; + uint16_t getHeartContainers = gSaveContext.ship.stats.heartContainers; + + if (hurtEnabled) { gSaveContext.healthCapacity = 320 - ((getHeartPieces + getHeartContainers) * 16); } else { gSaveContext.healthCapacity = 48 + ((getHeartPieces + getHeartContainers) * 16); diff --git a/soh/soh/Enhancements/randomizer/adult_trade_shuffle.c b/soh/soh/Enhancements/randomizer/adult_trade_shuffle.c index c1acc100b..4bf481d2a 100644 --- a/soh/soh/Enhancements/randomizer/adult_trade_shuffle.c +++ b/soh/soh/Enhancements/randomizer/adult_trade_shuffle.c @@ -4,7 +4,7 @@ #include "macros.h" void Randomizer_ConsumeAdultTradeItem(PlayState* play, u8 itemId) { - gSaveContext.adultTradeItems &= ~ADULT_TRADE_FLAG(itemId); + gSaveContext.ship.quest.data.randomizer.adultTradeItems &= ~ADULT_TRADE_FLAG(itemId); Inventory_ReplaceItem(play, itemId, Randomizer_GetNextAdultTradeItem()); } @@ -13,7 +13,7 @@ u8 Randomizer_GetNextAdultTradeItem() { u8 currentTradeItemIndex = INV_CONTENT(ITEM_TRADE_ADULT) - ITEM_POCKET_EGG; for (int i = 0; i < numTradeItems; i++) { u8 tradeIndex = (currentTradeItemIndex + i + 1) % numTradeItems; - if (gSaveContext.adultTradeItems & (1 << tradeIndex)) { + if (gSaveContext.ship.quest.data.randomizer.adultTradeItems & (1 << tradeIndex)) { return ITEM_POCKET_EGG + tradeIndex; } } @@ -25,7 +25,7 @@ u8 Randomizer_GetPrevAdultTradeItem() { u8 currentTradeItemIndex = INV_CONTENT(ITEM_TRADE_ADULT) - ITEM_POCKET_EGG; for (int i = 0; i < numTradeItems; i++) { u8 tradeIndex = (currentTradeItemIndex - i - 1 + numTradeItems) % numTradeItems; - if (gSaveContext.adultTradeItems & (1 << tradeIndex)) { + if (gSaveContext.ship.quest.data.randomizer.adultTradeItems & (1 << tradeIndex)) { return ITEM_POCKET_EGG + tradeIndex; } } diff --git a/soh/soh/Enhancements/randomizer/adult_trade_shuffle.h b/soh/soh/Enhancements/randomizer/adult_trade_shuffle.h index 13d905026..f9894cf4e 100644 --- a/soh/soh/Enhancements/randomizer/adult_trade_shuffle.h +++ b/soh/soh/Enhancements/randomizer/adult_trade_shuffle.h @@ -4,7 +4,7 @@ #include #define ADULT_TRADE_FLAG(itemId) (1 << (itemId - ITEM_POCKET_EGG)) -#define PLAYER_HAS_SHUFFLED_ADULT_TRADE_ITEM(itemID) (gSaveContext.adultTradeItems & ADULT_TRADE_FLAG(itemID)) +#define PLAYER_HAS_SHUFFLED_ADULT_TRADE_ITEM(itemID) (IS_RANDO && gSaveContext.ship.quest.data.randomizer.adultTradeItems & ADULT_TRADE_FLAG(itemID)) void Randomizer_ConsumeAdultTradeItem(PlayState* play, u8 itemId); u8 Randomizer_GetNextAdultTradeItem(); diff --git a/soh/soh/Enhancements/randomizer/draw.cpp b/soh/soh/Enhancements/randomizer/draw.cpp index bd7f92a84..f83786fd9 100644 --- a/soh/soh/Enhancements/randomizer/draw.cpp +++ b/soh/soh/Enhancements/randomizer/draw.cpp @@ -263,7 +263,7 @@ extern "C" void Randomizer_DrawTriforcePiece(PlayState* play, GetItemEntry getIt Gfx_SetupDL_25Xlu(play->state.gfxCtx); - uint8_t current = gSaveContext.triforcePiecesCollected; + uint8_t current = gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected; Matrix_Scale(0.035f, 0.035f, 0.035f, MTXMODE_APPLY); @@ -287,7 +287,7 @@ extern "C" void Randomizer_DrawTriforcePieceGI(PlayState* play, GetItemEntry get Gfx_SetupDL_25Xlu(play->state.gfxCtx); - uint8_t current = gSaveContext.triforcePiecesCollected; + uint8_t current = gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected; uint8_t required = OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_TRIFORCE_HUNT_PIECES_REQUIRED) + 1; Matrix_Scale(triforcePieceScale, triforcePieceScale, triforcePieceScale, MTXMODE_APPLY); diff --git a/soh/soh/Enhancements/randomizer/hook_handlers.cpp b/soh/soh/Enhancements/randomizer/hook_handlers.cpp index 86fb79418..14d4195d0 100644 --- a/soh/soh/Enhancements/randomizer/hook_handlers.cpp +++ b/soh/soh/Enhancements/randomizer/hook_handlers.cpp @@ -1010,7 +1010,7 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_l Item_Give(gPlayState, item00->itemEntry.itemId); } else if (item00->itemEntry.modIndex == MOD_RANDOMIZER) { if (item00->itemEntry.getItemId == RG_ICE_TRAP) { - gSaveContext.pendingIceTrapCount++; + gSaveContext.ship.pendingIceTrapCount++; } else { Randomizer_Item_Give(gPlayState, item00->itemEntry); } diff --git a/soh/soh/Enhancements/randomizer/location_access.cpp b/soh/soh/Enhancements/randomizer/location_access.cpp index 7c9cf7e7f..d3a17a0b9 100644 --- a/soh/soh/Enhancements/randomizer/location_access.cpp +++ b/soh/soh/Enhancements/randomizer/location_access.cpp @@ -267,7 +267,7 @@ void RegionTable_Init() { }, { //Locations LOCATION(RC_LINKS_POCKET, true), - LOCATION(RC_TRIFORCE_COMPLETED, logic->GetSaveContext()->triforcePiecesCollected >= ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_REQUIRED).GetContextOptionIndex() + 1;), + LOCATION(RC_TRIFORCE_COMPLETED, logic->GetSaveContext()->ship.quest.data.randomizer.triforcePiecesCollected >= ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_REQUIRED).GetContextOptionIndex() + 1;), LOCATION(RC_SARIA_SONG_HINT, logic->CanUse(RG_SARIAS_SONG)), }, { //Exits diff --git a/soh/soh/Enhancements/randomizer/logic.cpp b/soh/soh/Enhancements/randomizer/logic.cpp index 2b92484b3..85104d825 100644 --- a/soh/soh/Enhancements/randomizer/logic.cpp +++ b/soh/soh/Enhancements/randomizer/logic.cpp @@ -1625,7 +1625,7 @@ namespace Rando { SetRandoInf(RandoGetToRandInf.at(randoGet), state); break; case RG_TRIFORCE_PIECE: - mSaveContext->triforcePiecesCollected += (!state ? -1 : 1); + mSaveContext->ship.quest.data.randomizer.triforcePiecesCollected += (!state ? -1 : 1); break; case RG_BOMBCHU_5: case RG_BOMBCHU_10: @@ -1881,14 +1881,13 @@ namespace Rando { mSaveContext->sceneFlags[5].swch = 0x40000000; // SoH specific - mSaveContext->backupFW = mSaveContext->fw; - mSaveContext->pendingSale = ITEM_NONE; - mSaveContext->pendingSaleMod = MOD_NONE; - mSaveContext->isBossRushPaused = 0; - mSaveContext->pendingIceTrapCount = 0; + mSaveContext->ship.backupFW = mSaveContext->fw; + mSaveContext->ship.pendingSale = ITEM_NONE; + mSaveContext->ship.pendingSaleMod = MOD_NONE; + mSaveContext->ship.pendingIceTrapCount = 0; // Init with normal quest unless only an MQ rom is provided - mSaveContext->questId = OTRGlobals::Instance->HasOriginal() ? QUEST_NORMAL : QUEST_MASTER; + mSaveContext->ship.quest.id = OTRGlobals::Instance->HasOriginal() ? QUEST_NORMAL : QUEST_MASTER; //RANDOTODO (ADD ITEMLOCATIONS TO GSAVECONTEXT) } @@ -1937,16 +1936,16 @@ namespace Rando { bool Logic::HasAdultTrade(uint32_t itemID) { int tradeIndex = itemID - ITEM_POCKET_EGG; - return mSaveContext->adultTradeItems & (1 << tradeIndex); + return mSaveContext->ship.quest.data.randomizer.adultTradeItems & (1 << tradeIndex); } void Logic::SetAdultTrade(uint32_t itemID, bool state) { int tradeIndex = itemID - ITEM_POCKET_EGG; if (!state) { - mSaveContext->adultTradeItems &= ~(1 << tradeIndex); + mSaveContext->ship.quest.data.randomizer.adultTradeItems &= ~(1 << tradeIndex); } else { - mSaveContext->adultTradeItems |= (1 << tradeIndex); + mSaveContext->ship.quest.data.randomizer.adultTradeItems |= (1 << tradeIndex); } } @@ -1981,15 +1980,15 @@ namespace Rando { } bool Logic::CheckRandoInf(uint32_t flag) { - return mSaveContext->randomizerInf[flag >> 4] & (1 << (flag & 0xF)); + return mSaveContext->ship.randomizerInf[flag >> 4] & (1 << (flag & 0xF)); } void Logic::SetRandoInf(uint32_t flag, bool state) { if (!state) { - mSaveContext->randomizerInf[flag >> 4] &= ~(1 << (flag & 0xF)); + mSaveContext->ship.randomizerInf[flag >> 4] &= ~(1 << (flag & 0xF)); } else { - mSaveContext->randomizerInf[flag >> 4] |= (1 << (flag & 0xF)); + mSaveContext->ship.randomizerInf[flag >> 4] |= (1 << (flag & 0xF)); } } diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index b6c520ceb..1dcdb5506 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -2787,7 +2787,7 @@ void CreateTriforcePieceMessages() { CustomMessage Randomizer::GetTriforcePieceMessage() { // Item is only given after the textbox, so reflect that inside the textbox. - uint8_t current = gSaveContext.triforcePiecesCollected + 1; + uint8_t current = gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected + 1; uint8_t required = OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_TRIFORCE_HUNT_PIECES_REQUIRED) + 1; uint8_t remaining = required - current; float percentageCollected = (float)current / (float)required; @@ -3330,7 +3330,7 @@ void CreateFireTempleGoronMessages() { CustomMessage Randomizer::GetGoronMessage(u16 index) { CustomMessage messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, goronIDs[index]); messageEntry.Replace("[[days]]", std::to_string(gSaveContext.totalDays)); - messageEntry.Replace("[[a_btn]]", std::to_string(gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_A])); + messageEntry.Replace("[[a_btn]]", std::to_string(gSaveContext.ship.stats.count[COUNT_BUTTON_PRESSES_A])); messageEntry.Format(); return messageEntry; } @@ -3339,15 +3339,15 @@ void Randomizer::CreateCustomMessages() { // RANDTODO: Translate into french and german and replace GIMESSAGE_UNTRANSLATED // with GIMESSAGE(getItemID, itemID, english, german, french). const std::array getItemMessages = {{ - GIMESSAGE(RG_GREG_RUPEE, ITEM_MASK_GORON, + GIMESSAGE(RG_GREG_RUPEE, ITEM_MASK_GORON, "You found %gGreg%w!", "%gGreg%w! Du hast ihn wirklich gefunden!", "Félicitation! Vous avez trouvé %gGreg%w!"), - GIMESSAGE(RG_MASTER_SWORD, ITEM_SWORD_MASTER, + GIMESSAGE(RG_MASTER_SWORD, ITEM_SWORD_MASTER, "You found the %gMaster Sword%w!", "Du erhältst das %gMaster-Schwert%w!", "Vous obtenez %gl'Épée de Légende%w!"), - GIMESSAGE(RG_BOTTLE_WITH_BLUE_FIRE, ITEM_BLUE_FIRE, + GIMESSAGE(RG_BOTTLE_WITH_BLUE_FIRE, ITEM_BLUE_FIRE, "You got a %rBottle with Blue &Fire%w! Use it to melt Red Ice!", "Du erhältst eine %rFlasche mit&blauem Feuer%w! Nutze es um&%rRotes Eis%w zu schmelzen!", "Vous obtenez une %rBouteille avec&une Flamme Bleue%w! Utilisez-la&pour faire fondre la %rGlace&Rouge%w!"), @@ -3453,7 +3453,7 @@ void Randomizer::CreateCustomMessages() { "You found a %yGerudo Training &Grounds %wKeyring!", "Du erhältst ein %rSchlüsselbund%w&für die %yGerudo-Trainingsarena%w!", "Vous obtenez un trousseau de&clés du %yGymnase Gerudo%w!"), - GIMESSAGE(RG_GANONS_CASTLE_KEY_RING, ITEM_KEY_SMALL, + GIMESSAGE(RG_GANONS_CASTLE_KEY_RING, ITEM_KEY_SMALL, "You found a %rGanon's Castle &%wKeyring!", "Du erhältst ein %rSchlüsselbund%w&für %rGanons Schloß%w!", "Vous obtenez un trousseau de&clés du %rChâteau de Ganon%w!"), @@ -3706,28 +3706,28 @@ void Randomizer_GameplayStats_SetTimestamp(uint16_t item) { // Use ITEM_KEY_BOSS to timestamp Ganon's boss key if (item == RG_GANONS_CASTLE_BOSS_KEY) { - gSaveContext.sohStats.itemTimestamp[ITEM_KEY_BOSS] = time; + gSaveContext.ship.stats.itemTimestamp[ITEM_KEY_BOSS] = time; } // Count any bottled item as a bottle if (item >= RG_EMPTY_BOTTLE && item <= RG_BOTTLE_WITH_BIG_POE) { - if (gSaveContext.sohStats.itemTimestamp[ITEM_BOTTLE] == 0) { - gSaveContext.sohStats.itemTimestamp[ITEM_BOTTLE] = time; + if (gSaveContext.ship.stats.itemTimestamp[ITEM_BOTTLE] == 0) { + gSaveContext.ship.stats.itemTimestamp[ITEM_BOTTLE] = time; } return; } // Count any bombchu pack as bombchus if ((item >= RG_BOMBCHU_5 && item <= RG_BOMBCHU_20) || item == RG_PROGRESSIVE_BOMBCHUS) { - if (gSaveContext.sohStats.itemTimestamp[ITEM_BOMBCHU] = 0) { - gSaveContext.sohStats.itemTimestamp[ITEM_BOMBCHU] = time; + if (gSaveContext.ship.stats.itemTimestamp[ITEM_BOMBCHU] = 0) { + gSaveContext.ship.stats.itemTimestamp[ITEM_BOMBCHU] = time; } return; } if (item == RG_MAGIC_SINGLE) { - gSaveContext.sohStats.itemTimestamp[ITEM_SINGLE_MAGIC] = time; + gSaveContext.ship.stats.itemTimestamp[ITEM_SINGLE_MAGIC] = time; } if (item == RG_DOUBLE_DEFENSE) { - gSaveContext.sohStats.itemTimestamp[ITEM_DOUBLE_DEFENSE] = time; + gSaveContext.ship.stats.itemTimestamp[ITEM_DOUBLE_DEFENSE] = time; } } @@ -3920,7 +3920,7 @@ extern "C" u16 Randomizer_Item_Give(PlayState* play, GetItemEntry giEntry) { } if ((item >= RG_FOREST_TEMPLE_SMALL_KEY) && (item <= RG_GANONS_CASTLE_SMALL_KEY)) { - gSaveContext.sohStats.dungeonKeys[mapIndex]++; + gSaveContext.ship.stats.dungeonKeys[mapIndex]++; if (gSaveContext.inventory.dungeonKeys[mapIndex] < 0) { gSaveContext.inventory.dungeonKeys[mapIndex] = 1; } else { @@ -3930,7 +3930,7 @@ extern "C" u16 Randomizer_Item_Give(PlayState* play, GetItemEntry giEntry) { } if ((item >= RG_FOREST_TEMPLE_KEY_RING) && (item <= RG_GANONS_CASTLE_KEY_RING)) { - gSaveContext.sohStats.dungeonKeys[mapIndex] = numOfKeysOnKeyring; + gSaveContext.ship.stats.dungeonKeys[mapIndex] = numOfKeysOnKeyring; gSaveContext.inventory.dungeonKeys[mapIndex] = numOfKeysOnKeyring; return Return_Item_Entry(giEntry, RG_NONE); } @@ -3989,16 +3989,16 @@ extern "C" u16 Randomizer_Item_Give(PlayState* play, GetItemEntry giEntry) { case RG_GREG_RUPEE: Rupees_ChangeBy(1); Flags_SetRandomizerInf(RAND_INF_GREG_FOUND); - gSaveContext.sohStats.itemTimestamp[TIMESTAMP_FOUND_GREG] = GAMEPLAYSTAT_TOTAL_TIME; + gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_FOUND_GREG] = GAMEPLAYSTAT_TOTAL_TIME; break; case RG_TRIFORCE_PIECE: - gSaveContext.triforcePiecesCollected++; + gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected++; GameInteractor_SetTriforceHuntPieceGiven(true); // Teleport to credits when goal is reached. - if (gSaveContext.triforcePiecesCollected == (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_TRIFORCE_HUNT_PIECES_REQUIRED) + 1)) { - gSaveContext.sohStats.itemTimestamp[TIMESTAMP_TRIFORCE_COMPLETED] = GAMEPLAYSTAT_TOTAL_TIME; - gSaveContext.sohStats.gameComplete = 1; + if (gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected == (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_TRIFORCE_HUNT_PIECES_REQUIRED) + 1)) { + gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_TRIFORCE_COMPLETED] = GAMEPLAYSTAT_TOTAL_TIME; + gSaveContext.ship.stats.gameComplete = 1; Flags_SetRandomizerInf(RAND_INF_GRANT_GANONS_BOSSKEY); Play_PerformSave(play); GameInteractor_SetTriforceHuntCreditsWarpActive(true); diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp index 0af0b0128..ecd572ab9 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp @@ -1360,7 +1360,7 @@ bool IsVisibleInCheckTracker(RandomizerCheck rc) { OTRGlobals::Instance->gRandoContext->IsQuestOfLocationActive(rc) ) || (loc->GetRCType() == RCTYPE_SHOP && showShops && !hideShopUnshuffledChecks); } else { - return loc->IsVanillaCompletion() && (!loc->IsDungeon() || (loc->IsDungeon() && loc->GetQuest() == gSaveContext.questId)); + return loc->IsVanillaCompletion() && (!loc->IsDungeon() || (loc->IsDungeon() && loc->GetQuest() == gSaveContext.ship.quest.id)); } } diff --git a/soh/soh/Enhancements/randomizer/randomizer_entrance.c b/soh/soh/Enhancements/randomizer/randomizer_entrance.c index 7a492fe9c..14d630005 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_entrance.c +++ b/soh/soh/Enhancements/randomizer/randomizer_entrance.c @@ -740,7 +740,7 @@ u8 Entrance_GetIsSceneDiscovered(u8 sceneNum) { u32 idx = sceneNum / bitsPerIndex; if (idx < SAVEFILE_SCENES_DISCOVERED_IDX_COUNT) { u32 sceneBit = 1 << (sceneNum - (idx * bitsPerIndex)); - return (gSaveContext.sohStats.scenesDiscovered[idx] & sceneBit) != 0; + return (gSaveContext.ship.stats.scenesDiscovered[idx] & sceneBit) != 0; } return 0; } @@ -754,7 +754,7 @@ void Entrance_SetSceneDiscovered(u8 sceneNum) { u32 idx = sceneNum / bitsPerIndex; if (idx < SAVEFILE_SCENES_DISCOVERED_IDX_COUNT) { u32 sceneBit = 1 << (sceneNum - (idx * bitsPerIndex)); - gSaveContext.sohStats.scenesDiscovered[idx] |= sceneBit; + gSaveContext.ship.stats.scenesDiscovered[idx] |= sceneBit; } // Save scenesDiscovered Save_SaveSection(SECTION_ID_SCENES); @@ -765,7 +765,7 @@ u8 Entrance_GetIsEntranceDiscovered(u16 entranceIndex) { u32 idx = entranceIndex / bitsPerIndex; if (idx < SAVEFILE_ENTRANCES_DISCOVERED_IDX_COUNT) { u32 entranceBit = 1 << (entranceIndex - (idx * bitsPerIndex)); - return (gSaveContext.sohStats.entrancesDiscovered[idx] & entranceBit) != 0; + return (gSaveContext.ship.stats.entrancesDiscovered[idx] & entranceBit) != 0; } return 0; } @@ -782,7 +782,7 @@ void Entrance_SetEntranceDiscovered(u16 entranceIndex, u8 isReversedEntrance) { u32 idx = entranceIndex / bitsPerIndex; if (idx < SAVEFILE_ENTRANCES_DISCOVERED_IDX_COUNT) { u32 entranceBit = 1 << (entranceIndex - (idx * bitsPerIndex)); - gSaveContext.sohStats.entrancesDiscovered[idx] |= entranceBit; + gSaveContext.ship.stats.entrancesDiscovered[idx] |= entranceBit; // Set reverse entrance when not decoupled if (!Randomizer_GetSettingValue(RSK_DECOUPLED_ENTRANCES) && !isReversedEntrance) { diff --git a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp index 4c5ba4714..2517923fd 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp @@ -411,17 +411,17 @@ ItemTrackerNumbers GetItemCurrentAndMax(ItemTrackerItem item) { break; case ITEM_HEART_CONTAINER: result.maxCapacity = result.currentCapacity = 8; - result.currentAmmo = gSaveContext.sohStats.heartContainers; + result.currentAmmo = gSaveContext.ship.stats.heartContainers; break; case ITEM_HEART_PIECE: result.maxCapacity = result.currentCapacity = 36; - result.currentAmmo = gSaveContext.sohStats.heartPieces; + result.currentAmmo = gSaveContext.ship.stats.heartPieces; break; case ITEM_KEY_SMALL: // Though the ammo/capacity naming doesn't really make sense for keys, we are // hijacking the same system to display key counts as there are enough similarities result.currentAmmo = MAX(gSaveContext.inventory.dungeonKeys[item.data], 0); - result.currentCapacity = gSaveContext.sohStats.dungeonKeys[item.data]; + result.currentCapacity = gSaveContext.ship.stats.dungeonKeys[item.data]; switch (item.data) { case SCENE_FOREST_TEMPLE: result.maxCapacity = FOREST_TEMPLE_SMALL_KEY_MAX; @@ -582,11 +582,11 @@ void DrawItemCount(ItemTrackerItem item, bool hideMax) { std::string maxString = ""; uint8_t piecesRequired = (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_TRIFORCE_HUNT_PIECES_REQUIRED) + 1); uint8_t piecesTotal = (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_TRIFORCE_HUNT_PIECES_TOTAL) + 1); - ImU32 currentColor = gSaveContext.triforcePiecesCollected >= piecesRequired ? IM_COL_GREEN : IM_COL_WHITE; + ImU32 currentColor = gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected >= piecesRequired ? IM_COL_GREEN : IM_COL_WHITE; ImU32 maxColor = IM_COL_GREEN; int32_t trackerTriforcePieceNumberDisplayMode = CVarGetInteger(CVAR_TRACKER_ITEM("TriforcePieceCounts"), TRIFORCE_PIECE_COLLECTED_REQUIRED_MAX); - currentString += std::to_string(gSaveContext.triforcePiecesCollected); + currentString += std::to_string(gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected); currentString += "/"; // gItemTrackerTriforcePieceTrack if (trackerTriforcePieceNumberDisplayMode == TRIFORCE_PIECE_COLLECTED_REQUIRED_MAX) { @@ -651,11 +651,11 @@ void DrawItem(ItemTrackerItem item) { switch (item.id) { case ITEM_HEART_CONTAINER: actualItemId = item.id; - hasItem = gSaveContext.sohStats.heartContainers > 0; + hasItem = gSaveContext.ship.stats.heartContainers > 0; break; case ITEM_HEART_PIECE: actualItemId = item.id; - hasItem = gSaveContext.sohStats.heartPieces > 0; + hasItem = gSaveContext.ship.stats.heartPieces > 0; break; case ITEM_MAGIC_SMALL: case ITEM_MAGIC_LARGE: diff --git a/soh/soh/Enhancements/randomizer/savefile.cpp b/soh/soh/Enhancements/randomizer/savefile.cpp index eb081552f..44a4a859e 100644 --- a/soh/soh/Enhancements/randomizer/savefile.cpp +++ b/soh/soh/Enhancements/randomizer/savefile.cpp @@ -25,7 +25,7 @@ void StartingItemGive(GetItemEntry getItemEntry, RandomizerCheck randomizerCheck Item_Give(NULL, getItemEntry.itemId); } else if (getItemEntry.modIndex == MOD_RANDOMIZER) { if (getItemEntry.getItemId == RG_ICE_TRAP) { - gSaveContext.pendingIceTrapCount++; + gSaveContext.ship.pendingIceTrapCount++; } else { Randomizer_Item_Give(NULL, getItemEntry); } @@ -174,22 +174,22 @@ void SetStartingItems() { } if (Randomizer_GetSettingValue(RSK_KEYSANITY) == RO_DUNGEON_ITEM_LOC_STARTWITH) { - gSaveContext.inventory.dungeonKeys[SCENE_FOREST_TEMPLE] = FOREST_TEMPLE_SMALL_KEY_MAX; // Forest - gSaveContext.sohStats.dungeonKeys[SCENE_FOREST_TEMPLE] = FOREST_TEMPLE_SMALL_KEY_MAX; // Forest - gSaveContext.inventory.dungeonKeys[SCENE_FIRE_TEMPLE] = FIRE_TEMPLE_SMALL_KEY_MAX; // Fire - gSaveContext.sohStats.dungeonKeys[SCENE_FIRE_TEMPLE] = FIRE_TEMPLE_SMALL_KEY_MAX; // Fire - gSaveContext.inventory.dungeonKeys[SCENE_WATER_TEMPLE] = WATER_TEMPLE_SMALL_KEY_MAX; // Water - gSaveContext.sohStats.dungeonKeys[SCENE_WATER_TEMPLE] = WATER_TEMPLE_SMALL_KEY_MAX; // Water - gSaveContext.inventory.dungeonKeys[SCENE_SPIRIT_TEMPLE] = SPIRIT_TEMPLE_SMALL_KEY_MAX; // Spirit - gSaveContext.sohStats.dungeonKeys[SCENE_SPIRIT_TEMPLE] = SPIRIT_TEMPLE_SMALL_KEY_MAX; // Spirit - gSaveContext.inventory.dungeonKeys[SCENE_SHADOW_TEMPLE] = SHADOW_TEMPLE_SMALL_KEY_MAX; // Shadow - gSaveContext.sohStats.dungeonKeys[SCENE_SHADOW_TEMPLE] = SHADOW_TEMPLE_SMALL_KEY_MAX; // Shadow - gSaveContext.inventory.dungeonKeys[SCENE_BOTTOM_OF_THE_WELL] = BOTTOM_OF_THE_WELL_SMALL_KEY_MAX; // BotW - gSaveContext.sohStats.dungeonKeys[SCENE_BOTTOM_OF_THE_WELL] = BOTTOM_OF_THE_WELL_SMALL_KEY_MAX; // BotW + gSaveContext.inventory.dungeonKeys[SCENE_FOREST_TEMPLE] = FOREST_TEMPLE_SMALL_KEY_MAX; // Forest + gSaveContext.ship.stats.dungeonKeys[SCENE_FOREST_TEMPLE] = FOREST_TEMPLE_SMALL_KEY_MAX; // Forest + gSaveContext.inventory.dungeonKeys[SCENE_FIRE_TEMPLE] = FIRE_TEMPLE_SMALL_KEY_MAX; // Fire + gSaveContext.ship.stats.dungeonKeys[SCENE_FIRE_TEMPLE] = FIRE_TEMPLE_SMALL_KEY_MAX; // Fire + gSaveContext.inventory.dungeonKeys[SCENE_WATER_TEMPLE] = WATER_TEMPLE_SMALL_KEY_MAX; // Water + gSaveContext.ship.stats.dungeonKeys[SCENE_WATER_TEMPLE] = WATER_TEMPLE_SMALL_KEY_MAX; // Water + gSaveContext.inventory.dungeonKeys[SCENE_SPIRIT_TEMPLE] = SPIRIT_TEMPLE_SMALL_KEY_MAX; // Spirit + gSaveContext.ship.stats.dungeonKeys[SCENE_SPIRIT_TEMPLE] = SPIRIT_TEMPLE_SMALL_KEY_MAX; // Spirit + gSaveContext.inventory.dungeonKeys[SCENE_SHADOW_TEMPLE] = SHADOW_TEMPLE_SMALL_KEY_MAX; // Shadow + gSaveContext.ship.stats.dungeonKeys[SCENE_SHADOW_TEMPLE] = SHADOW_TEMPLE_SMALL_KEY_MAX; // Shadow + gSaveContext.inventory.dungeonKeys[SCENE_BOTTOM_OF_THE_WELL] = BOTTOM_OF_THE_WELL_SMALL_KEY_MAX; // BotW + gSaveContext.ship.stats.dungeonKeys[SCENE_BOTTOM_OF_THE_WELL] = BOTTOM_OF_THE_WELL_SMALL_KEY_MAX; // BotW gSaveContext.inventory.dungeonKeys[SCENE_GERUDO_TRAINING_GROUND] = GERUDO_TRAINING_GROUND_SMALL_KEY_MAX; // GTG - gSaveContext.sohStats.dungeonKeys[SCENE_GERUDO_TRAINING_GROUND] = GERUDO_TRAINING_GROUND_SMALL_KEY_MAX; // GTG - gSaveContext.inventory.dungeonKeys[SCENE_INSIDE_GANONS_CASTLE] = GANONS_CASTLE_SMALL_KEY_MAX; // Ganon - gSaveContext.sohStats.dungeonKeys[SCENE_INSIDE_GANONS_CASTLE] = GANONS_CASTLE_SMALL_KEY_MAX; // Ganon + gSaveContext.ship.stats.dungeonKeys[SCENE_GERUDO_TRAINING_GROUND] = GERUDO_TRAINING_GROUND_SMALL_KEY_MAX; // GTG + gSaveContext.inventory.dungeonKeys[SCENE_INSIDE_GANONS_CASTLE] = GANONS_CASTLE_SMALL_KEY_MAX; // Ganon + gSaveContext.ship.stats.dungeonKeys[SCENE_INSIDE_GANONS_CASTLE] = GANONS_CASTLE_SMALL_KEY_MAX; // Ganon } else if (Randomizer_GetSettingValue(RSK_KEYSANITY) == RO_DUNGEON_ITEM_LOC_VANILLA) { // Logic cannot handle vanilla key layout in some dungeons // this is because vanilla expects the dungeon major item to be @@ -198,7 +198,7 @@ void SetStartingItems() { if (ResourceMgr_IsSceneMasterQuest(SCENE_SPIRIT_TEMPLE)) { // MQ Spirit needs 3 keys gSaveContext.inventory.dungeonKeys[SCENE_SPIRIT_TEMPLE] = 3; - gSaveContext.sohStats.dungeonKeys[SCENE_SPIRIT_TEMPLE] = 3; + gSaveContext.ship.stats.dungeonKeys[SCENE_SPIRIT_TEMPLE] = 3; } } @@ -220,10 +220,10 @@ extern "C" void Randomizer_InitSaveFile() { ctx->GetLogic()->SetSaveContext(&gSaveContext); // Starts pending ice traps out at 0 before potentially incrementing them down the line. - gSaveContext.pendingIceTrapCount = 0; + gSaveContext.ship.pendingIceTrapCount = 0; // Reset triforce pieces collected - gSaveContext.triforcePiecesCollected = 0; + gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected = 0; // Set Cutscene flags and texts to skip them Flags_SetEventChkInf(EVENTCHKINF_FIRST_SPOKE_TO_MIDO); @@ -262,7 +262,7 @@ extern "C" void Randomizer_InitSaveFile() { // shuffle adult trade quest if (Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE)) { - gSaveContext.adultTradeItems = 0; + gSaveContext.ship.quest.data.randomizer.adultTradeItems = 0; } // remove One Time scrubs with scrubsanity off diff --git a/soh/soh/Enhancements/timesplits/TimeSplits.cpp b/soh/soh/Enhancements/timesplits/TimeSplits.cpp index 01faf7bf5..b17f95b82 100644 --- a/soh/soh/Enhancements/timesplits/TimeSplits.cpp +++ b/soh/soh/Enhancements/timesplits/TimeSplits.cpp @@ -345,8 +345,8 @@ void HandleDragAndDrop(std::vector& objectList, int targetIndex, co } void TimeSplitCompleteSplits() { - gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_GANON] = GAMEPLAYSTAT_TOTAL_TIME; - gSaveContext.sohStats.gameComplete = true; + gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_DEFEAT_GANON] = GAMEPLAYSTAT_TOTAL_TIME; + gSaveContext.ship.stats.gameComplete = true; } void TimeSplitsSkipSplit(uint32_t index) { diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 7856de88f..3cf63f18b 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -2322,10 +2322,10 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) { messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, textId, MF_FORMATTED); } else if (textId == TEXT_HEART_CONTAINER && CVarGetInteger(CVAR_ENHANCEMENT("InjectItemCounts.HeartContainer"), 0)) { messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_HEART_CONTAINER, MF_FORMATTED); - messageEntry.Replace("[[heartContainerCount]]", std::to_string(gSaveContext.sohStats.heartContainers + 1)); + messageEntry.Replace("[[heartContainerCount]]", std::to_string(gSaveContext.ship.stats.heartContainers + 1)); } else if (textId >= TEXT_HEART_PIECE && textId < TEXT_HEART_CONTAINER && CVarGetInteger(CVAR_ENHANCEMENT("InjectItemCounts.HeartPiece"), 0)) { messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_HEART_PIECE, MF_FORMATTED); - messageEntry.Replace("[[heartPieceCount]]", std::to_string(gSaveContext.sohStats.heartPieces + 1)); + messageEntry.Replace("[[heartPieceCount]]", std::to_string(gSaveContext.ship.stats.heartPieces + 1)); } else if (textId == TEXT_MARKET_GUARD_NIGHT && CVarGetInteger(CVAR_ENHANCEMENT("MarketSneak"), 0) && play->sceneNum == SCENE_MARKET_ENTRANCE_NIGHT) { messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_MARKET_GUARD_NIGHT, MF_FORMATTED); } diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index 36de01199..be5c88a5e 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -218,11 +218,11 @@ void SaveManager::LoadRandomizerVersion1() { } randoContext->AddHint(RH_GANONDORF_JOKE, Rando::Hint(RH_GANONDORF_JOKE, {CustomMessage(ganonText)})); - SaveManager::Instance->LoadData("adultTradeItems", gSaveContext.adultTradeItems); + SaveManager::Instance->LoadData("adultTradeItems", gSaveContext.ship.quest.data.randomizer.adultTradeItems); - SaveManager::Instance->LoadData("triforcePiecesCollected", gSaveContext.triforcePiecesCollected); + SaveManager::Instance->LoadData("triforcePiecesCollected", gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected); - SaveManager::Instance->LoadData("pendingIceTrapCount", gSaveContext.pendingIceTrapCount); + SaveManager::Instance->LoadData("pendingIceTrapCount", gSaveContext.ship.pendingIceTrapCount); size_t merchantPricesSize = 0; @@ -348,11 +348,11 @@ void SaveManager::LoadRandomizerVersion2() { SaveManager::Instance->LoadData("warpPreludeText", warpPreludeText); randoContext->AddHint(RH_PRELUDE_WARP_LOC, Rando::Hint(RH_PRELUDE_WARP_LOC, {CustomMessage(warpPreludeText)})); - SaveManager::Instance->LoadData("adultTradeItems", gSaveContext.adultTradeItems); + SaveManager::Instance->LoadData("adultTradeItems", gSaveContext.ship.quest.data.randomizer.adultTradeItems); - SaveManager::Instance->LoadData("triforcePiecesCollected", gSaveContext.triforcePiecesCollected); + SaveManager::Instance->LoadData("triforcePiecesCollected", gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected); - SaveManager::Instance->LoadData("pendingIceTrapCount", gSaveContext.pendingIceTrapCount); + SaveManager::Instance->LoadData("pendingIceTrapCount", gSaveContext.ship.pendingIceTrapCount); std::shared_ptr randomizer = OTRGlobals::Instance->gRandomizer; @@ -445,11 +445,11 @@ void SaveManager::LoadRandomizerVersion3() { randoContext->AddHint(hint, Rando::Hint(hint, json)); }); - SaveManager::Instance->LoadData("adultTradeItems", gSaveContext.adultTradeItems); + SaveManager::Instance->LoadData("adultTradeItems", gSaveContext.ship.quest.data.randomizer.adultTradeItems); - SaveManager::Instance->LoadData("triforcePiecesCollected", gSaveContext.triforcePiecesCollected); + SaveManager::Instance->LoadData("triforcePiecesCollected", gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected); - SaveManager::Instance->LoadData("pendingIceTrapCount", gSaveContext.pendingIceTrapCount); + SaveManager::Instance->LoadData("pendingIceTrapCount", gSaveContext.ship.pendingIceTrapCount); std::shared_ptr randomizer = OTRGlobals::Instance->gRandomizer; @@ -473,7 +473,7 @@ void SaveManager::LoadRandomizerVersion3() { void SaveManager::SaveRandomizer(SaveContext* saveContext, int sectionID, bool fullSave) { - if(saveContext->questId != QUEST_RANDOMIZER) return; + if(saveContext->ship.quest.id != QUEST_RANDOMIZER) return; auto randoContext = Rando::Context::GetInstance(); SaveManager::Instance->SaveArray("itemLocations", RC_MAX, [&](size_t i) { @@ -582,11 +582,11 @@ void SaveManager::SaveRandomizer(SaveContext* saveContext, int sectionID, bool f }); }); - SaveManager::Instance->SaveData("adultTradeItems", saveContext->adultTradeItems); + SaveManager::Instance->SaveData("adultTradeItems", saveContext->ship.quest.data.randomizer.adultTradeItems); - SaveManager::Instance->SaveData("triforcePiecesCollected", saveContext->triforcePiecesCollected); + SaveManager::Instance->SaveData("triforcePiecesCollected", saveContext->ship.quest.data.randomizer.triforcePiecesCollected); - SaveManager::Instance->SaveData("pendingIceTrapCount", saveContext->pendingIceTrapCount); + SaveManager::Instance->SaveData("pendingIceTrapCount", saveContext->ship.pendingIceTrapCount); std::shared_ptr randomizer = OTRGlobals::Instance->gRandomizer; @@ -701,10 +701,10 @@ void SaveManager::InitMeta(int fileNum) { // we don't actually require a vanilla OTR. fileMetaInfo[fileNum].requiresOriginal = !IS_MASTER_QUEST && (!IS_RANDO || randoContext->GetDungeons()->CountMQ() < 12); - fileMetaInfo[fileNum].buildVersionMajor = gSaveContext.sohStats.buildVersionMajor; - fileMetaInfo[fileNum].buildVersionMinor = gSaveContext.sohStats.buildVersionMinor; - fileMetaInfo[fileNum].buildVersionPatch = gSaveContext.sohStats.buildVersionPatch; - SohUtils::CopyStringToCharArray(fileMetaInfo[fileNum].buildVersion, gSaveContext.sohStats.buildVersion, + fileMetaInfo[fileNum].buildVersionMajor = gSaveContext.ship.stats.buildVersionMajor; + fileMetaInfo[fileNum].buildVersionMinor = gSaveContext.ship.stats.buildVersionMinor; + fileMetaInfo[fileNum].buildVersionPatch = gSaveContext.ship.stats.buildVersionPatch; + SohUtils::CopyStringToCharArray(fileMetaInfo[fileNum].buildVersion, gSaveContext.ship.stats.buildVersion, ARRAY_COUNT(fileMetaInfo[fileNum].buildVersion)); } @@ -821,8 +821,9 @@ void SaveManager::InitFileNormal() { for (int flag = 0; flag < ARRAY_COUNT(gSaveContext.infTable); flag++) { gSaveContext.infTable[flag] = 0; } - for (int flag = 0; flag < ARRAY_COUNT(gSaveContext.randomizerInf); flag++) { - gSaveContext.randomizerInf[flag] = 0; + // Currently randomizer flags are accessible from all quests + for (int flag = 0; flag < ARRAY_COUNT(gSaveContext.ship.randomizerInf); flag++) { + gSaveContext.ship.randomizerInf[flag] = 0; } gSaveContext.worldMapAreaData = 0; gSaveContext.scarecrowLongSongSet = 0; @@ -856,15 +857,14 @@ void SaveManager::InitFileNormal() { gSaveContext.sceneFlags[5].swch = 0x40000000; // SoH specific - gSaveContext.backupFW = gSaveContext.fw; - gSaveContext.pendingSale = ITEM_NONE; - gSaveContext.pendingSaleMod = MOD_NONE; - gSaveContext.isBossRushPaused = 0; - gSaveContext.pendingIceTrapCount = 0; - gSaveContext.maskMemory = PLAYER_MASK_NONE; + gSaveContext.ship.backupFW = gSaveContext.fw; + gSaveContext.ship.pendingSale = ITEM_NONE; + gSaveContext.ship.pendingSaleMod = MOD_NONE; + gSaveContext.ship.pendingIceTrapCount = 0; + gSaveContext.ship.maskMemory = PLAYER_MASK_NONE; // Init with normal quest unless only an MQ rom is provided - gSaveContext.questId = OTRGlobals::Instance->HasOriginal() ? QUEST_NORMAL : QUEST_MASTER; + gSaveContext.ship.quest.id = OTRGlobals::Instance->HasOriginal() ? QUEST_NORMAL : QUEST_MASTER; //RANDOTODO (ADD ITEMLOCATIONS TO GSAVECONTEXT) } @@ -1436,7 +1436,7 @@ void SaveManager::LoadBaseVersion1() { int isRando = 0; SaveManager::Instance->LoadData("n64ddFlag", isRando); if (isRando) { - gSaveContext.questId = QUEST_RANDOMIZER; + gSaveContext.ship.quest.id = QUEST_RANDOMIZER; } SaveManager::Instance->LoadData("healthCapacity", gSaveContext.healthCapacity); SaveManager::Instance->LoadData("health", gSaveContext.health); @@ -1561,8 +1561,8 @@ void SaveManager::LoadBaseVersion1() { SaveManager::Instance->LoadData("angle", gSaveContext.horseData.angle); }); - SaveManager::Instance->LoadArray("randomizerInf", ARRAY_COUNT(gSaveContext.randomizerInf), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.randomizerInf[i]); + SaveManager::Instance->LoadArray("randomizerInf", ARRAY_COUNT(gSaveContext.ship.randomizerInf), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.randomizerInf[i]); }); } @@ -1581,7 +1581,7 @@ void SaveManager::LoadBaseVersion2() { int isRando = 0; SaveManager::Instance->LoadData("n64ddFlag", isRando); if (isRando) { - gSaveContext.questId = QUEST_RANDOMIZER; + gSaveContext.ship.quest.id = QUEST_RANDOMIZER; } SaveManager::Instance->LoadData("healthCapacity", gSaveContext.healthCapacity); SaveManager::Instance->LoadData("health", gSaveContext.health); @@ -1648,26 +1648,26 @@ void SaveManager::LoadBaseVersion2() { SaveManager::Instance->LoadData("gsTokens", gSaveContext.inventory.gsTokens); }); SaveManager::Instance->LoadStruct("sohStats", []() { - SaveManager::Instance->LoadData("heartPieces", gSaveContext.sohStats.heartPieces); - SaveManager::Instance->LoadData("heartContainers", gSaveContext.sohStats.heartContainers); - SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.sohStats.dungeonKeys), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.dungeonKeys[i]); + SaveManager::Instance->LoadData("heartPieces", gSaveContext.ship.stats.heartPieces); + SaveManager::Instance->LoadData("heartContainers", gSaveContext.ship.stats.heartContainers); + SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.ship.stats.dungeonKeys), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.stats.dungeonKeys[i]); }); - SaveManager::Instance->LoadData("rtaTiming", gSaveContext.sohStats.rtaTiming); - SaveManager::Instance->LoadData("fileCreatedAt", gSaveContext.sohStats.fileCreatedAt); - SaveManager::Instance->LoadData("playTimer", gSaveContext.sohStats.playTimer); - SaveManager::Instance->LoadData("pauseTimer", gSaveContext.sohStats.pauseTimer); - SaveManager::Instance->LoadArray("timestamps", ARRAY_COUNT(gSaveContext.sohStats.itemTimestamp), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.itemTimestamp[i]); + SaveManager::Instance->LoadData("rtaTiming", gSaveContext.ship.stats.rtaTiming); + SaveManager::Instance->LoadData("fileCreatedAt", gSaveContext.ship.stats.fileCreatedAt); + SaveManager::Instance->LoadData("playTimer", gSaveContext.ship.stats.playTimer); + SaveManager::Instance->LoadData("pauseTimer", gSaveContext.ship.stats.pauseTimer); + SaveManager::Instance->LoadArray("timestamps", ARRAY_COUNT(gSaveContext.ship.stats.itemTimestamp), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.stats.itemTimestamp[i]); }); - SaveManager::Instance->LoadArray("counts", ARRAY_COUNT(gSaveContext.sohStats.count), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.count[i]); + SaveManager::Instance->LoadArray("counts", ARRAY_COUNT(gSaveContext.ship.stats.count), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.stats.count[i]); }); - SaveManager::Instance->LoadArray("scenesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.scenesDiscovered), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.scenesDiscovered[i]); + SaveManager::Instance->LoadArray("scenesDiscovered", ARRAY_COUNT(gSaveContext.ship.stats.scenesDiscovered), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.stats.scenesDiscovered[i]); }); - SaveManager::Instance->LoadArray("entrancesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.entrancesDiscovered), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.entrancesDiscovered[i]); + SaveManager::Instance->LoadArray("entrancesDiscovered", ARRAY_COUNT(gSaveContext.ship.stats.entrancesDiscovered), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.stats.entrancesDiscovered[i]); }); }); SaveManager::Instance->LoadArray("sceneFlags", ARRAY_COUNT(gSaveContext.sceneFlags), [](size_t i) { @@ -1745,13 +1745,13 @@ void SaveManager::LoadBaseVersion2() { SaveManager::Instance->LoadData("angle", gSaveContext.horseData.angle); }); - SaveManager::Instance->LoadArray("randomizerInf", ARRAY_COUNT(gSaveContext.randomizerInf), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.randomizerInf[i]); + SaveManager::Instance->LoadArray("randomizerInf", ARRAY_COUNT(gSaveContext.ship.randomizerInf), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.randomizerInf[i]); }); int isMQ = 0; SaveManager::Instance->LoadData("isMasterQuest", isMQ); if (isMQ) { - gSaveContext.questId = QUEST_MASTER; + gSaveContext.ship.quest.id = QUEST_MASTER; } // Workaround for breaking save compatibility from 5.0.2 -> 5.1.0 in commit d7c35221421bf712b5ead56a360f81f624aca4bc @@ -1797,7 +1797,7 @@ void SaveManager::LoadBaseVersion3() { int isRando = 0; SaveManager::Instance->LoadData("n64ddFlag", isRando); if (isRando) { - gSaveContext.questId = QUEST_RANDOMIZER; + gSaveContext.ship.quest.id = QUEST_RANDOMIZER; } SaveManager::Instance->LoadData("healthCapacity", gSaveContext.healthCapacity); SaveManager::Instance->LoadData("health", gSaveContext.health); @@ -1864,43 +1864,43 @@ void SaveManager::LoadBaseVersion3() { SaveManager::Instance->LoadData("gsTokens", gSaveContext.inventory.gsTokens); }); SaveManager::Instance->LoadStruct("sohStats", []() { - SaveManager::Instance->LoadCharArray("buildVersion", gSaveContext.sohStats.buildVersion, - ARRAY_COUNT(gSaveContext.sohStats.buildVersion)); - SaveManager::Instance->LoadData("buildVersionMajor", gSaveContext.sohStats.buildVersionMajor); - SaveManager::Instance->LoadData("buildVersionMinor", gSaveContext.sohStats.buildVersionMinor); - SaveManager::Instance->LoadData("buildVersionPatch", gSaveContext.sohStats.buildVersionPatch); + SaveManager::Instance->LoadCharArray("buildVersion", gSaveContext.ship.stats.buildVersion, + ARRAY_COUNT(gSaveContext.ship.stats.buildVersion)); + SaveManager::Instance->LoadData("buildVersionMajor", gSaveContext.ship.stats.buildVersionMajor); + SaveManager::Instance->LoadData("buildVersionMinor", gSaveContext.ship.stats.buildVersionMinor); + SaveManager::Instance->LoadData("buildVersionPatch", gSaveContext.ship.stats.buildVersionPatch); - SaveManager::Instance->LoadData("heartPieces", gSaveContext.sohStats.heartPieces); - SaveManager::Instance->LoadData("heartContainers", gSaveContext.sohStats.heartContainers); - SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.sohStats.dungeonKeys), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.dungeonKeys[i]); + SaveManager::Instance->LoadData("heartPieces", gSaveContext.ship.stats.heartPieces); + SaveManager::Instance->LoadData("heartContainers", gSaveContext.ship.stats.heartContainers); + SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.ship.stats.dungeonKeys), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.stats.dungeonKeys[i]); }); - SaveManager::Instance->LoadData("rtaTiming", gSaveContext.sohStats.rtaTiming); - SaveManager::Instance->LoadData("fileCreatedAt", gSaveContext.sohStats.fileCreatedAt); - SaveManager::Instance->LoadData("playTimer", gSaveContext.sohStats.playTimer); - SaveManager::Instance->LoadData("pauseTimer", gSaveContext.sohStats.pauseTimer); - SaveManager::Instance->LoadArray("itemTimestamps", ARRAY_COUNT(gSaveContext.sohStats.itemTimestamp), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.itemTimestamp[i]); + SaveManager::Instance->LoadData("rtaTiming", gSaveContext.ship.stats.rtaTiming); + SaveManager::Instance->LoadData("fileCreatedAt", gSaveContext.ship.stats.fileCreatedAt); + SaveManager::Instance->LoadData("playTimer", gSaveContext.ship.stats.playTimer); + SaveManager::Instance->LoadData("pauseTimer", gSaveContext.ship.stats.pauseTimer); + SaveManager::Instance->LoadArray("itemTimestamps", ARRAY_COUNT(gSaveContext.ship.stats.itemTimestamp), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.stats.itemTimestamp[i]); }); - SaveManager::Instance->LoadArray("sceneTimestamps", ARRAY_COUNT(gSaveContext.sohStats.sceneTimestamps), [](size_t i) { + SaveManager::Instance->LoadArray("sceneTimestamps", ARRAY_COUNT(gSaveContext.ship.stats.sceneTimestamps), [](size_t i) { SaveManager::Instance->LoadStruct("", [&i]() { - SaveManager::Instance->LoadData("scene", gSaveContext.sohStats.sceneTimestamps[i].scene); - SaveManager::Instance->LoadData("room", gSaveContext.sohStats.sceneTimestamps[i].room); - SaveManager::Instance->LoadData("sceneTime", gSaveContext.sohStats.sceneTimestamps[i].sceneTime); - SaveManager::Instance->LoadData("roomTime", gSaveContext.sohStats.sceneTimestamps[i].roomTime); - SaveManager::Instance->LoadData("isRoom", gSaveContext.sohStats.sceneTimestamps[i].isRoom); + SaveManager::Instance->LoadData("scene", gSaveContext.ship.stats.sceneTimestamps[i].scene); + SaveManager::Instance->LoadData("room", gSaveContext.ship.stats.sceneTimestamps[i].room); + SaveManager::Instance->LoadData("sceneTime", gSaveContext.ship.stats.sceneTimestamps[i].sceneTime); + SaveManager::Instance->LoadData("roomTime", gSaveContext.ship.stats.sceneTimestamps[i].roomTime); + SaveManager::Instance->LoadData("isRoom", gSaveContext.ship.stats.sceneTimestamps[i].isRoom); }); }); - SaveManager::Instance->LoadData("tsIdx", gSaveContext.sohStats.tsIdx); - SaveManager::Instance->LoadArray("counts", ARRAY_COUNT(gSaveContext.sohStats.count), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.count[i]); + SaveManager::Instance->LoadData("tsIdx", gSaveContext.ship.stats.tsIdx); + SaveManager::Instance->LoadArray("counts", ARRAY_COUNT(gSaveContext.ship.stats.count), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.stats.count[i]); }); - SaveManager::Instance->LoadArray("scenesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.scenesDiscovered), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.scenesDiscovered[i]); + SaveManager::Instance->LoadArray("scenesDiscovered", ARRAY_COUNT(gSaveContext.ship.stats.scenesDiscovered), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.stats.scenesDiscovered[i]); }); - SaveManager::Instance->LoadArray("entrancesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.entrancesDiscovered), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.entrancesDiscovered[i]); + SaveManager::Instance->LoadArray("entrancesDiscovered", ARRAY_COUNT(gSaveContext.ship.stats.entrancesDiscovered), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.stats.entrancesDiscovered[i]); }); }); SaveManager::Instance->LoadArray("sceneFlags", ARRAY_COUNT(gSaveContext.sceneFlags), [](size_t i) { @@ -1978,27 +1978,27 @@ void SaveManager::LoadBaseVersion3() { SaveManager::Instance->LoadData("angle", gSaveContext.horseData.angle); }); - SaveManager::Instance->LoadArray("randomizerInf", ARRAY_COUNT(gSaveContext.randomizerInf), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.randomizerInf[i]); + SaveManager::Instance->LoadArray("randomizerInf", ARRAY_COUNT(gSaveContext.ship.randomizerInf), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.randomizerInf[i]); }); int isMQ = 0; SaveManager::Instance->LoadData("isMasterQuest", isMQ); if (isMQ) { - gSaveContext.questId = QUEST_MASTER; + gSaveContext.ship.quest.id = QUEST_MASTER; } SaveManager::Instance->LoadStruct("backupFW", []() { SaveManager::Instance->LoadStruct("pos", []() { - SaveManager::Instance->LoadData("x", gSaveContext.backupFW.pos.x); - SaveManager::Instance->LoadData("y", gSaveContext.backupFW.pos.y); - SaveManager::Instance->LoadData("z", gSaveContext.backupFW.pos.z); + SaveManager::Instance->LoadData("x", gSaveContext.ship.backupFW.pos.x); + SaveManager::Instance->LoadData("y", gSaveContext.ship.backupFW.pos.y); + SaveManager::Instance->LoadData("z", gSaveContext.ship.backupFW.pos.z); }); - SaveManager::Instance->LoadData("yaw", gSaveContext.backupFW.yaw); - SaveManager::Instance->LoadData("playerParams", gSaveContext.backupFW.playerParams); - SaveManager::Instance->LoadData("entranceIndex", gSaveContext.backupFW.entranceIndex); - SaveManager::Instance->LoadData("roomIndex", gSaveContext.backupFW.roomIndex); - SaveManager::Instance->LoadData("set", gSaveContext.backupFW.set); - SaveManager::Instance->LoadData("tempSwchFlags", gSaveContext.backupFW.tempSwchFlags); - SaveManager::Instance->LoadData("tempCollectFlags", gSaveContext.backupFW.tempCollectFlags); + SaveManager::Instance->LoadData("yaw", gSaveContext.ship.backupFW.yaw); + SaveManager::Instance->LoadData("playerParams", gSaveContext.ship.backupFW.playerParams); + SaveManager::Instance->LoadData("entranceIndex", gSaveContext.ship.backupFW.entranceIndex); + SaveManager::Instance->LoadData("roomIndex", gSaveContext.ship.backupFW.roomIndex); + SaveManager::Instance->LoadData("set", gSaveContext.ship.backupFW.set); + SaveManager::Instance->LoadData("tempSwchFlags", gSaveContext.ship.backupFW.tempSwchFlags); + SaveManager::Instance->LoadData("tempCollectFlags", gSaveContext.ship.backupFW.tempCollectFlags); }); SaveManager::Instance->LoadData("dogParams", gSaveContext.dogParams); } @@ -2018,7 +2018,7 @@ void SaveManager::LoadBaseVersion4() { int isRando = 0; SaveManager::Instance->LoadData("n64ddFlag", isRando); if (isRando) { - gSaveContext.questId = QUEST_RANDOMIZER; + gSaveContext.ship.quest.id = QUEST_RANDOMIZER; } SaveManager::Instance->LoadData("healthCapacity", gSaveContext.healthCapacity); SaveManager::Instance->LoadData("health", gSaveContext.health); @@ -2159,30 +2159,30 @@ void SaveManager::LoadBaseVersion4() { SaveManager::Instance->LoadData("angle", gSaveContext.horseData.angle); }); - SaveManager::Instance->LoadArray("randomizerInf", ARRAY_COUNT(gSaveContext.randomizerInf), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.randomizerInf[i]); + SaveManager::Instance->LoadArray("randomizerInf", ARRAY_COUNT(gSaveContext.ship.randomizerInf), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.randomizerInf[i]); }); int isMQ = 0; SaveManager::Instance->LoadData("isMasterQuest", isMQ); if (isMQ) { - gSaveContext.questId = QUEST_MASTER; + gSaveContext.ship.quest.id = QUEST_MASTER; } SaveManager::Instance->LoadStruct("backupFW", []() { SaveManager::Instance->LoadStruct("pos", []() { - SaveManager::Instance->LoadData("x", gSaveContext.backupFW.pos.x); - SaveManager::Instance->LoadData("y", gSaveContext.backupFW.pos.y); - SaveManager::Instance->LoadData("z", gSaveContext.backupFW.pos.z); + SaveManager::Instance->LoadData("x", gSaveContext.ship.backupFW.pos.x); + SaveManager::Instance->LoadData("y", gSaveContext.ship.backupFW.pos.y); + SaveManager::Instance->LoadData("z", gSaveContext.ship.backupFW.pos.z); }); - SaveManager::Instance->LoadData("yaw", gSaveContext.backupFW.yaw); - SaveManager::Instance->LoadData("playerParams", gSaveContext.backupFW.playerParams); - SaveManager::Instance->LoadData("entranceIndex", gSaveContext.backupFW.entranceIndex); - SaveManager::Instance->LoadData("roomIndex", gSaveContext.backupFW.roomIndex); - SaveManager::Instance->LoadData("set", gSaveContext.backupFW.set); - SaveManager::Instance->LoadData("tempSwchFlags", gSaveContext.backupFW.tempSwchFlags); - SaveManager::Instance->LoadData("tempCollectFlags", gSaveContext.backupFW.tempCollectFlags); + SaveManager::Instance->LoadData("yaw", gSaveContext.ship.backupFW.yaw); + SaveManager::Instance->LoadData("playerParams", gSaveContext.ship.backupFW.playerParams); + SaveManager::Instance->LoadData("entranceIndex", gSaveContext.ship.backupFW.entranceIndex); + SaveManager::Instance->LoadData("roomIndex", gSaveContext.ship.backupFW.roomIndex); + SaveManager::Instance->LoadData("set", gSaveContext.ship.backupFW.set); + SaveManager::Instance->LoadData("tempSwchFlags", gSaveContext.ship.backupFW.tempSwchFlags); + SaveManager::Instance->LoadData("tempCollectFlags", gSaveContext.ship.backupFW.tempCollectFlags); }); SaveManager::Instance->LoadData("dogParams", gSaveContext.dogParams); - SaveManager::Instance->LoadData("maskMemory", gSaveContext.maskMemory); + SaveManager::Instance->LoadData("maskMemory", gSaveContext.ship.maskMemory); } void SaveManager::SaveBase(SaveContext* saveContext, int sectionID, bool fullSave) { @@ -2197,7 +2197,7 @@ void SaveManager::SaveBase(SaveContext* saveContext, int sectionID, bool fullSav SaveManager::Instance->SaveArray("playerName", ARRAY_COUNT(saveContext->playerName), [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->playerName[i]); }); - SaveManager::Instance->SaveData("n64ddFlag", saveContext->questId == QUEST_RANDOMIZER); + SaveManager::Instance->SaveData("n64ddFlag", saveContext->ship.quest.id == QUEST_RANDOMIZER); SaveManager::Instance->SaveData("healthCapacity", saveContext->healthCapacity); SaveManager::Instance->SaveData("health", saveContext->health); SaveManager::Instance->SaveData("magicLevel", saveContext->magicLevel); @@ -2333,26 +2333,26 @@ void SaveManager::SaveBase(SaveContext* saveContext, int sectionID, bool fullSav SaveManager::Instance->SaveData("angle", saveContext->horseData.angle); }); - SaveManager::Instance->SaveArray("randomizerInf", ARRAY_COUNT(saveContext->randomizerInf), [&](size_t i) { - SaveManager::Instance->SaveData("", saveContext->randomizerInf[i]); + SaveManager::Instance->SaveArray("randomizerInf", ARRAY_COUNT(saveContext->ship.randomizerInf), [&](size_t i) { + SaveManager::Instance->SaveData("", saveContext->ship.randomizerInf[i]); }); - SaveManager::Instance->SaveData("isMasterQuest", saveContext->questId == QUEST_MASTER); + SaveManager::Instance->SaveData("isMasterQuest", saveContext->ship.quest.id == QUEST_MASTER); SaveManager::Instance->SaveStruct("backupFW", [&]() { SaveManager::Instance->SaveStruct("pos", [&]() { - SaveManager::Instance->SaveData("x", saveContext->backupFW.pos.x); - SaveManager::Instance->SaveData("y", saveContext->backupFW.pos.y); - SaveManager::Instance->SaveData("z", saveContext->backupFW.pos.z); + SaveManager::Instance->SaveData("x", saveContext->ship.backupFW.pos.x); + SaveManager::Instance->SaveData("y", saveContext->ship.backupFW.pos.y); + SaveManager::Instance->SaveData("z", saveContext->ship.backupFW.pos.z); }); - SaveManager::Instance->SaveData("yaw", saveContext->backupFW.yaw); - SaveManager::Instance->SaveData("playerParams", saveContext->backupFW.playerParams); - SaveManager::Instance->SaveData("entranceIndex", saveContext->backupFW.entranceIndex); - SaveManager::Instance->SaveData("roomIndex", saveContext->backupFW.roomIndex); - SaveManager::Instance->SaveData("set", saveContext->backupFW.set); - SaveManager::Instance->SaveData("tempSwchFlags", saveContext->backupFW.tempSwchFlags); - SaveManager::Instance->SaveData("tempCollectFlags", saveContext->backupFW.tempCollectFlags); + SaveManager::Instance->SaveData("yaw", saveContext->ship.backupFW.yaw); + SaveManager::Instance->SaveData("playerParams", saveContext->ship.backupFW.playerParams); + SaveManager::Instance->SaveData("entranceIndex", saveContext->ship.backupFW.entranceIndex); + SaveManager::Instance->SaveData("roomIndex", saveContext->ship.backupFW.roomIndex); + SaveManager::Instance->SaveData("set", saveContext->ship.backupFW.set); + SaveManager::Instance->SaveData("tempSwchFlags", saveContext->ship.backupFW.tempSwchFlags); + SaveManager::Instance->SaveData("tempCollectFlags", saveContext->ship.backupFW.tempCollectFlags); }); SaveManager::Instance->SaveData("dogParams", saveContext->dogParams); - SaveManager::Instance->SaveData("maskMemory", saveContext->maskMemory); + SaveManager::Instance->SaveData("maskMemory", saveContext->ship.maskMemory); } // Load a string into a char array based on size and ensuring it is null terminated when overflowed diff --git a/soh/src/code/z_actor.c b/soh/src/code/z_actor.c index 70c7a3233..306a4f89c 100644 --- a/soh/src/code/z_actor.c +++ b/soh/src/code/z_actor.c @@ -4982,15 +4982,33 @@ void Flags_UnsetEventInf(s32 flag) { * Tests if "randomizerInf" flag is set. */ s32 Flags_GetRandomizerInf(RandomizerInf flag) { - return gSaveContext.randomizerInf[flag >> 4] & (1 << (flag & 0xF)); + // Randomizer flags are currently accessible from any quest (boss rush as an example) + /* + if (!IS_RANDO) { + LUSLOG_ERROR("Tried to get randomizerInf flag \"%d\" outside of rando", flag); + assert(false); + return 0; + } + */ + + return gSaveContext.ship.randomizerInf[flag >> 4] & (1 << (flag & 0xF)); } /** * Sets "randomizerInf" flag. */ void Flags_SetRandomizerInf(RandomizerInf flag) { + // Randomizer flags are currently accessible from any quest (boss rush as an example) + /* + if (!IS_RANDO) { + LUSLOG_ERROR("Tried to set randomizerInf flag \"%d\" outside of rando", flag); + assert(false); + return; + } + */ + s32 previouslyOff = !Flags_GetRandomizerInf(flag); - gSaveContext.randomizerInf[flag >> 4] |= (1 << (flag & 0xF)); + gSaveContext.ship.randomizerInf[flag >> 4] |= (1 << (flag & 0xF)); if (previouslyOff) { LUSLOG_INFO("RandomizerInf Flag Set - %#x", flag); GameInteractor_ExecuteOnFlagSet(FLAG_RANDOMIZER_INF, flag); @@ -5001,8 +5019,17 @@ void Flags_SetRandomizerInf(RandomizerInf flag) { * Unsets "randomizerInf" flag. */ void Flags_UnsetRandomizerInf(RandomizerInf flag) { + // Randomizer flags are currently accessible from any quest (boss rush as an example) + /* + if (!IS_RANDO) { + LUSLOG_ERROR("Tried to unset randomizerInf flag \"%d\" outside of rando", flag); + assert(false); + return; + } + */ + s32 previouslyOn = Flags_GetRandomizerInf(flag); - gSaveContext.randomizerInf[flag >> 4] &= ~(1 << (flag & 0xF)); + gSaveContext.ship.randomizerInf[flag >> 4] &= ~(1 << (flag & 0xF)); if (previouslyOn) { LUSLOG_INFO("RandomizerInf Flag Unset - %#x", flag); GameInteractor_ExecuteOnFlagUnset(FLAG_RANDOMIZER_INF, flag); diff --git a/soh/src/code/z_demo.c b/soh/src/code/z_demo.c index 4943b8390..9821b8d26 100644 --- a/soh/src/code/z_demo.c +++ b/soh/src/code/z_demo.c @@ -626,8 +626,8 @@ void Cutscene_Command_Terminator(PlayState* play, CutsceneContext* csCtx, CsCmdB break; case 8: if (CVarGetInteger(CVAR_ENHANCEMENT("BetterFarore"), 0)) { - FaroresWindData tempFW = gSaveContext.backupFW; - gSaveContext.backupFW = gSaveContext.fw; + FaroresWindData tempFW = gSaveContext.ship.backupFW; + gSaveContext.ship.backupFW = gSaveContext.fw; gSaveContext.fw = tempFW; } else { gSaveContext.fw.set = 0; diff --git a/soh/src/code/z_draw.c b/soh/src/code/z_draw.c index e27f230b1..523f65bbd 100644 --- a/soh/src/code/z_draw.c +++ b/soh/src/code/z_draw.c @@ -1046,7 +1046,7 @@ void GetItem_DrawTriforcePiece(PlayState* play, s16 drawId) { Matrix_Scale(0.035f, 0.035f, 0.035f, MTXMODE_APPLY); - uint8_t index = gSaveContext.triforcePiecesCollected % 3; + uint8_t index = gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected % 3; Gfx* triforcePieceDL; switch (index) { diff --git a/soh/src/code/z_kaleido_scope_call.c b/soh/src/code/z_kaleido_scope_call.c index 196e20041..bc21b9b55 100644 --- a/soh/src/code/z_kaleido_scope_call.c +++ b/soh/src/code/z_kaleido_scope_call.c @@ -59,9 +59,9 @@ void KaleidoScopeCall_Update(PlayState* play) { GameInteractor_ExecuteOnKaleidoUpdate(); - if (!gSaveContext.sohStats.gameComplete && - (!IS_BOSS_RUSH || !gSaveContext.isBossRushPaused)) { - gSaveContext.sohStats.pauseTimer++; + if (!gSaveContext.ship.stats.gameComplete && + (!IS_BOSS_RUSH || !gSaveContext.ship.quest.data.bossRush.isPaused)) { + gSaveContext.ship.stats.pauseTimer++; } if ((pauseCtx->state != 0) || (pauseCtx->debugState != 0)) { @@ -73,7 +73,7 @@ void KaleidoScopeCall_Update(PlayState* play) { pauseCtx->unk_1E4 = 0; pauseCtx->unk_1EC = 0; pauseCtx->state = (pauseCtx->state & 0xFFFF) + 1; - gSaveContext.sohStats.count[COUNT_PAUSES]++; + gSaveContext.ship.stats.count[COUNT_PAUSES]++; } } else if (pauseCtx->state == 8) { HREG(80) = 7; diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index 396188b48..39c6e111d 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -1812,7 +1812,7 @@ void func_80084BF4(PlayState* play, u16 flag) { void GameplayStats_SetTimestamp(PlayState* play, u8 item) { // If we already have a timestamp for this item, do nothing - if (gSaveContext.sohStats.itemTimestamp[item] != 0){ + if (gSaveContext.ship.stats.itemTimestamp[item] != 0){ return; } // Use ITEM_KEY_BOSS only for Ganon's boss key - not any other boss keys @@ -1831,20 +1831,20 @@ void GameplayStats_SetTimestamp(PlayState* play, u8 item) { // Count any bottled item as a bottle if (item >= ITEM_BOTTLE && item <= ITEM_POE) { - if (gSaveContext.sohStats.itemTimestamp[ITEM_BOTTLE] == 0) { - gSaveContext.sohStats.itemTimestamp[ITEM_BOTTLE] = time; + if (gSaveContext.ship.stats.itemTimestamp[ITEM_BOTTLE] == 0) { + gSaveContext.ship.stats.itemTimestamp[ITEM_BOTTLE] = time; } return; } // Count any bombchu pack as bombchus if (item == ITEM_BOMBCHU || (item >= ITEM_BOMBCHUS_5 && item <= ITEM_BOMBCHUS_20)) { - if (gSaveContext.sohStats.itemTimestamp[ITEM_BOMBCHU] == 0) { - gSaveContext.sohStats.itemTimestamp[ITEM_BOMBCHU] = time; + if (gSaveContext.ship.stats.itemTimestamp[ITEM_BOMBCHU] == 0) { + gSaveContext.ship.stats.itemTimestamp[ITEM_BOMBCHU] = time; } return; } - gSaveContext.sohStats.itemTimestamp[item] = time; + gSaveContext.ship.stats.itemTimestamp[item] = time; GameInteractor_ExecuteOnTimestamp(item); } @@ -2338,7 +2338,7 @@ u8 Item_Give(PlayState* play, u8 item) { return Return_Item(item, MOD_NONE, ITEM_NONE); } else if ((item == ITEM_HEART_PIECE_2) || (item == ITEM_HEART_PIECE)) { gSaveContext.inventory.questItems += 1 << (QUEST_HEART_PIECE + 4); - gSaveContext.sohStats.heartPieces++; + gSaveContext.ship.stats.heartPieces++; return Return_Item(item, MOD_NONE, ITEM_NONE); } else if (item == ITEM_HEART_CONTAINER) { if (!CVarGetInteger(CVAR_ENHANCEMENT("HurtContainer"), 0)) { @@ -2348,7 +2348,7 @@ u8 Item_Give(PlayState* play, u8 item) { gSaveContext.healthCapacity -= 0x10; gSaveContext.health -= 0x10; } - gSaveContext.sohStats.heartContainers++; + gSaveContext.ship.stats.heartContainers++; return Return_Item(item, MOD_NONE, ITEM_NONE); } else if (item == ITEM_HEART) { osSyncPrintf("回復ハート回復ハート回復ハート\n"); // "Recovery Heart" @@ -2447,7 +2447,7 @@ u8 Item_Give(PlayState* play, u8 item) { } if (item >= ITEM_POCKET_EGG) { - gSaveContext.adultTradeItems |= ADULT_TRADE_FLAG(item); + gSaveContext.ship.quest.data.randomizer.adultTradeItems |= ADULT_TRADE_FLAG(item); } temp = INV_CONTENT(item); @@ -2763,8 +2763,8 @@ bool Inventory_HatchPocketCucco(PlayState* play) { return 0; } - gSaveContext.adultTradeItems &= ~ADULT_TRADE_FLAG(ITEM_POCKET_EGG); - gSaveContext.adultTradeItems |= ADULT_TRADE_FLAG(ITEM_POCKET_CUCCO); + gSaveContext.ship.quest.data.randomizer.adultTradeItems &= ~ADULT_TRADE_FLAG(ITEM_POCKET_EGG); + gSaveContext.ship.quest.data.randomizer.adultTradeItems |= ADULT_TRADE_FLAG(ITEM_POCKET_CUCCO); Inventory_ReplaceItem(play, ITEM_POCKET_EGG, ITEM_POCKET_CUCCO); return 1; } @@ -2882,7 +2882,7 @@ s32 Health_ChangeBy(PlayState* play, s16 healthChange) { gSaveContext.healthCapacity); if (healthChange < 0) { - gSaveContext.sohStats.count[COUNT_DAMAGE_TAKEN] += -healthChange; + gSaveContext.ship.stats.count[COUNT_DAMAGE_TAKEN] += -healthChange; } // If one-hit ko mode is on, any damage kills you and you cannot gain health. @@ -2952,10 +2952,10 @@ void Rupees_ChangeBy(s16 rupeeChange) { } if (rupeeChange > 0) { - gSaveContext.sohStats.count[COUNT_RUPEES_COLLECTED] += rupeeChange; + gSaveContext.ship.stats.count[COUNT_RUPEES_COLLECTED] += rupeeChange; } if (rupeeChange < 0) { - gSaveContext.sohStats.count[COUNT_RUPEES_SPENT] += -rupeeChange; + gSaveContext.ship.stats.count[COUNT_RUPEES_SPENT] += -rupeeChange; } } @@ -2963,25 +2963,25 @@ void GameplayStats_UpdateAmmoUsed(s16 item, s16 ammoUsed) { switch (item) { case ITEM_STICK: - gSaveContext.sohStats.count[COUNT_AMMO_USED_STICK] += ammoUsed; + gSaveContext.ship.stats.count[COUNT_AMMO_USED_STICK] += ammoUsed; break; case ITEM_NUT: - gSaveContext.sohStats.count[COUNT_AMMO_USED_NUT] += ammoUsed; + gSaveContext.ship.stats.count[COUNT_AMMO_USED_NUT] += ammoUsed; break; case ITEM_BOMB: - gSaveContext.sohStats.count[COUNT_AMMO_USED_BOMB] += ammoUsed; + gSaveContext.ship.stats.count[COUNT_AMMO_USED_BOMB] += ammoUsed; break; case ITEM_BOW: - gSaveContext.sohStats.count[COUNT_AMMO_USED_ARROW] += ammoUsed; + gSaveContext.ship.stats.count[COUNT_AMMO_USED_ARROW] += ammoUsed; break; case ITEM_SLINGSHOT: - gSaveContext.sohStats.count[COUNT_AMMO_USED_SEED] += ammoUsed; + gSaveContext.ship.stats.count[COUNT_AMMO_USED_SEED] += ammoUsed; break; case ITEM_BOMBCHU: - gSaveContext.sohStats.count[COUNT_AMMO_USED_BOMBCHU] += ammoUsed; + gSaveContext.ship.stats.count[COUNT_AMMO_USED_BOMBCHU] += ammoUsed; break; case ITEM_BEAN: - gSaveContext.sohStats.count[COUNT_AMMO_USED_BEAN] += ammoUsed; + gSaveContext.ship.stats.count[COUNT_AMMO_USED_BEAN] += ammoUsed; break; default: break; @@ -6122,7 +6122,7 @@ void Interface_Draw(PlayState* play) { void Interface_DrawTotalGameplayTimer(PlayState* play) { // Draw timer based on the Gameplay Stats total time. - if ((IS_BOSS_RUSH && gSaveContext.bossRushOptions[BR_OPTIONS_TIMER] == BR_CHOICE_TIMER_YES) || + if ((IS_BOSS_RUSH && gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_TIMER] == BR_CHOICE_TIMER_YES) || (CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.ShowIngameTimer"), 0) && gSaveContext.fileNum >= 0 && gSaveContext.fileNum <= 2)) { s32 X_Margins_Timer = 0; @@ -6202,9 +6202,9 @@ void Interface_DrawTotalGameplayTimer(PlayState* play) { (rectTop + rectHeight) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); // Draw regular text. Change color based on if the timer is paused, running or the game is completed. - if (gSaveContext.sohStats.gameComplete) { + if (gSaveContext.ship.stats.gameComplete) { gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 120, 255, 0, 255); - } else if (gSaveContext.isBossRushPaused && !gSaveContext.sohStats.rtaTiming) { + } else if (IS_BOSS_RUSH && gSaveContext.ship.quest.data.bossRush.isPaused && !gSaveContext.ship.stats.rtaTiming) { gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 150, 150, 150, 255); } else { gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, 255); @@ -6429,11 +6429,11 @@ void Interface_Update(PlayState* play) { } else { gSaveContext.rupeeAccumulator = 0; } - if (gSaveContext.rupeeAccumulator == 0 && gSaveContext.pendingSale != ITEM_NONE) { - u16 tempSaleItem = gSaveContext.pendingSale; - u16 tempSaleMod = gSaveContext.pendingSaleMod; - gSaveContext.pendingSale = ITEM_NONE; - gSaveContext.pendingSaleMod = MOD_NONE; + if (gSaveContext.rupeeAccumulator == 0 && gSaveContext.ship.pendingSale != ITEM_NONE) { + u16 tempSaleItem = gSaveContext.ship.pendingSale; + u16 tempSaleMod = gSaveContext.ship.pendingSaleMod; + gSaveContext.ship.pendingSale = ITEM_NONE; + gSaveContext.ship.pendingSaleMod = MOD_NONE; if (tempSaleMod == MOD_NONE) { GetItemID getItemID = RetrieveGetItemIDFromItemID(tempSaleItem); RandomizerGet randomizerGet = RetrieveRandomizerGetFromItemID(tempSaleItem); diff --git a/soh/src/code/z_play.c b/soh/src/code/z_play.c index df1314e71..cc7af190d 100644 --- a/soh/src/code/z_play.c +++ b/soh/src/code/z_play.c @@ -646,32 +646,32 @@ void Play_Init(GameState* thisx) { gSaveContext.respawnFlag = 0; // #region SOH [Stats] - if (gSaveContext.sohStats.sceneNum != gPlayState->sceneNum) { - u16 idx = gSaveContext.sohStats.tsIdx; - gSaveContext.sohStats.sceneTimestamps[idx].sceneTime = gSaveContext.sohStats.sceneTimer / 2; - gSaveContext.sohStats.sceneTimestamps[idx].roomTime = gSaveContext.sohStats.roomTimer / 2; - gSaveContext.sohStats.sceneTimestamps[idx].scene = gSaveContext.sohStats.sceneNum; - gSaveContext.sohStats.sceneTimestamps[idx].room = gSaveContext.sohStats.roomNum; - gSaveContext.sohStats.sceneTimestamps[idx].isRoom = - gPlayState->sceneNum == gSaveContext.sohStats.sceneTimestamps[idx].scene && - gPlayState->roomCtx.curRoom.num != gSaveContext.sohStats.sceneTimestamps[idx].room; - gSaveContext.sohStats.tsIdx++; - gSaveContext.sohStats.sceneTimer = 0; - gSaveContext.sohStats.roomTimer = 0; - } else if (gSaveContext.sohStats.roomNum != gPlayState->roomCtx.curRoom.num) { - u16 idx = gSaveContext.sohStats.tsIdx; - gSaveContext.sohStats.sceneTimestamps[idx].roomTime = gSaveContext.sohStats.roomTimer / 2; - gSaveContext.sohStats.sceneTimestamps[idx].scene = gSaveContext.sohStats.sceneNum; - gSaveContext.sohStats.sceneTimestamps[idx].room = gSaveContext.sohStats.roomNum; - gSaveContext.sohStats.sceneTimestamps[idx].isRoom = - gPlayState->sceneNum == gSaveContext.sohStats.sceneTimestamps[idx].scene && - gPlayState->roomCtx.curRoom.num != gSaveContext.sohStats.sceneTimestamps[idx].room; - gSaveContext.sohStats.tsIdx++; - gSaveContext.sohStats.roomTimer = 0; + if (gSaveContext.ship.stats.sceneNum != gPlayState->sceneNum) { + u16 idx = gSaveContext.ship.stats.tsIdx; + gSaveContext.ship.stats.sceneTimestamps[idx].sceneTime = gSaveContext.ship.stats.sceneTimer / 2; + gSaveContext.ship.stats.sceneTimestamps[idx].roomTime = gSaveContext.ship.stats.roomTimer / 2; + gSaveContext.ship.stats.sceneTimestamps[idx].scene = gSaveContext.ship.stats.sceneNum; + gSaveContext.ship.stats.sceneTimestamps[idx].room = gSaveContext.ship.stats.roomNum; + gSaveContext.ship.stats.sceneTimestamps[idx].isRoom = + gPlayState->sceneNum == gSaveContext.ship.stats.sceneTimestamps[idx].scene && + gPlayState->roomCtx.curRoom.num != gSaveContext.ship.stats.sceneTimestamps[idx].room; + gSaveContext.ship.stats.tsIdx++; + gSaveContext.ship.stats.sceneTimer = 0; + gSaveContext.ship.stats.roomTimer = 0; + } else if (gSaveContext.ship.stats.roomNum != gPlayState->roomCtx.curRoom.num) { + u16 idx = gSaveContext.ship.stats.tsIdx; + gSaveContext.ship.stats.sceneTimestamps[idx].roomTime = gSaveContext.ship.stats.roomTimer / 2; + gSaveContext.ship.stats.sceneTimestamps[idx].scene = gSaveContext.ship.stats.sceneNum; + gSaveContext.ship.stats.sceneTimestamps[idx].room = gSaveContext.ship.stats.roomNum; + gSaveContext.ship.stats.sceneTimestamps[idx].isRoom = + gPlayState->sceneNum == gSaveContext.ship.stats.sceneTimestamps[idx].scene && + gPlayState->roomCtx.curRoom.num != gSaveContext.ship.stats.sceneTimestamps[idx].room; + gSaveContext.ship.stats.tsIdx++; + gSaveContext.ship.stats.roomTimer = 0; } - gSaveContext.sohStats.sceneNum = gPlayState->sceneNum; - gSaveContext.sohStats.roomNum = gPlayState->roomCtx.curRoom.num; + gSaveContext.ship.stats.sceneNum = gPlayState->sceneNum; + gSaveContext.ship.stats.roomNum = gPlayState->roomCtx.curRoom.num; // #endregion #if 0 @@ -741,28 +741,28 @@ void Play_Update(PlayState* play) { } // #region SOH [Stats] Gameplay stats: Count button presses - if (!gSaveContext.sohStats.gameComplete) { - if (CHECK_BTN_ALL(input[0].press.button, BTN_A)) {gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_A]++;} - if (CHECK_BTN_ALL(input[0].press.button, BTN_B)) {gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_B]++;} - if (CHECK_BTN_ALL(input[0].press.button, BTN_CUP)) {gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_CUP]++;} - if (CHECK_BTN_ALL(input[0].press.button, BTN_CRIGHT)) {gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_CRIGHT]++;} - if (CHECK_BTN_ALL(input[0].press.button, BTN_CLEFT)) {gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_CLEFT]++;} - if (CHECK_BTN_ALL(input[0].press.button, BTN_CDOWN)) {gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_CDOWN]++;} - if (CHECK_BTN_ALL(input[0].press.button, BTN_DUP)) {gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_DUP]++;} - if (CHECK_BTN_ALL(input[0].press.button, BTN_DRIGHT)) {gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_DRIGHT]++;} - if (CHECK_BTN_ALL(input[0].press.button, BTN_DDOWN)) {gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_DDOWN]++;} - if (CHECK_BTN_ALL(input[0].press.button, BTN_DLEFT)) {gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_DLEFT]++;} - if (CHECK_BTN_ALL(input[0].press.button, BTN_L)) {gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_L]++;} - if (CHECK_BTN_ALL(input[0].press.button, BTN_R)) {gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_R]++;} - if (CHECK_BTN_ALL(input[0].press.button, BTN_Z)) {gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_Z]++;} - if (CHECK_BTN_ALL(input[0].press.button, BTN_START)) {gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_START]++;} + if (!gSaveContext.ship.stats.gameComplete) { + if (CHECK_BTN_ALL(input[0].press.button, BTN_A)) {gSaveContext.ship.stats.count[COUNT_BUTTON_PRESSES_A]++;} + if (CHECK_BTN_ALL(input[0].press.button, BTN_B)) {gSaveContext.ship.stats.count[COUNT_BUTTON_PRESSES_B]++;} + if (CHECK_BTN_ALL(input[0].press.button, BTN_CUP)) {gSaveContext.ship.stats.count[COUNT_BUTTON_PRESSES_CUP]++;} + if (CHECK_BTN_ALL(input[0].press.button, BTN_CRIGHT)) {gSaveContext.ship.stats.count[COUNT_BUTTON_PRESSES_CRIGHT]++;} + if (CHECK_BTN_ALL(input[0].press.button, BTN_CLEFT)) {gSaveContext.ship.stats.count[COUNT_BUTTON_PRESSES_CLEFT]++;} + if (CHECK_BTN_ALL(input[0].press.button, BTN_CDOWN)) {gSaveContext.ship.stats.count[COUNT_BUTTON_PRESSES_CDOWN]++;} + if (CHECK_BTN_ALL(input[0].press.button, BTN_DUP)) {gSaveContext.ship.stats.count[COUNT_BUTTON_PRESSES_DUP]++;} + if (CHECK_BTN_ALL(input[0].press.button, BTN_DRIGHT)) {gSaveContext.ship.stats.count[COUNT_BUTTON_PRESSES_DRIGHT]++;} + if (CHECK_BTN_ALL(input[0].press.button, BTN_DDOWN)) {gSaveContext.ship.stats.count[COUNT_BUTTON_PRESSES_DDOWN]++;} + if (CHECK_BTN_ALL(input[0].press.button, BTN_DLEFT)) {gSaveContext.ship.stats.count[COUNT_BUTTON_PRESSES_DLEFT]++;} + if (CHECK_BTN_ALL(input[0].press.button, BTN_L)) {gSaveContext.ship.stats.count[COUNT_BUTTON_PRESSES_L]++;} + if (CHECK_BTN_ALL(input[0].press.button, BTN_R)) {gSaveContext.ship.stats.count[COUNT_BUTTON_PRESSES_R]++;} + if (CHECK_BTN_ALL(input[0].press.button, BTN_Z)) {gSaveContext.ship.stats.count[COUNT_BUTTON_PRESSES_Z]++;} + if (CHECK_BTN_ALL(input[0].press.button, BTN_START)) {gSaveContext.ship.stats.count[COUNT_BUTTON_PRESSES_START]++;} // Start RTA timing on first non-c-up input after intro cutscene if ( - !gSaveContext.sohStats.fileCreatedAt && !Player_InCsMode(play) && + !gSaveContext.ship.stats.fileCreatedAt && !Player_InCsMode(play) && ((input[0].press.button && input[0].press.button != 0x8) || input[0].rel.stick_x != 0 || input[0].rel.stick_y != 0) ) { - gSaveContext.sohStats.fileCreatedAt = GetUnixTimestamp(); + gSaveContext.ship.stats.fileCreatedAt = GetUnixTimestamp(); } } // #endregion @@ -1146,14 +1146,14 @@ void Play_Update(PlayState* play) { func_800AA178(true); // Gameplay stat tracking - if (!gSaveContext.sohStats.gameComplete && - (!IS_BOSS_RUSH || !gSaveContext.isBossRushPaused)) { - gSaveContext.sohStats.playTimer++; - gSaveContext.sohStats.sceneTimer++; - gSaveContext.sohStats.roomTimer++; + if (!gSaveContext.ship.stats.gameComplete && + (!IS_BOSS_RUSH || !gSaveContext.ship.quest.data.bossRush.isPaused)) { + gSaveContext.ship.stats.playTimer++; + gSaveContext.ship.stats.sceneTimer++; + gSaveContext.ship.stats.roomTimer++; if (CVarGetInteger(CVAR_ENHANCEMENT("MMBunnyHood"), BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA && Player_GetMask(play) == PLAYER_MASK_BUNNY) { - gSaveContext.sohStats.count[COUNT_TIME_BUNNY_HOOD]++; + gSaveContext.ship.stats.count[COUNT_TIME_BUNNY_HOOD]++; } } @@ -2220,7 +2220,7 @@ void Play_PerformSave(PlayState* play) { uint8_t triforceHuntCompleted = IS_RANDO && - gSaveContext.triforcePiecesCollected == (Randomizer_GetSettingValue(RSK_TRIFORCE_HUNT_PIECES_REQUIRED) + 1) && + gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected == (Randomizer_GetSettingValue(RSK_TRIFORCE_HUNT_PIECES_REQUIRED) + 1) && Randomizer_GetSettingValue(RSK_TRIFORCE_HUNT); if (CVarGetInteger(CVAR_ENHANCEMENT("Autosave"), AUTOSAVE_OFF) != AUTOSAVE_OFF || triforceHuntCompleted) { Overlay_DisplayText(3.0f, "Game Saved"); diff --git a/soh/src/code/z_room.c b/soh/src/code/z_room.c index 2e8cdc655..fdd8f78f8 100644 --- a/soh/src/code/z_room.c +++ b/soh/src/code/z_room.c @@ -653,14 +653,14 @@ void func_80097534(PlayState* play, RoomContext* roomCtx) { Map_SavePlayerInitialInfo(play); } Audio_SetEnvReverb(play->roomCtx.curRoom.echo); - u8 idx = gSaveContext.sohStats.tsIdx; - gSaveContext.sohStats.sceneTimestamps[idx].scene = gSaveContext.sohStats.sceneNum; - gSaveContext.sohStats.sceneTimestamps[idx].room = gSaveContext.sohStats.roomNum; - gSaveContext.sohStats.sceneTimestamps[idx].roomTime = gSaveContext.sohStats.roomTimer / 2; - gSaveContext.sohStats.sceneTimestamps[idx].isRoom = - gPlayState->sceneNum == gSaveContext.sohStats.sceneTimestamps[idx].scene && - gPlayState->roomCtx.curRoom.num != gSaveContext.sohStats.sceneTimestamps[idx].room; - gSaveContext.sohStats.tsIdx++; - gSaveContext.sohStats.roomNum = roomCtx->curRoom.num; - gSaveContext.sohStats.roomTimer = 0; + u8 idx = gSaveContext.ship.stats.tsIdx; + gSaveContext.ship.stats.sceneTimestamps[idx].scene = gSaveContext.ship.stats.sceneNum; + gSaveContext.ship.stats.sceneTimestamps[idx].room = gSaveContext.ship.stats.roomNum; + gSaveContext.ship.stats.sceneTimestamps[idx].roomTime = gSaveContext.ship.stats.roomTimer / 2; + gSaveContext.ship.stats.sceneTimestamps[idx].isRoom = + gPlayState->sceneNum == gSaveContext.ship.stats.sceneTimestamps[idx].scene && + gPlayState->roomCtx.curRoom.num != gSaveContext.ship.stats.sceneTimestamps[idx].room; + gSaveContext.ship.stats.tsIdx++; + gSaveContext.ship.stats.roomNum = roomCtx->curRoom.num; + gSaveContext.ship.stats.roomTimer = 0; } diff --git a/soh/src/code/z_sram.c b/soh/src/code/z_sram.c index adea0cbbf..d6141d78b 100644 --- a/soh/src/code/z_sram.c +++ b/soh/src/code/z_sram.c @@ -142,7 +142,7 @@ void Sram_OpenSave() { } if (!CVarGetInteger(CVAR_ENHANCEMENT("PersistentMasks"), 0)) { - gSaveContext.maskMemory = PLAYER_MASK_NONE; + gSaveContext.ship.maskMemory = PLAYER_MASK_NONE; } osSyncPrintf("scene_no = %d\n", gSaveContext.entranceIndex); @@ -252,11 +252,11 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) { u8 currentQuest = fileChooseCtx->questType[fileChooseCtx->buttonIndex]; if (currentQuest == QUEST_RANDOMIZER && (Randomizer_IsSeedGenerated() || Randomizer_IsSpoilerLoaded())) { - gSaveContext.questId = QUEST_RANDOMIZER; + gSaveContext.ship.quest.id = QUEST_RANDOMIZER; Randomizer_InitSaveFile(); } else { - gSaveContext.questId = currentQuest; + gSaveContext.ship.quest.id = currentQuest; } Save_SaveFile(); diff --git a/soh/src/overlays/actors/ovl_En_Box/z_en_box.c b/soh/src/overlays/actors/ovl_En_Box/z_en_box.c index bcb0cb1fc..b6fb10f3c 100644 --- a/soh/src/overlays/actors/ovl_En_Box/z_en_box.c +++ b/soh/src/overlays/actors/ovl_En_Box/z_en_box.c @@ -487,7 +487,7 @@ void EnBox_Open(EnBox* this, PlayState* play) { if (Animation_OnFrame(&this->skelanime, 30.0f)) { sfxId = NA_SE_EV_TBOX_UNLOCK; - gSaveContext.sohStats.count[COUNT_CHESTS_OPENED]++; + gSaveContext.ship.stats.count[COUNT_CHESTS_OPENED]++; } else if (Animation_OnFrame(&this->skelanime, 90.0f)) { sfxId = NA_SE_EV_TBOX_OPEN; } diff --git a/soh/src/overlays/actors/ovl_En_Dns/z_en_dns.c b/soh/src/overlays/actors/ovl_En_Dns/z_en_dns.c index fb665f74d..e79b7c7c8 100644 --- a/soh/src/overlays/actors/ovl_En_Dns/z_en_dns.c +++ b/soh/src/overlays/actors/ovl_En_Dns/z_en_dns.c @@ -391,8 +391,8 @@ void func_809EFDD0(EnDns* this, PlayState* play) { pendingGetItemId = this->dnsItemEntry->getItemId; } GetItemEntry itemEntry = ItemTable_Retrieve(pendingGetItemId); - gSaveContext.pendingSale = itemEntry.itemId; - gSaveContext.pendingSaleMod = itemEntry.modIndex; + gSaveContext.ship.pendingSale = itemEntry.itemId; + gSaveContext.ship.pendingSaleMod = itemEntry.modIndex; Actor_OfferGetItem(&this->actor, play, pendingGetItemId, 130.0f, 100.0f); } diff --git a/soh/src/overlays/actors/ovl_En_Ds/z_en_ds.c b/soh/src/overlays/actors/ovl_En_Ds/z_en_ds.c index 497ba9388..82ae493db 100644 --- a/soh/src/overlays/actors/ovl_En_Ds/z_en_ds.c +++ b/soh/src/overlays/actors/ovl_En_Ds/z_en_ds.c @@ -206,8 +206,8 @@ void EnDs_OfferBluePotion(EnDs* this, PlayState* play) { if (GameInteractor_Should(VB_GIVE_ITEM_FROM_GRANNYS_SHOP, true, this)) { GetItemEntry itemEntry = ItemTable_Retrieve(GI_POTION_BLUE); Actor_OfferGetItem(&this->actor, play, GI_POTION_BLUE, 10000.0f, 50.0f); - gSaveContext.pendingSale = itemEntry.itemId; - gSaveContext.pendingSaleMod = itemEntry.modIndex; + gSaveContext.ship.pendingSale = itemEntry.itemId; + gSaveContext.ship.pendingSaleMod = itemEntry.modIndex; this->actionFunc = EnDs_GiveBluePotion; } diff --git a/soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c b/soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c index b1ecb001e..3343fb615 100644 --- a/soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c +++ b/soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c @@ -880,16 +880,16 @@ s32 EnGirlA_CanBuy_Randomizer(PlayState* play, EnGirlA* this) { void EnGirlA_ItemGive_Arrows(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; Inventory_ChangeAmmo(ITEM_BOW, this->itemCount); Rupees_ChangeBy(-this->basePrice); } void EnGirlA_ItemGive_Bombs(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; switch (this->itemCount) { case 5: Item_Give(play, ITEM_BOMBS_5); @@ -909,8 +909,8 @@ void EnGirlA_ItemGive_Bombs(PlayState* play, EnGirlA* this) { void EnGirlA_ItemGive_DekuNuts(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; switch (this->itemCount) { case 5: Item_Give(play, ITEM_NUTS_5); @@ -924,16 +924,16 @@ void EnGirlA_ItemGive_DekuNuts(PlayState* play, EnGirlA* this) { void EnGirlA_ItemGive_DekuSticks(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; Item_Give(play, ITEM_STICK); Rupees_ChangeBy(-this->basePrice); } void EnGirlA_ItemGive_Longsword(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; func_800849EC(play); gSaveContext.swordHealth = 8; Rupees_ChangeBy(-this->basePrice); @@ -941,86 +941,86 @@ void EnGirlA_ItemGive_Longsword(PlayState* play, EnGirlA* this) { void EnGirlA_ItemGive_HylianShield(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; Item_Give(play, ITEM_SHIELD_HYLIAN); Rupees_ChangeBy(-this->basePrice); } void EnGirlA_ItemGive_DekuShield(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; Item_Give(play, ITEM_SHIELD_DEKU); Rupees_ChangeBy(-this->basePrice); } void EnGirlA_ItemGive_GoronTunic(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; Item_Give(play, ITEM_TUNIC_GORON); Rupees_ChangeBy(-this->basePrice); } void EnGirlA_ItemGive_ZoraTunic(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; Item_Give(play, ITEM_TUNIC_ZORA); Rupees_ChangeBy(-this->basePrice); } void EnGirlA_ItemGive_Health(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; Health_ChangeBy(play, this->itemCount); Rupees_ChangeBy(-this->basePrice); } void EnGirlA_ItemGive_MilkBottle(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; Item_Give(play, ITEM_MILK_BOTTLE); Rupees_ChangeBy(-this->basePrice); } void EnGirlA_ItemGive_WeirdEgg(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; Item_Give(play, ITEM_WEIRD_EGG); Rupees_ChangeBy(-this->basePrice); } void EnGirlA_ItemGive_Unk19(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; Rupees_ChangeBy(-this->basePrice); } void EnGirlA_ItemGive_Unk20(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; Rupees_ChangeBy(-this->basePrice); } void EnGirlA_ItemGive_DekuSeeds(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; Item_Give(play, ITEM_SEEDS_30); Rupees_ChangeBy(-this->basePrice); } void EnGirlA_ItemGive_BottledItem(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; switch (this->actor.params) { case SI_FISH: Item_Give(play, ITEM_FISH); @@ -1066,8 +1066,8 @@ void EnGirlA_ItemGive_Randomizer(PlayState* play, EnGirlA* this) { void EnGirlA_BuyEvent_ShieldDiscount(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; if (this->actor.params == SI_HYLIAN_SHIELD) { if (Flags_GetInfTable(INFTABLE_SHOWED_ZELDAS_LETTER_TO_GATE_GUARD)) { Rupees_ChangeBy(-(this->basePrice - sShieldDiscounts[(s32)Rand_ZeroFloat(7.9f)])); @@ -1079,22 +1079,22 @@ void EnGirlA_BuyEvent_ShieldDiscount(PlayState* play, EnGirlA* this) { void EnGirlA_BuyEvent_GoronTunic(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; Rupees_ChangeBy(-this->basePrice); } void EnGirlA_BuyEvent_ZoraTunic(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; Rupees_ChangeBy(-this->basePrice); } void EnGirlA_BuyEvent_ObtainBombchuPack(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; Rupees_ChangeBy(-this->basePrice); // Normally, buying a bombchu pack sets a flag indicating the pack is now sold out diff --git a/soh/src/overlays/actors/ovl_En_Js/z_en_js.c b/soh/src/overlays/actors/ovl_En_Js/z_en_js.c index 26e004f2f..48e62e400 100644 --- a/soh/src/overlays/actors/ovl_En_Js/z_en_js.c +++ b/soh/src/overlays/actors/ovl_En_Js/z_en_js.c @@ -135,8 +135,8 @@ void func_80A89160(EnJs* this, PlayState* play) { En_Js_SetupAction(this, func_80A8910C); } else { GetItemEntry itemEntry = ItemTable_Retrieve(GI_BOMBCHUS_10); - gSaveContext.pendingSale = itemEntry.itemId; - gSaveContext.pendingSaleMod = itemEntry.modIndex; + gSaveContext.ship.pendingSale = itemEntry.itemId; + gSaveContext.ship.pendingSaleMod = itemEntry.modIndex; Actor_OfferGetItem(&this->actor, play, GI_BOMBCHUS_10, 10000.0f, 50.0f); } } diff --git a/soh/src/overlays/actors/ovl_En_Kusa/z_en_kusa.c b/soh/src/overlays/actors/ovl_En_Kusa/z_en_kusa.c index 7389db34b..07274cad4 100644 --- a/soh/src/overlays/actors/ovl_En_Kusa/z_en_kusa.c +++ b/soh/src/overlays/actors/ovl_En_Kusa/z_en_kusa.c @@ -310,7 +310,7 @@ void EnKusa_Main(EnKusa* this, PlayState* play) { EnKusa_SpawnFragments(this, play); EnKusa_DropCollectible(this, play); SoundSource_PlaySfxAtFixedWorldPos(play, &this->actor.world.pos, 20, NA_SE_EV_PLANT_BROKEN); - gSaveContext.sohStats.count[COUNT_BUSHES_CUT]++; + gSaveContext.ship.stats.count[COUNT_BUSHES_CUT]++; if ((this->actor.params >> 4) & 1) { EnKusa_SpawnBugs(this, play); @@ -379,7 +379,7 @@ void EnKusa_Fall(EnKusa* this, PlayState* play) { if (this->actor.bgCheckFlags & 0xB) { if (!(this->actor.bgCheckFlags & 0x20)) { SoundSource_PlaySfxAtFixedWorldPos(play, &this->actor.world.pos, 20, NA_SE_EV_PLANT_BROKEN); - gSaveContext.sohStats.count[COUNT_BUSHES_CUT]++; + gSaveContext.ship.stats.count[COUNT_BUSHES_CUT]++; } EnKusa_SpawnFragments(this, play); EnKusa_DropCollectible(this, play); diff --git a/soh/src/overlays/actors/ovl_En_Ta/z_en_ta.c b/soh/src/overlays/actors/ovl_En_Ta/z_en_ta.c index 1e923335b..d2e1d109a 100644 --- a/soh/src/overlays/actors/ovl_En_Ta/z_en_ta.c +++ b/soh/src/overlays/actors/ovl_En_Ta/z_en_ta.c @@ -917,8 +917,8 @@ void func_80B15FE8(EnTa* this, PlayState* play) { EnTa_SetupAction(this, EnTa_GiveItemInLonLonHouse, EnTa_AnimRunToEnd); Rupees_ChangeBy(-30); GetItemEntry itemEntry = ItemTable_Retrieve(GI_MILK); - gSaveContext.pendingSale = itemEntry.itemId; - gSaveContext.pendingSaleMod = itemEntry.modIndex; + gSaveContext.ship.pendingSale = itemEntry.itemId; + gSaveContext.ship.pendingSaleMod = itemEntry.modIndex; Actor_OfferGetItem(&this->actor, play, GI_MILK, 10000.0f, 50.0f); break; } diff --git a/soh/src/overlays/actors/ovl_Obj_Tsubo/z_obj_tsubo.c b/soh/src/overlays/actors/ovl_Obj_Tsubo/z_obj_tsubo.c index 4cdc67e44..5c2c58dc4 100644 --- a/soh/src/overlays/actors/ovl_Obj_Tsubo/z_obj_tsubo.c +++ b/soh/src/overlays/actors/ovl_Obj_Tsubo/z_obj_tsubo.c @@ -189,7 +189,7 @@ void ObjTsubo_AirBreak(ObjTsubo* this, PlayState* play) { sObjectIds[(this->actor.params >> 8) & 1], D_80BA1B8C[(this->actor.params >> 8) & 1]); } func_80033480(play, &this->actor.world.pos, 30.0f, 4, 20, 50, 1); - gSaveContext.sohStats.count[COUNT_POTS_BROKEN]++; + gSaveContext.ship.stats.count[COUNT_POTS_BROKEN]++; } void ObjTsubo_WaterBreak(ObjTsubo* this, PlayState* play) { @@ -218,7 +218,7 @@ void ObjTsubo_WaterBreak(ObjTsubo* this, PlayState* play) { (Rand_ZeroOne() * 95.0f) + 15.0f, 0, 32, 70, KAKERA_COLOR_NONE, sObjectIds[(this->actor.params >> 8) & 1], D_80BA1B8C[(this->actor.params >> 8) & 1]); } - gSaveContext.sohStats.count[COUNT_POTS_BROKEN]++; + gSaveContext.ship.stats.count[COUNT_POTS_BROKEN]++; } void ObjTsubo_SetupWaitForObject(ObjTsubo* this) { diff --git a/soh/src/overlays/actors/ovl_player_actor/z_player.c b/soh/src/overlays/actors/ovl_player_actor/z_player.c index 8d229178b..496899bc6 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -1789,9 +1789,9 @@ void Player_PlaySteppingSfx(Player* this, f32 pitchAdjustment) { func_800F4010(&this->actor.projectedPos, sfxId, pitchAdjustment); // Gameplay stats: Count footsteps // Only count while game isn't complete and don't count Link's idle animations or crawling in crawlspaces - if (!gSaveContext.sohStats.gameComplete && !(this->stateFlags2 & PLAYER_STATE2_IDLE_FIDGET) && + if (!gSaveContext.ship.stats.gameComplete && !(this->stateFlags2 & PLAYER_STATE2_IDLE_FIDGET) && !(this->stateFlags2 & PLAYER_STATE2_CRAWLING)) { - gSaveContext.sohStats.count[COUNT_STEPS]++; + gSaveContext.ship.stats.count[COUNT_STEPS]++; } } @@ -2379,7 +2379,7 @@ void func_80833A20(Player* this, s32 newMeleeWeaponState) { } if (this->heldItemAction >= PLAYER_IA_SWORD_MASTER && this->heldItemAction <= PLAYER_IA_SWORD_BIGGORON) { - gSaveContext.sohStats.count[COUNT_SWORD_SWINGS]++; + gSaveContext.ship.stats.count[COUNT_SWORD_SWINGS]++; } } @@ -3484,7 +3484,7 @@ void Player_UseItem(PlayState* play, Player* this, s32 item) { this->currentMask = itemAction - PLAYER_IA_MASK_KEATON + 1; } - gSaveContext.maskMemory = this->currentMask; + gSaveContext.ship.maskMemory = this->currentMask; func_808328EC(this, NA_SE_PL_CHANGE_ARMS); } else if (((itemAction >= PLAYER_IA_OCARINA_FAIRY) && (itemAction <= PLAYER_IA_OCARINA_OF_TIME)) || @@ -5538,7 +5538,7 @@ void func_8083A0F4(PlayState* play, Player* this) { Player_SetupAction(play, this, Player_Action_8084F608, 0); this->stateFlags1 |= PLAYER_STATE1_IN_CUTSCENE; if (!CVarGetInteger(CVAR_ENHANCEMENT("PersistentMasks"), 0) || !CVarGetInteger(CVAR_ENHANCEMENT("AdultMasks"), 0)) { - gSaveContext.maskMemory = PLAYER_MASK_NONE; + gSaveContext.ship.maskMemory = PLAYER_MASK_NONE; } } else { LinkAnimationHeader* anim; @@ -6267,7 +6267,7 @@ void Player_SetupRoll(Player* this, PlayState* play) { LinkAnimation_PlayOnceSetSpeed(play, &this->skelAnime, GET_PLAYER_ANIM(PLAYER_ANIMGROUP_landing_roll, this->modelAnimType), 1.25f * sWaterSpeedFactor); - gSaveContext.sohStats.count[COUNT_ROLLS]++; + gSaveContext.ship.stats.count[COUNT_ROLLS]++; } s32 Player_TryRoll(Player* this, PlayState* play) { @@ -6326,10 +6326,10 @@ s32 Player_ActionHandler_10(Player* this, PlayState* play) { func_8083BCD0(this, play, controlStickDirection); if (controlStickDirection == 1 || controlStickDirection == 3) { - gSaveContext.sohStats.count[COUNT_SIDEHOPS]++; + gSaveContext.ship.stats.count[COUNT_SIDEHOPS]++; } if (controlStickDirection == 2) { - gSaveContext.sohStats.count[COUNT_BACKFLIPS]++; + gSaveContext.ship.stats.count[COUNT_BACKFLIPS]++; } return 1; @@ -7254,8 +7254,8 @@ void func_8083E4C4(PlayState* play, Player* this, GetItemEntry* giEntry) { s32 Player_ActionHandler_2(Player* this, PlayState* play) { Actor* interactedActor; - if(gSaveContext.pendingIceTrapCount) { - gSaveContext.pendingIceTrapCount--; + if(gSaveContext.ship.pendingIceTrapCount) { + gSaveContext.ship.pendingIceTrapCount--; GameInteractor_ExecuteOnItemReceiveHooks(ItemTable_RetrieveEntry(MOD_RANDOMIZER, RG_ICE_TRAP)); if (CVarGetInteger(CVAR_ENHANCEMENT("ExtraTraps.Enabled"), 0)) { return 1; @@ -7266,7 +7266,7 @@ s32 Player_ActionHandler_2(Player* this, PlayState* play) { this->getItemId = GI_NONE; this->getItemEntry = (GetItemEntry) GET_ITEM_NONE; // Gameplay stats: Increment Ice Trap count - gSaveContext.sohStats.count[COUNT_ICE_TRAPS]++; + gSaveContext.ship.stats.count[COUNT_ICE_TRAPS]++; return 1; } @@ -7295,7 +7295,7 @@ s32 Player_ActionHandler_2(Player* this, PlayState* play) { Player_SetPendingFlag(this, play); Message_StartTextbox(play, 0xF8, NULL); Audio_PlayFanfare(NA_BGM_SMALL_ITEM_GET); - gSaveContext.pendingIceTrapCount++; + gSaveContext.ship.pendingIceTrapCount++; return 1; } @@ -9513,7 +9513,7 @@ void func_80843AE8(PlayState* play, Player* this) { } else if (play->gameOverCtx.state == GAMEOVER_DEATH_WAIT_GROUND) { play->gameOverCtx.state = GAMEOVER_DEATH_DELAY_MENU; if (!CVarGetInteger(CVAR_ENHANCEMENT("PersistentMasks"), 0)) { - gSaveContext.maskMemory = PLAYER_MASK_NONE; + gSaveContext.ship.maskMemory = PLAYER_MASK_NONE; } } } @@ -9818,7 +9818,7 @@ void Player_Action_Roll(Player* this, PlayState* play) { Player_PlayVoiceSfx(this, NA_SE_VO_LI_CLIMB_END); this->av2.bonked = 1; - gSaveContext.sohStats.count[COUNT_BONKS]++; + gSaveContext.ship.stats.count[COUNT_BONKS]++; GameInteractor_ExecuteOnPlayerBonk(); return; @@ -10806,9 +10806,9 @@ void Player_Init(Actor* thisx, PlayState* play2) { //keep masks thru loading zones if (CVarGetInteger(CVAR_ENHANCEMENT("PersistentMasks"), 0)) { if (INV_CONTENT(ITEM_TRADE_CHILD) == ITEM_SOLD_OUT) { - gSaveContext.maskMemory = PLAYER_MASK_NONE; + gSaveContext.ship.maskMemory = PLAYER_MASK_NONE; } - this->currentMask = gSaveContext.maskMemory; + this->currentMask = gSaveContext.ship.maskMemory; } Player_InitCommon(this, play, gPlayerSkelHeaders[((void)0, gSaveContext.linkAge)]); // `giObjectSegment` is used for both "get item" objects and title cards. The maximum size for @@ -14282,7 +14282,7 @@ s32 func_8084DFF4(PlayState* play, Player* this) { // #region SOH [Randomizer] TODO Better Ice trap handling? if (this->getItemEntry.itemId == RG_ICE_TRAP && this->getItemEntry.modIndex == MOD_RANDOMIZER) { this->unk_862 = 0; - gSaveContext.pendingIceTrapCount++; + gSaveContext.ship.pendingIceTrapCount++; Player_SetPendingFlag(this, play); } // #endregion @@ -14460,7 +14460,7 @@ void Player_Action_8084E6D4(Player* this, PlayState* play) { this->actor.world.pos.y + 100.0f, this->actor.world.pos.z, 0, 0, 0, 0, true); func_8083C0E8(this, play); } else if (IS_RANDO) { - gSaveContext.pendingIceTrapCount++; + gSaveContext.ship.pendingIceTrapCount++; Player_SetPendingFlag(this, play); func_8083C0E8(this, play); } else { diff --git a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c index 9b964054e..dbff0955a 100644 --- a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c +++ b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c @@ -989,7 +989,7 @@ void DrawSeedHashSprites(FileChooseContext* this) { this->configMode == CM_NAME_ENTRY_TO_RANDOMIZER_SETTINGS_MENU || this->configMode == CM_START_NAME_ENTRY || this->configMode == CM_START_RANDOMIZER_SETTINGS_MENU) || this->configMode == CM_RANDOMIZER_SETTINGS_MENU) && - gSaveContext.questId == QUEST_RANDOMIZER)) { + gSaveContext.ship.quest.id == QUEST_RANDOMIZER)) { gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF); u16 xStart = 64; @@ -1298,7 +1298,7 @@ void FileChoose_UpdateQuestMenu(GameState* thisx) { } if (CHECK_BTN_ALL(input->press.button, BTN_A)) { - gSaveContext.questId = this->questType[this->buttonIndex]; + gSaveContext.ship.quest.id = this->questType[this->buttonIndex]; if (this->questType[this->buttonIndex] == QUEST_BOSSRUSH) { Audio_PlaySoundGeneral(NA_SE_SY_FSEL_DECIDE_L, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); @@ -1393,17 +1393,17 @@ void FileChoose_UpdateBossRushMenu(GameState* thisx) { if (ABS(this->stickRelX) > 30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DLEFT | BTN_DRIGHT))) { if (this->stickRelX > 30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DRIGHT))) { // If exceeding the amount of choices for the selected option, cycle back to the first. - if ((gSaveContext.bossRushOptions[this->bossRushIndex] + 1) == BossRush_GetSettingOptionsAmount(this->bossRushIndex)) { - gSaveContext.bossRushOptions[this->bossRushIndex] = 0; + if ((gSaveContext.ship.quest.data.bossRush.options[this->bossRushIndex] + 1) == BossRush_GetSettingOptionsAmount(this->bossRushIndex)) { + gSaveContext.ship.quest.data.bossRush.options[this->bossRushIndex] = 0; } else { - gSaveContext.bossRushOptions[this->bossRushIndex]++; + gSaveContext.ship.quest.data.bossRush.options[this->bossRushIndex]++; } } else if (this->stickRelX < -30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DLEFT))) { // If cycling back when already at the first choice for the selected option, cycle back to the last choice. - if ((gSaveContext.bossRushOptions[this->bossRushIndex] - 1) < 0) { - gSaveContext.bossRushOptions[this->bossRushIndex] = BossRush_GetSettingOptionsAmount(this->bossRushIndex) - 1; + if ((gSaveContext.ship.quest.data.bossRush.options[this->bossRushIndex] - 1) < 0) { + gSaveContext.ship.quest.data.bossRush.options[this->bossRushIndex] = BossRush_GetSettingOptionsAmount(this->bossRushIndex) - 1; } else { - gSaveContext.bossRushOptions[this->bossRushIndex]--; + gSaveContext.ship.quest.data.bossRush.options[this->bossRushIndex]--; } } @@ -1411,10 +1411,10 @@ void FileChoose_UpdateBossRushMenu(GameState* thisx) { } if (sLastBossRushOptionIndex != this->bossRushIndex || - sLastBossRushOptionValue != gSaveContext.bossRushOptions[this->bossRushIndex]) { - GameInteractor_ExecuteOnUpdateFileBossRushOptionSelection(this->bossRushIndex, gSaveContext.bossRushOptions[this->bossRushIndex]); + sLastBossRushOptionValue != gSaveContext.ship.quest.data.bossRush.options[this->bossRushIndex]) { + GameInteractor_ExecuteOnUpdateFileBossRushOptionSelection(this->bossRushIndex, gSaveContext.ship.quest.data.bossRush.options[this->bossRushIndex]); sLastBossRushOptionIndex = this->bossRushIndex; - sLastBossRushOptionValue = gSaveContext.bossRushOptions[this->bossRushIndex]; + sLastBossRushOptionValue = gSaveContext.ship.quest.data.bossRush.options[this->bossRushIndex]; } if (CHECK_BTN_ALL(input->press.button, BTN_B)) { @@ -2408,7 +2408,7 @@ void FileChoose_DrawWindowContents(GameState* thisx) { 65, (87 + textYOffset), 255, 255, 80, textAlpha, 0.8f, true); // Selected choice for option. - uint16_t finalKerning = Interface_DrawTextLine(this->state.gfxCtx, BossRush_GetSettingChoiceName(i, gSaveContext.bossRushOptions[i], gSaveContext.language), + uint16_t finalKerning = Interface_DrawTextLine(this->state.gfxCtx, BossRush_GetSettingChoiceName(i, gSaveContext.ship.quest.data.bossRush.options[i], gSaveContext.language), 165, (87 + textYOffset), 255, 255, 255, textAlpha, 0.8f, true); // Draw arrows around selected option. From ce289c0be9c40e8869f2ba4f4246ccb1aedb940b Mon Sep 17 00:00:00 2001 From: Pepper0ni <93387759+Pepper0ni@users.noreply.github.com> Date: Wed, 15 Jan 2025 12:05:52 +0000 Subject: [PATCH 16/26] Properly store starting age in spoiler log (#4873) * properly store starting age in spoiler log * convert ResolvedStatingAge to a setting to store it in the save --- .../Enhancements/randomizer/3drando/fill.cpp | 10 ++++----- .../randomizer/3drando/spoiler_log.cpp | 21 ++++++++++++------- soh/soh/Enhancements/randomizer/entrance.cpp | 4 ++-- .../randomizer/location_access.cpp | 8 +++---- soh/soh/Enhancements/randomizer/logic.cpp | 2 +- .../Enhancements/randomizer/randomizerTypes.h | 1 + .../randomizer/randomizer_check_tracker.cpp | 2 +- soh/soh/Enhancements/randomizer/savefile.cpp | 2 +- soh/soh/Enhancements/randomizer/settings.cpp | 12 ++++------- soh/soh/Enhancements/randomizer/settings.h | 9 -------- 10 files changed, 32 insertions(+), 39 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/3drando/fill.cpp b/soh/soh/Enhancements/randomizer/3drando/fill.cpp index 248fd960d..c86b7eff9 100644 --- a/soh/soh/Enhancements/randomizer/3drando/fill.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/fill.cpp @@ -130,14 +130,14 @@ static bool UpdateToDAccess(Entrance* entrance, Region* connection) { static void ValidateOtherEntrance(GetAccessibleLocationsStruct& gals) { auto ctx = Rando::Context::GetInstance(); // Condition for validating Temple of Time Access - if (!gals.foundTempleOfTime && ((ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_CHILD && RegionTable(RR_TEMPLE_OF_TIME)->Adult()) || - (ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_ADULT && RegionTable(RR_TEMPLE_OF_TIME)->Child()))) { + if (!gals.foundTempleOfTime && ((ctx->GetOption(RSK_SELECTED_STARTING_AGE).Is(RO_AGE_CHILD) && RegionTable(RR_TEMPLE_OF_TIME)->Adult()) || + (ctx->GetOption(RSK_SELECTED_STARTING_AGE).Is(RO_AGE_ADULT) && RegionTable(RR_TEMPLE_OF_TIME)->Child()))) { gals.foundTempleOfTime = true; } // Condition for validating a valid starting region if (!gals.validatedStartingRegion) { - bool childAccess = ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_CHILD || RegionTable(RR_TOT_BEYOND_DOOR_OF_TIME)->Child(); - bool adultAccess = ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_ADULT || RegionTable(RR_TOT_BEYOND_DOOR_OF_TIME)->Adult(); + bool childAccess = ctx->GetOption(RSK_SELECTED_STARTING_AGE).Is(RO_AGE_CHILD) || RegionTable(RR_TOT_BEYOND_DOOR_OF_TIME)->Child(); + bool adultAccess = ctx->GetOption(RSK_SELECTED_STARTING_AGE).Is(RO_AGE_ADULT) || RegionTable(RR_TOT_BEYOND_DOOR_OF_TIME)->Adult(); Region* kokiri = RegionTable(RR_KOKIRI_FOREST); Region* kakariko = RegionTable(RR_KAKARIKO_VILLAGE); @@ -168,7 +168,7 @@ static void ValidateSphereZero(GetAccessibleLocationsStruct& gals){ // Apply all items that are necessary for checking all location access ApplyAllAdvancmentItems(); // Reset access as the non-starting age - if (ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_CHILD) { + if (ctx->GetOption(RSK_SELECTED_STARTING_AGE).Is(RO_AGE_CHILD)) { for (RandomizerRegion regionKey : gals.regionPool) { RegionTable(regionKey)->adultDay = false; RegionTable(regionKey)->adultNight = false; diff --git a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp index bed532e9b..10c1afb60 100644 --- a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp @@ -206,14 +206,19 @@ static void WriteMasterQuestDungeons() { } // Writes the required trials to the spoiler log, if there are any. -static void WriteRequiredTrials() { - auto ctx = Rando::Context::GetInstance(); - for (const auto& trial : ctx->GetTrials()->GetTrialList()) { - if (trial->IsRequired()) { - std::string trialName = trial->GetName().GetForCurrentLanguage(MF_CLEAN); - jsonData["requiredTrials"].push_back(RemoveLineBreaks(trialName)); - } +static void WriteChosenOptions() { + auto ctx = Rando::Context::GetInstance(); + for (const auto& trial : ctx->GetTrials()->GetTrialList()) { + if (trial->IsRequired()) { + std::string trialName = trial->GetName().GetForCurrentLanguage(MF_CLEAN); + jsonData["requiredTrials"].push_back(RemoveLineBreaks(trialName)); } + } + if (ctx->GetOption(RSK_SELECTED_STARTING_AGE).Is(RO_AGE_ADULT)){ + jsonData["SelectedStartingAge"] = "Adult"; + } else { + jsonData["SelectedStartingAge"] = "Child"; + } } // Writes the intended playthrough to the spoiler log, separated into spheres. @@ -331,7 +336,7 @@ const char* SpoilerLog_Write() { WriteStartingInventory(); WriteEnabledTricks(); WriteMasterQuestDungeons(); - WriteRequiredTrials(); + WriteChosenOptions(); WritePlaythrough(); ctx->playthroughLocations.clear(); diff --git a/soh/soh/Enhancements/randomizer/entrance.cpp b/soh/soh/Enhancements/randomizer/entrance.cpp index 1e28aa2c3..910467e81 100644 --- a/soh/soh/Enhancements/randomizer/entrance.cpp +++ b/soh/soh/Enhancements/randomizer/entrance.cpp @@ -536,10 +536,10 @@ static bool ValidateWorld(Entrance* entrancePlaced) { // 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 (ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_CHILD && !RegionTable(RR_TEMPLE_OF_TIME)->Adult()) { + if (ctx->GetOption(RSK_SELECTED_STARTING_AGE).Is(RO_AGE_CHILD) && !RegionTable(RR_TEMPLE_OF_TIME)->Adult()) { SPDLOG_DEBUG("Path to Temple of Time as adult is not guaranteed\n"); return false; - } else if (ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_ADULT && + } else if (ctx->GetOption(RSK_SELECTED_STARTING_AGE).Is(RO_AGE_ADULT) && !RegionTable(RR_TEMPLE_OF_TIME)->Child()) { SPDLOG_DEBUG("Path to Temple of Time as child is not guaranteed\n"); return false; diff --git a/soh/soh/Enhancements/randomizer/location_access.cpp b/soh/soh/Enhancements/randomizer/location_access.cpp index d3a17a0b9..64f0b23d5 100644 --- a/soh/soh/Enhancements/randomizer/location_access.cpp +++ b/soh/soh/Enhancements/randomizer/location_access.cpp @@ -438,13 +438,13 @@ namespace Regions { } if (/*Settings::HasNightStart TODO:: Randomize Starting Time*/ false) { - if (ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_CHILD) { + if (ctx->GetOption(RSK_SELECTED_STARTING_AGE).Is(RO_AGE_CHILD)) { RegionTable(RR_ROOT)->childNight = true; } else { RegionTable(RR_ROOT)->adultNight = true; } } else { - if (ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_CHILD) { + if (ctx->GetOption(RSK_SELECTED_STARTING_AGE).Is(RO_AGE_CHILD)) { RegionTable(RR_ROOT)->childDay = true; } else { RegionTable(RR_ROOT)->adultDay = true; @@ -465,13 +465,13 @@ namespace Regions { } if (/*Settings::HasNightStart TODO:: Randomize Starting Time*/ false) { - if (ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_CHILD) { + if (ctx->GetOption(RSK_SELECTED_STARTING_AGE).Is(RO_AGE_CHILD)) { RegionTable(RR_ROOT)->childNight = true; } else { RegionTable(RR_ROOT)->adultNight = true; } } else { - if (ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_CHILD) { + if (ctx->GetOption(RSK_SELECTED_STARTING_AGE).Is(RO_AGE_CHILD)) { RegionTable(RR_ROOT)->childDay = true; } else { RegionTable(RR_ROOT)->adultDay = true; diff --git a/soh/soh/Enhancements/randomizer/logic.cpp b/soh/soh/Enhancements/randomizer/logic.cpp index 85104d825..b107ea939 100644 --- a/soh/soh/Enhancements/randomizer/logic.cpp +++ b/soh/soh/Enhancements/randomizer/logic.cpp @@ -2149,7 +2149,7 @@ namespace Rando { //Other AtDay = false; AtNight = false; - GetSaveContext()->linkAge = !ctx->GetSettings()->ResolvedStartingAge(); + GetSaveContext()->linkAge = !ctx->GetOption(RSK_SELECTED_STARTING_AGE).GetContextOptionIndex(); //Events ShowedMidoSwordAndShield = false; diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index 87ba34adf..703b2a301 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -5098,6 +5098,7 @@ typedef enum { RSK_ZORAS_FOUNTAIN, RSK_SLEEPING_WATERFALL, RSK_STARTING_AGE, + RSK_SELECTED_STARTING_AGE, RSK_GERUDO_FORTRESS, RSK_RAINBOW_BRIDGE, RSK_RAINBOW_BRIDGE_STONE_COUNT, diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp index ecd572ab9..c65c3c00d 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp @@ -490,7 +490,7 @@ void CheckTrackerLoadGame(int32_t fileNum) { } } if (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_LINKS_POCKET) != RO_LINKS_POCKET_NOTHING && IS_RANDO) { - s8 startingAge = OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_STARTING_AGE); + uint8_t startingAge = OTRGlobals::Instance->gRandoContext->GetOption(RSK_SELECTED_STARTING_AGE).GetContextOptionIndex(); RandomizerCheckArea startingArea; switch (startingAge) { case RO_AGE_CHILD: diff --git a/soh/soh/Enhancements/randomizer/savefile.cpp b/soh/soh/Enhancements/randomizer/savefile.cpp index 44a4a859e..af7abd49e 100644 --- a/soh/soh/Enhancements/randomizer/savefile.cpp +++ b/soh/soh/Enhancements/randomizer/savefile.cpp @@ -272,7 +272,7 @@ extern "C" void Randomizer_InitSaveFile() { Flags_SetRandomizerInf(RAND_INF_SCRUBS_PURCHASED_HF_DEKU_SCRUB_GROTTO); } - int startingAge = OTRGlobals::Instance->gRandoContext->GetSettings()->ResolvedStartingAge(); + int startingAge = OTRGlobals::Instance->gRandoContext->GetOption(RSK_SELECTED_STARTING_AGE).GetContextOptionIndex(); switch (startingAge) { case RO_AGE_ADULT: // Adult gSaveContext.linkAge = LINK_AGE_ADULT; diff --git a/soh/soh/Enhancements/randomizer/settings.cpp b/soh/soh/Enhancements/randomizer/settings.cpp index f5abde703..0c5e6c41c 100644 --- a/soh/soh/Enhancements/randomizer/settings.cpp +++ b/soh/soh/Enhancements/randomizer/settings.cpp @@ -126,6 +126,7 @@ void Settings::CreateOptions() { mOptions[RSK_GANONS_TRIALS] = Option::U8("Ganon's Trials", {"Skip", "Set Number", "Random Number"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("GanonTrial"), mOptionDescriptions[RSK_GANONS_TRIALS], WidgetType::Combobox, RO_GANONS_TRIALS_SET_NUMBER); mOptions[RSK_TRIAL_COUNT] = Option::U8("Ganon's Trials Count", {NumOpts(0, 6)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("GanonTrialCount"), mOptionDescriptions[RSK_TRIAL_COUNT], WidgetType::Slider, 6, true); mOptions[RSK_STARTING_AGE] = Option::U8("Starting Age", {"Child", "Adult", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("StartingAge"), mOptionDescriptions[RSK_STARTING_AGE], WidgetType::Combobox, RO_AGE_CHILD); + mOptions[RSK_SELECTED_STARTING_AGE] = Option::U8("Selected Starting Age", {"Child", "Adult"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("SelectedStartingAge"), mOptionDescriptions[RSK_STARTING_AGE], WidgetType::Combobox, RO_AGE_CHILD); mOptions[RSK_SHUFFLE_ENTRANCES] = Option::Bool("Shuffle Entrances"); mOptions[RSK_SHUFFLE_DUNGEON_ENTRANCES] = Option::U8("Dungeon Entrances", {"Off", "On", "On + Ganon"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleDungeonsEntrances"), mOptionDescriptions[RSK_SHUFFLE_DUNGEON_ENTRANCES], WidgetType::Combobox, RO_DUNGEON_ENTRANCE_SHUFFLE_OFF); mOptions[RSK_SHUFFLE_BOSS_ENTRANCES] = Option::U8("Boss Entrances", {"Off", "Age Restricted", "Full"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleBossEntrances"), mOptionDescriptions[RSK_SHUFFLE_BOSS_ENTRANCES], WidgetType::Combobox, RO_BOSS_ROOM_ENTRANCE_SHUFFLE_OFF); @@ -1327,11 +1328,6 @@ std::vector